[syslinux] [PATCH] core/lwip: Avoid immediate reuse of UDP port numbers
Michael Brown
mcb30 at ipxe.org
Mon Jul 4 01:35:09 PDT 2016
The UDP binding logic will reuse local port numbers immediately. This
causes problems for TFTP, which assumes a very low probability of a
source port number being reused. The consequence is that lpxelinux.0
may end up downloading an incorrect file (e.g. attempting to download
pxelinux.cfg/default but actually receiving a copy of ldlinux.c32, due
to the port number having been reused).
Fix by allocating local UDP port numbers in the same way as local TCP
port numbers.
Signed-off-by: Michael Brown <mcb30 at ipxe.org>
---
core/lwip/src/core/udp.c | 57 ++++++++++++++++++++++++++++--------------------
1 file changed, 33 insertions(+), 24 deletions(-)
diff --git a/core/lwip/src/core/udp.c b/core/lwip/src/core/udp.c
index 4596ba2..68e7f48 100644
--- a/core/lwip/src/core/udp.c
+++ b/core/lwip/src/core/udp.c
@@ -679,6 +679,37 @@ udp_sendto_if_chksum(struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *dst_ip,
}
/**
+ * A nastly hack featuring 'goto' statements that allocates a
+ * new UDP local port. Based on equivalent code in tcp_new_port()
+ *
+ * @return a new (free) local UDP port number
+ */
+static u16_t
+udp_new_port(void)
+{
+ struct udp_pcb *pcb;
+#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
+ static u16_t port = UDP_LOCAL_PORT_RANGE_START;
+
+ again:
+ if (port++ >= UDP_LOCAL_PORT_RANGE_END) {
+ port = UDP_LOCAL_PORT_RANGE_START;
+ }
+ /* Check PCB list. */
+ for(pcb = udp_pcbs; pcb != NULL; pcb = pcb->next) {
+ if (pcb->local_port == port) {
+ goto again;
+ }
+ }
+ return port;
+}
+
+/**
* Bind an UDP PCB.
*
* @param pcb UDP PCB to be bound with a local address ipaddr and port.
@@ -745,31 +776,9 @@ 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) {
- /* no more ports available in local range */
- LWIP_DEBUGF(UDP_DEBUG, ("udp_bind: out of free UDP ports\n"));
- return ERR_USE;
- }
+ port = udp_new_port();
}
+
pcb->local_port = port;
snmp_insert_udpidx_tree(pcb);
/* pcb not active yet? */
--
2.3.8
More information about the Syslinux
mailing list