ISC DHCP  4.3.3-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) 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);
151  ip.ip_tos = IPTOS_LOWDELAY;
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 
246 ssize_t
247 decode_udp_ip_header(struct interface_info *interface,
248  unsigned char *buf, unsigned bufix,
249  struct sockaddr_in *from, unsigned buflen,
250  unsigned *rbuflen, int csum_ready)
251 {
252  unsigned char *data;
253  struct ip ip;
254  struct udphdr udp;
255  unsigned char *upp;
256  u_int32_t ip_len, ulen, pkt_len;
257  static unsigned int ip_packets_seen = 0;
258  static unsigned int ip_packets_bad_checksum = 0;
259  static unsigned int udp_packets_seen = 0;
260  static unsigned int udp_packets_bad_checksum = 0;
261  static unsigned int udp_packets_length_checked = 0;
262  static unsigned int udp_packets_length_overflow = 0;
263  unsigned len;
264 
265  /* Assure there is at least an IP header there. */
266  if (sizeof(ip) > buflen)
267  return -1;
268 
269  /* Copy the IP header into a stack aligned structure for inspection.
270  * There may be bits in the IP header that we're not decoding, so we
271  * copy out the bits we grok and skip ahead by ip.ip_hl * 4.
272  */
273  upp = buf + bufix;
274  memcpy(&ip, upp, sizeof(ip));
275  ip_len = (*upp & 0x0f) << 2;
276  upp += ip_len;
277 
278  /* Check packet lengths are within the buffer:
279  * first the ip header (ip_len)
280  * then the packet length from the ip header (pkt_len)
281  * then the udp header (ip_len + sizeof(udp)
282  * We are liberal in what we accept, the udp payload should fit within
283  * pkt_len, but we only check against the full buffer size.
284  */
285  pkt_len = ntohs(ip.ip_len);
286  if ((ip_len > buflen) ||
287  (pkt_len > buflen) ||
288  ((ip_len + sizeof(udp)) > buflen))
289  return -1;
290 
291  /* Copy the UDP header into a stack aligned structure for inspection. */
292  memcpy(&udp, upp, sizeof(udp));
293 
294 #ifdef USERLAND_FILTER
295  /* Is it a UDP packet? */
296  if (ip.ip_p != IPPROTO_UDP)
297  return -1;
298 
299  /* Is it to the port we're serving? */
300  if (udp.uh_dport != local_port)
301  return -1;
302 #endif /* USERLAND_FILTER */
303 
304  ulen = ntohs(udp.uh_ulen);
305  if (ulen < sizeof(udp))
306  return -1;
307 
308  udp_packets_length_checked++;
309  /* verify that the payload length from the udp packet fits in the buffer */
310  if ((ip_len + ulen) > buflen) {
311  udp_packets_length_overflow++;
312  if (((udp_packets_length_checked > 4) &&
313  (udp_packets_length_overflow != 0)) &&
314  ((udp_packets_length_checked / udp_packets_length_overflow) < 2)) {
315  log_info("%u udp packets in %u too long - dropped",
316  udp_packets_length_overflow,
317  udp_packets_length_checked);
318  udp_packets_length_overflow = 0;
319  udp_packets_length_checked = 0;
320  }
321  return -1;
322  }
323 
324  /* If at least 5 with less than 50% bad, start over */
325  if (udp_packets_length_checked > 4) {
326  udp_packets_length_overflow = 0;
327  udp_packets_length_checked = 0;
328  }
329 
330  /* Check the IP header checksum - it should be zero. */
331  ip_packets_seen++;
332  if (wrapsum (checksum (buf + bufix, ip_len, 0))) {
333  ++ip_packets_bad_checksum;
334  if (((ip_packets_seen > 4) && (ip_packets_bad_checksum != 0)) &&
335  ((ip_packets_seen / ip_packets_bad_checksum) < 2)) {
336  log_info ("%u bad IP checksums seen in %u packets",
337  ip_packets_bad_checksum, ip_packets_seen);
338  ip_packets_seen = ip_packets_bad_checksum = 0;
339  }
340  return -1;
341  }
342 
343  /* If at least 5 with less than 50% bad, start over */
344  if (ip_packets_seen > 4) {
345  ip_packets_bad_checksum = 0;
346  ip_packets_seen = 0;
347  }
348 
349  /* Copy out the IP source address... */
350  memcpy(&from->sin_addr, &ip.ip_src, 4);
351 
352  data = upp + sizeof(udp);
353  len = ulen - sizeof(udp);
354 
355  /* UDP check sum may be optional (udp.uh_sum == 0) or not ready if checksum
356  * offloading is in use */
357  udp_packets_seen++;
358  if (udp.uh_sum && csum_ready) {
359  /* Check the UDP header checksum - since the received packet header
360  * contains the UDP checksum calculated by the transmitter, calculating
361  * it now should come out to zero. */
362  if (wrapsum(checksum((unsigned char *)&udp, sizeof(udp),
363  checksum(data, len,
364  checksum((unsigned char *)&ip.ip_src,
365  8, IPPROTO_UDP + ulen))))) {
366  udp_packets_bad_checksum++;
367  if (((udp_packets_seen > 4) && (udp_packets_bad_checksum != 0))
368  && ((udp_packets_seen / udp_packets_bad_checksum) < 2)) {
369  log_info ("%u bad udp checksums in %u packets",
370  udp_packets_bad_checksum, udp_packets_seen);
371  udp_packets_seen = udp_packets_bad_checksum = 0;
372  }
373 
374  return -1;
375  }
376  }
377 
378  /* If at least 5 with less than 50% bad, start over */
379  if (udp_packets_seen > 4) {
380  udp_packets_bad_checksum = 0;
381  udp_packets_seen = 0;
382  }
383 
384  /* Copy out the port... */
385  memcpy (&from -> sin_port, &udp.uh_sport, sizeof udp.uh_sport);
386 
387  /* Save the length of the UDP payload. */
388  if (rbuflen != NULL)
389  *rbuflen = len;
390 
391  /* Return the index to the UDP payload. */
392  return ip_len + sizeof udp;
393 }
394 #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:84
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: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
struct hardware hw_address
Definition: dhcpd.h:1329
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:484
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