diff options
author | 2017-03-20 16:15:37 +0000 | |
---|---|---|
committer | 2017-03-20 16:15:37 +0000 | |
commit | 9f4b1db1bca0618903ff5fd045eed07ad306f592 (patch) | |
tree | fbabf6523c739fcf66956fa09385336113573b9d | |
parent | simplify control socket path handling; sync from netcfgd by krw@ (diff) | |
download | wireguard-openbsd-9f4b1db1bca0618903ff5fd045eed07ad306f592.tar.xz wireguard-openbsd-9f4b1db1bca0618903ff5fd045eed07ad306f592.zip |
send proposals
-rw-r--r-- | usr.sbin/slaacd/engine.c | 88 | ||||
-rw-r--r-- | usr.sbin/slaacd/engine.h | 11 | ||||
-rw-r--r-- | usr.sbin/slaacd/slaacd.c | 147 | ||||
-rw-r--r-- | usr.sbin/slaacd/slaacd.h | 3 |
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[]; |