Add DHCPv6 ntp-server (56) option handling.

There was discussion in the past regarding DHCPv6 NTP server option
which needs special subclassing per RFC5908.

Patch adds support for unicast, multicast IPv6 address and for FQDN string,
preserving possibly used (as suggested earlier) hex value.

Unfortunately it's still not fully free from limitations - only address list or
only fqdn value list is possible, not mixed due current
state option parsing & flagging.
This commit is contained in:
Vladislav Grishenko
2020-03-08 15:34:34 +00:00
committed by Simon Kelley
parent b594e8defa
commit dded78b233
4 changed files with 41 additions and 8 deletions

View File

@@ -649,7 +649,7 @@ static const struct opttab_t opttab6[] = {
{ "sntp-server", 31, OT_ADDR_LIST }, { "sntp-server", 31, OT_ADDR_LIST },
{ "information-refresh-time", 32, OT_TIME }, { "information-refresh-time", 32, OT_TIME },
{ "FQDN", 39, OT_INTERNAL | OT_RFC1035_NAME }, { "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-url", 59, OT_NAME },
{ "bootfile-param", 60, OT_CSTRING }, { "bootfile-param", 60, OT_CSTRING },
{ NULL, 0, 0 } { NULL, 0, 0 }

View File

@@ -59,8 +59,12 @@
#define OPTION6_REMOTE_ID 37 #define OPTION6_REMOTE_ID 37
#define OPTION6_SUBSCRIBER_ID 38 #define OPTION6_SUBSCRIBER_ID 38
#define OPTION6_FQDN 39 #define OPTION6_FQDN 39
#define OPTION6_NTP_SERVER 56
#define OPTION6_CLIENT_MAC 79 #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 DHCP6SUCCESS 0
#define DHCP6UNSPEC 1 #define DHCP6UNSPEC 1

View File

@@ -1260,6 +1260,12 @@ static int parse_dhcp_opt(char *errstr, char *arg, int flags)
if (!found_colon) if (!found_colon)
is_addr6 = 0; 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 */ /* We know that some options take addresses */
if (opt_len & OT_ADDR_LIST) 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)) 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 len = 0;
int header_size = (is6 && new->opt == OPTION6_NTP_SERVER) ? 4 : 0;
arg = comma; arg = comma;
comma = split(arg); comma = split(arg);
@@ -1532,7 +1539,7 @@ static int parse_dhcp_opt(char *errstr, char *arg, int flags)
if (!dom) if (!dom)
goto_err(_("bad domain in dhcp-option")); 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) if (p)
{ {
@@ -1541,8 +1548,14 @@ static int parse_dhcp_opt(char *errstr, char *arg, int flags)
} }
p = newp; p = newp;
end = do_rfc1035_name(p + len, dom, NULL); q = p + len;
end = do_rfc1035_name(q + header_size, dom, NULL);
*end++ = 0; *end++ = 0;
if (is6 && new->opt == OPTION6_NTP_SERVER)
{
PUTSHORT(NTP_SUBOPTION_SRV_FQDN, q);
PUTSHORT(end - q - 2, q);
}
len = end - p; len = end - p;
free(dom); free(dom);

View File

@@ -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++) 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 (IN6_IS_ADDR_UNSPECIFIED(a))
{ {
if (!add_local_addrs(state->context)) if (!add_local_addrs(state->context))
put_opt6(state->fallback, IN6ADDRSZ); p = state->fallback;
} }
else if (IN6_IS_ADDR_ULA_ZERO(a)) else if (IN6_IS_ADDR_ULA_ZERO(a))
{ {
if (!IN6_IS_ADDR_UNSPECIFIED(state->ula_addr)) 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)) else if (IN6_IS_ADDR_LINK_LOCAL_ZERO(a))
{ {
if (!IN6_IS_ADDR_UNSPECIFIED(state->ll_addr)) if (!IN6_IS_ADDR_UNSPECIFIED(state->ll_addr))
put_opt6(state->ll_addr, IN6ADDRSZ); p = state->ll_addr;
} }
else 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); end_opt6(o);