netfilter: ctnetlink: add timeout and protoinfo to destroy events
authorFlorian Westphal <fw@strlen.de>
Thu, 10 Dec 2020 13:43:23 +0000 (14:43 +0100)
committerPablo Neira Ayuso <pablo@netfilter.org>
Sat, 12 Dec 2020 10:44:42 +0000 (11:44 +0100)
DESTROY events do not include the remaining timeout.

Add the timeout if the entry was removed explicitly. This can happen
when a conntrack gets deleted prematurely, e.g. due to a tcp reset,
module removal, netdev notifier (nat/masquerade device went down),
ctnetlink and so on.

Add the protocol state too for the destroy message to check for abnormal
state on connection termination.

Joint work with Pablo.

Signed-off-by: Florian Westphal <fw@strlen.de>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
include/net/netfilter/nf_conntrack_l4proto.h
net/netfilter/nf_conntrack_netlink.c
net/netfilter/nf_conntrack_proto_dccp.c
net/netfilter/nf_conntrack_proto_sctp.c
net/netfilter/nf_conntrack_proto_tcp.c

index 9be7320..96f9cf8 100644 (file)
@@ -32,7 +32,7 @@ struct nf_conntrack_l4proto {
 
        /* convert protoinfo to nfnetink attributes */
        int (*to_nlattr)(struct sk_buff *skb, struct nlattr *nla,
-                        struct nf_conn *ct);
+                        struct nf_conn *ct, bool destroy);
 
        /* convert nfnetlink attributes to protoinfo */
        int (*from_nlattr)(struct nlattr *tb[], struct nf_conn *ct);
index 3d0fd33..84caf33 100644 (file)
@@ -167,10 +167,14 @@ nla_put_failure:
        return -1;
 }
 
-static int ctnetlink_dump_timeout(struct sk_buff *skb, const struct nf_conn *ct)
+static int ctnetlink_dump_timeout(struct sk_buff *skb, const struct nf_conn *ct,
+                                 bool skip_zero)
 {
        long timeout = nf_ct_expires(ct) / HZ;
 
+       if (skip_zero && timeout == 0)
+               return 0;
+
        if (nla_put_be32(skb, CTA_TIMEOUT, htonl(timeout)))
                goto nla_put_failure;
        return 0;
@@ -179,7 +183,8 @@ nla_put_failure:
        return -1;
 }
 
-static int ctnetlink_dump_protoinfo(struct sk_buff *skb, struct nf_conn *ct)
+static int ctnetlink_dump_protoinfo(struct sk_buff *skb, struct nf_conn *ct,
+                                   bool destroy)
 {
        const struct nf_conntrack_l4proto *l4proto;
        struct nlattr *nest_proto;
@@ -193,7 +198,7 @@ static int ctnetlink_dump_protoinfo(struct sk_buff *skb, struct nf_conn *ct)
        if (!nest_proto)
                goto nla_put_failure;
 
-       ret = l4proto->to_nlattr(skb, nest_proto, ct);
+       ret = l4proto->to_nlattr(skb, nest_proto, ct, destroy);
 
        nla_nest_end(skb, nest_proto);
 
@@ -537,8 +542,8 @@ static int ctnetlink_dump_info(struct sk_buff *skb, struct nf_conn *ct)
                return -1;
 
        if (!test_bit(IPS_OFFLOAD_BIT, &ct->status) &&
-           (ctnetlink_dump_timeout(skb, ct) < 0 ||
-            ctnetlink_dump_protoinfo(skb, ct) < 0))
+           (ctnetlink_dump_timeout(skb, ct, false) < 0 ||
+            ctnetlink_dump_protoinfo(skb, ct, false) < 0))
                return -1;
 
        return 0;
