blob: 3514e44100969a5b3bf1a2e40b67c8716c0d1c2e [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 Kelleycc921df2019-01-02 22:48:59 +000027 union 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
Simon Kelleycc921df2019-01-02 22:48:59 +000065 if (inet_pton(AF_INET, daemon->namebuff, &addr.addr4))
Petr Menšík3a8b0f62017-04-23 14:12:37 +010066 {
Simon Kelleycc921df2019-01-02 22:48:59 +000067 if ((lease = lease4_allocate(addr.addr4)))
Petr Menšík3a8b0f62017-04-23 14:12:37 +010068 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
Simon Kelleycc921df2019-01-02 22:48:59 +000076 else if (inet_pton(AF_INET6, daemon->namebuff, &addr.addr6))
Petr Menšík3a8b0f62017-04-23 14:12:37 +010077 {
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
Simon Kelleycc921df2019-01-02 22:48:59 +000087 if ((lease = lease6_allocate(&addr.addr6, lease_type)))
Petr Menšík3a8b0f62017-04-23 14:12:37 +010088 {
89 lease_set_iaid(lease, strtoul(s, NULL, 10));
Paul Maddock51e4eee2018-06-12 16:37:40 +010090 domain = get_domain6(&lease->addr6);
Petr Menšík3a8b0f62017-04-23 14:12:37 +010091 }
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 Kelleycc921df2019-01-02 22:48:59 +0000517 cache_add_dhcp_entry(lease->fqdn, AF_INET6, (union all_addr *)&slaac->addr, lease->expires);
Simon Kelley801ca9a2012-03-06 19:30:17 +0000518 if (!option_bool(OPT_DHCP_FQDN) && lease->hostname)
Simon Kelleycc921df2019-01-02 22:48:59 +0000519 cache_add_dhcp_entry(lease->hostname, AF_INET6, (union 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 Kelleycc921df2019-01-02 22:48:59 +0000525 prot == AF_INET ? (union all_addr *)&lease->addr : (union 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 Kelleycc921df2019-01-02 22:48:59 +0000530 prot == AF_INET ? (union all_addr *)&lease->addr : (union 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)
Simon Kelleycc921df2019-01-02 22:48:59 +0000535 cache_add_dhcp_entry(lease->fqdn, prot, (union all_addr *)&lease->addr, lease->expires);
Simon Kelley91543f42013-09-23 12:41:20 +0100536
537 if (!option_bool(OPT_DHCP_FQDN) && lease->hostname)
Simon Kelleycc921df2019-01-02 22:48:59 +0000538 cache_add_dhcp_entry(lease->hostname, prot, (union all_addr *)&lease->addr, lease->expires);
Simon Kelley91543f42013-09-23 12:41:20 +0100539#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;
Julian Kornbergeraba8bbb2018-07-21 21:55:08 +0100558
559 daemon->metrics[lease->addr.s_addr ? METRIC_LEASES_PRUNED_4 : METRIC_LEASES_PRUNED_6]++;
560
Simon Kelleyc72daea2012-01-05 21:33:27 +0000561 *up = lease->next; /* unlink */
Simon Kelley7cebd202006-05-06 14:13:33 +0100562
563 /* Put on old_leases list 'till we
564 can run the script */
565 lease->next = old_leases;
566 old_leases = lease;
567
Simon Kelley44a2a312004-03-10 20:04:35 +0000568 leases_left++;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000569 }
570 else
571 up = &lease->next;
572 }
573}
574
575
Simon Kelleycdeda282006-03-16 20:16:06 +0000576struct dhcp_lease *lease_find_by_client(unsigned char *hwaddr, int hw_len, int hw_type,
Simon Kelley0a852542005-03-23 20:28:59 +0000577 unsigned char *clid, int clid_len)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000578{
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000579 struct dhcp_lease *lease;
580
Simon Kelley0a852542005-03-23 20:28:59 +0000581 if (clid)
582 for (lease = leases; lease; lease = lease->next)
Simon Kelleyc72daea2012-01-05 21:33:27 +0000583 {
584#ifdef HAVE_DHCP6
Simon Kelley4cb1b322012-02-06 14:30:41 +0000585 if (lease->flags & (LEASE_TA | LEASE_NA))
Simon Kelleyc72daea2012-01-05 21:33:27 +0000586 continue;
587#endif
588 if (lease->clid && clid_len == lease->clid_len &&
589 memcmp(clid, lease->clid, clid_len) == 0)
590 return lease;
591 }
Simon Kelley0a852542005-03-23 20:28:59 +0000592
593 for (lease = leases; lease; lease = lease->next)
Simon Kelleyc72daea2012-01-05 21:33:27 +0000594 {
595#ifdef HAVE_DHCP6
Simon Kelley4cb1b322012-02-06 14:30:41 +0000596 if (lease->flags & (LEASE_TA | LEASE_NA))
Simon Kelleyc72daea2012-01-05 21:33:27 +0000597 continue;
598#endif
599 if ((!lease->clid || !clid) &&
600 hw_len != 0 &&
601 lease->hwaddr_len == hw_len &&
602 lease->hwaddr_type == hw_type &&
603 memcmp(hwaddr, lease->hwaddr, hw_len) == 0)
604 return lease;
605 }
606
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000607 return NULL;
608}
609
610struct dhcp_lease *lease_find_by_addr(struct in_addr addr)
611{
612 struct dhcp_lease *lease;
613
614 for (lease = leases; lease; lease = lease->next)
Simon Kelleyc72daea2012-01-05 21:33:27 +0000615 {
616#ifdef HAVE_DHCP6
Simon Kelley4cb1b322012-02-06 14:30:41 +0000617 if (lease->flags & (LEASE_TA | LEASE_NA))
Simon Kelleyc72daea2012-01-05 21:33:27 +0000618 continue;
619#endif
620 if (lease->addr.s_addr == addr.s_addr)
621 return lease;
622 }
623
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000624 return NULL;
625}
626
Simon Kelley52b92f42012-01-22 16:05:15 +0000627#ifdef HAVE_DHCP6
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000628/* find address for {CLID, IAID, address} */
Simon Kelley4cb1b322012-02-06 14:30:41 +0000629struct dhcp_lease *lease6_find(unsigned char *clid, int clid_len,
630 int lease_type, int iaid, struct in6_addr *addr)
Simon Kelley52b92f42012-01-22 16:05:15 +0000631{
632 struct dhcp_lease *lease;
633
634 for (lease = leases; lease; lease = lease->next)
635 {
Simon Kelley89500e32013-09-20 16:29:20 +0100636 if (!(lease->flags & lease_type) || lease->iaid != iaid)
Simon Kelley4cb1b322012-02-06 14:30:41 +0000637 continue;
Simon Kelley52b92f42012-01-22 16:05:15 +0000638
Simon Kelley89500e32013-09-20 16:29:20 +0100639 if (!IN6_ARE_ADDR_EQUAL(&lease->addr6, addr))
Simon Kelley4cb1b322012-02-06 14:30:41 +0000640 continue;
641
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000642 if ((clid_len != lease->clid_len ||
Simon Kelley4cb1b322012-02-06 14:30:41 +0000643 memcmp(clid, lease->clid, clid_len) != 0))
644 continue;
645
Simon Kelley8b460612012-09-08 21:47:28 +0100646 return lease;
Simon Kelley52b92f42012-01-22 16:05:15 +0000647 }
648
649 return NULL;
650}
651
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000652/* reset "USED flags */
653void lease6_reset(void)
Simon Kelley8b460612012-09-08 21:47:28 +0100654{
655 struct dhcp_lease *lease;
656
657 for (lease = leases; lease; lease = lease->next)
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000658 lease->flags &= ~LEASE_USED;
659}
660
661/* enumerate all leases belonging to {CLID, IAID} */
662struct dhcp_lease *lease6_find_by_client(struct dhcp_lease *first, int lease_type, unsigned char *clid, int clid_len, int iaid)
663{
664 struct dhcp_lease *lease;
665
666 if (!first)
667 first = leases;
Simon Kelley27cb3142013-04-02 20:06:39 +0100668 else
669 first = first->next;
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000670
671 for (lease = first; lease; lease = lease->next)
Simon Kelley8b460612012-09-08 21:47:28 +0100672 {
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000673 if (lease->flags & LEASE_USED)
674 continue;
675
Simon Kelley89500e32013-09-20 16:29:20 +0100676 if (!(lease->flags & lease_type) || lease->iaid != iaid)
Simon Kelley8b460612012-09-08 21:47:28 +0100677 continue;
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000678
679 if ((clid_len != lease->clid_len ||
680 memcmp(clid, lease->clid, clid_len) != 0))
681 continue;
682
683 return lease;
Simon Kelley8b460612012-09-08 21:47:28 +0100684 }
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000685
686 return NULL;
Simon Kelley8b460612012-09-08 21:47:28 +0100687}
688
Simon Kelley52b92f42012-01-22 16:05:15 +0000689struct dhcp_lease *lease6_find_by_addr(struct in6_addr *net, int prefix, u64 addr)
690{
691 struct dhcp_lease *lease;
Simon Kelley4cb1b322012-02-06 14:30:41 +0000692
Simon Kelley52b92f42012-01-22 16:05:15 +0000693 for (lease = leases; lease; lease = lease->next)
694 {
Simon Kelley4cb1b322012-02-06 14:30:41 +0000695 if (!(lease->flags & (LEASE_TA | LEASE_NA)))
Simon Kelley52b92f42012-01-22 16:05:15 +0000696 continue;
Simon Kelley4cb1b322012-02-06 14:30:41 +0000697
Simon Kelley89500e32013-09-20 16:29:20 +0100698 if (is_same_net6(&lease->addr6, net, prefix) &&
699 (prefix == 128 || addr6part(&lease->addr6) == addr))
Simon Kelley52b92f42012-01-22 16:05:15 +0000700 return lease;
701 }
702
703 return NULL;
Simon Kelley07933802012-02-14 20:55:25 +0000704}
705
706/* Find largest assigned address in context */
707u64 lease_find_max_addr6(struct dhcp_context *context)
708{
709 struct dhcp_lease *lease;
710 u64 addr = addr6part(&context->start6);
711
712 if (!(context->flags & (CONTEXT_STATIC | CONTEXT_PROXY)))
713 for (lease = leases; lease; lease = lease->next)
714 {
Simon Kelley07933802012-02-14 20:55:25 +0000715 if (!(lease->flags & (LEASE_TA | LEASE_NA)))
716 continue;
Simon Kelley6caacac2012-02-15 21:58:33 +0000717
Simon Kelley89500e32013-09-20 16:29:20 +0100718 if (is_same_net6(&lease->addr6, &context->start6, 64) &&
719 addr6part(&lease->addr6) > addr6part(&context->start6) &&
720 addr6part(&lease->addr6) <= addr6part(&context->end6) &&
721 addr6part(&lease->addr6) > addr)
722 addr = addr6part(&lease->addr6);
Simon Kelley07933802012-02-14 20:55:25 +0000723 }
724
725 return addr;
726}
727
Simon Kelley52b92f42012-01-22 16:05:15 +0000728#endif
729
Simon Kelley7de060b2011-08-26 17:24:52 +0100730/* Find largest assigned address in context */
731struct in_addr lease_find_max_addr(struct dhcp_context *context)
732{
733 struct dhcp_lease *lease;
734 struct in_addr addr = context->start;
735
736 if (!(context->flags & (CONTEXT_STATIC | CONTEXT_PROXY)))
737 for (lease = leases; lease; lease = lease->next)
Simon Kelleyc72daea2012-01-05 21:33:27 +0000738 {
739#ifdef HAVE_DHCP6
Simon Kelley4cb1b322012-02-06 14:30:41 +0000740 if (lease->flags & (LEASE_TA | LEASE_NA))
Simon Kelleyc72daea2012-01-05 21:33:27 +0000741 continue;
742#endif
743 if (((unsigned)ntohl(lease->addr.s_addr)) > ((unsigned)ntohl(context->start.s_addr)) &&
744 ((unsigned)ntohl(lease->addr.s_addr)) <= ((unsigned)ntohl(context->end.s_addr)) &&
745 ((unsigned)ntohl(lease->addr.s_addr)) > ((unsigned)ntohl(addr.s_addr)))
746 addr = lease->addr;
747 }
Simon Kelley7de060b2011-08-26 17:24:52 +0100748
749 return addr;
750}
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000751
Simon Kelleyc72daea2012-01-05 21:33:27 +0000752static struct dhcp_lease *lease_allocate(void)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000753{
754 struct dhcp_lease *lease;
Simon Kelley5aabfc72007-08-29 11:24:47 +0100755 if (!leases_left || !(lease = whine_malloc(sizeof(struct dhcp_lease))))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000756 return NULL;
757
Simon Kelley7cebd202006-05-06 14:13:33 +0100758 memset(lease, 0, sizeof(struct dhcp_lease));
Simon Kelley4cb1b322012-02-06 14:30:41 +0000759 lease->flags = LEASE_NEW;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000760 lease->expires = 1;
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100761#ifdef HAVE_BROKEN_RTC
762 lease->length = 0xffffffff; /* illegal value */
763#endif
Simon Kelley89500e32013-09-20 16:29:20 +0100764 lease->hwaddr_len = 256; /* illegal value */
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000765 lease->next = leases;
766 leases = lease;
767
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100768 file_dirty = 1;
Simon Kelley44a2a312004-03-10 20:04:35 +0000769 leases_left--;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000770
771 return lease;
772}
773
Simon Kelley52b92f42012-01-22 16:05:15 +0000774struct dhcp_lease *lease4_allocate(struct in_addr addr)
Simon Kelleyc72daea2012-01-05 21:33:27 +0000775{
776 struct dhcp_lease *lease = lease_allocate();
Simon Kelley0b0a73c2013-04-11 14:07:02 +0100777 if (lease)
Julian Kornbergeraba8bbb2018-07-21 21:55:08 +0100778 {
779 lease->addr = addr;
780 daemon->metrics[METRIC_LEASES_ALLOCATED_4]++;
781 }
Simon Kelley89500e32013-09-20 16:29:20 +0100782
Simon Kelleyc72daea2012-01-05 21:33:27 +0000783 return lease;
784}
785
786#ifdef HAVE_DHCP6
Simon Kelley4cb1b322012-02-06 14:30:41 +0000787struct dhcp_lease *lease6_allocate(struct in6_addr *addrp, int lease_type)
Simon Kelleyc72daea2012-01-05 21:33:27 +0000788{
789 struct dhcp_lease *lease = lease_allocate();
Simon Kelley0b0a73c2013-04-11 14:07:02 +0100790
791 if (lease)
792 {
Simon Kelley89500e32013-09-20 16:29:20 +0100793 lease->addr6 = *addrp;
Simon Kelley0b0a73c2013-04-11 14:07:02 +0100794 lease->flags |= lease_type;
Simon Kelley89500e32013-09-20 16:29:20 +0100795 lease->iaid = 0;
Julian Kornbergeraba8bbb2018-07-21 21:55:08 +0100796
797 daemon->metrics[METRIC_LEASES_ALLOCATED_6]++;
Simon Kelley0b0a73c2013-04-11 14:07:02 +0100798 }
Simon Kelleyc72daea2012-01-05 21:33:27 +0000799
800 return lease;
801}
802#endif
803
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100804void lease_set_expires(struct dhcp_lease *lease, unsigned int len, time_t now)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000805{
Simon Kelleydd0e0a32014-01-22 11:16:59 +0000806 time_t exp;
807
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100808 if (len == 0xffffffff)
809 {
810 exp = 0;
811 len = 0;
812 }
Simon Kelleydd0e0a32014-01-22 11:16:59 +0000813 else
814 {
815 exp = now + (time_t)len;
816 /* Check for 2038 overflow. Make the lease
Josh Soref730c6742017-02-06 16:14:04 +0000817 infinite in that case, as the least disruptive
Simon Kelleydd0e0a32014-01-22 11:16:59 +0000818 thing we can do. */
819 if (difftime(exp, now) <= 0.0)
820 exp = 0;
821 }
822
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000823 if (exp != lease->expires)
Simon Kelley0a852542005-03-23 20:28:59 +0000824 {
Simon Kelley0a852542005-03-23 20:28:59 +0000825 dns_dirty = 1;
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100826 lease->expires = exp;
827#ifndef HAVE_BROKEN_RTC
Simon Kelley4cb1b322012-02-06 14:30:41 +0000828 lease->flags |= LEASE_AUX_CHANGED;
829 file_dirty = 1;
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100830#endif
Simon Kelley0a852542005-03-23 20:28:59 +0000831 }
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100832
833#ifdef HAVE_BROKEN_RTC
834 if (len != lease->length)
835 {
836 lease->length = len;
Simon Kelleyb7f40202012-02-29 21:43:37 +0000837 lease->flags |= LEASE_AUX_CHANGED;
838 file_dirty = 1;
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100839 }
840#endif
841}
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000842
Simon Kelley89500e32013-09-20 16:29:20 +0100843#ifdef HAVE_DHCP6
844void lease_set_iaid(struct dhcp_lease *lease, int iaid)
845{
846 if (lease->iaid != iaid)
847 {
848 lease->iaid = iaid;
849 lease->flags |= LEASE_CHANGED;
850 }
851}
852#endif
853
Nicolas Cavallari64bcff12015-04-28 21:55:18 +0100854void lease_set_hwaddr(struct dhcp_lease *lease, const unsigned char *hwaddr,
855 const unsigned char *clid, int hw_len, int hw_type,
856 int clid_len, time_t now, int force)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000857{
Simon Kelley353ae4d2012-03-19 20:07:51 +0000858#ifdef HAVE_DHCP6
Simon Kelleya9ab7322012-04-28 11:29:37 +0100859 int change = force;
Simon Kelley353ae4d2012-03-19 20:07:51 +0000860 lease->flags |= LEASE_HAVE_HWADDR;
861#endif
862
Simon Kelleya9ab7322012-04-28 11:29:37 +0100863 (void)force;
Vladislav Grishenko408c3682013-09-24 16:18:49 +0100864 (void)now;
Simon Kelleya9ab7322012-04-28 11:29:37 +0100865
Simon Kelleycdeda282006-03-16 20:16:06 +0000866 if (hw_len != lease->hwaddr_len ||
867 hw_type != lease->hwaddr_type ||
Simon Kelley7cebd202006-05-06 14:13:33 +0100868 (hw_len != 0 && memcmp(lease->hwaddr, hwaddr, hw_len) != 0))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000869 {
Simon Kelley4cb1b322012-02-06 14:30:41 +0000870 if (hw_len != 0)
871 memcpy(lease->hwaddr, hwaddr, hw_len);
Simon Kelleycdeda282006-03-16 20:16:06 +0000872 lease->hwaddr_len = hw_len;
873 lease->hwaddr_type = hw_type;
Simon Kelley4cb1b322012-02-06 14:30:41 +0000874 lease->flags |= LEASE_CHANGED;
875 file_dirty = 1; /* run script on change */
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000876 }
Simon Kelley0a852542005-03-23 20:28:59 +0000877
878 /* only update clid when one is available, stops packets
879 without a clid removing the record. Lease init uses
880 clid_len == 0 for no clid. */
881 if (clid_len != 0 && clid)
882 {
883 if (!lease->clid)
884 lease->clid_len = 0;
885
886 if (lease->clid_len != clid_len)
887 {
Simon Kelley4cb1b322012-02-06 14:30:41 +0000888 lease->flags |= LEASE_AUX_CHANGED;
889 file_dirty = 1;
Simon Kelley5aabfc72007-08-29 11:24:47 +0100890 free(lease->clid);
891 if (!(lease->clid = whine_malloc(clid_len)))
Simon Kelley7cebd202006-05-06 14:13:33 +0100892 return;
Simon Kelley353ae4d2012-03-19 20:07:51 +0000893#ifdef HAVE_DHCP6
894 change = 1;
895#endif
Simon Kelley0a852542005-03-23 20:28:59 +0000896 }
897 else if (memcmp(lease->clid, clid, clid_len) != 0)
Simon Kelley4cb1b322012-02-06 14:30:41 +0000898 {
899 lease->flags |= LEASE_AUX_CHANGED;
900 file_dirty = 1;
Simon Kelley353ae4d2012-03-19 20:07:51 +0000901#ifdef HAVE_DHCP6
902 change = 1;
903#endif
Simon Kelley4cb1b322012-02-06 14:30:41 +0000904 }
Simon Kelley353ae4d2012-03-19 20:07:51 +0000905
Simon Kelley0a852542005-03-23 20:28:59 +0000906 lease->clid_len = clid_len;
907 memcpy(lease->clid, clid, clid_len);
908 }
Simon Kelley353ae4d2012-03-19 20:07:51 +0000909
910#ifdef HAVE_DHCP6
911 if (change)
Simon Kelleya9ab7322012-04-28 11:29:37 +0100912 slaac_add_addrs(lease, now, force);
Simon Kelley353ae4d2012-03-19 20:07:51 +0000913#endif
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000914}
915
Simon Kelley9009d742008-11-14 20:04:27 +0000916static void kill_name(struct dhcp_lease *lease)
917{
918 /* run script to say we lost our old name */
919
920 /* this shouldn't happen unless updates are very quick and the
921 script very slow, we just avoid a memory leak if it does. */
922 free(lease->old_hostname);
923
924 /* If we know the fqdn, pass that. The helper will derive the
Simon Kelley4cb1b322012-02-06 14:30:41 +0000925 unqualified name from it, free the unqualified name here. */
Simon Kelley9009d742008-11-14 20:04:27 +0000926
927 if (lease->fqdn)
928 {
929 lease->old_hostname = lease->fqdn;
930 free(lease->hostname);
931 }
932 else
933 lease->old_hostname = lease->hostname;
934
935 lease->hostname = lease->fqdn = NULL;
936}
937
Nicolas Cavallari64bcff12015-04-28 21:55:18 +0100938void lease_set_hostname(struct dhcp_lease *lease, const char *name, int auth, char *domain, char *config_domain)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000939{
940 struct dhcp_lease *lease_tmp;
941 char *new_name = NULL, *new_fqdn = NULL;
Simon Kelley70c5e3e2012-02-06 22:05:15 +0000942
943 if (config_domain && (!domain || !hostname_isequal(domain, config_domain)))
944 my_syslog(MS_DHCP | LOG_WARNING, _("Ignoring domain %s for DHCP host name %s"), config_domain, name);
Simon Kelley9009d742008-11-14 20:04:27 +0000945
Simon Kelleya2226412004-05-13 20:27:08 +0100946 if (lease->hostname && name && hostname_isequal(lease->hostname, name))
Simon Kelleyb8187c82005-11-26 21:46:27 +0000947 {
Simon Kelley4cb1b322012-02-06 14:30:41 +0000948 if (auth)
949 lease->flags |= LEASE_AUTH_NAME;
Simon Kelleyb8187c82005-11-26 21:46:27 +0000950 return;
951 }
Simon Kelley7cebd202006-05-06 14:13:33 +0100952
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000953 if (!name && !lease->hostname)
954 return;
955
956 /* If a machine turns up on a new net without dropping the old lease,
957 or two machines claim the same name, then we end up with two interfaces with
Simon Kelleyb8187c82005-11-26 21:46:27 +0000958 the same name. Check for that here and remove the name from the old lease.
Simon Kelley4cb1b322012-02-06 14:30:41 +0000959 Note that IPv6 leases are different. All the leases to the same DUID are
960 allowed the same name.
961
Simon Kelleyb8187c82005-11-26 21:46:27 +0000962 Don't allow a name from the client to override a name from dnsmasq config. */
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000963
964 if (name)
965 {
Simon Kelley9009d742008-11-14 20:04:27 +0000966 if ((new_name = whine_malloc(strlen(name) + 1)))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000967 {
Simon Kelley9009d742008-11-14 20:04:27 +0000968 strcpy(new_name, name);
Simon Kelley4cb1b322012-02-06 14:30:41 +0000969 if (domain && (new_fqdn = whine_malloc(strlen(new_name) + strlen(domain) + 2)))
Simon Kelley9009d742008-11-14 20:04:27 +0000970 {
971 strcpy(new_fqdn, name);
972 strcat(new_fqdn, ".");
Simon Kelley4cb1b322012-02-06 14:30:41 +0000973 strcat(new_fqdn, domain);
Simon Kelley9009d742008-11-14 20:04:27 +0000974 }
975 }
976
977 /* Depending on mode, we check either unqualified name or FQDN. */
978 for (lease_tmp = leases; lease_tmp; lease_tmp = lease_tmp->next)
979 {
Simon Kelley28866e92011-02-14 20:19:14 +0000980 if (option_bool(OPT_DHCP_FQDN))
Simon Kelley9009d742008-11-14 20:04:27 +0000981 {
Simon Kelley4cb1b322012-02-06 14:30:41 +0000982 if (!new_fqdn || !lease_tmp->fqdn || !hostname_isequal(lease_tmp->fqdn, new_fqdn))
Simon Kelley9009d742008-11-14 20:04:27 +0000983 continue;
984 }
985 else
986 {
987 if (!new_name || !lease_tmp->hostname || !hostname_isequal(lease_tmp->hostname, new_name) )
988 continue;
989 }
Simon Kelley4cb1b322012-02-06 14:30:41 +0000990
991 if (lease->flags & (LEASE_TA | LEASE_NA))
992 {
993 if (!(lease_tmp->flags & (LEASE_TA | LEASE_NA)))
994 continue;
995
Simon Kelleyceae00d2012-02-09 21:28:14 +0000996 /* another lease for the same DUID is OK for IPv6 */
Simon Kelley4cb1b322012-02-06 14:30:41 +0000997 if (lease->clid_len == lease_tmp->clid_len &&
998 lease->clid && lease_tmp->clid &&
999 memcmp(lease->clid, lease_tmp->clid, lease->clid_len) == 0)
1000 continue;
1001 }
1002 else if (lease_tmp->flags & (LEASE_TA | LEASE_NA))
1003 continue;
1004
1005 if ((lease_tmp->flags & LEASE_AUTH_NAME) && !auth)
Simon Kelley9009d742008-11-14 20:04:27 +00001006 {
1007 free(new_name);
1008 free(new_fqdn);
1009 return;
1010 }
1011
1012 kill_name(lease_tmp);
1013 break;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001014 }
1015 }
1016
1017 if (lease->hostname)
Simon Kelley9009d742008-11-14 20:04:27 +00001018 kill_name(lease);
Simon Kelley16972692006-10-16 20:04:18 +01001019
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001020 lease->hostname = new_name;
1021 lease->fqdn = new_fqdn;
Simon Kelley4cb1b322012-02-06 14:30:41 +00001022
1023 if (auth)
1024 lease->flags |= LEASE_AUTH_NAME;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001025
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001026 file_dirty = 1;
Simon Kelley7cebd202006-05-06 14:13:33 +01001027 dns_dirty = 1;
Simon Kelley4cb1b322012-02-06 14:30:41 +00001028 lease->flags |= LEASE_CHANGED; /* run script on change */
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001029}
1030
Simon Kelley353ae4d2012-03-19 20:07:51 +00001031void lease_set_interface(struct dhcp_lease *lease, int interface, time_t now)
Simon Kelley824af852008-02-12 20:43:05 +00001032{
Vladislav Grishenko408c3682013-09-24 16:18:49 +01001033 (void)now;
1034
Simon Kelley824af852008-02-12 20:43:05 +00001035 if (lease->last_interface == interface)
1036 return;
1037
1038 lease->last_interface = interface;
Simon Kelley4cb1b322012-02-06 14:30:41 +00001039 lease->flags |= LEASE_CHANGED;
Simon Kelley353ae4d2012-03-19 20:07:51 +00001040
1041#ifdef HAVE_DHCP6
Simon Kelleya9ab7322012-04-28 11:29:37 +01001042 slaac_add_addrs(lease, now, 0);
Simon Kelley353ae4d2012-03-19 20:07:51 +00001043#endif
Simon Kelley824af852008-02-12 20:43:05 +00001044}
1045
Simon Kelley5aabfc72007-08-29 11:24:47 +01001046void rerun_scripts(void)
1047{
1048 struct dhcp_lease *lease;
1049
1050 for (lease = leases; lease; lease = lease->next)
Simon Kelley4cb1b322012-02-06 14:30:41 +00001051 lease->flags |= LEASE_CHANGED;
Simon Kelley5aabfc72007-08-29 11:24:47 +01001052}
1053
Simon Kelley7cebd202006-05-06 14:13:33 +01001054/* deleted leases get transferred to the old_leases list.
1055 remove them here, after calling the lease change
Simon Kelley16972692006-10-16 20:04:18 +01001056 script. Also run the lease change script on new/modified leases.
1057
1058 Return zero if nothing to do. */
Simon Kelley5aabfc72007-08-29 11:24:47 +01001059int do_script_run(time_t now)
Simon Kelley7cebd202006-05-06 14:13:33 +01001060{
1061 struct dhcp_lease *lease;
1062
Vladislav Grishenko408c3682013-09-24 16:18:49 +01001063 (void)now;
1064
Simon Kelley9009d742008-11-14 20:04:27 +00001065#ifdef HAVE_DBUS
1066 /* If we're going to be sending DBus signals, but the connection is not yet up,
1067 delay everything until it is. */
Simon Kelley28866e92011-02-14 20:19:14 +00001068 if (option_bool(OPT_DBUS) && !daemon->dbus)
Simon Kelley9009d742008-11-14 20:04:27 +00001069 return 0;
1070#endif
1071
Simon Kelley16972692006-10-16 20:04:18 +01001072 if (old_leases)
Simon Kelley7cebd202006-05-06 14:13:33 +01001073 {
Simon Kelley7cebd202006-05-06 14:13:33 +01001074 lease = old_leases;
Simon Kelley16972692006-10-16 20:04:18 +01001075
1076 /* If the lease still has an old_hostname, do the "old" action on that first */
1077 if (lease->old_hostname)
1078 {
Simon Kelley1f15b812009-10-13 17:49:32 +01001079#ifdef HAVE_SCRIPT
Simon Kelley5aabfc72007-08-29 11:24:47 +01001080 queue_script(ACTION_OLD_HOSTNAME, lease, lease->old_hostname, now);
1081#endif
Simon Kelley16972692006-10-16 20:04:18 +01001082 free(lease->old_hostname);
1083 lease->old_hostname = NULL;
1084 return 1;
1085 }
1086 else
1087 {
Simon Kelley353ae4d2012-03-19 20:07:51 +00001088#ifdef HAVE_DHCP6
1089 struct slaac_address *slaac, *tmp;
1090 for (slaac = lease->slaac_address; slaac; slaac = tmp)
1091 {
1092 tmp = slaac->next;
1093 free(slaac);
1094 }
1095#endif
Simon Kelley9009d742008-11-14 20:04:27 +00001096 kill_name(lease);
Simon Kelley1f15b812009-10-13 17:49:32 +01001097#ifdef HAVE_SCRIPT
Simon Kelley9009d742008-11-14 20:04:27 +00001098 queue_script(ACTION_DEL, lease, lease->old_hostname, now);
Simon Kelley5aabfc72007-08-29 11:24:47 +01001099#endif
Simon Kelley1f15b812009-10-13 17:49:32 +01001100#ifdef HAVE_DBUS
1101 emit_dbus_signal(ACTION_DEL, lease, lease->old_hostname);
1102#endif
Simon Kelley16972692006-10-16 20:04:18 +01001103 old_leases = lease->next;
1104
Simon Kelley9009d742008-11-14 20:04:27 +00001105 free(lease->old_hostname);
Simon Kelley5aabfc72007-08-29 11:24:47 +01001106 free(lease->clid);
Simon Kelley316e2732010-01-22 20:16:09 +00001107 free(lease->extradata);
Simon Kelley16972692006-10-16 20:04:18 +01001108 free(lease);
1109
1110 return 1;
1111 }
Simon Kelley7cebd202006-05-06 14:13:33 +01001112 }
Simon Kelley16972692006-10-16 20:04:18 +01001113
1114 /* make sure we announce the loss of a hostname before its new location. */
1115 for (lease = leases; lease; lease = lease->next)
1116 if (lease->old_hostname)
1117 {
Simon Kelley1f15b812009-10-13 17:49:32 +01001118#ifdef HAVE_SCRIPT
Simon Kelley5aabfc72007-08-29 11:24:47 +01001119 queue_script(ACTION_OLD_HOSTNAME, lease, lease->old_hostname, now);
1120#endif
Simon Kelley16972692006-10-16 20:04:18 +01001121 free(lease->old_hostname);
1122 lease->old_hostname = NULL;
1123 return 1;
1124 }
1125
Simon Kelley7cebd202006-05-06 14:13:33 +01001126 for (lease = leases; lease; lease = lease->next)
Simon Kelley4cb1b322012-02-06 14:30:41 +00001127 if ((lease->flags & (LEASE_NEW | LEASE_CHANGED)) ||
1128 ((lease->flags & LEASE_AUX_CHANGED) && option_bool(OPT_LEASE_RO)))
Simon Kelley7cebd202006-05-06 14:13:33 +01001129 {
Simon Kelley1f15b812009-10-13 17:49:32 +01001130#ifdef HAVE_SCRIPT
Simon Kelley4cb1b322012-02-06 14:30:41 +00001131 queue_script((lease->flags & LEASE_NEW) ? ACTION_ADD : ACTION_OLD, lease,
Simon Kelley9009d742008-11-14 20:04:27 +00001132 lease->fqdn ? lease->fqdn : lease->hostname, now);
Simon Kelley5aabfc72007-08-29 11:24:47 +01001133#endif
Simon Kelley1f15b812009-10-13 17:49:32 +01001134#ifdef HAVE_DBUS
Simon Kelley4cb1b322012-02-06 14:30:41 +00001135 emit_dbus_signal((lease->flags & LEASE_NEW) ? ACTION_ADD : ACTION_OLD, lease,
Simon Kelley1f15b812009-10-13 17:49:32 +01001136 lease->fqdn ? lease->fqdn : lease->hostname);
1137#endif
Simon Kelley4cb1b322012-02-06 14:30:41 +00001138 lease->flags &= ~(LEASE_NEW | LEASE_CHANGED | LEASE_AUX_CHANGED);
Simon Kelley16972692006-10-16 20:04:18 +01001139
Simon Kelley316e2732010-01-22 20:16:09 +00001140 /* this is used for the "add" call, then junked, since they're not in the database */
1141 free(lease->extradata);
1142 lease->extradata = NULL;
Simon Kelley16972692006-10-16 20:04:18 +01001143
1144 return 1;
Simon Kelley7cebd202006-05-06 14:13:33 +01001145 }
Simon Kelley16972692006-10-16 20:04:18 +01001146
1147 return 0; /* nothing to do */
Simon Kelley7cebd202006-05-06 14:13:33 +01001148}
Simon Kelley7622fc02009-06-04 20:32:05 +01001149
Simon Kelleyceae00d2012-02-09 21:28:14 +00001150#ifdef HAVE_SCRIPT
Josh Soref730c6742017-02-06 16:14:04 +00001151/* delim == -1 -> delim = 0, but embedded 0s, creating extra records, are OK. */
Simon Kelleyceae00d2012-02-09 21:28:14 +00001152void lease_add_extradata(struct dhcp_lease *lease, unsigned char *data, unsigned int len, int delim)
1153{
1154 unsigned int i;
1155
Simon Kelleya93bd4b2016-03-01 18:58:01 +00001156 if (delim == -1)
1157 delim = 0;
1158 else
Josh Soref730c6742017-02-06 16:14:04 +00001159 /* check for embedded NULLs */
Simon Kelleya93bd4b2016-03-01 18:58:01 +00001160 for (i = 0; i < len; i++)
1161 if (data[i] == 0)
1162 {
1163 len = i;
1164 break;
1165 }
1166
Simon Kelleyceae00d2012-02-09 21:28:14 +00001167 if ((lease->extradata_size - lease->extradata_len) < (len + 1))
1168 {
1169 size_t newsz = lease->extradata_len + len + 100;
1170 unsigned char *new = whine_malloc(newsz);
1171
1172 if (!new)
1173 return;
1174
1175 if (lease->extradata)
1176 {
1177 memcpy(new, lease->extradata, lease->extradata_len);
1178 free(lease->extradata);
1179 }
1180
1181 lease->extradata = new;
1182 lease->extradata_size = newsz;
1183 }
1184
1185 if (len != 0)
1186 memcpy(lease->extradata + lease->extradata_len, data, len);
1187 lease->extradata[lease->extradata_len + len] = delim;
1188 lease->extradata_len += len + 1;
1189}
1190#endif
1191
Simon Kelley7622fc02009-06-04 20:32:05 +01001192#endif
Simon Kelley7cebd202006-05-06 14:13:33 +01001193
1194
1195
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001196