Dnsmasq 2.67rc4 + Simon's tweaks up & incl 21 Oct 2013 20:47
[tomato.git] / release / src / router / dnsmasq / src / lease.c
blob2975c8ed9857d196158fa49044f4cd4aef056cdf
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 //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_RT
143 lease->length = ei;
144 #endif
145 #else
146 /* strictly time_t is opaque, but this hack should work on all sane systems,
147 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 + slop. */
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 + 10) > 0.0))
356 next_event = lease->expires + 10;
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;
377 (void) label;
378 (void) broadcast;
379 (void) vparam;
381 for (lease = leases; lease; lease = lease->next)
382 if (!(lease->flags & (LEASE_TA | LEASE_NA)))
383 if (is_same_net(local, lease->addr, netmask))
384 lease_set_interface(lease, if_index, *((time_t *)vparam));
386 return 1;
389 #ifdef HAVE_DHCP6
390 static int find_interface_v6(struct in6_addr *local, int prefix,
391 int scope, int if_index, int flags,
392 int preferred, int valid, void *vparam)
394 struct dhcp_lease *lease;
396 (void)scope;
397 (void)flags;
398 (void)preferred;
399 (void)valid;
401 for (lease = leases; lease; lease = lease->next)
402 if ((lease->flags & (LEASE_TA | LEASE_NA)))
403 if (is_same_net6(local, &lease->addr6, prefix))
404 lease_set_interface(lease, if_index, *((time_t *)vparam));
406 return 1;
409 void lease_ping_reply(struct in6_addr *sender, unsigned char *packet, char *interface)
411 /* We may be doing RA but not DHCPv4, in which case the lease
412 database may not exist and we have nothing to do anyway */
413 if (daemon->dhcp)
414 slaac_ping_reply(sender, packet, interface, leases);
417 void lease_update_slaac(time_t now)
419 /* Called when we contruct a new RA-names context, to add putative
420 new SLAAC addresses to existing leases. */
422 struct dhcp_lease *lease;
424 if (daemon->dhcp)
425 for (lease = leases; lease; lease = lease->next)
426 slaac_add_addrs(lease, now, 0);
429 #endif
432 /* Find interfaces associated with leases at start-up. This gets updated as
433 we do DHCP transactions, but information about directly-connected subnets
434 is useful from scrips and necessary for determining SLAAC addresses from
435 start-time. */
436 void lease_find_interfaces(time_t now)
438 iface_enumerate(AF_INET, &now, find_interface_v4);
439 #ifdef HAVE_DHCP6
440 iface_enumerate(AF_INET6, &now, find_interface_v6);
442 /* If we're not doing DHCPv6, and there are not v6 leases, don't add the DUID to the database */
443 if (!daemon->duid && daemon->dhcp6)
445 file_dirty = 1;
446 make_duid(now);
448 #endif
453 void lease_update_dns(int force)
455 struct dhcp_lease *lease;
457 if (daemon->port != 0 && (dns_dirty || force))
459 #ifndef HAVE_BROKEN_RTC
460 /* force transfer to authoritative secondaries */
461 daemon->soa_sn++;
462 #endif
464 cache_unhash_dhcp();
466 for (lease = leases; lease; lease = lease->next)
468 int prot = AF_INET;
470 #ifdef HAVE_DHCP6
471 if (lease->flags & (LEASE_TA | LEASE_NA))
472 prot = AF_INET6;
473 else if (lease->hostname || lease->fqdn)
475 struct slaac_address *slaac;
477 for (slaac = lease->slaac_address; slaac; slaac = slaac->next)
478 if (slaac->backoff == 0)
480 if (lease->fqdn)
481 cache_add_dhcp_entry(lease->fqdn, AF_INET6, (struct all_addr *)&slaac->addr, lease->expires);
482 if (!option_bool(OPT_DHCP_FQDN) && lease->hostname)
483 cache_add_dhcp_entry(lease->hostname, AF_INET6, (struct all_addr *)&slaac->addr, lease->expires);
487 if (lease->fqdn)
488 cache_add_dhcp_entry(lease->fqdn, prot,
489 prot == AF_INET ? (struct all_addr *)&lease->addr : (struct all_addr *)&lease->addr6,
490 lease->expires);
492 if (!option_bool(OPT_DHCP_FQDN) && lease->hostname)
493 cache_add_dhcp_entry(lease->hostname, prot,
494 prot == AF_INET ? (struct all_addr *)&lease->addr : (struct all_addr *)&lease->addr6,
495 lease->expires);
497 #else
498 if (lease->fqdn)
499 cache_add_dhcp_entry(lease->fqdn, prot, (struct all_addr *)&lease->addr, lease->expires);
501 if (!option_bool(OPT_DHCP_FQDN) && lease->hostname)
502 cache_add_dhcp_entry(lease->hostname, prot, (struct all_addr *)&lease->addr, lease->expires);
503 #endif
506 dns_dirty = 0;
510 void lease_prune(struct dhcp_lease *target, time_t now)
512 struct dhcp_lease *lease, *tmp, **up;
514 for (lease = leases, up = &leases; lease; lease = tmp)
516 tmp = lease->next;
517 if ((lease->expires != 0 && difftime(now, lease->expires) > 0) || lease == target)
519 file_dirty = 1;
520 if (lease->hostname)
521 dns_dirty = 1;
523 *up = lease->next; /* unlink */
525 /* Put on old_leases list 'till we
526 can run the script */
527 lease->next = old_leases;
528 old_leases = lease;
530 leases_left++;
532 else
533 up = &lease->next;
538 struct dhcp_lease *lease_find_by_client(unsigned char *hwaddr, int hw_len, int hw_type,
539 unsigned char *clid, int clid_len)
541 struct dhcp_lease *lease;
543 if (clid)
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_len == lease->clid_len &&
551 memcmp(clid, lease->clid, clid_len) == 0)
552 return lease;
555 for (lease = leases; lease; lease = lease->next)
557 #ifdef HAVE_DHCP6
558 if (lease->flags & (LEASE_TA | LEASE_NA))
559 continue;
560 #endif
561 if ((!lease->clid || !clid) &&
562 hw_len != 0 &&
563 lease->hwaddr_len == hw_len &&
564 lease->hwaddr_type == hw_type &&
565 memcmp(hwaddr, lease->hwaddr, hw_len) == 0)
566 return lease;
569 return NULL;
572 struct dhcp_lease *lease_find_by_addr(struct in_addr addr)
574 struct dhcp_lease *lease;
576 for (lease = leases; lease; lease = lease->next)
578 #ifdef HAVE_DHCP6
579 if (lease->flags & (LEASE_TA | LEASE_NA))
580 continue;
581 #endif
582 if (lease->addr.s_addr == addr.s_addr)
583 return lease;
586 return NULL;
589 #ifdef HAVE_DHCP6
590 /* find address for {CLID, IAID, address} */
591 struct dhcp_lease *lease6_find(unsigned char *clid, int clid_len,
592 int lease_type, int iaid, struct in6_addr *addr)
594 struct dhcp_lease *lease;
596 for (lease = leases; lease; lease = lease->next)
598 if (!(lease->flags & lease_type) || lease->iaid != iaid)
599 continue;
601 if (!IN6_ARE_ADDR_EQUAL(&lease->addr6, addr))
602 continue;
604 if ((clid_len != lease->clid_len ||
605 memcmp(clid, lease->clid, clid_len) != 0))
606 continue;
608 return lease;
611 return NULL;
614 /* reset "USED flags */
615 void lease6_reset(void)
617 struct dhcp_lease *lease;
619 for (lease = leases; lease; lease = lease->next)
620 lease->flags &= ~LEASE_USED;
623 /* enumerate all leases belonging to {CLID, IAID} */
624 struct dhcp_lease *lease6_find_by_client(struct dhcp_lease *first, int lease_type, unsigned char *clid, int clid_len, int iaid)
626 struct dhcp_lease *lease;
628 if (!first)
629 first = leases;
630 else
631 first = first->next;
633 for (lease = first; lease; lease = lease->next)
635 if (lease->flags & LEASE_USED)
636 continue;
638 if (!(lease->flags & lease_type) || lease->iaid != iaid)
639 continue;
641 if ((clid_len != lease->clid_len ||
642 memcmp(clid, lease->clid, clid_len) != 0))
643 continue;
645 return lease;
648 return NULL;
651 struct dhcp_lease *lease6_find_by_addr(struct in6_addr *net, int prefix, u64 addr)
653 struct dhcp_lease *lease;
655 for (lease = leases; lease; lease = lease->next)
657 if (!(lease->flags & (LEASE_TA | LEASE_NA)))
658 continue;
660 if (is_same_net6(&lease->addr6, net, prefix) &&
661 (prefix == 128 || addr6part(&lease->addr6) == addr))
662 return lease;
665 return NULL;
668 /* Find largest assigned address in context */
669 u64 lease_find_max_addr6(struct dhcp_context *context)
671 struct dhcp_lease *lease;
672 u64 addr = addr6part(&context->start6);
674 if (!(context->flags & (CONTEXT_STATIC | CONTEXT_PROXY)))
675 for (lease = leases; lease; lease = lease->next)
677 if (!(lease->flags & (LEASE_TA | LEASE_NA)))
678 continue;
680 if (is_same_net6(&lease->addr6, &context->start6, 64) &&
681 addr6part(&lease->addr6) > addr6part(&context->start6) &&
682 addr6part(&lease->addr6) <= addr6part(&context->end6) &&
683 addr6part(&lease->addr6) > addr)
684 addr = addr6part(&lease->addr6);
687 return addr;
690 #endif
692 /* Find largest assigned address in context */
693 struct in_addr lease_find_max_addr(struct dhcp_context *context)
695 struct dhcp_lease *lease;
696 struct in_addr addr = context->start;
698 if (!(context->flags & (CONTEXT_STATIC | CONTEXT_PROXY)))
699 for (lease = leases; lease; lease = lease->next)
701 #ifdef HAVE_DHCP6
702 if (lease->flags & (LEASE_TA | LEASE_NA))
703 continue;
704 #endif
705 if (((unsigned)ntohl(lease->addr.s_addr)) > ((unsigned)ntohl(context->start.s_addr)) &&
706 ((unsigned)ntohl(lease->addr.s_addr)) <= ((unsigned)ntohl(context->end.s_addr)) &&
707 ((unsigned)ntohl(lease->addr.s_addr)) > ((unsigned)ntohl(addr.s_addr)))
708 addr = lease->addr;
711 return addr;
714 static struct dhcp_lease *lease_allocate(void)
716 struct dhcp_lease *lease;
717 if (!leases_left || !(lease = whine_malloc(sizeof(struct dhcp_lease))))
718 return NULL;
720 memset(lease, 0, sizeof(struct dhcp_lease));
721 lease->flags = LEASE_NEW;
722 lease->expires = 1;
723 #ifdef HAVE_BROKEN_RTC
724 lease->length = 0xffffffff; /* illegal value */
725 #endif
726 lease->hwaddr_len = 256; /* illegal value */
727 lease->next = leases;
728 leases = lease;
730 file_dirty = 1;
731 leases_left--;
733 return lease;
736 struct dhcp_lease *lease4_allocate(struct in_addr addr)
738 struct dhcp_lease *lease = lease_allocate();
739 if (lease)
740 lease->addr = addr;
742 return lease;
745 #ifdef HAVE_DHCP6
746 struct dhcp_lease *lease6_allocate(struct in6_addr *addrp, int lease_type)
748 struct dhcp_lease *lease = lease_allocate();
750 if (lease)
752 lease->addr6 = *addrp;
753 lease->flags |= lease_type;
754 lease->iaid = 0;
757 return lease;
759 #endif
761 void lease_set_expires(struct dhcp_lease *lease, unsigned int len, time_t now)
763 time_t exp = now + (time_t)len;
765 if (len == 0xffffffff)
767 exp = 0;
768 len = 0;
771 if (exp != lease->expires)
773 dns_dirty = 1;
774 lease->expires = exp;
775 #ifndef HAVE_BROKEN_RTC
776 lease->flags |= LEASE_AUX_CHANGED;
777 file_dirty = 1;
778 #endif
781 #ifdef HAVE_BROKEN_RTC
782 if (len != lease->length)
784 lease->length = len;
785 lease->flags |= LEASE_AUX_CHANGED;
786 file_dirty = 1;
788 #endif
791 #ifdef HAVE_DHCP6
792 void lease_set_iaid(struct dhcp_lease *lease, int iaid)
794 if (lease->iaid != iaid)
796 lease->iaid = iaid;
797 lease->flags |= LEASE_CHANGED;
800 #endif
802 void lease_set_hwaddr(struct dhcp_lease *lease, unsigned char *hwaddr,
803 unsigned char *clid, int hw_len, int hw_type, int clid_len,
804 time_t now, int force)
806 #ifdef HAVE_DHCP6
807 int change = force;
808 lease->flags |= LEASE_HAVE_HWADDR;
809 #endif
811 (void)force;
812 (void)now;
814 if (hw_len != lease->hwaddr_len ||
815 hw_type != lease->hwaddr_type ||
816 (hw_len != 0 && memcmp(lease->hwaddr, hwaddr, hw_len) != 0))
818 if (hw_len != 0)
819 memcpy(lease->hwaddr, hwaddr, hw_len);
820 lease->hwaddr_len = hw_len;
821 lease->hwaddr_type = hw_type;
822 lease->flags |= LEASE_CHANGED;
823 file_dirty = 1; /* run script on change */
826 /* only update clid when one is available, stops packets
827 without a clid removing the record. Lease init uses
828 clid_len == 0 for no clid. */
829 if (clid_len != 0 && clid)
831 if (!lease->clid)
832 lease->clid_len = 0;
834 if (lease->clid_len != clid_len)
836 lease->flags |= LEASE_AUX_CHANGED;
837 file_dirty = 1;
838 free(lease->clid);
839 if (!(lease->clid = whine_malloc(clid_len)))
840 return;
841 #ifdef HAVE_DHCP6
842 change = 1;
843 #endif
845 else if (memcmp(lease->clid, clid, clid_len) != 0)
847 lease->flags |= LEASE_AUX_CHANGED;
848 file_dirty = 1;
849 #ifdef HAVE_DHCP6
850 change = 1;
851 #endif
854 lease->clid_len = clid_len;
855 memcpy(lease->clid, clid, clid_len);
858 #ifdef HAVE_DHCP6
859 if (change)
860 slaac_add_addrs(lease, now, force);
861 #endif
864 static void kill_name(struct dhcp_lease *lease)
866 /* run script to say we lost our old name */
868 /* this shouldn't happen unless updates are very quick and the
869 script very slow, we just avoid a memory leak if it does. */
870 free(lease->old_hostname);
872 /* If we know the fqdn, pass that. The helper will derive the
873 unqualified name from it, free the unqualified name here. */
875 if (lease->fqdn)
877 lease->old_hostname = lease->fqdn;
878 free(lease->hostname);
880 else
881 lease->old_hostname = lease->hostname;
883 lease->hostname = lease->fqdn = NULL;
886 void lease_set_hostname(struct dhcp_lease *lease, char *name, int auth, char *domain, char *config_domain)
888 struct dhcp_lease *lease_tmp;
889 char *new_name = NULL, *new_fqdn = NULL;
891 if (config_domain && (!domain || !hostname_isequal(domain, config_domain)))
892 my_syslog(MS_DHCP | LOG_WARNING, _("Ignoring domain %s for DHCP host name %s"), config_domain, name);
894 if (lease->hostname && name && hostname_isequal(lease->hostname, name))
896 if (auth)
897 lease->flags |= LEASE_AUTH_NAME;
898 return;
901 if (!name && !lease->hostname)
902 return;
904 /* If a machine turns up on a new net without dropping the old lease,
905 or two machines claim the same name, then we end up with two interfaces with
906 the same name. Check for that here and remove the name from the old lease.
907 Note that IPv6 leases are different. All the leases to the same DUID are
908 allowed the same name.
910 Don't allow a name from the client to override a name from dnsmasq config. */
912 if (name)
914 if ((new_name = whine_malloc(strlen(name) + 1)))
916 strcpy(new_name, name);
917 if (domain && (new_fqdn = whine_malloc(strlen(new_name) + strlen(domain) + 2)))
919 strcpy(new_fqdn, name);
920 strcat(new_fqdn, ".");
921 strcat(new_fqdn, domain);
925 /* Depending on mode, we check either unqualified name or FQDN. */
926 for (lease_tmp = leases; lease_tmp; lease_tmp = lease_tmp->next)
928 if (option_bool(OPT_DHCP_FQDN))
930 if (!new_fqdn || !lease_tmp->fqdn || !hostname_isequal(lease_tmp->fqdn, new_fqdn))
931 continue;
933 else
935 if (!new_name || !lease_tmp->hostname || !hostname_isequal(lease_tmp->hostname, new_name) )
936 continue;
939 if (lease->flags & (LEASE_TA | LEASE_NA))
941 if (!(lease_tmp->flags & (LEASE_TA | LEASE_NA)))
942 continue;
944 /* another lease for the same DUID is OK for IPv6 */
945 if (lease->clid_len == lease_tmp->clid_len &&
946 lease->clid && lease_tmp->clid &&
947 memcmp(lease->clid, lease_tmp->clid, lease->clid_len) == 0)
948 continue;
950 else if (lease_tmp->flags & (LEASE_TA | LEASE_NA))
951 continue;
953 if ((lease_tmp->flags & LEASE_AUTH_NAME) && !auth)
955 free(new_name);
956 free(new_fqdn);
957 return;
960 kill_name(lease_tmp);
961 break;
965 if (lease->hostname)
966 kill_name(lease);
968 lease->hostname = new_name;
969 lease->fqdn = new_fqdn;
971 if (auth)
972 lease->flags |= LEASE_AUTH_NAME;
974 file_dirty = 1;
975 dns_dirty = 1;
976 lease->flags |= LEASE_CHANGED; /* run script on change */
979 void lease_set_interface(struct dhcp_lease *lease, int interface, time_t now)
981 (void)now;
983 if (lease->last_interface == interface)
984 return;
986 lease->last_interface = interface;
987 lease->flags |= LEASE_CHANGED;
989 #ifdef HAVE_DHCP6
990 slaac_add_addrs(lease, now, 0);
991 #endif
994 void rerun_scripts(void)
996 struct dhcp_lease *lease;
998 for (lease = leases; lease; lease = lease->next)
999 lease->flags |= LEASE_CHANGED;
1002 /* deleted leases get transferred to the old_leases list.
1003 remove them here, after calling the lease change
1004 script. Also run the lease change script on new/modified leases.
1006 Return zero if nothing to do. */
1007 int do_script_run(time_t now)
1009 struct dhcp_lease *lease;
1011 (void)now;
1013 #ifdef HAVE_DBUS
1014 /* If we're going to be sending DBus signals, but the connection is not yet up,
1015 delay everything until it is. */
1016 if (option_bool(OPT_DBUS) && !daemon->dbus)
1017 return 0;
1018 #endif
1020 if (old_leases)
1022 lease = old_leases;
1024 /* If the lease still has an old_hostname, do the "old" action on that first */
1025 if (lease->old_hostname)
1027 #ifdef HAVE_SCRIPT
1028 queue_script(ACTION_OLD_HOSTNAME, lease, lease->old_hostname, now);
1029 #endif
1030 free(lease->old_hostname);
1031 lease->old_hostname = NULL;
1032 return 1;
1034 else
1036 #ifdef HAVE_DHCP6
1037 struct slaac_address *slaac, *tmp;
1038 for (slaac = lease->slaac_address; slaac; slaac = tmp)
1040 tmp = slaac->next;
1041 free(slaac);
1043 #endif
1044 kill_name(lease);
1045 #ifdef HAVE_SCRIPT
1046 queue_script(ACTION_DEL, lease, lease->old_hostname, now);
1047 #endif
1048 #ifdef HAVE_DBUS
1049 emit_dbus_signal(ACTION_DEL, lease, lease->old_hostname);
1050 #endif
1051 old_leases = lease->next;
1053 free(lease->old_hostname);
1054 free(lease->clid);
1055 free(lease->extradata);
1056 free(lease);
1058 return 1;
1062 /* make sure we announce the loss of a hostname before its new location. */
1063 for (lease = leases; lease; lease = lease->next)
1064 if (lease->old_hostname)
1066 #ifdef HAVE_SCRIPT
1067 queue_script(ACTION_OLD_HOSTNAME, lease, lease->old_hostname, now);
1068 #endif
1069 free(lease->old_hostname);
1070 lease->old_hostname = NULL;
1071 return 1;
1074 for (lease = leases; lease; lease = lease->next)
1075 if ((lease->flags & (LEASE_NEW | LEASE_CHANGED)) ||
1076 ((lease->flags & LEASE_AUX_CHANGED) && option_bool(OPT_LEASE_RO)))
1078 #ifdef HAVE_SCRIPT
1079 queue_script((lease->flags & LEASE_NEW) ? ACTION_ADD : ACTION_OLD, lease,
1080 lease->fqdn ? lease->fqdn : lease->hostname, now);
1081 #endif
1082 #ifdef HAVE_DBUS
1083 emit_dbus_signal((lease->flags & LEASE_NEW) ? ACTION_ADD : ACTION_OLD, lease,
1084 lease->fqdn ? lease->fqdn : lease->hostname);
1085 #endif
1086 lease->flags &= ~(LEASE_NEW | LEASE_CHANGED | LEASE_AUX_CHANGED);
1088 /* this is used for the "add" call, then junked, since they're not in the database */
1089 free(lease->extradata);
1090 lease->extradata = NULL;
1092 return 1;
1095 return 0; /* nothing to do */
1098 #ifdef HAVE_SCRIPT
1099 void lease_add_extradata(struct dhcp_lease *lease, unsigned char *data, unsigned int len, int delim)
1101 unsigned int i;
1103 /* check for embeded NULLs */
1104 for (i = 0; i < len; i++)
1105 if (data[i] == 0)
1107 len = i;
1108 break;
1111 if ((lease->extradata_size - lease->extradata_len) < (len + 1))
1113 size_t newsz = lease->extradata_len + len + 100;
1114 unsigned char *new = whine_malloc(newsz);
1116 if (!new)
1117 return;
1119 if (lease->extradata)
1121 memcpy(new, lease->extradata, lease->extradata_len);
1122 free(lease->extradata);
1125 lease->extradata = new;
1126 lease->extradata_size = newsz;
1129 if (len != 0)
1130 memcpy(lease->extradata + lease->extradata_len, data, len);
1131 lease->extradata[lease->extradata_len + len] = delim;
1132 lease->extradata_len += len + 1;
1134 #endif
1136 #ifdef HAVE_TOMATO
1138 void tomato_helper(time_t now)
1140 FILE *f;
1141 struct in_addr ia;
1142 char buf[64];
1143 struct dhcp_lease *lease;
1145 // if delete exists...
1146 if ((f = fopen("/var/tmp/dhcp/delete", "r")) != NULL) {
1147 while (fgets(buf, sizeof(buf), f)) {
1148 ia.s_addr = inet_addr(buf);
1149 lease = lease_find_by_addr(ia);
1150 if (lease) {
1151 lease_prune(lease, 0);
1152 lease_update_file(now);
1155 fclose(f);
1156 unlink("/var/tmp/dhcp/delete");
1159 // dump the leases file
1160 if ((f = fopen("/var/tmp/dhcp/leases.!", "w")) != NULL) {
1161 for (lease = leases; lease; lease = lease->next) {
1162 if (lease->hwaddr_type == ARPHRD_ETHER) {
1163 #ifdef HAVE_DHCPV6 //only dump dhcpv6 if we have it
1164 if (lease->flags & (LEASE_TA | LEASE_NA))
1165 inet_ntop(AF_INET6, &lease->addr6, buf, ADDRSTRLEN);
1166 else
1167 #endif // Thanks to Shibby :-)
1168 inet_ntop(AF_INET, &lease->addr, buf, ADDRSTRLEN);
1170 fprintf(f, "%lu %02X:%02X:%02X:%02X:%02X:%02X %s %s\n",
1171 lease->expires - now,
1172 lease->hwaddr[0], lease->hwaddr[1], lease->hwaddr[2], lease->hwaddr[3], lease->hwaddr[4], lease->hwaddr[5],
1173 buf,
1174 ((lease->hostname) && (strlen(lease->hostname) > 0)) ? lease->hostname : "*");
1177 fclose(f);
1178 rename("/var/tmp/dhcp/leases.!", "/var/tmp/dhcp/leases");
1181 #endif //HAVE_TOMATO
1183 #ifdef HAVE_LEASEFILE_EXPIRE
1184 void flush_lease_file(time_t now)
1186 static time_t flush_time = (time_t)0;
1188 if(difftime(flush_time, now) < 0)
1189 file_dirty = 1;
1191 lease_prune(NULL, now);
1192 lease_update_file(now);
1194 if (file_dirty == 0)
1195 flush_time = now;
1197 #endif //HAVE_LEASEFILE_EXPIRE
1199 #endif