]>
Commit | Line | Data |
---|---|---|
aff33962 | 1 | /* dnsmasq is Copyright (c) 2000-2015 Simon Kelley |
9e4abcb5 SK |
2 | |
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 | |
824af85b SK |
5 | the Free Software Foundation; version 2 dated June, 1991, or |
6 | (at your option) version 3 dated 29 June, 2007. | |
7 | ||
9e4abcb5 SK |
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. | |
824af85b | 12 | |
73a08a24 SK |
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/>. | |
9e4abcb5 SK |
15 | */ |
16 | ||
9e4abcb5 SK |
17 | #include "dnsmasq.h" |
18 | ||
7622fc06 SK |
19 | #ifdef HAVE_DHCP |
20 | ||
5aabfc78 | 21 | static struct dhcp_lease *leases = NULL, *old_leases = NULL; |
5e9e0efb | 22 | static int dns_dirty, file_dirty, leases_left; |
9e4abcb5 | 23 | |
5aabfc78 | 24 | void lease_init(time_t now) |
9e4abcb5 | 25 | { |
9e4abcb5 | 26 | unsigned long ei; |
c72daea8 | 27 | struct all_addr addr; |
9e4abcb5 | 28 | struct dhcp_lease *lease; |
5aabfc78 | 29 | int clid_len, hw_len, hw_type; |
208b65c5 | 30 | FILE *leasestream; |
5e9e0efb | 31 | |
3be34541 | 32 | leases_left = daemon->dhcp_max; |
ceae00dd | 33 | |
28866e95 | 34 | if (option_bool(OPT_LEASE_RO)) |
208b65c5 SK |
35 | { |
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. */ | |
1f15b81d SK |
40 | #ifdef HAVE_SCRIPT |
41 | if (daemon->lease_change_command) | |
208b65c5 | 42 | { |
1f15b81d SK |
43 | strcpy(daemon->dhcp_buff, daemon->lease_change_command); |
44 | strcat(daemon->dhcp_buff, " init"); | |
45 | leasestream = popen(daemon->dhcp_buff, "r"); | |
208b65c5 | 46 | } |
1f15b81d SK |
47 | else |
48 | #endif | |
49 | { | |
50 | file_dirty = dns_dirty = 0; | |
51 | return; | |
52 | } | |
53 | ||
208b65c5 SK |
54 | } |
55 | else | |
56 | { | |
57 | /* NOTE: need a+ mode to create file if it doesn't exist */ | |
58 | leasestream = daemon->lease_stream = fopen(daemon->lease_file, "a+"); | |
59 | ||
60 | if (!leasestream) | |
5aabfc78 | 61 | die(_("cannot open or create lease file %s: %s"), daemon->lease_file, EC_FILE); |
208b65c5 | 62 | |
7622fc06 | 63 | /* a+ mode leaves pointer at end. */ |
208b65c5 SK |
64 | rewind(leasestream); |
65 | } | |
7cebd20f | 66 | |
0a852541 SK |
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 */ | |
208b65c5 | 69 | if (leasestream) |
ceae00dd | 70 | while (fscanf(leasestream, "%255s %255s", daemon->dhcp_buff3, daemon->dhcp_buff2) == 2) |
208b65c5 | 71 | { |
3d7b550f | 72 | #ifdef HAVE_DHCP6 |
ceae00dd SK |
73 | if (strcmp(daemon->dhcp_buff3, "duid") == 0) |
74 | { | |
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; | |
79 | } | |
3d7b550f SK |
80 | #endif |
81 | ||
ceae00dd SK |
82 | ei = atol(daemon->dhcp_buff3); |
83 | ||
84 | if (fscanf(leasestream, " %64s %255s %764s", | |
85 | daemon->namebuff, daemon->dhcp_buff, daemon->packet) != 3) | |
86 | break; | |
87 | ||
88 | clid_len = 0; | |
89 | if (strcmp(daemon->packet, "*") != 0) | |
90 | clid_len = parse_hex(daemon->packet, (unsigned char *)daemon->packet, 255, NULL, NULL); | |
91 | ||
92 | if (inet_pton(AF_INET, daemon->namebuff, &addr.addr.addr4) && | |
93 | (lease = lease4_allocate(addr.addr.addr4))) | |
94 | { | |
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; | |
99 | ||
353ae4d2 | 100 | lease_set_hwaddr(lease, (unsigned char *)daemon->dhcp_buff2, (unsigned char *)daemon->packet, |
a9ab732e | 101 | hw_len, hw_type, clid_len, now, 0); |
ceae00dd SK |
102 | |
103 | if (strcmp(daemon->dhcp_buff, "*") != 0) | |
104 | lease_set_hostname(lease, daemon->dhcp_buff, 0, get_domain(lease->addr), NULL); | |
105 | } | |
c72daea8 | 106 | #ifdef HAVE_DHCP6 |
ceae00dd | 107 | else if (inet_pton(AF_INET6, daemon->namebuff, &addr.addr.addr6)) |
4cb1b320 SK |
108 | { |
109 | char *s = daemon->dhcp_buff2; | |
ceae00dd | 110 | int lease_type = LEASE_NA; |
89500e31 | 111 | int iaid; |
ceae00dd | 112 | |
4cb1b320 SK |
113 | if (s[0] == 'T') |
114 | { | |
115 | lease_type = LEASE_TA; | |
116 | s++; | |
117 | } | |
4cb1b320 | 118 | |
89500e31 | 119 | iaid = strtoul(s, NULL, 10); |
ceae00dd SK |
120 | |
121 | if ((lease = lease6_allocate(&addr.addr.addr6, lease_type))) | |
122 | { | |
89500e31 SK |
123 | lease_set_hwaddr(lease, NULL, (unsigned char *)daemon->packet, 0, 0, clid_len, now, 0); |
124 | lease_set_iaid(lease, iaid); | |
ceae00dd SK |
125 | if (strcmp(daemon->dhcp_buff, "*") != 0) |
126 | lease_set_hostname(lease, daemon->dhcp_buff, 0, get_domain6((struct in6_addr *)lease->hwaddr), NULL); | |
127 | } | |
4cb1b320 | 128 | } |
c72daea8 | 129 | #endif |
c72daea8 | 130 | else |
ceae00dd | 131 | break; |
c72daea8 | 132 | |
c72daea8 | 133 | if (!lease) |
5aabfc78 SK |
134 | die (_("too many stored leases"), NULL, EC_MISC); |
135 | ||
5e9e0efb | 136 | #ifdef HAVE_BROKEN_RTC |
208b65c5 SK |
137 | if (ei != 0) |
138 | lease->expires = (time_t)ei + now; | |
139 | else | |
140 | lease->expires = (time_t)0; | |
141 | lease->length = ei; | |
5e9e0efb | 142 | #else |
208b65c5 SK |
143 | /* strictly time_t is opaque, but this hack should work on all sane systems, |
144 | even when sizeof(time_t) == 8 */ | |
145 | lease->expires = (time_t)ei; | |
5e9e0efb | 146 | #endif |
208b65c5 | 147 | |
5aabfc78 SK |
148 | /* set these correctly: the "old" events are generated later from |
149 | the startup synthesised SIGHUP. */ | |
ceae00dd | 150 | lease->flags &= ~(LEASE_NEW | LEASE_CHANGED); |
208b65c5 SK |
151 | } |
152 | ||
1f15b81d | 153 | #ifdef HAVE_SCRIPT |
208b65c5 SK |
154 | if (!daemon->lease_stream) |
155 | { | |
156 | int rc = 0; | |
9e4abcb5 | 157 | |
208b65c5 SK |
158 | /* shell returns 127 for "command not found", 126 for bad permissions. */ |
159 | if (!leasestream || (rc = pclose(leasestream)) == -1 || WEXITSTATUS(rc) == 127 || WEXITSTATUS(rc) == 126) | |
160 | { | |
161 | if (WEXITSTATUS(rc) == 127) | |
162 | errno = ENOENT; | |
163 | else if (WEXITSTATUS(rc) == 126) | |
164 | errno = EACCES; | |
5aabfc78 | 165 | die(_("cannot run lease-init script %s: %s"), daemon->lease_change_command, EC_FILE); |
208b65c5 SK |
166 | } |
167 | ||
168 | if (WEXITSTATUS(rc) != 0) | |
169 | { | |
170 | sprintf(daemon->dhcp_buff, "%d", WEXITSTATUS(rc)); | |
5aabfc78 | 171 | die(_("lease-init script returned exit code %s"), daemon->dhcp_buff, WEXITSTATUS(rc) + EC_INIT_OFFSET); |
208b65c5 | 172 | } |
9e4abcb5 | 173 | } |
1f15b81d | 174 | #endif |
7cebd20f SK |
175 | |
176 | /* Some leases may have expired */ | |
177 | file_dirty = 0; | |
178 | lease_prune(NULL, now); | |
179 | dns_dirty = 1; | |
44a2a316 SK |
180 | } |
181 | ||
5aabfc78 | 182 | void lease_update_from_configs(void) |
44a2a316 SK |
183 | { |
184 | /* changes to the config may change current leases. */ | |
185 | ||
186 | struct dhcp_lease *lease; | |
187 | struct dhcp_config *config; | |
b8187c80 | 188 | char *name; |
4cb1b320 | 189 | |
9e4abcb5 | 190 | for (lease = leases; lease; lease = lease->next) |
89500e31 SK |
191 | if (lease->flags & (LEASE_TA | LEASE_NA)) |
192 | continue; | |
193 | else if ((config = find_config(daemon->dhcp_conf, NULL, lease->clid, lease->clid_len, | |
194 | lease->hwaddr, lease->hwaddr_len, lease->hwaddr_type, NULL)) && | |
195 | (config->flags & CONFIG_NAME) && | |
196 | (!(config->flags & CONFIG_ADDR) || config->addr.s_addr == lease->addr.s_addr)) | |
70c5e3e0 | 197 | lease_set_hostname(lease, config->hostname, 1, get_domain(lease->addr), NULL); |
5aabfc78 | 198 | else if ((name = host_from_dns(lease->addr))) |
70c5e3e0 | 199 | lease_set_hostname(lease, name, 1, get_domain(lease->addr), NULL); /* updates auth flag only */ |
9e4abcb5 | 200 | } |
4cb1b320 | 201 | |
5aabfc78 | 202 | static void ourprintf(int *errp, char *format, ...) |
9e4abcb5 | 203 | { |
7cebd20f | 204 | va_list ap; |
5e9e0efb | 205 | |
7cebd20f SK |
206 | va_start(ap, format); |
207 | if (!(*errp) && vfprintf(daemon->lease_stream, format, ap) < 0) | |
208 | *errp = errno; | |
209 | va_end(ap); | |
210 | } | |
211 | ||
5aabfc78 | 212 | void lease_update_file(time_t now) |
7cebd20f SK |
213 | { |
214 | struct dhcp_lease *lease; | |
215 | time_t next_event; | |
216 | int i, err = 0; | |
217 | ||
208b65c5 | 218 | if (file_dirty != 0 && daemon->lease_stream) |
9e4abcb5 | 219 | { |
cdeda28f SK |
220 | errno = 0; |
221 | rewind(daemon->lease_stream); | |
222 | if (errno != 0 || ftruncate(fileno(daemon->lease_stream), 0) != 0) | |
7cebd20f | 223 | err = errno; |
9e4abcb5 SK |
224 | |
225 | for (lease = leases; lease; lease = lease->next) | |
226 | { | |
c72daea8 SK |
227 | |
228 | #ifdef HAVE_DHCP6 | |
4cb1b320 | 229 | if (lease->flags & (LEASE_TA | LEASE_NA)) |
c72daea8 SK |
230 | continue; |
231 | #endif | |
232 | ||
44a2a316 | 233 | #ifdef HAVE_BROKEN_RTC |
5aabfc78 | 234 | ourprintf(&err, "%u ", lease->length); |
44a2a316 | 235 | #else |
5aabfc78 | 236 | ourprintf(&err, "%lu ", (unsigned long)lease->expires); |
5e9e0efb | 237 | #endif |
c72daea8 | 238 | |
7cebd20f | 239 | if (lease->hwaddr_type != ARPHRD_ETHER || lease->hwaddr_len == 0) |
5aabfc78 | 240 | ourprintf(&err, "%.2x-", lease->hwaddr_type); |
5e9e0efb SK |
241 | for (i = 0; i < lease->hwaddr_len; i++) |
242 | { | |
5aabfc78 | 243 | ourprintf(&err, "%.2x", lease->hwaddr[i]); |
7cebd20f | 244 | if (i != lease->hwaddr_len - 1) |
5aabfc78 | 245 | ourprintf(&err, ":"); |
5e9e0efb | 246 | } |
c72daea8 SK |
247 | |
248 | inet_ntop(AF_INET, &lease->addr, daemon->addrbuff, ADDRSTRLEN); | |
5aabfc78 | 249 | |
c72daea8 | 250 | ourprintf(&err, " %s ", daemon->addrbuff); |
1f15b81d SK |
251 | ourprintf(&err, "%s ", lease->hostname ? lease->hostname : "*"); |
252 | ||
0a852541 | 253 | if (lease->clid && lease->clid_len != 0) |
9e4abcb5 SK |
254 | { |
255 | for (i = 0; i < lease->clid_len - 1; i++) | |
5aabfc78 SK |
256 | ourprintf(&err, "%.2x:", lease->clid[i]); |
257 | ourprintf(&err, "%.2x\n", lease->clid[i]); | |
9e4abcb5 SK |
258 | } |
259 | else | |
5aabfc78 | 260 | ourprintf(&err, "*\n"); |
9e4abcb5 | 261 | } |
7cebd20f | 262 | |
c72daea8 SK |
263 | #ifdef HAVE_DHCP6 |
264 | if (daemon->duid) | |
265 | { | |
266 | ourprintf(&err, "duid "); | |
267 | for (i = 0; i < daemon->duid_len - 1; i++) | |
268 | ourprintf(&err, "%.2x:", daemon->duid[i]); | |
269 | ourprintf(&err, "%.2x\n", daemon->duid[i]); | |
270 | ||
271 | for (lease = leases; lease; lease = lease->next) | |
272 | { | |
273 | ||
4cb1b320 | 274 | if (!(lease->flags & (LEASE_TA | LEASE_NA))) |
c72daea8 SK |
275 | continue; |
276 | ||
277 | #ifdef HAVE_BROKEN_RTC | |
278 | ourprintf(&err, "%u ", lease->length); | |
279 | #else | |
280 | ourprintf(&err, "%lu ", (unsigned long)lease->expires); | |
281 | #endif | |
282 | ||
89500e31 | 283 | inet_ntop(AF_INET6, &lease->addr6, daemon->addrbuff, ADDRSTRLEN); |
c72daea8 | 284 | |
4cb1b320 | 285 | ourprintf(&err, "%s%u %s ", (lease->flags & LEASE_TA) ? "T" : "", |
89500e31 | 286 | lease->iaid, daemon->addrbuff); |
c72daea8 SK |
287 | ourprintf(&err, "%s ", lease->hostname ? lease->hostname : "*"); |
288 | ||
289 | if (lease->clid && lease->clid_len != 0) | |
290 | { | |
291 | for (i = 0; i < lease->clid_len - 1; i++) | |
292 | ourprintf(&err, "%.2x:", lease->clid[i]); | |
293 | ourprintf(&err, "%.2x\n", lease->clid[i]); | |
294 | } | |
295 | else | |
296 | ourprintf(&err, "*\n"); | |
297 | } | |
298 | } | |
299 | #endif | |
300 | ||
7cebd20f SK |
301 | if (fflush(daemon->lease_stream) != 0 || |
302 | fsync(fileno(daemon->lease_stream)) < 0) | |
303 | err = errno; | |
304 | ||
305 | if (!err) | |
306 | file_dirty = 0; | |
307 | } | |
308 | ||
dd0e0a39 | 309 | /* Set alarm for when the first lease expires. */ |
c5ad4e79 SK |
310 | next_event = 0; |
311 | ||
312 | #ifdef HAVE_DHCP6 | |
353ae4d2 | 313 | /* do timed RAs and determine when the next is, also pings to potential SLAAC addresses */ |
1f776932 | 314 | if (daemon->doing_ra) |
353ae4d2 | 315 | { |
919dd7cf | 316 | time_t event; |
353ae4d2 | 317 | |
919dd7cf SK |
318 | if ((event = periodic_slaac(now, leases)) != 0) |
319 | { | |
320 | if (next_event == 0 || difftime(next_event, event) > 0.0) | |
321 | next_event = event; | |
322 | } | |
353ae4d2 | 323 | |
919dd7cf SK |
324 | if ((event = periodic_ra(now)) != 0) |
325 | { | |
326 | if (next_event == 0 || difftime(next_event, event) > 0.0) | |
327 | next_event = event; | |
328 | } | |
353ae4d2 | 329 | } |
c5ad4e79 SK |
330 | #endif |
331 | ||
332 | for (lease = leases; lease; lease = lease->next) | |
7cebd20f | 333 | if (lease->expires != 0 && |
dd0e0a39 SK |
334 | (next_event == 0 || difftime(next_event, lease->expires) > 0.0)) |
335 | next_event = lease->expires; | |
7cebd20f SK |
336 | |
337 | if (err) | |
338 | { | |
339 | if (next_event == 0 || difftime(next_event, LEASE_RETRY + now) > 0.0) | |
340 | next_event = LEASE_RETRY + now; | |
341 | ||
7622fc06 | 342 | my_syslog(MS_DHCP | LOG_ERR, _("failed to write %s: %s (retry in %us)"), |
f2621c7f SK |
343 | daemon->lease_file, strerror(err), |
344 | (unsigned int)difftime(next_event, now)); | |
9e4abcb5 | 345 | } |
7cebd20f | 346 | |
353ae4d2 | 347 | send_alarm(next_event, now); |
44a2a316 | 348 | } |
9e4abcb5 | 349 | |
801ca9a7 | 350 | |
3f2873d4 | 351 | static int find_interface_v4(struct in_addr local, int if_index, char *label, |
801ca9a7 | 352 | struct in_addr netmask, struct in_addr broadcast, void *vparam) |
44a2a316 SK |
353 | { |
354 | struct dhcp_lease *lease; | |
6d8e8ac0 | 355 | int prefix = netmask_length(netmask); |
dc8a1b1b | 356 | |
3f2873d4 | 357 | (void) label; |
801ca9a7 SK |
358 | (void) broadcast; |
359 | (void) vparam; | |
360 | ||
361 | for (lease = leases; lease; lease = lease->next) | |
6d8e8ac0 SK |
362 | if (!(lease->flags & (LEASE_TA | LEASE_NA)) && |
363 | is_same_net(local, lease->addr, netmask) && | |
364 | prefix > lease->new_prefixlen) | |
365 | { | |
366 | lease->new_interface = if_index; | |
dc8a1b1b LPC |
367 | lease->new_prefixlen = prefix; |
368 | } | |
dc8a1b1b | 369 | |
801ca9a7 SK |
370 | return 1; |
371 | } | |
372 | ||
373 | #ifdef HAVE_DHCP6 | |
374 | static int find_interface_v6(struct in6_addr *local, int prefix, | |
bad7b875 | 375 | int scope, int if_index, int flags, |
1f776932 | 376 | int preferred, int valid, void *vparam) |
801ca9a7 SK |
377 | { |
378 | struct dhcp_lease *lease; | |
dc8a1b1b | 379 | |
353ae4d2 | 380 | (void)scope; |
bad7b875 | 381 | (void)flags; |
1f776932 SK |
382 | (void)preferred; |
383 | (void)valid; | |
dc8a1b1b | 384 | (void)vparam; |
801ca9a7 SK |
385 | |
386 | for (lease = leases; lease; lease = lease->next) | |
387 | if ((lease->flags & (LEASE_TA | LEASE_NA))) | |
dc8a1b1b LPC |
388 | if (is_same_net6(local, &lease->addr6, prefix) && prefix > lease->new_prefixlen) { |
389 | /* save prefix length for comparison, as we might get shorter matching | |
390 | * prefix in upcoming netlink GETADDR responses | |
391 | * */ | |
392 | lease->new_interface = if_index; | |
393 | lease->new_prefixlen = prefix; | |
394 | } | |
395 | ||
801ca9a7 SK |
396 | return 1; |
397 | } | |
353ae4d2 SK |
398 | |
399 | void lease_ping_reply(struct in6_addr *sender, unsigned char *packet, char *interface) | |
400 | { | |
5ef33279 SK |
401 | /* We may be doing RA but not DHCPv4, in which case the lease |
402 | database may not exist and we have nothing to do anyway */ | |
403 | if (daemon->dhcp) | |
404 | slaac_ping_reply(sender, packet, interface, leases); | |
353ae4d2 SK |
405 | } |
406 | ||
0c050242 SK |
407 | void lease_update_slaac(time_t now) |
408 | { | |
409 | /* Called when we contruct a new RA-names context, to add putative | |
410 | new SLAAC addresses to existing leases. */ | |
411 | ||
412 | struct dhcp_lease *lease; | |
413 | ||
414 | if (daemon->dhcp) | |
415 | for (lease = leases; lease; lease = lease->next) | |
416 | slaac_add_addrs(lease, now, 0); | |
417 | } | |
418 | ||
801ca9a7 SK |
419 | #endif |
420 | ||
421 | ||
422 | /* Find interfaces associated with leases at start-up. This gets updated as | |
423 | we do DHCP transactions, but information about directly-connected subnets | |
424 | is useful from scrips and necessary for determining SLAAC addresses from | |
425 | start-time. */ | |
8b372704 | 426 | void lease_find_interfaces(time_t now) |
801ca9a7 | 427 | { |
6d8e8ac0 SK |
428 | struct dhcp_lease *lease; |
429 | ||
430 | for (lease = leases; lease; lease = lease->next) | |
431 | lease->new_prefixlen = lease->new_interface = 0; | |
432 | ||
353ae4d2 SK |
433 | iface_enumerate(AF_INET, &now, find_interface_v4); |
434 | #ifdef HAVE_DHCP6 | |
435 | iface_enumerate(AF_INET6, &now, find_interface_v6); | |
3511a928 | 436 | #endif |
6d8e8ac0 SK |
437 | |
438 | for (lease = leases; lease; lease = lease->next) | |
439 | if (lease->new_interface != 0) | |
440 | lease_set_interface(lease, lease->new_interface, now); | |
3511a928 | 441 | } |
8b372704 | 442 | |
3511a928 SK |
443 | #ifdef HAVE_DHCP6 |
444 | void lease_make_duid(time_t now) | |
445 | { | |
8b372704 | 446 | /* If we're not doing DHCPv6, and there are not v6 leases, don't add the DUID to the database */ |
3511a928 | 447 | if (!daemon->duid && daemon->doing_dhcp6) |
8b372704 SK |
448 | { |
449 | file_dirty = 1; | |
450 | make_duid(now); | |
451 | } | |
801ca9a7 | 452 | } |
3511a928 SK |
453 | #endif |
454 | ||
801ca9a7 SK |
455 | |
456 | ||
457 | ||
353ae4d2 | 458 | void lease_update_dns(int force) |
801ca9a7 SK |
459 | { |
460 | struct dhcp_lease *lease; | |
461 | ||
353ae4d2 | 462 | if (daemon->port != 0 && (dns_dirty || force)) |
9e4abcb5 | 463 | { |
8ff55673 | 464 | #ifndef HAVE_BROKEN_RTC |
e1ff419c SK |
465 | /* force transfer to authoritative secondaries */ |
466 | daemon->soa_sn++; | |
8ff55673 | 467 | #endif |
e1ff419c | 468 | |
801ca9a7 SK |
469 | cache_unhash_dhcp(); |
470 | ||
9e4abcb5 SK |
471 | for (lease = leases; lease; lease = lease->next) |
472 | { | |
4cb1b320 | 473 | int prot = AF_INET; |
801ca9a7 | 474 | |
4cb1b320 SK |
475 | #ifdef HAVE_DHCP6 |
476 | if (lease->flags & (LEASE_TA | LEASE_NA)) | |
477 | prot = AF_INET6; | |
f444cddb | 478 | else if (lease->hostname || lease->fqdn) |
801ca9a7 | 479 | { |
353ae4d2 SK |
480 | struct slaac_address *slaac; |
481 | ||
482 | for (slaac = lease->slaac_address; slaac; slaac = slaac->next) | |
483 | if (slaac->backoff == 0) | |
801ca9a7 | 484 | { |
801ca9a7 | 485 | if (lease->fqdn) |
353ae4d2 | 486 | cache_add_dhcp_entry(lease->fqdn, AF_INET6, (struct all_addr *)&slaac->addr, lease->expires); |
801ca9a7 | 487 | if (!option_bool(OPT_DHCP_FQDN) && lease->hostname) |
353ae4d2 | 488 | cache_add_dhcp_entry(lease->hostname, AF_INET6, (struct all_addr *)&slaac->addr, lease->expires); |
801ca9a7 SK |
489 | } |
490 | } | |
4cb1b320 | 491 | |
9009d746 | 492 | if (lease->fqdn) |
4cb1b320 | 493 | cache_add_dhcp_entry(lease->fqdn, prot, |
89500e31 | 494 | prot == AF_INET ? (struct all_addr *)&lease->addr : (struct all_addr *)&lease->addr6, |
4cb1b320 | 495 | lease->expires); |
9009d746 | 496 | |
28866e95 | 497 | if (!option_bool(OPT_DHCP_FQDN) && lease->hostname) |
4cb1b320 | 498 | cache_add_dhcp_entry(lease->hostname, prot, |
89500e31 | 499 | prot == AF_INET ? (struct all_addr *)&lease->addr : (struct all_addr *)&lease->addr6, |
4cb1b320 | 500 | lease->expires); |
91543f48 SK |
501 | |
502 | #else | |
503 | if (lease->fqdn) | |
504 | cache_add_dhcp_entry(lease->fqdn, prot, (struct all_addr *)&lease->addr, lease->expires); | |
505 | ||
506 | if (!option_bool(OPT_DHCP_FQDN) && lease->hostname) | |
507 | cache_add_dhcp_entry(lease->hostname, prot, (struct all_addr *)&lease->addr, lease->expires); | |
508 | #endif | |
9e4abcb5 SK |
509 | } |
510 | ||
511 | dns_dirty = 0; | |
512 | } | |
513 | } | |
514 | ||
515 | void lease_prune(struct dhcp_lease *target, time_t now) | |
516 | { | |
517 | struct dhcp_lease *lease, *tmp, **up; | |
518 | ||
519 | for (lease = leases, up = &leases; lease; lease = tmp) | |
520 | { | |
521 | tmp = lease->next; | |
522 | if ((lease->expires != 0 && difftime(now, lease->expires) > 0) || lease == target) | |
523 | { | |
5e9e0efb | 524 | file_dirty = 1; |
9e4abcb5 | 525 | if (lease->hostname) |
7cebd20f SK |
526 | dns_dirty = 1; |
527 | ||
c72daea8 | 528 | *up = lease->next; /* unlink */ |
7cebd20f SK |
529 | |
530 | /* Put on old_leases list 'till we | |
531 | can run the script */ | |
532 | lease->next = old_leases; | |
533 | old_leases = lease; | |
534 | ||
44a2a316 | 535 | leases_left++; |
9e4abcb5 SK |
536 | } |
537 | else | |
538 | up = &lease->next; | |
539 | } | |
540 | } | |
541 | ||
542 | ||
cdeda28f | 543 | struct dhcp_lease *lease_find_by_client(unsigned char *hwaddr, int hw_len, int hw_type, |
0a852541 | 544 | unsigned char *clid, int clid_len) |
9e4abcb5 | 545 | { |
9e4abcb5 SK |
546 | struct dhcp_lease *lease; |
547 | ||
0a852541 SK |
548 | if (clid) |
549 | for (lease = leases; lease; lease = lease->next) | |
c72daea8 SK |
550 | { |
551 | #ifdef HAVE_DHCP6 | |
4cb1b320 | 552 | if (lease->flags & (LEASE_TA | LEASE_NA)) |
c72daea8 SK |
553 | continue; |
554 | #endif | |
555 | if (lease->clid && clid_len == lease->clid_len && | |
556 | memcmp(clid, lease->clid, clid_len) == 0) | |
557 | return lease; | |
558 | } | |
0a852541 SK |
559 | |
560 | for (lease = leases; lease; lease = lease->next) | |
c72daea8 SK |
561 | { |
562 | #ifdef HAVE_DHCP6 | |
4cb1b320 | 563 | if (lease->flags & (LEASE_TA | LEASE_NA)) |
c72daea8 SK |
564 | continue; |
565 | #endif | |
566 | if ((!lease->clid || !clid) && | |
567 | hw_len != 0 && | |
568 | lease->hwaddr_len == hw_len && | |
569 | lease->hwaddr_type == hw_type && | |
570 | memcmp(hwaddr, lease->hwaddr, hw_len) == 0) | |
571 | return lease; | |
572 | } | |
573 | ||
9e4abcb5 SK |
574 | return NULL; |
575 | } | |
576 | ||
577 | struct dhcp_lease *lease_find_by_addr(struct in_addr addr) | |
578 | { | |
579 | struct dhcp_lease *lease; | |
580 | ||
581 | for (lease = leases; lease; lease = lease->next) | |
c72daea8 SK |
582 | { |
583 | #ifdef HAVE_DHCP6 | |
4cb1b320 | 584 | if (lease->flags & (LEASE_TA | LEASE_NA)) |
c72daea8 SK |
585 | continue; |
586 | #endif | |
587 | if (lease->addr.s_addr == addr.s_addr) | |
588 | return lease; | |
589 | } | |
590 | ||
9e4abcb5 SK |
591 | return NULL; |
592 | } | |
593 | ||
52b92f4d | 594 | #ifdef HAVE_DHCP6 |
a6ebfacf | 595 | /* find address for {CLID, IAID, address} */ |
4cb1b320 SK |
596 | struct dhcp_lease *lease6_find(unsigned char *clid, int clid_len, |
597 | int lease_type, int iaid, struct in6_addr *addr) | |
52b92f4d SK |
598 | { |
599 | struct dhcp_lease *lease; | |
600 | ||
601 | for (lease = leases; lease; lease = lease->next) | |
602 | { | |
89500e31 | 603 | if (!(lease->flags & lease_type) || lease->iaid != iaid) |
4cb1b320 | 604 | continue; |
52b92f4d | 605 | |
89500e31 | 606 | if (!IN6_ARE_ADDR_EQUAL(&lease->addr6, addr)) |
4cb1b320 SK |
607 | continue; |
608 | ||
a6ebfacf | 609 | if ((clid_len != lease->clid_len || |
4cb1b320 SK |
610 | memcmp(clid, lease->clid, clid_len) != 0)) |
611 | continue; | |
612 | ||
8b46061e | 613 | return lease; |
52b92f4d SK |
614 | } |
615 | ||
616 | return NULL; | |
617 | } | |
618 | ||
a6ebfacf SK |
619 | /* reset "USED flags */ |
620 | void lease6_reset(void) | |
8b46061e SK |
621 | { |
622 | struct dhcp_lease *lease; | |
623 | ||
624 | for (lease = leases; lease; lease = lease->next) | |
a6ebfacf SK |
625 | lease->flags &= ~LEASE_USED; |
626 | } | |
627 | ||
628 | /* enumerate all leases belonging to {CLID, IAID} */ | |
629 | struct dhcp_lease *lease6_find_by_client(struct dhcp_lease *first, int lease_type, unsigned char *clid, int clid_len, int iaid) | |
630 | { | |
631 | struct dhcp_lease *lease; | |
632 | ||
633 | if (!first) | |
634 | first = leases; | |
27cb314e SK |
635 | else |
636 | first = first->next; | |
a6ebfacf SK |
637 | |
638 | for (lease = first; lease; lease = lease->next) | |
8b46061e | 639 | { |
a6ebfacf SK |
640 | if (lease->flags & LEASE_USED) |
641 | continue; | |
642 | ||
89500e31 | 643 | if (!(lease->flags & lease_type) || lease->iaid != iaid) |
8b46061e | 644 | continue; |
a6ebfacf SK |
645 | |
646 | if ((clid_len != lease->clid_len || | |
647 | memcmp(clid, lease->clid, clid_len) != 0)) | |
648 | continue; | |
649 | ||
650 | return lease; | |
8b46061e | 651 | } |
a6ebfacf SK |
652 | |
653 | return NULL; | |
8b46061e SK |
654 | } |
655 | ||
52b92f4d SK |
656 | struct dhcp_lease *lease6_find_by_addr(struct in6_addr *net, int prefix, u64 addr) |
657 | { | |
658 | struct dhcp_lease *lease; | |
4cb1b320 | 659 | |
52b92f4d SK |
660 | for (lease = leases; lease; lease = lease->next) |
661 | { | |
4cb1b320 | 662 | if (!(lease->flags & (LEASE_TA | LEASE_NA))) |
52b92f4d | 663 | continue; |
4cb1b320 | 664 | |
89500e31 SK |
665 | if (is_same_net6(&lease->addr6, net, prefix) && |
666 | (prefix == 128 || addr6part(&lease->addr6) == addr)) | |
52b92f4d SK |
667 | return lease; |
668 | } | |
669 | ||
670 | return NULL; | |
0793380b SK |
671 | } |
672 | ||
673 | /* Find largest assigned address in context */ | |
674 | u64 lease_find_max_addr6(struct dhcp_context *context) | |
675 | { | |
676 | struct dhcp_lease *lease; | |
677 | u64 addr = addr6part(&context->start6); | |
678 | ||
679 | if (!(context->flags & (CONTEXT_STATIC | CONTEXT_PROXY))) | |
680 | for (lease = leases; lease; lease = lease->next) | |
681 | { | |
0793380b SK |
682 | if (!(lease->flags & (LEASE_TA | LEASE_NA))) |
683 | continue; | |
6caacacf | 684 | |
89500e31 SK |
685 | if (is_same_net6(&lease->addr6, &context->start6, 64) && |
686 | addr6part(&lease->addr6) > addr6part(&context->start6) && | |
687 | addr6part(&lease->addr6) <= addr6part(&context->end6) && | |
688 | addr6part(&lease->addr6) > addr) | |
689 | addr = addr6part(&lease->addr6); | |
0793380b SK |
690 | } |
691 | ||
692 | return addr; | |
693 | } | |
694 | ||
52b92f4d SK |
695 | #endif |
696 | ||
7de060b0 SK |
697 | /* Find largest assigned address in context */ |
698 | struct in_addr lease_find_max_addr(struct dhcp_context *context) | |
699 | { | |
700 | struct dhcp_lease *lease; | |
701 | struct in_addr addr = context->start; | |
702 | ||
703 | if (!(context->flags & (CONTEXT_STATIC | CONTEXT_PROXY))) | |
704 | for (lease = leases; lease; lease = lease->next) | |
c72daea8 SK |
705 | { |
706 | #ifdef HAVE_DHCP6 | |
4cb1b320 | 707 | if (lease->flags & (LEASE_TA | LEASE_NA)) |
c72daea8 SK |
708 | continue; |
709 | #endif | |
710 | if (((unsigned)ntohl(lease->addr.s_addr)) > ((unsigned)ntohl(context->start.s_addr)) && | |
711 | ((unsigned)ntohl(lease->addr.s_addr)) <= ((unsigned)ntohl(context->end.s_addr)) && | |
712 | ((unsigned)ntohl(lease->addr.s_addr)) > ((unsigned)ntohl(addr.s_addr))) | |
713 | addr = lease->addr; | |
714 | } | |
7de060b0 SK |
715 | |
716 | return addr; | |
717 | } | |
9e4abcb5 | 718 | |
c72daea8 | 719 | static struct dhcp_lease *lease_allocate(void) |
9e4abcb5 SK |
720 | { |
721 | struct dhcp_lease *lease; | |
5aabfc78 | 722 | if (!leases_left || !(lease = whine_malloc(sizeof(struct dhcp_lease)))) |
9e4abcb5 SK |
723 | return NULL; |
724 | ||
7cebd20f | 725 | memset(lease, 0, sizeof(struct dhcp_lease)); |
4cb1b320 | 726 | lease->flags = LEASE_NEW; |
9e4abcb5 | 727 | lease->expires = 1; |
5e9e0efb SK |
728 | #ifdef HAVE_BROKEN_RTC |
729 | lease->length = 0xffffffff; /* illegal value */ | |
730 | #endif | |
89500e31 | 731 | lease->hwaddr_len = 256; /* illegal value */ |
9e4abcb5 SK |
732 | lease->next = leases; |
733 | leases = lease; | |
734 | ||
5e9e0efb | 735 | file_dirty = 1; |
44a2a316 | 736 | leases_left--; |
9e4abcb5 SK |
737 | |
738 | return lease; | |
739 | } | |
740 | ||
52b92f4d | 741 | struct dhcp_lease *lease4_allocate(struct in_addr addr) |
c72daea8 SK |
742 | { |
743 | struct dhcp_lease *lease = lease_allocate(); | |
0b0a73c1 | 744 | if (lease) |
89500e31 SK |
745 | lease->addr = addr; |
746 | ||
c72daea8 SK |
747 | return lease; |
748 | } | |
749 | ||
750 | #ifdef HAVE_DHCP6 | |
4cb1b320 | 751 | struct dhcp_lease *lease6_allocate(struct in6_addr *addrp, int lease_type) |
c72daea8 SK |
752 | { |
753 | struct dhcp_lease *lease = lease_allocate(); | |
0b0a73c1 SK |
754 | |
755 | if (lease) | |
756 | { | |
89500e31 | 757 | lease->addr6 = *addrp; |
0b0a73c1 | 758 | lease->flags |= lease_type; |
89500e31 | 759 | lease->iaid = 0; |
0b0a73c1 | 760 | } |
c72daea8 SK |
761 | |
762 | return lease; | |
763 | } | |
764 | #endif | |
765 | ||
5e9e0efb | 766 | void lease_set_expires(struct dhcp_lease *lease, unsigned int len, time_t now) |
9e4abcb5 | 767 | { |
dd0e0a39 SK |
768 | time_t exp; |
769 | ||
5e9e0efb SK |
770 | if (len == 0xffffffff) |
771 | { | |
772 | exp = 0; | |
773 | len = 0; | |
774 | } | |
dd0e0a39 SK |
775 | else |
776 | { | |
777 | exp = now + (time_t)len; | |
778 | /* Check for 2038 overflow. Make the lease | |
779 | inifinite in that case, as the least disruptive | |
780 | thing we can do. */ | |
781 | if (difftime(exp, now) <= 0.0) | |
782 | exp = 0; | |
783 | } | |
784 | ||
9e4abcb5 | 785 | if (exp != lease->expires) |
0a852541 | 786 | { |
0a852541 | 787 | dns_dirty = 1; |
5e9e0efb SK |
788 | lease->expires = exp; |
789 | #ifndef HAVE_BROKEN_RTC | |
4cb1b320 SK |
790 | lease->flags |= LEASE_AUX_CHANGED; |
791 | file_dirty = 1; | |
5e9e0efb | 792 | #endif |
0a852541 | 793 | } |
5e9e0efb SK |
794 | |
795 | #ifdef HAVE_BROKEN_RTC | |
796 | if (len != lease->length) | |
797 | { | |
798 | lease->length = len; | |
b7f40201 SK |
799 | lease->flags |= LEASE_AUX_CHANGED; |
800 | file_dirty = 1; | |
5e9e0efb SK |
801 | } |
802 | #endif | |
803 | } | |
9e4abcb5 | 804 | |
89500e31 SK |
805 | #ifdef HAVE_DHCP6 |
806 | void lease_set_iaid(struct dhcp_lease *lease, int iaid) | |
807 | { | |
808 | if (lease->iaid != iaid) | |
809 | { | |
810 | lease->iaid = iaid; | |
811 | lease->flags |= LEASE_CHANGED; | |
812 | } | |
813 | } | |
814 | #endif | |
815 | ||
7cebd20f | 816 | void lease_set_hwaddr(struct dhcp_lease *lease, unsigned char *hwaddr, |
a9ab732e SK |
817 | unsigned char *clid, int hw_len, int hw_type, int clid_len, |
818 | time_t now, int force) | |
9e4abcb5 | 819 | { |
353ae4d2 | 820 | #ifdef HAVE_DHCP6 |
a9ab732e | 821 | int change = force; |
353ae4d2 SK |
822 | lease->flags |= LEASE_HAVE_HWADDR; |
823 | #endif | |
824 | ||
a9ab732e | 825 | (void)force; |
408c368f | 826 | (void)now; |
a9ab732e | 827 | |
cdeda28f SK |
828 | if (hw_len != lease->hwaddr_len || |
829 | hw_type != lease->hwaddr_type || | |
7cebd20f | 830 | (hw_len != 0 && memcmp(lease->hwaddr, hwaddr, hw_len) != 0)) |
9e4abcb5 | 831 | { |
4cb1b320 SK |
832 | if (hw_len != 0) |
833 | memcpy(lease->hwaddr, hwaddr, hw_len); | |
cdeda28f SK |
834 | lease->hwaddr_len = hw_len; |
835 | lease->hwaddr_type = hw_type; | |
4cb1b320 SK |
836 | lease->flags |= LEASE_CHANGED; |
837 | file_dirty = 1; /* run script on change */ | |
9e4abcb5 | 838 | } |
0a852541 SK |
839 | |
840 | /* only update clid when one is available, stops packets | |
841 | without a clid removing the record. Lease init uses | |
842 | clid_len == 0 for no clid. */ | |
843 | if (clid_len != 0 && clid) | |
844 | { | |
845 | if (!lease->clid) | |
846 | lease->clid_len = 0; | |
847 | ||
848 | if (lease->clid_len != clid_len) | |
849 | { | |
4cb1b320 SK |
850 | lease->flags |= LEASE_AUX_CHANGED; |
851 | file_dirty = 1; | |
5aabfc78 SK |
852 | free(lease->clid); |
853 | if (!(lease->clid = whine_malloc(clid_len))) | |
7cebd20f | 854 | return; |
353ae4d2 SK |
855 | #ifdef HAVE_DHCP6 |
856 | change = 1; | |
857 | #endif | |
0a852541 SK |
858 | } |
859 | else if (memcmp(lease->clid, clid, clid_len) != 0) | |
4cb1b320 SK |
860 | { |
861 | lease->flags |= LEASE_AUX_CHANGED; | |
862 | file_dirty = 1; | |
353ae4d2 SK |
863 | #ifdef HAVE_DHCP6 |
864 | change = 1; | |
865 | #endif | |
4cb1b320 | 866 | } |
353ae4d2 | 867 | |
0a852541 SK |
868 | lease->clid_len = clid_len; |
869 | memcpy(lease->clid, clid, clid_len); | |
870 | } | |
353ae4d2 SK |
871 | |
872 | #ifdef HAVE_DHCP6 | |
873 | if (change) | |
a9ab732e | 874 | slaac_add_addrs(lease, now, force); |
353ae4d2 | 875 | #endif |
9e4abcb5 SK |
876 | } |
877 | ||
9009d746 SK |
878 | static void kill_name(struct dhcp_lease *lease) |
879 | { | |
880 | /* run script to say we lost our old name */ | |
881 | ||
882 | /* this shouldn't happen unless updates are very quick and the | |
883 | script very slow, we just avoid a memory leak if it does. */ | |
884 | free(lease->old_hostname); | |
885 | ||
886 | /* If we know the fqdn, pass that. The helper will derive the | |
4cb1b320 | 887 | unqualified name from it, free the unqualified name here. */ |
9009d746 SK |
888 | |
889 | if (lease->fqdn) | |
890 | { | |
891 | lease->old_hostname = lease->fqdn; | |
892 | free(lease->hostname); | |
893 | } | |
894 | else | |
895 | lease->old_hostname = lease->hostname; | |
896 | ||
897 | lease->hostname = lease->fqdn = NULL; | |
898 | } | |
899 | ||
70c5e3e0 | 900 | void lease_set_hostname(struct dhcp_lease *lease, char *name, int auth, char *domain, char *config_domain) |
9e4abcb5 SK |
901 | { |
902 | struct dhcp_lease *lease_tmp; | |
903 | char *new_name = NULL, *new_fqdn = NULL; | |
70c5e3e0 SK |
904 | |
905 | if (config_domain && (!domain || !hostname_isequal(domain, config_domain))) | |
906 | my_syslog(MS_DHCP | LOG_WARNING, _("Ignoring domain %s for DHCP host name %s"), config_domain, name); | |
9009d746 | 907 | |
a222641c | 908 | if (lease->hostname && name && hostname_isequal(lease->hostname, name)) |
b8187c80 | 909 | { |
4cb1b320 SK |
910 | if (auth) |
911 | lease->flags |= LEASE_AUTH_NAME; | |
b8187c80 SK |
912 | return; |
913 | } | |
7cebd20f | 914 | |
9e4abcb5 SK |
915 | if (!name && !lease->hostname) |
916 | return; | |
917 | ||
918 | /* If a machine turns up on a new net without dropping the old lease, | |
919 | or two machines claim the same name, then we end up with two interfaces with | |
b8187c80 | 920 | the same name. Check for that here and remove the name from the old lease. |
4cb1b320 SK |
921 | Note that IPv6 leases are different. All the leases to the same DUID are |
922 | allowed the same name. | |
923 | ||
b8187c80 | 924 | Don't allow a name from the client to override a name from dnsmasq config. */ |
9e4abcb5 SK |
925 | |
926 | if (name) | |
927 | { | |
9009d746 SK |
928 | if ((new_name = whine_malloc(strlen(name) + 1))) |
929 | { | |
9009d746 | 930 | strcpy(new_name, name); |
4cb1b320 | 931 | if (domain && (new_fqdn = whine_malloc(strlen(new_name) + strlen(domain) + 2))) |
9009d746 SK |
932 | { |
933 | strcpy(new_fqdn, name); | |
934 | strcat(new_fqdn, "."); | |
4cb1b320 | 935 | strcat(new_fqdn, domain); |
9009d746 SK |
936 | } |
937 | } | |
938 | ||
939 | /* Depending on mode, we check either unqualified name or FQDN. */ | |
9e4abcb5 | 940 | for (lease_tmp = leases; lease_tmp; lease_tmp = lease_tmp->next) |
9e4abcb5 | 941 | { |
28866e95 | 942 | if (option_bool(OPT_DHCP_FQDN)) |
9009d746 | 943 | { |
4cb1b320 | 944 | if (!new_fqdn || !lease_tmp->fqdn || !hostname_isequal(lease_tmp->fqdn, new_fqdn)) |
9009d746 SK |
945 | continue; |
946 | } | |
947 | else | |
948 | { | |
949 | if (!new_name || !lease_tmp->hostname || !hostname_isequal(lease_tmp->hostname, new_name) ) | |
950 | continue; | |
951 | } | |
4cb1b320 SK |
952 | |
953 | if (lease->flags & (LEASE_TA | LEASE_NA)) | |
954 | { | |
955 | if (!(lease_tmp->flags & (LEASE_TA | LEASE_NA))) | |
956 | continue; | |
957 | ||
ceae00dd | 958 | /* another lease for the same DUID is OK for IPv6 */ |
4cb1b320 SK |
959 | if (lease->clid_len == lease_tmp->clid_len && |
960 | lease->clid && lease_tmp->clid && | |
961 | memcmp(lease->clid, lease_tmp->clid, lease->clid_len) == 0) | |
962 | continue; | |
963 | } | |
964 | else if (lease_tmp->flags & (LEASE_TA | LEASE_NA)) | |
965 | continue; | |
966 | ||
967 | if ((lease_tmp->flags & LEASE_AUTH_NAME) && !auth) | |
9009d746 SK |
968 | { |
969 | free(new_name); | |
970 | free(new_fqdn); | |
971 | return; | |
972 | } | |
973 | ||
974 | kill_name(lease_tmp); | |
975 | break; | |
9e4abcb5 SK |
976 | } |
977 | } | |
978 | ||
979 | if (lease->hostname) | |
9009d746 | 980 | kill_name(lease); |
1697269c | 981 | |
9e4abcb5 SK |
982 | lease->hostname = new_name; |
983 | lease->fqdn = new_fqdn; | |
4cb1b320 SK |
984 | |
985 | if (auth) | |
986 | lease->flags |= LEASE_AUTH_NAME; | |
9e4abcb5 | 987 | |
5e9e0efb | 988 | file_dirty = 1; |
7cebd20f | 989 | dns_dirty = 1; |
4cb1b320 | 990 | lease->flags |= LEASE_CHANGED; /* run script on change */ |
7cebd20f SK |
991 | } |
992 | ||
353ae4d2 | 993 | void lease_set_interface(struct dhcp_lease *lease, int interface, time_t now) |
824af85b | 994 | { |
408c368f VG |
995 | (void)now; |
996 | ||
824af85b SK |
997 | if (lease->last_interface == interface) |
998 | return; | |
999 | ||
1000 | lease->last_interface = interface; | |
4cb1b320 | 1001 | lease->flags |= LEASE_CHANGED; |
353ae4d2 SK |
1002 | |
1003 | #ifdef HAVE_DHCP6 | |
a9ab732e | 1004 | slaac_add_addrs(lease, now, 0); |
353ae4d2 | 1005 | #endif |
824af85b SK |
1006 | } |
1007 | ||
5aabfc78 SK |
1008 | void rerun_scripts(void) |
1009 | { | |
1010 | struct dhcp_lease *lease; | |
1011 | ||
1012 | for (lease = leases; lease; lease = lease->next) | |
4cb1b320 | 1013 | lease->flags |= LEASE_CHANGED; |
5aabfc78 SK |
1014 | } |
1015 | ||
7cebd20f SK |
1016 | /* deleted leases get transferred to the old_leases list. |
1017 | remove them here, after calling the lease change | |
1697269c SK |
1018 | script. Also run the lease change script on new/modified leases. |
1019 | ||
1020 | Return zero if nothing to do. */ | |
5aabfc78 | 1021 | int do_script_run(time_t now) |
7cebd20f SK |
1022 | { |
1023 | struct dhcp_lease *lease; | |
9e4abcb5 | 1024 | |
408c368f VG |
1025 | (void)now; |
1026 | ||
9009d746 SK |
1027 | #ifdef HAVE_DBUS |
1028 | /* If we're going to be sending DBus signals, but the connection is not yet up, | |
1029 | delay everything until it is. */ | |
28866e95 | 1030 | if (option_bool(OPT_DBUS) && !daemon->dbus) |
9009d746 SK |
1031 | return 0; |
1032 | #endif | |
1033 | ||
1697269c | 1034 | if (old_leases) |
7cebd20f | 1035 | { |
7cebd20f | 1036 | lease = old_leases; |
1697269c SK |
1037 | |
1038 | /* If the lease still has an old_hostname, do the "old" action on that first */ | |
1039 | if (lease->old_hostname) | |
1040 | { | |
1f15b81d | 1041 | #ifdef HAVE_SCRIPT |
5aabfc78 SK |
1042 | queue_script(ACTION_OLD_HOSTNAME, lease, lease->old_hostname, now); |
1043 | #endif | |
1697269c SK |
1044 | free(lease->old_hostname); |
1045 | lease->old_hostname = NULL; | |
1046 | return 1; | |
1047 | } | |
1048 | else | |
1049 | { | |
353ae4d2 SK |
1050 | #ifdef HAVE_DHCP6 |
1051 | struct slaac_address *slaac, *tmp; | |
1052 | for (slaac = lease->slaac_address; slaac; slaac = tmp) | |
1053 | { | |
1054 | tmp = slaac->next; | |
1055 | free(slaac); | |
1056 | } | |
1057 | #endif | |
9009d746 | 1058 | kill_name(lease); |
1f15b81d | 1059 | #ifdef HAVE_SCRIPT |
9009d746 | 1060 | queue_script(ACTION_DEL, lease, lease->old_hostname, now); |
1f15b81d SK |
1061 | #endif |
1062 | #ifdef HAVE_DBUS | |
1063 | emit_dbus_signal(ACTION_DEL, lease, lease->old_hostname); | |
5aabfc78 | 1064 | #endif |
1697269c SK |
1065 | old_leases = lease->next; |
1066 | ||
9009d746 | 1067 | free(lease->old_hostname); |
5aabfc78 | 1068 | free(lease->clid); |
316e2730 | 1069 | free(lease->extradata); |
1697269c SK |
1070 | free(lease); |
1071 | ||
1072 | return 1; | |
1073 | } | |
7cebd20f | 1074 | } |
1697269c SK |
1075 | |
1076 | /* make sure we announce the loss of a hostname before its new location. */ | |
1077 | for (lease = leases; lease; lease = lease->next) | |
1078 | if (lease->old_hostname) | |
1079 | { | |
1f15b81d | 1080 | #ifdef HAVE_SCRIPT |
5aabfc78 SK |
1081 | queue_script(ACTION_OLD_HOSTNAME, lease, lease->old_hostname, now); |
1082 | #endif | |
1697269c SK |
1083 | free(lease->old_hostname); |
1084 | lease->old_hostname = NULL; | |
1085 | return 1; | |
1086 | } | |
1087 | ||
7cebd20f | 1088 | for (lease = leases; lease; lease = lease->next) |
4cb1b320 SK |
1089 | if ((lease->flags & (LEASE_NEW | LEASE_CHANGED)) || |
1090 | ((lease->flags & LEASE_AUX_CHANGED) && option_bool(OPT_LEASE_RO))) | |
7cebd20f | 1091 | { |
1f15b81d | 1092 | #ifdef HAVE_SCRIPT |
4cb1b320 | 1093 | queue_script((lease->flags & LEASE_NEW) ? ACTION_ADD : ACTION_OLD, lease, |
9009d746 | 1094 | lease->fqdn ? lease->fqdn : lease->hostname, now); |
1f15b81d SK |
1095 | #endif |
1096 | #ifdef HAVE_DBUS | |
4cb1b320 | 1097 | emit_dbus_signal((lease->flags & LEASE_NEW) ? ACTION_ADD : ACTION_OLD, lease, |
1f15b81d | 1098 | lease->fqdn ? lease->fqdn : lease->hostname); |
5aabfc78 | 1099 | #endif |
4cb1b320 | 1100 | lease->flags &= ~(LEASE_NEW | LEASE_CHANGED | LEASE_AUX_CHANGED); |
1697269c | 1101 | |
316e2730 SK |
1102 | /* this is used for the "add" call, then junked, since they're not in the database */ |
1103 | free(lease->extradata); | |
1104 | lease->extradata = NULL; | |
1697269c SK |
1105 | |
1106 | return 1; | |
7cebd20f | 1107 | } |
1697269c SK |
1108 | |
1109 | return 0; /* nothing to do */ | |
7cebd20f | 1110 | } |
7622fc06 | 1111 | |
ceae00dd SK |
1112 | #ifdef HAVE_SCRIPT |
1113 | void lease_add_extradata(struct dhcp_lease *lease, unsigned char *data, unsigned int len, int delim) | |
1114 | { | |
1115 | unsigned int i; | |
1116 | ||
1117 | /* check for embeded NULLs */ | |
1118 | for (i = 0; i < len; i++) | |
1119 | if (data[i] == 0) | |
1120 | { | |
1121 | len = i; | |
1122 | break; | |
1123 | } | |
1124 | ||
1125 | if ((lease->extradata_size - lease->extradata_len) < (len + 1)) | |
1126 | { | |
1127 | size_t newsz = lease->extradata_len + len + 100; | |
1128 | unsigned char *new = whine_malloc(newsz); | |
1129 | ||
1130 | if (!new) | |
1131 | return; | |
1132 | ||
1133 | if (lease->extradata) | |
1134 | { | |
1135 | memcpy(new, lease->extradata, lease->extradata_len); | |
1136 | free(lease->extradata); | |
1137 | } | |
1138 | ||
1139 | lease->extradata = new; | |
1140 | lease->extradata_size = newsz; | |
1141 | } | |
1142 | ||
1143 | if (len != 0) | |
1144 | memcpy(lease->extradata + lease->extradata_len, data, len); | |
1145 | lease->extradata[lease->extradata_len + len] = delim; | |
1146 | lease->extradata_len += len + 1; | |
1147 | } | |
1148 | #endif | |
1149 | ||
7622fc06 | 1150 | #endif |
7cebd20f SK |
1151 | |
1152 | ||
1153 | ||
9e4abcb5 | 1154 |