summaryrefslogtreecommitdiff
path: root/usr.sbin/rad
diff options
context:
space:
mode:
authorFlorian Obser <florian@cvs.openbsd.org>2024-05-31 16:10:43 +0000
committerFlorian Obser <florian@cvs.openbsd.org>2024-05-31 16:10:43 +0000
commit3437f05a569f25ee474836ca3d444faa90ce6b60 (patch)
treec64969869e20896656f49e8854f5a4ee072e5453 /usr.sbin/rad
parentfd9400319906e4d73e4a5bcb038e2337573e1b50 (diff)
Prefixes delegated via DHCPv6 have a lifetime, honour it.
The "auto prefix" feature derives the prefix to announce from a configured IPv6 address. If that address has a vltime / pltime use that value in router advertisements instead of statically configured values. We also need to count down the vltime / pltime as time progresses. testing Ryan Vogt testing & OK bket@, jmatthew@
Diffstat (limited to 'usr.sbin/rad')
-rw-r--r--usr.sbin/rad/frontend.c129
-rw-r--r--usr.sbin/rad/rad.h5
2 files changed, 111 insertions, 23 deletions
diff --git a/usr.sbin/rad/frontend.c b/usr.sbin/rad/frontend.c
index 56bd0a50051..e0beb335295 100644
--- a/usr.sbin/rad/frontend.c
+++ b/usr.sbin/rad/frontend.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: frontend.c,v 1.47 2024/05/31 16:10:02 florian Exp $ */
+/* $OpenBSD: frontend.c,v 1.48 2024/05/31 16:10:42 florian Exp $ */
/*
* Copyright (c) 2018 Florian Obser <florian@openbsd.org>
@@ -110,6 +110,7 @@ struct ra_iface {
int removed;
int link_state;
int prefix_count;
+ int ltime_decaying;
size_t datalen;
uint8_t data[RA_MAX_SIZE];
};
@@ -149,12 +150,13 @@ struct icmp6_ev *get_icmp6ev_by_rdomain(int);
void unref_icmp6ev(struct ra_iface *);
void set_icmp6sock(int, int);
void add_new_prefix_to_ra_iface(struct ra_iface *r,
- struct in6_addr *, int, struct ra_prefix_conf *);
+ struct in6_addr *, int, struct ra_prefix_conf *,
+ uint32_t, uint32_t);
void free_ra_iface(struct ra_iface *);
int in6_mask2prefixlen(struct in6_addr *);
void get_interface_prefixes(struct ra_iface *,
struct ra_prefix_conf *, struct ifaddrs *);
-void build_packet(struct ra_iface *);
+int build_packet(struct ra_iface *);
void build_leaving_packet(struct ra_iface *);
void ra_output(struct ra_iface *, struct sockaddr_in6 *);
void get_rtaddrs(int, struct sockaddr *,
@@ -961,14 +963,21 @@ merge_ra_interfaces(void)
entry) {
add_new_prefix_to_ra_iface(ra_iface,
&ra_prefix_conf->prefix,
- ra_prefix_conf->prefixlen, ra_prefix_conf);
+ ra_prefix_conf->prefixlen, ra_prefix_conf,
+ ND6_INFINITE_LIFETIME, ND6_INFINITE_LIFETIME);
}
if (ra_iface_conf->autoprefix)
get_interface_prefixes(ra_iface,
ra_iface_conf->autoprefix, ifap);
- build_packet(ra_iface);
+ if (build_packet(ra_iface)) {
+ /* packet changed; send new advertisements */
+ if (event_initialized(&ra_iface->icmp6ev->ev))
+ frontend_imsg_compose_engine(IMSG_UPDATE_IF, 0,
+ &ra_iface->if_index,
+ sizeof(ra_iface->if_index));
+ }
}
freeifaddrs(ifap);
}
@@ -1016,20 +1025,22 @@ in6_mask2prefixlen(struct in6_addr *in6)
void
get_interface_prefixes(struct ra_iface *ra_iface, struct ra_prefix_conf
- *autoprefix, struct ifaddrs *ifap)
+ *autoprefix_conf, struct ifaddrs *ifap)
{
struct in6_ifreq ifr6;
struct ifaddrs *ifa;
struct sockaddr_in6 *sin6;
+ uint32_t decaying_vltime, decaying_pltime;
int prefixlen;
for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next) {
- if (strcmp(ra_iface->name, ifa->ifa_name) != 0)
- continue;
if (ifa->ifa_addr == NULL ||
ifa->ifa_addr->sa_family != AF_INET6)
continue;
+ if (strcmp(ra_iface->name, ifa->ifa_name) != 0)
+ continue;
+
sin6 = (struct sockaddr_in6 *)ifa->ifa_addr;
if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr))
@@ -1039,6 +1050,24 @@ get_interface_prefixes(struct ra_iface *ra_iface, struct ra_prefix_conf
strlcpy(ifr6.ifr_name, ra_iface->name, sizeof(ifr6.ifr_name));
memcpy(&ifr6.ifr_addr, sin6, sizeof(ifr6.ifr_addr));
+ decaying_vltime = ND6_INFINITE_LIFETIME;
+ decaying_pltime = ND6_INFINITE_LIFETIME;
+
+ if (ioctl(ioctlsock, SIOCGIFALIFETIME_IN6,
+ (caddr_t)&ifr6) != -1) {
+ struct in6_addrlifetime *lifetime;
+
+ lifetime = &ifr6.ifr_ifru.ifru_lifetime;
+ if (lifetime->ia6t_preferred)
+ decaying_pltime = lifetime->ia6t_preferred;
+ if (lifetime->ia6t_expire)
+ decaying_vltime = lifetime->ia6t_expire;
+ }
+
+ memset(&ifr6, 0, sizeof(ifr6));
+ strlcpy(ifr6.ifr_name, ra_iface->name, sizeof(ifr6.ifr_name));
+ memcpy(&ifr6.ifr_addr, sin6, sizeof(ifr6.ifr_addr));
+
if (ioctl(ioctlsock, SIOCGIFNETMASK_IN6, (caddr_t)&ifr6) == -1)
continue; /* addr got deleted while we were looking */
@@ -1051,7 +1080,8 @@ get_interface_prefixes(struct ra_iface *ra_iface, struct ra_prefix_conf
mask_prefix(&sin6->sin6_addr, prefixlen);
add_new_prefix_to_ra_iface(ra_iface, &sin6->sin6_addr,
- prefixlen, autoprefix);
+ prefixlen, autoprefix_conf, decaying_vltime,
+ decaying_pltime);
}
}
@@ -1072,13 +1102,41 @@ find_ra_prefix_conf(struct ra_prefix_conf_head* head, struct in6_addr *prefix,
void
add_new_prefix_to_ra_iface(struct ra_iface *ra_iface, struct in6_addr *addr,
- int prefixlen, struct ra_prefix_conf *ra_prefix_conf)
+ int prefixlen, struct ra_prefix_conf *ra_prefix_conf,
+ uint32_t decaying_vltime, uint32_t decaying_pltime)
{
struct ra_prefix_conf *new_ra_prefix_conf;
- if (find_ra_prefix_conf(&ra_iface->prefixes, addr, prefixlen)) {
- log_debug("ignoring duplicate %s/%d prefix",
- in6_to_str(addr), prefixlen);
+ if ((new_ra_prefix_conf = find_ra_prefix_conf(&ra_iface->prefixes, addr,
+ prefixlen)) != NULL) {
+ if (decaying_vltime != ND6_INFINITE_LIFETIME ||
+ decaying_pltime != ND6_INFINITE_LIFETIME) {
+ ra_iface->ltime_decaying = 1;
+ new_ra_prefix_conf->ltime_decaying = 0;
+ if (decaying_vltime != ND6_INFINITE_LIFETIME) {
+ new_ra_prefix_conf->vltime = decaying_vltime;
+ new_ra_prefix_conf->ltime_decaying |=
+ VLTIME_DECAYING;
+ }
+ if (decaying_pltime != ND6_INFINITE_LIFETIME) {
+ new_ra_prefix_conf->pltime = decaying_pltime;
+ new_ra_prefix_conf->ltime_decaying |=
+ PLTIME_DECAYING;
+ }
+ } else if (new_ra_prefix_conf->ltime_decaying) {
+ struct ra_prefix_conf *pc;
+
+ new_ra_prefix_conf->ltime_decaying = 0;
+ ra_iface->ltime_decaying = 0;
+ SIMPLEQ_FOREACH(pc, &ra_iface->prefixes, entry) {
+ if (pc->ltime_decaying) {
+ ra_iface->ltime_decaying = 1;
+ break;
+ }
+ }
+ } else
+ log_debug("ignoring duplicate %s/%d prefix",
+ in6_to_str(addr), prefixlen);
return;
}
@@ -1090,13 +1148,25 @@ add_new_prefix_to_ra_iface(struct ra_iface *ra_iface, struct in6_addr *addr,
new_ra_prefix_conf->prefixlen = prefixlen;
new_ra_prefix_conf->vltime = ra_prefix_conf->vltime;
new_ra_prefix_conf->pltime = ra_prefix_conf->pltime;
+ if (decaying_vltime != ND6_INFINITE_LIFETIME ||
+ decaying_pltime != ND6_INFINITE_LIFETIME) {
+ ra_iface->ltime_decaying = 1;
+ if (decaying_vltime != ND6_INFINITE_LIFETIME) {
+ new_ra_prefix_conf->vltime = decaying_vltime;
+ new_ra_prefix_conf->ltime_decaying |= VLTIME_DECAYING;
+ }
+ if (decaying_pltime != ND6_INFINITE_LIFETIME) {
+ new_ra_prefix_conf->pltime = decaying_pltime;
+ new_ra_prefix_conf->ltime_decaying |= PLTIME_DECAYING;
+ }
+ }
new_ra_prefix_conf->aflag = ra_prefix_conf->aflag;
new_ra_prefix_conf->lflag = ra_prefix_conf->lflag;
SIMPLEQ_INSERT_TAIL(&ra_iface->prefixes, new_ra_prefix_conf, entry);
ra_iface->prefix_count++;
}
-void
+int
build_packet(struct ra_iface *ra_iface)
{
struct nd_router_advert *ra;
@@ -1113,13 +1183,15 @@ build_packet(struct ra_iface *ra_iface)
struct ra_dnssl_conf *ra_dnssl;
struct ra_pref64_conf *pref64;
size_t len, label_len;
+ time_t t;
+ uint32_t vltime, pltime;
uint8_t *p, buf[RA_MAX_SIZE];
char *label_start, *label_end;
ra_iface_conf = find_ra_iface_conf(&frontend_conf->ra_iface_list,
ra_iface->conf_name);
ra_options_conf = &ra_iface_conf->ra_options;
-
+ t = time(NULL);
len = sizeof(*ra);
if (ra_iface_conf->ra_options.source_link_addr)
len += sizeof(*ndopt_source_link_addr);
@@ -1205,9 +1277,20 @@ build_packet(struct ra_iface *ra_iface)
if (ra_prefix_conf->aflag)
ndopt_pi->nd_opt_pi_flags_reserved |=
ND_OPT_PI_FLAG_AUTO;
- ndopt_pi->nd_opt_pi_valid_time = htonl(ra_prefix_conf->vltime);
- ndopt_pi->nd_opt_pi_preferred_time =
- htonl(ra_prefix_conf->pltime);
+
+ if (ra_prefix_conf->ltime_decaying & VLTIME_DECAYING)
+ vltime = ra_prefix_conf->vltime < t ? 0 :
+ ra_prefix_conf->vltime - t;
+ else
+ vltime = ra_prefix_conf->vltime;
+ if (ra_prefix_conf->ltime_decaying & PLTIME_DECAYING)
+ pltime = ra_prefix_conf->pltime < t ? 0 :
+ ra_prefix_conf->pltime - t;
+ else
+ pltime = ra_prefix_conf->pltime;
+
+ ndopt_pi->nd_opt_pi_valid_time = htonl(vltime);
+ ndopt_pi->nd_opt_pi_preferred_time = htonl(pltime);
ndopt_pi->nd_opt_pi_prefix = ra_prefix_conf->prefix;
p += sizeof(*ndopt_pi);
@@ -1301,11 +1384,9 @@ build_packet(struct ra_iface *ra_iface)
!= 0) {
memcpy(ra_iface->data, buf, len);
ra_iface->datalen = len;
- /* packet changed; tell engine to send new advertisements */
- if (event_initialized(&ra_iface->icmp6ev->ev))
- frontend_imsg_compose_engine(IMSG_UPDATE_IF, 0,
- &ra_iface->if_index, sizeof(ra_iface->if_index));
+ return 1;
}
+ return 0;
}
void
@@ -1333,6 +1414,10 @@ ra_output(struct ra_iface *ra_iface, struct sockaddr_in6 *to)
if (!LINK_STATE_IS_UP(ra_iface->link_state))
return;
+ if (ra_iface->ltime_decaying)
+ /* update vltime & pltime */
+ build_packet(ra_iface);
+
sndmhdr.msg_name = to;
sndmhdr.msg_iov[0].iov_base = ra_iface->data;
sndmhdr.msg_iov[0].iov_len = ra_iface->datalen;
diff --git a/usr.sbin/rad/rad.h b/usr.sbin/rad/rad.h
index 442ff00fcce..46cdc51ea64 100644
--- a/usr.sbin/rad/rad.h
+++ b/usr.sbin/rad/rad.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: rad.h,v 1.27 2024/05/17 06:50:14 florian Exp $ */
+/* $OpenBSD: rad.h,v 1.28 2024/05/31 16:10:42 florian Exp $ */
/*
* Copyright (c) 2018 Florian Obser <florian@openbsd.org>
@@ -35,6 +35,8 @@
#define MIN_DELAY_BETWEEN_RAS 3 /* 3 seconds */
#define MAX_SEARCH 1025 /* MAXDNAME in arpa/nameser.h */
#define DEFAULT_RDNS_LIFETIME 600 * 1.5
+#define PLTIME_DECAYING 1
+#define VLTIME_DECAYING 2
#define IMSG_DATA_SIZE(imsg) ((imsg).hdr.len - IMSG_HEADER_SIZE)
@@ -114,6 +116,7 @@ struct ra_prefix_conf {
int prefixlen; /* prefix length */
uint32_t vltime; /* valid lifetime */
uint32_t pltime; /* preferred lifetime */
+ int ltime_decaying;
int lflag; /* on-link flag*/
int aflag; /* autonom. addr flag */
};