]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
dhcp6-option: Add helper function for uncompressed domain names
authorPatrik Flykt <patrik.flykt@linux.intel.com>
Mon, 4 May 2015 10:23:46 +0000 (13:23 +0300)
committerPatrik Flykt <patrik.flykt@linux.intel.com>
Fri, 21 Aug 2015 08:23:21 +0000 (11:23 +0300)
Add a helper function containing a modified version of dns_packet_read_name()
that does not use DnsPacket to extract a string array of domain names from
the provided option data. The domain names are stored uncompressed as defined
in Section 8. of RFC 3315.

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

index 87a3588db7804f679e4f0cbdf8317534b085cebf..83e8192f58494bd196db70561d353ad4f3ca6cf8 100644 (file)
@@ -71,6 +71,8 @@ int dhcp6_option_parse_ia(uint8_t **buf, size_t *buflen, uint16_t iatype,
 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_network_bind_udp_socket(int index, struct in6_addr *address);
 int dhcp6_network_send_udp_socket(int s, struct in6_addr *address,
index 693170bf0c78ce88685d729a587bf092acd0ae7e..6da7ea7e278363a34814d8138c623cd2cf87f361 100644 (file)
 #include "sparse-endian.h"
 #include "unaligned.h"
 #include "util.h"
+#include "strv.h"
 
 #include "dhcp6-internal.h"
 #include "dhcp6-protocol.h"
+#include "dns-domain.h"
 
 #define DHCP6_OPTION_IA_NA_LEN                  12
 #define DHCP6_OPTION_IA_TA_LEN                  4
@@ -335,3 +337,83 @@ 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_free_ char **names = NULL;
+        int r;
+
+        assert_return(optlen > 1, -ENODATA);
+        assert_return(optval[optlen] == '\0', -EINVAL);
+
+        while (pos < optlen) {
+                _cleanup_free_ char *ret = NULL;
+                size_t n = 0, allocated = 0;
+                bool first = true;
+
+                for (;;) {
+                        uint8_t c;
+
+                        c = optval[pos++];
+
+                        if (c == 0)
+                                /* End of name */
+                                break;
+                        else if (c <= 63) {
+                                _cleanup_free_ char *t = NULL;
+                                const char *label;
+
+                                /* Literal label */
+                                label = (const char *)&optval[pos];
+                                pos += c;
+                                if (pos > optlen)
+                                        return -EMSGSIZE;
+
+                                r = dns_label_escape(label, c, &t);
+                                if (r < 0)
+                                        goto fail;
+
+                                if (!GREEDY_REALLOC0(ret, allocated, n + !first + strlen(t) + 1)) {
+                                        r = -ENOMEM;
+                                        goto fail;
+                                }
+
+                                if (!first)
+                                        ret[n++] = '.';
+                                else
+                                        first = false;
+
+                                memcpy(ret + n, t, r);
+                                n += r;
+                                continue;
+                        } else {
+                                r = -EBADMSG;
+                                goto fail;
+                        }
+                }
+
+                if (!GREEDY_REALLOC(ret, allocated, n + 1)) {
+                        r = -ENOMEM;
+                        goto fail;
+                }
+
+                ret[n] = 0;
+
+                r = strv_extend(&names, ret);
+                if (r < 0)
+                        goto fail;
+
+                ret = NULL;
+                idx++;
+        }
+
+        *str_arr = names;
+        names = NULL;
+
+        return idx;
+
+fail:
+        return r;
+}