changeset 229:ff3465255c3a

* src/dhcp_prot.c (_dhcp_copy): Remove. Unnecessary as we can never receive a packet longer than sizeof(struct bootp) (do_dhcp): Also set giaddr to 0 before sends. Verify length of received packets, especially to check for truncation.
author jlarmour
date Thu, 04 Jul 2002 18:03:05 +0000
parents e1b642d73533
children 20314171555b
files packages/net/common/current/ChangeLog packages/net/common/current/src/dhcp_prot.c
diffstat 2 files changed, 52 insertions(+), 54 deletions(-) [+]
line wrap: on
line diff
--- a/packages/net/common/current/ChangeLog
+++ b/packages/net/common/current/ChangeLog
@@ -1,3 +1,10 @@
+2002-07-04  Jonathan Larmour  <jlarmour@redhat.com>
+
+	* src/dhcp_prot.c (_dhcp_copy): Remove. Unnecessary as we can never
+	receive a packet longer than sizeof(struct bootp)
+	(do_dhcp): Also set giaddr to 0 before sends.
+	Verify length of received packets, especially to check for truncation.
+
 2002-06-20  Gary Thomas  <gary@chez-thomas.org>
 
 	* src/inet_ntop.c: Fix build error when used with newer compilers.
--- a/packages/net/common/current/src/dhcp_prot.c
+++ b/packages/net/common/current/src/dhcp_prot.c
@@ -512,26 +512,6 @@ static void set_default_dhcp_tags( struc
     set_fixed_tag( xmit, TAG_DHCP_MAX_MSGSZ, BP_MINPKTSZ, 2 );
 }
 
-//
-// Make a copy of a BOOTP/DHCP record.  Note that this can
-// be [somewhat] arbitrarily long, thus it needs to be allocated
-// dynamically.  Reset certain fields within the record that are
-// supposed to only be returned by the server.
-//
-static struct bootp *
-_dhcp_copy(struct bootp *xmit, int xlen)
-{
-    struct bootp *xmit2;
-    xmit2 = (struct bootp *)cyg_net_malloc(xlen, 0, 0);
-    if (xmit2) {
-        bcopy(xmit, xmit2, xlen);
-        xmit2->bp_yiaddr.s_addr = 0;
-        xmit2->bp_siaddr.s_addr = 0;
-        xmit2->bp_hops = 0;
-    }
-    return xmit2;
-}
-
 // ------------------------------------------------------------------------
 // the DHCP state machine - this does all the work
 
