diff --git a/src/dhcp-common.c b/src/dhcp-common.c index a769fe9..ea449cb 100644 --- a/src/dhcp-common.c +++ b/src/dhcp-common.c @@ -649,7 +649,7 @@ static const struct opttab_t opttab6[] = { { "sntp-server", 31, OT_ADDR_LIST }, { "information-refresh-time", 32, OT_TIME }, { "FQDN", 39, OT_INTERNAL | OT_RFC1035_NAME }, - { "ntp-server", 56, 0 }, + { "ntp-server", 56, 0 /* OT_ADDR_LIST | OT_RFC1035_NAME */ }, { "bootfile-url", 59, OT_NAME }, { "bootfile-param", 60, OT_CSTRING }, { NULL, 0, 0 } diff --git a/src/dhcp6-protocol.h b/src/dhcp6-protocol.h index a893315..48b027b 100644 --- a/src/dhcp6-protocol.h +++ b/src/dhcp6-protocol.h @@ -59,8 +59,12 @@ #define OPTION6_REMOTE_ID 37 #define OPTION6_SUBSCRIBER_ID 38 #define OPTION6_FQDN 39 +#define OPTION6_NTP_SERVER 56 #define OPTION6_CLIENT_MAC 79 +#define NTP_SUBOPTION_SRV_ADDR 1 +#define NTP_SUBOPTION_MC_ADDR 2 +#define NTP_SUBOPTION_SRV_FQDN 3 #define DHCP6SUCCESS 0 #define DHCP6UNSPEC 1 diff --git a/src/option.c b/src/option.c index f8ba616..3052a4d 100644 --- a/src/option.c +++ b/src/option.c @@ -1260,6 +1260,12 @@ static int parse_dhcp_opt(char *errstr, char *arg, int flags) if (!found_colon) is_addr6 = 0; + +#ifdef HAVE_DHCP6 + /* NTP server option takes hex, addresses or FQDN */ + if (is6 && new->opt == OPTION6_NTP_SERVER && !is_hex) + opt_len |= is_addr6 ? OT_ADDR_LIST : OT_RFC1035_NAME; +#endif /* We know that some options take addresses */ if (opt_len & OT_ADDR_LIST) @@ -1521,8 +1527,9 @@ static int parse_dhcp_opt(char *errstr, char *arg, int flags) } else if (comma && (opt_len & OT_RFC1035_NAME)) { - unsigned char *p = NULL, *newp, *end; + unsigned char *p = NULL, *q, *newp, *end; int len = 0; + int header_size = (is6 && new->opt == OPTION6_NTP_SERVER) ? 4 : 0; arg = comma; comma = split(arg); @@ -1532,7 +1539,7 @@ static int parse_dhcp_opt(char *errstr, char *arg, int flags) if (!dom) goto_err(_("bad domain in dhcp-option")); - newp = opt_malloc(len + strlen(dom) + 2); + newp = opt_malloc(len + header_size + strlen(dom) + 2); if (p) { @@ -1541,8 +1548,14 @@ static int parse_dhcp_opt(char *errstr, char *arg, int flags) } p = newp; - end = do_rfc1035_name(p + len, dom, NULL); + q = p + len; + end = do_rfc1035_name(q + header_size, dom, NULL); *end++ = 0; + if (is6 && new->opt == OPTION6_NTP_SERVER) + { + PUTSHORT(NTP_SUBOPTION_SRV_FQDN, q); + PUTSHORT(end - q - 2, q); + } len = end - p; free(dom); diff --git a/src/rfc3315.c b/src/rfc3315.c index 43ed4f8..57f3f8b 100644 --- a/src/rfc3315.c +++ b/src/rfc3315.c @@ -1311,23 +1311,39 @@ static struct dhcp_netid *add_options(struct state *state, int do_refresh) for (a = (struct in6_addr *)opt_cfg->val, j = 0; j < opt_cfg->len; j+=IN6ADDRSZ, a++) { + struct in6_addr *p = NULL; + if (IN6_IS_ADDR_UNSPECIFIED(a)) { if (!add_local_addrs(state->context)) - put_opt6(state->fallback, IN6ADDRSZ); + p = state->fallback; } else if (IN6_IS_ADDR_ULA_ZERO(a)) { if (!IN6_IS_ADDR_UNSPECIFIED(state->ula_addr)) - put_opt6(state->ula_addr, IN6ADDRSZ); + p = state->ula_addr; } else if (IN6_IS_ADDR_LINK_LOCAL_ZERO(a)) { if (!IN6_IS_ADDR_UNSPECIFIED(state->ll_addr)) - put_opt6(state->ll_addr, IN6ADDRSZ); + p = state->ll_addr; } else - put_opt6(a, IN6ADDRSZ); + p = a; + + if (!p) + continue; + else if (opt_cfg->opt == OPTION6_NTP_SERVER) + { + if (IN6_IS_ADDR_MULTICAST(p)) + o1 = new_opt6(NTP_SUBOPTION_MC_ADDR); + else + o1 = new_opt6(NTP_SUBOPTION_SRV_ADDR); + put_opt6(p, IN6ADDRSZ); + end_opt6(o1); + } + else + put_opt6(p, IN6ADDRSZ); } end_opt6(o);