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>
diff --git a/src/core/tcp.c b/src/core/tcp.c
index 8712d76..f72597b 100644
--- a/src/core/tcp.c
+++ b/src/core/tcp.c
@@ -880,10 +880,11 @@
 #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 @@
 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 @@
     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 @@
  * @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 7f42f57..3d3ae33 100644
--- a/src/core/tcp_in.c
+++ b/src/core/tcp_in.c
@@ -542,6 +542,7 @@
 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 @@
     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 bce65ed..def2d08 100644
--- a/src/include/lwip/ip_addr.h
+++ b/src/include/lwip/ip_addr.h
@@ -66,7 +66,7 @@
  * 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 d350f3c..98180c6 100644
--- a/src/include/lwip/opt.h
+++ b/src/include/lwip/opt.h
@@ -2411,6 +2411,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)
  * - pbuf: received struct pbuf passed to ip_input()
diff --git a/src/include/lwip/priv/tcp_priv.h b/src/include/lwip/priv/tcp_priv.h
index f0eeb45..f68a856 100644
--- a/src/include/lwip/priv/tcp_priv.h
+++ b/src/include/lwip/priv/tcp_priv.h
@@ -452,7 +452,7 @@
        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);