The RDE needs to know the local v4 and v6 address of a session so that
nexthop self works. Until now the lookup for the other AF address was done
in the RDE when the session got established. This diff moves this code
over to the SE where it fits better. Especially this allows to remove the
route pledge from the RDE.

This diff works for me but I would like more tests especially on link
local IPv6 sessions (the KAME embedded scope curse haunts me again).
-- 
:wq Claudio

? obj
Index: bgpd.h
===================================================================
RCS file: /cvs/src/usr.sbin/bgpd/bgpd.h,v
retrieving revision 1.397
diff -u -p -r1.397 bgpd.h
--- bgpd.h      9 Jan 2020 11:55:25 -0000       1.397
+++ bgpd.h      9 Jan 2020 13:37:19 -0000
@@ -656,7 +656,8 @@ struct kif {
 };
 
 struct session_up {
-       struct bgpd_addr        local_addr;
+       struct bgpd_addr        local_v4_addr;
+       struct bgpd_addr        local_v6_addr;
        struct bgpd_addr        remote_addr;
        struct capabilities     capa;
        u_int32_t               remote_bgpid;
Index: rde.c
===================================================================
RCS file: /cvs/src/usr.sbin/bgpd/rde.c,v
retrieving revision 1.498
diff -u -p -r1.498 rde.c
--- rde.c       9 Jan 2020 13:31:52 -0000       1.498
+++ rde.c       9 Jan 2020 13:37:19 -0000
@@ -177,7 +177,7 @@ rde_main(int debug, int verbose)
            setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid))
                fatal("can't drop privileges");
 
-       if (pledge("stdio route recvfd", NULL) == -1)
+       if (pledge("stdio recvfd", NULL) == -1)
                fatal("pledge");
 
        signal(SIGTERM, rde_sighdlr);
Index: rde_peer.c
===================================================================
RCS file: /cvs/src/usr.sbin/bgpd/rde_peer.c,v
retrieving revision 1.2
diff -u -p -r1.2 rde_peer.c
--- rde_peer.c  9 Jan 2020 13:31:52 -0000       1.2
+++ rde_peer.c  9 Jan 2020 13:37:19 -0000
@@ -17,9 +17,7 @@
  */
 #include <sys/types.h>
 #include <sys/queue.h>
-#include <sys/socket.h>
 
-#include <ifaddrs.h>
 #include <stdlib.h>
 #include <stdio.h>
 #include <string.h>
@@ -306,102 +304,6 @@ rde_up_dump_done(void *ptr, u_int8_t aid
                fatal("%s: prefix_dump_new", __func__);
 }
 
-static int
-sa_cmp(struct bgpd_addr *a, struct sockaddr *b)
-{
-       struct sockaddr_in      *in_b;
-       struct sockaddr_in6     *in6_b;
-
-       if (aid2af(a->aid) != b->sa_family)
-               return (1);
-
-       switch (b->sa_family) {
-       case AF_INET:
-               in_b = (struct sockaddr_in *)b;
-               if (a->v4.s_addr != in_b->sin_addr.s_addr)
-                       return (1);
-               break;
-       case AF_INET6:
-               in6_b = (struct sockaddr_in6 *)b;
-#ifdef __KAME__
-               /* directly stolen from sbin/ifconfig/ifconfig.c */
-               if (IN6_IS_ADDR_LINKLOCAL(&in6_b->sin6_addr)) {
-                       in6_b->sin6_scope_id =
-                           ntohs(*(u_int16_t *)&in6_b->sin6_addr.s6_addr[2]);
-                       in6_b->sin6_addr.s6_addr[2] =
-                           in6_b->sin6_addr.s6_addr[3] = 0;
-               }
-#endif
-               if (bcmp(&a->v6, &in6_b->sin6_addr,
-                   sizeof(struct in6_addr)))
-                       return (1);
-               break;
-       default:
-               fatal("king bula sez: unknown address family");
-               /* NOTREACHED */
-       }
-
-       return (0);
-}
-
-/*
- * Figure out the local IP addresses most suitable for this session.
- * This looks up the local address of other address family based on
- * the address of the TCP session.
- */
-static int
-peer_localaddrs(struct rde_peer *peer, struct bgpd_addr *laddr)
-{
-       struct ifaddrs  *ifap, *ifa, *match;
-
-       if (getifaddrs(&ifap) == -1)
-               fatal("getifaddrs");
-
-       for (match = ifap; match != NULL; match = match->ifa_next)
-               if (sa_cmp(laddr, match->ifa_addr) == 0)
-                       break;
-
-       if (match == NULL) {
-               log_warnx("peer_localaddrs: local address not found");
-               return (-1);
-       }
-
-       for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next) {
-               if (ifa->ifa_addr->sa_family == AF_INET &&
-                   strcmp(ifa->ifa_name, match->ifa_name) == 0) {
-                       if (ifa->ifa_addr->sa_family ==
-                           match->ifa_addr->sa_family)
-                               ifa = match;
-                       sa2addr(ifa->ifa_addr, &peer->local_v4_addr, NULL);
-                       break;
-               }
-       }
-       for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next) {
-               if (ifa->ifa_addr->sa_family == AF_INET6 &&
-                   strcmp(ifa->ifa_name, match->ifa_name) == 0) {
-                       /*
-                        * only accept global scope addresses except explicitly
-                        * specified.
-                        */
-                       if (ifa->ifa_addr->sa_family ==
-                           match->ifa_addr->sa_family)
-                               ifa = match;
-                       else if (IN6_IS_ADDR_LINKLOCAL(
-                           &((struct sockaddr_in6 *)ifa->
-                           ifa_addr)->sin6_addr) ||
-                           IN6_IS_ADDR_SITELOCAL(
-                           &((struct sockaddr_in6 *)ifa->
-                           ifa_addr)->sin6_addr))
-                               continue;
-                       sa2addr(ifa->ifa_addr, &peer->local_v6_addr, NULL);
-                       break;
-               }
-       }
-
-       freeifaddrs(ifap);
-       return (0);
-}
-
 /*
  * Session got established, bring peer up, load RIBs do initial table dump.
  */
