#define START_DEFAULT 100
#define LIMIT_DEFAULT 150
+#define HOSTID_LEN_MIN 12
+#define HOSTID_LEN_MAX 64
+#define HOSTID_LEN_DEFAULT HOSTID_LEN_MIN
+
#define OAF_DHCPV6 (OAF_DHCPV6_NA | OAF_DHCPV6_PD)
enum {
IFACE_ATTR_DHCPV6_ASSIGNALL,
IFACE_ATTR_DHCPV6_PD,
IFACE_ATTR_DHCPV6_NA,
+ IFACE_ATTR_DHCPV6_HOSTID_LEN,
IFACE_ATTR_RA_DEFAULT,
IFACE_ATTR_RA_MANAGEMENT,
IFACE_ATTR_RA_FLAGS,
IFACE_ATTR_NDPROXY_SLAVE,
IFACE_ATTR_PREFIX_FILTER,
IFACE_ATTR_PREFERRED_LIFETIME,
+ IFACE_ATTR_NTP,
IFACE_ATTR_MAX
};
[IFACE_ATTR_DHCPV6_ASSIGNALL] = { .name ="dhcpv6_assignall", .type = BLOBMSG_TYPE_BOOL },
[IFACE_ATTR_DHCPV6_PD] = { .name = "dhcpv6_pd", .type = BLOBMSG_TYPE_BOOL },
[IFACE_ATTR_DHCPV6_NA] = { .name = "dhcpv6_na", .type = BLOBMSG_TYPE_BOOL },
+ [IFACE_ATTR_DHCPV6_HOSTID_LEN] = { .name = "dhcpv6_hostidlength", .type = BLOBMSG_TYPE_INT32 },
[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_NDPROXY_SLAVE] = { .name = "ndproxy_slave", .type = BLOBMSG_TYPE_BOOL },
[IFACE_ATTR_PREFIX_FILTER] = { .name = "prefix_filter", .type = BLOBMSG_TYPE_STRING },
[IFACE_ATTR_PREFERRED_LIFETIME] = { .name = "preferred_lifetime", .type = BLOBMSG_TYPE_STRING },
+ [IFACE_ATTR_NTP] = { .name = "ntp", .type = BLOBMSG_TYPE_ARRAY },
};
static const struct uci_blob_param_info iface_attr_info[IFACE_ATTR_MAX] = {
iface->dhcpv6_assignall = true;
iface->dhcpv6_pd = true;
iface->dhcpv6_na = true;
+ iface->dhcpv6_hostid_len = HOSTID_LEN_DEFAULT;
iface->dns_service = true;
iface->ra_flags = ND_RA_FLAG_OTHER;
iface->ra_slaac = true;
free(iface->dhcpv4_dns);
free(iface->dhcpv6_raw);
free(iface->filter_class);
+ free(iface->dhcpv4_ntp);
+ free(iface->dhcpv6_ntp);
+ free(iface->dhcpv6_sntp);
memset(&iface->ra, 0, sizeof(*iface) - offsetof(struct interface, ra));
set_interface_defaults(iface);
}
clean_interface(iface);
free(iface->addr4);
free(iface->addr6);
+ free(iface->invalid_addr6);
free(iface->ifname);
free(iface);
}
if ((c = tb[LEASE_ATTR_HOSTID])) {
errno = 0;
- l->hostid = strtoul(blobmsg_get_string(c), NULL, 16);
+ l->hostid = strtoull(blobmsg_get_string(c), NULL, 16);
if (errno)
goto err;
} else {
return set_lease_from_blobmsg(b.head);
}
+/* Parse NTP Options for DHCPv6 Address */
+static int parse_ntp_options(uint16_t *dhcpv6_ntp_len, struct in6_addr addr6, uint8_t **dhcpv6_ntp)
+{
+ uint16_t sub_opt = 0, sub_len = htons(IPV6_ADDR_LEN);
+ uint16_t ntp_len = IPV6_ADDR_LEN + 4;
+ uint8_t *ntp = *dhcpv6_ntp;
+ size_t pos = *dhcpv6_ntp_len;
+
+ ntp = realloc(ntp, pos + ntp_len);
+ if (!ntp)
+ return -1;
+
+ *dhcpv6_ntp = ntp;
+
+ if (IN6_IS_ADDR_MULTICAST(&addr6))
+ sub_opt = htons(NTP_SUBOPTION_MC_ADDR);
+ else
+ sub_opt = htons(NTP_SUBOPTION_SRV_ADDR);
+
+ memcpy(ntp + pos, &sub_opt, sizeof(sub_opt));
+ pos += sizeof(sub_opt);
+ memcpy(ntp + pos, &sub_len, sizeof(sub_len));
+ pos += sizeof(sub_len);
+ memcpy(ntp + pos, &addr6, IPV6_ADDR_LEN);
+
+ *dhcpv6_ntp_len += ntp_len;
+
+ return 0;
+}
+
+/* Parse NTP Options for FQDN */
+static int parse_ntp_fqdn(uint16_t *dhcpv6_ntp_len, char *fqdn, uint8_t **dhcpv6_ntp)
+{
+ size_t fqdn_len = strlen(fqdn);
+ uint16_t sub_opt = 0, sub_len = 0, ntp_len = 0;
+ uint8_t *ntp = *dhcpv6_ntp;
+ size_t pos = *dhcpv6_ntp_len;
+ uint8_t buf[256] = {0};
+
+ if (fqdn_len > 0 && fqdn[fqdn_len - 1] == '.')
+ fqdn[fqdn_len - 1] = 0;
+
+ int len = dn_comp(fqdn, buf, sizeof(buf), NULL, NULL);
+ if (len <= 0)
+ return -1;
+
+ ntp_len = len + 4;
+
+ ntp = realloc(ntp, pos + ntp_len);
+ if (!ntp)
+ return -1;
+
+ *dhcpv6_ntp = ntp;
+
+ sub_opt = htons(NTP_SUBOPTION_SRV_FQDN);
+ sub_len = htons(len);
+
+ memcpy(ntp + pos, &sub_opt, sizeof(sub_opt));
+ pos += sizeof(sub_opt);
+ memcpy(ntp + pos, &sub_len, sizeof(sub_len));
+ pos += sizeof(sub_len);
+ memcpy(ntp + pos, buf, len);
+
+ *dhcpv6_ntp_len += ntp_len;
+
+ return 0;
+}
+
int config_parse_interface(void *data, size_t len, const char *name, bool overwrite)
{
struct interface *iface;
if (!iface->ifindex &&
(iface->ifindex = if_nametoindex(iface->ifname)) <= 0)
goto err;
+
+ if ((iface->ifflags = odhcpd_get_flags(iface)) < 0)
+ goto err;
}
if (get_addrs) {
iface->addr4_len = len;
}
+ for (size_t i = 0; i < iface->addr6_len; i++) {
+ struct odhcpd_ipaddr *addr = &iface->addr6[i];
+
+ if (!addr->tentative) {
+ iface->have_link_local = true;
+ break;
+ }
+ }
+
iface->inuse = true;
if ((c = tb[IFACE_ATTR_DYNAMICDHCP]))
if ((c = tb[IFACE_ATTR_DHCPV6_NA]))
iface->dhcpv6_na = blobmsg_get_bool(c);
+ if ((c = tb[IFACE_ATTR_DHCPV6_HOSTID_LEN])) {
+ uint32_t hostid_len = blobmsg_get_u32(c);
+
+ if (hostid_len >= HOSTID_LEN_MIN && hostid_len <= HOSTID_LEN_MAX)
+ iface->dhcpv6_hostid_len = hostid_len;
+ else
+ syslog(LOG_ERR, "Invalid %s value configured for interface '%s'",
+ iface_attrs[IFACE_ATTR_DHCPV6_HOSTID_LEN].name, iface->name);
+
+ }
+
if ((c = tb[IFACE_ATTR_RA_DEFAULT]))
iface->default_router = blobmsg_get_u32(c);
}
if ((c = tb[IFACE_ATTR_RA_FLAGS])) {
+ iface->ra_flags = 0;
+
if (parse_ra_flags(&iface->ra_flags, c) < 0)
syslog(LOG_ERR, "Invalid %s value configured for interface '%s'",
iface_attrs[IFACE_ATTR_RA_FLAGS].name, iface->name);
free(astr);
}
+ if (overwrite && (c = tb[IFACE_ATTR_NTP])) {
+ struct blob_attr *cur;
+ unsigned rem;
+
+ blobmsg_for_each_attr(cur, c, rem) {
+ if (blobmsg_type(cur) != BLOBMSG_TYPE_STRING || !blobmsg_check_attr(cur, false))
+ continue;
+
+ char *str = blobmsg_get_string(cur);
+ struct in_addr addr4;
+ struct in6_addr addr6;
+
+ if (inet_pton(AF_INET, str, &addr4) == 1) {
+ if (addr4.s_addr == INADDR_ANY)
+ goto err;
+
+ iface->dhcpv4_ntp = realloc(iface->dhcpv4_ntp,
+ (++iface->dhcpv4_ntp_cnt) * sizeof(*iface->dhcpv4_ntp));
+ if (!iface->dhcpv4_ntp)
+ goto err;
+
+ iface->dhcpv4_ntp[iface->dhcpv4_ntp_cnt - 1] = addr4;
+ } else if (inet_pton(AF_INET6, str, &addr6) == 1) {
+ if (IN6_IS_ADDR_UNSPECIFIED(&addr6))
+ goto err;
+
+ iface->dhcpv6_sntp = realloc(iface->dhcpv6_sntp,
+ (++iface->dhcpv6_sntp_cnt) * sizeof(*iface->dhcpv6_sntp));
+ if (!iface->dhcpv6_sntp)
+ goto err;
+
+ iface->dhcpv6_sntp[iface->dhcpv6_sntp_cnt - 1] = addr6;
+
+ if (!parse_ntp_options(&iface->dhcpv6_ntp_len, addr6, &iface->dhcpv6_ntp))
+ iface->dhcpv6_ntp_cnt++;
+ } else {
+ if (!parse_ntp_fqdn(&iface->dhcpv6_ntp_len, str, &iface->dhcpv6_ntp))
+ iface->dhcpv6_ntp_cnt++;
+ }
+ }
+ }
+
return 0;
err:
return NULL;
}
-struct lease *config_find_lease_by_hostid(const uint32_t hostid)
+struct lease *config_find_lease_by_hostid(const uint64_t hostid)
{
struct lease *l;
avl_for_each_element_safe(&interfaces, i, avl, tmp) {
- if (i->inuse) {
+ if (i->inuse && i->ifflags & IFF_RUNNING) {
/* Resolve hybrid mode */
if (i->dhcpv6 == MODE_HYBRID)
i->dhcpv6 = (master && master->dhcpv6 == MODE_RELAY) ?