Download raw body.
Allow rad(8) to advertise shorter lifetimes
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 <rvogt.ca@gmail.com> 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 <v.string> STRING
> >> > %token <v.number> 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.
Allow rad(8) to advertise shorter lifetimes