]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
dhcp6: do not set T1 and T2 by dhcp6_option_append_pd() in client 18730/head
authorYu Watanabe <watanabe.yu+github@gmail.com>
Mon, 22 Feb 2021 13:39:31 +0000 (22:39 +0900)
committerYu Watanabe <watanabe.yu+github@gmail.com>
Tue, 23 Feb 2021 10:36:37 +0000 (19:36 +0900)
Fixes #18090.

src/libsystemd-network/dhcp6-internal.h
src/libsystemd-network/dhcp6-option.c
src/libsystemd-network/sd-dhcp6-client.c

index 9a32b007fc98db02bc7d8bf0bb710f9e1b8a2eb4..681c462315587cfea3cbc0b1ff32db791983716f 100644 (file)
@@ -97,7 +97,7 @@ typedef struct DHCP6IA DHCP6IA;
 int dhcp6_option_append(uint8_t **buf, size_t *buflen, uint16_t code,
                         size_t optlen, const void *optval);
 int dhcp6_option_append_ia(uint8_t **buf, size_t *buflen, const DHCP6IA *ia);
-int dhcp6_option_append_pd(uint8_t *buf, size_t len, const DHCP6IA *pd, DHCP6Address *hint_pd_prefix);
+int dhcp6_option_append_pd(uint8_t **buf, size_t *buflen, const DHCP6IA *pd, const DHCP6Address *hint_pd_prefix);
 int dhcp6_option_append_fqdn(uint8_t **buf, size_t *buflen, const char *fqdn);
 int dhcp6_option_append_user_class(uint8_t **buf, size_t *buflen, char * const *user_class);
 int dhcp6_option_append_vendor_class(uint8_t **buf, size_t *buflen, char * const *user_class);
index 0b32acd38a25666c8d2b0c37893b62efa4f07692..93140160245380ac293256df80b32cff8f43bf38 100644 (file)
@@ -184,6 +184,90 @@ int dhcp6_option_append_ia(uint8_t **buf, size_t *buflen, const DHCP6IA *ia) {
         return option_append_hdr(&ia_hdr, &ia_buflen, ia->type, len + ia_addrlen);
 }
 