@@ -566,7 +546,7 @@ do_dhcp(const char *intf, struct bootp *
     struct bootp rx_local;
     struct bootp *received = &rx_local;
     struct bootp *xmit = res;
-    struct bootp *xmit2 = (struct bootp *)NULL;
+    struct bootp xmit2;
     int xlen;
 
     // First, get a socket on the interface in question.  But Zeroth, if
@@ -743,15 +723,20 @@ do_dhcp(const char *intf, struct bootp *
                 *pstate = DHCPSTATE_INIT; // to retransmit
                 break;
             }
-
+            // Check for well-formed packet with correct termination (not truncated)
+            length = dhcp_size( received );
 #ifdef CYGDBG_NET_DHCP_CHATTER
             diag_printf( "---------DHCPSTATE_SELECTING received:\n" );
+            if ( length <= 0 )
+                diag_printf( "WARNING! malformed or truncated packet\n" );
             diag_printf( "...rx_addr is family %d, addr %08x, port %d\n",
                          rx_addr.sin_family,
                          rx_addr.sin_addr.s_addr,
                          rx_addr.sin_port );
             show_bootp( intf, received );
 #endif            
+            if ( length <= 0 )
+                break;
             if ( CHECK_XID() )          // XID and ESA matches?
                 break;                  // listen again...
 
@@ -807,13 +792,12 @@ do_dhcp(const char *intf, struct bootp *
 #endif            
             // Send back a [modified] copy.  Note that some fields are explicitly
             // cleared, as per the RFC.  We need the copy because these fields are
-            // still useful to us (and currently stored in the 'result' structure)            
-            xlen = dhcp_size_for_send(xmit);
-            if ((xmit2 = _dhcp_copy(xmit, xlen)) == (struct bootp *)NULL) {
-                *pstate = DHCPSTATE_FAILED;
-                break;
-            }
-            if(sendto(s, xmit2, xlen, 0, 
+            // still useful to us (and currently stored in the 'result' structure)
+            xlen = dhcp_size_for_send( xmit );
+            bcopy( xmit, &xmit2, xlen );
+            xmit2.bp_yiaddr.s_addr = xmit2.bp_siaddr.s_addr = xmit2.bp_giaddr.s_addr = 0;
+            xmit2.bp_hops = 0;
+            if(sendto(s, &xmit2, xlen, 0, 
                       (struct sockaddr *)&broadcast_addr, sizeof(broadcast_addr)) < 0) {
                 *pstate = DHCPSTATE_FAILED;
                 break;
@@ -840,15 +824,20 @@ do_dhcp(const char *intf, struct bootp *
                 *pstate = DHCPSTATE_REQUESTING;
                 break;
             }
-
+            // Check for well-formed packet with correct termination (not truncated)
+            length = dhcp_size( received );
 #ifdef CYGDBG_NET_DHCP_CHATTER
             diag_printf( "---------DHCPSTATE_REQUEST_RECV received:\n" );
+            if ( length <= 0 )
+                diag_printf( "WARNING! malformed or truncated packet\n" );
             diag_printf( "...rx_addr is family %d, addr %08x, port %d\n",
                          rx_addr.sin_family,
                          rx_addr.sin_addr.s_addr,
                          rx_addr.sin_port );
             show_bootp( intf, received );
 #endif            
+            if ( length <= 0 )
+                break;
             if ( CHECK_XID() )          // not the same transaction;
                 break;                  // listen again...
 
@@ -947,11 +936,10 @@ do_dhcp(const char *intf, struct bootp *
             // cleared, as per the RFC.  We need the copy because these fields are
             // still useful to us (and currently stored in the 'result' structure)
             xlen = dhcp_size_for_send(xmit);
-            if ((xmit2 = _dhcp_copy(xmit, xlen)) == (struct bootp *)NULL) {
-                *pstate = DHCPSTATE_FAILED;
-                break;
-            }
-            if(sendto(s, xmit2, xlen, 0, 
+            bcopy( xmit, &xmit2, xlen );
+            xmit2.bp_yiaddr.s_addr = xmit2.bp_siaddr.s_addr = xmit2.bp_giaddr.s_addr = 0;
+            xmit2.bp_hops = 0;
+            if(sendto(s, &xmit2, xlen, 0,
                        // UNICAST address of the server:
                       (struct sockaddr *)&server_addr,
                       sizeof(server_addr)) < 0) {
@@ -985,15 +973,20 @@ do_dhcp(const char *intf, struct bootp *
                 *pstate = DHCPSTATE_RENEWING;
                 break;
             }
-
+            // Check for well-formed packet with correct termination (not truncated)
+            length = dhcp_size( received );
 #ifdef CYGDBG_NET_DHCP_CHATTER
             diag_printf( "---------DHCPSTATE_RENEW_RECV received:\n" );
+            if ( length <= 0 )
+                diag_printf( "WARNING! malformed or truncated packet\n" );
             diag_printf( "...rx_addr is family %d, addr %08x, port %d\n",
                          rx_addr.sin_family,
                          rx_addr.sin_addr.s_addr,
                          rx_addr.sin_port );
             show_bootp( intf, received );
 #endif            
+            if ( length <= 0 )
+                break;
             if ( CHECK_XID() )          // not the same transaction;
                 break;                  // listen again...
 
@@ -1052,12 +1045,11 @@ do_dhcp(const char *intf, struct bootp *
             // Send back a [modified] copy.  Note that some fields are explicitly
             // cleared, as per the RFC.  We need the copy because these fields are
             // still useful to us (and currently stored in the 'result' structure)
-            xlen = dhcp_size_for_send(xmit);
-            if ((xmit2 = _dhcp_copy(xmit, xlen)) == (struct bootp *)NULL) {
-                *pstate = DHCPSTATE_FAILED;
-                break;
-            }
-            if(sendto(s, xmit2, xlen, 0, 
+            xlen = dhcp_size_for_send( xmit );
+            bcopy( xmit, &xmit2, xlen );
+            xmit2.bp_yiaddr.s_addr = xmit2.bp_siaddr.s_addr = xmit2.bp_giaddr.s_addr = 0;
+            xmit2.bp_hops = 0;
+            if(sendto(s, &xmit2, xlen, 0, 
                       (struct sockaddr *)&broadcast_addr, sizeof(broadcast_addr)) < 0) {
                 *pstate = DHCPSTATE_FAILED;
                 break;
@@ -1089,15 +1081,20 @@ do_dhcp(const char *intf, struct bootp *
                 *pstate = DHCPSTATE_REBINDING;
                 break;
             }
-
+            // Check for well-formed packet with correct termination (not truncated)
+            length = dhcp_size( received );
 #ifdef CYGDBG_NET_DHCP_CHATTER
             diag_printf( "---------DHCPSTATE_REBIND_RECV received:\n" );
+            if ( length <= 0 )
+                diag_printf( "WARNING! malformed or truncated packet\n" );
             diag_printf( "...rx_addr is family %d, addr %08x, port %d\n",
                          rx_addr.sin_family,
                          rx_addr.sin_addr.s_addr,
                          rx_addr.sin_port );
             show_bootp( intf, received );
 #endif            
+            if ( length <= 0 )
+                break;
             if ( CHECK_XID() )          // not the same transaction;
                 break;                  // listen again...
 
@@ -1201,12 +1198,11 @@ do_dhcp(const char *intf, struct bootp *
             // Send back a [modified] copy.  Note that some fields are explicitly
             // cleared, as per the RFC.  We need the copy because these fields are
             // still useful to us (and currently stored in the 'result' structure)
-            xlen = dhcp_size_for_send(xmit);
-            if ((xmit2 = _dhcp_copy(xmit, xlen)) == (struct bootp *)NULL) {
-                *pstate = DHCPSTATE_FAILED;
-                break;
-            }
-            if(sendto(s, xmit2, xlen, 0, 
+            xlen = dhcp_size_for_send( xmit );
+            bcopy( xmit, &xmit2, xlen );
+            xmit2.bp_yiaddr.s_addr = xmit2.bp_siaddr.s_addr = xmit2.bp_giaddr.s_addr = 0;
+            xmit2.bp_hops = 0;
+            if(sendto(s, &xmit2, xlen, 0, 
                        // UNICAST address of the server:
                       (struct sockaddr *)&server_addr,
                       sizeof(server_addr)) < 0) {
@@ -1222,11 +1218,6 @@ do_dhcp(const char *intf, struct bootp *
             close(s);
             return false;
         }
-        // Clean up temporary buffer(s)
-        if (xmit2) {
-            cyg_net_free(xmit2, 0);
-            xmit2 = (struct bootp *)NULL;
-        }
     }
     /* NOTREACHED */
     return false;