summaryrefslogtreecommitdiffstats
path: root/bgpd/bgp_network.c
diff options
context:
space:
mode:
authorQuentin Young <qlyoung@cumulusnetworks.com>2019-03-30 00:24:08 +0100
committerQuentin Young <qlyoung@cumulusnetworks.com>2019-04-16 17:26:20 +0200
commit9e7d9a61acc551ff73b10fa2892d38d4bd0109f3 (patch)
treeb3431d89d447d5916cf628f8763d9efb89f52048 /bgpd/bgp_network.c
parentlib: add support for extended TCP MD5 auth (diff)
downloadfrr-9e7d9a61acc551ff73b10fa2892d38d4bd0109f3.tar.xz
frr-9e7d9a61acc551ff73b10fa2892d38d4bd0109f3.zip
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>
Diffstat (limited to 'bgpd/bgp_network.c')
-rw-r--r--bgpd/bgp_network.c90
1 files changed, 77 insertions, 13 deletions
diff --git a/bgpd/bgp_network.c b/bgpd/bgp_network.c
index 4153da5a6..6a5c2c4b3 100644
--- a/bgpd/bgp_network.c
+++ b/bgpd/bgp_network.c
@@ -64,7 +64,7 @@ struct bgp_listener {
* If the password is NULL or zero-length, the option will be disabled.
*/
static int bgp_md5_set_socket(int socket, union sockunion *su,
- const char *password)
+ uint16_t prefixlen, const char *password)
{
int ret = -1;
int en = ENOSYS;
@@ -81,27 +81,49 @@ static int bgp_md5_set_socket(int socket, union sockunion *su,
su2.sin.sin_port = 0;
else
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;
#endif /* HAVE_TCP_MD5SIG */
- if (ret < 0)
- flog_warn(EC_BGP_NO_TCP_MD5,
- "can't set TCP_MD5SIG option on socket %d: %s",
- socket, safe_strerror(en));
+ if (ret < 0) {
+ char sabuf[SU_ADDRSTRLEN];
+ sockunion2str(su, sabuf, sizeof(sabuf));
+
+ 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;
}
/* Helper for bgp_connect */
static int bgp_md5_set_connect(int socket, union sockunion *su,
- const char *password)
+ uint16_t prefixlen, const char *password)
{
int ret = -1;
#if HAVE_DECL_TCP_MD5SIG
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 */
@@ -114,21 +136,57 @@ static int bgp_md5_set_password(struct peer *peer, const char *password)
int ret = 0;
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.
*/
+ frr_elevate_privs(&bgpd_privs)
+ {
for (ALL_LIST_ELEMENTS_RO(bm->listen_sockets, node, listener))
if (listener->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,
- &peer->su, password);
+ &peer->su, prefixlen,
+ password);
break;
}
}
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)
{
/* Set the password from listen socket. */
@@ -577,8 +635,14 @@ int bgp_connect(struct peer *peer)
}
#endif
- if (peer->password)
- bgp_md5_set_connect(peer->fd, &peer->su, peer->password);
+ if (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. */
if (bgp_update_source(peer) < 0) {