3 Packet assembly code, originally contributed by Archie Cobbs. */
6 * Copyright (c) 2004-2005 by Internet Systems Consortium, Inc. ("ISC")
7 * Copyright (c) 1996-2003 by Internet Software Consortium
9 * Permission to use, copy, modify, and distribute this software for any
10 * purpose with or without fee is hereby granted, provided that the above
11 * copyright notice and this permission notice appear in all copies.
13 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
14 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
15 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
16 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
17 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
18 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
19 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
21 * Internet Systems Consortium, Inc.
23 * Redwood City, CA 94063
27 * This code was originally contributed by Archie Cobbs, and is still
28 * very similar to that contribution, although the packet checksum code
29 * has been hacked significantly with the help of quite a few ISC DHCP
30 * users, without whose gracious and thorough help the checksum code would
35 static char copyright
[] =
36 "$Id$ Copyright (c) 2004-2005 Internet Systems Consortium. All rights reserved.\n";
41 #if defined (PACKET_ASSEMBLY) || defined (PACKET_DECODING)
42 #include "includes/netinet/ip.h"
43 #include "includes/netinet/udp.h"
44 #include "includes/netinet/if_ether.h"
45 #endif /* PACKET_ASSEMBLY || PACKET_DECODING */
47 /* Compute the easy part of the checksum on a range of bytes. */
49 u_int32_t
checksum (buf
, nbytes
, sum
)
57 log_debug ("checksum (%x %d %x)", buf
, nbytes
, sum
);
60 /* Checksum all the pairs of bytes first... */
61 for (i
= 0; i
< (nbytes
& ~1U); i
+= 2) {
62 #ifdef DEBUG_CHECKSUM_VERBOSE
63 log_debug ("sum = %x", sum
);
65 sum
+= (u_int16_t
) ntohs(*((u_int16_t
*)(buf
+ i
)));
71 /* If there's a single byte left over, checksum it, too. Network
72 byte order is big-endian, so the remaining byte is the high byte. */
74 #ifdef DEBUG_CHECKSUM_VERBOSE
75 log_debug ("sum = %x", sum
);
86 /* Finish computing the checksum, and then put it into network byte order. */
88 u_int32_t
wrapsum (sum
)
92 log_debug ("wrapsum (%x)", sum
);
96 #ifdef DEBUG_CHECKSUM_VERBOSE
97 log_debug ("sum = %x", sum
);
100 #ifdef DEBUG_CHECKSUM
101 log_debug ("wrapsum returns %x", htons (sum
));
106 #ifdef PACKET_ASSEMBLY
107 void assemble_hw_header (interface
, buf
, bufix
, to
)
108 struct interface_info
*interface
;
113 #if defined (HAVE_TR_SUPPORT)
114 if (interface
-> hw_address
.hbuf
[0] == HTYPE_IEEE802
)
115 assemble_tr_header (interface
, buf
, bufix
, to
);
118 #if defined (DEC_FDDI)
119 if (interface
-> hw_address
.hbuf
[0] == HTYPE_FDDI
)
120 assemble_fddi_header (interface
, buf
, bufix
, to
);
123 assemble_ethernet_header (interface
, buf
, bufix
, to
);
127 /* UDP header and IP header assembled together for convenience. */
129 void assemble_udp_ip_header (interface
, buf
, bufix
,
130 from
, to
, port
, data
, len
)
131 struct interface_info
*interface
;
143 /* Fill out the IP header */
146 ip
.ip_tos
= IPTOS_LOWDELAY
;
147 ip
.ip_len
= htons(sizeof(ip
) + sizeof(udp
) + len
);
151 ip
.ip_p
= IPPROTO_UDP
;
153 ip
.ip_src
.s_addr
= from
;
154 ip
.ip_dst
.s_addr
= to
;
156 /* Checksum the IP header... */
157 ip
.ip_sum
= wrapsum (checksum ((unsigned char *)&ip
, sizeof ip
, 0));
159 /* Copy the ip header into the buffer... */
160 memcpy (&buf
[*bufix
], &ip
, sizeof ip
);
163 /* Fill out the UDP header */
164 udp
.uh_sport
= local_port
; /* XXX */
165 udp
.uh_dport
= port
; /* XXX */
166 udp
.uh_ulen
= htons(sizeof(udp
) + len
);
167 memset (&udp
.uh_sum
, 0, sizeof udp
.uh_sum
);
169 /* Compute UDP checksums, including the ``pseudo-header'', the UDP
170 header and the data. */
173 wrapsum (checksum ((unsigned char *)&udp
, sizeof udp
,
175 checksum ((unsigned char *)
177 2 * sizeof ip
.ip_src
,
180 ntohs (udp
.uh_ulen
)))));
182 /* Copy the udp header into the buffer... */
183 memcpy (&buf
[*bufix
], &udp
, sizeof udp
);
184 *bufix
+= sizeof udp
;
186 #endif /* PACKET_ASSEMBLY */
188 #ifdef PACKET_DECODING
189 /* Decode a hardware header... */
190 /* XXX currently only supports ethernet; doesn't check for other types. */
192 ssize_t
decode_hw_header (interface
, buf
, bufix
, from
)
193 struct interface_info
*interface
;
196 struct hardware
*from
;
198 #if defined (HAVE_TR_SUPPORT)
199 if (interface
-> hw_address
.hbuf
[0] == HTYPE_IEEE802
)
200 return decode_tr_header (interface
, buf
, bufix
, from
);
203 #if defined (DEC_FDDI)
204 if (interface
-> hw_address
.hbuf
[0] == HTYPE_FDDI
)
205 return decode_fddi_header (interface
, buf
, bufix
, from
);
208 return decode_ethernet_header (interface
, buf
, bufix
, from
);
211 /* UDP header and IP header decoded together for convenience. */
213 ssize_t
decode_udp_ip_header (interface
, buf
, bufix
, from
, buflen
)
214 struct interface_info
*interface
;
217 struct sockaddr_in
*from
;
223 u_int32_t ip_len
= (buf
[bufix
] & 0xf) << 2;
225 static int ip_packets_seen
;
226 static int ip_packets_bad_checksum
;
227 static int udp_packets_seen
;
228 static int udp_packets_bad_checksum
;
229 static int udp_packets_length_checked
;
230 static int udp_packets_length_overflow
;
235 memcpy(&ip
, buf
+ bufix
, sizeof (struct ip
));
236 udp
= (struct udphdr
*)(buf
+ bufix
+ ip_len
);
238 #ifdef USERLAND_FILTER
239 /* Is it a UDP packet? */
240 if (ip
.ip_p
!= IPPROTO_UDP
)
243 /* Is it to the port we're serving? */
244 if (udp
-> uh_dport
!= local_port
)
246 #endif /* USERLAND_FILTER */
248 ulen
= ntohs (udp
-> uh_ulen
);
249 if (ulen
< sizeof *udp
||
250 ((unsigned char *)udp
) + ulen
> buf
+ bufix
+ buflen
) {
251 log_info ("bogus UDP packet length: %d", ulen
);
255 /* Check the IP header checksum - it should be zero. */
257 if (wrapsum (checksum (buf
+ bufix
, ip_len
, 0))) {
258 ++ip_packets_bad_checksum
;
259 if (ip_packets_seen
> 4 &&
260 (ip_packets_seen
/ ip_packets_bad_checksum
) < 2) {
261 log_info ("%d bad IP checksums seen in %d packets",
262 ip_packets_bad_checksum
, ip_packets_seen
);
263 ip_packets_seen
= ip_packets_bad_checksum
= 0;
268 /* Check the IP packet length. */
269 if (ntohs (ip
.ip_len
) != buflen
) {
270 if ((ntohs (ip
.ip_len
+ 2) & ~1) == buflen
)
273 log_debug ("ip length %d disagrees with bytes received %d.",
274 ntohs (ip
.ip_len
), buflen
);
277 /* Copy out the IP source address... */
278 memcpy (&from
-> sin_addr
, &ip
.ip_src
, 4);
280 /* Compute UDP checksums, including the ``pseudo-header'', the UDP
281 header and the data. If the UDP checksum field is zero, we're
282 not supposed to do a checksum. */
284 data
= buf
+ bufix
+ ip_len
+ sizeof *udp
;
285 len
= ulen
- sizeof *udp
;
286 ++udp_packets_length_checked
;
287 if (len
+ data
> buf
+ bufix
+ buflen
) {
288 ++udp_packets_length_overflow
;
289 if (udp_packets_length_checked
> 4 &&
290 (udp_packets_length_checked
/
291 udp_packets_length_overflow
) < 2) {
292 log_info ("%d udp packets in %d too long - dropped",
293 udp_packets_length_overflow
,
294 udp_packets_length_checked
);
295 udp_packets_length_overflow
=
296 udp_packets_length_checked
= 0;
300 if (len
+ data
< buf
+ bufix
+ buflen
&&
301 len
+ data
!= buf
+ bufix
+ buflen
&& !ignore
)
302 log_debug ("accepting packet with data after udp payload.");
303 if (len
+ data
> buf
+ bufix
+ buflen
) {
304 log_debug ("dropping packet with bogus uh_ulen %ld",
305 (long)(len
+ sizeof *udp
));
309 usum
= udp
-> uh_sum
;
312 sum
= wrapsum (checksum ((unsigned char *)udp
, sizeof *udp
,
314 checksum ((unsigned char *)
316 2 * sizeof ip
.ip_src
,
321 if (usum
&& usum
!= sum
) {
322 udp_packets_bad_checksum
++;
323 if (udp_packets_seen
> 4 &&
324 (udp_packets_seen
/ udp_packets_bad_checksum
) < 2) {
325 log_info ("%d bad udp checksums in %d packets",
326 udp_packets_bad_checksum
, udp_packets_seen
);
327 udp_packets_seen
= udp_packets_bad_checksum
= 0;
332 /* Copy out the port... */
333 memcpy (&from
-> sin_port
, &udp
-> uh_sport
, sizeof udp
-> uh_sport
);
335 return ip_len
+ sizeof *udp
;
337 #endif /* PACKET_DECODING */