Claudio Jeker(cje...@diehard.n-r-g.com) on 2023.10.16 09:23:12 +0200: > This diff fixes a few more things when establishing connections with > link-local IPv6 addresses. In get_alternate_addr() the interface scope > of the connection is recovered and then passed to the RDE. The RDE can > then use this scope id to insert link-local addresses with the correct > scope.
looks good. > I built a regress test for this which passes with this diff. > Now probably more is needed because IPv6 link-local addresses are a gift > that keep on giving. One thing to implement on top of this is template > matching for link local -- which allows to auto-configure sessions more > easily. This will probably follow soon. it would be nice if that could match just on interfaces. As in "neighbor <interface>", with some syntactic sugar so its clear this is for link-local? > -- > :wq Claudio > > Index: bgpd.h > =================================================================== > RCS file: /cvs/src/usr.sbin/bgpd/bgpd.h,v > retrieving revision 1.477 > diff -u -p -r1.477 bgpd.h > --- bgpd.h 30 Aug 2023 08:16:28 -0000 1.477 > +++ bgpd.h 9 Oct 2023 13:50:36 -0000 > @@ -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 *, ...) > Index: kroute.c > =================================================================== > RCS file: /cvs/src/usr.sbin/bgpd/kroute.c,v > retrieving revision 1.305 > diff -u -p -r1.305 kroute.c > --- kroute.c 1 Jun 2023 09:47:34 -0000 1.305 > +++ kroute.c 9 Oct 2023 13:54:25 -0000 > @@ -168,8 +168,6 @@ struct kroute6 *kroute6_match(struct kta > 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_ > 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 *rt > 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 *rt > 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 > Index: logmsg.c > =================================================================== > RCS file: /cvs/src/usr.sbin/bgpd/logmsg.c,v > retrieving revision 1.9 > diff -u -p -r1.9 logmsg.c > --- logmsg.c 24 Aug 2022 17:14:02 -0000 1.9 > +++ logmsg.c 14 Oct 2023 09:49:36 -0000 > @@ -60,55 +60,54 @@ log_fmt_peer(const struct peer_config *p > void > log_peer_info(const struct peer_config *peer, const char *emsg, ...) > { > - char *p, *nfmt; > + char *p, *msg; > va_list ap; > > p = log_fmt_peer(peer); > - if (asprintf(&nfmt, "%s: %s", p, emsg) == -1) > - fatal(NULL); > va_start(ap, emsg); > - vlog(LOG_INFO, nfmt, ap); > + if (vasprintf(&msg, emsg, ap) == -1) > + fatal(NULL); > va_end(ap); > + logit(LOG_INFO, "%s: %s", p, msg); > + free(msg); > free(p); > - free(nfmt); > } > > void > log_peer_warn(const struct peer_config *peer, const char *emsg, ...) > { > - char *p, *nfmt; > + char *p, *msg; > va_list ap; > + int saved_errno = errno; > > p = log_fmt_peer(peer); > if (emsg == NULL) { > - if (asprintf(&nfmt, "%s: %s", p, strerror(errno)) == -1) > - fatal(NULL); > + logit(LOG_ERR, "%s: %s", p, strerror(saved_errno)); > } else { > - if (asprintf(&nfmt, "%s: %s: %s", p, emsg, strerror(errno)) == > - -1) > + va_start(ap, emsg); > + if (vasprintf(&msg, emsg, ap) == -1) > fatal(NULL); > + va_end(ap); > + logit(LOG_ERR, "%s: %s: %s", p, msg, strerror(saved_errno)); > + free(msg); > } > - va_start(ap, emsg); > - vlog(LOG_ERR, nfmt, ap); > - va_end(ap); > free(p); > - free(nfmt); > } > > void > log_peer_warnx(const struct peer_config *peer, const char *emsg, ...) > { > - char *p, *nfmt; > + char *p, *msg; > va_list ap; > > p = log_fmt_peer(peer); > - if (asprintf(&nfmt, "%s: %s", p, emsg) == -1) > - fatal(NULL); > va_start(ap, emsg); > - vlog(LOG_ERR, nfmt, ap); > + if (vasprintf(&msg, emsg, ap) == -1) > + fatal(NULL); > va_end(ap); > + logit(LOG_ERR, "%s: %s", p, msg); > + free(msg); > free(p); > - free(nfmt); > } > > void > Index: rde.c > =================================================================== > RCS file: /cvs/src/usr.sbin/bgpd/rde.c,v > retrieving revision 1.610 > diff -u -p -r1.610 rde.c > --- rde.c 16 Aug 2023 08:26:35 -0000 1.610 > +++ rde.c 9 Oct 2023 14:16:23 -0000 > @@ -59,7 +59,7 @@ int rde_attr_parse(u_char *, uint16_t, > 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 *pee > /* 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, i > > 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_ > * 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_ > * 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_ > 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); > } > > Index: rde.h > =================================================================== > RCS file: /cvs/src/usr.sbin/bgpd/rde.h,v > retrieving revision 1.296 > diff -u -p -r1.296 rde.h > --- rde.h 16 Aug 2023 08:26:35 -0000 1.296 > +++ rde.h 9 Oct 2023 07:26:49 -0000 > @@ -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; > Index: rde_peer.c > =================================================================== > RCS file: /cvs/src/usr.sbin/bgpd/rde_peer.c,v > retrieving revision 1.32 > diff -u -p -r1.32 rde_peer.c > --- rde_peer.c 19 Apr 2023 13:23:33 -0000 1.32 > +++ rde_peer.c 26 Apr 2023 14:04:35 -0000 > @@ -430,6 +430,7 @@ peer_up(struct rde_peer *peer, struct se > 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 */ > Index: rde_rib.c > =================================================================== > RCS file: /cvs/src/usr.sbin/bgpd/rde_rib.c,v > retrieving revision 1.260 > diff -u -p -r1.260 rde_rib.c > --- rde_rib.c 23 Apr 2023 11:39:10 -0000 1.260 > +++ rde_rib.c 9 Oct 2023 14:05:30 -0000 > @@ -1910,7 +1910,7 @@ nexthop_compare(struct nexthop *na, stru > case AID_INET6: > return (memcmp(&a->v6, &b->v6, sizeof(struct in6_addr))); > default: > - fatalx("nexthop_cmp: unknown af"); > + fatalx("nexthop_cmp: unknown aid %s", aid2str(a->aid)); > } > return (-1); > } > Index: session.c > =================================================================== > RCS file: /cvs/src/usr.sbin/bgpd/session.c,v > retrieving revision 1.448 > diff -u -p -r1.448 session.c > --- session.c 9 Oct 2023 07:11:20 -0000 1.448 > +++ session.c 16 Oct 2023 07:13:58 -0000 > @@ -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, > } > } > 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, > } > 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 *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"); > 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; > Index: session.h > =================================================================== > RCS file: /cvs/src/usr.sbin/bgpd/session.h,v > retrieving revision 1.162 > diff -u -p -r1.162 session.h > --- session.h 28 Mar 2023 12:15:23 -0000 1.162 > +++ session.h 30 Mar 2023 07:17:19 -0000 > @@ -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; >