Overview
DNS poisoning is one of the most common cause of nuisance when accessing websites
that are outside this 1.4 billion-people Oriental country. So far, the best way to protect yourself from this trouble is to route all your DNS traffic through an encrypted channel, and the method I am going to introduce is DNSCrypt. There is not yet a standard for encrypted DNS, DNSCrypt is a project done by OpenDNS. According my experience, DNSCrypt is very reliable and robust, the cryptography of the protocol is called DNSCurve, which is a public-key crypto that employes an extremely strong elliptic-curve cryptography called Curve25519.
If you have read my previous writing, you should know my setup is a Raspberry Pi, and so the rest of this article is based on that, running Raspbian. Dnsmasq will be used as the first DNS caching proxy to serve incoming DNS queries from machines on the network. If the queried domain name is a China one, the request will be served by a China DNS. This is necessary because for some domains, answers from DNS servers in China and global ones could be different. If the requested domain does not belong to any known China domains, the request will be forwarded to dnscrypt-proxy
, which will ask a DNSCrypt server for an answer.
After DNSCrypt is used, your DNS traffic will look like this:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
+----------------------+ | China DNS server | +----> | | | | e.g. 114.114.114.114 | China +----------------------+ domains | +-----|---------------------------------+ | +-------+ Other +----------------+| +------+ | |dnsmasq|---------->| dnscrypt-proxy || | Host |-- DNS query --> | +-------+ domains +----------------+| +------+ | | | | Raspberry Pi | | +------------------------------|--------+ V +---------------+ |DNSCrypt server| +---------------+ |
Setting up DNSCrypt
As illustrated in the above diagram, dnscrypt-proxy
is the piece of software that handles DNSCrypt, but it is not available in Raspbian’s Wheezy and Jessie releases, only in testing (currently Stretch). You can either compile it yourself, or grab the debian package I built and install it. You can find the package here. It is based on the Raspbian package in testing repo, with some modification to debian packaging files, since the one in testing depends on systemd, which had not yet been adopted when Wheezy was released.
If you really want to build the package yourself, first install the libsodium packages. The package are also not available in Wheezy repo but the ones from testing, libsodium13_1.0.3-1_armhf.deb and libsodium-dev_1.0.3-1_armhf.deb, can be installed without any problem. Download and install them, then follow these steps to build your dnscrypt-proxy
package:
1 2 3 4 |
$ sudo apt-get install autotools-dev debhelper pkg-config $ git clone https://github.com/anthonywong/dnscrypt-proxy-raspbian-wheezy.git $ cd dnscrypt-proxy-raspbian-wheezy.git $ fakeroot debian/rules binary |
After dnscrypt-proxy
is installed, you have to update the port it uses. Change DNSCRYPT_PROXY_LOCAL_ADDRESS
in /etc/default/dnscrypt-proxy
to another port other than 53 (as it will be used by dnsmasq
later), like this:
1 |
DNSCRYPT_PROXY_LOCAL_ADDRESS=127.0.0.1:5353 |
You can also change the remote DNSCrypt server, but since the default (cisco) works well for me, I left it unchanged.
Now test it to make sure it works as expected:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 |
$ dig @localhost -p 5353 www.facebook.com ; <<>> DiG 9.8.4-rpz2+rl005.12-P1 <<>> @localhost -p 5353 www.facebook.com ; (2 servers found) ;; global options: +cmd ;; Got answer: ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 9735 ;; flags: qr rd ra; QUERY: 1, ANSWER: 2, AUTHORITY: 0, ADDITIONAL: 1 ;; OPT PSEUDOSECTION: ; EDNS: version: 0, flags:; udp: 4096 ;; QUESTION SECTION: ;www.facebook.com. IN A ;; ANSWER SECTION: www.facebook.com. 2725 IN CNAME star-mini.c10r.facebook.com. star-mini.c10r.facebook.com. 47 IN A 31.13.77.36 ;; Query time: 140 msec ;; SERVER: 127.0.0.1#5353(127.0.0.1) ;; WHEN: Mon Jan 18 00:39:36 2016 ;; MSG SIZE rcvd: 90 $ dig @localhost -p 5353 www.sina.com.cn ; <<>> DiG 9.8.4-rpz2+rl005.12-P1 <<>> @localhost -p 5353 www.sina.com.cn ; (2 servers found) ;; global options: +cmd ;; Got answer: ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 22371 ;; flags: qr rd ra; QUERY: 1, ANSWER: 5, AUTHORITY: 0, ADDITIONAL: 1 ;; OPT PSEUDOSECTION: ; EDNS: version: 0, flags:; udp: 4096 ;; QUESTION SECTION: ;www.sina.com.cn. IN A ;; ANSWER SECTION: www.sina.com.cn. 2733 IN CNAME jupiter.sina.com.cn. jupiter.sina.com.cn. 3580 IN CNAME region.sina.csglb.txcdn.cn. region.sina.csglb.txcdn.cn. 1261 IN CNAME n2wous.panthercdn.com. n2wous.panthercdn.com. 20 IN A 103.4.200.227 n2wous.panthercdn.com. 20 IN A 103.4.200.235 ;; Query time: 125 msec ;; SERVER: 127.0.0.1#5353(127.0.0.1) ;; WHEN: Mon Jan 18 00:38:25 2016 ;; MSG SIZE rcvd: 171 |
Setting up dnsmasq
Dnsmasq
is very common and is available in Raspbian, installing it is easy:
1 |
$ sudo apt-get install dnsmasq |
Now we have to do some configuration in /etc/dnsmasq.conf
. These are my recommended settings. Please note that the interface
option is the network interface that dnsmasq
will serve, and in my case that is wlan0
. You have to change it to the one that applies to your case.
1 2 3 4 |
domain-needed bogus-priv no-resolv interface=wlan0 |
Now comes the interesting part. We are going to tell dnsmasq
to use a China DNS server (114.114.114.114 in my example) for China domains and DNSCrypt server for all others. This is done by using the server
option in /etc/dnsmasq.conf
. Here is an example:
1 2 3 4 5 6 7 8 9 |
# Add other name servers here, with domain specs if they are for # non-public domains. server=/baidu.com/114.114.114.114 server=/sina.com/114.114.114.114 server=/ifeng.com/114.114.114.114 server=/phoenixtv.com/114.114.114.114 ... server=/deppon.com/114.114.114.114 server=127.0.0.1#5353 |
This is pretty straightforward. The last line tells dnsmasq to use your dnscrypt proxy if the domain you query does not match any China domains. In my config file there are 12238 lines for China domains so I’m not going to post them all here, you can get the snippet of my dnsmasq.conf
here, and put it into your own dnsmasq.conf
. The problem is to maintain the list for all China hosts. I am now using the list from the fqrouter project, it has been serving me well, since most common domains are already there. What’s worrying is due to the abandon of the project by it’s author, the list is now unmaintained. If you know a more updated list, please let me know!