summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFlorian Obser <florian@cvs.openbsd.org>2020-09-14 09:07:06 +0000
committerFlorian Obser <florian@cvs.openbsd.org>2020-09-14 09:07:06 +0000
commit11046a3d863960b14f1311eecb3b17cb9363fa68 (patch)
treee1776274f5c6ff82bd0b68c584fc757f02608525
parent5352130e146793b264d6d0dff61305cf25a21b97 (diff)
Let slaacd handle all rdomains in a single daemon.
Suggested by claudio and matthieu Testing matthieu Putting it in now to get enough testing before release so that there is enough time to back it out, suggested by deraadt
-rw-r--r--sbin/slaacd/engine.c48
-rw-r--r--sbin/slaacd/engine.h3
-rw-r--r--sbin/slaacd/frontend.c258
-rw-r--r--sbin/slaacd/slaacd.c107
-rw-r--r--sbin/slaacd/slaacd.h6
-rw-r--r--usr.sbin/slaacctl/slaacctl.c15
6 files changed, 279 insertions, 158 deletions
diff --git a/sbin/slaacd/engine.c b/sbin/slaacd/engine.c
index 543e55b52bc..2b3f5c43122 100644
--- a/sbin/slaacd/engine.c
+++ b/sbin/slaacd/engine.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: engine.c,v 1.48 2020/03/28 16:15:45 florian Exp $ */
+/* $OpenBSD: engine.c,v 1.49 2020/09/14 09:07:05 florian Exp $ */
/*
* Copyright (c) 2017 Florian Obser <florian@openbsd.org>
@@ -208,6 +208,7 @@ struct dfr_proposal {
struct timespec when;
struct timespec uptime;
uint32_t if_index;
+ int rdomain;
struct sockaddr_in6 addr;
uint32_t router_lifetime;
enum rpref rpref;
@@ -223,6 +224,7 @@ struct rdns_proposal {
struct timespec when;
struct timespec uptime;
uint32_t if_index;
+ int rdomain;
struct sockaddr_in6 from;
int rdns_count;
struct in6_addr rdns[MAX_RDNS_COUNT];
@@ -235,6 +237,7 @@ struct slaacd_iface {
struct event timer;
int probes;
uint32_t if_index;
+ uint32_t rdomain;
int running;
int autoconfprivacy;
int soii;
@@ -285,7 +288,7 @@ void gen_rdns_proposal(struct slaacd_iface *, struct
radv *);
void propose_rdns(struct rdns_proposal *);
void free_rdns_proposal(struct rdns_proposal *);
-void compose_rdns_proposal(uint32_t);
+void compose_rdns_proposal(uint32_t, int);
#endif /* SMALL */
char *parse_dnssl(char *, int);
void update_iface_ra(struct slaacd_iface *, struct radv *);
@@ -582,7 +585,8 @@ engine_dispatch_frontend(int fd, short event, void *bula)
#ifndef SMALL
case IMSG_REPROPOSE_RDNS:
LIST_FOREACH (iface, &slaacd_interfaces, entries)
- compose_rdns_proposal(iface->if_index);
+ compose_rdns_proposal(iface->if_index,
+ iface->rdomain);
break;
#endif /* SMALL */
default:
@@ -680,6 +684,7 @@ engine_dispatch_main(int fd, short event, void *bula)
evtimer_set(&iface->timer, iface_timeout,
iface);
iface->if_index = imsg_ifinfo.if_index;
+ iface->rdomain = imsg_ifinfo.rdomain;
iface->running = imsg_ifinfo.running;
if (iface->running)
start_probe(iface);
@@ -1107,7 +1112,7 @@ remove_slaacd_iface(uint32_t if_index)
rdns_proposal = LIST_FIRST(&iface->rdns_proposals);
free_rdns_proposal(rdns_proposal);
}
- compose_rdns_proposal(iface->if_index);
+ compose_rdns_proposal(iface->if_index, iface->rdomain);
#endif /* SMALL */
evtimer_del(&iface->timer);
free(iface);
@@ -1149,6 +1154,7 @@ free_ra(struct radv *ra)
void
parse_ra(struct slaacd_iface *iface, struct imsg_ra *ra)
{
+ struct icmp6_hdr *icmp6_hdr;
struct nd_router_advert *nd_ra;
struct radv *radv;
struct radv_prefix *prefix;
@@ -1164,6 +1170,17 @@ parse_ra(struct slaacd_iface *iface, struct imsg_ra *ra)
#endif /* SMALL */
hbuf = sin6_to_str(&ra->from);
+ if ((size_t)len < sizeof(struct icmp6_hdr)) {
+ log_warnx("received too short message (%ld) from %s", len,
+ hbuf);
+ return;
+ }
+
+ p = ra->packet;
+ icmp6_hdr = (struct icmp6_hdr *)p;
+ if (icmp6_hdr->icmp6_type != ND_ROUTER_ADVERT)
+ return;
+
if (!IN6_IS_ADDR_LINKLOCAL(&ra->from.sin6_addr)) {
log_debug("RA from non link local address %s", hbuf);
return;
@@ -1184,7 +1201,6 @@ parse_ra(struct slaacd_iface *iface, struct imsg_ra *ra)
radv->min_lifetime = UINT32_MAX;
- p = ra->packet;
nd_ra = (struct nd_router_advert *)p;
len -= sizeof(struct nd_router_advert);
p += sizeof(struct nd_router_advert);
@@ -1192,12 +1208,6 @@ parse_ra(struct slaacd_iface *iface, struct imsg_ra *ra)
log_debug("ICMPv6 type(%d), code(%d) from %s of length %ld",
nd_ra->nd_ra_type, nd_ra->nd_ra_code, hbuf, len);
- if (nd_ra->nd_ra_type != ND_ROUTER_ADVERT) {
- log_warnx("invalid ICMPv6 type (%d) from %s", nd_ra->nd_ra_type,
- hbuf);
- goto err;
- }
-
if (nd_ra->nd_ra_code != 0) {
log_warnx("invalid ICMPv6 code (%d) from %s", nd_ra->nd_ra_code,
hbuf);
@@ -2108,6 +2118,7 @@ gen_dfr_proposal(struct slaacd_iface *iface, struct radv *ra)
dfr_proposal->when = ra->when;
dfr_proposal->uptime = ra->uptime;
dfr_proposal->if_index = iface->if_index;
+ dfr_proposal->rdomain = iface->rdomain;
memcpy(&dfr_proposal->addr, &ra->from,
sizeof(dfr_proposal->addr));
dfr_proposal->router_lifetime = ra->router_lifetime;
@@ -2152,6 +2163,7 @@ configure_dfr(struct dfr_proposal *dfr_proposal)
}
dfr.if_index = dfr_proposal->if_index;
+ dfr.rdomain = dfr_proposal->rdomain;
memcpy(&dfr.addr, &dfr_proposal->addr, sizeof(dfr.addr));
dfr.router_lifetime = dfr_proposal->router_lifetime;
@@ -2166,6 +2178,7 @@ withdraw_dfr(struct dfr_proposal *dfr_proposal)
log_debug("%s: %d", __func__, dfr_proposal->if_index);
dfr.if_index = dfr_proposal->if_index;
+ dfr.rdomain = dfr_proposal->rdomain;
memcpy(&dfr.addr, &dfr_proposal->addr, sizeof(dfr.addr));
dfr.router_lifetime = dfr_proposal->router_lifetime;
@@ -2211,6 +2224,7 @@ gen_rdns_proposal(struct slaacd_iface *iface, struct radv *ra)
rdns_proposal->when = ra->when;
rdns_proposal->uptime = ra->uptime;
rdns_proposal->if_index = iface->if_index;
+ rdns_proposal->rdomain = iface->rdomain;
memcpy(&rdns_proposal->from, &ra->from,
sizeof(rdns_proposal->from));
rdns_proposal->rdns_lifetime = ra->rdns_lifetime;
@@ -2257,11 +2271,11 @@ propose_rdns(struct rdns_proposal *rdns_proposal)
/* nothing to do here rDNS proposals do not expire */
return;
}
- compose_rdns_proposal(rdns_proposal->if_index);
+ compose_rdns_proposal(rdns_proposal->if_index, rdns_proposal->rdomain);
}
void
-compose_rdns_proposal(uint32_t if_index)
+compose_rdns_proposal(uint32_t if_index, int rdomain)
{
struct imsg_propose_rdns rdns;
struct slaacd_iface *iface;
@@ -2270,6 +2284,7 @@ compose_rdns_proposal(uint32_t if_index)
memset(&rdns, 0, sizeof(rdns));
rdns.if_index = if_index;
+ rdns.rdomain = rdomain;
if ((iface = get_slaacd_iface_by_id(if_index)) != NULL) {
LIST_FOREACH(rdns_proposal, &iface->rdns_proposals, entries) {
@@ -2445,7 +2460,6 @@ rdns_proposal_timeout(int fd, short events, void *arg)
{
struct rdns_proposal *rdns_proposal;
struct timeval tv;
- uint32_t if_index;
const char *hbuf;
rdns_proposal = (struct rdns_proposal *)arg;
@@ -2471,10 +2485,10 @@ rdns_proposal_timeout(int fd, short events, void *arg)
case PROPOSAL_NEARLY_EXPIRED:
if (real_lifetime(&rdns_proposal->uptime,
rdns_proposal->rdns_lifetime) == 0) {
- if_index = rdns_proposal->if_index;
free_rdns_proposal(rdns_proposal);
log_debug("%s: removing rdns proposal", __func__);
- compose_rdns_proposal(if_index);
+ compose_rdns_proposal(rdns_proposal->if_index,
+ rdns_proposal->rdomain);
break;
}
engine_imsg_compose_frontend(IMSG_CTL_SEND_SOLICITATION,
@@ -2541,7 +2555,7 @@ iface_timeout(int fd, short events, void *arg)
rdns_proposal->state = PROPOSAL_STALE;
free_rdns_proposal(rdns_proposal);
}
- compose_rdns_proposal(iface->if_index);
+ compose_rdns_proposal(iface->if_index, iface->rdomain);
#endif /* SMALL */
break;
case IF_DOWN:
diff --git a/sbin/slaacd/engine.h b/sbin/slaacd/engine.h
index b0276e71406..e97538f539c 100644
--- a/sbin/slaacd/engine.h
+++ b/sbin/slaacd/engine.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: engine.h,v 1.4 2019/11/07 08:45:31 florian Exp $ */
+/* $OpenBSD: engine.h,v 1.5 2020/09/14 09:07:05 florian Exp $ */
/*
* Copyright (c) 2004, 2005 Esben Norby <norby@openbsd.org>
@@ -28,6 +28,7 @@ struct imsg_configure_address {
struct imsg_configure_dfr {
uint32_t if_index;
+ int rdomain;
struct sockaddr_in6 addr;
uint32_t router_lifetime;
};
diff --git a/sbin/slaacd/frontend.c b/sbin/slaacd/frontend.c
index 3594085ae06..c26ebde835f 100644
--- a/sbin/slaacd/frontend.c
+++ b/sbin/slaacd/frontend.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: frontend.c,v 1.34 2020/08/19 05:55:08 florian Exp $ */
+/* $OpenBSD: frontend.c,v 1.35 2020/09/14 09:07:05 florian Exp $ */
/*
* Copyright (c) 2017 Florian Obser <florian@openbsd.org>
@@ -59,6 +59,24 @@
#define ROUTE_SOCKET_BUF_SIZE 16384
#define ALLROUTER "ff02::2"
+struct icmp6_ev {
+ struct event ev;
+ uint8_t answer[1500];
+ struct msghdr rcvmhdr;
+ struct iovec rcviov[1];
+ struct sockaddr_in6 from;
+ int refcnt;
+};
+
+struct iface {
+ LIST_ENTRY(iface) entries;
+ struct icmp6_ev *icmp6ev;
+ struct ether_addr hw_address;
+ uint32_t if_index;
+ int rdomain;
+ int send_solicitation;
+};
+
__dead void frontend_shutdown(void);
void frontend_sig_handler(int, short, void *);
void update_iface(uint32_t, char*);
@@ -71,12 +89,17 @@ int get_flags(char *);
int get_xflags(char *);
int get_ifrdomain(char *);
void get_lladdr(char *, struct ether_addr *, struct sockaddr_in6 *);
+struct iface *get_iface_by_id(uint32_t);
+void remove_iface(uint32_t);
+struct icmp6_ev *get_icmp6ev_by_rdomain(int);
+void set_icmp6sock(int, int);
void send_solicitation(uint32_t);
#ifndef SMALL
void update_autoconf_addresses(uint32_t, char*);
const char *flags_to_str(int);
#endif /* SMALL */
+LIST_HEAD(, iface) interfaces;
struct imsgev *iev_main;
struct imsgev *iev_engine;
struct event ev_route;
@@ -86,15 +109,7 @@ struct nd_router_solicit rs;
struct nd_opt_hdr nd_opt_hdr;
struct ether_addr nd_opt_source_link_addr;
struct sockaddr_in6 dst;
-int icmp6sock = -1, ioctlsock;
-
-struct icmp6_ev {
- struct event ev;
- uint8_t answer[1500];
- struct msghdr rcvmhdr;
- struct iovec rcviov[1];
- struct sockaddr_in6 from;
-} icmp6ev;
+int ioctlsock;
void
frontend_sig_handler(int sig, short event, void *bula)
@@ -120,9 +135,9 @@ frontend(int debug, int verbose)
struct passwd *pw;
struct in6_pktinfo *pi;
struct cmsghdr *cm;
- size_t rcvcmsglen, sndcmsglen;
+ size_t sndcmsglen;
int hoplimit = 255;
- uint8_t *rcvcmsgbuf, *sndcmsgbuf;
+ uint8_t *sndcmsgbuf;
log_init(debug, LOG_DAEMON);
log_setverbose(verbose);
@@ -174,20 +189,6 @@ frontend(int debug, int verbose)
iev_main->handler, iev_main);
event_add(&iev_main->ev, NULL);
- rcvcmsglen = CMSG_SPACE(sizeof(struct in6_pktinfo)) +
- CMSG_SPACE(sizeof(int));
- if((rcvcmsgbuf = malloc(rcvcmsglen)) == NULL)
- fatal("malloc");
-
- icmp6ev.rcviov[0].iov_base = (caddr_t)icmp6ev.answer;
- icmp6ev.rcviov[0].iov_len = sizeof(icmp6ev.answer);
- icmp6ev.rcvmhdr.msg_name = (caddr_t)&icmp6ev.from;
- icmp6ev.rcvmhdr.msg_namelen = sizeof(icmp6ev.from);
- icmp6ev.rcvmhdr.msg_iov = icmp6ev.rcviov;
- icmp6ev.rcvmhdr.msg_iovlen = 1;
- icmp6ev.rcvmhdr.msg_control = (caddr_t) rcvcmsgbuf;
- icmp6ev.rcvmhdr.msg_controllen = rcvcmsglen;
-
sndcmsglen = CMSG_SPACE(sizeof(struct in6_pktinfo)) +
CMSG_SPACE(sizeof(int));
@@ -236,6 +237,8 @@ frontend(int debug, int verbose)
cm->cmsg_len = CMSG_LEN(sizeof(int));
memcpy(CMSG_DATA(cm), &hoplimit, sizeof(int));
+ LIST_INIT(&interfaces);
+
event_dispatch();
frontend_shutdown();
@@ -282,7 +285,7 @@ frontend_dispatch_main(int fd, short event, void *bula)
struct imsgev *iev = bula;
struct imsgbuf *ibuf = &iev->ibuf;
ssize_t n;
- int shut = 0;
+ int shut = 0, icmp6sock, rdomain;
if (event & EV_READ) {
if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN)
@@ -335,8 +338,11 @@ frontend_dispatch_main(int fd, short event, void *bula)
fatalx("%s: expected to receive imsg "
"ICMPv6 fd but didn't receive any",
__func__);
- event_set(&icmp6ev.ev, icmp6sock, EV_READ | EV_PERSIST,
- icmp6_receive, NULL);
+ if (IMSG_DATA_SIZE(imsg) != sizeof(rdomain))
+ fatalx("%s: IMSG_ICMP6SOCK wrong length: "
+ "%lu", __func__, IMSG_DATA_SIZE(imsg));
+ memcpy(&rdomain, imsg.data, sizeof(rdomain));
+ set_icmp6sock(icmp6sock, rdomain);
break;
case IMSG_ROUTESOCK:
if ((fd = imsg.fd) == -1)
@@ -347,8 +353,6 @@ frontend_dispatch_main(int fd, short event, void *bula)
route_receive, NULL);
break;
case IMSG_STARTUP:
- if (pledge("stdio unix route", NULL) == -1)
- fatal("pledge");
frontend_startup();
break;
#ifndef SMALL
@@ -497,29 +501,63 @@ get_ifrdomain(char *if_name)
void
update_iface(uint32_t if_index, char* if_name)
{
+ struct iface *iface;
+ struct icmp6_ev *icmp6ev;
struct imsg_ifinfo imsg_ifinfo;
int flags, xflags, ifrdomain;
if ((flags = get_flags(if_name)) == -1 || (xflags =
- get_xflags(if_name)) == -1 || (ifrdomain = get_ifrdomain(if_name))
- == -1)
+ get_xflags(if_name)) == -1)
return;
- if (ifrdomain != getrtable())
+ if (!(xflags & IFXF_AUTOCONF6))
return;
- if (!(xflags & IFXF_AUTOCONF6))
+ if((ifrdomain = get_ifrdomain(if_name)) == -1)
return;
+ if ((iface = get_iface_by_id(if_index)) == NULL) {
+ if ((iface = calloc(1, sizeof(*iface))) == NULL)
+ fatal("calloc");
+ iface->if_index = if_index;
+ iface->rdomain = ifrdomain;
+
+ if ((icmp6ev = get_icmp6ev_by_rdomain(ifrdomain)) == NULL) {
+ if ((icmp6ev = calloc(1, sizeof(*icmp6ev))) == NULL)
+ fatal("calloc");
+ icmp6ev->rcviov[0].iov_base = (caddr_t)icmp6ev->answer;
+ icmp6ev->rcviov[0].iov_len = sizeof(icmp6ev->answer);
+ icmp6ev->rcvmhdr.msg_name = (caddr_t)&icmp6ev->from;
+ icmp6ev->rcvmhdr.msg_namelen = sizeof(icmp6ev->from);
+ icmp6ev->rcvmhdr.msg_iov = icmp6ev->rcviov;
+ icmp6ev->rcvmhdr.msg_iovlen = 1;
+ icmp6ev->rcvmhdr.msg_controllen =
+ CMSG_SPACE(sizeof(struct in6_pktinfo)) +
+ CMSG_SPACE(sizeof(int));
+ if ((icmp6ev->rcvmhdr.msg_control = malloc(icmp6ev->
+ rcvmhdr.msg_controllen)) == NULL)
+ fatal("malloc");
+ frontend_imsg_compose_main(IMSG_OPEN_ICMP6SOCK, 0,
+ &ifrdomain, sizeof(ifrdomain));
+ }
+ iface->icmp6ev = icmp6ev;
+ iface->icmp6ev->refcnt++;
+ LIST_INSERT_HEAD(&interfaces, iface, entries);
+ }
+
memset(&imsg_ifinfo, 0, sizeof(imsg_ifinfo));
imsg_ifinfo.if_index = if_index;
+ imsg_ifinfo.rdomain = ifrdomain;
imsg_ifinfo.running = (flags & (IFF_UP | IFF_RUNNING)) == (IFF_UP |
IFF_RUNNING);
imsg_ifinfo.autoconfprivacy = !(xflags & IFXF_INET6_NOPRIVACY);
imsg_ifinfo.soii = !(xflags & IFXF_INET6_NOSOII);
get_lladdr(if_name, &imsg_ifinfo.hw_address, &imsg_ifinfo.ll_address);
+ memcpy(&iface->hw_address, &imsg_ifinfo.hw_address,
+ sizeof(iface->hw_address));
+
frontend_imsg_compose_main(IMSG_UPDATE_IF, 0, &imsg_ifinfo,
sizeof(imsg_ifinfo));
}
@@ -535,12 +573,9 @@ update_autoconf_addresses(uint32_t if_index, char* if_name)
struct sockaddr_in6 *sin6;
struct imsg_link_state imsg_link_state;
time_t t;
- int xflags, ifrdomain;
+ int xflags;
- if ((xflags = get_xflags(if_name)) == -1 || (ifrdomain =
- get_ifrdomain(if_name)) == -1)
- return;
- if (ifrdomain != getrtable())
+ if ((xflags = get_xflags(if_name)) == -1)
return;
if (!(xflags & IFXF_AUTOCONF6))
@@ -594,7 +629,8 @@ update_autoconf_addresses(uint32_t if_index, char* if_name)
(void) strlcpy(ifr6.ifr_name, if_name, sizeof(ifr6.ifr_name));
memcpy(&ifr6.ifr_addr, sin6, sizeof(ifr6.ifr_addr));
- if (ioctl(ioctlsock, SIOCGIFNETMASK_IN6, (caddr_t)&ifr6) == -1) {
+ if (ioctl(ioctlsock, SIOCGIFNETMASK_IN6, (caddr_t)&ifr6) ==
+ -1) {
log_warn("SIOCGIFNETMASK_IN6");
continue;
}
@@ -607,7 +643,8 @@ update_autoconf_addresses(uint32_t if_index, char* if_name)
memcpy(&ifr6.ifr_addr, sin6, sizeof(ifr6.ifr_addr));
lifetime = &ifr6.ifr_ifru.ifru_lifetime;
- if (ioctl(ioctlsock, SIOCGIFALIFETIME_IN6, (caddr_t)&ifr6) == -1) {
+ if (ioctl(ioctlsock, SIOCGIFALIFETIME_IN6, (caddr_t)&ifr6) ==
+ -1) {
log_warn("SIOCGIFALIFETIME_IN6");
continue;
}
@@ -674,17 +711,9 @@ frontend_startup(void)
event_add(&ev_route, NULL);
- if (!event_initialized(&icmp6ev.ev))
- fatalx("%s: did not receive a icmp6 socket fd from the main "
- "process", __func__);
-
- event_add(&icmp6ev.ev, NULL);
-
if ((ifnidxp = if_nameindex()) == NULL)
fatalx("if_nameindex");
- frontend_imsg_compose_main(IMSG_STARTUP_DONE, 0, NULL, 0);
-
for(ifnidx = ifnidxp; ifnidx->if_index !=0 && ifnidx->if_name != NULL;
ifnidx++) {
update_iface(ifnidx->if_index, ifnidx->if_name);
@@ -767,6 +796,7 @@ handle_route_message(struct rt_msghdr *rtm, struct sockaddr **rti_info)
if_index = ifm->ifm_index;
frontend_imsg_compose_engine(IMSG_REMOVE_IF, 0,
0, &if_index, sizeof(if_index));
+ remove_iface(if_index);
} else {
update_iface(ifm->ifm_index, if_name);
#ifndef SMALL
@@ -916,9 +946,6 @@ get_lladdr(char *if_name, struct ether_addr *mac, struct sockaddr_in6 *ll)
if (getifaddrs(&ifap) != 0)
fatal("getifaddrs");
- memset(mac, 0, sizeof(*mac));
- memset(ll, 0, sizeof(*ll));
-
for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next) {
if (strcmp(if_name, ifa->ifa_name) != 0)
continue;
@@ -954,21 +981,23 @@ void
icmp6_receive(int fd, short events, void *arg)
{
struct imsg_ra ra;
-
+ struct icmp6_hdr *icmp6_hdr;
+ struct icmp6_ev *icmp6ev;
struct in6_pktinfo *pi = NULL;
struct cmsghdr *cm;
ssize_t len;
int if_index = 0, *hlimp = NULL;
char ntopbuf[INET6_ADDRSTRLEN], ifnamebuf[IFNAMSIZ];
- if ((len = recvmsg(fd, &icmp6ev.rcvmhdr, 0)) == -1) {
+ icmp6ev = arg;
+ if ((len = recvmsg(fd, &icmp6ev->rcvmhdr, 0)) == -1) {
log_warn("recvmsg");
return;
}
/* extract optional information via Advanced API */
- for (cm = (struct cmsghdr *)CMSG_FIRSTHDR(&icmp6ev.rcvmhdr); cm;
- cm = (struct cmsghdr *)CMSG_NXTHDR(&icmp6ev.rcvmhdr, cm)) {
+ for (cm = (struct cmsghdr *)CMSG_FIRSTHDR(&icmp6ev->rcvmhdr); cm;
+ cm = (struct cmsghdr *)CMSG_NXTHDR(&icmp6ev->rcvmhdr, cm)) {
if (cm->cmsg_level == IPPROTO_IPV6 &&
cm->cmsg_type == IPV6_PKTINFO &&
cm->cmsg_len == CMSG_LEN(sizeof(struct in6_pktinfo))) {
@@ -993,7 +1022,7 @@ icmp6_receive(int fd, short events, void *arg)
if (*hlimp != 255) {
log_warnx("invalid RA with hop limit of %d from %s on %s",
- *hlimp, inet_ntop(AF_INET6, &icmp6ev.from.sin6_addr,
+ *hlimp, inet_ntop(AF_INET6, &icmp6ev->from.sin6_addr,
ntopbuf, INET6_ADDRSTRLEN), if_indextoname(if_index,
ifnamebuf));
return;
@@ -1001,16 +1030,22 @@ icmp6_receive(int fd, short events, void *arg)
if ((size_t)len > sizeof(ra.packet)) {
log_warnx("invalid RA with size %ld from %s on %s",
- len, inet_ntop(AF_INET6, &icmp6ev.from.sin6_addr,
+ len, inet_ntop(AF_INET6, &icmp6ev->from.sin6_addr,
ntopbuf, INET6_ADDRSTRLEN), if_indextoname(if_index,
ifnamebuf));
return;
}
+ if ((size_t)len < sizeof(struct icmp6_hdr))
+ return;
+ icmp6_hdr = (struct icmp6_hdr *)icmp6ev->answer;
+ if (icmp6_hdr->icmp6_type != ND_ROUTER_ADVERT)
+ return;
+
ra.if_index = if_index;
- memcpy(&ra.from, &icmp6ev.from, sizeof(ra.from));
+ memcpy(&ra.from, &icmp6ev->from, sizeof(ra.from));
ra.len = len;
- memcpy(ra.packet, icmp6ev.answer, len);
+ memcpy(ra.packet, icmp6ev->answer, len);
frontend_imsg_compose_engine(IMSG_RA, 0, 0, &ra, sizeof(ra));
}
@@ -1018,21 +1053,19 @@ icmp6_receive(int fd, short events, void *arg)
void
send_solicitation(uint32_t if_index)
{
- struct in6_pktinfo *pi;
- struct cmsghdr *cm;
- struct ether_addr hw_address;
- struct sockaddr_in6 ll_address;
- char if_name[IF_NAMESIZE];
+ struct in6_pktinfo *pi;
+ struct cmsghdr *cm;
+ struct iface *iface;
log_debug("%s(%u)", __func__, if_index);
- if (if_indextoname(if_index, if_name) == NULL)
+ if ((iface = get_iface_by_id(if_index)) == NULL)
return;
- get_lladdr(if_name, &hw_address, &ll_address);
-
- memcpy(&nd_opt_source_link_addr, &hw_address,
- sizeof(nd_opt_source_link_addr));
+ if (!event_initialized(&iface->icmp6ev->ev)) {
+ iface->send_solicitation = 1;
+ return;
+ }
dst.sin6_scope_id = if_index;
@@ -1040,7 +1073,88 @@ send_solicitation(uint32_t if_index)
pi = (struct in6_pktinfo *)CMSG_DATA(cm);
pi->ipi6_ifindex = if_index;
- if (sendmsg(icmp6sock, &sndmhdr, 0) != sizeof(rs) +
+ memcpy(&nd_opt_source_link_addr, &iface->hw_address,
+ sizeof(nd_opt_source_link_addr));
+
+ if (sendmsg(EVENT_FD(&iface->icmp6ev->ev), &sndmhdr, 0) != sizeof(rs) +
sizeof(nd_opt_hdr) + sizeof(nd_opt_source_link_addr))
log_warn("sendmsg");
}
+
+struct iface*
+get_iface_by_id(uint32_t if_index)
+{
+ struct iface *iface;
+
+ LIST_FOREACH (iface, &interfaces, entries) {
+ if (iface->if_index == if_index)
+ return (iface);
+ }
+
+ return (NULL);
+}
+
+void
+remove_iface(uint32_t if_index)
+{
+ struct iface *iface;
+
+ iface = get_iface_by_id(if_index);
+
+ if (iface == NULL)
+ return;
+
+ LIST_REMOVE(iface, entries);
+
+ if (iface->icmp6ev != NULL) {
+ iface->icmp6ev->refcnt--;
+ if (iface->icmp6ev->refcnt == 0) {
+ event_del(&iface->icmp6ev->ev);
+ close(EVENT_FD(&iface->icmp6ev->ev));
+ free(iface->icmp6ev);
+ }
+ }
+ free(iface);
+}
+
+struct icmp6_ev*
+get_icmp6ev_by_rdomain(int rdomain)
+{
+ struct iface *iface;
+
+ LIST_FOREACH (iface, &interfaces, entries) {
+ if (iface->rdomain == rdomain)
+ return (iface->icmp6ev);
+ }
+
+ return (NULL);
+}
+
+void
+set_icmp6sock(int icmp6sock, int rdomain)
+{
+ struct iface *iface;
+
+ LIST_FOREACH (iface, &interfaces, entries) {
+ if (!event_initialized(&iface->icmp6ev->ev) && iface->rdomain
+ == rdomain) {
+ event_set(&iface->icmp6ev->ev, icmp6sock, EV_READ |
+ EV_PERSIST, icmp6_receive, iface->icmp6ev);
+ event_add(&iface->icmp6ev->ev, NULL);
+ icmp6sock = -1;
+ break;
+ }
+ }
+
+ if (icmp6sock != -1)
+ fatalx("received unneeded ICMPv6 socket for rdomain %d",
+ rdomain);
+
+ LIST_FOREACH (iface, &interfaces, entries) {
+ if (event_initialized(&iface->icmp6ev->ev) &&
+ iface->send_solicitation) {
+ iface->send_solicitation = 0;
+ send_solicitation(iface->if_index);
+ }
+ }
+}
diff --git a/sbin/slaacd/slaacd.c b/sbin/slaacd/slaacd.c
index f23daf0b675..c048bbd6190 100644
--- a/sbin/slaacd/slaacd.c
+++ b/sbin/slaacd/slaacd.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: slaacd.c,v 1.50 2020/07/03 17:42:50 florian Exp $ */
+/* $OpenBSD: slaacd.c,v 1.51 2020/09/14 09:07:05 florian Exp $ */
/*
* Copyright (c) 2017 Florian Obser <florian@openbsd.org>
@@ -63,6 +63,7 @@ static pid_t start_child(int, char *, int, int, int);
void main_dispatch_frontend(int, short, void *);
void main_dispatch_engine(int, short, void *);
+void open_icmp6sock(int);
void configure_interface(struct imsg_configure_address *);
void delete_address(struct imsg_configure_address *);
void configure_gateway(struct imsg_configure_dfr *, uint8_t);
@@ -74,8 +75,7 @@ void send_rdns_proposal(struct imsg_propose_rdns *);
int get_soiikey(uint8_t *);
static int main_imsg_send_ipc_sockets(struct imsgbuf *, struct imsgbuf *);
-int main_imsg_compose_frontend(int, pid_t, void *, uint16_t);
-int main_imsg_compose_frontend_fd(int, pid_t, int);
+int main_imsg_compose_frontend(int, int, void *, uint16_t);
int main_imsg_compose_engine(int, pid_t, void *, uint16_t);
struct imsgev *iev_frontend;
@@ -117,16 +117,15 @@ int
main(int argc, char *argv[])
{
struct event ev_sigint, ev_sigterm;
- struct icmp6_filter filt;
int ch;
int debug = 0, engine_flag = 0, frontend_flag = 0;
int verbose = 0;
char *saved_argv0;
int pipe_main2frontend[2];
int pipe_main2engine[2];
- int icmp6sock, on = 1;
int frontend_routesock, rtfilter;
- char *csock = NULL;
+ int rtable_any = RTABLE_ANY;
+ char *csock = SLAACD_SOCKET;
#ifndef SMALL
struct imsg_propose_rdns rdns;
int control_fd;
@@ -151,8 +150,7 @@ main(int argc, char *argv[])
frontend_flag = 1;
break;
case 's':
- if ((csock = strdup(optarg)) == NULL)
- fatal(NULL);
+ csock = optarg;
break;
case 'v':
verbose++;
@@ -245,25 +243,6 @@ main(int argc, char *argv[])
if ((ioctl_sock = socket(AF_INET6, SOCK_DGRAM | SOCK_CLOEXEC, 0)) == -1)
fatal("socket");
- if ((icmp6sock = socket(AF_INET6, SOCK_RAW | SOCK_CLOEXEC,
- IPPROTO_ICMPV6)) == -1)
- fatal("ICMPv6 socket");
-
- if (setsockopt(icmp6sock, IPPROTO_IPV6, IPV6_RECVPKTINFO, &on,
- sizeof(on)) == -1)
- fatal("IPV6_RECVPKTINFO");
-
- if (setsockopt(icmp6sock, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, &on,
- sizeof(on)) == -1)
- fatal("IPV6_RECVHOPLIMIT");
-
- /* only router advertisements */
- ICMP6_FILTER_SETBLOCKALL(&filt);
- ICMP6_FILTER_SETPASS(ND_ROUTER_ADVERT, &filt);
- if (setsockopt(icmp6sock, IPPROTO_ICMPV6, ICMP6_FILTER, &filt,
- sizeof(filt)) == -1)
- fatal("ICMP6_FILTER");
-
if ((frontend_routesock = socket(AF_ROUTE, SOCK_RAW | SOCK_CLOEXEC,
AF_INET6)) == -1)
fatal("route socket");
@@ -274,29 +253,25 @@ main(int argc, char *argv[])
if (setsockopt(frontend_routesock, AF_ROUTE, ROUTE_MSGFILTER,
&rtfilter, sizeof(rtfilter)) == -1)
fatal("setsockopt(ROUTE_MSGFILTER)");
+ if (setsockopt(frontend_routesock, AF_ROUTE, ROUTE_TABLEFILTER,
+ &rtable_any, sizeof(rtable_any)) == -1)
+ fatal("setsockopt(ROUTE_TABLEFILTER)");
#ifndef SMALL
- if (csock == NULL) {
- if (asprintf(&csock, "%s.%d", SLAACD_SOCKET, getrtable()) == -1)
- fatal(NULL);
- }
if ((control_fd = control_init(csock)) == -1)
fatalx("control socket setup failed");
- free(csock);
#endif /* SMALL */
- if (pledge("stdio sendfd wroute", NULL) == -1)
+ if (pledge("stdio inet sendfd wroute", NULL) == -1)
fatal("pledge");
- main_imsg_compose_frontend_fd(IMSG_ICMP6SOCK, 0, icmp6sock);
-
- main_imsg_compose_frontend_fd(IMSG_ROUTESOCK, 0, frontend_routesock);
+ main_imsg_compose_frontend(IMSG_ROUTESOCK, frontend_routesock, NULL, 0);
#ifndef SMALL
- main_imsg_compose_frontend_fd(IMSG_CONTROLFD, 0, control_fd);
+ main_imsg_compose_frontend(IMSG_CONTROLFD, control_fd, NULL, 0);
#endif /* SMALL */
- main_imsg_compose_frontend(IMSG_STARTUP, 0, NULL, 0);
+ main_imsg_compose_frontend(IMSG_STARTUP, -1, NULL, 0);
#ifndef SMALL
/* we are taking over, clear all previos slaac proposals */
@@ -398,6 +373,7 @@ main_dispatch_frontend(int fd, short event, void *bula)
struct imsg_ifinfo imsg_ifinfo;
ssize_t n;
int shut = 0;
+ int rdomain;
#ifndef SMALL
struct imsg_addrinfo imsg_addrinfo;
struct imsg_link_state imsg_link_state;
@@ -426,9 +402,13 @@ main_dispatch_frontend(int fd, short event, void *bula)
break;
switch (imsg.hdr.type) {
- case IMSG_STARTUP_DONE:
- if (pledge("stdio wroute", NULL) == -1)
- fatal("pledge");
+ case IMSG_OPEN_ICMP6SOCK:
+ log_debug("IMSG_OPEN_ICMP6SOCK");
+ if (IMSG_DATA_SIZE(imsg) != sizeof(rdomain))
+ fatalx("%s: IMSG_OPEN_ICMP6SOCK wrong length: "
+ "%lu", __func__, IMSG_DATA_SIZE(imsg));
+ memcpy(&rdomain, imsg.data, sizeof(rdomain));
+ open_icmp6sock(rdomain);
break;
#ifndef SMALL
case IMSG_CTL_LOG_VERBOSE:
@@ -584,26 +564,16 @@ main_dispatch_engine(int fd, short event, void *bula)
}
int
-main_imsg_compose_frontend(int type, pid_t pid, void *data, uint16_t datalen)
+main_imsg_compose_frontend(int type, int fd, void *data, uint16_t datalen)
{
if (iev_frontend)
- return (imsg_compose_event(iev_frontend, type, 0, pid, -1, data,
+ return (imsg_compose_event(iev_frontend, type, 0, 0, fd, data,
datalen));
else
return (-1);
}
int
-main_imsg_compose_frontend_fd(int type, pid_t pid, int fd)
-{
- if (iev_frontend)
- return (imsg_compose_event(iev_frontend, type, 0, pid, fd,
- NULL, 0));
- else
- return (-1);
-}
-
-int
main_imsg_compose_engine(int type, pid_t pid, void *data, uint16_t datalen)
{
if (iev_engine)
@@ -759,7 +729,7 @@ configure_gateway(struct imsg_configure_dfr *dfr, uint8_t rtm_type)
rtm.rtm_version = RTM_VERSION;
rtm.rtm_type = rtm_type;
rtm.rtm_msglen = sizeof(rtm);
- rtm.rtm_tableid = getrtable();
+ rtm.rtm_tableid = dfr->rdomain;
rtm.rtm_index = dfr->if_index;
rtm.rtm_seq = ++rtm_seq;
rtm.rtm_priority = RTP_NONE;
@@ -856,7 +826,7 @@ send_rdns_proposal(struct imsg_propose_rdns *rdns)
rtm.rtm_version = RTM_VERSION;
rtm.rtm_type = RTM_PROPOSAL;
rtm.rtm_msglen = sizeof(rtm);
- rtm.rtm_tableid = getrtable();
+ rtm.rtm_tableid = rdns->rdomain;
rtm.rtm_index = rdns->if_index;
rtm.rtm_seq = ++rtm_seq;
rtm.rtm_priority = RTP_PROPOSAL_SLAAC;
@@ -909,3 +879,30 @@ get_soiikey(uint8_t *key)
return sysctl(mib, sizeof(mib) / sizeof(mib[0]), key, &size, NULL, 0);
}
+
+void
+open_icmp6sock(int rdomain)
+{
+ int icmp6sock, on = 1;
+
+ log_debug("%s: %d", __func__, rdomain);
+
+ if ((icmp6sock = socket(AF_INET6, SOCK_RAW | SOCK_CLOEXEC,
+ IPPROTO_ICMPV6)) == -1)
+ fatal("ICMPv6 socket");
+
+ if (setsockopt(icmp6sock, IPPROTO_IPV6, IPV6_RECVPKTINFO, &on,
+ sizeof(on)) == -1)
+ fatal("IPV6_RECVPKTINFO");
+
+ if (setsockopt(icmp6sock, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, &on,
+ sizeof(on)) == -1)
+ fatal("IPV6_RECVHOPLIMIT");
+
+ if (setsockopt(icmp6sock, SOL_SOCKET, SO_RTABLE, &rdomain,
+ sizeof(rdomain)) == -1)
+ fatal("setsockopt SO_RTABLE");
+
+ main_imsg_compose_frontend(IMSG_ICMP6SOCK, icmp6sock, &rdomain,
+ sizeof(rdomain));
+}
diff --git a/sbin/slaacd/slaacd.h b/sbin/slaacd/slaacd.h
index d8e15d00aad..16b47434b0f 100644
--- a/sbin/slaacd/slaacd.h
+++ b/sbin/slaacd/slaacd.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: slaacd.h,v 1.26 2019/11/22 15:30:00 florian Exp $ */
+/* $OpenBSD: slaacd.h,v 1.27 2020/09/14 09:07:05 florian Exp $ */
/*
* Copyright (c) 2017 Florian Obser <florian@openbsd.org>
@@ -67,11 +67,11 @@ enum imsg_type {
#endif /* SMALL */
IMSG_CTL_SEND_SOLICITATION,
IMSG_SOCKET_IPC,
+ IMSG_OPEN_ICMP6SOCK,
IMSG_ICMP6SOCK,
IMSG_ROUTESOCK,
IMSG_CONTROLFD,
IMSG_STARTUP,
- IMSG_STARTUP_DONE,
IMSG_UPDATE_IF,
IMSG_REMOVE_IF,
IMSG_RA,
@@ -197,6 +197,7 @@ struct imsg_link_state {
struct imsg_propose_rdns {
uint32_t if_index;
+ int rdomain;
int rdns_count;
struct in6_addr rdns[MAX_RDNS_COUNT];
};
@@ -205,6 +206,7 @@ struct imsg_propose_rdns {
struct imsg_ifinfo {
uint32_t if_index;
+ int rdomain;
int running;
int autoconfprivacy;
int soii;
diff --git a/usr.sbin/slaacctl/slaacctl.c b/usr.sbin/slaacctl/slaacctl.c
index 46e3d3d98dd..4b17fa3b02f 100644
--- a/usr.sbin/slaacctl/slaacctl.c
+++ b/usr.sbin/slaacctl/slaacctl.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: slaacctl.c,v 1.19 2020/04/16 05:28:30 florian Exp $ */
+/* $OpenBSD: slaacctl.c,v 1.20 2020/09/14 09:07:05 florian Exp $ */
/*
* Copyright (c) 2005 Claudio Jeker <claudio@openbsd.org>
@@ -71,13 +71,13 @@ main(int argc, char *argv[])
int done = 0;
int n, verbose = 0;
int ch;
- char *sockname = NULL;
+ char *sockname;
+ sockname = SLAACD_SOCKET;
while ((ch = getopt(argc, argv, "s:")) != -1) {
switch (ch) {
case 's':
- if ((sockname = strdup(optarg)) == NULL)
- err(1, NULL);
+ sockname = optarg;
break;
default:
usage();
@@ -86,12 +86,6 @@ main(int argc, char *argv[])
argc -= optind;
argv += optind;
- if (sockname == NULL) {
- if (asprintf(&sockname, "%s.%d", SLAACD_SOCKET, getrtable()) ==
- -1)
- err(1, NULL);
- }
-
if (pledge("stdio unix", NULL) == -1)
err(1, "pledge");
@@ -106,7 +100,6 @@ main(int argc, char *argv[])
memset(&sun, 0, sizeof(sun));
sun.sun_family = AF_UNIX;
strlcpy(sun.sun_path, sockname, sizeof(sun.sun_path));
- free(sockname);
if (connect(ctl_sock, (struct sockaddr *)&sun, sizeof(sun)) == -1)
err(1, "connect: %s", sockname);