wgsd

repository·main·Indexed 21 days ago

https://github.com/jwhited/wgsd

A CoreDNS plugin that serves WireGuard peer information using DNS-SD (RFC6763) semantics. It enables dynamic discovery of WireGuard endpoints (IP and port) to facilitate mesh networking and NAT traversal via UDP hole punching. The project includes wgsd-coredns, a pre-configured CoreDNS server, and wgsd-client, a utility to periodically update peer endpoint configurations based on DNS SRV records.

Tokens
2.3K
Snippets
10
Records
16
Agent score
75%

What's inside wgsd

  1. What is wgsd-client and how does it work?

    main

    The wgsd-client is a utility designed to keep peer endpoint configurations up to date. It performs the following workflow:

    1. Retrieves the list of configured peers.
    2. Queries the wgsd service for matching public keys.
    3. Updates the endpoint value for each peer if a change is detected.

    Operational Model:

    • Execution: The client checks all peers in a serialized fashion and then exits. It is not a long-running daemon.
    • Scheduling: Because it exits after a single run, it is intended to be executed periodically using a scheduler like cron.
  2. Query WireGuard peer information via DNS-SD

    main

    The wgsd plugin implements DNS-SD (RFC6763) to allow discovery of WireGuard peers.

    Peer Discovery

    To list all peers in a zone, query the PTR records at the namespace: _wireguard._udp.<zone>

    The target for these PTR records follows the format: <base32PubKey>._wireguard._udp.<zone>. Note that public keys are represented in Base32 in record names to ensure case-insensitivity in DNS.

    Peer Details

    To get specific details for a peer, query its SRV record. The response will include the following in the 'additional' section:

    • SRV Record: Provides the port number.
    • A/AAAA Record: Provides the endpoint IP address.
    • TXT Record: Contains the Base64 encoded public key (pub=...) and the allowed IPs (allowed=...).
    # List all peers
    dig @<dns-server> -p <port> _wireguard._udp.example.com. PTR
    
    # Get details for a specific peer
    dig @<dns-server> -p <port> <base32PubKey>._wireguard._udp.example.com. SRV
  3. Install wgsd via binary releases

    main

    You can download pre-compiled binary releases for various GOOS/GOARCH combinations from the GitHub releases page. Each release includes two packages:

    • wgsd-coredns: A CoreDNS server pre-configured with all internal plugins plus the wgsd plugin.
    • wgsd-client: A sample client for testing.
    https://github.com/jwhited/wgsd/releases
  4. Build wgsd-coredns from source

    main

    To build a CoreDNS server that includes the wgsd plugin, you can build the contents of cmd/coredns using go build. This method enables the plugin via external golang source code.

    After building, verify the plugin is active by checking the plugin list with the -plugins flag.

    % go build
    % ./coredns -plugins | grep wgsd
      dns.wgsd
  5. CoreDNS WGSD Plugin Overview

    main
    The wgsd plugin for CoreDNS provides WireGuard peer information using DNS-SD (DNS Service Discovery) semantics. It allows clients to discover WireGuard peers, their endpoints (IP/Port), and allowed IP ranges via standard DNS queries (PTR, SRV, A/AAAA, and TXT records).
  6. Configure the wgsd CoreDNS plugin

    main

    The wgsd plugin is configured within a CoreDNS Corefile. The basic syntax is:

    wgsd ZONE DEVICE

    • ZONE: The zone name the plugin is authoritative for (e.g., example.com).
    • DEVICE: The name of the local WireGuard interface (e.g., wg0).

    You can also use the self option to serve data about the local device in addition to its peers:

    wgsd ZONE DEVICE { self [ ENDPOINT ] [ ALLOWED-IPS ... ] }

    • self: Enables serving local device data.
    • ENDPOINT (optional): Sets a custom endpoint in ip:port format. If omitted, it defaults to the local IP address and the WireGuard ListenPort. This is useful for hosts behind NAT.
    • ALLOWED-IPS (optional, variadic): Sets the allowed-ips to be served for the local device.
    .:5353 {
      wgsd example.com. wg0 {
        self 192.0.2.1:51820 10.0.0.254/32
      }
    }
  7. Configure WGSD Zones

    main

    The Zones struct manages the mapping of zone names to specific Zone configurations. Each Zone defines which WireGuard device to query and how to handle 'self' information.

    Zone Configuration Fields

    • name: The authoritative zone name.
    • device: The WireGuard device name (e.g., wg0).
    • serveSelf: If true, the plugin includes information about the local WireGuard device as a peer.
    • selfEndpoint: (Optional) Overrides the default local endpoint for the 'self' peer.
    • selfAllowedIPs: (Optional) Overrides the allowed IPs for the 'self' peer.
  8. Querying WireGuard Peers via DNS-SD

    main

    WGSD uses specific DNS query patterns to expose peer information. The service prefix used is _wireguard._udp..

    1. Discovering Peers (PTR Records)

    To list all available peers in a zone, perform a PTR query on the service prefix.

    • Query: _wireguard._udp. <zone>
    • Response: A list of PTR records where the target is the base32-encoded public key followed by the service prefix and zone.

    2. Finding a Specific Peer's Endpoint (SRV Records)

    To find the port and target for a specific peer, perform an SRV query using the peer's base32-encoded public key as the name.

    • Query: <base32-encoded-pubkey>.<spSubPrefix><zone>
    • Response: An SRV record containing the port, and EXTRA section containing A/AAAA (host) and TXT records.

    3. Getting IP Addresses or Metadata (A, AAAA, TXT Records)

    Once you have the service instance name (the base32 public key + prefix), you can query for specific data:

    • A/AAAA: Returns the peer's endpoint IP address.
    • TXT: Returns metadata including txtvers, the base64-encoded public key (pub), and the comma-separated list of allowed IP ranges.
  9. Run the CoreDNS server with the wgsd plugin

    main

    This entrypoint builds a CoreDNS server that includes the wgsd plugin. The wgsd plugin is automatically injected into the CoreDNS directive chain immediately before the file plugin. This ensures that wgsd is treated as an authoritative plugin alongside the standard file-based DNS configuration.

    To use this, you must build and run the resulting binary as a standard CoreDNS server, providing a Corefile that includes the wgsd directive.

    go run cmd/coredns/main.go
  10. Convert Base32 DNS record names back to Base64 public keys

    main

    Since wgsd uses Base32 for DNS record names (to maintain case-insensitivity), you may need to convert them back to Base64 to use them with standard WireGuard tools. You can use tr, base32, and base64 from coreutils to perform this conversion.

    # Example conversion
    echo yutrled535igkl7bdlerl6m4vjxsxm3uqqpl4nmsn27mt56ad4ha==== | tr '[:lower:]' '[:upper:]' | base32 -d | base64
  11. Use wgsd-client CLI flags

    main

    The wgsd-client requires specific flags to identify the Wireguard device and DNS configuration. Use the following flags when invoking the binary:

    • -device <string>: The name of the Wireguard device to manage.
    • -dns <string>: The ip:port of the DNS server.
    • -zone <string>: The DNS zone name.
    ./wgsd-client --device wg0 --dns 192.168.1.1:53 --zone example.com