Problems with Iptables and VPN

hi everybody,

i’m having difficulties configuring iptables on my raspberry pi osmc.
my setup looks like this:

Raspberry Pi 3 with OSMC connected with my router through LAN
Openvpn (Openvpn Manager Addon in OSMC)
VPN Account
Iptables and iptables-persistent

What i wanted to to:
1.Force the whole trafffic through the Tunnel and drop all traffic, if the vpn connection is lost.
2. Use the tethering option in OSMC to create an wifi hotspot, so that i can use the vpn on my laptop as well.

I tried to accomplish this with iptables. I don’t have a good understanding of iptables, but i’ve read some how-tos and forum discussions.
The problem is that one time it seems to work, the other time it doesn’t (i get something like “active filtering but no valid connection” or i have a connection to the vpn but can’t get traffic out)

My rules look like this:

*filter
:INPUT DROP [4908:3410849]
:FORWARD DROP [7062:3114188]
:OUTPUT DROP [4295:793623]

#SSH
-A INPUT -p tcp -m tcp --dport 22 -j ACCEPT
-A OUTPUT -p tcp -m tcp --sport 22 -j ACCEPT

#DNS
-A INPUT -i eth0 -s DNS SERVER 1 -p udp -m udp --sport 53 -j ACCEPT
-A OUTPUT -o eth0 -d DNS SERVER 1 -p udp -m udp --dport 53 -j ACCEPT
-A INPUT -i eth0 -s DNS SERVER 1 -p tcp -m tcp --sport 53 -j ACCEPT
-A OUTPUT -o eth0 -d DNS SERVER 1 -p tcp -m tcp --dport 53 -j ACCEPT
-A INPUT -i eth0 -s DNS SERVER 2 -p udp -m udp --sport 53 -j ACCEPT
-A OUTPUT -o eth0 -d DNS SERVER 2 -p udp -m udp --dport 53 -j ACCEPT
-A INPUT -i eth0 -s DNS SERVER 2 -p tcp -m tcp --sport 53 -j ACCEPT
-A OUTPUT -o eth0 -d DNS SERVER 2 -p tcp -m tcp --dport 53 -j ACCEPT

#TRAFFIC TO VPN
-A INPUT -i eth0 -p udp -s IP-VPN --sport VPN-Port -j ACCEPT
-A OUTPUT -o eth0 -p udp -d IP-VPN --dport VPN-Port -j ACCEPT

#TRAFFIC LOCAL
-A INPUT -s 192.168.0.0/24 -j ACCEPT
-A OUTPUT -d 192.168.0.0/24 -j ACCEPT

#TETHERING
-A INPUT -i tether -j ACCEPT
-A OUTPUT -o tether -j ACCEPT

#TRAFFIC ON TUN0
-A INPUT -i tun0 -j ACCEPT
-A OUTPUT -o tun0 -j ACCEPT

#FORWARDING
-A FORWARD -i tether -o tun0 -j ACCEPT
-A FORWARD -i tun0 -o tether -j ACCEPT
-A FORWARD -i tun0 -o eth0 -m state --state RELATED,ESTABLISHED -j ACCEPT
-A FORWARD -i eth0 -o tun0 -j ACCEPT

COMMIT

Can anyone help me with my problem? Did I miss something? Is something unneccessary?

I can’t comment on the tethering part but your iptables rules for the VPN seem to be far too complicated. Sure, it’s possible to over-engineer everything but it’s not going to help in the vast majority of cases, and you’re probably not trying to build an enterprise-grade network.

You are on a home network and, TBH, I see little value in restricting INPUT traffic. Your router will/should reject all unsolicited incoming traffic from the Internet and if there’s something nasty already inside your network, well it’s pretty much Game Over.

The phrase “if the vpn connection is lost” is a bit general and can have a number of meanings. If you mean, for example, that the openvpn process dies and disappears, that can be taken care of by systemd, which can be configured to restart it automatically. If the network drops or the VPN server disconnects, openvpn will already try to reconnect until the network is restored. Perhaps you can clarify what kind of scenario you’re protecting yourself against. My own experience is that on Linux-based systems openvpn hardly ever crashes once it’s been properly configured.

