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 */