Score:0

Generate iptables rules while connecting to VPN Server

ad flag

I'm building a virtual Ubuntu Server(LXC on Proxmox) that shall act as router and tunnel some devices(e.g. AppleTV) of my local network through a VPN (expressVPN). Connecting and routing to different VPN destinations (different countries) is working.

But some services still know that I'm not calling from the country the VPN Server is standing in. (I think its called DNS leaking???)

Thats because my client, let's say the AppleTV box uses e.g. 1.1.1.1 as DNS. It doesn't know the DNS server the VPN Server published to my gateway.

To prevent that from happening I'ld like to use the VPN's DNS service I receive when connecting. I pointed the AppleTV to my gateway as DNS and wrote some iptables rules to DNAT the requests to the DNS servers provided by the VPN server. (Hope that makes sense)

# Route DNS Traffic
iptables -t nat -A PREROUTING -p tcp --dst x.x.x.x --dport 53 -j DNAT --to-destination 10.54.0.1:53
iptables -t nat -A PREROUTING -p udp --dst x.x.x.x --dport 53 -j DNAT --to-destination 10.54.0.1:53

That works well.

Question

How to automatically generate these rules when establishing the OpenVPN connection? The specific DNS Address will change when connection to another VPN station (e.g. different country). Or is there a better solution?

I was thinking about putting it in the update-systemd-resolved, but that seems way to complicated. I assume there is a easy way to go.

I'm thankful for any hint.

Score:0
ad flag

I'll answer my own question to show my solution.

I learned that resolved uses a dns via stub (127.0.0.53) and therefore knows how to use the DNS of the VPN.

I "just" had to forward/nat the DNS requests from the LAN clients who are using this server as a gateway (and DNS).

In the openvpn client configuration I added the following lines:

mci@vpngateway:/etc/openvpn$ head destinations/belgium_udp.ovpn -n4
script-security 2
up /etc/openvpn/linkup.sh
down /etc/openvpn/linkdown.sh
down-pre

My scripts are up...

mci@vpngateway:/etc/openvpn$ cat linkup.sh 
#!/bin/bash

# First let systemd-resolved do its magic
/etc/openvpn/update-systemd-resolved $@

# Set iptable rules
/etc/openvpn/iptables_baserules.sh

# Set DNS
/etc/openvpn/iptables_setdns.sh

and down

mci@vpngateway:/etc/openvpn$ cat linkdown.sh 
#!/bin/bash

# First delete DNS iptables rules
/etc/openvpn/iptables_removedns.sh

# After let systemd-resolved do its magic
/etc/openvpn/update-systemd-resolved $@

basic rules to mostly drop other things

mci@vpngateway:/etc/openvpn$ cat iptables_baserules.sh 
#!/bin/bash

# Flush
iptables -t nat -F
iptables -t mangle -F
iptables -F
iptables -X

# Block All
iptables -P OUTPUT DROP
iptables -P INPUT DROP
iptables -P FORWARD DROP

# allow Localhost
iptables -A INPUT -i lo -j ACCEPT
iptables -A OUTPUT -o lo -j ACCEPT

iptables -A INPUT -p udp --sport 53 -j ACCEPT
iptables -A INPUT -p udp --dport 53 -j ACCEPT
iptables -A OUTPUT -p udp --sport 53 -j ACCEPT
iptables -A OUTPUT -p udp --dport 53 -j ACCEPT

# Make sure you can communicate with any DHCP server
iptables -A OUTPUT -d 255.255.255.255 -j ACCEPT
iptables -A INPUT -s 255.255.255.255 -j ACCEPT

# Make sure that you can communicate within your own network
iptables -A INPUT -s x.x.x.0/24 -d x.x.x.0/24 -j ACCEPT
iptables -A OUTPUT -s x.x.x.0/24 -d x.x.x.0/24 -j ACCEPT

# Allow established sessions to receive traffic:
iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT

# Allow TUN
iptables -A INPUT -i tun0 -j ACCEPT
iptables -A FORWARD -i tun0 -j ACCEPT
iptables -A FORWARD -o tun0 -j ACCEPT
iptables -t nat -A POSTROUTING -o tun0 -j MASQUERADE
iptables -A OUTPUT -o tun0 -j ACCEPT

# allow VPN connection
iptables -I OUTPUT 1 -p udp --destination-port 1195 -m comment --comment "Allow VPN connection" -j ACCEPT
iptables -I OUTPUT 1 -p tcp --destination-port 1195 -m comment --comment "Allow VPN connection" -j ACCEPT

# Block All
iptables -A OUTPUT -j DROP
iptables -A INPUT -j DROP
iptables -A FORWARD -j DROP

note these rules, I had to add them so the node itself could lookup a name after the vpn connection got closed (maybe because I'ld like to switch the vpn config to another server).

iptables -A INPUT -p udp --sport 53 -j ACCEPT
iptables -A INPUT -p udp --dport 53 -j ACCEPT
iptables -A OUTPUT -p udp --sport 53 -j ACCEPT
iptables -A OUTPUT -p udp --dport 53 -j ACCEPT

Last thing is to dynamicaly add the DNS nat

mci@vpngateway:/etc/openvpn$ cat iptables_setdns.sh 
#!/bin/bash

# Route DNS Traffic
# Get DNS from VPN
dns=$(resolvectl dns -i tun0)
dns=${dns##* }
echo "Found DNS on tun0: ${dns}"
iptables -t nat -A PREROUTING -p tcp --dst x.x.x.x --dport 53 -j DNAT --to-destination ${dns}:53
iptables -t nat -A PREROUTING -p udp --dst x.x.x.x --dport 53 -j DNAT --to-destination ${dns}:53

and remove it afterwards

mci@vpngateway:/etc/openvpn$ cat iptables_removedns.sh 
#!/bin/bash

# Route DNS Traffic
# Get DNS from VPN
dns=$(resolvectl dns -i tun0)
dns=${dns##* }
echo "Found DNS on tun0: ${dns}"
iptables -t nat -D PREROUTING -p tcp --dst x.x.x.x --dport 53 -j DNAT --to-destination ${dns}:53
iptables -t nat -D PREROUTING -p udp --dst x.x.x.x --dport 53 -j DNAT --to-destination ${dns}:53

Maybe this will help somebody else who is building a vpn gateway.

Score:0
uy flag

Welcome, you may use the up and down command in your openvpn *.conf file These allow to execute custom scripts. script-security 2 is requirede if you go this Road Example:

script-security 2
up /usr/local/bin/set-redirect-dns.sh
down /usr/local/bin/unset-redirect-dns.sh

The real iptables commands are in these scripts. Please check with the man page if script-security 2 is fine for you.

Michael avatar
ad flag
at the moment I'm using up and down to feed resolved with the vpns infos like DNS. e.g. `up /etc/openvpn/update-systemd-resolved` I'll give it a try to add some iptable rules. I just thought there is an out of the box solution. I assumed this as a common problem.
I sit in a Tesla and translated this thread with Ai:

mangohost

Post an answer

Most people don’t grasp that asking a lot of questions unlocks learning and improves interpersonal bonding. In Alison’s studies, for example, though people could accurately recall how many questions had been asked in their conversations, they didn’t intuit the link between questions and liking. Across four studies, in which participants were engaged in conversations themselves or read transcripts of others’ conversations, people tended not to realize that question asking would influence—or had influenced—the level of amity between the conversationalists.