]>
git.ipfire.org Git - people/ms/dnsmasq.git/blob - src/lease.c
1 /* dnsmasq is Copyright (c) 2000-2011 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/>.
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
)
28 struct dhcp_lease
*lease
;
29 int clid_len
, hw_len
, hw_type
;
35 /* These each hold a DHCP option max size 255
36 and get a terminating zero added */
37 daemon
->dhcp_buff
= safe_malloc(256);
38 daemon
->dhcp_buff2
= safe_malloc(256);
39 daemon
->dhcp_buff3
= safe_malloc(256);
41 leases_left
= daemon
->dhcp_max
;
43 if (option_bool(OPT_LEASE_RO
))
45 /* run "<lease_change_script> init" once to get the
46 initial state of the database. If leasefile-ro is
47 set without a script, we just do without any
50 if (daemon
->lease_change_command
)
52 strcpy(daemon
->dhcp_buff
, daemon
->lease_change_command
);
53 strcat(daemon
->dhcp_buff
, " init");
54 leasestream
= popen(daemon
->dhcp_buff
, "r");
59 file_dirty
= dns_dirty
= 0;
66 /* NOTE: need a+ mode to create file if it doesn't exist */
67 leasestream
= daemon
->lease_stream
= fopen(daemon
->lease_file
, "a+");
70 die(_("cannot open or create lease file %s: %s"), daemon
->lease_file
, EC_FILE
);
72 /* a+ mode leaves pointer at end. */
80 /* client-id max length is 255 which is 255*2 digits + 254 colons
81 borrow DNS packet buffer which is always larger than 1000 bytes */
83 while (fscanf(leasestream
, "%lu %255s %64s %255s %764s",
84 &ei
, daemon
->dhcp_buff2
, daemon
->namebuff
,
85 daemon
->dhcp_buff
, daemon
->packet
) == 5)
91 hw_len
= parse_hex(daemon
->dhcp_buff2
, (unsigned char *)daemon
->dhcp_buff2
, DHCP_CHADDR_MAX
, NULL
, &hw_type
);
92 /* For backwards compatibility, no explict MAC address type means ether. */
93 if (hw_type
== 0 && hw_len
!= 0)
94 hw_type
= ARPHRD_ETHER
;
99 inet_pton(AF_INET6
, daemon
->namebuff
, &addr
.addr
.addr6
);
102 inet_pton(AF_INET
, daemon
->namebuff
, &addr
.addr
.addr4
);
105 if (strcmp(daemon
->packet
, "*") != 0)
106 clid_len
= parse_hex(daemon
->packet
, (unsigned char *)daemon
->packet
, 255, NULL
, NULL
);
110 lease
= lease_allocate6(&addr
.addr
.addr6
);
113 lease
= lease_allocate4(addr
.addr
.addr4
);
116 die (_("too many stored leases"), NULL
, EC_MISC
);
118 #ifdef HAVE_BROKEN_RTC
120 lease
->expires
= (time_t)ei
+ now
;
122 lease
->expires
= (time_t)0;
125 /* strictly time_t is opaque, but this hack should work on all sane systems,
126 even when sizeof(time_t) == 8 */
127 lease
->expires
= (time_t)ei
;
133 lease_set_hwaddr(lease
, (unsigned char *)daemon
->dhcp_buff2
, (unsigned char *)daemon
->packet
, hw_len
, hw_type
, clid_len
);
135 if (strcmp(daemon
->dhcp_buff
, "*") != 0)
136 lease_set_hostname(lease
, daemon
->dhcp_buff
, 0);
138 /* set these correctly: the "old" events are generated later from
139 the startup synthesised SIGHUP. */
140 lease
->new = lease
->changed
= 0;
146 if (fscanf(leasestream
, "duid %255s", daemon
->dhcp_buff
) == 1)
148 daemon
->duid_len
= parse_hex(daemon
->dhcp_buff
, (unsigned char *)daemon
->dhcp_buff
, 130, NULL
, NULL
);
149 daemon
->duid
= safe_malloc(daemon
->duid_len
);
150 memcpy(daemon
->duid
, daemon
->dhcp_buff
, daemon
->duid_len
);
155 /* If we're not doing DHCPv6, and there are not v6 leases, don't add the DUID to the database */
162 if (!daemon
->lease_stream
)
166 /* shell returns 127 for "command not found", 126 for bad permissions. */
167 if (!leasestream
|| (rc
= pclose(leasestream
)) == -1 || WEXITSTATUS(rc
) == 127 || WEXITSTATUS(rc
) == 126)
169 if (WEXITSTATUS(rc
) == 127)
171 else if (WEXITSTATUS(rc
) == 126)
173 die(_("cannot run lease-init script %s: %s"), daemon
->lease_change_command
, EC_FILE
);
176 if (WEXITSTATUS(rc
) != 0)
178 sprintf(daemon
->dhcp_buff
, "%d", WEXITSTATUS(rc
));
179 die(_("lease-init script returned exit code %s"), daemon
->dhcp_buff
, WEXITSTATUS(rc
) + EC_INIT_OFFSET
);
184 /* Some leases may have expired */
186 lease_prune(NULL
, now
);
190 void lease_update_from_configs(void)
192 /* changes to the config may change current leases. */
194 struct dhcp_lease
*lease
;
195 struct dhcp_config
*config
;
198 for (lease
= leases
; lease
; lease
= lease
->next
)
199 if ((config
= find_config(daemon
->dhcp_conf
, NULL
, lease
->clid
, lease
->clid_len
,
200 lease
->hwaddr
, lease
->hwaddr_len
, lease
->hwaddr_type
, NULL
)) &&
201 (config
->flags
& CONFIG_NAME
) &&
202 (!(config
->flags
& CONFIG_ADDR
) || config
->addr
.s_addr
== lease
->addr
.s_addr
))
203 lease_set_hostname(lease
, config
->hostname
, 1);
204 else if ((name
= host_from_dns(lease
->addr
)))
205 lease_set_hostname(lease
, name
, 1); /* updates auth flag only */
208 static void ourprintf(int *errp
, char *format
, ...)
212 va_start(ap
, format
);
213 if (!(*errp
) && vfprintf(daemon
->lease_stream
, format
, ap
) < 0)
218 void lease_update_file(time_t now
)
220 struct dhcp_lease
*lease
;
224 if (file_dirty
!= 0 && daemon
->lease_stream
)
227 rewind(daemon
->lease_stream
);
228 if (errno
!= 0 || ftruncate(fileno(daemon
->lease_stream
), 0) != 0)
231 for (lease
= leases
; lease
; lease
= lease
->next
)
239 #ifdef HAVE_BROKEN_RTC
240 ourprintf(&err
, "%u ", lease
->length
);
242 ourprintf(&err
, "%lu ", (unsigned long)lease
->expires
);
245 if (lease
->hwaddr_type
!= ARPHRD_ETHER
|| lease
->hwaddr_len
== 0)
246 ourprintf(&err
, "%.2x-", lease
->hwaddr_type
);
247 for (i
= 0; i
< lease
->hwaddr_len
; i
++)
249 ourprintf(&err
, "%.2x", lease
->hwaddr
[i
]);
250 if (i
!= lease
->hwaddr_len
- 1)
251 ourprintf(&err
, ":");
254 inet_ntop(AF_INET
, &lease
->addr
, daemon
->addrbuff
, ADDRSTRLEN
);
256 ourprintf(&err
, " %s ", daemon
->addrbuff
);
257 ourprintf(&err
, "%s ", lease
->hostname
? lease
->hostname
: "*");
259 if (lease
->clid
&& lease
->clid_len
!= 0)
261 for (i
= 0; i
< lease
->clid_len
- 1; i
++)
262 ourprintf(&err
, "%.2x:", lease
->clid
[i
]);
263 ourprintf(&err
, "%.2x\n", lease
->clid
[i
]);
266 ourprintf(&err
, "*\n");
272 ourprintf(&err
, "duid ");
273 for (i
= 0; i
< daemon
->duid_len
- 1; i
++)
274 ourprintf(&err
, "%.2x:", daemon
->duid
[i
]);
275 ourprintf(&err
, "%.2x\n", daemon
->duid
[i
]);
277 for (lease
= leases
; lease
; lease
= lease
->next
)
283 #ifdef HAVE_BROKEN_RTC
284 ourprintf(&err
, "%u ", lease
->length
);
286 ourprintf(&err
, "%lu ", (unsigned long)lease
->expires
);
289 inet_ntop(AF_INET6
, lease
->hwaddr
, daemon
->addrbuff
, ADDRSTRLEN
);
291 ourprintf(&err
, "* %s ", 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
]);
301 ourprintf(&err
, "*\n");
306 if (fflush(daemon
->lease_stream
) != 0 ||
307 fsync(fileno(daemon
->lease_stream
)) < 0)
314 /* Set alarm for when the first lease expires + slop. */
315 for (next_event
= 0, lease
= leases
; lease
; lease
= lease
->next
)
316 if (lease
->expires
!= 0 &&
317 (next_event
== 0 || difftime(next_event
, lease
->expires
+ 10) > 0.0))
318 next_event
= lease
->expires
+ 10;
322 if (next_event
== 0 || difftime(next_event
, LEASE_RETRY
+ now
) > 0.0)
323 next_event
= LEASE_RETRY
+ now
;
325 my_syslog(MS_DHCP
| LOG_ERR
, _("failed to write %s: %s (retry in %us)"),
326 daemon
->lease_file
, strerror(err
),
327 (unsigned int)difftime(next_event
, now
));
331 alarm((unsigned)difftime(next_event
, now
));
334 void lease_update_dns(void)
336 struct dhcp_lease
*lease
;
338 if (daemon
->port
!= 0 && dns_dirty
)
342 for (lease
= leases
; lease
; lease
= lease
->next
)
345 cache_add_dhcp_entry(lease
->fqdn
, &lease
->addr
, lease
->expires
);
347 if (!option_bool(OPT_DHCP_FQDN
) && lease
->hostname
)
348 cache_add_dhcp_entry(lease
->hostname
, &lease
->addr
, lease
->expires
);
355 void lease_prune(struct dhcp_lease
*target
, time_t now
)
357 struct dhcp_lease
*lease
, *tmp
, **up
;
359 for (lease
= leases
, up
= &leases
; lease
; lease
= tmp
)
362 if ((lease
->expires
!= 0 && difftime(now
, lease
->expires
) > 0) || lease
== target
)
368 *up
= lease
->next
; /* unlink */
370 /* Put on old_leases list 'till we
371 can run the script */
372 lease
->next
= old_leases
;
383 struct dhcp_lease
*lease_find_by_client(unsigned char *hwaddr
, int hw_len
, int hw_type
,
384 unsigned char *clid
, int clid_len
)
386 struct dhcp_lease
*lease
;
389 for (lease
= leases
; lease
; lease
= lease
->next
)
395 if (lease
->clid
&& clid_len
== lease
->clid_len
&&
396 memcmp(clid
, lease
->clid
, clid_len
) == 0)
400 for (lease
= leases
; lease
; lease
= lease
->next
)
406 if ((!lease
->clid
|| !clid
) &&
408 lease
->hwaddr_len
== hw_len
&&
409 lease
->hwaddr_type
== hw_type
&&
410 memcmp(hwaddr
, lease
->hwaddr
, hw_len
) == 0)
417 struct dhcp_lease
*lease_find_by_addr(struct in_addr addr
)
419 struct dhcp_lease
*lease
;
421 for (lease
= leases
; lease
; lease
= lease
->next
)
427 if (lease
->addr
.s_addr
== addr
.s_addr
)
434 /* Find largest assigned address in context */
435 struct in_addr
lease_find_max_addr(struct dhcp_context
*context
)
437 struct dhcp_lease
*lease
;
438 struct in_addr addr
= context
->start
;
440 if (!(context
->flags
& (CONTEXT_STATIC
| CONTEXT_PROXY
)))
441 for (lease
= leases
; lease
; lease
= lease
->next
)
447 if (((unsigned)ntohl(lease
->addr
.s_addr
)) > ((unsigned)ntohl(context
->start
.s_addr
)) &&
448 ((unsigned)ntohl(lease
->addr
.s_addr
)) <= ((unsigned)ntohl(context
->end
.s_addr
)) &&
449 ((unsigned)ntohl(lease
->addr
.s_addr
)) > ((unsigned)ntohl(addr
.s_addr
)))
456 static struct dhcp_lease
*lease_allocate(void)
458 struct dhcp_lease
*lease
;
459 if (!leases_left
|| !(lease
= whine_malloc(sizeof(struct dhcp_lease
))))
462 memset(lease
, 0, sizeof(struct dhcp_lease
));
465 #ifdef HAVE_BROKEN_RTC
466 lease
->length
= 0xffffffff; /* illegal value */
468 lease
->next
= leases
;
477 struct dhcp_lease
*lease_allocate4(struct in_addr addr
)
479 struct dhcp_lease
*lease
= lease_allocate();
481 lease
->hwaddr_len
= 256; /* illegal value */
487 struct dhcp_lease
*lease_allocate6(struct in6_addr
*addrp
)
489 struct dhcp_lease
*lease
= lease_allocate();
490 memcpy(lease
->hwaddr
, addrp
, sizeof(*addrp
)) ;
497 void lease_set_expires(struct dhcp_lease
*lease
, unsigned int len
, time_t now
)
499 time_t exp
= now
+ (time_t)len
;
501 if (len
== 0xffffffff)
507 if (exp
!= lease
->expires
)
510 lease
->expires
= exp
;
511 #ifndef HAVE_BROKEN_RTC
512 lease
->aux_changed
= file_dirty
= 1;
516 #ifdef HAVE_BROKEN_RTC
517 if (len
!= lease
->length
)
520 lease
->aux_changed
= file_dirty
= 1;
525 void lease_set_hwaddr(struct dhcp_lease
*lease
, unsigned char *hwaddr
,
526 unsigned char *clid
, int hw_len
, int hw_type
, int clid_len
)
528 if (hw_len
!= lease
->hwaddr_len
||
529 hw_type
!= lease
->hwaddr_type
||
530 (hw_len
!= 0 && memcmp(lease
->hwaddr
, hwaddr
, hw_len
) != 0))
532 memcpy(lease
->hwaddr
, hwaddr
, hw_len
);
533 lease
->hwaddr_len
= hw_len
;
534 lease
->hwaddr_type
= hw_type
;
535 lease
->changed
= file_dirty
= 1; /* run script on change */
538 /* only update clid when one is available, stops packets
539 without a clid removing the record. Lease init uses
540 clid_len == 0 for no clid. */
541 if (clid_len
!= 0 && clid
)
546 if (lease
->clid_len
!= clid_len
)
548 lease
->aux_changed
= file_dirty
= 1;
550 if (!(lease
->clid
= whine_malloc(clid_len
)))
553 else if (memcmp(lease
->clid
, clid
, clid_len
) != 0)
554 lease
->aux_changed
= file_dirty
= 1;
556 lease
->clid_len
= clid_len
;
557 memcpy(lease
->clid
, clid
, clid_len
);
562 static void kill_name(struct dhcp_lease
*lease
)
564 /* run script to say we lost our old name */
566 /* this shouldn't happen unless updates are very quick and the
567 script very slow, we just avoid a memory leak if it does. */
568 free(lease
->old_hostname
);
570 /* If we know the fqdn, pass that. The helper will derive the
571 unqualified name from it, free the unqulaified name here. */
575 lease
->old_hostname
= lease
->fqdn
;
576 free(lease
->hostname
);
579 lease
->old_hostname
= lease
->hostname
;
581 lease
->hostname
= lease
->fqdn
= NULL
;
584 void lease_set_hostname(struct dhcp_lease
*lease
, char *name
, int auth
)
586 struct dhcp_lease
*lease_tmp
;
587 char *new_name
= NULL
, *new_fqdn
= NULL
;
589 if (lease
->hostname
&& name
&& hostname_isequal(lease
->hostname
, name
))
591 lease
->auth_name
= auth
;
595 if (!name
&& !lease
->hostname
)
598 /* If a machine turns up on a new net without dropping the old lease,
599 or two machines claim the same name, then we end up with two interfaces with
600 the same name. Check for that here and remove the name from the old lease.
601 Don't allow a name from the client to override a name from dnsmasq config. */
605 if ((new_name
= whine_malloc(strlen(name
) + 1)))
607 char *suffix
= get_domain(lease
->addr
);
608 strcpy(new_name
, name
);
609 if (suffix
&& (new_fqdn
= whine_malloc(strlen(new_name
) + strlen(suffix
) + 2)))
611 strcpy(new_fqdn
, name
);
612 strcat(new_fqdn
, ".");
613 strcat(new_fqdn
, suffix
);
617 /* Depending on mode, we check either unqualified name or FQDN. */
618 for (lease_tmp
= leases
; lease_tmp
; lease_tmp
= lease_tmp
->next
)
620 if (option_bool(OPT_DHCP_FQDN
))
622 if (!new_fqdn
|| !lease_tmp
->fqdn
|| !hostname_isequal(lease_tmp
->fqdn
, new_fqdn
) )
627 if (!new_name
|| !lease_tmp
->hostname
|| !hostname_isequal(lease_tmp
->hostname
, new_name
) )
631 if (lease_tmp
->auth_name
&& !auth
)
638 kill_name(lease_tmp
);
646 lease
->hostname
= new_name
;
647 lease
->fqdn
= new_fqdn
;
648 lease
->auth_name
= auth
;
652 lease
->changed
= 1; /* run script on change */
655 void lease_set_interface(struct dhcp_lease
*lease
, int interface
)
657 if (lease
->last_interface
== interface
)
660 lease
->last_interface
= interface
;
664 void rerun_scripts(void)
666 struct dhcp_lease
*lease
;
668 for (lease
= leases
; lease
; lease
= lease
->next
)
672 /* deleted leases get transferred to the old_leases list.
673 remove them here, after calling the lease change
674 script. Also run the lease change script on new/modified leases.
676 Return zero if nothing to do. */
677 int do_script_run(time_t now
)
679 struct dhcp_lease
*lease
;
682 /* If we're going to be sending DBus signals, but the connection is not yet up,
683 delay everything until it is. */
684 if (option_bool(OPT_DBUS
) && !daemon
->dbus
)
692 /* If the lease still has an old_hostname, do the "old" action on that first */
693 if (lease
->old_hostname
)
696 queue_script(ACTION_OLD_HOSTNAME
, lease
, lease
->old_hostname
, now
);
698 free(lease
->old_hostname
);
699 lease
->old_hostname
= NULL
;
706 queue_script(ACTION_DEL
, lease
, lease
->old_hostname
, now
);
709 emit_dbus_signal(ACTION_DEL
, lease
, lease
->old_hostname
);
711 old_leases
= lease
->next
;
713 free(lease
->old_hostname
);
715 free(lease
->extradata
);
722 /* make sure we announce the loss of a hostname before its new location. */
723 for (lease
= leases
; lease
; lease
= lease
->next
)
724 if (lease
->old_hostname
)
727 queue_script(ACTION_OLD_HOSTNAME
, lease
, lease
->old_hostname
, now
);
729 free(lease
->old_hostname
);
730 lease
->old_hostname
= NULL
;
734 for (lease
= leases
; lease
; lease
= lease
->next
)
735 if (lease
->new || lease
->changed
||
736 (lease
->aux_changed
&& option_bool(OPT_LEASE_RO
)))
739 queue_script(lease
->new ? ACTION_ADD
: ACTION_OLD
, lease
,
740 lease
->fqdn
? lease
->fqdn
: lease
->hostname
, now
);
743 emit_dbus_signal(lease
->new ? ACTION_ADD
: ACTION_OLD
, lease
,
744 lease
->fqdn
? lease
->fqdn
: lease
->hostname
);
746 lease
->new = lease
->changed
= lease
->aux_changed
= 0;
748 /* this is used for the "add" call, then junked, since they're not in the database */
749 free(lease
->extradata
);
750 lease
->extradata
= NULL
;
755 return 0; /* nothing to do */