+static int option_append_pd_prefix(uint8_t **buf, size_t *buflen, const DHCP6Address *prefix) {
+        struct iapdprefix p;
+        int r;
+
+        assert(buf);
+        assert(*buf);
+        assert(buflen);
+        assert(prefix);
+
+        if (prefix->iapdprefix.prefixlen == 0)
+                return -EINVAL;
+
+        /* Do not append T1 and T2. */
+
+        p = (struct iapdprefix) {
+                .prefixlen = prefix->iapdprefix.prefixlen,
+                .address = prefix->iapdprefix.address,
+        };
+
+        r = option_append_hdr(buf, buflen, SD_DHCP6_OPTION_IA_PD_PREFIX, sizeof(struct iapdprefix));
+        if (r < 0)
+                return r;
+
+        memcpy(*buf, &p, sizeof(struct iapdprefix));
+
+        *buf += sizeof(struct iapdprefix);
+        *buflen -= sizeof(struct iapdprefix);
+
+        return offsetof(DHCP6Option, data) + sizeof(struct iapdprefix);
+}
+
+int dhcp6_option_append_pd(uint8_t **buf, size_t *buflen, const DHCP6IA *pd, const DHCP6Address *hint_pd_prefix) {
+        struct ia_pd ia_pd;
+        size_t len, pd_buflen;
+        uint8_t *pd_hdr;
+        int r;
+
+        assert_return(buf, -EINVAL);
+        assert_return(*buf, -EINVAL);
+        assert_return(buflen, -EINVAL);
+        assert_return(pd, -EINVAL);
+        assert_return(pd->type == SD_DHCP6_OPTION_IA_PD, -EINVAL);
+
+        /* Do not set T1 and T2. */
+        ia_pd = (struct ia_pd) {
+                .id = pd->ia_pd.id,
+        };
+        len = sizeof(struct ia_pd);
+
+        if (*buflen < offsetof(DHCP6Option, data) + len)
+                return -ENOBUFS;
+
+        pd_hdr = *buf;
+        pd_buflen = *buflen;
+
+        /* The header will be written at the end of this function. */
+        *buf += offsetof(DHCP6Option, data);
+        *buflen -= offsetof(DHCP6Option, data);
+
+        memcpy(*buf, &ia_pd, len);
+
+        *buf += sizeof(struct ia_pd);
+        *buflen -= sizeof(struct ia_pd);
+
+        DHCP6Address *prefix;
+        LIST_FOREACH(addresses, prefix, pd->addresses) {
+                r = option_append_pd_prefix(buf, buflen, prefix);
+                if (r < 0)
+                        return r;
+
+                len += r;
+        }
+
+        if (hint_pd_prefix) {
+                r = option_append_pd_prefix(buf, buflen, hint_pd_prefix);
+                if (r < 0 && r != -EINVAL)
+                        return r;
+
+                len += r;
+        }
+
+        return option_append_hdr(&pd_hdr, &pd_buflen, pd->type, len);
+}
+
 int dhcp6_option_append_fqdn(uint8_t **buf, size_t *buflen, const char *fqdn) {
         uint8_t buffer[1 + DNS_WIRE_FORMAT_HOSTNAME_MAX];
         int r;
@@ -286,51 +370,6 @@ int dhcp6_option_append_vendor_class(uint8_t **buf, size_t *buflen, char * const
         return dhcp6_option_append(buf, buflen, SD_DHCP6_OPTION_VENDOR_CLASS, total, p);
 }
 
-int dhcp6_option_append_pd(uint8_t *buf, size_t len, const DHCP6IA *pd, DHCP6Address *hint_pd_prefix) {
-        DHCP6Option *option = (DHCP6Option *)buf;
-        size_t i = sizeof(*option) + sizeof(pd->ia_pd);
-        DHCP6PDPrefixOption *prefix_opt;
-        DHCP6Address *prefix;
-
-        assert_return(buf, -EINVAL);
-        assert_return(pd, -EINVAL);
-        assert_return(pd->type == SD_DHCP6_OPTION_IA_PD, -EINVAL);
-
-        if (len < i)
-                return -ENOBUFS;
-
-        option->code = htobe16(SD_DHCP6_OPTION_IA_PD);
-
-        memcpy(&option->data, &pd->ia_pd, sizeof(pd->ia_pd));
-        LIST_FOREACH(addresses, prefix, pd->addresses) {
-                if (len < i + sizeof(*prefix_opt))
-                        return -ENOBUFS;
-
-                prefix_opt = (DHCP6PDPrefixOption *)&buf[i];
-                prefix_opt->option.code = htobe16(SD_DHCP6_OPTION_IA_PD_PREFIX);
-                prefix_opt->option.len = htobe16(sizeof(prefix_opt->iapdprefix));
-
-                memcpy(&prefix_opt->iapdprefix, &prefix->iapdprefix, sizeof(struct iapdprefix));
-                i += sizeof(*prefix_opt);
-        }
-
-        if (hint_pd_prefix && hint_pd_prefix->iapdprefix.prefixlen > 0) {
-                if (len < i + sizeof(*prefix_opt))
-                        return -ENOBUFS;
-
-                prefix_opt = (DHCP6PDPrefixOption *)&buf[i];
-                prefix_opt->option.code = htobe16(SD_DHCP6_OPTION_IA_PD_PREFIX);
-                prefix_opt->option.len = htobe16(sizeof(prefix_opt->iapdprefix));
-
-                memcpy(&prefix_opt->iapdprefix, &hint_pd_prefix->iapdprefix, sizeof(struct iapdprefix));
-                i += sizeof(*prefix_opt);
-        }
-
-        option->len = htobe16(i - sizeof(*option));
-
-        return i;
-}
-
 static int option_parse_hdr(uint8_t **buf, size_t *buflen, uint16_t *optcode, size_t *optlen) {
         DHCP6Option *option = (DHCP6Option*) *buf;
         uint16_t len;
index 2184073f19dfce420b77dc5fa48fff287f94e16e..410bfda10eaaab91f96f466c3e55be7a40eea771 100644 (file)
@@ -698,12 +698,9 @@ static int client_send_message(sd_dhcp6_client *client, usec_t time_now) {
                 }
 
                 if (FLAGS_SET(client->request, DHCP6_REQUEST_IA_PD)) {
-                        r = dhcp6_option_append_pd(opt, optlen, &client->ia_pd, &client->hint_pd_prefix);
+                        r = dhcp6_option_append_pd(&opt, &optlen, &client->ia_pd, &client->hint_pd_prefix);
                         if (r < 0)
                                 return r;
-
-                        opt += r;
-                        optlen -= r;
                 }
 
                 break;
@@ -762,12 +759,9 @@ static int client_send_message(sd_dhcp6_client *client, usec_t time_now) {
                 }
 
                 if (FLAGS_SET(client->request, DHCP6_REQUEST_IA_PD) && client->lease->pd.addresses) {
-                        r = dhcp6_option_append_pd(opt, optlen, &client->lease->pd, NULL);
+                        r = dhcp6_option_append_pd(&opt, &optlen, &client->lease->pd, NULL);
                         if (r < 0)
                                 return r;
-
-                        opt += r;
-                        optlen -= r;
                 }
 
                 break;
@@ -814,12 +808,9 @@ static int client_send_message(sd_dhcp6_client *client, usec_t time_now) {
                 }
 
                 if (FLAGS_SET(client->request, DHCP6_REQUEST_IA_PD)) {
-                        r = dhcp6_option_append_pd(opt, optlen, &client->lease->pd, NULL);
+                        r = dhcp6_option_append_pd(&opt, &optlen, &client->lease->pd, NULL);
                         if (r < 0)
                                 return r;
-
-                        opt += r;
-                        optlen -= r;
                 }
 
                 break;