From patchwork Thu Nov 29 21:12:54 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: [RFC] Handle routing changes for the MASQUERADE target Date: Thu, 29 Nov 2012 11:12:54 -0000 From: Jozsef Kadlecsik X-Patchwork-Id: 202827 Message-Id: To: netfilter-devel@vger.kernel.org Hi, This is the second variant of the patch which addresses the route changes affecting already masqueraded connections. When the route changes (backup default route, VPNs), the packets are sent out with wrong source address. The patch addresses the issue by comparing the outgoing interface directly with the masquerade interface in the nat table. It *is* MASQUERADE specific, so probably the inserted code could be enclosed in a proper ifdef. Events are inefficient, because it'd require scanning the whole conntrack table at any route change and re-checking the route for all entry, which is simply way too expensive. Comments are highly welcomed. Best regards, Jozsef --- net/ipv4/netfilter/iptable_nat.c | 19 +++++++++++++++++++ net/ipv6/netfilter/ip6table_nat.c | 19 +++++++++++++++++++ 2 files changed, 38 insertions(+), 0 deletions(-) diff --git a/net/ipv4/netfilter/iptable_nat.c b/net/ipv4/netfilter/iptable_nat.c index ac635a7..128885d 100644 --- a/net/ipv4/netfilter/iptable_nat.c +++ b/net/ipv4/netfilter/iptable_nat.c @@ -17,6 +17,7 @@ #include #include #include +#include static const struct xt_table nf_nat_ipv4_table = { .name = "nat", @@ -134,6 +135,24 @@ nf_nat_ipv4_fn(unsigned int hooknum, /* ESTABLISHED */ NF_CT_ASSERT(ctinfo == IP_CT_ESTABLISHED || ctinfo == IP_CT_ESTABLISHED_REPLY); + if (hooknum == NF_INET_POST_ROUTING && + CTINFO2DIR(ctinfo) == IP_CT_DIR_ORIGINAL && + nat->masq_index && nat->masq_index != out->ifindex) { + /* Outgoing interface changed, kill ct. */ + if (del_timer(&ct->timeout)) { + if (nf_conntrack_event(IPCT_DESTROY, ct) < 0) { + nf_ct_delete_from_lists(ct); + nf_ct_insert_dying_list(ct); + nf_ct_put(ct); + return NF_DROP; + } + set_bit(IPS_DYING_BIT, &ct->status); + nf_ct_delete_from_lists(ct); + nf_ct_put(ct); + } + nf_ct_put(ct); + return NF_DROP; + } } return nf_nat_packet(ct, ctinfo, hooknum, skb); diff --git a/net/ipv6/netfilter/ip6table_nat.c b/net/ipv6/netfilter/ip6table_nat.c index fa84cf8..d06d7de 100644 --- a/net/ipv6/netfilter/ip6table_nat.c +++ b/net/ipv6/netfilter/ip6table_nat.c @@ -19,6 +19,7 @@ #include #include #include +#include static const struct xt_table nf_nat_ipv6_table = { .name = "nat", @@ -137,6 +138,24 @@ nf_nat_ipv6_fn(unsigned int hooknum, /* ESTABLISHED */ NF_CT_ASSERT(ctinfo == IP_CT_ESTABLISHED || ctinfo == IP_CT_ESTABLISHED_REPLY); + if (hooknum == NF_INET_POST_ROUTING && + CTINFO2DIR(ctinfo) == IP_CT_DIR_ORIGINAL && + nat->masq_index && nat->masq_index != out->ifindex) { + /* Outgoing interface changed, kill ct. */ + if (del_timer(&ct->timeout)) { + if (nf_conntrack_event(IPCT_DESTROY, ct) < 0) { + nf_ct_delete_from_lists(ct); + nf_ct_insert_dying_list(ct); + nf_ct_put(ct); + return NF_DROP; + } + set_bit(IPS_DYING_BIT, &ct->status); + nf_ct_delete_from_lists(ct); + nf_ct_put(ct); + } + nf_ct_put(ct); + return NF_DROP; + } } return nf_nat_packet(ct, ctinfo, hooknum, skb);