diff options
Diffstat (limited to 'src/config.c')
-rw-r--r-- | src/config.c | 115 |
1 files changed, 115 insertions, 0 deletions
diff --git a/src/config.c b/src/config.c index 31893d1..4e3db86 100644 --- a/src/config.c +++ b/src/config.c @@ -88,6 +88,7 @@ enum { IFACE_ATTR_NDPROXY_SLAVE, IFACE_ATTR_PREFIX_FILTER, IFACE_ATTR_PREFERRED_LIFETIME, + IFACE_ATTR_NTP, IFACE_ATTR_MAX }; @@ -138,6 +139,7 @@ static const struct blobmsg_policy iface_attrs[IFACE_ATTR_MAX] = { [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] = { @@ -230,6 +232,9 @@ static void clean_interface(struct interface *iface) 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); } @@ -443,6 +448,74 @@ static int set_lease_from_uci(struct uci_section *s) 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; @@ -915,6 +988,48 @@ int config_parse_interface(void *data, size_t len, const char *name, bool overwr 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: |