I am trying to apply SNAT to a PPTP client. The TCP/1723 packets are being SNATed properly but not the GRE ones. Can anyone spot what's wrong?

I have the following iptables configuration:

$ sudo iptables -t nat -L POSTROUTING -v -n
Chain POSTROUTING (policy ACCEPT 616 packets, 37030 bytes)
pkts bytes target     prot opt in     out     source               destination         
   0     0 SNAT       47   --  *      *       $internal_ip            to:$external_ip

When inspecting outgoing traffic on the egress interface using tcpdump, I see the following:

<timestamp> IP $internal_ip > $target_ip: GREv1, call 31607, seq 1, length 36: LCP, Conf-Request (0x01), id 1, length 22

... instead of the expected $external_ip > so clearly the SNAT translation isn't working (as is clear from the 0 pkts 0 bytes).

I have the following modules loaded (among others):


A few notes in case this is relevant:

  • The routing is happening upstream using a 3rd party firewall (so the outgoing packets are already on the correct egress interface).
  • The firewall is actually running in a VM (the above iptables listing is from its hypervisor), bridged to the egress interface.
  • The TCP/1723 packets are being SNATed by the firewall (but not the GRE ones); I'm effectively trying to use IPTables as a workaround to the firewall shortcoming. Presumably IPTables doesn't care about how the packets got there?
  • The egress interface/bridge has a static IP which is different from $external_ip (albeit on the same subnet)

This is a Ubuntu 14.04 server running 3.13.0-123-generic


First of all your iptables command missing -t nat part. But this should generate an error as no POSTROUTING table exists in filter table by default. Make sure you are adding this to a correct table. This is very similar to this question: NAT GRE (IP protocol 47) over Linux router

Next, make sure your are specified correct $internal_ip and that one matches the one you see on your tcpdump. Sometimes a simple typo slides out of sight and makes things look complicated.

Also check your iptables rules doesn't have any preceding rule which triggers before your SNAT rule. Netfilter will trigger only first match on that occasion. Your note that TCP/1723 are natted actually means that you have other rules there.

If this doesn't helps, make sure to check & post your detailed configuration with iptables -t nat -L -v -n and things like ip rule ls && ip route ls. With -v switch with iptables you can actually see how much packets was triggered with each of your rules.

You are running inside VM. Check your host node iptables rules also! Your rule might worked but host node firewall has overwritten packed source IP coming from your VM back to your internal ip. As seems like you are inspecting packets somewhere else, i.e. not directly on your VM.

| improve this answer | |
  • Hi there, you're right, my iptables rule output above was missing a -t nat because I posted iptables -S -t nat (which omits the table); so the rule is in the correct table. Thanks for iptables -v; this does show that 0 pkts/bytes match my rule (although the count on the POSTROUTING chain does tick up nicely). My gut feel is that it's something to do with GRE and/or the pre-routing that happens in the firewall and yes I did check over a dozen related other questions... I have revised my OP to clarify and include few more details... – sxc731 Jul 10 '17 at 10:02

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.