OpenVPN CentOS – Fixing Client Connection Issues to Internet

vpn

I have set up an OpenVPN server on CentOS 6.7

I copied the configuration from a known working server so I was pretty sure the server was configured correctly.

The problem I'm having is that a VPN client will connect fine, but can't reach anything on the internet.

  • The clients are using certificates for authentication.
  • I'm pushing Google's public DNS server (8.8.8.8)

I've enabled packet forwarding in sysctl.conf


net.ipv4.conf.all.forwarding = 1
net.ipv4.conf.all.mc_forwarding = 0
net.ipv4.conf.default.forwarding = 1
net.ipv4.conf.default.mc_forwarding = 0
net.ipv4.conf.lo.forwarding = 1
net.ipv4.conf.lo.mc_forwarding = 0
net.ipv4.conf.eth0.forwarding = 1
net.ipv4.conf.eth0.mc_forwarding = 0
net.ipv4.conf.tun0.forwarding = 1
net.ipv4.conf.tun0.mc_forwarding = 0
net.ipv4.ip_forward = 1
net.ipv4.ip_forward_use_pmtu = 0

I've added these iptables rules:


iptables -t nat -A POSTROUTING -o tun0 -j MASQUERADE -m comment --comment "Masquerade OpenVPN traffic"

iptables -A INPUT -i tun0 -j ACCEPT -m comment --comment "Allow all incoming OpenVPN"

iptables -A FORWARD -i tun0 -j ACCEPT

tun0 is configured as follows:


$ ip address show tun0
6: tun0: mtu 1500 qdisc pfifo_fast state UNKNOWN qlen 100
link/[65534]
inet 172.16.1.1 peer 172.16.1.2/32 scope global tun0

In my openvpn.log I can see the client connects ok:


Thu Aug 20 06:54:59 2015 us=94453 31.108.32.42:55065 [David] Peer Connection Initiated with [AF_INET]31.108.32.42:55065
Thu Aug 20 06:54:59 2015 us=94789 MULTI: new connection by client 'David' will cause previous active sessions by this client to be dropped. Remember to use the --duplicate-cn option if you want multiple clients using the same certificate or username to concurrently connect.
Thu Aug 20 06:54:59 2015 us=94913 MULTI_sva: pool returned IPv4=172.16.1.6, IPv6=(Not enabled)
Thu Aug 20 06:54:59 2015 us=94991 MULTI: Learn: 172.16.1.6 -> David/31.108.32.42:55065
Thu Aug 20 06:54:59 2015 us=95013 MULTI: primary virtual IP for David/31.108.32.42:55065: 172.16.1.6
Thu Aug 20 06:55:00 2015 us=350681 David/31.108.32.42:55065 UDPv4 READ [56] from [AF_INET]31.108.32.42:55065: P_CONTROL_V1 kid=0 [ ] pid=6 DATA len=42
Thu Aug 20 06:55:00 2015 us=351165 David/31.108.32.42:55065 PUSH: Received control message: 'PUSH_REQUEST'
Thu Aug 20 06:55:00 2015 us=351212 David/31.108.32.42:55065 send_push_reply(): safe_cap=940
Thu Aug 20 06:55:00 2015 us=351282 David/31.108.32.42:55065 SENT CONTROL [David]: 'PUSH_REPLY,redirect-gateway def1 bypass-dhcp,dhcp-option DNS 8.8.8.8,route 172.16.1.1,topology net30,ping 10,ping-restart 120,ifconfig 172.16.1.6 172.16.1.5' (status=1)

If I use tshark to watch tun0 I can see DNS queries being performed, but there doesn't appear to be any response:


1.935018671 172.16.1.6 -> 8.8.8.8 DNS 74 Standard query 0xe4a3 A external-lhr3-1.xx.fbcdn.net
1.937067717 172.16.1.6 -> 8.8.8.8 DNS 68 Standard query 0xdbc8 A edge-chat.facebook.com
2.324716221 172.16.1.6 -> 8.8.8.8 DNS 65 Standard query 0xc98b A clients4.google.com
2.331865976 172.16.1.6 -> 8.8.8.8 DNS 65 Standard query 0x5acb AAAA clients4.google.com
2.335206663 172.16.1.6 -> 8.8.8.8 DNS 65 Standard query 0x6ba8 A clients4.google.com
2.610867667 172.16.1.6 -> 8.8.8.8 DNS 62 Standard query 0xfb5e A www.google.co.uk
2.612555200 172.16.1.6 -> 8.8.8.8 DNS 62 Standard query 0xcaf7 A www.google.co.uk
2.628983231 172.16.1.6 -> 8.8.8.8 DNS 75 Standard query 0x803d A fbcdn-photos-a-a.akamaihd.net

I can see packets on eth0 too, which has a public internet IP.


$ tshark -i eth0 -f "host 172.16.1.6"
Running as user "root" and group "root". This could be dangerous.
Capturing on eth0
0.000000000 172.16.1.6 -> 8.8.8.8 DNS 79 Standard query 0x7afb A clients4.google.com
0.002199239 172.16.1.6 -> 8.8.8.8 DNS 74 Standard query 0x4f3c A m.facebook.com
0.003786487 172.16.1.6 -> 8.8.8.8 DNS 74 Standard query 0x7033 A m.facebook.com
0.005484385 172.16.1.6 -> 8.8.8.8 DNS 70 Standard query 0x86a1 A google.com
0.008791391 172.16.1.6 -> 8.8.8.8 DNS 74 Standard query 0x031d AAAA api.amazon.com

