From 1711291ee4649af89c1c0ad75a8750b139d1a5ae Mon Sep 17 00:00:00 2001 From: Claudio Jeker Date: Thu, 11 Nov 2004 13:06:46 +0000 Subject: Store the local v4 and v6 address of a session. For IPv4 sessions the first IPv6 address with global scope of the interface used by the session is used. In any case the local endpoint of the session is used for one of the two no matter what scope. OK henning@ --- usr.sbin/bgpd/mrt.c | 6 +-- usr.sbin/bgpd/rde.c | 101 ++++++++++++++++++++++++++++++++++++++++++++- usr.sbin/bgpd/rde.h | 5 ++- usr.sbin/bgpd/rde_update.c | 14 +++---- 4 files changed, 112 insertions(+), 14 deletions(-) diff --git a/usr.sbin/bgpd/mrt.c b/usr.sbin/bgpd/mrt.c index b9db71fca52..6782b895727 100644 --- a/usr.sbin/bgpd/mrt.c +++ b/usr.sbin/bgpd/mrt.c @@ -1,4 +1,4 @@ -/* $OpenBSD: mrt.c,v 1.45 2004/09/16 17:36:29 henning Exp $ */ +/* $OpenBSD: mrt.c,v 1.46 2004/11/11 13:06:44 claudio Exp $ */ /* * Copyright (c) 2003, 2004 Claudio Jeker @@ -350,12 +350,12 @@ mrt_dump_entry_mp(struct mrt *mrt, struct prefix *p, u_int16_t snum, switch (af) { case AF_INET: DUMP_SHORT(buf, AFI_IPv4); - DUMP_NLONG(buf, peer->local_addr.v4.s_addr); + DUMP_NLONG(buf, peer->local_v4_addr.v4.s_addr); DUMP_NLONG(buf, peer->remote_addr.v4.s_addr); break; case AF_INET6: DUMP_SHORT(buf, AFI_IPv6); - if (buf_add(buf, &peer->local_addr.v6, + if (buf_add(buf, &peer->local_v6_addr.v6, sizeof(struct in6_addr)) == -1 || buf_add(buf, &peer->remote_addr.v6, sizeof(struct in6_addr)) == -1) { diff --git a/usr.sbin/bgpd/rde.c b/usr.sbin/bgpd/rde.c index 03674178b89..167f7673f1d 100644 --- a/usr.sbin/bgpd/rde.c +++ b/usr.sbin/bgpd/rde.c @@ -1,4 +1,4 @@ -/* $OpenBSD: rde.c,v 1.146 2004/11/11 10:35:15 claudio Exp $ */ +/* $OpenBSD: rde.c,v 1.147 2004/11/11 13:06:45 claudio Exp $ */ /* * Copyright (c) 2003, 2004 Henning Brauer @@ -17,8 +17,10 @@ */ #include +#include #include +#include #include #include #include @@ -68,6 +70,7 @@ void rde_update_queue_runner(void); void peer_init(u_int32_t); void peer_shutdown(void); +void peer_localaddrs(struct rde_peer *, struct bgpd_addr *); struct rde_peer *peer_add(u_int32_t, struct peer_config *); void peer_remove(struct rde_peer *); struct rde_peer *peer_get(u_int32_t); @@ -82,6 +85,7 @@ void network_dump_upcall(struct pt_entry *, void *); void network_flush(int); void rde_shutdown(void); +int sa_cmp(struct bgpd_addr *, struct sockaddr *); volatile sig_atomic_t rde_quit = 0; struct bgpd_config *conf, *nconf; @@ -1836,6 +1840,68 @@ peer_remove(struct rde_peer *peer) free(peer); } +void +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) + fatalx("peer_localaddrs: local address not found"); + + 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; + peer->local_v4_addr.af = AF_INET; + peer->local_v4_addr.v4.s_addr = + ((struct sockaddr_in *)ifa->ifa_addr)-> + sin_addr.s_addr; + 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; + } + peer->local_v6_addr.af = AF_INET6; + memcpy(&peer->local_v6_addr.v6, + &((struct sockaddr_in6 *)ifa->ifa_addr)-> + sin6_addr, sizeof(struct in6_addr)); + peer->local_v6_addr.scope_id = + ((struct sockaddr_in6 *)ifa->ifa_addr)-> + sin6_scope_id; + break; + } + } + + freeifaddrs(ifap); +} + void peer_up(u_int32_t id, struct session_up *sup) { @@ -1850,9 +1916,11 @@ peer_up(u_int32_t id, struct session_up *sup) if (peer->state != PEER_DOWN && peer->state != PEER_NONE) fatalx("peer_up: bad state"); peer->remote_bgpid = ntohl(sup->remote_bgpid); - memcpy(&peer->local_addr, &sup->local_addr, sizeof(peer->local_addr)); memcpy(&peer->remote_addr, &sup->remote_addr, sizeof(peer->remote_addr)); + + peer_localaddrs(peer, &sup->local_addr); + peer->state = PEER_UP; up_init(peer); @@ -2082,3 +2150,32 @@ rde_shutdown(void) free(mrt); } +int +sa_cmp(struct bgpd_addr *a, struct sockaddr *b) +{ + struct sockaddr_in *in_b; + struct sockaddr_in6 *in6_b; + + if (a->af != b->sa_family) + return (1); + + switch (a->af) { + 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; + if (bcmp(&a->v6, &in6_b->sin6_addr, + sizeof(struct in6_addr))) + return (1); + break; + default: + fatal("king bula sez: unknown address family"); + /* not reached */ + } + + return (0); +} + diff --git a/usr.sbin/bgpd/rde.h b/usr.sbin/bgpd/rde.h index 4561e4cd8b3..c8d0fc813f0 100644 --- a/usr.sbin/bgpd/rde.h +++ b/usr.sbin/bgpd/rde.h @@ -1,4 +1,4 @@ -/* $OpenBSD: rde.h,v 1.59 2004/11/11 10:35:15 claudio Exp $ */ +/* $OpenBSD: rde.h,v 1.60 2004/11/11 13:06:45 claudio Exp $ */ /* * Copyright (c) 2003, 2004 Claudio Jeker and @@ -54,7 +54,8 @@ struct rde_peer { u_int32_t prefix_cnt; u_int32_t remote_bgpid; struct bgpd_addr remote_addr; - struct bgpd_addr local_addr; + struct bgpd_addr local_v4_addr; + struct bgpd_addr local_v6_addr; u_int32_t up_pcnt; u_int32_t up_acnt; u_int32_t up_nlricnt; diff --git a/usr.sbin/bgpd/rde_update.c b/usr.sbin/bgpd/rde_update.c index 167580656d4..4f599c61acc 100644 --- a/usr.sbin/bgpd/rde_update.c +++ b/usr.sbin/bgpd/rde_update.c @@ -1,4 +1,4 @@ -/* $OpenBSD: rde_update.c,v 1.31 2004/09/28 12:09:31 claudio Exp $ */ +/* $OpenBSD: rde_update.c,v 1.32 2004/11/11 13:06:45 claudio Exp $ */ /* * Copyright (c) 2004 Claudio Jeker @@ -590,11 +590,11 @@ up_generate_attr(struct rde_peer *peer, struct update_attr *upa, /* nexthop, already network byte order */ if (peer->conf.ebgp == 0) { /* - * If directly connected use peer->local_addr + * If directly connected use peer->local_v4_addr * this is only true for announced networks. */ if (a->nexthop == NULL) - nexthop = peer->local_addr.v4.s_addr; + nexthop = peer->local_v4_addr.v4.s_addr; else if (a->nexthop->exit_nexthop.v4.s_addr == peer->remote_addr.v4.s_addr) /* @@ -602,7 +602,7 @@ up_generate_attr(struct rde_peer *peer, struct update_attr *upa, * the nexthop set the nexthop to our local address. * This reduces the risk of routing loops. */ - nexthop = peer->local_addr.v4.s_addr; + nexthop = peer->local_v4_addr.v4.s_addr; else nexthop = a->nexthop->exit_nexthop.v4.s_addr; } else if (peer->conf.distance == 1) { @@ -616,9 +616,9 @@ up_generate_attr(struct rde_peer *peer, struct update_attr *upa, /* nexthop and peer are in the same net */ nexthop = a->nexthop->exit_nexthop.v4.s_addr; else - nexthop = peer->local_addr.v4.s_addr; + nexthop = peer->local_v4_addr.v4.s_addr; } else - nexthop = peer->local_addr.v4.s_addr; + nexthop = peer->local_v4_addr.v4.s_addr; } else /* ebgp multihop */ /* @@ -626,7 +626,7 @@ up_generate_attr(struct rde_peer *peer, struct update_attr *upa, * NEXTHOP_CONNECTED set so it should be possible to unify the * two ebgp cases. But this is save and RFC compliant. */ - nexthop = peer->local_addr.v4.s_addr; + nexthop = peer->local_v4_addr.v4.s_addr; if ((r = attr_write(up_attr_buf + wlen, len, ATTR_WELL_KNOWN, ATTR_NEXTHOP, &nexthop, 4)) == -1) -- cgit v1.2.3