Changes to update Tomato RAF.
[tomato.git] / release / src / router / dnsmasq / src / lease.c
blobbb641ea5358fba6117247979f0326dc0e4191071
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;
112 if (s[0] == 'T')
114 lease_type = LEASE_TA;
115 s++;
118 hw_type = strtoul(s, NULL, 10);
120 if ((lease = lease6_allocate(&addr.addr.addr6, lease_type)))
122 lease_set_hwaddr(lease, NULL, (unsigned char *)daemon->packet, 0, hw_type, clid_len, now, 0);
124 if (strcmp(daemon->dhcp_buff, "*") != 0)
125 lease_set_hostname(lease, daemon->dhcp_buff, 0, get_domain6((struct in6_addr *)lease->hwaddr), NULL);
128 #endif
129 else
130 break;
132 if (!lease)
133 die (_("too many stored leases"), NULL, EC_MISC);
135 //Some ASUS & TOMATO tweaks
136 #if defined(HAVE_BROKEN_RTC) || defined(HAVE_LEASEFILE_EXPIRE)
137 if (ei != 0)
138 lease->expires = (time_t)ei + now;
139 else
140 lease->expires = (time_t)0;
141 #ifdef HAVE_BROKEN_RT
142 lease->length = ei;
143 #endif
144 #else
145 /* strictly time_t is opaque, but this hack should work on all sane
146 systems, even when sizeof(time_t) == 8 */
147 lease->expires = (time_t)ei;
148 #endif
150 /* set these correctly: the "old" events are generated later from
151 the startup synthesised SIGHUP. */
152 lease->flags &= ~(LEASE_NEW | LEASE_CHANGED);
155 #ifdef HAVE_SCRIPT
156 if (!daemon->lease_stream)
158 int rc = 0;
160 /* shell returns 127 for "command not found", 126 for bad permissions. */
161 if (!leasestream || (rc = pclose(leasestream)) == -1 || WEXITSTATUS(rc) == 127 || WEXITSTATUS(rc) == 126)
163 if (WEXITSTATUS(rc) == 127)
164 errno = ENOENT;
165 else if (WEXITSTATUS(rc) == 126)
166 errno = EACCES;
167 die(_("cannot run lease-init script %s: %s"), daemon->lease_change_command, EC_FILE);
170 if (WEXITSTATUS(rc) != 0)
172 sprintf(daemon->dhcp_buff, "%d", WEXITSTATUS(rc));
173 die(_("lease-init script returned exit code %s"), daemon->dhcp_buff, WEXITSTATUS(rc) + EC_INIT_OFFSET);
176 #endif
178 /* Some leases may have expired */
179 file_dirty = 0;
180 lease_prune(NULL, now);
181 dns_dirty = 1;
184 void lease_update_from_configs(void)
186 /* changes to the config may change current leases. */
188 struct dhcp_lease *lease;
189 struct dhcp_config *config;
190 char *name;
192 for (lease = leases; lease; lease = lease->next)
193 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 #ifdef HAVE_BROKEN_RTC
237 (lease->length == 0) ? 0 :
238 #else
239 (lease->expires == 0) ? 0 :
240 #endif
241 (unsigned int)difftime(lease->expires, now));
242 #elif defined(HAVE_BROKEN_RTC)
243 ourprintf(&err, "%u ", lease->length);
244 else
245 ourprintf(&err, "%lu ", (unsigned long)lease->expires);
246 #endif
248 if (lease->hwaddr_type != ARPHRD_ETHER || lease->hwaddr_len == 0)
249 ourprintf(&err, "%.2x-", lease->hwaddr_type);
250 for (i = 0; i < lease->hwaddr_len; i++)
252 ourprintf(&err, "%.2x", lease->hwaddr[i]);
253 if (i != lease->hwaddr_len - 1)
254 ourprintf(&err, ":");
257 inet_ntop(AF_INET, &lease->addr, daemon->addrbuff, ADDRSTRLEN);
259 ourprintf(&err, " %s ", daemon->addrbuff);
260 ourprintf(&err, "%s ", lease->hostname ? lease->hostname : "*");
262 if (lease->clid && lease->clid_len != 0)
264 for (i = 0; i < lease->clid_len - 1; i++)
265 ourprintf(&err, "%.2x:", lease->clid[i]);
266 ourprintf(&err, "%.2x\n", lease->clid[i]);
268 else
269 ourprintf(&err, "*\n");
272 #ifdef HAVE_DHCP6
273 if (daemon->duid)
275 ourprintf(&err, "duid ");
276 for (i = 0; i < daemon->duid_len - 1; i++)
277 ourprintf(&err, "%.2x:", daemon->duid[i]);
278 ourprintf(&err, "%.2x\n", daemon->duid[i]);
280 for (lease = leases; lease; lease = lease->next)
283 if (!(lease->flags & (LEASE_TA | LEASE_NA)))
284 continue;
286 //ASUS and TOMATO tweaks to output remaining leasetime
287 #ifdef HAVE_LEASEFILE_EXPIRE
288 ourprintf(&err, "%u ",
289 #ifdef HAVE_BROKEN_RTC
290 (lease->length == 0) ? 0 :
291 #else
292 (lease->expires == 0) ? 0 :
293 #endif
294 (unsigned int)difftime(lease->expires, now));
295 #elif defined(HAVE_BROKEN_RTC)
296 ourprintf(&err, "%u ", lease->length);
297 else
298 ourprintf(&err, "%lu ", (unsigned long)lease->expires);
299 #endif
301 inet_ntop(AF_INET6, lease->hwaddr, daemon->addrbuff, ADDRSTRLEN);
303 ourprintf(&err, "%s%u %s ", (lease->flags & LEASE_TA) ? "T" : "",
304 lease->hwaddr_type, daemon->addrbuff);
305 ourprintf(&err, "%s ", lease->hostname ? lease->hostname : "*");
307 if (lease->clid && lease->clid_len != 0)
309 for (i = 0; i < lease->clid_len - 1; i++)
310 ourprintf(&err, "%.2x:", lease->clid[i]);
311 ourprintf(&err, "%.2x\n", lease->clid[i]);
313 else
314 ourprintf(&err, "*\n");
317 #endif
319 if (fflush(daemon->lease_stream) != 0 ||
320 fsync(fileno(daemon->lease_stream)) < 0)
321 err = errno;
323 if (!err)
324 file_dirty = 0;
327 /* Set alarm for when the first lease expires + slop. */
328 next_event = 0;
330 #ifdef HAVE_DHCP6
331 /* do timed RAs and determine when the next is, also pings to potential SLAAC addresses */
332 if (daemon->doing_ra)
334 time_t event;
336 if ((event = periodic_slaac(now, leases)) != 0)
338 if (next_event == 0 || difftime(next_event, event) > 0.0)
339 next_event = event;
342 if ((event = periodic_ra(now)) != 0)
344 if (next_event == 0 || difftime(next_event, event) > 0.0)
345 next_event = event;
348 #endif
350 for (lease = leases; lease; lease = lease->next)
351 if (lease->expires != 0 &&
352 (next_event == 0 || difftime(next_event, lease->expires + 10) > 0.0))
353 next_event = lease->expires + 10;
355 if (err)
357 if (next_event == 0 || difftime(next_event, LEASE_RETRY + now) > 0.0)
358 next_event = LEASE_RETRY + now;
360 my_syslog(MS_DHCP | LOG_ERR, _("failed to write %s: %s (retry in %us)"),
361 daemon->lease_file, strerror(err),
362 (unsigned int)difftime(next_event, now));
365 send_alarm(next_event, now);
369 static int find_interface_v4(struct in_addr local, int if_index, char *label,
370 struct in_addr netmask, struct in_addr broadcast, void *vparam)
372 struct dhcp_lease *lease;
374 (void) label;
375 (void) broadcast;
376 (void) vparam;
378 for (lease = leases; lease; lease = lease->next)
379 if (!(lease->flags & (LEASE_TA | LEASE_NA)))
380 if (is_same_net(local, lease->addr, netmask))
381 lease_set_interface(lease, if_index, *((time_t *)vparam));
383 return 1;
386 #ifdef HAVE_DHCP6
387 static int find_interface_v6(struct in6_addr *local, int prefix,
388 int scope, int if_index, int flags,
389 int preferred, int valid, void *vparam)
391 struct dhcp_lease *lease;
393 (void)scope;
394 (void)flags;
395 (void)preferred;
396 (void)valid;
398 for (lease = leases; lease; lease = lease->next)
399 if ((lease->flags & (LEASE_TA | LEASE_NA)))
400 if (is_same_net6(local, (struct in6_addr *)&lease->hwaddr, prefix))
401 lease_set_interface(lease, if_index, *((time_t *)vparam));
403 return 1;
406 void lease_ping_reply(struct in6_addr *sender, unsigned char *packet, char *interface)
408 /* We may be doing RA but not DHCPv4, in which case the lease
409 database may not exist and we have nothing to do anyway */
410 if (daemon->dhcp)
411 slaac_ping_reply(sender, packet, interface, leases);
414 void lease_update_slaac(time_t now)
416 /* Called when we contruct a new RA-names context, to add putative
417 new SLAAC addresses to existing leases. */
419 struct dhcp_lease *lease;
421 if (daemon->dhcp)
422 for (lease = leases; lease; lease = lease->next)
423 slaac_add_addrs(lease, now, 0);
426 #endif
429 /* Find interfaces associated with leases at start-up. This gets updated as
430 we do DHCP transactions, but information about directly-connected subnets
431 is useful from scrips and necessary for determining SLAAC addresses from
432 start-time. */
433 void lease_find_interfaces(time_t now)
435 iface_enumerate(AF_INET, &now, find_interface_v4);
436 #ifdef HAVE_DHCP6
437 iface_enumerate(AF_INET6, &now, find_interface_v6);
439 /* If we're not doing DHCPv6, and there are not v6 leases, don't add the DUID to the database */
440 if (!daemon->duid && daemon->dhcp6)
442 file_dirty = 1;
443 make_duid(now);
445 #endif
450 void lease_update_dns(int force)
452 struct dhcp_lease *lease;
454 if (daemon->port != 0 && (dns_dirty || force))
456 #ifndef HAVE_BROKEN_RTC
457 /* force transfer to authoritative secondaries */
458 daemon->soa_sn++;
459 #endif
461 cache_unhash_dhcp();
463 for (lease = leases; lease; lease = lease->next)
465 int prot = AF_INET;
467 #ifdef HAVE_DHCP6
468 if (lease->flags & (LEASE_TA | LEASE_NA))
469 prot = AF_INET6;
470 else if (lease->hostname || lease->fqdn)
472 struct slaac_address *slaac;
474 for (slaac = lease->slaac_address; slaac; slaac = slaac->next)
475 if (slaac->backoff == 0)
477 if (lease->fqdn)
478 cache_add_dhcp_entry(lease->fqdn, AF_INET6, (struct all_addr *)&slaac->addr, lease->expires);
479 if (!option_bool(OPT_DHCP_FQDN) && lease->hostname)
480 cache_add_dhcp_entry(lease->hostname, AF_INET6, (struct all_addr *)&slaac->addr, lease->expires);
483 #endif
485 if (lease->fqdn)
486 cache_add_dhcp_entry(lease->fqdn, prot,
487 prot == AF_INET ? (struct all_addr *)&lease->addr : (struct all_addr *)&lease->hwaddr,
488 lease->expires);
490 if (!option_bool(OPT_DHCP_FQDN) && lease->hostname)
491 cache_add_dhcp_entry(lease->hostname, prot,
492 prot == AF_INET ? (struct all_addr *)&lease->addr : (struct all_addr *)&lease->hwaddr,
493 lease->expires);
496 dns_dirty = 0;
500 void lease_prune(struct dhcp_lease *target, time_t now)
502 struct dhcp_lease *lease, *tmp, **up;
504 for (lease = leases, up = &leases; lease; lease = tmp)
506 tmp = lease->next;
507 if ((lease->expires != 0 && difftime(now, lease->expires) > 0) || lease == target)
509 file_dirty = 1;
510 if (lease->hostname)
511 dns_dirty = 1;
513 *up = lease->next; /* unlink */
515 /* Put on old_leases list 'till we
516 can run the script */
517 lease->next = old_leases;
518 old_leases = lease;
520 leases_left++;
522 else
523 up = &lease->next;
528 struct dhcp_lease *lease_find_by_client(unsigned char *hwaddr, int hw_len, int hw_type,
529 unsigned char *clid, int clid_len)
531 struct dhcp_lease *lease;
533 if (clid)
534 for (lease = leases; lease; lease = lease->next)
536 #ifdef HAVE_DHCP6
537 if (lease->flags & (LEASE_TA | LEASE_NA))
538 continue;
539 #endif
540 if (lease->clid && clid_len == lease->clid_len &&
541 memcmp(clid, lease->clid, clid_len) == 0)
542 return lease;
545 for (lease = leases; lease; lease = lease->next)
547 #ifdef HAVE_DHCP6
548 if (lease->flags & (LEASE_TA | LEASE_NA))
549 continue;
550 #endif
551 if ((!lease->clid || !clid) &&
552 hw_len != 0 &&
553 lease->hwaddr_len == hw_len &&
554 lease->hwaddr_type == hw_type &&
555 memcmp(hwaddr, lease->hwaddr, hw_len) == 0)
556 return lease;
559 return NULL;
562 struct dhcp_lease *lease_find_by_addr(struct in_addr addr)
564 struct dhcp_lease *lease;
566 for (lease = leases; lease; lease = lease->next)
568 #ifdef HAVE_DHCP6
569 if (lease->flags & (LEASE_TA | LEASE_NA))
570 continue;
571 #endif
572 if (lease->addr.s_addr == addr.s_addr)
573 return lease;
576 return NULL;
579 #ifdef HAVE_DHCP6
580 /* find address for {CLID, IAID, address} */
581 struct dhcp_lease *lease6_find(unsigned char *clid, int clid_len,
582 int lease_type, int iaid, struct in6_addr *addr)
584 struct dhcp_lease *lease;
586 for (lease = leases; lease; lease = lease->next)
588 if (!(lease->flags & lease_type) || lease->hwaddr_type != iaid)
589 continue;
591 if (memcmp(lease->hwaddr, addr, IN6ADDRSZ) != 0)
592 continue;
594 if ((clid_len != lease->clid_len ||
595 memcmp(clid, lease->clid, clid_len) != 0))
596 continue;
598 return lease;
601 return NULL;
604 /* reset "USED flags */
605 void lease6_reset(void)
607 struct dhcp_lease *lease;
609 for (lease = leases; lease; lease = lease->next)
610 lease->flags &= ~LEASE_USED;
613 /* enumerate all leases belonging to {CLID, IAID} */
614 struct dhcp_lease *lease6_find_by_client(struct dhcp_lease *first, int lease_type, unsigned char *clid, int clid_len, int iaid)
616 struct dhcp_lease *lease;
618 if (!first)
619 first = leases;
620 else
621 first = first->next;
623 for (lease = first; lease; lease = lease->next)
625 if (lease->flags & LEASE_USED)
626 continue;
628 if (!(lease->flags & lease_type) || lease->hwaddr_type != iaid)
629 continue;
631 if ((clid_len != lease->clid_len ||
632 memcmp(clid, lease->clid, clid_len) != 0))
633 continue;
635 return lease;
638 return NULL;
641 struct dhcp_lease *lease6_find_by_addr(struct in6_addr *net, int prefix, u64 addr)
643 struct dhcp_lease *lease;
645 for (lease = leases; lease; lease = lease->next)
647 if (!(lease->flags & (LEASE_TA | LEASE_NA)))
648 continue;
650 if (is_same_net6((struct in6_addr *)lease->hwaddr, net, prefix) &&
651 (prefix == 128 || addr6part((struct in6_addr *)lease->hwaddr) == addr))
652 return lease;
655 return NULL;
658 /* Find largest assigned address in context */
659 u64 lease_find_max_addr6(struct dhcp_context *context)
661 struct dhcp_lease *lease;
662 u64 addr = addr6part(&context->start6);
664 if (!(context->flags & (CONTEXT_STATIC | CONTEXT_PROXY)))
665 for (lease = leases; lease; lease = lease->next)
667 if (!(lease->flags & (LEASE_TA | LEASE_NA)))
668 continue;
670 if (is_same_net6((struct in6_addr *)lease->hwaddr, &context->start6, 64) &&
671 addr6part((struct in6_addr *)lease->hwaddr) > addr6part(&context->start6) &&
672 addr6part((struct in6_addr *)lease->hwaddr) <= addr6part(&context->end6) &&
673 addr6part((struct in6_addr *)lease->hwaddr) > addr)
674 addr = addr6part((struct in6_addr *)lease->hwaddr);
677 return addr;
680 #endif
682 /* Find largest assigned address in context */
683 struct in_addr lease_find_max_addr(struct dhcp_context *context)
685 struct dhcp_lease *lease;
686 struct in_addr addr = context->start;
688 if (!(context->flags & (CONTEXT_STATIC | CONTEXT_PROXY)))
689 for (lease = leases; lease; lease = lease->next)
691 #ifdef HAVE_DHCP6
692 if (lease->flags & (LEASE_TA | LEASE_NA))
693 continue;
694 #endif
695 if (((unsigned)ntohl(lease->addr.s_addr)) > ((unsigned)ntohl(context->start.s_addr)) &&
696 ((unsigned)ntohl(lease->addr.s_addr)) <= ((unsigned)ntohl(context->end.s_addr)) &&
697 ((unsigned)ntohl(lease->addr.s_addr)) > ((unsigned)ntohl(addr.s_addr)))
698 addr = lease->addr;
701 return addr;
704 static struct dhcp_lease *lease_allocate(void)
706 struct dhcp_lease *lease;
707 if (!leases_left || !(lease = whine_malloc(sizeof(struct dhcp_lease))))
708 return NULL;
710 memset(lease, 0, sizeof(struct dhcp_lease));
711 lease->flags = LEASE_NEW;
712 lease->expires = 1;
713 #ifdef HAVE_BROKEN_RTC
714 lease->length = 0xffffffff; /* illegal value */
715 #endif
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)
730 lease->addr = addr;
731 lease->hwaddr_len = 256; /* illegal value */
734 return lease;
737 #ifdef HAVE_DHCP6
738 struct dhcp_lease *lease6_allocate(struct in6_addr *addrp, int lease_type)
740 struct dhcp_lease *lease = lease_allocate();
742 if (lease)
744 memcpy(lease->hwaddr, addrp, sizeof(*addrp)) ;
745 lease->flags |= lease_type;
748 return lease;
750 #endif
752 void lease_set_expires(struct dhcp_lease *lease, unsigned int len, time_t now)
754 time_t exp = now + (time_t)len;
756 if (len == 0xffffffff)
758 exp = 0;
759 len = 0;
762 if (exp != lease->expires)
764 dns_dirty = 1;
765 lease->expires = exp;
766 #ifndef HAVE_BROKEN_RTC
767 lease->flags |= LEASE_AUX_CHANGED;
768 file_dirty = 1;
769 #endif
772 #ifdef HAVE_BROKEN_RTC
773 if (len != lease->length)
775 lease->length = len;
776 lease->flags |= LEASE_AUX_CHANGED;
777 file_dirty = 1;
779 #endif
782 void lease_set_hwaddr(struct dhcp_lease *lease, unsigned char *hwaddr,
783 unsigned char *clid, int hw_len, int hw_type, int clid_len,
784 time_t now, int force)
786 #ifdef HAVE_DHCP6
787 int change = force;
788 lease->flags |= LEASE_HAVE_HWADDR;
789 #endif
791 (void)force;
793 if (hw_len != lease->hwaddr_len ||
794 hw_type != lease->hwaddr_type ||
795 (hw_len != 0 && memcmp(lease->hwaddr, hwaddr, hw_len) != 0))
797 if (hw_len != 0)
798 memcpy(lease->hwaddr, hwaddr, hw_len);
799 lease->hwaddr_len = hw_len;
800 lease->hwaddr_type = hw_type;
801 lease->flags |= LEASE_CHANGED;
802 file_dirty = 1; /* run script on change */
803 #ifdef HAVE_DHCP6
804 change = 1;
805 #endif
808 /* only update clid when one is available, stops packets
809 without a clid removing the record. Lease init uses
810 clid_len == 0 for no clid. */
811 if (clid_len != 0 && clid)
813 if (!lease->clid)
814 lease->clid_len = 0;
816 if (lease->clid_len != clid_len)
818 lease->flags |= LEASE_AUX_CHANGED;
819 file_dirty = 1;
820 free(lease->clid);
821 if (!(lease->clid = whine_malloc(clid_len)))
822 return;
823 #ifdef HAVE_DHCP6
824 change = 1;
825 #endif
827 else if (memcmp(lease->clid, clid, clid_len) != 0)
829 lease->flags |= LEASE_AUX_CHANGED;
830 file_dirty = 1;
831 #ifdef HAVE_DHCP6
832 change = 1;
833 #endif
836 lease->clid_len = clid_len;
837 memcpy(lease->clid, clid, clid_len);
840 #ifdef HAVE_DHCP6
841 if (change)
842 slaac_add_addrs(lease, now, force);
843 #endif
846 static void kill_name(struct dhcp_lease *lease)
848 /* run script to say we lost our old name */
850 /* this shouldn't happen unless updates are very quick and the
851 script very slow, we just avoid a memory leak if it does. */
852 free(lease->old_hostname);
854 /* If we know the fqdn, pass that. The helper will derive the
855 unqualified name from it, free the unqualified name here. */
857 if (lease->fqdn)
859 lease->old_hostname = lease->fqdn;
860 free(lease->hostname);
862 else
863 lease->old_hostname = lease->hostname;
865 lease->hostname = lease->fqdn = NULL;
868 void lease_set_hostname(struct dhcp_lease *lease, char *name, int auth, char *domain, char *config_domain)
870 struct dhcp_lease *lease_tmp;
871 char *new_name = NULL, *new_fqdn = NULL;
873 if (config_domain && (!domain || !hostname_isequal(domain, config_domain)))
874 my_syslog(MS_DHCP | LOG_WARNING, _("Ignoring domain %s for DHCP host name %s"), config_domain, name);
876 if (lease->hostname && name && hostname_isequal(lease->hostname, name))
878 if (auth)
879 lease->flags |= LEASE_AUTH_NAME;
880 return;
883 if (!name && !lease->hostname)
884 return;
886 /* If a machine turns up on a new net without dropping the old lease,
887 or two machines claim the same name, then we end up with two interfaces with
888 the same name. Check for that here and remove the name from the old lease.
889 Note that IPv6 leases are different. All the leases to the same DUID are
890 allowed the same name.
892 Don't allow a name from the client to override a name from dnsmasq config. */
894 if (name)
896 if ((new_name = whine_malloc(strlen(name) + 1)))
898 strcpy(new_name, name);
899 if (domain && (new_fqdn = whine_malloc(strlen(new_name) + strlen(domain) + 2)))
901 strcpy(new_fqdn, name);
902 strcat(new_fqdn, ".");
903 strcat(new_fqdn, domain);
907 /* Depending on mode, we check either unqualified name or FQDN. */
908 for (lease_tmp = leases; lease_tmp; lease_tmp = lease_tmp->next)
910 if (option_bool(OPT_DHCP_FQDN))
912 if (!new_fqdn || !lease_tmp->fqdn || !hostname_isequal(lease_tmp->fqdn, new_fqdn))
913 continue;
915 else
917 if (!new_name || !lease_tmp->hostname || !hostname_isequal(lease_tmp->hostname, new_name) )
918 continue;
921 if (lease->flags & (LEASE_TA | LEASE_NA))
923 if (!(lease_tmp->flags & (LEASE_TA | LEASE_NA)))
924 continue;
926 /* another lease for the same DUID is OK for IPv6 */
927 if (lease->clid_len == lease_tmp->clid_len &&
928 lease->clid && lease_tmp->clid &&
929 memcmp(lease->clid, lease_tmp->clid, lease->clid_len) == 0)
930 continue;
932 else if (lease_tmp->flags & (LEASE_TA | LEASE_NA))
933 continue;
935 if ((lease_tmp->flags & LEASE_AUTH_NAME) && !auth)
937 free(new_name);
938 free(new_fqdn);
939 return;
942 kill_name(lease_tmp);
943 break;
947 if (lease->hostname)
948 kill_name(lease);
950 lease->hostname = new_name;
951 lease->fqdn = new_fqdn;
953 if (auth)
954 lease->flags |= LEASE_AUTH_NAME;
956 file_dirty = 1;
957 dns_dirty = 1;
958 lease->flags |= LEASE_CHANGED; /* run script on change */
961 void lease_set_interface(struct dhcp_lease *lease, int interface, time_t now)
963 if (lease->last_interface == interface)
964 return;
966 lease->last_interface = interface;
967 lease->flags |= LEASE_CHANGED;
969 #ifdef HAVE_DHCP6
970 slaac_add_addrs(lease, now, 0);
971 #endif
974 void rerun_scripts(void)
976 struct dhcp_lease *lease;
978 for (lease = leases; lease; lease = lease->next)
979 lease->flags |= LEASE_CHANGED;
982 /* deleted leases get transferred to the old_leases list.
983 remove them here, after calling the lease change
984 script. Also run the lease change script on new/modified leases.
986 Return zero if nothing to do. */
987 int do_script_run(time_t now)
989 struct dhcp_lease *lease;
991 #ifdef HAVE_DBUS
992 /* If we're going to be sending DBus signals, but the connection is not yet up,
993 delay everything until it is. */
994 if (option_bool(OPT_DBUS) && !daemon->dbus)
995 return 0;
996 #endif
998 if (old_leases)
1000 lease = old_leases;
1002 /* If the lease still has an old_hostname, do the "old" action on that first */
1003 if (lease->old_hostname)
1005 #ifdef HAVE_SCRIPT
1006 queue_script(ACTION_OLD_HOSTNAME, lease, lease->old_hostname, now);
1007 #endif
1008 free(lease->old_hostname);
1009 lease->old_hostname = NULL;
1010 return 1;
1012 else
1014 #ifdef HAVE_DHCP6
1015 struct slaac_address *slaac, *tmp;
1016 for (slaac = lease->slaac_address; slaac; slaac = tmp)
1018 tmp = slaac->next;
1019 free(slaac);
1021 #endif
1022 kill_name(lease);
1023 #ifdef HAVE_SCRIPT
1024 queue_script(ACTION_DEL, lease, lease->old_hostname, now);
1025 #endif
1026 #ifdef HAVE_DBUS
1027 emit_dbus_signal(ACTION_DEL, lease, lease->old_hostname);
1028 #endif
1029 old_leases = lease->next;
1031 free(lease->old_hostname);
1032 free(lease->clid);
1033 free(lease->extradata);
1034 free(lease);
1036 return 1;
1040 /* make sure we announce the loss of a hostname before its new location. */
1041 for (lease = leases; lease; lease = lease->next)
1042 if (lease->old_hostname)
1044 #ifdef HAVE_SCRIPT
1045 queue_script(ACTION_OLD_HOSTNAME, lease, lease->old_hostname, now);
1046 #endif
1047 free(lease->old_hostname);
1048 lease->old_hostname = NULL;
1049 return 1;
1052 for (lease = leases; lease; lease = lease->next)
1053 if ((lease->flags & (LEASE_NEW | LEASE_CHANGED)) ||
1054 ((lease->flags & LEASE_AUX_CHANGED) && option_bool(OPT_LEASE_RO)))
1056 #ifdef HAVE_SCRIPT
1057 queue_script((lease->flags & LEASE_NEW) ? ACTION_ADD : ACTION_OLD, lease,
1058 lease->fqdn ? lease->fqdn : lease->hostname, now);
1059 #endif
1060 #ifdef HAVE_DBUS
1061 emit_dbus_signal((lease->flags & LEASE_NEW) ? ACTION_ADD : ACTION_OLD, lease,
1062 lease->fqdn ? lease->fqdn : lease->hostname);
1063 #endif
1064 lease->flags &= ~(LEASE_NEW | LEASE_CHANGED | LEASE_AUX_CHANGED);
1066 /* this is used for the "add" call, then junked, since they're not in the database */
1067 free(lease->extradata);
1068 lease->extradata = NULL;
1070 return 1;
1073 return 0; /* nothing to do */
1076 #ifdef HAVE_SCRIPT
1077 void lease_add_extradata(struct dhcp_lease *lease, unsigned char *data, unsigned int len, int delim)
1079 unsigned int i;
1081 /* check for embeded NULLs */
1082 for (i = 0; i < len; i++)
1083 if (data[i] == 0)
1085 len = i;
1086 break;
1089 if ((lease->extradata_size - lease->extradata_len) < (len + 1))
1091 size_t newsz = lease->extradata_len + len + 100;
1092 unsigned char *new = whine_malloc(newsz);
1094 if (!new)
1095 return;
1097 if (lease->extradata)
1099 memcpy(new, lease->extradata, lease->extradata_len);
1100 free(lease->extradata);
1103 lease->extradata = new;
1104 lease->extradata_size = newsz;
1107 if (len != 0)
1108 memcpy(lease->extradata + lease->extradata_len, data, len);
1109 lease->extradata[lease->extradata_len + len] = delim;
1110 lease->extradata_len += len + 1;
1112 #endif
1114 #ifdef HAVE_TOMATO
1116 void tomato_helper(time_t now)
1118 FILE *f;
1119 struct in_addr ia;
1120 char buf[64];
1121 struct dhcp_lease *lease;
1123 // if delete exists...
1124 if ((f = fopen("/var/tmp/dhcp/delete", "r")) != NULL) {
1125 while (fgets(buf, sizeof(buf), f)) {
1126 ia.s_addr = inet_addr(buf);
1127 lease = lease_find_by_addr(ia);
1128 if (lease) {
1129 lease_prune(lease, 0);
1130 lease_update_file(now);
1133 fclose(f);
1134 unlink("/var/tmp/dhcp/delete");
1137 // dump the leases file
1138 if ((f = fopen("/var/tmp/dhcp/leases.!", "w")) != NULL) {
1139 for (lease = leases; lease; lease = lease->next) {
1140 if (lease->hwaddr_type == ARPHRD_ETHER) {
1141 fprintf(f, "%lu %02X:%02X:%02X:%02X:%02X:%02X %s %s\n",
1142 lease->expires - now,
1143 lease->hwaddr[0], lease->hwaddr[1], lease->hwaddr[2], lease->hwaddr[3], lease->hwaddr[4], lease->hwaddr[5],
1144 inet_ntoa(lease->addr),
1145 ((lease->hostname) && (strlen(lease->hostname) > 0)) ? lease->hostname : "*");
1148 fclose(f);
1149 rename("/var/tmp/dhcp/leases.!", "/var/tmp/dhcp/leases");
1152 #endif //HAVE_TOMATO
1154 #ifdef HAVE_LEASEFILE_EXPIRE
1155 void flush_lease_file(time_t now)
1157 static time_t flush_time = (time_t)0;
1159 if(difftime(flush_time, now) < 0)
1160 file_dirty = 1;
1162 lease_prune(NULL, now);
1163 lease_update_file(now);
1165 if (file_dirty == 0)
1166 flush_time = now;
1168 #endif //HAVE_LEASEFILE_EXPIRE
1170 #endif