On 2022-10-15 13:00 +02, Florian Obser <flor...@openbsd.org> wrote:
> With this clients can learn the presence and used prefix for Network
> Address and Protocol Translation between IPv6 and IPv4 (NAT64).
>
> Apparently there is support in mobile devices as well as in macOS.
>
> This option, together with the the dhcp "IPv6-only preferred"
> option (108) enables the Customer-side transLATor (CLAT) on macOS so
> IPv4 literals can be used in IPv6-only networks.
>

Better diff, I messed up the default and maximum lifetime seconds.

OK?

diff --git engine.c engine.c
index dddff2d4579..543abffe388 100644
--- engine.c
+++ engine.c
@@ -269,6 +269,7 @@ engine_dispatch_main(int fd, short event, void *bula)
        struct ra_prefix_conf           *ra_prefix_conf;
        struct ra_rdnss_conf            *ra_rdnss_conf;
        struct ra_dnssl_conf            *ra_dnssl_conf;
+       struct ra_pref64_conf           *pref64;
        ssize_t                          n;
        int                              shut = 0;
 
@@ -333,6 +334,7 @@ engine_dispatch_main(int fd, short event, void *bula)
                        SIMPLEQ_INIT(&nconf->ra_iface_list);
                        SIMPLEQ_INIT(&nconf->ra_options.ra_rdnss_list);
                        SIMPLEQ_INIT(&nconf->ra_options.ra_dnssl_list);
+                       SIMPLEQ_INIT(&nconf->ra_options.ra_pref64_list);
                        ra_options = &nconf->ra_options;
                        break;
                case IMSG_RECONF_RA_IFACE:
@@ -349,6 +351,7 @@ engine_dispatch_main(int fd, short event, void *bula)
                        SIMPLEQ_INIT(&ra_iface_conf->ra_prefix_list);
                        SIMPLEQ_INIT(&ra_iface_conf->ra_options.ra_rdnss_list);
                        SIMPLEQ_INIT(&ra_iface_conf->ra_options.ra_dnssl_list);
+                       SIMPLEQ_INIT(&ra_iface_conf->ra_options.ra_pref64_list);
                        SIMPLEQ_INSERT_TAIL(&nconf->ra_iface_list,
                            ra_iface_conf, entry);
                        ra_options = &ra_iface_conf->ra_options;
@@ -405,6 +408,18 @@ engine_dispatch_main(int fd, short event, void *bula)
                        SIMPLEQ_INSERT_TAIL(&ra_options->ra_dnssl_list,
                            ra_dnssl_conf, entry);
                        break;
