rtadvd: add multi pref64 support
Add support for multi pref64 in rtadvd and rtadvctl Reviewed By: zlei, bz Differential Revision: https://reviews.freebsd.org/D54636
This commit is contained in:
@@ -89,6 +89,7 @@ static int action_show_prefix(struct prefix *);
|
||||
static int action_show_rtinfo(struct rtinfo *);
|
||||
static int action_show_rdnss(void *);
|
||||
static int action_show_dnssl(void *);
|
||||
static void action_show_pref64(void *);
|
||||
|
||||
static int csock_client_open(struct sockinfo *);
|
||||
static size_t dname_labeldec(char *, size_t, const char *);
|
||||
@@ -414,6 +415,7 @@ action_show(int argc, char **argv)
|
||||
char argv_ifi_ra_timer[IFNAMSIZ + sizeof(":ifi_ra_timer=")];
|
||||
char argv_rdnss[IFNAMSIZ + sizeof(":rdnss=")];
|
||||
char argv_dnssl[IFNAMSIZ + sizeof(":dnssl=")];
|
||||
char argv_pref64[IFNAMSIZ + sizeof(":pref64=")];
|
||||
char ssbuf[SSBUFLEN];
|
||||
|
||||
struct timespec now, ts0, ts;
|
||||
@@ -691,6 +693,21 @@ action_show(int argc, char **argv)
|
||||
action_show_dnssl(cp.cp_val);
|
||||
}
|
||||
|
||||
/* PREF64 information */
|
||||
sprintf(argv_pref64, "%s:pref64=", ifi->ifi_ifname);
|
||||
action_argv = argv_pref64;
|
||||
|
||||
error = action_propget(action_argv, &cp);
|
||||
if (error)
|
||||
continue;
|
||||
|
||||
len = *((uint16_t *)cp.cp_val);
|
||||
|
||||
if (len > 0) {
|
||||
printf("\tPREF64:\n");
|
||||
action_show_pref64(cp.cp_val);
|
||||
}
|
||||
|
||||
if (vflag < LOG_NOTICE)
|
||||
continue;
|
||||
|
||||
@@ -896,6 +913,35 @@ action_show_dnssl(void *msg)
|
||||
return (0);
|
||||
}
|
||||
|
||||
static void
|
||||
action_show_pref64(void *msg)
|
||||
{
|
||||
struct pref64 *prf64;
|
||||
uint16_t *prf64_cnt;
|
||||
char ntopbuf[INET6_ADDRSTRLEN];
|
||||
char ssbuf[SSBUFLEN];
|
||||
char *p;
|
||||
int i;
|
||||
uint16_t prf64len;
|
||||
|
||||
p = msg;
|
||||
prf64_cnt = (uint16_t *)p;
|
||||
p += sizeof(*prf64_cnt);
|
||||
|
||||
for (i = 0; i < *prf64_cnt; i++) {
|
||||
prf64 = (struct pref64 *)p;
|
||||
|
||||
/* RFC 8781 Section 4: Map PLC values to prefix lengths */
|
||||
prf64len = (prf64->p64_plc == 0) ? 96 : 72 - (8 * prf64->p64_plc);
|
||||
printf("\t %s/%d (ltime: %s)\n",
|
||||
inet_ntop(AF_INET6, &prf64->p64_prefix,
|
||||
ntopbuf, sizeof(ntopbuf)),
|
||||
prf64len, sec2str(prf64->p64_sl, ssbuf));
|
||||
|
||||
p += sizeof(*prf64);
|
||||
}
|
||||
}
|
||||
|
||||
/* Decode domain name label encoding in RFC 1035 Section 3.1 */
|
||||
static size_t
|
||||
dname_labeldec(char *dst, size_t dlen, const char *src)
|
||||
|
||||
+75
-57
@@ -291,6 +291,7 @@ rm_rainfo(struct rainfo *rai)
|
||||
struct rdnss *rdn;
|
||||
struct rdnss_addr *rdna;
|
||||
struct dnssl *dns;
|
||||
struct pref64 *prf64;
|
||||
struct rtinfo *rti;
|
||||
|
||||
syslog(LOG_DEBUG, "<%s>: enter", __func__);
|
||||
@@ -325,6 +326,10 @@ rm_rainfo(struct rainfo *rai)
|
||||
TAILQ_REMOVE(&rai->rai_route, rti, rti_next);
|
||||
free(rti);
|
||||
}
|
||||
while ((prf64 = TAILQ_FIRST(&rai->rai_pref64)) != NULL) {
|
||||
TAILQ_REMOVE(&rai->rai_pref64, prf64, p64_next);
|
||||
free(prf64);
|
||||
}
|
||||
free(rai);
|
||||
syslog(LOG_DEBUG, "<%s>: leave", __func__);
|
||||
|
||||
@@ -369,6 +374,7 @@ getconfig(struct ifinfo *ifi)
|
||||
TAILQ_INIT(&rai->rai_route);
|
||||
TAILQ_INIT(&rai->rai_rdnss);
|
||||
TAILQ_INIT(&rai->rai_dnssl);
|
||||
TAILQ_INIT(&rai->rai_pref64);
|
||||
TAILQ_INIT(&rai->rai_soliciter);
|
||||
rai->rai_ifinfo = ifi;
|
||||
|
||||
@@ -916,52 +922,62 @@ getconfig(struct ifinfo *ifi)
|
||||
/*
|
||||
* handle pref64
|
||||
*/
|
||||
rai->rai_pref64.p64_enabled = false;
|
||||
for (i = -1; i < MAXPREF64 ; i++) {
|
||||
struct pref64 *prf64;
|
||||
|
||||
if ((addr = (char *)agetstr("pref64", &bp))) {
|
||||
if (inet_pton(AF_INET6, addr, &rai->rai_pref64.p64_prefix) != 1) {
|
||||
makeentry(entbuf, sizeof(entbuf), i, "pref64");
|
||||
addr = (char *)agetstr(entbuf, &bp);
|
||||
if (addr == NULL)
|
||||
continue;
|
||||
ELM_MALLOC(prf64, exit(1));
|
||||
|
||||
if (inet_pton(AF_INET6, addr, &prf64->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;
|
||||
goto getconfig_free_prf64;
|
||||
}
|
||||
|
||||
makeentry(entbuf, sizeof(entbuf), i, "pref64len");
|
||||
MAYHAVE(val64, entbuf, 96);
|
||||
switch (val64) {
|
||||
case 96:
|
||||
prf64->p64_plc = 0;
|
||||
break;
|
||||
case 64:
|
||||
prf64->p64_plc = 1;
|
||||
break;
|
||||
case 56:
|
||||
prf64->p64_plc = 2;
|
||||
break;
|
||||
case 48:
|
||||
prf64->p64_plc = 3;
|
||||
break;
|
||||
case 40:
|
||||
prf64->p64_plc = 4;
|
||||
break;
|
||||
case 32:
|
||||
prf64->p64_plc = 5;
|
||||
break;
|
||||
default:
|
||||
syslog(LOG_ERR, "PREF64 prefix length %" PRIi64
|
||||
"on %s is invalid; skipping",
|
||||
val64, ifi->ifi_ifname);
|
||||
goto getconfig_free_prf64;
|
||||
}
|
||||
|
||||
makeentry(entbuf, sizeof(entbuf), i, "pref64lifetime");
|
||||
MAYHAVE(val64, entbuf, (rai->rai_lifetime * 3));
|
||||
/* This logic is from RFC 8781 section 4.1. */
|
||||
if (val64 > 65528)
|
||||
val64 = 65528;
|
||||
val64 = (val64 + 7) / 8;
|
||||
prf64->p64_sl = (uint16_t)val64;
|
||||
|
||||
/* link into chain */
|
||||
TAILQ_INSERT_TAIL(&rai->rai_pref64, prf64, p64_next);
|
||||
continue;
|
||||
getconfig_free_prf64:
|
||||
free(prf64);
|
||||
}
|
||||
|
||||
/* construct the sending packet */
|
||||
@@ -1386,6 +1402,7 @@ make_packet(struct rainfo *rai)
|
||||
struct rdnss *rdn;
|
||||
struct nd_opt_dnssl *ndopt_dnssl;
|
||||
struct dnssl *dns;
|
||||
struct pref64 *prf64;
|
||||
struct nd_opt_pref64 *ndopt_pref64;
|
||||
size_t len;
|
||||
struct prefix *pfx;
|
||||
@@ -1408,8 +1425,6 @@ 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) +
|
||||
@@ -1436,6 +1451,9 @@ make_packet(struct rainfo *rai)
|
||||
|
||||
packlen += len;
|
||||
}
|
||||
TAILQ_FOREACH(prf64, &rai->rai_pref64, p64_next)
|
||||
packlen += sizeof(struct nd_opt_pref64);
|
||||
|
||||
/* allocate memory for the packet */
|
||||
if ((buf = malloc(packlen)) == NULL) {
|
||||
syslog(LOG_ERR,
|
||||
@@ -1490,19 +1508,6 @@ 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;
|
||||
@@ -1616,4 +1621,17 @@ make_packet(struct rainfo *rai)
|
||||
syslog(LOG_DEBUG, "<%s>: nd_opt_dnssl_len = %d", __func__,
|
||||
ndopt_dnssl->nd_opt_dnssl_len);
|
||||
}
|
||||
|
||||
TAILQ_FOREACH(prf64, &rai->rai_pref64, p64_next) {
|
||||
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(prf64->p64_sl << 3)) |
|
||||
htons((prf64->p64_plc & 0x7));
|
||||
memcpy(&ndopt_pref64->nd_opt_prefix[0],
|
||||
&prf64->p64_prefix,
|
||||
sizeof(ndopt_pref64->nd_opt_prefix));
|
||||
buf += sizeof(struct nd_opt_pref64);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -52,3 +52,4 @@ extern void get_prefix(struct rainfo *);
|
||||
#define MAXROUTE 100
|
||||
#define MAXRDNSSENT 100
|
||||
#define MAXDNSSLENT 100
|
||||
#define MAXPREF64 100
|
||||
|
||||
@@ -80,6 +80,7 @@ static int cm_getprop_rai(struct ctrl_msg_pl *);
|
||||
static int cm_getprop_pfx(struct ctrl_msg_pl *);
|
||||
static int cm_getprop_rdnss(struct ctrl_msg_pl *);
|
||||
static int cm_getprop_dnssl(struct ctrl_msg_pl *);
|
||||
static int cm_getprop_pref64(struct ctrl_msg_pl *);
|
||||
static int cm_getprop_rti(struct ctrl_msg_pl *);
|
||||
|
||||
static int cm_setprop_reload(struct ctrl_msg_pl *);
|
||||
@@ -101,6 +102,7 @@ static struct dispatch_table {
|
||||
DEF_PL_HANDLER(pfx),
|
||||
DEF_PL_HANDLER(rdnss),
|
||||
DEF_PL_HANDLER(dnssl),
|
||||
DEF_PL_HANDLER(pref64),
|
||||
};
|
||||
|
||||
static int
|
||||
@@ -516,6 +518,60 @@ cm_getprop_dnssl(struct ctrl_msg_pl *cp)
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
cm_getprop_pref64(struct ctrl_msg_pl *cp)
|
||||
{
|
||||
struct ifinfo *ifi;
|
||||
struct rainfo *rai;
|
||||
struct pref64 *prf64;
|
||||
char *p;
|
||||
size_t len;
|
||||
uint16_t *prf64_cnt;
|
||||
|
||||
syslog(LOG_DEBUG, "<%s> enter", __func__);
|
||||
|
||||
len = 0;
|
||||
TAILQ_FOREACH(ifi, &ifilist, ifi_next) {
|
||||
if (strcmp(cp->cp_ifname, ifi->ifi_ifname) == 0)
|
||||
break;
|
||||
}
|
||||
if (ifi == NULL) {
|
||||
syslog(LOG_ERR, "<%s> %s not found", __func__,
|
||||
cp->cp_ifname);
|
||||
return (1);
|
||||
}
|
||||
if (ifi->ifi_rainfo == NULL) {
|
||||
syslog(LOG_ERR, "<%s> %s has no rainfo", __func__,
|
||||
cp->cp_ifname);
|
||||
return (1);
|
||||
}
|
||||
rai = ifi->ifi_rainfo;
|
||||
|
||||
len = sizeof(*prf64_cnt);
|
||||
TAILQ_FOREACH(prf64, &rai->rai_pref64, p64_next)
|
||||
len += sizeof(*prf64);
|
||||
|
||||
syslog(LOG_DEBUG, "<%s> len = %zu", __func__, len);
|
||||
|
||||
p = malloc(len);
|
||||
if (p == NULL)
|
||||
exit(1);
|
||||
memset(p, 0, len);
|
||||
cp->cp_val = p;
|
||||
|
||||
prf64_cnt = (uint16_t *)cp->cp_val;
|
||||
p += sizeof(*prf64_cnt);
|
||||
TAILQ_FOREACH(prf64, &rai->rai_pref64, p64_next) {
|
||||
(*prf64_cnt)++;
|
||||
memcpy(p, prf64, sizeof(*prf64));
|
||||
p += sizeof(*prf64);
|
||||
}
|
||||
cp->cp_val_len = p - cp->cp_val;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
cm_getprop(struct ctrl_msg_pl *cp)
|
||||
{
|
||||
|
||||
@@ -137,6 +137,7 @@ union nd_opt {
|
||||
#define NDOPT_FLAG_MTU (1 << 4)
|
||||
#define NDOPT_FLAG_RDNSS (1 << 5)
|
||||
#define NDOPT_FLAG_DNSSL (1 << 6)
|
||||
#define NDOPT_FLAG_PREF64 (1 << 7)
|
||||
|
||||
static uint32_t ndopt_flags[] = {
|
||||
[ND_OPT_SOURCE_LINKADDR] = NDOPT_FLAG_SRCLINKADDR,
|
||||
@@ -146,6 +147,7 @@ static uint32_t ndopt_flags[] = {
|
||||
[ND_OPT_MTU] = NDOPT_FLAG_MTU,
|
||||
[ND_OPT_RDNSS] = NDOPT_FLAG_RDNSS,
|
||||
[ND_OPT_DNSSL] = NDOPT_FLAG_DNSSL,
|
||||
[ND_OPT_PREF64] = NDOPT_FLAG_PREF64,
|
||||
};
|
||||
|
||||
static void rtadvd_shutdown(void);
|
||||
@@ -1083,7 +1085,7 @@ ra_input(int len, struct nd_router_advert *nra,
|
||||
error = nd6_options((struct nd_opt_hdr *)(nra + 1),
|
||||
len - sizeof(struct nd_router_advert), &ndopts,
|
||||
NDOPT_FLAG_SRCLINKADDR | NDOPT_FLAG_PREFIXINFO | NDOPT_FLAG_MTU |
|
||||
NDOPT_FLAG_RDNSS | NDOPT_FLAG_DNSSL);
|
||||
NDOPT_FLAG_RDNSS | NDOPT_FLAG_DNSSL | NDOPT_FLAG_PREF64);
|
||||
if (error) {
|
||||
syslog(LOG_INFO,
|
||||
"<%s> ND option check failed for an RA from %s on %s",
|
||||
@@ -1428,7 +1430,8 @@ nd6_options(struct nd_opt_hdr *hdr, int limit,
|
||||
|
||||
if (hdr->nd_opt_type > ND_OPT_MTU &&
|
||||
hdr->nd_opt_type != ND_OPT_RDNSS &&
|
||||
hdr->nd_opt_type != ND_OPT_DNSSL) {
|
||||
hdr->nd_opt_type != ND_OPT_DNSSL &&
|
||||
hdr->nd_opt_type != ND_OPT_PREF64) {
|
||||
syslog(LOG_INFO, "<%s> unknown ND option(type %d)",
|
||||
__func__, hdr->nd_opt_type);
|
||||
continue;
|
||||
@@ -1473,6 +1476,7 @@ nd6_options(struct nd_opt_hdr *hdr, int limit,
|
||||
case ND_OPT_REDIRECTED_HEADER:
|
||||
case ND_OPT_RDNSS:
|
||||
case ND_OPT_DNSSL:
|
||||
case ND_OPT_PREF64:
|
||||
break; /* we don't care about these options */
|
||||
case ND_OPT_SOURCE_LINKADDR:
|
||||
case ND_OPT_MTU:
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
.\" SUCH DAMAGE.
|
||||
.\"
|
||||
.Dd June 4, 2011
|
||||
.Dd January 14, 2026
|
||||
.Dt RTADVD.CONF 5
|
||||
.Os
|
||||
.Sh NAME
|
||||
@@ -435,6 +435,21 @@ These items are optional.
|
||||
.Bl -tag -width indent
|
||||
.It Cm \&pref64
|
||||
(str) The prefix to advertise in the PREF64 option.
|
||||
Multiple PREF64 prefixes can be specified by seperating entries using
|
||||
.Cm pref64 ,
|
||||
.Cm pref640 ,
|
||||
.Cm pref641 ,
|
||||
.Cm pref642 ...
|
||||
options with corresponding
|
||||
.Cm pref64len ,
|
||||
.Cm pref64len0 ,
|
||||
.Cm pref64len1 ,
|
||||
.Cm pref64len2 ...
|
||||
entries.
|
||||
This is also true for the
|
||||
.Cm pref64lifetime
|
||||
option.
|
||||
Note that the maximum number of prefixes depends on the receiver side.
|
||||
.It Cm \&pref64len
|
||||
(num) The length of the PREF64 prefix.
|
||||
This must be 96, 64, 56, 48, 40, or 32.
|
||||
@@ -484,13 +499,15 @@ ef0:\\
|
||||
.Pp
|
||||
The following example configures the
|
||||
.Li wlan0
|
||||
interface and adds two DNS servers and a DNS domain search options
|
||||
interface and adds two DNS servers, a DNS domain search,
|
||||
and a PREF64 prefix,
|
||||
using the default option lifetime values.
|
||||
.Bd -literal -offset indent
|
||||
wlan0:\\
|
||||
:addr="2001:db8:ffff:1000::":prefixlen#64:\\
|
||||
:rdnss="2001:db8:ffff::10,2001:db8:ffff::2:43":\\
|
||||
:dnssl="example.com":
|
||||
:dnssl="example.com":\\
|
||||
:pref64="64:ff9b::":
|
||||
.Ed
|
||||
.Pp
|
||||
The following example presents the default values in an explicit manner.
|
||||
|
||||
@@ -152,7 +152,6 @@ struct rdnss {
|
||||
|
||||
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;
|
||||
@@ -227,7 +226,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 */
|
||||
TAILQ_HEAD(, pref64) rai_pref64; /* PREF64 option */
|
||||
|
||||
/* info about soliciter */
|
||||
TAILQ_HEAD(, soliciter) rai_soliciter; /* recent solication source */
|
||||
|
||||
Reference in New Issue
Block a user