2006-10-09 00:48:34 +04:00
/*
2008-02-20 01:53:04 +03:00
* Copyright ( C ) Jelmer Vernooij 2005 , 2008 < jelmer @ samba . org >
2009-03-09 19:48:08 +03:00
* Copyright ( C ) Stefan Metzmacher 2006 - 2009 < metze @ samba . org >
2014-04-07 18:12:21 +04:00
* Copyright ( C ) Andreas Schneider 2013 < asn @ samba . org >
2006-10-09 00:48:34 +04:00
*
* All rights reserved .
2014-04-07 18:12:21 +04:00
*
2006-10-09 00:48:34 +04:00
* Redistribution and use in source and binary forms , with or without
* modification , are permitted provided that the following conditions
* are met :
2014-04-07 18:12:21 +04:00
*
2006-10-09 00:48:34 +04:00
* 1. Redistributions of source code must retain the above copyright
* notice , this list of conditions and the following disclaimer .
2014-04-07 18:12:21 +04:00
*
2006-10-09 00:48:34 +04:00
* 2. Redistributions in binary form must reproduce the above copyright
* notice , this list of conditions and the following disclaimer in the
* documentation and / or other materials provided with the distribution .
2014-04-07 18:12:21 +04:00
*
2006-10-09 00:48:34 +04:00
* 3. Neither the name of the author nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission .
2014-04-07 18:12:21 +04:00
*
2006-10-09 00:48:34 +04:00
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ` ` AS IS ' ' AND
* ANY EXPRESS OR IMPLIED WARRANTIES , INCLUDING , BUT NOT LIMITED TO , THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED . IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT , INDIRECT , INCIDENTAL , SPECIAL , EXEMPLARY , OR CONSEQUENTIAL
* DAMAGES ( INCLUDING , BUT NOT LIMITED TO , PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES ; LOSS OF USE , DATA , OR PROFITS ; OR BUSINESS INTERRUPTION )
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY , WHETHER IN CONTRACT , STRICT
* 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 .
*
*/
/*
Socket wrapper library . Passes all socket communication over
unix domain sockets if the environment variable SOCKET_WRAPPER_DIR
2005-03-28 05:00:39 +04:00
is set .
*/
2011-11-21 02:45:05 +04:00
# include "config.h"
2005-03-28 05:00:39 +04:00
# include <sys/types.h>
2006-10-19 08:56:21 +04:00
# include <sys/time.h>
2005-06-10 16:21:46 +04:00
# include <sys/stat.h>
2005-03-28 05:00:39 +04:00
# include <sys/socket.h>
2006-10-09 01:45:07 +04:00
# include <sys/ioctl.h>
2013-11-22 08:15:13 +04:00
# ifdef HAVE_SYS_FILIO_H
2006-10-17 13:35:45 +04:00
# include <sys/filio.h>
2013-11-22 08:15:13 +04:00
# endif
2014-04-07 18:12:21 +04:00
# ifdef HAVE_SYS_SIGNALFD_H
# include <sys/signalfd.h>
# endif
# ifdef HAVE_SYS_EVENTFD_H
# include <sys/eventfd.h>
# endif
# ifdef HAVE_SYS_TIMERFD_H
# include <sys/timerfd.h>
# endif
# include <sys/uio.h>
2005-03-28 05:00:39 +04:00
# include <errno.h>
# include <sys/un.h>
# include <netinet/in.h>
2005-03-31 03:28:15 +04:00
# include <netinet/tcp.h>
2014-04-07 18:12:21 +04:00
# include <arpa/inet.h>
2006-10-09 01:45:07 +04:00
# include <fcntl.h>
2005-03-28 05:00:39 +04:00
# include <stdlib.h>
# include <string.h>
# include <stdio.h>
2008-03-17 16:08:57 +03:00
# include <stdint.h>
2014-04-07 18:12:21 +04:00
# include <stdarg.h>
# include <stdbool.h>
# include <unistd.h>
2014-06-03 16:50:05 +04:00
# ifdef HAVE_GNU_LIB_NAMES_H
# include <gnu/lib-names.h>
# endif
2013-11-22 08:15:13 +04:00
2014-04-07 18:12:21 +04:00
enum swrap_dbglvl_e {
SWRAP_LOG_ERROR = 0 ,
SWRAP_LOG_WARN ,
SWRAP_LOG_DEBUG ,
SWRAP_LOG_TRACE
} ;
/* GCC have printf type attribute check. */
# ifdef HAVE_FUNCTION_ATTRIBUTE_FORMAT
# define PRINTF_ATTRIBUTE(a,b) __attribute__ ((__format__ (__printf__, a, b)))
# else
# define PRINTF_ATTRIBUTE(a,b)
# endif /* HAVE_FUNCTION_ATTRIBUTE_FORMAT */
# ifdef HAVE_DESTRUCTOR_ATTRIBUTE
# define DESTRUCTOR_ATTRIBUTE __attribute__ ((destructor))
# else
# define DESTRUCTOR_ATTRIBUTE
2013-11-22 08:15:13 +04:00
# endif
2014-04-07 18:12:21 +04:00
# ifdef HAVE_GCC_THREAD_LOCAL_STORAGE
# define SWRAP_THREAD __thread
# else
# define SWRAP_THREAD
# endif
# ifndef MIN
# define MIN(a,b) ((a)<(b)?(a):(b))
2013-11-22 08:15:13 +04:00
# endif
# ifndef ZERO_STRUCT
# define ZERO_STRUCT(x) memset((char *)&(x), 0, sizeof(x))
# endif
2006-09-17 09:11:57 +04:00
2014-04-07 18:12:21 +04:00
# ifndef discard_const
# define discard_const(ptr) ((void *)((uintptr_t)(ptr)))
# endif
2013-11-22 08:15:13 +04:00
2014-04-07 18:12:21 +04:00
# ifndef discard_const_p
# define discard_const_p(type, ptr) ((type *)discard_const(ptr))
2005-03-28 05:00:39 +04:00
# endif
2014-06-03 16:54:28 +04:00
# ifdef IPV6_PKTINFO
# ifndef IPV6_RECVPKTINFO
# define IPV6_RECVPKTINFO IPV6_PKTINFO
# endif /* IPV6_RECVPKTINFO */
# endif /* IPV6_PKTINFO */
2006-10-09 01:53:09 +04:00
# 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 )
2014-04-07 18:12:21 +04:00
# if defined(HAVE_GETTIMEOFDAY_TZ) || defined(HAVE_GETTIMEOFDAY_TZ_VOID)
2006-10-05 15:39:59 +04:00
# define swrapGetTimeOfDay(tval) gettimeofday(tval,NULL)
# else
# define swrapGetTimeOfDay(tval) gettimeofday(tval)
# endif
2005-07-21 12:42:17 +04:00
/* we need to use a very terse format here as IRIX 6.4 silently
truncates names to 16 chars , so if we use a longer name then we
2014-04-07 18:12:21 +04:00
can ' t tell which port a packet came from with recvfrom ( )
2005-07-21 12:42:17 +04:00
with this format we have 8 chars left for the directory name
*/
2005-11-07 18:36:51 +03:00
# define SOCKET_FORMAT "%c%02X%04X"
# define SOCKET_TYPE_CHAR_TCP 'T'
# define SOCKET_TYPE_CHAR_UDP 'U'
2007-04-16 08:59:47 +04:00
# define SOCKET_TYPE_CHAR_TCP_V6 'X'
# define SOCKET_TYPE_CHAR_UDP_V6 'Y'
2005-07-21 12:42:17 +04:00
2014-04-07 18:12:21 +04:00
/*
* Cut down to 1500 byte packets for stream sockets ,
* which makes it easier to format PCAP capture files
* ( as the caller will simply continue from here )
*/
# define SOCKET_MAX_PACKET 1500
# define SOCKET_MAX_SOCKETS 1024
2011-04-19 04:02:55 +04:00
/* 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
* without changing the format above */
2012-07-06 09:39:09 +04:00
# define MAX_WRAPPED_INTERFACES 40
2006-09-26 15:31:14 +04:00
2014-04-07 18:12:21 +04:00
struct socket_info_fd {
struct socket_info_fd * prev , * next ;
int fd ;
} ;
struct socket_info
{
struct socket_info_fd * fds ;
int family ;
int type ;
int protocol ;
int bound ;
int bcast ;
int is_server ;
int connected ;
int defer_connect ;
2014-06-03 16:54:28 +04:00
int pktinfo ;
2014-04-07 18:12:21 +04:00
char * tmp_path ;
2014-06-03 16:50:53 +04:00
struct sockaddr * bindname ;
socklen_t bindname_len ;
2014-04-07 18:12:21 +04:00
struct sockaddr * myname ;
socklen_t myname_len ;
struct sockaddr * peername ;
socklen_t peername_len ;
struct {
unsigned long pck_snd ;
unsigned long pck_rcv ;
} io ;
struct socket_info * prev , * next ;
} ;
/*
* File descriptors are shared between threads so we should share socket
* information too .
*/
struct socket_info * sockets ;
/* Function prototypes */
bool socket_wrapper_enabled ( void ) ;
void swrap_destructor ( void ) DESTRUCTOR_ATTRIBUTE ;
# ifdef NDEBUG
# define SWRAP_LOG(...)
# else
static void swrap_log ( enum swrap_dbglvl_e dbglvl , const char * format , . . . ) PRINTF_ATTRIBUTE ( 2 , 3 ) ;
# define SWRAP_LOG(dbglvl, ...) swrap_log((dbglvl), __VA_ARGS__)
static void swrap_log ( enum swrap_dbglvl_e dbglvl , const char * format , . . . )
{
char buffer [ 1024 ] ;
va_list va ;
const char * d ;
unsigned int lvl = 0 ;
d = getenv ( " SOCKET_WRAPPER_DEBUGLEVEL " ) ;
if ( d ! = NULL ) {
lvl = atoi ( d ) ;
}
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 \n " ,
( int ) getpid ( ) , buffer ) ;
break ;
case SWRAP_LOG_WARN :
fprintf ( stderr ,
" SWRAP_WARN(%d): %s \n " ,
( int ) getpid ( ) , buffer ) ;
break ;
case SWRAP_LOG_DEBUG :
fprintf ( stderr ,
" SWRAP_DEBUG(%d): %s \n " ,
( int ) getpid ( ) , buffer ) ;
break ;
case SWRAP_LOG_TRACE :
fprintf ( stderr ,
" SWRAP_TRACE(%d): %s \n " ,
( int ) getpid ( ) , buffer ) ;
break ;
}
}
}
# endif
/*********************************************************
* SWRAP LOADING LIBC FUNCTIONS
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
# include <dlfcn.h>
struct swrap_libc_fns {
int ( * libc_accept ) ( int sockfd ,
struct sockaddr * addr ,
socklen_t * addrlen ) ;
int ( * libc_bind ) ( int sockfd ,
const struct sockaddr * addr ,
socklen_t addrlen ) ;
int ( * libc_close ) ( int fd ) ;
int ( * libc_connect ) ( int sockfd ,
const struct sockaddr * addr ,
socklen_t addrlen ) ;
int ( * libc_dup ) ( int fd ) ;
int ( * libc_dup2 ) ( int oldfd , int newfd ) ;
# ifdef HAVE_EVENTFD
int ( * libc_eventfd ) ( int count , int flags ) ;
# endif
int ( * libc_getpeername ) ( int sockfd ,
struct sockaddr * addr ,
socklen_t * addrlen ) ;
int ( * libc_getsockname ) ( int sockfd ,
struct sockaddr * addr ,
socklen_t * addrlen ) ;
int ( * libc_getsockopt ) ( int sockfd ,
int level ,
int optname ,
void * optval ,
socklen_t * optlen ) ;
int ( * libc_ioctl ) ( int d , unsigned long int request , . . . ) ;
int ( * libc_listen ) ( int sockfd , int backlog ) ;
int ( * libc_open ) ( const char * pathname , int flags , mode_t mode ) ;
int ( * libc_pipe ) ( int pipefd [ 2 ] ) ;
int ( * libc_read ) ( int fd , void * buf , size_t count ) ;
ssize_t ( * libc_readv ) ( int fd , const struct iovec * iov , int iovcnt ) ;
int ( * libc_recv ) ( int sockfd , void * buf , size_t len , int flags ) ;
int ( * libc_recvfrom ) ( int sockfd ,
void * buf ,
size_t len ,
int flags ,
struct sockaddr * src_addr ,
socklen_t * addrlen ) ;
int ( * libc_recvmsg ) ( int sockfd , const struct msghdr * msg , int flags ) ;
int ( * libc_send ) ( int sockfd , const void * buf , size_t len , int flags ) ;
int ( * libc_sendmsg ) ( int sockfd , const struct msghdr * msg , int flags ) ;
int ( * libc_sendto ) ( int sockfd ,
const void * buf ,
size_t len ,
int flags ,
const struct sockaddr * dst_addr ,
socklen_t addrlen ) ;
int ( * libc_setsockopt ) ( int sockfd ,
int level ,
int optname ,
const void * optval ,
socklen_t optlen ) ;
# ifdef HAVE_SIGNALFD
int ( * libc_signalfd ) ( int fd , const sigset_t * mask , int flags ) ;
# endif
int ( * libc_socket ) ( int domain , int type , int protocol ) ;
int ( * libc_socketpair ) ( int domain , int type , int protocol , int sv [ 2 ] ) ;
# ifdef HAVE_TIMERFD_CREATE
int ( * libc_timerfd_create ) ( int clockid , int flags ) ;
# endif
ssize_t ( * libc_writev ) ( int fd , const struct iovec * iov , int iovcnt ) ;
} ;
struct swrap {
void * libc_handle ;
void * libsocket_handle ;
bool initialised ;
bool enabled ;
char * socket_dir ;
struct swrap_libc_fns fns ;
} ;
static struct swrap swrap ;
/* prototypes */
static const char * socket_wrapper_dir ( void ) ;
# define LIBC_NAME "libc.so"
enum swrap_lib {
SWRAP_LIBC ,
SWRAP_LIBNSL ,
SWRAP_LIBSOCKET ,
} ;
# ifndef NDEBUG
static const char * swrap_str_lib ( enum swrap_lib lib )
{
switch ( lib ) {
case SWRAP_LIBC :
return " libc " ;
case SWRAP_LIBNSL :
return " libnsl " ;
case SWRAP_LIBSOCKET :
return " libsocket " ;
}
/* 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 flags = RTLD_LAZY ;
void * handle = NULL ;
int i ;
# ifdef RTLD_DEEPBIND
flags | = RTLD_DEEPBIND ;
# endif
switch ( lib ) {
case SWRAP_LIBNSL :
/* FALL TROUGH */
case SWRAP_LIBSOCKET :
# ifdef HAVE_LIBSOCKET
handle = swrap . libsocket_handle ;
if ( handle = = NULL ) {
for ( handle = NULL , i = 10 ; handle = = NULL & & i > = 0 ; i - - ) {
char soname [ 256 ] = { 0 } ;
snprintf ( soname , sizeof ( soname ) , " libsocket.so.%d " , i ) ;
handle = dlopen ( soname , flags ) ;
}
swrap . libsocket_handle = handle ;
}
break ;
# endif
/* FALL TROUGH */
case SWRAP_LIBC :
handle = swrap . libc_handle ;
2014-06-03 16:50:05 +04:00
# ifdef LIBC_SO
if ( handle = = NULL ) {
handle = dlopen ( LIBC_SO , flags ) ;
}
# endif
2014-04-07 18:12:21 +04:00
if ( handle = = NULL ) {
for ( handle = NULL , i = 10 ; handle = = NULL & & i > = 0 ; i - - ) {
char soname [ 256 ] = { 0 } ;
snprintf ( soname , sizeof ( soname ) , " libc.so.%d " , i ) ;
handle = dlopen ( soname , flags ) ;
}
swrap . libc_handle = handle ;
}
break ;
}
if ( handle = = NULL ) {
2014-05-08 16:07:16 +04:00
# ifdef RTLD_NEXT
handle = swrap . libc_handle = swrap . libsocket_handle = RTLD_NEXT ;
# else
2014-04-07 18:12:21 +04:00
SWRAP_LOG ( SWRAP_LOG_ERROR ,
" Failed to dlopen library: %s \n " ,
dlerror ( ) ) ;
exit ( - 1 ) ;
2014-05-08 16:07:16 +04:00
# endif
2014-04-07 18:12:21 +04:00
}
return handle ;
}
static void * _swrap_load_lib_function ( enum swrap_lib lib , const char * fn_name )
{
void * handle ;
void * func ;
handle = swrap_load_lib_handle ( lib ) ;
func = dlsym ( handle , fn_name ) ;
if ( func = = NULL ) {
SWRAP_LOG ( SWRAP_LOG_ERROR ,
" Failed to find %s: %s \n " ,
fn_name , dlerror ( ) ) ;
exit ( - 1 ) ;
}
SWRAP_LOG ( SWRAP_LOG_TRACE ,
" Loaded %s from %s " ,
fn_name , swrap_str_lib ( lib ) ) ;
return func ;
}
# define swrap_load_lib_function(lib, fn_name) \
if ( swrap . fns . libc_ # # fn_name = = NULL ) { \
* ( void * * ) ( & swrap . fns . libc_ # # fn_name ) = \
_swrap_load_lib_function ( lib , # fn_name ) ; \
}
/*
* IMPORTANT
*
2014-05-08 17:30:09 +04:00
* Functions especially from libc need to be loaded individually , you can ' t load
2014-04-07 18:12:21 +04:00
* 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 .
*/
static int libc_accept ( int sockfd , struct sockaddr * addr , socklen_t * addrlen )
{
swrap_load_lib_function ( SWRAP_LIBSOCKET , accept ) ;
return swrap . fns . libc_accept ( sockfd , addr , addrlen ) ;
}
static int libc_bind ( int sockfd ,
const struct sockaddr * addr ,
socklen_t addrlen )
{
swrap_load_lib_function ( SWRAP_LIBSOCKET , bind ) ;
return swrap . fns . libc_bind ( sockfd , addr , addrlen ) ;
}
static int libc_close ( int fd )
{
swrap_load_lib_function ( SWRAP_LIBC , close ) ;
return swrap . fns . libc_close ( fd ) ;
}
static int libc_connect ( int sockfd ,
const struct sockaddr * addr ,
socklen_t addrlen )
{
swrap_load_lib_function ( SWRAP_LIBSOCKET , connect ) ;
return swrap . fns . libc_connect ( sockfd , addr , addrlen ) ;
}
static int libc_dup ( int fd )
{
swrap_load_lib_function ( SWRAP_LIBC , dup ) ;
return swrap . fns . libc_dup ( fd ) ;
}
static int libc_dup2 ( int oldfd , int newfd )
{
swrap_load_lib_function ( SWRAP_LIBC , dup2 ) ;
return swrap . fns . libc_dup2 ( oldfd , newfd ) ;
}
# ifdef HAVE_EVENTFD
static int libc_eventfd ( int count , int flags )
{
swrap_load_lib_function ( SWRAP_LIBC , eventfd ) ;
return swrap . fns . libc_eventfd ( count , flags ) ;
}
# endif
static int libc_getpeername ( int sockfd ,
struct sockaddr * addr ,
socklen_t * addrlen )
{
swrap_load_lib_function ( SWRAP_LIBSOCKET , getpeername ) ;
return swrap . fns . libc_getpeername ( sockfd , addr , addrlen ) ;
}
static int libc_getsockname ( int sockfd ,
struct sockaddr * addr ,
socklen_t * addrlen )
{
swrap_load_lib_function ( SWRAP_LIBSOCKET , getsockname ) ;
return swrap . fns . libc_getsockname ( sockfd , addr , addrlen ) ;
}
static int libc_getsockopt ( int sockfd ,
int level ,
int optname ,
void * optval ,
socklen_t * optlen )
{
swrap_load_lib_function ( SWRAP_LIBSOCKET , getsockopt ) ;
return swrap . fns . libc_getsockopt ( sockfd , level , optname , optval , optlen ) ;
}
static int libc_vioctl ( int d , unsigned long int request , va_list ap )
{
long int args [ 4 ] ;
int rc ;
int i ;
swrap_load_lib_function ( SWRAP_LIBC , ioctl ) ;
for ( i = 0 ; i < 4 ; i + + ) {
args [ i ] = va_arg ( ap , long int ) ;
}
rc = swrap . fns . libc_ioctl ( d ,
request ,
args [ 0 ] ,
args [ 1 ] ,
args [ 2 ] ,
args [ 3 ] ) ;
return rc ;
}
static int libc_listen ( int sockfd , int backlog )
{
swrap_load_lib_function ( SWRAP_LIBSOCKET , listen ) ;
return swrap . fns . libc_listen ( sockfd , backlog ) ;
}
static int libc_vopen ( const char * pathname , int flags , va_list ap )
{
long int mode = 0 ;
int fd ;
swrap_load_lib_function ( SWRAP_LIBC , open ) ;
mode = va_arg ( ap , long int ) ;
fd = swrap . fns . libc_open ( pathname , flags , ( mode_t ) mode ) ;
return fd ;
}
2014-05-08 16:05:30 +04:00
static int libc_open ( const char * pathname , int flags , . . . )
{
va_list ap ;
int fd ;
va_start ( ap , flags ) ;
fd = libc_vopen ( pathname , flags , ap ) ;
va_end ( ap ) ;
return fd ;
}
2014-04-07 18:12:21 +04:00
static int libc_pipe ( int pipefd [ 2 ] )
{
swrap_load_lib_function ( SWRAP_LIBSOCKET , pipe ) ;
return swrap . fns . libc_pipe ( pipefd ) ;
}
static int libc_read ( int fd , void * buf , size_t count )
{
swrap_load_lib_function ( SWRAP_LIBC , read ) ;
return swrap . fns . libc_read ( fd , buf , count ) ;
}
static ssize_t libc_readv ( int fd , const struct iovec * iov , int iovcnt )
{
swrap_load_lib_function ( SWRAP_LIBSOCKET , readv ) ;
return swrap . fns . libc_readv ( fd , iov , iovcnt ) ;
}
static int libc_recv ( int sockfd , void * buf , size_t len , int flags )
{
swrap_load_lib_function ( SWRAP_LIBSOCKET , recv ) ;
return swrap . fns . libc_recv ( sockfd , buf , len , flags ) ;
}
static int libc_recvfrom ( int sockfd ,
void * buf ,
size_t len ,
int flags ,
struct sockaddr * src_addr ,
socklen_t * addrlen )
{
swrap_load_lib_function ( SWRAP_LIBSOCKET , recvfrom ) ;
return swrap . fns . libc_recvfrom ( sockfd , buf , len , flags , src_addr , addrlen ) ;
}
static int libc_recvmsg ( int sockfd , struct msghdr * msg , int flags )
{
swrap_load_lib_function ( SWRAP_LIBSOCKET , recvmsg ) ;
return swrap . fns . libc_recvmsg ( sockfd , msg , flags ) ;
}
static int libc_send ( int sockfd , const void * buf , size_t len , int flags )
{
swrap_load_lib_function ( SWRAP_LIBSOCKET , send ) ;
return swrap . fns . libc_send ( sockfd , buf , len , flags ) ;
}
static int libc_sendmsg ( int sockfd , const struct msghdr * msg , int flags )
{
swrap_load_lib_function ( SWRAP_LIBSOCKET , sendmsg ) ;
return swrap . fns . libc_sendmsg ( sockfd , msg , flags ) ;
}
static int libc_sendto ( int sockfd ,
const void * buf ,
size_t len ,
int flags ,
const struct sockaddr * dst_addr ,
socklen_t addrlen )
{
swrap_load_lib_function ( SWRAP_LIBSOCKET , sendto ) ;
return swrap . fns . libc_sendto ( sockfd , buf , len , flags , dst_addr , addrlen ) ;
}
static int libc_setsockopt ( int sockfd ,
int level ,
int optname ,
const void * optval ,
socklen_t optlen )
{
swrap_load_lib_function ( SWRAP_LIBSOCKET , setsockopt ) ;
return swrap . fns . libc_setsockopt ( sockfd , level , optname , optval , optlen ) ;
}
# ifdef HAVE_SIGNALFD
static int libc_signalfd ( int fd , const sigset_t * mask , int flags )
{
swrap_load_lib_function ( SWRAP_LIBSOCKET , signalfd ) ;
return swrap . fns . libc_signalfd ( fd , mask , flags ) ;
}
# endif
static int libc_socket ( int domain , int type , int protocol )
{
swrap_load_lib_function ( SWRAP_LIBSOCKET , socket ) ;
return swrap . fns . libc_socket ( domain , type , protocol ) ;
}
static int libc_socketpair ( int domain , int type , int protocol , int sv [ 2 ] )
{
swrap_load_lib_function ( SWRAP_LIBSOCKET , socketpair ) ;
return swrap . fns . libc_socketpair ( domain , type , protocol , sv ) ;
}
# ifdef HAVE_TIMERFD_CREATE
static int libc_timerfd_create ( int clockid , int flags )
{
swrap_load_lib_function ( SWRAP_LIBC , timerfd_create ) ;
return swrap . fns . libc_timerfd_create ( clockid , flags ) ;
}
# endif
static ssize_t libc_writev ( int fd , const struct iovec * iov , int iovcnt )
{
swrap_load_lib_function ( SWRAP_LIBSOCKET , writev ) ;
return swrap . fns . libc_writev ( fd , iov , iovcnt ) ;
}
/*********************************************************
* SWRAP HELPER FUNCTIONS
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2009-03-03 18:45:41 +03:00
# ifdef HAVE_IPV6
/*
* FD00 : : 5357 : 5F XX
*/
2009-03-09 11:24:45 +03:00
static const struct in6_addr * swrap_ipv6 ( void )
{
static struct in6_addr v ;
static int initialized ;
int ret ;
if ( initialized ) {
return & v ;
}
initialized = 1 ;
ret = inet_pton ( AF_INET6 , " FD00::5357:5F00 " , & v ) ;
if ( ret < = 0 ) {
abort ( ) ;
}
return & v ;
}
2009-03-03 18:45:41 +03:00
# endif
2007-04-16 08:59:47 +04:00
2005-03-31 03:28:15 +04:00
static struct sockaddr * sockaddr_dup ( const void * data , socklen_t len )
2005-03-28 05:00:39 +04:00
{
struct sockaddr * ret = ( struct sockaddr * ) malloc ( len ) ;
memcpy ( ret , data , len ) ;
return ret ;
}
2007-04-16 08:59:47 +04:00
static void set_port ( int family , int prt , struct sockaddr * addr )
{
switch ( family ) {
case AF_INET :
( ( struct sockaddr_in * ) addr ) - > sin_port = htons ( prt ) ;
break ;
# ifdef HAVE_IPV6
case AF_INET6 :
( ( struct sockaddr_in6 * ) addr ) - > sin6_port = htons ( prt ) ;
break ;
# endif
}
}
2007-06-11 18:41:14 +04:00
static size_t socket_length ( int family )
2007-04-16 08:59:47 +04:00
{
switch ( family ) {
case AF_INET :
return sizeof ( struct sockaddr_in ) ;
# ifdef HAVE_IPV6
case AF_INET6 :
return sizeof ( struct sockaddr_in6 ) ;
# endif
}
2007-06-11 18:41:14 +04:00
return 0 ;
2007-04-16 08:59:47 +04:00
}
2014-04-07 18:12:21 +04:00
static const char * socket_wrapper_dir ( void )
2005-07-21 17:45:07 +04:00
{
const char * s = getenv ( " SOCKET_WRAPPER_DIR " ) ;
if ( s = = NULL ) {
return NULL ;
}
if ( strncmp ( s , " ./ " , 2 ) = = 0 ) {
s + = 2 ;
}
2014-04-07 18:12:21 +04:00
SWRAP_LOG ( SWRAP_LOG_TRACE , " socket_wrapper_dir: %s " , s ) ;
2005-07-21 17:45:07 +04:00
return s ;
}
2014-04-07 18:12:21 +04:00
bool socket_wrapper_enabled ( void )
{
const char * s = socket_wrapper_dir ( ) ;
return s ! = NULL ? true : false ;
}
static unsigned int socket_wrapper_default_iface ( void )
2005-11-07 18:36:51 +03:00
{
const char * s = getenv ( " SOCKET_WRAPPER_DEFAULT_IFACE " ) ;
if ( s ) {
unsigned int iface ;
2007-04-16 08:59:47 +04:00
if ( sscanf ( s , " %u " , & iface ) = = 1 ) {
if ( iface > = 1 & & iface < = MAX_WRAPPED_INTERFACES ) {
return iface ;
}
2005-11-07 18:36:51 +03:00
}
}
return 1 ; /* 127.0.0.1 */
}
2007-04-16 08:59:47 +04:00
static int convert_un_in ( const struct sockaddr_un * un , struct sockaddr * in , socklen_t * len )
2005-03-28 05:00:39 +04:00
{
2005-11-07 18:36:51 +03:00
unsigned int iface ;
2005-03-28 05:00:39 +04:00
unsigned int prt ;
const char * p ;
2005-11-07 18:36:51 +03:00
char type ;
2005-03-28 05:00:39 +04:00
2005-06-10 16:21:46 +04:00
p = strrchr ( un - > sun_path , ' / ' ) ;
2005-03-28 05:00:39 +04:00
if ( p ) p + + ; else p = un - > sun_path ;
2005-11-07 18:36:51 +03:00
if ( sscanf ( p , SOCKET_FORMAT , & type , & iface , & prt ) ! = 3 ) {
errno = EINVAL ;
return - 1 ;
}
2014-04-07 18:12:21 +04:00
SWRAP_LOG ( SWRAP_LOG_TRACE , " type %c iface %u port %u " ,
type , iface , prt ) ;
2007-04-16 08:59:47 +04:00
if ( iface = = 0 | | iface > MAX_WRAPPED_INTERFACES ) {
2005-11-07 18:36:51 +03:00
errno = EINVAL ;
return - 1 ;
}
2007-04-16 08:59:47 +04:00
if ( prt > 0xFFFF ) {
2005-11-07 18:36:51 +03:00
errno = EINVAL ;
return - 1 ;
}
2007-04-16 08:59:47 +04:00
switch ( type ) {
case SOCKET_TYPE_CHAR_TCP :
case SOCKET_TYPE_CHAR_UDP : {
2011-03-02 22:46:45 +03:00
struct sockaddr_in * in2 = ( struct sockaddr_in * ) ( void * ) in ;
2011-02-12 14:18:16 +03:00
2007-04-16 08:59:47 +04:00
if ( ( * len ) < sizeof ( * in2 ) ) {
errno = EINVAL ;
return - 1 ;
}
memset ( in2 , 0 , sizeof ( * in2 ) ) ;
in2 - > sin_family = AF_INET ;
in2 - > sin_addr . s_addr = htonl ( ( 127 < < 24 ) | iface ) ;
in2 - > sin_port = htons ( prt ) ;
* len = sizeof ( * in2 ) ;
break ;
}
# ifdef HAVE_IPV6
case SOCKET_TYPE_CHAR_TCP_V6 :
case SOCKET_TYPE_CHAR_UDP_V6 : {
2011-03-02 22:46:45 +03:00
struct sockaddr_in6 * in2 = ( struct sockaddr_in6 * ) ( void * ) in ;
2011-02-12 14:18:16 +03:00
2007-04-16 08:59:47 +04:00
if ( ( * len ) < sizeof ( * in2 ) ) {
errno = EINVAL ;
return - 1 ;
}
memset ( in2 , 0 , sizeof ( * in2 ) ) ;
in2 - > sin6_family = AF_INET6 ;
2009-03-09 11:24:45 +03:00
in2 - > sin6_addr = * swrap_ipv6 ( ) ;
2009-03-03 18:45:41 +03:00
in2 - > sin6_addr . s6_addr [ 15 ] = iface ;
2007-04-16 08:59:47 +04:00
in2 - > sin6_port = htons ( prt ) ;
* len = sizeof ( * in2 ) ;
break ;
}
# endif
default :
2005-11-07 18:36:51 +03:00
errno = EINVAL ;
return - 1 ;
2005-03-28 05:00:39 +04:00
}
2005-11-07 18:36:51 +03:00
2005-03-28 05:00:39 +04:00
return 0 ;
}
2007-04-16 08:59:47 +04:00
static int convert_in_un_remote ( struct socket_info * si , const struct sockaddr * inaddr , struct sockaddr_un * un ,
2005-11-07 18:36:51 +03:00
int * bcast )
2005-03-28 05:00:39 +04:00
{
2005-11-07 18:36:51 +03:00
char type = ' \0 ' ;
2007-04-16 08:59:47 +04:00
unsigned int prt ;
2005-11-07 18:36:51 +03:00
unsigned int iface ;
int is_bcast = 0 ;
if ( bcast ) * bcast = 0 ;
2009-06-09 07:33:09 +04:00
switch ( inaddr - > sa_family ) {
2007-04-16 08:59:47 +04:00
case AF_INET : {
const struct sockaddr_in * in =
2011-03-02 22:46:45 +03:00
( const struct sockaddr_in * ) ( const void * ) inaddr ;
2007-04-16 08:59:47 +04:00
unsigned int addr = ntohl ( in - > sin_addr . s_addr ) ;
char u_type = ' \0 ' ;
char b_type = ' \0 ' ;
char a_type = ' \0 ' ;
2005-11-07 18:36:51 +03:00
2007-04-16 08:59:47 +04:00
switch ( si - > type ) {
case SOCK_STREAM :
u_type = SOCKET_TYPE_CHAR_TCP ;
break ;
case SOCK_DGRAM :
u_type = SOCKET_TYPE_CHAR_UDP ;
a_type = SOCKET_TYPE_CHAR_UDP ;
b_type = SOCKET_TYPE_CHAR_UDP ;
break ;
2014-04-07 18:12:21 +04:00
default :
SWRAP_LOG ( SWRAP_LOG_ERROR , " Unknown socket type! \n " ) ;
errno = ESOCKTNOSUPPORT ;
return - 1 ;
2007-04-16 08:59:47 +04:00
}
prt = ntohs ( in - > sin_port ) ;
if ( a_type & & addr = = 0xFFFFFFFF ) {
/* 255.255.255.255 only udp */
is_bcast = 2 ;
type = a_type ;
iface = socket_wrapper_default_iface ( ) ;
} else if ( b_type & & addr = = 0x7FFFFFFF ) {
/* 127.255.255.255 only udp */
is_bcast = 1 ;
type = b_type ;
iface = socket_wrapper_default_iface ( ) ;
} else if ( ( addr & 0xFFFFFF00 ) = = 0x7F000000 ) {
/* 127.0.0.X */
is_bcast = 0 ;
type = u_type ;
iface = ( addr & 0x000000FF ) ;
} else {
errno = ENETUNREACH ;
return - 1 ;
}
if ( bcast ) * bcast = is_bcast ;
2005-11-07 18:36:51 +03:00
break ;
}
2007-04-16 08:59:47 +04:00
# ifdef HAVE_IPV6
case AF_INET6 : {
const struct sockaddr_in6 * in =
2011-03-02 22:46:45 +03:00
( const struct sockaddr_in6 * ) ( const void * ) inaddr ;
struct in6_addr cmp1 , cmp2 ;
2005-11-07 18:36:51 +03:00
2007-04-16 08:59:47 +04:00
switch ( si - > type ) {
case SOCK_STREAM :
type = SOCKET_TYPE_CHAR_TCP_V6 ;
break ;
case SOCK_DGRAM :
type = SOCKET_TYPE_CHAR_UDP_V6 ;
break ;
2014-04-07 18:12:21 +04:00
default :
SWRAP_LOG ( SWRAP_LOG_ERROR , " Unknown socket type! \n " ) ;
errno = ESOCKTNOSUPPORT ;
return - 1 ;
2007-04-16 08:59:47 +04:00
}
/* XXX no multicast/broadcast */
prt = ntohs ( in - > sin6_port ) ;
2009-03-03 18:45:41 +03:00
2011-03-02 22:46:45 +03:00
cmp1 = * swrap_ipv6 ( ) ;
cmp2 = in - > sin6_addr ;
cmp2 . s6_addr [ 15 ] = 0 ;
if ( IN6_ARE_ADDR_EQUAL ( & cmp1 , & cmp2 ) ) {
2009-03-03 18:45:41 +03:00
iface = in - > sin6_addr . s6_addr [ 15 ] ;
} else {
errno = ENETUNREACH ;
return - 1 ;
}
2007-04-16 08:59:47 +04:00
break ;
}
# endif
default :
2014-04-07 18:12:21 +04:00
SWRAP_LOG ( SWRAP_LOG_ERROR , " Unknown address family! \n " ) ;
2005-11-07 18:36:51 +03:00
errno = ENETUNREACH ;
return - 1 ;
}
2007-04-16 08:59:47 +04:00
if ( prt = = 0 ) {
2014-04-07 18:12:21 +04:00
SWRAP_LOG ( SWRAP_LOG_WARN , " Port not set \n " ) ;
2007-04-16 08:59:47 +04:00
errno = EINVAL ;
return - 1 ;
}
2005-11-07 18:36:51 +03:00
if ( is_bcast ) {
snprintf ( un - > sun_path , sizeof ( un - > sun_path ) , " %s/EINVAL " ,
socket_wrapper_dir ( ) ) ;
2014-04-07 18:12:21 +04:00
SWRAP_LOG ( SWRAP_LOG_DEBUG , " un path [%s] " , un - > sun_path ) ;
2005-11-07 18:36:51 +03:00
/* 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 ) ;
2014-04-07 18:12:21 +04:00
SWRAP_LOG ( SWRAP_LOG_DEBUG , " un path [%s] " , un - > sun_path ) ;
2005-11-07 18:36:51 +03:00
return 0 ;
}
2007-04-16 08:59:47 +04:00
static int convert_in_un_alloc ( struct socket_info * si , const struct sockaddr * inaddr , struct sockaddr_un * un ,
2005-11-07 18:36:51 +03:00
int * bcast )
{
char type = ' \0 ' ;
2007-04-16 08:59:47 +04:00
unsigned int prt ;
2005-11-07 18:36:51 +03:00
unsigned int iface ;
struct stat st ;
int is_bcast = 0 ;
if ( bcast ) * bcast = 0 ;
2007-04-16 08:59:47 +04:00
switch ( si - > family ) {
case AF_INET : {
const struct sockaddr_in * in =
2011-03-02 22:46:45 +03:00
( const struct sockaddr_in * ) ( const void * ) inaddr ;
2007-04-16 08:59:47 +04:00
unsigned int addr = ntohl ( in - > sin_addr . s_addr ) ;
char u_type = ' \0 ' ;
char d_type = ' \0 ' ;
char b_type = ' \0 ' ;
char a_type = ' \0 ' ;
prt = ntohs ( in - > sin_port ) ;
switch ( si - > type ) {
case SOCK_STREAM :
u_type = SOCKET_TYPE_CHAR_TCP ;
d_type = SOCKET_TYPE_CHAR_TCP ;
break ;
case SOCK_DGRAM :
u_type = SOCKET_TYPE_CHAR_UDP ;
d_type = SOCKET_TYPE_CHAR_UDP ;
a_type = SOCKET_TYPE_CHAR_UDP ;
b_type = SOCKET_TYPE_CHAR_UDP ;
break ;
2014-04-07 18:12:21 +04:00
default :
SWRAP_LOG ( SWRAP_LOG_ERROR , " Unknown socket type! \n " ) ;
errno = ESOCKTNOSUPPORT ;
return - 1 ;
2007-04-16 08:59:47 +04:00
}
if ( addr = = 0 ) {
/* 0.0.0.0 */
is_bcast = 0 ;
type = d_type ;
iface = socket_wrapper_default_iface ( ) ;
} else if ( a_type & & addr = = 0xFFFFFFFF ) {
/* 255.255.255.255 only udp */
is_bcast = 2 ;
type = a_type ;
iface = socket_wrapper_default_iface ( ) ;
} else if ( b_type & & addr = = 0x7FFFFFFF ) {
/* 127.255.255.255 only udp */
is_bcast = 1 ;
type = b_type ;
iface = socket_wrapper_default_iface ( ) ;
} else if ( ( addr & 0xFFFFFF00 ) = = 0x7F000000 ) {
/* 127.0.0.X */
is_bcast = 0 ;
type = u_type ;
iface = ( addr & 0x000000FF ) ;
} else {
errno = EADDRNOTAVAIL ;
return - 1 ;
}
2014-06-03 16:50:53 +04:00
/* Store the bind address for connect() */
if ( si - > bindname = = NULL ) {
struct sockaddr_in bind_in ;
socklen_t blen = sizeof ( struct sockaddr_in ) ;
ZERO_STRUCT ( bind_in ) ;
bind_in . sin_family = in - > sin_family ;
bind_in . sin_port = in - > sin_port ;
bind_in . sin_addr . s_addr = htonl ( 0x7F000000 | iface ) ;
si - > bindname = sockaddr_dup ( & bind_in , blen ) ;
si - > bindname_len = blen ;
}
2005-11-07 18:36:51 +03:00
break ;
}
2007-04-16 08:59:47 +04:00
# ifdef HAVE_IPV6
case AF_INET6 : {
const struct sockaddr_in6 * in =
2011-03-02 22:46:45 +03:00
( const struct sockaddr_in6 * ) ( const void * ) inaddr ;
struct in6_addr cmp1 , cmp2 ;
2005-11-07 18:36:51 +03:00
2007-04-16 08:59:47 +04:00
switch ( si - > type ) {
case SOCK_STREAM :
type = SOCKET_TYPE_CHAR_TCP_V6 ;
break ;
case SOCK_DGRAM :
type = SOCKET_TYPE_CHAR_UDP_V6 ;
break ;
2014-04-07 18:12:21 +04:00
default :
SWRAP_LOG ( SWRAP_LOG_ERROR , " Unknown socket type! \n " ) ;
errno = ESOCKTNOSUPPORT ;
return - 1 ;
2007-04-16 08:59:47 +04:00
}
/* XXX no multicast/broadcast */
prt = ntohs ( in - > sin6_port ) ;
2009-03-03 18:45:41 +03:00
2011-03-02 22:46:45 +03:00
cmp1 = * swrap_ipv6 ( ) ;
cmp2 = in - > sin6_addr ;
cmp2 . s6_addr [ 15 ] = 0 ;
2009-03-03 21:40:57 +03:00
if ( IN6_IS_ADDR_UNSPECIFIED ( & in - > sin6_addr ) ) {
iface = socket_wrapper_default_iface ( ) ;
2011-03-02 22:46:45 +03:00
} else if ( IN6_ARE_ADDR_EQUAL ( & cmp1 , & cmp2 ) ) {
2009-03-03 18:45:41 +03:00
iface = in - > sin6_addr . s6_addr [ 15 ] ;
} else {
errno = EADDRNOTAVAIL ;
return - 1 ;
}
2014-06-03 16:50:53 +04:00
/* Store the bind address for connect() */
if ( si - > bindname = = NULL ) {
struct sockaddr_in6 bind_in ;
socklen_t blen = sizeof ( struct sockaddr_in6 ) ;
ZERO_STRUCT ( bind_in ) ;
bind_in . sin6_family = in - > sin6_family ;
bind_in . sin6_port = in - > sin6_port ;
bind_in . sin6_addr = * swrap_ipv6 ( ) ;
bind_in . sin6_addr . s6_addr [ 15 ] = iface ;
si - > bindname = sockaddr_dup ( & bind_in , blen ) ;
si - > bindname_len = blen ;
}
2007-04-16 08:59:47 +04:00
break ;
}
# endif
default :
2014-04-07 18:12:21 +04:00
SWRAP_LOG ( SWRAP_LOG_ERROR , " Unknown address family \n " ) ;
2009-03-03 18:45:41 +03:00
errno = EADDRNOTAVAIL ;
2005-11-07 18:36:51 +03:00
return - 1 ;
}
2007-04-16 08:59:47 +04:00
2005-11-07 18:36:51 +03:00
if ( bcast ) * bcast = is_bcast ;
2011-07-10 18:40:37 +04:00
if ( iface = = 0 | | iface > MAX_WRAPPED_INTERFACES ) {
errno = EINVAL ;
return - 1 ;
}
2005-06-10 16:21:46 +04:00
if ( prt = = 0 ) {
/* handle auto-allocation of ephemeral ports */
2005-11-07 18:36:51 +03:00
for ( prt = 5001 ; prt < 10000 ; prt + + ) {
2005-07-21 12:42:17 +04:00
snprintf ( un - > sun_path , sizeof ( un - > sun_path ) , " %s/ " SOCKET_FORMAT ,
2005-11-07 18:36:51 +03:00
socket_wrapper_dir ( ) , type , iface , prt ) ;
if ( stat ( un - > sun_path , & st ) = = 0 ) continue ;
2007-04-16 08:59:47 +04:00
set_port ( si - > family , prt , si - > myname ) ;
2014-06-03 16:50:53 +04:00
set_port ( si - > family , prt , si - > bindname ) ;
2007-04-16 08:59:47 +04:00
break ;
}
if ( prt = = 10000 ) {
errno = ENFILE ;
return - 1 ;
2005-11-07 18:36:51 +03:00
}
}
2005-07-21 12:42:17 +04:00
snprintf ( un - > sun_path , sizeof ( un - > sun_path ) , " %s/ " SOCKET_FORMAT ,
2005-11-07 18:36:51 +03:00
socket_wrapper_dir ( ) , type , iface , prt ) ;
2014-04-07 18:12:21 +04:00
SWRAP_LOG ( SWRAP_LOG_DEBUG , " un path [%s] " , un - > sun_path ) ;
2005-03-28 05:00:39 +04:00
return 0 ;
}
static struct socket_info * find_socket_info ( int fd )
{
struct socket_info * i ;
2014-04-07 18:12:21 +04:00
2005-03-28 05:00:39 +04:00
for ( i = sockets ; i ; i = i - > next ) {
2011-09-29 01:09:49 +04:00
struct socket_info_fd * f ;
for ( f = i - > fds ; f ; f = f - > next ) {
if ( f - > fd = = fd ) {
return i ;
}
}
2005-03-28 05:00:39 +04:00
}
return NULL ;
}
2014-04-07 18:12:21 +04:00
static void swrap_remove_stale ( int fd )
{
struct socket_info * si = find_socket_info ( fd ) ;
struct socket_info_fd * fi ;
if ( si ! = NULL ) {
for ( fi = si - > fds ; fi ; fi = fi - > next ) {
if ( fi - > fd = = fd ) {
SWRAP_LOG ( SWRAP_LOG_TRACE , " remove stale wrapper for %d " , fd ) ;
SWRAP_DLIST_REMOVE ( si - > fds , fi ) ;
free ( fi ) ;
break ;
}
}
if ( si - > fds = = NULL ) {
SWRAP_DLIST_REMOVE ( sockets , si ) ;
}
}
}
static int sockaddr_convert_to_un ( struct socket_info * si ,
const struct sockaddr * in_addr ,
socklen_t in_len ,
struct sockaddr_un * out_addr ,
int alloc_sock ,
int * bcast )
2005-03-28 05:00:39 +04:00
{
2010-11-05 11:43:05 +03:00
struct sockaddr * out = ( struct sockaddr * ) ( void * ) out_addr ;
2014-04-07 18:12:21 +04:00
( void ) in_len ; /* unused */
if ( out_addr = = NULL ) {
2005-03-28 05:00:39 +04:00
return 0 ;
2014-04-07 18:12:21 +04:00
}
2005-03-28 05:00:39 +04:00
2010-11-05 11:43:05 +03:00
out - > sa_family = AF_UNIX ;
# ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
out - > sa_len = sizeof ( * out_addr ) ;
# endif
2005-03-31 03:28:15 +04:00
2005-03-28 05:00:39 +04:00
switch ( in_addr - > sa_family ) {
case AF_INET :
2007-04-16 08:59:47 +04:00
# ifdef HAVE_IPV6
case AF_INET6 :
# endif
2005-11-07 18:36:51 +03:00
switch ( si - > type ) {
case SOCK_STREAM :
case SOCK_DGRAM :
break ;
default :
2014-04-07 18:12:21 +04:00
SWRAP_LOG ( SWRAP_LOG_ERROR , " Unknown socket type! \n " ) ;
2005-11-07 18:36:51 +03:00
errno = ESOCKTNOSUPPORT ;
return - 1 ;
}
if ( alloc_sock ) {
2007-04-16 08:59:47 +04:00
return convert_in_un_alloc ( si , in_addr , out_addr , bcast ) ;
2005-11-07 18:36:51 +03:00
} else {
2007-04-16 08:59:47 +04:00
return convert_in_un_remote ( si , in_addr , out_addr , bcast ) ;
2005-11-07 18:36:51 +03:00
}
2005-03-28 05:00:39 +04:00
default :
break ;
}
2011-02-12 14:18:16 +03:00
2005-03-28 05:00:39 +04:00
errno = EAFNOSUPPORT ;
2014-04-07 18:12:21 +04:00
SWRAP_LOG ( SWRAP_LOG_ERROR , " Unknown address family \n " ) ;
2005-03-28 05:00:39 +04:00
return - 1 ;
}
2005-03-31 03:28:15 +04:00
static int sockaddr_convert_from_un ( const struct socket_info * si ,
2005-03-31 16:40:12 +04:00
const struct sockaddr_un * in_addr ,
socklen_t un_addrlen ,
int family ,
struct sockaddr * out_addr ,
2007-04-16 08:59:47 +04:00
socklen_t * out_addrlen )
2005-03-28 05:00:39 +04:00
{
2010-11-05 11:43:05 +03:00
int ret ;
2007-04-16 08:59:47 +04:00
if ( out_addr = = NULL | | out_addrlen = = NULL )
2005-03-28 05:00:39 +04:00
return 0 ;
2005-03-31 16:40:12 +04:00
if ( un_addrlen = = 0 ) {
2007-04-16 08:59:47 +04:00
* out_addrlen = 0 ;
2005-03-31 16:40:12 +04:00
return 0 ;
}
2005-03-28 05:00:39 +04:00
switch ( family ) {
case AF_INET :
2007-04-16 08:59:47 +04:00
# ifdef HAVE_IPV6
case AF_INET6 :
# endif
2005-11-07 18:36:51 +03:00
switch ( si - > type ) {
case SOCK_STREAM :
case SOCK_DGRAM :
break ;
default :
2014-04-07 18:12:21 +04:00
SWRAP_LOG ( SWRAP_LOG_ERROR , " Unknown socket type! \n " ) ;
2005-11-07 18:36:51 +03:00
errno = ESOCKTNOSUPPORT ;
return - 1 ;
}
2010-11-05 11:43:05 +03:00
ret = convert_un_in ( in_addr , out_addr , out_addrlen ) ;
# ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
out_addr - > sa_len = * out_addrlen ;
# endif
return ret ;
2005-03-28 05:00:39 +04:00
default :
break ;
}
2014-04-07 18:12:21 +04:00
SWRAP_LOG ( SWRAP_LOG_ERROR , " Unknown address family \n " ) ;
2005-03-28 05:00:39 +04:00
errno = EAFNOSUPPORT ;
return - 1 ;
}
2006-09-12 10:19:11 +04:00
enum swrap_packet_type {
2006-09-29 13:31:20 +04:00
SWRAP_CONNECT_SEND ,
SWRAP_CONNECT_UNREACH ,
SWRAP_CONNECT_RECV ,
SWRAP_CONNECT_ACK ,
SWRAP_ACCEPT_SEND ,
SWRAP_ACCEPT_RECV ,
SWRAP_ACCEPT_ACK ,
2006-09-12 10:19:11 +04:00
SWRAP_RECVFROM ,
SWRAP_SENDTO ,
2006-09-29 13:31:20 +04:00
SWRAP_SENDTO_UNREACH ,
SWRAP_PENDING_RST ,
2006-09-12 10:19:11 +04:00
SWRAP_RECV ,
2006-09-29 13:31:20 +04:00
SWRAP_RECV_RST ,
2006-09-12 13:08:55 +04:00
SWRAP_SEND ,
2006-09-29 13:31:20 +04:00
SWRAP_SEND_RST ,
SWRAP_CLOSE_SEND ,
SWRAP_CLOSE_RECV ,
2009-09-08 07:31:01 +04:00
SWRAP_CLOSE_ACK ,
2006-09-12 10:19:11 +04:00
} ;
2006-10-05 15:39:59 +04:00
struct swrap_file_hdr {
2008-03-17 16:08:57 +03:00
uint32_t magic ;
uint16_t version_major ;
uint16_t version_minor ;
int32_t timezone ;
uint32_t sigfigs ;
uint32_t frame_max_len ;
2006-10-05 15:39:59 +04:00
# define SWRAP_FRAME_LENGTH_MAX 0xFFFF
2008-03-17 16:08:57 +03:00
uint32_t link_type ;
2006-10-05 15:39:59 +04:00
} ;
# define SWRAP_FILE_HDR_SIZE 24
2009-03-03 16:58:53 +03:00
struct swrap_packet_frame {
uint32_t seconds ;
uint32_t micro_seconds ;
uint32_t recorded_length ;
uint32_t full_length ;
} ;
# define SWRAP_PACKET_FRAME_SIZE 16
union swrap_packet_ip {
2006-10-05 15:39:59 +04:00
struct {
2009-03-03 16:58:53 +03:00
uint8_t ver_hdrlen ;
uint8_t tos ;
uint16_t packet_length ;
uint16_t identification ;
uint8_t flags ;
uint8_t fragment ;
uint8_t ttl ;
uint8_t protocol ;
uint16_t hdr_checksum ;
uint32_t src_addr ;
uint32_t dest_addr ;
} v4 ;
# define SWRAP_PACKET_IP_V4_SIZE 20
2009-03-03 17:43:22 +03:00
struct {
uint8_t ver_prio ;
uint8_t flow_label_high ;
uint16_t flow_label_low ;
uint16_t payload_length ;
uint8_t next_header ;
uint8_t hop_limit ;
uint8_t src_addr [ 16 ] ;
uint8_t dest_addr [ 16 ] ;
} v6 ;
# define SWRAP_PACKET_IP_V6_SIZE 40
2009-03-03 16:58:53 +03:00
} ;
2009-03-03 17:43:22 +03:00
# define SWRAP_PACKET_IP_SIZE 40
2006-10-05 15:39:59 +04:00
2009-03-03 16:58:53 +03:00
union swrap_packet_payload {
2006-10-05 15:39:59 +04:00
struct {
2009-03-03 16:58:53 +03:00
uint16_t source_port ;
uint16_t dest_port ;
uint32_t seq_num ;
uint32_t ack_num ;
uint8_t hdr_length ;
uint8_t control ;
uint16_t window ;
uint16_t checksum ;
uint16_t urg ;
} tcp ;
# define SWRAP_PACKET_PAYLOAD_TCP_SIZE 20
struct {
uint16_t source_port ;
uint16_t dest_port ;
uint16_t length ;
uint16_t checksum ;
} udp ;
# define SWRAP_PACKET_PAYLOAD_UDP_SIZE 8
struct {
uint8_t type ;
uint8_t code ;
uint16_t checksum ;
uint32_t unused ;
} icmp4 ;
# define SWRAP_PACKET_PAYLOAD_ICMP4_SIZE 8
2009-03-03 17:43:22 +03:00
struct {
uint8_t type ;
uint8_t code ;
uint16_t checksum ;
uint32_t unused ;
} icmp6 ;
# define SWRAP_PACKET_PAYLOAD_ICMP6_SIZE 8
2006-10-05 15:39:59 +04:00
} ;
2009-03-03 16:58:53 +03:00
# define SWRAP_PACKET_PAYLOAD_SIZE 20
# define SWRAP_PACKET_MIN_ALLOC \
( SWRAP_PACKET_FRAME_SIZE + \
SWRAP_PACKET_IP_SIZE + \
SWRAP_PACKET_PAYLOAD_SIZE )
2006-10-05 15:39:59 +04:00
static const char * socket_wrapper_pcap_file ( void )
{
static int initialized = 0 ;
static const char * s = NULL ;
2009-03-03 16:58:53 +03:00
static const struct swrap_file_hdr h ;
static const struct swrap_packet_frame f ;
static const union swrap_packet_ip i ;
static const union swrap_packet_payload p ;
2006-10-05 15:39:59 +04:00
if ( initialized = = 1 ) {
return s ;
}
initialized = 1 ;
/*
* TODO : don ' t use the structs use plain buffer offsets
* and PUSH_U8 ( ) , PUSH_U16 ( ) and PUSH_U32 ( )
*
* for now make sure we disable PCAP support
* if the struct has alignment !
*/
if ( sizeof ( h ) ! = SWRAP_FILE_HDR_SIZE ) {
return NULL ;
}
2009-03-03 16:58:53 +03:00
if ( sizeof ( f ) ! = SWRAP_PACKET_FRAME_SIZE ) {
2006-10-05 15:39:59 +04:00
return NULL ;
}
2009-03-03 16:58:53 +03:00
if ( sizeof ( i ) ! = SWRAP_PACKET_IP_SIZE ) {
2006-10-05 15:39:59 +04:00
return NULL ;
}
2009-03-03 16:58:53 +03:00
if ( sizeof ( i . v4 ) ! = SWRAP_PACKET_IP_V4_SIZE ) {
2006-10-05 15:39:59 +04:00
return NULL ;
}
2009-03-03 17:43:22 +03:00
if ( sizeof ( i . v6 ) ! = SWRAP_PACKET_IP_V6_SIZE ) {
return NULL ;
}
2009-03-03 16:58:53 +03:00
if ( sizeof ( p ) ! = SWRAP_PACKET_PAYLOAD_SIZE ) {
2006-10-05 15:39:59 +04:00
return NULL ;
}
2009-03-03 16:58:53 +03:00
if ( sizeof ( p . tcp ) ! = SWRAP_PACKET_PAYLOAD_TCP_SIZE ) {
2006-10-05 15:39:59 +04:00
return NULL ;
}
2009-03-03 16:58:53 +03:00
if ( sizeof ( p . udp ) ! = SWRAP_PACKET_PAYLOAD_UDP_SIZE ) {
return NULL ;
}
if ( sizeof ( p . icmp4 ) ! = SWRAP_PACKET_PAYLOAD_ICMP4_SIZE ) {
2006-10-05 15:39:59 +04:00
return NULL ;
}
2009-03-03 17:43:22 +03:00
if ( sizeof ( p . icmp6 ) ! = SWRAP_PACKET_PAYLOAD_ICMP6_SIZE ) {
return NULL ;
}
2006-10-05 15:39:59 +04:00
s = getenv ( " SOCKET_WRAPPER_PCAP_FILE " ) ;
if ( s = = NULL ) {
return NULL ;
}
if ( strncmp ( s , " ./ " , 2 ) = = 0 ) {
s + = 2 ;
}
return s ;
}
2009-03-03 16:58:53 +03:00
static uint8_t * swrap_packet_init ( struct timeval * tval ,
2009-03-03 17:17:26 +03:00
const struct sockaddr * src ,
const struct sockaddr * dest ,
2009-03-03 16:58:53 +03:00
int socket_type ,
2009-03-03 17:17:26 +03:00
const uint8_t * payload ,
2009-03-03 16:58:53 +03:00
size_t payload_len ,
unsigned long tcp_seqno ,
unsigned long tcp_ack ,
unsigned char tcp_ctl ,
int unreachable ,
size_t * _packet_len )
2006-10-05 15:39:59 +04:00
{
2009-03-03 16:58:53 +03:00
uint8_t * base ;
uint8_t * buf ;
struct swrap_packet_frame * frame ;
union swrap_packet_ip * ip ;
union swrap_packet_payload * pay ;
2006-10-05 15:39:59 +04:00
size_t packet_len ;
size_t alloc_len ;
2009-03-03 16:58:53 +03:00
size_t nonwire_len = sizeof ( * frame ) ;
2006-10-06 19:16:18 +04:00
size_t wire_hdr_len = 0 ;
size_t wire_len = 0 ;
2009-03-03 17:17:26 +03:00
size_t ip_hdr_len = 0 ;
2006-10-05 15:39:59 +04:00
size_t icmp_hdr_len = 0 ;
size_t icmp_truncate_len = 0 ;
2009-03-03 16:58:53 +03:00
uint8_t protocol = 0 , icmp_protocol = 0 ;
2009-03-04 23:59:16 +03:00
const struct sockaddr_in * src_in = NULL ;
const struct sockaddr_in * dest_in = NULL ;
2009-03-03 17:43:22 +03:00
# ifdef HAVE_IPV6
2009-03-04 23:59:16 +03:00
const struct sockaddr_in6 * src_in6 = NULL ;
const struct sockaddr_in6 * dest_in6 = NULL ;
2009-03-03 17:43:22 +03:00
# endif
2009-03-03 17:17:26 +03:00
uint16_t src_port ;
uint16_t dest_port ;
switch ( src - > sa_family ) {
case AF_INET :
src_in = ( const struct sockaddr_in * ) src ;
dest_in = ( const struct sockaddr_in * ) dest ;
src_port = src_in - > sin_port ;
dest_port = dest_in - > sin_port ;
ip_hdr_len = sizeof ( ip - > v4 ) ;
break ;
2009-03-03 17:43:22 +03:00
# ifdef HAVE_IPV6
case AF_INET6 :
src_in6 = ( const struct sockaddr_in6 * ) src ;
dest_in6 = ( const struct sockaddr_in6 * ) dest ;
src_port = src_in6 - > sin6_port ;
dest_port = dest_in6 - > sin6_port ;
ip_hdr_len = sizeof ( ip - > v6 ) ;
break ;
# endif
2009-03-03 17:17:26 +03:00
default :
return NULL ;
}
2006-10-05 15:39:59 +04:00
switch ( socket_type ) {
case SOCK_STREAM :
protocol = 0x06 ; /* TCP */
2009-03-03 16:58:53 +03:00
wire_hdr_len = ip_hdr_len + sizeof ( pay - > tcp ) ;
2006-10-05 15:39:59 +04:00
wire_len = wire_hdr_len + payload_len ;
break ;
case SOCK_DGRAM :
protocol = 0x11 ; /* UDP */
2009-03-03 16:58:53 +03:00
wire_hdr_len = ip_hdr_len + sizeof ( pay - > udp ) ;
2006-10-05 15:39:59 +04:00
wire_len = wire_hdr_len + payload_len ;
break ;
2007-06-11 18:41:14 +04:00
default :
return NULL ;
2006-10-05 15:39:59 +04:00
}
if ( unreachable ) {
icmp_protocol = protocol ;
2009-03-03 17:43:22 +03:00
switch ( src - > sa_family ) {
case AF_INET :
protocol = 0x01 ; /* ICMPv4 */
icmp_hdr_len = ip_hdr_len + sizeof ( pay - > icmp4 ) ;
break ;
# ifdef HAVE_IPV6
case AF_INET6 :
protocol = 0x3A ; /* ICMPv6 */
icmp_hdr_len = ip_hdr_len + sizeof ( pay - > icmp6 ) ;
break ;
# endif
}
2006-10-05 15:39:59 +04:00
if ( wire_len > 64 ) {
icmp_truncate_len = wire_len - 64 ;
}
wire_hdr_len + = icmp_hdr_len ;
wire_len + = icmp_hdr_len ;
}
packet_len = nonwire_len + wire_len ;
alloc_len = packet_len ;
2009-03-03 16:58:53 +03:00
if ( alloc_len < SWRAP_PACKET_MIN_ALLOC ) {
alloc_len = SWRAP_PACKET_MIN_ALLOC ;
2006-10-05 15:39:59 +04:00
}
2009-03-03 16:58:53 +03:00
base = ( uint8_t * ) malloc ( alloc_len ) ;
2014-04-07 18:12:21 +04:00
if ( base = = NULL ) {
return NULL ;
}
memset ( base , 0x0 , alloc_len ) ;
2009-03-03 16:58:53 +03:00
buf = base ;
frame = ( struct swrap_packet_frame * ) 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 * ) buf ;
2009-03-03 17:17:26 +03:00
switch ( src - > sa_family ) {
case AF_INET :
2009-03-03 16:58:53 +03:00
ip - > v4 . ver_hdrlen = 0x45 ; /* version 4 and 5 * 32 bit words */
ip - > v4 . tos = 0x00 ;
2009-03-03 17:17:26 +03:00
ip - > v4 . packet_length = htons ( wire_len - icmp_truncate_len ) ;
2009-03-03 16:58:53 +03:00
ip - > v4 . identification = htons ( 0xFFFF ) ;
2014-05-08 17:30:09 +04:00
ip - > v4 . flags = 0x40 ; /* BIT 1 set - means don't fragment */
2009-03-03 16:58:53 +03:00
ip - > v4 . fragment = htons ( 0x0000 ) ;
ip - > v4 . ttl = 0xFF ;
2009-03-03 17:17:26 +03:00
ip - > v4 . protocol = protocol ;
2009-03-03 16:58:53 +03:00
ip - > v4 . hdr_checksum = htons ( 0x0000 ) ;
2009-03-03 17:17:26 +03:00
ip - > v4 . src_addr = src_in - > sin_addr . s_addr ;
ip - > v4 . dest_addr = dest_in - > sin_addr . s_addr ;
2009-03-03 16:58:53 +03:00
buf + = SWRAP_PACKET_IP_V4_SIZE ;
2009-03-03 17:17:26 +03:00
break ;
2009-03-03 17:43:22 +03:00
# 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 ;
2011-02-10 16:20:34 +03:00
ip - > v6 . payload_length = htons ( wire_len - icmp_truncate_len ) ; /* TODO */
2009-03-03 17:43:22 +03:00
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 ) ;
buf + = SWRAP_PACKET_IP_V6_SIZE ;
break ;
# endif
2009-03-03 17:17:26 +03:00
}
2006-10-05 15:39:59 +04:00
2009-03-03 17:17:26 +03:00
if ( unreachable ) {
pay = ( union swrap_packet_payload * ) buf ;
switch ( src - > sa_family ) {
case AF_INET :
pay - > icmp4 . type = 0x03 ; /* destination unreachable */
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 * ) 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 ) ;
2014-05-08 17:30:09 +04:00
ip - > v4 . flags = 0x40 ; /* BIT 1 set - means don't fragment */
2009-03-03 17:17:26 +03:00
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 ;
buf + = SWRAP_PACKET_IP_V4_SIZE ;
src_port = dest_in - > sin_port ;
dest_port = src_in - > sin_port ;
break ;
2009-03-03 17:43:22 +03:00
# ifdef HAVE_IPV6
case AF_INET6 :
pay - > icmp6 . type = 0x01 ; /* destination unreachable */
pay - > icmp6 . code = 0x03 ; /* address unreachable */
pay - > icmp6 . checksum = htons ( 0x0000 ) ;
pay - > icmp6 . unused = htonl ( 0x00000000 ) ;
buf + = SWRAP_PACKET_PAYLOAD_ICMP6_SIZE ;
/* set the ip header in the ICMP payload */
ip = ( union swrap_packet_ip * ) 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 ;
2011-02-10 16:20:34 +03:00
ip - > v6 . payload_length = htons ( wire_len - icmp_truncate_len ) ; /* TODO */
2009-03-03 17:43:22 +03:00
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 ) ;
buf + = SWRAP_PACKET_IP_V6_SIZE ;
src_port = dest_in6 - > sin6_port ;
dest_port = src_in6 - > sin6_port ;
break ;
# endif
2009-03-03 17:17:26 +03:00
}
2006-10-05 15:39:59 +04:00
}
2009-03-03 16:58:53 +03:00
pay = ( union swrap_packet_payload * ) buf ;
2006-10-05 15:39:59 +04:00
switch ( socket_type ) {
case SOCK_STREAM :
2009-03-03 16:58:53 +03:00
pay - > tcp . source_port = src_port ;
pay - > tcp . dest_port = dest_port ;
pay - > tcp . seq_num = htonl ( tcp_seqno ) ;
pay - > tcp . ack_num = htonl ( tcp_ack ) ;
pay - > tcp . hdr_length = 0x50 ; /* 5 * 32 bit words */
pay - > tcp . control = tcp_ctl ;
pay - > tcp . window = htons ( 0x7FFF ) ;
pay - > tcp . checksum = htons ( 0x0000 ) ;
pay - > tcp . urg = htons ( 0x0000 ) ;
buf + = SWRAP_PACKET_PAYLOAD_TCP_SIZE ;
2006-10-05 15:39:59 +04:00
break ;
case SOCK_DGRAM :
2009-03-03 17:17:26 +03:00
pay - > udp . source_port = src_port ;
pay - > udp . dest_port = dest_port ;
2009-03-03 16:58:53 +03:00
pay - > udp . length = htons ( 8 + payload_len ) ;
pay - > udp . checksum = htons ( 0x0000 ) ;
buf + = SWRAP_PACKET_PAYLOAD_UDP_SIZE ;
2006-10-05 15:39:59 +04:00
break ;
}
if ( payload & & payload_len > 0 ) {
2009-03-03 16:58:53 +03:00
memcpy ( buf , payload , payload_len ) ;
2006-10-05 15:39:59 +04:00
}
* _packet_len = packet_len - icmp_truncate_len ;
2009-03-03 16:58:53 +03:00
return base ;
2006-10-05 15:39:59 +04:00
}
static int swrap_get_pcap_fd ( const char * fname )
{
static int fd = - 1 ;
if ( fd ! = - 1 ) return fd ;
2014-05-08 16:05:30 +04:00
fd = libc_open ( fname , O_WRONLY | O_CREAT | O_EXCL | O_APPEND , 0644 ) ;
2006-10-05 15:39:59 +04:00
if ( fd ! = - 1 ) {
struct swrap_file_hdr file_hdr ;
file_hdr . magic = 0xA1B2C3D4 ;
file_hdr . version_major = 0x0002 ;
file_hdr . version_minor = 0x0004 ;
file_hdr . timezone = 0x00000000 ;
file_hdr . sigfigs = 0x00000000 ;
file_hdr . frame_max_len = SWRAP_FRAME_LENGTH_MAX ;
file_hdr . link_type = 0x0065 ; /* 101 RAW IP */
2008-12-23 07:08:14 +03:00
if ( write ( fd , & file_hdr , sizeof ( file_hdr ) ) ! = sizeof ( file_hdr ) ) {
close ( fd ) ;
2009-01-20 02:37:57 +03:00
fd = - 1 ;
2008-12-23 07:08:14 +03:00
}
2006-10-05 15:39:59 +04:00
return fd ;
}
2014-05-08 16:05:30 +04:00
fd = libc_open ( fname , O_WRONLY | O_APPEND , 0644 ) ;
2006-10-05 15:39:59 +04:00
return fd ;
}
2009-03-03 16:58:53 +03:00
static uint8_t * swrap_marshall_packet ( struct socket_info * si ,
const struct sockaddr * addr ,
enum swrap_packet_type type ,
const void * buf , size_t len ,
size_t * packet_len )
2006-09-12 10:19:11 +04:00
{
2009-03-03 17:17:26 +03:00
const struct sockaddr * src_addr ;
const struct sockaddr * dest_addr ;
2008-10-07 21:56:30 +04:00
unsigned long tcp_seqno = 0 ;
2006-10-05 11:03:41 +04:00
unsigned long tcp_ack = 0 ;
unsigned char tcp_ctl = 0 ;
2006-10-05 10:27:41 +04:00
int unreachable = 0 ;
2006-09-29 13:31:20 +04:00
2008-02-20 01:53:04 +03:00
struct timeval tv ;
2006-09-12 10:19:11 +04:00
2007-04-16 08:59:47 +04:00
switch ( si - > family ) {
case AF_INET :
break ;
2009-04-14 14:45:48 +04:00
# ifdef HAVE_IPV6
2009-03-03 17:43:22 +03:00
case AF_INET6 :
break ;
2009-04-14 14:45:48 +04:00
# endif
2007-04-16 08:59:47 +04:00
default :
2008-02-20 01:53:04 +03:00
return NULL ;
2006-09-29 13:31:20 +04:00
}
2006-10-05 10:27:41 +04:00
switch ( type ) {
case SWRAP_CONNECT_SEND :
2008-02-20 01:53:04 +03:00
if ( si - > type ! = SOCK_STREAM ) return NULL ;
2006-10-05 10:27:41 +04:00
2009-03-03 17:17:26 +03:00
src_addr = si - > myname ;
dest_addr = addr ;
2006-10-05 10:27:41 +04:00
2008-10-07 21:56:30 +04:00
tcp_seqno = si - > io . pck_snd ;
2006-10-05 10:27:41 +04:00
tcp_ack = si - > io . pck_rcv ;
tcp_ctl = 0x02 ; /* SYN */
si - > io . pck_snd + = 1 ;
break ;
case SWRAP_CONNECT_RECV :
2008-02-20 01:53:04 +03:00
if ( si - > type ! = SOCK_STREAM ) return NULL ;
2006-10-05 10:27:41 +04:00
2009-03-03 17:17:26 +03:00
dest_addr = si - > myname ;
src_addr = addr ;
2006-10-05 10:27:41 +04:00
2008-10-07 21:56:30 +04:00
tcp_seqno = si - > io . pck_rcv ;
2006-10-05 10:27:41 +04:00
tcp_ack = si - > io . pck_snd ;
tcp_ctl = 0x12 ; /** SYN,ACK */
si - > io . pck_rcv + = 1 ;
break ;
case SWRAP_CONNECT_UNREACH :
2008-02-20 01:53:04 +03:00
if ( si - > type ! = SOCK_STREAM ) return NULL ;
2006-10-05 10:27:41 +04:00
2009-03-03 17:17:26 +03:00
dest_addr = si - > myname ;
src_addr = addr ;
2006-10-05 10:27:41 +04:00
/* Unreachable: resend the data of SWRAP_CONNECT_SEND */
2008-10-07 21:56:30 +04:00
tcp_seqno = si - > io . pck_snd - 1 ;
2006-10-05 10:27:41 +04:00
tcp_ack = si - > io . pck_rcv ;
tcp_ctl = 0x02 ; /* SYN */
unreachable = 1 ;
break ;
case SWRAP_CONNECT_ACK :
2008-02-20 01:53:04 +03:00
if ( si - > type ! = SOCK_STREAM ) return NULL ;
2006-10-05 10:27:41 +04:00
2009-03-03 17:17:26 +03:00
src_addr = si - > myname ;
dest_addr = addr ;
2006-10-05 10:27:41 +04:00
2008-10-07 21:56:30 +04:00
tcp_seqno = si - > io . pck_snd ;
2006-10-05 10:27:41 +04:00
tcp_ack = si - > io . pck_rcv ;
tcp_ctl = 0x10 ; /* ACK */
break ;
case SWRAP_ACCEPT_SEND :
2008-02-20 01:53:04 +03:00
if ( si - > type ! = SOCK_STREAM ) return NULL ;
2006-10-05 10:27:41 +04:00
2009-03-03 17:17:26 +03:00
dest_addr = si - > myname ;
src_addr = addr ;
2006-10-05 10:27:41 +04:00
2008-10-07 21:56:30 +04:00
tcp_seqno = si - > io . pck_rcv ;
2006-10-05 10:27:41 +04:00
tcp_ack = si - > io . pck_snd ;
tcp_ctl = 0x02 ; /* SYN */
si - > io . pck_rcv + = 1 ;
break ;
case SWRAP_ACCEPT_RECV :
2008-02-20 01:53:04 +03:00
if ( si - > type ! = SOCK_STREAM ) return NULL ;
2006-10-05 10:27:41 +04:00
2009-03-03 17:17:26 +03:00
src_addr = si - > myname ;
dest_addr = addr ;
2006-10-05 10:27:41 +04:00
2008-10-07 21:56:30 +04:00
tcp_seqno = si - > io . pck_snd ;
2006-10-05 10:27:41 +04:00
tcp_ack = si - > io . pck_rcv ;
tcp_ctl = 0x12 ; /* SYN,ACK */
si - > io . pck_snd + = 1 ;
break ;
case SWRAP_ACCEPT_ACK :
2008-02-20 01:53:04 +03:00
if ( si - > type ! = SOCK_STREAM ) return NULL ;
2006-10-05 10:27:41 +04:00
2009-03-03 17:17:26 +03:00
dest_addr = si - > myname ;
src_addr = addr ;
2006-10-05 10:27:41 +04:00
2008-10-07 21:56:30 +04:00
tcp_seqno = si - > io . pck_rcv ;
2006-10-05 10:27:41 +04:00
tcp_ack = si - > io . pck_snd ;
tcp_ctl = 0x10 ; /* ACK */
break ;
case SWRAP_SEND :
2009-03-03 17:17:26 +03:00
src_addr = si - > myname ;
dest_addr = si - > peername ;
2006-10-05 10:27:41 +04:00
2008-10-07 21:56:30 +04:00
tcp_seqno = si - > io . pck_snd ;
2006-10-05 10:27:41 +04:00
tcp_ack = si - > io . pck_rcv ;
tcp_ctl = 0x18 ; /* PSH,ACK */
si - > io . pck_snd + = len ;
break ;
case SWRAP_SEND_RST :
2009-03-03 17:17:26 +03:00
dest_addr = si - > myname ;
src_addr = si - > peername ;
2006-10-05 10:27:41 +04:00
if ( si - > type = = SOCK_DGRAM ) {
2008-02-20 01:53:04 +03:00
return swrap_marshall_packet ( si , si - > peername ,
2006-10-05 10:27:41 +04:00
SWRAP_SENDTO_UNREACH ,
2008-02-20 01:53:04 +03:00
buf , len , packet_len ) ;
2006-10-05 10:27:41 +04:00
}
2008-10-07 21:56:30 +04:00
tcp_seqno = si - > io . pck_rcv ;
2006-10-05 10:27:41 +04:00
tcp_ack = si - > io . pck_snd ;
tcp_ctl = 0x14 ; /** RST,ACK */
break ;
case SWRAP_PENDING_RST :
2009-03-03 17:17:26 +03:00
dest_addr = si - > myname ;
src_addr = si - > peername ;
2006-10-05 10:27:41 +04:00
if ( si - > type = = SOCK_DGRAM ) {
2008-02-20 01:53:04 +03:00
return NULL ;
2006-10-05 10:27:41 +04:00
}
2008-10-07 21:56:30 +04:00
tcp_seqno = si - > io . pck_rcv ;
2006-10-05 10:27:41 +04:00
tcp_ack = si - > io . pck_snd ;
tcp_ctl = 0x14 ; /* RST,ACK */
break ;
case SWRAP_RECV :
2009-03-03 17:17:26 +03:00
dest_addr = si - > myname ;
src_addr = si - > peername ;
2006-10-05 10:27:41 +04:00
2008-10-07 21:56:30 +04:00
tcp_seqno = si - > io . pck_rcv ;
2006-10-05 10:27:41 +04:00
tcp_ack = si - > io . pck_snd ;
tcp_ctl = 0x18 ; /* PSH,ACK */
si - > io . pck_rcv + = len ;
break ;
case SWRAP_RECV_RST :
2009-03-03 17:17:26 +03:00
dest_addr = si - > myname ;
src_addr = si - > peername ;
2006-10-05 10:27:41 +04:00
if ( si - > type = = SOCK_DGRAM ) {
2008-02-20 01:53:04 +03:00
return NULL ;
2006-10-05 10:27:41 +04:00
}
2008-10-07 21:56:30 +04:00
tcp_seqno = si - > io . pck_rcv ;
2006-10-05 10:27:41 +04:00
tcp_ack = si - > io . pck_snd ;
tcp_ctl = 0x14 ; /* RST,ACK */
break ;
case SWRAP_SENDTO :
2009-03-03 17:17:26 +03:00
src_addr = si - > myname ;
dest_addr = addr ;
2006-10-05 10:27:41 +04:00
si - > io . pck_snd + = len ;
break ;
case SWRAP_SENDTO_UNREACH :
2009-03-03 17:17:26 +03:00
dest_addr = si - > myname ;
src_addr = addr ;
2006-10-05 10:27:41 +04:00
unreachable = 1 ;
break ;
case SWRAP_RECVFROM :
2009-03-03 17:17:26 +03:00
dest_addr = si - > myname ;
src_addr = addr ;
2006-10-05 10:27:41 +04:00
si - > io . pck_rcv + = len ;
break ;
case SWRAP_CLOSE_SEND :
2008-02-20 01:53:04 +03:00
if ( si - > type ! = SOCK_STREAM ) return NULL ;
2006-10-05 10:27:41 +04:00
2009-03-03 17:17:26 +03:00
src_addr = si - > myname ;
dest_addr = si - > peername ;
2006-10-05 10:27:41 +04:00
2008-10-07 21:56:30 +04:00
tcp_seqno = si - > io . pck_snd ;
2006-10-05 10:27:41 +04:00
tcp_ack = si - > io . pck_rcv ;
tcp_ctl = 0x11 ; /* FIN, ACK */
si - > io . pck_snd + = 1 ;
break ;
case SWRAP_CLOSE_RECV :
2008-02-20 01:53:04 +03:00
if ( si - > type ! = SOCK_STREAM ) return NULL ;
2006-10-05 10:27:41 +04:00
2009-03-03 17:17:26 +03:00
dest_addr = si - > myname ;
src_addr = si - > peername ;
2006-10-05 10:27:41 +04:00
2008-10-07 21:56:30 +04:00
tcp_seqno = si - > io . pck_rcv ;
2006-10-05 10:27:41 +04:00
tcp_ack = si - > io . pck_snd ;
tcp_ctl = 0x11 ; /* FIN,ACK */
si - > io . pck_rcv + = 1 ;
break ;
case SWRAP_CLOSE_ACK :
2008-02-20 01:53:04 +03:00
if ( si - > type ! = SOCK_STREAM ) return NULL ;
2006-10-05 10:27:41 +04:00
2009-03-03 17:17:26 +03:00
src_addr = si - > myname ;
dest_addr = si - > peername ;
2006-10-05 10:27:41 +04:00
2008-10-07 21:56:30 +04:00
tcp_seqno = si - > io . pck_snd ;
2006-10-05 10:27:41 +04:00
tcp_ack = si - > io . pck_rcv ;
tcp_ctl = 0x10 ; /* ACK */
break ;
2006-10-06 19:16:18 +04:00
default :
2008-02-20 01:53:04 +03:00
return NULL ;
2006-10-05 10:27:41 +04:00
}
2006-10-05 15:39:59 +04:00
swrapGetTimeOfDay ( & tv ) ;
2008-02-20 01:53:04 +03:00
return swrap_packet_init ( & tv , src_addr , dest_addr , si - > type ,
2009-03-03 17:17:26 +03:00
( const uint8_t * ) buf , len ,
tcp_seqno , tcp_ack , tcp_ctl , unreachable ,
packet_len ) ;
2008-02-20 01:53:04 +03:00
}
2009-03-03 16:58:53 +03:00
static void swrap_dump_packet ( struct socket_info * si ,
const struct sockaddr * addr ,
enum swrap_packet_type type ,
const void * buf , size_t len )
2008-02-20 01:53:04 +03:00
{
const char * file_name ;
2009-03-03 16:58:53 +03:00
uint8_t * packet ;
2008-02-20 01:53:04 +03:00
size_t packet_len = 0 ;
int fd ;
file_name = socket_wrapper_pcap_file ( ) ;
if ( ! file_name ) {
return ;
}
packet = swrap_marshall_packet ( si , addr , type , buf , len , & packet_len ) ;
2006-10-05 15:39:59 +04:00
if ( ! packet ) {
return ;
}
fd = swrap_get_pcap_fd ( file_name ) ;
if ( fd ! = - 1 ) {
2014-04-07 18:12:21 +04:00
if ( write ( fd , packet , packet_len ) ! = ( ssize_t ) packet_len ) {
2008-12-23 07:08:14 +03:00
free ( packet ) ;
return ;
}
2006-10-05 15:39:59 +04:00
}
2014-04-07 18:12:21 +04:00
free ( packet ) ;
}
/****************************************************************************
* SIGNALFD
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
# ifdef HAVE_SIGNALFD
static int swrap_signalfd ( int fd , const sigset_t * mask , int flags )
{
int rc ;
rc = libc_signalfd ( fd , mask , flags ) ;
if ( rc ! = - 1 ) {
swrap_remove_stale ( fd ) ;
}
return rc ;
}
int signalfd ( int fd , const sigset_t * mask , int flags )
{
return swrap_signalfd ( fd , mask , flags ) ;
2006-09-12 10:19:11 +04:00
}
2014-04-07 18:12:21 +04:00
# endif
/****************************************************************************
* SOCKET
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2006-09-12 10:19:11 +04:00
2014-04-07 18:12:21 +04:00
static int swrap_socket ( int family , int type , int protocol )
2005-03-28 05:00:39 +04:00
{
struct socket_info * si ;
2011-09-29 01:09:49 +04:00
struct socket_info_fd * fi ;
2005-03-28 05:00:39 +04:00
int fd ;
2009-06-04 08:14:14 +04:00
int real_type = type ;
2014-04-07 18:12:21 +04:00
/*
* Remove possible addition flags passed to socket ( ) so
* do not fail checking the type .
* See https : //lwn.net/Articles/281965/
*/
2009-06-04 08:14:14 +04:00
# ifdef SOCK_CLOEXEC
real_type & = ~ SOCK_CLOEXEC ;
# endif
# ifdef SOCK_NONBLOCK
real_type & = ~ SOCK_NONBLOCK ;
# endif
2005-03-28 05:00:39 +04:00
2014-04-07 18:12:21 +04:00
if ( ! socket_wrapper_enabled ( ) ) {
return libc_socket ( family , type , protocol ) ;
2005-03-28 05:00:39 +04:00
}
2006-09-12 18:44:44 +04:00
2006-09-12 18:59:08 +04:00
switch ( family ) {
2006-09-12 18:44:44 +04:00
case AF_INET :
2007-04-16 08:59:47 +04:00
# ifdef HAVE_IPV6
case AF_INET6 :
# endif
2006-09-12 18:44:44 +04:00
break ;
case AF_UNIX :
2014-04-07 18:12:21 +04:00
return libc_socket ( family , type , protocol ) ;
2006-09-12 18:44:44 +04:00
default :
errno = EAFNOSUPPORT ;
return - 1 ;
}
2006-09-26 17:15:31 +04:00
2009-06-04 08:14:14 +04:00
switch ( real_type ) {
2006-09-26 17:15:31 +04:00
case SOCK_STREAM :
break ;
case SOCK_DGRAM :
break ;
default :
errno = EPROTONOSUPPORT ;
return - 1 ;
}
switch ( protocol ) {
case 0 :
break ;
2007-04-16 08:59:47 +04:00
case 6 :
2009-06-04 08:14:14 +04:00
if ( real_type = = SOCK_STREAM ) {
2007-04-16 08:59:47 +04:00
break ;
}
2007-06-11 18:41:14 +04:00
/*fall through*/
2007-04-16 08:59:47 +04:00
case 17 :
2009-06-04 08:14:14 +04:00
if ( real_type = = SOCK_DGRAM ) {
2007-04-16 08:59:47 +04:00
break ;
}
2007-06-11 18:41:14 +04:00
/*fall through*/
2006-09-26 17:15:31 +04:00
default :
errno = EPROTONOSUPPORT ;
return - 1 ;
}
2014-04-07 18:12:21 +04:00
/*
* We must call libc_socket with type , from the caller , not the version
* we removed SOCK_CLOEXEC and SOCK_NONBLOCK from
*/
fd = libc_socket ( AF_UNIX , type , 0 ) ;
if ( fd = = - 1 ) {
return - 1 ;
}
2005-03-28 05:00:39 +04:00
2014-04-07 18:12:21 +04:00
/* Check if we have a stale fd and remove it */
si = find_socket_info ( fd ) ;
if ( si ! = NULL ) {
swrap_remove_stale ( fd ) ;
}
2005-03-28 05:00:39 +04:00
2014-04-07 18:12:21 +04:00
si = ( struct socket_info * ) malloc ( sizeof ( struct socket_info ) ) ;
memset ( si , 0 , sizeof ( struct socket_info ) ) ;
2011-09-29 01:09:49 +04:00
if ( si = = NULL ) {
errno = ENOMEM ;
return - 1 ;
}
2005-03-28 05:00:39 +04:00
2006-09-12 18:59:08 +04:00
si - > family = family ;
2009-06-04 08:14:14 +04:00
/* however, the rest of the socket_wrapper code expects just
* the type , not the flags */
si - > type = real_type ;
2005-03-28 05:00:39 +04:00
si - > protocol = protocol ;
2011-09-29 01:09:49 +04:00
fi = ( struct socket_info_fd * ) calloc ( 1 , sizeof ( struct socket_info_fd ) ) ;
if ( fi = = NULL ) {
free ( si ) ;
errno = ENOMEM ;
return - 1 ;
}
fi - > fd = fd ;
SWRAP_DLIST_ADD ( si - > fds , fi ) ;
2006-10-09 01:53:09 +04:00
SWRAP_DLIST_ADD ( sockets , si ) ;
2005-03-28 05:00:39 +04:00
2011-09-29 01:09:49 +04:00
return fd ;
2005-03-28 05:00:39 +04:00
}
2014-04-07 18:12:21 +04:00
int socket ( int family , int type , int protocol )
{
return swrap_socket ( family , type , protocol ) ;
}
/****************************************************************************
* SOCKETPAIR
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static int swrap_socketpair ( int family , int type , int protocol , int sv [ 2 ] )
{
int rc ;
rc = libc_socketpair ( family , type , protocol , sv ) ;
if ( rc ! = - 1 ) {
swrap_remove_stale ( sv [ 0 ] ) ;
swrap_remove_stale ( sv [ 1 ] ) ;
}
return rc ;
}
int socketpair ( int family , int type , int protocol , int sv [ 2 ] )
{
return swrap_socketpair ( family , type , protocol , sv ) ;
}
/****************************************************************************
* SOCKETPAIR
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
# ifdef HAVE_TIMERFD_CREATE
static int swrap_timerfd_create ( int clockid , int flags )
{
int fd ;
fd = libc_timerfd_create ( clockid , flags ) ;
if ( fd ! = - 1 ) {
swrap_remove_stale ( fd ) ;
}
return fd ;
}
int timerfd_create ( int clockid , int flags )
{
return swrap_timerfd_create ( clockid , flags ) ;
}
# endif
/****************************************************************************
* PIPE
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static int swrap_pipe ( int pipefd [ 2 ] )
{
int rc ;
rc = libc_pipe ( pipefd ) ;
if ( rc ! = - 1 ) {
swrap_remove_stale ( pipefd [ 0 ] ) ;
swrap_remove_stale ( pipefd [ 1 ] ) ;
}
return rc ;
}
int pipe ( int pipefd [ 2 ] )
{
return swrap_pipe ( pipefd ) ;
}
/****************************************************************************
* ACCEPT
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static int swrap_accept ( int s , struct sockaddr * addr , socklen_t * addrlen )
2005-03-28 05:00:39 +04:00
{
struct socket_info * parent_si , * child_si ;
2011-09-29 01:09:49 +04:00
struct socket_info_fd * child_fi ;
2005-03-28 05:00:39 +04:00
int fd ;
struct sockaddr_un un_addr ;
2005-12-05 18:26:49 +03:00
socklen_t un_addrlen = sizeof ( un_addr ) ;
struct sockaddr_un un_my_addr ;
socklen_t un_my_addrlen = sizeof ( un_my_addr ) ;
2007-04-16 08:59:47 +04:00
struct sockaddr * my_addr ;
socklen_t my_addrlen , len ;
2005-03-28 05:00:39 +04:00
int ret ;
parent_si = find_socket_info ( s ) ;
if ( ! parent_si ) {
2014-04-07 18:12:21 +04:00
return libc_accept ( s , addr , addrlen ) ;
2005-03-28 05:00:39 +04:00
}
2007-04-16 08:59:47 +04:00
/*
* assume out sockaddr have the same size as the in parent
* socket family
*/
my_addrlen = socket_length ( parent_si - > family ) ;
2007-06-11 18:41:14 +04:00
if ( my_addrlen < = 0 ) {
2007-04-16 08:59:47 +04:00
errno = EINVAL ;
return - 1 ;
}
2007-09-08 17:27:14 +04:00
my_addr = ( struct sockaddr * ) malloc ( my_addrlen ) ;
2007-04-16 08:59:47 +04:00
if ( my_addr = = NULL ) {
return - 1 ;
}
2005-07-21 12:42:17 +04:00
memset ( & un_addr , 0 , sizeof ( un_addr ) ) ;
2005-12-05 18:26:49 +03:00
memset ( & un_my_addr , 0 , sizeof ( un_my_addr ) ) ;
2005-07-21 12:42:17 +04:00
2014-04-07 18:12:21 +04:00
ret = libc_accept ( s , ( struct sockaddr * ) ( void * ) & un_addr , & un_addrlen ) ;
2007-04-16 08:59:47 +04:00
if ( ret = = - 1 ) {
2014-04-07 18:12:21 +04:00
if ( errno = = ENOTSOCK ) {
/* Remove stale fds */
swrap_remove_stale ( s ) ;
}
2007-04-16 08:59:47 +04:00
free ( my_addr ) ;
return ret ;
}
2005-03-28 05:00:39 +04:00
fd = ret ;
2007-04-16 08:59:47 +04:00
len = my_addrlen ;
2005-03-31 16:40:12 +04:00
ret = sockaddr_convert_from_un ( parent_si , & un_addr , un_addrlen ,
2007-04-16 08:59:47 +04:00
parent_si - > family , my_addr , & len ) ;
2006-09-16 21:57:50 +04:00
if ( ret = = - 1 ) {
2007-04-16 08:59:47 +04:00
free ( my_addr ) ;
2006-09-16 21:57:50 +04:00
close ( fd ) ;
return ret ;
}
2005-03-28 05:00:39 +04:00
2006-09-19 04:55:40 +04:00
child_si = ( struct socket_info * ) malloc ( sizeof ( struct socket_info ) ) ;
2014-04-07 18:12:21 +04:00
memset ( child_si , 0 , sizeof ( struct socket_info ) ) ;
2005-03-28 05:00:39 +04:00
2011-09-29 01:09:49 +04:00
child_fi = ( struct socket_info_fd * ) calloc ( 1 , sizeof ( struct socket_info_fd ) ) ;
if ( child_fi = = NULL ) {
free ( child_si ) ;
free ( my_addr ) ;
close ( fd ) ;
errno = ENOMEM ;
return - 1 ;
}
child_fi - > fd = fd ;
SWRAP_DLIST_ADD ( child_si - > fds , child_fi ) ;
2006-09-12 18:59:08 +04:00
child_si - > family = parent_si - > family ;
2005-12-05 18:26:49 +03:00
child_si - > type = parent_si - > type ;
child_si - > protocol = parent_si - > protocol ;
2005-06-19 16:34:59 +04:00
child_si - > bound = 1 ;
2006-09-29 13:31:20 +04:00
child_si - > is_server = 1 ;
2009-03-08 19:19:50 +03:00
child_si - > connected = 1 ;
2005-03-28 05:00:39 +04:00
2007-04-16 08:59:47 +04:00
child_si - > peername_len = len ;
child_si - > peername = sockaddr_dup ( my_addr , len ) ;
if ( addr ! = NULL & & addrlen ! = NULL ) {
2011-03-09 13:46:34 +03:00
size_t copy_len = MIN ( * addrlen , len ) ;
if ( copy_len > 0 ) {
memcpy ( addr , my_addr , copy_len ) ;
}
* addrlen = len ;
2007-04-16 08:59:47 +04:00
}
2014-04-07 18:12:21 +04:00
ret = libc_getsockname ( fd ,
( struct sockaddr * ) ( void * ) & un_my_addr ,
2011-03-02 22:46:45 +03:00
& un_my_addrlen ) ;
2006-09-16 21:57:50 +04:00
if ( ret = = - 1 ) {
2011-09-29 01:09:49 +04:00
free ( child_fi ) ;
2006-09-16 21:57:50 +04:00
free ( child_si ) ;
2014-04-07 18:12:21 +04:00
free ( my_addr ) ;
2006-09-16 21:57:50 +04:00
close ( fd ) ;
return ret ;
}
2005-12-05 18:26:49 +03:00
2007-04-16 08:59:47 +04:00
len = my_addrlen ;
2005-12-05 18:26:49 +03:00
ret = sockaddr_convert_from_un ( child_si , & un_my_addr , un_my_addrlen ,
2007-04-16 08:59:47 +04:00
child_si - > family , my_addr , & len ) ;
2006-09-16 21:57:50 +04:00
if ( ret = = - 1 ) {
2011-09-29 01:09:49 +04:00
free ( child_fi ) ;
2006-09-16 21:57:50 +04:00
free ( child_si ) ;
2007-04-16 08:59:47 +04:00
free ( my_addr ) ;
2006-09-16 21:57:50 +04:00
close ( fd ) ;
return ret ;
}
2005-12-05 18:26:49 +03:00
2014-04-07 18:12:21 +04:00
SWRAP_LOG ( SWRAP_LOG_TRACE ,
" accept() path=%s, fd=%d " ,
un_my_addr . sun_path , s ) ;
2007-04-16 08:59:47 +04:00
child_si - > myname_len = len ;
child_si - > myname = sockaddr_dup ( my_addr , len ) ;
free ( my_addr ) ;
2005-06-10 16:21:46 +04:00
2006-10-09 01:53:09 +04:00
SWRAP_DLIST_ADD ( sockets , child_si ) ;
2005-06-10 16:21:46 +04:00
2014-04-07 18:12:21 +04:00
if ( addr ! = NULL ) {
swrap_dump_packet ( child_si , addr , SWRAP_ACCEPT_SEND , NULL , 0 ) ;
swrap_dump_packet ( child_si , addr , SWRAP_ACCEPT_RECV , NULL , 0 ) ;
swrap_dump_packet ( child_si , addr , SWRAP_ACCEPT_ACK , NULL , 0 ) ;
}
2006-09-12 13:08:55 +04:00
2005-03-28 05:00:39 +04:00
return fd ;
}
2014-04-07 18:12:21 +04:00
# ifdef HAVE_ACCEPT_PSOCKLEN_T
int accept ( int s , struct sockaddr * addr , Psocklen_t addrlen )
# else
int accept ( int s , struct sockaddr * addr , socklen_t * addrlen )
# endif
{
return swrap_accept ( s , addr , ( socklen_t * ) addrlen ) ;
}
2006-09-26 17:15:31 +04:00
static int autobind_start_init ;
static int autobind_start ;
2005-06-10 16:21:46 +04:00
/* using sendto() or connect() on an unbound socket would give the
recipient no way to reply , as unlike UDP and TCP , a unix domain
2014-05-08 17:30:09 +04:00
socket can ' t auto - assign ephemeral port numbers , so we need to
2009-03-08 19:20:18 +03:00
assign it here .
Note : this might change the family from ipv6 to ipv4
*/
2011-09-29 01:04:51 +04:00
static int swrap_auto_bind ( int fd , struct socket_info * si , int family )
2005-06-10 16:21:46 +04:00
{
struct sockaddr_un un_addr ;
int i ;
2005-11-07 18:36:51 +03:00
char type ;
int ret ;
2006-09-12 20:25:50 +04:00
int port ;
2005-11-07 18:36:51 +03:00
struct stat st ;
2006-09-26 17:15:31 +04:00
if ( autobind_start_init ! = 1 ) {
autobind_start_init = 1 ;
autobind_start = getpid ( ) ;
autobind_start % = 50000 ;
autobind_start + = 10000 ;
}
2005-06-10 16:21:46 +04:00
un_addr . sun_family = AF_UNIX ;
2005-11-07 18:36:51 +03:00
2009-03-08 19:20:18 +03:00
switch ( family ) {
2007-04-16 08:59:47 +04:00
case AF_INET : {
struct sockaddr_in in ;
switch ( si - > type ) {
case SOCK_STREAM :
type = SOCKET_TYPE_CHAR_TCP ;
break ;
case SOCK_DGRAM :
type = SOCKET_TYPE_CHAR_UDP ;
break ;
default :
errno = ESOCKTNOSUPPORT ;
return - 1 ;
}
memset ( & in , 0 , sizeof ( in ) ) ;
in . sin_family = AF_INET ;
in . sin_addr . s_addr = htonl ( 127 < < 24 |
socket_wrapper_default_iface ( ) ) ;
si - > myname_len = sizeof ( in ) ;
si - > myname = sockaddr_dup ( & in , si - > myname_len ) ;
2005-11-07 18:36:51 +03:00
break ;
2007-04-16 08:59:47 +04:00
}
# ifdef HAVE_IPV6
case AF_INET6 : {
struct sockaddr_in6 in6 ;
2009-03-08 19:20:18 +03:00
if ( si - > family ! = family ) {
errno = ENETUNREACH ;
return - 1 ;
}
2007-04-16 08:59:47 +04:00
switch ( si - > type ) {
case SOCK_STREAM :
type = SOCKET_TYPE_CHAR_TCP_V6 ;
break ;
case SOCK_DGRAM :
type = SOCKET_TYPE_CHAR_UDP_V6 ;
break ;
default :
2009-03-03 18:45:41 +03:00
errno = ESOCKTNOSUPPORT ;
return - 1 ;
2007-04-16 08:59:47 +04:00
}
memset ( & in6 , 0 , sizeof ( in6 ) ) ;
in6 . sin6_family = AF_INET6 ;
2009-03-09 11:24:45 +03:00
in6 . sin6_addr = * swrap_ipv6 ( ) ;
2009-03-03 18:45:41 +03:00
in6 . sin6_addr . s6_addr [ 15 ] = socket_wrapper_default_iface ( ) ;
2007-04-16 08:59:47 +04:00
si - > myname_len = sizeof ( in6 ) ;
si - > myname = sockaddr_dup ( & in6 , si - > myname_len ) ;
2005-11-07 18:36:51 +03:00
break ;
2007-04-16 08:59:47 +04:00
}
# endif
2005-11-07 18:36:51 +03:00
default :
errno = ESOCKTNOSUPPORT ;
return - 1 ;
}
2006-09-26 17:15:31 +04:00
if ( autobind_start > 60000 ) {
autobind_start = 10000 ;
}
2014-04-07 18:12:21 +04:00
for ( i = 0 ; i < SOCKET_MAX_SOCKETS ; i + + ) {
2006-09-26 17:15:31 +04:00
port = autobind_start + i ;
2005-06-10 16:21:46 +04:00
snprintf ( un_addr . sun_path , sizeof ( un_addr . sun_path ) ,
2005-07-21 17:45:07 +04:00
" %s/ " SOCKET_FORMAT , socket_wrapper_dir ( ) ,
2006-09-12 20:25:50 +04:00
type , socket_wrapper_default_iface ( ) , port ) ;
2005-11-07 18:36:51 +03:00
if ( stat ( un_addr . sun_path , & st ) = = 0 ) continue ;
2011-02-12 14:18:16 +03:00
2014-04-07 18:12:21 +04:00
ret = libc_bind ( fd , ( struct sockaddr * ) ( void * ) & un_addr ,
2011-03-02 22:46:45 +03:00
sizeof ( un_addr ) ) ;
2005-11-07 18:36:51 +03:00
if ( ret = = - 1 ) return ret ;
si - > tmp_path = strdup ( un_addr . sun_path ) ;
si - > bound = 1 ;
2006-09-26 17:15:31 +04:00
autobind_start = port + 1 ;
2005-11-07 18:36:51 +03:00
break ;
2005-06-10 16:21:46 +04:00
}
2014-04-07 18:12:21 +04:00
if ( i = = SOCKET_MAX_SOCKETS ) {
SWRAP_LOG ( SWRAP_LOG_ERROR , " Too many open unix sockets (%u) for "
" interface " SOCKET_FORMAT ,
SOCKET_MAX_SOCKETS ,
type ,
socket_wrapper_default_iface ( ) ,
0 ) ;
2005-11-07 18:36:51 +03:00
errno = ENFILE ;
2005-06-10 16:21:46 +04:00
return - 1 ;
}
2006-09-26 17:15:31 +04:00
2009-03-08 19:20:18 +03:00
si - > family = family ;
2007-04-16 08:59:47 +04:00
set_port ( si - > family , port , si - > myname ) ;
2005-06-10 16:21:46 +04:00
return 0 ;
}
2014-04-07 18:12:21 +04:00
/****************************************************************************
* CONNECT
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2005-06-10 16:21:46 +04:00
2014-04-07 18:12:21 +04:00
static int swrap_connect ( int s , const struct sockaddr * serv_addr ,
socklen_t addrlen )
2005-03-28 05:00:39 +04:00
{
int ret ;
struct sockaddr_un un_addr ;
struct socket_info * si = find_socket_info ( s ) ;
2010-10-30 18:07:31 +04:00
int bcast = 0 ;
2005-03-28 05:00:39 +04:00
if ( ! si ) {
2014-04-07 18:12:21 +04:00
return libc_connect ( s , serv_addr , addrlen ) ;
2005-03-28 05:00:39 +04:00
}
2006-09-12 18:44:44 +04:00
if ( si - > bound = = 0 ) {
2011-09-29 01:04:51 +04:00
ret = swrap_auto_bind ( s , si , serv_addr - > sa_family ) ;
2005-06-10 16:21:46 +04:00
if ( ret = = - 1 ) return - 1 ;
}
2007-04-16 08:59:47 +04:00
if ( si - > family ! = serv_addr - > sa_family ) {
errno = EINVAL ;
return - 1 ;
}
2011-03-02 22:46:45 +03:00
ret = sockaddr_convert_to_un ( si , serv_addr ,
2010-10-30 18:07:31 +04:00
addrlen , & un_addr , 0 , & bcast ) ;
2005-03-31 16:40:12 +04:00
if ( ret = = - 1 ) return - 1 ;
2005-03-28 05:00:39 +04:00
2010-10-30 18:07:31 +04:00
if ( bcast ) {
errno = ENETUNREACH ;
return - 1 ;
}
2009-03-23 11:16:18 +03:00
if ( si - > type = = SOCK_DGRAM ) {
si - > defer_connect = 1 ;
ret = 0 ;
} else {
swrap_dump_packet ( si , serv_addr , SWRAP_CONNECT_SEND , NULL , 0 ) ;
2006-09-29 13:31:20 +04:00
2014-04-07 18:12:21 +04:00
ret = libc_connect ( s ,
( struct sockaddr * ) ( void * ) & un_addr ,
2009-03-23 11:16:18 +03:00
sizeof ( struct sockaddr_un ) ) ;
}
2005-03-28 05:00:39 +04:00
2014-04-07 18:12:21 +04:00
SWRAP_LOG ( SWRAP_LOG_TRACE ,
" connect() path=%s, fd=%d " ,
un_addr . sun_path , s ) ;
2005-11-07 18:36:51 +03:00
/* to give better errors */
2006-09-12 18:44:44 +04:00
if ( ret = = - 1 & & errno = = ENOENT ) {
errno = EHOSTUNREACH ;
2005-11-07 18:36:51 +03:00
}
2005-03-31 16:40:12 +04:00
if ( ret = = 0 ) {
2005-03-28 05:00:39 +04:00
si - > peername_len = addrlen ;
2005-03-31 03:28:15 +04:00
si - > peername = sockaddr_dup ( serv_addr , addrlen ) ;
2009-03-08 19:19:50 +03:00
si - > connected = 1 ;
2005-03-28 05:00:39 +04:00
2014-06-03 16:50:53 +04:00
/*
* When we connect ( ) on a socket than we have to bind the
* outgoing connection on the interface we use for the
* transport . We already bound it on the right interface
* but here we have to update the name so getsockname ( )
* returns correct information .
*/
if ( si - > bindname ! = NULL ) {
free ( si - > myname ) ;
si - > myname = si - > bindname ;
si - > myname_len = si - > bindname_len ;
si - > bindname = NULL ;
si - > bindname_len = 0 ;
}
2006-09-29 13:31:20 +04:00
swrap_dump_packet ( si , serv_addr , SWRAP_CONNECT_RECV , NULL , 0 ) ;
swrap_dump_packet ( si , serv_addr , SWRAP_CONNECT_ACK , NULL , 0 ) ;
} else {
swrap_dump_packet ( si , serv_addr , SWRAP_CONNECT_UNREACH , NULL , 0 ) ;
}
2006-09-12 13:08:55 +04:00
2005-03-28 05:00:39 +04:00
return ret ;
}
2014-04-07 18:12:21 +04:00
int connect ( int s , const struct sockaddr * serv_addr , socklen_t addrlen )
{
return swrap_connect ( s , serv_addr , addrlen ) ;
}
/****************************************************************************
* BIND
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static int swrap_bind ( int s , const struct sockaddr * myaddr , socklen_t addrlen )
2005-03-28 05:00:39 +04:00
{
int ret ;
struct sockaddr_un un_addr ;
struct socket_info * si = find_socket_info ( s ) ;
if ( ! si ) {
2014-04-07 18:12:21 +04:00
return libc_bind ( s , myaddr , addrlen ) ;
2005-03-28 05:00:39 +04:00
}
2005-06-10 16:21:46 +04:00
si - > myname_len = addrlen ;
si - > myname = sockaddr_dup ( myaddr , addrlen ) ;
2011-03-02 22:46:45 +03:00
ret = sockaddr_convert_to_un ( si , myaddr , addrlen , & un_addr , 1 , & si - > bcast ) ;
2005-03-31 16:40:12 +04:00
if ( ret = = - 1 ) return - 1 ;
2005-03-28 05:00:39 +04:00
unlink ( un_addr . sun_path ) ;
2014-04-07 18:12:21 +04:00
ret = libc_bind ( s , ( struct sockaddr * ) ( void * ) & un_addr ,
2005-03-31 16:40:12 +04:00
sizeof ( struct sockaddr_un ) ) ;
2005-03-28 05:00:39 +04:00
2014-04-07 18:12:21 +04:00
SWRAP_LOG ( SWRAP_LOG_TRACE ,
" bind() path=%s, fd=%d " ,
un_addr . sun_path , s ) ;
2005-03-31 16:40:12 +04:00
if ( ret = = 0 ) {
si - > bound = 1 ;
2005-03-28 05:00:39 +04:00
}
return ret ;
}
2014-04-07 18:12:21 +04:00
int bind ( int s , const struct sockaddr * myaddr , socklen_t addrlen )
{
return swrap_bind ( s , myaddr , addrlen ) ;
}
/****************************************************************************
* LISTEN
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static int swrap_listen ( int s , int backlog )
2006-09-27 14:13:45 +04:00
{
int ret ;
struct socket_info * si = find_socket_info ( s ) ;
if ( ! si ) {
2014-04-07 18:12:21 +04:00
return libc_listen ( s , backlog ) ;
2006-09-27 14:13:45 +04:00
}
2014-04-07 18:12:21 +04:00
ret = libc_listen ( s , backlog ) ;
return ret ;
}
int listen ( int s , int backlog )
{
return swrap_listen ( s , backlog ) ;
}
/****************************************************************************
* OPEN
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static int swrap_vopen ( const char * pathname , int flags , va_list ap )
{
int ret ;
2006-09-27 14:13:45 +04:00
2014-04-07 18:12:21 +04:00
ret = libc_vopen ( 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 ) ;
}
2006-09-27 14:13:45 +04:00
return ret ;
}
2014-04-07 18:12:21 +04:00
int open ( const char * pathname , int flags , . . . )
{
va_list ap ;
int fd ;
va_start ( ap , flags ) ;
fd = swrap_vopen ( pathname , flags , ap ) ;
va_end ( ap ) ;
return fd ;
}
/****************************************************************************
* GETPEERNAME
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static int swrap_getpeername ( int s , struct sockaddr * name , socklen_t * addrlen )
2005-03-28 05:00:39 +04:00
{
struct socket_info * si = find_socket_info ( s ) ;
if ( ! si ) {
2014-04-07 18:12:21 +04:00
return libc_getpeername ( s , name , addrlen ) ;
2005-03-28 05:00:39 +04:00
}
2006-09-29 13:31:20 +04:00
if ( ! si - > peername )
2005-03-28 05:00:39 +04:00
{
errno = ENOTCONN ;
return - 1 ;
}
memcpy ( name , si - > peername , si - > peername_len ) ;
* addrlen = si - > peername_len ;
return 0 ;
}
2014-04-07 18:12:21 +04:00
# ifdef HAVE_ACCEPT_PSOCKLEN_T
int getpeername ( int s , struct sockaddr * name , Psocklen_t addrlen )
# else
int getpeername ( int s , struct sockaddr * name , socklen_t * addrlen )
# endif
{
return swrap_getpeername ( s , name , ( socklen_t * ) addrlen ) ;
}
/****************************************************************************
* GETSOCKNAME
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static int swrap_getsockname ( int s , struct sockaddr * name , socklen_t * addrlen )
2005-03-28 05:00:39 +04:00
{
struct socket_info * si = find_socket_info ( s ) ;
if ( ! si ) {
2014-04-07 18:12:21 +04:00
return libc_getsockname ( s , name , addrlen ) ;
2005-03-28 05:00:39 +04:00
}
memcpy ( name , si - > myname , si - > myname_len ) ;
* addrlen = si - > myname_len ;
return 0 ;
}
2014-04-07 18:12:21 +04:00
# ifdef HAVE_ACCEPT_PSOCKLEN_T
int getsockname ( int s , struct sockaddr * name , Psocklen_t addrlen )
# else
int getsockname ( int s , struct sockaddr * name , socklen_t * addrlen )
# endif
{
return swrap_getsockname ( s , name , ( socklen_t * ) addrlen ) ;
}
/****************************************************************************
* GETSOCKOPT
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static int swrap_getsockopt ( int s , int level , int optname ,
void * optval , socklen_t * optlen )
2005-03-28 05:00:39 +04:00
{
struct socket_info * si = find_socket_info ( s ) ;
if ( ! si ) {
2014-04-07 18:12:21 +04:00
return libc_getsockopt ( s ,
level ,
optname ,
optval ,
optlen ) ;
2005-03-28 05:00:39 +04:00
}
2005-03-31 03:28:15 +04:00
if ( level = = SOL_SOCKET ) {
2014-04-07 18:12:21 +04:00
return libc_getsockopt ( s ,
level ,
optname ,
optval ,
optlen ) ;
}
2005-03-31 03:28:15 +04:00
2006-09-12 18:59:08 +04:00
errno = ENOPROTOOPT ;
return - 1 ;
2005-03-28 05:00:39 +04:00
}
2014-04-07 18:12:21 +04:00
# ifdef HAVE_ACCEPT_PSOCKLEN_T
int getsockopt ( int s , int level , int optname , void * optval , Psocklen_t optlen )
# else
int getsockopt ( int s , int level , int optname , void * optval , socklen_t * optlen )
# endif
{
return swrap_getsockopt ( s , level , optname , optval , ( socklen_t * ) optlen ) ;
}
/****************************************************************************
* SETSOCKOPT
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static int swrap_setsockopt ( int s , int level , int optname ,
const void * optval , socklen_t optlen )
2005-03-28 05:00:39 +04:00
{
struct socket_info * si = find_socket_info ( s ) ;
if ( ! si ) {
2014-04-07 18:12:21 +04:00
return libc_setsockopt ( s ,
level ,
optname ,
optval ,
optlen ) ;
2005-03-28 05:00:39 +04:00
}
2005-03-31 03:28:15 +04:00
if ( level = = SOL_SOCKET ) {
2014-04-07 18:12:21 +04:00
return libc_setsockopt ( s ,
level ,
optname ,
optval ,
optlen ) ;
2005-03-31 03:28:15 +04:00
}
2006-09-12 18:59:08 +04:00
switch ( si - > family ) {
2005-03-31 03:28:15 +04:00
case AF_INET :
2014-06-03 16:54:28 +04:00
if ( level = = IPPROTO_IP ) {
# ifdef IP_PKTINFO
if ( optname = = IP_PKTINFO ) {
si - > pktinfo = AF_INET ;
}
# endif /* IP_PKTINFO */
}
2006-04-08 06:44:37 +04:00
return 0 ;
2010-02-17 11:43:00 +03:00
# ifdef HAVE_IPV6
case AF_INET6 :
2014-06-03 16:54:28 +04:00
if ( level = = IPPROTO_IPV6 ) {
# ifdef IPV6_RECVPKTINFO
if ( optname = = IPV6_RECVPKTINFO ) {
si - > pktinfo = AF_INET6 ;
}
# endif /* IPV6_PKTINFO */
}
2010-02-17 11:43:00 +03:00
return 0 ;
# endif
2005-03-31 03:28:15 +04:00
default :
2005-03-28 05:00:39 +04:00
errno = ENOPROTOOPT ;
return - 1 ;
}
}
2014-04-07 18:12:21 +04:00
int setsockopt ( int s , int level , int optname ,
const void * optval , socklen_t optlen )
{
return swrap_setsockopt ( s , level , optname , optval , optlen ) ;
}
/****************************************************************************
* IOCTL
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static int swrap_vioctl ( int s , unsigned long int r , va_list va )
2010-10-30 18:19:33 +04:00
{
struct socket_info * si = find_socket_info ( s ) ;
2014-04-07 18:12:21 +04:00
va_list ap ;
2010-10-30 18:19:33 +04:00
int value ;
2014-04-07 18:12:21 +04:00
int rc ;
2010-10-30 18:19:33 +04:00
if ( ! si ) {
2014-04-07 18:12:21 +04:00
return libc_vioctl ( s , r , va ) ;
2010-10-30 18:19:33 +04:00
}
2014-04-07 18:12:21 +04:00
va_copy ( ap , va ) ;
rc = libc_vioctl ( s , r , va ) ;
2010-10-30 18:19:33 +04:00
switch ( r ) {
case FIONREAD :
2014-04-07 18:12:21 +04:00
value = * ( ( int * ) va_arg ( ap , int * ) ) ;
if ( rc = = - 1 & & errno ! = EAGAIN & & errno ! = ENOBUFS ) {
2010-10-30 18:19:33 +04:00
swrap_dump_packet ( si , NULL , SWRAP_PENDING_RST , NULL , 0 ) ;
} else if ( value = = 0 ) { /* END OF FILE */
swrap_dump_packet ( si , NULL , SWRAP_PENDING_RST , NULL , 0 ) ;
}
break ;
}
2014-04-07 18:12:21 +04:00
va_end ( ap ) ;
return rc ;
}
# ifdef HAVE_IOCTL_INT
int ioctl ( int s , int r , . . . )
# else
int ioctl ( int s , unsigned long int r , . . . )
# endif
{
va_list va ;
int rc ;
va_start ( va , r ) ;
rc = swrap_vioctl ( s , ( unsigned long int ) r , va ) ;
va_end ( va ) ;
return rc ;
2010-10-30 18:19:33 +04:00
}
2014-06-03 16:55:13 +04:00
/*****************
* CMSG
* * * * * * * * * * * * * * * * */
# ifdef HAVE_STRUCT_MSGHDR_MSG_CONTROL
/**
* @ brief Add a cmsghdr to a msghdr .
*
* This is an function to add any type of cmsghdr . It will operate on the
* msg - > msg_control and msg - > msg_controllen you pass in by adapting them to
* the buffer position after the added cmsg element . Hence , this function is
* intended to be used with an intermediate msghdr and not on the original
* one handed in by the client .
*
* @ param [ in ] msg The msghdr to which to add the cmsg .
*
* @ param [ in ] level The cmsg level to set .
*
* @ param [ in ] type The cmsg type to set .
*
* @ param [ in ] data The cmsg data to set .
*
* @ param [ in ] len the length of the data to set .
*/
static void swrap_msghdr_add_cmsghdr ( struct msghdr * msg ,
int level ,
int type ,
const void * data ,
size_t len )
{
size_t cmlen = CMSG_LEN ( len ) ;
size_t cmspace = CMSG_SPACE ( len ) ;
uint8_t cmbuf [ cmspace ] ;
struct cmsghdr * cm = ( struct cmsghdr * ) cmbuf ;
uint8_t * p ;
memset ( cmbuf , 0 , cmspace ) ;
if ( msg - > msg_controllen < cmlen ) {
cmlen = msg - > msg_controllen ;
msg - > msg_flags | = MSG_CTRUNC ;
}
if ( msg - > msg_controllen < cmspace ) {
cmspace = msg - > msg_controllen ;
}
/*
* We copy the full input data into an intermediate cmsghdr first
* in order to more easily cope with truncation .
*/
cm - > cmsg_len = cmlen ;
cm - > cmsg_level = level ;
cm - > cmsg_type = type ;
memcpy ( CMSG_DATA ( cm ) , data , len ) ;
/*
* We now copy the possibly truncated buffer .
* We copy cmlen bytes , but consume cmspace bytes ,
* leaving the possible padding uninitialiazed .
*/
p = ( uint8_t * ) msg - > msg_control ;
memcpy ( p , cm , cmlen ) ;
p + = cmspace ;
msg - > msg_control = p ;
msg - > msg_controllen - = cmspace ;
return ;
}
2014-06-03 16:55:49 +04:00
static int swrap_msghdr_add_pktinfo ( struct socket_info * si ,
struct msghdr * msg )
{
/* Add packet info */
switch ( si - > pktinfo ) {
# ifdef IP_PKTINFO
case AF_INET : {
struct sockaddr_in * sin ;
struct in_pktinfo pkt ;
if ( si - > bindname_len = = sizeof ( struct sockaddr_in ) ) {
sin = ( struct sockaddr_in * ) si - > bindname ;
} else {
if ( si - > myname_len ! = sizeof ( struct sockaddr_in ) ) {
return 0 ;
}
sin = ( struct sockaddr_in * ) si - > myname ;
}
ZERO_STRUCT ( pkt ) ;
pkt . ipi_ifindex = socket_wrapper_default_iface ( ) ;
pkt . ipi_addr . s_addr = sin - > sin_addr . s_addr ;
swrap_msghdr_add_cmsghdr ( msg , IPPROTO_IP , IP_PKTINFO ,
& pkt , sizeof ( pkt ) ) ;
break ;
}
# endif /* IP_PKTINFO */
# if defined(HAVE_IPV6)
case AF_INET6 : {
# if defined(IPV6_PKTINFO) && defined(HAVE_STRUCT_IN6_PKTINFO)
struct sockaddr_in6 * sin6 ;
struct in6_pktinfo pkt6 ;
if ( si - > bindname_len = = sizeof ( struct sockaddr_in6 ) ) {
sin6 = ( struct sockaddr_in6 * ) si - > bindname ;
} else {
if ( si - > myname_len ! = sizeof ( struct sockaddr_in6 ) ) {
return 0 ;
}
sin6 = ( struct sockaddr_in6 * ) si - > myname ;
}
ZERO_STRUCT ( pkt6 ) ;
pkt6 . ipi6_ifindex = socket_wrapper_default_iface ( ) ;
pkt6 . ipi6_addr = sin6 - > sin6_addr ;
swrap_msghdr_add_cmsghdr ( msg , IPPROTO_IPV6 , IPV6_PKTINFO ,
& pkt6 , sizeof ( pkt6 ) ) ;
# endif /* HAVE_STRUCT_IN6_PKTINFO */
break ;
}
# endif /* IPV6_PKTINFO */
default :
return - 1 ;
}
return 0 ;
}
2014-06-03 16:55:13 +04:00
# endif /* HAVE_STRUCT_MSGHDR_MSG_CONTROL */
2011-09-29 01:04:51 +04:00
static ssize_t swrap_sendmsg_before ( int fd ,
struct socket_info * si ,
2010-10-30 18:08:49 +04:00
struct msghdr * msg ,
struct iovec * tmp_iov ,
struct sockaddr_un * tmp_un ,
const struct sockaddr_un * * to_un ,
const struct sockaddr * * to ,
int * bcast )
{
size_t i , len = 0 ;
ssize_t ret ;
if ( to_un ) {
* to_un = NULL ;
}
if ( to ) {
* to = NULL ;
}
if ( bcast ) {
* bcast = 0 ;
}
switch ( si - > type ) {
case SOCK_STREAM :
if ( ! si - > connected ) {
errno = ENOTCONN ;
return - 1 ;
}
if ( msg - > msg_iovlen = = 0 ) {
break ;
}
2014-04-07 18:12:21 +04:00
for ( i = 0 ; i < ( size_t ) msg - > msg_iovlen ; i + + ) {
2010-10-30 18:08:49 +04:00
size_t nlen ;
nlen = len + msg - > msg_iov [ i ] . iov_len ;
2014-04-07 18:12:21 +04:00
if ( nlen > SOCKET_MAX_PACKET ) {
2010-10-30 18:08:49 +04:00
break ;
}
}
msg - > msg_iovlen = i ;
if ( msg - > msg_iovlen = = 0 ) {
* tmp_iov = msg - > msg_iov [ 0 ] ;
2014-04-07 18:12:21 +04:00
tmp_iov - > iov_len = MIN ( tmp_iov - > iov_len , SOCKET_MAX_PACKET ) ;
2010-10-30 18:08:49 +04:00
msg - > msg_iov = tmp_iov ;
msg - > msg_iovlen = 1 ;
}
break ;
case SOCK_DGRAM :
if ( si - > connected ) {
if ( msg - > msg_name ) {
errno = EISCONN ;
return - 1 ;
}
} else {
const struct sockaddr * msg_name ;
msg_name = ( const struct sockaddr * ) msg - > msg_name ;
if ( msg_name = = NULL ) {
errno = ENOTCONN ;
return - 1 ;
}
ret = sockaddr_convert_to_un ( si , msg_name , msg - > msg_namelen ,
tmp_un , 0 , bcast ) ;
if ( ret = = - 1 ) return - 1 ;
if ( to_un ) {
* to_un = tmp_un ;
}
if ( to ) {
* to = msg_name ;
}
msg - > msg_name = tmp_un ;
msg - > msg_namelen = sizeof ( * tmp_un ) ;
}
if ( si - > bound = = 0 ) {
2011-09-29 01:04:51 +04:00
ret = swrap_auto_bind ( fd , si , si - > family ) ;
2014-04-07 18:12:21 +04:00
if ( ret = = - 1 ) {
if ( errno = = ENOTSOCK ) {
swrap_remove_stale ( fd ) ;
return - ENOTSOCK ;
} else {
SWRAP_LOG ( SWRAP_LOG_ERROR , " swrap_sendmsg_before failed " ) ;
return - 1 ;
}
}
2010-10-30 18:08:49 +04:00
}
if ( ! si - > defer_connect ) {
break ;
}
ret = sockaddr_convert_to_un ( si , si - > peername , si - > peername_len ,
tmp_un , 0 , NULL ) ;
if ( ret = = - 1 ) return - 1 ;
2014-04-07 18:12:21 +04:00
ret = libc_connect ( fd ,
( struct sockaddr * ) ( void * ) tmp_un ,
2010-10-30 18:08:49 +04:00
sizeof ( * tmp_un ) ) ;
/* to give better errors */
if ( ret = = - 1 & & errno = = ENOENT ) {
errno = EHOSTUNREACH ;
}
if ( ret = = - 1 ) {
return ret ;
}
si - > defer_connect = 0 ;
break ;
default :
errno = EHOSTUNREACH ;
return - 1 ;
}
return 0 ;
}
2014-04-07 18:12:21 +04:00
static void swrap_sendmsg_after ( int fd ,
struct socket_info * si ,
2010-10-30 18:08:49 +04:00
struct msghdr * msg ,
const struct sockaddr * to ,
ssize_t ret )
{
int saved_errno = errno ;
size_t i , len = 0 ;
uint8_t * buf ;
off_t ofs = 0 ;
size_t avail = 0 ;
size_t remain ;
/* to give better errors */
2014-04-07 18:12:21 +04:00
if ( ret = = - 1 ) {
if ( saved_errno = = ENOENT ) {
saved_errno = EHOSTUNREACH ;
} else if ( saved_errno = = ENOTSOCK ) {
/* If the fd is not a socket, remove it */
swrap_remove_stale ( fd ) ;
}
2010-10-30 18:08:49 +04:00
}
2014-04-07 18:12:21 +04:00
for ( i = 0 ; i < ( size_t ) msg - > msg_iovlen ; i + + ) {
2010-10-30 18:08:49 +04:00
avail + = msg - > msg_iov [ i ] . iov_len ;
}
if ( ret = = - 1 ) {
remain = MIN ( 80 , avail ) ;
} else {
remain = ret ;
}
/* we capture it as one single packet */
buf = ( uint8_t * ) malloc ( remain ) ;
if ( ! buf ) {
/* we just not capture the packet */
errno = saved_errno ;
return ;
}
2014-04-07 18:12:21 +04:00
for ( i = 0 ; i < ( size_t ) msg - > msg_iovlen ; i + + ) {
size_t this_time = MIN ( remain , ( size_t ) msg - > msg_iov [ i ] . iov_len ) ;
2010-10-30 18:08:49 +04:00
memcpy ( buf + ofs ,
msg - > msg_iov [ i ] . iov_base ,
this_time ) ;
ofs + = this_time ;
remain - = this_time ;
}
len = ofs ;
switch ( si - > type ) {
case SOCK_STREAM :
2014-04-07 18:12:21 +04:00
if ( ret = = - 1 ) {
swrap_dump_packet ( si , NULL , SWRAP_SEND , buf , len ) ;
swrap_dump_packet ( si , NULL , SWRAP_SEND_RST , NULL , 0 ) ;
} else {
swrap_dump_packet ( si , NULL , SWRAP_SEND , buf , len ) ;
}
break ;
case SOCK_DGRAM :
if ( si - > connected ) {
to = si - > peername ;
}
if ( ret = = - 1 ) {
swrap_dump_packet ( si , to , SWRAP_SENDTO , buf , len ) ;
swrap_dump_packet ( si , to , SWRAP_SENDTO_UNREACH , buf , len ) ;
} else {
swrap_dump_packet ( si , to , SWRAP_SENDTO , buf , len ) ;
}
break ;
}
free ( buf ) ;
errno = saved_errno ;
}
static int swrap_recvmsg_before ( int fd ,
struct socket_info * si ,
struct msghdr * msg ,
struct iovec * tmp_iov )
{
size_t i , len = 0 ;
ssize_t ret ;
( void ) fd ; /* unused */
switch ( si - > type ) {
case SOCK_STREAM :
if ( ! si - > connected ) {
errno = ENOTCONN ;
return - 1 ;
}
if ( msg - > msg_iovlen = = 0 ) {
break ;
}
for ( i = 0 ; i < ( size_t ) msg - > msg_iovlen ; i + + ) {
size_t nlen ;
nlen = len + msg - > msg_iov [ i ] . iov_len ;
if ( nlen > SOCKET_MAX_PACKET ) {
break ;
}
}
msg - > msg_iovlen = i ;
if ( msg - > msg_iovlen = = 0 ) {
* tmp_iov = msg - > msg_iov [ 0 ] ;
tmp_iov - > iov_len = MIN ( tmp_iov - > iov_len , SOCKET_MAX_PACKET ) ;
msg - > msg_iov = tmp_iov ;
msg - > msg_iovlen = 1 ;
}
break ;
case SOCK_DGRAM :
if ( msg - > msg_name = = NULL ) {
errno = EINVAL ;
return - 1 ;
}
if ( msg - > msg_iovlen = = 0 ) {
break ;
}
if ( si - > bound = = 0 ) {
ret = swrap_auto_bind ( fd , si , si - > family ) ;
if ( ret = = - 1 ) {
/*
* When attempting to read or write to a
* descriptor , if an underlying autobind fails
* because it ' s not a socket , stop intercepting
* uses of that descriptor .
*/
if ( errno = = ENOTSOCK ) {
swrap_remove_stale ( fd ) ;
return - ENOTSOCK ;
} else {
SWRAP_LOG ( SWRAP_LOG_ERROR ,
" swrap_recvmsg_before failed " ) ;
return - 1 ;
}
}
}
break ;
default :
errno = EHOSTUNREACH ;
return - 1 ;
}
return 0 ;
}
static int swrap_recvmsg_after ( int fd ,
struct socket_info * si ,
struct msghdr * msg ,
const struct sockaddr_un * un_addr ,
socklen_t un_addrlen ,
ssize_t ret )
{
int saved_errno = errno ;
size_t i ;
2014-05-08 16:04:11 +04:00
uint8_t * buf = NULL ;
2014-04-07 18:12:21 +04:00
off_t ofs = 0 ;
size_t avail = 0 ;
size_t remain ;
/* to give better errors */
if ( ret = = - 1 ) {
if ( saved_errno = = ENOENT ) {
saved_errno = EHOSTUNREACH ;
} else if ( saved_errno = = ENOTSOCK ) {
/* If the fd is not a socket, remove it */
swrap_remove_stale ( fd ) ;
}
}
for ( i = 0 ; i < ( size_t ) msg - > msg_iovlen ; i + + ) {
avail + = msg - > msg_iov [ i ] . iov_len ;
}
if ( avail = = 0 ) {
errno = saved_errno ;
return 0 ;
}
if ( ret = = - 1 ) {
remain = MIN ( 80 , avail ) ;
} else {
remain = ret ;
}
/* we capture it as one single packet */
buf = ( uint8_t * ) malloc ( remain ) ;
2014-05-08 16:04:11 +04:00
if ( buf = = NULL ) {
2014-04-07 18:12:21 +04:00
/* we just not capture the packet */
errno = saved_errno ;
return - 1 ;
}
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 ) ;
ofs + = this_time ;
remain - = this_time ;
}
switch ( si - > type ) {
case SOCK_STREAM :
if ( ret = = - 1 & & saved_errno ! = EAGAIN & & saved_errno ! = ENOBUFS ) {
swrap_dump_packet ( si , NULL , SWRAP_RECV_RST , NULL , 0 ) ;
} else if ( ret = = 0 ) { /* END OF FILE */
swrap_dump_packet ( si , NULL , SWRAP_RECV_RST , NULL , 0 ) ;
} else if ( ret > 0 ) {
swrap_dump_packet ( si , NULL , SWRAP_RECV , buf , ret ) ;
2010-10-30 18:08:49 +04:00
}
break ;
case SOCK_DGRAM :
if ( ret = = - 1 ) {
2014-04-07 18:12:21 +04:00
break ;
}
if ( un_addr ! = NULL ) {
int rc ;
rc = sockaddr_convert_from_un ( si ,
un_addr ,
un_addrlen ,
si - > family ,
msg - > msg_name ,
& msg - > msg_namelen ) ;
if ( rc = = - 1 ) {
2014-05-08 16:04:11 +04:00
goto done ;
2014-04-07 18:12:21 +04:00
}
swrap_dump_packet ( si ,
msg - > msg_name ,
SWRAP_RECVFROM ,
buf ,
ret ) ;
2010-10-30 18:08:49 +04:00
} else {
2014-04-07 18:12:21 +04:00
swrap_dump_packet ( si ,
msg - > msg_name ,
SWRAP_RECV ,
buf ,
ret ) ;
2010-10-30 18:08:49 +04:00
}
2014-04-07 18:12:21 +04:00
2010-10-30 18:08:49 +04:00
break ;
}
2014-05-08 16:04:11 +04:00
done :
2010-10-30 18:08:49 +04:00
free ( buf ) ;
errno = saved_errno ;
2014-04-07 18:12:21 +04:00
return 0 ;
2010-10-30 18:08:49 +04:00
}
2014-04-07 18:12:21 +04:00
/****************************************************************************
* RECVFROM
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static ssize_t swrap_recvfrom ( int s , void * buf , size_t len , int flags ,
struct sockaddr * from , socklen_t * fromlen )
2005-03-28 05:00:39 +04:00
{
2014-04-07 18:12:21 +04:00
struct sockaddr_un from_addr ;
socklen_t from_addrlen = sizeof ( from_addr ) ;
ssize_t ret ;
2005-03-28 05:00:39 +04:00
struct socket_info * si = find_socket_info ( s ) ;
2009-03-08 19:19:50 +03:00
struct sockaddr_storage ss ;
socklen_t ss_len = sizeof ( ss ) ;
2014-04-07 18:12:21 +04:00
struct msghdr msg ;
struct iovec tmp ;
int tret ;
2005-03-28 05:00:39 +04:00
if ( ! si ) {
2014-04-07 18:12:21 +04:00
return libc_recvfrom ( s ,
buf ,
len ,
flags ,
from ,
fromlen ) ;
2005-03-28 05:00:39 +04:00
}
2014-04-07 18:12:21 +04:00
tmp . iov_base = buf ;
tmp . iov_len = len ;
ZERO_STRUCT ( msg ) ;
if ( from ! = NULL & & fromlen ! = NULL ) {
msg . msg_name = from ; /* optional address */
msg . msg_namelen = * fromlen ; /* size of address */
} else {
msg . msg_name = ( struct sockaddr * ) ( void * ) & ss ; /* optional address */
msg . msg_namelen = ss_len ; /* size of address */
2009-03-08 19:19:50 +03:00
}
2014-04-07 18:12:21 +04:00
msg . msg_iov = & tmp ; /* scatter/gather array */
msg . msg_iovlen = 1 ; /* # elements in msg_iov */
# 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
2009-03-08 19:19:50 +03:00
2014-04-07 18:12:21 +04:00
tret = swrap_recvmsg_before ( s , si , & msg , & tmp ) ;
if ( tret < 0 ) {
return - 1 ;
2009-06-19 07:25:28 +04:00
}
2008-06-10 10:33:24 +04:00
2014-04-07 18:12:21 +04:00
buf = msg . msg_iov [ 0 ] . iov_base ;
len = msg . msg_iov [ 0 ] . iov_len ;
2005-07-21 12:42:17 +04:00
/* irix 6.4 forgets to null terminate the sun_path string :-( */
2014-04-07 18:12:21 +04:00
memset ( & from_addr , 0 , sizeof ( from_addr ) ) ;
ret = libc_recvfrom ( s ,
buf ,
len ,
flags ,
( struct sockaddr * ) ( void * ) & from_addr ,
& from_addrlen ) ;
if ( ret = = - 1 ) {
2005-03-28 05:00:39 +04:00
return ret ;
2014-04-07 18:12:21 +04:00
}
2005-03-28 05:00:39 +04:00
2014-04-07 18:12:21 +04:00
tret = swrap_recvmsg_after ( s ,
si ,
& msg ,
& from_addr ,
from_addrlen ,
ret ) ;
if ( tret ! = 0 ) {
return tret ;
2005-03-31 16:40:12 +04:00
}
2006-09-12 10:19:11 +04:00
2014-04-07 18:12:21 +04:00
if ( from ! = NULL & & fromlen ! = NULL ) {
* fromlen = msg . msg_namelen ;
}
2006-09-12 10:19:11 +04:00
2005-03-28 05:00:39 +04:00
return ret ;
}
2014-04-07 18:12:21 +04:00
# ifdef HAVE_ACCEPT_PSOCKLEN_T
ssize_t recvfrom ( int s , void * buf , size_t len , int flags ,
struct sockaddr * from , Psocklen_t fromlen )
# else
ssize_t recvfrom ( int s , void * buf , size_t len , int flags ,
struct sockaddr * from , socklen_t * fromlen )
# endif
{
return swrap_recvfrom ( s , buf , len , flags , from , ( socklen_t * ) fromlen ) ;
}
/****************************************************************************
* SENDTO
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2005-06-10 16:21:46 +04:00
2014-04-07 18:12:21 +04:00
static ssize_t swrap_sendto ( int s , const void * buf , size_t len , int flags ,
const struct sockaddr * to , socklen_t tolen )
2005-03-28 05:00:39 +04:00
{
2010-10-30 18:23:49 +04:00
struct msghdr msg ;
struct iovec tmp ;
2005-03-28 05:00:39 +04:00
struct sockaddr_un un_addr ;
2010-10-30 18:23:49 +04:00
const struct sockaddr_un * to_un = NULL ;
ssize_t ret ;
2014-04-07 18:12:21 +04:00
int rc ;
2005-03-28 05:00:39 +04:00
struct socket_info * si = find_socket_info ( s ) ;
2005-11-07 18:36:51 +03:00
int bcast = 0 ;
2005-03-28 05:00:39 +04:00
if ( ! si ) {
2014-04-07 18:12:21 +04:00
return libc_sendto ( s , buf , len , flags , to , tolen ) ;
2005-03-28 05:00:39 +04:00
}
2010-10-30 18:23:49 +04:00
tmp . iov_base = discard_const_p ( char , buf ) ;
tmp . iov_len = len ;
2009-03-08 19:19:50 +03:00
2011-03-04 23:14:27 +03:00
ZERO_STRUCT ( msg ) ;
2010-10-30 18:23:49 +04:00
msg . msg_name = discard_const_p ( struct sockaddr , to ) ; /* optional address */
msg . msg_namelen = tolen ; /* size of address */
msg . msg_iov = & tmp ; /* scatter/gather array */
msg . msg_iovlen = 1 ; /* # elements in msg_iov */
2014-04-07 18:12:21 +04:00
# if HAVE_STRUCT_MSGHDR_MSG_CONTROL
2010-10-30 18:23:49 +04:00
msg . msg_control = NULL ; /* ancillary data, see below */
msg . msg_controllen = 0 ; /* ancillary data buffer len */
msg . msg_flags = 0 ; /* flags on received message */
2011-03-04 23:14:27 +03:00
# endif
2009-03-08 19:19:50 +03:00
2014-04-07 18:12:21 +04:00
rc = swrap_sendmsg_before ( s , si , & msg , & tmp , & un_addr , & to_un , & to , & bcast ) ;
if ( rc < 0 ) {
return - 1 ;
}
2011-02-12 14:18:16 +03:00
2010-10-30 18:23:49 +04:00
buf = msg . msg_iov [ 0 ] . iov_base ;
len = msg . msg_iov [ 0 ] . iov_len ;
2011-02-12 14:18:16 +03:00
2010-10-30 18:23:49 +04:00
if ( bcast ) {
struct stat st ;
unsigned int iface ;
unsigned int prt = ntohs ( ( ( const struct sockaddr_in * ) to ) - > sin_port ) ;
char type ;
2011-02-12 14:18:16 +03:00
2010-10-30 18:23:49 +04:00
type = SOCKET_TYPE_CHAR_UDP ;
2011-02-12 14:18:16 +03:00
2010-10-30 18:23:49 +04:00
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 ) ;
if ( stat ( un_addr . sun_path , & st ) ! = 0 ) continue ;
2011-02-12 14:18:16 +03:00
2010-10-30 18:23:49 +04:00
/* ignore the any errors in broadcast sends */
2014-04-07 18:12:21 +04:00
libc_sendto ( s ,
buf ,
len ,
flags ,
2010-10-30 18:23:49 +04:00
( struct sockaddr * ) ( void * ) & un_addr ,
sizeof ( un_addr ) ) ;
2005-11-07 18:36:51 +03:00
}
2009-03-23 11:16:18 +03:00
2010-10-30 18:23:49 +04:00
swrap_dump_packet ( si , to , SWRAP_SENDTO , buf , len ) ;
2009-03-23 11:16:18 +03:00
2010-10-30 18:23:49 +04:00
return len ;
2005-11-07 18:36:51 +03:00
}
2011-02-12 14:18:16 +03:00
2014-04-07 18:12:21 +04:00
ret = libc_sendto ( s ,
buf ,
len ,
flags ,
( struct sockaddr * ) msg . msg_name ,
2011-09-18 03:31:44 +04:00
msg . msg_namelen ) ;
2005-11-07 18:36:51 +03:00
2014-04-07 18:12:21 +04:00
swrap_sendmsg_after ( s , si , & msg , to , ret ) ;
2006-09-12 10:19:11 +04:00
2006-09-27 14:13:45 +04:00
return ret ;
}
2014-04-07 18:12:21 +04:00
ssize_t sendto ( int s , const void * buf , size_t len , int flags ,
const struct sockaddr * to , socklen_t tolen )
2006-09-12 10:19:11 +04:00
{
2014-04-07 18:12:21 +04:00
return swrap_sendto ( s , buf , len , flags , to , tolen ) ;
}
2006-09-12 10:19:11 +04:00
2014-04-07 18:12:21 +04:00
/****************************************************************************
* READV
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static ssize_t swrap_recv ( int s , void * buf , size_t len , int flags )
{
struct socket_info * si ;
struct msghdr msg ;
struct sockaddr_storage ss ;
socklen_t ss_len = sizeof ( ss ) ;
struct iovec tmp ;
ssize_t ret ;
int tret ;
si = find_socket_info ( s ) ;
if ( si = = NULL ) {
return libc_recv ( s , buf , len , flags ) ;
2006-09-12 10:19:11 +04:00
}
2014-04-07 18:12:21 +04:00
tmp . iov_base = buf ;
tmp . iov_len = len ;
ZERO_STRUCT ( msg ) ;
msg . msg_name = ( struct sockaddr * ) ( void * ) & ss ; /* optional address */
msg . msg_namelen = ss_len ; /* size of address */
msg . msg_iov = & tmp ; /* scatter/gather array */
msg . msg_iovlen = 1 ; /* # elements in msg_iov */
# 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
tret = swrap_recvmsg_before ( s , si , & msg , & tmp ) ;
if ( tret < 0 ) {
return - 1 ;
2009-06-19 07:25:28 +04:00
}
2008-06-10 10:33:24 +04:00
2014-04-07 18:12:21 +04:00
buf = msg . msg_iov [ 0 ] . iov_base ;
len = msg . msg_iov [ 0 ] . iov_len ;
ret = libc_recv ( s , buf , len , flags ) ;
tret = swrap_recvmsg_after ( s , si , & msg , NULL , 0 , ret ) ;
if ( tret ! = 0 ) {
return tret ;
2006-09-29 13:31:20 +04:00
}
2006-09-12 10:19:11 +04:00
return ret ;
}
2014-04-07 18:12:21 +04:00
ssize_t recv ( int s , void * buf , size_t len , int flags )
2009-09-08 07:31:01 +04:00
{
2014-04-07 18:12:21 +04:00
return swrap_recv ( s , buf , len , flags ) ;
}
2009-09-08 07:31:01 +04:00
2014-04-07 18:12:21 +04:00
/****************************************************************************
* READ
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static ssize_t swrap_read ( int s , void * buf , size_t len )
{
struct socket_info * si ;
struct msghdr msg ;
struct iovec tmp ;
struct sockaddr_storage ss ;
socklen_t ss_len = sizeof ( ss ) ;
ssize_t ret ;
int tret ;
si = find_socket_info ( s ) ;
if ( si = = NULL ) {
return libc_read ( s , buf , len ) ;
2009-09-08 07:31:01 +04:00
}
2014-04-07 18:12:21 +04:00
tmp . iov_base = buf ;
tmp . iov_len = len ;
ZERO_STRUCT ( msg ) ;
msg . msg_name = ( struct sockaddr * ) ( void * ) & ss ; /* optional address */
msg . msg_namelen = ss_len ; /* size of address */
msg . msg_iov = & tmp ; /* scatter/gather array */
msg . msg_iovlen = 1 ; /* # elements in msg_iov */
# 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
tret = swrap_recvmsg_before ( s , si , & msg , & tmp ) ;
if ( tret < 0 ) {
if ( tret = = - ENOTSOCK ) {
return libc_read ( s , buf , len ) ;
}
return - 1 ;
2009-09-08 07:31:01 +04:00
}
2014-04-07 18:12:21 +04:00
buf = msg . msg_iov [ 0 ] . iov_base ;
len = msg . msg_iov [ 0 ] . iov_len ;
ret = libc_read ( s , buf , len ) ;
tret = swrap_recvmsg_after ( s , si , & msg , NULL , 0 , ret ) ;
if ( tret ! = 0 ) {
return tret ;
2009-09-08 07:31:01 +04:00
}
return ret ;
}
2014-04-07 18:12:21 +04:00
ssize_t read ( int s , void * buf , size_t len )
{
return swrap_read ( s , buf , len ) ;
}
/****************************************************************************
* SEND
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2006-09-12 10:19:11 +04:00
2014-04-07 18:12:21 +04:00
static ssize_t swrap_send ( int s , const void * buf , size_t len , int flags )
2006-09-12 10:19:11 +04:00
{
2010-10-30 18:23:49 +04:00
struct msghdr msg ;
struct iovec tmp ;
struct sockaddr_un un_addr ;
ssize_t ret ;
2014-04-07 18:12:21 +04:00
int rc ;
2006-09-12 10:19:11 +04:00
struct socket_info * si = find_socket_info ( s ) ;
if ( ! si ) {
2014-04-07 18:12:21 +04:00
return libc_send ( s , buf , len , flags ) ;
2006-09-12 10:19:11 +04:00
}
2010-10-30 18:23:49 +04:00
tmp . iov_base = discard_const_p ( char , buf ) ;
tmp . iov_len = len ;
2009-03-23 11:16:18 +03:00
2011-03-04 23:14:27 +03:00
ZERO_STRUCT ( msg ) ;
2010-10-30 18:23:49 +04:00
msg . msg_name = NULL ; /* optional address */
msg . msg_namelen = 0 ; /* size of address */
msg . msg_iov = & tmp ; /* scatter/gather array */
msg . msg_iovlen = 1 ; /* # elements in msg_iov */
2014-04-07 18:12:21 +04:00
# if HAVE_STRUCT_MSGHDR_MSG_CONTROL
2010-10-30 18:23:49 +04:00
msg . msg_control = NULL ; /* ancillary data, see below */
msg . msg_controllen = 0 ; /* ancillary data buffer len */
msg . msg_flags = 0 ; /* flags on received message */
2011-03-04 23:14:27 +03:00
# endif
2009-03-23 11:16:18 +03:00
2014-04-07 18:12:21 +04:00
rc = swrap_sendmsg_before ( s , si , & msg , & tmp , & un_addr , NULL , NULL , NULL ) ;
if ( rc < 0 ) {
return - 1 ;
}
2009-03-23 11:16:18 +03:00
2010-10-30 18:23:49 +04:00
buf = msg . msg_iov [ 0 ] . iov_base ;
len = msg . msg_iov [ 0 ] . iov_len ;
2009-03-23 11:16:18 +03:00
2014-04-07 18:12:21 +04:00
ret = libc_send ( s , buf , len , flags ) ;
swrap_sendmsg_after ( s , si , & msg , NULL , ret ) ;
return ret ;
}
ssize_t send ( int s , const void * buf , size_t len , int flags )
{
return swrap_send ( s , buf , len , flags ) ;
}
/****************************************************************************
* RECVMSG
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static ssize_t swrap_recvmsg ( int s , struct msghdr * omsg , int flags )
{
struct sockaddr_un from_addr ;
socklen_t from_addrlen = sizeof ( from_addr ) ;
struct socket_info * si ;
struct msghdr msg ;
struct iovec tmp ;
ssize_t ret ;
int rc ;
si = find_socket_info ( s ) ;
if ( si = = NULL ) {
return libc_recvmsg ( s , omsg , flags ) ;
}
tmp . iov_base = NULL ;
tmp . iov_len = 0 ;
ZERO_STRUCT ( msg ) ;
msg . msg_name = ( struct sockaddr * ) & from_addr ; /* optional address */
msg . msg_namelen = from_addrlen ; /* size of address */
msg . msg_iov = omsg - > msg_iov ; /* scatter/gather array */
msg . msg_iovlen = omsg - > msg_iovlen ; /* # elements in msg_iov */
# ifdef HAVE_STRUCT_MSGHDR_MSG_CONTROL
msg . msg_control = omsg - > msg_control ; /* ancillary data, see below */
msg . msg_controllen = omsg - > msg_controllen ; /* ancillary data buffer len */
msg . msg_flags = omsg - > msg_flags ; /* flags on received message */
# endif
rc = swrap_recvmsg_before ( s , si , & msg , & tmp ) ;
if ( rc < 0 ) {
return - 1 ;
}
ret = libc_recvmsg ( s , & msg , flags ) ;
2006-09-12 10:19:11 +04:00
2014-04-07 18:12:21 +04:00
rc = swrap_recvmsg_after ( s , si , omsg , & from_addr , from_addrlen , ret ) ;
if ( rc ! = 0 ) {
return rc ;
}
2006-09-12 10:19:11 +04:00
2005-03-28 05:00:39 +04:00
return ret ;
}
2014-04-07 18:12:21 +04:00
ssize_t recvmsg ( int sockfd , struct msghdr * msg , int flags )
{
return swrap_recvmsg ( sockfd , msg , flags ) ;
}
/****************************************************************************
* SENDMSG
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static ssize_t swrap_sendmsg ( int s , const struct msghdr * omsg , int flags )
2009-05-26 05:43:37 +04:00
{
2010-10-30 18:23:49 +04:00
struct msghdr msg ;
struct iovec tmp ;
struct sockaddr_un un_addr ;
const struct sockaddr_un * to_un = NULL ;
const struct sockaddr * to = NULL ;
ssize_t ret ;
2014-04-07 18:12:21 +04:00
int rc ;
2009-05-26 05:43:37 +04:00
struct socket_info * si = find_socket_info ( s ) ;
2010-10-30 18:23:49 +04:00
int bcast = 0 ;
2009-05-26 05:43:37 +04:00
if ( ! si ) {
2014-04-07 18:12:21 +04:00
return libc_sendmsg ( s , omsg , flags ) ;
2009-05-26 05:43:37 +04:00
}
2014-04-07 18:12:21 +04:00
ZERO_STRUCT ( un_addr ) ;
2010-10-30 18:23:49 +04:00
tmp . iov_base = NULL ;
tmp . iov_len = 0 ;
2009-05-26 05:43:37 +04:00
2014-04-07 18:12:21 +04:00
ZERO_STRUCT ( msg ) ;
2010-10-30 18:23:49 +04:00
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 */
2014-04-07 18:12:21 +04:00
# ifdef HAVE_STRUCT_MSGHDR_MSG_CONTROL
2010-10-30 18:23:49 +04:00
msg . msg_control = omsg - > msg_control ; /* ancillary data, see below */
msg . msg_controllen = omsg - > msg_controllen ; /* ancillary data buffer len */
msg . msg_flags = omsg - > msg_flags ; /* flags on received message */
2011-03-04 23:14:27 +03:00
# endif
2010-10-30 18:23:49 +04:00
2014-04-07 18:12:21 +04:00
rc = swrap_sendmsg_before ( s , si , & msg , & tmp , & un_addr , & to_un , & to , & bcast ) ;
if ( rc < 0 ) {
return - 1 ;
}
2010-10-30 18:23:49 +04:00
if ( bcast ) {
struct stat st ;
unsigned int iface ;
unsigned int prt = ntohs ( ( ( const struct sockaddr_in * ) to ) - > sin_port ) ;
char type ;
size_t i , len = 0 ;
uint8_t * buf ;
off_t ofs = 0 ;
size_t avail = 0 ;
size_t remain ;
2014-04-07 18:12:21 +04:00
for ( i = 0 ; i < ( size_t ) msg . msg_iovlen ; i + + ) {
2010-10-30 18:23:49 +04:00
avail + = msg . msg_iov [ i ] . iov_len ;
2009-05-26 05:43:37 +04:00
}
2010-10-30 18:23:49 +04:00
len = avail ;
remain = avail ;
2009-05-26 05:43:37 +04:00
2010-10-30 18:23:49 +04:00
/* we capture it as one single packet */
buf = ( uint8_t * ) malloc ( remain ) ;
if ( ! buf ) {
return - 1 ;
}
2009-05-26 05:43:37 +04:00
2014-04-07 18:12:21 +04:00
for ( i = 0 ; i < ( size_t ) msg . msg_iovlen ; i + + ) {
size_t this_time = MIN ( remain , ( size_t ) msg . msg_iov [ i ] . iov_len ) ;
2010-10-30 18:23:49 +04:00
memcpy ( buf + ofs ,
msg . msg_iov [ i ] . iov_base ,
this_time ) ;
ofs + = this_time ;
remain - = this_time ;
2009-05-26 05:43:37 +04:00
}
2010-10-30 18:23:49 +04:00
type = SOCKET_TYPE_CHAR_UDP ;
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 ) ;
if ( stat ( un_addr . sun_path , & st ) ! = 0 ) continue ;
msg . msg_name = & un_addr ; /* optional address */
msg . msg_namelen = sizeof ( un_addr ) ; /* size of address */
/* ignore the any errors in broadcast sends */
2014-04-07 18:12:21 +04:00
libc_sendmsg ( s , & msg , flags ) ;
2009-05-26 05:43:37 +04:00
}
2010-10-30 18:23:49 +04:00
swrap_dump_packet ( si , to , SWRAP_SENDTO , buf , len ) ;
free ( buf ) ;
2011-02-12 14:18:16 +03:00
2010-10-30 18:23:49 +04:00
return len ;
2009-05-26 05:43:37 +04:00
}
2011-02-12 14:18:16 +03:00
2014-04-07 18:12:21 +04:00
ret = libc_sendmsg ( s , & msg , flags ) ;
2011-02-12 14:18:16 +03:00
2014-04-07 18:12:21 +04:00
swrap_sendmsg_after ( s , si , & msg , to , ret ) ;
2009-05-26 05:43:37 +04:00
return ret ;
}
2014-04-07 18:12:21 +04:00
ssize_t sendmsg ( int s , const struct msghdr * omsg , int flags )
2009-03-09 19:48:08 +03:00
{
2014-04-07 18:12:21 +04:00
return swrap_sendmsg ( s , omsg , flags ) ;
}
2009-03-09 19:48:08 +03:00
2014-04-07 18:12:21 +04:00
/****************************************************************************
* READV
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2010-10-30 18:28:23 +04:00
2014-04-07 18:12:21 +04:00
static ssize_t swrap_readv ( int s , const struct iovec * vector , int count )
{
struct socket_info * si ;
struct msghdr msg ;
struct iovec tmp ;
struct sockaddr_storage ss ;
socklen_t ss_len = sizeof ( ss ) ;
ssize_t ret ;
int rc ;
2011-02-12 14:18:16 +03:00
2014-04-07 18:12:21 +04:00
si = find_socket_info ( s ) ;
if ( si = = NULL ) {
return libc_readv ( s , vector , count ) ;
2009-03-09 19:48:08 +03:00
}
2014-04-07 18:12:21 +04:00
tmp . iov_base = NULL ;
tmp . iov_len = 0 ;
2009-03-09 19:48:08 +03:00
2014-04-07 18:12:21 +04:00
ZERO_STRUCT ( msg ) ;
msg . msg_name = ( struct sockaddr * ) ( void * ) & ss ; /* optional address */
msg . msg_namelen = ss_len ; /* size of address */
msg . msg_iov = discard_const_p ( struct iovec , vector ) ; /* scatter/gather array */
msg . msg_iovlen = count ; /* # elements in msg_iov */
# 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
2009-03-09 19:48:08 +03:00
2014-04-07 18:12:21 +04:00
rc = swrap_recvmsg_before ( s , si , & msg , & tmp ) ;
if ( rc < 0 ) {
if ( rc = = - ENOTSOCK ) {
return libc_readv ( s , vector , count ) ;
2009-03-09 19:48:08 +03:00
}
2014-04-07 18:12:21 +04:00
return - 1 ;
}
2009-03-09 19:48:08 +03:00
2014-04-07 18:12:21 +04:00
ret = libc_readv ( s , msg . msg_iov , msg . msg_iovlen ) ;
rc = swrap_recvmsg_after ( s , si , & msg , NULL , 0 , ret ) ;
if ( rc ! = 0 ) {
return rc ;
2009-03-09 19:48:08 +03:00
}
return ret ;
}
2014-04-07 18:12:21 +04:00
ssize_t readv ( int s , const struct iovec * vector , int count )
{
return swrap_readv ( s , vector , count ) ;
}
/****************************************************************************
* WRITEV
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static ssize_t swrap_writev ( int s , const struct iovec * vector , int count )
2009-03-09 19:48:08 +03:00
{
2010-10-30 18:23:49 +04:00
struct msghdr msg ;
struct iovec tmp ;
struct sockaddr_un un_addr ;
ssize_t ret ;
2014-04-07 18:12:21 +04:00
int rc ;
2009-03-09 19:48:08 +03:00
struct socket_info * si = find_socket_info ( s ) ;
if ( ! si ) {
2014-04-07 18:12:21 +04:00
return libc_writev ( s , vector , count ) ;
2009-03-09 19:48:08 +03:00
}
2010-10-30 18:23:49 +04:00
tmp . iov_base = NULL ;
tmp . iov_len = 0 ;
2009-03-09 19:48:08 +03:00
2011-03-04 23:14:27 +03:00
ZERO_STRUCT ( msg ) ;
2010-10-30 18:23:49 +04:00
msg . msg_name = NULL ; /* optional address */
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 */
2014-04-07 18:12:21 +04:00
# if HAVE_STRUCT_MSGHDR_MSG_CONTROL
2010-10-30 18:23:49 +04:00
msg . msg_control = NULL ; /* ancillary data, see below */
msg . msg_controllen = 0 ; /* ancillary data buffer len */
msg . msg_flags = 0 ; /* flags on received message */
2011-03-04 23:14:27 +03:00
# endif
2009-03-09 19:48:08 +03:00
2014-04-07 18:12:21 +04:00
rc = swrap_sendmsg_before ( s , si , & msg , & tmp , & un_addr , NULL , NULL , NULL ) ;
if ( rc < 0 ) {
if ( rc = = - ENOTSOCK ) {
return libc_readv ( s , vector , count ) ;
}
return - 1 ;
}
2009-03-09 19:48:08 +03:00
2014-04-07 18:12:21 +04:00
ret = libc_writev ( s , msg . msg_iov , msg . msg_iovlen ) ;
2009-03-09 19:48:08 +03:00
2014-04-07 18:12:21 +04:00
swrap_sendmsg_after ( s , si , & msg , NULL , ret ) ;
2009-03-09 19:48:08 +03:00
return ret ;
}
2014-04-07 18:12:21 +04:00
ssize_t writev ( int s , const struct iovec * vector , int count )
{
return swrap_writev ( s , vector , count ) ;
}
/****************************
* CLOSE
* * * * * * * * * * * * * * * * * * * * * * * * * * */
static int swrap_close ( int fd )
2005-03-28 05:00:39 +04:00
{
struct socket_info * si = find_socket_info ( fd ) ;
2011-09-29 01:09:49 +04:00
struct socket_info_fd * fi ;
2006-09-26 17:15:31 +04:00
int ret ;
if ( ! si ) {
2014-04-07 18:12:21 +04:00
return libc_close ( fd ) ;
2006-09-26 17:15:31 +04:00
}
2005-03-28 05:00:39 +04:00
2011-09-29 01:09:49 +04:00
for ( fi = si - > fds ; fi ; fi = fi - > next ) {
if ( fi - > fd = = fd ) {
SWRAP_DLIST_REMOVE ( si - > fds , fi ) ;
free ( fi ) ;
break ;
}
}
if ( si - > fds ) {
/* there are still references left */
2014-04-07 18:12:21 +04:00
return libc_close ( fd ) ;
2011-09-29 01:09:49 +04:00
}
2006-10-09 01:53:09 +04:00
SWRAP_DLIST_REMOVE ( sockets , si ) ;
2005-03-28 05:00:39 +04:00
2006-09-29 13:31:20 +04:00
if ( si - > myname & & si - > peername ) {
swrap_dump_packet ( si , NULL , SWRAP_CLOSE_SEND , NULL , 0 ) ;
}
2014-04-07 18:12:21 +04:00
ret = libc_close ( fd ) ;
2006-09-12 13:08:55 +04:00
2006-09-29 13:31:20 +04:00
if ( si - > myname & & si - > peername ) {
swrap_dump_packet ( si , NULL , SWRAP_CLOSE_RECV , NULL , 0 ) ;
swrap_dump_packet ( si , NULL , SWRAP_CLOSE_ACK , NULL , 0 ) ;
}
2014-06-03 16:50:53 +04:00
if ( si - > bindname ! = NULL ) {
free ( si - > bindname ) ;
}
2006-09-29 13:31:20 +04:00
if ( si - > myname ) free ( si - > myname ) ;
if ( si - > peername ) free ( si - > peername ) ;
2006-09-26 17:15:31 +04:00
if ( si - > tmp_path ) {
unlink ( si - > tmp_path ) ;
free ( si - > tmp_path ) ;
2005-03-28 05:00:39 +04:00
}
2006-09-26 17:15:31 +04:00
free ( si ) ;
2005-03-28 05:00:39 +04:00
2006-09-26 17:15:31 +04:00
return ret ;
2005-03-28 05:00:39 +04:00
}
2011-08-12 08:28:03 +04:00
2014-04-07 18:12:21 +04:00
int close ( int fd )
{
return swrap_close ( fd ) ;
}
/****************************
* DUP
* * * * * * * * * * * * * * * * * * * * * * * * * * */
static int swrap_dup ( int fd )
2011-08-12 08:28:03 +04:00
{
2011-09-29 01:09:49 +04:00
struct socket_info * si ;
struct socket_info_fd * fi ;
2011-08-12 08:28:03 +04:00
si = find_socket_info ( fd ) ;
if ( ! si ) {
2014-04-07 18:12:21 +04:00
return libc_dup ( fd ) ;
2011-08-12 08:28:03 +04:00
}
2011-09-29 01:09:49 +04:00
fi = ( struct socket_info_fd * ) calloc ( 1 , sizeof ( struct socket_info_fd ) ) ;
if ( fi = = NULL ) {
2011-08-12 08:28:03 +04:00
errno = ENOMEM ;
return - 1 ;
}
2014-04-07 18:12:21 +04:00
fi - > fd = libc_dup ( fd ) ;
2011-09-29 01:09:49 +04:00
if ( fi - > fd = = - 1 ) {
int saved_errno = errno ;
free ( fi ) ;
errno = saved_errno ;
return - 1 ;
2011-08-12 08:28:03 +04:00
}
2014-04-07 18:12:21 +04:00
/* Make sure we don't have an entry for the fd */
swrap_remove_stale ( fi - > fd ) ;
2011-09-29 01:09:49 +04:00
SWRAP_DLIST_ADD ( si - > fds , fi ) ;
return fi - > fd ;
2011-08-12 08:28:03 +04:00
}
2014-04-07 18:12:21 +04:00
int dup ( int fd )
{
return swrap_dup ( fd ) ;
}
/****************************
* DUP2
* * * * * * * * * * * * * * * * * * * * * * * * * * */
static int swrap_dup2 ( int fd , int newfd )
2011-08-12 08:28:03 +04:00
{
2011-09-29 01:09:49 +04:00
struct socket_info * si ;
struct socket_info_fd * fi ;
2011-08-12 08:28:03 +04:00
si = find_socket_info ( fd ) ;
if ( ! si ) {
2014-04-07 18:12:21 +04:00
return libc_dup2 ( fd , newfd ) ;
2011-08-12 08:28:03 +04:00
}
if ( find_socket_info ( newfd ) ) {
/* dup2() does an implicit close of newfd, which we
* need to emulate */
swrap_close ( newfd ) ;
}
2011-09-29 01:09:49 +04:00
fi = ( struct socket_info_fd * ) calloc ( 1 , sizeof ( struct socket_info_fd ) ) ;
if ( fi = = NULL ) {
2011-08-12 08:28:03 +04:00
errno = ENOMEM ;
return - 1 ;
}
2014-04-07 18:12:21 +04:00
fi - > fd = libc_dup2 ( fd , newfd ) ;
2011-09-29 01:09:49 +04:00
if ( fi - > fd = = - 1 ) {
int saved_errno = errno ;
free ( fi ) ;
errno = saved_errno ;
return - 1 ;
2011-08-12 08:28:03 +04:00
}
2014-04-07 18:12:21 +04:00
/* Make sure we don't have an entry for the fd */
swrap_remove_stale ( fi - > fd ) ;
2011-09-29 01:09:49 +04:00
SWRAP_DLIST_ADD ( si - > fds , fi ) ;
return fi - > fd ;
2011-08-12 08:28:03 +04:00
}
2014-04-07 18:12:21 +04:00
int dup2 ( int fd , int newfd )
{
return swrap_dup2 ( fd , newfd ) ;
}
/****************************
* DUP2
* * * * * * * * * * * * * * * * * * * * * * * * * * */
# ifdef HAVE_EVENTFD
static int swrap_eventfd ( int count , int flags )
{
int fd ;
fd = libc_eventfd ( count , flags ) ;
if ( fd ! = - 1 ) {
swrap_remove_stale ( fd ) ;
}
return fd ;
}
int eventfd ( int count , int flags )
{
return swrap_eventfd ( count , flags ) ;
}
# endif
/****************************
* DESTRUCTOR
* * * * * * * * * * * * * * * * * * * * * * * * * * */
/*
* This function is called when the library is unloaded and makes sure that
* sockets get closed and the unix file for the socket are unlinked .
*/
void swrap_destructor ( void )
{
struct socket_info * s = sockets ;
while ( s ! = NULL ) {
struct socket_info_fd * f = s - > fds ;
if ( f ! = NULL ) {
swrap_close ( f - > fd ) ;
}
s = sockets ;
}
}