Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Set the source IP address of DNS reply same as destionation IP of original request #1490

Closed
emlimap opened this issue Mar 19, 2020 · 4 comments
Assignees
Milestone

Comments

@emlimap
Copy link

emlimap commented Mar 19, 2020

Issue Details

  • Version of AdGuard Home server:
    • v0.101.0
  • How did you setup DNS configuration:
    • Set by Wireguard/IPSec Client during vpn connection process
  • If it's a router or IoT, please write device model:
    • Virtual Machine
  • Operating system and version:
    • Ubuntu 19.10

On a machine with multiple interfaces, each on different subnet, Adguard sets the DNS reply packets with the IP address of the interface traffic goes out via rather than setting the original request destination IP as source address for reply. This causes some programs to discard the response as it isn't from the source IP address they expected. dig throws reply from unexpected source error messages.

Information regarding the setup

The VM was set up using Algo (https://github.com/trailofbits/algo) which sets up Wireguard & IPsec VPN on Ubuntu 18.04 or 19.10. By default, it comes with dnsmasq for adblocking, but I am replacing it with Adguard Home.

The way algo sets up things is

  1. Adds a virtual IP to lo interface. 172.20.251.11 in this server
  2. Sets up Wireguard using user configured subnet, 10.19.49.0/24
  3. Sets up IPSec using Strongwan with another subnet, 10.19.48.0/24
  4. Generates config files for wireguard and IPsec clients using the IP address set in step 1 as DNS server IP.

So now when you do a DNS query while connected to VPN, dns query will be sent to 172.20.251.11 and the dns reply packets will have their source ip set to either from 10.19.49.1 or 10.19.48.1 depending on the vpn you are on.

By default, algo sets up dnsmasq forwarding to dnscrypt-proxy for adblocking setup or just dnscrypt-proxy for setup without adblocking. Neither of them have this issue as they seem to set 172.20.251.11 as source IP when queried from wireguard or ipsec connection.

Expected Behavior

Adguard sets the source IP of dns reply with the destination IP address of original request so there is no longer a mismatch of source IP. This behaviour could be an option in config file.

Actual Behavior

❯ dig google.com
;; reply from unexpected source: 10.19.49.1#53, expected 172.20.251.11#53

Screenshots

No screenshots but interface & route details.

Interfaces For some reason, strongswan virtual interface doesn't show up in interface details.
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet 172.20.251.11/32 scope global lo
       valid_lft forever preferred_lft forever
    inet6 fd00::4:fb0b/128 scope global
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host
       valid_lft forever preferred_lft forever
2: ens3: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000
    link/ether 56:00:02:a0:31:ce brd ff:ff:ff:ff:ff:ff
    inet 95.179.195.xxx/23 brd 95.179.195.255 scope global dynamic ens3
       valid_lft 80571sec preferred_lft 80571sec
    inet6 2a05:f480:1000:<removed>/64 scope global dynamic mngtmpaddr noprefixroute
       valid_lft 2591716sec preferred_lft 604516sec
    inet6 fe80::5400:2ff:fea0:31ce/64 scope link
       valid_lft forever preferred_lft forever
4: wg0: <POINTOPOINT,NOARP,UP,LOWER_UP> mtu 1420 qdisc noqueue state UNKNOWN group default qlen 1000
    link/none
    inet 10.19.49.1/24 scope global wg0
       valid_lft forever preferred_lft forever
    inet6 fd9d:bc11:4021::1/48 scope global
       valid_lft forever preferred_lft forever
Routing table
default via 95.179.194.1 dev ens3 proto dhcp src 95.179.195.xxx metric 100
10.19.49.0/24 dev wg0 proto kernel scope link src 10.19.49.1
95.179.194.0/23 dev ens3 proto kernel scope link src 95.179.195.xxx
169.254.169.254 via 95.179.194.1 dev ens3 proto dhcp src 95.179.195.xxx metric 100

Additional Information

@szolin
Copy link
Contributor

szolin commented Mar 20, 2020

Neither of them have this issue as they seem to set 172.20.251.11 as source IP when queried from wireguard or ipsec connection.

I doubt they do it by themselves, because it's the OS who sets the source IP address for the outcoming UDP packet.
Maybe they work because they listen on each interface separately, and AGH listens on 0.0.0.0. And maybe in this case OS routing mechanism is slightly different - but I'm not sure. Can you show network packets printed by tcpdump?

Anyway, there's nothing we can do at the moment with this issue.
You should configure AGH to listen on the correct network interface - otherwise it will always respond with the source IP address equal to its network interface address.

@emlimap
Copy link
Author

emlimap commented Mar 20, 2020

I did take a further look and you were right with your assumption. dnscrypt-proxy does bind to just the loopback interface.

I had to rebuild the vm so the loopback IP changed to 172.25.100.235 as the algo ansible playbook generates one on the fly. Everything else is the same

# netstat -lnptu | grep dnscrypt-proxy
tcp        0      0 172.25.100.235:53       0.0.0.0:*               LISTEN      4255/dnscrypt-proxy
tcp6       0      0 fd00::9:64eb:53         :::*                    LISTEN      4255/dnscrypt-proxy
udp        0      0 172.25.100.235:53       0.0.0.0:*                           4255/dnscrypt-proxy
udp6       0      0 fd00::9:64eb:53         :::*                                4255/dnscrypt-proxy

TCP Dump

16:51:10.546680 IP 10.19.49.4.59397 > 172.25.100.235.53: 37243+ [1au] A? google.com. (39)
16:51:10.547619 IP 172.25.100.235.53 > 10.19.49.4.59397: 37243 1/0/1 A 216.58.211.174 (55)
16:51:17.175061 IP 10.19.49.4.49577 > 172.25.100.235.53: 55110+ [1au] A? adguard.com. (40)
16:51:17.189852 IP 172.25.100.235.53 > 10.19.49.4.49577: 55110 2/0/1 A 104.20.30.130, A 104.20.31.130 (72)

I have also been testing out nextdns which does have similar issue with their current release build but it looks like someone already opened a bug report (nextdns/nextdns#101) few days ago and it has been addressed. Their client is also written in go and this is how they fixed it

The solution is to set the source addr to the dest addr of the incoming packet. It’s easy to fix.

Below is the nextdns build with code in master branch which includes the fix

# netstat -lnptu | grep nextdns
tcp6       0      0 :::53                   :::*                    LISTEN      18734/nextdns
udp6       0      0 :::53                   :::*                                18734/nextdns

tcpdump for nextdns

17:05:43.163112 IP 10.19.49.4.60362 > 172.25.100.235.53: 56953+ [1au] A? adguard.com. (40)
17:05:43.171092 IP 172.25.100.235.53 > 10.19.49.4.60362: 56953 2/0/1 A 104.20.30.130, A 104.20.31.130 (72)
17:05:47.146619 IP 10.19.49.4.59224 > 172.25.100.235.53: 29707+ [1au] A? google.com. (39)
17:05:47.149404 IP 172.25.100.235.53 > 10.19.49.4.59224: 29707 1/0/1 A 172.217.17.78 (55)
17:05:50.800907 IP 10.19.49.4.61469 > 172.25.100.235.53: 31067+ [1au] A? github.com. (39)
17:05:50.803229 IP 172.25.100.235.53 > 10.19.49.4.61469: 31067 1/0/1 A 140.82.118.3 (55)

@ameshkov
Copy link
Member

Interesting, their solution makes sense: nextdns/nextdns@51c5ea3

@wilsonfr4nco
Copy link

If you are using DNS server like UNBOUND, go to /etc/unbound/unbound.conf.

find line like: # interface: x.x.x.x
use only ip address on your loopback, any others just put down.
like this:

interface: 172.20.251.11

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants