Commit 813fb7d6 authored by Beniamino Galvani's avatar Beniamino Galvani

systemd: dhcp6: parse the FQDN option

Parse option 39 (Client Fully Qualified Domain Name, RFC 4704) from the DHCP
reply, which specifies the FQDN assigned by the server to the client.

https://github.com/systemd/systemd/commit/c43eea9f2effbb066901a61eafef473558d37b0f
parent e2248143
......@@ -109,8 +109,9 @@ int dhcp6_option_parse_ia(DHCP6Option *iaoption, DHCP6IA *ia, uint16_t *ret_stat
int dhcp6_option_parse_ip6addrs(uint8_t *optval, uint16_t optlen,
struct in6_addr **addrs, size_t count,
size_t *allocated);
int dhcp6_option_parse_domainname(const uint8_t *optval, uint16_t optlen,
char ***str_arr);
int dhcp6_option_parse_domainname_list(const uint8_t *optval, uint16_t optlen,
char ***str_arr);
int dhcp6_option_parse_domainname(const uint8_t *optval, uint16_t optlen, char **str);
int dhcp6_network_bind_udp_socket(int index, struct in6_addr *address);
int dhcp6_network_send_udp_socket(int s, struct in6_addr *address,
......
......@@ -35,6 +35,7 @@ struct sd_dhcp6_lease {
size_t ntp_allocated;
char **ntp_fqdn;
size_t ntp_fqdn_count;
char *fqdn;
};
int dhcp6_lease_ia_rebind_expire(const DHCP6IA *ia, uint32_t *expire);
......@@ -57,5 +58,6 @@ int dhcp6_lease_set_domains(sd_dhcp6_lease *lease, uint8_t *optval,
int dhcp6_lease_set_ntp(sd_dhcp6_lease *lease, uint8_t *optval, size_t optlen);
int dhcp6_lease_set_sntp(sd_dhcp6_lease *lease, uint8_t *optval,
size_t optlen) ;
int dhcp6_lease_set_fqdn(sd_dhcp6_lease *lease, const uint8_t *optval, size_t optlen);
int dhcp6_lease_new(sd_dhcp6_lease **ret);
......@@ -644,61 +644,103 @@ int dhcp6_option_parse_ip6addrs(uint8_t *optval, uint16_t optlen,
return count;
}
int dhcp6_option_parse_domainname(const uint8_t *optval, uint16_t optlen, char ***str_arr) {
size_t pos = 0, idx = 0;
_cleanup_strv_free_ char **names = NULL;
static int parse_domain(const uint8_t **data, uint16_t *len, char **out_domain) {
_cleanup_free_ char *ret = NULL;
size_t n = 0, allocated = 0;
const uint8_t *optval = *data;
uint16_t optlen = *len;
bool first = true;
int r;
if (optlen <= 1)
return -ENODATA;
if (optval[optlen - 1] != '\0')
return -EINVAL;
while (pos < optlen) {
_cleanup_free_ char *ret = NULL;
size_t n = 0, allocated = 0;
bool first = true;
for (;;) {
const char *label;
uint8_t c;
for (;;) {
const char *label;
uint8_t c;
c = optval[pos++];
if (optlen == 0)
break;
if (c == 0)
/* End of name */
break;
if (c > 63)
return -EBADMSG;
c = *optval;
optval++;
optlen--;
/* Literal label */
label = (const char *)&optval[pos];
pos += c;
if (pos >= optlen)
return -EMSGSIZE;
if (c == 0)
/* End label */
break;
if (c > 63)
return -EBADMSG;
if (c > optlen)
return -EMSGSIZE;
if (!GREEDY_REALLOC(ret, allocated, n + !first + DNS_LABEL_ESCAPED_MAX))
return -ENOMEM;
/* Literal label */
label = (const char *)optval;
optval += c;
optlen -= c;
if (first)
first = false;
else
ret[n++] = '.';
if (!GREEDY_REALLOC(ret, allocated, n + !first + DNS_LABEL_ESCAPED_MAX))
return -ENOMEM;
r = dns_label_escape(label, c, ret + n, DNS_LABEL_ESCAPED_MAX);
if (r < 0)
return r;
if (first)
first = false;
else
ret[n++] = '.';
n += r;
}
r = dns_label_escape(label, c, ret + n, DNS_LABEL_ESCAPED_MAX);
if (r < 0)
return r;
if (n == 0)
continue;
n += r;
}
if (n) {
if (!GREEDY_REALLOC(ret, allocated, n + 1))
return -ENOMEM;
ret[n] = 0;
}
*out_domain = TAKE_PTR(ret);
*data = optval;
*len = optlen;
return n;
}
int dhcp6_option_parse_domainname(const uint8_t *optval, uint16_t optlen, char **str) {
_cleanup_free_ char *domain = NULL;
int r;
r = parse_domain(&optval, &optlen, &domain);
if (r < 0)
return r;
if (r == 0)
return -ENODATA;
if (optlen != 0)
return -EINVAL;
*str = TAKE_PTR(domain);
return 0;
}
int dhcp6_option_parse_domainname_list(const uint8_t *optval, uint16_t optlen, char ***str_arr) {
size_t idx = 0;
_cleanup_strv_free_ char **names = NULL;
int r;
if (optlen <= 1)
return -ENODATA;
if (optval[optlen - 1] != '\0')
return -EINVAL;
while (optlen > 0) {
_cleanup_free_ char *ret = NULL;
r = parse_domain(&optval, &optlen, &ret);
if (r < 0)
return r;
if (r == 0)
continue;
r = strv_extend(&names, ret);
if (r < 0)
......
......@@ -1288,6 +1288,13 @@ static int client_parse_message(
break;
case SD_DHCP6_OPTION_FQDN:
r = dhcp6_lease_set_fqdn(lease, optval, optlen);
if (r < 0)
return r;
break;
case SD_DHCP6_OPTION_INFORMATION_REFRESH_TIME:
if (optlen != 4)
return -EINVAL;
......
......@@ -238,7 +238,7 @@ int dhcp6_lease_set_domains(sd_dhcp6_lease *lease, uint8_t *optval,
if (!optlen)
return 0;
r = dhcp6_option_parse_domainname(optval, optlen, &domains);
r = dhcp6_option_parse_domainname_list(optval, optlen, &domains);
if (r < 0)
return 0;
......@@ -296,8 +296,8 @@ int dhcp6_lease_set_ntp(sd_dhcp6_lease *lease, uint8_t *optval, size_t optlen) {
break;
case DHCP6_NTP_SUBOPTION_SRV_FQDN:
r = dhcp6_option_parse_domainname(subval, sublen,
&servers);
r = dhcp6_option_parse_domainname_list(subval, sublen,
&servers);
if (r < 0)
return 0;
......@@ -367,6 +367,38 @@ int sd_dhcp6_lease_get_ntp_fqdn(sd_dhcp6_lease *lease, char ***ntp_fqdn) {
return -ENOENT;
}
int dhcp6_lease_set_fqdn(sd_dhcp6_lease *lease, const uint8_t *optval,
size_t optlen) {
int r;
char *fqdn;
assert_return(lease, -EINVAL);
assert_return(optval, -EINVAL);
if (optlen < 2)
return -ENODATA;
/* Ignore the flags field, it doesn't carry any useful
information for clients. */
r = dhcp6_option_parse_domainname(optval + 1, optlen - 1, &fqdn);
if (r < 0)
return r;
return free_and_replace(lease->fqdn, fqdn);
}
int sd_dhcp6_lease_get_fqdn(sd_dhcp6_lease *lease, const char **fqdn) {
assert_return(lease, -EINVAL);
assert_return(fqdn, -EINVAL);
if (lease->fqdn) {
*fqdn = lease->fqdn;
return 0;
}
return -ENOENT;
}
static sd_dhcp6_lease *dhcp6_lease_free(sd_dhcp6_lease *lease) {
assert(lease);
......@@ -375,6 +407,7 @@ static sd_dhcp6_lease *dhcp6_lease_free(sd_dhcp6_lease *lease) {
dhcp6_lease_free_ia(&lease->pd);
free(lease->dns);
free(lease->fqdn);
lease->domains = strv_free(lease->domains);
......
......@@ -43,6 +43,7 @@ int sd_dhcp6_lease_get_dns(sd_dhcp6_lease *lease, const struct in6_addr **addrs)
int sd_dhcp6_lease_get_domains(sd_dhcp6_lease *lease, char ***domains);
int sd_dhcp6_lease_get_ntp_addrs(sd_dhcp6_lease *lease, const struct in6_addr **addrs);
int sd_dhcp6_lease_get_ntp_fqdn(sd_dhcp6_lease *lease, char ***ntp_fqdn);
int sd_dhcp6_lease_get_fqdn(sd_dhcp6_lease *lease, const char **fqdn);
sd_dhcp6_lease *sd_dhcp6_lease_ref(sd_dhcp6_lease *lease);
sd_dhcp6_lease *sd_dhcp6_lease_unref(sd_dhcp6_lease *lease);
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment