From: Jay Foster <jay@systech.com>
To: Gary Thomas <gary@mlbassoc.com>
Cc: eCos Patches <ecos-patches@ecos.sourceware.org>
Subject: Re: DHCP option parsing bug
Date: Tue, 22 Sep 2009 16:29:00 -0000 [thread overview]
Message-ID: <4AB8FB6B.9070008@systech.com> (raw)
In-Reply-To: <4AB39DFE.5030700@mlbassoc.com>
[-- Attachment #1: Type: text/plain, Size: 675 bytes --]
On 9/18/2009 7:49 AM, Gary Thomas wrote:
> On 09/17/2009 05:08 PM, Jay Foster wrote:
>> The attached patch fixes the DHCP option parsing to deal with DHCP
>> servers that don't terminate their options with an END tag. The eCos
>> implementation relies heavily on this. RFC 2132 doesn't specify if this
>> END tag is required or not. Up until now, I have never seen a DHCP
>> server do this, but have run into now.
>>
>> There are other ways to implement this, but I chose this approach as the
>> least invasive.
>
> How about abstracting the 'recvfrom()+test+repair' sequence
> to a function, since there are _four_ identical occurrences?
>
Attached is a revised patch.
Jay
[-- Attachment #2: dhcp.pat --]
[-- Type: text/plain, Size: 6427 bytes --]
Index: ecos/packages/net/common/current/ChangeLog
===================================================================
RCS file: /cvs/ecos/ecos-opt/net/net/common/current/ChangeLog,v
retrieving revision 1.86
diff -u -5 -p -r1.86 ChangeLog
--- ecos/packages/net/common/current/ChangeLog 3 Jul 2009 12:40:25 -0000 1.86
+++ ecos/packages/net/common/current/ChangeLog 22 Sep 2009 16:21:10 -0000
@@ -1,5 +1,10 @@
+2009-09-17 Jay Foster <jay@systech.com>
+
+ * 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 <rbn@vitesse.com>
* src/ifaddrs.c (getifaddrs): If socket() call for IPv6 fails,
a stray pointer was freed.
Index: ecos/packages/net/common/current/src/dhcp_prot.c
===================================================================
RCS file: /cvs/ecos/ecos-opt/net/net/common/current/src/dhcp_prot.c,v
retrieving revision 1.21
diff -u -5 -p -r1.21 dhcp_prot.c
--- ecos/packages/net/common/current/src/dhcp_prot.c 29 Jan 2009 17:49:57 -0000 1.21
+++ ecos/packages/net/common/current/src/dhcp_prot.c 22 Sep 2009 16:21:11 -0000
@@ -652,20 +652,48 @@ static void set_default_dhcp_tags( struc
// Explicitly specify our max message size.
set_fixed_tag( xmit, TAG_DHCP_MAX_MSGSZ, BP_MINPKTSZ, 2 );
}
// ------------------------------------------------------------------------
+// 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
do_dhcp(const char *intf, struct bootp *res,
cyg_uint8 *pstate, struct dhcp_lease *lease)
{
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;
struct timeout_state timeout_scratch;
cyg_uint8 oldstate = *pstate;
@@ -842,15 +870,11 @@ do_dhcp(const char *intf, struct bootp *
// This is a separate state so that we can listen again
// *without* retransmitting.
// 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
bcopy( received, xmit, dhcp_size(received) );
*pstate = DHCPSTATE_BOOTP_FALLBACK;
@@ -951,15 +975,11 @@ do_dhcp(const char *intf, struct bootp *
case DHCPSTATE_REQUEST_RECV:
// 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 ) ) {
*pstate = DHCPSTATE_FAILED;
break;
@@ -1097,15 +1117,11 @@ do_dhcp(const char *intf, struct bootp *
case DHCPSTATE_RENEW_RECV:
// wait for an ACK or a NACK - retry by going back to
// 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 ) ) {
// If we timed out completely, just give up until T2
// expires - retain the lease meanwhile. The normal
@@ -1205,15 +1221,11 @@ do_dhcp(const char *intf, struct bootp *
case DHCPSTATE_REBIND_RECV:
// wait for an ACK or a NACK - retry by going back to
// 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 ) ) {
// If we timed out completely, just give up until EX
// expires - retain the lease meanwhile. The normal
next prev parent reply other threads:[~2009-09-22 16:29 UTC|newest]
Thread overview: 4+ messages / expand[flat|nested] mbox.gz Atom feed top
2009-09-17 23:08 Jay Foster
2009-09-18 14:49 ` Gary Thomas
2009-09-22 16:29 ` Jay Foster [this message]
2009-09-23 14:29 ` Gary Thomas
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=4AB8FB6B.9070008@systech.com \
--to=jay@systech.com \
--cc=ecos-patches@ecos.sourceware.org \
--cc=gary@mlbassoc.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).