1*83ee113eSDavid van Moolenbroek /* $NetBSD: packet.c,v 1.1.1.4 2014/07/12 11:57:46 spz Exp $ */
2*83ee113eSDavid van Moolenbroek /* packet.c
3*83ee113eSDavid van Moolenbroek
4*83ee113eSDavid van Moolenbroek Packet assembly code, originally contributed by Archie Cobbs. */
5*83ee113eSDavid van Moolenbroek
6*83ee113eSDavid van Moolenbroek /*
7*83ee113eSDavid van Moolenbroek * Copyright (c) 2009,2012 by Internet Systems Consortium, Inc. ("ISC")
8*83ee113eSDavid van Moolenbroek * Copyright (c) 2004,2005,2007 by Internet Systems Consortium, Inc. ("ISC")
9*83ee113eSDavid van Moolenbroek * Copyright (c) 1996-2003 by Internet Software Consortium
10*83ee113eSDavid van Moolenbroek *
11*83ee113eSDavid van Moolenbroek * Permission to use, copy, modify, and distribute this software for any
12*83ee113eSDavid van Moolenbroek * purpose with or without fee is hereby granted, provided that the above
13*83ee113eSDavid van Moolenbroek * copyright notice and this permission notice appear in all copies.
14*83ee113eSDavid van Moolenbroek *
15*83ee113eSDavid van Moolenbroek * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
16*83ee113eSDavid van Moolenbroek * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
17*83ee113eSDavid van Moolenbroek * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
18*83ee113eSDavid van Moolenbroek * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
19*83ee113eSDavid van Moolenbroek * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
20*83ee113eSDavid van Moolenbroek * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
21*83ee113eSDavid van Moolenbroek * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
22*83ee113eSDavid van Moolenbroek *
23*83ee113eSDavid van Moolenbroek * Internet Systems Consortium, Inc.
24*83ee113eSDavid van Moolenbroek * 950 Charter Street
25*83ee113eSDavid van Moolenbroek * Redwood City, CA 94063
26*83ee113eSDavid van Moolenbroek * <info@isc.org>
27*83ee113eSDavid van Moolenbroek * https://www.isc.org/
28*83ee113eSDavid van Moolenbroek *
29*83ee113eSDavid van Moolenbroek * This code was originally contributed by Archie Cobbs, and is still
30*83ee113eSDavid van Moolenbroek * very similar to that contribution, although the packet checksum code
31*83ee113eSDavid van Moolenbroek * has been hacked significantly with the help of quite a few ISC DHCP
32*83ee113eSDavid van Moolenbroek * users, without whose gracious and thorough help the checksum code would
33*83ee113eSDavid van Moolenbroek * still be disabled.
34*83ee113eSDavid van Moolenbroek */
35*83ee113eSDavid van Moolenbroek
36*83ee113eSDavid van Moolenbroek #include <sys/cdefs.h>
37*83ee113eSDavid van Moolenbroek __RCSID("$NetBSD: packet.c,v 1.1.1.4 2014/07/12 11:57:46 spz Exp $");
38*83ee113eSDavid van Moolenbroek
39*83ee113eSDavid van Moolenbroek #include "dhcpd.h"
40*83ee113eSDavid van Moolenbroek
41*83ee113eSDavid van Moolenbroek #if defined (PACKET_ASSEMBLY) || defined (PACKET_DECODING)
42*83ee113eSDavid van Moolenbroek #include "includes/netinet/ip.h"
43*83ee113eSDavid van Moolenbroek #include "includes/netinet/udp.h"
44*83ee113eSDavid van Moolenbroek #include "includes/netinet/if_ether.h"
45*83ee113eSDavid van Moolenbroek #endif /* PACKET_ASSEMBLY || PACKET_DECODING */
46*83ee113eSDavid van Moolenbroek
47*83ee113eSDavid van Moolenbroek /* Compute the easy part of the checksum on a range of bytes. */
48*83ee113eSDavid van Moolenbroek
checksum(buf,nbytes,sum)49*83ee113eSDavid van Moolenbroek u_int32_t checksum (buf, nbytes, sum)
50*83ee113eSDavid van Moolenbroek unsigned char *buf;
51*83ee113eSDavid van Moolenbroek unsigned nbytes;
52*83ee113eSDavid van Moolenbroek u_int32_t sum;
53*83ee113eSDavid van Moolenbroek {
54*83ee113eSDavid van Moolenbroek unsigned i;
55*83ee113eSDavid van Moolenbroek
56*83ee113eSDavid van Moolenbroek #ifdef DEBUG_CHECKSUM
57*83ee113eSDavid van Moolenbroek log_debug ("checksum (%x %d %x)", buf, nbytes, sum);
58*83ee113eSDavid van Moolenbroek #endif
59*83ee113eSDavid van Moolenbroek
60*83ee113eSDavid van Moolenbroek /* Checksum all the pairs of bytes first... */
61*83ee113eSDavid van Moolenbroek for (i = 0; i < (nbytes & ~1U); i += 2) {
62*83ee113eSDavid van Moolenbroek #ifdef DEBUG_CHECKSUM_VERBOSE
63*83ee113eSDavid van Moolenbroek log_debug ("sum = %x", sum);
64*83ee113eSDavid van Moolenbroek #endif
65*83ee113eSDavid van Moolenbroek sum += (u_int16_t) ntohs(*((u_int16_t *)(buf + i)));
66*83ee113eSDavid van Moolenbroek /* Add carry. */
67*83ee113eSDavid van Moolenbroek if (sum > 0xFFFF)
68*83ee113eSDavid van Moolenbroek sum -= 0xFFFF;
69*83ee113eSDavid van Moolenbroek }
70*83ee113eSDavid van Moolenbroek
71*83ee113eSDavid van Moolenbroek /* If there's a single byte left over, checksum it, too. Network
72*83ee113eSDavid van Moolenbroek byte order is big-endian, so the remaining byte is the high byte. */
73*83ee113eSDavid van Moolenbroek if (i < nbytes) {
74*83ee113eSDavid van Moolenbroek #ifdef DEBUG_CHECKSUM_VERBOSE
75*83ee113eSDavid van Moolenbroek log_debug ("sum = %x", sum);
76*83ee113eSDavid van Moolenbroek #endif
77*83ee113eSDavid van Moolenbroek sum += buf [i] << 8;
78*83ee113eSDavid van Moolenbroek /* Add carry. */
79*83ee113eSDavid van Moolenbroek if (sum > 0xFFFF)
80*83ee113eSDavid van Moolenbroek sum -= 0xFFFF;
81*83ee113eSDavid van Moolenbroek }
82*83ee113eSDavid van Moolenbroek
83*83ee113eSDavid van Moolenbroek return sum;
84*83ee113eSDavid van Moolenbroek }
85*83ee113eSDavid van Moolenbroek
86*83ee113eSDavid van Moolenbroek /* Finish computing the checksum, and then put it into network byte order. */
87*83ee113eSDavid van Moolenbroek
wrapsum(sum)88*83ee113eSDavid van Moolenbroek u_int32_t wrapsum (sum)
89*83ee113eSDavid van Moolenbroek u_int32_t sum;
90*83ee113eSDavid van Moolenbroek {
91*83ee113eSDavid van Moolenbroek #ifdef DEBUG_CHECKSUM
92*83ee113eSDavid van Moolenbroek log_debug ("wrapsum (%x)", sum);
93*83ee113eSDavid van Moolenbroek #endif
94*83ee113eSDavid van Moolenbroek
95*83ee113eSDavid van Moolenbroek sum = ~sum & 0xFFFF;
96*83ee113eSDavid van Moolenbroek #ifdef DEBUG_CHECKSUM_VERBOSE
97*83ee113eSDavid van Moolenbroek log_debug ("sum = %x", sum);
98*83ee113eSDavid van Moolenbroek #endif
99*83ee113eSDavid van Moolenbroek
100*83ee113eSDavid van Moolenbroek #ifdef DEBUG_CHECKSUM
101*83ee113eSDavid van Moolenbroek log_debug ("wrapsum returns %x", htons (sum));
102*83ee113eSDavid van Moolenbroek #endif
103*83ee113eSDavid van Moolenbroek return htons(sum);
104*83ee113eSDavid van Moolenbroek }
105*83ee113eSDavid van Moolenbroek
106*83ee113eSDavid van Moolenbroek #ifdef PACKET_ASSEMBLY
assemble_hw_header(interface,buf,bufix,to)107*83ee113eSDavid van Moolenbroek void assemble_hw_header (interface, buf, bufix, to)
108*83ee113eSDavid van Moolenbroek struct interface_info *interface;
109*83ee113eSDavid van Moolenbroek unsigned char *buf;
110*83ee113eSDavid van Moolenbroek unsigned *bufix;
111*83ee113eSDavid van Moolenbroek struct hardware *to;
112*83ee113eSDavid van Moolenbroek {
113*83ee113eSDavid van Moolenbroek switch (interface->hw_address.hbuf[0]) {
114*83ee113eSDavid van Moolenbroek #if defined(HAVE_TR_SUPPORT)
115*83ee113eSDavid van Moolenbroek case HTYPE_IEEE802:
116*83ee113eSDavid van Moolenbroek assemble_tr_header(interface, buf, bufix, to);
117*83ee113eSDavid van Moolenbroek break;
118*83ee113eSDavid van Moolenbroek #endif
119*83ee113eSDavid van Moolenbroek #if defined (DEC_FDDI)
120*83ee113eSDavid van Moolenbroek case HTYPE_FDDI:
121*83ee113eSDavid van Moolenbroek assemble_fddi_header(interface, buf, bufix, to);
122*83ee113eSDavid van Moolenbroek break;
123*83ee113eSDavid van Moolenbroek #endif
124*83ee113eSDavid van Moolenbroek case HTYPE_INFINIBAND:
125*83ee113eSDavid van Moolenbroek log_error("Attempt to assemble hw header for infiniband");
126*83ee113eSDavid van Moolenbroek break;
127*83ee113eSDavid van Moolenbroek case HTYPE_ETHER:
128*83ee113eSDavid van Moolenbroek default:
129*83ee113eSDavid van Moolenbroek assemble_ethernet_header(interface, buf, bufix, to);
130*83ee113eSDavid van Moolenbroek break;
131*83ee113eSDavid van Moolenbroek }
132*83ee113eSDavid van Moolenbroek }
133*83ee113eSDavid van Moolenbroek
134*83ee113eSDavid van Moolenbroek /* UDP header and IP header assembled together for convenience. */
135*83ee113eSDavid van Moolenbroek
assemble_udp_ip_header(interface,buf,bufix,from,to,port,data,len)136*83ee113eSDavid van Moolenbroek void assemble_udp_ip_header (interface, buf, bufix,
137*83ee113eSDavid van Moolenbroek from, to, port, data, len)
138*83ee113eSDavid van Moolenbroek struct interface_info *interface;
139*83ee113eSDavid van Moolenbroek unsigned char *buf;
140*83ee113eSDavid van Moolenbroek unsigned *bufix;
141*83ee113eSDavid van Moolenbroek u_int32_t from;
142*83ee113eSDavid van Moolenbroek u_int32_t to;
143*83ee113eSDavid van Moolenbroek u_int32_t port;
144*83ee113eSDavid van Moolenbroek unsigned char *data;
145*83ee113eSDavid van Moolenbroek unsigned len;
146*83ee113eSDavid van Moolenbroek {
147*83ee113eSDavid van Moolenbroek struct ip ip;
148*83ee113eSDavid van Moolenbroek struct udphdr udp;
149*83ee113eSDavid van Moolenbroek
150*83ee113eSDavid van Moolenbroek memset (&ip, 0, sizeof ip);
151*83ee113eSDavid van Moolenbroek
152*83ee113eSDavid van Moolenbroek /* Fill out the IP header */
153*83ee113eSDavid van Moolenbroek IP_V_SET (&ip, 4);
154*83ee113eSDavid van Moolenbroek IP_HL_SET (&ip, 20);
155*83ee113eSDavid van Moolenbroek ip.ip_tos = IPTOS_LOWDELAY;
156*83ee113eSDavid van Moolenbroek ip.ip_len = htons(sizeof(ip) + sizeof(udp) + len);
157*83ee113eSDavid van Moolenbroek ip.ip_id = 0;
158*83ee113eSDavid van Moolenbroek ip.ip_off = 0;
159*83ee113eSDavid van Moolenbroek ip.ip_ttl = 128;
160*83ee113eSDavid van Moolenbroek ip.ip_p = IPPROTO_UDP;
161*83ee113eSDavid van Moolenbroek ip.ip_sum = 0;
162*83ee113eSDavid van Moolenbroek ip.ip_src.s_addr = from;
163*83ee113eSDavid van Moolenbroek ip.ip_dst.s_addr = to;
164*83ee113eSDavid van Moolenbroek
165*83ee113eSDavid van Moolenbroek /* Checksum the IP header... */
166*83ee113eSDavid van Moolenbroek ip.ip_sum = wrapsum (checksum ((unsigned char *)&ip, sizeof ip, 0));
167*83ee113eSDavid van Moolenbroek
168*83ee113eSDavid van Moolenbroek /* Copy the ip header into the buffer... */
169*83ee113eSDavid van Moolenbroek memcpy (&buf [*bufix], &ip, sizeof ip);
170*83ee113eSDavid van Moolenbroek *bufix += sizeof ip;
171*83ee113eSDavid van Moolenbroek
172*83ee113eSDavid van Moolenbroek /* Fill out the UDP header */
173*83ee113eSDavid van Moolenbroek udp.uh_sport = local_port; /* XXX */
174*83ee113eSDavid van Moolenbroek udp.uh_dport = port; /* XXX */
175*83ee113eSDavid van Moolenbroek udp.uh_ulen = htons(sizeof(udp) + len);
176*83ee113eSDavid van Moolenbroek memset (&udp.uh_sum, 0, sizeof udp.uh_sum);
177*83ee113eSDavid van Moolenbroek
178*83ee113eSDavid van Moolenbroek /* Compute UDP checksums, including the ``pseudo-header'', the UDP
179*83ee113eSDavid van Moolenbroek header and the data. */
180*83ee113eSDavid van Moolenbroek
181*83ee113eSDavid van Moolenbroek udp.uh_sum =
182*83ee113eSDavid van Moolenbroek wrapsum (checksum ((unsigned char *)&udp, sizeof udp,
183*83ee113eSDavid van Moolenbroek checksum (data, len,
184*83ee113eSDavid van Moolenbroek checksum ((unsigned char *)
185*83ee113eSDavid van Moolenbroek &ip.ip_src,
186*83ee113eSDavid van Moolenbroek 2 * sizeof ip.ip_src,
187*83ee113eSDavid van Moolenbroek IPPROTO_UDP +
188*83ee113eSDavid van Moolenbroek (u_int32_t)
189*83ee113eSDavid van Moolenbroek ntohs (udp.uh_ulen)))));
190*83ee113eSDavid van Moolenbroek
191*83ee113eSDavid van Moolenbroek /* Copy the udp header into the buffer... */
192*83ee113eSDavid van Moolenbroek memcpy (&buf [*bufix], &udp, sizeof udp);
193*83ee113eSDavid van Moolenbroek *bufix += sizeof udp;
194*83ee113eSDavid van Moolenbroek }
195*83ee113eSDavid van Moolenbroek #endif /* PACKET_ASSEMBLY */
196*83ee113eSDavid van Moolenbroek
197*83ee113eSDavid van Moolenbroek #ifdef PACKET_DECODING
198*83ee113eSDavid van Moolenbroek /* Decode a hardware header... */
199*83ee113eSDavid van Moolenbroek /* Support for ethernet, TR and FDDI
200*83ee113eSDavid van Moolenbroek * Doesn't support infiniband yet as the supported oses shouldn't get here
201*83ee113eSDavid van Moolenbroek */
202*83ee113eSDavid van Moolenbroek
decode_hw_header(interface,buf,bufix,from)203*83ee113eSDavid van Moolenbroek ssize_t decode_hw_header (interface, buf, bufix, from)
204*83ee113eSDavid van Moolenbroek struct interface_info *interface;
205*83ee113eSDavid van Moolenbroek unsigned char *buf;
206*83ee113eSDavid van Moolenbroek unsigned bufix;
207*83ee113eSDavid van Moolenbroek struct hardware *from;
208*83ee113eSDavid van Moolenbroek {
209*83ee113eSDavid van Moolenbroek switch(interface->hw_address.hbuf[0]) {
210*83ee113eSDavid van Moolenbroek #if defined (HAVE_TR_SUPPORT)
211*83ee113eSDavid van Moolenbroek case HTYPE_IEEE802:
212*83ee113eSDavid van Moolenbroek return (decode_tr_header(interface, buf, bufix, from));
213*83ee113eSDavid van Moolenbroek #endif
214*83ee113eSDavid van Moolenbroek #if defined (DEC_FDDI)
215*83ee113eSDavid van Moolenbroek case HTYPE_FDDI:
216*83ee113eSDavid van Moolenbroek return (decode_fddi_header(interface, buf, bufix, from));
217*83ee113eSDavid van Moolenbroek #endif
218*83ee113eSDavid van Moolenbroek case HTYPE_INFINIBAND:
219*83ee113eSDavid van Moolenbroek log_error("Attempt to decode hw header for infiniband");
220*83ee113eSDavid van Moolenbroek return (0);
221*83ee113eSDavid van Moolenbroek case HTYPE_ETHER:
222*83ee113eSDavid van Moolenbroek default:
223*83ee113eSDavid van Moolenbroek return (decode_ethernet_header(interface, buf, bufix, from));
224*83ee113eSDavid van Moolenbroek }
225*83ee113eSDavid van Moolenbroek }
226*83ee113eSDavid van Moolenbroek
227*83ee113eSDavid van Moolenbroek /* UDP header and IP header decoded together for convenience. */
228*83ee113eSDavid van Moolenbroek
229*83ee113eSDavid van Moolenbroek ssize_t
decode_udp_ip_header(struct interface_info * interface,unsigned char * buf,unsigned bufix,struct sockaddr_in * from,unsigned buflen,unsigned * rbuflen)230*83ee113eSDavid van Moolenbroek decode_udp_ip_header(struct interface_info *interface,
231*83ee113eSDavid van Moolenbroek unsigned char *buf, unsigned bufix,
232*83ee113eSDavid van Moolenbroek struct sockaddr_in *from, unsigned buflen,
233*83ee113eSDavid van Moolenbroek unsigned *rbuflen)
234*83ee113eSDavid van Moolenbroek {
235*83ee113eSDavid van Moolenbroek unsigned char *data;
236*83ee113eSDavid van Moolenbroek struct ip ip;
237*83ee113eSDavid van Moolenbroek struct udphdr udp;
238*83ee113eSDavid van Moolenbroek unsigned char *upp, *endbuf;
239*83ee113eSDavid van Moolenbroek u_int32_t ip_len, ulen, pkt_len;
240*83ee113eSDavid van Moolenbroek u_int32_t sum, usum;
241*83ee113eSDavid van Moolenbroek static int ip_packets_seen;
242*83ee113eSDavid van Moolenbroek static int ip_packets_bad_checksum;
243*83ee113eSDavid van Moolenbroek static int udp_packets_seen;
244*83ee113eSDavid van Moolenbroek static int udp_packets_bad_checksum;
245*83ee113eSDavid van Moolenbroek static int udp_packets_length_checked;
246*83ee113eSDavid van Moolenbroek static int udp_packets_length_overflow;
247*83ee113eSDavid van Moolenbroek unsigned len;
248*83ee113eSDavid van Moolenbroek
249*83ee113eSDavid van Moolenbroek /* Designate the end of the input buffer for bounds checks. */
250*83ee113eSDavid van Moolenbroek endbuf = buf + bufix + buflen;
251*83ee113eSDavid van Moolenbroek
252*83ee113eSDavid van Moolenbroek /* Assure there is at least an IP header there. */
253*83ee113eSDavid van Moolenbroek if ((buf + bufix + sizeof(ip)) > endbuf)
254*83ee113eSDavid van Moolenbroek return -1;
255*83ee113eSDavid van Moolenbroek
256*83ee113eSDavid van Moolenbroek /* Copy the IP header into a stack aligned structure for inspection.
257*83ee113eSDavid van Moolenbroek * There may be bits in the IP header that we're not decoding, so we
258*83ee113eSDavid van Moolenbroek * copy out the bits we grok and skip ahead by ip.ip_hl * 4.
259*83ee113eSDavid van Moolenbroek */
260*83ee113eSDavid van Moolenbroek upp = buf + bufix;
261*83ee113eSDavid van Moolenbroek memcpy(&ip, upp, sizeof(ip));
262*83ee113eSDavid van Moolenbroek ip_len = (*upp & 0x0f) << 2;
263*83ee113eSDavid van Moolenbroek upp += ip_len;
264*83ee113eSDavid van Moolenbroek
265*83ee113eSDavid van Moolenbroek /* Check the IP packet length. */
266*83ee113eSDavid van Moolenbroek pkt_len = ntohs(ip.ip_len);
267*83ee113eSDavid van Moolenbroek if (pkt_len > buflen)
268*83ee113eSDavid van Moolenbroek return -1;
269*83ee113eSDavid van Moolenbroek
270*83ee113eSDavid van Moolenbroek /* Assure after ip_len bytes that there is enough room for a UDP header. */
271*83ee113eSDavid van Moolenbroek if ((upp + sizeof(udp)) > endbuf)
272*83ee113eSDavid van Moolenbroek return -1;
273*83ee113eSDavid van Moolenbroek
274*83ee113eSDavid van Moolenbroek /* Copy the UDP header into a stack aligned structure for inspection. */
275*83ee113eSDavid van Moolenbroek memcpy(&udp, upp, sizeof(udp));
276*83ee113eSDavid van Moolenbroek
277*83ee113eSDavid van Moolenbroek #ifdef USERLAND_FILTER
278*83ee113eSDavid van Moolenbroek /* Is it a UDP packet? */
279*83ee113eSDavid van Moolenbroek if (ip.ip_p != IPPROTO_UDP)
280*83ee113eSDavid van Moolenbroek return -1;
281*83ee113eSDavid van Moolenbroek
282*83ee113eSDavid van Moolenbroek /* Is it to the port we're serving? */
283*83ee113eSDavid van Moolenbroek if (udp.uh_dport != local_port)
284*83ee113eSDavid van Moolenbroek return -1;
285*83ee113eSDavid van Moolenbroek #endif /* USERLAND_FILTER */
286*83ee113eSDavid van Moolenbroek
287*83ee113eSDavid van Moolenbroek ulen = ntohs(udp.uh_ulen);
288*83ee113eSDavid van Moolenbroek if (ulen < sizeof(udp))
289*83ee113eSDavid van Moolenbroek return -1;
290*83ee113eSDavid van Moolenbroek
291*83ee113eSDavid van Moolenbroek udp_packets_length_checked++;
292*83ee113eSDavid van Moolenbroek if ((upp + ulen) > endbuf) {
293*83ee113eSDavid van Moolenbroek udp_packets_length_overflow++;
294*83ee113eSDavid van Moolenbroek if ((udp_packets_length_checked > 4) &&
295*83ee113eSDavid van Moolenbroek ((udp_packets_length_checked /
296*83ee113eSDavid van Moolenbroek udp_packets_length_overflow) < 2)) {
297*83ee113eSDavid van Moolenbroek log_info("%d udp packets in %d too long - dropped",
298*83ee113eSDavid van Moolenbroek udp_packets_length_overflow,
299*83ee113eSDavid van Moolenbroek udp_packets_length_checked);
300*83ee113eSDavid van Moolenbroek udp_packets_length_overflow = 0;
301*83ee113eSDavid van Moolenbroek udp_packets_length_checked = 0;
302*83ee113eSDavid van Moolenbroek }
303*83ee113eSDavid van Moolenbroek return -1;
304*83ee113eSDavid van Moolenbroek }
305*83ee113eSDavid van Moolenbroek
306*83ee113eSDavid van Moolenbroek if ((ulen < sizeof(udp)) || ((upp + ulen) > endbuf))
307*83ee113eSDavid van Moolenbroek return -1;
308*83ee113eSDavid van Moolenbroek
309*83ee113eSDavid van Moolenbroek /* Check the IP header checksum - it should be zero. */
310*83ee113eSDavid van Moolenbroek ++ip_packets_seen;
311*83ee113eSDavid van Moolenbroek if (wrapsum (checksum (buf + bufix, ip_len, 0))) {
312*83ee113eSDavid van Moolenbroek ++ip_packets_bad_checksum;
313*83ee113eSDavid van Moolenbroek if (ip_packets_seen > 4 &&
314*83ee113eSDavid van Moolenbroek (ip_packets_seen / ip_packets_bad_checksum) < 2) {
315*83ee113eSDavid van Moolenbroek log_info ("%d bad IP checksums seen in %d packets",
316*83ee113eSDavid van Moolenbroek ip_packets_bad_checksum, ip_packets_seen);
317*83ee113eSDavid van Moolenbroek ip_packets_seen = ip_packets_bad_checksum = 0;
318*83ee113eSDavid van Moolenbroek }
319*83ee113eSDavid van Moolenbroek return -1;
320*83ee113eSDavid van Moolenbroek }
321*83ee113eSDavid van Moolenbroek
322*83ee113eSDavid van Moolenbroek /* Copy out the IP source address... */
323*83ee113eSDavid van Moolenbroek memcpy(&from->sin_addr, &ip.ip_src, 4);
324*83ee113eSDavid van Moolenbroek
325*83ee113eSDavid van Moolenbroek /* Compute UDP checksums, including the ``pseudo-header'', the UDP
326*83ee113eSDavid van Moolenbroek header and the data. If the UDP checksum field is zero, we're
327*83ee113eSDavid van Moolenbroek not supposed to do a checksum. */
328*83ee113eSDavid van Moolenbroek
329*83ee113eSDavid van Moolenbroek data = upp + sizeof(udp);
330*83ee113eSDavid van Moolenbroek len = ulen - sizeof(udp);
331*83ee113eSDavid van Moolenbroek
332*83ee113eSDavid van Moolenbroek usum = udp.uh_sum;
333*83ee113eSDavid van Moolenbroek udp.uh_sum = 0;
334*83ee113eSDavid van Moolenbroek
335*83ee113eSDavid van Moolenbroek /* XXX: We have to pass &udp, because we have to zero the checksum
336*83ee113eSDavid van Moolenbroek * field before calculating the sum...'upp' isn't zeroed.
337*83ee113eSDavid van Moolenbroek */
338*83ee113eSDavid van Moolenbroek sum = wrapsum(checksum((unsigned char *)&udp, sizeof(udp),
339*83ee113eSDavid van Moolenbroek checksum(data, len,
340*83ee113eSDavid van Moolenbroek checksum((unsigned char *)&ip.ip_src,
341*83ee113eSDavid van Moolenbroek 8, IPPROTO_UDP + ulen))));
342*83ee113eSDavid van Moolenbroek
343*83ee113eSDavid van Moolenbroek udp_packets_seen++;
344*83ee113eSDavid van Moolenbroek if (usum && usum != sum) {
345*83ee113eSDavid van Moolenbroek udp_packets_bad_checksum++;
346*83ee113eSDavid van Moolenbroek if (udp_packets_seen > 4 &&
347*83ee113eSDavid van Moolenbroek (udp_packets_seen / udp_packets_bad_checksum) < 2) {
348*83ee113eSDavid van Moolenbroek log_info ("%d bad udp checksums in %d packets",
349*83ee113eSDavid van Moolenbroek udp_packets_bad_checksum, udp_packets_seen);
350*83ee113eSDavid van Moolenbroek udp_packets_seen = udp_packets_bad_checksum = 0;
351*83ee113eSDavid van Moolenbroek }
352*83ee113eSDavid van Moolenbroek return -1;
353*83ee113eSDavid van Moolenbroek }
354*83ee113eSDavid van Moolenbroek
355*83ee113eSDavid van Moolenbroek /* Copy out the port... */
356*83ee113eSDavid van Moolenbroek memcpy (&from -> sin_port, &udp.uh_sport, sizeof udp.uh_sport);
357*83ee113eSDavid van Moolenbroek
358*83ee113eSDavid van Moolenbroek /* Save the length of the UDP payload. */
359*83ee113eSDavid van Moolenbroek if (rbuflen != NULL)
360*83ee113eSDavid van Moolenbroek *rbuflen = len;
361*83ee113eSDavid van Moolenbroek
362*83ee113eSDavid van Moolenbroek /* Return the index to the UDP payload. */
363*83ee113eSDavid van Moolenbroek return ip_len + sizeof udp;
364*83ee113eSDavid van Moolenbroek }
365*83ee113eSDavid van Moolenbroek #endif /* PACKET_DECODING */
366