is about taking small pieces of everyday life to the next level.

Category: network

Easing VPN Switching

Following up to my entry about circumventing geoblocking (https://nextlevel-blog.de/circumventing-amazon-geoblocking-the-tech-way/), I’ve written a small python program solving my Netflix blocking problem.

I realized that Netflix is not working as they rigorously ban the use of VPNs or proxies. Hence, it does work when using my home server as gateway/router but not when I additionaly enable the VPN.

First, I tried to enable or disable the VPN when I see the corresponding DNS queries for either amazon or netflix services. However, it turned out that my TV communicates with each other service regardless of what I am currently using. Therefore it is not possible to identify the desired state.

To ease the trouble at least a bit, I wrote a small webserver which allows me to make the switch with the click on a bookmark.

Flask Server

The following code snippet shows a default setup for a Flask server in python. It listens on the defined IP address and port.

#!/usr/bin/env python3
from flask import Flask
import os

app = Flask(__name__)

if __name__ == '__main__':
    app.run(host="192.168.42.19", port=5000)

Handling the VPN

To handle the VPN switching I just remove or add the ip rules to forward the traffic either to my wireguard table or using the default one.
A very hacky check routine identifies the current routing state.

def enableVPNRoute():
    print("enable VPN")
    os.system("ip rule add iif enp3s0 lookup 51820")
    os.system("ip rule flush")
    pass


def disableVPNRoute():
    print("disable VPN")
    os.system("ip rule del iif enp3s0 lookup 51820")
    pass


def isVPNOn():
    ir = os.popen("ip rule").read()
    return "iif" in ir

Establishing the Routes

Finally, Flask introduces the app.route directives which I now use to enable the VPN if the webserver is called as http://192.168.42.19:5000/amazon or disabled as http://192.168.42.19:5000/netflix.

@app.route('/amazon')
def amazon():
    if not isVPNOn():
        enableVPNRoute()
    return "Turned VPN on. Enjoy Amazon :-)"


@app.route('/netflix')
def netflix():
    if isVPNOn():
        disableVPNRoute()
    return "Turned VPN off. Enjoy Netflix :-)"

Enjoy your next movies and shows 😉

Circumventing Amazon Geoblocking the Tech-Way

After moving to a different country and having some days of vacations left, one of my concerns was to get the whole home IT setup working again. Precisely, for me this involves setting up my server again, building the network infrastructure and wireless access points as well as ensuring all my everyday services are up and running. One thing I came across when doing this, is the hassle of geoblocked streaming services which I still do want to use. So while my Netflix subscription still works out-of-the-box on my TV, the Amazon Prime Video service is not working anymore. Hence, in this article I will show you how circumventing the amazon geoblocking features is actually possible with only open-source tools.

I can still sign in to my Amazon account and see all the movies and shows. However, nothing is available to be watched in my country, i.e., in Denmark. After a while I realized, I am not looking at my German Amazon interface but the UK one. No surprise, I can login to the UK Prime Video service. But as my Prime subscription runs on the German branch, I do not have access to the UK movies and shows.

What does the TV do?

So, I had a look at the network traffic of my TV. I noticed that the communication with Amazon always started with a call to the website atv-ext-eu.amazon.com. First, I thought this website uses some kind of geolocating my IP address and then determining to which branch I shall be redirected. During transmission of this address, I thought I can intercept the response and alter it to the German branch. Then, I would have my TV once again talking to the German Prime Video. However, there was no response and apparently the forwarding happens on the server-side.

What then?

Normally, people use proxies or VPN services circumventing these amazon geoblocking problems. Unfortunately, my TV neither comes with a proxy or even a VPN configuration possibility. One solution, thus, would be to configure my router to route every traffic via a German VPN. But, then I would always go through this bottleneck, even for services which do not need it. On the one hand my router does not allow for such a configuration, on the other hand, this is not a viable solution for me. Hence, I built my very own approach to solve this problem.

The setup

I have a small server in my network for different services anyway. The idea is simple: intercept all traffic from my TV and route it through a VPN endpoint in Germany.

Using an ArchLinux server as a Router

First step is to configure the IP address of my home network server as the default gateway of my TV. Then, we need to make sure that the server actually forwards IP packets destined for other machines.

sysctl -w net.ipv4.ip_forward=1

VPN connection

For the VPN connection, I ordered a small virtual private server in Frankfurt, Germany, with unlimited traffic and a decent enough bandwidth. This server and the server in my home network are configured to establish a wireguard connection. While the main setup is as usual I took some modifications. The general setup for a VPN server is well explained on the ArchLinux wiki: https://wiki.archlinux.org/index.php/WireGuard

Server setup

The server will be the machine in Frankfurt.

[Interface]
Address = 10.42.0.1/24
ListenPort = 51871
PrivateKey = PRIVATEKEY_OF_VPN_SERVER

PostUp = iptables -A FORWARD -i %i -j ACCEPT; iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
PostDown = iptables -D FORWARD -i %i -j ACCEPT; iptables -t nat -D POSTROUTING -o eth0 -j MASQUERADE

[Peer]
PublicKey = PUBLICKEY_OF_HOME_ROUTER
AllowedIPs = 10.42.0.2/32, 192.168.42.180/32
Endpoint = HOME_NETWORK_IP:51871
PersistentKeepalive = 25

In contrast to the default wireguard VPN setups, I added the post up and down directives to ensure the VPN server actually performs network address translation. Obviously, you need to have iptables up and running for this. A second important point is, that we need to include all IP addresses in AllowedIPs which may redirect traffic through this VPN. As I have different subnets for the VPN itself and my actual home network, I have the wireguard address of my home server (10.42.0.2) and the local IP address of my TV (192.168.42.180).

Afterwards, we can just start the network interface with wg-quick up wg0.

Client setup

The client is the machine in my home network.

[Interface]
Address = 10.42.0.2/24
ListenPort = 51871
PrivateKey = PRIVATEKEY_OF_HOME_ROUTER

[Peer]
PublicKey = PUBLICKEY_OF_VPN_SERVER
AllowedIPs = 0.0.0.0/0, ::/0
Endpoint = VPN_ENDPOINT_IP:51871
PersistentKeepalive = 25

Restricting the VPN to Router Functionality

As I wrote in the beginning, I use the server in my home network for several other services which are in parts also publicly available. These services I do not want to route through the VPN but through my original internet connection as I do have a much bigger bandwidth there.

With iptables, wireguard uses a second routing table to separate its rules from your normal routing. On my system, this second table got named 51820. Wireguard then just creates one rule which captures all traffic not marked with 51820 to go through the new second routing table. At the same time, wireguard itself is able to mark all traffic coming from the remote endpoint with that mark. Hence, it is routed using your default table. To prevent routing every traffic through the VPN, we exchange this mark filter for a better suited one. After starting the wireguard interface with wg-quick up wg0, I remove the general routing rule which enforces all traffic to go through the VPN. Then, we replace it with a rule to only use the second routing table if we see packets coming to us on the plain network interface, i.e., enp3s0 on my system. This is done using the iif (incoming interface) rule.

ip rule del not fwmark 51820 lookup 51820
ip rule add iif enp3s0 lookup 51820

Therefore, all traffic originating at the machine itself will be routed using the default table while only packets which arrive on enp3s0 and are to be forwarded will use the second table.

Finally, now I can have every device in my home network choosing between two different gateways, the Danish one at .1 and the German one via the wireguard VPN on .19. Everything needed is just the change of the gateway on the corresponding device and appending the IP address on the VPN server to the AllowedIPs in the wireguard configuration.

Only Drawback

For now, everything is working fine: Prime Video and YouTube play well over this setup. But, for some unknown reason, I cannot connect to Netflix with this setup. The debugging showed it tries to reach three different servers while only two of these connections are successful. I still need to figure out what is wrong here…

Powered by WordPress & Theme by Anders Norén