lkml.org 
[lkml]   [2023]   [Feb]   [15]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH v4 15/21] net/tcp: Add tcp_hash_fail() ratelimited logs
    Date
    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>
    ---
    include/net/tcp.h | 14 ++++++++++++--
    include/net/tcp_ao.h | 27 +++++++++++++++++++++++++++
    net/ipv4/tcp.c | 23 +++++++++++++----------
    net/ipv4/tcp_ao.c | 7 +++++++
    4 files changed, 59 insertions(+), 12 deletions(-)

    diff --git a/include/net/tcp.h b/include/net/tcp.h
    index ff1680611530..7b1d8b05e3bc 100644
    --- a/include/net/tcp.h
    +++ b/include/net/tcp.h
    @@ -2579,12 +2579,19 @@ 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)
    + if (tcp_rsk_used_ao(req) != !!aoh) {
    + 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;
    + }
    }

    /* sdif set, means packet ingressed via a device
    @@ -2607,11 +2614,14 @@ tcp_inbound_hash(struct sock *sk, const struct request_sock *req,
    lockdep_sock_is_held(sk));
    NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPAOREQUIRED);
    atomic64_inc(&ao_info->counters.ao_required);
    + tcp_hash_fail("AO hash is required, but not found",
    + family, skb, "");
    return SKB_DROP_REASON_TCP_AONOTFOUND;
    }
    #endif
    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;
    diff --git a/include/net/tcp_ao.h b/include/net/tcp_ao.h
    index 07d05bb49e46..d953105f5f73 100644
    --- a/include/net/tcp_ao.h
    +++ b/include/net/tcp_ao.h
    @@ -98,6 +98,33 @@ struct tcp_ao_info {
    atomic_t refcnt; /* Protects twsk destruction */
    };

    +#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 (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 */

    diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c
    index 3a2caa5eeee2..d59e7422a481 100644
    --- a/net/ipv4/tcp.c
    +++ b/net/ipv4/tcp.c
    @@ -4525,7 +4525,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);
    struct tcp_sock *tp = tcp_sk(sk);
    struct tcp_md5sig_key *key;
    int genhash;
    @@ -4535,6 +4534,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;
    }

    @@ -4550,16 +4550,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;
    }
    diff --git a/net/ipv4/tcp_ao.c b/net/ipv4/tcp_ao.c
    index d34ff3682cf8..6f650ebe01c4 100644
    --- a/net/ipv4/tcp_ao.c
    +++ b/net/ipv4/tcp_ao.c
    @@ -693,6 +693,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;
    }

    @@ -703,6 +705,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, "");
    return SKB_DROP_REASON_TCP_AOFAILURE;
    }
    NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPAOGOOD);
    @@ -728,6 +731,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;
    }

    @@ -824,6 +829,8 @@ tcp_inbound_ao_hash(struct sock *sk, const struct sk_buff *skb,
    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;
    }

    --
    2.39.1
    \
     
     \ /
      Last update: 2023-03-27 00:24    [W:3.510 / U:0.224 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site