diff --git a/CHANGELOG b/CHANGELOG index 2321f9f4..aa47e307 100644 --- 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) diff --git a/src/core/tcp.c b/src/core/tcp.c index 5ae323e3..43244939 100644 --- a/src/core/tcp.c +++ b/src/core/tcp.c @@ -58,6 +58,14 @@ #include +#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) { diff --git a/src/core/udp.c b/src/core/udp.c index 87a64916..ff4d6896 100644 --- a/src/core/udp.c +++ b/src/core/udp.c @@ -68,10 +68,77 @@ #include +#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; diff --git a/src/include/lwip/opt.h b/src/include/lwip/opt.h index fdad392e..70d64bfe 100644 --- a/src/include/lwip/opt.h +++ b/src/include/lwip/opt.h @@ -606,6 +606,15 @@ #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 ---------- diff --git a/src/include/lwip/tcp_impl.h b/src/include/lwip/tcp_impl.h index 14c92fbb..3f83b132 100644 --- a/src/include/lwip/tcp_impl.h +++ b/src/include/lwip/tcp_impl.h @@ -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). */ diff --git a/src/include/lwip/udp.h b/src/include/lwip/udp.h index 648c9a46..aa1ad3fb 100644 --- a/src/include/lwip/udp.h +++ b/src/include/lwip/udp.h @@ -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);