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

Sources/odhcpd/src/config.c

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

This page was automatically generated by LXR 0.3.1.  •  OpenWrt