dnsmasq 2.72+ up to December 9 2014
[tomato.git] / release / src / router / dnsmasq / src / lease.c
blob9fc4cbf36df5287d82b6fa155040fbe37d04af7c
1 /* dnsmasq is Copyright (c) 2000-2014 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 //Some ASUS & TOMATO tweaks
137 #if defined(HAVE_BROKEN_RTC) || defined(HAVE_LEASEFILE_EXPIRE)
138 if (ei != 0)
139 lease->expires = (time_t)ei + now;
140 else
141 lease->expires = (time_t)0;
142 #ifdef HAVE_BROKEN_RTC
143 lease->length = ei;
144 #endif
145 #else
146 /* strictly time_t is opaque, but this hack should work on all sane
147 systems, even when sizeof(time_t) == 8 */
148 lease->expires = (time_t)ei;
149 #endif
151 /* set these correctly: the "old" events are generated later from
152 the startup synthesised SIGHUP. */
153 lease->flags &= ~(LEASE_NEW | LEASE_CHANGED);
156 #ifdef HAVE_SCRIPT
157 if (!daemon->lease_stream)
159 int rc = 0;
161 /* shell returns 127 for "command not found", 126 for bad permissions. */
162 if (!leasestream || (rc = pclose(leasestream)) == -1 || WEXITSTATUS(rc) == 127 || WEXITSTATUS(rc) == 126)
164 if (WEXITSTATUS(rc) == 127)
165 errno = ENOENT;
166 else if (WEXITSTATUS(rc) == 126)
167 errno = EACCES;
168 die(_("cannot run lease-init script %s: %s"), daemon->lease_change_command, EC_FILE);
171 if (WEXITSTATUS(rc) != 0)
173 sprintf(daemon->dhcp_buff, "%d", WEXITSTATUS(rc));
174 die(_("lease-init script returned exit code %s"), daemon->dhcp_buff, WEXITSTATUS(rc) + EC_INIT_OFFSET);
177 #endif
179 /* Some leases may have expired */
180 file_dirty = 0;
181 lease_prune(NULL, now);
182 dns_dirty = 1;
185 void lease_update_from_configs(void)
187 /* changes to the config may change current leases. */
189 struct dhcp_lease *lease;
190 struct dhcp_config *config;
191 char *name;
193 for (lease = leases; lease; lease = lease->next)
194 if (lease->flags & (LEASE_TA | LEASE_NA))
195 continue;
196 else if ((config = find_config(daemon->dhcp_conf, NULL, lease->clid, lease->clid_len,
197 lease->hwaddr, lease->hwaddr_len, lease->hwaddr_type, NULL)) &&
198 (config->flags & CONFIG_NAME) &&
199 (!(config->flags & CONFIG_ADDR) || config->addr.s_addr == lease->addr.s_addr))
200 lease_set_hostname(lease, config->hostname, 1, get_domain(lease->addr), NULL);
201 else if ((name = host_from_dns(lease->addr)))
202 lease_set_hostname(lease, name, 1, get_domain(lease->addr), NULL); /* updates auth flag only */
205 static void ourprintf(int *errp, char *format, ...)
207 va_list ap;
209 va_start(ap, format);
210 if (!(*errp) && vfprintf(daemon->lease_stream, format, ap) < 0)
211 *errp = errno;
212 va_end(ap);
215 void lease_update_file(time_t now)
217 struct dhcp_lease *lease;
218 time_t next_event;
219 int i, err = 0;
221 if (file_dirty != 0 && daemon->lease_stream)
223 errno = 0;
224 rewind(daemon->lease_stream);
225 if (errno != 0 || ftruncate(fileno(daemon->lease_stream), 0) != 0)
226 err = errno;
228 for (lease = leases; lease; lease = lease->next)
231 #ifdef HAVE_DHCP6
232 if (lease->flags & (LEASE_TA | LEASE_NA))
233 continue;
234 #endif
236 //ASUS and TOMATO tweaks to output remaining leasetime
237 #ifdef HAVE_LEASEFILE_EXPIRE
238 ourprintf(&err, "%u ",
239 #ifdef HAVE_BROKEN_RTC
240 (lease->length == 0) ? 0 :
241 #else
242 (lease->expires == 0) ? 0 :
243 #endif
244 (unsigned int)difftime(lease->expires, now));
245 #elif defined(HAVE_BROKEN_RTC)
246 ourprintf(&err, "%u ", lease->length);
247 else
248 ourprintf(&err, "%lu ", (unsigned long)lease->expires);
249 #endif
251 if (lease->hwaddr_type != ARPHRD_ETHER || lease->hwaddr_len == 0)
252 ourprintf(&err, "%.2x-", lease->hwaddr_type);
253 for (i = 0; i < lease->hwaddr_len; i++)
255 ourprintf(&err, "%.2x", lease->hwaddr[i]);
256 if (i != lease->hwaddr_len - 1)
257 ourprintf(&err, ":");
260 inet_ntop(AF_INET, &lease->addr, daemon->addrbuff, ADDRSTRLEN);
262 ourprintf(&err, " %s ", daemon->addrbuff);
263 ourprintf(&err, "%s ", lease->hostname ? lease->hostname : "*");
265 if (lease->clid && lease->clid_len != 0)
267 for (i = 0; i < lease->clid_len - 1; i++)
268 ourprintf(&err, "%.2x:", lease->clid[i]);
269 ourprintf(&err, "%.2x\n", lease->clid[i]);
271 else
272 ourprintf(&err, "*\n");
275 #ifdef HAVE_DHCP6
276 if (daemon->duid)
278 ourprintf(&err, "duid ");
279 for (i = 0; i < daemon->duid_len - 1; i++)
280 ourprintf(&err, "%.2x:", daemon->duid[i]);
281 ourprintf(&err, "%.2x\n", daemon->duid[i]);
283 for (lease = leases; lease; lease = lease->next)
286 if (!(lease->flags & (LEASE_TA | LEASE_NA)))
287 continue;
289 //ASUS and TOMATO tweaks to output remaining leasetime
290 #ifdef HAVE_LEASEFILE_EXPIRE
291 ourprintf(&err, "%u ",
292 #ifdef HAVE_BROKEN_RTC
293 (lease->length == 0) ? 0 :
294 #else
295 (lease->expires == 0) ? 0 :
296 #endif
297 (unsigned int)difftime(lease->expires, now));
298 #elif defined(HAVE_BROKEN_RTC)
299 ourprintf(&err, "%u ", lease->length);
300 else
301 ourprintf(&err, "%lu ", (unsigned long)lease->expires);
302 #endif
304 inet_ntop(AF_INET6, &lease->addr6, daemon->addrbuff, ADDRSTRLEN);
306 ourprintf(&err, "%s%u %s ", (lease->flags & LEASE_TA) ? "T" : "",
307 lease->iaid, daemon->addrbuff);
308 ourprintf(&err, "%s ", lease->hostname ? lease->hostname : "*");
310 if (lease->clid && lease->clid_len != 0)
312 for (i = 0; i < lease->clid_len - 1; i++)
313 ourprintf(&err, "%.2x:", lease->clid[i]);
314 ourprintf(&err, "%.2x\n", lease->clid[i]);
316 else
317 ourprintf(&err, "*\n");
320 #endif
322 if (fflush(daemon->lease_stream) != 0 ||
323 fsync(fileno(daemon->lease_stream)) < 0)
324 err = errno;
326 if (!err)
327 file_dirty = 0;
330 /* Set alarm for when the first lease expires. */
331 next_event = 0;
333 #ifdef HAVE_DHCP6
334 /* do timed RAs and determine when the next is, also pings to potential SLAAC addresses */
335 if (daemon->doing_ra)
337 time_t event;
339 if ((event = periodic_slaac(now, leases)) != 0)
341 if (next_event == 0 || difftime(next_event, event) > 0.0)
342 next_event = event;
345 if ((event = periodic_ra(now)) != 0)
347 if (next_event == 0 || difftime(next_event, event) > 0.0)
348 next_event = event;
351 #endif
353 for (lease = leases; lease; lease = lease->next)
354 if (lease->expires != 0 &&
355 (next_event == 0 || difftime(next_event, lease->expires) > 0.0))
356 next_event = lease->expires;
358 if (err)
360 if (next_event == 0 || difftime(next_event, LEASE_RETRY + now) > 0.0)
361 next_event = LEASE_RETRY + now;
363 my_syslog(MS_DHCP | LOG_ERR, _("failed to write %s: %s (retry in %us)"),
364 daemon->lease_file, strerror(err),
365 (unsigned int)difftime(next_event, now));
368 send_alarm(next_event, now);
372 static int find_interface_v4(struct in_addr local, int if_index, char *label,
373 struct in_addr netmask, struct in_addr broadcast, void *vparam)
375 struct dhcp_lease *lease;
376 int prefix = netmask_length(netmask);
378 (void) label;
379 (void) broadcast;
380 (void) vparam;
382 for (lease = leases; lease; lease = lease->next)
383 if (!(lease->flags & (LEASE_TA | LEASE_NA)) &&
384 is_same_net(local, lease->addr, netmask) &&
385 prefix > lease->new_prefixlen)
387 lease->new_interface = if_index;
388 lease->new_prefixlen = prefix;
391 return 1;
394 #ifdef HAVE_DHCP6
395 static int find_interface_v6(struct in6_addr *local, int prefix,
396 int scope, int if_index, int flags,
397 int preferred, int valid, void *vparam)
399 struct dhcp_lease *lease;
401 (void)scope;
402 (void)flags;
403 (void)preferred;
404 (void)valid;
405 (void)vparam;
407 for (lease = leases; lease; lease = lease->next)
408 if ((lease->flags & (LEASE_TA | LEASE_NA)))
409 if (is_same_net6(local, &lease->addr6, prefix) && prefix > lease->new_prefixlen) {
410 /* save prefix length for comparison, as we might get shorter matching
411 * prefix in upcoming netlink GETADDR responses
412 * */
413 lease->new_interface = if_index;
414 lease->new_prefixlen = prefix;
417 return 1;
420 void lease_ping_reply(struct in6_addr *sender, unsigned char *packet, char *interface)
422 /* We may be doing RA but not DHCPv4, in which case the lease
423 database may not exist and we have nothing to do anyway */
424 if (daemon->dhcp)
425 slaac_ping_reply(sender, packet, interface, leases);
428 void lease_update_slaac(time_t now)
430 /* Called when we contruct a new RA-names context, to add putative
431 new SLAAC addresses to existing leases. */
433 struct dhcp_lease *lease;
435 if (daemon->dhcp)
436 for (lease = leases; lease; lease = lease->next)
437 slaac_add_addrs(lease, now, 0);
440 #endif
443 /* Find interfaces associated with leases at start-up. This gets updated as
444 we do DHCP transactions, but information about directly-connected subnets
445 is useful from scrips and necessary for determining SLAAC addresses from
446 start-time. */
447 void lease_find_interfaces(time_t now)
449 struct dhcp_lease *lease;
451 for (lease = leases; lease; lease = lease->next)
452 lease->new_prefixlen = lease->new_interface = 0;
454 iface_enumerate(AF_INET, &now, find_interface_v4);
455 #ifdef HAVE_DHCP6
456 iface_enumerate(AF_INET6, &now, find_interface_v6);
457 #endif
459 for (lease = leases; lease; lease = lease->next)
460 if (lease->new_interface != 0)
461 lease_set_interface(lease, lease->new_interface, now);
464 #ifdef HAVE_DHCP6
465 void lease_make_duid(time_t now)
467 /* If we're not doing DHCPv6, and there are not v6 leases, don't add the DUID to the database */
468 if (!daemon->duid && daemon->doing_dhcp6)
470 file_dirty = 1;
471 make_duid(now);
474 #endif
479 void lease_update_dns(int force)
481 struct dhcp_lease *lease;
483 if (daemon->port != 0 && (dns_dirty || force))
485 #ifndef HAVE_BROKEN_RTC
486 /* force transfer to authoritative secondaries */
487 daemon->soa_sn++;
488 #endif
490 cache_unhash_dhcp();
492 for (lease = leases; lease; lease = lease->next)
494 int prot = AF_INET;
496 #ifdef HAVE_DHCP6
497 if (lease->flags & (LEASE_TA | LEASE_NA))
498 prot = AF_INET6;
499 else if (lease->hostname || lease->fqdn)
501 struct slaac_address *slaac;
503 for (slaac = lease->slaac_address; slaac; slaac = slaac->next)
504 if (slaac->backoff == 0)
506 if (lease->fqdn)
507 cache_add_dhcp_entry(lease->fqdn, AF_INET6, (struct all_addr *)&slaac->addr, lease->expires);
508 if (!option_bool(OPT_DHCP_FQDN) && lease->hostname)
509 cache_add_dhcp_entry(lease->hostname, AF_INET6, (struct all_addr *)&slaac->addr, lease->expires);
513 if (lease->fqdn)
514 cache_add_dhcp_entry(lease->fqdn, prot,
515 prot == AF_INET ? (struct all_addr *)&lease->addr : (struct all_addr *)&lease->addr6,
516 lease->expires);
518 if (!option_bool(OPT_DHCP_FQDN) && lease->hostname)
519 cache_add_dhcp_entry(lease->hostname, prot,
520 prot == AF_INET ? (struct all_addr *)&lease->addr : (struct all_addr *)&lease->addr6,
521 lease->expires);
523 #else
524 if (lease->fqdn)
525 cache_add_dhcp_entry(lease->fqdn, prot, (struct all_addr *)&lease->addr, lease->expires);
527 if (!option_bool(OPT_DHCP_FQDN) && lease->hostname)
528 cache_add_dhcp_entry(lease->hostname, prot, (struct all_addr *)&lease->addr, lease->expires);
529 #endif
532 dns_dirty = 0;
536 void lease_prune(struct dhcp_lease *target, time_t now)
538 struct dhcp_lease *lease, *tmp, **up;
540 for (lease = leases, up = &leases; lease; lease = tmp)
542 tmp = lease->next;
543 if ((lease->expires != 0 && difftime(now, lease->expires) > 0) || lease == target)
545 file_dirty = 1;
546 if (lease->hostname)
547 dns_dirty = 1;
549 *up = lease->next; /* unlink */
551 /* Put on old_leases list 'till we
552 can run the script */
553 lease->next = old_leases;
554 old_leases = lease;
556 leases_left++;
558 else
559 up = &lease->next;
564 struct dhcp_lease *lease_find_by_client(unsigned char *hwaddr, int hw_len, int hw_type,
565 unsigned char *clid, int clid_len)
567 struct dhcp_lease *lease;
569 if (clid)
570 for (lease = leases; lease; lease = lease->next)
572 #ifdef HAVE_DHCP6
573 if (lease->flags & (LEASE_TA | LEASE_NA))
574 continue;
575 #endif
576 if (lease->clid && clid_len == lease->clid_len &&
577 memcmp(clid, lease->clid, clid_len) == 0)
578 return lease;
581 for (lease = leases; lease; lease = lease->next)
583 #ifdef HAVE_DHCP6
584 if (lease->flags & (LEASE_TA | LEASE_NA))
585 continue;
586 #endif
587 if ((!lease->clid || !clid) &&
588 hw_len != 0 &&
589 lease->hwaddr_len == hw_len &&
590 lease->hwaddr_type == hw_type &&
591 memcmp(hwaddr, lease->hwaddr, hw_len) == 0)
592 return lease;
595 return NULL;
598 struct dhcp_lease *lease_find_by_addr(struct in_addr addr)
600 struct dhcp_lease *lease;
602 for (lease = leases; lease; lease = lease->next)
604 #ifdef HAVE_DHCP6
605 if (lease->flags & (LEASE_TA | LEASE_NA))
606 continue;
607 #endif
608 if (lease->addr.s_addr == addr.s_addr)
609 return lease;
612 return NULL;
615 #ifdef HAVE_DHCP6
616 /* find address for {CLID, IAID, address} */
617 struct dhcp_lease *lease6_find(unsigned char *clid, int clid_len,
618 int lease_type, int iaid, struct in6_addr *addr)
620 struct dhcp_lease *lease;
622 for (lease = leases; lease; lease = lease->next)
624 if (!(lease->flags & lease_type) || lease->iaid != iaid)
625 continue;
627 if (!IN6_ARE_ADDR_EQUAL(&lease->addr6, addr))
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 /* reset "USED flags */
641 void lease6_reset(void)
643 struct dhcp_lease *lease;
645 for (lease = leases; lease; lease = lease->next)
646 lease->flags &= ~LEASE_USED;
649 /* enumerate all leases belonging to {CLID, IAID} */
650 struct dhcp_lease *lease6_find_by_client(struct dhcp_lease *first, int lease_type, unsigned char *clid, int clid_len, int iaid)
652 struct dhcp_lease *lease;
654 if (!first)
655 first = leases;
656 else
657 first = first->next;
659 for (lease = first; lease; lease = lease->next)
661 if (lease->flags & LEASE_USED)
662 continue;
664 if (!(lease->flags & lease_type) || lease->iaid != iaid)
665 continue;
667 if ((clid_len != lease->clid_len ||
668 memcmp(clid, lease->clid, clid_len) != 0))
669 continue;
671 return lease;
674 return NULL;
677 struct dhcp_lease *lease6_find_by_addr(struct in6_addr *net, int prefix, u64 addr)
679 struct dhcp_lease *lease;
681 for (lease = leases; lease; lease = lease->next)
683 if (!(lease->flags & (LEASE_TA | LEASE_NA)))
684 continue;
686 if (is_same_net6(&lease->addr6, net, prefix) &&
687 (prefix == 128 || addr6part(&lease->addr6) == addr))
688 return lease;
691 return NULL;
694 /* Find largest assigned address in context */
695 u64 lease_find_max_addr6(struct dhcp_context *context)
697 struct dhcp_lease *lease;
698 u64 addr = addr6part(&context->start6);
700 if (!(context->flags & (CONTEXT_STATIC | CONTEXT_PROXY)))
701 for (lease = leases; lease; lease = lease->next)
703 if (!(lease->flags & (LEASE_TA | LEASE_NA)))
704 continue;
706 if (is_same_net6(&lease->addr6, &context->start6, 64) &&
707 addr6part(&lease->addr6) > addr6part(&context->start6) &&
708 addr6part(&lease->addr6) <= addr6part(&context->end6) &&
709 addr6part(&lease->addr6) > addr)
710 addr = addr6part(&lease->addr6);
713 return addr;
716 #endif
718 /* Find largest assigned address in context */
719 struct in_addr lease_find_max_addr(struct dhcp_context *context)
721 struct dhcp_lease *lease;
722 struct in_addr addr = context->start;
724 if (!(context->flags & (CONTEXT_STATIC | CONTEXT_PROXY)))
725 for (lease = leases; lease; lease = lease->next)
727 #ifdef HAVE_DHCP6
728 if (lease->flags & (LEASE_TA | LEASE_NA))
729 continue;
730 #endif
731 if (((unsigned)ntohl(lease->addr.s_addr)) > ((unsigned)ntohl(context->start.s_addr)) &&
732 ((unsigned)ntohl(lease->addr.s_addr)) <= ((unsigned)ntohl(context->end.s_addr)) &&
733 ((unsigned)ntohl(lease->addr.s_addr)) > ((unsigned)ntohl(addr.s_addr)))
734 addr = lease->addr;
737 return addr;
740 static struct dhcp_lease *lease_allocate(void)
742 struct dhcp_lease *lease;
743 if (!leases_left || !(lease = whine_malloc(sizeof(struct dhcp_lease))))
744 return NULL;
746 memset(lease, 0, sizeof(struct dhcp_lease));
747 lease->flags = LEASE_NEW;
748 lease->expires = 1;
749 #ifdef HAVE_BROKEN_RTC
750 lease->length = 0xffffffff; /* illegal value */
751 #endif
752 lease->hwaddr_len = 256; /* illegal value */
753 lease->next = leases;
754 leases = lease;
756 file_dirty = 1;
757 leases_left--;
759 return lease;
762 struct dhcp_lease *lease4_allocate(struct in_addr addr)
764 struct dhcp_lease *lease = lease_allocate();
765 if (lease)
766 lease->addr = addr;
768 return lease;
771 #ifdef HAVE_DHCP6
772 struct dhcp_lease *lease6_allocate(struct in6_addr *addrp, int lease_type)
774 struct dhcp_lease *lease = lease_allocate();
776 if (lease)
778 lease->addr6 = *addrp;
779 lease->flags |= lease_type;
780 lease->iaid = 0;
783 return lease;
785 #endif
787 void lease_set_expires(struct dhcp_lease *lease, unsigned int len, time_t now)
789 time_t exp;
791 if (len == 0xffffffff)
793 exp = 0;
794 len = 0;
796 else
798 exp = now + (time_t)len;
799 /* Check for 2038 overflow. Make the lease
800 inifinite in that case, as the least disruptive
801 thing we can do. */
802 if (difftime(exp, now) <= 0.0)
803 exp = 0;
806 if (exp != lease->expires)
808 dns_dirty = 1;
809 lease->expires = exp;
810 #ifndef HAVE_BROKEN_RTC
811 lease->flags |= LEASE_AUX_CHANGED;
812 file_dirty = 1;
813 #endif
816 #ifdef HAVE_BROKEN_RTC
817 if (len != lease->length)
819 lease->length = len;
820 lease->flags |= LEASE_AUX_CHANGED;
821 file_dirty = 1;
823 #endif
826 #ifdef HAVE_DHCP6
827 void lease_set_iaid(struct dhcp_lease *lease, int iaid)
829 if (lease->iaid != iaid)
831 lease->iaid = iaid;
832 lease->flags |= LEASE_CHANGED;
835 #endif
837 void lease_set_hwaddr(struct dhcp_lease *lease, unsigned char *hwaddr,
838 unsigned char *clid, int hw_len, int hw_type, int clid_len,
839 time_t now, int force)
841 #ifdef HAVE_DHCP6
842 int change = force;
843 lease->flags |= LEASE_HAVE_HWADDR;
844 #endif
846 (void)force;
847 (void)now;
849 if (hw_len != lease->hwaddr_len ||
850 hw_type != lease->hwaddr_type ||
851 (hw_len != 0 && memcmp(lease->hwaddr, hwaddr, hw_len) != 0))
853 if (hw_len != 0)
854 memcpy(lease->hwaddr, hwaddr, hw_len);
855 lease->hwaddr_len = hw_len;
856 lease->hwaddr_type = hw_type;
857 lease->flags |= LEASE_CHANGED;
858 file_dirty = 1; /* run script on change */
861 /* only update clid when one is available, stops packets
862 without a clid removing the record. Lease init uses
863 clid_len == 0 for no clid. */
864 if (clid_len != 0 && clid)
866 if (!lease->clid)
867 lease->clid_len = 0;
869 if (lease->clid_len != clid_len)
871 lease->flags |= LEASE_AUX_CHANGED;
872 file_dirty = 1;
873 free(lease->clid);
874 if (!(lease->clid = whine_malloc(clid_len)))
875 return;
876 #ifdef HAVE_DHCP6
877 change = 1;
878 #endif
880 else if (memcmp(lease->clid, clid, clid_len) != 0)
882 lease->flags |= LEASE_AUX_CHANGED;
883 file_dirty = 1;
884 #ifdef HAVE_DHCP6
885 change = 1;
886 #endif
889 lease->clid_len = clid_len;
890 memcpy(lease->clid, clid, clid_len);
893 #ifdef HAVE_DHCP6
894 if (change)
895 slaac_add_addrs(lease, now, force);
896 #endif
899 static void kill_name(struct dhcp_lease *lease)
901 /* run script to say we lost our old name */
903 /* this shouldn't happen unless updates are very quick and the
904 script very slow, we just avoid a memory leak if it does. */
905 free(lease->old_hostname);
907 /* If we know the fqdn, pass that. The helper will derive the
908 unqualified name from it, free the unqualified name here. */
910 if (lease->fqdn)
912 lease->old_hostname = lease->fqdn;
913 free(lease->hostname);
915 else
916 lease->old_hostname = lease->hostname;
918 lease->hostname = lease->fqdn = NULL;
921 void lease_set_hostname(struct dhcp_lease *lease, char *name, int auth, char *domain, char *config_domain)
923 struct dhcp_lease *lease_tmp;
924 char *new_name = NULL, *new_fqdn = NULL;
926 if (config_domain && (!domain || !hostname_isequal(domain, config_domain)))
927 my_syslog(MS_DHCP | LOG_WARNING, _("Ignoring domain %s for DHCP host name %s"), config_domain, name);
929 if (lease->hostname && name && hostname_isequal(lease->hostname, name))
931 if (auth)
932 lease->flags |= LEASE_AUTH_NAME;
933 return;
936 if (!name && !lease->hostname)
937 return;
939 /* If a machine turns up on a new net without dropping the old lease,
940 or two machines claim the same name, then we end up with two interfaces with
941 the same name. Check for that here and remove the name from the old lease.
942 Note that IPv6 leases are different. All the leases to the same DUID are
943 allowed the same name.
945 Don't allow a name from the client to override a name from dnsmasq config. */
947 if (name)
949 if ((new_name = whine_malloc(strlen(name) + 1)))
951 strcpy(new_name, name);
952 if (domain && (new_fqdn = whine_malloc(strlen(new_name) + strlen(domain) + 2)))
954 strcpy(new_fqdn, name);
955 strcat(new_fqdn, ".");
956 strcat(new_fqdn, domain);
960 /* Depending on mode, we check either unqualified name or FQDN. */
961 for (lease_tmp = leases; lease_tmp; lease_tmp = lease_tmp->next)
963 if (option_bool(OPT_DHCP_FQDN))
965 if (!new_fqdn || !lease_tmp->fqdn || !hostname_isequal(lease_tmp->fqdn, new_fqdn))
966 continue;
968 else
970 if (!new_name || !lease_tmp->hostname || !hostname_isequal(lease_tmp->hostname, new_name) )
971 continue;
974 if (lease->flags & (LEASE_TA | LEASE_NA))
976 if (!(lease_tmp->flags & (LEASE_TA | LEASE_NA)))
977 continue;
979 /* another lease for the same DUID is OK for IPv6 */
980 if (lease->clid_len == lease_tmp->clid_len &&
981 lease->clid && lease_tmp->clid &&
982 memcmp(lease->clid, lease_tmp->clid, lease->clid_len) == 0)
983 continue;
985 else if (lease_tmp->flags & (LEASE_TA | LEASE_NA))
986 continue;
988 if ((lease_tmp->flags & LEASE_AUTH_NAME) && !auth)
990 free(new_name);
991 free(new_fqdn);
992 return;
995 kill_name(lease_tmp);
996 break;
1000 if (lease->hostname)
1001 kill_name(lease);
1003 lease->hostname = new_name;
1004 lease->fqdn = new_fqdn;
1006 if (auth)
1007 lease->flags |= LEASE_AUTH_NAME;
1009 file_dirty = 1;
1010 dns_dirty = 1;
1011 lease->flags |= LEASE_CHANGED; /* run script on change */
1014 void lease_set_interface(struct dhcp_lease *lease, int interface, time_t now)
1016 (void)now;
1018 if (lease->last_interface == interface)
1019 return;
1021 lease->last_interface = interface;
1022 lease->flags |= LEASE_CHANGED;
1024 #ifdef HAVE_DHCP6
1025 slaac_add_addrs(lease, now, 0);
1026 #endif
1029 void rerun_scripts(void)
1031 struct dhcp_lease *lease;
1033 for (lease = leases; lease; lease = lease->next)
1034 lease->flags |= LEASE_CHANGED;
1037 /* deleted leases get transferred to the old_leases list.
1038 remove them here, after calling the lease change
1039 script. Also run the lease change script on new/modified leases.
1041 Return zero if nothing to do. */
1042 int do_script_run(time_t now)
1044 struct dhcp_lease *lease;
1046 (void)now;
1048 #ifdef HAVE_DBUS
1049 /* If we're going to be sending DBus signals, but the connection is not yet up,
1050 delay everything until it is. */
1051 if (option_bool(OPT_DBUS) && !daemon->dbus)
1052 return 0;
1053 #endif
1055 if (old_leases)
1057 lease = old_leases;
1059 /* If the lease still has an old_hostname, do the "old" action on that first */
1060 if (lease->old_hostname)
1062 #ifdef HAVE_SCRIPT
1063 queue_script(ACTION_OLD_HOSTNAME, lease, lease->old_hostname, now);
1064 #endif
1065 free(lease->old_hostname);
1066 lease->old_hostname = NULL;
1067 return 1;
1069 else
1071 #ifdef HAVE_DHCP6
1072 struct slaac_address *slaac, *tmp;
1073 for (slaac = lease->slaac_address; slaac; slaac = tmp)
1075 tmp = slaac->next;
1076 free(slaac);
1078 #endif
1079 kill_name(lease);
1080 #ifdef HAVE_SCRIPT
1081 queue_script(ACTION_DEL, lease, lease->old_hostname, now);
1082 #endif
1083 #ifdef HAVE_DBUS
1084 emit_dbus_signal(ACTION_DEL, lease, lease->old_hostname);
1085 #endif
1086 old_leases = lease->next;
1088 free(lease->old_hostname);
1089 free(lease->clid);
1090 free(lease->extradata);
1091 free(lease);
1093 return 1;
1097 /* make sure we announce the loss of a hostname before its new location. */
1098 for (lease = leases; lease; lease = lease->next)
1099 if (lease->old_hostname)
1101 #ifdef HAVE_SCRIPT
1102 queue_script(ACTION_OLD_HOSTNAME, lease, lease->old_hostname, now);
1103 #endif
1104 free(lease->old_hostname);
1105 lease->old_hostname = NULL;
1106 return 1;
1109 for (lease = leases; lease; lease = lease->next)
1110 if ((lease->flags & (LEASE_NEW | LEASE_CHANGED)) ||
1111 ((lease->flags & LEASE_AUX_CHANGED) && option_bool(OPT_LEASE_RO)))
1113 #ifdef HAVE_SCRIPT
1114 queue_script((lease->flags & LEASE_NEW) ? ACTION_ADD : ACTION_OLD, lease,
1115 lease->fqdn ? lease->fqdn : lease->hostname, now);
1116 #endif
1117 #ifdef HAVE_DBUS
1118 emit_dbus_signal((lease->flags & LEASE_NEW) ? ACTION_ADD : ACTION_OLD, lease,
1119 lease->fqdn ? lease->fqdn : lease->hostname);
1120 #endif
1121 lease->flags &= ~(LEASE_NEW | LEASE_CHANGED | LEASE_AUX_CHANGED);
1123 /* this is used for the "add" call, then junked, since they're not in the database */
1124 free(lease->extradata);
1125 lease->extradata = NULL;
1127 return 1;
1130 return 0; /* nothing to do */
1133 #ifdef HAVE_SCRIPT
1134 void lease_add_extradata(struct dhcp_lease *lease, unsigned char *data, unsigned int len, int delim)
1136 unsigned int i;
1138 /* check for embeded NULLs */
1139 for (i = 0; i < len; i++)
1140 if (data[i] == 0)
1142 len = i;
1143 break;
1146 if ((lease->extradata_size - lease->extradata_len) < (len + 1))
1148 size_t newsz = lease->extradata_len + len + 100;
1149 unsigned char *new = whine_malloc(newsz);
1151 if (!new)
1152 return;
1154 if (lease->extradata)
1156 memcpy(new, lease->extradata, lease->extradata_len);
1157 free(lease->extradata);
1160 lease->extradata = new;
1161 lease->extradata_size = newsz;
1164 if (len != 0)
1165 memcpy(lease->extradata + lease->extradata_len, data, len);
1166 lease->extradata[lease->extradata_len + len] = delim;
1167 lease->extradata_len += len + 1;
1169 #endif
1171 #ifdef HAVE_TOMATO
1173 void tomato_helper(time_t now)
1175 FILE *f;
1176 struct in_addr ia;
1177 char buf[64];
1178 struct dhcp_lease *lease;
1180 // if delete exists...
1181 if ((f = fopen("/var/tmp/dhcp/delete", "r")) != NULL) {
1182 while (fgets(buf, sizeof(buf), f)) {
1183 ia.s_addr = inet_addr(buf);
1184 lease = lease_find_by_addr(ia);
1185 if (lease) {
1186 lease_prune(lease, 0);
1187 lease_update_file(now);
1190 fclose(f);
1191 unlink("/var/tmp/dhcp/delete");
1194 // dump the leases file
1195 if ((f = fopen("/var/tmp/dhcp/leases.!", "w")) != NULL) {
1196 for (lease = leases; lease; lease = lease->next) {
1197 if (lease->hwaddr_type == ARPHRD_ETHER) {
1198 #ifdef HAVE_DHCP6 //only dump dhcpv6 if we have it
1199 if (lease->flags & (LEASE_TA | LEASE_NA))
1200 inet_ntop(AF_INET6, &lease->addr6, buf, ADDRSTRLEN);
1201 else
1202 #endif // Thanks to Shibby :-)
1203 inet_ntop(AF_INET, &lease->addr, buf, ADDRSTRLEN);
1205 fprintf(f, "%lu %02X:%02X:%02X:%02X:%02X:%02X %s %s\n",
1206 lease->expires - now,
1207 lease->hwaddr[0], lease->hwaddr[1], lease->hwaddr[2], lease->hwaddr[3], lease->hwaddr[4], lease->hwaddr[5],
1208 buf,
1209 ((lease->hostname) && (strlen(lease->hostname) > 0)) ? lease->hostname : "*");
1212 fclose(f);
1213 rename("/var/tmp/dhcp/leases.!", "/var/tmp/dhcp/leases");
1216 #endif //HAVE_TOMATO
1218 #ifdef HAVE_LEASEFILE_EXPIRE
1219 void flush_lease_file(time_t now)
1221 static time_t flush_time = (time_t)0;
1223 if(difftime(flush_time, now) < 0)
1224 file_dirty = 1;
1226 lease_prune(NULL, now);
1227 lease_update_file(now);
1229 if (file_dirty == 0)
1230 flush_time = now;
1232 #endif //HAVE_LEASEFILE_EXPIRE
1234 #endif