]> granicus.if.org Git - libtirpc/commitdiff
Always make IPv6 sockets V6ONLY
authorOlaf Kirch <okir@suse.de>
Tue, 2 Sep 2008 16:11:15 +0000 (12:11 -0400)
committerSteve Dickson <steved@redhat.com>
Tue, 2 Sep 2008 16:11:15 +0000 (12:11 -0400)
Assume you have a netconfig file looking like this:

udp        tpi_clts      v     inet     udp     -       -
udp6       tpi_clts      v     inet6    udp     -       -
...

a call to svc_tli_create(... &someaddr, "udp") will fail to create an
IPv6 server socket. The problem is that on Linux, passive IPv6 sockets
will also accept packets/connections from IPv4, and will simply map
the sender's address to an IPv6 mapped IPv4 address. So if you want to
bind both a UDPv4 and UDPv6 socket to the same port, this will fail with
EADDRINUSE.

The way to avoid this behavior is to change the socket to V6ONLY,
which tells the kernel to avoid the autmatic mapping.

The change proposed in the patch below does this. I *think* this is
a good place to do this, as it will also fix applications that do not
use svc_tli_create() - such as rpcbind, which creates the sockets on
its own using __rpc_nconf2fd.

I think this also improves portability, as BSD code assumes BSD
behavior, where this mapping does not occur either.

Signed-off-by: Olaf Kirch <okir@suse.de>
Signed-off-by: Steve Dickson <steved@redhat.com>
src/rpc_generic.c

index 583aff065e754ca5d1d344737a700357b4c9e073..ff4ba16792ccfa8d362337b7122b932d589c3472 100644 (file)
@@ -525,11 +525,18 @@ int
 __rpc_nconf2fd(const struct netconfig *nconf)
 {
        struct __rpc_sockinfo si;
+       int fd;
 
        if (!__rpc_nconf2sockinfo(nconf, &si))
                return 0;
 
-       return socket(si.si_af, si.si_socktype, si.si_proto);
+       if ((fd = socket(si.si_af, si.si_socktype, si.si_proto)) >= 0 &&
+           si.si_af == AF_INET6) {
+               int val = 1;
+
+               setsockopt(fd, SOL_IPV6, IPV6_V6ONLY, &val, sizeof(val));
+       }
+       return fd;
 }
 
 int