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

fixed a possible endless loop in tcp_new_port() if the number of active PCBs exceeds the number of available ports;
This commit is contained in:
Simon Goldschmidt 2011-09-11 12:44:01 +02:00
parent 5be300736e
commit 112158b056
6 changed files with 124 additions and 38 deletions

View File

@ -6,6 +6,11 @@ HISTORY
++ New features: ++ 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 2011-09-03: Simon Goldschmidt
* dhcp.c: DHCP uses LWIP_RAND() for xid's (bug #30302) * dhcp.c: DHCP uses LWIP_RAND() for xid's (bug #30302)

View File

@ -58,6 +58,14 @@
#include <string.h> #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[] = { const char * const tcp_state_str[] = {
"CLOSED", "CLOSED",
"LISTEN", "LISTEN",
@ -72,6 +80,9 @@ const char * const tcp_state_str[] = {
"TIME_WAIT" "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). */ /* Incremented every coarse grained timer shot (typically every 500 ms). */
u32_t tcp_ticks; u32_t tcp_ticks;
const u8_t tcp_backoff[13] = const u8_t tcp_backoff[13] =
@ -104,9 +115,19 @@ struct tcp_pcb *tcp_tmp_pcb;
static u8_t tcp_timer; static u8_t tcp_timer;
static u16_t tcp_new_port(void); 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. * Called periodically to dispatch TCP timers.
*
*/ */
void void
tcp_tmr(void) tcp_tmr(void)
@ -415,6 +436,9 @@ tcp_bind(struct tcp_pcb *pcb, ip_addr_t *ipaddr, u16_t port)
if (port == 0) { if (port == 0) {
port = tcp_new_port(); port = tcp_new_port();
if (port == 0) {
return ERR_BUF;
}
} }
/* Check if the address already is in use (on all lists) */ /* 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 * Allocate a new local TCP port.
* new TCP local port.
* *
* @return a new (free) local TCP port number * @return a new (free) local TCP port number
*/ */
static u16_t static u16_t
tcp_new_port(void) tcp_new_port(void)
{ {
int i; u8_t i;
u16_t n = 0;
struct tcp_pcb *pcb; 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: again:
if (port++ == TCP_LOCAL_PORT_RANGE_END) { if (tcp_port++ == TCP_LOCAL_PORT_RANGE_END) {
port = TCP_LOCAL_PORT_RANGE_START; tcp_port = TCP_LOCAL_PORT_RANGE_START;
} }
/* Check all PCB lists. */ /* Check all PCB lists. */
for (i = 0; i < NUM_TCP_PCB_LISTS; i++) { for (i = 0; i < NUM_TCP_PCB_LISTS; i++) {
for(pcb = *tcp_pcb_lists[i]; pcb != NULL; pcb = pcb->next) { 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; 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; old_local_port = pcb->local_port;
if (pcb->local_port == 0) { if (pcb->local_port == 0) {
pcb->local_port = tcp_new_port(); pcb->local_port = tcp_new_port();
if (pcb->local_port == 0) {
return ERR_BUF;
}
} }
#if SO_REUSE #if SO_REUSE
if ((pcb->so_options & SOF_REUSEADDR) != 0) { if ((pcb->so_options & SOF_REUSEADDR) != 0) {

View File

@ -68,10 +68,77 @@
#include <string.h> #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 */ /* The list of UDP PCBs */
/* exported in udp.h (was static) */ /* exported in udp.h (was static) */
struct udp_pcb *udp_pcbs; 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. * 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? */ /* no port specified? */
if (port == 0) { if (port == 0) {
#ifndef UDP_LOCAL_PORT_RANGE_START port = udp_new_port();
/* From http://www.iana.org/assignments/port-numbers: if (port == 0) {
"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) {
/* no more ports available in local range */ /* no more ports available in local range */
LWIP_DEBUGF(UDP_DEBUG, ("udp_bind: out of free UDP ports\n")); LWIP_DEBUGF(UDP_DEBUG, ("udp_bind: out of free UDP ports\n"));
return ERR_USE; return ERR_USE;

View File

@ -606,6 +606,15 @@
#define IP_FORWARD_ALLOW_TX_ON_RX_NETIF 0 #define IP_FORWARD_ALLOW_TX_ON_RX_NETIF 0
#endif #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 ---------- ---------- ICMP options ----------

View File

@ -52,7 +52,7 @@ extern "C" {
/* Functions for interfacing with TCP: */ /* Functions for interfacing with TCP: */
/* Lower layer interface to 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 void tcp_tmr (void); /* Must be called every
TCP_TMR_INTERVAL TCP_TMR_INTERVAL
ms. (Typically 250 ms). */ ms. (Typically 250 ms). */

View 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. */ /* The following functions are the lower layer interface to UDP. */
void udp_input (struct pbuf *p, struct netif *inp); void udp_input (struct pbuf *p, struct netif *inp);
#define udp_init() /* Compatibility define, not init needed. */ void udp_init (void);
#if LWIP_IPV6 #if LWIP_IPV6
struct udp_pcb * udp_new_ip6(void); struct udp_pcb * udp_new_ip6(void);