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