Automatic US / UK VPN connection with XBMC, iPlayer, Hulu and Free Cable

XBMC has addons for various geolocked services, Hulu and iPlayer being among most popular. Switching between VPN connections manually gets boring quick so I hacked following script that will automatically connect and disconnect VPN to US / UK on demand. Tested with XBMCbuntu and XBMC 12.0 Frodo.


You need to enable debug logging for this to work. It also assumes VPN connections are always on and switching between them can be done by simple routing table changes. On-demand connecting of VPN can be used as well but depending on how big delay there is on login you might have some problems with XBMC addon trying to access geolocked content before VPN is active. Also remember if you use your HTPC for any other purposes route changes this script does will break any active connections.

Rather than change default route (0.0.0.0/0) script below will create three new routes. Two routes that together cover everything (0.0.0.0/1 and 128.0.0.0/1) plus one pointing to your VPN server. If your DHCP server is not in same subnet as your HTPC you need to add route to it as well. Just figure out reliable way to determine DHCP server IP from your DHCP client program and then add lines similar to already present for VPN server route mangling.

Instructions below will also enable local DNS caching via dnsmasq. This is required for CDN and will also improve performance in case of high latency VPN links. DNS cache is flushed whenever route changes as otherwise DNS cache may have CDN IP addresses that are no longer optimal after packets are routed via VPN.

# Remove resolvconf
DEBIAN_FRONTEND=noninteractive apt-get -y remove resolvconf

# Install dnsmasq
apt-get update
apt-get -y install dnsmasq

# Configure dnsmasq
mv -f /etc/dnsmasq.conf /etc/dnsmasq.conf.old
cat <<'__EOF__'>/etc/dnsmasq.conf
port=53
domain-needed
bogus-priv
filterwin2k
no-resolv
no-poll
server=4.2.2.1
server=4.2.2.2
server=8.8.8.8
server=8.8.4.4
listen-address=127.0.0.1
neg-ttl=150
max-ttl=300
cache-size=1000
log-queries
all-servers
__EOF__

# Restart dnsmasq
service dnsmasq restart

# Enable dnsmasq for name resolution
echo "nameserver 127.0.0.1" >/etc/resolv.conf
echo "nameserver 127.0.0.1" >>/etc/resolv.conf

# Create script to toggle no VPN / UK VPN / US VPN routes
cat <<'__EOF__'>/opt/vpnroute.sh
#!/bin/bash
#
# settings
vpn="52.36.10.23"    # IP of your VPN server
 uk="10.255.102.11"  # IP of your tunneled gateway to UK
 us="10.255.102.21"  # IP of your tunneled gateway to US
#  
# read xbmc debug mode logfile
tail -F /home/xbmc/.xbmc/temp/xbmc.log |
while read -r line
do
 # Check if we're loading US only plugins
 if [[ "$line" == *"StartScript - calling plugin Hulu("* ]] ||\
    [[ "$line" == *"StartScript - calling plugin Free Cable("* ]]; then
  # Get current VPN route if any
  route=$(ip route show 0.0.0.0/1|cut -d" " -f3)
  # If current VPN route isn't US fix it
  if [ "$route". != "$us". ]; then
   # update routes, flush route and DNS cache
   ip route replace $vpn via $(ip route show 0.0.0.0/0|cut -d" " -f3)
   ip route replace   0.0.0.0/1 via $us
   ip route replace 128.0.0.0/1 via $us
   ip route flush cache
   killall -HUP dnsmasq
  fi
 fi
 # Check if we're loading UK only plugins
 if [[ "$line" == *"StartScript - calling plugin iPlayer("* ]] ||\
    [[ "$line" == *"StartScript - calling plugin FilmOn("* ]]; then
  # Get current VPN route if any
  route=$(ip route show 0.0.0.0/1|cut -d" " -f3)
  # If current VPN route isn't UK fix it
  if [ "$route". != "$uk". ]; then
   # update routes, flush route and DNS cache
   ip route replace $vpn via $(ip route show 0.0.0.0/0|cut -d" " -f3)
   ip route replace   0.0.0.0/1 via $uk
   ip route replace 128.0.0.0/1 via $uk
   ip route flush cache
   killall -HUP dnsmasq
  fi
 fi
 # Don't route via VPN when using other sources
 if [[ "$line" == *"CGUIMediaWindow::GetDirectory (sources://"* ]] ||\
    [[ "$line" == *"CGUIMediaWindow::GetDirectory (addons://"* ]] ||\
    [[ "$line" == *"StartScript - calling plugin YLE Areena("* ]] ||\
    [[ "$line" == *"StartScript - calling plugin Ruutu.fi("* ]] ||\
    [[ "$line" == *"StartScript - calling plugin Katsomo("* ]]; then
  # Get current VPN route if any
  route=$(ip route show 0.0.0.0/1|cut -d" " -f3)
  if [ "$route". != "". ]; then
   # update routes, flush route and DNS cache
   ip route del   0.0.0.0/1
   ip route del 128.0.0.0/1
   ip route del $vpn
   ip route flush cache
   killall -HUP dnsmasq
  fi
 fi
done
__EOF__

# make it executable
chmod a+x /opt/vpnroute.sh

# launch at system startup
echo 'su -l -c "/bin/bash /opt/vpnroute.sh" root &' >>/etc/rc.local


Comments