summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStephen Hemminger <shemminger@vyatta.com>2009-07-21 16:27:21 -0700
committerPaul Jakma <paul@quagga.net>2009-07-28 10:04:38 +0100
commitd023aec49f70156d2ed894a8fba65bcfa221ff02 (patch)
tree00ab5d69481c212b6ed2f350c5a5c7f430ef9208
parent03621955d8ab0ea30024bd8fc83afda8e48db712 (diff)
bgpd: start listener on first instance
Start BGP listener only after first instance is started. This helps the security if BGP is not used but daemon is started. It also addresses some issues like MD5 not working on listener unless IPV6 configured (because listener was not in list); as well as compiler warnings. * bgp_network.c: (bgp_listener) listen socket creation consolidated here (bgp_socket) Use bgp_listener * bgpd.c: (bgp_get) call bgp_socket on creation of first struct bgp. (bgp_init) remove bgp_socket call. * memtypes.c: Add MTYPE_BGP_LISTENER
-rw-r--r--bgpd/bgp_network.c190
-rw-r--r--bgpd/bgp_network.h3
-rw-r--r--bgpd/bgpd.c14
-rw-r--r--lib/memtypes.c1
4 files changed, 114 insertions, 94 deletions
diff --git a/bgpd/bgp_network.c b/bgpd/bgp_network.c
index 77847008..ade0fbc6 100644
--- a/bgpd/bgp_network.c
+++ b/bgpd/bgp_network.c
@@ -39,6 +39,13 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
extern struct zebra_privs_t bgpd_privs;
+/* BGP listening socket. */
+struct bgp_listener
+{
+ int fd;
+ union sockunion su;
+ struct thread *thread;
+};
/*
* Set MD5 key for the socket, for the given IPv4 peer address.
@@ -365,37 +372,90 @@ bgp_getsockname (struct peer *peer)
bgp_nexthop_set (peer->su_local, peer->su_remote, &peer->nexthop, peer);
}
+
+static int
+bgp_listener (int sock, struct sockaddr *sa, socklen_t salen)
+{
+ struct bgp_listener *listener;
+ int ret, en;
+
+ sockopt_reuseaddr (sock);
+ sockopt_reuseport (sock);
+
+#ifdef IPTOS_PREC_INTERNETCONTROL
+ if (sa->sa_family == AF_INET)
+ setsockopt_ipv4_tos (sock, IPTOS_PREC_INTERNETCONTROL);
+#endif
+
+#ifdef IPV6_V6ONLY
+ /* Want only IPV6 on ipv6 socket (not mapped addresses) */
+ if (sa->sa_family == AF_INET6) {
+ int on = 1;
+ setsockopt (sock, IPPROTO_IPV6, IPV6_V6ONLY,
+ (void *) &on, sizeof (on));
+ }
+#endif
+
+ if (bgpd_privs.change (ZPRIVS_RAISE) )
+ zlog_err ("bgp_socket: could not raise privs");
+
+ ret = bind (sock, sa, salen);
+ 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));
+ return ret;
+ }
+
+ ret = listen (sock, 3);
+ if (ret < 0)
+ {
+ zlog_err ("listen: %s", safe_strerror (errno));
+ return ret;
+ }
+
+ listener = XMALLOC (MTYPE_BGP_LISTENER, sizeof(*listener));
+ listener->fd = sock;
+ memcpy(&listener->su, sa, salen);
+ listener->thread = thread_add_read (master, bgp_accept, listener, sock);
+ listnode_add (bm->listen_sockets, listener);
+
+ return 0;
+}
+
/* IPv6 supported version of BGP server socket setup. */
#if defined (HAVE_IPV6) && ! defined (NRL)
int
-bgp_socket (struct bgp *bgp, unsigned short port, char *address)
+bgp_socket (unsigned short port, const char *address)
{
- int ret, en;
- struct addrinfo req;
struct addrinfo *ainfo;
struct addrinfo *ainfo_save;
- int sock = 0;
+ static const struct addrinfo req = {
+ .ai_family = AF_UNSPEC,
+ .ai_flags = AI_PASSIVE,
+ .ai_socktype = SOCK_STREAM,
+ };
+ int ret, count;
char port_str[BUFSIZ];
- memset (&req, 0, sizeof (struct addrinfo));
-
- req.ai_flags = AI_PASSIVE;
- req.ai_family = AF_UNSPEC;
- req.ai_socktype = SOCK_STREAM;
snprintf (port_str, sizeof(port_str), "%d", port);
port_str[sizeof (port_str) - 1] = '\0';
- ret = getaddrinfo (address, port_str, &req, &ainfo);
+ ret = getaddrinfo (address, port_str, &req, &ainfo_save);
if (ret != 0)
{
zlog_err ("getaddrinfo: %s", gai_strerror (ret));
return -1;
}
- ainfo_save = ainfo;
-
- do
+ count = 0;
+ for (ainfo = ainfo_save; ainfo; ainfo = ainfo->ai_next)
{
+ int sock;
+
if (ainfo->ai_family != AF_INET && ainfo->ai_family != AF_INET6)
continue;
@@ -406,59 +466,25 @@ bgp_socket (struct bgp *bgp, unsigned short port, char *address)
continue;
}
- sockopt_reuseaddr (sock);
- sockopt_reuseport (sock);
-
-#ifdef IPTOS_PREC_INTERNETCONTROL
- if (ainfo->ai_family == AF_INET)
- setsockopt_ipv4_tos (sock, IPTOS_PREC_INTERNETCONTROL);
-#endif
-
-#ifdef IPV6_V6ONLY
- /* Want only IPV6 on ipv6 socket (not mapped addresses) */
- if (ainfo->ai_family == AF_INET6) {
- int on = 1;
- setsockopt (sock, IPPROTO_IPV6, IPV6_V6ONLY,
- (void *) &on, sizeof (on));
- }
-#endif
-
- if (bgpd_privs.change (ZPRIVS_RAISE) )
- zlog_err ("bgp_socket: could not raise privs");
-
- ret = bind (sock, ainfo->ai_addr, ainfo->ai_addrlen);
- 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;
- }
-
- listnode_add (bm->listen_sockets, (void *)(long)sock);
- thread_add_read (master, bgp_accept, bgp, sock);
+ ret = bgp_listener (sock, ainfo->ai_addr, ainfo->ai_addrlen);
+ if (ret == 0)
+ ++count;
+ else
+ close(sock);
}
- while ((ainfo = ainfo->ai_next) != NULL);
-
freeaddrinfo (ainfo_save);
+ if (count == 0)
+ {
+ zlog_err ("%s: no usable addresses", __func__);
+ return -1;
+ }
- return sock;
+ return 0;
}
#else
/* Traditional IPv4 only version. */
int
-bgp_socket (struct bgp *bgp, unsigned short port, char *address)
+bgp_socket (unsigned short port, const char *address)
{
int sock;
int socklen;
@@ -472,15 +498,7 @@ bgp_socket (struct bgp *bgp, unsigned short port, char *address)
return sock;
}
- sockopt_reuseaddr (sock);
- sockopt_reuseport (sock);
-
-#ifdef IPTOS_PREC_INTERNETCONTROL
- setsockopt_ipv4_tos (sock, IPTOS_PREC_INTERNETCONTROL);
-#endif
-
memset (&sin, 0, sizeof (struct sockaddr_in));
-
sin.sin_family = AF_INET;
sin.sin_port = htons (port);
socklen = sizeof (struct sockaddr_in);
@@ -495,33 +513,27 @@ bgp_socket (struct bgp *bgp, unsigned short port, char *address)
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_socket: could not lower privs");
-
- if (ret < 0)
- {
- zlog_err ("bind: %s", safe_strerror (en));
- close (sock);
- return ret;
- }
-
- ret = listen (sock, 3);
+ ret = bgp_listener (sock, (struct sockaddr *) &sin, socklen);
if (ret < 0)
{
- zlog_err ("listen: %s", safe_strerror (errno));
close (sock);
return ret;
}
-
- listnode_add (bm->listen_sockets, (void *)(long)sock);
- thread_add_read (bm->master, bgp_accept, bgp, sock);
-
return sock;
}
#endif /* HAVE_IPV6 && !NRL */
+
+void
+bgp_close (void)
+{
+ struct listnode *node, *next;
+ struct bgp_listener *listener;
+
+ for (ALL_LIST_ELEMENTS (bm->listen_sockets, node, next, listener))
+ {
+ thread_cancel (listener->thread);
+ close (listener->fd);
+ listnode_delete (bm->listen_sockets, listener);
+ XFREE (MTYPE_BGP_LISTENER, listener);
+ }
+}
diff --git a/bgpd/bgp_network.h b/bgpd/bgp_network.h
index 618d8dbb..5bf2e5ff 100644
--- a/bgpd/bgp_network.h
+++ b/bgpd/bgp_network.h
@@ -21,7 +21,8 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
#ifndef _QUAGGA_BGP_NETWORK_H
#define _QUAGGA_BGP_NETWORK_H
-extern int bgp_socket (struct bgp *, unsigned short, char *);
+extern int bgp_socket (unsigned short, const char *);
+extern void bgp_close (void);
extern int bgp_connect (struct peer *);
extern void bgp_getsockname (struct peer *);
diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c
index d910956c..ef8fbe97 100644
--- a/bgpd/bgpd.c
+++ b/bgpd/bgpd.c
@@ -2036,6 +2036,13 @@ bgp_get (struct bgp **bgp_val, as_t *as, const char *name)
}
}
+ /* Create BGP server socket, if first instance. */
+ if (list_isempty(bm->bgp))
+ {
+ if (bgp_socket (bm->port, bm->address) < 0)
+ return BGP_ERR_INVALID_VALUE;
+ }
+
bgp = bgp_create (as, name);
listnode_add (bm->bgp, bgp);
bgp_router_id_set(bgp, &router_id_zebra);
@@ -2081,7 +2088,9 @@ bgp_delete (struct bgp *bgp)
* routes to be processed still referencing the struct bgp.
*/
listnode_delete (bm->bgp, bgp);
-
+ if (list_isempty(bm->bgp))
+ bgp_close ();
+
bgp_unlock(bgp); /* initial reference */
return 0;
@@ -5137,9 +5146,6 @@ bgp_init (void)
/* BGP VTY commands installation. */
bgp_vty_init ();
- /* Create BGP server socket. */
- bgp_socket (NULL, bm->port, bm->address);
-
/* Init zebra. */
bgp_zebra_init ();
diff --git a/lib/memtypes.c b/lib/memtypes.c
index dd365ddb..05d93225 100644
--- a/lib/memtypes.c
+++ b/lib/memtypes.c
@@ -91,6 +91,7 @@ struct memory_list memory_list_zebra[] =
struct memory_list memory_list_bgp[] =
{
{ MTYPE_BGP, "BGP instance" },
+ { MTYPE_BGP_LISTENER, "BGP listen socket details" },
{ MTYPE_BGP_PEER, "BGP peer" },
{ MTYPE_BGP_PEER_HOST, "BGP peer hostname" },
{ MTYPE_PEER_GROUP, "Peer group" },