ISC DHCP  4.3.6
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  * 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.
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);
150  ip.ip_tos = IPTOS_LOWDELAY;
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  udp.uh_ulen = htons(sizeof(udp) + len);
171  memset (&udp.uh_sum, 0, sizeof udp.uh_sum);
172 
173  /* Compute UDP checksums, including the ``pseudo-header'', the UDP
174  header and the data. */
175 
176  udp.uh_sum =
177  wrapsum (checksum ((unsigned char *)&udp, sizeof udp,
178  checksum (data, len,
179  checksum ((unsigned char *)
180  &ip.ip_src,
181  2 * sizeof ip.ip_src,
182  IPPROTO_UDP +
183  (u_int32_t)
184  ntohs (udp.uh_ulen)))));
185 
186  /* Copy the udp header into the buffer... */
187  memcpy (&buf [*bufix], &udp, sizeof udp);
188  *bufix += sizeof udp;
189 }
190 #endif /* PACKET_ASSEMBLY */
191 
192 #ifdef PACKET_DECODING
193 /* Decode a hardware header... */
194 /* Support for ethernet, TR and FDDI
195  * Doesn't support infiniband yet as the supported oses shouldn't get here
196  */
197 
198 ssize_t decode_hw_header (interface, buf, bufix, from)
199  struct interface_info *interface;
200  unsigned char *buf;
201  unsigned bufix;
202  struct hardware *from;
203 {
204  switch(interface->hw_address.hbuf[0]) {
205 #if defined (HAVE_TR_SUPPORT)
206  case HTYPE_IEEE802:
207  return (decode_tr_header(interface, buf, bufix, from));
208 #endif
209 #if defined (DEC_FDDI)
210  case HTYPE_FDDI:
211  return (decode_fddi_header(interface, buf, bufix, from));
212 #endif
213  case HTYPE_INFINIBAND:
214  log_error("Attempt to decode hw header for infiniband");
215  return (0);
216  case HTYPE_ETHER:
217  default:
218  return (decode_ethernet_header(interface, buf, bufix, from));
219  }
220 }
221 
245 ssize_t
246 decode_udp_ip_header(struct interface_info *interface,
247  unsigned char *buf, unsigned bufix,
248  struct sockaddr_in *from, unsigned buflen,
249  unsigned *rbuflen, int csum_ready)
250 {
251  unsigned char *data;
252  struct ip ip;
253  struct udphdr udp;
254  unsigned char *upp;
255  u_int32_t ip_len, ulen, pkt_len;
256  static unsigned int ip_packets_seen = 0;
257  static unsigned int ip_packets_bad_checksum = 0;
258  static unsigned int udp_packets_seen = 0;
259  static unsigned int udp_packets_bad_checksum = 0;
260  static unsigned int udp_packets_length_checked = 0;
261  static unsigned int udp_packets_length_overflow = 0;
262  unsigned len;
263 
264  /* Assure there is at least an IP header there. */
265  if (sizeof(ip) > buflen)
266  return -1;
267 
268  /* Copy the IP header into a stack aligned structure for inspection.
269  * There may be bits in the IP header that we're not decoding, so we
270  * copy out the bits we grok and skip ahead by ip.ip_hl * 4.
271  */
272  upp = buf + bufix;
273  memcpy(&ip, upp, sizeof(ip));
274  ip_len = (*upp & 0x0f) << 2;
275  upp += ip_len;
276 
277  /* Check packet lengths are within the buffer:
278  * first the ip header (ip_len)
279  * then the packet length from the ip header (pkt_len)
280  * then the udp header (ip_len + sizeof(udp)
281  * We are liberal in what we accept, the udp payload should fit within
282  * pkt_len, but we only check against the full buffer size.
283  */
284  pkt_len = ntohs(ip.ip_len);
285  if ((ip_len > buflen) ||
286  (pkt_len > buflen) ||
287  ((ip_len + sizeof(udp)) > buflen))
288  return -1;
289 
290  /* Copy the UDP header into a stack aligned structure for inspection. */
291  memcpy(&udp, upp, sizeof(udp));
292 
293 #ifdef USERLAND_FILTER
294  /* Is it a UDP packet? */
295  if (ip.ip_p != IPPROTO_UDP)
296  return -1;
297 
298  /* Is it to the port we're serving? */
299  if (udp.uh_dport != local_port)
300  return -1;
301 #endif /* USERLAND_FILTER */
302 
303  ulen = ntohs(udp.uh_ulen);
304  if (ulen < sizeof(udp))
305  return -1;
306 
307  udp_packets_length_checked++;
308  /* verify that the payload length from the udp packet fits in the buffer */
309  if ((ip_len + ulen) > buflen) {
310  udp_packets_length_overflow++;
311  if (((udp_packets_length_checked > 4) &&
312  (udp_packets_length_overflow != 0)) &&
313  ((udp_packets_length_checked / udp_packets_length_overflow) < 2)) {
314  log_info("%u udp packets in %u too long - dropped",
315  udp_packets_length_overflow,
316  udp_packets_length_checked);
317  udp_packets_length_overflow = 0;
318  udp_packets_length_checked = 0;
319  }
320  return -1;
321  }
322 
323  /* If at least 5 with less than 50% bad, start over */
324  if (udp_packets_length_checked > 4) {
325  udp_packets_length_overflow = 0;
326  udp_packets_length_checked = 0;
327  }
328 
329  /* Check the IP header checksum - it should be zero. */
330  ip_packets_seen++;
331  if (wrapsum (checksum (buf + bufix, ip_len, 0))) {
332  ++ip_packets_bad_checksum;
333  if (((ip_packets_seen > 4) && (ip_packets_bad_checksum != 0)) &&
334  ((ip_packets_seen / ip_packets_bad_checksum) < 2)) {
335  log_info ("%u bad IP checksums seen in %u packets",
336  ip_packets_bad_checksum, ip_packets_seen);
337  ip_packets_seen = ip_packets_bad_checksum = 0;
338  }
339  return -1;
340  }
341 
342  /* If at least 5 with less than 50% bad, start over */
343  if (ip_packets_seen > 4) {
344  ip_packets_bad_checksum = 0;
345  ip_packets_seen = 0;
346  }
347 
348  /* Copy out the IP source address... */
349  memcpy(&from->sin_addr, &ip.ip_src, 4);
350 
351  data = upp + sizeof(udp);
352  len = ulen - sizeof(udp);
353 
354  /* UDP check sum may be optional (udp.uh_sum == 0) or not ready if checksum
355  * offloading is in use */
356  udp_packets_seen++;
357  if (udp.uh_sum && csum_ready) {
358  /* Check the UDP header checksum - since the received packet header
359  * contains the UDP checksum calculated by the transmitter, calculating
360  * it now should come out to zero. */
361  if (wrapsum(checksum((unsigned char *)&udp, sizeof(udp),
362  checksum(data, len,
363  checksum((unsigned char *)&ip.ip_src,
364  8, IPPROTO_UDP + ulen))))) {
365  udp_packets_bad_checksum++;
366  if (((udp_packets_seen > 4) && (udp_packets_bad_checksum != 0))
367  && ((udp_packets_seen / udp_packets_bad_checksum) < 2)) {
368  log_debug ("%u bad udp checksums in %u packets",
369  udp_packets_bad_checksum, udp_packets_seen);
370  udp_packets_seen = udp_packets_bad_checksum = 0;
371  }
372 
373  return -1;
374  }
375  }
376 
377  /* If at least 5 with less than 50% bad, start over */
378  if (udp_packets_seen > 4) {
379  udp_packets_bad_checksum = 0;
380  udp_packets_seen = 0;
381  }
382 
383  /* Copy out the port... */
384  memcpy (&from -> sin_port, &udp.uh_sport, sizeof udp.uh_sport);
385 
386  /* Save the length of the UDP payload. */
387  if (rbuflen != NULL)
388  *rbuflen = len;
389 
390  /* Return the index to the UDP payload. */
391  return ip_len + sizeof udp;
392 }
393 #endif /* PACKET_DECODING */
void assemble_ethernet_header(struct interface_info *, unsigned char *, unsigned *, struct hardware *)
u_int16_t uh_sport
Definition: udp.h:62
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_int16_t uh_dport
Definition: udp.h:63
u_int32_t wrapsum(u_int32_t sum)
Definition: packet.c:83
u_int8_t ip_tos
Definition: ip.h:49
u_int16_t uh_sum
Definition: udp.h:65
u_int16_t uh_ulen
Definition: udp.h:64
#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:91
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
struct hardware hw_address
Definition: dhcpd.h:1353
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_int8_t hbuf[HARDWARE_ADDR_LEN+1]
Definition: dhcpd.h:490
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:44