The branch main has been updated by imp:

URL: 
https://cgit.FreeBSD.org/src/commit/?id=77f06c476c8cb8700bd1c154a4f4314d51286378

commit 77f06c476c8cb8700bd1c154a4f4314d51286378
Author:     Lexi Winter <l...@le-fay.org>
AuthorDate: 2024-04-26 21:41:37 +0000
Commit:     Warner Losh <i...@freebsd.org>
CommitDate: 2024-05-23 20:40:48 +0000

    rtadvd(8): support PREF64 (RFC 8781)
    
    PREF64 allows a router to advertise the network's NAT64 prefix, allowing
    clients to auto-configure CLAT.  This makes it possible to deploy
    IPv6-only or IPv6-mostly client access networks without the need for
    DNS64.
    
    Reviewed by: imp, glebius (prior suggetions done)
    Pull Request: https://github.com/freebsd/freebsd-src/pull/1206
---
 usr.sbin/rtadvd/config.c      | 68 +++++++++++++++++++++++++++++++++++++++++++
 usr.sbin/rtadvd/rtadvd.conf.5 | 18 ++++++++++++
 usr.sbin/rtadvd/rtadvd.h      | 11 +++++++
 3 files changed, 97 insertions(+)

diff --git a/usr.sbin/rtadvd/config.c b/usr.sbin/rtadvd/config.c
index bd990c58b36a..1b37d53c8b91 100644
--- a/usr.sbin/rtadvd/config.c
+++ b/usr.sbin/rtadvd/config.c
@@ -912,6 +912,58 @@ getconfig_free_dns:
                }
                free(dns);
        }
+
+       /*
+        * handle pref64
+        */
+       rai->rai_pref64.p64_enabled = false;
+
+       if ((addr = (char *)agetstr("pref64", &bp))) {
+               if (inet_pton(AF_INET6, addr, &rai->rai_pref64.p64_prefix) != 
1) {
+                       syslog(LOG_ERR, "<%s> inet_pton failed for %s",
+                           __func__, addr);
+               } else {
+                       rai->rai_pref64.p64_enabled = true;
+
+                       switch (val64 = agetnum("pref64len")) {
+                       case -1:
+                       case 96:
+                               rai->rai_pref64.p64_plc = 0;
+                               break;
+                       case 64:
+                               rai->rai_pref64.p64_plc = 1;
+                               break;
+                       case 56:
+                               rai->rai_pref64.p64_plc = 2;
+                               break;
+                       case 48:
+                               rai->rai_pref64.p64_plc = 3;
+                               break;
+                       case 40:
+                               rai->rai_pref64.p64_plc = 4;
+                               break;
+                       case 32:
+                               rai->rai_pref64.p64_plc = 5;
+                               break;
+                       default:
+                               syslog(LOG_ERR, "prefix length %" PRIi64
+                                      "on %s is invalid; disabling PREF64",
+                                      val64, ifi->ifi_ifname);
+                               rai->rai_pref64.p64_enabled = 0;
+                               break;
+                       }
+
+                       /* This logic is from RFC 8781 section 4.1. */
+                       val64 = agetnum("pref64lifetime");
+                       if (val64 == -1)
+                               val64 = rai->rai_lifetime * 3;
+                       if (val64 > 65528)
+                               val64 = 65528;
+                       val64 = (val64 + 7) / 8;
+                       rai->rai_pref64.p64_sl = (uint16_t) (uint64_t) val64;
+               }
+       }
+
        /* construct the sending packet */
        make_packet(rai);
 
@@ -1334,6 +1386,7 @@ make_packet(struct rainfo *rai)
        struct rdnss *rdn;
        struct nd_opt_dnssl *ndopt_dnssl;
        struct dnssl *dns;
+       struct nd_opt_pref64 *ndopt_pref64;
        size_t len;
        struct prefix *pfx;
        struct ifinfo *ifi;
@@ -1355,6 +1408,8 @@ make_packet(struct rainfo *rai)
                packlen += sizeof(struct nd_opt_prefix_info) * rai->rai_pfxs;
        if (rai->rai_linkmtu)
                packlen += sizeof(struct nd_opt_mtu);
