diff options
author | Michael Brown <mcb30@ipxe.org> | 2014-09-22 15:29:13 +0100 |
---|---|---|
committer | Michael Brown <mcb30@ipxe.org> | 2014-09-22 15:29:13 +0100 |
commit | 08bcc0fe0169fa369dee2810d45e5c6b43a94b97 (patch) | |
tree | 49ef0e0f9c695ae6f6c466f4809b0665d2fd6f74 /src | |
parent | 5d9fbf34ee3f7a8b7b829de43115437400d1189f (diff) | |
download | ipxe-08bcc0fe0169fa369dee2810d45e5c6b43a94b97.zip ipxe-08bcc0fe0169fa369dee2810d45e5c6b43a94b97.tar.gz ipxe-08bcc0fe0169fa369dee2810d45e5c6b43a94b97.tar.bz2 |
[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')
-rw-r--r-- | src/net/udp/dhcp.c | 37 |
1 files changed, 37 insertions, 0 deletions
diff --git a/src/net/udp/dhcp.c b/src/net/udp/dhcp.c index e6d3edd..cacbf5a 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: |