afs: Allow IPv6 address specification of VL servers
authorDavid Howells <dhowells@redhat.com>
Thu, 2 Nov 2017 15:27:47 +0000 (15:27 +0000)
committerDavid Howells <dhowells@redhat.com>
Mon, 13 Nov 2017 15:38:17 +0000 (15:38 +0000)
Allow VL server specifications to be given IPv6 addresses as well as IPv4
addresses, for example as:

echo add foo.org 1111:2222:3333:0:4444:5555:6666:7777 >/proc/fs/afs/cells

Note that ':' is the expected separator for separating IPv4 addresses, but
if a ',' is detected or no '.' is detected in the string, the delimiter is
switched to ','.

This also works with DNS AFSDB or SRV record strings fetched by upcall from
userspace.

Signed-off-by: David Howells <dhowells@redhat.com>
fs/afs/cell.c
fs/afs/proc.c
fs/afs/rxrpc.c
fs/afs/server.c
fs/afs/vlclient.c

index 5523fa3c05d907927fb185af1993a1a4fbde4aef..216821fd1a610698c90a53ec3581602803c09e64 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/ctype.h>
 #include <linux/dns_resolver.h>
 #include <linux/sched.h>
+#include <linux/inet.h>
 #include <keys/rxrpc-type.h>
 #include "internal.h"
 
@@ -86,28 +87,38 @@ static struct afs_cell *afs_cell_alloc(struct afs_net *net,
                delimiter = ',';
 
        } else {
+               if (strchr(vllist, ',') || !strchr(vllist, '.'))
+                       delimiter = ',';
                _vllist = vllist;
        }
 
        /* fill in the VL server list from the rest of the string */
        do {
                struct sockaddr_rxrpc *srx = &cell->vl_addrs[cell->vl_naddrs];
-               unsigned a, b, c, d;
+               const char *end;
 
                next = strchr(_vllist, delimiter);
                if (next)
                        *next++ = 0;
 
-               if (sscanf(_vllist, "%u.%u.%u.%u", &a, &b, &c, &d) != 4)
-                       goto bad_address;
-
-               if (a > 255 || b > 255 || c > 255 || d > 255)
+               if (in4_pton(_vllist, -1, (u8 *)&srx->transport.sin6.sin6_addr.s6_addr32[3],
+                            -1, &end)) {
+                       srx->transport_len              = sizeof(struct sockaddr_in6);
+                       srx->transport.sin6.sin6_family = AF_INET6;
+                       srx->transport.sin6.sin6_flowinfo = 0;
+                       srx->transport.sin6.sin6_scope_id = 0;
+                       srx->transport.sin6.sin6_addr.s6_addr32[0] = 0;
+                       srx->transport.sin6.sin6_addr.s6_addr32[1] = 0;
+                       srx->transport.sin6.sin6_addr.s6_addr32[2] = htonl(0xffff);
+               } else if (in6_pton(_vllist, -1, srx->transport.sin6.sin6_addr.s6_addr,
+                                   -1, &end)) {
+                       srx->transport_len              = sizeof(struct sockaddr_in6);
+                       srx->transport.sin6.sin6_family = AF_INET6;
+                       srx->transport.sin6.sin6_flowinfo = 0;
+                       srx->transport.sin6.sin6_scope_id = 0;
+               } else {
                        goto bad_address;
-
-               srx->transport_len              = sizeof(struct sockaddr_in);
-               srx->transport.sin.sin_family   = AF_INET;
-               srx->transport.sin.sin_addr.s_addr =
-                       htonl((a << 24) | (b << 16) | (c << 8) | d);
+               }
 
        } while (cell->vl_naddrs++,
                 cell->vl_naddrs < AFS_CELL_MAX_ADDRS && (_vllist = next));
index f76018104ae03489e7683f18ea8ee149f77a389e..d00d550ff2ef12ed9ac29a932ebcc904faccacd3 100644 (file)
@@ -662,7 +662,7 @@ static int afs_proc_cell_servers_show(struct seq_file *m, void *v)
 
        /* display one cell per line on subsequent lines */
        sprintf(ipaddr, "%pISp", &server->addr.transport);