There is one other thing to bear in mind: that in its current state OSMC’s network manager, connman, is (a) unable to deal with DNS push directives from an openvpn server and (b) will by default send all DNS traffic outside of the VPN tunnel. This can be worked around but it should be noted, since restricting all non-local traffic to tun0 would by default mean that DNS is blocked.

hey, thank you for your quick answer.

by “if the vpn connection is lost” i mean that i don’t want internet traffic (except maybe dns) to go outside the tunnel in case the connection to the vpn gets lost (like a killswitch). in the case of connection loss i want that internet traffic can’t get out until I’m connected to the vpn again.

But even if the vpn is down i want to access my NAS and access the pi through ssh.

what rules could i simplify? (the whole forwarding is meant to be for tethering and it works, but maybe this is too complicated as well?)
in my case dropping the input traffic didn’t cause problems, it’s something about the output drop policy i can’t figure out.

“This can be worked around but it should be noted, since restricting all non-local traffic to tun0 would by default mean that DNS is blocked”
that’s why i set all the dns rules, to allow traffic to the dns-servers even if tun0 isn’t established, wasn’t that right?

So which additional scenario are you trying to cover? We can restart the openvpn process automatically without resorting to iptables and openvpn will automatically restart a connection that gets dropped.

Openvpn can run either as a client (outbound traffic) or as a server (inbound traffic). Since you talk about forwarding tethered traffic via the VPN, I assume you are talking about running a VPN client, in which case local (LAN) access is not affected by running openvpn.

Why do that? It will probably lead to DNS leakage and, if tun0 is down, why would you want to allow any outbound traffic?

I’ve avoided commenting on the tethering side since AFAIK it should work without further configuration once enabled. That said, I’ve never used tethering myself, so might have missed some aspect that requires the use of iptables.

which additional scenario are you trying to cover? We can restart the openvpn process automatically without resorting to iptables and openvpn will automatically restart a connection that gets dropped.

but what happens between connection drop and the restarted vpn connection? sometimes it takes several minutes until the vpn connection is established again… in this time the traffic would go outside the tunnel, wouldn’t it?

Openvpn can run either as a client (outbound traffic) or as a server (inbound traffic). Since you talk about forwarding tethered traffic via the VPN, I assume you are talking about running a VPN client, in which case local (LAN) access is not affected by running openvpn.

ah ok, i didn’t know that.

Why do that? It will probably lead to DNS leakage and, if tun0 is down, why would you want to allow any outbound traffic?

i tried several times to do it without allowing dns on port 53, but it never worked, so allowed it and set it to the vpn’s dns server. first i used opendns server, which worked. (i tried to set it to the vpn’s dns server today, but somehow it didn’t work)

My main problem is that my rules i posted above don’t work all the time. sometimes they work, sometimes i can’t connect to the vpn at all, sometimes i can connect to the vpn but can’t go to any website)

what am I doing wrong? :unamused:

AFAIK, if tun0 still exists and the routing table still directs traffic to it, then no leak should occur.

You are over-engineering a solution to a problem that is unlikely to occur. The irony is that at the same time you are sending your DNS traffic outside the tunnel, so that all the sites you visit are (probably) being sent in the clear.

FYI, I wrote an iptables killswitch in 6 lines (or 5 if you exclude the flush). There are probably more elegant ways in iptables, but it seems to work. Here it is:

iptables -F
iptables -A OUTPUT -o lo -j ACCEPT
iptables -A OUTPUT -s 192.168.0.0/16 -d 192.168.0.0/16 -j ACCEPT
iptables -A OUTPUT -o tun+ -j ACCEPT
iptables -A OUTPUT -p udp --dport PPP -d XX.XX.XX.XX -j ACCEPT #Configure!
iptables -A OUTPUT -j DROP

I suspect that you might have DNS issues with it, but feel free to use it. Here it is in operation:

