diff options
author | David Lamparter <equinox@diac24.net> | 2010-02-02 20:18:23 +0100 |
---|---|---|
committer | Denis Ovsienko <infrastation@yandex.ru> | 2011-11-21 18:23:24 +0400 |
commit | 5d3c53b9995dd9cbfa08edfcb03a2dcb47b170f4 (patch) | |
tree | 5183c572f3b81b649bb4f2195d7ad47231de16c7 /bgpd | |
parent | 188506f4c618626e3da2c1e657100315f49664ee (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.
Diffstat (limited to 'bgpd')
-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 3355316c..ecad25b0 100644 --- a/bgpd/bgp_network.c +++ b/bgpd/bgp_network.c @@ -258,21 +258,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. */ @@ -280,7 +296,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) @@ -289,11 +305,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. */ |