From a8b986bbb67820a59be567d280b6be762ef65e92 Mon Sep 17 00:00:00 2001 From: David van Moolenbroek Date: Wed, 26 Oct 2016 21:24:46 +0000 Subject: [PATCH] Add hook for TCP Initial Sequence Number generation lwIP produces a TCP Initial Sequence Number (ISN) for each new TCP connection. The current algorithm is simple and predictable however. The result is that lwIP TCP connections may be the target of TCP spoofing attacks. The problem of such attacks is well known, and a recommended ISN generation algorithm is standardized in RFC 6528. This algorithm requires a high-resolution timer and cryptographic hashing function, though. The implementation (or best-effort approximation) of both of these aspects is well beyond the scope of lwIP itself. For that reason, this patch adds LWIP_HOOK_TCP_ISN, a hook that allows each platform to implement its own ISN generation using locally available means. The hook provides full flexibility, in that the hook may generate anything from a simple random number (by being set to LWIP_RAND()) to a full RFC 6528 implementation. Implementation note: Users of the hook would typically declare the function prototype of the hook function in arch/cc.h, as this is the last place where such prototypes can be supplied. However, at that point, the ip_addr_t type has not yet been defined. For that reason, this patch removes the leading underscore from "struct _ip_addr", so that a prototype of the hook function can use "struct ip_addr" instead of "ip_addr_t". Signed-off-by: sg --- src/core/tcp.c | 17 +++++++++-------- src/core/tcp_in.c | 6 ++++++ src/include/lwip/ip_addr.h | 2 +- src/include/lwip/opt.h | 23 +++++++++++++++++++++++ src/include/lwip/priv/tcp_priv.h | 2 +- 5 files changed, 40 insertions(+), 10 deletions(-) diff --git a/src/core/tcp.c b/src/core/tcp.c index 8712d76c..f72597bb 100644 --- a/src/core/tcp.c +++ b/src/core/tcp.c @@ -880,10 +880,11 @@ tcp_connect(struct tcp_pcb *pcb, const ip_addr_t *ipaddr, u16_t port, #endif /* SO_REUSE */ } - iss = tcp_next_iss(); + iss = tcp_next_iss(pcb); pcb->rcv_nxt = 0; pcb->snd_nxt = iss; pcb->lastack = iss - 1; + pcb->snd_wl2 = iss - 1; pcb->snd_lbb = iss - 1; /* Start with a window that does not need scaling. When window scaling is enabled and used, the window is enlarged when both sides agree on scaling. */ @@ -1491,7 +1492,6 @@ struct tcp_pcb * tcp_alloc(u8_t prio) { struct tcp_pcb *pcb; - u32_t iss; pcb = (struct tcp_pcb *)memp_malloc(MEMP_TCP_PCB); if (pcb == NULL) { @@ -1554,11 +1554,6 @@ tcp_alloc(u8_t prio) pcb->sv = 3000 / TCP_SLOW_INTERVAL; pcb->rtime = -1; pcb->cwnd = 1; - iss = tcp_next_iss(); - pcb->snd_wl2 = iss; - pcb->snd_nxt = iss; - pcb->lastack = iss; - pcb->snd_lbb = iss; pcb->tmr = tcp_ticks; pcb->last_timer = tcp_timer_ctr; @@ -1826,12 +1821,18 @@ tcp_pcb_remove(struct tcp_pcb **pcblist, struct tcp_pcb *pcb) * @return u32_t pseudo random sequence number */ u32_t -tcp_next_iss(void) +tcp_next_iss(struct tcp_pcb *pcb) { +#ifdef LWIP_HOOK_TCP_ISN + return LWIP_HOOK_TCP_ISN(&pcb->local_ip, pcb->local_port, &pcb->remote_ip, pcb->remote_port); +#else /* LWIP_HOOK_TCP_ISN */ static u32_t iss = 6510; + LWIP_UNUSED_ARG(pcb); + iss += tcp_ticks; /* XXX */ return iss; +#endif /* LWIP_HOOK_TCP_ISN */ } #if TCP_CALCULATE_EFF_SEND_MSS diff --git a/src/core/tcp_in.c b/src/core/tcp_in.c index 7f42f577..3d3ae33a 100644 --- a/src/core/tcp_in.c +++ b/src/core/tcp_in.c @@ -542,6 +542,7 @@ static void tcp_listen_input(struct tcp_pcb_listen *pcb) { struct tcp_pcb *npcb; + u32_t iss; err_t rc; if (flags & TCP_RST) { @@ -589,6 +590,11 @@ tcp_listen_input(struct tcp_pcb_listen *pcb) npcb->state = SYN_RCVD; npcb->rcv_nxt = seqno + 1; npcb->rcv_ann_right_edge = npcb->rcv_nxt; + iss = tcp_next_iss(npcb); + npcb->snd_wl2 = iss; + npcb->snd_nxt = iss; + npcb->lastack = iss; + npcb->snd_lbb = iss; npcb->snd_wl1 = seqno - 1;/* initialise to seqno-1 to force window update */ npcb->callback_arg = pcb->callback_arg; #if LWIP_CALLBACK_API || TCP_LISTEN_BACKLOG diff --git a/src/include/lwip/ip_addr.h b/src/include/lwip/ip_addr.h index bce65edd..def2d08c 100644 --- a/src/include/lwip/ip_addr.h +++ b/src/include/lwip/ip_addr.h @@ -66,7 +66,7 @@ enum lwip_ip_addr_type { * A union struct for both IP version's addresses. * ATTENTION: watch out for its size when adding IPv6 address scope! */ -typedef struct _ip_addr { +typedef struct ip_addr { union { ip6_addr_t ip6; ip4_addr_t ip4; diff --git a/src/include/lwip/opt.h b/src/include/lwip/opt.h index d350f3ce..98180c62 100644 --- a/src/include/lwip/opt.h +++ b/src/include/lwip/opt.h @@ -2410,6 +2410,29 @@ * @{ */ +/** + * LWIP_HOOK_TCP_ISN: + * Hook for generation of the Initial Sequence Number (ISN) for a new TCP + * connection. The default lwIP ISN generation algorithm is very basic and may + * allow for TCP spoofing attacks. This hook provides the means to implement + * the standardized ISN generation algorithm from RFC 6528, or any other + * desired algorithm (e.g., it can be set to LWIP_RAND()), as a replacement. + * Called from tcp_connect() and tcp_listen_input() when an ISN is needed for + * a new TCP connection, if TCP support (@ref LWIP_TCP) is enabled.\n + * Signature: u32_t my_hook_tcp_isn(const ip_addr_t* local_ip, u16_t local_port, const ip_addr_t* remote_ip, u16_t remote_port); + * - it may be necessary to use "struct ip_addr" (ip4_addr, ip6_addr) instead of "ip_addr_t" in function declarations\n + * Arguments: + * - local_ip: pointer to the local IP address of the connection + * - local_port: local port number of the connection (host-byte order) + * - remote_ip: pointer to the remote IP address of the connection + * - remote_port: remote port number of the connection (host-byte order)\n + * Return value: + * - the 32-bit Initial Sequence Number to use for the new TCP connection. + */ +#ifdef __DOXYGEN__ +#define LWIP_HOOK_TCP_ISN(local_ip, local_port, remote_ip, remote_port) +#endif + /** * LWIP_HOOK_IP4_INPUT(pbuf, input_netif): * - called from ip_input() (IPv4) diff --git a/src/include/lwip/priv/tcp_priv.h b/src/include/lwip/priv/tcp_priv.h index f0eeb450..f68a856a 100644 --- a/src/include/lwip/priv/tcp_priv.h +++ b/src/include/lwip/priv/tcp_priv.h @@ -452,7 +452,7 @@ void tcp_rst(u32_t seqno, u32_t ackno, const ip_addr_t *local_ip, const ip_addr_t *remote_ip, u16_t local_port, u16_t remote_port); -u32_t tcp_next_iss(void); +u32_t tcp_next_iss(struct tcp_pcb *pcb); err_t tcp_keepalive(struct tcp_pcb *pcb); err_t tcp_zero_window_probe(struct tcp_pcb *pcb);