mirror of
https://git.proxmox.com/git/mirror_frr
synced 2025-08-15 03:27:25 +00:00
BGP: Fix MD5 authentication for unnumbered neighbors
Ticket: CM-6369 Reviewed By: CCR-3318 Testing Done: Manual testing of various password scenarios. This is a port of patch bgpd-unnumbered-nbr-fix-password.patch from 2.5-br. In the case of BGP unnumbered, the peer IP address is derived and not explicitly configured. If there is a password configured for the peer, it can be set on the listen socket only after the IP address has been derived and needs to be cleared when the IP address goes away.
This commit is contained in:
parent
57e9ee0a94
commit
89ca90fad9
@ -104,8 +104,8 @@ bgp_md5_set_connect (int socket, union sockunion *su, const char *password)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
static int
|
||||||
bgp_md5_set (struct peer *peer)
|
bgp_md5_set_password (struct peer *peer, const char *password)
|
||||||
{
|
{
|
||||||
struct listnode *node;
|
struct listnode *node;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
@ -117,13 +117,13 @@ bgp_md5_set (struct peer *peer)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Just set the password on the listen socket(s). Outbound connections
|
/* Set or unset the password on the listen socket(s). Outbound connections
|
||||||
* are taken care of in bgp_connect() below.
|
* are taken care of in bgp_connect() below.
|
||||||
*/
|
*/
|
||||||
for (ALL_LIST_ELEMENTS_RO(bm->listen_sockets, node, listener))
|
for (ALL_LIST_ELEMENTS_RO(bm->listen_sockets, node, listener))
|
||||||
if (listener->su.sa.sa_family == peer->su.sa.sa_family)
|
if (listener->su.sa.sa_family == peer->su.sa.sa_family)
|
||||||
{
|
{
|
||||||
ret = bgp_md5_set_socket (listener->fd, &peer->su, peer->password);
|
ret = bgp_md5_set_socket (listener->fd, &peer->su, password);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -133,6 +133,20 @@ bgp_md5_set (struct peer *peer)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
bgp_md5_set (struct peer *peer)
|
||||||
|
{
|
||||||
|
/* Set the password from listen socket. */
|
||||||
|
return bgp_md5_set_password (peer, peer->password);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
bgp_md5_unset (struct peer *peer)
|
||||||
|
{
|
||||||
|
/* Unset the password from listen socket. */
|
||||||
|
return bgp_md5_set_password (peer, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
/* Update BGP socket send buffer size */
|
/* Update BGP socket send buffer size */
|
||||||
static void
|
static void
|
||||||
bgp_update_sock_send_buffer_size (int fd)
|
bgp_update_sock_send_buffer_size (int fd)
|
||||||
|
@ -29,6 +29,7 @@ extern int bgp_connect (struct peer *);
|
|||||||
extern int bgp_getsockname (struct peer *);
|
extern int bgp_getsockname (struct peer *);
|
||||||
|
|
||||||
extern int bgp_md5_set (struct peer *);
|
extern int bgp_md5_set (struct peer *);
|
||||||
|
extern int bgp_md5_unset (struct peer *);
|
||||||
extern int bgp_set_socket_ttl(struct peer *, int fd);
|
extern int bgp_set_socket_ttl(struct peer *, int fd);
|
||||||
|
|
||||||
#endif /* _QUAGGA_BGP_NETWORK_H */
|
#endif /* _QUAGGA_BGP_NETWORK_H */
|
||||||
|
192
bgpd/bgpd.c
192
bgpd/bgpd.c
@ -1168,83 +1168,127 @@ peer_xfer_config (struct peer *peer_dst, struct peer *peer_src)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
static int
|
||||||
* Set or reset the peer address socketunion structure based on the
|
bgp_peer_conf_if_to_su_update_v4 (struct peer *peer, struct interface *ifp)
|
||||||
* learnt peer address. Currently via the source address of the
|
|
||||||
* ipv6 ND router-advertisement.
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
bgp_peer_conf_if_to_su_update (struct peer *peer)
|
|
||||||
{
|
{
|
||||||
struct interface *ifp;
|
|
||||||
struct nbr_connected *ifc_nbr;
|
|
||||||
struct connected *ifc;
|
struct connected *ifc;
|
||||||
struct prefix p;
|
struct prefix p;
|
||||||
u_int32_t s_addr;
|
u_int32_t s_addr;
|
||||||
struct listnode *node;
|
struct listnode *node;
|
||||||
|
|
||||||
|
/* If our IPv4 address on the interface is /30 or /31, we can derive the
|
||||||
|
* IPv4 address of the other end.
|
||||||
|
*/
|
||||||
|
for (ALL_LIST_ELEMENTS_RO(ifp->connected, node, ifc))
|
||||||
|
{
|
||||||
|
if (ifc->address && (ifc->address->family == AF_INET))
|
||||||
|
{
|
||||||
|
PREFIX_COPY_IPV4(&p, CONNECTED_PREFIX(ifc));
|
||||||
|
if (p.prefixlen == 30)
|
||||||
|
{
|
||||||
|
peer->su.sa.sa_family = AF_INET;
|
||||||
|
s_addr = ntohl(p.u.prefix4.s_addr);
|
||||||
|
if (s_addr % 4 == 1)
|
||||||
|
peer->su.sin.sin_addr.s_addr = htonl(s_addr+1);
|
||||||
|
else if (s_addr % 4 == 2)
|
||||||
|
peer->su.sin.sin_addr.s_addr = htonl(s_addr-1);
|
||||||
|
#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
|
||||||
|
peer->su->sin.sin_len = sizeof(struct sockaddr_in);
|
||||||
|
#endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
else if (p.prefixlen == 31)
|
||||||
|
{
|
||||||
|
peer->su.sa.sa_family = AF_INET;
|
||||||
|
s_addr = ntohl(p.u.prefix4.s_addr);
|
||||||
|
if (s_addr % 2 == 0)
|
||||||
|
peer->su.sin.sin_addr.s_addr = htonl(s_addr+1);
|
||||||
|
else
|
||||||
|
peer->su.sin.sin_addr.s_addr = htonl(s_addr-1);
|
||||||
|
#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
|
||||||
|
peer->su->sin.sin_len = sizeof(struct sockaddr_in);
|
||||||
|
#endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
zlog_warn("%s: IPv4 interface address is not /30 or /31, v4 session not started",
|
||||||
|
peer->conf_if);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
bgp_peer_conf_if_to_su_update_v6 (struct peer *peer, struct interface *ifp)
|
||||||
|
{
|
||||||
|
struct nbr_connected *ifc_nbr;
|
||||||
|
|
||||||
|
/* Have we learnt the peer's IPv6 link-local address? */
|
||||||
|
if (ifp->nbr_connected &&
|
||||||
|
(ifc_nbr = listnode_head(ifp->nbr_connected)))
|
||||||
|
{
|
||||||
|
peer->su.sa.sa_family = AF_INET6;
|
||||||
|
memcpy(&peer->su.sin6.sin6_addr, &ifc_nbr->address->u.prefix,
|
||||||
|
sizeof (struct in6_addr));
|
||||||
|
#ifdef SIN6_LEN
|
||||||
|
peer->su.sin6.sin6_len = sizeof (struct sockaddr_in6);
|
||||||
|
#endif
|
||||||
|
peer->su.sin6.sin6_scope_id = ifp->ifindex;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Set or reset the peer address socketunion structure based on the
|
||||||
|
* learnt/derived peer address. If the address has changed, update the
|
||||||
|
* password on the listen socket, if needed.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
bgp_peer_conf_if_to_su_update (struct peer *peer)
|
||||||
|
{
|
||||||
|
struct interface *ifp;
|
||||||
|
int prev_family;
|
||||||
|
int peer_addr_updated = 0;
|
||||||
|
|
||||||
if (!peer->conf_if)
|
if (!peer->conf_if)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
prev_family = peer->su.sa.sa_family;
|
||||||
if ((ifp = if_lookup_by_name(peer->conf_if)))
|
if ((ifp = if_lookup_by_name(peer->conf_if)))
|
||||||
{
|
{
|
||||||
/* if multiple IP addresses assigned to link, we pick the first */
|
/* If BGP unnumbered is not "v6only", we first see if we can derive the
|
||||||
|
* peer's IPv4 address.
|
||||||
|
*/
|
||||||
if (!CHECK_FLAG(peer->flags, PEER_FLAG_IFPEER_V6ONLY))
|
if (!CHECK_FLAG(peer->flags, PEER_FLAG_IFPEER_V6ONLY))
|
||||||
for (ALL_LIST_ELEMENTS_RO(ifp->connected, node, ifc))
|
peer_addr_updated = bgp_peer_conf_if_to_su_update_v4 (peer, ifp);
|
||||||
if (ifc->address && (ifc->address->family == AF_INET))
|
|
||||||
{
|
|
||||||
/* Try IPv4 connection first, if present */
|
|
||||||
PREFIX_COPY_IPV4(&p, CONNECTED_PREFIX(ifc));
|
|
||||||
/* We can determine peer's IP address if prefixlen is 30/31 */
|
|
||||||
if (p.prefixlen == 30)
|
|
||||||
{
|
|
||||||
peer->su.sa.sa_family = AF_INET;
|
|
||||||
s_addr = ntohl(p.u.prefix4.s_addr);
|
|
||||||
if (s_addr % 4 == 1)
|
|
||||||
peer->su.sin.sin_addr.s_addr = htonl(s_addr+1);
|
|
||||||
else if (s_addr % 4 == 2)
|
|
||||||
peer->su.sin.sin_addr.s_addr = htonl(s_addr-1);
|
|
||||||
#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
|
|
||||||
peer->su->sin.sin_len = sizeof(struct sockaddr_in);
|
|
||||||
#endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
else if (p.prefixlen == 31)
|
|
||||||
{
|
|
||||||
peer->su.sa.sa_family = AF_INET;
|
|
||||||
s_addr = ntohl(p.u.prefix4.s_addr);
|
|
||||||
if (s_addr % 2 == 0)
|
|
||||||
peer->su.sin.sin_addr.s_addr = htonl(s_addr+1);
|
|
||||||
else
|
|
||||||
peer->su.sin.sin_addr.s_addr = htonl(s_addr-1);
|
|
||||||
#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
|
|
||||||
peer->su->sin.sin_len = sizeof(struct sockaddr_in);
|
|
||||||
#endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
zlog_warn("%s: IPv4 interface address is not /30 or /31, v4 session not started",
|
|
||||||
peer->conf_if);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ifp->nbr_connected &&
|
/* If "v6only" or we can't derive peer's IPv4 address, see if we've
|
||||||
(ifc_nbr = listnode_head(ifp->nbr_connected)))
|
* learnt the peer's IPv6 link-local address. This is from the source
|
||||||
{
|
* IPv6 address in router advertisement.
|
||||||
peer->su.sa.sa_family = AF_INET6;
|
*/
|
||||||
memcpy(&peer->su.sin6.sin6_addr, &ifc_nbr->address->u.prefix,
|
if (!peer_addr_updated)
|
||||||
sizeof (struct in6_addr));
|
peer_addr_updated = bgp_peer_conf_if_to_su_update_v6 (peer, ifp);
|
||||||
#ifdef SIN6_LEN
|
}
|
||||||
peer->su.sin6.sin6_len = sizeof (struct sockaddr_in6);
|
/* If we could derive the peer address, we may need to install the password
|
||||||
#endif
|
* configured for the peer, if any, on the listen socket. Otherwise, mark
|
||||||
peer->su.sin6.sin6_scope_id = ifp->ifindex;
|
* that peer's address is not available and uninstall the password, if
|
||||||
|
* needed.
|
||||||
return;
|
*/
|
||||||
}
|
if (peer_addr_updated)
|
||||||
|
{
|
||||||
|
if (peer->password && prev_family == AF_UNSPEC)
|
||||||
|
bgp_md5_set (peer);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (peer->password && prev_family != AF_UNSPEC)
|
||||||
|
bgp_md5_unset (peer);
|
||||||
|
peer->su.sa.sa_family = AF_UNSPEC;
|
||||||
|
memset(&peer->su.sin6.sin6_addr, 0, sizeof (struct in6_addr));
|
||||||
}
|
}
|
||||||
/* This works as an indication of unresolved peer address
|
|
||||||
on a BGP interface*/
|
|
||||||
peer->su.sa.sa_family = AF_UNSPEC;
|
|
||||||
memset(&peer->su.sin6.sin6_addr, 0, sizeof (struct in6_addr));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Create new BGP peer. */
|
/* Create new BGP peer. */
|
||||||
@ -1745,8 +1789,9 @@ peer_delete (struct peer *peer)
|
|||||||
peer->password = NULL;
|
peer->password = NULL;
|
||||||
|
|
||||||
if (!accept_peer &&
|
if (!accept_peer &&
|
||||||
|
! BGP_PEER_SU_UNSPEC(peer) &&
|
||||||
! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP))
|
! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP))
|
||||||
bgp_md5_set (peer);
|
bgp_md5_unset (peer);
|
||||||
}
|
}
|
||||||
|
|
||||||
bgp_timer_set (peer); /* stops all timers for Deleted */
|
bgp_timer_set (peer); /* stops all timers for Deleted */
|
||||||
@ -1987,7 +2032,8 @@ peer_group2peer_config_copy (struct peer_group *group, struct peer *peer,
|
|||||||
if (conf->password && !peer->password)
|
if (conf->password && !peer->password)
|
||||||
peer->password = XSTRDUP (MTYPE_PEER_PASSWORD, conf->password);
|
peer->password = XSTRDUP (MTYPE_PEER_PASSWORD, conf->password);
|
||||||
|
|
||||||
bgp_md5_set (peer);
|
if (! BGP_PEER_SU_UNSPEC(peer))
|
||||||
|
bgp_md5_set (peer);
|
||||||
|
|
||||||
/* maximum-prefix */
|
/* maximum-prefix */
|
||||||
peer->pmax[afi][safi] = conf->pmax[afi][safi];
|
peer->pmax[afi][safi] = conf->pmax[afi][safi];
|
||||||
@ -4597,6 +4643,9 @@ peer_password_set (struct peer *peer, const char *password)
|
|||||||
else
|
else
|
||||||
bgp_session_reset(peer);
|
bgp_session_reset(peer);
|
||||||
|
|
||||||
|
if (BGP_PEER_SU_UNSPEC(peer))
|
||||||
|
return BGP_SUCCESS;
|
||||||
|
|
||||||
return (bgp_md5_set (peer) >= 0) ? BGP_SUCCESS : BGP_ERR_TCPSIG_FAILED;
|
return (bgp_md5_set (peer) >= 0) ? BGP_SUCCESS : BGP_ERR_TCPSIG_FAILED;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -4615,8 +4664,11 @@ peer_password_set (struct peer *peer, const char *password)
|
|||||||
else
|
else
|
||||||
bgp_session_reset(peer);
|
bgp_session_reset(peer);
|
||||||
|
|
||||||
if (bgp_md5_set (peer) < 0)
|
if (! BGP_PEER_SU_UNSPEC(peer))
|
||||||
ret = BGP_ERR_TCPSIG_FAILED;
|
{
|
||||||
|
if (bgp_md5_set (peer) < 0)
|
||||||
|
ret = BGP_ERR_TCPSIG_FAILED;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
@ -4648,7 +4700,8 @@ peer_password_unset (struct peer *peer)
|
|||||||
|
|
||||||
peer->password = NULL;
|
peer->password = NULL;
|
||||||
|
|
||||||
bgp_md5_set (peer);
|
if (! BGP_PEER_SU_UNSPEC(peer))
|
||||||
|
bgp_md5_unset (peer);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -4669,7 +4722,8 @@ peer_password_unset (struct peer *peer)
|
|||||||
XFREE (MTYPE_PEER_PASSWORD, peer->password);
|
XFREE (MTYPE_PEER_PASSWORD, peer->password);
|
||||||
peer->password = NULL;
|
peer->password = NULL;
|
||||||
|
|
||||||
bgp_md5_set (peer);
|
if (! BGP_PEER_SU_UNSPEC(peer))
|
||||||
|
bgp_md5_unset (peer);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
Loading…
Reference in New Issue
Block a user