+       if (rai->rai_pref64.p64_enabled)
+               packlen += sizeof(struct nd_opt_pref64);
 
        TAILQ_FOREACH(rti, &rai->rai_route, rti_next)
                packlen += sizeof(struct nd_opt_route_info) +
@@ -1435,6 +1490,19 @@ make_packet(struct rainfo *rai)
                buf += sizeof(struct nd_opt_mtu);
        }
 
+       if (rai->rai_pref64.p64_enabled) {
+               ndopt_pref64 = (struct nd_opt_pref64 *)buf;
+               ndopt_pref64->nd_opt_pref64_type = ND_OPT_PREF64;
+               ndopt_pref64->nd_opt_pref64_len = 2;
+               ndopt_pref64->nd_opt_pref64_sl_plc =
+                       (htons(rai->rai_pref64.p64_sl << 3)) |
+                       htons((rai->rai_pref64.p64_plc & 0x7));
+               memcpy(&ndopt_pref64->nd_opt_prefix[0],
+                      &rai->rai_pref64.p64_prefix,
+                      sizeof(ndopt_pref64->nd_opt_prefix));
+               buf += sizeof(struct nd_opt_pref64);
+       }
+
        TAILQ_FOREACH(pfx, &rai->rai_prefix, pfx_next) {
                uint32_t vltime, pltime;
                struct timespec now;
diff --git a/usr.sbin/rtadvd/rtadvd.conf.5 b/usr.sbin/rtadvd/rtadvd.conf.5
index 6824d2a5578b..8158d09f99cf 100644
--- a/usr.sbin/rtadvd/rtadvd.conf.5
+++ b/usr.sbin/rtadvd/rtadvd.conf.5
@@ -428,6 +428,24 @@ DNS search list entries.
 The default value is 3/2 of the interval time.
 .El
 .Pp
+The following items are for PREF64 discovery
+.Pq RFC 8781 ,
+which will advertise the network's NAT64 prefix to clients.
+These items are optional.
+.Bl -tag -width indent
+.It Cm \&pref64
+(str) The prefix to advertise in the PREF64 option.
+.It Cm \&pref64len
+(num) The length of the PREF64 prefix.
+This must be 96, 64, 56, 48, 40, or 32.
+If not specified, the default is 96.
+.It Cm \&pref64lifetime
+(num) The prefix lifetime to advertise in the PREF64 option.
+This should be at least as long as the RA lifetime, but cannot be greater
+than 65528.
+If not specified, the default is the RA lifetime, or 65528, whichever is lower.
+.El
+.Pp
 You can also refer one line from another by using
 .Cm tc
 capability.
diff --git a/usr.sbin/rtadvd/rtadvd.h b/usr.sbin/rtadvd/rtadvd.h
index eb7746733c6e..597fb2f47f0d 100644
--- a/usr.sbin/rtadvd/rtadvd.h
+++ b/usr.sbin/rtadvd/rtadvd.h
@@ -32,6 +32,8 @@
  * SUCH DAMAGE.
  */
 
+#include <stdbool.h>
+
 #define        ELM_MALLOC(p,error_action)                                      
\
        do {                                                            \
                p = malloc(sizeof(*p));                                 \
@@ -148,6 +150,14 @@ struct rdnss {
        uint32_t rd_ltime;      /* number of seconds valid */
 };
 
+struct pref64 {
+       TAILQ_ENTRY(pref64) p64_next;
+       bool            p64_enabled;
+       uint16_t        p64_plc;        /* prefix length code */
+       uint16_t        p64_sl;         /* scaled lifetime */
+       struct in6_addr p64_prefix;
+};
+
 /*
  * The maximum length of a domain name in a DNS search list is calculated
  * by a domain name + length fields per 63 octets + a zero octet at
@@ -217,6 +227,7 @@ struct      rainfo {
        /* actual RA packet data and its length */
        size_t  rai_ra_datalen;
        char    *rai_ra_data;
+       struct pref64 rai_pref64;       /* PREF64 option */
 
        /* info about soliciter */
        TAILQ_HEAD(, soliciter) rai_soliciter;  /* recent solication source */

Reply via email to