blob: 5c33df7a76c8a06125ca58e7b8379fd16fd4788a [file] [log] [blame]
Simon Kelleyd1ced3a2018-01-01 22:18:03 +00001/* dnsmasq is Copyright (c) 2000-2018 Simon Kelley
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002
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
Simon Kelley824af852008-02-12 20:43:05 +00005 the Free Software Foundation; version 2 dated June, 1991, or
6 (at your option) version 3 dated 29 June, 2007.
7
Simon Kelley9e4abcb2004-01-22 19:47:41 +00008 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.
Simon Kelley824af852008-02-12 20:43:05 +000012
Simon Kelley73a08a22009-02-05 20:28:08 +000013 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/>.
Simon Kelley9e4abcb2004-01-22 19:47:41 +000015*/
16
Simon Kelley9e4abcb2004-01-22 19:47:41 +000017#include "dnsmasq.h"
18
Simon Kelley7622fc02009-06-04 20:32:05 +010019#ifdef HAVE_DHCP
20
Simon Kelley5aabfc72007-08-29 11:24:47 +010021static struct dhcp_lease *leases = NULL, *old_leases = NULL;
Simon Kelley5e9e0ef2006-04-17 14:24:29 +010022static int dns_dirty, file_dirty, leases_left;
Simon Kelley9e4abcb2004-01-22 19:47:41 +000023
Petr Menšík3a8b0f62017-04-23 14:12:37 +010024static int read_leases(time_t now, FILE *leasestream)
Simon Kelley9e4abcb2004-01-22 19:47:41 +000025{
Simon Kelley9e4abcb2004-01-22 19:47:41 +000026 unsigned long ei;
Simon Kelleyc72daea2012-01-05 21:33:27 +000027 struct all_addr addr;
Simon Kelley9e4abcb2004-01-22 19:47:41 +000028 struct dhcp_lease *lease;
Simon Kelley5aabfc72007-08-29 11:24:47 +010029 int clid_len, hw_len, hw_type;
Petr Menšík3a8b0f62017-04-23 14:12:37 +010030 int items;
31 char *domain = NULL;
32
33 *daemon->dhcp_buff3 = *daemon->dhcp_buff2 = '\0';
34
35 /* client-id max length is 255 which is 255*2 digits + 254 colons
36 borrow DNS packet buffer which is always larger than 1000 bytes
37
38 Check various buffers are big enough for the code below */
39
40#if (DHCP_BUFF_SZ < 255) || (MAXDNAME < 64) || (PACKETSZ+MAXDNAME+RRFIXEDSZ < 764)
41# error Buffer size breakage in leasefile parsing.
42#endif
43
44 while ((items=fscanf(leasestream, "%255s %255s", daemon->dhcp_buff3, daemon->dhcp_buff2)) == 2)
45 {
46 *daemon->namebuff = *daemon->dhcp_buff = *daemon->packet = '\0';
47 hw_len = hw_type = clid_len = 0;
48
49#ifdef HAVE_DHCP6
50 if (strcmp(daemon->dhcp_buff3, "duid") == 0)
51 {
52 daemon->duid_len = parse_hex(daemon->dhcp_buff2, (unsigned char *)daemon->dhcp_buff2, 130, NULL, NULL);
53 if (daemon->duid_len < 0)
54 return 0;
55 daemon->duid = safe_malloc(daemon->duid_len);
56 memcpy(daemon->duid, daemon->dhcp_buff2, daemon->duid_len);
57 continue;
58 }
59#endif
60
61 if (fscanf(leasestream, " %64s %255s %764s",
62 daemon->namebuff, daemon->dhcp_buff, daemon->packet) != 3)
63 return 0;
64
65 if (inet_pton(AF_INET, daemon->namebuff, &addr.addr.addr4))
66 {
67 if ((lease = lease4_allocate(addr.addr.addr4)))
68 domain = get_domain(lease->addr);
69
70 hw_len = parse_hex(daemon->dhcp_buff2, (unsigned char *)daemon->dhcp_buff2, DHCP_CHADDR_MAX, NULL, &hw_type);
71 /* For backwards compatibility, no explicit MAC address type means ether. */
72 if (hw_type == 0 && hw_len != 0)
73 hw_type = ARPHRD_ETHER;
74 }
75#ifdef HAVE_DHCP6
76 else if (inet_pton(AF_INET6, daemon->namebuff, &addr.addr.addr6))
77 {
78 char *s = daemon->dhcp_buff2;
79 int lease_type = LEASE_NA;
80
81 if (s[0] == 'T')
82 {
83 lease_type = LEASE_TA;
84 s++;
85 }
86
87 if ((lease = lease6_allocate(&addr.addr.addr6, lease_type)))
88 {
89 lease_set_iaid(lease, strtoul(s, NULL, 10));
90 domain = get_domain6((struct in6_addr *)lease->hwaddr);
91 }
92 }
93#endif
94 else
95 return 0;
96
97 if (!lease)
98 die (_("too many stored leases"), NULL, EC_MISC);
99
100 if (strcmp(daemon->packet, "*") != 0)
101 clid_len = parse_hex(daemon->packet, (unsigned char *)daemon->packet, 255, NULL, NULL);
102
103 lease_set_hwaddr(lease, (unsigned char *)daemon->dhcp_buff2, (unsigned char *)daemon->packet,
104 hw_len, hw_type, clid_len, now, 0);
105
106 if (strcmp(daemon->dhcp_buff, "*") != 0)
107 lease_set_hostname(lease, daemon->dhcp_buff, 0, domain, NULL);
108
109 ei = atol(daemon->dhcp_buff3);
110
111#ifdef HAVE_BROKEN_RTC
112 if (ei != 0)
113 lease->expires = (time_t)ei + now;
114 else
115 lease->expires = (time_t)0;
116 lease->length = ei;
117#else
118 /* strictly time_t is opaque, but this hack should work on all sane systems,
119 even when sizeof(time_t) == 8 */
120 lease->expires = (time_t)ei;
121#endif
122
123 /* set these correctly: the "old" events are generated later from
124 the startup synthesised SIGHUP. */
125 lease->flags &= ~(LEASE_NEW | LEASE_CHANGED);
126
127 *daemon->dhcp_buff3 = *daemon->dhcp_buff2 = '\0';
128 }
129
130 return (items == 0 || items == EOF);
131}
132
133void lease_init(time_t now)
134{
Simon Kelley208b65c2006-08-05 21:41:37 +0100135 FILE *leasestream;
Petr Menšík3a8b0f62017-04-23 14:12:37 +0100136
Simon Kelley3be34542004-09-11 19:12:13 +0100137 leases_left = daemon->dhcp_max;
Petr Menšík3a8b0f62017-04-23 14:12:37 +0100138
Simon Kelley28866e92011-02-14 20:19:14 +0000139 if (option_bool(OPT_LEASE_RO))
Simon Kelley208b65c2006-08-05 21:41:37 +0100140 {
141 /* run "<lease_change_script> init" once to get the
142 initial state of the database. If leasefile-ro is
Petr Menšík3a8b0f62017-04-23 14:12:37 +0100143 set without a script, we just do without any
Simon Kelley208b65c2006-08-05 21:41:37 +0100144 lease database. */
Simon Kelley1f15b812009-10-13 17:49:32 +0100145#ifdef HAVE_SCRIPT
146 if (daemon->lease_change_command)
Simon Kelley208b65c2006-08-05 21:41:37 +0100147 {
Simon Kelley1f15b812009-10-13 17:49:32 +0100148 strcpy(daemon->dhcp_buff, daemon->lease_change_command);
149 strcat(daemon->dhcp_buff, " init");
150 leasestream = popen(daemon->dhcp_buff, "r");
Simon Kelley208b65c2006-08-05 21:41:37 +0100151 }
Simon Kelley1f15b812009-10-13 17:49:32 +0100152 else
153#endif
154 {
155 file_dirty = dns_dirty = 0;
156 return;
157 }
158
Simon Kelley208b65c2006-08-05 21:41:37 +0100159 }
160 else
161 {
162 /* NOTE: need a+ mode to create file if it doesn't exist */
163 leasestream = daemon->lease_stream = fopen(daemon->lease_file, "a+");
Petr Menšík3a8b0f62017-04-23 14:12:37 +0100164
Simon Kelley208b65c2006-08-05 21:41:37 +0100165 if (!leasestream)
Simon Kelley5aabfc72007-08-29 11:24:47 +0100166 die(_("cannot open or create lease file %s: %s"), daemon->lease_file, EC_FILE);
Petr Menšík3a8b0f62017-04-23 14:12:37 +0100167
Simon Kelley7622fc02009-06-04 20:32:05 +0100168 /* a+ mode leaves pointer at end. */
Simon Kelley208b65c2006-08-05 21:41:37 +0100169 rewind(leasestream);
170 }
Simon Kelleybf4e62c2016-07-22 21:37:59 +0100171
Simon Kelley208b65c2006-08-05 21:41:37 +0100172 if (leasestream)
Petr Menšík3a8b0f62017-04-23 14:12:37 +0100173 {
Simon Kelley05f76da2017-05-09 22:57:04 +0100174 if (!read_leases(now, leasestream))
Simon Kelleyefff74c2017-04-28 23:01:23 +0100175 my_syslog(MS_DHCP | LOG_ERR, _("failed to parse lease database, invalid line: %s %s %s %s ..."),
176 daemon->dhcp_buff3, daemon->dhcp_buff2,
177 daemon->namebuff, daemon->dhcp_buff);
178
Petr Menšík3a8b0f62017-04-23 14:12:37 +0100179 if (ferror(leasestream))
180 die(_("failed to read lease file %s: %s"), daemon->lease_file, EC_FILE);
Petr Menšík3a8b0f62017-04-23 14:12:37 +0100181 }
Simon Kelley208b65c2006-08-05 21:41:37 +0100182
Simon Kelley1f15b812009-10-13 17:49:32 +0100183#ifdef HAVE_SCRIPT
Simon Kelley208b65c2006-08-05 21:41:37 +0100184 if (!daemon->lease_stream)
185 {
186 int rc = 0;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000187
Simon Kelley208b65c2006-08-05 21:41:37 +0100188 /* shell returns 127 for "command not found", 126 for bad permissions. */
189 if (!leasestream || (rc = pclose(leasestream)) == -1 || WEXITSTATUS(rc) == 127 || WEXITSTATUS(rc) == 126)
190 {
191 if (WEXITSTATUS(rc) == 127)
192 errno = ENOENT;
193 else if (WEXITSTATUS(rc) == 126)
194 errno = EACCES;
Petr Menšík3a8b0f62017-04-23 14:12:37 +0100195
Simon Kelley5aabfc72007-08-29 11:24:47 +0100196 die(_("cannot run lease-init script %s: %s"), daemon->lease_change_command, EC_FILE);
Simon Kelley208b65c2006-08-05 21:41:37 +0100197 }
198
199 if (WEXITSTATUS(rc) != 0)
200 {
201 sprintf(daemon->dhcp_buff, "%d", WEXITSTATUS(rc));
Simon Kelley5aabfc72007-08-29 11:24:47 +0100202 die(_("lease-init script returned exit code %s"), daemon->dhcp_buff, WEXITSTATUS(rc) + EC_INIT_OFFSET);
Simon Kelley208b65c2006-08-05 21:41:37 +0100203 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000204 }
Simon Kelley1f15b812009-10-13 17:49:32 +0100205#endif
Simon Kelley7cebd202006-05-06 14:13:33 +0100206
207 /* Some leases may have expired */
208 file_dirty = 0;
209 lease_prune(NULL, now);
210 dns_dirty = 1;
Simon Kelley44a2a312004-03-10 20:04:35 +0000211}
212
Simon Kelley5aabfc72007-08-29 11:24:47 +0100213void lease_update_from_configs(void)
Simon Kelley44a2a312004-03-10 20:04:35 +0000214{
215 /* changes to the config may change current leases. */
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000216
Simon Kelley44a2a312004-03-10 20:04:35 +0000217 struct dhcp_lease *lease;
218 struct dhcp_config *config;
Simon Kelleyb8187c82005-11-26 21:46:27 +0000219 char *name;
Simon Kelley4cb1b322012-02-06 14:30:41 +0000220
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000221 for (lease = leases; lease; lease = lease->next)
Simon Kelley89500e32013-09-20 16:29:20 +0100222 if (lease->flags & (LEASE_TA | LEASE_NA))
223 continue;
224 else if ((config = find_config(daemon->dhcp_conf, NULL, lease->clid, lease->clid_len,
225 lease->hwaddr, lease->hwaddr_len, lease->hwaddr_type, NULL)) &&
226 (config->flags & CONFIG_NAME) &&
227 (!(config->flags & CONFIG_ADDR) || config->addr.s_addr == lease->addr.s_addr))
Simon Kelley70c5e3e2012-02-06 22:05:15 +0000228 lease_set_hostname(lease, config->hostname, 1, get_domain(lease->addr), NULL);
Simon Kelley5aabfc72007-08-29 11:24:47 +0100229 else if ((name = host_from_dns(lease->addr)))
Simon Kelley70c5e3e2012-02-06 22:05:15 +0000230 lease_set_hostname(lease, name, 1, get_domain(lease->addr), NULL); /* updates auth flag only */
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000231}
Rosen Penev50a28412017-06-27 22:27:02 +0100232
Simon Kelley5aabfc72007-08-29 11:24:47 +0100233static void ourprintf(int *errp, char *format, ...)
Simon Kelley7cebd202006-05-06 14:13:33 +0100234{
235 va_list ap;
236
237 va_start(ap, format);
238 if (!(*errp) && vfprintf(daemon->lease_stream, format, ap) < 0)
239 *errp = errno;
240 va_end(ap);
241}
242
Simon Kelley5aabfc72007-08-29 11:24:47 +0100243void lease_update_file(time_t now)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000244{
245 struct dhcp_lease *lease;
Simon Kelley7cebd202006-05-06 14:13:33 +0100246 time_t next_event;
247 int i, err = 0;
248
Simon Kelley208b65c2006-08-05 21:41:37 +0100249 if (file_dirty != 0 && daemon->lease_stream)
Simon Kelley44a2a312004-03-10 20:04:35 +0000250 {
Simon Kelleycdeda282006-03-16 20:16:06 +0000251 errno = 0;
252 rewind(daemon->lease_stream);
253 if (errno != 0 || ftruncate(fileno(daemon->lease_stream), 0) != 0)
Simon Kelley7cebd202006-05-06 14:13:33 +0100254 err = errno;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000255
256 for (lease = leases; lease; lease = lease->next)
257 {
Simon Kelleyc72daea2012-01-05 21:33:27 +0000258
259#ifdef HAVE_DHCP6
Simon Kelley4cb1b322012-02-06 14:30:41 +0000260 if (lease->flags & (LEASE_TA | LEASE_NA))
Simon Kelleyc72daea2012-01-05 21:33:27 +0000261 continue;
262#endif
263
Simon Kelley44a2a312004-03-10 20:04:35 +0000264#ifdef HAVE_BROKEN_RTC
Simon Kelley5aabfc72007-08-29 11:24:47 +0100265 ourprintf(&err, "%u ", lease->length);
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100266#else
Simon Kelley5aabfc72007-08-29 11:24:47 +0100267 ourprintf(&err, "%lu ", (unsigned long)lease->expires);
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100268#endif
Simon Kelleyc72daea2012-01-05 21:33:27 +0000269
Simon Kelley7cebd202006-05-06 14:13:33 +0100270 if (lease->hwaddr_type != ARPHRD_ETHER || lease->hwaddr_len == 0)
Simon Kelley5aabfc72007-08-29 11:24:47 +0100271 ourprintf(&err, "%.2x-", lease->hwaddr_type);
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100272 for (i = 0; i < lease->hwaddr_len; i++)
273 {
Simon Kelley5aabfc72007-08-29 11:24:47 +0100274 ourprintf(&err, "%.2x", lease->hwaddr[i]);
Simon Kelley7cebd202006-05-06 14:13:33 +0100275 if (i != lease->hwaddr_len - 1)
Simon Kelley5aabfc72007-08-29 11:24:47 +0100276 ourprintf(&err, ":");
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100277 }
Simon Kelleyc72daea2012-01-05 21:33:27 +0000278
279 inet_ntop(AF_INET, &lease->addr, daemon->addrbuff, ADDRSTRLEN);
Simon Kelley5aabfc72007-08-29 11:24:47 +0100280
Simon Kelleyc72daea2012-01-05 21:33:27 +0000281 ourprintf(&err, " %s ", daemon->addrbuff);
Simon Kelley1f15b812009-10-13 17:49:32 +0100282 ourprintf(&err, "%s ", lease->hostname ? lease->hostname : "*");
283
Simon Kelley0a852542005-03-23 20:28:59 +0000284 if (lease->clid && lease->clid_len != 0)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000285 {
286 for (i = 0; i < lease->clid_len - 1; i++)
Simon Kelley5aabfc72007-08-29 11:24:47 +0100287 ourprintf(&err, "%.2x:", lease->clid[i]);
288 ourprintf(&err, "%.2x\n", lease->clid[i]);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000289 }
290 else
Simon Kelley5aabfc72007-08-29 11:24:47 +0100291 ourprintf(&err, "*\n");
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000292 }
Simon Kelley7cebd202006-05-06 14:13:33 +0100293
Simon Kelleyc72daea2012-01-05 21:33:27 +0000294#ifdef HAVE_DHCP6
295 if (daemon->duid)
296 {
297 ourprintf(&err, "duid ");
298 for (i = 0; i < daemon->duid_len - 1; i++)
299 ourprintf(&err, "%.2x:", daemon->duid[i]);
300 ourprintf(&err, "%.2x\n", daemon->duid[i]);
301
302 for (lease = leases; lease; lease = lease->next)
303 {
304
Simon Kelley4cb1b322012-02-06 14:30:41 +0000305 if (!(lease->flags & (LEASE_TA | LEASE_NA)))
Simon Kelleyc72daea2012-01-05 21:33:27 +0000306 continue;
307
308#ifdef HAVE_BROKEN_RTC
309 ourprintf(&err, "%u ", lease->length);
310#else
311 ourprintf(&err, "%lu ", (unsigned long)lease->expires);
312#endif
313
Simon Kelley89500e32013-09-20 16:29:20 +0100314 inet_ntop(AF_INET6, &lease->addr6, daemon->addrbuff, ADDRSTRLEN);
Simon Kelleyc72daea2012-01-05 21:33:27 +0000315
Simon Kelley4cb1b322012-02-06 14:30:41 +0000316 ourprintf(&err, "%s%u %s ", (lease->flags & LEASE_TA) ? "T" : "",
Simon Kelley89500e32013-09-20 16:29:20 +0100317 lease->iaid, daemon->addrbuff);
Simon Kelleyc72daea2012-01-05 21:33:27 +0000318 ourprintf(&err, "%s ", lease->hostname ? lease->hostname : "*");
319
320 if (lease->clid && lease->clid_len != 0)
321 {
322 for (i = 0; i < lease->clid_len - 1; i++)
323 ourprintf(&err, "%.2x:", lease->clid[i]);
324 ourprintf(&err, "%.2x\n", lease->clid[i]);
325 }
326 else
327 ourprintf(&err, "*\n");
328 }
329 }
330#endif
331
Simon Kelley7cebd202006-05-06 14:13:33 +0100332 if (fflush(daemon->lease_stream) != 0 ||
333 fsync(fileno(daemon->lease_stream)) < 0)
334 err = errno;
335
336 if (!err)
337 file_dirty = 0;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000338 }
Simon Kelley7cebd202006-05-06 14:13:33 +0100339
Simon Kelleydd0e0a32014-01-22 11:16:59 +0000340 /* Set alarm for when the first lease expires. */
Simon Kelleyc5ad4e72012-02-24 16:06:20 +0000341 next_event = 0;
342
343#ifdef HAVE_DHCP6
Simon Kelley353ae4d2012-03-19 20:07:51 +0000344 /* do timed RAs and determine when the next is, also pings to potential SLAAC addresses */
Simon Kelley1f776932012-12-16 19:46:08 +0000345 if (daemon->doing_ra)
Simon Kelley353ae4d2012-03-19 20:07:51 +0000346 {
Simon Kelley919dd7c2012-05-12 15:23:09 +0100347 time_t event;
Simon Kelley353ae4d2012-03-19 20:07:51 +0000348
Simon Kelley919dd7c2012-05-12 15:23:09 +0100349 if ((event = periodic_slaac(now, leases)) != 0)
350 {
351 if (next_event == 0 || difftime(next_event, event) > 0.0)
352 next_event = event;
353 }
Simon Kelley353ae4d2012-03-19 20:07:51 +0000354
Simon Kelley919dd7c2012-05-12 15:23:09 +0100355 if ((event = periodic_ra(now)) != 0)
356 {
357 if (next_event == 0 || difftime(next_event, event) > 0.0)
358 next_event = event;
359 }
Simon Kelley353ae4d2012-03-19 20:07:51 +0000360 }
Simon Kelleyc5ad4e72012-02-24 16:06:20 +0000361#endif
362
363 for (lease = leases; lease; lease = lease->next)
Simon Kelley7cebd202006-05-06 14:13:33 +0100364 if (lease->expires != 0 &&
Simon Kelleydd0e0a32014-01-22 11:16:59 +0000365 (next_event == 0 || difftime(next_event, lease->expires) > 0.0))
366 next_event = lease->expires;
Simon Kelley7cebd202006-05-06 14:13:33 +0100367
368 if (err)
369 {
370 if (next_event == 0 || difftime(next_event, LEASE_RETRY + now) > 0.0)
371 next_event = LEASE_RETRY + now;
372
Simon Kelley7622fc02009-06-04 20:32:05 +0100373 my_syslog(MS_DHCP | LOG_ERR, _("failed to write %s: %s (retry in %us)"),
Simon Kelleyf2621c72007-04-29 19:47:21 +0100374 daemon->lease_file, strerror(err),
375 (unsigned int)difftime(next_event, now));
Simon Kelley7cebd202006-05-06 14:13:33 +0100376 }
377
Simon Kelley353ae4d2012-03-19 20:07:51 +0000378 send_alarm(next_event, now);
Simon Kelley44a2a312004-03-10 20:04:35 +0000379}
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000380
Simon Kelley801ca9a2012-03-06 19:30:17 +0000381
Simon Kelley3f2873d2013-05-14 11:28:47 +0100382static int find_interface_v4(struct in_addr local, int if_index, char *label,
Simon Kelley801ca9a2012-03-06 19:30:17 +0000383 struct in_addr netmask, struct in_addr broadcast, void *vparam)
Simon Kelley44a2a312004-03-10 20:04:35 +0000384{
385 struct dhcp_lease *lease;
Simon Kelley6d8e8ac2014-07-13 22:12:45 +0100386 int prefix = netmask_length(netmask);
Lung-Pin Changdc8a1b12014-07-02 10:48:05 +0800387
Simon Kelley3f2873d2013-05-14 11:28:47 +0100388 (void) label;
Simon Kelley801ca9a2012-03-06 19:30:17 +0000389 (void) broadcast;
390 (void) vparam;
391
392 for (lease = leases; lease; lease = lease->next)
Simon Kelley6d8e8ac2014-07-13 22:12:45 +0100393 if (!(lease->flags & (LEASE_TA | LEASE_NA)) &&
394 is_same_net(local, lease->addr, netmask) &&
395 prefix > lease->new_prefixlen)
396 {
397 lease->new_interface = if_index;
Lung-Pin Changdc8a1b12014-07-02 10:48:05 +0800398 lease->new_prefixlen = prefix;
399 }
Lung-Pin Changdc8a1b12014-07-02 10:48:05 +0800400
Simon Kelley801ca9a2012-03-06 19:30:17 +0000401 return 1;
402}
403
404#ifdef HAVE_DHCP6
405static int find_interface_v6(struct in6_addr *local, int prefix,
Simon Kelleybad7b872012-12-20 22:00:39 +0000406 int scope, int if_index, int flags,
Simon Kelley1f776932012-12-16 19:46:08 +0000407 int preferred, int valid, void *vparam)
Simon Kelley801ca9a2012-03-06 19:30:17 +0000408{
409 struct dhcp_lease *lease;
Lung-Pin Changdc8a1b12014-07-02 10:48:05 +0800410
Simon Kelley353ae4d2012-03-19 20:07:51 +0000411 (void)scope;
Simon Kelleybad7b872012-12-20 22:00:39 +0000412 (void)flags;
Simon Kelley1f776932012-12-16 19:46:08 +0000413 (void)preferred;
414 (void)valid;
Lung-Pin Changdc8a1b12014-07-02 10:48:05 +0800415 (void)vparam;
Simon Kelley801ca9a2012-03-06 19:30:17 +0000416
417 for (lease = leases; lease; lease = lease->next)
418 if ((lease->flags & (LEASE_TA | LEASE_NA)))
Lung-Pin Changdc8a1b12014-07-02 10:48:05 +0800419 if (is_same_net6(local, &lease->addr6, prefix) && prefix > lease->new_prefixlen) {
420 /* save prefix length for comparison, as we might get shorter matching
421 * prefix in upcoming netlink GETADDR responses
422 * */
423 lease->new_interface = if_index;
424 lease->new_prefixlen = prefix;
425 }
426
Simon Kelley801ca9a2012-03-06 19:30:17 +0000427 return 1;
428}
Simon Kelley353ae4d2012-03-19 20:07:51 +0000429
430void lease_ping_reply(struct in6_addr *sender, unsigned char *packet, char *interface)
431{
Simon Kelley5ef33272012-03-30 15:10:28 +0100432 /* We may be doing RA but not DHCPv4, in which case the lease
433 database may not exist and we have nothing to do anyway */
434 if (daemon->dhcp)
435 slaac_ping_reply(sender, packet, interface, leases);
Simon Kelley353ae4d2012-03-19 20:07:51 +0000436}
437
Simon Kelley0c050242012-12-22 22:13:19 +0000438void lease_update_slaac(time_t now)
439{
Josh Soref730c6742017-02-06 16:14:04 +0000440 /* Called when we construct a new RA-names context, to add putative
Simon Kelley0c050242012-12-22 22:13:19 +0000441 new SLAAC addresses to existing leases. */
442
443 struct dhcp_lease *lease;
444
445 if (daemon->dhcp)
446 for (lease = leases; lease; lease = lease->next)
447 slaac_add_addrs(lease, now, 0);
448}
449
Simon Kelley801ca9a2012-03-06 19:30:17 +0000450#endif
451
452
453/* Find interfaces associated with leases at start-up. This gets updated as
454 we do DHCP transactions, but information about directly-connected subnets
455 is useful from scrips and necessary for determining SLAAC addresses from
456 start-time. */
Simon Kelley8b372702012-03-09 17:45:10 +0000457void lease_find_interfaces(time_t now)
Simon Kelley801ca9a2012-03-06 19:30:17 +0000458{
Simon Kelley6d8e8ac2014-07-13 22:12:45 +0100459 struct dhcp_lease *lease;
460
461 for (lease = leases; lease; lease = lease->next)
462 lease->new_prefixlen = lease->new_interface = 0;
463
Simon Kelley353ae4d2012-03-19 20:07:51 +0000464 iface_enumerate(AF_INET, &now, find_interface_v4);
465#ifdef HAVE_DHCP6
466 iface_enumerate(AF_INET6, &now, find_interface_v6);
Simon Kelley3511a922013-11-07 10:28:11 +0000467#endif
Simon Kelley6d8e8ac2014-07-13 22:12:45 +0100468
469 for (lease = leases; lease; lease = lease->next)
470 if (lease->new_interface != 0)
471 lease_set_interface(lease, lease->new_interface, now);
Simon Kelley3511a922013-11-07 10:28:11 +0000472}
Simon Kelley8b372702012-03-09 17:45:10 +0000473
Simon Kelley3511a922013-11-07 10:28:11 +0000474#ifdef HAVE_DHCP6
475void lease_make_duid(time_t now)
476{
Simon Kelley8b372702012-03-09 17:45:10 +0000477 /* If we're not doing DHCPv6, and there are not v6 leases, don't add the DUID to the database */
Simon Kelley3511a922013-11-07 10:28:11 +0000478 if (!daemon->duid && daemon->doing_dhcp6)
Simon Kelley8b372702012-03-09 17:45:10 +0000479 {
480 file_dirty = 1;
481 make_duid(now);
482 }
Simon Kelley801ca9a2012-03-06 19:30:17 +0000483}
Simon Kelley3511a922013-11-07 10:28:11 +0000484#endif
485
Simon Kelley801ca9a2012-03-06 19:30:17 +0000486
487
488
Simon Kelley353ae4d2012-03-19 20:07:51 +0000489void lease_update_dns(int force)
Simon Kelley801ca9a2012-03-06 19:30:17 +0000490{
491 struct dhcp_lease *lease;
492
Simon Kelley353ae4d2012-03-19 20:07:51 +0000493 if (daemon->port != 0 && (dns_dirty || force))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000494 {
Simon Kelley8ff55672012-12-09 21:09:01 +0000495#ifndef HAVE_BROKEN_RTC
Simon Kelleye1ff4192012-12-09 17:08:47 +0000496 /* force transfer to authoritative secondaries */
497 daemon->soa_sn++;
Simon Kelley8ff55672012-12-09 21:09:01 +0000498#endif
Simon Kelleye1ff4192012-12-09 17:08:47 +0000499
Simon Kelley801ca9a2012-03-06 19:30:17 +0000500 cache_unhash_dhcp();
501
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000502 for (lease = leases; lease; lease = lease->next)
503 {
Simon Kelley4cb1b322012-02-06 14:30:41 +0000504 int prot = AF_INET;
Simon Kelley801ca9a2012-03-06 19:30:17 +0000505
Simon Kelley4cb1b322012-02-06 14:30:41 +0000506#ifdef HAVE_DHCP6
507 if (lease->flags & (LEASE_TA | LEASE_NA))
508 prot = AF_INET6;
Simon Kelleyf444cdd2012-03-07 10:15:57 +0000509 else if (lease->hostname || lease->fqdn)
Simon Kelley801ca9a2012-03-06 19:30:17 +0000510 {
Simon Kelley353ae4d2012-03-19 20:07:51 +0000511 struct slaac_address *slaac;
512
513 for (slaac = lease->slaac_address; slaac; slaac = slaac->next)
514 if (slaac->backoff == 0)
Simon Kelley801ca9a2012-03-06 19:30:17 +0000515 {
Simon Kelley801ca9a2012-03-06 19:30:17 +0000516 if (lease->fqdn)
Simon Kelley353ae4d2012-03-19 20:07:51 +0000517 cache_add_dhcp_entry(lease->fqdn, AF_INET6, (struct all_addr *)&slaac->addr, lease->expires);
Simon Kelley801ca9a2012-03-06 19:30:17 +0000518 if (!option_bool(OPT_DHCP_FQDN) && lease->hostname)
Simon Kelley353ae4d2012-03-19 20:07:51 +0000519 cache_add_dhcp_entry(lease->hostname, AF_INET6, (struct all_addr *)&slaac->addr, lease->expires);
Simon Kelley801ca9a2012-03-06 19:30:17 +0000520 }
521 }
Simon Kelley4cb1b322012-02-06 14:30:41 +0000522
Simon Kelley9009d742008-11-14 20:04:27 +0000523 if (lease->fqdn)
Simon Kelley4cb1b322012-02-06 14:30:41 +0000524 cache_add_dhcp_entry(lease->fqdn, prot,
Simon Kelley89500e32013-09-20 16:29:20 +0100525 prot == AF_INET ? (struct all_addr *)&lease->addr : (struct all_addr *)&lease->addr6,
Simon Kelley4cb1b322012-02-06 14:30:41 +0000526 lease->expires);
Simon Kelley9009d742008-11-14 20:04:27 +0000527
Simon Kelley28866e92011-02-14 20:19:14 +0000528 if (!option_bool(OPT_DHCP_FQDN) && lease->hostname)
Simon Kelley4cb1b322012-02-06 14:30:41 +0000529 cache_add_dhcp_entry(lease->hostname, prot,
Simon Kelley89500e32013-09-20 16:29:20 +0100530 prot == AF_INET ? (struct all_addr *)&lease->addr : (struct all_addr *)&lease->addr6,
Simon Kelley4cb1b322012-02-06 14:30:41 +0000531 lease->expires);
Simon Kelley91543f42013-09-23 12:41:20 +0100532
533#else
534 if (lease->fqdn)
535 cache_add_dhcp_entry(lease->fqdn, prot, (struct all_addr *)&lease->addr, lease->expires);
536
537 if (!option_bool(OPT_DHCP_FQDN) && lease->hostname)
538 cache_add_dhcp_entry(lease->hostname, prot, (struct all_addr *)&lease->addr, lease->expires);
539#endif
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000540 }
541
542 dns_dirty = 0;
543 }
544}
545
546void lease_prune(struct dhcp_lease *target, time_t now)
547{
548 struct dhcp_lease *lease, *tmp, **up;
549
550 for (lease = leases, up = &leases; lease; lease = tmp)
551 {
552 tmp = lease->next;
553 if ((lease->expires != 0 && difftime(now, lease->expires) > 0) || lease == target)
554 {
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100555 file_dirty = 1;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000556 if (lease->hostname)
Simon Kelley7cebd202006-05-06 14:13:33 +0100557 dns_dirty = 1;
558
Simon Kelleyc72daea2012-01-05 21:33:27 +0000559 *up = lease->next; /* unlink */
Simon Kelley7cebd202006-05-06 14:13:33 +0100560
561 /* Put on old_leases list 'till we
562 can run the script */
563 lease->next = old_leases;
564 old_leases = lease;
565
Simon Kelley44a2a312004-03-10 20:04:35 +0000566 leases_left++;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000567 }
568 else
569 up = &lease->next;
570 }
571}
572
573
Simon Kelleycdeda282006-03-16 20:16:06 +0000574struct dhcp_lease *lease_find_by_client(unsigned char *hwaddr, int hw_len, int hw_type,
Simon Kelley0a852542005-03-23 20:28:59 +0000575 unsigned char *clid, int clid_len)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000576{
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000577 struct dhcp_lease *lease;
578
Simon Kelley0a852542005-03-23 20:28:59 +0000579 if (clid)
580 for (lease = leases; lease; lease = lease->next)
Simon Kelleyc72daea2012-01-05 21:33:27 +0000581 {
582#ifdef HAVE_DHCP6
Simon Kelley4cb1b322012-02-06 14:30:41 +0000583 if (lease->flags & (LEASE_TA | LEASE_NA))
Simon Kelleyc72daea2012-01-05 21:33:27 +0000584 continue;
585#endif
586 if (lease->clid && clid_len == lease->clid_len &&
587 memcmp(clid, lease->clid, clid_len) == 0)
588 return lease;
589 }
Simon Kelley0a852542005-03-23 20:28:59 +0000590
591 for (lease = leases; lease; lease = lease->next)
Simon Kelleyc72daea2012-01-05 21:33:27 +0000592 {
593#ifdef HAVE_DHCP6
Simon Kelley4cb1b322012-02-06 14:30:41 +0000594 if (lease->flags & (LEASE_TA | LEASE_NA))
Simon Kelleyc72daea2012-01-05 21:33:27 +0000595 continue;
596#endif
597 if ((!lease->clid || !clid) &&
598 hw_len != 0 &&
599 lease->hwaddr_len == hw_len &&
600 lease->hwaddr_type == hw_type &&
601 memcmp(hwaddr, lease->hwaddr, hw_len) == 0)
602 return lease;
603 }
604
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000605 return NULL;
606}
607
608struct dhcp_lease *lease_find_by_addr(struct in_addr addr)
609{
610 struct dhcp_lease *lease;
611
612 for (lease = leases; lease; lease = lease->next)
Simon Kelleyc72daea2012-01-05 21:33:27 +0000613 {
614#ifdef HAVE_DHCP6
Simon Kelley4cb1b322012-02-06 14:30:41 +0000615 if (lease->flags & (LEASE_TA | LEASE_NA))
Simon Kelleyc72daea2012-01-05 21:33:27 +0000616 continue;
617#endif
618 if (lease->addr.s_addr == addr.s_addr)
619 return lease;
620 }
621
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000622 return NULL;
623}
624
Simon Kelley52b92f42012-01-22 16:05:15 +0000625#ifdef HAVE_DHCP6
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000626/* find address for {CLID, IAID, address} */
Simon Kelley4cb1b322012-02-06 14:30:41 +0000627struct dhcp_lease *lease6_find(unsigned char *clid, int clid_len,
628 int lease_type, int iaid, struct in6_addr *addr)
Simon Kelley52b92f42012-01-22 16:05:15 +0000629{
630 struct dhcp_lease *lease;
631
632 for (lease = leases; lease; lease = lease->next)
633 {
Simon Kelley89500e32013-09-20 16:29:20 +0100634 if (!(lease->flags & lease_type) || lease->iaid != iaid)
Simon Kelley4cb1b322012-02-06 14:30:41 +0000635 continue;
Simon Kelley52b92f42012-01-22 16:05:15 +0000636
Simon Kelley89500e32013-09-20 16:29:20 +0100637 if (!IN6_ARE_ADDR_EQUAL(&lease->addr6, addr))
Simon Kelley4cb1b322012-02-06 14:30:41 +0000638 continue;
639
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000640 if ((clid_len != lease->clid_len ||
Simon Kelley4cb1b322012-02-06 14:30:41 +0000641 memcmp(clid, lease->clid, clid_len) != 0))
642 continue;
643
Simon Kelley8b460612012-09-08 21:47:28 +0100644 return lease;
Simon Kelley52b92f42012-01-22 16:05:15 +0000645 }
646
647 return NULL;
648}
649
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000650/* reset "USED flags */
651void lease6_reset(void)
Simon Kelley8b460612012-09-08 21:47:28 +0100652{
653 struct dhcp_lease *lease;
654
655 for (lease = leases; lease; lease = lease->next)
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000656 lease->flags &= ~LEASE_USED;
657}
658
659/* enumerate all leases belonging to {CLID, IAID} */
660struct dhcp_lease *lease6_find_by_client(struct dhcp_lease *first, int lease_type, unsigned char *clid, int clid_len, int iaid)
661{
662 struct dhcp_lease *lease;
663
664 if (!first)
665 first = leases;
Simon Kelley27cb3142013-04-02 20:06:39 +0100666 else
667 first = first->next;
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000668
669 for (lease = first; lease; lease = lease->next)
Simon Kelley8b460612012-09-08 21:47:28 +0100670 {
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000671 if (lease->flags & LEASE_USED)
672 continue;
673
Simon Kelley89500e32013-09-20 16:29:20 +0100674 if (!(lease->flags & lease_type) || lease->iaid != iaid)
Simon Kelley8b460612012-09-08 21:47:28 +0100675 continue;
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000676
677 if ((clid_len != lease->clid_len ||
678 memcmp(clid, lease->clid, clid_len) != 0))
679 continue;
680
681 return lease;
Simon Kelley8b460612012-09-08 21:47:28 +0100682 }
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000683
684 return NULL;
Simon Kelley8b460612012-09-08 21:47:28 +0100685}
686
Simon Kelley52b92f42012-01-22 16:05:15 +0000687struct dhcp_lease *lease6_find_by_addr(struct in6_addr *net, int prefix, u64 addr)
688{
689 struct dhcp_lease *lease;
Simon Kelley4cb1b322012-02-06 14:30:41 +0000690
Simon Kelley52b92f42012-01-22 16:05:15 +0000691 for (lease = leases; lease; lease = lease->next)
692 {
Simon Kelley4cb1b322012-02-06 14:30:41 +0000693 if (!(lease->flags & (LEASE_TA | LEASE_NA)))
Simon Kelley52b92f42012-01-22 16:05:15 +0000694 continue;
Simon Kelley4cb1b322012-02-06 14:30:41 +0000695
Simon Kelley89500e32013-09-20 16:29:20 +0100696 if (is_same_net6(&lease->addr6, net, prefix) &&
697 (prefix == 128 || addr6part(&lease->addr6) == addr))
Simon Kelley52b92f42012-01-22 16:05:15 +0000698 return lease;
699 }
700
701 return NULL;
Simon Kelley07933802012-02-14 20:55:25 +0000702}
703
704/* Find largest assigned address in context */
705u64 lease_find_max_addr6(struct dhcp_context *context)
706{
707 struct dhcp_lease *lease;
708 u64 addr = addr6part(&context->start6);
709
710 if (!(context->flags & (CONTEXT_STATIC | CONTEXT_PROXY)))
711 for (lease = leases; lease; lease = lease->next)
712 {
Simon Kelley07933802012-02-14 20:55:25 +0000713 if (!(lease->flags & (LEASE_TA | LEASE_NA)))
714 continue;
Simon Kelley6caacac2012-02-15 21:58:33 +0000715
Simon Kelley89500e32013-09-20 16:29:20 +0100716 if (is_same_net6(&lease->addr6, &context->start6, 64) &&
717 addr6part(&lease->addr6) > addr6part(&context->start6) &&
718 addr6part(&lease->addr6) <= addr6part(&context->end6) &&
719 addr6part(&lease->addr6) > addr)
720 addr = addr6part(&lease->addr6);
Simon Kelley07933802012-02-14 20:55:25 +0000721 }
722
723 return addr;
724}
725
Simon Kelley52b92f42012-01-22 16:05:15 +0000726#endif
727
Simon Kelley7de060b2011-08-26 17:24:52 +0100728/* Find largest assigned address in context */
729struct in_addr lease_find_max_addr(struct dhcp_context *context)
730{
731 struct dhcp_lease *lease;
732 struct in_addr addr = context->start;
733
734 if (!(context->flags & (CONTEXT_STATIC | CONTEXT_PROXY)))
735 for (lease = leases; lease; lease = lease->next)
Simon Kelleyc72daea2012-01-05 21:33:27 +0000736 {
737#ifdef HAVE_DHCP6
Simon Kelley4cb1b322012-02-06 14:30:41 +0000738 if (lease->flags & (LEASE_TA | LEASE_NA))
Simon Kelleyc72daea2012-01-05 21:33:27 +0000739 continue;
740#endif
741 if (((unsigned)ntohl(lease->addr.s_addr)) > ((unsigned)ntohl(context->start.s_addr)) &&
742 ((unsigned)ntohl(lease->addr.s_addr)) <= ((unsigned)ntohl(context->end.s_addr)) &&
743 ((unsigned)ntohl(lease->addr.s_addr)) > ((unsigned)ntohl(addr.s_addr)))
744 addr = lease->addr;
745 }
Simon Kelley7de060b2011-08-26 17:24:52 +0100746
747 return addr;
748}
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000749
Simon Kelleyc72daea2012-01-05 21:33:27 +0000750static struct dhcp_lease *lease_allocate(void)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000751{
752 struct dhcp_lease *lease;
Simon Kelley5aabfc72007-08-29 11:24:47 +0100753 if (!leases_left || !(lease = whine_malloc(sizeof(struct dhcp_lease))))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000754 return NULL;
755
Simon Kelley7cebd202006-05-06 14:13:33 +0100756 memset(lease, 0, sizeof(struct dhcp_lease));
Simon Kelley4cb1b322012-02-06 14:30:41 +0000757 lease->flags = LEASE_NEW;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000758 lease->expires = 1;
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100759#ifdef HAVE_BROKEN_RTC
760 lease->length = 0xffffffff; /* illegal value */
761#endif
Simon Kelley89500e32013-09-20 16:29:20 +0100762 lease->hwaddr_len = 256; /* illegal value */
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000763 lease->next = leases;
764 leases = lease;
765
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100766 file_dirty = 1;
Simon Kelley44a2a312004-03-10 20:04:35 +0000767 leases_left--;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000768
769 return lease;
770}
771
Simon Kelley52b92f42012-01-22 16:05:15 +0000772struct dhcp_lease *lease4_allocate(struct in_addr addr)
Simon Kelleyc72daea2012-01-05 21:33:27 +0000773{
774 struct dhcp_lease *lease = lease_allocate();
Simon Kelley0b0a73c2013-04-11 14:07:02 +0100775 if (lease)
Simon Kelley89500e32013-09-20 16:29:20 +0100776 lease->addr = addr;
777
Simon Kelleyc72daea2012-01-05 21:33:27 +0000778 return lease;
779}
780
781#ifdef HAVE_DHCP6
Simon Kelley4cb1b322012-02-06 14:30:41 +0000782struct dhcp_lease *lease6_allocate(struct in6_addr *addrp, int lease_type)
Simon Kelleyc72daea2012-01-05 21:33:27 +0000783{
784 struct dhcp_lease *lease = lease_allocate();
Simon Kelley0b0a73c2013-04-11 14:07:02 +0100785
786 if (lease)
787 {
Simon Kelley89500e32013-09-20 16:29:20 +0100788 lease->addr6 = *addrp;
Simon Kelley0b0a73c2013-04-11 14:07:02 +0100789 lease->flags |= lease_type;
Simon Kelley89500e32013-09-20 16:29:20 +0100790 lease->iaid = 0;
Simon Kelley0b0a73c2013-04-11 14:07:02 +0100791 }
Simon Kelleyc72daea2012-01-05 21:33:27 +0000792
793 return lease;
794}
795#endif
796
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100797void lease_set_expires(struct dhcp_lease *lease, unsigned int len, time_t now)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000798{
Simon Kelleydd0e0a32014-01-22 11:16:59 +0000799 time_t exp;
800
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100801 if (len == 0xffffffff)
802 {
803 exp = 0;
804 len = 0;
805 }
Simon Kelleydd0e0a32014-01-22 11:16:59 +0000806 else
807 {
808 exp = now + (time_t)len;
809 /* Check for 2038 overflow. Make the lease
Josh Soref730c6742017-02-06 16:14:04 +0000810 infinite in that case, as the least disruptive
Simon Kelleydd0e0a32014-01-22 11:16:59 +0000811 thing we can do. */
812 if (difftime(exp, now) <= 0.0)
813 exp = 0;
814 }
815
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000816 if (exp != lease->expires)
Simon Kelley0a852542005-03-23 20:28:59 +0000817 {
Simon Kelley0a852542005-03-23 20:28:59 +0000818 dns_dirty = 1;
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100819 lease->expires = exp;
820#ifndef HAVE_BROKEN_RTC
Simon Kelley4cb1b322012-02-06 14:30:41 +0000821 lease->flags |= LEASE_AUX_CHANGED;
822 file_dirty = 1;
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100823#endif
Simon Kelley0a852542005-03-23 20:28:59 +0000824 }
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100825
826#ifdef HAVE_BROKEN_RTC
827 if (len != lease->length)
828 {
829 lease->length = len;
Simon Kelleyb7f40202012-02-29 21:43:37 +0000830 lease->flags |= LEASE_AUX_CHANGED;
831 file_dirty = 1;
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100832 }
833#endif
834}
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000835
Simon Kelley89500e32013-09-20 16:29:20 +0100836#ifdef HAVE_DHCP6
837void lease_set_iaid(struct dhcp_lease *lease, int iaid)
838{
839 if (lease->iaid != iaid)
840 {
841 lease->iaid = iaid;
842 lease->flags |= LEASE_CHANGED;
843 }
844}
845#endif
846
Nicolas Cavallari64bcff12015-04-28 21:55:18 +0100847void lease_set_hwaddr(struct dhcp_lease *lease, const unsigned char *hwaddr,
848 const unsigned char *clid, int hw_len, int hw_type,
849 int clid_len, time_t now, int force)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000850{
Simon Kelley353ae4d2012-03-19 20:07:51 +0000851#ifdef HAVE_DHCP6
Simon Kelleya9ab7322012-04-28 11:29:37 +0100852 int change = force;
Simon Kelley353ae4d2012-03-19 20:07:51 +0000853 lease->flags |= LEASE_HAVE_HWADDR;
854#endif
855
Simon Kelleya9ab7322012-04-28 11:29:37 +0100856 (void)force;
Vladislav Grishenko408c3682013-09-24 16:18:49 +0100857 (void)now;
Simon Kelleya9ab7322012-04-28 11:29:37 +0100858
Simon Kelleycdeda282006-03-16 20:16:06 +0000859 if (hw_len != lease->hwaddr_len ||
860 hw_type != lease->hwaddr_type ||
Simon Kelley7cebd202006-05-06 14:13:33 +0100861 (hw_len != 0 && memcmp(lease->hwaddr, hwaddr, hw_len) != 0))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000862 {
Simon Kelley4cb1b322012-02-06 14:30:41 +0000863 if (hw_len != 0)
864 memcpy(lease->hwaddr, hwaddr, hw_len);
Simon Kelleycdeda282006-03-16 20:16:06 +0000865 lease->hwaddr_len = hw_len;
866 lease->hwaddr_type = hw_type;
Simon Kelley4cb1b322012-02-06 14:30:41 +0000867 lease->flags |= LEASE_CHANGED;
868 file_dirty = 1; /* run script on change */
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000869 }
Simon Kelley0a852542005-03-23 20:28:59 +0000870
871 /* only update clid when one is available, stops packets
872 without a clid removing the record. Lease init uses
873 clid_len == 0 for no clid. */
874 if (clid_len != 0 && clid)
875 {
876 if (!lease->clid)
877 lease->clid_len = 0;
878
879 if (lease->clid_len != clid_len)
880 {
Simon Kelley4cb1b322012-02-06 14:30:41 +0000881 lease->flags |= LEASE_AUX_CHANGED;
882 file_dirty = 1;
Simon Kelley5aabfc72007-08-29 11:24:47 +0100883 free(lease->clid);
884 if (!(lease->clid = whine_malloc(clid_len)))
Simon Kelley7cebd202006-05-06 14:13:33 +0100885 return;
Simon Kelley353ae4d2012-03-19 20:07:51 +0000886#ifdef HAVE_DHCP6
887 change = 1;
888#endif
Simon Kelley0a852542005-03-23 20:28:59 +0000889 }
890 else if (memcmp(lease->clid, clid, clid_len) != 0)
Simon Kelley4cb1b322012-02-06 14:30:41 +0000891 {
892 lease->flags |= LEASE_AUX_CHANGED;
893 file_dirty = 1;
Simon Kelley353ae4d2012-03-19 20:07:51 +0000894#ifdef HAVE_DHCP6
895 change = 1;
896#endif
Simon Kelley4cb1b322012-02-06 14:30:41 +0000897 }
Simon Kelley353ae4d2012-03-19 20:07:51 +0000898
Simon Kelley0a852542005-03-23 20:28:59 +0000899 lease->clid_len = clid_len;
900 memcpy(lease->clid, clid, clid_len);
901 }
Simon Kelley353ae4d2012-03-19 20:07:51 +0000902
903#ifdef HAVE_DHCP6
904 if (change)
Simon Kelleya9ab7322012-04-28 11:29:37 +0100905 slaac_add_addrs(lease, now, force);
Simon Kelley353ae4d2012-03-19 20:07:51 +0000906#endif
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000907}
908
Simon Kelley9009d742008-11-14 20:04:27 +0000909static void kill_name(struct dhcp_lease *lease)
910{
911 /* run script to say we lost our old name */
912
913 /* this shouldn't happen unless updates are very quick and the
914 script very slow, we just avoid a memory leak if it does. */
915 free(lease->old_hostname);
916
917 /* If we know the fqdn, pass that. The helper will derive the
Simon Kelley4cb1b322012-02-06 14:30:41 +0000918 unqualified name from it, free the unqualified name here. */
Simon Kelley9009d742008-11-14 20:04:27 +0000919
920 if (lease->fqdn)
921 {
922 lease->old_hostname = lease->fqdn;
923 free(lease->hostname);
924 }
925 else
926 lease->old_hostname = lease->hostname;
927
928 lease->hostname = lease->fqdn = NULL;
929}
930
Nicolas Cavallari64bcff12015-04-28 21:55:18 +0100931void lease_set_hostname(struct dhcp_lease *lease, const char *name, int auth, char *domain, char *config_domain)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000932{
933 struct dhcp_lease *lease_tmp;
934 char *new_name = NULL, *new_fqdn = NULL;
Simon Kelley70c5e3e2012-02-06 22:05:15 +0000935
936 if (config_domain && (!domain || !hostname_isequal(domain, config_domain)))
937 my_syslog(MS_DHCP | LOG_WARNING, _("Ignoring domain %s for DHCP host name %s"), config_domain, name);
Simon Kelley9009d742008-11-14 20:04:27 +0000938
Simon Kelleya2226412004-05-13 20:27:08 +0100939 if (lease->hostname && name && hostname_isequal(lease->hostname, name))
Simon Kelleyb8187c82005-11-26 21:46:27 +0000940 {
Simon Kelley4cb1b322012-02-06 14:30:41 +0000941 if (auth)
942 lease->flags |= LEASE_AUTH_NAME;
Simon Kelleyb8187c82005-11-26 21:46:27 +0000943 return;
944 }
Simon Kelley7cebd202006-05-06 14:13:33 +0100945
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000946 if (!name && !lease->hostname)
947 return;
948
949 /* If a machine turns up on a new net without dropping the old lease,
950 or two machines claim the same name, then we end up with two interfaces with
Simon Kelleyb8187c82005-11-26 21:46:27 +0000951 the same name. Check for that here and remove the name from the old lease.
Simon Kelley4cb1b322012-02-06 14:30:41 +0000952 Note that IPv6 leases are different. All the leases to the same DUID are
953 allowed the same name.
954
Simon Kelleyb8187c82005-11-26 21:46:27 +0000955 Don't allow a name from the client to override a name from dnsmasq config. */
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000956
957 if (name)
958 {
Simon Kelley9009d742008-11-14 20:04:27 +0000959 if ((new_name = whine_malloc(strlen(name) + 1)))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000960 {
Simon Kelley9009d742008-11-14 20:04:27 +0000961 strcpy(new_name, name);
Simon Kelley4cb1b322012-02-06 14:30:41 +0000962 if (domain && (new_fqdn = whine_malloc(strlen(new_name) + strlen(domain) + 2)))
Simon Kelley9009d742008-11-14 20:04:27 +0000963 {
964 strcpy(new_fqdn, name);
965 strcat(new_fqdn, ".");
Simon Kelley4cb1b322012-02-06 14:30:41 +0000966 strcat(new_fqdn, domain);
Simon Kelley9009d742008-11-14 20:04:27 +0000967 }
968 }
969
970 /* Depending on mode, we check either unqualified name or FQDN. */
971 for (lease_tmp = leases; lease_tmp; lease_tmp = lease_tmp->next)
972 {
Simon Kelley28866e92011-02-14 20:19:14 +0000973 if (option_bool(OPT_DHCP_FQDN))
Simon Kelley9009d742008-11-14 20:04:27 +0000974 {
Simon Kelley4cb1b322012-02-06 14:30:41 +0000975 if (!new_fqdn || !lease_tmp->fqdn || !hostname_isequal(lease_tmp->fqdn, new_fqdn))
Simon Kelley9009d742008-11-14 20:04:27 +0000976 continue;
977 }
978 else
979 {
980 if (!new_name || !lease_tmp->hostname || !hostname_isequal(lease_tmp->hostname, new_name) )
981 continue;
982 }
Simon Kelley4cb1b322012-02-06 14:30:41 +0000983
984 if (lease->flags & (LEASE_TA | LEASE_NA))
985 {
986 if (!(lease_tmp->flags & (LEASE_TA | LEASE_NA)))
987 continue;
988
Simon Kelleyceae00d2012-02-09 21:28:14 +0000989 /* another lease for the same DUID is OK for IPv6 */
Simon Kelley4cb1b322012-02-06 14:30:41 +0000990 if (lease->clid_len == lease_tmp->clid_len &&
991 lease->clid && lease_tmp->clid &&
992 memcmp(lease->clid, lease_tmp->clid, lease->clid_len) == 0)
993 continue;
994 }
995 else if (lease_tmp->flags & (LEASE_TA | LEASE_NA))
996 continue;
997
998 if ((lease_tmp->flags & LEASE_AUTH_NAME) && !auth)
Simon Kelley9009d742008-11-14 20:04:27 +0000999 {
1000 free(new_name);
1001 free(new_fqdn);
1002 return;
1003 }
1004
1005 kill_name(lease_tmp);
1006 break;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001007 }
1008 }
1009
1010 if (lease->hostname)
Simon Kelley9009d742008-11-14 20:04:27 +00001011 kill_name(lease);
Simon Kelley16972692006-10-16 20:04:18 +01001012
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001013 lease->hostname = new_name;
1014 lease->fqdn = new_fqdn;
Simon Kelley4cb1b322012-02-06 14:30:41 +00001015
1016 if (auth)
1017 lease->flags |= LEASE_AUTH_NAME;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001018
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001019 file_dirty = 1;
Simon Kelley7cebd202006-05-06 14:13:33 +01001020 dns_dirty = 1;
Simon Kelley4cb1b322012-02-06 14:30:41 +00001021 lease->flags |= LEASE_CHANGED; /* run script on change */
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001022}
1023
Simon Kelley353ae4d2012-03-19 20:07:51 +00001024void lease_set_interface(struct dhcp_lease *lease, int interface, time_t now)
Simon Kelley824af852008-02-12 20:43:05 +00001025{
Vladislav Grishenko408c3682013-09-24 16:18:49 +01001026 (void)now;
1027
Simon Kelley824af852008-02-12 20:43:05 +00001028 if (lease->last_interface == interface)
1029 return;
1030
1031 lease->last_interface = interface;
Simon Kelley4cb1b322012-02-06 14:30:41 +00001032 lease->flags |= LEASE_CHANGED;
Simon Kelley353ae4d2012-03-19 20:07:51 +00001033
1034#ifdef HAVE_DHCP6
Simon Kelleya9ab7322012-04-28 11:29:37 +01001035 slaac_add_addrs(lease, now, 0);
Simon Kelley353ae4d2012-03-19 20:07:51 +00001036#endif
Simon Kelley824af852008-02-12 20:43:05 +00001037}
1038
Simon Kelley5aabfc72007-08-29 11:24:47 +01001039void rerun_scripts(void)
1040{
1041 struct dhcp_lease *lease;
1042
1043 for (lease = leases; lease; lease = lease->next)
Simon Kelley4cb1b322012-02-06 14:30:41 +00001044 lease->flags |= LEASE_CHANGED;
Simon Kelley5aabfc72007-08-29 11:24:47 +01001045}
1046
Simon Kelley7cebd202006-05-06 14:13:33 +01001047/* deleted leases get transferred to the old_leases list.
1048 remove them here, after calling the lease change
Simon Kelley16972692006-10-16 20:04:18 +01001049 script. Also run the lease change script on new/modified leases.
1050
1051 Return zero if nothing to do. */
Simon Kelley5aabfc72007-08-29 11:24:47 +01001052int do_script_run(time_t now)
Simon Kelley7cebd202006-05-06 14:13:33 +01001053{
1054 struct dhcp_lease *lease;
1055
Vladislav Grishenko408c3682013-09-24 16:18:49 +01001056 (void)now;
1057
Simon Kelley9009d742008-11-14 20:04:27 +00001058#ifdef HAVE_DBUS
1059 /* If we're going to be sending DBus signals, but the connection is not yet up,
1060 delay everything until it is. */
Simon Kelley28866e92011-02-14 20:19:14 +00001061 if (option_bool(OPT_DBUS) && !daemon->dbus)
Simon Kelley9009d742008-11-14 20:04:27 +00001062 return 0;
1063#endif
1064
Simon Kelley16972692006-10-16 20:04:18 +01001065 if (old_leases)
Simon Kelley7cebd202006-05-06 14:13:33 +01001066 {
Simon Kelley7cebd202006-05-06 14:13:33 +01001067 lease = old_leases;
Simon Kelley16972692006-10-16 20:04:18 +01001068
1069 /* If the lease still has an old_hostname, do the "old" action on that first */
1070 if (lease->old_hostname)
1071 {
Simon Kelley1f15b812009-10-13 17:49:32 +01001072#ifdef HAVE_SCRIPT
Simon Kelley5aabfc72007-08-29 11:24:47 +01001073 queue_script(ACTION_OLD_HOSTNAME, lease, lease->old_hostname, now);
1074#endif
Simon Kelley16972692006-10-16 20:04:18 +01001075 free(lease->old_hostname);
1076 lease->old_hostname = NULL;
1077 return 1;
1078 }
1079 else
1080 {
Simon Kelley353ae4d2012-03-19 20:07:51 +00001081#ifdef HAVE_DHCP6
1082 struct slaac_address *slaac, *tmp;
1083 for (slaac = lease->slaac_address; slaac; slaac = tmp)
1084 {
1085 tmp = slaac->next;
1086 free(slaac);
1087 }
1088#endif
Simon Kelley9009d742008-11-14 20:04:27 +00001089 kill_name(lease);
Simon Kelley1f15b812009-10-13 17:49:32 +01001090#ifdef HAVE_SCRIPT
Simon Kelley9009d742008-11-14 20:04:27 +00001091 queue_script(ACTION_DEL, lease, lease->old_hostname, now);
Simon Kelley5aabfc72007-08-29 11:24:47 +01001092#endif
Simon Kelley1f15b812009-10-13 17:49:32 +01001093#ifdef HAVE_DBUS
1094 emit_dbus_signal(ACTION_DEL, lease, lease->old_hostname);
1095#endif
Simon Kelley16972692006-10-16 20:04:18 +01001096 old_leases = lease->next;
1097
Simon Kelley9009d742008-11-14 20:04:27 +00001098 free(lease->old_hostname);
Simon Kelley5aabfc72007-08-29 11:24:47 +01001099 free(lease->clid);
Simon Kelley316e2732010-01-22 20:16:09 +00001100 free(lease->extradata);
Simon Kelley16972692006-10-16 20:04:18 +01001101 free(lease);
1102
1103 return 1;
1104 }
Simon Kelley7cebd202006-05-06 14:13:33 +01001105 }
Simon Kelley16972692006-10-16 20:04:18 +01001106
1107 /* make sure we announce the loss of a hostname before its new location. */
1108 for (lease = leases; lease; lease = lease->next)
1109 if (lease->old_hostname)
1110 {
Simon Kelley1f15b812009-10-13 17:49:32 +01001111#ifdef HAVE_SCRIPT
Simon Kelley5aabfc72007-08-29 11:24:47 +01001112 queue_script(ACTION_OLD_HOSTNAME, lease, lease->old_hostname, now);
1113#endif
Simon Kelley16972692006-10-16 20:04:18 +01001114 free(lease->old_hostname);
1115 lease->old_hostname = NULL;
1116 return 1;
1117 }
1118
Simon Kelley7cebd202006-05-06 14:13:33 +01001119 for (lease = leases; lease; lease = lease->next)
Simon Kelley4cb1b322012-02-06 14:30:41 +00001120 if ((lease->flags & (LEASE_NEW | LEASE_CHANGED)) ||
1121 ((lease->flags & LEASE_AUX_CHANGED) && option_bool(OPT_LEASE_RO)))
Simon Kelley7cebd202006-05-06 14:13:33 +01001122 {
Simon Kelley1f15b812009-10-13 17:49:32 +01001123#ifdef HAVE_SCRIPT
Simon Kelley4cb1b322012-02-06 14:30:41 +00001124 queue_script((lease->flags & LEASE_NEW) ? ACTION_ADD : ACTION_OLD, lease,
Simon Kelley9009d742008-11-14 20:04:27 +00001125 lease->fqdn ? lease->fqdn : lease->hostname, now);
Simon Kelley5aabfc72007-08-29 11:24:47 +01001126#endif
Simon Kelley1f15b812009-10-13 17:49:32 +01001127#ifdef HAVE_DBUS
Simon Kelley4cb1b322012-02-06 14:30:41 +00001128 emit_dbus_signal((lease->flags & LEASE_NEW) ? ACTION_ADD : ACTION_OLD, lease,
Simon Kelley1f15b812009-10-13 17:49:32 +01001129 lease->fqdn ? lease->fqdn : lease->hostname);
1130#endif
Simon Kelley4cb1b322012-02-06 14:30:41 +00001131 lease->flags &= ~(LEASE_NEW | LEASE_CHANGED | LEASE_AUX_CHANGED);
Simon Kelley16972692006-10-16 20:04:18 +01001132
Simon Kelley316e2732010-01-22 20:16:09 +00001133 /* this is used for the "add" call, then junked, since they're not in the database */
1134 free(lease->extradata);
1135 lease->extradata = NULL;
Simon Kelley16972692006-10-16 20:04:18 +01001136
1137 return 1;
Simon Kelley7cebd202006-05-06 14:13:33 +01001138 }
Simon Kelley16972692006-10-16 20:04:18 +01001139
1140 return 0; /* nothing to do */
Simon Kelley7cebd202006-05-06 14:13:33 +01001141}
Simon Kelley7622fc02009-06-04 20:32:05 +01001142
Simon Kelleyceae00d2012-02-09 21:28:14 +00001143#ifdef HAVE_SCRIPT
Josh Soref730c6742017-02-06 16:14:04 +00001144/* delim == -1 -> delim = 0, but embedded 0s, creating extra records, are OK. */
Simon Kelleyceae00d2012-02-09 21:28:14 +00001145void lease_add_extradata(struct dhcp_lease *lease, unsigned char *data, unsigned int len, int delim)
1146{
1147 unsigned int i;
1148
Simon Kelleya93bd4b2016-03-01 18:58:01 +00001149 if (delim == -1)
1150 delim = 0;
1151 else
Josh Soref730c6742017-02-06 16:14:04 +00001152 /* check for embedded NULLs */
Simon Kelleya93bd4b2016-03-01 18:58:01 +00001153 for (i = 0; i < len; i++)
1154 if (data[i] == 0)
1155 {
1156 len = i;
1157 break;
1158 }
1159
Simon Kelleyceae00d2012-02-09 21:28:14 +00001160 if ((lease->extradata_size - lease->extradata_len) < (len + 1))
1161 {
1162 size_t newsz = lease->extradata_len + len + 100;
1163 unsigned char *new = whine_malloc(newsz);
1164
1165 if (!new)
1166 return;
1167
1168 if (lease->extradata)
1169 {
1170 memcpy(new, lease->extradata, lease->extradata_len);
1171 free(lease->extradata);
1172 }
1173
1174 lease->extradata = new;
1175 lease->extradata_size = newsz;
1176 }
1177
1178 if (len != 0)
1179 memcpy(lease->extradata + lease->extradata_len, data, len);
1180 lease->extradata[lease->extradata_len + len] = delim;
1181 lease->extradata_len += len + 1;
1182}
1183#endif
1184
Simon Kelley7622fc02009-06-04 20:32:05 +01001185#endif
Simon Kelley7cebd202006-05-06 14:13:33 +01001186
1187
1188
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001189