src/socket_wrapper.c: add some tracing for connected dgram sockets
[socket_wrapper.git] / src / socket_wrapper.c
index 61dce978ce64c3242e8c3b1c92f8f443487fd631..a24a9d15a83a41838c4e644bfc659c66760f9011 100644 (file)
@@ -2,8 +2,8 @@
  * BSD 3-Clause License
  *
  * Copyright (c) 2005-2008, Jelmer Vernooij <jelmer@samba.org>
- * Copyright (c) 2006-2018, Stefan Metzmacher <metze@samba.org>
- * Copyright (c) 2013-2018, Andreas Schneider <asn@samba.org>
+ * Copyright (c) 2006-2021, Stefan Metzmacher <metze@samba.org>
+ * Copyright (c) 2013-2021, Andreas Schneider <asn@samba.org>
  * Copyright (c) 2014-2017, Michael Adam <obnox@samba.org>
  * Copyright (c) 2016-2018, Anoop C S <anoopcs@redhat.com>
  * All rights reserved.
@@ -86,6 +86,8 @@
 #endif
 #include <pthread.h>
 
+#include "socket_wrapper.h"
+
 enum swrap_dbglvl_e {
        SWRAP_LOG_ERROR = 0,
        SWRAP_LOG_WARN,
@@ -370,7 +372,7 @@ static pthread_mutex_t autobind_start_mutex = PTHREAD_MUTEX_INITIALIZER;
 /* Mutex to guard the initialization of array of socket_info structures */
 static pthread_mutex_t sockets_mutex = PTHREAD_MUTEX_INITIALIZER;
 
-/* Mutex to guard the socket reset in swrap_close() and swrap_remove_stale() */
+/* Mutex to guard the socket reset in swrap_remove_wrapper() */
 static pthread_mutex_t socket_reset_mutex = PTHREAD_MUTEX_INITIALIZER;
 
 /* Mutex to synchronize access to first free index in socket_info array */
@@ -392,8 +394,6 @@ static pthread_mutex_t mtu_update_mutex = PTHREAD_MUTEX_INITIALIZER;
 
 /* Function prototypes */
 
-bool socket_wrapper_enabled(void);
-
 #if ! defined(HAVE_CONSTRUCTOR_ATTRIBUTE) && defined(HAVE_PRAGMA_INIT)
 /* xlC and other oldschool compilers support (only) this */
 #pragma init (swrap_constructor)
@@ -492,6 +492,9 @@ typedef int (*__libc_bind)(int sockfd,
                           const struct sockaddr *addr,
                           socklen_t addrlen);
 typedef int (*__libc_close)(int fd);
+#ifdef HAVE___CLOSE_NOCANCEL
+typedef int (*__libc___close_nocancel)(int fd);
+#endif
 typedef int (*__libc_connect)(int sockfd,
                              const struct sockaddr *addr,
                              socklen_t addrlen);
@@ -572,6 +575,9 @@ struct swrap_libc_symbols {
 #endif
        SWRAP_SYMBOL_ENTRY(bind);
        SWRAP_SYMBOL_ENTRY(close);
+#ifdef HAVE___CLOSE_NOCANCEL
+       SWRAP_SYMBOL_ENTRY(__close_nocancel);
+#endif
        SWRAP_SYMBOL_ENTRY(connect);
        SWRAP_SYMBOL_ENTRY(dup);
        SWRAP_SYMBOL_ENTRY(dup2);
@@ -851,6 +857,15 @@ static int libc_close(int fd)
        return swrap.libc.symbols._libc_close.f(fd);
 }
 
+#ifdef HAVE___CLOSE_NOCANCEL
+static int libc___close_nocancel(int fd)
+{
+       swrap_bind_symbol_all();
+
+       return swrap.libc.symbols._libc___close_nocancel.f(fd);
+}
+#endif /* HAVE___CLOSE_NOCANCEL */
+
 static int libc_connect(int sockfd,
                        const struct sockaddr *addr,
                        socklen_t addrlen)
@@ -969,6 +984,19 @@ static FILE *libc_fopen64(const char *name, const char *mode)
 }
 #endif /* HAVE_FOPEN64 */
 
