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 <goldsimon@gmx.de>
This commit is contained in:
David van Moolenbroek 2016-10-26 21:24:46 +00:00 committed by sg
parent da15132aa0
commit a8b986bbb6
5 changed files with 40 additions and 10 deletions

View File

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

View File

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

View File

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

View File

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

View File

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