IPV6: Add basic IPv6 support
authorRonnie Sahlberg <ronniesahlberg@gmail.com>
Sun, 16 Mar 2014 16:12:49 +0000 (09:12 -0700)
committerRonnie Sahlberg <ronniesahlberg@gmail.com>
Thu, 20 Mar 2014 01:25:49 +0000 (18:25 -0700)
This adds basic IPv6 support to libnfs.
Since libnfs currently only support PORTMAPPER protocol up to version 2
the IPv6 support only works if the server runs Both MOUNT and NFS protocols
on the same ports for IPv6 as for IPv4.

To get full IPv6 support we need to add support for PORTMAPPER version 3
and use it for discovery when using IPv6

lib/socket.c

index 055109a73c9f7b4be1f69d73f0552feb5c2d51ff..d025e070e017091e1f796178c139e8ff44c7cf48 100644 (file)
@@ -80,7 +80,6 @@
 #include "win32_errnowrapper.h"
 #endif
 
-
 static int rpc_reconnect_requeue(struct rpc_context *rpc);
 static int rpc_connect_sockaddr_async(struct rpc_context *rpc, struct sockaddr_storage *s);
 
@@ -418,6 +417,15 @@ static int rpc_connect_sockaddr_async(struct rpc_context *rpc, struct sockaddr_s
                if (rpc->tcp_syncnt != RPC_PARAM_UNDEFINED) {
                        set_tcp_sockopt(rpc->fd, TCP_SYNCNT, rpc->tcp_syncnt);
                }
+#endif
+               break;
+       case AF_INET6:
+               socksize = sizeof(struct sockaddr_in6);
+               rpc->fd = socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP);
+#ifdef HAVE_NETINET_TCP_H
+               if (rpc->tcp_syncnt != RPC_PARAM_UNDEFINED) {
+                       set_tcp_sockopt(rpc->fd, TCP_SYNCNT, rpc->tcp_syncnt);
+               }
 #endif
                break;
        default:
@@ -449,7 +457,7 @@ static int rpc_connect_sockaddr_async(struct rpc_context *rpc, struct sockaddr_s
         * binding will usually succeed.
         */
        {
-               struct sockaddr_in sin;
+               struct sockaddr_storage ss;
                static int portOfs = 0;
                const int firstPort = 512;      /* >= 512 according to Sun docs */
                const int portCount = IPPORT_RESERVED - firstPort;
@@ -466,12 +474,26 @@ static int rpc_connect_sockaddr_async(struct rpc_context *rpc, struct sockaddr_s
 
                        /* skip well-known ports */
                        if (!getservbyport(port, "tcp")) {
-                               memset(&sin, 0, sizeof(sin));
-                               sin.sin_port        = port;
-                               sin.sin_family      = AF_INET;
-                               sin.sin_addr.s_addr = 0;
+                               memset(&ss, 0, sizeof(ss));
+
+                               switch (s->ss_family) {
+                               case AF_INET:
+                                       ((struct sockaddr_in *)&ss)->sin_port = port;
+                                       ((struct sockaddr_in *)&ss)->sin_family      = AF_INET;
+#ifdef HAVE_SOCKADDR_LEN
+                                       ((struct sockaddr_in *)&ss)->sin_len = sizeof(struct sockaddr_in);
+#endif
+                                       break;
+                               case AF_INET6:
+                                       ((struct sockaddr_in6 *)&ss)->sin6_port = port;
+                                       ((struct sockaddr_in6 *)&ss)->sin6_family      = AF_INET6;
+#ifdef HAVE_SOCKADDR_LEN
+                                       ((struct sockaddr_in6 *)&ss)->sin6_len = sizeof(struct sockaddr_in);
+#endif
+                                       break;
+                               }
 
-                               rc = bind(rpc->fd, (struct sockaddr *)&sin, sizeof(struct sockaddr_in));
+                               rc = bind(rpc->fd, (struct sockaddr *)&ss, socksize);
 #if !defined(WIN32)
                                /* we got EACCES, so don't try again */
                                if (rc != 0 && errno == EACCES)
@@ -493,7 +515,7 @@ static int rpc_connect_sockaddr_async(struct rpc_context *rpc, struct sockaddr_s
 
 int rpc_connect_async(struct rpc_context *rpc, const char *server, int port, rpc_cb cb, void *private_data)
 {
-       struct sockaddr_in *sin = (struct sockaddr_in *)&rpc->s;
+       struct addrinfo *ai = NULL;
 
        assert(rpc->magic == RPC_CONTEXT_MAGIC);
 
@@ -509,18 +531,25 @@ int rpc_connect_async(struct rpc_context *rpc, const char *server, int port, rpc
 
        rpc->auto_reconnect = 0;
 
-       sin->sin_family = AF_INET;
-       sin->sin_port   = htons(port);
-       if (inet_pton(AF_INET, server, &sin->sin_addr) != 1) {
-               rpc_set_error(rpc, "Not a valid server ip address");
+       if (getaddrinfo(server, NULL, NULL, &ai) != 0) {
+               rpc_set_error(rpc, "Invalid address:%s. "
+                             "Can not resolv into IPv4/v6 structure.", server);
                return -1;
-       }
-
+       }
 
-       switch (rpc->s.ss_family) {
+       switch (ai->ai_family) {
        case AF_INET:
+               ((struct sockaddr_in *)&rpc->s)->sin_family = ai->ai_family;
+               ((struct sockaddr_in *)&rpc->s)->sin_port   = htons(port);
+#ifdef HAVE_SOCKADDR_LEN
+               ((struct sockaddr_in *)&rpc->s)->sin_len = sizeof(struct sockaddr_in);
+#endif
+               break;
+       case AF_INET6:
+               ((struct sockaddr_in6 *)&rpc->s)->sin6_family = ai->ai_family;
+               ((struct sockaddr_in6 *)&rpc->s)->sin6_port   = htons(port);
 #ifdef HAVE_SOCKADDR_LEN
-               sin->sin_len = sizeof(struct sockaddr_in);
+               ((struct sockaddr_in6 *)&rpc->s)->sin6_len = sizeof(struct sockaddr_in6);
 #endif
                break;
        }
@@ -528,6 +557,8 @@ int rpc_connect_async(struct rpc_context *rpc, const char *server, int port, rpc
        rpc->connect_cb  = cb;
        rpc->connect_data = private_data;
 
+       freeaddrinfo(ai);
+
        if (rpc_connect_sockaddr_async(rpc, &rpc->s) != 0) {
                return -1;
        }