socket_wrapper-1.4.4/CPackConfig.cmake000644 001750 000144 00000003440 14744201025 017641 0ustar00asnusers000000 000000 # For help take a look at: # http://www.cmake.org/Wiki/CMake:CPackConfiguration ### general settings set(CPACK_PACKAGE_NAME ${PROJECT_NAME}) set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "The SSH library") set(CPACK_PACKAGE_DESCRIPTION_FILE "${CMAKE_SOURCE_DIR}/README.md") set(CPACK_PACKAGE_VENDOR "The SSH Library Development Team") set(CPACK_PACKAGE_INSTALL_DIRECTORY ${CPACK_PACKAGE_NAME}) set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_SOURCE_DIR}/LICENSE") ### versions set(CPACK_PACKAGE_VERSION "${PROJECT_VERSION}") ### source generator set(CPACK_SOURCE_GENERATOR "TGZ") set(CPACK_SOURCE_IGNORE_FILES "~$;[.]swp$;/[.]bare/;/[.]git/;/[.]clangd/;/[.]cache/;.gitignore;/build*;/obj*;tags;cscope.*;compile_commands.json;.*\.patch") set(CPACK_SOURCE_PACKAGE_FILE_NAME "${CPACK_PACKAGE_NAME}-${CPACK_PACKAGE_VERSION}") if (WIN32) set(CPACK_GENERATOR "ZIP") ### nsis generator find_package(NSIS) if (NSIS_MAKE) set(CPACK_GENERATOR "${CPACK_GENERATOR};NSIS") set(CPACK_NSIS_DISPLAY_NAME "The SSH Library") set(CPACK_NSIS_COMPRESSOR "/SOLID zlib") set(CPACK_NSIS_MENU_LINKS "http://www.libssh.org/" "libssh homepage") endif (NSIS_MAKE) endif (WIN32) set(CPACK_PACKAGE_INSTALL_DIRECTORY "libssh") set(CPACK_PACKAGE_FILE_NAME ${CPACK_PACKAGE_NAME}-${CPACK_PACKAGE_VERSION}) set(CPACK_COMPONENT_LIBRARIES_DISPLAY_NAME "Libraries") set(CPACK_COMPONENT_HEADERS_DISPLAY_NAME "C/C++ Headers") set(CPACK_COMPONENT_LIBRARIES_DESCRIPTION "Libraries used to build programs which use libssh") set(CPACK_COMPONENT_HEADERS_DESCRIPTION "C/C++ header files for use with libssh") set(CPACK_COMPONENT_HEADERS_DEPENDS libraries) #set(CPACK_COMPONENT_PROJECTS_GROUP "Runtime") set(CPACK_COMPONENT_LIBRARIES_GROUP "Development") set(CPACK_COMPONENT_HEADERS_GROUP "Development") include(CPack) socket_wrapper-1.4.4/CMakeLists.txt000644 001750 000144 00000006315 14744201025 017274 0ustar00asnusers000000 000000 # Required cmake version cmake_minimum_required(VERSION 3.10.0) cmake_policy(SET CMP0048 NEW) # Specify search path for CMake modules to be loaded by include() # and find_package() list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake/Modules") # Add defaults for cmake # Those need to be set before the project() call. include(DefineCMakeDefaults) include(DefineCompilerFlags) project(socket_wrapper VERSION 1.4.4 LANGUAGES C) # global needed variables set(APPLICATION_NAME ${PROJECT_NAME}) # SOVERSION scheme: MAJOR.MINOR.PATCH # If there was an incompatible interface change: # Increment MAJOR. Set MINOR and PATCH to 0 # If there was a compatible interface change: # Increment MINOR. Set PATCH to 0 # If the source code was changed, but there were no interface changes: # Increment PATCH. set(LIBRARY_VERSION_MAJOR 0) set(LIBRARY_VERSION_MINOR 4) set(LIBRARY_VERSION_PATCH 2) set(LIBRARY_VERSION "${LIBRARY_VERSION_MAJOR}.${LIBRARY_VERSION_MINOR}.${LIBRARY_VERSION_PATCH}") set(LIBRARY_SOVERSION ${LIBRARY_VERSION_MAJOR}) set(NOOP_LIBRARY_VERSION_MAJOR 0) set(NOOP_LIBRARY_VERSION_MINOR 0) set(NOOP_LIBRARY_VERSION_PATCH 1) set(NOOP_LIBRARY_VERSION "${NOOP_LIBRARY_VERSION_MAJOR}.${NOOP_LIBRARY_VERSION_MINOR}.${NOOP_LIBRARY_VERSION_PATCH}") set(NOOP_LIBRARY_SOVERSION ${NOOP_LIBRARY_VERSION_MAJOR}) # add definitions include(DefinePlatformDefaults) include(DefineOptions.cmake) include(CPackConfig.cmake) include(CompilerChecks.cmake) include(GNUInstallDirs) # disallow in-source build include(MacroEnsureOutOfSourceBuild) macro_ensure_out_of_source_build("${PROJECT_NAME} requires an out of source build. Please create a separate build directory and run 'cmake /path/to/${PROJECT_NAME} [options]' there.") # Find out if we have threading available set(CMAKE_THREAD_PREFER_PTHREADS ON) find_package(Threads) # config.h checks include(ConfigureChecks.cmake) configure_file(config.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config.h) # check subdirectories add_subdirectory(src) if (UNIT_TESTING) find_package(cmocka 1.1.0 REQUIRED) include(AddCMockaTest) add_subdirectory(tests) endif (UNIT_TESTING) # pkg-config file get_filename_component(SOCKET_WRAPPER_LIB ${SOCKET_WRAPPER_LOCATION} NAME) configure_file(socket_wrapper.pc.cmake ${CMAKE_CURRENT_BINARY_DIR}/socket_wrapper.pc @ONLY) install( FILES ${CMAKE_CURRENT_BINARY_DIR}/socket_wrapper.pc DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig COMPONENT pkgconfig ) configure_file(socket_wrapper_noop.pc.cmake ${CMAKE_CURRENT_BINARY_DIR}/socket_wrapper_noop.pc @ONLY) install( FILES ${CMAKE_CURRENT_BINARY_DIR}/socket_wrapper_noop.pc DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig COMPONENT pkgconfig ) # cmake config files configure_file(socket_wrapper-config-version.cmake.in ${CMAKE_CURRENT_BINARY_DIR}/socket_wrapper-config-version.cmake @ONLY) configure_file(socket_wrapper-config.cmake.in ${CMAKE_CURRENT_BINARY_DIR}/socket_wrapper-config.cmake @ONLY) install( FILES ${CMAKE_CURRENT_BINARY_DIR}/socket_wrapper-config-version.cmake ${CMAKE_CURRENT_BINARY_DIR}/socket_wrapper-config.cmake DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/socket_wrapper COMPONENT devel ) add_subdirectory(doc) socket_wrapper-1.4.4/CTestConfig.cmake000644 001750 000144 00000000433 14631527256 017715 0ustar00asnusers000000 000000 set(UPDATE_TYPE "true") set(CTEST_PROJECT_NAME "socket_wrapper") set(CTEST_NIGHTLY_START_TIME "01:00:00 UTC") set(CTEST_DROP_METHOD "https") set(CTEST_DROP_SITE "test.cmocka.org") set(CTEST_DROP_LOCATION "/submit.php?project=${CTEST_PROJECT_NAME}") set(CTEST_DROP_SITE_CDASH TRUE) socket_wrapper-1.4.4/.clang-format000644 001750 000144 00000001651 14744201025 017105 0ustar00asnusers000000 000000 # https://clang.llvm.org/docs/ClangFormatStyleOptions.html AlignAfterOpenBracket: Align AlignEscapedNewlines: Left AllowAllArgumentsOnNextLine: true AllowAllParametersOfDeclarationOnNextLine: false AllowShortFunctionsOnASingleLine: Empty AllowShortIfStatementsOnASingleLine: false AlwaysBreakAfterReturnType: None BasedOnStyle: LLVM BinPackArguments: false BinPackParameters: false BraceWrapping: AfterEnum: false AfterFunction: true AfterStruct: false AfterUnion: false AfterExternBlock: true BeforeElse: false BeforeWhile: false AfterControlStatement: MultiLine BreakBeforeBinaryOperators: None BreakBeforeBraces: Custom ColumnLimit: 80 ContinuationIndentWidth: 8 IndentCaseLabels: false IndentGotoLabels: false IndentWidth: 8 PenaltyBreakAssignment: 200 PenaltyBreakBeforeFirstCallParameter: 100 PenaltyReturnTypeOnItsOwnLine: 1000 SortIncludes: false UseTab: true WhitespaceSensitiveMacros: ['DEBUG'] socket_wrapper-1.4.4/AUTHORS000644 001750 000144 00000000151 14631527256 015610 0ustar00asnusers000000 000000 Jelmer Vernooij Stefan Metzmacher Andreas Schneider socket_wrapper-1.4.4/LICENSE000644 001750 000144 00000003327 14631527256 015555 0ustar00asnusers000000 000000 BSD 3-Clause License Copyright (c) 2005-2008, Jelmer Vernooij Copyright (c) 2006-2018, Stefan Metzmacher Copyright (c) 2013-2018, Andreas Schneider Copyright (c) 2014-2017, Michael Adam Copyright (c) 2016-2018, Anoop C S All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the author nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. socket_wrapper-1.4.4/example/000755 001750 000144 00000000000 14744201044 016163 5ustar00asnusers000000 000000 socket_wrapper-1.4.4/example/openssh.sh000755 001750 000144 00000004241 14631527256 020215 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.4.4/.editorconfig000644 001750 000144 00000000472 14631527256 017223 0ustar00asnusers000000 000000 root = true [*] charset = utf-8 max_line_length = 80 end_of_line = lf trim_trailing_whitespace = true insert_final_newline = true [*.{c,h}] indent_style = tab indent_size = 8 tab_width = 8 [*.cmake] indent_style = space indent_size = 4 tab_width = 4 [CMake*] indent_style = space indent_size = 4 tab_width = 4 socket_wrapper-1.4.4/DefineOptions.cmake000644 001750 000144 00000000265 14631527256 020316 0ustar00asnusers000000 000000 option(UNIT_TESTING "Build with unit tests" OFF) option(HELGRIND_TESTING "Run threaded unit tests with helgrind" OFF) option(PICKY_DEVELOPER "Build with picky developer flags" OFF) socket_wrapper-1.4.4/cmake/000755 001750 000144 00000000000 14744201044 015610 5ustar00asnusers000000 000000 socket_wrapper-1.4.4/cmake/Toolchain-cross-m32.cmake000644 001750 000144 00000002142 14631527256 022272 0ustar00asnusers000000 000000 set(CMAKE_C_FLAGS "-m32" CACHE STRING "C compiler flags" FORCE) set(CMAKE_CXX_FLAGS "-m32" CACHE STRING "C++ compiler flags" FORCE) set(LIB32 /usr/lib) # Fedora if(EXISTS /usr/lib32) set(LIB32 /usr/lib32) # Arch, Solus endif() set(CMAKE_SYSTEM_LIBRARY_PATH ${LIB32} CACHE STRING "system library search path" FORCE) set(CMAKE_LIBRARY_PATH ${LIB32} CACHE STRING "library search path" FORCE) # this is probably unlikely to be needed, but just in case set(CMAKE_EXE_LINKER_FLAGS "-m32 -L${LIB32}" CACHE STRING "executable linker flags" FORCE) set(CMAKE_SHARED_LINKER_FLAGS "-m32 -L${LIB32}" CACHE STRING "shared library linker flags" FORCE) set(CMAKE_MODULE_LINKER_FLAGS "-m32 -L${LIB32}" CACHE STRING "module linker flags" FORCE) # on Fedora and Arch and similar, point pkgconfig at 32 bit .pc files. We have # to include the regular system .pc files as well (at the end), because some # are not always present in the 32 bit directory if(EXISTS ${LIB32}/pkgconfig) set(ENV{PKG_CONFIG_LIBDIR} ${LIB32}/pkgconfig:/usr/share/pkgconfig:/usr/lib/pkgconfig:/usr/lib64/pkgconfig) endiF() socket_wrapper-1.4.4/cmake/Modules/000755 001750 000144 00000000000 14744201044 017220 5ustar00asnusers000000 000000 socket_wrapper-1.4.4/cmake/Modules/COPYING-CMAKE-SCRIPTS000644 001750 000144 00000002457 14631527256 022241 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.4.4/cmake/Modules/AddCMockaTest.cmake000644 001750 000144 00000006250 14631527256 022646 0ustar00asnusers000000 000000 # # Copyright (c) 2007 Daniel Gollub # Copyright (c) 2007-2018 Andreas Schneider # Copyright (c) 2018 Anderson Toshiyuki Sasaki # # Redistribution and use is allowed according to the terms of the BSD license. # For details see the accompanying COPYING-CMAKE-SCRIPTS file. #.rst: # AddCMockaTest # ------------- # # This file provides a function to add a test # # Functions provided # ------------------ # # :: # # add_cmocka_test(target_name # SOURCES src1 src2 ... srcN # [COMPILE_OPTIONS opt1 opt2 ... optN] # [LINK_LIBRARIES lib1 lib2 ... libN] # [LINK_OPTIONS lopt1 lop2 .. loptN] # ) # # ``target_name``: # Required, expects the name of the test which will be used to define a target # # ``SOURCES``: # Required, expects one or more source files names # # ``COMPILE_OPTIONS``: # Optional, expects one or more options to be passed to the compiler # # ``LINK_LIBRARIES``: # Optional, expects one or more libraries to be linked with the test # executable. # # ``LINK_OPTIONS``: # Optional, expects one or more options to be passed to the linker # # # Example: # # .. code-block:: cmake # # add_cmocka_test(my_test # SOURCES my_test.c other_source.c # COMPILE_OPTIONS -g -Wall # LINK_LIBRARIES mylib # LINK_OPTIONS -Wl,--enable-syscall-fixup # ) # # Where ``my_test`` is the name of the test, ``my_test.c`` and # ``other_source.c`` are sources for the binary, ``-g -Wall`` are compiler # options to be used, ``mylib`` is a target of a library to be linked, and # ``-Wl,--enable-syscall-fixup`` is an option passed to the linker. # enable_testing() include(CTest) if (CMAKE_CROSSCOMPILING) if (WIN32) find_program(WINE_EXECUTABLE NAMES wine) set(TARGET_SYSTEM_EMULATOR ${WINE_EXECUTABLE} CACHE INTERNAL "") endif() endif() function(ADD_CMOCKA_TEST _TARGET_NAME) set(one_value_arguments ) set(multi_value_arguments SOURCES COMPILE_OPTIONS LINK_LIBRARIES LINK_OPTIONS ) cmake_parse_arguments(_add_cmocka_test "" "${one_value_arguments}" "${multi_value_arguments}" ${ARGN} ) if (NOT DEFINED _add_cmocka_test_SOURCES) message(FATAL_ERROR "No sources provided for target ${_TARGET_NAME}") endif() add_executable(${_TARGET_NAME} ${_add_cmocka_test_SOURCES}) if (DEFINED _add_cmocka_test_COMPILE_OPTIONS) target_compile_options(${_TARGET_NAME} PRIVATE ${_add_cmocka_test_COMPILE_OPTIONS} ) endif() if (DEFINED _add_cmocka_test_LINK_LIBRARIES) target_link_libraries(${_TARGET_NAME} PRIVATE ${_add_cmocka_test_LINK_LIBRARIES} ) endif() if (DEFINED _add_cmocka_test_LINK_OPTIONS) set_target_properties(${_TARGET_NAME} PROPERTIES LINK_FLAGS ${_add_cmocka_test_LINK_OPTIONS} ) endif() add_test(${_TARGET_NAME} ${TARGET_SYSTEM_EMULATOR} ${_TARGET_NAME} ) endfunction (ADD_CMOCKA_TEST) socket_wrapper-1.4.4/cmake/Modules/DefineCMakeDefaults.cmake000644 001750 000144 00000001251 14631527256 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) # Create the compile command database for clang by default set(CMAKE_EXPORT_COMPILE_COMMANDS ON) # Always build with -fPIC set(CMAKE_POSITION_INDEPENDENT_CODE ON) socket_wrapper-1.4.4/cmake/Modules/MacroEnsureOutOfSourceBuild.cmake000644 001750 000144 00000001227 14631527256 025600 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.4.4/cmake/Modules/AddCCompilerFlag.cmake000644 001750 000144 00000001515 14631527256 023317 0ustar00asnusers000000 000000 # # add_c_compiler_flag("-Werror" SUPPORTED_CFLAGS) # # Copyright (c) 2018 Andreas Schneider # # Redistribution and use is allowed according to the terms of the BSD license. # For details see the accompanying COPYING-CMAKE-SCRIPTS file. include(CheckCCompilerFlag) macro(add_c_compiler_flag _COMPILER_FLAG _OUTPUT_VARIABLE) string(TOUPPER ${_COMPILER_FLAG} _COMPILER_FLAG_NAME) string(REGEX REPLACE "^-" "" _COMPILER_FLAG_NAME "${_COMPILER_FLAG_NAME}") string(REGEX REPLACE "(-|=|\ )" "_" _COMPILER_FLAG_NAME "${_COMPILER_FLAG_NAME}") check_c_compiler_flag("${_COMPILER_FLAG}" WITH_${_COMPILER_FLAG_NAME}_FLAG) if (WITH_${_COMPILER_FLAG_NAME}_FLAG) #string(APPEND ${_OUTPUT_VARIABLE} "${_COMPILER_FLAG} ") list(APPEND ${_OUTPUT_VARIABLE} ${_COMPILER_FLAG}) endif() endmacro() socket_wrapper-1.4.4/cmake/Modules/DefineCompilerFlags.cmake000644 001750 000144 00000007340 14631527256 024103 0ustar00asnusers000000 000000 if (UNIX AND NOT WIN32) # Activate with: -DCMAKE_BUILD_TYPE=Profiling set(CMAKE_C_FLAGS_PROFILING "-O0 -g -fprofile-arcs -ftest-coverage" CACHE STRING "Flags used by the C compiler during PROFILING builds.") set(CMAKE_CXX_FLAGS_PROFILING "-O0 -g -fprofile-arcs -ftest-coverage" CACHE STRING "Flags used by the CXX compiler during PROFILING builds.") set(CMAKE_SHARED_LINKER_FLAGS_PROFILING "-fprofile-arcs -ftest-coverage" CACHE STRING "Flags used by the linker during the creation of shared libraries during PROFILING builds.") set(CMAKE_MODULE_LINKER_FLAGS_PROFILING "-fprofile-arcs -ftest-coverage" CACHE STRING "Flags used by the linker during the creation of shared libraries during PROFILING builds.") set(CMAKE_EXEC_LINKER_FLAGS_PROFILING "-fprofile-arcs -ftest-coverage" CACHE STRING "Flags used by the linker during PROFILING builds.") # Activate with: -DCMAKE_BUILD_TYPE=AddressSanitizer set(CMAKE_C_FLAGS_ADDRESSSANITIZER "-g -O1 -fsanitize=address -fno-omit-frame-pointer" CACHE STRING "Flags used by the C compiler during ADDRESSSANITIZER builds.") set(CMAKE_CXX_FLAGS_ADDRESSSANITIZER "-g -O1 -fsanitize=address -fno-omit-frame-pointer" CACHE STRING "Flags used by the CXX compiler during ADDRESSSANITIZER builds.") set(CMAKE_SHARED_LINKER_FLAGS_ADDRESSSANITIZER "-fsanitize=address" CACHE STRING "Flags used by the linker during the creation of shared libraries during ADDRESSSANITIZER builds.") set(CMAKE_MODULE_LINKER_FLAGS_ADDRESSSANITIZER "-fsanitize=address" CACHE STRING "Flags used by the linker during the creation of shared libraries during ADDRESSSANITIZER builds.") set(CMAKE_EXEC_LINKER_FLAGS_ADDRESSSANITIZER "-fsanitize=address" CACHE STRING "Flags used by the linker during ADDRESSSANITIZER builds.") # Activate with: -DCMAKE_BUILD_TYPE=UndefinedSanitizer set(CMAKE_C_FLAGS_UNDEFINEDSANITIZER "-g -O1 -fsanitize=undefined -fsanitize=null -fsanitize=alignment -fno-sanitize-recover" CACHE STRING "Flags used by the C compiler during UNDEFINEDSANITIZER builds.") set(CMAKE_CXX_FLAGS_UNDEFINEDSANITIZER "-g -O1 -fsanitize=undefined -fsanitize=null -fsanitize=alignment -fno-sanitize-recover" CACHE STRING "Flags used by the CXX compiler during UNDEFINEDSANITIZER builds.") set(CMAKE_SHARED_LINKER_FLAGS_UNDEFINEDSANITIZER "-fsanitize=undefined" CACHE STRING "Flags used by the linker during the creation of shared libraries during UNDEFINEDSANITIZER builds.") set(CMAKE_MODULE_LINKER_FLAGS_UNDEFINEDSANITIZER "-fsanitize=undefined" CACHE STRING "Flags used by the linker during the creation of shared libraries during UNDEFINEDSANITIZER builds.") set(CMAKE_EXEC_LINKER_FLAGS_UNDEFINEDSANITIZER "-fsanitize=undefined" CACHE STRING "Flags used by the linker during UNDEFINEDSANITIZER builds.") # Activate with: -DCMAKE_BUILD_TYPE=ThreadSanitizer set(CMAKE_C_FLAGS_THREADSANITIZER "-g -O1 -fsanitize=thread" CACHE STRING "Flags used by the C compiler during THREADSANITIZER builds.") set(CMAKE_CXX_FLAGS_THREADSANITIZER "-g -O1 -fsanitize=thread" CACHE STRING "Flags used by the CXX compiler during THREADSANITIZER builds.") set(CMAKE_SHARED_LINKER_FLAGS_THREADSANITIZER "-fsanitize=thread" CACHE STRING "Flags used by the linker during the creation of shared libraries during THREADSANITIZER builds.") set(CMAKE_MODULE_LINKER_FLAGS_THREADSANITIZER "-fsanitize=thread" CACHE STRING "Flags used by the linker during the creation of shared libraries during THREADSANITIZER builds.") set(CMAKE_EXEC_LINKER_FLAGS_THREADSANITIZER "-fsanitize=thread" CACHE STRING "Flags used by the linker during THREADSANITIZER builds.") endif() socket_wrapper-1.4.4/cmake/Modules/DefinePlatformDefaults.cmake000644 001750 000144 00000001460 14631527256 024625 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.4.4/cmake/Modules/CheckCCompilerFlagSSP.cmake000644 001750 000144 00000003560 14631527256 024234 0ustar00asnusers000000 000000 # - Check whether the C compiler supports a given flag in the # context of a stack checking compiler option. # CHECK_C_COMPILER_FLAG_SSP(FLAG VARIABLE) # # FLAG - the compiler flag # VARIABLE - variable to store the result # # This actually calls check_c_source_compiles. # See help for CheckCSourceCompiles for a listing of variables # that can modify the build. # Copyright (c) 2006, Alexander Neundorf, # # Redistribution and use is allowed according to the terms of the BSD license. # For details see the accompanying COPYING-CMAKE-SCRIPTS file. # Requires cmake 3.10 #include_guard(GLOBAL) include(CheckCSourceCompiles) include(CMakeCheckCompilerFlagCommonPatterns) macro(CHECK_C_COMPILER_FLAG_SSP _FLAG _RESULT) set(SAFE_CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS}") set(CMAKE_REQUIRED_FLAGS "${_FLAG}") # Normalize locale during test compilation. set(_CheckCCompilerFlag_LOCALE_VARS LC_ALL LC_MESSAGES LANG) foreach(v ${_CheckCCompilerFlag_LOCALE_VARS}) set(_CheckCCompilerFlag_SAVED_${v} "$ENV{${v}}") set(ENV{${v}} C) endforeach() CHECK_COMPILER_FLAG_COMMON_PATTERNS(_CheckCCompilerFlag_COMMON_PATTERNS) check_c_source_compiles("int main(int argc, char **argv) { char buffer[256]; return buffer[argc]=0;}" ${_RESULT} # Some compilers do not fail with a bad flag FAIL_REGEX "command line option .* is valid for .* but not for C" # GNU ${_CheckCCompilerFlag_COMMON_PATTERNS}) foreach(v ${_CheckCCompilerFlag_LOCALE_VARS}) set(ENV{${v}} ${_CheckCCompilerFlag_SAVED_${v}}) unset(_CheckCCompilerFlag_SAVED_${v}) endforeach() unset(_CheckCCompilerFlag_LOCALE_VARS) unset(_CheckCCompilerFlag_COMMON_PATTERNS) set(CMAKE_REQUIRED_FLAGS "${SAFE_CMAKE_REQUIRED_FLAGS}") endmacro(CHECK_C_COMPILER_FLAG_SSP) socket_wrapper-1.4.4/cmake/Toolchain-Debian-mips.cmake000644 001750 000144 00000001173 14631527256 022675 0ustar00asnusers000000 000000 include(CMakeForceCompiler) set(TOOLCHAIN_PREFIX mips-linux-gnu) set(CMAKE_SYSTEM_NAME Linux) set(CMAKE_SYSTEM_VERSION 1) set(CMAKE_SYSTEM_PROCESSOR mips) # This is the location of the mips toolchain set(CMAKE_C_COMPILER ${TOOLCHAIN_PREFIX}-gcc) set(CMAKE_CXX_COMPILER ${TOOLCHAIN_PREFIX}-g++) # This is the file system root of the target set(CMAKE_FIND_ROOT_PATH /usr/${TOOLCHAIN_PREFIX}) # Search for programs in the build host directories set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) # For libraries and headers in the target directories set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) socket_wrapper-1.4.4/socket_wrapper-config-version.cmake.in000644 001750 000144 00000000605 14631527256 024131 0ustar00asnusers000000 000000 set(PACKAGE_VERSION @PROJECT_VERSION@) # Check whether the requested PACKAGE_FIND_VERSION is compatible if("${PACKAGE_VERSION}" VERSION_LESS "${PACKAGE_FIND_VERSION}") set(PACKAGE_VERSION_COMPATIBLE FALSE) else() set(PACKAGE_VERSION_COMPATIBLE TRUE) if ("${PACKAGE_VERSION}" VERSION_EQUAL "${PACKAGE_FIND_VERSION}") set(PACKAGE_VERSION_EXACT TRUE) endif() endif() socket_wrapper-1.4.4/socket_wrapper_noop.pc.cmake000644 001750 000144 00000000354 14631527256 022233 0ustar00asnusers000000 000000 libdir=@CMAKE_INSTALL_FULL_LIBDIR@ includedir=@CMAKE_INSTALL_FULL_INCLUDEDIR@ Name: @PROJECT_NAME@ Description: The socket_wrapper_noop library Version: @PROJECT_VERSION@ Libs: -L${libdir} -lsocket_wrapper_noop Cflags: -I${includedir} socket_wrapper-1.4.4/README.install000644 001750 000144 00000003600 14631527256 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.4.4/tests/000755 001750 000144 00000000000 14744201044 015672 5ustar00asnusers000000 000000 socket_wrapper-1.4.4/tests/CMakeLists.txt000644 001750 000144 00000015641 14632503553 020447 0ustar00asnusers000000 000000 project(tests C) include_directories( ${CMAKE_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_SOURCE_DIR}/src ${CMOCKA_INCLUDE_DIR} ) # Required for cmocka >= 1.1.6 if (TARGET cmocka::cmocka) set(CMOCKA_LIBRARY cmocka::cmocka) endif() set(TORTURE_LIBRARY torture) # RFC862 echo server add_executable(echo_srv echo_srv.c) target_compile_options(echo_srv PRIVATE ${DEFAULT_C_COMPILE_FLAGS} -D_GNU_SOURCE) target_link_libraries(echo_srv ${SWRAP_REQUIRED_LIBRARIES}) if (DEFINED DEFAULT_LINK_FLAGS) set_target_properties(echo_srv PROPERTIES LINK_FLAGS ${DEFAULT_LINK_FLAGS}) endif() add_library(${TORTURE_LIBRARY} STATIC torture.c) target_compile_options(${TORTURE_LIBRARY} PRIVATE ${DEFAULT_C_COMPILE_FLAGS} -D_GNU_SOURCE) target_link_libraries(${TORTURE_LIBRARY} ${CMOCKA_LIBRARY} ${SWRAP_REQUIRED_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT}) add_library(swrap_fake_uid_wrapper SHARED swrap_fake_uid_wrapper.c) target_compile_options(swrap_fake_uid_wrapper PRIVATE ${DEFAULT_C_COMPILE_FLAGS} -D_GNU_SOURCE) #target_include_directories(swrap_fake_uid_wrapper # PRIVATE ${CMAKE_BINARY_DIR} ${CMOCKA_INCLUDE_DIR}) set(SWRAP_FAKE_UID_WRAPPER_LOCATION "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_SHARED_LIBRARY_PREFIX}swrap_fake_uid_wrapper${CMAKE_SHARED_LIBRARY_SUFFIX}") set(SWRAP_THREADED_TESTS test_thread_sockets test_thread_echo_tcp_connect test_thread_echo_tcp_write_read test_thread_echo_tcp_sendmsg_recvmsg test_thread_echo_udp_send_recv) set(SWRAP_TESTS test_ioctl test_tcp_listen test_tcp_dup2 test_fcntl test_fcntl_lock test_echo_tcp_connect test_echo_tcp_bind test_echo_tcp_socket_options test_echo_tcp_sendmsg_recvmsg test_echo_tcp_sendmmsg_recvmmsg test_echo_tcp_write_read test_echo_tcp_poll 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_max_sockets test_public_functions test_close_failure test_tcp_socket_overwrite test_syscall_uwrap ${SWRAP_THREADED_TESTS}) if (HAVE_STRUCT_MSGHDR_MSG_CONTROL) set(SWRAP_TESTS ${SWRAP_TESTS} test_sendmsg_recvmsg_fd test_echo_tcp_sendmsg_recvmsg_fd) endif (HAVE_STRUCT_MSGHDR_MSG_CONTROL) function(ADD_CMOCKA_TEST_ENVIRONMENT _TEST_NAME) if (CMAKE_BUILD_TYPE) string(TOLOWER "${CMAKE_BUILD_TYPE}" CMAKE_BUILD_TYPE_LOWER) if (CMAKE_BUILD_TYPE_LOWER STREQUAL "addresssanitizer") find_library(ASAN_LIBRARY NAMES asan) if (NOT ASAN_LIBRARY) foreach(version RANGE 10 1) if (NOT ASAN_LIBRARY) find_library(ASAN_LIBRARY libasan.so.${version}) endif() endforeach() endif() endif() endif() if (ASAN_LIBRARY) list(APPEND PRELOAD_LIBRARIES ${ASAN_LIBRARY}) endif() list(APPEND PRELOAD_LIBRARIES ${SWRAP_FAKE_UID_WRAPPER_LOCATION}) list(APPEND PRELOAD_LIBRARIES ${SOCKET_WRAPPER_LOCATION}) if (OSX) set(TORTURE_ENVIRONMENT "DYLD_FORCE_FLAT_NAMESPACE=1;DYLD_INSERT_LIBRARIES=${SOCKET_WRAPPER_LOCATION}") else () string(REPLACE ";" ":" _TMP_ENV "${PRELOAD_LIBRARIES}") set(TORTURE_ENVIRONMENT "LD_PRELOAD=${_TMP_ENV}") endif() if (CMAKE_BUILD_TYPE) string(TOLOWER "${CMAKE_BUILD_TYPE}" CMAKE_BUILD_TYPE_LOWER) if (CMAKE_BUILD_TYPE_LOWER STREQUAL "addresssanitizer" OR CMAKE_BUILD_TYPE_LOWER STREQUAL "threadsanitizer" OR CMAKE_BUILD_TYPE_LOWER STREQUAL "undefinedsanitizer") list(APPEND TORTURE_ENVIRONMENT "SOCKET_WRAPPER_DISABLE_DEEPBIND=1") endif() endif() set_property(TEST ${_TEST_NAME} PROPERTY ENVIRONMENT "${TORTURE_ENVIRONMENT}") endfunction() if (CMAKE_SIZEOF_VOID_P EQUAL 4) execute_process( COMMAND getconf LFS_CFLAGS OUTPUT_VARIABLE GETCONF_LFS_CFLAGS OUTPUT_STRIP_TRAILING_WHITESPACE) # Create a list from the string set(LFS_CFLAGS) if (GETCONF_LFS_CFLAGS) string(REPLACE " " ";" LFS_CFLAGS ${GETCONF_LFS_CFLAGS}) endif() message(STATUS "Enabling large file support for tests: ${LFS_CFLAGS}") endif() foreach(_SWRAP_TEST ${SWRAP_TESTS}) add_cmocka_test(${_SWRAP_TEST} SOURCES ${_SWRAP_TEST}.c COMPILE_OPTIONS ${DEFAULT_C_COMPILE_FLAGS} -D_GNU_SOURCE ${LFS_CFLAGS} LINK_LIBRARIES ${TORTURE_LIBRARY} ${CMOCKA_LIBRARY} socket_wrapper_noop LINK_OPTIONS ${DEFAULT_LINK_FLAGS}) add_cmocka_test_environment(${_SWRAP_TEST}) endforeach() if (HELGRIND_TESTING) find_program(VALGRIND_EXECUTABLE valgrind) if (VALGRIND_EXECUTABLE) set(VALGRIND_HELGRIND_OPTIONS -v --trace-children=yes --tool=helgrind --error-exitcode=1 --read-var-info=yes --suppressions=${CMAKE_CURRENT_SOURCE_DIR}/helgrind.supp) foreach(_TEST ${SWRAP_THREADED_TESTS}) set(_HELGRIND_TEST "helgrind_${_TEST}") add_test(NAME ${_HELGRIND_TEST} COMMAND ${VALGRIND_EXECUTABLE} ${VALGRIND_HELGRIND_OPTIONS} ${CMAKE_CURRENT_BINARY_DIR}/${_TEST}) if (OSX) set_property( TEST ${_HELGRIND_TEST} PROPERTY ENVIRONMENT DYLD_FORCE_FLAT_NAMESPACE=1;DYLD_INSERT_LIBRARIES=${SOCKET_WRAPPER_LOCATION}) else () set_property( TEST ${_HELGRIND_TEST} PROPERTY ENVIRONMENT LD_PRELOAD=${SOCKET_WRAPPER_LOCATION} SOCKET_WRAPPER_DISABLE_DEEPBIND=1) endif() endforeach() endif() endif() # test_swrap_unit (don't use LFS) add_cmocka_test(test_swrap_unit SOURCES test_swrap_unit.c COMPILE_OPTIONS ${DEFAULT_C_COMPILE_FLAGS} -D_GNU_SOURCE LINK_LIBRARIES ${TORTURE_LIBRARY} ${CMOCKA_LIBRARY} socket_wrapper_noop LINK_OPTIONS ${DEFAULT_LINK_FLAGS}) add_cmocka_test_environment(test_swrap_unit) # test_fork_pthread add_library(thread_deadlock SHARED thread_deadlock.c) target_link_libraries(thread_deadlock ${CMAKE_THREAD_LIBS_INIT}) target_compile_options(thread_deadlock PRIVATE ${DEFAULT_C_COMPILE_FLAGS}) add_cmocka_test(test_fork_thread_deadlock SOURCES test_fork_thread_deadlock.c COMPILE_OPTIONS ${DEFAULT_C_COMPILE_FLAGS} -D_GNU_SOURCE LINK_LIBRARIES ${TORTURE_LIBRARY} ${CMOCKA_LIBRARY} thread_deadlock LINK_OPTIONS ${DEFAULT_LINK_FLAGS}) add_cmocka_test_environment(test_fork_thread_deadlock) socket_wrapper-1.4.4/tests/torture.h000644 001750 000144 00000005262 14631527256 017567 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.4.4/tests/test_echo_tcp_poll.c000644 001750 000144 00000011625 14632503553 021722 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 handle_poll_loop(size_t size, int s) { char send_buf[size]; char recv_buf[size]; int nfds, num_open_fds; struct pollfd pfds[1]; size_t nread = 0, nwrote = 0; ssize_t ret; int i; num_open_fds = nfds = 1; pfds[0].fd = s; pfds[0].events = POLLIN | POLLOUT; i = 0; memset(send_buf, 0, sizeof(send_buf)); while (num_open_fds > 0 && i < 10) { int ready; printf("About to poll()\n"); ready = poll(pfds, nfds, -1); assert_int_not_equal(ready, -1); printf("Ready: %d\n", ready); /* Deal with array returned by poll(). */ for (int j = 0; j < nfds; j++) { if (pfds[j].revents != 0) { printf(" fd=%d; events: %s%s%s%s\n", pfds[j].fd, (pfds[j].revents & POLLIN) ? "POLLIN " : "", (pfds[j].revents & POLLOUT) ? "POLLOUT " : "", (pfds[j].revents & POLLHUP) ? "POLLHUP " : "", (pfds[j].revents & POLLERR) ? "POLLERR " : ""); } if (pfds[j].revents & POLLIN) { ret = read(s, recv_buf + nread, sizeof(recv_buf) - nread); printf(" fd=%d: read=%zd\n", pfds[j].fd, ret); assert_int_not_equal(ret, -1); nread += ret; /* try to delay */ sleep(1); } if (pfds[j].revents & POLLOUT) { snprintf(send_buf, sizeof(send_buf), "packet.%d", i); ret = write(s, send_buf + nwrote, sizeof(send_buf) - nwrote); printf(" fd=%d: wrote=%zd\n", pfds[j].fd, ret); assert_int_not_equal(ret, -1); nwrote += ret; if (nwrote == sizeof(send_buf)) { /* no more to write */ pfds[j].events &= ~POLLOUT; } } if (pfds[j].revents & (POLLERR | POLLHUP)) { printf(" closing fd %d\n", pfds[j].fd); close(pfds[j].fd); num_open_fds--; } /* verify the data */ if (nwrote == sizeof(send_buf) && nread == nwrote) { assert_memory_equal(send_buf, recv_buf, sizeof(send_buf)); i++; nwrote = 0; nread = 0; /* new packet to write */ pfds[j].events |= POLLOUT; printf("== Next packet %d\n", i); } } } printf("All file descriptors closed; bye\n"); } static void test_write_read_ipv4_size(void **state, size_t size) { 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()); 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); /* closes the socket too */ handle_poll_loop(size, s); } static void test_write_read_ipv4(void **state) { test_write_read_ipv4_size(state, 64); } static void test_write_read_ipv4_large(void **state) { test_write_read_ipv4_size(state, 2000); } #ifdef HAVE_IPV6 static void test_write_read_ipv6_size(void **state, size_t size) { struct torture_address addr = { .sa_socklen = sizeof(struct sockaddr_in6), }; 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(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); /* closes the socket too */ handle_poll_loop(size, s); } static void test_write_read_ipv6(void **state) { test_write_read_ipv6_size(state, 64); } static void test_write_read_ipv6_large(void **state) { test_write_read_ipv6_size(state, 2000); } #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), cmocka_unit_test_setup_teardown(test_write_read_ipv4_large, setup_echo_srv_tcp_ipv4, teardown), #ifdef HAVE_IPV6 cmocka_unit_test_setup_teardown(test_write_read_ipv6, setup_echo_srv_tcp_ipv6, teardown), cmocka_unit_test_setup_teardown(test_write_read_ipv6_large, setup_echo_srv_tcp_ipv6, teardown), #endif }; rc = cmocka_run_group_tests(tcp_write_tests, NULL, NULL); return rc; } socket_wrapper-1.4.4/tests/test_thread_echo_tcp_sendmsg_recvmsg.c000644 001750 000144 00000011312 14631527256 025467 0ustar00asnusers000000 000000 #include #include #include #include #include #include "config.h" #include "torture.h" #include #include #include #include #include #include #include #include #define NUM_THREADS 10 static int setup_echo_srv_tcp_ipv4(void **state) { torture_setup_echo_srv_tcp_ipv4(state); return 0; } static int teardown(void **state) { torture_teardown_echo_srv(state); return 0; } static void *thread_worker1(void *arg) { struct torture_address addr = { .sa_socklen = sizeof(struct sockaddr_storage), }; char send_buf[64] = {0}; char recv_buf[64] = {0}; ssize_t ret; int rc; int i; int s; (void) arg; /* unused */ s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); assert_int_not_equal(s, -1); addr.sa.in.sin_family = AF_INET; addr.sa.in.sin_port = htons(torture_server_port()); rc = inet_pton(AF_INET, torture_server_address(AF_INET), &addr.sa.in.sin_addr); assert_int_equal(rc, 1); rc = connect(s, &addr.sa.s, addr.sa_socklen); assert_return_code(rc, errno); for (i = 0; i < 10; i++) { struct torture_address reply_addr = { .sa_socklen = sizeof(struct sockaddr_storage), }; struct msghdr s_msg = { .msg_namelen = 0, }; struct msghdr r_msg = { .msg_namelen = 0, }; struct iovec s_iov; struct iovec r_iov; snprintf(send_buf, sizeof(send_buf), "packet.%d", i); /* This should be ignored */ rc = inet_pton(AF_INET, "127.0.0.1", &addr.sa.in.sin_addr); assert_int_equal(rc, 1); s_msg.msg_name = &addr.sa.s; s_msg.msg_namelen = addr.sa_socklen; s_iov.iov_base = send_buf; s_iov.iov_len = sizeof(send_buf); s_msg.msg_iov = &s_iov; s_msg.msg_iovlen = 1; ret = sendmsg(s, &s_msg, 0); assert_int_not_equal(ret, -1); r_msg.msg_name = &reply_addr.sa.s; r_msg.msg_namelen = reply_addr.sa_socklen; r_iov.iov_base = recv_buf; r_iov.iov_len = sizeof(recv_buf); r_msg.msg_iov = &r_iov; r_msg.msg_iovlen = 1; ret = recvmsg(s, &r_msg, 0); assert_int_not_equal(ret, -1); assert_int_equal(r_msg.msg_namelen, 0); assert_memory_equal(send_buf, recv_buf, sizeof(send_buf)); } close(s); return NULL; } static void *thread_worker2(void *arg) { struct torture_address send_addr = { .sa_socklen = sizeof(struct sockaddr_storage), }; struct msghdr s_msg = { .msg_namelen = 0, }; struct msghdr r_msg = { .msg_namelen = 0, }; struct iovec iov; char payload[] = "PACKET"; ssize_t ret; int rc; int s; (void)arg; /* unused */ s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); assert_int_not_equal(s, -1); send_addr.sa.in.sin_family = AF_INET; send_addr.sa.in.sin_port = htons(torture_server_port()); rc = inet_pton(AF_INET, torture_server_address(AF_INET), &send_addr.sa.in.sin_addr); assert_int_equal(rc, 1); rc = connect(s, &send_addr.sa.s, send_addr.sa_socklen); assert_return_code(rc, errno); /* msg_name = NULL */ iov.iov_base = (void *)payload; iov.iov_len = sizeof(payload); s_msg.msg_iov = &iov; s_msg.msg_iovlen = 1; ret = sendmsg(s, &s_msg, 0); assert_int_not_equal(ret, -1); /* msg_name = NULL */ memset(payload, 0, sizeof(payload)); r_msg.msg_iov = &iov; r_msg.msg_iovlen = 1; ret = recvmsg(s, &r_msg, 0); assert_int_not_equal(ret, -1); assert_int_equal(r_msg.msg_namelen, 0); assert_null(r_msg.msg_name); close(s); return NULL; } static void test_sendmsg_recvmsg_ipv4(void **state) { pthread_attr_t pthread_custom_attr; pthread_t threads[NUM_THREADS]; int i; (void) state; /* unused */ pthread_attr_init(&pthread_custom_attr); for (i = 0; i < NUM_THREADS; i++) { pthread_create(&threads[i], &pthread_custom_attr, thread_worker1, NULL); } for (i = 0; i < NUM_THREADS; i++) { pthread_join(threads[i], NULL); } pthread_attr_destroy(&pthread_custom_attr); } static void test_sendmsg_recvmsg_ipv4_null(void **state) { pthread_attr_t pthread_custom_attr; pthread_t threads[NUM_THREADS]; int i; (void) state; /* unused */ pthread_attr_init(&pthread_custom_attr); for (i = 0; i < NUM_THREADS; i++) { pthread_create(&threads[i], &pthread_custom_attr, thread_worker2, NULL); } for (i = 0; i < NUM_THREADS; i++) { pthread_join(threads[i], NULL); } pthread_attr_destroy(&pthread_custom_attr); } int main(void) { int rc; const struct CMUnitTest sendmsg_tests[] = { cmocka_unit_test_setup_teardown(test_sendmsg_recvmsg_ipv4, setup_echo_srv_tcp_ipv4, teardown), cmocka_unit_test_setup_teardown(test_sendmsg_recvmsg_ipv4_null, setup_echo_srv_tcp_ipv4, teardown), }; rc = cmocka_run_group_tests(sendmsg_tests, NULL, NULL); return rc; } socket_wrapper-1.4.4/tests/test_tcp_dup2.c000644 001750 000144 00000002342 14631527256 020631 0ustar00asnusers000000 000000 #include "torture.h" #include #include #include #ifdef HAVE___CLOSE_NOCANCEL extern int __close_nocancel(int fd); #endif static int setup(void **state) { torture_setup_socket_dir(state); return 0; } static int teardown(void **state) { torture_teardown_socket_dir(state); return 0; } static void test_dup2_existing_open_fd(void **state) { int s, dup_s; int rc; (void) state; /* unused */ s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); assert_int_not_equal(s, -1); /* * Here we try to duplicate the existing socket fd to itself * and as per man page for dup2() it must return the already * open fd without any failure. */ dup_s = dup2(s, s); assert_int_equal(dup_s, s); #ifdef HAVE___CLOSE_NOCANCEL rc = __close_nocancel(s); assert_return_code(rc, errno); rc = close(s); assert_int_equal(rc, -1); assert_int_equal(errno, EBADF); rc = __close_nocancel(s); assert_int_equal(rc, -1); assert_int_equal(errno, EBADF); #else rc = close(s); assert_return_code(rc, errno); #endif } int main(void) { int rc; const struct CMUnitTest tcp_dup2_tests[] = { cmocka_unit_test(test_dup2_existing_open_fd), }; rc = cmocka_run_group_tests(tcp_dup2_tests, setup, teardown); return rc; } socket_wrapper-1.4.4/tests/test_echo_tcp_connect.c000644 001750 000144 00000003736 14631527256 022416 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.4.4/tests/test_echo_tcp_get_peer_sock_name.c000644 001750 000144 00000030465 14631527256 024575 0ustar00asnusers000000 000000 #include #include #include #include #include "config.h" #include "torture.h" #include #include #include #include #include #include #include #include static int setup_echo_srv_tcp_ipv4(void **state) { torture_setup_echo_srv_tcp_ipv4(state); setenv("SOCKET_WRAPPER_DEFAULT_IFACE", "20", 1); return 0; } static int teardown(void **state) { torture_teardown_echo_srv(state); return 0; } static void _assert_sockaddr_equal(struct torture_address *addr, const char *a, const char * const file, const int line) { #ifdef HAVE_IPV6 char ip[INET6_ADDRSTRLEN] = { 0 }; #else char ip[INET_ADDRSTRLEN] = { 0 }; #endif const char *p; #ifdef HAVE_IPV6 p = inet_ntop(addr->sa.ss.ss_family, addr->sa.ss.ss_family == AF_INET6 ? (void *)&addr->sa.in6.sin6_addr : (void *)&addr->sa.in.sin_addr, ip, sizeof(ip)); #else p = inet_ntop(addr->sa.ss.ss_family, (void *)&addr->sa.in.sin_addr, ip, sizeof(ip)); #endif _assert_true(cast_ptr_to_largest_integral_type(p), "inet_ntop: Failed to convert IP address", file, line); _assert_string_equal(ip, a, file, line); } #define assert_sockaddr_equal(ss, a) \ _assert_sockaddr_equal(ss, a, __FILE__, __LINE__) static void _assert_sockaddr_port_equal(struct torture_address *addr, const char *a, uint16_t port, const char * const file, const int line) { uint16_t n_port; _assert_sockaddr_equal(addr, a, file, line); switch(addr->sa.ss.ss_family) { case AF_INET: n_port = addr->sa.in.sin_port; break; #ifdef HAVE_IPV6 case AF_INET6: n_port = addr->sa.in6.sin6_port; break; #endif default: return; } _assert_int_equal(ntohs(n_port), port, file, line); } #define assert_sockaddr_port_equal(ss, a, prt) \ _assert_sockaddr_port_equal(ss, a, prt, __FILE__, __LINE__) static void _assert_sockaddr_port_range_equal(struct torture_address *addr, const char *a, uint16_t min_port, uint16_t max_port, const char * const file, const int line) { uint16_t n_port; _assert_sockaddr_equal(addr, a, file, line); switch(addr->sa.ss.ss_family) { case AF_INET: n_port = addr->sa.in.sin_port; break; #ifdef HAVE_IPV6 case AF_INET6: n_port = addr->sa.in6.sin6_port; break; #endif default: return; } _assert_in_range(ntohs(n_port), min_port, max_port, file, line); } #define assert_sockaddr_port_range_equal(ss, a, min_prt, max_prt) \ _assert_sockaddr_port_range_equal(ss, a, min_prt, max_prt, __FILE__, __LINE__) static void test_connect_getsockname_getpeername(void **state) { struct torture_address addr = { .sa_socklen = sizeof(struct sockaddr_in), }; struct torture_address cli_addr = { .sa_socklen = sizeof(struct sockaddr_storage), }; struct torture_address srv_addr = { .sa_socklen = sizeof(struct sockaddr_storage), }; int rc; int s; (void) state; /* unused */ s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); assert_return_code(s, errno); /* Bind client address to wildcard address */ addr.sa.in.sin_family = AF_INET; rc = inet_pton(AF_INET, "127.0.0.20", &addr.sa.in.sin_addr); assert_int_equal(rc, 1); rc = bind(s, &addr.sa.s, addr.sa_socklen); assert_return_code(rc, errno); rc = getsockname(s, &cli_addr.sa.s, &cli_addr.sa_socklen); assert_return_code(rc, errno); assert_sockaddr_port_range_equal(&cli_addr, "127.0.0.20", 1024, 65535); rc = getpeername(s, &addr.sa.s, &addr.sa_socklen); assert_int_equal(rc, -1); assert_int_equal(errno, ENOTCONN); /* connect */ addr = (struct torture_address) { .sa_socklen = sizeof(struct sockaddr_in), .sa.in = (struct sockaddr_in) { .sin_family = AF_INET, .sin_port = htons(torture_server_port()), }, }; rc = inet_pton(AF_INET, torture_server_address(AF_INET), &addr.sa.in.sin_addr); assert_int_equal(rc, 1); /* Connect */ rc = connect(s, &addr.sa.s, addr.sa_socklen); assert_return_code(rc, errno); cli_addr = (struct torture_address) { .sa_socklen = sizeof(struct sockaddr_storage), }; rc = getsockname(s, &cli_addr.sa.s, &cli_addr.sa_socklen); assert_return_code(rc, errno); assert_sockaddr_port_range_equal(&cli_addr, "127.0.0.20", 1024, 65535); srv_addr = (struct torture_address) { .sa_socklen = sizeof(struct sockaddr_storage), }; rc = getpeername(s, &srv_addr.sa.s, &srv_addr.sa_socklen); assert_return_code(rc, errno); assert_sockaddr_port_equal(&srv_addr, "127.0.0.10", 7); close(s); } static void test_connect_getsockname_getpeername_port(void **state) { struct torture_address addr = { .sa_socklen = sizeof(struct sockaddr_in), }; struct torture_address cli_addr = { .sa_socklen = sizeof(struct sockaddr_storage), }; struct torture_address srv_addr = { .sa_socklen = sizeof(struct sockaddr_storage), }; int rc; int s; (void) state; /* unused */ s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); assert_return_code(s, errno); /* Bind client address to wildcard address */ addr.sa.in.sin_family = AF_INET; rc = inet_pton(AF_INET, "127.0.0.20", &addr.sa.in.sin_addr); assert_int_equal(rc, 1); addr.sa.in.sin_port = htons(12345); rc = bind(s, &addr.sa.s, addr.sa_socklen); assert_return_code(rc, errno); rc = getsockname(s, &cli_addr.sa.s, &cli_addr.sa_socklen); assert_return_code(rc, errno); assert_sockaddr_port_equal(&cli_addr, "127.0.0.20", 12345); rc = getpeername(s, &srv_addr.sa.s, &srv_addr.sa_socklen); assert_int_equal(rc, -1); assert_int_equal(errno, ENOTCONN); /* connect */ addr = (struct torture_address) { .sa_socklen = sizeof(struct sockaddr_in), .sa.in = (struct sockaddr_in) { .sin_family = AF_INET, .sin_port = htons(torture_server_port()), }, }; rc = inet_pton(AF_INET, torture_server_address(AF_INET), &addr.sa.in.sin_addr); assert_int_equal(rc, 1); /* Connect */ rc = connect(s, &addr.sa.s, addr.sa_socklen); assert_return_code(rc, errno); cli_addr = (struct torture_address) { .sa_socklen = sizeof(struct sockaddr_storage), }; rc = getsockname(s, &cli_addr.sa.s, &cli_addr.sa_socklen); assert_return_code(rc, errno); assert_sockaddr_port_equal(&cli_addr, "127.0.0.20", 12345); srv_addr = (struct torture_address) { .sa_socklen = sizeof(struct sockaddr_storage), }; rc = getpeername(s, &srv_addr.sa.s, &srv_addr.sa_socklen); assert_return_code(rc, errno); assert_sockaddr_port_equal(&srv_addr, "127.0.0.10", 7); close(s); } static void test_connect_getsockname_getpeername_any(void **state) { struct torture_address addr = { .sa_socklen = sizeof(struct sockaddr_in), }; struct torture_address cli_addr = { .sa_socklen = sizeof(struct sockaddr_storage), }; struct torture_address srv_addr = { .sa_socklen = sizeof(struct sockaddr_storage), }; int rc; int s; (void) state; /* unused */ s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); assert_return_code(s, errno); /* Bind client address to wildcard address */ addr.sa.in.sin_family = AF_INET; addr.sa.in.sin_addr.s_addr = htonl(INADDR_ANY); rc = bind(s, &addr.sa.s, addr.sa_socklen); assert_return_code(rc, errno); rc = getsockname(s, &cli_addr.sa.s, &cli_addr.sa_socklen); assert_return_code(rc, errno); assert_sockaddr_port_range_equal(&cli_addr, "0.0.0.0", 1024, 65535); rc = getpeername(s, &srv_addr.sa.s, &srv_addr.sa_socklen); assert_int_equal(rc, -1); assert_int_equal(errno, ENOTCONN); /* connect */ addr.sa.in.sin_family = AF_INET; addr.sa.in.sin_port = htons(torture_server_port()); rc = inet_pton(AF_INET, torture_server_address(AF_INET), &addr.sa.in.sin_addr); assert_int_equal(rc, 1); /* Connect */ rc = connect(s, &addr.sa.s, addr.sa_socklen); assert_return_code(rc, errno); cli_addr = (struct torture_address) { .sa_socklen = sizeof(struct sockaddr_storage), }; rc = getsockname(s, &cli_addr.sa.s, &cli_addr.sa_socklen); assert_return_code(rc, errno); assert_sockaddr_port_range_equal(&cli_addr, "127.0.0.20", 1024, 65535); srv_addr = (struct torture_address) { .sa_socklen = sizeof(struct sockaddr_storage), }; rc = getpeername(s, &srv_addr.sa.s, &srv_addr.sa_socklen); assert_return_code(rc, errno); assert_sockaddr_port_equal(&srv_addr, "127.0.0.10", 7); close(s); } static void test_connect_getsockname_getpeername_any_port(void **state) { struct torture_address addr = { .sa_socklen = sizeof(struct sockaddr_in), }; struct torture_address cli_addr = { .sa_socklen = sizeof(struct sockaddr_storage), }; struct torture_address srv_addr = { .sa_socklen = sizeof(struct sockaddr_storage), }; int rc; int s; (void) state; /* unused */ s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); assert_return_code(s, errno); /* Bind client address to wildcard address */ addr.sa.in.sin_family = AF_INET; addr.sa.in.sin_addr.s_addr = htonl(INADDR_ANY); addr.sa.in.sin_port = htons(12345); rc = bind(s, &addr.sa.s, addr.sa_socklen); assert_return_code(rc, errno); rc = getsockname(s, &cli_addr.sa.s, &cli_addr.sa_socklen); assert_return_code(rc, errno); assert_sockaddr_port_equal(&cli_addr, "0.0.0.0", 12345); rc = getpeername(s, &srv_addr.sa.s, &srv_addr.sa_socklen); assert_int_equal(rc, -1); assert_int_equal(errno, ENOTCONN); /* connect */ addr.sa.in.sin_family = AF_INET; addr.sa.in.sin_port = htons(torture_server_port()); rc = inet_pton(AF_INET, torture_server_address(AF_INET), &addr.sa.in.sin_addr); assert_int_equal(rc, 1); /* Connect */ rc = connect(s, &addr.sa.s, addr.sa_socklen); assert_return_code(rc, errno); cli_addr = (struct torture_address) { .sa_socklen = sizeof(struct sockaddr_storage), }; rc = getsockname(s, &cli_addr.sa.s, &cli_addr.sa_socklen); assert_return_code(rc, errno); assert_sockaddr_port_equal(&cli_addr, "127.0.0.20", 12345); srv_addr = (struct torture_address) { .sa_socklen = sizeof(struct sockaddr_storage), }; rc = getpeername(s, &srv_addr.sa.s, &srv_addr.sa_socklen); assert_return_code(rc, errno); assert_sockaddr_port_equal(&srv_addr, "127.0.0.10", 7); close(s); } static void test_connect_getsockname_getpeername_len(void **state) { struct torture_address addr = { .sa_socklen = sizeof(struct sockaddr_in), }; struct torture_address cli_addr = { .sa_socklen = sizeof(struct sockaddr_storage), }; struct torture_address srv_addr = { .sa_socklen = sizeof(struct sockaddr_storage), }; socklen_t tmp_len; int rc; int s; (void) state; /* unused */ s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); assert_return_code(s, errno); /* connect */ addr.sa.in.sin_family = AF_INET; addr.sa.in.sin_port = htons(torture_server_port()); rc = inet_pton(AF_INET, torture_server_address(AF_INET), &addr.sa.in.sin_addr); assert_int_equal(rc, 1); /* Connect */ rc = connect(s, &addr.sa.s, addr.sa_socklen); assert_return_code(rc, errno); /* Check with len=0 */ cli_addr.sa_socklen = 0; rc = getsockname(s, &cli_addr.sa.s, &cli_addr.sa_socklen); assert_return_code(rc, errno); srv_addr.sa_socklen = 0; rc = getpeername(s, &srv_addr.sa.s, &srv_addr.sa_socklen); assert_return_code(rc, errno); /* Check with len=too small */ cli_addr = (struct torture_address) { .sa_socklen = sizeof(struct sockaddr_in) - 2, }; tmp_len = cli_addr.sa_socklen; rc = getsockname(s, &cli_addr.sa.s, &cli_addr.sa_socklen); assert_return_code(rc, errno); assert_int_equal(tmp_len + 2, cli_addr.sa_socklen); srv_addr = (struct torture_address) { .sa_socklen = sizeof(struct sockaddr_in) - 2, }; tmp_len = srv_addr.sa_socklen; rc = getpeername(s, &srv_addr.sa.s, &srv_addr.sa_socklen); assert_return_code(rc, errno); assert_int_equal(tmp_len + 2, srv_addr.sa_socklen); close(s); } int main(void) { int rc; const struct CMUnitTest sock_name_tests[] = { cmocka_unit_test_setup_teardown(test_connect_getsockname_getpeername, setup_echo_srv_tcp_ipv4, teardown), cmocka_unit_test_setup_teardown(test_connect_getsockname_getpeername_port, setup_echo_srv_tcp_ipv4, teardown), cmocka_unit_test_setup_teardown(test_connect_getsockname_getpeername_any, setup_echo_srv_tcp_ipv4, teardown), cmocka_unit_test_setup_teardown(test_connect_getsockname_getpeername_any_port, setup_echo_srv_tcp_ipv4, teardown), cmocka_unit_test_setup_teardown(test_connect_getsockname_getpeername_len, setup_echo_srv_tcp_ipv4, teardown), }; rc = cmocka_run_group_tests(sock_name_tests, NULL, NULL); return rc; } socket_wrapper-1.4.4/tests/test_sendmsg_recvmsg_fd.c000644 001750 000144 00000004664 14631527256 022761 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.4.4/tests/test_echo_tcp_bind.c000644 001750 000144 00000027421 14631527256 021676 0ustar00asnusers000000 000000 #include #include #include #include #include "config.h" #include "torture.h" #include #include #include #include #include #include #include #include #include #ifdef HAVE_RPC_RPC_H #include #endif static int setup_echo_srv_tcp_ipv4(void **state) { torture_setup_echo_srv_tcp_ipv4(state); return 0; } #ifdef HAVE_IPV6 static int setup_echo_srv_tcp_ipv6(void **state) { torture_setup_echo_srv_tcp_ipv6(state); return 0; } #endif static int teardown(void **state) { torture_teardown_echo_srv(state); return 0; } static void test_bind_ipv4(void **state) { struct torture_address addr = { .sa_socklen = sizeof(struct sockaddr_storage), }; struct torture_address addr_in = { .sa_socklen = sizeof(struct sockaddr_in), }; struct torture_address addr_un = { .sa_socklen = sizeof(struct sockaddr_un), }; int rc; int s; (void) state; /* unused */ s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); assert_return_code(s, errno); /* * Test various cases with family AF_UNSPEC */ /* UNSPEC, len == 1: EINVAL */ addr_in.sa.in = (struct sockaddr_in) { .sin_family = AF_UNSPEC, }; rc = bind(s, &addr.sa.s, 1); assert_int_equal(rc, -1); assert_int_equal(errno, EINVAL); /* UNSPEC: EAFNOSUPPORT */ addr_in.sa.in = (struct sockaddr_in) { .sin_family = AF_UNSPEC, }; rc = inet_pton(AF_INET, "127.0.0.20", &addr_in.sa.in.sin_addr); assert_int_equal(rc, 1); rc = bind(s, &addr_in.sa.s, addr_in.sa_socklen); assert_int_equal(rc, -1); /* FreeBSD uses EADDRNOTAVAIL here ... */ assert_true(errno == EAFNOSUPPORT || errno == EADDRNOTAVAIL); /* special case: AF_UNSPEC with INADDR_ANY: success mapped to AF_INET */ addr_in.sa.in = (struct sockaddr_in) { .sin_family = AF_UNSPEC, }; assert_int_equal(addr_in.sa.in.sin_addr.s_addr, htonl(INADDR_ANY)); rc = bind(s, &addr_in.sa.s, addr_in.sa_socklen); assert_return_code(rc, errno); close(s); s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); assert_return_code(s, errno); /* * Test various cases with family AF_UNIX * all fail with EAFNOSUPPORT */ addr.sa.ss = (struct sockaddr_storage) { .ss_family = AF_UNIX, }; rc = bind(s, &addr.sa.s, addr.sa_socklen); assert_int_equal(rc, -1); assert_int_equal(errno, EAFNOSUPPORT); addr_in.sa.in = (struct sockaddr_in) { .sin_family = AF_UNIX, }; rc = bind(s, &addr_in.sa.s, addr_in.sa_socklen); assert_int_equal(rc, -1); assert_int_equal(errno, EAFNOSUPPORT); addr_un.sa.un = (struct sockaddr_un) { .sun_family = AF_UNIX, }; rc = bind(s, &addr_un.sa.s, addr_un.sa_socklen); assert_int_equal(rc, -1); assert_int_equal(errno, EAFNOSUPPORT); #ifdef HAVE_IPV6 /* * Test with family AF_INET6 - fail */ addr_in.sa.in = (struct sockaddr_in) { .sin_family = AF_INET6, }; rc = bind(s, &addr_in.sa.s, addr_in.sa_socklen); assert_int_equal(rc, -1); assert_int_equal(errno, EAFNOSUPPORT); #endif /* * Finally, success binding a new IPv4 address. */ addr_in = (struct torture_address) { .sa_socklen = sizeof(struct sockaddr_in), .sa.in = (struct sockaddr_in) { .sin_family = AF_INET, }, }; rc = inet_pton(AF_INET, "127.0.0.20", &addr_in.sa.in.sin_addr); assert_int_equal(rc, 1); rc = bind(s, &addr_in.sa.s, addr_in.sa_socklen); assert_return_code(rc, errno); addr_in = (struct torture_address) { .sa_socklen = sizeof(struct sockaddr_in), .sa.in = (struct sockaddr_in) { .sin_family = AF_INET, .sin_port = htons(torture_server_port()), }, }; rc = inet_pton(AF_INET, torture_server_address(AF_INET), &addr_in.sa.in.sin_addr); assert_int_equal(rc, 1); rc = connect(s, &addr_in.sa.s, addr_in.sa_socklen); assert_return_code(rc, errno); close(s); } #if 0 /* TODO */ static void test_bind_ipv4_addr_in_use(void **state) { struct sockaddr_in sin, sin2; socklen_t slen = sizeof(struct sockaddr_in); int rc; int s, s2; (void) state; /* unused */ s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); assert_return_code(s, errno); /* * Try to bind to the same address as already bound by a * different process. */ /* Without specifying the port - success */ ZERO_STRUCT(sin); sin.sin_family = AF_INET; rc = inet_pton(AF_INET, torture_server_address(AF_INET), &sin.sin_addr); assert_int_equal(rc, 1); rc = bind(s, (struct sockaddr *)&sin, slen); assert_return_code(rc, errno); close(s); s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); assert_return_code(s, errno); #if 0 /* specify the same port - fail with EADDRINUSE. */ /* Not supported by socket_wrapper yet. ==> TODO! */ ZERO_STRUCT(sin); sin.sin_family = AF_INET, sin.sin_port = htons(torture_server_port()); rc = inet_pton(AF_INET, torture_server_address(AF_INET), &sin.sin_addr); assert_int_equal(rc, 1); rc = bind(s, (struct sockaddr *)&sin, slen); assert_int_equal(rc, -1); assert_int_equal(errno, EADDRINUSE); #endif /* * Try double binding when the firs bind is with port == 0 */ ZERO_STRUCT(sin); sin.sin_family = AF_INET; rc = inet_pton(AF_INET, "127.0.0.20", &sin.sin_addr); assert_int_equal(rc, 1); rc = bind(s, (struct sockaddr *)&sin, slen); assert_return_code(rc, errno); /* * Open a second socket locally and try to bind to the same address. */ /* Succeeds with port == 0 */ s2 = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); assert_return_code(s, errno); ZERO_STRUCT(sin2); sin2.sin_family = AF_INET; rc = inet_pton(AF_INET, "127.0.0.20", &sin2.sin_addr); assert_int_equal(rc, 1); rc = bind(s2, (struct sockaddr *)&sin2, slen); assert_return_code(rc, errno); close(s2); /* second bind with port != 0 - succeeds */ s2 = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); assert_return_code(s, errno); ZERO_STRUCT(sin2); sin2.sin_family = AF_INET; sin2.sin_port = htons(12345); rc = inet_pton(AF_INET, "127.0.0.20", &sin2.sin_addr); assert_int_equal(rc, 1); rc = bind(s2, (struct sockaddr *)&sin2, slen); assert_return_code(rc, errno); close(s2); close(s); /* * Try double binding when the first bind is with port != 0 */ s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); assert_return_code(s, errno); ZERO_STRUCT(sin); sin.sin_family = AF_INET; sin.sin_port = htons(12345); rc = inet_pton(AF_INET, "127.0.0.20", &sin.sin_addr); assert_int_equal(rc, 1); rc = bind(s, (struct sockaddr *)&sin, slen); assert_return_code(rc, errno); /* * Open a second socket locally and try to bind to the same address. */ /* Succeeds with port == 0 */ s2 = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); assert_return_code(s, errno); ZERO_STRUCT(sin2); sin2.sin_family = AF_INET; rc = inet_pton(AF_INET, "127.0.0.20", &sin2.sin_addr); assert_int_equal(rc, 1); rc = bind(s2, (struct sockaddr *)&sin2, slen); assert_return_code(rc, errno); close(s2); /* with same port as above - fail with EADDRINUSE */ s2 = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); assert_return_code(s, errno); ZERO_STRUCT(sin2); sin2.sin_family = AF_INET; sin2.sin_port = htons(12345); rc = inet_pton(AF_INET, "127.0.0.20", &sin2.sin_addr); assert_int_equal(rc, 1); rc = bind(s2, (struct sockaddr *)&sin2, slen); assert_int_equal(rc, -1); assert_int_equal(errno, EADDRINUSE); close(s); } #endif #ifdef HAVE_BINDRESVPORT static void test_bindresvport_ipv4(void **state) { struct torture_address addr = { .sa_socklen = sizeof(struct sockaddr_storage), }; int rc; int s; (void) state; /* unused */ s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); assert_return_code(s, errno); addr.sa.in.sin_family = AF_INET; rc = inet_pton(AF_INET, "127.0.0.20", &addr.sa.in.sin_addr); assert_int_equal(rc, 1); rc = bindresvport(s, &addr.sa.in); assert_return_code(rc, errno); addr = (struct torture_address) { .sa_socklen = sizeof(struct sockaddr_storage), .sa.in = (struct sockaddr_in) { .sin_family = AF_INET, .sin_port = htons(torture_server_port()), }, }; rc = inet_pton(AF_INET, torture_server_address(AF_INET), &addr.sa.in.sin_addr); assert_int_equal(rc, 1); rc = connect(s, &addr.sa.s, addr.sa_socklen); assert_return_code(rc, errno); close(s); } static void test_bindresvport_ipv4_null(void **state) { struct torture_address addr = { .sa_socklen = sizeof(struct sockaddr_in), }; int rc; int s; (void) state; /* unused */ s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); assert_return_code(s, errno); rc = bindresvport(s, NULL); assert_return_code(rc, errno); addr.sa.in.sin_family = AF_INET; addr.sa.in.sin_port = htons(torture_server_port()); rc = inet_pton(AF_INET, torture_server_address(AF_INET), &addr.sa.in.sin_addr); assert_int_equal(rc, 1); rc = connect(s, &addr.sa.s, addr.sa_socklen); assert_return_code(rc, errno); close(s); } #endif /* HAVE_BINDRESVPORT */ #ifdef HAVE_IPV6 static void test_bind_on_ipv6_sock(void **state) { struct torture_address addr_in = { .sa_socklen = sizeof(struct sockaddr_in), }; struct torture_address addr_un = { .sa_socklen = sizeof(struct sockaddr_un), }; int rc; int s; (void) state; /* unused */ s = socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP); assert_return_code(s, errno); addr_un.sa.un.sun_family = AF_UNIX; rc = bind(s, &addr_un.sa.s, addr_un.sa_socklen); assert_int_equal(rc, -1); /* FreeBSD uses EINVAL here... */ assert_true(errno == EAFNOSUPPORT || errno == EINVAL); addr_in.sa.in.sin_family = AF_INET; rc = bind(s, &addr_in.sa.s, addr_in.sa_socklen); assert_int_equal(rc, -1); assert_int_equal(errno, EINVAL); addr_in.sa.in = (struct sockaddr_in) { .sin_family = AF_INET, }; rc = inet_pton(AF_INET, "127.0.0.20", &addr_in.sa.in.sin_addr); assert_int_equal(rc, 1); rc = bind(s, &addr_in.sa.s, addr_in.sa_socklen); assert_int_equal(rc, -1); assert_int_equal(errno, EINVAL); addr_in = (struct torture_address) { .sa_socklen = sizeof(struct sockaddr_in6), .sa.in = (struct sockaddr_in) { .sin_family = AF_INET, }, }; rc = bind(s, &addr_in.sa.s, addr_in.sa_socklen); assert_int_equal(rc, -1); assert_int_equal(errno, EAFNOSUPPORT); close(s); } #ifdef HAVE_BINDRESVPORT static void test_bindresvport_on_ipv6_sock(void **state) { struct sockaddr_in sin; int rc; int s; (void) state; /* unused */ s = socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP); assert_return_code(s, errno); ZERO_STRUCT(sin); sin.sin_family = AF_INET; rc = inet_pton(AF_INET, "127.0.0.20", &sin.sin_addr); assert_int_equal(rc, 1); rc = bindresvport(s, &sin); assert_int_equal(rc, -1); assert_int_equal(errno, EINVAL); close(s); } static void test_bindresvport_on_ipv6_sock_null(void **state) { int rc; int s; (void) state; /* unused */ s = socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP); assert_return_code(s, errno); rc = bindresvport(s, NULL); assert_return_code(rc, errno); close(s); } #endif /* HAVE_BINDRESVPORT */ #endif /* HAVE_IPV6 */ int main(void) { int rc; const struct CMUnitTest tcp_bind_tests[] = { cmocka_unit_test_setup_teardown(test_bind_ipv4, setup_echo_srv_tcp_ipv4, teardown), #if 0 /* TODO */ cmocka_unit_test_setup_teardown(test_bind_ipv4_addr_in_use, setup_echo_srv_tcp_ipv4, teardown), #endif #ifdef HAVE_BINDRESVPORT cmocka_unit_test_setup_teardown(test_bindresvport_ipv4, setup_echo_srv_tcp_ipv4, teardown), cmocka_unit_test_setup_teardown(test_bindresvport_ipv4_null, setup_echo_srv_tcp_ipv4, teardown), #endif /* HAVE_BINDRESVPORT */ #ifdef HAVE_IPV6 cmocka_unit_test_setup_teardown(test_bind_on_ipv6_sock, setup_echo_srv_tcp_ipv6, teardown), #ifdef HAVE_BINDRESVPORT cmocka_unit_test_setup_teardown(test_bindresvport_on_ipv6_sock, setup_echo_srv_tcp_ipv6, teardown), cmocka_unit_test_setup_teardown(test_bindresvport_on_ipv6_sock_null, setup_echo_srv_tcp_ipv6, teardown), #endif /* HAVE_BINDRESVPORT */ #endif /* HAVE_IPV6 */ }; rc = cmocka_run_group_tests(tcp_bind_tests, NULL, NULL); return rc; } socket_wrapper-1.4.4/tests/valgrind.supp000644 001750 000144 00000000435 14631527256 020426 0ustar00asnusers000000 000000 ### GLIBC { glibc_dlopen_alloc Memcheck:Leak fun:calloc fun:_dlerror_run fun:dlopen } { glibc_dlclose_alloc Memcheck:Leak fun:calloc fun:_dlerror_run fun:dlclose } { glibc_dlsym_alloc Memcheck:Leak fun:calloc fun:_dlerror_run fun:dlsym } socket_wrapper-1.4.4/tests/test_thread_sockets.c000644 001750 000144 00000002265 14631527256 022117 0ustar00asnusers000000 000000 #include "config.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #define NUM_THREADS 10 static void *thread_worker(void *arg) { int i; (void) arg; /* unused */ for (i = 0; i < 1000; i++) { int s; s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); assert_return_code(s, errno); close(s); } return NULL; } static void test_threads_socket(void **state) { pthread_attr_t pthread_custom_attr; pthread_t threads[NUM_THREADS]; int i; (void) state; /* unused */ pthread_attr_init(&pthread_custom_attr); for (i = 0; i < NUM_THREADS; i++) { pthread_create(&threads[i], &pthread_custom_attr, thread_worker, NULL); } for (i = 0; i < NUM_THREADS; i++) { pthread_join(threads[i], NULL); } pthread_attr_destroy(&pthread_custom_attr); } int main(void) { int rc; const struct CMUnitTest thread_tests[] = { cmocka_unit_test(test_threads_socket), }; rc = cmocka_run_group_tests(thread_tests, NULL, NULL); return rc; } socket_wrapper-1.4.4/tests/test_thread_echo_tcp_connect.c000644 001750 000144 00000003430 14631527256 023734 0ustar00asnusers000000 000000 #include #include #include #include #include #include "config.h" #include "torture.h" #include #include #include #include #include #include #include #include #define NUM_THREADS 10 static int setup_echo_srv_tcp_ipv4(void **state) { torture_setup_echo_srv_tcp_ipv4(state); return 0; } static int teardown(void **state) { torture_teardown_echo_srv(state); return 0; } static void *thread_worker(void *arg) { struct torture_address addr = { .sa_socklen = sizeof(struct sockaddr_in), }; int rc; int s; (void) arg; /* unused */ s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); assert_int_not_equal(s, -1); addr.sa.in.sin_family = AF_INET; addr.sa.in.sin_port = htons(torture_server_port()); rc = inet_pton(addr.sa.in.sin_family, torture_server_address(AF_INET), &addr.sa.in.sin_addr); assert_int_equal(rc, 1); rc = connect(s, &addr.sa.s, addr.sa_socklen); assert_return_code(rc, errno); close(s); return NULL; } static void test_connect_ipv4(void **state) { pthread_attr_t pthread_custom_attr; pthread_t threads[NUM_THREADS]; int i; (void) state; /* unused */ pthread_attr_init(&pthread_custom_attr); for (i = 0; i < NUM_THREADS; i++) { pthread_create(&threads[i], &pthread_custom_attr, thread_worker, NULL); } for (i = 0; i < NUM_THREADS; i++) { pthread_join(threads[i], NULL); } pthread_attr_destroy(&pthread_custom_attr); } int main(void) { int rc; const struct CMUnitTest tcp_connect_tests[] = { cmocka_unit_test(test_connect_ipv4), }; rc = cmocka_run_group_tests(tcp_connect_tests, setup_echo_srv_tcp_ipv4, teardown); return rc; } socket_wrapper-1.4.4/tests/swrap_fake_uid_wrapper.c000644 001750 000144 00000001344 14632503553 022571 0ustar00asnusers000000 000000 #include "config.h" #include #include #include #include #include #include #include #include #include #ifdef HAVE_SYS_SYSCALL_H #include #endif #ifdef HAVE_SYSCALL_H #include #endif #include "swrap_fake_uid_wrapper.h" /* simulate uid_wrapper hooks */ bool uid_wrapper_syscall_valid(long int sysno) { if (sysno >= __FAKE_UID_WRAPPER_SYSCALL_NO) { return true; } return false; } long int uid_wrapper_syscall_va(long int sysno, va_list va) { (void) va; /* unused */ if (sysno == __FAKE_UID_WRAPPER_SYSCALL_NO) { errno = 0; return __FAKE_UID_WRAPPER_SYSCALL_RC; } errno = ENOSYS; return -1; } socket_wrapper-1.4.4/tests/test_tcp_listen.c000644 001750 000144 00000004630 14631527256 021257 0ustar00asnusers000000 000000 #include #include #include #include #include "config.h" #include "torture.h" #include #include #include #include #include #include #include #include #include #ifdef HAVE_RPC_RPC_H #include #endif static int setup(void **state) { torture_setup_socket_dir(state); return 0; } static int teardown(void **state) { torture_teardown_socket_dir(state); return 0; } static void test_listen_unbound_ipv4(void **state) { struct torture_address addr = { .sa_socklen = sizeof(struct sockaddr_storage), }; int rc; int s1; int s2; (void) state; /* unused */ s1 = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); assert_return_code(s1, errno); rc = listen(s1, SOMAXCONN); assert_return_code(rc, errno); rc = getsockname(s1, &addr.sa.s, &addr.sa_socklen); assert_return_code(rc, errno); assert_int_equal(addr.sa.in.sin_family, AF_INET); assert_int_equal(addr.sa_socklen, sizeof(struct sockaddr_in)); assert_in_range(ntohs(addr.sa.in.sin_port), 1024, 65535); s2 = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); assert_return_code(s2, errno); rc = connect(s2, &addr.sa.s, addr.sa_socklen); assert_return_code(rc, errno); close(s1); close(s2); } #ifdef HAVE_IPV6 static void test_listen_unbound_ipv6(void **state) { struct torture_address addr = { .sa_socklen = sizeof(struct sockaddr_storage), }; int rc; int s1; int s2; (void) state; /* unused */ s1 = socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP); assert_return_code(s1, errno); rc = listen(s1, SOMAXCONN); assert_return_code(rc, errno); rc = getsockname(s1, &addr.sa.s, &addr.sa_socklen); assert_return_code(rc, errno); assert_int_equal(addr.sa.in6.sin6_family, AF_INET6); assert_int_equal(addr.sa_socklen, sizeof(struct sockaddr_in6)); assert_in_range(ntohs(addr.sa.in6.sin6_port), 1024, 65535); s2 = socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP); assert_return_code(s2, errno); rc = connect(s2, &addr.sa.s, addr.sa_socklen); assert_return_code(rc, errno); close(s1); close(s2); } #endif /* HAVE_IPV6 */ int main(void) { int rc; const struct CMUnitTest tcp_listen_tests[] = { cmocka_unit_test(test_listen_unbound_ipv4), #ifdef HAVE_IPV6 cmocka_unit_test(test_listen_unbound_ipv6), #endif /* HAVE_IPV6 */ }; rc = cmocka_run_group_tests(tcp_listen_tests, setup, teardown); return rc; } socket_wrapper-1.4.4/tests/torture.c000644 001750 000144 00000015376 14631527256 017571 0ustar00asnusers000000 000000 /* * Copyright (C) Andreas Schneider 2013 * * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * 3. Neither the name of the author nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include "config.h" #include "torture.h" #include #include #include #include #include #include #include #include #include #include #include #include #define TORTURE_ECHO_SRV_IPV4 "127.0.0.10" /* socket wrapper IPv6 prefix fd00::5357:5fxx */ #define TORTURE_ECHO_SRV_IPV6 "fd00::5357:5f0a" #define TORTURE_ECHO_SRV_PORT 7 #define TORTURE_SOCKET_DIR "/tmp/w_XXXXXX" #define TORTURE_ECHO_SRV_PIDFILE "echo_srv.pid" #define TORTURE_PCAP_FILE "socket_trace.pcap" const char *torture_server_address(int family) { switch (family) { case AF_INET: { const char *ip4 = getenv("TORTURE_SERVER_ADDRESS_IPV4"); if (ip4 != NULL && ip4[0] != '\0') { return ip4; } return TORTURE_ECHO_SRV_IPV4; } #ifdef HAVE_IPV6 case AF_INET6: { const char *ip6 = getenv("TORTURE_SERVER_ADDRESS_IPV6"); if (ip6 != NULL && ip6[0] != '\0') { return ip6; } return TORTURE_ECHO_SRV_IPV6; } #endif default: return NULL; } return NULL; } int torture_server_port(void) { char *env = getenv("TORTURE_SERVER_PORT"); if (env != NULL && env[0] != '\0' && strlen(env) < 6) { int port = atoi(env); if (port > 0 && port < 65536) { return port; } } return TORTURE_ECHO_SRV_PORT; } void torture_setup_socket_dir(void **state) { struct torture_state *s; const char *p; size_t len; s = malloc(sizeof(struct torture_state)); assert_non_null(s); s->socket_dir = strdup(TORTURE_SOCKET_DIR); assert_non_null(s->socket_dir); p = mkdtemp(s->socket_dir); assert_non_null(p); /* pcap file */ len = strlen(p) + 1 + strlen(TORTURE_PCAP_FILE) + 1; s->pcap_file = malloc(len); assert_non_null(s->pcap_file); snprintf(s->pcap_file, len, "%s/%s", p, TORTURE_PCAP_FILE); /* pid file */ len = strlen(p) + 1 + strlen(TORTURE_ECHO_SRV_PIDFILE) + 1; s->srv_pidfile = malloc(len); assert_non_null(s->srv_pidfile); snprintf(s->srv_pidfile, len, "%s/%s", p, TORTURE_ECHO_SRV_PIDFILE); setenv("SOCKET_WRAPPER_DIR", p, 1); setenv("SOCKET_WRAPPER_DEFAULT_IFACE", "170", 1); setenv("SOCKET_WRAPPER_PCAP_FILE", s->pcap_file, 1); *state = s; } static void torture_setup_echo_srv_ip(void **state, const char *ip, int port, int type) { struct torture_state *s; char start_echo_srv[1024] = {0}; const char *t; int count = 0; int rc; torture_setup_socket_dir(state); s = *state; switch (type) { case SOCK_STREAM: t = "-t"; break; case SOCK_DGRAM: t = "-u"; break; default: t = ""; break; } /* set default iface for the server */ setenv("SOCKET_WRAPPER_DEFAULT_IFACE", "10", 1); snprintf(start_echo_srv, sizeof(start_echo_srv), "%s/tests/echo_srv -b %s -p %d -D %s --pid %s", BINARYDIR, ip, port, t, s->srv_pidfile); rc = system(start_echo_srv); assert_int_equal(rc, 0); do { struct stat sb; count++; if (count > 20) { break; } rc = stat(s->srv_pidfile, &sb); usleep(50000L); /* 0.05s * 20 */ } while (rc != 0); assert_int_equal(rc, 0); /* set default iface for the client */ setenv("SOCKET_WRAPPER_DEFAULT_IFACE", "170", 1); } void torture_setup_echo_srv_udp_ipv4(void **state) { torture_setup_echo_srv_ip(state, "0.0.0.0", torture_server_port(), SOCK_DGRAM); } void torture_setup_echo_srv_udp_ipv6(void **state) { torture_setup_echo_srv_ip(state, "::", torture_server_port(), SOCK_DGRAM); } void torture_setup_echo_srv_tcp_ipv4(void **state) { torture_setup_echo_srv_ip(state, "0.0.0.0", torture_server_port(), SOCK_STREAM); } void torture_setup_echo_srv_tcp_ipv6(void **state) { torture_setup_echo_srv_ip(state, "::", torture_server_port(), SOCK_STREAM); } void torture_teardown_socket_dir(void **state) { struct torture_state *s = *state; char *env = getenv("TORTURE_SKIP_CLEANUP"); char remove_cmd[1024] = {0}; int rc; if (env != NULL && env[0] == '1') { fprintf(stderr, ">>> Skipping cleanup of %s", s->socket_dir); } else { snprintf(remove_cmd, sizeof(remove_cmd), "rm -rf %s", s->socket_dir); rc = system(remove_cmd); if (rc < 0) { fprintf(stderr, "%s failed: %s", remove_cmd, strerror(errno)); } } free(s->socket_dir); free(s->pcap_file); free(s->srv_pidfile); free(s); } void torture_teardown_echo_srv(void **state) { struct torture_state *s = *state; char buf[12] = {0}; /* -2147483648 + null byte */ 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'; errno = 0; pid = strtol(buf, NULL, 10); if (pid == 0 || errno != 0) { goto done; } for (count = 0; count < 10; count++) { /* Make sure the daemon goes away! */ kill(pid, SIGTERM); usleep(5000); rc = kill(pid, 0); if (rc != 0) { is_running = false; break; } } if (is_running) { fprintf(stderr, "WARNING the echo server is still running!\n"); } done: torture_teardown_socket_dir(state); } void torture_generate_random_buffer(uint8_t *out, int len) { int i; srand(time(NULL)); for (i = 0; i < len; i++) { out[i] = (uint8_t)rand(); } } socket_wrapper-1.4.4/tests/test_max_sockets.c000644 001750 000144 00000002714 14631527256 021434 0ustar00asnusers000000 000000 #include "torture.h" #include #include #include #include #include #define MAX_SOCKETS 4 static int setup(void **state) { int ret; char str[10]; torture_setup_socket_dir(state); ret = snprintf(str, 10, "%d", MAX_SOCKETS); if (ret < 0) { return ret; } ret = setenv("SOCKET_WRAPPER_MAX_SOCKETS", str, 1); return ret; } static int teardown(void **state) { torture_teardown_socket_dir(state); return 0; } static int _socket(int *_s) { int s; s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (s < 0) { return -1; } *_s = s; return 0; } static void test_max_sockets(void **state) { int rc; int s[MAX_SOCKETS+1] = { 0 }; int i; (void) state; /* unused */ for (i = 0; i < MAX_SOCKETS; i++) { rc = _socket(&s[i]); assert_return_code(rc, errno); } /* no free space for sockets left */ rc = _socket(&s[MAX_SOCKETS]); assert_int_equal(rc, -1); assert_int_equal(errno, ENFILE); /* closing a socket frees up space */ close(s[0]); rc = _socket(&s[0]); assert_return_code(rc, errno); /* but just one */ rc = _socket(&s[MAX_SOCKETS]); assert_int_equal(rc, -1); assert_int_equal(errno, ENFILE); for (i = 0; i < MAX_SOCKETS; i++) { close(s[i]); } } int main(void) { int rc; const struct CMUnitTest max_sockets_tests[] = { cmocka_unit_test_setup_teardown(test_max_sockets, setup, teardown), }; rc = cmocka_run_group_tests(max_sockets_tests, NULL, NULL); return rc; } socket_wrapper-1.4.4/tests/swrap_fake_uid_wrapper.h000644 001750 000144 00000000407 14631527256 022602 0ustar00asnusers000000 000000 #include /* simulate socket_wrapper hooks */ #define __FAKE_UID_WRAPPER_SYSCALL_NO 123456789 #define __FAKE_UID_WRAPPER_SYSCALL_RC 987654321 bool uid_wrapper_syscall_valid(long int sysno); long int uid_wrapper_syscall_va(long int sysno, va_list va); socket_wrapper-1.4.4/tests/helgrind.supp000644 001750 000144 00000000477 14631527256 020422 0ustar00asnusers000000 000000 # The swrap_bind_symbol_lib* macros have a thread race condition on purpose! # # As an optimization we do not lock the access. However if the obj is not # bound, we lock it with a mutex and reread it again. And binding the symbol is # protected. { SWRAP_SYMBOL_ACCESS Helgrind:Race fun:libc_* fun:swrap_* } socket_wrapper-1.4.4/tests/test_echo_tcp_write_read.c000644 001750 000144 00000010057 14631527256 023104 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_size(void **state, size_t size) { struct torture_address addr = { .sa_socklen = sizeof(struct sockaddr_in), }; char send_buf[size]; char recv_buf[size]; 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); memset(send_buf, 0, sizeof(send_buf)); for (i = 0; i < 10; i++) { size_t nread = 0, nwrote = 0; snprintf(send_buf, sizeof(send_buf), "packet.%d", i); do { ret = write(s, send_buf + nwrote, sizeof(send_buf) - nwrote); assert_int_not_equal(ret, -1); nwrote += ret; ret = read(s, recv_buf + nread, sizeof(recv_buf) - nread); assert_int_not_equal(ret, -1); nread += ret; } while (nread < sizeof(recv_buf) && nwrote < sizeof(send_buf)); assert_int_equal(nread, sizeof(send_buf)); assert_memory_equal(send_buf, recv_buf, sizeof(send_buf)); } close(s); } static void test_write_read_ipv4(void **state) { test_write_read_ipv4_size(state, 64); } static void test_write_read_ipv4_large(void **state) { test_write_read_ipv4_size(state, 2000); } #ifdef HAVE_IPV6 static void test_write_read_ipv6_size(void **state, size_t size) { struct torture_address addr = { .sa_socklen = sizeof(struct sockaddr_in6), }; char send_buf[size]; char recv_buf[size]; 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); memset(send_buf, 0, sizeof(send_buf)); for (i = 0; i < 10; i++) { size_t nread = 0, nwrote = 0; snprintf(send_buf, sizeof(send_buf), "packet.%d", i); do { ret = write(s, send_buf + nwrote, sizeof(send_buf) - nwrote); assert_int_not_equal(ret, -1); nwrote += ret; ret = read(s, recv_buf + nread, sizeof(recv_buf) - nread); assert_int_not_equal(ret, -1); nread += ret; } while (nread < sizeof(recv_buf) && nwrote < sizeof(send_buf)); assert_int_equal(nread, sizeof(send_buf)); assert_memory_equal(send_buf, recv_buf, sizeof(send_buf)); } close(s); } static void test_write_read_ipv6(void **state) { test_write_read_ipv6_size(state, 64); } static void test_write_read_ipv6_large(void **state) { test_write_read_ipv6_size(state, 2000); } #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), cmocka_unit_test_setup_teardown(test_write_read_ipv4_large, setup_echo_srv_tcp_ipv4, teardown), #ifdef HAVE_IPV6 cmocka_unit_test_setup_teardown(test_write_read_ipv6, setup_echo_srv_tcp_ipv6, teardown), cmocka_unit_test_setup_teardown(test_write_read_ipv6_large, setup_echo_srv_tcp_ipv6, teardown), #endif }; rc = cmocka_run_group_tests(tcp_write_tests, NULL, NULL); return rc; } socket_wrapper-1.4.4/tests/test_ioctl.c000644 001750 000144 00000003773 14632503553 020227 0ustar00asnusers000000 000000 #include #include #include #include #include #include #include #include #include #include #include #include #include #ifndef PATH_MAX #define PATH_MAX 4096 #endif 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.4.4/tests/test_tcp_socket_overwrite.c000644 001750 000144 00000002440 14631527256 023354 0ustar00asnusers000000 000000 #include "torture.h" #include #include #include #include static int setup(void **state) { torture_setup_socket_dir(state); return 0; } static int teardown(void **state) { torture_teardown_socket_dir(state); return 0; } static void test_tcp_socket_overwrite(void **state) { struct torture_address addr_in = { .sa_socklen = sizeof(struct sockaddr_in), .sa.in = (struct sockaddr_in) { .sin_family = AF_INET, }, }; int s, dup_s, new_s, rc; (void) state; /* unused */ s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); assert_int_not_equal(s, -1); dup_s = dup(s); assert_int_not_equal(dup_s, -1); close(dup_s); new_s = socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP); assert_int_not_equal(new_s, -1); close(new_s); rc = inet_pton(AF_INET, "127.0.0.20", &addr_in.sa.in.sin_addr); assert_int_equal(rc, 1); /* bind should fail during socklen check if old socket info * is overwritten by new socket info */ rc = bind(s, &addr_in.sa.s, addr_in.sa_socklen); assert_return_code(rc, errno); close(s); } int main(void) { int rc; const struct CMUnitTest tcp_socket_overwrite_tests[] = { cmocka_unit_test(test_tcp_socket_overwrite), }; rc = cmocka_run_group_tests(tcp_socket_overwrite_tests, setup, teardown); return rc; } socket_wrapper-1.4.4/tests/test_fcntl_lock.c000644 001750 000144 00000004156 14632503553 021227 0ustar00asnusers000000 000000 #include "torture.h" #include #include #include #include #include #include #include #include #ifndef PATH_MAX #define PATH_MAX 4096 #endif 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); 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_fcntl_lock(void **state) { char file[PATH_MAX]; char buf[16]; int fd, rc, len; char *s = (char *)*state; struct flock lock = { .l_type = F_WRLCK, .l_whence = SEEK_SET, .l_start = 0, .l_len = 1, }; int cmd = F_SETLK; /* Prefer OFD locks on Linux with _GNU_SOURCE set */ #ifdef F_OFD_SETLK if (sizeof(lock) >= 24) { cmd = F_OFD_SETLK; } #endif printf("sizeof(lock)=%zu\n", sizeof(lock)); #ifdef __USE_LARGEFILE64 printf("__USE_LARGEFILE64\n"); #endif #ifdef __USE_FILE_OFFSET64 printf("__USE_FILE_OFFSET64\n"); #endif rc = snprintf(file, sizeof(file), "%s/file", s); assert_in_range(rc, 0, PATH_MAX); fd = open(file, O_RDWR|O_CREAT, 0600); assert_return_code(fd, errno); rc = fcntl(fd, cmd, &lock); assert_return_code(rc, errno); len = snprintf(buf, sizeof(buf), "fd=%d\n", fd); assert_in_range(len, 0, sizeof(buf)); rc = write(fd, buf, len); assert_return_code(rc, errno); lock.l_type = F_UNLCK; rc = fcntl(fd, cmd, &lock); assert_return_code(rc, errno); rc = unlink(file); assert_return_code(rc, errno); rc = close(fd); assert_return_code(rc, errno); } int main(void) { int rc; const struct CMUnitTest tcp_fcntl_lock_tests[] = { cmocka_unit_test(test_fcntl_lock), }; rc = cmocka_run_group_tests(tcp_fcntl_lock_tests, setup, teardown); return rc; } socket_wrapper-1.4.4/tests/test_echo_tcp_writev_readv.c000644 001750 000144 00000007355 14631527256 023467 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.4.4/tests/test_echo_tcp_sendmsg_recvmsg.c000644 001750 000144 00000013006 14631527256 024142 0ustar00asnusers000000 000000 #include #include #include #include #include "config.h" #include "torture.h" #include #include #include #include #include #include #include #include static int setup_echo_srv_tcp_ipv4(void **state) { torture_setup_echo_srv_tcp_ipv4(state); return 0; } #ifdef HAVE_IPV6 static int setup_echo_srv_tcp_ipv6(void **state) { torture_setup_echo_srv_tcp_ipv6(state); return 0; } #endif static int teardown(void **state) { torture_teardown_echo_srv(state); return 0; } static void test_sendmsg_recvmsg_ipv4(void **state) { struct torture_address addr = { .sa_socklen = sizeof(struct sockaddr_storage), }; char send_buf[64] = {0}; char recv_buf[64] = {0}; ssize_t ret; int rc; int i; int s; (void) state; /* unused */ s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); assert_int_not_equal(s, -1); addr.sa.in.sin_family = AF_INET; addr.sa.in.sin_port = htons(torture_server_port()); rc = inet_pton(AF_INET, torture_server_address(AF_INET), &addr.sa.in.sin_addr); assert_int_equal(rc, 1); rc = connect(s, &addr.sa.s, addr.sa_socklen); assert_return_code(rc, errno); for (i = 0; i < 10; i++) { struct torture_address reply_addr = { .sa_socklen = sizeof(struct sockaddr_storage), }; struct msghdr s_msg = { .msg_namelen = 0, }; struct msghdr r_msg = { .msg_namelen = 0, }; struct iovec s_iov; struct iovec r_iov; snprintf(send_buf, sizeof(send_buf), "packet.%d", i); /* This should be ignored */ rc = inet_pton(AF_INET, "127.0.0.1", &addr.sa.in.sin_addr); assert_int_equal(rc, 1); s_msg.msg_name = &addr.sa.s; s_msg.msg_namelen = addr.sa_socklen; s_iov.iov_base = send_buf; s_iov.iov_len = sizeof(send_buf); s_msg.msg_iov = &s_iov; s_msg.msg_iovlen = 1; ret = sendmsg(s, &s_msg, 0); assert_int_not_equal(ret, -1); r_msg.msg_name = &reply_addr.sa.s; r_msg.msg_namelen = reply_addr.sa_socklen; r_iov.iov_base = recv_buf; r_iov.iov_len = sizeof(recv_buf); r_msg.msg_iov = &r_iov; r_msg.msg_iovlen = 1; ret = recvmsg(s, &r_msg, 0); assert_int_not_equal(ret, -1); assert_int_equal(r_msg.msg_namelen, 0); assert_memory_equal(send_buf, recv_buf, sizeof(send_buf)); } close(s); } #ifdef HAVE_IPV6 static void test_sendmsg_recvmsg_ipv6(void **state) { struct torture_address addr = { .sa_socklen = sizeof(struct sockaddr_storage), }; char send_buf[64] = {0}; char recv_buf[64] = {0}; ssize_t ret; int rc; int i; int s; (void) state; /* unused */ s = socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP); assert_int_not_equal(s, -1); addr.sa.in.sin_family = AF_INET6; addr.sa.in.sin_port = htons(torture_server_port()); rc = inet_pton(AF_INET6, torture_server_address(AF_INET6), &addr.sa.in6.sin6_addr); assert_int_equal(rc, 1); rc = connect(s, &addr.sa.s, addr.sa_socklen); assert_return_code(rc, errno); for (i = 0; i < 10; i++) { struct torture_address reply_addr = { .sa_socklen = sizeof(struct sockaddr_in), }; struct msghdr s_msg = { .msg_namelen = 0, }; struct msghdr r_msg = { .msg_namelen = 0, }; struct iovec s_iov; struct iovec r_iov; snprintf(send_buf, sizeof(send_buf), "packet.%d", i); s_iov.iov_base = send_buf; s_iov.iov_len = sizeof(send_buf); s_msg.msg_iov = &s_iov; s_msg.msg_iovlen = 1; ret = sendmsg(s, &s_msg, 0); assert_int_not_equal(ret, -1); r_msg.msg_name = &reply_addr.sa.s; r_msg.msg_namelen = reply_addr.sa_socklen; r_iov.iov_base = recv_buf; r_iov.iov_len = sizeof(recv_buf); r_msg.msg_iov = &r_iov; r_msg.msg_iovlen = 1; ret = recvmsg(s, &r_msg, 0); assert_int_not_equal(ret, -1); assert_int_equal(r_msg.msg_namelen, 0); assert_memory_equal(send_buf, recv_buf, sizeof(send_buf)); } close(s); } #endif static void test_sendmsg_recvmsg_ipv4_null(void **state) { struct torture_address send_addr = { .sa_socklen = sizeof(struct sockaddr_storage), }; struct msghdr s_msg = { .msg_namelen = 0, }; struct msghdr r_msg = { .msg_namelen = 0, }; struct iovec iov; char payload[] = "PACKET"; ssize_t ret; int rc; int s; (void)state; /* unused */ s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); assert_int_not_equal(s, -1); send_addr.sa.in.sin_family = AF_INET; send_addr.sa.in.sin_port = htons(torture_server_port()); rc = inet_pton(AF_INET, torture_server_address(AF_INET), &send_addr.sa.in.sin_addr); assert_int_equal(rc, 1); rc = connect(s, &send_addr.sa.s, send_addr.sa_socklen); assert_return_code(rc, errno); /* msg_name = NULL */ iov.iov_base = (void *)payload; iov.iov_len = sizeof(payload); s_msg.msg_iov = &iov; s_msg.msg_iovlen = 1; ret = sendmsg(s, &s_msg, 0); assert_int_not_equal(ret, -1); /* msg_name = NULL */ memset(payload, 0, sizeof(payload)); r_msg.msg_iov = &iov; r_msg.msg_iovlen = 1; ret = recvmsg(s, &r_msg, 0); assert_int_not_equal(ret, -1); assert_int_equal(r_msg.msg_namelen, 0); assert_null(r_msg.msg_name); close(s); } int main(void) { int rc; const struct CMUnitTest sendmsg_tests[] = { cmocka_unit_test_setup_teardown(test_sendmsg_recvmsg_ipv4, setup_echo_srv_tcp_ipv4, teardown), cmocka_unit_test_setup_teardown(test_sendmsg_recvmsg_ipv4_null, setup_echo_srv_tcp_ipv4, teardown), #ifdef HAVE_IPV6 cmocka_unit_test_setup_teardown(test_sendmsg_recvmsg_ipv6, setup_echo_srv_tcp_ipv6, teardown), #endif }; rc = cmocka_run_group_tests(sendmsg_tests, NULL, NULL); return rc; } socket_wrapper-1.4.4/tests/test_public_functions.c000644 001750 000144 00000004175 14631527256 022465 0ustar00asnusers000000 000000 #include "torture.h" #include #include #include #include #include #include static int setup_enabled(void **state) { torture_setup_socket_dir(state); return 0; } static int teardown_enabled(void **state) { torture_teardown_socket_dir(state); return 0; } static int setup_disabled(void **state) { (void) state; /* unused */ unsetenv("SOCKET_WRAPPER_DIR"); unsetenv("SOCKET_WRAPPER_DEFAULT_IFACE"); unsetenv("SOCKET_WRAPPER_PCAP_FILE"); return 0; } static int teardown_disabled(void **state) { (void) state; /* unused */ return 0; } static void test_call_enabled_true(void **state) { char *s = getenv("SOCKET_WRAPPER_DIR"); (void) state; /* unused */ assert_true(socket_wrapper_enabled()); assert_true(s != NULL); } static void test_call_enabled_false(void **state) { char *s = getenv("SOCKET_WRAPPER_DIR"); (void) state; /* unused */ assert_false(socket_wrapper_enabled()); assert_false(s != NULL); } static void test_call_indicate_no_inet_fd(void **state) { int rc; int s = -1; (void) state; /* unused */ socket_wrapper_indicate_no_inet_fd(987654321); socket_wrapper_indicate_no_inet_fd(-1); rc = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (rc >= 0) { s = rc; rc = 0; } assert_return_code(rc, errno); socket_wrapper_indicate_no_inet_fd(987654321); socket_wrapper_indicate_no_inet_fd(-1); socket_wrapper_indicate_no_inet_fd(s); socket_wrapper_indicate_no_inet_fd(0); socket_wrapper_indicate_no_inet_fd(1); socket_wrapper_indicate_no_inet_fd(2); } int main(void) { int rc; const struct CMUnitTest max_sockets_tests[] = { cmocka_unit_test_setup_teardown(test_call_enabled_true, setup_enabled, teardown_enabled), cmocka_unit_test_setup_teardown(test_call_enabled_false, setup_disabled, teardown_disabled), cmocka_unit_test_setup_teardown(test_call_indicate_no_inet_fd, setup_enabled, teardown_enabled), cmocka_unit_test_setup_teardown(test_call_indicate_no_inet_fd, setup_disabled, teardown_disabled), }; rc = cmocka_run_group_tests(max_sockets_tests, NULL, NULL); return rc; } socket_wrapper-1.4.4/tests/test_echo_udp_sendto_recvfrom.c000644 001750 000144 00000014536 14631527256 024166 0ustar00asnusers000000 000000 #include #include #include #include #include "config.h" #include "torture.h" #include #include #include #include #include #include #include #include static int setup_echo_srv_udp_ipv4(void **state) { torture_setup_echo_srv_udp_ipv4(state); return 0; } #ifdef HAVE_IPV6 static int setup_echo_srv_udp_ipv6(void **state) { torture_setup_echo_srv_udp_ipv6(state); return 0; } #endif static int teardown(void **state) { torture_teardown_echo_srv(state); return 0; } static void test_sendto_recvfrom_ipv4(void **state) { struct torture_address addr = { .sa_socklen = sizeof(struct sockaddr_in), }; char send_buf[64] = {0}; char recv_buf[64] = {0}; ssize_t ret; int rc; int i; int s; (void) state; /* unused */ s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); assert_int_not_equal(s, -1); addr.sa.in.sin_family = AF_INET; addr.sa.in.sin_port = htons(torture_server_port()); rc = inet_pton(AF_INET, torture_server_address(AF_INET), &addr.sa.in.sin_addr); assert_int_equal(rc, 1); for (i = 0; i < 10; i++) { char ip[INET_ADDRSTRLEN] = {0}; const char *a; struct torture_address srv_in = { .sa_socklen = sizeof(struct sockaddr_in), }; snprintf(send_buf, sizeof(send_buf), "packet.%d", i); ret = sendto(s, send_buf, sizeof(send_buf), 0, &addr.sa.s, addr.sa_socklen); assert_return_code(ret, errno); ret = recvfrom(s, recv_buf, sizeof(recv_buf), 0, &srv_in.sa.s, &srv_in.sa_socklen); assert_return_code(ret, errno); a = inet_ntop(AF_INET, &srv_in.sa.in.sin_addr, ip, sizeof(ip)); assert_non_null(a); assert_string_equal(a, torture_server_address(AF_INET)); assert_memory_equal(send_buf, recv_buf, sizeof(send_buf)); } ret = sendto(s, send_buf, sizeof(send_buf), 0, &addr.sa.s, addr.sa_socklen); assert_return_code(ret, errno); ret = recvfrom(s, recv_buf, sizeof(recv_buf), 0, NULL, NULL); assert_return_code(ret, errno); close(s); } #ifdef HAVE_IPV6 static void test_sendto_recvfrom_ipv6(void **state) { struct torture_address addr = { .sa_socklen = sizeof(struct sockaddr_in6), }; char send_buf[64] = {0}; char recv_buf[64] = {0}; ssize_t ret; int rc; int i; int s; (void) state; /* unused */ s = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP); assert_int_not_equal(s, -1); addr.sa.in6.sin6_family = AF_INET6; addr.sa.in6.sin6_port = htons(torture_server_port()); rc = inet_pton(AF_INET6, torture_server_address(AF_INET6), &addr.sa.in6.sin6_addr); assert_int_equal(rc, 1); for (i = 0; i < 10; i++) { char ip[INET6_ADDRSTRLEN] = {0}; const char *a; struct torture_address srv_in6 = { .sa_socklen = sizeof(struct sockaddr_in6), }; snprintf(send_buf, sizeof(send_buf), "packet.%d", i); ret = sendto(s, send_buf, sizeof(send_buf), 0, &addr.sa.s, addr.sa_socklen); assert_return_code(ret, errno); ret = recvfrom(s, recv_buf, sizeof(recv_buf), 0, &srv_in6.sa.s, &srv_in6.sa_socklen); assert_return_code(ret, errno); a = inet_ntop(AF_INET6, &srv_in6.sa.in6.sin6_addr, ip, sizeof(ip)); assert_non_null(a); assert_string_equal(a, torture_server_address(AF_INET6)); assert_memory_equal(send_buf, recv_buf, sizeof(send_buf)); } ret = sendto(s, send_buf, sizeof(send_buf), 0, &addr.sa.s, addr.sa_socklen); assert_return_code(ret, errno); ret = recvfrom(s, recv_buf, sizeof(recv_buf), 0, NULL, NULL); assert_return_code(ret, errno); close(s); } #endif static void test_connect_sendto_ipv4(void **state) { struct torture_address addr = { .sa_socklen = sizeof(struct sockaddr_in), }; char send_buf[] = "packet.0"; char recv_buf[64] = {0}; ssize_t ret; int rc; int s; (void) state; /* unused */ addr.sa.in.sin_family = AF_INET; addr.sa.in.sin_port = htons(torture_server_port()); rc = inet_pton(AF_INET, torture_server_address(AF_INET), &addr.sa.in.sin_addr); assert_int_equal(rc, 1); s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); assert_int_not_equal(s, -1); /* Now, connect */ rc = connect(s, &addr.sa.s, addr.sa_socklen); assert_return_code(rc, errno); ret = sendto(s, send_buf, sizeof(send_buf), 0, &addr.sa.s, addr.sa_socklen); assert_return_code(ret, errno); ret = recvfrom(s, recv_buf, sizeof(recv_buf), 0, NULL, 0); assert_return_code(ret, errno); assert_memory_equal(send_buf, recv_buf, sizeof(send_buf)); close(s); } static void test_connect_sendto_null_ipv4(void **state) { struct torture_address addr = { .sa_socklen = sizeof(struct sockaddr_in), }; char send_buf[] = "packet.0"; char recv_buf[64] = {0}; ssize_t ret; int rc; int s; (void) state; /* unused */ addr.sa.in.sin_family = AF_INET; addr.sa.in.sin_port = htons(torture_server_port()); rc = inet_pton(AF_INET, torture_server_address(AF_INET), &addr.sa.in.sin_addr); assert_int_equal(rc, 1); s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); assert_int_not_equal(s, -1); /* Now, connect */ rc = connect(s, &addr.sa.s, addr.sa_socklen); assert_return_code(rc, errno); ret = sendto(s, send_buf, sizeof(send_buf), 0, NULL, 0); assert_return_code(ret, errno); ret = recvfrom(s, recv_buf, sizeof(recv_buf), 0, NULL, 0); assert_return_code(ret, errno); assert_memory_equal(send_buf, recv_buf, sizeof(send_buf)); close(s); } int main(void) { int rc; const struct CMUnitTest sendto_tests[] = { cmocka_unit_test_setup_teardown(test_sendto_recvfrom_ipv4, setup_echo_srv_udp_ipv4, teardown), #ifdef HAVE_IPV6 cmocka_unit_test_setup_teardown(test_sendto_recvfrom_ipv6, setup_echo_srv_udp_ipv6, teardown), #endif cmocka_unit_test_setup_teardown(test_connect_sendto_ipv4, setup_echo_srv_udp_ipv4, teardown), cmocka_unit_test_setup_teardown(test_connect_sendto_null_ipv4, setup_echo_srv_udp_ipv4, teardown), }; rc = cmocka_run_group_tests(sendto_tests, NULL, NULL); return rc; } socket_wrapper-1.4.4/tests/thread_deadlock.c000644 001750 000144 00000004615 14631527256 021154 0ustar00asnusers000000 000000 /* * Copyright (C) 2017 Andreas Schneider * * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * 3. Neither the name of the author nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * */ #include "config.h" #include #include #include #ifdef HAVE_CONSTRUCTOR_ATTRIBUTE #define CONSTRUCTOR_ATTRIBUTE __attribute__ ((constructor)) #else #define CONSTRUCTOR_ATTRIBUTE #endif /* HAVE_CONSTRUCTOR_ATTRIBUTE */ #if ! defined(HAVE_CONSTRUCTOR_ATTRIBUTE) && defined(HAVE_PRAGMA_INIT) /* xlC and other oldschool compilers support (only) this */ #pragma init (thread_deadlock_constructor) #endif void thread_deadlock_constructor(void) CONSTRUCTOR_ATTRIBUTE; static void thread_deadlock_prepare(void) { pthread_kill(pthread_self(), SIGUSR1); return; } static void thread_deadlock_parent(void) { return; } static void thread_deadlock_child(void) { return; } void thread_deadlock_constructor(void) { pthread_atfork(&thread_deadlock_prepare, &thread_deadlock_parent, &thread_deadlock_child); } socket_wrapper-1.4.4/tests/test_close_failure.c000644 001750 000144 00000001437 14631527256 021731 0ustar00asnusers000000 000000 #include "torture.h" #include #include #include #include #include static int setup(void **state) { torture_setup_socket_dir(state); return 0; } static int teardown(void **state) { torture_teardown_socket_dir(state); return 0; } static void test_close_failure(void **state) { int s; (void) state; /* unused */ s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); assert_int_not_equal(s, -1); /* Do not close the socket here so that destructor * handles it and no hang should be observed.*/ } int main(void) { int rc; const struct CMUnitTest close_failure_tests[] = { cmocka_unit_test_setup_teardown(test_close_failure, setup, teardown), }; rc = cmocka_run_group_tests(close_failure_tests, NULL, NULL); return rc; } socket_wrapper-1.4.4/tests/test_fork_thread_deadlock.c000644 001750 000144 00000004302 14631527256 023225 0ustar00asnusers000000 000000 #include "config.h" #include #include #include #include #include #include #include #include #include #include #include #include #include /* * This reproduces and issue if we get a signal after the pthread_atfork() * prepare function of socket wrapper has been called. * * The order how pthread_atfork() handlers are set up is: * -> application * -> preloaded libraries * -> libraries * * We have a library called thread_deadlock. * * This library registers a thread_deadlock_prepare() function via * pthread_atfork(). * * So pthread_atfork() registers the prepare function in the follow order: * -> swrap_thread_prepare() * -> thread_deadlock_prepare() * * In this test we fork and the swrap_thread_prepare() locks the mutex for * symbol binding. * Then thread_deadlock_prepare() is called which sends a signal to the parent * process of this test. The signal triggers the signal handler below. * * When we call write() in the signal handler, we will try to bind the libc symbol * and want to lock the symbol binding mutex. As it is already locked we run into * a deadlock. */ static void test_swrap_signal_handler(int signum) { ssize_t w; fprintf(stderr, "PID: %u, SIGNUM: %d\n", (unsigned int)getpid(), signum); w = write(1, "DEADLOCK?\n", 10); fprintf(stderr, "WRITE: %zu\n", w); } static void test_swrap_fork_pthread(void **state) { pid_t pid; struct sigaction act = { .sa_handler = test_swrap_signal_handler, .sa_flags = 0, }; (void)state; /* unused */ sigemptyset(&act.sa_mask); sigaction(SIGUSR1, &act, NULL); pid = fork(); assert_return_code(pid, errno); /* child */ if (pid == 0) { exit(0); } /* parent */ if (pid > 0) { pid_t child_pid; int wstatus = -1; child_pid = waitpid(-1, &wstatus, 0); assert_return_code(child_pid, errno); assert_true(WIFEXITED(wstatus)); assert_int_equal(WEXITSTATUS(wstatus), 0); } } int main(void) { int rc; const struct CMUnitTest swrap_tests[] = { cmocka_unit_test(test_swrap_fork_pthread), }; rc = cmocka_run_group_tests(swrap_tests, NULL, NULL); return rc; } socket_wrapper-1.4.4/tests/test_echo_udp_sendmsg_recvmsg.c000644 001750 000144 00000021135 14631527256 024146 0ustar00asnusers000000 000000 #include #include #include #include #include "config.h" #include "torture.h" #include #include #include #include #include #include #include #include static int setup_echo_srv_udp_ipv4(void **state) { torture_setup_echo_srv_udp_ipv4(state); return 0; } #ifdef HAVE_IPV6 static int setup_echo_srv_udp_ipv6(void **state) { torture_setup_echo_srv_udp_ipv6(state); return 0; } #endif static int teardown(void **state) { torture_teardown_echo_srv(state); return 0; } static void test_sendmsg_recvmsg_ipv4(void **state) { struct torture_address addr = { .sa_socklen = sizeof(struct sockaddr_in), }; char send_buf[64] = {0}; char recv_buf[64] = {0}; ssize_t ret; int rc; int i; int s; (void) state; /* unused */ s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); assert_int_not_equal(s, -1); addr.sa.in.sin_family = AF_INET; addr.sa.in.sin_port = htons(torture_server_port()); rc = inet_pton(AF_INET, torture_server_address(AF_INET), &addr.sa.in.sin_addr); assert_int_equal(rc, 1); for (i = 0; i < 10; i++) { char ip[INET_ADDRSTRLEN] = {0}; const char *a; struct torture_address srv_in = { .sa_socklen = sizeof(struct sockaddr_in), }; struct msghdr s_msg; struct msghdr r_msg; struct iovec s_iov; struct iovec r_iov; snprintf(send_buf, sizeof(send_buf), "packet.%d", i); ZERO_STRUCT(s_msg); s_msg.msg_name = &addr.sa.s; s_msg.msg_namelen = addr.sa_socklen; s_iov.iov_base = send_buf; s_iov.iov_len = sizeof(send_buf); s_msg.msg_iov = &s_iov; s_msg.msg_iovlen = 1; ret = sendmsg(s, &s_msg, 0); assert_int_not_equal(ret, -1); ZERO_STRUCT(r_msg); r_msg.msg_name = &srv_in.sa.s; r_msg.msg_namelen = srv_in.sa_socklen; r_iov.iov_base = recv_buf; r_iov.iov_len = sizeof(recv_buf); r_msg.msg_iov = &r_iov; r_msg.msg_iovlen = 1; ret = recvmsg(s, &r_msg, 0); assert_int_not_equal(ret, -1); assert_int_equal(r_msg.msg_namelen, sizeof(struct sockaddr_in)); a = inet_ntop(AF_INET, &srv_in.sa.in.sin_addr, ip, sizeof(ip)); assert_non_null(a); assert_string_equal(a, torture_server_address(AF_INET)); assert_memory_equal(send_buf, recv_buf, sizeof(send_buf)); } close(s); } #ifdef HAVE_IPV6 static void test_sendmsg_recvmsg_ipv6(void **state) { struct torture_address addr = { .sa_socklen = sizeof(struct sockaddr_in6), }; char send_buf[64] = {0}; char recv_buf[64] = {0}; ssize_t ret; int rc; int i; int s; (void) state; /* unused */ s = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP); assert_int_not_equal(s, -1); addr.sa.in6.sin6_family = AF_INET6; addr.sa.in6.sin6_port = htons(torture_server_port()); rc = inet_pton(AF_INET6, torture_server_address(AF_INET6), &addr.sa.in6.sin6_addr); assert_int_equal(rc, 1); for (i = 0; i < 10; i++) { char ip[INET6_ADDRSTRLEN] = {0}; const char *a; struct torture_address srv_in6 = { .sa_socklen = sizeof(struct sockaddr_in6), }; struct msghdr s_msg; struct msghdr r_msg; struct iovec s_iov; struct iovec r_iov; snprintf(send_buf, sizeof(send_buf), "packet.%d", i); ZERO_STRUCT(s_msg); s_msg.msg_name = &addr.sa.s; s_msg.msg_namelen = addr.sa_socklen; s_iov.iov_base = send_buf; s_iov.iov_len = sizeof(send_buf); s_msg.msg_iov = &s_iov; s_msg.msg_iovlen = 1; ret = sendmsg(s, &s_msg, 0); assert_int_not_equal(ret, -1); ZERO_STRUCT(r_msg); r_msg.msg_name = &srv_in6.sa.s; r_msg.msg_namelen = srv_in6.sa_socklen; r_iov.iov_base = recv_buf; r_iov.iov_len = sizeof(recv_buf); r_msg.msg_iov = &r_iov; r_msg.msg_iovlen = 1; ret = recvmsg(s, &r_msg, 0); assert_int_not_equal(ret, -1); assert_int_equal(r_msg.msg_namelen, sizeof(struct sockaddr_in6)); a = inet_ntop(AF_INET6, &srv_in6.sa.in6.sin6_addr, ip, sizeof(ip)); assert_non_null(a); assert_string_equal(a, torture_server_address(AF_INET6)); assert_memory_equal(send_buf, recv_buf, sizeof(send_buf)); } close(s); } #endif static void test_sendmsg_recvmsg_ipv4_connected(void **state) { struct torture_address send_addr = { .sa_socklen = sizeof(struct sockaddr_storage), }; struct torture_address r_addr = { .sa_socklen = sizeof(struct sockaddr_storage), }; struct msghdr s_msg = { .msg_namelen = 0, }; struct msghdr r_msg = { .msg_namelen = 0, }; struct iovec iov; char ip[INET_ADDRSTRLEN] = {0}; char payload[] = "PACKET"; const char *a; ssize_t ret; int rc; int s; (void)state; /* unused */ s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); assert_int_not_equal(s, -1); send_addr.sa.in.sin_family = AF_INET; send_addr.sa.in.sin_port = htons(torture_server_port()); rc = inet_pton(AF_INET, torture_server_address(AF_INET), &send_addr.sa.in.sin_addr); assert_int_equal(rc, 1); rc = connect(s, &send_addr.sa.s, send_addr.sa_socklen); assert_return_code(rc, errno); iov.iov_base = (void *)payload; iov.iov_len = sizeof(payload); /* msg_name is NULL */ s_msg.msg_iov = &iov; s_msg.msg_iovlen = 1; ret = sendmsg(s, &s_msg, 0); assert_int_not_equal(ret, -1); r_msg.msg_name = &r_addr.sa.ss; r_msg.msg_namelen = r_addr.sa_socklen; memset(payload, 0, sizeof(payload)); r_msg.msg_iov = &iov; r_msg.msg_iovlen = 1; ret = recvmsg(s, &r_msg, 0); assert_int_not_equal(ret, -1); assert_int_equal(r_msg.msg_namelen, sizeof(struct sockaddr_in)); a = inet_ntop(AF_INET, &r_addr.sa.in.sin_addr, ip, sizeof(ip)); assert_non_null(a); assert_string_equal(a, torture_server_address(AF_INET)); close(s); } static void test_sendmsg_recvmsg_ipv4_connected_null(void **state) { struct torture_address send_addr = { .sa_socklen = sizeof(struct sockaddr_storage), }; struct msghdr s_msg = { .msg_namelen = 0, }; struct msghdr r_msg = { .msg_namelen = 0, }; struct iovec iov; char payload[] = "PACKET"; ssize_t ret; int rc; int s; (void)state; /* unused */ s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); assert_int_not_equal(s, -1); send_addr.sa.in.sin_family = AF_INET; send_addr.sa.in.sin_port = htons(torture_server_port()); rc = inet_pton(AF_INET, torture_server_address(AF_INET), &send_addr.sa.in.sin_addr); assert_int_equal(rc, 1); rc = connect(s, &send_addr.sa.s, send_addr.sa_socklen); assert_return_code(rc, errno); /* msg_name = NULL */ iov.iov_base = (void *)payload; iov.iov_len = sizeof(payload); s_msg.msg_iov = &iov; s_msg.msg_iovlen = 1; ret = sendmsg(s, &s_msg, 0); assert_int_not_equal(ret, -1); /* msg_name = NULL */ memset(payload, 0, sizeof(payload)); r_msg.msg_iov = &iov; r_msg.msg_iovlen = 1; ret = recvmsg(s, &r_msg, 0); assert_int_not_equal(ret, -1); assert_int_equal(r_msg.msg_namelen, 0); assert_null(r_msg.msg_name); close(s); } static void test_sendmsg_recvmsg_ipv4_connected_namelen(void **state) { struct torture_address send_addr = { .sa_socklen = sizeof(struct sockaddr_storage), }; struct msghdr s_msg = { .msg_namelen = 0, }; struct msghdr r_msg = { .msg_namelen = sizeof(struct sockaddr_storage), }; struct iovec iov; char payload[] = "PACKET"; ssize_t ret; int rc; int s; (void)state; /* unused */ s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); assert_int_not_equal(s, -1); send_addr.sa.in.sin_family = AF_INET; send_addr.sa.in.sin_port = htons(torture_server_port()); rc = inet_pton(AF_INET, torture_server_address(AF_INET), &send_addr.sa.in.sin_addr); assert_int_equal(rc, 1); rc = connect(s, &send_addr.sa.s, send_addr.sa_socklen); assert_return_code(rc, errno); /* msg_name = NULL */ iov.iov_base = (void *)payload; iov.iov_len = sizeof(payload); s_msg.msg_iov = &iov; s_msg.msg_iovlen = 1; ret = sendmsg(s, &s_msg, 0); assert_int_not_equal(ret, -1); /* msg_name = NULL */ memset(payload, 0, sizeof(payload)); r_msg.msg_iov = &iov; r_msg.msg_iovlen = 1; ret = recvmsg(s, &r_msg, 0); assert_int_not_equal(ret, -1); close(s); } int main(void) { int rc; const struct CMUnitTest sendmsg_tests[] = { cmocka_unit_test_setup_teardown(test_sendmsg_recvmsg_ipv4, setup_echo_srv_udp_ipv4, teardown), #ifdef HAVE_IPV6 cmocka_unit_test_setup_teardown(test_sendmsg_recvmsg_ipv6, setup_echo_srv_udp_ipv6, teardown), #endif cmocka_unit_test_setup_teardown(test_sendmsg_recvmsg_ipv4_connected, setup_echo_srv_udp_ipv4, teardown), cmocka_unit_test_setup_teardown(test_sendmsg_recvmsg_ipv4_connected_null, setup_echo_srv_udp_ipv4, teardown), cmocka_unit_test_setup_teardown(test_sendmsg_recvmsg_ipv4_connected_namelen, setup_echo_srv_udp_ipv4, teardown), }; rc = cmocka_run_group_tests(sendmsg_tests, NULL, NULL); return rc; } socket_wrapper-1.4.4/tests/test_echo_udp_send_recv.c000644 001750 000144 00000005662 14631527256 022737 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.4.4/tests/README000644 001750 000144 00000000476 14631527256 016574 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.4.4/tests/test_swrap_unit.c000644 001750 000144 00000005245 14631527256 021311 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.4.4/tests/test_fcntl.c000644 001750 000144 00000002220 14631527256 020212 0ustar00asnusers000000 000000 #include "torture.h" #include #include #include #include static int setup(void **state) { torture_setup_socket_dir(state); return 0; } static int teardown(void **state) { torture_teardown_socket_dir(state); return 0; } static void test_fcntl_dupfd_existing_open_fd(void **state) { int s, dup_s; (void) state; /* unused */ s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); assert_return_code(s, errno); dup_s = fcntl(s, F_DUPFD, 100); assert_int_equal(dup_s, 100); close(s); close(dup_s); } static void test_fcntl_getfd_existing_open_fd(void **state) { int s, rc, flags; (void) state; /* unused */ s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); assert_return_code(s, errno); rc = fcntl(s, F_SETFD, FD_CLOEXEC); assert_int_equal(rc, 0); flags = fcntl(s, F_GETFD); assert_int_equal(flags, FD_CLOEXEC); close(s); } int main(void) { int rc; const struct CMUnitTest tcp_fcntl_dupfd_tests[] = { cmocka_unit_test(test_fcntl_dupfd_existing_open_fd), cmocka_unit_test(test_fcntl_getfd_existing_open_fd), }; rc = cmocka_run_group_tests(tcp_fcntl_dupfd_tests, setup, teardown); return rc; } socket_wrapper-1.4.4/tests/test_echo_tcp_socket_options.c000644 001750 000144 00000023002 14744201025 024000 0ustar00asnusers000000 000000 #include #include #include #include #include "config.h" #include "torture.h" #include #include #include #include #include #ifdef HAVE_NETINET_TCP_FSM_H #include #endif #include #include #include #include #include #ifdef HAVE_NETINET_TCP_FSM_H /* This is FreeBSD */ # define __TCP_ESTABLISHED TCPS_ESTABLISHED # define __TCP_CLOSE TCPS_CLOSED #else /* This is Linux */ # define __TCP_ESTABLISHED TCP_ESTABLISHED # define __TCP_CLOSE TCP_CLOSE #endif #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; #ifdef TCP_INFO struct tcp_info info; #endif 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); #ifdef TCP_INFO ZERO_STRUCT(info); optlen = sizeof(info); rc = getsockopt(s, IPPROTO_TCP, TCP_INFO, &info, &optlen); assert_return_code(rc, errno); assert_int_equal(optlen, sizeof(info)); printf("info.tcpi_state=0x%x\n", info.tcpi_state); printf("info.tcpi_rto=%u\n", info.tcpi_rto); printf("info.tcpi_rtt=%u\n", info.tcpi_rtt); printf("info.tcpi_rttvar=%u\n", info.tcpi_rttvar); assert_int_equal(info.tcpi_state, __TCP_CLOSE); assert_int_not_equal(info.tcpi_rto, 0); assert_int_equal(info.tcpi_rtt, 0); assert_int_not_equal(info.tcpi_rttvar, 0); #endif /* TCP_INFO */ rc = connect(s, &addr.sa.s, addr.sa_socklen); assert_int_equal(rc, 0); opt = -1; optlen = sizeof(int); 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); #ifdef TCP_INFO ZERO_STRUCT(info); optlen = sizeof(info); rc = getsockopt(s, IPPROTO_TCP, TCP_INFO, &info, &optlen); assert_return_code(rc, errno); assert_int_equal(optlen, sizeof(info)); printf("info.tcpi_state=0x%x\n", info.tcpi_state); printf("info.tcpi_rto=%u\n", info.tcpi_rto); printf("info.tcpi_rtt=%u\n", info.tcpi_rtt); printf("info.tcpi_rttvar=%u\n", info.tcpi_rttvar); assert_int_equal(info.tcpi_state, __TCP_ESTABLISHED); assert_int_not_equal(info.tcpi_rto, 0); assert_int_not_equal(info.tcpi_rtt, 0); assert_int_not_equal(info.tcpi_rttvar, 0); #endif /* TCP_INFO */ close(s); } static void test_sockopt_reuseport(void **state) { socklen_t optlen = sizeof(int); int opt = 1; int rc; int s; (void) state; /* unused */ s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); assert_return_code(s, errno); rc = setsockopt(s, SOL_SOCKET, SO_REUSEPORT, &opt, optlen); assert_return_code(rc, errno); } 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), cmocka_unit_test_setup_teardown(test_sockopt_reuseport, setup_echo_srv_tcp_ipv4, teardown), }; rc = cmocka_run_group_tests(sockopt_tests, NULL, NULL); return rc; } socket_wrapper-1.4.4/tests/test_thread_echo_tcp_write_read.c000644 001750 000144 00000004316 14631527256 024434 0ustar00asnusers000000 000000 #include #include #include #include #include #include "config.h" #include "torture.h" #include #include #include #include #include #include #include #include #define NUM_THREADS 10 static int setup_echo_srv_tcp_ipv4(void **state) { torture_setup_echo_srv_tcp_ipv4(state); return 0; } static int teardown(void **state) { torture_teardown_echo_srv(state); return 0; } static void *thread_worker(void *arg) { struct torture_address addr = { .sa_socklen = sizeof(struct sockaddr_in), }; ssize_t ret; int rc; int i; int s; (void) arg; /* unused */ s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); assert_int_not_equal(s, -1); addr.sa.in.sin_family = AF_INET; addr.sa.in.sin_port = htons(torture_server_port()); rc = inet_pton(addr.sa.in.sin_family, torture_server_address(AF_INET), &addr.sa.in.sin_addr); assert_int_equal(rc, 1); rc = connect(s, &addr.sa.s, addr.sa_socklen); assert_return_code(rc, errno); for (i = 0; i < 10; i++) { char send_buf[64] = {0}; char recv_buf[64] = {0}; snprintf(send_buf, sizeof(send_buf), "packet.%d", i); ret = write(s, send_buf, sizeof(send_buf)); assert_return_code(ret, errno); ret = read(s, recv_buf, sizeof(recv_buf)); assert_int_not_equal(ret, -1); assert_memory_equal(send_buf, recv_buf, sizeof(send_buf)); } close(s); return NULL; } static void test_write_read_ipv4(void **state) { pthread_attr_t pthread_custom_attr; pthread_t threads[NUM_THREADS]; int i; (void) state; /* unused */ pthread_attr_init(&pthread_custom_attr); for (i = 0; i < NUM_THREADS; i++) { pthread_create(&threads[i], &pthread_custom_attr, thread_worker, NULL); } for (i = 0; i < NUM_THREADS; i++) { pthread_join(threads[i], NULL); } pthread_attr_destroy(&pthread_custom_attr); } int main(void) { int rc; const struct CMUnitTest tcp_write_tests[] = { cmocka_unit_test_setup_teardown(test_write_read_ipv4, setup_echo_srv_tcp_ipv4, teardown), }; rc = cmocka_run_group_tests(tcp_write_tests, NULL, NULL); return rc; } socket_wrapper-1.4.4/tests/test_thread_echo_udp_send_recv.c000644 001750 000144 00000004274 14631527256 024264 0ustar00asnusers000000 000000 #include #include #include #include #include #include "config.h" #include "torture.h" #include #include #include #include #include #include #include #include #define NUM_THREADS 10 static int setup_echo_srv_udp_ipv4(void **state) { torture_setup_echo_srv_udp_ipv4(state); return 0; } static int teardown(void **state) { torture_teardown_echo_srv(state); return 0; } static void *thread_worker(void *arg) { struct torture_address addr = { .sa_socklen = sizeof(struct sockaddr_in), }; ssize_t ret; int rc; int i; int s; (void) arg; /* unused */ s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); assert_int_not_equal(s, -1); addr.sa.in.sin_family = AF_INET; addr.sa.in.sin_port = htons(torture_server_port()); rc = inet_pton(AF_INET, torture_server_address(AF_INET), &addr.sa.in.sin_addr); assert_int_equal(rc, 1); rc = connect(s, &addr.sa.s, addr.sa_socklen); assert_int_equal(rc, 0); for (i = 0; i < 10; i++) { char send_buf[64] = {0}; char recv_buf[64] = {0}; snprintf(send_buf, sizeof(send_buf), "packet.%d", i); ret = send(s, send_buf, sizeof(send_buf), 0); assert_int_not_equal(ret, -1); ret = recv(s, recv_buf, sizeof(recv_buf), 0); assert_int_not_equal(ret, -1); assert_memory_equal(send_buf, recv_buf, sizeof(send_buf)); } close(s); return NULL; } static void test_send_recv_ipv4(void **state) { pthread_attr_t pthread_custom_attr; pthread_t threads[NUM_THREADS]; int i; (void) state; /* unused */ pthread_attr_init(&pthread_custom_attr); for (i = 0; i < NUM_THREADS; i++) { pthread_create(&threads[i], &pthread_custom_attr, thread_worker, NULL); } for (i = 0; i < NUM_THREADS; i++) { pthread_join(threads[i], NULL); } pthread_attr_destroy(&pthread_custom_attr); } int main(void) { int rc; const struct CMUnitTest send_tests[] = { cmocka_unit_test_setup_teardown(test_send_recv_ipv4, setup_echo_srv_udp_ipv4, teardown), }; rc = cmocka_run_group_tests(send_tests, NULL, NULL); return rc; } socket_wrapper-1.4.4/tests/test_echo_tcp_sendmsg_recvmsg_fd.c000644 001750 000144 00000032344 14631527256 024621 0ustar00asnusers000000 000000 #include #include #include #include #include "config.h" #include "torture.h" #include #include #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; } static int teardown(void **state) { torture_teardown_echo_srv(state); return 0; } struct test_fd { int fd; struct torture_address sock_addr; struct torture_address peer_addr; }; static int test_fill_test_fd(struct test_fd *tfd, int fd) { struct torture_address saddr = { .sa_socklen = sizeof(struct sockaddr_storage), }; struct torture_address paddr = { .sa_socklen = sizeof(struct sockaddr_storage), }; int ret; *tfd = (struct test_fd) { .fd = fd, }; ret = getsockname(fd, &saddr.sa.s, &saddr.sa_socklen); if (ret == -1 && errno == ENOTSOCK) { return 0; } if (ret == -1) { return ret; } ret = getpeername(fd, &paddr.sa.s, &paddr.sa_socklen); if (ret == -1) { return ret; } tfd->sock_addr = saddr; tfd->peer_addr = paddr; return 0; } static void _assert_torture_address_equal(const struct torture_address *ga, const struct torture_address *ea, const char * const file, const int line) { _assert_int_equal(ga->sa_socklen, ea->sa_socklen, file, line); if (ga->sa_socklen == 0) { return; } _assert_memory_equal(&ga->sa, &ea->sa, ga->sa_socklen, file, line); } #define assert_test_fd_equal(gfd, efd) \ _assert_test_fd_equal(gfd, efd, __FILE__, __LINE__) static void _assert_test_fd_equal(const struct test_fd *gfd, const struct test_fd *efd, const char * const file, const int line) { if (efd->fd == -1) { _assert_int_equal(gfd->fd, -1, file, line); return; } _assert_int_not_equal(gfd->fd, -1, file, line); _assert_torture_address_equal(&gfd->sock_addr, &efd->sock_addr, file, line); _assert_torture_address_equal(&gfd->peer_addr, &efd->peer_addr, file, line); } static void test_tcp_sendmsg_recvmsg_fd_array(const int *fds, size_t num_fds) { struct test_fd tfds[num_fds]; size_t idx; int sv[2]; int child_fd, parent_fd; pid_t pid; int rc; for (idx = 0; idx < num_fds; idx++) { rc = test_fill_test_fd(&tfds[idx], fds[idx]); assert_int_equal(rc, 0); } /* create unix domain socket stream */ 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; int recv_fd_array[num_fds]; char cmsgbuf[CMSG_SPACE(sizeof(int)*num_fds)]; struct cmsghdr *cmsg; ssize_t ret; char byte = { 0, }; struct iovec iov; iov.iov_base = &byte; iov.iov_len = 1; memset(&child_msg, 0, sizeof(child_msg)); child_msg.msg_iov = &iov; child_msg.msg_iovlen = 1; child_msg.msg_control = cmsgbuf; child_msg.msg_controllen = sizeof(cmsgbuf); rc = recvmsg(child_fd, &child_msg, 0); assert_int_equal(rc, iov.iov_len); assert_int_equal(byte, '!'); cmsg = CMSG_FIRSTHDR(&child_msg); assert_non_null(cmsg); assert_int_equal(cmsg->cmsg_type, SCM_RIGHTS); memcpy(recv_fd_array, CMSG_DATA(cmsg), sizeof(int)*num_fds); for (idx = 0; idx < num_fds; idx++) { assert_int_not_equal(recv_fd_array[idx], -1); } for (idx = 0; idx < num_fds; idx++) { struct test_fd recv_tfd = { .fd = -1, }; ret = test_fill_test_fd(&recv_tfd, recv_fd_array[idx]); assert_int_equal(ret, 0); assert_test_fd_equal(&recv_tfd, &tfds[idx]); } for (idx = 0; idx < num_fds; idx++) { int recv_fd = recv_fd_array[idx]; char send_buf[64] = {0,}; char recv_buf[64] = {0,}; if (tfds[idx].sock_addr.sa_socklen == 0) { /* * skip fds not belonging to * a socket. */ continue; } if (tfds[idx].sock_addr.sa.s.sa_family == AF_UNIX) { /* * skip fds not belonging to * a socket. */ continue; } snprintf(send_buf, sizeof(send_buf), "packet"); ret = write(recv_fd, send_buf, sizeof(send_buf)); assert_int_not_equal(ret, -1); ret = read(recv_fd, recv_buf, sizeof(recv_buf)); assert_int_not_equal(ret, -1); assert_memory_equal(send_buf, recv_buf, sizeof(send_buf)); } exit(0); } else { /* Parent */ struct msghdr parent_msg; struct cmsghdr *cmsg; char cmsgbuf[CMSG_SPACE(sizeof(int)*num_fds)]; int pass_fd_array[num_fds]; char byte = '!'; struct iovec iov; int cs; for (idx = 0; idx < num_fds; idx++) { pass_fd_array[idx] = tfds[idx].fd; } 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(int)*num_fds); /* place previously connected socket fd as ancillary data */ memcpy(CMSG_DATA(cmsg), pass_fd_array, sizeof(int)*num_fds); 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 */ waitpid(pid, &cs, 0); if (WIFEXITED(cs)) { assert_int_equal(WEXITSTATUS(cs), 0); } } } static void test_tcp_sendmsg_recvmsg_fd_same(size_t num_fds) { struct torture_address addr = { .sa_socklen = sizeof(struct sockaddr_in), }; int pass_sock_fd; int fd_array[num_fds]; size_t idx; int rc; /* create socket file descriptor to be passed */ pass_sock_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); assert_int_not_equal(pass_sock_fd, -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(pass_sock_fd, &addr.sa.s, addr.sa_socklen); assert_int_equal(rc, 0); for (idx = 0; idx < num_fds; idx++) { fd_array[idx] = pass_sock_fd; } test_tcp_sendmsg_recvmsg_fd_array(fd_array, num_fds); close(pass_sock_fd); } static void test_tcp_sendmsg_recvmsg_fd_1(void **state) { (void) state; /* unused */ test_tcp_sendmsg_recvmsg_fd_same(1); } static void test_tcp_sendmsg_recvmsg_fd_2s(void **state) { (void) state; /* unused */ test_tcp_sendmsg_recvmsg_fd_same(2); } static void test_tcp_sendmsg_recvmsg_fd_3s(void **state) { (void) state; /* unused */ test_tcp_sendmsg_recvmsg_fd_same(3); } static void test_tcp_sendmsg_recvmsg_fd_4s(void **state) { (void) state; /* unused */ test_tcp_sendmsg_recvmsg_fd_same(4); } static void test_tcp_sendmsg_recvmsg_fd_5s(void **state) { (void) state; /* unused */ test_tcp_sendmsg_recvmsg_fd_same(5); } static void test_tcp_sendmsg_recvmsg_fd_6s(void **state) { (void) state; /* unused */ test_tcp_sendmsg_recvmsg_fd_same(6); } static void test_tcp_sendmsg_recvmsg_fd_different(size_t num_fds) { int fd_array[num_fds]; size_t idx; assert_int_not_equal(num_fds, 0); memset(fd_array, -1, sizeof(fd_array)); for (idx = 0; idx < num_fds; idx++) { struct torture_address addr = { .sa_socklen = sizeof(struct sockaddr_in), }; int pass_sock_fd; int rc; /* create socket file descriptor to be passed */ pass_sock_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); assert_int_not_equal(pass_sock_fd, -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(pass_sock_fd, &addr.sa.s, addr.sa_socklen); assert_int_equal(rc, 0); fd_array[idx] = pass_sock_fd; } test_tcp_sendmsg_recvmsg_fd_array(fd_array, num_fds); for (idx = 0; idx < num_fds; idx++) { close(fd_array[idx]); } } static void test_tcp_sendmsg_recvmsg_fd_2d(void **state) { (void) state; /* unused */ test_tcp_sendmsg_recvmsg_fd_different(2); } static void test_tcp_sendmsg_recvmsg_fd_3d(void **state) { (void) state; /* unused */ test_tcp_sendmsg_recvmsg_fd_different(3); } static void test_tcp_sendmsg_recvmsg_fd_4d(void **state) { (void) state; /* unused */ test_tcp_sendmsg_recvmsg_fd_different(4); } static void test_tcp_sendmsg_recvmsg_fd_5d(void **state) { (void) state; /* unused */ test_tcp_sendmsg_recvmsg_fd_different(5); } static void test_tcp_sendmsg_recvmsg_fd_6d(void **state) { (void) state; /* unused */ test_tcp_sendmsg_recvmsg_fd_different(6); } static void test_tcp_sendmsg_recvmsg_fd_mixed(size_t num_fds) { int fd_array[num_fds]; int close_array[num_fds]; size_t idx; assert_int_not_equal(num_fds, 0); memset(fd_array, -1, sizeof(fd_array)); memset(close_array, -1, sizeof(fd_array)); /* * We send * 0: AF_UNIX * 1: TCP * 2: /dev/null * 3: pipe * 4: AF_UNIX * 5: TCP * 6: /dev/null * 7: pipe * . * . * . * */ for (idx = 0; idx < num_fds; idx++) { int sv[2]; int rc; if ((idx % 4) == 0) { rc = socketpair(AF_UNIX, SOCK_STREAM, 0, sv); assert_int_not_equal(rc, -1); } else if ((idx % 4) == 2) { rc = pipe(sv); assert_int_not_equal(rc, -1); } else { continue; } fd_array[idx] = sv[0]; close_array[idx] = sv[1]; } for (idx = 0; idx < num_fds; idx++) { struct torture_address addr = { .sa_socklen = sizeof(struct sockaddr_in), }; int pass_sock_fd; int rc; if ((idx % 4) != 1) { continue; } /* create socket file descriptor to be passed */ pass_sock_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); assert_int_not_equal(pass_sock_fd, -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(pass_sock_fd, &addr.sa.s, addr.sa_socklen); assert_int_equal(rc, 0); fd_array[idx] = pass_sock_fd; } for (idx = 0; idx < num_fds; idx++) { int pass_fd; if ((idx % 4) != 3) { continue; } /* create socket file descriptor to be passed */ pass_fd = open("/dev/null", O_RDWR); assert_int_not_equal(pass_fd, -1); fd_array[idx] = pass_fd; } for (idx = 0; idx < num_fds; idx++) { assert_int_not_equal(fd_array[idx], -1); } test_tcp_sendmsg_recvmsg_fd_array(fd_array, num_fds); for (idx = 0; idx < num_fds; idx++) { close(fd_array[idx]); if (close_array[idx] == -1) { continue; } close(close_array[idx]); } } static void test_tcp_sendmsg_recvmsg_fd_1m(void **state) { (void) state; /* unused */ test_tcp_sendmsg_recvmsg_fd_mixed(1); } static void test_tcp_sendmsg_recvmsg_fd_2m(void **state) { (void) state; /* unused */ test_tcp_sendmsg_recvmsg_fd_mixed(2); } static void test_tcp_sendmsg_recvmsg_fd_3m(void **state) { (void) state; /* unused */ test_tcp_sendmsg_recvmsg_fd_mixed(3); } static void test_tcp_sendmsg_recvmsg_fd_4m(void **state) { (void) state; /* unused */ test_tcp_sendmsg_recvmsg_fd_mixed(4); } static void test_tcp_sendmsg_recvmsg_fd_5m(void **state) { (void) state; /* unused */ test_tcp_sendmsg_recvmsg_fd_mixed(5); } static void test_tcp_sendmsg_recvmsg_fd_6m(void **state) { (void) state; /* unused */ test_tcp_sendmsg_recvmsg_fd_mixed(6); } int main(void) { int rc; const struct CMUnitTest tests[] = { cmocka_unit_test_setup_teardown(test_tcp_sendmsg_recvmsg_fd_1, setup_echo_srv_tcp_ipv4, teardown), cmocka_unit_test_setup_teardown(test_tcp_sendmsg_recvmsg_fd_2s, setup_echo_srv_tcp_ipv4, teardown), cmocka_unit_test_setup_teardown(test_tcp_sendmsg_recvmsg_fd_3s, setup_echo_srv_tcp_ipv4, teardown), cmocka_unit_test_setup_teardown(test_tcp_sendmsg_recvmsg_fd_4s, setup_echo_srv_tcp_ipv4, teardown), cmocka_unit_test_setup_teardown(test_tcp_sendmsg_recvmsg_fd_5s, setup_echo_srv_tcp_ipv4, teardown), cmocka_unit_test_setup_teardown(test_tcp_sendmsg_recvmsg_fd_6s, setup_echo_srv_tcp_ipv4, teardown), cmocka_unit_test_setup_teardown(test_tcp_sendmsg_recvmsg_fd_2d, setup_echo_srv_tcp_ipv4, teardown), cmocka_unit_test_setup_teardown(test_tcp_sendmsg_recvmsg_fd_3d, setup_echo_srv_tcp_ipv4, teardown), cmocka_unit_test_setup_teardown(test_tcp_sendmsg_recvmsg_fd_4d, setup_echo_srv_tcp_ipv4, teardown), cmocka_unit_test_setup_teardown(test_tcp_sendmsg_recvmsg_fd_5d, setup_echo_srv_tcp_ipv4, teardown), cmocka_unit_test_setup_teardown(test_tcp_sendmsg_recvmsg_fd_6d, setup_echo_srv_tcp_ipv4, teardown), cmocka_unit_test_setup_teardown(test_tcp_sendmsg_recvmsg_fd_1m, setup_echo_srv_tcp_ipv4, teardown), cmocka_unit_test_setup_teardown(test_tcp_sendmsg_recvmsg_fd_2m, setup_echo_srv_tcp_ipv4, teardown), cmocka_unit_test_setup_teardown(test_tcp_sendmsg_recvmsg_fd_3m, setup_echo_srv_tcp_ipv4, teardown), cmocka_unit_test_setup_teardown(test_tcp_sendmsg_recvmsg_fd_4m, setup_echo_srv_tcp_ipv4, teardown), cmocka_unit_test_setup_teardown(test_tcp_sendmsg_recvmsg_fd_5m, setup_echo_srv_tcp_ipv4, teardown), cmocka_unit_test_setup_teardown(test_tcp_sendmsg_recvmsg_fd_6m, setup_echo_srv_tcp_ipv4, teardown), }; rc = cmocka_run_group_tests(tests, NULL, NULL); return rc; } socket_wrapper-1.4.4/tests/test_syscall_uwrap.c000644 001750 000144 00000002015 14631527256 021776 0ustar00asnusers000000 000000 #include "config.h" #include #include #include #include #include #include #include #include #include #include #ifdef HAVE_SYS_SYSCALL_H #include #endif #ifdef HAVE_SYSCALL_H #include #endif #include "swrap_fake_uid_wrapper.h" static void test_swrap_syscall_uwrap(void **state) { long int rc; (void)state; /* unused */ rc = syscall(__FAKE_UID_WRAPPER_SYSCALL_NO); assert_int_equal(rc, __FAKE_UID_WRAPPER_SYSCALL_RC); /* * FreeBSD raises also a signal SIGSYS, so ignore it or the cmocka * exception handler will catch it. */ signal(SIGSYS, SIG_IGN); rc = syscall(__FAKE_UID_WRAPPER_SYSCALL_NO+1); signal(SIGSYS, SIG_DFL); assert_int_equal(rc, -1); assert_int_equal(errno, ENOSYS); } int main(void) { int rc; const struct CMUnitTest swrap_tests[] = { cmocka_unit_test(test_swrap_syscall_uwrap), }; rc = cmocka_run_group_tests(swrap_tests, NULL, NULL); return rc; } socket_wrapper-1.4.4/tests/test_echo_tcp_sendmmsg_recvmmsg.c000644 001750 000144 00000024714 14631527256 024504 0ustar00asnusers000000 000000 #include #include #include #include #include "config.h" #include "torture.h" #include #include #include #include #include #include #include #include #ifdef HAVE_SYS_SYSCALL_H #include #endif #ifdef HAVE_SYSCALL_H #include #endif static int setup_echo_srv_tcp_ipv4(void **state) { torture_setup_echo_srv_tcp_ipv4(state); return 0; } #ifdef HAVE_IPV6 static int setup_echo_srv_tcp_ipv6(void **state) { torture_setup_echo_srv_tcp_ipv6(state); return 0; } #endif static int teardown(void **state) { torture_teardown_echo_srv(state); return 0; } static void test_sendmmsg_recvmmsg_ipv4_ignore(void **state) { struct torture_address addr = { .sa_socklen = sizeof(struct sockaddr_storage), }; struct { struct torture_address reply_addr; struct iovec s_iov; struct iovec r_iov; char send_buf[64]; char recv_buf[64]; } tmsgs[10] = {}; struct mmsghdr s_msgs[10] = {}; struct mmsghdr r_msgs[10] = {}; ssize_t ret; int rc; int i; int s; (void) state; /* unused */ s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); assert_int_not_equal(s, -1); addr.sa.in.sin_family = AF_INET; addr.sa.in.sin_port = htons(torture_server_port()); rc = inet_pton(AF_INET, torture_server_address(AF_INET), &addr.sa.in.sin_addr); assert_int_equal(rc, 1); rc = connect(s, &addr.sa.s, addr.sa_socklen); assert_return_code(rc, errno); /* This should be ignored */ rc = inet_pton(AF_INET, "127.0.0.1", &addr.sa.in.sin_addr); assert_int_equal(rc, 1); for (i = 0; i < 10; i++) { tmsgs[i].reply_addr = (struct torture_address){ .sa_socklen = sizeof(struct sockaddr_storage), }; snprintf(tmsgs[i].send_buf, sizeof(tmsgs[i].send_buf), "packet.%d", i); tmsgs[i].s_iov.iov_base = tmsgs[i].send_buf; tmsgs[i].s_iov.iov_len = sizeof(tmsgs[i].send_buf); s_msgs[i].msg_hdr.msg_name = &addr.sa.s; s_msgs[i].msg_hdr.msg_namelen = addr.sa_socklen; s_msgs[i].msg_hdr.msg_iov = &tmsgs[i].s_iov; s_msgs[i].msg_hdr.msg_iovlen = 1; tmsgs[i].r_iov.iov_base = tmsgs[i].recv_buf; tmsgs[i].r_iov.iov_len = sizeof(tmsgs[i].recv_buf); r_msgs[i].msg_hdr.msg_name = &tmsgs[i].reply_addr.sa.s; r_msgs[i].msg_hdr.msg_namelen = tmsgs[i].reply_addr.sa_socklen; r_msgs[i].msg_hdr.msg_iov = &tmsgs[i].r_iov; r_msgs[i].msg_hdr.msg_iovlen = 1; } ret = sendmmsg(s, s_msgs, 10, 0); assert_int_equal(ret, 10); ret = recvmmsg(s, r_msgs, 10, 0, NULL); assert_int_equal(ret, 10); for (i = 0; i < 10; i++) { assert_int_equal(r_msgs[i].msg_hdr.msg_namelen, 0); assert_ptr_equal(r_msgs[i].msg_hdr.msg_name, &tmsgs[i].reply_addr.sa.s); assert_int_equal(r_msgs[i].msg_len, tmsgs[i].s_iov.iov_len); assert_memory_equal(tmsgs[i].send_buf, tmsgs[i].recv_buf, sizeof(tmsgs[i].send_buf)); } rc = close(s); assert_int_equal(rc, 0); } #ifdef HAVE_IPV6 static void test_sendmmsg_recvmmsg_ipv6(void **state) { struct torture_address addr = { .sa_socklen = sizeof(struct sockaddr_storage), }; struct { struct torture_address reply_addr; struct iovec s_iov; struct iovec r_iov; char send_buf[64]; char recv_buf[64]; } tmsgs[10] = {}; struct mmsghdr s_msgs[10] = {}; struct mmsghdr r_msgs[10] = {}; ssize_t ret; int rc; int i; int s; (void) state; /* unused */ s = socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP); assert_int_not_equal(s, -1); addr.sa.in.sin_family = AF_INET6; addr.sa.in.sin_port = htons(torture_server_port()); rc = inet_pton(AF_INET6, torture_server_address(AF_INET6), &addr.sa.in6.sin6_addr); assert_int_equal(rc, 1); rc = connect(s, &addr.sa.s, addr.sa_socklen); assert_return_code(rc, errno); for (i = 0; i < 10; i++) { tmsgs[i].reply_addr = (struct torture_address){ .sa_socklen = sizeof(struct sockaddr_storage), }; snprintf(tmsgs[i].send_buf, sizeof(tmsgs[i].send_buf), "packet.%d", i); tmsgs[i].s_iov.iov_base = tmsgs[i].send_buf; tmsgs[i].s_iov.iov_len = sizeof(tmsgs[i].send_buf); s_msgs[i].msg_hdr.msg_name = &addr.sa.s; s_msgs[i].msg_hdr.msg_namelen = addr.sa_socklen; s_msgs[i].msg_hdr.msg_iov = &tmsgs[i].s_iov; s_msgs[i].msg_hdr.msg_iovlen = 1; tmsgs[i].r_iov.iov_base = tmsgs[i].recv_buf; tmsgs[i].r_iov.iov_len = sizeof(tmsgs[i].recv_buf); r_msgs[i].msg_hdr.msg_name = &tmsgs[i].reply_addr.sa.s; r_msgs[i].msg_hdr.msg_namelen = tmsgs[i].reply_addr.sa_socklen; r_msgs[i].msg_hdr.msg_iov = &tmsgs[i].r_iov; r_msgs[i].msg_hdr.msg_iovlen = 1; } ret = sendmmsg(s, s_msgs, 10, 0); assert_int_equal(ret, 10); ret = recvmmsg(s, r_msgs, 10, 0, NULL); assert_int_equal(ret, 10); for (i = 0; i < 10; i++) { assert_int_equal(r_msgs[i].msg_hdr.msg_namelen, 0); assert_ptr_equal(r_msgs[i].msg_hdr.msg_name, &tmsgs[i].reply_addr.sa.s); assert_int_equal(r_msgs[i].msg_len, tmsgs[i].s_iov.iov_len); assert_memory_equal(tmsgs[i].send_buf, tmsgs[i].recv_buf, sizeof(tmsgs[i].send_buf)); } rc = close(s); assert_int_equal(rc, 0); } #endif static void test_sendmmsg_recvmmsg_ipv4_null(void **state) { struct torture_address addr = { .sa_socklen = sizeof(struct sockaddr_storage), }; struct { struct torture_address reply_addr; struct iovec s_iov; struct iovec r_iov; char send_buf[64]; char recv_buf[64]; } tmsgs[10] = {}; struct mmsghdr s_msgs[10] = {}; struct mmsghdr r_msgs[10] = {}; ssize_t ret; int rc; int i; int s; (void) state; /* unused */ s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); assert_int_not_equal(s, -1); addr.sa.in.sin_family = AF_INET; addr.sa.in.sin_port = htons(torture_server_port()); rc = inet_pton(AF_INET, torture_server_address(AF_INET), &addr.sa.in.sin_addr); assert_int_equal(rc, 1); rc = connect(s, &addr.sa.s, addr.sa_socklen); assert_return_code(rc, errno); for (i = 0; i < 10; i++) { tmsgs[i].reply_addr = (struct torture_address){ .sa_socklen = sizeof(struct sockaddr_storage), }; snprintf(tmsgs[i].send_buf, sizeof(tmsgs[i].send_buf), "packet.%d", i); tmsgs[i].s_iov.iov_base = tmsgs[i].send_buf; tmsgs[i].s_iov.iov_len = sizeof(tmsgs[i].send_buf); s_msgs[i].msg_hdr.msg_name = NULL; s_msgs[i].msg_hdr.msg_namelen = 0; s_msgs[i].msg_hdr.msg_iov = &tmsgs[i].s_iov; s_msgs[i].msg_hdr.msg_iovlen = 1; tmsgs[i].r_iov.iov_base = tmsgs[i].recv_buf; tmsgs[i].r_iov.iov_len = sizeof(tmsgs[i].recv_buf); r_msgs[i].msg_hdr.msg_name = NULL; r_msgs[i].msg_hdr.msg_namelen = 0; r_msgs[i].msg_hdr.msg_iov = &tmsgs[i].r_iov; r_msgs[i].msg_hdr.msg_iovlen = 1; } ret = sendmmsg(s, s_msgs, 10, 0); assert_int_equal(ret, 10); ret = recvmmsg(s, r_msgs, 10, 0, NULL); assert_int_equal(ret, 10); for (i = 0; i < 10; i++) { assert_int_equal(r_msgs[i].msg_hdr.msg_namelen, 0); assert_null(r_msgs[i].msg_hdr.msg_name); assert_int_equal(r_msgs[i].msg_len, tmsgs[i].s_iov.iov_len); assert_memory_equal(tmsgs[i].send_buf, tmsgs[i].recv_buf, sizeof(tmsgs[i].send_buf)); } rc = close(s); assert_int_equal(rc, 0); } #ifdef SYS_recvmmsg static int __raw_syscall_close(int sockfd) { return syscall(SYS_close, sockfd); } static int __raw_syscall_recvmmsg(int sockfd, struct mmsghdr *msgvec, unsigned int vlen, int flags, struct timespec *timeout) { return syscall(SYS_recvmmsg, sockfd, (uintptr_t)msgvec, vlen, flags, (uintptr_t)timeout); } static int __raw_syscall_sendmmsg(int sockfd, struct mmsghdr *msgvec, unsigned int vlen, int flags) { return syscall(SYS_sendmmsg, sockfd, (uintptr_t)msgvec, vlen, flags); } static void test_sendmmsg_recvmmsg_ipv4_raw(void **state) { struct torture_address addr = { .sa_socklen = sizeof(struct sockaddr_storage), }; struct { struct torture_address reply_addr; struct iovec s_iov; struct iovec r_iov; char send_buf[64]; char recv_buf[64]; } tmsgs[10] = {}; struct mmsghdr s_msgs[10] = {}; struct mmsghdr r_msgs[10] = {}; ssize_t ret; int rc; int i; int s; (void) state; /* unused */ s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); assert_int_not_equal(s, -1); addr.sa.in.sin_family = AF_INET; addr.sa.in.sin_port = htons(torture_server_port()); rc = inet_pton(AF_INET, torture_server_address(AF_INET), &addr.sa.in.sin_addr); assert_int_equal(rc, 1); rc = connect(s, &addr.sa.s, addr.sa_socklen); assert_return_code(rc, errno); /* This should be ignored */ rc = inet_pton(AF_INET, "127.0.0.1", &addr.sa.in.sin_addr); assert_int_equal(rc, 1); for (i = 0; i < 10; i++) { tmsgs[i].reply_addr = (struct torture_address){ .sa_socklen = sizeof(struct sockaddr_storage), }; snprintf(tmsgs[i].send_buf, sizeof(tmsgs[i].send_buf), "packet.%d", i); tmsgs[i].s_iov.iov_base = tmsgs[i].send_buf; tmsgs[i].s_iov.iov_len = sizeof(tmsgs[i].send_buf); s_msgs[i].msg_hdr.msg_name = &addr.sa.s; s_msgs[i].msg_hdr.msg_namelen = addr.sa_socklen; s_msgs[i].msg_hdr.msg_iov = &tmsgs[i].s_iov; s_msgs[i].msg_hdr.msg_iovlen = 1; tmsgs[i].r_iov.iov_base = tmsgs[i].recv_buf; tmsgs[i].r_iov.iov_len = sizeof(tmsgs[i].recv_buf); r_msgs[i].msg_hdr.msg_name = &tmsgs[i].reply_addr.sa.s; r_msgs[i].msg_hdr.msg_namelen = tmsgs[i].reply_addr.sa_socklen; r_msgs[i].msg_hdr.msg_iov = &tmsgs[i].r_iov; r_msgs[i].msg_hdr.msg_iovlen = 1; } ret = __raw_syscall_sendmmsg(s, s_msgs, 10, 0); assert_int_equal(ret, 10); ret = __raw_syscall_recvmmsg(s, r_msgs, 10, 0, NULL); assert_int_equal(ret, 10); for (i = 0; i < 10; i++) { assert_int_equal(r_msgs[i].msg_hdr.msg_namelen, 0); assert_ptr_equal(r_msgs[i].msg_hdr.msg_name, &tmsgs[i].reply_addr.sa.s); assert_int_equal(r_msgs[i].msg_len, tmsgs[i].s_iov.iov_len); assert_memory_equal(tmsgs[i].send_buf, tmsgs[i].recv_buf, sizeof(tmsgs[i].send_buf)); } rc = __raw_syscall_close(s); assert_int_equal(rc, 0); } #endif /* SYS_recvmmsg */ int main(void) { int rc; const struct CMUnitTest sendmsg_tests[] = { cmocka_unit_test_setup_teardown(test_sendmmsg_recvmmsg_ipv4_ignore, setup_echo_srv_tcp_ipv4, teardown), cmocka_unit_test_setup_teardown(test_sendmmsg_recvmmsg_ipv4_null, setup_echo_srv_tcp_ipv4, teardown), #ifdef SYS_recvmmsg cmocka_unit_test_setup_teardown(test_sendmmsg_recvmmsg_ipv4_raw, setup_echo_srv_tcp_ipv4, teardown), #endif /* SYS_recvmmsg */ #ifdef HAVE_IPV6 cmocka_unit_test_setup_teardown(test_sendmmsg_recvmmsg_ipv6, setup_echo_srv_tcp_ipv6, teardown), #endif }; rc = cmocka_run_group_tests(sendmsg_tests, NULL, NULL); return rc; } socket_wrapper-1.4.4/tests/echo_srv.c000644 001750 000144 00000054775 14631527256 017703 0ustar00asnusers000000 000000 #include "config.h" #include #include #include #include #include #include #include #include #ifdef HAVE_NETINET_TCP_FSM_H #include #endif #include #include #include #include #include #include #include #include #include #ifndef PIDFILE #define PIDFILE "echo_srv.pid" #endif /* PIDFILE */ #define ECHO_SRV_IPV4 "127.0.0.10" /* socket wrapper IPv6 prefix fd00::5357:5fxx */ #define ECHO_SRV_IPV6 "fd00::5357:5f0a" #define DFL_PORT 7 #define BACKLOG 16 #ifndef BUFSIZE #define BUFSIZE 0x20000 /* 128K */ #endif /* BUFSIZE */ #ifndef discard_const #define discard_const(ptr) ((void *)((uintptr_t)(ptr))) #endif #ifndef discard_const_p #define discard_const_p(type, ptr) ((type *)discard_const(ptr)) #endif #ifndef ZERO_STRUCT #define ZERO_STRUCT(x) memset((char *)&(x), 0, sizeof(x)) #endif struct torture_address { socklen_t sa_socklen; union { struct sockaddr s; struct sockaddr_in in; #ifdef HAVE_IPV6 struct sockaddr_in6 in6; #endif struct sockaddr_storage ss; } sa; }; struct echo_srv_opts { int port; int socktype; bool daemon; char *bind; const char *pidfile; }; #ifdef HAVE_STRUCT_MSGHDR_MSG_CONTROL #if defined(IP_PKTINFO) || defined(IP_RECVDSTADDR) || defined(IPV6_PKTINFO) union pktinfo { #ifdef HAVE_STRUCT_IN6_PKTINFO struct in6_pktinfo pkt6; #endif #ifdef HAVE_STRUCT_IN_PKTINFO struct in_pktinfo pkt4; #elif defined(IP_RECVDSTADDR) struct in_addr pkt4; #endif char c; }; #define HAVE_UNION_PKTINFO 1 #endif /* IP_PKTINFO || IP_RECVDSTADDR || IPV6_PKTINFO */ static const char *echo_server_address(int family) { switch (family) { case AF_INET: { const char *ip4 = getenv("TORTURE_SERVER_ADDRESS_IPV4"); if (ip4 != NULL && ip4[0] != '\0') { return ip4; } return ECHO_SRV_IPV4; } #ifdef HAVE_IPV6 case AF_INET6: { const char *ip6 = getenv("TORTURE_SERVER_ADDRESS_IPV6"); if (ip6 != NULL && ip6[0] != '\0') { return ip6; } return ECHO_SRV_IPV6; } #endif default: return NULL; } return NULL; } #endif /* HAVE_STRUCT_MSGHDR_MSG_CONTROL */ static void _assert_return_code(int rc, int err, const char * const file, const int line) { if (rc < 0) { fprintf(stderr, "Fatal error: %s\n", strerror(err)); fprintf(stderr, "%s:%d", file, line); abort(); } } #define assert_return_code(rc, err) \ _assert_return_code(rc, err, __FILE__, __LINE__) static int pidfile(const char *path) { int err; int fd; char pid_str[32] = { 0 }; ssize_t nwritten; size_t len; fd = open(path, O_RDONLY, 0644); err = errno; if (fd != -1) { close(fd); return EEXIST; } else if (err != ENOENT) { return err; } fd = open(path, O_CREAT | O_WRONLY | O_EXCL, 0644); err = errno; if (fd == -1) { return err; } snprintf(pid_str, sizeof(pid_str) -1, "%u\n", (unsigned int) getpid()); len = strlen(pid_str); nwritten = write(fd, pid_str, len); close(fd); if (nwritten != (ssize_t)len) { return EIO; } return 0; } static int become_daemon(void) { int ret; pid_t child_pid; int fd; int i; if (getppid() == 1) { return 0; } child_pid = fork(); if (child_pid == -1) { ret = errno; perror("fork"); return ret; } else if (child_pid > 0) { exit(0); } /* If a working directory was defined, go there */ #ifdef WORKING_DIR chdir(WORKING_DIR); #endif ret = setsid(); if (ret == -1) { ret = errno; perror("setsid"); return ret; } for (i = 0; i < 3; i++) { close(i); fd = open("/dev/null", O_RDWR, 0); if (fd < 0) { fd = open("/dev/null", O_WRONLY, 0); } if (fd < 0) { ret = errno; perror("Can't open /dev/null"); return ret; } if (fd != i) { perror("Didn't get correct fd"); close(fd); return EINVAL; } } umask(0177); return 0; } static void set_sock_pktinfo(int sock, int family) { int sockopt = 1; int option = 0; int proto = 0; int rc; switch(family) { case AF_INET: proto = IPPROTO_IP; #ifdef IP_PKTINFO option = IP_PKTINFO; #elif IP_RECVDSTADDR option = IP_RECVDSTADDR; #else return; #endif /* IP_PKTINFO */ break; #ifdef HAVE_IPV6 #ifdef IPV6_RECVPKTINFO case AF_INET6: proto = IPPROTO_IPV6; option = IPV6_RECVPKTINFO; break; #endif /* IPV6_RECVPKTINFO */ #endif /* HAVE_IPV6 */ default: return; } rc = setsockopt(sock, proto, option, &sockopt, sizeof(sockopt)); assert_return_code(rc, errno); } /* Returns 0 on success, errno on failure. If successful, * sock is a ready to use socket */ static int setup_srv(struct echo_srv_opts *opts, int *_sock) { struct addrinfo hints; struct addrinfo *res, *ri; char svc[6]; int ret; int sock; memset(&hints, 0, sizeof(hints)); hints.ai_family = AF_UNSPEC; hints.ai_socktype = opts->socktype; hints.ai_flags = AI_PASSIVE; snprintf(svc, sizeof(svc), "%d", opts->port); ret = getaddrinfo(opts->bind, svc, &hints, &res); if (ret != 0) { return errno; } for (ri = res; ri != NULL; ri = ri->ai_next) { sock = socket(ri->ai_family, ri->ai_socktype, ri->ai_protocol); if (sock == -1) { ret = errno; freeaddrinfo(res); perror("socket"); return ret; } if (ri->ai_socktype == SOCK_DGRAM) { set_sock_pktinfo(sock, ri->ai_family); } ret = bind(sock, ri->ai_addr, ri->ai_addrlen); if (ret == 0) { break; } close(sock); } freeaddrinfo(res); if (ri == NULL) { fprintf(stderr, "Could not bind\n"); return EFAULT; } if (opts->socktype == SOCK_STREAM) { ret = listen(sock, BACKLOG); if (ret == -1) { ret = errno; close(sock); perror("listen"); return ret; } #ifdef TCP_INFO { struct tcp_info info; socklen_t optlen = sizeof(info); ZERO_STRUCT(info); ret = getsockopt(sock, IPPROTO_TCP, TCP_INFO, &info, &optlen); if (ret == -1) { ret = errno; perror("TCP_INFO failed"); close(sock); return ret; } #ifdef HAVE_NETINET_TCP_FSM_H /* This is FreeBSD */ # define __TCP_LISTEN TCPS_LISTEN #else /* This is Linux */ # define __TCP_LISTEN TCP_LISTEN #endif if (info.tcpi_state != __TCP_LISTEN) { errno = ret = ERANGE; perror("not __TCP_LISTEN => ERANGE..."); close(sock); return ret; } } #endif /* TCP_INFO */ } *_sock = sock; return 0; } static int socket_dup(int s) { struct torture_address cli_addr1 = { .sa_socklen = sizeof(struct sockaddr_storage), }; struct torture_address srv_addr1 = { .sa_socklen = sizeof(struct sockaddr_storage), }; struct torture_address cli_addr2 = { .sa_socklen = sizeof(struct sockaddr_storage), }; struct torture_address srv_addr2 = { .sa_socklen = sizeof(struct sockaddr_storage), }; struct torture_address cli_addr3 = { .sa_socklen = sizeof(struct sockaddr_storage), }; struct torture_address srv_addr3 = { .sa_socklen = sizeof(struct sockaddr_storage), }; int s2; int rc; rc = getsockname(s, &srv_addr1.sa.s, &srv_addr1.sa_socklen); if (rc == -1) { perror("getsockname"); return -1; } rc = getpeername(s, &cli_addr1.sa.s, &cli_addr1.sa_socklen); if (rc == -1) { perror("getpeername"); return -1; } if (cli_addr1.sa.ss.ss_family != srv_addr1.sa.ss.ss_family) { perror("client/server family mismatch"); return -1; } /* Test dup */ s2 = dup(s); if (s2 == -1) { perror("dup"); return -1; } close(s); rc = getsockname(s2, &srv_addr2.sa.s, &srv_addr2.sa_socklen); if (rc == -1) { perror("getsockname"); close(s2); return -1; } rc = getpeername(s2, &cli_addr2.sa.s, &cli_addr2.sa_socklen); if (rc == -1) { perror("getpeername"); close(s2); return -1; } if (cli_addr1.sa_socklen != cli_addr2.sa_socklen || srv_addr1.sa_socklen != srv_addr2.sa_socklen) { perror("length mismatch"); close(s2); return -1; } switch(cli_addr1.sa.ss.ss_family) { case AF_INET: { rc = memcmp(&cli_addr1.sa.in, &cli_addr2.sa.in, sizeof(struct sockaddr_in)); if (rc != 0) { perror("client mismatch"); } rc = memcmp(&srv_addr1.sa.in, &srv_addr2.sa.in, sizeof(struct sockaddr_in)); if (rc != 0) { perror("server mismatch"); } break; } #ifdef HAVE_IPV6 case AF_INET6: { rc = memcmp(&cli_addr1.sa.in6, &cli_addr2.sa.in6, sizeof(struct sockaddr_in6)); if (rc != 0) { perror("client mismatch"); } rc = memcmp(&srv_addr1.sa.in6, &srv_addr2.sa.in6, sizeof(struct sockaddr_in6)); if (rc != 0) { perror("server mismatch"); } break; } #endif default: perror("family mismatch"); close(s2); return -1; } /* Test dup2 */ s = dup2(s2, s); close(s2); if (s == -1) { perror("dup"); return -1; } rc = getsockname(s, &srv_addr3.sa.s, &srv_addr3.sa_socklen); if (rc == -1) { perror("getsockname"); close(s); return -1; } rc = getpeername(s, &cli_addr3.sa.s, &cli_addr3.sa_socklen); if (rc == -1) { perror("getpeername"); close(s); return -1; } if (cli_addr2.sa_socklen != cli_addr3.sa_socklen || srv_addr2.sa_socklen != srv_addr3.sa_socklen) { perror("length mismatch"); close(s); return -1; } switch(cli_addr2.sa.ss.ss_family) { case AF_INET: { rc = memcmp(&cli_addr1.sa.in, &cli_addr2.sa.in, sizeof(struct sockaddr_in)); if (rc != 0) { perror("client mismatch"); } rc = memcmp(&srv_addr1.sa.in, &srv_addr2.sa.in, sizeof(struct sockaddr_in)); if (rc != 0) { perror("server mismatch"); } break; } #ifdef HAVE_IPV6 case AF_INET6: { rc = memcmp(&cli_addr1.sa.in6, &cli_addr2.sa.in6, sizeof(struct sockaddr_in6)); if (rc != 0) { perror("client mismatch"); } rc = memcmp(&srv_addr1.sa.in6, &srv_addr2.sa.in6, sizeof(struct sockaddr_in6)); if (rc != 0) { perror("server mismatch"); } break; } #endif default: perror("family mismatch"); close(s); return -1; } return s; } static void echo_tcp(int sock) { struct torture_address addr = { .sa_socklen = sizeof(struct sockaddr_storage), }; char buf[BUFSIZE]; ssize_t bret; int client_sock = -1; int s; pid_t pid; while (1) { waitpid(-1, NULL, WNOHANG); s = accept(sock, &addr.sa.s, &addr.sa_socklen); if (s == -1 && errno == ECONNABORTED) { continue; } if (s == -1) { perror("accept"); goto done; } pid = fork(); if (pid == -1) { perror("fork"); } else if (pid == 0) { close(sock); client_sock = socket_dup(s); if (client_sock == -1) { perror("socket_dup"); goto done; } while (1) { bret = recv(client_sock, buf, BUFSIZE, 0); if (bret == -1) { perror("recv"); goto done; } else if (bret == 0) { break; } bret = send(client_sock, buf, bret, 0); if (bret == -1) { perror("send"); goto done; } } close(s); exit(0); } close(s); } done: if (client_sock != -1) { close(client_sock); } } static ssize_t echo_udp_recv_from_to(int sock, void *buf, size_t buflen, int flags, struct torture_address *from, struct torture_address *to) { struct msghdr rmsg; struct iovec riov; ssize_t ret; #if defined(HAVE_STRUCT_MSGHDR_MSG_CONTROL) && defined(HAVE_UNION_PKTINFO) size_t cmlen = CMSG_LEN(sizeof(union pktinfo)); char cmsg[cmlen]; #endif /* HAVE_STRUCT_MSGHDR_MSG_CONTROL */ riov.iov_base = buf; riov.iov_len = buflen; ZERO_STRUCT(rmsg); rmsg.msg_name = &from->sa.s; rmsg.msg_namelen = from->sa_socklen; rmsg.msg_iov = &riov; rmsg.msg_iovlen = 1; #if defined(HAVE_STRUCT_MSGHDR_MSG_CONTROL) && defined(HAVE_UNION_PKTINFO) memset(cmsg, 0, cmlen); rmsg.msg_control = cmsg; rmsg.msg_controllen = cmlen; #endif ret = recvmsg(sock, &rmsg, flags); if (ret < 0) { return ret; } from->sa_socklen = rmsg.msg_namelen; #if defined(HAVE_STRUCT_MSGHDR_MSG_CONTROL) && defined(HAVE_UNION_PKTINFO) if (rmsg.msg_controllen > 0) { struct cmsghdr *cmsgptr; cmsgptr = CMSG_FIRSTHDR(&rmsg); while (cmsgptr != NULL) { const char *p; #if defined(IP_PKTINFO) && defined(HAVE_STRUCT_IN_PKTINFO) if (cmsgptr->cmsg_level == IPPROTO_IP && cmsgptr->cmsg_type == IP_PKTINFO) { char ip[INET_ADDRSTRLEN] = { 0 }; struct in_pktinfo *pkt; void *cmsg_cast_ptr = CMSG_DATA(cmsgptr); pkt = (struct in_pktinfo *)cmsg_cast_ptr; to->sa.in.sin_family = AF_INET; to->sa.in.sin_addr = pkt->ipi_addr; to->sa_socklen = sizeof(struct sockaddr_in); p = inet_ntop(AF_INET, &to->sa.in.sin_addr, ip, sizeof(ip)); if (p == 0) { fprintf(stderr, "Failed to convert IP address"); abort(); } if (strcmp(ip, echo_server_address(AF_INET)) != 0) { fprintf(stderr, "Wrong IP received"); abort(); } } #endif /* IP_PKTINFO */ #ifdef IP_RECVDSTADDR if (cmsgptr->cmsg_level == IPPROTO_IP && cmsgptr->cmsg_type == IP_RECVDSTADDR) { char ip[INET_ADDRSTRLEN] = { 0 }; struct in_addr *addr; void *cmsg_cast_ptr = CMSG_DATA(cmsgptr); addr = (struct in_addr *)cmsg_cast_ptr; to->sa.in.sin_family = AF_INET; to->sa.in.sin_addr = *addr; to->sa_socklen = sizeof(struct sockaddr_in); p = inet_ntop(AF_INET, &to->sa.in.sin_addr, ip, sizeof(ip)); if (p == 0) { fprintf(stderr, "Failed to convert IP address"); abort(); } if (strcmp(ip, echo_server_address(AF_INET)) != 0) { fprintf(stderr, "Wrong IP received"); abort(); } } #endif /* IP_RECVDSTADDR */ #if defined(IPV6_PKTINFO) && defined(HAVE_STRUCT_IN6_PKTINFO) if (cmsgptr->cmsg_level == IPPROTO_IPV6 && cmsgptr->cmsg_type == IPV6_PKTINFO) { char ip[INET6_ADDRSTRLEN] = { 0 }; struct in6_pktinfo *pkt6; void *cmsg_cast_ptr = CMSG_DATA(cmsgptr); pkt6 = (struct in6_pktinfo *)cmsg_cast_ptr; to->sa.in6.sin6_family = AF_INET6; to->sa.in6.sin6_addr = pkt6->ipi6_addr; p = inet_ntop(AF_INET6, &to->sa.in6.sin6_addr, ip, sizeof(ip)); if (p == 0) { fprintf(stderr, "Failed to convert IP address"); abort(); } if (strcmp(ip, echo_server_address(AF_INET6)) != 0) { fprintf(stderr, "Wrong IP received"); abort(); } } #endif /* IPV6_PKTINFO */ cmsgptr = CMSG_NXTHDR(&rmsg, cmsgptr); } } else { fprintf(stderr, "Failed to receive pktinfo"); abort(); } #endif /* HAVE_STRUCT_MSGHDR_MSG_CONTROL && HAVE_UNION_PKTINFO */ return ret; } static ssize_t echo_udp_send_to_from(int sock, void *buf, size_t buflen, int flags, struct sockaddr *to, socklen_t tolen, struct sockaddr *from, socklen_t fromlen) { struct msghdr msg; struct iovec iov; ssize_t ret; #if defined(HAVE_STRUCT_MSGHDR_MSG_CONTROL) && defined(HAVE_UNION_PKTINFO) size_t clen = CMSG_SPACE(sizeof(union pktinfo)); char cbuf[clen]; struct cmsghdr *cmsgptr; #else (void)from; /* unused */ (void)fromlen; /* unused */ #endif /* HAVE_STRUCT_MSGHDR_MSG_CONTROL && HAVE_UNION_PKTINFO */ iov.iov_base = buf; iov.iov_len = buflen; ZERO_STRUCT(msg); msg.msg_name = to; msg.msg_namelen = tolen; msg.msg_iov = &iov; msg.msg_iovlen = 1; #if defined(HAVE_STRUCT_MSGHDR_MSG_CONTROL) && defined(HAVE_UNION_PKTINFO) memset(cbuf, 0, clen); msg.msg_control = cbuf; msg.msg_controllen = clen; cmsgptr = CMSG_FIRSTHDR(&msg); msg.msg_controllen = 0; switch (from->sa_family) { #if defined(IP_PKTINFO) || defined(IP_SENDSRCADDR) case AF_INET: { void *cmsg_cast_ptr = CMSG_DATA(cmsgptr); #ifdef IP_PKTINFO struct in_pktinfo *p = (struct in_pktinfo *)cmsg_cast_ptr; #elif defined(IP_SENDSRCADDR) struct in_addr *p = (struct in_addr *)cmsg_cast_ptr; #endif const struct sockaddr_in *from4 = (const struct sockaddr_in *)(const void *)from; if (fromlen != sizeof(struct sockaddr_in)) { break; } cmsgptr->cmsg_level = IPPROTO_IP; #ifdef IP_PKTINFO cmsgptr->cmsg_type = IP_PKTINFO; p->ipi_spec_dst = from4->sin_addr; #elif defined(IP_SENDSRCADDR) cmsgptr->cmsg_type = IP_SENDSRCADDR; *p = from4->sin_addr; #endif cmsgptr->cmsg_len = CMSG_LEN(sizeof(*p)); msg.msg_controllen = CMSG_SPACE(sizeof(*p)); break; } #endif /* IP_PKTINFO || IP_SENDSRCADDR */ #ifdef IPV6_PKTINFO case AF_INET6: { void *cast_ptr = CMSG_DATA(cmsgptr); struct in6_pktinfo *p = (struct in6_pktinfo *)cast_ptr; const struct sockaddr_in6 *from6 = (const struct sockaddr_in6 *)(const void *)from; if (fromlen != sizeof(struct sockaddr_in6)) { break; } cmsgptr->cmsg_level = IPPROTO_IPV6; cmsgptr->cmsg_type = IPV6_PKTINFO; cmsgptr->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo)); p->ipi6_addr = from6->sin6_addr; msg.msg_controllen = CMSG_SPACE(sizeof(struct in6_pktinfo)); break; } #endif /* IPV6_PKTINFO */ default: break; } #endif /* HAVE_STRUCT_MSGHDR_MSG_CONTROL && HAVE_UNION_PKTINFO */ ret = sendmsg(sock, &msg, flags); return ret; } static void echo_udp(int sock) { struct torture_address saddr = { .sa_socklen = sizeof(struct sockaddr_storage), }; struct torture_address daddr = { .sa_socklen = sizeof(struct sockaddr_storage), }; ssize_t bret; char buf[BUFSIZE]; while (1) { bret = echo_udp_recv_from_to(sock, buf, BUFSIZE, 0, &saddr, &daddr); if (bret == -1) { perror("recvfrom"); continue; } bret = echo_udp_send_to_from(sock, buf, bret, 0, &saddr.sa.s, saddr.sa_socklen, &daddr.sa.s, daddr.sa_socklen); if (bret == -1) { perror("sendto"); continue; } } } static void echo(int sock, struct echo_srv_opts *opts) { switch (opts->socktype) { case SOCK_STREAM: echo_tcp(sock); return; case SOCK_DGRAM: echo_udp(sock); return; default: fprintf(stderr, "Unsupported protocol\n"); return; } } int main(int argc, char **argv) { int ret; int sock = -1; struct echo_srv_opts opts; int opt; int optindex; static struct option long_options[] = { { discard_const_p(char, "tcp"), no_argument, 0, 't' }, { discard_const_p(char, "udp"), no_argument, 0, 'u' }, { discard_const_p(char, "bind-addr"), required_argument, 0, 'b' }, { discard_const_p(char, "port"), required_argument, 0, 'p' }, { discard_const_p(char, "daemon"), no_argument, 0, 'D' }, { discard_const_p(char, "pid"), required_argument, 0, 0 }, {0, 0, 0, 0 } }; opts.port = DFL_PORT; opts.socktype = SOCK_STREAM; opts.bind = NULL; opts.pidfile = PIDFILE; opts.daemon = false; while ((opt = getopt_long(argc, argv, "Dutp:b:", long_options, &optindex)) != -1) { switch (opt) { case 0: if (optindex == 5) { opts.pidfile = optarg; } break; case 'p': opts.port = atoi(optarg); break; case 'b': opts.bind = optarg; break; case 'u': opts.socktype = SOCK_DGRAM; break; case 't': opts.socktype = SOCK_STREAM; break; case 'D': opts.daemon = true; break; default: /* '?' */ fprintf(stderr, "Usage: %s [-p port] [-u] [-t] [-b bind_addr] " \ "[-D] [--pid pidfile]\n" "-t makes the server listen on TCP\n" "-u makes the server listen on UDP\n" "-D tells the server to become a daemon and " \ "write a PIDfile\n" "The default port is 7, the default PIDfile is " \ "echo_srv.pid in the current directory\n", argv[0]); ret = 1; goto done; } } if (opts.daemon) { ret = become_daemon(); if (ret != 0) { fprintf(stderr, "Cannot become daemon: %s\n", strerror(ret)); goto done; } } ret = setup_srv(&opts, &sock); if (ret != 0) { fprintf(stderr, "Cannot setup server: %s\n", strerror(ret)); goto done; } if (opts.daemon && opts.pidfile != NULL) { ret = pidfile(opts.pidfile); if (ret != 0) { fprintf(stderr, "Cannot create pidfile %s: %s\n", opts.pidfile, strerror(ret)); goto done; } } echo(sock, &opts); if (sock >= 0) { close(sock); } if (opts.daemon && opts.pidfile != NULL) { unlink(opts.pidfile); } ret = 0; done: return ret; } socket_wrapper-1.4.4/socket_wrapper-config.cmake.in000644 001750 000144 00000000115 14631527256 022442 0ustar00asnusers000000 000000 set(SOCKET_WRAPPER_LIBRARY @CMAKE_INSTALL_FULL_LIBDIR@/@SOCKET_WRAPPER_LIB@) socket_wrapper-1.4.4/CompilerChecks.cmake000644 001750 000144 00000012627 14631527256 020450 0ustar00asnusers000000 000000 include(AddCCompilerFlag) include(CheckCCompilerFlagSSP) if (UNIX) # # Check for -Werror turned on if possible # # This will prevent that compiler flags are detected incorrectly. # check_c_compiler_flag("-Werror" REQUIRED_FLAGS_WERROR) if (REQUIRED_FLAGS_WERROR) set(CMAKE_REQUIRED_FLAGS "-Werror") if (PICKY_DEVELOPER) list(APPEND SUPPORTED_COMPILER_FLAGS "-Werror") endif() endif() add_c_compiler_flag("-std=gnu99" SUPPORTED_COMPILER_FLAGS) #add_c_compiler_flag("-Wpedantic" SUPPORTED_COMPILER_FLAGS) add_c_compiler_flag("-Wall" SUPPORTED_COMPILER_FLAGS) add_c_compiler_flag("-Wshadow" SUPPORTED_COMPILER_FLAGS) add_c_compiler_flag("-Wmissing-prototypes" SUPPORTED_COMPILER_FLAGS) add_c_compiler_flag("-Wcast-align" SUPPORTED_COMPILER_FLAGS) add_c_compiler_flag("-Wcast-qual" SUPPORTED_COMPILER_FLAGS) add_c_compiler_flag("-Werror=address" SUPPORTED_COMPILER_FLAGS) add_c_compiler_flag("-Wstrict-prototypes" SUPPORTED_COMPILER_FLAGS) add_c_compiler_flag("-Werror=strict-prototypes" SUPPORTED_COMPILER_FLAGS) add_c_compiler_flag("-Wwrite-strings" SUPPORTED_COMPILER_FLAGS) add_c_compiler_flag("-Werror=write-strings" SUPPORTED_COMPILER_FLAGS) add_c_compiler_flag("-Werror-implicit-function-declaration" SUPPORTED_COMPILER_FLAGS) add_c_compiler_flag("-Wpointer-arith" SUPPORTED_COMPILER_FLAGS) add_c_compiler_flag("-Werror=pointer-arith" SUPPORTED_COMPILER_FLAGS) add_c_compiler_flag("-Wdeclaration-after-statement" SUPPORTED_COMPILER_FLAGS) add_c_compiler_flag("-Werror=declaration-after-statement" SUPPORTED_COMPILER_FLAGS) add_c_compiler_flag("-Wreturn-type" SUPPORTED_COMPILER_FLAGS) add_c_compiler_flag("-Werror=return-type" SUPPORTED_COMPILER_FLAGS) add_c_compiler_flag("-Wuninitialized" SUPPORTED_COMPILER_FLAGS) add_c_compiler_flag("-Werror=uninitialized" SUPPORTED_COMPILER_FLAGS) add_c_compiler_flag("-Wimplicit-fallthrough" SUPPORTED_COMPILER_FLAGS) # FIXME: We can't use this as there is a glibc bug in socket.h # https://bugzilla.redhat.com/show_bug.cgi?id=2047022 # https://sourceware.org/bugzilla/show_bug.cgi?id=28846 #add_c_compiler_flag("-Werror=strict-overflow" SUPPORTED_COMPILER_FLAGS) #add_c_compiler_flag("-Wstrict-overflow=2" SUPPORTED_COMPILER_FLAGS) add_c_compiler_flag("-Wno-format-zero-length" SUPPORTED_COMPILER_FLAGS) check_c_compiler_flag("-Wformat" REQUIRED_FLAGS_WFORMAT) if (REQUIRED_FLAGS_WFORMAT) list(APPEND SUPPORTED_COMPILER_FLAGS "-Wformat") set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} -Wformat") endif() add_c_compiler_flag("-Wformat-security" SUPPORTED_COMPILER_FLAGS) add_c_compiler_flag("-Werror=format-security" SUPPORTED_COMPILER_FLAGS) # Allow zero for a variadic macro argument string(TOLOWER "${CMAKE_C_COMPILER_ID}" _C_COMPILER_ID) if ("${_C_COMPILER_ID}" STREQUAL "clang") add_c_compiler_flag("-Wno-gnu-zero-variadic-macro-arguments" SUPPORTED_COMPILER_FLAGS) endif() add_c_compiler_flag("-fno-common" SUPPORTED_COMPILER_FLAGS) if (CMAKE_BUILD_TYPE) string(TOLOWER "${CMAKE_BUILD_TYPE}" CMAKE_BUILD_TYPE_LOWER) if (CMAKE_BUILD_TYPE_LOWER MATCHES (release|relwithdebinfo|minsizerel)) add_c_compiler_flag("-Wp,-D_FORTIFY_SOURCE=2" SUPPORTED_COMPILER_FLAGS) endif() endif() if (NOT SOLARIS) check_c_compiler_flag_ssp("-fstack-protector-strong" WITH_STACK_PROTECTOR_STRONG) if (WITH_STACK_PROTECTOR_STRONG) list(APPEND SUPPORTED_COMPILER_FLAGS "-fstack-protector-strong") # This is needed as Solaris has a seperate libssp if (SOLARIS) list(APPEND SUPPORTED_LINKER_FLAGS "-fstack-protector-strong") endif() else (WITH_STACK_PROTECTOR_STRONG) check_c_compiler_flag_ssp("-fstack-protector" WITH_STACK_PROTECTOR) if (WITH_STACK_PROTECTOR) list(APPEND SUPPORTED_COMPILER_FLAGS "-fstack-protector") # This is needed as Solaris has a seperate libssp if (SOLARIS) list(APPEND SUPPORTED_LINKER_FLAGS "-fstack-protector") endif() endif() endif (WITH_STACK_PROTECTOR_STRONG) check_c_compiler_flag_ssp("-fstack-clash-protection" WITH_STACK_CLASH_PROTECTION) if (WITH_STACK_CLASH_PROTECTION) list(APPEND SUPPORTED_COMPILER_FLAGS "-fstack-clash-protection") endif() endif() if (PICKY_DEVELOPER) add_c_compiler_flag("-Wno-error=deprecated-declarations" SUPPORTED_COMPILER_FLAGS) add_c_compiler_flag("-Wno-error=tautological-compare" SUPPORTED_COMPILER_FLAGS) endif() # Unset CMAKE_REQUIRED_FLAGS unset(CMAKE_REQUIRED_FLAGS) endif() if (MSVC) add_c_compiler_flag("/D _CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES=1" SUPPORTED_COMPILER_FLAGS) add_c_compiler_flag("/D _CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES_COUNT=1" SUPPORTED_COMPILER_FLAGS) add_c_compiler_flag("/D _CRT_NONSTDC_NO_WARNINGS=1" SUPPORTED_COMPILER_FLAGS) add_c_compiler_flag("/D _CRT_SECURE_NO_WARNINGS=1" SUPPORTED_COMPILER_FLAGS) endif() if (SUPPORTED_COMPILER_FLAGS) set(DEFAULT_C_COMPILE_FLAGS ${SUPPORTED_COMPILER_FLAGS} CACHE INTERNAL "Default C Compiler Flags" FORCE) endif() if (SUPPORTED_LINKER_FLAGS) set(DEFAULT_LINK_FLAGS ${SUPPORTED_LINKER_FLAGS} CACHE INTERNAL "Default C Linker Flags" FORCE) endif() socket_wrapper-1.4.4/src/000755 001750 000144 00000000000 14744201044 015317 5ustar00asnusers000000 000000 socket_wrapper-1.4.4/src/CMakeLists.txt000644 001750 000144 00000005520 14631527256 020074 0ustar00asnusers000000 000000 project(libsocket_wrapper C) add_library(socket_wrapper SHARED socket_wrapper.c) target_include_directories(socket_wrapper PRIVATE ${CMAKE_BINARY_DIR}) target_compile_options(socket_wrapper PRIVATE ${DEFAULT_C_COMPILE_FLAGS} -D_GNU_SOURCE) if (CMAKE_SIZEOF_VOID_P EQUAL 4) target_compile_options(socket_wrapper PRIVATE -D_LARGEFILE64_SOURCE) endif() target_link_libraries(socket_wrapper PRIVATE ${SWRAP_REQUIRED_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT}) set_target_properties(socket_wrapper PROPERTIES VERSION ${LIBRARY_VERSION} SOVERSION ${LIBRARY_SOVERSION}) if (DEFINED DEFAULT_LINK_FLAGS) set_target_properties(socket_wrapper PROPERTIES LINK_FLAGS ${DEFAULT_LINK_FLAGS}) endif() install(TARGETS socket_wrapper RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} ) set(SOCKET_WRAPPER_LOCATION "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_SHARED_LIBRARY_PREFIX}socket_wrapper${CMAKE_SHARED_LIBRARY_SUFFIX}" PARENT_SCOPE) add_library(socket_wrapper_noop SHARED socket_wrapper_noop.c) target_include_directories(socket_wrapper_noop PRIVATE ${socket_wrapper_BINARY_DIR} PUBLIC $ $) target_compile_options(socket_wrapper_noop PRIVATE ${DEFAULT_C_COMPILE_FLAGS} -D_GNU_SOURCE) target_link_libraries(socket_wrapper_noop PRIVATE ${SWRAP_REQUIRED_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT}) set_target_properties(socket_wrapper_noop PROPERTIES VERSION ${NOOP_LIBRARY_VERSION} SOVERSION ${NOOP_LIBRARY_SOVERSION}) if (DEFINED DEFAULT_LINK_FLAGS) set_target_properties(socket_wrapper_noop PROPERTIES LINK_FLAGS ${DEFAULT_LINK_FLAGS}) endif() install(TARGETS socket_wrapper_noop EXPORT socket_wrapper_noop-config RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} ) install(EXPORT socket_wrapper_noop-config DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/socket_wrapper) install( FILES ${CMAKE_CURRENT_SOURCE_DIR}/socket_wrapper.h DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} ) socket_wrapper-1.4.4/src/socket_wrapper_noop.c000644 001750 000144 00000004542 14631527256 021566 0ustar00asnusers000000 000000 /* * BSD 3-Clause License * * Copyright (c) 2005-2008, Jelmer Vernooij * Copyright (c) 2006-2021, Stefan Metzmacher * Copyright (c) 2013-2021, Andreas Schneider * Copyright (c) 2014-2017, Michael Adam * Copyright (c) 2016-2018, Anoop C S * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * 3. Neither the name of the author nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* Socket wrapper noop library. Applications with the need to alter their behaviour when socket wrapper is active, can link to this with -lsocket_wrapper_noop in order to call get the required public functions at link time. During runtime these are overloaded with LD_PRELOAD by the real libsocket_wrapper.so. */ #include "config.h" #include "stdbool.h" #include "socket_wrapper.h" bool socket_wrapper_enabled(void) { return false; } void socket_wrapper_indicate_no_inet_fd(int fd) { (void) fd; /* unused */ return; } socket_wrapper-1.4.4/src/socket_wrapper.c000644 001750 000144 00000610702 14744201025 020520 0ustar00asnusers000000 000000 /* * BSD 3-Clause License * * Copyright (c) 2005-2008, Jelmer Vernooij * Copyright (c) 2006-2021, Stefan Metzmacher * Copyright (c) 2013-2021, Andreas Schneider * Copyright (c) 2014-2017, Michael Adam * Copyright (c) 2016-2018, Anoop C S * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * 3. Neither the name of the author nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* Socket wrapper library. Passes all socket communication over unix domain sockets if the environment variable SOCKET_WRAPPER_DIR is set. */ #include "config.h" /* * Make sure we do not redirect (f)open(at)() or fcntl() to their 64bit * variants */ #undef _FILE_OFFSET_BITS #include #include #include #ifdef HAVE_SYS_SYSCALL_H #include #endif #ifdef HAVE_SYSCALL_H #include #endif #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 #ifdef HAVE_NETINET_TCP_FSM_H #include #endif #include #include #include #include #include #include #include #include #include #ifdef HAVE_GNU_LIB_NAMES_H #include #endif #ifdef HAVE_RPC_RPC_H #include #endif #include #include "socket_wrapper.h" #ifdef __USE_FILE_OFFSET64 #error -D_FILE_OFFSET_BITS=64 should not be set for socket_wrapper! #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_CONSTRUCTOR_ATTRIBUTE #define CONSTRUCTOR_ATTRIBUTE __attribute__ ((constructor)) #else #define CONSTRUCTOR_ATTRIBUTE #endif /* HAVE_CONSTRUCTOR_ATTRIBUTE */ #ifdef HAVE_DESTRUCTOR_ATTRIBUTE #define DESTRUCTOR_ATTRIBUTE __attribute__ ((destructor)) #else #define DESTRUCTOR_ATTRIBUTE #endif #ifndef FALL_THROUGH # ifdef HAVE_FALLTHROUGH_ATTRIBUTE # define FALL_THROUGH __attribute__ ((fallthrough)) # else /* HAVE_FALLTHROUGH_ATTRIBUTE */ # define FALL_THROUGH ((void)0) # endif /* HAVE_FALLTHROUGH_ATTRIBUTE */ #endif /* FALL_THROUGH */ #ifdef HAVE_ADDRESS_SANITIZER_ATTRIBUTE #define DO_NOT_SANITIZE_ADDRESS_ATTRIBUTE __attribute__((no_sanitize_address)) #else #define DO_NOT_SANITIZE_ADDRESS_ATTRIBUTE #endif #ifdef HAVE_GCC_THREAD_LOCAL_STORAGE # define SWRAP_THREAD __thread #else # define SWRAP_THREAD #endif #ifndef MIN #define MIN(a,b) ((a)<(b)?(a):(b)) #endif #ifndef ZERO_STRUCT #define ZERO_STRUCT(x) memset((char *)&(x), 0, sizeof(x)) #endif #ifndef ZERO_STRUCTP #define ZERO_STRUCTP(x) do { \ if ((x) != NULL) \ memset((char *)(x), 0, sizeof(*(x))); \ } while(0) #endif #ifndef SAFE_FREE #define SAFE_FREE(x) do { if ((x) != NULL) {free(x); (x)=NULL;} } while(0) #endif #ifndef discard_const #define discard_const(ptr) ((void *)((uintptr_t)(ptr))) #endif #ifndef discard_const_p #define discard_const_p(type, ptr) ((type *)discard_const(ptr)) #endif #define UNUSED(x) (void)(x) #ifdef IPV6_PKTINFO # ifndef IPV6_RECVPKTINFO # define IPV6_RECVPKTINFO IPV6_PKTINFO # endif /* IPV6_RECVPKTINFO */ #endif /* IPV6_PKTINFO */ /* * On BSD IP_PKTINFO has a different name because during * the time when they implemented it, there was no RFC. * The name for IPv6 is the same as on Linux. */ #ifndef IP_PKTINFO # ifdef IP_RECVDSTADDR # define IP_PKTINFO IP_RECVDSTADDR # endif #endif #define socket_wrapper_init_mutex(m) \ _socket_wrapper_init_mutex(m, #m) /* Add new global locks here please */ # define SWRAP_REINIT_ALL do { \ int ret; \ ret = socket_wrapper_init_mutex(&sockets_mutex); \ if (ret != 0) exit(-1); \ ret = socket_wrapper_init_mutex(&socket_reset_mutex); \ if (ret != 0) exit(-1); \ ret = socket_wrapper_init_mutex(&first_free_mutex); \ if (ret != 0) exit(-1); \ ret = socket_wrapper_init_mutex(&sockets_si_global); \ if (ret != 0) exit(-1); \ ret = socket_wrapper_init_mutex(&autobind_start_mutex); \ if (ret != 0) exit(-1); \ ret = socket_wrapper_init_mutex(&pcap_dump_mutex); \ if (ret != 0) exit(-1); \ ret = socket_wrapper_init_mutex(&mtu_update_mutex); \ if (ret != 0) exit(-1); \ } while(0) # define SWRAP_LOCK_ALL do { \ swrap_mutex_lock(&sockets_mutex); \ swrap_mutex_lock(&socket_reset_mutex); \ swrap_mutex_lock(&first_free_mutex); \ swrap_mutex_lock(&sockets_si_global); \ swrap_mutex_lock(&autobind_start_mutex); \ swrap_mutex_lock(&pcap_dump_mutex); \ swrap_mutex_lock(&mtu_update_mutex); \ } while(0) # define SWRAP_UNLOCK_ALL do { \ swrap_mutex_unlock(&mtu_update_mutex); \ swrap_mutex_unlock(&pcap_dump_mutex); \ swrap_mutex_unlock(&autobind_start_mutex); \ swrap_mutex_unlock(&sockets_si_global); \ swrap_mutex_unlock(&first_free_mutex); \ swrap_mutex_unlock(&socket_reset_mutex); \ swrap_mutex_unlock(&sockets_mutex); \ } while(0) #define SOCKET_INFO_CONTAINER(si) \ (struct socket_info_container *)(si) #define SWRAP_LOCK_SI(si) do { \ struct socket_info_container *sic = SOCKET_INFO_CONTAINER(si); \ if (sic != NULL) { \ swrap_mutex_lock(&sockets_si_global); \ } else { \ abort(); \ } \ } while(0) #define SWRAP_UNLOCK_SI(si) do { \ struct socket_info_container *sic = SOCKET_INFO_CONTAINER(si); \ if (sic != NULL) { \ swrap_mutex_unlock(&sockets_si_global); \ } else { \ abort(); \ } \ } while(0) #if defined(HAVE_GETTIMEOFDAY_TZ) || defined(HAVE_GETTIMEOFDAY_TZ_VOID) #define swrapGetTimeOfDay(tval) gettimeofday(tval,NULL) #else #define swrapGetTimeOfDay(tval) gettimeofday(tval) #endif /* we need to use a very terse format here as IRIX 6.4 silently truncates names to 16 chars, so if we use a longer name then we can't tell which port a packet came from with recvfrom() with this format we have 8 chars left for the directory name */ #define SOCKET_FORMAT "%c%02X%04X" #define SOCKET_TYPE_CHAR_TCP 'T' #define SOCKET_TYPE_CHAR_UDP 'U' #define SOCKET_TYPE_CHAR_TCP_V6 'X' #define SOCKET_TYPE_CHAR_UDP_V6 'Y' /* * Set the packet MTU to 1500 bytes for stream sockets to make it it easier to * format PCAP capture files (as the caller will simply continue from here). */ #define SOCKET_WRAPPER_MTU_DEFAULT 1500 #define SOCKET_WRAPPER_MTU_MIN 512 #define SOCKET_WRAPPER_MTU_MAX 32768 #define SOCKET_MAX_SOCKETS 1024 /* * Maximum number of socket_info structures that can * be used. Can be overriden by the environment variable * SOCKET_WRAPPER_MAX_SOCKETS. */ #define SOCKET_WRAPPER_MAX_SOCKETS_DEFAULT 65535 #define SOCKET_WRAPPER_MAX_SOCKETS_LIMIT 262140 /* This limit is to avoid broadcast sendto() needing to stat too many * files. It may be raised (with a performance cost) to up to 254 * without changing the format above */ #define MAX_WRAPPED_INTERFACES 64 struct swrap_address { socklen_t sa_socklen; union { struct sockaddr s; struct sockaddr_in in; #ifdef HAVE_IPV6 struct sockaddr_in6 in6; #endif struct sockaddr_un un; struct sockaddr_storage ss; } sa; }; static int first_free; struct socket_info { /* * Remember to update swrap_unix_scm_right_magic * on any change. */ int family; int type; int protocol; int bound; int bcast; int is_server; int connected; int defer_connect; int pktinfo; int tcp_nodelay; int listening; int fd_passed; /* The unix path so we can unlink it on close() */ struct sockaddr_un un_addr; struct swrap_address bindname; struct swrap_address myname; struct swrap_address peername; struct { unsigned long pck_snd; unsigned long pck_rcv; } io; }; struct socket_info_meta { unsigned int refcount; int next_free; /* * As long as we don't use shared memory * for the sockets array, we use * sockets_si_global as a single mutex. * * pthread_mutex_t mutex; */ }; struct socket_info_container { struct socket_info info; struct socket_info_meta meta; }; static struct socket_info_container *sockets; static size_t socket_info_max = 0; /* * Allocate the socket array always on the limit value. We want it to be * at least bigger than the default so if we reach the limit we can * still deal with duplicate fds pointing to the same socket_info. */ static size_t socket_fds_max = SOCKET_WRAPPER_MAX_SOCKETS_LIMIT; /* Hash table to map fds to corresponding socket_info index */ static int *socket_fds_idx; /* Mutex for syncronizing port selection during swrap_auto_bind() */ static pthread_mutex_t autobind_start_mutex = PTHREAD_MUTEX_INITIALIZER; /* Mutex to guard the initialization of array of socket_info structures */ static pthread_mutex_t sockets_mutex = PTHREAD_MUTEX_INITIALIZER; /* Mutex to guard the socket reset in swrap_remove_wrapper() */ static pthread_mutex_t socket_reset_mutex = PTHREAD_MUTEX_INITIALIZER; /* Mutex to synchronize access to first free index in socket_info array */ static pthread_mutex_t first_free_mutex = PTHREAD_MUTEX_INITIALIZER; /* * Mutex to synchronize access to to socket_info structures * We use a single global mutex in order to avoid leaking * ~ 38M copy on write memory per fork. * max_sockets=65535 * sizeof(struct socket_info_container)=592 = 38796720 */ static pthread_mutex_t sockets_si_global = PTHREAD_MUTEX_INITIALIZER; /* Mutex to synchronize access to packet capture dump file */ static pthread_mutex_t pcap_dump_mutex = PTHREAD_MUTEX_INITIALIZER; /* Mutex for synchronizing mtu value fetch*/ static pthread_mutex_t mtu_update_mutex = PTHREAD_MUTEX_INITIALIZER; /* Function prototypes */ #if ! defined(HAVE_CONSTRUCTOR_ATTRIBUTE) && defined(HAVE_PRAGMA_INIT) /* xlC and other oldschool compilers support (only) this */ #pragma init (swrap_constructor) #endif void swrap_constructor(void) CONSTRUCTOR_ATTRIBUTE; #if ! defined(HAVE_DESTRUCTOR_ATTRIBUTE) && defined(HAVE_PRAGMA_FINI) #pragma fini (swrap_destructor) #endif void swrap_destructor(void) DESTRUCTOR_ATTRIBUTE; #ifndef HAVE_GETPROGNAME static const char *getprogname(void) { #if defined(HAVE_PROGRAM_INVOCATION_SHORT_NAME) return program_invocation_short_name; #elif defined(HAVE_GETEXECNAME) return getexecname(); #else return NULL; #endif /* HAVE_PROGRAM_INVOCATION_SHORT_NAME */ } #endif /* HAVE_GETPROGNAME */ static void swrap_log(enum swrap_dbglvl_e dbglvl, const char *func, const char *format, ...) PRINTF_ATTRIBUTE(3, 4); # define SWRAP_LOG(dbglvl, ...) swrap_log((dbglvl), __func__, __VA_ARGS__) static void swrap_log(enum swrap_dbglvl_e dbglvl, const char *func, const char *format, ...) { char buffer[1024]; va_list va; const char *d; unsigned int lvl = 0; const char *prefix = "SWRAP"; const char *progname = getprogname(); d = getenv("SOCKET_WRAPPER_DEBUGLEVEL"); if (d != NULL) { lvl = atoi(d); } if (lvl < dbglvl) { return; } va_start(va, format); vsnprintf(buffer, sizeof(buffer), format, va); va_end(va); switch (dbglvl) { case SWRAP_LOG_ERROR: prefix = "SWRAP_ERROR"; break; case SWRAP_LOG_WARN: prefix = "SWRAP_WARN"; break; case SWRAP_LOG_DEBUG: prefix = "SWRAP_DEBUG"; break; case SWRAP_LOG_TRACE: prefix = "SWRAP_TRACE"; break; } if (progname == NULL) { progname = ""; } fprintf(stderr, "%s[%s (%u)] - %s: %s\n", prefix, progname, (unsigned int)getpid(), func, buffer); } /********************************************************* * SWRAP LOADING LIBC FUNCTIONS *********************************************************/ #include #ifdef HAVE_ACCEPT4 typedef int (*__libc_accept4)(int sockfd, struct sockaddr *addr, socklen_t *addrlen, int flags); #else typedef int (*__libc_accept)(int sockfd, struct sockaddr *addr, socklen_t *addrlen); #endif typedef int (*__libc_bind)(int sockfd, const struct sockaddr *addr, socklen_t addrlen); typedef int (*__libc_close)(int fd); #ifdef HAVE___CLOSE_NOCANCEL typedef int (*__libc___close_nocancel)(int fd); #endif typedef int (*__libc_connect)(int sockfd, const struct sockaddr *addr, socklen_t addrlen); typedef int (*__libc_dup)(int fd); typedef int (*__libc_dup2)(int oldfd, int newfd); typedef int (*__libc_fcntl)(int fd, int cmd, ...); #ifdef HAVE_FCNTL64 typedef int (*__libc_fcntl64)(int fd, int cmd, ...); #endif typedef FILE *(*__libc_fopen)(const char *name, const char *mode); #ifdef HAVE_FOPEN64 typedef FILE *(*__libc_fopen64)(const char *name, const char *mode); #endif #ifdef HAVE_EVENTFD typedef int (*__libc_eventfd)(int count, int flags); #endif typedef int (*__libc_getpeername)(int sockfd, struct sockaddr *addr, socklen_t *addrlen); typedef int (*__libc_getsockname)(int sockfd, struct sockaddr *addr, socklen_t *addrlen); typedef int (*__libc_getsockopt)(int sockfd, int level, int optname, void *optval, socklen_t *optlen); typedef int (*__libc_ioctl)(int d, unsigned long int request, ...); typedef int (*__libc_listen)(int sockfd, int backlog); typedef int (*__libc_open)(const char *pathname, int flags, ...); #ifdef HAVE_OPEN64 typedef int (*__libc_open64)(const char *pathname, int flags, ...); #endif /* HAVE_OPEN64 */ #ifdef HAVE_OPENAT64 typedef int (*__libc_openat64)(int dirfd, const char *pathname, int flags, ...); #endif /* HAVE_OPENAT64 */ typedef int (*__libc_openat)(int dirfd, const char *path, int flags, ...); typedef int (*__libc_pipe)(int pipefd[2]); typedef int (*__libc_read)(int fd, void *buf, size_t count); typedef ssize_t (*__libc_readv)(int fd, const struct iovec *iov, int iovcnt); typedef int (*__libc_recv)(int sockfd, void *buf, size_t len, int flags); typedef int (*__libc_recvfrom)(int sockfd, void *buf, size_t len, int flags, struct sockaddr *src_addr, socklen_t *addrlen); typedef int (*__libc_recvmsg)(int sockfd, const struct msghdr *msg, int flags); #ifdef HAVE_RECVMMSG #if defined(HAVE_RECVMMSG_SSIZE_T_CONST_TIMEOUT) /* FreeBSD */ typedef ssize_t (*__libc_recvmmsg)(int sockfd, struct mmsghdr *msgvec, size_t vlen, int flags, const struct timespec *timeout); #elif defined(HAVE_RECVMMSG_CONST_TIMEOUT) /* Linux legacy glibc < 2.21 */ typedef int (*__libc_recvmmsg)(int sockfd, struct mmsghdr *msgvec, unsigned int vlen, int flags, const struct timespec *timeout); #else /* Linux glibc >= 2.21 */ typedef int (*__libc_recvmmsg)(int sockfd, struct mmsghdr *msgvec, unsigned int vlen, int flags, struct timespec *timeout); #endif #endif /* HAVE_RECVMMSG */ typedef int (*__libc_send)(int sockfd, const void *buf, size_t len, int flags); typedef int (*__libc_sendmsg)(int sockfd, const struct msghdr *msg, int flags); #ifdef HAVE_SENDMMSG #if defined(HAVE_SENDMMSG_SSIZE_T) /* FreeBSD */ typedef ssize_t (*__libc_sendmmsg)(int sockfd, struct mmsghdr *msgvec, size_t vlen, int flags); #else /* Linux */ typedef int (*__libc_sendmmsg)(int sockfd, struct mmsghdr *msgvec, unsigned int vlen, int flags); #endif #endif /* HAVE_SENDMMSG */ typedef int (*__libc_sendto)(int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *dst_addr, socklen_t addrlen); typedef int (*__libc_setsockopt)(int sockfd, int level, int optname, const void *optval, socklen_t optlen); #ifdef HAVE_SIGNALFD typedef int (*__libc_signalfd)(int fd, const sigset_t *mask, int flags); #endif typedef int (*__libc_socket)(int domain, int type, int protocol); typedef int (*__libc_socketpair)(int domain, int type, int protocol, int sv[2]); #ifdef HAVE_TIMERFD_CREATE typedef int (*__libc_timerfd_create)(int clockid, int flags); #endif typedef ssize_t (*__libc_write)(int fd, const void *buf, size_t count); typedef ssize_t (*__libc_writev)(int fd, const struct iovec *iov, int iovcnt); #ifdef HAVE_SYSCALL typedef long int (*__libc_syscall)(long int sysno, ...); #endif #define SWRAP_SYMBOL_ENTRY(i) \ union { \ __libc_##i f; \ void *obj; \ } _libc_##i struct swrap_libc_symbols { #ifdef HAVE_ACCEPT4 SWRAP_SYMBOL_ENTRY(accept4); #else SWRAP_SYMBOL_ENTRY(accept); #endif SWRAP_SYMBOL_ENTRY(bind); SWRAP_SYMBOL_ENTRY(close); #ifdef HAVE___CLOSE_NOCANCEL SWRAP_SYMBOL_ENTRY(__close_nocancel); #endif SWRAP_SYMBOL_ENTRY(connect); SWRAP_SYMBOL_ENTRY(dup); SWRAP_SYMBOL_ENTRY(dup2); SWRAP_SYMBOL_ENTRY(fcntl); #ifdef HAVE_FCNTL64 SWRAP_SYMBOL_ENTRY(fcntl64); #endif SWRAP_SYMBOL_ENTRY(fopen); #ifdef HAVE_FOPEN64 SWRAP_SYMBOL_ENTRY(fopen64); #endif #ifdef HAVE_EVENTFD SWRAP_SYMBOL_ENTRY(eventfd); #endif SWRAP_SYMBOL_ENTRY(getpeername); SWRAP_SYMBOL_ENTRY(getsockname); SWRAP_SYMBOL_ENTRY(getsockopt); SWRAP_SYMBOL_ENTRY(ioctl); SWRAP_SYMBOL_ENTRY(listen); SWRAP_SYMBOL_ENTRY(open); #ifdef HAVE_OPEN64 SWRAP_SYMBOL_ENTRY(open64); #endif #ifdef HAVE_OPENAT64 SWRAP_SYMBOL_ENTRY(openat64); #endif SWRAP_SYMBOL_ENTRY(openat); SWRAP_SYMBOL_ENTRY(pipe); SWRAP_SYMBOL_ENTRY(read); SWRAP_SYMBOL_ENTRY(readv); SWRAP_SYMBOL_ENTRY(recv); SWRAP_SYMBOL_ENTRY(recvfrom); SWRAP_SYMBOL_ENTRY(recvmsg); #ifdef HAVE_RECVMMSG SWRAP_SYMBOL_ENTRY(recvmmsg); #endif SWRAP_SYMBOL_ENTRY(send); SWRAP_SYMBOL_ENTRY(sendmsg); #ifdef HAVE_SENDMMSG SWRAP_SYMBOL_ENTRY(sendmmsg); #endif SWRAP_SYMBOL_ENTRY(sendto); SWRAP_SYMBOL_ENTRY(setsockopt); #ifdef HAVE_SIGNALFD SWRAP_SYMBOL_ENTRY(signalfd); #endif SWRAP_SYMBOL_ENTRY(socket); SWRAP_SYMBOL_ENTRY(socketpair); #ifdef HAVE_TIMERFD_CREATE SWRAP_SYMBOL_ENTRY(timerfd_create); #endif SWRAP_SYMBOL_ENTRY(write); SWRAP_SYMBOL_ENTRY(writev); #ifdef HAVE_SYSCALL SWRAP_SYMBOL_ENTRY(syscall); #endif }; #undef SWRAP_SYMBOL_ENTRY #define SWRAP_SYMBOL_ENTRY(i) \ union { \ __rtld_default_##i f; \ void *obj; \ } _rtld_default_##i #ifdef HAVE_SYSCALL typedef bool (*__rtld_default_uid_wrapper_syscall_valid)(long int sysno); typedef long int (*__rtld_default_uid_wrapper_syscall_va)(long int sysno, va_list va); #endif struct swrap_rtld_default_symbols { #ifdef HAVE_SYSCALL SWRAP_SYMBOL_ENTRY(uid_wrapper_syscall_valid); SWRAP_SYMBOL_ENTRY(uid_wrapper_syscall_va); #else uint8_t dummy; #endif }; #undef SWRAP_SYMBOL_ENTRY struct swrap { struct { void *handle; void *socket_handle; struct swrap_libc_symbols symbols; } libc; struct { struct swrap_rtld_default_symbols symbols; } rtld_default; }; static struct swrap swrap; /* prototypes */ static char *socket_wrapper_dir(void); #define LIBC_NAME "libc.so" enum swrap_lib { SWRAP_LIBC, SWRAP_LIBSOCKET, }; static const char *swrap_str_lib(enum swrap_lib lib) { switch (lib) { case SWRAP_LIBC: return "libc"; case SWRAP_LIBSOCKET: return "libsocket"; } /* Compiler would warn us about unhandled enum value if we get here */ return "unknown"; } static void *swrap_load_lib_handle(enum swrap_lib lib) { int flags = RTLD_LAZY; void *handle = NULL; int i; #ifdef RTLD_DEEPBIND const char *env_preload = getenv("LD_PRELOAD"); const char *env_deepbind = getenv("SOCKET_WRAPPER_DISABLE_DEEPBIND"); bool enable_deepbind = true; /* Don't do a deepbind if we run with libasan */ if (env_preload != NULL && strlen(env_preload) < 1024) { const char *p = strstr(env_preload, "libasan.so"); if (p != NULL) { enable_deepbind = false; } } if (env_deepbind != NULL && strlen(env_deepbind) >= 1) { enable_deepbind = false; } if (enable_deepbind) { flags |= RTLD_DEEPBIND; } #endif switch (lib) { case SWRAP_LIBSOCKET: #ifdef HAVE_LIBSOCKET handle = swrap.libc.socket_handle; if (handle == NULL) { for (i = 10; i >= 0; i--) { char soname[256] = {0}; snprintf(soname, sizeof(soname), "libsocket.so.%d", i); handle = dlopen(soname, flags); if (handle != NULL) { break; } } swrap.libc.socket_handle = handle; } break; #endif case SWRAP_LIBC: handle = swrap.libc.handle; #ifdef LIBC_SO if (handle == NULL) { handle = dlopen(LIBC_SO, flags); swrap.libc.handle = handle; } #endif if (handle == NULL) { for (i = 10; i >= 0; i--) { char soname[256] = {0}; snprintf(soname, sizeof(soname), "libc.so.%d", i); handle = dlopen(soname, flags); if (handle != NULL) { break; } } swrap.libc.handle = handle; } break; } if (handle == NULL) { #ifdef RTLD_NEXT handle = swrap.libc.handle = swrap.libc.socket_handle = RTLD_NEXT; #else SWRAP_LOG(SWRAP_LOG_ERROR, "Failed to dlopen library: %s", dlerror()); exit(-1); #endif } return handle; } static void *_swrap_bind_symbol(enum swrap_lib lib, const char *fn_name) { void *handle; void *func; handle = swrap_load_lib_handle(lib); func = dlsym(handle, fn_name); if (func == NULL) { SWRAP_LOG(SWRAP_LOG_ERROR, "Failed to find %s: %s", fn_name, dlerror()); exit(-1); } SWRAP_LOG(SWRAP_LOG_TRACE, "Loaded %s from %s", fn_name, swrap_str_lib(lib)); return func; } #define swrap_mutex_lock(m) _swrap_mutex_lock(m, #m, __func__, __LINE__) static void _swrap_mutex_lock(pthread_mutex_t *mutex, const char *name, const char *caller, unsigned line) { int ret; ret = pthread_mutex_lock(mutex); if (ret != 0) { SWRAP_LOG(SWRAP_LOG_ERROR, "PID(%d):PPID(%d): %s(%u): Couldn't lock pthread mutex(%s) - %s", getpid(), getppid(), caller, line, name, strerror(ret)); abort(); } } #define swrap_mutex_unlock(m) _swrap_mutex_unlock(m, #m, __func__, __LINE__) static void _swrap_mutex_unlock(pthread_mutex_t *mutex, const char *name, const char *caller, unsigned line) { int ret; ret = pthread_mutex_unlock(mutex); if (ret != 0) { SWRAP_LOG(SWRAP_LOG_ERROR, "PID(%d):PPID(%d): %s(%u): Couldn't unlock pthread mutex(%s) - %s", getpid(), getppid(), caller, line, name, strerror(ret)); abort(); } } /* * These macros have a thread race condition on purpose! * * This is an optimization to avoid locking each time we check if the symbol is * bound. */ #define _swrap_bind_symbol_generic(lib, sym_name) do { \ swrap.libc.symbols._libc_##sym_name.obj = \ _swrap_bind_symbol(lib, #sym_name); \ } while(0); #define swrap_bind_symbol_libc(sym_name) \ _swrap_bind_symbol_generic(SWRAP_LIBC, sym_name) #define swrap_bind_symbol_libsocket(sym_name) \ _swrap_bind_symbol_generic(SWRAP_LIBSOCKET, sym_name) #define swrap_bind_symbol_rtld_default_optional(sym_name) do { \ swrap.rtld_default.symbols._rtld_default_##sym_name.obj = \ dlsym(RTLD_DEFAULT, #sym_name); \ } while(0); static void swrap_bind_symbol_all(void); /**************************************************************************** * IMPORTANT **************************************************************************** * * Functions especially from libc need to be loaded individually, you can't * load all at once or gdb will segfault at startup. The same applies to * valgrind and has probably something todo with with the linker. So we need * load each function at the point it is called the first time. * ****************************************************************************/ #ifdef HAVE_ACCEPT4 static int libc_accept4(int sockfd, struct sockaddr *addr, socklen_t *addrlen, int flags) { swrap_bind_symbol_all(); return swrap.libc.symbols._libc_accept4.f(sockfd, addr, addrlen, flags); } #else /* HAVE_ACCEPT4 */ static int libc_accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen) { swrap_bind_symbol_all(); return swrap.libc.symbols._libc_accept.f(sockfd, addr, addrlen); } #endif /* HAVE_ACCEPT4 */ static int libc_bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen) { swrap_bind_symbol_all(); return swrap.libc.symbols._libc_bind.f(sockfd, addr, addrlen); } static int libc_close(int fd) { swrap_bind_symbol_all(); return swrap.libc.symbols._libc_close.f(fd); } #ifdef HAVE___CLOSE_NOCANCEL static int libc___close_nocancel(int fd) { swrap_bind_symbol_all(); return swrap.libc.symbols._libc___close_nocancel.f(fd); } #endif /* HAVE___CLOSE_NOCANCEL */ static int libc_connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen) { swrap_bind_symbol_all(); return swrap.libc.symbols._libc_connect.f(sockfd, addr, addrlen); } static int libc_dup(int fd) { swrap_bind_symbol_all(); return swrap.libc.symbols._libc_dup.f(fd); } static int libc_dup2(int oldfd, int newfd) { swrap_bind_symbol_all(); return swrap.libc.symbols._libc_dup2.f(oldfd, newfd); } #ifdef HAVE_EVENTFD static int libc_eventfd(int count, int flags) { swrap_bind_symbol_all(); return swrap.libc.symbols._libc_eventfd.f(count, flags); } #endif DO_NOT_SANITIZE_ADDRESS_ATTRIBUTE static int libc_vfcntl(int fd, int cmd, va_list ap) { void *arg; int rc; swrap_bind_symbol_all(); arg = va_arg(ap, void *); rc = swrap.libc.symbols._libc_fcntl.f(fd, cmd, arg); return rc; } #ifdef HAVE_FCNTL64 DO_NOT_SANITIZE_ADDRESS_ATTRIBUTE static int libc_vfcntl64(int fd, int cmd, va_list ap) { void *arg; int rc; swrap_bind_symbol_all(); arg = va_arg(ap, void *); rc = swrap.libc.symbols._libc_fcntl64.f(fd, cmd, arg); return rc; } #endif static int libc_getpeername(int sockfd, struct sockaddr *addr, socklen_t *addrlen) { swrap_bind_symbol_all(); return swrap.libc.symbols._libc_getpeername.f(sockfd, addr, addrlen); } static int libc_getsockname(int sockfd, struct sockaddr *addr, socklen_t *addrlen) { swrap_bind_symbol_all(); return swrap.libc.symbols._libc_getsockname.f(sockfd, addr, addrlen); } static int libc_getsockopt(int sockfd, int level, int optname, void *optval, socklen_t *optlen) { swrap_bind_symbol_all(); return swrap.libc.symbols._libc_getsockopt.f(sockfd, level, optname, optval, optlen); } DO_NOT_SANITIZE_ADDRESS_ATTRIBUTE static int libc_vioctl(int d, unsigned long int request, va_list ap) { void *arg; int rc; swrap_bind_symbol_all(); arg = va_arg(ap, void *); rc = swrap.libc.symbols._libc_ioctl.f(d, request, arg); return rc; } static int libc_listen(int sockfd, int backlog) { swrap_bind_symbol_all(); return swrap.libc.symbols._libc_listen.f(sockfd, backlog); } static FILE *libc_fopen(const char *name, const char *mode) { swrap_bind_symbol_all(); return swrap.libc.symbols._libc_fopen.f(name, mode); } #ifdef HAVE_FOPEN64 static FILE *libc_fopen64(const char *name, const char *mode) { swrap_bind_symbol_all(); return swrap.libc.symbols._libc_fopen64.f(name, mode); } #endif /* HAVE_FOPEN64 */ static void swrap_inject_o_largefile(int *flags) { (void)*flags; /* maybe unused */ #if SIZE_MAX == 0xffffffffUL && defined(O_LARGEFILE) #ifdef O_PATH if (((*flags) & O_PATH) == 0) #endif { *flags |= O_LARGEFILE; } #endif } static int libc_vopen(const char *pathname, int flags, va_list ap) { int mode = 0; int fd; swrap_bind_symbol_all(); swrap_inject_o_largefile(&flags); if (flags & O_CREAT) { mode = va_arg(ap, int); } fd = swrap.libc.symbols._libc_open.f(pathname, flags, (mode_t)mode); return fd; } static int libc_open(const char *pathname, int flags, ...) { va_list ap; int fd; va_start(ap, flags); fd = libc_vopen(pathname, flags, ap); va_end(ap); return fd; } #ifdef HAVE_OPEN64 static int libc_vopen64(const char *pathname, int flags, va_list ap) { int mode = 0; int fd; swrap_bind_symbol_all(); swrap_inject_o_largefile(&flags); if (flags & O_CREAT) { mode = va_arg(ap, int); } fd = swrap.libc.symbols._libc_open64.f(pathname, flags, (mode_t)mode); return fd; } #endif /* HAVE_OPEN64 */ #ifdef HAVE_OPENAT64 static int libc_vopenat64(int dirfd, const char *pathname, int flags, va_list ap) { int mode = 0; int fd; swrap_bind_symbol_all(); swrap_inject_o_largefile(&flags); if (flags & O_CREAT) { mode = va_arg(ap, int); } fd = swrap.libc.symbols._libc_openat64.f(dirfd, pathname, flags, (mode_t)mode); return fd; } #endif /* HAVE_OPENAT64 */ static int libc_vopenat(int dirfd, const char *path, int flags, va_list ap) { int mode = 0; int fd; swrap_bind_symbol_all(); swrap_inject_o_largefile(&flags); if (flags & O_CREAT) { mode = va_arg(ap, int); } fd = swrap.libc.symbols._libc_openat.f(dirfd, path, flags, (mode_t)mode); return fd; } #if 0 static int libc_openat(int dirfd, const char *path, int flags, ...) { va_list ap; int fd; va_start(ap, flags); fd = libc_vopenat(dirfd, path, flags, ap); va_end(ap); return fd; } #endif static int libc_pipe(int pipefd[2]) { swrap_bind_symbol_all(); return swrap.libc.symbols._libc_pipe.f(pipefd); } static int libc_read(int fd, void *buf, size_t count) { swrap_bind_symbol_all(); return swrap.libc.symbols._libc_read.f(fd, buf, count); } static ssize_t libc_readv(int fd, const struct iovec *iov, int iovcnt) { swrap_bind_symbol_all(); return swrap.libc.symbols._libc_readv.f(fd, iov, iovcnt); } static int libc_recv(int sockfd, void *buf, size_t len, int flags) { swrap_bind_symbol_all(); return swrap.libc.symbols._libc_recv.f(sockfd, buf, len, flags); } static int libc_recvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr *src_addr, socklen_t *addrlen) { swrap_bind_symbol_all(); return swrap.libc.symbols._libc_recvfrom.f(sockfd, buf, len, flags, src_addr, addrlen); } static int libc_recvmsg(int sockfd, struct msghdr *msg, int flags) { swrap_bind_symbol_all(); return swrap.libc.symbols._libc_recvmsg.f(sockfd, msg, flags); } #ifdef HAVE_RECVMMSG #if defined(HAVE_RECVMMSG_SSIZE_T_CONST_TIMEOUT) /* FreeBSD */ static ssize_t libc_recvmmsg(int sockfd, struct mmsghdr *msgvec, size_t vlen, int flags, const struct timespec *timeout) #elif defined(HAVE_RECVMMSG_CONST_TIMEOUT) /* Linux legacy glibc < 2.21 */ static int libc_recvmmsg(int sockfd, struct mmsghdr *msgvec, unsigned int vlen, int flags, const struct timespec *timeout) #else /* Linux glibc >= 2.21 */ static int libc_recvmmsg(int sockfd, struct mmsghdr *msgvec, unsigned int vlen, int flags, struct timespec *timeout) #endif { swrap_bind_symbol_all(); return swrap.libc.symbols._libc_recvmmsg.f(sockfd, msgvec, vlen, flags, timeout); } #endif static int libc_send(int sockfd, const void *buf, size_t len, int flags) { swrap_bind_symbol_all(); return swrap.libc.symbols._libc_send.f(sockfd, buf, len, flags); } static int libc_sendmsg(int sockfd, const struct msghdr *msg, int flags) { swrap_bind_symbol_all(); return swrap.libc.symbols._libc_sendmsg.f(sockfd, msg, flags); } #ifdef HAVE_SENDMMSG #if defined(HAVE_SENDMMSG_SSIZE_T) /* FreeBSD */ static ssize_t libc_sendmmsg(int sockfd, struct mmsghdr *msgvec, size_t vlen, int flags) #else /* Linux */ static int libc_sendmmsg(int sockfd, struct mmsghdr *msgvec, unsigned int vlen, int flags) #endif { swrap_bind_symbol_all(); return swrap.libc.symbols._libc_sendmmsg.f(sockfd, msgvec, vlen, flags); } #endif static int libc_sendto(int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *dst_addr, socklen_t addrlen) { swrap_bind_symbol_all(); return swrap.libc.symbols._libc_sendto.f(sockfd, buf, len, flags, dst_addr, addrlen); } static int libc_setsockopt(int sockfd, int level, int optname, const void *optval, socklen_t optlen) { swrap_bind_symbol_all(); return swrap.libc.symbols._libc_setsockopt.f(sockfd, level, optname, optval, optlen); } #ifdef HAVE_SIGNALFD static int libc_signalfd(int fd, const sigset_t *mask, int flags) { swrap_bind_symbol_all(); return swrap.libc.symbols._libc_signalfd.f(fd, mask, flags); } #endif static int libc_socket(int domain, int type, int protocol) { swrap_bind_symbol_all(); return swrap.libc.symbols._libc_socket.f(domain, type, protocol); } static int libc_socketpair(int domain, int type, int protocol, int sv[2]) { swrap_bind_symbol_all(); return swrap.libc.symbols._libc_socketpair.f(domain, type, protocol, sv); } #ifdef HAVE_TIMERFD_CREATE static int libc_timerfd_create(int clockid, int flags) { swrap_bind_symbol_all(); return swrap.libc.symbols._libc_timerfd_create.f(clockid, flags); } #endif static ssize_t libc_write(int fd, const void *buf, size_t count) { swrap_bind_symbol_all(); return swrap.libc.symbols._libc_write.f(fd, buf, count); } static ssize_t libc_writev(int fd, const struct iovec *iov, int iovcnt) { swrap_bind_symbol_all(); return swrap.libc.symbols._libc_writev.f(fd, iov, iovcnt); } /* JEMALLOC: This tells socket_wrapper if it should handle syscall() */ static bool swrap_handle_syscall; #ifdef HAVE_SYSCALL DO_NOT_SANITIZE_ADDRESS_ATTRIBUTE static long int libc_vsyscall(long int sysno, va_list va) { long int args[8]; long int rc; int i; /* * JEMALLOC: * * This is a workaround to prevent a deadlock in jemalloc calling * malloc_init() twice. The first allocation call will trigger a * malloc_init() of jemalloc. The functions calls syscall(SYS_open, ...) * so it goes to socket or uid wrapper. In this code path we need to * avoid any allocation calls. This will prevent the deadlock. * * We also need to avoid dlopen() as that would trigger the recursion * into malloc_init(), so we use dlsym(RTLD_NEXT), until we reached * swrap_constructor() or any real socket call at that time * swrap_bind_symbol_all() will replace the function pointer again after * dlopen of libc. */ if (swrap_handle_syscall) { swrap_bind_symbol_all(); } else if (swrap.libc.symbols._libc_syscall.obj == NULL) { swrap.libc.symbols._libc_syscall.obj = dlsym(RTLD_NEXT, "syscall"); } for (i = 0; i < 8; i++) { args[i] = va_arg(va, long int); } rc = swrap.libc.symbols._libc_syscall.f(sysno, args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7]); return rc; } static bool swrap_uwrap_syscall_valid(long int sysno) { swrap_bind_symbol_all(); if (swrap.rtld_default.symbols._rtld_default_uid_wrapper_syscall_valid.f == NULL) { return false; } return swrap.rtld_default.symbols._rtld_default_uid_wrapper_syscall_valid.f( sysno); } DO_NOT_SANITIZE_ADDRESS_ATTRIBUTE static long int swrap_uwrap_syscall_va(long int sysno, va_list va) { swrap_bind_symbol_all(); if (swrap.rtld_default.symbols._rtld_default_uid_wrapper_syscall_va.f == NULL) { /* * Fallback to libc, if uid_wrapper_syscall_va is not * available. */ return libc_vsyscall(sysno, va); } return swrap.rtld_default.symbols._rtld_default_uid_wrapper_syscall_va.f( sysno, va); } #endif /* HAVE_SYSCALL */ /* DO NOT call this function during library initialization! */ static void __swrap_bind_symbol_all_once(void) { #ifdef HAVE_ACCEPT4 swrap_bind_symbol_libsocket(accept4); #else swrap_bind_symbol_libsocket(accept); #endif swrap_bind_symbol_libsocket(bind); swrap_bind_symbol_libc(close); #ifdef HAVE___CLOSE_NOCANCEL swrap_bind_symbol_libc(__close_nocancel); #endif swrap_bind_symbol_libsocket(connect); swrap_bind_symbol_libc(dup); swrap_bind_symbol_libc(dup2); swrap_bind_symbol_libc(fcntl); #ifdef HAVE_FCNTL64 swrap_bind_symbol_libc(fcntl64); #endif swrap_bind_symbol_libc(fopen); #ifdef HAVE_FOPEN64 swrap_bind_symbol_libc(fopen64); #endif #ifdef HAVE_EVENTFD swrap_bind_symbol_libc(eventfd); #endif swrap_bind_symbol_libsocket(getpeername); swrap_bind_symbol_libsocket(getsockname); swrap_bind_symbol_libsocket(getsockopt); swrap_bind_symbol_libc(ioctl); swrap_bind_symbol_libsocket(listen); swrap_bind_symbol_libc(open); #ifdef HAVE_OPEN64 swrap_bind_symbol_libc(open64); #endif #ifdef HAVE_OPENAT64 swrap_bind_symbol_libc(openat64); #endif swrap_bind_symbol_libc(openat); swrap_bind_symbol_libsocket(pipe); swrap_bind_symbol_libc(read); swrap_bind_symbol_libsocket(readv); swrap_bind_symbol_libsocket(recv); swrap_bind_symbol_libsocket(recvfrom); swrap_bind_symbol_libsocket(recvmsg); #ifdef HAVE_RECVMMSG swrap_bind_symbol_libsocket(recvmmsg); #endif swrap_bind_symbol_libsocket(send); swrap_bind_symbol_libsocket(sendmsg); #ifdef HAVE_SENDMMSG swrap_bind_symbol_libsocket(sendmmsg); #endif swrap_bind_symbol_libsocket(sendto); swrap_bind_symbol_libsocket(setsockopt); #ifdef HAVE_SIGNALFD swrap_bind_symbol_libsocket(signalfd); #endif swrap_bind_symbol_libsocket(socket); swrap_bind_symbol_libsocket(socketpair); #ifdef HAVE_TIMERFD_CREATE swrap_bind_symbol_libc(timerfd_create); #endif swrap_bind_symbol_libc(write); swrap_bind_symbol_libsocket(writev); #ifdef HAVE_SYSCALL swrap_bind_symbol_libc(syscall); swrap_bind_symbol_rtld_default_optional(uid_wrapper_syscall_valid); swrap_bind_symbol_rtld_default_optional(uid_wrapper_syscall_va); #endif swrap_handle_syscall = true; } static void swrap_bind_symbol_all(void) { static pthread_once_t all_symbol_binding_once = PTHREAD_ONCE_INIT; pthread_once(&all_symbol_binding_once, __swrap_bind_symbol_all_once); } /********************************************************* * SWRAP HELPER FUNCTIONS *********************************************************/ /* * We return 127.0.0.0 (default) or 10.53.57.0. * * This can be controlled by: * SOCKET_WRAPPER_IPV4_NETWORK=127.0.0.0 (default) * or * SOCKET_WRAPPER_IPV4_NETWORK=10.53.57.0 */ static in_addr_t swrap_ipv4_net(void) { static int initialized; static in_addr_t hv; const char *net_str = NULL; struct in_addr nv; int ret; if (initialized) { return hv; } initialized = 1; net_str = getenv("SOCKET_WRAPPER_IPV4_NETWORK"); if (net_str == NULL) { net_str = "127.0.0.0"; } ret = inet_pton(AF_INET, net_str, &nv); if (ret <= 0) { SWRAP_LOG(SWRAP_LOG_ERROR, "INVALID IPv4 Network [%s]", net_str); abort(); } hv = ntohl(nv.s_addr); switch (hv) { case 0x7f000000: /* 127.0.0.0 */ break; case 0x0a353900: /* 10.53.57.0 */ break; default: SWRAP_LOG(SWRAP_LOG_ERROR, "INVALID IPv4 Network [%s][0x%x] should be " "127.0.0.0 or 10.53.57.0", net_str, (unsigned)hv); abort(); } return hv; } /* * This returns 127.255.255.255 or 10.255.255.255 */ static in_addr_t swrap_ipv4_bcast(void) { in_addr_t hv; hv = swrap_ipv4_net(); hv |= IN_CLASSA_HOST; return hv; } /* * This returns 127.0.0.${iface} or 10.53.57.${iface} */ static in_addr_t swrap_ipv4_iface(unsigned int iface) { in_addr_t hv; if (iface == 0 || iface > MAX_WRAPPED_INTERFACES) { SWRAP_LOG(SWRAP_LOG_ERROR, "swrap_ipv4_iface(%u) invalid!", iface); abort(); return -1; } hv = swrap_ipv4_net(); hv |= iface; return hv; } #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; } struct swrap_sockaddr_buf { char str[128]; }; static const char *swrap_sockaddr_string(struct swrap_sockaddr_buf *buf, const struct sockaddr *saddr) { unsigned int port = 0; char addr[64] = {0,}; switch (saddr->sa_family) { case AF_INET: { const struct sockaddr_in *in = (const struct sockaddr_in *)(const void *)saddr; port = ntohs(in->sin_port); inet_ntop(saddr->sa_family, &in->sin_addr, addr, sizeof(addr)); break; } #ifdef HAVE_IPV6 case AF_INET6: { const struct sockaddr_in6 *in6 = (const struct sockaddr_in6 *)(const void *)saddr; port = ntohs(in6->sin6_port); inet_ntop(saddr->sa_family, &in6->sin6_addr, addr, sizeof(addr)); break; } #endif default: snprintf(addr, sizeof(addr), "", saddr->sa_family); break; } snprintf(buf->str, sizeof(buf->str), "addr[%s]/port[%u]", addr, port); return buf->str; } static struct socket_info *swrap_get_socket_info(int si_index) { return (struct socket_info *)(&(sockets[si_index].info)); } static int swrap_get_refcount(struct socket_info *si) { struct socket_info_container *sic = SOCKET_INFO_CONTAINER(si); return sic->meta.refcount; } static void swrap_inc_refcount(struct socket_info *si) { struct socket_info_container *sic = SOCKET_INFO_CONTAINER(si); sic->meta.refcount += 1; } static void swrap_dec_refcount(struct socket_info *si) { struct socket_info_container *sic = SOCKET_INFO_CONTAINER(si); sic->meta.refcount -= 1; } static int swrap_get_next_free(struct socket_info *si) { struct socket_info_container *sic = SOCKET_INFO_CONTAINER(si); return sic->meta.next_free; } static void swrap_set_next_free(struct socket_info *si, int next_free) { struct socket_info_container *sic = SOCKET_INFO_CONTAINER(si); sic->meta.next_free = next_free; } static int swrap_un_path(struct sockaddr_un *un, const char *swrap_dir, char type, unsigned int iface, unsigned int prt) { int ret; ret = snprintf(un->sun_path, sizeof(un->sun_path), "%s/"SOCKET_FORMAT, swrap_dir, type, iface, prt); if ((size_t)ret >= sizeof(un->sun_path)) { return ENAMETOOLONG; } return 0; } static int swrap_un_path_EINVAL(struct sockaddr_un *un, const char *swrap_dir) { int ret; ret = snprintf(un->sun_path, sizeof(un->sun_path), "%s/EINVAL", swrap_dir); if ((size_t)ret >= sizeof(un->sun_path)) { return ENAMETOOLONG; } return 0; } static bool swrap_dir_usable(const char *swrap_dir) { struct sockaddr_un un; int ret; ret = swrap_un_path(&un, swrap_dir, SOCKET_TYPE_CHAR_TCP, 0, 0); if (ret == 0) { return true; } ret = swrap_un_path_EINVAL(&un, swrap_dir); if (ret == 0) { return true; } return false; } static char *socket_wrapper_dir(void) { char *swrap_dir = NULL; char *s = getenv("SOCKET_WRAPPER_DIR"); char *t; bool ok; if (s == NULL || s[0] == '\0') { SWRAP_LOG(SWRAP_LOG_WARN, "SOCKET_WRAPPER_DIR not set"); return NULL; } swrap_dir = realpath(s, NULL); if (swrap_dir == NULL) { SWRAP_LOG(SWRAP_LOG_ERROR, "Unable to resolve socket_wrapper dir path: %s - %s", s, strerror(errno)); abort(); } ok = swrap_dir_usable(swrap_dir); if (ok) { goto done; } free(swrap_dir); ok = swrap_dir_usable(s); if (!ok) { SWRAP_LOG(SWRAP_LOG_ERROR, "SOCKET_WRAPPER_DIR is too long"); abort(); } t = getenv("SOCKET_WRAPPER_DIR_ALLOW_ORIG"); if (t == NULL) { SWRAP_LOG(SWRAP_LOG_ERROR, "realpath(SOCKET_WRAPPER_DIR) too long and " "SOCKET_WRAPPER_DIR_ALLOW_ORIG not set"); abort(); } swrap_dir = strdup(s); if (swrap_dir == NULL) { SWRAP_LOG(SWRAP_LOG_ERROR, "Unable to duplicate socket_wrapper dir path"); abort(); } SWRAP_LOG(SWRAP_LOG_WARN, "realpath(SOCKET_WRAPPER_DIR) too long, " "using original SOCKET_WRAPPER_DIR\n"); done: SWRAP_LOG(SWRAP_LOG_TRACE, "socket_wrapper_dir: %s", swrap_dir); return swrap_dir; } static unsigned int socket_wrapper_mtu(void) { static unsigned int max_mtu = 0; unsigned int tmp; const char *s; char *endp; swrap_mutex_lock(&mtu_update_mutex); if (max_mtu != 0) { goto done; } max_mtu = SOCKET_WRAPPER_MTU_DEFAULT; s = getenv("SOCKET_WRAPPER_MTU"); if (s == NULL) { goto done; } tmp = strtol(s, &endp, 10); if (s == endp) { goto done; } if (tmp < SOCKET_WRAPPER_MTU_MIN || tmp > SOCKET_WRAPPER_MTU_MAX) { goto done; } max_mtu = tmp; done: swrap_mutex_unlock(&mtu_update_mutex); return max_mtu; } static int _socket_wrapper_init_mutex(pthread_mutex_t *m, const char *name) { pthread_mutexattr_t ma; bool need_destroy = false; int ret = 0; #define __CHECK(cmd) do { \ ret = cmd; \ if (ret != 0) { \ SWRAP_LOG(SWRAP_LOG_ERROR, \ "%s: %s - failed %d", \ name, #cmd, ret); \ goto done; \ } \ } while(0) *m = (pthread_mutex_t)PTHREAD_MUTEX_INITIALIZER; __CHECK(pthread_mutexattr_init(&ma)); need_destroy = true; __CHECK(pthread_mutexattr_settype(&ma, PTHREAD_MUTEX_ERRORCHECK)); __CHECK(pthread_mutex_init(m, &ma)); done: if (need_destroy) { pthread_mutexattr_destroy(&ma); } return ret; } static size_t socket_wrapper_max_sockets(void) { const char *s; size_t tmp; char *endp; if (socket_info_max != 0) { return socket_info_max; } socket_info_max = SOCKET_WRAPPER_MAX_SOCKETS_DEFAULT; s = getenv("SOCKET_WRAPPER_MAX_SOCKETS"); if (s == NULL || s[0] == '\0') { goto done; } tmp = strtoul(s, &endp, 10); if (s == endp) { goto done; } if (tmp == 0) { tmp = SOCKET_WRAPPER_MAX_SOCKETS_DEFAULT; SWRAP_LOG(SWRAP_LOG_ERROR, "Invalid number of sockets specified, " "using default (%zu)", tmp); } if (tmp > SOCKET_WRAPPER_MAX_SOCKETS_LIMIT) { tmp = SOCKET_WRAPPER_MAX_SOCKETS_LIMIT; SWRAP_LOG(SWRAP_LOG_ERROR, "Invalid number of sockets specified, " "using maximum (%zu).", tmp); } socket_info_max = tmp; done: return socket_info_max; } static void socket_wrapper_init_fds_idx(void) { int *tmp = NULL; size_t i; if (socket_fds_idx != NULL) { return; } tmp = (int *)calloc(socket_fds_max, sizeof(int)); if (tmp == NULL) { SWRAP_LOG(SWRAP_LOG_ERROR, "Failed to allocate socket fds index array: %s", strerror(errno)); exit(-1); } for (i = 0; i < socket_fds_max; i++) { tmp[i] = -1; } socket_fds_idx = tmp; } static void socket_wrapper_init_sockets(void) { size_t max_sockets; size_t i; int ret = 0; swrap_bind_symbol_all(); swrap_mutex_lock(&sockets_mutex); if (sockets != NULL) { swrap_mutex_unlock(&sockets_mutex); return; } SWRAP_LOG(SWRAP_LOG_DEBUG, "SOCKET_WRAPPER_PACKAGE[%s] SOCKET_WRAPPER_VERSION[%s]", SOCKET_WRAPPER_PACKAGE, SOCKET_WRAPPER_VERSION); /* * Intialize the static cache early before * any thread is able to start. */ (void)swrap_ipv4_net(); socket_wrapper_init_fds_idx(); /* Needs to be called inside the sockets_mutex lock here. */ max_sockets = socket_wrapper_max_sockets(); sockets = (struct socket_info_container *)calloc(max_sockets, sizeof(struct socket_info_container)); if (sockets == NULL) { SWRAP_LOG(SWRAP_LOG_ERROR, "Failed to allocate sockets array: %s", strerror(errno)); swrap_mutex_unlock(&sockets_mutex); exit(-1); } swrap_mutex_lock(&first_free_mutex); swrap_mutex_lock(&sockets_si_global); first_free = 0; for (i = 0; i < max_sockets; i++) { swrap_set_next_free(&sockets[i].info, i+1); } /* mark the end of the free list */ swrap_set_next_free(&sockets[max_sockets-1].info, -1); swrap_mutex_unlock(&sockets_si_global); swrap_mutex_unlock(&first_free_mutex); swrap_mutex_unlock(&sockets_mutex); if (ret != 0) { exit(-1); } } bool socket_wrapper_enabled(void) { char *s = socket_wrapper_dir(); if (s == NULL) { return false; } SAFE_FREE(s); socket_wrapper_init_sockets(); return true; } static unsigned int socket_wrapper_default_iface(void) { const char *s = getenv("SOCKET_WRAPPER_DEFAULT_IFACE"); if (s) { unsigned int iface; if (sscanf(s, "%u", &iface) == 1) { if (iface >= 1 && iface <= MAX_WRAPPED_INTERFACES) { return iface; } } } return 1;/* 127.0.0.1 */ } static void set_socket_info_index(int fd, int idx) { SWRAP_LOG(SWRAP_LOG_TRACE, "fd=%d idx=%d", fd, idx); socket_fds_idx[fd] = idx; /* This builtin issues a full memory barrier. */ __sync_synchronize(); } static void reset_socket_info_index(int fd) { SWRAP_LOG(SWRAP_LOG_TRACE, "fd=%d idx=%d", fd, -1); set_socket_info_index(fd, -1); } static int find_socket_info_index(int fd) { if (fd < 0) { return -1; } if (socket_fds_idx == NULL) { return -1; } if ((size_t)fd >= socket_fds_max) { /* * Do not add a log here as some applications do stupid things * like: * * for (fd = 0; fd <= getdtablesize(); fd++) { * close(fd) * }; * * This would produce millions of lines of debug messages. */ #if 0 SWRAP_LOG(SWRAP_LOG_ERROR, "Looking for a socket info for the fd %d is over the " "max socket index limit of %zu.", fd, socket_fds_max); #endif return -1; } /* This builtin issues a full memory barrier. */ __sync_synchronize(); return socket_fds_idx[fd]; } static int swrap_add_socket_info(const struct socket_info *si_input) { struct socket_info *si = NULL; int si_index = -1; if (si_input == NULL) { errno = EINVAL; return -1; } swrap_mutex_lock(&first_free_mutex); if (first_free == -1) { errno = ENFILE; goto out; } si_index = first_free; si = swrap_get_socket_info(si_index); SWRAP_LOCK_SI(si); first_free = swrap_get_next_free(si); *si = *si_input; swrap_inc_refcount(si); SWRAP_UNLOCK_SI(si); out: swrap_mutex_unlock(&first_free_mutex); return si_index; } static int swrap_create_socket(struct socket_info *si, int fd) { int idx; if ((size_t)fd >= socket_fds_max) { SWRAP_LOG(SWRAP_LOG_ERROR, "The max socket index limit of %zu has been reached, " "trying to add %d", socket_fds_max, fd); errno = EMFILE; return -1; } idx = swrap_add_socket_info(si); if (idx == -1) { return -1; } set_socket_info_index(fd, idx); return idx; } static int convert_un_in(const struct sockaddr_un *un, struct sockaddr *in, socklen_t *len) { unsigned int iface; unsigned int prt; const char *p; char type; p = strrchr(un->sun_path, '/'); if (p) p++; else p = un->sun_path; if (sscanf(p, SOCKET_FORMAT, &type, &iface, &prt) != 3) { SWRAP_LOG(SWRAP_LOG_ERROR, "sun_path[%s] p[%s]", un->sun_path, p); errno = EINVAL; return -1; } if (iface == 0 || iface > MAX_WRAPPED_INTERFACES) { SWRAP_LOG(SWRAP_LOG_ERROR, "type %c iface %u port %u", type, iface, prt); errno = EINVAL; return -1; } if (prt > 0xFFFF) { SWRAP_LOG(SWRAP_LOG_ERROR, "type %c iface %u port %u", type, iface, prt); errno = EINVAL; return -1; } SWRAP_LOG(SWRAP_LOG_TRACE, "type %c iface %u port %u", type, iface, prt); 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)) { SWRAP_LOG(SWRAP_LOG_ERROR, "V4: *len(%zu) < sizeof(*in2)=%zu", (size_t)*len, sizeof(*in2)); errno = EINVAL; return -1; } memset(in2, 0, sizeof(*in2)); in2->sin_family = AF_INET; in2->sin_addr.s_addr = htonl(swrap_ipv4_iface(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)) { SWRAP_LOG(SWRAP_LOG_ERROR, "V6: *len(%zu) < sizeof(*in2)=%zu", (size_t)*len, sizeof(*in2)); SWRAP_LOG(SWRAP_LOG_ERROR, "LINE:%d", __LINE__); 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: SWRAP_LOG(SWRAP_LOG_ERROR, "type %c iface %u port %u", type, iface, prt); errno = EINVAL; return -1; } return 0; } static int convert_in_un_remote(struct socket_info *si, const struct sockaddr *inaddr, struct sockaddr_un *un, int *bcast) { char type = '\0'; unsigned int prt; unsigned int iface; int is_bcast = 0; char *swrap_dir = NULL; if (bcast) *bcast = 0; switch (inaddr->sa_family) { case AF_INET: { const struct sockaddr_in *in = (const struct sockaddr_in *)(const void *)inaddr; unsigned int addr = ntohl(in->sin_addr.s_addr); char u_type = '\0'; char b_type = '\0'; char a_type = '\0'; const unsigned int sw_net_addr = swrap_ipv4_net(); const unsigned int sw_bcast_addr = swrap_ipv4_bcast(); 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!"); 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 == sw_bcast_addr) { /* * 127.255.255.255 * or * 10.255.255.255 * only udp */ is_bcast = 1; type = b_type; iface = socket_wrapper_default_iface(); } else if ((addr & 0xFFFFFF00) == sw_net_addr) { /* 127.0.0.X or 10.53.57.X */ is_bcast = 0; type = u_type; iface = (addr & 0x000000FF); } else { struct swrap_sockaddr_buf buf = {}; SWRAP_LOG(SWRAP_LOG_WARN, "%s", swrap_sockaddr_string(&buf, inaddr)); 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!"); 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 { struct swrap_sockaddr_buf buf = {}; SWRAP_LOG(SWRAP_LOG_WARN, "%s", swrap_sockaddr_string(&buf, inaddr)); errno = ENETUNREACH; return -1; } break; } #endif default: SWRAP_LOG(SWRAP_LOG_ERROR, "Unknown address family!"); errno = ENETUNREACH; return -1; } if (prt == 0) { SWRAP_LOG(SWRAP_LOG_WARN, "Port not set"); errno = EINVAL; return -1; } swrap_dir = socket_wrapper_dir(); if (swrap_dir == NULL) { errno = EINVAL; return -1; } if (is_bcast) { swrap_un_path_EINVAL(un, swrap_dir); SWRAP_LOG(SWRAP_LOG_DEBUG, "un path [%s]", un->sun_path); SAFE_FREE(swrap_dir); /* the caller need to do more processing */ return 0; } swrap_un_path(un, swrap_dir, type, iface, prt); SWRAP_LOG(SWRAP_LOG_DEBUG, "un path [%s]", un->sun_path); SAFE_FREE(swrap_dir); return 0; } static int convert_in_un_alloc(struct socket_info *si, const struct sockaddr *inaddr, struct sockaddr_un *un, int *bcast) { char type = '\0'; unsigned int prt; unsigned int iface; struct stat st; int is_bcast = 0; char *swrap_dir = NULL; if (bcast) *bcast = 0; switch (si->family) { case AF_INET: { const struct sockaddr_in *in = (const struct sockaddr_in *)(const void *)inaddr; unsigned int addr = ntohl(in->sin_addr.s_addr); char u_type = '\0'; char d_type = '\0'; char b_type = '\0'; char a_type = '\0'; const unsigned int sw_net_addr = swrap_ipv4_net(); const unsigned int sw_bcast_addr = swrap_ipv4_bcast(); 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!"); 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 == sw_bcast_addr) { /* 127.255.255.255 only udp */ is_bcast = 1; type = b_type; iface = socket_wrapper_default_iface(); } else if ((addr & 0xFFFFFF00) == sw_net_addr) { /* 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(swrap_ipv4_iface(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!"); 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"); errno = EADDRNOTAVAIL; return -1; } if (bcast) *bcast = is_bcast; if (iface == 0 || iface > MAX_WRAPPED_INTERFACES) { errno = EINVAL; return -1; } swrap_dir = socket_wrapper_dir(); if (swrap_dir == NULL) { errno = EINVAL; return -1; } if (prt == 0) { /* handle auto-allocation of ephemeral ports */ for (prt = 5001; prt < 10000; prt++) { swrap_un_path(un, swrap_dir, type, iface, prt); if (stat(un->sun_path, &st) == 0) continue; set_port(si->family, prt, &si->myname); set_port(si->family, prt, &si->bindname); break; } if (prt == 10000) { errno = ENFILE; SAFE_FREE(swrap_dir); return -1; } } swrap_un_path(un, swrap_dir, type, iface, prt); SWRAP_LOG(SWRAP_LOG_DEBUG, "un path [%s]", un->sun_path); SAFE_FREE(swrap_dir); return 0; } static struct socket_info *find_socket_info(int fd) { int idx = find_socket_info_index(fd); if (idx == -1) { return NULL; } return swrap_get_socket_info(idx); } #if 0 /* FIXME */ static bool check_addr_port_in_use(const struct sockaddr *sa, socklen_t len) { struct socket_info_fd *f; const struct socket_info *last_s = NULL; /* first catch invalid input */ switch (sa->sa_family) { case AF_INET: if (len < sizeof(struct sockaddr_in)) { return false; } break; #ifdef HAVE_IPV6 case AF_INET6: if (len < sizeof(struct sockaddr_in6)) { return false; } break; #endif default: return false; break; } for (f = socket_fds; f; f = f->next) { struct socket_info *s = swrap_get_socket_info(f->si_index); if (s == last_s) { continue; } last_s = s; if (s->myname == NULL) { continue; } if (s->myname->sa_family != sa->sa_family) { continue; } switch (s->myname->sa_family) { case AF_INET: { struct sockaddr_in *sin1, *sin2; sin1 = (struct sockaddr_in *)s->myname; sin2 = (struct sockaddr_in *)sa; if (sin1->sin_addr.s_addr == htonl(INADDR_ANY)) { continue; } if (sin1->sin_port != sin2->sin_port) { continue; } if (sin1->sin_addr.s_addr != sin2->sin_addr.s_addr) { continue; } /* found */ return true; break; } #ifdef HAVE_IPV6 case AF_INET6: { struct sockaddr_in6 *sin1, *sin2; sin1 = (struct sockaddr_in6 *)s->myname; sin2 = (struct sockaddr_in6 *)sa; if (sin1->sin6_port != sin2->sin6_port) { continue; } if (!IN6_ARE_ADDR_EQUAL(&sin1->sin6_addr, &sin2->sin6_addr)) { continue; } /* found */ return true; break; } #endif default: continue; break; } } return false; } #endif static void swrap_remove_stale(int fd); 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!"); 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"); 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!"); 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"); 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; } SWRAP_LOG(SWRAP_LOG_TRACE, "SOCKET_WRAPPER_PCAP_FILE: %s", s); return s; } static uint8_t *swrap_pcap_packet_init(struct timeval *tval, const struct sockaddr *src, const struct sockaddr *dest, int socket_type, const uint8_t *payload, size_t payload_len, unsigned long tcp_seqno, unsigned long tcp_ack, unsigned char tcp_ctl, int unreachable, size_t *_packet_len) { uint8_t *base = NULL; uint8_t *buf = NULL; union { uint8_t *ptr; struct swrap_packet_frame *frame; } f; union { uint8_t *ptr; union swrap_packet_ip *ip; } i; union swrap_packet_payload *pay; size_t packet_len; size_t alloc_len; size_t nonwire_len = sizeof(struct swrap_packet_frame); size_t wire_hdr_len = 0; size_t wire_len = 0; size_t ip_hdr_len = 0; size_t icmp_hdr_len = 0; size_t icmp_truncate_len = 0; uint8_t protocol = 0, icmp_protocol = 0; const struct sockaddr_in *src_in = NULL; const struct sockaddr_in *dest_in = NULL; #ifdef HAVE_IPV6 const struct sockaddr_in6 *src_in6 = NULL; const struct sockaddr_in6 *dest_in6 = NULL; #endif uint16_t src_port; uint16_t dest_port; switch (src->sa_family) { case AF_INET: src_in = (const struct sockaddr_in *)(const void *)src; dest_in = (const struct sockaddr_in *)(const void *)dest; src_port = src_in->sin_port; dest_port = dest_in->sin_port; ip_hdr_len = sizeof(i.ip->v4); break; #ifdef HAVE_IPV6 case AF_INET6: src_in6 = (const struct sockaddr_in6 *)(const void *)src; dest_in6 = (const struct sockaddr_in6 *)(const void *)dest; src_port = src_in6->sin6_port; dest_port = dest_in6->sin6_port; ip_hdr_len = sizeof(i.ip->v6); break; #endif default: return NULL; } switch (socket_type) { case SOCK_STREAM: protocol = 0x06; /* TCP */ wire_hdr_len = ip_hdr_len + sizeof(pay->tcp); wire_len = wire_hdr_len + payload_len; break; case SOCK_DGRAM: protocol = 0x11; /* UDP */ wire_hdr_len = ip_hdr_len + sizeof(pay->udp); wire_len = wire_hdr_len + payload_len; break; default: return NULL; } if (unreachable) { icmp_protocol = protocol; switch (src->sa_family) { case AF_INET: protocol = 0x01; /* ICMPv4 */ icmp_hdr_len = ip_hdr_len + sizeof(pay->icmp4); break; #ifdef HAVE_IPV6 case AF_INET6: protocol = 0x3A; /* ICMPv6 */ icmp_hdr_len = ip_hdr_len + sizeof(pay->icmp6); break; #endif } if (wire_len > 64 ) { icmp_truncate_len = wire_len - 64; } wire_len += icmp_hdr_len; } packet_len = nonwire_len + wire_len; alloc_len = packet_len; if (alloc_len < SWRAP_PACKET_MIN_ALLOC) { alloc_len = SWRAP_PACKET_MIN_ALLOC; } base = (uint8_t *)calloc(1, alloc_len); if (base == NULL) { return NULL; } buf = base; f.ptr = buf; f.frame->seconds = tval->tv_sec; f.frame->micro_seconds = tval->tv_usec; f.frame->recorded_length = wire_len - icmp_truncate_len; f.frame->full_length = wire_len - icmp_truncate_len; buf += SWRAP_PACKET_FRAME_SIZE; i.ptr = buf; switch (src->sa_family) { case AF_INET: if (src_in == NULL || dest_in == NULL) { SAFE_FREE(base); return NULL; } i.ip->v4.ver_hdrlen = 0x45; /* version 4 and 5 * 32 bit words */ i.ip->v4.tos = 0x00; i.ip->v4.packet_length = htons(wire_len - icmp_truncate_len); i.ip->v4.identification = htons(0xFFFF); i.ip->v4.flags = 0x40; /* BIT 1 set - means don't fragment */ i.ip->v4.fragment = htons(0x0000); i.ip->v4.ttl = 0xFF; i.ip->v4.protocol = protocol; i.ip->v4.hdr_checksum = htons(0x0000); i.ip->v4.src_addr = src_in->sin_addr.s_addr; i.ip->v4.dest_addr = dest_in->sin_addr.s_addr; buf += SWRAP_PACKET_IP_V4_SIZE; break; #ifdef HAVE_IPV6 case AF_INET6: if (src_in6 == NULL || dest_in6 == NULL) { SAFE_FREE(base); return NULL; } i.ip->v6.ver_prio = 0x60; /* version 4 and 5 * 32 bit words */ i.ip->v6.flow_label_high = 0x00; i.ip->v6.flow_label_low = 0x0000; i.ip->v6.payload_length = htons(wire_len - icmp_truncate_len); /* TODO */ i.ip->v6.next_header = protocol; memcpy(i.ip->v6.src_addr, src_in6->sin6_addr.s6_addr, 16); memcpy(i.ip->v6.dest_addr, dest_in6->sin6_addr.s6_addr, 16); buf += SWRAP_PACKET_IP_V6_SIZE; break; #endif } if (unreachable) { pay = (union swrap_packet_payload *)(void *)buf; switch (src->sa_family) { case AF_INET: pay->icmp4.type = 0x03; /* destination unreachable */ pay->icmp4.code = 0x01; /* host unreachable */ pay->icmp4.checksum = htons(0x0000); pay->icmp4.unused = htonl(0x00000000); buf += SWRAP_PACKET_PAYLOAD_ICMP4_SIZE; /* set the ip header in the ICMP payload */ i.ptr = buf; i.ip->v4.ver_hdrlen = 0x45; /* version 4 and 5 * 32 bit words */ i.ip->v4.tos = 0x00; i.ip->v4.packet_length = htons(wire_len - icmp_hdr_len); i.ip->v4.identification = htons(0xFFFF); i.ip->v4.flags = 0x40; /* BIT 1 set - means don't fragment */ i.ip->v4.fragment = htons(0x0000); i.ip->v4.ttl = 0xFF; i.ip->v4.protocol = icmp_protocol; i.ip->v4.hdr_checksum = htons(0x0000); i.ip->v4.src_addr = dest_in->sin_addr.s_addr; i.ip->v4.dest_addr = src_in->sin_addr.s_addr; buf += SWRAP_PACKET_IP_V4_SIZE; src_port = dest_in->sin_port; dest_port = src_in->sin_port; break; #ifdef HAVE_IPV6 case AF_INET6: pay->icmp6.type = 0x01; /* destination unreachable */ pay->icmp6.code = 0x03; /* address unreachable */ pay->icmp6.checksum = htons(0x0000); pay->icmp6.unused = htonl(0x00000000); buf += SWRAP_PACKET_PAYLOAD_ICMP6_SIZE; /* set the ip header in the ICMP payload */ i.ptr = buf; i.ip->v6.ver_prio = 0x60; /* version 4 and 5 * 32 bit words */ i.ip->v6.flow_label_high = 0x00; i.ip->v6.flow_label_low = 0x0000; i.ip->v6.payload_length = htons(wire_len - icmp_truncate_len); /* TODO */ i.ip->v6.next_header = protocol; memcpy(i.ip->v6.src_addr, dest_in6->sin6_addr.s6_addr, 16); memcpy(i.ip->v6.dest_addr, src_in6->sin6_addr.s6_addr, 16); buf += SWRAP_PACKET_IP_V6_SIZE; src_port = dest_in6->sin6_port; dest_port = src_in6->sin6_port; break; #endif } } pay = (union swrap_packet_payload *)(void *)buf; switch (socket_type) { case SOCK_STREAM: pay->tcp.source_port = src_port; pay->tcp.dest_port = dest_port; pay->tcp.seq_num = htonl(tcp_seqno); pay->tcp.ack_num = htonl(tcp_ack); pay->tcp.hdr_length = 0x50; /* 5 * 32 bit words */ pay->tcp.control = tcp_ctl; pay->tcp.window = htons(0x7FFF); pay->tcp.checksum = htons(0x0000); pay->tcp.urg = htons(0x0000); buf += SWRAP_PACKET_PAYLOAD_TCP_SIZE; break; case SOCK_DGRAM: pay->udp.source_port = src_port; pay->udp.dest_port = dest_port; pay->udp.length = htons(8 + payload_len); pay->udp.checksum = htons(0x0000); buf += SWRAP_PACKET_PAYLOAD_UDP_SIZE; break; } if (payload && payload_len > 0) { memcpy(buf, payload, payload_len); } *_packet_len = packet_len - icmp_truncate_len; return base; } static int swrap_pcap_get_fd(const char *fname) { static int fd = -1; if (fd != -1) { return fd; } fd = libc_open(fname, O_WRONLY|O_CREAT|O_EXCL|O_APPEND, 0644); if (fd != -1) { struct swrap_file_hdr file_hdr; file_hdr.magic = 0xA1B2C3D4; file_hdr.version_major = 0x0002; file_hdr.version_minor = 0x0004; file_hdr.timezone = 0x00000000; file_hdr.sigfigs = 0x00000000; file_hdr.frame_max_len = SWRAP_FRAME_LENGTH_MAX; file_hdr.link_type = 0x0065; /* 101 RAW IP */ if (libc_write(fd, &file_hdr, sizeof(file_hdr)) != sizeof(file_hdr)) { libc_close(fd); fd = -1; } return fd; } fd = libc_open(fname, O_WRONLY|O_APPEND, 0644); return fd; } static uint8_t *swrap_pcap_marshall_packet(struct socket_info *si, const struct sockaddr *addr, enum swrap_packet_type type, const void *buf, size_t len, size_t *packet_len) { const struct sockaddr *src_addr; const struct sockaddr *dest_addr; unsigned long tcp_seqno = 0; unsigned long tcp_ack = 0; unsigned char tcp_ctl = 0; int unreachable = 0; struct timeval tv; switch (si->family) { case AF_INET: break; #ifdef HAVE_IPV6 case AF_INET6: break; #endif default: return NULL; } switch (type) { case SWRAP_CONNECT_SEND: if (si->type != SOCK_STREAM) { return NULL; } src_addr = &si->myname.sa.s; dest_addr = addr; tcp_seqno = si->io.pck_snd; tcp_ack = si->io.pck_rcv; tcp_ctl = 0x02; /* SYN */ si->io.pck_snd += 1; break; case SWRAP_CONNECT_RECV: if (si->type != SOCK_STREAM) { return NULL; } dest_addr = &si->myname.sa.s; src_addr = addr; tcp_seqno = si->io.pck_rcv; tcp_ack = si->io.pck_snd; tcp_ctl = 0x12; /** SYN,ACK */ si->io.pck_rcv += 1; break; case SWRAP_CONNECT_UNREACH: if (si->type != SOCK_STREAM) { return NULL; } dest_addr = &si->myname.sa.s; src_addr = addr; /* Unreachable: resend the data of SWRAP_CONNECT_SEND */ tcp_seqno = si->io.pck_snd - 1; tcp_ack = si->io.pck_rcv; tcp_ctl = 0x02; /* SYN */ unreachable = 1; break; case SWRAP_CONNECT_ACK: if (si->type != SOCK_STREAM) { return NULL; } src_addr = &si->myname.sa.s; dest_addr = addr; tcp_seqno = si->io.pck_snd; tcp_ack = si->io.pck_rcv; tcp_ctl = 0x10; /* ACK */ break; case SWRAP_ACCEPT_SEND: if (si->type != SOCK_STREAM) { return NULL; } dest_addr = &si->myname.sa.s; src_addr = addr; tcp_seqno = si->io.pck_rcv; tcp_ack = si->io.pck_snd; tcp_ctl = 0x02; /* SYN */ si->io.pck_rcv += 1; break; case SWRAP_ACCEPT_RECV: if (si->type != SOCK_STREAM) { return NULL; } src_addr = &si->myname.sa.s; dest_addr = addr; tcp_seqno = si->io.pck_snd; tcp_ack = si->io.pck_rcv; tcp_ctl = 0x12; /* SYN,ACK */ si->io.pck_snd += 1; break; case SWRAP_ACCEPT_ACK: if (si->type != SOCK_STREAM) { return NULL; } dest_addr = &si->myname.sa.s; src_addr = addr; tcp_seqno = si->io.pck_rcv; tcp_ack = si->io.pck_snd; tcp_ctl = 0x10; /* ACK */ break; case SWRAP_SEND: src_addr = &si->myname.sa.s; dest_addr = &si->peername.sa.s; tcp_seqno = si->io.pck_snd; tcp_ack = si->io.pck_rcv; tcp_ctl = 0x18; /* PSH,ACK */ si->io.pck_snd += len; break; case SWRAP_SEND_RST: dest_addr = &si->myname.sa.s; src_addr = &si->peername.sa.s; if (si->type == SOCK_DGRAM) { return swrap_pcap_marshall_packet(si, &si->peername.sa.s, SWRAP_SENDTO_UNREACH, buf, len, packet_len); } tcp_seqno = si->io.pck_rcv; tcp_ack = si->io.pck_snd; tcp_ctl = 0x14; /** RST,ACK */ break; case SWRAP_PENDING_RST: dest_addr = &si->myname.sa.s; src_addr = &si->peername.sa.s; if (si->type == SOCK_DGRAM) { return NULL; } tcp_seqno = si->io.pck_rcv; tcp_ack = si->io.pck_snd; tcp_ctl = 0x14; /* RST,ACK */ break; case SWRAP_RECV: dest_addr = &si->myname.sa.s; src_addr = &si->peername.sa.s; tcp_seqno = si->io.pck_rcv; tcp_ack = si->io.pck_snd; tcp_ctl = 0x18; /* PSH,ACK */ si->io.pck_rcv += len; break; case SWRAP_RECV_RST: dest_addr = &si->myname.sa.s; src_addr = &si->peername.sa.s; if (si->type == SOCK_DGRAM) { return NULL; } tcp_seqno = si->io.pck_rcv; tcp_ack = si->io.pck_snd; tcp_ctl = 0x14; /* RST,ACK */ break; case SWRAP_SENDTO: src_addr = &si->myname.sa.s; dest_addr = addr; si->io.pck_snd += len; break; case SWRAP_SENDTO_UNREACH: dest_addr = &si->myname.sa.s; src_addr = addr; unreachable = 1; break; case SWRAP_RECVFROM: dest_addr = &si->myname.sa.s; src_addr = addr; si->io.pck_rcv += len; break; case SWRAP_CLOSE_SEND: if (si->type != SOCK_STREAM) { return NULL; } src_addr = &si->myname.sa.s; dest_addr = &si->peername.sa.s; tcp_seqno = si->io.pck_snd; tcp_ack = si->io.pck_rcv; tcp_ctl = 0x11; /* FIN, ACK */ si->io.pck_snd += 1; break; case SWRAP_CLOSE_RECV: if (si->type != SOCK_STREAM) { return NULL; } dest_addr = &si->myname.sa.s; src_addr = &si->peername.sa.s; tcp_seqno = si->io.pck_rcv; tcp_ack = si->io.pck_snd; tcp_ctl = 0x11; /* FIN,ACK */ si->io.pck_rcv += 1; break; case SWRAP_CLOSE_ACK: if (si->type != SOCK_STREAM) { return NULL; } src_addr = &si->myname.sa.s; dest_addr = &si->peername.sa.s; tcp_seqno = si->io.pck_snd; tcp_ack = si->io.pck_rcv; tcp_ctl = 0x10; /* ACK */ break; default: return NULL; } swrapGetTimeOfDay(&tv); return swrap_pcap_packet_init(&tv, src_addr, dest_addr, si->type, (const uint8_t *)buf, len, tcp_seqno, tcp_ack, tcp_ctl, unreachable, packet_len); } static void swrap_pcap_dump_packet(struct socket_info *si, const struct sockaddr *addr, enum swrap_packet_type type, const void *buf, size_t len) { const char *file_name; uint8_t *packet; size_t packet_len = 0; int fd; swrap_mutex_lock(&pcap_dump_mutex); file_name = swrap_pcap_init_file(); if (!file_name) { goto done; } packet = swrap_pcap_marshall_packet(si, addr, type, buf, len, &packet_len); if (packet == NULL) { goto done; } fd = swrap_pcap_get_fd(file_name); if (fd != -1) { if (libc_write(fd, packet, packet_len) != (ssize_t)packet_len) { free(packet); goto done; } } free(packet); done: swrap_mutex_unlock(&pcap_dump_mutex); } /**************************************************************************** * SIGNALFD ***************************************************************************/ #ifdef HAVE_SIGNALFD static int swrap_signalfd(int fd, const sigset_t *mask, int flags) { int rc; rc = libc_signalfd(fd, mask, flags); if (rc != -1) { swrap_remove_stale(fd); } return rc; } int signalfd(int fd, const sigset_t *mask, int flags) { return swrap_signalfd(fd, mask, flags); } #endif /**************************************************************************** * SOCKET ***************************************************************************/ static int swrap_socket(int family, int type, int protocol) { struct socket_info *si = NULL; struct socket_info _si = { 0 }; int fd; int ret; int real_type = type; /* * Remove possible addition flags passed to socket() so * do not fail checking the type. * See https://lwn.net/Articles/281965/ */ #ifdef SOCK_CLOEXEC real_type &= ~SOCK_CLOEXEC; #endif #ifdef SOCK_NONBLOCK real_type &= ~SOCK_NONBLOCK; #endif if (!socket_wrapper_enabled()) { return libc_socket(family, type, protocol); } switch (family) { case AF_INET: #ifdef HAVE_IPV6 case AF_INET6: #endif break; #ifdef AF_NETLINK case AF_NETLINK: #endif /* AF_NETLINK */ #ifdef AF_PACKET case AF_PACKET: #endif /* AF_PACKET */ case AF_UNIX: fd = libc_socket(family, type, protocol); if (fd != -1) { /* Check if we have a stale fd and remove it */ swrap_remove_stale(fd); SWRAP_LOG(SWRAP_LOG_TRACE, "Unix socket fd=%d", fd); } return fd; default: errno = EAFNOSUPPORT; return -1; } switch (real_type) { case SOCK_STREAM: break; case SOCK_DGRAM: break; default: errno = EPROTONOSUPPORT; return -1; } switch (protocol) { case 0: break; case 6: if (real_type == SOCK_STREAM) { break; } FALL_THROUGH; case 17: if (real_type == SOCK_DGRAM) { break; } FALL_THROUGH; default: errno = EPROTONOSUPPORT; return -1; } /* * We must call libc_socket with type, from the caller, not the version * we removed SOCK_CLOEXEC and SOCK_NONBLOCK from */ fd = libc_socket(AF_UNIX, type, 0); if (fd == -1) { return -1; } /* Check if we have a stale fd and remove it */ swrap_remove_stale(fd); si = &_si; si->family = family; /* however, the rest of the socket_wrapper code expects just * the type, not the flags */ si->type = real_type; si->protocol = protocol; /* * Setup myname so getsockname() can succeed to find out the socket * type. */ switch(si->family) { case AF_INET: { struct sockaddr_in sin = { .sin_family = AF_INET, }; si->myname.sa_socklen = sizeof(struct sockaddr_in); memcpy(&si->myname.sa.in, &sin, si->myname.sa_socklen); break; } #ifdef HAVE_IPV6 case AF_INET6: { struct sockaddr_in6 sin6 = { .sin6_family = AF_INET6, }; si->myname.sa_socklen = sizeof(struct sockaddr_in6); memcpy(&si->myname.sa.in6, &sin6, si->myname.sa_socklen); break; } #endif default: errno = EINVAL; return -1; } ret = swrap_create_socket(si, fd); if (ret == -1) { int saved_errno = errno; libc_close(fd); errno = saved_errno; return -1; } SWRAP_LOG(SWRAP_LOG_TRACE, "Created %s socket for protocol %s, fd=%d", family == AF_INET ? "IPv4" : "IPv6", real_type == SOCK_DGRAM ? "UDP" : "TCP", fd); return fd; } int socket(int family, int type, int protocol) { return swrap_socket(family, type, protocol); } /**************************************************************************** * SOCKETPAIR ***************************************************************************/ static int swrap_socketpair(int family, int type, int protocol, int sv[2]) { int rc; rc = libc_socketpair(family, type, protocol, sv); if (rc != -1) { swrap_remove_stale(sv[0]); swrap_remove_stale(sv[1]); } return rc; } int socketpair(int family, int type, int protocol, int sv[2]) { return swrap_socketpair(family, type, protocol, sv); } /**************************************************************************** * SOCKETPAIR ***************************************************************************/ #ifdef HAVE_TIMERFD_CREATE static int swrap_timerfd_create(int clockid, int flags) { int fd; fd = libc_timerfd_create(clockid, flags); if (fd != -1) { swrap_remove_stale(fd); } return fd; } int timerfd_create(int clockid, int flags) { return swrap_timerfd_create(clockid, flags); } #endif /**************************************************************************** * PIPE ***************************************************************************/ static int swrap_pipe(int pipefd[2]) { int rc; rc = libc_pipe(pipefd); if (rc != -1) { swrap_remove_stale(pipefd[0]); swrap_remove_stale(pipefd[1]); } return rc; } int pipe(int pipefd[2]) { return swrap_pipe(pipefd); } /**************************************************************************** * ACCEPT ***************************************************************************/ static int swrap_accept(int s, struct sockaddr *addr, socklen_t *addrlen, int flags) { struct socket_info *parent_si, *child_si; struct socket_info new_si = { 0 }; int fd; int idx; struct swrap_address un_addr = { .sa_socklen = sizeof(struct sockaddr_un), }; struct swrap_address un_my_addr = { .sa_socklen = sizeof(struct sockaddr_un), }; struct swrap_address in_addr = { .sa_socklen = sizeof(struct sockaddr_storage), }; struct swrap_address in_my_addr = { .sa_socklen = sizeof(struct sockaddr_storage), }; int ret; parent_si = find_socket_info(s); if (!parent_si) { #ifdef HAVE_ACCEPT4 return libc_accept4(s, addr, addrlen, flags); #else UNUSED(flags); return libc_accept(s, addr, addrlen); #endif } /* * prevent parent_si from being altered / closed * while we read it */ SWRAP_LOCK_SI(parent_si); /* * assume out sockaddr have the same size as the in parent * socket family */ in_addr.sa_socklen = socket_length(parent_si->family); if (in_addr.sa_socklen <= 0) { SWRAP_UNLOCK_SI(parent_si); errno = EINVAL; return -1; } SWRAP_UNLOCK_SI(parent_si); #ifdef HAVE_ACCEPT4 ret = libc_accept4(s, &un_addr.sa.s, &un_addr.sa_socklen, flags); #else UNUSED(flags); ret = libc_accept(s, &un_addr.sa.s, &un_addr.sa_socklen); #endif if (ret == -1) { int saved_errno = errno; if (saved_errno == ENOTSOCK) { /* Remove stale fds */ swrap_remove_stale(s); } errno = saved_errno; return ret; } fd = ret; /* Check if we have a stale fd and remove it */ swrap_remove_stale(fd); if (un_addr.sa.un.sun_path[0] == '\0') { /* * FreeBSD seems to have a problem where * accept4() on the unix socket doesn't * ECONNABORTED for already disconnected connections. * * Let's try libc_getpeername() to get the peer address * as a fallback, but it'll likely return ENOTCONN, * which we have to map to ECONNABORTED. */ un_addr.sa_socklen = sizeof(struct sockaddr_un), ret = libc_getpeername(fd, &un_addr.sa.s, &un_addr.sa_socklen); if (ret == -1) { int saved_errno = errno; libc_close(fd); if (saved_errno == ENOTCONN) { /* * If the connection is already disconnected * we should return ECONNABORTED. */ saved_errno = ECONNABORTED; } errno = saved_errno; return ret; } } ret = libc_getsockname(fd, &un_my_addr.sa.s, &un_my_addr.sa_socklen); if (ret == -1) { int saved_errno = errno; libc_close(fd); if (saved_errno == ENOTCONN) { /* * If the connection is already disconnected * we should return ECONNABORTED. */ saved_errno = ECONNABORTED; } errno = saved_errno; return ret; } SWRAP_LOCK_SI(parent_si); ret = sockaddr_convert_from_un(parent_si, &un_addr.sa.un, un_addr.sa_socklen, parent_si->family, &in_addr.sa.s, &in_addr.sa_socklen); if (ret == -1) { int saved_errno = errno; SWRAP_UNLOCK_SI(parent_si); libc_close(fd); errno = saved_errno; return ret; } child_si = &new_si; child_si->family = parent_si->family; child_si->type = parent_si->type; child_si->protocol = parent_si->protocol; child_si->bound = 1; child_si->is_server = 1; child_si->connected = 1; SWRAP_UNLOCK_SI(parent_si); child_si->peername = (struct swrap_address) { .sa_socklen = in_addr.sa_socklen, }; memcpy(&child_si->peername.sa.ss, &in_addr.sa.ss, in_addr.sa_socklen); if (addr != NULL && addrlen != NULL) { size_t copy_len = MIN(*addrlen, in_addr.sa_socklen); if (copy_len > 0) { memcpy(addr, &in_addr.sa.ss, copy_len); } *addrlen = in_addr.sa_socklen; } ret = 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) { int saved_errno = errno; libc_close(fd); errno = saved_errno; return ret; } SWRAP_LOG(SWRAP_LOG_TRACE, "accept() path=%s, fd=%d", un_my_addr.sa.un.sun_path, s); child_si->myname = (struct swrap_address) { .sa_socklen = in_my_addr.sa_socklen, }; memcpy(&child_si->myname.sa.ss, &in_my_addr.sa.ss, in_my_addr.sa_socklen); idx = swrap_create_socket(&new_si, fd); if (idx == -1) { int saved_errno = errno; libc_close(fd); errno = saved_errno; return -1; } if (addr != NULL) { struct socket_info *si = swrap_get_socket_info(idx); SWRAP_LOCK_SI(si); swrap_pcap_dump_packet(si, addr, SWRAP_ACCEPT_SEND, NULL, 0); swrap_pcap_dump_packet(si, addr, SWRAP_ACCEPT_RECV, NULL, 0); swrap_pcap_dump_packet(si, addr, SWRAP_ACCEPT_ACK, NULL, 0); SWRAP_UNLOCK_SI(si); } return fd; } #ifdef HAVE_ACCEPT4 int accept4(int s, struct sockaddr *addr, socklen_t *addrlen, int flags) { return swrap_accept(s, addr, (socklen_t *)addrlen, flags); } #endif #ifdef HAVE_ACCEPT_PSOCKLEN_T int accept(int s, struct sockaddr *addr, Psocklen_t addrlen) #else int accept(int s, struct sockaddr *addr, socklen_t *addrlen) #endif { return swrap_accept(s, addr, (socklen_t *)addrlen, 0); } static int autobind_start_init; static int autobind_start; /* using sendto() or connect() on an unbound socket would give the recipient no way to reply, as unlike UDP and TCP, a unix domain socket can't auto-assign ephemeral port numbers, so we need to assign it here. Note: this might change the family from ipv6 to ipv4 */ static int swrap_auto_bind(int fd, struct socket_info *si, int family) { struct swrap_address un_addr = { .sa_socklen = sizeof(struct sockaddr_un), }; int i; char type; int ret; int port; char *swrap_dir = NULL; swrap_mutex_lock(&autobind_start_mutex); if (autobind_start_init != 1) { autobind_start_init = 1; autobind_start = getpid(); autobind_start %= 50000; autobind_start += 10000; } un_addr.sa.un.sun_family = AF_UNIX; switch (family) { case AF_INET: { struct sockaddr_in in; switch (si->type) { case SOCK_STREAM: type = SOCKET_TYPE_CHAR_TCP; break; case SOCK_DGRAM: type = SOCKET_TYPE_CHAR_UDP; break; default: errno = ESOCKTNOSUPPORT; ret = -1; goto done; } memset(&in, 0, sizeof(in)); in.sin_family = AF_INET; in.sin_addr.s_addr = htonl(swrap_ipv4_iface( socket_wrapper_default_iface())); si->myname = (struct swrap_address) { .sa_socklen = sizeof(in), }; memcpy(&si->myname.sa.in, &in, si->myname.sa_socklen); break; } #ifdef HAVE_IPV6 case AF_INET6: { struct sockaddr_in6 in6; if (si->family != family) { errno = ENETUNREACH; ret = -1; goto done; } switch (si->type) { case SOCK_STREAM: type = SOCKET_TYPE_CHAR_TCP_V6; break; case SOCK_DGRAM: type = SOCKET_TYPE_CHAR_UDP_V6; break; default: errno = ESOCKTNOSUPPORT; ret = -1; goto done; } memset(&in6, 0, sizeof(in6)); in6.sin6_family = AF_INET6; in6.sin6_addr = *swrap_ipv6(); in6.sin6_addr.s6_addr[15] = socket_wrapper_default_iface(); si->myname = (struct swrap_address) { .sa_socklen = sizeof(in6), }; memcpy(&si->myname.sa.in6, &in6, si->myname.sa_socklen); break; } #endif default: errno = ESOCKTNOSUPPORT; ret = -1; goto done; } if (autobind_start > 60000) { autobind_start = 10000; } swrap_dir = socket_wrapper_dir(); if (swrap_dir == NULL) { errno = EINVAL; ret = -1; goto done; } for (i = 0; i < SOCKET_MAX_SOCKETS; i++) { port = autobind_start + i; swrap_un_path(&un_addr.sa.un, swrap_dir, type, socket_wrapper_default_iface(), port); ret = libc_bind(fd, &un_addr.sa.s, un_addr.sa_socklen); if (ret == -1) { if (errno == EALREADY || errno == EADDRINUSE) { continue; } goto done; } si->un_addr = un_addr.sa.un; si->bound = 1; autobind_start = port + 1; break; } if (i == SOCKET_MAX_SOCKETS) { SWRAP_LOG(SWRAP_LOG_ERROR, "Too many open unix sockets (%u) for " "interface "SOCKET_FORMAT, SOCKET_MAX_SOCKETS, type, socket_wrapper_default_iface(), 0); errno = ENFILE; ret = -1; goto done; } si->family = family; set_port(si->family, port, &si->myname); ret = 0; done: SAFE_FREE(swrap_dir); swrap_mutex_unlock(&autobind_start_mutex); return ret; } /**************************************************************************** * CONNECT ***************************************************************************/ static int swrap_connect(int s, const struct sockaddr *serv_addr, socklen_t addrlen) { int ret; struct swrap_address un_addr = { .sa_socklen = sizeof(struct sockaddr_un), }; struct socket_info *si = find_socket_info(s); struct swrap_sockaddr_buf buf = {}; int bcast = 0; if (!si) { return libc_connect(s, serv_addr, addrlen); } SWRAP_LOCK_SI(si); if (si->bound == 0) { ret = swrap_auto_bind(s, si, serv_addr->sa_family); if (ret == -1) { goto done; } } if (si->family != serv_addr->sa_family) { SWRAP_LOG(SWRAP_LOG_ERROR, "called for fd=%d (family=%d) called with invalid family=%d", s, si->family, serv_addr->sa_family); errno = EINVAL; ret = -1; goto done; } ret = sockaddr_convert_to_un(si, serv_addr, addrlen, &un_addr.sa.un, 0, &bcast); if (ret == -1) { goto done; } if (bcast) { errno = ENETUNREACH; ret = -1; goto done; } if (si->type == SOCK_DGRAM) { si->defer_connect = 1; ret = 0; } else { swrap_pcap_dump_packet(si, serv_addr, SWRAP_CONNECT_SEND, NULL, 0); ret = libc_connect(s, &un_addr.sa.s, un_addr.sa_socklen); } SWRAP_LOG(SWRAP_LOG_TRACE, "connect(%s) path=%s, fd=%d", swrap_sockaddr_string(&buf, serv_addr), un_addr.sa.un.sun_path, s); /* to give better errors */ if (ret == -1 && errno == ENOENT) { errno = EHOSTUNREACH; } if (ret == 0) { si->peername = (struct swrap_address) { .sa_socklen = addrlen, }; memcpy(&si->peername.sa.ss, serv_addr, addrlen); si->connected = 1; /* * When we connect() on a socket than we have to bind the * outgoing connection on the interface we use for the * transport. We already bound it on the right interface * but here we have to update the name so getsockname() * returns correct information. */ if (si->bindname.sa_socklen > 0) { si->myname = (struct swrap_address) { .sa_socklen = si->bindname.sa_socklen, }; memcpy(&si->myname.sa.ss, &si->bindname.sa.ss, si->bindname.sa_socklen); /* Cleanup bindname */ si->bindname = (struct swrap_address) { .sa_socklen = 0, }; } swrap_pcap_dump_packet(si, serv_addr, SWRAP_CONNECT_RECV, NULL, 0); swrap_pcap_dump_packet(si, serv_addr, SWRAP_CONNECT_ACK, NULL, 0); } else { swrap_pcap_dump_packet(si, serv_addr, SWRAP_CONNECT_UNREACH, NULL, 0); } done: SWRAP_UNLOCK_SI(si); return ret; } int connect(int s, const struct sockaddr *serv_addr, socklen_t addrlen) { return swrap_connect(s, serv_addr, addrlen); } /**************************************************************************** * BIND ***************************************************************************/ static int swrap_bind(int s, const struct sockaddr *myaddr, socklen_t addrlen) { int ret; struct swrap_address un_addr = { .sa_socklen = sizeof(struct sockaddr_un), }; struct socket_info *si = find_socket_info(s); struct swrap_sockaddr_buf buf = {}; int ret_errno = errno; int bind_error = 0; #if 0 /* FIXME */ bool in_use; #endif if (!si) { return libc_bind(s, myaddr, addrlen); } SWRAP_LOCK_SI(si); switch (si->family) { case AF_INET: { const struct sockaddr_in *sin; if (addrlen < sizeof(struct sockaddr_in)) { bind_error = EINVAL; break; } sin = (const struct sockaddr_in *)(const void *)myaddr; if (sin->sin_family != AF_INET) { bind_error = EAFNOSUPPORT; } /* special case for AF_UNSPEC */ if (sin->sin_family == AF_UNSPEC && (sin->sin_addr.s_addr == htonl(INADDR_ANY))) { bind_error = 0; } break; } #ifdef HAVE_IPV6 case AF_INET6: { const struct sockaddr_in6 *sin6; if (addrlen < sizeof(struct sockaddr_in6)) { bind_error = EINVAL; break; } sin6 = (const struct sockaddr_in6 *)(const void *)myaddr; if (sin6->sin6_family != AF_INET6) { bind_error = EAFNOSUPPORT; } break; } #endif default: bind_error = EINVAL; break; } if (bind_error != 0) { ret_errno = bind_error; ret = -1; goto out; } #if 0 /* FIXME */ in_use = check_addr_port_in_use(myaddr, addrlen); if (in_use) { errno = EADDRINUSE; ret = -1; goto out; } #endif si->myname.sa_socklen = addrlen; memcpy(&si->myname.sa.ss, myaddr, addrlen); ret = sockaddr_convert_to_un(si, myaddr, addrlen, &un_addr.sa.un, 1, &si->bcast); if (ret == -1) { ret_errno = errno; goto out; } unlink(un_addr.sa.un.sun_path); ret = libc_bind(s, &un_addr.sa.s, un_addr.sa_socklen); if (ret == -1) { ret_errno = errno; } SWRAP_LOG(SWRAP_LOG_TRACE, "bind(%s) path=%s, fd=%d ret=%d ret_errno=%d", swrap_sockaddr_string(&buf, myaddr), un_addr.sa.un.sun_path, s, ret, ret_errno); if (ret == 0) { si->bound = 1; } out: SWRAP_UNLOCK_SI(si); errno = ret_errno; return ret; } int bind(int s, const struct sockaddr *myaddr, socklen_t addrlen) { return swrap_bind(s, myaddr, addrlen); } /**************************************************************************** * BINDRESVPORT ***************************************************************************/ #ifdef HAVE_BINDRESVPORT static int swrap_getsockname(int s, struct sockaddr *name, socklen_t *addrlen); static int swrap_bindresvport_sa(int sd, struct sockaddr *sa) { struct swrap_address myaddr = { .sa_socklen = sizeof(struct sockaddr_storage), }; socklen_t salen; static uint16_t port; uint16_t i; int rc = -1; int af; #define SWRAP_STARTPORT 600 #define SWRAP_ENDPORT (IPPORT_RESERVED - 1) #define SWRAP_NPORTS (SWRAP_ENDPORT - SWRAP_STARTPORT + 1) if (port == 0) { port = (getpid() % SWRAP_NPORTS) + SWRAP_STARTPORT; } if (sa == NULL) { salen = myaddr.sa_socklen; sa = &myaddr.sa.s; rc = swrap_getsockname(sd, &myaddr.sa.s, &salen); if (rc < 0) { return -1; } af = sa->sa_family; memset(&myaddr.sa.ss, 0, salen); } else { af = sa->sa_family; } for (i = 0; i < SWRAP_NPORTS; i++, port++) { switch(af) { case AF_INET: { struct sockaddr_in *sinp = (struct sockaddr_in *)(void *)sa; salen = sizeof(struct sockaddr_in); sinp->sin_port = htons(port); break; } case AF_INET6: { struct sockaddr_in6 *sin6p = (struct sockaddr_in6 *)(void *)sa; salen = sizeof(struct sockaddr_in6); sin6p->sin6_port = htons(port); break; } default: errno = EAFNOSUPPORT; return -1; } sa->sa_family = af; if (port > SWRAP_ENDPORT) { port = SWRAP_STARTPORT; } rc = swrap_bind(sd, (struct sockaddr *)sa, salen); if (rc == 0 || errno != EADDRINUSE) { break; } } return rc; } int bindresvport(int sockfd, struct sockaddr_in *sinp) { return swrap_bindresvport_sa(sockfd, (struct sockaddr *)sinp); } #endif /**************************************************************************** * LISTEN ***************************************************************************/ static int swrap_listen(int s, int backlog) { int ret; struct socket_info *si = find_socket_info(s); if (!si) { return libc_listen(s, backlog); } SWRAP_LOCK_SI(si); if (si->bound == 0) { ret = swrap_auto_bind(s, si, si->family); if (ret == -1) { errno = EADDRINUSE; goto out; } } ret = libc_listen(s, backlog); if (ret == 0) { si->listening = 1; } out: SWRAP_UNLOCK_SI(si); return ret; } int listen(int s, int backlog) { return swrap_listen(s, backlog); } /**************************************************************************** * FOPEN ***************************************************************************/ static FILE *swrap_fopen(const char *name, const char *mode) { FILE *fp; fp = libc_fopen(name, mode); if (fp != NULL) { int fd = fileno(fp); swrap_remove_stale(fd); } return fp; } #undef fopen /* Needed for LFS handling */ FILE *fopen(const char *name, const char *mode) { return swrap_fopen(name, mode); } /**************************************************************************** * FOPEN64 ***************************************************************************/ #ifdef HAVE_FOPEN64 static FILE *swrap_fopen64(const char *name, const char *mode) { FILE *fp; fp = libc_fopen64(name, mode); if (fp != NULL) { int fd = fileno(fp); swrap_remove_stale(fd); } return fp; } FILE *fopen64(const char *name, const char *mode) { return swrap_fopen64(name, mode); } #endif /* HAVE_FOPEN64 */ /**************************************************************************** * OPEN ***************************************************************************/ static int swrap_vopen(const char *pathname, int flags, va_list ap) { int ret; ret = libc_vopen(pathname, flags, ap); if (ret != -1) { /* * There are methods for closing descriptors (libc-internal code * paths, direct syscalls) which close descriptors in ways that * we can't intercept, so try to recover when we notice that * that's happened */ swrap_remove_stale(ret); } return ret; } #undef open /* Needed for LFS handling */ int open(const char *pathname, int flags, ...) { va_list ap; int fd; va_start(ap, flags); fd = swrap_vopen(pathname, flags, ap); va_end(ap); return fd; } /**************************************************************************** * OPEN64 ***************************************************************************/ #ifdef HAVE_OPEN64 static int swrap_vopen64(const char *pathname, int flags, va_list ap) { int ret; ret = libc_vopen64(pathname, flags, ap); if (ret != -1) { /* * There are methods for closing descriptors (libc-internal code * paths, direct syscalls) which close descriptors in ways that * we can't intercept, so try to recover when we notice that * that's happened */ swrap_remove_stale(ret); } return ret; } int open64(const char *pathname, int flags, ...) { va_list ap; int fd; va_start(ap, flags); fd = swrap_vopen64(pathname, flags, ap); va_end(ap); return fd; } #endif /* HAVE_OPEN64 */ /**************************************************************************** * OPENAT64 ***************************************************************************/ #ifdef HAVE_OPENAT64 static int swrap_vopenat64(int dirfd, const char *pathname, int flags, va_list ap) { int ret; ret = libc_vopenat64(dirfd, 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 openat64(int dirfd, const char *pathname, int flags, ...) { va_list ap; int fd; va_start(ap, flags); fd = swrap_vopenat64(dirfd, pathname, flags, ap); va_end(ap); return fd; } #endif /* HAVE_OPENAT64 */ /**************************************************************************** * OPENAT ***************************************************************************/ static int swrap_vopenat(int dirfd, const char *path, int flags, va_list ap) { int ret; ret = libc_vopenat(dirfd, path, flags, ap); if (ret != -1) { /* * There are methods for closing descriptors (libc-internal code * paths, direct syscalls) which close descriptors in ways that * we can't intercept, so try to recover when we notice that * that's happened */ swrap_remove_stale(ret); } return ret; } #undef openat /* Needed for LFS handling */ int openat(int dirfd, const char *path, int flags, ...) { va_list ap; int fd; va_start(ap, flags); fd = swrap_vopenat(dirfd, path, flags, ap); va_end(ap); return fd; } /**************************************************************************** * GETPEERNAME ***************************************************************************/ static int swrap_getpeername(int s, struct sockaddr *name, socklen_t *addrlen) { struct socket_info *si = find_socket_info(s); socklen_t len; int ret = -1; if (!si) { return libc_getpeername(s, name, addrlen); } SWRAP_LOCK_SI(si); if (si->peername.sa_socklen == 0) { errno = ENOTCONN; goto out; } len = MIN(*addrlen, si->peername.sa_socklen); if (len == 0) { ret = 0; goto out; } memcpy(name, &si->peername.sa.ss, len); *addrlen = si->peername.sa_socklen; ret = 0; out: SWRAP_UNLOCK_SI(si); return ret; } #ifdef HAVE_ACCEPT_PSOCKLEN_T int getpeername(int s, struct sockaddr *name, Psocklen_t addrlen) #else int getpeername(int s, struct sockaddr *name, socklen_t *addrlen) #endif { return swrap_getpeername(s, name, (socklen_t *)addrlen); } /**************************************************************************** * GETSOCKNAME ***************************************************************************/ static int swrap_getsockname(int s, struct sockaddr *name, socklen_t *addrlen) { struct socket_info *si = find_socket_info(s); socklen_t len; int ret = -1; if (!si) { return libc_getsockname(s, name, addrlen); } SWRAP_LOCK_SI(si); len = MIN(*addrlen, si->myname.sa_socklen); if (len == 0) { ret = 0; goto out; } memcpy(name, &si->myname.sa.ss, len); *addrlen = si->myname.sa_socklen; ret = 0; out: SWRAP_UNLOCK_SI(si); return ret; } #ifdef HAVE_ACCEPT_PSOCKLEN_T int getsockname(int s, struct sockaddr *name, Psocklen_t addrlen) #else int getsockname(int s, struct sockaddr *name, socklen_t *addrlen) #endif { return swrap_getsockname(s, name, (socklen_t *)addrlen); } /**************************************************************************** * GETSOCKOPT ***************************************************************************/ #ifndef SO_PROTOCOL # ifdef SO_PROTOTYPE /* The Solaris name */ # define SO_PROTOCOL SO_PROTOTYPE # endif /* SO_PROTOTYPE */ #endif /* SO_PROTOCOL */ static int swrap_getsockopt(int s, int level, int optname, void *optval, socklen_t *optlen) { struct socket_info *si = find_socket_info(s); int ret; if (!si) { return libc_getsockopt(s, level, optname, optval, optlen); } SWRAP_LOCK_SI(si); if (level == SOL_SOCKET) { switch (optname) { #ifdef SO_DOMAIN case SO_DOMAIN: if (optval == NULL || optlen == NULL || *optlen < (socklen_t)sizeof(int)) { errno = EINVAL; ret = -1; goto done; } *optlen = sizeof(int); *(int *)optval = si->family; ret = 0; goto done; #endif /* SO_DOMAIN */ #ifdef SO_PROTOCOL case SO_PROTOCOL: if (optval == NULL || optlen == NULL || *optlen < (socklen_t)sizeof(int)) { errno = EINVAL; ret = -1; goto done; } *optlen = sizeof(int); *(int *)optval = si->protocol; ret = 0; goto done; #endif /* SO_PROTOCOL */ case SO_TYPE: if (optval == NULL || optlen == NULL || *optlen < (socklen_t)sizeof(int)) { errno = EINVAL; ret = -1; goto done; } *optlen = sizeof(int); *(int *)optval = si->type; ret = 0; goto done; default: ret = libc_getsockopt(s, level, optname, optval, optlen); goto done; } } else if (level == IPPROTO_TCP) { switch (optname) { #ifdef TCP_NODELAY case TCP_NODELAY: /* * This enables sending packets directly out over TCP. * As a unix socket is doing that any way, report it as * enabled. */ if (optval == NULL || optlen == NULL || *optlen < (socklen_t)sizeof(int)) { errno = EINVAL; ret = -1; goto done; } *optlen = sizeof(int); *(int *)optval = si->tcp_nodelay; ret = 0; goto done; #endif /* TCP_NODELAY */ #ifdef TCP_INFO case TCP_INFO: { struct tcp_info info; socklen_t ilen = sizeof(info); #ifdef HAVE_NETINET_TCP_FSM_H /* This is FreeBSD */ # define __TCP_LISTEN TCPS_LISTEN # define __TCP_ESTABLISHED TCPS_ESTABLISHED # define __TCP_CLOSE TCPS_CLOSED #else /* This is Linux */ # define __TCP_LISTEN TCP_LISTEN # define __TCP_ESTABLISHED TCP_ESTABLISHED # define __TCP_CLOSE TCP_CLOSE #endif ZERO_STRUCT(info); if (si->listening) { info.tcpi_state = __TCP_LISTEN; } else if (si->connected) { /* * For now we just fake a few values * supported both by FreeBSD and Linux */ info.tcpi_state = __TCP_ESTABLISHED; info.tcpi_rto = 200000; /* 200 msec */ info.tcpi_rtt = 5000; /* 5 msec */ info.tcpi_rttvar = 5000; /* 5 msec */ } else { info.tcpi_state = __TCP_CLOSE; info.tcpi_rto = 1000000; /* 1 sec */ info.tcpi_rtt = 0; info.tcpi_rttvar = 250000; /* 250 msec */ } if (optval == NULL || optlen == NULL || *optlen < (socklen_t)ilen) { errno = EINVAL; ret = -1; goto done; } *optlen = ilen; memcpy(optval, &info, ilen); ret = 0; goto done; } #endif /* TCP_INFO */ default: break; } } errno = ENOPROTOOPT; ret = -1; done: SWRAP_UNLOCK_SI(si); return ret; } #ifdef HAVE_ACCEPT_PSOCKLEN_T int getsockopt(int s, int level, int optname, void *optval, Psocklen_t optlen) #else int getsockopt(int s, int level, int optname, void *optval, socklen_t *optlen) #endif { return swrap_getsockopt(s, level, optname, optval, (socklen_t *)optlen); } /**************************************************************************** * SETSOCKOPT ***************************************************************************/ static int swrap_setsockopt(int s, int level, int optname, const void *optval, socklen_t optlen) { struct socket_info *si = find_socket_info(s); int ret; if (!si) { return libc_setsockopt(s, level, optname, optval, optlen); } if (level == SOL_SOCKET) { /* * SO_REUSEPORT is not supported on a unix socket. glibc 2.40 * returns ENOTSUPP now. */ if (optname == SO_REUSEPORT) { return 0; } return libc_setsockopt(s, level, optname, optval, optlen); } SWRAP_LOCK_SI(si); if (level == IPPROTO_TCP) { switch (optname) { #ifdef TCP_NODELAY case TCP_NODELAY: { int i; /* * This enables sending packets directly out over TCP. * A unix socket is doing that any way. */ if (optval == NULL || optlen == 0 || optlen < (socklen_t)sizeof(int)) { errno = EINVAL; ret = -1; goto done; } i = *discard_const_p(int, optval); if (i != 0 && i != 1) { errno = EINVAL; ret = -1; goto done; } si->tcp_nodelay = i; ret = 0; goto done; } #endif /* TCP_NODELAY */ default: break; } } switch (si->family) { case AF_INET: if (level == IPPROTO_IP) { #ifdef IP_PKTINFO if (optname == IP_PKTINFO) { si->pktinfo = AF_INET; } #endif /* IP_PKTINFO */ } ret = 0; goto done; #ifdef HAVE_IPV6 case AF_INET6: if (level == IPPROTO_IPV6) { #ifdef IPV6_RECVPKTINFO if (optname == IPV6_RECVPKTINFO) { si->pktinfo = AF_INET6; } #endif /* IPV6_PKTINFO */ } ret = 0; goto done; #endif default: errno = ENOPROTOOPT; ret = -1; goto done; } done: SWRAP_UNLOCK_SI(si); return ret; } int setsockopt(int s, int level, int optname, const void *optval, socklen_t optlen) { return swrap_setsockopt(s, level, optname, optval, optlen); } /**************************************************************************** * IOCTL ***************************************************************************/ static int swrap_vioctl(int s, unsigned long int r, va_list va) { struct socket_info *si = find_socket_info(s); va_list ap; int *value_ptr = NULL; int rc; if (!si) { return libc_vioctl(s, r, va); } SWRAP_LOCK_SI(si); va_copy(ap, va); rc = libc_vioctl(s, r, va); switch (r) { case FIONREAD: if (rc == 0) { value_ptr = ((int *)va_arg(ap, int *)); } if (rc == -1 && errno != EAGAIN && errno != ENOBUFS) { swrap_pcap_dump_packet(si, NULL, SWRAP_PENDING_RST, NULL, 0); } else if (value_ptr != NULL && *value_ptr == 0) { /* END OF FILE */ swrap_pcap_dump_packet(si, NULL, SWRAP_PENDING_RST, NULL, 0); } break; #ifdef FIONWRITE case FIONWRITE: /* this is FreeBSD */ FALL_THROUGH; /* to TIOCOUTQ */ #endif /* FIONWRITE */ case TIOCOUTQ: /* same as SIOCOUTQ on Linux */ /* * This may return more bytes then the application * sent into the socket, for tcp it should * return the number of unacked bytes. * * On AF_UNIX, all bytes are immediately acked! */ if (rc == 0) { value_ptr = ((int *)va_arg(ap, int *)); *value_ptr = 0; } break; } va_end(ap); SWRAP_UNLOCK_SI(si); return rc; } #ifdef HAVE_IOCTL_INT int ioctl(int s, int r, ...) #else int ioctl(int s, unsigned long int r, ...) #endif { va_list va; int rc; va_start(va, r); rc = swrap_vioctl(s, (unsigned long int) r, va); va_end(va); return rc; } /***************** * CMSG *****************/ #ifdef HAVE_STRUCT_MSGHDR_MSG_CONTROL #ifndef CMSG_ALIGN # ifdef _ALIGN /* BSD */ #define CMSG_ALIGN _ALIGN # else #define CMSG_ALIGN(len) (((len) + sizeof(size_t) - 1) & ~(sizeof(size_t) - 1)) # endif /* _ALIGN */ #endif /* CMSG_ALIGN */ /** * @brief Add a cmsghdr to a msghdr. * * This is an function to add any type of cmsghdr. It will operate on the * msg->msg_control and msg->msg_controllen you pass in by adapting them to * the buffer position after the added cmsg element. Hence, this function is * intended to be used with an intermediate msghdr and not on the original * one handed in by the client. * * @param[in] msg The msghdr to which to add the cmsg. * * @param[in] level The cmsg level to set. * * @param[in] type The cmsg type to set. * * @param[in] data The cmsg data to set. * * @param[in] len the length of the data to set. */ static void swrap_msghdr_add_cmsghdr(struct msghdr *msg, int level, int type, const void *data, size_t len) { size_t cmlen = CMSG_LEN(len); size_t cmspace = CMSG_SPACE(len); uint8_t cmbuf[cmspace]; void *cast_ptr = (void *)cmbuf; struct cmsghdr *cm = (struct cmsghdr *)cast_ptr; uint8_t *p; memset(cmbuf, 0, cmspace); if (msg->msg_controllen < cmlen) { cmlen = msg->msg_controllen; msg->msg_flags |= MSG_CTRUNC; } if (msg->msg_controllen < cmspace) { cmspace = msg->msg_controllen; } /* * We copy the full input data into an intermediate cmsghdr first * in order to more easily cope with truncation. */ cm->cmsg_len = cmlen; cm->cmsg_level = level; cm->cmsg_type = type; memcpy(CMSG_DATA(cm), data, len); /* * We now copy the possibly truncated buffer. * We copy cmlen bytes, but consume cmspace bytes, * leaving the possible padding uninitialiazed. */ p = (uint8_t *)msg->msg_control; memcpy(p, cm, cmlen); p += cmspace; msg->msg_control = p; msg->msg_controllen -= cmspace; return; } static int swrap_msghdr_add_pktinfo(struct socket_info *si, struct msghdr *msg) { /* Add packet info */ switch (si->pktinfo) { #if defined(IP_PKTINFO) && (defined(HAVE_STRUCT_IN_PKTINFO) || defined(IP_RECVDSTADDR)) case AF_INET: { struct sockaddr_in *sin; #if defined(HAVE_STRUCT_IN_PKTINFO) struct in_pktinfo pkt; #elif defined(IP_RECVDSTADDR) struct in_addr pkt; #endif if (si->bindname.sa_socklen == sizeof(struct sockaddr_in)) { sin = &si->bindname.sa.in; } else { if (si->myname.sa_socklen != sizeof(struct sockaddr_in)) { return 0; } sin = &si->myname.sa.in; } ZERO_STRUCT(pkt); #if defined(HAVE_STRUCT_IN_PKTINFO) pkt.ipi_ifindex = socket_wrapper_default_iface(); pkt.ipi_addr.s_addr = sin->sin_addr.s_addr; #elif defined(IP_RECVDSTADDR) pkt = sin->sin_addr; #endif swrap_msghdr_add_cmsghdr(msg, IPPROTO_IP, IP_PKTINFO, &pkt, sizeof(pkt)); break; } #endif /* IP_PKTINFO */ #if defined(HAVE_IPV6) case AF_INET6: { #if defined(IPV6_PKTINFO) && defined(HAVE_STRUCT_IN6_PKTINFO) struct sockaddr_in6 *sin6; struct in6_pktinfo pkt6; if (si->bindname.sa_socklen == sizeof(struct sockaddr_in6)) { sin6 = &si->bindname.sa.in6; } else { if (si->myname.sa_socklen != sizeof(struct sockaddr_in6)) { return 0; } sin6 = &si->myname.sa.in6; } ZERO_STRUCT(pkt6); pkt6.ipi6_ifindex = socket_wrapper_default_iface(); pkt6.ipi6_addr = sin6->sin6_addr; swrap_msghdr_add_cmsghdr(msg, IPPROTO_IPV6, IPV6_PKTINFO, &pkt6, sizeof(pkt6)); #endif /* HAVE_STRUCT_IN6_PKTINFO */ break; } #endif /* IPV6_PKTINFO */ default: return -1; } return 0; } static int swrap_msghdr_add_socket_info(struct socket_info *si, struct msghdr *omsg) { int rc = 0; if (si->pktinfo > 0) { rc = swrap_msghdr_add_pktinfo(si, omsg); } return rc; } static int swrap_sendmsg_copy_cmsg(const struct cmsghdr *cmsg, uint8_t **cm_data, size_t *cm_data_space); static int swrap_sendmsg_filter_cmsg_ipproto_ip(const struct cmsghdr *cmsg, uint8_t **cm_data, size_t *cm_data_space); static int swrap_sendmsg_filter_cmsg_sol_socket(const struct cmsghdr *cmsg, uint8_t **cm_data, size_t *cm_data_space); static int swrap_sendmsg_filter_cmsghdr(const struct msghdr *_msg, uint8_t **cm_data, size_t *cm_data_space) { struct msghdr *msg = discard_const_p(struct msghdr, _msg); 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_ipproto_ip(cmsg, cm_data, cm_data_space); break; case SOL_SOCKET: rc = swrap_sendmsg_filter_cmsg_sol_socket(cmsg, cm_data, cm_data_space); break; default: rc = swrap_sendmsg_copy_cmsg(cmsg, cm_data, cm_data_space); break; } if (rc < 0) { int saved_errno = errno; SAFE_FREE(*cm_data); *cm_data_space = 0; errno = saved_errno; return rc; } } return rc; } static int swrap_sendmsg_copy_cmsg(const 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(const struct cmsghdr *cmsg, uint8_t **cm_data, size_t *cm_data_space); static int swrap_sendmsg_filter_cmsg_ipproto_ip(const 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(const 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; } static int swrap_sendmsg_filter_cmsg_sol_socket(const struct cmsghdr *cmsg, uint8_t **cm_data, size_t *cm_data_space) { int rc = -1; switch (cmsg->cmsg_type) { case SCM_RIGHTS: SWRAP_LOG(SWRAP_LOG_TRACE, "Ignoring SCM_RIGHTS on inet socket!"); rc = 0; break; #ifdef SCM_CREDENTIALS case SCM_CREDENTIALS: SWRAP_LOG(SWRAP_LOG_TRACE, "Ignoring SCM_CREDENTIALS on inet socket!"); rc = 0; break; #endif /* SCM_CREDENTIALS */ default: rc = swrap_sendmsg_copy_cmsg(cmsg, cm_data, cm_data_space); break; } return rc; } static const uint64_t swrap_unix_scm_right_magic = 0x8e0e13f27c42fc36; /* * We only allow up to 6 fds at a time * as that's more than enough for Samba * and it means we can keep the logic simple * and work with fixed size arrays. * * We also keep sizeof(struct swrap_unix_scm_rights) * under PIPE_BUF (4096) in order to allow a non-blocking * write into the pipe. */ #ifndef PIPE_BUF #define PIPE_BUF 4096 #endif #define SWRAP_MAX_PASSED_FDS ((size_t)6) #define SWRAP_MAX_PASSED_SOCKET_INFO SWRAP_MAX_PASSED_FDS struct swrap_unix_scm_rights_payload { uint8_t num_idxs; int8_t idxs[SWRAP_MAX_PASSED_FDS]; struct socket_info infos[SWRAP_MAX_PASSED_SOCKET_INFO]; }; struct swrap_unix_scm_rights { uint64_t magic; char package_name[sizeof(SOCKET_WRAPPER_PACKAGE)]; char package_version[sizeof(SOCKET_WRAPPER_VERSION)]; uint32_t full_size; uint32_t payload_size; struct swrap_unix_scm_rights_payload payload; }; static void swrap_dec_fd_passed_array(size_t num, struct socket_info **array) { int saved_errno = errno; size_t i; for (i = 0; i < num; i++) { struct socket_info *si = array[i]; if (si == NULL) { continue; } SWRAP_LOCK_SI(si); swrap_dec_refcount(si); if (si->fd_passed > 0) { si->fd_passed -= 1; } SWRAP_UNLOCK_SI(si); array[i] = NULL; } errno = saved_errno; } static void swrap_undo_si_idx_array(size_t num, int *array) { int saved_errno = errno; size_t i; swrap_mutex_lock(&first_free_mutex); for (i = 0; i < num; i++) { struct socket_info *si = NULL; if (array[i] == -1) { continue; } si = swrap_get_socket_info(array[i]); if (si == NULL) { continue; } SWRAP_LOCK_SI(si); swrap_dec_refcount(si); SWRAP_UNLOCK_SI(si); swrap_set_next_free(si, first_free); first_free = array[i]; array[i] = -1; } swrap_mutex_unlock(&first_free_mutex); errno = saved_errno; } static void swrap_close_fd_array(size_t num, const int *array) { int saved_errno = errno; size_t i; for (i = 0; i < num; i++) { if (array[i] == -1) { continue; } libc_close(array[i]); } errno = saved_errno; } union __swrap_fds { const uint8_t *p; int *fds; }; union __swrap_cmsghdr { const uint8_t *p; struct cmsghdr *cmsg; }; static int swrap_sendmsg_unix_scm_rights(struct cmsghdr *cmsg, uint8_t **cm_data, size_t *cm_data_space, int *scm_rights_pipe_fd) { struct swrap_unix_scm_rights info; struct swrap_unix_scm_rights_payload *payload = NULL; int si_idx_array[SWRAP_MAX_PASSED_FDS]; struct socket_info *si_array[SWRAP_MAX_PASSED_FDS] = { NULL, }; size_t info_idx = 0; size_t size_fds_in; size_t num_fds_in; union __swrap_fds __fds_in = { .p = NULL, }; const int *fds_in = NULL; size_t num_fds_out; size_t size_fds_out; union __swrap_fds __fds_out = { .p = NULL, }; int *fds_out = NULL; size_t cmsg_len; size_t cmsg_space; size_t new_cm_data_space; union __swrap_cmsghdr __new_cmsg = { .p = NULL, }; struct cmsghdr *new_cmsg = NULL; uint8_t *p = NULL; size_t i; int pipefd[2] = { -1, -1 }; int rc; ssize_t sret; /* * We pass this a buffer to the kernel make sure any padding * is also cleared. */ ZERO_STRUCT(info); info.magic = swrap_unix_scm_right_magic; memcpy(info.package_name, SOCKET_WRAPPER_PACKAGE, sizeof(info.package_name)); memcpy(info.package_version, SOCKET_WRAPPER_VERSION, sizeof(info.package_version)); info.full_size = sizeof(info); info.payload_size = sizeof(info.payload); payload = &info.payload; if (*scm_rights_pipe_fd != -1) { SWRAP_LOG(SWRAP_LOG_ERROR, "Two SCM_RIGHTS headers are not supported by socket_wrapper"); errno = EINVAL; return -1; } if (cmsg->cmsg_len < CMSG_LEN(0)) { SWRAP_LOG(SWRAP_LOG_ERROR, "cmsg->cmsg_len=%zu < CMSG_LEN(0)=%zu", (size_t)cmsg->cmsg_len, CMSG_LEN(0)); errno = EINVAL; return -1; } size_fds_in = cmsg->cmsg_len - CMSG_LEN(0); if ((size_fds_in % sizeof(int)) != 0) { SWRAP_LOG(SWRAP_LOG_ERROR, "cmsg->cmsg_len=%zu => (size_fds_in=%zu %% sizeof(int)=%zu) != 0", (size_t)cmsg->cmsg_len, size_fds_in, sizeof(int)); errno = EINVAL; return -1; } num_fds_in = size_fds_in / sizeof(int); if (num_fds_in > SWRAP_MAX_PASSED_FDS) { SWRAP_LOG(SWRAP_LOG_ERROR, "cmsg->cmsg_len=%zu,size_fds_in=%zu => " "num_fds_in=%zu > " "SWRAP_MAX_PASSED_FDS(%zu)", (size_t)cmsg->cmsg_len, size_fds_in, num_fds_in, SWRAP_MAX_PASSED_FDS); errno = EINVAL; return -1; } if (num_fds_in == 0) { SWRAP_LOG(SWRAP_LOG_ERROR, "cmsg->cmsg_len=%zu,size_fds_in=%zu => " "num_fds_in=%zu", (size_t)cmsg->cmsg_len, size_fds_in, num_fds_in); errno = EINVAL; return -1; } __fds_in.p = CMSG_DATA(cmsg); fds_in = __fds_in.fds; num_fds_out = num_fds_in + 1; SWRAP_LOG(SWRAP_LOG_TRACE, "num_fds_in=%zu num_fds_out=%zu", num_fds_in, num_fds_out); size_fds_out = sizeof(int) * num_fds_out; cmsg_len = CMSG_LEN(size_fds_out); cmsg_space = CMSG_SPACE(size_fds_out); new_cm_data_space = *cm_data_space + cmsg_space; p = realloc((*cm_data), new_cm_data_space); if (p == NULL) { return -1; } (*cm_data) = p; p = (*cm_data) + (*cm_data_space); memset(p, 0, cmsg_space); __new_cmsg.p = p; new_cmsg = __new_cmsg.cmsg; *new_cmsg = *cmsg; __fds_out.p = CMSG_DATA(new_cmsg); fds_out = __fds_out.fds; memcpy(fds_out, fds_in, size_fds_in); new_cmsg->cmsg_len = cmsg->cmsg_len; for (i = 0; i < num_fds_in; i++) { size_t j; payload->idxs[i] = -1; payload->num_idxs++; si_idx_array[i] = find_socket_info_index(fds_in[i]); if (si_idx_array[i] == -1) { continue; } si_array[i] = swrap_get_socket_info(si_idx_array[i]); if (si_array[i] == NULL) { SWRAP_LOG(SWRAP_LOG_ERROR, "fds_in[%zu]=%d si_idx_array[%zu]=%d missing!", i, fds_in[i], i, si_idx_array[i]); errno = EINVAL; return -1; } for (j = 0; j < i; j++) { if (si_array[j] == si_array[i]) { payload->idxs[i] = payload->idxs[j]; break; } } if (payload->idxs[i] == -1) { if (info_idx >= SWRAP_MAX_PASSED_SOCKET_INFO) { SWRAP_LOG(SWRAP_LOG_ERROR, "fds_in[%zu]=%d,si_idx_array[%zu]=%d: " "info_idx=%zu >= SWRAP_MAX_PASSED_FDS(%zu)!", i, fds_in[i], i, si_idx_array[i], info_idx, SWRAP_MAX_PASSED_SOCKET_INFO); errno = EINVAL; return -1; } payload->idxs[i] = info_idx; info_idx += 1; continue; } } for (i = 0; i < num_fds_in; i++) { struct socket_info *si = si_array[i]; if (si == NULL) { SWRAP_LOG(SWRAP_LOG_TRACE, "fds_in[%zu]=%d not an inet socket", i, fds_in[i]); continue; } SWRAP_LOG(SWRAP_LOG_TRACE, "fds_in[%zu]=%d si_idx_array[%zu]=%d " "passing as info.idxs[%zu]=%d!", i, fds_in[i], i, si_idx_array[i], i, payload->idxs[i]); SWRAP_LOCK_SI(si); si->fd_passed += 1; payload->infos[payload->idxs[i]] = *si; payload->infos[payload->idxs[i]].fd_passed = 0; SWRAP_UNLOCK_SI(si); } rc = pipe(pipefd); if (rc == -1) { int saved_errno = errno; SWRAP_LOG(SWRAP_LOG_ERROR, "pipe() failed - %d %s", saved_errno, strerror(saved_errno)); swrap_dec_fd_passed_array(num_fds_in, si_array); errno = saved_errno; return -1; } sret = libc_write(pipefd[1], &info, sizeof(info)); if (sret != sizeof(info)) { int saved_errno = errno; if (sret != -1) { saved_errno = EINVAL; } SWRAP_LOG(SWRAP_LOG_ERROR, "write() failed - sret=%zd - %d %s", sret, saved_errno, strerror(saved_errno)); swrap_dec_fd_passed_array(num_fds_in, si_array); libc_close(pipefd[1]); libc_close(pipefd[0]); errno = saved_errno; return -1; } libc_close(pipefd[1]); /* * Add the pipe read end to the end of the passed fd array */ fds_out[num_fds_in] = pipefd[0]; new_cmsg->cmsg_len = cmsg_len; /* we're done ... */ *scm_rights_pipe_fd = pipefd[0]; *cm_data_space = new_cm_data_space; return 0; } static int swrap_sendmsg_unix_sol_socket(struct cmsghdr *cmsg, uint8_t **cm_data, size_t *cm_data_space, int *scm_rights_pipe_fd) { int rc = -1; switch (cmsg->cmsg_type) { case SCM_RIGHTS: rc = swrap_sendmsg_unix_scm_rights(cmsg, cm_data, cm_data_space, scm_rights_pipe_fd); break; default: rc = swrap_sendmsg_copy_cmsg(cmsg, cm_data, cm_data_space); break; } return rc; } static int swrap_recvmsg_unix_scm_rights(struct cmsghdr *cmsg, uint8_t **cm_data, size_t *cm_data_space) { int scm_rights_pipe_fd = -1; struct swrap_unix_scm_rights info; struct swrap_unix_scm_rights_payload *payload = NULL; int si_idx_array[SWRAP_MAX_PASSED_FDS]; size_t size_fds_in; size_t num_fds_in; union __swrap_fds __fds_in = { .p = NULL, }; const int *fds_in = NULL; size_t num_fds_out; size_t size_fds_out; union __swrap_fds __fds_out = { .p = NULL, }; int *fds_out = NULL; size_t cmsg_len; size_t cmsg_space; size_t new_cm_data_space; union __swrap_cmsghdr __new_cmsg = { .p = NULL, }; struct cmsghdr *new_cmsg = NULL; uint8_t *p = NULL; ssize_t sret; size_t i; int cmp; if (cmsg->cmsg_len < CMSG_LEN(0)) { SWRAP_LOG(SWRAP_LOG_ERROR, "cmsg->cmsg_len=%zu < CMSG_LEN(0)=%zu", (size_t)cmsg->cmsg_len, CMSG_LEN(0)); errno = EINVAL; return -1; } size_fds_in = cmsg->cmsg_len - CMSG_LEN(0); if ((size_fds_in % sizeof(int)) != 0) { SWRAP_LOG(SWRAP_LOG_ERROR, "cmsg->cmsg_len=%zu => (size_fds_in=%zu %% sizeof(int)=%zu) != 0", (size_t)cmsg->cmsg_len, size_fds_in, sizeof(int)); errno = EINVAL; return -1; } num_fds_in = size_fds_in / sizeof(int); if (num_fds_in > (SWRAP_MAX_PASSED_FDS + 1)) { SWRAP_LOG(SWRAP_LOG_ERROR, "cmsg->cmsg_len=%zu,size_fds_in=%zu => " "num_fds_in=%zu > SWRAP_MAX_PASSED_FDS+1(%zu)", (size_t)cmsg->cmsg_len, size_fds_in, num_fds_in, SWRAP_MAX_PASSED_FDS+1); errno = EINVAL; return -1; } if (num_fds_in <= 1) { SWRAP_LOG(SWRAP_LOG_ERROR, "cmsg->cmsg_len=%zu,size_fds_in=%zu => " "num_fds_in=%zu", (size_t)cmsg->cmsg_len, size_fds_in, num_fds_in); errno = EINVAL; return -1; } __fds_in.p = CMSG_DATA(cmsg); fds_in = __fds_in.fds; num_fds_out = num_fds_in - 1; SWRAP_LOG(SWRAP_LOG_TRACE, "num_fds_in=%zu num_fds_out=%zu", num_fds_in, num_fds_out); for (i = 0; i < num_fds_in; i++) { /* Check if we have a stale fd and remove it */ swrap_remove_stale(fds_in[i]); } scm_rights_pipe_fd = fds_in[num_fds_out]; size_fds_out = sizeof(int) * num_fds_out; cmsg_len = CMSG_LEN(size_fds_out); cmsg_space = CMSG_SPACE(size_fds_out); new_cm_data_space = *cm_data_space + cmsg_space; p = realloc((*cm_data), new_cm_data_space); if (p == NULL) { swrap_close_fd_array(num_fds_in, fds_in); return -1; } (*cm_data) = p; p = (*cm_data) + (*cm_data_space); memset(p, 0, cmsg_space); __new_cmsg.p = p; new_cmsg = __new_cmsg.cmsg; *new_cmsg = *cmsg; __fds_out.p = CMSG_DATA(new_cmsg); fds_out = __fds_out.fds; memcpy(fds_out, fds_in, size_fds_out); new_cmsg->cmsg_len = cmsg_len; sret = read(scm_rights_pipe_fd, &info, sizeof(info)); if (sret != sizeof(info)) { int saved_errno = errno; if (sret != -1) { saved_errno = EINVAL; } SWRAP_LOG(SWRAP_LOG_ERROR, "read() failed - sret=%zd - %d %s", sret, saved_errno, strerror(saved_errno)); swrap_close_fd_array(num_fds_in, fds_in); errno = saved_errno; return -1; } libc_close(scm_rights_pipe_fd); payload = &info.payload; if (info.magic != swrap_unix_scm_right_magic) { SWRAP_LOG(SWRAP_LOG_ERROR, "info.magic=0x%llx != swrap_unix_scm_right_magic=0x%llx", (unsigned long long)info.magic, (unsigned long long)swrap_unix_scm_right_magic); swrap_close_fd_array(num_fds_out, fds_out); errno = EINVAL; return -1; } cmp = memcmp(info.package_name, SOCKET_WRAPPER_PACKAGE, sizeof(info.package_name)); if (cmp != 0) { SWRAP_LOG(SWRAP_LOG_ERROR, "info.package_name='%.*s' != '%s'", (int)sizeof(info.package_name), info.package_name, SOCKET_WRAPPER_PACKAGE); swrap_close_fd_array(num_fds_out, fds_out); errno = EINVAL; return -1; } cmp = memcmp(info.package_version, SOCKET_WRAPPER_VERSION, sizeof(info.package_version)); if (cmp != 0) { SWRAP_LOG(SWRAP_LOG_ERROR, "info.package_version='%.*s' != '%s'", (int)sizeof(info.package_version), info.package_version, SOCKET_WRAPPER_VERSION); swrap_close_fd_array(num_fds_out, fds_out); errno = EINVAL; return -1; } if (info.full_size != sizeof(info)) { SWRAP_LOG(SWRAP_LOG_ERROR, "info.full_size=%zu != sizeof(info)=%zu", (size_t)info.full_size, sizeof(info)); swrap_close_fd_array(num_fds_out, fds_out); errno = EINVAL; return -1; } if (info.payload_size != sizeof(info.payload)) { SWRAP_LOG(SWRAP_LOG_ERROR, "info.payload_size=%zu != sizeof(info.payload)=%zu", (size_t)info.payload_size, sizeof(info.payload)); swrap_close_fd_array(num_fds_out, fds_out); errno = EINVAL; return -1; } if (payload->num_idxs != num_fds_out) { SWRAP_LOG(SWRAP_LOG_ERROR, "info.num_idxs=%u != num_fds_out=%zu", payload->num_idxs, num_fds_out); swrap_close_fd_array(num_fds_out, fds_out); errno = EINVAL; return -1; } for (i = 0; i < num_fds_out; i++) { size_t j; si_idx_array[i] = -1; if (payload->idxs[i] == -1) { SWRAP_LOG(SWRAP_LOG_TRACE, "fds_out[%zu]=%d not an inet socket", i, fds_out[i]); continue; } if (payload->idxs[i] < 0) { SWRAP_LOG(SWRAP_LOG_ERROR, "fds_out[%zu]=%d info.idxs[%zu]=%d < 0!", i, fds_out[i], i, payload->idxs[i]); swrap_close_fd_array(num_fds_out, fds_out); errno = EINVAL; return -1; } if (payload->idxs[i] >= payload->num_idxs) { SWRAP_LOG(SWRAP_LOG_ERROR, "fds_out[%zu]=%d info.idxs[%zu]=%d >= %u!", i, fds_out[i], i, payload->idxs[i], payload->num_idxs); swrap_close_fd_array(num_fds_out, fds_out); errno = EINVAL; return -1; } if ((size_t)fds_out[i] >= socket_fds_max) { SWRAP_LOG(SWRAP_LOG_ERROR, "The max socket index limit of %zu has been reached, " "trying to add %d", socket_fds_max, fds_out[i]); swrap_close_fd_array(num_fds_out, fds_out); errno = EMFILE; return -1; } SWRAP_LOG(SWRAP_LOG_TRACE, "fds_in[%zu]=%d " "received as info.idxs[%zu]=%d!", i, fds_out[i], i, payload->idxs[i]); for (j = 0; j < i; j++) { if (payload->idxs[j] == -1) { continue; } if (payload->idxs[j] == payload->idxs[i]) { si_idx_array[i] = si_idx_array[j]; } } if (si_idx_array[i] == -1) { const struct socket_info *si = &payload->infos[payload->idxs[i]]; si_idx_array[i] = swrap_add_socket_info(si); if (si_idx_array[i] == -1) { int saved_errno = errno; SWRAP_LOG(SWRAP_LOG_ERROR, "The max socket index limit of %zu has been reached, " "trying to add %d", socket_fds_max, fds_out[i]); swrap_undo_si_idx_array(i, si_idx_array); swrap_close_fd_array(num_fds_out, fds_out); errno = saved_errno; return -1; } SWRAP_LOG(SWRAP_LOG_TRACE, "Imported %s socket for protocol %s, fd=%d", si->family == AF_INET ? "IPv4" : "IPv6", si->type == SOCK_DGRAM ? "UDP" : "TCP", fds_out[i]); } } for (i = 0; i < num_fds_out; i++) { if (si_idx_array[i] == -1) { continue; } set_socket_info_index(fds_out[i], si_idx_array[i]); } /* we're done ... */ *cm_data_space = new_cm_data_space; return 0; } static int swrap_recvmsg_unix_sol_socket(struct cmsghdr *cmsg, uint8_t **cm_data, size_t *cm_data_space) { int rc = -1; switch (cmsg->cmsg_type) { case SCM_RIGHTS: rc = swrap_recvmsg_unix_scm_rights(cmsg, cm_data, cm_data_space); break; default: rc = swrap_sendmsg_copy_cmsg(cmsg, cm_data, cm_data_space); break; } return rc; } #endif /* HAVE_STRUCT_MSGHDR_MSG_CONTROL */ static int swrap_sendmsg_before_unix(const struct msghdr *_msg_in, struct msghdr *msg_tmp, int *scm_rights_pipe_fd) { #ifdef HAVE_STRUCT_MSGHDR_MSG_CONTROL struct msghdr *msg_in = discard_const_p(struct msghdr, _msg_in); struct cmsghdr *cmsg = NULL; uint8_t *cm_data = NULL; size_t cm_data_space = 0; int rc = -1; *msg_tmp = *msg_in; *scm_rights_pipe_fd = -1; /* Nothing to do */ if (msg_in->msg_controllen == 0 || msg_in->msg_control == NULL) { return 0; } for (cmsg = CMSG_FIRSTHDR(msg_in); cmsg != NULL; cmsg = CMSG_NXTHDR(msg_in, cmsg)) { switch (cmsg->cmsg_level) { case SOL_SOCKET: rc = swrap_sendmsg_unix_sol_socket(cmsg, &cm_data, &cm_data_space, scm_rights_pipe_fd); break; default: rc = swrap_sendmsg_copy_cmsg(cmsg, &cm_data, &cm_data_space); break; } if (rc < 0) { int saved_errno = errno; SAFE_FREE(cm_data); errno = saved_errno; return rc; } } msg_tmp->msg_controllen = cm_data_space; msg_tmp->msg_control = cm_data; return 0; #else /* HAVE_STRUCT_MSGHDR_MSG_CONTROL */ *msg_tmp = *_msg_in; return 0; #endif /* ! HAVE_STRUCT_MSGHDR_MSG_CONTROL */ } static ssize_t swrap_sendmsg_after_unix(struct msghdr *msg_tmp, ssize_t ret, int scm_rights_pipe_fd) { #ifdef HAVE_STRUCT_MSGHDR_MSG_CONTROL int saved_errno = errno; SAFE_FREE(msg_tmp->msg_control); if (scm_rights_pipe_fd != -1) { libc_close(scm_rights_pipe_fd); } errno = saved_errno; #endif /* HAVE_STRUCT_MSGHDR_MSG_CONTROL */ return ret; } static int swrap_recvmsg_before_unix(struct msghdr *msg_in, struct msghdr *msg_tmp, uint8_t **tmp_control) { #ifdef HAVE_STRUCT_MSGHDR_MSG_CONTROL const size_t cm_extra_space = CMSG_SPACE(sizeof(int)); uint8_t *cm_data = NULL; size_t cm_data_space = 0; *msg_tmp = *msg_in; *tmp_control = NULL; SWRAP_LOG(SWRAP_LOG_TRACE, "msg_in->msg_controllen=%zu", (size_t)msg_in->msg_controllen); /* Nothing to do */ if (msg_in->msg_controllen == 0 || msg_in->msg_control == NULL) { return 0; } /* * We need to give the kernel a bit more space in order * recv the pipe fd, added by swrap_sendmsg_before_unix()). * swrap_recvmsg_after_unix() will hide it again. */ cm_data_space = msg_in->msg_controllen; if (cm_data_space < (INT32_MAX - cm_extra_space)) { cm_data_space += cm_extra_space; } cm_data = calloc(1, cm_data_space); if (cm_data == NULL) { return -1; } msg_tmp->msg_controllen = cm_data_space; msg_tmp->msg_control = cm_data; *tmp_control = cm_data; SWRAP_LOG(SWRAP_LOG_TRACE, "msg_tmp->msg_controllen=%zu", (size_t)msg_tmp->msg_controllen); return 0; #else /* HAVE_STRUCT_MSGHDR_MSG_CONTROL */ *msg_tmp = *msg_in; *tmp_control = NULL; return 0; #endif /* ! HAVE_STRUCT_MSGHDR_MSG_CONTROL */ } static ssize_t swrap_recvmsg_after_unix(struct msghdr *msg_tmp, uint8_t **tmp_control, struct msghdr *msg_out, ssize_t ret) { #ifdef HAVE_STRUCT_MSGHDR_MSG_CONTROL struct cmsghdr *cmsg = NULL; uint8_t *cm_data = NULL; size_t cm_data_space = 0; int rc = -1; if (ret < 0) { int saved_errno = errno; SWRAP_LOG(SWRAP_LOG_TRACE, "ret=%zd - %d - %s", ret, saved_errno, strerror(saved_errno)); SAFE_FREE(*tmp_control); /* msg_out should not be touched on error */ errno = saved_errno; return ret; } SWRAP_LOG(SWRAP_LOG_TRACE, "msg_tmp->msg_controllen=%zu", (size_t)msg_tmp->msg_controllen); /* Nothing to do */ if (msg_tmp->msg_controllen == 0 || msg_tmp->msg_control == NULL) { int saved_errno = errno; *msg_out = *msg_tmp; SAFE_FREE(*tmp_control); errno = saved_errno; return ret; } for (cmsg = CMSG_FIRSTHDR(msg_tmp); cmsg != NULL; cmsg = CMSG_NXTHDR(msg_tmp, cmsg)) { switch (cmsg->cmsg_level) { case SOL_SOCKET: rc = swrap_recvmsg_unix_sol_socket(cmsg, &cm_data, &cm_data_space); break; default: rc = swrap_sendmsg_copy_cmsg(cmsg, &cm_data, &cm_data_space); break; } if (rc < 0) { int saved_errno = errno; SAFE_FREE(cm_data); SAFE_FREE(*tmp_control); errno = saved_errno; return rc; } } /* * msg_tmp->msg_control (*tmp_control) was created by * swrap_recvmsg_before_unix() and msg_out->msg_control * is still the buffer of the caller. */ msg_tmp->msg_control = msg_out->msg_control; msg_tmp->msg_controllen = msg_out->msg_controllen; *msg_out = *msg_tmp; cm_data_space = MIN(cm_data_space, msg_out->msg_controllen); memcpy(msg_out->msg_control, cm_data, cm_data_space); msg_out->msg_controllen = cm_data_space; SAFE_FREE(cm_data); SAFE_FREE(*tmp_control); SWRAP_LOG(SWRAP_LOG_TRACE, "msg_out->msg_controllen=%zu", (size_t)msg_out->msg_controllen); return ret; #else /* HAVE_STRUCT_MSGHDR_MSG_CONTROL */ int saved_errno = errno; *msg_out = *msg_tmp; SAFE_FREE(*tmp_control); errno = saved_errno; return ret; #endif /* ! HAVE_STRUCT_MSGHDR_MSG_CONTROL */ } static ssize_t swrap_sendmsg_before(int fd, struct socket_info *si, struct msghdr *msg, struct iovec *tmp_iov, struct sockaddr_un *tmp_un, const struct sockaddr_un **to_un, const struct sockaddr **to, int *bcast) { size_t i, len = 0; ssize_t ret = -1; struct swrap_sockaddr_buf buf = {}; if (to_un) { *to_un = NULL; } if (to) { *to = NULL; } if (bcast) { *bcast = 0; } SWRAP_LOCK_SI(si); switch (si->type) { case SOCK_STREAM: { unsigned long mtu; if (!si->connected) { errno = ENOTCONN; goto out; } if (msg->msg_iovlen == 0) { break; } mtu = socket_wrapper_mtu(); for (i = 0; i < (size_t)msg->msg_iovlen; i++) { size_t nlen; nlen = len + msg->msg_iov[i].iov_len; if (nlen < len) { /* overflow */ errno = EMSGSIZE; goto out; } if (nlen > mtu) { break; } } msg->msg_iovlen = i; if (msg->msg_iovlen == 0) { *tmp_iov = msg->msg_iov[0]; tmp_iov->iov_len = MIN((size_t)tmp_iov->iov_len, (size_t)mtu); msg->msg_iov = tmp_iov; msg->msg_iovlen = 1; } break; } case SOCK_DGRAM: if (si->connected) { if (msg->msg_name != NULL) { /* * We are dealing with unix sockets and if we * are connected, we should only talk to the * connected unix path. Using the fd to send * to another server would be hard to achieve. */ msg->msg_name = NULL; msg->msg_namelen = 0; } SWRAP_LOG(SWRAP_LOG_TRACE, "connected(%s) fd=%d", swrap_sockaddr_string(&buf, &si->peername.sa.s), fd); } else { const struct sockaddr *msg_name; msg_name = (const struct sockaddr *)msg->msg_name; if (msg_name == NULL) { errno = ENOTCONN; goto out; } ret = sockaddr_convert_to_un(si, msg_name, msg->msg_namelen, tmp_un, 0, bcast); if (ret == -1) { goto out; } if (to_un) { *to_un = tmp_un; } if (to) { *to = msg_name; } msg->msg_name = tmp_un; msg->msg_namelen = sizeof(*tmp_un); } if (si->bound == 0) { ret = swrap_auto_bind(fd, si, si->family); if (ret == -1) { SWRAP_UNLOCK_SI(si); if (errno == ENOTSOCK) { swrap_remove_stale(fd); ret = -ENOTSOCK; } else { SWRAP_LOG(SWRAP_LOG_ERROR, "swrap_sendmsg_before failed"); } return ret; } } if (!si->defer_connect) { break; } ret = sockaddr_convert_to_un(si, &si->peername.sa.s, si->peername.sa_socklen, tmp_un, 0, NULL); if (ret == -1) { goto out; } SWRAP_LOG(SWRAP_LOG_TRACE, "deferred connect(%s) path=%s, fd=%d", swrap_sockaddr_string(&buf, &si->peername.sa.s), tmp_un->sun_path, fd); ret = libc_connect(fd, (struct sockaddr *)(void *)tmp_un, sizeof(*tmp_un)); /* to give better errors */ if (ret == -1 && errno == ENOENT) { errno = EHOSTUNREACH; } if (ret == -1) { goto out; } si->defer_connect = 0; break; default: errno = EHOSTUNREACH; goto out; } ret = 0; out: SWRAP_UNLOCK_SI(si); return ret; } static void swrap_sendmsg_after(int fd, struct socket_info *si, struct msghdr *msg, const struct sockaddr *to, ssize_t ret) { int saved_errno = errno; size_t i, len = 0; uint8_t *buf; off_t ofs = 0; size_t avail = 0; size_t remain; /* to give better errors */ if (ret == -1) { if (saved_errno == ENOENT) { saved_errno = EHOSTUNREACH; } else if (saved_errno == ENOTSOCK) { /* If the fd is not a socket, remove it */ swrap_remove_stale(fd); } } for (i = 0; i < (size_t)msg->msg_iovlen; i++) { avail += msg->msg_iov[i].iov_len; } if (ret == -1) { remain = MIN(80, avail); } else { remain = ret; } /* we capture it as one single packet */ buf = (uint8_t *)malloc(remain); if (!buf) { /* we just not capture the packet */ errno = saved_errno; return; } for (i = 0; i < (size_t)msg->msg_iovlen; i++) { size_t this_time = MIN(remain, (size_t)msg->msg_iov[i].iov_len); if (this_time > 0) { memcpy(buf + ofs, msg->msg_iov[i].iov_base, this_time); } ofs += this_time; remain -= this_time; } len = ofs; SWRAP_LOCK_SI(si); switch (si->type) { case SOCK_STREAM: if (ret == -1) { swrap_pcap_dump_packet(si, NULL, SWRAP_SEND, buf, len); swrap_pcap_dump_packet(si, NULL, SWRAP_SEND_RST, NULL, 0); } else { swrap_pcap_dump_packet(si, NULL, SWRAP_SEND, buf, len); } break; case SOCK_DGRAM: if (si->connected) { to = &si->peername.sa.s; } if (ret == -1) { swrap_pcap_dump_packet(si, to, SWRAP_SENDTO, buf, len); swrap_pcap_dump_packet(si, to, SWRAP_SENDTO_UNREACH, buf, len); } else { swrap_pcap_dump_packet(si, to, SWRAP_SENDTO, buf, len); } break; } SWRAP_UNLOCK_SI(si); free(buf); errno = saved_errno; } static int swrap_recvmsg_before(int fd, struct socket_info *si, struct msghdr *msg, struct iovec *tmp_iov) { size_t i, len = 0; int ret = -1; SWRAP_LOCK_SI(si); (void)fd; /* unused */ switch (si->type) { case SOCK_STREAM: { unsigned int mtu; if (!si->connected) { errno = ENOTCONN; goto out; } if (msg->msg_iovlen == 0) { break; } mtu = socket_wrapper_mtu(); for (i = 0; i < (size_t)msg->msg_iovlen; i++) { size_t nlen; nlen = len + msg->msg_iov[i].iov_len; if (nlen > mtu) { break; } } msg->msg_iovlen = i; if (msg->msg_iovlen == 0) { *tmp_iov = msg->msg_iov[0]; tmp_iov->iov_len = MIN((size_t)tmp_iov->iov_len, (size_t)mtu); msg->msg_iov = tmp_iov; msg->msg_iovlen = 1; } break; } case SOCK_DGRAM: if (msg->msg_name == NULL) { errno = EINVAL; goto out; } if (msg->msg_iovlen == 0) { break; } if (si->bound == 0) { ret = swrap_auto_bind(fd, si, si->family); if (ret == -1) { SWRAP_UNLOCK_SI(si); /* * When attempting to read or write to a * descriptor, if an underlying autobind fails * because it's not a socket, stop intercepting * uses of that descriptor. */ if (errno == ENOTSOCK) { swrap_remove_stale(fd); ret = -ENOTSOCK; } else { SWRAP_LOG(SWRAP_LOG_ERROR, "swrap_recvmsg_before failed"); } return ret; } } break; default: errno = EHOSTUNREACH; goto out; } ret = 0; out: SWRAP_UNLOCK_SI(si); return ret; } static int swrap_recvmsg_after(int fd, struct socket_info *si, struct msghdr *msg, const struct sockaddr_un *un_addr, socklen_t un_addrlen, ssize_t ret) { int saved_errno = errno; size_t i; uint8_t *buf = NULL; off_t ofs = 0; size_t avail = 0; size_t remain; int rc; /* to give better errors */ if (ret == -1) { if (saved_errno == ENOENT) { saved_errno = EHOSTUNREACH; } else if (saved_errno == ENOTSOCK) { /* If the fd is not a socket, remove it */ swrap_remove_stale(fd); } } for (i = 0; i < (size_t)msg->msg_iovlen; i++) { avail += msg->msg_iov[i].iov_len; } SWRAP_LOCK_SI(si); /* Convert the socket address before we leave */ if (si->type == SOCK_DGRAM && un_addr != NULL) { rc = sockaddr_convert_from_un(si, un_addr, un_addrlen, si->family, msg->msg_name, &msg->msg_namelen); if (rc == -1) { goto done; } } if (avail == 0) { rc = 0; goto done; } if (ret == -1) { remain = MIN(80, avail); } else { remain = ret; } /* we capture it as one single packet */ buf = (uint8_t *)malloc(remain); if (buf == NULL) { /* we just not capture the packet */ SWRAP_UNLOCK_SI(si); errno = saved_errno; return -1; } for (i = 0; i < (size_t)msg->msg_iovlen; i++) { size_t this_time = MIN(remain, (size_t)msg->msg_iov[i].iov_len); memcpy(buf + ofs, msg->msg_iov[i].iov_base, this_time); ofs += this_time; remain -= this_time; } switch (si->type) { case SOCK_STREAM: if (ret == -1 && saved_errno != EAGAIN && saved_errno != ENOBUFS) { swrap_pcap_dump_packet(si, NULL, SWRAP_RECV_RST, NULL, 0); } else if (ret == 0) { /* END OF FILE */ swrap_pcap_dump_packet(si, NULL, SWRAP_RECV_RST, NULL, 0); } else if (ret > 0) { swrap_pcap_dump_packet(si, NULL, SWRAP_RECV, buf, ret); } break; case SOCK_DGRAM: if (ret == -1) { break; } if (un_addr != NULL) { swrap_pcap_dump_packet(si, msg->msg_name, SWRAP_RECVFROM, buf, ret); } else { swrap_pcap_dump_packet(si, msg->msg_name, SWRAP_RECV, buf, ret); } break; } rc = 0; done: free(buf); errno = saved_errno; #ifdef HAVE_STRUCT_MSGHDR_MSG_CONTROL if (rc == 0 && msg->msg_controllen > 0 && msg->msg_control != NULL) { rc = swrap_msghdr_add_socket_info(si, msg); if (rc < 0) { SWRAP_UNLOCK_SI(si); return -1; } } #endif SWRAP_UNLOCK_SI(si); return rc; } /**************************************************************************** * RECVFROM ***************************************************************************/ static ssize_t swrap_recvfrom(int s, void *buf, size_t len, int flags, struct sockaddr *from, socklen_t *fromlen) { struct swrap_address from_addr = { .sa_socklen = sizeof(struct sockaddr_un), }; ssize_t ret; struct socket_info *si = find_socket_info(s); struct swrap_address saddr = { .sa_socklen = sizeof(struct sockaddr_storage), }; struct msghdr msg; struct iovec tmp; int tret; if (!si) { return libc_recvfrom(s, buf, len, flags, from, fromlen); } tmp.iov_base = buf; tmp.iov_len = len; ZERO_STRUCT(msg); if (from != NULL && fromlen != NULL) { msg.msg_name = from; /* optional address */ msg.msg_namelen = *fromlen; /* size of address */ } else { msg.msg_name = &saddr.sa.s; /* optional address */ msg.msg_namelen = saddr.sa_socklen; /* size of address */ } msg.msg_iov = &tmp; /* scatter/gather array */ msg.msg_iovlen = 1; /* # elements in msg_iov */ #ifdef HAVE_STRUCT_MSGHDR_MSG_CONTROL msg.msg_control = NULL; /* ancillary data, see below */ msg.msg_controllen = 0; /* ancillary data buffer len */ msg.msg_flags = 0; /* flags on received message */ #endif tret = swrap_recvmsg_before(s, si, &msg, &tmp); if (tret < 0) { return -1; } buf = msg.msg_iov[0].iov_base; len = msg.msg_iov[0].iov_len; ret = libc_recvfrom(s, buf, len, flags, &from_addr.sa.s, &from_addr.sa_socklen); if (ret == -1) { return ret; } tret = swrap_recvmsg_after(s, si, &msg, &from_addr.sa.un, from_addr.sa_socklen, ret); if (tret != 0) { return tret; } if (from != NULL && fromlen != NULL) { *fromlen = msg.msg_namelen; } return ret; } #ifdef HAVE_ACCEPT_PSOCKLEN_T ssize_t recvfrom(int s, void *buf, size_t len, int flags, struct sockaddr *from, Psocklen_t fromlen) #else ssize_t recvfrom(int s, void *buf, size_t len, int flags, struct sockaddr *from, socklen_t *fromlen) #endif { return swrap_recvfrom(s, buf, len, flags, from, (socklen_t *)fromlen); } /**************************************************************************** * SENDTO ***************************************************************************/ static ssize_t swrap_sendto(int s, const void *buf, size_t len, int flags, const struct sockaddr *to, socklen_t tolen) { struct msghdr msg; struct iovec tmp; struct swrap_address un_addr = { .sa_socklen = sizeof(struct sockaddr_un), }; const struct sockaddr_un *to_un = NULL; ssize_t ret; int rc; struct socket_info *si = find_socket_info(s); int bcast = 0; if (!si) { return libc_sendto(s, buf, len, flags, to, tolen); } tmp.iov_base = discard_const_p(char, buf); tmp.iov_len = len; ZERO_STRUCT(msg); msg.msg_name = discard_const_p(struct sockaddr, to); /* optional address */ msg.msg_namelen = tolen; /* size of address */ msg.msg_iov = &tmp; /* scatter/gather array */ msg.msg_iovlen = 1; /* # elements in msg_iov */ #ifdef HAVE_STRUCT_MSGHDR_MSG_CONTROL msg.msg_control = NULL; /* ancillary data, see below */ msg.msg_controllen = 0; /* ancillary data buffer len */ msg.msg_flags = 0; /* flags on received message */ #endif rc = swrap_sendmsg_before(s, si, &msg, &tmp, &un_addr.sa.un, &to_un, &to, &bcast); if (rc < 0) { return -1; } buf = msg.msg_iov[0].iov_base; len = msg.msg_iov[0].iov_len; if (bcast) { struct stat st; unsigned int iface; unsigned int prt = ntohs(((const struct sockaddr_in *)(const void *)to)->sin_port); char type; char *swrap_dir = NULL; type = SOCKET_TYPE_CHAR_UDP; swrap_dir = socket_wrapper_dir(); if (swrap_dir == NULL) { return -1; } for(iface=0; iface <= MAX_WRAPPED_INTERFACES; iface++) { swrap_un_path(&un_addr.sa.un, swrap_dir, type, iface, prt); if (stat(un_addr.sa.un.sun_path, &st) != 0) continue; /* ignore the any errors in broadcast sends */ libc_sendto(s, buf, len, flags, &un_addr.sa.s, un_addr.sa_socklen); } SAFE_FREE(swrap_dir); SWRAP_LOCK_SI(si); swrap_pcap_dump_packet(si, to, SWRAP_SENDTO, buf, len); SWRAP_UNLOCK_SI(si); return len; } SWRAP_LOCK_SI(si); /* * If it is a dgram socket and we are connected, don't include the * 'to' address. */ if (si->type == SOCK_DGRAM && si->connected) { ret = libc_sendto(s, buf, len, flags, NULL, 0); } else { ret = libc_sendto(s, buf, len, flags, (struct sockaddr *)msg.msg_name, msg.msg_namelen); } SWRAP_UNLOCK_SI(si); swrap_sendmsg_after(s, si, &msg, to, ret); return ret; } ssize_t sendto(int s, const void *buf, size_t len, int flags, const struct sockaddr *to, socklen_t tolen) { return swrap_sendto(s, buf, len, flags, to, tolen); } /**************************************************************************** * READV ***************************************************************************/ static ssize_t swrap_recv(int s, void *buf, size_t len, int flags) { struct socket_info *si; struct msghdr msg; struct swrap_address saddr = { .sa_socklen = sizeof(struct sockaddr_storage), }; struct iovec tmp; ssize_t ret; int tret; si = find_socket_info(s); if (si == NULL) { return libc_recv(s, buf, len, flags); } tmp.iov_base = buf; tmp.iov_len = len; ZERO_STRUCT(msg); msg.msg_name = &saddr.sa.s; /* optional address */ msg.msg_namelen = saddr.sa_socklen; /* size of address */ msg.msg_iov = &tmp; /* scatter/gather array */ msg.msg_iovlen = 1; /* # elements in msg_iov */ #ifdef HAVE_STRUCT_MSGHDR_MSG_CONTROL msg.msg_control = NULL; /* ancillary data, see below */ msg.msg_controllen = 0; /* ancillary data buffer len */ msg.msg_flags = 0; /* flags on received message */ #endif tret = swrap_recvmsg_before(s, si, &msg, &tmp); if (tret < 0) { return -1; } buf = msg.msg_iov[0].iov_base; len = msg.msg_iov[0].iov_len; ret = libc_recv(s, buf, len, flags); tret = swrap_recvmsg_after(s, si, &msg, NULL, 0, ret); if (tret != 0) { return tret; } return ret; } ssize_t recv(int s, void *buf, size_t len, int flags) { return swrap_recv(s, buf, len, flags); } /**************************************************************************** * READ ***************************************************************************/ static ssize_t swrap_read(int s, void *buf, size_t len) { struct socket_info *si; struct msghdr msg; struct iovec tmp; struct swrap_address saddr = { .sa_socklen = sizeof(struct sockaddr_storage), }; ssize_t ret; int tret; si = find_socket_info(s); if (si == NULL) { return libc_read(s, buf, len); } tmp.iov_base = buf; tmp.iov_len = len; ZERO_STRUCT(msg); msg.msg_name = &saddr.sa.ss; /* optional address */ msg.msg_namelen = saddr.sa_socklen; /* size of address */ msg.msg_iov = &tmp; /* scatter/gather array */ msg.msg_iovlen = 1; /* # elements in msg_iov */ #ifdef HAVE_STRUCT_MSGHDR_MSG_CONTROL msg.msg_control = NULL; /* ancillary data, see below */ msg.msg_controllen = 0; /* ancillary data buffer len */ msg.msg_flags = 0; /* flags on received message */ #endif tret = swrap_recvmsg_before(s, si, &msg, &tmp); if (tret < 0) { if (tret == -ENOTSOCK) { return libc_read(s, buf, len); } return -1; } buf = msg.msg_iov[0].iov_base; len = msg.msg_iov[0].iov_len; ret = libc_read(s, buf, len); tret = swrap_recvmsg_after(s, si, &msg, NULL, 0, ret); if (tret != 0) { return tret; } return ret; } ssize_t read(int s, void *buf, size_t len) { return swrap_read(s, buf, len); } /**************************************************************************** * WRITE ***************************************************************************/ static ssize_t swrap_write(int s, const void *buf, size_t len) { struct msghdr msg; struct iovec tmp; struct sockaddr_un un_addr; ssize_t ret; int rc; struct socket_info *si; si = find_socket_info(s); if (si == NULL) { return libc_write(s, buf, len); } tmp.iov_base = discard_const_p(char, buf); tmp.iov_len = len; ZERO_STRUCT(msg); msg.msg_name = NULL; /* optional address */ msg.msg_namelen = 0; /* size of address */ msg.msg_iov = &tmp; /* scatter/gather array */ msg.msg_iovlen = 1; /* # elements in msg_iov */ #ifdef HAVE_STRUCT_MSGHDR_MSG_CONTROL msg.msg_control = NULL; /* ancillary data, see below */ msg.msg_controllen = 0; /* ancillary data buffer len */ msg.msg_flags = 0; /* flags on received message */ #endif rc = swrap_sendmsg_before(s, si, &msg, &tmp, &un_addr, NULL, NULL, NULL); if (rc < 0) { return -1; } buf = msg.msg_iov[0].iov_base; len = msg.msg_iov[0].iov_len; ret = libc_write(s, buf, len); swrap_sendmsg_after(s, si, &msg, NULL, ret); return ret; } ssize_t write(int s, const void *buf, size_t len) { return swrap_write(s, buf, len); } /**************************************************************************** * SEND ***************************************************************************/ static ssize_t swrap_send(int s, const void *buf, size_t len, int flags) { struct msghdr msg; struct iovec tmp; struct sockaddr_un un_addr; ssize_t ret; int rc; struct socket_info *si = find_socket_info(s); if (!si) { return libc_send(s, buf, len, flags); } tmp.iov_base = discard_const_p(char, buf); tmp.iov_len = len; ZERO_STRUCT(msg); msg.msg_name = NULL; /* optional address */ msg.msg_namelen = 0; /* size of address */ msg.msg_iov = &tmp; /* scatter/gather array */ msg.msg_iovlen = 1; /* # elements in msg_iov */ #ifdef HAVE_STRUCT_MSGHDR_MSG_CONTROL msg.msg_control = NULL; /* ancillary data, see below */ msg.msg_controllen = 0; /* ancillary data buffer len */ msg.msg_flags = 0; /* flags on received message */ #endif rc = swrap_sendmsg_before(s, si, &msg, &tmp, &un_addr, NULL, NULL, NULL); if (rc < 0) { return -1; } buf = msg.msg_iov[0].iov_base; len = msg.msg_iov[0].iov_len; ret = libc_send(s, buf, len, flags); swrap_sendmsg_after(s, si, &msg, NULL, ret); return ret; } ssize_t send(int s, const void *buf, size_t len, int flags) { return swrap_send(s, buf, len, flags); } /**************************************************************************** * RECVMSG ***************************************************************************/ static ssize_t swrap_recvmsg(int s, struct msghdr *omsg, int flags) { struct swrap_address from_addr = { .sa_socklen = sizeof(struct sockaddr_un), }; struct swrap_address convert_addr = { .sa_socklen = sizeof(struct sockaddr_storage), }; struct socket_info *si; struct msghdr msg; struct iovec tmp; #ifdef HAVE_STRUCT_MSGHDR_MSG_CONTROL size_t msg_ctrllen_filled; size_t msg_ctrllen_left; #endif ssize_t ret; int rc; si = find_socket_info(s); if (si == NULL) { uint8_t *tmp_control = NULL; rc = swrap_recvmsg_before_unix(omsg, &msg, &tmp_control); if (rc < 0) { return rc; } ret = libc_recvmsg(s, &msg, flags); return swrap_recvmsg_after_unix(&msg, &tmp_control, omsg, ret); } tmp.iov_base = NULL; tmp.iov_len = 0; ZERO_STRUCT(msg); msg.msg_name = &from_addr.sa; /* optional address */ msg.msg_namelen = from_addr.sa_socklen; /* size of address */ msg.msg_iov = omsg->msg_iov; /* scatter/gather array */ msg.msg_iovlen = omsg->msg_iovlen; /* # elements in msg_iov */ #ifdef HAVE_STRUCT_MSGHDR_MSG_CONTROL msg_ctrllen_filled = 0; msg_ctrllen_left = omsg->msg_controllen; msg.msg_control = omsg->msg_control; /* ancillary data, see below */ msg.msg_controllen = omsg->msg_controllen; /* ancillary data buffer len */ msg.msg_flags = omsg->msg_flags; /* flags on received message */ #endif rc = swrap_recvmsg_before(s, si, &msg, &tmp); if (rc < 0) { return -1; } ret = libc_recvmsg(s, &msg, flags); #ifdef HAVE_STRUCT_MSGHDR_MSG_CONTROL msg_ctrllen_filled += msg.msg_controllen; msg_ctrllen_left -= msg.msg_controllen; if (omsg->msg_control != NULL) { uint8_t *p; p = omsg->msg_control; p += msg_ctrllen_filled; msg.msg_control = p; msg.msg_controllen = msg_ctrllen_left; } else { msg.msg_control = NULL; msg.msg_controllen = 0; } #endif /* * We convert the unix address to a IP address so we need a buffer * which can store the address in case of SOCK_DGRAM, see below. */ msg.msg_name = &convert_addr.sa; msg.msg_namelen = convert_addr.sa_socklen; rc = swrap_recvmsg_after(s, si, &msg, &from_addr.sa.un, from_addr.sa_socklen, ret); if (rc != 0) { return rc; } #ifdef HAVE_STRUCT_MSGHDR_MSG_CONTROL if (omsg->msg_control != NULL) { /* msg.msg_controllen = space left */ msg_ctrllen_left = msg.msg_controllen; msg_ctrllen_filled = omsg->msg_controllen - msg_ctrllen_left; } /* Update the original message length */ omsg->msg_controllen = msg_ctrllen_filled; omsg->msg_flags = msg.msg_flags; #endif omsg->msg_iovlen = msg.msg_iovlen; SWRAP_LOCK_SI(si); /* * From the manpage: * * The msg_name field points to a caller-allocated buffer that is * used to return the source address if the socket is unconnected. The * caller should set msg_namelen to the size of this buffer before this * call; upon return from a successful call, msg_name will contain the * length of the returned address. If the application does not need * to know the source address, msg_name can be specified as NULL. */ if (si->type == SOCK_STREAM) { omsg->msg_namelen = 0; } else if (omsg->msg_name != NULL && omsg->msg_namelen != 0 && omsg->msg_namelen >= msg.msg_namelen) { memcpy(omsg->msg_name, msg.msg_name, msg.msg_namelen); omsg->msg_namelen = msg.msg_namelen; } SWRAP_UNLOCK_SI(si); return ret; } ssize_t recvmsg(int sockfd, struct msghdr *msg, int flags) { return swrap_recvmsg(sockfd, msg, flags); } /**************************************************************************** * RECVMMSG ***************************************************************************/ #ifdef HAVE_RECVMMSG #if defined(HAVE_RECVMMSG_SSIZE_T_CONST_TIMEOUT) /* FreeBSD */ static ssize_t swrap_recvmmsg(int s, struct mmsghdr *omsgvec, size_t _vlen, int flags, const struct timespec *timeout) #elif defined(HAVE_RECVMMSG_CONST_TIMEOUT) /* Linux legacy glibc < 2.21 */ static int swrap_recvmmsg(int s, struct mmsghdr *omsgvec, unsigned int _vlen, int flags, const struct timespec *timeout) #else /* Linux glibc >= 2.21 */ static int swrap_recvmmsg(int s, struct mmsghdr *omsgvec, unsigned int _vlen, int flags, struct timespec *timeout) #endif { struct socket_info *si = find_socket_info(s); #define __SWRAP_RECVMMSG_MAX_VLEN 16 struct mmsghdr msgvec[__SWRAP_RECVMMSG_MAX_VLEN] = {}; struct { struct iovec iov; struct swrap_address from_addr; struct swrap_address convert_addr; #ifdef HAVE_STRUCT_MSGHDR_MSG_CONTROL size_t msg_ctrllen_filled; size_t msg_ctrllen_left; #endif } tmp[__SWRAP_RECVMMSG_MAX_VLEN] = {}; int vlen; int i; int ret; int rc; int saved_errno; if (_vlen > __SWRAP_RECVMMSG_MAX_VLEN) { vlen = __SWRAP_RECVMMSG_MAX_VLEN; } else { vlen = _vlen; } if (si == NULL) { uint8_t *tmp_control[__SWRAP_RECVMMSG_MAX_VLEN] = { NULL, }; for (i = 0; i < vlen; i++) { struct msghdr *omsg = &omsgvec[i].msg_hdr; struct msghdr *msg = &msgvec[i].msg_hdr; rc = swrap_recvmsg_before_unix(omsg, msg, &tmp_control[i]); if (rc < 0) { ret = rc; goto fail_libc; } } ret = libc_recvmmsg(s, msgvec, vlen, flags, timeout); if (ret < 0) { goto fail_libc; } for (i = 0; i < ret; i++) { omsgvec[i].msg_len = msgvec[i].msg_len; } fail_libc: saved_errno = errno; for (i = 0; i < vlen; i++) { struct msghdr *omsg = &omsgvec[i].msg_hdr; struct msghdr *msg = &msgvec[i].msg_hdr; if (i == 0 || i < ret) { swrap_recvmsg_after_unix(msg, &tmp_control[i], omsg, ret); } SAFE_FREE(tmp_control[i]); } errno = saved_errno; return ret; } for (i = 0; i < vlen; i++) { struct msghdr *omsg = &omsgvec[i].msg_hdr; struct msghdr *msg = &msgvec[i].msg_hdr; tmp[i].from_addr.sa_socklen = sizeof(struct sockaddr_un); tmp[i].convert_addr.sa_socklen = sizeof(struct sockaddr_storage); msg->msg_name = &tmp[i].from_addr.sa; /* optional address */ msg->msg_namelen = tmp[i].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 tmp[i].msg_ctrllen_filled = 0; tmp[i].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[i].iov); if (rc < 0) { ret = rc; goto fail_swrap; } } ret = libc_recvmmsg(s, msgvec, vlen, flags, timeout); if (ret < 0) { goto fail_swrap; } for (i = 0; i < ret; i++) { omsgvec[i].msg_len = msgvec[i].msg_len; } fail_swrap: saved_errno = errno; for (i = 0; i < vlen; i++) { struct msghdr *omsg = &omsgvec[i].msg_hdr; struct msghdr *msg = &msgvec[i].msg_hdr; if (!(i == 0 || i < ret)) { break; } #ifdef HAVE_STRUCT_MSGHDR_MSG_CONTROL tmp[i].msg_ctrllen_filled += msg->msg_controllen; tmp[i].msg_ctrllen_left -= msg->msg_controllen; if (omsg->msg_control != NULL) { uint8_t *p; p = omsg->msg_control; p += tmp[i].msg_ctrllen_filled; msg->msg_control = p; msg->msg_controllen = tmp[i].msg_ctrllen_left; } else { msg->msg_control = NULL; msg->msg_controllen = 0; } #endif /* * We convert the unix address to a IP address so we need a buffer * which can store the address in case of SOCK_DGRAM, see below. */ msg->msg_name = &tmp[i].convert_addr.sa; msg->msg_namelen = tmp[i].convert_addr.sa_socklen; swrap_recvmsg_after(s, si, msg, &tmp[i].from_addr.sa.un, tmp[i].from_addr.sa_socklen, ret); #ifdef HAVE_STRUCT_MSGHDR_MSG_CONTROL if (omsg->msg_control != NULL) { /* msg->msg_controllen = space left */ tmp[i].msg_ctrllen_left = msg->msg_controllen; tmp[i].msg_ctrllen_filled = omsg->msg_controllen - tmp[i].msg_ctrllen_left; } /* Update the original message length */ omsg->msg_controllen = tmp[i].msg_ctrllen_filled; omsg->msg_flags = msg->msg_flags; #endif omsg->msg_iovlen = msg->msg_iovlen; SWRAP_LOCK_SI(si); /* * From the manpage: * * The msg_name field points to a caller-allocated buffer that is * used to return the source address if the socket is unconnected. The * caller should set msg_namelen to the size of this buffer before this * call; upon return from a successful call, msg_name will contain the * length of the returned address. If the application does not need * to know the source address, msg_name can be specified as NULL. */ if (si->type == SOCK_STREAM) { omsg->msg_namelen = 0; } else if (omsg->msg_name != NULL && omsg->msg_namelen != 0 && omsg->msg_namelen >= msg->msg_namelen) { memcpy(omsg->msg_name, msg->msg_name, msg->msg_namelen); omsg->msg_namelen = msg->msg_namelen; } SWRAP_UNLOCK_SI(si); } errno = saved_errno; return ret; } #if defined(HAVE_RECVMMSG_SSIZE_T_CONST_TIMEOUT) /* FreeBSD */ ssize_t recvmmsg(int sockfd, struct mmsghdr *msgvec, size_t vlen, int flags, const struct timespec *timeout) #elif defined(HAVE_RECVMMSG_CONST_TIMEOUT) /* Linux legacy glibc < 2.21 */ int recvmmsg(int sockfd, struct mmsghdr *msgvec, unsigned int vlen, int flags, const struct timespec *timeout) #else /* Linux glibc >= 2.21 */ int recvmmsg(int sockfd, struct mmsghdr *msgvec, unsigned int vlen, int flags, struct timespec *timeout) #endif { return swrap_recvmmsg(sockfd, msgvec, vlen, flags, timeout); } #endif /* HAVE_RECVMMSG */ /**************************************************************************** * 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) { int scm_rights_pipe_fd = -1; rc = swrap_sendmsg_before_unix(omsg, &msg, &scm_rights_pipe_fd); if (rc < 0) { return rc; } ret = libc_sendmsg(s, &msg, flags); return swrap_sendmsg_after_unix(&msg, ret, scm_rights_pipe_fd); } ZERO_STRUCT(un_addr); tmp.iov_base = NULL; tmp.iov_len = 0; ZERO_STRUCT(msg); SWRAP_LOCK_SI(si); if (si->connected == 0) { msg.msg_name = omsg->msg_name; /* optional address */ msg.msg_namelen = omsg->msg_namelen; /* size of address */ } msg.msg_iov = omsg->msg_iov; /* scatter/gather array */ msg.msg_iovlen = omsg->msg_iovlen; /* # elements in msg_iov */ SWRAP_UNLOCK_SI(si); #ifdef HAVE_STRUCT_MSGHDR_MSG_CONTROL if (omsg != NULL && omsg->msg_controllen > 0 && omsg->msg_control != NULL) { uint8_t *cmbuf = NULL; size_t cmlen = 0; rc = swrap_sendmsg_filter_cmsghdr(omsg, &cmbuf, &cmlen); if (rc < 0) { return rc; } if (cmlen == 0) { msg.msg_controllen = 0; msg.msg_control = NULL; } else { msg.msg_control = cmbuf; msg.msg_controllen = cmlen; } } 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) { int saved_errno = errno; #ifdef HAVE_STRUCT_MSGHDR_MSG_CONTROL SAFE_FREE(msg.msg_control); #endif errno = saved_errno; return -1; } if (bcast) { struct stat st; unsigned int iface; unsigned int prt = ntohs(((const struct sockaddr_in *)(const void *)to)->sin_port); char type; size_t i, len = 0; uint8_t *buf; off_t ofs = 0; size_t avail = 0; size_t remain; char *swrap_dir = NULL; for (i = 0; i < (size_t)msg.msg_iovlen; i++) { avail += msg.msg_iov[i].iov_len; } len = avail; remain = avail; /* we capture it as one single packet */ buf = (uint8_t *)malloc(remain); if (!buf) { int saved_errno = errno; #ifdef HAVE_STRUCT_MSGHDR_MSG_CONTROL SAFE_FREE(msg.msg_control); #endif 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; } type = SOCKET_TYPE_CHAR_UDP; swrap_dir = socket_wrapper_dir(); if (swrap_dir == NULL) { int saved_errno = errno; #ifdef HAVE_STRUCT_MSGHDR_MSG_CONTROL SAFE_FREE(msg.msg_control); #endif SAFE_FREE(buf); errno = saved_errno; return -1; } for(iface=0; iface <= MAX_WRAPPED_INTERFACES; iface++) { swrap_un_path(&un_addr, swrap_dir, type, iface, prt); if (stat(un_addr.sun_path, &st) != 0) continue; msg.msg_name = &un_addr; /* optional address */ msg.msg_namelen = sizeof(un_addr); /* size of address */ /* ignore the any errors in broadcast sends */ libc_sendmsg(s, &msg, flags); } SAFE_FREE(swrap_dir); SWRAP_LOCK_SI(si); swrap_pcap_dump_packet(si, to, SWRAP_SENDTO, buf, len); free(buf); SWRAP_UNLOCK_SI(si); return len; } ret = libc_sendmsg(s, &msg, flags); swrap_sendmsg_after(s, si, &msg, to, ret); #ifdef HAVE_STRUCT_MSGHDR_MSG_CONTROL { int saved_errno = errno; SAFE_FREE(msg.msg_control); errno = saved_errno; } #endif return ret; } ssize_t sendmsg(int s, const struct msghdr *omsg, int flags) { return swrap_sendmsg(s, omsg, flags); } /**************************************************************************** * SENDMMSG ***************************************************************************/ #ifdef HAVE_SENDMMSG #if defined(HAVE_SENDMMSG_SSIZE_T) /* FreeBSD */ static ssize_t swrap_sendmmsg(int s, struct mmsghdr *omsgvec, size_t _vlen, int flags) #else /* Linux */ static int swrap_sendmmsg(int s, struct mmsghdr *omsgvec, unsigned int _vlen, int flags) #endif { struct socket_info *si = find_socket_info(s); #define __SWRAP_SENDMMSG_MAX_VLEN 16 struct mmsghdr msgvec[__SWRAP_SENDMMSG_MAX_VLEN] = {}; struct { struct iovec iov; struct sockaddr_un un_addr; const struct sockaddr_un *to_un; const struct sockaddr *to; int bcast; } tmp[__SWRAP_SENDMMSG_MAX_VLEN] = {}; int vlen; int i; char *swrap_dir = NULL; int connected = 0; int found_bcast = 0; int ret; int rc; int saved_errno; if (_vlen > __SWRAP_SENDMMSG_MAX_VLEN) { vlen = __SWRAP_SENDMMSG_MAX_VLEN; } else { vlen = _vlen; } if (!si) { int scm_rights_pipe_fd[__SWRAP_SENDMMSG_MAX_VLEN]; for (i = 0; i < __SWRAP_SENDMMSG_MAX_VLEN; i++) { scm_rights_pipe_fd[i] = -1; } for (i = 0; i < vlen; i++) { struct msghdr *omsg = &omsgvec[i].msg_hdr; struct msghdr *msg = &msgvec[i].msg_hdr; rc = swrap_sendmsg_before_unix(omsg, msg, &scm_rights_pipe_fd[i]); if (rc < 0) { ret = rc; goto fail_libc; } } ret = libc_sendmmsg(s, msgvec, vlen, flags); if (ret < 0) { goto fail_libc; } for (i = 0; i < ret; i++) { omsgvec[i].msg_len = msgvec[i].msg_len; } fail_libc: saved_errno = errno; for (i = 0; i < vlen; i++) { struct msghdr *msg = &msgvec[i].msg_hdr; swrap_sendmsg_after_unix(msg, ret, scm_rights_pipe_fd[i]); } errno = saved_errno; return ret; } SWRAP_LOCK_SI(si); connected = si->connected; SWRAP_UNLOCK_SI(si); for (i = 0; i < vlen; i++) { struct msghdr *omsg = &omsgvec[i].msg_hdr; struct msghdr *msg = &msgvec[i].msg_hdr; if (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 (omsg->msg_controllen > 0 && omsg->msg_control != NULL) { uint8_t *cmbuf = NULL; size_t cmlen = 0; rc = swrap_sendmsg_filter_cmsghdr(omsg, &cmbuf, &cmlen); if (rc < 0) { ret = rc; goto fail_swrap; } if (cmlen != 0) { msg->msg_control = cmbuf; msg->msg_controllen = cmlen; } } msg->msg_flags = omsg->msg_flags; /* flags on received message */ #endif rc = swrap_sendmsg_before(s, si, msg, &tmp[i].iov, &tmp[i].un_addr, &tmp[i].to_un, &tmp[i].to, &tmp[i].bcast); if (rc < 0) { ret = rc; goto fail_swrap; } if (tmp[i].bcast) { found_bcast = 1; } } if (found_bcast) { swrap_dir = socket_wrapper_dir(); if (swrap_dir == NULL) { ret = -1; goto fail_swrap; } for (i = 0; i < vlen; i++) { struct msghdr *msg = &msgvec[i].msg_hdr; struct sockaddr_un *un_addr = &tmp[i].un_addr; const struct sockaddr *to = tmp[i].to; struct stat st; unsigned int iface; unsigned int prt = ntohs(((const struct sockaddr_in *)(const void *)to)->sin_port); char type; size_t l, len = 0; uint8_t *buf; off_t ofs = 0; size_t avail = 0; size_t remain; for (l = 0; l < (size_t)msg->msg_iovlen; l++) { avail += msg->msg_iov[l].iov_len; } len = avail; remain = avail; /* we capture it as one single packet */ buf = (uint8_t *)malloc(remain); if (!buf) { ret = -1; goto fail_swrap; } for (l = 0; l < (size_t)msg->msg_iovlen; l++) { size_t this_time = MIN(remain, (size_t)msg->msg_iov[l].iov_len); memcpy(buf + ofs, msg->msg_iov[l].iov_base, this_time); ofs += this_time; remain -= this_time; } type = SOCKET_TYPE_CHAR_UDP; for(iface=0; iface <= MAX_WRAPPED_INTERFACES; iface++) { swrap_un_path(un_addr, swrap_dir, type, iface, prt); if (stat(un_addr->sun_path, &st) != 0) continue; msg->msg_name = un_addr; /* optional address */ msg->msg_namelen = sizeof(*un_addr); /* size of address */ /* * ignore the any errors in broadcast sends and * do a single sendmsg instead of sendmmsg */ libc_sendmsg(s, msg, flags); } SWRAP_LOCK_SI(si); swrap_pcap_dump_packet(si, to, SWRAP_SENDTO, buf, len); SWRAP_UNLOCK_SI(si); SAFE_FREE(buf); msgvec[i].msg_len = len; } ret = vlen; goto bcast_done; } ret = libc_sendmmsg(s, msgvec, vlen, flags); if (ret < 0) { goto fail_swrap; } bcast_done: for (i = 0; i < ret; i++) { omsgvec[i].msg_len = msgvec[i].msg_len; } fail_swrap: saved_errno = errno; for (i = 0; i < vlen; i++) { struct msghdr *msg = &msgvec[i].msg_hdr; if (i == 0 || i < ret) { swrap_sendmsg_after(s, si, msg, tmp[i].to, ret); } #ifdef HAVE_STRUCT_MSGHDR_MSG_CONTROL SAFE_FREE(msg->msg_control); #endif } SAFE_FREE(swrap_dir); errno = saved_errno; return ret; } #if defined(HAVE_SENDMMSG_SSIZE_T) /* FreeBSD */ ssize_t sendmmsg(int s, struct mmsghdr *msgvec, size_t vlen, int flags) #else /* Linux */ int sendmmsg(int s, struct mmsghdr *msgvec, unsigned int vlen, int flags) #endif { return swrap_sendmmsg(s, msgvec, vlen, flags); } #endif /* HAVE_SENDMMSG */ /**************************************************************************** * READV ***************************************************************************/ static ssize_t swrap_readv(int s, const struct iovec *vector, int count) { struct socket_info *si; struct msghdr msg; struct iovec tmp; struct swrap_address saddr = { .sa_socklen = sizeof(struct sockaddr_storage) }; ssize_t ret; int rc; si = find_socket_info(s); if (si == NULL) { return libc_readv(s, vector, count); } tmp.iov_base = NULL; tmp.iov_len = 0; ZERO_STRUCT(msg); msg.msg_name = &saddr.sa.s; /* optional address */ msg.msg_namelen = saddr.sa_socklen; /* size of address */ msg.msg_iov = discard_const_p(struct iovec, vector); /* scatter/gather array */ msg.msg_iovlen = count; /* # elements in msg_iov */ #ifdef HAVE_STRUCT_MSGHDR_MSG_CONTROL msg.msg_control = NULL; /* ancillary data, see below */ msg.msg_controllen = 0; /* ancillary data buffer len */ msg.msg_flags = 0; /* flags on received message */ #endif rc = swrap_recvmsg_before(s, si, &msg, &tmp); if (rc < 0) { if (rc == -ENOTSOCK) { return libc_readv(s, vector, count); } return -1; } ret = libc_readv(s, msg.msg_iov, msg.msg_iovlen); rc = swrap_recvmsg_after(s, si, &msg, NULL, 0, ret); if (rc != 0) { return rc; } return ret; } ssize_t readv(int s, const struct iovec *vector, int count) { return swrap_readv(s, vector, count); } /**************************************************************************** * WRITEV ***************************************************************************/ static ssize_t swrap_writev(int s, const struct iovec *vector, int count) { struct msghdr msg; struct iovec tmp; struct sockaddr_un un_addr; ssize_t ret; int rc; struct socket_info *si = find_socket_info(s); if (!si) { return libc_writev(s, vector, count); } tmp.iov_base = NULL; tmp.iov_len = 0; ZERO_STRUCT(msg); msg.msg_name = NULL; /* optional address */ msg.msg_namelen = 0; /* size of address */ msg.msg_iov = discard_const_p(struct iovec, vector); /* scatter/gather array */ msg.msg_iovlen = count; /* # elements in msg_iov */ #ifdef HAVE_STRUCT_MSGHDR_MSG_CONTROL msg.msg_control = NULL; /* ancillary data, see below */ msg.msg_controllen = 0; /* ancillary data buffer len */ msg.msg_flags = 0; /* flags on received message */ #endif rc = swrap_sendmsg_before(s, si, &msg, &tmp, &un_addr, NULL, NULL, NULL); if (rc < 0) { if (rc == -ENOTSOCK) { return libc_readv(s, vector, count); } return -1; } ret = libc_writev(s, msg.msg_iov, msg.msg_iovlen); swrap_sendmsg_after(s, si, &msg, NULL, ret); return ret; } ssize_t writev(int s, const struct iovec *vector, int count) { return swrap_writev(s, vector, count); } /**************************** * CLOSE ***************************/ static int swrap_remove_wrapper(const char *__func_name, int (*__close_fd_fn)(int fd), int fd) { struct socket_info *si = NULL; int si_index; int ret_errno = errno; int ret; swrap_mutex_lock(&socket_reset_mutex); si_index = find_socket_info_index(fd); if (si_index == -1) { swrap_mutex_unlock(&socket_reset_mutex); return __close_fd_fn(fd); } swrap_log(SWRAP_LOG_TRACE, __func_name, "Remove wrapper for fd=%d", fd); reset_socket_info_index(fd); si = swrap_get_socket_info(si_index); swrap_mutex_lock(&first_free_mutex); SWRAP_LOCK_SI(si); ret = __close_fd_fn(fd); if (ret == -1) { ret_errno = errno; } swrap_dec_refcount(si); if (swrap_get_refcount(si) > 0) { /* there are still references left */ goto out; } if (si->fd_passed) { goto set_next_free; } if (si->myname.sa_socklen > 0 && si->peername.sa_socklen > 0) { swrap_pcap_dump_packet(si, NULL, SWRAP_CLOSE_SEND, NULL, 0); } if (si->myname.sa_socklen > 0 && si->peername.sa_socklen > 0) { swrap_pcap_dump_packet(si, NULL, SWRAP_CLOSE_RECV, NULL, 0); swrap_pcap_dump_packet(si, NULL, SWRAP_CLOSE_ACK, NULL, 0); } if (si->un_addr.sun_path[0] != '\0') { unlink(si->un_addr.sun_path); } set_next_free: swrap_set_next_free(si, first_free); first_free = si_index; out: SWRAP_UNLOCK_SI(si); swrap_mutex_unlock(&first_free_mutex); swrap_mutex_unlock(&socket_reset_mutex); errno = ret_errno; return ret; } static int swrap_noop_close(int fd) { (void)fd; /* unused */ return 0; } static void swrap_remove_stale(int fd) { swrap_remove_wrapper(__func__, swrap_noop_close, fd); } /* * This allows socket_wrapper aware applications to * indicate that the given fd does not belong to * an inet socket. * * We already overload a lot of unrelated functions * like eventfd(), timerfd_create(), ... in order to * call swrap_remove_stale() on the returned fd, but * we'll never be able to handle all possible syscalls. * * socket_wrapper_indicate_no_inet_fd() gives them a way * to do the same. * * We don't export swrap_remove_stale() in order to * make it easier to analyze SOCKET_WRAPPER_DEBUGLEVEL=3 * log files. */ void socket_wrapper_indicate_no_inet_fd(int fd) { swrap_remove_wrapper(__func__, swrap_noop_close, fd); } static int swrap_close(int fd) { return swrap_remove_wrapper(__func__, libc_close, fd); } int close(int fd) { return swrap_close(fd); } #ifdef HAVE___CLOSE_NOCANCEL static int swrap___close_nocancel(int fd) { return swrap_remove_wrapper(__func__, libc___close_nocancel, fd); } int __close_nocancel(int fd); int __close_nocancel(int fd) { return swrap___close_nocancel(fd); } #endif /* HAVE___CLOSE_NOCANCEL */ /**************************** * DUP ***************************/ static int swrap_dup(int fd) { struct socket_info *si; int dup_fd, idx; idx = find_socket_info_index(fd); if (idx == -1) { return libc_dup(fd); } si = swrap_get_socket_info(idx); dup_fd = libc_dup(fd); if (dup_fd == -1) { int saved_errno = errno; errno = saved_errno; return -1; } if ((size_t)dup_fd >= socket_fds_max) { SWRAP_LOG(SWRAP_LOG_ERROR, "The max socket index limit of %zu has been reached, " "trying to add %d", socket_fds_max, dup_fd); libc_close(dup_fd); errno = EMFILE; return -1; } SWRAP_LOCK_SI(si); swrap_inc_refcount(si); SWRAP_UNLOCK_SI(si); /* Make sure we don't have an entry for the fd */ swrap_remove_stale(dup_fd); set_socket_info_index(dup_fd, idx); return dup_fd; } int dup(int fd) { return swrap_dup(fd); } /**************************** * DUP2 ***************************/ static int swrap_dup2(int fd, int newfd) { struct socket_info *si; int dup_fd, idx; idx = find_socket_info_index(fd); if (idx == -1) { return libc_dup2(fd, newfd); } si = swrap_get_socket_info(idx); if (fd == newfd) { /* * According to the manpage: * * "If oldfd is a valid file descriptor, and newfd has the same * value as oldfd, then dup2() does nothing, and returns newfd." */ return newfd; } if ((size_t)newfd >= socket_fds_max) { SWRAP_LOG(SWRAP_LOG_ERROR, "The max socket index limit of %zu has been reached, " "trying to add %d", socket_fds_max, newfd); errno = EMFILE; return -1; } if (find_socket_info(newfd)) { /* dup2() does an implicit close of newfd, which we * need to emulate */ swrap_close(newfd); } dup_fd = libc_dup2(fd, newfd); if (dup_fd == -1) { int saved_errno = errno; errno = saved_errno; return -1; } SWRAP_LOCK_SI(si); swrap_inc_refcount(si); SWRAP_UNLOCK_SI(si); /* Make sure we don't have an entry for the fd */ swrap_remove_stale(dup_fd); set_socket_info_index(dup_fd, idx); return dup_fd; } int dup2(int fd, int newfd) { return swrap_dup2(fd, newfd); } /**************************** * FCNTL ***************************/ static int swrap_vfcntl(int fd, int cmd, va_list va) { struct socket_info *si; int rc, dup_fd, idx; idx = find_socket_info_index(fd); if (idx == -1) { return libc_vfcntl(fd, cmd, va); } si = swrap_get_socket_info(idx); switch (cmd) { case F_DUPFD: dup_fd = libc_vfcntl(fd, cmd, va); if (dup_fd == -1) { int saved_errno = errno; errno = saved_errno; return -1; } /* Make sure we don't have an entry for the fd */ swrap_remove_stale(dup_fd); if ((size_t)dup_fd >= socket_fds_max) { SWRAP_LOG(SWRAP_LOG_ERROR, "The max socket index limit of %zu has been reached, " "trying to add %d", socket_fds_max, dup_fd); libc_close(dup_fd); errno = EMFILE; return -1; } SWRAP_LOCK_SI(si); swrap_inc_refcount(si); SWRAP_UNLOCK_SI(si); set_socket_info_index(dup_fd, idx); rc = dup_fd; break; default: rc = libc_vfcntl(fd, cmd, va); break; } return rc; } #undef fcntl /* Needed for LFS handling */ 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; } /**************************** * FCNTL64 ***************************/ #ifdef HAVE_FCNTL64 static int swrap_vfcntl64(int fd, int cmd, va_list va) { struct socket_info *si; int rc, dup_fd, idx; idx = find_socket_info_index(fd); if (idx == -1) { return libc_vfcntl64(fd, cmd, va); } si = swrap_get_socket_info(idx); switch (cmd) { case F_DUPFD: dup_fd = libc_vfcntl64(fd, cmd, va); if (dup_fd == -1) { int saved_errno = errno; errno = saved_errno; return -1; } /* Make sure we don't have an entry for the fd */ swrap_remove_stale(dup_fd); if ((size_t)dup_fd >= socket_fds_max) { SWRAP_LOG(SWRAP_LOG_ERROR, "The max socket index limit of %zu has been reached, " "trying to add %d", socket_fds_max, dup_fd); libc_close(dup_fd); errno = EMFILE; return -1; } SWRAP_LOCK_SI(si); swrap_inc_refcount(si); SWRAP_UNLOCK_SI(si); set_socket_info_index(dup_fd, idx); rc = dup_fd; break; default: rc = libc_vfcntl64(fd, cmd, va); break; } return rc; } int fcntl64(int fd, int cmd, ...) { va_list va; int rc; va_start(va, cmd); rc = swrap_vfcntl64(fd, cmd, va); va_end(va); return rc; } #endif /**************************** * EVENTFD ***************************/ #ifdef HAVE_EVENTFD static int swrap_eventfd(int count, int flags) { int fd; fd = libc_eventfd(count, flags); if (fd != -1) { swrap_remove_stale(fd); } return fd; } #ifdef HAVE_EVENTFD_UNSIGNED_INT int eventfd(unsigned int count, int flags) #else int eventfd(int count, int flags) #endif { return swrap_eventfd(count, flags); } #endif #ifdef HAVE_PLEDGE int pledge(const char *promises, const char *paths[]) { (void)promises; /* unused */ (void)paths; /* unused */ return 0; } #endif /* HAVE_PLEDGE */ #ifdef HAVE_SYSCALL static bool swrap_is_swrap_related_syscall(long int sysno) { switch (sysno) { #ifdef SYS_close case SYS_close: return true; #endif /* SYS_close */ #ifdef SYS_recvmmsg case SYS_recvmmsg: return true; #endif /* SYS_recvmmsg */ #ifdef SYS_sendmmsg case SYS_sendmmsg: return true; #endif /* SYS_sendmmsg */ default: return false; } } static long int swrap_syscall(long int sysno, va_list vp) { long int rc; switch (sysno) { #ifdef SYS_close case SYS_close: { int fd = (int)va_arg(vp, int); SWRAP_LOG(SWRAP_LOG_TRACE, "calling swrap_close syscall %lu", sysno); rc = swrap_close(fd); } break; #endif /* SYS_close */ #ifdef SYS_recvmmsg case SYS_recvmmsg: { int fd = (int)va_arg(vp, int); struct mmsghdr *msgvec = va_arg(vp, struct mmsghdr *); unsigned int vlen = va_arg(vp, unsigned int); int flags = va_arg(vp, int); struct timespec *timeout = va_arg(vp, struct timespec *); SWRAP_LOG(SWRAP_LOG_TRACE, "calling swrap_recvmmsg syscall %lu", sysno); rc = swrap_recvmmsg(fd, msgvec, vlen, flags, timeout); } break; #endif /* SYS_recvmmsg */ #ifdef SYS_sendmmsg case SYS_sendmmsg: { int fd = (int)va_arg(vp, int); struct mmsghdr *msgvec = va_arg(vp, struct mmsghdr *); unsigned int vlen = va_arg(vp, unsigned int); int flags = va_arg(vp, int); SWRAP_LOG(SWRAP_LOG_TRACE, "calling swrap_sendmmsg syscall %lu", sysno); rc = swrap_sendmmsg(fd, msgvec, vlen, flags); } break; #endif /* SYS_sendmmsg */ default: rc = -1; errno = ENOSYS; break; } return rc; } #ifdef HAVE_SYSCALL_INT int syscall(int sysno, ...) #else long int syscall(long int sysno, ...) #endif { #ifdef HAVE_SYSCALL_INT int rc; #else long int rc; #endif va_list va; va_start(va, sysno); /* * JEMALLOC: * * This is a workaround to prevent a deadlock in jemalloc calling * malloc_init() twice. The first allocation call will trigger a * malloc_init() of jemalloc. The functions calls syscall(SYS_open, ...) * so it goes to socket or uid wrapper. In this code path we need to * avoid any allocation calls. This will prevent the deadlock. */ if (!swrap_handle_syscall) { rc = libc_vsyscall(sysno, va); va_end(va); return rc; } /* * We should only handle the syscall numbers * we care about... */ if (!swrap_is_swrap_related_syscall(sysno)) { /* * We need to give socket_wrapper a * chance to take over... */ if (swrap_uwrap_syscall_valid(sysno)) { rc = swrap_uwrap_syscall_va(sysno, va); va_end(va); return rc; } rc = libc_vsyscall(sysno, va); va_end(va); return rc; } if (!socket_wrapper_enabled()) { rc = libc_vsyscall(sysno, va); va_end(va); return rc; } rc = swrap_syscall(sysno, va); va_end(va); return rc; } /* used by uid_wrapper */ bool socket_wrapper_syscall_valid(long int sysno); bool socket_wrapper_syscall_valid(long int sysno) { if (!swrap_is_swrap_related_syscall(sysno)) { return false; } if (!socket_wrapper_enabled()) { return false; } return true; } /* used by uid_wrapper */ long int socket_wrapper_syscall_va(long int sysno, va_list va); long int socket_wrapper_syscall_va(long int sysno, va_list va) { if (!swrap_is_swrap_related_syscall(sysno)) { errno = ENOSYS; return -1; } if (!socket_wrapper_enabled()) { return libc_vsyscall(sysno, va); } return swrap_syscall(sysno, va); } #endif /* HAVE_SYSCALL */ static void swrap_thread_prepare(void) { /* * This function should only be called here!! * * We bind all symobls to avoid deadlocks of the fork is * interrupted by a signal handler using a symbol of this * library. */ swrap_bind_symbol_all(); SWRAP_LOCK_ALL; } static void swrap_thread_parent(void) { SWRAP_UNLOCK_ALL; } static void swrap_thread_child(void) { SWRAP_REINIT_ALL; } /**************************** * CONSTRUCTOR ***************************/ void swrap_constructor(void) { if (PIPE_BUF < sizeof(struct swrap_unix_scm_rights)) { SWRAP_LOG(SWRAP_LOG_ERROR, "PIPE_BUF=%zu < " "sizeof(struct swrap_unix_scm_rights)=%zu\n" "sizeof(struct swrap_unix_scm_rights_payload)=%zu " "sizeof(struct socket_info)=%zu", (size_t)PIPE_BUF, sizeof(struct swrap_unix_scm_rights), sizeof(struct swrap_unix_scm_rights_payload), sizeof(struct socket_info)); exit(-1); } SWRAP_REINIT_ALL; /* * If we hold a lock and the application forks, then the child * is not able to unlock the mutex and we are in a deadlock. * This should prevent such deadlocks. */ pthread_atfork(&swrap_thread_prepare, &swrap_thread_parent, &swrap_thread_child); /* Let socket_wrapper handle syscall() */ swrap_handle_syscall = true; } /**************************** * DESTRUCTOR ***************************/ /* * This function is called when the library is unloaded and makes sure that * sockets get closed and the unix file for the socket are unlinked. */ void swrap_destructor(void) { size_t i; if (socket_fds_idx != NULL) { for (i = 0; i < socket_fds_max; ++i) { if (socket_fds_idx[i] != -1) { swrap_close(i); } } SAFE_FREE(socket_fds_idx); } SAFE_FREE(sockets); if (swrap.libc.handle != NULL #ifdef RTLD_NEXT && swrap.libc.handle != RTLD_NEXT #endif ) { dlclose(swrap.libc.handle); } if (swrap.libc.socket_handle #ifdef RTLD_NEXT && swrap.libc.socket_handle != RTLD_NEXT #endif ) { dlclose(swrap.libc.socket_handle); } } #if defined(HAVE__SOCKET) && defined(HAVE__CLOSE) /* * On FreeBSD 12 (and maybe other platforms) * system libraries like libresolv prefix there * syscalls with '_' in order to always use * the symbols from libc. * * In the interaction with resolv_wrapper, * we need to inject socket wrapper into libresolv, * which means we need to private all socket * related syscalls also with the '_' prefix. * * This is tested in Samba's 'make test', * there we noticed that providing '_read', * '_open' and '_close' would cause errors, which * means we skip '_read', '_write' and * all non socket related calls without * further analyzing the problem. */ #define SWRAP_SYMBOL_ALIAS(__sym, __aliassym) \ extern typeof(__sym) __aliassym __attribute__ ((alias(#__sym))) #ifdef HAVE_ACCEPT4 SWRAP_SYMBOL_ALIAS(accept4, _accept4); #endif SWRAP_SYMBOL_ALIAS(accept, _accept); SWRAP_SYMBOL_ALIAS(bind, _bind); SWRAP_SYMBOL_ALIAS(connect, _connect); SWRAP_SYMBOL_ALIAS(dup, _dup); SWRAP_SYMBOL_ALIAS(dup2, _dup2); SWRAP_SYMBOL_ALIAS(fcntl, _fcntl); SWRAP_SYMBOL_ALIAS(getpeername, _getpeername); SWRAP_SYMBOL_ALIAS(getsockname, _getsockname); SWRAP_SYMBOL_ALIAS(getsockopt, _getsockopt); SWRAP_SYMBOL_ALIAS(ioctl, _ioctl); SWRAP_SYMBOL_ALIAS(listen, _listen); SWRAP_SYMBOL_ALIAS(readv, _readv); SWRAP_SYMBOL_ALIAS(recv, _recv); SWRAP_SYMBOL_ALIAS(recvfrom, _recvfrom); SWRAP_SYMBOL_ALIAS(recvmsg, _recvmsg); SWRAP_SYMBOL_ALIAS(send, _send); SWRAP_SYMBOL_ALIAS(sendmsg, _sendmsg); SWRAP_SYMBOL_ALIAS(sendto, _sendto); SWRAP_SYMBOL_ALIAS(setsockopt, _setsockopt); SWRAP_SYMBOL_ALIAS(socket, _socket); SWRAP_SYMBOL_ALIAS(socketpair, _socketpair); SWRAP_SYMBOL_ALIAS(writev, _writev); #endif /* SOCKET_WRAPPER_EXPORT_UNDERSCORE_SYMBOLS */ socket_wrapper-1.4.4/src/socket_wrapper.h000644 001750 000144 00000006736 14631527256 020547 0ustar00asnusers000000 000000 /* * BSD 3-Clause License * * Copyright (c) 2005-2008, Jelmer Vernooij * Copyright (c) 2006-2021, Stefan Metzmacher * Copyright (c) 2013-2021, Andreas Schneider * Copyright (c) 2014-2017, Michael Adam * Copyright (c) 2016-2018, Anoop C S * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * 3. Neither the name of the author nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef __SOCKET_WRAPPER_H__ #define __SOCKET_WRAPPER_H__ 1 #include /* Socket wrapper advanced helpers. Applications with the need to alter their behaviour when socket wrapper is active, can link use these functions. By default it's required for applications to use any of these functions as libsocket_wrapper.so is injected at runtime via LD_PRELOAD. Applications using these functions should link against libsocket_wrapper_noop.so by using -lsocket_wrapper_noop, or implement their own noop stubs. */ /* * This returns true when socket wrapper is actively in use. */ bool socket_wrapper_enabled(void); /* * This allows socket_wrapper aware applications to * indicate that the given fd does not belong to * an inet socket. * * socket_wrapper may not be able to intercept the __close_nocancel() * syscall made from within libc.so. As result it's possible * that the in memory meta date of socket_wrapper references * stale file descriptors, which are already reused for unrelated * kernel objects, e.g. files, directories, ... * * Socket wrapper already intercepts a lot of unrelated * functions like eventfd(), timerfd_create(), ... in order * to remove stale meta data for the returned fd, but * it will never be able to handle all possible syscalls. * * socket_wrapper_indicate_no_inet_fd() gives applications a way * to do the same, explicitly without waiting for new syscalls to * be added to libsocket_wrapper.so. * * This is a no-op if socket_wrapper is not in use or * if the there is no in memory meta data for the given fd. */ void socket_wrapper_indicate_no_inet_fd(int fd); #endif /* __SOCKET_WRAPPER_H__ */ socket_wrapper-1.4.4/README.md000644 001750 000144 00000000766 14631527256 016033 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.4.4/.gitlab-ci.yml000644 001750 000144 00000016466 14632503553 017207 0ustar00asnusers000000 000000 --- variables: BUILD_IMAGES_PROJECT: cmocka/gitlab-build-images FEDORA_BUILD: buildenv-fedora CENTOS7_BUILD: buildenv-centos7 TUMBLEWEED_BUILD: buildenv-tumbleweed MINGW_BUILD: buildenv-mingw UBUNTU_BUILD: buildenv-ubuntu UBUNTU32_BUILD: buildenv-ubuntu32 stages: - build - test - analysis centos7/x86_64: stage: test image: $CI_REGISTRY/$BUILD_IMAGES_PROJECT:$CENTOS7_BUILD script: - mkdir -p obj && cd obj && cmake3 -DCMAKE_BUILD_TYPE=RelWithDebInfo -DPICKY_DEVELOPER=ON -DUNIT_TESTING=ON .. && make -j$(nproc) && ctest --output-on-failure except: - tags artifacts: expire_in: 1 week when: on_failure paths: - obj/ fedora/x86_64: stage: test image: $CI_REGISTRY/$BUILD_IMAGES_PROJECT:$FEDORA_BUILD script: - mkdir -p obj && cd obj && cmake -DCMAKE_BUILD_TYPE=RelWithDebInfo -DPICKY_DEVELOPER=ON -DUNIT_TESTING=ON .. && make -j$(nproc) && ctest --output-on-failure except: - tags artifacts: expire_in: 1 week when: on_failure paths: - obj/ fedora/address-sanitizer: stage: build image: $CI_REGISTRY/$BUILD_IMAGES_PROJECT:$FEDORA_BUILD script: - mkdir -p obj && cd obj && cmake -DCMAKE_BUILD_TYPE=AddressSanitizer -DPICKY_DEVELOPER=ON -DUNIT_TESTING=ON .. && make -j$(nproc) && ctest --output-on-failure except: - tags artifacts: expire_in: 1 week when: on_failure paths: - obj/ fedora/undefined-sanitizer: stage: analysis image: $CI_REGISTRY/$BUILD_IMAGES_PROJECT:$FEDORA_BUILD script: - mkdir -p obj && cd obj && cmake -DCMAKE_BUILD_TYPE=UndefinedSanitizer -DUNIT_TESTING=ON .. && make -j$(nproc) && ctest --output-on-failure except: - tags artifacts: expire_in: 1 week when: on_failure paths: - obj/ # realpath() doesn't work with libtsan and returns EINVAL # # fedora/thread-sanitizer: tumbleweed/thread-sanitizer: stage: analysis image: $CI_REGISTRY/$BUILD_IMAGES_PROJECT:$TUMBLEWEED_BUILD script: # Workaround for TSAN with ASLR on newer kernel # https://github.com/google/sanitizers/issues/1716 - mkdir -p obj && cd obj && cmake -DCMAKE_BUILD_TYPE=ThreadSanitizer -DPICKY_DEVELOPER=ON -DUNIT_TESTING=ON .. && make -j$(nproc) && setarch --addr-no-randomize -- ctest --output-on-failure except: - tags artifacts: expire_in: 1 week when: on_failure paths: - obj/ fedora/csbuild: stage: analysis image: $CI_REGISTRY/$BUILD_IMAGES_PROJECT:$FEDORA_BUILD script: - | if [[ -z "$CI_COMMIT_BEFORE_SHA" ]]; then export CI_COMMIT_BEFORE_SHA=$(git rev-parse "${CI_COMMIT_SHA}~20") fi # Check if the commit exists in this branch # This is not the case for a force push git branch --contains $CI_COMMIT_BEFORE_SHA 2>/dev/null || export CI_COMMIT_BEFORE_SHA=$(git rev-parse "${CI_COMMIT_SHA}~20") export CI_COMMIT_RANGE="$CI_COMMIT_BEFORE_SHA..$CI_COMMIT_SHA" - csbuild --build-dir=obj-csbuild --prep-cmd="cmake -DCMAKE_BUILD_TYPE=Debug -DPICKY_DEVELOPER=ON -DUNIT_TESTING=ON @SRCDIR@" --build-cmd "make clean && make -j$(nproc)" --git-commit-range $CI_COMMIT_RANGE --color --print-current --print-fixed except: - tags artifacts: expire_in: 1 week when: on_failure paths: - obj-csbuild/ freebsd/x86_64: stage: test image: script: - mkdir -p obj && cd obj && cmake -DCMAKE_BUILD_TYPE=RelWithDebInfo -DPICKY_DEVELOPER=ON -DUNIT_TESTING=ON .. && make && ctest --output-on-failure tags: - freebsd except: - tags only: - branches@cwrap/socket_wrapper - branches@cryptomilk/socket_wrapper - branches@metze/socket_wrapper artifacts: expire_in: 1 week when: on_failure paths: - obj/ tumbleweed/x86_64/gcc: stage: test image: $CI_REGISTRY/$BUILD_IMAGES_PROJECT:$TUMBLEWEED_BUILD script: - mkdir -p obj && cd obj && cmake -DCMAKE_BUILD_TYPE=RelWithDebInfo -DPICKY_DEVELOPER=ON -DUNIT_TESTING=ON .. && make -j$(nproc) && ctest --output-on-failure except: - tags artifacts: expire_in: 1 week when: on_failure paths: - obj/ tumbleweed/x86_64/gcc7: stage: test image: $CI_REGISTRY/$BUILD_IMAGES_PROJECT:$TUMBLEWEED_BUILD script: - mkdir -p obj && cd obj && cmake -DCMAKE_C_COMPILER=gcc-7 -DCMAKE_CXX_COMPILER=g++-7 -DCMAKE_BUILD_TYPE=RelWithDebInfo -DPICKY_DEVELOPER=ON -DUNIT_TESTING=ON .. && make -j$(nproc) && ctest --output-on-failure except: - tags artifacts: expire_in: 1 week when: on_failure paths: - obj/ tumbleweed/x86_64/clang: stage: test image: $CI_REGISTRY/$BUILD_IMAGES_PROJECT:$TUMBLEWEED_BUILD script: - mkdir -p obj && cd obj && cmake -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -DPICKY_DEVELOPER=ON -DUNIT_TESTING=ON .. && make -j$(nproc) && ctest --output-on-failure except: - tags artifacts: expire_in: 1 week when: on_failure paths: - obj/ tumbleweed/x86/gcc: stage: test image: $CI_REGISTRY/$BUILD_IMAGES_PROJECT:$TUMBLEWEED_BUILD script: - mkdir -p obj && cd obj && cmake -DCMAKE_TOOLCHAIN_FILE=../cmake/Toolchain-cross-m32.cmake -DCMAKE_BUILD_TYPE=RelWithDebInfo -DPICKY_DEVELOPER=ON -DUNIT_TESTING=ON .. && make -j$(nproc) && ctest --output-on-failure except: - tags artifacts: expire_in: 1 week when: on_failure paths: - obj/ tumbleweed/static-analysis: stage: analysis image: $CI_REGISTRY/$BUILD_IMAGES_PROJECT:$TUMBLEWEED_BUILD script: - export CCC_CC=clang - export CCC_CXX=clang++ - mkdir -p obj && cd obj && scan-build cmake -DCMAKE_BUILD_TYPE=Debug -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -DPICKY_DEVELOPER=ON -DUNIT_TESTING=ON .. && scan-build --status-bugs -o scan make -j$(nproc) except: - tags artifacts: expire_in: 1 week when: on_failure paths: - obj/scan tumbleweed/helgrind: stage: analysis image: $CI_REGISTRY/$BUILD_IMAGES_PROJECT:$TUMBLEWEED_BUILD script: - mkdir -p obj && cd obj && cmake -DCMAKE_BUILD_TYPE=Debug -DPICKY_DEVELOPER=ON -DUNIT_TESTING=ON -DHELGRIND_TESTING=ON .. && make -j$(nproc) && ctest --output-on-failure except: - tags artifacts: expire_in: 1 week when: on_failure paths: - obj/ only: variables: - $VALGRIND_SUPPORTS_FORKED_MUTEXES == "yes" ubuntu/x86_64: stage: test image: $CI_REGISTRY/$BUILD_IMAGES_PROJECT:$UBUNTU_BUILD script: - mkdir -p obj && cd obj && cmake -DCMAKE_BUILD_TYPE=RelWithDebInfo -DPICKY_DEVELOPER=ON -DUNIT_TESTING=ON .. && make -j$(nproc) && ctest --output-on-failure except: - tags artifacts: expire_in: 1 week when: on_failure paths: - obj/ ubuntu/x86: stage: test image: $CI_REGISTRY/$BUILD_IMAGES_PROJECT:$UBUNTU32_BUILD script: - mkdir -p obj && cd obj && cmake -DCMAKE_BUILD_TYPE=RelWithDebInfo -DPICKY_DEVELOPER=ON -DUNIT_TESTING=ON .. && make -j$(nproc) && ctest --output-on-failure except: - tags artifacts: expire_in: 1 week when: on_failure paths: - obj/ socket_wrapper-1.4.4/ConfigureChecks.cmake000644 001750 000144 00000022624 14631527256 020615 0ustar00asnusers000000 000000 include(CheckIncludeFile) include(CheckSymbolExists) include(CheckFunctionExists) include(CheckLibraryExists) include(CheckTypeSize) include(CheckStructHasMember) include(CheckPrototypeDefinition) include(TestBigEndian) set(SOCKET_WRAPPER_PACKAGE ${PROJECT_NAME}) set(SOCKET_WRAPPER_VERSION ${PROJECT_VERSION}) set(BINARYDIR ${CMAKE_BINARY_DIR}) set(SOURCEDIR ${CMAKE_SOURCE_DIR}) function(COMPILER_DUMPVERSION _OUTPUT_VERSION) # Remove whitespaces from the argument. # This is needed for CC="ccache gcc" cmake .. string(REPLACE " " "" _C_COMPILER_ARG "${CMAKE_C_COMPILER_ARG1}") execute_process( COMMAND ${CMAKE_C_COMPILER} ${_C_COMPILER_ARG} -dumpversion OUTPUT_VARIABLE _COMPILER_VERSION ) string(REGEX REPLACE "([0-9])\\.([0-9])(\\.[0-9])?" "\\1\\2" _COMPILER_VERSION "${_COMPILER_VERSION}") set(${_OUTPUT_VERSION} ${_COMPILER_VERSION} PARENT_SCOPE) endfunction() if(CMAKE_COMPILER_IS_GNUCC AND NOT MINGW AND NOT OS2) compiler_dumpversion(GNUCC_VERSION) if (NOT GNUCC_VERSION EQUAL 34) set(CMAKE_REQUIRED_FLAGS "-fvisibility=hidden") check_c_source_compiles( "void __attribute__((visibility(\"default\"))) test() {} int main(void){ return 0; } " WITH_VISIBILITY_HIDDEN) unset(CMAKE_REQUIRED_FLAGS) endif (NOT GNUCC_VERSION EQUAL 34) endif(CMAKE_COMPILER_IS_GNUCC AND NOT MINGW AND NOT OS2) # HEADERS check_include_file(netinet/tcp_fsm.h HAVE_NETINET_TCP_FSM_H) 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(sys/syscall.h HAVE_SYS_SYSCALL_H) check_include_file(gnu/lib-names.h HAVE_GNU_LIB_NAMES_H) check_include_file(rpc/rpc.h HAVE_RPC_RPC_H) check_include_file(syscall.h HAVE_SYSCALL_H) # SYMBOLS set(CMAKE_REQUIRED_FLAGS -D_GNU_SOURCE) check_symbol_exists(program_invocation_short_name "errno.h" HAVE_PROGRAM_INVOCATION_SHORT_NAME) unset(CMAKE_REQUIRED_FLAGS) # FUNCTIONS check_function_exists(strncpy HAVE_STRNCPY) check_function_exists(vsnprintf HAVE_VSNPRINTF) check_function_exists(snprintf HAVE_SNPRINTF) check_function_exists(signalfd HAVE_SIGNALFD) check_function_exists(eventfd HAVE_EVENTFD) check_function_exists(timerfd_create HAVE_TIMERFD_CREATE) check_function_exists(bindresvport HAVE_BINDRESVPORT) check_function_exists(accept4 HAVE_ACCEPT4) check_function_exists(open64 HAVE_OPEN64) check_function_exists(openat64 HAVE_OPENAT64) check_function_exists(fopen64 HAVE_FOPEN64) check_function_exists(getprogname HAVE_GETPROGNAME) check_function_exists(getexecname HAVE_GETEXECNAME) check_function_exists(pledge HAVE_PLEDGE) check_function_exists(_socket HAVE__SOCKET) check_function_exists(_close HAVE__CLOSE) check_function_exists(__close_nocancel HAVE___CLOSE_NOCANCEL) check_function_exists(recvmmsg HAVE_RECVMMSG) check_function_exists(sendmmsg HAVE_SENDMMSG) check_function_exists(syscall HAVE_SYSCALL) check_function_exists(fcntl64 HAVE_FCNTL64) if (UNIX) find_library(DLFCN_LIBRARY dl) if (DLFCN_LIBRARY) list(APPEND _REQUIRED_LIBRARIES ${DLFCN_LIBRARY}) else() check_function_exists(dlopen HAVE_DLOPEN) if (NOT HAVE_DLOPEN) message(FATAL_ERROR "FATAL: No dlopen() function detected") endif() endif() if (NOT LINUX) # libsocket (Solaris) check_library_exists(socket getaddrinfo "" HAVE_LIBSOCKET) if (HAVE_LIBSOCKET) list(APPEND _REQUIRED_LIBRARIES socket) endif (HAVE_LIBSOCKET) # libnsl/inet_pton (Solaris) check_library_exists(nsl inet_pton "" HAVE_LIBNSL) if (HAVE_LIBNSL) list(APPEND _REQUIRED_LIBRARIES nsl) endif (HAVE_LIBNSL) endif (NOT LINUX) check_function_exists(getaddrinfo HAVE_GETADDRINFO) endif (UNIX) # STRUCTS check_struct_has_member("struct in_pktinfo" ipi_addr "sys/types.h;sys/socket.h;netinet/in.h" HAVE_STRUCT_IN_PKTINFO) set(CMAKE_REQUIRED_FLAGS -D_GNU_SOURCE) check_struct_has_member("struct in6_pktinfo" ipi6_addr "sys/types.h;sys/socket.h;netinet/in.h" HAVE_STRUCT_IN6_PKTINFO) unset(CMAKE_REQUIRED_FLAGS) # STRUCT MEMBERS check_struct_has_member("struct sockaddr" sa_len "sys/types.h;sys/socket.h;netinet/in.h" HAVE_STRUCT_SOCKADDR_SA_LEN) check_struct_has_member("struct msghdr" msg_control "sys/types.h;sys/socket.h" HAVE_STRUCT_MSGHDR_MSG_CONTROL) # PROTOTYPES check_prototype_definition(gettimeofday "int gettimeofday(struct timeval *tv, struct timezone *tz)" "-1" "sys/time.h" HAVE_GETTIMEOFDAY_TZ) check_prototype_definition(gettimeofday "int gettimeofday(struct timeval *tv, void *tzp)" "-1" "sys/time.h" HAVE_GETTIMEOFDAY_TZ_VOID) check_prototype_definition(accept "int accept(int s, struct sockaddr *addr, Psocklen_t addrlen)" "-1" "sys/types.h;sys/socket.h" HAVE_ACCEPT_PSOCKLEN_T) check_prototype_definition(ioctl "int ioctl(int s, int r, ...)" "-1" "unistd.h;sys/ioctl.h" HAVE_IOCTL_INT) if (HAVE_EVENTFD) check_prototype_definition(eventfd "int eventfd(unsigned int count, int flags)" "-1" "sys/eventfd.h" HAVE_EVENTFD_UNSIGNED_INT) endif (HAVE_EVENTFD) if (HAVE_SYSCALL) set(CMAKE_REQUIRED_DEFINITIONS -D_GNU_SOURCE) check_prototype_definition(syscall "int syscall(int sysno, ...)" "-1" "unistd.h;sys/syscall.h" HAVE_SYSCALL_INT) set(CMAKE_REQUIRED_DEFINITIONS) endif (HAVE_SYSCALL) if (HAVE_RECVMMSG) # Linux legacy glibc < 2.21 set(CMAKE_REQUIRED_DEFINITIONS -D_GNU_SOURCE) check_prototype_definition(recvmmsg "int recvmmsg(int __fd, struct mmsghdr *__vmessages, unsigned int __vlen, int __flags, const struct timespec *__tmo)" "-1" "sys/types.h;sys/socket.h" HAVE_RECVMMSG_CONST_TIMEOUT) set(CMAKE_REQUIRED_DEFINITIONS) # FreeBSD check_prototype_definition(recvmmsg "ssize_t recvmmsg(int __fd, struct mmsghdr * __restrict __vmessages, size_t __vlen, int __flags, const struct timespec * __restrict __tmo)" "-1" "sys/types.h;sys/socket.h" HAVE_RECVMMSG_SSIZE_T_CONST_TIMEOUT) endif (HAVE_RECVMMSG) if (HAVE_SENDMMSG) # FreeBSD check_prototype_definition(sendmmsg "ssize_t sendmmsg(int __fd, struct mmsghdr * __restrict __vmessages, size_t __vlen, int __flags)" "-1" "sys/types.h;sys/socket.h" HAVE_SENDMMSG_SSIZE_T) endif (HAVE_SENDMMSG) # IPV6 check_c_source_compiles(" #include #include #include #include #include int main(void) { struct sockaddr_storage sa_store; struct addrinfo *ai = NULL; struct in6_addr in6addr; int idx = if_nametoindex(\"iface1\"); int s = socket(AF_INET6, SOCK_STREAM, 0); int ret = getaddrinfo(NULL, NULL, NULL, &ai); if (ret != 0) { const char *es = gai_strerror(ret); } freeaddrinfo(ai); { int val = 1; #ifdef HAVE_LINUX_IPV6_V6ONLY_26 #define IPV6_V6ONLY 26 #endif ret = setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, (const void *)&val, sizeof(val)); } return 0; }" HAVE_IPV6) check_c_source_compiles(" #include int main(void) { struct sockaddr_storage s; return 0; }" HAVE_SOCKADDR_STORAGE) ########################################################### # For detecting attributes we need to treat warnings as # errors set(CMAKE_REQUIRED_FLAGS "-Werror") check_c_source_compiles(" void test_constructor_attribute(void) __attribute__ ((constructor)); void test_constructor_attribute(void) { return; } int main(void) { return 0; }" HAVE_CONSTRUCTOR_ATTRIBUTE) check_c_source_compiles(" void test_destructor_attribute(void) __attribute__ ((destructor)); void test_destructor_attribute(void) { return; } int main(void) { return 0; }" HAVE_DESTRUCTOR_ATTRIBUTE) check_c_source_compiles(" #pragma init (test_constructor) void test_constructor(void); void test_constructor(void) { return; } int main(void) { return 0; }" HAVE_PRAGMA_INIT) check_c_source_compiles(" #pragma fini (test_destructor) void test_destructor(void); void test_destructor(void) { return; } int main(void) { return 0; }" HAVE_PRAGMA_FINI) check_c_source_compiles(" #define FALL_THROUGH __attribute__((fallthrough)) int main(void) { int i = 2; switch (i) { case 0: FALL_THROUGH; case 1: break; default: break; } return 0; }" HAVE_FALLTHROUGH_ATTRIBUTE) check_c_source_compiles(" __thread int tls; int main(void) { return 0; }" HAVE_GCC_THREAD_LOCAL_STORAGE) check_c_source_compiles(" void log_fn(const char *format, ...) __attribute__ ((format (printf, 1, 2))); int main(void) { return 0; }" HAVE_FUNCTION_ATTRIBUTE_FORMAT) check_c_source_compiles(" void test_address_sanitizer_attribute(void) __attribute__((no_sanitize_address)); void test_address_sanitizer_attribute(void) { return; } int main(void) { return 0; }" HAVE_ADDRESS_SANITIZER_ATTRIBUTE) # Stop treating wanrings as errors unset(CMAKE_REQUIRED_FLAGS) ########################################################### if (OSX) set(HAVE_APPLE 1) endif (OSX) # ENDIAN if (NOT WIN32) test_big_endian(WORDS_BIGENDIAN) endif (NOT WIN32) check_type_size(pid_t SIZEOF_PID_T) set(SWRAP_REQUIRED_LIBRARIES ${_REQUIRED_LIBRARIES} CACHE INTERNAL "socket_wrapper required system libraries") socket_wrapper-1.4.4/socket_wrapper.pc.cmake000644 001750 000144 00000000217 14631527256 021176 0ustar00asnusers000000 000000 Name: @PROJECT_NAME@ Description: The socket_wrapper library Version: @PROJECT_VERSION@ Libs: @CMAKE_INSTALL_FULL_LIBDIR@/@SOCKET_WRAPPER_LIB@ socket_wrapper-1.4.4/TODO000644 001750 000144 00000002015 14631527256 015231 0ustar00asnusers000000 000000 TODO ===== This is the TODO list of this project. It should give you some hints of things which need to be implemented. If you can spend some time on this project, then look at the list below. Library: --------- Goals: * The proposed way ==> - fd-passing for tcp sockets (for free) Approach: - tdb "in small". So a "db file". - for each socket an entry in the db file (file, mmap, robust mutex. e.g. one file per local ip addr) - socket_info : structure in db. protected by pthread robust mutexes - socket_info_fd : --> pointer into mmap area of db - free-list - fd-passing: pass index in array - the last element we pass is not a fd but the index number in the mmaped file * Use realpath() in socket_wrapper_dir(). Testing: --------- * Add a test to make sure detect stale file descriptors. * Add a test for sento() to broadcast 255.255.255.255. * Add a test to check that read/readv/send/ only work on connected sockets. * Add unit tests for conversion functions like convert_in_un_remote(). socket_wrapper-1.4.4/.git000644 001750 000144 00000000112 14631527256 015321 0ustar00asnusers000000 000000 gitdir: /home/asn/workspace/prj/oss/socket_wrapper/.bare/worktrees/master socket_wrapper-1.4.4/CHANGELOG000644 001750 000144 00000011626 14744201025 015747 0ustar00asnusers000000 000000 CHANGELOG ========= version 1.4.4 (released 2025-01-21) * Fixed setsockopt(SO_REUSEPORT) with glibc 2.40 version 1.4.3 (released 2024-06-12) * Fixed socket_wrapper running with jemalloc compiled binaries * Fixed thread sanitizer on modern Linux Kernels * Fixed swrap_fake_uid_wrapper test * Fixed building on Hurd version 1.4.2 (released 2023-06-29) * Fixed LFS issues on 32bit platforms version 1.4.1 (released 2023-06-21) * Fixed issue with fnctl() on 32bit * Added openat64() to detect stale fds version 1.4.0 (released 2023-01-18) * Added support for sendmmsg()/recvmmsg() * Added support for handling close, recvmmsg and sendmmsg syscalls * Added support to interact with uid_wrapper syscall() * Improved IP address tracing output version 1.3.5 (released 2022-11-23) * Inject O_LARGEFILE as needed on 32bit * pkgconfig: Fix path to libsocket_wrapper.so * Fix -Wcast-qual warnings * Fix dclose(RTLD_NEXT) version 1.3.4 (released 2022-07-21) * Fixed TOCTOU issue with udp auto binding * Fixed running on FreeBSD version 1.3.3 (released 2021-03-17) * Added public libsocket_wrapper_noop library * Added wrapper for wrap __close_nocancel() * Fixed possible deadlock in swrap_pcap_dump_packet() * Fixed issue when writing pcap files version 1.3.2 (released 2021-02-10) * Fixed possible memory leak between swrap_recvmsg_{before,after}_unix() version 1.3.1 (released 2021-02-09) * Fixed copy on write leak of ~38M for every fork * Fixed issue with accept() on FreeBSD * Fixed fd-passing on 32bit platforms * Fixed invalid read in swrap_sendmsg_unix_scm_rights() version 1.3.0 (released 2021-02-03) * Added support for fd-passing via unix sockets * Added (de)contructor support on AIX with pragma init/finish * Fixed mutex fork handling version 1.2.5 (released 2020-06-22) * Added basic support for TCP_INFO and SIOCOUTQ/TIOCOUTQ/FIONWRITE * Add SOCKET_WRAPPER_DIR_ALLOW_ORIG and abort() early if SOCKET_WRAPPER_DIR is unusable version 1.2.4 (released 2020-03-24) * Added support for 10.53.57.0 network * Added _{socket,close,connect,...} symbols on FreeBSD * Fixed interaction with resolv_wrapper on FreeBSD version 1.2.3 (released 2019-03-21) * Fixed missing NULL check for socket_wrapper_dir() * Fixes building in Samba source tree version 1.2.2 (released 2019-03-21) * Added environment variable to disable deep binding * Fixed installation of socket_wrapper * Fixed several small bugs version 1.2.1 (released 2018-11-14) * Removed error message to fix applications doing stupid things version 1.2.0 (released 2018-11-13) * Added threading support * Moved to modern cmake * Several smaller bugfixes version 1.1.9 (released 2017-12-04) * Fixed thread - signal deadlock issue version 1.1.8 (released 2017-10-13) * Added support for openat() * Added support for open64() and fopen64() * Always enabled logging support * Increased maximum for wrapped interfaces to 64 * Improved fd duplication code * Fixed strict-aliasing issues * Fixed some use after free issues * Fixed issues on ppc64le version 1.1.7 (released 2016-05-20) * Added support for accept4() * Added support for OpenBSD * Fixed sendto() with UDP and a connected socket * Fixed AF_RAWLINK sockets version 1.1.6 (released 2016-03-15) * Added a wrapper for write() * Added support for automatic binding of ephemeral ports * Fixed recvmsg() with UDP * Fixed AF_NETLINK sockets version 1.1.5 (released 2015-10-15) * Added support for TCP_NODELAY in setsockopt/getsockopt * Fixed cmsg space calculation version 1.1.4 (released 2015-08-25) * Fixed handling of msg_name in recvmsg() * Fixed sendmsg()/recvmsg() TCP support * Fixed several compile warnings * Added environment variable to change MTU version 1.1.3 (released 2015-02-23) * Added support for address sanitizer. * Fixed leaking of memory and fds of stale sockets. * Fixed the library loading code. version 1.1.2 (released 2014-10-01) * Added support for fnctl(F_DUPFD). * Added support for glibc 2.20.90. version 1.1.1 (released 2014-06-05) * Disable incomplete address in use check in bind(). version 1.1.0 (released 2014-06-02) * Added support for IP_PKTINFO in recvmsg(). * Added support for IPV6_PKTINFO in recvmsg(). * Added support for IP_RECVDSTADDR in recvmsg() on BSD. * Added support for more socket options in getsockopt(). * Added support for bindresvport(). * Fixed rebinding on connect(). * Fixed sockaddr buffer truncation in getsockname() and getpeername(). * Fixed special cases in bind(). * Fixed loading libc on some platforms. version 1.0.2 (released 2014-05-05) * Fixed memory leaks * Fixed calling open from libc. * Fixed loading libc functions on some platforms. version 1.0.1 (released 2014-02-04) * Added --libs to pkg-config. * Added socket_wrapper-config.cmake * Fixed a bug packaging the obj directory. version 1.0.0 (released 2014-02-02) * Initial release socket_wrapper-1.4.4/doc/000755 001750 000144 00000000000 14744201044 015275 5ustar00asnusers000000 000000 socket_wrapper-1.4.4/doc/CMakeLists.txt000644 001750 000144 00000000151 14631527256 020045 0ustar00asnusers000000 000000 install(FILES socket_wrapper.1 DESTINATION ${CMAKE_INSTALL_MANDIR}/man1) socket_wrapper-1.4.4/doc/socket_wrapper.1000644 001750 000144 00000020335 14631527256 020425 0ustar00asnusers000000 000000 '\" t .\" Title: socket_wrapper .\" Author: Samba Team .\" Generator: Asciidoctor 2.0.10 .\" Date: 2021-02-24 .\" Manual: \ \& .\" Source: \ \& .\" Language: English .\" .TH "SOCKET_WRAPPER" "1" "2021-02-24" "\ \&" "\ \&" .ie \n(.g .ds Aq \(aq .el .ds Aq ' .ss \n[.ss] 0 .nh .ad l .de URL \fI\\$2\fP <\\$1>\\$3 .. .als MTO URL .if \n[.g] \{\ . mso www.tmac . am URL . ad l . . . am MTO . ad l . . . LINKSTYLE blue R < > .\} .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\fP .SH "DESCRIPTION" .sp socket_wrapper aims to help client/server software development teams willing to gain full functional test coverage. It makes possible to run several instances of the full software stack on the same machine and perform locally functional testing of complex network configurations. .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ . sp -1 . IP \(bu 2.3 .\} Redirects all network communication to happen over Unix sockets. .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ . sp -1 . IP \(bu 2.3 .\} Support for IPv4 and IPv6 socket and addressing emulation. .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ . sp -1 . IP \(bu 2.3 .\} Ability to capture network traffic in pcap format. .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ . sp -1 . IP \(bu 2.3 .\} Passing IP sockets (up to 6) via SCM_RIGHTS is supported, but pcap support only works reliable if the socket is used by a single process at a time. .RE .SH "ENVIRONMENT VARIABLES" .sp \fBSOCKET_WRAPPER_DIR\fP .RS 4 The user defines a directory where to put all the unix sockets using the environment variable "SOCKET_WRAPPER_DIR=/path/to/socket_dir". When a server opens a port or a client wants to connect, socket_wrapper will translate IP addresses to a special socket_wrapper name and look for the relevant Unix socket in the SOCKET_WRAPPER_DIR. .RE .sp \fBSOCKET_WRAPPER_IPV4_NETWORK\fP .RS 4 By default the loopback IPv4 network "127.0.0.0/8" and the "127.0.0.x" can be used. In order to make more realistic testing possible it is possible to use the "10.0.0.0/8" IPv4 network instead. But note within "10.0.0.0/8" only "10.53.57." can be used, but the broadcast address is "10.255.255.255". The following two value are allowed: SOCKET_WRAPPER_IPV4_NETWORK="127.0.0.0" (the default) and SOCKET_WRAPPER_IPV4_NETWORK="10.53.57.0". .RE .sp \fBSOCKET_WRAPPER_DEFAULT_IFACE\fP .RS 4 Additionally, the default interface to be used by an application is defined with "SOCKET_WRAPPER_DEFAULT_IFACE=" where the valid range for starts with 1 (the default) and ends with 64. This is analogous to use the IPv4 addresses "127.0.0."/"10.53.57." 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 .sp \fBSOCKET_WRAPPER_PCAP_FILE\fP .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 .sp \fBSOCKET_WRAPPER_MTU\fP .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. .sp \fBSOCKET_WRAPPER_MAX_SOCKETS\fP .RS 4 This variable can be used to set the maximum number of sockets to be used by an application. .RE .sp The default value is set to 65535 and the maximum 256000. .sp \fBSOCKET_WRAPPER_DEBUGLEVEL\fP .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 .sp \fBSOCKET_WRAPPER_DISABLE_DEEPBIND\fP .RS 4 This allows you to disable deep binding in socket_wrapper. This is useful for running valgrind tools or sanitizers like (address, undefined, thread). .RE .sp \fBSOCKET_WRAPPER_DIR_ALLOW_ORIG\fP .RS 4 SOCKET_WRAPPER_DIR is resolved by socket_wrapper using realpath(3). Given that Unix sockets are constructed relative to this directory, the resulting path can sometimes be too long to allow valid socket paths to be constructed due to length restrictions. Setting this variable (to any value) allows socket_wrapper to fall back to the original value of SOCKET_WRAPPER_DIR if realpath(3) makes it too long to be usable. .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 \(rs SOCKET_WRAPPER_DIR=/tmp/tmp.bQRELqDrhM \(rs 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 \(rs SOCKET_WRAPPER_DIR=/tmp/tmp.bQRELqDrhM \(rs SOCKET_WRAPPER_DEFAULT_IFACE=100 nc \-v 127.0.0.10 7 .fi .if n .RE .sp .if n .RS 4 .nf # (The client will use the address 127.0.0.100 when connecting to the server) # Now you can type \(aqHello!\(aq which will be sent to the server and should appear # in the console output of the server. .fi .if n .RE .SH "PUBLIC FUNCTIONS" .sp Socket wrapper advanced helpers. .sp Applications with the need to alter their behaviour when socket wrapper is active, can link use these functions. .sp By default it\(cqs required for applications to use any of these functions as libsocket_wrapper.so is injected at runtime via LD_PRELOAD. .sp Applications using these functions should link against libsocket_wrapper_noop.so by using \-lsocket_wrapper_noop, or implement their own noop stubs. .sp #include .sp bool socket_wrapper_enabled(void); .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ . sp -1 . IP \(bu 2.3 .\} This returns true when socket wrapper is actively in use. .RE .sp void socket_wrapper_indicate_no_inet_fd(int fd); .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ . sp -1 . IP \(bu 2.3 .\} This allows socket_wrapper aware applications to indicate that the given fd does not belong to an inet socket. .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ . sp -1 . IP \(bu 2.3 .\} socket_wrapper may not be able to intercept the __close_nocancel() syscall made from within libc.so. As result it\(cqs possible that the in memory meta date of socket_wrapper references stale file descriptors, which are already reused for unrelated kernel objects, e.g. files, directories, ... .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ . sp -1 . IP \(bu 2.3 .\} Socket wrapper already intercepts a lot of unrelated functions like eventfd(), timerfd_create(), ... in order to remove stale meta data for the returned fd, but it will never be able to handle all possible syscalls. .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ . sp -1 . IP \(bu 2.3 .\} socket_wrapper_indicate_no_inet_fd() gives applications a way to do the same, explicitly without waiting for new syscalls to be added to libsocket_wrapper.so. .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ . sp -1 . IP \(bu 2.3 .\} This is a no\-op if socket_wrapper is not in use or if the there is no in memory meta data for the given fd. .RE .SH "RESOURCES" .sp \fBProject web site:\fP \c .URL "https://cwrap.org" "" "" .SH "AUTHOR" .sp Samba Teamsocket_wrapper-1.4.4/doc/README000644 001750 000144 00000000261 14631527256 016167 0ustar00asnusers000000 000000 The manpage is written with asciidoc. To generate the manpage use: asciidoctor -b manpage doc/socket_wrapper.1.adoc or a2x --format manpage doc/socket_wrapper.1.adoc socket_wrapper-1.4.4/doc/socket_wrapper.1.adoc000644 001750 000144 00000014672 14631527256 021341 0ustar00asnusers000000 000000 socket_wrapper(1) ================= :revdate: 2021-02-01 :author: Samba Team :doctype: manpage NAME ---- socket_wrapper - A library passing all socket communications through unix sockets. SYNOPSIS -------- LD_PRELOAD=libsocket_wrapper.so SOCKET_WRAPPER_DIR=/tmp/tmp.bQRELqDrhM SOCKET_WRAPPER_DEFAULT_IFACE=10 *./myapplication* DESCRIPTION ----------- socket_wrapper aims to help client/server software development teams willing to gain full functional test coverage. It makes possible to run several instances of the full software stack on the same machine and perform locally functional testing of complex network configurations. - Redirects all network communication to happen over Unix sockets. - Support for IPv4 and IPv6 socket and addressing emulation. - Ability to capture network traffic in pcap format. - Passing IP sockets (up to 6) via SCM_RIGHTS is supported, but pcap support only works reliable if the socket is used by a single process at a time. ENVIRONMENT VARIABLES --------------------- *SOCKET_WRAPPER_DIR*:: The user defines a directory where to put all the unix sockets using the environment variable "SOCKET_WRAPPER_DIR=/path/to/socket_dir". When a server opens a port or a client wants to connect, socket_wrapper will translate IP addresses to a special socket_wrapper name and look for the relevant Unix socket in the SOCKET_WRAPPER_DIR. *SOCKET_WRAPPER_IPV4_NETWORK*:: By default the loopback IPv4 network "127.0.0.0/8" and the "127.0.0.x" can be used. In order to make more realistic testing possible it is possible to use the "10.0.0.0/8" IPv4 network instead. But note within "10.0.0.0/8" only "10.53.57." can be used, but the broadcast address is "10.255.255.255". The following two value are allowed: SOCKET_WRAPPER_IPV4_NETWORK="127.0.0.0" (the default) and SOCKET_WRAPPER_IPV4_NETWORK="10.53.57.0". *SOCKET_WRAPPER_DEFAULT_IFACE*:: Additionally, the default interface to be used by an application is defined with "SOCKET_WRAPPER_DEFAULT_IFACE=" where the valid range for starts with 1 (the default) and ends with 64. This is analogous to use the IPv4 addresses "127.0.0."/"10.53.57." or IPv6 addresses "fd00::5357:5f" (where is a hexadecimal presentation of ). You should always set the default interface. If you listen on INADDR_ANY then it will use the default interface to listen on. *SOCKET_WRAPPER_PCAP_FILE*:: When debugging, it is often interesting to investigate the network traffic between the client and server within your application. If you define SOCKET_WRAPPER_PCAP_FILE=/path/to/file.pcap, socket_wrapper will dump all your network traffic to the specified file. After the test has been finished you're able to open the file for example with Wireshark. *SOCKET_WRAPPER_MTU*:: With this variable you can change the MTU size. However we do not recomment to do that as the default size of 1500 byte is best for formatting PCAP files. The minimum value you can set is 512 and the maximum 32768. *SOCKET_WRAPPER_MAX_SOCKETS*:: This variable can be used to set the maximum number of sockets to be used by an application. The default value is set to 65535 and the maximum 256000. *SOCKET_WRAPPER_DEBUGLEVEL*:: If you need to see what is going on in socket_wrapper itself or try to find a bug, you can enable logging support in socket_wrapper if you built it with debug symbols. - 0 = ERROR - 1 = WARNING - 2 = DEBUG - 3 = TRACE *SOCKET_WRAPPER_DISABLE_DEEPBIND*:: This allows you to disable deep binding in socket_wrapper. This is useful for running valgrind tools or sanitizers like (address, undefined, thread). *SOCKET_WRAPPER_DIR_ALLOW_ORIG*:: SOCKET_WRAPPER_DIR is resolved by socket_wrapper using realpath(3). Given that Unix sockets are constructed relative to this directory, the resulting path can sometimes be too long to allow valid socket paths to be constructed due to length restrictions. Setting this variable (to any value) allows socket_wrapper to fall back to the original value of SOCKET_WRAPPER_DIR if realpath(3) makes it too long to be usable. 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. PUBLIC FUNCTIONS ---------------- Socket wrapper advanced helpers. Applications with the need to alter their behaviour when socket wrapper is active, can link use these functions. By default it's required for applications to use any of these functions as libsocket_wrapper.so is injected at runtime via LD_PRELOAD. Applications using these functions should link against libsocket_wrapper_noop.so by using -lsocket_wrapper_noop, or implement their own noop stubs. #include bool socket_wrapper_enabled(void); - This returns true when socket wrapper is actively in use. void socket_wrapper_indicate_no_inet_fd(int fd); - This allows socket_wrapper aware applications to indicate that the given fd does not belong to an inet socket. - socket_wrapper may not be able to intercept the __close_nocancel() syscall made from within libc.so. As result it's possible that the in memory meta date of socket_wrapper references stale file descriptors, which are already reused for unrelated kernel objects, e.g. files, directories, ... - Socket wrapper already intercepts a lot of unrelated functions like eventfd(), timerfd_create(), ... in order to remove stale meta data for the returned fd, but it will never be able to handle all possible syscalls. - socket_wrapper_indicate_no_inet_fd() gives applications a way to do the same, explicitly without waiting for new syscalls to be added to libsocket_wrapper.so. - This is a no-op if socket_wrapper is not in use or if the there is no in memory meta data for the given fd. RESOURCES --------- *Project web site:* https://cwrap.org socket_wrapper-1.4.4/config.h.cmake000644 001750 000144 00000005747 14631527256 017255 0ustar00asnusers000000 000000 /* Name of package */ #cmakedefine SOCKET_WRAPPER_PACKAGE "${SOCKET_WRAPPER_PACKAGE}" /* Version number of package */ #cmakedefine SOCKET_WRAPPER_VERSION "${SOCKET_WRAPPER_VERSION}" #cmakedefine BINARYDIR "${BINARYDIR}" #cmakedefine SOURCEDIR "${SOURCEDIR}" /************************** HEADER FILES *************************/ #cmakedefine HAVE_NETINET_TCP_FSM_H 1 #cmakedefine HAVE_SYS_FILIO_H 1 #cmakedefine HAVE_SYS_SIGNALFD_H 1 #cmakedefine HAVE_SYS_EVENTFD_H 1 #cmakedefine HAVE_SYS_SYSCALL_H 1 #cmakedefine HAVE_SYS_TIMERFD_H 1 #cmakedefine HAVE_GNU_LIB_NAMES_H 1 #cmakedefine HAVE_RPC_RPC_H 1 #cmakedefine HAVE_SYSCALL_H 1 /**************************** STRUCTS ****************************/ #cmakedefine HAVE_STRUCT_IN_PKTINFO 1 #cmakedefine HAVE_STRUCT_IN6_PKTINFO 1 /************************ STRUCT MEMBERS *************************/ #cmakedefine HAVE_STRUCT_SOCKADDR_SA_LEN 1 #cmakedefine HAVE_STRUCT_MSGHDR_MSG_CONTROL 1 /**************************** SYMBOLS ****************************/ #cmakedefine HAVE_PROGRAM_INVOCATION_SHORT_NAME 1 /*************************** FUNCTIONS ***************************/ /* Define to 1 if you have the `getaddrinfo' function. */ #cmakedefine HAVE_GETADDRINFO 1 #cmakedefine HAVE_SIGNALFD 1 #cmakedefine HAVE_EVENTFD 1 #cmakedefine HAVE_TIMERFD_CREATE 1 #cmakedefine HAVE_BINDRESVPORT 1 #cmakedefine HAVE_ACCEPT4 1 #cmakedefine HAVE_OPEN64 1 #cmakedefine HAVE_OPENAT64 1 #cmakedefine HAVE_FOPEN64 1 #cmakedefine HAVE_FCNTL64 1 #cmakedefine HAVE_GETPROGNAME 1 #cmakedefine HAVE_GETEXECNAME 1 #cmakedefine HAVE_PLEDGE 1 #cmakedefine HAVE__SOCKET 1 #cmakedefine HAVE__CLOSE 1 #cmakedefine HAVE___CLOSE_NOCANCEL 1 #cmakedefine HAVE_ACCEPT_PSOCKLEN_T 1 #cmakedefine HAVE_IOCTL_INT 1 #cmakedefine HAVE_EVENTFD_UNSIGNED_INT 1 #cmakedefine HAVE_RECVMMSG 1 #cmakedefine HAVE_RECVMMSG_CONST_TIMEOUT 1 #cmakedefine HAVE_RECVMMSG_SSIZE_T_CONST_TIMEOUT 1 #cmakedefine HAVE_SENDMMSG 1 #cmakedefine HAVE_SENDMMSG_SSIZE_T 1 #cmakedefine HAVE_SYSCALL 1 #cmakedefine HAVE_SYSCALL_INT 1 /*************************** LIBRARIES ***************************/ #cmakedefine HAVE_GETTIMEOFDAY_TZ 1 #cmakedefine HAVE_GETTIMEOFDAY_TZ_VOID 1 /*************************** DATA TYPES***************************/ #cmakedefine SIZEOF_PID_T @SIZEOF_PID_T@ /**************************** OPTIONS ****************************/ #cmakedefine HAVE_GCC_THREAD_LOCAL_STORAGE 1 #cmakedefine HAVE_CONSTRUCTOR_ATTRIBUTE 1 #cmakedefine HAVE_DESTRUCTOR_ATTRIBUTE 1 #cmakedefine HAVE_PRAGMA_INIT 1 #cmakedefine HAVE_PRAGMA_FINI 1 #cmakedefine HAVE_FALLTHROUGH_ATTRIBUTE 1 #cmakedefine HAVE_ADDRESS_SANITIZER_ATTRIBUTE 1 #cmakedefine HAVE_SOCKADDR_STORAGE 1 #cmakedefine HAVE_IPV6 1 #cmakedefine HAVE_FUNCTION_ATTRIBUTE_FORMAT 1 #cmakedefine HAVE_APPLE 1 #cmakedefine HAVE_LIBSOCKET 1 /*************************** ENDIAN *****************************/ /* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most significant byte first (like Motorola and SPARC, unlike Intel). */ #cmakedefine WORDS_BIGENDIAN 1