summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorflorian <florian@openbsd.org>2017-03-20 16:15:37 +0000
committerflorian <florian@openbsd.org>2017-03-20 16:15:37 +0000
commit9f4b1db1bca0618903ff5fd045eed07ad306f592 (patch)
treefbabf6523c739fcf66956fa09385336113573b9d
parentsimplify control socket path handling; sync from netcfgd by krw@ (diff)
downloadwireguard-openbsd-9f4b1db1bca0618903ff5fd045eed07ad306f592.tar.xz
wireguard-openbsd-9f4b1db1bca0618903ff5fd045eed07ad306f592.zip
send proposals
-rw-r--r--usr.sbin/slaacd/engine.c88
-rw-r--r--usr.sbin/slaacd/engine.h11
-rw-r--r--usr.sbin/slaacd/slaacd.c147
-rw-r--r--usr.sbin/slaacd/slaacd.h3
4 files changed, 240 insertions, 9 deletions
diff --git a/usr.sbin/slaacd/engine.c b/usr.sbin/slaacd/engine.c
index 78857f0c34c..c44d8cf5b6d 100644
--- a/usr.sbin/slaacd/engine.c
+++ b/usr.sbin/slaacd/engine.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: engine.c,v 1.3 2017/03/19 16:12:22 florian Exp $ */
+/* $OpenBSD: engine.c,v 1.4 2017/03/20 16:15:37 florian Exp $ */
/*
* Copyright (c) 2017 Florian Obser <florian@openbsd.org>
@@ -55,6 +55,7 @@
#include <sys/uio.h>
#include <net/if.h>
+#include <net/route.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <netinet/if_ether.h>
@@ -68,6 +69,7 @@
#include <netdb.h>
#include <pwd.h>
#include <signal.h>
+#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
@@ -170,10 +172,12 @@ void in6_prefixlen2mask(struct in6_addr *, int len);
void debug_log_ra(struct imsg_ra *);
char *parse_dnssl(char *, int);
void update_iface_ra(struct slaacd_iface *, struct radv *);
+void send_proposal(struct imsg_proposal *);
void start_probe(struct slaacd_iface *);
void ra_timeout(int, short, void *);
void iface_timeout(int, short, void *);
struct radv *find_ra(struct slaacd_iface *, struct sockaddr_in6 *);
+int engine_imsg_compose_main(int, pid_t, void *, uint16_t);
struct imsgev *iev_frontend;
struct imsgev *iev_main;
@@ -278,6 +282,14 @@ engine_imsg_compose_frontend(int type, pid_t pid, void *data,
data, datalen));
}
+int
+engine_imsg_compose_main(int type, pid_t pid, void *data,
+ uint16_t datalen)
+{
+ return (imsg_compose_event(iev_main, type, 0, pid, -1,
+ data, datalen));
+}
+
void
engine_dispatch_frontend(int fd, short event, void *bula)
{
@@ -1242,7 +1254,13 @@ update_iface_ra(struct slaacd_iface *iface, struct radv *ra)
{
struct radv *old_ra;
+ struct radv_prefix *prefix;
+ struct radv_rdns *rdns;
+ struct radv_dnssl *dnssl;
+ struct imsg_proposal proposal;
struct timeval tv;
+ size_t len;
+ char *p;
old_ra = find_ra(iface, &ra->from);
@@ -1266,6 +1284,74 @@ update_iface_ra(struct slaacd_iface *iface, struct radv *ra)
evtimer_set(&ra->timer, ra_timeout, iface);
evtimer_add(&ra->timer, &tv);
+
+ /*
+ * XXX we need to figure out what actually changed in the RA and
+ * adjust our proposal accordingly
+ */
+
+ memset(&proposal, 0, sizeof(proposal));
+
+ proposal.if_index = iface->if_index;
+
+ proposal.rdns.sr_family = AF_INET6;
+ rdns = LIST_FIRST(&ra->rdns_servers);
+ p = proposal.rdns.sr_dns;
+ while (rdns != NULL && proposal.rdns.sr_len + sizeof(rdns->rdns) <=
+ RTDNS_LEN) {
+ /* XXX lifetime */
+ memcpy(p, &rdns->rdns, sizeof(rdns->rdns));
+ p += sizeof(rdns->rdns);
+ proposal.rdns.sr_len += sizeof(rdns->rdns);
+ rdns = LIST_NEXT(rdns, entries);
+ }
+
+ if (proposal.rdns.sr_len > 0)
+ proposal.rdns.sr_len += offsetof(struct sockaddr_rtdns, sr_dns);
+
+ proposal.dnssl.sr_family = AF_INET6;
+ dnssl = LIST_FIRST(&ra->dnssls);
+ while(dnssl != NULL) {
+ len = strlcat(proposal.dnssl.sr_search, dnssl->dnssl,
+ RTSEARCH_LEN);
+ if (len >= RTSEARCH_LEN) {
+ log_warn("search too long");
+ break;
+ }
+ proposal.dnssl.sr_len = len + 1;
+ dnssl = LIST_NEXT(dnssl, entries);
+ if (dnssl != NULL) {
+ len = strlcat(proposal.dnssl.sr_search, " ",
+ RTSEARCH_LEN);
+ if (len >= RTSEARCH_LEN) {
+ log_warn("search too long");
+ break;
+ }
+ proposal.dnssl.sr_len = len + 1;
+ }
+ }
+ if (proposal.dnssl.sr_len > 0)
+ proposal.dnssl.sr_len += offsetof(struct sockaddr_rtsearch,
+ sr_search);
+
+ LIST_FOREACH(prefix, &ra->prefixes, entries) {
+ proposal.addr = prefix->addr;
+ proposal.mask = prefix->mask;
+ proposal.gateway = ra->from;
+
+ send_proposal(&proposal);
+
+ if (iface->autoconfprivacy) {
+ proposal.addr = prefix->priv_addr;
+ send_proposal(&proposal);
+ }
+ }
+}
+
+void
+send_proposal(struct imsg_proposal *proposal)
+{
+ engine_imsg_compose_main(IMSG_PROPOSAL, 0, proposal, sizeof(*proposal));
}
void
diff --git a/usr.sbin/slaacd/engine.h b/usr.sbin/slaacd/engine.h
index 0f0cf91084b..12e6f10864e 100644
--- a/usr.sbin/slaacd/engine.h
+++ b/usr.sbin/slaacd/engine.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: engine.h,v 1.1 2017/03/18 17:33:13 florian Exp $ */
+/* $OpenBSD: engine.h,v 1.2 2017/03/20 16:15:37 florian Exp $ */
/*
* Copyright (c) 2004, 2005 Esben Norby <norby@openbsd.org>
@@ -16,5 +16,14 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
+struct imsg_proposal {
+ uint32_t if_index;
+ struct sockaddr_in6 addr;
+ struct in6_addr mask;
+ struct sockaddr_in6 gateway;
+ struct sockaddr_rtdns rdns;
+ struct sockaddr_rtsearch dnssl;
+};
+
void engine(int, int);
int engine_imsg_compose_frontend(int, pid_t, void *, uint16_t);
diff --git a/usr.sbin/slaacd/slaacd.c b/usr.sbin/slaacd/slaacd.c
index 745d0e926a4..bf8c8217e9a 100644
--- a/usr.sbin/slaacd/slaacd.c
+++ b/usr.sbin/slaacd/slaacd.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: slaacd.c,v 1.2 2017/03/20 16:13:27 florian Exp $ */
+/* $OpenBSD: slaacd.c,v 1.3 2017/03/20 16:15:37 florian Exp $ */
/*
* Copyright (c) 2017 Florian Obser <florian@openbsd.org>
@@ -26,6 +26,7 @@
#include <sys/wait.h>
#include <net/if.h>
+#include <net/route.h>
#include <netinet/in.h>
#include <netinet/if_ether.h>
@@ -34,6 +35,7 @@
#include <event.h>
#include <imsg.h>
#include <pwd.h>
+#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -63,6 +65,7 @@ const char* imsg_type_name[] = {
"IMSG_REMOVE_IF",
"IMSG_RA",
"IMSG_CTL_SEND_SOLICITATION",
+ "IMSG_PROPOSAL",
};
__dead void usage(void);
@@ -74,6 +77,7 @@ static pid_t start_child(int, char *, int, int, int, char *);
void main_dispatch_frontend(int, short, void *);
void main_dispatch_engine(int, short, void *);
+void handle_proposal(struct imsg_proposal *);
static int main_imsg_send_ipc_sockets(struct imsgbuf *, struct imsgbuf *);
@@ -85,6 +89,8 @@ pid_t engine_pid;
uint32_t cmd_opts;
+int routesock;
+
char *csock;
void
@@ -204,6 +210,9 @@ main(int argc, char *argv[])
setproctitle(log_procnames[slaacd_process]);
log_procinit(log_procnames[slaacd_process]);
+ if ((routesock = socket(PF_ROUTE, SOCK_RAW, 0)) < 0)
+ fatal("route socket");
+
event_init();
/* Setup signal handler. */
@@ -383,11 +392,12 @@ main_dispatch_frontend(int fd, short event, void *bula)
void
main_dispatch_engine(int fd, short event, void *bula)
{
- struct imsgev *iev = bula;
- struct imsgbuf *ibuf;
- struct imsg imsg;
- ssize_t n;
- int shut = 0;
+ struct imsgev *iev = bula;
+ struct imsgbuf *ibuf;
+ struct imsg imsg;
+ struct imsg_proposal proposal;
+ ssize_t n;
+ int shut = 0;
ibuf = &iev->ibuf;
@@ -411,6 +421,13 @@ main_dispatch_engine(int fd, short event, void *bula)
break;
switch (imsg.hdr.type) {
+ case IMSG_PROPOSAL:
+ if (imsg.hdr.len != IMSG_HEADER_SIZE + sizeof(proposal))
+ fatal("%s: IMSG_PROPOSAL wrong "
+ "length: %d", __func__, imsg.hdr.len);
+ memcpy(&proposal, imsg.data, sizeof(proposal));
+ handle_proposal(&proposal);
+ break;
default:
log_debug("%s: error handling imsg %d", __func__,
imsg.hdr.type);
@@ -492,3 +509,121 @@ main_imsg_send_ipc_sockets(struct imsgbuf *frontend_buf,
imsg_flush(engine_buf);
return (0);
}
+
+#define ROUNDUP(a) \
+ (((a) & (sizeof(long) - 1)) ? (1 + ((a) | (sizeof(long) - 1))) : (a))
+void
+handle_proposal(struct imsg_proposal *proposal)
+{
+ static int seq = 0;
+ struct rt_msghdr rtm;
+ struct sockaddr_rtstatic rtstatic;
+ struct sockaddr_in6 ifa, mask, gateway;
+ struct in6_addr prefix;
+ struct iovec iov[11];
+ long pad = 0;
+ int iovcnt = 0, padlen;
+ uint8_t prefixlen;
+ char *p;
+
+ memset(&rtm, 0, sizeof(rtm));
+
+ rtm.rtm_version = RTM_VERSION;
+ rtm.rtm_type = RTM_PROPOSAL;
+ rtm.rtm_msglen = sizeof(rtm);
+ rtm.rtm_tableid = 0; /* XXX imsg->rdomain; */
+ rtm.rtm_index = proposal->if_index;
+ rtm.rtm_seq = ++seq;
+ rtm.rtm_priority = RTP_PROPOSAL_SLAAC;
+ rtm.rtm_addrs = RTA_NETMASK | RTA_IFA | RTA_STATIC;
+ rtm.rtm_flags = RTF_UP;
+
+ iov[iovcnt].iov_base = &rtm;
+ iov[iovcnt++].iov_len = sizeof(rtm);
+
+ memset(&mask, 0, sizeof(mask));
+ mask.sin6_family = AF_INET6;
+ mask.sin6_len = sizeof(struct sockaddr_in6);
+ mask.sin6_addr = proposal->mask;
+
+ ifa = proposal->addr;
+
+ iov[iovcnt].iov_base = &mask;
+ iov[iovcnt++].iov_len = sizeof(mask);
+ rtm.rtm_msglen += sizeof(mask);
+ padlen = ROUNDUP(sizeof(mask)) - sizeof(mask);
+ if (padlen > 0) {
+ iov[iovcnt].iov_base = &pad;
+ iov[iovcnt++].iov_len = padlen;
+ rtm.rtm_msglen += padlen;
+ }
+
+ iov[iovcnt].iov_base = &ifa;
+ iov[iovcnt++].iov_len = sizeof(ifa);
+ rtm.rtm_msglen += sizeof(ifa);
+ padlen = ROUNDUP(sizeof(ifa)) - sizeof(ifa);
+ if (padlen > 0) {
+ iov[iovcnt].iov_base = &pad;
+ iov[iovcnt++].iov_len = padlen;
+ rtm.rtm_msglen += padlen;
+ }
+
+ if (proposal->rdns.sr_len > 0) {
+ rtm.rtm_addrs |= RTA_DNS;
+
+ iov[iovcnt].iov_base = &proposal->rdns;
+ iov[iovcnt++].iov_len = proposal->rdns.sr_len;
+ rtm.rtm_msglen += proposal->rdns.sr_len;
+ padlen = ROUNDUP(proposal->rdns.sr_len) -
+ proposal->rdns.sr_len;
+ if (padlen > 0) {
+ iov[iovcnt].iov_base = &pad;
+ iov[iovcnt++].iov_len = padlen;
+ rtm.rtm_msglen += padlen;
+ }
+ }
+
+ /* setup default route ::/0 */
+ prefixlen = 0;
+ memset(&prefix, 0, sizeof(prefix));
+ gateway = proposal->gateway;
+
+ memset(&rtstatic, 0, sizeof(rtstatic));
+ rtstatic.sr_family = AF_INET6;
+ rtstatic.sr_len = offsetof(struct sockaddr_rtstatic, sr_static) +
+ sizeof(uint8_t) + sizeof(struct in6_addr) +
+ sizeof(struct sockaddr_in6);
+ p = rtstatic.sr_static;
+ memcpy(p, &prefixlen, sizeof(prefixlen));
+ p += sizeof(prefixlen);
+ memcpy(p, &prefix, sizeof(prefix));
+ p += sizeof(prefix);
+ memcpy(p, &gateway, sizeof(gateway));
+
+ iov[iovcnt].iov_base = &rtstatic;
+ iov[iovcnt++].iov_len = rtstatic.sr_len;
+ rtm.rtm_msglen += rtstatic.sr_len;
+ padlen = ROUNDUP(rtstatic.sr_len) - rtstatic.sr_len;
+ if (padlen > 0) {
+ iov[iovcnt].iov_base = &pad;
+ iov[iovcnt++].iov_len = padlen;
+ rtm.rtm_msglen += padlen;
+ }
+
+ if (proposal->dnssl.sr_len > 0) {
+ rtm.rtm_addrs |= RTA_SEARCH;
+ iov[iovcnt].iov_base = &proposal->dnssl;
+ iov[iovcnt++].iov_len = proposal->dnssl.sr_len;
+ rtm.rtm_msglen += proposal->dnssl.sr_len;
+ padlen = ROUNDUP(proposal->dnssl.sr_len) -
+ proposal->dnssl.sr_len;
+ if (padlen > 0) {
+ iov[iovcnt].iov_base = &pad;
+ iov[iovcnt++].iov_len = padlen;
+ rtm.rtm_msglen += padlen;
+ }
+ }
+
+ if (writev(routesock, iov, iovcnt) == -1)
+ log_warn("failed to send proposal");
+}
diff --git a/usr.sbin/slaacd/slaacd.h b/usr.sbin/slaacd/slaacd.h
index 760410c18d5..219c3d305bd 100644
--- a/usr.sbin/slaacd/slaacd.h
+++ b/usr.sbin/slaacd/slaacd.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: slaacd.h,v 1.5 2017/03/20 16:13:27 florian Exp $ */
+/* $OpenBSD: slaacd.h,v 1.6 2017/03/20 16:15:37 florian Exp $ */
/*
* Copyright (c) 2017 Florian Obser <florian@openbsd.org>
@@ -63,6 +63,7 @@ enum imsg_type {
IMSG_REMOVE_IF,
IMSG_RA,
IMSG_CTL_SEND_SOLICITATION,
+ IMSG_PROPOSAL,
};
extern const char* imsg_type_name[];