s4-ipv6: fixed ipv6_listen() to use IPV6_V6ONLY
authorAndrew Tridgell <tridge@samba.org>
Thu, 12 May 2011 10:30:16 +0000 (12:30 +0200)
committerAndrew Tridgell <tridge@samba.org>
Mon, 6 Jun 2011 02:26:09 +0000 (12:26 +1000)
this changes ipv6_listen() to use IPV6_V6ONLY, and to setup the right
scope id for link local IPv6 addresses

source4/lib/socket/socket_ip.c

index 4e66653252031fa44b3ce92e2a008c41b67a153a..bf0aff74ec97960a3abc6726102360dca8dc706b 100644 (file)
@@ -667,9 +667,22 @@ static NTSTATUS ipv6_tcp_connect(struct socket_context *sock,
        return ip_connect_complete(sock, flags);
 }
 
+/*
+  fix the sin6_scope_id based on the address interface
+ */
+static void fix_scope_id(struct sockaddr_in6 *in6,
+                        const char *address)
+{
+       const char *p = strchr(address, '%');
+       if (p != NULL) {
+               in6->sin6_scope_id = if_nametoindex(p+1);
+       }
+}
+
+
 static NTSTATUS ipv6_listen(struct socket_context *sock,
-                               const struct socket_address *my_address,
-                               int queue_size, uint32_t flags)
+                           const struct socket_address *my_address,
+                           int queue_size, uint32_t flags)
 {
        struct sockaddr_in6 my_addr;
        struct in6_addr ip_addr;
@@ -680,14 +693,21 @@ static NTSTATUS ipv6_listen(struct socket_context *sock,
        if (my_address->sockaddr) {
                ret = bind(sock->fd, my_address->sockaddr, my_address->sockaddrlen);
        } else {
+               int one = 1;
                ip_addr = interpret_addr6(my_address->addr);
                
                ZERO_STRUCT(my_addr);
                my_addr.sin6_addr       = ip_addr;
                my_addr.sin6_port       = htons(my_address->port);
                my_addr.sin6_family     = PF_INET6;
-               
-               ret = bind(sock->fd, (struct sockaddr *)&my_addr, sizeof(my_addr));
+               fix_scope_id(&my_addr, my_address->addr);
+
+               /* when binding on ipv6 we always want to only bind on v6 */
+               ret = setsockopt(sock->fd, IPPROTO_IPV6, IPV6_V6ONLY,
+                                (const void *)&one, sizeof(one));
+               if (ret != -1) {
+                       ret = bind(sock->fd, (struct sockaddr *)&my_addr, sizeof(my_addr));
+               }
        }
 
        if (ret == -1) {