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

This page was automatically generated by LXR 0.3.1.  •  OpenWrt