+               case IMSG_RECONF_RA_PREF64:
+                       if(IMSG_DATA_SIZE(imsg) != sizeof(struct
+                           ra_pref64_conf))
+                               fatalx("%s: IMSG_RECONF_RA_PREF64 wrong length: 
"
+                                   "%lu", __func__, IMSG_DATA_SIZE(imsg));
+                       if ((pref64 = malloc(sizeof(struct ra_pref64_conf))) ==
+                           NULL)
+                               fatal(NULL);
+                       memcpy(pref64, imsg.data, sizeof(struct 
ra_pref64_conf));
+                       SIMPLEQ_INSERT_TAIL(&ra_options->ra_pref64_list, pref64,
+                           entry);
+                       break;
                case IMSG_RECONF_END:
                        if (nconf == NULL)
                                fatalx("%s: IMSG_RECONF_END without "
diff --git frontend.c frontend.c
index 30bcde218c4..435d6aed8a8 100644
--- frontend.c
+++ frontend.c
@@ -113,6 +113,14 @@ struct ra_iface {
        uint8_t                          data[RA_MAX_SIZE];
 };
 
+#define ND_OPT_PREF64  38
+struct nd_opt_pref64 {
+       u_int8_t        nd_opt_pref64_type;
+       u_int8_t        nd_opt_pref64_len;
+       u_int16_t       nd_opt_pref64_sltime_plc;
+       u_int8_t        nd_opt_pref64[12];
+};
+
 TAILQ_HEAD(, ra_iface) ra_interfaces;
 
 __dead void             frontend_shutdown(void);
@@ -300,6 +308,7 @@ frontend_dispatch_main(int fd, short event, void *bula)
        struct ra_prefix_conf           *ra_prefix_conf;
        struct ra_rdnss_conf            *ra_rdnss_conf;
        struct ra_dnssl_conf            *ra_dnssl_conf;
+       struct ra_pref64_conf           *pref64;
        int                              n, shut = 0, icmp6sock, rdomain;
 
        if (event & EV_READ) {
@@ -361,6 +370,7 @@ frontend_dispatch_main(int fd, short event, void *bula)
                        SIMPLEQ_INIT(&nconf->ra_iface_list);
                        SIMPLEQ_INIT(&nconf->ra_options.ra_rdnss_list);
                        SIMPLEQ_INIT(&nconf->ra_options.ra_dnssl_list);
+                       SIMPLEQ_INIT(&nconf->ra_options.ra_pref64_list);
                        ra_options = &nconf->ra_options;
                        break;
                case IMSG_RECONF_RA_IFACE:
@@ -377,6 +387,7 @@ frontend_dispatch_main(int fd, short event, void *bula)
                        SIMPLEQ_INIT(&ra_iface_conf->ra_prefix_list);
                        SIMPLEQ_INIT(&ra_iface_conf->ra_options.ra_rdnss_list);
                        SIMPLEQ_INIT(&ra_iface_conf->ra_options.ra_dnssl_list);
+                       SIMPLEQ_INIT(&ra_iface_conf->ra_options.ra_pref64_list);
                        SIMPLEQ_INSERT_TAIL(&nconf->ra_iface_list,
                            ra_iface_conf, entry);
                        ra_options = &ra_iface_conf->ra_options;
@@ -433,6 +444,18 @@ frontend_dispatch_main(int fd, short event, void *bula)
                        SIMPLEQ_INSERT_TAIL(&ra_options->ra_dnssl_list,
                            ra_dnssl_conf, entry);
                        break;
+               case IMSG_RECONF_RA_PREF64:
+                       if (IMSG_DATA_SIZE(imsg) != sizeof(struct
+                           ra_pref64_conf))
+                               fatalx("%s: IMSG_RECONF_RA_PREF64 wrong length: 
"
+                                   "%lu", __func__, IMSG_DATA_SIZE(imsg));
+                       if ((pref64 = malloc(sizeof(struct ra_pref64_conf))) ==
+                           NULL)
+                               fatal(NULL);
+                       memcpy(pref64, imsg.data, sizeof(struct 
ra_pref64_conf));
+                       SIMPLEQ_INSERT_TAIL(&ra_options->ra_pref64_list, pref64,
+                           entry);
+                       break;
                case IMSG_RECONF_END:
                        if (nconf == NULL)
                                fatalx("%s: IMSG_RECONF_END without "
@@ -1084,8 +1107,10 @@ build_packet(struct ra_iface *ra_iface)
        struct ra_prefix_conf           *ra_prefix_conf;
        struct nd_opt_rdnss             *ndopt_rdnss;
        struct nd_opt_dnssl             *ndopt_dnssl;
+       struct nd_opt_pref64            *ndopt_pref64;
        struct ra_rdnss_conf            *ra_rdnss;
        struct ra_dnssl_conf            *ra_dnssl;
+       struct ra_pref64_conf           *pref64;
        size_t                           len, label_len;
        uint8_t                         *p, buf[RA_MAX_SIZE];
        char                            *label_start, *label_end;
@@ -1108,6 +1133,10 @@ build_packet(struct ra_iface *ra_iface)
                len += sizeof(*ndopt_dnssl) +
                    ((ra_iface_conf->ra_options.dnssl_len + 7) & ~7);
 
+       SIMPLEQ_FOREACH(pref64, &ra_iface_conf->ra_options.ra_pref64_list,
+           entry)
+               len += sizeof(struct nd_opt_pref64);
+
        if (len > sizeof(ra_iface->data))
                fatalx("%s: packet too big", __func__); /* XXX send multiple */
 
@@ -1207,6 +1236,46 @@ build_packet(struct ra_iface *ra_iface)
                        *p++ = '\0';
        }
 
+       SIMPLEQ_FOREACH(pref64, &ra_iface_conf->ra_options.ra_pref64_list,
+           entry) {
+               uint16_t        sltime_plc;
+
+               /* scaled lifetime in units of 8 seconds */
+               sltime_plc = pref64->ltime / 8;
+               sltime_plc = sltime_plc << 3;
+               /* encode prefix lenght in lower 3 bits */
+               switch (pref64->prefixlen) {
+               case 96:
+                       sltime_plc |= 0;
+                       break;
+               case 64:
+                       sltime_plc |= 1;
+                       break;
+               case 56:
+                       sltime_plc |= 2;
+                       break;
+               case 48:
+                       sltime_plc |= 3;
+                       break;
+               case 40:
+                       sltime_plc |= 4;
+                       break;
+               case 32:
+                       sltime_plc |= 5;
+                       break;
+               default:
+                       fatalx("%s: invalid pref64 length: %d", __func__,
+                           pref64->prefixlen);
+               }
+               ndopt_pref64 = (struct nd_opt_pref64 *)p;
+               ndopt_pref64->nd_opt_pref64_type = ND_OPT_PREF64;
+               ndopt_pref64->nd_opt_pref64_len = 2;
+               ndopt_pref64->nd_opt_pref64_sltime_plc = htons(sltime_plc);
+               memcpy(ndopt_pref64->nd_opt_pref64, &pref64->prefix,
+                   sizeof(ndopt_pref64->nd_opt_pref64));
+               p += sizeof(struct nd_opt_pref64);
+       }
+
        if (len != ra_iface->datalen || memcmp(buf, ra_iface->data, len)
            != 0) {
                memcpy(ra_iface->data, buf, len);
diff --git parse.y parse.y
index 41b1f0da133..3c5e2d9e18e 100644
--- parse.y
+++ parse.y
@@ -96,11 +96,15 @@ static int                   errors;
 
 static struct ra_iface_conf    *ra_iface_conf;
 static struct ra_prefix_conf   *ra_prefix_conf;
+static struct ra_pref64_conf   *ra_pref64_conf;
 
 struct ra_prefix_conf  *conf_get_ra_prefix(struct in6_addr*, int);
+struct ra_pref64_conf  *conf_get_ra_pref64(struct in6_addr*, int);
 struct ra_iface_conf   *conf_get_ra_iface(char *);
 void                    copy_dns_options(const struct ra_options_conf *,
                            struct ra_options_conf *);
+void                    copy_pref64_options(const struct ra_options_conf *,
+                           struct ra_options_conf *);
 
 typedef struct {
        union {
@@ -116,7 +120,7 @@ typedef struct {
 %token DEFAULT ROUTER HOP LIMIT MANAGED ADDRESS
 %token CONFIGURATION OTHER LIFETIME REACHABLE TIME RETRANS TIMER
 %token AUTO PREFIX VALID PREFERRED LIFETIME ONLINK AUTONOMOUS
-%token ADDRESS_CONFIGURATION DNS NAMESERVER SEARCH MTU
+%token ADDRESS_CONFIGURATION DNS NAMESERVER SEARCH MTU NAT64
 
 %token <v.string>      STRING
 %token <v.number>      NUMBER
@@ -215,6 +219,51 @@ ra_opt_block       : DEFAULT ROUTER yesno {
                | MTU NUMBER {
                        ra_options->mtu = $2;
                }
+               | NAT64 PREFIX STRING {
+                       struct in6_addr  addr;
+                       int              prefixlen;
+                       char            *p;
+                       const char      *errstr;
+
+                       memset(&addr, 0, sizeof(addr));
+                       p = strchr($3, '/');
+                       if (p != NULL) {
+                               *p++ = '\0';
+                               prefixlen = strtonum(p, 0, 128, &errstr);
+                               if (errstr != NULL) {
+                                       yyerror("error parsing prefix "
+                                           "\"%s/%s\"", $3, p);
+                                       free($3);
+                                       YYERROR;
+                               }
+                       } else
+                               prefixlen = 96;
+
+                       switch (prefixlen) {
+                       case 96:
+                       case 64:
+                       case 56:
+                       case 48:
+                       case 40:
+                       case 32:
+                               break;
+                       default:
+                               yyerror("invalid nat64 prefix length: %d",
+                                   prefixlen);
+                               YYERROR;
+                               break;
+                       }
+                       if(inet_pton(AF_INET6, $3, &addr) == 0) {
+                               yyerror("error parsing prefix \"%s/%d\"", $3,
+                                   prefixlen);
+                               free($3);
+                               YYERROR;
+                       }
+                       mask_prefix(&addr, prefixlen);
+                       ra_pref64_conf = conf_get_ra_pref64(&addr, prefixlen);
+               } ra_pref64_block {
+                       ra_pref64_conf = NULL;
+               }
                | DNS dns_block
                ;
 
@@ -312,6 +361,26 @@ ra_prefixoptsl     : VALID LIFETIME NUMBER {
                        ra_prefix_conf->aflag = $3;
                }
                ;
+
+ra_pref64_block        : '{' optnl ra_pref64opts_l '}'
+               | '{' optnl '}'
+               | /* empty */
+               ;
+
+ra_pref64opts_l        : ra_pref64opts_l ra_pref64optsl nl
+               | ra_pref64optsl optnl
+               ;
+
+ra_pref64optsl : LIFETIME NUMBER {
+                       if ($2 < 0 || $2 > 65528) {
+                               yyerror("Invalid nat64 prefix lifetime: %lld",
+                                   $2);
+                               YYERROR;
+                       }
+                       ra_pref64_conf->ltime = $2;
+               }
+               ;
+
 dns_block      : '{' optnl dnsopts_l '}'
                | '{' optnl '}'
                | /* empty */
@@ -446,6 +515,7 @@ lookup(char *s)
                {"managed",             MANAGED},
                {"mtu",                 MTU},
                {"nameserver",          NAMESERVER},
+               {"nat64",               NAT64},
                {"no",                  NO},
                {"on-link",             ONLINK},
                {"other",               OTHER},
@@ -853,6 +923,12 @@ parse_config(char *filename)
                            &iface->ra_options);
        }
 
+       if (!SIMPLEQ_EMPTY(&conf->ra_options.ra_pref64_list)) {
+               SIMPLEQ_FOREACH(iface, &conf->ra_iface_list, entry)
+                       copy_pref64_options(&conf->ra_options,
+                           &iface->ra_options);
+       }
+
        return (conf);
 }
 
@@ -884,6 +960,20 @@ copy_dns_options(const struct ra_options_conf *src, struct 
ra_options_conf *dst)
        }
 }
 
+void
+copy_pref64_options(const struct ra_options_conf *src, struct ra_options_conf
+    *dst)
+{
+       struct ra_pref64_conf   *pref64, *npref64;
+
+       SIMPLEQ_FOREACH(pref64, &src->ra_pref64_list, entry) {
+               if ((npref64 = calloc(1, sizeof(*npref64))) == NULL)
+                       errx(1, "%s", __func__);
+               memcpy(npref64, pref64, sizeof(*npref64));
+               SIMPLEQ_INSERT_TAIL(&dst->ra_pref64_list, npref64, entry);
+       }
+}
+
 int
 symset(const char *nam, const char *val, int persist)
 {
@@ -991,6 +1081,28 @@ conf_get_ra_prefix(struct in6_addr *addr, int prefixlen)
        return (prefix);
 }
 
+struct ra_pref64_conf *
+conf_get_ra_pref64(struct in6_addr *addr, int prefixlen)
+{
+       struct ra_pref64_conf   *pref64;
+
+       SIMPLEQ_FOREACH(pref64, &ra_options->ra_pref64_list, entry) {
+               if (pref64->prefixlen == prefixlen && memcmp(addr,
+                   &pref64->prefix, sizeof(*addr)) == 0)
+                       return (pref64);
+       }
+
+       pref64 = calloc(1, sizeof(*pref64));
+       if (pref64 == NULL)
+               errx(1, "%s: calloc", __func__);
+       pref64->prefixlen = prefixlen;
+       pref64->ltime = ADV_DEFAULT_LIFETIME;
+       pref64->prefix = *addr;
+       SIMPLEQ_INSERT_TAIL(&ra_options->ra_pref64_list, pref64, entry);
+
+       return (pref64);
+}
+
 struct ra_iface_conf *
 conf_get_ra_iface(char *name)
 {
@@ -1017,6 +1129,7 @@ conf_get_ra_iface(char *name)
        iface->ra_options.rdnss_count = 0;
        SIMPLEQ_INIT(&iface->ra_options.ra_dnssl_list);
        iface->ra_options.dnssl_len = 0;
+       SIMPLEQ_INIT(&iface->ra_options.ra_pref64_list);
 
        SIMPLEQ_INSERT_TAIL(&conf->ra_iface_list, iface, entry);
 
diff --git printconf.c printconf.c
index 78099534812..0204491983e 100644
--- printconf.c
+++ printconf.c
@@ -48,6 +48,7 @@ print_ra_options(const char *indent, const struct 
ra_options_conf *ra_options)
 {
        struct ra_rdnss_conf    *ra_rdnss;
        struct ra_dnssl_conf    *ra_dnssl;
+       struct ra_pref64_conf   *pref64;
        char                     buf[INET6_ADDRSTRLEN];
 
        printf("%sdefault router %s\n", indent, yesno(ra_options->dfr));
@@ -84,6 +85,13 @@ print_ra_options(const char *indent, const struct 
ra_options_conf *ra_options)
                }
                printf("%s}\n", indent);
        }
+       SIMPLEQ_FOREACH(pref64, &ra_options->ra_pref64_list, entry) {
+               printf("%snat64 prefix %s/%d {\n", indent, inet_ntop(AF_INET6,
+                   &pref64->prefix, buf, sizeof(buf)), pref64->prefixlen);
+               printf("%s\tlifetime %u\n", indent, pref64->ltime);
+               printf("%s}\n", indent);
+       }
+
 }
 
 void
diff --git rad.8 rad.8
index 8e023d9dbc6..551a010cd94 100644
--- rad.8
+++ rad.8
@@ -132,6 +132,14 @@ socket used for communication with
 .%R RFC 8106
 .%T IPv6 Router Advertisement Options for DNS Configuration
 .Re
+.Pp
+.Rs
+.%A L. Colitti
+.%A J. Linkova
+.%D April 2020
+.%R RFC 8781
+.%T Discovering PREF64 in Router Advertisements
+.Re
 .Sh HISTORY
 The
 .Nm
diff --git rad.c rad.c
index 3bb4851bdb3..2647f06bdf9 100644
--- rad.c
+++ rad.c
@@ -573,6 +573,7 @@ main_imsg_send_config(struct rad_conf *xconf)
        struct ra_prefix_conf   *ra_prefix_conf;
        struct ra_rdnss_conf    *ra_rdnss_conf;
        struct ra_dnssl_conf    *ra_dnssl_conf;
+       struct ra_pref64_conf   *pref64;
 
        /* Send fixed part of config to children. */
        if (main_sendboth(IMSG_RECONF_CONF, xconf, sizeof(*xconf)) == -1)
@@ -592,6 +593,14 @@ main_imsg_send_config(struct rad_conf *xconf)
                        return (-1);
        }
 