@@ -424,12 +326,10 @@ peer_up(struct rde_peer *peer, struct se
        }
        peer->remote_bgpid = ntohl(sup->remote_bgpid);
        peer->short_as = sup->short_as;
-       memcpy(&peer->remote_addr, &sup->remote_addr,
-           sizeof(peer->remote_addr));
+       peer->remote_addr = sup->remote_addr;
+       peer->local_v4_addr = sup->local_v4_addr;
+       peer->local_v6_addr = sup->local_v6_addr;
        memcpy(&peer->capa, &sup->capa, sizeof(peer->capa));
-
-       if (peer_localaddrs(peer, &sup->local_addr))
-               return (-1);
 
        peer->state = PEER_UP;
 
Index: session.c
===================================================================
RCS file: /cvs/src/usr.sbin/bgpd/session.c,v
retrieving revision 1.396
diff -u -p -r1.396 session.c
--- session.c   9 Jan 2020 11:51:18 -0000       1.396
+++ session.c   9 Jan 2020 13:37:19 -0000
@@ -33,6 +33,7 @@
 #include <err.h>
 #include <errno.h>
 #include <fcntl.h>
+#include <ifaddrs.h>
 #include <poll.h>
 #include <pwd.h>
 #include <signal.h>
@@ -1189,6 +1190,69 @@ session_setup_socket(struct peer *p)
        return (0);
 }
 
+/* compare two sockaddrs by converting them into bgpd_addr */
+static int
+sa_cmp(struct sockaddr *a, struct sockaddr *b)
+{
+       struct bgpd_addr ba, bb;
+
+       sa2addr(a, &ba, NULL);
+       sa2addr(b, &bb, NULL);
+
+       return (memcmp(&ba, &bb, sizeof(ba)) == 0);
+}
+
+static void
+get_alternate_addr(struct sockaddr *sa, struct bgpd_addr *alt)
+{
+       struct ifaddrs  *ifap, *ifa, *match;
+
+       if (getifaddrs(&ifap) == -1)
+               fatal("getifaddrs");
+
+       for (match = ifap; match != NULL; match = match->ifa_next)
+               if (sa_cmp(sa, match->ifa_addr) == 0)
+                       break;
+
+       if (match == NULL) {
+               log_warnx("%s: local address not found", __func__);
+               return;
+       }
+
+       switch (sa->sa_family) {
+       case AF_INET6:
+               for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next) {
+                       if (ifa->ifa_addr->sa_family == AF_INET &&
+                           strcmp(ifa->ifa_name, match->ifa_name) == 0) {
+                               sa2addr(ifa->ifa_addr, alt, NULL);
+                               break;
+                       }
+               }
+               break;
+       case AF_INET:
+               for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next) {
+                       struct sockaddr_in6 *s =
+                           (struct sockaddr_in6 *)ifa->ifa_addr;
+                       if (ifa->ifa_addr->sa_family == AF_INET6 &&
+                           strcmp(ifa->ifa_name, match->ifa_name) == 0) {
+                               /* only accept global scope addresses */
+                               if (IN6_IS_ADDR_LINKLOCAL(&s->sin6_addr) ||
+                                   IN6_IS_ADDR_SITELOCAL(&s->sin6_addr))
+                                       continue;
+                               sa2addr(ifa->ifa_addr, alt, NULL);
+                               break;
+                       }
+               }
+               break;
+       default:
+               log_warnx("%s: unsupported address family %d", __func__,
+                   sa->sa_family);
+               break;
+       }
+
+       freeifaddrs(ifap);
+}
+
 void
 session_tcp_established(struct peer *peer)
 {
@@ -1199,6 +1263,7 @@ session_tcp_established(struct peer *pee
        if (getsockname(peer->fd, (struct sockaddr *)&ss, &len) == -1)
                log_warn("getsockname");
        sa2addr((struct sockaddr *)&ss, &peer->local, &peer->local_port);
+       get_alternate_addr((struct sockaddr *)&ss, &peer->local_alt);
        len = sizeof(ss);
        if (getpeername(peer->fd, (struct sockaddr *)&ss, &len) == -1)
                log_warn("getpeername");
@@ -3070,7 +3135,13 @@ session_up(struct peer *p)
            &p->conf, sizeof(p->conf)) == -1)
                fatalx("imsg_compose error");
 