+static void swrap_inject_o_largefile(int *flags)
+{
+       (void)*flags; /* maybe unused */
+#if SIZE_MAX == 0xffffffffUL && defined(O_LARGEFILE)
+#ifdef O_PATH
+       if (((*flags) & O_PATH) == 0)
+#endif
+       {
+               *flags |= O_LARGEFILE;
+       }
+#endif
+}
+
 static int libc_vopen(const char *pathname, int flags, va_list ap)
 {
        int mode = 0;
@@ -976,6 +1004,8 @@ static int libc_vopen(const char *pathname, int flags, va_list ap)
 
        swrap_bind_symbol_all();
 
+       swrap_inject_o_largefile(&flags);
+
        if (flags & O_CREAT) {
                mode = va_arg(ap, int);
        }
@@ -1004,6 +1034,8 @@ static int libc_vopen64(const char *pathname, int flags, va_list ap)
 
        swrap_bind_symbol_all();
 
+       swrap_inject_o_largefile(&flags);
+
        if (flags & O_CREAT) {
                mode = va_arg(ap, int);
        }
@@ -1020,6 +1052,8 @@ static int libc_vopenat(int dirfd, const char *path, int flags, va_list ap)
 
        swrap_bind_symbol_all();
 
+       swrap_inject_o_largefile(&flags);
+
        if (flags & O_CREAT) {
                mode = va_arg(ap, int);
        }
@@ -1199,6 +1233,9 @@ static void __swrap_bind_symbol_all_once(void)
 #endif
        swrap_bind_symbol_libsocket(bind);
        swrap_bind_symbol_libc(close);
+#ifdef HAVE___CLOSE_NOCANCEL
+       swrap_bind_symbol_libc(__close_nocancel);
+#endif
        swrap_bind_symbol_libsocket(connect);
        swrap_bind_symbol_libc(dup);
        swrap_bind_symbol_libc(dup2);
@@ -1392,6 +1429,55 @@ static size_t socket_length(int family)
        return 0;
 }
 
+struct swrap_sockaddr_buf {
+       char str[128];
+};
+
+static const char *swrap_sockaddr_string(struct swrap_sockaddr_buf *buf,
+                                        const struct sockaddr *saddr)
+{
+       unsigned int port = 0;
+       char addr[64] = {0,};
+
+       switch (saddr->sa_family) {
+       case AF_INET: {
+               const struct sockaddr_in *in =
+                   (const struct sockaddr_in *)(const void *)saddr;
+
+               port = ntohs(in->sin_port);
+
+               inet_ntop(saddr->sa_family,
+                         &in->sin_addr,
+                         addr, sizeof(addr));
+               break;
+       }
+#ifdef HAVE_IPV6
+       case AF_INET6: {
+               const struct sockaddr_in6 *in6 =
+                   (const struct sockaddr_in6 *)(const void *)saddr;
+
+               port = ntohs(in6->sin6_port);
+
+               inet_ntop(saddr->sa_family,
+                         &in6->sin6_addr,
+                         addr, sizeof(addr));
+               break;
+       }
+#endif
+       default:
+               snprintf(addr, sizeof(addr),
+                        "<Unknown address family %u>",
+                        saddr->sa_family);
+               break;
+       }
+
+       snprintf(buf->str, sizeof(buf->str),
+                "addr[%s]/port[%u]",
+                addr, port);
+
+       return buf->str;
+}
+
 static struct socket_info *swrap_get_socket_info(int si_index)
 {
        return (struct socket_info *)(&(sockets[si_index].info));
@@ -2027,13 +2113,10 @@ static int convert_in_un_remote(struct socket_info *si, const struct sockaddr *i
                        type = u_type;
                        iface = (addr & 0x000000FF);
                } else {
-                       char str[256] = {0,};
-                       inet_ntop(inaddr->sa_family,
-                                 &in->sin_addr,
-                                 str, sizeof(str));
+                       struct swrap_sockaddr_buf buf = {};
                        SWRAP_LOG(SWRAP_LOG_WARN,
-                                 "str[%s] prt[%u]",
-                                 str, (unsigned)prt);
+                                 "%s",
+                                 swrap_sockaddr_string(&buf, inaddr));
                        errno = ENETUNREACH;
                        return -1;
                }
@@ -2069,13 +2152,10 @@ static int convert_in_un_remote(struct socket_info *si, const struct sockaddr *i
                if (IN6_ARE_ADDR_EQUAL(&cmp1, &cmp2)) {
                        iface = in->sin6_addr.s6_addr[15];
                } else {
-                       char str[256] = {0,};
-                       inet_ntop(inaddr->sa_family,
-                                 &in->sin6_addr,
-                                 str, sizeof(str));
+                       struct swrap_sockaddr_buf buf = {};
                        SWRAP_LOG(SWRAP_LOG_WARN,
-                                 "str[%s] prt[%u]",
-                                 str, (unsigned)prt);
+                                 "%s",
+                                 swrap_sockaddr_string(&buf, inaddr));
                        errno = ENETUNREACH;
                        return -1;
                }
