Configuration.
-/* $OpenBSD: engine.c,v 1.6 2018/07/11 19:05:25 florian Exp $ */
+/* $OpenBSD: engine.c,v 1.7 2018/07/15 09:28:21 florian Exp $ */
/*
* Copyright (c) 2018 Florian Obser <florian@openbsd.org>
#include "rad.h"
#include "engine.h"
-#define MAX_RTR_ADV_INTERVAL 600
-#define MIN_RTR_ADV_INTERVAL 200
-
struct engine_iface {
TAILQ_ENTRY(engine_iface) entry;
struct event timer;
struct imsgev *iev = bula;
struct imsgbuf *ibuf;
struct ra_prefix_conf *ra_prefix_conf;
+ struct ra_rdnss_conf *ra_rdnss_conf;
+ struct ra_dnssl_conf *ra_dnssl_conf;
ssize_t n;
int shut = 0;
sizeof(struct ra_iface_conf));
ra_iface_conf->autoprefix = NULL;
SIMPLEQ_INIT(&ra_iface_conf->ra_prefix_list);
+ SIMPLEQ_INIT(&ra_iface_conf->ra_rdnss_list);
+ SIMPLEQ_INIT(&ra_iface_conf->ra_dnssl_list);
SIMPLEQ_INSERT_TAIL(&nconf->ra_iface_list,
ra_iface_conf, entry);
break;
SIMPLEQ_INSERT_TAIL(&ra_iface_conf->ra_prefix_list,
ra_prefix_conf, entry);
break;
+ case IMSG_RECONF_RA_RDNS_LIFETIME:
+ ra_iface_conf->rdns_lifetime = *((uint32_t *)imsg.data);
+ break;
+ case IMSG_RECONF_RA_RDNSS:
+ if ((ra_rdnss_conf = malloc(sizeof(struct
+ ra_rdnss_conf))) == NULL)
+ fatal(NULL);
+ memcpy(ra_rdnss_conf, imsg.data, sizeof(struct
+ ra_rdnss_conf));
+ SIMPLEQ_INSERT_TAIL(&ra_iface_conf->ra_rdnss_list,
+ ra_rdnss_conf, entry);
+ break;
+ case IMSG_RECONF_RA_DNSSL:
+ if ((ra_dnssl_conf = malloc(sizeof(struct
+ ra_dnssl_conf))) == NULL)
+ fatal(NULL);
+ memcpy(ra_dnssl_conf, imsg.data, sizeof(struct
+ ra_dnssl_conf));
+ SIMPLEQ_INSERT_TAIL(&ra_iface_conf->ra_dnssl_list,
+ ra_dnssl_conf, entry);
+ break;
case IMSG_RECONF_END:
merge_config(engine_conf, nconf);
nconf = NULL;
-/* $OpenBSD: frontend.c,v 1.9 2018/07/15 09:26:26 florian Exp $ */
+/* $OpenBSD: frontend.c,v 1.10 2018/07/15 09:28:21 florian Exp $ */
/*
* Copyright (c) 2018 Florian Obser <florian@openbsd.org>
struct imsgev *iev = bula;
struct imsgbuf *ibuf = &iev->ibuf;
struct ra_prefix_conf *ra_prefix_conf;
+ struct ra_rdnss_conf *ra_rdnss_conf;
+ struct ra_dnssl_conf *ra_dnssl_conf;
int n, shut = 0;
if (event & EV_READ) {
ra_iface_conf));
ra_iface_conf->autoprefix = NULL;
SIMPLEQ_INIT(&ra_iface_conf->ra_prefix_list);
+ SIMPLEQ_INIT(&ra_iface_conf->ra_rdnss_list);
+ SIMPLEQ_INIT(&ra_iface_conf->ra_dnssl_list);
SIMPLEQ_INSERT_TAIL(&nconf->ra_iface_list,
ra_iface_conf, entry);
break;
SIMPLEQ_INSERT_TAIL(&ra_iface_conf->ra_prefix_list,
ra_prefix_conf, entry);
break;
+ case IMSG_RECONF_RA_RDNS_LIFETIME:
+ ra_iface_conf->rdns_lifetime = *((uint32_t *)imsg.data);
+ break;
+ case IMSG_RECONF_RA_RDNSS:
+ if ((ra_rdnss_conf = malloc(sizeof(struct
+ ra_rdnss_conf))) == NULL)
+ fatal(NULL);
+ memcpy(ra_rdnss_conf, imsg.data, sizeof(struct
+ ra_rdnss_conf));
+ SIMPLEQ_INSERT_TAIL(&ra_iface_conf->ra_rdnss_list,
+ ra_rdnss_conf, entry);
+ break;
+ case IMSG_RECONF_RA_DNSSL:
+ if ((ra_dnssl_conf = malloc(sizeof(struct
+ ra_dnssl_conf))) == NULL)
+ fatal(NULL);
+ memcpy(ra_dnssl_conf, imsg.data, sizeof(struct
+ ra_dnssl_conf));
+ SIMPLEQ_INSERT_TAIL(&ra_iface_conf->ra_dnssl_list,
+ ra_dnssl_conf, entry);
+ break;
case IMSG_RECONF_END:
merge_config(frontend_conf, nconf);
merge_ra_interfaces();
struct ra_iface_conf *ra_iface_conf;
struct ra_options_conf *ra_options_conf;
struct ra_prefix_conf *ra_prefix_conf;
- size_t len;
+ struct nd_opt_rdnss *ndopt_rdnss;
+ struct nd_opt_dnssl *ndopt_dnssl;
+ struct ra_rdnss_conf *ra_rdnss;
+ struct ra_dnssl_conf *ra_dnssl;
+ size_t len, label_len;
uint8_t *p, buf[RA_MAX_SIZE];
+ char *label_start, *label_end;
ra_iface_conf = find_ra_iface_conf(&frontend_conf->ra_iface_list,
ra_iface->name);
len = sizeof(*ra);
len += sizeof(*ndopt_pi) * ra_iface->prefix_count;
+ if (ra_iface_conf->rdnss_count > 0)
+ len += sizeof(*ndopt_rdnss) + ra_iface_conf->rdnss_count *
+ sizeof(struct in6_addr);
+
+ if (ra_iface_conf->dnssl_len > 0)
+ /* round up to 8 byte boundary */
+ len += sizeof(*ndopt_dnssl) + ((ra_iface_conf->dnssl_len + 7)
+ & ~7);
if (len > sizeof(ra_iface->data))
fatal("%s: packet too big", __func__); /* XXX send multiple */
p += sizeof(*ndopt_pi);
}
+ if (ra_iface_conf->rdnss_count > 0) {
+ ndopt_rdnss = (struct nd_opt_rdnss *)p;
+ ndopt_rdnss->nd_opt_rdnss_type = ND_OPT_RDNSS;
+ ndopt_rdnss->nd_opt_rdnss_len = 1 +
+ ra_iface_conf->rdnss_count * 2;
+ ndopt_rdnss->nd_opt_rdnss_reserved = 0;
+ ndopt_rdnss->nd_opt_rdnss_lifetime =
+ htonl(ra_iface_conf->rdns_lifetime);
+ p += sizeof(struct nd_opt_rdnss);
+ SIMPLEQ_FOREACH(ra_rdnss, &ra_iface_conf->ra_rdnss_list,
+ entry) {
+ memcpy(p, &ra_rdnss->rdnss, sizeof(ra_rdnss->rdnss));
+ p += sizeof(ra_rdnss->rdnss);
+ }
+ }
+
+ if (ra_iface_conf->dnssl_len > 0) {
+ ndopt_dnssl = (struct nd_opt_dnssl *)p;
+ ndopt_dnssl->nd_opt_dnssl_type = ND_OPT_DNSSL;
+ /* round up to 8 byte boundary */
+ ndopt_dnssl->nd_opt_dnssl_len = 1 +
+ ((ra_iface_conf->dnssl_len + 7) & ~7) / 8;
+ ndopt_dnssl->nd_opt_dnssl_reserved = 0;
+ ndopt_dnssl->nd_opt_dnssl_lifetime =
+ htonl(ra_iface_conf->rdns_lifetime);
+ p += sizeof(struct nd_opt_dnssl);
+
+ SIMPLEQ_FOREACH(ra_dnssl, &ra_iface_conf->ra_dnssl_list,
+ entry) {
+ label_start = ra_dnssl->search;
+ while ((label_end = strchr(label_start, '.')) != NULL) {
+ label_len = label_end - label_start;
+ *p++ = label_len;
+ memcpy(p, label_start, label_len);
+ p += label_len;
+ label_start = label_end + 1;
+ }
+ *p++ = '\0'; /* last dot */
+ }
+ /* zero pad */
+ while (((uintptr_t)p) % 8 != 0)
+ *p++ = '\0';
+ }
+
if (len != ra_iface->datalen || memcmp(buf, ra_iface->data, len)
!= 0) {
memcpy(ra_iface->data, buf, len);
-/* $OpenBSD: parse.y,v 1.2 2018/07/11 08:47:03 florian Exp $ */
+/* $OpenBSD: parse.y,v 1.3 2018/07/15 09:28:21 florian Exp $ */
/*
* Copyright (c) 2018 Florian Obser <florian@openbsd.org>
%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
+%token ADDRESS_CONFIGURATION DNS RESOLVER SEARCH
%token <v.string> STRING
%token <v.number> NUMBER
} ra_prefix_block {
ra_prefix_conf = NULL;
}
+ | DNS dns_block
| ra_opt_block
;
ra_prefix_conf->aflag = $3;
}
;
+dns_block : '{' optnl dnsopts_l '}'
+ | '{' optnl '}'
+ | /* empty */
+ ;
+
+dnsopts_l : dnsopts_l dnsoptsl nl
+ | dnsoptsl optnl
+ ;
+dnsoptsl : LIFETIME NUMBER {
+ ra_iface_conf->rdns_lifetime = $2;
+ }
+ | RESOLVER resolver_block
+ | SEARCH search_block
+ ;
+resolver_block : '{' optnl resolveropts_l '}'
+ | '{' optnl '}'
+ | resolveroptsl
+ | /* empty */
+ ;
+
+resolveropts_l : resolveropts_l resolveroptsl optnl
+ | resolveroptsl optnl
+ ;
+
+resolveroptsl : STRING {
+ struct ra_rdnss_conf *ra_rdnss_conf;
+ struct in6_addr addr;
+
+ memset(&addr, 0, sizeof(addr));
+ if (inet_pton(AF_INET6, $1, &addr)
+ != 1) {
+ yyerror("error parsing resolver address %s",
+ $1);
+ free($1);
+ YYERROR;
+ }
+ if ((ra_rdnss_conf = calloc(1, sizeof(*ra_rdnss_conf)))
+ == NULL)
+ err(1, "%s", __func__);
+ memcpy(&ra_rdnss_conf->rdnss, &addr, sizeof(addr));
+ SIMPLEQ_INSERT_TAIL(&ra_iface_conf->ra_rdnss_list,
+ ra_rdnss_conf, entry);
+ ra_iface_conf->rdnss_count++;
+ }
+ ;
+search_block : '{' optnl searchopts_l '}'
+ | '{' optnl '}'
+ | searchoptsl
+ | /* empty */
+ ;
+
+searchopts_l : searchopts_l searchoptsl optnl
+ | searchoptsl optnl
+ ;
+
+searchoptsl : STRING {
+ struct ra_dnssl_conf *ra_dnssl_conf;
+ size_t len;
+
+ if ((ra_dnssl_conf = calloc(1,
+ sizeof(*ra_dnssl_conf))) == NULL)
+ err(1, "%s", __func__);
+
+ if ((len = strlcpy(ra_dnssl_conf->search, $1,
+ sizeof(ra_dnssl_conf->search))) >
+ sizeof(ra_dnssl_conf->search)) {
+ yyerror("search string too long");
+ free($1);
+ YYERROR;
+ }
+ if (ra_dnssl_conf->search[len] != '.') {
+ if ((len = strlcat(ra_dnssl_conf->search, ".",
+ sizeof(ra_dnssl_conf->search))) >
+ sizeof(ra_dnssl_conf->search)) {
+ yyerror("search string too long");
+ free($1);
+ YYERROR;
+ }
+ }
+ SIMPLEQ_INSERT_TAIL(&ra_iface_conf->ra_dnssl_list,
+ ra_dnssl_conf, entry);
+ ra_iface_conf->dnssl_len += len + 1;
+ }
+ ;
%%
struct keywords {
{"autonomous", AUTONOMOUS},
{"configuration", CONFIGURATION},
{"default", DEFAULT},
+ {"dns", DNS},
{"hop", HOP},
{"include", INCLUDE},
{"interface", RA_IFACE},
{"preferred", PREFERRED},
{"prefix", PREFIX},
{"reachable", REACHABLE},
+ {"resolver", RESOLVER},
{"retrans", RETRANS},
{"router", ROUTER},
+ {"search", SEARCH},
{"time", TIME},
{"timer", TIMER},
{"valid", VALID},
/* Inherit attributes set in global section. */
iface->ra_options = conf->ra_options;
+ iface->rdns_lifetime = DEFAULT_RDNS_LIFETIME;
+
SIMPLEQ_INIT(&iface->ra_prefix_list);
+ SIMPLEQ_INIT(&iface->ra_rdnss_list);
+ SIMPLEQ_INIT(&iface->ra_dnssl_list);
SIMPLEQ_INSERT_TAIL(&conf->ra_iface_list, iface, entry);
-/* $OpenBSD: printconf.c,v 1.1 2018/07/10 16:39:54 florian Exp $ */
+/* $OpenBSD: printconf.c,v 1.2 2018/07/15 09:28:21 florian Exp $ */
/*
* Copyright (c) 2018 Florian Obser <florian@openbsd.org>
{
struct ra_iface_conf *iface;
struct ra_prefix_conf *prefix;
+ struct ra_rdnss_conf *ra_rdnss;
+ struct ra_dnssl_conf *ra_dnssl;
char buf[INET6_ADDRSTRLEN], *bufp;
print_ra_options("", &conf->ra_options);
printf("\t}\n");
}
+ if (!SIMPLEQ_EMPTY(&iface->ra_rdnss_list) ||
+ !SIMPLEQ_EMPTY(&iface->ra_dnssl_list)) {
+ printf("\tdns {\n");
+ printf("\t\tlifetime %u\n", iface->rdns_lifetime);
+ if (!SIMPLEQ_EMPTY(&iface->ra_rdnss_list)) {
+ printf("\t\tresolver {\n");
+ SIMPLEQ_FOREACH(ra_rdnss,
+ &iface->ra_rdnss_list, entry) {
+ inet_ntop(AF_INET6, &ra_rdnss->rdnss,
+ buf, sizeof(buf));
+ printf("\t\t\t%s\n", buf);
+ }
+ printf("\t\t}\n");
+ }
+ if (!SIMPLEQ_EMPTY(&iface->ra_dnssl_list)) {
+ printf("\t\tsearch {\n");
+ SIMPLEQ_FOREACH(ra_dnssl,
+ &iface->ra_dnssl_list, entry)
+ printf("\t\t\t%s\n", ra_dnssl->search);
+ printf("\t\t}\n");
+ }
+ printf("\t}\n");
+ }
+
printf("}\n");
}
}
-/* $OpenBSD: rad.c,v 1.7 2018/07/13 09:16:15 florian Exp $ */
+/* $OpenBSD: rad.c,v 1.8 2018/07/15 09:28:21 florian Exp $ */
/*
* Copyright (c) 2018 Florian Obser <florian@openbsd.org>
{
struct ra_iface_conf *ra_iface_conf;
struct ra_prefix_conf *ra_prefix_conf;
+ struct ra_rdnss_conf *ra_rdnss_conf;
+ struct ra_dnssl_conf *ra_dnssl_conf;
/* Send fixed part of config to children. */
if (main_sendboth(IMSG_RECONF_CONF, xconf, sizeof(*xconf)) == -1)
ra_prefix_conf, sizeof(*ra_prefix_conf)) == -1)
return (-1);
}
+ if (main_sendboth(IMSG_RECONF_RA_RDNS_LIFETIME,
+ &ra_iface_conf->rdns_lifetime,
+ sizeof(ra_iface_conf->rdns_lifetime)) == -1)
+ return (-1);
+ SIMPLEQ_FOREACH(ra_rdnss_conf, &ra_iface_conf->ra_rdnss_list,
+ entry) {
+ if (main_sendboth(IMSG_RECONF_RA_RDNSS, ra_rdnss_conf,
+ sizeof(*ra_rdnss_conf)) == -1)
+ return (-1);
+ }
+ SIMPLEQ_FOREACH(ra_dnssl_conf, &ra_iface_conf->ra_dnssl_list,
+ entry) {
+ if (main_sendboth(IMSG_RECONF_RA_DNSSL, ra_dnssl_conf,
+ sizeof(*ra_dnssl_conf)) == -1)
+ return (-1);
+ }
}
/* Tell children the revised config is now complete. */
-.\" $OpenBSD: rad.conf.5,v 1.4 2018/07/15 09:27:02 florian Exp $
+.\" $OpenBSD: rad.conf.5,v 1.5 2018/07/15 09:28:21 florian Exp $
.\"
.\" Copyright (c) 2018 Florian Obser <florian@openbsd.org>
.\" Copyright (c) 2005 Esben Norby <norby@openbsd.org>
prefix.
The default is 2592000.
.El
+.Pp
+Recursive resolvers are configured inside an interface block:
+.Bd -unfilled -offset indent
+.Ic dns Brq dns options
+.Ed
+.Pp
+.Ic dns
+options are as follows:
+.Bl -tag -width Ds
+.It Ic lifetime Ar seconds
+The number of seconds the dns options are valid after receiving a router
+advertisement message.
+The default is 900 seconds.
+.It Ic resolver Pq Ar IP Ns | Ns { resolver list }
+IPv6 address or list of IPv6 addresses of recursive dns resolvers.
+.It Ic search Pq Ar domain Ns | Ns { domain list }
+Domain or list of domains for the
+.Xr resolv.conf 5
+search list.
+.El
.Sh FILES
.Bl -tag -width "/etc/rad.conf" -compact
.It Pa /etc/rad.conf
-/* $OpenBSD: rad.h,v 1.10 2018/07/15 09:25:41 florian Exp $ */
+/* $OpenBSD: rad.h,v 1.11 2018/07/15 09:28:21 florian Exp $ */
/*
* Copyright (c) 2018 Florian Obser <florian@openbsd.org>
#define OPT_NOACTION 0x00000004
+#define MAX_RTR_ADV_INTERVAL 600
+#define MIN_RTR_ADV_INTERVAL 200
+#define MAX_SEARCH 1025 /* same as MAXDNAME in arpa/nameser.h */
+#define DEFAULT_RDNS_LIFETIME 600 * 1.5
+
enum {
PROC_MAIN,
PROC_ENGINE,
IMSG_RECONF_RA_IFACE,
IMSG_RECONF_RA_AUTOPREFIX,
IMSG_RECONF_RA_PREFIX,
+ IMSG_RECONF_RA_RDNS_LIFETIME,
+ IMSG_RECONF_RA_RDNSS,
+ IMSG_RECONF_RA_DNSSL,
IMSG_RECONF_END,
IMSG_ICMP6SOCK,
IMSG_ROUTESOCK,
int aflag; /* autonom. addr flag */
};
+/* RFC 8106 */
+struct ra_rdnss_conf {
+ SIMPLEQ_ENTRY(ra_rdnss_conf) entry;
+ struct in6_addr rdnss;
+};
+struct ra_dnssl_conf {
+ SIMPLEQ_ENTRY(ra_dnssl_conf) entry;
+ char search[MAX_SEARCH];
+};
+
struct ra_iface_conf {
- SIMPLEQ_ENTRY(ra_iface_conf) entry;
- struct ra_options_conf ra_options;
- struct ra_prefix_conf *autoprefix;
+ SIMPLEQ_ENTRY(ra_iface_conf) entry;
+ struct ra_options_conf ra_options;
+ struct ra_prefix_conf *autoprefix;
SIMPLEQ_HEAD(ra_prefix_conf_head,
- ra_prefix_conf) ra_prefix_list;
- char name[IF_NAMESIZE];
+ ra_prefix_conf) ra_prefix_list;
+ uint32_t rdns_lifetime;
+ SIMPLEQ_HEAD(, ra_rdnss_conf) ra_rdnss_list;
+ int rdnss_count;
+ SIMPLEQ_HEAD(, ra_dnssl_conf) ra_dnssl_list;
+ int dnssl_len;
+ char name[IF_NAMESIZE];
};
struct rad_conf {