diff options
Diffstat (limited to 'usr.sbin/dhcp/common/packet.c')
-rw-r--r-- | usr.sbin/dhcp/common/packet.c | 136 |
1 files changed, 66 insertions, 70 deletions
diff --git a/usr.sbin/dhcp/common/packet.c b/usr.sbin/dhcp/common/packet.c index 5b136c394ff..499f20cb1bf 100644 --- a/usr.sbin/dhcp/common/packet.c +++ b/usr.sbin/dhcp/common/packet.c @@ -3,7 +3,7 @@ Packet assembly code, originally contributed by Archie Cobbs. */ /* - * Copyright (c) 1995, 1996 The Internet Software Consortium. + * Copyright (c) 1995, 1996, 1999 The Internet Software Consortium. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -40,18 +40,11 @@ * Enterprises, see ``http://www.vix.com''. */ -#ifndef lint -static char copyright[] = -"$Id: packet.c,v 1.3 2001/01/14 23:01:19 angelos Exp $ Copyright (c) 1996 The Internet Software Consortium. All rights reserved.\n"; -#endif /* not lint */ - #include "dhcpd.h" -#if defined (PACKET_ASSEMBLY) || defined (PACKET_DECODING) -#include "includes/netinet/ip.h" -#include "includes/netinet/udp.h" -#include "includes/netinet/if_ether.h" -#endif /* PACKET_ASSEMBLY || PACKET_DECODING */ +#include <netinet/in_systm.h> +#include <netinet/ip.h> +#include <netinet/udp.h> /* Compute the easy part of the checksum on a range of bytes. */ @@ -60,7 +53,7 @@ u_int32_t checksum (buf, nbytes, sum) unsigned nbytes; u_int32_t sum; { - unsigned i; + int i; #ifdef DEBUG_CHECKSUM debug ("checksum (%x %d %x)", buf, nbytes, sum); @@ -92,7 +85,7 @@ u_int32_t checksum (buf, nbytes, sum) return sum; } -/* Finish computing the checksum, and then put it into network byte order. */ +/* Finish computing the sum, and then put it into network byte order. */ u_int32_t wrapsum (sum) u_int32_t sum; @@ -103,7 +96,7 @@ u_int32_t wrapsum (sum) sum = ~sum & 0xFFFF; #ifdef DEBUG_CHECKSUM_VERBOSE - log_debug ("sum = %x", sum); + debug ("sum = %x", sum); #endif #ifdef DEBUG_CHECKSUM @@ -112,7 +105,6 @@ u_int32_t wrapsum (sum) return htons(sum); } -#ifdef PACKET_ASSEMBLY /* Assemble an hardware header... */ /* XXX currently only supports ethernet; doesn't check for other types. */ @@ -122,26 +114,13 @@ void assemble_hw_header (interface, buf, bufix, to) int *bufix; struct hardware *to; { - struct ether_header eh; - - if (to && to -> hlen == 6) /* XXX */ - memcpy (eh.ether_dhost, to -> haddr, sizeof eh.ether_dhost); - else - memset (eh.ether_dhost, 0xff, sizeof (eh.ether_dhost)); - if (interface -> hw_address.hlen == sizeof (eh.ether_shost)) - memcpy (eh.ether_shost, interface -> hw_address.haddr, - sizeof (eh.ether_shost)); +#if defined (HAVE_TR_SUPPORT) + if (interface -> hw_address.htype == HTYPE_IEEE802) + assemble_tr_header (interface, buf, bufix, to); else - memset (eh.ether_shost, 0x00, sizeof (eh.ether_shost)); - -#ifdef BROKEN_FREEBSD_BPF /* Fixed in FreeBSD 2.2 */ - eh.ether_type = ETHERTYPE_IP; -#else - eh.ether_type = htons (ETHERTYPE_IP); #endif + assemble_ethernet_header (interface, buf, bufix, to); - memcpy (&buf [*bufix], &eh, sizeof eh); - *bufix += sizeof eh; } /* UDP header and IP header assembled together for convenience. */ @@ -153,7 +132,7 @@ void assemble_udp_ip_header (interface, buf, bufix, int *bufix; u_int32_t from; u_int32_t to; - u_int16_t port; + unsigned int port; unsigned char *data; int len; { @@ -189,7 +168,6 @@ void assemble_udp_ip_header (interface, buf, bufix, /* Compute UDP checksums, including the ``pseudo-header'', the UDP header and the data. */ -#if 1 udp.uh_sum = wrapsum (checksum ((unsigned char *)&udp, sizeof udp, checksum (data, len, @@ -199,17 +177,13 @@ void assemble_udp_ip_header (interface, buf, bufix, IPPROTO_UDP + (u_int32_t) ntohs (udp.uh_ulen))))); -#endif /* Copy the udp header into the buffer... */ memcpy (&buf [*bufix], &udp, sizeof udp); *bufix += sizeof udp; } -#endif /* PACKET_ASSEMBLY */ -#ifdef PACKET_DECODING /* Decode a hardware header... */ -/* XXX currently only supports ethernet; doesn't check for other types. */ ssize_t decode_hw_header (interface, buf, bufix, from) struct interface_info *interface; @@ -217,55 +191,57 @@ ssize_t decode_hw_header (interface, buf, bufix, from) int bufix; struct hardware *from; { - struct ether_header eh; - - memcpy (&eh, buf + bufix, sizeof eh); - -#ifdef USERLAND_FILTER - if (ntohs (eh.ether_type) != ETHERTYPE_IP) - return -1; +#if defined (HAVE_TR_SUPPORT) + if (interface -> hw_address.htype == HTYPE_IEEE802) + return decode_tr_header (interface, buf, bufix, from); + else #endif - memcpy (from -> haddr, eh.ether_shost, sizeof (eh.ether_shost)); - from -> htype = ARPHRD_ETHER; - from -> hlen = sizeof eh.ether_shost; - - return sizeof eh; + return decode_ethernet_header (interface, buf, bufix, from); } /* UDP header and IP header decoded together for convenience. */ -ssize_t decode_udp_ip_header (interface, buf, bufix, from, data, len) +ssize_t decode_udp_ip_header (interface, buf, bufix, from, data, buflen) struct interface_info *interface; unsigned char *buf; int bufix; struct sockaddr_in *from; unsigned char *data; - int len; + int buflen; { struct ip *ip; struct udphdr *udp; u_int32_t ip_len = (buf [bufix] & 0xf) << 2; + u_int32_t sum, usum; + static int ip_packets_seen; + static int ip_packets_bad_checksum; + static int udp_packets_seen; + static int udp_packets_bad_checksum; + static int udp_packets_length_checked; + static int udp_packets_length_overflow; + int len = 0; ip = (struct ip *)(buf + bufix); udp = (struct udphdr *)(buf + bufix + ip_len); -#ifdef USERLAND_FILTER - /* Is it a UDP packet? */ - if (ip -> ip_p != IPPROTO_UDP) - return -1; - - /* Is it to the port we're serving? */ - if (udp -> uh_dport != local_port) - return -1; -#endif /* USERLAND_FILTER */ - /* Check the IP header checksum - it should be zero. */ + ++ip_packets_seen; if (wrapsum (checksum (buf + bufix, ip_len, 0))) { - note ("Bad IP checksum: %x", - wrapsum (checksum (buf + bufix, sizeof *ip, 0))); + ++ip_packets_bad_checksum; + if (ip_packets_seen > 4 && + (ip_packets_seen / ip_packets_bad_checksum) < 2) { + note ("%d bad IP checksums seen in %d packets", + ip_packets_bad_checksum, ip_packets_seen); + ip_packets_seen = ip_packets_bad_checksum = 0; + } return -1; } + /* Check the IP packet length. */ + if (ntohs (ip -> ip_len) != buflen) + debug ("ip length %d disagrees with bytes received %d.", + ntohs (ip -> ip_len), buflen); + /* Copy out the IP source address... */ memcpy (&from -> sin_addr, &ip -> ip_src, 4); @@ -275,10 +251,25 @@ ssize_t decode_udp_ip_header (interface, buf, bufix, from, data, len) if (!data) { data = buf + bufix + ip_len + sizeof *udp; - len -= ip_len + sizeof *udp; + len = ntohs (udp -> uh_ulen) - sizeof *udp; + ++udp_packets_length_checked; + if (len + data > buf + bufix + buflen) { + ++udp_packets_length_overflow; + if (udp_packets_length_checked > 4 && + (udp_packets_length_checked / + udp_packets_length_overflow) < 2) { + note ("%d udp packets in %d too long - dropped", + udp_packets_length_overflow, + udp_packets_length_checked); + udp_packets_length_overflow = + udp_packets_length_checked = 0; + } + return -1; + } + if (len + data != buf + bufix + buflen) + debug ("accepting packet with data after udp payload."); } -#if 0 usum = udp -> uh_sum; udp -> uh_sum = 0; @@ -286,20 +277,25 @@ ssize_t decode_udp_ip_header (interface, buf, bufix, from, data, len) checksum (data, len, checksum ((unsigned char *) &ip -> ip_src, - sizeof ip -> ip_src, + 2 * sizeof ip -> ip_src, IPPROTO_UDP + (u_int32_t) ntohs (udp -> uh_ulen))))); + udp_packets_seen++; if (usum && usum != sum) { - note ("Bad udp checksum: %x %x", usum, sum); + udp_packets_bad_checksum++; + if (udp_packets_seen > 4 && + (udp_packets_seen / udp_packets_bad_checksum) < 2) { + note ("%d bad udp checksums in %d packets", + udp_packets_bad_checksum, udp_packets_seen); + udp_packets_seen = udp_packets_bad_checksum = 0; + } return -1; } -#endif /* Copy out the port... */ memcpy (&from -> sin_port, &udp -> uh_sport, sizeof udp -> uh_sport); return ip_len + sizeof *udp; } -#endif /* PACKET_DECODING */ |