summaryrefslogtreecommitdiffstats
path: root/src/net/udp
diff options
context:
space:
mode:
authorMichael Brown2014-09-22 16:29:13 +0200
committerMichael Brown2014-09-22 16:29:13 +0200
commit08bcc0fe0169fa369dee2810d45e5c6b43a94b97 (patch)
tree49ef0e0f9c695ae6f6c466f4809b0665d2fd6f74 /src/net/udp
parent[efi] Provide dummy device path in efi_image_probe() (diff)
downloadipxe-08bcc0fe0169fa369dee2810d45e5c6b43a94b97.tar.gz
ipxe-08bcc0fe0169fa369dee2810d45e5c6b43a94b97.tar.xz
ipxe-08bcc0fe0169fa369dee2810d45e5c6b43a94b97.zip
[dhcp] Check for matching chaddr in received DHCP packets
On large networks a DHCP XID collision is possible. Fix by explicitly checking the chaddr in received DHCP packets. Originally-fixed-by: Wissam Shoukair <wissams@mellanox.com> Signed-off-by: Michael Brown <mcb30@ipxe.org>
Diffstat (limited to 'src/net/udp')
-rw-r--r--src/net/udp/dhcp.c37
1 files changed, 37 insertions, 0 deletions
diff --git a/src/net/udp/dhcp.c b/src/net/udp/dhcp.c
index e6d3eddf..cacbf5a8 100644
--- a/src/net/udp/dhcp.c
+++ b/src/net/udp/dhcp.c
@@ -130,6 +130,29 @@ static inline const char * dhcp_msgtype_name ( unsigned int msgtype ) {
}
}
+/**
+ * Transcribe DHCP client hardware address (for debugging)
+ *
+ * @v chaddr Client hardware address
+ * @v hlen Client hardware address length
+ */
+static const char * dhcp_chaddr_ntoa ( const void *chaddr, size_t hlen ) {
+ static char buf[ 48 /* 16 x ( "xx" + ":" or NUL ) */ ];
+ const uint8_t *chaddr_bytes = chaddr;
+ char *tmp = buf;
+
+ /* Sanity check */
+ assert ( hlen < ( sizeof ( buf ) / 3 ) );
+
+ /* Transcribe address */
+ while ( hlen-- ) {
+ tmp += sprintf ( tmp, "%s%02x", ( ( tmp == buf ) ? "" : ":" ),
+ *(chaddr_bytes++) );
+ }
+
+ return buf;
+}
+
/****************************************************************************
*
* DHCP session
@@ -1159,6 +1182,8 @@ static int dhcp_deliver ( struct dhcp_session *dhcp,
struct dhcphdr *dhcphdr;
uint8_t msgtype = 0;
struct in_addr server_id = { 0 };
+ uint8_t chaddr[ sizeof ( dhcphdr->chaddr ) ];
+ unsigned int hlen;
int rc = 0;
/* Sanity checks */
@@ -1203,9 +1228,21 @@ static int dhcp_deliver ( struct dhcp_session *dhcp,
goto err_xid;
};
+ /* Check for matching client hardware address */
+ hlen = dhcp_chaddr ( dhcp->netdev, chaddr, NULL );
+ if ( memcmp ( dhcphdr->chaddr, chaddr, hlen ) != 0 ) {
+ DBGC ( dhcp, "DHCP %p %s from %s:%d has bad chaddr %s\n",
+ dhcp, dhcp_msgtype_name ( msgtype ),
+ inet_ntoa ( peer->sin_addr ), ntohs ( peer->sin_port ),
+ dhcp_chaddr_ntoa ( dhcphdr->chaddr, hlen ) );
+ rc = -EINVAL;
+ goto err_chaddr;
+ }
+
/* Handle packet based on current state */
dhcp->state->rx ( dhcp, dhcppkt, peer, msgtype, server_id );
+ err_chaddr:
err_xid:
dhcppkt_put ( dhcppkt );
err_alloc_dhcppkt: