ISC DHCP  4.4.2-P1
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) 2004-2017 by Internet Systems Consortium, Inc. ("ISC")
7  * Copyright (c) 1996-2003 by Internet Software Consortium
8  *
9  * This Source Code Form is subject to the terms of the Mozilla Public
10  * License, v. 2.0. If a copy of the MPL was not distributed with this
11  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
12  *
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.
20  *
21  * Internet Systems Consortium, Inc.
22  * 950 Charter Street
23  * Redwood City, CA 94063
24  * <info@isc.org>
25  * https://www.isc.org/
26  *
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
31  * still be disabled.
32  */
33 
34 #include "dhcpd.h"
35 
36 #if defined (PACKET_ASSEMBLY) || defined (PACKET_DECODING)
37 #include "includes/netinet/ip.h"
38 #include "includes/netinet/udp.h"
40 #endif /* PACKET_ASSEMBLY || PACKET_DECODING */
41 
42 /* Compute the easy part of the checksum on a range of bytes. */
43 
44 u_int32_t checksum (buf, nbytes, sum)
45  unsigned char *buf;
46  unsigned nbytes;
47  u_int32_t sum;
48 {
49  unsigned i;
50 
51 #ifdef DEBUG_CHECKSUM
52  log_debug ("checksum (%x %d %x)", (unsigned)buf, nbytes, sum);
53 #endif
54 
55  /* Checksum all the pairs of bytes first... */
56  for (i = 0; i < (nbytes & ~1U); i += 2) {
57 #ifdef DEBUG_CHECKSUM_VERBOSE
58  log_debug ("sum = %x", sum);
59 #endif
60  sum += (u_int16_t) ntohs(*((u_int16_t *)(buf + i)));
61  /* Add carry. */
62  if (sum > 0xFFFF)
63  sum -= 0xFFFF;
64  }
65 
66  /* If there's a single byte left over, checksum it, too. Network
67  byte order is big-endian, so the remaining byte is the high byte. */
68  if (i < nbytes) {
69 #ifdef DEBUG_CHECKSUM_VERBOSE
70  log_debug ("sum = %x", sum);
71 #endif
72  sum += buf [i] << 8;
73  /* Add carry. */
74  if (sum > 0xFFFF)
75  sum -= 0xFFFF;
76  }
77 
78  return sum;
79 }
80 
81 /* Finish computing the checksum, and then put it into network byte order. */
82 
83 u_int32_t wrapsum (sum)
84  u_int32_t sum;
85 {
86 #ifdef DEBUG_CHECKSUM
87  log_debug ("wrapsum (%x)", sum);
88 #endif
89 
90  sum = ~sum & 0xFFFF;
91 #ifdef DEBUG_CHECKSUM_VERBOSE
92  log_debug ("sum = %x", sum);
93 #endif
94 
95 #ifdef DEBUG_CHECKSUM
96  log_debug ("wrapsum returns %x", htons (sum));
97 #endif
98  return htons(sum);
99 }
100 
101 #ifdef PACKET_ASSEMBLY
102 void assemble_hw_header (interface, buf, bufix, to)
103  struct interface_info *interface;
104  unsigned char *buf;
105  unsigned *bufix;
106  struct hardware *to;
107 {
108  switch (interface->hw_address.hbuf[0]) {
109 #if defined(HAVE_TR_SUPPORT)
110  case HTYPE_IEEE802:
111  assemble_tr_header(interface, buf, bufix, to);
112  break;
113 #endif
114 #if defined (DEC_FDDI)
115  case HTYPE_FDDI:
116  assemble_fddi_header(interface, buf, bufix, to);
117  break;
118 #endif
119  case HTYPE_INFINIBAND:
120  log_error("Attempt to assemble hw header for infiniband");
121  break;
122  case HTYPE_ETHER:
123  default:
124  assemble_ethernet_header(interface, buf, bufix, to);
125  break;
126  }
127 }
128 
129 /* UDP header and IP header assembled together for convenience. */
130 
131 void assemble_udp_ip_header (interface, buf, bufix,
132  from, to, port, data, len)
133  struct interface_info *interface;
134  unsigned char *buf;
135  unsigned *bufix;
136  u_int32_t from;
137  u_int32_t to;
138  u_int32_t port;
139  unsigned char *data;
140  unsigned len;
141 {
142  struct ip ip;
143  struct udphdr udp;
144 
145  memset (&ip, 0, sizeof ip);
146 
147  /* Fill out the IP header */
148  IP_V_SET (&ip, 4);
149  IP_HL_SET (&ip, 20);
151  ip.ip_len = htons(sizeof(ip) + sizeof(udp) + len);
152  ip.ip_id = 0;
153  ip.ip_off = 0;
154  ip.ip_ttl = 128;
155  ip.ip_p = IPPROTO_UDP;
156  ip.ip_sum = 0;
157  ip.ip_src.s_addr = from;
158  ip.ip_dst.s_addr = to;
159 
160  /* Checksum the IP header... */
161  ip.ip_sum = wrapsum (checksum ((unsigned char *)&ip, sizeof ip, 0));
162 
163  /* Copy the ip header into the buffer... */
164  memcpy (&buf [*bufix], &ip, sizeof ip);
165  *bufix += sizeof ip;
166 
167  /* Fill out the UDP header */
168  udp.uh_sport = local_port; /* XXX */
169  udp.uh_dport = port; /* XXX */
170 #if defined(RELAY_PORT)
171  /* Change to relay port defined if sending to server */
172  if (relay_port && (port == htons(67))) {
173  udp.uh_sport = relay_port;
174  }
175 #endif
176  udp.uh_ulen = htons(sizeof(udp) + len);
177  memset (&udp.uh_sum, 0, sizeof udp.uh_sum);
178 
179  /* Compute UDP checksums, including the ``pseudo-header'', the UDP
180  header and the data. */
181 
182  udp.uh_sum =
183  wrapsum (checksum ((unsigned char *)&udp, sizeof udp,
184  checksum (data, len,
185  checksum ((unsigned char *)
186  &ip.ip_src,
187  2 * sizeof ip.ip_src,
188  IPPROTO_UDP +
189  (u_int32_t)
190  ntohs (udp.uh_ulen)))));
191 
192  /* Copy the udp header into the buffer... */
193  memcpy (&buf [*bufix], &udp, sizeof udp);
194  *bufix += sizeof udp;
195 }
196 #endif /* PACKET_ASSEMBLY */
197 
198 #ifdef PACKET_DECODING
199 /* Decode a hardware header... */
200 /* Support for ethernet, TR and FDDI
201  * Doesn't support infiniband yet as the supported oses shouldn't get here
202  */
203 
204 ssize_t decode_hw_header (interface, buf, bufix, from)
205  struct interface_info *interface;
206  unsigned char *buf;
207  unsigned bufix;
208  struct hardware *from;
209 {
210  switch(interface->hw_address.hbuf[0]) {
211 #if defined (HAVE_TR_SUPPORT)
212  case HTYPE_IEEE802:
213  return (decode_tr_header(interface, buf, bufix, from));
214 #endif
215 #if defined (DEC_FDDI)
216  case HTYPE_FDDI:
217  return (decode_fddi_header(interface, buf, bufix, from));
218 #endif
219  case HTYPE_INFINIBAND:
220  log_error("Attempt to decode hw header for infiniband");
221  return (0);
222  case HTYPE_ETHER:
223  default:
224  return (decode_ethernet_header(interface, buf, bufix, from));
225  }
226 }
227 
251 ssize_t
252 decode_udp_ip_header(struct interface_info *interface,
253  unsigned char *buf, unsigned bufix,
254  struct sockaddr_in *from, unsigned buflen,
255  unsigned *rbuflen, int csum_ready)
256 {
257  unsigned char *data;
258  struct ip ip;
259  struct udphdr udp;
260  unsigned char *upp;
261  u_int32_t ip_len, ulen, pkt_len;
262  static unsigned int ip_packets_seen = 0;
263  static unsigned int ip_packets_bad_checksum = 0;
264  static unsigned int udp_packets_seen = 0;
265  static unsigned int udp_packets_bad_checksum = 0;
266  static unsigned int udp_packets_length_checked = 0;
267  static unsigned int udp_packets_length_overflow = 0;
268  unsigned len;
269 
270  /* Assure there is at least an IP header there. */
271  if (sizeof(ip) > buflen)
272  return -1;
273 
274  /* Copy the IP header into a stack aligned structure for inspection.
275  * There may be bits in the IP header that we're not decoding, so we
276  * copy out the bits we grok and skip ahead by ip.ip_hl * 4.
277  */
278  upp = buf + bufix;
279  memcpy(&ip, upp, sizeof(ip));
280  ip_len = (*upp & 0x0f) << 2;
281  upp += ip_len;
282 
283  /* Check packet lengths are within the buffer:
284  * first the ip header (ip_len)
285  * then the packet length from the ip header (pkt_len)
286  * then the udp header (ip_len + sizeof(udp)
287  * We are liberal in what we accept, the udp payload should fit within
288  * pkt_len, but we only check against the full buffer size.
289  */
290  pkt_len = ntohs(ip.ip_len);
291  if ((ip_len > buflen) ||
292  (pkt_len > buflen) ||
293  ((ip_len + sizeof(udp)) > buflen))
294  return -1;
295 
296  /* Copy the UDP header into a stack aligned structure for inspection. */
297  memcpy(&udp, upp, sizeof(udp));
298 
299 #ifdef USERLAND_FILTER
300  /* Is it a UDP packet? */
301  if (ip.ip_p != IPPROTO_UDP)
302  return -1;
303 
304  /* Is it to the port we're serving? */
305 #if defined(RELAY_PORT)
306  if ((udp.uh_dport != local_port) &&
307  ((relay_port == 0) || (udp.uh_dport != relay_port)))
308 #else
309  if (udp.uh_dport != local_port)
310 #endif
311  return -1;
312 #endif /* USERLAND_FILTER */
313 
314  ulen = ntohs(udp.uh_ulen);
315  if (ulen < sizeof(udp))
316  return -1;
317 
318  udp_packets_length_checked++;
319  /* verify that the payload length from the udp packet fits in the buffer */
320  if ((ip_len + ulen) > buflen) {
321  udp_packets_length_overflow++;
322  if (((udp_packets_length_checked > 4) &&
323  (udp_packets_length_overflow != 0)) &&
324  ((udp_packets_length_checked / udp_packets_length_overflow) < 2)) {
325  log_info("%u udp packets in %u too long - dropped",
326  udp_packets_length_overflow,
327  udp_packets_length_checked);
328  udp_packets_length_overflow = 0;
329  udp_packets_length_checked = 0;
330  }
331  return -1;
332  }
333 
334  /* If at least 5 with less than 50% bad, start over */
335  if (udp_packets_length_checked > 4) {
336  udp_packets_length_overflow = 0;
337  udp_packets_length_checked = 0;
338  }
339 
340  /* Check the IP header checksum - it should be zero. */
341  ip_packets_seen++;
342  if (wrapsum (checksum (buf + bufix, ip_len, 0))) {
343  ++ip_packets_bad_checksum;
344  if (((ip_packets_seen > 4) && (ip_packets_bad_checksum != 0)) &&
345  ((ip_packets_seen / ip_packets_bad_checksum) < 2)) {
346  log_info ("%u bad IP checksums seen in %u packets",
347  ip_packets_bad_checksum, ip_packets_seen);
348  ip_packets_seen = ip_packets_bad_checksum = 0;
349  }
350  return -1;
351  }
352 
353  /* If at least 5 with less than 50% bad, start over */
354  if (ip_packets_seen > 4) {
355  ip_packets_bad_checksum = 0;
356  ip_packets_seen = 0;
357  }
358 
359  /* Copy out the IP source address... */
360  memcpy(&from->sin_addr, &ip.ip_src, 4);
361 
362  data = upp + sizeof(udp);
363  len = ulen - sizeof(udp);
364 
365  /* UDP check sum may be optional (udp.uh_sum == 0) or not ready if checksum
366  * offloading is in use */
367  udp_packets_seen++;
368  if (udp.uh_sum && csum_ready) {
369  /* Check the UDP header checksum - since the received packet header
370  * contains the UDP checksum calculated by the transmitter, calculating
371  * it now should come out to zero. */
372  if (wrapsum(checksum((unsigned char *)&udp, sizeof(udp),
373  checksum(data, len,
374  checksum((unsigned char *)&ip.ip_src,
375  8, IPPROTO_UDP + ulen))))) {
376  udp_packets_bad_checksum++;
377  if (((udp_packets_seen > 4) && (udp_packets_bad_checksum != 0))
378  && ((udp_packets_seen / udp_packets_bad_checksum) < 2)) {
379  log_debug ("%u bad udp checksums in %u packets",
380  udp_packets_bad_checksum, udp_packets_seen);
381  udp_packets_seen = udp_packets_bad_checksum = 0;
382  }
383 
384  return -1;
385  }
386  }
387 
388  /* If at least 5 with less than 50% bad, start over */
389  if (udp_packets_seen > 4) {
390  udp_packets_bad_checksum = 0;
391  udp_packets_seen = 0;
392  }
393 
394  /* Copy out the port... */
395  memcpy (&from -> sin_port, &udp.uh_sport, sizeof udp.uh_sport);
396 
397  /* Save the length of the UDP payload. */
398  if (rbuflen != NULL)
399  *rbuflen = len;
400 
401  /* Return the index to the UDP payload. */
402  return ip_len + sizeof udp;
403 }
404 #endif /* PACKET_DECODING */
u_int16_t local_port
Definition: dhclient.c:96
#define HTYPE_IEEE802
Definition: dhcp.h:76
#define HTYPE_FDDI
Definition: dhcp.h:77
#define HTYPE_ETHER
Definition: dhcp.h:75
#define HTYPE_INFINIBAND
Definition: dhcp.h:78
ssize_t decode_ethernet_header(struct interface_info *, unsigned char *, unsigned, struct hardware *)
void assemble_hw_header(struct interface_info *, unsigned char *, unsigned *, struct hardware *)
ssize_t decode_udp_ip_header(struct interface_info *, unsigned char *, unsigned, struct sockaddr_in *, unsigned, unsigned *, int)
void assemble_udp_ip_header(struct interface_info *, unsigned char *, unsigned *, u_int32_t, u_int32_t, u_int32_t, unsigned char *, unsigned)
void assemble_tr_header(struct interface_info *, unsigned char *, unsigned *, struct hardware *)
void assemble_ethernet_header(struct interface_info *, unsigned char *, unsigned *, struct hardware *)
ssize_t decode_tr_header(struct interface_info *, unsigned char *, unsigned, struct hardware *)
ssize_t decode_hw_header(struct interface_info *, unsigned char *, unsigned, struct hardware *)
u_int16_t relay_port
Definition: discover.c:50
#define IPTOS_LOWDELAY
Definition: ip.h:73
#define IP_V_SET(iph, x)
Definition: ip.h:64
#define IP_HL_SET(iph, x)
Definition: ip.h:65
int log_error(const char *,...) __attribute__((__format__(__printf__
int int int log_debug(const char *,...) __attribute__((__format__(__printf__
int int log_info(const char *,...) __attribute__((__format__(__printf__
u_int32_t checksum(unsigned char *buf, unsigned nbytes, u_int32_t sum)
Definition: packet.c:44
u_int32_t wrapsum(u_int32_t sum)
Definition: packet.c:83
u_int8_t hbuf[HARDWARE_ADDR_LEN+1]
Definition: dhcpd.h:493
struct hardware hw_address
Definition: dhcpd.h:1381
Definition: ip.h:47
u_int8_t ip_tos
Definition: ip.h:49
int16_t ip_off
Definition: ip.h:52
u_int8_t ip_p
Definition: ip.h:57
struct in_addr ip_src ip_dst
Definition: ip.h:59
u_int16_t ip_id
Definition: ip.h:51
u_int16_t ip_sum
Definition: ip.h:58
int16_t ip_len
Definition: ip.h:50
u_int8_t ip_ttl
Definition: ip.h:56
Definition: udp.h:61