{"id":2220,"date":"2026-02-22T20:04:07","date_gmt":"2026-02-22T19:04:07","guid":{"rendered":"https:\/\/caipirinha.spdns.org\/wp\/?p=2220"},"modified":"2026-02-22T20:04:07","modified_gmt":"2026-02-22T19:04:07","slug":"getting-around-tv-app-geo-blocking","status":"publish","type":"post","link":"https:\/\/caipirinha.spdns.org\/wp\/?p=2220","title":{"rendered":"Getting around TV App Geo-Blocking"},"content":{"rendered":"\n<h2 class=\"wp-block-heading\">Executive Summary<\/h2>\n\n\n\n<p>This blog post explains how <strong>Policy Routing<\/strong> on a Linux server together with <strong>commercial VPNs<\/strong> to other countries can help you to put your client devices (TV, smartphones) logically into the internet of other countries in order to get around geo-blocking.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Background<\/h2>\n\n\n\n<p>The idea or merely, the need for this approach, surged when I installed an app of a Portuguese TV provider and could not even watch the news journal due to geo-blocking. Additionally, I wanted to have a comfortable solution with which I can switch the TV to different countries while I am sitting in my TV chair with my smartphone at hand \ud83d\ude01.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Preconditions<\/h2>\n\n\n\n<p>In order to use the approach described here, you should:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>\u2026 have access to a Linux machine which is already properly configured on its principal network interface (e.g.,&nbsp;<em>eth0<\/em>)<\/li>\n\n\n\n<li>\u2026 have the package&nbsp;<a href=\"https:\/\/graphviz.org\/\" target=\"_blank\" rel=\"noreferrer noopener\">openvpn<\/a>&nbsp;installed on the Linux machine (preferably from a repository of your Linux distribution)<\/li>\n\n\n\n<li>\u2026 have access to a commercial VPN provider allowing you to run several parallel client connections on the same machine<\/li>\n\n\n\n<li>\u2026 have knowledge of routing concepts, networks, some understanding of shell scripts and configuration files<\/li>\n\n\n\n<li>\u2026 know related system commands like&nbsp;<em>sysctl<\/em><\/li>\n\n\n\n<li>&#8230; familiarize yourself with [<a href=\"https:\/\/caipirinha.spdns.org\/wp\/?p=734\" target=\"_blank\" rel=\"noreferrer noopener\"><\/a><a href=\"https:\/\/caipirinha.spdns.org\/wp\/?p=765\" target=\"_blank\" rel=\"noreferrer noopener\"><\/a><a href=\"https:\/\/caipirinha.spdns.org\/wp\/?p=765\" target=\"_blank\" rel=\"noreferrer noopener\">1<\/a>], [<a href=\"https:\/\/unix.stackexchange.com\/questions\/504366\/port-forwarding-over-openvpn\" target=\"_blank\" rel=\"noreferrer noopener\"><\/a><a href=\"https:\/\/unix.stackexchange.com\/questions\/504366\/port-forwarding-over-openvpn\" target=\"_blank\" rel=\"noreferrer noopener\"><\/a><a href=\"https:\/\/unix.stackexchange.com\/questions\/504366\/port-forwarding-over-openvpn\" target=\"_blank\" rel=\"noreferrer noopener\">3<\/a>], [<a href=\"https:\/\/lartc.org\/howto\/lartc.rpdb.multiple-links.html\" target=\"_blank\" rel=\"noreferrer noopener\"><\/a><a href=\"https:\/\/lartc.org\/howto\/lartc.rpdb.multiple-links.html\" target=\"_blank\" rel=\"noreferrer noopener\">4<\/a>], [<a href=\"https:\/\/www.thomas-krenn.com\/en\/wiki\/Predictable_Network_Interface_Names\" target=\"_blank\" rel=\"noreferrer noopener\"><\/a><a href=\"https:\/\/www.thomas-krenn.com\/en\/wiki\/Two_Default_Gateways_on_One_System\" target=\"_blank\" rel=\"noreferrer noopener\">5<\/a>]<\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\">Description and Usage<\/h2>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"576\" src=\"https:\/\/caipirinha.spdns.org\/wp\/wp-content\/uploads\/TV-Setup-Diagram-1024x576.png\" alt=\"\" class=\"wp-image-2221\" srcset=\"https:\/\/caipirinha.spdns.org\/wp\/wp-content\/uploads\/TV-Setup-Diagram-1024x576.png 1024w, https:\/\/caipirinha.spdns.org\/wp\/wp-content\/uploads\/TV-Setup-Diagram-300x169.png 300w, https:\/\/caipirinha.spdns.org\/wp\/wp-content\/uploads\/TV-Setup-Diagram-768x432.png 768w, https:\/\/caipirinha.spdns.org\/wp\/wp-content\/uploads\/TV-Setup-Diagram.png 1280w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><figcaption class=\"wp-element-caption\">Setup for the TV Geo-Relocation on eth0 and an additional WiFi on wlan0<\/figcaption><\/figure>\n\n\n\n<p>In this setup, we have a full-blown SoHo Linux server on an internal network <strong>192.168.2.0\/24<\/strong> that is also used by all other devices in the same home. Subsequently, we will connect this Linux server via a commercial VPN to two endpoints, one endpoint in <strong>Portugal<\/strong> and one endpoint in <strong>Brazil<\/strong>. We will also create two additional networks for our SoHo environment:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>192.168.4.0\/24<\/strong> will be spread via WLAN (WiFi) and will constantly logically be &#8220;in Brazil&#8221;. This network can simply be selected by a smartphone at home, and the smartphone will have a Brazilian internet connection while still being able to access all resources in the home network.<\/li>\n\n\n\n<li><strong>192.168.3.0\/24<\/strong> will an overlay on our wired SoHo network. The <strong>TV set<\/strong> will be the only client in this network. We will make the endpoint of this network selectable, that is, one shall be able to select whether this network is in Germany, in Portugal, or in Brazil.<\/li>\n<\/ul>\n\n\n\n<p>That setup is suited to my personal preferences, but of course, after having read through this article, you will know sufficiently to suit the setup to your preferences and demands.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">OpenVPN Client Configuration<\/h3>\n\n\n\n<p>For the setup described below, we need two client VPN connections, to Portugal and to Brazil. As I do not have infrastructure outside of Germany, I use a commercial VPN provider, in my case this is <a href=\"https:\/\/www.privateinternetaccess.com\/\" target=\"_blank\" rel=\"noreferrer noopener\">Private Internet Access<sup>\u00ae<\/sup><\/a>. However, there are several commercial VPNs that you can also use; the important thing is that they allow several active connections from one device and that you can configure and adapt the VPN configuration file, preferably for an <a href=\"https:\/\/graphviz.org\/\" target=\"_blank\" rel=\"noreferrer noopener\">openvpn<\/a> connection (as this will also be described here). The client configuration files listed here use <strong>UDP<\/strong>, a <strong>split-tunnel setup<\/strong> and also contain all the\u00a0necessary <strong>certificates<\/strong> in one file. The login credentials are stored in another file named <em>\/etc\/openvpn\/pia.login<\/em>. The certificates of the configuration files have been omitted here for readability reasons. An important configuration command is <em>route-nopull<\/em> as it inhibits that we pull (default) routes from the commercial VPN server. After all, we want to specify ourselves which IP packets shall use which outgoing network.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\" id=\"udp-based-vpn-full-tunneling-1\">UDP-based split VPN to Portugal<\/h4>\n\n\n\n<pre class=\"wp-block-code\"><code># Konfigurationsdatei f\u00fcr den openVPN-Client auf CAIPIRINHA zur Verbindung nach Portugal mit PIA\n\nauth-user-pass       \/etc\/openvpn\/pia.login\nauth-nocache \nauth-retry           nointeract\nauth                 sha1\nclient\ncompress\ndev                  tun0\ndisable-occ\nlog                  \/var\/log\/openvpn_PT.log\nlport                5457\nmute                 20\nproto                udp\npersist-key\npersist-tun\nremote               pt.privacy.network 1198\nremote-cert-tls      server\nreneg-sec            0\nresolv-retry         infinite\nroute-nopull\nscript-security      2\nstatus               \/var\/run\/openvpn\/status_PT\ntls-client\nup                   \/etc\/openvpn\/start_piavpn.sh\ndown                 \/etc\/openvpn\/stop_piavpn.sh\nverb                 3\n\n&lt;crl-verify&gt;\n-----BEGIN X509 CRL-----\n...\n-----END X509 CRL-----\n&lt;\/crl-verify&gt;\n\n&lt;ca&gt;\n-----BEGIN CERTIFICATE-----\n...\n-----END CERTIFICATE-----\n&lt;\/ca&gt;<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\" id=\"tcp-based-vpn-full-tunneling-1\">UDP-based split VPN to Brazil<\/h4>\n\n\n\n<pre class=\"wp-block-code\"><code># Konfigurationsdatei f\u00fcr den openVPN-Client auf CAIPIRINHA zur Verbindung nach Brasilien mit PIA\n\nauth-user-pass       \/etc\/openvpn\/pia.login\nauth-nocache \nauth-retry           nointeract\nauth                 sha1\nclient\ncompress\ndev                  tun1\ndisable-occ\nlog                  \/var\/log\/openvpn_BR.log\nlport                5458\nmute                 20\nproto                udp\npersist-key\npersist-tun\nremote               br.privacy.network 1198\nremote-cert-tls      server\nreneg-sec            0\nresolv-retry         infinite\nroute-nopull\nscript-security      2\nstatus               \/var\/run\/openvpn\/status_BR\ntls-client\nup                   \/etc\/openvpn\/start_piavpn.sh\ndown                 \/etc\/openvpn\/stop_piavpn.sh\nverb                 3\n\n&lt;crl-verify&gt;\n-----BEGIN X509 CRL-----\n...\n-----END X509 CRL-----\n&lt;\/crl-verify&gt;\n\n&lt;ca&gt;\n-----BEGIN CERTIFICATE-----\n...\n-----END CERTIFICATE-----\n&lt;\/ca&gt;<\/code><\/pre>\n\n\n\n<p>Both configuration files call upon scripts (<em>\/etc\/openvpn\/start_piavpn.sh<\/em> and <em>\/etc\/openvpn\/stop_piavpn.sh<\/em>) which are executed upon start and upon termination of the VPN. <strong>start_piavpn.sh<\/strong> (which needs the tool <em>ipcalc<\/em> to be installed on the server) populates the <strong>routing table<\/strong> <em>Portugal<\/em> or <em>Brasilien<\/em>, depending on which client configuration has called the script. It furthermore blocks incoming new connections from the commercial VPNs for security reasons. Normally, you should not experience incoming connections on your commercial VPN (unless this has been wanted and ordered by you), however, I have seen different behavior in the past. Finally, the script <em>start_piavpn.sh<\/em> sets the correct <strong>default route<\/strong> in the corresponding <strong>routing table<\/strong>. The script <em>stop_piavpn.sh<\/em> deletes the blocking of incoming requests. There is no need to delete the previously active default routes from the routing tables <em>Portugal<\/em> or <em>Brasilien<\/em> as they will vanish anyway with the termination of the VPN connection. All other configuration options have been discussed in detail already in [<a href=\"https:\/\/caipirinha.spdns.org\/wp\/?p=765\" target=\"_blank\" rel=\"noreferrer noopener\">1<\/a>], [<a href=\"https:\/\/caipirinha.spdns.org\/wp\/?p=734\">2<\/a>].<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">start_piavpn.sh<\/h4>\n\n\n\n<pre class=\"wp-block-code\"><code>#!\/bin\/bash\n#\n# This script sets the VPN parameters in the routing tables \"main\", \"Portugal\", and \"Brasilien\" once the connection has been successfully established.\n# This script requires the tool \"ipcalc\" which needs to be installed on the target system.\n\n# Set the correct PATH environment \nPATH='\/sbin:\/usr\/sbin:\/bin:\/usr\/bin'\n\nVPN_DEV=$1\nVPN_SRC=$4\nVPN_MSK=$5\n\nVPN_GW=$(ipcalc ${VPN_SRC}\/${VPN_MSK} | sed -n 's\/^HostMin:\\s*\\(&#91;0-9]\\{1,3\\}\\.&#91;0-9]\\{1,3\\}\\.&#91;0-9]\\{1,3\\}\\.&#91;0-9]\\{1,3\\}\\).*\/\\1\/p')\nVPN_NET=$(ipcalc ${VPN_SRC}\/${VPN_MSK} | sed -n 's\/^Network:\\s*\\(&#91;0-9]\\{1,3\\}\\.&#91;0-9]\\{1,3\\}\\.&#91;0-9]\\{1,3\\}\\.&#91;0-9]\\{1,3\\}\\\/&#91;0-9]\\{1,2\\}\\).*\/\\1\/p')\n\ncase \"${VPN_DEV}\" in\n  \"tun0\") ROUTING_TABLE='Portugal';;\n  \"tun1\") ROUTING_TABLE='Brasilien';;\nesac\n\niptables -t filter -A INPUT   -i ${VPN_DEV} -m state --state NEW,INVALID -j DROP\niptables -t filter -A FORWARD -i ${VPN_DEV} -m state --state NEW,INVALID -j DROP\n\nip route add ${VPN_NET} dev ${VPN_DEV} proto static scope link src ${VPN_SRC} table ${ROUTING_TABLE}\nip route replace default dev ${VPN_DEV} via ${VPN_GW} table ${ROUTING_TABLE}<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">stop_piavpn.sh<\/h4>\n\n\n\n<pre class=\"wp-block-code\"><code>#!\/bin\/bash\n#\n# This script removes some routing table entries when the connection is terminated.\n\n# Set the correct PATH environment \nPATH='\/sbin:\/usr\/sbin:\/bin:\/usr\/bin'\n\nVPN_DEV=$1\nVPN_SRC=$4\nVPN_MSK=$5\n\niptables -t filter -D INPUT   -i ${VPN_DEV} -m state --state NEW,INVALID -j DROP\niptables -t filter -D FORWARD -i ${VPN_DEV} -m state --state NEW,INVALID -j DROP<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Routing Tables<\/h3>\n\n\n\n<p>In order to use <strong>Policy Routing<\/strong>, we set up <a href=\"https:\/\/en.wikipedia.org\/wiki\/Routing_table\" target=\"_blank\" rel=\"noreferrer noopener\">routing tables<\/a> as described in [<a href=\"https:\/\/caipirinha.spdns.org\/wp\/?p=765\" target=\"_blank\" rel=\"noreferrer noopener\">1<\/a>], and we describe these routing tables in <strong>\/etc\/iproute2\/rt_tables<\/strong>:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>#\n# reserved values\n#\n255 local\n254 main\n253 default\n0 unspec\n#\n# local\n#\n\n240 Portugal\n241 Brasilien<\/code><\/pre>\n\n\n\n<p>The idea here is to direct all IP traffic that shall go to Portugal to the routing table <em>Portugal<\/em>, and to direct all IP traffic that shall go to Brazil to the routing table <em>Brasilien<\/em>. The routing table <em>main<\/em> will be used for all other traffic; it is part of the default configuration of <em>\/etc\/iproute2\/rt_tables<\/em>.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Local LAN for the TV set<\/h3>\n\n\n\n<p>The network that so far has been used on my Linux server has been <strong>192.168.2.0\/24<\/strong>, and the corresponding server interface has been <strong>eth0<\/strong>. We now need to add one more network to this interface. In order to make that addition permanent and my life easy, I did that via the graphical YaST2 interface.<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"870\" height=\"576\" src=\"https:\/\/caipirinha.spdns.org\/wp\/wp-content\/uploads\/Screenshot_20260219_174911.png\" alt=\"\" class=\"wp-image-2223\" srcset=\"https:\/\/caipirinha.spdns.org\/wp\/wp-content\/uploads\/Screenshot_20260219_174911.png 870w, https:\/\/caipirinha.spdns.org\/wp\/wp-content\/uploads\/Screenshot_20260219_174911-300x199.png 300w, https:\/\/caipirinha.spdns.org\/wp\/wp-content\/uploads\/Screenshot_20260219_174911-768x508.png 768w\" sizes=\"auto, (max-width: 870px) 100vw, 870px\" \/><figcaption class=\"wp-element-caption\">Adding a second IP address and network in the YaST2 network configuration menu<\/figcaption><\/figure>\n\n\n\n<p>In my case, I chose the address label &#8220;pt&#8221; (because the original idea was to use this network exclusively for the traffic to Portugal); however, you can choose any label that you wish. While the Linux server usually receives a pseudo-static IP address (192.168.2.3) in the SoHo network 192.168.2.0\/24 by the SoHo router (a <a href=\"https:\/\/fritz.com\/\" target=\"_blank\" rel=\"noreferrer noopener\">FRITZ!Box<\/a>), in our new network 192.168.3.0\/24, the server gets the static IP address (192.168.3.1). Clients in this network will consequently require a static IP address configuration; we cannot use <a href=\"https:\/\/en.wikipedia.org\/wiki\/Dynamic_Host_Configuration_Protocol\" target=\"_blank\" rel=\"noreferrer noopener\">DHCP<\/a> as this network runs on the same physical network infrastructure as the SoHo network 192.168.2.0\/24 which already has the <a href=\"https:\/\/fritz.com\/\" target=\"_blank\" rel=\"noreferrer noopener\">FRITZ!Box<\/a> as <a href=\"https:\/\/en.wikipedia.org\/wiki\/Dynamic_Host_Configuration_Protocol\" target=\"_blank\" rel=\"noreferrer noopener\">DHCP<\/a> master. In my case, I therefore have configured the TV set (the only client in the network 192.168.3.0\/24) with the setup:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>IP address: 192.168.3.186<\/li>\n\n\n\n<li>Netmask: 255.255.255.0<\/li>\n\n\n\n<li>Gateway: 192.168.3.1<\/li>\n\n\n\n<li>DNS server: 192.168.3.1<\/li>\n<\/ul>\n\n\n\n<p>As DNS I have used the server itself as I have a DNS relay running on the Linux server. If that was not the case, I could also have used 192.168.2.1 which is the address of the <a href=\"https:\/\/fritz.com\/\" target=\"_blank\" rel=\"noreferrer noopener\">FRITZ!Box<\/a>.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Local WLAN (WiFi) for wireless devices<\/h3>\n\n\n\n<p>For the WLAN (WiFi) network I have equipped the Linux server with a PCI Express WLAN card (in my case an old <strong>Asus PCE-N10<\/strong>, but I would recommend you a newer one in the 5 GHz band) and attached an external antenna to it. This WiFi card shall act as <strong>access point<\/strong> (master). I did not succeed to make that work with YaST2 in conjunction with WPA encryption, and subsequent to my failure, I consulted an Artificial Intelligence (AI) that recommended me to use the package <strong><a href=\"https:\/\/en.wikipedia.org\/wiki\/Hostapd\" target=\"_blank\" rel=\"noreferrer noopener\">hostapd<\/a><\/strong> which needs to be installed on the Linux server. I did so, and after some research and experiments, I came up with a suitable configuration:<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">\/etc\/hostapd.conf<\/h4>\n\n\n\n<pre class=\"wp-block-code\"><code># Basis-Einstellungen\ninterface=wlan0\ndriver=nl80211\nssid=Querstrasse 8 &#91;BR]\nhw_mode=g\nchannel=1                        # 1-13, vermeiden Sie DFS-Kan\u00e4le (52+)\nieee80211n=0                     # Optional f\u00fcr bessere Phones, aber ung\u00fcnstig bei schlechter Verbindung\n\n# WPA2-PSK (wpa=2 f\u00fcr WPA2 only, TKIP\/CCMP f\u00fcr Kompatibilit\u00e4t)\nwpa=2\nwpa_passphrase=my_secret_password\nwpa_key_mgmt=WPA-PSK WPA-PSK-SHA256\nwpa_pairwise=TKIP CCMP\nrsn_pairwise=CCMP\n\n# Sonstiges\nmacaddr_acl=0                    # MAC address -based authentication nicht aktivieren\nauth_algs=1                      # Open System Authentication\nignore_broadcast_ssid=0          # SSID frei sichtbar\nwmm_enabled=0                    # WMM deaktiviert wegen schlechter Verbindung\nbeacon_int=75                    # H\u00e4ufigere Beacons wegen schlechter Verbindung\nmax_num_sta=10                   # Max Clients\ncountry_code=DE\ncountry3=0x49                    # Indoor environment\nieee80211d=1                     # Advertise country-specific parameters\naccess_network_type=0            # Private network\ninternet=1                       # Network provides connectivity to the Internet\nvenue_group=7                    # 7,1 means Private Residence\nvenue_type=1\nipaddr_type_availability=10      # Double NATed private IPv4 address\nlogger_syslog=-1\nlogger_syslog_level=3            # Notifications only\nlogger_stdout=-1\nlogger_stdout_level=2<\/code><\/pre>\n\n\n\n<p>A couple of points in this configuration are important and shall be briefly discussed:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>The network is quite weak in some parts of my house, and so some parameters have been configured for <strong>bad network conditions<\/strong>. If you do not have this issue and see a strong WiFi signal all over your place, you might want to change some of the parameters or not set them to dedicated values at all. Consult the original <strong>hostapd.conf<\/strong> file for an explanation of all parameters or ask the AI for a suitable setup.<\/li>\n\n\n\n<li><em>my_secret_password<\/em> has to be replaced with the password that you intend to secure your WiFi with, of course.<\/li>\n\n\n\n<li>I configured the card for Germany, and hence power output is limited to 100 mW, according to the local regulations. A configuration for the USA would allow a higher power output, but this is illegal in Europe. Furthermore, that would only bring a real benefit if your client devices also had higher output power.<\/li>\n\n\n\n<li>I chose the SSID <strong>Querstrasse 8 [BR]<\/strong> (Yes, with white space in the SSID!). If you have old clients, you might want to avoid white spaces in the SSID name.<\/li>\n\n\n\n<li>I set the values for <em>venue_group<\/em>, <em>venue_type<\/em> and <em>access_network_type<\/em> in order to indicate to prospective clients that this is a private (non-public) network. You might also leave these configuration options away, there would be no real impact.<\/li>\n<\/ul>\n\n\n\n<p>In order to bring the interface <strong>wlan0<\/strong> to life, we need to issue these three commands:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>ip addr add 192.168.4.1\/24 dev wlan0\nip link set wlan0 up\nsystemctl start hostapd.service<\/code><\/pre>\n\n\n\n<p>However, before we can connect new clients to this WiFi, we need to set up a DHCP server on this network. The small <a href=\"https:\/\/en.wikipedia.org\/wiki\/Dynamic_Host_Configuration_Protocol\" target=\"_blank\" rel=\"noreferrer noopener\">DHCP<\/a> and <a href=\"https:\/\/en.wikipedia.org\/wiki\/Domain_Name_System\" target=\"_blank\" rel=\"noreferrer noopener\">DNS<\/a> caching server <a href=\"https:\/\/en.wikipedia.org\/wiki\/Dnsmasq\" target=\"_blank\" rel=\"noreferrer noopener\">dnsmasq<\/a> is the right tool to be used here.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Providing DHCP and DNS on wlan0<\/h4>\n\n\n\n<p><a href=\"https:\/\/en.wikipedia.org\/wiki\/Dnsmasq\" target=\"_blank\" rel=\"noreferrer noopener\">dnsmasq<\/a> can provide both <a href=\"https:\/\/en.wikipedia.org\/wiki\/Dynamic_Host_Configuration_Protocol\" target=\"_blank\" rel=\"noreferrer noopener\">DHCP<\/a> as well as cache <a href=\"https:\/\/en.wikipedia.org\/wiki\/Domain_Name_System\" target=\"_blank\" rel=\"noreferrer noopener\">DNS<\/a>. That is very practical as it allows us for example, to have only <a href=\"https:\/\/en.wikipedia.org\/wiki\/Domain_Name_System\" target=\"_blank\" rel=\"noreferrer noopener\">DNS<\/a> on <em>eth0<\/em> where the <a href=\"https:\/\/fritz.com\/\" target=\"_blank\" rel=\"noreferrer noopener\">FRITZ!Box<\/a> already is the <a href=\"https:\/\/en.wikipedia.org\/wiki\/Dynamic_Host_Configuration_Protocol\" target=\"_blank\" rel=\"noreferrer noopener\">DHCP<\/a> master, but to configure both <a href=\"https:\/\/en.wikipedia.org\/wiki\/Dynamic_Host_Configuration_Protocol\" target=\"_blank\" rel=\"noreferrer noopener\">DHCP<\/a> and a caching <a href=\"https:\/\/en.wikipedia.org\/wiki\/Domain_Name_System\" target=\"_blank\" rel=\"noreferrer noopener\">DNS<\/a> on <em>wlan0<\/em>. The following configuration file will exactly do that (it uses only a subset of the capabilities of <a href=\"https:\/\/en.wikipedia.org\/wiki\/Dnsmasq\" target=\"_blank\" rel=\"noreferrer noopener\">dnsmasq<\/a>):<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">\/etc\/dnsmasq.conf<\/h4>\n\n\n\n<pre class=\"wp-block-code\"><code># Never forward addresses in the non-routed address spaces.\nbogus-priv\n\n# If you don't want dnsmasq to read \/etc\/resolv.conf or any other\n# file, getting its servers from this file instead (see below), then\n# uncomment this.\nno-resolv\n\n# If you don't want dnsmasq to poll \/etc\/resolv.conf or other resolv\n# files for changes and re-read them then uncomment this.\nno-poll\n\n# Add other name servers here, with domain specs if they are for\n# non-public domains.\nserver=8.8.8.8\nserver=8.8.4.4\nserver=9.9.9.9\nserver=1.1.1.1\n\n# If you want dnsmasq to listen for DHCP and DNS requests only on\n# specified interfaces (and the loopback) give the name of the\n# interface (eg eth0) here.\n# Repeat the line for more than one interface.\ninterface=eth0\ninterface=wlan0\n\n# If you want dnsmasq to provide only DNS service on an interface,\n# configure it as shown above, and then use the following line to\n# disable DHCP and TFTP on it.\nno-dhcp-interface=eth0\n\n# Uncomment this to enable the integrated DHCP server, you need\n# to supply the range of addresses available for lease and optionally\n# a lease time. If you have more than one network, you will need to\n# repeat this for each network on which you want to supply DHCP\n# service.\ndhcp-range=tag:wlan0,192.168.4.10,192.168.4.254,24h\n\n# Set the NTP time server addresses\ndhcp-option=option:ntp-server,192.168.2.3\n\n# Send Microsoft-specific option to tell windows to release the DHCP lease\n# when it shuts down. Note the \"i\" flag, to tell dnsmasq to send the\n# value as a four-byte integer - that's what Microsoft wants. See\n# https:\/\/learn.microsoft.com\/en-us\/openspecs\/windows_protocols\/ms-dhcpe\/4cde5ceb-4fc1-4f9a-82e9-13f6b38d930c\ndhcp-option=vendor:MSFT,2,1i\n\n# Include all files in a directory which end in .conf\nconf-dir=\/etc\/dnsmasq.d\/,*.conf<\/code><\/pre>\n\n\n\n<p>In this configuration, we can see that on <em>eth0<\/em>, we will not enable <a href=\"https:\/\/en.wikipedia.org\/wiki\/Dynamic_Host_Configuration_Protocol\" target=\"_blank\" rel=\"noreferrer noopener\">DHCP<\/a> (Option <em>no-dhcp-interface=eth0<\/em>). As this option is missing for <em>wlan0<\/em>, we will have <a href=\"https:\/\/en.wikipedia.org\/wiki\/Dynamic_Host_Configuration_Protocol\" target=\"_blank\" rel=\"noreferrer noopener\">DHCP<\/a> active on <em>wlan0<\/em>. Furthermore, we propagate the server&#8217;s address <em>192.168.2.3<\/em> as <a href=\"https:\/\/en.wikipedia.org\/wiki\/Network_Time_Protocol\" target=\"_blank\" rel=\"noreferrer noopener\">NTP<\/a> server. For this, the <a href=\"https:\/\/en.wikipedia.org\/wiki\/Network_Time_Protocol\" target=\"_blank\" rel=\"noreferrer noopener\">NTP<\/a> service needs to be enabled, of course, otherwise that would be pointless.<\/p>\n\n\n\n<p>While address 192.168.2.3 is not in the network of <em>wlan0<\/em> (192.168.4.0\/24), we will enable access to that network in the subsequent chapter.<\/p>\n\n\n\n<p><a href=\"https:\/\/en.wikipedia.org\/wiki\/Dnsmasq\" target=\"_blank\" rel=\"noreferrer noopener\">dnsmasq<\/a> uses the file <strong>\/etc\/hosts<\/strong> as well as upstream <a href=\"https:\/\/en.wikipedia.org\/wiki\/Domain_Name_System\" target=\"_blank\" rel=\"noreferrer noopener\">DNS<\/a> servers for its own <a href=\"https:\/\/en.wikipedia.org\/wiki\/Domain_Name_System\" target=\"_blank\" rel=\"noreferrer noopener\">DNS<\/a> service. The advantage of this is that &#8211; if your file <em>\/etc\/hosts<\/em> is maintained &#8211; you can also use the device names listed there. As pstream <a href=\"https:\/\/en.wikipedia.org\/wiki\/Domain_Name_System\" target=\"_blank\" rel=\"noreferrer noopener\">DNS<\/a> servers from which <a href=\"https:\/\/en.wikipedia.org\/wiki\/Dnsmasq\" target=\"_blank\" rel=\"noreferrer noopener\">dnsmasq<\/a> gets the IP resolution, I have configured four popular ones (8.8.8.8, 8.8.4.4, 9.9.9.9, 1.1.1.1), but you could also just list the IP of your SoHo router or <a href=\"https:\/\/en.wikipedia.org\/wiki\/Domain_Name_System\" target=\"_blank\" rel=\"noreferrer noopener\">DNS<\/a> resolver of your internet provider.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Setting the Routing Policy<\/h3>\n\n\n\n<p>Now, we must ensure that traffic from our new networks <strong>192.168.3.0\/24<\/strong> and <strong>192.168.4.0\/24<\/strong> can flow as intended. We have to set up the correct <strong>routing policy<\/strong>, and for that, we need the following commands whereby the first three commands have already been mentioned (and been executed) in one of the chapters above:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code># Start interfaces wlan0\nip addr add 192.168.4.1\/24 dev wlan0\nip link set wlan0 up\nsystemctl start hostapd.service\n\n# Setup the NAT table for the VPNs.\niptables -t nat -F\niptables -t nat -A POSTROUTING -s 192.168.3.0\/24 -o eth0 -j SNAT --to-source 192.168.2.3\niptables -t nat -A POSTROUTING -s 192.168.4.0\/24 -o eth0 -j SNAT --to-source 192.168.2.3\niptables -t nat -A POSTROUTING                   -o tun0 -j MASQUERADE\niptables -t nat -A POSTROUTING                   -o tun1 -j MASQUERADE\n\n\n# Add the missing routes in the other routing tables\nfor TABLE in Portugal Brasilien; do\n    ip route add 192.168.2.0\/24 dev eth0  proto kernel scope link src 192.168.2.3 table ${TABLE}\n    ip route add 192.168.3.0\/24 dev eth0  proto kernel scope link src 192.168.3.1 table ${TABLE}\n    ip route add 192.168.4.0\/24 dev wlan0 proto kernel scope link src 192.168.4.1 table ${TABLE}\ndone\n\n# Setup the MANGLE tables which shape and mark the traffic that shall use other routing tables\niptables -t mangle -F\niptables -t mangle -A PREROUTING                            -j CONNMARK --restore-mark\niptables -t mangle -A PREROUTING -m mark  ! --mark 0        -j ACCEPT\niptables -t mangle -A PREROUTING -i eth0  -s 192.168.3.0\/24 -j MARK --set-mark 1\niptables -t mangle -A PREROUTING -i wlan0 -s 192.168.4.0\/24 -j MARK --set-mark 2\niptables -t mangle -A PREROUTING                            -j CONNMARK --save-mark\niptables -t mangle -A OUTPUT                                -j CONNMARK --restore-mark\niptables -t mangle -A OUTPUT     -m mark  ! --mark 0        -j ACCEPT\niptables -t mangle -A OUTPUT                                -j CONNMARK --save-mark\n\n# Add rules for the traffic that shall branch to the new routing table\nip rule add from all fwmark 0x1 priority 5000 lookup Portugal\nip rule add from all fwmark 0x2 priority 5000 lookup Brasilien<\/code><\/pre>\n\n\n\n<p>Personally, I have these commands executed as part of a shell script that runs after powering up the Linux server and that I also use to control many other services and configurations.<\/p>\n\n\n\n<p>Once we have started the <a href=\"https:\/\/en.wikipedia.org\/wiki\/Dnsmasq\" target=\"_blank\" rel=\"noreferrer noopener\">dnsmasq<\/a> service (<em>systemctl start dnsmasq.service<\/em>) from the previous chapter and set up the routing policy correctly, we should be able to connect with a smartphone or a notebook to our new WiFi network <strong>192.168.4.0\/24<\/strong> and do first tests like shown here:<\/p>\n\n\n\n<figure class=\"wp-block-gallery has-nested-images columns-default is-cropped wp-block-gallery-1 is-layout-flex wp-block-gallery-is-layout-flex\">\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"478\" height=\"1024\" data-id=\"2228\" src=\"https:\/\/caipirinha.spdns.org\/wp\/wp-content\/uploads\/IP-address-in-wlan0-478x1024.jpg\" alt=\"\" class=\"wp-image-2228\" srcset=\"https:\/\/caipirinha.spdns.org\/wp\/wp-content\/uploads\/IP-address-in-wlan0-478x1024.jpg 478w, https:\/\/caipirinha.spdns.org\/wp\/wp-content\/uploads\/IP-address-in-wlan0-140x300.jpg 140w, https:\/\/caipirinha.spdns.org\/wp\/wp-content\/uploads\/IP-address-in-wlan0-768x1647.jpg 768w, https:\/\/caipirinha.spdns.org\/wp\/wp-content\/uploads\/IP-address-in-wlan0-716x1536.jpg 716w, https:\/\/caipirinha.spdns.org\/wp\/wp-content\/uploads\/IP-address-in-wlan0-955x2048.jpg 955w, https:\/\/caipirinha.spdns.org\/wp\/wp-content\/uploads\/IP-address-in-wlan0.jpg 1080w\" sizes=\"auto, (max-width: 478px) 100vw, 478px\" \/><figcaption class=\"wp-element-caption\">The smartphone is (IP-wise) in Brazil<\/figcaption><\/figure>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"478\" height=\"1024\" data-id=\"2229\" src=\"https:\/\/caipirinha.spdns.org\/wp\/wp-content\/uploads\/Speed-Test-in-wlan0-478x1024.jpg\" alt=\"\" class=\"wp-image-2229\" srcset=\"https:\/\/caipirinha.spdns.org\/wp\/wp-content\/uploads\/Speed-Test-in-wlan0-478x1024.jpg 478w, https:\/\/caipirinha.spdns.org\/wp\/wp-content\/uploads\/Speed-Test-in-wlan0-140x300.jpg 140w, https:\/\/caipirinha.spdns.org\/wp\/wp-content\/uploads\/Speed-Test-in-wlan0-768x1647.jpg 768w, https:\/\/caipirinha.spdns.org\/wp\/wp-content\/uploads\/Speed-Test-in-wlan0-716x1536.jpg 716w, https:\/\/caipirinha.spdns.org\/wp\/wp-content\/uploads\/Speed-Test-in-wlan0-955x2048.jpg 955w, https:\/\/caipirinha.spdns.org\/wp\/wp-content\/uploads\/Speed-Test-in-wlan0.jpg 1080w\" sizes=\"auto, (max-width: 478px) 100vw, 478px\" \/><figcaption class=\"wp-element-caption\">Routing via the Linux router and a commercial VPN to Brazil slows down the speed.<\/figcaption><\/figure>\n<figcaption class=\"blocks-gallery-caption wp-element-caption\">A smartphone in the network <em>wlan0<\/em><\/figcaption><\/figure>\n\n\n\n<h3 class=\"wp-block-heading\">Relocating the TV Set to DE, PT, BR<\/h3>\n\n\n\n<p>As a means of convenience, we want to set up a small web page that can be accessed on our smartphone so that we can &#8220;re-locate&#8221; the TV set between the countries Germany, Portugal, and Brazil. This simple &#8220;no frills&#8221; page will serve our purpose:<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">relocate.php:<\/h4>\n\n\n\n<pre class=\"wp-block-code\"><code>&lt;!DOCTYPE HTML PUBLIC \"-\/\/W3C\/\/DTD HTML 4.0 Transitional\/\/EN\">\n&lt;html>\n&lt;head>\n  &lt;title>TV Geo-Relocation&lt;\/title>\n  &lt;style type=\"text\/css\">\n    a:link { text-decoration:underline; font-weight:normal; color:#0000FF; }\n    a:visited { text-decoration:underline; font-weight:normal; color:#800080; }\n    a:hover { text-decoration:underline; font-weight:normal; color:#909090; }\n    a:active { text-decoration:blink; font-weight:normal; color:#008080; }\n    h1 { font-family:Arial,Helvetica,sans-serif; font-size:100%; color:maroon; text-indent:0.0cm; }\n    hr { text-indent:0.0cm; height:3px; width:100%; text-align:left; }\n    p { font-family:Arial,Helvetica,sans-serif; font-size:80%; color: black; text-indent:0.0cm; }\n    body { font-family: Arial, sans-serif; background-color:#FFFFD8; max-width: 600px; margin: 50px auto; padding: 20px; }\n    .flag { width: 24px; height: 16px; vertical-align: middle; margin-right: 10px; }\n    .radio-group { margin: 20px 0; }\n    input&#91;type=\"radio\"] { margin-right: 5px; }\n    button { padding: 10px 20px; margin: 10px; background: #007cba; color: white; border: none; cursor: pointer; }\n  &lt;\/style>\n  &lt;meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n  &lt;meta http-equiv=\"content-language\" content=\"de\">\n  &lt;meta http-equiv=\"cache control\" content=\"no-cache\">\n  &lt;meta http-equiv=\"pragma\" content=\"no-cache\">\n  &lt;meta name=\"author\" content=\"Gabriel R\u00fceck\">\n  &lt;meta name=\"date\" content=\"2026-02-17T18:00:00+01:00\">\n  &lt;meta name=\"robots\" content=\"noindex\">\n&lt;\/head>\n\n&lt;body bgcolor=\"seashell\">\n  &lt;?php\n    \/\/ Setze die neue Markierung f\u00fcr Pakete aus 192.168.3.0\/24\n    if ($_SERVER&#91;'REQUEST_METHOD'] === 'POST') {\n      $fwmark = $_POST&#91;'fwmark'] ?? '';\n      if (in_array($fwmark, &#91;'0','1','2'], true)) {\n        shell_exec('sudo \/srv\/www\/htdocs\/tv\/write_status.sh ' . escapeshellarg($fwmark));\n      }\n    }\n\n    \/\/ Hole aktuelle Markierung f\u00fcr Pakete aus 192.168.3.0\/24\n    $current_mark = trim(shell_exec('sudo \/srv\/www\/htdocs\/tv\/read_status.sh'));\n  ?>\n  &lt;h1>TV Geo-Relocation&lt;\/h1>\n\n  &lt;form method=\"POST\">\n    &lt;div class=\"radio-group\">\n      &lt;label>\n        &lt;input type=\"radio\" name=\"fwmark\" value=\"0\" &lt;?= $current_mark === '0x0' ? 'checked' : '' ?>>\n        &lt;img src=\"https:\/\/flagcdn.com\/24x18\/de.png\" srcset=\"https:\/\/flagcdn.com\/48x36\/de.png 2x\" class=\"flag\" alt=\"\ud83c\udde9\ud83c\uddea\"> Deutschland (0x0)\n      &lt;\/label>&lt;br>&lt;br>\n\n      &lt;label>\n        &lt;input type=\"radio\" name=\"fwmark\" value=\"1\" &lt;?= $current_mark === '0x1' ? 'checked' : '' ?>>\n        &lt;img src=\"https:\/\/flagcdn.com\/24x18\/pt.png\" srcset=\"https:\/\/flagcdn.com\/48x36\/pt.png 2x\" class=\"flag\" alt=\"\ud83c\uddf5\ud83c\uddf9\"> Portugal (0x1)\n      &lt;\/label>&lt;br>&lt;br>\n\n      &lt;label>\n        &lt;input type=\"radio\" name=\"fwmark\" value=\"2\" &lt;?= $current_mark === '0x2' ? 'checked' : '' ?>>\n        &lt;img src=\"https:\/\/flagcdn.com\/24x18\/br.png\" srcset=\"https:\/\/flagcdn.com\/48x36\/br.png 2x\" class=\"flag\" alt=\"\ud83c\udde7\ud83c\uddf7\"> Brasilien (0x2)\n      &lt;\/label>\n    &lt;\/div>\n      \n    &lt;button type=\"submit\">Anwenden&lt;\/button>\n    &lt;button type=\"button\" onclick=\"location.reload()\">Neu laden&lt;\/button>\n\n    &lt;p>Flags with courtesy from &lt;a href=\"https:\/\/flagpedia.net\" target=\"_blank\">flagpedia.net&lt;\/a>.&lt;\/p>\n  &lt;\/form>\n  \n&lt;\/body>\n&lt;\/html><\/code><\/pre>\n\n\n\n<p>This <a href=\"https:\/\/en.wikipedia.org\/wiki\/PHP\" target=\"_blank\" rel=\"noreferrer noopener\">PHP<\/a> page needs to be put in a suitable directory, and you need to have web server up and running, of course (not described in this article). In my case, the file is located in <em>\/srv\/www\/htdocs\/tv\/relocate.php<\/em>. In the header of the PHP file, you can see the line:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>&lt;meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\"><\/code><\/pre>\n\n\n\n<p>This line adapts the width of the page when being called on a smartphone so that it appears with a reasonable scaling on the smartphone screen. Furthermore, as you can see, this web page calls two <strong>shell scripts<\/strong>, and those are:<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">read_status.sh<\/h4>\n\n\n\n<pre class=\"wp-block-code\"><code>#! \/bin\/bash\n#\n# This script will be executed as root by the PHP scipt relocate.php\n#\n# Gabriel R\u00fceck 15.02.2026\n#\n\n\/usr\/sbin\/iptables -t mangle --line-numbers -L PREROUTING -n -v | fgrep \"eth0\" | sed -r 's\/^.*MARK (set|and) (0x&#91;&#91;:xdigit:]]+)\/\\2\/'<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">write_status.sh<\/h4>\n\n\n\n<pre class=\"wp-block-code\"><code>#! \/bin\/bash\n#\n# This script will be executed as root by the PHP scipt relocate.php\n#\n# Gabriel R\u00fceck 15.02.2026\n#\n\nLINE_NUMBER=$(\/usr\/sbin\/iptables -t mangle --line-numbers -L PREROUTING -n -v | fgrep \"eth0\" | sed 's\/^\\(&#91;&#91;:digit:]]\\+\\) \\+.*\/\\1\/')\nMARK=${1}\n\/usr\/sbin\/iptables -t mangle -R PREROUTING ${LINE_NUMBER} -i eth0 -s 192.168.3.0\/24 -j MARK --set-mark ${MARK}<\/code><\/pre>\n\n\n\n<p><strong>read_status.sh<\/strong> reads the corresponding routing entry from the <strong>mangle<\/strong> table [<a href=\"https:\/\/en.wikipedia.org\/wiki\/Netfilter\" target=\"_blank\" rel=\"noreferrer noopener\">6<\/a>], and this information enables the page <strong>relocate.php<\/strong> to display the correct country to which the traffic of the TV set if channeled when <em>relocate.php<\/em> is called initially. <strong>write_status.sh<\/strong> is used to modify the correct entry in the <strong>mangle<\/strong> table  and channel the traffic to the country select on the <a href=\"https:\/\/en.wikipedia.org\/wiki\/PHP\" target=\"_blank\" rel=\"noreferrer noopener\">PHP<\/a> page. Both <strong>read_status.sh<\/strong> as well as <strong>write_status.sh<\/strong> need to be executed as <em>root<\/em>, and therefore, they need to be listed in the <strong>sudoers<\/strong> file structure. [<a href=\"https:\/\/www.linuxfoundation.org\/blog\/blog\/classic-sysadmin-configuring-the-linux-sudoers-file\" target=\"_blank\" rel=\"noreferrer noopener\">7<\/a>], [<a href=\"https:\/\/www.digitalocean.com\/community\/tutorials\/how-to-edit-the-sudoers-file\" target=\"_blank\" rel=\"noreferrer noopener\">8<\/a>] explain the correct proceeding. In our case, the file <strong>\/etc\/sudoers.d\/wwwrun<\/strong> has been set up with the access rights <strong>0440<\/strong>, and this file should have the content:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>wwwrun ALL=(root) NOPASSWD: \/srv\/www\/htdocs\/tv\/read_status.sh\nwwwrun ALL=(root) NOPASSWD: \/srv\/www\/htdocs\/tv\/write_status.sh<\/code><\/pre>\n\n\n\n<p>Of course, we do not want arbitrary internet users to change the geo-location of the TV set, and therefore, the access to the <a href=\"https:\/\/en.wikipedia.org\/wiki\/PHP\" target=\"_blank\" rel=\"noreferrer noopener\">PHP<\/a> page <em>relocate.php<\/em> must be restricted. An easy, <strong>but not entirely secure method<\/strong> is to limit access to this page to the local networks. This can be done in the webserver configuration file (in my case: <strong>\/etc\/apache2\/httpd.conf.local<\/strong>) where we add:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code># TV Configuration\n&lt;Directory \/srv\/www\/htdocs\/tv>\n  Require local\n  Require ip 192.168.0.0\/16 127.0.0.0\/8 ::1\/128 fd00:0:0::\/48\n&lt;\/Directory><\/code><\/pre>\n\n\n\n<p>This will restrict access to local networks. But this is entirely fool-proof against advanced hacking attacks (see [<a href=\"https:\/\/www.forcepoint.com\/sites\/default\/files\/resources\/files\/report-attacking-internal-network-en_0.pdf\" target=\"_blank\" rel=\"noreferrer noopener\">9<\/a>] as an example).<\/p>\n\n\n\n<p>The <a href=\"https:\/\/en.wikipedia.org\/wiki\/PHP\" target=\"_blank\" rel=\"noreferrer noopener\">PHP<\/a> page should ultimately look like this on a smartphone:<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"478\" height=\"1024\" src=\"https:\/\/caipirinha.spdns.org\/wp\/wp-content\/uploads\/Relocation-Seite-478x1024.jpg\" alt=\"\" class=\"wp-image-2227\" srcset=\"https:\/\/caipirinha.spdns.org\/wp\/wp-content\/uploads\/Relocation-Seite-478x1024.jpg 478w, https:\/\/caipirinha.spdns.org\/wp\/wp-content\/uploads\/Relocation-Seite-140x300.jpg 140w, https:\/\/caipirinha.spdns.org\/wp\/wp-content\/uploads\/Relocation-Seite-768x1647.jpg 768w, https:\/\/caipirinha.spdns.org\/wp\/wp-content\/uploads\/Relocation-Seite-716x1536.jpg 716w, https:\/\/caipirinha.spdns.org\/wp\/wp-content\/uploads\/Relocation-Seite-955x2048.jpg 955w, https:\/\/caipirinha.spdns.org\/wp\/wp-content\/uploads\/Relocation-Seite.jpg 1080w\" sizes=\"auto, (max-width: 478px) 100vw, 478px\" \/><figcaption class=\"wp-element-caption\">TV Geo-Relocation Page<\/figcaption><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\">Shortcomings<\/h2>\n\n\n\n<p>During experiments with this setup, I have come across the following shortcoming:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>On my TV set, a Samsung GQ75Q80, I was able to configure a static IPv4 address. However, it seemed to me that the TV was still getting a dynamic IPv6 address from the <a href=\"https:\/\/fritz.com\/\" target=\"_blank\" rel=\"noreferrer noopener\">FRITZ!Box<\/a>. I suppose that if one really wants to isolate the TV set from the SoHo network, it would be necessary to use a separate physical network. Luckily, this did not impact the possibility to watch TV with the Portuguese TV app.<\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\">Conclusion<\/h2>\n\n\n\n<p>With Policy Routing and commercial VPN connections, it is possible to create additional networks in a SoHo environment that will allow client devices to behave as if they were in another country. Basically, you could also achieve that with a VPN connection on the device (smartphone, etc.) itself; however, you then might have access to other services in your SoHo network (printer, etc.). And in the case of a TV set, I am not even sure if there are models that can build up VPN connections themselves. However, the setup described here also shows that it is not trivial as several services need to be configured and act together in a meaningful way.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Sources<\/h2>\n\n\n\n<ul class=\"wp-block-list\">\n<li>[<a href=\"https:\/\/caipirinha.spdns.org\/wp\/?p=765\" target=\"_blank\" rel=\"noreferrer noopener\">1<\/a>] = <a href=\"https:\/\/caipirinha.spdns.org\/wp\/?p=734\" target=\"_blank\" rel=\"noreferrer noopener\"><\/a><a href=\"https:\/\/caipirinha.spdns.org\/wp\/?p=765\" target=\"_blank\" rel=\"noreferrer noopener\">Setting up Client VPNs, Policy Routing<\/a><\/li>\n\n\n\n<li>[<a href=\"https:\/\/caipirinha.spdns.org\/wp\/?p=734\">2<\/a>] = <a href=\"https:\/\/caipirinha.spdns.org\/wp\/?p=734\" target=\"_blank\" rel=\"noreferrer noopener\">Setting up Dual Stack VPNs<\/a><\/li>\n\n\n\n<li>[<a href=\"https:\/\/unix.stackexchange.com\/questions\/504366\/port-forwarding-over-openvpn\" target=\"_blank\" rel=\"noreferrer noopener\">3<\/a>] = <a href=\"https:\/\/unix.stackexchange.com\/questions\/504366\/port-forwarding-over-openvpn\" target=\"_blank\" rel=\"noreferrer noopener\">iptables &#8211; Port forwarding over OpenVpn<\/a><\/li>\n\n\n\n<li>[<a href=\"https:\/\/lartc.org\/howto\/lartc.rpdb.multiple-links.html\" target=\"_blank\" rel=\"noreferrer noopener\">4<\/a>] = <a href=\"https:\/\/lartc.org\/howto\/lartc.rpdb.multiple-links.html\" target=\"_blank\" rel=\"noreferrer noopener\">Routing for multiple uplinks\/providers<\/a><\/li>\n\n\n\n<li>[<a href=\"https:\/\/www.thomas-krenn.com\/en\/wiki\/Two_Default_Gateways_on_One_System\" target=\"_blank\" rel=\"noreferrer noopener\">5<\/a>] = <a href=\"https:\/\/www.thomas-krenn.com\/en\/wiki\/Two_Default_Gateways_on_One_System\" target=\"_blank\" rel=\"noreferrer noopener\">Two Default Gateways on One System<\/a><\/li>\n\n\n\n<li>[<a href=\"https:\/\/en.wikipedia.org\/wiki\/Netfilter\" target=\"_blank\" rel=\"noreferrer noopener\">6<\/a>] = <a href=\"https:\/\/en.wikipedia.org\/wiki\/Netfilter\" target=\"_blank\" rel=\"noreferrer noopener\">Netfilter<\/a><\/li>\n\n\n\n<li>[<a href=\"https:\/\/www.linuxfoundation.org\/blog\/blog\/classic-sysadmin-configuring-the-linux-sudoers-file\" target=\"_blank\" rel=\"noreferrer noopener\">7<\/a>] = <a href=\"https:\/\/www.linuxfoundation.org\/blog\/blog\/classic-sysadmin-configuring-the-linux-sudoers-file\" target=\"_blank\" rel=\"noreferrer noopener\">Classic SysAdmin: Configuring the Linux Sudoers File<\/a><\/li>\n\n\n\n<li>[<a href=\"https:\/\/www.digitalocean.com\/community\/tutorials\/how-to-edit-the-sudoers-file\" target=\"_blank\" rel=\"noreferrer noopener\">8<\/a>] = <a href=\"https:\/\/www.digitalocean.com\/community\/tutorials\/how-to-edit-the-sudoers-file\" target=\"_blank\" rel=\"noreferrer noopener\">How To Edit the Sudoers File Safely<\/a><\/li>\n\n\n\n<li>[<a href=\"https:\/\/www.forcepoint.com\/sites\/default\/files\/resources\/files\/report-attacking-internal-network-en_0.pdf\" target=\"_blank\" rel=\"noreferrer noopener\">9<\/a>] = <a href=\"https:\/\/www.forcepoint.com\/sites\/default\/files\/resources\/files\/report-attacking-internal-network-en_0.pdf\" target=\"_blank\" rel=\"noreferrer noopener\">Forcepoint Research Report: Attacking the internal network from the public Internet using a browser as a proxy<\/a><\/li>\n<\/ul>\n\n\n\n<p><\/p>\n","protected":false},"excerpt":{"rendered":"<p>This blog post explains how Policy Routing on a Linux server together with commercial VPNs to other countries can help you to put your client devices (TV, smartphones) logically into the internet of other countries in order to get around geo-blocking.<\/p>\n","protected":false},"author":1,"featured_media":2234,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[35],"tags":[102,97,101,98],"class_list":["post-2220","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-it","tag-iptables","tag-openvpn","tag-policyrouting","tag-vpn"],"_links":{"self":[{"href":"https:\/\/caipirinha.spdns.org\/wp\/index.php?rest_route=\/wp\/v2\/posts\/2220","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/caipirinha.spdns.org\/wp\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/caipirinha.spdns.org\/wp\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/caipirinha.spdns.org\/wp\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/caipirinha.spdns.org\/wp\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=2220"}],"version-history":[{"count":8,"href":"https:\/\/caipirinha.spdns.org\/wp\/index.php?rest_route=\/wp\/v2\/posts\/2220\/revisions"}],"predecessor-version":[{"id":2235,"href":"https:\/\/caipirinha.spdns.org\/wp\/index.php?rest_route=\/wp\/v2\/posts\/2220\/revisions\/2235"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/caipirinha.spdns.org\/wp\/index.php?rest_route=\/wp\/v2\/media\/2234"}],"wp:attachment":[{"href":"https:\/\/caipirinha.spdns.org\/wp\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=2220"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/caipirinha.spdns.org\/wp\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=2220"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/caipirinha.spdns.org\/wp\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=2220"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}