Linux – OpenVPN + iptables / NAT routing

iptableslinuxopenvpn

I'm trying to set up an OpenVPN VPN, which will carry some (but not all) traffic from the clients to the internet via the OpenVPN server.

My OpenVPN server has a public IP on eth0, and is using tap0 to create a local network, 192.168.2.x. I have a client which connects from local IP 192.168.1.101 and gets VPN IP 192.168.2.3.

On the server, I ran:

iptables -A INPUT -i tap+ -j ACCEPT
iptables -A FORWARD -i tap+ -j ACCEPT

iptables -t nat -A POSTROUTING -s 192.168.2.0/24 -o eth0 -j MASQUERADE

On the client, the default remains to route via 192.168.1.1. In order to point it to 192.168.2.1 for HTTP, I ran

ip rule add fwmark 0x50 table 200
ip route add table 200 default via 192.168.2.1
iptables -t mangle -A OUTPUT -j MARK -p tcp --dport 80 --set-mark 80

Now, if I try accessing a website on the client (say, wget google.com), it just hangs there. On the server, I can see

$ sudo tcpdump -n -i tap0
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on tap0, link-type EN10MB (Ethernet), capture size 96 bytes
05:39:07.928358 IP 192.168.1.101.34941 > 74.125.67.100.80: S 4254520618:4254520618(0) win 5840 <mss 1334,sackOK,timestamp 558838 0,nop,wscale 5>
05:39:10.751921 IP 192.168.1.101.34941 > 74.125.67.100.80: S 4254520618:4254520618(0) win 5840 <mss 1334,sackOK,timestamp 559588 0,nop,wscale 5>

Where 74.125.67.100 is the IP it gets for google.com .

Why isn't the MASQUERADE working? More precisely, I see that the source showing up as 192.168.1.101 — shouldn't there be something to indicate that it came from the VPN?

Edit: Some routes [from the client]

$ ip route show table main
192.168.2.0/24 dev tap0  proto kernel  scope link  src 192.168.2.4
192.168.1.0/24 dev wlan0  proto kernel  scope link  src 192.168.1.101  metric 2
169.254.0.0/16 dev wlan0  scope link  metric 1000
default via 192.168.1.1 dev wlan0  proto static

$ ip route show table 200
default via 192.168.2.1 dev tap0

Best Answer

Can you post the output of ip route show table main and ip route show table 200? I suspect you are missing a couple routes in your '200' table. Your '200' route table should have pretty much the same routes as the 'main' table the only difference being the default route.


I see that you updated, and I believe my original suggestion was correct. Notice how your main table has the 'scope link' route for both your local network and the vpn link? Those routes have to be added to the '200' table as well.

Try running these commands in addition to the other commands you use.

ip route add 192.168.2.0/24 dev tap0  proto kernel  scope link  src 192.168.2.4 table 200
ip route add 192.168.1.0/24 dev wlan0  proto kernel  scope link  src 192.168.1.101  metric 2 table 200
ip route flush cache

If you want to script the creation of these routes you can use this. It will copy all the 'scope link' routes from the main route table into your other table.

#!/bin/bash
IFACE=wlan0
RT=200
/sbin/ip route list scope link table main proto kernel dev ${IFACE} \
| while read ROUTE ; do
    # and add that route to all the tables mentioned in the rrtables option
    # in the interfaces file
    /sbin/ip route add table ${RT} scope link proto kernel dev ${IFACE} ${ROUTE}
done

Another update. I just noticed I missed something rather obvious earlier.

Your MASQ statement seems to be working on eth0. From the route tables you posted, your output device isn't eth0. Instead of this.

iptables -t nat -A POSTROUTING -s 192.168.2.0/24 -o eth0 -j MASQUERADE

You probably should just use a statement like this.

iptables -t nat -A POSTROUTING -o tap0 -j MASQUERADE