Blob Blame History Raw
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;
 
 }