summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--usr.sbin/bgpd/bgpd.h4
-rw-r--r--usr.sbin/bgpd/kroute.c37
-rw-r--r--usr.sbin/bgpd/rde.c48
-rw-r--r--usr.sbin/bgpd/rde.h3
-rw-r--r--usr.sbin/bgpd/rde_peer.c3
-rw-r--r--usr.sbin/bgpd/rde_rib.c4
-rw-r--r--usr.sbin/bgpd/session.c62
-rw-r--r--usr.sbin/bgpd/session.h3
8 files changed, 118 insertions, 46 deletions
diff --git a/usr.sbin/bgpd/bgpd.h b/usr.sbin/bgpd/bgpd.h
index c19e2acfcc2..79d3c0638b0 100644
--- a/usr.sbin/bgpd/bgpd.h
+++ b/usr.sbin/bgpd/bgpd.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: bgpd.h,v 1.477 2023/08/30 08:16:28 claudio Exp $ */
+/* $OpenBSD: bgpd.h,v 1.478 2023/10/16 10:25:45 claudio Exp $ */
/*
* Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
@@ -796,6 +796,7 @@ struct session_up {
struct bgpd_addr remote_addr;
struct capabilities capa;
uint32_t remote_bgpid;
+ unsigned int if_scope;
uint16_t short_as;
};
@@ -1439,6 +1440,7 @@ void kr_ifinfo(char *);
void kr_net_reload(u_int, uint64_t, struct network_head *);
int kr_reload(void);
int get_mpe_config(const char *, u_int *, u_int *);
+uint8_t mask2prefixlen(sa_family_t, struct sockaddr *);
/* log.c */
void log_peer_info(const struct peer_config *, const char *, ...)
diff --git a/usr.sbin/bgpd/kroute.c b/usr.sbin/bgpd/kroute.c
index ac55f1033da..69c09c67041 100644
--- a/usr.sbin/bgpd/kroute.c
+++ b/usr.sbin/bgpd/kroute.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: kroute.c,v 1.305 2023/06/01 09:47:34 claudio Exp $ */
+/* $OpenBSD: kroute.c,v 1.306 2023/10/16 10:25:45 claudio Exp $ */
/*
* Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
@@ -168,8 +168,6 @@ struct kroute6 *kroute6_match(struct ktable *, struct bgpd_addr *, int);
void kroute_detach_nexthop(struct ktable *, struct knexthop *);
uint8_t prefixlen_classful(in_addr_t);
-uint8_t mask2prefixlen(in_addr_t);
-uint8_t mask2prefixlen6(struct sockaddr_in6 *);
uint64_t ift2ifm(uint8_t);
const char *get_media_descr(uint64_t);
const char *get_linkstate(uint8_t, int);
@@ -2419,21 +2417,28 @@ prefixlen_classful(in_addr_t ina)
return (8);
}
-uint8_t
-mask2prefixlen(in_addr_t ina)
+static uint8_t
+mask2prefixlen4(struct sockaddr_in *sa_in)
{
+ in_addr_t ina;
+
+ if (sa_in->sin_len == 0)
+ return (0);
+ ina = sa_in->sin_addr.s_addr;
if (ina == 0)
return (0);
else
return (33 - ffs(ntohl(ina)));
}
-uint8_t
+static uint8_t
mask2prefixlen6(struct sockaddr_in6 *sa_in6)
{
uint8_t *ap, *ep;
u_int l = 0;
+ if (sa_in6->sin6_len == 0)
+ return (0);
/*
* sin6_len is the size of the sockaddr so subtract the offset of
* the possibly truncated sin6_addr struct.
@@ -2480,6 +2485,19 @@ mask2prefixlen6(struct sockaddr_in6 *sa_in6)
return (l);
}
+uint8_t
+mask2prefixlen(sa_family_t af, struct sockaddr *mask)
+{
+ switch (af) {
+ case AF_INET:
+ return mask2prefixlen4((struct sockaddr_in *)mask);
+ case AF_INET6:
+ return mask2prefixlen6((struct sockaddr_in6 *)mask);
+ default:
+ fatalx("%s: unsupported af", __func__);
+ }
+}
+
const struct if_status_description
if_status_descriptions[] = LINK_STATE_DESCRIPTIONS;
const struct ifmedia_description
@@ -3079,9 +3097,7 @@ dispatch_rtmsg_addr(struct rt_msghdr *rtm, struct kroute_full *kf)
case AF_INET:
sa_in = (struct sockaddr_in *)rti_info[RTAX_NETMASK];
if (sa_in != NULL) {
- if (sa_in->sin_len != 0)
- kf->prefixlen =
- mask2prefixlen(sa_in->sin_addr.s_addr);
+ kf->prefixlen = mask2prefixlen4(sa_in);
} else if (rtm->rtm_flags & RTF_HOST)
kf->prefixlen = 32;
else
@@ -3091,8 +3107,7 @@ dispatch_rtmsg_addr(struct rt_msghdr *rtm, struct kroute_full *kf)
case AF_INET6:
sa_in6 = (struct sockaddr_in6 *)rti_info[RTAX_NETMASK];
if (sa_in6 != NULL) {
- if (sa_in6->sin6_len != 0)
- kf->prefixlen = mask2prefixlen6(sa_in6);
+ kf->prefixlen = mask2prefixlen6(sa_in6);
} else if (rtm->rtm_flags & RTF_HOST)
kf->prefixlen = 128;
else
diff --git a/usr.sbin/bgpd/rde.c b/usr.sbin/bgpd/rde.c
index dc6a318f747..659622bb065 100644
--- a/usr.sbin/bgpd/rde.c
+++ b/usr.sbin/bgpd/rde.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: rde.c,v 1.610 2023/08/16 08:26:35 claudio Exp $ */
+/* $OpenBSD: rde.c,v 1.611 2023/10/16 10:25:45 claudio Exp $ */
/*
* Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
@@ -59,7 +59,7 @@ int rde_attr_parse(u_char *, uint16_t, struct rde_peer *,
int rde_attr_add(struct filterstate *, u_char *, uint16_t);
uint8_t rde_attr_missing(struct rde_aspath *, int, uint16_t);
int rde_get_mp_nexthop(u_char *, uint16_t, uint8_t,
- struct filterstate *);
+ struct rde_peer *, struct filterstate *);
void rde_as4byte_fixup(struct rde_peer *, struct rde_aspath *);
uint8_t rde_aspa_validity(struct rde_peer *, struct rde_aspath *,
uint8_t);
@@ -1797,7 +1797,8 @@ rde_update_dispatch(struct rde_peer *peer, struct imsg *imsg)
/* unlock the previously locked nexthop, it is no longer used */
nexthop_unref(state.nexthop);
state.nexthop = NULL;
- if ((pos = rde_get_mp_nexthop(mpp, mplen, aid, &state)) == -1) {
+ if ((pos = rde_get_mp_nexthop(mpp, mplen, aid, peer,
+ &state)) == -1) {
log_peer_warnx(&peer->conf, "bad nlri nexthop");
rde_update_err(peer, ERR_UPDATE, ERR_UPD_OPTATTR,
mpa.reach, mpa.reach_len);
@@ -2482,7 +2483,7 @@ rde_attr_missing(struct rde_aspath *a, int ebgp, uint16_t nlrilen)
int
rde_get_mp_nexthop(u_char *data, uint16_t len, uint8_t aid,
- struct filterstate *state)
+ struct rde_peer *peer, struct filterstate *state)
{
struct bgpd_addr nexthop;
uint8_t totlen, nhlen;
@@ -2509,12 +2510,22 @@ rde_get_mp_nexthop(u_char *data, uint16_t len, uint8_t aid,
* traffic.
*/
if (nhlen != 16 && nhlen != 32) {
- log_warnx("bad %s nexthop, bad size %d", aid2str(aid),
- nhlen);
+ log_peer_warnx(&peer->conf, "bad %s nexthop, "
+ "bad size %d", aid2str(aid), nhlen);
return (-1);
}
memcpy(&nexthop.v6.s6_addr, data, 16);
nexthop.aid = AID_INET6;
+ if (IN6_IS_ADDR_LINKLOCAL(&nexthop.v6)) {
+ if (peer->local_if_scope != 0) {
+ nexthop.scope_id = peer->local_if_scope;
+ } else {
+ log_peer_warnx(&peer->conf,
+ "unexpected link-local nexthop: %s",
+ log_addr(&nexthop));
+ return (-1);
+ }
+ }
break;
case AID_VPN_IPv4:
/*
@@ -2531,8 +2542,8 @@ rde_get_mp_nexthop(u_char *data, uint16_t len, uint8_t aid,
* AID_VPN_IPv4 in nexthop and kroute.
*/
if (nhlen != 12) {
- log_warnx("bad %s nexthop, bad size %d", aid2str(aid),
- nhlen);
+ log_peer_warnx(&peer->conf, "bad %s nexthop, "
+ "bad size %d", aid2str(aid), nhlen);
return (-1);
}
nexthop.aid = AID_INET;
@@ -2541,26 +2552,37 @@ rde_get_mp_nexthop(u_char *data, uint16_t len, uint8_t aid,
break;
case AID_VPN_IPv6:
if (nhlen != 24) {
- log_warnx("bad %s nexthop, bad size %d", aid2str(aid),
- nhlen);
+ log_peer_warnx(&peer->conf, "bad %s nexthop, "
+ "bad size %d", aid2str(aid), nhlen);
return (-1);
}
memcpy(&nexthop.v6, data + sizeof(uint64_t),
sizeof(nexthop.v6));
nexthop.aid = AID_INET6;
+ if (IN6_IS_ADDR_LINKLOCAL(&nexthop.v6)) {
+ if (peer->local_if_scope != 0) {
+ nexthop.scope_id = peer->local_if_scope;
+ } else {
+ log_peer_warnx(&peer->conf,
+ "unexpected link-local nexthop: %s",
+ log_addr(&nexthop));
+ return (-1);
+ }
+ }
break;
case AID_FLOWSPECv4:
case AID_FLOWSPECv6:
/* nexthop must be 0 and ignored for flowspec */
if (nhlen != 0) {
- log_warnx("bad %s nexthop, bad size %d", aid2str(aid),
- nhlen);
+ log_peer_warnx(&peer->conf, "bad %s nexthop, "
+ "bad size %d", aid2str(aid), nhlen);
return (-1);
}
/* also ignore reserved (old SNPA) field as per RFC4760 */
return (totlen + 1);
default:
- log_warnx("bad multiprotocol nexthop, bad AID");
+ log_peer_warnx(&peer->conf, "bad multiprotocol nexthop, "
+ "bad AID");
return (-1);
}
diff --git a/usr.sbin/bgpd/rde.h b/usr.sbin/bgpd/rde.h
index c700aca75a3..ee8987cce1c 100644
--- a/usr.sbin/bgpd/rde.h
+++ b/usr.sbin/bgpd/rde.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: rde.h,v 1.296 2023/08/16 08:26:35 claudio Exp $ */
+/* $OpenBSD: rde.h,v 1.297 2023/10/16 10:25:46 claudio Exp $ */
/*
* Copyright (c) 2003, 2004 Claudio Jeker <claudio@openbsd.org> and
@@ -92,6 +92,7 @@ struct rde_peer {
time_t staletime[AID_MAX];
uint32_t remote_bgpid; /* host byte order! */
uint32_t path_id_tx;
+ unsigned int local_if_scope;
enum peer_state state;
enum export_type export_type;
enum role role;
diff --git a/usr.sbin/bgpd/rde_peer.c b/usr.sbin/bgpd/rde_peer.c
index bbf0a9e0ec9..fe67303fd42 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.32 2023/04/19 13:23:33 claudio Exp $ */
+/* $OpenBSD: rde_peer.c,v 1.33 2023/10/16 10:25:46 claudio Exp $ */
/*
* Copyright (c) 2019 Claudio Jeker <claudio@openbsd.org>
@@ -430,6 +430,7 @@ peer_up(struct rde_peer *peer, struct session_up *sup)
peer->remote_addr = sup->remote_addr;
peer->local_v4_addr = sup->local_v4_addr;
peer->local_v6_addr = sup->local_v6_addr;
+ peer->local_if_scope = sup->if_scope;
memcpy(&peer->capa, &sup->capa, sizeof(peer->capa));
/* clear eor markers depending on GR flags */
diff --git a/usr.sbin/bgpd/rde_rib.c b/usr.sbin/bgpd/rde_rib.c
index cd56b20300b..04f7e63d03b 100644
--- a/usr.sbin/bgpd/rde_rib.c
+++ b/usr.sbin/bgpd/rde_rib.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: rde_rib.c,v 1.260 2023/04/23 11:39:10 claudio Exp $ */
+/* $OpenBSD: rde_rib.c,v 1.261 2023/10/16 10:25:46 claudio Exp $ */
/*
* Copyright (c) 2003, 2004 Claudio Jeker <claudio@openbsd.org>
@@ -1910,7 +1910,7 @@ nexthop_compare(struct nexthop *na, struct nexthop *nb)
case AID_INET6:
return (memcmp(&a->v6, &b->v6, sizeof(struct in6_addr)));
default:
- fatalx("nexthop_cmp: unknown af");
+ fatalx("nexthop_cmp: %s is unsupported", aid2str(a->aid));
}
return (-1);
}
diff --git a/usr.sbin/bgpd/session.c b/usr.sbin/bgpd/session.c
index 30d40153643..ed809c4ce6b 100644
--- a/usr.sbin/bgpd/session.c
+++ b/usr.sbin/bgpd/session.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: session.c,v 1.448 2023/10/09 07:11:20 claudio Exp $ */
+/* $OpenBSD: session.c,v 1.449 2023/10/16 10:25:46 claudio Exp $ */
/*
* Copyright (c) 2003, 2004, 2005 Henning Brauer <henning@openbsd.org>
@@ -1202,37 +1202,64 @@ session_setup_socket(struct peer *p)
return (0);
}
-/* compare two sockaddrs by converting them into bgpd_addr */
+/*
+ * compare the bgpd_addr with the sockaddr by converting the latter into
+ * a bgpd_addr. Return true if the two are equal, including any scope
+ */
static int
-sa_equal(struct sockaddr *a, struct sockaddr *b)
+sa_equal(struct bgpd_addr *ba, struct sockaddr *b)
{
- struct bgpd_addr ba, bb;
+ struct bgpd_addr bb;
- sa2addr(a, &ba, NULL);
sa2addr(b, &bb, NULL);
-
- return (memcmp(&ba, &bb, sizeof(ba)) == 0);
+ return (memcmp(ba, &bb, sizeof(*ba)) == 0);
}
static void
-get_alternate_addr(struct sockaddr *sa, struct bgpd_addr *alt)
+get_alternate_addr(struct bgpd_addr *local, struct bgpd_addr *remote,
+ struct bgpd_addr *alt, unsigned int *scope)
{
struct ifaddrs *ifap, *ifa, *match;
+ int connected = 0;
+ u_int8_t plen;
if (getifaddrs(&ifap) == -1)
fatal("getifaddrs");
- for (match = ifap; match != NULL; match = match->ifa_next)
- if (match->ifa_addr != NULL && sa_equal(sa, match->ifa_addr))
+ for (match = ifap; match != NULL; match = match->ifa_next) {
+ if (match->ifa_addr == NULL)
+ continue;
+ if (match->ifa_addr->sa_family != AF_INET &&
+ match->ifa_addr->sa_family != AF_INET6)
+ continue;
+ if (sa_equal(local, match->ifa_addr)) {
+ if (match->ifa_flags & IFF_POINTOPOINT &&
+ match->ifa_dstaddr) {
+ if (sa_equal(remote, match->ifa_dstaddr))
+ connected = 1;
+ } else if (match->ifa_netmask) {
+ plen = mask2prefixlen(
+ match->ifa_addr->sa_family,
+ match->ifa_netmask);
+ if (plen != 0xff &&
+ prefix_compare(local, remote, plen) == 0)
+ connected = 1;
+ }
break;
+ }
+ }
if (match == NULL) {
log_warnx("%s: local address not found", __func__);
return;
}
+ if (connected)
+ *scope = if_nametoindex(match->ifa_name);
+ else
+ *scope = 0;
- switch (sa->sa_family) {
- case AF_INET6:
+ switch (local->aid) {
+ case AID_INET6:
for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next) {
if (ifa->ifa_addr != NULL &&
ifa->ifa_addr->sa_family == AF_INET &&
@@ -1242,7 +1269,7 @@ get_alternate_addr(struct sockaddr *sa, struct bgpd_addr *alt)
}
}
break;
- case AF_INET:
+ case AID_INET:
for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next) {
if (ifa->ifa_addr != NULL &&
ifa->ifa_addr->sa_family == AF_INET6 &&
@@ -1260,8 +1287,8 @@ get_alternate_addr(struct sockaddr *sa, struct bgpd_addr *alt)
}
break;
default:
- log_warnx("%s: unsupported address family %d", __func__,
- sa->sa_family);
+ log_warnx("%s: unsupported address family %s", __func__,
+ aid2str(local->aid));
break;
}
@@ -1278,11 +1305,13 @@ 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");
sa2addr((struct sockaddr *)&ss, &peer->remote, &peer->remote_port);
+
+ get_alternate_addr(&peer->local, &peer->remote, &peer->local_alt,
+ &peer->if_scope);
}
void
@@ -3546,6 +3575,7 @@ session_up(struct peer *p)
sup.local_v4_addr = p->local_alt;
}
sup.remote_addr = p->remote;
+ sup.if_scope = p->if_scope;
sup.remote_bgpid = p->remote_bgpid;
sup.short_as = p->short_as;
diff --git a/usr.sbin/bgpd/session.h b/usr.sbin/bgpd/session.h
index 65e96d6c87f..9c0969d6655 100644
--- a/usr.sbin/bgpd/session.h
+++ b/usr.sbin/bgpd/session.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: session.h,v 1.162 2023/03/28 12:15:23 claudio Exp $ */
+/* $OpenBSD: session.h,v 1.163 2023/10/16 10:25:46 claudio Exp $ */
/*
* Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
@@ -240,6 +240,7 @@ struct peer {
int lasterr;
u_int errcnt;
u_int IdleHoldTime;
+ unsigned int if_scope; /* interface scope for IPv6 */
uint32_t remote_bgpid;
enum session_state state;
enum session_state prev_state;