socket_wrapper-1.2.3/cmake/000755 001750 000144 00000000000 13444714527 015620 5ustar00asnusers000000 000000 socket_wrapper-1.2.3/cmake/Modules/000755 001750 000144 00000000000 13444714527 017230 5ustar00asnusers000000 000000 socket_wrapper-1.2.3/cmake/Modules/COPYING-CMAKE-SCRIPTS000644 001750 000144 00000002457 12247662153 022233 0ustar00asnusers000000 000000 Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The name of the author may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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-1.2.3/cmake/Modules/DefinePlatformDefaults.cmake000644 001750 000144 00000001460 12247662153 024617 0ustar00asnusers000000 000000 # Set system vars if (CMAKE_SYSTEM_NAME MATCHES "Linux") set(LINUX TRUE) endif(CMAKE_SYSTEM_NAME MATCHES "Linux") if (CMAKE_SYSTEM_NAME MATCHES "FreeBSD") set(FREEBSD TRUE) set(BSD TRUE) endif (CMAKE_SYSTEM_NAME MATCHES "FreeBSD") if (CMAKE_SYSTEM_NAME MATCHES "OpenBSD") set(OPENBSD TRUE) set(BSD TRUE) endif (CMAKE_SYSTEM_NAME MATCHES "OpenBSD") if (CMAKE_SYSTEM_NAME MATCHES "NetBSD") set(NETBSD TRUE) set(BSD TRUE) endif (CMAKE_SYSTEM_NAME MATCHES "NetBSD") if (CMAKE_SYSTEM_NAME MATCHES "(Solaris|SunOS)") set(SOLARIS TRUE) endif (CMAKE_SYSTEM_NAME MATCHES "(Solaris|SunOS)") if (CMAKE_SYSTEM_NAME MATCHES "OS2") set(OS2 TRUE) endif (CMAKE_SYSTEM_NAME MATCHES "OS2") if (CMAKE_SYSTEM_NAME MATCHES "Darwin") set(OSX TRUE) endif (CMAKE_SYSTEM_NAME MATCHES "Darwin") socket_wrapper-1.2.3/cmake/Modules/MacroEnsureOutOfSourceBuild.cmake000644 001750 000144 00000001227 12247662153 025572 0ustar00asnusers000000 000000 # - MACRO_ENSURE_OUT_OF_SOURCE_BUILD() # MACRO_ENSURE_OUT_OF_SOURCE_BUILD() # Copyright (c) 2006, Alexander Neundorf, # # Redistribution and use is allowed according to the terms of the BSD license. # For details see the accompanying COPYING-CMAKE-SCRIPTS file. macro (MACRO_ENSURE_OUT_OF_SOURCE_BUILD _errorMessage) string(COMPARE EQUAL "${CMAKE_SOURCE_DIR}" "${CMAKE_BINARY_DIR}" _insource) if (_insource) message(SEND_ERROR "${_errorMessage}") message(FATAL_ERROR "Remove the file CMakeCache.txt in ${CMAKE_SOURCE_DIR} first.") endif (_insource) endmacro (MACRO_ENSURE_OUT_OF_SOURCE_BUILD) socket_wrapper-1.2.3/cmake/Modules/AddCCompilerFlag.cmake000644 001750 000144 00000001515 13374561011 023302 0ustar00asnusers000000 000000 # # add_c_compiler_flag("-Werror" SUPPORTED_CFLAGS) # # Copyright (c) 2018 Andreas Schneider # # Redistribution and use is allowed according to the terms of the BSD license. # For details see the accompanying COPYING-CMAKE-SCRIPTS file. include(CheckCCompilerFlag) macro(add_c_compiler_flag _COMPILER_FLAG _OUTPUT_VARIABLE) string(TOUPPER ${_COMPILER_FLAG} _COMPILER_FLAG_NAME) string(REGEX REPLACE "^-" "" _COMPILER_FLAG_NAME "${_COMPILER_FLAG_NAME}") string(REGEX REPLACE "(-|=|\ )" "_" _COMPILER_FLAG_NAME "${_COMPILER_FLAG_NAME}") check_c_compiler_flag("${_COMPILER_FLAG}" WITH_${_COMPILER_FLAG_NAME}_FLAG) if (WITH_${_COMPILER_FLAG_NAME}_FLAG) #string(APPEND ${_OUTPUT_VARIABLE} "${_COMPILER_FLAG} ") list(APPEND ${_OUTPUT_VARIABLE} ${_COMPILER_FLAG}) endif() endmacro() socket_wrapper-1.2.3/cmake/Modules/AddCMockaTest.cmake000644 001750 000144 00000006250 13374561011 022631 0ustar00asnusers000000 000000 # # Copyright (c) 2007 Daniel Gollub # Copyright (c) 2007-2018 Andreas Schneider # Copyright (c) 2018 Anderson Toshiyuki Sasaki # # Redistribution and use is allowed according to the terms of the BSD license. # For details see the accompanying COPYING-CMAKE-SCRIPTS file. #.rst: # AddCMockaTest # ------------- # # This file provides a function to add a test # # Functions provided # ------------------ # # :: # # add_cmocka_test(target_name # SOURCES src1 src2 ... srcN # [COMPILE_OPTIONS opt1 opt2 ... optN] # [LINK_LIBRARIES lib1 lib2 ... libN] # [LINK_OPTIONS lopt1 lop2 .. loptN] # ) # # ``target_name``: # Required, expects the name of the test which will be used to define a target # # ``SOURCES``: # Required, expects one or more source files names # # ``COMPILE_OPTIONS``: # Optional, expects one or more options to be passed to the compiler # # ``LINK_LIBRARIES``: # Optional, expects one or more libraries to be linked with the test # executable. # # ``LINK_OPTIONS``: # Optional, expects one or more options to be passed to the linker # # # Example: # # .. code-block:: cmake # # add_cmocka_test(my_test # SOURCES my_test.c other_source.c # COMPILE_OPTIONS -g -Wall # LINK_LIBRARIES mylib # LINK_OPTIONS -Wl,--enable-syscall-fixup # ) # # Where ``my_test`` is the name of the test, ``my_test.c`` and # ``other_source.c`` are sources for the binary, ``-g -Wall`` are compiler # options to be used, ``mylib`` is a target of a library to be linked, and # ``-Wl,--enable-syscall-fixup`` is an option passed to the linker. # enable_testing() include(CTest) if (CMAKE_CROSSCOMPILING) if (WIN32) find_program(WINE_EXECUTABLE NAMES wine) set(TARGET_SYSTEM_EMULATOR ${WINE_EXECUTABLE} CACHE INTERNAL "") endif() endif() function(ADD_CMOCKA_TEST _TARGET_NAME) set(one_value_arguments ) set(multi_value_arguments SOURCES COMPILE_OPTIONS LINK_LIBRARIES LINK_OPTIONS ) cmake_parse_arguments(_add_cmocka_test "" "${one_value_arguments}" "${multi_value_arguments}" ${ARGN} ) if (NOT DEFINED _add_cmocka_test_SOURCES) message(FATAL_ERROR "No sources provided for target ${_TARGET_NAME}") endif() add_executable(${_TARGET_NAME} ${_add_cmocka_test_SOURCES}) if (DEFINED _add_cmocka_test_COMPILE_OPTIONS) target_compile_options(${_TARGET_NAME} PRIVATE ${_add_cmocka_test_COMPILE_OPTIONS} ) endif() if (DEFINED _add_cmocka_test_LINK_LIBRARIES) target_link_libraries(${_TARGET_NAME} PRIVATE ${_add_cmocka_test_LINK_LIBRARIES} ) endif() if (DEFINED _add_cmocka_test_LINK_OPTIONS) set_target_properties(${_TARGET_NAME} PROPERTIES LINK_FLAGS ${_add_cmocka_test_LINK_OPTIONS} ) endif() add_test(${_TARGET_NAME} ${TARGET_SYSTEM_EMULATOR} ${_TARGET_NAME} ) endfunction (ADD_CMOCKA_TEST) socket_wrapper-1.2.3/cmake/Modules/CheckCCompilerFlagSSP.cmake000644 001750 000144 00000003560 13374561011 024217 0ustar00asnusers000000 000000 # - Check whether the C compiler supports a given flag in the # context of a stack checking compiler option. # CHECK_C_COMPILER_FLAG_SSP(FLAG VARIABLE) # # FLAG - the compiler flag # VARIABLE - variable to store the result # # This actually calls check_c_source_compiles. # See help for CheckCSourceCompiles for a listing of variables # that can modify the build. # Copyright (c) 2006, Alexander Neundorf, # # Redistribution and use is allowed according to the terms of the BSD license. # For details see the accompanying COPYING-CMAKE-SCRIPTS file. # Requires cmake 3.10 #include_guard(GLOBAL) include(CheckCSourceCompiles) include(CMakeCheckCompilerFlagCommonPatterns) macro(CHECK_C_COMPILER_FLAG_SSP _FLAG _RESULT) set(SAFE_CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS}") set(CMAKE_REQUIRED_FLAGS "${_FLAG}") # Normalize locale during test compilation. set(_CheckCCompilerFlag_LOCALE_VARS LC_ALL LC_MESSAGES LANG) foreach(v ${_CheckCCompilerFlag_LOCALE_VARS}) set(_CheckCCompilerFlag_SAVED_${v} "$ENV{${v}}") set(ENV{${v}} C) endforeach() CHECK_COMPILER_FLAG_COMMON_PATTERNS(_CheckCCompilerFlag_COMMON_PATTERNS) check_c_source_compiles("int main(int argc, char **argv) { char buffer[256]; return buffer[argc]=0;}" ${_RESULT} # Some compilers do not fail with a bad flag FAIL_REGEX "command line option .* is valid for .* but not for C" # GNU ${_CheckCCompilerFlag_COMMON_PATTERNS}) foreach(v ${_CheckCCompilerFlag_LOCALE_VARS}) set(ENV{${v}} ${_CheckCCompilerFlag_SAVED_${v}}) unset(_CheckCCompilerFlag_SAVED_${v}) endforeach() unset(_CheckCCompilerFlag_LOCALE_VARS) unset(_CheckCCompilerFlag_COMMON_PATTERNS) set(CMAKE_REQUIRED_FLAGS "${SAFE_CMAKE_REQUIRED_FLAGS}") endmacro(CHECK_C_COMPILER_FLAG_SSP) socket_wrapper-1.2.3/cmake/Modules/DefineCMakeDefaults.cmake000644 001750 000144 00000001251 13374561011 024002 0ustar00asnusers000000 000000 # Always include srcdir and builddir in include path # This saves typing ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY} in # about every subdir # since cmake 2.4.0 set(CMAKE_INCLUDE_CURRENT_DIR ON) # Put the include dirs which are in the source or build tree # before all other include dirs, so the headers in the sources # are preferred over the already installed ones # since cmake 2.4.1 set(CMAKE_INCLUDE_DIRECTORIES_PROJECT_BEFORE ON) # Use colored output # since cmake 2.4.0 set(CMAKE_COLOR_MAKEFILE ON) # Create the compile command database for clang by default set(CMAKE_EXPORT_COMPILE_COMMANDS ON) # Always build with -fPIC set(CMAKE_POSITION_INDEPENDENT_CODE ON) socket_wrapper-1.2.3/cmake/Modules/DefineCompilerFlags.cmake000644 001750 000144 00000005551 13375035214 024072 0ustar00asnusers000000 000000 if (UNIX AND NOT WIN32) # Activate with: -DCMAKE_BUILD_TYPE=Profiling set(CMAKE_C_FLAGS_PROFILING "-O0 -g -fprofile-arcs -ftest-coverage" CACHE STRING "Flags used by the C compiler during PROFILING builds.") set(CMAKE_CXX_FLAGS_PROFILING "-O0 -g -fprofile-arcs -ftest-coverage" CACHE STRING "Flags used by the CXX compiler during PROFILING builds.") set(CMAKE_SHARED_LINKER_FLAGS_PROFILING "-fprofile-arcs -ftest-coverage" CACHE STRING "Flags used by the linker during the creation of shared libraries during PROFILING builds.") set(CMAKE_MODULE_LINKER_FLAGS_PROFILING "-fprofile-arcs -ftest-coverage" CACHE STRING "Flags used by the linker during the creation of shared libraries during PROFILING builds.") set(CMAKE_EXEC_LINKER_FLAGS_PROFILING "-fprofile-arcs -ftest-coverage" CACHE STRING "Flags used by the linker during PROFILING builds.") # Activate with: -DCMAKE_BUILD_TYPE=AddressSanitizer set(CMAKE_C_FLAGS_ADDRESSSANITIZER "-g -O1 -fsanitize=address -fno-omit-frame-pointer" CACHE STRING "Flags used by the C compiler during ADDRESSSANITIZER builds.") set(CMAKE_CXX_FLAGS_ADDRESSSANITIZER "-g -O1 -fsanitize=address -fno-omit-frame-pointer" CACHE STRING "Flags used by the CXX compiler during ADDRESSSANITIZER builds.") set(CMAKE_SHARED_LINKER_FLAGS_ADDRESSSANITIZER "-fsanitize=address" CACHE STRING "Flags used by the linker during the creation of shared libraries during ADDRESSSANITIZER builds.") set(CMAKE_MODULE_LINKER_FLAGS_ADDRESSSANITIZER "-fsanitize=address" CACHE STRING "Flags used by the linker during the creation of shared libraries during ADDRESSSANITIZER builds.") set(CMAKE_EXEC_LINKER_FLAGS_ADDRESSSANITIZER "-fsanitize=address" CACHE STRING "Flags used by the linker during ADDRESSSANITIZER builds.") # Activate with: -DCMAKE_BUILD_TYPE=UndefinedSanitizer set(CMAKE_C_FLAGS_UNDEFINEDSANITIZER "-g -O1 -fsanitize=undefined -fsanitize=null -fsanitize=alignment -fno-sanitize-recover" CACHE STRING "Flags used by the C compiler during UNDEFINEDSANITIZER builds.") set(CMAKE_CXX_FLAGS_UNDEFINEDSANITIZER "-g -O1 -fsanitize=undefined -fsanitize=null -fsanitize=alignment -fno-sanitize-recover" CACHE STRING "Flags used by the CXX compiler during UNDEFINEDSANITIZER builds.") set(CMAKE_SHARED_LINKER_FLAGS_UNDEFINEDSANITIZER "-fsanitize=undefined" CACHE STRING "Flags used by the linker during the creation of shared libraries during UNDEFINEDSANITIZER builds.") set(CMAKE_MODULE_LINKER_FLAGS_UNDEFINEDSANITIZER "-fsanitize=undefined" CACHE STRING "Flags used by the linker during the creation of shared libraries during UNDEFINEDSANITIZER builds.") set(CMAKE_EXEC_LINKER_FLAGS_UNDEFINEDSANITIZER "-fsanitize=undefined" CACHE STRING "Flags used by the linker during UNDEFINEDSANITIZER builds.") endif() socket_wrapper-1.2.3/cmake/Toolchain-Debian-mips.cmake000644 001750 000144 00000001173 13374561011 022660 0ustar00asnusers000000 000000 include(CMakeForceCompiler) set(TOOLCHAIN_PREFIX mips-linux-gnu) set(CMAKE_SYSTEM_NAME Linux) set(CMAKE_SYSTEM_VERSION 1) set(CMAKE_SYSTEM_PROCESSOR mips) # This is the location of the mips toolchain set(CMAKE_C_COMPILER ${TOOLCHAIN_PREFIX}-gcc) set(CMAKE_CXX_COMPILER ${TOOLCHAIN_PREFIX}-g++) # This is the file system root of the target set(CMAKE_FIND_ROOT_PATH /usr/${TOOLCHAIN_PREFIX}) # Search for programs in the build host directories set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) # For libraries and headers in the target directories set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) socket_wrapper-1.2.3/example/000755 001750 000144 00000000000 13444714527 016173 5ustar00asnusers000000 000000 socket_wrapper-1.2.3/example/openssh.sh000755 001750 000144 00000004241 12250071704 020175 0ustar00asnusers000000 000000 #!/bin/bash SSH_DIRECTORY=$(mktemp -d /tmp/tmp.swrap.XXXXXXXX) SERVER_ADDRESS="127.0.0.10" mkdir ${SSH_DIRECTORY}/swrap cleanup_and_exit () { trap EXIT test -z "$1" && set 0 echo echo "CLEANING UP" echo kill -TERM $(< ${SSH_DIRECTORY}/sshd.pid) rm -rf ${SSH_DIRECTORY} exit $1 } # Setup exit handler trap cleanup_and_exit SIGINT SIGTERM echo Generating ${SSH_DIRECTORY}/ssh_host_key. ssh-keygen -t rsa1 -b 2048 -f ${SSH_DIRECTORY}/ssh_host_key -N '' 2>/dev/null echo Generating ${SSH_DIRECTORY}/ssh_host_dsa_key. ssh-keygen -t dsa -f ${SSH_DIRECTORY}/ssh_host_dsa_key -N '' 2>/dev/null echo Generating ${SSH_DIRECTORY}/ssh_host_rsa_key. ssh-keygen -t rsa -b 2048 -f ${SSH_DIRECTORY}/ssh_host_rsa_key -N '' 2>/dev/null #echo Generating ${SSH_DIRECTORY}/ssh_host_ecdsa_key. #ssh-keygen -t ecdsa -b 256 -f ${SSH_DIRECTORY}/ssh_host_ecdsa_key -N '' 2>/dev/null # Create sshd_config file cat > ${SSH_DIRECTORY}/sshd_config << EOT Port 22 ListenAddress ${SERVER_ADDRESS} HostKey ${SSH_DIRECTORY}/ssh_host_key HostKey ${SSH_DIRECTORY}/ssh_host_rsa_key HostKey ${SSH_DIRECTORY}/ssh_host_dsa_key #HostKey ${SSH_DIRECTORY}/ssh_host_ecdsa_key Subsystem sftp /usr/lib/ssh/sftp-server LogLevel DEBUG1 AcceptEnv LANG LC_CTYPE LC_NUMERIC LC_TIME LC_COLLATE LC_MONETARY LC_MESSAGES AcceptEnv LC_PAPER LC_NAME LC_ADDRESS LC_TELEPHONE LC_MEASUREMENT AcceptEnv LC_IDENTIFICATION LC_ALL PidFile ${SSH_DIRECTORY}/sshd.pid EOT export SOCKET_WRAPPER_DIR="${SSH_DIRECTORY}/swrap" export SOCKET_WRAPPER_DEFAULT_IFACE=11 echo echo "Starting SSHD with SOCKET_WRAPPER_DIR=${SSH_DIRECTORY}/swrap ..." DYLD_INSERT_LIBRARIES=libsocket_wrapper.dylib LD_PRELOAD=libsocket_wrapper.so /usr/sbin/sshd -f ${SSH_DIRECTORY}/sshd_config -e 2> ${SSH_DIRECTORY}/sshd_log || cleanup_and_exit 1 echo "done" echo echo "Connecting to the ${SERVER_ADDRESS} ssh server using ssh binary." echo "You can check the sshd log file at ${SSH_DIRECTORY}/sshd_log." echo "If you logout sshd will be stopped and the environment cleaned up." DYLD_INSERT_LIBRARIES=libsocket_wrapper.dylib LD_PRELOAD=libsocket_wrapper.so ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no ${SERVER_ADDRESS} cleanup_and_exit 0 socket_wrapper-1.2.3/src/000755 001750 000144 00000000000 13444714527 015327 5ustar00asnusers000000 000000 socket_wrapper-1.2.3/src/CMakeLists.txt000644 001750 000144 00000002220 13433277502 020056 0ustar00asnusers000000 000000 project(libsocket_wrapper C) add_library(socket_wrapper SHARED socket_wrapper.c) target_include_directories(socket_wrapper PRIVATE ${CMAKE_BINARY_DIR}) target_compile_options(socket_wrapper PRIVATE ${DEFAULT_C_COMPILE_FLAGS} -D_GNU_SOURCE) target_link_libraries(socket_wrapper ${SWRAP_REQUIRED_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT}) set_target_properties(socket_wrapper PROPERTIES VERSION ${LIBRARY_VERSION} SOVERSION ${LIBRARY_SOVERSION}) if (DEFINED DEFAULT_LINK_FLAGS) set_target_properties(socket_wrapper PROPERTIES LINK_FLAGS ${DEFAULT_LINK_FLAGS}) endif() install(TARGETS socket_wrapper RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} ) set(SOCKET_WRAPPER_LOCATION "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_SHARED_LIBRARY_PREFIX}socket_wrapper${CMAKE_SHARED_LIBRARY_SUFFIX}" PARENT_SCOPE) socket_wrapper-1.2.3/src/socket_wrapper.c000644 001750 000144 00000417704 13444714272 020535 0ustar00asnusers000000 000000 /* * BSD 3-Clause License * * Copyright (c) 2005-2008, Jelmer Vernooij * Copyright (c) 2006-2018, Stefan Metzmacher * Copyright (c) 2013-2018, Andreas Schneider * Copyright (c) 2014-2017, Michael Adam * Copyright (c) 2016-2018, Anoop C S * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 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. * * 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. * * 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 is set. */ #include "config.h" #include #include #include #include #include #ifdef HAVE_SYS_FILIO_H #include #endif #ifdef HAVE_SYS_SIGNALFD_H #include #endif #ifdef HAVE_SYS_EVENTFD_H #include #endif #ifdef HAVE_SYS_TIMERFD_H #include #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef HAVE_GNU_LIB_NAMES_H #include #endif #ifdef HAVE_RPC_RPC_H #include #endif #include 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_CONSTRUCTOR_ATTRIBUTE #define CONSTRUCTOR_ATTRIBUTE __attribute__ ((constructor)) #else #define CONSTRUCTOR_ATTRIBUTE #endif /* HAVE_CONSTRUCTOR_ATTRIBUTE */ #ifdef HAVE_DESTRUCTOR_ATTRIBUTE #define DESTRUCTOR_ATTRIBUTE __attribute__ ((destructor)) #else #define DESTRUCTOR_ATTRIBUTE #endif #ifndef FALL_THROUGH # ifdef HAVE_FALLTHROUGH_ATTRIBUTE # define FALL_THROUGH __attribute__ ((fallthrough)) # else /* HAVE_FALLTHROUGH_ATTRIBUTE */ # define FALL_THROUGH ((void)0) # endif /* HAVE_FALLTHROUGH_ATTRIBUTE */ #endif /* FALL_THROUGH */ #ifdef HAVE_ADDRESS_SANITIZER_ATTRIBUTE #define DO_NOT_SANITIZE_ADDRESS_ATTRIBUTE __attribute__((no_sanitize_address)) #else #define DO_NOT_SANITIZE_ADDRESS_ATTRIBUTE #endif #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)) #endif #ifndef ZERO_STRUCT #define ZERO_STRUCT(x) memset((char *)&(x), 0, sizeof(x)) #endif #ifndef ZERO_STRUCTP #define ZERO_STRUCTP(x) do { \ if ((x) != NULL) \ memset((char *)(x), 0, sizeof(*(x))); \ } while(0) #endif #ifndef SAFE_FREE #define SAFE_FREE(x) do { if ((x) != NULL) {free(x); (x)=NULL;} } while(0) #endif #ifndef discard_const #define discard_const(ptr) ((void *)((uintptr_t)(ptr))) #endif #ifndef discard_const_p #define discard_const_p(type, ptr) ((type *)discard_const(ptr)) #endif #define UNUSED(x) (void)(x) #ifdef IPV6_PKTINFO # ifndef IPV6_RECVPKTINFO # define IPV6_RECVPKTINFO IPV6_PKTINFO # endif /* IPV6_RECVPKTINFO */ #endif /* IPV6_PKTINFO */ /* * 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 /* Add new global locks here please */ # define SWRAP_LOCK_ALL \ swrap_mutex_lock(&libc_symbol_binding_mutex); \ # define SWRAP_UNLOCK_ALL \ swrap_mutex_unlock(&libc_symbol_binding_mutex); \ #define SOCKET_INFO_CONTAINER(si) \ (struct socket_info_container *)(si) #define SWRAP_LOCK_SI(si) do { \ struct socket_info_container *sic = SOCKET_INFO_CONTAINER(si); \ swrap_mutex_lock(&sic->meta.mutex); \ } while(0) #define SWRAP_UNLOCK_SI(si) do { \ struct socket_info_container *sic = SOCKET_INFO_CONTAINER(si); \ swrap_mutex_unlock(&sic->meta.mutex); \ } while(0) #if defined(HAVE_GETTIMEOFDAY_TZ) || defined(HAVE_GETTIMEOFDAY_TZ_VOID) #define swrapGetTimeOfDay(tval) gettimeofday(tval,NULL) #else #define swrapGetTimeOfDay(tval) gettimeofday(tval) #endif /* 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 can't tell which port a packet came from with recvfrom() with this format we have 8 chars left for the directory name */ #define SOCKET_FORMAT "%c%02X%04X" #define SOCKET_TYPE_CHAR_TCP 'T' #define SOCKET_TYPE_CHAR_UDP 'U' #define SOCKET_TYPE_CHAR_TCP_V6 'X' #define SOCKET_TYPE_CHAR_UDP_V6 'Y' /* * Set the packet MTU to 1500 bytes for stream sockets to make it it easier to * format PCAP capture files (as the caller will simply continue from here). */ #define SOCKET_WRAPPER_MTU_DEFAULT 1500 #define SOCKET_WRAPPER_MTU_MIN 512 #define SOCKET_WRAPPER_MTU_MAX 32768 #define SOCKET_MAX_SOCKETS 1024 /* * Maximum number of socket_info structures that can * be used. Can be overriden by the environment variable * SOCKET_WRAPPER_MAX_SOCKETS. */ #define SOCKET_WRAPPER_MAX_SOCKETS_DEFAULT 65535 #define SOCKET_WRAPPER_MAX_SOCKETS_LIMIT 262140 /* This limit is to avoid broadcast sendto() needing to stat too many * files. It may be raised (with a performance cost) to up to 254 * without changing the format above */ #define MAX_WRAPPED_INTERFACES 64 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; }; int first_free; struct socket_info { int family; int type; int protocol; int bound; int bcast; int is_server; int connected; int defer_connect; int pktinfo; int tcp_nodelay; /* The unix path so we can unlink it on close() */ struct sockaddr_un un_addr; struct swrap_address bindname; struct swrap_address myname; struct swrap_address peername; struct { unsigned long pck_snd; unsigned long pck_rcv; } io; }; struct socket_info_meta { unsigned int refcount; int next_free; pthread_mutex_t mutex; }; struct socket_info_container { struct socket_info info; struct socket_info_meta meta; }; static struct socket_info_container *sockets; static size_t socket_info_max = 0; /* * Allocate the socket array always on the limit value. We want it to be * at least bigger than the default so if we reach the limit we can * still deal with duplicate fds pointing to the same socket_info. */ static size_t socket_fds_max = SOCKET_WRAPPER_MAX_SOCKETS_LIMIT; /* Hash table to map fds to corresponding socket_info index */ static int *socket_fds_idx; /* Mutex to synchronize access to global libc.symbols */ static pthread_mutex_t libc_symbol_binding_mutex = PTHREAD_MUTEX_INITIALIZER; /* Mutex for syncronizing port selection during swrap_auto_bind() */ static pthread_mutex_t autobind_start_mutex; /* Mutex to guard the initialization of array of socket_info structures */ static pthread_mutex_t sockets_mutex; /* Mutex to guard the socket reset in swrap_close() and swrap_remove_stale() */ static pthread_mutex_t socket_reset_mutex; /* Mutex to synchronize access to first free index in socket_info array */ static pthread_mutex_t first_free_mutex; /* Mutex to synchronize access to packet capture dump file */ static pthread_mutex_t pcap_dump_mutex; /* Mutex for synchronizing mtu value fetch*/ static pthread_mutex_t mtu_update_mutex; /* Function prototypes */ bool socket_wrapper_enabled(void); void swrap_constructor(void) CONSTRUCTOR_ATTRIBUTE; void swrap_destructor(void) DESTRUCTOR_ATTRIBUTE; #ifndef HAVE_GETPROGNAME static const char *getprogname(void) { #if defined(HAVE_PROGRAM_INVOCATION_SHORT_NAME) return program_invocation_short_name; #elif defined(HAVE_GETEXECNAME) return getexecname(); #else return NULL; #endif /* HAVE_PROGRAM_INVOCATION_SHORT_NAME */ } #endif /* HAVE_GETPROGNAME */ static void swrap_log(enum swrap_dbglvl_e dbglvl, const char *func, const char *format, ...) PRINTF_ATTRIBUTE(3, 4); # define SWRAP_LOG(dbglvl, ...) swrap_log((dbglvl), __func__, __VA_ARGS__) static void swrap_log(enum swrap_dbglvl_e dbglvl, const char *func, const char *format, ...) { char buffer[1024]; va_list va; const char *d; unsigned int lvl = 0; const char *prefix = "SWRAP"; const char *progname = getprogname(); d = getenv("SOCKET_WRAPPER_DEBUGLEVEL"); if (d != NULL) { lvl = atoi(d); } if (lvl < dbglvl) { return; } va_start(va, format); vsnprintf(buffer, sizeof(buffer), format, va); va_end(va); switch (dbglvl) { case SWRAP_LOG_ERROR: prefix = "SWRAP_ERROR"; break; case SWRAP_LOG_WARN: prefix = "SWRAP_WARN"; break; case SWRAP_LOG_DEBUG: prefix = "SWRAP_DEBUG"; break; case SWRAP_LOG_TRACE: prefix = "SWRAP_TRACE"; break; } if (progname == NULL) { progname = ""; } fprintf(stderr, "%s[%s (%u)] - %s: %s\n", prefix, progname, (unsigned int)getpid(), func, buffer); } /********************************************************* * SWRAP LOADING LIBC FUNCTIONS *********************************************************/ #include #ifdef HAVE_ACCEPT4 typedef int (*__libc_accept4)(int sockfd, struct sockaddr *addr, socklen_t *addrlen, int flags); #else typedef int (*__libc_accept)(int sockfd, struct sockaddr *addr, socklen_t *addrlen); #endif typedef int (*__libc_bind)(int sockfd, const struct sockaddr *addr, socklen_t addrlen); typedef int (*__libc_close)(int fd); typedef int (*__libc_connect)(int sockfd, const struct sockaddr *addr, socklen_t addrlen); typedef int (*__libc_dup)(int fd); typedef int (*__libc_dup2)(int oldfd, int newfd); typedef int (*__libc_fcntl)(int fd, int cmd, ...); typedef FILE *(*__libc_fopen)(const char *name, const char *mode); #ifdef HAVE_FOPEN64 typedef FILE *(*__libc_fopen64)(const char *name, const char *mode); #endif #ifdef HAVE_EVENTFD typedef int (*__libc_eventfd)(int count, int flags); #endif typedef int (*__libc_getpeername)(int sockfd, struct sockaddr *addr, socklen_t *addrlen); typedef int (*__libc_getsockname)(int sockfd, struct sockaddr *addr, socklen_t *addrlen); typedef int (*__libc_getsockopt)(int sockfd, int level, int optname, void *optval, socklen_t *optlen); typedef int (*__libc_ioctl)(int d, unsigned long int request, ...); typedef int (*__libc_listen)(int sockfd, int backlog); typedef int (*__libc_open)(const char *pathname, int flags, ...); #ifdef HAVE_OPEN64 typedef int (*__libc_open64)(const char *pathname, int flags, ...); #endif /* HAVE_OPEN64 */ typedef int (*__libc_openat)(int dirfd, const char *path, int flags, ...); typedef int (*__libc_pipe)(int pipefd[2]); typedef int (*__libc_read)(int fd, void *buf, size_t count); typedef ssize_t (*__libc_readv)(int fd, const struct iovec *iov, int iovcnt); typedef int (*__libc_recv)(int sockfd, void *buf, size_t len, int flags); typedef int (*__libc_recvfrom)(int sockfd, void *buf, size_t len, int flags, struct sockaddr *src_addr, socklen_t *addrlen); typedef int (*__libc_recvmsg)(int sockfd, const struct msghdr *msg, int flags); typedef int (*__libc_send)(int sockfd, const void *buf, size_t len, int flags); typedef int (*__libc_sendmsg)(int sockfd, const struct msghdr *msg, int flags); typedef int (*__libc_sendto)(int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *dst_addr, socklen_t addrlen); typedef int (*__libc_setsockopt)(int sockfd, int level, int optname, const void *optval, socklen_t optlen); #ifdef HAVE_SIGNALFD typedef int (*__libc_signalfd)(int fd, const sigset_t *mask, int flags); #endif typedef int (*__libc_socket)(int domain, int type, int protocol); typedef int (*__libc_socketpair)(int domain, int type, int protocol, int sv[2]); #ifdef HAVE_TIMERFD_CREATE typedef int (*__libc_timerfd_create)(int clockid, int flags); #endif typedef ssize_t (*__libc_write)(int fd, const void *buf, size_t count); typedef ssize_t (*__libc_writev)(int fd, const struct iovec *iov, int iovcnt); #define SWRAP_SYMBOL_ENTRY(i) \ union { \ __libc_##i f; \ void *obj; \ } _libc_##i struct swrap_libc_symbols { #ifdef HAVE_ACCEPT4 SWRAP_SYMBOL_ENTRY(accept4); #else SWRAP_SYMBOL_ENTRY(accept); #endif SWRAP_SYMBOL_ENTRY(bind); SWRAP_SYMBOL_ENTRY(close); SWRAP_SYMBOL_ENTRY(connect); SWRAP_SYMBOL_ENTRY(dup); SWRAP_SYMBOL_ENTRY(dup2); SWRAP_SYMBOL_ENTRY(fcntl); SWRAP_SYMBOL_ENTRY(fopen); #ifdef HAVE_FOPEN64 SWRAP_SYMBOL_ENTRY(fopen64); #endif #ifdef HAVE_EVENTFD SWRAP_SYMBOL_ENTRY(eventfd); #endif SWRAP_SYMBOL_ENTRY(getpeername); SWRAP_SYMBOL_ENTRY(getsockname); SWRAP_SYMBOL_ENTRY(getsockopt); SWRAP_SYMBOL_ENTRY(ioctl); SWRAP_SYMBOL_ENTRY(listen); SWRAP_SYMBOL_ENTRY(open); #ifdef HAVE_OPEN64 SWRAP_SYMBOL_ENTRY(open64); #endif SWRAP_SYMBOL_ENTRY(openat); SWRAP_SYMBOL_ENTRY(pipe); SWRAP_SYMBOL_ENTRY(read); SWRAP_SYMBOL_ENTRY(readv); SWRAP_SYMBOL_ENTRY(recv); SWRAP_SYMBOL_ENTRY(recvfrom); SWRAP_SYMBOL_ENTRY(recvmsg); SWRAP_SYMBOL_ENTRY(send); SWRAP_SYMBOL_ENTRY(sendmsg); SWRAP_SYMBOL_ENTRY(sendto); SWRAP_SYMBOL_ENTRY(setsockopt); #ifdef HAVE_SIGNALFD SWRAP_SYMBOL_ENTRY(signalfd); #endif SWRAP_SYMBOL_ENTRY(socket); SWRAP_SYMBOL_ENTRY(socketpair); #ifdef HAVE_TIMERFD_CREATE SWRAP_SYMBOL_ENTRY(timerfd_create); #endif SWRAP_SYMBOL_ENTRY(write); SWRAP_SYMBOL_ENTRY(writev); }; struct swrap { struct { void *handle; void *socket_handle; struct swrap_libc_symbols symbols; } libc; }; static struct swrap swrap; /* prototypes */ static char *socket_wrapper_dir(void); #define LIBC_NAME "libc.so" enum swrap_lib { SWRAP_LIBC, SWRAP_LIBNSL, SWRAP_LIBSOCKET, }; 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"; } static void *swrap_load_lib_handle(enum swrap_lib lib) { int flags = RTLD_LAZY; void *handle = NULL; int i; #ifdef RTLD_DEEPBIND const char *env_preload = getenv("LD_PRELOAD"); const char *env_deepbind = getenv("SOCKET_WRAPPER_DISABLE_DEEPBIND"); bool enable_deepbind = true; /* Don't do a deepbind if we run with libasan */ if (env_preload != NULL && strlen(env_preload) < 1024) { const char *p = strstr(env_preload, "libasan.so"); if (p != NULL) { enable_deepbind = false; } } if (env_deepbind != NULL && strlen(env_deepbind) >= 1) { enable_deepbind = false; } if (enable_deepbind) { flags |= RTLD_DEEPBIND; } #endif switch (lib) { case SWRAP_LIBNSL: case SWRAP_LIBSOCKET: #ifdef HAVE_LIBSOCKET handle = swrap.libc.socket_handle; if (handle == NULL) { for (i = 10; i >= 0; i--) { char soname[256] = {0}; snprintf(soname, sizeof(soname), "libsocket.so.%d", i); handle = dlopen(soname, flags); if (handle != NULL) { break; } } swrap.libc.socket_handle = handle; } break; #endif case SWRAP_LIBC: handle = swrap.libc.handle; #ifdef LIBC_SO if (handle == NULL) { handle = dlopen(LIBC_SO, flags); swrap.libc.handle = handle; } #endif if (handle == NULL) { for (i = 10; i >= 0; i--) { char soname[256] = {0}; snprintf(soname, sizeof(soname), "libc.so.%d", i); handle = dlopen(soname, flags); if (handle != NULL) { break; } } swrap.libc.handle = handle; } break; } if (handle == NULL) { #ifdef RTLD_NEXT handle = swrap.libc.handle = swrap.libc.socket_handle = RTLD_NEXT; #else SWRAP_LOG(SWRAP_LOG_ERROR, "Failed to dlopen library: %s\n", dlerror()); exit(-1); #endif } return handle; } static void *_swrap_bind_symbol(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; } static void swrap_mutex_lock(pthread_mutex_t *mutex) { int ret; ret = pthread_mutex_lock(mutex); if (ret != 0) { SWRAP_LOG(SWRAP_LOG_ERROR, "Couldn't lock pthread mutex - %s", strerror(ret)); } } static void swrap_mutex_unlock(pthread_mutex_t *mutex) { int ret; ret = pthread_mutex_unlock(mutex); if (ret != 0) { SWRAP_LOG(SWRAP_LOG_ERROR, "Couldn't unlock pthread mutex - %s", strerror(ret)); } } /* * These macros have a thread race condition on purpose! * * This is an optimization to avoid locking each time we check if the symbol is * bound. */ #define swrap_bind_symbol_libc(sym_name) \ if (swrap.libc.symbols._libc_##sym_name.obj == NULL) { \ swrap_mutex_lock(&libc_symbol_binding_mutex); \ if (swrap.libc.symbols._libc_##sym_name.obj == NULL) { \ swrap.libc.symbols._libc_##sym_name.obj = \ _swrap_bind_symbol(SWRAP_LIBC, #sym_name); \ } \ swrap_mutex_unlock(&libc_symbol_binding_mutex); \ } #define swrap_bind_symbol_libsocket(sym_name) \ if (swrap.libc.symbols._libc_##sym_name.obj == NULL) { \ swrap_mutex_lock(&libc_symbol_binding_mutex); \ if (swrap.libc.symbols._libc_##sym_name.obj == NULL) { \ swrap.libc.symbols._libc_##sym_name.obj = \ _swrap_bind_symbol(SWRAP_LIBSOCKET, #sym_name); \ } \ swrap_mutex_unlock(&libc_symbol_binding_mutex); \ } #define swrap_bind_symbol_libnsl(sym_name) \ if (swrap.libc.symbols._libc_##sym_name.obj == NULL) { \ swrap_mutex_lock(&libc_symbol_binding_mutex); \ if (swrap.libc.symbols._libc_##sym_name.obj == NULL) { \ swrap.libc.symbols._libc_##sym_name.obj = \ _swrap_bind_symbol(SWRAP_LIBNSL, #sym_name); \ } \ swrap_mutex_unlock(&libc_symbol_binding_mutex); \ } /**************************************************************************** * IMPORTANT **************************************************************************** * * Functions especially from libc need to be loaded individually, you can't * load all at once or gdb will segfault at startup. The same applies to * valgrind and has probably something todo with with the linker. So we need * load each function at the point it is called the first time. * ****************************************************************************/ #ifdef HAVE_ACCEPT4 static int libc_accept4(int sockfd, struct sockaddr *addr, socklen_t *addrlen, int flags) { swrap_bind_symbol_libsocket(accept4); return swrap.libc.symbols._libc_accept4.f(sockfd, addr, addrlen, flags); } #else /* HAVE_ACCEPT4 */ static int libc_accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen) { swrap_bind_symbol_libsocket(accept); return swrap.libc.symbols._libc_accept.f(sockfd, addr, addrlen); } #endif /* HAVE_ACCEPT4 */ static int libc_bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen) { swrap_bind_symbol_libsocket(bind); return swrap.libc.symbols._libc_bind.f(sockfd, addr, addrlen); } static int libc_close(int fd) { swrap_bind_symbol_libc(close); return swrap.libc.symbols._libc_close.f(fd); } static int libc_connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen) { swrap_bind_symbol_libsocket(connect); return swrap.libc.symbols._libc_connect.f(sockfd, addr, addrlen); } static int libc_dup(int fd) { swrap_bind_symbol_libc(dup); return swrap.libc.symbols._libc_dup.f(fd); } static int libc_dup2(int oldfd, int newfd) { swrap_bind_symbol_libc(dup2); return swrap.libc.symbols._libc_dup2.f(oldfd, newfd); } #ifdef HAVE_EVENTFD static int libc_eventfd(int count, int flags) { swrap_bind_symbol_libc(eventfd); return swrap.libc.symbols._libc_eventfd.f(count, flags); } #endif DO_NOT_SANITIZE_ADDRESS_ATTRIBUTE static int libc_vfcntl(int fd, int cmd, va_list ap) { void *arg; int rc; swrap_bind_symbol_libc(fcntl); arg = va_arg(ap, void *); rc = swrap.libc.symbols._libc_fcntl.f(fd, cmd, arg); return rc; } static int libc_getpeername(int sockfd, struct sockaddr *addr, socklen_t *addrlen) { swrap_bind_symbol_libsocket(getpeername); return swrap.libc.symbols._libc_getpeername.f(sockfd, addr, addrlen); } static int libc_getsockname(int sockfd, struct sockaddr *addr, socklen_t *addrlen) { swrap_bind_symbol_libsocket(getsockname); return swrap.libc.symbols._libc_getsockname.f(sockfd, addr, addrlen); } static int libc_getsockopt(int sockfd, int level, int optname, void *optval, socklen_t *optlen) { swrap_bind_symbol_libsocket(getsockopt); return swrap.libc.symbols._libc_getsockopt.f(sockfd, level, optname, optval, optlen); } DO_NOT_SANITIZE_ADDRESS_ATTRIBUTE static int libc_vioctl(int d, unsigned long int request, va_list ap) { void *arg; int rc; swrap_bind_symbol_libc(ioctl); arg = va_arg(ap, void *); rc = swrap.libc.symbols._libc_ioctl.f(d, request, arg); return rc; } static int libc_listen(int sockfd, int backlog) { swrap_bind_symbol_libsocket(listen); return swrap.libc.symbols._libc_listen.f(sockfd, backlog); } static FILE *libc_fopen(const char *name, const char *mode) { swrap_bind_symbol_libc(fopen); return swrap.libc.symbols._libc_fopen.f(name, mode); } #ifdef HAVE_FOPEN64 static FILE *libc_fopen64(const char *name, const char *mode) { swrap_bind_symbol_libc(fopen64); return swrap.libc.symbols._libc_fopen64.f(name, mode); } #endif /* HAVE_FOPEN64 */ static int libc_vopen(const char *pathname, int flags, va_list ap) { int mode = 0; int fd; swrap_bind_symbol_libc(open); if (flags & O_CREAT) { mode = va_arg(ap, int); } fd = swrap.libc.symbols._libc_open.f(pathname, flags, (mode_t)mode); return fd; } 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; } #ifdef HAVE_OPEN64 static int libc_vopen64(const char *pathname, int flags, va_list ap) { int mode = 0; int fd; swrap_bind_symbol_libc(open64); if (flags & O_CREAT) { mode = va_arg(ap, int); } fd = swrap.libc.symbols._libc_open64.f(pathname, flags, (mode_t)mode); return fd; } #endif /* HAVE_OPEN64 */ static int libc_vopenat(int dirfd, const char *path, int flags, va_list ap) { int mode = 0; int fd; swrap_bind_symbol_libc(openat); if (flags & O_CREAT) { mode = va_arg(ap, int); } fd = swrap.libc.symbols._libc_openat.f(dirfd, path, flags, (mode_t)mode); return fd; } #if 0 static int libc_openat(int dirfd, const char *path, int flags, ...) { va_list ap; int fd; va_start(ap, flags); fd = libc_vopenat(dirfd, path, flags, ap); va_end(ap); return fd; } #endif static int libc_pipe(int pipefd[2]) { swrap_bind_symbol_libsocket(pipe); return swrap.libc.symbols._libc_pipe.f(pipefd); } static int libc_read(int fd, void *buf, size_t count) { swrap_bind_symbol_libc(read); return swrap.libc.symbols._libc_read.f(fd, buf, count); } static ssize_t libc_readv(int fd, const struct iovec *iov, int iovcnt) { swrap_bind_symbol_libsocket(readv); return swrap.libc.symbols._libc_readv.f(fd, iov, iovcnt); } static int libc_recv(int sockfd, void *buf, size_t len, int flags) { swrap_bind_symbol_libsocket(recv); return swrap.libc.symbols._libc_recv.f(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_bind_symbol_libsocket(recvfrom); return swrap.libc.symbols._libc_recvfrom.f(sockfd, buf, len, flags, src_addr, addrlen); } static int libc_recvmsg(int sockfd, struct msghdr *msg, int flags) { swrap_bind_symbol_libsocket(recvmsg); return swrap.libc.symbols._libc_recvmsg.f(sockfd, msg, flags); } static int libc_send(int sockfd, const void *buf, size_t len, int flags) { swrap_bind_symbol_libsocket(send); return swrap.libc.symbols._libc_send.f(sockfd, buf, len, flags); } static int libc_sendmsg(int sockfd, const struct msghdr *msg, int flags) { swrap_bind_symbol_libsocket(sendmsg); return swrap.libc.symbols._libc_sendmsg.f(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_bind_symbol_libsocket(sendto); return swrap.libc.symbols._libc_sendto.f(sockfd, buf, len, flags, dst_addr, addrlen); } static int libc_setsockopt(int sockfd, int level, int optname, const void *optval, socklen_t optlen) { swrap_bind_symbol_libsocket(setsockopt); return swrap.libc.symbols._libc_setsockopt.f(sockfd, level, optname, optval, optlen); } #ifdef HAVE_SIGNALFD static int libc_signalfd(int fd, const sigset_t *mask, int flags) { swrap_bind_symbol_libsocket(signalfd); return swrap.libc.symbols._libc_signalfd.f(fd, mask, flags); } #endif static int libc_socket(int domain, int type, int protocol) { swrap_bind_symbol_libsocket(socket); return swrap.libc.symbols._libc_socket.f(domain, type, protocol); } static int libc_socketpair(int domain, int type, int protocol, int sv[2]) { swrap_bind_symbol_libsocket(socketpair); return swrap.libc.symbols._libc_socketpair.f(domain, type, protocol, sv); } #ifdef HAVE_TIMERFD_CREATE static int libc_timerfd_create(int clockid, int flags) { swrap_bind_symbol_libc(timerfd_create); return swrap.libc.symbols._libc_timerfd_create.f(clockid, flags); } #endif static ssize_t libc_write(int fd, const void *buf, size_t count) { swrap_bind_symbol_libc(write); return swrap.libc.symbols._libc_write.f(fd, buf, count); } static ssize_t libc_writev(int fd, const struct iovec *iov, int iovcnt) { swrap_bind_symbol_libsocket(writev); return swrap.libc.symbols._libc_writev.f(fd, iov, iovcnt); } /* DO NOT call this function during library initialization! */ static void swrap_bind_symbol_all(void) { #ifdef HAVE_ACCEPT4 swrap_bind_symbol_libsocket(accept4); #else swrap_bind_symbol_libsocket(accept); #endif swrap_bind_symbol_libsocket(bind); swrap_bind_symbol_libc(close); swrap_bind_symbol_libsocket(connect); swrap_bind_symbol_libc(dup); swrap_bind_symbol_libc(dup2); swrap_bind_symbol_libc(fcntl); swrap_bind_symbol_libc(fopen); #ifdef HAVE_FOPEN64 swrap_bind_symbol_libc(fopen64); #endif #ifdef HAVE_EVENTFD swrap_bind_symbol_libc(eventfd); #endif swrap_bind_symbol_libsocket(getpeername); swrap_bind_symbol_libsocket(getsockname); swrap_bind_symbol_libsocket(getsockopt); swrap_bind_symbol_libc(ioctl); swrap_bind_symbol_libsocket(listen); swrap_bind_symbol_libc(open); #ifdef HAVE_OPEN64 swrap_bind_symbol_libc(open64); #endif swrap_bind_symbol_libc(openat); swrap_bind_symbol_libsocket(pipe); swrap_bind_symbol_libc(read); swrap_bind_symbol_libsocket(readv); swrap_bind_symbol_libsocket(recv); swrap_bind_symbol_libsocket(recvfrom); swrap_bind_symbol_libsocket(recvmsg); swrap_bind_symbol_libsocket(send); swrap_bind_symbol_libsocket(sendmsg); swrap_bind_symbol_libsocket(sendto); swrap_bind_symbol_libsocket(setsockopt); #ifdef HAVE_SIGNALFD swrap_bind_symbol_libsocket(signalfd); #endif swrap_bind_symbol_libsocket(socket); swrap_bind_symbol_libsocket(socketpair); #ifdef HAVE_TIMERFD_CREATE swrap_bind_symbol_libc(timerfd_create); #endif swrap_bind_symbol_libc(write); swrap_bind_symbol_libsocket(writev); } /********************************************************* * SWRAP HELPER FUNCTIONS *********************************************************/ #ifdef HAVE_IPV6 /* * FD00::5357:5FXX */ 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; } #endif static void set_port(int family, int prt, struct swrap_address *addr) { switch (family) { case AF_INET: addr->sa.in.sin_port = htons(prt); break; #ifdef HAVE_IPV6 case AF_INET6: addr->sa.in6.sin6_port = htons(prt); break; #endif } } static size_t socket_length(int family) { switch (family) { case AF_INET: return sizeof(struct sockaddr_in); #ifdef HAVE_IPV6 case AF_INET6: return sizeof(struct sockaddr_in6); #endif } return 0; } static struct socket_info *swrap_get_socket_info(int si_index) { return (struct socket_info *)(&(sockets[si_index].info)); } static int swrap_get_refcount(struct socket_info *si) { struct socket_info_container *sic = SOCKET_INFO_CONTAINER(si); return sic->meta.refcount; } static void swrap_inc_refcount(struct socket_info *si) { struct socket_info_container *sic = SOCKET_INFO_CONTAINER(si); sic->meta.refcount += 1; } static void swrap_dec_refcount(struct socket_info *si) { struct socket_info_container *sic = SOCKET_INFO_CONTAINER(si); sic->meta.refcount -= 1; } static int swrap_get_next_free(struct socket_info *si) { struct socket_info_container *sic = SOCKET_INFO_CONTAINER(si); return sic->meta.next_free; } static void swrap_set_next_free(struct socket_info *si, int next_free) { struct socket_info_container *sic = SOCKET_INFO_CONTAINER(si); sic->meta.next_free = next_free; } static char *socket_wrapper_dir(void) { char *swrap_dir = NULL; char *s = getenv("SOCKET_WRAPPER_DIR"); if (s == NULL) { SWRAP_LOG(SWRAP_LOG_WARN, "SOCKET_WRAPPER_DIR not set\n"); return NULL; } swrap_dir = realpath(s, NULL); if (swrap_dir == NULL) { SWRAP_LOG(SWRAP_LOG_ERROR, "Unable to resolve socket_wrapper dir path: %s", strerror(errno)); return NULL; } SWRAP_LOG(SWRAP_LOG_TRACE, "socket_wrapper_dir: %s", swrap_dir); return swrap_dir; } static unsigned int socket_wrapper_mtu(void) { static unsigned int max_mtu = 0; unsigned int tmp; const char *s; char *endp; swrap_mutex_lock(&mtu_update_mutex); if (max_mtu != 0) { goto done; } max_mtu = SOCKET_WRAPPER_MTU_DEFAULT; s = getenv("SOCKET_WRAPPER_MTU"); if (s == NULL) { goto done; } tmp = strtol(s, &endp, 10); if (s == endp) { goto done; } if (tmp < SOCKET_WRAPPER_MTU_MIN || tmp > SOCKET_WRAPPER_MTU_MAX) { goto done; } max_mtu = tmp; done: swrap_mutex_unlock(&mtu_update_mutex); return max_mtu; } static int socket_wrapper_init_mutex(pthread_mutex_t *m) { pthread_mutexattr_t ma; int ret; ret = pthread_mutexattr_init(&ma); if (ret != 0) { return ret; } ret = pthread_mutexattr_settype(&ma, PTHREAD_MUTEX_ERRORCHECK); if (ret != 0) { goto done; } ret = pthread_mutex_init(m, &ma); done: pthread_mutexattr_destroy(&ma); return ret; } static size_t socket_wrapper_max_sockets(void) { const char *s; size_t tmp; char *endp; if (socket_info_max != 0) { return socket_info_max; } socket_info_max = SOCKET_WRAPPER_MAX_SOCKETS_DEFAULT; s = getenv("SOCKET_WRAPPER_MAX_SOCKETS"); if (s == NULL || s[0] == '\0') { goto done; } tmp = strtoul(s, &endp, 10); if (s == endp) { goto done; } if (tmp == 0) { tmp = SOCKET_WRAPPER_MAX_SOCKETS_DEFAULT; SWRAP_LOG(SWRAP_LOG_ERROR, "Invalid number of sockets specified, " "using default (%zu)", tmp); } if (tmp > SOCKET_WRAPPER_MAX_SOCKETS_LIMIT) { tmp = SOCKET_WRAPPER_MAX_SOCKETS_LIMIT; SWRAP_LOG(SWRAP_LOG_ERROR, "Invalid number of sockets specified, " "using maximum (%zu).", tmp); } socket_info_max = tmp; done: return socket_info_max; } static void socket_wrapper_init_fds_idx(void) { int *tmp = NULL; size_t i; if (socket_fds_idx != NULL) { return; } tmp = (int *)calloc(socket_fds_max, sizeof(int)); if (tmp == NULL) { SWRAP_LOG(SWRAP_LOG_ERROR, "Failed to allocate socket fds index array: %s", strerror(errno)); exit(-1); } for (i = 0; i < socket_fds_max; i++) { tmp[i] = -1; } socket_fds_idx = tmp; } static void socket_wrapper_init_sockets(void) { size_t max_sockets; size_t i; int ret; swrap_mutex_lock(&sockets_mutex); if (sockets != NULL) { swrap_mutex_unlock(&sockets_mutex); return; } socket_wrapper_init_fds_idx(); /* Needs to be called inside the sockets_mutex lock here. */ max_sockets = socket_wrapper_max_sockets(); sockets = (struct socket_info_container *)calloc(max_sockets, sizeof(struct socket_info_container)); if (sockets == NULL) { SWRAP_LOG(SWRAP_LOG_ERROR, "Failed to allocate sockets array: %s", strerror(errno)); swrap_mutex_unlock(&sockets_mutex); exit(-1); } swrap_mutex_lock(&first_free_mutex); first_free = 0; for (i = 0; i < max_sockets; i++) { swrap_set_next_free(&sockets[i].info, i+1); ret = socket_wrapper_init_mutex(&sockets[i].meta.mutex); if (ret != 0) { SWRAP_LOG(SWRAP_LOG_ERROR, "Failed to initialize pthread mutex"); goto done; } } /* mark the end of the free list */ swrap_set_next_free(&sockets[max_sockets-1].info, -1); ret = socket_wrapper_init_mutex(&autobind_start_mutex); if (ret != 0) { SWRAP_LOG(SWRAP_LOG_ERROR, "Failed to initialize pthread mutex"); goto done; } ret = socket_wrapper_init_mutex(&pcap_dump_mutex); if (ret != 0) { SWRAP_LOG(SWRAP_LOG_ERROR, "Failed to initialize pthread mutex"); goto done; } ret = socket_wrapper_init_mutex(&mtu_update_mutex); if (ret != 0) { SWRAP_LOG(SWRAP_LOG_ERROR, "Failed to initialize pthread mutex"); goto done; } done: swrap_mutex_unlock(&first_free_mutex); swrap_mutex_unlock(&sockets_mutex); if (ret != 0) { exit(-1); } } bool socket_wrapper_enabled(void) { char *s = socket_wrapper_dir(); if (s == NULL) { return false; } SAFE_FREE(s); socket_wrapper_init_sockets(); return true; } static unsigned int socket_wrapper_default_iface(void) { const char *s = getenv("SOCKET_WRAPPER_DEFAULT_IFACE"); if (s) { unsigned int iface; if (sscanf(s, "%u", &iface) == 1) { if (iface >= 1 && iface <= MAX_WRAPPED_INTERFACES) { return iface; } } } return 1;/* 127.0.0.1 */ } static void set_socket_info_index(int fd, int idx) { socket_fds_idx[fd] = idx; /* This builtin issues a full memory barrier. */ __sync_synchronize(); } static void reset_socket_info_index(int fd) { set_socket_info_index(fd, -1); } static int find_socket_info_index(int fd) { if (fd < 0) { return -1; } if (socket_fds_idx == NULL) { return -1; } if ((size_t)fd >= socket_fds_max) { /* * Do not add a log here as some applications do stupid things * like: * * for (fd = 0; fd <= getdtablesize(); fd++) { * close(fd) * }; * * This would produce millions of lines of debug messages. */ #if 0 SWRAP_LOG(SWRAP_LOG_ERROR, "Looking for a socket info for the fd %d is over the " "max socket index limit of %zu.", fd, socket_fds_max); #endif return -1; } /* This builtin issues a full memory barrier. */ __sync_synchronize(); return socket_fds_idx[fd]; } static int swrap_add_socket_info(struct socket_info *si_input) { struct socket_info *si = NULL; int si_index = -1; if (si_input == NULL) { errno = EINVAL; return -1; } swrap_mutex_lock(&first_free_mutex); if (first_free == -1) { errno = ENFILE; goto out; } si_index = first_free; si = swrap_get_socket_info(si_index); SWRAP_LOCK_SI(si); first_free = swrap_get_next_free(si); *si = *si_input; swrap_inc_refcount(si); SWRAP_UNLOCK_SI(si); out: swrap_mutex_unlock(&first_free_mutex); return si_index; } static int swrap_create_socket(struct socket_info *si, int fd) { int idx; if ((size_t)fd >= socket_fds_max) { SWRAP_LOG(SWRAP_LOG_ERROR, "The max socket index limit of %zu has been reached, " "trying to add %d", socket_fds_max, fd); return -1; } idx = swrap_add_socket_info(si); if (idx == -1) { return -1; } set_socket_info_index(fd, idx); return idx; } static int convert_un_in(const struct sockaddr_un *un, struct sockaddr *in, socklen_t *len) { unsigned int iface; unsigned int prt; const char *p; char type; p = strrchr(un->sun_path, '/'); if (p) p++; else p = un->sun_path; if (sscanf(p, SOCKET_FORMAT, &type, &iface, &prt) != 3) { errno = EINVAL; return -1; } SWRAP_LOG(SWRAP_LOG_TRACE, "type %c iface %u port %u", type, iface, prt); if (iface == 0 || iface > MAX_WRAPPED_INTERFACES) { errno = EINVAL; return -1; } if (prt > 0xFFFF) { errno = EINVAL; return -1; } switch(type) { case SOCKET_TYPE_CHAR_TCP: case SOCKET_TYPE_CHAR_UDP: { struct sockaddr_in *in2 = (struct sockaddr_in *)(void *)in; 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: { struct sockaddr_in6 *in2 = (struct sockaddr_in6 *)(void *)in; if ((*len) < sizeof(*in2)) { errno = EINVAL; return -1; } memset(in2, 0, sizeof(*in2)); in2->sin6_family = AF_INET6; in2->sin6_addr = *swrap_ipv6(); in2->sin6_addr.s6_addr[15] = iface; in2->sin6_port = htons(prt); *len = sizeof(*in2); break; } #endif default: errno = EINVAL; return -1; } return 0; } static int convert_in_un_remote(struct socket_info *si, const struct sockaddr *inaddr, struct sockaddr_un *un, int *bcast) { char type = '\0'; unsigned int prt; unsigned int iface; int is_bcast = 0; char *swrap_dir = NULL; if (bcast) *bcast = 0; switch (inaddr->sa_family) { case AF_INET: { const struct sockaddr_in *in = (const struct sockaddr_in *)(const void *)inaddr; unsigned int addr = ntohl(in->sin_addr.s_addr); char u_type = '\0'; char b_type = '\0'; char a_type = '\0'; 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; default: SWRAP_LOG(SWRAP_LOG_ERROR, "Unknown socket type!\n"); errno = ESOCKTNOSUPPORT; return -1; } 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; break; } #ifdef HAVE_IPV6 case AF_INET6: { const struct sockaddr_in6 *in = (const struct sockaddr_in6 *)(const void *)inaddr; struct in6_addr cmp1, cmp2; switch (si->type) { case SOCK_STREAM: type = SOCKET_TYPE_CHAR_TCP_V6; break; case SOCK_DGRAM: type = SOCKET_TYPE_CHAR_UDP_V6; break; default: SWRAP_LOG(SWRAP_LOG_ERROR, "Unknown socket type!\n"); errno = ESOCKTNOSUPPORT; return -1; } /* XXX no multicast/broadcast */ prt = ntohs(in->sin6_port); cmp1 = *swrap_ipv6(); cmp2 = in->sin6_addr; cmp2.s6_addr[15] = 0; if (IN6_ARE_ADDR_EQUAL(&cmp1, &cmp2)) { iface = in->sin6_addr.s6_addr[15]; } else { errno = ENETUNREACH; return -1; } break; } #endif default: SWRAP_LOG(SWRAP_LOG_ERROR, "Unknown address family!\n"); errno = ENETUNREACH; return -1; } if (prt == 0) { SWRAP_LOG(SWRAP_LOG_WARN, "Port not set\n"); errno = EINVAL; return -1; } swrap_dir = socket_wrapper_dir(); if (swrap_dir == NULL) { errno = EINVAL; return -1; } if (is_bcast) { snprintf(un->sun_path, sizeof(un->sun_path), "%s/EINVAL", swrap_dir); SWRAP_LOG(SWRAP_LOG_DEBUG, "un path [%s]", un->sun_path); SAFE_FREE(swrap_dir); /* the caller need to do more processing */ return 0; } snprintf(un->sun_path, sizeof(un->sun_path), "%s/"SOCKET_FORMAT, swrap_dir, type, iface, prt); SWRAP_LOG(SWRAP_LOG_DEBUG, "un path [%s]", un->sun_path); SAFE_FREE(swrap_dir); return 0; } static int convert_in_un_alloc(struct socket_info *si, const struct sockaddr *inaddr, struct sockaddr_un *un, int *bcast) { char type = '\0'; unsigned int prt; unsigned int iface; struct stat st; int is_bcast = 0; char *swrap_dir = NULL; if (bcast) *bcast = 0; switch (si->family) { case AF_INET: { const struct sockaddr_in *in = (const struct sockaddr_in *)(const void *)inaddr; 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; default: SWRAP_LOG(SWRAP_LOG_ERROR, "Unknown socket type!\n"); errno = ESOCKTNOSUPPORT; return -1; } 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; } /* Store the bind address for connect() */ if (si->bindname.sa_socklen == 0) { struct sockaddr_in bind_in; socklen_t blen = sizeof(struct sockaddr_in); ZERO_STRUCT(bind_in); bind_in.sin_family = in->sin_family; bind_in.sin_port = in->sin_port; bind_in.sin_addr.s_addr = htonl(0x7F000000 | iface); si->bindname.sa_socklen = blen; memcpy(&si->bindname.sa.in, &bind_in, blen); } break; } #ifdef HAVE_IPV6 case AF_INET6: { const struct sockaddr_in6 *in = (const struct sockaddr_in6 *)(const void *)inaddr; struct in6_addr cmp1, cmp2; switch (si->type) { case SOCK_STREAM: type = SOCKET_TYPE_CHAR_TCP_V6; break; case SOCK_DGRAM: type = SOCKET_TYPE_CHAR_UDP_V6; break; default: SWRAP_LOG(SWRAP_LOG_ERROR, "Unknown socket type!\n"); errno = ESOCKTNOSUPPORT; return -1; } /* XXX no multicast/broadcast */ prt = ntohs(in->sin6_port); cmp1 = *swrap_ipv6(); cmp2 = in->sin6_addr; cmp2.s6_addr[15] = 0; if (IN6_IS_ADDR_UNSPECIFIED(&in->sin6_addr)) { iface = socket_wrapper_default_iface(); } else if (IN6_ARE_ADDR_EQUAL(&cmp1, &cmp2)) { iface = in->sin6_addr.s6_addr[15]; } else { errno = EADDRNOTAVAIL; return -1; } /* Store the bind address for connect() */ if (si->bindname.sa_socklen == 0) { 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; memcpy(&si->bindname.sa.in6, &bind_in, blen); si->bindname.sa_socklen = blen; } break; } #endif default: SWRAP_LOG(SWRAP_LOG_ERROR, "Unknown address family\n"); errno = EADDRNOTAVAIL; return -1; } if (bcast) *bcast = is_bcast; if (iface == 0 || iface > MAX_WRAPPED_INTERFACES) { errno = EINVAL; return -1; } swrap_dir = socket_wrapper_dir(); if (swrap_dir == NULL) { errno = EINVAL; return -1; } if (prt == 0) { /* handle auto-allocation of ephemeral ports */ for (prt = 5001; prt < 10000; prt++) { snprintf(un->sun_path, sizeof(un->sun_path), "%s/"SOCKET_FORMAT, swrap_dir, type, iface, prt); if (stat(un->sun_path, &st) == 0) continue; set_port(si->family, prt, &si->myname); set_port(si->family, prt, &si->bindname); break; } if (prt == 10000) { errno = ENFILE; SAFE_FREE(swrap_dir); return -1; } } snprintf(un->sun_path, sizeof(un->sun_path), "%s/"SOCKET_FORMAT, swrap_dir, type, iface, prt); SWRAP_LOG(SWRAP_LOG_DEBUG, "un path [%s]", un->sun_path); SAFE_FREE(swrap_dir); return 0; } static struct socket_info *find_socket_info(int fd) { int idx = find_socket_info_index(fd); if (idx == -1) { return NULL; } return swrap_get_socket_info(idx); } #if 0 /* FIXME */ static bool check_addr_port_in_use(const struct sockaddr *sa, socklen_t len) { struct socket_info_fd *f; const struct socket_info *last_s = NULL; /* first catch invalid input */ switch (sa->sa_family) { case AF_INET: if (len < sizeof(struct sockaddr_in)) { return false; } break; #ifdef HAVE_IPV6 case AF_INET6: if (len < sizeof(struct sockaddr_in6)) { return false; } break; #endif default: return false; break; } for (f = socket_fds; f; f = f->next) { struct socket_info *s = swrap_get_socket_info(f->si_index); if (s == last_s) { continue; } last_s = s; 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; } #ifdef 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; } #endif static void swrap_remove_stale(int fd) { struct socket_info *si; int si_index; SWRAP_LOG(SWRAP_LOG_TRACE, "remove stale wrapper for %d", fd); swrap_mutex_lock(&socket_reset_mutex); si_index = find_socket_info_index(fd); if (si_index == -1) { swrap_mutex_unlock(&socket_reset_mutex); return; } reset_socket_info_index(fd); si = swrap_get_socket_info(si_index); swrap_mutex_lock(&first_free_mutex); SWRAP_LOCK_SI(si); swrap_dec_refcount(si); if (swrap_get_refcount(si) > 0) { goto out; } if (si->un_addr.sun_path[0] != '\0') { unlink(si->un_addr.sun_path); } swrap_set_next_free(si, first_free); first_free = si_index; out: SWRAP_UNLOCK_SI(si); swrap_mutex_unlock(&first_free_mutex); swrap_mutex_unlock(&socket_reset_mutex); } static 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) { struct sockaddr *out = (struct sockaddr *)(void *)out_addr; (void) in_len; /* unused */ if (out_addr == NULL) { return 0; } out->sa_family = AF_UNIX; #ifdef HAVE_STRUCT_SOCKADDR_SA_LEN out->sa_len = sizeof(*out_addr); #endif switch (in_addr->sa_family) { case AF_UNSPEC: { const struct sockaddr_in *sin; if (si->family != AF_INET) { break; } if (in_len < sizeof(struct sockaddr_in)) { break; } sin = (const struct sockaddr_in *)(const void *)in_addr; 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; } case AF_INET: #ifdef HAVE_IPV6 case AF_INET6: #endif switch (si->type) { case SOCK_STREAM: case SOCK_DGRAM: break; default: SWRAP_LOG(SWRAP_LOG_ERROR, "Unknown socket type!\n"); errno = ESOCKTNOSUPPORT; return -1; } if (alloc_sock) { return convert_in_un_alloc(si, in_addr, out_addr, bcast); } else { return convert_in_un_remote(si, in_addr, out_addr, bcast); } default: break; } errno = EAFNOSUPPORT; SWRAP_LOG(SWRAP_LOG_ERROR, "Unknown address family\n"); return -1; } static int sockaddr_convert_from_un(const struct socket_info *si, const struct sockaddr_un *in_addr, socklen_t un_addrlen, int family, struct sockaddr *out_addr, socklen_t *out_addrlen) { int ret; if (out_addr == NULL || out_addrlen == NULL) return 0; if (un_addrlen == 0) { *out_addrlen = 0; return 0; } switch (family) { case AF_INET: #ifdef HAVE_IPV6 case AF_INET6: #endif switch (si->type) { case SOCK_STREAM: case SOCK_DGRAM: break; default: SWRAP_LOG(SWRAP_LOG_ERROR, "Unknown socket type!\n"); errno = ESOCKTNOSUPPORT; return -1; } 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; default: break; } SWRAP_LOG(SWRAP_LOG_ERROR, "Unknown address family\n"); errno = EAFNOSUPPORT; return -1; } enum swrap_packet_type { SWRAP_CONNECT_SEND, SWRAP_CONNECT_UNREACH, SWRAP_CONNECT_RECV, SWRAP_CONNECT_ACK, SWRAP_ACCEPT_SEND, SWRAP_ACCEPT_RECV, SWRAP_ACCEPT_ACK, SWRAP_RECVFROM, SWRAP_SENDTO, SWRAP_SENDTO_UNREACH, SWRAP_PENDING_RST, SWRAP_RECV, SWRAP_RECV_RST, SWRAP_SEND, SWRAP_SEND_RST, SWRAP_CLOSE_SEND, SWRAP_CLOSE_RECV, SWRAP_CLOSE_ACK, }; struct swrap_file_hdr { uint32_t magic; uint16_t version_major; uint16_t version_minor; int32_t timezone; uint32_t sigfigs; uint32_t frame_max_len; #define SWRAP_FRAME_LENGTH_MAX 0xFFFF uint32_t link_type; }; #define SWRAP_FILE_HDR_SIZE 24 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 { struct { 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 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 }; #define SWRAP_PACKET_IP_SIZE 40 union swrap_packet_payload { struct { 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 struct { uint8_t type; uint8_t code; uint16_t checksum; uint32_t unused; } icmp6; #define SWRAP_PACKET_PAYLOAD_ICMP6_SIZE 8 }; #define SWRAP_PACKET_PAYLOAD_SIZE 20 #define SWRAP_PACKET_MIN_ALLOC \ (SWRAP_PACKET_FRAME_SIZE + \ SWRAP_PACKET_IP_SIZE + \ SWRAP_PACKET_PAYLOAD_SIZE) static const char *swrap_pcap_init_file(void) { static int initialized = 0; static const char *s = NULL; 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; if (initialized == 1) { return s; } initialized = 1; /* * TODO: don't use the structs use plain buffer offsets * and PUSH_U8(), PUSH_U16() and PUSH_U32() * * for now make sure we disable PCAP support * if the struct has alignment! */ if (sizeof(h) != SWRAP_FILE_HDR_SIZE) { return NULL; } if (sizeof(f) != SWRAP_PACKET_FRAME_SIZE) { return NULL; } if (sizeof(i) != SWRAP_PACKET_IP_SIZE) { return NULL; } if (sizeof(i.v4) != SWRAP_PACKET_IP_V4_SIZE) { return NULL; } if (sizeof(i.v6) != SWRAP_PACKET_IP_V6_SIZE) { return NULL; } if (sizeof(p) != SWRAP_PACKET_PAYLOAD_SIZE) { return NULL; } if (sizeof(p.tcp) != SWRAP_PACKET_PAYLOAD_TCP_SIZE) { return NULL; } if (sizeof(p.udp) != SWRAP_PACKET_PAYLOAD_UDP_SIZE) { return NULL; } if (sizeof(p.icmp4) != SWRAP_PACKET_PAYLOAD_ICMP4_SIZE) { return NULL; } if (sizeof(p.icmp6) != SWRAP_PACKET_PAYLOAD_ICMP6_SIZE) { return NULL; } s = getenv("SOCKET_WRAPPER_PCAP_FILE"); if (s == NULL) { return NULL; } if (strncmp(s, "./", 2) == 0) { s += 2; } return s; } 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) { uint8_t *base = NULL; uint8_t *buf = NULL; union { uint8_t *ptr; struct swrap_packet_frame *frame; } f; union { uint8_t *ptr; union swrap_packet_ip *ip; } i; union swrap_packet_payload *pay; size_t packet_len; size_t alloc_len; size_t nonwire_len = sizeof(struct swrap_packet_frame); size_t wire_hdr_len = 0; size_t wire_len = 0; size_t ip_hdr_len = 0; size_t icmp_hdr_len = 0; size_t icmp_truncate_len = 0; uint8_t protocol = 0, icmp_protocol = 0; const struct sockaddr_in *src_in = NULL; const struct sockaddr_in *dest_in = NULL; #ifdef HAVE_IPV6 const struct sockaddr_in6 *src_in6 = NULL; const struct sockaddr_in6 *dest_in6 = NULL; #endif uint16_t src_port; uint16_t dest_port; switch (src->sa_family) { case AF_INET: src_in = (const struct sockaddr_in *)(const void *)src; dest_in = (const struct sockaddr_in *)(const void *)dest; src_port = src_in->sin_port; dest_port = dest_in->sin_port; ip_hdr_len = sizeof(i.ip->v4); break; #ifdef HAVE_IPV6 case AF_INET6: src_in6 = (const struct sockaddr_in6 *)(const void *)src; dest_in6 = (const struct sockaddr_in6 *)(const void *)dest; src_port = src_in6->sin6_port; dest_port = dest_in6->sin6_port; ip_hdr_len = sizeof(i.ip->v6); break; #endif default: return NULL; } switch (socket_type) { case SOCK_STREAM: protocol = 0x06; /* TCP */ wire_hdr_len = ip_hdr_len + sizeof(pay->tcp); wire_len = wire_hdr_len + payload_len; break; case SOCK_DGRAM: protocol = 0x11; /* UDP */ wire_hdr_len = ip_hdr_len + sizeof(pay->udp); wire_len = wire_hdr_len + payload_len; break; default: return NULL; } if (unreachable) { icmp_protocol = protocol; 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 } if (wire_len > 64 ) { icmp_truncate_len = wire_len - 64; } wire_len += icmp_hdr_len; } packet_len = nonwire_len + wire_len; alloc_len = packet_len; if (alloc_len < SWRAP_PACKET_MIN_ALLOC) { alloc_len = SWRAP_PACKET_MIN_ALLOC; } base = (uint8_t *)calloc(1, alloc_len); if (base == NULL) { return NULL; } buf = base; f.ptr = buf; f.frame->seconds = tval->tv_sec; f.frame->micro_seconds = tval->tv_usec; f.frame->recorded_length = wire_len - icmp_truncate_len; f.frame->full_length = wire_len - icmp_truncate_len; buf += SWRAP_PACKET_FRAME_SIZE; i.ptr = buf; switch (src->sa_family) { case AF_INET: if (src_in == NULL || dest_in == NULL) { SAFE_FREE(base); return NULL; } i.ip->v4.ver_hdrlen = 0x45; /* version 4 and 5 * 32 bit words */ i.ip->v4.tos = 0x00; i.ip->v4.packet_length = htons(wire_len - icmp_truncate_len); i.ip->v4.identification = htons(0xFFFF); i.ip->v4.flags = 0x40; /* BIT 1 set - means don't fragment */ i.ip->v4.fragment = htons(0x0000); i.ip->v4.ttl = 0xFF; i.ip->v4.protocol = protocol; i.ip->v4.hdr_checksum = htons(0x0000); i.ip->v4.src_addr = src_in->sin_addr.s_addr; i.ip->v4.dest_addr = dest_in->sin_addr.s_addr; buf += SWRAP_PACKET_IP_V4_SIZE; break; #ifdef HAVE_IPV6 case AF_INET6: if (src_in6 == NULL || dest_in6 == NULL) { SAFE_FREE(base); return NULL; } i.ip->v6.ver_prio = 0x60; /* version 4 and 5 * 32 bit words */ i.ip->v6.flow_label_high = 0x00; i.ip->v6.flow_label_low = 0x0000; i.ip->v6.payload_length = htons(wire_len - icmp_truncate_len); /* TODO */ i.ip->v6.next_header = protocol; memcpy(i.ip->v6.src_addr, src_in6->sin6_addr.s6_addr, 16); memcpy(i.ip->v6.dest_addr, dest_in6->sin6_addr.s6_addr, 16); buf += SWRAP_PACKET_IP_V6_SIZE; break; #endif } if (unreachable) { pay = (union swrap_packet_payload *)(void *)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 */ i.ptr = buf; i.ip->v4.ver_hdrlen = 0x45; /* version 4 and 5 * 32 bit words */ i.ip->v4.tos = 0x00; i.ip->v4.packet_length = htons(wire_len - icmp_hdr_len); i.ip->v4.identification = htons(0xFFFF); i.ip->v4.flags = 0x40; /* BIT 1 set - means don't fragment */ i.ip->v4.fragment = htons(0x0000); i.ip->v4.ttl = 0xFF; i.ip->v4.protocol = icmp_protocol; i.ip->v4.hdr_checksum = htons(0x0000); i.ip->v4.src_addr = dest_in->sin_addr.s_addr; i.ip->v4.dest_addr = src_in->sin_addr.s_addr; buf += SWRAP_PACKET_IP_V4_SIZE; src_port = dest_in->sin_port; dest_port = src_in->sin_port; break; #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 */ i.ptr = buf; i.ip->v6.ver_prio = 0x60; /* version 4 and 5 * 32 bit words */ i.ip->v6.flow_label_high = 0x00; i.ip->v6.flow_label_low = 0x0000; i.ip->v6.payload_length = htons(wire_len - icmp_truncate_len); /* TODO */ i.ip->v6.next_header = protocol; memcpy(i.ip->v6.src_addr, dest_in6->sin6_addr.s6_addr, 16); memcpy(i.ip->v6.dest_addr, src_in6->sin6_addr.s6_addr, 16); buf += SWRAP_PACKET_IP_V6_SIZE; src_port = dest_in6->sin6_port; dest_port = src_in6->sin6_port; break; #endif } } pay = (union swrap_packet_payload *)(void *)buf; switch (socket_type) { case SOCK_STREAM: 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; break; case SOCK_DGRAM: pay->udp.source_port = src_port; pay->udp.dest_port = dest_port; pay->udp.length = htons(8 + payload_len); pay->udp.checksum = htons(0x0000); buf += SWRAP_PACKET_PAYLOAD_UDP_SIZE; break; } if (payload && payload_len > 0) { memcpy(buf, payload, payload_len); } *_packet_len = packet_len - icmp_truncate_len; return base; } static int swrap_pcap_get_fd(const char *fname) { static int fd = -1; if (fd != -1) { return fd; } fd = libc_open(fname, O_WRONLY|O_CREAT|O_EXCL|O_APPEND, 0644); 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 */ if (write(fd, &file_hdr, sizeof(file_hdr)) != sizeof(file_hdr)) { close(fd); fd = -1; } return fd; } fd = libc_open(fname, O_WRONLY|O_APPEND, 0644); return fd; } 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) { const struct sockaddr *src_addr; const struct sockaddr *dest_addr; unsigned long tcp_seqno = 0; unsigned long tcp_ack = 0; unsigned char tcp_ctl = 0; int unreachable = 0; struct timeval tv; switch (si->family) { case AF_INET: break; #ifdef HAVE_IPV6 case AF_INET6: break; #endif default: return NULL; } switch (type) { case SWRAP_CONNECT_SEND: if (si->type != SOCK_STREAM) { return NULL; } src_addr = &si->myname.sa.s; dest_addr = addr; tcp_seqno = si->io.pck_snd; tcp_ack = si->io.pck_rcv; tcp_ctl = 0x02; /* SYN */ si->io.pck_snd += 1; break; case SWRAP_CONNECT_RECV: if (si->type != SOCK_STREAM) { return NULL; } dest_addr = &si->myname.sa.s; src_addr = addr; tcp_seqno = si->io.pck_rcv; tcp_ack = si->io.pck_snd; tcp_ctl = 0x12; /** SYN,ACK */ si->io.pck_rcv += 1; break; case SWRAP_CONNECT_UNREACH: if (si->type != SOCK_STREAM) { return NULL; } dest_addr = &si->myname.sa.s; src_addr = addr; /* Unreachable: resend the data of SWRAP_CONNECT_SEND */ tcp_seqno = si->io.pck_snd - 1; tcp_ack = si->io.pck_rcv; tcp_ctl = 0x02; /* SYN */ unreachable = 1; break; case SWRAP_CONNECT_ACK: if (si->type != SOCK_STREAM) { return NULL; } src_addr = &si->myname.sa.s; dest_addr = addr; tcp_seqno = si->io.pck_snd; tcp_ack = si->io.pck_rcv; tcp_ctl = 0x10; /* ACK */ break; case SWRAP_ACCEPT_SEND: if (si->type != SOCK_STREAM) { return NULL; } dest_addr = &si->myname.sa.s; src_addr = addr; tcp_seqno = si->io.pck_rcv; tcp_ack = si->io.pck_snd; tcp_ctl = 0x02; /* SYN */ si->io.pck_rcv += 1; break; case SWRAP_ACCEPT_RECV: if (si->type != SOCK_STREAM) { return NULL; } src_addr = &si->myname.sa.s; dest_addr = addr; tcp_seqno = si->io.pck_snd; tcp_ack = si->io.pck_rcv; tcp_ctl = 0x12; /* SYN,ACK */ si->io.pck_snd += 1; break; case SWRAP_ACCEPT_ACK: if (si->type != SOCK_STREAM) { return NULL; } dest_addr = &si->myname.sa.s; src_addr = addr; tcp_seqno = si->io.pck_rcv; tcp_ack = si->io.pck_snd; tcp_ctl = 0x10; /* ACK */ break; case SWRAP_SEND: src_addr = &si->myname.sa.s; dest_addr = &si->peername.sa.s; tcp_seqno = si->io.pck_snd; tcp_ack = si->io.pck_rcv; tcp_ctl = 0x18; /* PSH,ACK */ si->io.pck_snd += len; break; case SWRAP_SEND_RST: dest_addr = &si->myname.sa.s; src_addr = &si->peername.sa.s; if (si->type == SOCK_DGRAM) { return swrap_pcap_marshall_packet(si, &si->peername.sa.s, SWRAP_SENDTO_UNREACH, buf, len, packet_len); } tcp_seqno = si->io.pck_rcv; tcp_ack = si->io.pck_snd; tcp_ctl = 0x14; /** RST,ACK */ break; case SWRAP_PENDING_RST: dest_addr = &si->myname.sa.s; src_addr = &si->peername.sa.s; if (si->type == SOCK_DGRAM) { return NULL; } tcp_seqno = si->io.pck_rcv; tcp_ack = si->io.pck_snd; tcp_ctl = 0x14; /* RST,ACK */ break; case SWRAP_RECV: dest_addr = &si->myname.sa.s; src_addr = &si->peername.sa.s; tcp_seqno = si->io.pck_rcv; tcp_ack = si->io.pck_snd; tcp_ctl = 0x18; /* PSH,ACK */ si->io.pck_rcv += len; break; case SWRAP_RECV_RST: dest_addr = &si->myname.sa.s; src_addr = &si->peername.sa.s; if (si->type == SOCK_DGRAM) { return NULL; } tcp_seqno = si->io.pck_rcv; tcp_ack = si->io.pck_snd; tcp_ctl = 0x14; /* RST,ACK */ break; case SWRAP_SENDTO: src_addr = &si->myname.sa.s; dest_addr = addr; si->io.pck_snd += len; break; case SWRAP_SENDTO_UNREACH: dest_addr = &si->myname.sa.s; src_addr = addr; unreachable = 1; break; case SWRAP_RECVFROM: dest_addr = &si->myname.sa.s; src_addr = addr; si->io.pck_rcv += len; break; case SWRAP_CLOSE_SEND: if (si->type != SOCK_STREAM) { return NULL; } src_addr = &si->myname.sa.s; dest_addr = &si->peername.sa.s; tcp_seqno = si->io.pck_snd; tcp_ack = si->io.pck_rcv; tcp_ctl = 0x11; /* FIN, ACK */ si->io.pck_snd += 1; break; case SWRAP_CLOSE_RECV: if (si->type != SOCK_STREAM) { return NULL; } dest_addr = &si->myname.sa.s; src_addr = &si->peername.sa.s; tcp_seqno = si->io.pck_rcv; tcp_ack = si->io.pck_snd; tcp_ctl = 0x11; /* FIN,ACK */ si->io.pck_rcv += 1; break; case SWRAP_CLOSE_ACK: if (si->type != SOCK_STREAM) { return NULL; } src_addr = &si->myname.sa.s; dest_addr = &si->peername.sa.s; tcp_seqno = si->io.pck_snd; tcp_ack = si->io.pck_rcv; tcp_ctl = 0x10; /* ACK */ break; default: return NULL; } swrapGetTimeOfDay(&tv); 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); } 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) { const char *file_name; uint8_t *packet; size_t packet_len = 0; int fd; swrap_mutex_lock(&pcap_dump_mutex); file_name = swrap_pcap_init_file(); if (!file_name) { goto done; } packet = swrap_pcap_marshall_packet(si, addr, type, buf, len, &packet_len); if (packet == NULL) { goto done; } fd = swrap_pcap_get_fd(file_name); if (fd != -1) { if (write(fd, packet, packet_len) != (ssize_t)packet_len) { free(packet); goto done; } } free(packet); done: swrap_mutex_unlock(&pcap_dump_mutex); } /**************************************************************************** * 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); } #endif /**************************************************************************** * SOCKET ***************************************************************************/ static int swrap_socket(int family, int type, int protocol) { struct socket_info *si = NULL; struct socket_info _si = { 0 }; int fd; int ret; int real_type = type; /* * Remove possible addition flags passed to socket() so * do not fail checking the type. * See https://lwn.net/Articles/281965/ */ #ifdef SOCK_CLOEXEC real_type &= ~SOCK_CLOEXEC; #endif #ifdef SOCK_NONBLOCK real_type &= ~SOCK_NONBLOCK; #endif if (!socket_wrapper_enabled()) { return libc_socket(family, type, protocol); } switch (family) { case AF_INET: #ifdef HAVE_IPV6 case AF_INET6: #endif break; #ifdef AF_NETLINK case AF_NETLINK: #endif /* AF_NETLINK */ #ifdef AF_PACKET case AF_PACKET: #endif /* AF_PACKET */ case AF_UNIX: return libc_socket(family, type, protocol); default: errno = EAFNOSUPPORT; return -1; } switch (real_type) { case SOCK_STREAM: break; case SOCK_DGRAM: break; default: errno = EPROTONOSUPPORT; return -1; } switch (protocol) { case 0: break; case 6: if (real_type == SOCK_STREAM) { break; } FALL_THROUGH; case 17: if (real_type == SOCK_DGRAM) { break; } FALL_THROUGH; default: errno = EPROTONOSUPPORT; return -1; } /* * 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; } /* Check if we have a stale fd and remove it */ swrap_remove_stale(fd); si = &_si; si->family = family; /* however, the rest of the socket_wrapper code expects just * the type, not the flags */ si->type = real_type; si->protocol = protocol; /* * 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, }; si->myname.sa_socklen = sizeof(struct sockaddr_in); memcpy(&si->myname.sa.in, &sin, si->myname.sa_socklen); break; } #ifdef HAVE_IPV6 case AF_INET6: { struct sockaddr_in6 sin6 = { .sin6_family = AF_INET6, }; si->myname.sa_socklen = sizeof(struct sockaddr_in6); memcpy(&si->myname.sa.in6, &sin6, si->myname.sa_socklen); break; } #endif default: errno = EINVAL; return -1; } ret = swrap_create_socket(si, fd); if (ret == -1) { return -1; } SWRAP_LOG(SWRAP_LOG_TRACE, "Created %s socket for protocol %s, fd=%d", family == AF_INET ? "IPv4" : "IPv6", real_type == SOCK_DGRAM ? "UDP" : "TCP", fd); return fd; } 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, int flags) { struct socket_info *parent_si, *child_si; struct socket_info new_si = { 0 }; int fd; int idx; struct swrap_address un_addr = { .sa_socklen = sizeof(struct sockaddr_un), }; struct swrap_address un_my_addr = { .sa_socklen = sizeof(struct sockaddr_un), }; struct swrap_address in_addr = { .sa_socklen = sizeof(struct sockaddr_storage), }; struct swrap_address in_my_addr = { .sa_socklen = sizeof(struct sockaddr_storage), }; int ret; parent_si = find_socket_info(s); if (!parent_si) { #ifdef HAVE_ACCEPT4 return libc_accept4(s, addr, addrlen, flags); #else UNUSED(flags); return libc_accept(s, addr, addrlen); #endif } /* * prevent parent_si from being altered / closed * while we read it */ SWRAP_LOCK_SI(parent_si); /* * assume out sockaddr have the same size as the in parent * socket family */ in_addr.sa_socklen = socket_length(parent_si->family); if (in_addr.sa_socklen <= 0) { SWRAP_UNLOCK_SI(parent_si); errno = EINVAL; return -1; } SWRAP_UNLOCK_SI(parent_si); #ifdef HAVE_ACCEPT4 ret = libc_accept4(s, &un_addr.sa.s, &un_addr.sa_socklen, flags); #else UNUSED(flags); ret = libc_accept(s, &un_addr.sa.s, &un_addr.sa_socklen); #endif if (ret == -1) { if (errno == ENOTSOCK) { /* Remove stale fds */ swrap_remove_stale(s); } return ret; } fd = ret; SWRAP_LOCK_SI(parent_si); ret = sockaddr_convert_from_un(parent_si, &un_addr.sa.un, un_addr.sa_socklen, parent_si->family, &in_addr.sa.s, &in_addr.sa_socklen); if (ret == -1) { SWRAP_UNLOCK_SI(parent_si); close(fd); return ret; } child_si = &new_si; child_si->family = parent_si->family; child_si->type = parent_si->type; child_si->protocol = parent_si->protocol; child_si->bound = 1; child_si->is_server = 1; child_si->connected = 1; SWRAP_UNLOCK_SI(parent_si); child_si->peername = (struct swrap_address) { .sa_socklen = in_addr.sa_socklen, }; memcpy(&child_si->peername.sa.ss, &in_addr.sa.ss, in_addr.sa_socklen); if (addr != NULL && addrlen != NULL) { size_t copy_len = MIN(*addrlen, in_addr.sa_socklen); if (copy_len > 0) { memcpy(addr, &in_addr.sa.ss, copy_len); } *addrlen = in_addr.sa_socklen; } ret = libc_getsockname(fd, &un_my_addr.sa.s, &un_my_addr.sa_socklen); if (ret == -1) { close(fd); return ret; } ret = sockaddr_convert_from_un(child_si, &un_my_addr.sa.un, un_my_addr.sa_socklen, child_si->family, &in_my_addr.sa.s, &in_my_addr.sa_socklen); if (ret == -1) { close(fd); return ret; } SWRAP_LOG(SWRAP_LOG_TRACE, "accept() path=%s, fd=%d", un_my_addr.sa.un.sun_path, s); 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); idx = swrap_create_socket(&new_si, fd); if (idx == -1) { close (fd); return -1; } if (addr != NULL) { struct socket_info *si = swrap_get_socket_info(idx); SWRAP_LOCK_SI(si); swrap_pcap_dump_packet(si, addr, SWRAP_ACCEPT_SEND, NULL, 0); swrap_pcap_dump_packet(si, addr, SWRAP_ACCEPT_RECV, NULL, 0); swrap_pcap_dump_packet(si, addr, SWRAP_ACCEPT_ACK, NULL, 0); SWRAP_UNLOCK_SI(si); } return fd; } #ifdef HAVE_ACCEPT4 int accept4(int s, struct sockaddr *addr, socklen_t *addrlen, int flags) { return swrap_accept(s, addr, (socklen_t *)addrlen, flags); } #endif #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, 0); } static int autobind_start_init; static int autobind_start; /* using sendto() or connect() on an unbound socket would give the recipient no way to reply, as unlike UDP and TCP, a unix domain socket can't auto-assign ephemeral port numbers, so we need to assign it here. Note: this might change the family from ipv6 to ipv4 */ static int swrap_auto_bind(int fd, struct socket_info *si, int family) { struct swrap_address un_addr = { .sa_socklen = sizeof(struct sockaddr_un), }; int i; char type; int ret; int port; struct stat st; char *swrap_dir = NULL; swrap_mutex_lock(&autobind_start_mutex); if (autobind_start_init != 1) { autobind_start_init = 1; autobind_start = getpid(); autobind_start %= 50000; autobind_start += 10000; } un_addr.sa.un.sun_family = AF_UNIX; switch (family) { case AF_INET: { struct sockaddr_in in; switch (si->type) { case SOCK_STREAM: type = SOCKET_TYPE_CHAR_TCP; break; case SOCK_DGRAM: type = SOCKET_TYPE_CHAR_UDP; break; default: errno = ESOCKTNOSUPPORT; ret = -1; goto done; } memset(&in, 0, sizeof(in)); in.sin_family = AF_INET; in.sin_addr.s_addr = htonl(127<<24 | socket_wrapper_default_iface()); si->myname = (struct swrap_address) { .sa_socklen = sizeof(in), }; memcpy(&si->myname.sa.in, &in, si->myname.sa_socklen); break; } #ifdef HAVE_IPV6 case AF_INET6: { struct sockaddr_in6 in6; if (si->family != family) { errno = ENETUNREACH; ret = -1; goto done; } switch (si->type) { case SOCK_STREAM: type = SOCKET_TYPE_CHAR_TCP_V6; break; case SOCK_DGRAM: type = SOCKET_TYPE_CHAR_UDP_V6; break; default: errno = ESOCKTNOSUPPORT; ret = -1; goto done; } memset(&in6, 0, sizeof(in6)); in6.sin6_family = AF_INET6; in6.sin6_addr = *swrap_ipv6(); in6.sin6_addr.s6_addr[15] = socket_wrapper_default_iface(); si->myname = (struct swrap_address) { .sa_socklen = sizeof(in6), }; memcpy(&si->myname.sa.in6, &in6, si->myname.sa_socklen); break; } #endif default: errno = ESOCKTNOSUPPORT; ret = -1; goto done; } if (autobind_start > 60000) { autobind_start = 10000; } swrap_dir = socket_wrapper_dir(); if (swrap_dir == NULL) { errno = EINVAL; ret = -1; goto done; } for (i = 0; i < SOCKET_MAX_SOCKETS; i++) { port = autobind_start + i; snprintf(un_addr.sa.un.sun_path, sizeof(un_addr.sa.un.sun_path), "%s/"SOCKET_FORMAT, swrap_dir, type, socket_wrapper_default_iface(), port); if (stat(un_addr.sa.un.sun_path, &st) == 0) continue; ret = libc_bind(fd, &un_addr.sa.s, un_addr.sa_socklen); if (ret == -1) { goto done; } si->un_addr = un_addr.sa.un; si->bound = 1; autobind_start = port + 1; break; } 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); errno = ENFILE; ret = -1; goto done; } si->family = family; set_port(si->family, port, &si->myname); ret = 0; done: SAFE_FREE(swrap_dir); swrap_mutex_unlock(&autobind_start_mutex); return ret; } /**************************************************************************** * CONNECT ***************************************************************************/ static int swrap_connect(int s, const struct sockaddr *serv_addr, socklen_t addrlen) { int ret; struct swrap_address un_addr = { .sa_socklen = sizeof(struct sockaddr_un), }; struct socket_info *si = find_socket_info(s); int bcast = 0; if (!si) { return libc_connect(s, serv_addr, addrlen); } SWRAP_LOCK_SI(si); if (si->bound == 0) { ret = swrap_auto_bind(s, si, serv_addr->sa_family); if (ret == -1) { goto done; } } if (si->family != serv_addr->sa_family) { errno = EINVAL; ret = -1; goto done; } ret = sockaddr_convert_to_un(si, serv_addr, addrlen, &un_addr.sa.un, 0, &bcast); if (ret == -1) { goto done; } if (bcast) { errno = ENETUNREACH; ret = -1; goto done; } if (si->type == SOCK_DGRAM) { si->defer_connect = 1; ret = 0; } else { swrap_pcap_dump_packet(si, serv_addr, SWRAP_CONNECT_SEND, NULL, 0); ret = libc_connect(s, &un_addr.sa.s, un_addr.sa_socklen); } SWRAP_LOG(SWRAP_LOG_TRACE, "connect() path=%s, fd=%d", un_addr.sa.un.sun_path, s); /* to give better errors */ if (ret == -1 && errno == ENOENT) { errno = EHOSTUNREACH; } if (ret == 0) { si->peername = (struct swrap_address) { .sa_socklen = addrlen, }; memcpy(&si->peername.sa.ss, serv_addr, addrlen); si->connected = 1; /* * When we connect() on a socket than we have to bind the * outgoing connection on the interface we use for the * transport. We already bound it on the right interface * but here we have to update the name so getsockname() * returns correct information. */ if (si->bindname.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, }; } swrap_pcap_dump_packet(si, serv_addr, SWRAP_CONNECT_RECV, NULL, 0); swrap_pcap_dump_packet(si, serv_addr, SWRAP_CONNECT_ACK, NULL, 0); } else { swrap_pcap_dump_packet(si, serv_addr, SWRAP_CONNECT_UNREACH, NULL, 0); } done: SWRAP_UNLOCK_SI(si); return ret; } 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) { int ret; struct swrap_address un_addr = { .sa_socklen = sizeof(struct sockaddr_un), }; struct socket_info *si = find_socket_info(s); int bind_error = 0; #if 0 /* FIXME */ bool in_use; #endif if (!si) { return libc_bind(s, myaddr, addrlen); } SWRAP_LOCK_SI(si); switch (si->family) { case AF_INET: { const struct sockaddr_in *sin; if (addrlen < sizeof(struct sockaddr_in)) { bind_error = EINVAL; break; } sin = (const struct sockaddr_in *)(const void *)myaddr; 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; } sin6 = (const struct sockaddr_in6 *)(const void *)myaddr; if (sin6->sin6_family != AF_INET6) { bind_error = EAFNOSUPPORT; } break; } #endif default: bind_error = EINVAL; break; } if (bind_error != 0) { errno = bind_error; ret = -1; goto out; } #if 0 /* FIXME */ in_use = check_addr_port_in_use(myaddr, addrlen); if (in_use) { errno = EADDRINUSE; ret = -1; goto out; } #endif si->myname.sa_socklen = addrlen; memcpy(&si->myname.sa.ss, myaddr, addrlen); ret = sockaddr_convert_to_un(si, myaddr, addrlen, &un_addr.sa.un, 1, &si->bcast); if (ret == -1) { goto out; } unlink(un_addr.sa.un.sun_path); ret = libc_bind(s, &un_addr.sa.s, un_addr.sa_socklen); SWRAP_LOG(SWRAP_LOG_TRACE, "bind() path=%s, fd=%d", un_addr.sa.un.sun_path, s); if (ret == 0) { si->bound = 1; } out: SWRAP_UNLOCK_SI(si); return ret; } int bind(int s, const struct sockaddr *myaddr, socklen_t addrlen) { return swrap_bind(s, myaddr, addrlen); } /**************************************************************************** * 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) { struct swrap_address myaddr = { .sa_socklen = sizeof(struct sockaddr_storage), }; 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) { salen = myaddr.sa_socklen; sa = &myaddr.sa.s; rc = swrap_getsockname(sd, &myaddr.sa.s, &salen); if (rc < 0) { return -1; } af = sa->sa_family; memset(&myaddr.sa.ss, 0, salen); } else { af = sa->sa_family; } for (i = 0; i < SWRAP_NPORTS; i++, port++) { switch(af) { case AF_INET: { struct sockaddr_in *sinp = (struct sockaddr_in *)(void *)sa; salen = sizeof(struct sockaddr_in); sinp->sin_port = htons(port); break; } case AF_INET6: { struct sockaddr_in6 *sin6p = (struct sockaddr_in6 *)(void *)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 /**************************************************************************** * LISTEN ***************************************************************************/ static int swrap_listen(int s, int backlog) { int ret; struct socket_info *si = find_socket_info(s); if (!si) { return libc_listen(s, backlog); } SWRAP_LOCK_SI(si); if (si->bound == 0) { ret = swrap_auto_bind(s, si, si->family); if (ret == -1) { errno = EADDRINUSE; goto out; } } ret = libc_listen(s, backlog); out: SWRAP_UNLOCK_SI(si); return ret; } int listen(int s, int backlog) { return swrap_listen(s, backlog); } /**************************************************************************** * 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); } /**************************************************************************** * FOPEN64 ***************************************************************************/ #ifdef HAVE_FOPEN64 static FILE *swrap_fopen64(const char *name, const char *mode) { FILE *fp; fp = libc_fopen64(name, mode); if (fp != NULL) { int fd = fileno(fp); swrap_remove_stale(fd); } return fp; } FILE *fopen64(const char *name, const char *mode) { return swrap_fopen64(name, mode); } #endif /* HAVE_FOPEN64 */ /**************************************************************************** * OPEN ***************************************************************************/ static int swrap_vopen(const char *pathname, int flags, va_list ap) { int ret; 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); } return ret; } 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; } /**************************************************************************** * OPEN64 ***************************************************************************/ #ifdef HAVE_OPEN64 static int swrap_vopen64(const char *pathname, int flags, va_list ap) { int ret; ret = libc_vopen64(pathname, flags, ap); if (ret != -1) { /* * There are methods for closing descriptors (libc-internal code * paths, direct syscalls) which close descriptors in ways that * we can't intercept, so try to recover when we notice that * that's happened */ swrap_remove_stale(ret); } return ret; } int open64(const char *pathname, int flags, ...) { va_list ap; int fd; va_start(ap, flags); fd = swrap_vopen64(pathname, flags, ap); va_end(ap); return fd; } #endif /* HAVE_OPEN64 */ /**************************************************************************** * OPENAT ***************************************************************************/ static int swrap_vopenat(int dirfd, const char *path, int flags, va_list ap) { int ret; ret = libc_vopenat(dirfd, path, flags, ap); if (ret != -1) { /* * There are methods for closing descriptors (libc-internal code * paths, direct syscalls) which close descriptors in ways that * we can't intercept, so try to recover when we notice that * that's happened */ swrap_remove_stale(ret); } return ret; } int openat(int dirfd, const char *path, int flags, ...) { va_list ap; int fd; va_start(ap, flags); fd = swrap_vopenat(dirfd, path, flags, ap); va_end(ap); return fd; } /**************************************************************************** * GETPEERNAME ***************************************************************************/ static int swrap_getpeername(int s, struct sockaddr *name, socklen_t *addrlen) { struct socket_info *si = find_socket_info(s); socklen_t len; int ret = -1; if (!si) { return libc_getpeername(s, name, addrlen); } SWRAP_LOCK_SI(si); if (si->peername.sa_socklen == 0) { errno = ENOTCONN; goto out; } len = MIN(*addrlen, si->peername.sa_socklen); if (len == 0) { ret = 0; goto out; } memcpy(name, &si->peername.sa.ss, len); *addrlen = si->peername.sa_socklen; ret = 0; out: SWRAP_UNLOCK_SI(si); return ret; } #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) { struct socket_info *si = find_socket_info(s); socklen_t len; int ret = -1; if (!si) { return libc_getsockname(s, name, addrlen); } SWRAP_LOCK_SI(si); len = MIN(*addrlen, si->myname.sa_socklen); if (len == 0) { ret = 0; goto out; } memcpy(name, &si->myname.sa.ss, len); *addrlen = si->myname.sa_socklen; ret = 0; out: SWRAP_UNLOCK_SI(si); return ret; } #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 ***************************************************************************/ #ifndef SO_PROTOCOL # ifdef SO_PROTOTYPE /* The Solaris name */ # define SO_PROTOCOL SO_PROTOTYPE # endif /* SO_PROTOTYPE */ #endif /* SO_PROTOCOL */ static int swrap_getsockopt(int s, int level, int optname, void *optval, socklen_t *optlen) { struct socket_info *si = find_socket_info(s); int ret; if (!si) { return libc_getsockopt(s, level, optname, optval, optlen); } SWRAP_LOCK_SI(si); if (level == SOL_SOCKET) { switch (optname) { #ifdef SO_DOMAIN case SO_DOMAIN: if (optval == NULL || optlen == NULL || *optlen < (socklen_t)sizeof(int)) { errno = EINVAL; ret = -1; goto done; } *optlen = sizeof(int); *(int *)optval = si->family; ret = 0; goto done; #endif /* SO_DOMAIN */ #ifdef SO_PROTOCOL case SO_PROTOCOL: if (optval == NULL || optlen == NULL || *optlen < (socklen_t)sizeof(int)) { errno = EINVAL; ret = -1; goto done; } *optlen = sizeof(int); *(int *)optval = si->protocol; ret = 0; goto done; #endif /* SO_PROTOCOL */ case SO_TYPE: if (optval == NULL || optlen == NULL || *optlen < (socklen_t)sizeof(int)) { errno = EINVAL; ret = -1; goto done; } *optlen = sizeof(int); *(int *)optval = si->type; ret = 0; goto done; default: ret = libc_getsockopt(s, level, optname, optval, optlen); goto done; } } else if (level == IPPROTO_TCP) { switch (optname) { #ifdef TCP_NODELAY case TCP_NODELAY: /* * This enables sending packets directly out over TCP. * As a unix socket is doing that any way, report it as * enabled. */ if (optval == NULL || optlen == NULL || *optlen < (socklen_t)sizeof(int)) { errno = EINVAL; ret = -1; goto done; } *optlen = sizeof(int); *(int *)optval = si->tcp_nodelay; ret = 0; goto done; #endif /* TCP_NODELAY */ default: break; } } errno = ENOPROTOOPT; ret = -1; done: SWRAP_UNLOCK_SI(si); return ret; } #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) { struct socket_info *si = find_socket_info(s); int ret; if (!si) { return libc_setsockopt(s, level, optname, optval, optlen); } if (level == SOL_SOCKET) { return libc_setsockopt(s, level, optname, optval, optlen); } SWRAP_LOCK_SI(si); if (level == IPPROTO_TCP) { switch (optname) { #ifdef TCP_NODELAY case TCP_NODELAY: { int i; /* * This enables sending packets directly out over TCP. * A unix socket is doing that any way. */ if (optval == NULL || optlen == 0 || optlen < (socklen_t)sizeof(int)) { errno = EINVAL; ret = -1; goto done; } i = *discard_const_p(int, optval); if (i != 0 && i != 1) { errno = EINVAL; ret = -1; goto done; } si->tcp_nodelay = i; ret = 0; goto done; } #endif /* TCP_NODELAY */ default: break; } } switch (si->family) { case AF_INET: if (level == IPPROTO_IP) { #ifdef IP_PKTINFO if (optname == IP_PKTINFO) { si->pktinfo = AF_INET; } #endif /* IP_PKTINFO */ } ret = 0; goto done; #ifdef HAVE_IPV6 case AF_INET6: if (level == IPPROTO_IPV6) { #ifdef IPV6_RECVPKTINFO if (optname == IPV6_RECVPKTINFO) { si->pktinfo = AF_INET6; } #endif /* IPV6_PKTINFO */ } ret = 0; goto done; #endif default: errno = ENOPROTOOPT; ret = -1; goto done; } done: SWRAP_UNLOCK_SI(si); return ret; } 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) { struct socket_info *si = find_socket_info(s); va_list ap; int value; int rc; if (!si) { return libc_vioctl(s, r, va); } SWRAP_LOCK_SI(si); va_copy(ap, va); rc = libc_vioctl(s, r, va); switch (r) { case FIONREAD: value = *((int *)va_arg(ap, int *)); if (rc == -1 && errno != EAGAIN && errno != ENOBUFS) { swrap_pcap_dump_packet(si, NULL, SWRAP_PENDING_RST, NULL, 0); } else if (value == 0) { /* END OF FILE */ swrap_pcap_dump_packet(si, NULL, SWRAP_PENDING_RST, NULL, 0); } break; } va_end(ap); SWRAP_UNLOCK_SI(si); 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; } /***************** * CMSG *****************/ #ifdef HAVE_STRUCT_MSGHDR_MSG_CONTROL #ifndef CMSG_ALIGN # ifdef _ALIGN /* BSD */ #define CMSG_ALIGN _ALIGN # else #define CMSG_ALIGN(len) (((len) + sizeof(size_t) - 1) & ~(sizeof(size_t) - 1)) # endif /* _ALIGN */ #endif /* CMSG_ALIGN */ /** * @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]; void *cast_ptr = (void *)cmbuf; struct cmsghdr *cm = (struct cmsghdr *)cast_ptr; 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; } static int swrap_msghdr_add_pktinfo(struct socket_info *si, struct msghdr *msg) { /* Add packet info */ switch (si->pktinfo) { #if defined(IP_PKTINFO) && (defined(HAVE_STRUCT_IN_PKTINFO) || defined(IP_RECVDSTADDR)) case AF_INET: { struct sockaddr_in *sin; #if defined(HAVE_STRUCT_IN_PKTINFO) struct in_pktinfo pkt; #elif defined(IP_RECVDSTADDR) struct in_addr pkt; #endif if (si->bindname.sa_socklen == sizeof(struct sockaddr_in)) { sin = &si->bindname.sa.in; } else { if (si->myname.sa_socklen != sizeof(struct sockaddr_in)) { return 0; } sin = &si->myname.sa.in; } ZERO_STRUCT(pkt); #if defined(HAVE_STRUCT_IN_PKTINFO) pkt.ipi_ifindex = socket_wrapper_default_iface(); pkt.ipi_addr.s_addr = sin->sin_addr.s_addr; #elif defined(IP_RECVDSTADDR) pkt = sin->sin_addr; #endif swrap_msghdr_add_cmsghdr(msg, IPPROTO_IP, IP_PKTINFO, &pkt, sizeof(pkt)); break; } #endif /* IP_PKTINFO */ #if defined(HAVE_IPV6) case AF_INET6: { #if defined(IPV6_PKTINFO) && defined(HAVE_STRUCT_IN6_PKTINFO) struct sockaddr_in6 *sin6; struct in6_pktinfo pkt6; if (si->bindname.sa_socklen == sizeof(struct sockaddr_in6)) { sin6 = &si->bindname.sa.in6; } else { if (si->myname.sa_socklen != sizeof(struct sockaddr_in6)) { return 0; } sin6 = &si->myname.sa.in6; } 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; } 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; } static int swrap_sendmsg_copy_cmsg(struct cmsghdr *cmsg, uint8_t **cm_data, size_t *cm_data_space); static int swrap_sendmsg_filter_cmsg_socket(struct cmsghdr *cmsg, uint8_t **cm_data, size_t *cm_data_space); static int swrap_sendmsg_filter_cmsghdr(struct msghdr *msg, uint8_t **cm_data, 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: rc = swrap_sendmsg_filter_cmsg_socket(cmsg, cm_data, cm_data_space); break; default: rc = swrap_sendmsg_copy_cmsg(cmsg, cm_data, cm_data_space); break; } } return rc; } static int swrap_sendmsg_copy_cmsg(struct cmsghdr *cmsg, uint8_t **cm_data, size_t *cm_data_space) { size_t cmspace; uint8_t *p; cmspace = *cm_data_space + CMSG_ALIGN(cmsg->cmsg_len); p = realloc((*cm_data), cmspace); if (p == NULL) { return -1; } (*cm_data) = p; p = (*cm_data) + (*cm_data_space); *cm_data_space = cmspace; memcpy(p, cmsg, cmsg->cmsg_len); return 0; } static int swrap_sendmsg_filter_cmsg_pktinfo(struct cmsghdr *cmsg, uint8_t **cm_data, size_t *cm_data_space); static int swrap_sendmsg_filter_cmsg_socket(struct cmsghdr *cmsg, uint8_t **cm_data, size_t *cm_data_space) { int rc = -1; switch(cmsg->cmsg_type) { #ifdef IP_PKTINFO case IP_PKTINFO: rc = swrap_sendmsg_filter_cmsg_pktinfo(cmsg, cm_data, cm_data_space); break; #endif #ifdef IPV6_PKTINFO case IPV6_PKTINFO: rc = swrap_sendmsg_filter_cmsg_pktinfo(cmsg, cm_data, cm_data_space); break; #endif default: break; } return rc; } static int swrap_sendmsg_filter_cmsg_pktinfo(struct cmsghdr *cmsg, uint8_t **cm_data, 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; } #endif /* HAVE_STRUCT_MSGHDR_MSG_CONTROL */ static ssize_t swrap_sendmsg_before(int fd, struct socket_info *si, 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 = -1; if (to_un) { *to_un = NULL; } if (to) { *to = NULL; } if (bcast) { *bcast = 0; } SWRAP_LOCK_SI(si); switch (si->type) { case SOCK_STREAM: { unsigned long mtu; if (!si->connected) { errno = ENOTCONN; goto out; } if (msg->msg_iovlen == 0) { break; } mtu = socket_wrapper_mtu(); for (i = 0; i < (size_t)msg->msg_iovlen; i++) { size_t nlen; nlen = len + msg->msg_iov[i].iov_len; if (nlen < len) { /* overflow */ errno = EMSGSIZE; goto out; } if (nlen > mtu) { break; } } msg->msg_iovlen = i; if (msg->msg_iovlen == 0) { *tmp_iov = msg->msg_iov[0]; tmp_iov->iov_len = MIN((size_t)tmp_iov->iov_len, (size_t)mtu); msg->msg_iov = tmp_iov; msg->msg_iovlen = 1; } break; } case SOCK_DGRAM: if (si->connected) { if (msg->msg_name != NULL) { /* * We are dealing with unix sockets and if we * are connected, we should only talk to the * connected unix path. Using the fd to send * to another server would be hard to achieve. */ msg->msg_name = NULL; msg->msg_namelen = 0; } } else { const struct sockaddr *msg_name; msg_name = (const struct sockaddr *)msg->msg_name; if (msg_name == NULL) { errno = ENOTCONN; goto out; } ret = sockaddr_convert_to_un(si, msg_name, msg->msg_namelen, tmp_un, 0, bcast); if (ret == -1) { goto out; } 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) { ret = swrap_auto_bind(fd, si, si->family); if (ret == -1) { SWRAP_UNLOCK_SI(si); if (errno == ENOTSOCK) { swrap_remove_stale(fd); ret = -ENOTSOCK; } else { SWRAP_LOG(SWRAP_LOG_ERROR, "swrap_sendmsg_before failed"); } return ret; } } if (!si->defer_connect) { break; } ret = sockaddr_convert_to_un(si, &si->peername.sa.s, si->peername.sa_socklen, tmp_un, 0, NULL); if (ret == -1) { goto out; } ret = libc_connect(fd, (struct sockaddr *)(void *)tmp_un, sizeof(*tmp_un)); /* to give better errors */ if (ret == -1 && errno == ENOENT) { errno = EHOSTUNREACH; } if (ret == -1) { goto out; } si->defer_connect = 0; break; default: errno = EHOSTUNREACH; goto out; } #ifdef HAVE_STRUCT_MSGHDR_MSG_CONTROL if (msg->msg_controllen > 0 && msg->msg_control != NULL) { uint8_t *cmbuf = NULL; size_t cmlen = 0; ret = swrap_sendmsg_filter_cmsghdr(msg, &cmbuf, &cmlen); if (ret < 0) { free(cmbuf); goto out; } if (cmlen == 0) { msg->msg_controllen = 0; msg->msg_control = NULL; } else if (cmlen < msg->msg_controllen && cmbuf != NULL) { memcpy(msg->msg_control, cmbuf, cmlen); msg->msg_controllen = cmlen; } free(cmbuf); } #endif ret = 0; out: SWRAP_UNLOCK_SI(si); return ret; } static void swrap_sendmsg_after(int fd, struct socket_info *si, 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 */ 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 (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; } 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; } len = ofs; SWRAP_LOCK_SI(si); switch (si->type) { case SOCK_STREAM: if (ret == -1) { swrap_pcap_dump_packet(si, NULL, SWRAP_SEND, buf, len); swrap_pcap_dump_packet(si, NULL, SWRAP_SEND_RST, NULL, 0); } else { swrap_pcap_dump_packet(si, NULL, SWRAP_SEND, buf, len); } break; case SOCK_DGRAM: if (si->connected) { to = &si->peername.sa.s; } if (ret == -1) { swrap_pcap_dump_packet(si, to, SWRAP_SENDTO, buf, len); swrap_pcap_dump_packet(si, to, SWRAP_SENDTO_UNREACH, buf, len); } else { swrap_pcap_dump_packet(si, to, SWRAP_SENDTO, buf, len); } break; } SWRAP_UNLOCK_SI(si); 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; int ret = -1; SWRAP_LOCK_SI(si); (void)fd; /* unused */ switch (si->type) { case SOCK_STREAM: { unsigned int mtu; if (!si->connected) { errno = ENOTCONN; goto out; } if (msg->msg_iovlen == 0) { break; } mtu = socket_wrapper_mtu(); for (i = 0; i < (size_t)msg->msg_iovlen; i++) { size_t nlen; nlen = len + msg->msg_iov[i].iov_len; if (nlen > mtu) { break; } } msg->msg_iovlen = i; if (msg->msg_iovlen == 0) { *tmp_iov = msg->msg_iov[0]; tmp_iov->iov_len = MIN((size_t)tmp_iov->iov_len, (size_t)mtu); msg->msg_iov = tmp_iov; msg->msg_iovlen = 1; } break; } case SOCK_DGRAM: if (msg->msg_name == NULL) { errno = EINVAL; goto out; } if (msg->msg_iovlen == 0) { break; } if (si->bound == 0) { ret = swrap_auto_bind(fd, si, si->family); if (ret == -1) { SWRAP_UNLOCK_SI(si); /* * When attempting to read or write to a * descriptor, if an underlying autobind fails * because it's not a socket, stop intercepting * uses of that descriptor. */ if (errno == ENOTSOCK) { swrap_remove_stale(fd); ret = -ENOTSOCK; } else { SWRAP_LOG(SWRAP_LOG_ERROR, "swrap_recvmsg_before failed"); } return ret; } } break; default: errno = EHOSTUNREACH; goto out; } ret = 0; out: SWRAP_UNLOCK_SI(si); return ret; } 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; uint8_t *buf = NULL; off_t ofs = 0; size_t avail = 0; size_t remain; int rc; /* 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; } SWRAP_LOCK_SI(si); /* Convert the socket address before we leave */ if (si->type == SOCK_DGRAM && un_addr != NULL) { rc = sockaddr_convert_from_un(si, un_addr, un_addrlen, si->family, msg->msg_name, &msg->msg_namelen); if (rc == -1) { goto done; } } if (avail == 0) { rc = 0; goto done; } if (ret == -1) { remain = MIN(80, avail); } else { remain = ret; } /* we capture it as one single packet */ buf = (uint8_t *)malloc(remain); if (buf == NULL) { /* we just not capture the packet */ SWRAP_UNLOCK_SI(si); errno = saved_errno; return -1; } for (i = 0; i < (size_t)msg->msg_iovlen; i++) { size_t this_time = MIN(remain, (size_t)msg->msg_iov[i].iov_len); memcpy(buf + ofs, msg->msg_iov[i].iov_base, this_time); ofs += this_time; remain -= this_time; } switch (si->type) { case SOCK_STREAM: if (ret == -1 && saved_errno != EAGAIN && saved_errno != ENOBUFS) { swrap_pcap_dump_packet(si, NULL, SWRAP_RECV_RST, NULL, 0); } else if (ret == 0) { /* END OF FILE */ swrap_pcap_dump_packet(si, NULL, SWRAP_RECV_RST, NULL, 0); } else if (ret > 0) { swrap_pcap_dump_packet(si, NULL, SWRAP_RECV, buf, ret); } break; case SOCK_DGRAM: if (ret == -1) { break; } if (un_addr != NULL) { swrap_pcap_dump_packet(si, msg->msg_name, SWRAP_RECVFROM, buf, ret); } else { swrap_pcap_dump_packet(si, msg->msg_name, SWRAP_RECV, buf, ret); } break; } rc = 0; done: free(buf); errno = saved_errno; #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) { SWRAP_UNLOCK_SI(si); return -1; } } #endif SWRAP_UNLOCK_SI(si); return rc; } /**************************************************************************** * RECVFROM ***************************************************************************/ static ssize_t swrap_recvfrom(int s, void *buf, size_t len, int flags, struct sockaddr *from, socklen_t *fromlen) { struct swrap_address from_addr = { .sa_socklen = sizeof(struct sockaddr_un), }; ssize_t ret; struct socket_info *si = find_socket_info(s); struct swrap_address saddr = { .sa_socklen = sizeof(struct sockaddr_storage), }; struct msghdr msg; struct iovec tmp; int tret; if (!si) { return libc_recvfrom(s, buf, len, flags, from, fromlen); } tmp.iov_base = buf; tmp.iov_len = len; ZERO_STRUCT(msg); if (from != NULL && fromlen != NULL) { msg.msg_name = from; /* optional address */ msg.msg_namelen = *fromlen; /* size of address */ } else { msg.msg_name = &saddr.sa.s; /* optional address */ msg.msg_namelen = saddr.sa_socklen; /* size of address */ } msg.msg_iov = &tmp; /* scatter/gather array */ msg.msg_iovlen = 1; /* # elements in msg_iov */ #ifdef HAVE_STRUCT_MSGHDR_MSG_CONTROL msg.msg_control = NULL; /* ancillary data, see below */ msg.msg_controllen = 0; /* ancillary data buffer len */ msg.msg_flags = 0; /* flags on received message */ #endif tret = swrap_recvmsg_before(s, si, &msg, &tmp); if (tret < 0) { return -1; } buf = msg.msg_iov[0].iov_base; len = msg.msg_iov[0].iov_len; ret = libc_recvfrom(s, buf, len, flags, &from_addr.sa.s, &from_addr.sa_socklen); if (ret == -1) { return ret; } tret = swrap_recvmsg_after(s, si, &msg, &from_addr.sa.un, from_addr.sa_socklen, ret); if (tret != 0) { return tret; } if (from != NULL && fromlen != NULL) { *fromlen = msg.msg_namelen; } return ret; } #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 ***************************************************************************/ static ssize_t swrap_sendto(int s, const void *buf, size_t len, int flags, const struct sockaddr *to, socklen_t tolen) { struct msghdr msg; struct iovec tmp; struct swrap_address un_addr = { .sa_socklen = sizeof(struct sockaddr_un), }; const struct sockaddr_un *to_un = NULL; ssize_t ret; int rc; struct socket_info *si = find_socket_info(s); int bcast = 0; if (!si) { return libc_sendto(s, buf, len, flags, to, tolen); } tmp.iov_base = discard_const_p(char, buf); tmp.iov_len = len; ZERO_STRUCT(msg); 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 */ #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 rc = swrap_sendmsg_before(s, si, &msg, &tmp, &un_addr.sa.un, &to_un, &to, &bcast); if (rc < 0) { return -1; } buf = msg.msg_iov[0].iov_base; len = msg.msg_iov[0].iov_len; if (bcast) { struct stat st; unsigned int iface; unsigned int prt = ntohs(((const struct sockaddr_in *)(const void *)to)->sin_port); char type; char *swrap_dir = NULL; type = SOCKET_TYPE_CHAR_UDP; swrap_dir = socket_wrapper_dir(); if (swrap_dir == NULL) { return -1; } for(iface=0; iface <= MAX_WRAPPED_INTERFACES; iface++) { snprintf(un_addr.sa.un.sun_path, sizeof(un_addr.sa.un.sun_path), "%s/"SOCKET_FORMAT, swrap_dir, type, iface, prt); if (stat(un_addr.sa.un.sun_path, &st) != 0) continue; /* ignore the any errors in broadcast sends */ libc_sendto(s, buf, len, flags, &un_addr.sa.s, un_addr.sa_socklen); } SAFE_FREE(swrap_dir); SWRAP_LOCK_SI(si); swrap_pcap_dump_packet(si, to, SWRAP_SENDTO, buf, len); SWRAP_UNLOCK_SI(si); return len; } SWRAP_LOCK_SI(si); /* * If it is a dgram socket and we are connected, don't include the * 'to' address. */ if (si->type == SOCK_DGRAM && si->connected) { ret = libc_sendto(s, buf, len, flags, NULL, 0); } else { ret = libc_sendto(s, buf, len, flags, (struct sockaddr *)msg.msg_name, msg.msg_namelen); } SWRAP_UNLOCK_SI(si); swrap_sendmsg_after(s, si, &msg, to, ret); return ret; } ssize_t sendto(int s, const void *buf, size_t len, int flags, const struct sockaddr *to, socklen_t tolen) { return swrap_sendto(s, buf, len, flags, to, tolen); } /**************************************************************************** * READV ***************************************************************************/ static ssize_t swrap_recv(int s, void *buf, size_t len, int flags) { struct socket_info *si; struct msghdr msg; struct swrap_address saddr = { .sa_socklen = sizeof(struct sockaddr_storage), }; struct iovec tmp; ssize_t ret; int tret; si = find_socket_info(s); if (si == NULL) { return libc_recv(s, buf, len, flags); } tmp.iov_base = buf; tmp.iov_len = len; ZERO_STRUCT(msg); msg.msg_name = &saddr.sa.s; /* optional address */ msg.msg_namelen = saddr.sa_socklen; /* size of address */ msg.msg_iov = &tmp; /* scatter/gather array */ msg.msg_iovlen = 1; /* # elements in msg_iov */ #ifdef HAVE_STRUCT_MSGHDR_MSG_CONTROL msg.msg_control = NULL; /* ancillary data, see below */ msg.msg_controllen = 0; /* ancillary data buffer len */ msg.msg_flags = 0; /* flags on received message */ #endif tret = swrap_recvmsg_before(s, si, &msg, &tmp); if (tret < 0) { return -1; } 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; } return ret; } ssize_t recv(int s, void *buf, size_t len, int flags) { return swrap_recv(s, buf, len, flags); } /**************************************************************************** * READ ***************************************************************************/ static ssize_t swrap_read(int s, void *buf, size_t len) { struct socket_info *si; struct msghdr msg; struct iovec tmp; struct swrap_address saddr = { .sa_socklen = sizeof(struct sockaddr_storage), }; ssize_t ret; int tret; si = find_socket_info(s); if (si == NULL) { return libc_read(s, buf, len); } tmp.iov_base = buf; tmp.iov_len = len; ZERO_STRUCT(msg); msg.msg_name = &saddr.sa.ss; /* optional address */ msg.msg_namelen = saddr.sa_socklen; /* size of address */ msg.msg_iov = &tmp; /* scatter/gather array */ msg.msg_iovlen = 1; /* # elements in msg_iov */ #ifdef HAVE_STRUCT_MSGHDR_MSG_CONTROL msg.msg_control = NULL; /* ancillary data, see below */ msg.msg_controllen = 0; /* ancillary data buffer len */ msg.msg_flags = 0; /* flags on received message */ #endif tret = swrap_recvmsg_before(s, si, &msg, &tmp); if (tret < 0) { if (tret == -ENOTSOCK) { return libc_read(s, buf, len); } return -1; } 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; } return ret; } ssize_t read(int s, void *buf, size_t len) { return swrap_read(s, buf, len); } /**************************************************************************** * WRITE ***************************************************************************/ static ssize_t swrap_write(int s, const void *buf, size_t len) { struct msghdr msg; struct iovec tmp; struct sockaddr_un un_addr; ssize_t ret; int rc; struct socket_info *si; si = find_socket_info(s); if (si == NULL) { return libc_write(s, buf, len); } tmp.iov_base = discard_const_p(char, buf); tmp.iov_len = len; ZERO_STRUCT(msg); 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 */ #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 rc = swrap_sendmsg_before(s, si, &msg, &tmp, &un_addr, NULL, NULL, NULL); if (rc < 0) { return -1; } buf = msg.msg_iov[0].iov_base; len = msg.msg_iov[0].iov_len; ret = libc_write(s, buf, len); swrap_sendmsg_after(s, si, &msg, NULL, ret); return ret; } ssize_t write(int s, const void *buf, size_t len) { return swrap_write(s, buf, len); } /**************************************************************************** * SEND ***************************************************************************/ static ssize_t swrap_send(int s, const void *buf, size_t len, int flags) { struct msghdr msg; struct iovec tmp; struct sockaddr_un un_addr; ssize_t ret; int rc; struct socket_info *si = find_socket_info(s); if (!si) { return libc_send(s, buf, len, flags); } tmp.iov_base = discard_const_p(char, buf); tmp.iov_len = len; ZERO_STRUCT(msg); 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 */ #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 rc = swrap_sendmsg_before(s, si, &msg, &tmp, &un_addr, NULL, NULL, NULL); if (rc < 0) { return -1; } buf = msg.msg_iov[0].iov_base; len = msg.msg_iov[0].iov_len; ret = libc_send(s, buf, len, flags); swrap_sendmsg_after(s, si, &msg, NULL, ret); return ret; } ssize_t send(int s, const void *buf, size_t len, int flags) { return swrap_send(s, buf, len, flags); } /**************************************************************************** * RECVMSG ***************************************************************************/ static ssize_t swrap_recvmsg(int s, struct msghdr *omsg, int flags) { struct swrap_address from_addr = { .sa_socklen = sizeof(struct sockaddr_un), }; struct swrap_address convert_addr = { .sa_socklen = sizeof(struct sockaddr_storage), }; struct socket_info *si; struct msghdr msg; struct iovec tmp; #ifdef HAVE_STRUCT_MSGHDR_MSG_CONTROL size_t msg_ctrllen_filled; size_t msg_ctrllen_left; #endif ssize_t ret; int rc; si = find_socket_info(s); if (si == NULL) { return libc_recvmsg(s, omsg, flags); } tmp.iov_base = NULL; tmp.iov_len = 0; ZERO_STRUCT(msg); msg.msg_name = &from_addr.sa; /* optional address */ msg.msg_namelen = from_addr.sa_socklen; /* size of address */ msg.msg_iov = omsg->msg_iov; /* scatter/gather array */ msg.msg_iovlen = omsg->msg_iovlen; /* # elements in msg_iov */ #ifdef HAVE_STRUCT_MSGHDR_MSG_CONTROL msg_ctrllen_filled = 0; msg_ctrllen_left = omsg->msg_controllen; 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); #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 /* * We convert the unix address to a IP address so we need a buffer * which can store the address in case of SOCK_DGRAM, see below. */ msg.msg_name = &convert_addr.sa; msg.msg_namelen = convert_addr.sa_socklen; rc = swrap_recvmsg_after(s, si, &msg, &from_addr.sa.un, from_addr.sa_socklen, ret); if (rc != 0) { return rc; } #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; SWRAP_LOCK_SI(si); /* * From the manpage: * * The msg_name field points to a caller-allocated buffer that is * used to return the source address if the socket is unconnected. The * caller should set msg_namelen to the size of this buffer before this * call; upon return from a successful call, msg_name will contain the * length of the returned address. If the application does not need * to know the source address, msg_name can be specified as NULL. */ if (si->type == SOCK_STREAM) { omsg->msg_namelen = 0; } else if (omsg->msg_name != NULL && omsg->msg_namelen != 0 && omsg->msg_namelen >= msg.msg_namelen) { memcpy(omsg->msg_name, msg.msg_name, msg.msg_namelen); omsg->msg_namelen = msg.msg_namelen; } SWRAP_UNLOCK_SI(si); return ret; } 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) { 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; int rc; struct socket_info *si = find_socket_info(s); int bcast = 0; if (!si) { return libc_sendmsg(s, omsg, flags); } ZERO_STRUCT(un_addr); tmp.iov_base = NULL; tmp.iov_len = 0; ZERO_STRUCT(msg); SWRAP_LOCK_SI(si); if (si->connected == 0) { msg.msg_name = omsg->msg_name; /* optional address */ msg.msg_namelen = omsg->msg_namelen; /* size of address */ } msg.msg_iov = omsg->msg_iov; /* scatter/gather array */ msg.msg_iovlen = omsg->msg_iovlen; /* # elements in msg_iov */ SWRAP_UNLOCK_SI(si); #ifdef HAVE_STRUCT_MSGHDR_MSG_CONTROL if (msg.msg_controllen > 0 && msg.msg_control != NULL) { /* omsg is a const so use a local buffer for modifications */ 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 */ } msg.msg_flags = omsg->msg_flags; /* flags on received message */ #endif rc = swrap_sendmsg_before(s, si, &msg, &tmp, &un_addr, &to_un, &to, &bcast); if (rc < 0) { return -1; } if (bcast) { struct stat st; unsigned int iface; unsigned int prt = ntohs(((const struct sockaddr_in *)(const void *)to)->sin_port); char type; size_t i, len = 0; uint8_t *buf; off_t ofs = 0; size_t avail = 0; size_t remain; char *swrap_dir = NULL; for (i = 0; i < (size_t)msg.msg_iovlen; i++) { avail += msg.msg_iov[i].iov_len; } len = avail; remain = avail; /* we capture it as one single packet */ buf = (uint8_t *)malloc(remain); if (!buf) { 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; } type = SOCKET_TYPE_CHAR_UDP; swrap_dir = socket_wrapper_dir(); if (swrap_dir == NULL) { free(buf); return -1; } for(iface=0; iface <= MAX_WRAPPED_INTERFACES; iface++) { snprintf(un_addr.sun_path, sizeof(un_addr.sun_path), "%s/"SOCKET_FORMAT, swrap_dir, type, iface, prt); 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 */ libc_sendmsg(s, &msg, flags); } SAFE_FREE(swrap_dir); SWRAP_LOCK_SI(si); swrap_pcap_dump_packet(si, to, SWRAP_SENDTO, buf, len); free(buf); SWRAP_UNLOCK_SI(si); return len; } ret = libc_sendmsg(s, &msg, flags); swrap_sendmsg_after(s, si, &msg, to, ret); return ret; } ssize_t sendmsg(int s, const struct msghdr *omsg, int flags) { return swrap_sendmsg(s, omsg, flags); } /**************************************************************************** * READV ***************************************************************************/ static ssize_t swrap_readv(int s, const struct iovec *vector, int count) { struct socket_info *si; struct msghdr msg; struct iovec tmp; struct swrap_address saddr = { .sa_socklen = sizeof(struct sockaddr_storage) }; ssize_t ret; int rc; si = find_socket_info(s); if (si == NULL) { return libc_readv(s, vector, count); } tmp.iov_base = NULL; tmp.iov_len = 0; ZERO_STRUCT(msg); msg.msg_name = &saddr.sa.s; /* optional address */ msg.msg_namelen = saddr.sa_socklen; /* size of address */ msg.msg_iov = discard_const_p(struct iovec, vector); /* scatter/gather array */ msg.msg_iovlen = count; /* # elements in msg_iov */ #ifdef HAVE_STRUCT_MSGHDR_MSG_CONTROL msg.msg_control = NULL; /* ancillary data, see below */ msg.msg_controllen = 0; /* ancillary data buffer len */ msg.msg_flags = 0; /* flags on received message */ #endif rc = swrap_recvmsg_before(s, si, &msg, &tmp); if (rc < 0) { if (rc == -ENOTSOCK) { return libc_readv(s, vector, count); } return -1; } 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; } return ret; } 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) { struct msghdr msg; struct iovec tmp; struct sockaddr_un un_addr; ssize_t ret; int rc; struct socket_info *si = find_socket_info(s); if (!si) { return libc_writev(s, vector, count); } tmp.iov_base = NULL; tmp.iov_len = 0; ZERO_STRUCT(msg); 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 */ #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 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; } ret = libc_writev(s, msg.msg_iov, msg.msg_iovlen); swrap_sendmsg_after(s, si, &msg, NULL, ret); return ret; } ssize_t writev(int s, const struct iovec *vector, int count) { return swrap_writev(s, vector, count); } /**************************** * CLOSE ***************************/ static int swrap_close(int fd) { struct socket_info *si = NULL; int si_index; int ret; swrap_mutex_lock(&socket_reset_mutex); si_index = find_socket_info_index(fd); if (si_index == -1) { swrap_mutex_unlock(&socket_reset_mutex); return libc_close(fd); } reset_socket_info_index(fd); si = swrap_get_socket_info(si_index); swrap_mutex_lock(&first_free_mutex); SWRAP_LOCK_SI(si); ret = libc_close(fd); swrap_dec_refcount(si); if (swrap_get_refcount(si) > 0) { /* there are still references left */ goto out; } if (si->myname.sa_socklen > 0 && si->peername.sa_socklen > 0) { swrap_pcap_dump_packet(si, NULL, SWRAP_CLOSE_SEND, NULL, 0); } if (si->myname.sa_socklen > 0 && si->peername.sa_socklen > 0) { swrap_pcap_dump_packet(si, NULL, SWRAP_CLOSE_RECV, NULL, 0); swrap_pcap_dump_packet(si, NULL, SWRAP_CLOSE_ACK, NULL, 0); } if (si->un_addr.sun_path[0] != '\0') { unlink(si->un_addr.sun_path); } swrap_set_next_free(si, first_free); first_free = si_index; out: SWRAP_UNLOCK_SI(si); swrap_mutex_unlock(&first_free_mutex); swrap_mutex_unlock(&socket_reset_mutex); return ret; } int close(int fd) { return swrap_close(fd); } /**************************** * DUP ***************************/ static int swrap_dup(int fd) { struct socket_info *si; int dup_fd, idx; idx = find_socket_info_index(fd); if (idx == -1) { return libc_dup(fd); } si = swrap_get_socket_info(idx); dup_fd = libc_dup(fd); if (dup_fd == -1) { int saved_errno = errno; errno = saved_errno; return -1; } SWRAP_LOCK_SI(si); swrap_inc_refcount(si); SWRAP_UNLOCK_SI(si); /* Make sure we don't have an entry for the fd */ swrap_remove_stale(dup_fd); set_socket_info_index(dup_fd, idx); return dup_fd; } int dup(int fd) { return swrap_dup(fd); } /**************************** * DUP2 ***************************/ static int swrap_dup2(int fd, int newfd) { struct socket_info *si; int dup_fd, idx; idx = find_socket_info_index(fd); if (idx == -1) { return libc_dup2(fd, newfd); } si = swrap_get_socket_info(idx); if (fd == newfd) { /* * According to the manpage: * * "If oldfd is a valid file descriptor, and newfd has the same * value as oldfd, then dup2() does nothing, and returns newfd." */ return newfd; } if (find_socket_info(newfd)) { /* dup2() does an implicit close of newfd, which we * need to emulate */ swrap_close(newfd); } dup_fd = libc_dup2(fd, newfd); if (dup_fd == -1) { int saved_errno = errno; errno = saved_errno; return -1; } SWRAP_LOCK_SI(si); swrap_inc_refcount(si); SWRAP_UNLOCK_SI(si); /* Make sure we don't have an entry for the fd */ swrap_remove_stale(dup_fd); set_socket_info_index(dup_fd, idx); return dup_fd; } int dup2(int fd, int newfd) { return swrap_dup2(fd, newfd); } /**************************** * FCNTL ***************************/ static int swrap_vfcntl(int fd, int cmd, va_list va) { struct socket_info *si; int rc, dup_fd, idx; idx = find_socket_info_index(fd); if (idx == -1) { return libc_vfcntl(fd, cmd, va); } si = swrap_get_socket_info(idx); switch (cmd) { case F_DUPFD: dup_fd = libc_vfcntl(fd, cmd, va); if (dup_fd == -1) { int saved_errno = errno; errno = saved_errno; return -1; } SWRAP_LOCK_SI(si); swrap_inc_refcount(si); SWRAP_UNLOCK_SI(si); /* Make sure we don't have an entry for the fd */ swrap_remove_stale(dup_fd); set_socket_info_index(dup_fd, idx); rc = dup_fd; break; default: rc = libc_vfcntl(fd, cmd, va); break; } return rc; } int fcntl(int fd, int cmd, ...) { va_list va; int rc; va_start(va, cmd); rc = swrap_vfcntl(fd, cmd, va); va_end(va); return rc; } /**************************** * EVENTFD ***************************/ #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; } #ifdef HAVE_EVENTFD_UNSIGNED_INT int eventfd(unsigned int count, int flags) #else int eventfd(int count, int flags) #endif { return swrap_eventfd(count, flags); } #endif #ifdef HAVE_PLEDGE int pledge(const char *promises, const char *paths[]) { (void)promises; /* unused */ (void)paths; /* unused */ return 0; } #endif /* HAVE_PLEDGE */ static void swrap_thread_prepare(void) { /* * This function should only be called here!! * * We bind all symobls to avoid deadlocks of the fork is * interrupted by a signal handler using a symbol of this * library. */ swrap_bind_symbol_all(); SWRAP_LOCK_ALL; } static void swrap_thread_parent(void) { SWRAP_UNLOCK_ALL; } static void swrap_thread_child(void) { SWRAP_UNLOCK_ALL; } /**************************** * CONSTRUCTOR ***************************/ void swrap_constructor(void) { int ret; /* * If we hold a lock and the application forks, then the child * is not able to unlock the mutex and we are in a deadlock. * This should prevent such deadlocks. */ pthread_atfork(&swrap_thread_prepare, &swrap_thread_parent, &swrap_thread_child); ret = socket_wrapper_init_mutex(&sockets_mutex); if (ret != 0) { SWRAP_LOG(SWRAP_LOG_ERROR, "Failed to initialize pthread mutex"); exit(-1); } ret = socket_wrapper_init_mutex(&socket_reset_mutex); if (ret != 0) { SWRAP_LOG(SWRAP_LOG_ERROR, "Failed to initialize pthread mutex"); exit(-1); } ret = socket_wrapper_init_mutex(&first_free_mutex); if (ret != 0) { SWRAP_LOG(SWRAP_LOG_ERROR, "Failed to initialize pthread mutex"); exit(-1); } } /**************************** * 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) { size_t i; if (socket_fds_idx != NULL) { for (i = 0; i < socket_fds_max; ++i) { if (socket_fds_idx[i] != -1) { swrap_close(i); } } SAFE_FREE(socket_fds_idx); } SAFE_FREE(sockets); if (swrap.libc.handle != NULL) { dlclose(swrap.libc.handle); } if (swrap.libc.socket_handle) { dlclose(swrap.libc.socket_handle); } } socket_wrapper-1.2.3/tests/000755 001750 000144 00000000000 13444714527 015702 5ustar00asnusers000000 000000 socket_wrapper-1.2.3/tests/README000644 001750 000144 00000000476 12323217475 016564 0ustar00asnusers000000 000000 In this directory you can find all socket_wrapper tests. All tests can also be executed outside of the 'make test' environment and without socket_wrapper. This can be done with: TORTURE_SERVER_ADDRESS_IPV4="127.0.0.1" \ TORTURE_SERVER_ADDRESS_IPV6="::1" \ TORTURE_SERVER_PORT=7777 \ ./tests/test_echo_tcp_write_read socket_wrapper-1.2.3/tests/test_echo_udp_send_recv.c000644 001750 000144 00000005662 13372600005 022715 0ustar00asnusers000000 000000 #include #include #include #include #include "config.h" #include "torture.h" #include #include #include #include #include #include #include #include static int setup_echo_srv_udp_ipv4(void **state) { torture_setup_echo_srv_udp_ipv4(state); return 0; } #ifdef HAVE_IPV6 static int setup_echo_srv_udp_ipv6(void **state) { torture_setup_echo_srv_udp_ipv6(state); return 0; } #endif static int teardown(void **state) { torture_teardown_echo_srv(state); return 0; } static void test_send_recv_ipv4(void **state) { struct torture_address addr = { .sa_socklen = sizeof(struct sockaddr_in), }; ssize_t ret; int rc; int i; int s; (void) state; /* unused */ s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); assert_int_not_equal(s, -1); addr.sa.in.sin_family = AF_INET; addr.sa.in.sin_port = htons(torture_server_port()); rc = inet_pton(AF_INET, torture_server_address(AF_INET), &addr.sa.in.sin_addr); assert_int_equal(rc, 1); rc = connect(s, &addr.sa.s, addr.sa_socklen); assert_int_equal(rc, 0); for (i = 0; i < 10; i++) { char send_buf[64] = {0}; char recv_buf[64] = {0}; snprintf(send_buf, sizeof(send_buf), "packet.%d", i); ret = send(s, send_buf, sizeof(send_buf), 0); assert_int_not_equal(ret, -1); ret = recv(s, recv_buf, sizeof(recv_buf), 0); assert_int_not_equal(ret, -1); assert_memory_equal(send_buf, recv_buf, sizeof(send_buf)); } close(s); } #ifdef HAVE_IPV6 static void test_send_recv_ipv6(void **state) { struct torture_address addr = { .sa_socklen = sizeof(struct sockaddr_in6), }; ssize_t ret; int rc; int i; int s; (void) state; /* unused */ s = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP); assert_int_not_equal(s, -1); addr.sa.in6.sin6_family = AF_INET6; addr.sa.in6.sin6_port = htons(torture_server_port()); rc = inet_pton(AF_INET6, torture_server_address(AF_INET6), &addr.sa.in6.sin6_addr); assert_int_equal(rc, 1); rc = connect(s, &addr.sa.s, addr.sa_socklen); assert_int_equal(rc, 0); for (i = 0; i < 10; i++) { char send_buf[64] = {0}; char recv_buf[64] = {0}; snprintf(send_buf, sizeof(send_buf), "packet.%d", i); ret = send(s, send_buf, sizeof(send_buf), 0); assert_int_not_equal(ret, -1); ret = recv(s, recv_buf, sizeof(recv_buf), 0); assert_int_not_equal(ret, -1); assert_memory_equal(send_buf, recv_buf, sizeof(send_buf)); } close(s); } #endif int main(void) { int rc; const struct CMUnitTest send_tests[] = { cmocka_unit_test_setup_teardown(test_send_recv_ipv4, setup_echo_srv_udp_ipv4, teardown), #ifdef HAVE_IPV6 cmocka_unit_test_setup_teardown(test_send_recv_ipv6, setup_echo_srv_udp_ipv6, teardown), #endif }; rc = cmocka_run_group_tests(send_tests, NULL, NULL); return rc; } socket_wrapper-1.2.3/tests/test_fcntl.c000644 001750 000144 00000002220 13372600005 020170 0ustar00asnusers000000 000000 #include "torture.h" #include #include #include #include static int setup(void **state) { torture_setup_socket_dir(state); return 0; } static int teardown(void **state) { torture_teardown_socket_dir(state); return 0; } static void test_fcntl_dupfd_existing_open_fd(void **state) { int s, dup_s; (void) state; /* unused */ s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); assert_return_code(s, errno); dup_s = fcntl(s, F_DUPFD, 100); assert_int_equal(dup_s, 100); close(s); close(dup_s); } static void test_fcntl_getfd_existing_open_fd(void **state) { int s, rc, flags; (void) state; /* unused */ s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); assert_return_code(s, errno); rc = fcntl(s, F_SETFD, FD_CLOEXEC); assert_int_equal(rc, 0); flags = fcntl(s, F_GETFD); assert_int_equal(flags, FD_CLOEXEC); close(s); } int main(void) { int rc; const struct CMUnitTest tcp_fcntl_dupfd_tests[] = { cmocka_unit_test(test_fcntl_dupfd_existing_open_fd), cmocka_unit_test(test_fcntl_getfd_existing_open_fd), }; rc = cmocka_run_group_tests(tcp_fcntl_dupfd_tests, setup, teardown); return rc; } socket_wrapper-1.2.3/tests/test_swrap_unit.c000644 001750 000144 00000005245 13372600005 021267 0ustar00asnusers000000 000000 #include #include #include #include #include #include #include "config.h" #include "socket_wrapper.c" #ifdef HAVE_STRUCT_MSGHDR_MSG_CONTROL /** * test wrap_sendmsg_filter_cmsghdr() * * Prepare a message with two cmsg: * - the first cmsg is a char buf with the string "Hello World" * - the second cmsg is a char buf with the string "!\n" * * Both cmsgs will be copied without modification by * wrap_sendmsg_filter_cmsghdr(), so we can check that the msg * controllen, the cmsg sizes and the payload are the same. * * We use an not existing cmsg_type which triggers cmsg copying. */ static void test_sendmsg_cmsg(void **state) { int rc = 0; char byte = '!'; struct iovec iov; struct msghdr msg = { 0 }; struct cmsghdr *cmsg; char *cmsgbuf; int cmsgbuf_size; const char *s1 = "Hello World"; const int s1_len = strlen(s1); const char *s2 = "!\n"; const int s2_len = strlen(s2); uint8_t *cmbuf = NULL; size_t cmlen = 0; (void)state; /* unused */ iov.iov_base = &byte; iov.iov_len = 1; /* * Prepare cmsgbuf and msg */ msg.msg_iov = &iov; msg.msg_iovlen = 1; cmsgbuf_size = CMSG_SPACE(s1_len) + CMSG_SPACE(s2_len); cmsgbuf = calloc(cmsgbuf_size, sizeof(char)); assert_non_null(cmsgbuf); msg.msg_control = cmsgbuf; msg.msg_controllen = cmsgbuf_size; /* * Prepare first cmsg with string "Hello World" */ cmsg = CMSG_FIRSTHDR(&msg); assert_non_null(cmsg); cmsg->cmsg_level = SOL_SOCKET; cmsg->cmsg_type = ~0 - 1; cmsg->cmsg_len = CMSG_LEN(s1_len); memcpy(CMSG_DATA(cmsg), s1, s1_len); /* * Prepare second cmsg with string "!\n" */ cmsg = CMSG_NXTHDR(&msg, cmsg); assert_non_null(cmsg); cmsg->cmsg_level = SOL_SOCKET; cmsg->cmsg_type = ~0 - 2; cmsg->cmsg_len = CMSG_LEN(s2_len); memcpy(CMSG_DATA(cmsg), s2, s2_len); /* * Now call swrap_sendmsg_filter_cmsghdr() on the msg */ rc = swrap_sendmsg_filter_cmsghdr(&msg, &cmbuf, &cmlen); assert_return_code(rc, errno); assert_int_equal(cmlen, msg.msg_controllen); /* * Insert filtered cmsgbug into msg and validate cmsgs. */ msg.msg_control = cmbuf; cmsg = CMSG_FIRSTHDR(&msg); assert_non_null(cmsg); assert_int_equal(cmsg->cmsg_len, CMSG_LEN(s1_len)); assert_memory_equal(CMSG_DATA(cmsg), s1, s1_len); cmsg = CMSG_NXTHDR(&msg, cmsg); assert_non_null(cmsg); assert_int_equal(cmsg->cmsg_len, CMSG_LEN(s2_len)); assert_memory_equal(CMSG_DATA(cmsg), s2, s2_len); free(cmbuf); free(cmsgbuf); } #endif int main(void) { int rc; const struct CMUnitTest unit_tests[] = { #ifdef HAVE_STRUCT_MSGHDR_MSG_CONTROL cmocka_unit_test(test_sendmsg_cmsg), #endif }; rc = cmocka_run_group_tests(unit_tests, NULL, NULL); return rc; } socket_wrapper-1.2.3/tests/test_tcp_listen.c000644 001750 000144 00000004630 13372600005 021235 0ustar00asnusers000000 000000 #include #include #include #include #include "config.h" #include "torture.h" #include #include #include #include #include #include #include #include #include #ifdef HAVE_RPC_RPC_H #include #endif static int setup(void **state) { torture_setup_socket_dir(state); return 0; } static int teardown(void **state) { torture_teardown_socket_dir(state); return 0; } static void test_listen_unbound_ipv4(void **state) { struct torture_address addr = { .sa_socklen = sizeof(struct sockaddr_storage), }; int rc; int s1; int s2; (void) state; /* unused */ s1 = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); assert_return_code(s1, errno); rc = listen(s1, SOMAXCONN); assert_return_code(rc, errno); rc = getsockname(s1, &addr.sa.s, &addr.sa_socklen); assert_return_code(rc, errno); assert_int_equal(addr.sa.in.sin_family, AF_INET); assert_int_equal(addr.sa_socklen, sizeof(struct sockaddr_in)); assert_in_range(ntohs(addr.sa.in.sin_port), 1024, 65535); s2 = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); assert_return_code(s2, errno); rc = connect(s2, &addr.sa.s, addr.sa_socklen); assert_return_code(rc, errno); close(s1); close(s2); } #ifdef HAVE_IPV6 static void test_listen_unbound_ipv6(void **state) { struct torture_address addr = { .sa_socklen = sizeof(struct sockaddr_storage), }; int rc; int s1; int s2; (void) state; /* unused */ s1 = socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP); assert_return_code(s1, errno); rc = listen(s1, SOMAXCONN); assert_return_code(rc, errno); rc = getsockname(s1, &addr.sa.s, &addr.sa_socklen); assert_return_code(rc, errno); assert_int_equal(addr.sa.in6.sin6_family, AF_INET6); assert_int_equal(addr.sa_socklen, sizeof(struct sockaddr_in6)); assert_in_range(ntohs(addr.sa.in6.sin6_port), 1024, 65535); s2 = socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP); assert_return_code(s2, errno); rc = connect(s2, &addr.sa.s, addr.sa_socklen); assert_return_code(rc, errno); close(s1); close(s2); } #endif /* HAVE_IPV6 */ int main(void) { int rc; const struct CMUnitTest tcp_listen_tests[] = { cmocka_unit_test(test_listen_unbound_ipv4), #ifdef HAVE_IPV6 cmocka_unit_test(test_listen_unbound_ipv6), #endif /* HAVE_IPV6 */ }; rc = cmocka_run_group_tests(tcp_listen_tests, setup, teardown); return rc; } socket_wrapper-1.2.3/tests/test_thread_echo_tcp_connect.c000644 001750 000144 00000003430 13372600005 023712 0ustar00asnusers000000 000000 #include #include #include #include #include #include "config.h" #include "torture.h" #include #include #include #include #include #include #include #include #define NUM_THREADS 10 static int setup_echo_srv_tcp_ipv4(void **state) { torture_setup_echo_srv_tcp_ipv4(state); return 0; } static int teardown(void **state) { torture_teardown_echo_srv(state); return 0; } static void *thread_worker(void *arg) { struct torture_address addr = { .sa_socklen = sizeof(struct sockaddr_in), }; int rc; int s; (void) arg; /* unused */ s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); assert_int_not_equal(s, -1); addr.sa.in.sin_family = AF_INET; addr.sa.in.sin_port = htons(torture_server_port()); rc = inet_pton(addr.sa.in.sin_family, torture_server_address(AF_INET), &addr.sa.in.sin_addr); assert_int_equal(rc, 1); rc = connect(s, &addr.sa.s, addr.sa_socklen); assert_return_code(rc, errno); close(s); return NULL; } static void test_connect_ipv4(void **state) { pthread_attr_t pthread_custom_attr; pthread_t threads[NUM_THREADS]; int i; (void) state; /* unused */ pthread_attr_init(&pthread_custom_attr); for (i = 0; i < NUM_THREADS; i++) { pthread_create(&threads[i], &pthread_custom_attr, thread_worker, NULL); } for (i = 0; i < NUM_THREADS; i++) { pthread_join(threads[i], NULL); } pthread_attr_destroy(&pthread_custom_attr); } int main(void) { int rc; const struct CMUnitTest tcp_connect_tests[] = { cmocka_unit_test(test_connect_ipv4), }; rc = cmocka_run_group_tests(tcp_connect_tests, setup_echo_srv_tcp_ipv4, teardown); return rc; } socket_wrapper-1.2.3/tests/torture.c000644 001750 000144 00000015426 13374561011 017550 0ustar00asnusers000000 000000 /* * Copyright (C) Andreas Schneider 2013 * * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 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. * * 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. * * 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. */ #include "config.h" #include "torture.h" #include #include #include #include #include #include #include #include #include #include #include #include #define TORTURE_ECHO_SRV_IPV4 "127.0.0.10" /* socket wrapper IPv6 prefix fd00::5357:5fxx */ #define TORTURE_ECHO_SRV_IPV6 "fd00::5357:5f0a" #define TORTURE_ECHO_SRV_PORT 7 #define TORTURE_SOCKET_DIR "/tmp/w_XXXXXX" #define TORTURE_ECHO_SRV_PIDFILE "echo_srv.pid" #define TORTURE_PCAP_FILE "socket_trace.pcap" const char *torture_server_address(int family) { switch (family) { case AF_INET: { const char *ip4 = getenv("TORTURE_SERVER_ADDRESS_IPV4"); if (ip4 != NULL && ip4[0] != '\0') { return ip4; } return TORTURE_ECHO_SRV_IPV4; } #ifdef HAVE_IPV6 case AF_INET6: { const char *ip6 = getenv("TORTURE_SERVER_ADDRESS_IPV6"); if (ip6 != NULL && ip6[0] != '\0') { return ip6; } return TORTURE_ECHO_SRV_IPV6; } #endif default: return NULL; } return NULL; } int torture_server_port(void) { char *env = getenv("TORTURE_SERVER_PORT"); if (env != NULL && env[0] != '\0' && strlen(env) < 6) { int port = atoi(env); if (port > 0 && port < 65536) { return port; } } return TORTURE_ECHO_SRV_PORT; } void torture_setup_socket_dir(void **state) { struct torture_state *s; const char *p; size_t len; s = malloc(sizeof(struct torture_state)); assert_non_null(s); s->socket_dir = strdup(TORTURE_SOCKET_DIR); assert_non_null(s->socket_dir); p = mkdtemp(s->socket_dir); assert_non_null(p); /* pcap file */ len = strlen(p) + 1 + strlen(TORTURE_PCAP_FILE) + 1; s->pcap_file = malloc(len); assert_non_null(s->pcap_file); snprintf(s->pcap_file, len, "%s/%s", p, TORTURE_PCAP_FILE); /* pid file */ len = strlen(p) + 1 + strlen(TORTURE_ECHO_SRV_PIDFILE) + 1; s->srv_pidfile = malloc(len); assert_non_null(s->srv_pidfile); snprintf(s->srv_pidfile, len, "%s/%s", p, TORTURE_ECHO_SRV_PIDFILE); setenv("SOCKET_WRAPPER_DIR", p, 1); setenv("SOCKET_WRAPPER_DEFAULT_IFACE", "170", 1); setenv("SOCKET_WRAPPER_PCAP_FILE", s->pcap_file, 1); *state = s; } static void torture_setup_echo_srv_ip(void **state, const char *ip, int port, int type) { struct torture_state *s; char start_echo_srv[1024] = {0}; const char *t; int count = 0; int rc; torture_setup_socket_dir(state); s = *state; switch (type) { case SOCK_STREAM: t = "-t"; break; case SOCK_DGRAM: t = "-u"; break; default: t = ""; break; } /* set default iface for the server */ setenv("SOCKET_WRAPPER_DEFAULT_IFACE", "10", 1); snprintf(start_echo_srv, sizeof(start_echo_srv), "%s/tests/echo_srv -b %s -p %d -D %s --pid %s", BINARYDIR, ip, port, t, s->srv_pidfile); rc = system(start_echo_srv); assert_int_equal(rc, 0); do { struct stat sb; count++; if (count > 20) { break; } rc = stat(s->srv_pidfile, &sb); usleep(50000L); /* 0.05s * 20 */ } while (rc != 0); assert_int_equal(rc, 0); /* set default iface for the client */ setenv("SOCKET_WRAPPER_DEFAULT_IFACE", "170", 1); } void torture_setup_echo_srv_udp_ipv4(void **state) { torture_setup_echo_srv_ip(state, "0.0.0.0", torture_server_port(), SOCK_DGRAM); } void torture_setup_echo_srv_udp_ipv6(void **state) { torture_setup_echo_srv_ip(state, "::", torture_server_port(), SOCK_DGRAM); } void torture_setup_echo_srv_tcp_ipv4(void **state) { torture_setup_echo_srv_ip(state, "0.0.0.0", torture_server_port(), SOCK_STREAM); } void torture_setup_echo_srv_tcp_ipv6(void **state) { torture_setup_echo_srv_ip(state, "::", torture_server_port(), SOCK_STREAM); } void torture_teardown_socket_dir(void **state) { struct torture_state *s = *state; char *env = getenv("TORTURE_SKIP_CLEANUP"); char remove_cmd[1024] = {0}; int rc; if (env != NULL && env[0] == '1') { fprintf(stderr, ">>> Skipping cleanup of %s", s->socket_dir); } else { snprintf(remove_cmd, sizeof(remove_cmd), "rm -rf %s", s->socket_dir); rc = system(remove_cmd); if (rc < 0) { fprintf(stderr, "%s failed: %s", remove_cmd, strerror(errno)); } } free(s->socket_dir); free(s->pcap_file); free(s->srv_pidfile); free(s); } void torture_teardown_echo_srv(void **state) { struct torture_state *s = *state; char buf[8] = {0}; long int tmp; ssize_t rc; pid_t pid; int fd; bool is_running = true; int count; /* read the pidfile */ fd = open(s->srv_pidfile, O_RDONLY); if (fd < 0) { goto done; } rc = read(fd, buf, sizeof(buf)); close(fd); if (rc <= 0) { goto done; } buf[sizeof(buf) - 1] = '\0'; tmp = strtol(buf, NULL, 10); if (tmp == 0 || tmp > 0xFFFF || errno == ERANGE) { goto done; } pid = (pid_t)(tmp & 0xFFFF); for (count = 0; count < 10; count++) { /* Make sure the daemon goes away! */ kill(pid, SIGTERM); usleep(5000); rc = kill(pid, 0); if (rc != 0) { is_running = false; break; } } if (is_running) { fprintf(stderr, "WARNING the echo server is still running!\n"); } done: torture_teardown_socket_dir(state); } void torture_generate_random_buffer(uint8_t *out, int len) { int i; srand(time(NULL)); for (i = 0; i < len; i++) { out[i] = (uint8_t)rand(); } } socket_wrapper-1.2.3/tests/echo_srv.c000644 001750 000144 00000053034 13444640217 017655 0ustar00asnusers000000 000000 #include "config.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifndef PIDFILE #define PIDFILE "echo_srv.pid" #endif /* PIDFILE */ #define ECHO_SRV_IPV4 "127.0.0.10" /* socket wrapper IPv6 prefix fd00::5357:5fxx */ #define ECHO_SRV_IPV6 "fd00::5357:5f0a" #define DFL_PORT 7 #define BACKLOG 16 #ifndef BUFSIZE #define BUFSIZE 0x20000 /* 128K */ #endif /* BUFSIZE */ #ifndef discard_const #define discard_const(ptr) ((void *)((uintptr_t)(ptr))) #endif #ifndef discard_const_p #define discard_const_p(type, ptr) ((type *)discard_const(ptr)) #endif #ifndef ZERO_STRUCT #define ZERO_STRUCT(x) memset((char *)&(x), 0, sizeof(x)) #endif struct torture_address { socklen_t sa_socklen; union { struct sockaddr s; struct sockaddr_in in; #ifdef HAVE_IPV6 struct sockaddr_in6 in6; #endif struct sockaddr_storage ss; } sa; }; struct echo_srv_opts { int port; int socktype; bool daemon; char *bind; const char *pidfile; }; #ifdef HAVE_STRUCT_MSGHDR_MSG_CONTROL #if defined(IP_PKTINFO) || defined(IP_RECVDSTADDR) || defined(IPV6_PKTINFO) union pktinfo { #ifdef HAVE_STRUCT_IN6_PKTINFO struct in6_pktinfo pkt6; #endif #ifdef HAVE_STRUCT_IN_PKTINFO struct in_pktinfo pkt4; #elif defined(IP_RECVDSTADDR) struct in_addr pkt4; #endif char c; }; #define HAVE_UNION_PKTINFO 1 #endif /* IP_PKTINFO || IP_RECVDSTADDR || IPV6_PKTINFO */ static const char *echo_server_address(int family) { switch (family) { case AF_INET: { const char *ip4 = getenv("TORTURE_SERVER_ADDRESS_IPV4"); if (ip4 != NULL && ip4[0] != '\0') { return ip4; } return ECHO_SRV_IPV4; } #ifdef HAVE_IPV6 case AF_INET6: { const char *ip6 = getenv("TORTURE_SERVER_ADDRESS_IPV6"); if (ip6 != NULL && ip6[0] != '\0') { return ip6; } return ECHO_SRV_IPV6; } #endif default: return NULL; } return NULL; } #endif /* HAVE_STRUCT_MSGHDR_MSG_CONTROL */ static void _assert_return_code(int rc, int err, const char * const file, const int line) { if (rc < 0) { fprintf(stderr, "Fatal error: %s\n", strerror(err)); fprintf(stderr, "%s:%d", file, line); abort(); } } #define assert_return_code(rc, err) \ _assert_return_code(rc, err, __FILE__, __LINE__) static int pidfile(const char *path) { int err; int fd; char pid_str[32] = { 0 }; ssize_t nwritten; size_t len; fd = open(path, O_RDONLY, 0644); err = errno; if (fd != -1) { close(fd); return EEXIST; } else if (err != ENOENT) { return err; } fd = open(path, O_CREAT | O_WRONLY | O_EXCL, 0644); err = errno; if (fd == -1) { return err; } snprintf(pid_str, sizeof(pid_str) -1, "%u\n", (unsigned int) getpid()); len = strlen(pid_str); nwritten = write(fd, pid_str, len); close(fd); if (nwritten != (ssize_t)len) { return EIO; } return 0; } static int become_daemon(void) { int ret; pid_t child_pid; int fd; int i; if (getppid() == 1) { return 0; } child_pid = fork(); if (child_pid == -1) { ret = errno; perror("fork"); return ret; } else if (child_pid > 0) { exit(0); } /* If a working directory was defined, go there */ #ifdef WORKING_DIR chdir(WORKING_DIR); #endif ret = setsid(); if (ret == -1) { ret = errno; perror("setsid"); return ret; } for (i = 0; i < 3; i++) { close(i); fd = open("/dev/null", O_RDWR, 0); if (fd < 0) { fd = open("/dev/null", O_WRONLY, 0); } if (fd < 0) { ret = errno; perror("Can't open /dev/null"); return ret; } if (fd != i) { perror("Didn't get correct fd"); close(fd); return EINVAL; } } umask(0177); return 0; } static void set_sock_pktinfo(int sock, int family) { int sockopt = 1; int option = 0; int proto = 0; int rc; switch(family) { case AF_INET: proto = IPPROTO_IP; #ifdef IP_PKTINFO option = IP_PKTINFO; #elif IP_RECVDSTADDR option = IP_RECVDSTADDR; #else return; #endif /* IP_PKTINFO */ break; #ifdef HAVE_IPV6 #ifdef IPV6_RECVPKTINFO case AF_INET6: proto = IPPROTO_IPV6; option = IPV6_RECVPKTINFO; break; #endif /* IPV6_RECVPKTINFO */ #endif /* HAVE_IPV6 */ default: return; } rc = setsockopt(sock, proto, option, &sockopt, sizeof(sockopt)); assert_return_code(rc, errno); } /* Returns 0 on success, errno on failure. If successful, * sock is a ready to use socket */ static int setup_srv(struct echo_srv_opts *opts, int *_sock) { struct addrinfo hints; struct addrinfo *res, *ri; char svc[6]; int ret; int sock; memset(&hints, 0, sizeof(hints)); hints.ai_family = AF_UNSPEC; hints.ai_socktype = opts->socktype; hints.ai_flags = AI_PASSIVE; snprintf(svc, sizeof(svc), "%d", opts->port); ret = getaddrinfo(opts->bind, svc, &hints, &res); if (ret != 0) { return errno; } for (ri = res; ri != NULL; ri = ri->ai_next) { sock = socket(ri->ai_family, ri->ai_socktype, ri->ai_protocol); if (sock == -1) { ret = errno; freeaddrinfo(res); perror("socket"); return ret; } if (ri->ai_socktype == SOCK_DGRAM) { set_sock_pktinfo(sock, ri->ai_family); } ret = bind(sock, ri->ai_addr, ri->ai_addrlen); if (ret == 0) { break; } close(sock); } freeaddrinfo(res); if (ri == NULL) { fprintf(stderr, "Could not bind\n"); return EFAULT; } if (opts->socktype == SOCK_STREAM) { ret = listen(sock, BACKLOG); if (ret == -1) { ret = errno; close(sock); perror("listen"); return ret; } } *_sock = sock; return 0; } static int socket_dup(int s) { struct torture_address cli_addr1 = { .sa_socklen = sizeof(struct sockaddr_storage), }; struct torture_address srv_addr1 = { .sa_socklen = sizeof(struct sockaddr_storage), }; struct torture_address cli_addr2 = { .sa_socklen = sizeof(struct sockaddr_storage), }; struct torture_address srv_addr2 = { .sa_socklen = sizeof(struct sockaddr_storage), }; struct torture_address cli_addr3 = { .sa_socklen = sizeof(struct sockaddr_storage), }; struct torture_address srv_addr3 = { .sa_socklen = sizeof(struct sockaddr_storage), }; int s2; int rc; rc = getsockname(s, &srv_addr1.sa.s, &srv_addr1.sa_socklen); if (rc == -1) { perror("getsockname"); return -1; } rc = getpeername(s, &cli_addr1.sa.s, &cli_addr1.sa_socklen); if (rc == -1) { perror("getpeername"); return -1; } if (cli_addr1.sa.ss.ss_family != srv_addr1.sa.ss.ss_family) { perror("client/server family mismatch"); return -1; } /* Test dup */ s2 = dup(s); if (s2 == -1) { perror("dup"); return -1; } close(s); rc = getsockname(s2, &srv_addr2.sa.s, &srv_addr2.sa_socklen); if (rc == -1) { perror("getsockname"); close(s2); return -1; } rc = getpeername(s2, &cli_addr2.sa.s, &cli_addr2.sa_socklen); if (rc == -1) { perror("getpeername"); close(s2); return -1; } if (cli_addr1.sa_socklen != cli_addr2.sa_socklen || srv_addr1.sa_socklen != srv_addr2.sa_socklen) { perror("length mismatch"); close(s2); return -1; } switch(cli_addr1.sa.ss.ss_family) { case AF_INET: { rc = memcmp(&cli_addr1.sa.in, &cli_addr2.sa.in, sizeof(struct sockaddr_in)); if (rc != 0) { perror("client mismatch"); } rc = memcmp(&srv_addr1.sa.in, &srv_addr2.sa.in, sizeof(struct sockaddr_in)); if (rc != 0) { perror("server mismatch"); } break; } #ifdef HAVE_IPV6 case AF_INET6: { rc = memcmp(&cli_addr1.sa.in6, &cli_addr2.sa.in6, sizeof(struct sockaddr_in6)); if (rc != 0) { perror("client mismatch"); } rc = memcmp(&srv_addr1.sa.in6, &srv_addr2.sa.in6, sizeof(struct sockaddr_in6)); if (rc != 0) { perror("server mismatch"); } break; } #endif default: perror("family mismatch"); close(s2); return -1; } /* Test dup2 */ s = dup2(s2, s); close(s2); if (s == -1) { perror("dup"); return -1; } rc = getsockname(s, &srv_addr3.sa.s, &srv_addr3.sa_socklen); if (rc == -1) { perror("getsockname"); close(s); return -1; } rc = getpeername(s, &cli_addr3.sa.s, &cli_addr3.sa_socklen); if (rc == -1) { perror("getpeername"); close(s); return -1; } if (cli_addr2.sa_socklen != cli_addr3.sa_socklen || srv_addr2.sa_socklen != srv_addr3.sa_socklen) { perror("length mismatch"); close(s); return -1; } switch(cli_addr2.sa.ss.ss_family) { case AF_INET: { rc = memcmp(&cli_addr1.sa.in, &cli_addr2.sa.in, sizeof(struct sockaddr_in)); if (rc != 0) { perror("client mismatch"); } rc = memcmp(&srv_addr1.sa.in, &srv_addr2.sa.in, sizeof(struct sockaddr_in)); if (rc != 0) { perror("server mismatch"); } break; } #ifdef HAVE_IPV6 case AF_INET6: { rc = memcmp(&cli_addr1.sa.in6, &cli_addr2.sa.in6, sizeof(struct sockaddr_in6)); if (rc != 0) { perror("client mismatch"); } rc = memcmp(&srv_addr1.sa.in6, &srv_addr2.sa.in6, sizeof(struct sockaddr_in6)); if (rc != 0) { perror("server mismatch"); } break; } #endif default: perror("family mismatch"); close(s); return -1; } return s; } static void echo_tcp(int sock) { struct torture_address addr = { .sa_socklen = sizeof(struct sockaddr_storage), }; char buf[BUFSIZE]; ssize_t bret; int client_sock = -1; int s; pid_t pid; while (1) { s = accept(sock, &addr.sa.s, &addr.sa_socklen); if (s == -1) { perror("accept"); goto done; } pid = fork(); if (pid == -1) { perror("fork"); } else if (pid == 0) { close(sock); client_sock = socket_dup(s); if (client_sock == -1) { perror("socket_dup"); goto done; } while (1) { bret = recv(client_sock, buf, BUFSIZE, 0); if (bret == -1) { perror("recv"); goto done; } else if (bret == 0) { break; } bret = send(client_sock, buf, bret, 0); if (bret == -1) { perror("send"); goto done; } } close(s); exit(0); } waitpid(-1, NULL, 0); close(s); } done: if (client_sock != -1) { close(client_sock); } } static ssize_t echo_udp_recv_from_to(int sock, void *buf, size_t buflen, int flags, struct torture_address *from, struct torture_address *to) { struct msghdr rmsg; struct iovec riov; ssize_t ret; #if defined(HAVE_STRUCT_MSGHDR_MSG_CONTROL) && defined(HAVE_UNION_PKTINFO) size_t cmlen = CMSG_LEN(sizeof(union pktinfo)); char cmsg[cmlen]; #endif /* HAVE_STRUCT_MSGHDR_MSG_CONTROL */ riov.iov_base = buf; riov.iov_len = buflen; ZERO_STRUCT(rmsg); rmsg.msg_name = &from->sa.s; rmsg.msg_namelen = from->sa_socklen; rmsg.msg_iov = &riov; rmsg.msg_iovlen = 1; #if defined(HAVE_STRUCT_MSGHDR_MSG_CONTROL) && defined(HAVE_UNION_PKTINFO) memset(cmsg, 0, cmlen); rmsg.msg_control = cmsg; rmsg.msg_controllen = cmlen; #endif ret = recvmsg(sock, &rmsg, flags); if (ret < 0) { return ret; } from->sa_socklen = rmsg.msg_namelen; #if defined(HAVE_STRUCT_MSGHDR_MSG_CONTROL) && defined(HAVE_UNION_PKTINFO) if (rmsg.msg_controllen > 0) { struct cmsghdr *cmsgptr; cmsgptr = CMSG_FIRSTHDR(&rmsg); while (cmsgptr != NULL) { const char *p; #if defined(IP_PKTINFO) && defined(HAVE_STRUCT_IN_PKTINFO) if (cmsgptr->cmsg_level == IPPROTO_IP && cmsgptr->cmsg_type == IP_PKTINFO) { char ip[INET_ADDRSTRLEN] = { 0 }; struct in_pktinfo *pkt; void *cmsg_cast_ptr = CMSG_DATA(cmsgptr); pkt = (struct in_pktinfo *)cmsg_cast_ptr; to->sa.in.sin_family = AF_INET; to->sa.in.sin_addr = pkt->ipi_addr; to->sa_socklen = sizeof(struct sockaddr_in); p = inet_ntop(AF_INET, &to->sa.in.sin_addr, ip, sizeof(ip)); if (p == 0) { fprintf(stderr, "Failed to convert IP address"); abort(); } if (strcmp(ip, echo_server_address(AF_INET)) != 0) { fprintf(stderr, "Wrong IP received"); abort(); } } #endif /* IP_PKTINFO */ #ifdef IP_RECVDSTADDR if (cmsgptr->cmsg_level == IPPROTO_IP && cmsgptr->cmsg_type == IP_RECVDSTADDR) { char ip[INET_ADDRSTRLEN] = { 0 }; struct in_addr *addr; void *cmsg_cast_ptr = CMSG_DATA(cmsgptr); addr = (struct in_addr *)cmsg_cast_ptr; to->sa.in.sin_family = AF_INET; to->sa.in.sin_addr = *addr; to->sa_socklen = sizeof(struct sockaddr_in); p = inet_ntop(AF_INET, &to->sa.in.sin_addr, ip, sizeof(ip)); if (p == 0) { fprintf(stderr, "Failed to convert IP address"); abort(); } if (strcmp(ip, echo_server_address(AF_INET)) != 0) { fprintf(stderr, "Wrong IP received"); abort(); } } #endif /* IP_RECVDSTADDR */ #if defined(IPV6_PKTINFO) && defined(HAVE_STRUCT_IN6_PKTINFO) if (cmsgptr->cmsg_level == IPPROTO_IPV6 && cmsgptr->cmsg_type == IPV6_PKTINFO) { char ip[INET6_ADDRSTRLEN] = { 0 }; struct in6_pktinfo *pkt6; void *cmsg_cast_ptr = CMSG_DATA(cmsgptr); pkt6 = (struct in6_pktinfo *)cmsg_cast_ptr; to->sa.in6.sin6_family = AF_INET6; to->sa.in6.sin6_addr = pkt6->ipi6_addr; p = inet_ntop(AF_INET6, &to->sa.in6.sin6_addr, ip, sizeof(ip)); if (p == 0) { fprintf(stderr, "Failed to convert IP address"); abort(); } if (strcmp(ip, echo_server_address(AF_INET6)) != 0) { fprintf(stderr, "Wrong IP received"); abort(); } } #endif /* IPV6_PKTINFO */ cmsgptr = CMSG_NXTHDR(&rmsg, cmsgptr); } } else { fprintf(stderr, "Failed to receive pktinfo"); abort(); } #endif /* HAVE_STRUCT_MSGHDR_MSG_CONTROL && HAVE_UNION_PKTINFO */ return ret; } static ssize_t echo_udp_send_to_from(int sock, void *buf, size_t buflen, int flags, struct sockaddr *to, socklen_t tolen, struct sockaddr *from, socklen_t fromlen) { struct msghdr msg; struct iovec iov; ssize_t ret; #if defined(HAVE_STRUCT_MSGHDR_MSG_CONTROL) && defined(HAVE_UNION_PKTINFO) size_t clen = CMSG_SPACE(sizeof(union pktinfo)); char cbuf[clen]; struct cmsghdr *cmsgptr; #else (void)from; /* unused */ (void)fromlen; /* unused */ #endif /* HAVE_STRUCT_MSGHDR_MSG_CONTROL && HAVE_UNION_PKTINFO */ iov.iov_base = buf; iov.iov_len = buflen; ZERO_STRUCT(msg); msg.msg_name = to; msg.msg_namelen = tolen; msg.msg_iov = &iov; msg.msg_iovlen = 1; #if defined(HAVE_STRUCT_MSGHDR_MSG_CONTROL) && defined(HAVE_UNION_PKTINFO) memset(cbuf, 0, clen); msg.msg_control = cbuf; msg.msg_controllen = clen; cmsgptr = CMSG_FIRSTHDR(&msg); msg.msg_controllen = 0; switch (from->sa_family) { #if defined(IP_PKTINFO) || defined(IP_SENDSRCADDR) case AF_INET: { void *cmsg_cast_ptr = CMSG_DATA(cmsgptr); #ifdef IP_PKTINFO struct in_pktinfo *p = (struct in_pktinfo *)cmsg_cast_ptr; #elif defined(IP_SENDSRCADDR) struct in_addr *p = (struct in_addr *)cmsg_cast_ptr; #endif const struct sockaddr_in *from4 = (const struct sockaddr_in *)(const void *)from; if (fromlen != sizeof(struct sockaddr_in)) { break; } cmsgptr->cmsg_level = IPPROTO_IP; #ifdef IP_PKTINFO cmsgptr->cmsg_type = IP_PKTINFO; p->ipi_spec_dst = from4->sin_addr; #elif defined(IP_SENDSRCADDR) cmsgptr->cmsg_type = IP_SENDSRCADDR; *p = from4->sin_addr; #endif cmsgptr->cmsg_len = CMSG_LEN(sizeof(*p)); msg.msg_controllen = CMSG_SPACE(sizeof(*p)); break; } #endif /* IP_PKTINFO || IP_SENDSRCADDR */ #ifdef IPV6_PKTINFO case AF_INET6: { void *cast_ptr = CMSG_DATA(cmsgptr); struct in6_pktinfo *p = (struct in6_pktinfo *)cast_ptr; const struct sockaddr_in6 *from6 = (const struct sockaddr_in6 *)(const void *)from; if (fromlen != sizeof(struct sockaddr_in6)) { break; } cmsgptr->cmsg_level = IPPROTO_IPV6; cmsgptr->cmsg_type = IPV6_PKTINFO; cmsgptr->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo)); p->ipi6_addr = from6->sin6_addr; msg.msg_controllen = CMSG_SPACE(sizeof(struct in6_pktinfo)); break; } #endif /* IPV6_PKTINFO */ default: break; } #endif /* HAVE_STRUCT_MSGHDR_MSG_CONTROL && HAVE_UNION_PKTINFO */ ret = sendmsg(sock, &msg, flags); return ret; } static void echo_udp(int sock) { struct torture_address saddr = { .sa_socklen = sizeof(struct sockaddr_storage), }; struct torture_address daddr = { .sa_socklen = sizeof(struct sockaddr_storage), }; ssize_t bret; char buf[BUFSIZE]; while (1) { bret = echo_udp_recv_from_to(sock, buf, BUFSIZE, 0, &saddr, &daddr); if (bret == -1) { perror("recvfrom"); continue; } bret = echo_udp_send_to_from(sock, buf, bret, 0, &saddr.sa.s, saddr.sa_socklen, &daddr.sa.s, daddr.sa_socklen); if (bret == -1) { perror("sendto"); continue; } } } static void echo(int sock, struct echo_srv_opts *opts) { switch (opts->socktype) { case SOCK_STREAM: echo_tcp(sock); return; case SOCK_DGRAM: echo_udp(sock); return; default: fprintf(stderr, "Unsupported protocol\n"); return; } } int main(int argc, char **argv) { int ret; int sock = -1; struct echo_srv_opts opts; int opt; int optindex; static struct option long_options[] = { { discard_const_p(char, "tcp"), no_argument, 0, 't' }, { discard_const_p(char, "udp"), no_argument, 0, 'u' }, { discard_const_p(char, "bind-addr"), required_argument, 0, 'b' }, { discard_const_p(char, "port"), required_argument, 0, 'p' }, { discard_const_p(char, "daemon"), no_argument, 0, 'D' }, { discard_const_p(char, "pid"), required_argument, 0, 0 }, {0, 0, 0, 0 } }; opts.port = DFL_PORT; opts.socktype = SOCK_STREAM; opts.bind = NULL; opts.pidfile = PIDFILE; opts.daemon = false; while ((opt = getopt_long(argc, argv, "Dutp:b:", long_options, &optindex)) != -1) { switch (opt) { case 0: if (optindex == 5) { opts.pidfile = optarg; } break; case 'p': opts.port = atoi(optarg); break; case 'b': opts.bind = optarg; break; case 'u': opts.socktype = SOCK_DGRAM; break; case 't': opts.socktype = SOCK_STREAM; break; case 'D': opts.daemon = true; break; default: /* '?' */ fprintf(stderr, "Usage: %s [-p port] [-u] [-t] [-b bind_addr] " \ "[-D] [--pid pidfile]\n" "-t makes the server listen on TCP\n" "-u makes the server listen on UDP\n" "-D tells the server to become a daemon and " \ "write a PIDfile\n" "The default port is 7, the default PIDfile is " \ "echo_srv.pid in the current directory\n", argv[0]); ret = 1; goto done; } } if (opts.daemon) { ret = become_daemon(); if (ret != 0) { fprintf(stderr, "Cannot become daemon: %s\n", strerror(ret)); goto done; } } ret = setup_srv(&opts, &sock); if (ret != 0) { fprintf(stderr, "Cannot setup server: %s\n", strerror(ret)); goto done; } if (opts.daemon && opts.pidfile != NULL) { ret = pidfile(opts.pidfile); if (ret != 0) { fprintf(stderr, "Cannot create pidfile %s: %s\n", opts.pidfile, strerror(ret)); goto done; } } echo(sock, &opts); close(sock); if (opts.daemon && opts.pidfile != NULL) { unlink(opts.pidfile); } ret = 0; done: return ret; } socket_wrapper-1.2.3/tests/test_echo_tcp_get_peer_sock_name.c000644 001750 000144 00000030465 13374561011 024560 0ustar00asnusers000000 000000 #include #include #include #include #include "config.h" #include "torture.h" #include #include #include #include #include #include #include #include static int setup_echo_srv_tcp_ipv4(void **state) { torture_setup_echo_srv_tcp_ipv4(state); setenv("SOCKET_WRAPPER_DEFAULT_IFACE", "20", 1); return 0; } static int teardown(void **state) { torture_teardown_echo_srv(state); return 0; } static void _assert_sockaddr_equal(struct torture_address *addr, const char *a, const char * const file, const int line) { #ifdef HAVE_IPV6 char ip[INET6_ADDRSTRLEN] = { 0 }; #else char ip[INET_ADDRSTRLEN] = { 0 }; #endif const char *p; #ifdef HAVE_IPV6 p = inet_ntop(addr->sa.ss.ss_family, addr->sa.ss.ss_family == AF_INET6 ? (void *)&addr->sa.in6.sin6_addr : (void *)&addr->sa.in.sin_addr, ip, sizeof(ip)); #else p = inet_ntop(addr->sa.ss.ss_family, (void *)&addr->sa.in.sin_addr, ip, sizeof(ip)); #endif _assert_true(cast_ptr_to_largest_integral_type(p), "inet_ntop: Failed to convert IP address", file, line); _assert_string_equal(ip, a, file, line); } #define assert_sockaddr_equal(ss, a) \ _assert_sockaddr_equal(ss, a, __FILE__, __LINE__) static void _assert_sockaddr_port_equal(struct torture_address *addr, const char *a, uint16_t port, const char * const file, const int line) { uint16_t n_port; _assert_sockaddr_equal(addr, a, file, line); switch(addr->sa.ss.ss_family) { case AF_INET: n_port = addr->sa.in.sin_port; break; #ifdef HAVE_IPV6 case AF_INET6: n_port = addr->sa.in6.sin6_port; break; #endif default: return; } _assert_int_equal(ntohs(n_port), port, file, line); } #define assert_sockaddr_port_equal(ss, a, prt) \ _assert_sockaddr_port_equal(ss, a, prt, __FILE__, __LINE__) static void _assert_sockaddr_port_range_equal(struct torture_address *addr, const char *a, uint16_t min_port, uint16_t max_port, const char * const file, const int line) { uint16_t n_port; _assert_sockaddr_equal(addr, a, file, line); switch(addr->sa.ss.ss_family) { case AF_INET: n_port = addr->sa.in.sin_port; break; #ifdef HAVE_IPV6 case AF_INET6: n_port = addr->sa.in6.sin6_port; break; #endif default: return; } _assert_in_range(ntohs(n_port), min_port, max_port, file, line); } #define assert_sockaddr_port_range_equal(ss, a, min_prt, max_prt) \ _assert_sockaddr_port_range_equal(ss, a, min_prt, max_prt, __FILE__, __LINE__) static void test_connect_getsockname_getpeername(void **state) { struct torture_address addr = { .sa_socklen = sizeof(struct sockaddr_in), }; struct torture_address cli_addr = { .sa_socklen = sizeof(struct sockaddr_storage), }; struct torture_address srv_addr = { .sa_socklen = sizeof(struct sockaddr_storage), }; int rc; int s; (void) state; /* unused */ s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); assert_return_code(s, errno); /* Bind client address to wildcard address */ addr.sa.in.sin_family = AF_INET; rc = inet_pton(AF_INET, "127.0.0.20", &addr.sa.in.sin_addr); assert_int_equal(rc, 1); rc = bind(s, &addr.sa.s, addr.sa_socklen); assert_return_code(rc, errno); rc = getsockname(s, &cli_addr.sa.s, &cli_addr.sa_socklen); assert_return_code(rc, errno); assert_sockaddr_port_range_equal(&cli_addr, "127.0.0.20", 1024, 65535); rc = getpeername(s, &addr.sa.s, &addr.sa_socklen); assert_int_equal(rc, -1); assert_int_equal(errno, ENOTCONN); /* connect */ addr = (struct torture_address) { .sa_socklen = sizeof(struct sockaddr_in), .sa.in = (struct sockaddr_in) { .sin_family = AF_INET, .sin_port = htons(torture_server_port()), }, }; rc = inet_pton(AF_INET, torture_server_address(AF_INET), &addr.sa.in.sin_addr); assert_int_equal(rc, 1); /* Connect */ rc = connect(s, &addr.sa.s, addr.sa_socklen); assert_return_code(rc, errno); cli_addr = (struct torture_address) { .sa_socklen = sizeof(struct sockaddr_storage), }; rc = getsockname(s, &cli_addr.sa.s, &cli_addr.sa_socklen); assert_return_code(rc, errno); assert_sockaddr_port_range_equal(&cli_addr, "127.0.0.20", 1024, 65535); srv_addr = (struct torture_address) { .sa_socklen = sizeof(struct sockaddr_storage), }; rc = getpeername(s, &srv_addr.sa.s, &srv_addr.sa_socklen); assert_return_code(rc, errno); assert_sockaddr_port_equal(&srv_addr, "127.0.0.10", 7); close(s); } static void test_connect_getsockname_getpeername_port(void **state) { struct torture_address addr = { .sa_socklen = sizeof(struct sockaddr_in), }; struct torture_address cli_addr = { .sa_socklen = sizeof(struct sockaddr_storage), }; struct torture_address srv_addr = { .sa_socklen = sizeof(struct sockaddr_storage), }; int rc; int s; (void) state; /* unused */ s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); assert_return_code(s, errno); /* Bind client address to wildcard address */ addr.sa.in.sin_family = AF_INET; rc = inet_pton(AF_INET, "127.0.0.20", &addr.sa.in.sin_addr); assert_int_equal(rc, 1); addr.sa.in.sin_port = htons(12345); rc = bind(s, &addr.sa.s, addr.sa_socklen); assert_return_code(rc, errno); rc = getsockname(s, &cli_addr.sa.s, &cli_addr.sa_socklen); assert_return_code(rc, errno); assert_sockaddr_port_equal(&cli_addr, "127.0.0.20", 12345); rc = getpeername(s, &srv_addr.sa.s, &srv_addr.sa_socklen); assert_int_equal(rc, -1); assert_int_equal(errno, ENOTCONN); /* connect */ addr = (struct torture_address) { .sa_socklen = sizeof(struct sockaddr_in), .sa.in = (struct sockaddr_in) { .sin_family = AF_INET, .sin_port = htons(torture_server_port()), }, }; rc = inet_pton(AF_INET, torture_server_address(AF_INET), &addr.sa.in.sin_addr); assert_int_equal(rc, 1); /* Connect */ rc = connect(s, &addr.sa.s, addr.sa_socklen); assert_return_code(rc, errno); cli_addr = (struct torture_address) { .sa_socklen = sizeof(struct sockaddr_storage), }; rc = getsockname(s, &cli_addr.sa.s, &cli_addr.sa_socklen); assert_return_code(rc, errno); assert_sockaddr_port_equal(&cli_addr, "127.0.0.20", 12345); srv_addr = (struct torture_address) { .sa_socklen = sizeof(struct sockaddr_storage), }; rc = getpeername(s, &srv_addr.sa.s, &srv_addr.sa_socklen); assert_return_code(rc, errno); assert_sockaddr_port_equal(&srv_addr, "127.0.0.10", 7); close(s); } static void test_connect_getsockname_getpeername_any(void **state) { struct torture_address addr = { .sa_socklen = sizeof(struct sockaddr_in), }; struct torture_address cli_addr = { .sa_socklen = sizeof(struct sockaddr_storage), }; struct torture_address srv_addr = { .sa_socklen = sizeof(struct sockaddr_storage), }; int rc; int s; (void) state; /* unused */ s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); assert_return_code(s, errno); /* Bind client address to wildcard address */ addr.sa.in.sin_family = AF_INET; addr.sa.in.sin_addr.s_addr = htonl(INADDR_ANY); rc = bind(s, &addr.sa.s, addr.sa_socklen); assert_return_code(rc, errno); rc = getsockname(s, &cli_addr.sa.s, &cli_addr.sa_socklen); assert_return_code(rc, errno); assert_sockaddr_port_range_equal(&cli_addr, "0.0.0.0", 1024, 65535); rc = getpeername(s, &srv_addr.sa.s, &srv_addr.sa_socklen); assert_int_equal(rc, -1); assert_int_equal(errno, ENOTCONN); /* connect */ addr.sa.in.sin_family = AF_INET; addr.sa.in.sin_port = htons(torture_server_port()); rc = inet_pton(AF_INET, torture_server_address(AF_INET), &addr.sa.in.sin_addr); assert_int_equal(rc, 1); /* Connect */ rc = connect(s, &addr.sa.s, addr.sa_socklen); assert_return_code(rc, errno); cli_addr = (struct torture_address) { .sa_socklen = sizeof(struct sockaddr_storage), }; rc = getsockname(s, &cli_addr.sa.s, &cli_addr.sa_socklen); assert_return_code(rc, errno); assert_sockaddr_port_range_equal(&cli_addr, "127.0.0.20", 1024, 65535); srv_addr = (struct torture_address) { .sa_socklen = sizeof(struct sockaddr_storage), }; rc = getpeername(s, &srv_addr.sa.s, &srv_addr.sa_socklen); assert_return_code(rc, errno); assert_sockaddr_port_equal(&srv_addr, "127.0.0.10", 7); close(s); } static void test_connect_getsockname_getpeername_any_port(void **state) { struct torture_address addr = { .sa_socklen = sizeof(struct sockaddr_in), }; struct torture_address cli_addr = { .sa_socklen = sizeof(struct sockaddr_storage), }; struct torture_address srv_addr = { .sa_socklen = sizeof(struct sockaddr_storage), }; int rc; int s; (void) state; /* unused */ s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); assert_return_code(s, errno); /* Bind client address to wildcard address */ addr.sa.in.sin_family = AF_INET; addr.sa.in.sin_addr.s_addr = htonl(INADDR_ANY); addr.sa.in.sin_port = htons(12345); rc = bind(s, &addr.sa.s, addr.sa_socklen); assert_return_code(rc, errno); rc = getsockname(s, &cli_addr.sa.s, &cli_addr.sa_socklen); assert_return_code(rc, errno); assert_sockaddr_port_equal(&cli_addr, "0.0.0.0", 12345); rc = getpeername(s, &srv_addr.sa.s, &srv_addr.sa_socklen); assert_int_equal(rc, -1); assert_int_equal(errno, ENOTCONN); /* connect */ addr.sa.in.sin_family = AF_INET; addr.sa.in.sin_port = htons(torture_server_port()); rc = inet_pton(AF_INET, torture_server_address(AF_INET), &addr.sa.in.sin_addr); assert_int_equal(rc, 1); /* Connect */ rc = connect(s, &addr.sa.s, addr.sa_socklen); assert_return_code(rc, errno); cli_addr = (struct torture_address) { .sa_socklen = sizeof(struct sockaddr_storage), }; rc = getsockname(s, &cli_addr.sa.s, &cli_addr.sa_socklen); assert_return_code(rc, errno); assert_sockaddr_port_equal(&cli_addr, "127.0.0.20", 12345); srv_addr = (struct torture_address) { .sa_socklen = sizeof(struct sockaddr_storage), }; rc = getpeername(s, &srv_addr.sa.s, &srv_addr.sa_socklen); assert_return_code(rc, errno); assert_sockaddr_port_equal(&srv_addr, "127.0.0.10", 7); close(s); } static void test_connect_getsockname_getpeername_len(void **state) { struct torture_address addr = { .sa_socklen = sizeof(struct sockaddr_in), }; struct torture_address cli_addr = { .sa_socklen = sizeof(struct sockaddr_storage), }; struct torture_address srv_addr = { .sa_socklen = sizeof(struct sockaddr_storage), }; socklen_t tmp_len; int rc; int s; (void) state; /* unused */ s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); assert_return_code(s, errno); /* connect */ addr.sa.in.sin_family = AF_INET; addr.sa.in.sin_port = htons(torture_server_port()); rc = inet_pton(AF_INET, torture_server_address(AF_INET), &addr.sa.in.sin_addr); assert_int_equal(rc, 1); /* Connect */ rc = connect(s, &addr.sa.s, addr.sa_socklen); assert_return_code(rc, errno); /* Check with len=0 */ cli_addr.sa_socklen = 0; rc = getsockname(s, &cli_addr.sa.s, &cli_addr.sa_socklen); assert_return_code(rc, errno); srv_addr.sa_socklen = 0; rc = getpeername(s, &srv_addr.sa.s, &srv_addr.sa_socklen); assert_return_code(rc, errno); /* Check with len=too small */ cli_addr = (struct torture_address) { .sa_socklen = sizeof(struct sockaddr_in) - 2, }; tmp_len = cli_addr.sa_socklen; rc = getsockname(s, &cli_addr.sa.s, &cli_addr.sa_socklen); assert_return_code(rc, errno); assert_int_equal(tmp_len + 2, cli_addr.sa_socklen); srv_addr = (struct torture_address) { .sa_socklen = sizeof(struct sockaddr_in) - 2, }; tmp_len = srv_addr.sa_socklen; rc = getpeername(s, &srv_addr.sa.s, &srv_addr.sa_socklen); assert_return_code(rc, errno); assert_int_equal(tmp_len + 2, srv_addr.sa_socklen); close(s); } int main(void) { int rc; const struct CMUnitTest sock_name_tests[] = { cmocka_unit_test_setup_teardown(test_connect_getsockname_getpeername, setup_echo_srv_tcp_ipv4, teardown), cmocka_unit_test_setup_teardown(test_connect_getsockname_getpeername_port, setup_echo_srv_tcp_ipv4, teardown), cmocka_unit_test_setup_teardown(test_connect_getsockname_getpeername_any, setup_echo_srv_tcp_ipv4, teardown), cmocka_unit_test_setup_teardown(test_connect_getsockname_getpeername_any_port, setup_echo_srv_tcp_ipv4, teardown), cmocka_unit_test_setup_teardown(test_connect_getsockname_getpeername_len, setup_echo_srv_tcp_ipv4, teardown), }; rc = cmocka_run_group_tests(sock_name_tests, NULL, NULL); return rc; } socket_wrapper-1.2.3/tests/test_echo_udp_sendto_recvfrom.c000644 001750 000144 00000014536 13374561011 024151 0ustar00asnusers000000 000000 #include #include #include #include #include "config.h" #include "torture.h" #include #include #include #include #include #include #include #include static int setup_echo_srv_udp_ipv4(void **state) { torture_setup_echo_srv_udp_ipv4(state); return 0; } #ifdef HAVE_IPV6 static int setup_echo_srv_udp_ipv6(void **state) { torture_setup_echo_srv_udp_ipv6(state); return 0; } #endif static int teardown(void **state) { torture_teardown_echo_srv(state); return 0; } static void test_sendto_recvfrom_ipv4(void **state) { struct torture_address addr = { .sa_socklen = sizeof(struct sockaddr_in), }; char send_buf[64] = {0}; char recv_buf[64] = {0}; ssize_t ret; int rc; int i; int s; (void) state; /* unused */ s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); assert_int_not_equal(s, -1); addr.sa.in.sin_family = AF_INET; addr.sa.in.sin_port = htons(torture_server_port()); rc = inet_pton(AF_INET, torture_server_address(AF_INET), &addr.sa.in.sin_addr); assert_int_equal(rc, 1); for (i = 0; i < 10; i++) { char ip[INET_ADDRSTRLEN] = {0}; const char *a; struct torture_address srv_in = { .sa_socklen = sizeof(struct sockaddr_in), }; snprintf(send_buf, sizeof(send_buf), "packet.%d", i); ret = sendto(s, send_buf, sizeof(send_buf), 0, &addr.sa.s, addr.sa_socklen); assert_return_code(ret, errno); ret = recvfrom(s, recv_buf, sizeof(recv_buf), 0, &srv_in.sa.s, &srv_in.sa_socklen); assert_return_code(ret, errno); a = inet_ntop(AF_INET, &srv_in.sa.in.sin_addr, ip, sizeof(ip)); assert_non_null(a); assert_string_equal(a, torture_server_address(AF_INET)); assert_memory_equal(send_buf, recv_buf, sizeof(send_buf)); } ret = sendto(s, send_buf, sizeof(send_buf), 0, &addr.sa.s, addr.sa_socklen); assert_return_code(ret, errno); ret = recvfrom(s, recv_buf, sizeof(recv_buf), 0, NULL, NULL); assert_return_code(ret, errno); close(s); } #ifdef HAVE_IPV6 static void test_sendto_recvfrom_ipv6(void **state) { struct torture_address addr = { .sa_socklen = sizeof(struct sockaddr_in6), }; char send_buf[64] = {0}; char recv_buf[64] = {0}; ssize_t ret; int rc; int i; int s; (void) state; /* unused */ s = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP); assert_int_not_equal(s, -1); addr.sa.in6.sin6_family = AF_INET6; addr.sa.in6.sin6_port = htons(torture_server_port()); rc = inet_pton(AF_INET6, torture_server_address(AF_INET6), &addr.sa.in6.sin6_addr); assert_int_equal(rc, 1); for (i = 0; i < 10; i++) { char ip[INET6_ADDRSTRLEN] = {0}; const char *a; struct torture_address srv_in6 = { .sa_socklen = sizeof(struct sockaddr_in6), }; snprintf(send_buf, sizeof(send_buf), "packet.%d", i); ret = sendto(s, send_buf, sizeof(send_buf), 0, &addr.sa.s, addr.sa_socklen); assert_return_code(ret, errno); ret = recvfrom(s, recv_buf, sizeof(recv_buf), 0, &srv_in6.sa.s, &srv_in6.sa_socklen); assert_return_code(ret, errno); a = inet_ntop(AF_INET6, &srv_in6.sa.in6.sin6_addr, ip, sizeof(ip)); assert_non_null(a); assert_string_equal(a, torture_server_address(AF_INET6)); assert_memory_equal(send_buf, recv_buf, sizeof(send_buf)); } ret = sendto(s, send_buf, sizeof(send_buf), 0, &addr.sa.s, addr.sa_socklen); assert_return_code(ret, errno); ret = recvfrom(s, recv_buf, sizeof(recv_buf), 0, NULL, NULL); assert_return_code(ret, errno); close(s); } #endif static void test_connect_sendto_ipv4(void **state) { struct torture_address addr = { .sa_socklen = sizeof(struct sockaddr_in), }; char send_buf[] = "packet.0"; char recv_buf[64] = {0}; ssize_t ret; int rc; int s; (void) state; /* unused */ addr.sa.in.sin_family = AF_INET; addr.sa.in.sin_port = htons(torture_server_port()); rc = inet_pton(AF_INET, torture_server_address(AF_INET), &addr.sa.in.sin_addr); assert_int_equal(rc, 1); s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); assert_int_not_equal(s, -1); /* Now, connect */ rc = connect(s, &addr.sa.s, addr.sa_socklen); assert_return_code(rc, errno); ret = sendto(s, send_buf, sizeof(send_buf), 0, &addr.sa.s, addr.sa_socklen); assert_return_code(ret, errno); ret = recvfrom(s, recv_buf, sizeof(recv_buf), 0, NULL, 0); assert_return_code(ret, errno); assert_memory_equal(send_buf, recv_buf, sizeof(send_buf)); close(s); } static void test_connect_sendto_null_ipv4(void **state) { struct torture_address addr = { .sa_socklen = sizeof(struct sockaddr_in), }; char send_buf[] = "packet.0"; char recv_buf[64] = {0}; ssize_t ret; int rc; int s; (void) state; /* unused */ addr.sa.in.sin_family = AF_INET; addr.sa.in.sin_port = htons(torture_server_port()); rc = inet_pton(AF_INET, torture_server_address(AF_INET), &addr.sa.in.sin_addr); assert_int_equal(rc, 1); s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); assert_int_not_equal(s, -1); /* Now, connect */ rc = connect(s, &addr.sa.s, addr.sa_socklen); assert_return_code(rc, errno); ret = sendto(s, send_buf, sizeof(send_buf), 0, NULL, 0); assert_return_code(ret, errno); ret = recvfrom(s, recv_buf, sizeof(recv_buf), 0, NULL, 0); assert_return_code(ret, errno); assert_memory_equal(send_buf, recv_buf, sizeof(send_buf)); close(s); } int main(void) { int rc; const struct CMUnitTest sendto_tests[] = { cmocka_unit_test_setup_teardown(test_sendto_recvfrom_ipv4, setup_echo_srv_udp_ipv4, teardown), #ifdef HAVE_IPV6 cmocka_unit_test_setup_teardown(test_sendto_recvfrom_ipv6, setup_echo_srv_udp_ipv6, teardown), #endif cmocka_unit_test_setup_teardown(test_connect_sendto_ipv4, setup_echo_srv_udp_ipv4, teardown), cmocka_unit_test_setup_teardown(test_connect_sendto_null_ipv4, setup_echo_srv_udp_ipv4, teardown), }; rc = cmocka_run_group_tests(sendto_tests, NULL, NULL); return rc; } socket_wrapper-1.2.3/tests/test_tcp_socket_overwrite.c000644 001750 000144 00000002440 13374561011 023337 0ustar00asnusers000000 000000 #include "torture.h" #include #include #include #include static int setup(void **state) { torture_setup_socket_dir(state); return 0; } static int teardown(void **state) { torture_teardown_socket_dir(state); return 0; } static void test_tcp_socket_overwrite(void **state) { struct torture_address addr_in = { .sa_socklen = sizeof(struct sockaddr_in), .sa.in = (struct sockaddr_in) { .sin_family = AF_INET, }, }; int s, dup_s, new_s, rc; (void) state; /* unused */ s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); assert_int_not_equal(s, -1); dup_s = dup(s); assert_int_not_equal(dup_s, -1); close(dup_s); new_s = socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP); assert_int_not_equal(new_s, -1); close(new_s); rc = inet_pton(AF_INET, "127.0.0.20", &addr_in.sa.in.sin_addr); assert_int_equal(rc, 1); /* bind should fail during socklen check if old socket info * is overwritten by new socket info */ rc = bind(s, &addr_in.sa.s, addr_in.sa_socklen); assert_return_code(rc, errno); close(s); } int main(void) { int rc; const struct CMUnitTest tcp_socket_overwrite_tests[] = { cmocka_unit_test(test_tcp_socket_overwrite), }; rc = cmocka_run_group_tests(tcp_socket_overwrite_tests, setup, teardown); return rc; } socket_wrapper-1.2.3/tests/test_thread_sockets.c000644 001750 000144 00000002265 13374561011 022102 0ustar00asnusers000000 000000 #include "config.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #define NUM_THREADS 10 static void *thread_worker(void *arg) { int i; (void) arg; /* unused */ for (i = 0; i < 1000; i++) { int s; s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); assert_return_code(s, errno); close(s); } return NULL; } static void test_threads_socket(void **state) { pthread_attr_t pthread_custom_attr; pthread_t threads[NUM_THREADS]; int i; (void) state; /* unused */ pthread_attr_init(&pthread_custom_attr); for (i = 0; i < NUM_THREADS; i++) { pthread_create(&threads[i], &pthread_custom_attr, thread_worker, NULL); } for (i = 0; i < NUM_THREADS; i++) { pthread_join(threads[i], NULL); } pthread_attr_destroy(&pthread_custom_attr); } int main(void) { int rc; const struct CMUnitTest thread_tests[] = { cmocka_unit_test(test_threads_socket), }; rc = cmocka_run_group_tests(thread_tests, NULL, NULL); return rc; } socket_wrapper-1.2.3/tests/torture.h000644 001750 000144 00000005262 13272341670 017556 0ustar00asnusers000000 000000 /* * Copyright (C) Andreas Schneider 2013 * * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 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. * * 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. * * 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. */ #ifndef _TORTURE_H #define _TORTURE_H #include "config.h" #include #include #include #include #include #include #include #include #include struct torture_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; }; struct torture_state { char *socket_dir; char *pcap_file; char *srv_pidfile; }; #ifndef ZERO_STRUCT #define ZERO_STRUCT(x) memset((char *)&(x), 0, sizeof(x)) #endif const char *torture_server_address(int domain); int torture_server_port(void); void torture_setup_socket_dir(void **state); void torture_setup_echo_srv_udp_ipv4(void **state); void torture_setup_echo_srv_udp_ipv6(void **state); void torture_setup_echo_srv_tcp_ipv4(void **state); void torture_setup_echo_srv_tcp_ipv6(void **state); void torture_teardown_socket_dir(void **state); void torture_teardown_echo_srv(void **state); void torture_generate_random_buffer(uint8_t *out, int len); #endif /* _TORTURE_H */ socket_wrapper-1.2.3/tests/test_echo_tcp_connect.c000644 001750 000144 00000003736 13372600005 022374 0ustar00asnusers000000 000000 #include #include #include #include #include "config.h" #include "torture.h" #include #include #include #include #include #include #include #include static int setup_echo_srv_tcp_ipv4(void **state) { torture_setup_echo_srv_tcp_ipv4(state); return 0; } static int teardown(void **state) { torture_teardown_echo_srv(state); return 0; } static void test_connect_broadcast_ipv4(void **state) { struct torture_address addr = { .sa_socklen = sizeof(struct sockaddr_in), }; int rc; int s; (void) state; /* unused */ s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); assert_int_not_equal(s, -1); addr.sa.in.sin_family = AF_INET; addr.sa.in.sin_port = htons(torture_server_port()); addr.sa.in.sin_addr.s_addr = INADDR_BROADCAST; /* We don't allow connect to broadcast addresses */ rc = connect(s, &addr.sa.s, addr.sa_socklen); assert_int_equal(rc, -1); close(s); } #ifdef HAVE_IPV6 static void test_connect_downgrade_ipv6(void **state) { struct torture_address addr = { .sa_socklen = sizeof(struct sockaddr_in), }; int rc; int s; (void) state; /* unused */ s = socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP); assert_int_not_equal(s, -1); addr.sa.in.sin_family = AF_INET; addr.sa.in.sin_port = htons(torture_server_port()); rc = inet_pton(addr.sa.in.sin_family, torture_server_address(AF_INET), &addr.sa.in.sin_addr); assert_int_equal(rc, 1); /* Connect should downgrade to IPv4 and allow the connect */ rc = connect(s, &addr.sa.s, addr.sa_socklen); assert_int_equal(rc, 0); close(s); } #endif int main(void) { int rc; const struct CMUnitTest tcp_connect_tests[] = { cmocka_unit_test(test_connect_broadcast_ipv4), #ifdef HAVE_IPV6 cmocka_unit_test(test_connect_downgrade_ipv6), #endif }; rc = cmocka_run_group_tests(tcp_connect_tests, setup_echo_srv_tcp_ipv4, teardown); return rc; } socket_wrapper-1.2.3/tests/test_echo_tcp_socket_options.c000644 001750 000144 00000017100 13372600005 023774 0ustar00asnusers000000 000000 #include #include #include #include #include "config.h" #include "torture.h" #include #include #include #include #include #include #include #include #include #include #ifndef ZERO_STRUCT #define ZERO_STRUCT(x) memset((char *)&(x), 0, sizeof(x)) #endif static int setup_echo_srv_tcp_ipv4(void **state) { torture_setup_echo_srv_tcp_ipv4(state); return 0; } #ifdef HAVE_IPV6 static int setup_echo_srv_tcp_ipv6(void **state) { torture_setup_echo_srv_tcp_ipv6(state); return 0; } static int setup_ipv6(void **state) { torture_setup_socket_dir(state); return 0; } #endif static int teardown(void **state) { torture_teardown_echo_srv(state); return 0; } static void test_sockopt_sndbuf(void **state) { struct torture_address addr = { .sa_socklen = sizeof(struct sockaddr_in), }; int obufsize = 0; socklen_t olen = sizeof(obufsize); int gbufsize = 0; socklen_t glen = sizeof(gbufsize); int sbufsize = 0; int rc; int s; (void) state; /* unused */ s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); assert_int_not_equal(s, -1); addr.sa.in.sin_family = AF_INET; addr.sa.in.sin_port = htons(torture_server_port()); rc = inet_pton(addr.sa.in.sin_family, torture_server_address(AF_INET), &addr.sa.in.sin_addr); assert_int_equal(rc, 1); rc = connect(s, &addr.sa.s, addr.sa_socklen); assert_int_equal(rc, 0); rc = getsockopt(s, SOL_SOCKET, SO_SNDBUF, &obufsize, &olen); assert_int_equal(rc, 0); /* request 4k, on Linux the kernel doubles the value */ sbufsize = 4096; rc = setsockopt(s, SOL_SOCKET, SO_SNDBUF, &sbufsize, sizeof(sbufsize)); assert_int_equal(rc, 0); rc = getsockopt(s, SOL_SOCKET, SO_SNDBUF, &gbufsize, &glen); assert_int_equal(rc, 0); assert_true(sbufsize == gbufsize || sbufsize == gbufsize/2); close(s); } #ifndef SO_PROTOCOL # ifdef SO_PROTOTYPE /* The Solaris name */ # define SO_PROTOCOL SO_PROTOTYPE # endif /* SO_PROTOTYPE */ #endif /* SO_PROTOCOL */ static void test_sockopt_so(void **state) { struct torture_address addr = { .sa_socklen = sizeof(struct sockaddr_in), }; socklen_t so_len; #ifdef SO_DOMAIN int so_domain = -1; #endif /* SO_DOMAIN */ #ifdef SO_PROTOCOL int so_protocol = -1; int so_type = -1; #endif /* SO_PROTOCOL */ int rc; int s; (void) state; /* unused */ s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); assert_int_not_equal(s, -1); addr.sa.in.sin_family = AF_INET; addr.sa.in.sin_port = htons(torture_server_port()); rc = inet_pton(addr.sa.in.sin_family, torture_server_address(AF_INET), &addr.sa.in.sin_addr); assert_int_equal(rc, 1); rc = connect(s, &addr.sa.s, addr.sa_socklen); assert_int_equal(rc, 0); #ifdef SO_DOMAIN so_len = sizeof(so_domain); rc = getsockopt(s, SOL_SOCKET, SO_DOMAIN, &so_domain, &so_len); assert_return_code(rc, errno); assert_int_equal(so_domain, AF_INET); assert_int_equal(so_len, sizeof(int)); #endif /* SO_DOMAIN */ #ifdef SO_PROTOCOL so_len = sizeof(so_protocol); rc = getsockopt(s, SOL_SOCKET, SO_PROTOCOL, &so_protocol, &so_len); assert_return_code(rc, errno); assert_int_equal(so_protocol, IPPROTO_TCP); assert_int_equal(so_len, sizeof(int)); so_len = sizeof(so_type); rc = getsockopt(s, SOL_SOCKET, SO_TYPE, &so_type, &so_len); assert_return_code(rc, errno); assert_int_equal(so_type, SOCK_STREAM); assert_int_equal(so_len, sizeof(int)); #endif /* SO_PROTOCOL */ close(s); } #ifdef HAVE_IPV6 static void test_sockopt_so6(void **state) { struct torture_address addr = { .sa_socklen = sizeof(struct sockaddr_in), }; #ifdef SO_DOMAIN int so_domain = -1; #endif /* SO_DOMAIN */ #ifdef SO_PROTOCOL socklen_t so_len; int so_protocol = -1; int so_type = -1; #endif /* SO_PROTOCOL */ int rc; int s; (void) state; /* unused */ s = socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP); assert_int_not_equal(s, -1); addr.sa.in6.sin6_family = AF_INET6; addr.sa.in6.sin6_port = htons(torture_server_port()); rc = inet_pton(addr.sa.in6.sin6_family, torture_server_address(AF_INET6), &addr.sa.in6.sin6_addr); assert_int_equal(rc, 1); rc = connect(s, &addr.sa.s, addr.sa_socklen); assert_int_equal(rc, 0); #ifdef SO_DOMAIN so_len = sizeof(so_domain); rc = getsockopt(s, SOL_SOCKET, SO_DOMAIN, &so_domain, &so_len); assert_return_code(rc, errno); assert_int_equal(so_domain, AF_INET6); assert_int_equal(so_len, sizeof(int)); #endif /* SO_DOMAIN */ #ifdef SO_PROTOCOL so_len = sizeof(so_protocol); rc = getsockopt(s, SOL_SOCKET, SO_PROTOCOL, &so_protocol, &so_len); assert_return_code(rc, errno); assert_int_equal(so_protocol, IPPROTO_TCP); assert_int_equal(so_len, sizeof(int)); so_len = sizeof(so_type); rc = getsockopt(s, SOL_SOCKET, SO_TYPE, &so_type, &so_len); assert_return_code(rc, errno); assert_int_equal(so_type, SOCK_STREAM); assert_int_equal(so_len, sizeof(int)); #endif /* SO_PROTOCOL */ close(s); } static void test_bind_ipv6_only(void **state) { struct addrinfo hints; struct addrinfo *res, *ri; char svc[] = "7777"; int rc; int s; (void) state; /* unused */ ZERO_STRUCT(hints); hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; hints.ai_flags = AI_PASSIVE; rc = getaddrinfo(torture_server_address(AF_INET6), svc, &hints, &res); assert_int_equal(rc, 0); for (ri = res; ri != NULL; ri = ri->ai_next) { int one = 1; s = socket(ri->ai_family, ri->ai_socktype, ri->ai_protocol); assert_int_not_equal(rc, -1); rc = setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, (const void *)&one, sizeof(one)); switch(ri->ai_family) { case AF_INET: assert_int_equal(rc, -1); break; case AF_INET6: assert_int_equal(rc, 0); rc = bind(s, ri->ai_addr, ri->ai_addrlen); assert_int_equal(rc, 0); break; default: break; } close(s); } freeaddrinfo(res); } #endif static void test_sockopt_tcp(void **state) { struct torture_address addr = { .sa_socklen = sizeof(struct sockaddr_in), }; int opt = -1; socklen_t optlen = sizeof(int); int rc; int s; (void) state; /* unused */ s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); assert_int_not_equal(s, -1); addr.sa.in.sin_family = AF_INET; addr.sa.in.sin_port = htons(torture_server_port()); rc = inet_pton(addr.sa.in.sin_family, torture_server_address(AF_INET), &addr.sa.in.sin_addr); assert_int_equal(rc, 1); rc = connect(s, &addr.sa.s, addr.sa_socklen); assert_int_equal(rc, 0); rc = getsockopt(s, IPPROTO_TCP, TCP_NODELAY, &opt, &optlen); assert_return_code(rc, errno); assert_int_equal(opt, 0); opt = 1; /* Turn on TCP_NODELAY */ optlen = sizeof(int); rc = setsockopt(s, IPPROTO_TCP, TCP_NODELAY, &opt, optlen); assert_return_code(rc, errno); opt = -1; optlen = sizeof(int); rc = getsockopt(s, IPPROTO_TCP, TCP_NODELAY, &opt, &optlen); assert_return_code(rc, errno); assert_int_equal(opt, 1); close(s); } int main(void) { int rc; const struct CMUnitTest sockopt_tests[] = { cmocka_unit_test_setup_teardown(test_sockopt_sndbuf, setup_echo_srv_tcp_ipv4, teardown), cmocka_unit_test_setup_teardown(test_sockopt_so, setup_echo_srv_tcp_ipv4, teardown), #ifdef HAVE_IPV6 cmocka_unit_test_setup_teardown(test_sockopt_so6, setup_echo_srv_tcp_ipv6, teardown), cmocka_unit_test_setup_teardown(test_bind_ipv6_only, setup_ipv6, teardown), #endif cmocka_unit_test_setup_teardown(test_sockopt_tcp, setup_echo_srv_tcp_ipv4, teardown), }; rc = cmocka_run_group_tests(sockopt_tests, NULL, NULL); return rc; } socket_wrapper-1.2.3/tests/test_echo_tcp_write_read.c000644 001750 000144 00000005662 13372600005 023070 0ustar00asnusers000000 000000 #include #include #include #include #include "config.h" #include "torture.h" #include #include #include #include #include #include #include #include static int setup_echo_srv_tcp_ipv4(void **state) { torture_setup_echo_srv_tcp_ipv4(state); return 0; } #ifdef HAVE_IPV6 static int setup_echo_srv_tcp_ipv6(void **state) { torture_setup_echo_srv_tcp_ipv6(state); return 0; } #endif static int teardown(void **state) { torture_teardown_echo_srv(state); return 0; } static void test_write_read_ipv4(void **state) { struct torture_address addr = { .sa_socklen = sizeof(struct sockaddr_in), }; ssize_t ret; int rc; int i; int s; (void) state; /* unused */ s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); assert_int_not_equal(s, -1); addr.sa.in.sin_family = AF_INET; addr.sa.in.sin_port = htons(torture_server_port()); rc = inet_pton(addr.sa.in.sin_family, torture_server_address(AF_INET), &addr.sa.in.sin_addr); assert_int_equal(rc, 1); rc = connect(s, &addr.sa.s, addr.sa_socklen); assert_int_equal(rc, 0); for (i = 0; i < 10; i++) { char send_buf[64] = {0}; char recv_buf[64] = {0}; snprintf(send_buf, sizeof(send_buf), "packet.%d", i); ret = write(s, send_buf, sizeof(send_buf)); assert_int_not_equal(ret, -1); ret = read(s, recv_buf, sizeof(recv_buf)); assert_int_not_equal(ret, -1); assert_memory_equal(send_buf, recv_buf, sizeof(send_buf)); } close(s); } #ifdef HAVE_IPV6 static void test_write_read_ipv6(void **state) { struct torture_address addr = { .sa_socklen = sizeof(struct sockaddr_in6), }; ssize_t ret; int rc; int i; int s; (void) state; /* unused */ s = socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP); assert_int_not_equal(s, -1); addr.sa.in6.sin6_family = AF_INET6; addr.sa.in6.sin6_port = htons(torture_server_port()); rc = inet_pton(AF_INET6, torture_server_address(AF_INET6), &addr.sa.in6.sin6_addr); assert_int_equal(rc, 1); rc = connect(s, &addr.sa.s, addr.sa_socklen); assert_int_equal(rc, 0); for (i = 0; i < 10; i++) { char send_buf[64] = {0}; char recv_buf[64] = {0}; snprintf(send_buf, sizeof(send_buf), "packet.%d", i); ret = write(s, send_buf, sizeof(send_buf)); assert_int_not_equal(ret, -1); ret = read(s, recv_buf, sizeof(recv_buf)); assert_int_not_equal(ret, -1); assert_memory_equal(send_buf, recv_buf, sizeof(send_buf)); } close(s); } #endif int main(void) { int rc; const struct CMUnitTest tcp_write_tests[] = { cmocka_unit_test_setup_teardown(test_write_read_ipv4, setup_echo_srv_tcp_ipv4, teardown), #ifdef HAVE_IPV6 cmocka_unit_test_setup_teardown(test_write_read_ipv6, setup_echo_srv_tcp_ipv6, teardown), #endif }; rc = cmocka_run_group_tests(tcp_write_tests, NULL, NULL); return rc; } socket_wrapper-1.2.3/tests/test_echo_tcp_writev_readv.c000644 001750 000144 00000007355 13372600005 023445 0ustar00asnusers000000 000000 #include #include #include #include #include "config.h" #include "torture.h" #include #include #include #include #include #include #include #include #include static int setup_echo_srv_tcp_ipv4(void **state) { torture_setup_echo_srv_tcp_ipv4(state); return 0; } #ifdef HAVE_IPV6 static int setup_echo_srv_tcp_ipv6(void **state) { torture_setup_echo_srv_tcp_ipv6(state); return 0; } #endif static int teardown(void **state) { torture_teardown_echo_srv(state); return 0; } static void test_writev_readv_ipv4(void **state) { struct torture_address addr = { .sa_socklen = sizeof(struct sockaddr_in), }; ssize_t ret; int rc; int i; int s; (void) state; /* unused */ s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); assert_int_not_equal(s, -1); addr.sa.in.sin_family = AF_INET; addr.sa.in.sin_port = htons(torture_server_port()); rc = inet_pton(addr.sa.in.sin_family, torture_server_address(AF_INET), &addr.sa.in.sin_addr); assert_int_equal(rc, 1); rc = connect(s, &addr.sa.s, addr.sa_socklen); assert_int_equal(rc, 0); for (i = 1; i < 10; i++) { char send_buf[10][64]; char recv_buf[10][64]; struct iovec iov_send[10]; struct iovec iov_recv[10]; int j; for (j = 0; j < i; j++) { memset(send_buf[j], 0, 64); snprintf(send_buf[j], sizeof(send_buf[j]), "packet.%d", j); iov_send[j].iov_base = send_buf[j]; iov_send[j].iov_len = strlen(send_buf[j]); iov_recv[j].iov_base = recv_buf[j]; iov_recv[j].iov_len = strlen(send_buf[j]); } ret = writev(s, iov_send, j); assert_int_not_equal(ret, -1); ret = readv(s, iov_recv, j); assert_int_not_equal(ret, -1); for (j = 0; j < i; j++) { assert_int_equal(iov_send[j].iov_len, iov_recv[j].iov_len); assert_memory_equal(iov_send[j].iov_base, iov_recv[j].iov_base, iov_send[j].iov_len); } } close(s); } #ifdef HAVE_IPV6 static void test_writev_readv_ipv6(void **state) { struct torture_address addr = { .sa_socklen = sizeof(struct sockaddr_in6), }; ssize_t ret; int rc; int i; int s; (void) state; /* unused */ s = socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP); assert_int_not_equal(s, -1); addr.sa.in6.sin6_family = AF_INET6; addr.sa.in6.sin6_port = htons(torture_server_port()); rc = inet_pton(AF_INET6, torture_server_address(AF_INET6), &addr.sa.in6.sin6_addr); assert_int_equal(rc, 1); rc = connect(s, &addr.sa.s, addr.sa_socklen); assert_int_equal(rc, 0); for (i = 1; i < 10; i++) { char send_buf[10][64]; char recv_buf[10][64]; struct iovec iov_send[10]; struct iovec iov_recv[10]; int j; for (j = 0; j < i; j++) { memset(send_buf[j], 0, 64); snprintf(send_buf[j], sizeof(send_buf[j]), "packet.%d", j); iov_send[j].iov_base = send_buf[j]; iov_send[j].iov_len = strlen(send_buf[j]); iov_recv[j].iov_base = recv_buf[j]; iov_recv[j].iov_len = strlen(send_buf[j]); } ret = writev(s, iov_send, j); assert_int_not_equal(ret, -1); ret = readv(s, iov_recv, j); assert_int_not_equal(ret, -1); for (j = 0; j < i; j++) { assert_int_equal(iov_send[j].iov_len, iov_recv[j].iov_len); assert_memory_equal(iov_send[j].iov_base, iov_recv[j].iov_base, iov_send[j].iov_len); } } close(s); } #endif int main(void) { int rc; const struct CMUnitTest tcp_writev_tests[] = { cmocka_unit_test_setup_teardown(test_writev_readv_ipv4, setup_echo_srv_tcp_ipv4, teardown), #ifdef HAVE_IPV6 cmocka_unit_test_setup_teardown(test_writev_readv_ipv6, setup_echo_srv_tcp_ipv6, teardown), #endif }; rc = cmocka_run_group_tests(tcp_writev_tests, NULL, NULL); return rc; } socket_wrapper-1.2.3/tests/test_ioctl.c000644 001750 000144 00000003714 13372600005 020205 0ustar00asnusers000000 000000 #include #include #include #include #include #include #include #include #include #include #include #include #include static int setup(void **state) { char test_tmpdir[256]; const char *p; (void) state; /* unused */ snprintf(test_tmpdir, sizeof(test_tmpdir), "/tmp/test_socket_wrapper_XXXXXX"); p = mkdtemp(test_tmpdir); assert_non_null(p); *state = strdup(p); setenv("SOCKET_WRAPPER_DIR", p, 1); setenv("SOCKET_WRAPPER_DEFAULT_IFACE", "11", 1); return 0; } static int teardown(void **state) { char remove_cmd[PATH_MAX] = {0}; char *s = (char *)*state; int rc; if (s == NULL) { return -1; } snprintf(remove_cmd, sizeof(remove_cmd), "rm -rf %s", s); free(s); rc = system(remove_cmd); if (rc < 0) { fprintf(stderr, "%s failed: %s", remove_cmd, strerror(errno)); } return rc; } static void test_swrap_socket(void **state) { int rc; (void) state; /* unused */ rc = socket(1337, 1337, 0); assert_int_equal(rc, -1); assert_int_equal(errno, EAFNOSUPPORT); rc = socket(AF_INET, 1337, 0); assert_int_equal(rc, -1); assert_int_equal(errno, EPROTONOSUPPORT); rc = socket(AF_INET, SOCK_DGRAM, 10); assert_int_equal(rc, -1); assert_int_equal(errno, EPROTONOSUPPORT); } static void test_swrap_ioctl_sock(void **state) { int fd; #ifdef SIOCGPGRP int rc; int grp = -127; #endif (void) state; /* unused */ fd = socket(AF_INET, SOCK_DGRAM, 0); assert_int_not_equal(fd, -1); #ifdef SIOCGPGRP rc = ioctl(fd, SIOCGPGRP, &grp); assert_int_equal(rc, 0); assert_int_not_equal(grp, -127); #endif close(fd); } int main(void) { int rc; const struct CMUnitTest ioctl_tests[] = { cmocka_unit_test_setup_teardown(test_swrap_socket, setup, teardown), cmocka_unit_test_setup_teardown(test_swrap_ioctl_sock, setup, teardown), }; rc = cmocka_run_group_tests(ioctl_tests, NULL, NULL); return rc; } socket_wrapper-1.2.3/tests/test_sendmsg_recvmsg_fd.c000644 001750 000144 00000004664 13372600005 022737 0ustar00asnusers000000 000000 #include #include #include #include #include #include #include #include #include #include #include #include #include static void test_sendmsg_recvmsg_fd(void **state) { int sv[2]; int child_fd, parent_fd; int rc; pid_t pid; (void) state; /* unused */ rc = socketpair(AF_LOCAL, SOCK_STREAM, 0, sv); assert_int_not_equal(rc, -1); parent_fd = sv[0]; child_fd = sv[1]; pid = fork(); assert_int_not_equal(pid, -1); if (pid == 0) { /* Child */ struct msghdr child_msg; char cmsgbuf[CMSG_SPACE(sizeof(int))]; struct cmsghdr *cmsg; int rcv_fd; char buf[8]; int i; memset(&child_msg, 0, sizeof(child_msg)); child_msg.msg_control = cmsgbuf; child_msg.msg_controllen = sizeof(cmsgbuf); do { errno = 0; rc = recvmsg(child_fd, &child_msg, 0); } while (errno == EAGAIN || errno == EWOULDBLOCK); assert_int_not_equal(rc, -1); cmsg = CMSG_FIRSTHDR(&child_msg); assert_non_null(cmsg); assert_int_equal(cmsg->cmsg_type, SCM_RIGHTS); memcpy(&rcv_fd, CMSG_DATA(cmsg), sizeof(rcv_fd)); assert_int_not_equal(rcv_fd, -1); rc = read(rcv_fd, buf, sizeof(buf)); assert_int_not_equal(rc, -1); for (i = 0; i < 8; i++) { assert_int_equal(buf[i], 0); } exit(0); } else { /* Parent */ int pass_fd; struct msghdr parent_msg; struct cmsghdr *cmsg; char cmsgbuf[CMSG_SPACE(sizeof(pass_fd))]; char byte = '!'; struct iovec iov; int cs; pass_fd = open("/dev/zero", O_RDONLY); assert_int_not_equal(pass_fd, -1); iov.iov_base = &byte; iov.iov_len = 1; memset(&parent_msg, 0, sizeof(parent_msg)); parent_msg.msg_iov = &iov; parent_msg.msg_iovlen = 1; parent_msg.msg_control = cmsgbuf; parent_msg.msg_controllen = sizeof(cmsgbuf); cmsg = CMSG_FIRSTHDR(&parent_msg); cmsg->cmsg_level = SOL_SOCKET; cmsg->cmsg_type = SCM_RIGHTS; cmsg->cmsg_len = CMSG_LEN(sizeof(pass_fd)); memcpy(CMSG_DATA(cmsg), &pass_fd, sizeof(pass_fd)); parent_msg.msg_controllen = cmsg->cmsg_len; rc = sendmsg(parent_fd, &parent_msg, 0); assert_int_not_equal(rc, -1); alarm(5); /* 5 seconds timeout for the child */ rc = waitpid(pid, &cs, 0); assert_int_not_equal(rc, -1); } } int main(void) { int rc; const struct CMUnitTest tests[] = { cmocka_unit_test(test_sendmsg_recvmsg_fd), }; rc = cmocka_run_group_tests(tests, NULL, NULL); return rc; } socket_wrapper-1.2.3/tests/test_tcp_dup2.c000644 001750 000144 00000001517 13372600005 020612 0ustar00asnusers000000 000000 #include "torture.h" #include #include static int setup(void **state) { torture_setup_socket_dir(state); return 0; } static int teardown(void **state) { torture_teardown_socket_dir(state); return 0; } static void test_dup2_existing_open_fd(void **state) { int s, dup_s; (void) state; /* unused */ s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); assert_int_not_equal(s, -1); /* * Here we try to duplicate the existing socket fd to itself * and as per man page for dup2() it must return the already * open fd without any failure. */ dup_s = dup2(s, s); assert_int_equal(dup_s, s); close(s); } int main(void) { int rc; const struct CMUnitTest tcp_dup2_tests[] = { cmocka_unit_test(test_dup2_existing_open_fd), }; rc = cmocka_run_group_tests(tcp_dup2_tests, setup, teardown); return rc; } socket_wrapper-1.2.3/tests/test_thread_echo_udp_send_recv.c000644 001750 000144 00000004274 13372600005 024242 0ustar00asnusers000000 000000 #include #include #include #include #include #include "config.h" #include "torture.h" #include #include #include #include #include #include #include #include #define NUM_THREADS 10 static int setup_echo_srv_udp_ipv4(void **state) { torture_setup_echo_srv_udp_ipv4(state); return 0; } static int teardown(void **state) { torture_teardown_echo_srv(state); return 0; } static void *thread_worker(void *arg) { struct torture_address addr = { .sa_socklen = sizeof(struct sockaddr_in), }; ssize_t ret; int rc; int i; int s; (void) arg; /* unused */ s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); assert_int_not_equal(s, -1); addr.sa.in.sin_family = AF_INET; addr.sa.in.sin_port = htons(torture_server_port()); rc = inet_pton(AF_INET, torture_server_address(AF_INET), &addr.sa.in.sin_addr); assert_int_equal(rc, 1); rc = connect(s, &addr.sa.s, addr.sa_socklen); assert_int_equal(rc, 0); for (i = 0; i < 10; i++) { char send_buf[64] = {0}; char recv_buf[64] = {0}; snprintf(send_buf, sizeof(send_buf), "packet.%d", i); ret = send(s, send_buf, sizeof(send_buf), 0); assert_int_not_equal(ret, -1); ret = recv(s, recv_buf, sizeof(recv_buf), 0); assert_int_not_equal(ret, -1); assert_memory_equal(send_buf, recv_buf, sizeof(send_buf)); } close(s); return NULL; } static void test_send_recv_ipv4(void **state) { pthread_attr_t pthread_custom_attr; pthread_t threads[NUM_THREADS]; int i; (void) state; /* unused */ pthread_attr_init(&pthread_custom_attr); for (i = 0; i < NUM_THREADS; i++) { pthread_create(&threads[i], &pthread_custom_attr, thread_worker, NULL); } for (i = 0; i < NUM_THREADS; i++) { pthread_join(threads[i], NULL); } pthread_attr_destroy(&pthread_custom_attr); } int main(void) { int rc; const struct CMUnitTest send_tests[] = { cmocka_unit_test_setup_teardown(test_send_recv_ipv4, setup_echo_srv_udp_ipv4, teardown), }; rc = cmocka_run_group_tests(send_tests, NULL, NULL); return rc; } socket_wrapper-1.2.3/tests/thread_deadlock.c000644 001750 000144 00000004331 13372600005 021125 0ustar00asnusers000000 000000 /* * Copyright (C) 2017 Andreas Schneider * * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 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. * * 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. * * 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. * */ #include "config.h" #include #include #include #ifdef HAVE_CONSTRUCTOR_ATTRIBUTE #define CONSTRUCTOR_ATTRIBUTE __attribute__ ((constructor)) #else #define CONSTRUCTOR_ATTRIBUTE #endif /* HAVE_CONSTRUCTOR_ATTRIBUTE */ void thread_deadlock_constructor(void) CONSTRUCTOR_ATTRIBUTE; static void thread_deadlock_prepare(void) { pthread_kill(pthread_self(), SIGUSR1); return; } static void thread_deadlock_parent(void) { return; } static void thread_deadlock_child(void) { return; } void thread_deadlock_constructor(void) { pthread_atfork(&thread_deadlock_prepare, &thread_deadlock_parent, &thread_deadlock_child); } socket_wrapper-1.2.3/tests/helgrind.supp000644 001750 000144 00000000477 13374561011 020405 0ustar00asnusers000000 000000 # The swrap_bind_symbol_lib* macros have a thread race condition on purpose! # # As an optimization we do not lock the access. However if the obj is not # bound, we lock it with a mutex and reread it again. And binding the symbol is # protected. { SWRAP_SYMBOL_ACCESS Helgrind:Race fun:libc_* fun:swrap_* } socket_wrapper-1.2.3/tests/test_echo_tcp_sendmsg_recvmsg.c000644 001750 000144 00000013006 13374561011 024125 0ustar00asnusers000000 000000 #include #include #include #include #include "config.h" #include "torture.h" #include #include #include #include #include #include #include #include static int setup_echo_srv_tcp_ipv4(void **state) { torture_setup_echo_srv_tcp_ipv4(state); return 0; } #ifdef HAVE_IPV6 static int setup_echo_srv_tcp_ipv6(void **state) { torture_setup_echo_srv_tcp_ipv6(state); return 0; } #endif static int teardown(void **state) { torture_teardown_echo_srv(state); return 0; } static void test_sendmsg_recvmsg_ipv4(void **state) { struct torture_address addr = { .sa_socklen = sizeof(struct sockaddr_storage), }; char send_buf[64] = {0}; char recv_buf[64] = {0}; ssize_t ret; int rc; int i; int s; (void) state; /* unused */ s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); assert_int_not_equal(s, -1); addr.sa.in.sin_family = AF_INET; addr.sa.in.sin_port = htons(torture_server_port()); rc = inet_pton(AF_INET, torture_server_address(AF_INET), &addr.sa.in.sin_addr); assert_int_equal(rc, 1); rc = connect(s, &addr.sa.s, addr.sa_socklen); assert_return_code(rc, errno); for (i = 0; i < 10; i++) { struct torture_address reply_addr = { .sa_socklen = sizeof(struct sockaddr_storage), }; struct msghdr s_msg = { .msg_namelen = 0, }; struct msghdr r_msg = { .msg_namelen = 0, }; struct iovec s_iov; struct iovec r_iov; snprintf(send_buf, sizeof(send_buf), "packet.%d", i); /* This should be ignored */ rc = inet_pton(AF_INET, "127.0.0.1", &addr.sa.in.sin_addr); assert_int_equal(rc, 1); s_msg.msg_name = &addr.sa.s; s_msg.msg_namelen = addr.sa_socklen; s_iov.iov_base = send_buf; s_iov.iov_len = sizeof(send_buf); s_msg.msg_iov = &s_iov; s_msg.msg_iovlen = 1; ret = sendmsg(s, &s_msg, 0); assert_int_not_equal(ret, -1); r_msg.msg_name = &reply_addr.sa.s; r_msg.msg_namelen = reply_addr.sa_socklen; r_iov.iov_base = recv_buf; r_iov.iov_len = sizeof(recv_buf); r_msg.msg_iov = &r_iov; r_msg.msg_iovlen = 1; ret = recvmsg(s, &r_msg, 0); assert_int_not_equal(ret, -1); assert_int_equal(r_msg.msg_namelen, 0); assert_memory_equal(send_buf, recv_buf, sizeof(send_buf)); } close(s); } #ifdef HAVE_IPV6 static void test_sendmsg_recvmsg_ipv6(void **state) { struct torture_address addr = { .sa_socklen = sizeof(struct sockaddr_storage), }; char send_buf[64] = {0}; char recv_buf[64] = {0}; ssize_t ret; int rc; int i; int s; (void) state; /* unused */ s = socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP); assert_int_not_equal(s, -1); addr.sa.in.sin_family = AF_INET6; addr.sa.in.sin_port = htons(torture_server_port()); rc = inet_pton(AF_INET6, torture_server_address(AF_INET6), &addr.sa.in6.sin6_addr); assert_int_equal(rc, 1); rc = connect(s, &addr.sa.s, addr.sa_socklen); assert_return_code(rc, errno); for (i = 0; i < 10; i++) { struct torture_address reply_addr = { .sa_socklen = sizeof(struct sockaddr_in), }; struct msghdr s_msg = { .msg_namelen = 0, }; struct msghdr r_msg = { .msg_namelen = 0, }; struct iovec s_iov; struct iovec r_iov; snprintf(send_buf, sizeof(send_buf), "packet.%d", i); s_iov.iov_base = send_buf; s_iov.iov_len = sizeof(send_buf); s_msg.msg_iov = &s_iov; s_msg.msg_iovlen = 1; ret = sendmsg(s, &s_msg, 0); assert_int_not_equal(ret, -1); r_msg.msg_name = &reply_addr.sa.s; r_msg.msg_namelen = reply_addr.sa_socklen; r_iov.iov_base = recv_buf; r_iov.iov_len = sizeof(recv_buf); r_msg.msg_iov = &r_iov; r_msg.msg_iovlen = 1; ret = recvmsg(s, &r_msg, 0); assert_int_not_equal(ret, -1); assert_int_equal(r_msg.msg_namelen, 0); assert_memory_equal(send_buf, recv_buf, sizeof(send_buf)); } close(s); } #endif static void test_sendmsg_recvmsg_ipv4_null(void **state) { struct torture_address send_addr = { .sa_socklen = sizeof(struct sockaddr_storage), }; struct msghdr s_msg = { .msg_namelen = 0, }; struct msghdr r_msg = { .msg_namelen = 0, }; struct iovec iov; char payload[] = "PACKET"; ssize_t ret; int rc; int s; (void)state; /* unused */ s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); assert_int_not_equal(s, -1); send_addr.sa.in.sin_family = AF_INET; send_addr.sa.in.sin_port = htons(torture_server_port()); rc = inet_pton(AF_INET, torture_server_address(AF_INET), &send_addr.sa.in.sin_addr); assert_int_equal(rc, 1); rc = connect(s, &send_addr.sa.s, send_addr.sa_socklen); assert_return_code(rc, errno); /* msg_name = NULL */ iov.iov_base = (void *)payload; iov.iov_len = sizeof(payload); s_msg.msg_iov = &iov; s_msg.msg_iovlen = 1; ret = sendmsg(s, &s_msg, 0); assert_int_not_equal(ret, -1); /* msg_name = NULL */ memset(payload, 0, sizeof(payload)); r_msg.msg_iov = &iov; r_msg.msg_iovlen = 1; ret = recvmsg(s, &r_msg, 0); assert_int_not_equal(ret, -1); assert_int_equal(r_msg.msg_namelen, 0); assert_null(r_msg.msg_name); close(s); } int main(void) { int rc; const struct CMUnitTest sendmsg_tests[] = { cmocka_unit_test_setup_teardown(test_sendmsg_recvmsg_ipv4, setup_echo_srv_tcp_ipv4, teardown), cmocka_unit_test_setup_teardown(test_sendmsg_recvmsg_ipv4_null, setup_echo_srv_tcp_ipv4, teardown), #ifdef HAVE_IPV6 cmocka_unit_test_setup_teardown(test_sendmsg_recvmsg_ipv6, setup_echo_srv_tcp_ipv6, teardown), #endif }; rc = cmocka_run_group_tests(sendmsg_tests, NULL, NULL); return rc; } socket_wrapper-1.2.3/tests/test_fork_thread_deadlock.c000644 001750 000144 00000004215 13374561011 023213 0ustar00asnusers000000 000000 #include "config.h" #include #include #include #include #include #include #include #include #include #include #include #include #include /* * This reproduces and issue if we get a signal after the pthread_atfork() * prepare function of socket wrapper has been called. * * The order how pthread_atfork() handlers are set up is: * -> application * -> preloaded libraries * -> libraries * * We have a library called thread_deadlock. * * This library registers a thread_deadlock_prepare() function via * pthread_atfork(). * * So pthread_atfork() registers the prepare function in the follow order: * -> swrap_thread_prepare() * -> thread_deadlock_prepare() * * In this test we fork and the swrap_thread_prepare() locks the mutex for * symbol binding. * Then thread_deadlock_prepare() is called which sends a signal to the parent * process of this test. The signal triggers the signal handler below. * * When we call write() in the signal handler, we will try to bind the libc symbol * and want to lock the symbol binding mutex. As it is already locked we run into * a deadlock. */ static void test_swrap_signal_handler(int signum) { fprintf(stderr, "PID: %u, SIGNUM: %d\n", (unsigned int)getpid(), signum); write(1, "DEADLOCK?\n", 10); } static void test_swrap_fork_pthread(void **state) { pid_t pid; struct sigaction act = { .sa_handler = test_swrap_signal_handler, .sa_flags = 0, }; (void)state; /* unused */ sigemptyset(&act.sa_mask); sigaction(SIGUSR1, &act, NULL); pid = fork(); assert_return_code(pid, errno); /* child */ if (pid == 0) { exit(0); } /* parent */ if (pid > 0) { pid_t child_pid; int wstatus = -1; child_pid = waitpid(-1, &wstatus, 0); assert_return_code(child_pid, errno); assert_true(WIFEXITED(wstatus)); assert_int_equal(WEXITSTATUS(wstatus), 0); } } int main(void) { int rc; const struct CMUnitTest swrap_tests[] = { cmocka_unit_test(test_swrap_fork_pthread), }; rc = cmocka_run_group_tests(swrap_tests, NULL, NULL); return rc; } socket_wrapper-1.2.3/tests/test_thread_echo_tcp_write_read.c000644 001750 000144 00000004316 13374561011 024417 0ustar00asnusers000000 000000 #include #include #include #include #include #include "config.h" #include "torture.h" #include #include #include #include #include #include #include #include #define NUM_THREADS 10 static int setup_echo_srv_tcp_ipv4(void **state) { torture_setup_echo_srv_tcp_ipv4(state); return 0; } static int teardown(void **state) { torture_teardown_echo_srv(state); return 0; } static void *thread_worker(void *arg) { struct torture_address addr = { .sa_socklen = sizeof(struct sockaddr_in), }; ssize_t ret; int rc; int i; int s; (void) arg; /* unused */ s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); assert_int_not_equal(s, -1); addr.sa.in.sin_family = AF_INET; addr.sa.in.sin_port = htons(torture_server_port()); rc = inet_pton(addr.sa.in.sin_family, torture_server_address(AF_INET), &addr.sa.in.sin_addr); assert_int_equal(rc, 1); rc = connect(s, &addr.sa.s, addr.sa_socklen); assert_return_code(rc, errno); for (i = 0; i < 10; i++) { char send_buf[64] = {0}; char recv_buf[64] = {0}; snprintf(send_buf, sizeof(send_buf), "packet.%d", i); ret = write(s, send_buf, sizeof(send_buf)); assert_return_code(ret, errno); ret = read(s, recv_buf, sizeof(recv_buf)); assert_int_not_equal(ret, -1); assert_memory_equal(send_buf, recv_buf, sizeof(send_buf)); } close(s); return NULL; } static void test_write_read_ipv4(void **state) { pthread_attr_t pthread_custom_attr; pthread_t threads[NUM_THREADS]; int i; (void) state; /* unused */ pthread_attr_init(&pthread_custom_attr); for (i = 0; i < NUM_THREADS; i++) { pthread_create(&threads[i], &pthread_custom_attr, thread_worker, NULL); } for (i = 0; i < NUM_THREADS; i++) { pthread_join(threads[i], NULL); } pthread_attr_destroy(&pthread_custom_attr); } int main(void) { int rc; const struct CMUnitTest tcp_write_tests[] = { cmocka_unit_test_setup_teardown(test_write_read_ipv4, setup_echo_srv_tcp_ipv4, teardown), }; rc = cmocka_run_group_tests(tcp_write_tests, NULL, NULL); return rc; } socket_wrapper-1.2.3/tests/valgrind.supp000644 001750 000144 00000000435 13374561011 020411 0ustar00asnusers000000 000000 ### GLIBC { glibc_dlopen_alloc Memcheck:Leak fun:calloc fun:_dlerror_run fun:dlopen } { glibc_dlclose_alloc Memcheck:Leak fun:calloc fun:_dlerror_run fun:dlclose } { glibc_dlsym_alloc Memcheck:Leak fun:calloc fun:_dlerror_run fun:dlsym } socket_wrapper-1.2.3/tests/test_close_failure.c000644 001750 000144 00000001437 13372600005 021707 0ustar00asnusers000000 000000 #include "torture.h" #include #include #include #include #include static int setup(void **state) { torture_setup_socket_dir(state); return 0; } static int teardown(void **state) { torture_teardown_socket_dir(state); return 0; } static void test_close_failure(void **state) { int s; (void) state; /* unused */ s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); assert_int_not_equal(s, -1); /* Do not close the socket here so that destructor * handles it and no hang should be observed.*/ } int main(void) { int rc; const struct CMUnitTest close_failure_tests[] = { cmocka_unit_test_setup_teardown(test_close_failure, setup, teardown), }; rc = cmocka_run_group_tests(close_failure_tests, NULL, NULL); return rc; } socket_wrapper-1.2.3/tests/test_echo_tcp_bind.c000644 001750 000144 00000027421 13374561011 021661 0ustar00asnusers000000 000000 #include #include #include #include #include "config.h" #include "torture.h" #include #include #include #include #include #include #include #include #include #ifdef HAVE_RPC_RPC_H #include #endif static int setup_echo_srv_tcp_ipv4(void **state) { torture_setup_echo_srv_tcp_ipv4(state); return 0; } #ifdef HAVE_IPV6 static int setup_echo_srv_tcp_ipv6(void **state) { torture_setup_echo_srv_tcp_ipv6(state); return 0; } #endif static int teardown(void **state) { torture_teardown_echo_srv(state); return 0; } static void test_bind_ipv4(void **state) { struct torture_address addr = { .sa_socklen = sizeof(struct sockaddr_storage), }; struct torture_address addr_in = { .sa_socklen = sizeof(struct sockaddr_in), }; struct torture_address addr_un = { .sa_socklen = sizeof(struct sockaddr_un), }; int rc; int s; (void) state; /* unused */ s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); assert_return_code(s, errno); /* * Test various cases with family AF_UNSPEC */ /* UNSPEC, len == 1: EINVAL */ addr_in.sa.in = (struct sockaddr_in) { .sin_family = AF_UNSPEC, }; rc = bind(s, &addr.sa.s, 1); assert_int_equal(rc, -1); assert_int_equal(errno, EINVAL); /* UNSPEC: EAFNOSUPPORT */ addr_in.sa.in = (struct sockaddr_in) { .sin_family = AF_UNSPEC, }; rc = inet_pton(AF_INET, "127.0.0.20", &addr_in.sa.in.sin_addr); assert_int_equal(rc, 1); rc = bind(s, &addr_in.sa.s, addr_in.sa_socklen); assert_int_equal(rc, -1); /* FreeBSD uses EADDRNOTAVAIL here ... */ assert_true(errno == EAFNOSUPPORT || errno == EADDRNOTAVAIL); /* special case: AF_UNSPEC with INADDR_ANY: success mapped to AF_INET */ addr_in.sa.in = (struct sockaddr_in) { .sin_family = AF_UNSPEC, }; assert_int_equal(addr_in.sa.in.sin_addr.s_addr, htonl(INADDR_ANY)); rc = bind(s, &addr_in.sa.s, addr_in.sa_socklen); assert_return_code(rc, errno); close(s); s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); assert_return_code(s, errno); /* * Test various cases with family AF_UNIX * all fail with EAFNOSUPPORT */ addr.sa.ss = (struct sockaddr_storage) { .ss_family = AF_UNIX, }; rc = bind(s, &addr.sa.s, addr.sa_socklen); assert_int_equal(rc, -1); assert_int_equal(errno, EAFNOSUPPORT); addr_in.sa.in = (struct sockaddr_in) { .sin_family = AF_UNIX, }; rc = bind(s, &addr_in.sa.s, addr_in.sa_socklen); assert_int_equal(rc, -1); assert_int_equal(errno, EAFNOSUPPORT); addr_un.sa.un = (struct sockaddr_un) { .sun_family = AF_UNIX, }; rc = bind(s, &addr_un.sa.s, addr_un.sa_socklen); assert_int_equal(rc, -1); assert_int_equal(errno, EAFNOSUPPORT); #ifdef HAVE_IPV6 /* * Test with family AF_INET6 - fail */ addr_in.sa.in = (struct sockaddr_in) { .sin_family = AF_INET6, }; rc = bind(s, &addr_in.sa.s, addr_in.sa_socklen); assert_int_equal(rc, -1); assert_int_equal(errno, EAFNOSUPPORT); #endif /* * Finally, success binding a new IPv4 address. */ addr_in = (struct torture_address) { .sa_socklen = sizeof(struct sockaddr_in), .sa.in = (struct sockaddr_in) { .sin_family = AF_INET, }, }; rc = inet_pton(AF_INET, "127.0.0.20", &addr_in.sa.in.sin_addr); assert_int_equal(rc, 1); rc = bind(s, &addr_in.sa.s, addr_in.sa_socklen); assert_return_code(rc, errno); addr_in = (struct torture_address) { .sa_socklen = sizeof(struct sockaddr_in), .sa.in = (struct sockaddr_in) { .sin_family = AF_INET, .sin_port = htons(torture_server_port()), }, }; rc = inet_pton(AF_INET, torture_server_address(AF_INET), &addr_in.sa.in.sin_addr); assert_int_equal(rc, 1); rc = connect(s, &addr_in.sa.s, addr_in.sa_socklen); assert_return_code(rc, errno); close(s); } #if 0 /* TODO */ static void test_bind_ipv4_addr_in_use(void **state) { struct sockaddr_in sin, sin2; socklen_t slen = sizeof(struct sockaddr_in); int rc; int s, s2; (void) state; /* unused */ s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); assert_return_code(s, errno); /* * Try to bind to the same address as already bound by a * different process. */ /* Without specifying the port - success */ ZERO_STRUCT(sin); sin.sin_family = AF_INET; rc = inet_pton(AF_INET, torture_server_address(AF_INET), &sin.sin_addr); assert_int_equal(rc, 1); rc = bind(s, (struct sockaddr *)&sin, slen); assert_return_code(rc, errno); close(s); s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); assert_return_code(s, errno); #if 0 /* specify the same port - fail with EADDRINUSE. */ /* Not supported by socket_wrapper yet. ==> TODO! */ ZERO_STRUCT(sin); sin.sin_family = AF_INET, sin.sin_port = htons(torture_server_port()); rc = inet_pton(AF_INET, torture_server_address(AF_INET), &sin.sin_addr); assert_int_equal(rc, 1); rc = bind(s, (struct sockaddr *)&sin, slen); assert_int_equal(rc, -1); assert_int_equal(errno, EADDRINUSE); #endif /* * Try double binding when the firs bind is with port == 0 */ ZERO_STRUCT(sin); sin.sin_family = AF_INET; rc = inet_pton(AF_INET, "127.0.0.20", &sin.sin_addr); assert_int_equal(rc, 1); rc = bind(s, (struct sockaddr *)&sin, slen); assert_return_code(rc, errno); /* * Open a second socket locally and try to bind to the same address. */ /* Succeeds with port == 0 */ s2 = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); assert_return_code(s, errno); ZERO_STRUCT(sin2); sin2.sin_family = AF_INET; rc = inet_pton(AF_INET, "127.0.0.20", &sin2.sin_addr); assert_int_equal(rc, 1); rc = bind(s2, (struct sockaddr *)&sin2, slen); assert_return_code(rc, errno); close(s2); /* second bind with port != 0 - succeeds */ s2 = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); assert_return_code(s, errno); ZERO_STRUCT(sin2); sin2.sin_family = AF_INET; sin2.sin_port = htons(12345); rc = inet_pton(AF_INET, "127.0.0.20", &sin2.sin_addr); assert_int_equal(rc, 1); rc = bind(s2, (struct sockaddr *)&sin2, slen); assert_return_code(rc, errno); close(s2); close(s); /* * Try double binding when the first bind is with port != 0 */ s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); assert_return_code(s, errno); ZERO_STRUCT(sin); sin.sin_family = AF_INET; sin.sin_port = htons(12345); rc = inet_pton(AF_INET, "127.0.0.20", &sin.sin_addr); assert_int_equal(rc, 1); rc = bind(s, (struct sockaddr *)&sin, slen); assert_return_code(rc, errno); /* * Open a second socket locally and try to bind to the same address. */ /* Succeeds with port == 0 */ s2 = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); assert_return_code(s, errno); ZERO_STRUCT(sin2); sin2.sin_family = AF_INET; rc = inet_pton(AF_INET, "127.0.0.20", &sin2.sin_addr); assert_int_equal(rc, 1); rc = bind(s2, (struct sockaddr *)&sin2, slen); assert_return_code(rc, errno); close(s2); /* with same port as above - fail with EADDRINUSE */ s2 = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); assert_return_code(s, errno); ZERO_STRUCT(sin2); sin2.sin_family = AF_INET; sin2.sin_port = htons(12345); rc = inet_pton(AF_INET, "127.0.0.20", &sin2.sin_addr); assert_int_equal(rc, 1); rc = bind(s2, (struct sockaddr *)&sin2, slen); assert_int_equal(rc, -1); assert_int_equal(errno, EADDRINUSE); close(s); } #endif #ifdef HAVE_BINDRESVPORT static void test_bindresvport_ipv4(void **state) { struct torture_address addr = { .sa_socklen = sizeof(struct sockaddr_storage), }; int rc; int s; (void) state; /* unused */ s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); assert_return_code(s, errno); addr.sa.in.sin_family = AF_INET; rc = inet_pton(AF_INET, "127.0.0.20", &addr.sa.in.sin_addr); assert_int_equal(rc, 1); rc = bindresvport(s, &addr.sa.in); assert_return_code(rc, errno); addr = (struct torture_address) { .sa_socklen = sizeof(struct sockaddr_storage), .sa.in = (struct sockaddr_in) { .sin_family = AF_INET, .sin_port = htons(torture_server_port()), }, }; rc = inet_pton(AF_INET, torture_server_address(AF_INET), &addr.sa.in.sin_addr); assert_int_equal(rc, 1); rc = connect(s, &addr.sa.s, addr.sa_socklen); assert_return_code(rc, errno); close(s); } static void test_bindresvport_ipv4_null(void **state) { struct torture_address addr = { .sa_socklen = sizeof(struct sockaddr_in), }; int rc; int s; (void) state; /* unused */ s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); assert_return_code(s, errno); rc = bindresvport(s, NULL); assert_return_code(rc, errno); addr.sa.in.sin_family = AF_INET; addr.sa.in.sin_port = htons(torture_server_port()); rc = inet_pton(AF_INET, torture_server_address(AF_INET), &addr.sa.in.sin_addr); assert_int_equal(rc, 1); rc = connect(s, &addr.sa.s, addr.sa_socklen); assert_return_code(rc, errno); close(s); } #endif /* HAVE_BINDRESVPORT */ #ifdef HAVE_IPV6 static void test_bind_on_ipv6_sock(void **state) { struct torture_address addr_in = { .sa_socklen = sizeof(struct sockaddr_in), }; struct torture_address addr_un = { .sa_socklen = sizeof(struct sockaddr_un), }; int rc; int s; (void) state; /* unused */ s = socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP); assert_return_code(s, errno); addr_un.sa.un.sun_family = AF_UNIX; rc = bind(s, &addr_un.sa.s, addr_un.sa_socklen); assert_int_equal(rc, -1); /* FreeBSD uses EINVAL here... */ assert_true(errno == EAFNOSUPPORT || errno == EINVAL); addr_in.sa.in.sin_family = AF_INET; rc = bind(s, &addr_in.sa.s, addr_in.sa_socklen); assert_int_equal(rc, -1); assert_int_equal(errno, EINVAL); addr_in.sa.in = (struct sockaddr_in) { .sin_family = AF_INET, }; rc = inet_pton(AF_INET, "127.0.0.20", &addr_in.sa.in.sin_addr); assert_int_equal(rc, 1); rc = bind(s, &addr_in.sa.s, addr_in.sa_socklen); assert_int_equal(rc, -1); assert_int_equal(errno, EINVAL); addr_in = (struct torture_address) { .sa_socklen = sizeof(struct sockaddr_in6), .sa.in = (struct sockaddr_in) { .sin_family = AF_INET, }, }; rc = bind(s, &addr_in.sa.s, addr_in.sa_socklen); assert_int_equal(rc, -1); assert_int_equal(errno, EAFNOSUPPORT); close(s); } #ifdef HAVE_BINDRESVPORT static void test_bindresvport_on_ipv6_sock(void **state) { struct sockaddr_in sin; int rc; int s; (void) state; /* unused */ s = socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP); assert_return_code(s, errno); ZERO_STRUCT(sin); sin.sin_family = AF_INET; rc = inet_pton(AF_INET, "127.0.0.20", &sin.sin_addr); assert_int_equal(rc, 1); rc = bindresvport(s, &sin); assert_int_equal(rc, -1); assert_int_equal(errno, EINVAL); close(s); } static void test_bindresvport_on_ipv6_sock_null(void **state) { int rc; int s; (void) state; /* unused */ s = socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP); assert_return_code(s, errno); rc = bindresvport(s, NULL); assert_return_code(rc, errno); close(s); } #endif /* HAVE_BINDRESVPORT */ #endif /* HAVE_IPV6 */ int main(void) { int rc; const struct CMUnitTest tcp_bind_tests[] = { cmocka_unit_test_setup_teardown(test_bind_ipv4, setup_echo_srv_tcp_ipv4, teardown), #if 0 /* TODO */ cmocka_unit_test_setup_teardown(test_bind_ipv4_addr_in_use, setup_echo_srv_tcp_ipv4, teardown), #endif #ifdef HAVE_BINDRESVPORT cmocka_unit_test_setup_teardown(test_bindresvport_ipv4, setup_echo_srv_tcp_ipv4, teardown), cmocka_unit_test_setup_teardown(test_bindresvport_ipv4_null, setup_echo_srv_tcp_ipv4, teardown), #endif /* HAVE_BINDRESVPORT */ #ifdef HAVE_IPV6 cmocka_unit_test_setup_teardown(test_bind_on_ipv6_sock, setup_echo_srv_tcp_ipv6, teardown), #ifdef HAVE_BINDRESVPORT cmocka_unit_test_setup_teardown(test_bindresvport_on_ipv6_sock, setup_echo_srv_tcp_ipv6, teardown), cmocka_unit_test_setup_teardown(test_bindresvport_on_ipv6_sock_null, setup_echo_srv_tcp_ipv6, teardown), #endif /* HAVE_BINDRESVPORT */ #endif /* HAVE_IPV6 */ }; rc = cmocka_run_group_tests(tcp_bind_tests, NULL, NULL); return rc; } socket_wrapper-1.2.3/tests/test_echo_udp_sendmsg_recvmsg.c000644 001750 000144 00000021135 13374561011 024131 0ustar00asnusers000000 000000 #include #include #include #include #include "config.h" #include "torture.h" #include #include #include #include #include #include #include #include static int setup_echo_srv_udp_ipv4(void **state) { torture_setup_echo_srv_udp_ipv4(state); return 0; } #ifdef HAVE_IPV6 static int setup_echo_srv_udp_ipv6(void **state) { torture_setup_echo_srv_udp_ipv6(state); return 0; } #endif static int teardown(void **state) { torture_teardown_echo_srv(state); return 0; } static void test_sendmsg_recvmsg_ipv4(void **state) { struct torture_address addr = { .sa_socklen = sizeof(struct sockaddr_in), }; char send_buf[64] = {0}; char recv_buf[64] = {0}; ssize_t ret; int rc; int i; int s; (void) state; /* unused */ s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); assert_int_not_equal(s, -1); addr.sa.in.sin_family = AF_INET; addr.sa.in.sin_port = htons(torture_server_port()); rc = inet_pton(AF_INET, torture_server_address(AF_INET), &addr.sa.in.sin_addr); assert_int_equal(rc, 1); for (i = 0; i < 10; i++) { char ip[INET_ADDRSTRLEN] = {0}; const char *a; struct torture_address srv_in = { .sa_socklen = sizeof(struct sockaddr_in), }; struct msghdr s_msg; struct msghdr r_msg; struct iovec s_iov; struct iovec r_iov; snprintf(send_buf, sizeof(send_buf), "packet.%d", i); ZERO_STRUCT(s_msg); s_msg.msg_name = &addr.sa.s; s_msg.msg_namelen = addr.sa_socklen; s_iov.iov_base = send_buf; s_iov.iov_len = sizeof(send_buf); s_msg.msg_iov = &s_iov; s_msg.msg_iovlen = 1; ret = sendmsg(s, &s_msg, 0); assert_int_not_equal(ret, -1); ZERO_STRUCT(r_msg); r_msg.msg_name = &srv_in.sa.s; r_msg.msg_namelen = srv_in.sa_socklen; r_iov.iov_base = recv_buf; r_iov.iov_len = sizeof(recv_buf); r_msg.msg_iov = &r_iov; r_msg.msg_iovlen = 1; ret = recvmsg(s, &r_msg, 0); assert_int_not_equal(ret, -1); assert_int_equal(r_msg.msg_namelen, sizeof(struct sockaddr_in)); a = inet_ntop(AF_INET, &srv_in.sa.in.sin_addr, ip, sizeof(ip)); assert_non_null(a); assert_string_equal(a, torture_server_address(AF_INET)); assert_memory_equal(send_buf, recv_buf, sizeof(send_buf)); } close(s); } #ifdef HAVE_IPV6 static void test_sendmsg_recvmsg_ipv6(void **state) { struct torture_address addr = { .sa_socklen = sizeof(struct sockaddr_in6), }; char send_buf[64] = {0}; char recv_buf[64] = {0}; ssize_t ret; int rc; int i; int s; (void) state; /* unused */ s = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP); assert_int_not_equal(s, -1); addr.sa.in6.sin6_family = AF_INET6; addr.sa.in6.sin6_port = htons(torture_server_port()); rc = inet_pton(AF_INET6, torture_server_address(AF_INET6), &addr.sa.in6.sin6_addr); assert_int_equal(rc, 1); for (i = 0; i < 10; i++) { char ip[INET6_ADDRSTRLEN] = {0}; const char *a; struct torture_address srv_in6 = { .sa_socklen = sizeof(struct sockaddr_in6), }; struct msghdr s_msg; struct msghdr r_msg; struct iovec s_iov; struct iovec r_iov; snprintf(send_buf, sizeof(send_buf), "packet.%d", i); ZERO_STRUCT(s_msg); s_msg.msg_name = &addr.sa.s; s_msg.msg_namelen = addr.sa_socklen; s_iov.iov_base = send_buf; s_iov.iov_len = sizeof(send_buf); s_msg.msg_iov = &s_iov; s_msg.msg_iovlen = 1; ret = sendmsg(s, &s_msg, 0); assert_int_not_equal(ret, -1); ZERO_STRUCT(r_msg); r_msg.msg_name = &srv_in6.sa.s; r_msg.msg_namelen = srv_in6.sa_socklen; r_iov.iov_base = recv_buf; r_iov.iov_len = sizeof(recv_buf); r_msg.msg_iov = &r_iov; r_msg.msg_iovlen = 1; ret = recvmsg(s, &r_msg, 0); assert_int_not_equal(ret, -1); assert_int_equal(r_msg.msg_namelen, sizeof(struct sockaddr_in6)); a = inet_ntop(AF_INET6, &srv_in6.sa.in6.sin6_addr, ip, sizeof(ip)); assert_non_null(a); assert_string_equal(a, torture_server_address(AF_INET6)); assert_memory_equal(send_buf, recv_buf, sizeof(send_buf)); } close(s); } #endif static void test_sendmsg_recvmsg_ipv4_connected(void **state) { struct torture_address send_addr = { .sa_socklen = sizeof(struct sockaddr_storage), }; struct torture_address r_addr = { .sa_socklen = sizeof(struct sockaddr_storage), }; struct msghdr s_msg = { .msg_namelen = 0, }; struct msghdr r_msg = { .msg_namelen = 0, }; struct iovec iov; char ip[INET_ADDRSTRLEN] = {0}; char payload[] = "PACKET"; const char *a; ssize_t ret; int rc; int s; (void)state; /* unused */ s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); assert_int_not_equal(s, -1); send_addr.sa.in.sin_family = AF_INET; send_addr.sa.in.sin_port = htons(torture_server_port()); rc = inet_pton(AF_INET, torture_server_address(AF_INET), &send_addr.sa.in.sin_addr); assert_int_equal(rc, 1); rc = connect(s, &send_addr.sa.s, send_addr.sa_socklen); assert_return_code(rc, errno); iov.iov_base = (void *)payload; iov.iov_len = sizeof(payload); /* msg_name is NULL */ s_msg.msg_iov = &iov; s_msg.msg_iovlen = 1; ret = sendmsg(s, &s_msg, 0); assert_int_not_equal(ret, -1); r_msg.msg_name = &r_addr.sa.ss; r_msg.msg_namelen = r_addr.sa_socklen; memset(payload, 0, sizeof(payload)); r_msg.msg_iov = &iov; r_msg.msg_iovlen = 1; ret = recvmsg(s, &r_msg, 0); assert_int_not_equal(ret, -1); assert_int_equal(r_msg.msg_namelen, sizeof(struct sockaddr_in)); a = inet_ntop(AF_INET, &r_addr.sa.in.sin_addr, ip, sizeof(ip)); assert_non_null(a); assert_string_equal(a, torture_server_address(AF_INET)); close(s); } static void test_sendmsg_recvmsg_ipv4_connected_null(void **state) { struct torture_address send_addr = { .sa_socklen = sizeof(struct sockaddr_storage), }; struct msghdr s_msg = { .msg_namelen = 0, }; struct msghdr r_msg = { .msg_namelen = 0, }; struct iovec iov; char payload[] = "PACKET"; ssize_t ret; int rc; int s; (void)state; /* unused */ s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); assert_int_not_equal(s, -1); send_addr.sa.in.sin_family = AF_INET; send_addr.sa.in.sin_port = htons(torture_server_port()); rc = inet_pton(AF_INET, torture_server_address(AF_INET), &send_addr.sa.in.sin_addr); assert_int_equal(rc, 1); rc = connect(s, &send_addr.sa.s, send_addr.sa_socklen); assert_return_code(rc, errno); /* msg_name = NULL */ iov.iov_base = (void *)payload; iov.iov_len = sizeof(payload); s_msg.msg_iov = &iov; s_msg.msg_iovlen = 1; ret = sendmsg(s, &s_msg, 0); assert_int_not_equal(ret, -1); /* msg_name = NULL */ memset(payload, 0, sizeof(payload)); r_msg.msg_iov = &iov; r_msg.msg_iovlen = 1; ret = recvmsg(s, &r_msg, 0); assert_int_not_equal(ret, -1); assert_int_equal(r_msg.msg_namelen, 0); assert_null(r_msg.msg_name); close(s); } static void test_sendmsg_recvmsg_ipv4_connected_namelen(void **state) { struct torture_address send_addr = { .sa_socklen = sizeof(struct sockaddr_storage), }; struct msghdr s_msg = { .msg_namelen = 0, }; struct msghdr r_msg = { .msg_namelen = sizeof(struct sockaddr_storage), }; struct iovec iov; char payload[] = "PACKET"; ssize_t ret; int rc; int s; (void)state; /* unused */ s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); assert_int_not_equal(s, -1); send_addr.sa.in.sin_family = AF_INET; send_addr.sa.in.sin_port = htons(torture_server_port()); rc = inet_pton(AF_INET, torture_server_address(AF_INET), &send_addr.sa.in.sin_addr); assert_int_equal(rc, 1); rc = connect(s, &send_addr.sa.s, send_addr.sa_socklen); assert_return_code(rc, errno); /* msg_name = NULL */ iov.iov_base = (void *)payload; iov.iov_len = sizeof(payload); s_msg.msg_iov = &iov; s_msg.msg_iovlen = 1; ret = sendmsg(s, &s_msg, 0); assert_int_not_equal(ret, -1); /* msg_name = NULL */ memset(payload, 0, sizeof(payload)); r_msg.msg_iov = &iov; r_msg.msg_iovlen = 1; ret = recvmsg(s, &r_msg, 0); assert_int_not_equal(ret, -1); close(s); } int main(void) { int rc; const struct CMUnitTest sendmsg_tests[] = { cmocka_unit_test_setup_teardown(test_sendmsg_recvmsg_ipv4, setup_echo_srv_udp_ipv4, teardown), #ifdef HAVE_IPV6 cmocka_unit_test_setup_teardown(test_sendmsg_recvmsg_ipv6, setup_echo_srv_udp_ipv6, teardown), #endif cmocka_unit_test_setup_teardown(test_sendmsg_recvmsg_ipv4_connected, setup_echo_srv_udp_ipv4, teardown), cmocka_unit_test_setup_teardown(test_sendmsg_recvmsg_ipv4_connected_null, setup_echo_srv_udp_ipv4, teardown), cmocka_unit_test_setup_teardown(test_sendmsg_recvmsg_ipv4_connected_namelen, setup_echo_srv_udp_ipv4, teardown), }; rc = cmocka_run_group_tests(sendmsg_tests, NULL, NULL); return rc; } socket_wrapper-1.2.3/tests/test_max_sockets.c000644 001750 000144 00000002714 13374561011 021417 0ustar00asnusers000000 000000 #include "torture.h" #include #include #include #include #include #define MAX_SOCKETS 4 static int setup(void **state) { int ret; char str[10]; torture_setup_socket_dir(state); ret = snprintf(str, 10, "%d", MAX_SOCKETS); if (ret < 0) { return ret; } ret = setenv("SOCKET_WRAPPER_MAX_SOCKETS", str, 1); return ret; } static int teardown(void **state) { torture_teardown_socket_dir(state); return 0; } static int _socket(int *_s) { int s; s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (s < 0) { return -1; } *_s = s; return 0; } static void test_max_sockets(void **state) { int rc; int s[MAX_SOCKETS+1] = { 0 }; int i; (void) state; /* unused */ for (i = 0; i < MAX_SOCKETS; i++) { rc = _socket(&s[i]); assert_return_code(rc, errno); } /* no free space for sockets left */ rc = _socket(&s[MAX_SOCKETS]); assert_int_equal(rc, -1); assert_int_equal(errno, ENFILE); /* closing a socket frees up space */ close(s[0]); rc = _socket(&s[0]); assert_return_code(rc, errno); /* but just one */ rc = _socket(&s[MAX_SOCKETS]); assert_int_equal(rc, -1); assert_int_equal(errno, ENFILE); for (i = 0; i < MAX_SOCKETS; i++) { close(s[i]); } } int main(void) { int rc; const struct CMUnitTest max_sockets_tests[] = { cmocka_unit_test_setup_teardown(test_max_sockets, setup, teardown), }; rc = cmocka_run_group_tests(max_sockets_tests, NULL, NULL); return rc; } socket_wrapper-1.2.3/tests/test_thread_echo_tcp_sendmsg_recvmsg.c000644 001750 000144 00000011312 13374561011 025452 0ustar00asnusers000000 000000 #include #include #include #include #include #include "config.h" #include "torture.h" #include #include #include #include #include #include #include #include #define NUM_THREADS 10 static int setup_echo_srv_tcp_ipv4(void **state) { torture_setup_echo_srv_tcp_ipv4(state); return 0; } static int teardown(void **state) { torture_teardown_echo_srv(state); return 0; } static void *thread_worker1(void *arg) { struct torture_address addr = { .sa_socklen = sizeof(struct sockaddr_storage), }; char send_buf[64] = {0}; char recv_buf[64] = {0}; ssize_t ret; int rc; int i; int s; (void) arg; /* unused */ s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); assert_int_not_equal(s, -1); addr.sa.in.sin_family = AF_INET; addr.sa.in.sin_port = htons(torture_server_port()); rc = inet_pton(AF_INET, torture_server_address(AF_INET), &addr.sa.in.sin_addr); assert_int_equal(rc, 1); rc = connect(s, &addr.sa.s, addr.sa_socklen); assert_return_code(rc, errno); for (i = 0; i < 10; i++) { struct torture_address reply_addr = { .sa_socklen = sizeof(struct sockaddr_storage), }; struct msghdr s_msg = { .msg_namelen = 0, }; struct msghdr r_msg = { .msg_namelen = 0, }; struct iovec s_iov; struct iovec r_iov; snprintf(send_buf, sizeof(send_buf), "packet.%d", i); /* This should be ignored */ rc = inet_pton(AF_INET, "127.0.0.1", &addr.sa.in.sin_addr); assert_int_equal(rc, 1); s_msg.msg_name = &addr.sa.s; s_msg.msg_namelen = addr.sa_socklen; s_iov.iov_base = send_buf; s_iov.iov_len = sizeof(send_buf); s_msg.msg_iov = &s_iov; s_msg.msg_iovlen = 1; ret = sendmsg(s, &s_msg, 0); assert_int_not_equal(ret, -1); r_msg.msg_name = &reply_addr.sa.s; r_msg.msg_namelen = reply_addr.sa_socklen; r_iov.iov_base = recv_buf; r_iov.iov_len = sizeof(recv_buf); r_msg.msg_iov = &r_iov; r_msg.msg_iovlen = 1; ret = recvmsg(s, &r_msg, 0); assert_int_not_equal(ret, -1); assert_int_equal(r_msg.msg_namelen, 0); assert_memory_equal(send_buf, recv_buf, sizeof(send_buf)); } close(s); return NULL; } static void *thread_worker2(void *arg) { struct torture_address send_addr = { .sa_socklen = sizeof(struct sockaddr_storage), }; struct msghdr s_msg = { .msg_namelen = 0, }; struct msghdr r_msg = { .msg_namelen = 0, }; struct iovec iov; char payload[] = "PACKET"; ssize_t ret; int rc; int s; (void)arg; /* unused */ s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); assert_int_not_equal(s, -1); send_addr.sa.in.sin_family = AF_INET; send_addr.sa.in.sin_port = htons(torture_server_port()); rc = inet_pton(AF_INET, torture_server_address(AF_INET), &send_addr.sa.in.sin_addr); assert_int_equal(rc, 1); rc = connect(s, &send_addr.sa.s, send_addr.sa_socklen); assert_return_code(rc, errno); /* msg_name = NULL */ iov.iov_base = (void *)payload; iov.iov_len = sizeof(payload); s_msg.msg_iov = &iov; s_msg.msg_iovlen = 1; ret = sendmsg(s, &s_msg, 0); assert_int_not_equal(ret, -1); /* msg_name = NULL */ memset(payload, 0, sizeof(payload)); r_msg.msg_iov = &iov; r_msg.msg_iovlen = 1; ret = recvmsg(s, &r_msg, 0); assert_int_not_equal(ret, -1); assert_int_equal(r_msg.msg_namelen, 0); assert_null(r_msg.msg_name); close(s); return NULL; } static void test_sendmsg_recvmsg_ipv4(void **state) { pthread_attr_t pthread_custom_attr; pthread_t threads[NUM_THREADS]; int i; (void) state; /* unused */ pthread_attr_init(&pthread_custom_attr); for (i = 0; i < NUM_THREADS; i++) { pthread_create(&threads[i], &pthread_custom_attr, thread_worker1, NULL); } for (i = 0; i < NUM_THREADS; i++) { pthread_join(threads[i], NULL); } pthread_attr_destroy(&pthread_custom_attr); } static void test_sendmsg_recvmsg_ipv4_null(void **state) { pthread_attr_t pthread_custom_attr; pthread_t threads[NUM_THREADS]; int i; (void) state; /* unused */ pthread_attr_init(&pthread_custom_attr); for (i = 0; i < NUM_THREADS; i++) { pthread_create(&threads[i], &pthread_custom_attr, thread_worker2, NULL); } for (i = 0; i < NUM_THREADS; i++) { pthread_join(threads[i], NULL); } pthread_attr_destroy(&pthread_custom_attr); } int main(void) { int rc; const struct CMUnitTest sendmsg_tests[] = { cmocka_unit_test_setup_teardown(test_sendmsg_recvmsg_ipv4, setup_echo_srv_tcp_ipv4, teardown), cmocka_unit_test_setup_teardown(test_sendmsg_recvmsg_ipv4_null, setup_echo_srv_tcp_ipv4, teardown), }; rc = cmocka_run_group_tests(sendmsg_tests, NULL, NULL); return rc; } socket_wrapper-1.2.3/tests/CMakeLists.txt000644 001750 000144 00000011603 13431516670 020436 0ustar00asnusers000000 000000 project(tests C) include_directories( ${CMAKE_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_SOURCE_DIR}/src ${CMOCKA_INCLUDE_DIR} ) set(TORTURE_LIBRARY torture) # RFC862 echo server add_executable(echo_srv echo_srv.c) target_compile_options(echo_srv PRIVATE ${DEFAULT_C_COMPILE_FLAGS} -D_GNU_SOURCE) target_link_libraries(echo_srv ${SWRAP_REQUIRED_LIBRARIES}) if (DEFINED DEFAULT_LINK_FLAGS) set_target_properties(echo_srv PROPERTIES LINK_FLAGS ${DEFAULT_LINK_FLAGS}) endif() add_library(${TORTURE_LIBRARY} STATIC torture.c) target_compile_options(${TORTURE_LIBRARY} PRIVATE ${DEFAULT_C_COMPILE_FLAGS} -D_GNU_SOURCE) target_link_libraries(${TORTURE_LIBRARY} ${CMOCKA_LIBRARY} ${SWRAP_REQUIRED_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT}) set(SWRAP_THREADED_TESTS test_thread_sockets test_thread_echo_tcp_connect test_thread_echo_tcp_write_read test_thread_echo_tcp_sendmsg_recvmsg test_thread_echo_udp_send_recv) set(SWRAP_TESTS test_ioctl test_tcp_listen test_tcp_dup2 test_fcntl test_echo_tcp_connect test_echo_tcp_bind test_echo_tcp_socket_options test_echo_tcp_sendmsg_recvmsg test_echo_tcp_write_read test_echo_tcp_writev_readv test_echo_tcp_get_peer_sock_name test_echo_udp_sendto_recvfrom test_echo_udp_send_recv test_echo_udp_sendmsg_recvmsg test_swrap_unit test_max_sockets test_close_failure test_tcp_socket_overwrite ${SWRAP_THREADED_TESTS}) if (HAVE_STRUCT_MSGHDR_MSG_CONTROL) set(SWRAP_TESTS ${SWRAP_TESTS} test_sendmsg_recvmsg_fd) endif (HAVE_STRUCT_MSGHDR_MSG_CONTROL) function(ADD_CMOCKA_TEST_ENVIRONMENT _TEST_NAME) if (CMAKE_BUILD_TYPE) string(TOLOWER "${CMAKE_BUILD_TYPE}" CMAKE_BUILD_TYPE_LOWER) if (CMAKE_BUILD_TYPE_LOWER STREQUAL "addresssanitizer") find_library(ASAN_LIBRARY NAMES asan) if (NOT ASAN_LIBRARY) foreach(version RANGE 10 1) if (NOT ASAN_LIBRARY) find_library(ASAN_LIBRARY libasan.so.${version}) endif() endforeach() endif() endif() endif() if (ASAN_LIBRARY) list(APPEND PRELOAD_LIBRARIES ${ASAN_LIBRARY}) endif() list(APPEND PRELOAD_LIBRARIES ${SOCKET_WRAPPER_LOCATION}) if (OSX) set(TORTURE_ENVIRONMENT "DYLD_FORCE_FLAT_NAMESPACE=1;DYLD_INSERT_LIBRARIES=${SOCKET_WRAPPER_LOCATION}") else () string(REPLACE ";" ":" _TMP_ENV "${PRELOAD_LIBRARIES}") set(TORTURE_ENVIRONMENT "LD_PRELOAD=${_TMP_ENV}") endif() set_property(TEST ${_TEST_NAME} PROPERTY ENVIRONMENT "${TORTURE_ENVIRONMENT}") endfunction() foreach(_SWRAP_TEST ${SWRAP_TESTS}) add_cmocka_test(${_SWRAP_TEST} SOURCES ${_SWRAP_TEST}.c COMPILE_OPTIONS ${DEFAULT_C_COMPILE_FLAGS} -D_GNU_SOURCE LINK_LIBRARIES ${TORTURE_LIBRARY} LINK_OPTIONS ${DEFAULT_LINK_FLAGS}) add_cmocka_test_environment(${_SWRAP_TEST}) endforeach() if (HELGRIND_TESTING) find_program(VALGRIND_EXECUTABLE valgrind) if (VALGRIND_EXECUTABLE) set(VALGRIND_HELGRIND_OPTIONS -v --trace-children=yes --tool=helgrind --error-exitcode=1 --read-var-info=yes --suppressions=${CMAKE_CURRENT_SOURCE_DIR}/helgrind.supp) foreach(_TEST ${SWRAP_THREADED_TESTS}) set(_HELGRIND_TEST "helgrind_${_TEST}") add_test(NAME ${_HELGRIND_TEST} COMMAND ${VALGRIND_EXECUTABLE} ${VALGRIND_HELGRIND_OPTIONS} ${CMAKE_CURRENT_BINARY_DIR}/${_TEST}) if (OSX) set_property( TEST ${_HELGRIND_TEST} PROPERTY ENVIRONMENT DYLD_FORCE_FLAT_NAMESPACE=1;DYLD_INSERT_LIBRARIES=${SOCKET_WRAPPER_LOCATION}) else () set_property( TEST ${_HELGRIND_TEST} PROPERTY ENVIRONMENT LD_PRELOAD=${SOCKET_WRAPPER_LOCATION} SOCKET_WRAPPER_DISABLE_DEEPBIND=1) endif() endforeach() endif() endif() # test_fork_pthread add_library(thread_deadlock SHARED thread_deadlock.c) target_link_libraries(thread_deadlock ${CMAKE_THREAD_LIBS_INIT}) target_compile_options(thread_deadlock PRIVATE ${DEFAULT_C_COMPILE_FLAGS}) add_cmocka_test(test_fork_thread_deadlock SOURCES test_fork_thread_deadlock.c COMPILE_OPTIONS ${DEFAULT_C_COMPILE_FLAGS} -D_GNU_SOURCE LINK_LIBRARIES ${TORTURE_LIBRARY} thread_deadlock LINK_OPTIONS ${DEFAULT_LINK_FLAGS}) add_cmocka_test_environment(test_fork_thread_deadlock) socket_wrapper-1.2.3/.clang_complete000644 001750 000144 00000000022 12267261735 017507 0ustar00asnusers000000 000000 -Iobj -DHAVE_IPV6 socket_wrapper-1.2.3/AUTHORS000644 001750 000144 00000000151 12247662153 015602 0ustar00asnusers000000 000000 Jelmer Vernooij Stefan Metzmacher Andreas Schneider socket_wrapper-1.2.3/DefineOptions.cmake000644 001750 000144 00000000265 13374561011 020301 0ustar00asnusers000000 000000 option(UNIT_TESTING "Build with unit tests" OFF) option(HELGRIND_TESTING "Run threaded unit tests with helgrind" OFF) option(PICKY_DEVELOPER "Build with picky developer flags" OFF) socket_wrapper-1.2.3/CompilerChecks.cmake000644 001750 000144 00000012335 13444704255 020436 0ustar00asnusers000000 000000 include(AddCCompilerFlag) include(CheckCCompilerFlagSSP) if (UNIX) # # Check for -Werror turned on if possible # # This will prevent that compiler flags are detected incorrectly. # check_c_compiler_flag("-Werror" REQUIRED_FLAGS_WERROR) if (REQUIRED_FLAGS_WERROR) set(CMAKE_REQUIRED_FLAGS "-Werror") if (PICKY_DEVELOPER) list(APPEND SUPPORTED_COMPILER_FLAGS "-Werror") endif() endif() add_c_compiler_flag("-std=gnu99" SUPPORTED_COMPILER_FLAGS) #add_c_compiler_flag("-Wpedantic" SUPPORTED_COMPILER_FLAGS) add_c_compiler_flag("-Wall" SUPPORTED_COMPILER_FLAGS) add_c_compiler_flag("-Wshadow" SUPPORTED_COMPILER_FLAGS) add_c_compiler_flag("-Wmissing-prototypes" SUPPORTED_COMPILER_FLAGS) add_c_compiler_flag("-Wcast-align" SUPPORTED_COMPILER_FLAGS) #add_c_compiler_flag("-Wcast-qual" SUPPORTED_COMPILER_FLAGS) add_c_compiler_flag("-Werror=address" SUPPORTED_COMPILER_FLAGS) add_c_compiler_flag("-Wstrict-prototypes" SUPPORTED_COMPILER_FLAGS) add_c_compiler_flag("-Werror=strict-prototypes" SUPPORTED_COMPILER_FLAGS) add_c_compiler_flag("-Wwrite-strings" SUPPORTED_COMPILER_FLAGS) add_c_compiler_flag("-Werror=write-strings" SUPPORTED_COMPILER_FLAGS) add_c_compiler_flag("-Werror-implicit-function-declaration" SUPPORTED_COMPILER_FLAGS) add_c_compiler_flag("-Wpointer-arith" SUPPORTED_COMPILER_FLAGS) add_c_compiler_flag("-Werror=pointer-arith" SUPPORTED_COMPILER_FLAGS) add_c_compiler_flag("-Wdeclaration-after-statement" SUPPORTED_COMPILER_FLAGS) add_c_compiler_flag("-Werror=declaration-after-statement" SUPPORTED_COMPILER_FLAGS) add_c_compiler_flag("-Wreturn-type" SUPPORTED_COMPILER_FLAGS) add_c_compiler_flag("-Werror=return-type" SUPPORTED_COMPILER_FLAGS) add_c_compiler_flag("-Wuninitialized" SUPPORTED_COMPILER_FLAGS) add_c_compiler_flag("-Werror=uninitialized" SUPPORTED_COMPILER_FLAGS) add_c_compiler_flag("-Wimplicit-fallthrough" SUPPORTED_COMPILER_FLAGS) add_c_compiler_flag("-Werror=strict-overflow" SUPPORTED_COMPILER_FLAGS) add_c_compiler_flag("-Wstrict-overflow=2" SUPPORTED_COMPILER_FLAGS) add_c_compiler_flag("-Wno-format-zero-length" SUPPORTED_COMPILER_FLAGS) check_c_compiler_flag("-Wformat" REQUIRED_FLAGS_WFORMAT) if (REQUIRED_FLAGS_WFORMAT) list(APPEND SUPPORTED_COMPILER_FLAGS "-Wformat") set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} -Wformat") endif() add_c_compiler_flag("-Wformat-security" SUPPORTED_COMPILER_FLAGS) add_c_compiler_flag("-Werror=format-security" SUPPORTED_COMPILER_FLAGS) # Allow zero for a variadic macro argument string(TOLOWER "${CMAKE_C_COMPILER_ID}" _C_COMPILER_ID) if ("${_C_COMPILER_ID}" STREQUAL "clang") add_c_compiler_flag("-Wno-gnu-zero-variadic-macro-arguments" SUPPORTED_COMPILER_FLAGS) endif() add_c_compiler_flag("-fno-common" SUPPORTED_COMPILER_FLAGS) if (CMAKE_BUILD_TYPE) string(TOLOWER "${CMAKE_BUILD_TYPE}" CMAKE_BUILD_TYPE_LOWER) if (CMAKE_BUILD_TYPE_LOWER MATCHES (release|relwithdebinfo|minsizerel)) add_c_compiler_flag("-Wp,-D_FORTIFY_SOURCE=2" SUPPORTED_COMPILER_FLAGS) endif() endif() if (NOT SOLARIS) check_c_compiler_flag_ssp("-fstack-protector-strong" WITH_STACK_PROTECTOR_STRONG) if (WITH_STACK_PROTECTOR_STRONG) list(APPEND SUPPORTED_COMPILER_FLAGS "-fstack-protector-strong") # This is needed as Solaris has a seperate libssp if (SOLARIS) list(APPEND SUPPORTED_LINKER_FLAGS "-fstack-protector-strong") endif() else (WITH_STACK_PROTECTOR_STRONG) check_c_compiler_flag_ssp("-fstack-protector" WITH_STACK_PROTECTOR) if (WITH_STACK_PROTECTOR) list(APPEND SUPPORTED_COMPILER_FLAGS "-fstack-protector") # This is needed as Solaris has a seperate libssp if (SOLARIS) list(APPEND SUPPORTED_LINKER_FLAGS "-fstack-protector") endif() endif() endif (WITH_STACK_PROTECTOR_STRONG) check_c_compiler_flag_ssp("-fstack-clash-protection" WITH_STACK_CLASH_PROTECTION) if (WITH_STACK_CLASH_PROTECTION) list(APPEND SUPPORTED_COMPILER_FLAGS "-fstack-clash-protection") endif() endif() if (PICKY_DEVELOPER) add_c_compiler_flag("-Wno-error=deprecated-declarations" SUPPORTED_COMPILER_FLAGS) add_c_compiler_flag("-Wno-error=tautological-compare" SUPPORTED_COMPILER_FLAGS) endif() # Unset CMAKE_REQUIRED_FLAGS unset(CMAKE_REQUIRED_FLAGS) endif() if (MSVC) add_c_compiler_flag("/D _CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES=1" SUPPORTED_COMPILER_FLAGS) add_c_compiler_flag("/D _CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES_COUNT=1" SUPPORTED_COMPILER_FLAGS) add_c_compiler_flag("/D _CRT_NONSTDC_NO_WARNINGS=1" SUPPORTED_COMPILER_FLAGS) add_c_compiler_flag("/D _CRT_SECURE_NO_WARNINGS=1" SUPPORTED_COMPILER_FLAGS) endif() if (SUPPORTED_COMPILER_FLAGS) set(DEFAULT_C_COMPILE_FLAGS ${SUPPORTED_COMPILER_FLAGS} CACHE INTERNAL "Default C Compiler Flags" FORCE) endif() if (SUPPORTED_LINKER_FLAGS) set(DEFAULT_LINK_FLAGS ${SUPPORTED_LINKER_FLAGS} CACHE INTERNAL "Default C Linker Flags" FORCE) endif() socket_wrapper-1.2.3/.gitlab-ci.yml000644 001750 000144 00000013402 13433277502 017167 0ustar00asnusers000000 000000 variables: BUILD_IMAGES_PROJECT: cmocka/gitlab-build-images FEDORA_BUILD: buildenv-fedora CENTOS7_BUILD: buildenv-centos7 TUMBLEWEED_BUILD: buildenv-tumbleweed MINGW_BUILD: buildenv-mingw DEBIAN_CROSS_BUILD: buildenv-debian-cross centos7/x86_64: image: $CI_REGISTRY/$BUILD_IMAGES_PROJECT:$CENTOS7_BUILD script: - mkdir -p obj && cd obj && cmake3 -DCMAKE_BUILD_TYPE=RelWithDebInfo -DPICKY_DEVELOPER=ON -DUNIT_TESTING=ON .. && make -j$(nproc) && ctest --output-on-failure tags: - shared except: - tags artifacts: expire_in: 1 week when: on_failure paths: - obj/ fedora/x86_64: image: $CI_REGISTRY/$BUILD_IMAGES_PROJECT:$FEDORA_BUILD script: - mkdir -p obj && cd obj && cmake -DCMAKE_BUILD_TYPE=RelWithDebInfo -DPICKY_DEVELOPER=ON -DUNIT_TESTING=ON .. && make -j$(nproc) && ctest --output-on-failure tags: - shared except: - tags artifacts: expire_in: 1 week when: on_failure paths: - obj/ fedora/address-sanitizer: image: $CI_REGISTRY/$BUILD_IMAGES_PROJECT:$FEDORA_BUILD script: - mkdir -p obj && cd obj && cmake -DCMAKE_BUILD_TYPE=AddressSanitizer -DPICKY_DEVELOPER=ON -DUNIT_TESTING=ON .. && make -j$(nproc) && ctest --output-on-failure tags: - shared except: - tags artifacts: expire_in: 1 week when: on_failure paths: - obj/ fedora/undefined-sanitizer: image: $CI_REGISTRY/$BUILD_IMAGES_PROJECT:$FEDORA_BUILD script: - mkdir -p obj && cd obj && cmake -DCMAKE_BUILD_TYPE=UndefinedSanitizer -DUNIT_TESTING=ON .. && make -j$(nproc) && ctest --output-on-failure tags: - shared except: - tags artifacts: expire_in: 1 week when: on_failure paths: - obj/ fedora/csbuild: image: $CI_REGISTRY/$BUILD_IMAGES_PROJECT:$FEDORA_BUILD script: - | if [[ -z "$CI_COMMIT_BEFORE_SHA" ]]; then export CI_COMMIT_BEFORE_SHA=$(git rev-parse "${CI_COMMIT_SHA}~20") fi # Check if the commit exists in this branch # This is not the case for a force push git branch --contains $CI_COMMIT_BEFORE_SHA 2>/dev/null || export CI_COMMIT_BEFORE_SHA=$(git rev-parse "${CI_COMMIT_SHA}~20") export CI_COMMIT_RANGE="$CI_COMMIT_BEFORE_SHA..$CI_COMMIT_SHA" - csbuild --build-dir=obj-csbuild --prep-cmd="cmake -DCMAKE_BUILD_TYPE=Debug -DPICKY_DEVELOPER=ON -DUNIT_TESTING=ON @SRCDIR@" --build-cmd "make clean && make -j$(nproc)" --git-commit-range $CI_COMMIT_RANGE --color --print-current --print-fixed tags: - shared except: - tags artifacts: expire_in: 1 week when: on_failure paths: - obj-csbuild/ freebsd/x86_64: image: script: - mkdir -p obj && cd obj && cmake -DCMAKE_BUILD_TYPE=RelWithDebInfo -DPICKY_DEVELOPER=ON -DUNIT_TESTING=ON .. && make && ctest --output-on-failure tags: - freebsd except: - tags only: - branches@cwrap/socket_wrapper - branches@cryptomilk/socket_wrapper artifacts: expire_in: 1 week when: on_failure paths: - obj/ .Debian.cross.template: &Debian_cross_template stage: test image: $CI_REGISTRY/$BUILD_IMAGES_PROJECT:$DEBIAN_CROSS_BUILD script: - build=$(dpkg-architecture -qDEB_HOST_GNU_TYPE) - host="${CI_JOB_NAME#*.cross.}" - mkdir -p obj && cd obj && cmake -DCMAKE_TOOLCHAIN_FILE=../cmake/Toolchain-Debian-mips.cmake -DCMAKE_BUILD_TYPE=RelWithDebInfo -DUNIT_TESTING=ON .. && make -j$(nproc) && ctest --output-on-failure tags: - shared except: - tags artifacts: expire_in: 1 week when: on_failure paths: - obj/ Debian.cross.mips-linux-gnu: <<: *Debian_cross_template tumbleweed/x86_64/gcc: image: $CI_REGISTRY/$BUILD_IMAGES_PROJECT:$TUMBLEWEED_BUILD script: - mkdir -p obj && cd obj && cmake -DCMAKE_BUILD_TYPE=RelWithDebInfo -DPICKY_DEVELOPER=ON -DUNIT_TESTING=ON .. && make -j$(nproc) && ctest --output-on-failure tags: - shared except: - tags artifacts: expire_in: 1 week when: on_failure paths: - obj/ tumbleweed/x86_64/gcc7: image: $CI_REGISTRY/$BUILD_IMAGES_PROJECT:$TUMBLEWEED_BUILD script: - mkdir -p obj && cd obj && cmake -DCMAKE_C_COMPILER=gcc-7 -DCMAKE_CXX_COMPILER=g++-7 -DCMAKE_BUILD_TYPE=RelWithDebInfo -DPICKY_DEVELOPER=ON -DUNIT_TESTING=ON .. && make -j$(nproc) && ctest --output-on-failure tags: - shared except: - tags artifacts: expire_in: 1 week when: on_failure paths: - obj/ tumbleweed/x86_64/clang: image: $CI_REGISTRY/$BUILD_IMAGES_PROJECT:$TUMBLEWEED_BUILD script: - mkdir -p obj && cd obj && cmake -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -DPICKY_DEVELOPER=ON -DUNIT_TESTING=ON .. && make -j$(nproc) && ctest --output-on-failure tags: - shared except: - tags artifacts: expire_in: 1 week when: on_failure paths: - obj/ tumbleweed/static-analysis: image: $CI_REGISTRY/$BUILD_IMAGES_PROJECT:$TUMBLEWEED_BUILD script: - export CCC_CC=clang - export CCC_CXX=clang++ - mkdir -p obj && cd obj && scan-build cmake -DCMAKE_BUILD_TYPE=Debug -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -DPICKY_DEVELOPER=ON -DUNIT_TESTING=ON .. && scan-build --status-bugs -o scan make -j$(nproc) tags: - shared except: - tags artifacts: expire_in: 1 week when: on_failure paths: - obj/scan tumbleweed/helgrind: image: $CI_REGISTRY/$BUILD_IMAGES_PROJECT:$TUMBLEWEED_BUILD script: - mkdir -p obj && cd obj && cmake -DCMAKE_BUILD_TYPE=Debug -DPICKY_DEVELOPER=ON -DUNIT_TESTING=ON -DHELGRIND_TESTING=ON .. && make -j$(nproc) && ctest --output-on-failure tags: - shared except: - tags artifacts: expire_in: 1 week when: on_failure paths: - obj/ socket_wrapper-1.2.3/CPackConfig.cmake000644 001750 000144 00000003350 13433277502 017645 0ustar00asnusers000000 000000 # For help take a look at: # http://www.cmake.org/Wiki/CMake:CPackConfiguration ### general settings set(CPACK_PACKAGE_NAME ${PROJECT_NAME}) set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "The SSH library") set(CPACK_PACKAGE_DESCRIPTION_FILE "${CMAKE_SOURCE_DIR}/README.md") set(CPACK_PACKAGE_VENDOR "The SSH Library Development Team") set(CPACK_PACKAGE_INSTALL_DIRECTORY ${CPACK_PACKAGE_NAME}) set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_SOURCE_DIR}/LICENSE") ### versions set(CPACK_PACKAGE_VERSION "${PROJECT_VERSION}") ### source generator set(CPACK_SOURCE_GENERATOR "TGZ") set(CPACK_SOURCE_IGNORE_FILES "~$;[.]swp$;/[.]svn/;/[.]git/;.gitignore;/build*;/obj*;tags;cscope.*") set(CPACK_SOURCE_PACKAGE_FILE_NAME "${CPACK_PACKAGE_NAME}-${CPACK_PACKAGE_VERSION}") if (WIN32) set(CPACK_GENERATOR "ZIP") ### nsis generator find_package(NSIS) if (NSIS_MAKE) set(CPACK_GENERATOR "${CPACK_GENERATOR};NSIS") set(CPACK_NSIS_DISPLAY_NAME "The SSH Library") set(CPACK_NSIS_COMPRESSOR "/SOLID zlib") set(CPACK_NSIS_MENU_LINKS "http://www.libssh.org/" "libssh homepage") endif (NSIS_MAKE) endif (WIN32) set(CPACK_PACKAGE_INSTALL_DIRECTORY "libssh") set(CPACK_PACKAGE_FILE_NAME ${CPACK_PACKAGE_NAME}-${CPACK_PACKAGE_VERSION}) set(CPACK_COMPONENT_LIBRARIES_DISPLAY_NAME "Libraries") set(CPACK_COMPONENT_HEADERS_DISPLAY_NAME "C/C++ Headers") set(CPACK_COMPONENT_LIBRARIES_DESCRIPTION "Libraries used to build programs which use libssh") set(CPACK_COMPONENT_HEADERS_DESCRIPTION "C/C++ header files for use with libssh") set(CPACK_COMPONENT_HEADERS_DEPENDS libraries) #set(CPACK_COMPONENT_PROJECTS_GROUP "Runtime") set(CPACK_COMPONENT_LIBRARIES_GROUP "Development") set(CPACK_COMPONENT_HEADERS_GROUP "Development") include(CPack) socket_wrapper-1.2.3/config.h.cmake000644 001750 000144 00000004604 13433277502 017234 0ustar00asnusers000000 000000 /* Name of package */ #cmakedefine PACKAGE "${PROJECT_NAME}" /* Version number of package */ #cmakedefine VERSION "${PROJECT_VERSION}" #cmakedefine BINARYDIR "${BINARYDIR}" #cmakedefine SOURCEDIR "${SOURCEDIR}" /************************** HEADER FILES *************************/ #cmakedefine HAVE_SYS_FILIO_H 1 #cmakedefine HAVE_SYS_SIGNALFD_H 1 #cmakedefine HAVE_SYS_EVENTFD_H 1 #cmakedefine HAVE_SYS_TIMERFD_H 1 #cmakedefine HAVE_GNU_LIB_NAMES_H 1 #cmakedefine HAVE_RPC_RPC_H 1 /**************************** STRUCTS ****************************/ #cmakedefine HAVE_STRUCT_IN_PKTINFO 1 #cmakedefine HAVE_STRUCT_IN6_PKTINFO 1 /************************ STRUCT MEMBERS *************************/ #cmakedefine HAVE_STRUCT_SOCKADDR_SA_LEN 1 #cmakedefine HAVE_STRUCT_MSGHDR_MSG_CONTROL 1 /**************************** SYMBOLS ****************************/ #cmakedefine HAVE_PROGRAM_INVOCATION_SHORT_NAME 1 /*************************** FUNCTIONS ***************************/ /* Define to 1 if you have the `getaddrinfo' function. */ #cmakedefine HAVE_GETADDRINFO 1 #cmakedefine HAVE_SIGNALFD 1 #cmakedefine HAVE_EVENTFD 1 #cmakedefine HAVE_TIMERFD_CREATE 1 #cmakedefine HAVE_BINDRESVPORT 1 #cmakedefine HAVE_ACCEPT4 1 #cmakedefine HAVE_OPEN64 1 #cmakedefine HAVE_FOPEN64 1 #cmakedefine HAVE_GETPROGNAME 1 #cmakedefine HAVE_GETEXECNAME 1 #cmakedefine HAVE_PLEDGE 1 #cmakedefine HAVE_ACCEPT_PSOCKLEN_T 1 #cmakedefine HAVE_IOCTL_INT 1 #cmakedefine HAVE_EVENTFD_UNSIGNED_INT 1 /*************************** LIBRARIES ***************************/ #cmakedefine HAVE_GETTIMEOFDAY_TZ 1 #cmakedefine HAVE_GETTIMEOFDAY_TZ_VOID 1 /*************************** DATA TYPES***************************/ #cmakedefine SIZEOF_PID_T @SIZEOF_PID_T@ /**************************** OPTIONS ****************************/ #cmakedefine HAVE_GCC_THREAD_LOCAL_STORAGE 1 #cmakedefine HAVE_CONSTRUCTOR_ATTRIBUTE 1 #cmakedefine HAVE_DESTRUCTOR_ATTRIBUTE 1 #cmakedefine HAVE_FALLTHROUGH_ATTRIBUTE 1 #cmakedefine HAVE_ADDRESS_SANITIZER_ATTRIBUTE 1 #cmakedefine HAVE_SOCKADDR_STORAGE 1 #cmakedefine HAVE_IPV6 1 #cmakedefine HAVE_FUNCTION_ATTRIBUTE_FORMAT 1 #cmakedefine HAVE_APPLE 1 #cmakedefine HAVE_LIBSOCKET 1 /*************************** ENDIAN *****************************/ /* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most significant byte first (like Motorola and SPARC, unlike Intel). */ #cmakedefine WORDS_BIGENDIAN 1 socket_wrapper-1.2.3/CTestConfig.cmake000644 001750 000144 00000000433 13374561011 017700 0ustar00asnusers000000 000000 set(UPDATE_TYPE "true") set(CTEST_PROJECT_NAME "socket_wrapper") set(CTEST_NIGHTLY_START_TIME "01:00:00 UTC") set(CTEST_DROP_METHOD "https") set(CTEST_DROP_SITE "test.cmocka.org") set(CTEST_DROP_LOCATION "/submit.php?project=${CTEST_PROJECT_NAME}") set(CTEST_DROP_SITE_CDASH TRUE) socket_wrapper-1.2.3/LICENSE000644 001750 000144 00000003327 13374561011 015540 0ustar00asnusers000000 000000 BSD 3-Clause License Copyright (c) 2005-2008, Jelmer Vernooij Copyright (c) 2006-2018, Stefan Metzmacher Copyright (c) 2013-2018, Andreas Schneider Copyright (c) 2014-2017, Michael Adam Copyright (c) 2016-2018, Anoop C S All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 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. 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. 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-1.2.3/socket_wrapper-config-version.cmake.in000644 001750 000144 00000000605 13374561011 024114 0ustar00asnusers000000 000000 set(PACKAGE_VERSION @PROJECT_VERSION@) # Check whether the requested PACKAGE_FIND_VERSION is compatible if("${PACKAGE_VERSION}" VERSION_LESS "${PACKAGE_FIND_VERSION}") set(PACKAGE_VERSION_COMPATIBLE FALSE) else() set(PACKAGE_VERSION_COMPATIBLE TRUE) if ("${PACKAGE_VERSION}" VERSION_EQUAL "${PACKAGE_FIND_VERSION}") set(PACKAGE_VERSION_EXACT TRUE) endif() endif() socket_wrapper-1.2.3/ConfigureChecks.cmake000644 001750 000144 00000016402 13433277502 020602 0ustar00asnusers000000 000000 include(CheckIncludeFile) include(CheckSymbolExists) include(CheckFunctionExists) include(CheckLibraryExists) include(CheckTypeSize) include(CheckStructHasMember) include(CheckPrototypeDefinition) include(TestBigEndian) set(PACKAGE ${PROJECT_NAME}) set(VERSION ${PROJECT_VERSION}) set(BINARYDIR ${CMAKE_BINARY_DIR}) set(SOURCEDIR ${CMAKE_SOURCE_DIR}) function(COMPILER_DUMPVERSION _OUTPUT_VERSION) # Remove whitespaces from the argument. # This is needed for CC="ccache gcc" cmake .. string(REPLACE " " "" _C_COMPILER_ARG "${CMAKE_C_COMPILER_ARG1}") execute_process( COMMAND ${CMAKE_C_COMPILER} ${_C_COMPILER_ARG} -dumpversion OUTPUT_VARIABLE _COMPILER_VERSION ) string(REGEX REPLACE "([0-9])\\.([0-9])(\\.[0-9])?" "\\1\\2" _COMPILER_VERSION "${_COMPILER_VERSION}") set(${_OUTPUT_VERSION} ${_COMPILER_VERSION} PARENT_SCOPE) endfunction() if(CMAKE_COMPILER_IS_GNUCC AND NOT MINGW AND NOT OS2) compiler_dumpversion(GNUCC_VERSION) if (NOT GNUCC_VERSION EQUAL 34) set(CMAKE_REQUIRED_FLAGS "-fvisibility=hidden") check_c_source_compiles( "void __attribute__((visibility(\"default\"))) test() {} int main(void){ return 0; } " WITH_VISIBILITY_HIDDEN) unset(CMAKE_REQUIRED_FLAGS) endif (NOT GNUCC_VERSION EQUAL 34) endif(CMAKE_COMPILER_IS_GNUCC AND NOT MINGW AND NOT OS2) # HEADERS check_include_file(sys/filio.h HAVE_SYS_FILIO_H) check_include_file(sys/signalfd.h HAVE_SYS_SIGNALFD_H) check_include_file(sys/eventfd.h HAVE_SYS_EVENTFD_H) check_include_file(sys/timerfd.h HAVE_SYS_TIMERFD_H) check_include_file(gnu/lib-names.h HAVE_GNU_LIB_NAMES_H) check_include_file(rpc/rpc.h HAVE_RPC_RPC_H) # SYMBOLS set(CMAKE_REQUIRED_FLAGS -D_GNU_SOURCE) check_symbol_exists(program_invocation_short_name "errno.h" HAVE_PROGRAM_INVOCATION_SHORT_NAME) unset(CMAKE_REQUIRED_FLAGS) # FUNCTIONS check_function_exists(strncpy HAVE_STRNCPY) check_function_exists(vsnprintf HAVE_VSNPRINTF) check_function_exists(snprintf HAVE_SNPRINTF) check_function_exists(signalfd HAVE_SIGNALFD) check_function_exists(eventfd HAVE_EVENTFD) check_function_exists(timerfd_create HAVE_TIMERFD_CREATE) check_function_exists(bindresvport HAVE_BINDRESVPORT) check_function_exists(accept4 HAVE_ACCEPT4) check_function_exists(open64 HAVE_OPEN64) check_function_exists(fopen64 HAVE_FOPEN64) check_function_exists(getprogname HAVE_GETPROGNAME) check_function_exists(getexecname HAVE_GETEXECNAME) check_function_exists(pledge HAVE_PLEDGE) if (UNIX) find_library(DLFCN_LIBRARY dl) if (DLFCN_LIBRARY) list(APPEND _REQUIRED_LIBRARIES ${DLFCN_LIBRARY}) else() check_function_exists(dlopen HAVE_DLOPEN) if (NOT HAVE_DLOPEN) message(FATAL_ERROR "FATAL: No dlopen() function detected") endif() endif() if (NOT LINUX) # libsocket (Solaris) check_library_exists(socket getaddrinfo "" HAVE_LIBSOCKET) if (HAVE_LIBSOCKET) list(APPEND _REQUIRED_LIBRARIES socket) endif (HAVE_LIBSOCKET) # libnsl/inet_pton (Solaris) check_library_exists(nsl inet_pton "" HAVE_LIBNSL) if (HAVE_LIBNSL) list(APPEND _REQUIRED_LIBRARIES nsl) endif (HAVE_LIBNSL) endif (NOT LINUX) check_function_exists(getaddrinfo HAVE_GETADDRINFO) endif (UNIX) # STRUCTS check_struct_has_member("struct in_pktinfo" ipi_addr "sys/types.h;sys/socket.h;netinet/in.h" HAVE_STRUCT_IN_PKTINFO) set(CMAKE_REQUIRED_FLAGS -D_GNU_SOURCE) check_struct_has_member("struct in6_pktinfo" ipi6_addr "sys/types.h;sys/socket.h;netinet/in.h" HAVE_STRUCT_IN6_PKTINFO) unset(CMAKE_REQUIRED_FLAGS) # STRUCT MEMBERS check_struct_has_member("struct sockaddr" sa_len "sys/types.h;sys/socket.h;netinet/in.h" HAVE_STRUCT_SOCKADDR_SA_LEN) check_struct_has_member("struct msghdr" msg_control "sys/types.h;sys/socket.h" HAVE_STRUCT_MSGHDR_MSG_CONTROL) # PROTOTYPES check_prototype_definition(gettimeofday "int gettimeofday(struct timeval *tv, struct timezone *tz)" "-1" "sys/time.h" HAVE_GETTIMEOFDAY_TZ) check_prototype_definition(gettimeofday "int gettimeofday(struct timeval *tv, void *tzp)" "-1" "sys/time.h" HAVE_GETTIMEOFDAY_TZ_VOID) check_prototype_definition(accept "int accept(int s, struct sockaddr *addr, Psocklen_t addrlen)" "-1" "sys/types.h;sys/socket.h" HAVE_ACCEPT_PSOCKLEN_T) check_prototype_definition(ioctl "int ioctl(int s, int r, ...)" "-1" "unistd.h;sys/ioctl.h" HAVE_IOCTL_INT) if (HAVE_EVENTFD) check_prototype_definition(eventfd "int eventfd(unsigned int count, int flags)" "-1" "sys/eventfd.h" HAVE_EVENTFD_UNSIGNED_INT) endif (HAVE_EVENTFD) # IPV6 check_c_source_compiles(" #include #include #include #include #include int main(void) { struct sockaddr_storage sa_store; struct addrinfo *ai = NULL; struct in6_addr in6addr; int idx = if_nametoindex(\"iface1\"); int s = socket(AF_INET6, SOCK_STREAM, 0); int ret = getaddrinfo(NULL, NULL, NULL, &ai); if (ret != 0) { const char *es = gai_strerror(ret); } freeaddrinfo(ai); { int val = 1; #ifdef HAVE_LINUX_IPV6_V6ONLY_26 #define IPV6_V6ONLY 26 #endif ret = setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, (const void *)&val, sizeof(val)); } return 0; }" HAVE_IPV6) check_c_source_compiles(" #include int main(void) { struct sockaddr_storage s; return 0; }" HAVE_SOCKADDR_STORAGE) ########################################################### # For detecting attributes we need to treat warnings as # errors set(CMAKE_REQUIRED_FLAGS "-Werror") check_c_source_compiles(" void test_constructor_attribute(void) __attribute__ ((constructor)); void test_constructor_attribute(void) { return; } int main(void) { return 0; }" HAVE_CONSTRUCTOR_ATTRIBUTE) check_c_source_compiles(" void test_destructor_attribute(void) __attribute__ ((destructor)); void test_destructor_attribute(void) { return; } int main(void) { return 0; }" HAVE_DESTRUCTOR_ATTRIBUTE) check_c_source_compiles(" #define FALL_THROUGH __attribute__((fallthrough)) int main(void) { int i = 2; switch (i) { case 0: FALL_THROUGH; case 1: break; default: break; } return 0; }" HAVE_FALLTHROUGH_ATTRIBUTE) check_c_source_compiles(" __thread int tls; int main(void) { return 0; }" HAVE_GCC_THREAD_LOCAL_STORAGE) check_c_source_compiles(" void log_fn(const char *format, ...) __attribute__ ((format (printf, 1, 2))); int main(void) { return 0; }" HAVE_FUNCTION_ATTRIBUTE_FORMAT) check_c_source_compiles(" void test_address_sanitizer_attribute(void) __attribute__((no_sanitize_address)); void test_address_sanitizer_attribute(void) { return; } int main(void) { return 0; }" HAVE_ADDRESS_SANITIZER_ATTRIBUTE) # Stop treating wanrings as errors unset(CMAKE_REQUIRED_FLAGS) ########################################################### if (OSX) set(HAVE_APPLE 1) endif (OSX) # ENDIAN if (NOT WIN32) test_big_endian(WORDS_BIGENDIAN) endif (NOT WIN32) check_type_size(pid_t SIZEOF_PID_T) set(SWRAP_REQUIRED_LIBRARIES ${_REQUIRED_LIBRARIES} CACHE INTERNAL "socket_wrapper required system libraries") socket_wrapper-1.2.3/CMakeLists.txt000644 001750 000144 00000005017 13444712246 017277 0ustar00asnusers000000 000000 # Required cmake version cmake_minimum_required(VERSION 3.5.0) cmake_policy(SET CMP0048 NEW) # Specify search path for CMake modules to be loaded by include() # and find_package() list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake/Modules") # Add defaults for cmake # Those need to be set before the project() call. include(DefineCMakeDefaults) include(DefineCompilerFlags) project(socket_wrapper VERSION 1.2.3 LANGUAGES C) # global needed variables set(APPLICATION_NAME ${PROJECT_NAME}) # SOVERSION scheme: CURRENT.AGE.REVISION # If there was an incompatible interface change: # Increment CURRENT. Set AGE and REVISION to 0 # If there was a compatible interface change: # Increment AGE. Set REVISION to 0 # If the source code was changed, but there were no interface changes: # Increment REVISION. set(LIBRARY_VERSION "0.1.13") set(LIBRARY_SOVERSION "0") # add definitions include(DefinePlatformDefaults) include(DefineOptions.cmake) include(CPackConfig.cmake) include(CompilerChecks.cmake) include(GNUInstallDirs) # disallow in-source build include(MacroEnsureOutOfSourceBuild) macro_ensure_out_of_source_build("${PROJECT_NAME} requires an out of source build. Please create a separate build directory and run 'cmake /path/to/${PROJECT_NAME} [options]' there.") # Find out if we have threading available set(CMAKE_THREAD_PREFER_PTHREADS ON) find_package(Threads) # config.h checks include(ConfigureChecks.cmake) configure_file(config.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config.h) # check subdirectories add_subdirectory(src) if (UNIT_TESTING) find_package(cmocka 1.1.0 REQUIRED) include(AddCMockaTest) add_subdirectory(tests) endif (UNIT_TESTING) # pkg-config file get_filename_component(SOCKET_WRAPPER_LIB ${SOCKET_WRAPPER_LOCATION} NAME) configure_file(socket_wrapper.pc.cmake ${CMAKE_CURRENT_BINARY_DIR}/socket_wrapper.pc @ONLY) install( FILES ${CMAKE_CURRENT_BINARY_DIR}/socket_wrapper.pc DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig COMPONENT pkgconfig ) # cmake config files configure_file(socket_wrapper-config-version.cmake.in ${CMAKE_CURRENT_BINARY_DIR}/socket_wrapper-config-version.cmake @ONLY) configure_file(socket_wrapper-config.cmake.in ${CMAKE_CURRENT_BINARY_DIR}/socket_wrapper-config.cmake @ONLY) install( FILES ${CMAKE_CURRENT_BINARY_DIR}/socket_wrapper-config-version.cmake ${CMAKE_CURRENT_BINARY_DIR}/socket_wrapper-config.cmake DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/socket_wrapper COMPONENT devel ) add_subdirectory(doc) socket_wrapper-1.2.3/README.install000644 001750 000144 00000003600 13272341670 017056 0ustar00asnusers000000 000000 Obtaining the sources ===================== Source tarballs for socket_wrapper can be downloaded from https://ftp.samba.org/pub/cwrap/ The source code repository for socket wrapper is located under git://git.samba.org/socket_wrapper.git To create a local copy, run $ git clone git://git.samba.org/socket_wrapper.git $ cd socket_wrapper Building from sources ===================== socket_wrapper uses cmake (www.cmake.org) as its build system. In an unpacked sources base directory, create a directory to contain the build results, e.g. $ mkdir obj $ cd obj Note that "obj" is just an example. The directory can be named arbitrarily. Next, run cmake to configure the build, e.g. $ cmake -DCMAKE_INSTALL_PREFIX= .. or on a 64 bit red hat system: $ cmake -DCMAKE_INSTALL_PREFIX= -DLIB_SUFFIX=64 .. The "" should be replaced by the intended installation target prefix directory, typically /usr or /usr/local. Note that the target directory does not have to be a direct or indirect subdirectory of the source base directory: It can be an arbitrary directory in the system. In the general case, ".." has to be replaced by a relative or absolute path of the source base directory in the "cmake" command line. One can control the build type with "-DCMAKE_BUILD_TYPE=" where can be one of Debug, Release, RelWithDebInfo, and some more (see cmake.org). The default is "RelWithDebInfo". After configuring with cmake, run the build with $ make Unit testing ============ In order to support running the test suite after building, the cmocka unit test framework needs to be installed (cmocka.org), and you need to specify -DUNIT_TESTING=ON in the cmake run. After running "make", $ make test runs the test suite. Installing ========== socket_wrapper is installed into the prefix directory after running "cmake" and "make" with $ make install socket_wrapper-1.2.3/doc/000755 001750 000144 00000000000 13444714527 015305 5ustar00asnusers000000 000000 socket_wrapper-1.2.3/doc/README000644 001750 000144 00000000204 13272341670 016153 0ustar00asnusers000000 000000 The manpage is written with asciidoc. To generate the manpage use: a2x --doctype manpage --format manpage doc/socket_wrapper.1.txt socket_wrapper-1.2.3/doc/CMakeLists.txt000644 001750 000144 00000000151 13433277502 020035 0ustar00asnusers000000 000000 install(FILES socket_wrapper.1 DESTINATION ${CMAKE_INSTALL_MANDIR}/man1) socket_wrapper-1.2.3/doc/socket_wrapper.1000644 001750 000144 00000013445 13444640217 020420 0ustar00asnusers000000 000000 '\" t .\" Title: socket_wrapper .\" Author: Samba Team .\" Generator: DocBook XSL Stylesheets vsnapshot .\" Date: 2018-11-28 .\" Manual: \ \& .\" Source: \ \& .\" Language: English .\" .TH "SOCKET_WRAPPER" "1" "2018\-11\-28" "\ \&" "\ \&" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .\" http://bugs.debian.org/507673 .\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- .\" disable hyphenation .nh .\" disable justification (adjust text to left margin only) .ad l .\" ----------------------------------------------------------------- .\" * MAIN CONTENT STARTS HERE * .\" ----------------------------------------------------------------- .SH "NAME" socket_wrapper \- A library passing all socket communications through unix sockets\&. .SH "SYNOPSIS" .sp LD_PRELOAD=libsocket_wrapper\&.so SOCKET_WRAPPER_DIR=/tmp/tmp\&.bQRELqDrhM SOCKET_WRAPPER_DEFAULT_IFACE=10 \fB\&./myapplication\fR .SH "DESCRIPTION" .sp socket_wrapper aims to help client/server software development teams willing to gain full functional test coverage\&. It makes possible to run several instances of the full software stack on the same machine and perform locally functional testing of complex network configurations\&. .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} Redirects all network communication to happen over Unix sockets\&. .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} Support for IPv4 and IPv6 socket and addressing emulation\&. .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} Ability to capture network traffic in pcap format\&. .RE .SH "ENVIRONMENT VARIABLES" .PP \fBSOCKET_WRAPPER_DIR\fR .RS 4 The user defines a directory where to put all the unix sockets using the environment variable "SOCKET_WRAPPER_DIR=/path/to/socket_dir"\&. When a server opens a port or a client wants to connect, socket_wrapper will translate IP addresses to a special socket_wrapper name and look for the relevant Unix socket in the SOCKET_WRAPPER_DIR\&. .RE .PP \fBSOCKET_WRAPPER_DEFAULT_IFACE\fR .RS 4 Additionally, the default interface to be used by an application is defined with "SOCKET_WRAPPER_DEFAULT_IFACE=" where is between 2 and 254\&. This is analogous to use the IPv4 addresses "127\&.0\&.0\&." or IPv6 addresses "fd00::5357:5f" (where is a hexadecimal presentation of )\&. You should always set the default interface\&. If you listen on INADDR_ANY then it will use the default interface to listen on\&. .RE .PP \fBSOCKET_WRAPPER_PCAP_FILE\fR .RS 4 When debugging, it is often interesting to investigate the network traffic between the client and server within your application\&. If you define SOCKET_WRAPPER_PCAP_FILE=/path/to/file\&.pcap, socket_wrapper will dump all your network traffic to the specified file\&. After the test has been finished you\(cqre able to open the file for example with Wireshark\&. .RE .PP \fBSOCKET_WRAPPER_MTU\fR .RS 4 With this variable you can change the MTU size\&. However we do not recomment to do that as the default size of 1500 byte is best for formatting PCAP files\&. .RE .sp The minimum value you can set is 512 and the maximum 32768\&. .PP \fBSOCKET_WRAPPER_MAX_SOCKETS\fR .RS 4 This variable can be used to set the maximum number of sockets to be used by an application\&. .RE .sp The default value is set to 65535 and the maximum 256000\&. .PP \fBSOCKET_WRAPPER_DEBUGLEVEL\fR .RS 4 If you need to see what is going on in socket_wrapper itself or try to find a bug, you can enable logging support in socket_wrapper if you built it with debug symbols\&. .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} 0 = ERROR .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} 1 = WARNING .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} 2 = DEBUG .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} 3 = TRACE .RE .RE .PP \fBSOCKET_WRAPPER_DISABLE_DEEPBIND\fR .RS 4 This allows you to disable deep binding in socket_wrapper\&. This is useful for running valgrind tools or sanitizers like (address, undefined, thread)\&. .RE .SH "EXAMPLE" .sp .if n \{\ .RS 4 .\} .nf # Open a console and create a directory for the unix sockets\&. $ mktemp \-d /tmp/tmp\&.bQRELqDrhM .fi .if n \{\ .RE .\} .sp .if n \{\ .RS 4 .\} .nf # Then start nc to listen for network traffic using the temporary directory\&. $ LD_PRELOAD=libsocket_wrapper\&.so \e SOCKET_WRAPPER_DIR=/tmp/tmp\&.bQRELqDrhM \e SOCKET_WRAPPER_DEFAULT_IFACE=10 nc \-v \-l 127\&.0\&.0\&.10 7 .fi .if n \{\ .RE .\} .sp .if n \{\ .RS 4 .\} .nf # (If nc, listens on 0\&.0\&.0\&.0 then listener will be open on 127\&.0\&.0\&.10 because # it is the default interface) .fi .if n \{\ .RE .\} .sp .if n \{\ .RS 4 .\} .nf # Now open another console and start \*(Aqnc\*(Aq as a client to connect to the server: $ LD_PRELOAD=libsocket_wrapper\&.so \e SOCKET_WRAPPER_DIR=/tmp/tmp\&.bQRELqDrhM \e SOCKET_WRAPPER_DEFAULT_IFACE=100 nc \-v 127\&.0\&.0\&.10 7 .fi .if n \{\ .RE .\} .sp .if n \{\ .RS 4 .\} .nf # (The client will use the address 127\&.0\&.0\&.100 when connecting to the server) # Now you can type \*(AqHello!\*(Aq which will be sent to the server and should appear # in the console output of the server\&. .fi .if n \{\ .RE .\} .SH "AUTHOR" .PP \fBSamba Team\fR .RS 4 Author. .RE socket_wrapper-1.2.3/doc/socket_wrapper.1.txt000644 001750 000144 00000007322 13444640217 021233 0ustar00asnusers000000 000000 socket_wrapper(1) ================= :revdate: 2018-11-28 :author: Samba Team NAME ---- socket_wrapper - A library passing all socket communications through unix sockets. SYNOPSIS -------- LD_PRELOAD=libsocket_wrapper.so SOCKET_WRAPPER_DIR=/tmp/tmp.bQRELqDrhM SOCKET_WRAPPER_DEFAULT_IFACE=10 *./myapplication* DESCRIPTION ----------- socket_wrapper aims to help client/server software development teams willing to gain full functional test coverage. It makes possible to run several instances of the full software stack on the same machine and perform locally functional testing of complex network configurations. - Redirects all network communication to happen over Unix sockets. - Support for IPv4 and IPv6 socket and addressing emulation. - Ability to capture network traffic in pcap format. ENVIRONMENT VARIABLES --------------------- *SOCKET_WRAPPER_DIR*:: The user defines a directory where to put all the unix sockets using the environment variable "SOCKET_WRAPPER_DIR=/path/to/socket_dir". When a server opens a port or a client wants to connect, socket_wrapper will translate IP addresses to a special socket_wrapper name and look for the relevant Unix socket in the SOCKET_WRAPPER_DIR. *SOCKET_WRAPPER_DEFAULT_IFACE*:: Additionally, the default interface to be used by an application is defined with "SOCKET_WRAPPER_DEFAULT_IFACE=" where is between 2 and 254. This is analogous to use the IPv4 addresses "127.0.0." or IPv6 addresses "fd00::5357:5f" (where is a hexadecimal presentation of ). You should always set the default interface. If you listen on INADDR_ANY then it will use the default interface to listen on. *SOCKET_WRAPPER_PCAP_FILE*:: When debugging, it is often interesting to investigate the network traffic between the client and server within your application. If you define SOCKET_WRAPPER_PCAP_FILE=/path/to/file.pcap, socket_wrapper will dump all your network traffic to the specified file. After the test has been finished you're able to open the file for example with Wireshark. *SOCKET_WRAPPER_MTU*:: With this variable you can change the MTU size. However we do not recomment to do that as the default size of 1500 byte is best for formatting PCAP files. The minimum value you can set is 512 and the maximum 32768. *SOCKET_WRAPPER_MAX_SOCKETS*:: This variable can be used to set the maximum number of sockets to be used by an application. The default value is set to 65535 and the maximum 256000. *SOCKET_WRAPPER_DEBUGLEVEL*:: If you need to see what is going on in socket_wrapper itself or try to find a bug, you can enable logging support in socket_wrapper if you built it with debug symbols. - 0 = ERROR - 1 = WARNING - 2 = DEBUG - 3 = TRACE *SOCKET_WRAPPER_DISABLE_DEEPBIND*:: This allows you to disable deep binding in socket_wrapper. This is useful for running valgrind tools or sanitizers like (address, undefined, thread). EXAMPLE ------- # Open a console and create a directory for the unix sockets. $ mktemp -d /tmp/tmp.bQRELqDrhM # Then start nc to listen for network traffic using the temporary directory. $ LD_PRELOAD=libsocket_wrapper.so \ SOCKET_WRAPPER_DIR=/tmp/tmp.bQRELqDrhM \ SOCKET_WRAPPER_DEFAULT_IFACE=10 nc -v -l 127.0.0.10 7 # (If nc, listens on 0.0.0.0 then listener will be open on 127.0.0.10 because # it is the default interface) # Now open another console and start 'nc' as a client to connect to the server: $ LD_PRELOAD=libsocket_wrapper.so \ SOCKET_WRAPPER_DIR=/tmp/tmp.bQRELqDrhM \ SOCKET_WRAPPER_DEFAULT_IFACE=100 nc -v 127.0.0.10 7 # (The client will use the address 127.0.0.100 when connecting to the server) # Now you can type 'Hello!' which will be sent to the server and should appear # in the console output of the server. socket_wrapper-1.2.3/foo000644 001750 000144 00000002321 13344247063 015237 0ustar00asnusers000000 000000 src/socket_wrapper.c | 30 ++++++++++-------------------- 1 file changed, 10 insertions(+), 20 deletions(-) diff --git a/src/socket_wrapper.c b/src/socket_wrapper.c index 0eff366..136b6d7 100644 --- a/src/socket_wrapper.c +++ b/src/socket_wrapper.c @@ -3193,26 +3193,6 @@ static int swrap_accept(int s, #endif } - - /* - * prevent parent_si from being altered / closed - * while we read it - */ - SWRAP_LOCK_SI(parent_si); - - /* - * assume out sockaddr have the same size as the in parent - * socket family - */ - in_addr.sa_socklen = socket_length(parent_si->family); - if (in_addr.sa_socklen <= 0) { - SWRAP_UNLOCK_SI(parent_si); - errno = EINVAL; - return -1; - } - - SWRAP_UNLOCK_SI(parent_si); - #ifdef HAVE_ACCEPT4 ret = libc_accept4(s, &un_addr.sa.s, &un_addr.sa_socklen, flags); #else @@ -3230,6 +3210,16 @@ static int swrap_accept(int s, fd = ret; SWRAP_LOCK_SI(parent_si); + /* + * assume out sockaddr have the same size as the in parent + * socket family + */ + in_addr.sa_socklen = socket_length(parent_si->family); + if (in_addr.sa_socklen <= 0) { + SWRAP_UNLOCK_SI(parent_si); + errno = EINVAL; + return -1; + } ret = sockaddr_convert_from_un(parent_si, &un_addr.sa.un, socket_wrapper-1.2.3/README.md000644 001750 000144 00000000766 13433277502 016023 0ustar00asnusers000000 000000 SOCKET_WRAPPER ============== This is a library passing all socket communications through unix sockets. DESCRIPTION ----------- More details can be found in the manpage: man -l ./doc/socket_wrapper.1 or the raw text version: less ./doc/socket_wrapper.1.txt For installation instructions please take a look at the README.install file. MAILINGLIST ----------- As the mailing list samba-technical is used and can be found here: * https://lists.samba.org/mailman/listinfo/samba-technical socket_wrapper-1.2.3/ChangeLog000644 001750 000144 00000005431 13444712246 016311 0ustar00asnusers000000 000000 ChangeLog ========== version 1.2.3 (released 2019-03-21) * Fixed missing NULL check for socket_wrapper_dir() * Fixes building in Samba source tree version 1.2.2 (released 2019-03-21) * Added environment variable to disable deep binding * Fixed installation of socket_wrapper * Fixed several small bugs version 1.2.1 (released 2018-11-14) * Removed error message to fix applications doing stupid things version 1.2.0 (released 2018-11-13) * Added threading support * Moved to modern cmake * Several smaller bugfixes version 1.1.9 (released 2017-12-04) * Fixed thread - signal deadlock issue version 1.1.8 (released 2017-10-13) * Added support for openat() * Added support for open64() and fopen64() * Always enabled logging support * Increased maximum for wrapped interfaces to 64 * Improved fd duplication code * Fixed strict-aliasing issues * Fixed some use after free issues * Fixed issues on ppc64le version 1.1.7 (released 2016-05-20) * Added support for accept4() * Added support for OpenBSD * Fixed sendto() with UDP and a connected socket * Fixed AF_RAWLINK sockets version 1.1.6 (released 2016-03-15) * Added a wrapper for write() * Added support for automatic binding of ephemeral ports * Fixed recvmsg() with UDP * Fixed AF_NETLINK sockets version 1.1.5 (released 2015-10-15) * Added support for TCP_NODELAY in setsockopt/getsockopt * Fixed cmsg space calculation version 1.1.4 (released 2015-08-25) * Fixed handling of msg_name in recvmsg() * Fixed sendmsg()/recvmsg() TCP support * Fixed several compile warnings * Added environment variable to change MTU version 1.1.3 (released 2015-02-23) * Added support for address sanitizer. * Fixed leaking of memory and fds of stale sockets. * Fixed the library loading code. version 1.1.2 (released 2014-10-01) * Added support for fnctl(F_DUPFD). * Added support for glibc 2.20.90. version 1.1.1 (released 2014-06-05) * Disable incomplete address in use check in bind(). version 1.1.0 (released 2014-06-02) * Added support for IP_PKTINFO in recvmsg(). * Added support for IPV6_PKTINFO in recvmsg(). * Added support for IP_RECVDSTADDR in recvmsg() on BSD. * Added support for more socket options in getsockopt(). * Added support for bindresvport(). * Fixed rebinding on connect(). * Fixed sockaddr buffer truncation in getsockname() and getpeername(). * Fixed special cases in bind(). * Fixed loading libc on some platforms. version 1.0.2 (released 2014-05-05) * Fixed memory leaks * Fixed calling open from libc. * Fixed loading libc functions on some platforms. version 1.0.1 (released 2014-02-04) * Added --libs to pkg-config. * Added socket_wrapper-config.cmake * Fixed a bug packaging the obj directory. version 1.0.0 (released 2014-02-02) * Initial release socket_wrapper-1.2.3/TODO000644 001750 000144 00000002015 13430566113 015215 0ustar00asnusers000000 000000 TODO ===== This is the TODO list of this project. It should give you some hints of things which need to be implemented. If you can spend some time on this project, then look at the list below. Library: --------- Goals: * The proposed way ==> - fd-passing for tcp sockets (for free) Approach: - tdb "in small". So a "db file". - for each socket an entry in the db file (file, mmap, robust mutex. e.g. one file per local ip addr) - socket_info : structure in db. protected by pthread robust mutexes - socket_info_fd : --> pointer into mmap area of db - free-list - fd-passing: pass index in array - the last element we pass is not a fd but the index number in the mmaped file * Use realpath() in socket_wrapper_dir(). Testing: --------- * Add a test to make sure detect stale file descriptors. * Add a test for sento() to broadcast 255.255.255.255. * Add a test to check that read/readv/send/ only work on connected sockets. * Add unit tests for conversion functions like convert_in_un_remote(). socket_wrapper-1.2.3/socket_wrapper-config.cmake.in000644 001750 000144 00000000115 13433277502 022432 0ustar00asnusers000000 000000 set(SOCKET_WRAPPER_LIBRARY @CMAKE_INSTALL_FULL_LIBDIR@/@SOCKET_WRAPPER_LIB@) socket_wrapper-1.2.3/socket_wrapper.pc.cmake000644 001750 000144 00000000212 13433277502 021161 0ustar00asnusers000000 000000 Name: @PROJECT_NAME@ Description: The socket_wrapper library Version: @PROJECT_VERSION@ Libs: @CMAKE_INSTALL_LIBDIR@/@SOCKET_WRAPPER_LIB@