3 Packet assembly code, originally contributed by Archie Cobbs. */
6 * Copyright (c) 2009,2012,2014 by Internet Systems Consortium, Inc. ("ISC")
7 * Copyright (c) 2004,2005,2007 by Internet Systems Consortium, Inc. ("ISC")
8 * Copyright (c) 1996-2003 by Internet Software Consortium
10 * Permission to use, copy, modify, and distribute this software for any
11 * purpose with or without fee is hereby granted, provided that the above
12 * copyright notice and this permission notice appear in all copies.
14 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
15 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
16 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
17 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
18 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
19 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
20 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
22 * Internet Systems Consortium, Inc.
24 * Redwood City, CA 94063
26 * https://www.isc.org/
28 * This code was originally contributed by Archie Cobbs, and is still
29 * very similar to that contribution, although the packet checksum code
30 * has been hacked significantly with the help of quite a few ISC DHCP
31 * users, without whose gracious and thorough help the checksum code would
37 #if defined (PACKET_ASSEMBLY) || defined (PACKET_DECODING)
38 #include "includes/netinet/ip.h"
39 #include "includes/netinet/udp.h"
40 #include "includes/netinet/if_ether.h"
41 #endif /* PACKET_ASSEMBLY || PACKET_DECODING */
43 /* Compute the easy part of the checksum on a range of bytes. */
45 u_int32_t
checksum (buf
, nbytes
, sum
)
53 log_debug ("checksum (%x %d %x)", buf
, nbytes
, sum
);
56 /* Checksum all the pairs of bytes first... */
57 for (i
= 0; i
< (nbytes
& ~1U); i
+= 2) {
58 #ifdef DEBUG_CHECKSUM_VERBOSE
59 log_debug ("sum = %x", sum
);
61 sum
+= (u_int16_t
) ntohs(*((u_int16_t
*)(buf
+ i
)));
67 /* If there's a single byte left over, checksum it, too. Network
68 byte order is big-endian, so the remaining byte is the high byte. */
70 #ifdef DEBUG_CHECKSUM_VERBOSE
71 log_debug ("sum = %x", sum
);
82 /* Finish computing the checksum, and then put it into network byte order. */
84 u_int32_t
wrapsum (sum
)
88 log_debug ("wrapsum (%x)", sum
);
92 #ifdef DEBUG_CHECKSUM_VERBOSE
93 log_debug ("sum = %x", sum
);
97 log_debug ("wrapsum returns %x", htons (sum
));
102 #ifdef PACKET_ASSEMBLY
103 void assemble_hw_header (interface
, buf
, bufix
, to
)
104 struct interface_info
*interface
;
109 switch (interface
->hw_address
.hbuf
[0]) {
110 #if defined(HAVE_TR_SUPPORT)
112 assemble_tr_header(interface
, buf
, bufix
, to
);
115 #if defined (DEC_FDDI)
117 assemble_fddi_header(interface
, buf
, bufix
, to
);
120 case HTYPE_INFINIBAND
:
121 log_error("Attempt to assemble hw header for infiniband");
125 assemble_ethernet_header(interface
, buf
, bufix
, to
);
130 /* UDP header and IP header assembled together for convenience. */
132 void assemble_udp_ip_header (interface
, buf
, bufix
,
133 from
, to
, port
, data
, len
)
134 struct interface_info
*interface
;
146 memset (&ip
, 0, sizeof ip
);
148 /* Fill out the IP header */
151 ip
.ip_tos
= IPTOS_LOWDELAY
;
152 ip
.ip_len
= htons(sizeof(ip
) + sizeof(udp
) + len
);
156 ip
.ip_p
= IPPROTO_UDP
;
158 ip
.ip_src
.s_addr
= from
;
159 ip
.ip_dst
.s_addr
= to
;
161 /* Checksum the IP header... */
162 ip
.ip_sum
= wrapsum (checksum ((unsigned char *)&ip
, sizeof ip
, 0));
164 /* Copy the ip header into the buffer... */
165 memcpy (&buf
[*bufix
], &ip
, sizeof ip
);
168 /* Fill out the UDP header */
169 udp
.uh_sport
= local_port
; /* XXX */
170 udp
.uh_dport
= port
; /* XXX */
171 udp
.uh_ulen
= htons(sizeof(udp
) + len
);
172 memset (&udp
.uh_sum
, 0, sizeof udp
.uh_sum
);
174 /* Compute UDP checksums, including the ``pseudo-header'', the UDP
175 header and the data. */
178 wrapsum (checksum ((unsigned char *)&udp
, sizeof udp
,
180 checksum ((unsigned char *)
182 2 * sizeof ip
.ip_src
,
185 ntohs (udp
.uh_ulen
)))));
187 /* Copy the udp header into the buffer... */
188 memcpy (&buf
[*bufix
], &udp
, sizeof udp
);
189 *bufix
+= sizeof udp
;
191 #endif /* PACKET_ASSEMBLY */
193 #ifdef PACKET_DECODING
194 /* Decode a hardware header... */
195 /* Support for ethernet, TR and FDDI
196 * Doesn't support infiniband yet as the supported oses shouldn't get here
199 ssize_t
decode_hw_header (interface
, buf
, bufix
, from
)
200 struct interface_info
*interface
;
203 struct hardware
*from
;
205 switch(interface
->hw_address
.hbuf
[0]) {
206 #if defined (HAVE_TR_SUPPORT)
208 return (decode_tr_header(interface
, buf
, bufix
, from
));
210 #if defined (DEC_FDDI)
212 return (decode_fddi_header(interface
, buf
, bufix
, from
));
214 case HTYPE_INFINIBAND
:
215 log_error("Attempt to decode hw header for infiniband");
219 return (decode_ethernet_header(interface
, buf
, bufix
, from
));
223 /* UDP header and IP header decoded together for convenience. */
226 decode_udp_ip_header(struct interface_info
*interface
,
227 unsigned char *buf
, unsigned bufix
,
228 struct sockaddr_in
*from
, unsigned buflen
,
229 unsigned *rbuflen
, int csum_ready
)
234 unsigned char *upp
, *endbuf
;
235 u_int32_t ip_len
, ulen
, pkt_len
;
236 static unsigned int ip_packets_seen
= 0;
237 static unsigned int ip_packets_bad_checksum
= 0;
238 static unsigned int udp_packets_seen
= 0;
239 static unsigned int udp_packets_bad_checksum
= 0;
240 static unsigned int udp_packets_length_checked
= 0;
241 static unsigned int udp_packets_length_overflow
= 0;
244 /* Designate the end of the input buffer for bounds checks. */
245 endbuf
= buf
+ bufix
+ buflen
;
247 /* Assure there is at least an IP header there. */
248 if ((buf
+ bufix
+ sizeof(ip
)) > endbuf
)
251 /* Copy the IP header into a stack aligned structure for inspection.
252 * There may be bits in the IP header that we're not decoding, so we
253 * copy out the bits we grok and skip ahead by ip.ip_hl * 4.
256 memcpy(&ip
, upp
, sizeof(ip
));
257 ip_len
= (*upp
& 0x0f) << 2;
260 /* Check the IP packet length. */
261 pkt_len
= ntohs(ip
.ip_len
);
262 if (pkt_len
> buflen
)
265 /* Assure after ip_len bytes that there is enough room for a UDP header. */
266 if ((upp
+ sizeof(udp
)) > endbuf
)
269 /* Copy the UDP header into a stack aligned structure for inspection. */
270 memcpy(&udp
, upp
, sizeof(udp
));
272 #ifdef USERLAND_FILTER
273 /* Is it a UDP packet? */
274 if (ip
.ip_p
!= IPPROTO_UDP
)
277 /* Is it to the port we're serving? */
278 if (udp
.uh_dport
!= local_port
)
280 #endif /* USERLAND_FILTER */
282 ulen
= ntohs(udp
.uh_ulen
);
283 if (ulen
< sizeof(udp
))
286 udp_packets_length_checked
++;
287 if ((upp
+ ulen
) > endbuf
) {
288 udp_packets_length_overflow
++;
289 if (((udp_packets_length_checked
> 4) &&
290 (udp_packets_length_overflow
!= 0)) &&
291 ((udp_packets_length_checked
/ udp_packets_length_overflow
) < 2)) {
292 log_info("%u udp packets in %u too long - dropped",
293 udp_packets_length_overflow
,
294 udp_packets_length_checked
);
295 udp_packets_length_overflow
= 0;
296 udp_packets_length_checked
= 0;
301 /* If at least 5 with less than 50% bad, start over */
302 if (udp_packets_length_checked
> 4) {
303 udp_packets_length_overflow
= 0;
304 udp_packets_length_checked
= 0;
307 /* Check the IP header checksum - it should be zero. */
309 if (wrapsum (checksum (buf
+ bufix
, ip_len
, 0))) {
310 ++ip_packets_bad_checksum
;
311 if (((ip_packets_seen
> 4) && (ip_packets_bad_checksum
!= 0)) &&
312 ((ip_packets_seen
/ ip_packets_bad_checksum
) < 2)) {
313 log_info ("%u bad IP checksums seen in %u packets",
314 ip_packets_bad_checksum
, ip_packets_seen
);
315 ip_packets_seen
= ip_packets_bad_checksum
= 0;
320 /* If at least 5 with less than 50% bad, start over */
321 if (ip_packets_seen
> 4) {
322 ip_packets_bad_checksum
= 0;
326 /* Copy out the IP source address... */
327 memcpy(&from
->sin_addr
, &ip
.ip_src
, 4);
329 data
= upp
+ sizeof(udp
);
330 len
= ulen
- sizeof(udp
);
332 /* UDP check sum may be optional (udp.uh_sum == 0) or not ready if checksum
333 * offloading is in use */
335 if (udp
.uh_sum
&& csum_ready
) {
336 /* Check the UDP header checksum - since the received packet header
337 * contains the UDP checksum calculated by the transmitter, calculating
338 * it now should come out to zero. */
339 if (wrapsum(checksum((unsigned char *)&udp
, sizeof(udp
),
341 checksum((unsigned char *)&ip
.ip_src
,
342 8, IPPROTO_UDP
+ ulen
))))) {
343 udp_packets_bad_checksum
++;
344 if (((udp_packets_seen
> 4) && (udp_packets_bad_checksum
!= 0))
345 && ((udp_packets_seen
/ udp_packets_bad_checksum
) < 2)) {
346 log_info ("%u bad udp checksums in %u packets",
347 udp_packets_bad_checksum
, udp_packets_seen
);
348 udp_packets_seen
= udp_packets_bad_checksum
= 0;
355 /* If at least 5 with less than 50% bad, start over */
356 if (udp_packets_seen
> 4) {
357 udp_packets_bad_checksum
= 0;
358 udp_packets_seen
= 0;
361 /* Copy out the port... */
362 memcpy (&from
-> sin_port
, &udp
.uh_sport
, sizeof udp
.uh_sport
);
364 /* Save the length of the UDP payload. */
368 /* Return the index to the UDP payload. */
369 return ip_len
+ sizeof udp
;
371 #endif /* PACKET_DECODING */