Reverse-path filter part 2: OpenVPN and traceroute

After my recent adventure with reverse-path filtering, I didn’t expect to see it again so soon. And then I took another look at a long-standing annoyance in our OpenVPN network.

I set up OpenVPN so our offices and laptops could securely access internal resources. This lets me print documents directly to another office, for instance. Or access web-based applications that we don’t make available to the public. Or remotely SSH into a PC and fix a problem. A month after setting it up, I realised that:

  1. I could traceroute from a host on the LAN to a host on another office LAN, via the VPN
  2. I could traceroute from a host on the LAN to a host in the Internet, where the traffic never enters the VPN
  3. I could not traceroute from a host on the LAN, through the VPN to the central VPN server, and from there to a server on the public Internet

Why would I want to do #3? Because I sometimes deal with ISPs and autocratic governments that filter Internet traffic. In those circumstances, I back-haul all my traffic to the VPN server and break out there, bypassing any annoying proxies.

How I do it is a story for another day. Suffice it to say that much complicated NAT trickery and careful routing is involved.

So, #1 (through the VPN to the VPN server, and again to another office) is good:

tyler@baal:~$ sudo traceroute -n -I

And #2 (avoiding the VPN entirely) is good:

tyler@baal:~$ sudo traceroute -n -I

But #3 (through the VPN to the VPN server) gives no joy. If I change my router’s VPN setup to route all traffic through the VPN (or create a specific route for Google), I see:

tyler@baal:~$ sudo traceroute -n -I

So I can ping it, and the final step in the trace shows the answer, but no routers between the VPN server and Google appear.

Or does it? A little sniffing at my router showed something interesting:

root@router:~# tshark -i tun0 -f 'icmp[icmptype] = icmp-timxceed'

So the traffic is coming in the VPN tunnel. But what is going out?

root@router:~# tshark -i eth1 -f 'icmp[icmptype] = icmp-timxceed'

I could see the initial “TTL expired” messages from the first few hops, but none after that. Something is stopping them between tun0 (the OpenVPN tun interface) and eth1 (the inside LAN interface).

Can you see where I’m going with this? It’s our old friend, the reverse-path filter. Disable it with sysctl or echo.

echo 0 > /proc/sys/net/ipv4/conf/all/rp_filter

For some reason, the kernel doesn’t mind most traffic moving between eth1 and tun0, but something about the ICMP “TTL expired” messages triggered rp_filter. Disable it and traceroute works again.

Aside: I always use mtr in place of regular traceroute. What traceroute does in O(n), mtr does in O(1). Actually O(n/5), but explaining that needs it own post. mtr is fast. You should use mtr. Your distro has it.

Tags: , ,

  1. Mark Denovich’s avatar

    Thanks for the tip on mtr.

    sudo port install mtr


    Installed on the Mac.



Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.