-       sup.local_addr = p->local;
+       if (p->local.aid == AID_INET) {
+               sup.local_v4_addr = p->local;
+               sup.local_v6_addr = p->local_alt;
+       } else {
+               sup.local_v6_addr = p->local;
+               sup.local_v4_addr = p->local_alt;
+       }
        sup.remote_addr = p->remote;
 
        sup.remote_bgpid = p->remote_bgpid;
Index: session.h
===================================================================
RCS file: /cvs/src/usr.sbin/bgpd/session.h,v
retrieving revision 1.142
diff -u -p -r1.142 session.h
--- session.h   9 Jan 2020 11:51:18 -0000       1.142
+++ session.h   9 Jan 2020 13:37:19 -0000
@@ -211,6 +211,7 @@ struct peer {
                u_int8_t                established;
        }                        auth;
        struct bgpd_addr         local;
+       struct bgpd_addr         local_alt;
        struct bgpd_addr         remote;
        struct peer_timer_head   timers;
        struct msgbuf            wbuf;
Index: util.c
===================================================================
RCS file: /cvs/src/usr.sbin/bgpd/util.c,v
retrieving revision 1.51
diff -u -p -r1.51 util.c
--- util.c      3 Jul 2019 03:24:02 -0000       1.51
+++ util.c      9 Jan 2020 13:37:19 -0000
@@ -75,6 +75,7 @@ log_in6addr(const struct in6_addr *addr)
        sa_in6.sin6_family = AF_INET6;
        memcpy(&sa_in6.sin6_addr, addr, sizeof(sa_in6.sin6_addr));
 
+#ifdef __KAME__
        /* XXX thanks, KAME, for this ugliness... adopted from route/show.c */
        if (IN6_IS_ADDR_LINKLOCAL(&sa_in6.sin6_addr) ||
            IN6_IS_ADDR_MC_LINKLOCAL(&sa_in6.sin6_addr)) {
@@ -83,6 +84,7 @@ log_in6addr(const struct in6_addr *addr)
                sa_in6.sin6_addr.s6_addr[2] = 0;
                sa_in6.sin6_addr.s6_addr[3] = 0;
        }
+#endif
 
        return (log_sockaddr((struct sockaddr *)&sa_in6, sizeof(sa_in6)));
 }
@@ -883,6 +885,23 @@ sa2addr(struct sockaddr *sa, struct bgpd
        case AF_INET6:
                addr->aid = AID_INET6;
                memcpy(&addr->v6, &sa_in6->sin6_addr, sizeof(addr->v6));
+#ifdef __KAME__
+               /*
+                * XXX thanks, KAME, for this ugliness...
+                * adopted from route/show.c
+                */
+               if (IN6_IS_ADDR_LINKLOCAL(&sa_in6->sin6_addr) ||
+                   IN6_IS_ADDR_MC_LINKLOCAL(&sa_in6->sin6_addr)) {
+                       uint16_t tmp16;
+                       memcpy(&tmp16, &sa_in6->sin6_addr.s6_addr[2],
+                           sizeof(tmp16));
+                       if (tmp16 != 0) {
+                               sa_in6->sin6_scope_id = ntohs(tmp16);
+                               sa_in6->sin6_addr.s6_addr[2] = 0;
+                               sa_in6->sin6_addr.s6_addr[3] = 0;
+                       }
+               }
+#endif
                addr->scope_id = sa_in6->sin6_scope_id; /* I hate v6 */
                if (port)
                        *port = ntohs(sa_in6->sin6_port);

Reply via email to