On 2023-06-29 15:03 +02, Claudio Jeker <[email protected]> wrote:
> Once again struct sockaddr_in6 causes 64bit systems to cry. This time in
> relayd. You can not statically setup a route message and think it will
> work. All our routing daemons switched to iov for building the route
> message out of various components. This diff does the same for relayd.
> With this it is possible to use router blocks with IPv6 addrs.
>
> Btw. this does not work with link local addressing but I do not care
> about that dumpster fire.
I had hoped for considerably more -
Oh well, one can dream.
One nit inline, diff reads fine, OK florian
> --
> :wq Claudio
>
> Index: pfe_route.c
> ===================================================================
> RCS file: /cvs/src/usr.sbin/relayd/pfe_route.c,v
> retrieving revision 1.12
> diff -u -p -r1.12 pfe_route.c
> --- pfe_route.c 28 May 2017 10:39:15 -0000 1.12
> +++ pfe_route.c 29 Jun 2023 12:55:59 -0000
> @@ -19,12 +19,14 @@
> #include <sys/types.h>
> #include <sys/queue.h>
> #include <sys/socket.h>
> +#include <sys/uio.h>
>
> #include <netinet/in.h>
> #include <net/route.h>
> #include <arpa/inet.h>
>
> #include <limits.h>
> +#include <stddef.h>
> #include <stdio.h>
> #include <unistd.h>
> #include <string.h>
> @@ -32,24 +34,6 @@
>
> #include "relayd.h"
>
> -struct relay_rtmsg {
> - struct rt_msghdr rm_hdr;
> - union {
> - struct {
> - struct sockaddr_in rm_dst;
> - struct sockaddr_in rm_gateway;
> - struct sockaddr_in rm_netmask;
> - struct sockaddr_rtlabel rm_label;
> - } u4;
> - struct {
> - struct sockaddr_in6 rm_dst;
> - struct sockaddr_in6 rm_gateway;
> - struct sockaddr_in6 rm_netmask;
> - struct sockaddr_rtlabel rm_label;
> - } u6;
> - } rm_u;
> -};
> -
> void
> init_routes(struct relayd *env)
> {
> @@ -103,110 +87,97 @@ sync_routes(struct relayd *env, struct r
> }
> }
>
> +static void
> +pfe_apply_prefixlen(struct sockaddr_storage *ss, int af, int len)
> +{
> + int q, r, off;
> + uint8_t *b = (uint8_t *)ss;
> +
> + q = len >> 3;
^ spaces vs. tab
> + r = len & 7;
> +
> + bzero(ss, sizeof(*ss));
> + ss->ss_family = af;
> + switch (af) {
> + case AF_INET:
> + ss->ss_len = sizeof(struct sockaddr_in);
> + off = offsetof(struct sockaddr_in, sin_addr);
> + break;
> + case AF_INET6:
> + ss->ss_len = sizeof(struct sockaddr_in6);
> + off = offsetof(struct sockaddr_in6, sin6_addr);
> + break;
> + default:
> + fatal("%s: invalid address family", __func__);
> + }
> + if (q > 0)
> + memset(b + off, 0xff, q);
> + if (r > 0)
> + b[off + q] = (0xff00 >> r) & 0xff;
> +}
> +
> +#define ROUNDUP(a) \
> + ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
> +
> int
> pfe_route(struct relayd *env, struct ctl_netroute *crt)
> {
> - struct relay_rtmsg rm;
> - struct sockaddr_rtlabel sr;
> - struct sockaddr_storage *gw;
> - struct sockaddr_in *s4;
> - struct sockaddr_in6 *s6;
> - size_t len = 0;
> + struct iovec iov[5];
> + struct rt_msghdr hdr;
> + struct sockaddr_storage dst, gw, mask, label;
> + struct sockaddr_rtlabel *sr = (struct sockaddr_rtlabel *)&label;
> + int iovcnt = 0;
> char *gwname;
> - int i = 0;
>
> - gw = &crt->host.ss;
> - gwname = crt->host.name;
> + bzero(&hdr, sizeof(hdr));
> + hdr.rtm_msglen = sizeof(hdr);
> + hdr.rtm_version = RTM_VERSION;
> + hdr.rtm_type = HOST_ISUP(crt->up) ? RTM_ADD : RTM_DELETE;
> + hdr.rtm_flags = RTF_STATIC | RTF_GATEWAY | RTF_MPATH;
> + hdr.rtm_seq = env->sc_rtseq++;
> + hdr.rtm_addrs = RTA_DST | RTA_GATEWAY | RTA_NETMASK;
> + hdr.rtm_tableid = crt->rt.rtable;
> + hdr.rtm_priority = crt->host.priority;
>
> - bzero(&rm, sizeof(rm));
> - bzero(&sr, sizeof(sr));
> + iov[iovcnt].iov_base = &hdr;
> + iov[iovcnt++].iov_len = sizeof(hdr);
> +
> + dst = crt->nr.ss;
> + gw = crt->host.ss;
> + gwname = crt->host.name;
> + pfe_apply_prefixlen(&mask, dst.ss_family, crt->nr.prefixlen);
>
> - rm.rm_hdr.rtm_msglen = len;
> - rm.rm_hdr.rtm_version = RTM_VERSION;
> - rm.rm_hdr.rtm_type = HOST_ISUP(crt->up) ? RTM_ADD : RTM_DELETE;
> - rm.rm_hdr.rtm_flags = RTF_STATIC | RTF_GATEWAY | RTF_MPATH;
> - rm.rm_hdr.rtm_seq = env->sc_rtseq++;
> - rm.rm_hdr.rtm_addrs = RTA_DST | RTA_GATEWAY;
> - rm.rm_hdr.rtm_tableid = crt->rt.rtable;
> - rm.rm_hdr.rtm_priority = crt->host.priority;
> + iov[iovcnt].iov_base = &dst;
> + iov[iovcnt++].iov_len = ROUNDUP(dst.ss_len);
> + hdr.rtm_msglen += ROUNDUP(dst.ss_len);
> +
> + iov[iovcnt].iov_base = &gw;
> + iov[iovcnt++].iov_len = ROUNDUP(gw.ss_len);
> + hdr.rtm_msglen += ROUNDUP(gw.ss_len);
> +
> + iov[iovcnt].iov_base = &mask;
> + iov[iovcnt++].iov_len = ROUNDUP(mask.ss_len);
> + hdr.rtm_msglen += ROUNDUP(mask.ss_len);
>
> if (strlen(crt->rt.label)) {
> - rm.rm_hdr.rtm_addrs |= RTA_LABEL;
> - sr.sr_len = sizeof(sr);
> - if (snprintf(sr.sr_label, sizeof(sr.sr_label),
> - "%s", crt->rt.label) == -1)
> - goto bad;
> - }
> + sr->sr_len = sizeof(*sr);
> + strlcpy(sr->sr_label, crt->rt.label, sizeof(sr->sr_label));
>
> - if (crt->nr.ss.ss_family == AF_INET) {
> - rm.rm_hdr.rtm_msglen = len =
> - sizeof(rm.rm_hdr) + sizeof(rm.rm_u.u4);
> -
> - bcopy(&sr, &rm.rm_u.u4.rm_label, sizeof(sr));
> -
> - s4 = &rm.rm_u.u4.rm_dst;
> - s4->sin_family = AF_INET;
> - s4->sin_len = sizeof(rm.rm_u.u4.rm_dst);
> - s4->sin_addr.s_addr =
> - ((struct sockaddr_in *)&crt->nr.ss)->sin_addr.s_addr;
> -
> - s4 = &rm.rm_u.u4.rm_gateway;
> - s4->sin_family = AF_INET;
> - s4->sin_len = sizeof(rm.rm_u.u4.rm_gateway);
> - s4->sin_addr.s_addr =
> - ((struct sockaddr_in *)gw)->sin_addr.s_addr;
> -
> - rm.rm_hdr.rtm_addrs |= RTA_NETMASK;
> - s4 = &rm.rm_u.u4.rm_netmask;
> - s4->sin_family = AF_INET;
> - s4->sin_len = sizeof(rm.rm_u.u4.rm_netmask);
> - if (crt->nr.prefixlen)
> - s4->sin_addr.s_addr =
> - htonl(0xffffffff << (32 - crt->nr.prefixlen));
> - else if (crt->nr.prefixlen < 0)
> - rm.rm_hdr.rtm_flags |= RTF_HOST;
> - } else if (crt->nr.ss.ss_family == AF_INET6) {
> - rm.rm_hdr.rtm_msglen = len =
> - sizeof(rm.rm_hdr) + sizeof(rm.rm_u.u6);
> -
> - bcopy(&sr, &rm.rm_u.u6.rm_label, sizeof(sr));
> -
> - s6 = &rm.rm_u.u6.rm_dst;
> - bcopy(((struct sockaddr_in6 *)&crt->nr.ss),
> - s6, sizeof(*s6));
> - s6->sin6_family = AF_INET6;
> - s6->sin6_len = sizeof(*s6);
> -
> - s6 = &rm.rm_u.u6.rm_gateway;
> - bcopy(((struct sockaddr_in6 *)gw), s6, sizeof(*s6));
> - s6->sin6_family = AF_INET6;
> - s6->sin6_len = sizeof(*s6);
> -
> - rm.rm_hdr.rtm_addrs |= RTA_NETMASK;
> - s6 = &rm.rm_u.u6.rm_netmask;
> - s6->sin6_family = AF_INET6;
> - s6->sin6_len = sizeof(*s6);
> - if (crt->nr.prefixlen) {
> - for (i = 0; i < crt->nr.prefixlen / 8; i++)
> - s6->sin6_addr.s6_addr[i] = 0xff;
> - i = crt->nr.prefixlen % 8;
> - if (i)
> - s6->sin6_addr.s6_addr[crt->nr.prefixlen
> - / 8] = 0xff00 >> i;
> - } else if (crt->nr.prefixlen < 0)
> - rm.rm_hdr.rtm_flags |= RTF_HOST;
> - } else
> - fatal("%s: invalid address family", __func__);
> + iov[iovcnt].iov_base = &label;
> + iov[iovcnt++].iov_len = ROUNDUP(label.ss_len);
> + hdr.rtm_msglen += ROUNDUP(label.ss_len);
> + hdr.rtm_addrs |= RTA_LABEL;
> + }
>
> retry:
> - if (write(env->sc_rtsock, &rm, len) == -1) {
> + if (writev(env->sc_rtsock, iov, iovcnt) == -1) {
> switch (errno) {
> case EEXIST:
> case ESRCH:
> - if (rm.rm_hdr.rtm_type == RTM_ADD) {
> - rm.rm_hdr.rtm_type = RTM_CHANGE;
> + if (hdr.rtm_type == RTM_ADD) {
> + hdr.rtm_type = RTM_CHANGE;
> goto retry;
> - } else if (rm.rm_hdr.rtm_type == RTM_DELETE) {
> + } else if (hdr.rtm_type == RTM_DELETE) {
> /* Ignore */
> break;
> }
>
--
In my defence, I have been left unsupervised.