osmc@osmc:~$ sudo iptables -F
osmc@osmc:~$ ping -c1 8.8.8.8
PING 8.8.8.8 (8.8.8.8): 56 data bytes
64 bytes from 8.8.8.8: seq=0 ttl=59 time=66.150 ms

--- 8.8.8.8 ping statistics ---
1 packets transmitted, 1 packets received, 0% packet loss
round-trip min/avg/max = 66.150/66.150/66.150 ms
osmc@osmc:~$ ping -c1 osmc.tv
PING osmc.tv (159.253.212.250): 56 data bytes
64 bytes from 159.253.212.250: seq=0 ttl=57 time=191.827 ms

--- osmc.tv ping statistics ---
1 packets transmitted, 1 packets received, 0% packet loss
round-trip min/avg/max = 191.827/191.827/191.827 ms
osmc@osmc:~$ sudo ./killsw.sh 
osmc@osmc:~$ ping -c1 8.8.8.8
PING 8.8.8.8 (8.8.8.8): 56 data bytes
ping: sendto: Operation not permitted
osmc@osmc:~$ ping -c1 osmc.tv
PING osmc.tv (159.253.212.250): 56 data bytes
ping: sendto: Operation not permitted
osmc@osmc:~$ sudo systemctl start openvpn
osmc@osmc:~$ ping -c1 8.8.8.8
PING 8.8.8.8 (8.8.8.8): 56 data bytes
64 bytes from 8.8.8.8: seq=0 ttl=58 time=125.014 ms

--- 8.8.8.8 ping statistics ---
1 packets transmitted, 1 packets received, 0% packet loss
round-trip min/avg/max = 125.014/125.014/125.014 ms
osmc@osmc:~$ ping -c1 osmc.tv
PING osmc.tv (159.253.212.250): 56 data bytes
64 bytes from 159.253.212.250: seq=0 ttl=52 time=259.144 ms

--- osmc.tv ping statistics ---
1 packets transmitted, 1 packets received, 0% packet loss
round-trip min/avg/max = 259.144/259.144/259.144 ms
osmc@osmc:~$ sudo systemctl stop openvpn
osmc@osmc:~$ ping -c1 8.8.8.8
PING 8.8.8.8 (8.8.8.8): 56 data bytes
ping: sendto: Operation not permitted
osmc@osmc:~$ ping -c1 osmc.tv
PING osmc.tv (159.253.212.250): 56 data bytes
ping: sendto: Operation not permitted
osmc@osmc:~$ ping -c1 192.168.8.3
PING 192.168.8.3 (192.168.8.3): 56 data bytes
64 bytes from 192.168.8.3: seq=0 ttl=64 time=0.518 ms

--- 192.168.8.3 ping statistics ---
1 packets transmitted, 1 packets received, 0% packet loss
round-trip min/avg/max = 0.518/0.518/0.518 ms
osmc@osmc:~$ ping 8.8.8.8
PING 8.8.8.8 (8.8.8.8): 56 data bytes
ping: sendto: Operation not permitted

Edit: Slimmed the script down further!

Thank you very much!!! i’ll try it when I’m at home…

another question:
i read some thread about dns nameservers (i didn’t quite understand all, because my knowledge of linux is still very little, sorry if the question is dumb or doesn’t make sense at all)
would it solve the dns problem if i set the nameserver in /etc/resolv.conf to 10.8.0.1 and chattr +i /etc/resolve.conf so that it can’t be changed? :thinking:

Try it. :wink: You’ll only have DNS once the tunnel is up an running.

that would be ok, i just need dns when i’m connected to the vpn. and the dns would go through the tunnel, wouldn’t it?

i tested changing the nameserver in /etc/resolve.conf:
it seems to work, at least i can ping hosts, BUT tethering isn’t working… i can connect to the hotspot but can’t open websites (dns seems to work though…when i put in an IP i get the hostname but the website won’t open)

EDIT:
i just read your last post again. you meant i’ll just have dns when tun is up using your iptables rules? thanks, i’ll try that :blush:

No. It has nothing to do with the iptable rules. You’ll only see IP address 10.8.0.1 after the tunnel has been established.