@@ -2404,46 +2484,7 @@ static bool check_addr_port_in_use(const struct sockaddr *sa, socklen_t len)
 }
 #endif
 
-static void swrap_remove_stale(int fd)
-{
-       struct socket_info *si;
-       int si_index;
-
-       SWRAP_LOG(SWRAP_LOG_TRACE, "remove stale wrapper for %d", fd);
-
-       swrap_mutex_lock(&socket_reset_mutex);
-
-       si_index = find_socket_info_index(fd);
-       if (si_index == -1) {
-               swrap_mutex_unlock(&socket_reset_mutex);
-               return;
-       }
-
-       reset_socket_info_index(fd);
-
-       si = swrap_get_socket_info(si_index);
-
-       swrap_mutex_lock(&first_free_mutex);
-       SWRAP_LOCK_SI(si);
-
-       swrap_dec_refcount(si);
-
-       if (swrap_get_refcount(si) > 0) {
-               goto out;
-       }
-
-       if (si->un_addr.sun_path[0] != '\0') {
-               unlink(si->un_addr.sun_path);
-       }
-
-       swrap_set_next_free(si, first_free);
-       first_free = si_index;
-
-out:
-       SWRAP_UNLOCK_SI(si);
-       swrap_mutex_unlock(&first_free_mutex);
-       swrap_mutex_unlock(&socket_reset_mutex);
-}
+static void swrap_remove_stale(int fd);
 
 static int sockaddr_convert_to_un(struct socket_info *si,
                                  const struct sockaddr *in_addr,
@@ -3836,7 +3877,6 @@ static int swrap_auto_bind(int fd, struct socket_info *si, int family)
        char type;
        int ret;
        int port;
-       struct stat st;
        char *swrap_dir = NULL;
 
        swrap_mutex_lock(&autobind_start_mutex);
@@ -3937,10 +3977,12 @@ static int swrap_auto_bind(int fd, struct socket_info *si, int family)
                              type,
                              socket_wrapper_default_iface(),
                              port);
-               if (stat(un_addr.sa.un.sun_path, &st) == 0) continue;
 
                ret = libc_bind(fd, &un_addr.sa.s, un_addr.sa_socklen);
                if (ret == -1) {
+                       if (errno == EALREADY || errno == EADDRINUSE) {
+                               continue;
+                       }
                        goto done;
                }
 
@@ -3985,6 +4027,7 @@ static int swrap_connect(int s, const struct sockaddr *serv_addr,
                .sa_socklen = sizeof(struct sockaddr_un),
        };
        struct socket_info *si = find_socket_info(s);
+       struct swrap_sockaddr_buf buf = {};
        int bcast = 0;
 
        if (!si) {
@@ -4033,7 +4076,8 @@ static int swrap_connect(int s, const struct sockaddr *serv_addr,
        }
 
        SWRAP_LOG(SWRAP_LOG_TRACE,
-                 "connect() path=%s, fd=%d",
+                 "connect(%s) path=%s, fd=%d",
+                 swrap_sockaddr_string(&buf, serv_addr),
                  un_addr.sa.un.sun_path, s);
 
 
@@ -4099,6 +4143,8 @@ static int swrap_bind(int s, const struct sockaddr *myaddr, socklen_t addrlen)
                .sa_socklen = sizeof(struct sockaddr_un),
        };
        struct socket_info *si = find_socket_info(s);
+       struct swrap_sockaddr_buf buf = {};
+       int ret_errno = errno;
        int bind_error = 0;
 #if 0 /* FIXME */
        bool in_use;
@@ -4156,7 +4202,7 @@ static int swrap_bind(int s, const struct sockaddr *myaddr, socklen_t addrlen)
        }
 
        if (bind_error != 0) {
-               errno = bind_error;
+               ret_errno = bind_error;
                ret = -1;
                goto out;
        }
@@ -4180,16 +4226,21 @@ static int swrap_bind(int s, const struct sockaddr *myaddr, socklen_t addrlen)
                                     1,
                                     &si->bcast);
        if (ret == -1) {
+               ret_errno = errno;
                goto out;
        }
 
        unlink(un_addr.sa.un.sun_path);
 
        ret = libc_bind(s, &un_addr.sa.s, un_addr.sa_socklen);
