dnsmasq: v2.67test16 patch Sept.25th/2013.
[tomato.git] / release / src / router / dnsmasq / src / lease.c
blob4a910990bd5a051fa93406cff3ef3984e2492950
1 /* dnsmasq is Copyright (c) 2000-2013 Simon Kelley
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.
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.
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/>.
17 #include "dnsmasq.h"
19 #ifdef HAVE_DHCP
21 static struct dhcp_lease *leases = NULL, *old_leases = NULL;
22 static int dns_dirty, file_dirty, leases_left;
24 void lease_init(time_t now)
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;
32 leases_left = daemon->dhcp_max;
34 if (option_bool(OPT_LEASE_RO))
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)
43 strcpy(daemon->dhcp_buff, daemon->lease_change_command);
44 strcat(daemon->dhcp_buff, " init");
45 leasestream = popen(daemon->dhcp_buff, "r");
47 else
48 #endif
50 file_dirty = dns_dirty = 0;
51 return;
55 else
57 /* NOTE: need a+ mode to create file if it doesn't exist */
58 leasestream = daemon->lease_stream = fopen(daemon->lease_file, "a+");
60 if (!leasestream)
61 die(_("cannot open or create lease file %s: %s"), daemon->lease_file, EC_FILE);
63 /* a+ mode leaves pointer at end. */
64 rewind(leasestream);
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)
72 #ifdef HAVE_DHCP6
73 if (strcmp(daemon->dhcp_buff3, "duid") == 0)
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;
80 #endif
82 ei = atol(daemon->dhcp_buff3);
84 if (fscanf(leasestream, " %64s %255s %764s",
85 daemon->namebuff, daemon->dhcp_buff, daemon->packet) != 3)
86 break;
88 clid_len = 0;
89 if (strcmp(daemon->packet, "*") != 0)
90 clid_len = parse_hex(daemon->packet, (unsigned char *)daemon->packet, 255, NULL, NULL);
92 if (inet_pton(AF_INET, daemon->namebuff, &addr.addr.addr4) &&
93 (lease = lease4_allocate(addr.addr.addr4)))
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;
100 lease_set_hwaddr(lease, (unsigned char *)daemon->dhcp_buff2, (unsigned char *)daemon->packet,
101 hw_len, hw_type, clid_len, now, 0);
103 if (strcmp(daemon->dhcp_buff, "*") != 0)
104 lease_set_hostname(lease, daemon->dhcp_buff, 0, get_domain(lease->addr), NULL);
106 #ifdef HAVE_DHCP6
107 else if (inet_pton(AF_INET6, daemon->namebuff, &addr.addr.addr6))
109 char *s = daemon->dhcp_buff2;
110 int lease_type = LEASE_NA;
111 int iaid;
113 if (s[0] == 'T')
115 lease_type = LEASE_TA;
116 s++;
119 iaid = strtoul(s, NULL, 10);
121 if ((lease = lease6_allocate(&addr.addr.addr6, lease_type)))
123 lease_set_hwaddr(lease, NULL, (unsigned char *)daemon->packet, 0, 0, clid_len, now, 0);
124 lease_set_iaid(lease, iaid);
125 if (strcmp(daemon->dhcp_buff, "*") != 0)
126 lease_set_hostname(lease, daemon->dhcp_buff, 0, get_domain6((struct in6_addr *)lease->hwaddr), NULL);
129 #endif
130 else
131 break;
133 if (!lease)
134 die (_("too many stored leases"), NULL, EC_MISC);
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
148 /* set these correctly: the "old" events are generated later from
149 the startup synthesised SIGHUP. */
150 lease->flags &= ~(LEASE_NEW | LEASE_CHANGED);
153 #ifdef HAVE_SCRIPT
154 if (!daemon->lease_stream)
156 int rc = 0;
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)
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);
168 if (WEXITSTATUS(rc) != 0)
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);
174 #endif
176 /* Some leases may have expired */
177 file_dirty = 0;
178 lease_prune(NULL, now);
179 dns_dirty = 1;
182 void lease_update_from_configs(void)
184 /* changes to the config may change current leases. */
186 struct dhcp_lease *lease;
187 struct dhcp_config *config;
188 char *name;
190 for (lease = leases; lease; lease = lease->next)
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))
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 */
202 static void ourprintf(int *errp, char *format, ...)
204 va_list ap;
206 va_start(ap, format);
207 if (!(*errp) && vfprintf(daemon->lease_stream, format, ap) < 0)
208 *errp = errno;
209 va_end(ap);
212 void lease_update_file(time_t now)
214 struct dhcp_lease *lease;
215 time_t next_event;
216 int i, err = 0;
218 if (file_dirty != 0 && daemon->lease_stream)
220 errno = 0;
221 rewind(daemon->lease_stream);
222 if (errno != 0 || ftruncate(fileno(daemon->lease_stream), 0) != 0)
223 err = errno;
225 for (lease = leases; lease; lease = lease->next)
228 #ifdef HAVE_DHCP6
229 if (lease->flags & (LEASE_TA | LEASE_NA))
230 continue;
231 #endif
233 //ASUS and TOMATO tweaks to output remaining leasetime
234 #ifdef HAVE_LEASEFILE_EXPIRE
235 ourprintf(&err, "%u ");
236 #endif
238 #ifdef HAVE_BROKEN_RTC
239 ourprintf(&err, "%u ", lease->length);
240 #else
241 ourprintf(&err, "%lu ", (unsigned long)lease->expires);
242 #endif
244 if (lease->hwaddr_type != ARPHRD_ETHER || lease->hwaddr_len == 0)
245 ourprintf(&err, "%.2x-", lease->hwaddr_type);
246 for (i = 0; i < lease->hwaddr_len; i++)
248 ourprintf(&err, "%.2x", lease->hwaddr[i]);
249 if (i != lease->hwaddr_len - 1)
250 ourprintf(&err, ":");
253 inet_ntop(AF_INET, &lease->addr, daemon->addrbuff, ADDRSTRLEN);
255 ourprintf(&err, " %s ", daemon->addrbuff);
256 ourprintf(&err, "%s ", lease->hostname ? lease->hostname : "*");
258 if (lease->clid && lease->clid_len != 0)
260 for (i = 0; i < lease->clid_len - 1; i++)
261 ourprintf(&err, "%.2x:", lease->clid[i]);
262 ourprintf(&err, "%.2x\n", lease->clid[i]);
264 else
265 ourprintf(&err, "*\n");
268 #ifdef HAVE_DHCP6
269 if (daemon->duid)
271 ourprintf(&err, "duid ");
272 for (i = 0; i < daemon->duid_len - 1; i++)
273 ourprintf(&err, "%.2x:", daemon->duid[i]);
274 ourprintf(&err, "%.2x\n", daemon->duid[i]);
276 for (lease = leases; lease; lease = lease->next)
279 if (!(lease->flags & (LEASE_TA | LEASE_NA)))
280 continue;
282 //ASUS and TOMATO tweaks to output remaining leasetime
283 #ifdef HAVE_LEASEFILE_EXPIRE
284 ourprintf(&err, "%u ");
285 #endif
287 #ifdef HAVE_BROKEN_RTC
288 ourprintf(&err, "%u ", lease->length);
289 #else
290 ourprintf(&err, "%lu ", (unsigned long)lease->expires);
291 #endif
293 inet_ntop(AF_INET6, &lease->addr6, daemon->addrbuff, ADDRSTRLEN);
295 ourprintf(&err, "%s%u %s ", (lease->flags & LEASE_TA) ? "T" : "",
296 lease->iaid, daemon->addrbuff);
297 ourprintf(&err, "%s ", lease->hostname ? lease->hostname : "*");
299 if (lease->clid && lease->clid_len != 0)
301 for (i = 0; i < lease->clid_len - 1; i++)
302 ourprintf(&err, "%.2x:", lease->clid[i]);
303 ourprintf(&err, "%.2x\n", lease->clid[i]);
305 else
306 ourprintf(&err, "*\n");
309 #endif
311 if (fflush(daemon->lease_stream) != 0 ||
312 fsync(fileno(daemon->lease_stream)) < 0)
313 err = errno;
315 if (!err)
316 file_dirty = 0;
319 /* Set alarm for when the first lease expires + slop. */
320 next_event = 0;
322 #ifdef HAVE_DHCP6
323 /* do timed RAs and determine when the next is, also pings to potential SLAAC addresses */
324 if (daemon->doing_ra)
326 time_t event;
328 if ((event = periodic_slaac(now, leases)) != 0)
330 if (next_event == 0 || difftime(next_event, event) > 0.0)
331 next_event = event;
334 if ((event = periodic_ra(now)) != 0)
336 if (next_event == 0 || difftime(next_event, event) > 0.0)
337 next_event = event;
340 #endif
342 for (lease = leases; lease; lease = lease->next)
343 if (lease->expires != 0 &&
344 (next_event == 0 || difftime(next_event, lease->expires + 10) > 0.0))
345 next_event = lease->expires + 10;
347 if (err)
349 if (next_event == 0 || difftime(next_event, LEASE_RETRY + now) > 0.0)
350 next_event = LEASE_RETRY + now;
352 my_syslog(MS_DHCP | LOG_ERR, _("failed to write %s: %s (retry in %us)"),
353 daemon->lease_file, strerror(err),
354 (unsigned int)difftime(next_event, now));
357 send_alarm(next_event, now);
361 static int find_interface_v4(struct in_addr local, int if_index, char *label,
362 struct in_addr netmask, struct in_addr broadcast, void *vparam)
364 struct dhcp_lease *lease;
366 (void) label;
367 (void) broadcast;
368 (void) vparam;
370 for (lease = leases; lease; lease = lease->next)
371 if (!(lease->flags & (LEASE_TA | LEASE_NA)))
372 if (is_same_net(local, lease->addr, netmask))
373 lease_set_interface(lease, if_index, *((time_t *)vparam));
375 return 1;
378 #ifdef HAVE_DHCP6
379 static int find_interface_v6(struct in6_addr *local, int prefix,
380 int scope, int if_index, int flags,
381 int preferred, int valid, void *vparam)
383 struct dhcp_lease *lease;
385 (void)scope;
386 (void)flags;
387 (void)preferred;
388 (void)valid;
390 for (lease = leases; lease; lease = lease->next)
391 if ((lease->flags & (LEASE_TA | LEASE_NA)))
392 if (is_same_net6(local, &lease->addr6, prefix))
393 lease_set_interface(lease, if_index, *((time_t *)vparam));
395 return 1;
398 void lease_ping_reply(struct in6_addr *sender, unsigned char *packet, char *interface)
400 /* We may be doing RA but not DHCPv4, in which case the lease
401 database may not exist and we have nothing to do anyway */
402 if (daemon->dhcp)
403 slaac_ping_reply(sender, packet, interface, leases);
406 void lease_update_slaac(time_t now)
408 /* Called when we contruct a new RA-names context, to add putative
409 new SLAAC addresses to existing leases. */
411 struct dhcp_lease *lease;
413 if (daemon->dhcp)
414 for (lease = leases; lease; lease = lease->next)
415 slaac_add_addrs(lease, now, 0);
418 #endif
421 /* Find interfaces associated with leases at start-up. This gets updated as
422 we do DHCP transactions, but information about directly-connected subnets
423 is useful from scrips and necessary for determining SLAAC addresses from
424 start-time. */
425 void lease_find_interfaces(time_t now)
427 iface_enumerate(AF_INET, &now, find_interface_v4);
428 #ifdef HAVE_DHCP6
429 iface_enumerate(AF_INET6, &now, find_interface_v6);
431 /* If we're not doing DHCPv6, and there are not v6 leases, don't add the DUID to the database */
432 if (!daemon->duid && daemon->dhcp6)
434 file_dirty = 1;
435 make_duid(now);
437 #endif
442 void lease_update_dns(int force)
444 struct dhcp_lease *lease;
446 if (daemon->port != 0 && (dns_dirty || force))
448 #ifndef HAVE_BROKEN_RTC
449 /* force transfer to authoritative secondaries */
450 daemon->soa_sn++;
451 #endif
453 cache_unhash_dhcp();
455 for (lease = leases; lease; lease = lease->next)
457 int prot = AF_INET;
459 #ifdef HAVE_DHCP6
460 if (lease->flags & (LEASE_TA | LEASE_NA))
461 prot = AF_INET6;
462 else if (lease->hostname || lease->fqdn)
464 struct slaac_address *slaac;
466 for (slaac = lease->slaac_address; slaac; slaac = slaac->next)
467 if (slaac->backoff == 0)
469 if (lease->fqdn)
470 cache_add_dhcp_entry(lease->fqdn, AF_INET6, (struct all_addr *)&slaac->addr, lease->expires);
471 if (!option_bool(OPT_DHCP_FQDN) && lease->hostname)
472 cache_add_dhcp_entry(lease->hostname, AF_INET6, (struct all_addr *)&slaac->addr, lease->expires);
476 if (lease->fqdn)
477 cache_add_dhcp_entry(lease->fqdn, prot,
478 prot == AF_INET ? (struct all_addr *)&lease->addr : (struct all_addr *)&lease->addr6,
479 lease->expires);
481 if (!option_bool(OPT_DHCP_FQDN) && lease->hostname)
482 cache_add_dhcp_entry(lease->hostname, prot,
483 prot == AF_INET ? (struct all_addr *)&lease->addr : (struct all_addr *)&lease->addr6,
484 lease->expires);
486 #else
487 if (lease->fqdn)
488 cache_add_dhcp_entry(lease->fqdn, prot, (struct all_addr *)&lease->addr, lease->expires);
490 if (!option_bool(OPT_DHCP_FQDN) && lease->hostname)
491 cache_add_dhcp_entry(lease->hostname, prot, (struct all_addr *)&lease->addr, lease->expires);
492 #endif
495 dns_dirty = 0;
499 void lease_prune(struct dhcp_lease *target, time_t now)
501 struct dhcp_lease *lease, *tmp, **up;
503 for (lease = leases, up = &leases; lease; lease = tmp)
505 tmp = lease->next;
506 if ((lease->expires != 0 && difftime(now, lease->expires) > 0) || lease == target)
508 file_dirty = 1;
509 if (lease->hostname)
510 dns_dirty = 1;
512 *up = lease->next; /* unlink */
514 /* Put on old_leases list 'till we
515 can run the script */
516 lease->next = old_leases;
517 old_leases = lease;
519 leases_left++;
521 else
522 up = &lease->next;
527 struct dhcp_lease *lease_find_by_client(unsigned char *hwaddr, int hw_len, int hw_type,
528 unsigned char *clid, int clid_len)
530 struct dhcp_lease *lease;
532 if (clid)
533 for (lease = leases; lease; lease = lease->next)
535 #ifdef HAVE_DHCP6
536 if (lease->flags & (LEASE_TA | LEASE_NA))
537 continue;
538 #endif
539 if (lease->clid && clid_len == lease->clid_len &&
540 memcmp(clid, lease->clid, clid_len) == 0)
541 return lease;
544 for (lease = leases; lease; lease = lease->next)
546 #ifdef HAVE_DHCP6
547 if (lease->flags & (LEASE_TA | LEASE_NA))
548 continue;
549 #endif
550 if ((!lease->clid || !clid) &&
551 hw_len != 0 &&
552 lease->hwaddr_len == hw_len &&
553 lease->hwaddr_type == hw_type &&
554 memcmp(hwaddr, lease->hwaddr, hw_len) == 0)
555 return lease;
558 return NULL;
561 struct dhcp_lease *lease_find_by_addr(struct in_addr addr)
563 struct dhcp_lease *lease;
565 for (lease = leases; lease; lease = lease->next)
567 #ifdef HAVE_DHCP6
568 if (lease->flags & (LEASE_TA | LEASE_NA))
569 continue;
570 #endif
571 if (lease->addr.s_addr == addr.s_addr)
572 return lease;
575 return NULL;
578 #ifdef HAVE_DHCP6
579 /* find address for {CLID, IAID, address} */
580 struct dhcp_lease *lease6_find(unsigned char *clid, int clid_len,
581 int lease_type, int iaid, struct in6_addr *addr)
583 struct dhcp_lease *lease;
585 for (lease = leases; lease; lease = lease->next)
587 if (!(lease->flags & lease_type) || lease->iaid != iaid)
588 continue;
590 if (!IN6_ARE_ADDR_EQUAL(&lease->addr6, addr))
591 continue;
593 if ((clid_len != lease->clid_len ||
594 memcmp(clid, lease->clid, clid_len) != 0))
595 continue;
597 return lease;
600 return NULL;
603 /* reset "USED flags */
604 void lease6_reset(void)
606 struct dhcp_lease *lease;
608 for (lease = leases; lease; lease = lease->next)
609 lease->flags &= ~LEASE_USED;
612 /* enumerate all leases belonging to {CLID, IAID} */
613 struct dhcp_lease *lease6_find_by_client(struct dhcp_lease *first, int lease_type, unsigned char *clid, int clid_len, int iaid)
615 struct dhcp_lease *lease;
617 if (!first)
618 first = leases;
619 else
620 first = first->next;
622 for (lease = first; lease; lease = lease->next)
624 if (lease->flags & LEASE_USED)
625 continue;
627 if (!(lease->flags & lease_type) || lease->iaid != iaid)
628 continue;
630 if ((clid_len != lease->clid_len ||
631 memcmp(clid, lease->clid, clid_len) != 0))
632 continue;
634 return lease;
637 return NULL;
640 struct dhcp_lease *lease6_find_by_addr(struct in6_addr *net, int prefix, u64 addr)
642 struct dhcp_lease *lease;
644 for (lease = leases; lease; lease = lease->next)
646 if (!(lease->flags & (LEASE_TA | LEASE_NA)))
647 continue;
649 if (is_same_net6(&lease->addr6, net, prefix) &&
650 (prefix == 128 || addr6part(&lease->addr6) == addr))
651 return lease;
654 return NULL;
657 /* Find largest assigned address in context */
658 u64 lease_find_max_addr6(struct dhcp_context *context)
660 struct dhcp_lease *lease;
661 u64 addr = addr6part(&context->start6);
663 if (!(context->flags & (CONTEXT_STATIC | CONTEXT_PROXY)))
664 for (lease = leases; lease; lease = lease->next)
666 if (!(lease->flags & (LEASE_TA | LEASE_NA)))
667 continue;
669 if (is_same_net6(&lease->addr6, &context->start6, 64) &&
670 addr6part(&lease->addr6) > addr6part(&context->start6) &&
671 addr6part(&lease->addr6) <= addr6part(&context->end6) &&
672 addr6part(&lease->addr6) > addr)
673 addr = addr6part(&lease->addr6);
676 return addr;
679 #endif
681 /* Find largest assigned address in context */
682 struct in_addr lease_find_max_addr(struct dhcp_context *context)
684 struct dhcp_lease *lease;
685 struct in_addr addr = context->start;
687 if (!(context->flags & (CONTEXT_STATIC | CONTEXT_PROXY)))
688 for (lease = leases; lease; lease = lease->next)
690 #ifdef HAVE_DHCP6
691 if (lease->flags & (LEASE_TA | LEASE_NA))
692 continue;
693 #endif
694 if (((unsigned)ntohl(lease->addr.s_addr)) > ((unsigned)ntohl(context->start.s_addr)) &&
695 ((unsigned)ntohl(lease->addr.s_addr)) <= ((unsigned)ntohl(context->end.s_addr)) &&
696 ((unsigned)ntohl(lease->addr.s_addr)) > ((unsigned)ntohl(addr.s_addr)))
697 addr = lease->addr;
700 return addr;
703 static struct dhcp_lease *lease_allocate(void)
705 struct dhcp_lease *lease;
706 if (!leases_left || !(lease = whine_malloc(sizeof(struct dhcp_lease))))
707 return NULL;
709 memset(lease, 0, sizeof(struct dhcp_lease));
710 lease->flags = LEASE_NEW;
711 lease->expires = 1;
712 #ifdef HAVE_BROKEN_RTC
713 lease->length = 0xffffffff; /* illegal value */
714 #endif
715 lease->hwaddr_len = 256; /* illegal value */
716 lease->next = leases;
717 leases = lease;
719 file_dirty = 1;
720 leases_left--;
722 return lease;
725 struct dhcp_lease *lease4_allocate(struct in_addr addr)
727 struct dhcp_lease *lease = lease_allocate();
728 if (lease)
729 lease->addr = addr;
731 return lease;
734 #ifdef HAVE_DHCP6
735 struct dhcp_lease *lease6_allocate(struct in6_addr *addrp, int lease_type)
737 struct dhcp_lease *lease = lease_allocate();
739 if (lease)
741 lease->addr6 = *addrp;
742 lease->flags |= lease_type;
743 lease->iaid = 0;
746 return lease;
748 #endif
750 void lease_set_expires(struct dhcp_lease *lease, unsigned int len, time_t now)
752 time_t exp = now + (time_t)len;
754 if (len == 0xffffffff)
756 exp = 0;
757 len = 0;
760 if (exp != lease->expires)
762 dns_dirty = 1;
763 lease->expires = exp;
764 #ifndef HAVE_BROKEN_RTC
765 lease->flags |= LEASE_AUX_CHANGED;
766 file_dirty = 1;
767 #endif
770 #ifdef HAVE_BROKEN_RTC
771 if (len != lease->length)
773 lease->length = len;
774 lease->flags |= LEASE_AUX_CHANGED;
775 file_dirty = 1;
777 #endif
780 #ifdef HAVE_DHCP6
781 void lease_set_iaid(struct dhcp_lease *lease, int iaid)
783 if (lease->iaid != iaid)
785 lease->iaid = iaid;
786 lease->flags |= LEASE_CHANGED;
789 #endif
791 void lease_set_hwaddr(struct dhcp_lease *lease, unsigned char *hwaddr,
792 unsigned char *clid, int hw_len, int hw_type, int clid_len,
793 time_t now, int force)
795 #ifdef HAVE_DHCP6
796 int change = force;
797 lease->flags |= LEASE_HAVE_HWADDR;
798 #endif
800 (void)force;
801 (void)now;
803 if (hw_len != lease->hwaddr_len ||
804 hw_type != lease->hwaddr_type ||
805 (hw_len != 0 && memcmp(lease->hwaddr, hwaddr, hw_len) != 0))
807 if (hw_len != 0)
808 memcpy(lease->hwaddr, hwaddr, hw_len);
809 lease->hwaddr_len = hw_len;
810 lease->hwaddr_type = hw_type;
811 lease->flags |= LEASE_CHANGED;
812 file_dirty = 1; /* run script on change */
815 /* only update clid when one is available, stops packets
816 without a clid removing the record. Lease init uses
817 clid_len == 0 for no clid. */
818 if (clid_len != 0 && clid)
820 if (!lease->clid)
821 lease->clid_len = 0;
823 if (lease->clid_len != clid_len)
825 lease->flags |= LEASE_AUX_CHANGED;
826 file_dirty = 1;
827 free(lease->clid);
828 if (!(lease->clid = whine_malloc(clid_len)))
829 return;
830 #ifdef HAVE_DHCP6
831 change = 1;
832 #endif
834 else if (memcmp(lease->clid, clid, clid_len) != 0)
836 lease->flags |= LEASE_AUX_CHANGED;
837 file_dirty = 1;
838 #ifdef HAVE_DHCP6
839 change = 1;
840 #endif
843 lease->clid_len = clid_len;
844 memcpy(lease->clid, clid, clid_len);
847 #ifdef HAVE_DHCP6
848 if (change)
849 slaac_add_addrs(lease, now, force);
850 #endif
853 static void kill_name(struct dhcp_lease *lease)
855 /* run script to say we lost our old name */
857 /* this shouldn't happen unless updates are very quick and the
858 script very slow, we just avoid a memory leak if it does. */
859 free(lease->old_hostname);
861 /* If we know the fqdn, pass that. The helper will derive the
862 unqualified name from it, free the unqualified name here. */
864 if (lease->fqdn)
866 lease->old_hostname = lease->fqdn;
867 free(lease->hostname);
869 else
870 lease->old_hostname = lease->hostname;
872 lease->hostname = lease->fqdn = NULL;
875 void lease_set_hostname(struct dhcp_lease *lease, char *name, int auth, char *domain, char *config_domain)
877 struct dhcp_lease *lease_tmp;
878 char *new_name = NULL, *new_fqdn = NULL;
880 if (config_domain && (!domain || !hostname_isequal(domain, config_domain)))
881 my_syslog(MS_DHCP | LOG_WARNING, _("Ignoring domain %s for DHCP host name %s"), config_domain, name);
883 if (lease->hostname && name && hostname_isequal(lease->hostname, name))
885 if (auth)
886 lease->flags |= LEASE_AUTH_NAME;
887 return;
890 if (!name && !lease->hostname)
891 return;
893 /* If a machine turns up on a new net without dropping the old lease,
894 or two machines claim the same name, then we end up with two interfaces with
895 the same name. Check for that here and remove the name from the old lease.
896 Note that IPv6 leases are different. All the leases to the same DUID are
897 allowed the same name.
899 Don't allow a name from the client to override a name from dnsmasq config. */
901 if (name)
903 if ((new_name = whine_malloc(strlen(name) + 1)))
905 strcpy(new_name, name);
906 if (domain && (new_fqdn = whine_malloc(strlen(new_name) + strlen(domain) + 2)))
908 strcpy(new_fqdn, name);
909 strcat(new_fqdn, ".");
910 strcat(new_fqdn, domain);
914 /* Depending on mode, we check either unqualified name or FQDN. */
915 for (lease_tmp = leases; lease_tmp; lease_tmp = lease_tmp->next)
917 if (option_bool(OPT_DHCP_FQDN))
919 if (!new_fqdn || !lease_tmp->fqdn || !hostname_isequal(lease_tmp->fqdn, new_fqdn))
920 continue;
922 else
924 if (!new_name || !lease_tmp->hostname || !hostname_isequal(lease_tmp->hostname, new_name) )
925 continue;
928 if (lease->flags & (LEASE_TA | LEASE_NA))
930 if (!(lease_tmp->flags & (LEASE_TA | LEASE_NA)))
931 continue;
933 /* another lease for the same DUID is OK for IPv6 */
934 if (lease->clid_len == lease_tmp->clid_len &&
935 lease->clid && lease_tmp->clid &&
936 memcmp(lease->clid, lease_tmp->clid, lease->clid_len) == 0)
937 continue;
939 else if (lease_tmp->flags & (LEASE_TA | LEASE_NA))
940 continue;
942 if ((lease_tmp->flags & LEASE_AUTH_NAME) && !auth)
944 free(new_name);
945 free(new_fqdn);
946 return;
949 kill_name(lease_tmp);
950 break;
954 if (lease->hostname)
955 kill_name(lease);
957 lease->hostname = new_name;
958 lease->fqdn = new_fqdn;
960 if (auth)
961 lease->flags |= LEASE_AUTH_NAME;
963 file_dirty = 1;
964 dns_dirty = 1;
965 lease->flags |= LEASE_CHANGED; /* run script on change */
968 void lease_set_interface(struct dhcp_lease *lease, int interface, time_t now)
970 (void)now;
972 if (lease->last_interface == interface)
973 return;
975 lease->last_interface = interface;
976 lease->flags |= LEASE_CHANGED;
978 #ifdef HAVE_DHCP6
979 slaac_add_addrs(lease, now, 0);
980 #endif
983 void rerun_scripts(void)
985 struct dhcp_lease *lease;
987 for (lease = leases; lease; lease = lease->next)
988 lease->flags |= LEASE_CHANGED;
991 /* deleted leases get transferred to the old_leases list.
992 remove them here, after calling the lease change
993 script. Also run the lease change script on new/modified leases.
995 Return zero if nothing to do. */
996 int do_script_run(time_t now)
998 struct dhcp_lease *lease;
1000 (void)now;
1002 #ifdef HAVE_DBUS
1003 /* If we're going to be sending DBus signals, but the connection is not yet up,
1004 delay everything until it is. */
1005 if (option_bool(OPT_DBUS) && !daemon->dbus)
1006 return 0;
1007 #endif
1009 if (old_leases)
1011 lease = old_leases;
1013 /* If the lease still has an old_hostname, do the "old" action on that first */
1014 if (lease->old_hostname)
1016 #ifdef HAVE_SCRIPT
1017 queue_script(ACTION_OLD_HOSTNAME, lease, lease->old_hostname, now);
1018 #endif
1019 free(lease->old_hostname);
1020 lease->old_hostname = NULL;
1021 return 1;
1023 else
1025 #ifdef HAVE_DHCP6
1026 struct slaac_address *slaac, *tmp;
1027 for (slaac = lease->slaac_address; slaac; slaac = tmp)
1029 tmp = slaac->next;
1030 free(slaac);
1032 #endif
1033 kill_name(lease);
1034 #ifdef HAVE_SCRIPT
1035 queue_script(ACTION_DEL, lease, lease->old_hostname, now);
1036 #endif
1037 #ifdef HAVE_DBUS
1038 emit_dbus_signal(ACTION_DEL, lease, lease->old_hostname);
1039 #endif
1040 old_leases = lease->next;
1042 free(lease->old_hostname);
1043 free(lease->clid);
1044 free(lease->extradata);
1045 free(lease);
1047 return 1;
1051 /* make sure we announce the loss of a hostname before its new location. */
1052 for (lease = leases; lease; lease = lease->next)
1053 if (lease->old_hostname)
1055 #ifdef HAVE_SCRIPT
1056 queue_script(ACTION_OLD_HOSTNAME, lease, lease->old_hostname, now);
1057 #endif
1058 free(lease->old_hostname);
1059 lease->old_hostname = NULL;
1060 return 1;
1063 for (lease = leases; lease; lease = lease->next)
1064 if ((lease->flags & (LEASE_NEW | LEASE_CHANGED)) ||
1065 ((lease->flags & LEASE_AUX_CHANGED) && option_bool(OPT_LEASE_RO)))
1067 #ifdef HAVE_SCRIPT
1068 queue_script((lease->flags & LEASE_NEW) ? ACTION_ADD : ACTION_OLD, lease,
1069 lease->fqdn ? lease->fqdn : lease->hostname, now);
1070 #endif
1071 #ifdef HAVE_DBUS
1072 emit_dbus_signal((lease->flags & LEASE_NEW) ? ACTION_ADD : ACTION_OLD, lease,
1073 lease->fqdn ? lease->fqdn : lease->hostname);
1074 #endif
1075 lease->flags &= ~(LEASE_NEW | LEASE_CHANGED | LEASE_AUX_CHANGED);
1077 /* this is used for the "add" call, then junked, since they're not in the database */
1078 free(lease->extradata);
1079 lease->extradata = NULL;
1081 return 1;
1084 return 0; /* nothing to do */
1087 #ifdef HAVE_SCRIPT
1088 void lease_add_extradata(struct dhcp_lease *lease, unsigned char *data, unsigned int len, int delim)
1090 unsigned int i;
1092 /* check for embeded NULLs */
1093 for (i = 0; i < len; i++)
1094 if (data[i] == 0)
1096 len = i;
1097 break;
1100 if ((lease->extradata_size - lease->extradata_len) < (len + 1))
1102 size_t newsz = lease->extradata_len + len + 100;
1103 unsigned char *new = whine_malloc(newsz);
1105 if (!new)
1106 return;
1108 if (lease->extradata)
1110 memcpy(new, lease->extradata, lease->extradata_len);
1111 free(lease->extradata);
1114 lease->extradata = new;
1115 lease->extradata_size = newsz;
1118 if (len != 0)
1119 memcpy(lease->extradata + lease->extradata_len, data, len);
1120 lease->extradata[lease->extradata_len + len] = delim;
1121 lease->extradata_len += len + 1;
1123 #endif
1125 #ifdef HAVE_TOMATO
1127 void tomato_helper(time_t now)
1129 FILE *f;
1130 struct in_addr ia;
1131 char buf[64];
1132 struct dhcp_lease *lease;
1134 // if delete exists...
1135 if ((f = fopen("/var/tmp/dhcp/delete", "r")) != NULL) {
1136 while (fgets(buf, sizeof(buf), f)) {
1137 ia.s_addr = inet_addr(buf);
1138 lease = lease_find_by_addr(ia);
1139 if (lease) {
1140 lease_prune(lease, 0);
1141 lease_update_file(now);
1144 fclose(f);
1145 unlink("/var/tmp/dhcp/delete");
1148 // dump the leases file
1149 if ((f = fopen("/var/tmp/dhcp/leases.!", "w")) != NULL) {
1150 for (lease = leases; lease; lease = lease->next) {
1151 if (lease->hwaddr_type == ARPHRD_ETHER) {
1152 fprintf(f, "%lu %02X:%02X:%02X:%02X:%02X:%02X %s %s\n",
1153 lease->expires - now,
1154 lease->hwaddr[0], lease->hwaddr[1], lease->hwaddr[2], lease->hwaddr[3], lease->hwaddr[4], lease->hwaddr[5],
1155 inet_ntoa(lease->addr),
1156 ((lease->hostname) && (strlen(lease->hostname) > 0)) ? lease->hostname : "*");
1159 fclose(f);
1160 rename("/var/tmp/dhcp/leases.!", "/var/tmp/dhcp/leases");
1163 #endif //HAVE_TOMATO
1165 #ifdef HAVE_LEASEFILE_EXPIRE
1166 void flush_lease_file(time_t now)
1168 static time_t flush_time = (time_t)0;
1170 if(difftime(flush_time, now) < 0)
1171 file_dirty = 1;
1173 lease_prune(NULL, now);
1174 lease_update_file(now);
1176 if (file_dirty == 0)
1177 flush_time = now;
1179 #endif //HAVE_LEASEFILE_EXPIRE
1181 #endif