On 2023-06-29 15:03 +02, Claudio Jeker <cje...@diehard.n-r-g.com> 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.

Reply via email to