The goal is to connect some network device(s), like TV, to the VPN. The device itself does not support any VPN functionality.
What I have
- Home LAN network with range
10.0.1.0/24
10.0.1.1
- gateway10.0.1.2
- Raspberry Pi10.0.1.3
- TV10.0.1.4
- NAS
- OpenVPN setup with range
10.8.0.0/24
10.8.0.1
- gateway10.8.0.2
- connected client
The main idea is to connect RPi to the VPN and route all traffic from TV through NAT into the VPN. To be able to still access the local NAS server, the traffic to 10.0.1.0/24
is not routed into the VPN. The RPi itself still uses your local gateway.
This way the only thing the TV must support is to manually set IP address, IP address of default gateway and IP address of DNS server.
I was using extra subnet
10.0.3.1/24
for TV and RPi (interface alias) before, but then the NAS (on subnet10.0.1.1/24
) was not accessible via DLNA. It uses broadcasts which are not routed between subnets.
I have almost zero knowledge of routing so there could be better solution. But hey, this works for me and might work for you too.
Manually set IP address, gateway and DNS on your TV you want to share the VPN connection with
IP address: 10.0.1.208
Gateway: 10.0.1.2
DNS: 8.8.8.8 (or any other DNS server, even your local at 10.0.1.x subnet)
I've had trouble using the same RPi also as DNS server (setting DNS to
10.0.1.2
). Another DNS server from the local network worked fine.
All these changes are lost on device restart. It could be persisted somehow. But this has the advantage that if you screw something up, simply restart the RPi and everything should reset.
Enable IP forwarding (this was already enabled for me)
sudo sysctl -w net.ipv4.ip_forward=1
Create new routing table name, eg. ovpn
with id 7
. This step is persistent.
cat /etc/iproute2/rt_tables
#
# reserved values
#
255 local
254 main
253 default
0 unspec
#
# local
#
#1 inr.ruhep
7 ovpn
Assign routing table ovpn
to the range 10.0.1.208/29
(this includes the TV with IP 10.0.1.208
).
sudo ip rule add from 10.0.1.208/29 table ovpn
Verify
sudo ip rule list
0: from all lookup local
32765: from 10.0.1.208/29 lookup ovpn
32766: from all lookup main
32767: from all lookup default
Allow forwarding in firewall
sudo iptables -A FORWARD -j ACCEPT
Now the TV should work like without any changes. You should be able to see NAS (using DLNA) and access internet (YouTube, browser etc.).
Download openvpn
client
sudo apt install openvpn
Ensure the
config.ovpn
file containsroute-nopull
clause. Otherwise you will be cut-off from ssh after connecting to VPN.
Prepare VPN credentials into file credentials.txt
(this is pretty insecure!)
cat credentials.txt
your-vpn-username
your-vpn-password
Connect to VPN
sudo openvpn --config config.ovpn --auth-user-pass credentials.txt --daemon
Note for scripting - when the command above finishes, the VPN might not be established yet. You have to wait a second or two.
This will create new tun0
device with 10.8.0.2
IP address, the default VPN gateway is 10.8.0.1
ip add
...
15: tun0: <POINTOPOINT,MULTICAST,NOARP,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UNKNOWN group default qlen 500
link/none
inet 10.8.0.2/24 scope global tun0
valid_lft forever preferred_lft forever
inet6 xxxx::xxxx:xxxx:xxxx:xxxx/64 scope link stable-privacy
valid_lft forever preferred_lft forever
Traffic from TV to local network should not go through the RPi as they are on the same network 10.0.1.0/24
. So we can safely route all the traffic on the RPi from 10.0.1.208/29
to the VPN gateway 10.8.0.1
on tun0
device
sudo ip route add default via 10.8.0.1 dev tun0 table ovpn
The table should look like this
sudo ip route show table ovpn
default via 10.8.0.1 dev tun0
Enable NAT on the tun0
device for VPN router to know how to send the traffic back
sudo iptables -t nat -A POSTROUTING -o tun0 -j MASQUERADE
Now you should still be able to access your local NAS. However the internet traffic should be routed via VPN. Check your public IP address via browser (eg. http://ifconfig.me).
To disconnect from VPN simply kill the openvpn
process
sudo killall openvpn
This will also automatically remove the default
route so all your traffic will go through your local gateway.
sudo ip route show table ovpn
The NAT
is also automatically removed.
You can have more devices connected to the VPN. Just setup each device like the TV above, except the IP address - choose a different from range 10.0.1.208/29
, that is 10.0.1.208
- 10.0.1.215
.
You can also enlarge the subnet first removing the prior settings and adding new setting. To add 8 more devices
sudo ip rule del from 10.0.1.208/29 table ovpn
sudo ip rule add from 10.0.1.208/28 table ovpn
I choose the starting IP address
10.0.1.208
because my router assigns the range10.0.1.100
-10.0.1.200
to WiFi devices. See this online range calculator (be aware of the starting IP address as the actual range could be a bit different than you might think).
You can emulate connected device's traffic on your RPi. This is useful when you can not run commands like ping
and curl
on the device (eg. TV).
First add unused IP address from the range 10.0.1.208/29
to RPi's ethernet card eth0
. I choose 10.0.1.209
sudo ip addr add 10.0.1.209/24 dev eth0
Verify
ip add
...
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000
link/ether xx:xx:xx:xx:xx:xx brd ff:ff:ff:ff:ff:ff
inet 10.0.1.2/24 brd 10.0.1.255 scope global dynamic noprefixroute eth0
valid_lft 1841sec preferred_lft 1391sec
inet 10.0.1.209/24 scope global secondary eth0
valid_lft forever preferred_lft forever
inet6 xxxx::xxxx:xxxx:xxxx:xxxx/64 scope link
valid_lft forever preferred_lft forever
...
Now you can send ping
from the IP address 10.0.1.209
ping -I 10.0.1.209 google.com -c 1
PING google.com (142.251.37.110) from 10.0.1.209 : 56(84) bytes of data.
64 bytes from xxx (yy.yy.yy.yy): icmp_seq=1 ttl=116 time=12.1 ms
and see it in the tcpdump
sudo tcpdump -i eth0 icmp
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on eth0, link-type EN10MB (Ethernet), snapshot length 262144 bytes
00:03:52.412033 IP 10.0.1.209 > xxx: ICMP echo request, id 4, seq 1, length 64
00:03:53.141391 IP xxx > 10.0.1.209: ICMP echo reply, id 4, seq 1, length 64
You can also check your public IP address using curl
. If you have established the VPN connection you can simply verify the routing. This should give you the public IP address of the VPN provider
curl --silent --interface 10.0.1.209 ifconfig.me
ww.xx.yy.zz
You should see something like this in the tcpdump
sudo tcpdump -i eth0 src net 10.0.1.209/32
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on eth0, link-type EN10MB (Ethernet), snapshot length 262144 bytes
00:13:52.400380 IP 10.0.1.209.50687 > xxx.bc.googleusercontent.com.http: Flags [S], seq 3384149146, win 64240, options [mss 1460,sackOK,TS val 1078011361 ecr 0,nop,wscale 7], length 0
00:13:52.412553 IP 10.0.1.209.50687 > xxx.bc.googleusercontent.com.http: Flags [.], ack 2725034648, win 502, options [nop,nop,TS val 1078011373 ecr 1415169667], length 0
00:13:52.412623 IP 10.0.1.209.50687 > xxx.bc.googleusercontent.com.http: Flags [P.], seq 0:75, ack 1, win 502, options [nop,nop,TS val 1078011373 ecr 1415169667], length 75: HTTP: GET / HTTP/1.1
00:13:52.544447 IP 10.0.1.209.50687 > xxx.bc.googleusercontent.com.http: Flags [.], ack 284, win 501, options [nop,nop,TS val 1078011505 ecr 1415169797], length 0
00:13:52.544870 IP 10.0.1.209.50687 > xxx.bc.googleusercontent.com.http: Flags [F.], seq 75, ack 284, win 501, options [nop,nop,TS val 1078011506 ecr 1415169797], length 0
00:13:52.557463 IP 10.0.1.209.50687 > xxx.bc.googleusercontent.com.http: Flags [.], ack 285, win 501, options [nop,nop,TS val 1078011518 ecr 1415169810], length 0
You can also check the public address of your local gateway
curl --silent --interface 10.0.1.2 ifconfig.me
aa.bb.cc.dd
After disconnecting from VPN you should have the same public address from both IP addresses
curl --silent --interface 10.0.1.209 ifconfig.me
aa.bb.cc.dd
When you are done, remove the assigned IP address from eth0
sudo ip addr del 10.0.1.209/24 dev eth0
Monitor traffic on eth0
interface from your connected devices
sudo tcpdump -i eth0 src net 10.0.1.208/29
Monitor ping
traffic on eth0
interface
sudo tcpdump -i eth0 icmp
Monitor all traffic on tun0
device
sudo tcpdump -i tun0
Inspect dropping packets (the numbers should not go up)
sudo iptables -v -L FORWARD
Chain FORWARD (policy DROP 250 packets, 20642 bytes)
...
Or view more
sudo iptables -v -L
View NAT rules
sudo iptables -v -t nat -L
Show ovpn
routing table
sudo ip route show table ovpn
Show how the ovpn
table is used
sudo ip rule list