diff options
Diffstat (limited to 'bgpd/bgp_network.c')
-rw-r--r-- | bgpd/bgp_network.c | 158 |
1 files changed, 61 insertions, 97 deletions
diff --git a/bgpd/bgp_network.c b/bgpd/bgp_network.c index e981e718..87f7f7b6 100644 --- a/bgpd/bgp_network.c +++ b/bgpd/bgp_network.c @@ -29,6 +29,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA #include "prefix.h" #include "command.h" #include "privs.h" +#include "linklist.h" #include "bgpd/bgpd.h" #include "bgpd/bgp_fsm.h" @@ -39,33 +40,70 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA extern struct zebra_privs_t bgpd_privs; -#if defined(HAVE_TCP_MD5SIG) /* * Set MD5 key for the socket, for the given IPv4 peer address. * If the password is NULL or zero-length, the option will be disabled. */ -int -bgp_md5_set (int sock, struct sockaddr_in *sin, const char *password) +static int +bgp_md5_set_socket (int socket, union sockunion *su, const char *password) { - int ret, en; - - if ( bgpd_privs.change (ZPRIVS_RAISE) ) - zlog_err ("bgp_md5_set: could not raise privs"); - - ret = sockopt_tcp_signature (sock, sin, password); + int ret = -1; + int en = ENOSYS; + + assert (socket >= 0); + +#if HAVE_DECL_TCP_MD5SIG + ret = sockopt_tcp_signature (socket, su, password); en = errno; - - if (bgpd_privs.change (ZPRIVS_LOWER) ) - zlog_err ("bgp_md5_set: could not lower privs"); - +#endif /* HAVE_TCP_MD5SIG */ + if (ret < 0) zlog (NULL, LOG_WARNING, "can't set TCP_MD5SIG option on socket %d: %s", - sock, safe_strerror (en)); + socket, safe_strerror (en)); return ret; } +/* Helper for bgp_connect */ +static int +bgp_md5_set_connect (int socket, union sockunion *su, const char *password) +{ + int ret = -1; + +#if HAVE_DECL_TCP_MD5SIG + if ( bgpd_privs.change (ZPRIVS_RAISE) ) + { + zlog_err ("%s: could not raise privs", __func__); + return ret; + } + + ret = bgp_md5_set_socket (socket, su, password); + + if (bgpd_privs.change (ZPRIVS_LOWER) ) + zlog_err ("%s: could not lower privs", __func__); #endif /* HAVE_TCP_MD5SIG */ + + return ret; +} + +int +bgp_md5_set (struct peer *peer) +{ + struct listnode *node; + int fret = 0, ret; + int *socket; + + /* Just set the password on the listen socket(s). Outbound connections + * are taken care of in bgp_connect() below. + */ + for (ALL_LIST_ELEMENTS_RO(bm->listen_sockets, node, socket)) + { + ret = bgp_md5_set_socket ((int )socket, &peer->su, peer->password); + if (ret < 0) + fret = ret; + } + return fret; +} /* Accept bgp connection. */ static int @@ -266,17 +304,14 @@ bgp_connect (struct peer *peer) sockopt_reuseaddr (peer->fd); sockopt_reuseport (peer->fd); - + #ifdef IPTOS_PREC_INTERNETCONTROL if (sockunion_family (&peer->su) == AF_INET) setsockopt_ipv4_tos (peer->fd, IPTOS_PREC_INTERNETCONTROL); #endif -#ifdef HAVE_TCP_MD5SIG - if (CHECK_FLAG (peer->flags, PEER_FLAG_PASSWORD)) - if (sockunion_family (&peer->su) == AF_INET) - bgp_md5_set (peer->fd, &peer->su.sin, peer->password); -#endif /* HAVE_TCP_MD5SIG */ + if (peer->password) + bgp_md5_set_connect (peer->fd, &peer->su, peer->password); /* Bind socket. */ bgp_bind (peer); @@ -328,10 +363,6 @@ bgp_socket (struct bgp *bgp, unsigned short port, char *address) struct addrinfo req; struct addrinfo *ainfo; struct addrinfo *ainfo_save; -#if defined(HAVE_TCP_MD5SIG) && defined(IPV6_V6ONLY) - struct sockaddr_in sin; - int socklen, on = 1; -#endif int sock = 0; char port_str[BUFSIZ]; @@ -372,18 +403,12 @@ bgp_socket (struct bgp *bgp, unsigned short port, char *address) setsockopt_ipv4_tos (sock, IPTOS_PREC_INTERNETCONTROL); #endif -#if defined(HAVE_TCP_MD5SIG) && defined(IPV6_V6ONLY) -/* We can not apply MD5SIG to an IPv6 socket. If this is an AF_INET6 - socket, we'll have to create another socket for IPv4*/ - +#ifdef IPV6_V6ONLY + /* Want only IPV6 on ipv6 socket (not mapped addresses) */ if (ainfo->ai_family == AF_INET6) { -/* Mark this one for IPv6 only */ - ret = setsockopt (sock, IPPROTO_IPV6, IPV6_V6ONLY, + int on = 1; + setsockopt (sock, IPPROTO_IPV6, IPV6_V6ONLY, (void *) &on, sizeof (on)); - if( ret < 0 ) { - en = errno; - zlog_err ("setsockopt V6ONLY: %s", safe_strerror (en)); - } } #endif @@ -409,67 +434,9 @@ bgp_socket (struct bgp *bgp, unsigned short port, char *address) close (sock); continue; } - -#if defined(HAVE_TCP_MD5SIG) && defined(IPV6_V6ONLY) - thread_add_read (master, bgp_accept, bgp, sock); - - if (ainfo->ai_family != AF_INET6) - continue; - - /* If first socket was an IPv6 socket, we need to create an IPv4 - socket for use by the TCP_MD5SIG logic. This code is blatently - copied and modified from the alternate IPv4 only code from below... */ - - sock = socket (AF_INET, SOCK_STREAM, 0); - if (sock < 0) - { - zlog_err ("socket: %s", safe_strerror (errno)); - continue; - } - - sockopt_reuseaddr (sock); - sockopt_reuseport (sock); - setsockopt_ipv4_tos (sock, IPTOS_PREC_INTERNETCONTROL); - - memset (&sin, 0, sizeof (struct sockaddr_in)); - - sin.sin_family = AF_INET; - sin.sin_port = htons (port); - socklen = sizeof (struct sockaddr_in); -#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN - sin.sin_len = socklen; -#endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */ - - if ( bgpd_privs.change (ZPRIVS_RAISE) ) - zlog_err ("bgp_socket: could not raise privs"); - - ret = bind (sock, (struct sockaddr *) &sin, socklen); - en = errno; - if (bgpd_privs.change (ZPRIVS_LOWER) ) - zlog_err ("bgp_bind_address: could not lower privs"); - - if (ret < 0) - { - zlog_err ("bind: %s", safe_strerror (en)); - close(sock); - continue; - } - - ret = listen (sock, 3); - if (ret < 0) - { - zlog_err ("listen: %s", safe_strerror (errno)); - close (sock); - continue; - } -#endif - -#ifdef HAVE_TCP_MD5SIG - bm->sock = sock; -#endif /* HAVE_TCP_MD5SIG */ - + + listnode_add (bm->listen_sockets, (void *)sock); thread_add_read (master, bgp_accept, bgp, sock); - } while ((ainfo = ainfo->ai_next) != NULL); @@ -540,9 +507,6 @@ bgp_socket (struct bgp *bgp, unsigned short port, char *address) close (sock); return ret; } -#ifdef HAVE_TCP_MD5SIG - bm->sock = sock; -#endif /* HAVE_TCP_MD5SIG */ thread_add_read (bm->master, bgp_accept, bgp, sock); |