netfilter: conntrack: udp: only extend timeout to stream mode after 2s
authorFlorian Westphal <fw@strlen.de>
Thu, 6 Dec 2018 10:50:49 +0000 (11:50 +0100)
committerPablo Neira Ayuso <pablo@netfilter.org>
Thu, 20 Dec 2018 23:48:38 +0000 (00:48 +0100)
Currently DNS resolvers that send both A and AAAA queries from same source port
can trigger stream mode prematurely, which results in non-early-evictable conntrack entry
for three minutes, even though DNS requests are done in a few milliseconds.

Add a two second grace period where we continue to use the ordinary
30-second default timeout.  Its enough for DNS request/response traffic,
even if two request/reply packets are involved.

ASSURED is still set, else conntrack (and thus a possible
NAT mapping ...) gets zapped too in case conntrack table runs full.

Signed-off-by: Florian Westphal <fw@strlen.de>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
include/net/netfilter/nf_conntrack.h
net/netfilter/nf_conntrack_proto_udp.c

index 7e012312cd6107a1c57e559a4a3c91664746380e..249d0a5b12b824b8da21491709afbcec40f9c67c 100644 (file)
 
 #include <net/netfilter/nf_conntrack_tuple.h>
 
+struct nf_ct_udp {
+       unsigned long   stream_ts;
+};
+
 /* per conntrack: protocol private data */
 union nf_conntrack_proto {
        /* insert conntrack proto private data here */
        struct nf_ct_dccp dccp;
        struct ip_ct_sctp sctp;
        struct ip_ct_tcp tcp;
+       struct nf_ct_udp udp;
        struct nf_ct_gre gre;
        unsigned int tmpl_padto;
 };
index c879d8d78cfde88a223b961bb203bf7bb48ef1b2..9f2e05adba69d999bebd0bf6fa47ac286b7f2c59 100644 (file)
@@ -100,11 +100,21 @@ static int udp_packet(struct nf_conn *ct,
        if (!timeouts)
                timeouts = udp_get_timeouts(nf_ct_net(ct));
 
+       if (!nf_ct_is_confirmed(ct))
+               ct->proto.udp.stream_ts = 2 * HZ + jiffies;
+
        /* If we've seen traffic both ways, this is some kind of UDP
-          stream.  Extend timeout. */
+        * stream. Set Assured.
+        */
        if (test_bit(IPS_SEEN_REPLY_BIT, &ct->status)) {
-               nf_ct_refresh_acct(ct, ctinfo, skb,
-                                  timeouts[UDP_CT_REPLIED]);
+               unsigned long extra = timeouts[UDP_CT_UNREPLIED];
+
+               /* Still active after two seconds? Extend timeout. */
+               if (time_after(jiffies, ct->proto.udp.stream_ts))
+                       extra = timeouts[UDP_CT_REPLIED];
+
+               nf_ct_refresh_acct(ct, ctinfo, skb, extra);
+
                /* Also, more likely to be important, and not a probe */
                if (!test_and_set_bit(IPS_ASSURED_BIT, &ct->status))
                        nf_conntrack_event_cache(IPCT_ASSURED, ct);