@@ -780,15 +785,19 @@ ctnetlink_conntrack_event(unsigned int events, struct nf_ct_event *item)
                goto nla_put_failure;
 
        if (events & (1 << IPCT_DESTROY)) {
+               if (ctnetlink_dump_timeout(skb, ct, true) < 0)
+                       goto nla_put_failure;
+
                if (ctnetlink_dump_acct(skb, ct, type) < 0 ||
-                   ctnetlink_dump_timestamp(skb, ct) < 0)
+                   ctnetlink_dump_timestamp(skb, ct) < 0 ||
+                   ctnetlink_dump_protoinfo(skb, ct, true) < 0)
                        goto nla_put_failure;
        } else {
-               if (ctnetlink_dump_timeout(skb, ct) < 0)
+               if (ctnetlink_dump_timeout(skb, ct, false) < 0)
                        goto nla_put_failure;
 
-               if (events & (1 << IPCT_PROTOINFO)
-                   && ctnetlink_dump_protoinfo(skb, ct) < 0)
+               if (events & (1 << IPCT_PROTOINFO) &&
+                   ctnetlink_dump_protoinfo(skb, ct, false) < 0)
                        goto nla_put_failure;
 
                if ((events & (1 << IPCT_HELPER) || nfct_help(ct))
@@ -2720,10 +2729,10 @@ static int __ctnetlink_glue_build(struct sk_buff *skb, struct nf_conn *ct)
        if (ctnetlink_dump_status(skb, ct) < 0)
                goto nla_put_failure;
 
-       if (ctnetlink_dump_timeout(skb, ct) < 0)
+       if (ctnetlink_dump_timeout(skb, ct, false) < 0)
                goto nla_put_failure;
 
-       if (ctnetlink_dump_protoinfo(skb, ct) < 0)
+       if (ctnetlink_dump_protoinfo(skb, ct, false) < 0)
                goto nla_put_failure;
 
        if (ctnetlink_dump_helpinfo(skb, ct) < 0)
index b3f4a33..db7479d 100644 (file)
@@ -589,7 +589,7 @@ static void dccp_print_conntrack(struct seq_file *s, struct nf_conn *ct)
 
 #if IS_ENABLED(CONFIG_NF_CT_NETLINK)
 static int dccp_to_nlattr(struct sk_buff *skb, struct nlattr *nla,
-                         struct nf_conn *ct)
+                         struct nf_conn *ct, bool destroy)
 {
        struct nlattr *nest_parms;
 
@@ -597,15 +597,22 @@ static int dccp_to_nlattr(struct sk_buff *skb, struct nlattr *nla,
        nest_parms = nla_nest_start(skb, CTA_PROTOINFO_DCCP);
        if (!nest_parms)
                goto nla_put_failure;
-       if (nla_put_u8(skb, CTA_PROTOINFO_DCCP_STATE, ct->proto.dccp.state) ||
-           nla_put_u8(skb, CTA_PROTOINFO_DCCP_ROLE,
+       if (nla_put_u8(skb, CTA_PROTOINFO_DCCP_STATE, ct->proto.dccp.state))
+               goto nla_put_failure;
+
+       if (destroy)
+               goto skip_state;
+
+       if (nla_put_u8(skb, CTA_PROTOINFO_DCCP_ROLE,
                       ct->proto.dccp.role[IP_CT_DIR_ORIGINAL]) ||
            nla_put_be64(skb, CTA_PROTOINFO_DCCP_HANDSHAKE_SEQ,
                         cpu_to_be64(ct->proto.dccp.handshake_seq),
                         CTA_PROTOINFO_DCCP_PAD))
                goto nla_put_failure;
+skip_state:
        nla_nest_end(skb, nest_parms);
        spin_unlock_bh(&ct->lock);
+
        return 0;
 
 nla_put_failure:
index 810cca2..fb8dc02 100644 (file)
@@ -543,7 +543,7 @@ static bool sctp_can_early_drop(const struct nf_conn *ct)
 #include <linux/netfilter/nfnetlink_conntrack.h>
 
 static int sctp_to_nlattr(struct sk_buff *skb, struct nlattr *nla,
-                         struct nf_conn *ct)
+                         struct nf_conn *ct, bool destroy)
 {
        struct nlattr *nest_parms;
 
@@ -552,15 +552,20 @@ static int sctp_to_nlattr(struct sk_buff *skb, struct nlattr *nla,
        if (!nest_parms)
                goto nla_put_failure;
 
-       if (nla_put_u8(skb, CTA_PROTOINFO_SCTP_STATE, ct->proto.sctp.state) ||
-           nla_put_be32(skb, CTA_PROTOINFO_SCTP_VTAG_ORIGINAL,
+       if (nla_put_u8(skb, CTA_PROTOINFO_SCTP_STATE, ct->proto.sctp.state))
+               goto nla_put_failure;
+
+       if (destroy)
+               goto skip_state;
+
+       if (nla_put_be32(skb, CTA_PROTOINFO_SCTP_VTAG_ORIGINAL,
                         ct->proto.sctp.vtag[IP_CT_DIR_ORIGINAL]) ||
            nla_put_be32(skb, CTA_PROTOINFO_SCTP_VTAG_REPLY,
                         ct->proto.sctp.vtag[IP_CT_DIR_REPLY]))
                goto nla_put_failure;
 
+skip_state:
        spin_unlock_bh(&ct->lock);
-
        nla_nest_end(skb, nest_parms);
 
        return 0;
index 811c6c9..1d7e1c5 100644 (file)
@@ -1186,7 +1186,7 @@ static bool tcp_can_early_drop(const struct nf_conn *ct)
 #include <linux/netfilter/nfnetlink_conntrack.h>
 
 static int tcp_to_nlattr(struct sk_buff *skb, struct nlattr *nla,
-                        struct nf_conn *ct)
+                        struct nf_conn *ct, bool destroy)
 {
        struct nlattr *nest_parms;
        struct nf_ct_tcp_flags tmp = {};
@@ -1196,8 +1196,13 @@ static int tcp_to_nlattr(struct sk_buff *skb, struct nlattr *nla,
        if (!nest_parms)
                goto nla_put_failure;
 
-       if (nla_put_u8(skb, CTA_PROTOINFO_TCP_STATE, ct->proto.tcp.state) ||
-           nla_put_u8(skb, CTA_PROTOINFO_TCP_WSCALE_ORIGINAL,
+       if (nla_put_u8(skb, CTA_PROTOINFO_TCP_STATE, ct->proto.tcp.state))
+               goto nla_put_failure;
+
+       if (destroy)
+               goto skip_state;
+
+       if (nla_put_u8(skb, CTA_PROTOINFO_TCP_WSCALE_ORIGINAL,
                       ct->proto.tcp.seen[0].td_scale) ||
            nla_put_u8(skb, CTA_PROTOINFO_TCP_WSCALE_REPLY,
                       ct->proto.tcp.seen[1].td_scale))
@@ -1212,8 +1217,8 @@ static int tcp_to_nlattr(struct sk_buff *skb, struct nlattr *nla,
        if (nla_put(skb, CTA_PROTOINFO_TCP_FLAGS_REPLY,
                    sizeof(struct nf_ct_tcp_flags), &tmp))
                goto nla_put_failure;
+skip_state:
        spin_unlock_bh(&ct->lock);
-
        nla_nest_end(skb, nest_parms);
 
        return 0;