[PATCH v2 12/25] tcp: ipv6: Add AO signing for tcp_v6_send_response

From: Leonard Crestez
Date: Mon Nov 01 2021 - 12:36:24 EST


This is a special code path for acks and resets outside of normal
connection establishment and closing.

Signed-off-by: Leonard Crestez <cdleonard@xxxxxxxxx>
---
net/ipv4/tcp_authopt.c | 2 ++
net/ipv6/tcp_ipv6.c | 38 ++++++++++++++++++++++++++++++++++++++
2 files changed, 40 insertions(+)

diff --git a/net/ipv4/tcp_authopt.c b/net/ipv4/tcp_authopt.c
index a48b741c83e4..c9d201d8f7a7 100644
--- a/net/ipv4/tcp_authopt.c
+++ b/net/ipv4/tcp_authopt.c
@@ -296,10 +296,11 @@ struct tcp_authopt_key_info *__tcp_authopt_select_key(const struct sock *sk,
const struct sock *addr_sk,
u8 *rnextkeyid)
{
return tcp_authopt_lookup_send(info, addr_sk, -1);
}
+EXPORT_SYMBOL(__tcp_authopt_select_key);

static struct tcp_authopt_info *__tcp_authopt_info_get_or_create(struct sock *sk)
{
struct tcp_sock *tp = tcp_sk(sk);
struct tcp_authopt_info *info;
@@ -1202,10 +1203,11 @@ int tcp_authopt_hash(char *hash_location,
* try to make it obvious inside the packet.
*/
memset(hash_location, 0, TCP_AUTHOPT_MACLEN);
return err;
}
+EXPORT_SYMBOL(tcp_authopt_hash);

static struct tcp_authopt_key_info *tcp_authopt_lookup_recv(struct sock *sk,
struct sk_buff *skb,
struct tcp_authopt_info *info,
int recv_id)
diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c
index 96a29caf56c7..68f9545e4347 100644
--- a/net/ipv6/tcp_ipv6.c
+++ b/net/ipv6/tcp_ipv6.c
@@ -902,13 +902,37 @@ static void tcp_v6_send_response(const struct sock *sk, struct sk_buff *skb, u32
struct sock *ctl_sk = net->ipv6.tcp_sk;
unsigned int tot_len = sizeof(struct tcphdr);
__be32 mrst = 0, *topt;
struct dst_entry *dst;
__u32 mark = 0;
+#ifdef CONFIG_TCP_AUTHOPT
+ struct tcp_authopt_info *authopt_info = NULL;
+ struct tcp_authopt_key_info *authopt_key_info = NULL;
+ u8 authopt_rnextkeyid;
+#endif

if (tsecr)
tot_len += TCPOLEN_TSTAMP_ALIGNED;
+#ifdef CONFIG_TCP_AUTHOPT
+ /* Key lookup before SKB allocation */
+ if (static_branch_unlikely(&tcp_authopt_needed) && sk) {
+ if (sk->sk_state == TCP_TIME_WAIT)
+ authopt_info = tcp_twsk(sk)->tw_authopt_info;
+ else
+ authopt_info = rcu_dereference(tcp_sk(sk)->authopt_info);
+
+ if (authopt_info) {
+ authopt_key_info = __tcp_authopt_select_key(sk, authopt_info, sk,
+ &authopt_rnextkeyid);
+ if (authopt_key_info) {
+ tot_len += TCPOLEN_AUTHOPT_OUTPUT;
+ /* Don't use MD5 */
+ key = NULL;
+ }
+ }
+ }
+#endif
#ifdef CONFIG_TCP_MD5SIG
if (key)
tot_len += TCPOLEN_MD5SIG_ALIGNED;
#endif

@@ -961,10 +985,24 @@ static void tcp_v6_send_response(const struct sock *sk, struct sk_buff *skb, u32
tcp_v6_md5_hash_hdr((__u8 *)topt, key,
&ipv6_hdr(skb)->saddr,
&ipv6_hdr(skb)->daddr, t1);
}
#endif
+#ifdef CONFIG_TCP_AUTHOPT
+ /* Compute the TCP-AO mac. Unlike in the ipv4 case we have a real SKB */
+ if (static_branch_unlikely(&tcp_authopt_needed) && authopt_key_info) {
+ *topt++ = htonl((TCPOPT_AUTHOPT << 24) |
+ (TCPOLEN_AUTHOPT_OUTPUT << 16) |
+ (authopt_key_info->send_id << 8) |
+ (authopt_rnextkeyid));
+ tcp_authopt_hash((char *)topt,
+ authopt_key_info,
+ authopt_info,
+ (struct sock *)sk,
+ buff);
+ }
+#endif

memset(&fl6, 0, sizeof(fl6));
fl6.daddr = ipv6_hdr(skb)->saddr;
fl6.saddr = ipv6_hdr(skb)->daddr;
fl6.flowlabel = label;
--
2.25.1