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