summaryrefslogtreecommitdiffstats
path: root/usr.sbin/bgpd
diff options
context:
space:
mode:
authorclaudio <claudio@openbsd.org>2020-02-12 10:33:56 +0000
committerclaudio <claudio@openbsd.org>2020-02-12 10:33:56 +0000
commitbe6ced5ee5a1afe0142ea2666978906cb40b9169 (patch)
treeb231026225010b801a9fb149b967d04019d146fc /usr.sbin/bgpd
parentPrevent double free in error path; pointed out by scan-build. (diff)
downloadwireguard-openbsd-be6ced5ee5a1afe0142ea2666978906cb40b9169.tar.xz
wireguard-openbsd-be6ced5ee5a1afe0142ea2666978906cb40b9169.zip
Move the code to figure out the alternate IP address (IPv6 addr for IPv4
sessions and vice versa) from the RDE to the SE. The SE is the right place for this since there getsockname(2) fetches the local address and so the alternate one can be fetched there as well. With this the route pledge is no longer needed in the RDE and the pledge is now just "stdio recvfd". OK benno@
Diffstat (limited to 'usr.sbin/bgpd')
-rw-r--r--usr.sbin/bgpd/bgpd.h5
-rw-r--r--usr.sbin/bgpd/rde.c4
-rw-r--r--usr.sbin/bgpd/rde_peer.c108
-rw-r--r--usr.sbin/bgpd/session.c75
-rw-r--r--usr.sbin/bgpd/session.h3
-rw-r--r--usr.sbin/bgpd/util.c21
6 files changed, 104 insertions, 112 deletions
diff --git a/usr.sbin/bgpd/bgpd.h b/usr.sbin/bgpd/bgpd.h
index 12313bf4c16..f6be46f757f 100644
--- a/usr.sbin/bgpd/bgpd.h
+++ b/usr.sbin/bgpd/bgpd.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: bgpd.h,v 1.399 2020/01/24 05:44:05 claudio Exp $ */
+/* $OpenBSD: bgpd.h,v 1.400 2020/02/12 10:33:56 claudio Exp $ */
/*
* Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
@@ -660,7 +660,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;
diff --git a/usr.sbin/bgpd/rde.c b/usr.sbin/bgpd/rde.c
index f819f4c1947..0fb3c618b91 100644
--- a/usr.sbin/bgpd/rde.c
+++ b/usr.sbin/bgpd/rde.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: rde.c,v 1.500 2020/01/24 05:44:05 claudio Exp $ */
+/* $OpenBSD: rde.c,v 1.501 2020/02/12 10:33:56 claudio Exp $ */
/*
* Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
@@ -175,7 +175,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);
diff --git a/usr.sbin/bgpd/rde_peer.c b/usr.sbin/bgpd/rde_peer.c
index ce0662e51cb..c164cb05f66 100644
--- a/usr.sbin/bgpd/rde_peer.c
+++ b/usr.sbin/bgpd/rde_peer.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: rde_peer.c,v 1.4 2020/01/24 05:44:05 claudio Exp $ */
+/* $OpenBSD: rde_peer.c,v 1.5 2020/02/12 10:33:56 claudio Exp $ */
/*
* Copyright (c) 2019 Claudio Jeker <claudio@openbsd.org>
@@ -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.
*/
@@ -425,13 +327,11 @@ peer_up(struct rde_peer *peer, struct session_up *sup)
}
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;
for (i = 0; i < AID_MAX; i++) {
diff --git a/usr.sbin/bgpd/session.c b/usr.sbin/bgpd/session.c
index 56a252196e5..6902a5ff0ee 100644
--- a/usr.sbin/bgpd/session.c
+++ b/usr.sbin/bgpd/session.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: session.c,v 1.398 2020/01/24 05:44:05 claudio Exp $ */
+/* $OpenBSD: session.c,v 1.399 2020/02/12 10:33:56 claudio Exp $ */
/*
* Copyright (c) 2003, 2004, 2005 Henning Brauer <henning@openbsd.org>
@@ -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>
@@ -1191,6 +1192,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)
{
@@ -1201,6 +1265,7 @@ session_tcp_established(struct peer *peer)
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");
@@ -3080,7 +3145,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;
diff --git a/usr.sbin/bgpd/session.h b/usr.sbin/bgpd/session.h
index 4448a2af79c..522e1c5f863 100644
--- a/usr.sbin/bgpd/session.h
+++ b/usr.sbin/bgpd/session.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: session.h,v 1.144 2020/01/24 05:44:05 claudio Exp $ */
+/* $OpenBSD: session.h,v 1.145 2020/02/12 10:33:56 claudio Exp $ */
/*
* Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
@@ -214,6 +214,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;
diff --git a/usr.sbin/bgpd/util.c b/usr.sbin/bgpd/util.c
index 44e6cd151fd..778083958d9 100644
--- a/usr.sbin/bgpd/util.c
+++ b/usr.sbin/bgpd/util.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: util.c,v 1.51 2019/07/03 03:24:02 deraadt Exp $ */
+/* $OpenBSD: util.c,v 1.52 2020/02/12 10:33:56 claudio Exp $ */
/*
* Copyright (c) 2006 Claudio Jeker <claudio@openbsd.org>
@@ -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_addr *addr, u_int16_t *port)
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);