Again – nothing the other way

The client can ping the vpn server (172.16.1.1) but nothing outside of it.

I'm not sure what else I can check.

Best Answer

Just did a quick test to see whether tcpdump (I̶ ̶a̶s̶s̶u̶m̶e̶ ̶T̶S̶H̶A̶R̶K̶ ̶b̶e̶h̶a̶v̶e̶s̶ ̶t̶h̶e̶ ̶s̶a̶m̶e̶) shows the NAT'd or original source IP address on the egress interface, when NAT is configured using iptables, even without OpenVPN configured.

Setup : Ubuntu eth1 <-> eth1 CentOS eth0 <-> "Internet"

Ubuntu config :

sudo ip addr add 172.16.1.2/30 dev eth1
sudo ip link set dev eth1 up
sudo ip route add default via 172.16.1.1

CentOS config :

dhclient -v eth0
ip addr add 172.16.1.1/30 dev eth1
ip link set dev eth1 up
echo 1 > /proc/sys/net/ipv4/ip_forward
iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
iptables -F FORWARD
iptables -A FORWARD -i eth1 -o eth0 -j ACCEPT
iptables -A FORWARD -i eth0 -o eth1 -m state --state RELATED,ESTABLISHED -j ACCEPT

(Just ask if you need any of the above config explained.)

Now we ping from Ubuntu (172.16.1.2) to 8.8.8.8 (Google DNS) ...

Internal :

[root@localhost ~]# tcpdump -ni eth1 'icmp'
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on eth1, link-type EN10MB (Ethernet), capture size 65535 bytes
11:02:44.251212 IP 172.16.1.2 > 8.8.8.8: ICMP echo request, id 2996, seq 1, length 64
11:02:44.269621 IP 8.8.8.8 > 172.16.1.2: ICMP echo reply, id 2996, seq 1, length 64
11:02:45.252338 IP 172.16.1.2 > 8.8.8.8: ICMP echo request, id 2996, seq 2, length 64
11:02:45.268138 IP 8.8.8.8 > 172.16.1.2: ICMP echo reply, id 2996, seq 2, length 64
11:02:46.253904 IP 172.16.1.2 > 8.8.8.8: ICMP echo request, id 2996, seq 3, length 64
11:02:46.270498 IP 8.8.8.8 > 172.16.1.2: ICMP echo reply, id 2996, seq 3, length 64

External :

[root@localhost ~]# tcpdump -ni eth0 'icmp'
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on eth0, link-type EN10MB (Ethernet), capture size 65535 bytes
11:02:44.251252 IP 10.0.2.15 > 8.8.8.8: ICMP echo request, id 2996, seq 1, length 64
11:02:44.269581 IP 8.8.8.8 > 10.0.2.15: ICMP echo reply, id 2996, seq 1, length 64
11:02:45.252363 IP 10.0.2.15 > 8.8.8.8: ICMP echo request, id 2996, seq 2, length 64
11:02:45.268126 IP 8.8.8.8 > 10.0.2.15: ICMP echo reply, id 2996, seq 2, length 64
11:02:46.253942 IP 10.0.2.15 > 8.8.8.8: ICMP echo request, id 2996, seq 3, length 64
11:02:46.270469 IP 8.8.8.8 > 10.0.2.15: ICMP echo reply, id 2996, seq 3, length 64

Success !
More importantly, we see that tcpdump shows the NAT'd address !

In your output, the captured IP is "172.16.1.6" - a clear indication of why no traffic is being returned.
Your ISP (or some Internet router) is dropping the traffic as soon as it sees a private address.

As another comment mentioned, check your NAT configuration - or try to get NAT working as I did above before you even touch OpenVPN.

Cheers !

EDIT : Just tested with tshark and it does behave the same as tcpdump, in that it shows the source IP address post-NAT :

[root@localhost ~]# tshark -ni eth0 'icmp'
Running as user "root" and group "root". This could be dangerous.
Capturing on eth0
0.000000000 10.0.2.15 -> 8.8.8.8 ICMP 98 Echo (ping) request id=0x0bbb, seq=1/256, ttl=63
0.015220791 8.8.8.8 -> 10.0.2.15 ICMP 98 Echo (ping) reply id=0x0bbb, seq=1/256, ttl=54

Looking at your iptables config more closely ...

iptables -t nat -A POSTROUTING -o tun0 -j MASQUERADE
iptables -A INPUT -i tun0 -j ACCEPT
iptables -A FORWARD -i tun0 -j ACCEPT

The first line specifies the "external networking device" on which to perform NAT as tun0.
The second line isn't really relevant to forwarding, since the INPUT chain concerns traffic destined for the local server itself, not traffic passing through, iinm.
The third line specifies that tun0 is the "internal / inside" interface.

Seems to me that
1) your NAT'd interface should be eth0, not the tunnel interface, and
2) that you need to specify the outside interface (eth0) with an option like "-o eth0 -j ACCEPT" on the same line you specify your inside interface (tun0), and
3) don't forget a separate iptables statement for return traffic, as in my example above !

Related Topic