3 Packet assembly code, originally contributed by Archie Cobbs. */
6 * Copyright (c) 1996-2001 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.41 2001/06/27 00:29:55 mellon Exp $ Copyright (c) 1996-2001 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 */