summary refs log tree commit diff
path: root/src/systemd
diff options
context:
space:
mode:
Diffstat (limited to 'src/systemd')
-rw-r--r--src/systemd/src/libsystemd-network/dhcp6-internal.h5
-rw-r--r--src/systemd/src/libsystemd-network/dhcp6-lease-internal.h2
-rw-r--r--src/systemd/src/libsystemd-network/dhcp6-option.c120
-rw-r--r--src/systemd/src/libsystemd-network/sd-dhcp6-client.c7
-rw-r--r--src/systemd/src/libsystemd-network/sd-dhcp6-lease.c39
-rw-r--r--src/systemd/src/systemd/sd-dhcp6-lease.h1
6 files changed, 131 insertions, 43 deletions
diff --git a/src/systemd/src/libsystemd-network/dhcp6-internal.h b/src/systemd/src/libsystemd-network/dhcp6-internal.h
index b0d1216e..068dcade 100644
--- a/src/systemd/src/libsystemd-network/dhcp6-internal.h
+++ b/src/systemd/src/libsystemd-network/dhcp6-internal.h
@@ -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,
diff --git a/src/systemd/src/libsystemd-network/dhcp6-lease-internal.h b/src/systemd/src/libsystemd-network/dhcp6-lease-internal.h
index e004f48b..df6c95e0 100644
--- a/src/systemd/src/libsystemd-network/dhcp6-lease-internal.h
+++ b/src/systemd/src/libsystemd-network/dhcp6-lease-internal.h
@@ -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);
diff --git a/src/systemd/src/libsystemd-network/dhcp6-option.c b/src/systemd/src/libsystemd-network/dhcp6-option.c
index d596752b..a6dad934 100644
--- a/src/systemd/src/libsystemd-network/dhcp6-option.c
+++ b/src/systemd/src/libsystemd-network/dhcp6-option.c
@@ -644,59 +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;
 
-        assert_return(optlen > 1, -ENODATA);
-        assert_return(optval[optlen - 1] == '\0', -EINVAL);
-
-        while (pos < optlen) {
-                _cleanup_free_ char *ret = NULL;
-                size_t n = 0, allocated = 0;
-                bool first = true;
+        if (optlen <= 1)
+                return -ENODATA;
 
-                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)
diff --git a/src/systemd/src/libsystemd-network/sd-dhcp6-client.c b/src/systemd/src/libsystemd-network/sd-dhcp6-client.c
index d653b257..b80e4e54 100644
--- a/src/systemd/src/libsystemd-network/sd-dhcp6-client.c
+++ b/src/systemd/src/libsystemd-network/sd-dhcp6-client.c
@@ -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;
diff --git a/src/systemd/src/libsystemd-network/sd-dhcp6-lease.c b/src/systemd/src/libsystemd-network/sd-dhcp6-lease.c
index b6dc0279..5f5a7fe6 100644
--- a/src/systemd/src/libsystemd-network/sd-dhcp6-lease.c
+++ b/src/systemd/src/libsystemd-network/sd-dhcp6-lease.c
@@ -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);
 
diff --git a/src/systemd/src/systemd/sd-dhcp6-lease.h b/src/systemd/src/systemd/sd-dhcp6-lease.h
index 4301c6db..240df74a 100644
--- a/src/systemd/src/systemd/sd-dhcp6-lease.h
+++ b/src/systemd/src/systemd/sd-dhcp6-lease.h
@@ -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);