From f96ccab7e0e6cb96851010682abbc1ac0909264d Mon Sep 17 00:00:00 2001 From: Patrik Flykt Date: Mon, 4 May 2015 13:23:46 +0300 Subject: dhcp6-option: Add helper function for uncompressed domain names 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 | 2 + src/libsystemd-network/dhcp6-option.c | 82 +++++++++++++++++++++++++++++++++ 2 files changed, 84 insertions(+) diff --git a/src/libsystemd-network/dhcp6-internal.h b/src/libsystemd-network/dhcp6-internal.h index 87a3588db7..83e8192f58 100644 --- a/src/libsystemd-network/dhcp6-internal.h +++ b/src/libsystemd-network/dhcp6-internal.h @@ -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, diff --git a/src/libsystemd-network/dhcp6-option.c b/src/libsystemd-network/dhcp6-option.c index 693170bf0c..6da7ea7e27 100644 --- a/src/libsystemd-network/dhcp6-option.c +++ b/src/libsystemd-network/dhcp6-option.c @@ -26,9 +26,11 @@ #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; +} -- cgit v1.2.3-54-g00ecf