X-Git-Url: http://git.archive.openwrt.org/?p=project%2Fodhcpd.git;a=blobdiff_plain;f=src%2Fconfig.c;h=7d870f129b27047a8eb8bb57c805908aee3f842f;hp=06e54072546efa0b949f7b8993b0f2d96a5a011c;hb=d0ca3022a4041e7232587b024ebfaadbe2c095cc;hpb=05969d06380387fc6d093e80b142145c2a9c2293 diff --git a/src/config.c b/src/config.c index 06e5407..7d870f1 100644 --- a/src/config.c +++ b/src/config.c @@ -30,16 +30,21 @@ enum { IFACE_ATTR_DHCPV4, IFACE_ATTR_DHCPV6, IFACE_ATTR_NDP, + IFACE_ATTR_ROUTER, IFACE_ATTR_DNS, IFACE_ATTR_DOMAIN, - IFACE_ATTR_ULA_COMPAT, + IFACE_ATTR_FILTER_CLASS, + IFACE_ATTR_DHCPV6_RAW, IFACE_ATTR_RA_DEFAULT, IFACE_ATTR_RA_MANAGEMENT, IFACE_ATTR_RA_OFFLINK, IFACE_ATTR_RA_PREFERENCE, + IFACE_ATTR_RA_ADVROUTER, + IFACE_ATTR_RA_MAXINTERVAL, + IFACE_ATTR_PD_MANAGER, + IFACE_ATTR_PD_CER, IFACE_ATTR_NDPROXY_ROUTING, IFACE_ATTR_NDPROXY_SLAVE, - IFACE_ATTR_NDPROXY_STATIC, IFACE_ATTR_MAX }; @@ -58,23 +63,27 @@ static const struct blobmsg_policy iface_attrs[IFACE_ATTR_MAX] = { [IFACE_ATTR_DHCPV4] = { .name = "dhcpv4", .type = BLOBMSG_TYPE_STRING }, [IFACE_ATTR_DHCPV6] = { .name = "dhcpv6", .type = BLOBMSG_TYPE_STRING }, [IFACE_ATTR_NDP] = { .name = "ndp", .type = BLOBMSG_TYPE_STRING }, + [IFACE_ATTR_ROUTER] = { .name = "router", .type = BLOBMSG_TYPE_ARRAY }, [IFACE_ATTR_DNS] = { .name = "dns", .type = BLOBMSG_TYPE_ARRAY }, [IFACE_ATTR_DOMAIN] = { .name = "domain", .type = BLOBMSG_TYPE_ARRAY }, - [IFACE_ATTR_ULA_COMPAT] = { .name = "ula_compat", .type = BLOBMSG_TYPE_BOOL }, + [IFACE_ATTR_FILTER_CLASS] = { .name = "filter_class", .type = BLOBMSG_TYPE_STRING }, + [IFACE_ATTR_DHCPV6_RAW] = { .name = "dhcpv6_raw", .type = BLOBMSG_TYPE_STRING }, + [IFACE_ATTR_PD_MANAGER] = { .name = "pd_manager", .type = BLOBMSG_TYPE_STRING }, + [IFACE_ATTR_PD_CER] = { .name = "pd_cer", .type = BLOBMSG_TYPE_STRING }, [IFACE_ATTR_RA_DEFAULT] = { .name = "ra_default", .type = BLOBMSG_TYPE_INT32 }, [IFACE_ATTR_RA_MANAGEMENT] = { .name = "ra_management", .type = BLOBMSG_TYPE_INT32 }, [IFACE_ATTR_RA_OFFLINK] = { .name = "ra_offlink", .type = BLOBMSG_TYPE_BOOL }, [IFACE_ATTR_RA_PREFERENCE] = { .name = "ra_preference", .type = BLOBMSG_TYPE_STRING }, + [IFACE_ATTR_RA_ADVROUTER] = { .name = "ra_advrouter", .type = BLOBMSG_TYPE_BOOL }, + [IFACE_ATTR_RA_MAXINTERVAL] = { .name = "ra_maxinterval", .type = BLOBMSG_TYPE_INT32 }, [IFACE_ATTR_NDPROXY_ROUTING] = { .name = "ndproxy_routing", .type = BLOBMSG_TYPE_BOOL }, [IFACE_ATTR_NDPROXY_SLAVE] = { .name = "ndproxy_slave", .type = BLOBMSG_TYPE_BOOL }, - [IFACE_ATTR_NDPROXY_STATIC] = { .name = "ndproxy_static", .type = BLOBMSG_TYPE_ARRAY }, }; static const struct uci_blob_param_info iface_attr_info[IFACE_ATTR_MAX] = { [IFACE_ATTR_UPSTREAM] = { .type = BLOBMSG_TYPE_STRING }, [IFACE_ATTR_DNS] = { .type = BLOBMSG_TYPE_STRING }, [IFACE_ATTR_DOMAIN] = { .type = BLOBMSG_TYPE_STRING }, - [IFACE_ATTR_NDPROXY_STATIC] = { .type = BLOBMSG_TYPE_STRING }, }; const struct uci_blob_param_list interface_attr_list = { @@ -89,7 +98,7 @@ enum { LEASE_ATTR_MAC, LEASE_ATTR_DUID, LEASE_ATTR_HOSTID, - LEASE_ATTR_HOSTNAME, + LEASE_ATTR_NAME, LEASE_ATTR_MAX }; @@ -99,7 +108,7 @@ static const struct blobmsg_policy lease_attrs[LEASE_ATTR_MAX] = { [LEASE_ATTR_MAC] = { .name = "mac", .type = BLOBMSG_TYPE_STRING }, [LEASE_ATTR_DUID] = { .name = "duid", .type = BLOBMSG_TYPE_STRING }, [LEASE_ATTR_HOSTID] = { .name = "hostid", .type = BLOBMSG_TYPE_STRING }, - [LEASE_ATTR_HOSTNAME] = { .name = "hostname", .type = BLOBMSG_TYPE_STRING }, + [LEASE_ATTR_NAME] = { .name = "name", .type = BLOBMSG_TYPE_STRING }, }; @@ -110,7 +119,7 @@ const struct uci_blob_param_list lease_attr_list = { enum { - ODHCPD_ATTR_LEGACY, + ODHCPD_ATTR_MAINDHCP, ODHCPD_ATTR_LEASEFILE, ODHCPD_ATTR_LEASETRIGGER, ODHCPD_ATTR_MAX @@ -118,7 +127,7 @@ enum { static const struct blobmsg_policy odhcpd_attrs[LEASE_ATTR_MAX] = { - [ODHCPD_ATTR_LEGACY] = { .name = "legacy", .type = BLOBMSG_TYPE_BOOL }, + [ODHCPD_ATTR_MAINDHCP] = { .name = "maindhcp", .type = BLOBMSG_TYPE_BOOL }, [ODHCPD_ATTR_LEASEFILE] = { .name = "leasefile", .type = BLOBMSG_TYPE_STRING }, [ODHCPD_ATTR_LEASETRIGGER] = { .name = "leasetrigger", .type = BLOBMSG_TYPE_STRING }, }; @@ -145,8 +154,10 @@ static void clean_interface(struct interface *iface) free(iface->dns); free(iface->search); free(iface->upstream); - free(iface->static_ndp); + free(iface->dhcpv4_router); free(iface->dhcpv4_dns); + free(iface->dhcpv6_raw); + free(iface->filter_class); memset(&iface->ra, 0, sizeof(*iface) - offsetof(struct interface, ra)); } @@ -187,10 +198,10 @@ static void set_config(struct uci_section *s) struct blob_attr *tb[ODHCPD_ATTR_MAX], *c; blob_buf_init(&b, 0); - uci_to_blob(&b, s, &lease_attr_list); - blobmsg_parse(lease_attrs, ODHCPD_ATTR_MAX, tb, blob_data(b.head), blob_len(b.head)); + uci_to_blob(&b, s, &odhcpd_attr_list); + blobmsg_parse(odhcpd_attrs, ODHCPD_ATTR_MAX, tb, blob_data(b.head), blob_len(b.head)); - if ((c = tb[ODHCPD_ATTR_LEGACY])) + if ((c = tb[ODHCPD_ATTR_MAINDHCP])) config.legacy = blobmsg_get_bool(c); if ((c = tb[ODHCPD_ATTR_LEASEFILE])) { @@ -214,10 +225,12 @@ static int set_lease(struct uci_section *s) blobmsg_parse(lease_attrs, LEASE_ATTR_MAX, tb, blob_data(b.head), blob_len(b.head)); size_t hostlen = 1; - if ((c = tb[LEASE_ATTR_HOSTNAME])) + if ((c = tb[LEASE_ATTR_NAME])) hostlen = blobmsg_data_len(c); struct lease *lease = calloc(1, sizeof(*lease) + hostlen); + if (!lease) + goto err; if (hostlen > 1) memcpy(lease->hostname, blobmsg_get_string(c), hostlen); @@ -233,6 +246,9 @@ static int set_lease(struct uci_section *s) if ((c = tb[LEASE_ATTR_DUID])) { size_t duidlen = (blobmsg_data_len(c) - 1) / 2; lease->duid = malloc(duidlen); + if (!lease->duid) + goto err; + ssize_t len = odhcpd_unhexlify(lease->duid, duidlen, blobmsg_get_string(c)); @@ -242,17 +258,21 @@ static int set_lease(struct uci_section *s) lease->duid_len = len; } - if ((c = tb[LEASE_ATTR_HOSTID])) - if (odhcpd_unhexlify((uint8_t*)&lease->hostid, sizeof(lease->hostid), - blobmsg_get_string(c)) < 0) + if ((c = tb[LEASE_ATTR_HOSTID])) { + errno = 0; + lease->hostid = strtoul(blobmsg_get_string(c), NULL, 16); + if (errno) goto err; + } list_add(&lease->head, &leases); return 0; err: - free(lease->duid); - free(lease); + if (lease) { + free(lease->duid); + free(lease); + } return -1; } @@ -271,10 +291,12 @@ int config_parse_interface(void *data, size_t len, const char *name, bool overwr struct interface *iface = get_interface(name); if (!iface) { iface = calloc(1, sizeof(*iface)); + if (!iface) + return -1; + strncpy(iface->name, name, sizeof(iface->name) - 1); list_add(&iface->head, &interfaces); - } else if (overwrite) { - clean_interface(iface); + overwrite = true; } const char *ifname = NULL; @@ -296,10 +318,10 @@ int config_parse_interface(void *data, size_t len, const char *name, bool overwr if (ifname) strncpy(iface->ifname, ifname, sizeof(iface->ifname) - 1); - iface->inuse = true; + if ((iface->ifindex = if_nametoindex(iface->ifname)) <= 0) + return -1; - if (overwrite) - clean_interface(iface); + iface->inuse = true; if ((c = tb[IFACE_ATTR_DYNAMICDHCP])) iface->no_dynamic_dhcp = !blobmsg_get_bool(c); @@ -353,6 +375,9 @@ int config_parse_interface(void *data, size_t len, const char *name, bool overwr iface->upstream = realloc(iface->upstream, iface->upstream_len + blobmsg_data_len(cur)); + if (!iface->upstream) + goto err; + memcpy(iface->upstream + iface->upstream_len, blobmsg_get_string(cur), blobmsg_data_len(cur)); iface->upstream_len += blobmsg_data_len(cur); } @@ -387,6 +412,28 @@ int config_parse_interface(void *data, size_t len, const char *name, bool overwr goto err; } + if ((c = tb[IFACE_ATTR_ROUTER])) { + struct blob_attr *cur; + unsigned rem; + + blobmsg_for_each_attr(cur, c, rem) { + if (blobmsg_type(cur) != BLOBMSG_TYPE_STRING || !blobmsg_check_attr(cur, NULL)) + continue; + + struct in_addr addr4; + if (inet_pton(AF_INET, blobmsg_get_string(cur), &addr4) == 1) { + iface->dhcpv4_router = realloc(iface->dhcpv4_router, + (++iface->dhcpv4_router_cnt) * sizeof(*iface->dhcpv4_router)); + if (!iface->dhcpv4_router) + goto err; + + iface->dhcpv4_router[iface->dhcpv4_router_cnt - 1] = addr4; + } else { + goto err; + } + } + } + if ((c = tb[IFACE_ATTR_DNS])) { struct blob_attr *cur; unsigned rem; @@ -401,10 +448,16 @@ int config_parse_interface(void *data, size_t len, const char *name, bool overwr if (inet_pton(AF_INET, blobmsg_get_string(cur), &addr4) == 1) { iface->dhcpv4_dns = realloc(iface->dhcpv4_dns, (++iface->dhcpv4_dns_cnt) * sizeof(*iface->dhcpv4_dns)); + if (!iface->dhcpv4_dns) + goto err; + iface->dhcpv4_dns[iface->dhcpv4_dns_cnt - 1] = addr4; } else if (inet_pton(AF_INET6, blobmsg_get_string(cur), &addr6) == 1) { iface->dns = realloc(iface->dns, (++iface->dns_cnt) * sizeof(*iface->dns)); + if (!iface->dns) + goto err; + iface->dns[iface->dns_cnt - 1] = addr6; } else { goto err; @@ -421,28 +474,52 @@ int config_parse_interface(void *data, size_t len, const char *name, bool overwr continue; uint8_t buf[256]; - int len = dn_comp(blobmsg_get_string(cur), buf, sizeof(buf), NULL, NULL); + char *domain = blobmsg_get_string(cur); + size_t domainlen = strlen(domain); + if (domainlen > 0 && domain[domainlen - 1] == '.') + domain[domainlen - 1] = 0; + + int len = dn_comp(domain, buf, sizeof(buf), NULL, NULL); if (len <= 0) goto err; iface->search = realloc(iface->search, iface->search_len + len); + if (!iface->search) + goto err; + memcpy(&iface->search[iface->search_len], buf, len); iface->search_len += len; } } - if ((c = tb[IFACE_ATTR_ULA_COMPAT])) - iface->deprecate_ula_if_public_avail = blobmsg_get_bool(c); + if ((c = tb[IFACE_ATTR_FILTER_CLASS])) { + iface->filter_class = realloc(iface->filter_class, blobmsg_data_len(c) + 1); + memcpy(iface->filter_class, blobmsg_get_string(c), blobmsg_data_len(c) + 1); + } + + if ((c = tb[IFACE_ATTR_DHCPV6_RAW])) { + iface->dhcpv6_raw_len = blobmsg_data_len(c) / 2; + iface->dhcpv6_raw = realloc(iface->dhcpv6_raw, iface->dhcpv6_raw_len); + odhcpd_unhexlify(iface->dhcpv6_raw, iface->dhcpv6_raw_len, blobmsg_get_string(c)); + } if ((c = tb[IFACE_ATTR_RA_DEFAULT])) iface->default_router = blobmsg_get_u32(c); if ((c = tb[IFACE_ATTR_RA_MANAGEMENT])) iface->managed = blobmsg_get_u32(c); + else if (overwrite) + iface->managed = 1; if ((c = tb[IFACE_ATTR_RA_OFFLINK])) iface->ra_not_onlink = blobmsg_get_bool(c); + if ((c = tb[IFACE_ATTR_RA_ADVROUTER])) + iface->ra_advrouter = blobmsg_get_bool(c); + + if ((c = tb[IFACE_ATTR_RA_MAXINTERVAL])) + iface->ra_maxinterval = blobmsg_get_u32(c); + if ((c = tb[IFACE_ATTR_RA_PREFERENCE])) { const char *prio = blobmsg_get_string(c); @@ -456,28 +533,22 @@ int config_parse_interface(void *data, size_t len, const char *name, bool overwr goto err; } + if ((c = tb[IFACE_ATTR_PD_MANAGER])) + strncpy(iface->dhcpv6_pd_manager, blobmsg_get_string(c), + sizeof(iface->dhcpv6_pd_manager) - 1); + + if ((c = tb[IFACE_ATTR_PD_CER]) && + inet_pton(AF_INET6, blobmsg_get_string(c), &iface->dhcpv6_pd_cer) < 1) + goto err; + if ((c = tb[IFACE_ATTR_NDPROXY_ROUTING])) iface->learn_routes = blobmsg_get_bool(c); + else if (overwrite) + iface->learn_routes = true; if ((c = tb[IFACE_ATTR_NDPROXY_SLAVE])) iface->external = blobmsg_get_bool(c); - if ((c = tb[IFACE_ATTR_NDPROXY_STATIC])) { - struct blob_attr *cur; - unsigned rem; - - blobmsg_for_each_attr(cur, c, rem) { - if (blobmsg_type(cur) != BLOBMSG_TYPE_STRING || !blobmsg_check_attr(cur, NULL)) - continue; - - int len = blobmsg_data_len(cur); - iface->static_ndp = realloc(iface->static_ndp, iface->static_ndp_len + len); - memcpy(&iface->static_ndp[iface->static_ndp_len], blobmsg_get_string(cur), len); - iface->static_ndp_len += len; - } - } - - iface->ignore = (iface->ifindex = if_nametoindex(iface->ifname)) < 0; return 0; err: @@ -496,19 +567,27 @@ static int set_interface(struct uci_section *s) void odhcpd_reload(void) { struct uci_context *uci = uci_alloc_context(); - struct lease *l; - list_for_each_entry(l, &leases, head) { + while (!list_empty(&leases)) { + struct lease *l = list_first_entry(&leases, struct lease, head); list_del(&l->head); free(l->duid); free(l); } + struct interface *master = NULL, *i, *n; + + if (!uci) + return; + + list_for_each_entry(i, &interfaces, head) + clean_interface(i); + struct uci_package *dhcp = NULL; if (!uci_load(uci, "dhcp", &dhcp)) { struct uci_element *e; uci_foreach_element(&dhcp->sections, e) { struct uci_section *s = uci_to_section(e); - if (!strcmp(s->type, "lease")) + if (!strcmp(s->type, "host")) set_lease(s); else if (!strcmp(s->type, "odhcpd")) set_config(s); @@ -521,31 +600,57 @@ void odhcpd_reload(void) } } + #ifdef WITH_UBUS ubus_apply_network(); #endif + bool any_dhcpv6_slave = false, any_ra_slave = false, any_ndp_slave = false; + + // Test for + list_for_each_entry(i, &interfaces, head) { + if (i->master) + continue; + + if (i->dhcpv6 == RELAYD_HYBRID || i->dhcpv6 == RELAYD_RELAY) + any_dhcpv6_slave = true; + + if (i->ra == RELAYD_HYBRID || i->ra == RELAYD_RELAY) + any_ra_slave = true; + + if (i->ndp == RELAYD_HYBRID || i->ndp == RELAYD_RELAY) + any_ndp_slave = true; + } + // Evaluate hybrid mode for master - struct interface *master = NULL, *i, *n; list_for_each_entry(i, &interfaces, head) { if (!i->master) continue; enum odhcpd_mode hybrid_mode = RELAYD_DISABLED; #ifdef WITH_UBUS - if (ubus_has_prefix(i->name, i->ifname)) + if (!ubus_has_prefix(i->name, i->ifname)) hybrid_mode = RELAYD_RELAY; #endif if (i->dhcpv6 == RELAYD_HYBRID) i->dhcpv6 = hybrid_mode; + if (i->dhcpv6 == RELAYD_RELAY && !any_dhcpv6_slave) + i->dhcpv6 = RELAYD_DISABLED; + if (i->ra == RELAYD_HYBRID) i->ra = hybrid_mode; + if (i->ra == RELAYD_RELAY && !any_ra_slave) + i->ra = RELAYD_DISABLED; + if (i->ndp == RELAYD_HYBRID) i->ndp = hybrid_mode; + if (i->ndp == RELAYD_RELAY && !any_ndp_slave) + i->ndp = RELAYD_DISABLED; + if (i->dhcpv6 == RELAYD_RELAY || i->ra == RELAYD_RELAY || i->ndp == RELAYD_RELAY) master = i; } @@ -564,13 +669,12 @@ void odhcpd_reload(void) if (i->ndp == RELAYD_HYBRID) i->ndp = (master && master->ndp == RELAYD_RELAY) ? - RELAYD_RELAY : RELAYD_SERVER; + RELAYD_RELAY : RELAYD_DISABLED; setup_router_interface(i, true); setup_dhcpv6_interface(i, true); setup_ndp_interface(i, true); setup_dhcpv4_interface(i, true); - i->inuse = false; } else { close_interface(i); } @@ -584,9 +688,10 @@ void odhcpd_reload(void) static void handle_signal(int signal) { char b[1] = {0}; - if (signal == SIGHUP) - write(reload_pipe[1], b, sizeof(b)); - else + + if (signal == SIGHUP) { + if (write(reload_pipe[1], b, sizeof(b)) < 0) {} + } else uloop_end(); } @@ -595,7 +700,7 @@ static void handle_signal(int signal) static void reload_cb(struct uloop_fd *u, _unused unsigned int events) { char b[512]; - read(u->fd, b, sizeof(b)); + if (read(u->fd, b, sizeof(b)) < 0) {} odhcpd_reload(); } @@ -603,7 +708,7 @@ static struct uloop_fd reload_fd = { .cb = reload_cb }; void odhcpd_run(void) { - pipe2(reload_pipe, O_NONBLOCK | O_CLOEXEC); + if (pipe2(reload_pipe, O_NONBLOCK | O_CLOEXEC) < 0) {} reload_fd.fd = reload_pipe[0]; uloop_fd_add(&reload_fd, ULOOP_READ); @@ -612,10 +717,14 @@ void odhcpd_run(void) signal(SIGHUP, handle_signal); #ifdef WITH_UBUS - init_ubus(); + while (init_ubus()) + sleep(1); #endif odhcpd_reload(); uloop_run(); + + while (!list_empty(&interfaces)) + close_interface(list_first_entry(&interfaces, struct interface, head)); }