From: Alexander Bluhm Subject: Re: Allow rad(8) to advertise shorter lifetimes To: Ryan Vogt , tech@openbsd.org Date: Sun, 14 Sep 2025 23:13:29 +0200 On Sun, Sep 14, 2025 at 01:05:33PM +0200, Florian Obser wrote: > Apologies for my silence and very late response, life happened... > > I fully agree that lifetimes should be limited and a excessively long > lifetimes handed out by a DHCPv6 server are a problem. > > I don't think we need a config option for this. The minimum of what we > find on an interface and what we have in the config file (including > defaults) should win. > > The following diff, inspired by your work, implements that. > Does this work for you? > Florian OK bluhm@ > diff --git frontend.c frontend.c > index 2a519dac0b1..97f4d0ba708 100644 > --- frontend.c > +++ frontend.c > @@ -110,7 +110,7 @@ struct ra_iface { > int removed; > int link_state; > int prefix_count; > - int ltime_decaying; > + int has_autoconf_prefix; > size_t datalen; > uint8_t data[RA_MAX_SIZE]; > }; > @@ -151,11 +151,12 @@ 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 *, > - uint32_t, uint32_t); > + int, 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 *); > +uint32_t calc_autoconf_ltime(time_t, uint32_t, uint32_t); > int build_packet(struct ra_iface *); > void build_leaving_packet(struct ra_iface *); > void ra_output(struct ra_iface *, struct sockaddr_in6 *); > @@ -979,7 +980,7 @@ 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, 0, > ND6_INFINITE_LIFETIME, ND6_INFINITE_LIFETIME); > } > > @@ -1046,7 +1047,7 @@ get_interface_prefixes(struct ra_iface *ra_iface, struct ra_prefix_conf > struct in6_ifreq ifr6; > struct ifaddrs *ifa; > struct sockaddr_in6 *sin6; > - uint32_t decaying_vltime, decaying_pltime; > + uint32_t if_vltime, if_pltime; > int prefixlen; > > for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next) { > @@ -1066,8 +1067,8 @@ 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_vltime = ND6_INFINITE_LIFETIME; > + if_pltime = ND6_INFINITE_LIFETIME; > > if (ioctl(ioctlsock, SIOCGIFALIFETIME_IN6, > (caddr_t)&ifr6) != -1) { > @@ -1075,9 +1076,9 @@ get_interface_prefixes(struct ra_iface *ra_iface, struct ra_prefix_conf > > lifetime = &ifr6.ifr_ifru.ifru_lifetime; > if (lifetime->ia6t_preferred) > - decaying_pltime = lifetime->ia6t_preferred; > + if_pltime = lifetime->ia6t_preferred; > if (lifetime->ia6t_expire) > - decaying_vltime = lifetime->ia6t_expire; > + if_vltime = lifetime->ia6t_expire; > } > > memset(&ifr6, 0, sizeof(ifr6)); > @@ -1096,8 +1097,7 @@ 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_conf, decaying_vltime, > - decaying_pltime); > + prefixlen, autoprefix_conf, 1, if_vltime, if_pltime); > } > } > > @@ -1118,41 +1118,30 @@ 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, > - uint32_t decaying_vltime, uint32_t decaying_pltime) > + int prefixlen, struct ra_prefix_conf *ra_prefix_conf, int autoconf, > + uint32_t if_vltime, uint32_t if_pltime) > { > struct ra_prefix_conf *new_ra_prefix_conf; > > 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) { > + int changed = new_ra_prefix_conf->autoconf != autoconf; > + > + new_ra_prefix_conf->autoconf = autoconf; > + new_ra_prefix_conf->if_vltime = if_vltime; > + new_ra_prefix_conf->if_pltime = if_pltime; > + > + if (changed) { > struct ra_prefix_conf *pc; > > - new_ra_prefix_conf->ltime_decaying = 0; > - ra_iface->ltime_decaying = 0; > + ra_iface->has_autoconf_prefix = 0; > SIMPLEQ_FOREACH(pc, &ra_iface->prefixes, entry) { > - if (pc->ltime_decaying) { > - ra_iface->ltime_decaying = 1; > + if (pc->autoconf) { > + ra_iface->has_autoconf_prefix = 1; > break; > } > } > - } else > - log_debug("ignoring duplicate %s/%d prefix", > - in6_to_str(addr), prefixlen); > + } > return; > } > > @@ -1164,24 +1153,36 @@ 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->autoconf = autoconf; > + if (autoconf) > + ra_iface->has_autoconf_prefix = 1; > + new_ra_prefix_conf->if_vltime = if_vltime; > + new_ra_prefix_conf->if_pltime = if_pltime; > 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++; > } > > +uint32_t > +calc_autoconf_ltime(time_t t, uint32_t conf_ltime, uint32_t if_ltime) > +{ > + uint32_t ltime; > + > + if (if_ltime == ND6_INFINITE_LIFETIME) > + return conf_ltime; > + > + if (if_ltime > t) > + ltime = if_ltime - t; > + else > + ltime = 0; > + > + if (ltime < conf_ltime) > + return ltime; > + else > + return conf_ltime; > +} > + > int > build_packet(struct ra_iface *ra_iface) > { > @@ -1294,16 +1295,15 @@ build_packet(struct ra_iface *ra_iface) > ndopt_pi->nd_opt_pi_flags_reserved |= > ND_OPT_PI_FLAG_AUTO; > > - 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 > + if (ra_prefix_conf->autoconf) { > + pltime = calc_autoconf_ltime(t, > + ra_prefix_conf->pltime, ra_prefix_conf->if_pltime); > + vltime = calc_autoconf_ltime(t, > + ra_prefix_conf->vltime, ra_prefix_conf->if_vltime); > + } else { > pltime = ra_prefix_conf->pltime; > + vltime = ra_prefix_conf->vltime; > + } > > ndopt_pi->nd_opt_pi_valid_time = htonl(vltime); > ndopt_pi->nd_opt_pi_preferred_time = htonl(pltime); > @@ -1430,7 +1430,7 @@ 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) > + if (ra_iface->has_autoconf_prefix) > /* update vltime & pltime */ > build_packet(ra_iface); > > diff --git rad.conf.5 rad.conf.5 > index d03bcc139aa..7211c48d0a1 100644 > --- rad.conf.5 > +++ rad.conf.5 > @@ -207,13 +207,13 @@ The preferred lifetime (pltime) in seconds for addresses generated from this > prefix. > The default is 2700. > This option is ignored if the prefix is discovered from a network interface > -and it has a preferred lifetime configured. > +and it has a lower preferred lifetime. > .It Cm valid lifetime Ar seconds > The valid lifetime (vltime) in seconds for addresses generated from this > prefix. > The default is 5400. > This option is ignored if the prefix is discovered from a network interface > -and it has a valid lifetime configured. > +and it has a lower valid lifetime. > .El > .El > .El > diff --git rad.h rad.h > index 7775ac4a0aa..00b4f1bfeb0 100644 > --- rad.h > +++ rad.h > @@ -35,8 +35,6 @@ > #define MIN_DELAY_BETWEEN_RAS 3 /* 3 seconds */ > #define MAX_SEARCH 1025 /* MAXDNAME in arpa/nameser.h */ > #define DEFAULT_RDNS_LIFETIME 3 * MAX_RTR_ADV_INTERVAL > -#define PLTIME_DECAYING 1 > -#define VLTIME_DECAYING 2 > > #define IMSG_DATA_SIZE(imsg) ((imsg).hdr.len - IMSG_HEADER_SIZE) > > @@ -116,7 +114,9 @@ struct ra_prefix_conf { > int prefixlen; /* prefix length */ > uint32_t vltime; /* valid lifetime */ > uint32_t pltime; /* preferred lifetime */ > - int ltime_decaying; > + uint32_t if_vltime; /* valid lifetime */ > + uint32_t if_pltime; /* preferred lifetime */ > + int autoconf; > int lflag; /* on-link flag*/ > int aflag; /* autonom. addr flag */ > }; > > > > On 2025-08-07 17:09 -07, Ryan Vogt wrote: > > Hi tech@, > > > > I'd like to ping one final time, to see if there's any feedback about > > this proposed patch. > > > > I also wanted to elaborate on one comment that I made in my previous > > message (inline below), which I explained very poorly. > > > > On Sun, Jul 20, 2025 at 01:43:06PM -0700, Ryan Vogt wrote: > >> On Tue, Jul 01, 2025 at 04:11:48PM -0700, Ryan Vogt wrote: > >> > Hi tech@, > >> > > >> > I've attached a proposed patch for rad(8). It allows rad to send > >> > advertisements with shorter valid and preferred lifetimes than the > >> > lifetimes otherwise already configured for a prefix discovered on an > >> > interface. > >> > > >> > The motivation for the patch is for debugging network setups. > >> > Currently, let's say you have dhcp6leased(8) getting an upstream > >> > prefix-delegation lease, good for 7 days. When rad starts advertising > >> > the prefix, it'll advertise it as having a lifetime of 7 days. In > >> > general, this is good behaviour. But, for debugging, I'd like to be > >> > able to tell rad to advertise a lifetime of *no longer* than > >> > 10 minutes, even if the upstream lease is good for more than 10 min. > >> > >> I'm less confident in this statement now than I was a few weeks ago: > >> that the current default behaviour of rad(8) is ideal (providing de > >> facto unbounded lifetimes where they exist). > >> > >> Someone sent me a message off-list where they commented about their > >> situation with Google Fiber/Webpass. From what I understood, this > >> Google service gives 1-year valid lifetimes and 1/2-year preferred > >> lifetimes on DHCPv6 prefix delegations. Discussing extra-big numbers > >> like that made me think more about the "ecosystem" (for lack of a > >> better word) formed by dhcp6leased(8) and rad(8). > >> > >> As it stands right now, in -current with the default behaviour of both > >> rad(8) and dhcpd6leased(6), firing up those two programs on an OpenBSD > >> gateway would send 1-year valid / half-year preferred lifetimes into > >> the network behind the gateway. For comparison, the default lifetimes > >> rad uses in a static-address situation are 90-minutes valid, > >> 45-minutes preferred. > > > > In my previous message, I did a really poor job explaining what it was > > that made me uncomfortable with this situation. Please allow me a > > second attempt. > > > > Let's say that dhcp6leased gets a really long prefix delegation -- > > 1 year, 20 years, it doesn't matter. Let's call that prefix > > XXXX:XXXX:XXXX:XXXX::/64 > > Now, in the situation I described above, rad will echo that prefix > > into the internal network, inside the gateway. All the clients on that > > side will now have autoconfigured IPv6 addresses in the > > XXXX:XXXX:XXXX:XXXX::/64 block with really long lifetimes. > > > > My concern is what would happen, now, if dhcp6leased were to get a new > > prefix delegation early. As for how this could happen, maybe the > > original DHCPv6 reply was malicious? Maybe there was a change to the > > DHCPv6 server immediately upstream? I'm admittedly hand-waving the > > specifics here, because my concern is only that it's a possibility. > > > > So, let's say that dhcp6leased gets another really long prefix > > delegation -- again, some number of years, this time for prefix > > YYYY:YYYY:YYYY:YYYY::/64 > > Once again, rad will echo that prefix into the internal network. So, > > all the hosts on the internal network will now have autoconfigured > > addresses in the YYYY:YYYY:YYYY:YYYY::/64 range and the > > XXXX:XXXX:XXXX:XXXX::/64 range, both with really long lifetimes. It > > doesn't matter if rad isn't advertising XXXX:XXXX:XXXX:XXXX::/64 > > anymore, because the hosts will remember it for its lifetime. > > > > Repeat by giving dhcp6leased a ZZZZ:ZZZZ:ZZZZ:ZZZZ::/64 delegation, > > a WWWW:WWWW:WWWW:WWWW::/64 delegation, etc., and all the hosts inside > > the network could have a lot of IPv6 addresses, all with really long > > lifetimes. > > > > While IPv6 is designed to allow hosts to have lots of different > > addresses, what concerns me is whether there's some risk of resource > > exhaustion to the hosts inside the network, if rad keeps advertising > > different prefixes with very long lifetimes. > > > > Bounding rad's advertised lifetimes doesn't make this potential > > problem go away (and there are a lot of question marks after > > "potential problem", because I'm not sure how much of one it is). But > > my thinking, in my previous message, was that bounding rad's > > advertised lifetimes could limit how long any issue persists. > > > > As always, thank you very much for your time. > > > > Cheers, > > Ryan > > > >> All of that to say, is the current default behaviour of rad(8) what > >> the default behaviour should be? I've added some example configuration > >> files, inline below, showing what would happen if we changed that > >> behaviour. > >> > >> [...] > >> > >> As a thought exercise, here's what would happen if I were to change > >> the patch slightly, making "configured lifetimes no" the default, > >> instead of matching rad's current behaviour with > >> "configured lifetimes yes" being the default. > >> > >> [...] > >> > >> This would change the default behaviour of rad only in situations with > >> configured lifetimes, such as where a lifetime has been placed onto > >> the interface by dhcp6leased(8). > >> > >> Here are some example rad.conf(5) configuration files and how they > >> would behave with this modification: > >> > >> Configuration file 1 - rad would send lifetimes of at most > >> 5400 seconds (90 minutes) valid, 2700 seconds (45 minutes) preferred. > >> If the configured lifetimes on the interface are shorter, rad would > >> send those smaller values: > >> > >> interface em1 > >> > >> Configuration file 2 - rad would send lifetimes of at most 600 seconds > >> (10 mintues) valid, 300 seconds (5 minutes) preferred. Again, if the > >> configurated lifetimes are less, rad would send those smaller values: > >> > >> interface em1 { > >> auto prefix { > >> valid lifetime 600 > >> preferred lifetime 300 > >> } > >> } > >> > >> Configuration file 3 - we explicitly tell rad to go ahead and send > >> whatever lifetimes dhcp6leased places onto em1, even if they're huge: > >> > >> interface em1 { > >> auto prefix { > >> configured lifetimes yes > >> } > >> } > >> > >> (For clarity: the behaviour of rad in -current with the first two > >> configuration files is to send the unbounded configured lifetimes. > >> There's no "configured lifetimes" option in -current, so the third > >> configuration file has no meaning in -current.) > >> > >> Changing the patch like this to bound rad's behaviour by default, > >> though, would change the behaviour of rad for what I imagine are a lot > >> of people's current rad.conf files. And, it would be over something > >> that I can't actually convince myself is a real problem. Thoughts? > >> > >> Again, thank you very much for taking the time to look through this > >> wall of text I've created, and for sharing any insight. > >> > >> Cheers, > >> Ryan > >> > >> > Thank you very much for taking the time to consider this patch, and > >> > for any feedback provided. > >> > > >> > Cheers, > >> > Ryan > >> > > >> > diff --git usr.sbin/rad/frontend.c usr.sbin/rad/frontend.c > >> > index 2a519dac0b1..cb955043576 100644 > >> > --- usr.sbin/rad/frontend.c > >> > +++ usr.sbin/rad/frontend.c > >> > @@ -89,6 +89,9 @@ > >> > #define RA_MAX_SIZE 1500 > >> > #define ROUTE_SOCKET_BUF_SIZE 16384 > >> > > >> > +#define LT_IS_DECAYING(vltime, pltime) \ > >> > + ((vltime) != ND6_INFINITE_LIFETIME || (pltime) != ND6_INFINITE_LIFETIME) > >> > + > >> > struct icmp6_ev { > >> > struct event ev; > >> > uint8_t answer[1500]; > >> > @@ -1122,37 +1125,35 @@ add_new_prefix_to_ra_iface(struct ra_iface *ra_iface, struct in6_addr *addr, > >> > uint32_t decaying_vltime, uint32_t decaying_pltime) > >> > { > >> > struct ra_prefix_conf *new_ra_prefix_conf; > >> > + struct ra_prefix_conf *pc; > >> > + int was_decaying; > >> > > >> > 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) { > >> > + if (new_ra_prefix_conf->decaying_vltime == decaying_vltime && > >> > + new_ra_prefix_conf->decaying_pltime == decaying_pltime) { > >> > + log_debug("ignoring duplicate %s/%d prefix", > >> > + in6_to_str(addr), prefixlen); > >> > + return; > >> > + } > >> > + was_decaying = LT_IS_DECAYING( > >> > + new_ra_prefix_conf->decaying_vltime, > >> > + new_ra_prefix_conf->decaying_pltime); > >> > + new_ra_prefix_conf->decaying_vltime = decaying_vltime; > >> > + new_ra_prefix_conf->decaying_pltime = decaying_pltime; > >> > + if (LT_IS_DECAYING(decaying_vltime, decaying_pltime)) > >> > 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; > >> > + else if (was_decaying) { > >> > ra_iface->ltime_decaying = 0; > >> > SIMPLEQ_FOREACH(pc, &ra_iface->prefixes, entry) { > >> > - if (pc->ltime_decaying) { > >> > + if (LT_IS_DECAYING(pc->vltime, pc->pltime)) { > >> > ra_iface->ltime_decaying = 1; > >> > break; > >> > } > >> > } > >> > - } else > >> > - log_debug("ignoring duplicate %s/%d prefix", > >> > - in6_to_str(addr), prefixlen); > >> > + } > >> > + log_debug("updating %s/%d prefix lifetimes", in6_to_str(addr), > >> > + prefixlen); > >> > return; > >> > } > >> > > >> > @@ -1164,18 +1165,11 @@ 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) { > >> > + new_ra_prefix_conf->decaying_vltime = decaying_vltime; > >> > + new_ra_prefix_conf->decaying_pltime = decaying_pltime; > >> > + if (LT_IS_DECAYING(decaying_vltime, decaying_pltime)) > >> > 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->cfgltimes = ra_prefix_conf->cfgltimes; > >> > 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); > >> > @@ -1294,14 +1288,22 @@ build_packet(struct ra_iface *ra_iface) > >> > ndopt_pi->nd_opt_pi_flags_reserved |= > >> > ND_OPT_PI_FLAG_AUTO; > >> > > >> > - if (ra_prefix_conf->ltime_decaying & VLTIME_DECAYING) > >> > - vltime = ra_prefix_conf->vltime < t ? 0 : > >> > - ra_prefix_conf->vltime - t; > >> > + if (ra_prefix_conf->decaying_vltime != ND6_INFINITE_LIFETIME) { > >> > + vltime = ra_prefix_conf->decaying_vltime < t ? 0 : > >> > + ra_prefix_conf->decaying_vltime - t; > >> > + if (vltime > ra_prefix_conf->vltime && > >> > + !ra_prefix_conf->cfgltimes) > >> > + vltime = ra_prefix_conf->vltime; > >> > + } > >> > 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; > >> > + if (ra_prefix_conf->decaying_pltime != ND6_INFINITE_LIFETIME) { > >> > + pltime = ra_prefix_conf->decaying_pltime < t ? 0 : > >> > + ra_prefix_conf->decaying_pltime - t; > >> > + if (pltime > ra_prefix_conf->pltime && > >> > + !ra_prefix_conf->cfgltimes) > >> > + pltime = ra_prefix_conf->pltime; > >> > + } > >> > else > >> > pltime = ra_prefix_conf->pltime; > >> > > >> > diff --git usr.sbin/rad/parse.y usr.sbin/rad/parse.y > >> > index bf6b6e6b86d..d4d058491dd 100644 > >> > --- usr.sbin/rad/parse.y > >> > +++ usr.sbin/rad/parse.y > >> > @@ -122,7 +122,7 @@ typedef struct { > >> > %token CONFIGURATION OTHER LIFETIME REACHABLE TIME RETRANS TIMER > >> > %token AUTO PREFIX VALID PREFERENCE PREFERRED LIFETIME ONLINK AUTONOMOUS > >> > %token ADDRESS_CONFIGURATION DNS NAMESERVER SEARCH MTU NAT64 HIGH MEDIUM LOW > >> > -%token SOURCE LINK_LAYER > >> > +%token SOURCE LINK_LAYER CONFIGURED LIFETIMES > >> > > >> > %token STRING > >> > %token NUMBER > >> > @@ -368,6 +368,9 @@ ra_prefixoptsl : VALID LIFETIME NUMBER { > >> > | PREFERRED LIFETIME NUMBER { > >> > ra_prefix_conf->pltime = $3; > >> > } > >> > + | CONFIGURED LIFETIMES yesno { > >> > + ra_prefix_conf->cfgltimes = $3; > >> > + } > >> > | ONLINK yesno { > >> > ra_prefix_conf->lflag = $2; > >> > } > >> > @@ -519,6 +522,7 @@ lookup(char *s) > >> > {"auto", AUTO}, > >> > {"autonomous", AUTONOMOUS}, > >> > {"configuration", CONFIGURATION}, > >> > + {"configured", CONFIGURED}, > >> > {"default", DEFAULT}, > >> > {"dns", DNS}, > >> > {"high", HIGH}, > >> > @@ -526,6 +530,7 @@ lookup(char *s) > >> > {"include", INCLUDE}, > >> > {"interface", RA_IFACE}, > >> > {"lifetime", LIFETIME}, > >> > + {"lifetimes", LIFETIMES}, > >> > {"limit", LIMIT}, > >> > {"link-layer", LINK_LAYER}, > >> > {"low", LOW}, > >> > @@ -1087,6 +1092,7 @@ conf_get_ra_prefix(struct in6_addr *addr, int prefixlen) > >> > prefix->prefixlen = prefixlen; > >> > prefix->vltime = ADV_VALID_LIFETIME; > >> > prefix->pltime = ADV_PREFERRED_LIFETIME; > >> > + prefix->cfgltimes = 1; > >> > prefix->lflag = 1; > >> > prefix->aflag = 1; > >> > > >> > diff --git usr.sbin/rad/rad.conf.5 usr.sbin/rad/rad.conf.5 > >> > index bf684759e11..292070c7c60 100644 > >> > --- usr.sbin/rad/rad.conf.5 > >> > +++ usr.sbin/rad/rad.conf.5 > >> > @@ -168,6 +168,20 @@ options are as follows: > >> > This prefix can be used to generate IPv6 addresses. > >> > The default is > >> > .Cm yes . > >> > +.It Ic configured lifetimes Pq Cm yes Ns | Ns Cm no > >> > +If the prefix is discovered from a network interface and it has configured > >> > +valid or preferred lifetimes, use the configured lifetimes instead of those > >> > +specified in the static > >> > +.Ic preferred lifetime > >> > +and > >> > +.Ic valid lifetime > >> > +options. > >> > +Even if set to > >> > +.Cm no , > >> > +static lifetimes will never be used when they are longer than the > >> > +prefix's configured lifetimes. > >> > +The default is > >> > +.Cm yes . > >> > .It Ic on-link Pq Cm yes Ns | Ns Cm no > >> > This prefix is considered on-link. > >> > The default is > >> > @@ -176,14 +190,10 @@ The default is > >> > The preferred lifetime (pltime) in seconds for addresses generated from this > >> > prefix. > >> > The default is 2700. > >> > -This option is ignored if the prefix is discovered from a network interface > >> > -and it has a preferred lifetime configured. > >> > .It Ic valid lifetime Ar seconds > >> > The valid lifetime (vltime) in seconds for addresses generated from this > >> > prefix. > >> > The default is 5400. > >> > -This option is ignored if the prefix is discovered from a network interface > >> > -and it has a valid lifetime configured. > >> > .El > >> > .El > >> > .El > >> > diff --git usr.sbin/rad/rad.h usr.sbin/rad/rad.h > >> > index 7775ac4a0aa..5f7b79fb38b 100644 > >> > --- usr.sbin/rad/rad.h > >> > +++ usr.sbin/rad/rad.h > >> > @@ -35,8 +35,6 @@ > >> > #define MIN_DELAY_BETWEEN_RAS 3 /* 3 seconds */ > >> > #define MAX_SEARCH 1025 /* MAXDNAME in arpa/nameser.h */ > >> > #define DEFAULT_RDNS_LIFETIME 3 * MAX_RTR_ADV_INTERVAL > >> > -#define PLTIME_DECAYING 1 > >> > -#define VLTIME_DECAYING 2 > >> > > >> > #define IMSG_DATA_SIZE(imsg) ((imsg).hdr.len - IMSG_HEADER_SIZE) > >> > > >> > @@ -116,7 +114,9 @@ struct ra_prefix_conf { > >> > int prefixlen; /* prefix length */ > >> > uint32_t vltime; /* valid lifetime */ > >> > uint32_t pltime; /* preferred lifetime */ > >> > - int ltime_decaying; > >> > + uint32_t decaying_vltime; > >> > + uint32_t decaying_pltime; > >> > + int cfgltimes; /* config'd lifetimes */ > >> > int lflag; /* on-link flag*/ > >> > int aflag; /* autonom. addr flag */ > >> > }; > > > > -- > In my defence, I have been left unsupervised.