#endif
/* Add new global locks here please */
-# define SWRAP_LOCK_ALL \
- swrap_mutex_lock(&libc_symbol_binding_mutex); \
+# define SWRAP_LOCK_ALL do { \
+} while(0)
-# define SWRAP_UNLOCK_ALL \
- swrap_mutex_unlock(&libc_symbol_binding_mutex); \
+# define SWRAP_UNLOCK_ALL do { \
+} while(0)
#define SOCKET_INFO_CONTAINER(si) \
(struct socket_info_container *)(si)
/* 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;
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)
+#endif
void swrap_constructor(void) CONSTRUCTOR_ATTRIBUTE;
+#if ! defined(HAVE_DESTRUCTOR_ATTRIBUTE) && defined(HAVE_PRAGMA_FINI)
+#pragma fini (swrap_destructor)
+#endif
void swrap_destructor(void) DESTRUCTOR_ATTRIBUTE;
#ifndef HAVE_GETPROGNAME
enum swrap_lib {
SWRAP_LIBC,
- SWRAP_LIBNSL,
SWRAP_LIBSOCKET,
};
switch (lib) {
case SWRAP_LIBC:
return "libc";
- case SWRAP_LIBNSL:
- return "libnsl";
case SWRAP_LIBSOCKET:
return "libsocket";
}
#endif
switch (lib) {
- case SWRAP_LIBNSL:
case SWRAP_LIBSOCKET:
#ifdef HAVE_LIBSOCKET
handle = swrap.libc.socket_handle;
* This is an optimization to avoid locking each time we check if the symbol is
* bound.
*/
+#define _swrap_bind_symbol_generic(lib, sym_name) do { \
+ swrap.libc.symbols._libc_##sym_name.obj = \
+ _swrap_bind_symbol(lib, #sym_name); \
+} while(0);
+
#define swrap_bind_symbol_libc(sym_name) \
- if (swrap.libc.symbols._libc_##sym_name.obj == NULL) { \
- 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); \
- }
+ _swrap_bind_symbol_generic(SWRAP_LIBC, sym_name)
#define swrap_bind_symbol_libsocket(sym_name) \
- if (swrap.libc.symbols._libc_##sym_name.obj == NULL) { \
- 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); \
- }
+ _swrap_bind_symbol_generic(SWRAP_LIBSOCKET, sym_name)
-#define swrap_bind_symbol_libnsl(sym_name) \
- if (swrap.libc.symbols._libc_##sym_name.obj == NULL) { \
- 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); \
- }
+static void swrap_bind_symbol_all(void);
/****************************************************************************
* IMPORTANT
socklen_t *addrlen,
int flags)
{
- swrap_bind_symbol_libsocket(accept4);
+ swrap_bind_symbol_all();
return swrap.libc.symbols._libc_accept4.f(sockfd, addr, addrlen, flags);
}
static int libc_accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen)
{
- swrap_bind_symbol_libsocket(accept);
+ swrap_bind_symbol_all();
return swrap.libc.symbols._libc_accept.f(sockfd, addr, addrlen);
}
const struct sockaddr *addr,
socklen_t addrlen)
{
- swrap_bind_symbol_libsocket(bind);
+ swrap_bind_symbol_all();
return swrap.libc.symbols._libc_bind.f(sockfd, addr, addrlen);
}
static int libc_close(int fd)
{
- swrap_bind_symbol_libc(close);
+ swrap_bind_symbol_all();
return swrap.libc.symbols._libc_close.f(fd);
}
const struct sockaddr *addr,
socklen_t addrlen)
{
- swrap_bind_symbol_libsocket(connect);
+ swrap_bind_symbol_all();
return swrap.libc.symbols._libc_connect.f(sockfd, addr, addrlen);
}
static int libc_dup(int fd)
{
- swrap_bind_symbol_libc(dup);
+ swrap_bind_symbol_all();
return swrap.libc.symbols._libc_dup.f(fd);
}
static int libc_dup2(int oldfd, int newfd)
{
- swrap_bind_symbol_libc(dup2);
+ swrap_bind_symbol_all();
return swrap.libc.symbols._libc_dup2.f(oldfd, newfd);
}
#ifdef HAVE_EVENTFD
static int libc_eventfd(int count, int flags)
{
- swrap_bind_symbol_libc(eventfd);
+ swrap_bind_symbol_all();
return swrap.libc.symbols._libc_eventfd.f(count, flags);
}
void *arg;
int rc;
- swrap_bind_symbol_libc(fcntl);
+ swrap_bind_symbol_all();
arg = va_arg(ap, void *);
struct sockaddr *addr,
socklen_t *addrlen)
{
- swrap_bind_symbol_libsocket(getpeername);
+ swrap_bind_symbol_all();
return swrap.libc.symbols._libc_getpeername.f(sockfd, addr, addrlen);
}
struct sockaddr *addr,
socklen_t *addrlen)
{
- swrap_bind_symbol_libsocket(getsockname);
+ swrap_bind_symbol_all();
return swrap.libc.symbols._libc_getsockname.f(sockfd, addr, addrlen);
}
void *optval,
socklen_t *optlen)
{
- swrap_bind_symbol_libsocket(getsockopt);
+ swrap_bind_symbol_all();
return swrap.libc.symbols._libc_getsockopt.f(sockfd,
level,
void *arg;
int rc;
- swrap_bind_symbol_libc(ioctl);
+ swrap_bind_symbol_all();
arg = va_arg(ap, void *);
static int libc_listen(int sockfd, int backlog)
{
- swrap_bind_symbol_libsocket(listen);
+ swrap_bind_symbol_all();
return swrap.libc.symbols._libc_listen.f(sockfd, backlog);
}
static FILE *libc_fopen(const char *name, const char *mode)
{
- swrap_bind_symbol_libc(fopen);
+ swrap_bind_symbol_all();
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);
+ swrap_bind_symbol_all();
return swrap.libc.symbols._libc_fopen64.f(name, mode);
}
int mode = 0;
int fd;
- swrap_bind_symbol_libc(open);
+ swrap_bind_symbol_all();
if (flags & O_CREAT) {
mode = va_arg(ap, int);
int mode = 0;
int fd;
- swrap_bind_symbol_libc(open64);
+ swrap_bind_symbol_all();
if (flags & O_CREAT) {
mode = va_arg(ap, int);
int mode = 0;
int fd;
- swrap_bind_symbol_libc(openat);
+ swrap_bind_symbol_all();
if (flags & O_CREAT) {
mode = va_arg(ap, int);
static int libc_pipe(int pipefd[2])
{
- swrap_bind_symbol_libsocket(pipe);
+ swrap_bind_symbol_all();
return swrap.libc.symbols._libc_pipe.f(pipefd);
}
static int libc_read(int fd, void *buf, size_t count)
{
- swrap_bind_symbol_libc(read);
+ swrap_bind_symbol_all();
return swrap.libc.symbols._libc_read.f(fd, buf, count);
}
static ssize_t libc_readv(int fd, const struct iovec *iov, int iovcnt)
{
- swrap_bind_symbol_libsocket(readv);
+ swrap_bind_symbol_all();
return swrap.libc.symbols._libc_readv.f(fd, iov, iovcnt);
}
static int libc_recv(int sockfd, void *buf, size_t len, int flags)
{
- swrap_bind_symbol_libsocket(recv);
+ swrap_bind_symbol_all();
return swrap.libc.symbols._libc_recv.f(sockfd, buf, len, flags);
}
struct sockaddr *src_addr,
socklen_t *addrlen)
{
- swrap_bind_symbol_libsocket(recvfrom);
+ swrap_bind_symbol_all();
return swrap.libc.symbols._libc_recvfrom.f(sockfd,
buf,
static int libc_recvmsg(int sockfd, struct msghdr *msg, int flags)
{
- swrap_bind_symbol_libsocket(recvmsg);
+ swrap_bind_symbol_all();
return swrap.libc.symbols._libc_recvmsg.f(sockfd, msg, flags);
}
static int libc_send(int sockfd, const void *buf, size_t len, int flags)
{
- swrap_bind_symbol_libsocket(send);
+ swrap_bind_symbol_all();
return swrap.libc.symbols._libc_send.f(sockfd, buf, len, flags);
}
static int libc_sendmsg(int sockfd, const struct msghdr *msg, int flags)
{
- swrap_bind_symbol_libsocket(sendmsg);
+ swrap_bind_symbol_all();
return swrap.libc.symbols._libc_sendmsg.f(sockfd, msg, flags);
}
const struct sockaddr *dst_addr,
socklen_t addrlen)
{
- swrap_bind_symbol_libsocket(sendto);
+ swrap_bind_symbol_all();
return swrap.libc.symbols._libc_sendto.f(sockfd,
buf,
const void *optval,
socklen_t optlen)
{
- swrap_bind_symbol_libsocket(setsockopt);
+ swrap_bind_symbol_all();
return swrap.libc.symbols._libc_setsockopt.f(sockfd,
level,
#ifdef HAVE_SIGNALFD
static int libc_signalfd(int fd, const sigset_t *mask, int flags)
{
- swrap_bind_symbol_libsocket(signalfd);
+ swrap_bind_symbol_all();
return swrap.libc.symbols._libc_signalfd.f(fd, mask, flags);
}
static int libc_socket(int domain, int type, int protocol)
{
- swrap_bind_symbol_libsocket(socket);
+ swrap_bind_symbol_all();
return swrap.libc.symbols._libc_socket.f(domain, type, protocol);
}
static int libc_socketpair(int domain, int type, int protocol, int sv[2])
{
- swrap_bind_symbol_libsocket(socketpair);
+ swrap_bind_symbol_all();
return swrap.libc.symbols._libc_socketpair.f(domain, type, protocol, sv);
}
#ifdef HAVE_TIMERFD_CREATE
static int libc_timerfd_create(int clockid, int flags)
{
- swrap_bind_symbol_libc(timerfd_create);
+ swrap_bind_symbol_all();
return swrap.libc.symbols._libc_timerfd_create.f(clockid, flags);
}
static ssize_t libc_write(int fd, const void *buf, size_t count)
{
- swrap_bind_symbol_libc(write);
+ swrap_bind_symbol_all();
return swrap.libc.symbols._libc_write.f(fd, buf, count);
}
static ssize_t libc_writev(int fd, const struct iovec *iov, int iovcnt)
{
- swrap_bind_symbol_libsocket(writev);
+ swrap_bind_symbol_all();
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)
+static void __swrap_bind_symbol_all_once(void)
{
#ifdef HAVE_ACCEPT4
swrap_bind_symbol_libsocket(accept4);
swrap_bind_symbol_libsocket(writev);
}
+static void swrap_bind_symbol_all(void)
+{
+ static pthread_once_t all_symbol_binding_once = PTHREAD_ONCE_INIT;
+
+ pthread_once(&all_symbol_binding_once, __swrap_bind_symbol_all_once);
+}
+
/*********************************************************
* SWRAP HELPER FUNCTIONS
*********************************************************/
sic->meta.next_free = next_free;
}
+static int swrap_un_path(struct sockaddr_un *un,
+ const char *swrap_dir,
+ char type,
+ unsigned int iface,
+ unsigned int prt)
+{
+ int ret;
+
+ ret = snprintf(un->sun_path,
+ sizeof(un->sun_path),
+ "%s/"SOCKET_FORMAT,
+ swrap_dir,
+ type,
+ iface,
+ prt);
+ if ((size_t)ret >= sizeof(un->sun_path)) {
+ return ENAMETOOLONG;
+ }
+
+ return 0;
+}
+
+static int swrap_un_path_EINVAL(struct sockaddr_un *un,
+ const char *swrap_dir)
+{
+ int ret;
+
+ ret = snprintf(un->sun_path,
+ sizeof(un->sun_path),
+ "%s/EINVAL",
+ swrap_dir);
+
+ if ((size_t)ret >= sizeof(un->sun_path)) {
+ return ENAMETOOLONG;
+ }
+
+ return 0;
+}
+
+static bool swrap_dir_usable(const char *swrap_dir)
+{
+ struct sockaddr_un un;
+ int ret;
+
+ ret = swrap_un_path(&un, swrap_dir, SOCKET_TYPE_CHAR_TCP, 0, 0);
+ if (ret == 0) {
+ return true;
+ }
+
+ ret = swrap_un_path_EINVAL(&un, swrap_dir);
+ if (ret == 0) {
+ return true;
+ }
+
+ return false;
+}
+
static char *socket_wrapper_dir(void)
{
char *swrap_dir = NULL;
char *s = getenv("SOCKET_WRAPPER_DIR");
+ char *t;
+ bool ok;
if (s == NULL) {
SWRAP_LOG(SWRAP_LOG_WARN, "SOCKET_WRAPPER_DIR not set");
SWRAP_LOG(SWRAP_LOG_ERROR,
"Unable to resolve socket_wrapper dir path: %s",
strerror(errno));
- return NULL;
+ abort();
+ }
+
+ ok = swrap_dir_usable(swrap_dir);
+ if (ok) {
+ goto done;
}
+ free(swrap_dir);
+
+ ok = swrap_dir_usable(s);
+ if (!ok) {
+ SWRAP_LOG(SWRAP_LOG_ERROR, "SOCKET_WRAPPER_DIR is too long");
+ abort();
+ }
+
+ t = getenv("SOCKET_WRAPPER_DIR_ALLOW_ORIG");
+ if (t == NULL) {
+ SWRAP_LOG(SWRAP_LOG_ERROR,
+ "realpath(SOCKET_WRAPPER_DIR) too long and "
+ "SOCKET_WRAPPER_DIR_ALLOW_ORIG not set");
+ abort();
+
+ }
+
+ swrap_dir = strdup(s);
+ if (swrap_dir == NULL) {
+ SWRAP_LOG(SWRAP_LOG_ERROR,
+ "Unable to duplicate socket_wrapper dir path");
+ abort();
+ }
+
+ SWRAP_LOG(SWRAP_LOG_WARN,
+ "realpath(SOCKET_WRAPPER_DIR) too long, "
+ "using original SOCKET_WRAPPER_DIR\n");
+
+done:
SWRAP_LOG(SWRAP_LOG_TRACE, "socket_wrapper_dir: %s", swrap_dir);
return swrap_dir;
}
size_t i;
int ret;
+ swrap_bind_symbol_all();
+
swrap_mutex_lock(&sockets_mutex);
if (sockets != NULL) {
}
if (is_bcast) {
- snprintf(un->sun_path, sizeof(un->sun_path),
- "%s/EINVAL", swrap_dir);
+ swrap_un_path_EINVAL(un, 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,
- swrap_dir, type, iface, prt);
+ swrap_un_path(un, swrap_dir, type, iface, prt);
SWRAP_LOG(SWRAP_LOG_DEBUG, "un path [%s]", un->sun_path);
SAFE_FREE(swrap_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,
- swrap_dir, type, iface, prt);
+ swrap_un_path(un, swrap_dir, type, iface, prt);
if (stat(un->sun_path, &st) == 0) continue;
set_port(si->family, prt, &si->myname);
}
}
- snprintf(un->sun_path, sizeof(un->sun_path), "%s/"SOCKET_FORMAT,
- swrap_dir, type, iface, prt);
+ swrap_un_path(un, swrap_dir, type, iface, prt);
SWRAP_LOG(SWRAP_LOG_DEBUG, "un path [%s]", un->sun_path);
SAFE_FREE(swrap_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, swrap_dir, type,
- socket_wrapper_default_iface(), port);
+ swrap_un_path(&un_addr.sa.un,
+ 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);
{
struct socket_info *si = find_socket_info(s);
va_list ap;
- int value;
+ int *value_ptr = NULL;
int rc;
if (!si) {
switch (r) {
case FIONREAD:
- value = *((int *)va_arg(ap, int *));
+ if (rc == 0) {
+ value_ptr = ((int *)va_arg(ap, int *));
+ }
if (rc == -1 && errno != EAGAIN && errno != ENOBUFS) {
swrap_pcap_dump_packet(si, NULL, SWRAP_PENDING_RST, NULL, 0);
- } else if (value == 0) { /* END OF FILE */
+ } else if (value_ptr != NULL && *value_ptr == 0) { /* END OF FILE */
swrap_pcap_dump_packet(si, NULL, SWRAP_PENDING_RST, NULL, 0);
}
break;
+#ifdef FIONWRITE
+ case FIONWRITE:
+ /* this is FreeBSD */
+ FALL_THROUGH; /* to TIOCOUTQ */
+#endif /* FIONWRITE */
+ case TIOCOUTQ: /* same as SIOCOUTQ on Linux */
+ /*
+ * This may return more bytes then the application
+ * sent into the socket, for tcp it should
+ * return the number of unacked bytes.
+ *
+ * On AF_UNIX, all bytes are immediately acked!
+ */
+ if (rc == 0) {
+ value_ptr = ((int *)va_arg(ap, int *));
+ *value_ptr = 0;
+ }
+ break;
}
va_end(ap);
}
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, swrap_dir, type, iface, prt);
+ swrap_un_path(&un_addr.sa.un,
+ swrap_dir,
+ type,
+ iface,
+ prt);
if (stat(un_addr.sa.un.sun_path, &st) != 0) continue;
/* ignore the any errors in broadcast sends */
}
for(iface=0; iface <= MAX_WRAPPED_INTERFACES; iface++) {
- snprintf(un_addr.sun_path, sizeof(un_addr.sun_path), "%s/"SOCKET_FORMAT,
- swrap_dir, type, iface, prt);
+ swrap_un_path(&un_addr, swrap_dir, type, iface, prt);
if (stat(un_addr.sun_path, &st) != 0) continue;
msg.msg_name = &un_addr; /* optional address */