[PR #6087] dns: prefer loopback over WireGuard IP when binding DNS listener #29028

Open
opened 2026-08-05 08:07:20 -04:00 by saavagebueno · 0 comments
Owner

Original Pull Request: https://github.com/netbirdio/netbird/pull/6087

State: closed
Merged: No


Describe your changes

`testFreePort` in `client/internal/dns/service_listener.go` tries the WireGuard interface IP first when scanning for a free port. If the DNS server binds to that IP (e.g. `100.71.x.x:53`), queries routed to it are silently dropped by the WireGuard kernel module — the host's own WireGuard IP is not in any peer's `AllowedIPs`, so packets never reach the listener. DNS resolution breaks entirely.

This fix reorders the candidate IP list so loopback (`127.0.0.1`) is tried first, then `127.0.0.153`, with the WireGuard IP as a last resort. The DNS proxy then binds to a loopback address where packets are always delivered locally.

```go
// Before
ips = []netip.Addr{s.wgInterface.Address().IP, defaultIP, customIP}

// After
ips = []netip.Addr{defaultIP, customIP, s.wgInterface.Address().IP}
```

Verified on Ubuntu 25.10 with systemd-resolved: after the fix `netbird` binds to `127.0.0.1:53` and DNS resolves correctly. Before the fix it bound to the WireGuard IP and all DNS queries timed out.

Fixes #4110 (timeout towards netbird domain DNS forwarder on arch linux)
Related to #3258 (client does not set DNS server in systemd-resolved on Linux)

Both issues stem from the DNS listener binding to the WireGuard interface IP, which the WireGuard kernel module drops packets for since the local IP is not in any peer's AllowedIPs.

Stack

Checklist

  • Is it a bug fix
  • Is a typo/documentation fix
  • Is a feature enhancement
  • It is a refactor
  • Created tests that fail without the change (if possible)

By submitting this pull request, you confirm that you have read and agree to the terms of the Contributor License Agreement.

Documentation

Select exactly one:

  • Documentation is not needed for this change (internal bind address selection, no user-facing behavior change)

Summary by CodeRabbit

  • Refactor
    • Adjusted DNS port probing order on non-Darwin systems to prefer loopback addresses when determining a free port.
  • Tests
    • Added a test ensuring loopback addresses are preferred over other interfaces when selecting a free DNS port.
**Original Pull Request:** https://github.com/netbirdio/netbird/pull/6087 **State:** closed **Merged:** No --- ## Describe your changes \`testFreePort\` in \`client/internal/dns/service_listener.go\` tries the WireGuard interface IP first when scanning for a free port. If the DNS server binds to that IP (e.g. \`100.71.x.x:53\`), queries routed to it are silently dropped by the WireGuard kernel module — the host's own WireGuard IP is not in any peer's \`AllowedIPs\`, so packets never reach the listener. DNS resolution breaks entirely. This fix reorders the candidate IP list so loopback (\`127.0.0.1\`) is tried first, then \`127.0.0.153\`, with the WireGuard IP as a last resort. The DNS proxy then binds to a loopback address where packets are always delivered locally. \`\`\`go // Before ips = []netip.Addr{s.wgInterface.Address().IP, defaultIP, customIP} // After ips = []netip.Addr{defaultIP, customIP, s.wgInterface.Address().IP} \`\`\` Verified on Ubuntu 25.10 with systemd-resolved: after the fix \`netbird\` binds to \`127.0.0.1:53\` and DNS resolves correctly. Before the fix it bound to the WireGuard IP and all DNS queries timed out. ## Issue ticket number and link Fixes #4110 (timeout towards netbird domain DNS forwarder on arch linux) Related to #3258 (client does not set DNS server in systemd-resolved on Linux) Both issues stem from the DNS listener binding to the WireGuard interface IP, which the WireGuard kernel module drops packets for since the local IP is not in any peer's AllowedIPs. ## Stack <!-- branch-stack --> ### Checklist - [x] Is it a bug fix - [ ] Is a typo/documentation fix - [ ] Is a feature enhancement - [ ] It is a refactor - [ ] Created tests that fail without the change (if possible) > By submitting this pull request, you confirm that you have read and agree to the terms of the [Contributor License Agreement](https://github.com/netbirdio/netbird/blob/main/CONTRIBUTOR_LICENSE_AGREEMENT.md). ## Documentation Select exactly one: - [x] Documentation is **not needed** for this change (internal bind address selection, no user-facing behavior change) <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Refactor** * Adjusted DNS port probing order on non-Darwin systems to prefer loopback addresses when determining a free port. * **Tests** * Added a test ensuring loopback addresses are preferred over other interfaces when selecting a free DNS port. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
saavagebueno added the pull-request label 2026-08-05 08:07:20 -04:00
Sign in to join this conversation.
No Label pull-request
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: DYNR/netbird#29028