mirror of
https://github.com/systemd/systemd.git
synced 2025-03-28 02:50:16 +03:00
ndisc: Parse RFC9463 encrypted DNS (DNR) option
This option is equivalent to the V4/V6 DNR options for DHCP.
This commit is contained in:
parent
cb386795c2
commit
0c90d1d2f2
@ -3,6 +3,7 @@
|
||||
#include <linux/ipv6.h>
|
||||
#include <netinet/icmp6.h>
|
||||
|
||||
#include "dns-resolver-internal.h"
|
||||
#include "dns-domain.h"
|
||||
#include "ether-addr-util.h"
|
||||
#include "hostname-util.h"
|
||||
@ -89,6 +90,13 @@ static void ndisc_dnssl_done(sd_ndisc_dnssl *dnssl) {
|
||||
strv_free(dnssl->domains);
|
||||
}
|
||||
|
||||
static void ndisc_dnr_done(sd_ndisc_dnr *dnr) {
|
||||
if (!dnr)
|
||||
return;
|
||||
|
||||
sd_dns_resolver_unref(dnr->resolver);
|
||||
}
|
||||
|
||||
sd_ndisc_option* ndisc_option_free(sd_ndisc_option *option) {
|
||||
if (!option)
|
||||
return NULL;
|
||||
@ -109,6 +117,10 @@ sd_ndisc_option* ndisc_option_free(sd_ndisc_option *option) {
|
||||
case SD_NDISC_OPTION_CAPTIVE_PORTAL:
|
||||
free(option->captive_portal);
|
||||
break;
|
||||
|
||||
case SD_NDISC_OPTION_ENCRYPTED_DNS:
|
||||
ndisc_dnr_done(&option->encrypted_dns);
|
||||
break;
|
||||
}
|
||||
|
||||
return mfree(option);
|
||||
@ -1270,6 +1282,147 @@ static int ndisc_option_build_prefix64(const sd_ndisc_option *option, usec_t tim
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ndisc_option_add_encrypted_dns_internal(
|
||||
Set **options,
|
||||
size_t offset,
|
||||
sd_dns_resolver *res,
|
||||
usec_t lifetime,
|
||||
usec_t valid_until) {
|
||||
assert(options);
|
||||
|
||||
sd_ndisc_option *p = ndisc_option_new(SD_NDISC_OPTION_ENCRYPTED_DNS, offset);
|
||||
if (!p)
|
||||
return -ENOMEM;
|
||||
|
||||
p->encrypted_dns = (sd_ndisc_dnr) {
|
||||
.resolver = res,
|
||||
.lifetime = lifetime,
|
||||
.valid_until = valid_until,
|
||||
};
|
||||
|
||||
return ndisc_option_consume(options, p);
|
||||
}
|
||||
|
||||
static int ndisc_get_dns_name(const uint8_t *optval, size_t optlen, char **ret) {
|
||||
_cleanup_free_ char *name = NULL;
|
||||
int r;
|
||||
|
||||
assert(optval || optlen == 0);
|
||||
assert(ret);
|
||||
|
||||
r = dns_name_from_wire_format(&optval, &optlen, &name);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (r == 0 || optlen != 0)
|
||||
return -EBADMSG;
|
||||
|
||||
*ret = TAKE_PTR(name);
|
||||
return r;
|
||||
}
|
||||
|
||||
static int ndisc_option_parse_encrypted_dns(Set **options, size_t offset, size_t len, const uint8_t *opt) {
|
||||
int r;
|
||||
|
||||
assert(options);
|
||||
assert(opt);
|
||||
_cleanup_(sd_dns_resolver_done) sd_dns_resolver res = {};
|
||||
usec_t lifetime;
|
||||
size_t ilen;
|
||||
|
||||
/* Every field up to and including adn must be present */
|
||||
if (len < 2*8)
|
||||
return -EBADMSG;
|
||||
|
||||
if (opt[0] != SD_NDISC_OPTION_ENCRYPTED_DNS)
|
||||
return -EBADMSG;
|
||||
|
||||
size_t off = 2;
|
||||
|
||||
/* Priority */
|
||||
res.priority = unaligned_read_be16(opt + off);
|
||||
/* Alias mode is not allowed */
|
||||
if (res.priority == 0)
|
||||
return -EBADMSG;
|
||||
off += sizeof(uint16_t);
|
||||
|
||||
/* Lifetime */
|
||||
lifetime = unaligned_be32_sec_to_usec(opt + off, /* max_as_infinity = */ true);
|
||||
off += sizeof(uint32_t);
|
||||
|
||||
/* adn field (length + dns-name) */
|
||||
ilen = unaligned_read_be16(opt + off);
|
||||
off += sizeof(uint16_t);
|
||||
if (off + ilen > len)
|
||||
return -EBADMSG;
|
||||
|
||||
r = ndisc_get_dns_name(opt + off, ilen, &res.auth_name);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (dns_name_is_root(res.auth_name))
|
||||
return -EBADMSG;
|
||||
off += ilen;
|
||||
|
||||
/* This is the last field in adn-only mode, sans padding */
|
||||
if (8 * DIV_ROUND_UP(off, 8) == len && memeqzero(opt + off, len - off))
|
||||
return log_debug_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "Received ADN-only encrypted DNS option, ignoring.");
|
||||
|
||||
/* Fields following the variable (octets) length adn field are no longer certain to be aligned. */
|
||||
|
||||
/* addrs (length + packed struct in6_addr) */
|
||||
if (off + sizeof(uint16_t) > len)
|
||||
return -EBADMSG;
|
||||
ilen = unaligned_read_be16(opt + off);
|
||||
off += sizeof(uint16_t);
|
||||
if (off + ilen > len || ilen % (sizeof(struct in6_addr)) != 0)
|
||||
return -EBADMSG;
|
||||
|
||||
size_t n_addrs = ilen / (sizeof(struct in6_addr));
|
||||
if (n_addrs == 0)
|
||||
return -EBADMSG;
|
||||
res.addrs = new(union in_addr_union, n_addrs);
|
||||
if (!res.addrs)
|
||||
return -ENOMEM;
|
||||
|
||||
for (size_t i = 0; i < n_addrs; i++) {
|
||||
union in_addr_union addr;
|
||||
memcpy(&addr.in6, opt + off, sizeof(struct in6_addr));
|
||||
if (in_addr_is_multicast(AF_INET6, &addr) ||
|
||||
in_addr_is_localhost(AF_INET, &addr))
|
||||
return -EBADMSG;
|
||||
res.addrs[i] = addr;
|
||||
off += sizeof(struct in6_addr);
|
||||
}
|
||||
res.n_addrs = n_addrs;
|
||||
res.family = AF_INET6;
|
||||
|
||||
/* SvcParam field. (length + SvcParams) */
|
||||
if (off + sizeof(uint16_t) > len)
|
||||
return -EBADMSG;
|
||||
ilen = unaligned_read_be16(opt + off);
|
||||
off += sizeof(uint16_t);
|
||||
if (off + ilen > len)
|
||||
return -EBADMSG;
|
||||
|
||||
r = dnr_parse_svc_params(opt + off, ilen, &res);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (r == 0) /* This indicates a valid message we don't support */
|
||||
return -EOPNOTSUPP;
|
||||
off += ilen;
|
||||
|
||||
/* the remaining padding bytes must be zeroed */
|
||||
if (len - off >= 8 || !memeqzero(opt + off, len - off))
|
||||
return -EBADMSG;
|
||||
|
||||
sd_dns_resolver *new_res = new(sd_dns_resolver, 1);
|
||||
if (!new_res)
|
||||
return -ENOMEM;
|
||||
|
||||
*new_res = TAKE_STRUCT(res);
|
||||
|
||||
return ndisc_option_add_encrypted_dns(options, offset, new_res, lifetime);
|
||||
}
|
||||
|
||||
static int ndisc_option_parse_default(Set **options, size_t offset, size_t len, const uint8_t *opt) {
|
||||
assert(options);
|
||||
assert(opt);
|
||||
@ -1376,6 +1529,10 @@ int ndisc_parse_options(ICMP6Packet *packet, Set **ret_options) {
|
||||
r = ndisc_option_parse_prefix64(&options, offset, length, opt);
|
||||
break;
|
||||
|
||||
case SD_NDISC_OPTION_ENCRYPTED_DNS:
|
||||
r = ndisc_option_parse_encrypted_dns(&options, offset, length, opt);
|
||||
break;
|
||||
|
||||
default:
|
||||
r = ndisc_option_parse_default(&options, offset, length, opt);
|
||||
}
|
||||
|
@ -9,6 +9,7 @@
|
||||
#include <sys/uio.h>
|
||||
|
||||
#include "sd-ndisc-protocol.h"
|
||||
#include "sd-dns-resolver.h"
|
||||
|
||||
#include "icmp6-packet.h"
|
||||
#include "macro.h"
|
||||
@ -66,6 +67,12 @@ typedef struct sd_ndisc_prefix64 {
|
||||
usec_t valid_until;
|
||||
} sd_ndisc_prefix64;
|
||||
|
||||
typedef struct sd_ndisc_dnr {
|
||||
sd_dns_resolver *resolver;
|
||||
usec_t lifetime;
|
||||
usec_t valid_until;
|
||||
} sd_ndisc_dnr;
|
||||
|
||||
typedef struct sd_ndisc_option {
|
||||
uint8_t type;
|
||||
size_t offset;
|
||||
@ -83,6 +90,7 @@ typedef struct sd_ndisc_option {
|
||||
sd_ndisc_dnssl dnssl; /* SD_NDISC_OPTION_DNSSL */
|
||||
char *captive_portal; /* SD_NDISC_OPTION_CAPTIVE_PORTAL */
|
||||
sd_ndisc_prefix64 prefix64; /* SD_NDISC_OPTION_PREF64 */
|
||||
sd_ndisc_dnr encrypted_dns; /* SD_NDISC_OPTION_ENCRYPTED_DNS */
|
||||
};
|
||||
} sd_ndisc_option;
|
||||
|
||||
@ -327,4 +335,26 @@ static inline int ndisc_option_set_prefix64(
|
||||
return ndisc_option_add_prefix64_internal(options, 0, prefixlen, prefix, lifetime, valid_until);
|
||||
}
|
||||
|
||||
int ndisc_option_add_encrypted_dns_internal(
|
||||
Set **options,
|
||||
size_t offset,
|
||||
sd_dns_resolver *res,
|
||||
usec_t lifetime,
|
||||
usec_t valid_until);
|
||||
static inline int ndisc_option_add_encrypted_dns(
|
||||
Set **options,
|
||||
size_t offset,
|
||||
sd_dns_resolver *res,
|
||||
usec_t lifetime) {
|
||||
return ndisc_option_add_encrypted_dns_internal(options, offset, res, lifetime, USEC_INFINITY);
|
||||
}
|
||||
static inline int ndisc_option_set_encrypted_dns(
|
||||
Set **options,
|
||||
size_t offset,
|
||||
sd_dns_resolver *res,
|
||||
usec_t lifetime,
|
||||
usec_t valid_until) {
|
||||
return ndisc_option_add_encrypted_dns_internal(options, 0, res, lifetime, valid_until);
|
||||
}
|
||||
|
||||
int ndisc_send(int fd, const struct in6_addr *dst, const struct icmp6_hdr *hdr, Set *options, usec_t timestamp);
|
||||
|
@ -8,9 +8,12 @@
|
||||
#include "sd-ndisc.h"
|
||||
|
||||
#include "alloc-util.h"
|
||||
#include "dns-domain.h"
|
||||
#include "dns-resolver-internal.h"
|
||||
#include "ndisc-internal.h"
|
||||
#include "ndisc-router-internal.h"
|
||||
#include "string-table.h"
|
||||
#include "unaligned.h"
|
||||
|
||||
static sd_ndisc_router* ndisc_router_free(sd_ndisc_router *rt) {
|
||||
if (!rt)
|
||||
@ -91,6 +94,7 @@ DEFINE_GET_TIMESTAMP(route_get_lifetime);
|
||||
DEFINE_GET_TIMESTAMP(rdnss_get_lifetime);
|
||||
DEFINE_GET_TIMESTAMP(dnssl_get_lifetime);
|
||||
DEFINE_GET_TIMESTAMP(prefix64_get_lifetime);
|
||||
DEFINE_GET_TIMESTAMP(encrypted_dns_get_lifetime);
|
||||
|
||||
int ndisc_router_parse(sd_ndisc *nd, sd_ndisc_router *rt) {
|
||||
const struct nd_router_advert *a;
|
||||
@ -342,3 +346,6 @@ DEFINE_GETTER(dnssl, SD_NDISC_OPTION_DNSSL, lifetime, uint64_t);
|
||||
DEFINE_GETTER(prefix64, SD_NDISC_OPTION_PREF64, prefixlen, uint8_t);
|
||||
DEFINE_GETTER(prefix64, SD_NDISC_OPTION_PREF64, prefix, struct in6_addr);
|
||||
DEFINE_GETTER(prefix64, SD_NDISC_OPTION_PREF64, lifetime, uint64_t);
|
||||
|
||||
DEFINE_GETTER(encrypted_dns, SD_NDISC_OPTION_ENCRYPTED_DNS, lifetime, uint64_t);
|
||||
DEFINE_GETTER(encrypted_dns, SD_NDISC_OPTION_ENCRYPTED_DNS, resolver, sd_dns_resolver*);
|
||||
|
@ -167,6 +167,7 @@ typedef struct Link {
|
||||
Set *ndisc_captive_portals;
|
||||
Set *ndisc_pref64;
|
||||
Set *ndisc_redirects;
|
||||
Set *ndisc_dnr;
|
||||
uint32_t ndisc_mtu;
|
||||
unsigned ndisc_messages;
|
||||
bool ndisc_configured:1;
|
||||
|
@ -22,6 +22,7 @@
|
||||
#include "networkd-route.h"
|
||||
#include "networkd-state-file.h"
|
||||
#include "networkd-sysctl.h"
|
||||
#include "sort-util.h"
|
||||
#include "string-table.h"
|
||||
#include "string-util.h"
|
||||
#include "strv.h"
|
||||
@ -1828,6 +1829,144 @@ static int ndisc_router_process_pref64(Link *link, sd_ndisc_router *rt) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static NDiscDNR* ndisc_dnr_free(NDiscDNR *x) {
|
||||
if (!x)
|
||||
return NULL;
|
||||
|
||||
sd_dns_resolver_done(&x->resolver);
|
||||
return mfree(x);
|
||||
}
|
||||
|
||||
DEFINE_TRIVIAL_CLEANUP_FUNC(NDiscDNR*, ndisc_dnr_free);
|
||||
|
||||
static int ndisc_dnr_compare_func(const NDiscDNR *a, const NDiscDNR *b) {
|
||||
return CMP(a->resolver.priority, b->resolver.priority) ||
|
||||
strcmp_ptr(a->resolver.auth_name, b->resolver.auth_name) ||
|
||||
CMP(a->resolver.transports, b->resolver.transports) ||
|
||||
CMP(a->resolver.port, b->resolver.port) ||
|
||||
strcmp_ptr(a->resolver.dohpath, b->resolver.dohpath) ||
|
||||
CMP(a->resolver.family, b->resolver.family) ||
|
||||
CMP(a->resolver.n_addrs, b->resolver.n_addrs) ||
|
||||
memcmp(a->resolver.addrs, b->resolver.addrs, sizeof(a->resolver.addrs[0]) * a->resolver.n_addrs);
|
||||
}
|
||||
|
||||
static void ndisc_dnr_hash_func(const NDiscDNR *x, struct siphash *state) {
|
||||
assert(x);
|
||||
|
||||
siphash24_compress_resolver(&x->resolver, state);
|
||||
}
|
||||
|
||||
DEFINE_PRIVATE_HASH_OPS_WITH_KEY_DESTRUCTOR(
|
||||
ndisc_dnr_hash_ops,
|
||||
NDiscDNR,
|
||||
ndisc_dnr_hash_func,
|
||||
ndisc_dnr_compare_func,
|
||||
ndisc_dnr_free);
|
||||
|
||||
static int sd_dns_resolver_copy(const sd_dns_resolver *a, sd_dns_resolver *b) {
|
||||
int r;
|
||||
|
||||
assert(a);
|
||||
assert(b);
|
||||
|
||||
_cleanup_(sd_dns_resolver_done) sd_dns_resolver c = {
|
||||
.priority = a->priority,
|
||||
.transports = a->transports,
|
||||
.port = a->port,
|
||||
/* .auth_name */
|
||||
.family = a->family,
|
||||
/* .addrs */
|
||||
/* .n_addrs */
|
||||
/* .dohpath */
|
||||
};
|
||||
|
||||
/* auth_name */
|
||||
r = strdup_to(&c.auth_name, a->auth_name);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
/* addrs, n_addrs */
|
||||
c.addrs = newdup(union in_addr_union, a->addrs, a->n_addrs);
|
||||
if (!c.addrs)
|
||||
return r;
|
||||
c.n_addrs = a->n_addrs;
|
||||
|
||||
/* dohpath */
|
||||
r = strdup_to(&c.dohpath, a->dohpath);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
*b = TAKE_STRUCT(c);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ndisc_router_process_encrypted_dns(Link *link, sd_ndisc_router *rt) {
|
||||
int r;
|
||||
|
||||
assert(link);
|
||||
assert(link->network);
|
||||
assert(rt);
|
||||
|
||||
struct in6_addr router;
|
||||
usec_t lifetime_usec;
|
||||
sd_dns_resolver *res;
|
||||
_cleanup_(ndisc_dnr_freep) NDiscDNR *new_entry = NULL;
|
||||
|
||||
r = sd_ndisc_router_get_sender_address(rt, &router);
|
||||
if (r < 0)
|
||||
return log_link_warning_errno(link, r, "Failed to get gateway address from RA: %m");
|
||||
|
||||
r = sd_ndisc_router_encrypted_dns_get_lifetime_timestamp(rt, CLOCK_BOOTTIME, &lifetime_usec);
|
||||
if (r < 0)
|
||||
return log_link_warning_errno(link, r, "Failed to get lifetime of RA message: %m");
|
||||
|
||||
r = sd_ndisc_router_encrypted_dns_get_resolver(rt, &res);
|
||||
if (r < 0)
|
||||
return log_link_warning_errno(link, r, "Failed to get encrypted dns resolvers: %m");
|
||||
|
||||
NDiscDNR *dnr, d = { .resolver = *res };
|
||||
if (lifetime_usec == 0) {
|
||||
dnr = set_remove(link->ndisc_dnr, &d);
|
||||
if (dnr) {
|
||||
ndisc_dnr_free(dnr);
|
||||
link_dirty(link);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
dnr = set_get(link->ndisc_dnr, &d);
|
||||
if (dnr) {
|
||||
dnr->router = router;
|
||||
dnr->lifetime_usec = lifetime_usec;
|
||||
return 0;
|
||||
}
|
||||
|
||||
new_entry = new(NDiscDNR, 1);
|
||||
if (!new_entry)
|
||||
return log_oom();
|
||||
|
||||
*new_entry = (NDiscDNR) {
|
||||
.router = router,
|
||||
/* .resolver, */
|
||||
.lifetime_usec = lifetime_usec,
|
||||
};
|
||||
r = sd_dns_resolver_copy(res, &new_entry->resolver);
|
||||
if (r < 0)
|
||||
return log_oom();
|
||||
|
||||
/* Not sorted by priority */
|
||||
r = set_ensure_put(&link->ndisc_dnr, &ndisc_dnr_hash_ops, new_entry);
|
||||
if (r < 0)
|
||||
return log_oom();
|
||||
|
||||
assert(r > 0);
|
||||
TAKE_PTR(new_entry);
|
||||
|
||||
link_dirty(link);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ndisc_router_process_options(Link *link, sd_ndisc_router *rt) {
|
||||
size_t n_captive_portal = 0;
|
||||
int r;
|
||||
@ -1879,6 +2018,9 @@ static int ndisc_router_process_options(Link *link, sd_ndisc_router *rt) {
|
||||
case SD_NDISC_OPTION_PREF64:
|
||||
r = ndisc_router_process_pref64(link, rt);
|
||||
break;
|
||||
case SD_NDISC_OPTION_ENCRYPTED_DNS:
|
||||
r = ndisc_router_process_encrypted_dns(link, rt);
|
||||
break;
|
||||
}
|
||||
if (r < 0 && r != -EBADMSG)
|
||||
return r;
|
||||
@ -1891,6 +2033,7 @@ static int ndisc_drop_outdated(Link *link, const struct in6_addr *router, usec_t
|
||||
NDiscRDNSS *rdnss;
|
||||
NDiscCaptivePortal *cp;
|
||||
NDiscPREF64 *p64;
|
||||
NDiscDNR *dnr;
|
||||
Address *address;
|
||||
Route *route;
|
||||
int r, ret = 0;
|
||||
@ -1989,6 +2132,14 @@ static int ndisc_drop_outdated(Link *link, const struct in6_addr *router, usec_t
|
||||
* the 'updated' flag. */
|
||||
}
|
||||
|
||||
SET_FOREACH(dnr, link->ndisc_dnr) {
|
||||
if (dnr->lifetime_usec > timestamp_usec)
|
||||
continue; /* The resolver is still valid */
|
||||
|
||||
ndisc_dnr_free(set_remove(link->ndisc_dnr, dnr));
|
||||
updated = true;
|
||||
}
|
||||
|
||||
if (updated)
|
||||
link_dirty(link);
|
||||
|
||||
@ -2016,6 +2167,7 @@ static int ndisc_setup_expire(Link *link) {
|
||||
NDiscDNSSL *dnssl;
|
||||
NDiscRDNSS *rdnss;
|
||||
NDiscPREF64 *p64;
|
||||
NDiscDNR *dnr;
|
||||
Address *address;
|
||||
Route *route;
|
||||
int r;
|
||||
@ -2068,6 +2220,9 @@ static int ndisc_setup_expire(Link *link) {
|
||||
SET_FOREACH(p64, link->ndisc_pref64)
|
||||
lifetime_usec = MIN(lifetime_usec, p64->lifetime_usec);
|
||||
|
||||
SET_FOREACH(dnr, link->ndisc_dnr)
|
||||
lifetime_usec = MIN(lifetime_usec, dnr->lifetime_usec);
|
||||
|
||||
if (lifetime_usec == USEC_INFINITY)
|
||||
return 0;
|
||||
|
||||
@ -2324,6 +2479,14 @@ static int ndisc_neighbor_handle_router_message(Link *link, sd_ndisc_neighbor *n
|
||||
p64->router = current_address;
|
||||
}
|
||||
|
||||
NDiscDNR *dnr;
|
||||
SET_FOREACH(dnr, link->ndisc_dnr) {
|
||||
if (!in6_addr_equal(&dnr->router, &original_address))
|
||||
continue;
|
||||
|
||||
dnr->router = current_address;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -2507,7 +2670,7 @@ int ndisc_stop(Link *link) {
|
||||
void ndisc_flush(Link *link) {
|
||||
assert(link);
|
||||
|
||||
/* Remove all addresses, routes, RDNSS, DNSSL, and Captive Portal entries, without exception. */
|
||||
/* Remove all addresses, routes, RDNSS, DNSSL, DNR, and Captive Portal entries, without exception. */
|
||||
(void) ndisc_drop_outdated(link, /* router = */ NULL, /* timestamp_usec = */ USEC_INFINITY);
|
||||
(void) ndisc_drop_redirect(link, /* router = */ NULL);
|
||||
|
||||
@ -2517,6 +2680,7 @@ void ndisc_flush(Link *link) {
|
||||
link->ndisc_captive_portals = set_free(link->ndisc_captive_portals);
|
||||
link->ndisc_pref64 = set_free(link->ndisc_pref64);
|
||||
link->ndisc_redirects = set_free(link->ndisc_redirects);
|
||||
link->ndisc_dnr = set_free(link->ndisc_dnr);
|
||||
link->ndisc_mtu = 0;
|
||||
}
|
||||
|
||||
|
@ -2,6 +2,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "conf-parser.h"
|
||||
#include "dns-resolver-internal.h"
|
||||
#include "time-util.h"
|
||||
|
||||
typedef struct Address Address;
|
||||
@ -49,6 +50,12 @@ typedef struct NDiscPREF64 {
|
||||
struct in6_addr prefix;
|
||||
} NDiscPREF64;
|
||||
|
||||
typedef struct NDiscDNR {
|
||||
struct in6_addr router;
|
||||
usec_t lifetime_usec;
|
||||
sd_dns_resolver resolver;
|
||||
} NDiscDNR;
|
||||
|
||||
static inline char* NDISC_DNSSL_DOMAIN(const NDiscDNSSL *n) {
|
||||
return ((char*) n) + ALIGN(sizeof(NDiscDNSSL));
|
||||
}
|
||||
|
@ -28,6 +28,7 @@
|
||||
_SD_BEGIN_DECLARATIONS;
|
||||
|
||||
typedef struct sd_ndisc_router sd_ndisc_router;
|
||||
typedef struct sd_dns_resolver sd_dns_resolver;
|
||||
|
||||
sd_ndisc_router *sd_ndisc_router_ref(sd_ndisc_router *rt);
|
||||
sd_ndisc_router *sd_ndisc_router_unref(sd_ndisc_router *rt);
|
||||
@ -87,6 +88,11 @@ int sd_ndisc_router_prefix64_get_prefixlen(sd_ndisc_router *rt, uint8_t *ret);
|
||||
int sd_ndisc_router_prefix64_get_lifetime(sd_ndisc_router *rt, uint64_t *ret);
|
||||
int sd_ndisc_router_prefix64_get_lifetime_timestamp(sd_ndisc_router *rt, clockid_t clock, uint64_t *ret);
|
||||
|
||||
/* Specific option access: SD_NDISC_OPTION_ENCRYPTED_DNS */
|
||||
int sd_ndisc_router_encrypted_dns_get_resolver(sd_ndisc_router *rt, sd_dns_resolver **ret);
|
||||
int sd_ndisc_router_encrypted_dns_get_lifetime(sd_ndisc_router *rt, uint64_t *ret);
|
||||
int sd_ndisc_router_encrypted_dns_get_lifetime_timestamp(sd_ndisc_router *rt, clockid_t clock, uint64_t *ret);
|
||||
|
||||
_SD_END_DECLARATIONS;
|
||||
|
||||
#endif
|
||||
|
Loading…
x
Reference in New Issue
Block a user