Blame SOURCES/bz720543-pcmk-pcmk_remote_ipv6_support.patch

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