commit edabd027144c2a9fcd44a997f47981b836b53b77
Author: David Vossel <dvossel@redhat.com>
Date: Wed Nov 6 13:27:11 2013 -0500
High: remote: Add support for ipv6 into pacemaker_remote daemon
(cherry picked from commit 1595263ff56ac14cc697d9866b532c14267d708f)
diff --git a/lrmd/tls_backend.c b/lrmd/tls_backend.c
index 780d17b..46e7f27 100644
--- a/lrmd/tls_backend.c
+++ b/lrmd/tls_backend.c
@@ -30,6 +30,7 @@
#include <lrmd_private.h>
+#include <netdb.h>
#include <sys/socket.h>
#include <netinet/ip.h>
#include <arpa/inet.h>
@@ -38,7 +39,7 @@
# define LRMD_REMOTE_AUTH_TIMEOUT 10000
gnutls_psk_server_credentials_t psk_cred_s;
gnutls_dh_params_t dh_params;
-static int ssock = 0;
+static int ssock = -1;
extern int lrmd_call_id;
static void
@@ -253,12 +254,72 @@ lrmd_tls_server_key_cb(gnutls_session_t session, const char *username, gnutls_da
return lrmd_tls_set_key(key);
}
+static int
+bind_and_listen(struct addrinfo *addr)
+{
+ int optval;
+ int fd;
+ int rc;
+ char buffer[256] = { 0, };
+
+ if (addr->ai_family == AF_INET6) {
+ struct sockaddr_in6 *addr_in = (struct sockaddr_in6 *)addr->ai_addr;
+ inet_ntop(addr->ai_family, &addr_in->sin6_addr, buffer, DIMOF(buffer));
+
+ } else {
+ struct sockaddr_in *addr_in = (struct sockaddr_in *)addr->ai_addr;
+ inet_ntop(addr->ai_family, &addr_in->sin_addr, buffer, DIMOF(buffer));
+ }
+
+ crm_trace("Attempting to bind on address %s", buffer);
+
+ fd = socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol);
+ if (fd < 0) {
+ return -1;
+ }
+
+ /* reuse address */
+ optval = 1;
+ rc = setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval));
+ if (rc < 0) {
+ crm_perror(LOG_INFO, "Couldn't allow the reuse of local addresses by our remote listener, bind address %s", buffer);
+ close(fd);
+ return -1;
+ }
+
+ if (addr->ai_family == AF_INET6) {
+ optval = 0;
+ rc = setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &optval, sizeof(optval));
+ if (rc < 0) {
+ crm_perror(LOG_INFO, "Couldn't disable IPV6 only on address %s", buffer);
+ close(fd);
+ return -1;
+ }
+ }
+
+ if (bind(fd, addr->ai_addr, addr->ai_addrlen) != 0) {
+ close(fd);
+ return -1;
+ }
+
+ if (listen(fd, 10) == -1) {
+ crm_err("Can not start listen on address %s", buffer);
+ close(fd);
+ return -1;
+ }
+
+ crm_notice("Listening on address %s", buffer);
+
+ return fd;
+}
+
int
lrmd_init_remote_tls_server(int port)
{
int rc;
- struct sockaddr_in saddr;
- int optval;
+ int filter;
+ struct addrinfo hints, *res = NULL, *iter;
+ char port_str[16];
static struct mainloop_fd_callbacks remote_listen_fd_callbacks = {
.dispatch = lrmd_remote_listen,
@@ -275,34 +336,39 @@ lrmd_init_remote_tls_server(int port)
gnutls_psk_set_server_credentials_function(psk_cred_s, lrmd_tls_server_key_cb);
gnutls_psk_set_server_dh_params(psk_cred_s, dh_params);
- /* create server socket */
- ssock = socket(AF_INET, SOCK_STREAM, 0);
- if (ssock == -1) {
- crm_err("Can not create server socket.");
- return -1;
- }
+ memset(&hints, 0, sizeof(struct addrinfo));
+ hints.ai_flags = AI_PASSIVE; /* Only return socket addresses with wildcard INADDR_ANY or IN6ADDR_ANY_INIT */
+ hints.ai_family = AF_UNSPEC; /* Return IPv6 or IPv4 */
+ hints.ai_socktype = SOCK_STREAM;
+ hints.ai_protocol = IPPROTO_TCP;
- /* reuse address */
- optval = 1;
- rc = setsockopt(ssock, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval));
- if (rc < 0) {
- crm_perror(LOG_INFO, "Couldn't allow the reuse of local addresses by our remote listener");
+ snprintf(port_str, sizeof(port_str), "%d", port);
+ rc = getaddrinfo(NULL, port_str, &hints, &res);
+ if (rc) {
+ crm_err("getaddrinfo: %s", gai_strerror(rc));
+ return -1;
}
- rc = -1;
+ iter = res;
+ filter = AF_INET6;
+ /* Try IPv6 addresses first, then IPv4 */
+ while (iter) {
+ if (iter->ai_family == filter) {
+ ssock = bind_and_listen(iter);
+ }
+ if (ssock != -1) {
+ break;
+ }
- /* bind server socket */
- memset(&saddr, '\0', sizeof(saddr));
- saddr.sin_family = AF_INET;
- saddr.sin_addr.s_addr = INADDR_ANY;
- saddr.sin_port = htons(port);
- if (bind(ssock, (struct sockaddr *)&saddr, sizeof(saddr)) == -1) {
- crm_err("Can not bind server socket.");
- goto init_remote_cleanup;
+ iter = iter->ai_next;
+ if (iter == NULL && filter == AF_INET6) {
+ iter = res;
+ filter = AF_INET;
+ }
}
- if (listen(ssock, 10) == -1) {
- crm_err("Can not start listen.");
+ if (ssock < 0) {
+ crm_err("unable to bind to address");
goto init_remote_cleanup;
}
@@ -314,6 +380,7 @@ lrmd_init_remote_tls_server(int port)
close(ssock);
ssock = 0;
}
+ freeaddrinfo(res);
return rc;
}