2020-11-09 05:23:58 +01:00
|
|
|
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
network: beef up ipv6 RA support considerably
This reworks sd-ndisc and networkd substantially to support IPv6 RA much more
comprehensively. Since the API is extended quite a bit networkd has been ported
over too, and the patch is not as straight-forward as one could wish. The
rework includes:
- Support for DNSSL, RDNSS and RA routing options in sd-ndisc and networkd. Two
new configuration options have been added to networkd to make this
configurable.
- sd-ndisc now exposes an sd_ndisc_router object that encapsulates a full RA
message, and has direct, friendly acessor functions for the singleton RA
properties, as well as an iterative interface to iterate through known and
unsupported options. The router object may either be retrieved from the wire,
or generated from raw data. In many ways the sd-ndisc API now matches the
sd-lldp API, except that no implicit database of seen data is kept. (Note
that sd-ndisc actually had a half-written, but unused implementaiton of such
a store, which is removed now.)
- sd-ndisc will now collect the reception timestamps of RA, which is useful to
make sd_ndisc_router fully descriptive of what it covers.
Fixes: #1079
2016-06-02 20:38:12 +02:00
|
|
|
/***
|
2018-06-12 17:15:23 +02:00
|
|
|
Copyright © 2014 Intel Corporation. All rights reserved.
|
network: beef up ipv6 RA support considerably
This reworks sd-ndisc and networkd substantially to support IPv6 RA much more
comprehensively. Since the API is extended quite a bit networkd has been ported
over too, and the patch is not as straight-forward as one could wish. The
rework includes:
- Support for DNSSL, RDNSS and RA routing options in sd-ndisc and networkd. Two
new configuration options have been added to networkd to make this
configurable.
- sd-ndisc now exposes an sd_ndisc_router object that encapsulates a full RA
message, and has direct, friendly acessor functions for the singleton RA
properties, as well as an iterative interface to iterate through known and
unsupported options. The router object may either be retrieved from the wire,
or generated from raw data. In many ways the sd-ndisc API now matches the
sd-lldp API, except that no implicit database of seen data is kept. (Note
that sd-ndisc actually had a half-written, but unused implementaiton of such
a store, which is removed now.)
- sd-ndisc will now collect the reception timestamps of RA, which is useful to
make sd_ndisc_router fully descriptive of what it covers.
Fixes: #1079
2016-06-02 20:38:12 +02:00
|
|
|
***/
|
|
|
|
|
|
|
|
#include <netinet/icmp6.h>
|
|
|
|
|
|
|
|
#include "sd-ndisc.h"
|
|
|
|
|
|
|
|
#include "alloc-util.h"
|
|
|
|
#include "dns-domain.h"
|
|
|
|
#include "hostname-util.h"
|
2019-03-13 12:02:21 +01:00
|
|
|
#include "memory-util.h"
|
2019-10-31 03:07:23 +01:00
|
|
|
#include "missing_network.h"
|
network: beef up ipv6 RA support considerably
This reworks sd-ndisc and networkd substantially to support IPv6 RA much more
comprehensively. Since the API is extended quite a bit networkd has been ported
over too, and the patch is not as straight-forward as one could wish. The
rework includes:
- Support for DNSSL, RDNSS and RA routing options in sd-ndisc and networkd. Two
new configuration options have been added to networkd to make this
configurable.
- sd-ndisc now exposes an sd_ndisc_router object that encapsulates a full RA
message, and has direct, friendly acessor functions for the singleton RA
properties, as well as an iterative interface to iterate through known and
unsupported options. The router object may either be retrieved from the wire,
or generated from raw data. In many ways the sd-ndisc API now matches the
sd-lldp API, except that no implicit database of seen data is kept. (Note
that sd-ndisc actually had a half-written, but unused implementaiton of such
a store, which is removed now.)
- sd-ndisc will now collect the reception timestamps of RA, which is useful to
make sd_ndisc_router fully descriptive of what it covers.
Fixes: #1079
2016-06-02 20:38:12 +02:00
|
|
|
#include "ndisc-internal.h"
|
|
|
|
#include "ndisc-router.h"
|
|
|
|
#include "strv.h"
|
|
|
|
|
2018-08-27 07:01:46 +02:00
|
|
|
DEFINE_PUBLIC_TRIVIAL_REF_UNREF_FUNC(sd_ndisc_router, sd_ndisc_router, mfree);
|
network: beef up ipv6 RA support considerably
This reworks sd-ndisc and networkd substantially to support IPv6 RA much more
comprehensively. Since the API is extended quite a bit networkd has been ported
over too, and the patch is not as straight-forward as one could wish. The
rework includes:
- Support for DNSSL, RDNSS and RA routing options in sd-ndisc and networkd. Two
new configuration options have been added to networkd to make this
configurable.
- sd-ndisc now exposes an sd_ndisc_router object that encapsulates a full RA
message, and has direct, friendly acessor functions for the singleton RA
properties, as well as an iterative interface to iterate through known and
unsupported options. The router object may either be retrieved from the wire,
or generated from raw data. In many ways the sd-ndisc API now matches the
sd-lldp API, except that no implicit database of seen data is kept. (Note
that sd-ndisc actually had a half-written, but unused implementaiton of such
a store, which is removed now.)
- sd-ndisc will now collect the reception timestamps of RA, which is useful to
make sd_ndisc_router fully descriptive of what it covers.
Fixes: #1079
2016-06-02 20:38:12 +02:00
|
|
|
|
|
|
|
sd_ndisc_router *ndisc_router_new(size_t raw_size) {
|
|
|
|
sd_ndisc_router *rt;
|
|
|
|
|
|
|
|
rt = malloc0(ALIGN(sizeof(sd_ndisc_router)) + raw_size);
|
|
|
|
if (!rt)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
rt->raw_size = raw_size;
|
|
|
|
rt->n_ref = 1;
|
|
|
|
|
|
|
|
return rt;
|
|
|
|
}
|
|
|
|
|
|
|
|
_public_ int sd_ndisc_router_from_raw(sd_ndisc_router **ret, const void *raw, size_t raw_size) {
|
|
|
|
_cleanup_(sd_ndisc_router_unrefp) sd_ndisc_router *rt = NULL;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
assert_return(ret, -EINVAL);
|
|
|
|
assert_return(raw || raw_size <= 0, -EINVAL);
|
|
|
|
|
|
|
|
rt = ndisc_router_new(raw_size);
|
|
|
|
if (!rt)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
memcpy(NDISC_ROUTER_RAW(rt), raw, raw_size);
|
|
|
|
r = ndisc_router_parse(rt);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
2018-04-05 07:26:26 +02:00
|
|
|
*ret = TAKE_PTR(rt);
|
network: beef up ipv6 RA support considerably
This reworks sd-ndisc and networkd substantially to support IPv6 RA much more
comprehensively. Since the API is extended quite a bit networkd has been ported
over too, and the patch is not as straight-forward as one could wish. The
rework includes:
- Support for DNSSL, RDNSS and RA routing options in sd-ndisc and networkd. Two
new configuration options have been added to networkd to make this
configurable.
- sd-ndisc now exposes an sd_ndisc_router object that encapsulates a full RA
message, and has direct, friendly acessor functions for the singleton RA
properties, as well as an iterative interface to iterate through known and
unsupported options. The router object may either be retrieved from the wire,
or generated from raw data. In many ways the sd-ndisc API now matches the
sd-lldp API, except that no implicit database of seen data is kept. (Note
that sd-ndisc actually had a half-written, but unused implementaiton of such
a store, which is removed now.)
- sd-ndisc will now collect the reception timestamps of RA, which is useful to
make sd_ndisc_router fully descriptive of what it covers.
Fixes: #1079
2016-06-02 20:38:12 +02:00
|
|
|
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
_public_ int sd_ndisc_router_get_address(sd_ndisc_router *rt, struct in6_addr *ret_addr) {
|
|
|
|
assert_return(rt, -EINVAL);
|
|
|
|
assert_return(ret_addr, -EINVAL);
|
|
|
|
|
2016-11-18 13:13:28 +01:00
|
|
|
if (IN6_IS_ADDR_UNSPECIFIED(&rt->address))
|
network: beef up ipv6 RA support considerably
This reworks sd-ndisc and networkd substantially to support IPv6 RA much more
comprehensively. Since the API is extended quite a bit networkd has been ported
over too, and the patch is not as straight-forward as one could wish. The
rework includes:
- Support for DNSSL, RDNSS and RA routing options in sd-ndisc and networkd. Two
new configuration options have been added to networkd to make this
configurable.
- sd-ndisc now exposes an sd_ndisc_router object that encapsulates a full RA
message, and has direct, friendly acessor functions for the singleton RA
properties, as well as an iterative interface to iterate through known and
unsupported options. The router object may either be retrieved from the wire,
or generated from raw data. In many ways the sd-ndisc API now matches the
sd-lldp API, except that no implicit database of seen data is kept. (Note
that sd-ndisc actually had a half-written, but unused implementaiton of such
a store, which is removed now.)
- sd-ndisc will now collect the reception timestamps of RA, which is useful to
make sd_ndisc_router fully descriptive of what it covers.
Fixes: #1079
2016-06-02 20:38:12 +02:00
|
|
|
return -ENODATA;
|
|
|
|
|
|
|
|
*ret_addr = rt->address;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
_public_ int sd_ndisc_router_get_timestamp(sd_ndisc_router *rt, clockid_t clock, uint64_t *ret) {
|
|
|
|
assert_return(rt, -EINVAL);
|
|
|
|
assert_return(TRIPLE_TIMESTAMP_HAS_CLOCK(clock), -EOPNOTSUPP);
|
|
|
|
assert_return(clock_supported(clock), -EOPNOTSUPP);
|
|
|
|
assert_return(ret, -EINVAL);
|
|
|
|
|
|
|
|
if (!triple_timestamp_is_set(&rt->timestamp))
|
|
|
|
return -ENODATA;
|
|
|
|
|
|
|
|
*ret = triple_timestamp_by_clock(&rt->timestamp, clock);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
_public_ int sd_ndisc_router_get_raw(sd_ndisc_router *rt, const void **ret, size_t *size) {
|
|
|
|
assert_return(rt, -EINVAL);
|
|
|
|
assert_return(ret, -EINVAL);
|
|
|
|
assert_return(size, -EINVAL);
|
|
|
|
|
|
|
|
*ret = NDISC_ROUTER_RAW(rt);
|
|
|
|
*size = rt->raw_size;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int ndisc_router_parse(sd_ndisc_router *rt) {
|
|
|
|
struct nd_router_advert *a;
|
|
|
|
const uint8_t *p;
|
|
|
|
bool has_mtu = false, has_flag_extension = false;
|
|
|
|
size_t left;
|
|
|
|
|
|
|
|
assert(rt);
|
|
|
|
|
|
|
|
if (rt->raw_size < sizeof(struct nd_router_advert)) {
|
|
|
|
log_ndisc("Too small to be a router advertisement, ignoring.");
|
|
|
|
return -EBADMSG;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Router advertisement packets are neatly aligned to 64bit boundaries, hence we can access them directly */
|
|
|
|
a = NDISC_ROUTER_RAW(rt);
|
|
|
|
|
|
|
|
if (a->nd_ra_type != ND_ROUTER_ADVERT) {
|
|
|
|
log_ndisc("Received ND packet that is not a router advertisement, ignoring.");
|
|
|
|
return -EBADMSG;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (a->nd_ra_code != 0) {
|
|
|
|
log_ndisc("Received ND packet with wrong RA code, ignoring.");
|
|
|
|
return -EBADMSG;
|
|
|
|
}
|
|
|
|
|
|
|
|
rt->hop_limit = a->nd_ra_curhoplimit;
|
|
|
|
rt->flags = a->nd_ra_flags_reserved; /* the first 8bit */
|
|
|
|
rt->lifetime = be16toh(a->nd_ra_router_lifetime);
|
|
|
|
|
|
|
|
rt->preference = (rt->flags >> 3) & 3;
|
|
|
|
if (!IN_SET(rt->preference, SD_NDISC_PREFERENCE_LOW, SD_NDISC_PREFERENCE_HIGH))
|
|
|
|
rt->preference = SD_NDISC_PREFERENCE_MEDIUM;
|
|
|
|
|
|
|
|
p = (const uint8_t*) NDISC_ROUTER_RAW(rt) + sizeof(struct nd_router_advert);
|
|
|
|
left = rt->raw_size - sizeof(struct nd_router_advert);
|
|
|
|
|
|
|
|
for (;;) {
|
|
|
|
uint8_t type;
|
|
|
|
size_t length;
|
|
|
|
|
|
|
|
if (left == 0)
|
|
|
|
break;
|
|
|
|
|
|
|
|
if (left < 2) {
|
|
|
|
log_ndisc("Option lacks header, ignoring datagram.");
|
|
|
|
return -EBADMSG;
|
|
|
|
}
|
|
|
|
|
|
|
|
type = p[0];
|
|
|
|
length = p[1] * 8;
|
|
|
|
|
|
|
|
if (length == 0) {
|
|
|
|
log_ndisc("Zero-length option, ignoring datagram.");
|
|
|
|
return -EBADMSG;
|
|
|
|
}
|
|
|
|
if (left < length) {
|
|
|
|
log_ndisc("Option truncated, ignoring datagram.");
|
|
|
|
return -EBADMSG;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (type) {
|
|
|
|
|
|
|
|
case SD_NDISC_OPTION_PREFIX_INFORMATION:
|
|
|
|
|
|
|
|
if (length != 4*8) {
|
|
|
|
log_ndisc("Prefix option of invalid size, ignoring datagram.");
|
|
|
|
return -EBADMSG;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (p[2] > 128) {
|
|
|
|
log_ndisc("Bad prefix length, ignoring datagram.");
|
|
|
|
return -EBADMSG;
|
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
case SD_NDISC_OPTION_MTU: {
|
|
|
|
uint32_t m;
|
|
|
|
|
|
|
|
if (has_mtu) {
|
|
|
|
log_ndisc("MTU option specified twice, ignoring.");
|
2018-09-28 12:28:05 +02:00
|
|
|
break;
|
network: beef up ipv6 RA support considerably
This reworks sd-ndisc and networkd substantially to support IPv6 RA much more
comprehensively. Since the API is extended quite a bit networkd has been ported
over too, and the patch is not as straight-forward as one could wish. The
rework includes:
- Support for DNSSL, RDNSS and RA routing options in sd-ndisc and networkd. Two
new configuration options have been added to networkd to make this
configurable.
- sd-ndisc now exposes an sd_ndisc_router object that encapsulates a full RA
message, and has direct, friendly acessor functions for the singleton RA
properties, as well as an iterative interface to iterate through known and
unsupported options. The router object may either be retrieved from the wire,
or generated from raw data. In many ways the sd-ndisc API now matches the
sd-lldp API, except that no implicit database of seen data is kept. (Note
that sd-ndisc actually had a half-written, but unused implementaiton of such
a store, which is removed now.)
- sd-ndisc will now collect the reception timestamps of RA, which is useful to
make sd_ndisc_router fully descriptive of what it covers.
Fixes: #1079
2016-06-02 20:38:12 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (length != 8) {
|
|
|
|
log_ndisc("MTU option of invalid size, ignoring datagram.");
|
|
|
|
return -EBADMSG;
|
|
|
|
}
|
|
|
|
|
|
|
|
m = be32toh(*(uint32_t*) (p + 4));
|
|
|
|
if (m >= IPV6_MIN_MTU) /* ignore invalidly small MTUs */
|
|
|
|
rt->mtu = m;
|
|
|
|
|
|
|
|
has_mtu = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case SD_NDISC_OPTION_ROUTE_INFORMATION:
|
|
|
|
if (length < 1*8 || length > 3*8) {
|
|
|
|
log_ndisc("Route information option of invalid size, ignoring datagram.");
|
|
|
|
return -EBADMSG;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (p[2] > 128) {
|
|
|
|
log_ndisc("Bad route prefix length, ignoring datagram.");
|
|
|
|
return -EBADMSG;
|
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
case SD_NDISC_OPTION_RDNSS:
|
|
|
|
if (length < 3*8 || (length % (2*8)) != 1*8) {
|
|
|
|
log_ndisc("RDNSS option has invalid size.");
|
|
|
|
return -EBADMSG;
|
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
case SD_NDISC_OPTION_FLAGS_EXTENSION:
|
|
|
|
|
|
|
|
if (has_flag_extension) {
|
|
|
|
log_ndisc("Flags extension option specified twice, ignoring.");
|
2018-09-28 12:28:05 +02:00
|
|
|
break;
|
network: beef up ipv6 RA support considerably
This reworks sd-ndisc and networkd substantially to support IPv6 RA much more
comprehensively. Since the API is extended quite a bit networkd has been ported
over too, and the patch is not as straight-forward as one could wish. The
rework includes:
- Support for DNSSL, RDNSS and RA routing options in sd-ndisc and networkd. Two
new configuration options have been added to networkd to make this
configurable.
- sd-ndisc now exposes an sd_ndisc_router object that encapsulates a full RA
message, and has direct, friendly acessor functions for the singleton RA
properties, as well as an iterative interface to iterate through known and
unsupported options. The router object may either be retrieved from the wire,
or generated from raw data. In many ways the sd-ndisc API now matches the
sd-lldp API, except that no implicit database of seen data is kept. (Note
that sd-ndisc actually had a half-written, but unused implementaiton of such
a store, which is removed now.)
- sd-ndisc will now collect the reception timestamps of RA, which is useful to
make sd_ndisc_router fully descriptive of what it covers.
Fixes: #1079
2016-06-02 20:38:12 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (length < 1*8) {
|
|
|
|
log_ndisc("Flags extension option has invalid size.");
|
|
|
|
return -EBADMSG;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Add in the additional flags bits */
|
|
|
|
rt->flags |=
|
|
|
|
((uint64_t) p[2] << 8) |
|
|
|
|
((uint64_t) p[3] << 16) |
|
|
|
|
((uint64_t) p[4] << 24) |
|
|
|
|
((uint64_t) p[5] << 32) |
|
|
|
|
((uint64_t) p[6] << 40) |
|
|
|
|
((uint64_t) p[7] << 48);
|
|
|
|
|
|
|
|
has_flag_extension = true;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case SD_NDISC_OPTION_DNSSL:
|
|
|
|
if (length < 2*8) {
|
|
|
|
log_ndisc("DNSSL option has invalid size.");
|
|
|
|
return -EBADMSG;
|
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
p += length, left -= length;
|
|
|
|
}
|
|
|
|
|
|
|
|
rt->rindex = sizeof(struct nd_router_advert);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
_public_ int sd_ndisc_router_get_hop_limit(sd_ndisc_router *rt, uint8_t *ret) {
|
|
|
|
assert_return(rt, -EINVAL);
|
|
|
|
assert_return(ret, -EINVAL);
|
|
|
|
|
|
|
|
*ret = rt->hop_limit;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
_public_ int sd_ndisc_router_get_flags(sd_ndisc_router *rt, uint64_t *ret_flags) {
|
|
|
|
assert_return(rt, -EINVAL);
|
|
|
|
assert_return(ret_flags, -EINVAL);
|
|
|
|
|
|
|
|
*ret_flags = rt->flags;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
_public_ int sd_ndisc_router_get_lifetime(sd_ndisc_router *rt, uint16_t *ret_lifetime) {
|
|
|
|
assert_return(rt, -EINVAL);
|
|
|
|
assert_return(ret_lifetime, -EINVAL);
|
|
|
|
|
|
|
|
*ret_lifetime = rt->lifetime;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
_public_ int sd_ndisc_router_get_preference(sd_ndisc_router *rt, unsigned *ret) {
|
|
|
|
assert_return(rt, -EINVAL);
|
|
|
|
assert_return(ret, -EINVAL);
|
|
|
|
|
|
|
|
*ret = rt->preference;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
_public_ int sd_ndisc_router_get_mtu(sd_ndisc_router *rt, uint32_t *ret) {
|
|
|
|
assert_return(rt, -EINVAL);
|
|
|
|
assert_return(ret, -EINVAL);
|
|
|
|
|
|
|
|
if (rt->mtu <= 0)
|
|
|
|
return -ENODATA;
|
|
|
|
|
|
|
|
*ret = rt->mtu;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
_public_ int sd_ndisc_router_option_rewind(sd_ndisc_router *rt) {
|
|
|
|
assert_return(rt, -EINVAL);
|
|
|
|
|
|
|
|
assert(rt->raw_size >= sizeof(struct nd_router_advert));
|
|
|
|
rt->rindex = sizeof(struct nd_router_advert);
|
|
|
|
|
|
|
|
return rt->rindex < rt->raw_size;
|
|
|
|
}
|
|
|
|
|
|
|
|
_public_ int sd_ndisc_router_option_next(sd_ndisc_router *rt) {
|
|
|
|
size_t length;
|
|
|
|
|
|
|
|
assert_return(rt, -EINVAL);
|
|
|
|
|
|
|
|
if (rt->rindex == rt->raw_size) /* EOF */
|
|
|
|
return -ESPIPE;
|
|
|
|
|
|
|
|
if (rt->rindex + 2 > rt->raw_size) /* Truncated message */
|
|
|
|
return -EBADMSG;
|
|
|
|
|
|
|
|
length = NDISC_ROUTER_OPTION_LENGTH(rt);
|
|
|
|
if (rt->rindex + length > rt->raw_size)
|
|
|
|
return -EBADMSG;
|
|
|
|
|
|
|
|
rt->rindex += length;
|
|
|
|
return rt->rindex < rt->raw_size;
|
|
|
|
}
|
|
|
|
|
|
|
|
_public_ int sd_ndisc_router_option_get_type(sd_ndisc_router *rt, uint8_t *ret) {
|
|
|
|
assert_return(rt, -EINVAL);
|
|
|
|
assert_return(ret, -EINVAL);
|
|
|
|
|
|
|
|
if (rt->rindex == rt->raw_size) /* EOF */
|
|
|
|
return -ESPIPE;
|
|
|
|
|
|
|
|
if (rt->rindex + 2 > rt->raw_size) /* Truncated message */
|
|
|
|
return -EBADMSG;
|
|
|
|
|
|
|
|
*ret = NDISC_ROUTER_OPTION_TYPE(rt);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
_public_ int sd_ndisc_router_option_is_type(sd_ndisc_router *rt, uint8_t type) {
|
|
|
|
uint8_t k;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
assert_return(rt, -EINVAL);
|
|
|
|
|
|
|
|
r = sd_ndisc_router_option_get_type(rt, &k);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
return type == k;
|
|
|
|
}
|
|
|
|
|
|
|
|
_public_ int sd_ndisc_router_option_get_raw(sd_ndisc_router *rt, const void **ret, size_t *size) {
|
|
|
|
size_t length;
|
|
|
|
|
|
|
|
assert_return(rt, -EINVAL);
|
|
|
|
assert_return(ret, -EINVAL);
|
|
|
|
assert_return(size, -EINVAL);
|
|
|
|
|
|
|
|
/* Note that this returns the full option, including the option header */
|
|
|
|
|
|
|
|
if (rt->rindex + 2 > rt->raw_size)
|
|
|
|
return -EBADMSG;
|
|
|
|
|
|
|
|
length = NDISC_ROUTER_OPTION_LENGTH(rt);
|
|
|
|
if (rt->rindex + length > rt->raw_size)
|
|
|
|
return -EBADMSG;
|
|
|
|
|
|
|
|
*ret = (uint8_t*) NDISC_ROUTER_RAW(rt) + rt->rindex;
|
|
|
|
*size = length;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int get_prefix_info(sd_ndisc_router *rt, struct nd_opt_prefix_info **ret) {
|
|
|
|
struct nd_opt_prefix_info *ri;
|
|
|
|
size_t length;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(rt);
|
|
|
|
assert(ret);
|
|
|
|
|
|
|
|
r = sd_ndisc_router_option_is_type(rt, SD_NDISC_OPTION_PREFIX_INFORMATION);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
if (r == 0)
|
|
|
|
return -EMEDIUMTYPE;
|
|
|
|
|
|
|
|
length = NDISC_ROUTER_OPTION_LENGTH(rt);
|
|
|
|
if (length != sizeof(struct nd_opt_prefix_info))
|
|
|
|
return -EBADMSG;
|
|
|
|
|
|
|
|
ri = (struct nd_opt_prefix_info*) ((uint8_t*) NDISC_ROUTER_RAW(rt) + rt->rindex);
|
|
|
|
if (ri->nd_opt_pi_prefix_len > 128)
|
|
|
|
return -EBADMSG;
|
|
|
|
|
|
|
|
*ret = ri;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
_public_ int sd_ndisc_router_prefix_get_valid_lifetime(sd_ndisc_router *rt, uint32_t *ret) {
|
|
|
|
struct nd_opt_prefix_info *ri;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
assert_return(rt, -EINVAL);
|
|
|
|
assert_return(ret, -EINVAL);
|
|
|
|
|
|
|
|
r = get_prefix_info(rt, &ri);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
*ret = be32toh(ri->nd_opt_pi_valid_time);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
_public_ int sd_ndisc_router_prefix_get_preferred_lifetime(sd_ndisc_router *rt, uint32_t *ret) {
|
|
|
|
struct nd_opt_prefix_info *pi;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
assert_return(rt, -EINVAL);
|
|
|
|
assert_return(ret, -EINVAL);
|
|
|
|
|
|
|
|
r = get_prefix_info(rt, &pi);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
*ret = be32toh(pi->nd_opt_pi_preferred_time);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
_public_ int sd_ndisc_router_prefix_get_flags(sd_ndisc_router *rt, uint8_t *ret) {
|
|
|
|
struct nd_opt_prefix_info *pi;
|
2016-12-20 20:27:06 +01:00
|
|
|
uint8_t flags;
|
network: beef up ipv6 RA support considerably
This reworks sd-ndisc and networkd substantially to support IPv6 RA much more
comprehensively. Since the API is extended quite a bit networkd has been ported
over too, and the patch is not as straight-forward as one could wish. The
rework includes:
- Support for DNSSL, RDNSS and RA routing options in sd-ndisc and networkd. Two
new configuration options have been added to networkd to make this
configurable.
- sd-ndisc now exposes an sd_ndisc_router object that encapsulates a full RA
message, and has direct, friendly acessor functions for the singleton RA
properties, as well as an iterative interface to iterate through known and
unsupported options. The router object may either be retrieved from the wire,
or generated from raw data. In many ways the sd-ndisc API now matches the
sd-lldp API, except that no implicit database of seen data is kept. (Note
that sd-ndisc actually had a half-written, but unused implementaiton of such
a store, which is removed now.)
- sd-ndisc will now collect the reception timestamps of RA, which is useful to
make sd_ndisc_router fully descriptive of what it covers.
Fixes: #1079
2016-06-02 20:38:12 +02:00
|
|
|
int r;
|
|
|
|
|
|
|
|
assert_return(rt, -EINVAL);
|
|
|
|
assert_return(ret, -EINVAL);
|
|
|
|
|
|
|
|
r = get_prefix_info(rt, &pi);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
2016-12-20 20:27:06 +01:00
|
|
|
flags = pi->nd_opt_pi_flags_reserved;
|
|
|
|
|
|
|
|
if ((flags & ND_OPT_PI_FLAG_AUTO) && (pi->nd_opt_pi_prefix_len != 64)) {
|
|
|
|
log_ndisc("Invalid prefix length, ignoring prefix for stateless autoconfiguration.");
|
|
|
|
flags &= ~ND_OPT_PI_FLAG_AUTO;
|
|
|
|
}
|
|
|
|
|
|
|
|
*ret = flags;
|
network: beef up ipv6 RA support considerably
This reworks sd-ndisc and networkd substantially to support IPv6 RA much more
comprehensively. Since the API is extended quite a bit networkd has been ported
over too, and the patch is not as straight-forward as one could wish. The
rework includes:
- Support for DNSSL, RDNSS and RA routing options in sd-ndisc and networkd. Two
new configuration options have been added to networkd to make this
configurable.
- sd-ndisc now exposes an sd_ndisc_router object that encapsulates a full RA
message, and has direct, friendly acessor functions for the singleton RA
properties, as well as an iterative interface to iterate through known and
unsupported options. The router object may either be retrieved from the wire,
or generated from raw data. In many ways the sd-ndisc API now matches the
sd-lldp API, except that no implicit database of seen data is kept. (Note
that sd-ndisc actually had a half-written, but unused implementaiton of such
a store, which is removed now.)
- sd-ndisc will now collect the reception timestamps of RA, which is useful to
make sd_ndisc_router fully descriptive of what it covers.
Fixes: #1079
2016-06-02 20:38:12 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
_public_ int sd_ndisc_router_prefix_get_address(sd_ndisc_router *rt, struct in6_addr *ret_addr) {
|
|
|
|
struct nd_opt_prefix_info *pi;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
assert_return(rt, -EINVAL);
|
|
|
|
assert_return(ret_addr, -EINVAL);
|
|
|
|
|
|
|
|
r = get_prefix_info(rt, &pi);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
*ret_addr = pi->nd_opt_pi_prefix;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
_public_ int sd_ndisc_router_prefix_get_prefixlen(sd_ndisc_router *rt, unsigned *ret) {
|
|
|
|
struct nd_opt_prefix_info *pi;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
assert_return(rt, -EINVAL);
|
|
|
|
assert_return(ret, -EINVAL);
|
|
|
|
|
|
|
|
r = get_prefix_info(rt, &pi);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
if (pi->nd_opt_pi_prefix_len > 128)
|
|
|
|
return -EBADMSG;
|
|
|
|
|
|
|
|
*ret = pi->nd_opt_pi_prefix_len;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int get_route_info(sd_ndisc_router *rt, uint8_t **ret) {
|
|
|
|
uint8_t *ri;
|
|
|
|
size_t length;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(rt);
|
|
|
|
assert(ret);
|
|
|
|
|
|
|
|
r = sd_ndisc_router_option_is_type(rt, SD_NDISC_OPTION_ROUTE_INFORMATION);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
if (r == 0)
|
|
|
|
return -EMEDIUMTYPE;
|
|
|
|
|
|
|
|
length = NDISC_ROUTER_OPTION_LENGTH(rt);
|
|
|
|
if (length < 1*8 || length > 3*8)
|
|
|
|
return -EBADMSG;
|
|
|
|
|
|
|
|
ri = (uint8_t*) NDISC_ROUTER_RAW(rt) + rt->rindex;
|
|
|
|
|
|
|
|
if (ri[2] > 128)
|
|
|
|
return -EBADMSG;
|
|
|
|
|
|
|
|
*ret = ri;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
_public_ int sd_ndisc_router_route_get_lifetime(sd_ndisc_router *rt, uint32_t *ret) {
|
|
|
|
uint8_t *ri;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
assert_return(rt, -EINVAL);
|
|
|
|
assert_return(ret, -EINVAL);
|
|
|
|
|
|
|
|
r = get_route_info(rt, &ri);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
*ret = be32toh(*(uint32_t*) (ri + 4));
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
_public_ int sd_ndisc_router_route_get_address(sd_ndisc_router *rt, struct in6_addr *ret_addr) {
|
|
|
|
uint8_t *ri;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
assert_return(rt, -EINVAL);
|
|
|
|
assert_return(ret_addr, -EINVAL);
|
|
|
|
|
|
|
|
r = get_route_info(rt, &ri);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
zero(*ret_addr);
|
|
|
|
memcpy(ret_addr, ri + 8, NDISC_ROUTER_OPTION_LENGTH(rt) - 8);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
_public_ int sd_ndisc_router_route_get_prefixlen(sd_ndisc_router *rt, unsigned *ret) {
|
|
|
|
uint8_t *ri;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
assert_return(rt, -EINVAL);
|
|
|
|
assert_return(ret, -EINVAL);
|
|
|
|
|
|
|
|
r = get_route_info(rt, &ri);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
*ret = ri[2];
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
_public_ int sd_ndisc_router_route_get_preference(sd_ndisc_router *rt, unsigned *ret) {
|
|
|
|
uint8_t *ri;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
assert_return(rt, -EINVAL);
|
|
|
|
assert_return(ret, -EINVAL);
|
|
|
|
|
|
|
|
r = get_route_info(rt, &ri);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
*ret = (ri[3] >> 3) & 3;
|
|
|
|
if (!IN_SET(*ret, SD_NDISC_PREFERENCE_LOW, SD_NDISC_PREFERENCE_HIGH))
|
|
|
|
*ret = SD_NDISC_PREFERENCE_MEDIUM;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int get_rdnss_info(sd_ndisc_router *rt, uint8_t **ret) {
|
|
|
|
size_t length;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(rt);
|
|
|
|
assert(ret);
|
|
|
|
|
|
|
|
r = sd_ndisc_router_option_is_type(rt, SD_NDISC_OPTION_RDNSS);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
if (r == 0)
|
|
|
|
return -EMEDIUMTYPE;
|
|
|
|
|
|
|
|
length = NDISC_ROUTER_OPTION_LENGTH(rt);
|
|
|
|
if (length < 3*8 || (length % (2*8)) != 1*8)
|
|
|
|
return -EBADMSG;
|
|
|
|
|
|
|
|
*ret = (uint8_t*) NDISC_ROUTER_RAW(rt) + rt->rindex;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
_public_ int sd_ndisc_router_rdnss_get_addresses(sd_ndisc_router *rt, const struct in6_addr **ret) {
|
|
|
|
uint8_t *ri;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
assert_return(rt, -EINVAL);
|
|
|
|
assert_return(ret, -EINVAL);
|
|
|
|
|
|
|
|
r = get_rdnss_info(rt, &ri);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
*ret = (const struct in6_addr*) (ri + 8);
|
|
|
|
return (NDISC_ROUTER_OPTION_LENGTH(rt) - 8) / 16;
|
|
|
|
}
|
|
|
|
|
|
|
|
_public_ int sd_ndisc_router_rdnss_get_lifetime(sd_ndisc_router *rt, uint32_t *ret) {
|
|
|
|
uint8_t *ri;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
assert_return(rt, -EINVAL);
|
|
|
|
assert_return(ret, -EINVAL);
|
|
|
|
|
|
|
|
r = get_rdnss_info(rt, &ri);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
*ret = be32toh(*(uint32_t*) (ri + 4));
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int get_dnssl_info(sd_ndisc_router *rt, uint8_t **ret) {
|
|
|
|
size_t length;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(rt);
|
|
|
|
assert(ret);
|
|
|
|
|
|
|
|
r = sd_ndisc_router_option_is_type(rt, SD_NDISC_OPTION_DNSSL);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
if (r == 0)
|
|
|
|
return -EMEDIUMTYPE;
|
|
|
|
|
|
|
|
length = NDISC_ROUTER_OPTION_LENGTH(rt);
|
|
|
|
if (length < 2*8)
|
|
|
|
return -EBADMSG;
|
|
|
|
|
|
|
|
*ret = (uint8_t*) NDISC_ROUTER_RAW(rt) + rt->rindex;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
_public_ int sd_ndisc_router_dnssl_get_domains(sd_ndisc_router *rt, char ***ret) {
|
|
|
|
_cleanup_strv_free_ char **l = NULL;
|
|
|
|
_cleanup_free_ char *e = NULL;
|
|
|
|
size_t allocated = 0, n = 0, left;
|
|
|
|
uint8_t *ri, *p;
|
|
|
|
bool first = true;
|
|
|
|
int r;
|
|
|
|
unsigned k = 0;
|
|
|
|
|
|
|
|
assert_return(rt, -EINVAL);
|
|
|
|
assert_return(ret, -EINVAL);
|
|
|
|
|
|
|
|
r = get_dnssl_info(rt, &ri);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
p = ri + 8;
|
|
|
|
left = NDISC_ROUTER_OPTION_LENGTH(rt) - 8;
|
|
|
|
|
|
|
|
for (;;) {
|
|
|
|
if (left == 0) {
|
|
|
|
|
|
|
|
if (n > 0) /* Not properly NUL terminated */
|
|
|
|
return -EBADMSG;
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (*p == 0) {
|
|
|
|
/* Found NUL termination */
|
|
|
|
|
|
|
|
if (n > 0) {
|
|
|
|
_cleanup_free_ char *normalized = NULL;
|
|
|
|
|
|
|
|
e[n] = 0;
|
resolve: reject host names with leading or trailing dashes in /etc/hosts
https://tools.ietf.org/html/rfc1035#section-2.3.1 says (approximately)
that only letters, numbers, and non-leading non-trailing dashes are allowed
(for entries with A/AAAA records). We set no restrictions.
hosts(5) says:
> Host names may contain only alphanumeric characters, minus signs ("-"), and
> periods ("."). They must begin with an alphabetic character and end with an
> alphanumeric character.
nss-files follows those rules, and will ignore names in /etc/hosts that do not
follow this rule.
Let's follow the documented rules for /etc/hosts. In particular, this makes us
consitent with nss-files, reducing surprises for the user.
I'm pretty sure we should apply stricter filtering to names received over DNS
and LLMNR and MDNS, but it's a bigger project, because the rules differ
depepending on which level the label appears (rules for top-level names are
stricter), and this patch takes the minimalistic approach and only changes
behaviour for /etc/hosts.
Escape syntax is also disallowed in /etc/hosts, even if the resulting character
would be allowed. Other tools that parse /etc/hosts do not support this, and
there is no need to use it because no allowed characters benefit from escaping.
2018-11-21 22:58:13 +01:00
|
|
|
r = dns_name_normalize(e, 0, &normalized);
|
network: beef up ipv6 RA support considerably
This reworks sd-ndisc and networkd substantially to support IPv6 RA much more
comprehensively. Since the API is extended quite a bit networkd has been ported
over too, and the patch is not as straight-forward as one could wish. The
rework includes:
- Support for DNSSL, RDNSS and RA routing options in sd-ndisc and networkd. Two
new configuration options have been added to networkd to make this
configurable.
- sd-ndisc now exposes an sd_ndisc_router object that encapsulates a full RA
message, and has direct, friendly acessor functions for the singleton RA
properties, as well as an iterative interface to iterate through known and
unsupported options. The router object may either be retrieved from the wire,
or generated from raw data. In many ways the sd-ndisc API now matches the
sd-lldp API, except that no implicit database of seen data is kept. (Note
that sd-ndisc actually had a half-written, but unused implementaiton of such
a store, which is removed now.)
- sd-ndisc will now collect the reception timestamps of RA, which is useful to
make sd_ndisc_router fully descriptive of what it covers.
Fixes: #1079
2016-06-02 20:38:12 +02:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
/* Ignore the root domain name or "localhost" and friends */
|
|
|
|
if (!is_localhost(normalized) &&
|
|
|
|
!dns_name_is_root(normalized)) {
|
|
|
|
|
|
|
|
if (strv_push(&l, normalized) < 0)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
normalized = NULL;
|
|
|
|
k++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
n = 0;
|
|
|
|
first = true;
|
|
|
|
p++, left--;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Check for compression (which is not allowed) */
|
|
|
|
if (*p > 63)
|
|
|
|
return -EBADMSG;
|
|
|
|
|
|
|
|
if (1U + *p + 1U > left)
|
|
|
|
return -EBADMSG;
|
|
|
|
|
|
|
|
if (!GREEDY_REALLOC(e, allocated, n + !first + DNS_LABEL_ESCAPED_MAX + 1U))
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
if (first)
|
|
|
|
first = false;
|
|
|
|
else
|
|
|
|
e[n++] = '.';
|
|
|
|
|
|
|
|
r = dns_label_escape((char*) p+1, *p, e + n, DNS_LABEL_ESCAPED_MAX);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
n += r;
|
|
|
|
|
|
|
|
left -= 1 + *p;
|
|
|
|
p += 1 + *p;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (strv_isempty(l)) {
|
|
|
|
*ret = NULL;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2018-04-05 07:26:26 +02:00
|
|
|
*ret = TAKE_PTR(l);
|
network: beef up ipv6 RA support considerably
This reworks sd-ndisc and networkd substantially to support IPv6 RA much more
comprehensively. Since the API is extended quite a bit networkd has been ported
over too, and the patch is not as straight-forward as one could wish. The
rework includes:
- Support for DNSSL, RDNSS and RA routing options in sd-ndisc and networkd. Two
new configuration options have been added to networkd to make this
configurable.
- sd-ndisc now exposes an sd_ndisc_router object that encapsulates a full RA
message, and has direct, friendly acessor functions for the singleton RA
properties, as well as an iterative interface to iterate through known and
unsupported options. The router object may either be retrieved from the wire,
or generated from raw data. In many ways the sd-ndisc API now matches the
sd-lldp API, except that no implicit database of seen data is kept. (Note
that sd-ndisc actually had a half-written, but unused implementaiton of such
a store, which is removed now.)
- sd-ndisc will now collect the reception timestamps of RA, which is useful to
make sd_ndisc_router fully descriptive of what it covers.
Fixes: #1079
2016-06-02 20:38:12 +02:00
|
|
|
|
|
|
|
return k;
|
|
|
|
}
|
|
|
|
|
|
|
|
_public_ int sd_ndisc_router_dnssl_get_lifetime(sd_ndisc_router *rt, uint32_t *ret_sec) {
|
|
|
|
uint8_t *ri;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
assert_return(rt, -EINVAL);
|
|
|
|
assert_return(ret_sec, -EINVAL);
|
|
|
|
|
|
|
|
r = get_dnssl_info(rt, &ri);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
*ret_sec = be32toh(*(uint32_t*) (ri + 4));
|
|
|
|
return 0;
|
|
|
|
}
|