Annotation of embedaddon/dnsmasq/src/lease.c, revision 1.1
1.1 ! misho 1: /* dnsmasq is Copyright (c) 2000-2013 Simon Kelley
! 2:
! 3: This program is free software; you can redistribute it and/or modify
! 4: it under the terms of the GNU General Public License as published by
! 5: the Free Software Foundation; version 2 dated June, 1991, or
! 6: (at your option) version 3 dated 29 June, 2007.
! 7:
! 8: This program is distributed in the hope that it will be useful,
! 9: but WITHOUT ANY WARRANTY; without even the implied warranty of
! 10: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
! 11: GNU General Public License for more details.
! 12:
! 13: You should have received a copy of the GNU General Public License
! 14: along with this program. If not, see <http://www.gnu.org/licenses/>.
! 15: */
! 16:
! 17: #include "dnsmasq.h"
! 18:
! 19: #ifdef HAVE_DHCP
! 20:
! 21: static struct dhcp_lease *leases = NULL, *old_leases = NULL;
! 22: static int dns_dirty, file_dirty, leases_left;
! 23:
! 24: void lease_init(time_t now)
! 25: {
! 26: unsigned long ei;
! 27: struct all_addr addr;
! 28: struct dhcp_lease *lease;
! 29: int clid_len, hw_len, hw_type;
! 30: FILE *leasestream;
! 31:
! 32: leases_left = daemon->dhcp_max;
! 33:
! 34: if (option_bool(OPT_LEASE_RO))
! 35: {
! 36: /* run "<lease_change_script> init" once to get the
! 37: initial state of the database. If leasefile-ro is
! 38: set without a script, we just do without any
! 39: lease database. */
! 40: #ifdef HAVE_SCRIPT
! 41: if (daemon->lease_change_command)
! 42: {
! 43: strcpy(daemon->dhcp_buff, daemon->lease_change_command);
! 44: strcat(daemon->dhcp_buff, " init");
! 45: leasestream = popen(daemon->dhcp_buff, "r");
! 46: }
! 47: else
! 48: #endif
! 49: {
! 50: file_dirty = dns_dirty = 0;
! 51: return;
! 52: }
! 53:
! 54: }
! 55: else
! 56: {
! 57: /* NOTE: need a+ mode to create file if it doesn't exist */
! 58: leasestream = daemon->lease_stream = fopen(daemon->lease_file, "a+");
! 59:
! 60: if (!leasestream)
! 61: die(_("cannot open or create lease file %s: %s"), daemon->lease_file, EC_FILE);
! 62:
! 63: /* a+ mode leaves pointer at end. */
! 64: rewind(leasestream);
! 65: }
! 66:
! 67: /* client-id max length is 255 which is 255*2 digits + 254 colons
! 68: borrow DNS packet buffer which is always larger than 1000 bytes */
! 69: if (leasestream)
! 70: while (fscanf(leasestream, "%255s %255s", daemon->dhcp_buff3, daemon->dhcp_buff2) == 2)
! 71: {
! 72: #ifdef HAVE_DHCP6
! 73: if (strcmp(daemon->dhcp_buff3, "duid") == 0)
! 74: {
! 75: daemon->duid_len = parse_hex(daemon->dhcp_buff2, (unsigned char *)daemon->dhcp_buff2, 130, NULL, NULL);
! 76: daemon->duid = safe_malloc(daemon->duid_len);
! 77: memcpy(daemon->duid, daemon->dhcp_buff2, daemon->duid_len);
! 78: continue;
! 79: }
! 80: #endif
! 81:
! 82: ei = atol(daemon->dhcp_buff3);
! 83:
! 84: if (fscanf(leasestream, " %64s %255s %764s",
! 85: daemon->namebuff, daemon->dhcp_buff, daemon->packet) != 3)
! 86: break;
! 87:
! 88: clid_len = 0;
! 89: if (strcmp(daemon->packet, "*") != 0)
! 90: clid_len = parse_hex(daemon->packet, (unsigned char *)daemon->packet, 255, NULL, NULL);
! 91:
! 92: if (inet_pton(AF_INET, daemon->namebuff, &addr.addr.addr4) &&
! 93: (lease = lease4_allocate(addr.addr.addr4)))
! 94: {
! 95: hw_len = parse_hex(daemon->dhcp_buff2, (unsigned char *)daemon->dhcp_buff2, DHCP_CHADDR_MAX, NULL, &hw_type);
! 96: /* For backwards compatibility, no explict MAC address type means ether. */
! 97: if (hw_type == 0 && hw_len != 0)
! 98: hw_type = ARPHRD_ETHER;
! 99:
! 100: lease_set_hwaddr(lease, (unsigned char *)daemon->dhcp_buff2, (unsigned char *)daemon->packet,
! 101: hw_len, hw_type, clid_len, now, 0);
! 102:
! 103: if (strcmp(daemon->dhcp_buff, "*") != 0)
! 104: lease_set_hostname(lease, daemon->dhcp_buff, 0, get_domain(lease->addr), NULL);
! 105: }
! 106: #ifdef HAVE_DHCP6
! 107: else if (inet_pton(AF_INET6, daemon->namebuff, &addr.addr.addr6))
! 108: {
! 109: char *s = daemon->dhcp_buff2;
! 110: int lease_type = LEASE_NA;
! 111:
! 112: if (s[0] == 'T')
! 113: {
! 114: lease_type = LEASE_TA;
! 115: s++;
! 116: }
! 117:
! 118: hw_type = strtoul(s, NULL, 10);
! 119:
! 120: if ((lease = lease6_allocate(&addr.addr.addr6, lease_type)))
! 121: {
! 122: lease_set_hwaddr(lease, NULL, (unsigned char *)daemon->packet, 0, hw_type, clid_len, now, 0);
! 123:
! 124: if (strcmp(daemon->dhcp_buff, "*") != 0)
! 125: lease_set_hostname(lease, daemon->dhcp_buff, 0, get_domain6((struct in6_addr *)lease->hwaddr), NULL);
! 126: }
! 127: }
! 128: #endif
! 129: else
! 130: break;
! 131:
! 132: if (!lease)
! 133: die (_("too many stored leases"), NULL, EC_MISC);
! 134:
! 135: #ifdef HAVE_BROKEN_RTC
! 136: if (ei != 0)
! 137: lease->expires = (time_t)ei + now;
! 138: else
! 139: lease->expires = (time_t)0;
! 140: lease->length = ei;
! 141: #else
! 142: /* strictly time_t is opaque, but this hack should work on all sane systems,
! 143: even when sizeof(time_t) == 8 */
! 144: lease->expires = (time_t)ei;
! 145: #endif
! 146:
! 147: /* set these correctly: the "old" events are generated later from
! 148: the startup synthesised SIGHUP. */
! 149: lease->flags &= ~(LEASE_NEW | LEASE_CHANGED);
! 150: }
! 151:
! 152: #ifdef HAVE_SCRIPT
! 153: if (!daemon->lease_stream)
! 154: {
! 155: int rc = 0;
! 156:
! 157: /* shell returns 127 for "command not found", 126 for bad permissions. */
! 158: if (!leasestream || (rc = pclose(leasestream)) == -1 || WEXITSTATUS(rc) == 127 || WEXITSTATUS(rc) == 126)
! 159: {
! 160: if (WEXITSTATUS(rc) == 127)
! 161: errno = ENOENT;
! 162: else if (WEXITSTATUS(rc) == 126)
! 163: errno = EACCES;
! 164: die(_("cannot run lease-init script %s: %s"), daemon->lease_change_command, EC_FILE);
! 165: }
! 166:
! 167: if (WEXITSTATUS(rc) != 0)
! 168: {
! 169: sprintf(daemon->dhcp_buff, "%d", WEXITSTATUS(rc));
! 170: die(_("lease-init script returned exit code %s"), daemon->dhcp_buff, WEXITSTATUS(rc) + EC_INIT_OFFSET);
! 171: }
! 172: }
! 173: #endif
! 174:
! 175: /* Some leases may have expired */
! 176: file_dirty = 0;
! 177: lease_prune(NULL, now);
! 178: dns_dirty = 1;
! 179: }
! 180:
! 181: void lease_update_from_configs(void)
! 182: {
! 183: /* changes to the config may change current leases. */
! 184:
! 185: struct dhcp_lease *lease;
! 186: struct dhcp_config *config;
! 187: char *name;
! 188:
! 189: for (lease = leases; lease; lease = lease->next)
! 190: if ((config = find_config(daemon->dhcp_conf, NULL, lease->clid, lease->clid_len,
! 191: lease->hwaddr, lease->hwaddr_len, lease->hwaddr_type, NULL)) &&
! 192: (config->flags & CONFIG_NAME) &&
! 193: (!(config->flags & CONFIG_ADDR) || config->addr.s_addr == lease->addr.s_addr))
! 194: lease_set_hostname(lease, config->hostname, 1, get_domain(lease->addr), NULL);
! 195: else if ((name = host_from_dns(lease->addr)))
! 196: lease_set_hostname(lease, name, 1, get_domain(lease->addr), NULL); /* updates auth flag only */
! 197: }
! 198:
! 199: static void ourprintf(int *errp, char *format, ...)
! 200: {
! 201: va_list ap;
! 202:
! 203: va_start(ap, format);
! 204: if (!(*errp) && vfprintf(daemon->lease_stream, format, ap) < 0)
! 205: *errp = errno;
! 206: va_end(ap);
! 207: }
! 208:
! 209: void lease_update_file(time_t now)
! 210: {
! 211: struct dhcp_lease *lease;
! 212: time_t next_event;
! 213: int i, err = 0;
! 214:
! 215: if (file_dirty != 0 && daemon->lease_stream)
! 216: {
! 217: errno = 0;
! 218: rewind(daemon->lease_stream);
! 219: if (errno != 0 || ftruncate(fileno(daemon->lease_stream), 0) != 0)
! 220: err = errno;
! 221:
! 222: for (lease = leases; lease; lease = lease->next)
! 223: {
! 224:
! 225: #ifdef HAVE_DHCP6
! 226: if (lease->flags & (LEASE_TA | LEASE_NA))
! 227: continue;
! 228: #endif
! 229:
! 230: #ifdef HAVE_BROKEN_RTC
! 231: ourprintf(&err, "%u ", lease->length);
! 232: #else
! 233: ourprintf(&err, "%lu ", (unsigned long)lease->expires);
! 234: #endif
! 235:
! 236: if (lease->hwaddr_type != ARPHRD_ETHER || lease->hwaddr_len == 0)
! 237: ourprintf(&err, "%.2x-", lease->hwaddr_type);
! 238: for (i = 0; i < lease->hwaddr_len; i++)
! 239: {
! 240: ourprintf(&err, "%.2x", lease->hwaddr[i]);
! 241: if (i != lease->hwaddr_len - 1)
! 242: ourprintf(&err, ":");
! 243: }
! 244:
! 245: inet_ntop(AF_INET, &lease->addr, daemon->addrbuff, ADDRSTRLEN);
! 246:
! 247: ourprintf(&err, " %s ", daemon->addrbuff);
! 248: ourprintf(&err, "%s ", lease->hostname ? lease->hostname : "*");
! 249:
! 250: if (lease->clid && lease->clid_len != 0)
! 251: {
! 252: for (i = 0; i < lease->clid_len - 1; i++)
! 253: ourprintf(&err, "%.2x:", lease->clid[i]);
! 254: ourprintf(&err, "%.2x\n", lease->clid[i]);
! 255: }
! 256: else
! 257: ourprintf(&err, "*\n");
! 258: }
! 259:
! 260: #ifdef HAVE_DHCP6
! 261: if (daemon->duid)
! 262: {
! 263: ourprintf(&err, "duid ");
! 264: for (i = 0; i < daemon->duid_len - 1; i++)
! 265: ourprintf(&err, "%.2x:", daemon->duid[i]);
! 266: ourprintf(&err, "%.2x\n", daemon->duid[i]);
! 267:
! 268: for (lease = leases; lease; lease = lease->next)
! 269: {
! 270:
! 271: if (!(lease->flags & (LEASE_TA | LEASE_NA)))
! 272: continue;
! 273:
! 274: #ifdef HAVE_BROKEN_RTC
! 275: ourprintf(&err, "%u ", lease->length);
! 276: #else
! 277: ourprintf(&err, "%lu ", (unsigned long)lease->expires);
! 278: #endif
! 279:
! 280: inet_ntop(AF_INET6, lease->hwaddr, daemon->addrbuff, ADDRSTRLEN);
! 281:
! 282: ourprintf(&err, "%s%u %s ", (lease->flags & LEASE_TA) ? "T" : "",
! 283: lease->hwaddr_type, daemon->addrbuff);
! 284: ourprintf(&err, "%s ", lease->hostname ? lease->hostname : "*");
! 285:
! 286: if (lease->clid && lease->clid_len != 0)
! 287: {
! 288: for (i = 0; i < lease->clid_len - 1; i++)
! 289: ourprintf(&err, "%.2x:", lease->clid[i]);
! 290: ourprintf(&err, "%.2x\n", lease->clid[i]);
! 291: }
! 292: else
! 293: ourprintf(&err, "*\n");
! 294: }
! 295: }
! 296: #endif
! 297:
! 298: if (fflush(daemon->lease_stream) != 0 ||
! 299: fsync(fileno(daemon->lease_stream)) < 0)
! 300: err = errno;
! 301:
! 302: if (!err)
! 303: file_dirty = 0;
! 304: }
! 305:
! 306: /* Set alarm for when the first lease expires + slop. */
! 307: next_event = 0;
! 308:
! 309: #ifdef HAVE_DHCP6
! 310: /* do timed RAs and determine when the next is, also pings to potential SLAAC addresses */
! 311: if (daemon->doing_ra)
! 312: {
! 313: time_t event;
! 314:
! 315: if ((event = periodic_slaac(now, leases)) != 0)
! 316: {
! 317: if (next_event == 0 || difftime(next_event, event) > 0.0)
! 318: next_event = event;
! 319: }
! 320:
! 321: if ((event = periodic_ra(now)) != 0)
! 322: {
! 323: if (next_event == 0 || difftime(next_event, event) > 0.0)
! 324: next_event = event;
! 325: }
! 326: }
! 327: #endif
! 328:
! 329: for (lease = leases; lease; lease = lease->next)
! 330: if (lease->expires != 0 &&
! 331: (next_event == 0 || difftime(next_event, lease->expires + 10) > 0.0))
! 332: next_event = lease->expires + 10;
! 333:
! 334: if (err)
! 335: {
! 336: if (next_event == 0 || difftime(next_event, LEASE_RETRY + now) > 0.0)
! 337: next_event = LEASE_RETRY + now;
! 338:
! 339: my_syslog(MS_DHCP | LOG_ERR, _("failed to write %s: %s (retry in %us)"),
! 340: daemon->lease_file, strerror(err),
! 341: (unsigned int)difftime(next_event, now));
! 342: }
! 343:
! 344: send_alarm(next_event, now);
! 345: }
! 346:
! 347:
! 348: static int find_interface_v4(struct in_addr local, int if_index,
! 349: struct in_addr netmask, struct in_addr broadcast, void *vparam)
! 350: {
! 351: struct dhcp_lease *lease;
! 352:
! 353: (void) broadcast;
! 354: (void) vparam;
! 355:
! 356: for (lease = leases; lease; lease = lease->next)
! 357: if (!(lease->flags & (LEASE_TA | LEASE_NA)))
! 358: if (is_same_net(local, lease->addr, netmask))
! 359: lease_set_interface(lease, if_index, *((time_t *)vparam));
! 360:
! 361: return 1;
! 362: }
! 363:
! 364: #ifdef HAVE_DHCP6
! 365: static int find_interface_v6(struct in6_addr *local, int prefix,
! 366: int scope, int if_index, int flags,
! 367: int preferred, int valid, void *vparam)
! 368: {
! 369: struct dhcp_lease *lease;
! 370:
! 371: (void)scope;
! 372: (void)flags;
! 373: (void)preferred;
! 374: (void)valid;
! 375:
! 376: for (lease = leases; lease; lease = lease->next)
! 377: if ((lease->flags & (LEASE_TA | LEASE_NA)))
! 378: if (is_same_net6(local, (struct in6_addr *)&lease->hwaddr, prefix))
! 379: lease_set_interface(lease, if_index, *((time_t *)vparam));
! 380:
! 381: return 1;
! 382: }
! 383:
! 384: void lease_ping_reply(struct in6_addr *sender, unsigned char *packet, char *interface)
! 385: {
! 386: /* We may be doing RA but not DHCPv4, in which case the lease
! 387: database may not exist and we have nothing to do anyway */
! 388: if (daemon->dhcp)
! 389: slaac_ping_reply(sender, packet, interface, leases);
! 390: }
! 391:
! 392: void lease_update_slaac(time_t now)
! 393: {
! 394: /* Called when we contruct a new RA-names context, to add putative
! 395: new SLAAC addresses to existing leases. */
! 396:
! 397: struct dhcp_lease *lease;
! 398:
! 399: if (daemon->dhcp)
! 400: for (lease = leases; lease; lease = lease->next)
! 401: slaac_add_addrs(lease, now, 0);
! 402: }
! 403:
! 404: #endif
! 405:
! 406:
! 407: /* Find interfaces associated with leases at start-up. This gets updated as
! 408: we do DHCP transactions, but information about directly-connected subnets
! 409: is useful from scrips and necessary for determining SLAAC addresses from
! 410: start-time. */
! 411: void lease_find_interfaces(time_t now)
! 412: {
! 413: iface_enumerate(AF_INET, &now, find_interface_v4);
! 414: #ifdef HAVE_DHCP6
! 415: iface_enumerate(AF_INET6, &now, find_interface_v6);
! 416:
! 417: /* If we're not doing DHCPv6, and there are not v6 leases, don't add the DUID to the database */
! 418: if (!daemon->duid && daemon->dhcp6)
! 419: {
! 420: file_dirty = 1;
! 421: make_duid(now);
! 422: }
! 423: #endif
! 424: }
! 425:
! 426:
! 427:
! 428: void lease_update_dns(int force)
! 429: {
! 430: struct dhcp_lease *lease;
! 431:
! 432: if (daemon->port != 0 && (dns_dirty || force))
! 433: {
! 434: #ifndef HAVE_BROKEN_RTC
! 435: /* force transfer to authoritative secondaries */
! 436: daemon->soa_sn++;
! 437: #endif
! 438:
! 439: cache_unhash_dhcp();
! 440:
! 441: for (lease = leases; lease; lease = lease->next)
! 442: {
! 443: int prot = AF_INET;
! 444:
! 445: #ifdef HAVE_DHCP6
! 446: if (lease->flags & (LEASE_TA | LEASE_NA))
! 447: prot = AF_INET6;
! 448: else if (lease->hostname || lease->fqdn)
! 449: {
! 450: struct slaac_address *slaac;
! 451:
! 452: for (slaac = lease->slaac_address; slaac; slaac = slaac->next)
! 453: if (slaac->backoff == 0)
! 454: {
! 455: if (lease->fqdn)
! 456: cache_add_dhcp_entry(lease->fqdn, AF_INET6, (struct all_addr *)&slaac->addr, lease->expires);
! 457: if (!option_bool(OPT_DHCP_FQDN) && lease->hostname)
! 458: cache_add_dhcp_entry(lease->hostname, AF_INET6, (struct all_addr *)&slaac->addr, lease->expires);
! 459: }
! 460: }
! 461: #endif
! 462:
! 463: if (lease->fqdn)
! 464: cache_add_dhcp_entry(lease->fqdn, prot,
! 465: prot == AF_INET ? (struct all_addr *)&lease->addr : (struct all_addr *)&lease->hwaddr,
! 466: lease->expires);
! 467:
! 468: if (!option_bool(OPT_DHCP_FQDN) && lease->hostname)
! 469: cache_add_dhcp_entry(lease->hostname, prot,
! 470: prot == AF_INET ? (struct all_addr *)&lease->addr : (struct all_addr *)&lease->hwaddr,
! 471: lease->expires);
! 472: }
! 473:
! 474: dns_dirty = 0;
! 475: }
! 476: }
! 477:
! 478: void lease_prune(struct dhcp_lease *target, time_t now)
! 479: {
! 480: struct dhcp_lease *lease, *tmp, **up;
! 481:
! 482: for (lease = leases, up = &leases; lease; lease = tmp)
! 483: {
! 484: tmp = lease->next;
! 485: if ((lease->expires != 0 && difftime(now, lease->expires) > 0) || lease == target)
! 486: {
! 487: file_dirty = 1;
! 488: if (lease->hostname)
! 489: dns_dirty = 1;
! 490:
! 491: *up = lease->next; /* unlink */
! 492:
! 493: /* Put on old_leases list 'till we
! 494: can run the script */
! 495: lease->next = old_leases;
! 496: old_leases = lease;
! 497:
! 498: leases_left++;
! 499: }
! 500: else
! 501: up = &lease->next;
! 502: }
! 503: }
! 504:
! 505:
! 506: struct dhcp_lease *lease_find_by_client(unsigned char *hwaddr, int hw_len, int hw_type,
! 507: unsigned char *clid, int clid_len)
! 508: {
! 509: struct dhcp_lease *lease;
! 510:
! 511: if (clid)
! 512: for (lease = leases; lease; lease = lease->next)
! 513: {
! 514: #ifdef HAVE_DHCP6
! 515: if (lease->flags & (LEASE_TA | LEASE_NA))
! 516: continue;
! 517: #endif
! 518: if (lease->clid && clid_len == lease->clid_len &&
! 519: memcmp(clid, lease->clid, clid_len) == 0)
! 520: return lease;
! 521: }
! 522:
! 523: for (lease = leases; lease; lease = lease->next)
! 524: {
! 525: #ifdef HAVE_DHCP6
! 526: if (lease->flags & (LEASE_TA | LEASE_NA))
! 527: continue;
! 528: #endif
! 529: if ((!lease->clid || !clid) &&
! 530: hw_len != 0 &&
! 531: lease->hwaddr_len == hw_len &&
! 532: lease->hwaddr_type == hw_type &&
! 533: memcmp(hwaddr, lease->hwaddr, hw_len) == 0)
! 534: return lease;
! 535: }
! 536:
! 537: return NULL;
! 538: }
! 539:
! 540: struct dhcp_lease *lease_find_by_addr(struct in_addr addr)
! 541: {
! 542: struct dhcp_lease *lease;
! 543:
! 544: for (lease = leases; lease; lease = lease->next)
! 545: {
! 546: #ifdef HAVE_DHCP6
! 547: if (lease->flags & (LEASE_TA | LEASE_NA))
! 548: continue;
! 549: #endif
! 550: if (lease->addr.s_addr == addr.s_addr)
! 551: return lease;
! 552: }
! 553:
! 554: return NULL;
! 555: }
! 556:
! 557: #ifdef HAVE_DHCP6
! 558: /* find address for {CLID, IAID, address} */
! 559: struct dhcp_lease *lease6_find(unsigned char *clid, int clid_len,
! 560: int lease_type, int iaid, struct in6_addr *addr)
! 561: {
! 562: struct dhcp_lease *lease;
! 563:
! 564: for (lease = leases; lease; lease = lease->next)
! 565: {
! 566: if (!(lease->flags & lease_type) || lease->hwaddr_type != iaid)
! 567: continue;
! 568:
! 569: if (memcmp(lease->hwaddr, addr, IN6ADDRSZ) != 0)
! 570: continue;
! 571:
! 572: if ((clid_len != lease->clid_len ||
! 573: memcmp(clid, lease->clid, clid_len) != 0))
! 574: continue;
! 575:
! 576: return lease;
! 577: }
! 578:
! 579: return NULL;
! 580: }
! 581:
! 582: /* reset "USED flags */
! 583: void lease6_reset(void)
! 584: {
! 585: struct dhcp_lease *lease;
! 586:
! 587: for (lease = leases; lease; lease = lease->next)
! 588: lease->flags &= ~LEASE_USED;
! 589: }
! 590:
! 591: /* enumerate all leases belonging to {CLID, IAID} */
! 592: struct dhcp_lease *lease6_find_by_client(struct dhcp_lease *first, int lease_type, unsigned char *clid, int clid_len, int iaid)
! 593: {
! 594: struct dhcp_lease *lease;
! 595:
! 596: if (!first)
! 597: first = leases;
! 598: else
! 599: first = first->next;
! 600:
! 601: for (lease = first; lease; lease = lease->next)
! 602: {
! 603: if (lease->flags & LEASE_USED)
! 604: continue;
! 605:
! 606: if (!(lease->flags & lease_type) || lease->hwaddr_type != iaid)
! 607: continue;
! 608:
! 609: if ((clid_len != lease->clid_len ||
! 610: memcmp(clid, lease->clid, clid_len) != 0))
! 611: continue;
! 612:
! 613: return lease;
! 614: }
! 615:
! 616: return NULL;
! 617: }
! 618:
! 619: struct dhcp_lease *lease6_find_by_addr(struct in6_addr *net, int prefix, u64 addr)
! 620: {
! 621: struct dhcp_lease *lease;
! 622:
! 623: for (lease = leases; lease; lease = lease->next)
! 624: {
! 625: if (!(lease->flags & (LEASE_TA | LEASE_NA)))
! 626: continue;
! 627:
! 628: if (is_same_net6((struct in6_addr *)lease->hwaddr, net, prefix) &&
! 629: (prefix == 128 || addr6part((struct in6_addr *)lease->hwaddr) == addr))
! 630: return lease;
! 631: }
! 632:
! 633: return NULL;
! 634: }
! 635:
! 636: /* Find largest assigned address in context */
! 637: u64 lease_find_max_addr6(struct dhcp_context *context)
! 638: {
! 639: struct dhcp_lease *lease;
! 640: u64 addr = addr6part(&context->start6);
! 641:
! 642: if (!(context->flags & (CONTEXT_STATIC | CONTEXT_PROXY)))
! 643: for (lease = leases; lease; lease = lease->next)
! 644: {
! 645: if (!(lease->flags & (LEASE_TA | LEASE_NA)))
! 646: continue;
! 647:
! 648: if (is_same_net6((struct in6_addr *)lease->hwaddr, &context->start6, 64) &&
! 649: addr6part((struct in6_addr *)lease->hwaddr) > addr6part(&context->start6) &&
! 650: addr6part((struct in6_addr *)lease->hwaddr) <= addr6part(&context->end6) &&
! 651: addr6part((struct in6_addr *)lease->hwaddr) > addr)
! 652: addr = addr6part((struct in6_addr *)lease->hwaddr);
! 653: }
! 654:
! 655: return addr;
! 656: }
! 657:
! 658: #endif
! 659:
! 660: /* Find largest assigned address in context */
! 661: struct in_addr lease_find_max_addr(struct dhcp_context *context)
! 662: {
! 663: struct dhcp_lease *lease;
! 664: struct in_addr addr = context->start;
! 665:
! 666: if (!(context->flags & (CONTEXT_STATIC | CONTEXT_PROXY)))
! 667: for (lease = leases; lease; lease = lease->next)
! 668: {
! 669: #ifdef HAVE_DHCP6
! 670: if (lease->flags & (LEASE_TA | LEASE_NA))
! 671: continue;
! 672: #endif
! 673: if (((unsigned)ntohl(lease->addr.s_addr)) > ((unsigned)ntohl(context->start.s_addr)) &&
! 674: ((unsigned)ntohl(lease->addr.s_addr)) <= ((unsigned)ntohl(context->end.s_addr)) &&
! 675: ((unsigned)ntohl(lease->addr.s_addr)) > ((unsigned)ntohl(addr.s_addr)))
! 676: addr = lease->addr;
! 677: }
! 678:
! 679: return addr;
! 680: }
! 681:
! 682: static struct dhcp_lease *lease_allocate(void)
! 683: {
! 684: struct dhcp_lease *lease;
! 685: if (!leases_left || !(lease = whine_malloc(sizeof(struct dhcp_lease))))
! 686: return NULL;
! 687:
! 688: memset(lease, 0, sizeof(struct dhcp_lease));
! 689: lease->flags = LEASE_NEW;
! 690: lease->expires = 1;
! 691: #ifdef HAVE_BROKEN_RTC
! 692: lease->length = 0xffffffff; /* illegal value */
! 693: #endif
! 694: lease->next = leases;
! 695: leases = lease;
! 696:
! 697: file_dirty = 1;
! 698: leases_left--;
! 699:
! 700: return lease;
! 701: }
! 702:
! 703: struct dhcp_lease *lease4_allocate(struct in_addr addr)
! 704: {
! 705: struct dhcp_lease *lease = lease_allocate();
! 706: if (lease)
! 707: {
! 708: lease->addr = addr;
! 709: lease->hwaddr_len = 256; /* illegal value */
! 710: }
! 711:
! 712: return lease;
! 713: }
! 714:
! 715: #ifdef HAVE_DHCP6
! 716: struct dhcp_lease *lease6_allocate(struct in6_addr *addrp, int lease_type)
! 717: {
! 718: struct dhcp_lease *lease = lease_allocate();
! 719:
! 720: if (lease)
! 721: {
! 722: memcpy(lease->hwaddr, addrp, sizeof(*addrp)) ;
! 723: lease->flags |= lease_type;
! 724: }
! 725:
! 726: return lease;
! 727: }
! 728: #endif
! 729:
! 730: void lease_set_expires(struct dhcp_lease *lease, unsigned int len, time_t now)
! 731: {
! 732: time_t exp = now + (time_t)len;
! 733:
! 734: if (len == 0xffffffff)
! 735: {
! 736: exp = 0;
! 737: len = 0;
! 738: }
! 739:
! 740: if (exp != lease->expires)
! 741: {
! 742: dns_dirty = 1;
! 743: lease->expires = exp;
! 744: #ifndef HAVE_BROKEN_RTC
! 745: lease->flags |= LEASE_AUX_CHANGED;
! 746: file_dirty = 1;
! 747: #endif
! 748: }
! 749:
! 750: #ifdef HAVE_BROKEN_RTC
! 751: if (len != lease->length)
! 752: {
! 753: lease->length = len;
! 754: lease->flags |= LEASE_AUX_CHANGED;
! 755: file_dirty = 1;
! 756: }
! 757: #endif
! 758: }
! 759:
! 760: void lease_set_hwaddr(struct dhcp_lease *lease, unsigned char *hwaddr,
! 761: unsigned char *clid, int hw_len, int hw_type, int clid_len,
! 762: time_t now, int force)
! 763: {
! 764: #ifdef HAVE_DHCP6
! 765: int change = force;
! 766: lease->flags |= LEASE_HAVE_HWADDR;
! 767: #endif
! 768:
! 769: (void)force;
! 770:
! 771: if (hw_len != lease->hwaddr_len ||
! 772: hw_type != lease->hwaddr_type ||
! 773: (hw_len != 0 && memcmp(lease->hwaddr, hwaddr, hw_len) != 0))
! 774: {
! 775: if (hw_len != 0)
! 776: memcpy(lease->hwaddr, hwaddr, hw_len);
! 777: lease->hwaddr_len = hw_len;
! 778: lease->hwaddr_type = hw_type;
! 779: lease->flags |= LEASE_CHANGED;
! 780: file_dirty = 1; /* run script on change */
! 781: #ifdef HAVE_DHCP6
! 782: change = 1;
! 783: #endif
! 784: }
! 785:
! 786: /* only update clid when one is available, stops packets
! 787: without a clid removing the record. Lease init uses
! 788: clid_len == 0 for no clid. */
! 789: if (clid_len != 0 && clid)
! 790: {
! 791: if (!lease->clid)
! 792: lease->clid_len = 0;
! 793:
! 794: if (lease->clid_len != clid_len)
! 795: {
! 796: lease->flags |= LEASE_AUX_CHANGED;
! 797: file_dirty = 1;
! 798: free(lease->clid);
! 799: if (!(lease->clid = whine_malloc(clid_len)))
! 800: return;
! 801: #ifdef HAVE_DHCP6
! 802: change = 1;
! 803: #endif
! 804: }
! 805: else if (memcmp(lease->clid, clid, clid_len) != 0)
! 806: {
! 807: lease->flags |= LEASE_AUX_CHANGED;
! 808: file_dirty = 1;
! 809: #ifdef HAVE_DHCP6
! 810: change = 1;
! 811: #endif
! 812: }
! 813:
! 814: lease->clid_len = clid_len;
! 815: memcpy(lease->clid, clid, clid_len);
! 816: }
! 817:
! 818: #ifdef HAVE_DHCP6
! 819: if (change)
! 820: slaac_add_addrs(lease, now, force);
! 821: #endif
! 822: }
! 823:
! 824: static void kill_name(struct dhcp_lease *lease)
! 825: {
! 826: /* run script to say we lost our old name */
! 827:
! 828: /* this shouldn't happen unless updates are very quick and the
! 829: script very slow, we just avoid a memory leak if it does. */
! 830: free(lease->old_hostname);
! 831:
! 832: /* If we know the fqdn, pass that. The helper will derive the
! 833: unqualified name from it, free the unqualified name here. */
! 834:
! 835: if (lease->fqdn)
! 836: {
! 837: lease->old_hostname = lease->fqdn;
! 838: free(lease->hostname);
! 839: }
! 840: else
! 841: lease->old_hostname = lease->hostname;
! 842:
! 843: lease->hostname = lease->fqdn = NULL;
! 844: }
! 845:
! 846: void lease_set_hostname(struct dhcp_lease *lease, char *name, int auth, char *domain, char *config_domain)
! 847: {
! 848: struct dhcp_lease *lease_tmp;
! 849: char *new_name = NULL, *new_fqdn = NULL;
! 850:
! 851: if (config_domain && (!domain || !hostname_isequal(domain, config_domain)))
! 852: my_syslog(MS_DHCP | LOG_WARNING, _("Ignoring domain %s for DHCP host name %s"), config_domain, name);
! 853:
! 854: if (lease->hostname && name && hostname_isequal(lease->hostname, name))
! 855: {
! 856: if (auth)
! 857: lease->flags |= LEASE_AUTH_NAME;
! 858: return;
! 859: }
! 860:
! 861: if (!name && !lease->hostname)
! 862: return;
! 863:
! 864: /* If a machine turns up on a new net without dropping the old lease,
! 865: or two machines claim the same name, then we end up with two interfaces with
! 866: the same name. Check for that here and remove the name from the old lease.
! 867: Note that IPv6 leases are different. All the leases to the same DUID are
! 868: allowed the same name.
! 869:
! 870: Don't allow a name from the client to override a name from dnsmasq config. */
! 871:
! 872: if (name)
! 873: {
! 874: if ((new_name = whine_malloc(strlen(name) + 1)))
! 875: {
! 876: strcpy(new_name, name);
! 877: if (domain && (new_fqdn = whine_malloc(strlen(new_name) + strlen(domain) + 2)))
! 878: {
! 879: strcpy(new_fqdn, name);
! 880: strcat(new_fqdn, ".");
! 881: strcat(new_fqdn, domain);
! 882: }
! 883: }
! 884:
! 885: /* Depending on mode, we check either unqualified name or FQDN. */
! 886: for (lease_tmp = leases; lease_tmp; lease_tmp = lease_tmp->next)
! 887: {
! 888: if (option_bool(OPT_DHCP_FQDN))
! 889: {
! 890: if (!new_fqdn || !lease_tmp->fqdn || !hostname_isequal(lease_tmp->fqdn, new_fqdn))
! 891: continue;
! 892: }
! 893: else
! 894: {
! 895: if (!new_name || !lease_tmp->hostname || !hostname_isequal(lease_tmp->hostname, new_name) )
! 896: continue;
! 897: }
! 898:
! 899: if (lease->flags & (LEASE_TA | LEASE_NA))
! 900: {
! 901: if (!(lease_tmp->flags & (LEASE_TA | LEASE_NA)))
! 902: continue;
! 903:
! 904: /* another lease for the same DUID is OK for IPv6 */
! 905: if (lease->clid_len == lease_tmp->clid_len &&
! 906: lease->clid && lease_tmp->clid &&
! 907: memcmp(lease->clid, lease_tmp->clid, lease->clid_len) == 0)
! 908: continue;
! 909: }
! 910: else if (lease_tmp->flags & (LEASE_TA | LEASE_NA))
! 911: continue;
! 912:
! 913: if ((lease_tmp->flags & LEASE_AUTH_NAME) && !auth)
! 914: {
! 915: free(new_name);
! 916: free(new_fqdn);
! 917: return;
! 918: }
! 919:
! 920: kill_name(lease_tmp);
! 921: break;
! 922: }
! 923: }
! 924:
! 925: if (lease->hostname)
! 926: kill_name(lease);
! 927:
! 928: lease->hostname = new_name;
! 929: lease->fqdn = new_fqdn;
! 930:
! 931: if (auth)
! 932: lease->flags |= LEASE_AUTH_NAME;
! 933:
! 934: file_dirty = 1;
! 935: dns_dirty = 1;
! 936: lease->flags |= LEASE_CHANGED; /* run script on change */
! 937: }
! 938:
! 939: void lease_set_interface(struct dhcp_lease *lease, int interface, time_t now)
! 940: {
! 941: if (lease->last_interface == interface)
! 942: return;
! 943:
! 944: lease->last_interface = interface;
! 945: lease->flags |= LEASE_CHANGED;
! 946:
! 947: #ifdef HAVE_DHCP6
! 948: slaac_add_addrs(lease, now, 0);
! 949: #endif
! 950: }
! 951:
! 952: void rerun_scripts(void)
! 953: {
! 954: struct dhcp_lease *lease;
! 955:
! 956: for (lease = leases; lease; lease = lease->next)
! 957: lease->flags |= LEASE_CHANGED;
! 958: }
! 959:
! 960: /* deleted leases get transferred to the old_leases list.
! 961: remove them here, after calling the lease change
! 962: script. Also run the lease change script on new/modified leases.
! 963:
! 964: Return zero if nothing to do. */
! 965: int do_script_run(time_t now)
! 966: {
! 967: struct dhcp_lease *lease;
! 968:
! 969: #ifdef HAVE_DBUS
! 970: /* If we're going to be sending DBus signals, but the connection is not yet up,
! 971: delay everything until it is. */
! 972: if (option_bool(OPT_DBUS) && !daemon->dbus)
! 973: return 0;
! 974: #endif
! 975:
! 976: if (old_leases)
! 977: {
! 978: lease = old_leases;
! 979:
! 980: /* If the lease still has an old_hostname, do the "old" action on that first */
! 981: if (lease->old_hostname)
! 982: {
! 983: #ifdef HAVE_SCRIPT
! 984: queue_script(ACTION_OLD_HOSTNAME, lease, lease->old_hostname, now);
! 985: #endif
! 986: free(lease->old_hostname);
! 987: lease->old_hostname = NULL;
! 988: return 1;
! 989: }
! 990: else
! 991: {
! 992: #ifdef HAVE_DHCP6
! 993: struct slaac_address *slaac, *tmp;
! 994: for (slaac = lease->slaac_address; slaac; slaac = tmp)
! 995: {
! 996: tmp = slaac->next;
! 997: free(slaac);
! 998: }
! 999: #endif
! 1000: kill_name(lease);
! 1001: #ifdef HAVE_SCRIPT
! 1002: queue_script(ACTION_DEL, lease, lease->old_hostname, now);
! 1003: #endif
! 1004: #ifdef HAVE_DBUS
! 1005: emit_dbus_signal(ACTION_DEL, lease, lease->old_hostname);
! 1006: #endif
! 1007: old_leases = lease->next;
! 1008:
! 1009: free(lease->old_hostname);
! 1010: free(lease->clid);
! 1011: free(lease->extradata);
! 1012: free(lease);
! 1013:
! 1014: return 1;
! 1015: }
! 1016: }
! 1017:
! 1018: /* make sure we announce the loss of a hostname before its new location. */
! 1019: for (lease = leases; lease; lease = lease->next)
! 1020: if (lease->old_hostname)
! 1021: {
! 1022: #ifdef HAVE_SCRIPT
! 1023: queue_script(ACTION_OLD_HOSTNAME, lease, lease->old_hostname, now);
! 1024: #endif
! 1025: free(lease->old_hostname);
! 1026: lease->old_hostname = NULL;
! 1027: return 1;
! 1028: }
! 1029:
! 1030: for (lease = leases; lease; lease = lease->next)
! 1031: if ((lease->flags & (LEASE_NEW | LEASE_CHANGED)) ||
! 1032: ((lease->flags & LEASE_AUX_CHANGED) && option_bool(OPT_LEASE_RO)))
! 1033: {
! 1034: #ifdef HAVE_SCRIPT
! 1035: queue_script((lease->flags & LEASE_NEW) ? ACTION_ADD : ACTION_OLD, lease,
! 1036: lease->fqdn ? lease->fqdn : lease->hostname, now);
! 1037: #endif
! 1038: #ifdef HAVE_DBUS
! 1039: emit_dbus_signal((lease->flags & LEASE_NEW) ? ACTION_ADD : ACTION_OLD, lease,
! 1040: lease->fqdn ? lease->fqdn : lease->hostname);
! 1041: #endif
! 1042: lease->flags &= ~(LEASE_NEW | LEASE_CHANGED | LEASE_AUX_CHANGED);
! 1043:
! 1044: /* this is used for the "add" call, then junked, since they're not in the database */
! 1045: free(lease->extradata);
! 1046: lease->extradata = NULL;
! 1047:
! 1048: return 1;
! 1049: }
! 1050:
! 1051: return 0; /* nothing to do */
! 1052: }
! 1053:
! 1054: #ifdef HAVE_SCRIPT
! 1055: void lease_add_extradata(struct dhcp_lease *lease, unsigned char *data, unsigned int len, int delim)
! 1056: {
! 1057: unsigned int i;
! 1058:
! 1059: /* check for embeded NULLs */
! 1060: for (i = 0; i < len; i++)
! 1061: if (data[i] == 0)
! 1062: {
! 1063: len = i;
! 1064: break;
! 1065: }
! 1066:
! 1067: if ((lease->extradata_size - lease->extradata_len) < (len + 1))
! 1068: {
! 1069: size_t newsz = lease->extradata_len + len + 100;
! 1070: unsigned char *new = whine_malloc(newsz);
! 1071:
! 1072: if (!new)
! 1073: return;
! 1074:
! 1075: if (lease->extradata)
! 1076: {
! 1077: memcpy(new, lease->extradata, lease->extradata_len);
! 1078: free(lease->extradata);
! 1079: }
! 1080:
! 1081: lease->extradata = new;
! 1082: lease->extradata_size = newsz;
! 1083: }
! 1084:
! 1085: if (len != 0)
! 1086: memcpy(lease->extradata + lease->extradata_len, data, len);
! 1087: lease->extradata[lease->extradata_len + len] = delim;
! 1088: lease->extradata_len += len + 1;
! 1089: }
! 1090: #endif
! 1091:
! 1092: #endif
! 1093:
! 1094:
! 1095:
! 1096:
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>