# HG changeset patch # User gthomas # Date 1253716128 0 # Node ID ca9867bef994c3428dd3aa674fe504025e032a39 # Parent 2b12e401c9d2358101ebfc50e2c06f6ae5f2dc20 DHCP parsing improvement/bugfix from Jay Foster diff --git a/packages/net/common/current/ChangeLog b/packages/net/common/current/ChangeLog --- a/packages/net/common/current/ChangeLog +++ b/packages/net/common/current/ChangeLog @@ -1,3 +1,8 @@ +2009-09-17 Jay Foster + + * src/dhcp_prot.c (do_dhcp): Fix packet parsing for DHCP servers + that do not terminate the options with an END tag. + 2009-06-23 Rene Schipp von Branitz Nielsen * src/ifaddrs.c (getifaddrs): If socket() call for IPv6 fails, diff --git a/packages/net/common/current/src/dhcp_prot.c b/packages/net/common/current/src/dhcp_prot.c --- a/packages/net/common/current/src/dhcp_prot.c +++ b/packages/net/common/current/src/dhcp_prot.c @@ -654,6 +654,35 @@ static void set_default_dhcp_tags( struc } // ------------------------------------------------------------------------ +// Get BOOTP/DHCP response. +// Wait up to the amount of time specified by *tvp. + +static int +get_response(int s, struct bootp *response, struct sockaddr_in *from, struct timeval *tvp) +{ + int pktlen; + socklen_t addrlen; + + setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, tvp, sizeof(*tvp)); + + addrlen = sizeof(*from); + pktlen = recvfrom(s, response, sizeof(*response), 0, (struct sockaddr *)from, &addrlen); + /* Some DHCP servers don't terminate the options list with + * an END tag. Append one if we can. + */ + if ((pktlen >= 0) && (pktlen < sizeof(*response))) + { + /* Do not count the added END tag in the returned packet length. + * The returned packet length is the number of bytes received + * from the DHCP server. The added END tag is only used + * internally for packet parsing purposes. + */ + ((unsigned char *)response)[pktlen] = TAG_END; + } + return pktlen; +} + +// ------------------------------------------------------------------------ // the DHCP state machine - this does all the work int @@ -663,7 +692,6 @@ do_dhcp(const char *intf, struct bootp * struct ifreq ifr; struct sockaddr_in cli_addr, broadcast_addr, server_addr, rx_addr; int s = -1; - socklen_t addrlen; int one = 1; unsigned char mincookie[] = {99,130,83,99,255} ; struct timeval tv; @@ -844,11 +872,7 @@ do_dhcp(const char *intf, struct bootp * // listen for the DHCPOFFER reply - setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)); - - addrlen = sizeof(rx_addr); - if (recvfrom(s, received, sizeof(struct bootp), 0, - (struct sockaddr *)&rx_addr, &addrlen) < 0) { + if (get_response(s, received, &rx_addr, &tv) < 0) { // No packet arrived (this time) if ( seen_bootp_reply ) { // then already have a bootp reply // Save the good packet in *xmit @@ -953,11 +977,7 @@ do_dhcp(const char *intf, struct bootp * // wait for an ACK or a NACK - retry by going back to // DHCPSTATE_REQUESTING; NACK means go back to INIT. - setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)); - - addrlen = sizeof(rx_addr); - if (recvfrom(s, received, sizeof(struct bootp), 0, - (struct sockaddr *)&rx_addr, &addrlen) < 0) { + if (get_response(s, received, &rx_addr, &tv) < 0) { // No packet arrived // go to the next larger timeout and re-send: if ( ! next_timeout( &tv, &timeout_scratch ) ) { @@ -1099,11 +1119,7 @@ do_dhcp(const char *intf, struct bootp * // DHCPSTATE_RENEWING; NACK means go to NOTBOUND. // No answer means just wait for T2, to broadcast. - setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)); - - addrlen = sizeof(rx_addr); - if (recvfrom(s, received, sizeof(struct bootp), 0, - (struct sockaddr *)&rx_addr, &addrlen) < 0) { + if (get_response(s, received, &rx_addr, &tv) < 0) { // No packet arrived // go to the next larger timeout and re-send: if ( ! next_timeout( &tv, &timeout_scratch ) ) { @@ -1207,11 +1223,7 @@ do_dhcp(const char *intf, struct bootp * // DHCPSTATE_REBINDING; NACK means go to NOTBOUND. // No answer means just wait for expiry; we tried! - setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)); - - addrlen = sizeof(rx_addr); - if (recvfrom(s, received, sizeof(struct bootp), 0, - (struct sockaddr *)&rx_addr, &addrlen) < 0) { + if (get_response(s, received, &rx_addr, &tv) < 0) { // No packet arrived // go to the next larger timeout and re-send: if ( ! next_timeout( &tv, &timeout_scratch ) ) {