socket_wrapper-1.1.5/AUTHORS000644 001750 000144 00000000151 12247662153 015603 0ustar00asnusers000000 000000 Jelmer Vernooij Stefan Metzmacher Andreas Schneider socket_wrapper-1.1.5/COPYING000644 001750 000144 00000003112 12247662153 015566 0ustar00asnusers000000 000000 Copyright (C) Jelmer Vernooij 2005,2008 Copyright (C) Stefan Metzmacher 2006-2009 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. socket_wrapper-1.1.5/DefineOptions.cmake000644 001750 000144 00000000061 12247662153 020303 0ustar00asnusers000000 000000 option(UNIT_TESTING "Build with unit tests" OFF) socket_wrapper-1.1.5/cmake/Modules/AddCMockaTest.cmake000644 001750 000144 00000002373 12247662153 022643 0ustar00asnusers000000 000000 # - ADD_CHECK_TEST(test_name test_source linklib1 ... linklibN) # Copyright (c) 2007 Daniel Gollub # Copyright (c) 2007-2010 Andreas Schneider # # Redistribution and use is allowed according to the terms of the BSD license. # For details see the accompanying COPYING-CMAKE-SCRIPTS file. enable_testing() include(CTest) if(CMAKE_COMPILER_IS_GNUCC AND NOT MINGW) set(CMAKE_C_FLAGS_PROFILING "-g -O0 -Wall -W -Wshadow -Wunused-variable -Wunused-parameter -Wunused-function -Wunused -Wno-system-headers -Wwrite-strings -fprofile-arcs -ftest-coverage" CACHE STRING "Profiling Compiler Flags") set(CMAKE_SHARED_LINKER_FLAGS_PROFILING " -fprofile-arcs -ftest-coverage" CACHE STRING "Profiling Linker Flags") set(CMAKE_MODULE_LINKER_FLAGS_PROFILING " -fprofile-arcs -ftest-coverage" CACHE STRING "Profiling Linker Flags") set(CMAKE_EXEC_LINKER_FLAGS_PROFILING " -fprofile-arcs -ftest-coverage" CACHE STRING "Profiling Linker Flags") endif(CMAKE_COMPILER_IS_GNUCC AND NOT MINGW) function (ADD_CMOCKA_TEST _testName _testSource) add_executable(${_testName} ${_testSource}) target_link_libraries(${_testName} ${ARGN}) add_test(${_testName} ${CMAKE_CURRENT_BINARY_DIR}/${_testName}) endfunction (ADD_CMOCKA_TEST) socket_wrapper-1.1.5/cmake/Modules/COPYING-CMAKE-SCRIPTS000644 001750 000144 00000002457 12247662153 022234 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.1.5/cmake/Modules/CheckCCompilerFlagSSP.cmake000644 001750 000144 00000001755 12247662153 024233 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. include(CheckCSourceCompiles) function(CHECK_C_COMPILER_FLAG_SSP _FLAG _RESULT) set(SAFE_CMAKE_REQUIRED_DEFINITIONS "${CMAKE_REQUIRED_DEFINITIONS}") set(CMAKE_REQUIRED_DEFINITIONS "${_FLAG}") check_c_source_compiles("int main(int argc, char **argv) { char buffer[256]; return buffer[argc]=0;}" ${_RESULT}) set(CMAKE_REQUIRED_DEFINITIONS "${SAFE_CMAKE_REQUIRED_DEFINITIONS}") endfunction(CHECK_C_COMPILER_FLAG_SSP) socket_wrapper-1.1.5/cmake/Modules/DefinePlatformDefaults.cmake000644 001750 000144 00000001460 12247662153 024620 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.1.5/cmake/Modules/MacroEnsureOutOfSourceBuild.cmake000644 001750 000144 00000001227 12247662153 025573 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.1.5/cmake/Modules/DefineCMakeDefaults.cmake000644 001750 000144 00000001742 12332671455 024017 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) # Define the generic version of the libraries here set(GENERIC_LIB_VERSION "0.1.0") set(GENERIC_LIB_SOVERSION "0") # Set the default build type to release with debug info if (NOT CMAKE_BUILD_TYPE) set(CMAKE_BUILD_TYPE RelWithDebInfo CACHE STRING "Choose the type of build, options are: None Debug Release RelWithDebInfo MinSizeRel." ) endif (NOT CMAKE_BUILD_TYPE) # Create the compile command database for clang by default set(CMAKE_EXPORT_COMPILE_COMMANDS ON) socket_wrapper-1.1.5/cmake/Modules/DefineInstallationPaths.cmake000644 001750 000144 00000007343 12332671455 025013 0ustar00asnusers000000 000000 if (UNIX OR OS2) IF (NOT APPLICATION_NAME) MESSAGE(STATUS "${PROJECT_NAME} is used as APPLICATION_NAME") SET(APPLICATION_NAME ${PROJECT_NAME}) ENDIF (NOT APPLICATION_NAME) # Suffix for Linux SET(LIB_SUFFIX CACHE STRING "Define suffix of directory name (32/64)" ) SET(EXEC_INSTALL_PREFIX "${CMAKE_INSTALL_PREFIX}" CACHE PATH "Base directory for executables and libraries" ) SET(SHARE_INSTALL_PREFIX "${CMAKE_INSTALL_PREFIX}/share" CACHE PATH "Base directory for files which go to share/" ) SET(DATA_INSTALL_PREFIX "${SHARE_INSTALL_PREFIX}/${APPLICATION_NAME}" CACHE PATH "The parent directory where applications can install their data") # The following are directories where stuff will be installed to SET(BIN_INSTALL_DIR "${EXEC_INSTALL_PREFIX}/bin" CACHE PATH "The ${APPLICATION_NAME} binary install dir (default prefix/bin)" ) SET(SBIN_INSTALL_DIR "${EXEC_INSTALL_PREFIX}/sbin" CACHE PATH "The ${APPLICATION_NAME} sbin install dir (default prefix/sbin)" ) SET(LIB_INSTALL_DIR "${EXEC_INSTALL_PREFIX}/lib${LIB_SUFFIX}" CACHE PATH "The subdirectory relative to the install prefix where libraries will be installed (default is prefix/lib)" ) SET(LIBEXEC_INSTALL_DIR "${EXEC_INSTALL_PREFIX}/libexec" CACHE PATH "The subdirectory relative to the install prefix where libraries will be installed (default is prefix/libexec)" ) SET(PLUGIN_INSTALL_DIR "${LIB_INSTALL_DIR}/${APPLICATION_NAME}" CACHE PATH "The subdirectory relative to the install prefix where plugins will be installed (default is prefix/lib/${APPLICATION_NAME})" ) SET(INCLUDE_INSTALL_DIR "${CMAKE_INSTALL_PREFIX}/include" CACHE PATH "The subdirectory to the header prefix (default prefix/include)" ) set(CMAKE_INSTALL_DIR "${LIB_INSTALL_DIR}/cmake" CACHE PATH "The subdirectory to install cmake config files") SET(DATA_INSTALL_DIR "${DATA_INSTALL_PREFIX}" CACHE PATH "The parent directory where applications can install their data (default prefix/share/${APPLICATION_NAME})" ) SET(HTML_INSTALL_DIR "${DATA_INSTALL_PREFIX}/doc/HTML" CACHE PATH "The HTML install dir for documentation (default data/doc/html)" ) SET(ICON_INSTALL_DIR "${DATA_INSTALL_PREFIX}/icons" CACHE PATH "The icon install dir (default data/icons/)" ) SET(SOUND_INSTALL_DIR "${DATA_INSTALL_PREFIX}/sounds" CACHE PATH "The install dir for sound files (default data/sounds)" ) SET(LOCALE_INSTALL_DIR "${SHARE_INSTALL_PREFIX}/locale" CACHE PATH "The install dir for translations (default prefix/share/locale)" ) SET(XDG_APPS_DIR "${SHARE_INSTALL_PREFIX}/applications/" CACHE PATH "The XDG apps dir" ) SET(XDG_DIRECTORY_DIR "${SHARE_INSTALL_PREFIX}/desktop-directories" CACHE PATH "The XDG directory" ) SET(SYSCONF_INSTALL_DIR "${EXEC_INSTALL_PREFIX}/etc" CACHE PATH "The ${APPLICATION_NAME} sysconfig install dir (default prefix/etc)" ) SET(MAN_INSTALL_DIR "${SHARE_INSTALL_PREFIX}/man" CACHE PATH "The ${APPLICATION_NAME} man install dir (default prefix/man)" ) SET(INFO_INSTALL_DIR "${SHARE_INSTALL_PREFIX}/info" CACHE PATH "The ${APPLICATION_NAME} info install dir (default prefix/info)" ) else() # Same same set(BIN_INSTALL_DIR "bin" CACHE PATH "-") set(SBIN_INSTALL_DIR "sbin" CACHE PATH "-") set(LIB_INSTALL_DIR "lib${LIB_SUFFIX}" CACHE PATH "-") set(INCLUDE_INSTALL_DIR "include" CACHE PATH "-") set(CMAKE_INSTALL_DIR "CMake" CACHE PATH "-") set(PLUGIN_INSTALL_DIR "plugins" CACHE PATH "-") set(HTML_INSTALL_DIR "doc/HTML" CACHE PATH "-") set(ICON_INSTALL_DIR "icons" CACHE PATH "-") set(SOUND_INSTALL_DIR "sounds" CACHE PATH "-") set(LOCALE_INSTALL_DIR "lang" CACHE PATH "-") endif () socket_wrapper-1.1.5/cmake/Modules/DefineCompilerFlags.cmake000644 001750 000144 00000007216 12413156767 024104 0ustar00asnusers000000 000000 # define system dependent compiler flags include(CheckCCompilerFlag) include(CheckCCompilerFlagSSP) if (UNIX AND NOT WIN32) # # Define GNUCC compiler flags # if (${CMAKE_C_COMPILER_ID} MATCHES "(GNU|Clang)") # add -Wconversion ? set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=gnu99") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra -Wshadow -Wmissing-prototypes -Wdeclaration-after-statement") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wunused -Wfloat-equal -Wpointer-arith -Wwrite-strings -Wformat-security") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wmissing-format-attribute -Wcast-align -Wcast-qual") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-missing-field-initializers") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Werror=pointer-arith -Werror=declaration-after-statement") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Werror=implicit-function-declaration -Werror=write-strings") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Werror=int-to-pointer-cast -Werror=pointer-to-int-cast") # -Werror=strict-aliasing is broken set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fstrict-aliasing -Wstrict-aliasing=2") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fstrict-overflow -Wstrict-overflow=5 -Werror=strict-overflow") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -D_GNU_SOURCE") if (OSX) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -D__APPLE_USE_RFC_3542") endif (OSX) # with -fPIC check_c_compiler_flag("-fPIC" WITH_FPIC) if (WITH_FPIC) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fPIC") endif (WITH_FPIC) check_c_compiler_flag_ssp("-fstack-protector" WITH_STACK_PROTECTOR) if (WITH_STACK_PROTECTOR) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fstack-protector") endif (WITH_STACK_PROTECTOR) if (CMAKE_BUILD_TYPE) string(TOLOWER "${CMAKE_BUILD_TYPE}" CMAKE_BUILD_TYPE_LOWER) if (CMAKE_BUILD_TYPE_LOWER MATCHES (release|relwithdebinfo|minsizerel)) check_c_compiler_flag("-Wp,-D_FORTIFY_SOURCE=2" WITH_FORTIFY_SOURCE) if (WITH_FORTIFY_SOURCE) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wp,-D_FORTIFY_SOURCE=2") endif (WITH_FORTIFY_SOURCE) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Werror=uninitialized") endif() endif() endif (${CMAKE_C_COMPILER_ID} MATCHES "(GNU|Clang)") # # Check for large filesystem support # if (CMAKE_SIZEOF_VOID_P MATCHES "8") # with large file support execute_process( COMMAND getconf LFS64_CFLAGS OUTPUT_VARIABLE _lfs_CFLAGS ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE ) else (CMAKE_SIZEOF_VOID_P MATCHES "8") # with large file support execute_process( COMMAND getconf LFS_CFLAGS OUTPUT_VARIABLE _lfs_CFLAGS ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE ) endif (CMAKE_SIZEOF_VOID_P MATCHES "8") if (_lfs_CFLAGS) string(REGEX REPLACE "[\r\n]" " " "${_lfs_CFLAGS}" "${${_lfs_CFLAGS}}") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${_lfs_CFLAGS}") endif (_lfs_CFLAGS) endif (UNIX AND NOT WIN32) if (MSVC) # Use secure functions by defaualt and suppress warnings about #"deprecated" functions set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /D _CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES=1") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /D _CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES_COUNT=1") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /D _CRT_NONSTDC_NO_WARNINGS=1 /D _CRT_SECURE_NO_WARNINGS=1") endif (MSVC) socket_wrapper-1.1.5/example/openssh.sh000755 001750 000144 00000004241 12250071704 020176 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.1.5/src/CMakeLists.txt000644 001750 000144 00000001310 12413156767 020064 0ustar00asnusers000000 000000 project(libsocket_wrapper C) include_directories(${CMAKE_BINARY_DIR}) add_library(socket_wrapper SHARED socket_wrapper.c) target_link_libraries(socket_wrapper ${SWRAP_REQUIRED_LIBRARIES}) install( TARGETS socket_wrapper RUNTIME DESTINATION ${BIN_INSTALL_DIR} LIBRARY DESTINATION ${LIB_INSTALL_DIR} ARCHIVE DESTINATION ${LIB_INSTALL_DIR} ) set_target_properties( socket_wrapper PROPERTIES VERSION ${LIBRARY_VERSION} SOVERSION ${LIBRARY_SOVERSION} ) # This needs to be at the end if (POLICY CMP0026) cmake_policy(SET CMP0026 OLD) endif() get_target_property(SWRAP_LOCATION socket_wrapper LOCATION) set(SOCKET_WRAPPER_LOCATION ${SWRAP_LOCATION} PARENT_SCOPE) socket_wrapper-1.1.5/src/socket_wrapper.c000644 001750 000144 00000336412 12607653567 020543 0ustar00asnusers000000 000000 /* * Copyright (c) 2005-2008 Jelmer Vernooij * Copyright (C) 2006-2014 Stefan Metzmacher * Copyright (C) 2013-2014 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. * */ /* 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 enum swrap_dbglvl_e { SWRAP_LOG_ERROR = 0, SWRAP_LOG_WARN, SWRAP_LOG_DEBUG, SWRAP_LOG_TRACE }; /* GCC have printf type attribute check. */ #ifdef HAVE_FUNCTION_ATTRIBUTE_FORMAT #define PRINTF_ATTRIBUTE(a,b) __attribute__ ((__format__ (__printf__, a, b))) #else #define PRINTF_ATTRIBUTE(a,b) #endif /* HAVE_FUNCTION_ATTRIBUTE_FORMAT */ #ifdef HAVE_DESTRUCTOR_ATTRIBUTE #define DESTRUCTOR_ATTRIBUTE __attribute__ ((destructor)) #else #define DESTRUCTOR_ATTRIBUTE #endif #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 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 #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 #define SWRAP_DLIST_ADD(list,item) do { \ if (!(list)) { \ (item)->prev = NULL; \ (item)->next = NULL; \ (list) = (item); \ } else { \ (item)->prev = NULL; \ (item)->next = (list); \ (list)->prev = (item); \ (list) = (item); \ } \ } while (0) #define SWRAP_DLIST_REMOVE(list,item) do { \ if ((list) == (item)) { \ (list) = (item)->next; \ if (list) { \ (list)->prev = NULL; \ } \ } else { \ if ((item)->prev) { \ (item)->prev->next = (item)->next; \ } \ if ((item)->next) { \ (item)->next->prev = (item)->prev; \ } \ } \ (item)->prev = NULL; \ (item)->next = NULL; \ } while (0) #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 /* 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 40 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; }; struct socket_info_fd { struct socket_info_fd *prev, *next; int fd; }; struct socket_info { struct socket_info_fd *fds; int family; int type; int protocol; int bound; int bcast; int is_server; int connected; int defer_connect; 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 *prev, *next; }; /* * File descriptors are shared between threads so we should share socket * information too. */ struct socket_info *sockets; /* Function prototypes */ bool socket_wrapper_enabled(void); void swrap_destructor(void) DESTRUCTOR_ATTRIBUTE; #ifdef NDEBUG # define SWRAP_LOG(...) #else static void swrap_log(enum swrap_dbglvl_e dbglvl, const char *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; d = getenv("SOCKET_WRAPPER_DEBUGLEVEL"); if (d != NULL) { lvl = atoi(d); } va_start(va, format); vsnprintf(buffer, sizeof(buffer), format, va); va_end(va); if (lvl >= dbglvl) { switch (dbglvl) { case SWRAP_LOG_ERROR: fprintf(stderr, "SWRAP_ERROR(%d) - %s: %s\n", (int)getpid(), func, buffer); break; case SWRAP_LOG_WARN: fprintf(stderr, "SWRAP_WARN(%d) - %s: %s\n", (int)getpid(), func, buffer); break; case SWRAP_LOG_DEBUG: fprintf(stderr, "SWRAP_DEBUG(%d) - %s: %s\n", (int)getpid(), func, buffer); break; case SWRAP_LOG_TRACE: fprintf(stderr, "SWRAP_TRACE(%d) - %s: %s\n", (int)getpid(), func, buffer); break; } } } #endif /********************************************************* * SWRAP LOADING LIBC FUNCTIONS *********************************************************/ #include struct swrap_libc_fns { int (*libc_accept)(int sockfd, struct sockaddr *addr, socklen_t *addrlen); int (*libc_bind)(int sockfd, const struct sockaddr *addr, socklen_t addrlen); int (*libc_close)(int fd); int (*libc_connect)(int sockfd, const struct sockaddr *addr, socklen_t addrlen); int (*libc_dup)(int fd); int (*libc_dup2)(int oldfd, int newfd); int (*libc_fcntl)(int fd, int cmd, ...); FILE *(*libc_fopen)(const char *name, const char *mode); #ifdef HAVE_EVENTFD int (*libc_eventfd)(int count, int flags); #endif int (*libc_getpeername)(int sockfd, struct sockaddr *addr, socklen_t *addrlen); int (*libc_getsockname)(int sockfd, struct sockaddr *addr, socklen_t *addrlen); int (*libc_getsockopt)(int sockfd, int level, int optname, void *optval, socklen_t *optlen); int (*libc_ioctl)(int d, unsigned long int request, ...); int (*libc_listen)(int sockfd, int backlog); int (*libc_open)(const char *pathname, int flags, mode_t mode); int (*libc_pipe)(int pipefd[2]); int (*libc_read)(int fd, void *buf, size_t count); ssize_t (*libc_readv)(int fd, const struct iovec *iov, int iovcnt); int (*libc_recv)(int sockfd, void *buf, size_t len, int flags); int (*libc_recvfrom)(int sockfd, void *buf, size_t len, int flags, struct sockaddr *src_addr, socklen_t *addrlen); int (*libc_recvmsg)(int sockfd, const struct msghdr *msg, int flags); int (*libc_send)(int sockfd, const void *buf, size_t len, int flags); int (*libc_sendmsg)(int sockfd, const struct msghdr *msg, int flags); int (*libc_sendto)(int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *dst_addr, socklen_t addrlen); int (*libc_setsockopt)(int sockfd, int level, int optname, const void *optval, socklen_t optlen); #ifdef HAVE_SIGNALFD int (*libc_signalfd)(int fd, const sigset_t *mask, int flags); #endif int (*libc_socket)(int domain, int type, int protocol); int (*libc_socketpair)(int domain, int type, int protocol, int sv[2]); #ifdef HAVE_TIMERFD_CREATE int (*libc_timerfd_create)(int clockid, int flags); #endif ssize_t (*libc_writev)(int fd, const struct iovec *iov, int iovcnt); }; struct swrap { void *libc_handle; void *libsocket_handle; bool initialised; bool enabled; char *socket_dir; struct swrap_libc_fns fns; }; static struct swrap swrap; /* prototypes */ static const char *socket_wrapper_dir(void); #define LIBC_NAME "libc.so" enum swrap_lib { SWRAP_LIBC, SWRAP_LIBNSL, SWRAP_LIBSOCKET, }; #ifndef NDEBUG static const char *swrap_str_lib(enum swrap_lib lib) { switch (lib) { case SWRAP_LIBC: return "libc"; case SWRAP_LIBNSL: return "libnsl"; case SWRAP_LIBSOCKET: return "libsocket"; } /* Compiler would warn us about unhandled enum value if we get here */ return "unknown"; } #endif static void *swrap_load_lib_handle(enum swrap_lib lib) { int flags = RTLD_LAZY; void *handle = NULL; int i; #ifdef RTLD_DEEPBIND flags |= RTLD_DEEPBIND; #endif switch (lib) { case SWRAP_LIBNSL: /* FALL TROUGH */ case SWRAP_LIBSOCKET: #ifdef HAVE_LIBSOCKET handle = swrap.libsocket_handle; if (handle == NULL) { for (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.libsocket_handle = handle; } break; #endif /* FALL TROUGH */ 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.libsocket_handle = RTLD_NEXT; #else SWRAP_LOG(SWRAP_LOG_ERROR, "Failed to dlopen library: %s\n", dlerror()); exit(-1); #endif } return handle; } static void *_swrap_load_lib_function(enum swrap_lib lib, const char *fn_name) { void *handle; void *func; handle = swrap_load_lib_handle(lib); func = dlsym(handle, fn_name); if (func == NULL) { SWRAP_LOG(SWRAP_LOG_ERROR, "Failed to find %s: %s\n", fn_name, dlerror()); exit(-1); } SWRAP_LOG(SWRAP_LOG_TRACE, "Loaded %s from %s", fn_name, swrap_str_lib(lib)); return func; } #define swrap_load_lib_function(lib, fn_name) \ if (swrap.fns.libc_##fn_name == NULL) { \ void *swrap_cast_ptr = _swrap_load_lib_function(lib, #fn_name); \ *(void **) (&swrap.fns.libc_##fn_name) = \ swrap_cast_ptr; \ } /* * 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. */ static int libc_accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen) { swrap_load_lib_function(SWRAP_LIBSOCKET, accept); return swrap.fns.libc_accept(sockfd, addr, addrlen); } static int libc_bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen) { swrap_load_lib_function(SWRAP_LIBSOCKET, bind); return swrap.fns.libc_bind(sockfd, addr, addrlen); } static int libc_close(int fd) { swrap_load_lib_function(SWRAP_LIBC, close); return swrap.fns.libc_close(fd); } static int libc_connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen) { swrap_load_lib_function(SWRAP_LIBSOCKET, connect); return swrap.fns.libc_connect(sockfd, addr, addrlen); } static int libc_dup(int fd) { swrap_load_lib_function(SWRAP_LIBC, dup); return swrap.fns.libc_dup(fd); } static int libc_dup2(int oldfd, int newfd) { swrap_load_lib_function(SWRAP_LIBC, dup2); return swrap.fns.libc_dup2(oldfd, newfd); } #ifdef HAVE_EVENTFD static int libc_eventfd(int count, int flags) { swrap_load_lib_function(SWRAP_LIBC, eventfd); return swrap.fns.libc_eventfd(count, flags); } #endif DO_NOT_SANITIZE_ADDRESS_ATTRIBUTE static int libc_vfcntl(int fd, int cmd, va_list ap) { long int args[4]; int rc; int i; swrap_load_lib_function(SWRAP_LIBC, fcntl); for (i = 0; i < 4; i++) { args[i] = va_arg(ap, long int); } rc = swrap.fns.libc_fcntl(fd, cmd, args[0], args[1], args[2], args[3]); return rc; } static int libc_getpeername(int sockfd, struct sockaddr *addr, socklen_t *addrlen) { swrap_load_lib_function(SWRAP_LIBSOCKET, getpeername); return swrap.fns.libc_getpeername(sockfd, addr, addrlen); } static int libc_getsockname(int sockfd, struct sockaddr *addr, socklen_t *addrlen) { swrap_load_lib_function(SWRAP_LIBSOCKET, getsockname); return swrap.fns.libc_getsockname(sockfd, addr, addrlen); } static int libc_getsockopt(int sockfd, int level, int optname, void *optval, socklen_t *optlen) { swrap_load_lib_function(SWRAP_LIBSOCKET, getsockopt); return swrap.fns.libc_getsockopt(sockfd, level, optname, optval, optlen); } DO_NOT_SANITIZE_ADDRESS_ATTRIBUTE static int libc_vioctl(int d, unsigned long int request, va_list ap) { long int args[4]; int rc; int i; swrap_load_lib_function(SWRAP_LIBC, ioctl); for (i = 0; i < 4; i++) { args[i] = va_arg(ap, long int); } rc = swrap.fns.libc_ioctl(d, request, args[0], args[1], args[2], args[3]); return rc; } static int libc_listen(int sockfd, int backlog) { swrap_load_lib_function(SWRAP_LIBSOCKET, listen); return swrap.fns.libc_listen(sockfd, backlog); } static FILE *libc_fopen(const char *name, const char *mode) { swrap_load_lib_function(SWRAP_LIBC, fopen); return swrap.fns.libc_fopen(name, mode); } static int libc_vopen(const char *pathname, int flags, va_list ap) { long int mode = 0; int fd; swrap_load_lib_function(SWRAP_LIBC, open); mode = va_arg(ap, long int); fd = swrap.fns.libc_open(pathname, flags, (mode_t)mode); return fd; } 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; } static int libc_pipe(int pipefd[2]) { swrap_load_lib_function(SWRAP_LIBSOCKET, pipe); return swrap.fns.libc_pipe(pipefd); } static int libc_read(int fd, void *buf, size_t count) { swrap_load_lib_function(SWRAP_LIBC, read); return swrap.fns.libc_read(fd, buf, count); } static ssize_t libc_readv(int fd, const struct iovec *iov, int iovcnt) { swrap_load_lib_function(SWRAP_LIBSOCKET, readv); return swrap.fns.libc_readv(fd, iov, iovcnt); } static int libc_recv(int sockfd, void *buf, size_t len, int flags) { swrap_load_lib_function(SWRAP_LIBSOCKET, recv); return swrap.fns.libc_recv(sockfd, buf, len, flags); } static int libc_recvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr *src_addr, socklen_t *addrlen) { swrap_load_lib_function(SWRAP_LIBSOCKET, recvfrom); return swrap.fns.libc_recvfrom(sockfd, buf, len, flags, src_addr, addrlen); } static int libc_recvmsg(int sockfd, struct msghdr *msg, int flags) { swrap_load_lib_function(SWRAP_LIBSOCKET, recvmsg); return swrap.fns.libc_recvmsg(sockfd, msg, flags); } static int libc_send(int sockfd, const void *buf, size_t len, int flags) { swrap_load_lib_function(SWRAP_LIBSOCKET, send); return swrap.fns.libc_send(sockfd, buf, len, flags); } static int libc_sendmsg(int sockfd, const struct msghdr *msg, int flags) { swrap_load_lib_function(SWRAP_LIBSOCKET, sendmsg); return swrap.fns.libc_sendmsg(sockfd, msg, flags); } static int libc_sendto(int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *dst_addr, socklen_t addrlen) { swrap_load_lib_function(SWRAP_LIBSOCKET, sendto); return swrap.fns.libc_sendto(sockfd, buf, len, flags, dst_addr, addrlen); } static int libc_setsockopt(int sockfd, int level, int optname, const void *optval, socklen_t optlen) { swrap_load_lib_function(SWRAP_LIBSOCKET, setsockopt); return swrap.fns.libc_setsockopt(sockfd, level, optname, optval, optlen); } #ifdef HAVE_SIGNALFD static int libc_signalfd(int fd, const sigset_t *mask, int flags) { swrap_load_lib_function(SWRAP_LIBSOCKET, signalfd); return swrap.fns.libc_signalfd(fd, mask, flags); } #endif static int libc_socket(int domain, int type, int protocol) { swrap_load_lib_function(SWRAP_LIBSOCKET, socket); return swrap.fns.libc_socket(domain, type, protocol); } static int libc_socketpair(int domain, int type, int protocol, int sv[2]) { swrap_load_lib_function(SWRAP_LIBSOCKET, socketpair); return swrap.fns.libc_socketpair(domain, type, protocol, sv); } #ifdef HAVE_TIMERFD_CREATE static int libc_timerfd_create(int clockid, int flags) { swrap_load_lib_function(SWRAP_LIBC, timerfd_create); return swrap.fns.libc_timerfd_create(clockid, flags); } #endif static ssize_t libc_writev(int fd, const struct iovec *iov, int iovcnt) { swrap_load_lib_function(SWRAP_LIBSOCKET, writev); return swrap.fns.libc_writev(fd, iov, iovcnt); } /********************************************************* * SWRAP HELPER FUNCTIONS *********************************************************/ #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 const char *socket_wrapper_dir(void) { const char *s = getenv("SOCKET_WRAPPER_DIR"); if (s == NULL) { return NULL; } /* TODO use realpath(3) here, when we add support for threads */ if (strncmp(s, "./", 2) == 0) { s += 2; } SWRAP_LOG(SWRAP_LOG_TRACE, "socket_wrapper_dir: %s", s); return s; } static unsigned int socket_wrapper_mtu(void) { static unsigned int max_mtu = 0; unsigned int tmp; const char *s; char *endp; if (max_mtu != 0) { return max_mtu; } 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: return max_mtu; } bool socket_wrapper_enabled(void) { const char *s = socket_wrapper_dir(); return s != NULL ? true : false; } 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 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; 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; } if (is_bcast) { snprintf(un->sun_path, sizeof(un->sun_path), "%s/EINVAL", socket_wrapper_dir()); SWRAP_LOG(SWRAP_LOG_DEBUG, "un path [%s]", un->sun_path); /* the caller need to do more processing */ return 0; } snprintf(un->sun_path, sizeof(un->sun_path), "%s/"SOCKET_FORMAT, socket_wrapper_dir(), type, iface, prt); SWRAP_LOG(SWRAP_LOG_DEBUG, "un path [%s]", un->sun_path); 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; 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; } if (prt == 0) { /* handle auto-allocation of ephemeral ports */ for (prt = 5001; prt < 10000; prt++) { snprintf(un->sun_path, sizeof(un->sun_path), "%s/"SOCKET_FORMAT, socket_wrapper_dir(), type, iface, prt); 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; return -1; } } snprintf(un->sun_path, sizeof(un->sun_path), "%s/"SOCKET_FORMAT, socket_wrapper_dir(), type, iface, prt); SWRAP_LOG(SWRAP_LOG_DEBUG, "un path [%s]", un->sun_path); return 0; } static struct socket_info *find_socket_info(int fd) { struct socket_info *i; for (i = sockets; i; i = i->next) { struct socket_info_fd *f; for (f = i->fds; f; f = f->next) { if (f->fd == fd) { return i; } } } return NULL; } #if 0 /* FIXME */ static bool check_addr_port_in_use(const struct sockaddr *sa, socklen_t len) { struct socket_info *s; /* first catch invalid input */ switch (sa->sa_family) { case AF_INET: if (len < sizeof(struct sockaddr_in)) { return false; } break; #if HAVE_IPV6 case AF_INET6: if (len < sizeof(struct sockaddr_in6)) { return false; } break; #endif default: return false; break; } for (s = sockets; s != NULL; s = s->next) { if (s->myname == NULL) { continue; } if (s->myname->sa_family != sa->sa_family) { continue; } switch (s->myname->sa_family) { case AF_INET: { struct sockaddr_in *sin1, *sin2; sin1 = (struct sockaddr_in *)s->myname; sin2 = (struct sockaddr_in *)sa; if (sin1->sin_addr.s_addr == htonl(INADDR_ANY)) { continue; } if (sin1->sin_port != sin2->sin_port) { continue; } if (sin1->sin_addr.s_addr != sin2->sin_addr.s_addr) { continue; } /* found */ return true; break; } #if HAVE_IPV6 case AF_INET6: { struct sockaddr_in6 *sin1, *sin2; sin1 = (struct sockaddr_in6 *)s->myname; sin2 = (struct sockaddr_in6 *)sa; if (sin1->sin6_port != sin2->sin6_port) { continue; } if (!IN6_ARE_ADDR_EQUAL(&sin1->sin6_addr, &sin2->sin6_addr)) { continue; } /* found */ return true; break; } #endif default: continue; break; } } return false; } #endif static void swrap_remove_stale(int fd) { struct socket_info *si = find_socket_info(fd); struct socket_info_fd *fi; if (si != NULL) { for (fi = si->fds; fi; fi = fi->next) { if (fi->fd == fd) { SWRAP_LOG(SWRAP_LOG_TRACE, "remove stale wrapper for %d", fd); SWRAP_DLIST_REMOVE(si->fds, fi); free(fi); break; } } if (si->fds == NULL) { SWRAP_DLIST_REMOVE(sockets, si); if (si->un_addr.sun_path[0] != '\0') { unlink(si->un_addr.sun_path); } free(si); } } } static int sockaddr_convert_to_un(struct socket_info *si, const struct sockaddr *in_addr, socklen_t in_len, struct sockaddr_un *out_addr, int alloc_sock, int *bcast) { 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; uint8_t *buf; struct swrap_packet_frame *frame; union swrap_packet_ip *ip; union swrap_packet_payload *pay; size_t packet_len; size_t alloc_len; size_t nonwire_len = sizeof(*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(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(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_hdr_len += icmp_hdr_len; 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 *)malloc(alloc_len); if (base == NULL) { return NULL; } memset(base, 0x0, alloc_len); buf = base; frame = (struct swrap_packet_frame *)(void *)buf; frame->seconds = tval->tv_sec; frame->micro_seconds = tval->tv_usec; frame->recorded_length = wire_len - icmp_truncate_len; frame->full_length = wire_len - icmp_truncate_len; buf += SWRAP_PACKET_FRAME_SIZE; ip = (union swrap_packet_ip *)(void *)buf; switch (src->sa_family) { case AF_INET: ip->v4.ver_hdrlen = 0x45; /* version 4 and 5 * 32 bit words */ ip->v4.tos = 0x00; ip->v4.packet_length = htons(wire_len - icmp_truncate_len); ip->v4.identification = htons(0xFFFF); ip->v4.flags = 0x40; /* BIT 1 set - means don't fragment */ ip->v4.fragment = htons(0x0000); ip->v4.ttl = 0xFF; ip->v4.protocol = protocol; ip->v4.hdr_checksum = htons(0x0000); ip->v4.src_addr = src_in->sin_addr.s_addr; ip->v4.dest_addr = dest_in->sin_addr.s_addr; buf += SWRAP_PACKET_IP_V4_SIZE; break; #ifdef HAVE_IPV6 case AF_INET6: ip->v6.ver_prio = 0x60; /* version 4 and 5 * 32 bit words */ ip->v6.flow_label_high = 0x00; ip->v6.flow_label_low = 0x0000; ip->v6.payload_length = htons(wire_len - icmp_truncate_len); /* TODO */ ip->v6.next_header = protocol; memcpy(ip->v6.src_addr, src_in6->sin6_addr.s6_addr, 16); memcpy(ip->v6.dest_addr, dest_in6->sin6_addr.s6_addr, 16); 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 */ ip = (union swrap_packet_ip *)(void *)buf; ip->v4.ver_hdrlen = 0x45; /* version 4 and 5 * 32 bit words */ ip->v4.tos = 0x00; ip->v4.packet_length = htons(wire_len - icmp_hdr_len); ip->v4.identification = htons(0xFFFF); ip->v4.flags = 0x40; /* BIT 1 set - means don't fragment */ ip->v4.fragment = htons(0x0000); ip->v4.ttl = 0xFF; ip->v4.protocol = icmp_protocol; ip->v4.hdr_checksum = htons(0x0000); ip->v4.src_addr = dest_in->sin_addr.s_addr; ip->v4.dest_addr = src_in->sin_addr.s_addr; 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 */ ip = (union swrap_packet_ip *)(void *)buf; ip->v6.ver_prio = 0x60; /* version 4 and 5 * 32 bit words */ ip->v6.flow_label_high = 0x00; ip->v6.flow_label_low = 0x0000; ip->v6.payload_length = htons(wire_len - icmp_truncate_len); /* TODO */ ip->v6.next_header = protocol; memcpy(ip->v6.src_addr, dest_in6->sin6_addr.s6_addr, 16); memcpy(ip->v6.dest_addr, src_in6->sin6_addr.s6_addr, 16); 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; file_name = swrap_pcap_init_file(); if (!file_name) { return; } packet = swrap_pcap_marshall_packet(si, addr, type, buf, len, &packet_len); if (packet == NULL) { return; } fd = swrap_pcap_get_fd(file_name); if (fd != -1) { if (write(fd, packet, packet_len) != (ssize_t)packet_len) { free(packet); return; } } free(packet); } /**************************************************************************** * SIGNALFD ***************************************************************************/ #ifdef HAVE_SIGNALFD static int swrap_signalfd(int fd, const sigset_t *mask, int flags) { int rc; rc = libc_signalfd(fd, mask, flags); if (rc != -1) { swrap_remove_stale(fd); } return rc; } int signalfd(int fd, const sigset_t *mask, int flags) { return swrap_signalfd(fd, mask, flags); } #endif /**************************************************************************** * SOCKET ***************************************************************************/ static int swrap_socket(int family, int type, int protocol) { struct socket_info *si; struct socket_info_fd *fi; int fd; 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; 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 */ si = find_socket_info(fd); if (si != NULL) { swrap_remove_stale(fd); } si = (struct socket_info *)malloc(sizeof(struct socket_info)); memset(si, 0, sizeof(struct socket_info)); if (si == NULL) { errno = ENOMEM; return -1; } 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; } 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; } default: free(si); errno = EINVAL; return -1; } fi = (struct socket_info_fd *)calloc(1, sizeof(struct socket_info_fd)); if (fi == NULL) { free(si); errno = ENOMEM; return -1; } fi->fd = fd; SWRAP_DLIST_ADD(si->fds, fi); SWRAP_DLIST_ADD(sockets, si); SWRAP_LOG(SWRAP_LOG_TRACE, "Created %s socket for protocol %s", si->family == AF_INET ? "IPv4" : "IPv6", si->type == SOCK_DGRAM ? "UDP" : "TCP"); 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) { struct socket_info *parent_si, *child_si; struct socket_info_fd *child_fi; int fd; 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) { return libc_accept(s, addr, addrlen); } /* * 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) { errno = EINVAL; return -1; } ret = libc_accept(s, &un_addr.sa.s, &un_addr.sa_socklen); if (ret == -1) { if (errno == ENOTSOCK) { /* Remove stale fds */ swrap_remove_stale(s); } return ret; } fd = ret; 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) { close(fd); return ret; } child_si = (struct socket_info *)malloc(sizeof(struct socket_info)); memset(child_si, 0, sizeof(struct socket_info)); child_fi = (struct socket_info_fd *)calloc(1, sizeof(struct socket_info_fd)); if (child_fi == NULL) { free(child_si); close(fd); errno = ENOMEM; return -1; } child_fi->fd = fd; SWRAP_DLIST_ADD(child_si->fds, child_fi); 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; 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) { free(child_fi); free(child_si); 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) { free(child_fi); free(child_si); 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); SWRAP_DLIST_ADD(sockets, child_si); if (addr != NULL) { swrap_pcap_dump_packet(child_si, addr, SWRAP_ACCEPT_SEND, NULL, 0); swrap_pcap_dump_packet(child_si, addr, SWRAP_ACCEPT_RECV, NULL, 0); swrap_pcap_dump_packet(child_si, addr, SWRAP_ACCEPT_ACK, NULL, 0); } return fd; } #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); } 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; 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; return -1; } memset(&in, 0, sizeof(in)); in.sin_family = AF_INET; in.sin_addr.s_addr = htonl(127<<24 | socket_wrapper_default_iface()); si->myname = (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; return -1; } 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; return -1; } 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; return -1; } if (autobind_start > 60000) { autobind_start = 10000; } for (i = 0; i < SOCKET_MAX_SOCKETS; i++) { port = autobind_start + i; snprintf(un_addr.sa.un.sun_path, sizeof(un_addr.sa.un.sun_path), "%s/"SOCKET_FORMAT, socket_wrapper_dir(), type, socket_wrapper_default_iface(), port); if (stat(un_addr.sa.un.sun_path, &st) == 0) continue; ret = libc_bind(fd, &un_addr.sa.s, un_addr.sa_socklen); if (ret == -1) return ret; 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; return -1; } si->family = family; set_port(si->family, port, &si->myname); return 0; } /**************************************************************************** * 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); } if (si->bound == 0) { ret = swrap_auto_bind(s, si, serv_addr->sa_family); if (ret == -1) return -1; } if (si->family != serv_addr->sa_family) { errno = EINVAL; return -1; } ret = sockaddr_convert_to_un(si, serv_addr, addrlen, &un_addr.sa.un, 0, &bcast); if (ret == -1) return -1; if (bcast) { errno = ENETUNREACH; return -1; } 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); } 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); } 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; return -1; } #if 0 /* FIXME */ in_use = check_addr_port_in_use(myaddr, addrlen); if (in_use) { errno = EADDRINUSE; return -1; } #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) return -1; 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; } 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); } ret = libc_listen(s, backlog); 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); } /**************************************************************************** * 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; } /**************************************************************************** * GETPEERNAME ***************************************************************************/ static int swrap_getpeername(int s, struct sockaddr *name, socklen_t *addrlen) { struct socket_info *si = find_socket_info(s); socklen_t len; if (!si) { return libc_getpeername(s, name, addrlen); } if (si->peername.sa_socklen == 0) { errno = ENOTCONN; return -1; } len = MIN(*addrlen, si->peername.sa_socklen); if (len == 0) { return 0; } memcpy(name, &si->peername.sa.ss, len); *addrlen = si->peername.sa_socklen; return 0; } #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; if (!si) { return libc_getsockname(s, name, addrlen); } len = MIN(*addrlen, si->myname.sa_socklen); if (len == 0) { return 0; } memcpy(name, &si->myname.sa.ss, len); *addrlen = si->myname.sa_socklen; return 0; } #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); if (!si) { return libc_getsockopt(s, level, optname, optval, optlen); } if (level == SOL_SOCKET) { switch (optname) { #ifdef SO_DOMAIN case SO_DOMAIN: if (optval == NULL || optlen == NULL || *optlen < (socklen_t)sizeof(int)) { errno = EINVAL; return -1; } *optlen = sizeof(int); *(int *)optval = si->family; return 0; #endif /* SO_DOMAIN */ #ifdef SO_PROTOCOL case SO_PROTOCOL: if (optval == NULL || optlen == NULL || *optlen < (socklen_t)sizeof(int)) { errno = EINVAL; return -1; } *optlen = sizeof(int); *(int *)optval = si->protocol; return 0; #endif /* SO_PROTOCOL */ case SO_TYPE: if (optval == NULL || optlen == NULL || *optlen < (socklen_t)sizeof(int)) { errno = EINVAL; return -1; } *optlen = sizeof(int); *(int *)optval = si->type; return 0; default: return libc_getsockopt(s, level, optname, optval, optlen); } } 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; return -1; } *optlen = sizeof(int); *(int *)optval = si->tcp_nodelay; return 0; #endif /* TCP_NODELAY */ default: break; } } errno = ENOPROTOOPT; return -1; } #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); if (!si) { return libc_setsockopt(s, level, optname, optval, optlen); } if (level == SOL_SOCKET) { return libc_setsockopt(s, level, optname, optval, optlen); } else 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; return -1; } i = *discard_const_p(int, optval); if (i != 0 && i != 1) { errno = EINVAL; return -1; } si->tcp_nodelay = i; return 0; } #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 */ } return 0; #ifdef HAVE_IPV6 case AF_INET6: if (level == IPPROTO_IPV6) { #ifdef IPV6_RECVPKTINFO if (optname == IPV6_RECVPKTINFO) { si->pktinfo = AF_INET6; } #endif /* IPV6_PKTINFO */ } return 0; #endif default: errno = ENOPROTOOPT; return -1; } } 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); } 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); 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; if (to_un) { *to_un = NULL; } if (to) { *to = NULL; } if (bcast) { *bcast = 0; } switch (si->type) { case SOCK_STREAM: { unsigned long mtu; if (!si->connected) { errno = ENOTCONN; return -1; } 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(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) { errno = EISCONN; return -1; } } else { const struct sockaddr *msg_name; msg_name = (const struct sockaddr *)msg->msg_name; if (msg_name == NULL) { errno = ENOTCONN; return -1; } ret = sockaddr_convert_to_un(si, msg_name, msg->msg_namelen, tmp_un, 0, bcast); if (ret == -1) return -1; if (to_un) { *to_un = tmp_un; } if (to) { *to = msg_name; } msg->msg_name = tmp_un; msg->msg_namelen = sizeof(*tmp_un); } if (si->bound == 0) { ret = swrap_auto_bind(fd, si, si->family); if (ret == -1) { if (errno == ENOTSOCK) { swrap_remove_stale(fd); return -ENOTSOCK; } else { SWRAP_LOG(SWRAP_LOG_ERROR, "swrap_sendmsg_before failed"); return -1; } } } 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) return -1; 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) { return ret; } si->defer_connect = 0; break; default: errno = EHOSTUNREACH; return -1; } #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); return -1; } 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 return 0; } 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; 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; } free(buf); errno = saved_errno; } static int swrap_recvmsg_before(int fd, struct socket_info *si, struct msghdr *msg, struct iovec *tmp_iov) { size_t i, len = 0; ssize_t ret; (void)fd; /* unused */ switch (si->type) { case SOCK_STREAM: { unsigned int mtu; if (!si->connected) { errno = ENOTCONN; return -1; } 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(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; return -1; } if (msg->msg_iovlen == 0) { break; } if (si->bound == 0) { ret = swrap_auto_bind(fd, si, si->family); if (ret == -1) { /* * When attempting to read or write to a * descriptor, if an underlying autobind fails * because it's not a socket, stop intercepting * uses of that descriptor. */ if (errno == ENOTSOCK) { swrap_remove_stale(fd); return -ENOTSOCK; } else { SWRAP_LOG(SWRAP_LOG_ERROR, "swrap_recvmsg_before failed"); return -1; } } } break; default: errno = EHOSTUNREACH; return -1; } return 0; } static int swrap_recvmsg_after(int fd, struct socket_info *si, struct msghdr *msg, const struct sockaddr_un *un_addr, socklen_t un_addrlen, ssize_t ret) { int saved_errno = errno; size_t i; 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; } /* 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 */ 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) { return -1; } } #endif 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 */ #if 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; type = SOCKET_TYPE_CHAR_UDP; for(iface=0; iface <= MAX_WRAPPED_INTERFACES; iface++) { snprintf(un_addr.sa.un.sun_path, sizeof(un_addr.sa.un.sun_path), "%s/"SOCKET_FORMAT, socket_wrapper_dir(), type, iface, prt); 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); } swrap_pcap_dump_packet(si, to, SWRAP_SENDTO, buf, len); return len; } ret = libc_sendto(s, buf, len, flags, (struct sockaddr *)msg.msg_name, msg.msg_namelen); 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); } /**************************************************************************** * 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 */ #if 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 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 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; /* * 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; } 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); 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 */ #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; 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; for(iface=0; iface <= MAX_WRAPPED_INTERFACES; iface++) { snprintf(un_addr.sun_path, sizeof(un_addr.sun_path), "%s/"SOCKET_FORMAT, socket_wrapper_dir(), type, iface, prt); if (stat(un_addr.sun_path, &st) != 0) continue; msg.msg_name = &un_addr; /* optional address */ msg.msg_namelen = sizeof(un_addr); /* size of address */ /* ignore the any errors in broadcast sends */ libc_sendmsg(s, &msg, flags); } swrap_pcap_dump_packet(si, to, SWRAP_SENDTO, buf, len); free(buf); 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 */ #if 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 = find_socket_info(fd); struct socket_info_fd *fi; int ret; if (!si) { return libc_close(fd); } for (fi = si->fds; fi; fi = fi->next) { if (fi->fd == fd) { SWRAP_DLIST_REMOVE(si->fds, fi); free(fi); break; } } if (si->fds) { /* there are still references left */ return libc_close(fd); } SWRAP_DLIST_REMOVE(sockets, si); if (si->myname.sa_socklen > 0 && si->peername.sa_socklen > 0) { swrap_pcap_dump_packet(si, NULL, SWRAP_CLOSE_SEND, NULL, 0); } ret = libc_close(fd); 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); } free(si); return ret; } int close(int fd) { return swrap_close(fd); } /**************************** * DUP ***************************/ static int swrap_dup(int fd) { struct socket_info *si; struct socket_info_fd *fi; si = find_socket_info(fd); if (!si) { return libc_dup(fd); } fi = (struct socket_info_fd *)calloc(1, sizeof(struct socket_info_fd)); if (fi == NULL) { errno = ENOMEM; return -1; } fi->fd = libc_dup(fd); if (fi->fd == -1) { int saved_errno = errno; free(fi); errno = saved_errno; return -1; } /* Make sure we don't have an entry for the fd */ swrap_remove_stale(fi->fd); SWRAP_DLIST_ADD(si->fds, fi); return fi->fd; } int dup(int fd) { return swrap_dup(fd); } /**************************** * DUP2 ***************************/ static int swrap_dup2(int fd, int newfd) { struct socket_info *si; struct socket_info_fd *fi; si = find_socket_info(fd); if (!si) { return libc_dup2(fd, newfd); } if (find_socket_info(newfd)) { /* dup2() does an implicit close of newfd, which we * need to emulate */ swrap_close(newfd); } fi = (struct socket_info_fd *)calloc(1, sizeof(struct socket_info_fd)); if (fi == NULL) { errno = ENOMEM; return -1; } fi->fd = libc_dup2(fd, newfd); if (fi->fd == -1) { int saved_errno = errno; free(fi); errno = saved_errno; return -1; } /* Make sure we don't have an entry for the fd */ swrap_remove_stale(fi->fd); SWRAP_DLIST_ADD(si->fds, fi); return fi->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_fd *fi; struct socket_info *si; int rc; si = find_socket_info(fd); if (si == NULL) { rc = libc_vfcntl(fd, cmd, va); return rc; } switch (cmd) { case F_DUPFD: fi = (struct socket_info_fd *)calloc(1, sizeof(struct socket_info_fd)); if (fi == NULL) { errno = ENOMEM; return -1; } fi->fd = libc_vfcntl(fd, cmd, va); if (fi->fd == -1) { int saved_errno = errno; free(fi); errno = saved_errno; return -1; } /* Make sure we don't have an entry for the fd */ swrap_remove_stale(fi->fd); SWRAP_DLIST_ADD(si->fds, fi); rc = fi->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 /**************************** * DESTRUCTOR ***************************/ /* * This function is called when the library is unloaded and makes sure that * sockets get closed and the unix file for the socket are unlinked. */ void swrap_destructor(void) { struct socket_info *s = sockets; while (s != NULL) { struct socket_info_fd *f = s->fds; if (f != NULL) { swrap_close(f->fd); } s = sockets; } if (swrap.libc_handle != NULL) { dlclose(swrap.libc_handle); } if (swrap.libsocket_handle) { dlclose(swrap.libsocket_handle); } } socket_wrapper-1.1.5/tests/README000644 001750 000144 00000000476 12323217475 016565 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.1.5/tests/torture.h000644 001750 000144 00000005262 12413157202 017547 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.1.5/tests/echo_srv.c000644 001750 000144 00000052552 12503754156 017665 0ustar00asnusers000000 000000 #include "config.h" #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 5 #ifndef BUFSIZE #define BUFSIZE 0x400000 #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; } case AF_INET6: { const char *ip6 = getenv("TORTURE_SERVER_ADDRESS_IPV6"); if (ip6 != NULL && ip6[0] != '\0') { return ip6; } return ECHO_SRV_IPV6; } 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 (fd = getdtablesize(); fd >= 0; --fd) { close(fd); } for (i = 0; i < 3; 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; } 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; } 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; } 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; } 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; s = accept(sock, &addr.sa.s, &addr.sa_socklen); if (s == -1) { perror("accept"); goto done; } client_sock = socket_dup(s); if (client_sock == -1) { perror("socket_dup"); goto done; } /* Start ping pong */ 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; } } 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 sockaddr *from, socklen_t *fromlen, struct sockaddr *to, socklen_t *tolen) { 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]; #else (void)to; /* unused */ (void)tolen; /* unused */ #endif /* HAVE_STRUCT_MSGHDR_MSG_CONTROL */ riov.iov_base = buf; riov.iov_len = buflen; ZERO_STRUCT(rmsg); rmsg.msg_name = from; rmsg.msg_namelen = *fromlen; 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; } *fromlen = 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 sockaddr_in *sinp = (struct sockaddr_in *)to; struct in_pktinfo *pkt; void *cmsg_cast_ptr = CMSG_DATA(cmsgptr); pkt = (struct in_pktinfo *)cmsg_cast_ptr; sinp->sin_family = AF_INET; sinp->sin_addr = pkt->ipi_addr; *tolen = sizeof(struct sockaddr_in); p = inet_ntop(AF_INET, &sinp->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 sockaddr_in *sinp = (struct sockaddr_in *)(void *)to; struct in_addr *addr; void *cmsg_cast_ptr = CMSG_DATA(cmsgptr); addr = (struct in_addr *)cmsg_cast_ptr; sinp->sin_family = AF_INET; sinp->sin_addr = *addr; *tolen = sizeof(struct sockaddr_in); p = inet_ntop(AF_INET, &sinp->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; struct sockaddr_in6 *sin6p = (struct sockaddr_in6 *)(void *)to; void *cmsg_cast_ptr = CMSG_DATA(cmsgptr); pkt6 = (struct in6_pktinfo *)cmsg_cast_ptr; sin6p->sin6_family = AF_INET6; sin6p->sin6_addr = pkt6->ipi6_addr; p = inet_ntop(AF_INET6, &sin6p->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.sa.s, &saddr.sa_socklen, &daddr.sa.s, &daddr.sa_socklen); 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 deamon 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) { unlink(opts.pidfile); } ret = 0; done: return ret; } socket_wrapper-1.1.5/tests/torture.c000644 001750 000144 00000015424 12602753040 017545 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/test_socket_wrapper_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 > 100) { break; } rc = stat(s->srv_pidfile, &sb); usleep(200); } 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(200); 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.1.5/tests/CMakeLists.txt000644 001750 000144 00000002703 12607421211 020426 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_link_libraries(echo_srv ${SWRAP_REQUIRED_LIBRARIES}) add_library(${TORTURE_LIBRARY} STATIC torture.c) target_link_libraries(${TORTURE_LIBRARY} ${CMOCKA_LIBRARY} ${SWRAP_REQUIRED_LIBRARIES}) set(SWRAP_TESTS test_ioctl test_echo_tcp_socket 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) if (HAVE_STRUCT_MSGHDR_MSG_CONTROL) set(SWRAP_TESTS ${SWRAP_TESTS} test_sendmsg_recvmsg_fd) endif (HAVE_STRUCT_MSGHDR_MSG_CONTROL) foreach(_SWRAP_TEST ${SWRAP_TESTS}) add_cmocka_test(${_SWRAP_TEST} ${_SWRAP_TEST}.c ${TORTURE_LIBRARY}) if (OSX) set_property( TEST ${_SWRAP_TEST} PROPERTY ENVIRONMENT DYLD_FORCE_FLAT_NAMESPACE=1;DYLD_INSERT_LIBRARIES=${SOCKET_WRAPPER_LOCATION}) else () set_property( TEST ${_SWRAP_TEST} PROPERTY ENVIRONMENT LD_PRELOAD=${SOCKET_WRAPPER_LOCATION}) endif() endforeach() socket_wrapper-1.1.5/tests/test_echo_tcp_bind.c000644 001750 000144 00000027372 12607421211 021662 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; } static int setup_echo_srv_tcp_ipv6(void **state) { torture_setup_echo_srv_tcp_ipv6(state); return 0; } 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_un), .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_un), .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.in, 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.1.5/tests/test_echo_tcp_connect.c000644 001750 000144 00000003736 12607421211 022375 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.1.5/tests/test_echo_tcp_get_peer_sock_name.c000644 001750 000144 00000030070 12607421211 024544 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) { char ip[INET6_ADDRSTRLEN] = { 0 }; const char *p; 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)); _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; case AF_INET6: n_port = addr->sa.in6.sin6_port; break; 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; case AF_INET6: n_port = addr->sa.in6.sin6_port; break; 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.1.5/tests/test_echo_tcp_sendmsg_recvmsg.c000644 001750 000144 00000012646 12607421211 024132 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); 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); 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); /* 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.1.5/tests/test_echo_tcp_socket.c000644 001750 000144 00000002557 12607421211 022234 0ustar00asnusers000000 000000 #include #include #include #include #include "config.h" #include "torture.h" #include #include #include #include #include #include #include #include static void test_socket_getsockname(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); rc = getsockname(s, &addr.sa.s, &addr.sa_socklen); assert_return_code(rc, errno); assert_int_equal(addr.sa.in.sin_family, AF_INET); } #ifdef HAVE_IPV6 static void test_socket_getsockname6(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); rc = getsockname(s, &addr.sa.s, &addr.sa_socklen); assert_return_code(rc, errno); assert_int_equal(addr.sa.in6.sin6_family, AF_INET6); } #endif int main(void) { int rc; const struct CMUnitTest getsockname_tests[] = { cmocka_unit_test(test_socket_getsockname), #ifdef HAVE_IPV6 cmocka_unit_test(test_socket_getsockname6), #endif }; rc = cmocka_run_group_tests(getsockname_tests, NULL, NULL); return rc; } socket_wrapper-1.1.5/tests/test_echo_tcp_socket_options.c000644 001750 000144 00000017100 12607421211 023775 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.1.5/tests/test_echo_tcp_write_read.c000644 001750 000144 00000005662 12607421211 023071 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.1.5/tests/test_echo_tcp_writev_readv.c000644 001750 000144 00000007355 12607421211 023446 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.1.5/tests/test_echo_udp_send_recv.c000644 001750 000144 00000005662 12607421211 022716 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.1.5/tests/test_echo_udp_sendmsg_recvmsg.c000644 001750 000144 00000020775 12607421211 024136 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); 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); /* 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); /* 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.1.5/tests/test_echo_udp_sendto_recvfrom.c000644 001750 000144 00000010256 12607421211 024140 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_int_not_equal(ret, -1); ret = recvfrom(s, recv_buf, sizeof(recv_buf), 0, &srv_in.sa.s, &srv_in.sa_socklen); assert_int_not_equal(ret, -1); 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_int_not_equal(ret, -1); ret = recvfrom(s, recv_buf, sizeof(recv_buf), 0, NULL, NULL); assert_int_not_equal(ret, -1); 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_int_not_equal(ret, -1); ret = recvfrom(s, recv_buf, sizeof(recv_buf), 0, &srv_in6.sa.s, &srv_in6.sa_socklen); assert_int_not_equal(ret, -1); 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_int_not_equal(ret, -1); ret = recvfrom(s, recv_buf, sizeof(recv_buf), 0, NULL, NULL); assert_int_not_equal(ret, -1); close(s); } #endif 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 }; rc = cmocka_run_group_tests(sendto_tests, NULL, NULL); return rc; } socket_wrapper-1.1.5/tests/test_ioctl.c000644 001750 000144 00000003714 12607421211 020206 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.1.5/tests/test_sendmsg_recvmsg_fd.c000644 001750 000144 00000004664 12607421211 022740 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.1.5/tests/test_swrap_unit.c000644 001750 000144 00000005245 12607421211 021270 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.1.5/.clang_complete000644 001750 000144 00000000022 12267261735 017510 0ustar00asnusers000000 000000 -Iobj -DHAVE_IPV6 socket_wrapper-1.1.5/socket_wrapper-config-version.cmake.in000644 001750 000144 00000000611 12267760757 024134 0ustar00asnusers000000 000000 set(PACKAGE_VERSION @APPLICATION_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.1.5/socket_wrapper.pc.cmake000644 001750 000144 00000000215 12331636450 021162 0ustar00asnusers000000 000000 Name: @APPLICATION_NAME@ Description: The socket_wrapper library Version: @APPLICATION_VERSION@ Libs: @LIB_INSTALL_DIR@/@SOCKET_WRAPPER_LIB@ socket_wrapper-1.1.5/CPackConfig.cmake000644 001750 000144 00000003765 12341034705 017651 0ustar00asnusers000000 000000 # For help take a look at: # http://www.cmake.org/Wiki/CMake:CPackConfiguration ### general settings set(CPACK_PACKAGE_NAME ${APPLICATION_NAME}) set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "The SSH library") set(CPACK_PACKAGE_DESCRIPTION_FILE "${CMAKE_SOURCE_DIR}/README") 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}/COPYING") ### versions set(CPACK_PACKAGE_VERSION_MAJOR "${APPLICATION_VERSION_MAJOR}") set(CPACK_PACKAGE_VERSION_MINOR "${APPLICATION_VERSION_MINOR}") set(CPACK_PACKAGE_VERSION_PATCH "${APPLICATION_VERSION_PATCH}") set(CPACK_PACKAGE_VERSION "${CPACK_PACKAGE_VERSION_MAJOR}.${CPACK_PACKAGE_VERSION_MINOR}.${CPACK_PACKAGE_VERSION_PATCH}") ### 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 ${APPLICATION_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_APPLICATIONS_GROUP "Runtime") set(CPACK_COMPONENT_LIBRARIES_GROUP "Development") set(CPACK_COMPONENT_HEADERS_GROUP "Development") include(CPack) socket_wrapper-1.1.5/socket_wrapper-config.cmake.in000644 001750 000144 00000000103 12343343221 022417 0ustar00asnusers000000 000000 set(SOCKET_WRAPPER_LIBRARY @LIB_INSTALL_DIR@/@SOCKET_WRAPPER_LIB@) socket_wrapper-1.1.5/README000644 001750 000144 00000000760 12377353715 015426 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.1.5/README.install000644 001750 000144 00000003600 12377353715 017067 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.1.5/doc/CMakeLists.txt000644 001750 000144 00000000144 12377353715 020047 0ustar00asnusers000000 000000 install(FILES socket_wrapper.1 DESTINATION ${MAN_INSTALL_DIR}/man1) socket_wrapper-1.1.5/doc/README000644 001750 000144 00000000204 12377353715 016164 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.1.5/doc/socket_wrapper.1000644 001750 000144 00000012576 12607421211 020414 0ustar00asnusers000000 000000 '\" t .\" Title: socket_wrapper .\" Author: [FIXME: author] [see http://docbook.sf.net/el/author] .\" Generator: DocBook XSL Stylesheets v1.78.1 .\" Date: 2015-08-11 .\" Manual: \ \& .\" Source: \ \& .\" Language: English .\" .TH "SOCKET_WRAPPER" "1" "2015\-08\-11" "\ \&" "\ \&" .\" ----------------------------------------------------------------- .\" * 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 .\} Ablility 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 envionment 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_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 .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 .\} socket_wrapper-1.1.5/doc/socket_wrapper.1.txt000644 001750 000144 00000006511 12607421211 021222 0ustar00asnusers000000 000000 socket_wrapper(1) ================= :revdate: 2015-08-11 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. - Ablility 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 envionment 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_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 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.1.5/ConfigureChecks.cmake000644 001750 000144 00000014537 12503754156 020614 0ustar00asnusers000000 000000 include(CheckIncludeFile) include(CheckSymbolExists) include(CheckFunctionExists) include(CheckLibraryExists) include(CheckTypeSize) include(CheckStructHasMember) include(CheckPrototypeDefinition) include(TestBigEndian) set(PACKAGE ${APPLICATION_NAME}) set(VERSION ${APPLICATION_VERSION}) set(DATADIR ${DATA_INSTALL_DIR}) set(LIBDIR ${LIB_INSTALL_DIR}) set(PLUGINDIR "${PLUGIN_INSTALL_DIR}-${LIBRARY_SOVERSION}") set(SYSCONFDIR ${SYSCONF_INSTALL_DIR}) 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) set(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) # 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) if (UNIX) if (NOT LINUX) # libsocket (Solaris) check_library_exists(socket getaddrinfo "" HAVE_LIBSOCKET) if (HAVE_LIBSOCKET) set(CMAKE_REQUIRED_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES} socket) endif (HAVE_LIBSOCKET) # libnsl/inet_pton (Solaris) check_library_exists(nsl inet_pton "" HAVE_LIBNSL) if (HAVE_LIBNSL) set(CMAKE_REQUIRED_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES} nsl) endif (HAVE_LIBNSL) endif (NOT LINUX) check_function_exists(getaddrinfo HAVE_GETADDRINFO) endif (UNIX) set(SWRAP_REQUIRED_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES} CACHE INTERNAL "socket_wrapper required system libraries") # 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) set(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) 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(" __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) # If this produces a warning treat it as error! set(CMAKE_REQUIRED_FLAGS "-Werror") 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) set(CMAKE_REQUIRED_FLAGS) check_library_exists(dl dlopen "" HAVE_LIBDL) if (HAVE_LIBDL) find_library(DLFCN_LIBRARY dl) set(CMAKE_REQUIRED_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES} ${DLFCN_LIBRARY}) endif (HAVE_LIBDL) 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 ${CMAKE_REQUIRED_LIBRARIES} CACHE INTERNAL "swrap required system libraries") socket_wrapper-1.1.5/config.h.cmake000644 001750 000144 00000004321 12503754156 017233 0ustar00asnusers000000 000000 /* Name of package */ #cmakedefine PACKAGE "${APPLICATION_NAME}" /* Version number of package */ #cmakedefine VERSION "${APPLICATION_VERSION}" #cmakedefine LOCALEDIR "${LOCALE_INSTALL_DIR}" #cmakedefine DATADIR "${DATADIR}" #cmakedefine LIBDIR "${LIBDIR}" #cmakedefine PLUGINDIR "${PLUGINDIR}" #cmakedefine SYSCONFDIR "${SYSCONFDIR}" #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 /*************************** 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_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_DESTRUCTOR_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.1.5/CTestConfig.cmake000644 001750 000144 00000000426 12560407341 017704 0ustar00asnusers000000 000000 set(UPDATE_TYPE "true") set(CTEST_PROJECT_NAME "socketwrapper") set(CTEST_NIGHTLY_START_TIME "01:00:00 UTC") set(CTEST_DROP_METHOD "https") set(CTEST_DROP_SITE "mock.cryptomilk.org") set(CTEST_DROP_LOCATION "/submit.php?project=socketwrapper") set(CTEST_DROP_SITE_CDASH TRUE) socket_wrapper-1.1.5/TODO000644 001750 000144 00000002063 12607421211 015213 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: * Thread safety * 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(). * Add threaded tests. socket_wrapper-1.1.5/CMakeLists.txt000644 001750 000144 00000005057 12607653567 017316 0ustar00asnusers000000 000000 project(socket_wrapper C) # Required cmake version cmake_minimum_required(VERSION 2.8.5) # global needed variables set(APPLICATION_NAME ${PROJECT_NAME}) set(APPLICATION_VERSION_MAJOR "1") set(APPLICATION_VERSION_MINOR "1") set(APPLICATION_VERSION_PATCH "5") set(APPLICATION_VERSION "${APPLICATION_VERSION_MAJOR}.${APPLICATION_VERSION_MINOR}.${APPLICATION_VERSION_PATCH}") # 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.5") set(LIBRARY_SOVERSION "0") # where to look first for cmake modules, before ${CMAKE_ROOT}/Modules/ is checked set(CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake/Modules ) # add definitions include(DefineCMakeDefaults) include(DefinePlatformDefaults) include(DefineCompilerFlags) include(DefineInstallationPaths) include(DefineOptions.cmake) include(CPackConfig.cmake) # 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 0.4.1 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 ${LIB_INSTALL_DIR}/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_DIR}/socket_wrapper COMPONENT devel ) add_subdirectory(doc) socket_wrapper-1.1.5/ChangeLog000644 001750 000144 00000003020 12607661375 016310 0ustar00asnusers000000 000000 ChangeLog ========== 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