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 * Copyright (c) 1993, 2010, Oracle and/or its affiliates. All rights reserved. 23 */ 24 25 #include <stdio.h> 26 #include <stdlib.h> 27 #include <alloca.h> 28 #include <stdarg.h> 29 #include <sys/types.h> 30 #include <sys/sysmacros.h> 31 #include <assert.h> 32 #include <sys/socket.h> 33 #include <sys/byteorder.h> 34 #include <string.h> 35 #include <time.h> 36 #include <sys/socket.h> 37 #include <syslog.h> 38 #include <sys/errno.h> 39 #include <net/if.h> 40 #include <netinet/in.h> 41 #include <arpa/inet.h> 42 #include <netdb.h> 43 #include <netinet/dhcp.h> 44 #include <dhcp_symbol.h> 45 #include <nss_dbdefs.h> 46 #include <dlfcn.h> 47 #include "dhcpd.h" 48 #include "per_dnet.h" 49 #include "interfaces.h" 50 #include <locale.h> 51 #include <resolv.h> 52 53 static void dhcp_offer(dsvc_clnt_t *, PKT_LIST *); 54 static void dhcp_req_ack(dsvc_clnt_t *, PKT_LIST *); 55 static void dhcp_dec_rel(dsvc_clnt_t *, PKT_LIST *, int); 56 static void dhcp_inform(dsvc_clnt_t *, PKT_LIST *); 57 static PKT *gen_reply_pkt(dsvc_clnt_t *, PKT_LIST *, int, uint_t *, 58 uchar_t **, struct in_addr *); 59 static void set_lease_option(ENCODE **, lease_t); 60 static int config_lease(PKT_LIST *, dn_rec_t *, ENCODE **, lease_t, boolean_t); 61 static int is_option_requested(PKT_LIST *, ushort_t); 62 static void add_request_list(IF *, PKT_LIST *, ENCODE **, struct in_addr *); 63 static char *disp_clnt_msg(PKT_LIST *, char *, int); 64 static void add_dnet_cache(dsvc_dnet_t *, dn_rec_list_t *); 65 static void purge_dnet_cache(dsvc_dnet_t *, dn_rec_t *); 66 67 static boolean_t addr_avail(dsvc_dnet_t *, dsvc_clnt_t *, dn_rec_list_t **, 68 struct in_addr, boolean_t); 69 static boolean_t name_avail(char *, dsvc_clnt_t *, PKT_LIST *, 70 dn_rec_list_t **, ENCODE *, struct in_addr **); 71 static boolean_t entry_available(dsvc_clnt_t *, dn_rec_t *); 72 static boolean_t do_nsupdate(struct in_addr, ENCODE *, PKT_LIST *); 73 74 extern int dns_puthostent(struct hostent *, time_t); 75 76 /* 77 * Offer cache. 78 * 79 * The DHCP server maintains a cache of DHCP OFFERs it has extended to DHCP 80 * clients. It does so because: 81 * a) Subsequent requests get the same answer, and the same IP address 82 * isn't offered to a different client. 83 * 84 * b) No ICMP validation is required the second time through, nor is a 85 * database lookup required. 86 * 87 * c) If the client accepts the OFFER and sends a REQUEST, we can simply 88 * lookup the record by client IP address, the one field guaranteed to 89 * be unique within the dhcp network table. 90 * 91 * We don't explicitly delete entries from the offer cache. We let them time 92 * out on their own. This is done to ensure the server responds correctly when 93 * many pending client requests are queued (duplicates). We don't want to ICMP 94 * validate an IP address we just allocated. 95 * 96 * The offer cache (and any database records cached in select_offer()) will 97 * diverge from the database for the length of the D_OFFER lifetime. 98 * SIGHUP flushes the offer cache, allowing management tools to inform the 99 * server of changes in a timely manner. 100 */ 101 102 /* 103 * Dispatch the DHCP packet based on its type. 104 */ 105 void 106 dhcp(dsvc_clnt_t *pcd, PKT_LIST *plp) 107 { 108 if (plp->opts[CD_DHCP_TYPE]->len != 1) { 109 dhcpmsg(LOG_ERR, 110 "Garbled DHCP Message type option from client: %s\n", 111 pcd->cidbuf); 112 return; 113 } 114 115 pcd->state = *plp->opts[CD_DHCP_TYPE]->value; 116 switch (pcd->state) { 117 case DISCOVER: 118 #ifdef DEBUG 119 dhcpmsg(LOG_DEBUG, "dhcp() - processing OFFER...\n"); 120 #endif /* DEBUG */ 121 dhcp_offer(pcd, plp); 122 #ifdef DEBUG 123 dhcpmsg(LOG_DEBUG, "dhcp() - processed OFFER.\n"); 124 #endif /* DEBUG */ 125 break; 126 case REQUEST: 127 #ifdef DEBUG 128 dhcpmsg(LOG_DEBUG, "dhcp() - processing REQUEST...\n"); 129 #endif /* DEBUG */ 130 dhcp_req_ack(pcd, plp); 131 #ifdef DEBUG 132 dhcpmsg(LOG_DEBUG, "dhcp() - processed REQUEST.\n"); 133 #endif /* DEBUG */ 134 break; 135 case DECLINE: 136 #ifdef DEBUG 137 dhcpmsg(LOG_DEBUG, "dhcp() - processing DECLINE...\n"); 138 #endif /* DEBUG */ 139 dhcp_dec_rel(pcd, plp, DECLINE); 140 #ifdef DEBUG 141 dhcpmsg(LOG_DEBUG, "dhcp() - processed DECLINE.\n"); 142 #endif /* DEBUG */ 143 break; 144 case RELEASE: 145 #ifdef DEBUG 146 dhcpmsg(LOG_DEBUG, "dhcp() - processing RELEASE...\n"); 147 #endif /* DEBUG */ 148 dhcp_dec_rel(pcd, plp, RELEASE); 149 #ifdef DEBUG 150 dhcpmsg(LOG_DEBUG, "dhcp() - processed RELEASE.\n"); 151 #endif /* DEBUG */ 152 break; 153 case INFORM: 154 #ifdef DEBUG 155 dhcpmsg(LOG_DEBUG, "dhcp() - processing INFORM...\n"); 156 #endif /* DEBUG */ 157 dhcp_inform(pcd, plp); 158 #ifdef DEBUG 159 dhcpmsg(LOG_DEBUG, "dhcp() - processed INFORM.\n"); 160 #endif /* DEBUG */ 161 break; 162 default: 163 dhcpmsg(LOG_INFO, 164 "Unexpected DHCP message type: %d from client: %s.\n", 165 pcd->state, pcd->cidbuf); 166 break; 167 } 168 } 169 170 /* 171 * Responding to a DISCOVER message. icmp echo check (if done) is synchronous. 172 * Previously known requests are in the OFFER cache. 173 */ 174 static void 175 dhcp_offer(dsvc_clnt_t *pcd, PKT_LIST *plp) 176 { 177 IF *ifp = pcd->ifp; 178 boolean_t result; 179 struct in_addr nsip, ncip; 180 dsvc_dnet_t *pnd = pcd->pnd; 181 uint_t replen; 182 int used_pkt_len; 183 PKT *rep_pktp = NULL; 184 uchar_t *optp; 185 ENCODE *ecp, *vecp, *macro_ecp, *macro_vecp, 186 *class_ecp, *class_vecp, 187 *cid_ecp, *cid_vecp, 188 *net_ecp, *net_vecp; 189 MACRO *net_mp, *pkt_mp, *class_mp, *cid_mp; 190 char *class_id; 191 time_t now = time(NULL); 192 lease_t newlease, oldlease = 0; 193 int err = 0; 194 boolean_t existing_allocation = B_FALSE; 195 boolean_t existing_offer = B_FALSE; 196 char sipstr[INET_ADDRSTRLEN], cipstr[INET_ADDRSTRLEN]; 197 char class_idbuf[DSYM_CLASS_SIZE]; 198 dn_rec_t *dnp, dn, ndn; 199 uint32_t query; 200 dn_rec_list_t *dncp = NULL, *dnlp = NULL; 201 boolean_t unreserve = B_FALSE; 202 203 class_id = get_class_id(plp, class_idbuf, sizeof (class_idbuf)); 204 205 /* 206 * Purge offers when expired or the database has been re-read. 207 * 208 * Multi-threading: to better distribute garbage collection 209 * and data structure aging tasks, each thread must actively 210 * implement policy, rather then specialized, non-scalable 211 * threads which halt the server and update all data 212 * structures. 213 * 214 * The test below checks whether the offer has expired, 215 * due to aging, or re-reading of the dhcptab, via timeout 216 * or explicit signal. 217 */ 218 if (pcd->off_ip.s_addr != htonl(INADDR_ANY) && 219 PCD_OFFER_TIMEOUT(pcd, now)) 220 purge_offer(pcd, B_TRUE, B_TRUE); 221 222 if (pcd->off_ip.s_addr != htonl(INADDR_ANY)) { 223 /* 224 * We've already validated this IP address in the past, and 225 * due to the OFFER hash table, we would not have offered this 226 * IP address to another client, so use the offer-cached record. 227 */ 228 existing_offer = B_TRUE; 229 dnlp = pcd->dnlp; 230 dnp = dnlp->dnl_rec; 231 ncip.s_addr = htonl(dnp->dn_cip.s_addr); 232 } else { 233 /* Try to find an existing usable entry for the client. */ 234 DSVC_QINIT(query); 235 DSVC_QEQ(query, DN_QCID); 236 (void) memcpy(dn.dn_cid, pcd->cid, pcd->cid_len); 237 dn.dn_cid_len = pcd->cid_len; 238 239 /* No bootp records, thank you. */ 240 DSVC_QNEQ(query, DN_QFBOOTP_ONLY); 241 dn.dn_flags = DN_FBOOTP_ONLY; 242 243 /* 244 * We don't limit this search by SIP, because this client 245 * may be owned by another server, and we need to detect this 246 * since that record may be MANUAL. 247 */ 248 dncp = NULL; 249 dnlp = dhcp_lookup_dd_classify(pcd->pnd, B_FALSE, query, 250 -1, &dn, (void **)&dncp, S_CID); 251 252 while (dnlp != NULL) { 253 254 dnp = dnlp->dnl_rec; 255 if (match_ownerip(htonl(dnp->dn_sip.s_addr)) == NULL) { 256 /* 257 * An IP address, but not ours! It's up to the 258 * primary to respond to DISCOVERs on this 259 * address. 260 */ 261 if (verbose) { 262 char *m1, *m2; 263 264 if (dnp->dn_flags & DN_FMANUAL) { 265 m1 = "MANUAL"; 266 m2 = " No other IP address " 267 "will be allocated."; 268 } else { 269 m1 = "DYNAMIC"; 270 m2 = ""; 271 } 272 273 nsip.s_addr = htonl(dnp->dn_sip.s_addr); 274 (void) inet_ntop(AF_INET, &nsip, sipstr, 275 sizeof (sipstr)); 276 ncip.s_addr = htonl(dnp->dn_cip.s_addr); 277 (void) inet_ntop(AF_INET, &ncip, cipstr, 278 sizeof (cipstr)); 279 dhcpmsg(LOG_INFO, "Client: %1$s has " 280 "%2$s %3$s owned by server: " 281 "%4$s.%5$s\n", pcd->cidbuf, 282 m1, cipstr, sipstr, m2); 283 } 284 285 /* We give up if that IP address is manual */ 286 if (dnp->dn_flags & DN_FMANUAL) 287 goto leave_offer; 288 } else { 289 uint_t bits = DN_FUNUSABLE | DN_FMANUAL; 290 if ((dnp->dn_flags & bits) == bits) { 291 ncip.s_addr = htonl(dnp->dn_cip.s_addr); 292 (void) inet_ntop(AF_INET, &ncip, cipstr, 293 sizeof (cipstr)); 294 dhcpmsg(LOG_WARNING, "Client: %1$s " 295 "MANUAL record %2$s is UNUSABLE. " 296 "No other IP address will be " 297 "allocated.\n", pcd->cidbuf, 298 cipstr); 299 goto leave_offer; 300 } else 301 break; /* success */ 302 } 303 304 free_dnrec_list(dnlp); 305 dnlp = detach_dnrec_from_list(NULL, dncp, &dncp); 306 } 307 308 if (dnlp == NULL) { 309 /* 310 * select_offer() ONLY selects IP addresses owned 311 * by us. Only log a notice if we own any IP addresses 312 * at all. Otherwise, this is an informational server. 313 */ 314 if (!select_offer(pnd, plp, pcd, &dnlp)) { 315 if (pnd->naddrs > 0) { 316 dhcpmsg(LOG_NOTICE, 317 "No more IP addresses on %1$s " 318 "network (%2$s)\n", pnd->network, 319 pcd->cidbuf); 320 } 321 goto leave_offer; 322 } 323 dnp = dnlp->dnl_rec; 324 } else 325 existing_allocation = B_TRUE; 326 327 ncip.s_addr = htonl(dnp->dn_cip.s_addr); 328 (void) inet_ntop(AF_INET, &ncip, cipstr, sizeof (cipstr)); 329 330 /* 331 * ICMP echo validate the address. 332 */ 333 if (!noping) { 334 /* 335 * If icmp echo validation fails, let the plp fall by 336 * the wayside. 337 */ 338 if (icmp_echo_check(&ncip, &result) != 0) { 339 dhcpmsg(LOG_ERR, "ICMP ECHO check cannot be " 340 "registered for: %s, ignoring\n", cipstr); 341 unreserve = B_TRUE; 342 goto leave_offer; 343 } 344 if (result) { 345 dhcpmsg(LOG_WARNING, 346 "ICMP ECHO reply to OFFER candidate: " 347 "%s, disabling.\n", cipstr); 348 349 ndn = *dnp; /* struct copy */ 350 ndn.dn_flags |= DN_FUNUSABLE; 351 352 if ((err = dhcp_modify_dd_entry(pnd->dh, dnp, 353 &ndn)) != DSVC_SUCCESS) { 354 dhcpmsg(LOG_ERR, 355 "ICMP ECHO reply to OFFER " 356 "candidate: %1$s. No " 357 "modifiable dhcp network " 358 "record. (%2$s)\n", cipstr, 359 dhcpsvc_errmsg(err)); 360 } else { 361 /* Keep the cached entry current. */ 362 *dnp = ndn; /* struct copy */ 363 } 364 365 logtrans(P_DHCP, L_ICMP_ECHO, 0, ncip, 366 server_ip, plp); 367 368 unreserve = B_TRUE; 369 370 goto leave_offer; 371 } 372 } 373 } 374 375 /* 376 * At this point, we've ICMP validated (if requested) the IP 377 * address, and can go about producing an OFFER for the client. 378 */ 379 380 ecp = vecp = NULL; 381 net_vecp = net_ecp = NULL; 382 macro_vecp = macro_ecp = NULL; 383 class_vecp = class_ecp = NULL; 384 cid_vecp = cid_ecp = NULL; 385 if (!no_dhcptab) { 386 open_macros(); 387 388 /* 389 * Macros are evaluated this way: First apply parameters from 390 * a client class macro (if present), then apply those from the 391 * network macro (if present), then apply those from the 392 * dhcp network macro (if present), and finally apply those 393 * from a client id macro (if present). 394 */ 395 396 /* 397 * First get a handle on network, dhcp network table macro, 398 * and client id macro values. 399 */ 400 if ((net_mp = get_macro(pnd->network)) != NULL) 401 net_ecp = net_mp->head; 402 if ((pkt_mp = get_macro(dnp->dn_macro)) != NULL) 403 macro_ecp = pkt_mp->head; 404 if ((cid_mp = get_macro(pcd->cidbuf)) != NULL) 405 cid_ecp = cid_mp->head; 406 407 if (class_id != NULL) { 408 /* Get a handle on the class id macro (if it exists). */ 409 if ((class_mp = get_macro(class_id)) != NULL) { 410 /* 411 * Locate the ENCODE list for encapsulated 412 * options associated with our class id within 413 * the class id macro. 414 */ 415 class_vecp = vendor_encodes(class_mp, class_id); 416 class_ecp = class_mp->head; 417 } 418 419 /* 420 * Locate the ENCODE list for encapsulated options 421 * associated with our class id within the network, 422 * dhcp network, and client macros. 423 */ 424 if (net_mp != NULL) 425 net_vecp = vendor_encodes(net_mp, class_id); 426 if (pkt_mp != NULL) 427 macro_vecp = vendor_encodes(pkt_mp, class_id); 428 if (cid_mp != NULL) 429 cid_vecp = vendor_encodes(cid_mp, class_id); 430 431 /* 432 * Combine the encapsulated option encode lists 433 * associated with our class id in the order defined 434 * above (class, net, dhcp network, client id) 435 */ 436 vecp = combine_encodes(class_vecp, net_vecp, ENC_COPY); 437 vecp = combine_encodes(vecp, macro_vecp, ENC_DONT_COPY); 438 vecp = combine_encodes(vecp, cid_vecp, ENC_DONT_COPY); 439 } 440 441 /* 442 * Combine standard option encode lists in the order defined 443 * above (class, net, dhcp network, and client id). 444 */ 445 if (class_ecp != NULL) 446 ecp = combine_encodes(class_ecp, net_ecp, ENC_COPY); 447 else 448 ecp = dup_encode_list(net_ecp); 449 450 ecp = combine_encodes(ecp, macro_ecp, ENC_DONT_COPY); 451 ecp = combine_encodes(ecp, cid_ecp, ENC_DONT_COPY); 452 453 /* If dhcptab configured to return hostname, do so. */ 454 if (find_encode(ecp, DSYM_INTERNAL, CD_BOOL_HOSTNAME) != NULL) { 455 struct hostent h, *hp; 456 char hbuf[NSS_BUFLEN_HOSTS]; 457 ENCODE *hecp; 458 hp = gethostbyaddr_r((char *)&ncip, sizeof (ncip), 459 AF_INET, &h, hbuf, sizeof (hbuf), &err); 460 if (hp != NULL) { 461 hecp = make_encode(DSYM_STANDARD, 462 CD_HOSTNAME, strlen(hp->h_name), 463 hp->h_name, ENC_COPY); 464 replace_encode(&ecp, hecp, ENC_DONT_COPY); 465 } 466 } 467 468 /* If dhcptab configured to echo client class, do so. */ 469 if (plp->opts[CD_CLASS_ID] != NULL && 470 find_encode(ecp, DSYM_INTERNAL, CD_BOOL_ECHO_VCLASS) != 471 NULL) { 472 ENCODE *echo_ecp; 473 DHCP_OPT *op = plp->opts[CD_CLASS_ID]; 474 echo_ecp = make_encode(DSYM_STANDARD, CD_CLASS_ID, 475 op->len, op->value, ENC_COPY); 476 replace_encode(&ecp, echo_ecp, ENC_DONT_COPY); 477 } 478 } 479 480 if ((ifp->flags & IFF_NOARP) == 0) 481 (void) set_arp(ifp, &ncip, NULL, 0, DHCP_ARP_DEL); 482 483 /* 484 * For OFFERs, we don't check the client's lease nor LeaseNeg, 485 * regardless of whether the client has an existing allocation 486 * or not. Lease expiration (w/o LeaseNeg) only occur during 487 * RENEW/REBIND or INIT-REBOOT client states, not SELECTing state. 488 */ 489 if (existing_allocation) { 490 if (dnp->dn_lease == DHCP_PERM || 491 (dnp->dn_flags & DN_FAUTOMATIC)) { 492 oldlease = DHCP_PERM; 493 } else { 494 if ((lease_t)dnp->dn_lease < (lease_t)now) 495 oldlease = (lease_t)0; 496 else { 497 oldlease = (lease_t)dnp->dn_lease - 498 (lease_t)now; 499 } 500 } 501 } 502 503 /* First get a generic reply packet. */ 504 rep_pktp = gen_reply_pkt(pcd, plp, OFFER, &replen, &optp, &ifp->addr); 505 506 /* Set the client's IP address */ 507 rep_pktp->yiaddr.s_addr = htonl(dnp->dn_cip.s_addr); 508 509 /* Calculate lease time. */ 510 newlease = config_lease(plp, dnp, &ecp, oldlease, B_TRUE); 511 512 /* 513 * Client is requesting specific options. let's try and ensure it 514 * gets what it wants, if at all possible. 515 */ 516 if (plp->opts[CD_REQUEST_LIST] != NULL) 517 add_request_list(ifp, plp, &ecp, &ncip); 518 519 /* Now load all the asked for / configured options */ 520 used_pkt_len = load_options(DHCP_DHCP_CLNT | DHCP_SEND_LEASE, plp, 521 rep_pktp, replen, optp, ecp, vecp); 522 523 free_encode_list(ecp); 524 free_encode_list(vecp); 525 if (!no_dhcptab) 526 close_macros(); 527 528 if (used_pkt_len < sizeof (PKT)) 529 used_pkt_len = sizeof (PKT); 530 531 if (send_reply(ifp, rep_pktp, used_pkt_len, &ncip) == 0) { 532 if (newlease == DHCP_PERM) 533 newlease = htonl(newlease); 534 else 535 newlease = htonl(now + newlease); 536 (void) update_offer(pcd, &dnlp, newlease, NULL, B_TRUE); 537 existing_offer = B_TRUE; 538 } else { 539 unreserve = B_TRUE; 540 } 541 542 leave_offer: 543 if (unreserve) 544 purge_offer(pcd, B_FALSE, B_TRUE); 545 if (rep_pktp != NULL) 546 free(rep_pktp); 547 if (dncp != NULL) 548 dhcp_free_dd_list(pnd->dh, dncp); 549 if (dnlp != NULL && !existing_offer) 550 dhcp_free_dd_list(pnd->dh, dnlp); 551 } 552 553 /* 554 * Responding to REQUEST message. 555 * 556 * Very similar to dhcp_offer(), except that we need to be more 557 * discriminating. 558 * 559 * The ciaddr field is TRUSTED. A INIT-REBOOTing client will place its 560 * notion of its IP address in the requested IP address option. INIT 561 * clients will place the value in the OFFERs yiaddr in the requested 562 * IP address option. INIT-REBOOT packets are differentiated from INIT 563 * packets in that the server id option is missing. ciaddr will only 564 * appear from clients in the RENEW/REBIND states. 565 * 566 * Error messages may be generated. Database write failures are no longer 567 * fatal, since we'll only respond to the client if the write succeeds. 568 */ 569 static void 570 dhcp_req_ack(dsvc_clnt_t *pcd, PKT_LIST *plp) 571 { 572 dn_rec_t dn, ndn, *dnp; 573 struct in_addr serverid, ciaddr, claddr, nreqaddr, cipaddr, 574 ncipaddr, sipaddr; 575 struct in_addr dest_in; 576 dsvc_dnet_t *pnd = pcd->pnd; 577 uint_t replen; 578 int actual_len; 579 int pkt_type = ACK; 580 DHCP_MSG_CATEGORIES log; 581 PKT *rep_pktp = NULL; 582 uchar_t *optp; 583 ENCODE *ecp, *vecp, 584 *class_ecp, *class_vecp, 585 *net_ecp, *net_vecp, 586 *macro_ecp, *macro_vecp, 587 *cid_ecp, *cid_vecp; 588 MACRO *class_mp, *pkt_mp, *net_mp, *cid_mp; 589 char *class_id; 590 char nak_mesg[DHCP_SCRATCH]; 591 time_t now; 592 lease_t newlease, oldlease; 593 boolean_t negot; 594 int err = 0; 595 int write_error = DSVC_SUCCESS, clnt_state; 596 ushort_t boot_secs; 597 char ntoaa[INET_ADDRSTRLEN], ntoab[INET_ADDRSTRLEN], 598 ntoac[INET_ADDRSTRLEN]; 599 char class_idbuf[DSYM_CLASS_SIZE]; 600 boolean_t hostname_update = B_FALSE; 601 dn_rec_list_t *nlp, *dncp = NULL, *dnlp = NULL; 602 uint32_t query; 603 IF *ifp = pcd->ifp; 604 boolean_t existing_offer = B_FALSE; 605 606 ciaddr.s_addr = plp->pkt->ciaddr.s_addr; 607 boot_secs = ntohs(plp->pkt->secs); 608 now = time(NULL); 609 610 class_id = get_class_id(plp, class_idbuf, sizeof (class_idbuf)); 611 612 /* Determine type of REQUEST we've got. */ 613 if (plp->opts[CD_SERVER_ID] != NULL) { 614 if (plp->opts[CD_SERVER_ID]->len != sizeof (struct in_addr)) { 615 dhcpmsg(LOG_ERR, "Garbled DHCP Server ID option from " 616 "client: '%1$s'. Len is %2$d, when it should be " 617 "%3$d \n", pcd->cidbuf, 618 plp->opts[CD_SERVER_ID]->len, 619 sizeof (struct in_addr)); 620 goto leave_ack; 621 } 622 623 /* 624 * Request in response to an OFFER. ciaddr must not 625 * be set. Requested IP address option will hold address 626 * we offered the client. 627 */ 628 clnt_state = INIT_STATE; 629 (void) memcpy((void *)&serverid, 630 plp->opts[CD_SERVER_ID]->value, sizeof (struct in_addr)); 631 632 if (plp->opts[CD_REQUESTED_IP_ADDR] == NULL) { 633 if (verbose) { 634 dhcpmsg(LOG_NOTICE, "%1$s: REQUEST on %2$s is " 635 "missing requested IP option.\n", 636 pcd->cidbuf, pcd->pnd->network); 637 } 638 goto leave_ack; 639 } 640 if (plp->opts[CD_REQUESTED_IP_ADDR]->len != 641 sizeof (struct in_addr)) { 642 dhcpmsg(LOG_ERR, "Garbled Requested IP option from " 643 "client: '%1$s'. Len is %2$d, when it should be " 644 "%3$d \n", 645 pcd->cidbuf, plp->opts[CD_REQUESTED_IP_ADDR]->len, 646 sizeof (struct in_addr)); 647 goto leave_ack; 648 } 649 (void) memcpy((void *)&nreqaddr, 650 plp->opts[CD_REQUESTED_IP_ADDR]->value, 651 sizeof (struct in_addr)); 652 653 if (serverid.s_addr != ifp->addr.s_addr) { 654 /* 655 * Another server address was selected. 656 * 657 * If the server address is handled by another 658 * thread of our process, do nothing in the 659 * hope that the other thread will eventually 660 * receive a REQUEST with its server address. 661 * 662 * If a server address was selected which is 663 * not handled by this process, see if we made 664 * an offer, and clear it if we did. If offer 665 * expired before client responded, then no 666 * need to do anything. 667 */ 668 if (is_our_address(serverid.s_addr)) { 669 if (verbose) { 670 dhcpmsg(LOG_INFO, 671 "Client: %1$s chose %2$s from " 672 "server: %3$s, which is being " 673 "handled by another thread\n", 674 pcd->cidbuf, 675 inet_ntop(AF_INET, &nreqaddr, ntoaa, 676 sizeof (ntoaa)), 677 inet_ntop(AF_INET, &serverid, ntoab, 678 sizeof (ntoab))); 679 } 680 } else { 681 purge_offer(pcd, B_FALSE, B_TRUE); 682 if (verbose) { 683 dhcpmsg(LOG_INFO, 684 "Client: %1$s chose %2$s from " 685 "server: %3$s, not %4$s\n", 686 pcd->cidbuf, 687 inet_ntop(AF_INET, &nreqaddr, ntoaa, 688 sizeof (ntoaa)), 689 inet_ntop(AF_INET, &serverid, ntoab, 690 sizeof (ntoab)), 691 inet_ntop(AF_INET, &ifp->addr, 692 ntoac, sizeof (ntoac))); 693 } 694 } 695 goto leave_ack; 696 } 697 698 /* 699 * See comment at the top of the file for description of 700 * OFFER cache. 701 * 702 * If the offer expires before the client got around to 703 * requesting, and we can't confirm the address is still free, 704 * we'll silently ignore the client, until it drops back and 705 * tries to discover again. We will print a message in 706 * verbose mode however. If the Offer hasn't timed out, we 707 * bump it up again in case we have a bounce of queued up 708 * INIT requests to respond to. 709 */ 710 if (pcd->off_ip.s_addr == htonl(INADDR_ANY) || 711 PCD_OFFER_TIMEOUT(pcd, now)) { 712 /* 713 * Hopefully, the timeout value is fairly long to 714 * prevent this. 715 */ 716 purge_offer(pcd, B_TRUE, B_TRUE); 717 if (verbose) { 718 dhcpmsg(LOG_INFO, 719 "Offer on %1$s expired for client: %2$s\n", 720 pcd->pnd->network, pcd->cidbuf); 721 } 722 goto leave_ack; 723 } else 724 (void) update_offer(pcd, NULL, 0, NULL, B_TRUE); 725 726 /* 727 * The client selected us. Create a ACK, and send 728 * it off to the client, commit to permanent 729 * storage the new binding. 730 */ 731 existing_offer = B_TRUE; 732 dnlp = pcd->dnlp; 733 dnp = dnlp->dnl_rec; 734 ndn = *dnp; /* struct copy */ 735 ndn.dn_lease = pcd->lease; 736 ncipaddr.s_addr = htonl(dnp->dn_cip.s_addr); 737 738 /* 739 * If client thinks we offered it a different address, then 740 * ignore it. 741 */ 742 if (memcmp((char *)&ncipaddr, 743 plp->opts[CD_REQUESTED_IP_ADDR]->value, 744 sizeof (struct in_addr)) != 0) { 745 if (verbose) { 746 dhcpmsg(LOG_INFO, "Client %1$s believes " 747 "offered IP address %2$s is different than " 748 "what was offered.\n", pcd->cidbuf, 749 inet_ntop(AF_INET, &ncipaddr, ntoab, 750 sizeof (ntoab))); 751 } 752 goto leave_ack; 753 } 754 755 /* 756 * Clear out any temporary ARP table entry we may have 757 * created during the offer. 758 */ 759 if ((ifp->flags & IFF_NOARP) == 0) 760 (void) set_arp(ifp, &ncipaddr, NULL, 0, DHCP_ARP_DEL); 761 } else { 762 /* 763 * Either a client in the INIT-REBOOT state, or one in 764 * either RENEW or REBIND states. The latter will have 765 * ciaddr set, whereas the former will place its concept 766 * of its IP address in the requested IP address option. 767 */ 768 if (ciaddr.s_addr == htonl(INADDR_ANY)) { 769 clnt_state = INIT_REBOOT_STATE; 770 /* 771 * Client isn't sure of its IP address. It's 772 * attempting to verify its address, thus requested 773 * IP option better be present, and correct. 774 */ 775 if (plp->opts[CD_REQUESTED_IP_ADDR] == NULL) { 776 dhcpmsg(LOG_ERR, 777 "Client: %s REQUEST is missing " 778 "requested IP option.\n", pcd->cidbuf); 779 goto leave_ack; 780 } 781 if (plp->opts[CD_REQUESTED_IP_ADDR]->len != 782 sizeof (struct in_addr)) { 783 dhcpmsg(LOG_ERR, "Garbled Requested IP option " 784 "from client: '%1$s'. Len is %2$d, when it " 785 "should be %3$d \n", pcd->cidbuf, 786 plp->opts[CD_REQUESTED_IP_ADDR]->len, 787 sizeof (struct in_addr)); 788 goto leave_ack; 789 } 790 (void) memcpy(&claddr, 791 plp->opts[CD_REQUESTED_IP_ADDR]->value, 792 sizeof (struct in_addr)); 793 794 DSVC_QINIT(query); 795 DSVC_QEQ(query, DN_QCID); 796 (void) memcpy(dn.dn_cid, pcd->cid, pcd->cid_len); 797 dn.dn_cid_len = pcd->cid_len; 798 799 /* No bootp records, thank you. */ 800 DSVC_QNEQ(query, DN_QFBOOTP_ONLY); 801 dn.dn_flags = DN_FBOOTP_ONLY; 802 803 } else { 804 clnt_state = RENEW_REBIND_STATE; 805 /* 806 * Client knows its IP address. It is trying to 807 * RENEW/REBIND (extend its lease). We trust ciaddr, 808 * and use it to locate the client's record. If we 809 * can't find the client's record, then we keep 810 * silent. If the client id of the record doesn't 811 * match this client, then the database is 812 * inconsistent, and we'll ignore it. 813 */ 814 DSVC_QINIT(query); 815 DSVC_QEQ(query, DN_QCID|DN_QCIP); 816 (void) memcpy(dn.dn_cid, pcd->cid, pcd->cid_len); 817 dn.dn_cid_len = pcd->cid_len; 818 dn.dn_cip.s_addr = ntohl(ciaddr.s_addr); 819 820 /* No bootp records, thank you. */ 821 DSVC_QNEQ(query, DN_QFBOOTP_ONLY); 822 dn.dn_flags = DN_FBOOTP_ONLY; 823 824 claddr.s_addr = ciaddr.s_addr; 825 } 826 827 dncp = NULL; 828 dnlp = dhcp_lookup_dd_classify(pcd->pnd, B_FALSE, query, 829 -1, &dn, (void **)&dncp, S_CID); 830 831 if (dnlp != NULL) { 832 dnp = dnlp->dnl_rec; 833 if (dnp->dn_flags & DN_FUNUSABLE) 834 goto leave_ack; 835 836 sipaddr.s_addr = htonl(dnp->dn_sip.s_addr); 837 cipaddr.s_addr = htonl(dnp->dn_cip.s_addr); 838 839 /* 840 * If this address is not owned by this server and 841 * the client is trying to verify the address, then 842 * ignore the client. If the client is simply trying 843 * to rebind, then don't respond until after 844 * renog_secs passes, to give the server that *OWNS* 845 * the address time to respond first. 846 */ 847 if (match_ownerip(sipaddr.s_addr) == NULL) { 848 if (clnt_state == INIT_REBOOT_STATE) { 849 if (verbose) { 850 dhcpmsg(LOG_NOTICE, "Client: " 851 "%1$s is requesting " 852 "verification of %2$s " 853 "owned by %3$s\n", 854 pcd->cidbuf, 855 inet_ntop(AF_INET, &cipaddr, 856 ntoab, sizeof (ntoab)), 857 inet_ntop(AF_INET, &sipaddr, 858 ntoac, sizeof (ntoac))); 859 } 860 goto leave_ack; 861 } else { 862 /* RENEW/REBIND - wait for primary */ 863 if (boot_secs < (ushort_t)renog_secs) 864 goto leave_ack; 865 } 866 867 } 868 if (claddr.s_addr != htonl(dnp->dn_cip.s_addr)) { 869 /* 870 * Client has the wrong IP address. Nak. 871 */ 872 (void) snprintf(nak_mesg, sizeof (nak_mesg), 873 "Incorrect IP address."); 874 pkt_type = NAK; 875 } else { 876 if (!(dnp->dn_flags & DN_FAUTOMATIC) && 877 (lease_t)dnp->dn_lease < (lease_t)now) { 878 (void) snprintf(nak_mesg, 879 sizeof (nak_mesg), 880 "Lease has expired."); 881 pkt_type = NAK; 882 } 883 } 884 } else { 885 if (clnt_state == RENEW_REBIND_STATE) { 886 dhcpmsg(LOG_ERR, "Client: %1$s is trying to " 887 "renew %2$s, an IP address it has not " 888 "leased.\n", pcd->cidbuf, inet_ntop(AF_INET, 889 &ciaddr, ntoab, sizeof (ntoab))); 890 goto leave_ack; 891 } 892 /* 893 * There is no such client registered for this 894 * address. Check if their address is on the correct 895 * net. If it is, then we'll assume that some other, 896 * non-database sharing DHCP server knows about this 897 * client. If the client is on the wrong net, NAK'em. 898 */ 899 if ((claddr.s_addr & pnd->subnet.s_addr) == 900 pnd->net.s_addr) { 901 /* Right net, but no record of client. */ 902 if (verbose) { 903 dhcpmsg(LOG_INFO, 904 "Client: %1$s is trying to verify " 905 "unrecorded address: %2$s, " 906 "ignored.\n", pcd->cidbuf, 907 inet_ntop(AF_INET, &claddr, 908 ntoab, sizeof (ntoab))); 909 } 910 goto leave_ack; 911 } else { 912 if (ciaddr.s_addr == 0L) { 913 (void) snprintf(nak_mesg, 914 sizeof (nak_mesg), 915 "No valid configuration exists on " 916 "network: %s", pnd->network); 917 pkt_type = NAK; 918 } else { 919 if (verbose) { 920 dhcpmsg(LOG_INFO, 921 "Client: %1$s is not " 922 "recorded as having " 923 "address: %2$s\n", 924 pcd->cidbuf, 925 inet_ntop(AF_INET, &ciaddr, 926 ntoab, sizeof (ntoab))); 927 } 928 goto leave_ack; 929 } 930 } 931 } 932 } 933 934 /* 935 * Produce the appropriate response. 936 */ 937 if (pkt_type == NAK) { 938 rep_pktp = gen_reply_pkt(pcd, plp, NAK, &replen, &optp, 939 &ifp->addr); 940 /* 941 * Setting yiaddr to the client's ciaddr abuses the 942 * semantics of yiaddr, So we set this to 0L. 943 * 944 * We twiddle the broadcast flag to force the 945 * server/relay agents to broadcast the NAK. 946 * 947 * Exception: If a client's lease has expired, and it 948 * is still trying to renegotiate its lease, AND ciaddr 949 * is set, AND ciaddr is on a "remote" net, unicast the 950 * NAK. Gross, huh? But SPA could make this happen with 951 * super short leases. 952 */ 953 rep_pktp->yiaddr.s_addr = 0L; 954 if (ciaddr.s_addr != 0L && 955 (ciaddr.s_addr & pnd->subnet.s_addr) != pnd->net.s_addr) { 956 dest_in.s_addr = ciaddr.s_addr; 957 } else { 958 rep_pktp->flags |= htons(BCAST_MASK); 959 dest_in.s_addr = INADDR_BROADCAST; 960 } 961 962 *optp++ = CD_MESSAGE; 963 *optp++ = (uchar_t)strlen(nak_mesg); 964 (void) memcpy(optp, nak_mesg, strlen(nak_mesg)); 965 optp += strlen(nak_mesg); 966 *optp = CD_END; 967 actual_len = BASE_PKT_SIZE + (uint_t)(optp - rep_pktp->options); 968 if (actual_len < sizeof (PKT)) 969 actual_len = sizeof (PKT); 970 971 (void) send_reply(ifp, rep_pktp, actual_len, &dest_in); 972 973 logtrans(P_DHCP, L_NAK, 0, dest_in, server_ip, plp); 974 } else { 975 rep_pktp = gen_reply_pkt(pcd, plp, ACK, &replen, &optp, 976 &ifp->addr); 977 978 /* Set the client's IP address */ 979 rep_pktp->yiaddr.s_addr = htonl(dnp->dn_cip.s_addr); 980 dest_in.s_addr = htonl(dnp->dn_cip.s_addr); 981 982 /* 983 * Macros are evaluated this way: First apply parameters 984 * from a client class macro (if present), then apply 985 * those from the network macro (if present), then apply 986 * those from the server macro (if present), and finally 987 * apply those from a client id macro (if present). 988 */ 989 ecp = vecp = NULL; 990 class_vecp = class_ecp = NULL; 991 net_vecp = net_ecp = NULL; 992 macro_vecp = macro_ecp = NULL; 993 cid_vecp = cid_ecp = NULL; 994 995 if (!no_dhcptab) { 996 open_macros(); 997 if ((net_mp = get_macro(pnd->network)) != NULL) 998 net_ecp = net_mp->head; 999 if ((pkt_mp = get_macro(dnp->dn_macro)) != NULL) 1000 macro_ecp = pkt_mp->head; 1001 if ((cid_mp = get_macro(pcd->cidbuf)) != NULL) 1002 cid_ecp = cid_mp->head; 1003 if (class_id != NULL) { 1004 if ((class_mp = get_macro(class_id)) != NULL) { 1005 class_vecp = vendor_encodes(class_mp, 1006 class_id); 1007 class_ecp = class_mp->head; 1008 } 1009 if (net_mp != NULL) { 1010 net_vecp = vendor_encodes(net_mp, 1011 class_id); 1012 } 1013 if (pkt_mp != NULL) 1014 macro_vecp = vendor_encodes(pkt_mp, 1015 class_id); 1016 if (cid_mp != NULL) { 1017 cid_vecp = vendor_encodes(cid_mp, 1018 class_id); 1019 } 1020 vecp = combine_encodes(class_vecp, net_vecp, 1021 ENC_COPY); 1022 vecp = combine_encodes(vecp, macro_vecp, 1023 ENC_DONT_COPY); 1024 vecp = combine_encodes(vecp, cid_vecp, 1025 ENC_DONT_COPY); 1026 } 1027 if (class_ecp != NULL) { 1028 ecp = combine_encodes(class_ecp, net_ecp, 1029 ENC_COPY); 1030 } else 1031 ecp = dup_encode_list(net_ecp); 1032 1033 ecp = combine_encodes(ecp, macro_ecp, ENC_DONT_COPY); 1034 ecp = combine_encodes(ecp, cid_ecp, ENC_DONT_COPY); 1035 1036 ncipaddr.s_addr = htonl(dnp->dn_cip.s_addr); 1037 /* 1038 * If the server is configured to do host name updates 1039 * and the REQUEST packet contains a hostname request, 1040 * see whether we can honor it. 1041 * 1042 * First, determine (via name_avail()) whether the host 1043 * name is unassigned or belongs to an unleased IP 1044 * address under our control. If not, we won't do a 1045 * host name update on behalf of the client. 1046 * 1047 * Second, if we own the IP address and it is in the 1048 * correct network table, see whether an update is 1049 * necessary (or, in the lucky case, whether the name 1050 * requested already belongs to that address), in which 1051 * case we need do nothing more than return the option. 1052 */ 1053 if ((nsutimeout_secs != DHCP_NO_NSU) && 1054 (plp->opts[CD_HOSTNAME] != NULL)) { 1055 char hname[MAXHOSTNAMELEN + 1]; 1056 int hlen; 1057 struct in_addr ia, *iap = &ia; 1058 1059 /* turn hostname option into a string */ 1060 hlen = plp->opts[CD_HOSTNAME]->len; 1061 hlen = MIN(hlen, MAXHOSTNAMELEN); 1062 (void) memcpy(hname, 1063 plp->opts[CD_HOSTNAME]->value, hlen); 1064 hname[hlen] = '\0'; 1065 1066 nlp = NULL; 1067 if (name_avail(hname, pcd, plp, &nlp, ecp, 1068 &iap)) { 1069 ENCODE *hecp; 1070 1071 /* 1072 * If we pass this test, it means either 1073 * no address is currently associated 1074 * with the requested host name (iap is 1075 * NULL) or the address doesn't match 1076 * the one to be leased; in either case 1077 * an update attempt is needed. 1078 * 1079 * Otherwise (in the else case), we need 1080 * only send the response - the name and 1081 * address already match. 1082 */ 1083 if ((iap == NULL) || (iap->s_addr != 1084 dnp->dn_cip.s_addr)) { 1085 if (do_nsupdate(dnp->dn_cip, 1086 ecp, plp)) { 1087 hecp = make_encode( 1088 DSYM_STANDARD, 1089 CD_HOSTNAME, 1090 strlen(hname), 1091 hname, 1092 ENC_COPY); 1093 replace_encode(&ecp, 1094 hecp, 1095 ENC_DONT_COPY); 1096 hostname_update = 1097 B_TRUE; 1098 } 1099 } else { 1100 hecp = make_encode( 1101 DSYM_STANDARD, 1102 CD_HOSTNAME, 1103 strlen(hname), hname, 1104 ENC_COPY); 1105 replace_encode(&ecp, hecp, 1106 ENC_DONT_COPY); 1107 hostname_update = B_TRUE; 1108 } 1109 if (nlp != NULL) 1110 dhcp_free_dd_list(pnd->dh, nlp); 1111 } 1112 } 1113 1114 /* 1115 * If dhcptab configured to return hostname, do so. 1116 */ 1117 if ((hostname_update == B_FALSE) && 1118 (find_encode(ecp, DSYM_INTERNAL, 1119 CD_BOOL_HOSTNAME) != NULL)) { 1120 struct hostent h, *hp; 1121 ENCODE *hecp; 1122 char hbuf[NSS_BUFLEN_HOSTS]; 1123 hp = gethostbyaddr_r((char *)&ncipaddr, 1124 sizeof (struct in_addr), AF_INET, &h, hbuf, 1125 sizeof (hbuf), &err); 1126 if (hp != NULL) { 1127 hecp = make_encode(DSYM_STANDARD, 1128 CD_HOSTNAME, strlen(hp->h_name), 1129 hp->h_name, ENC_COPY); 1130 replace_encode(&ecp, hecp, 1131 ENC_DONT_COPY); 1132 } 1133 } 1134 1135 /* 1136 * If dhcptab configured to echo client class, do so. 1137 */ 1138 if (plp->opts[CD_CLASS_ID] != NULL && 1139 find_encode(ecp, DSYM_INTERNAL, 1140 CD_BOOL_ECHO_VCLASS) != NULL) { 1141 ENCODE *echo_ecp; 1142 DHCP_OPT *op = plp->opts[CD_CLASS_ID]; 1143 echo_ecp = make_encode(DSYM_STANDARD, 1144 CD_CLASS_ID, op->len, op->value, 1145 ENC_COPY); 1146 replace_encode(&ecp, echo_ecp, ENC_DONT_COPY); 1147 } 1148 } 1149 1150 if (dnp->dn_flags & DN_FAUTOMATIC || dnp->dn_lease == DHCP_PERM) 1151 oldlease = DHCP_PERM; 1152 else { 1153 if (plp->opts[CD_SERVER_ID] != NULL) { 1154 /* 1155 * Offered absolute Lease time is cached 1156 * in the lease field of the record. If 1157 * that's expired, then they'll get the 1158 * policy value again here. Must have been 1159 * LONG time between DISC/REQ! 1160 */ 1161 if ((lease_t)dnp->dn_lease < (lease_t)now) 1162 oldlease = (lease_t)0; 1163 else 1164 oldlease = dnp->dn_lease - now; 1165 } else 1166 oldlease = dnp->dn_lease - now; 1167 } 1168 1169 if (find_encode(ecp, DSYM_INTERNAL, CD_BOOL_LEASENEG) != 1170 NULL) 1171 negot = B_TRUE; 1172 else 1173 negot = B_FALSE; 1174 1175 /* 1176 * Modify changed fields in new database record. 1177 */ 1178 ndn = *dnp; /* struct copy */ 1179 (void) memcpy(ndn.dn_cid, pcd->cid, pcd->cid_len); 1180 ndn.dn_cid_len = pcd->cid_len; 1181 1182 /* 1183 * This is a little longer than we offered (not taking into 1184 * account the secs field), but since I trust the UNIX 1185 * clock better than the PC's, it is a good idea to give 1186 * the PC a little more time than it thinks, just due to 1187 * clock slop on PC's. 1188 */ 1189 newlease = config_lease(plp, &ndn, &ecp, oldlease, negot); 1190 1191 if (newlease != DHCP_PERM) 1192 ndn.dn_lease = now + newlease; 1193 else 1194 ndn.dn_lease = DHCP_PERM; 1195 1196 1197 /* 1198 * It is critical to write the database record if the 1199 * client is in the INIT state, so we don't reply to the 1200 * client if this fails. However, if the client is simply 1201 * trying to verify its address or extend its lease, then 1202 * we'll reply regardless of the status of the write, 1203 * although we'll return the old lease time. 1204 * 1205 * If the client is in the INIT_REBOOT state, and the 1206 * lease time hasn't changed, we don't bother with the 1207 * write, since nothing has changed. 1208 */ 1209 if (clnt_state == INIT_STATE || oldlease != newlease) { 1210 1211 write_error = dhcp_modify_dd_entry(pnd->dh, dnp, &ndn); 1212 1213 /* Keep state of the cached entry current. */ 1214 if (write_error == DSVC_SUCCESS) { 1215 *dnp = ndn; /* struct copy */ 1216 } 1217 } else { 1218 if (verbose) { 1219 dhcpmsg(LOG_INFO, 1220 "Database write unnecessary for " 1221 "DHCP client: " 1222 "%1$s, %2$s\n", pcd->cidbuf, 1223 inet_ntop(AF_INET, &ncipaddr, 1224 ntoab, sizeof (ntoab))); 1225 } 1226 } 1227 if (write_error == DSVC_SUCCESS || 1228 clnt_state == INIT_REBOOT_STATE) { 1229 1230 if (write_error != DSVC_SUCCESS) 1231 set_lease_option(&ecp, oldlease); 1232 else { 1233 /* Note that the conversation has completed. */ 1234 pcd->state = ACK; 1235 } 1236 1237 if (plp->opts[CD_REQUEST_LIST]) 1238 add_request_list(ifp, plp, &ecp, &ncipaddr); 1239 1240 /* Now load all the asked for / configured options */ 1241 actual_len = load_options(DHCP_DHCP_CLNT | 1242 DHCP_SEND_LEASE, plp, rep_pktp, replen, optp, ecp, 1243 vecp); 1244 1245 if (actual_len < sizeof (PKT)) 1246 actual_len = sizeof (PKT); 1247 if (verbose) { 1248 dhcpmsg(LOG_INFO, 1249 "Client: %1$s maps to IP: %2$s\n", 1250 pcd->cidbuf, 1251 inet_ntop(AF_INET, &ncipaddr, 1252 ntoab, sizeof (ntoab))); 1253 } 1254 (void) send_reply(ifp, rep_pktp, actual_len, &dest_in); 1255 1256 if (clnt_state == INIT_STATE) 1257 log = L_ASSIGN; 1258 else 1259 log = L_REPLY; 1260 1261 logtrans(P_DHCP, log, ndn.dn_lease, ncipaddr, 1262 server_ip, plp); 1263 } 1264 1265 free_encode_list(ecp); 1266 free_encode_list(vecp); 1267 if (!no_dhcptab) 1268 close_macros(); 1269 } 1270 1271 leave_ack: 1272 if (rep_pktp != NULL) 1273 free(rep_pktp); 1274 if (dncp != NULL) 1275 dhcp_free_dd_list(pnd->dh, dncp); 1276 if (dnlp != NULL && !existing_offer) 1277 dhcp_free_dd_list(pnd->dh, dnlp); 1278 } 1279 1280 /* Reacting to a client's DECLINE or RELEASE. */ 1281 static void 1282 dhcp_dec_rel(dsvc_clnt_t *pcd, PKT_LIST *plp, int type) 1283 { 1284 char *fmtp; 1285 dn_rec_t *dnp, dn, ndn; 1286 dsvc_dnet_t *pnd; 1287 struct in_addr ip; 1288 int err = 0; 1289 DHCP_MSG_CATEGORIES log; 1290 dn_rec_list_t *dncp, *dnlp = NULL; 1291 uint32_t query; 1292 char ipb[INET_ADDRSTRLEN]; 1293 char clnt_msg[DHCP_MAX_OPT_SIZE]; 1294 1295 pnd = pcd->pnd; 1296 1297 if (type == DECLINE) { 1298 if (plp->opts[CD_REQUESTED_IP_ADDR] && 1299 plp->opts[CD_REQUESTED_IP_ADDR]->len == 1300 sizeof (struct in_addr)) { 1301 (void) memcpy((char *)&ip, 1302 plp->opts[CD_REQUESTED_IP_ADDR]->value, 1303 sizeof (struct in_addr)); 1304 } 1305 } else 1306 ip.s_addr = plp->pkt->ciaddr.s_addr; 1307 1308 (void) inet_ntop(AF_INET, &ip, ipb, sizeof (ipb)); 1309 1310 /* Look for a matching IP address and Client ID */ 1311 1312 DSVC_QINIT(query); 1313 DSVC_QEQ(query, DN_QCID|DN_QCIP); 1314 (void) memcpy(dn.dn_cid, pcd->cid, pcd->cid_len); 1315 dn.dn_cid_len = pcd->cid_len; 1316 dn.dn_cip.s_addr = ntohl(ip.s_addr); 1317 1318 dncp = NULL; 1319 dnlp = dhcp_lookup_dd_classify(pcd->pnd, B_FALSE, query, -1, 1320 &dn, (void **)&dncp, S_CID); 1321 assert(dncp == NULL); 1322 1323 if (dnlp == NULL) { 1324 if (verbose) { 1325 if (type == DECLINE) { 1326 fmtp = "Unregistered client: %1$s is " 1327 "DECLINEing address: %2$s.\n"; 1328 } else { 1329 fmtp = "Unregistered client: %1$s is " 1330 "RELEASEing address: %2$s.\n"; 1331 } 1332 dhcpmsg(LOG_INFO, fmtp, pcd->cidbuf, ipb); 1333 } 1334 return; 1335 } 1336 1337 dnp = dnlp->dnl_rec; 1338 ndn = *dnp; /* struct copy */ 1339 1340 /* If the entry is not one of ours, then give up. */ 1341 if (match_ownerip(htonl(ndn.dn_sip.s_addr)) == NULL) { 1342 if (verbose) { 1343 if (type == DECLINE) { 1344 fmtp = "Client: %1$s is DECLINEing: " 1345 "%2$s not owned by this server.\n"; 1346 } else { 1347 fmtp = "Client: %1$s is RELEASEing: " 1348 "%2$s not owned by this server.\n"; 1349 } 1350 dhcpmsg(LOG_INFO, fmtp, pcd->cidbuf, ipb); 1351 } 1352 goto leave_dec_rel; 1353 } 1354 1355 if (type == DECLINE) { 1356 log = L_DECLINE; 1357 dhcpmsg(LOG_ERR, "Client: %1$s DECLINED address: %2$s.\n", 1358 pcd->cidbuf, ipb); 1359 if (plp->opts[CD_MESSAGE]) { 1360 dhcpmsg(LOG_ERR, "DECLINE: client message: %s\n", 1361 disp_clnt_msg(plp, clnt_msg, sizeof (clnt_msg))); 1362 } 1363 ndn.dn_flags |= DN_FUNUSABLE; 1364 } else { 1365 log = L_RELEASE; 1366 if (ndn.dn_flags & DN_FMANUAL) { 1367 dhcpmsg(LOG_ERR, 1368 "Client: %1$s is trying to RELEASE manual " 1369 "address: %2$s\n", pcd->cidbuf, ipb); 1370 goto leave_dec_rel; 1371 } 1372 if (verbose) { 1373 dhcpmsg(LOG_INFO, 1374 "Client: %1$s RELEASED address: %2$s\n", 1375 pcd->cidbuf, ipb); 1376 if (plp->opts[CD_MESSAGE]) { 1377 dhcpmsg(LOG_INFO, 1378 "RELEASE: client message: %s\n", 1379 disp_clnt_msg(plp, clnt_msg, 1380 sizeof (clnt_msg))); 1381 } 1382 } 1383 } 1384 1385 /* Clear out the cid and lease fields */ 1386 if (!(ndn.dn_flags & DN_FMANUAL)) { 1387 ndn.dn_cid[0] = '\0'; 1388 ndn.dn_cid_len = 1; 1389 ndn.dn_lease = (lease_t)0; 1390 } 1391 1392 /* Ignore write errors. */ 1393 err = dhcp_modify_dd_entry(pnd->dh, dnp, &ndn); 1394 if (err != DSVC_SUCCESS) { 1395 dhcpmsg(LOG_NOTICE, 1396 "%1$s: ERROR modifying database: %2$s for client %3$s\n", 1397 log == L_RELEASE ? "RELEASE" : "DECLINE", 1398 dhcpsvc_errmsg(err), ipb); 1399 } else { 1400 if (type == RELEASE) { 1401 /* 1402 * performance: save select_offer() lots of work by 1403 * caching this perfectly good ip address in freerec. 1404 */ 1405 *(dnlp->dnl_rec) = ndn; /* struct copy */ 1406 add_dnet_cache(pnd, dnlp); 1407 dnlp = NULL; 1408 } 1409 } 1410 1411 logtrans(P_DHCP, log, ndn.dn_lease, ip, server_ip, plp); 1412 1413 leave_dec_rel: 1414 1415 if (dnlp != NULL) 1416 dhcp_free_dd_list(pnd->dh, dnlp); 1417 } 1418 1419 /* 1420 * Responding to an INFORM message. 1421 * 1422 * INFORM messages are received from clients that already have their network 1423 * parameters (such as IP address and subnet mask), but wish to receive 1424 * other configuration parameters. The server will not check for an existing 1425 * lease as clients may have obtained their network parameters by some 1426 * means other than DHCP. Similarly, the DHCPACK generated in response to 1427 * the INFORM message will not include lease time information. All other 1428 * configuration parameters are returned. 1429 */ 1430 static void 1431 dhcp_inform(dsvc_clnt_t *pcd, PKT_LIST *plp) 1432 { 1433 uint_t replen; 1434 int used_pkt_len; 1435 PKT *rep_pktp = NULL; 1436 uchar_t *optp; 1437 ENCODE *ecp, *vecp, *class_ecp, *class_vecp, 1438 *cid_ecp, *cid_vecp, *net_ecp, *net_vecp; 1439 MACRO *net_mp, *class_mp, *cid_mp; 1440 dsvc_dnet_t *pnd; 1441 char *class_id; 1442 char class_idbuf[DSYM_CLASS_SIZE]; 1443 IF *ifp = pcd->ifp; 1444 1445 pnd = pcd->pnd; 1446 class_id = get_class_id(plp, class_idbuf, sizeof (class_idbuf)); 1447 1448 /* 1449 * Macros are evaluated this way: First apply parameters from 1450 * a client class macro (if present), then apply those from the 1451 * network macro (if present), and finally apply those from a 1452 * client id macro (if present). 1453 */ 1454 ecp = vecp = NULL; 1455 net_vecp = net_ecp = NULL; 1456 class_vecp = class_ecp = NULL; 1457 cid_vecp = cid_ecp = NULL; 1458 1459 if (!no_dhcptab) { 1460 open_macros(); 1461 if ((net_mp = get_macro(pnd->network)) != NULL) 1462 net_ecp = net_mp->head; 1463 if ((cid_mp = get_macro(pcd->cidbuf)) != NULL) 1464 cid_ecp = cid_mp->head; 1465 if (class_id != NULL) { 1466 if ((class_mp = get_macro(class_id)) != NULL) { 1467 class_vecp = vendor_encodes(class_mp, 1468 class_id); 1469 class_ecp = class_mp->head; 1470 } 1471 if (net_mp != NULL) 1472 net_vecp = vendor_encodes(net_mp, class_id); 1473 if (cid_mp != NULL) 1474 cid_vecp = vendor_encodes(cid_mp, class_id); 1475 vecp = combine_encodes(class_vecp, net_vecp, 1476 ENC_COPY); 1477 vecp = combine_encodes(vecp, cid_vecp, ENC_DONT_COPY); 1478 } 1479 1480 ecp = combine_encodes(class_ecp, net_ecp, ENC_COPY); 1481 ecp = combine_encodes(ecp, cid_ecp, ENC_DONT_COPY); 1482 } 1483 1484 /* First get a generic reply packet. */ 1485 rep_pktp = gen_reply_pkt(pcd, plp, ACK, &replen, &optp, &ifp->addr); 1486 1487 /* 1488 * Client is requesting specific options. let's try and ensure it 1489 * gets what it wants, if at all possible. 1490 */ 1491 if (plp->opts[CD_REQUEST_LIST] != NULL) 1492 add_request_list(ifp, plp, &ecp, &plp->pkt->ciaddr); 1493 1494 /* 1495 * Explicitly set the ciaddr to be that which the client gave 1496 * us. 1497 */ 1498 rep_pktp->ciaddr.s_addr = plp->pkt->ciaddr.s_addr; 1499 1500 /* 1501 * Now load all the asked for / configured options. DON'T send 1502 * any lease time info! 1503 */ 1504 used_pkt_len = load_options(DHCP_DHCP_CLNT, plp, rep_pktp, replen, optp, 1505 ecp, vecp); 1506 1507 free_encode_list(ecp); 1508 free_encode_list(vecp); 1509 if (!no_dhcptab) 1510 close_macros(); 1511 1512 if (used_pkt_len < sizeof (PKT)) 1513 used_pkt_len = sizeof (PKT); 1514 1515 (void) send_reply(ifp, rep_pktp, used_pkt_len, &plp->pkt->ciaddr); 1516 1517 logtrans(P_DHCP, L_INFORM, 0, plp->pkt->ciaddr, server_ip, plp); 1518 1519 leave_inform: 1520 if (rep_pktp != NULL) 1521 free(rep_pktp); 1522 } 1523 1524 static char * 1525 disp_clnt_msg(PKT_LIST *plp, char *bufp, int len) 1526 { 1527 uchar_t tlen; 1528 1529 bufp[0] = '\0'; /* null string */ 1530 1531 if (plp && plp->opts[CD_MESSAGE]) { 1532 tlen = ((uchar_t)len < plp->opts[CD_MESSAGE]->len) ? 1533 (len - 1) : plp->opts[CD_MESSAGE]->len; 1534 (void) memcpy(bufp, plp->opts[CD_MESSAGE]->value, tlen); 1535 bufp[tlen] = '\0'; 1536 } 1537 return (bufp); 1538 } 1539 1540 /* 1541 * serverip expected in host order 1542 */ 1543 static PKT * 1544 gen_reply_pkt(dsvc_clnt_t *pcd, PKT_LIST *plp, int type, uint_t *len, 1545 uchar_t **optpp, struct in_addr *serverip) 1546 { 1547 PKT *reply_pktp; 1548 uint16_t plen; 1549 1550 /* 1551 * We need to determine the packet size. Perhaps the client has told 1552 * us? 1553 */ 1554 if (plp->opts[CD_MAX_DHCP_SIZE]) { 1555 if (plp->opts[CD_MAX_DHCP_SIZE]->len != sizeof (uint16_t)) { 1556 dhcpmsg(LOG_ERR, "Garbled MAX DHCP message size option " 1557 "from\nclient: '%1$s'. Len is %2$d, when it should " 1558 "be %3$d. Defaulting to %4$d.\n", 1559 pcd->cidbuf, 1560 plp->opts[CD_MAX_DHCP_SIZE]->len, 1561 sizeof (uint16_t), DHCP_DEF_MAX_SIZE); 1562 plen = DHCP_DEF_MAX_SIZE; 1563 } else { 1564 (void) memcpy(&plen, plp->opts[CD_MAX_DHCP_SIZE]->value, 1565 sizeof (uint16_t)); 1566 plen = ntohs(plen); 1567 if (plen < DHCP_DEF_MAX_SIZE) 1568 plen = DHCP_DEF_MAX_SIZE; 1569 } 1570 } else { 1571 /* 1572 * Define size to be a fixed length. Too hard to add up all 1573 * possible class id, macro, and hostname/lease time options 1574 * without doing just about as much work as constructing the 1575 * whole reply packet. 1576 */ 1577 plen = DHCP_MAX_REPLY_SIZE; 1578 } 1579 1580 /* Generate a generically initialized BOOTP packet */ 1581 reply_pktp = gen_bootp_pkt(plen, plp->pkt); 1582 1583 reply_pktp->op = BOOTREPLY; 1584 *optpp = reply_pktp->options; 1585 1586 /* 1587 * Set pkt type. 1588 */ 1589 *(*optpp)++ = (uchar_t)CD_DHCP_TYPE; 1590 *(*optpp)++ = (uchar_t)1; 1591 *(*optpp)++ = (uchar_t)type; 1592 1593 /* 1594 * All reply packets have server id set. 1595 */ 1596 *(*optpp)++ = (uchar_t)CD_SERVER_ID; 1597 *(*optpp)++ = (uchar_t)4; 1598 #if defined(_LITTLE_ENDIAN) 1599 *(*optpp)++ = (uchar_t)(serverip->s_addr & 0xff); 1600 *(*optpp)++ = (uchar_t)((serverip->s_addr >> 8) & 0xff); 1601 *(*optpp)++ = (uchar_t)((serverip->s_addr >> 16) & 0xff); 1602 *(*optpp)++ = (uchar_t)((serverip->s_addr >> 24) & 0xff); 1603 #else 1604 *(*optpp)++ = (uchar_t)((serverip->s_addr >> 24) & 0xff); 1605 *(*optpp)++ = (uchar_t)((serverip->s_addr >> 16) & 0xff); 1606 *(*optpp)++ = (uchar_t)((serverip->s_addr >> 8) & 0xff); 1607 *(*optpp)++ = (uchar_t)(serverip->s_addr & 0xff); 1608 #endif /* _LITTLE_ENDIAN */ 1609 1610 *len = plen; 1611 return (reply_pktp); 1612 } 1613 1614 /* 1615 * If the client requests it, and either it isn't currently configured 1616 * or hasn't already been added, provide the option now. Will also work 1617 * for NULL ENCODE lists, but initializing them to point to the requested 1618 * options. 1619 * 1620 * If nsswitch contains host name services which hang, big problems occur 1621 * with dhcp server, since the main thread hangs waiting for that name 1622 * service's timeout. 1623 * 1624 * NOTE: this function should be called only after all other parameter 1625 * merges have taken place (combine_encode). 1626 */ 1627 static void 1628 add_request_list(IF *ifp, PKT_LIST *plp, ENCODE **ecp, struct in_addr *ip) 1629 { 1630 ENCODE *ep, *ifecp, *end_ecp = NULL; 1631 struct hostent h, *hp; 1632 char hbuf[NSS_BUFLEN_HOSTS]; 1633 int herrno; 1634 1635 /* Find the end. */ 1636 if (*ecp) { 1637 for (ep = *ecp; ep->next; ep = ep->next) 1638 /* null */; 1639 end_ecp = ep; 1640 } 1641 1642 /* HOSTNAME */ 1643 if (is_option_requested(plp, CD_HOSTNAME) && 1644 (find_encode(*ecp, DSYM_STANDARD, CD_HOSTNAME) == NULL) && 1645 (find_encode(*ecp, DSYM_INTERNAL, CD_BOOL_HOSTNAME) == NULL)) { 1646 hp = gethostbyaddr_r((char *)ip, sizeof (struct in_addr), 1647 AF_INET, &h, hbuf, sizeof (hbuf), &herrno); 1648 if (hp != NULL) { 1649 if (end_ecp) { 1650 end_ecp->next = make_encode(DSYM_STANDARD, 1651 CD_HOSTNAME, strlen(hp->h_name), 1652 hp->h_name, ENC_COPY); 1653 end_ecp = end_ecp->next; 1654 } else { 1655 end_ecp = make_encode(DSYM_STANDARD, 1656 CD_HOSTNAME, strlen(hp->h_name), 1657 hp->h_name, ENC_COPY); 1658 } 1659 } 1660 } 1661 1662 /* 1663 * all bets off for the following if thru a relay agent. 1664 */ 1665 if (plp->pkt->giaddr.s_addr != 0L) 1666 return; 1667 1668 /* SUBNET MASK */ 1669 if (is_option_requested(plp, CD_SUBNETMASK) && find_encode(*ecp, 1670 DSYM_STANDARD, CD_SUBNETMASK) == NULL) { 1671 ifecp = find_encode(ifp->ecp, DSYM_STANDARD, CD_SUBNETMASK); 1672 if (end_ecp) { 1673 end_ecp->next = dup_encode(ifecp); 1674 end_ecp = end_ecp->next; 1675 } else 1676 end_ecp = dup_encode(ifecp); 1677 } 1678 1679 /* BROADCAST ADDRESS */ 1680 if (is_option_requested(plp, CD_BROADCASTADDR) && find_encode(*ecp, 1681 DSYM_STANDARD, CD_BROADCASTADDR) == NULL) { 1682 ifecp = find_encode(ifp->ecp, DSYM_STANDARD, 1683 CD_BROADCASTADDR); 1684 if (end_ecp) { 1685 end_ecp->next = dup_encode(ifecp); 1686 end_ecp = end_ecp->next; 1687 } else 1688 end_ecp = dup_encode(ifecp); 1689 } 1690 1691 /* IP MTU */ 1692 if (is_option_requested(plp, CD_MTU) && find_encode(*ecp, 1693 DSYM_STANDARD, CD_MTU) == NULL) { 1694 ifecp = find_encode(ifp->ecp, DSYM_STANDARD, CD_MTU); 1695 if (end_ecp) { 1696 end_ecp->next = dup_encode(ifecp); 1697 end_ecp = end_ecp->next; 1698 } else 1699 end_ecp = dup_encode(ifecp); 1700 } 1701 1702 if (*ecp == NULL) 1703 *ecp = end_ecp; 1704 } 1705 1706 /* 1707 * Is a specific option requested? Returns True if so, False otherwise. 1708 */ 1709 static int 1710 is_option_requested(PKT_LIST *plp, ushort_t code) 1711 { 1712 uchar_t c, *tp; 1713 DHCP_OPT *cp = plp->opts[CD_REQUEST_LIST]; 1714 1715 for (c = 0, tp = (uchar_t *)cp->value; c < cp->len; c++, tp++) { 1716 if (*tp == (uchar_t)code) 1717 return (B_TRUE); 1718 } 1719 return (B_FALSE); 1720 } 1721 1722 /* 1723 * Locates lease option, if possible, otherwise allocates an encode and 1724 * appends it to the end. Changes current lease setting. 1725 * 1726 * TODO: ugh. We don't address the case where the Lease time changes, but 1727 * T1 and T2 don't. We don't want T1 or T2 to be greater than the lease 1728 * time! Perhaps T1 and T2 should be a percentage of lease time... Later.. 1729 */ 1730 static void 1731 set_lease_option(ENCODE **ecpp, lease_t lease) 1732 { 1733 ENCODE *ep, *prev_ep, *lease_ep; 1734 1735 lease = htonl(lease); 1736 1737 if (ecpp != NULL && (lease_ep = find_encode(*ecpp, DSYM_STANDARD, 1738 CD_LEASE_TIME)) != NULL && lease_ep->len == sizeof (lease_t)) { 1739 (void) memcpy(lease_ep->data, (void *)&lease, sizeof (lease_t)); 1740 } else { 1741 if (*ecpp != NULL) { 1742 for (prev_ep = ep = *ecpp; ep != NULL; ep = ep->next) 1743 prev_ep = ep; 1744 prev_ep->next = make_encode(DSYM_STANDARD, 1745 CD_LEASE_TIME, sizeof (lease_t), &lease, ENC_COPY); 1746 } else { 1747 *ecpp = make_encode(DSYM_STANDARD, CD_LEASE_TIME, 1748 sizeof (lease_t), &lease, ENC_COPY); 1749 (*ecpp)->next = NULL; 1750 } 1751 } 1752 } 1753 /* 1754 * Sets appropriate option in passed ENCODE list for lease. Returns 1755 * calculated relative lease time. 1756 */ 1757 static int 1758 config_lease(PKT_LIST *plp, dn_rec_t *dnp, ENCODE **ecpp, lease_t oldlease, 1759 boolean_t negot) 1760 { 1761 lease_t newlease, rel_current; 1762 ENCODE *lease_ecp; 1763 1764 if (ecpp != NULL && (lease_ecp = find_encode(*ecpp, DSYM_STANDARD, 1765 CD_LEASE_TIME)) != NULL && lease_ecp->len == sizeof (lease_t)) { 1766 (void) memcpy((void *)&rel_current, lease_ecp->data, 1767 sizeof (lease_t)); 1768 rel_current = htonl(rel_current); 1769 } else 1770 rel_current = (lease_t)DEFAULT_LEASE; 1771 1772 if (dnp->dn_flags & DN_FAUTOMATIC || !negot) { 1773 if (dnp->dn_flags & DN_FAUTOMATIC) 1774 newlease = ntohl(DHCP_PERM); 1775 else { 1776 /* sorry! */ 1777 if (oldlease) 1778 newlease = oldlease; 1779 else 1780 newlease = rel_current; 1781 } 1782 } else { 1783 /* 1784 * lease is not automatic and is negotiable! 1785 * If the dhcp-network lease is bigger than the current 1786 * policy value, then let the client benefit from this 1787 * situation. 1788 */ 1789 if (oldlease > rel_current) 1790 rel_current = oldlease; 1791 1792 if (plp->opts[CD_LEASE_TIME] && 1793 plp->opts[CD_LEASE_TIME]->len == sizeof (lease_t)) { 1794 /* 1795 * Client is requesting a lease renegotiation. 1796 */ 1797 (void) memcpy((void *)&newlease, 1798 plp->opts[CD_LEASE_TIME]->value, sizeof (lease_t)); 1799 1800 newlease = ntohl(newlease); 1801 1802 /* 1803 * Note that this comparison handles permanent 1804 * leases as well. Limit lease to configured value. 1805 */ 1806 if (newlease > rel_current) 1807 newlease = rel_current; 1808 } else 1809 newlease = rel_current; 1810 } 1811 1812 set_lease_option(ecpp, newlease); 1813 1814 return (newlease); 1815 } 1816 1817 /* 1818 * If a packet has the classid set, return the value, else return null. 1819 */ 1820 char * 1821 get_class_id(PKT_LIST *plp, char *bufp, int len) 1822 { 1823 uchar_t *ucp, ulen; 1824 char *retp; 1825 1826 if (plp->opts[CD_CLASS_ID]) { 1827 /* 1828 * If the class id is set, see if there is a macro by this 1829 * name. If so, then "OR" the ENCODE settings of the class 1830 * macro with the packet macro. Settings in the packet macro 1831 * OVERRIDE settings in the class macro. 1832 */ 1833 ucp = plp->opts[CD_CLASS_ID]->value; 1834 ulen = plp->opts[CD_CLASS_ID]->len; 1835 if (len < ulen) 1836 ulen = len; 1837 (void) memcpy(bufp, ucp, ulen); 1838 bufp[ulen] = '\0'; 1839 1840 retp = bufp; 1841 } else 1842 retp = NULL; 1843 1844 return (retp); 1845 } 1846 1847 /* 1848 * Checks whether an offer ip address in the per net inet address 1849 * cache. 1850 * 1851 * pnd - per net structure 1852 * reservep - address to check, in network order. 1853 */ 1854 static boolean_t 1855 check_offer(dsvc_dnet_t *pnd, struct in_addr *reservep) 1856 { 1857 dsvc_clnt_t tpcd; 1858 1859 tpcd.off_ip.s_addr = reservep->s_addr; 1860 1861 return (hash_Lookup(pnd->itable, reservep, sizeof (struct in_addr), 1862 clnt_netcmp, &tpcd, B_FALSE) == NULL ? B_TRUE : B_FALSE); 1863 } 1864 1865 /* 1866 * Adds or updates an offer to the per client data structure. The client 1867 * struct is hashed by clientid into the per net ctable hash table, and 1868 * by offer address in the itable hash table, which is used to reserve the 1869 * ip address. Lease time is expected to be set by caller. 1870 * Will update existing OFFER if already provided. 1871 * 1872 * This implementation does not consider the fact that an offer can be 1873 * sent out via more than one interface, so dsvc_clnt_t.ifp should 1874 * really be a list or the itable's entries should be lists of 1875 * dsvc_clnt_ts. As long as we don't change this, we assume that the 1876 * client will eventually REQUEST the last offer we have sent out 1877 * because when we receive the same DISCOVER via multiple interfaces, 1878 * we always update the same offer cache entry so its ifp is always 1879 * the interface we received the last DISCOVER on. 1880 * 1881 * pcd - per client data struct. 1882 * dnlp - pointer to pointer to current container entry. Performance: caching 1883 * reduces datastore activity, structure copying. 1884 * nlease - new lease time. 1885 * reservep - new offer address (expected in network order). 1886 * purge_cache - Multithreading: avoid redundant cache purging in 1887 * select_offer(). 1888 */ 1889 boolean_t 1890 update_offer(dsvc_clnt_t *pcd, dn_rec_list_t **dnlp, lease_t nlease, 1891 struct in_addr *reservep, boolean_t purge_cache) 1892 { 1893 char ntoab[INET_ADDRSTRLEN]; 1894 boolean_t insert = B_TRUE; 1895 boolean_t update = B_FALSE; 1896 boolean_t offer = B_FALSE; 1897 dsvc_dnet_t *pnd = pcd->pnd; 1898 IF *ifp = pcd->ifp; 1899 dn_rec_t *dnp = NULL; 1900 struct in_addr off_ip; 1901 1902 /* Save the original datastore record. */ 1903 if (dnlp != NULL && *dnlp != NULL) { 1904 if (pcd->dnlp != NULL && pcd->dnlp != *dnlp) 1905 dhcp_free_dd_list(pnd->dh, pcd->dnlp); 1906 pcd->dnlp = *dnlp; 1907 } 1908 if (pcd->dnlp != NULL) 1909 dnp = pcd->dnlp->dnl_rec; 1910 1911 /* Determine the offer address. */ 1912 if (reservep == NULL && dnp != NULL) 1913 off_ip.s_addr = htonl(dnp->dn_cip.s_addr); 1914 else if (reservep != NULL) 1915 off_ip.s_addr = reservep->s_addr; 1916 else { 1917 dhcpmsg(LOG_DEBUG, 1918 "Neither offer IP nor IP to reserve present\n"); 1919 assert(B_FALSE); 1920 return (B_FALSE); 1921 } 1922 1923 /* If updating, release the old offer address. */ 1924 if (pcd->off_ip.s_addr == htonl(INADDR_ANY)) { 1925 offer = B_TRUE; 1926 } else { 1927 update = B_TRUE; 1928 if (pcd->off_ip.s_addr != off_ip.s_addr) { 1929 purge_offer(pcd, B_FALSE, purge_cache); 1930 offer = B_TRUE; 1931 } else 1932 insert = B_FALSE; 1933 } 1934 1935 if (nlease != 0) 1936 pcd->lease = nlease; 1937 1938 /* Prepare to insert pcd into the offer hash table. */ 1939 pcd->mtime = reinit_time; 1940 1941 pcd->off_ip.s_addr = off_ip.s_addr; 1942 1943 assert(pcd->off_ip.s_addr != htonl(INADDR_ANY)); 1944 1945 if (insert) { 1946 if ((pcd->ihand = hash_Insert(pnd->itable, &pcd->off_ip, 1947 sizeof (struct in_addr), clnt_netcmp, pcd, pcd)) == NULL) { 1948 if (reservep == NULL) { 1949 dhcpmsg(LOG_WARNING, "Duplicate offer of %1$s " 1950 "to client: %2$s\n", 1951 inet_ntop(AF_INET, &pcd->off_ip, ntoab, 1952 sizeof (ntoab)), pcd->cidbuf); 1953 } 1954 pcd->off_ip.s_addr = htonl(INADDR_ANY); 1955 dhcp_free_dd_list(pnd->dh, pcd->dnlp); 1956 if (dnlp != NULL && *dnlp != NULL && 1957 pcd->dnlp == *dnlp) { 1958 *dnlp = NULL; 1959 } 1960 pcd->dnlp = NULL; 1961 return (B_FALSE); 1962 } 1963 } else 1964 hash_Dtime(pcd->ihand, time(NULL) + off_secs); 1965 1966 if (offer) { 1967 (void) mutex_lock(&ifp->ifp_mtx); 1968 ifp->offers++; 1969 (void) mutex_unlock(&ifp->ifp_mtx); 1970 } 1971 1972 if (debug) { 1973 if (reservep != NULL) { 1974 dhcpmsg(LOG_INFO, "Reserved offer: %s\n", 1975 inet_ntop(AF_INET, &pcd->off_ip, 1976 ntoab, sizeof (ntoab))); 1977 } else if (update) { 1978 dhcpmsg(LOG_INFO, "Updated offer: %s\n", 1979 inet_ntop(AF_INET, &pcd->off_ip, 1980 ntoab, sizeof (ntoab))); 1981 } else { 1982 dhcpmsg(LOG_INFO, "Added offer: %s\n", 1983 inet_ntop(AF_INET, &pcd->off_ip, 1984 ntoab, sizeof (ntoab))); 1985 } 1986 } 1987 return (B_TRUE); 1988 } 1989 1990 /* 1991 * Deletes an offer. 1992 * 1993 * pcd - per client struct 1994 * expired - has offer expired, or been purged 1995 * purge_cache - Multi-threading: avoid redundant cache purging in 1996 * select_offer(). 1997 */ 1998 void 1999 purge_offer(dsvc_clnt_t *pcd, boolean_t expired, boolean_t purge_cache) 2000 { 2001 char ntoab[INET_ADDRSTRLEN]; 2002 dsvc_dnet_t *pnd = pcd->pnd; 2003 IF *ifp = pcd->ifp; 2004 2005 if (pcd->off_ip.s_addr != htonl(INADDR_ANY)) { 2006 if (debug) { 2007 if (expired == B_TRUE) 2008 dhcpmsg(LOG_INFO, "Freeing offer: %s\n", 2009 inet_ntop(AF_INET, &pcd->off_ip, 2010 ntoab, sizeof (ntoab))); 2011 else 2012 dhcpmsg(LOG_INFO, "Purging offer: %s\n", 2013 inet_ntop(AF_INET, &pcd->off_ip, 2014 ntoab, sizeof (ntoab))); 2015 } 2016 2017 /* 2018 * The offer cache ensures that recently granted offer 2019 * addresses won't attempt to be reused from the dnet 2020 * caches. When purging one of these offers, be sure to 2021 * remove the associated record from the dnet cache, 2022 * to avoid collisions. 2023 */ 2024 if (pcd->state == ACK && pcd->dnlp != NULL) { 2025 if (purge_cache) 2026 purge_dnet_cache(pnd, pcd->dnlp->dnl_rec); 2027 dhcp_free_dd_list(pnd->dh, pcd->dnlp); 2028 pcd->dnlp = NULL; 2029 } 2030 2031 2032 /* Prepare to delete pcd from the offer hash table. */ 2033 (void) hash_Delete(pnd->itable, &pcd->off_ip, 2034 sizeof (struct in_addr), clnt_netcmp, pcd, NULL); 2035 2036 pcd->off_ip.s_addr = htonl(INADDR_ANY); 2037 2038 (void) mutex_lock(&ifp->ifp_mtx); 2039 if (ifp->offers > 0) 2040 ifp->offers--; 2041 if (expired) 2042 ifp->expired++; 2043 (void) mutex_unlock(&ifp->ifp_mtx); 2044 } 2045 } 2046 2047 /* 2048 * Allocate a new entry in the dhcp-network db for the cid, taking into 2049 * account requested IP address. Verify address. 2050 * 2051 * The network portion of the address doesn't have to be the same as ours, 2052 * just owned by us. We also make sure we don't select a record which is 2053 * currently in use, by reserving the address in the offer cache. Database 2054 * records are cached up to the D_OFFER lifetime to improve performance. 2055 * 2056 * Returns: 1 if there's a usable entry for the client, 0 2057 * if not. Places the record in the dn_rec_list_t structure 2058 * pointer handed in. 2059 */ 2060 /*ARGSUSED*/ 2061 boolean_t 2062 select_offer(dsvc_dnet_t *pnd, PKT_LIST *plp, dsvc_clnt_t *pcd, 2063 dn_rec_list_t **dnlpp) 2064 { 2065 struct in_addr req_ip, *req_ipp = &req_ip, tip; 2066 boolean_t found = B_FALSE; 2067 time_t now; 2068 dn_rec_t dn, *dnp; 2069 dn_rec_list_t *dncp, *dnsp, *tlp; 2070 int nrecords; 2071 uint32_t query; 2072 int retry; 2073 boolean_t io_done, is_bootp; 2074 struct in_addr *oip; 2075 2076 if (plp->opts[CD_DHCP_TYPE] == NULL) 2077 is_bootp = B_TRUE; 2078 else 2079 is_bootp = B_FALSE; 2080 2081 *dnlpp = NULL; 2082 if (!is_bootp) { 2083 /* 2084 * Is the DHCP client requesting a specific address? Is so, and 2085 * we can satisfy him, do so. 2086 */ 2087 if (plp->opts[CD_REQUESTED_IP_ADDR] != NULL) { 2088 (void) memcpy((void *)&req_ip, 2089 plp->opts[CD_REQUESTED_IP_ADDR]->value, 2090 sizeof (struct in_addr)); 2091 2092 if ((req_ip.s_addr & pnd->subnet.s_addr) == 2093 pnd->net.s_addr) 2094 found = B_TRUE; 2095 2096 } else if (plp->opts[CD_HOSTNAME] != NULL) { 2097 char hname[MAXHOSTNAMELEN + 1]; 2098 int hlen; 2099 2100 /* turn hostname option into a string */ 2101 hlen = plp->opts[CD_HOSTNAME]->len; 2102 hlen = MIN(hlen, MAXHOSTNAMELEN); 2103 (void) memcpy(hname, plp->opts[CD_HOSTNAME]->value, 2104 hlen); 2105 hname[hlen] = '\0'; 2106 2107 dhcpmsg(LOG_DEBUG, 2108 "select_offer: hostname request for %s\n", hname); 2109 if (name_avail(hname, pcd, plp, dnlpp, NULL, 2110 &req_ipp) && req_ipp) { 2111 if ((req_ip.s_addr & pnd->subnet.s_addr) == 2112 pnd->net.s_addr) { 2113 found = B_TRUE; 2114 } else if (*dnlpp != NULL) { 2115 dhcp_free_dd_list(pnd->dh, *dnlpp); 2116 *dnlpp = NULL; 2117 } 2118 dhcpmsg(LOG_DEBUG, "select_offer: hostname %s " 2119 "available, req_ip %x\n", hname, 2120 ntohl(req_ip.s_addr)); 2121 } else 2122 dhcpmsg(LOG_DEBUG, "select_offer: name_avail " 2123 "false or no address for %s\n", hname); 2124 } 2125 } 2126 2127 /* 2128 * Check the offer list and table entry. 2129 */ 2130 if (found && *dnlpp == NULL) 2131 found = addr_avail(pnd, pcd, dnlpp, req_ip, B_FALSE); 2132 2133 if (!found) { 2134 /* 2135 * Try to find a free entry. Look for an AVAILABLE entry 2136 * (cid == 0x00, len == 1), owned by us. 2137 * The outer loop runs through the server ips owned by us. 2138 * 2139 * Multi-threading: to improve performance, the following 2140 * algorithm coordinates accesses to the underlying table, 2141 * so only one thread is initiating lookups per network. 2142 * This is crucial, as lookup operations are expensive, 2143 * and not sufficiently malleable to allow partitioned 2144 * lookups (e.g. all that can be asked for are n free or 2145 * server-owned entries, multiple threads will retrieve 2146 * the same records). 2147 * 2148 * The three iterations through the inner loop attempt to use 2149 * 2150 * 1) the next cached entry 2151 * 2) all cached entries 2152 * 3) all free or per-server entries in the underlying table 2153 * 2154 * Since many threads are consuming the cached entries, 2155 * any thread may find itself in the role of having to 2156 * refresh the cache. We always read at least enough 2157 * entries to satisfy all current threads. Reading all 2158 * records is prohibitively expensive, and should only 2159 * be done as a last resort. 2160 * 2161 * As always, to better distribute garbage 2162 * collection and data structure aging tasks, each 2163 * thread must actively implement policy, checking 2164 * for offer expiration (which invalidates the cache). 2165 */ 2166 2167 for (oip = owner_ip; oip->s_addr != INADDR_ANY; oip++) { 2168 /* 2169 * Initialize query. 2170 */ 2171 DSVC_QINIT(query); 2172 DSVC_QEQ(query, DN_QCID|DN_QSIP); 2173 dn.dn_cid[0] = '\0'; 2174 dn.dn_cid_len = 1; 2175 dn.dn_sip.s_addr = ntohl(oip->s_addr); 2176 2177 /* 2178 * Decide whether a bootp record is required. 2179 */ 2180 dn.dn_flags = 0; 2181 DSVC_QEQ(query, DN_QFBOOTP_ONLY); 2182 if (is_bootp) 2183 dn.dn_flags = DN_FBOOTP_ONLY; 2184 2185 /* 2186 * These flags are used counter-intuitively. 2187 * This says that the setting of the bit 2188 * (off) in the dn.dn_flags matches the 2189 * setting in the record (off). 2190 */ 2191 DSVC_QEQ(query, DN_QFUNUSABLE|DN_QFMANUAL); 2192 2193 for (retry = 0; !found && retry < 3; retry++) { 2194 now = time(NULL); 2195 (void) mutex_lock(&pnd->thr_mtx); 2196 nrecords = pnd->nthreads < DHCP_MIN_RECORDS ? 2197 DHCP_MIN_RECORDS : pnd->nthreads; 2198 (void) mutex_unlock(&pnd->thr_mtx); 2199 2200 /* 2201 * Purge cached records when expired or database 2202 * re-read. 2203 */ 2204 2205 (void) mutex_lock(&pnd->free_mtx); 2206 dncp = pnd->freerec; 2207 if (dncp != NULL && 2208 PND_FREE_TIMEOUT(pnd, now)) { 2209 pnd->freerec = NULL; 2210 dhcp_free_dd_list(pnd->dh, dncp); 2211 dncp = NULL; 2212 } 2213 2214 if (dncp != NULL) { 2215 if (retry == 0) { 2216 /* Try the next cached record */ 2217 pnd->freerec = dncp->dnl_next; 2218 dncp->dnl_next = NULL; 2219 } else if (retry == 1) { 2220 /* 2221 * Try all remaining cached 2222 * records 2223 */ 2224 pnd->freerec = NULL; 2225 } 2226 } 2227 if (retry > 1) { 2228 /* Try all possible records in datastore. */ 2229 pnd->freerec = NULL; 2230 nrecords = -1; 2231 if (dncp != NULL) { 2232 dhcp_free_dd_list( 2233 pnd->dh, dncp); 2234 dncp = NULL; 2235 } 2236 } 2237 (void) mutex_unlock(&pnd->free_mtx); 2238 2239 io_done = (dncp == NULL); 2240 *dnlpp = dhcp_lookup_dd_classify(pcd->pnd, 2241 nrecords == -1 ? B_FALSE : B_TRUE, query, 2242 nrecords, &dn, (void **)&dncp, 2243 S_CID | S_FREE); 2244 if (*dnlpp != NULL) { 2245 dnp = (*dnlpp)->dnl_rec; 2246 tip.s_addr = htonl(dnp->dn_cip.s_addr); 2247 (void) update_offer(pcd, NULL, 0, 2248 &tip, B_TRUE); 2249 found = B_TRUE; 2250 } 2251 2252 (void) mutex_lock(&pnd->free_mtx); 2253 if (io_done) { 2254 /* 2255 * Note time when records were read. 2256 */ 2257 if (dncp != NULL) { 2258 now = time(NULL); 2259 pnd->free_mtime = reinit_time; 2260 pnd->free_stamp = now + 2261 cache_secs; 2262 } 2263 } 2264 2265 /* Save any leftover records for later use. */ 2266 if (dncp != NULL) { 2267 for (tlp = dncp; 2268 tlp != NULL && tlp->dnl_next; 2269 tlp = tlp->dnl_next) 2270 /* null statement */; 2271 tlp->dnl_next = pnd->freerec; 2272 pnd->freerec = dncp; 2273 } 2274 (void) mutex_unlock(&pnd->free_mtx); 2275 } 2276 } 2277 } 2278 2279 if (!found && !is_bootp) { 2280 /* 2281 * Struck out. No usable available addresses. Let's look for 2282 * the LRU expired address. Only makes sense for dhcp 2283 * clients. First we'll try the next record from 2284 * the lru list (this assumes lru database search capability). 2285 * Next we'll try all records. Finally we'll go get all 2286 * free records. 2287 * 2288 * Multi-threading: to improve performance, the following 2289 * algorithm coordinates accesses to the underlying table, 2290 * so only one thread is initiating lookups per network. 2291 * This is crucial, as lookup operations are expensive, 2292 * and not sufficiently malleable to allow partitioned 2293 * lookups (e.g. all that can be asked for are n free or 2294 * server-owned entries, multiple threads will retrieve 2295 * the same records). 2296 * 2297 * We only consider clients owned by us. 2298 * The outer loop runs through the server ips owned by us 2299 * 2300 * The three iterations through the inner loop attempt to use 2301 * 2302 * 1) the next cached entry 2303 * 2) all cached entries 2304 * 3) all free or per-server entries in the underlying table 2305 * 2306 * Since many threads are consuming the cached entries, 2307 * any thread may find itself in the role of having to 2308 * refresh the cache. We always read at least enough 2309 * entries to satisfy all current threads. Reading all 2310 * records is prohibitively expensive, and should only 2311 * be done as a last resort. 2312 * 2313 * As always, to better distribute garbage 2314 * collection and data structure aging tasks, each 2315 * thread must actively implement policy, checking 2316 * for offer expiration (which invalidates the cache). 2317 */ 2318 2319 for (oip = owner_ip; oip->s_addr != INADDR_ANY; oip++) { 2320 /* 2321 * Initialize query. 2322 */ 2323 DSVC_QINIT(query); 2324 DSVC_QEQ(query, DN_QSIP); 2325 dn.dn_sip.s_addr = ntohl(oip->s_addr); 2326 2327 /* 2328 * These flags are used counter-intuitively. 2329 * This says that the setting of the bit 2330 * (off) in the dn.dn_flags matches the 2331 * setting in the record (off). 2332 */ 2333 DSVC_QEQ(query, DN_QFBOOTP_ONLY| 2334 DN_QFMANUAL|DN_QFUNUSABLE); 2335 dn.dn_flags = 0; 2336 2337 for (retry = 0; !found && retry < 3; retry++) { 2338 now = time(NULL); 2339 (void) mutex_lock(&pnd->thr_mtx); 2340 nrecords = pnd->nthreads < DHCP_MIN_RECORDS ? 2341 DHCP_MIN_RECORDS : pnd->nthreads; 2342 (void) mutex_unlock(&pnd->thr_mtx); 2343 2344 /* 2345 * Purge cached records when expired or database 2346 * re-read. 2347 */ 2348 2349 (void) mutex_lock(&pnd->lru_mtx); 2350 dnsp = pnd->lrurec; 2351 if (dnsp != NULL && PND_LRU_TIMEOUT(pnd, now)) { 2352 pnd->lrurec = NULL; 2353 dhcp_free_dd_list(pnd->dh, dnsp); 2354 dnsp = NULL; 2355 } 2356 2357 if (dnsp != NULL) { 2358 if (retry == 0) { 2359 /* Try the next cached record */ 2360 pnd->lrurec = dnsp->dnl_next; 2361 dnsp->dnl_next = NULL; 2362 } else if (retry == 1) { 2363 /* 2364 * Try all remaining cached 2365 * records 2366 */ 2367 pnd->lrurec = NULL; 2368 } 2369 } 2370 if (retry > 1) { 2371 /* Try all possible records */ 2372 pnd->lrurec = NULL; 2373 nrecords = -1; 2374 if (dnsp != NULL) { 2375 dhcp_free_dd_list(pnd->dh, 2376 dnsp); 2377 dnsp = NULL; 2378 } 2379 } 2380 (void) mutex_unlock(&pnd->lru_mtx); 2381 2382 io_done = (dnsp == NULL); 2383 *dnlpp = dhcp_lookup_dd_classify(pcd->pnd, 2384 nrecords == -1 ? B_FALSE : B_TRUE, query, 2385 nrecords, &dn, (void **)&dnsp, S_LRU); 2386 if (*dnlpp != NULL) { 2387 dnp = (*dnlpp)->dnl_rec; 2388 tip.s_addr = htonl(dnp->dn_cip.s_addr); 2389 (void) update_offer(pcd, NULL, 0, &tip, 2390 B_TRUE); 2391 found = B_TRUE; 2392 } 2393 2394 (void) mutex_lock(&pnd->lru_mtx); 2395 if (io_done) { 2396 if (dnsp != NULL) { 2397 now = time(NULL); 2398 pnd->lru_mtime = reinit_time; 2399 pnd->lru_stamp = now + 2400 cache_secs; 2401 } 2402 } 2403 2404 /* 2405 * Save any leftover records for possible 2406 * later use 2407 */ 2408 if (dnsp != NULL) { 2409 for (tlp = dnsp; 2410 tlp != NULL && tlp->dnl_next; 2411 tlp = tlp->dnl_next) 2412 /* null statement */; 2413 tlp->dnl_next = pnd->lrurec; 2414 pnd->lrurec = dnsp; 2415 } 2416 (void) mutex_unlock(&pnd->lru_mtx); 2417 } 2418 } 2419 } 2420 2421 return (found); 2422 } 2423 2424 /* 2425 * purge_dnet_cache() - remove conflicting entries from the 2426 * free and lru dnet caches when records are modified. Expensive 2427 * but necessary. 2428 * 2429 * pnd - per net struct 2430 * dnp - pointer to cached/modified entry 2431 */ 2432 static void 2433 purge_dnet_cache(dsvc_dnet_t *pnd, dn_rec_t *dnp) 2434 { 2435 dn_rec_list_t *tlp; 2436 dn_rec_list_t *plp; 2437 2438 (void) mutex_lock(&pnd->free_mtx); 2439 2440 for (plp = tlp = pnd->freerec; tlp != NULL; tlp = tlp->dnl_next) { 2441 if (tlp->dnl_rec->dn_cip.s_addr == dnp->dn_cip.s_addr) { 2442 if (tlp == plp) { 2443 pnd->freerec = tlp->dnl_next; 2444 } else { 2445 plp->dnl_next = tlp->dnl_next; 2446 } 2447 tlp->dnl_next = NULL; 2448 break; 2449 } 2450 plp = tlp; 2451 } 2452 (void) mutex_unlock(&pnd->free_mtx); 2453 if (tlp != NULL) 2454 dhcp_free_dd_list(pnd->dh, tlp); 2455 2456 (void) mutex_lock(&pnd->lru_mtx); 2457 for (plp = tlp = pnd->lrurec; tlp != NULL; tlp = tlp->dnl_next) { 2458 if (tlp->dnl_rec->dn_cip.s_addr == dnp->dn_cip.s_addr) { 2459 if (tlp == plp) { 2460 pnd->lrurec = tlp->dnl_next; 2461 } else { 2462 plp->dnl_next = tlp->dnl_next; 2463 } 2464 tlp->dnl_next = NULL; 2465 break; 2466 } 2467 plp = tlp; 2468 } 2469 (void) mutex_unlock(&pnd->lru_mtx); 2470 if (tlp != NULL) 2471 dhcp_free_dd_list(pnd->dh, tlp); 2472 } 2473 2474 /* 2475 * add_dnet_cache() - add a free entry back to the free dnet cache. 2476 * 2477 * Performance: this can greatly reduce the amount of work select_offer() 2478 * must perform. 2479 * 2480 * pnd - per net struct 2481 * dnlp - pointer to cached/modified entry. 2482 */ 2483 static void 2484 add_dnet_cache(dsvc_dnet_t *pnd, dn_rec_list_t *dnlp) 2485 { 2486 (void) mutex_lock(&pnd->free_mtx); 2487 dnlp->dnl_next = pnd->freerec; 2488 pnd->freerec = dnlp; 2489 (void) mutex_unlock(&pnd->free_mtx); 2490 } 2491 2492 static char unowned_net[] = "the DHCP server believes the IP address that" 2493 " corresponds to the requested host name belongs to a network not" 2494 " managed by the DHCP server.\n"; 2495 static char unowned_addr[] = "the DHCP server believes the IP address that" 2496 " corresponds to the requested host name is not managed by the DHCP" 2497 " server.\n"; 2498 2499 /* 2500 * Determine whether the requested IP address is available to the requesting 2501 * client. To be so, its IP address must be managed by us, be on the ``right'' 2502 * network and neither currently leased nor currently under offer to another 2503 * client. 2504 */ 2505 static boolean_t 2506 addr_avail(dsvc_dnet_t *pnd, dsvc_clnt_t *pcd, dn_rec_list_t **dnlpp, 2507 struct in_addr req_ip, boolean_t isname) 2508 { 2509 dn_rec_t dn; 2510 dn_rec_list_t *dnip; 2511 uint32_t query; 2512 2513 *dnlpp = NULL; 2514 /* 2515 * first, check the ICMP list or offer list. 2516 */ 2517 if (isname) { 2518 if (pcd->off_ip.s_addr != req_ip.s_addr && 2519 check_offer(pnd, &req_ip) == B_FALSE) { 2520 /* Offered to someone else. Sorry. */ 2521 dhcpmsg(LOG_DEBUG, "name_avail(F):" 2522 " check_offer failed\n"); 2523 return (B_FALSE); 2524 } 2525 } else { 2526 if (update_offer(pcd, NULL, 0, &req_ip, B_TRUE) == B_FALSE) { 2527 /* Offered to someone else. Sorry. */ 2528 if (isname) { 2529 dhcpmsg(LOG_DEBUG, "name_avail(F):" 2530 " check_other_offers failed\n"); 2531 } 2532 return (B_FALSE); 2533 } 2534 } 2535 2536 /* 2537 * entry_available() searches for owner_ips 2538 * query on DN_QCIP will suffice here 2539 */ 2540 DSVC_QINIT(query); 2541 DSVC_QEQ(query, DN_QCIP); 2542 dn.dn_cip.s_addr = ntohl(req_ip.s_addr); 2543 2544 dnip = NULL; 2545 *dnlpp = dhcp_lookup_dd_classify(pnd, B_FALSE, query, -1, &dn, 2546 (void **)&dnip, 0); 2547 dhcp_free_dd_list(pnd->dh, dnip); 2548 if (*dnlpp != NULL) { 2549 /* 2550 * Ok, the requested IP exists. But is it available? 2551 */ 2552 if (!entry_available(pcd, (*dnlpp)->dnl_rec)) { 2553 dhcp_free_dd_list(pnd->dh, *dnlpp); 2554 *dnlpp = NULL; 2555 purge_offer(pcd, B_FALSE, B_TRUE); 2556 return (B_FALSE); 2557 } 2558 } else { 2559 if (isname) 2560 dhcpmsg(LOG_DEBUG, "name_avail(F): %s", unowned_addr); 2561 else 2562 purge_offer(pcd, B_FALSE, B_TRUE); 2563 return (B_FALSE); 2564 } 2565 return (B_TRUE); 2566 } 2567 2568 /* 2569 * Determine whether "name" is available. To be so, it must either not have 2570 * a corresponding IP address, or its IP address must be managed by us and 2571 * neither currently leased nor currently under offer to a client. 2572 * 2573 * To determine this, we first attempt to translate the name to an address. 2574 * If no name-to-address translation exists, it's automatically available. 2575 * Otherwise, we next check for any outstanding offers. Finally, we look 2576 * at the flags in the corresponding per-network table to see whether the 2577 * address is currently leased. 2578 * 2579 * Upon successful completion, we also return the vetted IP address as a 2580 * value result parameter. 2581 */ 2582 static boolean_t 2583 name_avail(char *name, dsvc_clnt_t *pcd, PKT_LIST *plp, dn_rec_list_t **dnlpp, 2584 ENCODE *ecp, struct in_addr **iap) 2585 { 2586 struct hostent h, *hp, *owner_hp; 2587 char hbuf[NSS_BUFLEN_HOSTS]; 2588 char fqname [NS_MAXDNAME+1]; 2589 char owner [NS_MAXDNAME+1]; 2590 int err, ho_len; 2591 struct in_addr ia, ma; 2592 dsvc_dnet_t *pnd; 2593 boolean_t isopen = B_FALSE; 2594 ENCODE *ep; 2595 2596 *dnlpp = NULL; 2597 /* 2598 * If possible, use a fully-qualified name to do the name-to- 2599 * address query. The complication is that the domain name 2600 * with which to qualify the client's host name resides in a 2601 * dhcptab macro unavailable at the time of the DHCPOFFER. 2602 * ecp will be non-NULL if we may have the means to fully-qualify 2603 * the name given. 2604 */ 2605 if (strchr(name, '.') != NULL) { 2606 (void) strlcpy(fqname, name, sizeof (fqname)); 2607 if (fqname[(strlen(fqname))-1] != '.') 2608 (void) strcat(fqname, "."); 2609 } else { 2610 /* 2611 * Append '.' domain-name '.' to hostname. 2612 * Note the use of the trailing '.' to avoid any surprises 2613 * because of the ndots value (see resolv.conf(4) for more 2614 * information about the latter). 2615 * 2616 * First see whether we can dredge up domain-name from the 2617 * ENCODE list. 2618 */ 2619 if ((ecp != NULL) && ((ep = find_encode(ecp, 2620 DSYM_STANDARD, CD_DNSDOMAIN)) != NULL)) { 2621 DHCP_OPT *ho = plp->opts[CD_HOSTNAME]; 2622 2623 /* 2624 * name_avail() should never be called unless the 2625 * CD_HOSTNAME option is present in the client's 2626 * packet. 2627 */ 2628 assert(ho != NULL); 2629 ho_len = ho->len; 2630 if (ho->value[ho_len - 1] == '\0') { 2631 /* null at end of the hostname */ 2632 ho_len = strlen((char *)ho->value); 2633 } 2634 2635 if (qualify_hostname(fqname, (char *)ho->value, 2636 (char *)ep->data, ho_len, ep->len) == -1) 2637 return (B_FALSE); 2638 2639 dhcpmsg(LOG_DEBUG, "name_avail: unqualified name\n" 2640 "found CD_DNSDOMAIN and qualified: %s\n", fqname); 2641 } else { 2642 /* 2643 * No DNS domain in the ENCODE list, have to use 2644 * local domain name. 2645 */ 2646 if ((resolv_conf.defdname == NULL) || 2647 (qualify_hostname(fqname, name, 2648 resolv_conf.defdname, 2649 strlen(name), 2650 strlen(resolv_conf.defdname)) == -1)) 2651 return (B_FALSE); 2652 2653 dhcpmsg(LOG_DEBUG, 2654 "name_avail: unqualified name\n" 2655 "qualified with local domain: %s\n", fqname); 2656 } 2657 } 2658 2659 /* 2660 * Try a forward lookup on the requested name. 2661 * Consider the name available if we get a definitive 2662 * ``name doesn't exist'' indication. 2663 */ 2664 hp = gethostbyname_r(fqname, &h, hbuf, sizeof (hbuf), &err); 2665 if (hp == NULL) 2666 if ((err == HOST_NOT_FOUND) || (err == NO_DATA)) { 2667 *iap = NULL; 2668 dhcpmsg(LOG_DEBUG, 2669 "name_avail(T): gethostbyname_r failed\n"); 2670 return (B_TRUE); 2671 } else { 2672 dhcpmsg(LOG_DEBUG, 2673 "name_avail(F): gethostbyname_r failed, err %d\n", 2674 err); 2675 return (B_FALSE); 2676 } 2677 2678 /* 2679 * Check that the address has not been leased to someone else. 2680 * Bear in mind that there may be inactive A records in the DNS 2681 * (since we don't delete them when a lease expires or is released). 2682 * Try a reverse lookup on the address returned in hp. 2683 * If the owner of this address is different to the requested name 2684 * we can infer that owner is a stale A record. 2685 */ 2686 2687 (void) memcpy(&ia, hp->h_addr, sizeof (struct in_addr)); 2688 owner_hp = gethostbyaddr_r((char *)&ia, sizeof (struct in_addr), 2689 AF_INET, &h, hbuf, sizeof (hbuf), &err); 2690 2691 if (owner_hp == NULL) { 2692 /* If there's no PTR record the address can't be in use */ 2693 if ((err == HOST_NOT_FOUND) || (err == NO_DATA)) { 2694 *iap = NULL; 2695 dhcpmsg(LOG_DEBUG, 2696 "name_avail(T): gethostbyaddr_r failed\n"); 2697 return (B_TRUE); 2698 } else { 2699 dhcpmsg(LOG_DEBUG, 2700 "name_avail(F): gethostbyaddr_r failed\n"); 2701 return (B_FALSE); 2702 } 2703 } 2704 2705 /* If name returned is not a FQDN, qualify with local domain name */ 2706 2707 if (strchr(owner_hp->h_name, '.') != NULL) { 2708 (void) strlcpy(owner, owner_hp->h_name, sizeof (owner)); 2709 if (owner[(strlen(owner))-1] != '.') 2710 (void) strcat(owner, "."); 2711 } else { 2712 if ((resolv_conf.defdname == NULL) || 2713 (qualify_hostname(owner, owner_hp->h_name, 2714 resolv_conf.defdname, 2715 strlen(owner_hp->h_name), 2716 strlen(resolv_conf.defdname)) == -1)) 2717 return (B_FALSE); 2718 2719 dhcpmsg(LOG_DEBUG, 2720 "name_avail: address owner qualified with %s\n", 2721 resolv_conf.defdname); 2722 } 2723 2724 if ((strncmp(owner, fqname, NS_MAXDNAME)) != 0) { 2725 /* Forward lookup found an inactive record - ignore it */ 2726 *iap = NULL; 2727 dhcpmsg(LOG_DEBUG, "name_avail(T): 'A' record inactive: %s\n", 2728 owner); 2729 return (B_TRUE); 2730 } 2731 2732 /* Get pnd of the current client */ 2733 pnd = pcd->pnd; 2734 get_netmask(&ia, &ma); 2735 if (pnd->net.s_addr != (ia.s_addr & ma.s_addr)) { 2736 /* get pnd of previous owner of the hostname */ 2737 if (open_dnet(&pnd, &ia, &ma) != DSVC_SUCCESS) { 2738 /* we must not manage the net containing this address */ 2739 dhcpmsg(LOG_DEBUG, "name_avail(F): %s", unowned_net); 2740 return (B_FALSE); 2741 } 2742 isopen = B_TRUE; 2743 } 2744 2745 /* 2746 * Test that the address has not been offered to someone else. 2747 */ 2748 if (!addr_avail(pnd, pcd, dnlpp, ia, B_TRUE)) { 2749 if (isopen) { 2750 close_dnet(pnd, B_FALSE); 2751 } 2752 return (B_FALSE); 2753 } 2754 if (isopen) 2755 close_dnet(pnd, B_FALSE); 2756 2757 /* LINTED */ 2758 **iap = *((struct in_addr *)hp->h_addr); 2759 dhcpmsg(LOG_DEBUG, "name_avail(T)\n"); 2760 return (B_TRUE); 2761 } 2762 2763 static boolean_t 2764 entry_available(dsvc_clnt_t *pcd, dn_rec_t *dnp) 2765 { 2766 char ntoab[INET_ADDRSTRLEN]; 2767 boolean_t isme = dnp->dn_cid_len == pcd->cid_len && 2768 memcmp(pcd->cid, dnp->dn_cid, pcd->cid_len) == 0; 2769 (void) inet_ntop(AF_INET, &(dnp->dn_sip), ntoab, sizeof (ntoab)); 2770 2771 if ((dnp->dn_flags & (DN_FMANUAL|DN_FUNUSABLE)) != 0) { 2772 dhcpmsg(LOG_DEBUG, "entry_available():" 2773 " %s is manually allocated or not usable\n", 2774 ntoab); 2775 return (B_FALSE); 2776 } 2777 2778 if (dnp->dn_cid_len != 0 && isme == B_FALSE && 2779 (dnp->dn_flags & (DN_FAUTOMATIC|DN_FBOOTP_ONLY))) { 2780 dhcpmsg(LOG_DEBUG, "entry_available():" 2781 " %s is a permanent address or reserved for BOOTP\n", 2782 ntoab); 2783 return (B_FALSE); 2784 } 2785 2786 if (dnp->dn_cid_len != 0 && isme == B_FALSE && 2787 (lease_t)time(NULL) < (lease_t)ntohl(dnp->dn_lease)) { 2788 dhcpmsg(LOG_DEBUG, "entry_available():" 2789 " lease on %s has not expired\n", 2790 ntoab); 2791 return (B_FALSE); 2792 } 2793 2794 if (match_ownerip(htonl(dnp->dn_sip.s_addr)) == NULL) { 2795 dhcpmsg(LOG_DEBUG, "entry_available():" 2796 " %s does not match owner_ip\n", 2797 ntoab); 2798 return (B_FALSE); 2799 } 2800 2801 /* Input IP is good. */ 2802 return (B_TRUE); 2803 } 2804 2805 static char msft_classid[] = "MSFT "; 2806 static char no_domain[] = "name service update on behalf of client with ID" 2807 " %s failed because requested name was not fully-qualified and no DNS" 2808 " domain name was specified for this client in the dhcptab\n"; 2809 2810 /* 2811 * Given a host name and IP address, try to do a host name update. 2812 */ 2813 static boolean_t 2814 do_nsupdate(struct in_addr ia, ENCODE *ecp, PKT_LIST *plp) 2815 { 2816 struct hostent *hp; 2817 DHCP_OPT *ho; 2818 ENCODE *ep; 2819 char class_idbuf[DSYM_CLASS_SIZE]; 2820 int puthostent_ret; 2821 2822 /* 2823 * hostent information is dynamically allocated so that threads spawned 2824 * by dns_puthostent() will have access to it after the calling thread 2825 * has returned. 2826 */ 2827 hp = (struct hostent *)smalloc(sizeof (struct hostent)); 2828 hp->h_addr_list = (char **)smalloc(2 * sizeof (char **)); 2829 hp->h_addr_list[1] = NULL; 2830 hp->h_addr = smalloc(sizeof (struct in_addr)); 2831 hp->h_aliases = NULL; 2832 hp->h_addrtype = AF_INET; 2833 hp->h_length = sizeof (struct in_addr); 2834 /* 2835 * Convert address to network order, as that's what hostent's are 2836 * expected to be. 2837 */ 2838 /* LINTED */ 2839 ((struct in_addr *)hp->h_addr)->s_addr = htonl(ia.s_addr); 2840 2841 /* 2842 * Is the host name unqualified? If so, try to qualify it. If that 2843 * can't be done, explain why the update won't be attempted. 2844 */ 2845 ho = plp->opts[CD_HOSTNAME]; 2846 if (memchr(ho->value, '.', ho->len) == NULL) { 2847 /* 2848 * See whether we can dredge up the DNS domain from the 2849 * ENCODE list. 2850 */ 2851 if ((ep = find_encode(ecp, DSYM_STANDARD, CD_DNSDOMAIN)) != 2852 NULL) { 2853 char *fqname; 2854 int ho_len = ho->len; 2855 2856 /* 2857 * We need room for 2858 * 2859 * hostname len + 2860 * strlen(".") + 2861 * domainname len + 2862 * strlen(".") + 2863 * trailing '\0' 2864 * 2865 * Note the use of the trailing '.' to avoid any 2866 * surprises because of the ndots value (see 2867 * resolv.conf(4) for more information about 2868 * the latter). 2869 */ 2870 if (ho->value[ho_len - 1] == '\0') { 2871 ho_len = strlen((char *)ho->value); 2872 } 2873 fqname = smalloc(ho_len + ep->len + 1 + 1 + 1); 2874 /* first copy host name, ... */ 2875 (void) memcpy(fqname, ho->value, ho_len); 2876 /* then '.', ... */ 2877 (void) memcpy(fqname + ho_len, ".", 1); 2878 /* ... then domain name, */ 2879 (void) memcpy(fqname + ho_len + 1, ep->data, ep->len); 2880 /* then a trailing '.', ... */ 2881 (void) memcpy(fqname + ho_len + ep->len + 1, ".", 1); 2882 /* no need to null-terminate - smalloc() did it */ 2883 2884 hp->h_name = fqname; 2885 dhcpmsg(LOG_DEBUG, "do_nsupdate: unqualified name\n" 2886 "found CD_DNSDOMAIN and qualified: %s\n", fqname); 2887 } else { 2888 char cidbuf[BUFSIZ]; 2889 2890 (void) disp_cid(plp, cidbuf, sizeof (cidbuf)); 2891 dhcpmsg(LOG_INFO, no_domain, cidbuf); 2892 } 2893 } else { 2894 hp->h_name = smalloc(ho->len + 1); 2895 (void) memcpy(hp->h_name, ho->value, ho->len); 2896 dhcpmsg(LOG_DEBUG, "do_nsupdate: fully qualified name: %s\n", 2897 hp->h_name); 2898 } 2899 2900 /* returns -1 or the number of name service updates done */ 2901 puthostent_ret = dns_puthostent(hp, nsutimeout_secs); 2902 dhcpmsg(LOG_DEBUG, "do_nsupdate: dns_puthostent returned %d\n", 2903 puthostent_ret); 2904 if (puthostent_ret == -1) { 2905 return (B_FALSE); 2906 } else if (puthostent_ret == 0) { 2907 /* 2908 * dns_puthostent() didn't see any errors occur, 2909 * but no updates were done; Microsoft clients 2910 * (i.e. clients with a Microsoft class ID) expect 2911 * it to succeed, so we lie to them. 2912 */ 2913 if (((get_class_id(plp, class_idbuf, 2914 sizeof (class_idbuf))) != NULL) && 2915 (strncmp(msft_classid, class_idbuf, 2916 sizeof (msft_classid)) == 0)) { 2917 dhcpmsg(LOG_DEBUG, "do_nsupdate: class ID \"%s\"\n", 2918 class_idbuf); 2919 return (B_TRUE); 2920 } else 2921 return (B_FALSE); 2922 } else { 2923 return (B_TRUE); 2924 } 2925 }