From d1c73b6ed65cfb51dc8b8a8a8dc5854e77638f55 Mon Sep 17 00:00:00 2001 From: Zhe Weng Date: Wed, 1 Nov 2023 11:30:36 +0800 Subject: [PATCH] net/tcp: Support initial sequence number described in RFC 6528 Signed-off-by: Zhe Weng --- net/tcp/Kconfig | 11 +++++++ net/tcp/tcp.h | 2 +- net/tcp/tcp_conn.c | 19 +++++++----- net/tcp/tcp_seqno.c | 75 ++++++++++++++++++++++++++++++++++++++++++--- 4 files changed, 94 insertions(+), 13 deletions(-) diff --git a/net/tcp/Kconfig b/net/tcp/Kconfig index a6b98c41985ff..8645ef8a5f1ab 100644 --- a/net/tcp/Kconfig +++ b/net/tcp/Kconfig @@ -158,6 +158,17 @@ config NET_TCP_CC_NEWRENO The TCP Congestion Control defines four congestion control algorithms, slow start, congestion avoidance, fast retransmit, and fast recovery. +config NET_TCP_ISN_RFC6528 + bool "Use Initial Sequence Number Algorithm from RFC 6528" + default n + depends on CRYPTO + ---help--- + Initial Sequence Number Generation Algorithm from RFC 6528: + ISN = M + F(localip, localport, remoteip, remoteport, secretkey) + + M is the 4 microsecond timer, and F() is a pseudorandom + function (PRF) which is MD5 (suggested by RFC 6528). + config NET_TCP_WINDOW_SCALE bool "Enable TCP/IP Window Scale Option" default n diff --git a/net/tcp/tcp.h b/net/tcp/tcp.h index 7398084f06270..fc6f847ce5436 100644 --- a/net/tcp/tcp.h +++ b/net/tcp/tcp.h @@ -896,7 +896,7 @@ uint32_t tcp_addsequence(FAR uint8_t *seqno, uint16_t len); * ****************************************************************************/ -void tcp_initsequence(FAR uint8_t *seqno); +void tcp_initsequence(FAR struct tcp_conn_s *conn); /**************************************************************************** * Name: tcp_nextsequence diff --git a/net/tcp/tcp_conn.c b/net/tcp/tcp_conn.c index 3a681eea17f4d..566a7b16dac02 100644 --- a/net/tcp/tcp_conn.c +++ b/net/tcp/tcp_conn.c @@ -1200,7 +1200,7 @@ FAR struct tcp_conn_s *tcp_alloc_accept(FAR struct net_driver_s *dev, conn->rport = tcp->srcport; conn->tcpstateflags = TCP_SYN_RCVD; - tcp_initsequence(conn->sndseq); + tcp_initsequence(conn); #if !defined(CONFIG_NET_TCP_WRITE_BUFFERS) conn->rexmit_seq = tcp_getsequence(conn->sndseq); #endif @@ -1506,13 +1506,6 @@ int tcp_connect(FAR struct tcp_conn_s *conn, FAR const struct sockaddr *addr) */ conn->tcpstateflags = TCP_SYN_SENT; - tcp_initsequence(conn->sndseq); - - /* Save initial sndseq to rexmit_seq, otherwise it will be zero */ - -#if !defined(CONFIG_NET_TCP_WRITE_BUFFERS) - conn->rexmit_seq = tcp_getsequence(conn->sndseq); -#endif conn->tx_unacked = 1; /* TCP length of the SYN is one. */ conn->nrtx = 0; @@ -1528,6 +1521,16 @@ int tcp_connect(FAR struct tcp_conn_s *conn, FAR const struct sockaddr *addr) conn->sndseq_max = 0; #endif + /* Set initial sndseq when we have both local/remote addr and port */ + + tcp_initsequence(conn); + + /* Save initial sndseq to rexmit_seq, otherwise it will be zero */ + +#if !defined(CONFIG_NET_TCP_WRITE_BUFFERS) + conn->rexmit_seq = tcp_getsequence(conn->sndseq); +#endif + #ifdef CONFIG_NET_TCP_CC_NEWRENO /* Initialize the variables of congestion control. */ diff --git a/net/tcp/tcp_seqno.c b/net/tcp/tcp_seqno.c index e68ad9cf2d65d..d790b2243a031 100644 --- a/net/tcp/tcp_seqno.c +++ b/net/tcp/tcp_seqno.c @@ -43,23 +43,84 @@ #include #if defined(CONFIG_NET) && defined(CONFIG_NET_TCP) -#include +#include #include +#include #include #include #include #include "devif/devif.h" +#include "tcp/tcp.h" #include "utils/utils.h" /**************************************************************************** * Private Data ****************************************************************************/ -/* g_tcpsequence is used to generate initial TCP sequence numbers */ +/* These fields are used to generate initial TCP sequence numbers */ +#ifdef CONFIG_NET_TCP_ISN_RFC6528 +/* RFC 6528, Section 3: Key lengths of 128 bits should be adequate. */ + +static uint32_t g_tcp_isnkey[4]; +#else static uint32_t g_tcpsequence; +#endif + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: tcp_isn_rfc6528 + * + * Description: + * Calculate the initial sequence number described in RFC 6528. + * ISN = M + F(localip, localport, remoteip, remoteport, secretkey) + * + ****************************************************************************/ + +#ifdef CONFIG_NET_TCP_ISN_RFC6528 +static uint32_t tcp_isn_rfc6528(FAR struct tcp_conn_s *conn) +{ + const size_t addrlen = net_ip_domain_select(conn->domain, + sizeof(in_addr_t), sizeof(net_ipv6addr_t)); + MD5_CTX ctx; + uint32_t digest[MD5_DIGEST_LENGTH / 4]; + uint32_t m; + + /* Make sure we have a secret key */ + + if (g_tcp_isnkey[0] == 0) + { + net_getrandom(g_tcp_isnkey, sizeof(g_tcp_isnkey)); + } + + /* M is the 4 microsecond timer */ + + m = TICK2USEC(clock_systime_ticks()) / 4; + + /* F() is suggested to be MD5 */ + + md5init(&ctx); + + /* Calculate F(localip, localport, remoteip, remoteport, secretkey) */ + + md5update(&ctx, net_ip_binding_laddr(&conn->u, conn->domain), addrlen); + md5update(&ctx, &conn->lport, sizeof(conn->lport)); + md5update(&ctx, net_ip_binding_raddr(&conn->u, conn->domain), addrlen); + md5update(&ctx, &conn->rport, sizeof(conn->rport)); + md5update(&ctx, g_tcp_isnkey, sizeof(g_tcp_isnkey)); + + md5final((FAR uint8_t *)digest, &ctx); + + /* ISN = M + F(localip, localport, remoteip, remoteport, secretkey) */ + + return m + digest[0]; +} +#endif /**************************************************************************** * Public Functions @@ -142,8 +203,11 @@ uint32_t tcp_addsequence(FAR uint8_t *seqno, uint16_t len) * ****************************************************************************/ -void tcp_initsequence(FAR uint8_t *seqno) +void tcp_initsequence(FAR struct tcp_conn_s *conn) { +#ifdef CONFIG_NET_TCP_ISN_RFC6528 + tcp_setsequence(conn->sndseq, tcp_isn_rfc6528(conn)); +#else /* If g_tcpsequence is already initialized, just copy it */ if (g_tcpsequence == 0) @@ -164,7 +228,8 @@ void tcp_initsequence(FAR uint8_t *seqno) } } - tcp_setsequence(seqno, g_tcpsequence); + tcp_setsequence(conn->sndseq, g_tcpsequence); +#endif } /**************************************************************************** @@ -180,7 +245,9 @@ void tcp_initsequence(FAR uint8_t *seqno) void tcp_nextsequence(void) { +#ifndef CONFIG_NET_TCP_ISN_RFC6528 g_tcpsequence++; +#endif } #endif /* CONFIG_NET && CONFIG_NET_TCP */