diff options
-rw-r--r-- | usr.sbin/bgpd/bgpd.h | 4 | ||||
-rw-r--r-- | usr.sbin/bgpd/kroute.c | 37 | ||||
-rw-r--r-- | usr.sbin/bgpd/rde.c | 48 | ||||
-rw-r--r-- | usr.sbin/bgpd/rde.h | 3 | ||||
-rw-r--r-- | usr.sbin/bgpd/rde_peer.c | 3 | ||||
-rw-r--r-- | usr.sbin/bgpd/rde_rib.c | 4 | ||||
-rw-r--r-- | usr.sbin/bgpd/session.c | 62 | ||||
-rw-r--r-- | usr.sbin/bgpd/session.h | 3 |
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; |