-       seq_printf(m, "%3d %-15.15s %5d\n",
+       seq_printf(m, "%3d %-15s %5d\n",
                   atomic_read(&server->usage), ipaddr, server->fs_state);
 
        return 0;
index c108effb54be3af1182dc657342467e0c63a975a..5d2c1a34ffd5f578b6d2c256909835bea441d574 100644 (file)
@@ -46,21 +46,20 @@ int afs_open_socket(struct afs_net *net)
 
        _enter("");
 
-       ret = sock_create_kern(&init_net, AF_RXRPC, SOCK_DGRAM, PF_INET, &socket);
+       ret = sock_create_kern(&init_net, AF_RXRPC, SOCK_DGRAM, PF_INET6, &socket);
        if (ret < 0)
                goto error_1;
 
        socket->sk->sk_allocation = GFP_NOFS;
 
        /* bind the callback manager's address to make this a server socket */
+       memset(&srx, 0, sizeof(srx));
        srx.srx_family                  = AF_RXRPC;
        srx.srx_service                 = CM_SERVICE;
        srx.transport_type              = SOCK_DGRAM;
-       srx.transport_len               = sizeof(srx.transport.sin);
-       srx.transport.sin.sin_family    = AF_INET;
-       srx.transport.sin.sin_port      = htons(AFS_CM_PORT);
-       memset(&srx.transport.sin.sin_addr, 0,
-              sizeof(srx.transport.sin.sin_addr));
+       srx.transport_len               = sizeof(srx.transport.sin6);
+       srx.transport.sin6.sin6_family  = AF_INET6;
+       srx.transport.sin6.sin6_port    = htons(AFS_CM_PORT);
 
        ret = kernel_bind(socket, (struct sockaddr *) &srx, sizeof(srx));
        if (ret < 0)
index 662f7fbf5d050af539d3b72ddc1a825c2990622b..c63974f06385453f22ca9753cc79e3014ef1ea06 100644 (file)
@@ -200,11 +200,6 @@ struct afs_server *afs_find_server(struct afs_net *net,
 
        _enter("{%d,%pIS}", srx->transport.family, &srx->transport);
 
-       if (srx->transport.family != AF_INET) {
-               WARN(true, "AFS does not yes support non-IPv4 addresses\n");
-               return NULL;
-       }
-
        read_lock(&net->servers_lock);
 
        p = net->servers.rb_node;
index 48d137628d6a9d5769bd5db6ffa77ed8c43ae5fc..276319aa86d8b25336d75bbc9d12170260bba8f5 100644 (file)
@@ -88,10 +88,15 @@ static int afs_deliver_vl_get_entry_by_xxx(struct afs_call *call)
                entry->servers[loop].srx_family = AF_RXRPC;
                entry->servers[loop].srx_service = FS_SERVICE;
                entry->servers[loop].transport_type = SOCK_DGRAM;
-               entry->servers[loop].transport_len = sizeof(entry->servers[loop].transport.sin);
-               entry->servers[loop].transport.sin.sin_family = AF_INET;
-               entry->servers[loop].transport.sin.sin_port = htons(AFS_FS_PORT);
-               entry->servers[loop].transport.sin.sin_addr.s_addr = *bp++;
+               entry->servers[loop].transport_len = sizeof(entry->servers[loop].transport.sin6);
+               entry->servers[loop].transport.sin6.sin6_family = AF_INET6;
+               entry->servers[loop].transport.sin6.sin6_port = htons(AFS_FS_PORT);
+               entry->servers[loop].transport.sin6.sin6_flowinfo = 0;
+               entry->servers[loop].transport.sin6.sin6_scope_id = 0;
+               entry->servers[loop].transport.sin6.sin6_addr.s6_addr32[0] = 0;
+               entry->servers[loop].transport.sin6.sin6_addr.s6_addr32[1] = 0;
+               entry->servers[loop].transport.sin6.sin6_addr.s6_addr32[2] = htonl(0xffff);
+               entry->servers[loop].transport.sin6.sin6_addr.s6_addr32[3] = *bp++;
        }
 
        bp += 8; /* partition IDs */