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

Sources/odhcpd/src/config.c

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

This page was automatically generated by LXR 0.3.1.  •  OpenWrt