1 /* $NetBSD: packet.c,v 1.1.1.4 2014/07/12 11:57:46 spz Exp $ */ 2 /* packet.c 3 4 Packet assembly code, originally contributed by Archie Cobbs. */ 5 6 /* 7 * Copyright (c) 2009,2012 by Internet Systems Consortium, Inc. ("ISC") 8 * Copyright (c) 2004,2005,2007 by Internet Systems Consortium, Inc. ("ISC") 9 * Copyright (c) 1996-2003 by Internet Software Consortium 10 * 11 * Permission to use, copy, modify, and distribute this software for any 12 * purpose with or without fee is hereby granted, provided that the above 13 * copyright notice and this permission notice appear in all copies. 14 * 15 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES 16 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 17 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR 18 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 19 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 20 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT 21 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 22 * 23 * Internet Systems Consortium, Inc. 24 * 950 Charter Street 25 * Redwood City, CA 94063 26 * <info@isc.org> 27 * https://www.isc.org/ 28 * 29 * This code was originally contributed by Archie Cobbs, and is still 30 * very similar to that contribution, although the packet checksum code 31 * has been hacked significantly with the help of quite a few ISC DHCP 32 * users, without whose gracious and thorough help the checksum code would 33 * still be disabled. 34 */ 35 36 #include <sys/cdefs.h> 37 __RCSID("$NetBSD: packet.c,v 1.1.1.4 2014/07/12 11:57:46 spz Exp $"); 38 39 #include "dhcpd.h" 40 41 #if defined (PACKET_ASSEMBLY) || defined (PACKET_DECODING) 42 #include "includes/netinet/ip.h" 43 #include "includes/netinet/udp.h" 44 #include "includes/netinet/if_ether.h" 45 #endif /* PACKET_ASSEMBLY || PACKET_DECODING */ 46 47 /* Compute the easy part of the checksum on a range of bytes. */ 48 49 u_int32_t checksum (buf, nbytes, sum) 50 unsigned char *buf; 51 unsigned nbytes; 52 u_int32_t sum; 53 { 54 unsigned i; 55 56 #ifdef DEBUG_CHECKSUM 57 log_debug ("checksum (%x %d %x)", buf, nbytes, sum); 58 #endif 59 60 /* Checksum all the pairs of bytes first... */ 61 for (i = 0; i < (nbytes & ~1U); i += 2) { 62 #ifdef DEBUG_CHECKSUM_VERBOSE 63 log_debug ("sum = %x", sum); 64 #endif 65 sum += (u_int16_t) ntohs(*((u_int16_t *)(buf + i))); 66 /* Add carry. */ 67 if (sum > 0xFFFF) 68 sum -= 0xFFFF; 69 } 70 71 /* If there's a single byte left over, checksum it, too. Network 72 byte order is big-endian, so the remaining byte is the high byte. */ 73 if (i < nbytes) { 74 #ifdef DEBUG_CHECKSUM_VERBOSE 75 log_debug ("sum = %x", sum); 76 #endif 77 sum += buf [i] << 8; 78 /* Add carry. */ 79 if (sum > 0xFFFF) 80 sum -= 0xFFFF; 81 } 82 83 return sum; 84 } 85 86 /* Finish computing the checksum, and then put it into network byte order. */ 87 88 u_int32_t wrapsum (sum) 89 u_int32_t sum; 90 { 91 #ifdef DEBUG_CHECKSUM 92 log_debug ("wrapsum (%x)", sum); 93 #endif 94 95 sum = ~sum & 0xFFFF; 96 #ifdef DEBUG_CHECKSUM_VERBOSE 97 log_debug ("sum = %x", sum); 98 #endif 99 100 #ifdef DEBUG_CHECKSUM 101 log_debug ("wrapsum returns %x", htons (sum)); 102 #endif 103 return htons(sum); 104 } 105 106 #ifdef PACKET_ASSEMBLY 107 void assemble_hw_header (interface, buf, bufix, to) 108 struct interface_info *interface; 109 unsigned char *buf; 110 unsigned *bufix; 111 struct hardware *to; 112 { 113 switch (interface->hw_address.hbuf[0]) { 114 #if defined(HAVE_TR_SUPPORT) 115 case HTYPE_IEEE802: 116 assemble_tr_header(interface, buf, bufix, to); 117 break; 118 #endif 119 #if defined (DEC_FDDI) 120 case HTYPE_FDDI: 121 assemble_fddi_header(interface, buf, bufix, to); 122 break; 123 #endif 124 case HTYPE_INFINIBAND: 125 log_error("Attempt to assemble hw header for infiniband"); 126 break; 127 case HTYPE_ETHER: 128 default: 129 assemble_ethernet_header(interface, buf, bufix, to); 130 break; 131 } 132 } 133 134 /* UDP header and IP header assembled together for convenience. */ 135 136 void assemble_udp_ip_header (interface, buf, bufix, 137 from, to, port, data, len) 138 struct interface_info *interface; 139 unsigned char *buf; 140 unsigned *bufix; 141 u_int32_t from; 142 u_int32_t to; 143 u_int32_t port; 144 unsigned char *data; 145 unsigned len; 146 { 147 struct ip ip; 148 struct udphdr udp; 149 150 memset (&ip, 0, sizeof ip); 151 152 /* Fill out the IP header */ 153 IP_V_SET (&ip, 4); 154 IP_HL_SET (&ip, 20); 155 ip.ip_tos = IPTOS_LOWDELAY; 156 ip.ip_len = htons(sizeof(ip) + sizeof(udp) + len); 157 ip.ip_id = 0; 158 ip.ip_off = 0; 159 ip.ip_ttl = 128; 160 ip.ip_p = IPPROTO_UDP; 161 ip.ip_sum = 0; 162 ip.ip_src.s_addr = from; 163 ip.ip_dst.s_addr = to; 164 165 /* Checksum the IP header... */ 166 ip.ip_sum = wrapsum (checksum ((unsigned char *)&ip, sizeof ip, 0)); 167 168 /* Copy the ip header into the buffer... */ 169 memcpy (&buf [*bufix], &ip, sizeof ip); 170 *bufix += sizeof ip; 171 172 /* Fill out the UDP header */ 173 udp.uh_sport = local_port; /* XXX */ 174 udp.uh_dport = port; /* XXX */ 175 udp.uh_ulen = htons(sizeof(udp) + len); 176 memset (&udp.uh_sum, 0, sizeof udp.uh_sum); 177 178 /* Compute UDP checksums, including the ``pseudo-header'', the UDP 179 header and the data. */ 180 181 udp.uh_sum = 182 wrapsum (checksum ((unsigned char *)&udp, sizeof udp, 183 checksum (data, len, 184 checksum ((unsigned char *) 185 &ip.ip_src, 186 2 * sizeof ip.ip_src, 187 IPPROTO_UDP + 188 (u_int32_t) 189 ntohs (udp.uh_ulen))))); 190 191 /* Copy the udp header into the buffer... */ 192 memcpy (&buf [*bufix], &udp, sizeof udp); 193 *bufix += sizeof udp; 194 } 195 #endif /* PACKET_ASSEMBLY */ 196 197 #ifdef PACKET_DECODING 198 /* Decode a hardware header... */ 199 /* Support for ethernet, TR and FDDI 200 * Doesn't support infiniband yet as the supported oses shouldn't get here 201 */ 202 203 ssize_t decode_hw_header (interface, buf, bufix, from) 204 struct interface_info *interface; 205 unsigned char *buf; 206 unsigned bufix; 207 struct hardware *from; 208 { 209 switch(interface->hw_address.hbuf[0]) { 210 #if defined (HAVE_TR_SUPPORT) 211 case HTYPE_IEEE802: 212 return (decode_tr_header(interface, buf, bufix, from)); 213 #endif 214 #if defined (DEC_FDDI) 215 case HTYPE_FDDI: 216 return (decode_fddi_header(interface, buf, bufix, from)); 217 #endif 218 case HTYPE_INFINIBAND: 219 log_error("Attempt to decode hw header for infiniband"); 220 return (0); 221 case HTYPE_ETHER: 222 default: 223 return (decode_ethernet_header(interface, buf, bufix, from)); 224 } 225 } 226 227 /* UDP header and IP header decoded together for convenience. */ 228 229 ssize_t 230 decode_udp_ip_header(struct interface_info *interface, 231 unsigned char *buf, unsigned bufix, 232 struct sockaddr_in *from, unsigned buflen, 233 unsigned *rbuflen) 234 { 235 unsigned char *data; 236 struct ip ip; 237 struct udphdr udp; 238 unsigned char *upp, *endbuf; 239 u_int32_t ip_len, ulen, pkt_len; 240 u_int32_t sum, usum; 241 static int ip_packets_seen; 242 static int ip_packets_bad_checksum; 243 static int udp_packets_seen; 244 static int udp_packets_bad_checksum; 245 static int udp_packets_length_checked; 246 static int udp_packets_length_overflow; 247 unsigned len; 248 249 /* Designate the end of the input buffer for bounds checks. */ 250 endbuf = buf + bufix + buflen; 251 252 /* Assure there is at least an IP header there. */ 253 if ((buf + bufix + sizeof(ip)) > endbuf) 254 return -1; 255 256 /* Copy the IP header into a stack aligned structure for inspection. 257 * There may be bits in the IP header that we're not decoding, so we 258 * copy out the bits we grok and skip ahead by ip.ip_hl * 4. 259 */ 260 upp = buf + bufix; 261 memcpy(&ip, upp, sizeof(ip)); 262 ip_len = (*upp & 0x0f) << 2; 263 upp += ip_len; 264 265 /* Check the IP packet length. */ 266 pkt_len = ntohs(ip.ip_len); 267 if (pkt_len > buflen) 268 return -1; 269 270 /* Assure after ip_len bytes that there is enough room for a UDP header. */ 271 if ((upp + sizeof(udp)) > endbuf) 272 return -1; 273 274 /* Copy the UDP header into a stack aligned structure for inspection. */ 275 memcpy(&udp, upp, sizeof(udp)); 276 277 #ifdef USERLAND_FILTER 278 /* Is it a UDP packet? */ 279 if (ip.ip_p != IPPROTO_UDP) 280 return -1; 281 282 /* Is it to the port we're serving? */ 283 if (udp.uh_dport != local_port) 284 return -1; 285 #endif /* USERLAND_FILTER */ 286 287 ulen = ntohs(udp.uh_ulen); 288 if (ulen < sizeof(udp)) 289 return -1; 290 291 udp_packets_length_checked++; 292 if ((upp + ulen) > endbuf) { 293 udp_packets_length_overflow++; 294 if ((udp_packets_length_checked > 4) && 295 ((udp_packets_length_checked / 296 udp_packets_length_overflow) < 2)) { 297 log_info("%d udp packets in %d too long - dropped", 298 udp_packets_length_overflow, 299 udp_packets_length_checked); 300 udp_packets_length_overflow = 0; 301 udp_packets_length_checked = 0; 302 } 303 return -1; 304 } 305 306 if ((ulen < sizeof(udp)) || ((upp + ulen) > endbuf)) 307 return -1; 308 309 /* Check the IP header checksum - it should be zero. */ 310 ++ip_packets_seen; 311 if (wrapsum (checksum (buf + bufix, ip_len, 0))) { 312 ++ip_packets_bad_checksum; 313 if (ip_packets_seen > 4 && 314 (ip_packets_seen / ip_packets_bad_checksum) < 2) { 315 log_info ("%d bad IP checksums seen in %d packets", 316 ip_packets_bad_checksum, ip_packets_seen); 317 ip_packets_seen = ip_packets_bad_checksum = 0; 318 } 319 return -1; 320 } 321 322 /* Copy out the IP source address... */ 323 memcpy(&from->sin_addr, &ip.ip_src, 4); 324 325 /* Compute UDP checksums, including the ``pseudo-header'', the UDP 326 header and the data. If the UDP checksum field is zero, we're 327 not supposed to do a checksum. */ 328 329 data = upp + sizeof(udp); 330 len = ulen - sizeof(udp); 331 332 usum = udp.uh_sum; 333 udp.uh_sum = 0; 334 335 /* XXX: We have to pass &udp, because we have to zero the checksum 336 * field before calculating the sum...'upp' isn't zeroed. 337 */ 338 sum = wrapsum(checksum((unsigned char *)&udp, sizeof(udp), 339 checksum(data, len, 340 checksum((unsigned char *)&ip.ip_src, 341 8, IPPROTO_UDP + ulen)))); 342 343 udp_packets_seen++; 344 if (usum && usum != sum) { 345 udp_packets_bad_checksum++; 346 if (udp_packets_seen > 4 && 347 (udp_packets_seen / udp_packets_bad_checksum) < 2) { 348 log_info ("%d bad udp checksums in %d packets", 349 udp_packets_bad_checksum, udp_packets_seen); 350 udp_packets_seen = udp_packets_bad_checksum = 0; 351 } 352 return -1; 353 } 354 355 /* Copy out the port... */ 356 memcpy (&from -> sin_port, &udp.uh_sport, sizeof udp.uh_sport); 357 358 /* Save the length of the UDP payload. */ 359 if (rbuflen != NULL) 360 *rbuflen = len; 361 362 /* Return the index to the UDP payload. */ 363 return ip_len + sizeof udp; 364 } 365 #endif /* PACKET_DECODING */ 366