Score:1

Assigning public IP to OpenVPN client. iptables, route or what to use for that?

jp flag

I have a server with Pi-Hole configured to block Ads and trackers. The clients are connected via OpenVPN and get addresses from 10.8.0.0/24. OpenVPN only pushes the DNS to the client and the traffic is routed via the local gateway but of course, every client on the VPN can contact every other client via their 10.8.0.x addresses.

I have ordered a second ipv4 that I would like to use specifically for the client 10.8.0.4. I want to be able to access the public ip and expose that client directly to the internet to use a locally hosted Nextcloud.

I searched Server Fault and found some similar problems. I tried to add POSTROUTING and PREROUTING rules to iptables but that didn't work out. The ipv4 is currently added temporarily to eth0 via 'ip addr add xx.xx.xx.xx. dev eth0', not tun0 (is that correct?). The OpenVPN Server is configured exactly as mentioned in the Pi-Hole docs (https://docs.pi-hole.net/guides/vpn/openvpn/only-dns-via-vpn/). net.ipv4.ip_forward is enabled.

Do I even have to use iptables? Is it possible or advised to add the public ip to a route or something? Sorry if the question sounds silly. I'm pretty new to OpenVPN and Route/iptables configuration.

That is the first thing I tried: Redirect all incoming traffic from a secondary public IP to an internal IP address using iptables

My current iptables rules are:

# Generated by xtables-save v1.8.2 on Thu Dec 12 14:37:26 2019
*nat
:PREROUTING ACCEPT [329:28209]
:INPUT ACCEPT [281:25114]
:POSTROUTING ACCEPT [17:1423]
:OUTPUT ACCEPT [245:22126]
-A POSTROUTING -s 10.8.0.0/24 ! -d 10.8.0.0/24 -j SNAT --to-source xx.xx.xx.xx
-A POSTROUTING -o eth0 -j MASQUERADE
COMMIT
# Completed on Thu Dec 12 14:37:26 2019
# Generated by xtables-save v1.8.2 on Thu Dec 12 14:37:26 2019
*filter
:INPUT DROP [0:0]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
-A INPUT -i lo -j ACCEPT
-A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
-A INPUT -i tun0 -j ACCEPT
-A INPUT -i tun0 -p tcp -m tcp --dport 53 -j ACCEPT
-A INPUT -i tun0 -p udp -m udp --dport 53 -j ACCEPT
-A INPUT -i tun0 -p tcp -m tcp --dport 80 -j ACCEPT
-A INPUT -i eth0 -p tcp -m tcp --dport 80 -j ACCEPT
-A INPUT -i tun0 -p tcp -m tcp --dport 443 -j ACCEPT
-A INPUT -i eth0 -p tcp -m tcp --dport 443 -j ACCEPT
-A INPUT -p tcp -m tcp --dport 2202 -j ACCEPT
-A INPUT -p tcp -m tcp --dport 1194 -j ACCEPT
-A INPUT -p udp -m udp --dport 1194 -j ACCEPT
-A INPUT -p udp -m udp --dport 80 -j REJECT --reject-with icmp-port-unreachable
-A INPUT -p udp -m udp --dport 443 -j REJECT --reject-with icmp-port-unreachable
COMMIT
# Completed on Thu Dec 12 14:37:26 2019

iptables NAT rules:

Chain PREROUTING (policy ACCEPT)
target     prot opt source               destination

Chain INPUT (policy ACCEPT)
target     prot opt source               destination

Chain POSTROUTING (policy ACCEPT)
target     prot opt source               destination
SNAT       all  --  10.8.0.0/24         !10.8.0.0/24          to:xx.xx.xx.xx
MASQUERADE  all  --  anywhere             anywhere

Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination

After the comment from NiKiZe i added the public ip address temporarily via

ip addr add xx.xx.xx.xx dev eth0

and entered both rules (to clarify that: i exported the working ruleset via iptables-save, edited both commands in and restored it via iptables-restore)

-A PREROUTING -d xx.xx.xx.xx -j DNAT --to-destination 10.8.0.4
-A POSTROUTING -s 10.8.0.4 ! -d 10.8.0.4 -j SNAT --to-source xx.xx.xx.xx

I then opened several terminal sessions and monitored the web traffic with tcpdump at the OpenVPN server and my local server, confirming that incoming traffic at eth0 to pi.hole.http is routed to my local server server.vpn.http correctly. But the answer times out...

My current nat rules are:

