Annotation of embedaddon/dnsmasq/src/lease.c, revision 1.1.1.2
1.1.1.2 ! misho 1: /* dnsmasq is Copyright (c) 2000-2014 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;
355:
1.1.1.2 ! misho 356: (void) label;
1.1 misho 357: (void) broadcast;
358: (void) vparam;
359:
360: for (lease = leases; lease; lease = lease->next)
361: if (!(lease->flags & (LEASE_TA | LEASE_NA)))
362: if (is_same_net(local, lease->addr, netmask))
363: lease_set_interface(lease, if_index, *((time_t *)vparam));
364:
365: return 1;
366: }
367:
368: #ifdef HAVE_DHCP6
369: static int find_interface_v6(struct in6_addr *local, int prefix,
370: int scope, int if_index, int flags,
371: int preferred, int valid, void *vparam)
372: {
373: struct dhcp_lease *lease;
374:
375: (void)scope;
376: (void)flags;
377: (void)preferred;
378: (void)valid;
379:
380: for (lease = leases; lease; lease = lease->next)
381: if ((lease->flags & (LEASE_TA | LEASE_NA)))
1.1.1.2 ! misho 382: if (is_same_net6(local, &lease->addr6, prefix))
1.1 misho 383: lease_set_interface(lease, if_index, *((time_t *)vparam));
384:
385: return 1;
386: }
387:
388: void lease_ping_reply(struct in6_addr *sender, unsigned char *packet, char *interface)
389: {
390: /* We may be doing RA but not DHCPv4, in which case the lease
391: database may not exist and we have nothing to do anyway */
392: if (daemon->dhcp)
393: slaac_ping_reply(sender, packet, interface, leases);
394: }
395:
396: void lease_update_slaac(time_t now)
397: {
398: /* Called when we contruct a new RA-names context, to add putative
399: new SLAAC addresses to existing leases. */
400:
401: struct dhcp_lease *lease;
402:
403: if (daemon->dhcp)
404: for (lease = leases; lease; lease = lease->next)
405: slaac_add_addrs(lease, now, 0);
406: }
407:
408: #endif
409:
410:
411: /* Find interfaces associated with leases at start-up. This gets updated as
412: we do DHCP transactions, but information about directly-connected subnets
413: is useful from scrips and necessary for determining SLAAC addresses from
414: start-time. */
415: void lease_find_interfaces(time_t now)
416: {
417: iface_enumerate(AF_INET, &now, find_interface_v4);
418: #ifdef HAVE_DHCP6
419: iface_enumerate(AF_INET6, &now, find_interface_v6);
1.1.1.2 ! misho 420: #endif
! 421: }
1.1 misho 422:
1.1.1.2 ! misho 423: #ifdef HAVE_DHCP6
! 424: void lease_make_duid(time_t now)
! 425: {
1.1 misho 426: /* 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 427: if (!daemon->duid && daemon->doing_dhcp6)
1.1 misho 428: {
429: file_dirty = 1;
430: make_duid(now);
431: }
432: }
1.1.1.2 ! misho 433: #endif
! 434:
1.1 misho 435:
436:
437:
438: void lease_update_dns(int force)
439: {
440: struct dhcp_lease *lease;
441:
442: if (daemon->port != 0 && (dns_dirty || force))
443: {
444: #ifndef HAVE_BROKEN_RTC
445: /* force transfer to authoritative secondaries */
446: daemon->soa_sn++;
447: #endif
448:
449: cache_unhash_dhcp();
450:
451: for (lease = leases; lease; lease = lease->next)
452: {
453: int prot = AF_INET;
454:
455: #ifdef HAVE_DHCP6
456: if (lease->flags & (LEASE_TA | LEASE_NA))
457: prot = AF_INET6;
458: else if (lease->hostname || lease->fqdn)
459: {
460: struct slaac_address *slaac;
461:
462: for (slaac = lease->slaac_address; slaac; slaac = slaac->next)
463: if (slaac->backoff == 0)
464: {
465: if (lease->fqdn)
466: cache_add_dhcp_entry(lease->fqdn, AF_INET6, (struct all_addr *)&slaac->addr, lease->expires);
467: if (!option_bool(OPT_DHCP_FQDN) && lease->hostname)
468: cache_add_dhcp_entry(lease->hostname, AF_INET6, (struct all_addr *)&slaac->addr, lease->expires);
469: }
470: }
471:
472: if (lease->fqdn)
473: cache_add_dhcp_entry(lease->fqdn, prot,
1.1.1.2 ! misho 474: prot == AF_INET ? (struct all_addr *)&lease->addr : (struct all_addr *)&lease->addr6,
1.1 misho 475: lease->expires);
476:
477: if (!option_bool(OPT_DHCP_FQDN) && lease->hostname)
478: cache_add_dhcp_entry(lease->hostname, prot,
1.1.1.2 ! misho 479: prot == AF_INET ? (struct all_addr *)&lease->addr : (struct all_addr *)&lease->addr6,
1.1 misho 480: lease->expires);
1.1.1.2 ! misho 481:
! 482: #else
! 483: if (lease->fqdn)
! 484: cache_add_dhcp_entry(lease->fqdn, prot, (struct all_addr *)&lease->addr, lease->expires);
! 485:
! 486: if (!option_bool(OPT_DHCP_FQDN) && lease->hostname)
! 487: cache_add_dhcp_entry(lease->hostname, prot, (struct all_addr *)&lease->addr, lease->expires);
! 488: #endif
1.1 misho 489: }
490:
491: dns_dirty = 0;
492: }
493: }
494:
495: void lease_prune(struct dhcp_lease *target, time_t now)
496: {
497: struct dhcp_lease *lease, *tmp, **up;
498:
499: for (lease = leases, up = &leases; lease; lease = tmp)
500: {
501: tmp = lease->next;
502: if ((lease->expires != 0 && difftime(now, lease->expires) > 0) || lease == target)
503: {
504: file_dirty = 1;
505: if (lease->hostname)
506: dns_dirty = 1;
507:
508: *up = lease->next; /* unlink */
509:
510: /* Put on old_leases list 'till we
511: can run the script */
512: lease->next = old_leases;
513: old_leases = lease;
514:
515: leases_left++;
516: }
517: else
518: up = &lease->next;
519: }
520: }
521:
522:
523: struct dhcp_lease *lease_find_by_client(unsigned char *hwaddr, int hw_len, int hw_type,
524: unsigned char *clid, int clid_len)
525: {
526: struct dhcp_lease *lease;
527:
528: if (clid)
529: for (lease = leases; lease; lease = lease->next)
530: {
531: #ifdef HAVE_DHCP6
532: if (lease->flags & (LEASE_TA | LEASE_NA))
533: continue;
534: #endif
535: if (lease->clid && clid_len == lease->clid_len &&
536: memcmp(clid, lease->clid, clid_len) == 0)
537: return lease;
538: }
539:
540: for (lease = leases; lease; lease = lease->next)
541: {
542: #ifdef HAVE_DHCP6
543: if (lease->flags & (LEASE_TA | LEASE_NA))
544: continue;
545: #endif
546: if ((!lease->clid || !clid) &&
547: hw_len != 0 &&
548: lease->hwaddr_len == hw_len &&
549: lease->hwaddr_type == hw_type &&
550: memcmp(hwaddr, lease->hwaddr, hw_len) == 0)
551: return lease;
552: }
553:
554: return NULL;
555: }
556:
557: struct dhcp_lease *lease_find_by_addr(struct in_addr addr)
558: {
559: struct dhcp_lease *lease;
560:
561: for (lease = leases; lease; lease = lease->next)
562: {
563: #ifdef HAVE_DHCP6
564: if (lease->flags & (LEASE_TA | LEASE_NA))
565: continue;
566: #endif
567: if (lease->addr.s_addr == addr.s_addr)
568: return lease;
569: }
570:
571: return NULL;
572: }
573:
574: #ifdef HAVE_DHCP6
575: /* find address for {CLID, IAID, address} */
576: struct dhcp_lease *lease6_find(unsigned char *clid, int clid_len,
577: int lease_type, int iaid, struct in6_addr *addr)
578: {
579: struct dhcp_lease *lease;
580:
581: for (lease = leases; lease; lease = lease->next)
582: {
1.1.1.2 ! misho 583: if (!(lease->flags & lease_type) || lease->iaid != iaid)
1.1 misho 584: continue;
585:
1.1.1.2 ! misho 586: if (!IN6_ARE_ADDR_EQUAL(&lease->addr6, addr))
1.1 misho 587: continue;
588:
589: if ((clid_len != lease->clid_len ||
590: memcmp(clid, lease->clid, clid_len) != 0))
591: continue;
592:
593: return lease;
594: }
595:
596: return NULL;
597: }
598:
599: /* reset "USED flags */
600: void lease6_reset(void)
601: {
602: struct dhcp_lease *lease;
603:
604: for (lease = leases; lease; lease = lease->next)
605: lease->flags &= ~LEASE_USED;
606: }
607:
608: /* enumerate all leases belonging to {CLID, IAID} */
609: struct dhcp_lease *lease6_find_by_client(struct dhcp_lease *first, int lease_type, unsigned char *clid, int clid_len, int iaid)
610: {
611: struct dhcp_lease *lease;
612:
613: if (!first)
614: first = leases;
615: else
616: first = first->next;
617:
618: for (lease = first; lease; lease = lease->next)
619: {
620: if (lease->flags & LEASE_USED)
621: continue;
622:
1.1.1.2 ! misho 623: if (!(lease->flags & lease_type) || lease->iaid != iaid)
1.1 misho 624: continue;
625:
626: if ((clid_len != lease->clid_len ||
627: memcmp(clid, lease->clid, clid_len) != 0))
628: continue;
629:
630: return lease;
631: }
632:
633: return NULL;
634: }
635:
636: struct dhcp_lease *lease6_find_by_addr(struct in6_addr *net, int prefix, u64 addr)
637: {
638: struct dhcp_lease *lease;
639:
640: for (lease = leases; lease; lease = lease->next)
641: {
642: if (!(lease->flags & (LEASE_TA | LEASE_NA)))
643: continue;
644:
1.1.1.2 ! misho 645: if (is_same_net6(&lease->addr6, net, prefix) &&
! 646: (prefix == 128 || addr6part(&lease->addr6) == addr))
1.1 misho 647: return lease;
648: }
649:
650: return NULL;
651: }
652:
653: /* Find largest assigned address in context */
654: u64 lease_find_max_addr6(struct dhcp_context *context)
655: {
656: struct dhcp_lease *lease;
657: u64 addr = addr6part(&context->start6);
658:
659: if (!(context->flags & (CONTEXT_STATIC | CONTEXT_PROXY)))
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, &context->start6, 64) &&
! 666: addr6part(&lease->addr6) > addr6part(&context->start6) &&
! 667: addr6part(&lease->addr6) <= addr6part(&context->end6) &&
! 668: addr6part(&lease->addr6) > addr)
! 669: addr = addr6part(&lease->addr6);
1.1 misho 670: }
671:
672: return addr;
673: }
674:
675: #endif
676:
677: /* Find largest assigned address in context */
678: struct in_addr lease_find_max_addr(struct dhcp_context *context)
679: {
680: struct dhcp_lease *lease;
681: struct in_addr addr = context->start;
682:
683: if (!(context->flags & (CONTEXT_STATIC | CONTEXT_PROXY)))
684: for (lease = leases; lease; lease = lease->next)
685: {
686: #ifdef HAVE_DHCP6
687: if (lease->flags & (LEASE_TA | LEASE_NA))
688: continue;
689: #endif
690: if (((unsigned)ntohl(lease->addr.s_addr)) > ((unsigned)ntohl(context->start.s_addr)) &&
691: ((unsigned)ntohl(lease->addr.s_addr)) <= ((unsigned)ntohl(context->end.s_addr)) &&
692: ((unsigned)ntohl(lease->addr.s_addr)) > ((unsigned)ntohl(addr.s_addr)))
693: addr = lease->addr;
694: }
695:
696: return addr;
697: }
698:
699: static struct dhcp_lease *lease_allocate(void)
700: {
701: struct dhcp_lease *lease;
702: if (!leases_left || !(lease = whine_malloc(sizeof(struct dhcp_lease))))
703: return NULL;
704:
705: memset(lease, 0, sizeof(struct dhcp_lease));
706: lease->flags = LEASE_NEW;
707: lease->expires = 1;
708: #ifdef HAVE_BROKEN_RTC
709: lease->length = 0xffffffff; /* illegal value */
710: #endif
1.1.1.2 ! misho 711: lease->hwaddr_len = 256; /* illegal value */
1.1 misho 712: lease->next = leases;
713: leases = lease;
714:
715: file_dirty = 1;
716: leases_left--;
717:
718: return lease;
719: }
720:
721: struct dhcp_lease *lease4_allocate(struct in_addr addr)
722: {
723: struct dhcp_lease *lease = lease_allocate();
724: if (lease)
1.1.1.2 ! misho 725: lease->addr = addr;
! 726:
1.1 misho 727: return lease;
728: }
729:
730: #ifdef HAVE_DHCP6
731: struct dhcp_lease *lease6_allocate(struct in6_addr *addrp, int lease_type)
732: {
733: struct dhcp_lease *lease = lease_allocate();
734:
735: if (lease)
736: {
1.1.1.2 ! misho 737: lease->addr6 = *addrp;
1.1 misho 738: lease->flags |= lease_type;
1.1.1.2 ! misho 739: lease->iaid = 0;
1.1 misho 740: }
741:
742: return lease;
743: }
744: #endif
745:
746: void lease_set_expires(struct dhcp_lease *lease, unsigned int len, time_t now)
747: {
1.1.1.2 ! misho 748: time_t exp;
! 749:
1.1 misho 750: if (len == 0xffffffff)
751: {
752: exp = 0;
753: len = 0;
754: }
1.1.1.2 ! misho 755: else
! 756: {
! 757: exp = now + (time_t)len;
! 758: /* Check for 2038 overflow. Make the lease
! 759: inifinite in that case, as the least disruptive
! 760: thing we can do. */
! 761: if (difftime(exp, now) <= 0.0)
! 762: exp = 0;
! 763: }
! 764:
1.1 misho 765: if (exp != lease->expires)
766: {
767: dns_dirty = 1;
768: lease->expires = exp;
769: #ifndef HAVE_BROKEN_RTC
770: lease->flags |= LEASE_AUX_CHANGED;
771: file_dirty = 1;
772: #endif
773: }
774:
775: #ifdef HAVE_BROKEN_RTC
776: if (len != lease->length)
777: {
778: lease->length = len;
779: lease->flags |= LEASE_AUX_CHANGED;
780: file_dirty = 1;
781: }
782: #endif
783: }
784:
1.1.1.2 ! misho 785: #ifdef HAVE_DHCP6
! 786: void lease_set_iaid(struct dhcp_lease *lease, int iaid)
! 787: {
! 788: if (lease->iaid != iaid)
! 789: {
! 790: lease->iaid = iaid;
! 791: lease->flags |= LEASE_CHANGED;
! 792: }
! 793: }
! 794: #endif
! 795:
1.1 misho 796: void lease_set_hwaddr(struct dhcp_lease *lease, unsigned char *hwaddr,
797: unsigned char *clid, int hw_len, int hw_type, int clid_len,
798: time_t now, int force)
799: {
800: #ifdef HAVE_DHCP6
801: int change = force;
802: lease->flags |= LEASE_HAVE_HWADDR;
803: #endif
804:
805: (void)force;
1.1.1.2 ! misho 806: (void)now;
1.1 misho 807:
808: if (hw_len != lease->hwaddr_len ||
809: hw_type != lease->hwaddr_type ||
810: (hw_len != 0 && memcmp(lease->hwaddr, hwaddr, hw_len) != 0))
811: {
812: if (hw_len != 0)
813: memcpy(lease->hwaddr, hwaddr, hw_len);
814: lease->hwaddr_len = hw_len;
815: lease->hwaddr_type = hw_type;
816: lease->flags |= LEASE_CHANGED;
817: file_dirty = 1; /* run script on change */
818: }
819:
820: /* only update clid when one is available, stops packets
821: without a clid removing the record. Lease init uses
822: clid_len == 0 for no clid. */
823: if (clid_len != 0 && clid)
824: {
825: if (!lease->clid)
826: lease->clid_len = 0;
827:
828: if (lease->clid_len != clid_len)
829: {
830: lease->flags |= LEASE_AUX_CHANGED;
831: file_dirty = 1;
832: free(lease->clid);
833: if (!(lease->clid = whine_malloc(clid_len)))
834: return;
835: #ifdef HAVE_DHCP6
836: change = 1;
837: #endif
838: }
839: else if (memcmp(lease->clid, clid, clid_len) != 0)
840: {
841: lease->flags |= LEASE_AUX_CHANGED;
842: file_dirty = 1;
843: #ifdef HAVE_DHCP6
844: change = 1;
845: #endif
846: }
847:
848: lease->clid_len = clid_len;
849: memcpy(lease->clid, clid, clid_len);
850: }
851:
852: #ifdef HAVE_DHCP6
853: if (change)
854: slaac_add_addrs(lease, now, force);
855: #endif
856: }
857:
858: static void kill_name(struct dhcp_lease *lease)
859: {
860: /* run script to say we lost our old name */
861:
862: /* this shouldn't happen unless updates are very quick and the
863: script very slow, we just avoid a memory leak if it does. */
864: free(lease->old_hostname);
865:
866: /* If we know the fqdn, pass that. The helper will derive the
867: unqualified name from it, free the unqualified name here. */
868:
869: if (lease->fqdn)
870: {
871: lease->old_hostname = lease->fqdn;
872: free(lease->hostname);
873: }
874: else
875: lease->old_hostname = lease->hostname;
876:
877: lease->hostname = lease->fqdn = NULL;
878: }
879:
880: void lease_set_hostname(struct dhcp_lease *lease, char *name, int auth, char *domain, char *config_domain)
881: {
882: struct dhcp_lease *lease_tmp;
883: char *new_name = NULL, *new_fqdn = NULL;
884:
885: if (config_domain && (!domain || !hostname_isequal(domain, config_domain)))
886: my_syslog(MS_DHCP | LOG_WARNING, _("Ignoring domain %s for DHCP host name %s"), config_domain, name);
887:
888: if (lease->hostname && name && hostname_isequal(lease->hostname, name))
889: {
890: if (auth)
891: lease->flags |= LEASE_AUTH_NAME;
892: return;
893: }
894:
895: if (!name && !lease->hostname)
896: return;
897:
898: /* If a machine turns up on a new net without dropping the old lease,
899: or two machines claim the same name, then we end up with two interfaces with
900: the same name. Check for that here and remove the name from the old lease.
901: Note that IPv6 leases are different. All the leases to the same DUID are
902: allowed the same name.
903:
904: Don't allow a name from the client to override a name from dnsmasq config. */
905:
906: if (name)
907: {
908: if ((new_name = whine_malloc(strlen(name) + 1)))
909: {
910: strcpy(new_name, name);
911: if (domain && (new_fqdn = whine_malloc(strlen(new_name) + strlen(domain) + 2)))
912: {
913: strcpy(new_fqdn, name);
914: strcat(new_fqdn, ".");
915: strcat(new_fqdn, domain);
916: }
917: }
918:
919: /* Depending on mode, we check either unqualified name or FQDN. */
920: for (lease_tmp = leases; lease_tmp; lease_tmp = lease_tmp->next)
921: {
922: if (option_bool(OPT_DHCP_FQDN))
923: {
924: if (!new_fqdn || !lease_tmp->fqdn || !hostname_isequal(lease_tmp->fqdn, new_fqdn))
925: continue;
926: }
927: else
928: {
929: if (!new_name || !lease_tmp->hostname || !hostname_isequal(lease_tmp->hostname, new_name) )
930: continue;
931: }
932:
933: if (lease->flags & (LEASE_TA | LEASE_NA))
934: {
935: if (!(lease_tmp->flags & (LEASE_TA | LEASE_NA)))
936: continue;
937:
938: /* another lease for the same DUID is OK for IPv6 */
939: if (lease->clid_len == lease_tmp->clid_len &&
940: lease->clid && lease_tmp->clid &&
941: memcmp(lease->clid, lease_tmp->clid, lease->clid_len) == 0)
942: continue;
943: }
944: else if (lease_tmp->flags & (LEASE_TA | LEASE_NA))
945: continue;
946:
947: if ((lease_tmp->flags & LEASE_AUTH_NAME) && !auth)
948: {
949: free(new_name);
950: free(new_fqdn);
951: return;
952: }
953:
954: kill_name(lease_tmp);
955: break;
956: }
957: }
958:
959: if (lease->hostname)
960: kill_name(lease);
961:
962: lease->hostname = new_name;
963: lease->fqdn = new_fqdn;
964:
965: if (auth)
966: lease->flags |= LEASE_AUTH_NAME;
967:
968: file_dirty = 1;
969: dns_dirty = 1;
970: lease->flags |= LEASE_CHANGED; /* run script on change */
971: }
972:
973: void lease_set_interface(struct dhcp_lease *lease, int interface, time_t now)
974: {
1.1.1.2 ! misho 975: (void)now;
! 976:
1.1 misho 977: if (lease->last_interface == interface)
978: return;
979:
980: lease->last_interface = interface;
981: lease->flags |= LEASE_CHANGED;
982:
983: #ifdef HAVE_DHCP6
984: slaac_add_addrs(lease, now, 0);
985: #endif
986: }
987:
988: void rerun_scripts(void)
989: {
990: struct dhcp_lease *lease;
991:
992: for (lease = leases; lease; lease = lease->next)
993: lease->flags |= LEASE_CHANGED;
994: }
995:
996: /* deleted leases get transferred to the old_leases list.
997: remove them here, after calling the lease change
998: script. Also run the lease change script on new/modified leases.
999:
1000: Return zero if nothing to do. */
1001: int do_script_run(time_t now)
1002: {
1003: struct dhcp_lease *lease;
1004:
1.1.1.2 ! misho 1005: (void)now;
! 1006:
1.1 misho 1007: #ifdef HAVE_DBUS
1008: /* If we're going to be sending DBus signals, but the connection is not yet up,
1009: delay everything until it is. */
1010: if (option_bool(OPT_DBUS) && !daemon->dbus)
1011: return 0;
1012: #endif
1013:
1014: if (old_leases)
1015: {
1016: lease = old_leases;
1017:
1018: /* If the lease still has an old_hostname, do the "old" action on that first */
1019: if (lease->old_hostname)
1020: {
1021: #ifdef HAVE_SCRIPT
1022: queue_script(ACTION_OLD_HOSTNAME, lease, lease->old_hostname, now);
1023: #endif
1024: free(lease->old_hostname);
1025: lease->old_hostname = NULL;
1026: return 1;
1027: }
1028: else
1029: {
1030: #ifdef HAVE_DHCP6
1031: struct slaac_address *slaac, *tmp;
1032: for (slaac = lease->slaac_address; slaac; slaac = tmp)
1033: {
1034: tmp = slaac->next;
1035: free(slaac);
1036: }
1037: #endif
1038: kill_name(lease);
1039: #ifdef HAVE_SCRIPT
1040: queue_script(ACTION_DEL, lease, lease->old_hostname, now);
1041: #endif
1042: #ifdef HAVE_DBUS
1043: emit_dbus_signal(ACTION_DEL, lease, lease->old_hostname);
1044: #endif
1045: old_leases = lease->next;
1046:
1047: free(lease->old_hostname);
1048: free(lease->clid);
1049: free(lease->extradata);
1050: free(lease);
1051:
1052: return 1;
1053: }
1054: }
1055:
1056: /* make sure we announce the loss of a hostname before its new location. */
1057: for (lease = leases; lease; lease = lease->next)
1058: if (lease->old_hostname)
1059: {
1060: #ifdef HAVE_SCRIPT
1061: queue_script(ACTION_OLD_HOSTNAME, lease, lease->old_hostname, now);
1062: #endif
1063: free(lease->old_hostname);
1064: lease->old_hostname = NULL;
1065: return 1;
1066: }
1067:
1068: for (lease = leases; lease; lease = lease->next)
1069: if ((lease->flags & (LEASE_NEW | LEASE_CHANGED)) ||
1070: ((lease->flags & LEASE_AUX_CHANGED) && option_bool(OPT_LEASE_RO)))
1071: {
1072: #ifdef HAVE_SCRIPT
1073: queue_script((lease->flags & LEASE_NEW) ? ACTION_ADD : ACTION_OLD, lease,
1074: lease->fqdn ? lease->fqdn : lease->hostname, now);
1075: #endif
1076: #ifdef HAVE_DBUS
1077: emit_dbus_signal((lease->flags & LEASE_NEW) ? ACTION_ADD : ACTION_OLD, lease,
1078: lease->fqdn ? lease->fqdn : lease->hostname);
1079: #endif
1080: lease->flags &= ~(LEASE_NEW | LEASE_CHANGED | LEASE_AUX_CHANGED);
1081:
1082: /* this is used for the "add" call, then junked, since they're not in the database */
1083: free(lease->extradata);
1084: lease->extradata = NULL;
1085:
1086: return 1;
1087: }
1088:
1089: return 0; /* nothing to do */
1090: }
1091:
1092: #ifdef HAVE_SCRIPT
1093: void lease_add_extradata(struct dhcp_lease *lease, unsigned char *data, unsigned int len, int delim)
1094: {
1095: unsigned int i;
1096:
1097: /* check for embeded NULLs */
1098: for (i = 0; i < len; i++)
1099: if (data[i] == 0)
1100: {
1101: len = i;
1102: break;
1103: }
1104:
1105: if ((lease->extradata_size - lease->extradata_len) < (len + 1))
1106: {
1107: size_t newsz = lease->extradata_len + len + 100;
1108: unsigned char *new = whine_malloc(newsz);
1109:
1110: if (!new)
1111: return;
1112:
1113: if (lease->extradata)
1114: {
1115: memcpy(new, lease->extradata, lease->extradata_len);
1116: free(lease->extradata);
1117: }
1118:
1119: lease->extradata = new;
1120: lease->extradata_size = newsz;
1121: }
1122:
1123: if (len != 0)
1124: memcpy(lease->extradata + lease->extradata_len, data, len);
1125: lease->extradata[lease->extradata_len + len] = delim;
1126: lease->extradata_len += len + 1;
1127: }
1128: #endif
1129:
1130: #endif
1131:
1132:
1133:
1134:
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>