aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndrew Zaborowski <andrew.zaborowski@intel.com>2022-09-19 15:31:00 +0200
committerDenis Kenzior <denkenz@gmail.com>2022-09-19 13:30:47 -0500
commit4b1ce9b3e3d0600ac6f173d189259cda05af0784 (patch)
tree7f59642295f1a30ae212ebf071a231f40ff1736c
parent5fc3c8d84677560b534b9799063471fb0e837383 (diff)
icmp6: Parse RDNSS and DNSSL options
Save the list of DNS server addresses and the local domain search list from Router Advertisements in the l_icmp6_router structure.
-rw-r--r--ell/icmp6-private.h14
-rw-r--r--ell/icmp6.c94
2 files changed, 106 insertions, 2 deletions
diff --git a/ell/icmp6-private.h b/ell/icmp6-private.h
index a26639d9..f2071645 100644
--- a/ell/icmp6-private.h
+++ b/ell/icmp6-private.h
@@ -34,6 +34,16 @@ struct autoconf_prefix_info {
uint32_t valid_lifetime;
};
+struct dns_info {
+ uint8_t address[16];
+ uint32_t lifetime;
+};
+
+struct domain_info {
+ char *domain;
+ uint32_t lifetime;
+};
+
struct l_icmp6_router {
uint8_t address[16];
bool managed : 1;
@@ -47,6 +57,10 @@ struct l_icmp6_router {
struct route_info *routes;
uint32_t n_ac_prefixes;
struct autoconf_prefix_info *ac_prefixes;
+ uint32_t n_dns;
+ struct dns_info *dns_list;
+ uint32_t n_domains;
+ struct domain_info *domains;
};
struct l_icmp6_router *_icmp6_router_new();
diff --git a/ell/icmp6.c b/ell/icmp6.c
index b71a98f4..c38df170 100644
--- a/ell/icmp6.c
+++ b/ell/icmp6.c
@@ -50,6 +50,7 @@
#include "netlink.h"
#include "rtnl.h"
#include "missing.h"
+#include "utf8.h"
#include "icmp6.h"
#include "icmp6-private.h"
@@ -58,6 +59,14 @@
#define ND_OPT_ROUTE_INFORMATION 24
#endif
+/* RFC8106 */
+#ifndef ND_OPT_RECURSIVE_DNS_SERVER
+#define ND_OPT_RECURSIVE_DNS_SERVER 25
+#endif
+#ifndef ND_OPT_DNS_SEARCH_LIST
+#define ND_OPT_DNS_SEARCH_LIST 31
+#endif
+
#define CLIENT_DEBUG(fmt, args...) \
l_util_debug(client->debug_handler, client->debug_data, \
"%s:%i " fmt, __func__, __LINE__, ## args)
@@ -755,6 +764,8 @@ struct l_icmp6_router *_icmp6_router_parse(const struct nd_router_advert *ra,
uint32_t opts_len;
uint32_t n_routes = 0;
uint32_t n_ac_prefixes = 0;
+ uint32_t n_dns = 0;
+ uint32_t n_domains = 0;
if (ra->nd_ra_type != ND_ROUTER_ADVERT)
return NULL;
@@ -825,6 +836,46 @@ struct l_icmp6_router *_icmp6_router_parse(const struct nd_router_advert *ra,
n_routes += 1;
break;
+ case ND_OPT_RECURSIVE_DNS_SERVER:
+ if (l < 24 || (l & 15) != 8)
+ return NULL;
+
+ n_dns += (l - 8) / 16;
+ break;
+ case ND_OPT_DNS_SEARCH_LIST:
+ {
+ unsigned int n_labels;
+ unsigned int pos = 8;
+
+ if (l < 16)
+ return NULL;
+
+ /* Count domains according to RFC1035 Section 3.1 */
+ do {
+ unsigned int label_len;
+
+ n_labels = 0;
+
+ do {
+ label_len = opts[pos];
+ pos += 1 + label_len;
+ n_labels += label_len ? 1 : 0;
+ } while (label_len && pos < l);
+
+ /*
+ * Check if the root label was missing, or
+ * a label didn't fit in the option bytes, or
+ * the first domain had 0 labels, i.e. there
+ * were no domains.
+ */
+ if (label_len || pos > l || pos == 9)
+ return NULL;
+
+ n_domains += n_labels ? 1 : 0;
+ } while (n_labels && pos < l);
+
+ break;
+ }
}
opts += l;
@@ -834,9 +885,9 @@ struct l_icmp6_router *_icmp6_router_parse(const struct nd_router_advert *ra,
r = _icmp6_router_new();
memcpy(r->address, src, sizeof(r->address));
r->routes = l_new(struct route_info, n_routes);
- r->n_routes = n_routes;
r->ac_prefixes = l_new(struct autoconf_prefix_info, n_ac_prefixes);
- r->n_ac_prefixes = n_ac_prefixes;
+ r->dns_list = l_new(struct dns_info, n_dns);
+ r->domains = l_new(struct domain_info, n_domains);
if (ra->nd_ra_flags_reserved & ND_RA_FLAG_MANAGED)
r->managed = true;
@@ -855,6 +906,8 @@ struct l_icmp6_router *_icmp6_router_parse(const struct nd_router_advert *ra,
opts_len = len - sizeof(struct nd_router_advert);
n_routes = 0;
n_ac_prefixes = 0;
+ n_dns = 0;
+ n_domains = 0;
while (opts_len) {
uint8_t t = opts[0];
@@ -946,12 +999,49 @@ struct l_icmp6_router *_icmp6_router_parse(const struct nd_router_advert *ra,
n_routes += 1;
break;
}
+ case ND_OPT_RECURSIVE_DNS_SERVER:
+ {
+ unsigned int pos;
+
+ for (pos = 8; pos < l; pos += 16) {
+ struct dns_info *i = &r->dns_list[n_dns++];
+
+ i->lifetime = l_get_be32(opts + 4);
+ memcpy(i->address, opts + pos, 16);
+ }
+
+ break;
+ }
+ case ND_OPT_DNS_SEARCH_LIST:
+ {
+ struct domain_info *info = &r->domains[n_domains];
+ _auto_(l_free) char **domain_list =
+ net_domain_list_parse(opts + 8, l - 8);
+ char **i;
+
+ /* Ignore invalid option */
+ if (!domain_list)
+ break;
+
+ for (i = domain_list; *i; i++) {
+ info->lifetime = l_get_be32(opts + 4);
+ info->domain = *i;
+ info++;
+ n_domains++;
+ }
+
+ break;
+ }
}
opts += l;
opts_len -= l;
}
+ r->n_routes = n_routes;
+ r->n_ac_prefixes = n_ac_prefixes;
+ r->n_dns = n_dns;
+ r->n_domains = n_domains;
return r;
}