NixOS / nixpkgs

Nix Packages collection & NixOS
MIT License
16.69k stars 13.14k forks source link

wireguard: peer endpoints are set after the opportunities to set DNS configuration #169128

Open nagisa opened 2 years ago

nagisa commented 2 years ago

Describe the bug

The units generated by the networking.wireguard set-up disallow using DNS service provided by the peer and connecting to peers using a domain address, rather than an IP.

A typical attempt to achieve this might look like this:

{
  networking.wireguard = {
    enable = true;
    interfaces.wg0 = {
      postSetup = ''echo "nameserver 192.168.2.1" | ${pkgs.openresolv}/bin/resolvconf -x -m 0 -a wg0'';
      postShutdown = "${pkgs.openresolv}/bin/resolvconf -f -d wg0";
      peers = [{
        endpoint = "wg.example.com:12345";
        allowedIPs = ["0.0.0.0/0"];
      }];
    };
  };
}

However here the sequence of operations will be:

  1. ip link add dev wg0 type wireguard
  2. Set up the nameserver
  3. wg set wg0 peer "..." endpoint "wg.example.com:12345"

Here resolving the wg.example.com will naturally fail, since it cannot be resolved anymore.

Instead the setup should provide an (easy) way to tie some setup to a specific peer – and it needs to work with the dynamicEndpointRefreshSeconds functionality too. For initial set-up I'd imagine the flow needs to look like this (this is also what wg-quick does)

  1. ip link add dev wg0 type wireguard
  2. wg set wg0 peer "..." endpoint "wg.example.com:12345"
  3. Set up the nameserver.

and for the refreshes it might make sense to first try resolving with the DNS server that has been set-up and failing that recreate the peer from scratch (which would involve removing the peer, unsetting the DNS settings tied to it, and recreating it.)

Notify maintainers

Metadata

Please run nix-shell -p nix-info --run "nix-info -m" and paste the result.

[user@system:~]$ nix-shell -p nix-info --run "nix-info -m"
output here
peterhoeg commented 2 years ago

If you need to do split DNS, I suggest using systemd-resolve instead. This is what I use that works perfectly:

postSetup = ''
  ${pkgs.systemd}/bin/resolvectl dns    ${cfg.interface} 10.1.1.1
  ${pkgs.systemd}/bin/resolvectl domain ${cfg.interface} the.internal.domain
'';
nagisa commented 2 years ago

I would like to redirect all DNS queries to the DNS server hosted on the peer.

peterhoeg commented 2 years ago

Why not have wg.example.com be resolvable by 192.168.2.1?

nagisa commented 2 years ago

Ah, sorry for not making it clearer. 192.168.2.1 is wg.example.com's IP within the wireguard subnet. So in order to resolve wg.example.com with 192.168.2.1 the connection with the peer at wg.example.com must already have been established. To break this chicken-and-egg looking-problem, wg.example.com is also resolvable globally through DNS servers like those provided by Google, Cloudflare or Quad9, which allows resolving the peer's address when setting up the tunnel for the first time.

Note that this sort of setup does work correctly with wg-quick as it sets up (⇒ resolves the address of) the peer first before adding the routes and the DNS configuration.