Wednesday, September 14 2011

Tokyo Surfing

[Note: this is one of those “braindump so I don’t miss a step when I tell someone how to do it” posts]

Let’s say that you’ve come across a web site that refuses to serve up its content to people located outside of a certain geographical region. For instance, “Japan” (or UK for BBC streams, etc).

There are two basic ways to go about this: pointing your web browser at an HTTP/HTTPS proxy service that’s located in Japan, or opening a VPN connection to a server in Japan. I chose the second method, in part because it isn’t limited to web traffic (allowing you to do things like bypass your ISP’s outgoing SMTP blocking), and in part because I already knew how.

My weapons of choice were Amazon EC2, OpenVPN (free Community Edition, easy-rsa, OpenVPN GUI for Windows, and Tunnelblick for Mac), and DynDNS plus ddclient.

Step 1: sign up for Amazon EC2 service, select the Tokyo region, and launch a t1.micro instance with the standard 32-bit Amazon Linux, opening UDP port 1194 in the security group. Yes, I realize there’s a whole lot to learn in this step, but the documentation is quite good. When you reach the point where you’ve successfully ssh’d into your new machine and are staring at a root shell, we can continue. And hey, if you’ve always wanted your very own fully-functional Linux server in the cloud, there you go.

Step 2: install the openvpn package, run chkconfig openvpn on, cd to /usr/share/openvpn/easy-rsa/2.0, and follow the “Typical usage for initial PKI setup” instructions at the very end of the README (you need to generate one server and at least one client key), with one addition:
    openvpn -‐genkey -‐secret keys/ta.key

Step 3: copy the following files from the keys directory to /etc/openvpn: ca.crt, dh1024.pem, myserver.crt, myserver.key, ta.key. Nail down the file permissions.

Step 4: Create /etc/openvpn/openvpn.conf, containing (note the NAT subnet must be the same in this step and the next one):

ca ca.crt
dh dh1024.pem
cert myserver.crt
key myserver.key
tls-auth ta.key 0
server 192.168.100.0 255.255.255.0
push "redirect-gateway def1 bypass-dhcp"
push "dhcp-option DNS 8.8.8.8"
port 1194
proto udp
dev tun
keepalive 10 120
user nobody
group nobody
persist-key
persist-tun
verb 3
log openvpn.log
ifconfig-pool-persist ipp.txt
status openvpn-status.log

Step 5: Replace the contents of /etc/sysconfig/iptables with the following (note that this allows ICMP, SSH, and OpenVPN; if you decide to use this machine for other services, you’ll need to open them in iptables and in the security group):

*nat
:PREROUTING ACCEPT [0:0]
:OUTPUT ACCEPT [3:268]
:POSTROUTING ACCEPT [3:268]
-A POSTROUTING -s 192.168.100.0/24 -o eth0 -j MASQUERADE 
COMMIT
*filter
:INPUT DROP [0:0]
:FORWARD DROP [0:0]
:OUTPUT ACCEPT [93:11892]
-A INPUT -p icmp -m icmp -‐icmp-type 8 -j ACCEPT 
-A INPUT -p icmp -m icmp -‐icmp-type 18 -j DROP 
-A INPUT -p icmp -m icmp -‐icmp-type 17 -j DROP 
-A INPUT -p icmp -m icmp -‐icmp-type 10 -j DROP 
-A INPUT -p icmp -m icmp -‐icmp-type 9 -j DROP 
-A INPUT -p icmp -m icmp -‐icmp-type 5 -j DROP 
-A INPUT -i tun0 -j ACCEPT 
-A INPUT -i lo -j ACCEPT 
-A INPUT -i eth0 -m state -‐state RELATED,ESTABLISHED -j ACCEPT 
-A INPUT -p icmp -m state -‐state RELATED,ESTABLISHED -j ACCEPT 
-A INPUT -i eth0 -p icmp -m icmp -‐icmp-type 8 -m limit -‐limit 1/sec -j ACCEPT 
-A INPUT -p tcp -m tcp -‐dport 22 -j ACCEPT 
-A INPUT -p udp -m udp -‐dport 1194 -j ACCEPT 
-A INPUT -i eth0 -p tcp -m tcp -j DROP 
-A INPUT -i eth0 -p udp -m udp -j DROP 
-A FORWARD -i tun0 -j ACCEPT 
-A FORWARD -m state -‐state RELATED,ESTABLISHED -j ACCEPT 
-A OUTPUT -o tun0 -j ACCEPT 
-A OUTPUT -o lo -j ACCEPT 
-A OUTPUT -p icmp -m state -‐state NEW -j ACCEPT 
COMMIT

Step 6: turn on packet forwarding so the NAT works, by editing /etc/sysctl.conf:
    net.ipv4.ip_forward = 1

Step 7: Sign up for a free account with DynDNS, install the perl-IO-Socket-SSL package, download a copy of ddclient, unpack it,, and follow the 7-step install instructions in the README, putting the following into /etc/ddclient/ddclient.conf (substituting appropriate values for the placeholders):

daemon=600
syslog=yes
mail-failure=EMAIL
pid=/var/run/ddclient.pid
use=web, web=169.254.169.254/latest/meta-data/public-ipv4
login=USER
password=PASSWD
protocol=dyndns2
server=members.dyndns.org
HOST.dyndns.org

Step 8: reboot your EC2 server; when it comes back up, login to it by its new DynDNS name. If you’re ssh’ing from Linux or a Mac, the following lines in ~/.ssh/config will make your life a little easier:

Host HOST.dyndns.org
User ec2-user 
IdentityFile /myhomedir/.ssh/amazon-key-file.pem
UserKnownHostsFile=/dev/null
StrictHostKeyChecking=no

Step 9: copy the following files from your easy-rsa keys directory down to your client machine, putting them wherever your client tells you: ca.crt, dh1024.pem, client1.crt, client1.key, ta.key.
    TunnelBlick: ~/Library/Application Support/TunnelBlick/Configurations
    OpenVPN GUI: \Program Files\OpenVPN\config

Step 10: create a client config file in the same directory, named openvpn.conf (for Windows, openvpn.ovpn), containing the following, substituting your DynDNS hostname:

client
dev tun
proto udp
remote HOST.dyndns.org 1194
resolv-retry infinite
persist-key
persist-tun
ca ca.crt
cert client1.crt
key client1.key
tls-auth ta.key 1
ns-cert-type server
verb 3

Step 11: fire up your OpenVPN client and surf to some page that will report your current IP address, like DSLReports.com. If everything worked, you can not only reach the outside world, but your IP address will match the current value of your dynamic DNS host name.

Step 12: shut down your EC2 server when you’re not using it. A t1.micro is cheap to run 24x7, but it’s even cheaper 2x4.

Note that with a minor config change, you can set up a split-tunnel VPN with local subnet access, allowing you to do things like securely access another machine that’s connected to the same VPN, wherever it happens to be, without having to open incoming firewall holes, even if they’re both hidden behind NAT routers. Just replace the two “push” lines in the server openvpn.conf with:
    client-to-client