0

So we are working with iptables at class and I've been testing some rules in the NAT table. As far as I know SNAT changes the IP source of a packet to which the rule dictates but what I tested does not seem to work every time.

I added this rule: iptables -t nat -A POSTROUTING -j SNAT --to 1.2.3.4

And when I ping other machines in the network they receive a packet from 1.2.3.4 which is correct since I added the rule above. But when those machines ping (knowing that the firewall machine IP is not 1.2.3.4) its real IP it does not translate to the new IP and they answer to its real IP and not to 1.2.3.4.

I checked iptables diagram flow in case the rule wasn't being executed but what I saw seems to be ok. I am thinking that maybe it could be because it is an incoming packet or something like that, but shouldn't POSTROUTING be executed for every packet and not just for those the machine outputs?

How can I make it to think it was 1.2.3.4 the machine who answered? Is it possible by translating the source?

0

Any rule in the nat table is executed for every first packet in a connection.

When a new packet arrives, system searches a connection tracking table if it belongs to a known connection. If that's the case, it is assigned to that connection and translation is applied which was recorded for that connection in the table. The table stores enough information to identify forward and reply packets of a connection and translate them. A connection is a bidirectional thing, two flows. The nat table isn't traversed for packets that were identified by the connection tracker (the conntrack).

However, if it wasn't found, a new record in the conntrack table is created, and then packet is processed according to the nat table. If a translation is requested, packet is translated and information is recorded into the conntrack table for subsequent forward and reply packets to be translated the same way.

A connection is deleted if timeout occurs, or if TCP connection is FINalized or RESet. What is considered a "connection" for connectionless protocols is specific to each case. For example, for UDP only addresses, ports and timeouts are considered.

You can see current contents of this table via the pseudo-file /proc/net/nf_conntrack. Note you can see what exactly is translated to what. Also you may use helper utilites like conntrack-tools or iptstate.


Please, consider this diagram.

All your packets are being translated. They are translated, because the rule instructs doing so. Outgoing packets get translated as you expected, their source address gets changed to 1.2.3.4 and then they being sent out to original destination.

Incoming packets get their source address translated to 1.2.3.4, then they're routed to original destination. You have set up a source translation prior to routing (SNAT rule in the PREROUTING chain), remember? That rule applies to all packets.

The destination in this case is localhost, I believe. After a translation, the system sees a packet from 1.2.3.4 incoming to its own address.

If you install, say, a HTTP server there and read its access log, you'll find that all requests were made from 1.2.3.4. That's because it sees only packets after source address was translated. The real source is hidden by the source nat.

Then, if it bothers to reply, it forms a packet from its own address to 1.2.3.4. Connection tracker (see "output path" in the diagram) identifies that as reply to a known connection and translates it back according to the table entry it found (notice, however, now it changes a destination address from 1.2.3.4 to what it found in the table, because it's a reply). Then reply packet is rerouted and sent out to original sender.

Source address of a reply packet must not be translated — there was no instruction to do so.


To avoid such confusing effects, you always add a outgoing interface match to SNAT rules. For instance, iptables -t nat -A POSTROUTING -o eth0 -j SNAT --to-source 1.2.3.4.

You can achieve interesting effects if you translate incoming packets, for example, you can make packets from remote host to appear they were sent from the LAN, but such rule will have quite tight match, at least a source IP which you want to appear local and a address in the LAN to use as its alias. That address will likely be different than the address you use in the general SNAT rule.

4
  • So what I understood is that because it is a reply it gets rerouted to the original address, and you said there was no instruction to translate the source address of a reply packet then how can I do that? – Deketh Jan 28 at 12:56
  • What exactly do you want? How should it look? You ping some address, and replies to be sent from another? – Nikita Kipriyanov Jan 28 at 17:58
  • @NikitaKipriyanov You say: "(SNAT rule in the PREROUTING chain), remember?". But what OP said is POSTROUTING, not PREROUTING. According to the manual, SNAT only works for the POSTROUTING and INPUT chains. – conradkleinespel Apr 21 at 22:06
  • Notice the autor updated their question after I last edited my answer. So when I actually answered it seems there could be something slightly different, and nobody remember what. But wow. Thank you for pointing me at the mistake. Now I need to re-read everything, rebuild the case in my head and fix, this will take some time. – Nikita Kipriyanov Apr 22 at 5:54

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.