1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2010 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #include <stdio.h> 28 #include <stdlib.h> 29 #include <unistd.h> 30 #include <stdarg.h> 31 #include <sys/types.h> 32 #include <sys/time.h> 33 #include <fcntl.h> 34 #include <errno.h> 35 #include <assert.h> 36 #include <string.h> 37 #include <sys/socket.h> 38 #include <sys/sockio.h> 39 #include <net/if.h> 40 #include <net/if_arp.h> 41 #include <netinet/in_systm.h> 42 #include <netinet/in.h> 43 #include <arpa/inet.h> 44 #include <netinet/if_ether.h> 45 #include <netinet/ip.h> 46 #include <netinet/udp.h> 47 #include <stropts.h> 48 #include <stdio.h> 49 #include <ctype.h> 50 #include <syslog.h> 51 #include <netinet/dhcp.h> 52 #include <dhcp_symbol.h> 53 #include "dhcpd.h" 54 #include "per_dnet.h" 55 #include "interfaces.h" 56 #include <v4_sum_impl.h> 57 #include <locale.h> 58 59 static int socksize = 64 * 1024; /* large socket window size for data */ 60 static const uchar_t magic_cookie[] = BOOTMAGIC; 61 static void disp_if(IF *); 62 63 /* 64 * Network interface configuration. This file contains routines which 65 * handle the input side of the DHCP/BOOTP/Relay agent. Multiple interfaces 66 * are handled by identifying explicitly each interface, and creating a 67 * stream for each. If only one usable interface exists, then a "normal" 68 * UDP socket is used for simplicity's sake. 69 */ 70 71 IF *if_head; /* head of interfaces list */ 72 mutex_t if_head_mtx; /* mutex for adding/deleting IF list entries */ 73 char *interfaces; /* user specified interfaces */ 74 static int num_interfaces; /* # of usable interfaces on the system */ 75 76 static char * 77 dsrvr_socktype(dsrvr_socktype_t stype) 78 { 79 char *rp; 80 81 switch (stype) { 82 case DSRVR_LBCAST: 83 rp = "limited broadcast"; 84 break; 85 case DSRVR_DBCAST: 86 rp = "directed broadcast"; 87 break; 88 case DSRVR_UCAST: 89 rp = "unicast"; 90 break; 91 } 92 return (rp); 93 } 94 95 /* 96 * Given two packets, match them based on BOOTP header operation, packet len, 97 * hardware type, flags, ciaddr, DHCP type, client id, or chaddr. 98 * Returns B_TRUE if they match, B_FALSE otherwise. 99 */ 100 static boolean_t 101 match_plp(PKT_LIST *alp, PKT_LIST *blp) 102 { 103 DHCP_OPT *a, *b; 104 105 assert(alp != NULL && blp != NULL); 106 107 if (alp->pkt->op != blp->pkt->op || 108 alp->len != alp->len || 109 alp->pkt->htype != blp->pkt->htype || 110 alp->pkt->flags != blp->pkt->flags || 111 alp->pkt->ciaddr.s_addr != blp->pkt->ciaddr.s_addr) 112 return (B_FALSE); /* not even the same BOOTP type. */ 113 114 #ifdef DEBUG 115 if (alp->pkt->giaddr.s_addr != blp->pkt->giaddr.s_addr) { 116 dhcpmsg(LOG_DEBUG, 117 "%04d match_plp: giaddr mismatch on 0x%x, 0x%x\n", 118 thr_self()); 119 } 120 #endif /* DEBUG */ 121 122 a = alp->opts[CD_DHCP_TYPE]; 123 b = blp->opts[CD_DHCP_TYPE]; 124 if (a == NULL && b == NULL) { 125 /* bootp */ 126 if (memcmp(alp->pkt->chaddr, blp->pkt->chaddr, 127 alp->pkt->hlen) == 0) 128 return (B_TRUE); 129 } else if (a != NULL && b != NULL) { 130 if (a->value[0] == b->value[0]) { 131 /* dhcp - packet types match. */ 132 a = alp->opts[CD_CLIENT_ID]; 133 b = blp->opts[CD_CLIENT_ID]; 134 if (a != NULL && b != NULL) { 135 if (memcmp(a->value, b->value, a->len) == 0) 136 return (B_TRUE); 137 } else { 138 if (memcmp(alp->pkt->chaddr, blp->pkt->chaddr, 139 alp->pkt->hlen) == 0) 140 return (B_TRUE); 141 } 142 } 143 } 144 return (B_FALSE); 145 } 146 147 /* 148 * Given a packet, searches for a later packet in the 149 * interface's client list. If the search is successful, the argument 150 * packet is deleted, and the later packet is returned with the appropriate 151 * fields/options modified. 152 * 153 * Matches are based on match_plp(). The list is scanned until the final packet 154 * which "matches" is found. The last match replaces 155 * the argument plp. Duplicates are deleted. 156 * 157 * General Notes: After the first candidate is found, the list is checked to 158 * the tail of the list for other matches. For each packet which is deleted. 159 * the duplicate statistic is incremented for each one. If no candidate is 160 * found, then the argument plp is returned. 161 * 162 * Caveats: What about length and contents of packets? By definition, a 163 * client is not supposed to be altering this between frames, so we should 164 * be ok. Since the argument plp may be destroyed, it is assumed to be 165 * detached. 166 */ 167 PKT_LIST * 168 refresh_pktlist(dsvc_clnt_t *pcd, PKT_LIST *plp) 169 { 170 PKT_LIST *wplp, *tplp, *retplp = NULL; 171 IF *ifp = pcd->ifp; 172 173 assert(MUTEX_HELD(&pcd->pkt_mtx)); 174 175 wplp = pcd->pkthead; 176 while (wplp != NULL) { 177 if (match_plp(plp, wplp)) { 178 pcd->pending--; 179 180 (void) mutex_lock(&ifp->ifp_mtx); 181 ifp->duplicate++; 182 (void) mutex_unlock(&ifp->ifp_mtx); 183 184 /* 185 * Note that tplp, retplp can be synonyms for 186 * wplp. The synonyms are used because moldy plp's 187 * will be nuked, and the plp to return will be 188 * detached. 189 */ 190 tplp = wplp; 191 wplp = wplp->next; 192 193 if (retplp != NULL) { 194 /* moldy duplicates */ 195 free_plp(retplp); 196 } 197 retplp = tplp; 198 detach_plp(pcd, retplp); 199 } else { 200 wplp = wplp->next; 201 } 202 } 203 204 if (retplp == NULL) 205 retplp = plp; 206 else { 207 if (debug) { 208 dhcpmsg(LOG_DEBUG, 209 "%04d: Refreshed (0x%p) to (0x%p)\n", 210 thr_self(), (void *)plp, (void *)retplp); 211 } 212 free_plp(plp); 213 } 214 215 return (retplp); 216 } 217 218 /* 219 * Queries the IP transport layer for configured interfaces. Those that 220 * are acceptable for use by our daemon have these characteristics: 221 * 222 * Not loopback 223 * Is UP 224 * 225 * Sets num_interfaces global to number of valid, selected interfaces. 226 * 227 * Returns: 0 for success, the appropriate errno on fatal failure. 228 * 229 * Notes: Code gleaned from the in.rarpd, solaris 2.2. 230 */ 231 static int 232 find_interfaces(void) 233 { 234 int i, k, ip, reqsize, numifs; 235 boolean_t found; 236 ushort_t mtu_tmp; 237 struct ifreq *reqbuf, *ifr; 238 struct ifconf ifconf; 239 IF *ifp, *if_tail; 240 struct sockaddr_in *sin; 241 char **user_if; 242 ENCODE *hecp; 243 244 if ((ip = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { 245 dhcpmsg(LOG_ERR, "Error opening socket: %s\n", 246 strerror(errno)); 247 return (1); 248 } 249 250 if (ioctl(ip, SIOCGIFNUM, &numifs) < 0) { 251 dhcpmsg(LOG_WARNING, 252 "Error discovering number of network interfaces: %s\n", 253 strerror(errno)); 254 (void) close(ip); 255 return (1); 256 } 257 258 reqsize = numifs * sizeof (struct ifreq); 259 reqbuf = (struct ifreq *)smalloc(reqsize); 260 261 ifconf.ifc_len = reqsize; 262 ifconf.ifc_buf = (caddr_t)reqbuf; 263 264 if (ioctl(ip, SIOCGIFCONF, &ifconf) < 0) { 265 dhcpmsg(LOG_ERR, 266 "Error getting network interface information: %s\n", 267 strerror(errno)); 268 free(reqbuf); 269 (void) close(ip); 270 return (1); 271 } 272 273 /* 274 * Verify that user specified interfaces are valid. 275 */ 276 user_if = (char **)smalloc(numifs * sizeof (char *)); 277 if (interfaces != NULL) { 278 for (i = 0; i < numifs; i++) { 279 user_if[i] = strtok(interfaces, ","); 280 if (user_if[i] == NULL) 281 break; /* we're done */ 282 interfaces = NULL; /* for next call to strtok() */ 283 284 for (found = B_FALSE, ifr = ifconf.ifc_req; 285 ifr < &ifconf.ifc_req[ifconf.ifc_len / 286 sizeof (struct ifreq)]; ifr++) { 287 if (strcmp(user_if[i], ifr->ifr_name) == 0) { 288 found = B_TRUE; 289 break; 290 } 291 } 292 if (!found) { 293 dhcpmsg(LOG_ERR, 294 "Invalid network interface: %s\n", 295 user_if[i]); 296 free(reqbuf); 297 free(user_if); 298 (void) close(ip); 299 return (1); 300 } 301 } 302 if (i < numifs) 303 user_if[i] = NULL; 304 } else 305 user_if[0] = NULL; 306 307 /* 308 * For each interface, build an interface structure. Ignore any 309 * LOOPBACK or down interfaces. 310 */ 311 if_tail = if_head = NULL; 312 for (ifr = ifconf.ifc_req; 313 ifr < &ifconf.ifc_req[ifconf.ifc_len / sizeof (struct ifreq)]; 314 ifr++) { 315 if (ioctl(ip, SIOCGIFFLAGS, ifr) < 0) { 316 dhcpmsg(LOG_ERR, 317 "Error encountered getting interface: %s flags: %s\n", 318 ifr->ifr_name, strerror(errno)); 319 continue; 320 } 321 if ((ifr->ifr_flags & IFF_LOOPBACK) || 322 !(ifr->ifr_flags & IFF_UP)) 323 continue; 324 325 num_interfaces++; /* all possible interfaces counted */ 326 327 /* 328 * If the user specified a list of interfaces, 329 * we'll only consider the ones specified. 330 */ 331 if (user_if[0] != NULL) { 332 for (i = 0; i < numifs; i++) { 333 if (user_if[i] == NULL) 334 break; /* skip this interface */ 335 if (strcmp(user_if[i], ifr->ifr_name) == 0) 336 break; /* user wants this one */ 337 } 338 if (i == numifs || user_if[i] == NULL) 339 continue; /* skip this interface */ 340 } else if (strchr(ifr->ifr_name, ':') != NULL) 341 continue; /* skip virtual interfaces */ 342 343 ifp = (IF *)smalloc(sizeof (IF)); 344 (void) strcpy(ifp->nm, ifr->ifr_name); 345 346 ifp->ifceno = if_nametoindex(ifp->nm); 347 ifp->flags = ifr->ifr_flags; 348 for (k = 0; k < DSRVR_NUM_DESC; k++) 349 ifp->descs[k] = -1; 350 351 /* 352 * Broadcast address. Not valid for POINTOPOINT 353 * connections. 354 */ 355 if ((ifp->flags & IFF_POINTOPOINT) == 0) { 356 if (ifp->flags & IFF_BROADCAST) { 357 if (ioctl(ip, SIOCGIFBRDADDR, ifr) < 0) { 358 dhcpmsg(LOG_ERR, "Error encountered \ 359 getting interface: %s broadcast address: %s\n", ifp->nm, strerror(errno)); 360 free(ifp); 361 num_interfaces--; 362 continue; 363 } 364 /* LINTED [alignment ok] */ 365 sin = (struct sockaddr_in *)&ifr->ifr_addr; 366 ifp->bcast = sin->sin_addr; 367 } else 368 ifp->bcast.s_addr = htonl(INADDR_ANY); 369 370 hecp = make_encode(DSYM_STANDARD, CD_BROADCASTADDR, 371 sizeof (struct in_addr), &ifp->bcast, 372 ENC_COPY); 373 replace_encode(&ifp->ecp, hecp, ENC_DONT_COPY); 374 } 375 376 /* Subnet mask */ 377 if (ioctl(ip, SIOCGIFNETMASK, ifr) < 0) { 378 dhcpmsg(LOG_ERR, "Error encountered getting \ 379 interface: %s netmask: %s\n", ifp->nm, strerror(errno)); 380 free_encode_list(ifp->ecp); 381 free(ifp); 382 num_interfaces--; 383 continue; 384 } 385 /* LINTED [alignment ok] */ 386 sin = (struct sockaddr_in *)&ifr->ifr_addr; 387 ifp->mask = sin->sin_addr; 388 hecp = make_encode(DSYM_STANDARD, CD_SUBNETMASK, 389 sizeof (struct in_addr), &ifp->mask, ENC_COPY); 390 replace_encode(&ifp->ecp, hecp, ENC_DONT_COPY); 391 392 /* Address */ 393 if (ioctl(ip, SIOCGIFADDR, ifr) < 0) { 394 dhcpmsg(LOG_ERR, "Error encountered getting \ 395 interface: %s address: %s\n", ifp->nm, strerror(errno)); 396 free_encode_list(ifp->ecp); 397 free(ifp); 398 num_interfaces--; 399 continue; 400 } 401 /* LINTED [alignment ok] */ 402 sin = (struct sockaddr_in *)&ifr->ifr_addr; 403 ifp->addr = sin->sin_addr; 404 405 /* MTU */ 406 if (ioctl(ip, SIOCGIFMTU, ifr) < 0) { 407 dhcpmsg(LOG_ERR, "Error encountered getting \ 408 interface: %s MTU: %s\n", ifp->nm, strerror(errno)); 409 free_encode_list(ifp->ecp); 410 free(ifp); 411 num_interfaces--; 412 continue; 413 } 414 415 ifp->mtu = ifr->ifr_metric; 416 mtu_tmp = htons(ifp->mtu); 417 hecp = make_encode(DSYM_STANDARD, CD_MTU, 2, 418 &mtu_tmp, ENC_COPY); 419 replace_encode(&ifp->ecp, hecp, ENC_DONT_COPY); 420 421 /* Attach to interface list */ 422 if (!if_tail) { 423 (void) mutex_init(&if_head_mtx, USYNC_THREAD, 0); 424 (void) mutex_lock(&if_head_mtx); 425 if_tail = if_head = ifp; 426 (void) mutex_unlock(&if_head_mtx); 427 } else { 428 (void) mutex_lock(&if_head_mtx); 429 if_tail->next = ifp; 430 if_tail = ifp; 431 (void) mutex_unlock(&if_head_mtx); 432 } 433 } 434 435 free(reqbuf); 436 free(user_if); 437 (void) close(ip); 438 439 if (if_head == NULL) { 440 num_interfaces = 0; 441 dhcpmsg(LOG_ERR, "Cannot find any valid interfaces.\n"); 442 (void) mutex_destroy(&if_head_mtx); 443 return (EINVAL); 444 } 445 return (0); 446 } 447 448 /* 449 * Destroy an *uninitialized* IF structure - returns next ifp. 450 */ 451 static IF * 452 zap_ifp(IF **ifp_prevpp, IF *ifp) 453 { 454 IF *tifp; 455 456 assert(MUTEX_HELD(&if_head_mtx)); 457 458 if (*ifp_prevpp == ifp) { 459 if_head = ifp->next; 460 *ifp_prevpp = if_head; 461 } else 462 (*ifp_prevpp)->next = ifp->next; 463 464 tifp = ifp->next; 465 466 free(ifp); 467 468 return (tifp); 469 } 470 471 /* 472 * Monitor thread function. Poll on interface descriptors. Add valid BOOTP 473 * packets to interfaces PKT_LIST. 474 * 475 * Because the buffer will potentially contain the ip/udp headers, we flag 476 * this by setting the 'offset' field to the length of the two headers so that 477 * free_plp() can "do the right thing" 478 * 479 * Monitor the given interface. Signals are handled by sig_client thread. 480 * 481 * We make some attempt to deal with marginal interfaces as follows. We 482 * keep track of system errors (errors) and protocol errors (ifp->errors). 483 * If we encounter more than DHCP_MON_SYSERRS in DHCP_MON_ERRINTVL, 484 * then the interface thread will put itself to sleep for DHCP_MON_SLEEP 485 * minutes. 486 * 487 * MT SAFE 488 */ 489 static void * 490 monitor_interface(void *argp) 491 { 492 PKT_LIST *plp, *tplp; 493 IF *ifp = (IF *)argp; 494 int errors, err, i; 495 uint_t verify_len; 496 struct pollfd pfd[DSRVR_NUM_DESC]; 497 struct strbuf data; 498 char cbuf[DN_MAX_CID_LEN], ntoab[INET_ADDRSTRLEN]; 499 time_t err_interval; 500 dn_rec_t dn; 501 dsvc_dnet_t *pnd; 502 dsvc_clnt_t *pcd; 503 struct in_addr netaddr, subnetaddr; 504 dsvc_pendclnt_t *workp; 505 int open_ret; 506 dsvc_thr_t *freep; 507 thread_t tid; 508 boolean_t existing_allocation; 509 510 if (debug) { 511 dhcpmsg(LOG_DEBUG, "Monitor (%04d/%s) started...\n", 512 ifp->if_thread, ifp->nm); 513 } 514 515 if (verbose) 516 disp_if(ifp); 517 518 pfd[DSRVR_LBCAST].fd = ifp->descs[DSRVR_LBCAST]; 519 pfd[DSRVR_LBCAST].events = POLLIN | POLLPRI; 520 pfd[DSRVR_DBCAST].fd = ifp->descs[DSRVR_DBCAST]; 521 pfd[DSRVR_DBCAST].events = POLLIN | POLLPRI; 522 pfd[DSRVR_UCAST].fd = ifp->descs[DSRVR_UCAST]; 523 pfd[DSRVR_UCAST].events = POLLIN | POLLPRI; 524 525 err_interval = time(NULL) + DHCP_MON_ERRINTVL; 526 errors = 0; 527 while (time_to_go == 0) { 528 if (errors > DHCP_MON_SYSERRS) { 529 if (time(NULL) < err_interval) { 530 dhcpmsg(LOG_WARNING, 531 "Monitor (%04d/%s): Too many system errors (%d), pausing for %d minute(s)...\n", 532 ifp->if_thread, ifp->nm, errors, 533 DHCP_MON_SYSERRS); 534 (void) sleep(DHCP_MON_SLEEP); 535 err_interval = time(NULL) + DHCP_MON_ERRINTVL; 536 } 537 errors = 0; 538 } 539 pfd[DSRVR_LBCAST].revents = 0; 540 pfd[DSRVR_DBCAST].revents = 0; 541 pfd[DSRVR_UCAST].revents = 0; 542 if (poll(&pfd[0], (nfds_t)DSRVR_NUM_DESC, INFTIM) < 0) { 543 dhcpmsg(LOG_ERR, 544 "Monitor (%04d/%s) Polling error: (%s).\n", 545 ifp->if_thread, ifp->nm, strerror(errno)); 546 errors++; 547 continue; 548 } 549 /* 550 * See if we are to exit. We can't be holding any locks... 551 */ 552 (void) mutex_lock(&ifp->ifp_mtx); 553 if (ifp->thr_exit) { 554 if (debug) { 555 dhcpmsg(LOG_DEBUG, 556 "Monitor (%04d/%s): exiting.\n", 557 ifp->if_thread, ifp->nm); 558 } 559 (void) mutex_unlock(&ifp->ifp_mtx); 560 break; 561 } 562 (void) mutex_unlock(&ifp->ifp_mtx); 563 564 /* examine each socket for packets in turn */ 565 for (i = 0; i < DSRVR_NUM_DESC; i++) { 566 if (pfd[i].revents == 0) 567 continue; 568 if (pfd[i].revents & (POLLERR | POLLHUP | POLLNVAL)) { 569 dhcpmsg(LOG_ERR, "Network interface " 570 "error on device: %s(%s)\n", ifp->nm, 571 dsrvr_socktype(i)); 572 errors++; 573 continue; 574 } 575 if (!(pfd[i].revents & (POLLIN | POLLRDNORM))) { 576 dhcpmsg(LOG_INFO, "Unsupported event " 577 "on device %s(%s): %d\n", ifp->nm, 578 dsrvr_socktype(i), 579 pfd[i].revents); 580 errors++; 581 continue; 582 } 583 data.buf = smalloc(ifp->mtu); 584 data.len = recv(ifp->descs[i], data.buf, ifp->mtu, 0); 585 if (data.len < 0) { 586 dhcpmsg(LOG_ERR, "Error: %s receiving UDP " 587 "datagrams on %s(%s)\n", 588 strerror(errno), ifp->nm, 589 dsrvr_socktype(i)); 590 free(data.buf); 591 errors++; 592 continue; 593 } else 594 verify_len = data.len; 595 596 if (debug) { 597 dhcpmsg(LOG_INFO, 598 "Datagram received on network device: " 599 "%s(%s)\n", ifp->nm, dsrvr_socktype(i)); 600 } 601 602 (void) mutex_lock(&ifp->ifp_mtx); 603 ifp->received++; 604 (void) mutex_unlock(&ifp->ifp_mtx); 605 606 if (verify_len < BASE_PKT_SIZE) { 607 if (verbose) { 608 dhcpmsg(LOG_INFO, "Short packet %d < " 609 "%d on %s(%s) ignored\n", 610 verify_len, sizeof (PKT), 611 ifp->nm, dsrvr_socktype(i)); 612 } 613 free(data.buf); 614 (void) mutex_lock(&ifp->ifp_mtx); 615 ifp->errors++; 616 (void) mutex_unlock(&ifp->ifp_mtx); 617 continue; 618 } 619 620 plp = (PKT_LIST *)smalloc(sizeof (PKT_LIST)); 621 plp->offset = 0; 622 plp->len = data.len; 623 /* LINTED [alignment ok] */ 624 plp->pkt = (PKT *)data.buf; 625 626 if (plp->pkt->hops >= max_hops + 1) { 627 if (verbose) { 628 dhcpmsg(LOG_INFO, "%s(%s): Packet " 629 "dropped: too many hops: %d\n", 630 ifp->nm, dsrvr_socktype(i), 631 plp->pkt->hops); 632 } 633 free_plp(plp); 634 (void) mutex_lock(&ifp->ifp_mtx); 635 ifp->errors++; 636 (void) mutex_unlock(&ifp->ifp_mtx); 637 continue; 638 } 639 640 /* validate hardware len */ 641 if (plp->pkt->hlen > sizeof (plp->pkt->chaddr)) 642 plp->pkt->hlen = sizeof (plp->pkt->chaddr); 643 644 if (debug && plp->pkt->giaddr.s_addr != 0L && 645 plp->pkt->giaddr.s_addr != ifp->addr.s_addr) { 646 dhcpmsg(LOG_INFO, "%s(%s): Packet received " 647 "from relay agent: %s\n", ifp->nm, 648 dsrvr_socktype(i), inet_ntop(AF_INET, 649 &plp->pkt->giaddr, ntoab, sizeof (ntoab))); 650 } 651 652 if (!server_mode) { 653 /* 654 * Relay agent mode. No further processing 655 * required ; we'll handle it here. 656 */ 657 (void) mutex_lock(&if_head_mtx); 658 err = relay_agent(ifp, plp); 659 (void) mutex_unlock(&if_head_mtx); 660 if (err != 0) { 661 dhcpmsg(LOG_ERR, "Relay agent mode " 662 "failed: %d (%s) on: %s(%s)\n", 663 err, (plp->pkt->op == BOOTREPLY) ? 664 "reply" : "request", ifp->nm, 665 dsrvr_socktype(i)); 666 errors++; /* considered system error */ 667 } else { 668 /* update statistics */ 669 (void) mutex_lock(&ifp->ifp_mtx); 670 ifp->processed++; 671 ifp->received++; 672 (void) mutex_unlock(&ifp->ifp_mtx); 673 } 674 free_plp(plp); 675 continue; 676 } 677 678 /* ============ Packets destined for bootp and dhcp server modules ========== */ 679 680 /* 681 * Allow packets without RFC1048 magic cookies. 682 * Just don't do an options scan on them, 683 * thus we treat them as plain BOOTP packets. 684 * The BOOTP server can deal with requests of 685 * this type. 686 */ 687 if (memcmp(plp->pkt->cookie, magic_cookie, 688 sizeof (magic_cookie)) != 0) { 689 if (verbose) { 690 dhcpmsg(LOG_INFO, "%s(%s): Client: %s " 691 "using non-RFC1048 BOOTP cookie.\n", 692 ifp->nm, dsrvr_socktype(i), 693 disp_cid(plp, cbuf, sizeof (cbuf))); 694 } 695 plp->rfc1048 = B_FALSE; 696 } else { 697 /* 698 * Scan the options in the packet and fill in 699 * the opts and vs fields in the * clientlist 700 * structure. If there's a DHCP message type 701 * in the packet then it's a DHCP packet; 702 * otherwise it's a BOOTP packet. Standard 703 * options are RFC1048 style. 704 */ 705 if (dhcp_options_scan(plp, B_FALSE) != 0) { 706 dhcpmsg(LOG_ERR, "Garbled DHCP/BOOTP " 707 "packet received on: %s(%s)\n", 708 ifp->nm, dsrvr_socktype(i)); 709 free_plp(plp); 710 (void) mutex_lock(&ifp->ifp_mtx); 711 ifp->errors++; 712 (void) mutex_unlock(&ifp->ifp_mtx); 713 continue; 714 } 715 plp->rfc1048 = B_TRUE; 716 } 717 718 /* 719 * Link the new packet to the list of packets 720 * for this network/client. No need to lock plp, 721 * since it isn't visible outside this function yet. 722 */ 723 if (plp->pkt->op != BOOTREQUEST) { 724 dhcpmsg(LOG_ERR, "Unexpected packet received " 725 "on %s(%s), BOOTP server port. Ignored.\n", 726 ifp->nm, dsrvr_socktype(i)); 727 free_plp(plp); 728 (void) mutex_lock(&ifp->ifp_mtx); 729 ifp->errors++; 730 (void) mutex_unlock(&ifp->ifp_mtx); 731 continue; 732 } 733 734 determine_network(ifp, plp, &netaddr, &subnetaddr); 735 if ((err = open_dnet(&pnd, &netaddr, &subnetaddr)) != 736 DSVC_SUCCESS) { 737 if (verbose && err == DSVC_NO_TABLE) { 738 netaddr.s_addr &= subnetaddr.s_addr; 739 dhcpmsg(LOG_INFO, "%s(%s): There is no " 740 "%s dhcp-network table for DHCP " 741 "client's network.\n", ifp->nm, 742 dsrvr_socktype(i), 743 inet_ntop(AF_INET, &netaddr, 744 ntoab, sizeof (ntoab))); 745 } 746 free_plp(plp); 747 continue; 748 } 749 750 /* Find client */ 751 get_clnt_id(plp, (uchar_t *)dn.dn_cid, 752 sizeof (dn.dn_cid), &dn.dn_cid_len); 753 open_ret = open_clnt(pnd, &pcd, dn.dn_cid, 754 dn.dn_cid_len, B_FALSE); 755 756 if (pcd == NULL) { 757 free_plp(plp); 758 close_dnet(pnd, B_FALSE); 759 continue; 760 } 761 762 /* 763 * DOS via Packet flooding: ensure that each client's 764 * PKT_LIST never exceeds DHCP_MON_THRESHOLD pkts in 765 * length. If it does, we prune it from the head of 766 * the list, dropping sequential packets. Note that 767 * since DHCP is a multi-transaction protocol, we would 768 * like to be sure not to discard a REQUEST for an OFFER 769 * we've extended. 770 * 771 * TODO: we are still vulnerable to flooding attacks 772 * where bogus client ids are presented. This can be 773 * manually controlled via the MAX_CLIENTS and 774 * MAX_THREADS config file knobs. 775 */ 776 (void) mutex_lock(&pcd->pkt_mtx); 777 if (pcd->pending > DHCP_MON_THRESHOLD) { 778 if ((tplp = pcd->pkthead) != NULL) { 779 detach_plp(pcd, tplp); 780 free_plp(tplp); 781 pcd->pending--; 782 } 783 } 784 785 if (pcd->pkthead == NULL) 786 pcd->pkthead = plp; 787 else { 788 pcd->pkttail->next = plp; 789 plp->prev = pcd->pkttail; 790 } 791 pcd->pkttail = plp; 792 pcd->pending++; 793 (void) mutex_unlock(&pcd->pkt_mtx); 794 795 /* 796 * Manage worker threads and deferred thread work list. 797 */ 798 (void) mutex_lock(&pcd->pcd_mtx); 799 pcd->ifp = ifp; 800 if (pcd->clnt_thread == NULL && 801 (pcd->flags & DHCP_PCD_CLOSING) == 0) { 802 existing_allocation = B_FALSE; 803 (void) mutex_lock(&pnd->thr_mtx); 804 if ((freep = pnd->thrhead) != NULL) { 805 existing_allocation = B_TRUE; 806 /* 807 * Restart a suspended thread. 808 */ 809 pnd->thrhead = freep->thr_next; 810 if (pnd->thrhead == NULL) 811 pnd->thrtail = NULL; 812 (void) mutex_unlock(&pnd->thr_mtx); 813 814 (void) mutex_lock(&freep->thr_mtx); 815 freep->thr_flags &= ~DHCP_THR_LIST; 816 freep->thr_next = NULL; 817 freep->thr_pcd = pcd; 818 (void) mutex_unlock(&freep->thr_mtx); 819 pcd->clnt_thread = freep; 820 } else if (max_threads != -1 && 821 pnd->nthreads >= max_threads) { 822 /* 823 * Add client once to deferred work 824 * list, to keep track of future work. 825 */ 826 if ((pcd->flags & DHCP_PCD_WORK) == 0) { 827 pcd->flags |= DHCP_PCD_WORK; 828 workp = (dsvc_pendclnt_t *) 829 smalloc( 830 sizeof (dsvc_pendclnt_t)); 831 get_clnt_id(plp, 832 (uchar_t *)workp->pnd_cid, 833 sizeof (workp->pnd_cid), 834 &workp->pnd_cid_len); 835 if (pnd->workhead == NULL) 836 pnd->workhead = workp; 837 else { 838 pnd->worktail-> 839 pnd_next = workp; 840 } 841 pnd->worktail = workp; 842 } 843 (void) mutex_unlock(&pnd->thr_mtx); 844 (void) mutex_unlock(&pcd->pcd_mtx); 845 if (open_ret == DSVC_SUCCESS) 846 close_clnt(pcd, B_FALSE); 847 close_dnet(pnd, B_FALSE); 848 continue; 849 } 850 if (pcd->clnt_thread == NULL) { 851 pnd->nthreads++; 852 (void) mutex_unlock(&pnd->thr_mtx); 853 freep = pcd->clnt_thread = 854 (dsvc_thr_t *) 855 smalloc(sizeof (dsvc_thr_t)); 856 (void) mutex_init(&freep->thr_mtx, 857 USYNC_THREAD, 0); 858 freep->thr_pcd = pcd; 859 860 /* Fire up a client thread. */ 861 if (thr_create(NULL, 0, monitor_client, 862 freep, THR_BOUND | THR_SUSPENDED | 863 THR_DETACHED, &freep->thr_tid) != 864 0) { 865 dhcpmsg(LOG_ERR, "%s(%s): " 866 "Error %s starting client " 867 "monitor thread.\n", 868 ifp->nm, dsrvr_socktype(i), 869 strerror(errno)); 870 (void) mutex_lock( 871 &pnd->thr_mtx); 872 pnd->nthreads--; 873 (void) mutex_unlock( 874 &pnd->thr_mtx); 875 free(freep); 876 freep = pcd->clnt_thread = NULL; 877 } 878 } 879 if (freep != NULL) { 880 /* 881 * Continue the new or reused thread. 882 * Let it close the client. 883 */ 884 open_ret = DSVC_BUSY; 885 tid = freep->thr_tid; 886 (void) mutex_unlock(&pcd->pcd_mtx); 887 pcd = NULL; 888 if (existing_allocation) { 889 (void) cond_signal( 890 &freep->thr_cv); 891 } else { 892 (void) thr_continue(tid); 893 } 894 } 895 } 896 if (pcd != NULL) { 897 (void) mutex_unlock(&pcd->pcd_mtx); 898 if (open_ret == DSVC_SUCCESS) 899 close_clnt(pcd, B_FALSE); 900 } 901 close_dnet(pnd, B_FALSE); 902 } 903 } 904 return (NULL); 905 } 906 907 /* 908 * close interface sockets 909 */ 910 static void 911 close_sockets(IF *ifp) { 912 int i; 913 914 for (i = 0; i < DSRVR_NUM_DESC; i++) { 915 if (ifp->descs[i] == -1) 916 continue; 917 (void) close(ifp->descs[i]); 918 ifp->descs[i] = -1; 919 } 920 } 921 922 /* 923 * initialize interface sockets. 924 * 925 * Returns: 0 for success, -1 otherwise. 926 */ 927 static int 928 init_sockets(IF *ifp) 929 { 930 int i, soptbuf = 1; 931 struct sockaddr_in sin; 932 933 sin.sin_family = AF_INET; 934 sin.sin_port = htons((short)IPPORT_BOOTPS + port_offset); 935 936 ifp->descs[DSRVR_LBCAST] = -1; 937 ifp->descs[DSRVR_DBCAST] = -1; 938 ifp->descs[DSRVR_UCAST] = -1; 939 940 for (i = 0; i < DSRVR_NUM_DESC; i++) { 941 ifp->descs[i] = socket(AF_INET, SOCK_DGRAM, 0); 942 if (ifp->descs[i] < 0) { 943 dhcpmsg(LOG_ERR, "Error opening socket on %s(%s) for " 944 "receiving UDP datagrams: %s\n", 945 ifp->nm, dsrvr_socktype(i), strerror(errno)); 946 return (-1); 947 } 948 949 if (setsockopt(ifp->descs[i], SOL_SOCKET, SO_REUSEADDR, 950 &soptbuf, (int)sizeof (soptbuf)) < 0) { 951 dhcpmsg(LOG_DEBUG, "Setting socket option on %s(%s) " 952 "to allow reuse on send descriptor failed: %s\n", 953 ifp->nm, dsrvr_socktype(i), strerror(errno)); 954 close_sockets(ifp); 955 return (-1); 956 } 957 958 (void) setsockopt(ifp->descs[i], SOL_SOCKET, SO_RCVBUF, 959 &socksize, sizeof (socksize)); 960 (void) setsockopt(ifp->descs[i], SOL_SOCKET, SO_SNDBUF, 961 &socksize, sizeof (socksize)); 962 963 switch (i) { 964 case DSRVR_LBCAST: 965 if (setsockopt(ifp->descs[i], IPPROTO_IP, 966 IP_BOUND_IF, &ifp->ifceno, 967 (int)sizeof (char *)) < 0) { 968 dhcpmsg(LOG_ERR, 969 "Bind to index failed on %s: %s\n", 970 ifp->nm, strerror(errno)); 971 close_sockets(ifp); 972 return (-1); 973 } 974 sin.sin_addr.s_addr = htonl(INADDR_BROADCAST); 975 break; 976 case DSRVR_DBCAST: 977 sin.sin_addr.s_addr = 978 ifp->addr.s_addr & ifp->mask.s_addr; 979 break; 980 case DSRVR_UCAST: 981 /* We send out the unicast socket */ 982 if (setsockopt(ifp->descs[i], SOL_SOCKET, 983 SO_BROADCAST, &soptbuf, 984 (int)sizeof (soptbuf)) < 0) { 985 dhcpmsg(LOG_ERR, "Setting socket " 986 "option on %s to allow broadcast " 987 "on send descriptor failed: %s\n", 988 ifp->nm, strerror(errno)); 989 close_sockets(ifp); 990 return (-1); 991 } 992 sin.sin_addr.s_addr = ifp->addr.s_addr; 993 break; 994 } 995 if (bind(ifp->descs[i], 996 (struct sockaddr *)&sin, sizeof (sin)) < 0) { 997 dhcpmsg(LOG_ERR, 998 "Error binding to UDP socket on %s(%s): %s\n", 999 ifp->nm, dsrvr_socktype(i), strerror(errno)); 1000 close_sockets(ifp); 1001 return (-1); 1002 } 1003 } 1004 return (0); 1005 } 1006 1007 /* 1008 * Based on the list generated by find_interfaces(), possibly modified by 1009 * user arguments, open a stream for each valid / requested interface. 1010 * 1011 * If: 1012 * 1013 * 1) Only one interface exists, open a standard bidirectional UDP 1014 * socket. Note that this is different than if only ONE 1015 * interface is requested (but more exist). 1016 * 1017 * 2) If more than one valid interface exists, then attach to the 1018 * datalink layer, push on the packet filter and buffering 1019 * modules, and wait for fragment 0 IP packets that contain 1020 * UDP packets with port 67 (server port). 1021 * 1022 * Comments: 1023 * Using DLPI to identify the interface thru which BOOTP 1024 * packets pass helps in providing the correct response. 1025 * Note that I will open a socket for use in transmitting 1026 * responses, suitably specifying the destination relay agent 1027 * or host. Note that if I'm unicasting to the client (broadcast 1028 * flag not set), that somehow I have to clue the IP layer about 1029 * the client's hw address. The only way I can see doing this is 1030 * making the appropriate ARP table entry. 1031 * 1032 * The only remaining unknown is dealing with clients that 1033 * require broadcasting, and multiple interfaces exist. I assume 1034 * that if I specify the interface's source address when 1035 * opening the socket, that a limited broadcast will be 1036 * directed to the correct net, and only the correct net. 1037 * 1038 * Returns: 0 for success, non-zero for failure. 1039 */ 1040 int 1041 open_interfaces(void) 1042 { 1043 int inum, err = 0; 1044 IF *ifp, *ifp_prevp; 1045 1046 /* Uncover list of valid, user-selected interfaces to monitor */ 1047 if ((err = find_interfaces()) != 0) 1048 return (err); 1049 1050 (void) mutex_lock(&if_head_mtx); 1051 1052 /* 1053 * Setup valid interfaces. 1054 */ 1055 ifp = ifp_prevp = if_head; 1056 err = inum = 0; 1057 while (ifp != NULL) { 1058 if (init_sockets(ifp) < 0) { 1059 ifp = zap_ifp(&ifp_prevp, ifp); 1060 num_interfaces--; 1061 continue; 1062 } 1063 1064 /* Accounting */ 1065 ifp->transmit = ifp->received = 0; 1066 ifp->duplicate = ifp->dropped = 0; 1067 ifp->processed = 0; 1068 1069 /* ifp structure lock */ 1070 (void) mutex_init(&ifp->ifp_mtx, USYNC_THREAD, 0); 1071 ifp->thr_exit = 0; 1072 1073 /* fire up monitor thread */ 1074 if (thr_create(NULL, 0, monitor_interface, ifp, 1075 THR_BOUND, &ifp->if_thread) != 0) { 1076 dhcpmsg(LOG_ERR, 1077 "Interface: %s - Error %s starting monitor thread.\n", ifp->nm, 1078 strerror(errno)); 1079 close_sockets(ifp); 1080 (void) mutex_destroy(&ifp->ifp_mtx); 1081 ifp = zap_ifp(&ifp_prevp, ifp); 1082 num_interfaces--; 1083 continue; 1084 } 1085 inum++; 1086 ifp_prevp = ifp; 1087 ifp = ifp->next; 1088 } 1089 (void) mutex_unlock(&if_head_mtx); 1090 1091 /* 1092 * We must succeed in configuring at least one interface 1093 * to be considered successful. 1094 */ 1095 if (num_interfaces == 0) { 1096 err = EINVAL; 1097 dhcpmsg(LOG_ERR, "Cannot configure any interfaces.\n"); 1098 } 1099 return (err); 1100 } 1101 1102 /* 1103 * Detach the referenced plp from the client list. 1104 */ 1105 void 1106 detach_plp(dsvc_clnt_t *pcd, PKT_LIST *plp) 1107 { 1108 assert(MUTEX_HELD(&pcd->pkt_mtx)); 1109 1110 if (plp->prev == NULL) { 1111 pcd->pkthead = plp->next; 1112 if (pcd->pkthead != NULL) 1113 pcd->pkthead->prev = NULL; 1114 } else 1115 plp->prev->next = plp->next; 1116 1117 if (plp->next != NULL) 1118 plp->next->prev = plp->prev; 1119 else { 1120 pcd->pkttail = plp->prev; 1121 if (pcd->pkttail != NULL) 1122 pcd->pkttail->next = NULL; 1123 } 1124 plp->prev = plp->next = NULL; 1125 } 1126 1127 /* 1128 * Write a packet to an interface. 1129 * 1130 * Returns 0 on success otherwise non-zero. 1131 */ 1132 int 1133 write_interface(IF *ifp, PKT *clientp, int len, struct sockaddr_in *to) 1134 { 1135 int err; 1136 1137 to->sin_family = AF_INET; 1138 1139 if ((err = sendto(ifp->descs[DSRVR_UCAST], clientp, len, 0, 1140 (struct sockaddr *)to, sizeof (struct sockaddr))) < 0) { 1141 dhcpmsg(LOG_ERR, "SENDTO: %s.\n", strerror(errno)); 1142 return (err); 1143 } 1144 1145 (void) mutex_lock(&ifp->ifp_mtx); 1146 ifp->transmit++; 1147 (void) mutex_unlock(&ifp->ifp_mtx); 1148 1149 return (0); 1150 } 1151 1152 /* 1153 * Pop any packet filters, buffering modules, close stream, free encode 1154 * list, terminate monitor thread, free ifp. Return ifp next ptr. 1155 */ 1156 static IF * 1157 close_interface(IF *ifp) 1158 { 1159 int err; 1160 IF *tifp; 1161 1162 assert(ifp != NULL); 1163 1164 assert(MUTEX_HELD(&if_head_mtx)); 1165 1166 (void) mutex_lock(&ifp->ifp_mtx); 1167 ifp->thr_exit = 1; 1168 1169 close_sockets(ifp); /* thread will exit poll ... */ 1170 (void) mutex_unlock(&ifp->ifp_mtx); 1171 1172 /* 1173 * Wait for the thread to exit. We release the if_head_mtx 1174 * lock, since the monitor thread(s) need to acquire it to traverse 1175 * the list - and we don't want to deadlock. Once the monitor thread 1176 * notices the thr_exit flag, it'll be gone anyway. Note that if_head 1177 * is changing (in close_interfaces()). At this point, only monitor 1178 * threads that haven't been reaped could be walking the interface 1179 * list. They will "see" the change in if_head. 1180 */ 1181 (void) mutex_unlock(&if_head_mtx); 1182 if ((err = thr_join(ifp->if_thread, NULL, NULL)) != 0) { 1183 dhcpmsg(LOG_ERR, 1184 "Error %d while waiting for monitor %d of %s\n", 1185 err, ifp->if_thread, ifp->nm); 1186 } 1187 (void) mutex_lock(&if_head_mtx); 1188 1189 /* 1190 * Note: clients and their associated packet lists are freed prior 1191 * to interfaces being closed. 1192 */ 1193 1194 /* free encode list */ 1195 free_encode_list(ifp->ecp); 1196 1197 /* display statistics */ 1198 disp_if_stats(ifp); 1199 1200 ifp->received = ifp->processed = 0; 1201 1202 (void) mutex_unlock(&ifp->ifp_mtx); 1203 (void) mutex_destroy(&ifp->ifp_mtx); 1204 tifp = ifp->next; 1205 free(ifp); 1206 return (tifp); 1207 } 1208 1209 /* 1210 * Close all interfaces, freeing up associated resources. 1211 * This should only be called from main() during final exit. 1212 */ 1213 void 1214 close_interfaces(void) 1215 { 1216 (void) mutex_lock(&if_head_mtx); 1217 for (; if_head != NULL; if_head = close_interface(if_head)) { 1218 if (verbose) { 1219 dhcpmsg(LOG_INFO, "Closing interface: %s\n", 1220 if_head->nm); 1221 } 1222 } 1223 (void) mutex_unlock(&if_head_mtx); 1224 (void) mutex_destroy(&if_head_mtx); 1225 } 1226 1227 /* 1228 * display IF info. Must be MT Safe - called from monitor threads. 1229 */ 1230 static void 1231 disp_if(IF *ifp) 1232 { 1233 char ntoab[INET_ADDRSTRLEN]; 1234 1235 dhcpmsg(LOG_INFO, "Thread Id: %04d - Monitoring Interface: %s *****\n", 1236 ifp->if_thread, ifp->nm); 1237 dhcpmsg(LOG_INFO, "MTU: %d\tType: %s\n", ifp->mtu, "SOCKET"); 1238 if ((ifp->flags & IFF_POINTOPOINT) == 0) 1239 dhcpmsg(LOG_INFO, "Broadcast: %s\n", 1240 inet_ntop(AF_INET, &ifp->bcast, ntoab, sizeof (ntoab))); 1241 dhcpmsg(LOG_INFO, "Netmask: %s\n", 1242 inet_ntop(AF_INET, &ifp->mask, ntoab, sizeof (ntoab))); 1243 dhcpmsg(LOG_INFO, "Address: %s\n", 1244 inet_ntop(AF_INET, &ifp->addr, ntoab, sizeof (ntoab))); 1245 } 1246 1247 /* 1248 * Display IF statistics. 1249 */ 1250 void 1251 disp_if_stats(IF *ifp) 1252 { 1253 dhcpmsg(LOG_INFO, "Interface statistics for: %s **************\n", 1254 ifp->nm); 1255 1256 dhcpmsg(LOG_INFO, "Pending DHCP offers: %d\n", ifp->offers); 1257 dhcpmsg(LOG_INFO, "Total Packets Transmitted: %d\n", ifp->transmit); 1258 dhcpmsg(LOG_INFO, "Total Packets Received: %d\n", ifp->received); 1259 dhcpmsg(LOG_INFO, "Total Packet Duplicates: %d\n", ifp->duplicate); 1260 dhcpmsg(LOG_INFO, "Total Packets Dropped: %d\n", ifp->dropped); 1261 dhcpmsg(LOG_INFO, "Total Packets Processed: %d\n", ifp->processed); 1262 dhcpmsg(LOG_INFO, "Total Protocol Errors: %d\n", ifp->errors); 1263 } 1264 1265 /* 1266 * Setup the arp cache so that IP address 'ia' will be temporarily 1267 * bound to hardware address 'ha' of length 'len'. 'ia' is expected in 1268 * network order. 1269 * 1270 * Returns: 0 if the arp entry was made, 1 otherwise. 1271 */ 1272 int 1273 set_arp(IF *ifp, struct in_addr *ia, uchar_t *ha, int len, uchar_t flags) 1274 { 1275 struct sockaddr_in *si; 1276 struct xarpreq arpreq; 1277 int err = 0; 1278 char scratch[DHCP_SCRATCH]; 1279 uint_t scratch_len; 1280 char ntoab[INET_ADDRSTRLEN]; 1281 1282 (void) memset((caddr_t)&arpreq, 0, sizeof (arpreq)); 1283 1284 arpreq.xarp_ha.sdl_family = AF_LINK; 1285 1286 si = (struct sockaddr_in *)&arpreq.xarp_pa; 1287 si->sin_family = AF_INET; 1288 si->sin_addr = *ia; /* struct copy */ 1289 1290 switch (flags) { 1291 case DHCP_ARP_ADD: 1292 if (debug) { 1293 scratch_len = sizeof (scratch); 1294 if (octet_to_hexascii(ha, len, scratch, 1295 &scratch_len) != 0) { 1296 dhcpmsg(LOG_DEBUG, "Cannot convert ARP \ 1297 request to ASCII: %s: len: %d\n", 1298 inet_ntop(AF_INET, ia, 1299 ntoab, sizeof (ntoab)), 1300 len); 1301 } else { 1302 dhcpmsg(LOG_DEBUG, 1303 "Adding ARP entry: %s == %s\n", 1304 inet_ntop(AF_INET, ia, 1305 ntoab, sizeof (ntoab)), 1306 scratch); 1307 } 1308 } 1309 arpreq.xarp_flags = ATF_INUSE | ATF_COM; 1310 (void) memcpy(LLADDR(&arpreq.xarp_ha), ha, len); 1311 arpreq.xarp_ha.sdl_alen = len; 1312 1313 if (ioctl(ifp->descs[DSRVR_UCAST], SIOCSXARP, &arpreq) < 0) { 1314 dhcpmsg(LOG_ERR, 1315 "ADD: Cannot modify ARP table to add: %s\n", 1316 inet_ntop(AF_INET, ia, ntoab, sizeof (ntoab))); 1317 err = 1; 1318 } 1319 break; 1320 case DHCP_ARP_DEL: 1321 /* give it a good effort, but don't worry... */ 1322 (void) ioctl(ifp->descs[DSRVR_UCAST], SIOCDXARP, &arpreq); 1323 break; 1324 default: 1325 err = 1; 1326 break; 1327 } 1328 1329 return (err); 1330 } 1331 1332 /* 1333 * Address and send a BOOTP reply packet appropriately. Does right thing 1334 * based on BROADCAST flag. Also checks if giaddr field is set, and 1335 * WE are the relay agent... 1336 * 1337 * Returns: 0 for success, nonzero otherwise (fatal) 1338 */ 1339 int 1340 send_reply(IF *ifp, PKT *pp, int len, struct in_addr *dstp) 1341 { 1342 int local = B_FALSE; 1343 struct sockaddr_in to; 1344 struct in_addr if_in, cl_in; 1345 char ntoab[INET_ADDRSTRLEN]; 1346 1347 if (pp->giaddr.s_addr != 0L && ifp->addr.s_addr != 1348 pp->giaddr.s_addr) { 1349 /* Going thru a relay agent */ 1350 to.sin_addr.s_addr = pp->giaddr.s_addr; 1351 to.sin_port = htons(IPPORT_BOOTPS + port_offset); 1352 } else { 1353 to.sin_port = htons(IPPORT_BOOTPC + port_offset); 1354 1355 if (ntohs(pp->flags) & BCAST_MASK) { 1356 /* 1357 * TODO - what should we do if broadcast 1358 * flag is set, but ptp connection? 1359 */ 1360 if (debug) 1361 dhcpmsg(LOG_INFO, 1362 "Sending datagram to broadcast address.\n"); 1363 to.sin_addr.s_addr = INADDR_BROADCAST; 1364 } else { 1365 /* 1366 * By default, we assume unicast! 1367 */ 1368 to.sin_addr.s_addr = dstp->s_addr; 1369 1370 if (debug) { 1371 dhcpmsg(LOG_INFO, 1372 "Unicasting datagram to %s address.\n", 1373 inet_ntop(AF_INET, dstp, 1374 ntoab, sizeof (ntoab))); 1375 } 1376 if (ifp->addr.s_addr == pp->giaddr.s_addr) { 1377 /* 1378 * No doubt a reply packet which we, as 1379 * the relay agent, are supposed to deliver. 1380 * Local Delivery! 1381 */ 1382 local = B_TRUE; 1383 } else { 1384 /* 1385 * We can't use the giaddr field to 1386 * determine whether the client is local 1387 * or remote. Use the client's address, 1388 * our interface's address, and our 1389 * interface's netmask to make this 1390 * determination. 1391 */ 1392 if_in.s_addr = ntohl(ifp->addr.s_addr); 1393 if_in.s_addr &= ntohl(ifp->mask.s_addr); 1394 cl_in.s_addr = ntohl(dstp->s_addr); 1395 cl_in.s_addr &= ntohl(ifp->mask.s_addr); 1396 if (if_in.s_addr == cl_in.s_addr) 1397 local = B_TRUE; 1398 } 1399 1400 if (local) { 1401 /* 1402 * Local delivery. If we can make an 1403 * ARP entry we'll unicast. But only in 1404 * cases when we do have the chaddr handy. 1405 * RFC2855 and IPoIB are cases that do not 1406 * send chaddr and set hlen = 0. Identify 1407 * such media by their htype, and rely on 1408 * in-kernel ARP for them. 1409 */ 1410 if ((ifp->flags & IFF_NOARP) == 0 && 1411 ((pp->htype == ARPHRD_IB) || 1412 (set_arp(ifp, dstp, pp->chaddr, pp->hlen, 1413 DHCP_ARP_ADD) == 0))) { 1414 to.sin_addr.s_addr = dstp->s_addr; 1415 } else { 1416 to.sin_addr.s_addr = INADDR_BROADCAST; 1417 } 1418 } 1419 } 1420 } 1421 return (write_interface(ifp, pp, len, &to)); 1422 } 1423 1424 /* 1425 * Free pkts 1426 */ 1427 void 1428 free_pktlist(dsvc_clnt_t *pcd) 1429 { 1430 PKT_LIST *plp, *plp_next; 1431 IF *ifp = pcd->ifp; 1432 1433 assert(MUTEX_HELD(&pcd->pcd_mtx)); 1434 1435 plp = pcd->pkthead; 1436 while (plp != NULL) { 1437 plp_next = plp; 1438 plp = plp->next; 1439 free_plp(plp_next); 1440 ifp->dropped++; 1441 pcd->pending--; 1442 } 1443 pcd->pkthead = NULL; 1444 } 1445 1446 /* Check if address is one of the addresses we are listening on */ 1447 boolean_t 1448 is_our_address(in_addr_t addr) 1449 { 1450 IF *ifp; 1451 boolean_t found = B_FALSE; 1452 1453 (void) mutex_lock(&if_head_mtx); 1454 for (ifp = if_head; ifp != NULL; ifp = ifp->next) { 1455 if (ifp->addr.s_addr == addr) { 1456 found = B_TRUE; 1457 break; 1458 } 1459 } 1460 (void) mutex_unlock(&if_head_mtx); 1461 return (found); 1462 }