summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorPatrik Flykt <patrik.flykt@linux.intel.com>2015-05-04 13:23:46 +0300
committerPatrik Flykt <patrik.flykt@linux.intel.com>2015-08-21 11:23:21 +0300
commitf96ccab7e0e6cb96851010682abbc1ac0909264d (patch)
treec4e8f74fd7694906cd53c63ac9f2aec50df93aa4 /src
parentb553817ccfc950df53b9d9870799919824945de5 (diff)
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.
Diffstat (limited to 'src')
-rw-r--r--src/libsystemd-network/dhcp6-internal.h2
-rw-r--r--src/libsystemd-network/dhcp6-option.c82
2 files changed, 84 insertions, 0 deletions
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;
+}