ISC DHCP  4.3.3
A reference DHCPv4 and DHCPv6 implementation
packet.c
Go to the documentation of this file.
1 /* packet.c
2 
3  Packet assembly code, originally contributed by Archie Cobbs. */
4 
5 /*
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
9  *
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.
13  *
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.
21  *
22  * Internet Systems Consortium, Inc.
23  * 950 Charter Street
24  * Redwood City, CA 94063
25  * <info@isc.org>
26  * https://www.isc.org/
27  *
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
32  * still be disabled.
33  */
34 
35 #include "dhcpd.h"
36 
37 #if defined (PACKET_ASSEMBLY) || defined (PACKET_DECODING)
38 #include "includes/netinet/ip.h"
39 #include "includes/netinet/udp.h"
41 #endif /* PACKET_ASSEMBLY || PACKET_DECODING */
42 
43 /* Compute the easy part of the checksum on a range of bytes. */
44 
45 u_int32_t checksum (buf, nbytes, sum)
46  unsigned char *buf;
47  unsigned nbytes;
48  u_int32_t sum;
49 {
50  unsigned i;
51 
52 #ifdef DEBUG_CHECKSUM
53  log_debug ("checksum (%x %d %x)", buf, nbytes, sum);
54 #endif
55 
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);
60 #endif
61  sum += (u_int16_t) ntohs(*((u_int16_t *)(buf + i)));
62  /* Add carry. */
63  if (sum > 0xFFFF)
64  sum -= 0xFFFF;
65  }
66 
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. */
69  if (i < nbytes) {
70 #ifdef DEBUG_CHECKSUM_VERBOSE
71  log_debug ("sum = %x", sum);
72 #endif
73  sum += buf [i] << 8;
74  /* Add carry. */
75  if (sum > 0xFFFF)
76  sum -= 0xFFFF;
77  }
78 
79  return sum;
80 }
81 
82 /* Finish computing the checksum, and then put it into network byte order. */
83 
84 u_int32_t wrapsum (sum)
85  u_int32_t sum;
86 {
87 #ifdef DEBUG_CHECKSUM
88  log_debug ("wrapsum (%x)", sum);
89 #endif
90 
91  sum = ~sum & 0xFFFF;
92 #ifdef DEBUG_CHECKSUM_VERBOSE
93  log_debug ("sum = %x", sum);
94 #endif
95 
96 #ifdef DEBUG_CHECKSUM
97  log_debug ("wrapsum returns %x", htons (sum));
98 #endif
99  return htons(sum);
100 }
101 
102 #ifdef PACKET_ASSEMBLY
103 void assemble_hw_header (interface, buf, bufix, to)
104  struct interface_info *interface;
105  unsigned char *buf;
106  unsigned *bufix;
107  struct hardware *to;
108 {
109  switch (interface->hw_address.hbuf[0]) {
110 #if defined(HAVE_TR_SUPPORT)
111  case HTYPE_IEEE802:
112  assemble_tr_header(interface, buf, bufix, to);
113  break;
114 #endif
115 #if defined (DEC_FDDI)
116  case HTYPE_FDDI:
117  assemble_fddi_header(interface, buf, bufix, to);
118  break;
119 #endif
120  case HTYPE_INFINIBAND:
121  log_error("Attempt to assemble hw header for infiniband");
122  break;
123  case HTYPE_ETHER:
124  default:
125  assemble_ethernet_header(interface, buf, bufix, to);
126  break;
127  }
128 }
129 
130 /* UDP header and IP header assembled together for convenience. */
131 
132 void assemble_udp_ip_header (interface, buf, bufix,
133  from, to, port, data, len)
134  struct interface_info *interface;
135  unsigned char *buf;
136  unsigned *bufix;
137  u_int32_t from;
138  u_int32_t to;
139  u_int32_t port;
140  unsigned char *data;
141  unsigned len;
142 {
143  struct ip ip;
144  struct udphdr udp;
145 
146  memset (&ip, 0, sizeof ip);
147 
148  /* Fill out the IP header */
149  IP_V_SET (&ip, 4);
150  IP_HL_SET (&ip, 20);
152  ip.ip_len = htons(sizeof(ip) + sizeof(udp) + len);
153  ip.ip_id = 0;
154  ip.ip_off = 0;
155  ip.ip_ttl = 128;
156  ip.ip_p = IPPROTO_UDP;
157  ip.ip_sum = 0;
158  ip.ip_src.s_addr = from;
159  ip.ip_dst.s_addr = to;
160 
161  /* Checksum the IP header... */
162  ip.ip_sum = wrapsum (checksum ((unsigned char *)&ip, sizeof ip, 0));
163 
164  /* Copy the ip header into the buffer... */
165  memcpy (&buf [*bufix], &ip, sizeof ip);
166  *bufix += sizeof ip;
167 
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);
173 
174  /* Compute UDP checksums, including the ``pseudo-header'', the UDP
175  header and the data. */
176 
177  udp.uh_sum =
178  wrapsum (checksum ((unsigned char *)&udp, sizeof udp,
179  checksum (data, len,
180  checksum ((unsigned char *)
181  &ip.ip_src,
182  2 * sizeof ip.ip_src,
183  IPPROTO_UDP +
184  (u_int32_t)
185  ntohs (udp.uh_ulen)))));
186 
187  /* Copy the udp header into the buffer... */
188  memcpy (&buf [*bufix], &udp, sizeof udp);
189  *bufix += sizeof udp;
190 }
191 #endif /* PACKET_ASSEMBLY */
192 
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
197  */
198 
199 ssize_t decode_hw_header (interface, buf, bufix, from)
200  struct interface_info *interface;
201  unsigned char *buf;
202  unsigned bufix;
203  struct hardware *from;
204 {
205  switch(interface->hw_address.hbuf[0]) {
206 #if defined (HAVE_TR_SUPPORT)
207  case HTYPE_IEEE802:
208  return (decode_tr_header(interface, buf, bufix, from));
209 #endif
210 #if defined (DEC_FDDI)
211  case HTYPE_FDDI:
212  return (decode_fddi_header(interface, buf, bufix, from));
213 #endif
214  case HTYPE_INFINIBAND:
215  log_error("Attempt to decode hw header for infiniband");
216  return (0);
217  case HTYPE_ETHER:
218  default:
219  return (decode_ethernet_header(interface, buf, bufix, from));
220  }
221 }
222 
223 /* UDP header and IP header decoded together for convenience. */
224 
225 ssize_t
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)
230 {
231  unsigned char *data;
232  struct ip ip;
233  struct udphdr udp;
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;
242  unsigned len;
243 
244  /* Designate the end of the input buffer for bounds checks. */
245  endbuf = buf + bufix + buflen;
246 
247  /* Assure there is at least an IP header there. */
248  if ((buf + bufix + sizeof(ip)) > endbuf)
249  return -1;
250 
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.
254  */
255  upp = buf + bufix;
256  memcpy(&ip, upp, sizeof(ip));
257  ip_len = (*upp & 0x0f) << 2;
258  upp += ip_len;
259 
260  /* Check the IP packet length. */
261  pkt_len = ntohs(ip.ip_len);
262  if (pkt_len > buflen)
263  return -1;
264 
265  /* Assure after ip_len bytes that there is enough room for a UDP header. */
266  if ((upp + sizeof(udp)) > endbuf)
267  return -1;
268 
269  /* Copy the UDP header into a stack aligned structure for inspection. */
270  memcpy(&udp, upp, sizeof(udp));
271 
272 #ifdef USERLAND_FILTER
273  /* Is it a UDP packet? */
274  if (ip.ip_p != IPPROTO_UDP)
275  return -1;
276 
277  /* Is it to the port we're serving? */
278  if (udp.uh_dport != local_port)
279  return -1;
280 #endif /* USERLAND_FILTER */
281 
282  ulen = ntohs(udp.uh_ulen);
283  if (ulen < sizeof(udp))
284  return -1;
285 
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;
297  }
298  return -1;
299  }
300 
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;
305  }
306 
307  /* Check the IP header checksum - it should be zero. */
308  ip_packets_seen++;
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;
316  }
317  return -1;
318  }
319 
320  /* If at least 5 with less than 50% bad, start over */
321  if (ip_packets_seen > 4) {
322  ip_packets_bad_checksum = 0;
323  ip_packets_seen = 0;
324  }
325 
326  /* Copy out the IP source address... */
327  memcpy(&from->sin_addr, &ip.ip_src, 4);
328 
329  data = upp + sizeof(udp);
330  len = ulen - sizeof(udp);
331 
332  /* UDP check sum may be optional (udp.uh_sum == 0) or not ready if checksum
333  * offloading is in use */
334  udp_packets_seen++;
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),
340  checksum(data, len,
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;
349  }
350 
351  return -1;
352  }
353  }
354 
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;
359  }
360 
361  /* Copy out the port... */
362  memcpy (&from -> sin_port, &udp.uh_sport, sizeof udp.uh_sport);
363 
364  /* Save the length of the UDP payload. */
365  if (rbuflen != NULL)
366  *rbuflen = len;
367 
368  /* Return the index to the UDP payload. */
369  return ip_len + sizeof udp;
370 }
371 #endif /* PACKET_DECODING */
void assemble_ethernet_header(struct interface_info *, unsigned char *, unsigned *, struct hardware *)
void assemble_udp_ip_header(struct interface_info *, unsigned char *, unsigned *, u_int32_t, u_int32_t, u_int32_t, unsigned char *, unsigned)
ssize_t decode_udp_ip_header(struct interface_info *, unsigned char *, unsigned, struct sockaddr_in *, unsigned, unsigned *, int)
ssize_t decode_tr_header(struct interface_info *, unsigned char *, unsigned, struct hardware *)
int int int log_debug(const char *,...) __attribute__((__format__(__printf__
struct in_addr ip_src ip_dst
Definition: ip.h:59
void assemble_tr_header(struct interface_info *, unsigned char *, unsigned *, struct hardware *)
u_int8_t ip_ttl
Definition: ip.h:56
int log_error(const char *,...) __attribute__((__format__(__printf__
u_int32_t wrapsum(u_int32_t sum)
Definition: packet.c:84
u_int8_t ip_tos
Definition: ip.h:49
#define HTYPE_ETHER
Definition: dhcp.h:76
int16_t ip_off
Definition: ip.h:52
#define HTYPE_INFINIBAND
Definition: dhcp.h:79
Definition: udp.h:61
u_int16_t local_port
Definition: dhclient.c:88
void assemble_hw_header(struct interface_info *, unsigned char *, unsigned *, struct hardware *)
Definition: ip.h:47
#define IP_HL_SET(iph, x)
Definition: ip.h:65
int int log_info(const char *,...) __attribute__((__format__(__printf__
ssize_t decode_ethernet_header(struct interface_info *, unsigned char *, unsigned, struct hardware *)
int16_t ip_len
Definition: ip.h:50
#define HTYPE_FDDI
Definition: dhcp.h:78
#define IPTOS_LOWDELAY
Definition: ip.h:73
u_int16_t ip_sum
Definition: ip.h:58
#define HTYPE_IEEE802
Definition: dhcp.h:77
ssize_t decode_hw_header(struct interface_info *, unsigned char *, unsigned, struct hardware *)
u_int16_t ip_id
Definition: ip.h:51
u_int8_t ip_p
Definition: ip.h:57
#define IP_V_SET(iph, x)
Definition: ip.h:64
u_int32_t checksum(unsigned char *buf, unsigned nbytes, u_int32_t sum)
Definition: packet.c:45