user@dns:~# iptables -t nat -vL --line-numbers
Chain PREROUTING (policy ACCEPT 1 packets, 52 bytes)
num   pkts bytes target     prot opt in     out     source               destination
1        0     0 DNAT       all  --  any    any     anywhere             pi.hole              to:10.8.0.4

Chain INPUT (policy ACCEPT 0 packets, 0 bytes)
num   pkts bytes target     prot opt in     out     source               destination

Chain POSTROUTING (policy ACCEPT 1 packets, 60 bytes)
num   pkts bytes target     prot opt in     out     source               destination
1        0     0 SNAT       all  --  any    any     server.vpn        !server.vpn         to:xx.xx.xx.xx <- temporarily added ip address
2        0     0 SNAT       all  --  any    any     10.8.0.0/24         !10.8.0.0/24          to:xx.xx.xx.xx <- main ip address, statically entered
3        0     0 MASQUERADE  all  --  any    eth0    anywhere             anywhere

Chain OUTPUT (policy ACCEPT 1 packets, 60 bytes)
num   pkts bytes target     prot opt in     out     source               destination

Another edit: When i add 'src server.vpn' to tcpdump i can see that there is no outbound traffic from the local server. So there has to be either a problem with the local server configuration or the postrouting rule. Am i correct?

After changing the route on the server.vpn the connection is working. 'route -n' Before:

Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
0.0.0.0         192.168.178.1   0.0.0.0         UG    0      0        0 eth0
10.8.0.0        0.0.0.0         255.255.255.0   U     0      0        0 tun0
169.254.0.0     0.0.0.0         255.255.0.0     U     0      0        0 eth3
169.254.160.0   169.254.160.1   255.255.248.0   UG    0      0        0 tun1000
169.254.160.0   0.0.0.0         255.255.248.0   U     0      0        0 tun1000
172.17.0.0      0.0.0.0         255.255.0.0     U     0      0        0 docker0
192.168.178.0   0.0.0.0         255.255.255.0   U     0      0        0 eth0

And after:

Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
0.0.0.0         10.8.0.1        0.0.0.0         UG    0      0        0 tun0
10.8.0.0        0.0.0.0         255.255.255.0   U     0      0        0 tun0
169.254.0.0     0.0.0.0         255.255.0.0     U     0      0        0 eth3
169.254.160.0   169.254.160.1   255.255.248.0   UG    0      0        0 tun1000
169.254.160.0   0.0.0.0         255.255.248.0   U     0      0        0 tun1000
172.17.0.0      0.0.0.0         255.255.0.0     U     0      0        0 docker0
192.168.178.0   0.0.0.0         255.255.255.0   U     0      0        0 eth0

If i understand this correctly, that means that EVERY network connection, even initiated by server.vpn is routed via the VPN. This is not the anticipated behavior. I simply want the server to be accessible locally and use the regular, locally routed internet and also answer connections routed from the public ip on the OpenVPN Server.

in flag
The public IP needs to be added to the same interface as where the gateway for that address is, so most likely your internet/eth0 interface (the alternative would be to get a range which is routed thru your public IP) The "first thing I tried" link is what you will need to do, but there is probably more gotchas on the way. tcpdump is a great tool to trace traffic, and try to understand the flow. the counters in iptables is another often missed tool to diagnose issues.
Thomson avatar
jp flag
Thank you for the hints. I've checked the tun0 interface at the local server and the OpenVPN server. After adding the pre and postrouting rules, i can see via tcpdump the traffic coming in at the local server but no answer is returned. It times out. Does that mean my postrouting rule is wrong?
in flag
You will need to get the traffic to flow both ways. using tcpdump check where the traffic comes from, and verify that you have a route that takes that traffic back.
Thomson avatar
jp flag
I thought that i had that covered with the POSTROUTING rule on the OpenVPN server. But obviously the server.vpn is not sending an answer to the http response. I checked with tcpdump again and found that the response incoming from the OpenVPN server on tun0 is answered on eth0 and therefore dropped by the recipient. Do i have to add a static routing rule to the server.vpn as well? iptables is available there but what rule is needed there? How do i make sure that traffic incoming from tun0 is answered without changing the default gateway?
in flag
Yes this probably ends up with a "multi homed" setup, which means that the common way to resolve this is using `ip rule` and `ip route` ex. https://serverfault.com/a/736047/187998 (you do not have to create names for the tables, but can instead just use numbers)
Thomson avatar
jp flag
Thank you for your help! I managed to get it working by setting the OpenVPN server as the gateway but had no luck in setting up a "multi homed" setup by now. I'm currently reading more about the configuration of OpenVPN, iptables and routing in general. I hope to get that working.
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.