Scott O'Brien

Easily accessing GeoIP restricted sites in your network.

Created: 6/3/2012, 11:05:05 AM

We all know the problem, some sites are restricted to certain countries based on the IP address you're using to view them.  When trying to access over-seas, some solutions are HTTP proxies, Socks proxies and the like.  The problem I have with all of these is that they're annoying to set up whenever you want to to view the site and I don't want to have to do that for all my devices (iPad, computer, etc).

This solution will tunnel only the sites you want over a VPN connection to be NAT'd out the other end, all on the gateway

Network Config

First we want to set up OpenVPN on the remote host by issuing “openvpn –genkey –secret static.key” then creating a file in (/etc/openvpn/server.conf)

# Network
port 1194
proto tcp-server
dev tun
ifconfig 10.0.6.1 10.0.6.2

# Crypto
secret /etc/openvpn/static.key
comp-lzo
keepalive 10 120

# Security
persist-key
persist-tun

# Logging
status openvpn-status.log

One thing we need to do on the server is set up NAT on the outbound address (to make sure all traffic that passes our VPS destined for the internet looks like it's from that US IP address)

# Previously initiated and accepted exchanges bypass rule checking
# Allow unlimited outbound traffic
/sbin/iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
/sbin/iptables -A OUTPUT -m state --state NEW,ESTABLISHED,RELATED -j ACCEPT

iptables -t nat -A POSTROUTING -s 10.0.6.0/24 -o eth0 -j MASQUERADE
echo 1 > /proc/sys/net/ipv4/ip_forward

On the client side, things look very similar,

remote vps.server.com 1194 tcp-client
persist-key
comp-lzo no
redirect-gateway def1
nobind
persist-tun
secret secret.key
dev tun
ifconfig 10.0.6.2. 10.0.6.1

On the client, I just also MASQUERADE'd data though (I know, double NAT'ing, easier then adjusting routing table on the VPS)

Now for the magic to happen. I just replaced the DNS server on my home router with a little Python script (❤️ Twisted framework) to proxy requests, adding a tunnel for IP's that get returned by sites in my list (in this case I've chosen two fictious sites, HooLoo.com and pandoor.com

from twisted.internet.protocol import Factory, Protocol
from twisted.internet import reactor
from twisted.names import dns
from twisted.names import client, server
import subprocess
from sys import exit

tunnelDomains = [
  "pandoor.com",
  "hooloo.com"
]
dnsServers = [("203.12.160.35", 53), ("203.12.160.36", 53)]

def tunnel(address):
       subprocess.call(["route", "add", address + "/32", "tun0"])  

class SpelDnsReolver(client.Resolver):
  def filterAnswers(self, message):
    if message.trunc:
      return self.queryTCP(message.queries).addCallback(self.filterAnswers)
    else:
      for d in tunnelDomains:
        if str(message.queries[0].name).endswith(d):
          for answer in message.answers:
            if answer.type == 1: #A record
              tunnel(answer.payload.dottedQuad())

    return (message.answers, message.authority, message.additional)

verbosity = 0
resolver = SpelDnsReolver(servers=dnsServers)
f = server.DNSServerFactory(clients=[resolver], verbose=verbosity)
p = dns.DNSDatagramProtocol(f)
f.noisy = p.noisy = verbosity

reactor.listenUDP(53, p)
reactor.listenTCP(53, f)
reactor.run()