+       /* send global pref64 list to children */
+       SIMPLEQ_FOREACH(pref64, &xconf->ra_options.ra_pref64_list,
+           entry) {
+               if (main_sendboth(IMSG_RECONF_RA_PREF64, pref64,
+                   sizeof(*pref64)) == -1)
+                       return (-1);
+       }
+
        /* Send the interface list to children. */
        SIMPLEQ_FOREACH(ra_iface_conf, &xconf->ra_iface_list, entry) {
                if (main_sendboth(IMSG_RECONF_RA_IFACE, ra_iface_conf,
@@ -621,6 +630,12 @@ main_imsg_send_config(struct rad_conf *xconf)
                            sizeof(*ra_dnssl_conf)) == -1)
                                return (-1);
                }
+               SIMPLEQ_FOREACH(pref64,
+                   &ra_iface_conf->ra_options.ra_pref64_list, entry) {
+                       if (main_sendboth(IMSG_RECONF_RA_PREF64, pref64,
+                           sizeof(*pref64)) == -1)
+                               return (-1);
+               }
        }
 
        /* Tell children the revised config is now complete. */
@@ -644,6 +659,7 @@ void
 free_ra_iface_conf(struct ra_iface_conf *ra_iface_conf)
 {
        struct ra_prefix_conf   *prefix;
+       struct ra_pref64_conf   *pref64;
 
        if (!ra_iface_conf)
                return;
@@ -658,6 +674,13 @@ free_ra_iface_conf(struct ra_iface_conf *ra_iface_conf)
 
        free_dns_options(&ra_iface_conf->ra_options);
 
+       while ((pref64 =
+           SIMPLEQ_FIRST(&ra_iface_conf->ra_options.ra_pref64_list)) != NULL) {
+               SIMPLEQ_REMOVE_HEAD(&ra_iface_conf->ra_options.ra_pref64_list,
+                   entry);
+               free(pref64);
+       }
+
        free(ra_iface_conf);
 }
 
