Assume you already have a Raspberry Pi configured as a WIFI router like mine shown below, but you live in China and have to deal with the fact that many websites can’t be accessed due to GFW. Don’t be despair and with some hacking you can get your Internet freedom back.
The mechanism is to use shadowsocks on your router which directs any traffic to a shadowsocks server in the free world. It’s simple to get it up and running on a local machine, but on a router you need to use redsocks to redirect traffic to the shadowsocks client running on your Raspberry Pi. DNS traffic has to be routed by redsocks as well otherwise your DNS replies will be contaminated. To remain as fast as normal when accessing China websites you also need to skip routing traffic to Redsocks for anything within the China IP ranges. Even if you don’t care about performance, this is still necessary in some circumstances like geoip restriction such as tv.sohu.com does not deliver contents if you live outside of China.
Finally, we want to improve the performance even further by using ChinaDNS. To avoid DNS poisoning, we can always resolve DNS over our secured shadowsocks connection, but this is not optimal if a China website have CDNs outside China. ChinaDNS queries local DNS servers to resolve Chinese domains and queries foreign DNS servers to resolve foreign domains, and from my testing it is useful to avoid DNS poisoning with the “DNS compression pointer mutation” option. (Update: I have switched from ChinaDNS to dnsmasq+dnscrypt, please read Securing DNS Traffic in China to see how it works.)
Shadowsocks
I assume that you have shadowsocks server running on a public server, so I will skip that part and only talk about the client side.
Installing shadowsocks is very simple, note that it will be installed under /usr/local/.
1 2 3 4 5 6 7 8 9 10 11 12 |
pi@raspberrypi $ sudo apt-get install python-pip pi@raspberrypi $ sudo pip install shadowsocks Downloading/unpacking shadowsocks Running setup.py egg_info for package shadowsocks Installing collected packages: shadowsocks Running setup.py install for shadowsocks Installing sslocal script to /usr/local/bin Installing ssserver script to /usr/local/bin Successfully installed shadowsocks Cleaning up... |
Start up shadowsocks while listening on local port 1080:
1 |
pi@raspberrypi $ sslocal -s <shadowsocks server IP> -p <shadowsocks server port> -k <password> -b 127.0.0.1 -l 1080 |
Redsocks
Install redsocks, simply apt-get from the archive:
1 |
pi@raspberrypi $ sudo apt-get install redsocks |
Then you need to change the START option in /etc/default/redsocks from NO to YES, so that redsocks will start automatically at boot time and also can be started by sudo /etc/init.d/redsocks start:
1 2 |
pi@raspberrypi $ sudo vi /etc/default/redsocks START=yes |
Then update /etc/redsocks.conf. Most of the default settings work fine, just need to change local_ip in the redsocks section to your address of the network interface that accepts traffic from your local network. The default is 127.0.0.1, but that does not work well if you want to re-route traffic from other machines on your network, so change it to something like:
1 2 3 4 5 6 7 8 9 |
redsocks { /* `local_ip' defaults to 127.0.0.1 for security reasons, * use 0.0.0.0 if you want to listen on every interface. * `local_*' are used as port to redirect to. */ local_ip = 192.168.0.1; local_port = 12345; ... } |
But we want traffic from other hosts in your network to be redirected by redsocks to your local shadowsocks client, which in turn sent to the the remote shadowsocks server. We need to pay special attention to DNS traffic, as DNS poisoning is prevalent in China. We need to take special care to redirect DNS traffic through redsocks/shadowsocks.
We also want all China traffic NOT to go through shadowsocks for performance. This can be easily done by looking at the destination IP, if it is in the China IP range we skip going through the REDSOCKS china. First we need to get all network segments allocated to China and save it to a file called chnroute.txt:
1 |
pi@raspberrypi $ curl 'http://ftp.apnic.net/apnic/stats/apnic/delegated-apnic-latest' | grep ipv4 | grep CN | awk -F\| '{ printf("%s/%d\n", $4, 32-log($5)/log(2)) }' > chnroute.txt |
These all can be accomplished by iptables. You need to run the following iptables commands, or put them in a local script and run it with sudo.
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 |
# Specify your shadowsocks server SS_SERVER_IP=11.22.33.44 iptables -t nat -N REDSOCKS # Create a new chain called REDSOCKS # Do not redirect to shadowsocks server iptables -t nat -A REDSOCKS -d $SS_SERVER_IP -j RETURN # Do not redirect local traffic iptables -t nat -A REDSOCKS -d 0.0.0.0/8 -j RETURN iptables -t nat -A REDSOCKS -d 10.0.0.0/8 -j RETURN iptables -t nat -A REDSOCKS -d 127.0.0.0/8 -j RETURN iptables -t nat -A REDSOCKS -d 169.254.0.0/16 -j RETURN iptables -t nat -A REDSOCKS -d 172.16.0.0/12 -j RETURN iptables -t nat -A REDSOCKS -d 192.168.0.0/16 -j RETURN iptables -t nat -A REDSOCKS -d 224.0.0.0/4 -j RETURN iptables -t nat -A REDSOCKS -d 240.0.0.0/4 -j RETURN # China traffic does not go through REDSOCKS while read subnet; do sudo iptables -t nat -A REDSOCKS -d $subnet -j RETURN done < /tmp/chnroute.txt # Redirect all TCP traffic to redsocks, which listens on port 12345 iptables -t nat -A REDSOCKS -p tcp -j REDIRECT --to-ports 12345 # These traffic go to REDSOCKS chain first iptables -t nat -A PREROUTING -p tcp -j REDSOCKS |
Run iptables -t nat -L -n to make sure the rules have been added correctly. Now start up redsocks by sudo /etc/init.d/redsocks start and let’s test it out by doing some web browsing on another computer in your local network. If that works fine, congratulations and you have set up everything correctly! If not, look at shadowsocks output and also turn on redsock’s log_debug and check if there is anything useful in /var/log/daemon.log.
ChinaDNS
ChinaDNS is not absolutely necessary, but as explained at the beginning it is desirable. There is no pre-built package so we need to compile it. It is simple to do:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
pi@raspberrypi $ sudo apt-get install git automake pi@raspberrypi $ git clone https://github.com/clowwindy/ChinaDNS.git Cloning into 'ChinaDNS'... remote: Counting objects: 815, done. remote: Compressing objects: 100% (5/5), done. remote: Total 815 (delta 0), reused 0 (delta 0), pack-reused 810 Receiving objects: 100% (815/815), 213.52 KiB | 111 KiB/s, done. Resolving deltas: 100% (426/426), done. pi@raspberrypi $ ./autogen.sh pi@raspberrypi $ ls aclocal.m4 autom4te.cache chnroute.txt configure COPYING install-sh Makefile.am missing packaging src autogen.sh CHANGES config.h.in configure.ac depcomp iplist.txt Makefile.in openwrt README.md tests pi@raspberrypi $ ./configure ... pi@raspberrypi $ make ... |
After it is successfully compiled, test it out:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
pi@raspberrypi $ sudo src/chinadns pi@raspberrypi $ host video.sina.com.cn video.sina.com.cn has address 58.63.237.200 pi@raspberrypi $ host www.youtube.com www.youtube.com is an alias for youtube-ui.l.google.com. youtube-ui.l.google.com is an alias for youtube-ui-china.l.google.com. youtube-ui-china.l.google.com has address 46.82.174.68 youtube-ui-china.l.google.com has IPv6 address 2404:6800:4005:80b::200e pi@raspberrypi $ sudo src/chinadns -m -c chnroute.txt pi@raspberrypi $ host video.sina.com.cn video.sina.com.cn has address 123.125.22.225 pi@raspberrypi $ host www.youtube.com www.youtube.com is an alias for youtube-ui.l.google.com. youtube-ui.l.google.com is an alias for youtube-ui-china.l.google.com. youtube-ui-china.l.google.com has address 74.125.203.138 youtube-ui-china.l.google.com has address 74.125.203.100 youtube-ui-china.l.google.com has address 74.125.203.113 youtube-ui-china.l.google.com has address 74.125.203.139 youtube-ui-china.l.google.com has address 74.125.203.101 youtube-ui-china.l.google.com has address 74.125.203.102 youtube-ui-china.l.google.com has IPv6 address 2404:6800:4005:808::200e |
If it goes well, run src/chinadns -m -c chnroute.txt when your router boots.
That’s it! I hope these are useful to you.
Update: I have switched from ChinaDNS to dnsmasq+dnscrypt, please read Securing DNS Traffic in China to see how to set it up.
What DNS server do you run on the pi? bind? Does it “just work” with redsocks?
I am now using ChinaDNS as shown here. Before I used dnsmasq.
Blog is very helpful for navigation of CN Internet. You have my humble thanks for the time you spend creating,
I just wanted to check. But it looks like you are getting your wan connection through your ethernet and broadcasting wifi with shadowsocks. Correct?
Yes that’s correct.
Great manual, but unfortunately I cannot get it running. Something is wrong with the routing. It connects well to the SS Server, and redsocks also brings no error. But I do not get any result. No browsing, no HTTP page, nothing. Really not knowing how to find the issue and how to debug. Can you help here with some hints where to start? Thanks so much.
Anthony,
Thanks for the detailed post. Will there be an update of this blog? I run Raspbian Stretch on Raspberry Pi 3 + B and do not think this amazing and detailed info will run on stretch.
Thanks