GeoDNS

repository·main·Indexed 22 days ago

https://github.com/abh/geodns

A CoreDNS plugin and standalone server providing geographically-aware DNS responses. It enables returning different IP addresses based on client location (country or continent) or via weighted record distribution. Features include JSON-based zone configuration, Prometheus metrics, and support for A, AAAA, MX, and SRV records.

Tokens
2.4K
Snippets
5
Records
24
Agent score
81%

What's inside geodns

  1. How weighted records work in GeoDNS

    main

    GeoDNS allows assigning a weight to records. If any records for a specific name/type have a weight, the system returns max_hosts records (default is 2).

    • If all weights are 0, all matching records are returned.
    • Weights allow for probabilistic distribution. For example, if you have weights of 10, 20, 30, and 40 with max_hosts set to 2, the record with weight 40 will be returned approximately 4 times more often than the record with weight 10.
    • Weights must be less than 2 billion.
  2. Run the GeoDNS server

    main

    After building the binary, you can start the server using command-line flags. For example, to listen on 127.1 on port 5053 with logging enabled:

    ./geodns -log -interface 127.1 -port 5053

    To test the responses, use dig against the specified interface and port:

    # Test A record
    dig -t a test.example.com @127.1 -p 5053
    
    # Test PTR record
    dig -t ptr 2.1.168.192.IN-ADDR.ARPA. @127.1 -p 5053
    
    # Test reverse lookup
    dig -x 192.168.1.2 @127.1 -p 5053
  3. Install GeoDNS from source

    main

    To build GeoDNS from source, you need a recent version of Go installed. Follow these steps:

    1. Clone the repository.
    2. Navigate to the directory.
    3. Build the binary.
    4. Run the help command to verify.
    git clone https://github.com/abh/geodns.git
    cd geodns
    go build
    ./geodns -h
  4. Define zones using JSON configuration files

    main

    GeoDNS uses JSON files for zone configuration. These files are automatically reloaded when they change. If a file contains invalid JSON, the previous valid configuration for that zone is retained.

    Zone Structure

    A zone file is a JSON object containing:

    • Top-level options: serial, ttl, max_hosts, and contact.
    • data key: A hash containing the actual DNS records.

    Record Hierarchy

    Inside data, keys are hostnames. Each hostname maps to a hash where keys are record types (lowercase) and values are arrays of records.

    Example Zone Configuration

    {
        "serial": 1,
        "data": {
            "": {
                "ns": [ "ns.example.net", "ns2.example.net" ],
                "txt": "Example zone",
                "spf": [ { "spf": "v=spf1 ~all", "weight": 1 } ],
                "mx": { "mx": "mail.example.com", "preference": 10 }
            },
            "mail": {
                "a": [ ["192.168.0.1", 100], ["192.168.10.1", 50] ]
            },
            "mail.europe": {
                "a": [ ["192.168.255.1", 0] ]
            },
            "smtp": {
                "alias": "mail"
            }
        }
    }
  5. Monitor GeoDNS with Prometheus metrics

    main

    GeoDNS exposes Prometheus-formatted metrics on the HTTP interface. Access them via the /metrics endpoint on the configured HTTP port.

    Example: If running on port 8053, visit http://<your-ip>:8053/metrics.

  6. Configure GeoDNS via command line flags

    main

    The following command-line parameters are used to configure the GeoDNS server instance:

    FlagDefaultDescription
    -config./dns/Directory of zone files and the geodns.conf file.
    -checkconfigfalseCheck configuration file, parse zone files, and exit.
    -interface*Comma-separated IPs to listen on for DNS requests.
    -port53Port number for DNS requests (UDP and TCP).
    -http:8053Listen address for the HTTP interface.
    -identifier""Identifier for this instance (e.g., hostname or group names).
    -logfalseEnable extra logging (not recommended for high-traffic production).
    -cpus4Maximum number of CPUs to use. Set to 0 to match system availability.
  7. Gracefully shut down the Server

    main
    The Shutdown method performs a graceful shutdown of all active DNS listeners (UDP and TCP) with a 3-second timeout per listener. It also attempts to close the configured querylog.QueryLogger if one is present. It returns a joined error if any component fails to shut down correctly.
  8. Format durations with DayDuration.DayString()

    main

    The DayDuration type embeds time.Duration and provides a DayString() method for pretty-printing durations in a human-readable format that includes days, hours, minutes, and seconds.

    Unlike the standard time.Duration.String() method, DayString():

    • Skips fractional seconds.
    • Does not show durations less than one second (returns 0s).
    • Formats components with spaces (e.g., 1d 2h 3m 4s).
    • Provides a simplified view suitable for displaying 'uptime' or long-term durations.
  9. Add a Zone to the Server

    main
    Use the Add method to register a *zones.Zone to be handled under a specific domain name. The method automatically ensures the name is in canonical FQDN form (adding a trailing dot if necessary) before registering it with the internal DNS multiplexer.
  10. Start the DNS Server with ListenAndServe

    main
    The ListenAndServe method starts the DNS server on the provided IP address, listening on both udp and tcp protocols simultaneously. It uses an errgroup to manage the lifecycle of both listeners. This method blocks until the context is cancelled or an error occurs.
  11. Configure a Query Logger

    main
    Use SetQueryLogger to attach a querylog.QueryLogger implementation to the server. This allows the server to log incoming DNS queries. Note that currently, all zones are logged to the same logger instance.
  12. Initialize and run the GeoDNS HTTP server

    main

    The NewHTTPServer function creates a new instance of the GeoDNS HTTP server, which provides an interface for monitoring, metrics, and status information. The server includes a /metrics endpoint for Prometheus and a /version endpoint.

    To run the server, use the Run method, providing a context for lifecycle management and a listen address (e.g., :8080). The server is protected by Basic Authentication if configured in the application settings.