diff options
author | Quentin Young <qlyoung@cumulusnetworks.com> | 2019-03-30 00:24:08 +0100 |
---|---|---|
committer | Quentin Young <qlyoung@cumulusnetworks.com> | 2019-04-16 17:26:20 +0200 |
commit | 9e7d9a61acc551ff73b10fa2892d38d4bd0109f3 (patch) | |
tree | b3431d89d447d5916cf628f8763d9efb89f52048 /bgpd/bgp_network.c | |
parent | lib: add support for extended TCP MD5 auth (diff) | |
download | frr-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.c | 90 |
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) { |