s3: Fix the clustering build
[mat/samba.git] / source4 / lib / socket / socket_ip.c
index 8ee12d8916030370cb370afee7f45b3884ea8e6a..d531053add354befe633a1a06935b6fbc471bd10 100644 (file)
@@ -27,6 +27,9 @@
 #include "system/network.h"
 #include "lib/util/util_net.h"
 
+_PUBLIC_ const struct socket_ops *socket_ipv4_ops(enum socket_type type);
+_PUBLIC_ const struct socket_ops *socket_ipv6_ops(enum socket_type type);
+
 static NTSTATUS ipv4_init(struct socket_context *sock)
 {
        int type;
@@ -44,9 +47,11 @@ static NTSTATUS ipv4_init(struct socket_context *sock)
 
        sock->fd = socket(PF_INET, type, 0);
        if (sock->fd == -1) {
-               return map_nt_error_from_unix(errno);
+               return map_nt_error_from_unix_common(errno);
        }
 
+       smb_set_close_on_exec(sock->fd);
+
        sock->backend_name = "ipv4";
        sock->family = AF_INET;
 
@@ -55,7 +60,10 @@ static NTSTATUS ipv4_init(struct socket_context *sock)
 
 static void ip_close(struct socket_context *sock)
 {
-       close(sock->fd);
+       if (sock->fd != -1) {
+               close(sock->fd);
+               sock->fd = -1;
+       }
 }
 
 static NTSTATUS ip_connect_complete(struct socket_context *sock, uint32_t flags)
@@ -67,16 +75,16 @@ static NTSTATUS ip_connect_complete(struct socket_context *sock, uint32_t flags)
           for non-blocking connect */
        ret = getsockopt(sock->fd, SOL_SOCKET, SO_ERROR, &error, &len);
        if (ret == -1) {
-               return map_nt_error_from_unix(errno);
+               return map_nt_error_from_unix_common(errno);
        }
        if (error != 0) {
-               return map_nt_error_from_unix(error);
+               return map_nt_error_from_unix_common(error);
        }
 
        if (!(flags & SOCKET_FLAG_BLOCK)) {
                ret = set_blocking(sock->fd, false);
                if (ret == -1) {
-                       return map_nt_error_from_unix(errno);
+                       return map_nt_error_from_unix_common(errno);
                }
        }
 
@@ -99,7 +107,7 @@ static NTSTATUS ipv4_connect(struct socket_context *sock,
        if (my_address && my_address->sockaddr) {
                ret = bind(sock->fd, my_address->sockaddr, my_address->sockaddrlen);
                if (ret == -1) {
-                       return map_nt_error_from_unix(errno);
+                       return map_nt_error_from_unix_common(errno);
                }
        } else if (my_address) {
                my_ip = interpret_addr2(my_address->addr);
@@ -116,7 +124,7 @@ static NTSTATUS ipv4_connect(struct socket_context *sock,
                        
                        ret = bind(sock->fd, (struct sockaddr *)&my_addr, sizeof(my_addr));
                        if (ret == -1) {
-                               return map_nt_error_from_unix(errno);
+                               return map_nt_error_from_unix_common(errno);
                        }
                }
        }
@@ -124,7 +132,7 @@ static NTSTATUS ipv4_connect(struct socket_context *sock,
        if (srv_address->sockaddr) {
                ret = connect(sock->fd, srv_address->sockaddr, srv_address->sockaddrlen);
                if (ret == -1) {
-                       return map_nt_error_from_unix(errno);
+                       return map_nt_error_from_unix_common(errno);
                }
        } else {
                srv_ip = interpret_addr2(srv_address->addr);
@@ -144,7 +152,7 @@ static NTSTATUS ipv4_connect(struct socket_context *sock,
 
                ret = connect(sock->fd, (const struct sockaddr *)&srv_addr, sizeof(srv_addr));
                if (ret == -1) {
-                       return map_nt_error_from_unix(errno);
+                       return map_nt_error_from_unix_common(errno);
                }
        }
 
@@ -183,20 +191,20 @@ static NTSTATUS ipv4_listen(struct socket_context *sock,
        }
 
        if (ret == -1) {
-               return map_nt_error_from_unix(errno);
+               return map_nt_error_from_unix_common(errno);
        }
 
        if (sock->type == SOCKET_TYPE_STREAM) {
                ret = listen(sock->fd, queue_size);
                if (ret == -1) {
-                       return map_nt_error_from_unix(errno);
+                       return map_nt_error_from_unix_common(errno);
                }
        }
 
        if (!(flags & SOCKET_FLAG_BLOCK)) {
                ret = set_blocking(sock->fd, false);
                if (ret == -1) {
-                       return map_nt_error_from_unix(errno);
+                       return map_nt_error_from_unix_common(errno);
                }
        }
 
@@ -217,14 +225,14 @@ static NTSTATUS ipv4_accept(struct socket_context *sock, struct socket_context *
 
        new_fd = accept(sock->fd, (struct sockaddr *)&cli_addr, &cli_addr_len);
        if (new_fd == -1) {
-               return map_nt_error_from_unix(errno);
+               return map_nt_error_from_unix_common(errno);
        }
 
        if (!(sock->flags & SOCKET_FLAG_BLOCK)) {
                int ret = set_blocking(new_fd, false);
                if (ret == -1) {
                        close(new_fd);
-                       return map_nt_error_from_unix(errno);
+                       return map_nt_error_from_unix_common(errno);
                }
        }
 
@@ -265,7 +273,7 @@ static NTSTATUS ip_recv(struct socket_context *sock, void *buf,
        if (gotlen == 0) {
                return NT_STATUS_END_OF_FILE;
        } else if (gotlen == -1) {
-               return map_nt_error_from_unix(errno);
+               return map_nt_error_from_unix_common(errno);
        }
 
        *nread = gotlen;
@@ -308,7 +316,7 @@ static NTSTATUS ipv4_recvfrom(struct socket_context *sock, void *buf,
                return NT_STATUS_END_OF_FILE;
        } else if (gotlen == -1) {
                talloc_free(src);
-               return map_nt_error_from_unix(errno);
+               return map_nt_error_from_unix_common(errno);
        }
 
        src->sockaddrlen = from_len;
@@ -339,7 +347,7 @@ static NTSTATUS ip_send(struct socket_context *sock,
 
        len = send(sock->fd, blob->data, blob->length, 0);
        if (len == -1) {
-               return map_nt_error_from_unix(errno);
+               return map_nt_error_from_unix_common(errno);
        }       
 
        *sendlen = len;
@@ -380,7 +388,7 @@ static NTSTATUS ipv4_sendto(struct socket_context *sock,
                             (struct sockaddr *)&srv_addr, sizeof(srv_addr));
        }
        if (len == -1) {
-               return map_nt_error_from_unix(errno);
+               return map_nt_error_from_unix_common(errno);
        }       
 
        *sendlen = len;
@@ -515,7 +523,7 @@ static NTSTATUS ip_pending(struct socket_context *sock, size_t *npending)
                *npending = value;
                return NT_STATUS_OK;
        }
-       return map_nt_error_from_unix(errno);
+       return map_nt_error_from_unix_common(errno);
 }
 
 static const struct socket_ops ipv4_ops = {
@@ -601,9 +609,11 @@ static NTSTATUS ipv6_init(struct socket_context *sock)
 
        sock->fd = socket(PF_INET6, type, 0);
        if (sock->fd == -1) {
-               return map_nt_error_from_unix(errno);
+               return map_nt_error_from_unix_common(errno);
        }
 
+       smb_set_close_on_exec(sock->fd);
+
        sock->backend_name = "ipv6";
        sock->family = AF_INET6;
 
@@ -620,7 +630,7 @@ static NTSTATUS ipv6_tcp_connect(struct socket_context *sock,
        if (my_address && my_address->sockaddr) {
                ret = bind(sock->fd, my_address->sockaddr, my_address->sockaddrlen);
                if (ret == -1) {
-                       return map_nt_error_from_unix(errno);
+                       return map_nt_error_from_unix_common(errno);
                }
        } else if (my_address) {
                struct in6_addr my_ip;
@@ -635,7 +645,7 @@ static NTSTATUS ipv6_tcp_connect(struct socket_context *sock,
                        
                        ret = bind(sock->fd, (struct sockaddr *)&my_addr, sizeof(my_addr));
                        if (ret == -1) {
-                               return map_nt_error_from_unix(errno);
+                               return map_nt_error_from_unix_common(errno);
                        }
                }
        }
@@ -658,15 +668,28 @@ static NTSTATUS ipv6_tcp_connect(struct socket_context *sock,
                ret = connect(sock->fd, (const struct sockaddr *)&srv_addr, sizeof(srv_addr));
        }
        if (ret == -1) {
-               return map_nt_error_from_unix(errno);
+               return map_nt_error_from_unix_common(errno);
        }
 
        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;
@@ -677,31 +700,38 @@ 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) {
-               return map_nt_error_from_unix(errno);
+               return map_nt_error_from_unix_common(errno);
        }
 
        if (sock->type == SOCKET_TYPE_STREAM) {
                ret = listen(sock->fd, queue_size);
                if (ret == -1) {
-                       return map_nt_error_from_unix(errno);
+                       return map_nt_error_from_unix_common(errno);
                }
        }
 
        if (!(flags & SOCKET_FLAG_BLOCK)) {
                ret = set_blocking(sock->fd, false);
                if (ret == -1) {
-                       return map_nt_error_from_unix(errno);
+                       return map_nt_error_from_unix_common(errno);
                }
        }
 
@@ -712,7 +742,7 @@ static NTSTATUS ipv6_listen(struct socket_context *sock,
 
 static NTSTATUS ipv6_tcp_accept(struct socket_context *sock, struct socket_context **new_sock)
 {
-       struct sockaddr_in cli_addr;
+       struct sockaddr_in6 cli_addr;
        socklen_t cli_addr_len = sizeof(cli_addr);
        int new_fd;
        
@@ -722,14 +752,14 @@ static NTSTATUS ipv6_tcp_accept(struct socket_context *sock, struct socket_conte
 
        new_fd = accept(sock->fd, (struct sockaddr *)&cli_addr, &cli_addr_len);
        if (new_fd == -1) {
-               return map_nt_error_from_unix(errno);
+               return map_nt_error_from_unix_common(errno);
        }
 
        if (!(sock->flags & SOCKET_FLAG_BLOCK)) {
                int ret = set_blocking(new_fd, false);
                if (ret == -1) {
                        close(new_fd);
-                       return map_nt_error_from_unix(errno);
+                       return map_nt_error_from_unix_common(errno);
                }
        }
 
@@ -793,7 +823,7 @@ static NTSTATUS ipv6_recvfrom(struct socket_context *sock, void *buf,
                return NT_STATUS_END_OF_FILE;
        } else if (gotlen == -1) {
                talloc_free(src);
-               return map_nt_error_from_unix(errno);
+               return map_nt_error_from_unix_common(errno);
        }
 
        src->sockaddrlen = from_len;
@@ -844,7 +874,7 @@ static NTSTATUS ipv6_sendto(struct socket_context *sock,
                             (struct sockaddr *)&srv_addr, sizeof(srv_addr));
        }
        if (len == -1) {
-               return map_nt_error_from_unix(errno);
+               return map_nt_error_from_unix_common(errno);
        }       
 
        *sendlen = len;