summaryrefslogtreecommitdiffstats
path: root/bgpd/bgp_network.c
diff options
context:
space:
mode:
Diffstat (limited to 'bgpd/bgp_network.c')
-rw-r--r--bgpd/bgp_network.c487
1 files changed, 316 insertions, 171 deletions
diff --git a/bgpd/bgp_network.c b/bgpd/bgp_network.c
index 856ac879..b929bf14 100644
--- a/bgpd/bgp_network.c
+++ b/bgpd/bgp_network.c
@@ -20,6 +20,7 @@
*/
#include <zebra.h>
+#include <stdbool.h>
#include "sockunion.h"
#include "sockopt.h"
@@ -55,10 +56,11 @@ static void
bgp_accept_action(qps_file qf, void* file_info) ;
static int
-bgp_getsockname(int fd, union sockunion* su_local, union sockunion* su_remote) ;
+bgp_get_names(int sock_fd, union sockunion* su_local,
+ union sockunion* su_remote) ;
static int
-bgp_socket_set_common_options(int fd, union sockunion* su, int ttl,
+bgp_socket_set_common_options(int sock_fd, union sockunion* su, int ttl,
const char* password) ;
static int
bgp_md5_set_listeners(union sockunion* su, const char* password) ;
@@ -98,7 +100,76 @@ struct bgp_listener
} ;
/* Forward reference */
-static int bgp_init_listener(int sock, struct sockaddr *sa, socklen_t salen) ;
+static int bgp_open_listener_on(const char* address, unsigned short port);
+static int bgp_init_listener(int sock_fd, struct sockaddr *sa, socklen_t salen);
+
+/*------------------------------------------------------------------------------
+ * Open Listeners.
+ *
+ * Using given address and port, get all possible addresses and set up a
+ * listener on each one.
+ *
+ * Accepts: address = NULL => any local address
+ * address = comma separated list of addresses
+ *
+ * NB: an empty address counts as "any local address", so:
+ *
+ * "80.177.246.130,80.177.246.131" -- will listen on those addresses.
+ *
+ * "80.177.246.130," -- will list on that address and
+ * any other local address.
+ *
+ * NB: only listens on AF_INET and (if HAVE_IPV6) AF_INET6.
+ *
+ * Returns: > 0 => OK -- number of listeners set up
+ * -1 => failed -- no listeners set up
+ */
+extern int
+bgp_open_listeners(const char* address, unsigned short port)
+{
+ int count ;
+ bool do_null ;
+
+ count = 0 ;
+ do_null = (address == NULL) ;
+
+ if (!do_null)
+ {
+ char* copy ;
+ char* next ;
+ char* this ;
+
+ copy = XSTRDUP(MTYPE_TMP, address) ;
+
+ next = copy ;
+ while (next != NULL)
+ {
+ this = next ;
+ next = strchr(address, ',') ;
+
+ if (next != NULL)
+ *next++ = '\0' ;
+
+ if (*this == '\0')
+ do_null = true ; /* empty address => do_null */
+ else
+ count += bgp_open_listener_on(this, port) ;
+ } ;
+
+ XFREE(MTYPE_TMP, copy) ;
+ } ;
+
+ if (do_null)
+ count += bgp_open_listener_on(NULL, port) ;
+
+ if (count == 0)
+ {
+ zlog_err ("%s: no usable addresses", __func__);
+ return -1;
+ }
+
+ return 0;
+} ;
/*------------------------------------------------------------------------------
* Open Listeners.
@@ -110,10 +181,9 @@ static int bgp_init_listener(int sock, struct sockaddr *sa, socklen_t salen) ;
*
* Returns: 0 => OK
* -1 => failed -- no listeners set up
- *
*/
-extern int
-bgp_open_listeners(unsigned short port, const char *address)
+static int
+bgp_open_listener_on(const char* address, unsigned short port)
{
#if defined (HAVE_IPV6) && ! defined (NRL) /*----------------------------*/
@@ -137,47 +207,41 @@ bgp_open_listeners(unsigned short port, const char *address)
if (ret != 0)
{
zlog_err ("getaddrinfo: %s", gai_strerror (ret));
- return -1;
+ return 0 ;
}
count = 0;
for (ainfo = ainfo_save; ainfo; ainfo = ainfo->ai_next)
{
- int sock;
+ int sock_fd;
if (ainfo->ai_family != AF_INET && ainfo->ai_family != AF_INET6)
continue;
- sock = sockunion_socket(ainfo->ai_family, ainfo->ai_socktype,
+ sock_fd = sockunion_socket(ainfo->ai_family, ainfo->ai_socktype,
ainfo->ai_protocol);
- if (sock < 0)
+ if (sock_fd < 0)
{
zlog_err ("socket: %s", safe_strerror (errno));
continue;
}
- ret = bgp_init_listener(sock, ainfo->ai_addr, ainfo->ai_addrlen);
+ ret = bgp_init_listener(sock_fd, ainfo->ai_addr, ainfo->ai_addrlen);
if (ret == 0)
++count;
else
- close(sock);
+ close(sock_fd);
}
freeaddrinfo (ainfo_save);
- if (count == 0)
- {
- zlog_err ("%s: no usable addresses", __func__);
- return -1;
- }
-
- return 0;
+ return count ;
}
#else /*----------------------------------------------------*/
/* Traditional IPv4 only version. */
- int sock;
+ int sock_fd;
int socklen;
struct sockaddr_in sin;
int ret, en;
@@ -197,20 +261,20 @@ bgp_open_listeners(unsigned short port, const char *address)
sin.sin_len = socklen;
#endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
- sock = socket (AF_INET, SOCK_STREAM, 0);
- if (sock < 0)
+ sock_fd = socket (AF_INET, SOCK_STREAM, 0);
+ if (sock_fd < 0)
{
zlog_err ("socket: %s", safe_strerror (errno));
- return sock;
+ return sock_fd;
}
- ret = bgp_init_listener (sock, (struct sockaddr *) &sin, socklen);
+ ret = bgp_init_listener (sock_fd, (struct sockaddr *) &sin, socklen);
if (ret < 0)
{
- close (sock);
+ close (sock_fd);
return ret;
}
- return sock;
+ return sock_fd;
}
#endif /* HAVE_IPV6 && !NRL --------------------------------------------------*/
@@ -264,57 +328,65 @@ bgp_reset_listeners(bgp_listener* p_listener)
* != 0 : error number (from errno or otherwise)
*/
static int
-bgp_init_listener(int sock, struct sockaddr *sa, socklen_t salen)
+bgp_init_listener(int sock_fd, struct sockaddr *sa, socklen_t salen)
{
bgp_listener listener ;
- int ret ;
+ int ret, err ;
- ret = bgp_socket_set_common_options(sock, (union sockunion*)sa, 0, NULL) ;
- if (ret != 0)
- return ret ;
+ err = bgp_socket_set_common_options(sock_fd, (union sockunion*)sa, 0, NULL) ;
+ if (err != 0)
+ return err ;
-#ifdef IPV6_V6ONLY
- /* Want only IPV6 on ipv6 socket (not mapped addresses) */
+#if defined(HAVE_IPV6) && defined(IPV6_V6ONLY)
+ /* Want only IPV6 on ipv6 socket (not mapped addresses)
+ *
+ * This distinguishes 0.0.0.0 from :: -- without this, bind() will reject the
+ * attempt to bind to :: after binding to 0.0.0.0.
+ */
if (sa->sa_family == AF_INET6)
{
int on = 1;
- /* TODO: trap errors when setting IPPROTO_IPV6, IPV6_V6ONLY ?? */
- setsockopt (sock, IPPROTO_IPV6, IPV6_V6ONLY, (void *)&on, sizeof(on)) ;
+ ret = setsockopt (sock_fd, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on));
+ if (ret < 0)
+ return errno ;
}
#endif
if (bgpd_privs.change(ZPRIVS_RAISE))
{
- ret = errno ;
- zlog_err("%s: could not raise privs", __func__);
-
- return ret ;
+ err = errno ;
+ zlog_err("%s: could not raise privs: %s", __func__, safe_strerror(errno));
} ;
- ret = bind(sock, sa, salen) ;
+ ret = bind(sock_fd, sa, salen) ;
if (ret < 0)
{
- ret = errno ;
- zlog_err ("bind: %s", safe_strerror(ret));
+ err = errno ;
+ zlog_err ("%s: bind: %s", __func__, safe_strerror(err));
} ;
if (bgpd_privs.change(ZPRIVS_LOWER))
{
- if (ret == 0)
- ret = errno ;
- zlog_err("%s: could not lower privs", __func__) ;
+ if (err == 0)
+ err = errno ;
+ zlog_err("%s: could not lower privs: %s", __func__, safe_strerror(errno));
} ;
- if (ret != 0)
- return ret ;
+ if (err == 0)
+ {
+ ret = listen (sock_fd, 43);
+ if (ret < 0)
+ {
+ err = errno ;
+ zlog_err ("%s: listen: %s", __func__, safe_strerror(err)) ;
+ }
+ } ;
- ret = listen (sock, 3);
- if (ret < 0)
+ if (err != 0)
{
- ret = errno ;
- zlog_err ("listen: %s", safe_strerror(ret)) ;
- return ret;
- }
+ close(sock_fd) ;
+ return err ;
+ } ;
/* Having successfully opened the listener, record it so that can be found
* again, add it to the BGP Engine Nexus file selection and enable it for
@@ -324,7 +396,7 @@ bgp_init_listener(int sock, struct sockaddr *sa, socklen_t salen)
listener = XCALLOC(MTYPE_BGP_LISTENER, sizeof(struct bgp_listener)) ;
qps_file_init_new(&listener->qf, NULL) ;
- qps_add_file(bgp_nexus->selection, &listener->qf, sock, listener) ;
+ qps_add_file(bgp_nexus->selection, &listener->qf, sock_fd, listener) ;
qps_enable_mode(&listener->qf, qps_read_mnum, bgp_accept_action) ;
memcpy(&listener->su, sa, salen) ;
@@ -352,11 +424,11 @@ bgp_init_listener(int sock, struct sockaddr *sa, socklen_t salen)
extern void
bgp_prepare_to_accept(bgp_connection connection)
{
- int ret ;
+ int err ;
if (connection->session->password != NULL)
{
- ret = bgp_md5_set_listeners(connection->session->su_peer,
+ err = bgp_md5_set_listeners(connection->session->su_peer,
connection->session->password) ;
/* TODO: failure to set password in bgp_prepare_to_accept ? */
@@ -376,11 +448,11 @@ bgp_prepare_to_accept(bgp_connection connection)
extern void
bgp_not_prepared_to_accept(bgp_connection connection)
{
- int ret ;
+ int err ;
if (connection->session->password != NULL)
{
- ret = bgp_md5_set_listeners(connection->session->su_peer, NULL) ;
+ err = bgp_md5_set_listeners(connection->session->su_peer, NULL) ;
/* TODO: failure to clear password in bgp_not_prepared_to_accept ? */
} ;
@@ -441,17 +513,18 @@ bgp_accept_action(qps_file qf, void* file_info)
union sockunion su_remote ;
union sockunion su_local ;
int exists ;
- int fd ;
- int ret ;
+ int sock_fd ;
+ int err ;
+ int family ;
char buf[SU_ADDRSTRLEN] ;
/* Accept client connection. */
- fd = sockunion_accept(qps_file_fd(qf), &su_remote) ;
- if (fd < 0)
+ sock_fd = sockunion_accept(qps_file_fd(qf), &su_remote) ;
+ if (sock_fd < 0)
{
- if (fd == -1)
- zlog_err("[Error] BGP socket accept failed (%s)",
- safe_strerror(errno)) ;
+ err = errno ;
+ if (sock_fd == -1)
+ zlog_err("[Error] BGP socket accept failed (%s)", safe_strerror(err)) ;
return ; /* have no connection to report this to */
} ;
@@ -468,7 +541,7 @@ bgp_accept_action(qps_file qf, void* file_info)
? "[Event] BGP accept IP address %s is not accepting"
: "[Event] BGP accept IP address %s is not configured",
sockunion2str(&su_remote, buf, sizeof(buf))) ;
- close(fd) ;
+ close(sock_fd) ;
return ; /* quietly reject connection */
/* TODO: RFC recommends sending a NOTIFICATION when refusing accept() */
} ;
@@ -489,34 +562,46 @@ bgp_accept_action(qps_file qf, void* file_info)
/* Set the common socket options.
* Does not set password -- that is inherited from the listener.
*
- * If all is well, set up the listener connection, and set it ready
- * to go. Set session not to accept further inbound connections.
- *
- * Kicks the FSM with bgp_fsm_TCP_connection_open.
+ * At this point, su_remote is the value returned by accept(), so is the
+ * actual address (which may be IPv6 mapped IPv4).
*/
+ err = bgp_socket_set_common_options(sock_fd, &su_remote,
+ connection->session->ttl, NULL) ;
- ret = bgp_getsockname(fd, &su_local, &su_remote) ;
- if (ret != 0)
- ret = bgp_socket_set_common_options(fd, &su_remote,
- connection->session->ttl, NULL) ;
+ /* Get the actual socket family. */
+ if (err == 0)
+ {
+ family = sockunion_getsockfamily(sock_fd) ;
+ if (family < 0)
+ err = errno ;
+ } ;
- if (ret == 0)
- bgp_connection_open(connection, fd) ;
+ /* Get the local and remote addresses -- noting that IPv6 mapped IPv4
+ * addresses are rendered as IPv4 addresses.
+ */
+ if (err == 0)
+ err = bgp_get_names(sock_fd, &su_local, &su_remote) ;
+
+ /* If all is well, set up the accept connection, and set it ready
+ * to go. Set session not to accept further inbound connections.
+ */
+ if (err == 0)
+ bgp_connection_open(connection, sock_fd, family) ;
else
- close(fd) ;
+ close(sock_fd) ;
BGP_CONNECTION_SESSION_UNLOCK(connection) ; /*>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/
/* Now kick the FSM in an appropriate fashion */
- bgp_fsm_connect_completed(connection, ret, &su_local, &su_remote) ;
+ bgp_fsm_connect_completed(connection, err, &su_local, &su_remote) ;
} ;
/*==============================================================================
* Open BGP Connection -- connect() to the other end
*/
-static int bgp_bind_ifname(bgp_connection connection, int fd) ;
-static int bgp_bind_ifaddress(bgp_connection connection, int fd) ;
+static int bgp_bind_ifname(bgp_connection connection, int sock_fd) ;
+static int bgp_bind_ifaddress(bgp_connection connection, int sock_fd) ;
/*------------------------------------------------------------------------------
* Open BGP Connection -- connect() to the other end
@@ -533,45 +618,55 @@ static int bgp_bind_ifaddress(bgp_connection connection, int fd) ;
extern void
bgp_open_connect(bgp_connection connection)
{
- int fd ;
- int ret ;
+ int sock_fd ;
+ int err ;
+ int family ;
union sockunion* su = connection->session->su_peer ;
+ err = 0 ;
+
/* Make socket for the connect connection. */
- fd = sockunion_socket(sockunion_family(su), SOCK_STREAM, 0) ;
- ret = (fd >= 0) ? 0 : errno ;
+ family = sockunion_family(su) ;
+ sock_fd = sockunion_socket(family, SOCK_STREAM, 0) ;
+ if (sock_fd < 0)
+ err = errno ;
/* Set the common options. */
- if (ret == 0)
- ret = bgp_socket_set_common_options(fd, su, connection->session->ttl,
+ if (err == 0)
+ err = bgp_socket_set_common_options(sock_fd, su, connection->session->ttl,
connection->session->password) ;
/* Bind socket. */
- if (ret == 0)
- ret = bgp_bind_ifname(connection, fd) ;
+ if (err == 0)
+ err = bgp_bind_ifname(connection, sock_fd) ;
/* Update source bind. */
- if (ret == 0)
- ret = bgp_bind_ifaddress(connection, fd) ;
+ if (err == 0)
+ err = bgp_bind_ifaddress(connection, sock_fd) ;
if (BGP_DEBUG(events, EVENTS))
- plog_debug(connection->log, "%s [Event] Connect start to %s fd %d",
- connection->host, connection->host, fd);
+ plog_debug(connection->log, "%s [Event] Connect start to %s socket %d",
+ connection->host, connection->host, sock_fd);
/* Connect to the remote peer. */
- if (ret == 0)
- ret = sockunion_connect(fd, su, connection->session->port,
+ if (err == 0)
+ {
+ int ret ;
+ ret = sockunion_connect(sock_fd, su, connection->session->port,
connection->session->ifindex) ;
/* does not report EINPROGRESS as an error. */
+ if (ret < 0)
+ err = errno ;
+ } ;
- /* If not OK now, close the fd and signal the error */
+ /* If not OK now, close the sock_fd and signal the error */
- if (ret != 0)
+ if (err != 0)
{
- if (fd >= 0)
- close(fd) ;
+ if (sock_fd >= 0)
+ close(sock_fd) ;
- bgp_fsm_connect_completed(connection, ret, NULL, NULL) ;
+ bgp_fsm_connect_completed(connection, err, NULL, NULL) ;
return ;
} ;
@@ -584,15 +679,15 @@ bgp_open_connect(bgp_connection connection)
* up immediately).
* if fails: will become readable (may also become writable)
*
- * Generally, expect it to be a while before the fd becomes readable or
+ * Generally, expect it to be a while before the sock_fd becomes readable or
* writable. But for local connections this may happen immediately. But,
* in any case, this will be handled by the qpselect action.
*/
- bgp_connection_open(connection, fd) ;
+ bgp_connection_open(connection, sock_fd, family) ;
- qps_enable_mode(&connection->qf, qps_read_mnum, bgp_connect_action) ;
- qps_enable_mode(&connection->qf, qps_write_mnum, bgp_connect_action) ;
+ qps_enable_mode(connection->qf, qps_read_mnum, bgp_connect_action) ;
+ qps_enable_mode(connection->qf, qps_write_mnum, bgp_connect_action) ;
return ;
} ;
@@ -609,6 +704,11 @@ bgp_open_connect(bgp_connection connection)
*
* Either way, use getsockopt() to extract any error condition.
*
+ * If becomes both readable and writable at the same time, then the first to
+ * arrive here will disable the file for both read and write, which will
+ * discard the other pending event -- so will not attempt to do this more than
+ * once.
+ *
* NB: does not require the session mutex.
*
* Events and Errors:
@@ -634,7 +734,7 @@ bgp_connect_action(qps_file qf, void* file_info)
{
bgp_connection connection ;
int ret, err ;
- socklen_t len = sizeof(err) ;
+ socklen_t len ;
union sockunion su_remote ;
union sockunion su_local ;
@@ -643,54 +743,73 @@ bgp_connect_action(qps_file qf, void* file_info)
/* See if connection successful or not. */
/* If successful, set the connection->su_local and ->su_remote */
+ len = sizeof(err) ;
+ err = 0 ;
ret = getsockopt(qps_file_fd(qf), SOL_SOCKET, SO_ERROR, &err, &len) ;
- if (ret != 0)
- ret = errno ;
- else if (len != sizeof(err))
- zabort("getsockopt returned unexpected length") ;
- else if (err != 0)
- ret = err ;
+ if (ret != 0)
+ {
+ err = errno ;
+ if (err == 0) /* cannot be and cannot continue */
+ zabort("Invalid return from getsockopt()") ;
+ }
else
- ret = bgp_getsockname(qps_file_fd(qf), &su_local, &su_remote) ;
+ {
+ if (len != sizeof(err))
+ zabort("getsockopt returned unexpected length") ;
+ } ;
+
+ if (err == 0)
+ err = bgp_get_names(qps_file_fd(qf), &su_local, &su_remote) ;
/* In any case, disable both read and write for this file. */
qps_disable_modes(qf, qps_write_mbit | qps_read_mbit) ;
/* Now kick the FSM in an appropriate fashion */
- bgp_fsm_connect_completed(connection, ret, &su_local, &su_remote) ;
+ bgp_fsm_connect_completed(connection, err, &su_local, &su_remote) ;
} ;
/*==============================================================================
- * Set the TTL for the given connection (if any), if there is an fd.
+ * Set the TTL for the given connection (if any), if there is an sock_fd.
*/
extern void
bgp_set_ttl(bgp_connection connection, int ttl)
{
- int fd ;
+ int sock_fd ;
if (connection == NULL)
return ;
- fd = qps_file_fd(&connection->qf) ;
- if (fd < 0)
+ sock_fd = qps_file_fd(connection->qf) ;
+ if (sock_fd < 0)
return ;
if (ttl != 0)
- sockopt_ttl(connection->paf, fd, ttl) ;
+ sockopt_ttl(sock_fd, ttl) ;
} ;
/*==============================================================================
* Get local and remote address and port for connection.
+ *
+ * Returns: 0 => OK
+ * != 0 : error number (from errno or otherwise)
*/
static int
-bgp_getsockname(int fd, union sockunion* su_local, union sockunion* su_remote)
+bgp_get_names(int sock_fd, union sockunion* su_local,
+ union sockunion* su_remote)
{
- int ret_l, ret_r ;
+ int ret, err ;
- ret_l = sockunion_getsockname(fd, su_local) ;
- ret_r = sockunion_getpeername(fd, su_remote) ;
+ err = 0 ;
- return (ret_l != 0) ? ret_l : ret_r ;
+ ret = sockunion_getsockname(sock_fd, su_local) ;
+ if (ret < 0)
+ err = errno ;
+
+ ret = sockunion_getpeername(sock_fd, su_remote) ;
+ if ((ret < 0) && (err == 0))
+ err = errno ;
+
+ return err ;
} ;
/*==============================================================================
@@ -704,44 +823,46 @@ bgp_getsockname(int fd, union sockunion* su_local, union sockunion* su_remote)
* If there is a specific interface to bind an outbound connection to, that
* is done here.
*
- *
* Returns: 0 : OK (so far so good)
* != 0 : error number (from errno or otherwise)
*/
static int
-bgp_bind_ifname(bgp_connection connection, int fd)
+bgp_bind_ifname(bgp_connection connection, int sock_fd)
{
#ifdef SO_BINDTODEVICE
- int ret, retp ;
+ int ret, err ;
struct ifreq ifreq;
if (connection->session->ifname == NULL)
return 0;
strncpy ((char *)&ifreq.ifr_name, connection->session->ifname,
- sizeof (ifreq.ifr_name));
+ sizeof (ifreq.ifr_name)) ;
- ret = 0 ;
- retp = 0 ;
+ err = 0 ;
if (bgpd_privs.change (ZPRIVS_RAISE))
{
- zlog_err ("bgp_bind: could not raise privs");
- retp = -1 ;
+ err = errno ;
+ zlog_err ("bgp_bind: could not raise privs: %s", safe_strerror(errno));
} ;
- ret = setsockopt (fd, SOL_SOCKET, SO_BINDTODEVICE, &ifreq, sizeof (ifreq));
+ ret = setsockopt (sock_fd, SOL_SOCKET, SO_BINDTODEVICE,
+ &ifreq, sizeof (ifreq)) ;
+ if (ret < 0)
+ err = errno ;
if (bgpd_privs.change (ZPRIVS_LOWER) )
{
- zlog_err ("bgp_bind: could not lower privs");
- retp = -1 ;
+ if (err == 0)
+ err = errno ;
+ zlog_err ("bgp_bind: could not lower privs: %s", safe_strerror(errno));
} ;
- if ((ret < 0) || (retp < 0))
+ if (err != 0)
{
- zlog (connection->log, LOG_INFO, "bind to interface %s failed",
- connection->session->ifname);
- return -1 ;
+ zlog (connection->log, LOG_INFO, "bind to interface %s failed (%s)",
+ connection->session->ifname, safe_strerror(err));
+ return err ;
}
#endif /* SO_BINDTODEVICE */
return 0;
@@ -754,12 +875,34 @@ bgp_bind_ifname(bgp_connection connection, int fd)
* != 0 : error number (from errno or otherwise)
*/
static int
-bgp_bind_ifaddress(bgp_connection connection, int fd)
+bgp_bind_ifaddress(bgp_connection connection, int sock_fd)
{
if (connection->session->ifaddress != NULL)
{
- union sockunion su = *(connection->session->ifaddress) ;
- return sockunion_bind (fd, &su, 0, &su) ;
+ union sockunion su ;
+ int ret ;
+ int family ;
+
+ sockunion_new_sockaddr(&su, &connection->session->ifaddress->sa) ;
+
+ family = sockunion_getsockfamily(sock_fd) ;
+ if (family < 0)
+ return errno ;
+
+#ifdef HAVE_IPV6
+ if (family != sockunion_family(&su))
+ {
+ if (family == AF_INET)
+ sockunion_unmap_ipv4(&su) ;
+ if (family == AF_INET6)
+ sockunion_map_ipv4(&su) ;
+ } ;
+#endif
+
+ ret = sockunion_bind (sock_fd, &su, 0, &su) ;
+
+ if (ret < 0)
+ return errno ;
} ;
return 0 ;
} ;
@@ -769,7 +912,7 @@ bgp_bind_ifaddress(bgp_connection connection, int fd)
*/
static int
-bgp_md5_set_socket(int fd, union sockunion *su, const char *password) ;
+bgp_md5_set_socket(int sock_fd, union sockunion *su, const char *password) ;
/*------------------------------------------------------------------------------
* Common socket options:
@@ -787,39 +930,39 @@ bgp_md5_set_socket(int fd, union sockunion *su, const char *password) ;
* != 0 == errno -- not that we really expect any errors here
*/
static int
-bgp_socket_set_common_options(int fd, union sockunion* su, int ttl,
+bgp_socket_set_common_options(int sock_fd, union sockunion* su, int ttl,
const char* password)
{
- int ret ;
+ int err ;
int val ;
/* Make socket non-blocking */
- val = fcntl(fd, F_GETFL, 0) ;
- if (val != -1) /* Don't really expect it to be -1 (see POSIX) */
- val = fcntl(fd, F_SETFL, val | O_NONBLOCK) ;
+ val = fcntl(sock_fd, F_GETFL, 0) ;
+ if (val != -1) /* POSIX says "return value is not negative" */
+ val = fcntl(sock_fd, F_SETFL, val | O_NONBLOCK) ;
if (val == -1)
return errno ;
/* Reuse addr and port */
- if (sockopt_reuseaddr(fd) < 0)
+ if (sockopt_reuseaddr(sock_fd) < 0)
return errno ;
- if (sockopt_reuseport(fd) < 0)
+ if (sockopt_reuseport(sock_fd) < 0)
return errno ;
/* Adjust ttl if required */
if (ttl != 0)
- if ((ret = sockopt_ttl(sockunion_family(su), fd, ttl)) != 0)
- return ret ;
+ if (sockopt_ttl(sock_fd, ttl) != 0)
+ return errno ;
/* Set the TCP MD5 "password", if required. */
if (password != NULL)
- if ((ret = bgp_md5_set_socket(fd, su, password)) != 0)
- return ret ;
+ if ((err = bgp_md5_set_socket(sock_fd, su, password)) != 0)
+ return err ;
#ifdef IPTOS_PREC_INTERNETCONTROL
/* set IPPROTO_IP/IP_TOS -- if is AF_INET */
if (sockunion_family(su) == AF_INET)
- if (setsockopt_ipv4_tos(fd, IPTOS_PREC_INTERNETCONTROL) < 0)
+ if (setsockopt_ipv4_tos(sock_fd, IPTOS_PREC_INTERNETCONTROL) < 0)
return errno ;
#endif
@@ -840,34 +983,36 @@ bgp_socket_set_common_options(int fd, union sockunion* su, int ttl,
* NB: has to change up privileges, which can fail (if things are badly set up)
*/
static int
-bgp_md5_set_socket(int fd, union sockunion *su, const char *password)
+bgp_md5_set_socket(int sock_fd, union sockunion *su, const char *password)
{
- int ret ;
+ int err, ret ;
- assert(fd >= 0) ;
+ assert(sock_fd >= 0) ;
+
+ err = 0 ;
if (bgpd_privs.change(ZPRIVS_RAISE))
{
- ret = errno ;
- zlog_err("%s: could not raise privs", __func__);
-
- return ret ;
+ err = errno ;
+ zlog_err("%s: could not raise privs: %s", __func__, safe_strerror(errno));
} ;
- ret = sockopt_tcp_signature(fd, su, password) ;
+ ret = sockopt_tcp_signature(sock_fd, su, password) ;
if (ret != 0) /* TODO: error already logged as zlog_err() */
- zlog (NULL, LOG_WARNING, "can't set TCP_MD5SIG option on socket %d: %s",
- fd, safe_strerror(ret));
+ err = errno ;
if (bgpd_privs.change(ZPRIVS_LOWER))
{
- if (ret == 0)
- ret = errno ;
- zlog_err("%s: could not lower privs", __func__) ;
+ if (err == 0)
+ err = errno ;
+ zlog_err("%s: could not lower privs: %s", __func__, safe_strerror(errno));
} ;
- return ret;
+ if (err != 0)
+ zlog (NULL, LOG_WARNING, "cannot set TCP_MD5SIG option on socket %d: %s",
+ sock_fd, safe_strerror(err)) ;
+ return err ;
} ;
/*------------------------------------------------------------------------------
@@ -891,7 +1036,7 @@ static int
bgp_md5_set_listeners(union sockunion* su, const char* password)
{
bgp_listener listener ;
- int ret ;
+ int err ;
#ifdef HAVE_IPV6
assert((su->sa.sa_family == AF_INET) || (su->sa.sa_family == AF_INET6)) ;
@@ -903,9 +1048,9 @@ bgp_md5_set_listeners(union sockunion* su, const char* password)
while (listener != NULL)
{
- ret = bgp_md5_set_socket(qps_file_fd(&listener->qf), su, password) ;
- if (ret != 0)
- return ret ;
+ err = bgp_md5_set_socket(qps_file_fd(&listener->qf), su, password) ;
+ if (err != 0)
+ return err ;
listener = listener->next ;
} ;