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);