diff options
author | David Lamparter <equinox@diac24.net> | 2010-02-02 20:18:23 +0100 |
---|---|---|
committer | Denis Ovsienko <infrastation@yandex.ru> | 2011-11-21 19:41:59 +0400 |
commit | 1727d2e2b939c8670d0f0e0d1a0e5eb0a8be2135 (patch) | |
tree | 3bdfda661f96113d61eae25059608d468a8ea4cc | |
parent | 17e52061bacec93e84324b23382e5ec61e1f16d0 (diff) |
bgpd: fix update-source for IPv6 (BZ#548)
if update-source was given as interface name, bgpd was unconditionally
trying to bind to an IPv4 address from that interface.
change function to find the best-matching (number of address bits)
same-family address on the interface.
-rw-r--r-- | bgpd/bgp_network.c | 39 |
1 files changed, 27 insertions, 12 deletions
diff --git a/bgpd/bgp_network.c b/bgpd/bgp_network.c index 52c72b67..b9cb6223 100644 --- a/bgpd/bgp_network.c +++ b/bgpd/bgp_network.c @@ -263,21 +263,37 @@ bgp_bind_address (int sock, struct in_addr *addr) return 0; } -static struct in_addr * -bgp_update_address (struct interface *ifp) +static int +bgp_update_address (struct interface *ifp, const union sockunion *dst, + union sockunion *addr) { - struct prefix_ipv4 *p; + struct prefix *p, *sel, *d; struct connected *connected; struct listnode *node; + int common; + + d = sockunion2hostprefix (dst); + sel = NULL; + common = -1; for (ALL_LIST_ELEMENTS_RO (ifp->connected, node, connected)) { - p = (struct prefix_ipv4 *) connected->address; - - if (p->family == AF_INET) - return &p->prefix; + p = connected->address; + if (p->family != d->family) + continue; + if (prefix_common_bits (p, d) > common) + { + sel = p; + common = prefix_common_bits (sel, d); + } } - return NULL; + + prefix_free (d); + if (!sel) + return 1; + + prefix2sockunion (sel, addr); + return 0; } /* Update source selection. */ @@ -285,7 +301,7 @@ static void bgp_update_source (struct peer *peer) { struct interface *ifp; - struct in_addr *addr; + union sockunion addr; /* Source is specified with interface name. */ if (peer->update_if) @@ -294,11 +310,10 @@ bgp_update_source (struct peer *peer) if (! ifp) return; - addr = bgp_update_address (ifp); - if (! addr) + if (bgp_update_address (ifp, &peer->su, &addr)) return; - bgp_bind_address (peer->fd, addr); + sockunion_bind (peer->fd, &addr, 0, &addr); } /* Source is specified with IP address. */ |