]> git.ipfire.org Git - thirdparty/dhcp.git/commitdiff
[v4_1_esv] Tidy up bpf processing
authorShawn Routhier <sar@isc.org>
Sat, 25 Jan 2014 04:08:39 +0000 (20:08 -0800)
committerShawn Routhier <sar@isc.org>
Sat, 25 Jan 2014 04:08:39 +0000 (20:08 -0800)
Make bpf processing a bit better so we properly
process broken packets and their successors

RELNOTES
common/bpf.c

index 092ba94ef34075f24afb576f3fa07645fa70dd29..81113d77e8c4417f8e6461075ed78f41fb3a71c2 100644 (file)
--- a/RELNOTES
+++ b/RELNOTES
@@ -57,6 +57,12 @@ ISC DHCP is open source software maintained by Internet Systems
 Consortium.  This product includes cryptographic software written
 by Eric Young (eay@cryptsoft.com).
 
+                       Changes since 4.1-ESV-R9b1
+
+- Tidy up receive packet processing.
+  Thanks to Brad Plank of GTA for reporting the issue and suggesting
+  a possible patch.
+  [ISC-Bugs #34447]
                        Changes since 4.1-ESV-R8
 
 - Modify the server code to only prohibit the administrator from configuring
index a9681bb1ed8ad5240aeca76d54452aced0fa9c8f..79abfe2b9b5eb7756b2122c77c7f32552f9abd12 100644 (file)
@@ -3,7 +3,7 @@
    BPF socket interface code, originally contributed by Archie Cobbs. */
 
 /*
- * Copyright (c) 2004,2007,2009 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 2004,2007,2009,2014 by Internet Systems Consortium, Inc. ("ISC")
  * Copyright (c) 1996-2003 by Internet Software Consortium
  *
  * Permission to use, copy, modify, and distribute this software for any
@@ -405,45 +405,43 @@ ssize_t receive_packet (interface, buf, len, from, hfrom)
        /* Process packets until we get one we can return or until we've
           done a read and gotten nothing we can return... */
 
-       do {
-               /* If the buffer is empty, fill it. */
-               if (interface -> rbuf_offset == interface -> rbuf_len) {
-                       length = read (interface -> rfdesc,
-                                      interface -> rbuf,
-                                      (size_t)interface -> rbuf_max);
-                       if (length <= 0) {
+       /* If the buffer is empty, fill it. */
+       if (interface->rbuf_offset >= interface->rbuf_len) {
+               length = read(interface->rfdesc, interface->rbuf,
+                             (size_t)interface->rbuf_max);
+               if (length <= 0) {
 #ifdef __FreeBSD__
-                               if (errno == ENXIO) {
+                       if (errno == ENXIO) {
 #else
-                               if (errno == EIO) {
+                       if (errno == EIO) {
 #endif
-                                       dhcp_interface_remove
-                                               ((omapi_object_t *)interface,
-                                                (omapi_object_t *)0);
-                               }
-                               return length;
+                               dhcp_interface_remove
+                                       ((omapi_object_t *)interface, NULL);
                        }
-                       interface -> rbuf_offset = 0;
-                       interface -> rbuf_len = BPF_WORDALIGN (length);
+                       return (length);
                }
+               interface->rbuf_offset = 0;
+               interface->rbuf_len = BPF_WORDALIGN(length);
+       }
 
+       do {
                /* If there isn't room for a whole bpf header, something went
                   wrong, but we'll ignore it and hope it goes away... XXX */
-               if (interface -> rbuf_len -
-                   interface -> rbuf_offset < sizeof hdr) {
-                       interface -> rbuf_offset = interface -> rbuf_len;
+               if (interface->rbuf_len -
+                   interface->rbuf_offset < sizeof hdr) {
+                       interface->rbuf_offset = interface->rbuf_len;
                        continue;
                }
 
                /* Copy out a bpf header... */
-               memcpy (&hdr, &interface -> rbuf [interface -> rbuf_offset],
-                       sizeof hdr);
+               memcpy(&hdr, &interface->rbuf[interface->rbuf_offset],
+                      sizeof hdr);
 
                /* If the bpf header plus data doesn't fit in what's left
                   of the buffer, stick head in sand yet again... */
-               if (interface -> rbuf_offset +
-                   hdr.bh_hdrlen + hdr.bh_caplen > interface -> rbuf_len) {
-                       interface -> rbuf_offset = interface -> rbuf_len;
+               if (interface->rbuf_offset +
+                   hdr.bh_hdrlen + hdr.bh_caplen > interface->rbuf_len) {
+                       interface->rbuf_offset = interface->rbuf_len;
                        continue;
                }
 
@@ -451,67 +449,64 @@ ssize_t receive_packet (interface, buf, len, from, hfrom)
                   the packet won't fit in the input buffer, all we
                   can do is drop it. */
                if (hdr.bh_caplen != hdr.bh_datalen) {
-                       interface -> rbuf_offset =
-                               BPF_WORDALIGN (interface -> rbuf_offset +
-                                              hdr.bh_hdrlen + hdr.bh_caplen);
+                       interface->rbuf_offset =
+                               BPF_WORDALIGN(interface->rbuf_offset +
+                                             hdr.bh_hdrlen + hdr.bh_caplen);
                        continue;
                }
 
                /* Skip over the BPF header... */
-               interface -> rbuf_offset += hdr.bh_hdrlen;
+               interface->rbuf_offset += hdr.bh_hdrlen;
 
                /* Decode the physical header... */
-               offset = decode_hw_header (interface,
-                                          interface -> rbuf,
-                                          interface -> rbuf_offset,
-                                          hfrom);
+               offset = decode_hw_header(interface, interface->rbuf,
+                                         interface->rbuf_offset, hfrom);
 
                /* If a physical layer checksum failed (dunno of any
                   physical layer that supports this, but WTH), skip this
                   packet. */
                if (offset < 0) {
-                       interface -> rbuf_offset = 
-                               BPF_WORDALIGN (interface -> rbuf_offset +
-                                              hdr.bh_caplen);
+                       interface->rbuf_offset = 
+                               BPF_WORDALIGN(interface->rbuf_offset +
+                                             hdr.bh_caplen);
                        continue;
                }
-               interface -> rbuf_offset += offset;
+               interface->rbuf_offset += offset;
                hdr.bh_caplen -= offset;
 
                /* Decode the IP and UDP headers... */
-               offset = decode_udp_ip_header (interface,
-                                              interface -> rbuf,
-                                              interface -> rbuf_offset,
+               offset = decode_udp_ip_header(interface, interface->rbuf,
+                                              interface->rbuf_offset,
                                               from, hdr.bh_caplen, &paylen);
 
                /* If the IP or UDP checksum was bad, skip the packet... */
                if (offset < 0) {
-                       interface -> rbuf_offset = 
-                               BPF_WORDALIGN (interface -> rbuf_offset +
-                                              hdr.bh_caplen);
+                       interface->rbuf_offset = 
+                               BPF_WORDALIGN(interface->rbuf_offset +
+                                             hdr.bh_caplen);
                        continue;
                }
-               interface -> rbuf_offset = interface -> rbuf_offset + offset;
+               interface->rbuf_offset = interface->rbuf_offset + offset;
                hdr.bh_caplen -= offset;
 
                /* If there's not enough room to stash the packet data,
                   we have to skip it (this shouldn't happen in real
                   life, though). */
                if (hdr.bh_caplen > len) {
-                       interface -> rbuf_offset =
-                               BPF_WORDALIGN (interface -> rbuf_offset +
+                       interface->rbuf_offset =
+                               BPF_WORDALIGN(interface->rbuf_offset +
                                               hdr.bh_caplen);
                        continue;
                }
 
                /* Copy out the data in the packet... */
                memcpy(buf, interface->rbuf + interface->rbuf_offset, paylen);
-               interface -> rbuf_offset =
-                       BPF_WORDALIGN (interface -> rbuf_offset +
-                                      hdr.bh_caplen);
+               interface->rbuf_offset =
+                       BPF_WORDALIGN(interface->rbuf_offset + hdr.bh_caplen);
                return paylen;
-       } while (!length);
-       return 0;
+       } while (interface->rbuf_offset < interface->rbuf_len);
+
+       return (0);
 }
 
 int can_unicast_without_arp (ip)