+       if (ret == -1) {
+               ret_errno = errno;
+       }
 
        SWRAP_LOG(SWRAP_LOG_TRACE,
-                 "bind() path=%s, fd=%d",
-                 un_addr.sa.un.sun_path, s);
+                 "bind(%s) path=%s, fd=%d ret=%d ret_errno=%d",
+                 swrap_sockaddr_string(&buf, myaddr),
+                 un_addr.sa.un.sun_path, s, ret, ret_errno);
 
        if (ret == 0) {
                si->bound = 1;
@@ -4197,7 +4248,7 @@ static int swrap_bind(int s, const struct sockaddr *myaddr, socklen_t addrlen)
 
 out:
        SWRAP_UNLOCK_SI(si);
-
+       errno = ret_errno;
        return ret;
 }
 
@@ -5345,7 +5396,7 @@ union __swrap_cmsghdr {
        struct cmsghdr *cmsg;
 };
 
-static int swrap_sendmsg_unix_scm_rights(const struct cmsghdr *cmsg,
+static int swrap_sendmsg_unix_scm_rights(struct cmsghdr *cmsg,
                                         uint8_t **cm_data,
                                         size_t *cm_data_space,
                                         int *scm_rights_pipe_fd)
@@ -5577,7 +5628,7 @@ static int swrap_sendmsg_unix_scm_rights(const struct cmsghdr *cmsg,
        return 0;
 }
 
-static int swrap_sendmsg_unix_sol_socket(const struct cmsghdr *cmsg,
+static int swrap_sendmsg_unix_sol_socket(struct cmsghdr *cmsg,
                                         uint8_t **cm_data,
                                         size_t *cm_data_space,
                                         int *scm_rights_pipe_fd)
@@ -5601,7 +5652,7 @@ static int swrap_sendmsg_unix_sol_socket(const struct cmsghdr *cmsg,
        return rc;
 }
 
-static int swrap_recvmsg_unix_scm_rights(const struct cmsghdr *cmsg,
+static int swrap_recvmsg_unix_scm_rights(struct cmsghdr *cmsg,
                                         uint8_t **cm_data,
                                         size_t *cm_data_space)
 {
@@ -5880,7 +5931,7 @@ static int swrap_recvmsg_unix_scm_rights(const struct cmsghdr *cmsg,
        return 0;
 }
 
-static int swrap_recvmsg_unix_sol_socket(const struct cmsghdr *cmsg,
+static int swrap_recvmsg_unix_sol_socket(struct cmsghdr *cmsg,
                                         uint8_t **cm_data,
                                         size_t *cm_data_space)
 {
@@ -6121,6 +6172,7 @@ static ssize_t swrap_sendmsg_before(int fd,
 {
        size_t i, len = 0;
        ssize_t ret = -1;
+       struct swrap_sockaddr_buf buf = {};
 
        if (to_un) {
                *to_un = NULL;
@@ -6182,6 +6234,10 @@ static ssize_t swrap_sendmsg_before(int fd,
                                msg->msg_name = NULL;
                                msg->msg_namelen = 0;
                        }
+                       SWRAP_LOG(SWRAP_LOG_TRACE,
+                                 "connected(%s) fd=%d",
+                                 swrap_sockaddr_string(&buf, &si->peername.sa.s),
+                                 fd);
                } else {
                        const struct sockaddr *msg_name;
                        msg_name = (const struct sockaddr *)msg->msg_name;
@@ -6236,6 +6292,11 @@ static ssize_t swrap_sendmsg_before(int fd,
                        goto out;
                }
 
+               SWRAP_LOG(SWRAP_LOG_TRACE,
+                         "deferred connect(%s) path=%s, fd=%d",
+                         swrap_sockaddr_string(&buf, &si->peername.sa.s),
+                         tmp_un->sun_path, fd);
+
                ret = libc_connect(fd,
                                   (struct sockaddr *)(void *)tmp_un,
                                   sizeof(*tmp_un));
@@ -6306,9 +6367,11 @@ static void swrap_sendmsg_after(int fd,
 
        for (i = 0; i < (size_t)msg->msg_iovlen; i++) {
                size_t this_time = MIN(remain, (size_t)msg->msg_iov[i].iov_len);
-               memcpy(buf + ofs,
-                      msg->msg_iov[i].iov_base,
-                      this_time);
+               if (this_time > 0) {
+                       memcpy(buf + ofs,
+                              msg->msg_iov[i].iov_base,
+                              this_time);
+               }
                ofs += this_time;
                remain -= this_time;
        }
@@ -7417,7 +7480,9 @@ ssize_t writev(int s, const struct iovec *vector, int count)
  * CLOSE
  ***************************/
 
-static int swrap_close(int fd)
+static int swrap_remove_wrapper(const char *__func_name,
+                               int (*__close_fd_fn)(int fd),
+                               int fd)
 {
        struct socket_info *si = NULL;
        int si_index;
@@ -7429,10 +7494,10 @@ static int swrap_close(int fd)
        si_index = find_socket_info_index(fd);
        if (si_index == -1) {
                swrap_mutex_unlock(&socket_reset_mutex);
-               return libc_close(fd);
+               return __close_fd_fn(fd);
        }
 
-       SWRAP_LOG(SWRAP_LOG_TRACE, "Close wrapper for fd=%d", fd);
+       swrap_log(SWRAP_LOG_TRACE, __func_name, "Remove wrapper for fd=%d", fd);
        reset_socket_info_index(fd);
 
        si = swrap_get_socket_info(si_index);
@@ -7440,7 +7505,7 @@ static int swrap_close(int fd)
        swrap_mutex_lock(&first_free_mutex);
        SWRAP_LOCK_SI(si);
 
-       ret = libc_close(fd);
+       ret = __close_fd_fn(fd);
        if (ret == -1) {
                ret_errno = errno;
        }
@@ -7482,11 +7547,64 @@ out:
        return ret;
 }
 
+static int swrap_noop_close(int fd)
+{
+       (void)fd; /* unused */
+       return 0;
+}
+
+static void swrap_remove_stale(int fd)
+{
+       swrap_remove_wrapper(__func__, swrap_noop_close, fd);
+}
+
+/*
+ * This allows socket_wrapper aware applications to
+ * indicate that the given fd does not belong to
+ * an inet socket.
+ *
+ * We already overload a lot of unrelated functions
+ * like eventfd(), timerfd_create(), ... in order to
+ * call swrap_remove_stale() on the returned fd, but
+ * we'll never be able to handle all possible syscalls.
+ *
+ * socket_wrapper_indicate_no_inet_fd() gives them a way
+ * to do the same.
+ *
+ * We don't export swrap_remove_stale() in order to
+ * make it easier to analyze SOCKET_WRAPPER_DEBUGLEVEL=3
+ * log files.
+ */
+void socket_wrapper_indicate_no_inet_fd(int fd)
+{
+       swrap_remove_wrapper(__func__, swrap_noop_close, fd);
+}
+
+static int swrap_close(int fd)
+{
+       return swrap_remove_wrapper(__func__, libc_close, fd);
+}
+
 int close(int fd)
 {
        return swrap_close(fd);
 }
 
+#ifdef HAVE___CLOSE_NOCANCEL
+
+static int swrap___close_nocancel(int fd)
+{
+       return swrap_remove_wrapper(__func__, libc___close_nocancel, fd);
+}
+
+int __close_nocancel(int fd);
+int __close_nocancel(int fd)
+{
+       return swrap___close_nocancel(fd);
+}
+
+#endif /* HAVE___CLOSE_NOCANCEL */
+
 /****************************
  * DUP
  ***************************/
@@ -7794,10 +7912,18 @@ void swrap_destructor(void)
 
        SAFE_FREE(sockets);
 
-       if (swrap.libc.handle != NULL) {
+       if (swrap.libc.handle != NULL
+#ifdef RTLD_NEXT
+           && swrap.libc.handle != RTLD_NEXT
+#endif
+                       ) {
                dlclose(swrap.libc.handle);
        }
-       if (swrap.libc.socket_handle) {
+       if (swrap.libc.socket_handle
+#ifdef RTLD_NEXT
+           && swrap.libc.socket_handle != RTLD_NEXT
+#endif
+                       ) {
                dlclose(swrap.libc.socket_handle);
        }
 }
@@ -7815,8 +7941,8 @@ void swrap_destructor(void)
  * related syscalls also with the '_' prefix.
  *
  * This is tested in Samba's 'make test',
- * there we noticed that providing '_read'
- * and '_open' would cause errors, which
+ * there we noticed that providing '_read',
+ * '_open' and '_close' would cause errors, which
  * means we skip '_read', '_write' and
  * all non socket related calls without
  * further analyzing the problem.
@@ -7829,7 +7955,6 @@ SWRAP_SYMBOL_ALIAS(accept4, _accept4);
 #endif
 SWRAP_SYMBOL_ALIAS(accept, _accept);
 SWRAP_SYMBOL_ALIAS(bind, _bind);
-SWRAP_SYMBOL_ALIAS(close, _close);
 SWRAP_SYMBOL_ALIAS(connect, _connect);
 SWRAP_SYMBOL_ALIAS(dup, _dup);
 SWRAP_SYMBOL_ALIAS(dup2, _dup2);