1 /* $NetBSD: packet.c,v 1.3 2020/05/15 12:31:03 manu Exp $ */ 2 3 /* packet.c 4 5 Packet assembly code, originally contributed by Archie Cobbs. */ 6 7 /* 8 * Copyright (c) 2004-2017 by Internet Systems Consortium, Inc. ("ISC") 9 * Copyright (c) 1996-2003 by Internet Software Consortium 10 * 11 * This Source Code Form is subject to the terms of the Mozilla Public 12 * License, v. 2.0. If a copy of the MPL was not distributed with this 13 * file, You can obtain one at http://mozilla.org/MPL/2.0/. 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.3 2020/05/15 12:31:03 manu 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)", (unsigned)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 = *libdhcp_callbacks.local_port; /* XXX */ 174 udp.uh_dport = port; /* XXX */ 175 #if defined(RELAY_PORT) 176 /* Change to relay port defined if sending to server */ 177 if (relay_port && (port == htons(67))) { 178 udp.uh_sport = relay_port; 179 } 180 #endif 181 udp.uh_ulen = htons(sizeof(udp) + len); 182 memset (&udp.uh_sum, 0, sizeof udp.uh_sum); 183 184 /* Compute UDP checksums, including the ``pseudo-header'', the UDP 185 header and the data. */ 186 187 udp.uh_sum = 188 wrapsum (checksum ((unsigned char *)&udp, sizeof udp, 189 checksum (data, len, 190 checksum ((unsigned char *) 191 &ip.ip_src, 192 2 * sizeof ip.ip_src, 193 IPPROTO_UDP + 194 (u_int32_t) 195 ntohs (udp.uh_ulen))))); 196 197 /* Copy the udp header into the buffer... */ 198 memcpy (&buf [*bufix], &udp, sizeof udp); 199 *bufix += sizeof udp; 200 } 201 #endif /* PACKET_ASSEMBLY */ 202 203 #ifdef PACKET_DECODING 204 /* Decode a hardware header... */ 205 /* Support for ethernet, TR and FDDI 206 * Doesn't support infiniband yet as the supported oses shouldn't get here 207 */ 208 209 ssize_t decode_hw_header (interface, buf, bufix, from) 210 struct interface_info *interface; 211 unsigned char *buf; 212 unsigned bufix; 213 struct hardware *from; 214 { 215 switch(interface->hw_address.hbuf[0]) { 216 #if defined (HAVE_TR_SUPPORT) 217 case HTYPE_IEEE802: 218 return (decode_tr_header(interface, buf, bufix, from)); 219 #endif 220 #if defined (DEC_FDDI) 221 case HTYPE_FDDI: 222 return (decode_fddi_header(interface, buf, bufix, from)); 223 #endif 224 case HTYPE_INFINIBAND: 225 log_error("Attempt to decode hw header for infiniband"); 226 return (0); 227 case HTYPE_ETHER: 228 default: 229 return (decode_ethernet_header(interface, buf, bufix, from)); 230 } 231 } 232 233 /*! 234 * 235 * \brief UDP header and IP header decoded together for convenience. 236 * 237 * Attempt to decode the UDP and IP headers and, if necessary, checksum 238 * the packet. 239 * 240 * \param inteface - the interface on which the packet was recevied 241 * \param buf - a pointer to the buffer for the received packet 242 * \param bufix - where to start processing the buffer, previous 243 * routines may have processed parts of the buffer already 244 * \param from - space to return the address of the packet sender 245 * \param buflen - remaining length of the buffer, this will have been 246 * decremented by bufix by the caller 247 * \param rbuflen - space to return the length of the payload from the udp 248 * header 249 * \param csum_ready - indication if the checksum is valid for use 250 * non-zero indicates the checksum should be validated 251 * 252 * \return - the index to the first byte of the udp payload (that is the 253 * start of the DHCP packet 254 */ 255 256 ssize_t 257 decode_udp_ip_header(struct interface_info *interface, 258 unsigned char *buf, unsigned bufix, 259 struct sockaddr_in *from, unsigned buflen, 260 unsigned *rbuflen, int csum_ready) 261 { 262 unsigned char *data; 263 struct ip ip; 264 struct udphdr udp; 265 unsigned char *upp; 266 u_int32_t ip_len, ulen, pkt_len; 267 static unsigned int ip_packets_seen = 0; 268 static unsigned int ip_packets_bad_checksum = 0; 269 static unsigned int udp_packets_seen = 0; 270 static unsigned int udp_packets_bad_checksum = 0; 271 static unsigned int udp_packets_length_checked = 0; 272 static unsigned int udp_packets_length_overflow = 0; 273 unsigned len; 274 275 /* Assure there is at least an IP header there. */ 276 if (sizeof(ip) > buflen) 277 return -1; 278 279 /* Copy the IP header into a stack aligned structure for inspection. 280 * There may be bits in the IP header that we're not decoding, so we 281 * copy out the bits we grok and skip ahead by ip.ip_hl * 4. 282 */ 283 upp = buf + bufix; 284 memcpy(&ip, upp, sizeof(ip)); 285 ip_len = (*upp & 0x0f) << 2; 286 upp += ip_len; 287 288 /* Check packet lengths are within the buffer: 289 * first the ip header (ip_len) 290 * then the packet length from the ip header (pkt_len) 291 * then the udp header (ip_len + sizeof(udp) 292 * We are liberal in what we accept, the udp payload should fit within 293 * pkt_len, but we only check against the full buffer size. 294 */ 295 pkt_len = ntohs(ip.ip_len); 296 if ((ip_len > buflen) || 297 (pkt_len > buflen) || 298 ((ip_len + sizeof(udp)) > buflen)) 299 return -1; 300 301 /* Copy the UDP header into a stack aligned structure for inspection. */ 302 memcpy(&udp, upp, sizeof(udp)); 303 304 #ifdef USERLAND_FILTER 305 /* Is it a UDP packet? */ 306 if (ip.ip_p != IPPROTO_UDP) 307 return -1; 308 309 /* Is it to the port we're serving? */ 310 #if defined(RELAY_PORT) 311 if ((udp.uh_dport != *libdhcp_callbacks.local_port) && 312 ((relay_port == 0) || (udp.uh_dport != relay_port))) 313 #else 314 if (udp.uh_dport != *libdhcp_callbacks.local_port) 315 #endif 316 return -1; 317 #endif /* USERLAND_FILTER */ 318 319 ulen = ntohs(udp.uh_ulen); 320 if (ulen < sizeof(udp)) 321 return -1; 322 323 udp_packets_length_checked++; 324 /* verify that the payload length from the udp packet fits in the buffer */ 325 if ((ip_len + ulen) > buflen) { 326 udp_packets_length_overflow++; 327 if (((udp_packets_length_checked > 4) && 328 (udp_packets_length_overflow != 0)) && 329 ((udp_packets_length_checked / udp_packets_length_overflow) < 2)) { 330 log_info("%u udp packets in %u too long - dropped", 331 udp_packets_length_overflow, 332 udp_packets_length_checked); 333 udp_packets_length_overflow = 0; 334 udp_packets_length_checked = 0; 335 } 336 return -1; 337 } 338 339 /* If at least 5 with less than 50% bad, start over */ 340 if (udp_packets_length_checked > 4) { 341 udp_packets_length_overflow = 0; 342 udp_packets_length_checked = 0; 343 } 344 345 /* Check the IP header checksum - it should be zero. */ 346 ip_packets_seen++; 347 if (wrapsum (checksum (buf + bufix, ip_len, 0))) { 348 ++ip_packets_bad_checksum; 349 if (((ip_packets_seen > 4) && (ip_packets_bad_checksum != 0)) && 350 ((ip_packets_seen / ip_packets_bad_checksum) < 2)) { 351 log_info ("%u bad IP checksums seen in %u packets", 352 ip_packets_bad_checksum, ip_packets_seen); 353 ip_packets_seen = ip_packets_bad_checksum = 0; 354 } 355 return -1; 356 } 357 358 /* If at least 5 with less than 50% bad, start over */ 359 if (ip_packets_seen > 4) { 360 ip_packets_bad_checksum = 0; 361 ip_packets_seen = 0; 362 } 363 364 /* Copy out the IP source address... */ 365 memcpy(&from->sin_addr, &ip.ip_src, 4); 366 367 data = upp + sizeof(udp); 368 len = ulen - sizeof(udp); 369 370 /* UDP check sum may be optional (udp.uh_sum == 0) or not ready if checksum 371 * offloading is in use */ 372 udp_packets_seen++; 373 if (udp.uh_sum && csum_ready) { 374 /* Check the UDP header checksum - since the received packet header 375 * contains the UDP checksum calculated by the transmitter, calculating 376 * it now should come out to zero. */ 377 if (wrapsum(checksum((unsigned char *)&udp, sizeof(udp), 378 checksum(data, len, 379 checksum((unsigned char *)&ip.ip_src, 380 8, IPPROTO_UDP + ulen))))) { 381 udp_packets_bad_checksum++; 382 if (((udp_packets_seen > 4) && (udp_packets_bad_checksum != 0)) 383 && ((udp_packets_seen / udp_packets_bad_checksum) < 2)) { 384 log_debug ("%u bad udp checksums in %u packets", 385 udp_packets_bad_checksum, udp_packets_seen); 386 udp_packets_seen = udp_packets_bad_checksum = 0; 387 } 388 389 return -1; 390 } 391 } 392 393 /* If at least 5 with less than 50% bad, start over */ 394 if (udp_packets_seen > 4) { 395 udp_packets_bad_checksum = 0; 396 udp_packets_seen = 0; 397 } 398 399 /* Copy out the port... */ 400 memcpy (&from -> sin_port, &udp.uh_sport, sizeof udp.uh_sport); 401 402 /* Save the length of the UDP payload. */ 403 if (rbuflen != NULL) 404 *rbuflen = len; 405 406 /* Return the index to the UDP payload. */ 407 return ip_len + sizeof udp; 408 } 409 #endif /* PACKET_DECODING */ 410