because of the nameserver changed to 10.8.0.1 or shouldn’t i change that? (i’m sorry for asking so many question)

I should have been clearer. IP address 10.8.0.1 is not a public address and the only way you will be able to access it is through the VPN tunnel. On the other hand, if you choose, say, OpenDNS (208.67.222.222 and 208.67.220.220) as your DNS resolver(s) you will be able to see these addresses until you apply the iptables rules, after which all traffic must pass through tun0.

where should i put the ip of the opendns servers? in “myOSMC/Network” or in /etc/resolv.conf?
(when i put them in “myOSMC/Network” /etc/resolv.conf will still say “nameserver 127.0.0.1”)

It’s hacky, but put them in /etc/resolv.conf. If you use the iptables script, the DNS resolvers should differ from the address(es) entered in myOSMC > Network.

Interesting. That’s not my experience - and I just checked, to be sure - but it’s not an issue in this case if you directly modify /etc/resolv.conf.

Interesting. That’s not my experience - and I just checked, to be sure - but it’s not an issue in this case if you directly modify /etc/resolv.conf.

i checked several times as well, i put different dns servers in “myOSMC/Network” and rebooted between changes, but /etc/resolv.conf always says 127.0.0.1

i now put it in /etc/resolv.conf and tried everything with your rules and it seems to work :slight_smile: thank you very much again!

Unfortunately tethering isn’t working… i can connect to the hotspot, but can’t go to any websites…

I have no experience of using tethering, but does it work without the VPN? If you’ve never had tethering working, disable the VPN/iptables before you proceed any further.

i now put it in /etc/resolv.conf and tried everything with your rules and it seems to work :slight_smile: thank you very much again!

ok, it doesn’t work anymore (i didn’t change anything), i think it has something to do with the opendns servers because when i put 8.8.8.8 in /etc/resolv.conf i can ping websites.

btw: i found out why /etc/resolv.conf kept updating to 127.0.0.1
i had dnsproxy=yes in /etc/connman.prefs because apparently you need it for thethering… if i put it to “no” /etc/resolv.conf keeps the dns servers.

EDIT:
when i set dnsproxy=yes and chattr +i /etc/resolv.conf tethering is working (and it uses the opendns servers…)
but it seems that way it doesn’t matter what’s in /etc/resolv.conf because it uses the opendns servers (they are also put in “myosmc/network”) even if i just put 8.8.8.8 in /etc/resolv.conf :thinking:

If you are correct and tethering ignores /etc/resolv.conf, and uses the resolvers from myOSMC > Network, then I think you have a problem.

There is a (deliberate) “feature” of connman that sets an explicit route for each DNS resolver it has that will effectively ignore the default gateway. If you type route -n you’ll see what I mean. Without tethering or VPN enabled it’ll probably look something like this:

osmc@osmc:~$ route -n
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
0.0.0.0         192.168.1.1     0.0.0.0         UG    0      0        0 eth0
192.168.1.0     0.0.0.0         255.255.255.0   U     0      0        0 eth0
208.67.222.222  0.0.0.0         255.255.255.255 UH    0      0        0 eth0
208.67.220.220  0.0.0.0         255.255.255.255 UH    0      0        0 eth0

Those last two entries are the problem. The kernel will always send traffic to OpenDNS through interface eth0, even when tun0 is there. However, once the iptables rules are in effect, outbound traffic is only permitted through tun0 and, if tethering ignores /etc/resolv.conf settings, you will therefore have no DNS.

If you are correct and tethering ignores /etc/resolv.conf then, unless @sam_nazarko can think of a workaround, it looks like tethering in its current form is incompatible with running a secure VPN.

here’s what route route -n looks like with /etc/resolv.conf set to nameserver 8.8.8.8 and the DNS servers in “MyOSMC/Network” set to the opendns servers:

image

it’s the same when tethering is disabled.

Is there any way to tell the kernel to send dns through tun0 instead of eth0?

Run host -v osmc.tv and look for a line like:

Received 100 bytes from 208.67.220.220#53 in 116 ms

That’s the resolver it’s normally using. The question then is which one does tethering use?