]> rtime.felk.cvut.cz Git - pes-rpp/rpp-lwip.git/commitdiff
Added a config option to randomize initial local TCP/UDP ports (so that different...
authorSimon Goldschmidt <goldsimon@gmx.de>
Sun, 11 Sep 2011 10:44:01 +0000 (12:44 +0200)
committerSimon Goldschmidt <goldsimon@gmx.de>
Sun, 11 Sep 2011 10:44:01 +0000 (12:44 +0200)
fixed a possible endless loop in tcp_new_port() if the number of active PCBs exceeds the number of available ports;

CHANGELOG
src/core/tcp.c
src/core/udp.c
src/include/lwip/opt.h
src/include/lwip/tcp_impl.h
src/include/lwip/udp.h

index 2321f9f4dca93368bbecf78ff305cf3e6b598591..aa47e307c0ac8e69cee12cdcc4efa625583b1ec8 100644 (file)
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -6,6 +6,11 @@ HISTORY
 
  ++ New features:
 
+  2011-09-11: Simon Goldschmidt
+  * opt.h, tcp_impl.h, tcp.c, udp.h/.c: Added a config option to randomize
+    initial local TCP/UDP ports (so that different port ranges are used after
+    a reboot; bug #33818; this one added tcp_init/udp_init functions again)
+
   2011-09-03: Simon Goldschmidt
   * dhcp.c: DHCP uses LWIP_RAND() for xid's (bug #30302)
 
index 5ae323e397542cb9dfd1f98486a9bcae21f24aa3..432449390d49a457c338e8c8e59a009ce89eb455 100644 (file)
 
 #include <string.h>
 
+#ifndef TCP_LOCAL_PORT_RANGE_START
+/* From http://www.iana.org/assignments/port-numbers:
+   "The Dynamic and/or Private Ports are those from 49152 through 65535" */
+#define TCP_LOCAL_PORT_RANGE_START        0xc000
+#define TCP_LOCAL_PORT_RANGE_END          0xffff
+#define TCP_ENSURE_LOCAL_PORT_RANGE(port) (((port) & ~TCP_LOCAL_PORT_RANGE_START) + TCP_LOCAL_PORT_RANGE_START)
+#endif
+
 const char * const tcp_state_str[] = {
   "CLOSED",      
   "LISTEN",      
@@ -72,6 +80,9 @@ const char * const tcp_state_str[] = {
   "TIME_WAIT"   
 };
 
+/* last local TCP port */
+static u16_t tcp_port = TCP_LOCAL_PORT_RANGE_START;
+
 /* Incremented every coarse grained timer shot (typically every 500 ms). */
 u32_t tcp_ticks;
 const u8_t tcp_backoff[13] =
@@ -104,9 +115,19 @@ struct tcp_pcb *tcp_tmp_pcb;
 static u8_t tcp_timer;
 static u16_t tcp_new_port(void);
 
+/**
+ * Initialize this module.
+ */
+void
+tcp_init(void)
+{
+#if LWIP_RANDOMIZE_INITIAL_LOCAL_PORTS && defined(LWIP_RAND)
+  tcp_port = TCP_ENSURE_LOCAL_PORT_RANGE(LWIP_RAND());
+#endif /* LWIP_RANDOMIZE_INITIAL_LOCAL_PORTS && defined(LWIP_RAND) */
+}
+
 /**
  * Called periodically to dispatch TCP timers.
- *
  */
 void
 tcp_tmr(void)
@@ -415,6 +436,9 @@ tcp_bind(struct tcp_pcb *pcb, ip_addr_t *ipaddr, u16_t port)
 
   if (port == 0) {
     port = tcp_new_port();
+    if (port == 0) {
+      return ERR_BUF;
+    }
   }
 
   /* Check if the address already is in use (on all lists) */
@@ -628,37 +652,33 @@ tcp_recved(struct tcp_pcb *pcb, u16_t len)
 }
 
 /**
- * A nastly hack featuring 'goto' statements that allocates a
- * new TCP local port.
+ * Allocate a new local TCP port.
  *
  * @return a new (free) local TCP port number
  */
 static u16_t
 tcp_new_port(void)
 {
-  int i;
+  u8_t i;
+  u16_t n = 0;
   struct tcp_pcb *pcb;
-#ifndef TCP_LOCAL_PORT_RANGE_START
-/* From http://www.iana.org/assignments/port-numbers:
-   "The Dynamic and/or Private Ports are those from 49152 through 65535" */
-#define TCP_LOCAL_PORT_RANGE_START  0xc000
-#define TCP_LOCAL_PORT_RANGE_END    0xffff
-#endif
-  static u16_t port = TCP_LOCAL_PORT_RANGE_START;
   
- again:
-  if (port++ == TCP_LOCAL_PORT_RANGE_END) {
-    port = TCP_LOCAL_PORT_RANGE_START;
+again:
+  if (tcp_port++ == TCP_LOCAL_PORT_RANGE_END) {
+    tcp_port = TCP_LOCAL_PORT_RANGE_START;
   }
   /* Check all PCB lists. */
   for (i = 0; i < NUM_TCP_PCB_LISTS; i++) {
     for(pcb = *tcp_pcb_lists[i]; pcb != NULL; pcb = pcb->next) {
-      if (pcb->local_port == port) {
+      if (pcb->local_port == tcp_port) {
+        if (++n > (TCP_LOCAL_PORT_RANGE_END - TCP_LOCAL_PORT_RANGE_START)) {
+          return 0;
+        }
         goto again;
       }
     }
   }
-  return port;
+  return tcp_port;
 }
 
 /**
@@ -709,6 +729,9 @@ tcp_connect(struct tcp_pcb *pcb, ip_addr_t *ipaddr, u16_t port,
   old_local_port = pcb->local_port;
   if (pcb->local_port == 0) {
     pcb->local_port = tcp_new_port();
+    if (pcb->local_port == 0) {
+      return ERR_BUF;
+    }
   }
 #if SO_REUSE
   if ((pcb->so_options & SOF_REUSEADDR) != 0) {
index 87a6491620d0b30d1d3e9d701962c4bebea91780..ff4d68968646a2f0f828c41fa9425ebb24f3470d 100644 (file)
 
 #include <string.h>
 
+#ifndef UDP_LOCAL_PORT_RANGE_START
+/* From http://www.iana.org/assignments/port-numbers:
+   "The Dynamic and/or Private Ports are those from 49152 through 65535" */
+#define UDP_LOCAL_PORT_RANGE_START  0xc000
+#define UDP_LOCAL_PORT_RANGE_END    0xffff
+#define UDP_ENSURE_LOCAL_PORT_RANGE(port) (((port) & ~UDP_LOCAL_PORT_RANGE_START) + UDP_LOCAL_PORT_RANGE_START)
+#endif
+
+/* last local UDP port */
+static u16_t udp_port = UDP_LOCAL_PORT_RANGE_START;
+
 /* The list of UDP PCBs */
 /* exported in udp.h (was static) */
 struct udp_pcb *udp_pcbs;
 
+/**
+ * Initialize this module.
+ */
+void
+udp_init(void)
+{
+#if LWIP_RANDOMIZE_INITIAL_LOCAL_PORTS && defined(LWIP_RAND)
+  udp_port = UDP_ENSURE_LOCAL_PORT_RANGE(LWIP_RAND());
+#endif /* LWIP_RANDOMIZE_INITIAL_LOCAL_PORTS && defined(LWIP_RAND) */
+}
+
+/**
+ * Allocate a new local UDP port.
+ *
+ * @return a new (free) local UDP port number
+ */
+static u16_t
+udp_new_port(void)
+{
+  u16_t n = 0;
+  struct udp_pcb *pcb;
+  
+again:
+  if (udp_port++ == UDP_LOCAL_PORT_RANGE_END) {
+    udp_port = UDP_LOCAL_PORT_RANGE_START;
+  }
+  /* Check all PCBs. */
+  for(pcb = udp_pcbs; pcb != NULL; pcb = pcb->next) {
+    if (pcb->local_port == udp_port) {
+      if (++n > (UDP_LOCAL_PORT_RANGE_END - UDP_LOCAL_PORT_RANGE_START)) {
+        return 0;
+      }
+      goto again;
+    }
+  }
+  return udp_port;
+#if 0
+  struct udp_pcb *ipcb = udp_pcbs;
+  while ((ipcb != NULL) && (udp_port != UDP_LOCAL_PORT_RANGE_END)) {
+    if (ipcb->local_port == udp_port) {
+      /* port is already used by another udp_pcb */
+      udp_port++;
+      /* restart scanning all udp pcbs */
+      ipcb = udp_pcbs;
+    } else {
+      /* go on with next udp pcb */
+      ipcb = ipcb->next;
+    }
+  }
+  if (ipcb != NULL) {
+    return 0;
+  }
+  return udp_port;
+#endif
+}
+
 /**
  * Process an incoming UDP datagram.
  *
@@ -854,26 +921,8 @@ udp_bind(struct udp_pcb *pcb, ip_addr_t *ipaddr, u16_t port)
 
   /* no port specified? */
   if (port == 0) {
-#ifndef UDP_LOCAL_PORT_RANGE_START
-/* From http://www.iana.org/assignments/port-numbers:
-   "The Dynamic and/or Private Ports are those from 49152 through 65535" */
-#define UDP_LOCAL_PORT_RANGE_START  0xc000
-#define UDP_LOCAL_PORT_RANGE_END    0xffff
-#endif
-    port = UDP_LOCAL_PORT_RANGE_START;
-    ipcb = udp_pcbs;
-    while ((ipcb != NULL) && (port != UDP_LOCAL_PORT_RANGE_END)) {
-      if (ipcb->local_port == port) {
-        /* port is already used by another udp_pcb */
-        port++;
-        /* restart scanning all udp pcbs */
-        ipcb = udp_pcbs;
-      } else {
-        /* go on with next udp pcb */
-        ipcb = ipcb->next;
-      }
-    }
-    if (ipcb != NULL) {
+    port = udp_new_port();
+    if (port == 0) {
       /* no more ports available in local range */
       LWIP_DEBUGF(UDP_DEBUG, ("udp_bind: out of free UDP ports\n"));
       return ERR_USE;
index fdad392e42bb6e5d68e281c3f19898a1d9cb6d8e..70d64bfe3a4ed4ed70b774e1049a0efdb137c926 100644 (file)
 #define IP_FORWARD_ALLOW_TX_ON_RX_NETIF 0
 #endif
 
+/**
+ * LWIP_RANDOMIZE_INITIAL_LOCAL_PORTS==1: randomize the local port for the first
+ * local TCP/UDP pcb (default==0). This can prevent creating predictable port
+ * numbers after booting a device.
+ */
+#ifndef LWIP_RANDOMIZE_INITIAL_LOCAL_PORTS
+#define LWIP_RANDOMIZE_INITIAL_LOCAL_PORTS 0
+#endif
+
 /*
    ----------------------------------
    ---------- ICMP options ----------
index 14c92fbb4c8a3d9572f03538837664916f5e1251..3f83b1329d28f8cd5775db491512a46ba25df8a0 100644 (file)
@@ -52,7 +52,7 @@ extern "C" {
 /* Functions for interfacing with TCP: */
 
 /* Lower layer interface to TCP: */
-#define tcp_init() /* Compatibility define, no init needed. */
+void             tcp_init    (void);  /* Initialize this module. */
 void             tcp_tmr     (void);  /* Must be called every
                                          TCP_TMR_INTERVAL
                                          ms. (Typically 250 ms). */
index 648c9a469b2f6bbe66dd8145443a2ee7266c357e..aa1ad3fba99f7cef34bb1e7a037552c8b0608136 100644 (file)
@@ -178,7 +178,7 @@ err_t            udp_send_chksum(struct udp_pcb *pcb, struct pbuf *p,
 /* The following functions are the lower layer interface to UDP. */
 void             udp_input      (struct pbuf *p, struct netif *inp);
 
-#define udp_init() /* Compatibility define, not init needed. */
+void             udp_init       (void);
 
 #if LWIP_IPV6
 struct udp_pcb * udp_new_ip6(void);