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

This page was automatically generated by LXR 0.3.1.  •  OpenWrt