fix ipv6 lease remaining time in dhcp leases file. Now behaves
[tomato.git] / release / src / router / dnsmasq / src / lease.c
blob78639ab6c830ab77f6b2c0d87e1d9c9135528590
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 #ifdef HAVE_BROKEN_RTC
136 if (ei != 0)
137 lease->expires = (time_t)ei + now;
138 else
139 lease->expires = (time_t)0;
140 lease->length = ei;
141 #else
142 /* strictly time_t is opaque, but this hack should work on all sane systems,
143 even when sizeof(time_t) == 8 */
144 lease->expires = (time_t)ei;
145 #endif
147 /* set these correctly: the "old" events are generated later from
148 the startup synthesised SIGHUP. */
149 lease->flags &= ~(LEASE_NEW | LEASE_CHANGED);
152 #ifdef HAVE_SCRIPT
153 if (!daemon->lease_stream)
155 int rc = 0;
157 /* shell returns 127 for "command not found", 126 for bad permissions. */
158 if (!leasestream || (rc = pclose(leasestream)) == -1 || WEXITSTATUS(rc) == 127 || WEXITSTATUS(rc) == 126)
160 if (WEXITSTATUS(rc) == 127)
161 errno = ENOENT;
162 else if (WEXITSTATUS(rc) == 126)
163 errno = EACCES;
164 die(_("cannot run lease-init script %s: %s"), daemon->lease_change_command, EC_FILE);
167 if (WEXITSTATUS(rc) != 0)
169 sprintf(daemon->dhcp_buff, "%d", WEXITSTATUS(rc));
170 die(_("lease-init script returned exit code %s"), daemon->dhcp_buff, WEXITSTATUS(rc) + EC_INIT_OFFSET);
173 #endif
175 /* Some leases may have expired */
176 file_dirty = 0;
177 lease_prune(NULL, now);
178 dns_dirty = 1;
181 void lease_update_from_configs(void)
183 /* changes to the config may change current leases. */
185 struct dhcp_lease *lease;
186 struct dhcp_config *config;
187 char *name;
189 for (lease = leases; lease; lease = lease->next)
190 if ((config = find_config(daemon->dhcp_conf, NULL, lease->clid, lease->clid_len,
191 lease->hwaddr, lease->hwaddr_len, lease->hwaddr_type, NULL)) &&
192 (config->flags & CONFIG_NAME) &&
193 (!(config->flags & CONFIG_ADDR) || config->addr.s_addr == lease->addr.s_addr))
194 lease_set_hostname(lease, config->hostname, 1, get_domain(lease->addr), NULL);
195 else if ((name = host_from_dns(lease->addr)))
196 lease_set_hostname(lease, name, 1, get_domain(lease->addr), NULL); /* updates auth flag only */
199 static void ourprintf(int *errp, char *format, ...)
201 va_list ap;
203 va_start(ap, format);
204 if (!(*errp) && vfprintf(daemon->lease_stream, format, ap) < 0)
205 *errp = errno;
206 va_end(ap);
209 void lease_update_file(time_t now)
211 struct dhcp_lease *lease;
212 time_t next_event;
213 int i, err = 0;
215 if (file_dirty != 0 && daemon->lease_stream)
217 errno = 0;
218 rewind(daemon->lease_stream);
219 if (errno != 0 || ftruncate(fileno(daemon->lease_stream), 0) != 0)
220 err = errno;
222 for (lease = leases; lease; lease = lease->next)
225 #ifdef HAVE_DHCP6
226 if (lease->flags & (LEASE_TA | LEASE_NA))
227 continue;
228 #endif
230 #ifdef HAVE_TOMATO
231 ourprintf(&err, "%lu ", (unsigned long)lease->expires - now);
232 #else
233 #ifdef HAVE_BROKEN_RTC
234 ourprintf(&err, "%u ", lease->length);
235 #else
236 ourprintf(&err, "%lu ", (unsigned long)lease->expires);
237 #endif
238 #endif
240 if (lease->hwaddr_type != ARPHRD_ETHER || lease->hwaddr_len == 0)
241 ourprintf(&err, "%.2x-", lease->hwaddr_type);
242 for (i = 0; i < lease->hwaddr_len; i++)
244 ourprintf(&err, "%.2x", lease->hwaddr[i]);
245 if (i != lease->hwaddr_len - 1)
246 ourprintf(&err, ":");
249 inet_ntop(AF_INET, &lease->addr, daemon->addrbuff, ADDRSTRLEN);
251 ourprintf(&err, " %s ", daemon->addrbuff);
252 ourprintf(&err, "%s ", lease->hostname ? lease->hostname : "*");
254 if (lease->clid && lease->clid_len != 0)
256 for (i = 0; i < lease->clid_len - 1; i++)
257 ourprintf(&err, "%.2x:", lease->clid[i]);
258 ourprintf(&err, "%.2x\n", lease->clid[i]);
260 else
261 ourprintf(&err, "*\n");
264 #ifdef HAVE_DHCP6
265 if (daemon->duid)
267 ourprintf(&err, "duid ");
268 for (i = 0; i < daemon->duid_len - 1; i++)
269 ourprintf(&err, "%.2x:", daemon->duid[i]);
270 ourprintf(&err, "%.2x\n", daemon->duid[i]);
272 for (lease = leases; lease; lease = lease->next)
275 if (!(lease->flags & (LEASE_TA | LEASE_NA)))
276 continue;
278 #ifdef HAVE_TOMATO
279 ourprintf(&err, "%lu ", (unsigned long)lease->expires - now);
280 #else
281 #ifdef HAVE_BROKEN_RTC
282 ourprintf(&err, "%u ", lease->length);
283 #else
284 ourprintf(&err, "%lu ", (unsigned long)lease->expires);
285 #endif
286 #endif
288 inet_ntop(AF_INET6, lease->hwaddr, daemon->addrbuff, ADDRSTRLEN);
290 ourprintf(&err, "%s%u %s ", (lease->flags & LEASE_TA) ? "T" : "",
291 lease->hwaddr_type, daemon->addrbuff);
292 ourprintf(&err, "%s ", lease->hostname ? lease->hostname : "*");
294 if (lease->clid && lease->clid_len != 0)
296 for (i = 0; i < lease->clid_len - 1; i++)
297 ourprintf(&err, "%.2x:", lease->clid[i]);
298 ourprintf(&err, "%.2x\n", lease->clid[i]);
300 else
301 ourprintf(&err, "*\n");
304 #endif
306 if (fflush(daemon->lease_stream) != 0 ||
307 fsync(fileno(daemon->lease_stream)) < 0)
308 err = errno;
310 if (!err)
311 file_dirty = 0;
314 /* Set alarm for when the first lease expires + slop. */
315 next_event = 0;
317 #ifdef HAVE_DHCP6
318 /* do timed RAs and determine when the next is, also pings to potential SLAAC addresses */
319 if (daemon->doing_ra)
321 time_t event;
323 if ((event = periodic_slaac(now, leases)) != 0)
325 if (next_event == 0 || difftime(next_event, event) > 0.0)
326 next_event = event;
329 if ((event = periodic_ra(now)) != 0)
331 if (next_event == 0 || difftime(next_event, event) > 0.0)
332 next_event = event;
335 #endif
337 for (lease = leases; lease; lease = lease->next)
338 if (lease->expires != 0 &&
339 (next_event == 0 || difftime(next_event, lease->expires + 10) > 0.0))
340 next_event = lease->expires + 10;
342 if (err)
344 if (next_event == 0 || difftime(next_event, LEASE_RETRY + now) > 0.0)
345 next_event = LEASE_RETRY + now;
347 my_syslog(MS_DHCP | LOG_ERR, _("failed to write %s: %s (retry in %us)"),
348 daemon->lease_file, strerror(err),
349 (unsigned int)difftime(next_event, now));
352 send_alarm(next_event, now);
356 static int find_interface_v4(struct in_addr local, int if_index,
357 struct in_addr netmask, struct in_addr broadcast, void *vparam)
359 struct dhcp_lease *lease;
361 (void) broadcast;
362 (void) vparam;
364 for (lease = leases; lease; lease = lease->next)
365 if (!(lease->flags & (LEASE_TA | LEASE_NA)))
366 if (is_same_net(local, lease->addr, netmask))
367 lease_set_interface(lease, if_index, *((time_t *)vparam));
369 return 1;
372 #ifdef HAVE_DHCP6
373 static int find_interface_v6(struct in6_addr *local, int prefix,
374 int scope, int if_index, int flags,
375 int preferred, int valid, void *vparam)
377 struct dhcp_lease *lease;
379 (void)scope;
380 (void)flags;
381 (void)preferred;
382 (void)valid;
384 for (lease = leases; lease; lease = lease->next)
385 if ((lease->flags & (LEASE_TA | LEASE_NA)))
386 if (is_same_net6(local, (struct in6_addr *)&lease->hwaddr, prefix))
387 lease_set_interface(lease, if_index, *((time_t *)vparam));
389 return 1;
392 void lease_ping_reply(struct in6_addr *sender, unsigned char *packet, char *interface)
394 /* We may be doing RA but not DHCPv4, in which case the lease
395 database may not exist and we have nothing to do anyway */
396 if (daemon->dhcp)
397 slaac_ping_reply(sender, packet, interface, leases);
400 void lease_update_slaac(time_t now)
402 /* Called when we contruct a new RA-names context, to add putative
403 new SLAAC addresses to existing leases. */
405 struct dhcp_lease *lease;
407 if (daemon->dhcp)
408 for (lease = leases; lease; lease = lease->next)
409 slaac_add_addrs(lease, now, 0);
412 #endif
415 /* Find interfaces associated with leases at start-up. This gets updated as
416 we do DHCP transactions, but information about directly-connected subnets
417 is useful from scrips and necessary for determining SLAAC addresses from
418 start-time. */
419 void lease_find_interfaces(time_t now)
421 iface_enumerate(AF_INET, &now, find_interface_v4);
422 #ifdef HAVE_DHCP6
423 iface_enumerate(AF_INET6, &now, find_interface_v6);
425 /* If we're not doing DHCPv6, and there are not v6 leases, don't add the DUID to the database */
426 if (!daemon->duid && daemon->dhcp6)
428 file_dirty = 1;
429 make_duid(now);
431 #endif
436 void lease_update_dns(int force)
438 struct dhcp_lease *lease;
440 if (daemon->port != 0 && (dns_dirty || force))
442 #ifndef HAVE_BROKEN_RTC
443 /* force transfer to authoritative secondaries */
444 daemon->soa_sn++;
445 #endif
447 cache_unhash_dhcp();
449 for (lease = leases; lease; lease = lease->next)
451 int prot = AF_INET;
453 #ifdef HAVE_DHCP6
454 if (lease->flags & (LEASE_TA | LEASE_NA))
455 prot = AF_INET6;
456 else if (lease->hostname || lease->fqdn)
458 struct slaac_address *slaac;
460 for (slaac = lease->slaac_address; slaac; slaac = slaac->next)
461 if (slaac->backoff == 0)
463 if (lease->fqdn)
464 cache_add_dhcp_entry(lease->fqdn, AF_INET6, (struct all_addr *)&slaac->addr, lease->expires);
465 if (!option_bool(OPT_DHCP_FQDN) && lease->hostname)
466 cache_add_dhcp_entry(lease->hostname, AF_INET6, (struct all_addr *)&slaac->addr, lease->expires);
469 #endif
471 if (lease->fqdn)
472 cache_add_dhcp_entry(lease->fqdn, prot,
473 prot == AF_INET ? (struct all_addr *)&lease->addr : (struct all_addr *)&lease->hwaddr,
474 lease->expires);
476 if (!option_bool(OPT_DHCP_FQDN) && lease->hostname)
477 cache_add_dhcp_entry(lease->hostname, prot,
478 prot == AF_INET ? (struct all_addr *)&lease->addr : (struct all_addr *)&lease->hwaddr,
479 lease->expires);
482 dns_dirty = 0;
486 void lease_prune(struct dhcp_lease *target, time_t now)
488 struct dhcp_lease *lease, *tmp, **up;
490 for (lease = leases, up = &leases; lease; lease = tmp)
492 tmp = lease->next;
493 if ((lease->expires != 0 && difftime(now, lease->expires) > 0) || lease == target)
495 file_dirty = 1;
496 if (lease->hostname)
497 dns_dirty = 1;
499 *up = lease->next; /* unlink */
501 /* Put on old_leases list 'till we
502 can run the script */
503 lease->next = old_leases;
504 old_leases = lease;
506 leases_left++;
508 else
509 up = &lease->next;
514 struct dhcp_lease *lease_find_by_client(unsigned char *hwaddr, int hw_len, int hw_type,
515 unsigned char *clid, int clid_len)
517 struct dhcp_lease *lease;
519 if (clid)
520 for (lease = leases; lease; lease = lease->next)
522 #ifdef HAVE_DHCP6
523 if (lease->flags & (LEASE_TA | LEASE_NA))
524 continue;
525 #endif
526 if (lease->clid && clid_len == lease->clid_len &&
527 memcmp(clid, lease->clid, clid_len) == 0)
528 return lease;
531 for (lease = leases; lease; lease = lease->next)
533 #ifdef HAVE_DHCP6
534 if (lease->flags & (LEASE_TA | LEASE_NA))
535 continue;
536 #endif
537 if ((!lease->clid || !clid) &&
538 hw_len != 0 &&
539 lease->hwaddr_len == hw_len &&
540 lease->hwaddr_type == hw_type &&
541 memcmp(hwaddr, lease->hwaddr, hw_len) == 0)
542 return lease;
545 return NULL;
548 struct dhcp_lease *lease_find_by_addr(struct in_addr addr)
550 struct dhcp_lease *lease;
552 for (lease = leases; lease; lease = lease->next)
554 #ifdef HAVE_DHCP6
555 if (lease->flags & (LEASE_TA | LEASE_NA))
556 continue;
557 #endif
558 if (lease->addr.s_addr == addr.s_addr)
559 return lease;
562 return NULL;
565 #ifdef HAVE_DHCP6
566 /* find address for {CLID, IAID, address} */
567 struct dhcp_lease *lease6_find(unsigned char *clid, int clid_len,
568 int lease_type, int iaid, struct in6_addr *addr)
570 struct dhcp_lease *lease;
572 for (lease = leases; lease; lease = lease->next)
574 if (!(lease->flags & lease_type) || lease->hwaddr_type != iaid)
575 continue;
577 if (memcmp(lease->hwaddr, addr, IN6ADDRSZ) != 0)
578 continue;
580 if ((clid_len != lease->clid_len ||
581 memcmp(clid, lease->clid, clid_len) != 0))
582 continue;
584 return lease;
587 return NULL;
590 /* reset "USED flags */
591 void lease6_reset(void)
593 struct dhcp_lease *lease;
595 for (lease = leases; lease; lease = lease->next)
596 lease->flags &= ~LEASE_USED;
599 /* enumerate all leases belonging to {CLID, IAID} */
600 struct dhcp_lease *lease6_find_by_client(struct dhcp_lease *first, int lease_type, unsigned char *clid, int clid_len, int iaid)
602 struct dhcp_lease *lease;
604 if (!first)
605 first = leases;
606 else
607 first = first->next;
609 for (lease = first; lease; lease = lease->next)
611 if (lease->flags & LEASE_USED)
612 continue;
614 if (!(lease->flags & lease_type) || lease->hwaddr_type != iaid)
615 continue;
617 if ((clid_len != lease->clid_len ||
618 memcmp(clid, lease->clid, clid_len) != 0))
619 continue;
621 return lease;
624 return NULL;
627 struct dhcp_lease *lease6_find_by_addr(struct in6_addr *net, int prefix, u64 addr)
629 struct dhcp_lease *lease;
631 for (lease = leases; lease; lease = lease->next)
633 if (!(lease->flags & (LEASE_TA | LEASE_NA)))
634 continue;
636 if (is_same_net6((struct in6_addr *)lease->hwaddr, net, prefix) &&
637 (prefix == 128 || addr6part((struct in6_addr *)lease->hwaddr) == addr))
638 return lease;
641 return NULL;
644 /* Find largest assigned address in context */
645 u64 lease_find_max_addr6(struct dhcp_context *context)
647 struct dhcp_lease *lease;
648 u64 addr = addr6part(&context->start6);
650 if (!(context->flags & (CONTEXT_STATIC | CONTEXT_PROXY)))
651 for (lease = leases; lease; lease = lease->next)
653 if (!(lease->flags & (LEASE_TA | LEASE_NA)))
654 continue;
656 if (is_same_net6((struct in6_addr *)lease->hwaddr, &context->start6, 64) &&
657 addr6part((struct in6_addr *)lease->hwaddr) > addr6part(&context->start6) &&
658 addr6part((struct in6_addr *)lease->hwaddr) <= addr6part(&context->end6) &&
659 addr6part((struct in6_addr *)lease->hwaddr) > addr)
660 addr = addr6part((struct in6_addr *)lease->hwaddr);
663 return addr;
666 #endif
668 /* Find largest assigned address in context */
669 struct in_addr lease_find_max_addr(struct dhcp_context *context)
671 struct dhcp_lease *lease;
672 struct in_addr addr = context->start;
674 if (!(context->flags & (CONTEXT_STATIC | CONTEXT_PROXY)))
675 for (lease = leases; lease; lease = lease->next)
677 #ifdef HAVE_DHCP6
678 if (lease->flags & (LEASE_TA | LEASE_NA))
679 continue;
680 #endif
681 if (((unsigned)ntohl(lease->addr.s_addr)) > ((unsigned)ntohl(context->start.s_addr)) &&
682 ((unsigned)ntohl(lease->addr.s_addr)) <= ((unsigned)ntohl(context->end.s_addr)) &&
683 ((unsigned)ntohl(lease->addr.s_addr)) > ((unsigned)ntohl(addr.s_addr)))
684 addr = lease->addr;
687 return addr;
690 static struct dhcp_lease *lease_allocate(void)
692 struct dhcp_lease *lease;
693 if (!leases_left || !(lease = whine_malloc(sizeof(struct dhcp_lease))))
694 return NULL;
696 memset(lease, 0, sizeof(struct dhcp_lease));
697 lease->flags = LEASE_NEW;
698 lease->expires = 1;
699 #ifdef HAVE_BROKEN_RTC
700 lease->length = 0xffffffff; /* illegal value */
701 #endif
702 lease->next = leases;
703 leases = lease;
705 file_dirty = 1;
706 leases_left--;
708 return lease;
711 struct dhcp_lease *lease4_allocate(struct in_addr addr)
713 struct dhcp_lease *lease = lease_allocate();
714 if (lease)
716 lease->addr = addr;
717 lease->hwaddr_len = 256; /* illegal value */
720 return lease;
723 #ifdef HAVE_DHCP6
724 struct dhcp_lease *lease6_allocate(struct in6_addr *addrp, int lease_type)
726 struct dhcp_lease *lease = lease_allocate();
728 if (lease)
730 memcpy(lease->hwaddr, addrp, sizeof(*addrp)) ;
731 lease->flags |= lease_type;
734 return lease;
736 #endif
738 void lease_set_expires(struct dhcp_lease *lease, unsigned int len, time_t now)
740 time_t exp = now + (time_t)len;
742 if (len == 0xffffffff)
744 exp = 0;
745 len = 0;
748 if (exp != lease->expires)
750 dns_dirty = 1;
751 lease->expires = exp;
752 #ifndef HAVE_BROKEN_RTC
753 lease->flags |= LEASE_AUX_CHANGED;
754 file_dirty = 1;
755 #endif
758 #ifdef HAVE_BROKEN_RTC
759 if (len != lease->length)
761 lease->length = len;
762 lease->flags |= LEASE_AUX_CHANGED;
763 file_dirty = 1;
765 #endif
768 void lease_set_hwaddr(struct dhcp_lease *lease, unsigned char *hwaddr,
769 unsigned char *clid, int hw_len, int hw_type, int clid_len,
770 time_t now, int force)
772 #ifdef HAVE_DHCP6
773 int change = force;
774 lease->flags |= LEASE_HAVE_HWADDR;
775 #endif
777 (void)force;
779 if (hw_len != lease->hwaddr_len ||
780 hw_type != lease->hwaddr_type ||
781 (hw_len != 0 && memcmp(lease->hwaddr, hwaddr, hw_len) != 0))
783 if (hw_len != 0)
784 memcpy(lease->hwaddr, hwaddr, hw_len);
785 lease->hwaddr_len = hw_len;
786 lease->hwaddr_type = hw_type;
787 lease->flags |= LEASE_CHANGED;
788 file_dirty = 1; /* run script on change */
789 #ifdef HAVE_DHCP6
790 change = 1;
791 #endif
794 /* only update clid when one is available, stops packets
795 without a clid removing the record. Lease init uses
796 clid_len == 0 for no clid. */
797 if (clid_len != 0 && clid)
799 if (!lease->clid)
800 lease->clid_len = 0;
802 if (lease->clid_len != clid_len)
804 lease->flags |= LEASE_AUX_CHANGED;
805 file_dirty = 1;
806 free(lease->clid);
807 if (!(lease->clid = whine_malloc(clid_len)))
808 return;
809 #ifdef HAVE_DHCP6
810 change = 1;
811 #endif
813 else if (memcmp(lease->clid, clid, clid_len) != 0)
815 lease->flags |= LEASE_AUX_CHANGED;
816 file_dirty = 1;
817 #ifdef HAVE_DHCP6
818 change = 1;
819 #endif
822 lease->clid_len = clid_len;
823 memcpy(lease->clid, clid, clid_len);
826 #ifdef HAVE_DHCP6
827 if (change)
828 slaac_add_addrs(lease, now, force);
829 #endif
832 static void kill_name(struct dhcp_lease *lease)
834 /* run script to say we lost our old name */
836 /* this shouldn't happen unless updates are very quick and the
837 script very slow, we just avoid a memory leak if it does. */
838 free(lease->old_hostname);
840 /* If we know the fqdn, pass that. The helper will derive the
841 unqualified name from it, free the unqualified name here. */
843 if (lease->fqdn)
845 lease->old_hostname = lease->fqdn;
846 free(lease->hostname);
848 else
849 lease->old_hostname = lease->hostname;
851 lease->hostname = lease->fqdn = NULL;
854 void lease_set_hostname(struct dhcp_lease *lease, char *name, int auth, char *domain, char *config_domain)
856 struct dhcp_lease *lease_tmp;
857 char *new_name = NULL, *new_fqdn = NULL;
859 if (config_domain && (!domain || !hostname_isequal(domain, config_domain)))
860 my_syslog(MS_DHCP | LOG_WARNING, _("Ignoring domain %s for DHCP host name %s"), config_domain, name);
862 if (lease->hostname && name && hostname_isequal(lease->hostname, name))
864 if (auth)
865 lease->flags |= LEASE_AUTH_NAME;
866 return;
869 if (!name && !lease->hostname)
870 return;
872 /* If a machine turns up on a new net without dropping the old lease,
873 or two machines claim the same name, then we end up with two interfaces with
874 the same name. Check for that here and remove the name from the old lease.
875 Note that IPv6 leases are different. All the leases to the same DUID are
876 allowed the same name.
878 Don't allow a name from the client to override a name from dnsmasq config. */
880 if (name)
882 if ((new_name = whine_malloc(strlen(name) + 1)))
884 strcpy(new_name, name);
885 if (domain && (new_fqdn = whine_malloc(strlen(new_name) + strlen(domain) + 2)))
887 strcpy(new_fqdn, name);
888 strcat(new_fqdn, ".");
889 strcat(new_fqdn, domain);
893 /* Depending on mode, we check either unqualified name or FQDN. */
894 for (lease_tmp = leases; lease_tmp; lease_tmp = lease_tmp->next)
896 if (option_bool(OPT_DHCP_FQDN))
898 if (!new_fqdn || !lease_tmp->fqdn || !hostname_isequal(lease_tmp->fqdn, new_fqdn))
899 continue;
901 else
903 if (!new_name || !lease_tmp->hostname || !hostname_isequal(lease_tmp->hostname, new_name) )
904 continue;
907 if (lease->flags & (LEASE_TA | LEASE_NA))
909 if (!(lease_tmp->flags & (LEASE_TA | LEASE_NA)))
910 continue;
912 /* another lease for the same DUID is OK for IPv6 */
913 if (lease->clid_len == lease_tmp->clid_len &&
914 lease->clid && lease_tmp->clid &&
915 memcmp(lease->clid, lease_tmp->clid, lease->clid_len) == 0)
916 continue;
918 else if (lease_tmp->flags & (LEASE_TA | LEASE_NA))
919 continue;
921 if ((lease_tmp->flags & LEASE_AUTH_NAME) && !auth)
923 free(new_name);
924 free(new_fqdn);
925 return;
928 kill_name(lease_tmp);
929 break;
933 if (lease->hostname)
934 kill_name(lease);
936 lease->hostname = new_name;
937 lease->fqdn = new_fqdn;
939 if (auth)
940 lease->flags |= LEASE_AUTH_NAME;
942 file_dirty = 1;
943 dns_dirty = 1;
944 lease->flags |= LEASE_CHANGED; /* run script on change */
947 void lease_set_interface(struct dhcp_lease *lease, int interface, time_t now)
949 if (lease->last_interface == interface)
950 return;
952 lease->last_interface = interface;
953 lease->flags |= LEASE_CHANGED;
955 #ifdef HAVE_DHCP6
956 slaac_add_addrs(lease, now, 0);
957 #endif
960 void rerun_scripts(void)
962 struct dhcp_lease *lease;
964 for (lease = leases; lease; lease = lease->next)
965 lease->flags |= LEASE_CHANGED;
968 /* deleted leases get transferred to the old_leases list.
969 remove them here, after calling the lease change
970 script. Also run the lease change script on new/modified leases.
972 Return zero if nothing to do. */
973 int do_script_run(time_t now)
975 struct dhcp_lease *lease;
977 #ifdef HAVE_DBUS
978 /* If we're going to be sending DBus signals, but the connection is not yet up,
979 delay everything until it is. */
980 if (option_bool(OPT_DBUS) && !daemon->dbus)
981 return 0;
982 #endif
984 if (old_leases)
986 lease = old_leases;
988 /* If the lease still has an old_hostname, do the "old" action on that first */
989 if (lease->old_hostname)
991 #ifdef HAVE_SCRIPT
992 queue_script(ACTION_OLD_HOSTNAME, lease, lease->old_hostname, now);
993 #endif
994 free(lease->old_hostname);
995 lease->old_hostname = NULL;
996 return 1;
998 else
1000 #ifdef HAVE_DHCP6
1001 struct slaac_address *slaac, *tmp;
1002 for (slaac = lease->slaac_address; slaac; slaac = tmp)
1004 tmp = slaac->next;
1005 free(slaac);
1007 #endif
1008 kill_name(lease);
1009 #ifdef HAVE_SCRIPT
1010 queue_script(ACTION_DEL, lease, lease->old_hostname, now);
1011 #endif
1012 #ifdef HAVE_DBUS
1013 emit_dbus_signal(ACTION_DEL, lease, lease->old_hostname);
1014 #endif
1015 old_leases = lease->next;
1017 free(lease->old_hostname);
1018 free(lease->clid);
1019 free(lease->extradata);
1020 free(lease);
1022 return 1;
1026 /* make sure we announce the loss of a hostname before its new location. */
1027 for (lease = leases; lease; lease = lease->next)
1028 if (lease->old_hostname)
1030 #ifdef HAVE_SCRIPT
1031 queue_script(ACTION_OLD_HOSTNAME, lease, lease->old_hostname, now);
1032 #endif
1033 free(lease->old_hostname);
1034 lease->old_hostname = NULL;
1035 return 1;
1038 for (lease = leases; lease; lease = lease->next)
1039 if ((lease->flags & (LEASE_NEW | LEASE_CHANGED)) ||
1040 ((lease->flags & LEASE_AUX_CHANGED) && option_bool(OPT_LEASE_RO)))
1042 #ifdef HAVE_SCRIPT
1043 queue_script((lease->flags & LEASE_NEW) ? ACTION_ADD : ACTION_OLD, lease,
1044 lease->fqdn ? lease->fqdn : lease->hostname, now);
1045 #endif
1046 #ifdef HAVE_DBUS
1047 emit_dbus_signal((lease->flags & LEASE_NEW) ? ACTION_ADD : ACTION_OLD, lease,
1048 lease->fqdn ? lease->fqdn : lease->hostname);
1049 #endif
1050 lease->flags &= ~(LEASE_NEW | LEASE_CHANGED | LEASE_AUX_CHANGED);
1052 /* this is used for the "add" call, then junked, since they're not in the database */
1053 free(lease->extradata);
1054 lease->extradata = NULL;
1056 return 1;
1059 return 0; /* nothing to do */
1062 #ifdef HAVE_SCRIPT
1063 void lease_add_extradata(struct dhcp_lease *lease, unsigned char *data, unsigned int len, int delim)
1065 unsigned int i;
1067 /* check for embeded NULLs */
1068 for (i = 0; i < len; i++)
1069 if (data[i] == 0)
1071 len = i;
1072 break;
1075 if ((lease->extradata_size - lease->extradata_len) < (len + 1))
1077 size_t newsz = lease->extradata_len + len + 100;
1078 unsigned char *new = whine_malloc(newsz);
1080 if (!new)
1081 return;
1083 if (lease->extradata)
1085 memcpy(new, lease->extradata, lease->extradata_len);
1086 free(lease->extradata);
1089 lease->extradata = new;
1090 lease->extradata_size = newsz;
1093 if (len != 0)
1094 memcpy(lease->extradata + lease->extradata_len, data, len);
1095 lease->extradata[lease->extradata_len + len] = delim;
1096 lease->extradata_len += len + 1;
1098 #endif
1100 #ifdef HAVE_TOMATO
1102 void tomato_helper(time_t now)
1104 FILE *f;
1105 struct in_addr ia;
1106 char buf[64];
1107 struct dhcp_lease *lease;
1109 // if delete exists...
1110 if ((f = fopen("/var/tmp/dhcp/delete", "r")) != NULL) {
1111 while (fgets(buf, sizeof(buf), f)) {
1112 ia.s_addr = inet_addr(buf);
1113 lease = lease_find_by_addr(ia);
1114 if (lease) {
1115 lease_prune(lease, 0);
1116 lease_update_file(now);
1119 fclose(f);
1120 unlink("/var/tmp/dhcp/delete");
1123 // dump the leases file
1124 if ((f = fopen("/var/tmp/dhcp/leases.!", "w")) != NULL) {
1125 for (lease = leases; lease; lease = lease->next) {
1126 if (lease->hwaddr_type == ARPHRD_ETHER) {
1127 fprintf(f, "%lu %02X:%02X:%02X:%02X:%02X:%02X %s %s\n",
1128 lease->expires - now,
1129 lease->hwaddr[0], lease->hwaddr[1], lease->hwaddr[2], lease->hwaddr[3], lease->hwaddr[4], lease->hwaddr[5],
1130 inet_ntoa(lease->addr),
1131 ((lease->hostname) && (strlen(lease->hostname) > 0)) ? lease->hostname : "*");
1134 fclose(f);
1135 rename("/var/tmp/dhcp/leases.!", "/var/tmp/dhcp/leases");
1139 void flush_lease_file(time_t now)
1141 file_dirty = 1;
1142 lease_update_file(now);
1145 #endif //TOMATO
1147 #endif