diff options
author | David Lamparter <equinox@diac24.net> | 2010-02-02 20:18:23 +0100 |
---|---|---|
committer | David Lamparter <equinox@diac24.net> | 2010-02-03 05:01:52 +0100 |
commit | ee3ec5a6ef3bfc1774ca429167cb159a92972061 (patch) | |
tree | adf000272cf14ff506b256262ce192e4b88e8255 /bgpd | |
parent | d8e181cbcf3b017d1cc97e4b85f2d3204a1cbc43 (diff) | |
download | quagga-ee3ec5a6ef3bfc1774ca429167cb159a92972061.tar.bz2 quagga-ee3ec5a6ef3bfc1774ca429167cb159a92972061.tar.xz |
bgpd: bug #537: find proper source address for interface update-source
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 9e3427d2..bc824138 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. */ |