[PATCH v8 10/26] tcp: ipv6: Add AO signing for tcp_v6_send_response

From: Leonard Crestez
Date: Mon Sep 05 2022 - 03:08:09 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 | 60 ++++++++++++++++++++++++++++++++++++++++++
2 files changed, 62 insertions(+)

diff --git a/net/ipv4/tcp_authopt.c b/net/ipv4/tcp_authopt.c
index 1c2039a48bf6..bb74ab96b18f 100644
--- a/net/ipv4/tcp_authopt.c
+++ b/net/ipv4/tcp_authopt.c
@@ -381,10 +381,11 @@ struct tcp_authopt_key_info *__tcp_authopt_select_key(const struct sock *sk,
{
struct netns_tcp_authopt *net = sock_net_tcp_authopt(sk);

return tcp_authopt_lookup_send(net, addr_sk);
}
+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;
@@ -1206,10 +1207,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);

/**
* tcp_authopt_lookup_recv - lookup key for receive
*
* @sk: Receive socket
diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c
index 8969aee822d5..9e507fcad7cc 100644
--- a/net/ipv6/tcp_ipv6.c
+++ b/net/ipv6/tcp_ipv6.c
@@ -40,10 +40,11 @@
#include <linux/icmpv6.h>
#include <linux/random.h>
#include <linux/indirect_call_wrapper.h>

#include <net/tcp.h>
+#include <net/tcp_authopt.h>
#include <net/ndisc.h>
#include <net/inet6_hashtables.h>
#include <net/inet6_connection_sock.h>
#include <net/ipv6.h>
#include <net/transp_v6.h>
@@ -853,10 +854,48 @@ const struct tcp_request_sock_ops tcp_request_sock_ipv6_ops = {
.init_seq = tcp_v6_init_seq,
.init_ts_off = tcp_v6_init_ts_off,
.send_synack = tcp_v6_send_synack,
};

+#ifdef CONFIG_TCP_AUTHOPT
+static int tcp_v6_send_response_init_authopt(const struct sock *sk,
+ struct tcp_authopt_info **info,
+ struct tcp_authopt_key_info **key,
+ u8 *rnextkeyid)
+{
+ /* Key lookup before SKB allocation */
+ if (!(tcp_authopt_needed && sk))
+ return 0;
+ if (sk->sk_state == TCP_TIME_WAIT)
+ *info = tcp_twsk(sk)->tw_authopt_info;
+ else
+ *info = rcu_dereference(tcp_sk(sk)->authopt_info);
+ if (!*info)
+ return 0;
+ *key = __tcp_authopt_select_key(sk, *info, sk, rnextkeyid);
+ if (*key)
+ return TCPOLEN_AUTHOPT_OUTPUT;
+ return 0;
+}
+
+static void tcp_v6_send_response_sign_authopt(const struct sock *sk,
+ struct tcp_authopt_info *info,
+ struct tcp_authopt_key_info *key,
+ struct sk_buff *skb,
+ struct tcphdr_authopt *ptr,
+ u8 rnextkeyid)
+{
+ if (!(tcp_authopt_needed && key))
+ return;
+ ptr->num = TCPOPT_AUTHOPT;
+ ptr->len = TCPOLEN_AUTHOPT_OUTPUT;
+ ptr->keyid = key->send_id;
+ ptr->rnextkeyid = rnextkeyid;
+ tcp_authopt_hash(ptr->mac, key, info, (struct sock *)sk, skb);
+}
+#endif
+
static void tcp_v6_send_response(const struct sock *sk, struct sk_buff *skb, u32 seq,
u32 ack, u32 win, u32 tsval, u32 tsecr,
int oif, struct tcp_md5sig_key *key, int rst,
u8 tclass, __be32 label, u32 priority, u32 txhash)
{
@@ -868,13 +907,30 @@ 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 *aoinfo;
+ struct tcp_authopt_key_info *aokey;
+ u8 aornextkeyid;
+ int aolen;
+#endif

if (tsecr)
tot_len += TCPOLEN_TSTAMP_ALIGNED;
+#ifdef CONFIG_TCP_AUTHOPT
+ /* Key lookup before SKB allocation */
+ aolen = tcp_v6_send_response_init_authopt(sk, &aoinfo, &aokey, &aornextkeyid);
+ if (aolen) {
+ tot_len += aolen;
+#ifdef CONFIG_TCP_MD5SIG
+ /* Don't use MD5 */
+ key = NULL;
+#endif
+ }
+#endif
#ifdef CONFIG_TCP_MD5SIG
if (key)
tot_len += TCPOLEN_MD5SIG_ALIGNED;
#endif

@@ -926,10 +982,14 @@ 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
+ tcp_v6_send_response_sign_authopt(sk, aoinfo, aokey, buff,
+ (struct tcphdr_authopt *)topt, aornextkeyid);
+#endif

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