@@ -684,6 +707,7 @@ void
 merge_config(struct rad_conf *conf, struct rad_conf *xconf)
 {
        struct ra_iface_conf    *ra_iface_conf;
+       struct ra_pref64_conf   *pref64;
 
        /* Remove & discard existing interfaces. */
        while ((ra_iface_conf = SIMPLEQ_FIRST(&conf->ra_iface_list)) != NULL) {
@@ -692,9 +716,16 @@ merge_config(struct rad_conf *conf, struct rad_conf *xconf)
        }
        free_dns_options(&conf->ra_options);
 
+       while ((pref64 = SIMPLEQ_FIRST(&conf->ra_options.ra_pref64_list))
+           != NULL) {
+               SIMPLEQ_REMOVE_HEAD(&conf->ra_options.ra_pref64_list, entry);
+               free(pref64);
+       }
+
        conf->ra_options = xconf->ra_options;
        SIMPLEQ_INIT(&conf->ra_options.ra_rdnss_list);
        SIMPLEQ_INIT(&conf->ra_options.ra_dnssl_list);
+       SIMPLEQ_INIT(&conf->ra_options.ra_pref64_list);
 
        /* Add new interfaces. */
        SIMPLEQ_CONCAT(&conf->ra_iface_list, &xconf->ra_iface_list);
@@ -704,6 +735,8 @@ merge_config(struct rad_conf *conf, struct rad_conf *xconf)
            &xconf->ra_options.ra_rdnss_list);
        SIMPLEQ_CONCAT(&conf->ra_options.ra_dnssl_list,
            &xconf->ra_options.ra_dnssl_list);
