Opened 8 years ago

Last modified 8 years ago

#5345 new Bug

UDP dns request 'reported' on all interfaces even after binding transmission to a specific IP

Reported by: DogJohnson Owned by:
Priority: Normal Milestone: None Set
Component: Daemon Version: 2.77+
Severity: Normal Keywords: DNS UDP bind interface VPN leak
Cc:

Description

I have successfully bound transmission to only use a specific IP address in the settings.json file. This seems to work well for actual torrenting traffic, but when I issue the command 'netstat -ulnp' I get:

udp        0      0 10.0.0.2:33333        0.0.0.0:*        15127/transmission-daemon
udp        0      0 0.0.0.0:35685         0.0.0.0:*        15127/transmission-daemon

While I see that port 33333 (my forwarded port for transmission) is bound to 10.0.0.2 (my tun0 adapter of my VPN), the other port 35685 is a random UDP port not bound to any interface. Using tcpdump (tcpdump -n -i tun0) I was able to determine that this random UDP port originates as an outbound DNS request. My concern is that this '0.0.0.0' could mean that transmission-daemon is able to send out udp dns requests on all interfaces and not just the one it is bound to.

I believe that this DNS request is only using the correct tun0 interface (my firewall log doesn't show any blocked or audit reports of attempts to send DNS queries on any other interface, nor does tcpdump of eth0 for port 53 show any activity), but this could be because of how my internal routing is set up and might not the same for everyone.

I would like to be certain that DNS requests are also bound to the designated interface, evidenced by transmission never showing '0.0.0.0' as its ip if using the bind function. Worst-case scenario being that I am torrenting behind a VPN where my non-vpn'd interface is used to resolve tracker hostnames. This would seem to defeat the purpose.

DJ

I've used 2.77-2 and builds r14057 and r14072 to test this.

Change History (5)

comment:1 Changed 8 years ago by jaseg

I can confirm that this actually does not send the DNS requests over the interface transmission is bound to, as can be seen in the following tcpdump output:

/tmp <3 tcpdump -i eth0 port 53
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on eth0, link-type EN10MB (Ethernet), capture size 65535 bytes
15:37:30.132297 IP dezibel.XXXXXXXX.52378 > dns.XXXXXXXX.domain: 27392+ A? open.nyaatorrents.info. (40)
15:37:30.132309 IP dezibel.XXXXXXXX.52378 > dns.XXXXXXXX.domain: 35545+ AAAA? open.nyaatorrents.info. (40)
15:37:30.132490 IP dezibel.XXXXXXXX.56351 > dns.XXXXXXXX.domain: 12952+ A? open.nyaatorrents.info. (40)
15:37:30.132497 IP dezibel.XXXXXXXX.56351 > dns.XXXXXXXX.domain: 32512+ AAAA? open.nyaatorrents.info. (40)
15:37:30.132530 IP dezibel.XXXXXXXX.33485 > dns.XXXXXXXX.domain: 61152+ A? open.nyaatorrents.info. (40)
15:37:30.132539 IP dezibel.XXXXXXXX.33485 > dns.XXXXXXXX.domain: 15247+ AAAA? open.nyaatorrents.info. (40)
15:37:30.132550 IP dezibel.XXXXXXXX.51175 > dns.XXXXXXXX.domain: 28707+ A? open.nyaatorrents.info. (40)
15:37:30.132556 IP dezibel.XXXXXXXX.51175 > dns.XXXXXXXX.domain: 10001+ AAAA? open.nyaatorrents.info. (40)
15:37:30.132565 IP dezibel.XXXXXXXX.36542 > dns.XXXXXXXX.domain: 57913+ A? open.nyaatorrents.info. (40)
15:37:30.132570 IP dezibel.XXXXXXXX.36542 > dns.XXXXXXXX.domain: 3898+ AAAA? open.nyaatorrents.info. (40)
15:37:30.132823 IP dns.XXXXXXXX.domain > dezibel.XXXXXXXX.52378: 27392 1/2/6 A 188.95.48.67 (188)
15:37:30.132832 IP dns.XXXXXXXX.domain > dezibel.XXXXXXXX.52378: 35545 0/1/0 (98)
15:37:30.132945 IP dns.XXXXXXXX.domain > dezibel.XXXXXXXX.56351: 12952 1/2/6 A 188.95.48.67 (188)
15:37:30.132955 IP dns.XXXXXXXX.domain > dezibel.XXXXXXXX.56351: 32512 0/1/0 (98)
15:37:30.133049 IP dns.XXXXXXXX.domain > dezibel.XXXXXXXX.33485: 61152 1/2/6 A 188.95.48.67 (188)
15:37:30.133057 IP dns.XXXXXXXX.domain > dezibel.XXXXXXXX.33485: 15247 0/1/0 (98)
15:37:30.133060 IP dns.XXXXXXXX.domain > dezibel.XXXXXXXX.51175: 28707 1/2/6 A 188.95.48.67 (188)
15:37:30.133066 IP dns.XXXXXXXX.domain > dezibel.XXXXXXXX.51175: 10001 0/1/0 (98)
15:37:30.133078 IP dns.XXXXXXXX.domain > dezibel.XXXXXXXX.36542: 57913 1/2/6 A 188.95.48.67 (188)
15:37:30.133082 IP dns.XXXXXXXX.domain > dezibel.XXXXXXXX.36542: 3898 0/1/0 (98)

I run transmission as follows:

/usr/bin/transmission-daemon [...] --bind-address-ipv4 10.8.0.190 --bind-address-ipv6 ::1 [...]

I think this can be considered a bug since a) it leaks information if using a VPN and b) it allows DNS-level censoring of torrent trackers.

