For a while now (introduced in version 1.3 I believe), iptables
' conntrack module can track two virtual states, SNAT and DNAT:
SNAT A virtual state, matching if the original source address differs from the reply destination. DNAT A virtual state, matching if the original destination differs from the reply source.
On my router/firewall host, I have some rules for SNAT like this:
# SNAT
iptables -t filter -A FORWARD -i $FROM_IFACE -o $TO_IFACE -s $FROM_IP -d $TO_IP -m conntrack --ctstate NEW,ESTABLISHED,RELATED -j ACCEPT
iptables -t filter -A FORWARD -i $TO_IFACE -o $FROM_IFACE -s $TO_IP -d $FROM_IP -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
iptables -t nat -A POSTROUTING -o $TO_IFACE -s $FROM_IP -d $TO_IP -j SNAT --to-source $SNAT_IP
# DNAT
iptables -t nat -A PREROUTING -i $FROM_IFACE -d $FROM_IP -p $PROTO --dport $PORT -j DNAT --to-destination $TO_IP
iptables -t filter -A FORWARD -i $FROM_IFACE -o $TO_IFACE -d $TO_IP -p $PROTO --dport $PORT -j ACCEPT
iptables -t filter -A FORWARD -i $TO_IFACE -o $FROM_IFACE -s $TO_IP -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
After a fair bit of googling, I couldn't find any example of iptables
rules using those "new" SNAT
or DNAT
states, but I tried anyway to replace ESTABLISHED,RELATED
by SNAT
or DNAT
, like this:
# SNAT
iptables -t filter -A FORWARD -i $FROM_IFACE -o $TO_IFACE -s $FROM_IP -d $TO_IP -m conntrack --ctstate NEW,SNAT -j ACCEPT
iptables -t filter -A FORWARD -i $TO_IFACE -o $FROM_IFACE -s $TO_IP -d $FROM_IP -m conntrack --ctstate SNAT -j ACCEPT
iptables -t nat -A POSTROUTING -o $TO_IFACE -s $FROM_IP -d $TO_IP -j SNAT --to-source $SNAT_IP
# DNAT
iptables -t nat -A PREROUTING -i $FROM_IFACE -d $FROM_IP -p $PROTO --dport $PORT -j DNAT --to-destination $TO_IP
iptables -t filter -A FORWARD -i $FROM_IFACE -o $TO_IFACE -d $TO_IP -p $PROTO --dport $PORT -j ACCEPT
iptables -t filter -A FORWARD -i $TO_IFACE -o $FROM_IFACE -s $TO_IP -m conntrack --ctstate DNAT -j ACCEPT
It seemed to work, and this method has at least one benefit I could notice: my firewall used to drop RST packets going from my internal hosts to the Internet (since they are in .INVALID
state), but with this new method, they were allowed to pass
Unfortunately, although convenient, I'm not sure if this method is really suitable, because my theoretical knowledge about networks is not sufficient to understand if it's too permissive (i.e. allow some unwanted packets from outside my LAN to reach inside).
I think my question could be worded like this: can a packet have the SNAT
or DNAT
state while not also have the ESTABLISHED
or RELATED
state (except, obviously, the first one which has the NEW
state) ?
Note: I tried to log such packets but to my knowledge it's impossible, since iptables
accepts only one --ctstate
option, and !
can't be used within it (in other words, I can't say, or at least couldn't find a way to say, "log packets which have SNAT
state but not ESTABLISHED
or RELATED
state"). If there is an alternate method to log them I didn't think of, this would also be very welcomed.
EDIT 1: after some trial and error, I realized I was wrong (hence the stroked text): some packets are still in state INVALID
and thus finally dropped.
EDIT 2: if using SNAT
/DNAT
in place of ESTABLISH,RELATED
is not safe, please provide some concrete examples of cases where packets could be in those former states without being in the latter ones.