+       SIMPLEQ_CONCAT(&conf->ra_options.ra_pref64_list,
+           &xconf->ra_options.ra_pref64_list);
        free(xconf);
 }
 
@@ -729,6 +762,7 @@ config_new_empty(void)
        xconf->ra_options.rdns_lifetime = DEFAULT_RDNS_LIFETIME;
        SIMPLEQ_INIT(&xconf->ra_options.ra_rdnss_list);
        SIMPLEQ_INIT(&xconf->ra_options.ra_dnssl_list);
+       SIMPLEQ_INIT(&xconf->ra_options.ra_pref64_list);
 
        return (xconf);
 }
diff --git rad.conf.5 rad.conf.5
index b3ecf8c11be..622e85e6009 100644
--- rad.conf.5
+++ rad.conf.5
@@ -96,6 +96,23 @@ The MTU option is used in Router Advertisement messages to 
ensure that all
 nodes on a link use the same MTU value in those cases where the link MTU
 is not well known.
 The default is 0, meaning unspecified by this router.
+.It Ic nat64 prefix Ar prefix Oc Brq nat64 options
+Add a PREF64 router advertisement option to communicate prefixes used
+for Network Address and Protocol Translation from IPv6 to IPv4 (NAT64).
+If
+.Ar prefix
+is specified without a prefix length, its default is 64.
+.Pp
+.Ic nat64 prefix
+options are as follows:
+.Bl -tag -width Ds
+.It Ic lifetime Ar seconds
+The number of seconds the nat64 prefix option is valid after receiving a router
+advertisement message.
+A value of zero indicates to not use the prefix anymore.
+The maximum is 65528 seconds.
+The default is 1800 seconds.
+.El
 .It Ic other configuration Pq Ic yes Ns | Ns Ic no
 If set to yes, hosts should consult DHCPv6 for additional configuration
 like NTP servers or DNS name servers.
