On Thu, Jan 09, 2020 at 02:45:46PM +0100, Claudio Jeker wrote: > 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).
ping... -- :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);