netfilter: nf_nat: Handle routing changes in MASQUERADE target
authorJozsef Kadlecsik <kadlec@blackhole.kfki.hu>
Fri, 30 Nov 2012 12:37:26 +0000 (12:37 +0000)
committerPablo Neira Ayuso <pablo@netfilter.org>
Mon, 3 Dec 2012 14:14:20 +0000 (15:14 +0100)
When the route changes (backup default route, VPNs) which affect a
masqueraded target, the packets were sent out with the outdated source
address. The patch addresses the issue by comparing the outgoing interface
directly with the masqueraded interface in the nat table.

Events are inefficient in this case, because it'd require adding route
events to the network core and then scanning the whole conntrack table
and re-checking the route for all entry.

Signed-off-by: Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
include/net/netfilter/nf_nat.h
net/ipv4/netfilter/iptable_nat.c
net/ipv6/netfilter/ip6table_nat.c

index bd8eea720f2ed0c3e0b61de6b03cb36035ff61cf..ad14a799fd2e50b153e47e80a9cd6fbc4235be7f 100644 (file)
@@ -68,4 +68,19 @@ static inline struct nf_conn_nat *nfct_nat(const struct nf_conn *ct)
 #endif
 }
 
+static inline bool nf_nat_oif_changed(unsigned int hooknum,
+                                     enum ip_conntrack_info ctinfo,
+                                     struct nf_conn_nat *nat,
+                                     const struct net_device *out)
+{
+#if IS_ENABLED(CONFIG_IP_NF_TARGET_MASQUERADE) || \
+    IS_ENABLED(CONFIG_IP6_NF_TARGET_MASQUERADE)
+       return nat->masq_index && hooknum == NF_INET_POST_ROUTING &&
+              CTINFO2DIR(ctinfo) == IP_CT_DIR_ORIGINAL &&
+              nat->masq_index != out->ifindex;
+#else
+       return false;
+#endif
+}
+
 #endif
index ac635a7b441603148662433cb4f007711b018b1a..da2c8a368f68d9c6b72c605593aa5b83e0622344 100644 (file)
@@ -134,6 +134,10 @@ nf_nat_ipv4_fn(unsigned int hooknum,
                /* ESTABLISHED */
                NF_CT_ASSERT(ctinfo == IP_CT_ESTABLISHED ||
                             ctinfo == IP_CT_ESTABLISHED_REPLY);
+               if (nf_nat_oif_changed(hooknum, ctinfo, nat, out)) {
+                       nf_ct_kill_acct(ct, ctinfo, skb);
+                       return NF_DROP;
+               }
        }
 
        return nf_nat_packet(ct, ctinfo, hooknum, skb);
index fa84cf8ec6bcd674fe42a3d04e588d85310a16de..6c8ae24b85eb15f525e2e43a1b0e7f93068e8d85 100644 (file)
@@ -137,6 +137,10 @@ nf_nat_ipv6_fn(unsigned int hooknum,
                /* ESTABLISHED */
                NF_CT_ASSERT(ctinfo == IP_CT_ESTABLISHED ||
                             ctinfo == IP_CT_ESTABLISHED_REPLY);
+               if (nf_nat_oif_changed(hooknum, ctinfo, nat, out)) {
+                       nf_ct_kill_acct(ct, ctinfo, skb);
+                       return NF_DROP;
+               }
        }
 
        return nf_nat_packet(ct, ctinfo, hooknum, skb);