-/* $OpenBSD: engine.c,v 1.20 2022/03/23 15:26:08 florian Exp $ */
+/* $OpenBSD: engine.c,v 1.21 2022/10/15 13:26:15 florian Exp $ */
/*
* Copyright (c) 2018 Florian Obser <florian@openbsd.org>
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;
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:
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;
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 "
-/* $OpenBSD: frontend.c,v 1.40 2022/01/17 18:04:35 naddy Exp $ */
+/* $OpenBSD: frontend.c,v 1.41 2022/10/15 13:26:15 florian Exp $ */
/*
* Copyright (c) 2018 Florian Obser <florian@openbsd.org>
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);
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) {
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:
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;
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 "
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;
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 */
*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);
-/* $OpenBSD: parse.y,v 1.19 2021/10/15 15:01:28 naddy Exp $ */
+/* $OpenBSD: parse.y,v 1.20 2022/10/15 13:26:15 florian Exp $ */
/*
* Copyright (c) 2018 Florian Obser <florian@openbsd.org>
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 {
%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
| 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
;
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 */
{"managed", MANAGED},
{"mtu", MTU},
{"nameserver", NAMESERVER},
+ {"nat64", NAT64},
{"no", NO},
{"on-link", ONLINK},
{"other", OTHER},
&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);
}
}
}
+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)
+ err(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)
{
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)
+ err(1, "%s", __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)
{
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);
-/* $OpenBSD: printconf.c,v 1.6 2021/01/19 17:38:41 florian Exp $ */
+/* $OpenBSD: printconf.c,v 1.7 2022/10/15 13:26:15 florian Exp $ */
/*
* Copyright (c) 2018 Florian Obser <florian@openbsd.org>
{
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));
}
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
-.\" $OpenBSD: rad.8,v 1.6 2019/11/10 20:51:53 landry Exp $
+.\" $OpenBSD: rad.8,v 1.7 2022/10/15 13:26:15 florian Exp $
.\"
.\" Copyright (c) 2018 Florian Obser <florian@openbsd.org>
.\" Copyright (c) 2016 Kenneth R Westerback <kwesterback@gmail.com>
.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
.\"
-.Dd $Mdocdate: November 10 2019 $
+.Dd $Mdocdate: October 15 2022 $
.Dt RAD 8
.Os
.Sh NAME
.%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
-/* $OpenBSD: rad.c,v 1.27 2021/02/27 10:35:20 florian Exp $ */
+/* $OpenBSD: rad.c,v 1.28 2022/10/15 13:26:15 florian Exp $ */
/*
* Copyright (c) 2018 Florian Obser <florian@openbsd.org>
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)
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,
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. */
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;
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);
}
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) {
}
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);
&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);
}
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);
}
-.\" $OpenBSD: rad.conf.5,v 1.18 2022/09/23 19:24:08 florian Exp $
+.\" $OpenBSD: rad.conf.5,v 1.19 2022/10/15 13:26:15 florian Exp $
.\"
.\" Copyright (c) 2018 Florian Obser <florian@openbsd.org>
.\" Copyright (c) 2005 Esben Norby <norby@openbsd.org>
.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
.\"
-.Dd $Mdocdate: September 23 2022 $
+.Dd $Mdocdate: October 15 2022 $
.Dt RAD.CONF 5
.Os
.Sh NAME
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.
.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:
-/* $OpenBSD: rad.h,v 1.22 2022/03/23 15:26:08 florian Exp $ */
+/* $OpenBSD: rad.h,v 1.23 2022/10/15 13:26:15 florian Exp $ */
/*
* Copyright (c) 2018 Florian Obser <florian@openbsd.org>
IMSG_RECONF_RA_PREFIX,
IMSG_RECONF_RA_RDNSS,
IMSG_RECONF_RA_DNSSL,
+ IMSG_RECONF_RA_PREF64,
IMSG_RECONF_END,
IMSG_ICMP6SOCK,
IMSG_OPEN_ICMP6SOCK,
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? */
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 */