summaryrefslogtreecommitdiffhomepage
path: root/src/config.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/config.c')
-rw-r--r--src/config.c115
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: