• source navigation  • diff markup  • identifier search  • freetext search  • 

Sources/odhcpd/src/config.c

  1 #include <errno.h>
  2 #include <fcntl.h>
  3 #include <resolv.h>
  4 #include <signal.h>
  5 #include <arpa/inet.h>
  6 #include <unistd.h>
  7 #include <libgen.h>
  8 #include <net/if.h>
  9 #include <string.h>
 10 #include <sys/stat.h>
 11 #include <ctype.h>
 12 
 13 #include <uci.h>
 14 #include <uci_blob.h>
 15 #include <json-c/json.h>
 16 #include <libubox/utils.h>
 17 #include <libubox/avl.h>
 18 #include <libubox/avl-cmp.h>
 19 #include <libubox/list.h>
 20 #include <libubox/vlist.h>
 21 
 22 #include "odhcpd.h"
 23 #include "router.h"
 24 #include "dhcpv6-pxe.h"
 25 #include "dhcpv4.h"
 26 
 27 static struct blob_buf b;
 28 
 29 static int lease_cfg_cmp(const void *k1, const void *k2, void *ptr);
 30 static void lease_cfg_update(struct vlist_tree *tree, struct vlist_node *node_new,
 31                              struct vlist_node *node_old);
 32 
 33 struct vlist_tree lease_cfgs = VLIST_TREE_INIT(lease_cfgs, lease_cfg_cmp,
 34                                                lease_cfg_update, true, false);
 35 
 36 AVL_TREE(interfaces, avl_strcmp, false, NULL);
 37 struct config config = {
 38         .enable_tz = true,
 39         .main_dhcpv4 = false,
 40         .dhcp_cb = NULL,
 41 #ifdef WITH_UBUS
 42         .use_ubus = true,
 43 #else
 44         .use_ubus = false,
 45 #endif /* WITH_UBUS */
 46         .dhcp_statefile = NULL,
 47         .dhcp_statedir_fd = -1,
 48         .dhcp_hostsdir = NULL,
 49         .dhcp_hostsdir_fd = -1,
 50         .ra_piofolder = NULL,
 51         .ra_piofolder_fd = -1,
 52         .uci_cfgdir = NULL,
 53         .log_level = LOG_WARNING,
 54         .log_level_cmdline = false,
 55         .log_syslog = true,
 56         .default_duid = { 0 },
 57         .default_duid_len = 0,
 58 };
 59 
 60 struct sys_conf sys_conf = {
 61         .posix_tz = NULL, // "timezone"
 62         .posix_tz_len = 0,
 63         .tzdb_tz = NULL, // "zonename"
 64         .tzdb_tz_len = 0,
 65 };
 66 
 67 #define DHCPV4_POOL_LIMIT_DEFAULT       150
 68 
 69 #define HOSTID_LEN_MIN  12
 70 #define HOSTID_LEN_MAX  64
 71 #define HOSTID_LEN_DEFAULT HOSTID_LEN_MIN
 72 
 73 #define PD_MIN_LEN_MAX (64-2) // must delegate at least 2 bits of prefix
 74 
 75 #define OAF_DHCPV6      (OAF_DHCPV6_NA | OAF_DHCPV6_PD)
 76 
 77 enum {
 78         IPV6_PXE_URL,
 79         IPV6_PXE_ARCH,
 80         IPV6_PXE_MAX
 81 };
 82 
 83 static const struct blobmsg_policy ipv6_pxe_attrs[IPV6_PXE_MAX] = {
 84         [IPV6_PXE_URL] = {.name = "url", .type = BLOBMSG_TYPE_STRING },
 85         [IPV6_PXE_ARCH] = {.name = "arch", .type = BLOBMSG_TYPE_INT32 },
 86 };
 87 
 88 const struct uci_blob_param_list ipv6_pxe_attr_list = {
 89         .n_params = IPV6_PXE_MAX,
 90         .params = ipv6_pxe_attrs,
 91 };
 92 
 93 enum {
 94         IFACE_ATTR_INTERFACE,
 95         IFACE_ATTR_IFNAME,
 96         IFACE_ATTR_NETWORKID,
 97         IFACE_ATTR_DYNAMICDHCP,
 98         IFACE_ATTR_LEASETIME,
 99         IFACE_ATTR_DHCPV4_POOL_START,
100         IFACE_ATTR_DHCPV4_POOL_LIMIT,
101         IFACE_ATTR_MASTER,
102         IFACE_ATTR_UPSTREAM,
103         IFACE_ATTR_RA,
104         IFACE_ATTR_DHCPV4,
105         IFACE_ATTR_DHCPV6,
106         IFACE_ATTR_NDP,
107         IFACE_ATTR_ROUTER,
108         IFACE_ATTR_DNS,
109         IFACE_ATTR_DNR,
110         IFACE_ATTR_DNS_SERVICE,
111         IFACE_ATTR_DNS_DOMAIN_SEARCH,
112         IFACE_ATTR_DHCPV4_FORCERECONF,
113         IFACE_ATTR_DHCPV6_RAW,
114         IFACE_ATTR_DHCPV6_ASSIGNALL,
115         IFACE_ATTR_DHCPV6_PD_PREFERRED,
116         IFACE_ATTR_DHCPV6_PD,
117         IFACE_ATTR_DHCPV6_PD_MIN_LEN,
118         IFACE_ATTR_DHCPV6_NA,
119         IFACE_ATTR_DHCPV6_HOSTID_LEN,
120         IFACE_ATTR_RA_DEFAULT,
121         IFACE_ATTR_RA_FLAGS,
122         IFACE_ATTR_RA_SLAAC,
123         IFACE_ATTR_RA_OFFLINK,
124         IFACE_ATTR_RA_PREFERENCE,
125         IFACE_ATTR_RA_ADVROUTER,
126         IFACE_ATTR_RA_MININTERVAL,
127         IFACE_ATTR_RA_MAXINTERVAL,
128         IFACE_ATTR_RA_LIFETIME,
129         IFACE_ATTR_RA_REACHABLETIME,
130         IFACE_ATTR_RA_RETRANSTIME,
131         IFACE_ATTR_RA_HOPLIMIT,
132         IFACE_ATTR_RA_MTU,
133         IFACE_ATTR_RA_DNS,
134         IFACE_ATTR_RA_PREF64,
135         IFACE_ATTR_NDPROXY_ROUTING,
136         IFACE_ATTR_NDPROXY_SLAVE,
137         IFACE_ATTR_NDP_FROM_LINK_LOCAL,
138         IFACE_ATTR_PREFIX_FILTER,
139         IFACE_ATTR_MAX_PREFERRED_LIFETIME,
140         IFACE_ATTR_MAX_VALID_LIFETIME,
141         IFACE_ATTR_NTP,
142         IFACE_ATTR_CAPTIVE_PORTAL_URI,
143         IFACE_ATTR_IPV6_ONLY_PREFERRED,
144         IFACE_ATTR_MAX
145 };
146 
147 static const struct blobmsg_policy iface_attrs[IFACE_ATTR_MAX] = {
148         [IFACE_ATTR_INTERFACE] = { .name = "interface", .type = BLOBMSG_TYPE_STRING },
149         [IFACE_ATTR_IFNAME] = { .name = "ifname", .type = BLOBMSG_TYPE_STRING },
150         [IFACE_ATTR_NETWORKID] = { .name = "networkid", .type = BLOBMSG_TYPE_STRING },
151         [IFACE_ATTR_DYNAMICDHCP] = { .name = "dynamicdhcp", .type = BLOBMSG_TYPE_BOOL },
152         [IFACE_ATTR_LEASETIME] = { .name = "leasetime", .type = BLOBMSG_TYPE_STRING },
153         [IFACE_ATTR_DHCPV4_POOL_START] = { .name = "start", .type = BLOBMSG_TYPE_INT32 },
154         [IFACE_ATTR_DHCPV4_POOL_LIMIT] = { .name = "limit", .type = BLOBMSG_TYPE_INT32 },
155         [IFACE_ATTR_MASTER] = { .name = "master", .type = BLOBMSG_TYPE_BOOL },
156         [IFACE_ATTR_UPSTREAM] = { .name = "upstream", .type = BLOBMSG_TYPE_ARRAY },
157         [IFACE_ATTR_RA] = { .name = "ra", .type = BLOBMSG_TYPE_STRING },
158         [IFACE_ATTR_DHCPV4] = { .name = "dhcpv4", .type = BLOBMSG_TYPE_STRING },
159         [IFACE_ATTR_DHCPV6] = { .name = "dhcpv6", .type = BLOBMSG_TYPE_STRING },
160         [IFACE_ATTR_NDP] = { .name = "ndp", .type = BLOBMSG_TYPE_STRING },
161         [IFACE_ATTR_ROUTER] = { .name = "router", .type = BLOBMSG_TYPE_ARRAY },
162         [IFACE_ATTR_DNS] = { .name = "dns", .type = BLOBMSG_TYPE_ARRAY },
163         [IFACE_ATTR_DNR] = { .name = "dnr", .type = BLOBMSG_TYPE_ARRAY },
164         [IFACE_ATTR_DNS_SERVICE] = { .name = "dns_service", .type = BLOBMSG_TYPE_BOOL },
165         [IFACE_ATTR_DNS_DOMAIN_SEARCH] = { .name = "domain", .type = BLOBMSG_TYPE_ARRAY },
166         [IFACE_ATTR_DHCPV4_FORCERECONF] = { .name = "dhcpv4_forcereconf", .type = BLOBMSG_TYPE_BOOL },
167         [IFACE_ATTR_DHCPV6_RAW] = { .name = "dhcpv6_raw", .type = BLOBMSG_TYPE_STRING },
168         [IFACE_ATTR_DHCPV6_ASSIGNALL] = { .name ="dhcpv6_assignall", .type = BLOBMSG_TYPE_BOOL },
169         [IFACE_ATTR_DHCPV6_PD_PREFERRED] = { .name = "dhcpv6_pd_preferred", .type = BLOBMSG_TYPE_BOOL },
170         [IFACE_ATTR_DHCPV6_PD] = { .name = "dhcpv6_pd", .type = BLOBMSG_TYPE_BOOL },
171         [IFACE_ATTR_DHCPV6_PD_MIN_LEN] = { .name = "dhcpv6_pd_min_len", .type = BLOBMSG_TYPE_INT32 },
172         [IFACE_ATTR_DHCPV6_NA] = { .name = "dhcpv6_na", .type = BLOBMSG_TYPE_BOOL },
173         [IFACE_ATTR_DHCPV6_HOSTID_LEN] = { .name = "dhcpv6_hostidlength", .type = BLOBMSG_TYPE_INT32 },
174         [IFACE_ATTR_RA_DEFAULT] = { .name = "ra_default", .type = BLOBMSG_TYPE_INT32 },
175         [IFACE_ATTR_RA_FLAGS] = { .name = "ra_flags", . type = BLOBMSG_TYPE_ARRAY },
176         [IFACE_ATTR_RA_SLAAC] = { .name = "ra_slaac", .type = BLOBMSG_TYPE_BOOL },
177         [IFACE_ATTR_RA_OFFLINK] = { .name = "ra_offlink", .type = BLOBMSG_TYPE_BOOL },
178         [IFACE_ATTR_RA_PREFERENCE] = { .name = "ra_preference", .type = BLOBMSG_TYPE_STRING },
179         [IFACE_ATTR_RA_ADVROUTER] = { .name = "ra_advrouter", .type = BLOBMSG_TYPE_BOOL },
180         [IFACE_ATTR_RA_MININTERVAL] = { .name = "ra_mininterval", .type = BLOBMSG_TYPE_INT32 },
181         [IFACE_ATTR_RA_MAXINTERVAL] = { .name = "ra_maxinterval", .type = BLOBMSG_TYPE_INT32 },
182         [IFACE_ATTR_RA_LIFETIME] = { .name = "ra_lifetime", .type = BLOBMSG_TYPE_INT32 },
183         [IFACE_ATTR_RA_REACHABLETIME] = { .name = "ra_reachabletime", .type = BLOBMSG_TYPE_INT32 },
184         [IFACE_ATTR_RA_RETRANSTIME] = { .name = "ra_retranstime", .type = BLOBMSG_TYPE_INT32 },
185         [IFACE_ATTR_RA_HOPLIMIT] = { .name = "ra_hoplimit", .type = BLOBMSG_TYPE_INT32 },
186         [IFACE_ATTR_RA_MTU] = { .name = "ra_mtu", .type = BLOBMSG_TYPE_INT32 },
187         [IFACE_ATTR_RA_DNS] = { .name = "ra_dns", .type = BLOBMSG_TYPE_BOOL },
188         [IFACE_ATTR_RA_PREF64] = { .name = "ra_pref64", .type = BLOBMSG_TYPE_STRING },
189         [IFACE_ATTR_NDPROXY_ROUTING] = { .name = "ndproxy_routing", .type = BLOBMSG_TYPE_BOOL },
190         [IFACE_ATTR_NDPROXY_SLAVE] = { .name = "ndproxy_slave", .type = BLOBMSG_TYPE_BOOL },
191         [IFACE_ATTR_NDP_FROM_LINK_LOCAL] = { .name = "ndp_from_link_local", .type = BLOBMSG_TYPE_BOOL },
192         [IFACE_ATTR_PREFIX_FILTER] = { .name = "prefix_filter", .type = BLOBMSG_TYPE_STRING },
193         [IFACE_ATTR_MAX_PREFERRED_LIFETIME] = { .name = "max_preferred_lifetime", .type = BLOBMSG_TYPE_STRING },
194         [IFACE_ATTR_MAX_VALID_LIFETIME] = { .name = "max_valid_lifetime", .type = BLOBMSG_TYPE_STRING },
195         [IFACE_ATTR_NTP] = { .name = "ntp", .type = BLOBMSG_TYPE_ARRAY },
196         [IFACE_ATTR_CAPTIVE_PORTAL_URI] = { .name = "captive_portal_uri", .type = BLOBMSG_TYPE_STRING },
197         [IFACE_ATTR_IPV6_ONLY_PREFERRED] = { .name = "ipv6_only_preferred", .type = BLOBMSG_TYPE_INT32 },
198 };
199 
200 const struct uci_blob_param_list interface_attr_list = {
201         .n_params = IFACE_ATTR_MAX,
202         .params = iface_attrs,
203 };
204 
205 const struct blobmsg_policy lease_cfg_attrs[LEASE_CFG_ATTR_MAX] = {
206         [LEASE_CFG_ATTR_IPV4] = { .name = "ip", .type = BLOBMSG_TYPE_STRING },
207         [LEASE_CFG_ATTR_MAC] = { .name = "mac", .type = BLOBMSG_TYPE_ARRAY },
208         [LEASE_CFG_ATTR_DUID] = { .name = "duid", .type = BLOBMSG_TYPE_ARRAY },
209         [LEASE_CFG_ATTR_HOSTID] = { .name = "hostid", .type = BLOBMSG_TYPE_STRING },
210         [LEASE_CFG_ATTR_LEASETIME] = { .name = "leasetime", .type = BLOBMSG_TYPE_STRING },
211         [LEASE_CFG_ATTR_NAME] = { .name = "name", .type = BLOBMSG_TYPE_STRING },
212 };
213 
214 const struct uci_blob_param_list lease_cfg_attr_list = {
215         .n_params = LEASE_CFG_ATTR_MAX,
216         .params = lease_cfg_attrs,
217 };
218 
219 enum {
220         ODHCPD_ATTR_MAINDHCP,
221         ODHCPD_ATTR_LEASEFILE,
222         ODHCPD_ATTR_LEASETRIGGER,
223         ODHCPD_ATTR_LOGLEVEL,
224         ODHCPD_ATTR_HOSTSDIR,
225         ODHCPD_ATTR_PIOFOLDER,
226         ODHCPD_ATTR_ENABLE_TZ,
227         ODHCPD_ATTR_MAX
228 };
229 
230 static const struct blobmsg_policy odhcpd_attrs[ODHCPD_ATTR_MAX] = {
231         [ODHCPD_ATTR_MAINDHCP] = { .name = "maindhcp", .type = BLOBMSG_TYPE_BOOL },
232         [ODHCPD_ATTR_LEASEFILE] = { .name = "leasefile", .type = BLOBMSG_TYPE_STRING },
233         [ODHCPD_ATTR_LEASETRIGGER] = { .name = "leasetrigger", .type = BLOBMSG_TYPE_STRING },
234         [ODHCPD_ATTR_LOGLEVEL] = { .name = "loglevel", .type = BLOBMSG_TYPE_INT32 },
235         [ODHCPD_ATTR_HOSTSDIR] = { .name = "hostsdir", .type = BLOBMSG_TYPE_STRING },
236         [ODHCPD_ATTR_PIOFOLDER] = { .name = "piofolder", .type = BLOBMSG_TYPE_STRING },
237         [ODHCPD_ATTR_ENABLE_TZ] = { .name = "enable_tz", .type = BLOBMSG_TYPE_BOOL },
238 };
239 
240 const struct uci_blob_param_list odhcpd_attr_list = {
241         .n_params = ODHCPD_ATTR_MAX,
242         .params = odhcpd_attrs,
243 };
244 
245 enum {
246         SYSTEM_ATTR_TIMEZONE,
247         SYSTEM_ATTR_ZONENAME,
248         SYSTEM_ATTR_MAX
249 };
250 
251 static const struct blobmsg_policy system_attrs[SYSTEM_ATTR_MAX] = {
252         [SYSTEM_ATTR_TIMEZONE] = { .name = "timezone", .type = BLOBMSG_TYPE_STRING },
253         [SYSTEM_ATTR_ZONENAME] = { .name = "zonename", .type = BLOBMSG_TYPE_STRING },
254 };
255 
256 const struct uci_blob_param_list system_attr_list = {
257         .n_params = SYSTEM_ATTR_MAX,
258         .params = system_attrs,
259 };
260 
261 enum {
262         GLOBAL_ATTR_DUID,
263         GLOBAL_ATTR_MAX
264 };
265 
266 static const struct blobmsg_policy global_attrs[GLOBAL_ATTR_MAX] = {
267         [GLOBAL_ATTR_DUID] = { .name = "dhcp_default_duid", .type = BLOBMSG_TYPE_STRING },
268 };
269 
270 const struct uci_blob_param_list global_attr_list = {
271         .n_params = GLOBAL_ATTR_MAX,
272         .params = global_attrs,
273 };
274 
275 static const struct { const char *name; uint8_t flag; } ra_flags[] = {
276         { .name = "managed-config", .flag = ND_RA_FLAG_MANAGED },
277         { .name = "other-config", .flag = ND_RA_FLAG_OTHER },
278         { .name = "home-agent", .flag = ND_RA_FLAG_HOME_AGENT },
279         { .name = "none", . flag = 0 },
280         { .name = NULL, },
281 };
282 
283 // https://www.iana.org/assignments/dns-svcb/dns-svcb.xhtml
284 enum svc_param_keys {
285         DNR_SVC_MANDATORY,
286         DNR_SVC_ALPN,
287         DNR_SVC_NO_DEFAULT_ALPN,
288         DNR_SVC_PORT,
289         DNR_SVC_IPV4HINT,
290         DNR_SVC_ECH,
291         DNR_SVC_IPV6HINT,
292         DNR_SVC_DOHPATH,
293         DNR_SVC_OHTTP,
294         DNR_SVC_MAX,
295 };
296 
297 static const char *svc_param_key_names[DNR_SVC_MAX] = {
298         [DNR_SVC_MANDATORY] = "mandatory",
299         [DNR_SVC_ALPN] = "alpn",
300         [DNR_SVC_NO_DEFAULT_ALPN] = "no-default-alpn",
301         [DNR_SVC_PORT] = "port",
302         [DNR_SVC_IPV4HINT] = "ipv4hint",
303         [DNR_SVC_ECH] = "ech",
304         [DNR_SVC_IPV6HINT] = "ipv6hint",
305         [DNR_SVC_DOHPATH] = "dohpath",
306         [DNR_SVC_OHTTP] = "ohttp",
307 };
308 
309 static void set_interface_defaults(struct interface *iface)
310 {
311         iface->ignore = true;
312         iface->dhcpv4 = MODE_DISABLED;
313         iface->dhcpv6 = MODE_DISABLED;
314         iface->ra = MODE_DISABLED;
315         iface->ndp = MODE_DISABLED;
316         iface->learn_routes = 1;
317         iface->ndp_from_link_local = true;
318         iface->cached_linklocal_valid = false;
319         iface->dhcp_leasetime = 43200;
320         iface->max_preferred_lifetime = ND_PREFERRED_LIMIT;
321         iface->max_valid_lifetime = ND_VALID_LIMIT;
322         iface->captive_portal_uri = NULL;
323         iface->dhcpv4_pool_start = 0;
324         iface->dhcpv4_pool_end = 0;
325         iface->dhcpv6_assignall = true;
326         iface->dhcpv6_pd = true;
327         iface->dhcpv6_pd_preferred = false;
328         iface->dhcpv6_pd_min_len = 0;
329         iface->dhcpv6_na = true;
330         iface->dhcpv6_hostid_len = HOSTID_LEN_DEFAULT;
331         iface->dns_service = true;
332         iface->ra_flags = ND_RA_FLAG_OTHER;
333         iface->ra_slaac = true;
334         iface->ra_maxinterval = 600;
335         /*
336          * RFC4861: MinRtrAdvInterval: Default: 0.33 * MaxRtrAdvInterval If
337          * MaxRtrAdvInterval >= 9 seconds; otherwise, the Default is MaxRtrAdvInterval.
338          */
339         iface->ra_mininterval = iface->ra_maxinterval/3;
340         iface->ra_lifetime = 3 * iface->ra_maxinterval; /* RFC4861: AdvDefaultLifetime: Default: 3 * MaxRtrAdvInterval */
341         iface->ra_dns = true;
342         iface->pio_update = false;
343         iface->update_statefile = true;
344 }
345 
346 static void clean_interface(struct interface *iface)
347 {
348         free(iface->dns_addrs4);
349         free(iface->dns_addrs6);
350         free(iface->dns_search);
351         free(iface->upstream);
352         free(iface->dhcpv4_routers);
353         free(iface->dhcpv6_raw);
354         free(iface->dhcpv4_ntp);
355         free(iface->dhcpv6_ntp);
356         free(iface->dhcpv6_sntp);
357         free(iface->captive_portal_uri);
358         for (unsigned i = 0; i < iface->dnr_cnt; i++) {
359                 free(iface->dnr[i].adn);
360                 free(iface->dnr[i].addr4);
361                 free(iface->dnr[i].addr6);
362                 free(iface->dnr[i].svc);
363         }
364         free(iface->dnr);
365         free(iface->pios);
366         memset(&iface->ra, 0, sizeof(*iface) - offsetof(struct interface, ra));
367         set_interface_defaults(iface);
368 }
369 
370 static void close_interface(struct interface *iface)
371 {
372         avl_delete(&interfaces, &iface->avl);
373 
374         router_setup_interface(iface, false);
375         dhcpv6_setup_interface(iface, false);
376         ndp_setup_interface(iface, false);
377         dhcpv4_setup_interface(iface, false);
378 
379         /* make sure timer is not on the timeouts list before freeing */
380         uloop_timeout_cancel(&iface->timer_rs);
381 
382         clean_interface(iface);
383         free(iface->oaddrs4);
384         free(iface->addr6);
385         free(iface->ifname);
386         free(iface);
387 }
388 
389 static int parse_mode(const char *mode)
390 {
391         if (!strcmp(mode, "disabled"))
392                 return MODE_DISABLED;
393         else if (!strcmp(mode, "server"))
394                 return MODE_SERVER;
395         else if (!strcmp(mode, "relay"))
396                 return MODE_RELAY;
397         else if (!strcmp(mode, "hybrid"))
398                 return MODE_HYBRID;
399         else
400                 return -1;
401 }
402 
403 static int parse_ra_flags(uint8_t *flags, struct blob_attr *attr)
404 {
405         struct blob_attr *cur;
406         unsigned rem;
407 
408         blobmsg_for_each_attr(cur, attr, rem) {
409                 int i;
410 
411                 if (blobmsg_type(cur) != BLOBMSG_TYPE_STRING)
412                         continue;
413 
414                                 if (!blobmsg_check_attr(cur, false))
415                                                 continue;
416 
417                 for (i = 0; ra_flags[i].name; i++) {
418                         if (!strcmp(ra_flags[i].name, blobmsg_get_string(cur))) {
419                                 *flags |= ra_flags[i].flag;
420                                 break;
421                         }
422                 }
423 
424                 if (!ra_flags[i].name)
425                         return -1;
426         }
427 
428         return 0;
429 }
430 
431 static void set_global_config(struct uci_section *s)
432 {
433         struct blob_attr *tb[GLOBAL_ATTR_MAX], *c;
434 
435         blob_buf_init(&b, 0);
436         uci_to_blob(&b, s, &global_attr_list);
437         blobmsg_parse(global_attrs, GLOBAL_ATTR_MAX, tb, blob_data(b.head), blob_len(b.head));
438 
439         if ((c = tb[GLOBAL_ATTR_DUID])) {
440                 size_t len = blobmsg_data_len(c) / 2;
441 
442                 config.default_duid_len = 0;
443                 if (len >= DUID_MIN_LEN && len <= DUID_MAX_LEN) {
444                         ssize_t r = odhcpd_unhexlify(config.default_duid, len, blobmsg_get_string(c));
445                         if (r >= DUID_MIN_LEN)
446                                 config.default_duid_len = r;
447                 }
448         }
449 }
450 
451 static void set_config(struct uci_section *s)
452 {
453         struct blob_attr *tb[ODHCPD_ATTR_MAX], *c;
454 
455         blob_buf_init(&b, 0);
456         uci_to_blob(&b, s, &odhcpd_attr_list);
457         blobmsg_parse(odhcpd_attrs, ODHCPD_ATTR_MAX, tb, blob_data(b.head), blob_len(b.head));
458 
459         if ((c = tb[ODHCPD_ATTR_MAINDHCP]))
460                 config.main_dhcpv4 = blobmsg_get_bool(c);
461 
462         if ((c = tb[ODHCPD_ATTR_LEASEFILE])) {
463                 free(config.dhcp_statefile);
464                 config.dhcp_statefile = strdup(blobmsg_get_string(c));
465         }
466 
467         if ((c = tb[ODHCPD_ATTR_HOSTSDIR])) {
468                 free(config.dhcp_hostsdir);
469                 config.dhcp_hostsdir = strdup(blobmsg_get_string(c));
470         }
471 
472         if ((c = tb[ODHCPD_ATTR_PIOFOLDER])) {
473                 free(config.ra_piofolder);
474                 config.ra_piofolder = strdup(blobmsg_get_string(c));
475         }
476 
477         if ((c = tb[ODHCPD_ATTR_LEASETRIGGER])) {
478                 free(config.dhcp_cb);
479                 config.dhcp_cb = strdup(blobmsg_get_string(c));
480         }
481 
482         if ((c = tb[ODHCPD_ATTR_LOGLEVEL])) {
483                 int log_level = (blobmsg_get_u32(c) & LOG_PRIMASK);
484 
485                 if (config.log_level != log_level && !config.log_level_cmdline) {
486                         config.log_level = log_level;
487                         if (config.log_syslog)
488                                 setlogmask(LOG_UPTO(config.log_level));
489                         notice("Log level set to %d\n", config.log_level);
490                 }
491         }
492 
493         if ((c = tb[ODHCPD_ATTR_ENABLE_TZ]))
494                 config.enable_tz = blobmsg_get_bool(c);
495 
496 }
497 
498 static void sanitize_tz_string(const char *src, uint8_t **dst, size_t *dst_len)
499 {
500         /* replace any spaces with '_' in tz strings. luci, where these strings
501         are normally set, (had a bug that) replaced underscores for spaces in the
502         names. */
503 
504         if (!dst || !dst_len)
505                 return;
506 
507         free(*dst);
508         *dst = NULL;
509         *dst_len = 0;
510 
511         if (!src || !*src)
512                 return;
513 
514         char *copy = strdup(src);
515         if (!copy)
516                 return;
517 
518         for (char *p = copy; *p; p++) {
519                 if (isspace((unsigned char)*p))
520                         *p = '_';
521         }
522 
523         *dst = (uint8_t *)copy;
524         *dst_len = strlen(copy);
525 }
526 
527 static void set_timezone_info_from_uci(struct uci_section *s)
528 {
529         struct blob_attr *tb[SYSTEM_ATTR_MAX], *c;
530 
531         blob_buf_init(&b, 0);
532         uci_to_blob(&b, s, &system_attr_list);
533         blobmsg_parse(system_attrs, SYSTEM_ATTR_MAX, tb, blob_data(b.head), blob_len(b.head));
534 
535         if ((c = tb[SYSTEM_ATTR_TIMEZONE]))
536                 sanitize_tz_string(blobmsg_get_string(c), &sys_conf.posix_tz, &sys_conf.posix_tz_len);
537 
538         if ((c = tb[SYSTEM_ATTR_ZONENAME]))
539                 sanitize_tz_string(blobmsg_get_string(c), &sys_conf.tzdb_tz, &sys_conf.tzdb_tz_len);
540 }
541 
542 static uint32_t parse_leasetime(struct blob_attr *c) {
543         char *val = blobmsg_get_string(c), *endptr = NULL;
544         uint32_t time = strcmp(val, "infinite") ? (uint32_t)strtod(val, &endptr) : UINT32_MAX;
545 
546         if (time && endptr && endptr[0]) {
547                 switch(endptr[0]) {
548                         case 's': break; /* seconds */
549                         case 'm': time *= 60; break; /* minutes */
550                         case 'h': time *= 3600; break; /* hours */
551                         case 'd': time *= 24 * 3600; break; /* days */
552                         case 'w': time *= 7 * 24 * 3600; break; /* weeks */
553                         default: goto err;
554                 }
555         }
556 
557         if (time < 60)
558                 time = 60;
559 
560         return time;
561 
562 err:
563         return 0;
564 }
565 
566 static void free_lease_cfg(struct lease_cfg *lease_cfg)
567 {
568         if (!lease_cfg)
569                 return;
570 
571         free(lease_cfg->hostname);
572         free(lease_cfg);
573 }
574 
575 static bool parse_duid(struct duid *duid, struct blob_attr *c)
576 {
577         const char *duid_str = blobmsg_get_string(c);
578         size_t duid_str_len = blobmsg_data_len(c) - 1;
579         ssize_t duid_len;
580         const char *iaid_str;
581 
582         /* We support a hex string with either "<DUID>", or "<DUID>%<IAID>" */
583         iaid_str = strrchr(duid_str, '%');
584         if (iaid_str) {
585                 size_t iaid_str_len = strlen(++iaid_str);
586                 char *end;
587 
588                 /* IAID = uint32, RFC8415, §21.4, §21.5, §21.21 */
589                 if (iaid_str_len < 1 || iaid_str_len > 2 * sizeof(uint32_t)) {
590                         error("Invalid IAID length '%s'", iaid_str);
591                         return false;
592                 }
593 
594                 errno = 0;
595                 duid->iaid = strtoul(iaid_str, &end, 16);
596                 if (errno || *end != '\0') {
597                         error("Invalid IAID '%s'", iaid_str);
598                         return false;
599                 }
600 
601                 duid->iaid_set = true;
602                 duid_str_len -= (iaid_str_len + 1);
603         }
604 
605         if (duid_str_len < 2 || duid_str_len > DUID_MAX_LEN * 2 || duid_str_len % 2) {
606                 error("Invalid DUID length '%.*s'", (int)duid_str_len, duid_str);
607                 return false;
608         }
609 
610         duid_len = odhcpd_unhexlify(duid->id, duid_str_len / 2, duid_str);
611         if (duid_len < 0) {
612                 error("Invalid DUID '%.*s'", (int)duid_str_len, duid_str);
613                 return false;
614         }
615 
616         duid->len = duid_len;
617         return true;
618 }
619 
620 int config_set_lease_cfg_from_blobmsg(struct blob_attr *ba)
621 {
622         struct blob_attr *tb[LEASE_CFG_ATTR_MAX], *c;
623         struct lease_cfg *lease_cfg = NULL;
624         int mac_count = 0;
625         struct ether_addr *macs;
626         int duid_count = 0;
627         struct duid *duids;
628 
629         blobmsg_parse(lease_cfg_attrs, LEASE_CFG_ATTR_MAX, tb, blob_data(ba), blob_len(ba));
630 
631         if ((c = tb[LEASE_CFG_ATTR_MAC])) {
632                 mac_count = blobmsg_check_array_len(c, BLOBMSG_TYPE_STRING, blob_raw_len(c));
633                 if (mac_count < 0)
634                         goto err;
635         }
636 
637         if ((c = tb[LEASE_CFG_ATTR_DUID])) {
638                 duid_count = blobmsg_check_array_len(c, BLOBMSG_TYPE_STRING, blob_raw_len(c));
639                 if (duid_count < 0)
640                         goto err;
641         }
642 
643         lease_cfg = calloc_a(sizeof(*lease_cfg),
644                              &macs, mac_count * sizeof(*macs),
645                              &duids, duid_count * sizeof(*duids));
646         if (!lease_cfg)
647                 goto err;
648 
649         if ((c = tb[LEASE_CFG_ATTR_MAC])) {
650                 struct blob_attr *cur;
651                 size_t rem;
652                 int i = 0;
653 
654                 lease_cfg->mac_count = mac_count;
655                 lease_cfg->macs = macs;
656 
657                 blobmsg_for_each_attr(cur, c, rem)
658                         if (!ether_aton_r(blobmsg_get_string(cur), &lease_cfg->macs[i++]))
659                                 goto err;
660         }
661 
662         if ((c = tb[LEASE_CFG_ATTR_DUID])) {
663                 struct blob_attr *cur;
664                 size_t rem;
665                 unsigned i = 0;
666 
667                 lease_cfg->duid_count = duid_count;
668                 lease_cfg->duids = duids;
669 
670                 blobmsg_for_each_attr(cur, c, rem)
671                         if (!parse_duid(&duids[i++], cur))
672                                 goto err;
673         }
674 
675         if ((c = tb[LEASE_CFG_ATTR_NAME])) {
676                 lease_cfg->hostname = strdup(blobmsg_get_string(c));
677                 if (!lease_cfg->hostname || !odhcpd_valid_hostname(lease_cfg->hostname))
678                         goto err;
679         }
680 
681         if ((c = tb[LEASE_CFG_ATTR_IPV4])) {
682                 const char *ip = blobmsg_get_string(c);
683 
684                 if (!strcmp(ip, "ignore"))
685                         lease_cfg->ignore4 = true;
686                 else if (inet_pton(AF_INET, blobmsg_get_string(c), &lease_cfg->ipv4) != 1)
687                         goto err;
688         }
689 
690         if ((c = tb[LEASE_CFG_ATTR_HOSTID])) {
691                 const char *iid = blobmsg_get_string(c);
692 
693                 if (!strcmp(iid, "ignore")) {
694                         lease_cfg->ignore6 = true;
695                 } else {
696                         errno = 0;
697                         lease_cfg->hostid = strtoull(blobmsg_get_string(c), NULL, 16);
698                         if (errno)
699                                 goto err;
700                 }
701         } else {
702                 uint32_t i4a = ntohl(lease_cfg->ipv4.s_addr) & 0xff;
703                 lease_cfg->hostid = ((i4a / 100) << 8) | (((i4a % 100) / 10) << 4) | (i4a % 10);
704         }
705 
706         if ((c = tb[LEASE_CFG_ATTR_LEASETIME])) {
707                 uint32_t time = parse_leasetime(c);
708                 if (time == 0)
709                         goto err;
710 
711                 lease_cfg->leasetime = time;
712         }
713 
714         INIT_LIST_HEAD(&lease_cfg->dhcpv6_leases);
715         vlist_add(&lease_cfgs, &lease_cfg->node, lease_cfg);
716         return 0;
717 
718 err:
719         free_lease_cfg(lease_cfg);
720         return -1;
721 }
722 
723 static int set_lease_cfg_from_uci(struct uci_section *s)
724 {
725         blob_buf_init(&b, 0);
726         uci_to_blob(&b, s, &lease_cfg_attr_list);
727 
728         return config_set_lease_cfg_from_blobmsg(b.head);
729 }
730 
731 /* Parse NTP Options for DHCPv6 Address */
732 static int parse_ntp_options(uint16_t *dhcpv6_ntp_len, struct in6_addr addr6, uint8_t **dhcpv6_ntp)
733 {
734         uint16_t sub_opt = 0, sub_len = htons(IPV6_ADDR_LEN);
735         uint16_t ntp_len = IPV6_ADDR_LEN + 4;
736         uint8_t *ntp;
737         size_t pos = *dhcpv6_ntp_len;
738 
739         ntp = realloc(*dhcpv6_ntp, pos + ntp_len);
740         if (!ntp)
741                 return -1;
742 
743         *dhcpv6_ntp = ntp;
744 
745         if (IN6_IS_ADDR_MULTICAST(&addr6))
746                 sub_opt = htons(NTP_SUBOPTION_MC_ADDR);
747         else
748                 sub_opt = htons(NTP_SUBOPTION_SRV_ADDR);
749 
750         memcpy(ntp + pos, &sub_opt, sizeof(sub_opt));
751         pos += sizeof(sub_opt);
752         memcpy(ntp + pos, &sub_len, sizeof(sub_len));
753         pos += sizeof(sub_len);
754         memcpy(ntp + pos, &addr6, IPV6_ADDR_LEN);
755 
756         *dhcpv6_ntp_len += ntp_len;
757 
758         return 0;
759 }
760 
761 /* Parse NTP Options for FQDN */
762 static int parse_ntp_fqdn(uint16_t *dhcpv6_ntp_len, char *fqdn, uint8_t **dhcpv6_ntp)
763 {
764         size_t fqdn_len = strlen(fqdn);
765         uint16_t sub_opt = 0, sub_len = 0, ntp_len = 0;
766         uint8_t *ntp;
767         size_t pos = *dhcpv6_ntp_len;
768         uint8_t buf[256] = {0};
769 
770         if (fqdn_len > 0 && fqdn[fqdn_len - 1] == '.')
771                 fqdn[fqdn_len - 1] = 0;
772 
773         int len = dn_comp(fqdn, buf, sizeof(buf), NULL, NULL);
774         if (len <= 0)
775                 return -1;
776 
777         ntp_len = len + 4;
778 
779         ntp = realloc(*dhcpv6_ntp, pos + ntp_len);
780         if (!ntp)
781                 return -1;
782 
783         *dhcpv6_ntp = ntp;
784 
785         sub_opt = htons(NTP_SUBOPTION_SRV_FQDN);
786         sub_len = htons(len);
787 
788         memcpy(ntp + pos, &sub_opt, sizeof(sub_opt));
789         pos += sizeof(sub_opt);
790         memcpy(ntp + pos, &sub_len, sizeof(sub_len));
791         pos += sizeof(sub_len);
792         memcpy(ntp + pos, buf, len);
793 
794         *dhcpv6_ntp_len += ntp_len;
795 
796         return 0;
797 }
798 
799 /* Parse DNR Options */
800 static int parse_dnr_str(char *str, struct interface *iface)
801 {
802         struct dnr_options dnr = {0};
803         size_t adn_len;
804         uint8_t adn_buf[256] = {0};
805         char *saveptr1, *saveptr2;
806 
807         char *priority;
808         priority = strtok_r(str, " \f\n\r\t\v", &saveptr1);
809         if (!priority) {
810                 goto err;
811         } else if (sscanf(priority, "%" SCNu16, &dnr.priority) != 1) {
812                 error("Unable to parse priority '%s'", priority);
813                 goto err;
814         } else if (dnr.priority == 0) {
815                 error("Invalid priority '%s'", priority);
816                 goto err;
817         }
818 
819         char *adn;
820         adn = strtok_r(NULL, " \f\n\r\t\v", &saveptr1);
821         if (!adn)
822                 goto err;
823 
824         adn_len = strlen(adn);
825         if (adn_len > 0 && adn[adn_len - 1] == '.')
826                 adn[adn_len - 1] = '\0';
827 
828         if (adn_len >= sizeof(adn_buf)) {
829                 error("Hostname '%s' too long", adn);
830                 goto err;
831         }
832 
833         adn_len = dn_comp(adn, adn_buf, sizeof(adn_buf), NULL, NULL);
834         if (adn_len <= 0) {
835                 error("Unable to parse hostname '%s'", adn);
836                 goto err;
837         }
838 
839         dnr.adn = malloc(adn_len);
840         if (!dnr.adn)
841                 goto err;
842         memcpy(dnr.adn, adn_buf, adn_len);
843         dnr.adn_len = adn_len;
844 
845         char *addrs;
846         addrs = strtok_r(NULL, " \f\n\r\t\v", &saveptr1);
847         if (!addrs)
848                 // ADN-Only mode
849                 goto done;
850 
851         for (char *addr = strtok_r(addrs, ",", &saveptr2); addr; addr = strtok_r(NULL, ",", &saveptr2)) {
852                 struct in6_addr addr6, *tmp6;
853                 struct in_addr addr4, *tmp4;
854                 size_t new_sz;
855 
856                 if (inet_pton(AF_INET6, addr, &addr6) == 1) {
857                         new_sz = (dnr.addr6_cnt + 1) * sizeof(*dnr.addr6);
858                         if (new_sz > UINT16_MAX)
859                                 continue;
860                         tmp6 = realloc(dnr.addr6, new_sz);
861                         if (!tmp6)
862                                 goto err;
863                         dnr.addr6 = tmp6;
864                         memcpy(&dnr.addr6[dnr.addr6_cnt], &addr6, sizeof(*dnr.addr6));
865                         dnr.addr6_cnt++;
866 
867                 } else if (inet_pton(AF_INET, addr, &addr4) == 1) {
868                         new_sz = (dnr.addr4_cnt + 1) * sizeof(*dnr.addr4);
869                         if (new_sz > UINT8_MAX)
870                                 continue;
871                         tmp4 = realloc(dnr.addr4, new_sz);
872                         if (!tmp4)
873                                 goto err;
874                         dnr.addr4 = tmp4;
875                         memcpy(&dnr.addr4[dnr.addr4_cnt], &addr4, sizeof(*dnr.addr4));
876                         dnr.addr4_cnt++;
877 
878                 } else {
879                         error("Unable to parse IP address '%s'", addr);
880                         goto err;
881                 }
882         }
883 
884         char *svc_vals[DNR_SVC_MAX] = { NULL, };
885         for (char *svc_tok = strtok_r(NULL, " \f\n\r\t\v", &saveptr1); svc_tok; svc_tok = strtok_r(NULL, " \f\n\r\t\v", &saveptr1)) {
886                 uint16_t svc_id;
887                 char *svc_key, *svc_val;
888 
889                 svc_key = strtok_r(svc_tok, "=", &saveptr2);
890                 svc_val = strtok_r(NULL, "=", &saveptr2);
891 
892                 if (!strcmp(svc_key, "_lifetime")) {
893                         uint32_t lifetime;
894 
895                         if (!svc_val || sscanf(svc_val, "%" SCNu32, &lifetime) != 1) {
896                                 error("Invalid value '%s' for _lifetime", svc_val ? svc_val : "");
897                                 goto err;
898                         }
899 
900                         dnr.lifetime = lifetime;
901                         dnr.lifetime_set = true;
902                         continue;
903                 }
904 
905                 for (svc_id = 0; svc_id < DNR_SVC_MAX; svc_id++)
906                         if (!strcmp(svc_key, svc_param_key_names[svc_id]))
907                                 break;
908 
909                 if (svc_id >= DNR_SVC_MAX) {
910                         error("Invalid SvcParam '%s'", svc_key);
911                         goto err;
912                 }
913 
914                 svc_vals[svc_id] = svc_val ? svc_val : "";
915         }
916 
917         /* SvcParamKeys must be in increasing order, RFC9460 §2.2 */
918         for (uint16_t svc_key = 0; svc_key < DNR_SVC_MAX; svc_key++) {
919                 uint16_t svc_key_be = ntohs(svc_key);
920                 uint16_t svc_val_len, svc_val_len_be;
921                 char *svc_val_str = svc_vals[svc_key];
922                 uint8_t *tmp;
923 
924                 if (!svc_val_str)
925                         continue;
926 
927                 switch (svc_key) {
928                 case DNR_SVC_MANDATORY:
929                         uint16_t mkeys[DNR_SVC_MAX];
930 
931                         svc_val_len = 0;
932                         for (char *mkey_str = strtok_r(svc_val_str, ",", &saveptr2); mkey_str; mkey_str = strtok_r(NULL, ",", &saveptr2)) {
933                                 uint16_t mkey;
934 
935                                 for (mkey = 0; mkey < DNR_SVC_MAX; mkey++)
936                                         if (!strcmp(mkey_str, svc_param_key_names[mkey]))
937                                                 break;
938 
939                                 if (mkey >= DNR_SVC_MAX || !svc_vals[mkey]) {
940                                         error("Invalid value '%s' for SvcParam 'mandatory'", mkey_str);
941                                         goto err;
942                                 }
943 
944                                 mkeys[svc_val_len++] = ntohs(mkey);
945                         }
946 
947                         svc_val_len *= sizeof(uint16_t);
948                         svc_val_len_be = ntohs(svc_val_len);
949 
950                         tmp = realloc(dnr.svc, dnr.svc_len + 4 + svc_val_len);
951                         if (!tmp)
952                                 goto err;
953 
954                         dnr.svc = tmp;
955                         memcpy(dnr.svc + dnr.svc_len, &svc_key_be, sizeof(svc_key_be));
956                         memcpy(dnr.svc + dnr.svc_len + 2, &svc_val_len_be, sizeof(svc_val_len_be));
957                         memcpy(dnr.svc + dnr.svc_len + 4, mkeys, svc_val_len);
958                         dnr.svc_len += 4 + svc_val_len;
959                         break;
960 
961                 case DNR_SVC_ALPN:
962                         size_t len_off;
963 
964                         tmp = realloc(dnr.svc, dnr.svc_len + 4);
965                         if (!tmp)
966                                 goto err;
967 
968                         dnr.svc = tmp;
969                         memcpy(dnr.svc + dnr.svc_len, &svc_key_be, sizeof(svc_key_be));
970                         /* the length is not known yet */
971                         len_off = dnr.svc_len + sizeof(svc_key_be);
972                         dnr.svc_len += 4;
973 
974                         svc_val_len = 0;
975                         for (char *alpn_id_str = strtok_r(svc_val_str, ",", &saveptr2); alpn_id_str; alpn_id_str = strtok_r(NULL, ",", &saveptr2)) {
976                                 size_t alpn_id_len;
977 
978                                 alpn_id_len = strlen(alpn_id_str);
979                                 if (alpn_id_len > UINT8_MAX) {
980                                         error("Invalid value '%s' for SvcParam 'alpn'", alpn_id_str);
981                                         goto err;
982                                 }
983 
984                                 tmp = realloc(dnr.svc, dnr.svc_len + 1 + alpn_id_len);
985                                 if (!tmp)
986                                         goto err;
987                                 dnr.svc = tmp;
988 
989                                 dnr.svc[dnr.svc_len] = alpn_id_len;
990                                 memcpy(dnr.svc + dnr.svc_len + 1, alpn_id_str, alpn_id_len);
991                                 dnr.svc_len += 1 + alpn_id_len;
992                                 svc_val_len += 1 + alpn_id_len;
993                         }
994 
995                         svc_val_len_be = ntohs(svc_val_len);
996                         memcpy(dnr.svc + len_off, &svc_val_len_be, sizeof(svc_val_len_be));
997                         break;
998 
999                 case DNR_SVC_PORT:
1000                         uint16_t port;
1001 
1002                         if (sscanf(svc_val_str, "%" SCNu16, &port) != 1) {
1003                                 error("Invalid value '%s' for SvcParam 'port'", svc_val_str);
1004                                 goto err;
1005                         }
1006 
1007                         port = ntohs(port);
1008                         svc_val_len_be = ntohs(2);
1009 
1010                         tmp = realloc(dnr.svc, dnr.svc_len + 6);
1011                         if (!tmp)
1012                                 goto err;
1013 
1014                         dnr.svc = tmp;
1015                         memcpy(dnr.svc + dnr.svc_len, &svc_key_be, sizeof(svc_key_be));
1016                         memcpy(dnr.svc + dnr.svc_len + 2, &svc_val_len_be, sizeof(svc_val_len_be));
1017                         memcpy(dnr.svc + dnr.svc_len + 4, &port, sizeof(port));
1018                         dnr.svc_len += 6;
1019                         break;
1020 
1021                 case DNR_SVC_NO_DEFAULT_ALPN:
1022                 case DNR_SVC_OHTTP:
1023                         if (strlen(svc_val_str) > 0) {
1024                                 error("Invalid value '%s' for SvcParam 'port'", svc_val_str);
1025                                 goto err;
1026                         }
1027                         _o_fallthrough;
1028 
1029                 case DNR_SVC_DOHPATH:
1030                         /* plain string */
1031                         svc_val_len = strlen(svc_val_str);
1032                         svc_val_len_be = ntohs(svc_val_len);
1033                         tmp = realloc(dnr.svc, dnr.svc_len + 4 + svc_val_len);
1034                         if (!tmp)
1035                                 goto err;
1036 
1037                         dnr.svc = tmp;
1038                         memcpy(dnr.svc + dnr.svc_len, &svc_key_be, sizeof(svc_key_be));
1039                         dnr.svc_len += sizeof(svc_key_be);
1040                         memcpy(dnr.svc + dnr.svc_len, &svc_val_len_be, sizeof(svc_val_len_be));
1041                         dnr.svc_len += sizeof(svc_val_len_be);
1042                         memcpy(dnr.svc + dnr.svc_len, svc_val_str, svc_val_len);
1043                         dnr.svc_len += svc_val_len;
1044                         break;
1045 
1046                 case DNR_SVC_ECH:
1047                         error("SvcParam 'ech' is not implemented");
1048                         goto err;
1049 
1050                 case DNR_SVC_IPV4HINT:
1051                 case DNR_SVC_IPV6HINT:
1052                         error("SvcParam '%s' is not allowed", svc_param_key_names[svc_key]);
1053                         goto err;
1054                 }
1055         }
1056 
1057 done:
1058         struct dnr_options *tmp;
1059         tmp = realloc(iface->dnr, (iface->dnr_cnt + 1) * sizeof(dnr));
1060         if (!tmp)
1061                 goto err;
1062 
1063         iface->dnr = tmp;
1064         memcpy(iface->dnr + iface->dnr_cnt, &dnr, sizeof(dnr));
1065         iface->dnr_cnt++;
1066         return 0;
1067 
1068 err:
1069         free(dnr.adn);
1070         free(dnr.addr4);
1071         free(dnr.addr6);
1072         free(dnr.svc);
1073         return -1;
1074 }
1075 
1076 static int avl_ipv4_cmp(const void *k1, const void *k2, _o_unused void *ptr)
1077 {
1078         return memcmp(k1, k2, sizeof(struct in_addr));
1079 }
1080 
1081 int config_parse_interface(void *data, size_t len, const char *name, bool overwrite)
1082 {
1083         struct interface *iface;
1084         struct blob_attr *tb[IFACE_ATTR_MAX], *c;
1085         struct odhcpd_ipaddr *oaddrs = NULL;
1086         ssize_t oaddrs_cnt;
1087         bool get_addrs = false;
1088         int mode;
1089         const char *ifname = NULL;
1090 
1091         blobmsg_parse(iface_attrs, IFACE_ATTR_MAX, tb, data, len);
1092 
1093         if (tb[IFACE_ATTR_INTERFACE])
1094                 name = blobmsg_get_string(tb[IFACE_ATTR_INTERFACE]);
1095 
1096         if (!name)
1097                 return -1;
1098 
1099         iface = avl_find_element(&interfaces, name, iface, avl);
1100         if (!iface) {
1101                 char *new_name;
1102 
1103                 iface = calloc_a(sizeof(*iface), &new_name, strlen(name) + 1);
1104                 if (!iface)
1105                         return -1;
1106 
1107                 iface->name = strcpy(new_name, name);
1108                 iface->avl.key = iface->name;
1109                 iface->router_event.uloop.fd = -1;
1110                 iface->dhcpv6_event.uloop.fd = -1;
1111                 iface->ndp_event.uloop.fd = -1;
1112                 iface->ndp_ping_fd = -1;
1113                 iface->dhcpv4_event.uloop.fd = -1;
1114                 INIT_LIST_HEAD(&iface->ia_assignments);
1115                 avl_init(&iface->dhcpv4_leases, avl_ipv4_cmp, false, iface);
1116                 INIT_LIST_HEAD(&iface->dhcpv4_fr_ips);
1117 
1118                 set_interface_defaults(iface);
1119 
1120                 avl_insert(&interfaces, &iface->avl);
1121                 get_addrs = overwrite = true;
1122         }
1123 
1124         if (overwrite) {
1125                 if ((c = tb[IFACE_ATTR_IFNAME]))
1126                         ifname = blobmsg_get_string(c);
1127                 else if ((c = tb[IFACE_ATTR_NETWORKID]))
1128                         ifname = blobmsg_get_string(c);
1129         }
1130 
1131         if (overwrite || !iface->ifname)
1132                 if (config.use_ubus)
1133                         ifname = ubus_get_ifname(name);
1134 
1135         if (!iface->ifname && !ifname)
1136                 goto err;
1137 
1138         if (ifname) {
1139                 free(iface->ifname);
1140                 iface->ifname = strdup(ifname);
1141 
1142                 if (!iface->ifname)
1143                         goto err;
1144 
1145                 if (!iface->ifindex &&
1146                         (iface->ifindex = if_nametoindex(iface->ifname)) <= 0)
1147                         goto err;
1148 
1149                 if ((iface->ifflags = odhcpd_get_flags(iface)) < 0)
1150                         goto err;
1151         }
1152 
1153         if (get_addrs) {
1154                 oaddrs_cnt = netlink_get_interface_addrs(iface->ifindex,
1155                                                          true, &iface->addr6);
1156 
1157                 if (oaddrs_cnt > 0)
1158                         iface->addr6_len = oaddrs_cnt;
1159 
1160                 oaddrs_cnt = netlink_get_interface_addrs(iface->ifindex,
1161                                                          false, &iface->oaddrs4);
1162                 if (oaddrs_cnt > 0)
1163                         iface->oaddrs4_cnt = oaddrs_cnt;
1164         }
1165 
1166         oaddrs_cnt = netlink_get_interface_linklocal(iface->ifindex, &oaddrs);
1167         if (oaddrs_cnt > 0) {
1168                 for (ssize_t i = 0; i < oaddrs_cnt; i++) {
1169                         if (!oaddrs[i].tentative) {
1170                                 iface->have_link_local = true;
1171                                 break;
1172                         }
1173                 }
1174                 free(oaddrs);
1175         }
1176 
1177         iface->inuse = true;
1178 
1179         if ((c = tb[IFACE_ATTR_DYNAMICDHCP]))
1180                 iface->no_dynamic_dhcp = !blobmsg_get_bool(c);
1181 
1182         if ((c = tb[IFACE_ATTR_LEASETIME])) {
1183                 uint32_t time = parse_leasetime(c);
1184 
1185                 if (time > 0)
1186                         iface->dhcp_leasetime = time;
1187                 else
1188                         error("Invalid %s value configured for interface '%s'",
1189                               iface_attrs[IFACE_ATTR_LEASETIME].name, iface->name);
1190         }
1191 
1192         if ((c = tb[IFACE_ATTR_MAX_PREFERRED_LIFETIME])) {
1193                 uint32_t time = parse_leasetime(c);
1194 
1195                 if (time > 0)
1196                         iface->max_preferred_lifetime = time;
1197                 else
1198                         error("Invalid %s value configured for interface '%s'",
1199                               iface_attrs[IFACE_ATTR_MAX_PREFERRED_LIFETIME].name, iface->name);
1200         }
1201 
1202         if ((c = tb[IFACE_ATTR_MAX_VALID_LIFETIME])) {
1203                 uint32_t time = parse_leasetime(c);
1204 
1205                 if (time > 0)
1206                         iface->max_valid_lifetime = time;
1207                 else
1208                         error("Invalid %s value configured for interface '%s'",
1209                               iface_attrs[IFACE_ATTR_MAX_VALID_LIFETIME].name, iface->name);
1210         }
1211 
1212         if ((c = tb[IFACE_ATTR_DHCPV4_POOL_START])) {
1213                 iface->dhcpv4_pool_start = blobmsg_get_u32(c);
1214                 iface->dhcpv4_pool_end = iface->dhcpv4_pool_start + DHCPV4_POOL_LIMIT_DEFAULT - 1;
1215         }
1216 
1217         if ((c = tb[IFACE_ATTR_DHCPV4_POOL_LIMIT]))
1218                 iface->dhcpv4_pool_end = iface->dhcpv4_pool_start + blobmsg_get_u32(c) - 1;
1219 
1220         if (iface->dhcpv4_pool_start > UINT16_MAX ||
1221             iface->dhcpv4_pool_end > UINT16_MAX ||
1222             iface->dhcpv4_pool_start > iface->dhcpv4_pool_end) {
1223                 warn("Invalid DHCPv4 pool range for %s, disabling dynamic leases", iface->name);
1224                 iface->no_dynamic_dhcp = true;
1225         }
1226 
1227         if ((c = tb[IFACE_ATTR_MASTER]))
1228                 iface->master = blobmsg_get_bool(c);
1229 
1230         if (overwrite && (c = tb[IFACE_ATTR_UPSTREAM])) {
1231                 struct blob_attr *cur;
1232                 unsigned rem;
1233                 char *tmp;
1234 
1235                 blobmsg_for_each_attr(cur, c, rem) {
1236                         if (blobmsg_type(cur) != BLOBMSG_TYPE_STRING || !blobmsg_check_attr(cur, false))
1237                                 continue;
1238 
1239                         tmp = realloc(iface->upstream, iface->upstream_len + blobmsg_data_len(cur));
1240                         if (!tmp)
1241                                 goto err;
1242 
1243                         iface->upstream = tmp;
1244                         memcpy(iface->upstream + iface->upstream_len, blobmsg_get_string(cur), blobmsg_data_len(cur));
1245                         iface->upstream_len += blobmsg_data_len(cur);
1246                 }
1247         }
1248 
1249         if ((c = tb[IFACE_ATTR_RA])) {
1250                 if ((mode = parse_mode(blobmsg_get_string(c))) >= 0) {
1251                         iface->ra = mode;
1252 
1253                         if (iface->ra != MODE_DISABLED)
1254                                 iface->ignore = false;
1255                 } else
1256                         error("Invalid %s mode configured for interface '%s'",
1257                               iface_attrs[IFACE_ATTR_RA].name, iface->name);
1258         }
1259 
1260         if ((c = tb[IFACE_ATTR_DHCPV4])) {
1261                 if ((mode = parse_mode(blobmsg_get_string(c))) >= 0) {
1262                         iface->dhcpv4 = config.main_dhcpv4 ? mode : MODE_DISABLED;
1263 
1264                         if (iface->dhcpv4 != MODE_DISABLED)
1265                                 iface->ignore = false;
1266                 } else
1267                         error("Invalid %s mode configured for interface %s",
1268                               iface_attrs[IFACE_ATTR_DHCPV4].name, iface->name);
1269         }
1270 
1271         if ((c = tb[IFACE_ATTR_DHCPV6])) {
1272                 if ((mode = parse_mode(blobmsg_get_string(c))) >= 0) {
1273                         iface->dhcpv6 = mode;
1274 
1275                         if (iface->dhcpv6 != MODE_DISABLED)
1276                                 iface->ignore = false;
1277                 } else
1278                         error("Invalid %s mode configured for interface '%s'",
1279                               iface_attrs[IFACE_ATTR_DHCPV6].name, iface->name);
1280         }
1281 
1282         if ((c = tb[IFACE_ATTR_NDP])) {
1283                 if ((mode = parse_mode(blobmsg_get_string(c))) >= 0) {
1284                         iface->ndp = mode;
1285 
1286                         if (iface->ndp != MODE_DISABLED)
1287                                 iface->ignore = false;
1288                 } else
1289                         error("Invalid %s mode configured for interface '%s'",
1290                               iface_attrs[IFACE_ATTR_NDP].name, iface->name);
1291         }
1292 
1293         if ((c = tb[IFACE_ATTR_ROUTER])) {
1294                 struct blob_attr *cur;
1295                 unsigned rem;
1296 
1297                 blobmsg_for_each_attr(cur, c, rem) {
1298                         struct in_addr addr4, *tmp;
1299 
1300                         if (blobmsg_type(cur) != BLOBMSG_TYPE_STRING || !blobmsg_check_attr(cur, false))
1301                                 continue;
1302 
1303                         if (inet_pton(AF_INET, blobmsg_get_string(cur), &addr4) == 1) {
1304                                 tmp = realloc(iface->dhcpv4_routers,
1305                                               (iface->dhcpv4_routers_cnt + 1) * sizeof(*iface->dhcpv4_routers));
1306                                 if (!tmp)
1307                                         goto err;
1308 
1309                                 iface->dhcpv4_routers = tmp;
1310                                 iface->dhcpv4_routers[iface->dhcpv4_routers_cnt++] = addr4;
1311                         } else {
1312                                 error("Invalid %s value configured for interface '%s'",
1313                                       iface_attrs[IFACE_ATTR_ROUTER].name, iface->name);
1314                         }
1315                 }
1316         }
1317 
1318         if ((c = tb[IFACE_ATTR_CAPTIVE_PORTAL_URI])) {
1319                 iface->captive_portal_uri = strdup(blobmsg_get_string(c));
1320                 iface->captive_portal_uri_len = strlen(iface->captive_portal_uri);
1321                 if (iface->captive_portal_uri_len > UINT8_MAX) {
1322                         warn("RFC8910 captive portal URI > %d characters for interface '%s': option via DHCPv4 not possible",
1323                                 UINT8_MAX,
1324                                 iface->name);
1325                 }
1326                 debug("Set RFC8910 captive portal URI: '%s' for interface '%s'",
1327                         iface->captive_portal_uri, iface->name);
1328         }
1329 
1330         if ((c = tb[IFACE_ATTR_DNS])) {
1331                 struct blob_attr *cur;
1332                 unsigned rem;
1333 
1334                 iface->always_rewrite_dns = true;
1335                 blobmsg_for_each_attr(cur, c, rem) {
1336                         struct in_addr addr4, *tmp4;
1337                         struct in6_addr addr6, *tmp6;
1338 
1339                         if (blobmsg_type(cur) != BLOBMSG_TYPE_STRING || !blobmsg_check_attr(cur, false))
1340                                 continue;
1341 
1342                         if (inet_pton(AF_INET, blobmsg_get_string(cur), &addr4) == 1) {
1343                                 if (addr4.s_addr == INADDR_ANY) {
1344                                         error("Invalid %s value configured for interface '%s'",
1345                                               iface_attrs[IFACE_ATTR_DNS].name, iface->name);
1346                                         continue;
1347                                 }
1348 
1349                                 tmp4 = realloc(iface->dns_addrs4, (iface->dns_addrs4_cnt + 1) *
1350                                                sizeof(*iface->dns_addrs4));
1351                                 if (!tmp4)
1352                                         goto err;
1353 
1354                                 iface->dns_addrs4 = tmp4;
1355                                 iface->dns_addrs4[iface->dns_addrs4_cnt++] = addr4;
1356 
1357                         } else if (inet_pton(AF_INET6, blobmsg_get_string(cur), &addr6) == 1) {
1358                                 if (IN6_IS_ADDR_UNSPECIFIED(&addr6)) {
1359                                         error("Invalid %s value configured for interface '%s'",
1360                                               iface_attrs[IFACE_ATTR_DNS].name, iface->name);
1361                                         continue;
1362                                 }
1363 
1364                                 tmp6 = realloc(iface->dns_addrs6, (iface->dns_addrs6_cnt + 1) *
1365                                                sizeof(*iface->dns_addrs6));
1366                                 if (!tmp6)
1367                                         goto err;
1368 
1369                                 iface->dns_addrs6 = tmp6;
1370                                 iface->dns_addrs6[iface->dns_addrs6_cnt++] = addr6;
1371 
1372                         } else {
1373                                 error("Invalid %s value configured for interface '%s'",
1374                                       iface_attrs[IFACE_ATTR_DNS].name, iface->name);
1375                         }
1376                 }
1377         }
1378 
1379         if ((c = tb[IFACE_ATTR_DNS_SERVICE]))
1380                 iface->dns_service = blobmsg_get_bool(c);
1381 
1382         if ((c = tb[IFACE_ATTR_DNS_DOMAIN_SEARCH])) {
1383                 struct blob_attr *cur;
1384                 unsigned rem;
1385 
1386                 blobmsg_for_each_attr(cur, c, rem) {
1387                         uint8_t buf[DNS_MAX_NAME_LEN];
1388                         char *domain;
1389                         size_t domainlen;
1390                         int ds_len;
1391                         uint8_t *tmp;
1392 
1393                         if (blobmsg_type(cur) != BLOBMSG_TYPE_STRING || !blobmsg_check_attr(cur, false))
1394                                 continue;
1395 
1396                         domain = blobmsg_get_string(cur);
1397                         domainlen = strlen(domain);
1398 
1399                         if (domainlen > 0 && domain[domainlen - 1] == '.')
1400                                 domain[domainlen - 1] = 0;
1401 
1402                         ds_len = dn_comp(domain, buf, sizeof(buf), NULL, NULL);
1403                         if (ds_len <= 0) {
1404                                 error("Invalid %s value configured for interface '%s'",
1405                                       iface_attrs[IFACE_ATTR_DNS_DOMAIN_SEARCH].name, iface->name);
1406                                 continue;
1407                         }
1408 
1409                         tmp = realloc(iface->dns_search, iface->dns_search_len + ds_len);
1410                         if (!tmp)
1411                                 goto err;
1412 
1413                         iface->dns_search = tmp;
1414                         memcpy(&iface->dns_search[iface->dns_search_len], buf, ds_len);
1415                         iface->dns_search_len += ds_len;
1416                 }
1417         }
1418 
1419         if ((c = tb[IFACE_ATTR_DHCPV4_FORCERECONF]))
1420                 iface->dhcpv4_forcereconf = blobmsg_get_bool(c);
1421 
1422         if ((c = tb[IFACE_ATTR_DHCPV6_RAW])) {
1423                 void *tmp;
1424                 size_t opt_len = blobmsg_data_len(c) / 2;
1425 
1426                 tmp = realloc(iface->dhcpv6_raw, opt_len);
1427                 if (!tmp)
1428                         goto err;
1429 
1430                 iface->dhcpv6_raw = tmp;
1431                 iface->dhcpv6_raw_len = opt_len;
1432                 odhcpd_unhexlify(iface->dhcpv6_raw, iface->dhcpv6_raw_len, blobmsg_get_string(c));
1433         }
1434 
1435         if ((c = tb[IFACE_ATTR_DHCPV6_ASSIGNALL]))
1436                 iface->dhcpv6_assignall = blobmsg_get_bool(c);
1437 
1438         if ((c = tb[IFACE_ATTR_DHCPV6_PD_PREFERRED]))
1439                 iface->dhcpv6_pd_preferred = blobmsg_get_bool(c);
1440 
1441         if ((c = tb[IFACE_ATTR_DHCPV6_PD]))
1442                 iface->dhcpv6_pd = blobmsg_get_bool(c);
1443 
1444         if ((c = tb[IFACE_ATTR_DHCPV6_PD_MIN_LEN])) {
1445                 uint32_t pd_min_len = blobmsg_get_u32(c);
1446                 if (pd_min_len > PD_MIN_LEN_MAX)
1447                         iface->dhcpv6_pd_min_len = PD_MIN_LEN_MAX;
1448                 iface->dhcpv6_pd_min_len = pd_min_len;
1449                 if (pd_min_len > PD_MIN_LEN_MAX)
1450                         warn("Clamped invalid %s value configured for interface '%s' to %d",
1451                              iface_attrs[IFACE_ATTR_DHCPV6_PD_MIN_LEN].name, iface->name, iface->dhcpv6_pd_min_len);
1452         }
1453 
1454         if ((c = tb[IFACE_ATTR_DHCPV6_NA]))
1455                 iface->dhcpv6_na = blobmsg_get_bool(c);
1456 
1457         if ((c = tb[IFACE_ATTR_DHCPV6_HOSTID_LEN])) {
1458                 uint32_t original_hostid_len, hostid_len;
1459                 original_hostid_len = hostid_len = blobmsg_get_u32(c);
1460 
1461                 if (hostid_len < HOSTID_LEN_MIN)
1462                         hostid_len = HOSTID_LEN_MIN;
1463                 else if (hostid_len > HOSTID_LEN_MAX)
1464                         hostid_len = HOSTID_LEN_MAX;
1465 
1466                 iface->dhcpv6_hostid_len = hostid_len;
1467 
1468                 if (original_hostid_len != hostid_len) {
1469                         warn("Clamped invalid %s value configured for interface '%s' to %d",
1470                              iface_attrs[IFACE_ATTR_DHCPV6_HOSTID_LEN].name, iface->name, iface->dhcpv6_hostid_len);
1471                 }
1472         }
1473 
1474         if ((c = tb[IFACE_ATTR_RA_DEFAULT]))
1475                 iface->default_router = blobmsg_get_u32(c);
1476 
1477         if ((c = tb[IFACE_ATTR_RA_FLAGS])) {
1478                 iface->ra_flags = 0;
1479 
1480                 if (parse_ra_flags(&iface->ra_flags, c) < 0)
1481                         error("Invalid %s value configured for interface '%s'",
1482                               iface_attrs[IFACE_ATTR_RA_FLAGS].name, iface->name);
1483         }
1484 
1485         if ((c = tb[IFACE_ATTR_RA_REACHABLETIME])) {
1486                 uint32_t ra_reachabletime = blobmsg_get_u32(c);
1487 
1488                 /* RFC4861 §6.2.1 : AdvReachableTime :
1489                  * MUST be no greater than 3,600,000 msec
1490                  */
1491                 iface->ra_reachabletime = ra_reachabletime <= AdvReachableTime ? ra_reachabletime : AdvReachableTime;
1492                 if(ra_reachabletime > AdvReachableTime)
1493                         warn("Clamped invalid %s value configured for interface '%s' to %d",
1494                              iface_attrs[IFACE_ATTR_RA_REACHABLETIME].name, iface->name, iface->ra_reachabletime);
1495         }
1496 
1497         if ((c = tb[IFACE_ATTR_RA_RETRANSTIME])) {
1498                 uint32_t ra_retranstime = blobmsg_get_u32(c);
1499 
1500                 iface->ra_retranstime = ra_retranstime <= RETRANS_TIMER_MAX ? ra_retranstime : RETRANS_TIMER_MAX;
1501                 if (ra_retranstime > RETRANS_TIMER_MAX)
1502                         warn("Clamped invalid %s value configured for interface '%s' to %d",
1503                              iface_attrs[IFACE_ATTR_RA_RETRANSTIME].name, iface->name, iface->ra_retranstime);
1504         }
1505 
1506         if ((c = tb[IFACE_ATTR_RA_HOPLIMIT])) {
1507                 uint32_t ra_hoplimit = blobmsg_get_u32(c);
1508 
1509                 /* RFC4861 §6.2.1 : AdvCurHopLimit */
1510                 iface->ra_hoplimit = ra_hoplimit <= AdvCurHopLimit ? ra_hoplimit : AdvCurHopLimit;
1511                 if(ra_hoplimit > AdvCurHopLimit)
1512                         warn("Clamped invalid %s value configured for interface '%s' to %d",
1513                              iface_attrs[IFACE_ATTR_RA_HOPLIMIT].name, iface->name, iface->ra_hoplimit);
1514         }
1515 
1516         iface->if_mtu = odhcpd_get_interface_config(iface->ifname, "mtu");
1517         if ((c = tb[IFACE_ATTR_RA_MTU])) {
1518                 uint32_t original_ra_mtu, ra_mtu;
1519                 original_ra_mtu = ra_mtu = blobmsg_get_u32(c);
1520                 if (ra_mtu < RA_MTU_MIN)
1521                         ra_mtu = RA_MTU_MIN;
1522                 else if (ra_mtu > RA_MTU_MAX)
1523                         ra_mtu = RA_MTU_MAX;
1524                 if (iface->if_mtu && ra_mtu > iface->if_mtu)
1525                         ra_mtu = iface->if_mtu;
1526 
1527                 iface->ra_mtu = ra_mtu;
1528 
1529                 if (original_ra_mtu != ra_mtu) {
1530                         warn("Clamped invalid %s value configured for interface '%s' to %d",
1531                              iface_attrs[IFACE_ATTR_RA_MTU].name, iface->name, iface->ra_mtu);
1532                 }
1533         }
1534 
1535         /* Default RA MTU to the interface MTU if no value is assigned */
1536         if (!iface->ra_mtu && iface->if_mtu) {
1537                 iface->ra_mtu = iface->if_mtu;
1538                 info("Defaulted %s value for interface '%s' to %d",
1539                      iface_attrs[IFACE_ATTR_RA_MTU].name, iface->name, iface->ra_mtu);
1540         }
1541 
1542         if ((c = tb[IFACE_ATTR_RA_SLAAC]))
1543                 iface->ra_slaac = blobmsg_get_bool(c);
1544 
1545         if ((c = tb[IFACE_ATTR_RA_OFFLINK]))
1546                 iface->ra_not_onlink = blobmsg_get_bool(c);
1547 
1548         if ((c = tb[IFACE_ATTR_RA_ADVROUTER]))
1549                 iface->ra_advrouter = blobmsg_get_bool(c);
1550 
1551         /*
1552          * RFC4861: MaxRtrAdvInterval: MUST be no less than 4 seconds and no greater than 1800 seconds.
1553          * RFC8319: MaxRtrAdvInterval: MUST be no less than 4 seconds and no greater than 65535 seconds.
1554          * Default: 600 seconds
1555          */
1556         if ((c = tb[IFACE_ATTR_RA_MAXINTERVAL])){
1557                 uint32_t ra_maxinterval = blobmsg_get_u32(c);
1558                 if (ra_maxinterval < 4)
1559                         ra_maxinterval = 4;
1560                 else if (ra_maxinterval > MaxRtrAdvInterval)
1561                                 ra_maxinterval = MaxRtrAdvInterval;
1562                 iface->ra_maxinterval = ra_maxinterval;
1563         }
1564 
1565         /*
1566          * RFC4861: MinRtrAdvInterval: MUST be no less than 3 seconds and no greater than .75 * MaxRtrAdvInterval.
1567          * Default: 0.33 * MaxRtrAdvInterval If MaxRtrAdvInterval >= 9 seconds; otherwise, the
1568          * Default is MaxRtrAdvInterval.
1569          */
1570         if ((c = tb[IFACE_ATTR_RA_MININTERVAL])){
1571                 uint32_t ra_mininterval = blobmsg_get_u32(c);
1572                 if (ra_mininterval < MinRtrAdvInterval)
1573                         ra_mininterval = MinRtrAdvInterval; // clamp min
1574                 else if (ra_mininterval > (0.75 * iface->ra_maxinterval))
1575                                 ra_mininterval = 0.75 * iface->ra_maxinterval; // clamp max
1576                 iface->ra_mininterval = ra_mininterval;
1577         }
1578 
1579         /*
1580          * RFC4861: AdvDefaultLifetime: MUST be either zero or between MaxRtrAdvInterval and 9000 seconds.
1581          * RFC8319: AdvDefaultLifetime: MUST be either zero or between MaxRtrAdvInterval and 65535 seconds.
1582          * Default: 3 * MaxRtrAdvInterval
1583          * i.e. 3 * 65535 => 65535 seconds.
1584          */
1585         if ((c = tb[IFACE_ATTR_RA_LIFETIME])){
1586                 uint32_t ra_lifetime = blobmsg_get_u32(c);
1587                 if (ra_lifetime != 0){
1588                         if (ra_lifetime < iface->ra_maxinterval)
1589                                 ra_lifetime = iface->ra_maxinterval; // clamp min
1590                         else if (ra_lifetime > AdvDefaultLifetime)
1591                                 ra_lifetime = AdvDefaultLifetime; // clamp max
1592                 }
1593                 iface->ra_lifetime = ra_lifetime;
1594         }
1595 
1596         if ((c = tb[IFACE_ATTR_RA_DNS]))
1597                 iface->ra_dns = blobmsg_get_bool(c);
1598 
1599         if ((c = tb[IFACE_ATTR_DNR])) {
1600                 struct blob_attr *cur;
1601                 unsigned rem;
1602 
1603                 blobmsg_for_each_attr(cur, c, rem) {
1604                         if (blobmsg_type(cur) != BLOBMSG_TYPE_STRING || !blobmsg_check_attr(cur, false))
1605                                 continue;
1606 
1607                         if (parse_dnr_str(blobmsg_get_string(cur), iface))
1608                                 error("Invalid %s value configured for interface '%s'",
1609                                       iface_attrs[IFACE_ATTR_DNR].name, iface->name);
1610                 }
1611         }
1612 
1613         if ((c = tb[IFACE_ATTR_RA_PREF64])) {
1614                 struct in6_addr addr;
1615 
1616                 odhcpd_parse_addr6_prefix(blobmsg_get_string(c),
1617                                           &addr, &iface->pref64_length);
1618 
1619                 iface->pref64_prefix[0] = addr.s6_addr32[0];
1620                 switch (iface->pref64_length) {
1621                 case 96:
1622                         iface->pref64_plc = 0;
1623                         iface->pref64_prefix[1] = addr.s6_addr32[1];
1624                         iface->pref64_prefix[2] = addr.s6_addr32[2];
1625                         break;
1626                 case 64:
1627                         iface->pref64_plc = 1;
1628                         iface->pref64_prefix[1] = addr.s6_addr32[1];
1629                         iface->pref64_prefix[2] = 0;
1630                         break;
1631                 case 56:
1632                         iface->pref64_plc = 2;
1633                         iface->pref64_prefix[1] = addr.s6_addr32[1] & htonl(0xffffff00);
1634                         iface->pref64_prefix[2] = 0;
1635                         break;
1636                 case 48:
1637                         iface->pref64_plc = 3;
1638                         iface->pref64_prefix[1] = addr.s6_addr32[1] & htonl(0xffff0000);
1639                         iface->pref64_prefix[2] = 0;
1640                         break;
1641                 case 40:
1642                         iface->pref64_plc = 4;
1643                         iface->pref64_prefix[1] = addr.s6_addr32[1] & htonl(0xff000000);
1644                         iface->pref64_prefix[2] = 0;
1645                         break;
1646                 case 32:
1647                         iface->pref64_plc = 5;
1648                         iface->pref64_prefix[1] = 0;
1649                         iface->pref64_prefix[2] = 0;
1650                         break;
1651                 default:
1652                         warn("Invalid PREF64 prefix size (%d), ignoring ra_pref64 option!",
1653                              iface->pref64_length);
1654                         iface->pref64_length = 0;
1655                 }
1656         }
1657 
1658         if ((c = tb[IFACE_ATTR_IPV6_ONLY_PREFERRED])) {
1659                 uint32_t v6only_wait = blobmsg_get_u32(c);
1660 
1661                 if (v6only_wait > 0 && v6only_wait < DHCPV4_MIN_V6ONLY_WAIT) {
1662                         warn("Invalid %s value configured for interface '%s', clamped to %d",
1663                              iface_attrs[IFACE_ATTR_IPV6_ONLY_PREFERRED].name,
1664                              iface->name, DHCPV4_MIN_V6ONLY_WAIT);
1665                         v6only_wait = DHCPV4_MIN_V6ONLY_WAIT;
1666                 }
1667 
1668                 iface->dhcpv4_v6only_wait = v6only_wait;
1669         }
1670 
1671         if ((c = tb[IFACE_ATTR_RA_PREFERENCE])) {
1672                 const char *prio = blobmsg_get_string(c);
1673 
1674                 if (!strcmp(prio, "high"))
1675                         iface->route_preference = 1;
1676                 else if (!strcmp(prio, "low"))
1677                         iface->route_preference = -1;
1678                 else if (!strcmp(prio, "medium") || !strcmp(prio, "default"))
1679                         iface->route_preference = 0;
1680                 else
1681                         error("Invalid %s mode configured for interface '%s'",
1682                               iface_attrs[IFACE_ATTR_RA_PREFERENCE].name, iface->name);
1683         }
1684 
1685         if ((c = tb[IFACE_ATTR_NDPROXY_ROUTING]))
1686                 iface->learn_routes = blobmsg_get_bool(c);
1687 
1688         if ((c = tb[IFACE_ATTR_NDPROXY_SLAVE]))
1689                 iface->external = blobmsg_get_bool(c);
1690 
1691         if ((c = tb[IFACE_ATTR_NDP_FROM_LINK_LOCAL]))
1692                 iface->ndp_from_link_local = blobmsg_get_bool(c);
1693 
1694         if ((c = tb[IFACE_ATTR_PREFIX_FILTER]))
1695                 odhcpd_parse_addr6_prefix(blobmsg_get_string(c),
1696                                           &iface->pio_filter_addr,
1697                                           &iface->pio_filter_length);
1698 
1699         if (overwrite && (c = tb[IFACE_ATTR_NTP])) {
1700                 struct blob_attr *cur;
1701                 unsigned rem;
1702 
1703                 blobmsg_for_each_attr(cur, c, rem) {
1704                         if (blobmsg_type(cur) != BLOBMSG_TYPE_STRING || !blobmsg_check_attr(cur, false))
1705                                 continue;
1706 
1707                         char *str = blobmsg_get_string(cur);
1708                         struct in_addr addr4, *tmp4;
1709                         struct in6_addr addr6, *tmp6;
1710 
1711                         if (inet_pton(AF_INET, str, &addr4) == 1) {
1712                                 if (addr4.s_addr == INADDR_ANY)
1713                                         goto err;
1714 
1715                                 tmp4 = realloc(iface->dhcpv4_ntp, (iface->dhcpv4_ntp_cnt + 1) * sizeof(*iface->dhcpv4_ntp));
1716                                 if (!tmp4)
1717                                         goto err;
1718 
1719                                 iface->dhcpv4_ntp = tmp4;
1720                                 iface->dhcpv4_ntp[iface->dhcpv4_ntp_cnt++] = addr4;
1721 
1722                         } else if (inet_pton(AF_INET6, str, &addr6) == 1) {
1723                                 if (IN6_IS_ADDR_UNSPECIFIED(&addr6))
1724                                         goto err;
1725 
1726                                 tmp6 = realloc(iface->dhcpv6_sntp, (iface->dhcpv6_sntp_cnt + 1) * sizeof(*iface->dhcpv6_sntp));
1727                                 if (!tmp6)
1728                                         goto err;
1729 
1730                                 iface->dhcpv6_sntp = tmp6;
1731                                 iface->dhcpv6_sntp[iface->dhcpv6_sntp_cnt++] = addr6;
1732 
1733                                 if (!parse_ntp_options(&iface->dhcpv6_ntp_len, addr6, &iface->dhcpv6_ntp))
1734                                         iface->dhcpv6_ntp_cnt++;
1735 
1736                         } else {
1737                                 if (!parse_ntp_fqdn(&iface->dhcpv6_ntp_len, str, &iface->dhcpv6_ntp))
1738                                         iface->dhcpv6_ntp_cnt++;
1739                         }
1740                 }
1741         }
1742 
1743         config_load_ra_pio(iface);
1744 
1745         return 0;
1746 
1747 err:
1748         close_interface(iface);
1749         return -1;
1750 }
1751 
1752 static int set_interface(struct uci_section *s)
1753 {
1754         blob_buf_init(&b, 0);
1755         uci_to_blob(&b, s, &interface_attr_list);
1756 
1757         return config_parse_interface(blob_data(b.head), blob_len(b.head), s->e.name, true);
1758 }
1759 
1760 static void lease_cfg_delete_dhcpv6_leases(struct lease_cfg *lease_cfg)
1761 {
1762         struct dhcpv6_lease *lease, *tmp;
1763 
1764         list_for_each_entry_safe(lease, tmp, &lease_cfg->dhcpv6_leases, lease_cfg_list)
1765                 dhcpv6_free_lease(lease);
1766 }
1767 
1768 static void lease_cfg_update_leases(struct lease_cfg *lease_cfg)
1769 {
1770         struct dhcpv4_lease *a4 = lease_cfg->dhcpv4_lease;
1771         struct dhcpv6_lease *lease6;
1772 
1773         if (a4) {
1774                 free(a4->hostname);
1775                 a4->hostname = NULL;
1776 
1777                 if (lease_cfg->hostname)
1778                         a4->hostname = strdup(lease_cfg->hostname);
1779         }
1780 
1781         list_for_each_entry(lease6, &lease_cfg->dhcpv6_leases, lease_cfg_list) {
1782                 free(lease6->hostname);
1783                 lease6->hostname = NULL;
1784 
1785                 if (lease_cfg->hostname)
1786                         lease6->hostname = strdup(lease_cfg->hostname);
1787 
1788                 lease6->leasetime = lease_cfg->leasetime;
1789         }
1790 }
1791 
1792 static int lease_cfg_cmp(const void *k1, const void *k2, _o_unused void *ptr)
1793 {
1794         const struct lease_cfg *lease_cfg1 = k1, *lease_cfg2 = k2;
1795         int cmp = 0;
1796 
1797         if (lease_cfg1->duid_count != lease_cfg2->duid_count)
1798                 return lease_cfg1->duid_count - lease_cfg2->duid_count;
1799 
1800         for (size_t i = 0; i < lease_cfg1->duid_count; i++) {
1801                 if (lease_cfg1->duids[i].len != lease_cfg2->duids[i].len)
1802                         return lease_cfg1->duids[i].len - lease_cfg2->duids[i].len;
1803 
1804                 if (lease_cfg1->duids[i].len && lease_cfg2->duids[i].len) {
1805                         cmp = memcmp(lease_cfg1->duids[i].id, lease_cfg2->duids[i].id,
1806                                      lease_cfg1->duids[i].len);
1807                         if (cmp)
1808                                 return cmp;
1809                 }
1810         }
1811 
1812         if (lease_cfg1->mac_count != lease_cfg2->mac_count)
1813                 return lease_cfg1->mac_count - lease_cfg2->mac_count;
1814 
1815         for (size_t i = 0; i < lease_cfg1->mac_count; i++) {
1816                 cmp = memcmp(lease_cfg1->macs[i].ether_addr_octet,
1817                              lease_cfg2->macs[i].ether_addr_octet,
1818                              sizeof(lease_cfg1->macs[i].ether_addr_octet));
1819                 if (cmp)
1820                         return cmp;
1821         }
1822 
1823         return 0;
1824 }
1825 
1826 static void lease_cfg_change(struct lease_cfg *lease_cfg_old, struct lease_cfg *lease_cfg_new)
1827 {
1828         bool update = false;
1829 
1830         if ((!!lease_cfg_new->hostname != !!lease_cfg_old->hostname) ||
1831             (lease_cfg_new->hostname && strcmp(lease_cfg_new->hostname, lease_cfg_old->hostname))) {
1832                 free(lease_cfg_old->hostname);
1833                 lease_cfg_old->hostname = NULL;
1834 
1835                 if (lease_cfg_new->hostname)
1836                         lease_cfg_old->hostname = strdup(lease_cfg_new->hostname);
1837 
1838                 update = true;
1839         }
1840 
1841         if (lease_cfg_old->leasetime != lease_cfg_new->leasetime) {
1842                 lease_cfg_old->leasetime = lease_cfg_new->leasetime;
1843                 update = true;
1844         }
1845 
1846         if (lease_cfg_old->ipv4.s_addr != lease_cfg_new->ipv4.s_addr) {
1847                 lease_cfg_old->ipv4 = lease_cfg_new->ipv4;
1848                 dhcpv4_free_lease(lease_cfg_old->dhcpv4_lease);
1849         }
1850 
1851         if (lease_cfg_old->hostid != lease_cfg_new->hostid) {
1852                 lease_cfg_old->hostid = lease_cfg_new->hostid;
1853                 lease_cfg_delete_dhcpv6_leases(lease_cfg_old);
1854         }
1855 
1856         if (update)
1857                 lease_cfg_update_leases(lease_cfg_old);
1858 
1859         free_lease_cfg(lease_cfg_new);
1860 }
1861 
1862 static void lease_cfg_delete(struct lease_cfg *lease_cfg)
1863 {
1864         dhcpv4_free_lease(lease_cfg->dhcpv4_lease);
1865         lease_cfg_delete_dhcpv6_leases(lease_cfg);
1866         free_lease_cfg(lease_cfg);
1867 }
1868 
1869 static void lease_cfg_update(_o_unused struct vlist_tree *tree, struct vlist_node *node_new,
1870                             struct vlist_node *node_old)
1871 {
1872         struct lease_cfg *lease_cfg_new = container_of(node_new, struct lease_cfg, node);
1873         struct lease_cfg *lease_cfg_old = container_of(node_old, struct lease_cfg, node);
1874 
1875         if (node_old && node_new)
1876                 lease_cfg_change(lease_cfg_old, lease_cfg_new);
1877         else if (node_old)
1878                 lease_cfg_delete(lease_cfg_old);
1879 }
1880 
1881 /*
1882  * Either find:
1883  *  a) a lease cfg with an exact DUID/IAID match; or
1884  *  b) a lease cfg with a matching DUID and no IAID set
1885  */
1886 struct lease_cfg *
1887 config_find_lease_cfg_by_duid_and_iaid(const uint8_t *duid, const uint16_t len, const uint32_t iaid)
1888 {
1889         struct lease_cfg *lease_cfg, *candidate = NULL;
1890 
1891         vlist_for_each_element(&lease_cfgs, lease_cfg, node) {
1892                 for (size_t i = 0; i < lease_cfg->duid_count; i++) {
1893                         if (lease_cfg->duids[i].len != len)
1894                                 continue;
1895 
1896                         if (memcmp(lease_cfg->duids[i].id, duid, len))
1897                                 continue;
1898 
1899                         if (!lease_cfg->duids[i].iaid_set) {
1900                                 candidate = lease_cfg;
1901                                 continue;
1902                         }
1903 
1904                         if (lease_cfg->duids[i].iaid == iaid)
1905                                 return lease_cfg;
1906                 }
1907         }
1908 
1909         return candidate;
1910 }
1911 
1912 struct lease_cfg *config_find_lease_cfg_by_mac(const uint8_t *mac)
1913 {
1914         struct lease_cfg *lease_cfg;
1915 
1916         vlist_for_each_element(&lease_cfgs, lease_cfg, node) {
1917                 for (size_t i = 0; i < lease_cfg->mac_count; i++) {
1918                         if (!memcmp(lease_cfg->macs[i].ether_addr_octet, mac,
1919                                     sizeof(lease_cfg->macs[i].ether_addr_octet)))
1920                                 return lease_cfg;
1921                 }
1922         }
1923 
1924         return NULL;
1925 }
1926 
1927 struct lease_cfg *config_find_lease_cfg_by_hostid(const uint64_t hostid)
1928 {
1929         struct lease_cfg *lease_cfg;
1930 
1931         vlist_for_each_element(&lease_cfgs, lease_cfg, node) {
1932                 if (lease_cfg->hostid == hostid)
1933                         return lease_cfg;
1934         }
1935 
1936         return NULL;
1937 }
1938 
1939 struct lease_cfg *config_find_lease_cfg_by_ipv4(const struct in_addr ipv4)
1940 {
1941         struct lease_cfg *lease_cfg;
1942 
1943         vlist_for_each_element(&lease_cfgs, lease_cfg, node) {
1944                 if (lease_cfg->ipv4.s_addr == ipv4.s_addr)
1945                         return lease_cfg;
1946         }
1947 
1948         return NULL;
1949 }
1950 
1951 void reload_services(struct interface *iface)
1952 {
1953         if (iface->ifflags & IFF_RUNNING) {
1954                 debug("Enabling services with %s running", iface->ifname);
1955                 router_setup_interface(iface, iface->ra != MODE_DISABLED);
1956                 dhcpv6_setup_interface(iface, iface->dhcpv6 != MODE_DISABLED);
1957                 ndp_setup_interface(iface, iface->ndp != MODE_DISABLED);
1958                 dhcpv4_setup_interface(iface, iface->dhcpv4 != MODE_DISABLED);
1959         } else {
1960                 debug("Disabling services with %s not running", iface->ifname);
1961                 router_setup_interface(iface, false);
1962                 dhcpv6_setup_interface(iface, false);
1963                 ndp_setup_interface(iface, false);
1964                 dhcpv4_setup_interface(iface, false);
1965         }
1966 }
1967 
1968 static int ipv6_pxe_from_uci(struct uci_section* s)
1969 {
1970         blob_buf_init(&b, 0);
1971         uci_to_blob(&b, s, &ipv6_pxe_attr_list);
1972 
1973         void* data = blob_data(b.head);
1974         size_t len = blob_len(b.head);
1975 
1976         struct blob_attr* tb[IFACE_ATTR_MAX];
1977         blobmsg_parse(ipv6_pxe_attrs, IPV6_PXE_MAX, tb, data, len);
1978 
1979         if (!tb[IPV6_PXE_URL])
1980                 return -1;
1981 
1982         const char* url = blobmsg_get_string(tb[IPV6_PXE_URL]);
1983 
1984         uint32_t arch = 0xFFFFFFFF;
1985         if (tb[IPV6_PXE_ARCH])
1986                 arch = blobmsg_get_u32(tb[IPV6_PXE_ARCH]);
1987 
1988         return ipv6_pxe_entry_new(arch, url) ? -1 : 0;
1989 }
1990 
1991 #define JSON_LENGTH "length"
1992 #define JSON_PREFIX "prefix"
1993 #define JSON_SLAAC "slaac"
1994 #define JSON_TIME "time"
1995 
1996 static inline time_t config_time_from_json(time_t json_time)
1997 {
1998         time_t ref, now;
1999 
2000         ref = time(NULL);
2001         now = odhcpd_time();
2002 
2003         if (now > json_time || ref > json_time)
2004                 return 0;
2005 
2006         return json_time + (now - ref);
2007 }
2008 
2009 static inline time_t config_time_to_json(time_t config_time)
2010 {
2011         time_t ref, now;
2012 
2013         ref = time(NULL);
2014         now = odhcpd_time();
2015 
2016         return config_time + (ref - now);
2017 }
2018 
2019 static inline bool config_ra_pio_enabled(struct interface *iface)
2020 {
2021         return config.ra_piofolder_fd >= 0 && iface->ra == MODE_SERVER && !iface->master;
2022 }
2023 
2024 static bool config_ra_pio_time(json_object *slaac_json, time_t *slaac_time)
2025 {
2026         time_t pio_json_time, pio_time;
2027         json_object *time_json;
2028 
2029         time_json = json_object_object_get(slaac_json, JSON_TIME);
2030         if (!time_json)
2031                 return true;
2032 
2033         pio_json_time = (time_t) json_object_get_int64(time_json);
2034         if (!pio_json_time)
2035                 return true;
2036 
2037         pio_time = config_time_from_json(pio_json_time);
2038         if (!pio_time)
2039                 return false;
2040 
2041         *slaac_time = pio_time;
2042 
2043         return true;
2044 }
2045 
2046 static json_object *config_load_ra_pio_json(struct interface *iface)
2047 {
2048         json_object *json;
2049         int fd;
2050 
2051         fd = openat(config.ra_piofolder_fd, iface->ifname, O_RDONLY | O_CLOEXEC);
2052         if (fd < 0)
2053                 return NULL;
2054 
2055         json = json_object_from_fd(fd);
2056 
2057         close(fd);
2058 
2059         if (!json)
2060                 error("rfc9096: %s: json read error %s",
2061                       iface->ifname,
2062                       json_util_get_last_err());
2063 
2064         return json;
2065 }
2066 
2067 void config_load_ra_pio(struct interface *iface)
2068 {
2069         json_object *json, *slaac_json;
2070         struct ra_pio *new_pios;
2071         size_t pio_cnt;
2072         time_t now;
2073 
2074         if (!config_ra_pio_enabled(iface))
2075                 return;
2076 
2077         json = config_load_ra_pio_json(iface);
2078         if (!json)
2079                 return;
2080 
2081         slaac_json = json_object_object_get(json, JSON_SLAAC);
2082         if (!slaac_json) {
2083                 json_object_put(json);
2084                 return;
2085         }
2086 
2087         now = odhcpd_time();
2088 
2089         pio_cnt = json_object_array_length(slaac_json);
2090         new_pios = realloc(iface->pios, sizeof(struct ra_pio) * pio_cnt);
2091         if (!new_pios) {
2092                 json_object_put(json);
2093                 return;
2094         }
2095 
2096         iface->pios = new_pios;
2097         iface->pio_cnt = 0;
2098         for (size_t i = 0; i < pio_cnt; i++) {
2099                 json_object *cur_pio_json, *length_json, *prefix_json;
2100                 const char *pio_str;
2101                 time_t pio_lt = 0;
2102                 struct ra_pio *pio;
2103                 uint8_t pio_len;
2104 
2105                 cur_pio_json = json_object_array_get_idx(slaac_json, i);
2106                 if (!cur_pio_json)
2107                         continue;
2108 
2109                 if (!config_ra_pio_time(cur_pio_json, &pio_lt))
2110                         continue;
2111 
2112                 length_json = json_object_object_get(cur_pio_json, JSON_LENGTH);
2113                 if (!length_json)
2114                         continue;
2115 
2116                 prefix_json = json_object_object_get(cur_pio_json, JSON_PREFIX);
2117                 if (!prefix_json)
2118                         continue;
2119 
2120                 pio_len = (uint8_t) json_object_get_uint64(length_json);
2121                 pio_str = json_object_get_string(prefix_json);
2122                 pio = &iface->pios[iface->pio_cnt];
2123 
2124                 inet_pton(AF_INET6, pio_str, &pio->prefix);
2125                 pio->length = pio_len;
2126                 pio->lifetime = pio_lt;
2127                 info("rfc9096: %s: load %s/%u (%u)",
2128                      iface->ifname,
2129                      pio_str,
2130                      pio_len,
2131                      ra_pio_lifetime(pio, now));
2132 
2133                 iface->pio_cnt++;
2134         }
2135 
2136         json_object_put(json);
2137 
2138         if (!iface->pio_cnt) {
2139                 free(iface->pios);
2140                 iface->pios = NULL;
2141         } else if (iface->pio_cnt != pio_cnt) {
2142                 struct ra_pio *tmp;
2143 
2144                 tmp = realloc(iface->pios, sizeof(struct ra_pio) * iface->pio_cnt);
2145                 if (tmp)
2146                         iface->pios = tmp;
2147         }
2148 }
2149 
2150 static void config_save_ra_pio_json(struct interface *iface, struct json_object *json)
2151 {
2152         size_t tmp_piofile_strlen;
2153         char *tmp_piofile;
2154         int fd, ret;
2155 
2156         tmp_piofile_strlen = strlen(iface->ifname) + 2;
2157         tmp_piofile = alloca(tmp_piofile_strlen);
2158         snprintf(tmp_piofile, tmp_piofile_strlen, ".%s", iface->ifname);
2159 
2160         fd = openat(config.ra_piofolder_fd,
2161                 tmp_piofile,
2162                 O_CREAT | O_TRUNC | O_WRONLY | O_CLOEXEC,
2163                 0644);
2164         if (fd < 0) {
2165                 error("rfc9096: %s: error %m creating temporary json file",
2166                       iface->ifname);
2167                 return;
2168         }
2169 
2170         ret = json_object_to_fd(fd, json, JSON_C_TO_STRING_PLAIN);
2171         if (ret) {
2172                 error("rfc9096: %s: json write error %s",
2173                       iface->ifname,
2174                       json_util_get_last_err());
2175                 close(fd);
2176                 unlinkat(config.ra_piofolder_fd, tmp_piofile, 0);
2177                 return;
2178         }
2179 
2180         ret = fsync(fd);
2181         if (ret) {
2182                 error("rfc9096: %s: error %m syncing %s",
2183                       iface->ifname,
2184                       tmp_piofile);
2185                 close(fd);
2186                 unlinkat(config.ra_piofolder_fd, tmp_piofile, 0);
2187                 return;
2188         }
2189 
2190         ret = close(fd);
2191         if (ret) {
2192                 error("rfc9096: %s: error %m closing %s",
2193                       iface->ifname,
2194                       tmp_piofile);
2195                 unlinkat(config.ra_piofolder_fd, tmp_piofile, 0);
2196                 return;
2197         }
2198 
2199         ret = renameat(config.ra_piofolder_fd,
2200                 tmp_piofile,
2201                 config.ra_piofolder_fd,
2202                 iface->ifname);
2203         if (ret) {
2204                 error("rfc9096: %s: error %m renaming piofile: %s -> %s",
2205                       iface->ifname,
2206                       tmp_piofile,
2207                       iface->ifname);
2208                 close(fd);
2209                 unlinkat(config.ra_piofolder_fd, tmp_piofile, 0);
2210                 return;
2211         }
2212 
2213         iface->pio_update = false;
2214         warn("rfc9096: %s: piofile updated", iface->ifname);
2215 }
2216 
2217 void config_save_ra_pio(struct interface *iface)
2218 {
2219         struct json_object *json, *slaac_json;
2220         char ipv6_str[INET6_ADDRSTRLEN];
2221         time_t now;
2222 
2223         if (!config_ra_pio_enabled(iface))
2224                 return;
2225 
2226         if (!iface->pio_update)
2227                 return;
2228 
2229         now = odhcpd_time();
2230 
2231         json = json_object_new_object();
2232         if (!json)
2233                 return;
2234 
2235         slaac_json = json_object_new_array_ext(iface->pio_cnt);
2236         if (!slaac_json) {
2237                 json_object_put(slaac_json);
2238                 return;
2239         }
2240 
2241         json_object_object_add(json, JSON_SLAAC, slaac_json);
2242 
2243         for (size_t i = 0; i < iface->pio_cnt; i++) {
2244                 struct json_object *cur_pio_json, *len_json, *pfx_json;
2245                 const struct ra_pio *cur_pio = &iface->pios[i];
2246 
2247                 if (ra_pio_expired(cur_pio, now))
2248                         continue;
2249 
2250                 cur_pio_json = json_object_new_object();
2251                 if (!cur_pio_json)
2252                         continue;
2253 
2254                 inet_ntop(AF_INET6, &cur_pio->prefix, ipv6_str, sizeof(ipv6_str));
2255 
2256                 pfx_json = json_object_new_string(ipv6_str);
2257                 if (!pfx_json) {
2258                         json_object_put(cur_pio_json);
2259                         continue;
2260                 }
2261 
2262                 len_json = json_object_new_uint64(cur_pio->length);
2263                 if (!len_json) {
2264                         json_object_put(cur_pio_json);
2265                         json_object_put(pfx_json);
2266                         continue;
2267                 }
2268 
2269                 json_object_object_add(cur_pio_json, JSON_PREFIX, pfx_json);
2270                 json_object_object_add(cur_pio_json, JSON_LENGTH, len_json);
2271 
2272                 if (cur_pio->lifetime) {
2273                         struct json_object *time_json;
2274                         time_t pio_lt;
2275 
2276                         pio_lt = config_time_to_json(cur_pio->lifetime);
2277 
2278                         time_json = json_object_new_int64(pio_lt);
2279                         if (time_json)
2280                                 json_object_object_add(cur_pio_json, JSON_TIME, time_json);
2281                 }
2282 
2283                 json_object_array_add(slaac_json, cur_pio_json);
2284         }
2285 
2286         config_save_ra_pio_json(iface, json);
2287 
2288         json_object_put(json);
2289 }
2290 
2291 void odhcpd_reload(void)
2292 {
2293         struct uci_context *uci = uci_alloc_context();
2294         struct interface *master = NULL, *i, *tmp;
2295         char *uci_dhcp_path = "dhcp";
2296         char *uci_system_path = "system";
2297         char *uci_network_path = "network";
2298 
2299         if (!uci)
2300                 return;
2301 
2302         if (config.uci_cfgdir) {
2303                 size_t dlen = strlen(config.uci_cfgdir);
2304 
2305                 uci_dhcp_path = alloca(dlen + sizeof("/dhcp"));
2306                 sprintf(uci_dhcp_path, "%s/dhcp", config.uci_cfgdir);
2307                 uci_system_path = alloca(dlen + sizeof("/system"));
2308                 sprintf(uci_system_path, "%s/system", config.uci_cfgdir);
2309                 uci_network_path = alloca(dlen + sizeof("/network"));
2310                 sprintf(uci_network_path, "%s/network", config.uci_cfgdir);
2311         }
2312 
2313         vlist_update(&lease_cfgs);
2314         avl_for_each_element(&interfaces, i, avl)
2315                 clean_interface(i);
2316 
2317         struct uci_package *network = NULL;
2318         if (!uci_load(uci, uci_network_path, &network)) {
2319                 struct uci_element *e;
2320 
2321                 /* 0. Global settings */
2322                 uci_foreach_element(&network->sections, e) {
2323                         struct uci_section *s = uci_to_section(e);
2324                         if (!strcmp(s->type, "globals"))
2325                                 set_global_config(s);
2326                 }
2327         }
2328         uci_unload(uci, network);
2329 
2330         struct uci_package *dhcp = NULL;
2331         if (!uci_load(uci, uci_dhcp_path, &dhcp)) {
2332                 struct uci_element *e;
2333 
2334                 /* 1. General odhcpd settings */
2335                 uci_foreach_element(&dhcp->sections, e) {
2336                         struct uci_section *s = uci_to_section(e);
2337                         if (!strcmp(s->type, "odhcpd"))
2338                                 set_config(s);
2339                 }
2340 
2341                 /* 2. DHCP pools */
2342                 uci_foreach_element(&dhcp->sections, e) {
2343                         struct uci_section *s = uci_to_section(e);
2344                         if (!strcmp(s->type, "dhcp"))
2345                                 set_interface(s);
2346                 }
2347 
2348                 /* 3. Static lease cfgs */
2349                 uci_foreach_element(&dhcp->sections, e) {
2350                         struct uci_section* s = uci_to_section(e);
2351                         if (!strcmp(s->type, "host"))
2352                                 set_lease_cfg_from_uci(s);
2353                 }
2354 
2355                 /* 4. IPv6 PxE */
2356                 ipv6_pxe_clear();
2357                 uci_foreach_element(&dhcp->sections, e) {
2358                         struct uci_section* s = uci_to_section(e);
2359                         if (!strcmp(s->type, "boot6"))
2360                                 ipv6_pxe_from_uci(s);
2361                 }
2362                 ipv6_pxe_dump();
2363         }
2364         uci_unload(uci, dhcp);
2365 
2366         struct uci_package *system = NULL;
2367         if (config.enable_tz && !uci_load(uci, uci_system_path, &system)) {
2368                 struct uci_element *e;
2369 
2370                 /* 5. System settings */
2371                 uci_foreach_element(&system->sections, e) {
2372                         struct uci_section *s = uci_to_section(e);
2373                         if (!strcmp(s->type, "system"))
2374                                 set_timezone_info_from_uci(s);
2375                 }
2376         }
2377         uci_unload(uci, system);
2378 
2379         if (config.dhcp_statefile) {
2380                 char *dir = dirname(strdupa(config.dhcp_statefile));
2381                 char *file = basename(config.dhcp_statefile);
2382 
2383                 memmove(config.dhcp_statefile, file, strlen(file) + 1);
2384                 mkdir_p(dir, 0755);
2385 
2386                 close(config.dhcp_statedir_fd);
2387                 config.dhcp_statedir_fd = open(dir, O_PATH | O_DIRECTORY | O_CLOEXEC);
2388                 if (config.dhcp_statedir_fd < 0)
2389                         error("Unable to open statedir: '%s': %m", dir);
2390         }
2391 
2392         if (config.dhcp_hostsdir) {
2393                 char *dir = strdupa(config.dhcp_hostsdir);
2394 
2395                 mkdir_p(dir, 0755);
2396 
2397                 close(config.dhcp_hostsdir_fd);
2398                 config.dhcp_hostsdir_fd = open(dir, O_PATH | O_DIRECTORY | O_CLOEXEC);
2399                 if (config.dhcp_hostsdir_fd < 0)
2400                         error("Unable to open hostsdir '%s': %m", dir);
2401         }
2402 
2403         if (config.ra_piofolder) {
2404                 char *path = strdupa(config.ra_piofolder);
2405 
2406                 mkdir_p(path, 0755);
2407 
2408                 close(config.ra_piofolder_fd);
2409                 config.ra_piofolder_fd = open(path, O_PATH | O_DIRECTORY | O_CLOEXEC);
2410                 if (config.ra_piofolder_fd < 0)
2411                         error("Unable to open piofolder '%s': %m", path);
2412         }
2413 
2414         vlist_flush(&lease_cfgs);
2415 
2416         ubus_apply_network();
2417 
2418         bool any_dhcpv6_slave = false, any_ra_slave = false, any_ndp_slave = false;
2419 
2420         /* Test for */
2421         avl_for_each_element(&interfaces, i, avl) {
2422                 if (i->master)
2423                         continue;
2424 
2425                 if (i->dhcpv6 == MODE_HYBRID || i->dhcpv6 == MODE_RELAY)
2426                         any_dhcpv6_slave = true;
2427 
2428                 if (i->ra == MODE_HYBRID || i->ra == MODE_RELAY)
2429                         any_ra_slave = true;
2430 
2431                 if (i->ndp == MODE_HYBRID || i->ndp == MODE_RELAY)
2432                         any_ndp_slave = true;
2433         }
2434 
2435         /* Evaluate hybrid mode for master */
2436         avl_for_each_element(&interfaces, i, avl) {
2437                 if (!i->master)
2438                         continue;
2439 
2440                 enum odhcpd_mode hybrid_mode = MODE_DISABLED;
2441 
2442                 if (config.use_ubus && !ubus_has_prefix(i->name, i->ifname))
2443                         hybrid_mode = MODE_RELAY;
2444 
2445                 if (i->dhcpv6 == MODE_HYBRID)
2446                         i->dhcpv6 = hybrid_mode;
2447 
2448                 if (i->dhcpv6 == MODE_RELAY && !any_dhcpv6_slave)
2449                         i->dhcpv6 = MODE_DISABLED;
2450 
2451                 if (i->ra == MODE_HYBRID)
2452                         i->ra = hybrid_mode;
2453 
2454                 if (i->ra == MODE_RELAY && !any_ra_slave)
2455                         i->ra = MODE_DISABLED;
2456 
2457                 if (i->ndp == MODE_HYBRID)
2458                         i->ndp = hybrid_mode;
2459 
2460                 if (i->ndp == MODE_RELAY && !any_ndp_slave)
2461                         i->ndp = MODE_DISABLED;
2462 
2463                 if (i->dhcpv6 == MODE_RELAY || i->ra == MODE_RELAY || i->ndp == MODE_RELAY)
2464                         master = i;
2465         }
2466 
2467 
2468         avl_for_each_element_safe(&interfaces, i, avl, tmp) {
2469                 if (i->inuse && i->ifflags & IFF_RUNNING) {
2470                         /* Resolve hybrid mode */
2471                         if (i->dhcpv6 == MODE_HYBRID)
2472                                 i->dhcpv6 = (master && master->dhcpv6 == MODE_RELAY) ?
2473                                                 MODE_RELAY : MODE_SERVER;
2474 
2475                         if (i->ra == MODE_HYBRID)
2476                                 i->ra = (master && master->ra == MODE_RELAY) ?
2477                                                 MODE_RELAY : MODE_SERVER;
2478 
2479                         if (i->ndp == MODE_HYBRID)
2480                                 i->ndp = (master && master->ndp == MODE_RELAY) ?
2481                                                 MODE_RELAY : MODE_DISABLED;
2482 
2483                         reload_services(i);
2484                 } else
2485                         close_interface(i);
2486         }
2487 
2488         uci_free_context(uci);
2489 }
2490 
2491 static void signal_reload(_o_unused struct uloop_signal *signal)
2492 {
2493         odhcpd_reload();
2494 }
2495 
2496 int odhcpd_run(void)
2497 {
2498         static struct uloop_signal sighup = { .signo = SIGHUP, .cb = signal_reload };
2499 
2500         if (config.use_ubus) {
2501                 while (ubus_init()) {
2502                         if (uloop_cancelled)
2503                                 return EXIT_FAILURE;
2504                         sleep(1);
2505                 }
2506         }
2507 
2508         odhcpd_reload();
2509 
2510         /* uloop_init() already handles SIGINT/SIGTERM */
2511         if (uloop_signal_add(&sighup) < 0)
2512                 return EXIT_FAILURE;
2513 
2514         uloop_run();
2515 
2516         return EXIT_SUCCESS;
2517 }
2518 

This page was automatically generated by LXR 0.3.1.  •  OpenWrt