resolv_wrapper-1.1.5/COPYING000644 001750 000144 00000002723 12421451254 015607 0ustar00asnusers000000 000000 Copyright (c) Andreas Schneider 2014 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. resolv_wrapper-1.1.5/DefineOptions.cmake000644 001750 000144 00000000061 12421451254 020315 0ustar00asnusers000000 000000 option(UNIT_TESTING "Build with unit tests" OFF) resolv_wrapper-1.1.5/README000644 001750 000144 00000000714 12421451254 015432 0ustar00asnusers000000 000000 RESOLV_WRAPPER =============== This is a wrapper for dns resolving. DESCRIPTION ----------- More details can be found in the manpage: man -l ./doc/resolv_wrapper.1 or the raw text version: less ./doc/resolv_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 resolv_wrapper-1.1.5/cmake/000755 001750 000144 00000000000 12764206151 015634 5ustar00asnusers000000 000000 resolv_wrapper-1.1.5/cmake/Modules/000755 001750 000144 00000000000 12764206152 017245 5ustar00asnusers000000 000000 resolv_wrapper-1.1.5/cmake/Modules/AddCMockaTest.cmake000644 001750 000144 00000002373 12421451254 022655 0ustar00asnusers000000 000000 # - ADD_CHECK_TEST(test_name test_source linklib1 ... linklibN) # Copyright (c) 2007 Daniel Gollub # Copyright (c) 2007-2010 Andreas Schneider # # Redistribution and use is allowed according to the terms of the BSD license. # For details see the accompanying COPYING-CMAKE-SCRIPTS file. enable_testing() include(CTest) if(CMAKE_COMPILER_IS_GNUCC AND NOT MINGW) set(CMAKE_C_FLAGS_PROFILING "-g -O0 -Wall -W -Wshadow -Wunused-variable -Wunused-parameter -Wunused-function -Wunused -Wno-system-headers -Wwrite-strings -fprofile-arcs -ftest-coverage" CACHE STRING "Profiling Compiler Flags") set(CMAKE_SHARED_LINKER_FLAGS_PROFILING " -fprofile-arcs -ftest-coverage" CACHE STRING "Profiling Linker Flags") set(CMAKE_MODULE_LINKER_FLAGS_PROFILING " -fprofile-arcs -ftest-coverage" CACHE STRING "Profiling Linker Flags") set(CMAKE_EXEC_LINKER_FLAGS_PROFILING " -fprofile-arcs -ftest-coverage" CACHE STRING "Profiling Linker Flags") endif(CMAKE_COMPILER_IS_GNUCC AND NOT MINGW) function (ADD_CMOCKA_TEST _testName _testSource) add_executable(${_testName} ${_testSource}) target_link_libraries(${_testName} ${ARGN}) add_test(${_testName} ${CMAKE_CURRENT_BINARY_DIR}/${_testName}) endfunction (ADD_CMOCKA_TEST) resolv_wrapper-1.1.5/cmake/Modules/CheckCCompilerFlagSSP.cmake000644 001750 000144 00000001755 12421451254 024245 0ustar00asnusers000000 000000 # - Check whether the C compiler supports a given flag in the # context of a stack checking compiler option. # CHECK_C_COMPILER_FLAG_SSP(FLAG VARIABLE) # # FLAG - the compiler flag # VARIABLE - variable to store the result # # This actually calls check_c_source_compiles. # See help for CheckCSourceCompiles for a listing of variables # that can modify the build. # Copyright (c) 2006, Alexander Neundorf, # # Redistribution and use is allowed according to the terms of the BSD license. # For details see the accompanying COPYING-CMAKE-SCRIPTS file. include(CheckCSourceCompiles) function(CHECK_C_COMPILER_FLAG_SSP _FLAG _RESULT) set(SAFE_CMAKE_REQUIRED_DEFINITIONS "${CMAKE_REQUIRED_DEFINITIONS}") set(CMAKE_REQUIRED_DEFINITIONS "${_FLAG}") check_c_source_compiles("int main(int argc, char **argv) { char buffer[256]; return buffer[argc]=0;}" ${_RESULT}) set(CMAKE_REQUIRED_DEFINITIONS "${SAFE_CMAKE_REQUIRED_DEFINITIONS}") endfunction(CHECK_C_COMPILER_FLAG_SSP) resolv_wrapper-1.1.5/cmake/Modules/DefineCMakeDefaults.cmake000644 001750 000144 00000001741 12421451254 024030 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 prefered over the already installed ones # since cmake 2.4.1 set(CMAKE_INCLUDE_DIRECTORIES_PROJECT_BEFORE ON) # Use colored output # since cmake 2.4.0 set(CMAKE_COLOR_MAKEFILE ON) # Define the generic version of the libraries here set(GENERIC_LIB_VERSION "0.1.0") set(GENERIC_LIB_SOVERSION "0") # Set the default build type to release with debug info if (NOT CMAKE_BUILD_TYPE) set(CMAKE_BUILD_TYPE RelWithDebInfo CACHE STRING "Choose the type of build, options are: None Debug Release RelWithDebInfo MinSizeRel." ) endif (NOT CMAKE_BUILD_TYPE) # Create the compile command database for clang by default set(CMAKE_EXPORT_COMPILE_COMMANDS ON) resolv_wrapper-1.1.5/cmake/Modules/DefineCompilerFlags.cmake000644 001750 000144 00000005471 12421451254 024113 0ustar00asnusers000000 000000 # define system dependent compiler flags include(CheckCCompilerFlag) include(CheckCCompilerFlagSSP) if (UNIX AND NOT WIN32) # # Define GNUCC compiler flags # if (${CMAKE_C_COMPILER_ID} MATCHES "(GNU|Clang)") # add -Wconversion ? set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=gnu99 -pedantic -pedantic-errors") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra -Wshadow -Wmissing-prototypes -Wdeclaration-after-statement") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wunused -Wfloat-equal -Wpointer-arith -Wwrite-strings -Wformat-security") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wmissing-format-attribute") # with -fPIC check_c_compiler_flag("-fPIC" WITH_FPIC) if (WITH_FPIC) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fPIC") endif (WITH_FPIC) check_c_compiler_flag_ssp("-fstack-protector" WITH_STACK_PROTECTOR) if (WITH_STACK_PROTECTOR) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fstack-protector") endif (WITH_STACK_PROTECTOR) if (CMAKE_BUILD_TYPE) string(TOLOWER "${CMAKE_BUILD_TYPE}" CMAKE_BUILD_TYPE_LOWER) if (CMAKE_BUILD_TYPE_LOWER MATCHES (release|relwithdebinfo|minsizerel)) check_c_compiler_flag("-Wp,-D_FORTIFY_SOURCE=2" WITH_FORTIFY_SOURCE) if (WITH_FORTIFY_SOURCE) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wp,-D_FORTIFY_SOURCE=2") endif (WITH_FORTIFY_SOURCE) endif() endif() endif (${CMAKE_C_COMPILER_ID} MATCHES "(GNU|Clang)") # # Check for large filesystem support # if (CMAKE_SIZEOF_VOID_P MATCHES "8") # with large file support execute_process( COMMAND getconf LFS64_CFLAGS OUTPUT_VARIABLE _lfs_CFLAGS ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE ) else (CMAKE_SIZEOF_VOID_P MATCHES "8") # with large file support execute_process( COMMAND getconf LFS_CFLAGS OUTPUT_VARIABLE _lfs_CFLAGS ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE ) endif (CMAKE_SIZEOF_VOID_P MATCHES "8") if (_lfs_CFLAGS) string(REGEX REPLACE "[\r\n]" " " "${_lfs_CFLAGS}" "${${_lfs_CFLAGS}}") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${_lfs_CFLAGS}") endif (_lfs_CFLAGS) endif (UNIX AND NOT WIN32) if (MSVC) # Use secure functions by defaualt and suppress warnings about #"deprecated" functions set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /D _CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES=1") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /D _CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES_COUNT=1") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /D _CRT_NONSTDC_NO_WARNINGS=1 /D _CRT_SECURE_NO_WARNINGS=1") endif (MSVC) resolv_wrapper-1.1.5/cmake/Modules/DefineInstallationPaths.cmake000644 001750 000144 00000007343 12421451254 025025 0ustar00asnusers000000 000000 if (UNIX OR OS2) IF (NOT APPLICATION_NAME) MESSAGE(STATUS "${PROJECT_NAME} is used as APPLICATION_NAME") SET(APPLICATION_NAME ${PROJECT_NAME}) ENDIF (NOT APPLICATION_NAME) # Suffix for Linux SET(LIB_SUFFIX CACHE STRING "Define suffix of directory name (32/64)" ) SET(EXEC_INSTALL_PREFIX "${CMAKE_INSTALL_PREFIX}" CACHE PATH "Base directory for executables and libraries" ) SET(SHARE_INSTALL_PREFIX "${CMAKE_INSTALL_PREFIX}/share" CACHE PATH "Base directory for files which go to share/" ) SET(DATA_INSTALL_PREFIX "${SHARE_INSTALL_PREFIX}/${APPLICATION_NAME}" CACHE PATH "The parent directory where applications can install their data") # The following are directories where stuff will be installed to SET(BIN_INSTALL_DIR "${EXEC_INSTALL_PREFIX}/bin" CACHE PATH "The ${APPLICATION_NAME} binary install dir (default prefix/bin)" ) SET(SBIN_INSTALL_DIR "${EXEC_INSTALL_PREFIX}/sbin" CACHE PATH "The ${APPLICATION_NAME} sbin install dir (default prefix/sbin)" ) SET(LIB_INSTALL_DIR "${EXEC_INSTALL_PREFIX}/lib${LIB_SUFFIX}" CACHE PATH "The subdirectory relative to the install prefix where libraries will be installed (default is prefix/lib)" ) SET(LIBEXEC_INSTALL_DIR "${EXEC_INSTALL_PREFIX}/libexec" CACHE PATH "The subdirectory relative to the install prefix where libraries will be installed (default is prefix/libexec)" ) SET(PLUGIN_INSTALL_DIR "${LIB_INSTALL_DIR}/${APPLICATION_NAME}" CACHE PATH "The subdirectory relative to the install prefix where plugins will be installed (default is prefix/lib/${APPLICATION_NAME})" ) SET(INCLUDE_INSTALL_DIR "${CMAKE_INSTALL_PREFIX}/include" CACHE PATH "The subdirectory to the header prefix (default prefix/include)" ) set(CMAKE_INSTALL_DIR "${LIB_INSTALL_DIR}/cmake" CACHE PATH "The subdirectory to install cmake config files") SET(DATA_INSTALL_DIR "${DATA_INSTALL_PREFIX}" CACHE PATH "The parent directory where applications can install their data (default prefix/share/${APPLICATION_NAME})" ) SET(HTML_INSTALL_DIR "${DATA_INSTALL_PREFIX}/doc/HTML" CACHE PATH "The HTML install dir for documentation (default data/doc/html)" ) SET(ICON_INSTALL_DIR "${DATA_INSTALL_PREFIX}/icons" CACHE PATH "The icon install dir (default data/icons/)" ) SET(SOUND_INSTALL_DIR "${DATA_INSTALL_PREFIX}/sounds" CACHE PATH "The install dir for sound files (default data/sounds)" ) SET(LOCALE_INSTALL_DIR "${SHARE_INSTALL_PREFIX}/locale" CACHE PATH "The install dir for translations (default prefix/share/locale)" ) SET(XDG_APPS_DIR "${SHARE_INSTALL_PREFIX}/applications/" CACHE PATH "The XDG apps dir" ) SET(XDG_DIRECTORY_DIR "${SHARE_INSTALL_PREFIX}/desktop-directories" CACHE PATH "The XDG directory" ) SET(SYSCONF_INSTALL_DIR "${EXEC_INSTALL_PREFIX}/etc" CACHE PATH "The ${APPLICATION_NAME} sysconfig install dir (default prefix/etc)" ) SET(MAN_INSTALL_DIR "${SHARE_INSTALL_PREFIX}/man" CACHE PATH "The ${APPLICATION_NAME} man install dir (default prefix/man)" ) SET(INFO_INSTALL_DIR "${SHARE_INSTALL_PREFIX}/info" CACHE PATH "The ${APPLICATION_NAME} info install dir (default prefix/info)" ) else() # Same same set(BIN_INSTALL_DIR "bin" CACHE PATH "-") set(SBIN_INSTALL_DIR "sbin" CACHE PATH "-") set(LIB_INSTALL_DIR "lib${LIB_SUFFIX}" CACHE PATH "-") set(INCLUDE_INSTALL_DIR "include" CACHE PATH "-") set(CMAKE_INSTALL_DIR "CMake" CACHE PATH "-") set(PLUGIN_INSTALL_DIR "plugins" CACHE PATH "-") set(HTML_INSTALL_DIR "doc/HTML" CACHE PATH "-") set(ICON_INSTALL_DIR "icons" CACHE PATH "-") set(SOUND_INSTALL_DIR "soudns" CACHE PATH "-") set(LOCALE_INSTALL_DIR "lang" CACHE PATH "-") endif () resolv_wrapper-1.1.5/cmake/Modules/DefinePlatformDefaults.cmake000644 001750 000144 00000001312 12421451254 024626 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") resolv_wrapper-1.1.5/cmake/Modules/MacroEnsureOutOfSourceBuild.cmake000644 001750 000144 00000001227 12421451254 025605 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) resolv_wrapper-1.1.5/cmake/Modules/COPYING-CMAKE-SCRIPTS000644 001750 000144 00000002457 12422105604 022242 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. resolv_wrapper-1.1.5/doc/000755 001750 000144 00000000000 12764206152 015322 5ustar00asnusers000000 000000 resolv_wrapper-1.1.5/doc/CMakeLists.txt000644 001750 000144 00000000144 12421451254 020054 0ustar00asnusers000000 000000 install(FILES resolv_wrapper.1 DESTINATION ${MAN_INSTALL_DIR}/man1) resolv_wrapper-1.1.5/doc/README000644 001750 000144 00000000204 12421451254 016171 0ustar00asnusers000000 000000 The manpage is written with asciidoc. To generate the manpage use: a2x --doctype manpage --format manpage doc/resolv_wrapper.1.txt resolv_wrapper-1.1.5/doc/resolv_wrapper.1000644 001750 000144 00000007376 12755520322 020471 0ustar00asnusers000000 000000 '\" t .\" Title: resolv_wrapper .\" Author: [FIXME: author] [see http://docbook.sf.net/el/author] .\" Generator: DocBook XSL Stylesheets v1.78.1 .\" Date: 2015-08-18 .\" Manual: \ \& .\" Source: \ \& .\" Language: English .\" .TH "RESOLV_WRAPPER" "1" "2015\-08\-18" "\ \&" "\ \&" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .\" http://bugs.debian.org/507673 .\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- .\" disable hyphenation .nh .\" disable justification (adjust text to left margin only) .ad l .\" ----------------------------------------------------------------- .\" * MAIN CONTENT STARTS HERE * .\" ----------------------------------------------------------------- .SH "NAME" resolv_wrapper \- A wrapper for dns name resolving or dns faking\&. .SH "SYNOPSIS" .sp LD_PRELOAD=libresolv_wrapper\&.so RESOLV_WRAPPER_CONF="/path/to/resolv\&.conf" \fB\&./myapplication\fR .SH "DESCRIPTION" .sp resolv_wrapper makes it possible on most UNIX platforms to contact your own DNS implementation in your test environment\&. It requires socket_wrapper to be able to contact it\&. If it doesn\(cqt work on a special platform the wrapper is able to fake DNS queries and return valid responses to your application\&. .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} Redirects name queries to the nameservers specified in your resolv\&.conf .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} Can fake DNS queries using a simple formatted DNS hosts file\&. .RE .SH "ENVIRONMENT VARIABLES" .PP \fBRESOLV_WRAPPER_CONF\fR .RS 4 This is used to specify the resolv\&.conf to use\&. The format of the resolv\&.conf file is defined in the manpage \fIresolv\&.conf(5)\fR\&. Currently only the \fBnamserver\fR directive is supported\&. .RE .PP \fBRESOLV_WRAPPER_HOSTS\fR .RS 4 This environment variable is used for faking DNS queries\&. It must point to a hosts\-like text file that specifies fake records for custom queries\&. The format of the file looks like this: .sp .if n \{\ .RS 4 .\} .nf TYPE RECORD_NAME RECORD_VALUE .fi .if n \{\ .RE .\} .RE .sp For example: .sp .if n \{\ .RS 4 .\} .nf A dc\&.cwrap\&.org 127\&.0\&.0\&.10 AAAA dc\&.cwrap\&.org fd00::5357:5f0a CNAME kerberos\&.cwrap\&.org dc\&.cwrap\&.org SRV _kerberos\&._tcp\&.cwrap\&.org kerberos\&.cwrap\&.org 88 URI _vpn\&.cwrap\&.org https://vpn\&.cwrap\&.org/VPN .fi .if n \{\ .RE .\} .PP \fBRESOLV_WRAPPER_DEBUGLEVEL\fR .RS 4 If you need to see what is going on in resolv_wrapper itself or try to find a bug, you can enable logging support in resolv_wrapper if you built it with debug symbols\&. .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} 0 = ERROR .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} 1 = WARNING .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} 2 = DEBUG .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} 3 = TRACE .RE .RE .SH "EXAMPLE" .sp The following command would trick \fIkinit(1)\fR into using DNS servers from "\&./resolv\&.conf" for Kerberos service resolution: .sp .if n \{\ .RS 4 .\} .nf $ LD_PRELOAD=libresolv_wrapper\&.so RESOLV_WRAPPER_CONF="\&./resolv\&.conf" kinit user@EXAMPLE\&.COM .fi .if n \{\ .RE .\} resolv_wrapper-1.1.5/doc/resolv_wrapper.1.txt000644 001750 000144 00000003642 12755520322 021277 0ustar00asnusers000000 000000 resolv_wrapper(1) ================= :revdate: 2015-08-18 NAME ---- resolv_wrapper - A wrapper for dns name resolving or dns faking. SYNOPSIS -------- LD_PRELOAD=libresolv_wrapper.so RESOLV_WRAPPER_CONF="/path/to/resolv.conf" *./myapplication* DESCRIPTION ----------- resolv_wrapper makes it possible on most UNIX platforms to contact your own DNS implementation in your test environment. It requires socket_wrapper to be able to contact it. If it doesn't work on a special platform the wrapper is able to fake DNS queries and return valid responses to your application. - Redirects name queries to the nameservers specified in your resolv.conf - Can fake DNS queries using a simple formatted DNS hosts file. ENVIRONMENT VARIABLES --------------------- *RESOLV_WRAPPER_CONF*:: This is used to specify the resolv.conf to use. The format of the resolv.conf file is defined in the manpage 'resolv.conf(5)'. Currently only the *namserver* directive is supported. *RESOLV_WRAPPER_HOSTS*:: This environment variable is used for faking DNS queries. It must point to a hosts-like text file that specifies fake records for custom queries. The format of the file looks like this: TYPE RECORD_NAME RECORD_VALUE For example: A dc.cwrap.org 127.0.0.10 AAAA dc.cwrap.org fd00::5357:5f0a CNAME kerberos.cwrap.org dc.cwrap.org SRV _kerberos._tcp.cwrap.org kerberos.cwrap.org 88 URI _vpn.cwrap.org https://vpn.cwrap.org/VPN *RESOLV_WRAPPER_DEBUGLEVEL*:: If you need to see what is going on in resolv_wrapper itself or try to find a bug, you can enable logging support in resolv_wrapper if you built it with debug symbols. - 0 = ERROR - 1 = WARNING - 2 = DEBUG - 3 = TRACE EXAMPLE ------- The following command would trick 'kinit(1)' into using DNS servers from "./resolv.conf" for Kerberos service resolution: $ LD_PRELOAD=libresolv_wrapper.so RESOLV_WRAPPER_CONF="./resolv.conf" kinit user@EXAMPLE.COM resolv_wrapper-1.1.5/resolv_wrapper-config-version.cmake.in000644 001750 000144 00000000611 12421451254 024155 0ustar00asnusers000000 000000 set(PACKAGE_VERSION @APPLICATION_VERSION@) # Check whether the requested PACKAGE_FIND_VERSION is compatible if("${PACKAGE_VERSION}" VERSION_LESS "${PACKAGE_FIND_VERSION}") set(PACKAGE_VERSION_COMPATIBLE FALSE) else() set(PACKAGE_VERSION_COMPATIBLE TRUE) if ("${PACKAGE_VERSION}" VERSION_EQUAL "${PACKAGE_FIND_VERSION}") set(PACKAGE_VERSION_EXACT TRUE) endif() endif() resolv_wrapper-1.1.5/resolv_wrapper-config.cmake.in000644 001750 000144 00000000103 12421451254 022466 0ustar00asnusers000000 000000 set(RESOLV_WRAPPER_LIBRARY @LIB_INSTALL_DIR@/@RESOLV_WRAPPER_LIB@) resolv_wrapper-1.1.5/resolv_wrapper.pc.cmake000644 001750 000144 00000000215 12421451254 021223 0ustar00asnusers000000 000000 Name: @APPLICATION_NAME@ Description: The resolv_wrapper library Version: @APPLICATION_VERSION@ Libs: @LIB_INSTALL_DIR@/@RESOLV_WRAPPER_LIB@ resolv_wrapper-1.1.5/src/000755 001750 000144 00000000000 12764206152 015344 5ustar00asnusers000000 000000 resolv_wrapper-1.1.5/src/CMakeLists.txt000644 001750 000144 00000001306 12422105604 020073 0ustar00asnusers000000 000000 project(libresolv_wrapper C) include_directories(${CMAKE_BINARY_DIR}) add_library(resolv_wrapper SHARED resolv_wrapper.c) target_link_libraries(resolv_wrapper ${RWRAP_REQUIRED_LIBRARIES}) set_target_properties( resolv_wrapper PROPERTIES VERSION ${LIBRARY_VERSION} SOVERSION ${LIBRARY_SOVERSION} ) install( TARGETS resolv_wrapper RUNTIME DESTINATION ${BIN_INSTALL_DIR} LIBRARY DESTINATION ${LIB_INSTALL_DIR} ARCHIVE DESTINATION ${LIB_INSTALL_DIR} ) # This needs to be at the end if (POLICY CMP0026) cmake_policy(SET CMP0026 OLD) endif() get_target_property(RWRAP_LOCATION resolv_wrapper LOCATION) set(RESOLV_WRAPPER_LOCATION ${RWRAP_LOCATION} PARENT_SCOPE) resolv_wrapper-1.1.5/src/resolv_wrapper.c000644 001750 000144 00000131136 12764206067 020574 0ustar00asnusers000000 000000 /* * Copyright (c) 2014 Andreas Schneider * Copyright (c) 2014 Jakub Hrozek * * 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 #ifdef HAVE_ARPA_NAMESER_H #include #endif /* HAVE_ARPA_NAMESER_H */ #include #include #include #include #include #include #include #include #include #include #include /* GCC has printf type attribute check. */ #ifdef HAVE_ATTRIBUTE_PRINTF_FORMAT #define PRINTF_ATTRIBUTE(a,b) __attribute__ ((__format__ (__printf__, a, b))) #else #define PRINTF_ATTRIBUTE(a,b) #endif /* HAVE_ATTRIBUTE_PRINTF_FORMAT */ #ifdef HAVE_DESTRUCTOR_ATTRIBUTE #define DESTRUCTOR_ATTRIBUTE __attribute__ ((destructor)) #else #define DESTRUCTOR_ATTRIBUTE #endif /* HAVE_DESTRUCTOR_ATTRIBUTE */ #ifndef RWRAP_DEFAULT_FAKE_TTL #define RWRAP_DEFAULT_FAKE_TTL 600 #endif /* RWRAP_DEFAULT_FAKE_TTL */ #ifndef HAVE_NS_NAME_COMPRESS #define ns_name_compress dn_comp #endif #define ns_t_uri 256 enum rwrap_dbglvl_e { RWRAP_LOG_ERROR = 0, RWRAP_LOG_WARN, RWRAP_LOG_DEBUG, RWRAP_LOG_TRACE }; #ifdef NDEBUG # define RWRAP_LOG(...) #else /* NDEBUG */ static void rwrap_log(enum rwrap_dbglvl_e dbglvl, const char *func, const char *format, ...) PRINTF_ATTRIBUTE(3, 4); # define RWRAP_LOG(dbglvl, ...) rwrap_log((dbglvl), __func__, __VA_ARGS__) static void rwrap_log(enum rwrap_dbglvl_e dbglvl, const char *func, const char *format, ...) { char buffer[1024]; va_list va; const char *d; unsigned int lvl = 0; int pid = getpid(); d = getenv("RESOLV_WRAPPER_DEBUGLEVEL"); if (d != NULL) { lvl = atoi(d); } va_start(va, format); vsnprintf(buffer, sizeof(buffer), format, va); va_end(va); if (lvl >= dbglvl) { switch (dbglvl) { case RWRAP_LOG_ERROR: fprintf(stderr, "RWRAP_ERROR(%d) - %s: %s\n", pid, func, buffer); break; case RWRAP_LOG_WARN: fprintf(stderr, "RWRAP_WARN(%d) - %s: %s\n", pid, func, buffer); break; case RWRAP_LOG_DEBUG: fprintf(stderr, "RWRAP_DEBUG(%d) - %s: %s\n", pid, func, buffer); break; case RWRAP_LOG_TRACE: fprintf(stderr, "RWRAP_TRACE(%d) - %s: %s\n", pid, func, buffer); break; } } } #endif /* NDEBUG RWRAP_LOG */ #ifndef SAFE_FREE #define SAFE_FREE(x) do { if ((x) != NULL) {free(x); (x)=NULL;} } while(0) #endif #define NEXT_KEY(buf, key) do { \ (key) = (buf) ? strpbrk((buf), " \t") : NULL; \ if ((key) != NULL) { \ (key)[0] = '\0'; \ (key)++; \ } \ while ((key) != NULL \ && (isblank((int)(key)[0]))) { \ (key)++; \ } \ } while(0); #define RWRAP_MAX_RECURSION 64 /* Priority and weight can be omitted from the hosts file, but need to be part * of the output */ #define DFL_SRV_PRIO 1 #define DFL_SRV_WEIGHT 100 #define DFL_URI_PRIO 1 #define DFL_URI_WEIGHT 100 struct rwrap_srv_rrdata { uint16_t port; uint16_t prio; uint16_t weight; char hostname[MAXDNAME]; }; struct rwrap_uri_rrdata { uint16_t prio; uint16_t weight; char uri[MAXDNAME]; }; struct rwrap_soa_rrdata { uint32_t serial; uint32_t refresh; uint32_t retry; uint32_t expire; uint32_t minimum; char nameserver[MAXDNAME]; char mailbox[MAXDNAME]; }; struct rwrap_fake_rr { union fake_rrdata { struct in_addr a_rec; struct in6_addr aaaa_rec; struct rwrap_srv_rrdata srv_rec; struct rwrap_uri_rrdata uri_rec; struct rwrap_soa_rrdata soa_rec; char cname_rec[MAXDNAME]; char ptr_rec[MAXDNAME]; } rrdata; char key[MAXDNAME]; int type; /* ns_t_* */ }; static void rwrap_fake_rr_init(struct rwrap_fake_rr *rr, size_t len) { size_t i; for (i = 0; i < len; i++) { rr[i].type = ns_t_invalid; } } static int rwrap_create_fake_a_rr(const char *key, const char *value, struct rwrap_fake_rr *rr) { int ok; ok = inet_pton(AF_INET, value, &rr->rrdata.a_rec); if (!ok) { RWRAP_LOG(RWRAP_LOG_ERROR, "Failed to convert [%s] to binary\n", value); return -1; } memcpy(rr->key, key, strlen(key) + 1); rr->type = ns_t_a; return 0; } static int rwrap_create_fake_aaaa_rr(const char *key, const char *value, struct rwrap_fake_rr *rr) { int ok; ok = inet_pton(AF_INET6, value, &rr->rrdata.aaaa_rec); if (!ok) { RWRAP_LOG(RWRAP_LOG_ERROR, "Failed to convert [%s] to binary\n", value); return -1; } memcpy(rr->key, key, strlen(key) + 1); rr->type = ns_t_aaaa; return 0; } static int rwrap_create_fake_ns_rr(const char *key, const char *value, struct rwrap_fake_rr *rr) { memcpy(rr->rrdata.srv_rec.hostname, value, strlen(value) + 1); memcpy(rr->key, key, strlen(key) + 1); rr->type = ns_t_ns; return 0; } static int rwrap_create_fake_srv_rr(const char *key, const char *value, struct rwrap_fake_rr *rr) { char *str_prio; char *str_weight; char *str_port; const char *hostname; /* parse the value into priority, weight, port and hostname * and check the validity */ hostname = value; NEXT_KEY(hostname, str_port); NEXT_KEY(str_port, str_prio); NEXT_KEY(str_prio, str_weight); if (str_port == NULL || hostname == NULL) { RWRAP_LOG(RWRAP_LOG_ERROR, "Malformed SRV entry [%s]\n", value); return -1; } if (str_prio) { rr->rrdata.srv_rec.prio = atoi(str_prio); } else { rr->rrdata.srv_rec.prio = DFL_SRV_PRIO; } if (str_weight) { rr->rrdata.srv_rec.weight = atoi(str_weight); } else { rr->rrdata.srv_rec.weight = DFL_SRV_WEIGHT; } rr->rrdata.srv_rec.port = atoi(str_port); memcpy(rr->rrdata.srv_rec.hostname , hostname, strlen(hostname) + 1); memcpy(rr->key, key, strlen(key) + 1); rr->type = ns_t_srv; return 0; } static int rwrap_create_fake_uri_rr(const char *key, const char *value, struct rwrap_fake_rr *rr) { char *str_prio; char *str_weight; const char *uri; /* parse the value into priority, weight, and uri * and check the validity */ uri = value; NEXT_KEY(uri, str_prio); NEXT_KEY(str_prio, str_weight); if (uri == NULL) { RWRAP_LOG(RWRAP_LOG_ERROR, "Malformed URI entry [%s]\n", value); return -1; } if (str_prio) { rr->rrdata.uri_rec.prio = atoi(str_prio); } else { rr->rrdata.uri_rec.prio = DFL_URI_PRIO; } if (str_weight) { rr->rrdata.uri_rec.weight = atoi(str_weight); } else { rr->rrdata.uri_rec.weight = DFL_URI_WEIGHT; } memcpy(rr->rrdata.uri_rec.uri, uri, strlen(uri) + 1); memcpy(rr->key, key, strlen(key) + 1); rr->type = ns_t_uri; return 0; } static int rwrap_create_fake_soa_rr(const char *key, const char *value, struct rwrap_fake_rr *rr) { const char *nameserver; char *mailbox; char *str_serial; char *str_refresh; char *str_retry; char *str_expire; char *str_minimum; /* parse the value into nameserver, mailbox, serial, refresh, * retry, expire, minimum and check the validity */ nameserver = value; NEXT_KEY(nameserver, mailbox); NEXT_KEY(mailbox, str_serial); NEXT_KEY(str_serial, str_refresh); NEXT_KEY(str_refresh, str_retry); NEXT_KEY(str_retry, str_expire); NEXT_KEY(str_expire, str_minimum); if (nameserver == NULL || mailbox == NULL || str_serial == NULL || str_refresh == NULL || str_retry == NULL || str_expire == NULL || str_minimum == NULL) { RWRAP_LOG(RWRAP_LOG_ERROR, "Malformed SOA entry [%s]\n", value); return -1; } memcpy(rr->rrdata.soa_rec.nameserver, nameserver, strlen(nameserver)+1); memcpy(rr->rrdata.soa_rec.mailbox, mailbox, strlen(mailbox)+1); rr->rrdata.soa_rec.serial = atoi(str_serial); rr->rrdata.soa_rec.refresh = atoi(str_refresh); rr->rrdata.soa_rec.retry = atoi(str_retry); rr->rrdata.soa_rec.expire = atoi(str_expire); rr->rrdata.soa_rec.minimum = atoi(str_minimum); memcpy(rr->key, key, strlen(key) + 1); rr->type = ns_t_soa; return 0; } static int rwrap_create_fake_cname_rr(const char *key, const char *value, struct rwrap_fake_rr *rr) { memcpy(rr->rrdata.cname_rec , value, strlen(value) + 1); memcpy(rr->key, key, strlen(key) + 1); rr->type = ns_t_cname; return 0; } static int rwrap_create_fake_ptr_rr(const char *key, const char *value, struct rwrap_fake_rr *rr) { memcpy(rr->rrdata.ptr_rec , value, strlen(value) + 1); memcpy(rr->key, key, strlen(key) + 1); rr->type = ns_t_ptr; return 0; } /* Prepares a fake header with a single response. Advances header_blob */ static ssize_t rwrap_fake_header(uint8_t **header_blob, size_t remaining, size_t ancount, size_t arcount) { uint8_t *hb; HEADER *h; if (remaining < NS_HFIXEDSZ) { RWRAP_LOG(RWRAP_LOG_ERROR, "Buffer too small!\n"); return -1; } hb = *header_blob; memset(hb, 0, NS_HFIXEDSZ); h = (HEADER *) hb; h->id = res_randomid(); /* random query ID */ h->qr = 1; /* response flag */ h->rd = 1; /* recursion desired */ h->ra = 1; /* recursion available */ h->qdcount = htons(1); /* no. of questions */ h->ancount = htons(ancount); /* no. of answers */ h->arcount = htons(arcount); /* no. of add'tl records */ hb += NS_HFIXEDSZ; /* move past the header */ *header_blob = hb; return NS_HFIXEDSZ; } static ssize_t rwrap_fake_question(const char *question, uint16_t type, uint8_t **question_ptr, size_t remaining) { uint8_t *qb = *question_ptr; int n; n = ns_name_compress(question, qb, remaining, NULL, NULL); if (n < 0) { RWRAP_LOG(RWRAP_LOG_ERROR, "Failed to compress [%s]\n", question); return -1; } qb += n; remaining -= n; if (remaining < 2 * sizeof(uint16_t)) { RWRAP_LOG(RWRAP_LOG_ERROR, "Buffer too small!\n"); return -1; } NS_PUT16(type, qb); NS_PUT16(ns_c_in, qb); *question_ptr = qb; return n + 2 * sizeof(uint16_t); } static ssize_t rwrap_fake_rdata_common(uint16_t type, size_t rdata_size, const char *key, size_t remaining, uint8_t **rdata_ptr) { uint8_t *rd = *rdata_ptr; ssize_t written = 0; written = ns_name_compress(key, rd, remaining, NULL, NULL); if (written < 0) { RWRAP_LOG(RWRAP_LOG_ERROR, "Failed to compress [%s]\n", key); return -1; } rd += written; remaining -= written; if (remaining < 3 * sizeof(uint16_t) + sizeof(uint32_t)) { RWRAP_LOG(RWRAP_LOG_ERROR, "Buffer too small\n"); return -1; } NS_PUT16(type, rd); NS_PUT16(ns_c_in, rd); NS_PUT32(RWRAP_DEFAULT_FAKE_TTL, rd); NS_PUT16(rdata_size, rd); if (remaining < rdata_size) { RWRAP_LOG(RWRAP_LOG_ERROR, "Buffer too small\n"); return -1; } *rdata_ptr = rd; return written + 3 * sizeof(uint16_t) + sizeof(uint32_t) + rdata_size; } static ssize_t rwrap_fake_a(struct rwrap_fake_rr *rr, uint8_t *answer_ptr, size_t anslen) { uint8_t *a = answer_ptr; ssize_t resp_size; if (rr->type != ns_t_a) { RWRAP_LOG(RWRAP_LOG_ERROR, "Wrong type!\n"); return -1; } RWRAP_LOG(RWRAP_LOG_TRACE, "Adding A RR"); resp_size = rwrap_fake_rdata_common(ns_t_a, sizeof(struct in_addr), rr->key, anslen, &a); if (resp_size < 0) { return -1; } memcpy(a, &rr->rrdata.a_rec, sizeof(struct in_addr)); return resp_size; } static ssize_t rwrap_fake_aaaa(struct rwrap_fake_rr *rr, uint8_t *answer, size_t anslen) { uint8_t *a = answer; ssize_t resp_size; if (rr->type != ns_t_aaaa) { RWRAP_LOG(RWRAP_LOG_ERROR, "Wrong type!\n"); return -1; } RWRAP_LOG(RWRAP_LOG_TRACE, "Adding AAAA RR"); resp_size = rwrap_fake_rdata_common(ns_t_aaaa, sizeof(struct in6_addr), rr->key, anslen, &a); if (resp_size < 0) { return -1; } memcpy(a, &rr->rrdata.aaaa_rec, sizeof(struct in6_addr)); return resp_size; } static ssize_t rwrap_fake_ns(struct rwrap_fake_rr *rr, uint8_t *answer, size_t anslen) { uint8_t *a = answer; ssize_t resp_size = 0; size_t rdata_size; unsigned char hostname_compressed[MAXDNAME]; ssize_t compressed_len; if (rr->type != ns_t_ns) { RWRAP_LOG(RWRAP_LOG_ERROR, "Wrong type!\n"); return -1; } RWRAP_LOG(RWRAP_LOG_TRACE, "Adding NS RR"); /* Prepare the data to write */ compressed_len = ns_name_compress(rr->rrdata.srv_rec.hostname, hostname_compressed, MAXDNAME, NULL, NULL); if (compressed_len < 0) { return -1; } /* Is this enough? */ rdata_size = compressed_len; resp_size = rwrap_fake_rdata_common(ns_t_ns, rdata_size, rr->key, anslen, &a); if (resp_size < 0) { return -1; } memcpy(a, hostname_compressed, compressed_len); return resp_size; } static ssize_t rwrap_fake_srv(struct rwrap_fake_rr *rr, uint8_t *answer, size_t anslen) { uint8_t *a = answer; ssize_t resp_size; size_t rdata_size; unsigned char hostname_compressed[MAXDNAME]; ssize_t compressed_len; if (rr->type != ns_t_srv) { RWRAP_LOG(RWRAP_LOG_ERROR, "Wrong type!\n"); return -1; } RWRAP_LOG(RWRAP_LOG_TRACE, "Adding SRV RR"); rdata_size = 3 * sizeof(uint16_t); /* Prepare the data to write */ compressed_len = ns_name_compress(rr->rrdata.srv_rec.hostname, hostname_compressed, MAXDNAME, NULL, NULL); if (compressed_len < 0) { return -1; } rdata_size += compressed_len; resp_size = rwrap_fake_rdata_common(ns_t_srv, rdata_size, rr->key, anslen, &a); if (resp_size < 0) { return -1; } NS_PUT16(rr->rrdata.srv_rec.prio, a); NS_PUT16(rr->rrdata.srv_rec.weight, a); NS_PUT16(rr->rrdata.srv_rec.port, a); memcpy(a, hostname_compressed, compressed_len); return resp_size; } static ssize_t rwrap_fake_uri(struct rwrap_fake_rr *rr, uint8_t *answer, size_t anslen) { uint8_t *a = answer; ssize_t resp_size; size_t rdata_size; size_t uri_len; if (rr->type != ns_t_uri) { RWRAP_LOG(RWRAP_LOG_ERROR, "Wrong type!\n"); return -1; } RWRAP_LOG(RWRAP_LOG_TRACE, "Adding URI RR"); rdata_size = 3 * sizeof(uint16_t); uri_len = strlen(rr->rrdata.uri_rec.uri) + 1; rdata_size += uri_len; resp_size = rwrap_fake_rdata_common(ns_t_uri, rdata_size, rr->key, anslen, &a); if (resp_size < 0) { return -1; } NS_PUT16(rr->rrdata.uri_rec.prio, a); NS_PUT16(rr->rrdata.uri_rec.weight, a); memcpy(a, rr->rrdata.uri_rec.uri, uri_len); return resp_size; } static ssize_t rwrap_fake_soa(struct rwrap_fake_rr *rr, uint8_t *answer, size_t anslen) { uint8_t *a = answer; ssize_t resp_size; size_t rdata_size; unsigned char nameser_compressed[MAXDNAME]; ssize_t compressed_ns_len; unsigned char mailbox_compressed[MAXDNAME]; ssize_t compressed_mb_len; if (rr->type != ns_t_soa) { RWRAP_LOG(RWRAP_LOG_ERROR, "Wrong type!\n"); return -1; } RWRAP_LOG(RWRAP_LOG_TRACE, "Adding SOA RR"); rdata_size = 5 * sizeof(uint16_t); compressed_ns_len = ns_name_compress(rr->rrdata.soa_rec.nameserver, nameser_compressed, MAXDNAME, NULL, NULL); if (compressed_ns_len < 0) { return -1; } rdata_size += compressed_ns_len; compressed_mb_len = ns_name_compress(rr->rrdata.soa_rec.mailbox, mailbox_compressed, MAXDNAME, NULL, NULL); if (compressed_mb_len < 0) { return -1; } rdata_size += compressed_mb_len; resp_size = rwrap_fake_rdata_common(ns_t_soa, rdata_size, rr->key, anslen, &a); if (resp_size < 0) { return -1; } memcpy(a, nameser_compressed, compressed_ns_len); a += compressed_ns_len; memcpy(a, mailbox_compressed, compressed_mb_len); a += compressed_mb_len; NS_PUT32(rr->rrdata.soa_rec.serial, a); NS_PUT32(rr->rrdata.soa_rec.refresh, a); NS_PUT32(rr->rrdata.soa_rec.retry, a); NS_PUT32(rr->rrdata.soa_rec.expire, a); NS_PUT32(rr->rrdata.soa_rec.minimum, a); return resp_size; } static ssize_t rwrap_fake_cname(struct rwrap_fake_rr *rr, uint8_t *answer, size_t anslen) { uint8_t *a = answer; ssize_t resp_size; unsigned char hostname_compressed[MAXDNAME]; ssize_t rdata_size; if (rr->type != ns_t_cname) { RWRAP_LOG(RWRAP_LOG_ERROR, "Wrong type!\n"); return -1; } RWRAP_LOG(RWRAP_LOG_TRACE, "Adding CNAME RR"); /* Prepare the data to write */ rdata_size = ns_name_compress(rr->rrdata.cname_rec, hostname_compressed, MAXDNAME, NULL, NULL); if (rdata_size < 0) { return -1; } resp_size = rwrap_fake_rdata_common(ns_t_cname, rdata_size, rr->key, anslen, &a); if (resp_size < 0) { return -1; } memcpy(a, hostname_compressed, rdata_size); return resp_size; } static ssize_t rwrap_fake_ptr(struct rwrap_fake_rr *rr, uint8_t *answer, size_t anslen) { uint8_t *a = answer; ssize_t rdata_size; ssize_t resp_size; unsigned char hostname_compressed[MAXDNAME]; if (rr->type != ns_t_ptr) { RWRAP_LOG(RWRAP_LOG_ERROR, "Wrong type!\n"); return -1; } RWRAP_LOG(RWRAP_LOG_TRACE, "Adding PTR RR"); /* Prepare the data to write */ rdata_size = ns_name_compress(rr->rrdata.ptr_rec, hostname_compressed, MAXDNAME, NULL, NULL); if (rdata_size < 0) { return -1; } resp_size = rwrap_fake_rdata_common(ns_t_ptr, rdata_size, rr->key, anslen, &a); if (resp_size < 0) { return -1; } memcpy(a, hostname_compressed, rdata_size); return resp_size; } #define RESOLV_MATCH(line, name) \ (strncmp(line, name, sizeof(name) - 1) == 0 && \ (line[sizeof(name) - 1] == ' ' || \ line[sizeof(name) - 1] == '\t')) #define TYPE_MATCH(type, ns_type, rec_type, str_type, key, query) \ ((type) == (ns_type) && \ (strncmp((rec_type), (str_type), sizeof(str_type)) == 0) && \ (strcasecmp(key, query)) == 0) static int rwrap_get_record(const char *hostfile, unsigned recursion, const char *query, int type, struct rwrap_fake_rr *rr); static int rwrap_uri_recurse(const char *hostfile, unsigned recursion, const char *query, struct rwrap_fake_rr *rr) { int rc; rc = rwrap_get_record(hostfile, recursion, query, ns_t_uri, rr); if (rc == ENOENT) { rc = 0; } return rc; } static int rwrap_srv_recurse(const char *hostfile, unsigned recursion, const char *query, struct rwrap_fake_rr *rr) { int rc; rc = rwrap_get_record(hostfile, recursion, query, ns_t_a, rr); if (rc == 0) return 0; rc = rwrap_get_record(hostfile, recursion, query, ns_t_aaaa, rr); if (rc == ENOENT) rc = 0; return rc; } static int rwrap_cname_recurse(const char *hostfile, unsigned recursion, const char *query, struct rwrap_fake_rr *rr) { int rc; rc = rwrap_get_record(hostfile, recursion, query, ns_t_a, rr); if (rc == 0) return 0; rc = rwrap_get_record(hostfile, recursion, query, ns_t_aaaa, rr); if (rc == 0) return 0; rc = rwrap_get_record(hostfile, recursion, query, ns_t_cname, rr); if (rc == ENOENT) rc = 0; return rc; } static int rwrap_get_record(const char *hostfile, unsigned recursion, const char *query, int type, struct rwrap_fake_rr *rr) { FILE *fp = NULL; char buf[BUFSIZ]; char *key = NULL; char *value = NULL; int rc = ENOENT; unsigned num_uris = 0; if (recursion >= RWRAP_MAX_RECURSION) { RWRAP_LOG(RWRAP_LOG_ERROR, "Recursed too deep!\n"); return -1; } RWRAP_LOG(RWRAP_LOG_TRACE, "Searching in fake hosts file %s for %s:%d\n", hostfile, query, type); fp = fopen(hostfile, "r"); if (fp == NULL) { RWRAP_LOG(RWRAP_LOG_ERROR, "Opening %s failed: %s", hostfile, strerror(errno)); return -1; } while (fgets(buf, sizeof(buf), fp) != NULL) { char *rec_type; char *q; rec_type = buf; key = value = NULL; NEXT_KEY(rec_type, key); NEXT_KEY(key, value); if (key == NULL || value == NULL) { RWRAP_LOG(RWRAP_LOG_WARN, "Malformed line: not enough parts, use \"rec_type key data\n" "For example \"A cwrap.org 10.10.10.10\""); continue; } q = value; while(q[0] != '\n' && q[0] != '\0') { q++; } q[0] = '\0'; if (type == ns_t_uri && recursion > 0) { /* Skip non-URI records. */ if (!TYPE_MATCH(type, ns_t_uri, rec_type, "URI", key, query)) { continue; } /* Skip previous records based on the recurse depth. */ num_uris++; if (num_uris <= recursion) { continue; } } if (TYPE_MATCH(type, ns_t_a, rec_type, "A", key, query)) { rc = rwrap_create_fake_a_rr(key, value, rr); break; } else if (TYPE_MATCH(type, ns_t_aaaa, rec_type, "AAAA", key, query)) { rc = rwrap_create_fake_aaaa_rr(key, value, rr); break; } else if (TYPE_MATCH(type, ns_t_ns, rec_type, "NS", key, query)) { rc = rwrap_create_fake_ns_rr(key, value, rr); break; } else if (TYPE_MATCH(type, ns_t_srv, rec_type, "SRV", key, query)) { rc = rwrap_create_fake_srv_rr(key, value, rr); if (rc == 0) { rc = rwrap_srv_recurse(hostfile, recursion+1, rr->rrdata.srv_rec.hostname, rr + 1); } break; } else if (TYPE_MATCH(type, ns_t_uri, rec_type, "URI", key, query)) { rc = rwrap_create_fake_uri_rr(key, value, rr); if (rc == 0) { /* Recurse to collect multiple URI answers under a single key. */ rc = rwrap_uri_recurse(hostfile, recursion + 1, key, rr + 1); } break; } else if (TYPE_MATCH(type, ns_t_soa, rec_type, "SOA", key, query)) { rc = rwrap_create_fake_soa_rr(key, value, rr); break; } else if (TYPE_MATCH(type, ns_t_cname, rec_type, "CNAME", key, query)) { rc = rwrap_create_fake_cname_rr(key, value, rr); if (rc == 0) { rc = rwrap_cname_recurse(hostfile, recursion+1, value, rr + 1); } break; } else if (TYPE_MATCH(type, ns_t_a, rec_type, "CNAME", key, query)) { rc = rwrap_create_fake_cname_rr(key, value, rr); if (rc == 0) { rc = rwrap_cname_recurse(hostfile, recursion+1, value, rr + 1); } break; } else if (TYPE_MATCH(type, ns_t_ptr, rec_type, "PTR", key, query)) { rc = rwrap_create_fake_ptr_rr(key, value, rr); break; } } if (rc == ENOENT && recursion == 0 && key != NULL) { RWRAP_LOG(RWRAP_LOG_TRACE, "Record for [%s] not found\n", query); memcpy(rr->key, key, strlen(key) + 1); } fclose(fp); return rc; } static ssize_t rwrap_fake_empty(int type, const char *question, uint8_t *answer, size_t anslen) { ssize_t resp_data; size_t remaining = anslen; resp_data = rwrap_fake_header(&answer, remaining, 0, 0); if (resp_data < 0) { return -1; } remaining -= resp_data; resp_data += rwrap_fake_question(question, type, &answer, remaining); if (resp_data < 0) { return -1; } remaining -= resp_data; resp_data += rwrap_fake_rdata_common(type, 0, question, remaining, &answer); if (resp_data < 0) { return -1; } return resp_data; } static inline bool rwrap_known_type(int type) { switch (type) { case ns_t_a: case ns_t_aaaa: case ns_t_ns: case ns_t_srv: case ns_t_uri: case ns_t_soa: case ns_t_cname: case ns_t_ptr: return true; } return false; } static int rwrap_ancount(struct rwrap_fake_rr *rrs, int qtype) { int i; int ancount = 0; /* For URI return the number of URIs. */ if (qtype == ns_t_uri) { for (i = 0; i < RWRAP_MAX_RECURSION; i++) { if (rwrap_known_type(rrs[i].type) && rrs[i].type == qtype) { ancount++; } } return ancount; } /* Include all RRs in the stack until the sought type * in the answer section. This is the case i.e. when looking * up an A record but the name points to a CNAME */ for (i = 0; i < RWRAP_MAX_RECURSION; i++) { ancount++; if (rwrap_known_type(rrs[i].type) && rrs[i].type == qtype) { break; } } /* Return 0 records if the sought type wasn't in the stack */ return i < RWRAP_MAX_RECURSION ? ancount : 0; } static int rwrap_arcount(struct rwrap_fake_rr *rrs, int ancount) { int i; int arcount = 0; /* start from index ancount */ for (i = ancount; i < RWRAP_MAX_RECURSION; i++) { if (rwrap_known_type(rrs[i].type)) { arcount++; } } return arcount; } static ssize_t rwrap_add_rr(struct rwrap_fake_rr *rr, uint8_t *answer, size_t anslen) { ssize_t resp_data; if (rr == NULL) { RWRAP_LOG(RWRAP_LOG_ERROR, "Internal error!\n"); return -1; } switch (rr->type) { case ns_t_a: resp_data = rwrap_fake_a(rr, answer, anslen); break; case ns_t_aaaa: resp_data = rwrap_fake_aaaa(rr, answer, anslen); break; case ns_t_ns: resp_data = rwrap_fake_ns(rr, answer, anslen); break; case ns_t_srv: resp_data = rwrap_fake_srv(rr, answer, anslen); break; case ns_t_uri: resp_data = rwrap_fake_uri(rr, answer, anslen); break; case ns_t_soa: resp_data = rwrap_fake_soa(rr, answer, anslen); break; case ns_t_cname: resp_data = rwrap_fake_cname(rr, answer, anslen); break; case ns_t_ptr: resp_data = rwrap_fake_ptr(rr, answer, anslen); break; default: return -1; } return resp_data; } static ssize_t rwrap_fake_answer(struct rwrap_fake_rr *rrs, int type, uint8_t *answer, size_t anslen) { ssize_t resp_data; ssize_t rrlen; size_t remaining = anslen; int ancount; int arcount; int i; ancount = rwrap_ancount(rrs, type); arcount = rwrap_arcount(rrs, ancount); RWRAP_LOG(RWRAP_LOG_TRACE, "Got %d answers and %d additional records\n", ancount, arcount); resp_data = rwrap_fake_header(&answer, remaining, ancount, arcount); if (resp_data < 0) { return -1; } remaining -= resp_data; resp_data += rwrap_fake_question(rrs->key, rrs->type, &answer, remaining); if (resp_data < 0) { return -1; } remaining -= resp_data; /* answer */ for (i = 0; i < ancount; i++) { rrlen = rwrap_add_rr(&rrs[i], answer, remaining); if (rrlen < 0) { return -1; } remaining -= rrlen; answer += rrlen; resp_data += rrlen; } /* add authoritative NS here? */ /* additional records */ for (i = ancount; i < ancount + arcount; i++) { rrlen = rwrap_add_rr(&rrs[i], answer, remaining); if (rrlen < 0) { return -1; } remaining -= rrlen; answer += rrlen; resp_data += rrlen; } return resp_data; } /* Reads in a file in the following format: * TYPE RDATA * * Malformed entries are silently skipped. * Allocates answer buffer of size anslen that has to be freed after use. */ static int rwrap_res_fake_hosts(const char *hostfile, const char *query, int type, unsigned char *answer, size_t anslen) { int rc = ENOENT; char *query_name = NULL; size_t qlen = strlen(query); struct rwrap_fake_rr rrs[RWRAP_MAX_RECURSION]; ssize_t resp_size; RWRAP_LOG(RWRAP_LOG_TRACE, "Searching in fake hosts file %s\n", hostfile); if (qlen > 0 && query[qlen-1] == '.') { qlen--; } query_name = strndup(query, qlen); if (query_name == NULL) { return -1; } rwrap_fake_rr_init(rrs, RWRAP_MAX_RECURSION); rc = rwrap_get_record(hostfile, 0, query_name, type, rrs); switch (rc) { case 0: RWRAP_LOG(RWRAP_LOG_TRACE, "Found record for [%s]\n", query_name); resp_size = rwrap_fake_answer(rrs, type, answer, anslen); break; case ENOENT: RWRAP_LOG(RWRAP_LOG_TRACE, "No record for [%s]\n", query_name); resp_size = rwrap_fake_empty(type, rrs->key, answer, anslen); break; default: RWRAP_LOG(RWRAP_LOG_ERROR, "Error searching for [%s]\n", query_name); free(query_name); return -1; } switch (resp_size) { case -1: RWRAP_LOG(RWRAP_LOG_ERROR, "Error faking answer for [%s]\n", query_name); break; default: RWRAP_LOG(RWRAP_LOG_TRACE, "Successfully faked answer for [%s]\n", query_name); break; } free(query_name); return resp_size; } /********************************************************* * RWRAP LOADING LIBC FUNCTIONS *********************************************************/ #include typedef int (*__libc_res_ninit)(struct __res_state *state); typedef int (*__libc___res_ninit)(struct __res_state *state); typedef void (*__libc_res_nclose)(struct __res_state *state); typedef void (*__libc___res_nclose)(struct __res_state *state); typedef int (*__libc_res_nquery)(struct __res_state *state, const char *dname, int class, int type, unsigned char *answer, int anslen); typedef int (*__libc___res_nquery)(struct __res_state *state, const char *dname, int class, int type, unsigned char *answer, int anslen); typedef int (*__libc_res_nsearch)(struct __res_state *state, const char *dname, int class, int type, unsigned char *answer, int anslen); typedef int (*__libc___res_nsearch)(struct __res_state *state, const char *dname, int class, int type, unsigned char *answer, int anslen); #define RWRAP_SYMBOL_ENTRY(i) \ union { \ __libc_##i f; \ void *obj; \ } _libc_##i struct rwrap_libc_symbols { RWRAP_SYMBOL_ENTRY(res_ninit); RWRAP_SYMBOL_ENTRY(__res_ninit); RWRAP_SYMBOL_ENTRY(res_nclose); RWRAP_SYMBOL_ENTRY(__res_nclose); RWRAP_SYMBOL_ENTRY(res_nquery); RWRAP_SYMBOL_ENTRY(__res_nquery); RWRAP_SYMBOL_ENTRY(res_nsearch); RWRAP_SYMBOL_ENTRY(__res_nsearch); }; #undef RWRAP_SYMBOL_ENTRY struct rwrap { struct { void *handle; struct rwrap_libc_symbols symbols; } libc; struct { void *handle; struct rwrap_libc_symbols symbols; } libresolv; bool initialised; bool enabled; char *socket_dir; }; static struct rwrap rwrap; enum rwrap_lib { RWRAP_LIBC, RWRAP_LIBRESOLV }; #ifndef NDEBUG static const char *rwrap_str_lib(enum rwrap_lib lib) { switch (lib) { case RWRAP_LIBC: return "libc"; case RWRAP_LIBRESOLV: return "libresolv"; } /* Compiler would warn us about unhandled enum value if we get here */ return "unknown"; } #endif static void *rwrap_load_lib_handle(enum rwrap_lib lib) { int flags = RTLD_LAZY; void *handle = NULL; int i; #ifdef RTLD_DEEPBIND flags |= RTLD_DEEPBIND; #endif switch (lib) { case RWRAP_LIBRESOLV: #ifdef HAVE_LIBRESOLV handle = rwrap.libresolv.handle; if (handle == NULL) { for (i = 10; i >= 0; i--) { char soname[256] = {0}; snprintf(soname, sizeof(soname), "libresolv.so.%d", i); handle = dlopen(soname, flags); if (handle != NULL) { break; } } rwrap.libresolv.handle = handle; } break; #endif /* FALL TROUGH */ case RWRAP_LIBC: handle = rwrap.libc.handle; #ifdef LIBC_SO if (handle == NULL) { handle = dlopen(LIBC_SO, flags); rwrap.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; } } rwrap.libc.handle = handle; } break; } if (handle == NULL) { #ifdef RTLD_NEXT handle = rwrap.libc.handle = rwrap.libresolv.handle = RTLD_NEXT; #else RWRAP_LOG(RWRAP_LOG_ERROR, "Failed to dlopen library: %s\n", dlerror()); exit(-1); #endif } return handle; } static void *_rwrap_bind_symbol(enum rwrap_lib lib, const char *fn_name) { void *handle; void *func; handle = rwrap_load_lib_handle(lib); func = dlsym(handle, fn_name); if (func == NULL) { RWRAP_LOG(RWRAP_LOG_ERROR, "Failed to find %s: %s\n", fn_name, dlerror()); exit(-1); } RWRAP_LOG(RWRAP_LOG_TRACE, "Loaded %s from %s", fn_name, rwrap_str_lib(lib)); return func; } #define rwrap_bind_symbol_libc(sym_name) \ if (rwrap.libc.symbols._libc_##sym_name.obj == NULL) { \ rwrap.libc.symbols._libc_##sym_name.obj = \ _rwrap_bind_symbol(RWRAP_LIBC, #sym_name); \ } #define rwrap_bind_symbol_libresolv(sym_name) \ if (rwrap.libresolv.symbols._libc_##sym_name.obj == NULL) { \ rwrap.libresolv.symbols._libc_##sym_name.obj = \ _rwrap_bind_symbol(RWRAP_LIBRESOLV, #sym_name); \ } /* * IMPORTANT * * Functions especially from libc need to be loaded individually, you can't load * all at once or gdb will segfault at startup. The same applies to valgrind and * has probably something todo with with the linker. * So we need load each function at the point it is called the first time. */ static int libc_res_ninit(struct __res_state *state) { #if !defined(res_ninit) && defined(HAVE_RES_NINIT) #if defined(HAVE_RES_NINIT_IN_LIBRESOLV) rwrap_bind_symbol_libresolv(res_ninit); return rwrap.libresolv.symbols._libc_res_ninit.f(state); #else /* HAVE_RES_NINIT_IN_LIBRESOLV */ rwrap_bind_symbol_libc(res_ninit); return rwrap.libc.symbols._libc_res_ninit.f(state); #endif /* HAVE_RES_NINIT_IN_LIBRESOLV */ #elif defined(HAVE___RES_NINIT) rwrap_bind_symbol_libc(__res_ninit); return rwrap.libc.symbols._libc___res_ninit.f(state); #else #error "No res_ninit function" #endif } static void libc_res_nclose(struct __res_state *state) { #if !defined(res_close) && defined(HAVE_RES_NCLOSE) #if defined(HAVE_RES_NCLOSE_IN_LIBRESOLV) rwrap_bind_symbol_libresolv(res_nclose); rwrap.libresolv.symbols._libc_res_nclose.f(state); return; #else /* HAVE_RES_NCLOSE_IN_LIBRESOLV */ rwrap_bind_symbol_libc(res_nclose); rwrap.libc.symbols._libc_res_nclose.f(state); return; #endif /* HAVE_RES_NCLOSE_IN_LIBRESOLV */ #elif defined(HAVE___RES_NCLOSE) rwrap_bind_symbol_libc(__res_nclose); rwrap.libc.symbols._libc___res_nclose.f(state); #else #error "No res_nclose function" #endif } static int libc_res_nquery(struct __res_state *state, const char *dname, int class, int type, unsigned char *answer, int anslen) { #if !defined(res_nquery) && defined(HAVE_RES_NQUERY) rwrap_bind_symbol_libresolv(res_nquery); return rwrap.libresolv.symbols._libc_res_nquery.f(state, dname, class, type, answer, anslen); #elif defined(HAVE___RES_NQUERY) rwrap_bind_symbol_libresolv(__res_nquery); return rwrap.libresolv.symbols._libc___res_nquery.f(state, dname, class, type, answer, anslen); #else #error "No res_nquery function" #endif } static int libc_res_nsearch(struct __res_state *state, const char *dname, int class, int type, unsigned char *answer, int anslen) { #if !defined(res_nsearch) && defined(HAVE_RES_NSEARCH) rwrap_bind_symbol_libresolv(res_nsearch); return rwrap.libresolv.symbols._libc_res_nsearch.f(state, dname, class, type, answer, anslen); #elif defined(HAVE___RES_NSEARCH) rwrap_bind_symbol_libresolv(__res_nsearch); return rwrap.libresolv.symbols._libc___res_nsearch.f(state, dname, class, type, answer, anslen); #else #error "No res_nsearch function" #endif } /**************************************************************************** * RES_HELPER ***************************************************************************/ static int rwrap_parse_resolv_conf(struct __res_state *state, const char *resolv_conf) { FILE *fp; char buf[BUFSIZ]; int nserv = 0; fp = fopen(resolv_conf, "r"); if (fp == NULL) { RWRAP_LOG(RWRAP_LOG_ERROR, "Opening %s failed: %s", resolv_conf, strerror(errno)); return -1; } while(fgets(buf, sizeof(buf), fp) != NULL) { char *p; /* Ignore comments */ if (buf[0] == '#' || buf[0] == ';') { continue; } if (RESOLV_MATCH(buf, "nameserver") && nserv < MAXNS) { struct in_addr a; char *q; int ok; p = buf + strlen("nameserver"); /* Skip spaces and tabs */ while(isblank((int)p[0])) { p++; } q = p; while(q[0] != '\n' && q[0] != '\0') { q++; } q[0] = '\0'; ok = inet_pton(AF_INET, p, &a); if (ok) { state->nsaddr_list[state->nscount] = (struct sockaddr_in) { .sin_family = AF_INET, .sin_addr = a, .sin_port = htons(53), .sin_zero = { 0 }, }; state->nscount++; nserv++; } else { #ifdef HAVE_RESOLV_IPV6_NSADDRS /* IPv6 */ struct in6_addr a6; ok = inet_pton(AF_INET6, p, &a6); if (ok) { struct sockaddr_in6 *sa6; sa6 = malloc(sizeof(*sa6)); if (sa6 == NULL) { fclose(fp); return -1; } sa6->sin6_family = AF_INET6; sa6->sin6_port = htons(53); sa6->sin6_flowinfo = 0; sa6->sin6_addr = a6; state->_u._ext.nsaddrs[state->_u._ext.nscount] = sa6; state->_u._ext.nssocks[state->_u._ext.nscount] = -1; state->_u._ext.nsmap[state->_u._ext.nscount] = MAXNS + 1; state->_u._ext.nscount++; nserv++; } else { RWRAP_LOG(RWRAP_LOG_ERROR, "Malformed DNS server"); continue; } #else /* !HAVE_RESOLV_IPV6_NSADDRS */ /* * BSD uses an opaque structure to store the * IPv6 addresses. So we can not simply store * these addresses the same way as above. */ RWRAP_LOG(RWRAP_LOG_WARN, "resolve_wrapper does not support " "IPv6 on this platform"); continue; #endif } continue; } /* TODO: match other keywords */ } if (ferror(fp)) { RWRAP_LOG(RWRAP_LOG_ERROR, "Reading from %s failed", resolv_conf); fclose(fp); return -1; } fclose(fp); return 0; } /**************************************************************************** * RES_NINIT ***************************************************************************/ static int rwrap_res_ninit(struct __res_state *state) { int rc; rc = libc_res_ninit(state); if (rc == 0) { const char *resolv_conf = getenv("RESOLV_WRAPPER_CONF"); if (resolv_conf != NULL) { uint16_t i; (void)i; /* maybe unused */ /* Delete name servers */ state->nscount = 0; memset(state->nsaddr_list, 0, sizeof(state->nsaddr_list)); #ifdef HAVE_RESOLV_IPV6_NSADDRS state->_u._ext.nscount = 0; for (i = 0; i < state->_u._ext.nscount; i++) { SAFE_FREE(state->_u._ext.nsaddrs[i]); } #endif rc = rwrap_parse_resolv_conf(state, resolv_conf); } } return rc; } #if !defined(res_ninit) && defined(HAVE_RES_NINIT) int res_ninit(struct __res_state *state) #elif defined(HAVE___RES_NINIT) int __res_ninit(struct __res_state *state) #endif { return rwrap_res_ninit(state); } /**************************************************************************** * RES_INIT ***************************************************************************/ static struct __res_state rwrap_res_state; static int rwrap_res_init(void) { int rc; rc = rwrap_res_ninit(&rwrap_res_state); return rc; } #if !defined(res_ninit) && defined(HAVE_RES_INIT) int res_init(void) #elif defined(HAVE___RES_INIT) int __res_init(void) #endif { return rwrap_res_init(); } /**************************************************************************** * RES_NCLOSE ***************************************************************************/ static void rwrap_res_nclose(struct __res_state *state) { #ifdef HAVE_RESOLV_IPV6_NSADDRS int i; #endif libc_res_nclose(state); #ifdef HAVE_RESOLV_IPV6_NSADDRS if (state != NULL) { for (i = 0; i < state->_u._ext.nscount; i++) { SAFE_FREE(state->_u._ext.nsaddrs[i]); } } #endif } #if !defined(res_nclose) && defined(HAVE_RES_NCLOSE) void res_nclose(struct __res_state *state) #elif defined(HAVE___RES_NCLOSE) void __res_nclose(struct __res_state *state) #endif { rwrap_res_nclose(state); } /**************************************************************************** * RES_CLOSE ***************************************************************************/ static void rwrap_res_close(void) { rwrap_res_nclose(&rwrap_res_state); } #if defined(HAVE_RES_CLOSE) void res_close(void) #elif defined(HAVE___RES_CLOSE) void __res_close(void) #endif { rwrap_res_close(); } /**************************************************************************** * RES_NQUERY ***************************************************************************/ static int rwrap_res_nquery(struct __res_state *state, const char *dname, int class, int type, unsigned char *answer, int anslen) { int rc; const char *fake_hosts; #ifndef NDEBUG int i; #endif RWRAP_LOG(RWRAP_LOG_TRACE, "Resolve the domain name [%s] - class=%d, type=%d", dname, class, type); #ifndef NDEBUG for (i = 0; i < state->nscount; i++) { char ip[INET6_ADDRSTRLEN]; inet_ntop(AF_INET, &state->nsaddr_list[i].sin_addr, ip, sizeof(ip)); RWRAP_LOG(RWRAP_LOG_TRACE, " nameserver: %s", ip); } #endif fake_hosts = getenv("RESOLV_WRAPPER_HOSTS"); if (fake_hosts != NULL) { rc = rwrap_res_fake_hosts(fake_hosts, dname, type, answer, anslen); } else { rc = libc_res_nquery(state, dname, class, type, answer, anslen); } RWRAP_LOG(RWRAP_LOG_TRACE, "The returned response length is: %d", rc); return rc; } #if !defined(res_nquery) && defined(HAVE_RES_NQUERY) int res_nquery(struct __res_state *state, const char *dname, int class, int type, unsigned char *answer, int anslen) #elif defined(HAVE___RES_NQUERY) int __res_nquery(struct __res_state *state, const char *dname, int class, int type, unsigned char *answer, int anslen) #endif { return rwrap_res_nquery(state, dname, class, type, answer, anslen); } /**************************************************************************** * RES_QUERY ***************************************************************************/ static int rwrap_res_query(const char *dname, int class, int type, unsigned char *answer, int anslen) { int rc; rc = rwrap_res_ninit(&rwrap_res_state); if (rc != 0) { return rc; } rc = rwrap_res_nquery(&rwrap_res_state, dname, class, type, answer, anslen); return rc; } #if !defined(res_query) && defined(HAVE_RES_QUERY) int res_query(const char *dname, int class, int type, unsigned char *answer, int anslen) #elif defined(HAVE___RES_QUERY) int __res_query(const char *dname, int class, int type, unsigned char *answer, int anslen) #endif { return rwrap_res_query(dname, class, type, answer, anslen); } /**************************************************************************** * RES_NSEARCH ***************************************************************************/ static int rwrap_res_nsearch(struct __res_state *state, const char *dname, int class, int type, unsigned char *answer, int anslen) { int rc; const char *fake_hosts; #ifndef NDEBUG int i; #endif RWRAP_LOG(RWRAP_LOG_TRACE, "Resolve the domain name [%s] - class=%d, type=%d", dname, class, type); #ifndef NDEBUG for (i = 0; i < state->nscount; i++) { char ip[INET6_ADDRSTRLEN]; inet_ntop(AF_INET, &state->nsaddr_list[i].sin_addr, ip, sizeof(ip)); RWRAP_LOG(RWRAP_LOG_TRACE, " nameserver: %s", ip); } #endif fake_hosts = getenv("RESOLV_WRAPPER_HOSTS"); if (fake_hosts != NULL) { rc = rwrap_res_fake_hosts(fake_hosts, dname, type, answer, anslen); } else { rc = libc_res_nsearch(state, dname, class, type, answer, anslen); } RWRAP_LOG(RWRAP_LOG_TRACE, "The returned response length is: %d", rc); return rc; } #if !defined(res_nsearch) && defined(HAVE_RES_NSEARCH) int res_nsearch(struct __res_state *state, const char *dname, int class, int type, unsigned char *answer, int anslen) #elif defined(HAVE___RES_NSEARCH) int __res_nsearch(struct __res_state *state, const char *dname, int class, int type, unsigned char *answer, int anslen) #endif { return rwrap_res_nsearch(state, dname, class, type, answer, anslen); } /**************************************************************************** * RES_SEARCH ***************************************************************************/ static int rwrap_res_search(const char *dname, int class, int type, unsigned char *answer, int anslen) { int rc; rc = rwrap_res_ninit(&rwrap_res_state); if (rc != 0) { return rc; } rc = rwrap_res_nsearch(&rwrap_res_state, dname, class, type, answer, anslen); return rc; } #if !defined(res_search) && defined(HAVE_RES_SEARCH) int res_search(const char *dname, int class, int type, unsigned char *answer, int anslen) #elif defined(HAVE___RES_SEARCH) int __res_search(const char *dname, int class, int type, unsigned char *answer, int anslen) #endif { return rwrap_res_search(dname, class, type, answer, anslen); } resolv_wrapper-1.1.5/tests/000755 001750 000144 00000000000 12764206152 015717 5ustar00asnusers000000 000000 resolv_wrapper-1.1.5/tests/torture.h000644 001750 000144 00000005211 12421451254 017566 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; char *resolv_conf; }; #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); const char *torture_server_resolv_conf(void **state); void torture_setup_socket_dir(void **state); void torture_setup_dns_srv_ipv4(void **state); void torture_setup_dns_srv_ipv6(void **state); void torture_teardown_socket_dir(void **state); void torture_teardown_dns_srv(void **state); void torture_generate_random_buffer(uint8_t *out, int len); #endif /* _TORTURE_H */ resolv_wrapper-1.1.5/tests/torture.c000644 001750 000144 00000016707 12437551414 017603 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_DNS_SRV_IPV4 "127.0.0.10" /* socket wrapper IPv6 prefix fd00::5357:5fxx */ #define TORTURE_DNS_SRV_IPV6 "fd00::5357:5f0a" #define TORTURE_DNS_SRV_PORT 53 #define TORTURE_SOCKET_DIR "/tmp/test_resolv_wrapper_XXXXXX" #define TORTURE_DNS_SRV_PIDFILE "dns_srv.pid" #define TORTURE_PCAP_FILE "socket_trace.pcap" #define RWRAP_RESOLV_CONF_TMPL "rwrap_resolv_conf_XXXXXX" 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_DNS_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_DNS_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_DNS_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_DNS_SRV_PIDFILE) + 1; s->srv_pidfile = malloc(len); assert_non_null(s->srv_pidfile); snprintf(s->srv_pidfile, len, "%s/%s", p, TORTURE_DNS_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; } const char *torture_server_resolv_conf(void **state) { struct torture_state *s = (struct torture_state *) *state; if (s == NULL) { return NULL; } return s->resolv_conf; } static char *torture_setup_resolv_conf(const char **nameservers, size_t num_ns) { char *path; int rc_fd; FILE *resolv_conf; size_t i; path = strdup(RWRAP_RESOLV_CONF_TMPL); assert_non_null(path); rc_fd = mkstemp(path); assert_non_null(path); resolv_conf = fdopen(rc_fd, "a"); assert_non_null(resolv_conf); for (i = 0; i < num_ns; i++) { fputs("nameserver ", resolv_conf); fputs(nameservers[i], resolv_conf); fputs("\n", resolv_conf); } fflush(resolv_conf); fclose(resolv_conf); close(rc_fd); return path; } static void torture_teardown_resolv_conf(char *resolv_conf_path) { unlink(resolv_conf_path); free(resolv_conf_path); } static void torture_setup_dns_srv_ip(void **state, int family, const char *ip, int port) { struct torture_state *s; char start_dns_srv[1024] = {0}; int count = 0; int rc; const char *nameservers[1] = { torture_server_address(family), }; torture_setup_socket_dir(state); s = (struct torture_state *) *state; /* set default iface for the server */ setenv("SOCKET_WRAPPER_DEFAULT_IFACE", "10", 1); snprintf(start_dns_srv, sizeof(start_dns_srv), "%s/tests/dns_srv -b %s -p %d -D --pid %s", BINARYDIR, ip, port, s->srv_pidfile); rc = system(start_dns_srv); assert_int_equal(rc, 0); do { struct stat sb; count++; if (count > 100) { break; } rc = stat(s->srv_pidfile, &sb); usleep(200); } while (rc != 0); assert_int_equal(rc, 0); /* set default iface for the client */ setenv("SOCKET_WRAPPER_DEFAULT_IFACE", "170", 1); /* write a resolv.conf for the client */ s->resolv_conf = torture_setup_resolv_conf(nameservers, 1); } void torture_setup_dns_srv_ipv4(void **state) { torture_setup_dns_srv_ip(state, AF_INET, "0.0.0.0", torture_server_port()); } void torture_setup_dns_srv_ipv6(void **state) { torture_setup_dns_srv_ip(state, AF_INET6, "::", torture_server_port()); } void torture_teardown_socket_dir(void **state) { struct torture_state *s = (struct torture_state *) *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_dns_srv(void **state) { struct torture_state *s = (struct torture_state *) *state; char buf[8] = {0}; long int tmp; ssize_t rc; pid_t pid; int fd; bool is_running = true; int count; /* read the pidfile */ fd = open(s->srv_pidfile, O_RDONLY); if (fd < 0) { goto done; } rc = read(fd, buf, sizeof(buf)); close(fd); if (rc <= 0) { goto done; } buf[sizeof(buf) - 1] = '\0'; tmp = strtol(buf, NULL, 10); if (tmp == 0 || tmp > 0xFFFF || errno == ERANGE) { goto done; } pid = (pid_t)(tmp & 0xFFFF); /* Make sure the daemon goes away! */ for (count = 0; count < 10; count++) { kill(pid, SIGTERM); usleep(200); rc = kill(pid, 0); if (rc != 0) { is_running = false; break; } } if (is_running) { fprintf(stderr, "WARNING the DNS server is still running!\n"); } done: torture_teardown_resolv_conf(s->resolv_conf); 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(); } } resolv_wrapper-1.1.5/tests/CMakeLists.txt000644 001750 000144 00000004466 12563303252 020465 0ustar00asnusers000000 000000 project(tests C) include_directories( ${CMAKE_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_SOURCE_DIR}/src ${CMOCKA_INCLUDE_DIR} ) set(TORTURE_LIBRARY torture) # A simple DNS server for testing add_executable(dns_srv dns_srv.c) target_link_libraries(dns_srv ${RWRAP_REQUIRED_LIBRARIES}) add_executable(test_real_res_query test_real_res_query.c) target_link_libraries(test_real_res_query ${RWRAP_REQUIRED_LIBRARIES} ${CMOCKA_LIBRARY}) configure_file(fake_hosts.in ${CMAKE_CURRENT_BINARY_DIR}/fake_hosts @ONLY) add_library(${TORTURE_LIBRARY} STATIC torture.c) target_link_libraries(${TORTURE_LIBRARY} ${CMOCKA_LIBRARY} ${SWRAP_REQUIRED_LIBRARIES}) set(TESTSUITE_LIBRARIES ${RWRAP_REQUIRED_LIBRARIES} ${CMOCKA_LIBRARY}) if (HAVE_LIBRESOLV) set(TESTSUITE_LIBRARIES ${TESTSUITE_LIBRARIES} resolv) endif() set(RWRAP_TESTS test_res_init) set(PRELOAD_LIBS ${RESOLV_WRAPPER_LOCATION}) # Some tests require socket_wrapper as well. find_package(socket_wrapper) # On Solaris the socket functions are compiled into libresolv.so so we can't preload # socket_wrapper. Only faking will work! if (HAVE_LIBRESOLV AND SOCKET_WRAPPER_LIBRARY AND NOT SOLARIS) set(RWRAP_TESTS ${RWRAP_TESTS} test_res_query_search) set(PRELOAD_LIBS ${RESOLV_WRAPPER_LOCATION}:${SOCKET_WRAPPER_LIBRARY}) endif() foreach(_RWRAP_TEST ${RWRAP_TESTS}) add_cmocka_test(${_RWRAP_TEST} ${_RWRAP_TEST}.c ${TORTURE_LIBRARY} ${TESTSUITE_LIBRARIES}) if (OSX) set_property( TEST ${_RWRAP_TEST} PROPERTY ENVIRONMENT DYLD_FORCE_FLAT_NAMESPACE=1;DYLD_INSERT_LIBRARIES=${PRELOAD_LIBS}) else () set_property( TEST ${_RWRAP_TEST} PROPERTY ENVIRONMENT LD_PRELOAD=${PRELOAD_LIBS}) endif() endforeach() add_cmocka_test(test_dns_fake test_dns_fake.c ${TORTURE_LIBRARY} ${TESTSUITE_LIBRARIES}) if (OSX) set_property( TEST test_dns_fake PROPERTY ENVIRONMENT DYLD_FORCE_FLAT_NAMESPACE=1;DYLD_INSERT_LIBRARIES=${PRELOAD_LIBS};RESOLV_WRAPPER_HOSTS=${CMAKE_CURRENT_BINARY_DIR}/fake_hosts) else () set_property( TEST test_dns_fake PROPERTY ENVIRONMENT LD_PRELOAD=${PRELOAD_LIBS};RESOLV_WRAPPER_HOSTS=${CMAKE_CURRENT_BINARY_DIR}/fake_hosts) endif () resolv_wrapper-1.1.5/tests/test_res_init.c000644 001750 000144 00000012341 12567034411 020735 0ustar00asnusers000000 000000 #include "config.h" #include #include #include #include #include #include #include #include #include #include #include #include #define RWRAP_RESOLV_CONF_TMPL "rwrap_resolv_conf_XXXXXX" struct resolv_conf_test_state { int rc_fd; FILE *resolv_conf; char *resolv_conf_path; }; static int setup(void **state) { struct resolv_conf_test_state *test_state; test_state = malloc(sizeof(struct resolv_conf_test_state)); assert_non_null(test_state); test_state->rc_fd = -1; test_state->resolv_conf = NULL; test_state->resolv_conf_path = strdup(RWRAP_RESOLV_CONF_TMPL); assert_non_null(test_state->resolv_conf_path); test_state->rc_fd = mkstemp(test_state->resolv_conf_path); assert_non_null(test_state->resolv_conf_path); test_state->resolv_conf = fdopen(test_state->rc_fd, "a"); assert_non_null(test_state->resolv_conf); *state = test_state; return 0; } static int teardown(void **state) { struct resolv_conf_test_state *test_state; test_state = (struct resolv_conf_test_state *) *state; if (test_state == NULL) return -1; if (test_state->resolv_conf) { fclose(test_state->resolv_conf); } if (test_state->rc_fd != -1) { close(test_state->rc_fd); } if (test_state->resolv_conf_path) { unlink(test_state->resolv_conf_path); free(test_state->resolv_conf_path); } free(test_state); return 0; } static void test_res_ninit(void **state) { struct resolv_conf_test_state *test_state; struct __res_state dnsstate; /* * libc resolver only supports 3 name servers. Make sure the * extra are skipped for both v4 and v6. Also make sure there's * 'too many' nameservers even on platforms where v6 is not * supported. */ const char *nameservers[] = { "127.0.0.1", "10.10.10.1", "2607:f8b0:4009:802::1011", "10.10.10.2", "10.10.10.3", "2607:f8b0:4009:802::1012", NULL, }; int i; int rv; char straddr[INET6_ADDRSTRLEN] = { '\0' }; #ifdef HAVE_RESOLV_IPV6_NSADDRS struct sockaddr_in6 *sa6; #endif test_state = (struct resolv_conf_test_state *) *state; /* * Write a valid resolv.conf. * Make sure it's possible to skip comments */ fputs("# Hello world\n", test_state->resolv_conf); fputs("; This is resolv_wrapper\n", test_state->resolv_conf); for (i = 0; nameservers[i]; i++) { fputs("nameserver ", test_state->resolv_conf); fputs(nameservers[i], test_state->resolv_conf); fputs("\n", test_state->resolv_conf); } fflush(test_state->resolv_conf); rv = setenv("RESOLV_WRAPPER_CONF", test_state->resolv_conf_path, 1); assert_int_equal(rv, 0); memset(&dnsstate, 0, sizeof(dnsstate)); rv = res_ninit(&dnsstate); unsetenv("RESOLV_WRAPPER_CONF"); assert_int_equal(rv, 0); /* * Validate the number of parsed name servers. */ assert_int_equal(dnsstate.nscount + dnsstate._u._ext.nscount, MAXNS); #ifndef HAVE_RESOLV_IPV6_NSADDRS /* * On platforms that don't support IPv6, the v6 address is skipped * and we end up reading three v4 addresses. */ assert_int_equal(dnsstate.nscount, MAXNS); #else /* * test we have two v4 and one v6 server * * Note: This test assumes MAXNS == 3, which is the * case on all systems encountered so far. */ assert_int_equal(dnsstate.nscount, 2); assert_int_equal(dnsstate._u._ext.nscount, 1); #endif /* HAVE_RESOLV_IPV6_NSADDRS */ /* Validate the servers. */ /* IPv4 */ assert_int_equal(dnsstate.nsaddr_list[0].sin_family, AF_INET); assert_int_equal(dnsstate.nsaddr_list[0].sin_port, htons(53)); inet_ntop(AF_INET, &(dnsstate.nsaddr_list[0].sin_addr), straddr, INET6_ADDRSTRLEN); assert_string_equal(nameservers[0], straddr); assert_int_equal(dnsstate.nsaddr_list[1].sin_family, AF_INET); assert_int_equal(dnsstate.nsaddr_list[1].sin_port, htons(53)); inet_ntop(AF_INET, &(dnsstate.nsaddr_list[1].sin_addr), straddr, INET6_ADDRSTRLEN); assert_string_equal(nameservers[1], straddr); #ifndef HAVE_RESOLV_IPV6_NSADDRS /* * On platforms that don't support IPv6, the v6 address is skipped * and we end up reading three v4 addresses. */ assert_int_equal(dnsstate.nsaddr_list[2].sin_family, AF_INET); assert_int_equal(dnsstate.nsaddr_list[2].sin_port, htons(53)); inet_ntop(AF_INET, &(dnsstate.nsaddr_list[2].sin_addr), straddr, INET6_ADDRSTRLEN); assert_string_equal(nameservers[3], straddr); #else /* IPv6 */ sa6 = dnsstate._u._ext.nsaddrs[0]; assert_int_equal(sa6->sin6_family, AF_INET6); assert_int_equal(sa6->sin6_port, htons(53)); inet_ntop(AF_INET6, &(sa6->sin6_addr), straddr, INET6_ADDRSTRLEN); assert_string_equal(nameservers[2], straddr); #endif res_nclose(&dnsstate); } static void test_res_ninit_enoent(void **state) { int rv; struct __res_state dnsstate; (void) state; /* unused */ rv = setenv("RESOLV_WRAPPER_CONF", "/no/such/file", 1); assert_int_equal(rv, 0); /* Just make sure we don't crash, error is fine */ memset(&dnsstate, 0, sizeof(dnsstate)); rv = res_ninit(&dnsstate); unsetenv("RESOLV_WRAPPER_CONF"); assert_int_equal(rv, -1); } int main(void) { int rc; const struct CMUnitTest init_tests[] = { cmocka_unit_test_setup_teardown(test_res_ninit, setup, teardown), cmocka_unit_test(test_res_ninit_enoent), }; rc = cmocka_run_group_tests(init_tests, NULL, NULL); return rc; } resolv_wrapper-1.1.5/tests/dns_srv.c000644 001750 000144 00000032463 12567034507 017555 0ustar00asnusers000000 000000 /* * Copyright (C) Jakub Hrozek 2014 * * 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifndef PIDFILE #define PIDFILE "dns_srv.pid" #endif /* PIDFILE */ #define DNS_PORT 53 #define DFL_TTL 30 #ifndef BUFSIZE #define BUFSIZE 1024 #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 /* The macros below are taken from c-ares */ #define DNS__16BIT(p) ((unsigned short)((unsigned int) 0xffff & \ (((unsigned int)((unsigned char)(p)[0]) << 8U) | \ ((unsigned int)((unsigned char)(p)[1]))))) #define DNS__SET16BIT(p, v) (((p)[0] = (unsigned char)(((v) >> 8) & 0xff)), \ ((p)[1] = (unsigned char)((v) & 0xff))) #define DNS__SET32BIT(p, v) (((p)[0] = (unsigned char)(((v) >> 24) & 0xff)), \ ((p)[1] = (unsigned char)(((v) >> 16) & 0xff)), \ ((p)[2] = (unsigned char)(((v) >> 8) & 0xff)), \ ((p)[3] = (unsigned char)((v) & 0xff))); /* Macros for parsing a DNS header */ #define DNS_HEADER_QID(h) DNS__16BIT(h) #define DNS_HEADER_OPCODE(h) (((h)[2] >> 3) & 0xf) #define DNS_HEADER_TC(h) (((h)[2] >> 1) & 0x1) #define DNS_HEADER_QDCOUNT(h) DNS__16BIT((h) + 4) /* Macros for parsing the fixed part of a DNS question */ #define DNS_QUESTION_TYPE(q) DNS__16BIT(q) #define DNS_QUESTION_CLASS(q) DNS__16BIT((q) + 2) /* Macros for constructing a DNS header */ #define DNS_HEADER_SET_QID(h, v) DNS__SET16BIT(h, v) #define DNS_HEADER_SET_QR(h, v) ((h)[2] |= (unsigned char)(((v) & 0x1) << 7)) #define DNS_HEADER_SET_RD(h, v) ((h)[2] |= (unsigned char)((v) & 0x1)) #define DNS_HEADER_SET_RA(h, v) ((h)[3] |= (unsigned char)(((v) & 0x1) << 7)) #define DNS_HEADER_SET_QDCOUNT(h, v) DNS__SET16BIT((h) + 4, v) #define DNS_HEADER_SET_ANCOUNT(h, v) DNS__SET16BIT((h) + 6, v) /* Macros for constructing the fixed part of a DNS question */ #define DNS_QUESTION_SET_TYPE(q, v) DNS__SET16BIT(q, v) #define DNS_QUESTION_SET_CLASS(q, v) DNS__SET16BIT((q) + 2, v) /* Macros for constructing the fixed part of a DNS resource record */ #define DNS_RR_SET_TYPE(r, v) DNS__SET16BIT(r, v) #define DNS_RR_SET_CLASS(r, v) DNS__SET16BIT((r) + 2, v) #define DNS_RR_SET_TTL(r, v) DNS__SET32BIT((r) + 4, v) #define DNS_RR_SET_LEN(r, v) DNS__SET16BIT((r) + 8, v) #define DEFAULT_A_REC "127.0.10.10" struct dns_srv_opts { char *bind; bool daemon; int port; const char *pidfile; }; struct dns_query { char *query; uint16_t id; uint16_t qtype; uint16_t qclass; unsigned char *reply; size_t reply_len; }; static void free_dns_query(struct dns_query *query) { free(query->query); free(query->reply); memset(query, 0, sizeof(struct dns_query)); } static size_t encode_name(unsigned char *buffer, const char *name) { const char *p, *dot; unsigned char *bp; size_t len; p = name; bp = buffer; len = 0; while ((dot = strchr(p, '.')) != NULL) { *bp++ = dot - p; len++; while (p < dot) { *bp++ = *p++; len++; } p = dot + 1; /* move past the dot */ } *bp = '\0'; len++; return len; } static void fake_header(struct dns_query *query) { DNS_HEADER_SET_QID(query->reply, query->id); DNS_HEADER_SET_QR(query->reply, 1); DNS_HEADER_SET_RD(query->reply, 1); DNS_HEADER_SET_RA(query->reply, 1); DNS_HEADER_SET_QDCOUNT(query->reply, 1); DNS_HEADER_SET_ANCOUNT(query->reply, 1); } static size_t fake_question(struct dns_query *query, unsigned char **pout) { unsigned char *p; size_t len; p = *pout; len = encode_name(p, query->query); p += len; DNS_QUESTION_SET_TYPE(p, query->qtype); len += sizeof(uint16_t); DNS_QUESTION_SET_CLASS(p, query->qclass); len += sizeof(uint16_t); p += 2 * sizeof(uint16_t); *pout = p; return len; } static size_t fake_answer(struct dns_query *query, unsigned char **pout) { unsigned char *p; size_t len; size_t rlen; char *val; struct in_addr a_rec; p = *pout; len = encode_name(p, query->query); p += len; DNS_RR_SET_TYPE(p, query->qtype); len += sizeof(uint16_t); DNS_RR_SET_CLASS(p, query->qclass); len += sizeof(uint16_t); DNS_RR_SET_TTL(p, DFL_TTL); len += sizeof(uint32_t); switch (query->qtype) { case ns_t_a: val = getenv("RWRAP_TEST_A_REC"); inet_pton(AF_INET, val ? val : DEFAULT_A_REC, &a_rec); rlen = sizeof(struct in_addr); break; default: /* Unhandled record */ return -1; } DNS_RR_SET_LEN(p, rlen); len += sizeof(uint16_t); /* Move to the RDATA section */ p += sizeof(uint16_t) + /* type */ sizeof(uint16_t) + /* class */ sizeof(uint32_t) + /* ttl */ sizeof(uint16_t); /* rlen */ /* Copy RDATA */ memcpy(p, &a_rec, sizeof(struct in_addr)); len += rlen; *pout = p; return len; } static int fake_reply(struct dns_query *query) { unsigned char *p; query->reply = malloc(BUFSIZE); if (query->reply == NULL) { return ENOMEM; } memset(query->reply, 0, BUFSIZE); p = query->reply; fake_header(query); query->reply_len = NS_HFIXEDSZ; p += NS_HFIXEDSZ; /* advances p internally */ query->reply_len += fake_question(query, &p); query->reply_len += fake_answer(query, &p); return 0; } static char *extract_name(char **buffer, size_t maxlen) { char *query, *qp, *bp; unsigned int len; unsigned int i; query = malloc(maxlen); if (query == NULL) return NULL; i = 0; qp = query; bp = *buffer; do { len = *bp; bp++; if (len > (maxlen - (qp - query))) { /* label is past the buffer */ free(query); return NULL; } for (i = 0; i < len; i++) { *qp++ = *bp++; } if (len > 0) { *qp++ = '.'; } else { *qp = '\0'; } } while (len > 0); *buffer = bp; return query; } static int parse_query(unsigned char *buffer, size_t len, struct dns_query *query) { unsigned char *p; p = buffer; if (len < NS_HFIXEDSZ) { /* Message too short */ return EBADMSG; } if (DNS_HEADER_OPCODE(p) != 0) { /* Queries must have the opcode set to 0 */ return EBADMSG; } if (DNS_HEADER_QDCOUNT(p) != 1) { /* We only support one query */ return EBADMSG; } if (len < NS_HFIXEDSZ + 2 * sizeof(uint16_t)) { /* No room for class and type */ return EBADMSG; } /* Need to remember the query to respond with the same */ query->id = DNS_HEADER_QID(p); /* Done with the header, move past it */ p += NS_HFIXEDSZ; query->query = extract_name((char **) &p, len - NS_HFIXEDSZ); if (query->query == NULL) { return EIO; } query->qclass = DNS_QUESTION_CLASS(p); if (query->qclass != ns_c_in) { /* We only support Internet queries */ return EBADMSG; } query->qtype = DNS_QUESTION_TYPE(p); return 0; } static void dns(int sock) { struct sockaddr_storage css; socklen_t addrlen = sizeof(css); ssize_t bret; unsigned char buf[BUFSIZE]; struct dns_query query; int rv; ZERO_STRUCT(query); while (1) { free_dns_query(&query); /* for advanced features, use recvmsg here */ ZERO_STRUCT(buf); bret = recvfrom(sock, buf, BUFSIZE, 0, (struct sockaddr *) &css, &addrlen); if (bret == -1) { perror("recvfrom"); continue; } /* parse query */ rv = parse_query(buf, bret, &query); if (rv != 0) { continue; } /* Construct the reply */ rv = fake_reply(&query); if (rv != 0) { continue; } /* send reply back */ bret = sendto(sock, query.reply, query.reply_len, 0, (struct sockaddr *) &css, addrlen); if (bret == -1) { perror("sendto"); continue; } } } static int pidfile(const char *path) { int err; int fd; char pid_str[32] = { 0 }; ssize_t nwritten; size_t len; fd = open(path, O_RDONLY, 0644); err = errno; if (fd != -1) { close(fd); return EEXIST; } else if (err != ENOENT) { return err; } fd = open(path, O_CREAT | O_WRONLY | O_EXCL, 0644); err = errno; if (fd == -1) { return err; } snprintf(pid_str, sizeof(pid_str) -1, "%u\n", (unsigned int) getpid()); len = strlen(pid_str); nwritten = write(fd, pid_str, len); close(fd); if (nwritten != (ssize_t)len) { return EIO; } return 0; } static int become_daemon(void) { int ret; pid_t child_pid; int fd; int i; if (getppid() == 1) { return 0; } child_pid = fork(); if (child_pid == -1) { ret = errno; perror("fork"); return ret; } else if (child_pid > 0) { exit(0); } /* If a working directory was defined, go there */ #ifdef WORKING_DIR chdir(WORKING_DIR); #endif ret = setsid(); if (ret == -1) { ret = errno; perror("setsid"); return ret; } for (fd = getdtablesize(); fd >= 0; --fd) { close(fd); } for (i = 0; i < 3; i++) { fd = open("/dev/null", O_RDWR, 0); if (fd < 0) { fd = open("/dev/null", O_WRONLY, 0); } if (fd < 0) { ret = errno; perror("Can't open /dev/null"); return ret; } if (fd != i) { perror("Didn't get correct fd"); close(fd); return EINVAL; } } umask(0177); return 0; } /* * Returns 0 on success, errno on failure. * If successful, sock is a ready to use socket. */ static int setup_srv(struct dns_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 = SOCK_DGRAM; 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; } 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; } *_sock = sock; return 0; } int main(int argc, char **argv) { int ret; int sock = -1; struct dns_srv_opts opts; int opt; int optindex; static struct option long_options[] = { { discard_const_p(char, "bind-addr"), required_argument, 0, 'b' }, { discard_const_p(char, "daemon"), no_argument, 0, 'D' }, { discard_const_p(char, "port"), required_argument, 0, 'p' }, { discard_const_p(char, "pid"), required_argument, 0, 0 }, { 0, 0, 0, 0 } }; opts.bind = NULL; opts.pidfile = PIDFILE; opts.daemon = false; opts.port = DNS_PORT; while ((opt = getopt_long(argc, argv, "Db:p:", long_options, &optindex)) != -1) { switch (opt) { case 0: if (optindex == 3) { opts.pidfile = optarg; } break; case 'b': opts.bind = optarg; break; case 'D': opts.daemon = true; break; case 'p': opts.port = atoi(optarg); break; default: /* '?' */ fprintf(stderr, "Usage: %s [-p port] [-b bind_addr] " "[-D] [--pid pidfile]\n" "-D tells the server to become a " "deamon and write a PIDfile\n" "The default PIDfile is '%s' " "in the current directory\n", PIDFILE, 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) { if (opts.pidfile == NULL) { fprintf(stderr, "Error: pidfile == NULL\n"); ret = -1; goto done; } ret = pidfile(opts.pidfile); if (ret != 0) { fprintf(stderr, "Cannot create pidfile %s: %s\n", opts.pidfile, strerror(ret)); goto done; } } dns(sock); close(sock); if (opts.daemon) { unlink(opts.pidfile); } ret = 0; done: return ret; } resolv_wrapper-1.1.5/tests/test_res_query_search.c000644 001750 000144 00000014642 12567034507 022500 0ustar00asnusers000000 000000 /* * Copyright (C) Jakub Hrozek 2014 * * 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 #include #include #include #include "config.h" #include "torture.h" #include #include #include #include #include #include #include #include #define ANSIZE 256 static int setup_dns_srv_ipv4(void **state) { torture_setup_dns_srv_ipv4(state); setenv("RESOLV_WRAPPER_CONF", torture_server_resolv_conf(state), 1); return 0; } static int teardown(void **state) { torture_teardown_dns_srv(state); return 0; } static void test_res_nquery(void **state) { int rv; struct __res_state dnsstate; unsigned char answer[ANSIZE]; char addr[INET_ADDRSTRLEN]; ns_msg handle; ns_rr rr; /* expanded resource record */ (void) state; /* unused */ memset(&dnsstate, 0, sizeof(struct __res_state)); rv = res_ninit(&dnsstate); assert_int_equal(rv, 0); rv = res_nquery(&dnsstate, "www.cwrap.org", ns_c_in, ns_t_a, answer, sizeof(answer)); assert_int_not_equal(rv, -1); ns_initparse(answer, sizeof(answer), &handle); /* * The query must finish w/o an error, have one answer and the answer * must be a parseable RR of type A and have the address that our * test server sends. */ assert_int_equal(ns_msg_getflag(handle, ns_f_rcode), ns_r_noerror); assert_int_equal(ns_msg_count(handle, ns_s_an), 1); assert_int_equal(ns_parserr(&handle, ns_s_an, 0, &rr), 0); assert_int_equal(ns_rr_type(rr), ns_t_a); assert_non_null(inet_ntop(AF_INET, ns_rr_rdata(rr), addr, sizeof(addr))); assert_string_equal(addr, "127.0.10.10"); res_nclose(&dnsstate); } static void test_res_query(void **state) { int rv; unsigned char answer[ANSIZE]; char addr[INET_ADDRSTRLEN]; ns_msg handle; ns_rr rr; /* expanded resource record */ (void) state; /* unused */ rv = res_query("www.cwrap.org", ns_c_in, ns_t_a, answer, sizeof(answer)); assert_int_not_equal(rv, -1); ns_initparse(answer, sizeof(answer), &handle); /* * The query must finish w/o an error, have one answer and the answer * must be a parseable RR of type A and have the address that our * test server sends. */ assert_int_equal(ns_msg_getflag(handle, ns_f_rcode), ns_r_noerror); assert_int_equal(ns_msg_count(handle, ns_s_an), 1); assert_int_equal(ns_parserr(&handle, ns_s_an, 0, &rr), 0); assert_int_equal(ns_rr_type(rr), ns_t_a); assert_non_null(inet_ntop(AF_INET, ns_rr_rdata(rr), addr, sizeof(addr))); assert_string_equal(addr, "127.0.10.10"); res_close(); } static void test_res_nsearch(void **state) { int rv; struct __res_state dnsstate; unsigned char answer[ANSIZE]; char addr[INET_ADDRSTRLEN]; ns_msg handle; ns_rr rr; /* expanded resource record */ (void) state; /* unused */ memset(&dnsstate, 0, sizeof(struct __res_state)); rv = res_ninit(&dnsstate); assert_int_equal(rv, 0); rv = res_nsearch(&dnsstate, "www.cwrap.org", ns_c_in, ns_t_a, answer, sizeof(answer)); assert_int_not_equal(rv, -1); ns_initparse(answer, sizeof(answer), &handle); /* The query must finish w/o an error, have one answer and the answer * must be a parseable RR of type A and have the address that our * test server sends */ assert_int_equal(ns_msg_getflag(handle, ns_f_rcode), ns_r_noerror); assert_int_equal(ns_msg_count(handle, ns_s_an), 1); assert_int_equal(ns_parserr(&handle, ns_s_an, 0, &rr), 0); assert_int_equal(ns_rr_type(rr), ns_t_a); assert_non_null(inet_ntop(AF_INET, ns_rr_rdata(rr), addr, sizeof(addr))); assert_string_equal(addr, "127.0.10.10"); res_nclose(&dnsstate); } static void test_res_search(void **state) { int rv; unsigned char answer[ANSIZE]; char addr[INET_ADDRSTRLEN]; ns_msg handle; ns_rr rr; /* expanded resource record */ (void) state; /* unused */ rv = res_search("www.cwrap.org", ns_c_in, ns_t_a, answer, sizeof(answer)); assert_int_not_equal(rv, -1); ns_initparse(answer, sizeof(answer), &handle); /* The query must finish w/o an error, have one answer and the answer * must be a parseable RR of type A and have the address that our * test server sends */ assert_int_equal(ns_msg_getflag(handle, ns_f_rcode), ns_r_noerror); assert_int_equal(ns_msg_count(handle, ns_s_an), 1); assert_int_equal(ns_parserr(&handle, ns_s_an, 0, &rr), 0); assert_int_equal(ns_rr_type(rr), ns_t_a); assert_non_null(inet_ntop(AF_INET, ns_rr_rdata(rr), addr, sizeof(addr))); assert_string_equal(addr, "127.0.10.10"); res_close(); } int main(void) { int rc; const struct CMUnitTest res_tests[] = { cmocka_unit_test_setup_teardown(test_res_nquery, setup_dns_srv_ipv4, teardown), cmocka_unit_test_setup_teardown(test_res_query, setup_dns_srv_ipv4, teardown), cmocka_unit_test_setup_teardown(test_res_nsearch, setup_dns_srv_ipv4, teardown), cmocka_unit_test_setup_teardown(test_res_search, setup_dns_srv_ipv4, teardown), }; rc = cmocka_run_group_tests(res_tests, NULL, NULL); return rc; } resolv_wrapper-1.1.5/tests/test_real_res_query.c000644 001750 000144 00000013462 12721063307 022145 0ustar00asnusers000000 000000 /* * Copyright (C) Jakub Hrozek 2014 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include #include #include #include "config.h" #include #include #include #include #include #include #include #include #include #ifndef MIN #define MIN(a,b) ((a)<(b)?(a):(b)) #endif #define ANSIZE 256 static void print_asc(const uint8_t *buf, uint32_t len) { uint32_t i; for (i = 0; i < len; i++) { printf("%c", isprint(buf[i])?buf[i]:'.'); } } static void dump_data(const uint8_t *buf, int len) { int i=0; static const uint8_t empty[16] = { 0, }; if (len<=0) return; for (i=0; i 0) && (len > i+16) && (memcmp(&buf[i], &empty, 16) == 0)) { i +=16; continue; } if (i8) printf(" "); while (n--) printf(" "); n = MIN(8,i%16); print_asc(&buf[i-(i%16)],n); printf( " " ); n = (i%16) - n; if (n>0) print_asc(&buf[i-n],n); printf("\n"); } } static void test_res_query_a_record(void **state) { int rv; struct __res_state dnsstate; unsigned char answer[ANSIZE] = { 0 }; char addr[INET_ADDRSTRLEN]; ns_msg handle; ns_rr rr; /* expanded resource record */ (void) state; /* unused */ memset(&dnsstate, 0, sizeof(struct __res_state)); rv = res_ninit(&dnsstate); assert_int_equal(rv, 0); rv = res_nquery(&dnsstate, "cwrap.org", ns_c_in, ns_t_a, answer, sizeof(answer)); assert_in_range(rv, 1, 100); printf("dump answer:\n"); dump_data(answer, rv); ns_initparse(answer, sizeof(answer), &handle); /* The query must finish w/o an error, have one answer and the answer * must be a parseable RR of type A and have the address that our * fake hosts file contains */ assert_int_equal(ns_msg_getflag(handle, ns_f_rcode), ns_r_noerror); assert_int_equal(ns_msg_count(handle, ns_s_an), 1); assert_int_equal(ns_parserr(&handle, ns_s_an, 0, &rr), 0); assert_int_equal(ns_rr_type(rr), ns_t_a); assert_non_null(inet_ntop(AF_INET, ns_rr_rdata(rr), addr, sizeof(addr))); assert_string_equal(addr, "78.46.80.163"); } static void test_res_query_ns_record(void **state) { int rv; struct __res_state dnsstate; unsigned char answer[ANSIZE] = { 0 }; char addr[INET_ADDRSTRLEN]; ns_msg handle; ns_rr rr; /* expanded resource record */ (void) state; /* unused */ memset(&dnsstate, 0, sizeof(struct __res_state)); rv = res_ninit(&dnsstate); assert_int_equal(rv, 0); rv = res_nquery(&dnsstate, "cwrap.org", ns_c_in, ns_t_ns, answer, sizeof(answer)); assert_in_range(rv, 1, 150); printf("dump answer:\n"); dump_data(answer, rv); ns_initparse(answer, sizeof(answer), &handle); /* The query must finish w/o an error, have two answers and the answer * must be a parseable RR of type A and have the address that our * fake hosts file contains */ assert_int_equal(ns_msg_getflag(handle, ns_f_rcode), ns_r_noerror); assert_int_equal(ns_msg_count(handle, ns_s_an), 2); assert_int_equal(ns_parserr(&handle, ns_s_an, 0, &rr), 0); assert_int_equal(ns_rr_type(rr), ns_t_ns); assert_non_null(inet_ntop(AF_INET, ns_rr_rdata(rr), addr, sizeof(addr))); /*assert_string_equal(addr, "3.110.115.50");*/ } static void test_res_query_srv_record(void **state) { int rv; struct __res_state dnsstate; unsigned char answer[ANSIZE] = { 0 }; ns_msg handle; ns_rr rr; /* expanded resource record */ const uint8_t *rrdata; int prio; int weight; int port; char hostname[MAXDNAME]; (void) state; /* unused */ memset(&dnsstate, 0, sizeof(struct __res_state)); rv = res_ninit(&dnsstate); assert_int_equal(rv, 0); rv = res_nquery(&dnsstate, "_http._tcp.mxtoolbox.com", ns_c_in, ns_t_srv, answer, sizeof(answer)); assert_in_range(rv, 1, 100); printf("dump answer:\n"); dump_data(answer, rv); ns_initparse(answer, sizeof(answer), &handle); /* * The query must finish w/o an error, have one answer and the answer * must be a parseable RR of type SRV and have the priority, weight, * port and hostname as in the fake hosts file */ assert_int_equal(ns_msg_getflag(handle, ns_f_rcode), ns_r_noerror); assert_int_equal(ns_msg_count(handle, ns_s_an), 1); assert_int_equal(ns_parserr(&handle, ns_s_an, 0, &rr), 0); assert_int_equal(ns_rr_type(rr), ns_t_srv); rrdata = ns_rr_rdata(rr); NS_GET16(prio, rrdata); NS_GET16(weight, rrdata); NS_GET16(port, rrdata); rv = ns_name_uncompress(ns_msg_base(handle), ns_msg_end(handle), rrdata, hostname, MAXDNAME); assert_int_not_equal(rv, -1); assert_int_equal(prio, 10); assert_int_equal(weight, 100); assert_int_equal(port, 80); assert_string_equal(hostname, "mxtoolbox.com"); } int main(void) { int rc; const struct CMUnitTest real_tests[] = { cmocka_unit_test(test_res_query_a_record), cmocka_unit_test(test_res_query_ns_record), cmocka_unit_test(test_res_query_srv_record), }; rc = cmocka_run_group_tests(real_tests, NULL, NULL); return rc; } resolv_wrapper-1.1.5/tests/fake_hosts.in000644 001750 000144 00000001312 12764206067 020377 0ustar00asnusers000000 000000 NS cwrap.org ns1.cwrap.org NS cwrap.org ns2.cwrap.org A brokenrecord.com A cwrap.org 127.0.0.21 AAAA cwrap6.org 2a00:1450:4013:c01::63 SRV _ldap._tcp.cwrap.org ldap.cwrap.org 389 1 5 SRV _krb5._tcp.cwrap.org krb5.cwrap.org 88 SOA cwrap.org ns1.cwrap.org admin.cwrap.org 2014100457 3600 300 1814400 600 CNAME rwrap.org web.cwrap.org CNAME web.cwrap.org www.cwrap.org A www.cwrap.org 127.0.0.22 A krb5.cwrap.org 127.0.0.23 A ns1.cwrap.org 127.0.0.24 A ns2.cwrap.org 127.0.0.25 URI _vpn.cwrap.org https://vpn.cwrap.org/VPN 2 5 URI _vpn.cwrap.org https://vpn2.cwrap.org/VPN 2 10 URI _vpn.cwrap.org https://vpn3.cwrap.org/VPN 2 20 URI _ftp.cwrap.org ftp://ftp.cwrap.org/public PTR 22.0.0.127.in-addr.arpa www.cwrap.org resolv_wrapper-1.1.5/tests/test_dns_fake.c000644 001750 000144 00000052322 12764206067 020705 0ustar00asnusers000000 000000 /* * Copyright (C) Jakub Hrozek 2014 * * 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 #include #include #include #include "config.h" #include #include #include #include #include #include #include #include #define ANSIZE 256 #define ns_t_uri 256 static void test_res_fake_a_query(void **state) { int rv; struct __res_state dnsstate; unsigned char answer[ANSIZE]; char addr[INET_ADDRSTRLEN]; ns_msg handle; ns_rr rr; /* expanded resource record */ (void) state; /* unused */ memset(&dnsstate, 0, sizeof(struct __res_state)); rv = res_ninit(&dnsstate); assert_int_equal(rv, 0); rv = res_nquery(&dnsstate, "cwrap.org", ns_c_in, ns_t_a, answer, sizeof(answer)); assert_in_range(rv, 1, 100); ns_initparse(answer, sizeof(answer), &handle); /* The query must finish w/o an error, have one answer and the answer * must be a parseable RR of type A and have the address that our * fake hosts file contains */ assert_int_equal(ns_msg_getflag(handle, ns_f_rcode), ns_r_noerror); assert_int_equal(ns_msg_count(handle, ns_s_an), 1); assert_int_equal(ns_parserr(&handle, ns_s_an, 0, &rr), 0); assert_int_equal(ns_rr_type(rr), ns_t_a); assert_non_null(inet_ntop(AF_INET, ns_rr_rdata(rr), addr, sizeof(addr))); assert_string_equal(addr, "127.0.0.21"); } static void test_res_fake_a_query_case_insensitive(void **state) { int rv; struct __res_state dnsstate; unsigned char answer[ANSIZE]; char addr[INET_ADDRSTRLEN]; ns_msg handle; ns_rr rr; /* expanded resource record */ (void) state; /* unused */ memset(&dnsstate, 0, sizeof(struct __res_state)); rv = res_ninit(&dnsstate); assert_int_equal(rv, 0); rv = res_nquery(&dnsstate, "CWRAP.ORG", ns_c_in, ns_t_a, answer, sizeof(answer)); assert_in_range(rv, 1, 100); ns_initparse(answer, sizeof(answer), &handle); /* The query must finish w/o an error, have one answer and the answer * must be a parseable RR of type A and have the address that our * fake hosts file contains. Case does not matter. */ assert_int_equal(ns_msg_getflag(handle, ns_f_rcode), ns_r_noerror); assert_int_equal(ns_msg_count(handle, ns_s_an), 1); assert_int_equal(ns_parserr(&handle, ns_s_an, 0, &rr), 0); assert_int_equal(ns_rr_type(rr), ns_t_a); assert_non_null(inet_ntop(AF_INET, ns_rr_rdata(rr), addr, sizeof(addr))); assert_string_equal(addr, "127.0.0.21"); res_nclose(&dnsstate); } static void test_res_fake_a_query_trailing_dot(void **state) { int rv; struct __res_state dnsstate; unsigned char answer[ANSIZE]; char addr[INET_ADDRSTRLEN]; ns_msg handle; ns_rr rr; /* expanded resource record */ (void) state; /* unused */ memset(&dnsstate, 0, sizeof(struct __res_state)); rv = res_ninit(&dnsstate); assert_int_equal(rv, 0); rv = res_nquery(&dnsstate, "cwrap.org.", ns_c_in, ns_t_a, answer, ANSIZE); assert_in_range(rv, 1, 100); ns_initparse(answer, 256, &handle); /* The query must finish w/o an error, have one answer and the answer * must be a parseable RR of type A and have the address that our * fake hosts file contains */ assert_int_equal(ns_msg_getflag(handle, ns_f_rcode), ns_r_noerror); assert_int_equal(ns_msg_count(handle, ns_s_an), 1); assert_int_equal(ns_parserr(&handle, ns_s_an, 0, &rr), 0); assert_int_equal(ns_rr_type(rr), ns_t_a); assert_non_null(inet_ntop(AF_INET, ns_rr_rdata(rr), addr, 256)); assert_string_equal(addr, "127.0.0.21"); res_nclose(&dnsstate); } static void test_res_fake_a_query_notfound(void **state) { int rv; struct __res_state dnsstate; unsigned char answer[ANSIZE]; ns_msg handle; (void) state; /* unused */ memset(&dnsstate, 0, sizeof(struct __res_state)); rv = res_ninit(&dnsstate); assert_int_equal(rv, 0); rv = res_nquery(&dnsstate, "nosuchentry.org", ns_c_in, ns_t_a, answer, sizeof(answer)); assert_in_range(rv, 1, 100); ns_initparse(answer, sizeof(answer), &handle); /* The query must finish w/o an error and have no answer */ assert_int_equal(ns_msg_getflag(handle, ns_f_rcode), ns_r_noerror); assert_int_equal(ns_msg_count(handle, ns_s_an), 0); } static void test_res_fake_aaaa_query(void **state) { int rv; struct __res_state dnsstate; unsigned char answer[ANSIZE]; char addr[INET6_ADDRSTRLEN]; ns_msg handle; ns_rr rr; /* expanded resource record */ (void) state; /* unused */ memset(&dnsstate, 0, sizeof(struct __res_state)); rv = res_ninit(&dnsstate); assert_int_equal(rv, 0); rv = res_nquery(&dnsstate, "cwrap6.org", ns_c_in, ns_t_aaaa, answer, sizeof(answer)); assert_in_range(rv, 1, 100); ns_initparse(answer, sizeof(answer), &handle); /* The query must finish w/o an error, have one answer and the answer * must be a parseable RR of type AAAA and have the address that our * fake hosts file contains */ assert_int_equal(ns_msg_getflag(handle, ns_f_rcode), ns_r_noerror); assert_int_equal(ns_msg_count(handle, ns_s_an), 1); assert_int_equal(ns_parserr(&handle, ns_s_an, 0, &rr), 0); assert_int_equal(ns_rr_type(rr), ns_t_aaaa); assert_non_null(inet_ntop(AF_INET6, ns_rr_rdata(rr), addr, sizeof(addr))); assert_string_equal(addr, "2a00:1450:4013:c01::63"); } static void test_res_fake_aaaa_query_notfound(void **state) { int rv; struct __res_state dnsstate; unsigned char answer[ANSIZE]; ns_msg handle; (void) state; /* unused */ memset(&dnsstate, 0, sizeof(struct __res_state)); rv = res_ninit(&dnsstate); assert_int_equal(rv, 0); rv = res_nquery(&dnsstate, "nosuchentry.org", ns_c_in, ns_t_aaaa, answer, sizeof(answer)); assert_in_range(rv, 1, 100); ns_initparse(answer, sizeof(answer), &handle); /* The query must finish w/o an error and have no answer */ assert_int_equal(ns_msg_getflag(handle, ns_f_rcode), ns_r_noerror); assert_int_equal(ns_msg_count(handle, ns_s_an), 0); } static void test_res_fake_srv_query(void **state) { int rv; struct __res_state dnsstate; unsigned char answer[ANSIZE]; ns_msg handle; ns_rr rr; /* expanded resource record */ const uint8_t *rrdata; int prio; int weight; int port; char hostname[MAXDNAME]; (void) state; /* unused */ memset(&dnsstate, 0, sizeof(struct __res_state)); rv = res_ninit(&dnsstate); assert_int_equal(rv, 0); rv = res_nquery(&dnsstate, "_ldap._tcp.cwrap.org", ns_c_in, ns_t_srv, answer, sizeof(answer)); assert_in_range(rv, 1, 100); ns_initparse(answer, sizeof(answer), &handle); /* * The query must finish w/o an error, have one answer and the answer * must be a parseable RR of type SRV and have the priority, weight, * port and hostname as in the fake hosts file */ assert_int_equal(ns_msg_getflag(handle, ns_f_rcode), ns_r_noerror); assert_int_equal(ns_msg_count(handle, ns_s_an), 1); assert_int_equal(ns_parserr(&handle, ns_s_an, 0, &rr), 0); assert_int_equal(ns_rr_type(rr), ns_t_srv); rrdata = ns_rr_rdata(rr); NS_GET16(prio, rrdata); NS_GET16(weight, rrdata); NS_GET16(port, rrdata); rv = ns_name_uncompress(ns_msg_base(handle), ns_msg_end(handle), rrdata, hostname, MAXDNAME); assert_int_not_equal(rv, -1); assert_int_equal(prio, 1); assert_int_equal(weight, 5); assert_int_equal(port, 389); assert_string_equal(hostname, "ldap.cwrap.org"); } /* * Test the case of a SRV record query where the * fake hosts file entry is minimal in the sense * that it omits the priority and weight entries. * The server then fills in some default values. */ static void test_res_fake_srv_query_minimal(void **state) { int rv; struct __res_state dnsstate; unsigned char answer[ANSIZE]; ns_msg handle; ns_rr rr; /* expanded resource record */ const uint8_t *rrdata; int prio; int weight; int port; char hostname[MAXDNAME]; char addr[INET_ADDRSTRLEN]; (void) state; /* unused */ memset(&dnsstate, 0, sizeof(struct __res_state)); rv = res_ninit(&dnsstate); assert_int_equal(rv, 0); rv = res_nquery(&dnsstate, "_krb5._tcp.cwrap.org", ns_c_in, ns_t_srv, answer, sizeof(answer)); assert_in_range(rv, 1, 256); ns_initparse(answer, sizeof(answer), &handle); /* * The query must finish w/o an error, have one answer and the answer * must be a parseable RR of type SRV and have the priority, weight, * port and hostname as in the fake hosts file */ assert_int_equal(ns_msg_getflag(handle, ns_f_rcode), ns_r_noerror); assert_int_equal(ns_msg_count(handle, ns_s_an), 1); assert_int_equal(ns_parserr(&handle, ns_s_an, 0, &rr), 0); assert_int_equal(ns_rr_type(rr), ns_t_srv); rrdata = ns_rr_rdata(rr); NS_GET16(prio, rrdata); NS_GET16(weight, rrdata); NS_GET16(port, rrdata); rv = ns_name_uncompress(ns_msg_base(handle), ns_msg_end(handle), rrdata, hostname, MAXDNAME); assert_int_not_equal(rv, -1); assert_int_equal(prio, 1); assert_int_equal(weight, 100); assert_int_equal(port, 88); assert_string_equal(hostname, "krb5.cwrap.org"); /* The additional section contains the A record of krb5.cwrap.org */ assert_int_equal(ns_msg_count(handle, ns_s_ar), 1); assert_int_equal(ns_parserr(&handle, ns_s_ar, 0, &rr), 0); assert_int_equal(ns_rr_type(rr), ns_t_a); assert_string_equal(ns_rr_name(rr), "krb5.cwrap.org"); assert_non_null(inet_ntop(AF_INET, ns_rr_rdata(rr), addr, sizeof(addr))); assert_string_equal(addr, "127.0.0.23"); } static void test_res_fake_uri_query(void **state) { int rv; struct __res_state dnsstate; unsigned char answer[ANSIZE]; ns_msg handle; ns_rr rr; /* expanded resource record */ const uint8_t *rrdata; int prio; int weight; (void) state; /* unused */ memset(&dnsstate, 0, sizeof(struct __res_state)); rv = res_ninit(&dnsstate); assert_int_equal(rv, 0); rv = res_nquery(&dnsstate, "_vpn.cwrap.org", ns_c_in, ns_t_uri, answer, sizeof(answer)); assert_in_range(rv, 1, ANSIZE); ns_initparse(answer, sizeof(answer), &handle); /* * The query must finish w/o an error, have three answers and they must be * a parseable RR of type URI and have the priority, weight, and URI string * as in the hosts file. */ assert_int_equal(ns_msg_getflag(handle, ns_f_rcode), ns_r_noerror); assert_int_equal(ns_msg_count(handle, ns_s_an), 3); assert_int_equal(ns_parserr(&handle, ns_s_an, 0, &rr), 0); assert_int_equal(ns_rr_type(rr), ns_t_uri); rrdata = ns_rr_rdata(rr); NS_GET16(prio, rrdata); NS_GET16(weight, rrdata); assert_int_equal(prio, 2); assert_int_equal(weight, 5); assert_string_equal(rrdata, "https://vpn.cwrap.org/VPN"); assert_int_equal(ns_parserr(&handle, ns_s_an, 1, &rr), 0); assert_int_equal(ns_rr_type(rr), ns_t_uri); rrdata = ns_rr_rdata(rr); NS_GET16(prio, rrdata); NS_GET16(weight, rrdata); assert_int_equal(prio, 2); assert_int_equal(weight, 10); assert_string_equal(rrdata, "https://vpn2.cwrap.org/VPN"); assert_int_equal(ns_parserr(&handle, ns_s_an, 2, &rr), 0); assert_int_equal(ns_rr_type(rr), ns_t_uri); rrdata = ns_rr_rdata(rr); NS_GET16(prio, rrdata); NS_GET16(weight, rrdata); assert_int_equal(prio, 2); assert_int_equal(weight, 20); assert_string_equal(rrdata, "https://vpn3.cwrap.org/VPN"); } /* * Test the case of a URI record query where the * fake hosts file entry is minimal in the sense * that it omits the priority and weight entries. * The server then fills in some default values. */ static void test_res_fake_uri_query_minimal(void **state) { int rv; struct __res_state dnsstate; unsigned char answer[ANSIZE]; ns_msg handle; ns_rr rr; /* expanded resource record */ const uint8_t *rrdata; int prio; int weight; (void) state; /* unused */ memset(&dnsstate, 0, sizeof(struct __res_state)); rv = res_ninit(&dnsstate); assert_int_equal(rv, 0); rv = res_nquery(&dnsstate, "_ftp.cwrap.org", ns_c_in, ns_t_uri, answer, sizeof(answer)); assert_in_range(rv, 1, 256); ns_initparse(answer, sizeof(answer), &handle); /* * The query must finish w/o an error, have one answer and the answer * must be a parseable RR of type URI and have the priority, weight, and * URI string as in the fake hosts file */ assert_int_equal(ns_msg_getflag(handle, ns_f_rcode), ns_r_noerror); assert_int_equal(ns_msg_count(handle, ns_s_an), 1); assert_int_equal(ns_parserr(&handle, ns_s_an, 0, &rr), 0); assert_int_equal(ns_rr_type(rr), ns_t_uri); rrdata = ns_rr_rdata(rr); NS_GET16(prio, rrdata); NS_GET16(weight, rrdata); assert_int_equal(prio, 1); assert_int_equal(weight, 100); assert_string_equal(rrdata, "ftp://ftp.cwrap.org/public"); } static void test_res_fake_soa_query(void **state) { int rv; struct __res_state dnsstate; unsigned char answer[ANSIZE]; ns_msg handle; ns_rr rr; /* expanded resource record */ const uint8_t *rrdata; char nameser[MAXDNAME]; char admin[MAXDNAME]; int serial; int refresh; int retry; int expire; int minimum; (void) state; /* unused */ memset(&dnsstate, 0, sizeof(struct __res_state)); rv = res_ninit(&dnsstate); assert_int_equal(rv, 0); rv = res_nquery(&dnsstate, "cwrap.org", ns_c_in, ns_t_soa, answer, sizeof(answer)); assert_in_range(rv, 1, 100); ns_initparse(answer, sizeof(answer), &handle); /* * The query must finish w/o an error, have one answer and the answer * must be a parseable RR of type SOA and have the data as in the fake * hosts file */ assert_int_equal(ns_msg_getflag(handle, ns_f_rcode), ns_r_noerror); assert_int_equal(ns_msg_count(handle, ns_s_an), 1); assert_int_equal(ns_parserr(&handle, ns_s_an, 0, &rr), 0); assert_int_equal(ns_rr_type(rr), ns_t_soa); rrdata = ns_rr_rdata(rr); rv = ns_name_uncompress(ns_msg_base(handle), ns_msg_end(handle), rrdata, nameser, MAXDNAME); assert_int_not_equal(rv, -1); rrdata += rv; rv = ns_name_uncompress(ns_msg_base(handle), ns_msg_end(handle), rrdata, admin, MAXDNAME); assert_int_not_equal(rv, -1); rrdata += rv; NS_GET32(serial, rrdata); NS_GET32(refresh, rrdata); NS_GET32(retry, rrdata); NS_GET32(expire, rrdata); NS_GET32(minimum, rrdata); assert_string_equal(nameser, "ns1.cwrap.org"); assert_string_equal(admin, "admin.cwrap.org"); assert_int_equal(serial, 2014100457); assert_int_equal(refresh, 3600); assert_int_equal(retry, 300); assert_int_equal(expire, 1814400); assert_int_equal(minimum, 600); } static void test_res_fake_cname_query(void **state) { int rv; struct __res_state dnsstate; unsigned char answer[ANSIZE]; ns_msg handle; ns_rr rr; /* expanded resource record */ const uint8_t *rrdata; char cname[MAXDNAME]; char addr[INET_ADDRSTRLEN]; (void) state; /* unused */ memset(&dnsstate, 0, sizeof(struct __res_state)); rv = res_ninit(&dnsstate); assert_int_equal(rv, 0); rv = res_nquery(&dnsstate, "rwrap.org", ns_c_in, ns_t_cname, answer, sizeof(answer)); assert_in_range(rv, 1, 256); ns_initparse(answer, 256, &handle); ns_initparse(answer, sizeof(answer), &handle); /* * The query must finish w/o an error, have one answer and the answer * must be a parseable RR of type CNAME and have the cname as in the * fake hosts file */ assert_int_equal(ns_msg_getflag(handle, ns_f_rcode), ns_r_noerror); assert_int_equal(ns_msg_count(handle, ns_s_an), 1); assert_int_equal(ns_parserr(&handle, ns_s_an, 0, &rr), 0); assert_int_equal(ns_rr_type(rr), ns_t_cname); rrdata = ns_rr_rdata(rr); rv = ns_name_uncompress(ns_msg_base(handle), ns_msg_end(handle), rrdata, cname, MAXDNAME); assert_int_not_equal(rv, -1); assert_string_equal(cname, "web.cwrap.org"); /* The CNAME points to an A record that's present in the additional * section */ assert_int_equal(ns_msg_count(handle, ns_s_ar), 2); assert_int_equal(ns_parserr(&handle, ns_s_ar, 0, &rr), 0); assert_int_equal(ns_rr_type(rr), ns_t_cname); assert_string_equal(ns_rr_name(rr), "web.cwrap.org"); rrdata = ns_rr_rdata(rr); rv = ns_name_uncompress(ns_msg_base(handle), ns_msg_end(handle), rrdata, cname, MAXDNAME); assert_int_not_equal(rv, -1); assert_string_equal(cname, "www.cwrap.org"); assert_int_equal(ns_parserr(&handle, ns_s_ar, 1, &rr), 0); assert_int_equal(ns_rr_type(rr), ns_t_a); assert_string_equal(ns_rr_name(rr), "www.cwrap.org"); assert_non_null(inet_ntop(AF_INET, ns_rr_rdata(rr), addr, sizeof(addr))); assert_string_equal(addr, "127.0.0.22"); } static void test_res_fake_a_via_cname(void **state) { int rv; struct __res_state dnsstate; unsigned char answer[ANSIZE]; ns_msg handle; ns_rr rr; /* expanded resource record */ const uint8_t *rrdata; char cname[MAXDNAME]; char addr[INET_ADDRSTRLEN]; (void) state; /* unused */ memset(&dnsstate, 0, sizeof(struct __res_state)); rv = res_ninit(&dnsstate); assert_int_equal(rv, 0); /* Query for A record, but the key is a CNAME. The expected result is * that the whole chain of CNAMEs will be included in the answer section * along with the resulting A */ rv = res_nquery(&dnsstate, "rwrap.org", ns_c_in, ns_t_a, answer, sizeof(answer)); assert_in_range(rv, 1, 256); ns_initparse(answer, sizeof(answer), &handle); /* * The query must finish w/o an error, have three answers and the answers * must be a parseable RR of type CNAME and have the cname as in the * fake hosts file */ assert_int_equal(ns_msg_getflag(handle, ns_f_rcode), ns_r_noerror); assert_int_equal(ns_msg_count(handle, ns_s_an), 3); assert_int_equal(ns_parserr(&handle, ns_s_an, 0, &rr), 0); assert_int_equal(ns_rr_type(rr), ns_t_cname); rrdata = ns_rr_rdata(rr); rv = ns_name_uncompress(ns_msg_base(handle), ns_msg_end(handle), rrdata, cname, MAXDNAME); assert_int_not_equal(rv, -1); assert_string_equal(cname, "web.cwrap.org"); assert_int_equal(ns_parserr(&handle, ns_s_an, 1, &rr), 0); assert_int_equal(ns_rr_type(rr), ns_t_cname); rrdata = ns_rr_rdata(rr); rv = ns_name_uncompress(ns_msg_base(handle), ns_msg_end(handle), rrdata, cname, MAXDNAME); assert_int_not_equal(rv, -1); assert_string_equal(cname, "www.cwrap.org"); assert_int_equal(ns_parserr(&handle, ns_s_an, 2, &rr), 0); assert_int_equal(ns_rr_type(rr), ns_t_a); assert_string_equal(ns_rr_name(rr), "www.cwrap.org"); assert_non_null(inet_ntop(AF_INET, ns_rr_rdata(rr), addr, sizeof(addr))); assert_string_equal(addr, "127.0.0.22"); } static void test_res_fake_ptr_query(void **state) { int rv; struct __res_state dnsstate; unsigned char answer[ANSIZE]; const uint8_t *rrdata; char ptrname[MAXDNAME]; ns_msg handle; ns_rr rr; /* expanded resource record */ (void) state; /* unused */ memset(&dnsstate, 0, sizeof(struct __res_state)); rv = res_ninit(&dnsstate); assert_int_equal(rv, 0); rv = res_nquery(&dnsstate, "22.0.0.127.in-addr.arpa", ns_c_in, ns_t_ptr, answer, sizeof(answer)); assert_in_range(rv, 1, 100); ns_initparse(answer, sizeof(answer), &handle); /* * The query must finish w/o an error, have one answer and the answer * must be a parseable RR of type PTR and have the name that our * fake hosts file contains */ assert_int_equal(ns_msg_getflag(handle, ns_f_rcode), ns_r_noerror); assert_int_equal(ns_msg_count(handle, ns_s_an), 1); assert_int_equal(ns_parserr(&handle, ns_s_an, 0, &rr), 0); assert_int_equal(ns_rr_type(rr), ns_t_ptr); rrdata = ns_rr_rdata(rr); rv = ns_name_uncompress(ns_msg_base(handle), ns_msg_end(handle), rrdata, ptrname, MAXDNAME); assert_int_not_equal(rv, -1); assert_string_equal(ptrname, "www.cwrap.org"); } int main(void) { int rc; const struct CMUnitTest fake_tests[] = { cmocka_unit_test(test_res_fake_a_query), cmocka_unit_test(test_res_fake_a_query_case_insensitive), cmocka_unit_test(test_res_fake_a_query_trailing_dot), cmocka_unit_test(test_res_fake_a_query_notfound), cmocka_unit_test(test_res_fake_aaaa_query), cmocka_unit_test(test_res_fake_aaaa_query_notfound), cmocka_unit_test(test_res_fake_srv_query), cmocka_unit_test(test_res_fake_srv_query_minimal), cmocka_unit_test(test_res_fake_uri_query), cmocka_unit_test(test_res_fake_uri_query_minimal), cmocka_unit_test(test_res_fake_soa_query), cmocka_unit_test(test_res_fake_cname_query), cmocka_unit_test(test_res_fake_a_via_cname), cmocka_unit_test(test_res_fake_ptr_query), }; rc = cmocka_run_group_tests(fake_tests, NULL, NULL); return rc; } resolv_wrapper-1.1.5/CPackConfig.cmake000644 001750 000144 00000003747 12422405514 017673 0ustar00asnusers000000 000000 # For help take a look at: # http://www.cmake.org/Wiki/CMake:CPackConfiguration ### general settings set(CPACK_PACKAGE_NAME ${APPLICATION_NAME}) set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "The resolv wrapper") set(CPACK_PACKAGE_DESCRIPTION_FILE "${CMAKE_SOURCE_DIR}/README") set(CPACK_PACKAGE_VENDOR "The Samba Team") set(CPACK_PACKAGE_INSTALL_DIRECTORY ${CPACK_PACKAGE_NAME}) set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_SOURCE_DIR}/COPYING") ### versions set(CPACK_PACKAGE_VERSION_MAJOR "${APPLICATION_VERSION_MAJOR}") set(CPACK_PACKAGE_VERSION_MINOR "${APPLICATION_VERSION_MINOR}") set(CPACK_PACKAGE_VERSION_PATCH "${APPLICATION_VERSION_PATCH}") set(CPACK_PACKAGE_VERSION "${CPACK_PACKAGE_VERSION_MAJOR}.${CPACK_PACKAGE_VERSION_MINOR}.${CPACK_PACKAGE_VERSION_PATCH}") ### source generator set(CPACK_SOURCE_GENERATOR "TGZ") set(CPACK_SOURCE_IGNORE_FILES "~$;[.]swp$;/[.]svn/;/[.]git/;.gitignore;/build/;/obj/;tags;cscope.*") set(CPACK_SOURCE_PACKAGE_FILE_NAME "${CPACK_PACKAGE_NAME}-${CPACK_PACKAGE_VERSION}") if (WIN32) set(CPACK_GENERATOR "ZIP") ### nsis generator find_package(NSIS) if (NSIS_MAKE) set(CPACK_GENERATOR "${CPACK_GENERATOR};NSIS") set(CPACK_NSIS_DISPLAY_NAME "The resolv wrapper") set(CPACK_NSIS_COMPRESSOR "/SOLID zlib") set(CPACK_NSIS_MENU_LINKS "http://www.samba.org/" "Samba homepage") endif (NSIS_MAKE) endif (WIN32) set(CPACK_PACKAGE_INSTALL_DIRECTORY "libssh") set(CPACK_PACKAGE_FILE_NAME ${APPLICATION_NAME}-${CPACK_PACKAGE_VERSION}) set(CPACK_COMPONENT_LIBRARIES_DISPLAY_NAME "Libraries") set(CPACK_COMPONENT_HEADERS_DISPLAY_NAME "C/C++ Headers") set(CPACK_COMPONENT_LIBRARIES_DESCRIPTION "Libraries used to build programs which use libssh") set(CPACK_COMPONENT_HEADERS_DESCRIPTION "C/C++ header files for use with libssh") set(CPACK_COMPONENT_HEADERS_DEPENDS libraries) #set(CPACK_COMPONENT_APPLICATIONS_GROUP "Runtime") set(CPACK_COMPONENT_LIBRARIES_GROUP "Development") set(CPACK_COMPONENT_HEADERS_GROUP "Development") include(CPack) resolv_wrapper-1.1.5/AUTHORS000644 001750 000144 00000000037 12427110221 015610 0ustar00asnusers000000 000000 Andreas Schneider Jakub Hrozek resolv_wrapper-1.1.5/README.install000644 001750 000144 00000004171 12427110221 017070 0ustar00asnusers000000 000000 Obtaining the sources ===================== Source tarballs for resolv_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/resolv_wrapper.git To create a local copy, run $ git clone git://git.samba.org/resolv_wrapper.git $ cd resolv_wrapper Building from sources ===================== resolv_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. Note that for unit testing, resolv_wrapper requires socket_wrapper to be installed. If socket_wrapper is installed in a non-standard location, this can be passed to cmake via -Dsocket_wrapper_DIR=//cmake/socket_wrapper After running "make", $ make test runs the test suite. Installing ========== resolv_wrapper is installed into the prefix directory after running "cmake" and "make" with $ make install resolv_wrapper-1.1.5/CTestConfig.cmake000644 001750 000144 00000000426 12563107154 017730 0ustar00asnusers000000 000000 set(UPDATE_TYPE "true") set(CTEST_PROJECT_NAME "resolvwrapper") set(CTEST_NIGHTLY_START_TIME "01:00:00 UTC") set(CTEST_DROP_METHOD "https") set(CTEST_DROP_SITE "mock.cryptomilk.org") set(CTEST_DROP_LOCATION "/submit.php?project=resolvwrapper") set(CTEST_DROP_SITE_CDASH TRUE) resolv_wrapper-1.1.5/look000644 001750 000144 00000006575 12606742102 015454 0ustar00asnusers000000 000000 From cb5f73d269f22ecad026caaff7a27e38abc4d15b Mon Sep 17 00:00:00 2001 From: Jakub Wilk Date: Mon, 12 Oct 2015 14:59:01 +0200 Subject: [PATCH] Fix typos Signed-off-by: Jakub Wilk --- ChangeLog | 2 +- doc/resolv_wrapper.1 | 2 +- doc/resolv_wrapper.1.txt | 2 +- src/resolv_wrapper.c | 4 ++-- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/ChangeLog b/ChangeLog index 08cbfa6..0c4e25b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -14,7 +14,7 @@ version 1.1.1 (released 2015-01-12) * Fix a possible segfault. version 1.1.0 (released 2014-12-02) - * Added case insensitive comparsion of dns names (dns faking). + * Added case insensitive comparison of dns names (dns faking). * Added support complete dns names (trailing dot) (dns faking). * Added support for recursive name resolving (dns faking). * Fixed calculation of response size (dns faking). diff --git a/doc/resolv_wrapper.1 b/doc/resolv_wrapper.1 index 2691964..5219713 100644 --- a/doc/resolv_wrapper.1 +++ b/doc/resolv_wrapper.1 @@ -34,7 +34,7 @@ resolv_wrapper \- A wrapper for dns name resolving or dns faking\&. LD_PRELOAD=libresolv_wrapper\&.so RESOLV_WRAPPER_CONF="/path/to/resolv\&.conf" \fB\&./myapplication\fR .SH "DESCRIPTION" .sp -resolv_wrapper makes it possible on most UNIX platforms to contact your own DNS implmentation in your test environment\&. It requires socket_wrapper to be able to contact it\&. If it doesn\(cqt work on a special platform the wrapper is able to fake DNS queries and return valid responses to your application\&. +resolv_wrapper makes it possible on most UNIX platforms to contact your own DNS implementation in your test environment\&. It requires socket_wrapper to be able to contact it\&. If it doesn\(cqt work on a special platform the wrapper is able to fake DNS queries and return valid responses to your application\&. .sp .RS 4 .ie n \{\ diff --git a/doc/resolv_wrapper.1.txt b/doc/resolv_wrapper.1.txt index e2e6837..12f96d0 100644 --- a/doc/resolv_wrapper.1.txt +++ b/doc/resolv_wrapper.1.txt @@ -16,7 +16,7 @@ DESCRIPTION ----------- resolv_wrapper makes it possible on most UNIX platforms to contact your own DNS -implmentation in your test environment. It requires socket_wrapper to be able +implementation in your test environment. It requires socket_wrapper to be able to contact it. If it doesn't work on a special platform the wrapper is able to fake DNS queries and return valid responses to your application. diff --git a/src/resolv_wrapper.c b/src/resolv_wrapper.c index d6a17cf..77baa45 100644 --- a/src/resolv_wrapper.c +++ b/src/resolv_wrapper.c @@ -340,7 +340,7 @@ static ssize_t rwrap_fake_header(uint8_t **header_blob, size_t remaining, h->id = res_randomid(); /* random query ID */ h->qr = 1; /* response flag */ h->rd = 1; /* recursion desired */ - h->ra = 1; /* resursion available */ + h->ra = 1; /* recursion available */ h->qdcount = htons(1); /* no. of questions */ h->ancount = htons(ancount); /* no. of answers */ @@ -911,7 +911,7 @@ static ssize_t rwrap_fake_answer(struct rwrap_fake_rr *rrs, /* Reads in a file in the following format: * TYPE RDATA * - * Malformed entried are silently skipped. + * Malformed entries are silently skipped. * Allocates answer buffer of size anslen that has to be freed after use. */ static int rwrap_res_fake_hosts(const char *hostfile, -- 2.6.1 resolv_wrapper-1.1.5/ConfigureChecks.cmake000644 001750 000144 00000012501 12755560555 020632 0ustar00asnusers000000 000000 include(CheckIncludeFile) include(CheckSymbolExists) include(CheckFunctionExists) include(CheckLibraryExists) include(CheckTypeSize) include(CheckStructHasMember) include(CheckPrototypeDefinition) include(TestBigEndian) set(PACKAGE ${APPLICATION_NAME}) set(VERSION ${APPLICATION_VERSION}) set(DATADIR ${DATA_INSTALL_DIR}) set(LIBDIR ${LIB_INSTALL_DIR}) set(PLUGINDIR "${PLUGIN_INSTALL_DIR}-${LIBRARY_SOVERSION}") set(SYSCONFDIR ${SYSCONF_INSTALL_DIR}) set(BINARYDIR ${CMAKE_BINARY_DIR}) set(SOURCEDIR ${CMAKE_SOURCE_DIR}) function(COMPILER_DUMPVERSION _OUTPUT_VERSION) # Remove whitespaces from the argument. # This is needed for CC="ccache gcc" cmake .. string(REPLACE " " "" _C_COMPILER_ARG "${CMAKE_C_COMPILER_ARG1}") execute_process( COMMAND ${CMAKE_C_COMPILER} ${_C_COMPILER_ARG} -dumpversion OUTPUT_VARIABLE _COMPILER_VERSION ) string(REGEX REPLACE "([0-9])\\.([0-9])(\\.[0-9])?" "\\1\\2" _COMPILER_VERSION "${_COMPILER_VERSION}") set(${_OUTPUT_VERSION} ${_COMPILER_VERSION} PARENT_SCOPE) endfunction() if(CMAKE_COMPILER_IS_GNUCC AND NOT MINGW AND NOT OS2) compiler_dumpversion(GNUCC_VERSION) if (NOT GNUCC_VERSION EQUAL 34) set(CMAKE_REQUIRED_FLAGS "-fvisibility=hidden") check_c_source_compiles( "void __attribute__((visibility(\"default\"))) test() {} int main(void){ return 0; } " WITH_VISIBILITY_HIDDEN) set(CMAKE_REQUIRED_FLAGS "") endif (NOT GNUCC_VERSION EQUAL 34) endif(CMAKE_COMPILER_IS_GNUCC AND NOT MINGW AND NOT OS2) # HEADERS check_include_file(sys/types.h HAVE_SYS_TYPES_H) check_include_file(resolv.h HAVE_RESOLV_H) check_include_file(arpa/nameser.h HAVE_ARPA_NAMESER_H) # FUNCTIONS set(CMAKE_REQUIRED_LIBRARIES) find_library(RESOLV_LIRBRARY resolv) if (RESOLV_LIRBRARY) check_library_exists(${RESOLV_LIRBRARY} res_send "" RES_SEND_IN_LIBRESOLV) check_library_exists(${RESOLV_LIRBRARY} __res_send "" __RES_SEND_IN_LIBRESOLV) if (RES_SEND_IN_LIBRESOLV OR __RES_SEND_IN_LIBRESOLV) set(HAVE_LIBRESOLV TRUE) set(CMAKE_REQUIRED_LIBRARIES ${RESOLV_LIRBRARY}) endif() endif() check_function_exists(res_init HAVE_RES_INIT) check_function_exists(__res_init HAVE___RES_INIT) check_function_exists(res_ninit HAVE_RES_NINIT) check_function_exists(__res_ninit HAVE___RES_NINIT) if (RESOLV_LIRBRARY) check_library_exists(${RESOLV_LIRBRARY} res_ninit "" HAVE_RES_NINIT_IN_LIBRESOLV) endif() check_function_exists(res_close HAVE_RES_CLOSE) check_function_exists(__res_close HAVE___RES_CLOSE) check_function_exists(res_nclose HAVE_RES_NCLOSE) check_function_exists(__res_nclose HAVE___RES_NCLOSE) if (RESOLV_LIRBRARY) check_library_exists(${RESOLV_LIRBRARY} res_nclose "" HAVE_RES_NCLOSE_IN_LIBRESOLV) endif() check_function_exists(res_query HAVE_RES_QUERY) check_function_exists(__res_query HAVE___RES_QUERY) check_function_exists(res_nquery HAVE_RES_NQUERY) check_function_exists(__res_nquery HAVE___RES_NQUERY) check_function_exists(res_search HAVE_RES_SEARCH) check_function_exists(__res_search HAVE___RES_SEARCH) check_function_exists(res_nsearch HAVE_RES_NSEARCH) check_function_exists(__res_nsearch HAVE___RES_NSEARCH) check_symbol_exists(ns_name_compress "sys/types.h;arpa/nameser.h" HAVE_NS_NAME_COMPRESS) if (UNIX) if (NOT LINUX) # libsocket (Solaris) check_library_exists(socket getaddrinfo "" HAVE_LIBSOCKET) if (HAVE_LIBSOCKET) set(CMAKE_REQUIRED_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES} socket) endif (HAVE_LIBSOCKET) # libnsl/inet_pton (Solaris) check_library_exists(nsl inet_pton "" HAVE_LIBNSL) if (HAVE_LIBNSL) set(CMAKE_REQUIRED_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES} nsl) endif (HAVE_LIBNSL) endif (NOT LINUX) check_function_exists(getaddrinfo HAVE_GETADDRINFO) endif (UNIX) check_library_exists(dl dlopen "" HAVE_LIBDL) if (HAVE_LIBDL) find_library(DLFCN_LIBRARY dl) set(CMAKE_REQUIRED_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES} ${DLFCN_LIBRARY}) endif (HAVE_LIBDL) # 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_struct_has_member("struct __res_state" _u._ext.nsaddrs resolv.h HAVE_RESOLV_IPV6_NSADDRS) check_c_source_compiles(" void log_fn(const char *format, ...) __attribute__ ((format (printf, 1, 2))); int main(void) { return 0; }" HAVE_ATTRIBUTE_PRINTF_FORMAT) 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) # ENDIAN test_big_endian(WORDS_BIGENDIAN) set(RWRAP_REQUIRED_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES} CACHE INTERNAL "resolv_wrapper required system libraries") resolv_wrapper-1.1.5/config.h.cmake000644 001750 000144 00000003473 12755560555 017273 0ustar00asnusers000000 000000 /* Name of package */ #cmakedefine PACKAGE "${APPLICATION_NAME}" /* Version number of package */ #cmakedefine VERSION "${APPLICATION_VERSION}" #cmakedefine LOCALEDIR "${LOCALE_INSTALL_DIR}" #cmakedefine DATADIR "${DATADIR}" #cmakedefine LIBDIR "${LIBDIR}" #cmakedefine PLUGINDIR "${PLUGINDIR}" #cmakedefine SYSCONFDIR "${SYSCONFDIR}" #cmakedefine BINARYDIR "${BINARYDIR}" #cmakedefine SOURCEDIR "${SOURCEDIR}" /************************** HEADER FILES *************************/ #cmakedefine HAVE_SYS_TYPES_H 1 #cmakedefine HAVE_RESOLV_H 1 #cmakedefine HAVE_ARPA_NAMESER_H 1 /*************************** FUNCTIONS ***************************/ #cmakedefine HAVE_RES_INIT 1 #cmakedefine HAVE___RES_INIT 1 #cmakedefine HAVE_RES_NINIT 1 #cmakedefine HAVE_RES_NINIT_IN_LIBRESOLV 1 #cmakedefine HAVE___RES_NINIT 1 #cmakedefine HAVE_RES_CLOSE 1 #cmakedefine HAVE___RES_CLOSE 1 #cmakedefine HAVE_RES_NCLOSE 1 #cmakedefine HAVE_RES_NCLOSE_IN_LIBRESOLV 1 #cmakedefine HAVE___RES_NCLOSE 1 #cmakedefine HAVE_RES_QUERY 1 #cmakedefine HAVE___RES_QUERY 1 #cmakedefine HAVE_RES_SEARCH 1 #cmakedefine HAVE___RES_SEARCH 1 #cmakedefine HAVE_RES_NQUERY 1 #cmakedefine HAVE___RES_NQUERY 1 #cmakedefine HAVE_RES_NSEARCH 1 #cmakedefine HAVE___RES_NSEARCH 1 #cmakedefine HAVE_NS_NAME_COMPRESS 1 /*************************** LIBRARIES ***************************/ #cmakedefine HAVE_LIBRESOLV 1 /**************************** OPTIONS ****************************/ #cmakedefine HAVE_IPV6 1 #cmakedefine HAVE_RESOLV_IPV6_NSADDRS 1 #cmakedefine HAVE_ATTRIBUTE_PRINTF_FORMAT 1 #cmakedefine HAVE_DESTRUCTOR_ATTRIBUTE 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 resolv_wrapper-1.1.5/CMakeLists.txt000644 001750 000144 00000005122 12764206071 017315 0ustar00asnusers000000 000000 project(resolv_wrapper C) # Required cmake version cmake_minimum_required(VERSION 2.8.0) # global needed variables set(APPLICATION_NAME ${PROJECT_NAME}) set(APPLICATION_VERSION_MAJOR "1") set(APPLICATION_VERSION_MINOR "1") set(APPLICATION_VERSION_PATCH "5") set(APPLICATION_VERSION "${APPLICATION_VERSION_MAJOR}.${APPLICATION_VERSION_MINOR}.${APPLICATION_VERSION_PATCH}") # SOVERSION scheme: CURRENT.AGE.REVISION # If there was an incompatible interface change: # Increment CURRENT. Set AGE and REVISION to 0 # If there was a compatible interface change: # Increment AGE. Set REVISION to 0 # If the source code was changed, but there were no interface changes: # Increment REVISION. set(LIBRARY_VERSION "0.0.5") set(LIBRARY_SOVERSION "0") # where to look first for cmake modules, before ${CMAKE_ROOT}/Modules/ is checked set(CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake/Modules ) # add definitions include(DefineCMakeDefaults) include(DefinePlatformDefaults) include(DefineInstallationPaths) include(DefineOptions.cmake) include(CPackConfig.cmake) # disallow in-source build include(MacroEnsureOutOfSourceBuild) macro_ensure_out_of_source_build("${PROJECT_NAME} requires an out of source build. Please create a separate build directory and run 'cmake /path/to/${PROJECT_NAME} [options]' there.") # Find out if we have threading available set(CMAKE_THREAD_PREFER_PTHREADS ON) find_package(Threads) # config.h checks include(ConfigureChecks.cmake) configure_file(config.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config.h) # Add compiler flags for the project now. include(DefineCompilerFlags) # check subdirectories add_subdirectory(src) # pkg-config file get_filename_component(RESOLV_WRAPPER_LIB ${RESOLV_WRAPPER_LOCATION} NAME) configure_file(resolv_wrapper.pc.cmake ${CMAKE_CURRENT_BINARY_DIR}/resolv_wrapper.pc @ONLY) install( FILES ${CMAKE_CURRENT_BINARY_DIR}/resolv_wrapper.pc DESTINATION ${LIB_INSTALL_DIR}/pkgconfig COMPONENT pkgconfig ) # cmake config files configure_file(resolv_wrapper-config-version.cmake.in ${CMAKE_CURRENT_BINARY_DIR}/resolv_wrapper-config-version.cmake @ONLY) configure_file(resolv_wrapper-config.cmake.in ${CMAKE_CURRENT_BINARY_DIR}/resolv_wrapper-config.cmake @ONLY) install( FILES ${CMAKE_CURRENT_BINARY_DIR}/resolv_wrapper-config-version.cmake ${CMAKE_CURRENT_BINARY_DIR}/resolv_wrapper-config.cmake DESTINATION ${CMAKE_INSTALL_DIR}/resolv_wrapper COMPONENT devel ) add_subdirectory(doc) if (UNIT_TESTING) find_package(cmocka REQUIRED) include(AddCMockaTest) add_subdirectory(tests) endif (UNIT_TESTING) resolv_wrapper-1.1.5/ChangeLog000644 001750 000144 00000001751 12764206071 016333 0ustar00asnusers000000 000000 ChangeLog ========== version 1.1.5 (released 2016-09-08) * Added support for faking PTR entries * Added support for faking URI entries version 1.1.4 (released 2016-05-31) * Added support for faking NS entries * Fixed some platform compatibility bugs version 1.1.3 (released 2015-01-13) * Fixed symbol detection if macros are used for res_* functions * Fixed strict aliasing warnings for symbol binding * Added missing tests for req_query and res_search version 1.1.2 (released 2015-01-13) * Fix detection for ns_name_compress. version 1.1.1 (released 2015-01-12) * Fixed building on older Linux distributions. * Fix a possible segfault. version 1.1.0 (released 2014-12-02) * Added case insensitive comparison of dns names (dns faking). * Added support complete dns names (trailing dot) (dns faking). * Added support for recursive name resolving (dns faking). * Fixed calculation of response size (dns faking). version 1.0.0 (released 2014-10-24) * Initial release