mirror of
https://git.proxmox.com/git/mirror_frr
synced 2025-10-19 08:06:10 +00:00
bgpd: add support for MD5 auth on listen ranges
Co-authored-by: Donald Sharp <sharpd@cumulusnetworks.com> Co-authored-by: Quentin Young <qlyoung@cumulusnetworks.com> Signed-off-by: Quentin Young <qlyoung@cumulusnetworks.com>
This commit is contained in:
parent
b33e46666d
commit
9e7d9a61ac
@ -64,7 +64,7 @@ struct bgp_listener {
|
|||||||
* If the password is NULL or zero-length, the option will be disabled.
|
* If the password is NULL or zero-length, the option will be disabled.
|
||||||
*/
|
*/
|
||||||
static int bgp_md5_set_socket(int socket, union sockunion *su,
|
static int bgp_md5_set_socket(int socket, union sockunion *su,
|
||||||
const char *password)
|
uint16_t prefixlen, const char *password)
|
||||||
{
|
{
|
||||||
int ret = -1;
|
int ret = -1;
|
||||||
int en = ENOSYS;
|
int en = ENOSYS;
|
||||||
@ -81,27 +81,49 @@ static int bgp_md5_set_socket(int socket, union sockunion *su,
|
|||||||
su2.sin.sin_port = 0;
|
su2.sin.sin_port = 0;
|
||||||
else
|
else
|
||||||
su2.sin6.sin6_port = 0;
|
su2.sin6.sin6_port = 0;
|
||||||
ret = sockopt_tcp_signature(socket, &su2, password);
|
|
||||||
|
/* For addresses, use the non-extended signature functionality */
|
||||||
|
if ((su2.sa.sa_family == AF_INET && prefixlen == IPV4_MAX_PREFIXLEN)
|
||||||
|
|| (su2.sa.sa_family == AF_INET6
|
||||||
|
&& prefixlen == IPV6_MAX_PREFIXLEN))
|
||||||
|
ret = sockopt_tcp_signature(socket, &su2, password);
|
||||||
|
else
|
||||||
|
ret = sockopt_tcp_signature_ext(socket, &su2, prefixlen,
|
||||||
|
password);
|
||||||
en = errno;
|
en = errno;
|
||||||
#endif /* HAVE_TCP_MD5SIG */
|
#endif /* HAVE_TCP_MD5SIG */
|
||||||
|
|
||||||
if (ret < 0)
|
if (ret < 0) {
|
||||||
flog_warn(EC_BGP_NO_TCP_MD5,
|
char sabuf[SU_ADDRSTRLEN];
|
||||||
"can't set TCP_MD5SIG option on socket %d: %s",
|
sockunion2str(su, sabuf, sizeof(sabuf));
|
||||||
socket, safe_strerror(en));
|
|
||||||
|
switch (ret) {
|
||||||
|
case -2:
|
||||||
|
flog_warn(
|
||||||
|
EC_BGP_NO_TCP_MD5,
|
||||||
|
"Unable to set TCP MD5 option on socket for peer %s (sock=%d): This platform does not support MD5 auth for prefixes",
|
||||||
|
sabuf, socket);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
flog_warn(
|
||||||
|
EC_BGP_NO_TCP_MD5,
|
||||||
|
"Unable to set TCP MD5 option on socket for peer %s (sock=%d): %s",
|
||||||
|
sabuf, socket, safe_strerror(en));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Helper for bgp_connect */
|
/* Helper for bgp_connect */
|
||||||
static int bgp_md5_set_connect(int socket, union sockunion *su,
|
static int bgp_md5_set_connect(int socket, union sockunion *su,
|
||||||
const char *password)
|
uint16_t prefixlen, const char *password)
|
||||||
{
|
{
|
||||||
int ret = -1;
|
int ret = -1;
|
||||||
|
|
||||||
#if HAVE_DECL_TCP_MD5SIG
|
#if HAVE_DECL_TCP_MD5SIG
|
||||||
frr_elevate_privs(&bgpd_privs) {
|
frr_elevate_privs(&bgpd_privs) {
|
||||||
ret = bgp_md5_set_socket(socket, su, password);
|
ret = bgp_md5_set_socket(socket, su, prefixlen, password);
|
||||||
}
|
}
|
||||||
#endif /* HAVE_TCP_MD5SIG */
|
#endif /* HAVE_TCP_MD5SIG */
|
||||||
|
|
||||||
@ -114,21 +136,57 @@ static int bgp_md5_set_password(struct peer *peer, const char *password)
|
|||||||
int ret = 0;
|
int ret = 0;
|
||||||
struct bgp_listener *listener;
|
struct bgp_listener *listener;
|
||||||
|
|
||||||
frr_elevate_privs(&bgpd_privs) {
|
/*
|
||||||
/* Set or unset the password on the listen socket(s). Outbound
|
* Set or unset the password on the listen socket(s). Outbound
|
||||||
* connections are taken care of in bgp_connect() below.
|
* connections are taken care of in bgp_connect() below.
|
||||||
*/
|
*/
|
||||||
|
frr_elevate_privs(&bgpd_privs)
|
||||||
|
{
|
||||||
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
|
if (listener->su.sa.sa_family
|
||||||
== peer->su.sa.sa_family) {
|
== peer->su.sa.sa_family) {
|
||||||
|
uint16_t prefixlen =
|
||||||
|
peer->su.sa.sa_family == AF_INET
|
||||||
|
? IPV4_MAX_PREFIXLEN
|
||||||
|
: IPV6_MAX_PREFIXLEN;
|
||||||
|
|
||||||
ret = bgp_md5_set_socket(listener->fd,
|
ret = bgp_md5_set_socket(listener->fd,
|
||||||
&peer->su, password);
|
&peer->su, prefixlen,
|
||||||
|
password);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int bgp_md5_set_prefix(struct prefix *p, const char *password)
|
||||||
|
{
|
||||||
|
int ret = 0;
|
||||||
|
union sockunion su;
|
||||||
|
struct listnode *node;
|
||||||
|
struct bgp_listener *listener;
|
||||||
|
|
||||||
|
/* Set or unset the password on the listen socket(s). */
|
||||||
|
frr_elevate_privs(&bgpd_privs)
|
||||||
|
{
|
||||||
|
for (ALL_LIST_ELEMENTS_RO(bm->listen_sockets, node, listener))
|
||||||
|
if (listener->su.sa.sa_family == p->family) {
|
||||||
|
prefix2sockunion(p, &su);
|
||||||
|
ret = bgp_md5_set_socket(listener->fd, &su,
|
||||||
|
p->prefixlen,
|
||||||
|
password);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int bgp_md5_unset_prefix(struct prefix *p)
|
||||||
|
{
|
||||||
|
return bgp_md5_set_prefix(p, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
int bgp_md5_set(struct peer *peer)
|
int bgp_md5_set(struct peer *peer)
|
||||||
{
|
{
|
||||||
/* Set the password from listen socket. */
|
/* Set the password from listen socket. */
|
||||||
@ -577,8 +635,14 @@ int bgp_connect(struct peer *peer)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (peer->password)
|
if (peer->password) {
|
||||||
bgp_md5_set_connect(peer->fd, &peer->su, peer->password);
|
uint16_t prefixlen = peer->su.sa.sa_family == AF_INET
|
||||||
|
? IPV4_MAX_PREFIXLEN
|
||||||
|
: IPV6_MAX_PREFIXLEN;
|
||||||
|
|
||||||
|
bgp_md5_set_connect(peer->fd, &peer->su, prefixlen,
|
||||||
|
peer->password);
|
||||||
|
}
|
||||||
|
|
||||||
/* Update source bind. */
|
/* Update source bind. */
|
||||||
if (bgp_update_source(peer) < 0) {
|
if (bgp_update_source(peer) < 0) {
|
||||||
|
@ -30,6 +30,8 @@ extern void bgp_close(void);
|
|||||||
extern int bgp_connect(struct peer *);
|
extern int bgp_connect(struct peer *);
|
||||||
extern int bgp_getsockname(struct peer *);
|
extern int bgp_getsockname(struct peer *);
|
||||||
|
|
||||||
|
extern int bgp_md5_set_prefix(struct prefix *p, const char *password);
|
||||||
|
extern int bgp_md5_unset_prefix(struct prefix *p);
|
||||||
extern int bgp_md5_set(struct peer *);
|
extern int bgp_md5_set(struct peer *);
|
||||||
extern int bgp_md5_unset(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);
|
||||||
|
27
bgpd/bgpd.c
27
bgpd/bgpd.c
@ -2645,6 +2645,11 @@ int peer_group_listen_range_add(struct peer_group *group, struct prefix *range)
|
|||||||
prefix = prefix_new();
|
prefix = prefix_new();
|
||||||
prefix_copy(prefix, range);
|
prefix_copy(prefix, range);
|
||||||
listnode_add(group->listen_range[afi], prefix);
|
listnode_add(group->listen_range[afi], prefix);
|
||||||
|
|
||||||
|
/* Update passwords for new ranges */
|
||||||
|
if (group->conf->password)
|
||||||
|
bgp_md5_set_prefix(prefix, group->conf->password);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2689,6 +2694,10 @@ int peer_group_listen_range_del(struct peer_group *group, struct prefix *range)
|
|||||||
/* Get rid of the listen range */
|
/* Get rid of the listen range */
|
||||||
listnode_delete(group->listen_range[afi], prefix);
|
listnode_delete(group->listen_range[afi], prefix);
|
||||||
|
|
||||||
|
/* Remove passwords for deleted ranges */
|
||||||
|
if (group->conf->password)
|
||||||
|
bgp_md5_unset_prefix(prefix);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -5519,6 +5528,15 @@ int peer_password_set(struct peer *peer, const char *password)
|
|||||||
ret = BGP_ERR_TCPSIG_FAILED;
|
ret = BGP_ERR_TCPSIG_FAILED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Set flag and configuration on all peer-group listen ranges */
|
||||||
|
struct listnode *ln;
|
||||||
|
struct prefix *lr;
|
||||||
|
|
||||||
|
for (ALL_LIST_ELEMENTS_RO(peer->group->listen_range[AFI_IP], ln, lr))
|
||||||
|
bgp_md5_set_prefix(lr, password);
|
||||||
|
for (ALL_LIST_ELEMENTS_RO(peer->group->listen_range[AFI_IP6], ln, lr))
|
||||||
|
bgp_md5_set_prefix(lr, password);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -5583,6 +5601,15 @@ int peer_password_unset(struct peer *peer)
|
|||||||
bgp_md5_unset(member);
|
bgp_md5_unset(member);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Set flag and configuration on all peer-group listen ranges */
|
||||||
|
struct listnode *ln;
|
||||||
|
struct prefix *lr;
|
||||||
|
|
||||||
|
for (ALL_LIST_ELEMENTS_RO(peer->group->listen_range[AFI_IP], ln, lr))
|
||||||
|
bgp_md5_unset_prefix(lr);
|
||||||
|
for (ALL_LIST_ELEMENTS_RO(peer->group->listen_range[AFI_IP6], ln, lr))
|
||||||
|
bgp_md5_unset_prefix(lr);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user