moby / vpnkit

A toolkit for embedding VPN capabilities in your application
Apache License 2.0
1.09k stars 182 forks source link

VPNKit DNS server returns NXDOMAIN for SRV records #509

Open AkihiroSuda opened 3 years ago

AkihiroSuda commented 3 years ago

VPNKit DNS server returns NXDOMAIN for SRV records

$ rootlesskit --net=vpnkit dig -t srv _imaps._tcp.gmail.com
WARN[0000] specifying --disable-host-loopback is highly recommended to prohibit connecting to 127.0.0.1:* on the host namespace (requires slirp4netns or VPNKit) 
WARN[0000] Mounting /etc/resolv.conf without copying-up /etc. Note that /etc/resolv.conf in the namespace will be unmounted when it is recreated on the host. Unless /etc/resolv.conf is statically configured, copying-up /etc is highly recommended. Please refer to RootlessKit documentation for further information. 

; <<>> DiG 9.16.1-Ubuntu <<>> -t srv _imaps._tcp.gmail.com
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NXDOMAIN, id: 870
;; flags: qr rd ra; QUERY: 1, ANSWER: 0, AUTHORITY: 0, ADDITIONAL: 0

;; QUESTION SECTION:
;_imaps._tcp.gmail.com.         IN      SRV

;; Query time: 0 msec
;; SERVER: 192.168.65.1#53(192.168.65.1)
;; WHEN: Mon Aug 31 20:02:57 JST 2020
;; MSG SIZE  rcvd: 39

OTOH slirp4netns DNS works as expected:

$ ./rootlesskit --net=slirp4netns dig -t srv _imaps._tcp.gmail.com
WARN[0000] specifying --disable-host-loopback is highly recommended to prohibit connecting to 127.0.0.1:* on the host namespace (requires slirp4netns or VPNKit) 
WARN[0000] Mounting /etc/resolv.conf without copying-up /etc. Note that /etc/resolv.conf in the namespace will be unmounted when it is recreated on the host. Unless /etc/resolv.conf is statically configured, copying-up /etc is highly recommended. Please refer to RootlessKit documentation for further information. 

; <<>> DiG 9.16.1-Ubuntu <<>> -t srv _imaps._tcp.gmail.com
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 34903
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 65494
;; QUESTION SECTION:
;_imaps._tcp.gmail.com.         IN      SRV

;; ANSWER SECTION:
_imaps._tcp.gmail.com.  5       IN      SRV     5 0 993 imap.gmail.com.

;; Query time: 15 msec
;; SERVER: 10.0.2.3#53(10.0.2.3)
;; WHEN: Mon Aug 31 20:04:05 JST 2020
;; MSG SIZE  rcvd: 84

VPNKit version: v0.4.0 RootlessKit version: v0.10.0

Originally reported by @hawicz in https://github.com/moby/libnetwork/issues/2574

joanbm commented 1 year ago

I am running into the same problem, but with AAAA records instead. And in particular, it seems to break DNS resolution for IPv4-hosts for Alpine Linux containers started inside a docker:dind-rootless container, since it seems musl considers that getting a NXDOMAIN response for an AAAA query means that the entire query should fail even though the A query returns a valid list of IP addresses.

I was going to open a new issue and found this one at the last minute, so here's my writeup/analysis for it:

Steps to reproduce

The easiest way I have found to reproduce the issue is as follows:

  1. Install rootful Docker using the official distribution and instructions, for example over Ubuntu Server 22.04

  2. Run the docker:dind-rootless image:

    $ sudo docker run -d --name dind --privileged --env DOCKER_TLS_CERTDIR="" docker:24.0.2-dind-rootless --tls=false
  3. Launch an Alpine Linux container inside it, and try to resolve an IPv4-only domain:

    $ sudo docker exec -it dind env DOCKER_HOST=tcp://localhost:2375 docker run --rm -it alpine:3.18 wget http://ipv4.tlund.se -O /dev/null

Further tests

Some further tests tell us more about the nature of the problem, and why I believe it's related to VPNKit:

Potential cause: NXDOMAIN for AAAA records

I believe that the problem is that when you run an AAAA query for a domain without any AAAA records inside rootlesskit+vpnkit, you get an invalid NXDOMAIN response:

$ sudo docker exec -it -u 0 dind apk add bind-tools
$ sudo docker exec -it dind rootlesskit --net=vpnkit dig ipv4.tlund.se AAAA | grep status
;; ->>HEADER<<- opcode: QUERY, status: NXDOMAIN, id: 60429

While if you run it without vpnkit or with slirp4netns, you get a NOERROR response:

$ sudo docker exec -it dind dig ipv4.tlund.se AAAA | grep status
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 54463
$ sudo docker exec -it dind rootlesskit --net=slirp4netns dig ipv4.tlund.se AAAA | grep status
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 41316

It appears that the musl DNS resolver will fail the resolution once it sees that NXDOMAIN response for the AAAA records, failing the entire resolution.

I have not yet had time to figure out why we're getting a NXDOMAIN response after we add VPNKit (or what the specs say about those weird cases), but at first glance it seems like it should return NOERROR instead.

joanbm commented 1 year ago

At least for AAAA queries, the NXDOMAIN appears to come from those two lines: https://github.com/moby/vpnkit/blob/dc331cb22850be0cdd97c84a9cfecaf44a1afb6e/src/hostnet/hostnet_dns.ml#L449-L450, which seem to be turning a response with no answers into a NXDOMAIN.