I'm trying to use iptables to:

  1. Mark packets going to a destination IP
  2. Detect that mark to change the destination IP
  3. Detect that mark to change the source IP

These are the commands I'm trying to use to achieve that:

sudo iptables -t mangle -A PREROUTING --destination -j MARK --set-mark 11
sudo iptables -t nat -A PREROUTING -m mark --mark 11 -j DNAT --to-destination ${DESTINATION_IP}
sudo iptables -t nat -A POSTROUTING -m mark --mark 11 -j SNAT --to-source ${SOURCE_IP}

It looks like the first MARK command is not picking up any packets to mark them:

sudo iptables -vL -t mangle
Chain PREROUTING (policy ACCEPT 11892 packets, 1184K bytes)
 pkts bytes target     prot opt in     out     source               destination         
    0     0 MARK       all  --  any    any     anywhere               MARK set 0xb

After that the later rules do not see any marked packets to modify.

Am I right in thinking that pkts being 0 for that rule means it hasn't matched any packets?

How should I be marking packets to later identify and modify?

  • 2
    If you test this rule set from the same host, then packets are local-originated, and you should use mangle/OUTPUT and nat/OUTPUT instead mangle/PREROUTING and nat/PREROUTING. Jul 8 '19 at 20:12
  • @AntonDanilov changing PREROUTING to OUTPUT seems to be the correct change, thank you. Do you want to post it as an answer?
    – MHG
    Jul 8 '19 at 20:29

Local-originated packets don't pass through PREROUTING chain, but through OUTPUT. So, if you try to test your rules from the same host, you should add the MARK rule into mangle/OUTPUT chain and the DNAT rule into nat/OUTPUT chain.

In result your rules will look like:

sudo iptables -t mangle -A OUTPUT --destination -j MARK --set-mark 11
sudo iptables -t nat -A OUTPUT -m mark --mark 11 -j DNAT --to-destination ${DESTINATION_IP}
sudo iptables -t nat -A POSTROUTING -m mark --mark 11 -j SNAT --to-source ${SOURCE_IP}

Also, there is a way to avoid marking and refer to the original (before translation) addresses and port numbers.

sudo iptables -t nat -A OUTPUT --dst -j DNAT --to ${DESTINATION_IP}
sudo iptables -t nat -A POSTROUTING -m conntrack --ctstate DNAT --ctorigdst -j SNAT --to ${SOURCE_IP}

To get the options list of an iptables match or an iptables target you can use brief built-in help. For example:

iptables -m connmark --help
iptables -j DNAT --help

When you troubleshoot nat rules, you should know only first packet of new connection passes the nat table.

Other tools to troubleshoot issues are the tcpdump and the conntrack.

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.