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