2013-06-01

On Use of CurveCP as a UDP Tunnel for DNS Client Traffic to the Resolver

Caveat: CurveCP is currently in early public alpha release. Proceed at your own risk.

Assume for a second that you have DNSCurve running on your DNS resolver at home. (Accomplishing this requires a combination of setting up the NaCl networking and cryptography library as well as Matthew Dempsky's djbdns dnscurve patch on that machine.) Works great. Now what?

At some point you are probably going to find yourself in a coffeeshop or a Kinko's or some other place with free wi-fi and even if you happen to have a DNSCurve-capable DNS resolver installed on your laptop, you're only going to have encryption for the packets that are going to DNSCurve-enabled authoritative DNS servers out there, of which there aren't yet very many. (In May 2013, there were 39 amongst all of the .com, .net, and .org zones comprising a total of 370 domains (or 0.00027% of the Internet). I know. I checked.)

This leaves you with a bit of a conundrum: your connection to the Internet is pretty much fair game for people who want to sniff your DNS traffic. This is hardly news because nearly all DNS traffic is unencrypted and has been for decades. DNS was not designed with security in mind, let alone secrecy. There's this extension called DNSSEC, but it is a signing system and was deliberately designed to not encrypt its data. What you want at the very least is to encrypt your queries to the resolver, even if your resolver is sending out unencrypted queries. For the vast majority of unencrypting DNS servers, your traffic is still visible. You want to surf for porn in peace using a combination of HTTPS, a browser with history-tracking disabled, and DNSCurve. Unless the porn sites are using DNSCurve on their servers they use to send their IP addresses to your laptop, your DNS queries are unencrypted and openly visible to anyone watching. (No joke: many of the DNSCurve-enabled DNS servers in my May 2013 survey are hosts for porn domains, primarily phone sex related.) What to do? You can't force your porn sites to install a DNSCurve forwarder for you. You could switch your fetish to phone sex lines, perhaps. Rather than curse the darkness, I choose instead to light a candle. We have two options.

First, you can run DNSCrypt. DNSCrypt is a fun little proxy that will encrypt your DNS client queries to a specially-configured resolver. This is the traffic that typically goes directly from your device to the IP address in /etc/resolv.conf or equivalent. If this IP is 127.0.0.1 for you, you are relatively secure in knowing that your queries aren't being broadcast but most computers don't run their own DNS resolvers yet. Usually the DNS resolver IP address that you're assigned when using free wi-fi is the IP address of the wireless access point itself. With a DNSCrypt proxy running on your machine, your "resolver" becomes 127.0.0.1, which accepts your queries and automatically encrypts them and forwards them to OpenDNS, which are the sponsors of the tool. If you trust OpenDNS not to notice or care what you're surfing for, this is a very fast solution and will effectively thwart anyone in the vicinity who is running Wireshark and looking at UDP port 53.

Personally, I like OpenDNS. I think it's a good company with a sincere interest in protecting their users and general Internet freedom as a whole. Still, I wanted another way. If I'm running my own DNS resolver at home, it seemed feasible to me that I could forward all of my queries from anywhere I happened to be over to it with a CurveCP tunnel. The tunneling used herein is uncomplicated, but I hit a snag in implementing it properly due to the syntax of the UDP-tunneling software and the fact I found it all-too-easy to misunderstand its documentation.

Using the NaCl reference README as a guide, you can set up an alpha-test implementation of a CurveCP server in two lines. Assuming your DNS resolver is running on 10.0.0.1:

curvecpmakekey serverkey
curvecpserver this.machine.name serverkey \
  10.0.0.1 10000 31415926535897932384626433832795 \
  curvecpmessage socat udp:10.0.0.1:53,reuseaddr - &

Important point to make here: socat is terrific for this kind of thing and I'm taking steps to replace all of my existing uses of netcat with it in the future. It runs on multiple platforms, there's a Cygwin port for it, there really isn't much that it can't do.

Running the above command on your DNS server is easy enough. You'll now have a UDP server listening on 10.0.0.1:10000, which you'll have to expose to the Internet somehow. If you're running pf, add this line where applicable:

pass in log quick on $ext_if inet proto udp from any to any port = 10000 keep state rdr-to 10.0.0.1

If you don't have $ext_if defined in /etc/pf.conf, substitute it with the name of the interface on which you're filtering.

Grab the hexadecimal string of your server key while you're at it:

curvecpprintkey serverkey > serverkey.hex

Keep a copy of this file on you. Back in the coffeeshop, on your laptop where you've got the alpha CurveCP binaries set up, you'll want to run something that looks a little like this:

curvecpclient this.machine.name $(cat serverkey.hex) \
  1.2.3.4 10000 31415926535897932384626433832795 \
  curvecpmessage -C sh -c "exec socat udp4-recvfrom:53,bind=127.0.0.53,reuseaddr,fork - <&6 >&7"

Note that socat is using udp4-recvfrom and NOT udp4-listen. This mistake cost me more time debugging the solution than I care to admit. Joy was finally made apparent to me courtesy of a page about tunneling UDP over TCP over SSH over an HTTPS proxy written by Wicher Minnaard who very succintly points out that udp4-listen does not know when to stop listening and udp4-recvfrom doesn't allow anything to keep listening beyond the first packet. In general DNS queries are single-packet conversations each way, so udp4-recvfrom is the correct socat argument to use here.

So if you're running your alpha-test CurveCP server on your home DNS resolver with IP address 1.2.3.4 (which is NATed to 10.0.0.1) eavesdroppers will see encrypted packets leaving your laptop bound for 1.2.3.4:10000 and you'll get encrypted responses from that IP address. Since you've set up socat to bind to the local IP address and port 127.0.0.53:53 you can run this alongside any local DNS resolver you may be running on your laptop on 127.0.0.1:53, just be sure to have your resolver forward all of its queries to 127.0.0.53 to take advantage of your CurveCP-tunneled DNS forwarder.

Until there is ubiquitous encryption of DNS traffic implemented between servers and resolvers, someone somewhere is going to know you're searching for the addresses for Redtube and The Pirate Bay. After you've implemented encryption between your client and the resolver, it won't be the dweeb sitting two tables over from you with a latte in one hand and tcpdump running in the other.

(Another option I didn't really consider is to use a dnscrypt wrapper for your resolver and point your dnscrypt proxy at it. I didn't test this because I'd rather use something closer to a pure CurveCP tunnel than DNSCurve-specific proxyware. Personal preference; your actual mileage may vary.)

No comments: