3 Packet assembly code, originally contributed by Archie Cobbs. */
6 * Copyright (c) 1996-2002 Internet Software Consortium.
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. Neither the name of The Internet Software Consortium nor the names
19 * of its contributors may be used to endorse or promote products derived
20 * from this software without specific prior written permission.
22 * THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM AND
23 * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
24 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
25 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
26 * DISCLAIMED. IN NO EVENT SHALL THE INTERNET SOFTWARE CONSORTIUM OR
27 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
28 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
29 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
30 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
31 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
32 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
33 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36 * This code was originally contributed by Archie Cobbs, and is still
37 * very similar to that contribution, although the packet checksum code
38 * has been hacked significantly with the help of quite a few ISC DHCP
39 * users, without whose gracious and thorough help the checksum code would
44 static char copyright[] =
45 "$Id: packet.c,v 1.40.2.2 2002/11/17 02:26:59 dhankins Exp $ Copyright (c) 1996-2002 The Internet Software Consortium. All rights reserved.\n";
50 #if defined (PACKET_ASSEMBLY) || defined (PACKET_DECODING)
51 #include "includes/netinet/ip.h"
52 #include "includes/netinet/udp.h"
53 #include "includes/netinet/if_ether.h"
54 #endif /* PACKET_ASSEMBLY || PACKET_DECODING */
56 /* Compute the easy part of the checksum on a range of bytes. */
58 u_int32_t checksum (buf, nbytes, sum)
66 log_debug ("checksum (%x %d %x)", buf, nbytes, sum);
69 /* Checksum all the pairs of bytes first... */
70 for (i = 0; i < (nbytes & ~1U); i += 2) {
71 #ifdef DEBUG_CHECKSUM_VERBOSE
72 log_debug ("sum = %x", sum);
74 sum += (u_int16_t) ntohs(*((u_int16_t *)(buf + i)));
80 /* If there's a single byte left over, checksum it, too. Network
81 byte order is big-endian, so the remaining byte is the high byte. */
83 #ifdef DEBUG_CHECKSUM_VERBOSE
84 log_debug ("sum = %x", sum);
95 /* Finish computing the checksum, and then put it into network byte order. */
97 u_int32_t wrapsum (sum)
100 #ifdef DEBUG_CHECKSUM
101 log_debug ("wrapsum (%x)", sum);
105 #ifdef DEBUG_CHECKSUM_VERBOSE
106 log_debug ("sum = %x", sum);
109 #ifdef DEBUG_CHECKSUM
110 log_debug ("wrapsum returns %x", htons (sum));
115 #ifdef PACKET_ASSEMBLY
116 void assemble_hw_header (interface, buf, bufix, to)
117 struct interface_info *interface;
122 #if defined (HAVE_TR_SUPPORT)
123 if (interface -> hw_address.hbuf [0] == HTYPE_IEEE802)
124 assemble_tr_header (interface, buf, bufix, to);
127 #if defined (DEC_FDDI)
128 if (interface -> hw_address.hbuf [0] == HTYPE_FDDI)
129 assemble_fddi_header (interface, buf, bufix, to);
132 assemble_ethernet_header (interface, buf, bufix, to);
136 /* UDP header and IP header assembled together for convenience. */
138 void assemble_udp_ip_header (interface, buf, bufix,
139 from, to, port, data, len)
140 struct interface_info *interface;
152 /* Fill out the IP header */
155 ip.ip_tos = IPTOS_LOWDELAY;
156 ip.ip_len = htons(sizeof(ip) + sizeof(udp) + len);
160 ip.ip_p = IPPROTO_UDP;
162 ip.ip_src.s_addr = from;
163 ip.ip_dst.s_addr = to;
165 /* Checksum the IP header... */
166 ip.ip_sum = wrapsum (checksum ((unsigned char *)&ip, sizeof ip, 0));
168 /* Copy the ip header into the buffer... */
169 memcpy (&buf [*bufix], &ip, sizeof ip);
172 /* Fill out the UDP header */
173 udp.uh_sport = local_port; /* XXX */
174 udp.uh_dport = port; /* XXX */
175 udp.uh_ulen = htons(sizeof(udp) + len);
176 memset (&udp.uh_sum, 0, sizeof udp.uh_sum);
178 /* Compute UDP checksums, including the ``pseudo-header'', the UDP
179 header and the data. */
182 wrapsum (checksum ((unsigned char *)&udp, sizeof udp,
184 checksum ((unsigned char *)
186 2 * sizeof ip.ip_src,
189 ntohs (udp.uh_ulen)))));
191 /* Copy the udp header into the buffer... */
192 memcpy (&buf [*bufix], &udp, sizeof udp);
193 *bufix += sizeof udp;
195 #endif /* PACKET_ASSEMBLY */
197 #ifdef PACKET_DECODING
198 /* Decode a hardware header... */
199 /* XXX currently only supports ethernet; doesn't check for other types. */
201 ssize_t decode_hw_header (interface, buf, bufix, from)
202 struct interface_info *interface;
205 struct hardware *from;
207 #if defined (HAVE_TR_SUPPORT)
208 if (interface -> hw_address.hbuf [0] == HTYPE_IEEE802)
209 return decode_tr_header (interface, buf, bufix, from);
212 #if defined (DEC_FDDI)
213 if (interface -> hw_address.hbuf [0] == HTYPE_FDDI)
214 return decode_fddi_header (interface, buf, bufix, from);
217 return decode_ethernet_header (interface, buf, bufix, from);
220 /* UDP header and IP header decoded together for convenience. */
222 ssize_t decode_udp_ip_header (interface, buf, bufix, from, data, buflen)
223 struct interface_info *interface;
226 struct sockaddr_in *from;
232 u_int32_t ip_len = (buf [bufix] & 0xf) << 2;
234 static int ip_packets_seen;
235 static int ip_packets_bad_checksum;
236 static int udp_packets_seen;
237 static int udp_packets_bad_checksum;
238 static int udp_packets_length_checked;
239 static int udp_packets_length_overflow;
244 ip = (struct ip *)(buf + bufix);
245 udp = (struct udphdr *)(buf + bufix + ip_len);
247 #ifdef USERLAND_FILTER
248 /* Is it a UDP packet? */
249 if (ip -> ip_p != IPPROTO_UDP)
252 /* Is it to the port we're serving? */
253 if (udp -> uh_dport != local_port)
255 #endif /* USERLAND_FILTER */
257 ulen = ntohs (udp -> uh_ulen);
258 if (ulen < sizeof *udp ||
259 ((unsigned char *)udp) + ulen > buf + bufix + buflen) {
260 log_info ("bogus UDP packet length: %d", ulen);
264 /* Check the IP header checksum - it should be zero. */
266 if (wrapsum (checksum (buf + bufix, ip_len, 0))) {
267 ++ip_packets_bad_checksum;
268 if (ip_packets_seen > 4 &&
269 (ip_packets_seen / ip_packets_bad_checksum) < 2) {
270 log_info ("%d bad IP checksums seen in %d packets",
271 ip_packets_bad_checksum, ip_packets_seen);
272 ip_packets_seen = ip_packets_bad_checksum = 0;
277 /* Check the IP packet length. */
278 if (ntohs (ip -> ip_len) != buflen) {
279 if ((ntohs (ip -> ip_len + 2) & ~1) == buflen)
282 log_debug ("ip length %d disagrees with bytes received %d.",
283 ntohs (ip -> ip_len), buflen);
286 /* Copy out the IP source address... */
287 memcpy (&from -> sin_addr, &ip -> ip_src, 4);
289 /* Compute UDP checksums, including the ``pseudo-header'', the UDP
290 header and the data. If the UDP checksum field is zero, we're
291 not supposed to do a checksum. */
294 data = buf + bufix + ip_len + sizeof *udp;
295 len = ulen - sizeof *udp;
296 ++udp_packets_length_checked;
297 if (len + data > buf + bufix + buflen) {
298 ++udp_packets_length_overflow;
299 if (udp_packets_length_checked > 4 &&
300 (udp_packets_length_checked /
301 udp_packets_length_overflow) < 2) {
302 log_info ("%d udp packets in %d too long - dropped",
303 udp_packets_length_overflow,
304 udp_packets_length_checked);
305 udp_packets_length_overflow =
306 udp_packets_length_checked = 0;
310 if (len + data < buf + bufix + buflen &&
311 len + data != buf + bufix + buflen && !ignore)
312 log_debug ("accepting packet with data after udp payload.");
313 if (len + data > buf + bufix + buflen) {
314 log_debug ("dropping packet with bogus uh_ulen %ld",
315 (long)(len + sizeof *udp));
320 usum = udp -> uh_sum;
323 sum = wrapsum (checksum ((unsigned char *)udp, sizeof *udp,
325 checksum ((unsigned char *)
327 2 * sizeof ip -> ip_src,
332 if (usum && usum != sum) {
333 udp_packets_bad_checksum++;
334 if (udp_packets_seen > 4 &&
335 (udp_packets_seen / udp_packets_bad_checksum) < 2) {
336 log_info ("%d bad udp checksums in %d packets",
337 udp_packets_bad_checksum, udp_packets_seen);
338 udp_packets_seen = udp_packets_bad_checksum = 0;
343 /* Copy out the port... */
344 memcpy (&from -> sin_port, &udp -> uh_sport, sizeof udp -> uh_sport);
346 return ip_len + sizeof *udp;
348 #endif /* PACKET_DECODING */