@@ -128,7 +145,7 @@ This can be disabled with
 .Ic no auto prefix .
 If
 .Ar prefix
-is specified without prefixlen, its default is 64.
+is specified without a prefix length, its default is 64.
 .Pp
 .Ic prefix
 options are as follows:
diff --git rad.h rad.h
index 9b0fedd77fb..77ad9b28c2a 100644
--- rad.h
+++ rad.h
@@ -55,6 +55,7 @@ enum imsg_type {
        IMSG_RECONF_RA_PREFIX,
        IMSG_RECONF_RA_RDNSS,
        IMSG_RECONF_RA_DNSSL,
+       IMSG_RECONF_RA_PREF64,
        IMSG_RECONF_END,
        IMSG_ICMP6SOCK,
        IMSG_OPEN_ICMP6SOCK,
@@ -78,6 +79,14 @@ struct ra_dnssl_conf {
        char                            search[MAX_SEARCH];
 };
 
+/* RFC 8781 Section 4 */
+struct ra_pref64_conf {
+       SIMPLEQ_ENTRY(ra_pref64_conf)    entry;
+       struct in6_addr                  prefix;        /* prefix */
+       int                              prefixlen;     /* prefix length */
+       uint32_t                         ltime;         /* lifetime */
+};
+
 /* RFC 4861 Sections 4.2 and 4.6.4 */
 struct ra_options_conf {
        int             dfr;                    /* is default router? */
@@ -93,6 +102,7 @@ struct ra_options_conf {
        int             rdnss_count;
        SIMPLEQ_HEAD(, ra_dnssl_conf)            ra_dnssl_list;
        int             dnssl_len;
+       SIMPLEQ_HEAD(, ra_pref64_conf)           ra_pref64_list;
 };
 
 /* RFC 4861 Section 4.6.2 */


-- 
I'm not entirely sure you are real.

Reply via email to