Message ID | CAMxdDZBwqRxZjywAfHUm-bbe-0veLPqPwAfFpw90cb0As80Dmg@mail.gmail.com |
---|---|
State | Deferred |
Delegated to: | Pablo Neira |
Headers | show |
On Fri, Jul 24, 2015 at 01:34:19PM +0300, Tarik Demirci wrote: > Hi Everyone, > > Problem: > I have a simple daemon listening for packets coming from nfqueue. When > a client issues parallel dns requests for IPv4 and IPv6 addresses > (since glibc 2.9 this is default behaviour), IPv6 request is dropped > on its way in gateway. Client, after 5 seconds timeout, sends these > requests sequentially and there is no problem in this case. > > Workaround: > I applied a kernel patch from an earlier mail ( > http://www.spinics.net/lists/netfilter-devel/msg15860.html ) to kernel > version 3.16. This patch solves the problem but I'm unaware of the > performance and security implications of this solution. I hope to find > a better solution that doesn't require patching kernel. I think we can resolve this from nf_reinject() which is slow path, with something that looks like this: { struct nf_conntrack_tuple_hash *h; enum ip_conntrack_info ctinfo; struct nf_conn *ct; ct = nf_ct_get(skb, &ctinfo); if (ct == NULL || nf_ct_is_untracked(ct) || nf_ct_is_confirmed(ct)) return; h = nf_conntrack_find_get(nf_ct_net(ct), nf_ct_zone(ct), &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple); if (h) { nf_conntrack_put(ct); ct = nf_ct_tuplehash_to_ctrack(h); skb->nfct = &ct->ct_general; skb->nfctinfo = ctinfo; } } But to avoid dependencies with ct we have to add a RCU hook pointer to function, so this code it only invoked if conntrack is loaded. I'll try to find some spare time to send a patch, otherwise if there is anyone else willing to work on this, just drop me a line privately. Thanks. -- To unsubscribe from this list: send the line "unsubscribe netfilter-devel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
diff --git a/net/ipv4/netfilter/iptable_nat.c b/net/ipv4/netfilter/iptable_nat.c index f1787c0..b9f282a 100644 --- a/net/ipv4/netfilter/iptable_nat.c +++ b/net/ipv4/netfilter/iptable_nat.c @@ -18,6 +18,11 @@ #include <net/netfilter/nf_nat_core.h> #include <net/netfilter/nf_nat_l3proto.h> +#include <net/netfilter/nf_conntrack.h> +#include <net/netfilter/nf_conntrack_core.h> +#include <net/netfilter/nf_conntrack_extend.h> +#include <net/netfilter/nf_conntrack_tuple.h> +#include <net/netfilter/nf_conntrack_zones.h> static const struct xt_table nf_nat_ipv4_table = { .name = "nat", .valid_hooks = (1 << NF_INET_PRE_ROUTING) | @@ -107,6 +112,20 @@ nf_nat_ipv4_fn(const struct nf_hook_ops *ops, } /* Fall thru... (Only ICMPs can be IP_CT_IS_REPLY) */ case IP_CT_NEW: + /* Nasty asynchronous DNS hack: Avoid NAT and conntrack_confirm race */ + if (!nf_ct_is_confirmed(ct) && CTINFO2DIR(ctinfo) == IP_CT_DIR_ORIGINAL && + ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum == IPPROTO_UDP) { + struct nf_conntrack_tuple_hash *h = nf_conntrack_find_get( + nf_ct_net(ct), + NF_CT_DEFAULT_ZONE, + &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple); + if (h) { + ct = nf_ct_tuplehash_to_ctrack(h); + nf_conntrack_put(skb->nfct); + skb->nfct = &ct->ct_general; + }