net/tcp: Add tcp_hash_fail() ratelimited logs
authorDmitry Safonov <dima@arista.com>
Mon, 23 Oct 2023 19:22:07 +0000 (20:22 +0100)
committerDavid S. Miller <davem@davemloft.net>
Fri, 27 Oct 2023 09:35:45 +0000 (10:35 +0100)
Add a helper for logging connection-detailed messages for failed TCP
hash verification (both MD5 and AO).

Co-developed-by: Francesco Ruggeri <fruggeri@arista.com>
Signed-off-by: Francesco Ruggeri <fruggeri@arista.com>
Co-developed-by: Salam Noureddine <noureddine@arista.com>
Signed-off-by: Salam Noureddine <noureddine@arista.com>
Signed-off-by: Dmitry Safonov <dima@arista.com>
Acked-by: David Ahern <dsahern@kernel.org>
Signed-off-by: David S. Miller <davem@davemloft.net>
include/net/tcp.h
include/net/tcp_ao.h
net/ipv4/tcp.c
net/ipv4/tcp_ao.c

index 50ae1ed244e5ae10a7921e7d199a7680a2b23f20..54226d85feb8e0ee2672e4a7988e96402a9760bf 100644 (file)
@@ -2748,12 +2748,18 @@ tcp_inbound_hash(struct sock *sk, const struct request_sock *req,
        int l3index;
 
        /* Invalid option or two times meet any of auth options */
-       if (tcp_parse_auth_options(th, &md5_location, &aoh))
+       if (tcp_parse_auth_options(th, &md5_location, &aoh)) {
+               tcp_hash_fail("TCP segment has incorrect auth options set",
+                             family, skb, "");
                return SKB_DROP_REASON_TCP_AUTH_HDR;
+       }
 
        if (req) {
                if (tcp_rsk_used_ao(req) != !!aoh) {
                        NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPAOBAD);
+                       tcp_hash_fail("TCP connection can't start/end using TCP-AO",
+                                     family, skb, "%s",
+                                     !aoh ? "missing AO" : "AO signed");
                        return SKB_DROP_REASON_TCP_AOFAILURE;
                }
        }
@@ -2770,10 +2776,14 @@ tcp_inbound_hash(struct sock *sk, const struct request_sock *req,
                 * the last key is impossible to remove, so there's
                 * always at least one current_key.
                 */
-               if (tcp_ao_required(sk, saddr, family, true))
+               if (tcp_ao_required(sk, saddr, family, true)) {
+                       tcp_hash_fail("AO hash is required, but not found",
+                                       family, skb, "L3 index %d", l3index);
                        return SKB_DROP_REASON_TCP_AONOTFOUND;
+               }
                if (unlikely(tcp_md5_do_lookup(sk, l3index, saddr, family))) {
                        NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPMD5NOTFOUND);
+                       tcp_hash_fail("MD5 Hash not found", family, skb, "");
                        return SKB_DROP_REASON_TCP_MD5NOTFOUND;
                }
                return SKB_NOT_DROPPED_YET;
index 0c3516d1b96881b1687800ab8c8c832595f76f43..4da6e36579133876402ffb2b75eca2e6f24c8f19 100644 (file)
@@ -118,6 +118,35 @@ struct tcp_ao_info {
        struct rcu_head         rcu;
 };
 
