14 #include <libubox/utils.h>
15 #include <libubox/avl.h>
16 #include <libubox/avl-cmp.h>
17 #include <libubox/list.h>
18 #include <libubox/vlist.h>
22 static struct blob_buf b
;
23 static int reload_pipe
[2] = { -1, -1 };
25 static int lease_cmp(const void *k1
, const void *k2
, void *ptr
);
26 static void lease_update(struct vlist_tree
*tree
, struct vlist_node
*node_new
,
27 struct vlist_node
*node_old
);
29 struct vlist_tree leases
= VLIST_TREE_INIT(leases
, lease_cmp
, lease_update
, true, false);
30 AVL_TREE(interfaces
, avl_strcmp
, false, NULL
);
31 struct config config
= {.legacy
= false, .main_dhcpv4
= false,
32 .dhcp_cb
= NULL
, .dhcp_statefile
= NULL
,
33 .log_level
= LOG_WARNING
};
35 #define START_DEFAULT 100
36 #define LIMIT_DEFAULT 150
42 IFACE_ATTR_DYNAMICDHCP
,
55 IFACE_ATTR_FILTER_CLASS
,
56 IFACE_ATTR_DHCPV4_FORCERECONF
,
57 IFACE_ATTR_DHCPV6_RAW
,
58 IFACE_ATTR_DHCPV6_ASSIGNALL
,
61 IFACE_ATTR_RA_DEFAULT
,
62 IFACE_ATTR_RA_MANAGEMENT
,
63 IFACE_ATTR_RA_OFFLINK
,
64 IFACE_ATTR_RA_PREFERENCE
,
65 IFACE_ATTR_RA_ADVROUTER
,
66 IFACE_ATTR_RA_MININTERVAL
,
67 IFACE_ATTR_RA_MAXINTERVAL
,
68 IFACE_ATTR_RA_LIFETIME
,
69 IFACE_ATTR_RA_USELEASETIME
,
70 IFACE_ATTR_RA_REACHABLETIME
,
71 IFACE_ATTR_RA_RETRANSTIME
,
72 IFACE_ATTR_RA_HOPLIMIT
,
75 IFACE_ATTR_PD_MANAGER
,
77 IFACE_ATTR_NDPROXY_ROUTING
,
78 IFACE_ATTR_NDPROXY_SLAVE
,
79 IFACE_ATTR_PREFIX_FILTER
,
83 static const struct blobmsg_policy iface_attrs
[IFACE_ATTR_MAX
] = {
84 [IFACE_ATTR_INTERFACE
] = { .name
= "interface", .type
= BLOBMSG_TYPE_STRING
},
85 [IFACE_ATTR_IFNAME
] = { .name
= "ifname", .type
= BLOBMSG_TYPE_STRING
},
86 [IFACE_ATTR_NETWORKID
] = { .name
= "networkid", .type
= BLOBMSG_TYPE_STRING
},
87 [IFACE_ATTR_DYNAMICDHCP
] = { .name
= "dynamicdhcp", .type
= BLOBMSG_TYPE_BOOL
},
88 [IFACE_ATTR_LEASETIME
] = { .name
= "leasetime", .type
= BLOBMSG_TYPE_STRING
},
89 [IFACE_ATTR_START
] = { .name
= "start", .type
= BLOBMSG_TYPE_INT32
},
90 [IFACE_ATTR_LIMIT
] = { .name
= "limit", .type
= BLOBMSG_TYPE_INT32
},
91 [IFACE_ATTR_MASTER
] = { .name
= "master", .type
= BLOBMSG_TYPE_BOOL
},
92 [IFACE_ATTR_UPSTREAM
] = { .name
= "upstream", .type
= BLOBMSG_TYPE_ARRAY
},
93 [IFACE_ATTR_RA
] = { .name
= "ra", .type
= BLOBMSG_TYPE_STRING
},
94 [IFACE_ATTR_DHCPV4
] = { .name
= "dhcpv4", .type
= BLOBMSG_TYPE_STRING
},
95 [IFACE_ATTR_DHCPV6
] = { .name
= "dhcpv6", .type
= BLOBMSG_TYPE_STRING
},
96 [IFACE_ATTR_NDP
] = { .name
= "ndp", .type
= BLOBMSG_TYPE_STRING
},
97 [IFACE_ATTR_ROUTER
] = { .name
= "router", .type
= BLOBMSG_TYPE_ARRAY
},
98 [IFACE_ATTR_DNS
] = { .name
= "dns", .type
= BLOBMSG_TYPE_ARRAY
},
99 [IFACE_ATTR_DOMAIN
] = { .name
= "domain", .type
= BLOBMSG_TYPE_ARRAY
},
100 [IFACE_ATTR_FILTER_CLASS
] = { .name
= "filter_class", .type
= BLOBMSG_TYPE_STRING
},
101 [IFACE_ATTR_DHCPV4_FORCERECONF
] = { .name
= "dhcpv4_forcereconf", .type
= BLOBMSG_TYPE_BOOL
},
102 [IFACE_ATTR_DHCPV6_RAW
] = { .name
= "dhcpv6_raw", .type
= BLOBMSG_TYPE_STRING
},
103 [IFACE_ATTR_DHCPV6_ASSIGNALL
] = { .name
="dhcpv6_assignall", .type
= BLOBMSG_TYPE_BOOL
},
104 [IFACE_ATTR_DHCPV6_PD
] = { .name
= "dhcpv6_pd", .type
= BLOBMSG_TYPE_BOOL
},
105 [IFACE_ATTR_DHCPV6_NA
] = { .name
= "dhcpv6_na", .type
= BLOBMSG_TYPE_BOOL
},
106 [IFACE_ATTR_PD_MANAGER
] = { .name
= "pd_manager", .type
= BLOBMSG_TYPE_STRING
},
107 [IFACE_ATTR_PD_CER
] = { .name
= "pd_cer", .type
= BLOBMSG_TYPE_STRING
},
108 [IFACE_ATTR_RA_DEFAULT
] = { .name
= "ra_default", .type
= BLOBMSG_TYPE_INT32
},
109 [IFACE_ATTR_RA_MANAGEMENT
] = { .name
= "ra_management", .type
= BLOBMSG_TYPE_INT32
},
110 [IFACE_ATTR_RA_OFFLINK
] = { .name
= "ra_offlink", .type
= BLOBMSG_TYPE_BOOL
},
111 [IFACE_ATTR_RA_PREFERENCE
] = { .name
= "ra_preference", .type
= BLOBMSG_TYPE_STRING
},
112 [IFACE_ATTR_RA_ADVROUTER
] = { .name
= "ra_advrouter", .type
= BLOBMSG_TYPE_BOOL
},
113 [IFACE_ATTR_RA_MININTERVAL
] = { .name
= "ra_mininterval", .type
= BLOBMSG_TYPE_INT32
},
114 [IFACE_ATTR_RA_MAXINTERVAL
] = { .name
= "ra_maxinterval", .type
= BLOBMSG_TYPE_INT32
},
115 [IFACE_ATTR_RA_LIFETIME
] = { .name
= "ra_lifetime", .type
= BLOBMSG_TYPE_INT32
},
116 [IFACE_ATTR_RA_USELEASETIME
] = { .name
= "ra_useleasetime", .type
= BLOBMSG_TYPE_BOOL
},
117 [IFACE_ATTR_RA_REACHABLETIME
] = { .name
= "ra_reachabletime", .type
= BLOBMSG_TYPE_INT32
},
118 [IFACE_ATTR_RA_RETRANSTIME
] = { .name
= "ra_retranstime", .type
= BLOBMSG_TYPE_INT32
},
119 [IFACE_ATTR_RA_HOPLIMIT
] = { .name
= "ra_hoplimit", .type
= BLOBMSG_TYPE_INT32
},
120 [IFACE_ATTR_RA_MTU
] = { .name
= "ra_mtu", .type
= BLOBMSG_TYPE_INT32
},
121 [IFACE_ATTR_RA_DNS
] = { .name
= "ra_dns", .type
= BLOBMSG_TYPE_BOOL
},
122 [IFACE_ATTR_NDPROXY_ROUTING
] = { .name
= "ndproxy_routing", .type
= BLOBMSG_TYPE_BOOL
},
123 [IFACE_ATTR_NDPROXY_SLAVE
] = { .name
= "ndproxy_slave", .type
= BLOBMSG_TYPE_BOOL
},
124 [IFACE_ATTR_PREFIX_FILTER
] = { .name
= "prefix_filter", .type
= BLOBMSG_TYPE_STRING
},
127 static const struct uci_blob_param_info iface_attr_info
[IFACE_ATTR_MAX
] = {
128 [IFACE_ATTR_UPSTREAM
] = { .type
= BLOBMSG_TYPE_STRING
},
129 [IFACE_ATTR_DNS
] = { .type
= BLOBMSG_TYPE_STRING
},
130 [IFACE_ATTR_DOMAIN
] = { .type
= BLOBMSG_TYPE_STRING
},
133 const struct uci_blob_param_list interface_attr_list
= {
134 .n_params
= IFACE_ATTR_MAX
,
135 .params
= iface_attrs
,
136 .info
= iface_attr_info
,
144 LEASE_ATTR_LEASETIME
,
149 static const struct blobmsg_policy lease_attrs
[LEASE_ATTR_MAX
] = {
150 [LEASE_ATTR_IP
] = { .name
= "ip", .type
= BLOBMSG_TYPE_STRING
},
151 [LEASE_ATTR_MAC
] = { .name
= "mac", .type
= BLOBMSG_TYPE_STRING
},
152 [LEASE_ATTR_DUID
] = { .name
= "duid", .type
= BLOBMSG_TYPE_STRING
},
153 [LEASE_ATTR_HOSTID
] = { .name
= "hostid", .type
= BLOBMSG_TYPE_STRING
},
154 [LEASE_ATTR_LEASETIME
] = { .name
= "leasetime", .type
= BLOBMSG_TYPE_STRING
},
155 [LEASE_ATTR_NAME
] = { .name
= "name", .type
= BLOBMSG_TYPE_STRING
},
158 const struct uci_blob_param_list lease_attr_list
= {
159 .n_params
= LEASE_ATTR_MAX
,
160 .params
= lease_attrs
,
165 ODHCPD_ATTR_MAINDHCP
,
166 ODHCPD_ATTR_LEASEFILE
,
167 ODHCPD_ATTR_LEASETRIGGER
,
168 ODHCPD_ATTR_LOGLEVEL
,
172 static const struct blobmsg_policy odhcpd_attrs
[ODHCPD_ATTR_MAX
] = {
173 [ODHCPD_ATTR_LEGACY
] = { .name
= "legacy", .type
= BLOBMSG_TYPE_BOOL
},
174 [ODHCPD_ATTR_MAINDHCP
] = { .name
= "maindhcp", .type
= BLOBMSG_TYPE_BOOL
},
175 [ODHCPD_ATTR_LEASEFILE
] = { .name
= "leasefile", .type
= BLOBMSG_TYPE_STRING
},
176 [ODHCPD_ATTR_LEASETRIGGER
] = { .name
= "leasetrigger", .type
= BLOBMSG_TYPE_STRING
},
177 [ODHCPD_ATTR_LOGLEVEL
] = { .name
= "loglevel", .type
= BLOBMSG_TYPE_INT32
},
180 const struct uci_blob_param_list odhcpd_attr_list
= {
181 .n_params
= ODHCPD_ATTR_MAX
,
182 .params
= odhcpd_attrs
,
185 static int mkdir_p(char *dir
, mode_t mask
)
187 char *l
= strrchr(dir
, '/');
195 if (mkdir_p(dir
, mask
))
200 ret
= mkdir(dir
, mask
);
201 if (ret
&& errno
== EEXIST
)
205 syslog(LOG_ERR
, "mkdir(%s, %d) failed: %m\n", dir
, mask
);
210 static void set_interface_defaults(struct interface
*iface
)
212 iface
->ignore
= true;
213 iface
->dhcpv4
= MODE_DISABLED
;
214 iface
->dhcpv6
= MODE_DISABLED
;
215 iface
->ra
= MODE_DISABLED
;
216 iface
->ndp
= MODE_DISABLED
;
217 iface
->learn_routes
= 1;
218 iface
->dhcpv4_leasetime
= 43200;
219 iface
->dhcpv4_start
.s_addr
= htonl(START_DEFAULT
);
220 iface
->dhcpv4_end
.s_addr
= htonl(START_DEFAULT
+ LIMIT_DEFAULT
- 1);
221 iface
->dhcpv6_assignall
= true;
222 iface
->dhcpv6_pd
= true;
223 iface
->dhcpv6_na
= true;
224 iface
->ra_managed
= RA_MANAGED_MFLAG
;
225 iface
->ra_maxinterval
= 600;
226 iface
->ra_mininterval
= iface
->ra_maxinterval
/3;
227 iface
->ra_lifetime
= -1;
228 iface
->ra_dns
= true;
231 static void clean_interface(struct interface
*iface
)
235 free(iface
->upstream
);
236 free(iface
->dhcpv4_router
);
237 free(iface
->dhcpv4_dns
);
238 free(iface
->dhcpv6_raw
);
239 free(iface
->filter_class
);
240 memset(&iface
->ra
, 0, sizeof(*iface
) - offsetof(struct interface
, ra
));
241 set_interface_defaults(iface
);
244 static void close_interface(struct interface
*iface
)
246 avl_delete(&interfaces
, &iface
->avl
);
248 router_setup_interface(iface
, false);
249 dhcpv6_setup_interface(iface
, false);
250 ndp_setup_interface(iface
, false);
251 #ifdef DHCPV4_SUPPORT
252 dhcpv4_setup_interface(iface
, false);
255 clean_interface(iface
);
262 static int parse_mode(const char *mode
)
264 if (!strcmp(mode
, "disabled"))
265 return MODE_DISABLED
;
266 else if (!strcmp(mode
, "server"))
268 else if (!strcmp(mode
, "relay"))
270 else if (!strcmp(mode
, "hybrid"))
276 static void set_config(struct uci_section
*s
)
278 struct blob_attr
*tb
[ODHCPD_ATTR_MAX
], *c
;
280 blob_buf_init(&b
, 0);
281 uci_to_blob(&b
, s
, &odhcpd_attr_list
);
282 blobmsg_parse(odhcpd_attrs
, ODHCPD_ATTR_MAX
, tb
, blob_data(b
.head
), blob_len(b
.head
));
284 if ((c
= tb
[ODHCPD_ATTR_LEGACY
]))
285 config
.legacy
= blobmsg_get_bool(c
);
287 if ((c
= tb
[ODHCPD_ATTR_MAINDHCP
]))
288 config
.main_dhcpv4
= blobmsg_get_bool(c
);
290 if ((c
= tb
[ODHCPD_ATTR_LEASEFILE
])) {
291 free(config
.dhcp_statefile
);
292 config
.dhcp_statefile
= strdup(blobmsg_get_string(c
));
295 if ((c
= tb
[ODHCPD_ATTR_LEASETRIGGER
])) {
296 free(config
.dhcp_cb
);
297 config
.dhcp_cb
= strdup(blobmsg_get_string(c
));
300 if ((c
= tb
[ODHCPD_ATTR_LOGLEVEL
])) {
301 int log_level
= (blobmsg_get_u32(c
) & LOG_PRIMASK
);
303 if (config
.log_level
!= log_level
) {
304 config
.log_level
= log_level
;
305 setlogmask(LOG_UPTO(config
.log_level
));
310 static double parse_leasetime(struct blob_attr
*c
) {
311 char *val
= blobmsg_get_string(c
), *endptr
= NULL
;
312 double time
= strcmp(val
, "infinite") ? strtod(val
, &endptr
) : UINT32_MAX
;
314 if (time
&& endptr
&& endptr
[0]) {
315 if (endptr
[0] == 's')
317 else if (endptr
[0] == 'm')
319 else if (endptr
[0] == 'h')
321 else if (endptr
[0] == 'd')
323 else if (endptr
[0] == 'w')
324 time
*= 7 * 24 * 3600;
338 static void free_lease(struct lease
*l
)
344 static int set_lease(struct uci_section
*s
)
346 struct blob_attr
*tb
[LEASE_ATTR_MAX
], *c
;
351 blob_buf_init(&b
, 0);
352 uci_to_blob(&b
, s
, &lease_attr_list
);
353 blobmsg_parse(lease_attrs
, LEASE_ATTR_MAX
, tb
, blob_data(b
.head
), blob_len(b
.head
));
355 if ((c
= tb
[LEASE_ATTR_DUID
]))
356 duidlen
= (blobmsg_data_len(c
) - 1) / 2;
358 l
= calloc_a(sizeof(*l
), &duid
, duidlen
);
362 if ((c
= tb
[LEASE_ATTR_MAC
]))
363 if (!ether_aton_r(blobmsg_get_string(c
), &l
->mac
))
366 if ((c
= tb
[LEASE_ATTR_DUID
])) {
370 len
= odhcpd_unhexlify(l
->duid
, duidlen
, blobmsg_get_string(c
));
378 if ((c
= tb
[LEASE_ATTR_NAME
])) {
379 l
->hostname
= strdup(blobmsg_get_string(c
));
380 if (!l
->hostname
|| !odhcpd_valid_hostname(l
->hostname
))
384 if ((c
= tb
[LEASE_ATTR_IP
]))
385 if (inet_pton(AF_INET
, blobmsg_get_string(c
), &l
->ipaddr
) < 0)
388 if ((c
= tb
[LEASE_ATTR_HOSTID
])) {
390 l
->hostid
= strtoul(blobmsg_get_string(c
), NULL
, 16);
394 uint32_t i4a
= ntohl(l
->ipaddr
) & 0xff;
395 l
->hostid
= ((i4a
/ 100) << 8) | (((i4a
% 100) / 10) << 4) | (i4a
% 10);
398 if ((c
= tb
[LEASE_ATTR_LEASETIME
])) {
399 double time
= parse_leasetime(c
);
406 INIT_LIST_HEAD(&l
->assignments
);
407 vlist_add(&leases
, &l
->node
, l
);
417 int config_parse_interface(void *data
, size_t len
, const char *name
, bool overwrite
)
419 struct interface
*iface
;
420 struct blob_attr
*tb
[IFACE_ATTR_MAX
], *c
;
421 bool get_addrs
= false;
423 blobmsg_parse(iface_attrs
, IFACE_ATTR_MAX
, tb
, data
, len
);
425 if (tb
[IFACE_ATTR_INTERFACE
])
426 name
= blobmsg_get_string(tb
[IFACE_ATTR_INTERFACE
]);
431 iface
= avl_find_element(&interfaces
, name
, iface
, avl
);
435 iface
= calloc_a(sizeof(*iface
), &new_name
, strlen(name
) + 1);
439 iface
->name
= strcpy(new_name
, name
);
440 iface
->avl
.key
= iface
->name
;
441 iface
->router_event
.uloop
.fd
= -1;
442 iface
->dhcpv6_event
.uloop
.fd
= -1;
443 iface
->ndp_event
.uloop
.fd
= -1;
444 iface
->ndp_ping_fd
= -1;
445 iface
->dhcpv4_event
.uloop
.fd
= -1;
446 INIT_LIST_HEAD(&iface
->ia_assignments
);
447 INIT_LIST_HEAD(&iface
->dhcpv4_assignments
);
448 INIT_LIST_HEAD(&iface
->dhcpv4_fr_ips
);
450 set_interface_defaults(iface
);
452 avl_insert(&interfaces
, &iface
->avl
);
453 get_addrs
= overwrite
= true;
456 const char *ifname
= NULL
;
458 if ((c
= tb
[IFACE_ATTR_IFNAME
]))
459 ifname
= blobmsg_get_string(c
);
460 else if ((c
= tb
[IFACE_ATTR_NETWORKID
]))
461 ifname
= blobmsg_get_string(c
);
465 if (overwrite
|| !iface
->ifname
)
466 ifname
= ubus_get_ifname(name
);
469 if (!iface
->ifname
&& !ifname
)
474 iface
->ifname
= strdup(ifname
);
479 if (!iface
->ifindex
&&
480 (iface
->ifindex
= if_nametoindex(iface
->ifname
)) <= 0)
485 ssize_t len
= netlink_get_interface_addrs(iface
->ifindex
,
486 true, &iface
->addr6
);
489 iface
->addr6_len
= len
;
491 len
= netlink_get_interface_addrs(iface
->ifindex
,
492 false, &iface
->addr4
);
494 iface
->addr4_len
= len
;
499 if ((c
= tb
[IFACE_ATTR_DYNAMICDHCP
]))
500 iface
->no_dynamic_dhcp
= !blobmsg_get_bool(c
);
502 if ((c
= tb
[IFACE_ATTR_LEASETIME
])) {
503 double time
= parse_leasetime(c
);
507 iface
->dhcpv4_leasetime
= time
;
510 if ((c
= tb
[IFACE_ATTR_START
])) {
511 iface
->dhcpv4_start
.s_addr
= htonl(blobmsg_get_u32(c
));
512 iface
->dhcpv4_end
.s_addr
= htonl(ntohl(iface
->dhcpv4_start
.s_addr
) +
515 if (config
.main_dhcpv4
&& config
.legacy
)
516 iface
->dhcpv4
= MODE_SERVER
;
519 if ((c
= tb
[IFACE_ATTR_LIMIT
]))
520 iface
->dhcpv4_end
.s_addr
= htonl(ntohl(iface
->dhcpv4_start
.s_addr
) +
521 blobmsg_get_u32(c
) - 1);
523 if ((c
= tb
[IFACE_ATTR_MASTER
]))
524 iface
->master
= blobmsg_get_bool(c
);
526 if (overwrite
&& (c
= tb
[IFACE_ATTR_UPSTREAM
])) {
527 struct blob_attr
*cur
;
530 blobmsg_for_each_attr(cur
, c
, rem
) {
531 if (blobmsg_type(cur
) != BLOBMSG_TYPE_STRING
|| !blobmsg_check_attr(cur
, false))
534 iface
->upstream
= realloc(iface
->upstream
,
535 iface
->upstream_len
+ blobmsg_data_len(cur
));
536 if (!iface
->upstream
)
539 memcpy(iface
->upstream
+ iface
->upstream_len
, blobmsg_get_string(cur
), blobmsg_data_len(cur
));
540 iface
->upstream_len
+= blobmsg_data_len(cur
);
545 if ((c
= tb
[IFACE_ATTR_RA
])) {
546 if ((mode
= parse_mode(blobmsg_get_string(c
))) >= 0) {
549 if (iface
->ra
!= MODE_DISABLED
)
550 iface
->ignore
= false;
555 if ((c
= tb
[IFACE_ATTR_DHCPV4
])) {
556 if ((mode
= parse_mode(blobmsg_get_string(c
))) >= 0) {
557 if (config
.main_dhcpv4
) {
558 iface
->dhcpv4
= mode
;
560 if (iface
->dhcpv4
!= MODE_DISABLED
)
561 iface
->ignore
= false;
568 if ((c
= tb
[IFACE_ATTR_DHCPV6
])) {
569 if ((mode
= parse_mode(blobmsg_get_string(c
))) >= 0) {
570 iface
->dhcpv6
= mode
;
572 if (iface
->dhcpv6
!= MODE_DISABLED
)
573 iface
->ignore
= false;
578 if ((c
= tb
[IFACE_ATTR_NDP
])) {
579 if ((mode
= parse_mode(blobmsg_get_string(c
))) >= 0) {
582 if (iface
->ndp
!= MODE_DISABLED
)
583 iface
->ignore
= false;
588 if ((c
= tb
[IFACE_ATTR_ROUTER
])) {
589 struct blob_attr
*cur
;
592 blobmsg_for_each_attr(cur
, c
, rem
) {
593 if (blobmsg_type(cur
) != BLOBMSG_TYPE_STRING
|| !blobmsg_check_attr(cur
, false))
596 struct in_addr addr4
;
597 if (inet_pton(AF_INET
, blobmsg_get_string(cur
), &addr4
) == 1) {
598 iface
->dhcpv4_router
= realloc(iface
->dhcpv4_router
,
599 (++iface
->dhcpv4_router_cnt
) * sizeof(*iface
->dhcpv4_router
));
600 if (!iface
->dhcpv4_router
)
603 iface
->dhcpv4_router
[iface
->dhcpv4_router_cnt
- 1] = addr4
;
609 if ((c
= tb
[IFACE_ATTR_DNS
])) {
610 struct blob_attr
*cur
;
613 iface
->always_rewrite_dns
= true;
614 blobmsg_for_each_attr(cur
, c
, rem
) {
615 if (blobmsg_type(cur
) != BLOBMSG_TYPE_STRING
|| !blobmsg_check_attr(cur
, false))
618 struct in_addr addr4
;
619 struct in6_addr addr6
;
620 if (inet_pton(AF_INET
, blobmsg_get_string(cur
), &addr4
) == 1) {
621 if (addr4
.s_addr
== INADDR_ANY
)
624 iface
->dhcpv4_dns
= realloc(iface
->dhcpv4_dns
,
625 (++iface
->dhcpv4_dns_cnt
) * sizeof(*iface
->dhcpv4_dns
));
626 if (!iface
->dhcpv4_dns
)
629 iface
->dhcpv4_dns
[iface
->dhcpv4_dns_cnt
- 1] = addr4
;
630 } else if (inet_pton(AF_INET6
, blobmsg_get_string(cur
), &addr6
) == 1) {
631 if (IN6_IS_ADDR_UNSPECIFIED(&addr6
))
634 iface
->dns
= realloc(iface
->dns
,
635 (++iface
->dns_cnt
) * sizeof(*iface
->dns
));
639 iface
->dns
[iface
->dns_cnt
- 1] = addr6
;
645 if ((c
= tb
[IFACE_ATTR_DOMAIN
])) {
646 struct blob_attr
*cur
;
649 blobmsg_for_each_attr(cur
, c
, rem
) {
650 if (blobmsg_type(cur
) != BLOBMSG_TYPE_STRING
|| !blobmsg_check_attr(cur
, false))
654 char *domain
= blobmsg_get_string(cur
);
655 size_t domainlen
= strlen(domain
);
656 if (domainlen
> 0 && domain
[domainlen
- 1] == '.')
657 domain
[domainlen
- 1] = 0;
659 int len
= dn_comp(domain
, buf
, sizeof(buf
), NULL
, NULL
);
663 iface
->search
= realloc(iface
->search
, iface
->search_len
+ len
);
667 memcpy(&iface
->search
[iface
->search_len
], buf
, len
);
668 iface
->search_len
+= len
;
672 if ((c
= tb
[IFACE_ATTR_FILTER_CLASS
])) {
673 iface
->filter_class
= realloc(iface
->filter_class
, blobmsg_data_len(c
) + 1);
674 memcpy(iface
->filter_class
, blobmsg_get_string(c
), blobmsg_data_len(c
) + 1);
677 if ((c
= tb
[IFACE_ATTR_DHCPV4_FORCERECONF
]))
678 iface
->dhcpv4_forcereconf
= blobmsg_get_bool(c
);
680 if ((c
= tb
[IFACE_ATTR_DHCPV6_RAW
])) {
681 iface
->dhcpv6_raw_len
= blobmsg_data_len(c
) / 2;
682 iface
->dhcpv6_raw
= realloc(iface
->dhcpv6_raw
, iface
->dhcpv6_raw_len
);
683 odhcpd_unhexlify(iface
->dhcpv6_raw
, iface
->dhcpv6_raw_len
, blobmsg_get_string(c
));
686 if ((c
= tb
[IFACE_ATTR_DHCPV6_ASSIGNALL
]))
687 iface
->dhcpv6_assignall
= blobmsg_get_bool(c
);
689 if ((c
= tb
[IFACE_ATTR_DHCPV6_PD
]))
690 iface
->dhcpv6_pd
= blobmsg_get_bool(c
);
692 if ((c
= tb
[IFACE_ATTR_DHCPV6_NA
]))
693 iface
->dhcpv6_na
= blobmsg_get_bool(c
);
695 if ((c
= tb
[IFACE_ATTR_RA_DEFAULT
]))
696 iface
->default_router
= blobmsg_get_u32(c
);
698 if ((c
= tb
[IFACE_ATTR_RA_MANAGEMENT
]))
699 iface
->ra_managed
= blobmsg_get_u32(c
);
701 if ((c
= tb
[IFACE_ATTR_RA_REACHABLETIME
])) {
702 uint32_t ra_reachabletime
= blobmsg_get_u32(c
);
703 if (ra_reachabletime
> 3600000)
706 iface
->ra_reachabletime
= ra_reachabletime
;
709 if ((c
= tb
[IFACE_ATTR_RA_RETRANSTIME
])) {
710 uint32_t ra_retranstime
= blobmsg_get_u32(c
);
711 if (ra_retranstime
> 60000)
714 iface
->ra_retranstime
= ra_retranstime
;
717 if ((c
= tb
[IFACE_ATTR_RA_HOPLIMIT
])) {
718 uint32_t ra_hoplimit
= blobmsg_get_u32(c
);
719 if (ra_hoplimit
> 255)
722 iface
->ra_hoplimit
= ra_hoplimit
;
725 if ((c
= tb
[IFACE_ATTR_RA_MTU
])) {
726 uint32_t ra_mtu
= blobmsg_get_u32(c
);
727 if (ra_mtu
< 1280 || ra_mtu
> 65535)
730 iface
->ra_mtu
= ra_mtu
;
733 if ((c
= tb
[IFACE_ATTR_RA_OFFLINK
]))
734 iface
->ra_not_onlink
= blobmsg_get_bool(c
);
736 if ((c
= tb
[IFACE_ATTR_RA_ADVROUTER
]))
737 iface
->ra_advrouter
= blobmsg_get_bool(c
);
739 if ((c
= tb
[IFACE_ATTR_RA_MININTERVAL
]))
740 iface
->ra_mininterval
= blobmsg_get_u32(c
);
742 if ((c
= tb
[IFACE_ATTR_RA_MAXINTERVAL
]))
743 iface
->ra_maxinterval
= blobmsg_get_u32(c
);
745 if ((c
= tb
[IFACE_ATTR_RA_LIFETIME
]))
746 iface
->ra_lifetime
= blobmsg_get_u32(c
);
748 if ((c
= tb
[IFACE_ATTR_RA_USELEASETIME
]))
749 iface
->ra_useleasetime
= blobmsg_get_bool(c
);
751 if ((c
= tb
[IFACE_ATTR_RA_DNS
]))
752 iface
->ra_dns
= blobmsg_get_bool(c
);
754 if ((c
= tb
[IFACE_ATTR_RA_PREFERENCE
])) {
755 const char *prio
= blobmsg_get_string(c
);
757 if (!strcmp(prio
, "high"))
758 iface
->route_preference
= 1;
759 else if (!strcmp(prio
, "low"))
760 iface
->route_preference
= -1;
761 else if (!strcmp(prio
, "medium") || !strcmp(prio
, "default"))
762 iface
->route_preference
= 0;
767 if ((c
= tb
[IFACE_ATTR_PD_MANAGER
]))
768 strncpy(iface
->dhcpv6_pd_manager
, blobmsg_get_string(c
),
769 sizeof(iface
->dhcpv6_pd_manager
) - 1);
771 if ((c
= tb
[IFACE_ATTR_PD_CER
]) &&
772 inet_pton(AF_INET6
, blobmsg_get_string(c
), &iface
->dhcpv6_pd_cer
) < 1)
775 if ((c
= tb
[IFACE_ATTR_NDPROXY_ROUTING
]))
776 iface
->learn_routes
= blobmsg_get_bool(c
);
778 if ((c
= tb
[IFACE_ATTR_NDPROXY_SLAVE
]))
779 iface
->external
= blobmsg_get_bool(c
);
781 if ((c
= tb
[IFACE_ATTR_PREFIX_FILTER
])) {
782 const char *str
= blobmsg_get_string(c
);
783 char *astr
= malloc(strlen(str
) + 1);
787 if (!astr
|| !strcpy(astr
, str
) ||
788 (delim
= strchr(astr
, '/')) == NULL
|| (*(delim
++) = 0) ||
789 sscanf(delim
, "%i", &l
) == 0 || l
> 128 ||
790 inet_pton(AF_INET6
, astr
, &iface
->pio_filter_addr
) == 0)
791 iface
->pio_filter_length
= 0;
793 iface
->pio_filter_length
= l
;
802 close_interface(iface
);
806 static int set_interface(struct uci_section
*s
)
808 blob_buf_init(&b
, 0);
809 uci_to_blob(&b
, s
, &interface_attr_list
);
811 return config_parse_interface(blob_data(b
.head
), blob_len(b
.head
), s
->e
.name
, true);
814 static void lease_delete_assignments(struct lease
*l
, bool v6
)
816 struct dhcp_assignment
*a
, *tmp
;
817 unsigned int flag
= v6
? OAF_DHCPV6
: OAF_DHCPV4
;
819 list_for_each_entry_safe(a
, tmp
, &l
->assignments
, lease_list
) {
825 static void lease_update_assignments(struct lease
*l
)
827 struct dhcp_assignment
*a
;
829 list_for_each_entry(a
, &l
->assignments
, lease_list
) {
835 a
->hostname
= strdup(l
->hostname
);
837 a
->leasetime
= l
->leasetime
;
841 static int lease_cmp(const void *k1
, const void *k2
, _unused
void *ptr
)
843 const struct lease
*l1
= k1
, *l2
= k2
;
846 if (l1
->duid_len
!= l2
->duid_len
)
847 return l1
->duid_len
- l2
->duid_len
;
849 if (l1
->duid_len
&& l2
->duid_len
)
850 cmp
= memcmp(l1
->duid
, l2
->duid
, l1
->duid_len
);
855 return memcmp(l1
->mac
.ether_addr_octet
, l2
->mac
.ether_addr_octet
,
856 sizeof(l1
->mac
.ether_addr_octet
));
859 static void lease_change_config(struct lease
*l_old
, struct lease
*l_new
)
863 if ((!!l_new
->hostname
!= !!l_old
->hostname
) ||
864 (l_new
->hostname
&& strcmp(l_new
->hostname
, l_old
->hostname
))) {
865 free(l_old
->hostname
);
866 l_old
->hostname
= NULL
;
869 l_old
->hostname
= strdup(l_new
->hostname
);
874 if (l_old
->leasetime
!= l_new
->leasetime
) {
875 l_old
->leasetime
= l_new
->leasetime
;
879 if (l_old
->ipaddr
!= l_new
->ipaddr
) {
880 l_old
->ipaddr
= l_new
->ipaddr
;
881 lease_delete_assignments(l_old
, false);
884 if (l_old
->hostid
!= l_new
->hostid
) {
885 l_old
->hostid
= l_new
->hostid
;
886 lease_delete_assignments(l_old
, true);
890 lease_update_assignments(l_old
);
895 static void lease_delete(struct lease
*l
)
897 struct dhcp_assignment
*a
, *tmp
;
899 list_for_each_entry_safe(a
, tmp
, &l
->assignments
, lease_list
)
905 static void lease_update(_unused
struct vlist_tree
*tree
, struct vlist_node
*node_new
,
906 struct vlist_node
*node_old
)
908 struct lease
*lease_new
= container_of(node_new
, struct lease
, node
);
909 struct lease
*lease_old
= container_of(node_old
, struct lease
, node
);
911 if (node_old
&& node_new
)
912 lease_change_config(lease_old
, lease_new
);
914 lease_delete(lease_old
);
917 struct lease
*config_find_lease_by_duid(const uint8_t *duid
, const uint16_t len
)
921 vlist_for_each_element(&leases
, l
, node
) {
922 if (l
->duid_len
== len
&& !memcmp(l
->duid
, duid
, len
))
929 struct lease
*config_find_lease_by_mac(const uint8_t *mac
)
933 vlist_for_each_element(&leases
, l
, node
) {
934 if (!memcmp(l
->mac
.ether_addr_octet
, mac
,
935 sizeof(l
->mac
.ether_addr_octet
)))
942 struct lease
*config_find_lease_by_hostid(const uint32_t hostid
)
946 vlist_for_each_element(&leases
, l
, node
) {
947 if (l
->hostid
== hostid
)
954 struct lease
*config_find_lease_by_ipaddr(const uint32_t ipaddr
)
958 vlist_for_each_element(&leases
, l
, node
) {
959 if (l
->ipaddr
== ipaddr
)
966 void odhcpd_reload(void)
968 struct uci_context
*uci
= uci_alloc_context();
969 struct interface
*master
= NULL
, *i
, *tmp
;
974 vlist_update(&leases
);
975 avl_for_each_element(&interfaces
, i
, avl
)
978 struct uci_package
*dhcp
= NULL
;
979 if (!uci_load(uci
, "dhcp", &dhcp
)) {
980 struct uci_element
*e
;
982 /* 1. Global settings */
983 uci_foreach_element(&dhcp
->sections
, e
) {
984 struct uci_section
*s
= uci_to_section(e
);
985 if (!strcmp(s
->type
, "odhcpd"))
990 uci_foreach_element(&dhcp
->sections
, e
) {
991 struct uci_section
*s
= uci_to_section(e
);
992 if (!strcmp(s
->type
, "dhcp"))
996 /* 3. Static leases */
997 uci_foreach_element(&dhcp
->sections
, e
) {
998 struct uci_section
* s
= uci_to_section(e
);
999 if (!strcmp(s
->type
, "host"))
1004 if (config
.dhcp_statefile
) {
1005 char *path
= strdup(config
.dhcp_statefile
);
1007 mkdir_p(dirname(path
), 0755);
1011 vlist_flush(&leases
);
1014 ubus_apply_network();
1017 bool any_dhcpv6_slave
= false, any_ra_slave
= false, any_ndp_slave
= false;
1020 avl_for_each_element(&interfaces
, i
, avl
) {
1024 if (i
->dhcpv6
== MODE_HYBRID
|| i
->dhcpv6
== MODE_RELAY
)
1025 any_dhcpv6_slave
= true;
1027 if (i
->ra
== MODE_HYBRID
|| i
->ra
== MODE_RELAY
)
1028 any_ra_slave
= true;
1030 if (i
->ndp
== MODE_HYBRID
|| i
->ndp
== MODE_RELAY
)
1031 any_ndp_slave
= true;
1034 /* Evaluate hybrid mode for master */
1035 avl_for_each_element(&interfaces
, i
, avl
) {
1039 enum odhcpd_mode hybrid_mode
= MODE_DISABLED
;
1041 if (!ubus_has_prefix(i
->name
, i
->ifname
))
1042 hybrid_mode
= MODE_RELAY
;
1045 if (i
->dhcpv6
== MODE_HYBRID
)
1046 i
->dhcpv6
= hybrid_mode
;
1048 if (i
->dhcpv6
== MODE_RELAY
&& !any_dhcpv6_slave
)
1049 i
->dhcpv6
= MODE_DISABLED
;
1051 if (i
->ra
== MODE_HYBRID
)
1052 i
->ra
= hybrid_mode
;
1054 if (i
->ra
== MODE_RELAY
&& !any_ra_slave
)
1055 i
->ra
= MODE_DISABLED
;
1057 if (i
->ndp
== MODE_HYBRID
)
1058 i
->ndp
= hybrid_mode
;
1060 if (i
->ndp
== MODE_RELAY
&& !any_ndp_slave
)
1061 i
->ndp
= MODE_DISABLED
;
1063 if (i
->dhcpv6
== MODE_RELAY
|| i
->ra
== MODE_RELAY
|| i
->ndp
== MODE_RELAY
)
1068 avl_for_each_element_safe(&interfaces
, i
, avl
, tmp
) {
1070 /* Resolve hybrid mode */
1071 if (i
->dhcpv6
== MODE_HYBRID
)
1072 i
->dhcpv6
= (master
&& master
->dhcpv6
== MODE_RELAY
) ?
1073 MODE_RELAY
: MODE_SERVER
;
1075 if (i
->ra
== MODE_HYBRID
)
1076 i
->ra
= (master
&& master
->ra
== MODE_RELAY
) ?
1077 MODE_RELAY
: MODE_SERVER
;
1079 if (i
->ndp
== MODE_HYBRID
)
1080 i
->ndp
= (master
&& master
->ndp
== MODE_RELAY
) ?
1081 MODE_RELAY
: MODE_DISABLED
;
1083 router_setup_interface(i
, i
->ra
!= MODE_DISABLED
);
1084 dhcpv6_setup_interface(i
, i
->dhcpv6
!= MODE_DISABLED
);
1085 ndp_setup_interface(i
, i
->ndp
!= MODE_DISABLED
);
1086 #ifdef DHCPV4_SUPPORT
1087 dhcpv4_setup_interface(i
, i
->dhcpv4
!= MODE_DISABLED
);
1093 uci_unload(uci
, dhcp
);
1094 uci_free_context(uci
);
1097 static void handle_signal(int signal
)
1101 if (signal
== SIGHUP
) {
1102 if (write(reload_pipe
[1], b
, sizeof(b
)) < 0) {}
1107 static void reload_cb(struct uloop_fd
*u
, _unused
unsigned int events
)
1110 if (read(u
->fd
, b
, sizeof(b
)) < 0) {}
1115 static struct uloop_fd reload_fd
= { .fd
= -1, .cb
= reload_cb
};
1117 void odhcpd_run(void)
1119 if (pipe2(reload_pipe
, O_NONBLOCK
| O_CLOEXEC
) < 0) {}
1121 reload_fd
.fd
= reload_pipe
[0];
1122 uloop_fd_add(&reload_fd
, ULOOP_READ
);
1124 signal(SIGTERM
, handle_signal
);
1125 signal(SIGINT
, handle_signal
);
1126 signal(SIGHUP
, handle_signal
);