/*
- * Copyright (c) 2005-2008 Jelmer Vernooij <jelmer@samba.org>
- * Copyright (C) 2006-2014 Stefan Metzmacher <metze@samba.org>
- * Copyright (C) 2013-2014 Andreas Schneider <asn@samba.org>
+ * 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) 2014-2017, Michael Adam <obnox@samba.org>
+ * Copyright (c) 2016-2018, Anoop C S <anoopcs@redhat.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
- *
*/
/*
#define DESTRUCTOR_ATTRIBUTE
#endif
+#ifndef FALL_THROUGH
+# ifdef HAVE_FALLTHROUGH_ATTRIBUTE
+# define FALL_THROUGH __attribute__ ((fallthrough))
+# else /* HAVE_FALLTHROUGH_ATTRIBUTE */
+# define FALL_THROUGH ((void)0)
+# endif /* HAVE_FALLTHROUGH_ATTRIBUTE */
+#endif /* FALL_THROUGH */
+
#ifdef HAVE_ADDRESS_SANITIZER_ATTRIBUTE
#define DO_NOT_SANITIZE_ADDRESS_ATTRIBUTE __attribute__((no_sanitize_address))
#else
} while(0)
#endif
+#ifndef SAFE_FREE
+#define SAFE_FREE(x) do { if ((x) != NULL) {free(x); (x)=NULL;} } while(0)
+#endif
+
#ifndef discard_const
#define discard_const(ptr) ((void *)((uintptr_t)(ptr)))
#endif
# endif
#endif
-/* Macros for accessing mutexes */
-# define SWRAP_LOCK(m) do { \
- pthread_mutex_lock(&(m ## _mutex)); \
-} while(0)
-
-# define SWRAP_UNLOCK(m) do { \
- pthread_mutex_unlock(&(m ## _mutex)); \
-} while(0)
-
/* Add new global locks here please */
# define SWRAP_LOCK_ALL \
- SWRAP_LOCK(libc_symbol_binding); \
+ swrap_mutex_lock(&libc_symbol_binding_mutex); \
# define SWRAP_UNLOCK_ALL \
- SWRAP_UNLOCK(libc_symbol_binding); \
-
-
-#define SWRAP_DLIST_ADD(list,item) do { \
- if (!(list)) { \
- (item)->prev = NULL; \
- (item)->next = NULL; \
- (list) = (item); \
- } else { \
- (item)->prev = NULL; \
- (item)->next = (list); \
- (list)->prev = (item); \
- (list) = (item); \
- } \
-} while (0)
-
-#define SWRAP_DLIST_REMOVE(list,item) do { \
- if ((list) == (item)) { \
- (list) = (item)->next; \
- if (list) { \
- (list)->prev = NULL; \
- } \
- } else { \
- if ((item)->prev) { \
- (item)->prev->next = (item)->next; \
- } \
- if ((item)->next) { \
- (item)->next->prev = (item)->prev; \
- } \
- } \
- (item)->prev = NULL; \
- (item)->next = NULL; \
-} while (0)
-
-#define SWRAP_DLIST_ADD_AFTER(list, item, el) \
-do { \
- if ((list) == NULL || (el) == NULL) { \
- SWRAP_DLIST_ADD(list, item); \
- } else { \
- (item)->prev = (el); \
- (item)->next = (el)->next; \
- (el)->next = (item); \
- if ((item)->next != NULL) { \
- (item)->next->prev = (item); \
- } \
- } \
-} while (0)
+ swrap_mutex_unlock(&libc_symbol_binding_mutex); \
+
+#define SOCKET_INFO_CONTAINER(si) \
+ (struct socket_info_container *)(si)
+
+#define SWRAP_LOCK_SI(si) do { \
+ struct socket_info_container *sic = SOCKET_INFO_CONTAINER(si); \
+ swrap_mutex_lock(&sic->meta.mutex); \
+} while(0)
+
+#define SWRAP_UNLOCK_SI(si) do { \
+ struct socket_info_container *sic = SOCKET_INFO_CONTAINER(si); \
+ swrap_mutex_unlock(&sic->meta.mutex); \
+} while(0)
#if defined(HAVE_GETTIMEOFDAY_TZ) || defined(HAVE_GETTIMEOFDAY_TZ_VOID)
#define swrapGetTimeOfDay(tval) gettimeofday(tval,NULL)
#define SOCKET_MAX_SOCKETS 1024
-
/*
* Maximum number of socket_info structures that can
* be used. Can be overriden by the environment variable
*/
#define SOCKET_WRAPPER_MAX_SOCKETS_DEFAULT 65535
-#define SOCKET_WRAPPER_MAX_SOCKETS_LIMIT 256000
+#define SOCKET_WRAPPER_MAX_SOCKETS_LIMIT 262140
/* This limit is to avoid broadcast sendto() needing to stat too many
* files. It may be raised (with a performance cost) to up to 254
} sa;
};
-struct socket_info_fd {
- struct socket_info_fd *prev, *next;
- int fd;
-
- /*
- * Points to corresponding index in array of
- * socket_info structures
- */
- int si_index;
-};
-
int first_free;
struct socket_info
{
- unsigned int refcount;
-
- int next_free;
-
int family;
int type;
int protocol;
} io;
};
-static struct socket_info *sockets;
-static size_t max_sockets = 0;
+struct socket_info_meta
+{
+ unsigned int refcount;
+ int next_free;
+ pthread_mutex_t mutex;
+};
+
+struct socket_info_container
+{
+ struct socket_info info;
+ struct socket_info_meta meta;
+};
+
+static struct socket_info_container *sockets;
+
+static size_t socket_info_max = 0;
/*
- * While socket file descriptors are passed among different processes, the
- * numerical value gets changed. So its better to store it locally to each
- * process rather than including it within socket_info which will be shared.
+ * Allocate the socket array always on the limit value. We want it to be
+ * at least bigger than the default so if we reach the limit we can
+ * still deal with duplicate fds pointing to the same socket_info.
*/
-static struct socket_info_fd *socket_fds;
+static size_t socket_fds_max = SOCKET_WRAPPER_MAX_SOCKETS_LIMIT;
-/* The mutex for accessing the global libc.symbols */
+/* Hash table to map fds to corresponding socket_info index */
+static int *socket_fds_idx;
+
+/* Mutex to synchronize access to global libc.symbols */
static pthread_mutex_t libc_symbol_binding_mutex = PTHREAD_MUTEX_INITIALIZER;
+/* Mutex for syncronizing port selection during swrap_auto_bind() */
+static pthread_mutex_t autobind_start_mutex;
+
+/* Mutex to guard the initialization of array of socket_info structures */
+static pthread_mutex_t sockets_mutex;
+
+/* Mutex to guard the socket reset in swrap_close() and swrap_remove_stale() */
+static pthread_mutex_t socket_reset_mutex;
+
+/* Mutex to synchronize access to first free index in socket_info array */
+static pthread_mutex_t first_free_mutex;
+
+/* Mutex to synchronize access to packet capture dump file */
+static pthread_mutex_t pcap_dump_mutex;
+
+/* Mutex for synchronizing mtu value fetch*/
+static pthread_mutex_t mtu_update_mutex;
+
/* Function prototypes */
bool socket_wrapper_enabled(void);
void swrap_constructor(void) CONSTRUCTOR_ATTRIBUTE;
void swrap_destructor(void) DESTRUCTOR_ATTRIBUTE;
-#ifdef NDEBUG
-# define SWRAP_LOG(...)
+#ifndef HAVE_GETPROGNAME
+static const char *getprogname(void)
+{
+#if defined(HAVE_PROGRAM_INVOCATION_SHORT_NAME)
+ return program_invocation_short_name;
+#elif defined(HAVE_GETEXECNAME)
+ return getexecname();
#else
+ return NULL;
+#endif /* HAVE_PROGRAM_INVOCATION_SHORT_NAME */
+}
+#endif /* HAVE_GETPROGNAME */
static void swrap_log(enum swrap_dbglvl_e dbglvl, const char *func, const char *format, ...) PRINTF_ATTRIBUTE(3, 4);
# define SWRAP_LOG(dbglvl, ...) swrap_log((dbglvl), __func__, __VA_ARGS__)
va_list va;
const char *d;
unsigned int lvl = 0;
+ const char *prefix = "SWRAP";
+ const char *progname = getprogname();
d = getenv("SOCKET_WRAPPER_DEBUGLEVEL");
if (d != NULL) {
lvl = atoi(d);
}
+ if (lvl < dbglvl) {
+ return;
+ }
+
va_start(va, format);
vsnprintf(buffer, sizeof(buffer), format, va);
va_end(va);
- if (lvl >= dbglvl) {
- switch (dbglvl) {
- case SWRAP_LOG_ERROR:
- fprintf(stderr,
- "SWRAP_ERROR(%d) - %s: %s\n",
- (int)getpid(), func, buffer);
- break;
- case SWRAP_LOG_WARN:
- fprintf(stderr,
- "SWRAP_WARN(%d) - %s: %s\n",
- (int)getpid(), func, buffer);
- break;
- case SWRAP_LOG_DEBUG:
- fprintf(stderr,
- "SWRAP_DEBUG(%d) - %s: %s\n",
- (int)getpid(), func, buffer);
- break;
- case SWRAP_LOG_TRACE:
- fprintf(stderr,
- "SWRAP_TRACE(%d) - %s: %s\n",
- (int)getpid(), func, buffer);
- break;
- }
+ switch (dbglvl) {
+ case SWRAP_LOG_ERROR:
+ prefix = "SWRAP_ERROR";
+ break;
+ case SWRAP_LOG_WARN:
+ prefix = "SWRAP_WARN";
+ break;
+ case SWRAP_LOG_DEBUG:
+ prefix = "SWRAP_DEBUG";
+ break;
+ case SWRAP_LOG_TRACE:
+ prefix = "SWRAP_TRACE";
+ break;
}
+
+ if (progname == NULL) {
+ progname = "<unknown>";
+ }
+
+ fprintf(stderr,
+ "%s[%s (%u)] - %s: %s\n",
+ prefix,
+ progname,
+ (unsigned int)getpid(),
+ func,
+ buffer);
}
-#endif
/*********************************************************
* SWRAP LOADING LIBC FUNCTIONS
typedef int (*__libc_dup2)(int oldfd, int newfd);
typedef int (*__libc_fcntl)(int fd, int cmd, ...);
typedef FILE *(*__libc_fopen)(const char *name, const char *mode);
+#ifdef HAVE_FOPEN64
+typedef FILE *(*__libc_fopen64)(const char *name, const char *mode);
+#endif
#ifdef HAVE_EVENTFD
typedef int (*__libc_eventfd)(int count, int flags);
#endif
socklen_t *optlen);
typedef int (*__libc_ioctl)(int d, unsigned long int request, ...);
typedef int (*__libc_listen)(int sockfd, int backlog);
-typedef int (*__libc_open)(const char *pathname, int flags, mode_t mode);
+typedef int (*__libc_open)(const char *pathname, int flags, ...);
+#ifdef HAVE_OPEN64
+typedef int (*__libc_open64)(const char *pathname, int flags, ...);
+#endif /* HAVE_OPEN64 */
typedef int (*__libc_openat)(int dirfd, const char *path, int flags, ...);
typedef int (*__libc_pipe)(int pipefd[2]);
typedef int (*__libc_read)(int fd, void *buf, size_t count);
SWRAP_SYMBOL_ENTRY(dup2);
SWRAP_SYMBOL_ENTRY(fcntl);
SWRAP_SYMBOL_ENTRY(fopen);
+#ifdef HAVE_FOPEN64
+ SWRAP_SYMBOL_ENTRY(fopen64);
+#endif
#ifdef HAVE_EVENTFD
SWRAP_SYMBOL_ENTRY(eventfd);
#endif
SWRAP_SYMBOL_ENTRY(ioctl);
SWRAP_SYMBOL_ENTRY(listen);
SWRAP_SYMBOL_ENTRY(open);
+#ifdef HAVE_OPEN64
+ SWRAP_SYMBOL_ENTRY(open64);
+#endif
SWRAP_SYMBOL_ENTRY(openat);
SWRAP_SYMBOL_ENTRY(pipe);
SWRAP_SYMBOL_ENTRY(read);
static struct swrap swrap;
/* prototypes */
-static const char *socket_wrapper_dir(void);
+static char *socket_wrapper_dir(void);
#define LIBC_NAME "libc.so"
SWRAP_LIBSOCKET,
};
-#ifndef NDEBUG
static const char *swrap_str_lib(enum swrap_lib lib)
{
switch (lib) {
/* Compiler would warn us about unhandled enum value if we get here */
return "unknown";
}
-#endif
static void *swrap_load_lib_handle(enum swrap_lib lib)
{
int i;
#ifdef RTLD_DEEPBIND
- flags |= RTLD_DEEPBIND;
+ const char *env_preload = getenv("LD_PRELOAD");
+ const char *env_deepbind = getenv("SOCKET_WRAPPER_DISABLE_DEEPBIND");
+ bool enable_deepbind = true;
+
+ /* Don't do a deepbind if we run with libasan */
+ if (env_preload != NULL && strlen(env_preload) < 1024) {
+ const char *p = strstr(env_preload, "libasan.so");
+ if (p != NULL) {
+ enable_deepbind = false;
+ }
+ }
+
+ if (env_deepbind != NULL && strlen(env_deepbind) >= 1) {
+ enable_deepbind = false;
+ }
+
+ if (enable_deepbind) {
+ flags |= RTLD_DEEPBIND;
+ }
#endif
switch (lib) {
case SWRAP_LIBNSL:
- /* FALL TROUGH */
case SWRAP_LIBSOCKET:
#ifdef HAVE_LIBSOCKET
handle = swrap.libc.socket_handle;
}
break;
#endif
- /* FALL TROUGH */
case SWRAP_LIBC:
handle = swrap.libc.handle;
#ifdef LIBC_SO
return func;
}
+static void swrap_mutex_lock(pthread_mutex_t *mutex)
+{
+ int ret;
+
+ ret = pthread_mutex_lock(mutex);
+ if (ret != 0) {
+ SWRAP_LOG(SWRAP_LOG_ERROR, "Couldn't lock pthread mutex - %s",
+ strerror(ret));
+ }
+}
+
+static void swrap_mutex_unlock(pthread_mutex_t *mutex)
+{
+ int ret;
+
+ ret = pthread_mutex_unlock(mutex);
+ if (ret != 0) {
+ SWRAP_LOG(SWRAP_LOG_ERROR, "Couldn't unlock pthread mutex - %s",
+ strerror(ret));
+ }
+}
+
+/*
+ * These macros have a thread race condition on purpose!
+ *
+ * This is an optimization to avoid locking each time we check if the symbol is
+ * bound.
+ */
#define swrap_bind_symbol_libc(sym_name) \
- SWRAP_LOCK(libc_symbol_binding); \
if (swrap.libc.symbols._libc_##sym_name.obj == NULL) { \
- swrap.libc.symbols._libc_##sym_name.obj = \
- _swrap_bind_symbol(SWRAP_LIBC, #sym_name); \
- } \
- SWRAP_UNLOCK(libc_symbol_binding)
+ swrap_mutex_lock(&libc_symbol_binding_mutex); \
+ if (swrap.libc.symbols._libc_##sym_name.obj == NULL) { \
+ swrap.libc.symbols._libc_##sym_name.obj = \
+ _swrap_bind_symbol(SWRAP_LIBC, #sym_name); \
+ } \
+ swrap_mutex_unlock(&libc_symbol_binding_mutex); \
+ }
#define swrap_bind_symbol_libsocket(sym_name) \
- SWRAP_LOCK(libc_symbol_binding); \
if (swrap.libc.symbols._libc_##sym_name.obj == NULL) { \
- swrap.libc.symbols._libc_##sym_name.obj = \
- _swrap_bind_symbol(SWRAP_LIBSOCKET, #sym_name); \
- } \
- SWRAP_UNLOCK(libc_symbol_binding)
+ swrap_mutex_lock(&libc_symbol_binding_mutex); \
+ if (swrap.libc.symbols._libc_##sym_name.obj == NULL) { \
+ swrap.libc.symbols._libc_##sym_name.obj = \
+ _swrap_bind_symbol(SWRAP_LIBSOCKET, #sym_name); \
+ } \
+ swrap_mutex_unlock(&libc_symbol_binding_mutex); \
+ }
#define swrap_bind_symbol_libnsl(sym_name) \
- SWRAP_LOCK(libc_symbol_binding); \
if (swrap.libc.symbols._libc_##sym_name.obj == NULL) { \
- swrap.libc.symbols._libc_##sym_name.obj = \
- _swrap_bind_symbol(SWRAP_LIBNSL, #sym_name); \
- } \
- SWRAP_UNLOCK(libc_symbol_binding)
+ swrap_mutex_lock(&libc_symbol_binding_mutex); \
+ if (swrap.libc.symbols._libc_##sym_name.obj == NULL) { \
+ swrap.libc.symbols._libc_##sym_name.obj = \
+ _swrap_bind_symbol(SWRAP_LIBNSL, #sym_name); \
+ } \
+ swrap_mutex_unlock(&libc_symbol_binding_mutex); \
+ }
-/*
- * IMPORTANT
+/****************************************************************************
+ * IMPORTANT
+ ****************************************************************************
*
- * Functions especially from libc need to be loaded individually, you can't load
- * all at once or gdb will segfault at startup. The same applies to valgrind and
- * has probably something todo with with the linker.
- * So we need load each function at the point it is called the first time.
- */
+ * Functions especially from libc need to be loaded individually, you can't
+ * load all at once or gdb will segfault at startup. The same applies to
+ * valgrind and has probably something todo with with the linker. So we need
+ * load each function at the point it is called the first time.
+ *
+ ****************************************************************************/
+
#ifdef HAVE_ACCEPT4
static int libc_accept4(int sockfd,
struct sockaddr *addr,
DO_NOT_SANITIZE_ADDRESS_ATTRIBUTE
static int libc_vfcntl(int fd, int cmd, va_list ap)
{
- long int args[4];
+ void *arg;
int rc;
- int i;
swrap_bind_symbol_libc(fcntl);
- for (i = 0; i < 4; i++) {
- args[i] = va_arg(ap, long int);
- }
+ arg = va_arg(ap, void *);
- rc = swrap.libc.symbols._libc_fcntl.f(fd,
- cmd,
- args[0],
- args[1],
- args[2],
- args[3]);
+ rc = swrap.libc.symbols._libc_fcntl.f(fd, cmd, arg);
return rc;
}
DO_NOT_SANITIZE_ADDRESS_ATTRIBUTE
static int libc_vioctl(int d, unsigned long int request, va_list ap)
{
- long int args[4];
+ void *arg;
int rc;
- int i;
swrap_bind_symbol_libc(ioctl);
- for (i = 0; i < 4; i++) {
- args[i] = va_arg(ap, long int);
- }
+ arg = va_arg(ap, void *);
- rc = swrap.libc.symbols._libc_ioctl.f(d,
- request,
- args[0],
- args[1],
- args[2],
- args[3]);
+ rc = swrap.libc.symbols._libc_ioctl.f(d, request, arg);
return rc;
}
return swrap.libc.symbols._libc_fopen.f(name, mode);
}
+#ifdef HAVE_FOPEN64
+static FILE *libc_fopen64(const char *name, const char *mode)
+{
+ swrap_bind_symbol_libc(fopen64);
+
+ return swrap.libc.symbols._libc_fopen64.f(name, mode);
+}
+#endif /* HAVE_FOPEN64 */
+
static int libc_vopen(const char *pathname, int flags, va_list ap)
{
- long int mode = 0;
+ int mode = 0;
int fd;
swrap_bind_symbol_libc(open);
- mode = va_arg(ap, long int);
-
+ if (flags & O_CREAT) {
+ mode = va_arg(ap, int);
+ }
fd = swrap.libc.symbols._libc_open.f(pathname, flags, (mode_t)mode);
return fd;
return fd;
}
+#ifdef HAVE_OPEN64
+static int libc_vopen64(const char *pathname, int flags, va_list ap)
+{
+ int mode = 0;
+ int fd;
+
+ swrap_bind_symbol_libc(open64);
+
+ if (flags & O_CREAT) {
+ mode = va_arg(ap, int);
+ }
+ fd = swrap.libc.symbols._libc_open64.f(pathname, flags, (mode_t)mode);
+
+ return fd;
+}
+#endif /* HAVE_OPEN64 */
+
static int libc_vopenat(int dirfd, const char *path, int flags, va_list ap)
{
- long int mode = 0;
+ int mode = 0;
int fd;
swrap_bind_symbol_libc(openat);
- mode = va_arg(ap, long int);
-
- fd = swrap.libc.symbols._libc_openat.f(dirfd, path, flags, (mode_t)mode);
+ if (flags & O_CREAT) {
+ mode = va_arg(ap, int);
+ }
+ fd = swrap.libc.symbols._libc_openat.f(dirfd,
+ path,
+ flags,
+ (mode_t)mode);
return fd;
}
return swrap.libc.symbols._libc_writev.f(fd, iov, iovcnt);
}
+/* DO NOT call this function during library initialization! */
+static void swrap_bind_symbol_all(void)
+{
+#ifdef HAVE_ACCEPT4
+ swrap_bind_symbol_libsocket(accept4);
+#else
+ swrap_bind_symbol_libsocket(accept);
+#endif
+ swrap_bind_symbol_libsocket(bind);
+ swrap_bind_symbol_libc(close);
+ swrap_bind_symbol_libsocket(connect);
+ swrap_bind_symbol_libc(dup);
+ swrap_bind_symbol_libc(dup2);
+ swrap_bind_symbol_libc(fcntl);
+ swrap_bind_symbol_libc(fopen);
+#ifdef HAVE_FOPEN64
+ swrap_bind_symbol_libc(fopen64);
+#endif
+#ifdef HAVE_EVENTFD
+ swrap_bind_symbol_libc(eventfd);
+#endif
+ swrap_bind_symbol_libsocket(getpeername);
+ swrap_bind_symbol_libsocket(getsockname);
+ swrap_bind_symbol_libsocket(getsockopt);
+ swrap_bind_symbol_libc(ioctl);
+ swrap_bind_symbol_libsocket(listen);
+ swrap_bind_symbol_libc(open);
+#ifdef HAVE_OPEN64
+ swrap_bind_symbol_libc(open64);
+#endif
+ swrap_bind_symbol_libc(openat);
+ swrap_bind_symbol_libsocket(pipe);
+ swrap_bind_symbol_libc(read);
+ swrap_bind_symbol_libsocket(readv);
+ swrap_bind_symbol_libsocket(recv);
+ swrap_bind_symbol_libsocket(recvfrom);
+ swrap_bind_symbol_libsocket(recvmsg);
+ swrap_bind_symbol_libsocket(send);
+ swrap_bind_symbol_libsocket(sendmsg);
+ swrap_bind_symbol_libsocket(sendto);
+ swrap_bind_symbol_libsocket(setsockopt);
+#ifdef HAVE_SIGNALFD
+ swrap_bind_symbol_libsocket(signalfd);
+#endif
+ swrap_bind_symbol_libsocket(socket);
+ swrap_bind_symbol_libsocket(socketpair);
+#ifdef HAVE_TIMERFD_CREATE
+ swrap_bind_symbol_libc(timerfd_create);
+#endif
+ swrap_bind_symbol_libc(write);
+ swrap_bind_symbol_libsocket(writev);
+}
+
/*********************************************************
* SWRAP HELPER FUNCTIONS
*********************************************************/
return 0;
}
-static const char *socket_wrapper_dir(void)
+static struct socket_info *swrap_get_socket_info(int si_index)
+{
+ return (struct socket_info *)(&(sockets[si_index].info));
+}
+
+static int swrap_get_refcount(struct socket_info *si)
+{
+ struct socket_info_container *sic = SOCKET_INFO_CONTAINER(si);
+ return sic->meta.refcount;
+}
+
+static void swrap_inc_refcount(struct socket_info *si)
+{
+ struct socket_info_container *sic = SOCKET_INFO_CONTAINER(si);
+
+ sic->meta.refcount += 1;
+}
+
+static void swrap_dec_refcount(struct socket_info *si)
+{
+ struct socket_info_container *sic = SOCKET_INFO_CONTAINER(si);
+
+ sic->meta.refcount -= 1;
+}
+
+static int swrap_get_next_free(struct socket_info *si)
+{
+ struct socket_info_container *sic = SOCKET_INFO_CONTAINER(si);
+
+ return sic->meta.next_free;
+}
+
+static void swrap_set_next_free(struct socket_info *si, int next_free)
{
- const char *s = getenv("SOCKET_WRAPPER_DIR");
+ struct socket_info_container *sic = SOCKET_INFO_CONTAINER(si);
+
+ sic->meta.next_free = next_free;
+}
+
+static char *socket_wrapper_dir(void)
+{
+ char *swrap_dir = NULL;
+ char *s = getenv("SOCKET_WRAPPER_DIR");
+
if (s == NULL) {
return NULL;
}
- /* TODO use realpath(3) here, when we add support for threads */
- if (strncmp(s, "./", 2) == 0) {
- s += 2;
+
+ swrap_dir = realpath(s, NULL);
+ if (swrap_dir == NULL) {
+ SWRAP_LOG(SWRAP_LOG_ERROR,
+ "Unable to resolve socket_wrapper dir path: %s",
+ strerror(errno));
+ return NULL;
}
- SWRAP_LOG(SWRAP_LOG_TRACE, "socket_wrapper_dir: %s", s);
- return s;
+ SWRAP_LOG(SWRAP_LOG_TRACE, "socket_wrapper_dir: %s", swrap_dir);
+ return swrap_dir;
}
static unsigned int socket_wrapper_mtu(void)
const char *s;
char *endp;
+ swrap_mutex_lock(&mtu_update_mutex);
+
if (max_mtu != 0) {
- return max_mtu;
+ goto done;
}
max_mtu = SOCKET_WRAPPER_MTU_DEFAULT;
max_mtu = tmp;
done:
+ swrap_mutex_unlock(&mtu_update_mutex);
return max_mtu;
}
+static int socket_wrapper_init_mutex(pthread_mutex_t *m)
+{
+ pthread_mutexattr_t ma;
+ int ret;
+
+ ret = pthread_mutexattr_init(&ma);
+ if (ret != 0) {
+ return ret;
+ }
+
+ ret = pthread_mutexattr_settype(&ma, PTHREAD_MUTEX_ERRORCHECK);
+ if (ret != 0) {
+ goto done;
+ }
+
+ ret = pthread_mutex_init(m, &ma);
+
+done:
+ pthread_mutexattr_destroy(&ma);
+
+ return ret;
+}
+
static size_t socket_wrapper_max_sockets(void)
{
const char *s;
- unsigned long tmp;
+ size_t tmp;
char *endp;
- if (max_sockets != 0) {
- return max_sockets;
+ if (socket_info_max != 0) {
+ return socket_info_max;
}
- max_sockets = SOCKET_WRAPPER_MAX_SOCKETS_DEFAULT;
+ socket_info_max = SOCKET_WRAPPER_MAX_SOCKETS_DEFAULT;
s = getenv("SOCKET_WRAPPER_MAX_SOCKETS");
if (s == NULL || s[0] == '\0') {
if (s == endp) {
goto done;
}
- if (tmp == 0 || tmp > SOCKET_WRAPPER_MAX_SOCKETS_LIMIT) {
+ if (tmp == 0) {
+ tmp = SOCKET_WRAPPER_MAX_SOCKETS_DEFAULT;
SWRAP_LOG(SWRAP_LOG_ERROR,
- "Invalid number of sockets specified, using default.");
- goto done;
+ "Invalid number of sockets specified, "
+ "using default (%zu)",
+ tmp);
}
- max_sockets = tmp;
+ if (tmp > SOCKET_WRAPPER_MAX_SOCKETS_LIMIT) {
+ tmp = SOCKET_WRAPPER_MAX_SOCKETS_LIMIT;
+ SWRAP_LOG(SWRAP_LOG_ERROR,
+ "Invalid number of sockets specified, "
+ "using maximum (%zu).",
+ tmp);
+ }
+
+ socket_info_max = tmp;
done:
- return max_sockets;
+ return socket_info_max;
+}
+
+static void socket_wrapper_init_fds_idx(void)
+{
+ int *tmp = NULL;
+ size_t i;
+
+ if (socket_fds_idx != NULL) {
+ return;
+ }
+
+ tmp = (int *)calloc(socket_fds_max, sizeof(int));
+ if (tmp == NULL) {
+ SWRAP_LOG(SWRAP_LOG_ERROR,
+ "Failed to allocate socket fds index array: %s",
+ strerror(errno));
+ exit(-1);
+ }
+
+ for (i = 0; i < socket_fds_max; i++) {
+ tmp[i] = -1;
+ }
+
+ socket_fds_idx = tmp;
}
static void socket_wrapper_init_sockets(void)
{
+ size_t max_sockets;
size_t i;
+ int ret;
+
+ swrap_mutex_lock(&sockets_mutex);
if (sockets != NULL) {
+ swrap_mutex_unlock(&sockets_mutex);
return;
}
+ socket_wrapper_init_fds_idx();
+
+ /* Needs to be called inside the sockets_mutex lock here. */
max_sockets = socket_wrapper_max_sockets();
- sockets = (struct socket_info *)calloc(max_sockets,
- sizeof(struct socket_info));
+ sockets = (struct socket_info_container *)calloc(max_sockets,
+ sizeof(struct socket_info_container));
if (sockets == NULL) {
SWRAP_LOG(SWRAP_LOG_ERROR,
- "Failed to allocate sockets array.\n");
+ "Failed to allocate sockets array: %s",
+ strerror(errno));
+ swrap_mutex_unlock(&sockets_mutex);
exit(-1);
}
+ swrap_mutex_lock(&first_free_mutex);
+
first_free = 0;
for (i = 0; i < max_sockets; i++) {
- sockets[i].next_free = i+1;
+ swrap_set_next_free(&sockets[i].info, i+1);
+ ret = socket_wrapper_init_mutex(&sockets[i].meta.mutex);
+ if (ret != 0) {
+ SWRAP_LOG(SWRAP_LOG_ERROR,
+ "Failed to initialize pthread mutex");
+ goto done;
+ }
+ }
+
+ /* mark the end of the free list */
+ swrap_set_next_free(&sockets[max_sockets-1].info, -1);
+
+ ret = socket_wrapper_init_mutex(&autobind_start_mutex);
+ if (ret != 0) {
+ SWRAP_LOG(SWRAP_LOG_ERROR,
+ "Failed to initialize pthread mutex");
+ goto done;
}
- sockets[max_sockets-1].next_free = -1;
+ ret = socket_wrapper_init_mutex(&pcap_dump_mutex);
+ if (ret != 0) {
+ SWRAP_LOG(SWRAP_LOG_ERROR,
+ "Failed to initialize pthread mutex");
+ goto done;
+ }
+
+ ret = socket_wrapper_init_mutex(&mtu_update_mutex);
+ if (ret != 0) {
+ SWRAP_LOG(SWRAP_LOG_ERROR,
+ "Failed to initialize pthread mutex");
+ goto done;
+ }
+
+done:
+ swrap_mutex_unlock(&first_free_mutex);
+ swrap_mutex_unlock(&sockets_mutex);
+ if (ret != 0) {
+ exit(-1);
+ }
}
bool socket_wrapper_enabled(void)
{
- const char *s = socket_wrapper_dir();
+ char *s = socket_wrapper_dir();
if (s == NULL) {
return false;
}
+ SAFE_FREE(s);
+
socket_wrapper_init_sockets();
return true;
return 1;/* 127.0.0.1 */
}
-/*
- * Return the first free entry (if any) and make
- * it re-usable again (by nulling it out)
- */
-static int socket_wrapper_first_free_index(void)
+static void set_socket_info_index(int fd, int idx)
{
- int next_free;
+ socket_fds_idx[fd] = idx;
+ /* This builtin issues a full memory barrier. */
+ __sync_synchronize();
+}
+
+static void reset_socket_info_index(int fd)
+{
+ set_socket_info_index(fd, -1);
+}
+
+static int find_socket_info_index(int fd)
+{
+ if (fd < 0) {
+ return -1;
+ }
+
+ if (socket_fds_idx == NULL) {
+ return -1;
+ }
+
+ if ((size_t)fd >= socket_fds_max) {
+ /*
+ * Do not add a log here as some applications do stupid things
+ * like:
+ *
+ * for (fd = 0; fd <= getdtablesize(); fd++) {
+ * close(fd)
+ * };
+ *
+ * This would produce millions of lines of debug messages.
+ */
+#if 0
+ SWRAP_LOG(SWRAP_LOG_ERROR,
+ "Looking for a socket info for the fd %d is over the "
+ "max socket index limit of %zu.",
+ fd,
+ socket_fds_max);
+#endif
+ return -1;
+ }
+ /* This builtin issues a full memory barrier. */
+ __sync_synchronize();
+ return socket_fds_idx[fd];
+}
+
+static int swrap_add_socket_info(struct socket_info *si_input)
+{
+ struct socket_info *si = NULL;
+ int si_index = -1;
+
+ if (si_input == NULL) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ swrap_mutex_lock(&first_free_mutex);
if (first_free == -1) {
+ errno = ENFILE;
+ goto out;
+ }
+
+ si_index = first_free;
+ si = swrap_get_socket_info(si_index);
+
+ SWRAP_LOCK_SI(si);
+
+ first_free = swrap_get_next_free(si);
+ *si = *si_input;
+ swrap_inc_refcount(si);
+
+ SWRAP_UNLOCK_SI(si);
+
+out:
+ swrap_mutex_unlock(&first_free_mutex);
+
+ return si_index;
+}
+
+static int swrap_create_socket(struct socket_info *si, int fd)
+{
+ int idx;
+
+ if ((size_t)fd >= socket_fds_max) {
+ SWRAP_LOG(SWRAP_LOG_ERROR,
+ "The max socket index limit of %zu has been reached, "
+ "trying to add %d",
+ socket_fds_max,
+ fd);
+ return -1;
+ }
+
+ idx = swrap_add_socket_info(si);
+ if (idx == -1) {
return -1;
}
- next_free = sockets[first_free].next_free;
- ZERO_STRUCT(sockets[first_free]);
- sockets[first_free].next_free = next_free;
+ set_socket_info_index(fd, idx);
- return first_free;
+ return idx;
}
static int convert_un_in(const struct sockaddr_un *un, struct sockaddr *in, socklen_t *len)
unsigned int prt;
unsigned int iface;
int is_bcast = 0;
+ char *swrap_dir = NULL;
if (bcast) *bcast = 0;
return -1;
}
+ swrap_dir = socket_wrapper_dir();
+
if (is_bcast) {
- snprintf(un->sun_path, sizeof(un->sun_path), "%s/EINVAL",
- socket_wrapper_dir());
+ snprintf(un->sun_path, sizeof(un->sun_path),
+ "%s/EINVAL", swrap_dir);
SWRAP_LOG(SWRAP_LOG_DEBUG, "un path [%s]", un->sun_path);
+ SAFE_FREE(swrap_dir);
/* the caller need to do more processing */
return 0;
}
snprintf(un->sun_path, sizeof(un->sun_path), "%s/"SOCKET_FORMAT,
- socket_wrapper_dir(), type, iface, prt);
+ swrap_dir, type, iface, prt);
SWRAP_LOG(SWRAP_LOG_DEBUG, "un path [%s]", un->sun_path);
+ SAFE_FREE(swrap_dir);
+
return 0;
}
unsigned int iface;
struct stat st;
int is_bcast = 0;
+ char *swrap_dir = NULL;
if (bcast) *bcast = 0;
if (addr == 0) {
/* 0.0.0.0 */
- is_bcast = 0;
+ is_bcast = 0;
type = d_type;
iface = socket_wrapper_default_iface();
} else if (a_type && addr == 0xFFFFFFFF) {
return -1;
}
+ swrap_dir = socket_wrapper_dir();
+
if (prt == 0) {
/* handle auto-allocation of ephemeral ports */
for (prt = 5001; prt < 10000; prt++) {
snprintf(un->sun_path, sizeof(un->sun_path), "%s/"SOCKET_FORMAT,
- socket_wrapper_dir(), type, iface, prt);
+ swrap_dir, type, iface, prt);
if (stat(un->sun_path, &st) == 0) continue;
set_port(si->family, prt, &si->myname);
break;
}
+
if (prt == 10000) {
errno = ENFILE;
+ SAFE_FREE(swrap_dir);
return -1;
}
}
snprintf(un->sun_path, sizeof(un->sun_path), "%s/"SOCKET_FORMAT,
- socket_wrapper_dir(), type, iface, prt);
+ swrap_dir, type, iface, prt);
SWRAP_LOG(SWRAP_LOG_DEBUG, "un path [%s]", un->sun_path);
- return 0;
-}
-
-static struct socket_info_fd *find_socket_info_fd(int fd)
-{
- struct socket_info_fd *f;
- for (f = socket_fds; f; f = f->next) {
- if (f->fd == fd) {
- return f;
- }
- }
-
- return NULL;
-}
+ SAFE_FREE(swrap_dir);
-static int find_socket_info_index(int fd)
-{
- struct socket_info_fd *fi = find_socket_info_fd(fd);
-
- if (fi == NULL) {
- return -1;
- }
-
- return fi->si_index;
+ return 0;
}
static struct socket_info *find_socket_info(int fd)
return NULL;
}
- return &sockets[idx];
+ return swrap_get_socket_info(idx);
}
#if 0 /* FIXME */
return false;
}
break;
-#if HAVE_IPV6
+#ifdef HAVE_IPV6
case AF_INET6:
if (len < sizeof(struct sockaddr_in6)) {
return false;
}
for (f = socket_fds; f; f = f->next) {
- struct socket_info *s = &sockets[f->si_index];
+ struct socket_info *s = swrap_get_socket_info(f->si_index);
if (s == last_s) {
continue;
return true;
break;
}
-#if HAVE_IPV6
+#ifdef HAVE_IPV6
case AF_INET6: {
struct sockaddr_in6 *sin1, *sin2;
static void swrap_remove_stale(int fd)
{
- struct socket_info_fd *fi = find_socket_info_fd(fd);
struct socket_info *si;
int si_index;
- if (fi == NULL) {
+ 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;
}
- si_index = fi->si_index;
+ reset_socket_info_index(fd);
- SWRAP_LOG(SWRAP_LOG_TRACE, "remove stale wrapper for %d", fd);
- SWRAP_DLIST_REMOVE(socket_fds, fi);
- free(fi);
+ si = swrap_get_socket_info(si_index);
- si = &sockets[si_index];
- si->refcount--;
+ swrap_mutex_lock(&first_free_mutex);
+ SWRAP_LOCK_SI(si);
- if (si->refcount > 0) {
- return;
+ 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);
}
- si->next_free = first_free;
+ 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 int sockaddr_convert_to_un(struct socket_info *si,
* AF_UNSPEC is mapped to AF_INET and must be treated here.
*/
- /* FALL THROUGH */
+ FALL_THROUGH;
}
case AF_INET:
#ifdef HAVE_IPV6
int unreachable,
size_t *_packet_len)
{
- uint8_t *base;
- uint8_t *buf;
- struct swrap_packet_frame *frame;
- union swrap_packet_ip *ip;
+ uint8_t *base = NULL;
+ uint8_t *buf = NULL;
+ union {
+ uint8_t *ptr;
+ struct swrap_packet_frame *frame;
+ } f;
+ union {
+ uint8_t *ptr;
+ union swrap_packet_ip *ip;
+ } i;
union swrap_packet_payload *pay;
size_t packet_len;
size_t alloc_len;
- size_t nonwire_len = sizeof(*frame);
+ size_t nonwire_len = sizeof(struct swrap_packet_frame);
size_t wire_hdr_len = 0;
size_t wire_len = 0;
size_t ip_hdr_len = 0;
dest_in = (const struct sockaddr_in *)(const void *)dest;
src_port = src_in->sin_port;
dest_port = dest_in->sin_port;
- ip_hdr_len = sizeof(ip->v4);
+ ip_hdr_len = sizeof(i.ip->v4);
break;
#ifdef HAVE_IPV6
case AF_INET6:
dest_in6 = (const struct sockaddr_in6 *)(const void *)dest;
src_port = src_in6->sin6_port;
dest_port = dest_in6->sin6_port;
- ip_hdr_len = sizeof(ip->v6);
+ ip_hdr_len = sizeof(i.ip->v6);
break;
#endif
default:
if (wire_len > 64 ) {
icmp_truncate_len = wire_len - 64;
}
- wire_hdr_len += icmp_hdr_len;
wire_len += icmp_hdr_len;
}
}
buf = base;
+ f.ptr = buf;
+
+ f.frame->seconds = tval->tv_sec;
+ f.frame->micro_seconds = tval->tv_usec;
+ f.frame->recorded_length = wire_len - icmp_truncate_len;
+ f.frame->full_length = wire_len - icmp_truncate_len;
- frame = (struct swrap_packet_frame *)(void *)buf;
- frame->seconds = tval->tv_sec;
- frame->micro_seconds = tval->tv_usec;
- frame->recorded_length = wire_len - icmp_truncate_len;
- frame->full_length = wire_len - icmp_truncate_len;
buf += SWRAP_PACKET_FRAME_SIZE;
- ip = (union swrap_packet_ip *)(void *)buf;
+ i.ptr = buf;
switch (src->sa_family) {
case AF_INET:
- ip->v4.ver_hdrlen = 0x45; /* version 4 and 5 * 32 bit words */
- ip->v4.tos = 0x00;
- ip->v4.packet_length = htons(wire_len - icmp_truncate_len);
- ip->v4.identification = htons(0xFFFF);
- ip->v4.flags = 0x40; /* BIT 1 set - means don't fragment */
- ip->v4.fragment = htons(0x0000);
- ip->v4.ttl = 0xFF;
- ip->v4.protocol = protocol;
- ip->v4.hdr_checksum = htons(0x0000);
- ip->v4.src_addr = src_in->sin_addr.s_addr;
- ip->v4.dest_addr = dest_in->sin_addr.s_addr;
+ i.ip->v4.ver_hdrlen = 0x45; /* version 4 and 5 * 32 bit words */
+ i.ip->v4.tos = 0x00;
+ i.ip->v4.packet_length = htons(wire_len - icmp_truncate_len);
+ i.ip->v4.identification = htons(0xFFFF);
+ i.ip->v4.flags = 0x40; /* BIT 1 set - means don't fragment */
+ i.ip->v4.fragment = htons(0x0000);
+ i.ip->v4.ttl = 0xFF;
+ i.ip->v4.protocol = protocol;
+ i.ip->v4.hdr_checksum = htons(0x0000);
+ i.ip->v4.src_addr = src_in->sin_addr.s_addr;
+ i.ip->v4.dest_addr = dest_in->sin_addr.s_addr;
buf += SWRAP_PACKET_IP_V4_SIZE;
break;
#ifdef HAVE_IPV6
case AF_INET6:
- ip->v6.ver_prio = 0x60; /* version 4 and 5 * 32 bit words */
- ip->v6.flow_label_high = 0x00;
- ip->v6.flow_label_low = 0x0000;
- ip->v6.payload_length = htons(wire_len - icmp_truncate_len); /* TODO */
- ip->v6.next_header = protocol;
- memcpy(ip->v6.src_addr, src_in6->sin6_addr.s6_addr, 16);
- memcpy(ip->v6.dest_addr, dest_in6->sin6_addr.s6_addr, 16);
+ i.ip->v6.ver_prio = 0x60; /* version 4 and 5 * 32 bit words */
+ i.ip->v6.flow_label_high = 0x00;
+ i.ip->v6.flow_label_low = 0x0000;
+ i.ip->v6.payload_length = htons(wire_len - icmp_truncate_len); /* TODO */
+ i.ip->v6.next_header = protocol;
+ memcpy(i.ip->v6.src_addr, src_in6->sin6_addr.s6_addr, 16);
+ memcpy(i.ip->v6.dest_addr, dest_in6->sin6_addr.s6_addr, 16);
buf += SWRAP_PACKET_IP_V6_SIZE;
break;
#endif
pay->icmp4.code = 0x01; /* host unreachable */
pay->icmp4.checksum = htons(0x0000);
pay->icmp4.unused = htonl(0x00000000);
+
buf += SWRAP_PACKET_PAYLOAD_ICMP4_SIZE;
/* set the ip header in the ICMP payload */
- ip = (union swrap_packet_ip *)(void *)buf;
- ip->v4.ver_hdrlen = 0x45; /* version 4 and 5 * 32 bit words */
- ip->v4.tos = 0x00;
- ip->v4.packet_length = htons(wire_len - icmp_hdr_len);
- ip->v4.identification = htons(0xFFFF);
- ip->v4.flags = 0x40; /* BIT 1 set - means don't fragment */
- ip->v4.fragment = htons(0x0000);
- ip->v4.ttl = 0xFF;
- ip->v4.protocol = icmp_protocol;
- ip->v4.hdr_checksum = htons(0x0000);
- ip->v4.src_addr = dest_in->sin_addr.s_addr;
- ip->v4.dest_addr = src_in->sin_addr.s_addr;
+ i.ptr = buf;
+ i.ip->v4.ver_hdrlen = 0x45; /* version 4 and 5 * 32 bit words */
+ i.ip->v4.tos = 0x00;
+ i.ip->v4.packet_length = htons(wire_len - icmp_hdr_len);
+ i.ip->v4.identification = htons(0xFFFF);
+ i.ip->v4.flags = 0x40; /* BIT 1 set - means don't fragment */
+ i.ip->v4.fragment = htons(0x0000);
+ i.ip->v4.ttl = 0xFF;
+ i.ip->v4.protocol = icmp_protocol;
+ i.ip->v4.hdr_checksum = htons(0x0000);
+ i.ip->v4.src_addr = dest_in->sin_addr.s_addr;
+ i.ip->v4.dest_addr = src_in->sin_addr.s_addr;
+
buf += SWRAP_PACKET_IP_V4_SIZE;
src_port = dest_in->sin_port;
buf += SWRAP_PACKET_PAYLOAD_ICMP6_SIZE;
/* set the ip header in the ICMP payload */
- ip = (union swrap_packet_ip *)(void *)buf;
- ip->v6.ver_prio = 0x60; /* version 4 and 5 * 32 bit words */
- ip->v6.flow_label_high = 0x00;
- ip->v6.flow_label_low = 0x0000;
- ip->v6.payload_length = htons(wire_len - icmp_truncate_len); /* TODO */
- ip->v6.next_header = protocol;
- memcpy(ip->v6.src_addr, dest_in6->sin6_addr.s6_addr, 16);
- memcpy(ip->v6.dest_addr, src_in6->sin6_addr.s6_addr, 16);
+ i.ptr = buf;
+ i.ip->v6.ver_prio = 0x60; /* version 4 and 5 * 32 bit words */
+ i.ip->v6.flow_label_high = 0x00;
+ i.ip->v6.flow_label_low = 0x0000;
+ i.ip->v6.payload_length = htons(wire_len - icmp_truncate_len); /* TODO */
+ i.ip->v6.next_header = protocol;
+ memcpy(i.ip->v6.src_addr, dest_in6->sin6_addr.s6_addr, 16);
+ memcpy(i.ip->v6.dest_addr, src_in6->sin6_addr.s6_addr, 16);
+
buf += SWRAP_PACKET_IP_V6_SIZE;
src_port = dest_in6->sin6_port;
if (fd != -1) {
struct swrap_file_hdr file_hdr;
file_hdr.magic = 0xA1B2C3D4;
- file_hdr.version_major = 0x0002;
+ file_hdr.version_major = 0x0002;
file_hdr.version_minor = 0x0004;
file_hdr.timezone = 0x00000000;
file_hdr.sigfigs = 0x00000000;
size_t packet_len = 0;
int fd;
+ swrap_mutex_lock(&pcap_dump_mutex);
+
file_name = swrap_pcap_init_file();
if (!file_name) {
- return;
+ goto done;
}
packet = swrap_pcap_marshall_packet(si,
len,
&packet_len);
if (packet == NULL) {
- return;
+ goto done;
}
fd = swrap_pcap_get_fd(file_name);
if (fd != -1) {
if (write(fd, packet, packet_len) != (ssize_t)packet_len) {
free(packet);
- return;
+ goto done;
}
}
free(packet);
+
+done:
+ swrap_mutex_unlock(&pcap_dump_mutex);
}
/****************************************************************************
static int swrap_socket(int family, int type, int protocol)
{
- struct socket_info *si;
- struct socket_info_fd *fi;
+ struct socket_info *si = NULL;
+ struct socket_info _si = { 0 };
int fd;
- int idx;
+ int ret;
int real_type = type;
/*
if (real_type == SOCK_STREAM) {
break;
}
- /*fall through*/
+ FALL_THROUGH;
case 17:
if (real_type == SOCK_DGRAM) {
break;
}
- /*fall through*/
+ FALL_THROUGH;
default:
errno = EPROTONOSUPPORT;
return -1;
/* Check if we have a stale fd and remove it */
swrap_remove_stale(fd);
- idx = socket_wrapper_first_free_index();
- if (idx == -1) {
- errno = ENOMEM;
- return -1;
- }
-
- si = &sockets[idx];
-
+ si = &_si;
si->family = family;
/* however, the rest of the socket_wrapper code expects just
memcpy(&si->myname.sa.in, &sin, si->myname.sa_socklen);
break;
}
+#ifdef HAVE_IPV6
case AF_INET6: {
struct sockaddr_in6 sin6 = {
.sin6_family = AF_INET6,
memcpy(&si->myname.sa.in6, &sin6, si->myname.sa_socklen);
break;
}
+#endif
default:
errno = EINVAL;
return -1;
}
- fi = (struct socket_info_fd *)calloc(1, sizeof(struct socket_info_fd));
- if (fi == NULL) {
- errno = ENOMEM;
+ ret = swrap_create_socket(si, fd);
+ if (ret == -1) {
return -1;
}
- si->refcount = 1;
- first_free = si->next_free;
- si->next_free = 0;
-
- fi->fd = fd;
- fi->si_index = idx;
-
- SWRAP_DLIST_ADD(socket_fds, fi);
-
SWRAP_LOG(SWRAP_LOG_TRACE,
- "Created %s socket for protocol %s",
- si->family == AF_INET ? "IPv4" : "IPv6",
- si->type == SOCK_DGRAM ? "UDP" : "TCP");
+ "Created %s socket for protocol %s, fd=%d",
+ family == AF_INET ? "IPv4" : "IPv6",
+ real_type == SOCK_DGRAM ? "UDP" : "TCP",
+ fd);
return fd;
}
int flags)
{
struct socket_info *parent_si, *child_si;
- struct socket_info_fd *child_fi;
+ struct socket_info new_si = { 0 };
int fd;
int idx;
struct swrap_address un_addr = {
#endif
}
+
+ /*
+ * prevent parent_si from being altered / closed
+ * while we read it
+ */
+ SWRAP_LOCK_SI(parent_si);
+
/*
* assume out sockaddr have the same size as the in parent
* socket family
*/
in_addr.sa_socklen = socket_length(parent_si->family);
if (in_addr.sa_socklen <= 0) {
+ SWRAP_UNLOCK_SI(parent_si);
errno = EINVAL;
return -1;
}
+ SWRAP_UNLOCK_SI(parent_si);
+
#ifdef HAVE_ACCEPT4
ret = libc_accept4(s, &un_addr.sa.s, &un_addr.sa_socklen, flags);
#else
fd = ret;
+ SWRAP_LOCK_SI(parent_si);
+
ret = sockaddr_convert_from_un(parent_si,
&un_addr.sa.un,
un_addr.sa_socklen,
&in_addr.sa.s,
&in_addr.sa_socklen);
if (ret == -1) {
+ SWRAP_UNLOCK_SI(parent_si);
close(fd);
return ret;
}
- idx = socket_wrapper_first_free_index();
- if (idx == -1) {
- errno = ENOMEM;
- return -1;
- }
-
- child_si = &sockets[idx];
-
- child_fi = (struct socket_info_fd *)calloc(1, sizeof(struct socket_info_fd));
- if (child_fi == NULL) {
- close(fd);
- errno = ENOMEM;
- return -1;
- }
-
- child_fi->fd = fd;
+ child_si = &new_si;
child_si->family = parent_si->family;
child_si->type = parent_si->type;
child_si->is_server = 1;
child_si->connected = 1;
+ SWRAP_UNLOCK_SI(parent_si);
+
child_si->peername = (struct swrap_address) {
.sa_socklen = in_addr.sa_socklen,
};
&un_my_addr.sa.s,
&un_my_addr.sa_socklen);
if (ret == -1) {
- free(child_fi);
close(fd);
return ret;
}
&in_my_addr.sa.s,
&in_my_addr.sa_socklen);
if (ret == -1) {
- free(child_fi);
close(fd);
return ret;
}
};
memcpy(&child_si->myname.sa.ss, &in_my_addr.sa.ss, in_my_addr.sa_socklen);
- child_si->refcount = 1;
- first_free = child_si->next_free;
- child_si->next_free = 0;
-
- child_fi->si_index = idx;
-
- SWRAP_DLIST_ADD(socket_fds, child_fi);
+ idx = swrap_create_socket(&new_si, fd);
+ if (idx == -1) {
+ close (fd);
+ return -1;
+ }
if (addr != NULL) {
- swrap_pcap_dump_packet(child_si, addr, SWRAP_ACCEPT_SEND, NULL, 0);
- swrap_pcap_dump_packet(child_si, addr, SWRAP_ACCEPT_RECV, NULL, 0);
- swrap_pcap_dump_packet(child_si, addr, SWRAP_ACCEPT_ACK, NULL, 0);
+ struct socket_info *si = swrap_get_socket_info(idx);
+
+ SWRAP_LOCK_SI(si);
+ swrap_pcap_dump_packet(si, addr, SWRAP_ACCEPT_SEND, NULL, 0);
+ swrap_pcap_dump_packet(si, addr, SWRAP_ACCEPT_RECV, NULL, 0);
+ swrap_pcap_dump_packet(si, addr, SWRAP_ACCEPT_ACK, NULL, 0);
+ SWRAP_UNLOCK_SI(si);
}
return fd;
int ret;
int port;
struct stat st;
+ char *swrap_dir = NULL;
+
+ swrap_mutex_lock(&autobind_start_mutex);
if (autobind_start_init != 1) {
autobind_start_init = 1;
type = SOCKET_TYPE_CHAR_UDP;
break;
default:
- errno = ESOCKTNOSUPPORT;
- return -1;
+ errno = ESOCKTNOSUPPORT;
+ ret = -1;
+ goto done;
}
memset(&in, 0, sizeof(in));
if (si->family != family) {
errno = ENETUNREACH;
- return -1;
+ ret = -1;
+ goto done;
}
switch (si->type) {
break;
default:
errno = ESOCKTNOSUPPORT;
- return -1;
+ ret = -1;
+ goto done;
}
memset(&in6, 0, sizeof(in6));
#endif
default:
errno = ESOCKTNOSUPPORT;
- return -1;
+ ret = -1;
+ goto done;
}
if (autobind_start > 60000) {
autobind_start = 10000;
}
+ swrap_dir = socket_wrapper_dir();
+
for (i = 0; i < SOCKET_MAX_SOCKETS; i++) {
port = autobind_start + i;
snprintf(un_addr.sa.un.sun_path, sizeof(un_addr.sa.un.sun_path),
- "%s/"SOCKET_FORMAT, socket_wrapper_dir(),
- type, socket_wrapper_default_iface(), port);
+ "%s/"SOCKET_FORMAT, swrap_dir, 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) {
- return ret;
+ goto done;
}
si->un_addr = un_addr.sa.un;
socket_wrapper_default_iface(),
0);
errno = ENFILE;
- return -1;
+ ret = -1;
+ goto done;
}
si->family = family;
set_port(si->family, port, &si->myname);
- return 0;
+ ret = 0;
+
+done:
+ SAFE_FREE(swrap_dir);
+ swrap_mutex_unlock(&autobind_start_mutex);
+ return ret;
}
/****************************************************************************
return libc_connect(s, serv_addr, addrlen);
}
+ SWRAP_LOCK_SI(si);
+
if (si->bound == 0) {
ret = swrap_auto_bind(s, si, serv_addr->sa_family);
if (ret == -1) {
- return -1;
+ goto done;
}
}
if (si->family != serv_addr->sa_family) {
errno = EINVAL;
- return -1;
+ ret = -1;
+ goto done;
}
ret = sockaddr_convert_to_un(si, serv_addr,
addrlen, &un_addr.sa.un, 0, &bcast);
if (ret == -1) {
- return -1;
+ goto done;
}
if (bcast) {
errno = ENETUNREACH;
- return -1;
+ ret = -1;
+ goto done;
}
if (si->type == SOCK_DGRAM) {
swrap_pcap_dump_packet(si, serv_addr, SWRAP_CONNECT_UNREACH, NULL, 0);
}
+done:
+ SWRAP_UNLOCK_SI(si);
return ret;
}
return libc_bind(s, myaddr, addrlen);
}
+ SWRAP_LOCK_SI(si);
+
switch (si->family) {
case AF_INET: {
const struct sockaddr_in *sin;
if (bind_error != 0) {
errno = bind_error;
- return -1;
+ ret = -1;
+ goto out;
}
#if 0 /* FIXME */
in_use = check_addr_port_in_use(myaddr, addrlen);
if (in_use) {
errno = EADDRINUSE;
- return -1;
+ ret = -1;
+ goto out;
}
#endif
1,
&si->bcast);
if (ret == -1) {
- return -1;
+ goto out;
}
unlink(un_addr.sa.un.sun_path);
si->bound = 1;
}
+out:
+ SWRAP_UNLOCK_SI(si);
+
return ret;
}
return libc_listen(s, backlog);
}
+ SWRAP_LOCK_SI(si);
+
if (si->bound == 0) {
ret = swrap_auto_bind(s, si, si->family);
if (ret == -1) {
errno = EADDRINUSE;
- return ret;
+ goto out;
}
}
ret = libc_listen(s, backlog);
+out:
+ SWRAP_UNLOCK_SI(si);
+
return ret;
}
return swrap_fopen(name, mode);
}
+/****************************************************************************
+ * FOPEN64
+ ***************************************************************************/
+
+#ifdef HAVE_FOPEN64
+static FILE *swrap_fopen64(const char *name, const char *mode)
+{
+ FILE *fp;
+
+ fp = libc_fopen64(name, mode);
+ if (fp != NULL) {
+ int fd = fileno(fp);
+
+ swrap_remove_stale(fd);
+ }
+
+ return fp;
+}
+
+FILE *fopen64(const char *name, const char *mode)
+{
+ return swrap_fopen64(name, mode);
+}
+#endif /* HAVE_FOPEN64 */
+
/****************************************************************************
* OPEN
***************************************************************************/
return fd;
}
+/****************************************************************************
+ * OPEN64
+ ***************************************************************************/
+
+#ifdef HAVE_OPEN64
+static int swrap_vopen64(const char *pathname, int flags, va_list ap)
+{
+ int ret;
+
+ ret = libc_vopen64(pathname, flags, ap);
+ if (ret != -1) {
+ /*
+ * There are methods for closing descriptors (libc-internal code
+ * paths, direct syscalls) which close descriptors in ways that
+ * we can't intercept, so try to recover when we notice that
+ * that's happened
+ */
+ swrap_remove_stale(ret);
+ }
+ return ret;
+}
+
+int open64(const char *pathname, int flags, ...)
+{
+ va_list ap;
+ int fd;
+
+ va_start(ap, flags);
+ fd = swrap_vopen64(pathname, flags, ap);
+ va_end(ap);
+
+ return fd;
+}
+#endif /* HAVE_OPEN64 */
+
/****************************************************************************
* OPENAT
***************************************************************************/
{
struct socket_info *si = find_socket_info(s);
socklen_t len;
+ int ret = -1;
if (!si) {
return libc_getpeername(s, name, addrlen);
}
+ SWRAP_LOCK_SI(si);
+
if (si->peername.sa_socklen == 0)
{
errno = ENOTCONN;
- return -1;
+ goto out;
}
len = MIN(*addrlen, si->peername.sa_socklen);
if (len == 0) {
- return 0;
+ ret = 0;
+ goto out;
}
memcpy(name, &si->peername.sa.ss, len);
*addrlen = si->peername.sa_socklen;
- return 0;
+ ret = 0;
+out:
+ SWRAP_UNLOCK_SI(si);
+
+ return ret;
}
#ifdef HAVE_ACCEPT_PSOCKLEN_T
{
struct socket_info *si = find_socket_info(s);
socklen_t len;
+ int ret = -1;
if (!si) {
return libc_getsockname(s, name, addrlen);
}
+ SWRAP_LOCK_SI(si);
+
len = MIN(*addrlen, si->myname.sa_socklen);
if (len == 0) {
- return 0;
+ ret = 0;
+ goto out;
}
memcpy(name, &si->myname.sa.ss, len);
*addrlen = si->myname.sa_socklen;
- return 0;
+ ret = 0;
+out:
+ SWRAP_UNLOCK_SI(si);
+
+ return ret;
}
#ifdef HAVE_ACCEPT_PSOCKLEN_T
void *optval, socklen_t *optlen)
{
struct socket_info *si = find_socket_info(s);
+ int ret;
if (!si) {
return libc_getsockopt(s,
optlen);
}
+ SWRAP_LOCK_SI(si);
+
if (level == SOL_SOCKET) {
switch (optname) {
#ifdef SO_DOMAIN
if (optval == NULL || optlen == NULL ||
*optlen < (socklen_t)sizeof(int)) {
errno = EINVAL;
- return -1;
+ ret = -1;
+ goto done;
}
*optlen = sizeof(int);
*(int *)optval = si->family;
- return 0;
+ ret = 0;
+ goto done;
#endif /* SO_DOMAIN */
#ifdef SO_PROTOCOL
if (optval == NULL || optlen == NULL ||
*optlen < (socklen_t)sizeof(int)) {
errno = EINVAL;
- return -1;
+ ret = -1;
+ goto done;
}
*optlen = sizeof(int);
*(int *)optval = si->protocol;
- return 0;
+ ret = 0;
+ goto done;
#endif /* SO_PROTOCOL */
case SO_TYPE:
if (optval == NULL || optlen == NULL ||
*optlen < (socklen_t)sizeof(int)) {
errno = EINVAL;
- return -1;
+ ret = -1;
+ goto done;
}
*optlen = sizeof(int);
*(int *)optval = si->type;
- return 0;
+ ret = 0;
+ goto done;
default:
- return libc_getsockopt(s,
- level,
- optname,
- optval,
- optlen);
+ ret = libc_getsockopt(s,
+ level,
+ optname,
+ optval,
+ optlen);
+ goto done;
}
} else if (level == IPPROTO_TCP) {
switch (optname) {
if (optval == NULL || optlen == NULL ||
*optlen < (socklen_t)sizeof(int)) {
errno = EINVAL;
- return -1;
+ ret = -1;
+ goto done;
}
*optlen = sizeof(int);
*(int *)optval = si->tcp_nodelay;
- return 0;
+ ret = 0;
+ goto done;
#endif /* TCP_NODELAY */
default:
break;
}
errno = ENOPROTOOPT;
- return -1;
+ ret = -1;
+
+done:
+ SWRAP_UNLOCK_SI(si);
+ return ret;
}
#ifdef HAVE_ACCEPT_PSOCKLEN_T
const void *optval, socklen_t optlen)
{
struct socket_info *si = find_socket_info(s);
+ int ret;
if (!si) {
return libc_setsockopt(s,
optname,
optval,
optlen);
- } else if (level == IPPROTO_TCP) {
+ }
+
+ SWRAP_LOCK_SI(si);
+
+ if (level == IPPROTO_TCP) {
switch (optname) {
#ifdef TCP_NODELAY
case TCP_NODELAY: {
if (optval == NULL || optlen == 0 ||
optlen < (socklen_t)sizeof(int)) {
errno = EINVAL;
- return -1;
+ ret = -1;
+ goto done;
}
i = *discard_const_p(int, optval);
if (i != 0 && i != 1) {
errno = EINVAL;
- return -1;
+ ret = -1;
+ goto done;
}
si->tcp_nodelay = i;
- return 0;
+ ret = 0;
+ goto done;
}
#endif /* TCP_NODELAY */
default:
}
#endif /* IP_PKTINFO */
}
- return 0;
+ ret = 0;
+ goto done;
#ifdef HAVE_IPV6
case AF_INET6:
if (level == IPPROTO_IPV6) {
}
#endif /* IPV6_PKTINFO */
}
- return 0;
+ ret = 0;
+ goto done;
#endif
default:
errno = ENOPROTOOPT;
- return -1;
+ ret = -1;
+ goto done;
}
+
+done:
+ SWRAP_UNLOCK_SI(si);
+ return ret;
}
int setsockopt(int s, int level, int optname,
return libc_vioctl(s, r, va);
}
+ SWRAP_LOCK_SI(si);
+
va_copy(ap, va);
rc = libc_vioctl(s, r, va);
va_end(ap);
+ SWRAP_UNLOCK_SI(si);
return rc;
}
int *bcast)
{
size_t i, len = 0;
- ssize_t ret;
+ ssize_t ret = -1;
if (to_un) {
*to_un = NULL;
*bcast = 0;
}
+ SWRAP_LOCK_SI(si);
+
switch (si->type) {
case SOCK_STREAM: {
unsigned long mtu;
if (!si->connected) {
errno = ENOTCONN;
- return -1;
+ goto out;
}
if (msg->msg_iovlen == 0) {
for (i = 0; i < (size_t)msg->msg_iovlen; i++) {
size_t nlen;
nlen = len + msg->msg_iov[i].iov_len;
+ if (nlen < len) {
+ /* overflow */
+ errno = EMSGSIZE;
+ goto out;
+ }
if (nlen > mtu) {
break;
}
if (msg_name == NULL) {
errno = ENOTCONN;
- return -1;
+ goto out;
}
ret = sockaddr_convert_to_un(si, msg_name, msg->msg_namelen,
tmp_un, 0, bcast);
if (ret == -1) {
- return -1;
+ goto out;
}
if (to_un) {
if (si->bound == 0) {
ret = swrap_auto_bind(fd, si, si->family);
if (ret == -1) {
+ SWRAP_UNLOCK_SI(si);
if (errno == ENOTSOCK) {
swrap_remove_stale(fd);
- return -ENOTSOCK;
+ ret = -ENOTSOCK;
} else {
SWRAP_LOG(SWRAP_LOG_ERROR, "swrap_sendmsg_before failed");
- return -1;
}
+ return ret;
}
}
0,
NULL);
if (ret == -1) {
- return -1;
+ goto out;
}
ret = libc_connect(fd,
}
if (ret == -1) {
- return ret;
+ goto out;
}
si->defer_connect = 0;
break;
default:
errno = EHOSTUNREACH;
- return -1;
+ goto out;
}
#ifdef HAVE_STRUCT_MSGHDR_MSG_CONTROL
ret = swrap_sendmsg_filter_cmsghdr(msg, &cmbuf, &cmlen);
if (ret < 0) {
free(cmbuf);
- return -1;
+ goto out;
}
if (cmlen == 0) {
}
#endif
- return 0;
+ ret = 0;
+out:
+ SWRAP_UNLOCK_SI(si);
+
+ return ret;
}
static void swrap_sendmsg_after(int fd,
}
len = ofs;
+ SWRAP_LOCK_SI(si);
+
switch (si->type) {
case SOCK_STREAM:
if (ret == -1) {
break;
}
+ SWRAP_UNLOCK_SI(si);
+
free(buf);
errno = saved_errno;
}
struct iovec *tmp_iov)
{
size_t i, len = 0;
- ssize_t ret;
+ int ret = -1;
+
+ SWRAP_LOCK_SI(si);
(void)fd; /* unused */
unsigned int mtu;
if (!si->connected) {
errno = ENOTCONN;
- return -1;
+ goto out;
}
if (msg->msg_iovlen == 0) {
case SOCK_DGRAM:
if (msg->msg_name == NULL) {
errno = EINVAL;
- return -1;
+ goto out;
}
if (msg->msg_iovlen == 0) {
if (si->bound == 0) {
ret = swrap_auto_bind(fd, si, si->family);
if (ret == -1) {
+ SWRAP_UNLOCK_SI(si);
/*
* When attempting to read or write to a
* descriptor, if an underlying autobind fails
*/
if (errno == ENOTSOCK) {
swrap_remove_stale(fd);
- return -ENOTSOCK;
+ ret = -ENOTSOCK;
} else {
SWRAP_LOG(SWRAP_LOG_ERROR,
"swrap_recvmsg_before failed");
- return -1;
}
+ return ret;
}
}
break;
default:
errno = EHOSTUNREACH;
- return -1;
+ goto out;
}
- return 0;
+ ret = 0;
+out:
+ SWRAP_UNLOCK_SI(si);
+
+ return ret;
}
static int swrap_recvmsg_after(int fd,
avail += msg->msg_iov[i].iov_len;
}
+ SWRAP_LOCK_SI(si);
+
/* Convert the socket address before we leave */
if (si->type == SOCK_DGRAM && un_addr != NULL) {
rc = sockaddr_convert_from_un(si,
buf = (uint8_t *)malloc(remain);
if (buf == NULL) {
/* we just not capture the packet */
+ SWRAP_UNLOCK_SI(si);
errno = saved_errno;
return -1;
}
msg->msg_control != NULL) {
rc = swrap_msghdr_add_socket_info(si, msg);
if (rc < 0) {
+ SWRAP_UNLOCK_SI(si);
return -1;
}
}
#endif
+ SWRAP_UNLOCK_SI(si);
return rc;
}
msg.msg_namelen = tolen; /* size of address */
msg.msg_iov = &tmp; /* scatter/gather array */
msg.msg_iovlen = 1; /* # elements in msg_iov */
-#if HAVE_STRUCT_MSGHDR_MSG_CONTROL
+#ifdef HAVE_STRUCT_MSGHDR_MSG_CONTROL
msg.msg_control = NULL; /* ancillary data, see below */
msg.msg_controllen = 0; /* ancillary data buffer len */
msg.msg_flags = 0; /* flags on received message */
unsigned int iface;
unsigned int prt = ntohs(((const struct sockaddr_in *)(const void *)to)->sin_port);
char type;
+ char *swrap_dir = NULL;
type = SOCKET_TYPE_CHAR_UDP;
+ swrap_dir = socket_wrapper_dir();
+
for(iface=0; iface <= MAX_WRAPPED_INTERFACES; iface++) {
snprintf(un_addr.sa.un.sun_path,
sizeof(un_addr.sa.un.sun_path),
- "%s/"SOCKET_FORMAT,
- socket_wrapper_dir(), type, iface, prt);
+ "%s/"SOCKET_FORMAT, swrap_dir, type, iface, prt);
if (stat(un_addr.sa.un.sun_path, &st) != 0) continue;
/* ignore the any errors in broadcast sends */
un_addr.sa_socklen);
}
+ SAFE_FREE(swrap_dir);
+
+ SWRAP_LOCK_SI(si);
+
swrap_pcap_dump_packet(si, to, SWRAP_SENDTO, buf, len);
+ SWRAP_UNLOCK_SI(si);
+
return len;
}
+ SWRAP_LOCK_SI(si);
/*
* If it is a dgram socket and we are connected, don't include the
* 'to' address.
msg.msg_namelen);
}
+ SWRAP_UNLOCK_SI(si);
+
swrap_sendmsg_after(s, si, &msg, to, ret);
return ret;
msg.msg_namelen = 0; /* size of address */
msg.msg_iov = &tmp; /* scatter/gather array */
msg.msg_iovlen = 1; /* # elements in msg_iov */
-#if HAVE_STRUCT_MSGHDR_MSG_CONTROL
+#ifdef HAVE_STRUCT_MSGHDR_MSG_CONTROL
msg.msg_control = NULL; /* ancillary data, see below */
msg.msg_controllen = 0; /* ancillary data buffer len */
msg.msg_flags = 0; /* flags on received message */
msg.msg_namelen = 0; /* size of address */
msg.msg_iov = &tmp; /* scatter/gather array */
msg.msg_iovlen = 1; /* # elements in msg_iov */
-#if HAVE_STRUCT_MSGHDR_MSG_CONTROL
+#ifdef HAVE_STRUCT_MSGHDR_MSG_CONTROL
msg.msg_control = NULL; /* ancillary data, see below */
msg.msg_controllen = 0; /* ancillary data buffer len */
msg.msg_flags = 0; /* flags on received message */
#endif
omsg->msg_iovlen = msg.msg_iovlen;
+ SWRAP_LOCK_SI(si);
+
/*
* From the manpage:
*
omsg->msg_namelen = msg.msg_namelen;
}
+ SWRAP_UNLOCK_SI(si);
+
return ret;
}
ZERO_STRUCT(msg);
+ SWRAP_LOCK_SI(si);
+
if (si->connected == 0) {
msg.msg_name = omsg->msg_name; /* optional address */
msg.msg_namelen = omsg->msg_namelen; /* size of address */
}
msg.msg_iov = omsg->msg_iov; /* scatter/gather array */
msg.msg_iovlen = omsg->msg_iovlen; /* # elements in msg_iov */
+
+ SWRAP_UNLOCK_SI(si);
+
#ifdef HAVE_STRUCT_MSGHDR_MSG_CONTROL
if (msg.msg_controllen > 0 && msg.msg_control != NULL) {
/* omsg is a const so use a local buffer for modifications */
off_t ofs = 0;
size_t avail = 0;
size_t remain;
+ char *swrap_dir = NULL;
for (i = 0; i < (size_t)msg.msg_iovlen; i++) {
avail += msg.msg_iov[i].iov_len;
type = SOCKET_TYPE_CHAR_UDP;
+ swrap_dir = socket_wrapper_dir();
+
for(iface=0; iface <= MAX_WRAPPED_INTERFACES; iface++) {
snprintf(un_addr.sun_path, sizeof(un_addr.sun_path), "%s/"SOCKET_FORMAT,
- socket_wrapper_dir(), type, iface, prt);
+ swrap_dir, type, iface, prt);
if (stat(un_addr.sun_path, &st) != 0) continue;
msg.msg_name = &un_addr; /* optional address */
libc_sendmsg(s, &msg, flags);
}
+ SAFE_FREE(swrap_dir);
+
+ SWRAP_LOCK_SI(si);
+
swrap_pcap_dump_packet(si, to, SWRAP_SENDTO, buf, len);
free(buf);
+ SWRAP_UNLOCK_SI(si);
+
return len;
}
msg.msg_namelen = 0; /* size of address */
msg.msg_iov = discard_const_p(struct iovec, vector); /* scatter/gather array */
msg.msg_iovlen = count; /* # elements in msg_iov */
-#if HAVE_STRUCT_MSGHDR_MSG_CONTROL
+#ifdef HAVE_STRUCT_MSGHDR_MSG_CONTROL
msg.msg_control = NULL; /* ancillary data, see below */
msg.msg_controllen = 0; /* ancillary data buffer len */
msg.msg_flags = 0; /* flags on received message */
static int swrap_close(int fd)
{
- struct socket_info_fd *fi = find_socket_info_fd(fd);
struct socket_info *si = NULL;
int si_index;
int ret;
- if (fi == NULL) {
+ swrap_mutex_lock(&socket_reset_mutex);
+
+ si_index = find_socket_info_index(fd);
+ if (si_index == -1) {
+ swrap_mutex_unlock(&socket_reset_mutex);
return libc_close(fd);
}
- si_index = fi->si_index;
+ reset_socket_info_index(fd);
+
+ si = swrap_get_socket_info(si_index);
- SWRAP_DLIST_REMOVE(socket_fds, fi);
- free(fi);
+ swrap_mutex_lock(&first_free_mutex);
+ SWRAP_LOCK_SI(si);
ret = libc_close(fd);
- si = &sockets[si_index];
- si->refcount--;
+ swrap_dec_refcount(si);
- if (si->refcount > 0) {
+ if (swrap_get_refcount(si) > 0) {
/* there are still references left */
- return ret;
+ goto out;
}
if (si->myname.sa_socklen > 0 && si->peername.sa_socklen > 0) {
unlink(si->un_addr.sun_path);
}
- si->next_free = first_free;
+ 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);
+
return ret;
}
static int swrap_dup(int fd)
{
struct socket_info *si;
- struct socket_info_fd *src_fi, *fi;
+ int dup_fd, idx;
- src_fi = find_socket_info_fd(fd);
- if (src_fi == NULL) {
+ idx = find_socket_info_index(fd);
+ if (idx == -1) {
return libc_dup(fd);
}
- si = &sockets[src_fi->si_index];
-
- fi = (struct socket_info_fd *)calloc(1, sizeof(struct socket_info_fd));
- if (fi == NULL) {
- errno = ENOMEM;
- return -1;
- }
+ si = swrap_get_socket_info(idx);
- fi->fd = libc_dup(fd);
- if (fi->fd == -1) {
+ dup_fd = libc_dup(fd);
+ if (dup_fd == -1) {
int saved_errno = errno;
- free(fi);
errno = saved_errno;
return -1;
}
- si->refcount++;
- fi->si_index = src_fi->si_index;
+ SWRAP_LOCK_SI(si);
+
+ swrap_inc_refcount(si);
+
+ SWRAP_UNLOCK_SI(si);
/* Make sure we don't have an entry for the fd */
- swrap_remove_stale(fi->fd);
+ swrap_remove_stale(dup_fd);
- SWRAP_DLIST_ADD_AFTER(socket_fds, fi, src_fi);
- return fi->fd;
+ set_socket_info_index(dup_fd, idx);
+
+ return dup_fd;
}
int dup(int fd)
static int swrap_dup2(int fd, int newfd)
{
struct socket_info *si;
- struct socket_info_fd *src_fi, *fi;
+ int dup_fd, idx;
- src_fi = find_socket_info_fd(fd);
- if (src_fi == NULL) {
+ idx = find_socket_info_index(fd);
+ if (idx == -1) {
return libc_dup2(fd, newfd);
}
- si = &sockets[src_fi->si_index];
+ si = swrap_get_socket_info(idx);
if (fd == newfd) {
/*
swrap_close(newfd);
}
- fi = (struct socket_info_fd *)calloc(1, sizeof(struct socket_info_fd));
- if (fi == NULL) {
- errno = ENOMEM;
- return -1;
- }
-
- fi->fd = libc_dup2(fd, newfd);
- if (fi->fd == -1) {
+ dup_fd = libc_dup2(fd, newfd);
+ if (dup_fd == -1) {
int saved_errno = errno;
- free(fi);
errno = saved_errno;
return -1;
}
- si->refcount++;
- fi->si_index = src_fi->si_index;
+ SWRAP_LOCK_SI(si);
+
+ swrap_inc_refcount(si);
+
+ SWRAP_UNLOCK_SI(si);
/* Make sure we don't have an entry for the fd */
- swrap_remove_stale(fi->fd);
+ swrap_remove_stale(dup_fd);
+
+ set_socket_info_index(dup_fd, idx);
- SWRAP_DLIST_ADD_AFTER(socket_fds, fi, src_fi);
- return fi->fd;
+ return dup_fd;
}
int dup2(int fd, int newfd)
static int swrap_vfcntl(int fd, int cmd, va_list va)
{
- struct socket_info_fd *src_fi, *fi;
struct socket_info *si;
- int rc;
+ int rc, dup_fd, idx;
- src_fi = find_socket_info_fd(fd);
- if (src_fi == NULL) {
+ idx = find_socket_info_index(fd);
+ if (idx == -1) {
return libc_vfcntl(fd, cmd, va);
}
- si = &sockets[src_fi->si_index];
+ si = swrap_get_socket_info(idx);
switch (cmd) {
case F_DUPFD:
- fi = (struct socket_info_fd *)calloc(1, sizeof(struct socket_info_fd));
- if (fi == NULL) {
- errno = ENOMEM;
- return -1;
- }
-
- fi->fd = libc_vfcntl(fd, cmd, va);
- if (fi->fd == -1) {
+ dup_fd = libc_vfcntl(fd, cmd, va);
+ if (dup_fd == -1) {
int saved_errno = errno;
- free(fi);
errno = saved_errno;
return -1;
}
- si->refcount++;
- fi->si_index = src_fi->si_index;
+ SWRAP_LOCK_SI(si);
+
+ swrap_inc_refcount(si);
+
+ SWRAP_UNLOCK_SI(si);
/* Make sure we don't have an entry for the fd */
- swrap_remove_stale(fi->fd);
+ swrap_remove_stale(dup_fd);
- SWRAP_DLIST_ADD_AFTER(socket_fds, fi, src_fi);
+ set_socket_info_index(dup_fd, idx);
- rc = fi->fd;
+ rc = dup_fd;
break;
default:
rc = libc_vfcntl(fd, cmd, va);
static void swrap_thread_prepare(void)
{
+ /*
+ * This function should only be called here!!
+ *
+ * We bind all symobls to avoid deadlocks of the fork is
+ * interrupted by a signal handler using a symbol of this
+ * library.
+ */
+ swrap_bind_symbol_all();
+
SWRAP_LOCK_ALL;
}
***************************/
void swrap_constructor(void)
{
+ int ret;
+
/*
* If we hold a lock and the application forks, then the child
* is not able to unlock the mutex and we are in a deadlock.
pthread_atfork(&swrap_thread_prepare,
&swrap_thread_parent,
&swrap_thread_child);
+
+ ret = socket_wrapper_init_mutex(&sockets_mutex);
+ if (ret != 0) {
+ SWRAP_LOG(SWRAP_LOG_ERROR,
+ "Failed to initialize pthread mutex");
+ exit(-1);
+ }
+
+ ret = socket_wrapper_init_mutex(&socket_reset_mutex);
+ if (ret != 0) {
+ SWRAP_LOG(SWRAP_LOG_ERROR,
+ "Failed to initialize pthread mutex");
+ exit(-1);
+ }
+
+ ret = socket_wrapper_init_mutex(&first_free_mutex);
+ if (ret != 0) {
+ SWRAP_LOG(SWRAP_LOG_ERROR,
+ "Failed to initialize pthread mutex");
+ exit(-1);
+ }
}
/****************************
*/
void swrap_destructor(void)
{
- struct socket_info_fd *s = socket_fds;
+ size_t i;
- while (s != NULL) {
- swrap_close(s->fd);
- s = socket_fds;
+ if (socket_fds_idx != NULL) {
+ for (i = 0; i < socket_fds_max; ++i) {
+ if (socket_fds_idx[i] != -1) {
+ swrap_close(i);
+ }
+ }
+ SAFE_FREE(socket_fds_idx);
}
- free(sockets);
+ SAFE_FREE(sockets);
if (swrap.libc.handle != NULL) {
dlclose(swrap.libc.handle);