Annotation of embedaddon/dnsmasq/src/lease.c, revision 1.1.1.5
1.1.1.5 ! misho 1: /* dnsmasq is Copyright (c) 2000-2022 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:
1.1.1.5 ! misho 381: my_syslog(MS_DHCP | LOG_ERR, _("failed to write %s: %s (retry in %u s)"),
1.1 misho 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);
1.1.1.5 ! misho 1024: lease_tmp->flags |= LEASE_CHANGED; /* run script on change */
1.1 misho 1025: break;
1026: }
1027: }
1028:
1029: if (lease->hostname)
1030: kill_name(lease);
1031:
1032: lease->hostname = new_name;
1033: lease->fqdn = new_fqdn;
1034:
1035: if (auth)
1036: lease->flags |= LEASE_AUTH_NAME;
1037:
1038: file_dirty = 1;
1039: dns_dirty = 1;
1040: lease->flags |= LEASE_CHANGED; /* run script on change */
1041: }
1042:
1043: void lease_set_interface(struct dhcp_lease *lease, int interface, time_t now)
1044: {
1.1.1.2 misho 1045: (void)now;
1046:
1.1 misho 1047: if (lease->last_interface == interface)
1048: return;
1049:
1050: lease->last_interface = interface;
1051: lease->flags |= LEASE_CHANGED;
1052:
1053: #ifdef HAVE_DHCP6
1054: slaac_add_addrs(lease, now, 0);
1055: #endif
1056: }
1057:
1058: void rerun_scripts(void)
1059: {
1060: struct dhcp_lease *lease;
1061:
1062: for (lease = leases; lease; lease = lease->next)
1063: lease->flags |= LEASE_CHANGED;
1064: }
1065:
1066: /* deleted leases get transferred to the old_leases list.
1067: remove them here, after calling the lease change
1068: script. Also run the lease change script on new/modified leases.
1069:
1070: Return zero if nothing to do. */
1071: int do_script_run(time_t now)
1072: {
1073: struct dhcp_lease *lease;
1074:
1.1.1.2 misho 1075: (void)now;
1076:
1.1 misho 1077: #ifdef HAVE_DBUS
1078: /* If we're going to be sending DBus signals, but the connection is not yet up,
1079: delay everything until it is. */
1080: if (option_bool(OPT_DBUS) && !daemon->dbus)
1081: return 0;
1082: #endif
1083:
1084: if (old_leases)
1085: {
1086: lease = old_leases;
1087:
1088: /* If the lease still has an old_hostname, do the "old" action on that first */
1089: if (lease->old_hostname)
1090: {
1091: #ifdef HAVE_SCRIPT
1092: queue_script(ACTION_OLD_HOSTNAME, lease, lease->old_hostname, now);
1093: #endif
1094: free(lease->old_hostname);
1095: lease->old_hostname = NULL;
1096: return 1;
1097: }
1098: else
1099: {
1100: #ifdef HAVE_DHCP6
1101: struct slaac_address *slaac, *tmp;
1102: for (slaac = lease->slaac_address; slaac; slaac = tmp)
1103: {
1104: tmp = slaac->next;
1105: free(slaac);
1106: }
1107: #endif
1108: kill_name(lease);
1109: #ifdef HAVE_SCRIPT
1110: queue_script(ACTION_DEL, lease, lease->old_hostname, now);
1111: #endif
1112: #ifdef HAVE_DBUS
1113: emit_dbus_signal(ACTION_DEL, lease, lease->old_hostname);
1114: #endif
1115: old_leases = lease->next;
1116:
1117: free(lease->old_hostname);
1118: free(lease->clid);
1119: free(lease->extradata);
1120: free(lease);
1121:
1122: return 1;
1123: }
1124: }
1125:
1126: /* make sure we announce the loss of a hostname before its new location. */
1127: for (lease = leases; lease; lease = lease->next)
1128: if (lease->old_hostname)
1129: {
1130: #ifdef HAVE_SCRIPT
1131: queue_script(ACTION_OLD_HOSTNAME, lease, lease->old_hostname, now);
1132: #endif
1133: free(lease->old_hostname);
1134: lease->old_hostname = NULL;
1135: return 1;
1136: }
1137:
1138: for (lease = leases; lease; lease = lease->next)
1139: if ((lease->flags & (LEASE_NEW | LEASE_CHANGED)) ||
1.1.1.4 misho 1140: ((lease->flags & LEASE_AUX_CHANGED) && option_bool(OPT_LEASE_RO)) ||
1141: ((lease->flags & LEASE_EXP_CHANGED) && option_bool(OPT_LEASE_RENEW)))
1.1 misho 1142: {
1143: #ifdef HAVE_SCRIPT
1144: queue_script((lease->flags & LEASE_NEW) ? ACTION_ADD : ACTION_OLD, lease,
1145: lease->fqdn ? lease->fqdn : lease->hostname, now);
1146: #endif
1147: #ifdef HAVE_DBUS
1148: emit_dbus_signal((lease->flags & LEASE_NEW) ? ACTION_ADD : ACTION_OLD, lease,
1149: lease->fqdn ? lease->fqdn : lease->hostname);
1150: #endif
1.1.1.4 misho 1151: lease->flags &= ~(LEASE_NEW | LEASE_CHANGED | LEASE_AUX_CHANGED | LEASE_EXP_CHANGED);
1.1 misho 1152:
1153: /* this is used for the "add" call, then junked, since they're not in the database */
1154: free(lease->extradata);
1155: lease->extradata = NULL;
1156:
1157: return 1;
1158: }
1159:
1160: return 0; /* nothing to do */
1161: }
1162:
1163: #ifdef HAVE_SCRIPT
1.1.1.4 misho 1164: /* delim == -1 -> delim = 0, but embedded 0s, creating extra records, are OK. */
1.1 misho 1165: void lease_add_extradata(struct dhcp_lease *lease, unsigned char *data, unsigned int len, int delim)
1166: {
1167: unsigned int i;
1168:
1.1.1.3 misho 1169: if (delim == -1)
1170: delim = 0;
1171: else
1.1.1.4 misho 1172: /* check for embedded NULLs */
1.1.1.3 misho 1173: for (i = 0; i < len; i++)
1174: if (data[i] == 0)
1175: {
1176: len = i;
1177: break;
1178: }
1179:
1.1 misho 1180: if ((lease->extradata_size - lease->extradata_len) < (len + 1))
1181: {
1182: size_t newsz = lease->extradata_len + len + 100;
1.1.1.5 ! misho 1183: unsigned char *new = whine_realloc(lease->extradata, newsz);
1.1 misho 1184:
1185: if (!new)
1186: return;
1187:
1188: lease->extradata = new;
1189: lease->extradata_size = newsz;
1190: }
1191:
1192: if (len != 0)
1193: memcpy(lease->extradata + lease->extradata_len, data, len);
1194: lease->extradata[lease->extradata_len + len] = delim;
1195: lease->extradata_len += len + 1;
1196: }
1197: #endif
1198:
1.1.1.5 ! misho 1199: #endif /* HAVE_DHCP */
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>