The remaining traffic is sent nicely encrypted through my VPN.

comment:2 Changed 8 years ago by DogJohnson

I thought this bug was lost forever. That is interesting that it is leaking for you. It is still not for me (that I can see) despite the potential. But if this is true, it I think I should change it to HIGH priority, as it defeats the whole purpose of binding and a VPN.

Two things first:

I am assuming eth0 is not ip 10.8.0.190? I think this is obvious but just to double check...

And then if you did a 'tcpdump -n -i eth0 port 53' (-n to not resolve hostnames) that is definitely shows eth0 as the source ip for the DNS request despite transmission being bound to another interface?

DJ

comment:3 Changed 8 years ago by rb07

The problem is that libcurl is used to communicate with trackers (and other operations, like testing if the peer port is open), and the corresponding option for binding the address used for DNS queries is not used.

From the Curl documentation:

CURLOPT_DNS_INTERFACE Pass a char * as parameter. Set the name of the network interface that the DNS resolver should bind to. This must be an interface name (not an address). Set this option to NULL to use the default setting (don't bind to a specific interface).

This option requires that libcurl was built with a resolver backend that supports this operation. The c-ares backend is the only such one.

(Added in 7.33.0)

CURLOPT_DNS_LOCAL_IP4 Set the local IPv4 address that the resolver should bind to. The argument should be of type char * and contain a single IPv4 address as a string. Set this option to NULL to use the default setting (don't bind to a specific IP address).

This option requires that libcurl was built with a resolver backend that supports this operation. The c-ares backend is the only such one.

(Added in 7.33.0)

CURLOPT_DNS_LOCAL_IP6 Set the local IPv6 address that the resolver should bind to. The argument should be of type char * and contain a single IPv6 address as a string. Set this option to NULL to use the default setting (don't bind to a specific IP address).

This option requires that libcurl was built with a resolver backend that supports this operation. The c-ares backend is the only such one.

Note that using one of these options also means you must use c-ares, which is something Transmission doesn't (can't) force. That means using a special build, not just adding the corresponding option in web.c with the parameter from the settings.

comment:4 Changed 8 years ago by x190

Possible workaround:
use openDNS, e.g. 208.67.220.220, and/or G::gle, e.g. 8.8.4.4, set via network settings, not router. VPN must be disconnected and the openVPN daemon stopped first. If your VPN connection app has a 'route all traffic through the VPN' option, check that as well. https://www.dnsleaktest.com, (extended test) will only see their nameservers and eth0, or en0 (os x), should be clean for port 53.

comment:5 Changed 8 years ago by jaseg

Another workaround would be to set up a separarte routing table for the VPN and send all traffic from transmission-daemon's UID through that table using some iptables magic.

Note: See TracTickets for help on using tickets.