2006-10-09 00:48:34 +04:00
/*
2014-10-02 09:20:15 +04:00
* Copyright ( c ) 2005 - 2008 Jelmer Vernooij < jelmer @ samba . org >
* Copyright ( C ) 2006 - 2014 Stefan Metzmacher < metze @ samba . org >
* Copyright ( C ) 2013 - 2014 Andreas Schneider < asn @ samba . org >
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
2014-06-03 17:11:46 +04:00
# ifdef HAVE_RPC_RPC_H
# include <rpc/rpc.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-06-03 17:10:19 +04:00
# ifndef ZERO_STRUCTP
# define ZERO_STRUCTP(x) do { \
if ( ( x ) ! = NULL ) \
memset ( ( char * ) ( x ) , 0 , sizeof ( * ( x ) ) ) ; \
} while ( 0 )
# endif
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 */
2014-06-03 17:02:17 +04:00
/*
* On BSD IP_PKTINFO has a different name because during
* the time when they implemented it , there was no RFC .
* The name for IPv6 is the same as on Linux .
*/
# ifndef IP_PKTINFO
# ifdef IP_RECVDSTADDR
# define IP_PKTINFO IP_RECVDSTADDR
# endif
# endif
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-10-02 09:09:33 +04:00
struct swrap_address {
socklen_t sa_socklen ;
union {
struct sockaddr s ;
struct sockaddr_in in ;
# ifdef HAVE_IPV6
struct sockaddr_in6 in6 ;
# endif
struct sockaddr_un un ;
struct sockaddr_storage ss ;
} sa ;
} ;
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
2014-10-02 09:16:25 +04:00
/* The unix path so we can unlink it on close() */
struct sockaddr_un un_addr ;
2014-04-07 18:12:21 +04:00
2014-10-02 09:17:10 +04:00
struct swrap_address bindname ;
struct swrap_address myname ;
struct swrap_address peername ;
2014-04-07 18:12:21 +04:00
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 ) ;
2014-10-02 09:18:48 +04:00
FILE * ( * libc_fopen ) ( const char * name , const char * mode ) ;
2014-04-07 18:12:21 +04:00
# 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 ) ;
2014-06-03 16:59:21 +04:00
swrap . libc_handle = handle ;
2014-06-03 16:50:05 +04:00
}
# 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 ) ;
}
2014-10-02 09:18:48 +04:00
static FILE * libc_fopen ( const char * name , const char * mode )
{
swrap_load_lib_function ( SWRAP_LIBC , fopen ) ;
return swrap . fns . libc_fopen ( name , mode ) ;
}
2014-04-07 18:12:21 +04:00
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
2014-10-02 09:17:10 +04:00
static void set_port ( int family , int prt , struct swrap_address * addr )
2007-04-16 08:59:47 +04:00
{
switch ( family ) {
case AF_INET :
2014-10-02 09:17:10 +04:00
addr - > sa . in . sin_port = htons ( prt ) ;
2007-04-16 08:59:47 +04:00
break ;
# ifdef HAVE_IPV6
case AF_INET6 :
2014-10-02 09:17:10 +04:00
addr - > sa . in6 . sin6_port = htons ( prt ) ;
2007-04-16 08:59:47 +04:00
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 ;
}
2014-06-03 17:12:34 +04:00
/* TODO use realpath(3) here, when we add support for threads */
2005-07-21 17:45:07 +04:00
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 : {
2014-10-02 09:20:53 +04:00
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 : {
2014-10-02 09:20:53 +04:00
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 ) {
2014-10-02 09:20:53 +04:00
snprintf ( un - > sun_path , sizeof ( un - > sun_path ) , " %s/EINVAL " ,
2005-11-07 18:36:51 +03:00
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 ;
}
2014-10-02 09:20:53 +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-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 : {
2014-10-02 09:20:53 +04:00
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() */
2014-10-02 09:17:10 +04:00
if ( si - > bindname . sa_socklen = = 0 ) {
2014-06-03 16:50:53 +04:00
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 ) ;
2014-10-02 09:17:10 +04:00
si - > bindname . sa_socklen = blen ;
memcpy ( & si - > bindname . sa . in , & bind_in , blen ) ;
2014-06-03 16:50:53 +04:00
}
2005-11-07 18:36:51 +03:00
break ;
}
2007-04-16 08:59:47 +04:00
# ifdef HAVE_IPV6
case AF_INET6 : {
2014-10-02 09:20:53 +04:00
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() */
2014-10-02 09:17:10 +04:00
if ( si - > bindname . sa_socklen = = 0 ) {
2014-06-03 16:50:53 +04:00
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 ;
2014-10-02 09:17:10 +04:00
memcpy ( & si - > bindname . sa . in6 , & bind_in , blen ) ;
si - > bindname . sa_socklen = blen ;
2014-06-03 16:50:53 +04:00
}
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 + + ) {
2014-10-02 09:20:53 +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 ;
2014-10-02 09:17:10 +04:00
set_port ( si - > family , prt , & si - > myname ) ;
set_port ( si - > family , prt , & si - > bindname ) ;
2014-06-03 16:50:53 +04:00
2007-04-16 08:59:47 +04:00
break ;
}
if ( prt = = 10000 ) {
errno = ENFILE ;
return - 1 ;
2005-11-07 18:36:51 +03:00
}
}
2014-10-02 09:20:53 +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-06-06 01:38:59 +04:00
#if 0 /* FIXME */
2014-06-03 17:13:59 +04:00
static bool check_addr_port_in_use ( const struct sockaddr * sa , socklen_t len )
{
struct socket_info * s ;
/* first catch invalid input */
switch ( sa - > sa_family ) {
case AF_INET :
if ( len < sizeof ( struct sockaddr_in ) ) {
return false ;
}
break ;
# if HAVE_IPV6
case AF_INET6 :
if ( len < sizeof ( struct sockaddr_in6 ) ) {
return false ;
}
break ;
# endif
default :
return false ;
break ;
}
for ( s = sockets ; s ! = NULL ; s = s - > next ) {
if ( s - > myname = = NULL ) {
continue ;
}
if ( s - > myname - > sa_family ! = sa - > sa_family ) {
continue ;
}
switch ( s - > myname - > sa_family ) {
case AF_INET : {
struct sockaddr_in * sin1 , * sin2 ;
sin1 = ( struct sockaddr_in * ) s - > myname ;
sin2 = ( struct sockaddr_in * ) sa ;
if ( sin1 - > sin_addr . s_addr = = htonl ( INADDR_ANY ) ) {
continue ;
}
if ( sin1 - > sin_port ! = sin2 - > sin_port ) {
continue ;
}
if ( sin1 - > sin_addr . s_addr ! = sin2 - > sin_addr . s_addr ) {
continue ;
}
/* found */
return true ;
break ;
}
# if HAVE_IPV6
case AF_INET6 : {
struct sockaddr_in6 * sin1 , * sin2 ;
sin1 = ( struct sockaddr_in6 * ) s - > myname ;
sin2 = ( struct sockaddr_in6 * ) sa ;
if ( sin1 - > sin6_port ! = sin2 - > sin6_port ) {
continue ;
}
if ( ! IN6_ARE_ADDR_EQUAL ( & sin1 - > sin6_addr ,
& sin2 - > sin6_addr ) )
{
continue ;
}
/* found */
return true ;
break ;
}
# endif
default :
continue ;
break ;
}
}
return false ;
}
2014-06-06 01:38:59 +04:00
# endif
2014-06-03 17:13:59 +04:00
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 ) {
2014-06-03 17:13:02 +04:00
case AF_UNSPEC : {
2014-10-02 09:01:34 +04:00
const struct sockaddr_in * sin ;
2014-06-03 17:13:02 +04:00
if ( si - > family ! = AF_INET ) {
break ;
}
if ( in_len < sizeof ( struct sockaddr_in ) ) {
break ;
}
2014-10-02 09:01:34 +04:00
sin = ( const struct sockaddr_in * ) in_addr ;
2014-06-03 17:13:02 +04:00
if ( sin - > sin_addr . s_addr ! = htonl ( INADDR_ANY ) ) {
break ;
}
/*
* Note : in the special case of AF_UNSPEC and INADDR_ANY ,
* AF_UNSPEC is mapped to AF_INET and must be treated here .
*/
/* FALL THROUGH */
}
2005-03-28 05:00:39 +04:00
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 ;
}
2014-10-02 09:20:53 +04:00
static int sockaddr_convert_from_un ( const struct socket_info * si ,
const struct sockaddr_un * in_addr ,
2005-03-31 16:40:12 +04:00
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 ;
2014-10-02 09:20:53 +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
2014-10-02 09:11:49 +04:00
static const char * swrap_pcap_init_file ( void )
2006-10-05 15:39:59 +04:00
{
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 ( )
2014-10-02 09:20:53 +04:00
*
2006-10-05 15:39:59 +04:00
* 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 ;
}
2014-10-02 09:13:10 +04:00
static uint8_t * swrap_pcap_packet_init ( struct timeval * tval ,
const struct sockaddr * src ,
const struct sockaddr * dest ,
int socket_type ,
const uint8_t * payload ,
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
}
2014-10-02 09:14:44 +04:00
static int swrap_pcap_get_fd ( const char * fname )
2006-10-05 15:39:59 +04:00
{
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 ;
}
2014-10-02 09:14:04 +04:00
static uint8_t * swrap_pcap_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
2014-10-02 09:17:10 +04:00
src_addr = & si - > myname . sa . s ;
2009-03-03 17:17:26 +03:00
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
2014-10-02 09:17:10 +04:00
dest_addr = & si - > myname . sa . s ;
2009-03-03 17:17:26 +03:00
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
2014-10-02 09:17:10 +04:00
dest_addr = & si - > myname . sa . s ;
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
2014-10-02 09:17:10 +04:00
src_addr = & si - > myname . sa . s ;
2009-03-03 17:17:26 +03:00
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
2014-10-02 09:17:10 +04:00
dest_addr = & si - > myname . sa . s ;
2009-03-03 17:17:26 +03:00
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
2014-10-02 09:17:10 +04:00
src_addr = & si - > myname . sa . s ;
2009-03-03 17:17:26 +03:00
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
2014-10-02 09:17:10 +04:00
dest_addr = & si - > myname . sa . s ;
2009-03-03 17:17:26 +03:00
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 :
2014-10-02 09:17:10 +04:00
src_addr = & si - > myname . sa . s ;
dest_addr = & si - > peername . sa . s ;
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 :
2014-10-02 09:17:10 +04:00
dest_addr = & si - > myname . sa . s ;
src_addr = & si - > peername . sa . s ;
2006-10-05 10:27:41 +04:00
if ( si - > type = = SOCK_DGRAM ) {
2014-10-02 09:17:10 +04:00
return swrap_pcap_marshall_packet ( si ,
& si - > peername . sa . s ,
SWRAP_SENDTO_UNREACH ,
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 :
2014-10-02 09:17:10 +04:00
dest_addr = & si - > myname . sa . s ;
src_addr = & si - > peername . sa . s ;
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 :
2014-10-02 09:17:10 +04:00
dest_addr = & si - > myname . sa . s ;
src_addr = & si - > peername . sa . s ;
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 :
2014-10-02 09:17:10 +04:00
dest_addr = & si - > myname . sa . s ;
src_addr = & si - > peername . sa . s ;
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 :
2014-10-02 09:17:10 +04:00
src_addr = & si - > myname . sa . s ;
2009-03-03 17:17:26 +03:00
dest_addr = addr ;
2006-10-05 10:27:41 +04:00
si - > io . pck_snd + = len ;
break ;
case SWRAP_SENDTO_UNREACH :
2014-10-02 09:17:10 +04:00
dest_addr = & si - > myname . sa . s ;
2009-03-03 17:17:26 +03:00
src_addr = addr ;
2006-10-05 10:27:41 +04:00
unreachable = 1 ;
break ;
case SWRAP_RECVFROM :
2014-10-02 09:17:10 +04:00
dest_addr = & si - > myname . sa . s ;
2009-03-03 17:17:26 +03:00
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
2014-10-02 09:17:10 +04:00
src_addr = & si - > myname . sa . s ;
dest_addr = & si - > peername . sa . s ;
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
2014-10-02 09:17:10 +04:00
dest_addr = & si - > myname . sa . s ;
src_addr = & si - > peername . sa . s ;
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
2014-10-02 09:17:10 +04:00
src_addr = & si - > myname . sa . s ;
dest_addr = & si - > peername . sa . s ;
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 ) ;
2014-10-02 09:13:10 +04:00
return swrap_pcap_packet_init ( & tv ,
src_addr ,
dest_addr ,
si - > type ,
( const uint8_t * ) buf ,
len ,
tcp_seqno ,
tcp_ack ,
tcp_ctl ,
unreachable ,
packet_len ) ;
2008-02-20 01:53:04 +03:00
}
2014-10-02 09:15:38 +04:00
static void swrap_pcap_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 ;
2014-10-02 09:11:49 +04:00
file_name = swrap_pcap_init_file ( ) ;
2008-02-20 01:53:04 +03:00
if ( ! file_name ) {
return ;
}
2014-10-02 09:14:04 +04:00
packet = swrap_pcap_marshall_packet ( si ,
addr ,
type ,
buf ,
len ,
& packet_len ) ;
if ( packet = = NULL ) {
2006-10-05 15:39:59 +04:00
return ;
}
2014-10-02 09:14:44 +04:00
fd = swrap_pcap_get_fd ( file_name ) ;
2006-10-05 15:39:59 +04:00
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 ;
2014-06-03 17:08:07 +04:00
/*
* Setup myname so getsockname ( ) can succeed to find out the socket
* type .
*/
switch ( si - > family ) {
case AF_INET : {
struct sockaddr_in sin = {
. sin_family = AF_INET ,
} ;
2014-10-02 09:17:10 +04:00
si - > myname . sa_socklen = sizeof ( struct sockaddr_in ) ;
memcpy ( & si - > myname . sa . in , & sin , si - > myname . sa_socklen ) ;
2014-06-03 17:08:07 +04:00
break ;
}
case AF_INET6 : {
struct sockaddr_in6 sin6 = {
. sin6_family = AF_INET6 ,
} ;
2014-10-02 09:17:10 +04:00
si - > myname . sa_socklen = sizeof ( struct sockaddr_in6 ) ;
memcpy ( & si - > myname . sa . in6 , & sin6 , si - > myname . sa_socklen ) ;
2014-06-03 17:08:07 +04:00
break ;
}
default :
free ( si ) ;
errno = EINVAL ;
return - 1 ;
}
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 ;
2014-10-02 09:09:33 +04:00
struct swrap_address un_addr = {
. sa_socklen = sizeof ( struct sockaddr_un ) ,
} ;
struct swrap_address un_my_addr = {
. sa_socklen = sizeof ( struct sockaddr_un ) ,
} ;
2014-10-02 09:18:14 +04:00
struct swrap_address in_addr = {
. sa_socklen = sizeof ( struct sockaddr_storage ) ,
} ;
struct swrap_address in_my_addr = {
. sa_socklen = sizeof ( struct sockaddr_storage ) ,
} ;
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
}
2014-10-02 09:20:53 +04:00
/*
2007-04-16 08:59:47 +04:00
* assume out sockaddr have the same size as the in parent
* socket family
*/
2014-10-02 09:18:14 +04:00
in_addr . sa_socklen = socket_length ( parent_si - > family ) ;
if ( in_addr . sa_socklen < = 0 ) {
2007-04-16 08:59:47 +04:00
errno = EINVAL ;
return - 1 ;
}
2014-10-02 09:09:33 +04:00
ret = libc_accept ( s , & un_addr . sa . s , & un_addr . sa_socklen ) ;
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
return ret ;
}
2005-03-28 05:00:39 +04:00
fd = ret ;
2014-10-02 09:09:33 +04:00
ret = sockaddr_convert_from_un ( parent_si ,
& un_addr . sa . un ,
un_addr . sa_socklen ,
parent_si - > family ,
2014-10-02 09:18:14 +04:00
& in_addr . sa . s ,
& in_addr . sa_socklen ) ;
2006-09-16 21:57:50 +04:00
if ( ret = = - 1 ) {
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 ) ;
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
2014-10-02 09:18:14 +04:00
child_si - > peername = ( struct swrap_address ) {
. sa_socklen = in_addr . sa_socklen ,
} ;
memcpy ( & child_si - > peername . sa . ss , & in_addr . sa . ss , in_addr . sa_socklen ) ;
2007-04-16 08:59:47 +04:00
if ( addr ! = NULL & & addrlen ! = NULL ) {
2014-10-02 09:18:14 +04:00
size_t copy_len = MIN ( * addrlen , in_addr . sa_socklen ) ;
2011-03-09 13:46:34 +03:00
if ( copy_len > 0 ) {
2014-10-02 09:18:14 +04:00
memcpy ( addr , & in_addr . sa . ss , copy_len ) ;
2011-03-09 13:46:34 +03:00
}
2014-10-02 09:18:14 +04:00
* addrlen = in_addr . sa_socklen ;
2007-04-16 08:59:47 +04:00
}
2014-04-07 18:12:21 +04:00
ret = libc_getsockname ( fd ,
2014-10-02 09:09:33 +04:00
& un_my_addr . sa . s ,
& un_my_addr . sa_socklen ) ;
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 ) ;
close ( fd ) ;
return ret ;
}
2005-12-05 18:26:49 +03:00
2014-10-02 09:09:33 +04:00
ret = sockaddr_convert_from_un ( child_si ,
& un_my_addr . sa . un ,
un_my_addr . sa_socklen ,
child_si - > family ,
2014-10-02 09:18:14 +04:00
& in_my_addr . sa . s ,
& in_my_addr . sa_socklen ) ;
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 ) ;
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 " ,
2014-10-02 09:09:33 +04:00
un_my_addr . sa . un . sun_path , s ) ;
2014-04-07 18:12:21 +04:00
2014-10-02 09:18:14 +04:00
child_si - > myname = ( struct swrap_address ) {
. sa_socklen = in_my_addr . sa_socklen ,
} ;
memcpy ( & child_si - > myname . sa . ss , & in_my_addr . sa . ss , in_my_addr . sa_socklen ) ;
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 ) {
2014-10-02 09:15:38 +04:00
swrap_pcap_dump_packet ( child_si , addr , SWRAP_ACCEPT_SEND , NULL , 0 ) ;
swrap_pcap_dump_packet ( child_si , addr , SWRAP_ACCEPT_RECV , NULL , 0 ) ;
swrap_pcap_dump_packet ( child_si , addr , SWRAP_ACCEPT_ACK , NULL , 0 ) ;
2014-04-07 18:12:21 +04:00
}
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
{
2014-10-02 09:09:33 +04:00
struct swrap_address un_addr = {
. sa_socklen = sizeof ( struct sockaddr_un ) ,
} ;
2005-06-10 16:21:46 +04:00
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 ;
}
2014-10-02 09:09:33 +04:00
un_addr . sa . un . 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 :
2014-10-02 09:20:53 +04:00
type = SOCKET_TYPE_CHAR_UDP ;
2007-04-16 08:59:47 +04:00
break ;
default :
errno = ESOCKTNOSUPPORT ;
return - 1 ;
}
memset ( & in , 0 , sizeof ( in ) ) ;
in . sin_family = AF_INET ;
2014-10-02 09:20:53 +04:00
in . sin_addr . s_addr = htonl ( 127 < < 24 |
2007-04-16 08:59:47 +04:00
socket_wrapper_default_iface ( ) ) ;
2014-10-02 09:17:10 +04:00
si - > myname = ( struct swrap_address ) {
. sa_socklen = sizeof ( in ) ,
} ;
memcpy ( & si - > myname . sa . in , & in , si - > myname . sa_socklen ) ;
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 :
2014-10-02 09:20:53 +04:00
type = SOCKET_TYPE_CHAR_UDP_V6 ;
2007-04-16 08:59:47 +04:00
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 ( ) ;
2014-10-02 09:17:10 +04:00
si - > myname = ( struct swrap_address ) {
. sa_socklen = sizeof ( in6 ) ,
} ;
memcpy ( & si - > myname . sa . in6 , & in6 , si - > myname . sa_socklen ) ;
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 ;
2014-10-02 09:09:33 +04:00
snprintf ( un_addr . sa . un . sun_path , un_addr . sa_socklen ,
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 ) ;
2014-10-02 09:09:33 +04:00
if ( stat ( un_addr . sa . un . sun_path , & st ) = = 0 ) continue ;
2011-02-12 14:18:16 +03:00
2014-10-02 09:09:33 +04:00
ret = libc_bind ( fd , & un_addr . sa . s , un_addr . sa_socklen ) ;
2005-11-07 18:36:51 +03:00
if ( ret = = - 1 ) return ret ;
2014-10-02 09:16:25 +04:00
si - > un_addr = un_addr . sa . un ;
2005-11-07 18:36:51 +03:00
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 ;
2014-10-02 09:17:10 +04:00
set_port ( si - > family , port , & si - > myname ) ;
2007-04-16 08:59:47 +04:00
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 ;
2014-10-02 09:09:33 +04:00
struct swrap_address un_addr = {
. sa_socklen = sizeof ( struct sockaddr_un ) ,
} ;
2005-03-28 05:00:39 +04:00
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 ,
2014-10-02 09:09:33 +04:00
addrlen , & un_addr . sa . un , 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 {
2014-10-02 09:15:38 +04:00
swrap_pcap_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 ,
2014-10-02 09:09:33 +04:00
& un_addr . sa . s ,
un_addr . sa_socklen ) ;
2009-03-23 11:16:18 +03:00
}
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 " ,
2014-10-02 09:22:13 +04:00
un_addr . sa . un . sun_path , s ) ;
2014-04-07 18:12:21 +04:00
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 ) {
2014-10-02 09:17:10 +04:00
si - > peername = ( struct swrap_address ) {
. sa_socklen = addrlen ,
} ;
memcpy ( & si - > peername . sa . ss , 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 .
*/
2014-10-02 09:17:10 +04:00
if ( si - > bindname . sa_socklen > 0 ) {
si - > myname = ( struct swrap_address ) {
. sa_socklen = si - > bindname . sa_socklen ,
} ;
memcpy ( & si - > myname . sa . ss ,
& si - > bindname . sa . ss ,
si - > bindname . sa_socklen ) ;
/* Cleanup bindname */
si - > bindname = ( struct swrap_address ) {
. sa_socklen = 0 ,
} ;
2014-06-03 16:50:53 +04:00
}
2014-10-02 09:15:38 +04:00
swrap_pcap_dump_packet ( si , serv_addr , SWRAP_CONNECT_RECV , NULL , 0 ) ;
swrap_pcap_dump_packet ( si , serv_addr , SWRAP_CONNECT_ACK , NULL , 0 ) ;
2006-09-29 13:31:20 +04:00
} else {
2014-10-02 09:15:38 +04:00
swrap_pcap_dump_packet ( si , serv_addr , SWRAP_CONNECT_UNREACH , NULL , 0 ) ;
2006-09-29 13:31:20 +04:00
}
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 ;
2014-10-02 09:09:33 +04:00
struct swrap_address un_addr = {
. sa_socklen = sizeof ( struct sockaddr_un ) ,
} ;
2005-03-28 05:00:39 +04:00
struct socket_info * si = find_socket_info ( s ) ;
2014-06-03 17:12:34 +04:00
int bind_error = 0 ;
2014-06-06 01:38:59 +04:00
#if 0 /* FIXME */
2014-06-03 17:14:44 +04:00
bool in_use ;
2014-06-06 01:38:59 +04:00
# endif
2005-03-28 05:00:39 +04:00
if ( ! si ) {
2014-04-07 18:12:21 +04:00
return libc_bind ( s , myaddr , addrlen ) ;
2005-03-28 05:00:39 +04:00
}
2014-06-03 17:12:34 +04:00
switch ( si - > family ) {
case AF_INET : {
const struct sockaddr_in * sin ;
if ( addrlen < sizeof ( struct sockaddr_in ) ) {
bind_error = EINVAL ;
break ;
}
2014-10-02 09:02:36 +04:00
sin = ( const struct sockaddr_in * ) myaddr ;
2014-06-03 17:12:34 +04:00
if ( sin - > sin_family ! = AF_INET ) {
bind_error = EAFNOSUPPORT ;
}
/* special case for AF_UNSPEC */
if ( sin - > sin_family = = AF_UNSPEC & &
( sin - > sin_addr . s_addr = = htonl ( INADDR_ANY ) ) )
{
bind_error = 0 ;
}
break ;
}
# ifdef HAVE_IPV6
case AF_INET6 : {
const struct sockaddr_in6 * sin6 ;
if ( addrlen < sizeof ( struct sockaddr_in6 ) ) {
bind_error = EINVAL ;
break ;
}
2014-10-02 09:03:22 +04:00
sin6 = ( const struct sockaddr_in6 * ) myaddr ;
2014-06-03 17:12:34 +04:00
if ( sin6 - > sin6_family ! = AF_INET6 ) {
bind_error = EAFNOSUPPORT ;
}
break ;
}
# endif
default :
bind_error = EINVAL ;
break ;
}
if ( bind_error ! = 0 ) {
errno = bind_error ;
2014-06-03 17:08:57 +04:00
return - 1 ;
}
2014-06-06 01:38:59 +04:00
#if 0 /* FIXME */
2014-06-03 17:14:44 +04:00
in_use = check_addr_port_in_use ( myaddr , addrlen ) ;
if ( in_use ) {
errno = EADDRINUSE ;
return - 1 ;
}
2014-06-06 01:38:59 +04:00
# endif
2014-06-03 17:14:44 +04:00
2014-10-02 09:17:10 +04:00
si - > myname . sa_socklen = addrlen ;
memcpy ( & si - > myname . sa . ss , myaddr , addrlen ) ;
2005-06-10 16:21:46 +04:00
2014-10-02 09:09:33 +04:00
ret = sockaddr_convert_to_un ( si ,
myaddr ,
addrlen ,
& un_addr . sa . un ,
1 ,
& si - > bcast ) ;
2005-03-31 16:40:12 +04:00
if ( ret = = - 1 ) return - 1 ;
2005-03-28 05:00:39 +04:00
2014-10-02 09:09:33 +04:00
unlink ( un_addr . sa . un . sun_path ) ;
2005-03-28 05:00:39 +04:00
2014-10-02 09:09:33 +04:00
ret = libc_bind ( s , & un_addr . sa . s , un_addr . sa_socklen ) ;
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 " ,
2014-10-02 09:22:13 +04:00
un_addr . sa . un . sun_path , s ) ;
2014-04-07 18:12:21 +04:00
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 ) ;
}
2014-06-03 17:10:19 +04:00
/****************************************************************************
* BINDRESVPORT
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
# ifdef HAVE_BINDRESVPORT
static int swrap_getsockname ( int s , struct sockaddr * name , socklen_t * addrlen ) ;
static int swrap_bindresvport_sa ( int sd , struct sockaddr * sa )
{
2014-10-02 09:09:33 +04:00
struct swrap_address myaddr = {
. sa_socklen = sizeof ( struct sockaddr_storage ) ,
} ;
2014-06-03 17:10:19 +04:00
socklen_t salen ;
static uint16_t port ;
uint16_t i ;
int rc = - 1 ;
int af ;
# define SWRAP_STARTPORT 600
# define SWRAP_ENDPORT (IPPORT_RESERVED - 1)
# define SWRAP_NPORTS (SWRAP_ENDPORT - SWRAP_STARTPORT + 1)
if ( port = = 0 ) {
port = ( getpid ( ) % SWRAP_NPORTS ) + SWRAP_STARTPORT ;
}
if ( sa = = NULL ) {
2014-10-02 09:09:33 +04:00
salen = myaddr . sa_socklen ;
sa = & myaddr . sa . s ;
2014-06-03 17:10:19 +04:00
2014-10-02 09:09:33 +04:00
rc = swrap_getsockname ( sd , & myaddr . sa . s , & salen ) ;
2014-06-03 17:10:19 +04:00
if ( rc < 0 ) {
return - 1 ;
}
af = sa - > sa_family ;
2014-10-02 09:09:33 +04:00
memset ( & myaddr . sa . ss , 0 , salen ) ;
2014-06-03 17:10:19 +04:00
} else {
af = sa - > sa_family ;
}
for ( i = 0 ; i < SWRAP_NPORTS ; i + + , port + + ) {
switch ( af ) {
case AF_INET : {
2014-10-02 09:09:33 +04:00
struct sockaddr_in * sinp = ( struct sockaddr_in * ) ( void * ) sa ;
2014-06-03 17:10:19 +04:00
salen = sizeof ( struct sockaddr_in ) ;
sinp - > sin_port = htons ( port ) ;
break ;
}
case AF_INET6 : {
struct sockaddr_in6 * sin6p = ( struct sockaddr_in6 * ) sa ;
salen = sizeof ( struct sockaddr_in6 ) ;
sin6p - > sin6_port = htons ( port ) ;
break ;
}
default :
errno = EAFNOSUPPORT ;
return - 1 ;
}
sa - > sa_family = af ;
if ( port > SWRAP_ENDPORT ) {
port = SWRAP_STARTPORT ;
}
rc = swrap_bind ( sd , ( struct sockaddr * ) sa , salen ) ;
if ( rc = = 0 | | errno ! = EADDRINUSE ) {
break ;
}
}
return rc ;
}
int bindresvport ( int sockfd , struct sockaddr_in * sinp )
{
return swrap_bindresvport_sa ( sockfd , ( struct sockaddr * ) sinp ) ;
}
# endif
2014-04-07 18:12:21 +04:00
/****************************************************************************
* 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 ) ;
}
2014-10-02 09:18:48 +04:00
/****************************************************************************
* FOPEN
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static FILE * swrap_fopen ( const char * name , const char * mode )
{
FILE * fp ;
fp = libc_fopen ( name , mode ) ;
if ( fp ! = NULL ) {
int fd = fileno ( fp ) ;
swrap_remove_stale ( fd ) ;
}
return fp ;
}
FILE * fopen ( const char * name , const char * mode )
{
return swrap_fopen ( name , mode ) ;
}
2014-04-07 18:12:21 +04:00
/****************************************************************************
* 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 ) ;
2014-06-03 16:58:24 +04:00
socklen_t len ;
2005-03-28 05:00:39 +04:00
if ( ! si ) {
2014-04-07 18:12:21 +04:00
return libc_getpeername ( s , name , addrlen ) ;
2005-03-28 05:00:39 +04:00
}
2014-10-02 09:17:10 +04:00
if ( si - > peername . sa_socklen = = 0 )
2005-03-28 05:00:39 +04:00
{
errno = ENOTCONN ;
return - 1 ;
}
2014-10-02 09:17:10 +04:00
len = MIN ( * addrlen , si - > peername . sa_socklen ) ;
2014-06-03 16:58:24 +04:00
if ( len = = 0 ) {
return 0 ;
}
2014-10-02 09:17:10 +04:00
memcpy ( name , & si - > peername . sa . ss , len ) ;
* addrlen = si - > peername . sa_socklen ;
2005-03-28 05:00:39 +04:00
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 ) ;
2014-06-03 16:58:24 +04:00
socklen_t len ;
2005-03-28 05:00:39 +04:00
if ( ! si ) {
2014-04-07 18:12:21 +04:00
return libc_getsockname ( s , name , addrlen ) ;
2005-03-28 05:00:39 +04:00
}
2014-10-02 09:17:10 +04:00
len = MIN ( * addrlen , si - > myname . sa_socklen ) ;
2014-06-03 16:58:24 +04:00
if ( len = = 0 ) {
return 0 ;
}
2014-10-02 09:17:10 +04:00
memcpy ( name , & si - > myname . sa . ss , len ) ;
* addrlen = si - > myname . sa_socklen ;
2005-03-28 05:00:39 +04:00
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
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2014-06-03 17:05:56 +04:00
# ifndef SO_PROTOCOL
# ifdef SO_PROTOTYPE /* The Solaris name */
# define SO_PROTOCOL SO_PROTOTYPE
# endif /* SO_PROTOTYPE */
# endif /* SO_PROTOCOL */
2014-04-07 18:12:21 +04:00
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-06-03 17:05:56 +04:00
switch ( optname ) {
# ifdef SO_DOMAIN
case SO_DOMAIN :
if ( optval = = NULL | | optlen = = NULL | |
* optlen < ( socklen_t ) sizeof ( int ) ) {
errno = EINVAL ;
return - 1 ;
}
* optlen = sizeof ( int ) ;
* ( int * ) optval = si - > family ;
return 0 ;
# endif /* SO_DOMAIN */
2014-10-02 09:04:15 +04:00
# ifdef SO_PROTOCOL
2014-06-03 17:05:56 +04:00
case SO_PROTOCOL :
if ( optval = = NULL | | optlen = = NULL | |
* optlen < ( socklen_t ) sizeof ( int ) ) {
errno = EINVAL ;
return - 1 ;
}
* optlen = sizeof ( int ) ;
* ( int * ) optval = si - > protocol ;
return 0 ;
2014-10-02 09:04:15 +04:00
# endif /* SO_PROTOCOL */
2014-06-03 17:05:56 +04:00
case SO_TYPE :
if ( optval = = NULL | | optlen = = NULL | |
* optlen < ( socklen_t ) sizeof ( int ) ) {
errno = EINVAL ;
return - 1 ;
}
* optlen = sizeof ( int ) ;
* ( int * ) optval = si - > type ;
return 0 ;
default :
return libc_getsockopt ( s ,
level ,
optname ,
optval ,
optlen ) ;
}
2014-04-07 18:12:21 +04:00
}
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 ) {
2014-10-02 09:15:38 +04:00
swrap_pcap_dump_packet ( si , NULL , SWRAP_PENDING_RST , NULL , 0 ) ;
2010-10-30 18:19:33 +04:00
} else if ( value = = 0 ) { /* END OF FILE */
2014-10-02 09:15:38 +04:00
swrap_pcap_dump_packet ( si , NULL , SWRAP_PENDING_RST , NULL , 0 ) ;
2010-10-30 18:19:33 +04:00
}
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
2014-06-03 17:03:41 +04:00
# ifndef CMSG_ALIGN
# ifdef _ALIGN /* BSD */
# define CMSG_ALIGN _ALIGN
# else
2014-10-02 09:05:35 +04:00
# define CMSG_ALIGN(len) (((len) + sizeof(size_t) - 1) & ~(sizeof(size_t) - 1))
2014-06-03 17:03:41 +04:00
# endif /* _ALIGN */
# endif /* CMSG_ALIGN */
2014-06-03 16:55:13 +04:00
/**
* @ 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 ] ;
2014-10-02 09:09:33 +04:00
void * cast_ptr = ( void * ) cmbuf ;
struct cmsghdr * cm = ( struct cmsghdr * ) cast_ptr ;
2014-06-03 16:55:13 +04:00
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 ) {
2014-10-02 09:00:44 +04:00
# if defined(IP_PKTINFO) && (defined(HAVE_STRUCT_IN_PKTINFO) || defined(IP_RECVDSTADDR))
2014-06-03 16:55:49 +04:00
case AF_INET : {
struct sockaddr_in * sin ;
2014-06-03 17:02:17 +04:00
# if defined(HAVE_STRUCT_IN_PKTINFO)
2014-06-03 16:55:49 +04:00
struct in_pktinfo pkt ;
2014-06-03 17:02:17 +04:00
# elif defined(IP_RECVDSTADDR)
struct in_addr pkt ;
# endif
2014-06-03 16:55:49 +04:00
2014-10-02 09:17:10 +04:00
if ( si - > bindname . sa_socklen = = sizeof ( struct sockaddr_in ) ) {
sin = & si - > bindname . sa . in ;
2014-06-03 16:55:49 +04:00
} else {
2014-10-02 09:17:10 +04:00
if ( si - > myname . sa_socklen ! = sizeof ( struct sockaddr_in ) ) {
2014-06-03 16:55:49 +04:00
return 0 ;
}
2014-10-02 09:17:10 +04:00
sin = & si - > myname . sa . in ;
2014-06-03 16:55:49 +04:00
}
ZERO_STRUCT ( pkt ) ;
2014-06-03 17:02:17 +04:00
# if defined(HAVE_STRUCT_IN_PKTINFO)
2014-06-03 16:55:49 +04:00
pkt . ipi_ifindex = socket_wrapper_default_iface ( ) ;
pkt . ipi_addr . s_addr = sin - > sin_addr . s_addr ;
2014-06-03 17:02:17 +04:00
# elif defined(IP_RECVDSTADDR)
pkt = sin - > sin_addr ;
# endif
2014-06-03 16:55:49 +04:00
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 ;
2014-10-02 09:17:10 +04:00
if ( si - > bindname . sa_socklen = = sizeof ( struct sockaddr_in6 ) ) {
sin6 = & si - > bindname . sa . in6 ;
2014-06-03 16:55:49 +04:00
} else {
2014-10-02 09:17:10 +04:00
if ( si - > myname . sa_socklen ! = sizeof ( struct sockaddr_in6 ) ) {
2014-06-03 16:55:49 +04:00
return 0 ;
}
2014-10-02 09:17:10 +04:00
sin6 = & si - > myname . sa . in6 ;
2014-06-03 16:55:49 +04:00
}
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:56:28 +04:00
static int swrap_msghdr_add_socket_info ( struct socket_info * si ,
struct msghdr * omsg )
{
int rc = 0 ;
if ( si - > pktinfo > 0 ) {
rc = swrap_msghdr_add_pktinfo ( si , omsg ) ;
}
return rc ;
}
2014-06-03 17:03:03 +04:00
2014-06-03 17:03:41 +04:00
static int swrap_sendmsg_copy_cmsg ( struct cmsghdr * cmsg ,
2014-06-03 17:06:33 +04:00
uint8_t * * cm_data ,
2014-06-03 17:03:41 +04:00
size_t * cm_data_space ) ;
2014-06-03 17:04:18 +04:00
static int swrap_sendmsg_filter_cmsg_socket ( struct cmsghdr * cmsg ,
2014-06-03 17:06:33 +04:00
uint8_t * * cm_data ,
2014-06-03 17:04:18 +04:00
size_t * cm_data_space ) ;
2014-06-03 17:03:41 +04:00
2014-06-03 17:03:03 +04:00
static int swrap_sendmsg_filter_cmsghdr ( struct msghdr * msg ,
2014-06-03 17:06:33 +04:00
uint8_t * * cm_data ,
2014-06-03 17:03:03 +04:00
size_t * cm_data_space ) {
struct cmsghdr * cmsg ;
int rc = - 1 ;
/* Nothing to do */
if ( msg - > msg_controllen = = 0 | | msg - > msg_control = = NULL ) {
return 0 ;
}
for ( cmsg = CMSG_FIRSTHDR ( msg ) ;
cmsg ! = NULL ;
cmsg = CMSG_NXTHDR ( msg , cmsg ) ) {
switch ( cmsg - > cmsg_level ) {
case IPPROTO_IP :
2014-06-03 17:04:18 +04:00
rc = swrap_sendmsg_filter_cmsg_socket ( cmsg ,
cm_data ,
cm_data_space ) ;
2014-06-03 17:03:03 +04:00
break ;
default :
2014-06-03 17:03:41 +04:00
rc = swrap_sendmsg_copy_cmsg ( cmsg ,
cm_data ,
cm_data_space ) ;
2014-06-03 17:03:03 +04:00
break ;
}
}
return rc ;
}
2014-06-03 17:03:41 +04:00
static int swrap_sendmsg_copy_cmsg ( struct cmsghdr * cmsg ,
2014-06-03 17:06:33 +04:00
uint8_t * * cm_data ,
2014-06-03 17:03:41 +04:00
size_t * cm_data_space )
{
size_t cmspace ;
uint8_t * p ;
cmspace =
( * cm_data_space ) +
CMSG_SPACE ( cmsg - > cmsg_len - CMSG_ALIGN ( sizeof ( struct cmsghdr ) ) ) ;
2014-06-03 17:06:33 +04:00
p = realloc ( ( * cm_data ) , cmspace ) ;
2014-06-03 17:03:41 +04:00
if ( p = = NULL ) {
return - 1 ;
}
2014-06-03 17:06:33 +04:00
( * cm_data ) = p ;
2014-06-03 17:03:41 +04:00
2014-06-03 17:06:33 +04:00
p = ( * cm_data ) + ( * cm_data_space ) ;
2014-06-03 17:03:41 +04:00
* cm_data_space = cmspace ;
memcpy ( p , cmsg , cmsg - > cmsg_len ) ;
return 0 ;
}
2014-06-03 17:04:18 +04:00
2014-06-03 17:04:45 +04:00
static int swrap_sendmsg_filter_cmsg_pktinfo ( struct cmsghdr * cmsg ,
2014-06-03 17:06:33 +04:00
uint8_t * * cm_data ,
2014-06-03 17:04:45 +04:00
size_t * cm_data_space ) ;
2014-06-03 17:04:18 +04:00
static int swrap_sendmsg_filter_cmsg_socket ( struct cmsghdr * cmsg ,
2014-06-03 17:06:33 +04:00
uint8_t * * cm_data ,
2014-06-03 17:04:18 +04:00
size_t * cm_data_space )
{
int rc = - 1 ;
switch ( cmsg - > cmsg_type ) {
# ifdef IP_PKTINFO
case IP_PKTINFO :
2014-06-03 17:04:45 +04:00
rc = swrap_sendmsg_filter_cmsg_pktinfo ( cmsg ,
cm_data ,
cm_data_space ) ;
2014-06-03 17:04:18 +04:00
break ;
# endif
# ifdef IPV6_PKTINFO
case IPV6_PKTINFO :
2014-06-03 17:04:45 +04:00
rc = swrap_sendmsg_filter_cmsg_pktinfo ( cmsg ,
cm_data ,
cm_data_space ) ;
2014-06-03 17:04:18 +04:00
break ;
# endif
default :
break ;
}
return rc ;
}
2014-06-03 17:04:45 +04:00
static int swrap_sendmsg_filter_cmsg_pktinfo ( struct cmsghdr * cmsg ,
2014-06-03 17:06:33 +04:00
uint8_t * * cm_data ,
2014-06-03 17:04:45 +04:00
size_t * cm_data_space )
{
( void ) cmsg ; /* unused */
( void ) cm_data ; /* unused */
( void ) cm_data_space ; /* unused */
/*
* Passing a IP pktinfo to a unix socket might be rejected by the
* Kernel , at least on FreeBSD . So skip this cmsg .
*/
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 ;
}
2014-10-02 09:17:10 +04:00
ret = sockaddr_convert_to_un ( si ,
& si - > peername . sa . s ,
si - > peername . sa_socklen ,
tmp_un ,
0 ,
NULL ) ;
2010-10-30 18:08:49 +04:00
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 ;
}
2014-06-03 17:05:12 +04:00
# ifdef HAVE_STRUCT_MSGHDR_MSG_CONTROL
if ( msg - > msg_controllen > 0 & & msg - > msg_control ! = NULL ) {
uint8_t * cmbuf = NULL ;
size_t cmlen = 0 ;
2014-06-03 17:06:33 +04:00
ret = swrap_sendmsg_filter_cmsghdr ( msg , & cmbuf , & cmlen ) ;
2014-06-03 17:05:12 +04:00
if ( ret < 0 ) {
free ( cmbuf ) ;
return - 1 ;
}
if ( cmlen = = 0 ) {
msg - > msg_controllen = 0 ;
msg - > msg_control = NULL ;
2014-06-03 17:07:07 +04:00
} else if ( cmlen < msg - > msg_controllen & & cmbuf ! = NULL ) {
2014-06-03 17:05:12 +04:00
memcpy ( msg - > msg_control , cmbuf , cmlen ) ;
msg - > msg_controllen = cmlen ;
}
free ( cmbuf ) ;
}
# endif
2010-10-30 18:08:49 +04:00
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 ) {
2014-10-02 09:15:38 +04:00
swrap_pcap_dump_packet ( si , NULL , SWRAP_SEND , buf , len ) ;
swrap_pcap_dump_packet ( si , NULL , SWRAP_SEND_RST , NULL , 0 ) ;
2014-04-07 18:12:21 +04:00
} else {
2014-10-02 09:15:38 +04:00
swrap_pcap_dump_packet ( si , NULL , SWRAP_SEND , buf , len ) ;
2014-04-07 18:12:21 +04:00
}
break ;
case SOCK_DGRAM :
if ( si - > connected ) {
2014-10-02 09:17:10 +04:00
to = & si - > peername . sa . s ;
2014-04-07 18:12:21 +04:00
}
if ( ret = = - 1 ) {
2014-10-02 09:15:38 +04:00
swrap_pcap_dump_packet ( si , to , SWRAP_SENDTO , buf , len ) ;
swrap_pcap_dump_packet ( si , to , SWRAP_SENDTO_UNREACH , buf , len ) ;
2014-04-07 18:12:21 +04:00
} else {
2014-10-02 09:15:38 +04:00
swrap_pcap_dump_packet ( si , to , SWRAP_SENDTO , buf , len ) ;
2014-04-07 18:12:21 +04:00
}
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 ;
2014-06-03 16:57:08 +04:00
int rc ;
2014-04-07 18:12:21 +04:00
/* 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 ) {
2014-06-03 16:57:08 +04:00
rc = 0 ;
goto done ;
2014-04-07 18:12:21 +04:00
}
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 ) {
2014-10-02 09:15:38 +04:00
swrap_pcap_dump_packet ( si , NULL , SWRAP_RECV_RST , NULL , 0 ) ;
2014-04-07 18:12:21 +04:00
} else if ( ret = = 0 ) { /* END OF FILE */
2014-10-02 09:15:38 +04:00
swrap_pcap_dump_packet ( si , NULL , SWRAP_RECV_RST , NULL , 0 ) ;
2014-04-07 18:12:21 +04:00
} else if ( ret > 0 ) {
2014-10-02 09:15:38 +04:00
swrap_pcap_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 ) {
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
}
2014-10-02 09:15:38 +04:00
swrap_pcap_dump_packet ( si ,
2014-04-07 18:12:21 +04:00
msg - > msg_name ,
SWRAP_RECVFROM ,
buf ,
ret ) ;
2010-10-30 18:08:49 +04:00
} else {
2014-10-02 09:15:38 +04:00
swrap_pcap_dump_packet ( si ,
2014-04-07 18:12:21 +04:00
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-06-03 16:57:08 +04:00
rc = 0 ;
2014-05-08 16:04:11 +04:00
done :
2010-10-30 18:08:49 +04:00
free ( buf ) ;
errno = saved_errno ;
2014-06-03 16:57:08 +04:00
# ifdef HAVE_STRUCT_MSGHDR_MSG_CONTROL
if ( rc = = 0 & &
msg - > msg_controllen > 0 & &
msg - > msg_control ! = NULL ) {
rc = swrap_msghdr_add_socket_info ( si , msg ) ;
if ( rc < 0 ) {
return - 1 ;
}
}
# endif
return rc ;
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-10-02 09:09:33 +04:00
struct swrap_address from_addr = {
. sa_socklen = sizeof ( struct sockaddr_un ) ,
} ;
2014-04-07 18:12:21 +04:00
ssize_t ret ;
2005-03-28 05:00:39 +04:00
struct socket_info * si = find_socket_info ( s ) ;
2014-10-02 09:09:33 +04:00
struct swrap_address saddr = {
. sa_socklen = sizeof ( struct sockaddr_storage ) ,
} ;
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 {
2014-10-02 09:09:33 +04:00
msg . msg_name = & saddr . sa . s ; /* optional address */
msg . msg_namelen = saddr . sa_socklen ; /* 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 ;
ret = libc_recvfrom ( s ,
buf ,
len ,
flags ,
2014-10-02 09:09:33 +04:00
& from_addr . sa . s ,
& from_addr . sa_socklen ) ;
2014-04-07 18:12:21 +04:00
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 ,
2014-10-02 09:09:33 +04:00
& from_addr . sa . un ,
from_addr . sa_socklen ,
2014-04-07 18:12:21 +04:00
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 ;
2014-10-02 09:09:33 +04:00
struct swrap_address un_addr = {
. sa_socklen = sizeof ( struct sockaddr_un ) ,
} ;
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-10-02 09:09:33 +04:00
rc = swrap_sendmsg_before ( s ,
si ,
& msg ,
& tmp ,
& un_addr . sa . un ,
& to_un ,
& to ,
& bcast ) ;
2014-04-07 18:12:21 +04:00
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 + + ) {
2014-10-02 09:09:33 +04:00
snprintf ( un_addr . sa . un . sun_path ,
sizeof ( un_addr . sa . un . sun_path ) ,
" %s/ " SOCKET_FORMAT ,
2010-10-30 18:23:49 +04:00
socket_wrapper_dir ( ) , type , iface , prt ) ;
2014-10-02 09:09:33 +04:00
if ( stat ( un_addr . sa . un . 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 ,
2014-10-02 09:09:33 +04:00
& un_addr . sa . s ,
un_addr . sa_socklen ) ;
2005-11-07 18:36:51 +03:00
}
2009-03-23 11:16:18 +03:00
2014-10-02 09:15:38 +04:00
swrap_pcap_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 ;
2014-10-02 09:09:33 +04:00
struct swrap_address saddr = {
. sa_socklen = sizeof ( struct sockaddr_storage ) ,
} ;
2014-04-07 18:12:21 +04:00
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 ) ;
2014-10-02 09:09:33 +04:00
msg . msg_name = & saddr . sa . s ; /* optional address */
msg . msg_namelen = saddr . sa_socklen ; /* size of address */
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
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 ;
2014-10-02 09:09:33 +04:00
struct swrap_address saddr = {
. sa_socklen = sizeof ( struct sockaddr_storage ) ,
} ;
2014-04-07 18:12:21 +04:00
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 ) ;
2014-10-02 09:09:33 +04:00
msg . msg_name = & saddr . sa . ss ; /* optional address */
msg . msg_namelen = saddr . sa_socklen ; /* size of address */
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
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 )
{
2014-10-02 09:09:33 +04:00
struct swrap_address from_addr = {
. sa_socklen = sizeof ( struct sockaddr_un ) ,
} ;
2014-04-07 18:12:21 +04:00
struct socket_info * si ;
struct msghdr msg ;
struct iovec tmp ;
2014-06-03 17:00:18 +04:00
# ifdef HAVE_STRUCT_MSGHDR_MSG_CONTROL
2014-06-03 16:57:35 +04:00
size_t msg_ctrllen_filled ;
size_t msg_ctrllen_left ;
2014-06-03 17:00:18 +04:00
# endif
2014-04-07 18:12:21 +04:00
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 ) ;
2014-10-02 09:09:33 +04:00
msg . msg_name = & from_addr . sa ; /* optional address */
msg . msg_namelen = from_addr . sa_socklen ; /* size of address */
2014-04-07 18:12:21 +04:00
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
2014-06-03 16:57:35 +04:00
msg_ctrllen_filled = 0 ;
msg_ctrllen_left = omsg - > msg_controllen ;
2014-04-07 18:12:21 +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 */
# 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-06-03 16:57:35 +04:00
msg . msg_name = omsg - > msg_name ;
msg . msg_namelen = omsg - > msg_namelen ;
# ifdef HAVE_STRUCT_MSGHDR_MSG_CONTROL
msg_ctrllen_filled + = msg . msg_controllen ;
msg_ctrllen_left - = msg . msg_controllen ;
if ( omsg - > msg_control ! = NULL ) {
uint8_t * p ;
p = omsg - > msg_control ;
p + = msg_ctrllen_filled ;
msg . msg_control = p ;
msg . msg_controllen = msg_ctrllen_left ;
} else {
msg . msg_control = NULL ;
msg . msg_controllen = 0 ;
}
# endif
2014-10-02 09:09:33 +04:00
rc = swrap_recvmsg_after ( s ,
si ,
& msg ,
& from_addr . sa . un ,
from_addr . sa_socklen ,
ret ) ;
2014-04-07 18:12:21 +04:00
if ( rc ! = 0 ) {
return rc ;
}
2006-09-12 10:19:11 +04:00
2014-06-03 16:57:35 +04:00
# ifdef HAVE_STRUCT_MSGHDR_MSG_CONTROL
if ( omsg - > msg_control ! = NULL ) {
/* msg.msg_controllen = space left */
msg_ctrllen_left = msg . msg_controllen ;
msg_ctrllen_filled = omsg - > msg_controllen - msg_ctrllen_left ;
}
/* Update the original message length */
omsg - > msg_controllen = msg_ctrllen_filled ;
omsg - > msg_flags = msg . msg_flags ;
# endif
omsg - > msg_iovlen = msg . msg_iovlen ;
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
2014-06-03 17:05:12 +04:00
if ( msg . msg_controllen > 0 & & msg . msg_control ! = NULL ) {
/* omsg is a const so use a local buffer for modifications */
uint8_t cmbuf [ omsg - > msg_controllen ] ;
memcpy ( cmbuf , omsg - > msg_control , omsg - > msg_controllen ) ;
msg . msg_control = cmbuf ; /* ancillary data, see below */
msg . msg_controllen = omsg - > msg_controllen ; /* ancillary data buffer len */
}
2010-10-30 18:23:49 +04:00
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
}
2014-10-02 09:15:38 +04:00
swrap_pcap_dump_packet ( si , to , SWRAP_SENDTO , buf , len ) ;
2010-10-30 18:23:49 +04:00
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 ;
2014-10-02 09:09:33 +04:00
struct swrap_address saddr = {
. sa_socklen = sizeof ( struct sockaddr_storage )
} ;
2014-04-07 18:12:21 +04:00
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 ) ;
2014-10-02 09:09:33 +04:00
msg . msg_name = & saddr . sa . s ; /* optional address */
msg . msg_namelen = saddr . sa_socklen ; /* size of address */
2014-04-07 18:12:21 +04:00
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
2014-10-02 09:17:10 +04:00
if ( si - > myname . sa_socklen > 0 & & si - > peername . sa_socklen > 0 ) {
2014-10-02 09:15:38 +04:00
swrap_pcap_dump_packet ( si , NULL , SWRAP_CLOSE_SEND , NULL , 0 ) ;
2006-09-29 13:31:20 +04:00
}
2014-04-07 18:12:21 +04:00
ret = libc_close ( fd ) ;
2006-09-12 13:08:55 +04:00
2014-10-02 09:17:10 +04:00
if ( si - > myname . sa_socklen > 0 & & si - > peername . sa_socklen > 0 ) {
2014-10-02 09:15:38 +04:00
swrap_pcap_dump_packet ( si , NULL , SWRAP_CLOSE_RECV , NULL , 0 ) ;
swrap_pcap_dump_packet ( si , NULL , SWRAP_CLOSE_ACK , NULL , 0 ) ;
2006-09-29 13:31:20 +04:00
}
2014-10-02 09:16:25 +04:00
if ( si - > un_addr . sun_path [ 0 ] ! = ' \0 ' ) {
unlink ( si - > un_addr . sun_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 ;
}
}