diff options
author | 2017-03-02 17:09:21 +0000 | |
---|---|---|
committer | 2017-03-02 17:09:21 +0000 | |
commit | 46c62a11c36c34beb2d403777db75ed08acd9022 (patch) | |
tree | 6aa06affaea28162af8970ce25f884c2f1644156 | |
parent | Document some installation quirks for the EdgeRouter Lite in INSTALL.octeon: (diff) | |
download | wireguard-openbsd-46c62a11c36c34beb2d403777db75ed08acd9022.tar.xz wireguard-openbsd-46c62a11c36c34beb2d403777db75ed08acd9022.zip |
Implement a new routing message RTM_PROPOSAL that communicates
information that can be used to configure an interface and
related network components.
ok bluhm@, ok for various older versions mpi@ florian@ claudio@
-rw-r--r-- | sbin/route/route.c | 220 | ||||
-rw-r--r-- | sys/net/route.h | 38 | ||||
-rw-r--r-- | sys/net/rtsock.c | 107 |
3 files changed, 358 insertions, 7 deletions
diff --git a/sbin/route/route.c b/sbin/route/route.c index 3a82c0414c0..10fae42ba01 100644 --- a/sbin/route/route.c +++ b/sbin/route/route.c @@ -1,4 +1,4 @@ -/* $OpenBSD: route.c,v 1.196 2017/01/23 00:10:07 krw Exp $ */ +/* $OpenBSD: route.c,v 1.197 2017/03/02 17:09:21 krw Exp $ */ /* $NetBSD: route.c,v 1.16 1996/04/15 18:27:05 cgd Exp $ */ /* @@ -119,6 +119,9 @@ void interfaces(void); void getlabel(char *); int gettable(const char *); int rdomain(int, char **); +void print_rtdns(struct sockaddr_rtdns *); +void print_rtstatic(struct sockaddr_rtstatic *); +void print_rtsearch(struct sockaddr_rtsearch *); __dead void usage(char *cp) @@ -1258,6 +1261,7 @@ char *msgtypes[] = { "RTM_DESYNC: route socket overflow", "RTM_INVALIDATE: invalidate cache of L2 route", "RTM_BFD: bidirectional forwarding detection", + "RTM_PROPOSAL: config proposal" }; char metricnames[] = @@ -1271,7 +1275,7 @@ char ifnetflags[] = "\1UP\2BROADCAST\3DEBUG\4LOOPBACK\5PTP\6NOTRAILERS\7RUNNING\010NOARP\011PPROMISC" "\012ALLMULTI\013OACTIVE\014SIMPLEX\015LINK0\016LINK1\017LINK2\020MULTICAST"; char addrnames[] = -"\1DST\2GATEWAY\3NETMASK\4GENMASK\5IFP\6IFA\7AUTHOR\010BRD\011SRC\12SRCMASK\013LABEL"; +"\1DST\2GATEWAY\3NETMASK\4GENMASK\5IFP\6IFA\7AUTHOR\010BRD\011SRC\012SRCMASK\013LABEL\014BFD\015DNS\016STATIC\017SEARCH"; const char * get_linkstate(int mt, int link_state) @@ -1355,6 +1359,87 @@ print_rtmsg(struct rt_msghdr *rtm, int msglen) print_bfdmsg(rtm); break; #endif + case RTM_PROPOSAL: + printf(", source "); + switch (rtm->rtm_priority) { + case RTP_PROPOSAL_STATIC: + printf("static"); + break; + case RTP_PROPOSAL_DHCLIENT: + printf("dhcp"); + break; + case RTP_PROPOSAL_SLAAC: + printf("slaac"); + break; + default: + printf("unknown"); + break; + } + printf(" table %u, ifidx %u, ", + rtm->rtm_tableid, rtm->rtm_index); + printf("pid: %ld, seq %d, errno %d\nflags:", + (long)rtm->rtm_pid, rtm->rtm_seq, rtm->rtm_errno); + bprintf(stdout, rtm->rtm_flags, routeflags); + printf("\nfmask:"); + bprintf(stdout, rtm->rtm_fmask, routeflags); + if (verbose) { +#define lock(f) ((rtm->rtm_rmx.rmx_locks & __CONCAT(RTV_,f)) ? 'L' : ' ') + relative_expire = rtm->rtm_rmx.rmx_expire ? + rtm->rtm_rmx.rmx_expire - time(NULL) : 0; + printf("\nuse: %8llu mtu: %8u%c expire: %8lld%c", + rtm->rtm_rmx.rmx_pksent, + rtm->rtm_rmx.rmx_mtu, lock(MTU), + relative_expire, lock(EXPIRE)); +#undef lock + } + printf("\nlocks: "); + bprintf(stdout, rtm->rtm_rmx.rmx_locks, metricnames); + printf(" inits: "); + bprintf(stdout, rtm->rtm_inits, metricnames); + pmsg_addrs(((char *)rtm + rtm->rtm_hdrlen), + rtm->rtm_addrs & ~(RTA_STATIC | RTA_SEARCH | RTA_DNS)); + printf("Static Routes:\n"); + if (rtm->rtm_addrs & RTA_STATIC) { + char *next = (char *)rtm + rtm->rtm_hdrlen; + struct sockaddr *sa, *rti_info[RTAX_MAX]; + struct sockaddr_rtstatic *rtstatic; + sa = (struct sockaddr *)next; + get_rtaddrs(rtm->rtm_addrs, sa, rti_info); + rtstatic = (struct sockaddr_rtstatic *) + rti_info[RTAX_STATIC]; + if (rtstatic != NULL) { + printf(" "); + print_rtstatic(rtstatic); + } + } + printf("Domain search:\n"); + if (rtm->rtm_addrs & RTA_SEARCH) { + char *next = (char *)rtm + rtm->rtm_hdrlen; + struct sockaddr *sa, *rti_info[RTAX_MAX]; + struct sockaddr_rtsearch *rtsearch; + sa = (struct sockaddr *)next; + get_rtaddrs(rtm->rtm_addrs, sa, rti_info); + rtsearch = (struct sockaddr_rtsearch *) + rti_info[RTAX_SEARCH]; + if (rtsearch != NULL) { + printf(" "); + print_rtsearch(rtsearch); + } + } + printf("Domain Name Servers:\n"); + if (rtm->rtm_addrs & RTA_DNS) { + char *next = (char *)rtm + rtm->rtm_hdrlen; + struct sockaddr *sa, *rti_info[RTAX_MAX]; + struct sockaddr_rtdns *rtdns; + sa = (struct sockaddr *)next; + get_rtaddrs(rtm->rtm_addrs, sa, rti_info); + rtdns = (struct sockaddr_rtdns *)rti_info[RTAX_DNS]; + if (rtdns != NULL) { + printf(" "); + print_rtdns(rtdns); + } + } + break; default: printf(", priority %d, table %u, ifidx %u, ", rtm->rtm_priority, rtm->rtm_tableid, rtm->rtm_index); @@ -1918,3 +2003,134 @@ rdomain(int argc, char **argv) warn("%s", argv[0]); return (errno == ENOENT ? 127 : 126); } + +/* + * Print RTM_PROPOSAL DNS server addresses. + */ +void +print_rtdns(struct sockaddr_rtdns *rtdns) +{ + struct in_addr server; + char *src = rtdns->sr_dns; + size_t srclen, offset; + unsigned int servercnt; + int i; + + offset = offsetof(struct sockaddr_rtdns, sr_dns); + if (rtdns->sr_len <= offset) { + printf("<invalid sr_len (%d <= %zu)>\n", rtdns->sr_len, + offset); + return; + } + srclen = rtdns->sr_len - offset; + if (srclen > sizeof(rtdns->sr_dns)) { + printf("<invalid sr_len (%zu > %zu)>\n", srclen, + sizeof(rtdns->sr_dns)); + return; + } + + switch (rtdns->sr_family) { + case AF_INET: + /* An array of IPv4 addresses. */ + servercnt = srclen / sizeof(struct in_addr); + if (servercnt * sizeof(struct in_addr) != srclen) { + printf("<invalid server count>\n"); + return; + } + for (i = 0; i < servercnt; i++) { + memcpy(&server.s_addr, src, sizeof(server.s_addr)); + printf("%s ", inet_ntoa(server)); + src += sizeof(struct in_addr); + } + break; + case AF_INET6: + printf("<AF_INET6> printing not yet implemented\n"); + break; + default: + break; + } + printf("\n"); +} + +/* + * Print RTM_PROPOSAL static routes. + */ +void +print_rtstatic(struct sockaddr_rtstatic *rtstatic) +{ + struct in_addr dest, gateway; + unsigned char *src = rtstatic->sr_static; + size_t srclen, offset; + int bits, bytes; + char ntoabuf[INET_ADDRSTRLEN]; + + offset = offsetof(struct sockaddr_rtstatic, sr_static); + if (rtstatic->sr_len <= offset) { + printf("<invalid sr_len (%d <= %zu)>\n", rtstatic->sr_len, + offset); + return; + } + srclen = rtstatic->sr_len - offset; + if (srclen > sizeof(rtstatic->sr_static)) { + printf("<invalid sr_len (%zu > %zu)>\n", srclen, + sizeof(rtstatic->sr_static)); + return; + } + + switch (rtstatic->sr_family) { + case AF_INET: + /* AF_INET -> RFC 3442 encoded static routes. */ + while (srclen) { + bits = *src; + src++; + srclen--; + bytes = (bits + 7) / 8; + if (srclen < bytes || bytes > sizeof(dest.s_addr)) + break; + memset(&dest, 0, sizeof(dest)); + memcpy(&dest.s_addr, src, bytes); + src += bytes; + srclen -= bytes; + strlcpy(ntoabuf, inet_ntoa(dest), sizeof(ntoabuf)); + if (srclen < sizeof(gateway.s_addr)) + break; + memcpy(&gateway.s_addr, src, sizeof(gateway.s_addr)); + src += sizeof(gateway.s_addr); + srclen -= sizeof(gateway.s_addr); + printf("%s/%u %s ", ntoabuf, bits, inet_ntoa(gateway)); + } + break; + case AF_INET6: + printf("<AF_INET6 printing not yet implemented>"); + break; + default: + printf("<unknown address family %d>", rtstatic->sr_family); + break; + } + printf("\n"); +} + +/* + * Print RTM_PROPOSAL domain search list. + */ +void +print_rtsearch(struct sockaddr_rtsearch *rtsearch) +{ + char *src = rtsearch->sr_search; + size_t srclen, offset; + + offset = offsetof(struct sockaddr_rtsearch, sr_search); + if (rtsearch->sr_len <= offset) { + printf("<invalid sr_len (%d <= %zu)>\n", rtsearch->sr_len, + offset); + return; + } + srclen = rtsearch->sr_len - offset; + if (srclen > sizeof(rtsearch->sr_search)) { + printf("<invalid sr_len (%zu > %zu)>\n", srclen, + sizeof(rtsearch->sr_search)); + return; + } + + printf("%*s\n", (int)srclen, src); +} diff --git a/sys/net/route.h b/sys/net/route.h index 8e5ee2d7ba2..a67f3af27a5 100644 --- a/sys/net/route.h +++ b/sys/net/route.h @@ -1,4 +1,4 @@ -/* $OpenBSD: route.h,v 1.156 2017/01/23 00:59:22 krw Exp $ */ +/* $OpenBSD: route.h,v 1.157 2017/03/02 17:09:21 krw Exp $ */ /* $NetBSD: route.h,v 1.9 1996/02/13 22:00:49 christos Exp $ */ /* @@ -168,6 +168,9 @@ struct rtentry { #define RTP_RIP 40 /* RIP routes */ #define RTP_BGP 48 /* BGP routes */ #define RTP_DEFAULT 56 /* routes that have nothing set */ +#define RTP_PROPOSAL_STATIC 57 +#define RTP_PROPOSAL_DHCLIENT 58 +#define RTP_PROPOSAL_SLAAC 59 #define RTP_MAX 63 /* maximum priority */ #define RTP_ANY 64 /* any of the above */ #define RTP_MASK 0x7f @@ -237,6 +240,7 @@ struct rt_msghdr { #define RTM_DESYNC 0x10 /* route socket buffer overflow */ #define RTM_INVALIDATE 0x11 /* Invalidate cache of L2 route */ #define RTM_BFD 0x12 /* bidirectional forwarding detection */ +#define RTM_PROPOSAL 0x13 /* proposal for netconfigd */ #define RTV_MTU 0x1 /* init or lock _mtu */ #define RTV_HOPCOUNT 0x2 /* init or lock _hopcount */ @@ -262,6 +266,9 @@ struct rt_msghdr { #define RTA_SRCMASK 0x200 /* source netmask present */ #define RTA_LABEL 0x400 /* route label present */ #define RTA_BFD 0x800 /* bfd present */ +#define RTA_DNS 0x1000 /* DNS Servers sockaddr present */ +#define RTA_STATIC 0x2000 /* RFC 3442 encoded static routes present */ +#define RTA_SEARCH 0x4000 /* RFC 3397 encoded search path present */ /* * Index offsets for sockaddr array for alternate internal encoding. @@ -278,7 +285,10 @@ struct rt_msghdr { #define RTAX_SRCMASK 9 /* source netmask present */ #define RTAX_LABEL 10 /* route label present */ #define RTAX_BFD 11 /* bfd present */ -#define RTAX_MAX 12 /* size of array to allocate */ +#define RTAX_DNS 12 /* DNS Server(s) sockaddr present */ +#define RTAX_STATIC 13 /* RFC 3442 encoded static routes present */ +#define RTAX_SEARCH 14 /* RFC 3397 encoded search path present */ +#define RTAX_MAX 15 /* size of array to allocate */ /* * setsockopt defines used for the filtering. @@ -299,6 +309,30 @@ struct sockaddr_rtlabel { char sr_label[RTLABEL_LEN]; }; +#define RTDNS_LEN 128 + +struct sockaddr_rtdns { + u_int8_t sr_len; /* total length */ + sa_family_t sr_family; /* address family */ + char sr_dns[RTDNS_LEN]; +}; + +#define RTSTATIC_LEN 128 + +struct sockaddr_rtstatic { + u_int8_t sr_len; /* total length */ + sa_family_t sr_family; /* address family */ + char sr_static[RTSTATIC_LEN]; +}; + +#define RTSEARCH_LEN 128 + +struct sockaddr_rtsearch { + u_int8_t sr_len; /* total length */ + sa_family_t sr_family; /* address family */ + char sr_search[RTSEARCH_LEN]; +}; + /* * A route consists of a destination address and a reference * to a routing entry. These are often held by protocols diff --git a/sys/net/rtsock.c b/sys/net/rtsock.c index 89c6a0bef0d..27338b49e35 100644 --- a/sys/net/rtsock.c +++ b/sys/net/rtsock.c @@ -1,4 +1,4 @@ -/* $OpenBSD: rtsock.c,v 1.225 2017/03/02 09:37:04 mpi Exp $ */ +/* $OpenBSD: rtsock.c,v 1.226 2017/03/02 17:09:21 krw Exp $ */ /* $NetBSD: rtsock.c,v 1.18 1996/03/29 00:32:10 cgd Exp $ */ /* @@ -108,10 +108,14 @@ int rt_msg2(int, int, struct rt_addrinfo *, caddr_t, struct walkarg *); void rt_xaddrs(caddr_t, caddr_t, struct rt_addrinfo *); +void rt_proposalmsg(struct rt_msghdr *, struct rt_addrinfo *); + int sysctl_iflist(int, struct walkarg *); int sysctl_ifnames(struct walkarg *); int sysctl_rtable_rtstat(void *, size_t *, void *); +int validate_proposal(struct rt_addrinfo *); + struct routecb { struct rawcb rcb; struct timeout timeout; @@ -597,6 +601,7 @@ route_output(struct mbuf *m, ...) case RTM_GET: case RTM_CHANGE: case RTM_LOCK: + case RTM_PROPOSAL: break; default: error = EOPNOTSUPP; @@ -652,11 +657,12 @@ route_output(struct mbuf *m, ...) info.rti_addrs = rtm->rtm_addrs; rt_xaddrs(rtm->rtm_hdrlen + (caddr_t)rtm, len + (caddr_t)rtm, &info); info.rti_flags = rtm->rtm_flags; - if (info.rti_info[RTAX_DST] == NULL || + if (rtm->rtm_type != RTM_PROPOSAL && + (info.rti_info[RTAX_DST] == NULL || info.rti_info[RTAX_DST]->sa_family >= AF_MAX || (info.rti_info[RTAX_GATEWAY] != NULL && info.rti_info[RTAX_GATEWAY]->sa_family >= AF_MAX) || - info.rti_info[RTAX_GENMASK] != NULL) { + info.rti_info[RTAX_GENMASK] != NULL)) { error = EINVAL; goto fail; } @@ -675,6 +681,18 @@ route_output(struct mbuf *m, ...) * may be not consistent and could cause unexpected behaviour in other * userland clients. Use goto fail instead. */ + + /* + * Validate RTM_PROPOSAL and pass it along or error out. + */ + if (rtm->rtm_type == RTM_PROPOSAL) { + if (validate_proposal(&info) == -1) { + error = EINVAL; + goto fail; + } + goto flush; + } + switch (rtm->rtm_type) { case RTM_ADD: if (info.rti_info[RTAX_GATEWAY] == NULL) { @@ -1642,6 +1660,89 @@ sysctl_rtable_rtstat(void *oldp, size_t *oldlenp, void *newp) return (sysctl_rdstruct(oldp, oldlenp, newp, &rtstat, sizeof(rtstat))); } +int +validate_proposal(struct rt_addrinfo *info) +{ + if (info->rti_addrs & ~(RTA_NETMASK | RTA_IFA | RTA_DNS | RTA_STATIC | + RTA_SEARCH)) { + return -1; + } + + if (ISSET(info->rti_addrs, RTA_NETMASK)) { + struct sockaddr *sa = info->rti_info[RTAX_NETMASK]; + if (sa == NULL) + return -1; + switch (sa->sa_family) { + case AF_INET: + if (sa->sa_len != sizeof(struct sockaddr_in)) + return -1; + break; + case AF_INET6: + if (sa->sa_len != sizeof(struct sockaddr_in6)) + return -1; + break; + default: + return -1; + } + } + + if (ISSET(info->rti_addrs, RTA_IFA)) { + struct sockaddr *sa = info->rti_info[RTAX_IFA]; + if (sa == NULL) + return -1; + switch (sa->sa_family) { + case AF_INET: + if (sa->sa_len != sizeof(struct sockaddr_in)) + return -1; + break; + case AF_INET6: + if (sa->sa_len != sizeof(struct sockaddr_in6)) + return -1; + break; + default: + return -1; + } + } + + if (ISSET(info->rti_addrs, RTA_DNS)) { + struct sockaddr_rtdns *rtdns = + (struct sockaddr_rtdns *)info->rti_info[RTAX_DNS]; + if (rtdns == NULL) + return -1; + if (rtdns->sr_len > sizeof(*rtdns)) + return -1; + if (rtdns->sr_len <= + offsetof(struct sockaddr_rtdns, sr_dns)) + return -1; + } + + if (ISSET(info->rti_addrs, RTA_STATIC)) { + struct sockaddr_rtstatic *rtstatic = + (struct sockaddr_rtstatic *)info->rti_info[RTAX_STATIC]; + if (rtstatic == NULL) + return -1; + if (rtstatic->sr_len > sizeof(*rtstatic)) + return -1; + if (rtstatic->sr_len <= + offsetof(struct sockaddr_rtstatic, sr_static)) + return -1; + } + + if (ISSET(info->rti_addrs, RTA_SEARCH)) { + struct sockaddr_rtsearch *rtsearch = + (struct sockaddr_rtsearch *)info->rti_info[RTAX_SEARCH]; + if (rtsearch == NULL) + return -1; + if (rtsearch->sr_len > sizeof(*rtsearch)) + return -1; + if (rtsearch->sr_len <= + offsetof(struct sockaddr_rtsearch, sr_search)) + return -1; + } + + return 0; +} + /* * Definitions of protocols supported in the ROUTE domain. */ |