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