git: 77f06c476c8c - main - rtadvd(8): support PREF64 (RFC 8781)
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Thu, 23 May 2024 20:41:46 UTC
The branch main has been updated by imp:
URL: https://cgit.FreeBSD.org/src/commit/?id=77f06c476c8cb8700bd1c154a4f4314d51286378
commit 77f06c476c8cb8700bd1c154a4f4314d51286378
Author: Lexi Winter <lexi@le-Fay.ORG>
AuthorDate: 2024-04-26 21:41:37 +0000
Commit: Warner Losh <imp@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 */