net/tcp: Support initial sequence number described in RFC 6528

Signed-off-by: Zhe Weng <wengzhe@xiaomi.com>
This commit is contained in:
Zhe Weng 2023-11-01 11:30:36 +08:00 committed by Xiang Xiao
parent 5096a2c9fd
commit d1c73b6ed6
4 changed files with 94 additions and 13 deletions

View File

@ -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

View File

@ -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

View File

@ -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. */

View File

@ -43,23 +43,84 @@
#include <nuttx/config.h>
#if defined(CONFIG_NET) && defined(CONFIG_NET_TCP)
#include <stdint.h>
#include <crypto/md5.h>
#include <debug.h>
#include <stdint.h>
#include <nuttx/clock.h>
#include <nuttx/net/netconfig.h>
#include <nuttx/net/netdev.h>
#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 */