+#define tcp_hash_fail(msg, family, skb, fmt, ...)                      \
+do {                                                                   \
+       const struct tcphdr *th = tcp_hdr(skb);                         \
+       char hdr_flags[5] = {};                                         \
+       char *f = hdr_flags;                                            \
+                                                                       \
+       if (th->fin)                                                    \
+               *f++ = 'F';                                             \
+       if (th->syn)                                                    \
+               *f++ = 'S';                                             \
+       if (th->rst)                                                    \
+               *f++ = 'R';                                             \
+       if (th->ack)                                                    \
+               *f++ = 'A';                                             \
+       if (f != hdr_flags)                                             \
+               *f = ' ';                                               \
+       if ((family) == AF_INET) {                                      \
+               net_info_ratelimited("%s for (%pI4, %d)->(%pI4, %d) %s" fmt "\n", \
+                               msg, &ip_hdr(skb)->saddr, ntohs(th->source), \
+                               &ip_hdr(skb)->daddr, ntohs(th->dest),   \
+                               hdr_flags, ##__VA_ARGS__);              \
+       } else {                                                        \
+               net_info_ratelimited("%s for [%pI6c]:%u->[%pI6c]:%u %s" fmt "\n", \
+                               msg, &ipv6_hdr(skb)->saddr, ntohs(th->source), \
+                               &ipv6_hdr(skb)->daddr, ntohs(th->dest), \
+                               hdr_flags, ##__VA_ARGS__);              \
+       }                                                               \
+} while (0)
+
 #ifdef CONFIG_TCP_AO
 /* TCP-AO structures and functions */
 
index eb71212a09d8273028e26da0c5e6bfd83c8c2a0a..1be6467a059ac8fead260050592bf9d070475da8 100644 (file)
@@ -4383,7 +4383,6 @@ tcp_inbound_md5_hash(const struct sock *sk, const struct sk_buff *skb,
         * o MD5 hash and we're not expecting one.
         * o MD5 hash and its wrong.
         */
-       const struct tcphdr *th = tcp_hdr(skb);
        const struct tcp_sock *tp = tcp_sk(sk);
        struct tcp_md5sig_key *key;
        u8 newhash[16];
@@ -4393,6 +4392,7 @@ tcp_inbound_md5_hash(const struct sock *sk, const struct sk_buff *skb,
 
        if (!key && hash_location) {
                NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPMD5UNEXPECTED);
+               tcp_hash_fail("Unexpected MD5 Hash found", family, skb, "");
                return SKB_DROP_REASON_TCP_MD5UNEXPECTED;
        }
 
@@ -4408,16 +4408,19 @@ tcp_inbound_md5_hash(const struct sock *sk, const struct sk_buff *skb,
        if (genhash || memcmp(hash_location, newhash, 16) != 0) {
                NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPMD5FAILURE);
                if (family == AF_INET) {
-                       net_info_ratelimited("MD5 Hash failed for (%pI4, %d)->(%pI4, %d)%s L3 index %d\n",
-                                       saddr, ntohs(th->source),
-                                       daddr, ntohs(th->dest),
-                                       genhash ? " tcp_v4_calc_md5_hash failed"
-                                       : "", l3index);
+                       tcp_hash_fail("MD5 Hash failed", AF_INET, skb, "%s L3 index %d",
+                                     genhash ? "tcp_v4_calc_md5_hash failed"
+                                     : "", l3index);
                } else {
-                       net_info_ratelimited("MD5 Hash %s for [%pI6c]:%u->[%pI6c]:%u L3 index %d\n",
-                                       genhash ? "failed" : "mismatch",
-                                       saddr, ntohs(th->source),
-                                       daddr, ntohs(th->dest), l3index);
+                       if (genhash) {
+                               tcp_hash_fail("MD5 Hash failed",
+                                             AF_INET6, skb, "L3 index %d",
+                                             l3index);
+                       } else {
+                               tcp_hash_fail("MD5 Hash mismatch",
+                                             AF_INET6, skb, "L3 index %d",
+                                             l3index);
+                       }
                }
                return SKB_DROP_REASON_TCP_MD5FAILURE;
        }
index 7e14bcd4dfd4b87b935229711a75056fb658785c..f76fcb93499d3bd377abe18961d99f612773622b 100644 (file)
@@ -800,6 +800,8 @@ tcp_ao_verify_hash(const struct sock *sk, const struct sk_buff *skb,
                NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPAOBAD);
                atomic64_inc(&info->counters.pkt_bad);
                atomic64_inc(&key->pkt_bad);
+               tcp_hash_fail("AO hash wrong length", family, skb,
+                             "%u != %d", maclen, tcp_ao_maclen(key));
                return SKB_DROP_REASON_TCP_AOFAILURE;
        }
 
@@ -814,6 +816,7 @@ tcp_ao_verify_hash(const struct sock *sk, const struct sk_buff *skb,
                NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPAOBAD);
                atomic64_inc(&info->counters.pkt_bad);
                atomic64_inc(&key->pkt_bad);
+               tcp_hash_fail("AO hash mismatch", family, skb, "");
                kfree(hash_buf);
                return SKB_DROP_REASON_TCP_AOFAILURE;
        }
@@ -841,6 +844,8 @@ tcp_inbound_ao_hash(struct sock *sk, const struct sk_buff *skb,
        info = rcu_dereference(tcp_sk(sk)->ao_info);
        if (!info) {
                NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPAOKEYNOTFOUND);
+               tcp_hash_fail("AO key not found", family, skb,
+                             "keyid: %u", aoh->keyid);
                return SKB_DROP_REASON_TCP_AOUNEXPECTED;
        }
 
@@ -942,6 +947,8 @@ verify_hash:
 key_not_found:
        NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPAOKEYNOTFOUND);
        atomic64_inc(&info->counters.key_not_found);
+       tcp_hash_fail("Requested by the peer AO key id not found",
+                     family, skb, "");
        return SKB_DROP_REASON_TCP_AOKEYNOTFOUND;
 }