#! /usr/bin/env bash # source: test.sh # Copyright Gerhard Rieger and contributors (see file CHANGES) # Published under the GNU General Public License V.2, see file COPYING # perform lots of tests on socat # this script uses functions; you need a shell that supports them # you can pass general options to socat: export OPTS="-d -d -d -d -lu" # you can eg strace socat with: export TRACE="strace -v -tt -ff -D -x -s 1024 -o /tmp/$USER/socat.strace" #set -vx #TODO: Add options for interface, broadcast-interface [ -z "$USER" ] && USER="$LOGNAME" # HP-UX if [ -z "$TMPDIR" ]; then if [ -z "$TMP" ]; then TMP=/tmp fi TMPDIR="$TMP" fi #E=-e # Linux if [ $(echo "x\c") = "x" ]; then E="" elif [ $(echo -e "x\c") = "x" ]; then E="-e" else echo "cannot suppress trailing newline on echo" >&2 exit 1 fi ECHO="echo $E" PRINTF="printf" usage() { $ECHO "Usage: $0 [ ...]" $ECHO "options:" $ECHO "\t-h \t\tShow this help" $ECHO "\t-t \tBase for timeouts in seconds, default: 0.1" $ECHO "\t-v \t\tBe more verbose, show failed commands" $ECHO "\t-n \tOnly perform test with given number" $ECHO "\t-N \tOnly perform tests starting with given number" $ECHO "\t-C \t\tClear/remove left over certificates from previous runs" $ECHO "\t-x \t\tShow commands executed, even when test succeeded" #$ECHO "\t-d \t\tShow log output of commands, even when they did not fail" $ECHO "\t-internet \tAllow tests that send packets to Internet" $ECHO "\t-expect-fail N1,N2,... \tIgnore failure of these tests" $ECHO "\ttest-spec \Number of test or name of test" $ECHO "Contents of environment variable OPTS are passed to Socat invocations, e.'g:" $ECHO "OPTS=\"-d -d -d -d -lu\" ./test.sh" $ECHO "TRACE=\"strace -tt -v\" Use trace,valgrind etc.on socat" $ECHO "SOCAT=/path/to/socat \tselect socat executable for test" $ECHO "FILAN=... PROCAN=..." $ECHO "Find the tests' stdout,stderr,diff in $TMPDIR/$USER/\$PID" } val_t=0.1 NUMCOND=true #NUMCOND="test \$N -gt 70" VERBOSE= DEBUG= INTERNET= OPT_EXPECT_FAIL= EXPECT_FAIL= while [ "$1" ]; do case "X$1" in X-h) usage; exit 0 ;; X-d) DEBUG="1" ;; X-t?*) val_t="${1#-t}" ;; X-t) shift; val_t="$1" ;; X-v) VERBOSE=1 ;; # show commands X-n?*) NUMCOND="test \$N -eq ${1#-n}" ;; X-n) shift; NUMCOND="test \$N -eq $1" ;; X-N?*) NUMCOND="test \$N -gt ${1#-N}" ;; X-N) shift; NUMCOND="test \$N -ge $1" ;; X-C) rm -f testcert*.conf testcert.dh testcli*.* testsrv*.* ;; X-internet|X--internet) INTERNET=1 ;; # allow access to 3rd party Internet hosts X-expect-fail|X--expect-fail) OPT_EXPECT_FAIL=1; shift; EXPECT_FAIL="$1" ;; X-*) echo "Unknown option \"$1\"" >&2 usage >&2 exit 1 ;; *) break; esac shift done debug=$DEBUG opt_t="-t $val_t" UNAME=`uname` UNAME_R=`uname -r` #MICROS=100000 case "X$val_t" in X*.???????*) S="${val_t%.*}"; uS="${val_t#*.}"; uS="${uS:0:6}" ;; X*.*) S="${val_t%.*}"; uS="${val_t#*.}"; uS="${uS}000000"; uS="${uS:0:6}" ;; X*) S="${val_t}"; uS="000000" ;; esac MICROS=${S}${uS} MICROS=${MICROS##0000}; MICROS=${MICROS##00}; MICROS=${MICROS##0} #echo MICROS=$MICROS >&2 # _MICROS=$((MICROS+999999)); SECONDs="${_MICROS%??????}" [ -z "$SECONDs" ] && SECONDs=0 withroot=0 # perform privileged tests even if not run by root [ -z "$SOCAT" ] && SOCAT="./socat" if ! [ -x "$SOCAT" ] && ! type $SOCAT >/dev/null 2>&1; then echo "$SOCAT does not exist" >&2; exit 1; fi if [ "$SOCAT" = socat ]; then SOCAT=$(type -p socat) || SOCAT=$(which socat) fi #echo $SOCAT if [ -z "$PROCAN" ]; then if test -x ./procan; then PROCAN="./procan"; elif type procan >/dev/null 2>&1; then PROCAN=procan; elif test -x ${SOCAT%/*}/procan; then PROCAN=${SOCAT%/*}/procan; else PROCAN=false; fi; fi if [ -z "$FILAN" ]; then if test -x ./filan; then FILAN="./filan"; elif ! type filan >/dev/null 2>&1; then FILAN=filan; elif test -x ${SOCAT%/*}/filan; then FILAN=${SOCAT%/*}/filan; else FILAN=false; fi; fi #PATH=$PATH:/opt/freeware/bin #PATH=$PATH:/usr/local/ssl/bin PATH=$PATH:/sbin # RHEL6:ip case "$0" in */*) PATH="${0%/*}:$PATH" esac #OPENSSL_RAND="-rand /dev/egd-pool" #SOCAT_EGD="egd=/dev/egd-pool" MISCDELAY=1 opts="$opt_t $OPTS" export SOCAT_OPTS="$opts" TESTS="$*"; export TESTS if ! SOCAT_MAIN_WAIT= $SOCAT -V >/dev/null 2>&1; then echo "Failed to execute $SOCAT, exiting" >&2 exit 1 fi SOCAT_VERSION=$(SOCAT_MAIN_WAIT= $SOCAT -V |head -n 2 |tail -n 1 |sed 's/.* \([0-9][1-9]*\.[0-9][0-9]*\.[0-9][^[:space:]]*\).*/\1/') if [ -z "$SOCAT_VERSION" ]; then echo "Warning: failed to retrieve Socat version" >&2 fi if type ip >/dev/null 2>&1; then if ip -V |grep -q -i -e "^ip utility, iproute2-" -e BusyBox; then IP=$(type -p ip) else unset IP fi fi if type ss >/dev/null 2>&1; then if ss -V |grep -q "^ss utility, iproute2-"; then SS=$(type -p ss) else unset SS fi fi # for some tests we need a network interface if type ip >/dev/null 2>&1; then INTERFACE=$(ip r get 8.8.8.8 |grep ' dev ' |head -n 1 |sed "s/.*dev[[:space:]][[:space:]]*\([^[:space:]][^[:space:]]*\).*/\1/") else case "$UNAME" in Linux) if [ "$IP" ]; then INTERFACE="$($IP route get 8.8.8.8 |grep ' dev ' |sed -e 's/.* dev //' -e 's/ .*//')" else INTERFACE="$(netstat -rn |grep -e "^default" -e "^0\.0\.0\.0" |awk '{print($8);}')" fi ;; FreeBSD) INTERFACE="$(netstat -rn |grep -e "^default" -e "^0\.0\.0\.0" |awk '{print($4);}')" ;; *) INTERFACE="$(netstat -rn |grep -e "^default" -e "^0\.0\.0\.0" |awk '{print($4);}')" ;; esac fi MCINTERFACE=$INTERFACE [ -z "$MCINTERFACE" ] && MCINTERFACE=lo # !!! Linux only - and not always #LOCALHOST=192.168.58.1 LOCALHOST=localhost # attention: on FreeBSD-10 localhost resolves primarily to IPv6 LOCALHOST4=127.0.0.1 LOCALHOST6="[::1]" #PROTO=$(awk '{print($2);}' /etc/protocols |sort -n |tail -n 1) #PROTO=$(($PROTO+1)) PROTO=$((144+RANDOM/2048)) _PORT=12001 SOURCEPORT=2002 REUSEADDR=reuseaddr # use this with LISTEN addresses and bind options # get some system constants for use in tests SOCK_DGRAM="$($PROCAN -c |grep "^#define[[:space:]]*SOCK_DGRAM[[:space:]]" |cut -d' ' -f3)" FOPEN_MAX=$($PROCAN -c 2>/dev/null |grep '^#define[ ][ ]*FOPEN_MAX' |awk '{print($3);}') PF_INET6="$($PROCAN -c |grep "^#define[[:space:]]*PF_INET6[[:space:]]" |cut -d' ' -f3)" TIOCEXCL="$($PROCAN -c |grep "^#define[[:space:]]*TIOCEXCL[[:space:]]" |cut -d' ' -f3)" SOL_SOCKET="$($PROCAN -c |grep "^#define[[:space:]]*SOL_SOCKET[[:space:]]" |cut -d' ' -f3)" SO_REUSEADDR="$($PROCAN -c |grep "^#define[[:space:]]*SO_REUSEADDR[[:space:]]" |cut -d' ' -f3)" TCP_MAXSEG="$($PROCAN -c |grep "^#define[[:space:]]*TCP_MAXSEG[[:space:]]" |cut -d' ' -f3)" SIZE_T=$($PROCAN |grep size_t |awk '{print($3);}') #AI_ADDRCONFIG=; if [ "$($SOCAT -hhh |grep ai-addrconfig)" ]; then AI_ADDRCONFIG="ai-addrconfig=0"; fi # SSL certificate contents TESTCERT_CONF=testcert.conf TESTCERT6_CONF=testcert6.conf TESTALT_CONF=testalt.conf # TESTCERT_COMMONNAME="$LOCALHOST" TESTCERT_COMMONNAME6="$LOCALHOST6" TESTCERT_COUNTRYNAME="XY" TESTCERT_LOCALITYNAME="Lunar Base" TESTCERT_ORGANIZATIONALUNITNAME="socat" TESTCERT_ORGANIZATIONNAME="dest-unreach" TESTCERT_SUBJECT="C = $TESTCERT_COUNTRYNAME, CN = $TESTCERT_COMMONNAME, O = $TESTCERT_ORGANIZATIONNAME, OU = $TESTCERT_ORGANIZATIONALUNITNAME, L = $TESTCERT_LOCALITYNAME" TESTCERT_ISSUER="C = $TESTCERT_COUNTRYNAME, CN = $TESTCERT_COMMONNAME, O = $TESTCERT_ORGANIZATIONNAME, OU = $TESTCERT_ORGANIZATIONALUNITNAME, L = $TESTCERT_LOCALITYNAME" RSABITS=2048 # Ubuntu-20.04 with OpenSSL-1.1.1f does not work with 1024 nor 1536 DSABITS=2048 cat >$TESTCERT_CONF <$TESTCERT6_CONF <$TESTALT_CONF </dev/null } # time in microseconds to wait in some situations if ! type usleep >/dev/null 2>&1 || usleep 0 2>&1 |grep -q deprecated; then usleep () { local n="$1" case "$n" in *???????) S="${n%??????}"; uS="${n:${#n}-6}" ;; *) S=0; uS="00000$n"; uS="${uS:${#uS}-6}" ;; esac $SOCAT -T "$S.$uS" pipe pipe 2>/dev/null } fi #USLEEP=usleep # A sleep with configurable clocking ($vat_t) # val_t should be at least the time that a Socat invocation, no action, and # termination takes relsleep () { usleep $(($1*MICROS)) } if type ping6 >/dev/null 2>&1; then PING6=ping6 else PING6="ping -6" fi F_n="%3d" # format string for test numbers export LC_ALL=C # for timestamps format... export LANG=C export LANGUAGE=C # knoppix case "$UNAME" in HP-UX|OSF1) echo "$SOCAT -u stdin stdout" >cat.sh chmod a+x cat.sh CAT=./cat.sh ;; SunOS) # /usr/bin/tr doesn't handle the a-z range syntax (needs [a-z]), use # /usr/xpg4/bin/tr instead alias tr=/usr/xpg4/bin/tr ;; *) CAT="cat" ;; esac # some OSes need special options case "$UNAME" in #HP-UX) # # on HP-UX, the default options (below) hang some tests (former 14, 15) # PTYOPTS= # PTYOPTS2= # ;; SunOS) PTYOPTS="perm=600" PTYOPTS2="echo=0,opost=0" ;; *) PTYOPTS="echo=0,opost=0" #PTYOPTS2="raw,echo=0" PTYOPTS2="cfmakeraw" #PTYOPTS2="rawer" ;; esac # for some tests we need an unprivileged user id to su to if [ "$SUDO_USER" ]; then SUBSTUSER="$SUDO_USER" else SUBSTUSER="$(grep -v '^[^:]*:^[^:]*:0:' /etc/passwd |tail -n 1 |cut -d: -f1)" fi if [ -z "$SS" ]; then # non-root users might miss ifconfig in their path case "$UNAME" in AIX) IFCONFIG=/usr/sbin/ifconfig ;; FreeBSD) IFCONFIG=/sbin/ifconfig ;; HP-UX) IFCONFIG=/usr/sbin/ifconfig ;; Linux) IFCONFIG=/sbin/ifconfig ;; NetBSD)IFCONFIG=/sbin/ifconfig ;; OpenBSD)IFCONFIG=/sbin/ifconfig ;; OSF1) IFCONFIG=/sbin/ifconfig ;; SunOS) IFCONFIG=/sbin/ifconfig ;; Darwin)IFCONFIG=/sbin/ifconfig ;; DragonFly) IFCONFIG=/sbin/ifconfig ;; *) IFCONFIG=/sbin/ifconfig ;; esac fi # need output like "644" case "$UNAME" in Linux) fileperms() { stat -L --print "%a\n" "$1" 2>/dev/null; } ;; FreeBSD) fileperms() { stat -L -x "$1" |grep ' Mode:' |sed 's/.* Mode:[[:space:]]*([0-9]\([0-7][0-7][0-7]\).*/\1/'; } ;; *) fileperms() { local p s=0 c p="$(ls -l -L "$1" |awk '{print($1);}')" p="${p:1:9}" while [ "$p" ]; do c=${p:0:1}; p=${p:1}; [ "x$c" == x- ]; let "s=2*s+$?"; done printf "%03o\n" $s; } ;; esac # need user (owner) of filesystem entry case "$UNAME" in Linux) fileuser() { stat -L --print "%U\n" "$1" 2>/dev/null; } ;; FreeBSD) fileuser() { ls -l "$1" |awk '{print($3);}'; } ;; *) fileuser() { ls -l "$1" |awk '{print($3);}'; } ;; esac if2addr4() { local IF="$1" if [ "$IP" ]; then $IP address show dev "$IF" |grep "inet " |sed -e "s/.*inet //" -e "s/ .*//" else $IFCONFIG "$BROADCASTIF" |grep 'inet ' |awk '{print($2);}' |cut -d: -f2 fi } if2bc4() { local IF="$1" if [ "$IP" ]; then $IP address show dev "$IF" |grep ' inet .* brd ' |awk '{print($4);}' else $IFCONFIG "$IF" |grep 'broadcast ' |sed 's/.*broadcast/broadcast/' |awk '{print($2);}' fi } # for some tests we need a second local IPv4 address case "$UNAME" in Linux) if [ "$IP" ]; then BROADCASTIF=$($IP r get 8.8.8.8 |grep ' dev ' |sed 's/.*\&2 exit 1 fi ECHO="echo $E" PRINTF="printf" case "$TERM" in vt100|vt320|linux|xterm|cons25|dtterm|aixterm|sun-color|xterm-color|xterm-256color|screen) # there are different behaviours of printf (and echo) # on some systems, echo behaves different than printf... if [ "$($PRINTF "\0101")" = "A" ]; then RED="\0033[31m" GREEN="\0033[32m" YELLOW="\0033[33m" # if [ "$UNAME" = SunOS ]; then # NORMAL="\0033[30m" # else NORMAL="\0033[39m" # fi else RED="\033[31m" GREEN="\033[32m" YELLOW="\033[33m" # if [ "$UNAME" = SunOS ]; then # NORMAL="\033[30m" # else NORMAL="\033[39m" # fi fi OK="${GREEN}OK${NORMAL}" FAILED="${RED}FAILED${NORMAL}" NO_RESULT="${YELLOW}NO RESULT${NORMAL}" CANT="$NO_RESULT" ;; *) OK="OK" FAILED="FAILED" NO_RESULT="NO RESULT" CANT="$NO_RESULT" ;; esac if [ -x /usr/xpg4/bin/id ]; then # SunOS has rather useless tools in its default path PATH="/usr/xpg4/bin:$PATH" fi OPENSSL_S_CLIENT_4= OPENSSL_S_CLIENT_DTLS= init_openssl_s_client () { if openssl s_client -help 2>&1 |grep -q ' -4 '; then OPENSSL_S_CLIENT_4="-4" else OPENSSL_S_CLIENT_4=" " fi if openssl s_client -help 2>&1 | grep -q ' -dtls '; then OPENSSL_S_CLIENT_DTLS=-dtls else OPENSSL_S_CLIENT_DTLS=-dtls1 fi } OPENSSL_S_SERVER_4= OPENSSL_S_SERVER_DTLS= OPENSSL_S_SERVER_NO_IGN_EOF= init_openssl_s_server () { if openssl s_server -help 2>&1 |grep -q ' -4 '; then OPENSSL_S_SERVER_4="-4" else OPENSSL_S_SERVER_4=" " fi if openssl s_server -help 2>&1 | grep -q ' -dtls '; then OPENSSL_S_SERVER_DTLS="-dtls" else OPENSSL_S_SERVER_DTLS="-dtls1" fi if openssl s_server -help 2>&1 | grep -q ' -no-ign_eof '; then OPENSSL_S_SERVER_NO_IGN_EOF="-no-ign_eof" else OPENSSL_S_SERVER_NO_IGN_EOF=" " fi } [ -z "$TESTS" ] && TESTS="consistency functions filan" # use '%' as separation char TESTS="%$(echo " $TESTS " |tr ' ' '%')%" [ -z "$USER" ] && USER="$LOGNAME" # HP-UX if [ -z "$TMPDIR" ]; then if [ -z "$TMP" ]; then TMP=/tmp fi TMPDIR="$TMP" fi TD="$TMPDIR/$USER/$$"; td="$TD" rm -rf "$TD" || (echo "cannot rm $TD" >&2; exit 1) mkdir -p "$TD" #trap "rm -r $TD" 0 3 echo "Using temp directory $TD" case "$TESTS" in *%consistency%*) # test if addresses are sorted alphabetically: $ECHO "testing if address array is sorted...\c" TF="$TD/socat-q" IFS="$($ECHO ' \n\t')" $SOCAT -hhh |sed -n '/^ address-head:/,/^ opts:/ p' |grep -v -e "^ address-head:" -e "^ opts:" |sed -e 's/^[[:space:]]*//' -e 's/[: ].*//' |grep -v '^<' >"$TF" $SOCAT -hhh |sed -n '/^ address-head:/,/^ opts:/ p' |grep -v -e "^ address-head:" -e "^ opts:" |sed -e 's/^[[:space:]]*//' -e 's/[: ].*//' |grep -v '^<' |LC_ALL=C sort |diff "$TF" - >"$TF-diff" if [ -s "$TF-diff" ]; then $ECHO "\n*** address array is not sorted. Wrong entries:" >&2 cat "$TD/socat-q-diff" >&2 exit 1 else echo " ok" fi #/bin/rm "$TF" #/bin/rm "$TF-diff" esac case "$TESTS" in *%consistency%*) # test if address options array ("optionnames") is sorted alphabetically: $ECHO "testing if address options are sorted...\c" TF="$TD/socat-qq" $SOCAT -hhh |sed '1,/opt:/ d' |awk '{print($1);}' >"$TF" LC_ALL=C sort "$TF" |diff "$TF" - >"$TF-diff" if [ -s "$TF-diff" ]; then $ECHO "\n*** option array is not sorted. Wrong entries:" >&2 cat "$TD/socat-qq-diff" >&2 exit 1 else echo " ok" fi /bin/rm "$TF" /bin/rm "$TF-diff" esac #============================================================================== N=1 numOK=0 numFAIL=0 numCANT=0 listFAIL= listCANT= namesFAIL= #============================================================================== # test if selected socat features work ("FUNCTIONS") testecho () { local N="$1" local title="$2" local arg1="$3"; [ -z "$arg1" ] && arg1="-" local arg2="$4"; [ -z "$arg2" ] && arg2="echo" local opts="$5" local T="$6"; [ -z "$T" ] && T=0 local tf="$td/test$N.stdout" local te="$td/test$N.stderr" local tdiff="$td/test$N.diff" local da="test$N $(date) $RANDOM" if ! eval $NUMCOND; then :; else #local cmd="$TRACE $SOCAT $opts $arg1 $arg2" #$ECHO "testing $title (test $N)... \c" $PRINTF "test $F_n %s... " $N "$title" #echo "$da" |$cmd >"$tf" 2>"$te" (psleep $T; echo "$da"; psleep $T) |($TRACE $SOCAT $opts "$arg1" "$arg2" >"$tf" 2>"$te"; echo $? >"$td/test$N.rc") & export rc1=$! #sleep 5 && kill $rc1 2>/dev/null & # rc2=$! wait $rc1 # kill $rc2 2>/dev/null if [ "$(cat "$td/test$N.rc")" != 0 ]; then $PRINTF "$FAILED: $TRACE $SOCAT:\n" echo "$TRACE $SOCAT $opts $arg1 $arg2" >&2 cat "$te" >&2 numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" elif echo "$da" |diff - "$tf" >"$tdiff" 2>&1; then $PRINTF "$OK\n" if [ "$VERBOSE" ]; then echo "$SOCAT $opts $arg1 $arg2" >&2; fi if [ -n "$debug" ]; then cat $te >&2; fi numOK=$((numOK+1)) else $PRINTF "$FAILED:\n" echo "$TRACE $SOCAT $opts $arg1 $arg2" >&2 cat "$te" >&2 echo diff: >&2 cat "$tdiff" >&2 numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" fi fi # NUMCOND } # test if call to od and throughput of data works - with graceful shutdown and # flush of od buffers testod () { local num="$1" local title="$2" local arg1="$3"; [ -z "$arg1" ] && arg1="-" local arg2="$4"; [ -z "$arg2" ] && arg2="echo" local opts="$5" local T="$6"; [ -z "$T" ] && T=0 local tf="$td/test$N.stdout" local te="$td/test$N.stderr" local tr="$td/test$N.ref" local tdiff="$td/test$N.diff" local dain="$(date) $RANDOM" if ! eval $NUMCOND; then :; else echo "$dain" |$OD_C >"$tr" # local daout="$(echo "$dain" |$OD_C)" $PRINTF "test $F_n %s... " $num "$title" (psleep $T; echo "$dain"; psleep $T) |$TRACE $SOCAT $opts "$arg1" "$arg2" >"$tf" 2>"$te" if [ "$?" != 0 ]; then $PRINTF "$FAILED: $TRACE $SOCAT:\n" echo "$TRACE $SOCAT $opts $arg1 $arg2" cat "$te" numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $num" # elif echo "$daout" |diff - "$tf" >"$tdiff" 2>&1; then elif diff "$tr" "$tf" >"$tdiff" 2>&1; then $PRINTF "$OK\n" if [ -n "$debug" ]; then cat $te; fi numOK=$((numOK+1)) else $PRINTF "$FAILED: diff:\n" echo "$TRACE $SOCAT $opts $arg1 $arg2" cat "$te" cat "$tdiff" numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $num" fi fi # NUMCOND } # test if the socat executable has these features compiled in # print the first missing address type testfeats () { local a A; for a in $@; do A=$(echo "$a" |tr 'a-z-' 'A-Z_') if SOCAT_MAIN_WAIT= $SOCAT -V |grep "#define WITH_$A 1\$" >/dev/null; then if [[ "$A" =~ OPENSSL.* ]]; then gentestcert testsrv gentestcert testcli fi shift continue fi echo "$a" return 1 done return 0 } # test if the socat executable has these address types compiled in # print the first missing address type testaddrs () { local a A; for a in $@; do A=$(echo "$a" |tr 'a-z' 'A-Z') # the ::::: forces syntax errer and prevents the address from doing anything if ! $SOCAT $A::::: /dev/null 2>&1 /dev/null; then shift continue fi echo "$a" return 1 done return 0 } # check if the given pid exists and has child processes # if yes: prints child process lines to stdout, returns 0 # if not: prints ev.message to stderr, returns 1 childprocess () { local l case "$UNAME" in AIX) l="$(ps -fade |grep "^........ ...... $(printf %6u $1)")" ;; FreeBSD) l="$(ps -faje |grep "^........ ..... $(printf %5u $1)")" ;; HP-UX) l="$(ps -fade |grep "^........ ..... $(printf %5u $1)")" ;; Linux) l="$(ps -fade |grep "^........ ..... $(printf %5u $1)")" ;; # NetBSD) l="$(ps -aj |grep "^........ ..... $(printf %4u $1)")" ;; NetBSD) l="$(ps -aj |grep "^[^ ][^ ]*[ ][ ]*..... $(printf %5u $1)")" ;; OpenBSD) l="$(ps -aj |grep "^........ ..... $(printf %5u $1)")" ;; SunOS) l="$(ps -fade |grep "^........ ..... $(printf %5u $1)")" ;; DragonFly)l="$(ps -faje |grep "^[^ ][^ ]*[ ][ ]*..... $(printf %5u $1)")" ;; CYGWIN*) l="$(ps -pafe |grep "^[^ ]*[ ][ ]*[^ ][^ ]*[ ][ ]*$1[ ]")" ;; *) l="$(ps -fade |grep "^[^ ][^ ]*[ ][ ]*[0-9][0-9]**[ ][ ]*$(printf %5u $1) ")" ;; esac if [ -z "$l" ]; then return 1; fi echo "$l" return 0 } # return a list of child process pids [killchild] childpids () { case "$UNAME" in AIX) l="$(ps -fade |grep "^........ ...... $(printf %6u $1)" |awk '{print($2);}')" ;; FreeBSD) l="$(ps -fl |grep "^[^ ][^ ]*[ ][ ]*[0-9][0-9]*[ ][ ]*$1[ ]" |awk '{print($2);}')" ;; HP-UX) l="$(ps -fade |grep "^........ ..... $(printf %5u $1)" |awk '{print($2);}')" ;; # Linux) l="$(ps -fade |grep "^........ ..... $(printf %5u $1)" |awk '{print($2);}')" ;; Linux) l="$(ps -fade |grep "^[^[:space:]][^[:space:]]*[[:space:]][[:space:]]*[^[:space:]][^[:space:]]*[[:space:]][[:space:]]*$1 " |awk '{print($2);}')" ;; # NetBSD) l="$(ps -aj |grep "^........ ..... $(printf %4u $1)" |awk '{print($2);}')" ;; NetBSD) l="$(ps -aj |grep "^[^ ][^ ]*[ ][ ]*..... $(printf %5u $1)" |awk '{print($2);}')" ;; OpenBSD) l="$(ps -aj |grep "^........ ..... $(printf %5u $1)" |awk '{print($2);}')" ;; SunOS) l="$(ps -fade |grep "^........ ..... $(printf %5u $1)" |awk '{print($2);}')" ;; DragonFly)l="$(ps -faje |grep "^[^ ][^ ]*[ ][ ]*..... $(printf %5u $1)" |awk '{print($2);}')" ;; CYGWIN*) l="$(ps -pafe |grep "^[^ ]*[ ][ ]*[^ ][^ ]*[ ][ ]*$1[ ]" |awk '{print($2);}')" ;; *) l="$(ps -fade |grep "^[^ ][^ ]*[ ][ ]*[0-9][0-9]*[ ][ ]*$(printf %5u $1) " |awk '{print($2);}')" ;; esac if [ -z "$l" ]; then return 1; fi echo "$l" return 0 } # check if the given process line refers to a defunct (zombie) process # yes: returns 0 # no: returns 1 isdefunct () { local l case "$UNAME" in AIX) l="$(echo "$1" |grep ' $')" ;; FreeBSD) l="$(echo "$1" |grep ' $')" ;; HP-UX) l="$(echo "$1" |grep ' $')" ;; Linux) l="$(echo "$1" |grep ' $')" ;; SunOS) l="$(echo "$1" |grep ' $')" ;; DragonFly)l="$(echo "$1" |grep ' $')" ;; *) l="$(echo "$1" |grep ' $')" ;; esac [ -n "$l" ]; } # check if UNIX socket protocol is available on host runsunix () { return 0; $TRACE $SOCAT /dev/null UNIX-LISTEN:"$td/unix.socket" 2>"$td/unix.stderr" & pid=$! usleep $MICROS kill "$pid" 2>/dev/null test ! -s "$td/unix.stderr" } unset HAVENOT_IP4 # check if an IP4 loopback interface exists runsip4 () { [ -n "$HAVENOT_IP4" ] && return $HAVENOT_IP4 local l case "$UNAME" in AIX) l=$($IFCONFIG lo0 |fgrep 'inet 127.0.0.1 ') ;; FreeBSD) l=$($IFCONFIG lo0 |fgrep 'inet 127.0.0.1 ') ;; HP-UX) l=$($IFCONFIG lo0 |fgrep 'inet 127.0.0.1 ') ;; Linux) if [ "$IP" ]; then l=$($IP address |egrep ' inet 127.0.0.1/') else l=$($IFCONFIG |egrep 'inet (addr:)?127\.0\.0\.1 ') fi ;; NetBSD)l=$($IFCONFIG -a |fgrep 'inet 127.0.0.1 ');; OpenBSD)l=$($IFCONFIG -a |fgrep 'inet 127.0.0.1 ');; OSF1) l=$($IFCONFIG -a |grep ' inet ') ;; SunOS) l=$($IFCONFIG -a |grep 'inet ') ;; Darwin)l=$($IFCONFIG lo0 |fgrep 'inet 127.0.0.1 ') ;; DragonFly)l=$($IFCONFIG -a |fgrep 'inet 127.0.0.1 ');; CYGWIN*) l=$(ipconfig |grep IPv4);; *) l=$($IFCONFIG -a |grep ' ::1[^:0-9A-Fa-f]') ;; esac [ -z "$l" ] && return 1 # existence of interface might not suffice, check for routeability: case "$UNAME" in Darwin) ping -c 1 127.0.0.1 >/dev/null 2>&1; l="$?" ;; Linux) ping -c 1 127.0.0.1 >/dev/null 2>&1; l="$?" ;; *) if [ -n "$l" ]; then l=0; else l=1; fi ;; esac HAVENOT_IP4=$l if [ "$HAVENOT_IP4" -ne 0 ]; then echo IP4 fi return $l; } unset HAVENOT_IP6 # check if an IP6 loopback interface exists runsip6 () { [ -n "$HAVENOT_IP6" ] && return $HAVENOT_IP6 local l case "$UNAME" in AIX) l=$($IFCONFIG lo0 |grep 'inet6 ::1[/%]') ;; HP-UX) l=$($IFCONFIG lo0 |grep ' inet6 ') ;; Linux) if [ "$IP" ]; then l=$($IP address |egrep 'inet6 ::1/128') else l=$($IFCONFIG |egrep 'inet6 (addr: )?::1/?') fi ;; NetBSD)l=$($IFCONFIG -a |grep 'inet6 ::1 ');; OSF1) l=$($IFCONFIG -a |grep ' inet6 ') ;; SunOS) l=$($IFCONFIG -a |grep 'inet6 ') ;; Darwin)l=$($IFCONFIG lo0 |grep 'inet6 ::1 ') ;; CYGWIN*) l=$(ipconfig |grep IPv6);; *) l=$($IFCONFIG -a |grep ' ::1[^:0-9A-Fa-f]') ;; esac [ -z "$l" ] && return 1 # existence of interface might not suffice, check for routeability: case "$UNAME" in Darwin) $PING6 -c 1 ::1 >/dev/null 2>&1; l="$?" ;; Linux) $PING6 -c 1 ::1 >/dev/null 2>&1; l="$?" ;; *) if [ -n "$l" ]; then l=0; else l=1; fi ;; esac HAVENOT_IP6=$l if [ "$HAVENOT_IP6" -ne 0 ]; then echo IP6 fi return "$HAVENOT_IP6" } # check if TCP on IPv4 is available on host runstcp4 () { runsip4 >/dev/null || { echo TCP4; return 1; } $SOCAT -h |grep -i ' TCP4-' >/dev/null || return 1 return 0; } # check if TCP on IPv6 is available on host runstcp6 () { runsip6 >/dev/null || { echo TCP6; return 1; } $SOCAT -h |grep -i ' TCP6-' >/dev/null || return 1 return 0; } # check if UDP on IPv4 is available on host runsudp4 () { runsip4 >/dev/null || { echo UDP4; return 1; } $SOCAT -h |grep -i ' UDP4-' >/dev/null || return 1 return 0; } # check if UDP on IPv6 is available on host runsudp6 () { runsip6 >/dev/null || { echo UDP6; return 1; } $SOCAT -h |grep -i ' UDP6-' >/dev/null || return 1 return 0; } # check if SCTP on IPv4 is available on host runssctp4 () { runsip4 >/dev/null || { echo SCTP4; return 1; } $SOCAT -h |grep -i ' SCTP4-' >/dev/null || return 1 $SOCAT /dev/null SCTP4-L:0,accept-timeout=0.001 2>/dev/null || return 1; return 0; } # check if SCTP on IPv6 is available on host runssctp6 () { runsip6 >/dev/null || { echo SCTP6; return 1; } $SOCAT -h |grep -i ' SCTP6-' >/dev/null || return 1 $SOCAT /dev/null SCTP6-L:0,accept-timeout=0.001 2>/dev/null || return 1; return 0; } routesip6 () { runsip6 >/dev/null || { echo route6; return 1; } ping -c 1 -s 0 -6 2606:4700:4700::1111 >/dev/null 2>&1 || { echo route6; return 1; } return 0; } routesip6 () { runsip6 >/dev/null || { echo route6; return 1; } ping -c 1 -s 0 -6 2606:4700:4700::1111 >/dev/null 2>&1 || { echo route6; return 1; } return 0; } # Perform a couple of checks to make sure the test has a chance of a useful # result: # platform is supported, features compiled in, addresses and options # available; needs root; is allowed to access the internet checkconds() { local unames="$(echo "$1")" # must be one of... exa: "Linux,FreeBSD" local root="$2" # "root" or "" local progs="$(echo "$3" |tr 'A-Z,' 'a-z ')" # exa: "nslookup" local feats="$(echo "$4" |tr 'a-z,' 'A-Z ')" # list of req.features (socat -V) local addrs="$(echo "$5" |tr 'a-z,' 'A-Z ')" # list of req.addresses (socat -h) local opts="$(echo "$6" |tr 'A-Z,' 'a-z ')" # list of req.options (socat -hhh) local runs="$(echo "$7" |tr , ' ')" # list of req.protocols, exa: "sctp6" local inet="$8" # when "internet": needs allowance local i if [ "$unames" ]; then local uname="$(echo $UNAME |tr 'A-Z' 'a-z')" for i in $unames; do if [ "$uname" = "$(echo "$i" |tr 'A-Z,' 'a-z ')" ]; then # good, mark as passed i= break; fi done [ "$i" ] && { echo "Only on (one of) $unames"; return -1; } fi if [ "$root" = "root" ]; then if [ $(id -u) -ne 0 -a "$withroot" -eq 0 ]; then echo "Must be root" return -1; fi fi if [ "$progs" ]; then for i in $progs; do if ! type >/dev/null 2>&1; then echo "Program $i not available" return -1 fi done fi if [ "$feats" ]; then if ! F=$(testfeats $feats); then echo "Feature $F not configured in $SOCAT" return -1 fi fi if [ "$addrs" ]; then if ! A=$(testaddrs - $addrs); then echo "Address $A not available in $SOCAT" return -1 fi fi if [ "$opts" ]; then if ! o=$(testoptions $opts); then echo "Option $o not available in $SOCAT" return -1 fi fi if [ "$runs" ]; then for i in $runs; do if ! runs$i >/dev/null; then echo "$i not available on host" return -1; fi done fi if [ "$inet" ]; then if [ -z "$NTERNET" ]; then echo "Use test.sh option -internet" return -1 fi fi return 0 } # wait until an IP4 protocol is ready waitip4proto () { local proto="$1" local logic="$2" # 0..wait until free; 1..wait until listening local timeout="$3" local l [ "$logic" ] || logic=1 [ "$timeout" ] || timeout=5 while [ $timeout -gt 0 ]; do case "$UNAME" in Linux) if [ "$SS" ]; then l=$($SS -n -w -l |grep '^\(raw\|UNCONN\) .* .*[0-9*]:'$proto' [ ]*0\.0\.0\.0:\*') else l=$(netstat -n -w -l |grep '^raw .* .*[0-9*]:'$proto' [ ]*0\.0\.0\.0:\*') fi ;; # FreeBSD) l=$(netstat -an |egrep '^raw46? .*[0-9*]\.'$proto' .* \*\.\*') ;; # NetBSD) l=$(netstat -an |grep '^raw .*[0-9*]\.'$proto' [ ]* \*\.\*') ;; # OpenBSD) l=$(netstat -an |grep '^raw .*[0-9*]\.'$proto' [ ]* \*\.\*') ;; # Darwin) case "$(uname -r)" in # [1-5]*) l=$(netstat -an |grep '^raw.* .*[0-9*]\.'$proto' .* \*\.\*') ;; # *) l=$(netstat -an |grep '^raw4.* .*[0-9*]\.'$proto' .* \*\.\* .*') ;; # esac ;; AIX) # does not seem to show raw sockets in netstat sleep 1; return 0 ;; # SunOS) l=$(netstat -an -f inet -P raw |grep '.*[1-9*]\.'$proto' [ ]*Idle') ;; # HP-UX) l=$(netstat -an |grep '^raw 0 0 .*[0-9*]\.'$proto' .* \*\.\* ') ;; # OSF1) l=$(/usr/sbin/netstat -an |grep '^raw 0 0 .*[0-9*]\.'$proto' [ ]*\*\.\*') ;; *) #l=$(netstat -an |grep -i 'raw .*[0-9*][:.]'$proto' ') ;; sleep 1; return 0 ;; esac [ \( \( $logic -ne 0 \) -a -n "$l" \) -o \ \( \( $logic -eq 0 \) -a -z "$l" \) ] && return 0 psleep $val_t timeout=$((timeout-1)) done $ECHO "!protocol $proto timed out! \c" >&2 return 1 } # we need this misleading function name for canonical reasons waitip4port () { waitip4proto "$1" "$2" "$3" } # wait until an IP6 protocol is ready waitip6proto () { local proto="$1" local logic="$2" # 0..wait until free; 1..wait until listening local timeout="$3" local l [ "$logic" ] || logic=1 [ "$timeout" ] || timeout=5 while [ $timeout -gt 0 ]; do case "$UNAME" in Linux) if [ "$SS" ]; then l=$($SS -n -w -l |grep '^\(raw\|UNCONN\) .* \*:'$proto' [ ]*\*:\*') else l=$(netstat -n -w -l |grep '^raw[6 ] .* .*:[0-9*]*:'$proto' [ ]*:::\*') fi ;; # FreeBSD) l=$(netstat -an |egrep '^raw46? .*[0-9*]\.'$proto' .* \*\.\*') ;; # NetBSD) l=$(netstat -an |grep '^raw .*[0-9*]\.'$proto' [ ]* \*\.\*') ;; # OpenBSD) l=$(netstat -an |grep '^raw .*[0-9*]\.'$proto' [ ]* \*\.\*') ;; # Darwin) case "$(uname -r)" in # [1-5]*) l=$(netstat -an |grep '^raw.* .*[0-9*]\.'$proto' .* \*\.\*') ;; # *) l=$(netstat -an |grep '^raw4.* .*[0-9*]\.'$proto' .* \*\.\* .*') ;; # esac ;; AIX) # does not seem to show raw sockets in netstat sleep 1; return 0 ;; # SunOS) l=$(netstat -an -f inet -P raw |grep '.*[1-9*]\.'$proto' [ ]*Idle') ;; # HP-UX) l=$(netstat -an |grep '^raw 0 0 .*[0-9*]\.'$proto' .* \*\.\* ') ;; # OSF1) l=$(/usr/sbin/netstat -an |grep '^raw 0 0 .*[0-9*]\.'$proto' [ ]*\*\.\*') ;; *) #l=$(netstat -an |egrep -i 'raw6? .*[0-9*][:.]'$proto' ') ;; sleep 1; return 0 ;; esac [ \( \( $logic -ne 0 \) -a -n "$l" \) -o \ \( \( $logic -eq 0 \) -a -z "$l" \) ] && return 0 psleep $val_t timeout=$((timeout-1)) done $ECHO "!protocol $proto timed out! \c" >&2 return 1 } # we need this misleading function name for canonical reasons waitip6port () { waitip6proto "$1" "$2" "$3" } # Check if a TCP port is in use # exits with 0 when it is not used checktcpport () { local port="$1" local l case "$UNAME" in Linux) if [ "$SS" ]; then l=$($SS -a -n -t |grep ".*:$port\>") else l=$(netstat -a -n -t |grep '^tcp.* .*[0-9*]:'$port' .*') fi ;; FreeBSD) l=$(netstat -an |grep '^tcp.* .*[0-9*]\.'$port' .* .*') ;; NetBSD) l=$(netstat -an |grep '^tcp.* .*[0-9*]\.'$port' [ ]* .* [ ]*.*') ;; Darwin) case "$(uname -r)" in [1-5]*) l=$(netstat -an |grep '^tcp.* .*[0-9*]\.'$port' .* .* .*') ;; *) l=$(netstat -an |grep '^tcp.* .*[0-9*]\.'$port' .* .* .*') ;; esac ;; AIX) l=$(netstat -an |grep '^tcp.* 0 0 .*[*0-9]\.'$port' .*') ;; SunOS) l=$(netstat -an -f inet -P tcp |grep '.*[1-9*]\.'$port' .*\* 0 .*') ;; HP-UX) l=$(netstat -an |grep '^tcp 0 0 .*[0-9*]\.'$port' .*') ;; OSF1) l=$(/usr/sbin/netstat -an |grep '^tcp 0 0 .*[0-9*]\.'$port' [ ]*\*\.\* [ ]*') ;; CYGWIN*) l=$(netstat -an -p TCP |grep '^ TCP [0-9.]*:'$port' .*') ;; DragonFly)l=$(netstat -ant |grep '^tcp.* .* .*[0-9*]\.'$port' [ ]* \*\.\* [ ]*') ;; *) l=$(netstat -an |grep -i 'tcp .*[0-9*][:.]'$port' .*') ;; esac [ -z "$l" ] && return 0 return 1 } checktcp4port () { checktcpport $1 } # wait until a TCP4 listen port is ready waittcp4port () { local port="$1" local logic="$2" # 0..wait until free; 1..wait until listening (default) local timeout="$3" local l local vx=+; case $- in *vx*) set +vx; vx=-; esac # no tracing here [ "$logic" ] || logic=1 [ "$timeout" ] || timeout=5 while true; do case "$UNAME" in Linux) if [ "$SS" ]; then l=$($SS -l -n -t |grep "^LISTEN .*:$port\>") else l=$(netstat -a -n -t |grep '^tcp .* .*[0-9*]:'$port' .* LISTEN') fi ;; FreeBSD) l=$(netstat -an |grep '^tcp4.* .*[0-9*]\.'$port' .* \*\.\* .* LISTEN') ;; NetBSD) l=$(netstat -an |grep '^tcp .* .*[0-9*]\.'$port' [ ]* \*\.\* [ ]* LISTEN.*') ;; Darwin) case "$(uname -r)" in [1-5]*) l=$(netstat -an |grep '^tcp.* .*[0-9*]\.'$port' .* \*\.\* .* LISTEN') ;; *) l=$(netstat -an |grep '^tcp4.* .*[0-9*]\.'$port' .* \*\.\* .* LISTEN') ;; esac ;; AIX) l=$(netstat -an |grep '^tcp[^6] 0 0 .*[*0-9]\.'$port' .* LISTEN$') ;; SunOS) l=$(netstat -an -f inet -P tcp |grep '.*[1-9*]\.'$port' .*\* .* 0 .* LISTEN') ;; HP-UX) l=$(netstat -an |grep '^tcp 0 0 .*[0-9*]\.'$port' .* LISTEN$') ;; OSF1) l=$(/usr/sbin/netstat -an |grep '^tcp 0 0 .*[0-9*]\.'$port' [ ]*\*\.\* [ ]*LISTEN') ;; CYGWIN*) l=$(netstat -an -p TCP |grep '^ TCP [0-9.]*:'$port' .* LISTENING') ;; DragonFly) l=$(netstat -ant |grep '^tcp4 .* .*[0-9*]\.'$port' [ ]* \*\.\* [ ]* LISTEN.*') ;; *) l=$(netstat -an |grep -i 'tcp .*[0-9*][:.]'$port' .* listen') ;; esac if [ \( \( $logic -ne 0 \) -a -n "$l" \) -o \ \( \( $logic -eq 0 \) -a -z "$l" \) ]; then set ${vx}vx return 0 fi if [ $timeout -le 0 ]; then set ${vx}vx return 1 fi psleep $val_t timeout=$((timeout-1)) done $ECHO "!port $port timed out! \c" >&2 set ${vx}vx return 1 } # Check if a UDP4 port is in use # exits with 0 when it is not used checkudpport () { local port="$1" local l case "$UNAME" in Linux) if [ "$SS" ]; then l=$($SS -a -n -u |grep ".*:$port\>") else l=$(netstat -a -n -u |grep '^udp.* .*[0-9*]:'$port' .*') fi ;; FreeBSD) l=$(netstat -an |grep '^udp.* .*[0-9*]\.'$port' .* \*\.\* .*') ;; NetBSD) l=$(netstat -an |grep '^udp.* .*[0-9*]\.'$port' [ ]* \*\.\* [ ]*.*') ;; Darwin) case "$(uname -r)" in [1-5]*) l=$(netstat -an |grep '^udp.* .*[0-9*]\.'$port' .* \*\.\* .*') ;; *) l=$(netstat -an |grep '^udp.* .*[0-9*]\.'$port' .* \*\.\* .*') ;; esac ;; AIX) l=$(netstat -an |grep '^udp.* 0 0 .*[*0-9]\.'$port' .*') ;; SunOS) l=$(netstat -an -f inet -P udp |grep '.*[1-9*]\.'$port' .*\* 0 .*') ;; HP-UX) l=$(netstat -an |grep '^udp.* 0 0 .*[0-9*]\.'$port' .*') ;; OSF1) l=$(/usr/sbin/netstat -an |grep '^udp.* 0 0 .*[0-9*]\.'$port' [ ]*\*\.\* [ ]*') ;; CYGWIN*) l=$(netstat -an -p UDP |grep '^ UDP [0-9.]*:'$port' .*') ;; DragonFly)l=$(netstat -ant |grep '^udp.* .* .*[0-9*]\.'$port' [ ]* \*\.\* [ ]*') ;; *) l=$(netstat -an |grep -i 'udp .*[0-9*][:.]'$port' .*') ;; esac [ -z "$l" ] && return 0 return 1 } checkudp4port () { checkudpport $1 } # wait until a UDP4 port is ready waitudp4port () { local port="$1" local logic="$2" # 0..wait until free; 1..wait until listening local timeout="$3" local l local vx=+; case $- in *vx*) set +vx; vx=-; esac # no tracing here [ "$logic" ] || logic=1 [ "$timeout" ] || timeout=5 while [ $timeout -gt 0 ]; do case "$UNAME" in Linux) if [ "$SS" ]; then l=$($SS -4 -l -n -u |grep "^UNCONN .*:$port\>") else l=$(netstat -a -n -u -l |grep '^udp .* .*[0-9*]:'$port' [ ]*0\.0\.0\.0:\*') fi ;; FreeBSD) l=$(netstat -an |egrep '^udp46? .*[0-9*]\.'$port' .* \*\.\*') ;; NetBSD) l=$(netstat -an |grep '^udp .*[0-9*]\.'$port' [ ]* \*\.\*') ;; OpenBSD) l=$(netstat -an |grep '^udp .*[0-9*]\.'$port' [ ]* \*\.\*') ;; Darwin) case "$(uname -r)" in [1-5]*) l=$(netstat -an |grep '^udp.* .*[0-9*]\.'$port' .* \*\.\*') ;; *) l=$(netstat -an |grep '^udp4.* .*[0-9*]\.'$port' .* \*\.\* .*') ;; esac ;; AIX) l=$(netstat -an |grep '^udp[4 ] 0 0 .*[*0-9]\.'$port' .* \*\.\*[ ]*$') ;; SunOS) l=$(netstat -an -f inet -P udp |grep '.*[1-9*]\.'$port' [ ]*Idle') ;; HP-UX) l=$(netstat -an |grep '^udp 0 0 .*[0-9*]\.'$port' .* \*\.\* ') ;; OSF1) l=$(/usr/sbin/netstat -an |grep '^udp 0 0 .*[0-9*]\.'$port' [ ]*\*\.\*') ;; DragonFly) l=$(netstat -an |grep '^udp4 .* .*[0-9*]\.'$port' [ ]* \*\.\* [ ]*') ;; *) l=$(netstat -an |grep -i 'udp .*[0-9*][:.]'$port' ') ;; esac if [ \( \( $logic -ne 0 \) -a -n "$l" \) -o \ \( \( $logic -eq 0 \) -a -z "$l" \) ]; then set ${vx}vx return 0 fi psleep $val_t timeout=$((timeout-1)) done $ECHO "!port $port timed out! \c" >&2 set ${vx}vx return 1 } # Check if a SCTP port is in use # exits with 0 when it is not used checksctpport () { local port="$1" local l case "$UNAME" in Linux) if [ "$SS" ]; then l=$($SS -a -n |grep "^sctp.*:$port\>") else l=$(netstat -a -n |grep '^sctp.* .*[0-9*]:'$port' .*') fi ;; FreeBSD) l=$(netstat -an |grep '^sctp.* .*[0-9*]\.'$port' .* \*\.\* .*') ;; NetBSD) l=$(netstat -an |grep '^sctp.* .*[0-9*]\.'$port' [ ]* \*\.\* [ ]*.*') ;; Darwin) case "$(uname -r)" in [1-5]*) l=$(netstat -an |grep '^sctp.* .*[0-9*]\.'$port' .* \*\.\* .*') ;; *) l=$(netstat -an |grep '^sctp.* .*[0-9*]\.'$port' .* \*\.\* .*') ;; esac ;; AIX) l=$(netstat -an |grep '^sctp.* 0 0 .*[*0-9]\.'$port' .*') ;; SunOS) l=$(netstat -an -f inet -P sctp |grep '.*[1-9*]\.'$port' .*\* 0 .*') ;; HP-UX) l=$(netstat -an |grep '^sctp 0 0 .*[0-9*]\.'$port' .*') ;; OSF1) l=$(/usr/sbin/netstat -an |grep '^sctp.* 0 0 .*[0-9*]\.'$port' [ ]*\*\.\* [ ]*') ;; CYGWIN*) l=$(netstat -an -p SCTP |grep '^ SCTP [0-9.]*:'$port' .*') ;; DragonFly)l=$(netstat -ant |grep '^sctp.* .*[0-9*]\.'$port' [ ]* \*\.\* [ ]*') ;; *) l=$(netstat -an |grep -i 'sctp.*[0-9*][:.]'$port' .*') ;; esac [ -z "$l" ] && return 0 return 1 } checksctp4port () { checksctpport $1 } # wait until an SCTP4 listen port is ready waitsctp4port () { local port="$1" local logic="$2" # 0..wait until free; 1..wait until listening local timeout="$3" local l local vx=+; case $- in *vx*) set +vx; vx=-; esac # no tracing here [ "$logic" ] || logic=1 [ "$timeout" ] || timeout=5 while [ $timeout -gt 0 ]; do case "$UNAME" in Linux) if [ "$SS" ]; then l=$($SS -4 -n 2>/dev/null |grep "^sctp.*LISTEN .*:$port\>") else l=$(netstat -n -a |grep '^sctp .*[0-9*]:'$port' .* LISTEN') fi ;; # FreeBSD) l=$(netstat -an |grep '^tcp4.* .*[0-9*]\.'$port' .* \*\.\* .* LISTEN') ;; # NetBSD) l=$(netstat -an |grep '^tcp .* .*[0-9*]\.'$port' [ ]* \*\.\* [ ]* LISTEN.*') ;; # Darwin) case "$(uname -r)" in # [1-5]*) l=$(netstat -an |grep '^tcp.* .*[0-9*]\.'$port' .* \*\.\* .* LISTEN') ;; # *) l=$(netstat -an |grep '^tcp4.* .*[0-9*]\.'$port' .* \*\.\* .* LISTEN') ;; # esac ;; # AIX) l=$(netstat -an |grep '^tcp[^6] 0 0 .*[*0-9]\.'$port' .* LISTEN$') ;; SunOS) l=$(netstat -an -f inet -P sctp |grep '.*[1-9*]\.'$port' .*\* 0 .* LISTEN') ;; # HP-UX) l=$(netstat -an |grep '^tcp 0 0 .*[0-9*]\.'$port' .* LISTEN$') ;; # OSF1) l=$(/usr/sbin/netstat -an |grep '^tcp 0 0 .*[0-9*]\.'$port' [ ]*\*\.\* [ ]*LISTEN') ;; # CYGWIN*) l=$(netstat -an -p TCP |grep '^ TCP [0-9.]*:'$port' .* LISTENING') ;; *) l=$(netstat -an |grep -i 'sctp .*[0-9*][:.]'$port' .* listen') ;; esac if [ \( \( $logic -ne 0 \) -a -n "$l" \) -o \ \( \( $logic -eq 0 \) -a -z "$l" \) ]; then set ${vx}vx return 0 fi psleep $val_t timeout=$((timeout-1)) done $ECHO "!port $port timed out! \c" >&2 set ${vx}vx return 1 } # check if a TCP6 port is in use # exits with 0 when it is not used checktcp6port () { checktcpport $1 } # wait until a tcp6 listen port is ready waittcp6port () { local port="$1" local logic="$2" # 0..wait until free; 1..wait until listening local timeout="$3" local l local vx=+; case $- in *vx*) set +vx; vx=-; esac # no tracing here [ "$logic" ] || logic=1 [ "$timeout" ] || timeout=5 while [ $timeout -gt 0 ]; do case "$UNAME" in Linux) if [ "$SS" ]; then l=$($SS -6 -n -t -l |grep "^LISTEN .*:$port\>") #l=$($SS -6 -n -t -l |grep "^tcp6* .*:$port\>") else l=$(netstat -an |grep -E '^tcp6? .* [0-9a-f:%]*:'$port' .* LISTEN') fi ;; FreeBSD) l=$(netstat -an |egrep -i 'tcp(6|46) .*[0-9*][:.]'$port' .* listen') ;; NetBSD) l=$(netstat -an |grep '^tcp6 .*[0-9*]\.'$port' [ ]* \*\.\*') ;; OpenBSD) l=$(netstat -an |grep -i 'tcp6 .*[0-9*][:.]'$port' .* listen') ;; Darwin) l=$(netstat -an |egrep '^tcp4?6 +[0-9]+ +[0-9]+ +[0-9a-z:%*]+\.'$port' +[0-9a-z:%*.]+ +LISTEN') ;; AIX) l=$(netstat -an |grep '^tcp[6 ] 0 0 .*[*0-9]\.'$port' .* LISTEN$') ;; SunOS) l=$(netstat -an -f inet6 -P tcp |grep '.*[1-9*]\.'$port' .*\* [ ]* 0 .* LISTEN') ;; #OSF1) l=$(/usr/sbin/netstat -an |grep '^tcp6 0 0 .*[0-9*]\.'$port' [ ]*\*\.\* [ ]*LISTEN') /*?*/;; DragonFly) l=$(netstat -ant |grep '^tcp6 .* .*[0-9*]\.'$port' [ ]* \*\.\* [ ]* LISTEN.*') ;; *) l=$(netstat -an |grep -i 'tcp6 .*:'$port' .* listen') ;; esac if [ \( \( $logic -ne 0 \) -a -n "$l" \) -o \ \( \( $logic -eq 0 \) -a -z "$l" \) ]; then set ${vx}vx return 0 fi psleep $val_t timeout=$((timeout-1)) done $ECHO "!port $port timed out! \c" >&2 #echo set ${vx}vx >&2 set ${vx}vx return 1 } # Check if a UDP6 port is in use # exits with 0 when it is not used checkudp6port () { checkudpport $1 } # wait until a UDP6 port is ready waitudp6port () { local port="$1" local logic="$2" # 0..wait until free; 1..wait until listening local timeout="$3" local l local vx=+; case $- in *vx*) set +vx; vx=-; esac # no tracing here [ "$logic" ] || logic=1 [ "$timeout" ] || timeout=5 while [ $timeout -gt 0 ]; do case "$UNAME" in Linux) if [ "$SS" ]; then # CAUTION!!! ss from iproute2 4.15.0-2ubuntu on 18-04 changes # the output format when writing to pipe l=$($SS -6 -u -l -n |grep "^UNCONN.*:$port\>") else l=$(netstat -an |grep -E '^udp6? .* .*[0-9*:%]:'$port' [ ]*:::\*') fi ;; FreeBSD) l=$(netstat -an |egrep '^udp(6|46) .*[0-9*]\.'$port' .* \*\.\*') ;; NetBSD) l=$(netstat -an |grep '^udp6 .* \*\.'$port' [ ]* \*\.\*') ;; OpenBSD) l=$(netstat -an |grep '^udp6 .*[0-9*]\.'$port' [ ]* \*\.\*') ;; Darwin) l=$(netstat -an |egrep '^udp4?6 +[0-9]+ +[0-9]+ +[0-9a-z:%*]+\.'$port' +[0-9a-z:%*.]+') ;; AIX) l=$(netstat -an |grep '^udp[6 ] 0 0 .*[*0-9]\.'$port' .* \*\.\*[ ]*$') ;; SunOS) l=$(netstat -an -f inet6 -P udp |grep '.*[1-9*]\.'$port' [ ]*Idle') ;; #HP-UX) l=$(netstat -an |grep '^udp 0 0 .*[0-9*]\.'$port' ') ;; #OSF1) l=$(/usr/sbin/netstat -an |grep '^udp6 0 0 .*[0-9*]\.'$port' [ ]*\*\.\*') ;; DragonFly) l=$(netstat -ant |grep '^udp6 .* .*[0-9*]\.'$port' [ ]* \*\.\* [ ]*') ;; *) l=$(netstat -an |grep -i 'udp .*[0-9*][:.]'$port' ') ;; esac if [ \( \( $logic -ne 0 \) -a -n "$l" \) -o \ \( \( $logic -eq 0 \) -a -z "$l" \) ]; then set ${vx}vx return 0 fi psleep $val_t timeout=$((timeout-1)) done $ECHO "!port $port timed out! \c" >&2 set ${vx}vx return 1 } # Check if a SCTP6 port is in use # exits with 0 when it is not used checksctp6port () { checksctpport $1 } # wait until a sctp6 listen port is ready # not all (Linux) variants show this in netstat waitsctp6port () { local port="$1" local logic="$2" # 0..wait until free; 1..wait until listening local timeout="$3" local l local vx=+; case $- in *vx*) set +vx; vx=-; esac # no tracing here [ "$logic" ] || logic=1 [ "$timeout" ] || timeout=5 while [ $timeout -gt 0 ]; do case "$UNAME" in Linux) if [ "$SS" ]; then l=$($SS -6 -n 2>/dev/null |grep "^LISTEN .*:$port\>") else l=$(netstat -an |grep '^sctp[6 ] .* [0-9a-f:]*:'$port' .* LISTEN') fi ;; # FreeBSD) l=$(netstat -an |grep -i 'tcp[46][6 ] .*[0-9*][:.]'$port' .* listen') ;; # NetBSD) l=$(netstat -an |grep '^tcp6 .*[0-9*]\.'$port' [ ]* \*\.\*') ;; # OpenBSD) l=$(netstat -an |grep -i 'tcp6 .*[0-9*][:.]'$port' .* listen') ;; # AIX) l=$(netstat -an |grep '^tcp[6 ] 0 0 .*[*0-9]\.'$port' .* LISTEN$') ;; SunOS) l=$(netstat -an -f inet6 -P sctp |grep '.*[1-9*]\.'$port' .*\* [ ]* 0 .* LISTEN') ;; # #OSF1) l=$(/usr/sbin/netstat -an |grep '^tcp6 0 0 .*[0-9*]\.'$port' [ ]*\*\.\* [ ]*LISTEN') /*?*/;; *) l=$(netstat -an |grep -i 'stcp6 .*:'$port' .* listen') ;; esac if [ \( \( $logic -ne 0 \) -a -n "$l" \) -o \ \( \( $logic -eq 0 \) -a -z "$l" \) ]; then set ${vx}vx return 0 fi psleep $val_t timeout=$((timeout-1)) done $ECHO "!port $port timed out! \c" >&2 set ${vx}vx return 1 } # we need this misleading function name for canonical reasons waitunixport () { waitfile "$1" "$2" "$3" } # Not implemented waitabstractport () { relsleep 5 } # wait until a filesystem entry exists waitfile () { local crit=-e case "X$1" in X-*) crit="$1"; shift ;; esac local file="$1" local logic="$2" # 0..wait until gone; 1..wait until exists (default); # 2..wait until not empty local timeout="$3" local vx=+; case $- in *vx*) set +vx; vx=-; esac # no tracing here [ "$logic" ] || logic=1 [ "$logic" -eq 2 ] && crit=-s [ "$timeout" ] || timeout=5 while [ $timeout -gt 0 ]; do if [ \( $logic -ne 0 -a $crit "$file" \) -o \ \( $logic -eq 0 -a ! $crit "$file" \) ]; then set ${vx}vx return 0 fi psleep $val_t timeout=$((timeout-1)) done echo "file $file timed out" >&2 set ${vx}vx return 1 } # system dependent values case "$UNAME" in SunOS) SOCK_SEQPACKET=6 ;; *) SOCK_SEQPACKET=5 ;; esac # generate a test certificate and key gentestcert () { local name="$1" if ! [ -f testcert.dh ]; then openssl dhparam -out testcert.dh $RSABITS fi if [ -s $name.key -a -s $name.crt -a -s $name.pem ]; then return; fi openssl genrsa $OPENSSL_RAND -out $name.key $RSABITS >/dev/null 2>&1 #openssl req -new -config $TESTCERT_CONF -key $name.key -x509 -out $name.crt -days 3653 -extensions v3_ca >/dev/null 2>&1 openssl req -new -config $TESTCERT_CONF -key $name.key -x509 -out $name.crt -days 3653 >/dev/null 2>&1 cat $name.key $name.crt testcert.dh >$name.pem } # generate a test DSA key and certificate gentestdsacert () { local name="$1" if [ -s $name.key -a -s $name.crt -a -s $name.pem ]; then return; fi openssl dsaparam -out $name-dsa.pem $DSABITS >/dev/null 2>&1 openssl dhparam -dsaparam -out $name-dh.pem $DSABITS >/dev/null 2>&1 openssl req -newkey dsa:$name-dsa.pem -keyout $name.key -nodes -x509 -config $TESTCERT_CONF -out $name.crt -days 3653 >/dev/null 2>&1 cat $name-dsa.pem $name-dh.pem $name.key $name.crt >$name.pem } # generate a test EC key and certificate gentesteccert () { local name="$1" if [ -s $name.key -a -s $name.crt -a -s $name.pem ]; then return; fi openssl ecparam -name secp521r1 -out $name-ec.pem >/dev/null 2>&1 chmod 0400 $name-ec.pem openssl req -newkey ec:$name-ec.pem -keyout $name.key -nodes -x509 -config $TESTCERT_CONF -out $name.crt -days 3653 >/dev/null 2>&1 cat $name-ec.pem $name.key $name.crt >$name.pem } gentestcert6 () { local name="$1" if [ -s $name.key -a -s $name.crt -a -s $name.pem ]; then return; fi cat $TESTCERT_CONF | { echo "# automatically generated by $0"; cat; } | sed 's/\(commonName\s*=\s*\).*/\1[::1]/' >$TESTCERT6_CONF openssl genrsa $OPENSSL_RAND -out $name.key $RSABITS >/dev/null 2>&1 openssl req -new -config $TESTCERT6_CONF -key $name.key -x509 -out $name.crt -days 3653 >/dev/null 2>&1 cat $name.key $name.crt >$name.pem } # generate a server certificate and key with SubjectAltName gentestaltcert () { local name="$1" if ! [ -f testcert.dh ]; then openssl dhparam -out testcert.dh $RSABITS fi if [ -s $name.key -a -s $name.crt -a -s $name.pem ]; then return; fi openssl genrsa $OPENSSL_RAND -out $name.key $RSABITS >/dev/null 2>&1 openssl req -new -config $TESTALT_CONF -key $name.key -x509 -out $name.crt -days 3653 >/dev/null 2>&1 cat $name.key $name.crt testcert.dh >$name.pem } #------------------------------------------------------------------------------ # Begin of functional tests NAME=UNISTDIO case "$TESTS " in *%$N%*|*%functions%*|*%stdio%*|*%$NAME%*) TEST="$NAME: unidirectional throughput from stdin to stdout" testecho "$N" "$TEST" "stdin" "stdout" "$opts -u" esac N=$((N+1)) #------------------------------------------------------------------------------ # Begin of common tests NAME=UNPIPESTDIO case "$TESTS" in *%$N%*|*%functions%*|*%stdio%*|*%$NAME%*) TEST="$NAME: stdio with simple echo via internal pipe" testecho "$N" "$TEST" "stdio" "pipe" "$opts" esac N=$((N+1)) NAME=UNPIPESHORT case "$TESTS" in *%$N%*|*%functions%*|*%stdio%*|*%$NAME%*) TEST="$NAME: short form of stdio ('-') with simple echo via internal pipe" testecho "$N" "$TEST" "-" "pipe" "$opts" esac N=$((N+1)) NAME=DUALSTDIO case "$TESTS" in *%$N%*|*%functions%*|*%stdio%*|*%$NAME%*) TEST="$NAME: splitted form of stdio ('stdin!!stdout') with simple echo via internal pipe" testecho "$N" "$TEST" "stdin!!stdout" "pipe" "$opts" esac N=$((N+1)) NAME=DUALSHORTSTDIO case "$TESTS" in *%$N%*|*%functions%*|*%stdio%*|*%$NAME%*) TEST="$NAME: short splitted form of stdio ('-!!-') with simple echo via internal pipe" testecho "$N" "$TEST" "-!!-" "pipe" "$opts" esac N=$((N+1)) NAME=DUALFDS case "$TESTS" in *%$N%*|*%functions%*|*%fd%*|*%$NAME%*) TEST="$NAME: file descriptors with simple echo via internal pipe" testecho "$N" "$TEST" "0!!1" "pipe" "$opts" esac N=$((N+1)) NAME=NAMEDPIPE case "$TESTS" in *%$N%*|*%functions%*|*%pipe%*|*%$NAME%*) TEST="$NAME: simple echo via named pipe" # with MacOS, this test hangs if nonblock is not used. Is an OS bug. tp="$td/pipe$N" # note: the nonblock is required by MacOS 10.1(?), otherwise it hangs (OS bug?) testecho "$N" "$TEST" "" "pipe:$tp,nonblock" "$opts" esac N=$((N+1)) NAME=DUALPIPE case "$TESTS" in *%$N%*|*%functions%*|*%pipe%*|*%$NAME%*) TEST="$NAME: simple echo via named pipe, specified twice" tp="$td/pipe$N" testecho "$N" "$TEST" "" "pipe:$tp,nonblock!!pipe:$tp" "$opts" esac N=$((N+1)) NAME=FILE case "$TESTS" in *%$N%*|*%functions%*|*%engine%*|*%file%*|*%ignoreeof%*|*%$NAME%*) TEST="$NAME: simple echo via file" tf="$td/file$N" testecho "$N" "$TEST" "" "$tf,ignoreeof!!$tf" "$opts" esac N=$((N+1)) NAME=EXECSOCKETPAIR case "$TESTS" in *%$N%*|*%functions%*|*%exec%*|*%socketpair%*|*%$NAME%*) TEST="$NAME: simple echo via exec of cat with socketpair" testecho "$N" "$TEST" "" "EXEC:$CAT" "$opts" esac N=$((N+1)) NAME=SYSTEMSOCKETPAIR case "$TESTS" in *%$N%*|*%functions%*|*%system%*|*%socketpair%*|*%$NAME%*) TEST="$NAME: simple echo via system() of cat with socketpair" testecho "$N" "$TEST" "" "SYSTEM:$CAT" "$opts" "$val_t" esac N=$((N+1)) NAME=EXECPIPES case "$TESTS" in *%$N%*|*%functions%*|*%exec%*|*%pipe%*|*%$NAME%*) TEST="$NAME: simple echo via exec of cat with pipes" testecho "$N" "$TEST" "" "EXEC:$CAT,pipes" "$opts" esac N=$((N+1)) NAME=SYSTEMPIPES case "$TESTS" in *%$N%*|*%functions%*|*%system%*|*%pipes%*|*%$NAME%*) TEST="$NAME: simple echo via system() of cat with pipes" testecho "$N" "$TEST" "" "SYSTEM:$CAT,pipes" "$opts" esac N=$((N+1)) NAME=EXECPTY case "$TESTS" in *%$N%*|*%functions%*|*%exec%*|*%pty%*|*%$NAME%*) TEST="$NAME: simple echo via exec of cat with pseudo terminal" if ! eval $NUMCOND; then :; elif ! testfeats pty >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}PTY not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" else testecho "$N" "$TEST" "" "EXEC:$CAT,pty,$PTYOPTS,$PTYOPTS2" "$opts" fi esac N=$((N+1)) NAME=SYSTEMPTY case "$TESTS" in *%$N%*|*%functions%*|*%system%*|*%pty%*|*%$NAME%*) TEST="$NAME: simple echo via system() of cat with pseudo terminal" if ! eval $NUMCOND; then :; elif ! testfeats pty >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}PTY not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" else testecho "$N" "$TEST" "" "SYSTEM:$CAT,pty,$PTYOPTS,$PTYOPTS2" "$opts" fi esac N=$((N+1)) NAME=SYSTEMPIPESFDS case "$TESTS" in *%$N%*|*%functions%*|*%system%*|*%pipes%*|*%$NAME%*) TEST="$NAME: simple echo via system() of cat with pipes, non stdio" testecho "$N" "$TEST" "" "SYSTEM:$CAT>&9 <&8,pipes,fdin=8,fdout=9" "$opts" esac N=$((N+1)) NAME=DUALSYSTEMFDS case "$TESTS" in *%$N%*|*%functions%*|*%system%*|*%socketpair%*|*%$NAME%*) TEST="$NAME: echo via dual system() of cat" testecho "$N" "$TEST" "SYSTEM:$CAT>&6,fdout=6!!system:$CAT<&7,fdin=7" "" "$opts" "$val_t" esac N=$((N+1)) # test: send EOF to exec'ed sub process, let it finish its operation, and # check if the sub process returns its data before terminating. NAME=EXECSOCKETPAIRFLUSH # idea: have socat exec'ing od; send data and EOF, and check if the od'ed data # arrives. case "$TESTS" in *%$N%*|*%functions%*|*%exec%*|*%socketpair%*|*%$NAME%*) TEST="$NAME: call to od via exec with socketpair" testod "$N" "$TEST" "" "EXEC:$OD_C" "$opts" esac N=$((N+1)) NAME=SYSTEMSOCKETPAIRFLUSH case "$TESTS" in *%$N%*|*%functions%*|*%system%*|*%socketpair%*|*%$NAME%*) TEST="$NAME: call to od via system() with socketpair" testod "$N" "$TEST" "" "SYSTEM:$OD_C" "$opts" $val_t esac N=$((N+1)) NAME=EXECPIPESFLUSH case "$TESTS" in *%$N%*|*%functions%*|*%exec%*|*%pipes%*|*%$NAME%*) TEST="$NAME: call to od via EXEC with pipes" testod "$N" "$TEST" "" "EXEC:$OD_C,pipes" "$opts" esac N=$((N+1)) NAME=SYSTEMPIPESFLUSH case "$TESTS" in *%$N%*|*%functions%*|*%system%*|*%pipes%*|*%$NAME%*) TEST="$NAME: call to od via system() with pipes" testod "$N" "$TEST" "" "SYSTEM:$OD_C,pipes" "$opts" "$val_t" esac N=$((N+1)) ## LATER: #NAME=EXECPTYFLUSH #case "$TESTS" in #*%$N%*|*%functions%*|*%exec%*|*%pty%*|*%$NAME%*) #TEST="$NAME: call to od via exec with pseudo terminal" #if ! testfeats pty >/dev/null; then # $PRINTF "test $F_n $TEST... ${YELLOW}PTY not available${NORMAL}\n" $N # numCANT=$((numCANT+1)) # listCANT="$listCANT $N" #else #testod "$N" "$TEST" "" "exec:$OD_C,pty,$PTYOPTS" "$opts" #fi #esac #N=$((N+1)) ## LATER: #NAME=SYSTEMPTYFLUSH #case "$TESTS" in #*%$N%*|*%functions%*|*%system%*|*%pty%*|*%$NAME%*) #TEST="$NAME: call to od via system() with pseudo terminal" #if ! testfeats pty >/dev/null; then # $PRINTF "test $F_n $TEST... ${YELLOW}PTY not available${NORMAL}\n" $N # numCANT=$((numCANT+1)) # listCANT="$listCANT $N" #else #testod "$N" "$TEST" "" "system:$OD_C,pty,$PTYOPTS" "$opts" #fi #esac #N=$((N+1)) NAME=SYSTEMPIPESFDSFLUSH case "$TESTS" in *%$N%*|*%functions%*|*%system%*|*%pipes%*|*%$NAME%*) TEST="$NAME: call to od via system() with pipes, non stdio" testod "$N" "$TEST" "" "SYSTEM:$OD_C>&9 <&8,pipes,fdin=8,fdout=9" "$opts" "$val_t" esac N=$((N+1)) NAME=DUALSYSTEMFDSFLUSH case "$TESTS" in *%$N%*|*%functions%*|*%system%*|*%pipes%*|*%$NAME%*) TEST="$NAME: call to od via dual system()" testod "$N" "$TEST" "SYSTEM:$OD_C>&6,fdout=6!!SYSTEM:$CAT<&7,fdin=7" "pipe" "$opts" "$val_t" esac N=$((N+1)) case "$UNAME" in Linux) IPPROTO=254 ;; Darwin) IPPROTO=255 ;; *) IPPROTO=254 ;; # just a guess esac NAME=RAWIP4SELF case "$TESTS" in *%$N%*|*%functions%*|*%ip4%*|*%rawip%*|*%root%*|*%$NAME%*) TEST="$NAME: simple echo via self receiving raw IPv4 protocol" if ! eval $NUMCOND; then :; elif ! feat=$(testfeats ip4) || ! runsip4 >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}IP4 not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif ! feat=$(testfeats rawip) >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}RAWIP not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif [ $(id -u) -ne 0 -a "$withroot" -eq 0 ]; then $PRINTF "test $F_n $TEST... ${YELLOW}must be root${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" else testecho "$N" "$TEST" "" "ip4:127.0.0.1:$IPPROTO" "$opts" fi esac N=$((N+1)) NAME=RAWIPX4SELF case "$TESTS" in *%$N%*|*%functions%*|*%ip4%*|*%rawip%*|*%root%*|*%$NAME%*) TEST="$NAME: simple echo via self receiving raw IP protocol, v4 by target" if ! eval $NUMCOND; then :; elif ! feat=$(testfeats ip4) || ! runsip4 >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}IP4 not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif ! feat=$(testfeats rawip) >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}RAWIP not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif [ $(id -u) -ne 0 -a "$withroot" -eq 0 ]; then $PRINTF "test $F_n $TEST... ${YELLOW}must be root${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" else testecho "$N" "$TEST" "" "ip:127.0.0.1:$IPPROTO" "$opts" fi ;; # NUMCOND, feats esac N=$((N+1)) NAME=RAWIP6SELF case "$TESTS" in *%$N%*|*%functions%*|*%ip6%*|*%rawip%*|*%root%*|*%$NAME%*) TEST="$NAME: simple echo via self receiving raw IPv6 protocol" if ! eval $NUMCOND; then :; elif ! feat=$(testfeats ip6) || ! runsip6 >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}IP6 not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif ! feat=$(testfeats rawip) || ! runsip6 >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}RAWIP not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif [ $(id -u) -ne 0 -a "$withroot" -eq 0 ]; then $PRINTF "test $F_n $TEST... ${YELLOW}must be root${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" else testecho "$N" "$TEST" "" "ip6:[::1]:$IPPROTO" "$opts" fi ;; # NUMCOND, feats esac N=$((N+1)) NAME=RAWIPX6SELF case "$TESTS" in *%$N%*|*%functions%*|*%ip%*|*%ip6%*|*%rawip%*|*%rawip6%*|*%root%*|*%$NAME%*) TEST="$NAME: simple echo via self receiving raw IP protocol, v6 by target" if ! eval $NUMCOND; then :; elif ! feat=$(testfeats ip6) || ! runsip6 >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}IP6 not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif ! feat=$(testfeats rawip) || ! runsip6 >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}RAWIP not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif [ $(id -u) -ne 0 -a "$withroot" -eq 0 ]; then $PRINTF "test $F_n $TEST... ${YELLOW}must be root${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" else testecho "$N" "$TEST" "" "ip:[::1]:$IPPROTO" "$opts" fi esac N=$((N+1)) newport() { _PORT=$((_PORT+1)) while eval wait${1}port $_PORT 1 0 2>/dev/null; do _PORT=$((_PORT+1)); done #echo "PORT=$_PORT" >&2 PORT=$_PORT } NAME=TCPSELF case "$TESTS" in *%$N%*|*%functions%*|*%$NAME%*) TEST="$NAME: echo via self connection of TCP IPv4 socket" if ! eval $NUMCOND; then :; elif [ "$UNAME" != Linux ]; then $PRINTF "test $F_n $TEST... ${YELLOW}only on Linux$NORMAL\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" else newport tcp4 # provide free port number in $PORT #ts="127.0.0.1:$tsl" testecho "$N" "$TEST" "" "tcp:$SECONDADDR:$PORT,sp=$PORT,bind=$SECONDADDR,reuseaddr" "$opts" fi esac N=$((N+1)) NAME=UDPSELF if ! eval $NUMCOND; then :; else case "$TESTS" in *%$N%*|*%functions%*|*%$NAME%*) TEST="$NAME: echo via self connection of UDP IPv4 socket" if [ "$UNAME" != Linux ]; then $PRINTF "test $F_n $TEST... ${YELLOW}only on Linux$NORMAL\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" else newport udp4 # provide free port number in $PORT testecho "$N" "$TEST" "" "UDP:$SECONDADDR:$PORT,sp=$PORT,bind=$SECONDADDR" "$opts" fi esac fi # NUMCOND N=$((N+1)) NAME=UDP6SELF case "$TESTS" in *%$N%*|*%functions%*|*%udp%*|*%udp6%*|*%ip6%*|*%$NAME%*) TEST="$NAME: echo via self connection of UDP IPv6 socket" if ! eval $NUMCOND; then :; elif [ "$UNAME" != Linux ]; then $PRINTF "test $F_n $TEST... ${YELLOW}only on Linux${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif ! testfeats udp ip6 >/dev/null || ! runsudp6 >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}UDP6 not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" else tf="$td/file$N" newport udp6 # provide free port number in $PORT testecho "$N" "$TEST" "" "UDP6:[::1]:$PORT,sp=$PORT,bind=[::1]" "$opts" fi esac N=$((N+1)) NAME=DUALUDPSELF if ! eval $NUMCOND; then :; else case "$TESTS" in *%$N%*|*%functions%*|*%$NAME%*) TEST="$NAME: echo via two unidirectional UDP IPv4 sockets" tf="$td/file$N" newport udp4; PORT1=$PORT # get free port newport udp4; PORT2=$PORT # get free port testecho "$N" "$TEST" "" "UDP:127.0.0.1:$PORT2,sp=$PORT1!!UDP:127.0.0.1:$PORT1,sp=$PORT2" "$opts" esac fi # NUMCOND N=$((N+1)) #function testdual { # local #} NAME=UNIXSTREAM if ! eval $NUMCOND; then :; else case "$TESTS" in *%$N%*|*%functions%*|*%unix%*|*%listen%*|*%$NAME%*) TEST="$NAME: echo via connection to UNIX domain socket" tf="$td/test$N.stdout" te="$td/test$N.stderr" ts="$td/test$N.socket" tdiff="$td/test$N.diff" da="test$N $(date) $RANDOM" CMD1="$TRACE $SOCAT $opts UNIX-LISTEN:$ts PIPE" CMD2="$TRACE $SOCAT $opts -!!- UNIX-CONNECT:$ts" printf "test $F_n $TEST... " $N $CMD1 $tf 2>"${te}1" & bg=$! # background process id waitfile "$ts" echo "$da" |$CMD2 >>"$tf" 2>>"${te}2" rc2=$? if [ "$rc2" -ne 0 ]; then $PRINTF "$FAILED: $TRACE $SOCAT:\n" echo "$CMD1 &" cat "${te}1" echo "$CMD2" echo "rc=$rc2" cat "${te}2" numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" elif ! echo "$da" |diff - "$tf" >"$tdiff"; then $PRINTF "$FAILED: diff:\n" cat "$tdiff" echo "$CMD1 &" cat "${te}1" echo "$CMD2" cat "${te}2" numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" else $PRINTF "$OK\n" if [ -n "$debug" ]; then cat "${te}1" "${te}2"; fi numOK=$((numOK+1)) fi kill $bg 2>/dev/null esac fi # NUMCOND N=$((N+1)) NAME=TCP4 case "$TESTS" in *%$N%*|*%functions%*|*%ip4%*|*%ipapp%*|*%tcp%*|*%listen%*|*%$NAME%*) TEST="$NAME: echo via connection to TCP V4 socket" if ! eval $NUMCOND; then : elif ! cond=$(checkconds "" "" "" \ "IP4 TCP LISTEN STDIO PIPE" \ "TCP4-LISTEN PIPE STDIN STDOUT TCP4" \ "so-reuseaddr" \ "tcp4" ); then $PRINTF "test $F_n $TEST... ${YELLOW}$cond${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" else tf="$td/test$N.stdout" te="$td/test$N.stderr" tdiff="$td/test$N.diff" newport tcp4; tsl=$PORT ts="127.0.0.1:$tsl" da="test$N $(date) $RANDOM" CMD1="$TRACE $SOCAT $opts TCP4-LISTEN:$tsl,$REUSEADDR PIPE" CMD2="$TRACE $SOCAT $opts STDIN!!STDOUT TCP4:$ts" printf "test $F_n $TEST... " $N $CMD1 >"$tf" 2>"${te}1" & pid1=$! waittcp4port $tsl 1 echo "$da" |$CMD2 >>"$tf" 2>>"${te}2" if [ $? -ne 0 ]; then $PRINTF "$FAILED\n" echo "$CMD0 &" cat "${te}0" >&2 echo "$CMD1" cat "${te}1" >&2 numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" namesFAIL="$namesFAIL $NAME" elif ! echo "$da" |diff - "$tf" >"$tdiff"; then $PRINTF "$FAILED\n" echo "$CMD0 &" cat "${te}0" >&2 echo "$CMD1" cat "${te}1" >&2 echo "// diff:" >&2 cat "$tdiff" >&2 numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" namesFAIL="$namesFAIL $NAME" else $PRINTF "$OK\n" if [ "$VERBOSE" ]; then echo "$CMD0 &"; fi if [ "$DEBUG" ]; then cat "${te}0" >&2; fi if [ "$VERBOSE" ]; then echo "$CMD1"; fi if [ "$DEBUG" ]; then cat "${te}1" >&2; fi numOK=$((numOK+1)) fi kill $pid1 2>/dev/null wait fi ;; # NUMCOND, checkconds esac N=$((N+1)) #et -xv NAME=TCP6 case "$TESTS" in *%$N%*|*%functions%*|*%ip6%*|*%ipapp%*|*%tcp%*|*%listen%*|*%$NAME%*) TEST="$NAME: echo via connection to TCP V6 socket" if ! eval $NUMCOND; then :; elif ! F=$(testfeats IP6 TCP LISTEN STDIO PIPE); then $PRINTF "test $F_n $TEST... ${YELLOW}Feature $F not configured${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif ! A=$(testaddrs - TCP6-LISTEN PIPE STDIN STDOUT TCP6-CONNECT); then $PRINTF "test $F_n $TEST... ${YELLOW}Address $A not available in $SOCAT${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif ! o=$(testoptions so-reuseaddr ) >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}Option $o not available in $SOCAT${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif ! runsip6 >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}IPv6 not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" else tf="$td/test$N.stdout" te="$td/test$N.stderr" tdiff="$td/test$N.diff" newport tcp6; tsl=$PORT ts="[::1]:$tsl" da="test$N $(date) $RANDOM" CMD1="$TRACE $SOCAT $opts TCP6-LISTEN:$tsl,$REUSEADDR PIPE" CMD2="$TRACE $SOCAT $opts STDIN!!STDOUT TCP6:$ts" printf "test $F_n $TEST... " $N $CMD1 >"$tf" 2>"${te}1" & pid=$! # background process id waittcp6port $tsl 1 echo "$da" |$CMD2 >>"$tf" 2>>"${te}2" if [ $? -ne 0 ]; then $PRINTF "$FAILED: $TRACE $SOCAT:\n" echo "$CMD1 &" cat "${te}1" >&2 echo "$CMD2" cat "${te}2" >&2 numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" elif ! echo "$da" |diff - "$tf" >"$tdiff"; then $PRINTF "$FAILED: diff:\n" echo "$CMD1 &" cat "${te}1" >&2 echo "$CMD2" cat "${te}2" >&2 echo diff: cat "$tdiff" numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" else $PRINTF "$OK\n" if [ "$VERBOSE" ]; then echo "$CMD1 &"; fi if [ "$DEBUG" ]; then cat "${te}1" >&2; fi if [ "$VERBOSE" ]; then echo "$CMD2"; fi if [ "$DEBUG" ]; then cat "${te}2" >&2; fi numOK=$((numOK+1)) fi kill $pid 2>/dev/null fi esac N=$((N+1)) #set +vx # Test if TCP client with IPv4 address connects to IPv4 port NAME=TCPX4 case "$TESTS" in *%$N%*|*%functions%*|*%ip4%*|*%ipapp%*|*%tcp%*|*%listen%*|*%$NAME%*) TEST="$NAME: echo via connection to TCP socket, v4 by target" if ! eval $NUMCOND; then :; elif ! F=$(testfeats STDIO PIPE IP4 TCP LISTEN); then $PRINTF "test $F_n $TEST... ${YELLOW}Feature $F not configured${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif ! A=$(testaddrs TCP TCP-LISTEN STDIN STDOUT PIPE); then $PRINTF "test $F_n $TEST... ${YELLOW}Address $A not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif ! o=$(testoptions pf) >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}Option $o not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif ! runsip4 >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}IPv4 not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" else tf="$td/test$N.stdout" te="$td/test$N.stderr" tdiff="$td/test$N.diff" newport tcp4; tsl=$PORT ts="127.0.0.1:$tsl" da="test$N $(date) $RANDOM" CMD0="$TRACE $SOCAT $opts TCP-LISTEN:$tsl,pf=ip4,$REUSEADDR PIPE" CMD1="$TRACE $SOCAT $opts STDIN!!STDOUT TCP:$ts" printf "test $F_n $TEST... " $N $CMD0 >"$tf" 2>"${te}0" & pid=$! # background process id waittcp4port $tsl 1 echo "$da" |$CMD1 >>"$tf" 2>>"${te}1" if [ $? -ne 0 ]; then $PRINTF "$FAILED: $TRACE $SOCAT:\n" echo "$CMD0 &" cat "${te}0" >&2 echo "$CMD1" cat "${te}1" >&2 numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" namesFAIL="$namesFAIL $NAME" elif ! echo "$da" |diff - "$tf" >"$tdiff"; then $PRINTF "$FAILED: diff:\n" cat "$tdiff" echo "$CMD0 &" cat "${te}0" >&2 echo "$CMD1" cat "${te}1" >&2 numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" namesFAIL="$namesFAIL $NAME" else $PRINTF "$OK\n" if [ "$VERBOSE" ]; then echo "$CMD0 &"; fi if [ "$DEBUG" ]; then cat "${te}0" >&2; fi if [ "$VERBOSE" ]; then echo "$CMD1"; fi if [ "$DEBUG" ]; then cat "${te}1" >&2; fi numOK=$((numOK+1)) fi kill $pid 2>/dev/null fi esac N=$((N+1)) # Test if TCP client with IPv6 address connects to IPv6 port NAME=TCPX6 case "$TESTS" in *%$N%*|*%functions%*|*%ip6%*|*%ipapp%*|*%tcp%*|*%listen%*|*%$NAME%*) TEST="$NAME: echo via connection to TCP socket, v6 by target" if ! eval $NUMCOND; then :; elif ! F=$(testfeats STDIO PIPE IP6 TCP LISTEN); then $PRINTF "test $F_n $TEST... ${YELLOW}Feature $F not configured${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif ! A=$(testaddrs TCP TCP-LISTEN STDIN STDOUT PIPE); then $PRINTF "test $F_n $TEST... ${YELLOW}Address $A not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif ! o=$(testoptions pf) >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}Option $o not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif ! runsip6 >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}IPv6 not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" else tf="$td/test$N.stdout" te="$td/test$N.stderr" tdiff="$td/test$N.diff" newport tcp6; tsl=$PORT ts="[::1]:$tsl" da="test$N $(date) $RANDOM" CMD0="$TRACE $SOCAT $opts TCP-LISTEN:$tsl,pf=ip6,$REUSEADDR PIPE" CMD1="$TRACE $SOCAT $opts STDIN!!STDOUT TCP:$ts" printf "test $F_n $TEST... " $N $CMD0 >"$tf" 2>"${te}0" & pid=$! # background process id waittcp6port $tsl 1 echo "$da" |$CMD1 >>"$tf" 2>>"${te}1" if [ $? -ne 0 ]; then $PRINTF "$FAILED: $TRACE $SOCAT:\n" echo "$CMD0 &" cat "${te}0" >&2 echo "$CMD1" cat "${te}1" >&2 numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" namesFAIL="$namesFAIL $NAME" elif ! echo "$da" |diff - "$tf" >"$tdiff"; then $PRINTF "$FAILED: diff:\n" cat "$tdiff" echo "$CMD0 &" cat "${te}0" >&2 echo "$CMD1" cat "${te}1" >&2 numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" namesFAIL="$namesFAIL $NAME" else $PRINTF "$OK\n" if [ "$VERBOSE" ]; then echo "$CMD0 &"; fi if [ "$DEBUG" ]; then cat "${te}0" >&2; fi if [ "$VERBOSE" ]; then echo "$CMD1"; fi if [ "$DEBUG" ]; then cat "${te}1" >&2; fi numOK=$((numOK+1)) fi kill $pid 2>/dev/null fi esac N=$((N+1)) # TCP6-LISTEN may also listen for IPv4 connections. Test if option # ipv6-v6only=0 shows this behaviour. NAME=IPV6ONLY0 case "$TESTS" in *%$N%*|*%functions%*|*%ip6%*|*%ipapp%*|*%tcp%*|*%listen%*|*%$NAME%*) TEST="$NAME: option ipv6-v6only=0 listens on IPv4" # create a listening TCP6 socket and try to connect to the port using TCP4 if ! eval $NUMCOND; then :; elif ! testfeats tcp ip4 >/dev/null || ! runsip4 >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}TCP4 not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif ! testfeats ip6 >/dev/null || ! runsip6 >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}TCP6 not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif ! feat=$(testoptions ipv6-v6only); then $PRINTF "test $F_n $TEST... ${YELLOW}$feat not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" else tf="$td/test$N.stdout" te="$td/test$N.stderr" tdiff="$td/test$N.diff" newport tcp6; tsl=$PORT ts="127.0.0.1:$tsl" da="test$N $(date) $RANDOM" CMD1="$TRACE $SOCAT $opts TCP6-LISTEN:$tsl,ipv6-v6only=0,$REUSEADDR PIPE" CMD2="$TRACE $SOCAT $opts STDIN!!STDOUT TCP4:$ts" printf "test $F_n $TEST... " $N $CMD1 >"$tf" 2>"${te}1" & pid=$! # background process id waittcp6port $tsl 1 echo "$da" |$CMD2 >>"$tf" 2>>"${te}2" if [ $? -ne 0 ]; then $PRINTF "$FAILED: $TRACE $SOCAT:\n" echo "$CMD1 &" echo "$CMD2" cat "${te}1" "${te}2" numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" elif ! echo "$da" |diff - "$tf" >"$tdiff"; then $PRINTF "$FAILED: diff:\n" cat "$tdiff" numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" else $PRINTF "$OK\n" if [ -n "$debug" ]; then cat "${te}1" "${te}2"; fi numOK=$((numOK+1)) fi kill $pid 2>/dev/null fi esac N=$((N+1)) #set -vx # TCP6-LISTEN may also listen for IPv4 connections. Test if option # ipv6-v6only=1 turns off this behaviour. NAME=IPV6ONLY1 case "$TESTS" in *%$N%*|*%functions%*|*%ip6%*|*%ipapp%*|*%tcp%*|*%listen%*|*%$NAME%*) TEST="$NAME: option ipv6-v6only=1 does not listen on IPv4" if ! eval $NUMCOND; then :; elif ! testfeats tcp ip4 >/dev/null || ! runsip4 >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}TCP4 not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif ! testfeats ip6 >/dev/null || ! runsip6 >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}IP6 not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif ! feat=$(testoptions ipv6-v6only); then $PRINTF "test $F_n $TEST... ${YELLOW}$feat not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" else tf="$td/test$N.stdout" te="$td/test$N.stderr" tdiff="$td/test$N.diff" newport tcp6; tsl=$PORT ts="127.0.0.1:$tsl" da="test$N $(date) $RANDOM" CMD1="$TRACE $SOCAT $opts TCP6-LISTEN:$tsl,ipv6-v6only=1,$REUSEADDR PIPE" CMD2="$TRACE $SOCAT $opts stdin!!stdout TCP4:$ts" printf "test $F_n $TEST... " $N $CMD1 >"$tf" 2>"${te}1" & pid=$! # background process id waittcp6port $tsl 1 echo "$da" |$CMD2 >>"$tf" 2>>"${te}2" if [ $? -eq 0 ]; then $PRINTF "$FAILED:\n" cat "${te}1" "${te}2" numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" elif echo "$da" |diff - "$tf" >"$tdiff"; then $PRINTF "$FAILED:\n" if [ -n "$debug" ]; then cat "${te}1" "${te}2"; fi numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" else $PRINTF "$OK\n" numOK=$((numOK+1)) fi kill $pid; wait wait fi esac N=$((N+1)) #set +vx NAME=ENV_LISTEN_4 case "$TESTS" in *%$N%*|*%functions%*|*%ip6%*|*%ipapp%*|*%tcp%*|*%listen%*|*%$NAME%*) TEST="$NAME: env SOCAT_DEFAULT_LISTEN_IP for IPv4 preference on listen" if ! eval $NUMCOND; then :; elif ! testfeats tcp ip4 >/dev/null || ! runsip4 >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}TCP4 not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif ! testfeats ip6 >/dev/null || ! runstcp6 >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}TCP6 not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif ! feat=$(testoptions ipv6-v6only); then $PRINTF "test $F_n $TEST... ${YELLOW}$feat not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" else tf="$td/test$N.stdout" te="$td/test$N.stderr" tdiff="$td/test$N.diff" newport tcp4; tsl=$PORT ts="127.0.0.1:$tsl" da="test$N $(date) $RANDOM" CMD1="$TRACE $SOCAT $opts TCP-LISTEN:$tsl,$REUSEADDR PIPE" CMD2="$TRACE $SOCAT $opts STDIN!!STDOUT TCP4:$ts" printf "test $F_n $TEST... " $N SOCAT_DEFAULT_LISTEN_IP=4 $CMD1 >"$tf" 2>"${te}1" & pid=$! # background process id waittcp4port $tsl 1 echo "$da" |$CMD2 >>"$tf" 2>>"${te}2" if [ $? -ne 0 ]; then $PRINTF "$FAILED: $TRACE $SOCAT:\n" echo "$CMD1 &" echo "$CMD2" cat "${te}1" "${te}2" numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" elif ! echo "$da" |diff - "$tf" >"$tdiff"; then $PRINTF "$FAILED: diff:\n" cat "$tdiff" numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" else $PRINTF "$OK\n" if [ -n "$debug" ]; then cat "${te}1" "${te}2"; fi numOK=$((numOK+1)) fi kill $pid 2>/dev/null; wait fi esac N=$((N+1)) NAME=ENV_LISTEN_6 case "$TESTS" in *%$N%*|*%functions%*|*%ip6%*|*%ipapp%*|*%tcp%*|*%listen%*|*%$NAME%*) TEST="$NAME: env SOCAT_DEFAULT_LISTEN_IP for IPv6 preference on listen" if ! eval $NUMCOND; then :; elif ! testfeats tcp ip4 >/dev/null || ! runsip4 >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}TCP4 not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif ! testfeats ip6 >/dev/null || ! runsip6 >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}IP6 not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" else tf="$td/test$N.stdout" te="$td/test$N.stderr" tdiff="$td/test$N.diff" newport tcp6; tsl=$PORT ts="[::1]:$tsl" da="test$N $(date) $RANDOM" CMD1="$TRACE $SOCAT $opts TCP-LISTEN:$tsl,$REUSEADDR PIPE" CMD2="$TRACE $SOCAT $opts STDIN!!STDOUT TCP6:$ts" printf "test $F_n $TEST... " $N SOCAT_DEFAULT_LISTEN_IP=6 $CMD1 >"$tf" 2>"${te}1" & pid=$! # background process id waittcp6port $tsl 1 echo "$da" |$CMD2 >>"$tf" 2>>"${te}2" if [ $? -ne 0 ]; then $PRINTF "$FAILED: $TRACE $SOCAT:\n" echo "SOCAT_DEFAULT_LISTEN_IP=6 $CMD1 &" cat "${te}1" >&2 echo "$CMD2" cat "${te}2" >&2 numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" elif ! echo "$da" |diff - "$tf" >"$tdiff"; then $PRINTF "$FAILED (diff):\n" echo "SOCAT_DEFAULT_LISTEN_IP=6 $CMD1 &" cat "${te}1" >&2 echo "$CMD2" cat "${te}2" >&2 echo "// diff:" >&2 cat "$tdiff" >&2 numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" else $PRINTF "$OK\n" if [ "$VERBOSE" ]; then echo "$CMD1 &"; fi if [ "$DEBUG" ]; then cat "${te}1" >&2; fi if [ "$VERBOSE" ]; then echo "$CMD2"; fi if [ "$DEBUG" ]; then cat "${te}2" >&2; fi numOK=$((numOK+1)) fi kill $pid 2>/dev/null; wait fi esac N=$((N+1)) NAME=LISTEN_OPTION_4 case "$TESTS" in *%$N%*|*%functions%*|*%ip6%*|*%ipapp%*|*%tcp%*|*%listen%*|*%$NAME%*) TEST="$NAME: option -4 for IPv4 preference on listen" if ! eval $NUMCOND; then :; elif ! testfeats tcp ip4 >/dev/null || ! runsip4 >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}TCP4 not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif ! testfeats ip6 >/dev/null || ! runsip6 >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}IP6 not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif ! feat=$(testoptions ipv6-v6only); then $PRINTF "test $F_n $TEST... ${YELLOW}$feat not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" else tf="$td/test$N.stdout" te="$td/test$N.stderr" tdiff="$td/test$N.diff" newport tcp4; tsl=$PORT ts="127.0.0.1:$tsl" da="test$N $(date) $RANDOM" CMD1="$TRACE $SOCAT $opts -4 TCP-LISTEN:$tsl,$REUSEADDR PIPE" CMD2="$TRACE $SOCAT $opts STDIN!!STDOUT TCP4:$ts" printf "test $F_n $TEST... " $N SOCAT_DEFAULT_LISTEN_IP=6 $CMD1 >"$tf" 2>"${te}1" & pid=$! # background process id waittcp4port $tsl 1 echo "$da" |$CMD2 >>"$tf" 2>>"${te}2" if [ $? -ne 0 ]; then $PRINTF "$FAILED: $TRACE $SOCAT:\n" echo "$CMD1 &" echo "$CMD2" cat "${te}1" "${te}2" numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" elif ! echo "$da" |diff - "$tf" >"$tdiff"; then $PRINTF "$FAILED: diff:\n" cat "$tdiff" numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" else $PRINTF "$OK\n" if [ -n "$debug" ]; then cat "${te}1" "${te}2"; fi numOK=$((numOK+1)) fi kill $pid 2>/dev/null; wait fi esac N=$((N+1)) NAME=LISTEN_OPTION_6 case "$TESTS" in *%$N%*|*%functions%*|*%ip6%*|*%ipapp%*|*%tcp%*|*%listen%*|*%$NAME%*) TEST="$NAME: option -6 for IPv6 preference on listen" if ! eval $NUMCOND; then :; elif ! testfeats tcp ip4 >/dev/null || ! runsip4 >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}TCP4 not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif ! testfeats ip6 >/dev/null || ! runsip6 >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}IP6 not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" else tf="$td/test$N.stdout" te="$td/test$N.stderr" tdiff="$td/test$N.diff" newport tcp6; tsl=$PORT ts="[::1]:$tsl" da="test$N $(date) $RANDOM" CMD1="$TRACE $SOCAT $opts -6 TCP-LISTEN:$tsl,$REUSEADDR PIPE" CMD2="$TRACE $SOCAT $opts STDIN!!STDOUT TCP6:$ts" printf "test $F_n $TEST... " $N SOCAT_DEFAULT_LISTEN_IP=4 $CMD1 >"$tf" 2>"${te}1" & pid=$! # background process id waittcp6port $tsl 1 echo "$da" |$CMD2 >>"$tf" 2>>"${te}2" if [ $? -ne 0 ]; then $PRINTF "$FAILED: $TRACE $SOCAT:\n" echo "$CMD1 &" echo "$CMD2" cat "${te}1" "${te}2" numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" elif ! echo "$da" |diff - "$tf" >"$tdiff"; then $PRINTF "$FAILED: diff:\n" cat "$tdiff" numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" else $PRINTF "$OK\n" if [ -n "$debug" ]; then cat "${te}1" "${te}2"; fi numOK=$((numOK+1)) fi kill $pid 2>/dev/null; wait wait fi # feats esac N=$((N+1)) NAME=LISTEN_PF_IP4 case "$TESTS" in *%$N%*|*%functions%*|*%ip6%*|*%ipapp%*|*%tcp%*|*%listen%*|*%$NAME%*) TEST="$NAME: pf=4 overrides option -6 on listen" if ! eval $NUMCOND; then :; elif ! testfeats tcp ip4 >/dev/null || ! runsip4 >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}TCP4 not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif ! testfeats ip6 >/dev/null || ! runsip6 >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}IP6 not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif ! feat=$(testoptions ipv6-v6only); then $PRINTF "test $F_n $TEST... ${YELLOW}$feat not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" else tf="$td/test$N.stdout" te="$td/test$N.stderr" tdiff="$td/test$N.diff" newport tcp4; tsl=$PORT ts="127.0.0.1:$tsl" da="test$N $(date) $RANDOM" CMD1="$TRACE $SOCAT $opts -6 TCP-LISTEN:$tsl,pf=ip4,$REUSEADDR PIPE" CMD2="$TRACE $SOCAT $opts STDIN!!STDOUT TCP4:$ts" printf "test $F_n $TEST... " $N SOCAT_DEFAULT_LISTEN_IP=6 $CMD1 >"$tf" 2>"${te}1" & pid=$! # background process id waittcp4port $tsl 1 echo "$da" |$CMD2 >>"$tf" 2>>"${te}2" if [ $? -ne 0 ]; then $PRINTF "$FAILED: $TRACE $SOCAT:\n" echo "$CMD1 &" echo "$CMD2" cat "${te}1" "${te}2" numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" elif ! echo "$da" |diff - "$tf" >"$tdiff"; then $PRINTF "$FAILED: diff:\n" cat "$tdiff" numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" else $PRINTF "$OK\n" if [ -n "$debug" ]; then cat "${te}1" "${te}2"; fi numOK=$((numOK+1)) fi kill $pid 2>/dev/null; wait fi esac N=$((N+1)) NAME=LISTEN_PF_IP6 case "$TESTS" in *%$N%*|*%functions%*|*%ip6%*|*%ipapp%*|*%tcp%*|*%listen%*|*%$NAME%*) TEST="$NAME: pf=6 overrides option -4 on listen" if ! eval $NUMCOND; then :; elif ! testfeats tcp ip4 >/dev/null || ! runsip4 >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}TCP4 not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif ! testfeats ip6 >/dev/null || ! runsip6 >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}IP6 not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" else tf="$td/test$N.stdout" te="$td/test$N.stderr" tdiff="$td/test$N.diff" newport tcp6; tsl=$PORT ts="[::1]:$tsl" da="test$N $(date) $RANDOM" CMD1="$TRACE $SOCAT $opts -4 TCP-LISTEN:$tsl,pf=ip6,$REUSEADDR PIPE" CMD2="$TRACE $SOCAT $opts STDIN!!STDOUT TCP6:$ts" printf "test $F_n $TEST... " $N SOCAT_DEFAULT_LISTEN_IP=4 $CMD1 >"$tf" 2>"${te}1" & pid=$! # background process id waittcp6port $tsl 1 echo "$da" |$CMD2 >>"$tf" 2>>"${te}2" if [ $? -ne 0 ]; then $PRINTF "$FAILED: $TRACE $SOCAT:\n" echo "$CMD1 &" echo "$CMD2" cat "${te}1" "${te}2" numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" elif ! echo "$da" |diff - "$tf" >"$tdiff"; then $PRINTF "$FAILED: diff:\n" cat "$tdiff" numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" else $PRINTF "$OK\n" if [ -n "$debug" ]; then cat "${te}1" "${te}2"; fi numOK=$((numOK+1)) fi kill $pid 2>/dev/null; wait fi ;; # NUMCOND, feats esac N=$((N+1)) NAME=UDP4STREAM case "$TESTS" in *%$N%*|*%functions%*|*%ip4%*|*%ipapp%*|*%udp%*|*%listen%*|*%$NAME%*) TEST="$NAME: echo via connection to UDP V4 socket" if ! eval $NUMCOND; then :; else tf="$td/test$N.stdout" te="$td/test$N.stderr" tdiff="$td/test$N.diff" newport udp4; tsl=$PORT ts="$LOCALHOST:$tsl" da="test$N $(date) $RANDOM" CMD1="$TRACE $SOCAT $opts UDP4-LISTEN:$tsl,$REUSEADDR PIPE" CMD2="$TRACE $SOCAT $opts - UDP4:$ts" printf "test $F_n $TEST... " $N $CMD1 >"$tf" 2>"${te}1" & pid1=$! waitudp4port $tsl 1 echo "$da" |$CMD2 >>"$tf" 2>>"${te}2" rc2=$? kill $pid1 2>/dev/null; wait if [ $rc2 -ne 0 ]; then $PRINTF "$FAILED: $TRACE $SOCAT:\n" echo "$CMD1 &" echo "$CMD2" cat "${te}1" "${te}2" numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" elif ! echo "$da" |diff - "$tf" >"$tdiff"; then $PRINTF "$FAILED\n" echo "$CMD1 &" cat "${te}1" echo "$CMD2" cat "${te}2" cat "$tdiff" numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" else $PRINTF "$OK\n" if [ -n "$debug" ]; then cat "${te}1" "${te}2"; fi numOK=$((numOK+1)) fi fi ;; # NUMCOND esac N=$((N+1)) NAME=UDP6STREAM case "$TESTS" in *%$N%*|*%functions%*|*%ip6%*|*%ipapp%*|*%udp%*|*%listen%*|*%$NAME%*) TEST="$NAME: echo via connection to UDP V6 socket" if ! eval $NUMCOND; then :; elif ! feat=$(testfeats udp ip6) || ! runsip6 >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}UDP6 not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" else tf="$td/test$N.stdout" te="$td/test$N.stderr" tdiff="$td/test$N.diff" newport udp6; tsl=$PORT ts="$LOCALHOST6:$tsl" da="test$N $(date) $RANDOM" CMD1="$TRACE $SOCAT $opts UDP6-LISTEN:$tsl,$REUSEADDR PIPE" CMD2="$TRACE $SOCAT $opts - UDP6:$ts" printf "test $F_n $TEST... " $N $CMD1 >"$tf" 2>"${te}1" & pid1=$! waitudp6port $tsl 1 echo "$da" |$CMD2 >>"$tf" 2>>"${te}2" rc2=$? kill $pid1 2>/dev/null; wait if [ $rc2 -ne 0 ]; then $PRINTF "$FAILED: $TRACE $SOCAT:\n" echo "$CMD1 &" echo "$CMD2" cat "${te}1" "${te}2" numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" elif ! echo "$da" |diff - "$tf" >"$tdiff"; then $PRINTF "$FAILED\n" cat "$tdiff" numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" else $PRINTF "$OK\n" if [ -n "$debug" ]; then cat "${te}1" "${te}2"; fi numOK=$((numOK+1)) fi fi ;; # ! testfeats esac N=$((N+1)) NAME=GOPENFILE case "$TESTS" in *%$N%*|*%functions%*|*%engine%*|*%gopen%*|*%file%*|*%ignoreeof%*|*%$NAME%*) TEST="$NAME: file opening with gopen" if ! eval $NUMCOND; then :; else tf1="$td/test$N.1.stdout" tf2="$td/test$N.2.stdout" te="$td/test$N.stderr" tdiff="$td/test$N.diff" da="test$N $(date) $RANDOM" echo "$da" >$tf1 CMD="$TRACE $SOCAT $opts $tf1!!/dev/null /dev/null,ignoreeof!!-" printf "test $F_n $TEST... " $N $CMD >"$tf2" 2>"$te" if [ $? -ne 0 ]; then $PRINTF "$FAILED: $TRACE $SOCAT:\n" echo "$CMD" cat "$te" numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" elif ! diff "$tf1" "$tf2" >"$tdiff"; then $PRINTF "$FAILED: diff:\n" cat "$tdiff" numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" else $PRINTF "$OK\n" if [ -n "$debug" ]; then cat $te; fi numOK=$((numOK+1)) fi fi # NUMCOND esac N=$((N+1)) NAME=GOPENPIPE case "$TESTS" in *%$N%*|*%functions%*|*%gopen%*|*%pipe%*|*%ignoreeof%*|*%$NAME%*) TEST="$NAME: pipe opening with gopen for reading" if ! eval $NUMCOND; then :; else tp="$td/pipe$N" tf="$td/test$N.stdout" te="$td/test$N.stderr" tdiff="$td/test$N.diff" da="test$N $(date) $RANDOM" CMD="$TRACE $SOCAT $opts $tp!!/dev/null /dev/null,ignoreeof!!$tf" printf "test $F_n $TEST... " $N #mknod $tp p # no mknod p on FreeBSD mkfifo $tp $CMD >$tf 2>"$te" & #($CMD >$tf 2>"$te" || rm -f "$tp") 2>/dev/null & bg=$! # background process id usleep $MICROS if [ ! -p "$tp" ]; then $PRINTF "$FAILED: $TRACE $SOCAT:\n" echo "$CMD" cat "$te" numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" else #echo "$da" >"$tp" # might hang forever echo "$da" >"$tp" & export pid=$!; (sleep 1; kill $pid 2>/dev/null) & # Solaris needs more time: sleep 1 kill "$bg" 2>/dev/null; wait if ! echo "$da" |diff - "$tf" >"$tdiff"; then if [ -s "$te" ]; then $PRINTF "$FAILED: $TRACE $SOCAT:\n" echo "$CMD" cat "$te" else $PRINTF "$FAILED: diff:\n" cat "$tdiff" fi numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" else $PRINTF "$OK\n" if [ -n "$debug" ]; then cat $te; fi numOK=$((numOK+1)) fi fi wait fi # NUMCOND esac N=$((N+1)) NAME=GOPENUNIXSTREAM case "$TESTS" in *%$N%*|*%functions%*|*%gopen%*|*%unix%*|*%listen%*|*%$NAME%*) TEST="$NAME: GOPEN on UNIX stream socket" if ! eval $NUMCOND; then :; else ts="$td/test$N.socket" tf="$td/test$N.stdout" te="$td/test$N.stderr" tdiff="$td/test$N.diff" da1="test$N $(date) $RANDOM" #establish a listening unix socket in background SRV="$TRACE $SOCAT $opts -lpserver UNIX-LISTEN:\"$ts\" PIPE" #make a connection CMD="$TRACE $SOCAT $opts - $ts" $PRINTF "test $F_n $TEST... " $N eval "$SRV 2>${te}s &" pids=$! waitfile "$ts" echo "$da1" |eval "$CMD" >"${tf}1" 2>"${te}1" if [ $? -ne 0 ]; then kill "$pids" 2>/dev/null $PRINTF "$FAILED:\n" echo "$SRV &" cat "${te}s" echo "$CMD" cat "${te}1" numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" elif ! echo "$da1" |diff - "${tf}1" >"$tdiff"; then kill "$pids" 2>/dev/null $PRINTF "$FAILED:\n" echo "$SRV &" cat "${te}s" echo "$CMD" cat "${te}1" cat "$tdiff" numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" else $PRINTF "$OK\n" if [ -n "$debug" ]; then cat $te; fi numOK=$((numOK+1)) fi # !(rc -ne 0) wait fi # NUMCOND esac N=$((N+1)) NAME=GOPENUNIXSEQPACKET case "$TESTS" in *%$N%*|*%functions%*|*%gopen%*|*%unix%*|*%listen%*|*%seqpacket%*|*%$NAME%*) TEST="$NAME: GOPEN on UNIX seqpacket socket" if ! eval $NUMCOND; then :; else ts="$td/test$N.socket" tf="$td/test$N.stdout" te="$td/test$N.stderr" tdiff="$td/test$N.diff" da1="test$N $(date) $RANDOM" #establish a listening unix socket in background SRV="$TRACE $SOCAT $opts -lpserver UNIX-LISTEN:\"$ts\",so-type=$SOCK_SEQPACKET PIPE" #make a connection CMD="$TRACE $SOCAT $opts - $ts" $PRINTF "test $F_n $TEST... " $N eval "$SRV 2>${te}s &" pids=$! waitfile "$ts" echo "$da1" |eval "$CMD" >"${tf}1" 2>"${te}1" if [ $? -ne 0 ]; then kill "$pids" 2>/dev/null $PRINTF "$FAILED:\n" echo "$SRV &" cat "${te}s" echo "$CMD" cat "${te}1" numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" elif ! echo "$da1" |diff - "${tf}1" >"$tdiff"; then kill "$pids" 2>/dev/null $PRINTF "$FAILED:\n" echo "$SRV &" cat "${te}s" echo "$CMD" cat "${te}1" cat "$tdiff" numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" else $PRINTF "$OK\n" if [ -n "$debug" ]; then cat $te; fi numOK=$((numOK+1)) fi # !(rc -ne 0) wait fi # NUMCOND esac N=$((N+1)) NAME=GOPENUNIXDGRAM case "$TESTS" in *%$N%*|*%functions%*|*%gopen%*|*%unix%*|*%dgram%*|*%$NAME%*) TEST="$NAME: GOPEN on UNIX datagram socket" if ! eval $NUMCOND; then :; else ts="$td/test$N.socket" tf="$td/test$N.stdout" te="$td/test$N.stderr" tdiff="$td/test$N.diff" da1="test$N $(date) $RANDOM" #establish a receiving unix socket in background SRV="$TRACE $SOCAT $opts -u -lpserver UNIX-RECV:\"$ts\" file:\"$tf\",create" #make a connection CMD="$TRACE $SOCAT $opts -u - $ts" $PRINTF "test $F_n $TEST... " $N eval "$SRV 2>${te}s &" pids=$! waitfile "$ts" echo "$da1" |eval "$CMD" 2>"${te}1" waitfile -s "$tf" if [ $? -ne 0 ]; then $PRINTF "$FAILED:\n" echo "$SRV &" cat "${te}s" echo "$CMD" cat "${te}1" numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" elif ! echo "$da1" |diff - "${tf}" >"$tdiff"; then $PRINTF "$FAILED:\n" echo "$SRV &" cat "${te}s" echo "$CMD" cat "${te}1" cat "$tdiff" numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" else $PRINTF "$OK\n" if [ -n "$debug" ]; then cat $te; fi numOK=$((numOK+1)) fi # !(rc -ne 0) kill "$pids" 2>/dev/null; wait fi ;; # NUMCOND esac N=$((N+1)) NAME=IGNOREEOF case "$TESTS" in *%$N%*|*%functions%*|*%engine%*|*%ignoreeof%*|*%$NAME%*) TEST="$NAME: ignoreeof on file" if ! eval $NUMCOND; then :; else ti="$td/test$N.file" tf="$td/test$N.stdout" te="$td/test$N.stderr" tdiff="$td/test$N.diff" da="test$N $(date) $RANDOM" CMD="$TRACE $SOCAT $opts -u file:\"$ti\",ignoreeof -" printf "test $F_n $TEST... " $N touch "$ti" $CMD >"$tf" 2>"$te" & bg=$! usleep 500000 echo "$da" >>"$ti" sleep 1 kill $bg 2>/dev/null; wait if ! echo "$da" |diff - "$tf" >"$tdiff"; then $PRINTF "$FAILED: diff:\n" cat "$tdiff" listFAIL="$listFAIL $N" numFAIL=$((numFAIL+1)) else $PRINTF "$OK\n" if [ -n "$debug" ]; then cat $te; fi numOK=$((numOK+1)) fi fi ;; # NUMCOND esac N=$((N+1)) NAME=IGNOREEOF_REV case "$TESTS" in *%$N%*|*%functions%*|*%engine%*|*%ignoreeof%*|*%$NAME%*) TEST="$NAME: ignoreeof on file right-to-left" if ! eval $NUMCOND; then :; else ti="$td/test$N.file" tf="$td/test$N.stdout" te="$td/test$N.stderr" tdiff="$td/test$N.diff" da="test$N $(date) $RANDOM" CMD="$SOCAT $opts -U - file:\"$ti\",ignoreeof" printf "test $F_n $TEST... " $N touch "$ti" $CMD >"$tf" 2>"$te" & bg=$! usleep 500000 echo "$da" >>"$ti" sleep 1 kill $bg 2>/dev/null if ! echo "$da" |diff - "$tf" >"$tdiff"; then $PRINTF "$FAILED: diff:\n" cat "$tdiff" listFAIL="$listFAIL $N" numFAIL=$((numFAIL+1)) else $PRINTF "$OK\n" if [ -n "$debug" ]; then cat $te; fi numOK=$((numOK+1)) fi wait fi ;; # NUMCOND esac N=$((N+1)) NAME=EXECIGNOREEOF case "$TESTS" in *%$N%*|*%functions%*|*%engine%*|*%ignoreeof%*|*%$NAME%*) TEST="$NAME: exec against address with ignoreeof" if ! eval $NUMCOND; then :; else tf="$td/test$N.stdout" te="$td/test$N.stderr" # remark: diagnostics to null, no good style CMD="$TRACE $SOCAT $opts -lf /dev/null EXEC:$TRUE /dev/null,ignoreeof" printf "test $F_n $TEST... " $N $CMD >"$tf" 2>"$te" if [ -s "$te" ]; then $PRINTF "$FAILED: $TRACE $SOCAT:\n" echo "$CMD" cat "$te" numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" else $PRINTF "$OK\n" if [ -n "$debug" ]; then cat $te; fi numOK=$((numOK+1)) fi fi ;; # NUMCOND esac N=$((N+1)) NAME=FAKEPTY case "$TESTS" in *%$N%*|*%functions%*|*%pty%*|*%$NAME%*) TEST="$NAME: generation of pty for other processes" if ! eval $NUMCOND; then :; elif ! testfeats pty >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}PTY not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" else tt="$td/pty$N" tf="$td/test$N.stdout" te="$td/test$N.stderr" tdiff="$td/test$N.diff" da="test$N $(date) $RANDOM" CMD1="$TRACE $SOCAT $opts PTY,$PTYOPTS,link=$tt PIPE" CMD2="$TRACE $SOCAT $opts - $tt,$PTYOPTS2" printf "test $F_n $TEST... " $N $CMD1 2>"${te}1" & pid=$! # background process id waitfile "$tt" # this hangs on HP-UX, so we use a timeout (echo "$da"; sleep 1) |$CMD2 >$tf 2>"${te}2" & pid2=$! #sleep 5 && kill $rc2 2>/dev/null & wait $pid2 if ! echo "$da" |diff - "$tf" >"$tdiff"; then $PRINTF "$FAILED: $TRACE $SOCAT:\n" echo "$CMD1 &" sleep 1 echo "$CMD2" cat "${te}1" cat "${te}2" cat "$tdiff" numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" else $PRINTF "$OK\n" if [ -n "$debug" ]; then cat "${te}1" "${te}2"; fi numOK=$((numOK+1)) fi kill $pid 2>/dev/null; wait fi ;; # NUMCOND, feats esac N=$((N+1)) NAME=O_TRUNC case "$TESTS" in *%$N%*|*%functions%*|*%$NAME%*) TEST="$NAME: option o-trunc" if ! eval $NUMCOND; then :; else ff="$td/test$N.file" tf="$td/test$N.stdout" te="$td/test$N.stderr" tdiff="$td/test$N.diff" da="test$N $(date) $RANDOM" CMD="$TRACE $SOCAT -u $opts - open:$ff,append,o-trunc" printf "test $F_n $TEST... " $N rm -f $ff; $ECHO "prefix-\c" >$ff echo "$da" |$CMD >$tf 2>"$te" rc0=$? if ! [ $rc0 = 0 ] || ! echo "$da" |diff - $ff >"$tdiff"; then $PRINTF "$FAILED: $TRACE $SOCAT:\n" echo "$CMD" cat "$te" cat "$tdiff" numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" else $PRINTF "$OK\n" if [ -n "$debug" ]; then cat $te; fi numOK=$((numOK+1)) fi fi ;; # NUMCOND esac N=$((N+1)) NAME=FTRUNCATE case "$TESTS" in *%$N%*|*%functions%*|*%$NAME%*) TEST="$NAME: option ftruncate" if ! eval $NUMCOND; then :; else ff="$td/test$N.file" tf="$td/test$N.stdout" te="$td/test$N.stderr" tdiff="$td/test$N.diff" da="test$N $(date) $RANDOM" CMD="$TRACE $SOCAT -u $opts - open:$ff,append,ftruncate=0" printf "test $F_n $TEST... " $N rm -f $ff; $ECHO "prefix-\c" >$ff if ! echo "$da" |$CMD >$tf 2>"$te" || ! echo "$da" |diff - $ff >"$tdiff"; then $PRINTF "$FAILED: $TRACE $SOCAT:\n" echo "$CMD" cat "$te" cat "$tdiff" numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" else $PRINTF "$OK\n" if [ -n "$debug" ]; then cat $te; fi numOK=$((numOK+1)) fi fi ;; # NUMCOND esac N=$((N+1)) NAME=RIGHTTOLEFT case "$TESTS" in *%$N%*|*%functions%*|*%$NAME%*) TEST="$NAME: unidirectional throughput from stdin to stdout, right to left" testecho "$N" "$TEST" "stdout" "stdin" "$opts -U" esac N=$((N+1)) # I cannot remember the clou of this test, seems rather useless NAME=CHILDDEFAULT case "$TESTS" in *%$N%*|*%functions%*|*%$NAME%*) if ! eval $NUMCOND; then : elif ! F=$(testfeats STDIO EXEC); then $PRINTF "test $F_n $TEST... ${YELLOW}Feature $F not configured in $SOCAT${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif ! A=$(testaddrs STDIO EXEC); then $PRINTF "test $F_n $TEST... ${YELLOW}Address $A not available in $SOCAT${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" else TEST="$NAME: child process default properties" tf="$td/test$N.stdout" te="$td/test$N.stderr" CMD="$TRACE $SOCAT $opts -u EXEC:$PROCAN -" printf "test $F_n $TEST... " $N $CMD >$tf 2>$te MYPID=`expr "\`grep "process id =" $tf\`" : '[^0-9]*\([0-9]*\).*'` MYPPID=`expr "\`grep "process parent id =" $tf\`" : '[^0-9]*\([0-9]*\).*'` MYPGID=`expr "\`grep "process group id =" $tf\`" : '[^0-9]*\([0-9]*\).*'` MYSID=`expr "\`grep "process session id =" $tf\`" : '[^0-9]*\([0-9]*\).*'` #echo "PID=$MYPID, PPID=$MYPPID, PGID=$MYPGID, SID=$MYSID" #if [ "$MYPID" = "$MYPPID" -o "$MYPID" = "$MYPGID" -o "$MYPID" = "$MYSID" -o \ # "$MYPPID" = "$MYPGID" -o "$MYPPID" = "$MYSID" -o "$MYPGID" = "$MYSID" ]; if [ "$MYPID" = "$MYPPID" ]; then $PRINTF "$FAILED:\n" echo "$CMD" cat "$te" >&2 numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" else $PRINTF "$OK\n" if [ "$VERBOSE" ]; then echo "$CMD"; fi if [ "$DEBUG" ]; then cat "${te}" >&2; fi numOK=$((numOK+1)) fi fi ;; # NUMCOND esac N=$((N+1)) NAME=CHILDSETSID case "$TESTS" in *%$N%*|*%functions%*|*%$NAME%*) TEST="$NAME: child process with setsid" if ! eval $NUMCOND; then :; else tf="$td/test$N.stdout" te="$td/test$N.stderr" CMD="$TRACE $SOCAT $opts -u exec:$PROCAN,setsid -" printf "test $F_n $TEST... " $N $CMD >$tf 2>$te MYPID=`grep "process id =" $tf |(expr "\`cat\`" : '[^0-9]*\([0-9]*\).*')` MYPPID=`grep "process parent id =" $tf |(expr "\`cat\`" : '[^0-9]*\([0-9]*\).*')` MYPGID=`grep "process group id =" $tf |(expr "\`cat\`" : '[^0-9]*\([0-9]*\).*')` MYSID=`grep "process session id =" $tf |(expr "\`cat\`" : '[^0-9]*\([0-9]*\).*')` #$ECHO "\nPID=$MYPID, PPID=$MYPPID, PGID=$MYPGID, SID=$MYSID" # PID, PGID, and SID must be the same if [ "$MYPID" = "$MYPPID" -o \ "$MYPID" != "$MYPGID" -o "$MYPID" != "$MYSID" ]; then $PRINTF "$FAILED\n" echo "$CMD" cat "$te" numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" else $PRINTF "$OK\n" numOK=$((numOK+1)) fi fi ;; # NUMCOND esac N=$((N+1)) NAME=MAINSETSID case "$TESTS" in *%$N%*|*%functions%*|*%$NAME%*) TEST="$NAME: main process with setsid" if ! eval $NUMCOND; then :; else tf="$td/test$N.stdout" te="$td/test$N.stderr" CMD="$TRACE $SOCAT $opts -U -,setsid exec:$PROCAN" printf "test $F_n $TEST... " $N $CMD >$tf 2>$te MYPID=`grep "process id =" $tf |(expr "\`cat\`" : '[^0-9]*\([0-9]*\).*')` MYPPID=`grep "process parent id =" $tf |(expr "\`cat\`" : '[^0-9]*\([0-9]*\).*')` MYPGID=`grep "process group id =" $tf |(expr "\`cat\`" : '[^0-9]*\([0-9]*\).*')` MYSID=`grep "process session id =" $tf |(expr "\`cat\`" : '[^0-9]*\([0-9]*\).*')` #$ECHO "\nPID=$MYPID, PPID=$MYPPID, PGID=$MYPGID, SID=$MYSID" # PPID, PGID, and SID must be the same if [ "$MYPID" = "$MYPPID" -o \ "$MYPPID" != "$MYPGID" -o "$MYPPID" != "$MYSID" ]; then $PRINTF "$FAILED\n" echo "$CMD" cat "$te" numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" else $PRINTF "$OK\n" numOK=$((numOK+1)) fi fi ;; # NUMCOND esac N=$((N+1)) NAME=OPENSSL_TCP4 case "$TESTS" in *%$N%*|*%functions%*|*%openssl%*|*%tcp%*|*%tcp4%*|*%ip4%*|*%$NAME%*) TEST="$NAME: openssl connect" if ! eval $NUMCOND; then :; elif ! testfeats openssl >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}OPENSSL not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif ! type openssl >/dev/null 2>&1; then $PRINTF "test $F_n $TEST... ${YELLOW}openssl executable not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif ! testfeats tcp ip4 >/dev/null || ! runsip4 >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}TCP/IPv4 not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" else gentestcert testsrv tf="$td/test$N.stdout" te="$td/test$N.stderr" tdiff="$td/test$N.diff" da="test$N $(date) $RANDOM" newport tcp4 # provide free port number in $PORT init_openssl_s_server CMD2="$TRACE $SOCAT $opts exec:'openssl s_server $OPENSSL_S_SERVER_4 -accept "$PORT" -quiet -cert testsrv.pem' pipe" CMD="$TRACE $SOCAT $opts - openssl:$LOCALHOST:$PORT,pf=ip4,verify=0,$SOCAT_EGD" printf "test $F_n $TEST... " $N eval "$CMD2 2>\"${te}1\" &" pid=$! # background process id # this might timeout when openssl opens tcp46 port like " :::$PORT" waittcp4port $PORT #echo "$da" |$CMD >$tf 2>"${te}2" #note: with about OpenSSL 1.1 s_server lost the half close feature, thus: (echo "$da"; psleep 0.1) |$CMD >$tf 2>"${te}2" if ! echo "$da" |diff - "$tf" >"$tdiff"; then $PRINTF "$FAILED: $TRACE $SOCAT:\n" echo "$CMD2 &" echo "$CMD" cat "${te}1" cat "${te}2" cat "$tdiff" numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" else $PRINTF "$OK\n" if [ -n "$debug" ]; then cat "${te}1" "${te}2"; fi numOK=$((numOK+1)) fi kill $pid 2>/dev/null; wait fi ;; # NUMCOND, feats esac N=$((N+1)) NAME=OPENSSLLISTEN_TCP4 case "$TESTS" in *%$N%*|*%functions%*|*%openssl%*|*%tcp%*|*%tcp4%*|*%ip4%*|*%listen%*|*%$NAME%*) TEST="$NAME: openssl listen" if ! eval $NUMCOND; then :; elif ! testfeats openssl >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}OPENSSL not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif ! testfeats listen tcp ip4 >/dev/null || ! runsip4 >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}TCP/IPv4 not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" else gentestcert testsrv tf="$td/test$N.stdout" te="$td/test$N.stderr" tdiff="$td/test$N.diff" da="test$N $(date) $RANDOM" newport tcp4 # provide free port number in $PORT CMD2="$TRACE $SOCAT $opts OPENSSL-LISTEN:$PORT,pf=ip4,$REUSEADDR,$SOCAT_EGD,cert=testsrv.crt,key=testsrv.key,verify=0 pipe" CMD="$TRACE $SOCAT $opts - OPENSSL:$LOCALHOST:$PORT,pf=ip4,verify=0,$SOCAT_EGD" printf "test $F_n $TEST... " $N eval "$CMD2 2>\"${te}1\" &" pid=$! # background process id waittcp4port $PORT echo "$da" |$CMD >$tf 2>"${te}2" if ! echo "$da" |diff - "$tf" >"$tdiff"; then $PRINTF "$FAILED: $TRACE $SOCAT:\n" echo "$CMD2 &" echo "$CMD" cat "${te}1" cat "${te}2" cat "$tdiff" numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" else $PRINTF "$OK\n" if [ -n "$debug" ]; then cat "${te}1" "${te}2"; fi numOK=$((numOK+1)) fi kill $pid 2>/dev/null wait fi ;; # NUMCOND, feats esac N=$((N+1)) NAME=OPENSSLLISTEN_TCP6 case "$TESTS" in *%$N%*|*%functions%*|*%openssl%*|*%tcp%*|*%tcp6%*|*%ip6%*|*%listen%*|*%$NAME%*) TEST="$NAME: openssl listen" if ! eval $NUMCOND; then :; elif ! testfeats openssl >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}OPENSSL not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif ! testfeats listen tcp ip6 >/dev/null || ! runsip6 >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}TCP/IPv6 not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" else gentestcert testsrv tf="$td/test$N.stdout" te="$td/test$N.stderr" tdiff="$td/test$N.diff" da="test$N $(date) $RANDOM" newport tcp6 # provide free port number in $PORT CMD2="$TRACE $SOCAT $opts OPENSSL-LISTEN:$PORT,pf=ip6,$REUSEADDR,$SOCAT_EGD,cert=testsrv.crt,key=testsrv.key,verify=0 pipe" CMD="$TRACE $SOCAT $opts - OPENSSL:$LOCALHOST6:$PORT,verify=0,$SOCAT_EGD" printf "test $F_n $TEST... " $N eval "$CMD2 2>\"${te}1\" &" pid=$! # background process id waittcp6port $PORT echo "$da" |$CMD >$tf 2>"${te}2" if ! echo "$da" |diff - "$tf" >"$tdiff"; then $PRINTF "$FAILED: $TRACE $SOCAT:\n" echo "$CMD2 &" echo "$CMD" cat "${te}1" cat "${te}2" cat "$tdiff" numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" else $PRINTF "$OK\n" if [ -n "$debug" ]; then cat "${te}1" "${te}2"; fi numOK=$((numOK+1)) fi kill $pid 2>/dev/null wait fi ;; # NUMCOND, feats esac N=$((N+1)) newport $RUNS # in case it has not yet been invoked while read NAMEKEYW FEAT RUNS TESTTMPL PEERTMPL WAITTMPL; do if [ -z "$NAMEKEYW" ] || [[ "$NAMEKEYW" == \#* ]]; then continue; fi export ts="$td/test$N.socket" case $RUNS in tcp4|tcp6) newport $RUNS;; esac WAITTMPL="$(echo "$WAITTMPL" |sed -e 's/\040/ /g')" TESTADDR=$(eval echo $TESTTMPL) PEERADDR=$(eval echo $PEERTMPL) WAITCMD=$(eval echo $WAITTMPL) TESTKEYW=${TESTADDR%%:*} feat=$(tolower $FEAT) # does our address implementation support halfclose? NAME=${NAMEKEYW}_HALFCLOSE case "$TESTS" in *%$N%*|*%functions%*|*%$feat%*|*%socket%*|*%halfclose%*|*%listen%*|*%$NAME%*) TEST="$NAME: $TESTKEYW half close" # have a "peer" socat "peer" that executes "$OD_C" and see if EOF on the # connecting socat brings the result of od if ! eval $NUMCOND; then :; elif [ "$FEAT" != ',' ] && ! testfeats "$FEAT" >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}Feature $FEAT not configured${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif ! runs$RUNS >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}$RUNS not available$ on host${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" else tf="$td/test$N.stdout" te="$td/test$N.stderr" tdiff="$td/test$N.diff" da="test$N $(date) $RANDOM" case $RUNS in tcp4|tcp6) newport $RUNS;; esac CMD2="$TRACE $SOCAT $opts \"$PEERADDR\" EXEC:'$OD_C'" CMD="$TRACE $SOCAT -T1 $opts -t 1 - $TESTADDR" printf "test $F_n $TEST... " $N eval "$CMD2 2>\"${te}2\" &" pid2=$! # background process id $WAITCMD echo "$da" |$CMD >$tf 2>"${te}" kill $pid2 2>/dev/null wait if ! echo "$da" |$OD_C |diff - "$tf" >"$tdiff"; then $PRINTF "$FAILED: $TRACE $SOCAT:\n" echo "$CMD2 &" cat "${te}2" echo "$CMD" cat "${te}" cat "$tdiff" numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" else $PRINTF "$OK\n" if [ "$VERBOSE" ]; then echo " $CMD2 &" echo " $CMD" fi if [ -n "$debug" ]; then cat "${te}2" "${te}"; fi numOK=$((numOK+1)) fi wait fi ;; # NUMCOND, feats esac N=$((N+1)) done <<<" UNIXCONNECT , unix UNIX-CONNECT:\$ts UNIX-LISTEN:\$ts waitfile\040\$ts UNIXCLIENT , unix UNIX-CLIENT:\$ts UNIX-LISTEN:\$ts waitfile\040\$ts GOPEN_UNIXSTREAM , unix GOPEN:\$ts UNIX-LISTEN:\$ts waitfile\040\$ts UNIXLISTEN , unix UNIX-LISTEN:\$ts UNIX-CONNECT:\$ts,retry=3 sleep\040\1 TCP4CONNECT , tcp4 TCP4-CONNECT:\$LOCALHOST:\$PORT TCP4-LISTEN:\$PORT,$REUSEADDR waittcp4port\040\$PORT TCP4LISTEN , tcp4 TCP4-LISTEN:\$PORT,$REUSEADDR TCP4-CONNECT:\$LOCALHOST:\$PORT,retry=3 TCP6CONNECT , tcp6 TCP6-CONNECT:\$LOCALHOST6:\$PORT TCP6-LISTEN:\$PORT,$REUSEADDR waittcp6port\040\$PORT TCP6LISTEN , tcp6 TCP6-LISTEN:\$PORT,$REUSEADDR TCP6-CONNECT:\$LOCALHOST6:\$PORT,retry=3 OPENSSL4CLIENT OPENSSL tcp4 OPENSSL:\$LOCALHOST:\$PORT,pf=ip4,verify=0 OPENSSL-LISTEN:\$PORT,pf=ip4,$REUSEADDR,$SOCAT_EGD,cert=testsrv.crt,key=testsrv.key,verify=0 waittcp4port\040\$PORT OPENSSL4SERVER OPENSSL tcp4 OPENSSL-LISTEN:\$PORT,pf=ip4,$SOCAT_EGD,cert=testsrv.crt,key=testsrv.key,verify=0 OPENSSL:\$LOCALHOST:\$PORT,pf=ip4,$REUSEADDR,verify=0,retry=3 OPENSSL6CLIENT OPENSSL tcp6 OPENSSL:\$LOCALHOST6:\$PORT,pf=ip6,verify=0 OPENSSL-LISTEN:\$PORT,pf=ip6,$REUSEADDR,$SOCAT_EGD,cert=testsrv.crt,key=testsrv.key,verify=0 waittcp6port\040\$PORT OPENSSL6SERVER OPENSSL tcp6 OPENSSL-LISTEN:\$PORT,pf=ip6,$SOCAT_EGD,cert=testsrv.crt,key=testsrv.key,verify=0 OPENSSL:\$LOCALHOST6:\$PORT,pf=ip6,$REUSEADDR,verify=0,retry=3 " NAME=OPENSSL_SERVERAUTH case "$TESTS" in *%$N%*|*%functions%*|*%openssl%*|*%tcp%*|*%tcp4%*|*%ip4%*|*%listen%*|*%$NAME%*) TEST="$NAME: OpenSSL server authentication (hostname)" if ! eval $NUMCOND; then :; elif ! testfeats openssl >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}OPENSSL not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif ! testfeats listen tcp ip4 >/dev/null || ! runsip4 >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}TCP/IPv4 not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" else gentestcert testsrv gentestcert testcli tf="$td/test$N.stdout" te="$td/test$N.stderr" tdiff="$td/test$N.diff" da="test$N $(date) $RANDOM" newport tcp4 # provide free port number in $PORT CMD0="$TRACE $SOCAT $opts OPENSSL-LISTEN:$PORT,pf=ip4,$REUSEADDR,$SOCAT_EGD,cert=testsrv.crt,key=testsrv.key,verify=0 pipe" CMD1="$TRACE $SOCAT $opts - OPENSSL:$LOCALHOST:$PORT,pf=ip4,verify=1,cafile=testsrv.crt,$SOCAT_EGD" printf "test $F_n $TEST... " $N eval "$CMD0 2>\"${te}0\" &" pid=$! # background process id waittcp4port $PORT echo "$da" |$CMD1 >$tf 2>"${te}1" if ! echo "$da" |diff - "$tf" >"$tdiff"; then $PRINTF "$FAILED: $TRACE $SOCAT:\n" echo "$CMD0 &" cat "${te}0" echo "$CMD1" cat "${te}1" cat "$tdiff" numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" else $PRINTF "$OK\n" if [ -n "$debug" ]; then cat "${te}1" "${te}2"; fi numOK=$((numOK+1)) fi kill $pid 2>/dev/null wait fi ;; # NUMCOND, feats esac N=$((N+1)) NAME=OPENSSL_CLIENTAUTH case "$TESTS" in *%$N%*|*%functions%*|*%openssl%*|*%tcp%*|*%tcp4%*|*%ip4%*|*%listen%*|*%$NAME%*) TEST="$NAME: openssl client authentication" if ! eval $NUMCOND; then :; elif ! testfeats openssl >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}OPENSSL not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif ! testfeats listen tcp ip4 >/dev/null || ! runsip4 >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}TCP/IPv4 not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" else gentestcert testsrv gentestcert testcli tf="$td/test$N.stdout" te="$td/test$N.stderr" tdiff="$td/test$N.diff" da="test$N $(date) $RANDOM" newport tcp4 # provide free port number in $PORT CMD2="$TRACE $SOCAT $opts OPENSSL-LISTEN:$PORT,pf=ip4,$REUSEADDR,verify=1,cert=testsrv.crt,key=testsrv.key,cafile=testcli.crt,$SOCAT_EGD PIPE" CMD="$TRACE $SOCAT $opts - OPENSSL:$LOCALHOST:$PORT,pf=ip4,verify=0,cert=testcli.crt,key=testcli.key,$SOCAT_EGD" printf "test $F_n $TEST... " $N eval "$CMD2 2>\"${te}1\" &" pid=$! # background process id waittcp4port $PORT echo "$da" |$CMD >$tf 2>"${te}2" if ! echo "$da" |diff - "$tf" >"$tdiff"; then $PRINTF "$FAILED: $TRACE $SOCAT:\n" echo "$CMD2 &" echo "$CMD" cat "${te}1" cat "${te}2" cat "$tdiff" numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" else $PRINTF "$OK\n" if [ -n "$debug" ]; then cat "${te}1" "${te}2"; fi numOK=$((numOK+1)) fi kill $pid 2>/dev/null wait fi ;; # NUMCOND, feats esac N=$((N+1)) NAME=OPENSSL_FIPS_BOTHAUTH case "$TESTS" in *%$N%*|*%functions%*|*%openssl%*|*%fips%*|*%tcp%*|*%tcp4%*|*%ip4%*|*%listen%*|*%$NAME%*) TEST="$NAME: OpenSSL+FIPS client and server authentication" if ! eval $NUMCOND; then :; elif ! testfeats openssl >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}OPENSSL not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif ! testfeats listen tcp ip4 >/dev/null || ! runsip4 >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}TCP/IPv4 not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif ! testoptions fips >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}OPENSSL/FIPS not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" else OPENSSL_FIPS=1 gentestcert testsrvfips OPENSSL_FIPS=1 gentestcert testclifips tf="$td/test$N.stdout" te="$td/test$N.stderr" tdiff="$td/test$N.diff" da="test$N $(date) $RANDOM" newport tcp4 # provide free port number in $PORT CMD2="$TRACE $SOCAT $opts OPENSSL-LISTEN:$PORT,$REUSEADDR,fips,$SOCAT_EGD,cert=testsrvfips.crt,key=testsrvfips.key,cafile=testclifips.crt pipe" CMD="$TRACE $SOCAT $opts - OPENSSL:$LOCALHOST:$PORT,fips,verify=1,cert=testclifips.crt,key=testclifips.key,cafile=testsrvfips.crt,$SOCAT_EGD" printf "test $F_n $TEST... " $N eval "$CMD2 2>\"${te}1\" &" pid=$! # background process id waittcp4port $PORT echo "$da" |$CMD >$tf 2>"${te}2" if ! echo "$da" |diff - "$tf" >"$tdiff"; then $PRINTF "$FAILED: $TRACE $SOCAT:\n" echo "$CMD2 &" echo "$CMD" cat "${te}1" cat "${te}2" cat "$tdiff" numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" else $PRINTF "$OK\n" if [ -n "$debug" ]; then cat "${te}1" "${te}2"; fi numOK=$((numOK+1)) fi kill $pid 2>/dev/null wait fi ;; # NUMCOND, feats esac N=$((N+1)) NAME=OPENSSL_COMPRESS case "$TESTS" in *%$N%*|*%functions%*|*%openssl%*|*%tcp%*|*%tcp4%*|*%ip4%*|*%listen%*|*%$NAME%*) TEST="$NAME: OpenSSL compression" if ! eval $NUMCOND; then :; elif ! testfeats openssl >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}OPENSSL not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif ! testfeats listen tcp ip4 >/dev/null || ! runsip4 >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}TCP/IPv4 not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif ! testoptions openssl-compress >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}OPENSSL compression option not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" else gentestcert testsrv printf "test $F_n $TEST... " $N tf="$td/test$N.stdout" te="$td/test$N.stderr" tdiff="$td/test$N.diff" da="test$N $(date) $RANDOM" success=yes for srccompr in '' compress=auto compress=none; do for dstcompr in '' compress=auto compress=none; do newport tcp4 # provide free port number in $PORT CMD2="$TRACE $SOCAT $opts OPENSSL-LISTEN:$PORT,pf=ip4,$REUSEADDR,$SOCAT_EGD,cert=testsrv.crt,key=testsrv.key,verify=0,$dstcompr PIPE" CMD="$TRACE $SOCAT $opts - OPENSSL:$LOCALHOST:$PORT,pf=ip4,verify=0,$SOCAT_EGD,$srccompr" eval "$CMD2 2>\"${te}1\" &" pid=$! # background process id waittcp4port $PORT echo "$da" | $CMD >$tf 2>"${te}2" kill $pid 2>/dev/null if ! echo "$da" |diff - "$tf" >"$tdiff"; then success= break fi done done if test -z "$success"; then $PRINTF "$FAILED: $TRACE $SOCAT:\n" echo "$CMD2 &" echo "$CMD" cat "${te}1" cat "${te}2" cat "$tdiff" numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" else $PRINTF "$OK\n" if [ -n "$debug" ]; then cat "${te}1" "${te}2"; fi numOK=$((numOK+1)) fi fi ;; # NUMCOND, feats esac N=$((N+1)) NAME=SOCKS4CONNECT_TCP4 case "$TESTS" in *%$N%*|*%functions%*|*%socks%*|*%socks4%*|*%tcp%*|*%tcp4%*|*%ip4%*|*%listen%*|*%$NAME%*) TEST="$NAME: socks4 connect over TCP/IPv4" if ! eval $NUMCOND; then :; elif ! testfeats socks4 >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}SOCKS4 not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif ! testfeats listen tcp ip4 >/dev/null || ! runsip4 >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}TCP/IPv4 not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" else tf="$td/test$N.stdout" te="$td/test$N.stderr" tdiff="$td/test$N.diff" da="test$N $(date) $RANDOM"; da="$da$($ECHO '\r')" # we have a normal tcp echo listening - so the socks header must appear in answer newport tcp4 # provide free port number in $PORT CMD2="$TRACE $SOCAT $opts TCP4-L:$PORT,$REUSEADDR EXEC:\"./socks4echo.sh\"" CMD="$TRACE $SOCAT $opts - SOCKS4:$LOCALHOST:32.98.76.54:32109,pf=ip4,socksport=$PORT",socksuser="nobody" printf "test $F_n $TEST... " $N eval "$CMD2 2>\"${te}1\" &" pid=$! # background process id waittcp4port $PORT 1 echo "$da" |$CMD >$tf 2>"${te}2" if ! echo "$da" |diff - "$tf" >"$tdiff"; then $PRINTF "$FAILED: $TRACE $SOCAT:\n" echo "$CMD2 &" echo "$CMD" cat "${te}1" cat "${te}2" cat "$tdiff" numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" else $PRINTF "$OK\n" if [ -n "$debug" ]; then cat "${te}1" "${te}2"; fi numOK=$((numOK+1)) fi kill $pid 2>/dev/null wait fi ;; # NUMCOND, feats esac N=$((N+1)) NAME=SOCKS4CONNECT_TCP6 case "$TESTS" in *%$N%*|*%functions%*|*%socks%*|*%socks4%*|*%tcp%*|*%tcp6%*|*%ip6%*|*%listen%*|*%$NAME%*) TEST="$NAME: socks4 connect over TCP/IPv6" if ! eval $NUMCOND; then :; elif ! testfeats socks4 >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}SOCKS4 not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif ! testfeats listen tcp ip6 >/dev/null || ! runsip6 >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}TCP/IPv6 not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" else tf="$td/test$N.stdout" te="$td/test$N.stderr" tdiff="$td/test$N.diff" da="test$N $(date) $RANDOM"; da="$da$($ECHO '\r')" # we have a normal tcp echo listening - so the socks header must appear in answer newport tcp6 # provide free port number in $PORT CMD0="$TRACE $SOCAT $opts TCP6-L:$PORT,$REUSEADDR exec:\"./socks4echo.sh\"" CMD1="$TRACE $SOCAT $opts - socks4:$LOCALHOST6:32.98.76.54:32109,socksport=$PORT",socksuser="nobody" printf "test $F_n $TEST... " $N eval "$CMD0 2>\"${te}0\" &" pid=$! # background process id waittcp6port $PORT 1 echo "$da" |$CMD1 >${tf}1 2>"${te}1" if ! echo "$da" |diff - "${tf}1" >"$tdiff"; then $PRINTF "$FAILED: $TRACE $SOCAT:\n" echo "$CMD0 &" cat "${te}0" >&2 echo "$CMD1" cat "${te}1" >&2 echo "// diff:" >&2 cat "$tdiff" >&2 numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" else $PRINTF "$OK\n" if [ "$VERBOSE" ]; then echo "$CMD0 &"; fi if [ "$DEBUG" ]; then cat "${te}0" >&2; fi if [ "$VERBOSE" ]; then echo "$CMD1"; fi if [ "$DEBUG" ]; then cat "${te}1" >&2; fi numOK=$((numOK+1)) fi kill $pid 2>/dev/null wait fi ;; # NUMCOND, feats esac N=$((N+1)) NAME=SOCKS4ACONNECT_TCP4 case "$TESTS" in *%$N%*|*%functions%*|*%socks%*|*%socks4a%*|*%tcp%*|*%tcp4%*|*%ip4%*|*%listen%*|*%$NAME%*) TEST="$NAME: socks4a connect over TCP/IPv4" if ! eval $NUMCOND; then :; elif ! testfeats socks4a >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}SOCKS4A not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif ! testfeats listen tcp ip4 >/dev/null || ! runsip4 >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}TCP/IPv4 not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" else tf="$td/test$N.stdout" te="$td/test$N.stderr" tdiff="$td/test$N.diff" da="test$N $(date) $RANDOM"; da="$da$($ECHO '\r')" # we have a normal tcp echo listening - so the socks header must appear in answer newport tcp4 # provide free port number in $PORT CMD2="$TRACE $SOCAT $opts TCP4-L:$PORT,$REUSEADDR EXEC:\"./socks4a-echo.sh\"" CMD="$TRACE $SOCAT $opts - SOCKS4A:$LOCALHOST:localhost:32109,pf=ip4,socksport=$PORT",socksuser="nobody" printf "test $F_n $TEST... " $N eval "$CMD2 2>\"${te}1\" &" pid=$! # background process id waittcp4port $PORT 1 echo "$da" |$CMD >$tf 2>"${te}2" if ! echo "$da" |diff - "$tf" >"$tdiff"; then $PRINTF "$FAILED: $TRACE $SOCAT:\n" echo "$CMD2 &" echo "$CMD" cat "${te}1" cat "${te}2" cat "$tdiff" numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" else $PRINTF "$OK\n" if [ -n "$debug" ]; then cat "${te}1" "${te}2"; fi numOK=$((numOK+1)) fi kill $pid 2>/dev/null wait fi ;; # NUMCOND, feats esac N=$((N+1)) NAME=SOCKS4ACONNECT_TCP6 case "$TESTS" in *%$N%*|*%functions%*|*%socks%*|*%socks4a%*|*%tcp%*|*%tcp6%*|*%ip6%*|*%listen%*|*%$NAME%*) TEST="$NAME: socks4a connect over TCP/IPv6" if ! eval $NUMCOND; then :; elif ! testfeats socks4a >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}SOCKS4A not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif ! testfeats listen tcp ip6 >/dev/null || ! runsip6 >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}TCP/IPv6 not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" else tf="$td/test$N.stdout" te="$td/test$N.stderr" tdiff="$td/test$N.diff" da="test$N $(date) $RANDOM"; da="$da$($ECHO '\r')" # we have a normal tcp echo listening - so the socks header must appear in answer newport tcp6 # provide free port number in $PORT CMD2="$TRACE $SOCAT $opts TCP6-L:$PORT,$REUSEADDR EXEC:\"./socks4a-echo.sh\"" CMD="$TRACE $SOCAT $opts - SOCKS4A:$LOCALHOST6:localhost:32109,socksport=$PORT",socksuser="nobody" printf "test $F_n $TEST... " $N eval "$CMD2 2>\"${te}1\" &" pid=$! # background process id waittcp6port $PORT 1 echo "$da" |$CMD >$tf 2>"${te}2" if ! echo "$da" |diff - "$tf" >"$tdiff"; then $PRINTF "$FAILED: $TRACE $SOCAT:\n" echo "$CMD2 &" echo "$CMD" cat "${te}1" cat "${te}2" cat "$tdiff" numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" else $PRINTF "$OK\n" if [ -n "$debug" ]; then cat "${te}1" "${te}2"; fi numOK=$((numOK+1)) fi kill $pid 2>/dev/null wait fi ;; # NUMCOND, feats esac N=$((N+1)) NAME=PROXYCONNECT_TCP4 case "$TESTS" in *%$N%*|*%functions%*|*%proxyconnect%*|*%proxy%*|*%tcp%*|*%tcp4%*|*%ip4%*|*%listen%*|*%$NAME%*) TEST="$NAME: proxy connect over TCP/IPv4" if ! eval $NUMCOND; then :; elif ! testfeats proxy >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}PROXY not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif ! testfeats listen tcp ip4 >/dev/null || ! runsip4 >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}TCP/IPv4 not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" else ts="$td/test$N.sh" tf="$td/test$N.stdout" te="$td/test$N.stderr" tdiff="$td/test$N.diff" da="test$N $(date) $RANDOM"; da="$da$($ECHO '\r')" newport tcp4 # provide free port number in $PORT #CMD2="$TRACE $SOCAT tcp4-l:$PORT,crlf SYSTEM:\"read; read; $ECHO \\\"HTTP/1.0 200 OK\n\\\"; cat\"" CMD2="$TRACE $SOCAT $opts TCP4-L:$PORT,$REUSEADDR,crlf EXEC:\"/usr/bin/env bash proxyecho.sh\"" CMD="$TRACE $SOCAT $opts - PROXY:$LOCALHOST:127.0.0.1:1000,pf=ip4,proxyport=$PORT" printf "test $F_n $TEST... " $N eval "$CMD2 2>\"${te}2\" &" pid=$! # background process id waittcp4port $PORT 1 echo "$da" |$CMD >"$tf" 2>"${te}1" if ! echo "$da" |diff - "$tf" >"$tdiff"; then $PRINTF "$FAILED: $TRACE $SOCAT:\n" echo "$CMD2 &" echo "$CMD" cat "${te}1" cat "${te}2" cat "$tdiff" numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" else $PRINTF "$OK\n" if [ -n "$debug" ]; then cat "${te}1" "${te}2"; fi numOK=$((numOK+1)) fi kill $pid 2>/dev/null wait fi ;; # NUMCOND, feats esac N=$((N+1)) NAME=PROXYCONNECT_TCP6 case "$TESTS" in *%$N%*|*%functions%*|*%proxyconnect%*|*%proxy%*|*%tcp%*|*%tcp6%*|*%ip6%*|*%listen%*|*%$NAME%*) TEST="$NAME: proxy connect over TCP/IPv6" if ! eval $NUMCOND; then :; elif ! testfeats proxy >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}PROXY not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif ! testfeats listen tcp ip6 >/dev/null || ! runsip6 >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}TCP/IPv6 not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" else ts="$td/test$N.sh" tf="$td/test$N.stdout" te="$td/test$N.stderr" tdiff="$td/test$N.diff" da="test$N $(date) $RANDOM"; da="$da$($ECHO '\r')" newport tcp6 # provide free port number in $PORT #CMD2="$TRACE $SOCAT $opts TCP6-L:$PORT,crlf SYSTEM:\"read; read; $ECHO \\\"HTTP/1.0 200 OK\n\\\"; cat\"" CMD2="$TRACE $SOCAT $opts TCP6-L:$PORT,$REUSEADDR,crlf EXEC:\"/usr/bin/env bash proxyecho.sh\"" CMD="$TRACE $SOCAT $opts - PROXY:$LOCALHOST6:127.0.0.1:1000,proxyport=$PORT" printf "test $F_n $TEST... " $N eval "$CMD2 2>\"${te}2\" &" pid=$! # background process id waittcp6port $PORT 1 echo "$da" |$CMD >"$tf" 2>"${te}1" if ! echo "$da" |diff - "$tf" >"$tdiff"; then $PRINTF "$FAILED: $TRACE $SOCAT:\n" echo "$CMD2 &" echo "$CMD" cat "${te}1" cat "${te}2" cat "$tdiff" numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" else $PRINTF "$OK\n" if [ -n "$debug" ]; then cat "${te}1" "${te}2"; fi numOK=$((numOK+1)) fi kill $pid 2>/dev/null wait fi ;; # NUMCOND, feats esac N=$((N+1)) NAME=TCP4NOFORK case "$TESTS" in *%$N%*|*%functions%*|*%ip%*|*%ip4%*|*%tcp%*|*%tcp4%*|*%exec%*|*%listen%*|*%$NAME%*) TEST="$NAME: echo via connection to TCP V4 socket with nofork'ed exec" if ! eval $NUMCOND; then :; else tf="$td/test$N.stdout" te="$td/test$N.stderr" tdiff="$td/test$N.diff" newport tcp4; tsl=$PORT ts="127.0.0.1:$tsl" da="test$N $(date) $RANDOM" CMD1="$TRACE $SOCAT $opts TCP4-LISTEN:$tsl,$REUSEADDR EXEC:$CAT,nofork" CMD2="$TRACE $SOCAT $opts STDIN!!STDOUT TCP4:$ts" printf "test $F_n $TEST... " $N #$CMD1 >"$tf" 2>"${te}1" & $CMD1 >/dev/null 2>"${te}1" & waittcp4port $tsl #usleep $MICROS echo "$da" |$CMD2 >"$tf" 2>>"${te}2" if [ $? -ne 0 ]; then $PRINTF "$FAILED: $TRACE $SOCAT:\n" echo "$CMD1 &" echo "$CMD2" cat "${te}1" cat "${te}2" numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" elif ! echo "$da" |diff - "$tf" >"$tdiff"; then $PRINTF "$FAILED\n" cat "$tdiff" numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" else $PRINTF "$OK\n" if [ -n "$debug" ]; then cat "${te}1" "${te}2"; fi numOK=$((numOK+1)) fi fi ;; # NUMCOND esac N=$((N+1)) NAME=EXECCATNOFORK case "$TESTS" in *%$N%*|*%functions%*|*%$NAME%*) TEST="$NAME: simple echo via exec of cat with nofork" testecho "$N" "$TEST" "" "EXEC:$CAT,nofork" "$opts" esac N=$((N+1)) NAME=SYSTEMCATNOFORK case "$TESTS" in *%$N%*|*%functions%*|*%$NAME%*) TEST="$NAME: simple echo via system() of cat with nofork" testecho "$N" "$TEST" "" "SYSTEM:$CAT,nofork" "$opts" esac N=$((N+1)) NAME=NOFORKSETSID case "$TESTS" in *%$N%*|*%functions%*|*%$NAME%*) TEST="$NAME: simple echo via exec() of cat with nofork and setsid" testecho "$N" "$TEST" "" "SYSTEM:$CAT,nofork,setsid" "$opts" esac N=$((N+1)) #============================================================================== #TEST="$NAME: echo via 'connection' to UDP V4 socket" #if ! eval $NUMCOND; then :; else #tf="$td/file$N" #tsl=65534 #ts="127.0.0.1:$tsl" #da="test$N $(date) $RANDOM" #$TRACE $SOCAT UDP-LISTEN:$tsl,$REUSEADDR PIPE & #sleep 2 #echo "$da" |$TRACE $SOCAT stdin!!stdout UDP:$ts >"$tf" #if [ $? -eq 0 ] && echo "$da" |diff "$tf" -; then # $ECHO "... test $N succeeded" # numOK=$((numOK+1)) #else # $ECHO "*** test $N $FAILED" # numFAIL=$((numFAIL+1)) # listFAIL="$listFAIL $N" #fi #fi ;; # NUMCOND #N=$((N+1)) #============================================================================== # TEST 4 - simple echo via new file #if ! eval $NUMCOND; then :; else #N=4 #tf="$td/file$N" #tp="$td/pipe$N" #da="test$N $(date) $RANDOM" #rm -f "$tf.tmp" #echo "$da" |$TRACE $SOCAT - FILE:$tf.tmp,ignoreeof >"$tf" #if [ $? -eq 0 ] && echo "$da" |diff "$tf" -; then # $ECHO "... test $N succeeded" # numOK=$((numOK+1)) #else # $ECHO "*** test $N $FAILED" # numFAIL=$((numFAIL+1)) # listFAIL="$listFAIL $N" #fi #fi ;; # NUMCOND #============================================================================== NAME=TOTALTIMEOUT case "$TESTS" in *%$N%*|*%functions%*|*%engine%*|*%timeout%*|*%listen%*|*%$NAME%*) TEST="$NAME: socat inactivity timeout" if ! eval $NUMCOND; then :; else #set -vx tf="$td/test$N.stdout" te="$td/test$N.stderr" tdiff="$td/test$N.diff" da="test$N $(date) $RANDOM"; da="$da$($ECHO '\r')" newport tcp4 # provide free port number in $PORT CMD2="$TRACE $SOCAT $opts -T 1 TCP4-LISTEN:$PORT,$REUSEADDR pipe" CMD="$TRACE $SOCAT $opts - TCP4-CONNECT:$LOCALHOST:$PORT" printf "test $F_n $TEST... " $N eval "$CMD2 2>${te}1 &" pid=$! # background process id waittcp4port $PORT 1 (echo "$da"; sleep 2; echo X) |$CMD >"$tf" 2>"${te}2" if ! echo "$da" |diff - "$tf" >"$tdiff"; then $PRINTF "$FAILED: $TRACE $SOCAT:\n" echo "$CMD2 &" echo "$CMD" cat "${te}1" cat "${te}2" cat "$tdiff" numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" else $PRINTF "$OK\n" if [ -n "$debug" ]; then cat "${te}1" "${te}2"; fi numOK=$((numOK+1)) fi kill $pid 2>/dev/null wait #set +vx fi ;; # NUMCOND esac N=$((N+1)) NAME=IGNOREEOF+TOTALTIMEOUT case "$TESTS" in *%$N%*|*%functions%*|*%engine%*|*%timeout%*|*%ignoreeof%*|*%$NAME%*) TEST="$NAME: ignoreeof and inactivity timeout" if ! eval $NUMCOND; then :; else #set -vx ti="$td/test$N.file" tf="$td/test$N.stdout" te="$td/test$N.stderr" tdiff="$td/test$N.diff" da="test$N $(date) $RANDOM" CMD="$TRACE $SOCAT $opts -T 2 -u file:\"$ti\",ignoreeof -" printf "test $F_n $TEST... " $N touch "$ti" $CMD >"$tf" 2>"$te" & bg=$! # background process id psleep 0.5 echo "$da" >>"$ti" sleep 4 echo X >>"$ti" sleep 1 kill $bg 2>/dev/null if ! echo "$da" |diff - "$tf" >"$tdiff"; then $PRINTF "$FAILED: $TRACE $SOCAT:\n" echo "$CMD &" cat "$te" cat "$tdiff" numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" else $PRINTF "$OK\n" if [ -n "$debug" ]; then cat "$te"; fi numOK=$((numOK+1)) fi wait fi ;; # NUMCOND, feats esac N=$((N+1)) NAME=PROXY2SPACES case "$TESTS" in *%$N%*|*%functions%*|*%proxy%*|*%listen%*|*%$NAME%*) TEST="$NAME: proxy connect accepts status with multiple spaces" if ! eval $NUMCOND; then :; elif ! testfeats proxy >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}PROXY not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" else ts="$td/test$N.sh" tf="$td/test$N.stdout" te="$td/test$N.stderr" tdiff="$td/test$N.diff" da="test$N $(date) $RANDOM"; da="$da$($ECHO '\r')" newport tcp4 # provide free port number in $PORT #CMD2="$TRACE $SOCAT $opts TCP-L:$PORT,crlf SYSTEM:\"read; read; $ECHO \\\"HTTP/1.0 200 OK\n\\\"; cat\"" CMD0="$TRACE $SOCAT $opts TCP4-L:$PORT,reuseaddr,crlf EXEC:\"/usr/bin/env bash proxyecho.sh -w 2\"" CMD1="$TRACE $SOCAT $opts - PROXY:$LOCALHOST:127.0.0.1:1000,pf=ip4,proxyport=$PORT" printf "test $F_n $TEST... " $N eval "$CMD0 2>\"${te}1\" &" pid=$! # background process id waittcp4port $PORT 1 echo "$da" |$CMD1 >"$tf" 2>"${te}0" if ! echo "$da" |diff - "$tf" >"$tdiff"; then $PRINTF "$FAILED: $TRACE $SOCAT:\n" echo "$CMD0 &" cat "${te}0" >&2 echo "$CMD1" cat "${te}1" >&2 echo "diff:" cat "$tdiff" numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" else $PRINTF "$OK\n" if [ "$VERBOSE" ]; then echo "$CMD0 &"; fi if [ "$debug" ]; then cat "${te}0" >&2; fi if [ "$VERBOSE" ]; then echo "$CMD1"; fi if [ "$debug" ]; then cat "${te}1" >&2; fi numOK=$((numOK+1)) fi kill $pid 2>/dev/null wait fi ;; # NUMCOND, feats esac N=$((N+1)) NAME=BUG-UNISTDIO case "$TESTS" in *%$N%*|*%functions%*|*%$NAME%*) TEST="$NAME: for bug with address options on both stdin/out in unidirectional mode" if ! eval $NUMCOND; then :; else tf="$td/test$N.stdout" te="$td/test$N.stderr" ff="$td/test$N.file" printf "test $F_n $TEST... " $N >"$ff" #$TRACE $SOCAT $opts -u /dev/null -,setlk <"$ff" 2>"$te" CMD="$TRACE $SOCAT $opts -u /dev/null -,setlk" $CMD <"$ff" 2>"$te" if [ "$?" -eq 0 ]; then $PRINTF "$OK\n" numOK=$((numOK+1)) else if [ "$UNAME" = "Linux" ]; then $PRINTF "$FAILED\n" echo "$CMD" cat "$te" numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" else $PRINTF "${YELLOW}failed (don't care)${NORMAL}\n" numCANT=$((numCANT+1)) listCANT="$listCANT $N" fi fi fi ;; # NUMCOND esac N=$((N+1)) NAME=SINGLEEXECOUTSOCKETPAIR case "$TESTS" in *%$N%*|*%functions%*|*%$NAME%*) TEST="$NAME: inheritance of stdout to single exec with socketpair" testecho "$N" "$TEST" "-!!exec:cat" "" "$opts" 1 esac N=$((N+1)) NAME=SINGLEEXECOUTPIPE case "$TESTS" in *%$N%*|*%functions%*|*%$NAME%*) TEST="$NAME: inheritance of stdout to single exec with pipe" testecho "$N" "$TEST" "-!!exec:cat,pipes" "" "$opts" 1 esac N=$((N+1)) NAME=SINGLEEXECOUTPTY case "$TESTS" in *%$N%*|*%functions%*|*%pty%*|*%$NAME%*) TEST="$NAME: inheritance of stdout to single exec with pty" if ! eval $NUMCOND; then :; elif ! testfeats pty >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}PTY not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" else testecho "$N" "$TEST" "-!!exec:cat,pty,raw" "" "$opts" 1 fi ;; # NUMCOND, feats esac N=$((N+1)) NAME=SINGLEEXECINSOCKETPAIR case "$TESTS" in *%$N%*|*%functions%*|*%$NAME%*) TEST="$NAME: inheritance of stdin to single exec with socketpair" testecho "$N" "$TEST" "exec:cat!!-" "" "$opts" esac N=$((N+1)) NAME=SINGLEEXECINPIPE case "$TESTS" in *%$N%*|*%functions%*|*%$NAME%*) TEST="$NAME: inheritance of stdin to single exec with pipe" testecho "$N" "$TEST" "exec:cat,pipes!!-" "" "$opts" esac N=$((N+1)) NAME=SINGLEEXECINPTYDELAY case "$TESTS" in *%$N%*|*%functions%*|*%pty%*|*%$NAME%*) TEST="$NAME: inheritance of stdin to single exec with pty, with delay" if ! eval $NUMCOND; then :; elif ! testfeats pty >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}PTY not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" else testecho "$N" "$TEST" "exec:cat,pty,raw!!-" "" "$opts" $MISCDELAY fi ;; # NUMCOND, feats esac N=$((N+1)) NAME=SINGLEEXECINPTY case "$TESTS" in *%$N%*|*%functions%*|*%pty%*|*%$NAME%*) TEST="$NAME: inheritance of stdin to single exec with pty" if ! eval $NUMCOND; then :; elif ! testfeats pty >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}PTY not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" else # T value needed (only) by AIX testecho "$N" "$TEST" "exec:cat,pty,raw!!-" "" "$opts" 0.1 fi ;; # NUMCOND, feats esac N=$((N+1)) NAME=READLINE #set -vx case "$TESTS" in *%$N%*|*%functions%*|*%pty%*|*%readline%*|*%sigint%*|*%$NAME%*) TEST="$NAME: readline with password and sigint" if ! eval $NUMCOND; then :; elif ! feat=$(testfeats readline pty); then $PRINTF "test $F_n $TEST... ${YELLOW}$(echo "$feat"| tr 'a-z' 'A-Z') not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" else SAVETERM="$TERM"; TERM= # 'cause console might print controls even in raw SAVEMICS=$MICROS #MICROS=2000000 ts="$td/test$N.sh" to="$td/test$N.stdout" tpi="$td/test$N.inpipe" tpo="$td/test$N.outpipe" te="$td/test$N.stderr" tr="$td/test$N.ref" tdiff="$td/test$N.diff" da="test$N $(date) $RANDOM"; da="$da$($ECHO '\r')" # the feature that we really want to test is in the readline.sh script: CMD="$TRACE $SOCAT -lpwrapper $opts -t1 open:$tpi,nonblock!!open:$tpo exec:\"./readline.sh -nh ./readline-test.sh\",pty,ctty,setsid,raw,echo=0,isig" #echo "$CMD" >"$ts" #chmod a+x "$ts" printf "test $F_n $TEST... " $N rm -f "$tpi" "$tpo" mkfifo "$tpi" touch "$tpo" # # during development of this test, the following command line succeeded: # ECHO="echo -e" SOCAT=./socat # (sleep 1; $ECHO "user\n\c"; sleep 1; $ECHO "password\c"; sleep 1; $ECHO "\n\c"; sleep 1; $ECHO "test 1\n\c"; sleep 1; $ECHO "\003\c"; sleep 1; $ECHO "test 2\n\c"; sleep 1; $ECHO "exit\n\c"; sleep 1) |$TRACE $SOCAT -d -d -d -d -lf/tmp/$USER/debug1 -v -x - exec:'./readline.sh ./readline-test.sh',pty,ctty,setsid,raw,echo=0,isig # # the following cat, in case of socat failure, reads the pipe to prevent below writer from hanging PATH=${SOCAT%socat}:$PATH eval "$CMD 2>$te || cat $tpi >/dev/null &" pid=$! # background process id usleep $MICROS ( usleep $((3*MICROS)) $ECHO "user\n\c" usleep $MICROS $ECHO "password\c" usleep $MICROS $ECHO "\n\c" usleep $MICROS $ECHO "test 1\n\c" usleep $MICROS $ECHO "\003\c" usleep $MICROS $ECHO "test 2\n\c" usleep $MICROS $ECHO "exit\n\c" usleep $MICROS ) >"$tpi" cat >$tr < test 1 executing test 1 prog> ./readline-test.sh got SIGINT test 2 executing test 2 prog> exit EOF #0 if ! sed 's/.*\r//g' "$tpo" |diff -q "$tr" - >/dev/null 2>&1; then #0 if ! sed 's/.*'"$($ECHO '\r\c')"'//dev/null 2>&1; then wait if ! tr "$($ECHO '\r \c')" "% " <$tpo |sed 's/%$//g' |sed 's/.*%//g' |diff "$tr" - >"$tdiff" 2>&1; then $PRINTF "$FAILED: $TRACE $SOCAT:\n" echo "$CMD" 2>&1 cat "$te" 2>&1 echo diff: 2>&1 cat "$tdiff" 2>&1 numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" else $PRINTF "$OK\n" if [ "$VERBOSE" ]; then echo "$CMD0 &"; fi if [ "$DEBUG" ]; then cat "${te}0" >&2; fi numOK=$((numOK+1)) fi kill $pid 2>/dev/null # necc on OpenBSD wait MICROS=$SAVEMICS TERM="$SAVETERM" fi ;; # NUMCOND, feats esac N=$((N+1)) NAME=GENDERCHANGER case "$TESTS" in *%$N%*|*%functions%*|*%listen%*|*%$NAME%*) TEST="$NAME: TCP4 \"gender changer\"" if ! eval $NUMCOND; then :; else tf="$td/test$N.stdout" te="$td/test$N.stderr" tdiff="$td/test$N.diff" da="test$N $(date) $RANDOM" newport tcp4; PORT1=$PORT newport tcp4; PORT2=$PORT newport tcp4; PORT3=$PORT # this is the server in the protected network that we want to reach CMD1="$TRACE $SOCAT -lpserver $opts TCP4-L:$PORT1,reuseaddr,bind=$LOCALHOST ECHO" # this is the double client in the protected network CMD2="$TRACE $SOCAT -lp2client $opts TCP4:$LOCALHOST:$PORT2,retry=10,interval=1 TCP4:$LOCALHOST:$PORT1" # this is the double server in the outside network CMD3="$TRACE $SOCAT -lp2server $opts TCP4-L:$PORT3,reuseaddr,bind=$LOCALHOST TCP4-L:$PORT2,reuseaddr,bind=$LOCALHOST" # this is the outside client that wants to use the protected server CMD4="$TRACE $SOCAT -lpclient $opts -t1 - tcp4:$LOCALHOST:$PORT3" printf "test $F_n $TEST... " $N eval "$CMD1 2>${te}1 &" pid1=$! eval "$CMD2 2>${te}2 &" pid2=$! eval "$CMD3 2>${te}3 &" pid3=$! waittcp4port $PORT1 1 && waittcp4port $PORT3 1 sleep 1 echo "$da" |$CMD4 >$tf 2>"${te}4" kill $pid1 $pid2 $pid3 $pid4 2>/dev/null wait if ! echo "$da" |diff - "$tf" >"$tdiff"; then $PRINTF "$FAILED: $TRACE $SOCAT:\n" echo "$CMD1 &" cat "${te}1" >&2 echo "$CMD2 &" cat "${te}2" >&2 echo "$CMD3 &" cat "${te}3" >&2 echo "$CMD4" cat "${te}4" >&2 echo diff: >&2 cat "$tdiff" numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" else $PRINTF "$OK\n" if [ "$VERBOSE" ]; then echo "$CMD1 &"; fi if [ "$DEBUG" ]; then cat "${te}1" >&2; fi if [ "$VERBOSE" ]; then echo "$CMD2 &"; fi if [ "$DEBUG" ]; then cat "${te}2" >&2; fi if [ "$VERBOSE" ]; then echo "$CMD3 &"; fi if [ "$DEBUG" ]; then cat "${te}3" >&2; fi if [ "$VERBOSE" ]; then echo "$CMD4"; fi if [ "$DEBUG" ]; then cat "${te}4" >&2; fi numOK=$((numOK+1)) fi fi ;; # NUMCOND esac N=$((N+1)) NAME=OUTBOUNDIN case "$TESTS" in *%$N%*|*%functions%*|*%openssl%*|*%proxy%*|*%fork%*|*%listen%*|*%$NAME%*) TEST="$NAME: gender changer via SSL through HTTP proxy, oneshot" if ! eval $NUMCOND; then :; elif ! feat=$(testfeats openssl proxy); then $PRINTF "test $F_n $TEST... ${YELLOW}$(echo "$feat" |tr 'a-z' 'A-Z') not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" else gentestcert testsrv gentestcert testcli tf="$td/test$N.stdout" te="$td/test$N.stderr" tdiff="$td/test$N.diff" da="test$N $(date) $RANDOM" newport tcp4; PORT1=$PORT newport tcp4; PORT2=$PORT newport tcp4; PORT3=$PORT newport tcp4; PORT4=$PORT newport tcp4; PORT5=$PORT # this is the server in the protected network that we want to reach CMD1="$TRACE $SOCAT $opts -lpserver TCP4-L:$PORT1,reuseaddr,bind=$LOCALHOST ECHO" # this is the proxy in the protected network that provides a way out CMD2="$TRACE $SOCAT $opts -lpproxy TCP4-L:$PORT2,reuseaddr,bind=$LOCALHOST,fork EXEC:./proxy.sh" # this is our proxy connect wrapper in the protected network CMD3="$TRACE $SOCAT $opts -lpwrapper TCP4-L:$PORT3,reuseaddr,bind=$LOCALHOST,fork PROXY:$LOCALHOST:$LOCALHOST:$PORT4,pf=ip4,proxyport=$PORT2,resolve" # this is our double client in the protected network using SSL #CMD4="$TRACE $SOCAT $opts -lp2client SSL:$LOCALHOST:$PORT3,pf=ip4,retry=10,interval=1,cert=testcli.pem,cafile=testsrv.crt,$SOCAT_EGD TCP4:$LOCALHOST:$PORT1" CMD4="$TRACE $SOCAT $opts -lp2client SSL:$LOCALHOST:$PORT3,pf=ip4,cert=testcli.pem,cafile=testsrv.crt,$SOCAT_EGD TCP4:$LOCALHOST:$PORT1" # this is the double server in the outside network CMD5="$TRACE $SOCAT $opts -lp2server -t1 tcp4-l:$PORT5,reuseaddr,bind=$LOCALHOST ssl-l:$PORT4,pf=ip4,reuseaddr,bind=$LOCALHOST,$SOCAT_EGD,cert=testsrv.pem,cafile=testcli.crt" # this is the outside client that wants to use the protected server CMD6="$TRACE $SOCAT $opts -lpclient -t5 - tcp4:$LOCALHOST:$PORT5" printf "test $F_n $TEST... " $N eval "$CMD1 2>${te}1 &" pid1=$! eval "$CMD2 2>${te}2 &" pid2=$! eval "$CMD3 2>${te}3 &" pid3=$! waittcp4port $PORT1 1 || $PRINTF "$FAILED: port $PORT1\n" >&2 &2 &2 ${te}5 &" pid5=$! waittcp4port $PORT5 1 || $PRINTF "$FAILED: port $PORT5\n" >&2 $tf 2>"${te}6" & pid6=$! waittcp4port $PORT4 1 || $PRINTF "$FAILED: port $PORT4\n" >&2 ${te}4 &" pid4=$! wait $pid6 if ! (echo "$da"; sleep 2) |diff - "$tf" >"$tdiff"; then $PRINTF "$FAILED: $TRACE $SOCAT:\n" echo "$CMD1 &" cat "${te}1" echo "$CMD2 &" cat "${te}2" echo "$CMD3 &" cat "${te}3" echo "$CMD5 &" cat "${te}5" echo "$CMD6" cat "${te}6" echo "$CMD4 &" cat "${te}4" cat "$tdiff" numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" else $PRINTF "$OK\n" if [ -n "$debug" ]; then cat "${te}1" "${te}2" "${te}3" "${te}4" "${te}5" "${te}6"; fi numOK=$((numOK+1)) fi kill $pid1 $pid2 $pid3 $pid4 $pid5 2>/dev/null wait fi ;; # NUMCOND, feats esac N=$((N+1)) # test the TCP gender changer with almost production requirements: a double # client repeatedly tries to connect to a double server via SSL through an HTTP # proxy. the double servers SSL port becomes active for one connection only # after a (real) client has connected to its TCP port. when the double client # succeeded to establish an SSL connection, it connects with its second client # side to the specified (protected) server. all three consecutive connections # must function for full success of this test. #PORT=$((RANDOM+16184)) #! NAME=INTRANETRIPPER case "$TESTS" in *%$N%*|*%functions%*|*%openssl%*|*%proxy%*|*%listen%*|*%fork%*|*%$NAME%*) TEST="$NAME: gender changer via SSL through HTTP proxy, daemons" if ! eval $NUMCOND; then :; elif ! feat=$(testfeats openssl proxy); then $PRINTF "test $F_n $TEST... ${YELLOW}$(echo "$feat"| tr 'a-z' 'A-Z') not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" else gentestcert testsrv gentestcert testcli tf="$td/test$N.stdout" te="$td/test$N.stderr" tdiff="$td/test$N.diff" da1="test$N.1 $(date) $RANDOM" da2="test$N.2 $(date) $RANDOM" da3="test$N.3 $(date) $RANDOM" newport tcp4; PORT1=$PORT newport tcp4; PORT2=$PORT newport tcp4; PORT3=$PORT newport tcp4; PORT4=$PORT newport tcp4; PORT5=$PORT # this is the server in the protected network that we want to reach CMD1="$TRACE $SOCAT $opts -lpserver -t1 tcp4-l:$PORT1,reuseaddr,bind=$LOCALHOST,fork echo" # this is the proxy in the protected network that provides a way out # note: the proxy.sh script starts one or two more socat processes without # setting the program name CMD2="$TRACE $SOCAT $opts -lpproxy -t1 tcp4-l:$PORT2,reuseaddr,bind=$LOCALHOST,fork exec:./proxy.sh" # this is our proxy connect wrapper in the protected network CMD3="$TRACE $SOCAT $opts -lpwrapper -t3 tcp4-l:$PORT3,reuseaddr,bind=$LOCALHOST,fork proxy:$LOCALHOST:$LOCALHOST:$PORT4,pf=ip4,proxyport=$PORT2,resolve" # this is our double client in the protected network using SSL CMD4="$TRACE $SOCAT $opts -lp2client -t3 ssl:$LOCALHOST:$PORT3,retry=10,interval=1,cert=testcli.pem,cafile=testsrv.crt,verify,fork,$SOCAT_EGD tcp4:$LOCALHOST:$PORT1,forever,interval=0.1" # this is the double server in the outside network CMD5="$TRACE $SOCAT $opts -lp2server -t4 tcp4-l:$PORT5,reuseaddr,bind=$LOCALHOST,backlog=3,fork ssl-l:$PORT4,pf=ip4,reuseaddr,bind=$LOCALHOST,$SOCAT_EGD,cert=testsrv.pem,cafile=testcli.crt,retry=20,interval=0.5" # this is the outside client that wants to use the protected server CMD6="$TRACE $SOCAT $opts -lpclient -t6 - tcp4:$LOCALHOST:$PORT5,retry=3" printf "test $F_n $TEST... " $N # start the intranet infrastructure eval "$CMD1 2>\"${te}1\" &" pid1=$! eval "$CMD2 2>\"${te}2\" &" pid2=$! waittcp4port $PORT1 1 || $PRINTF "$FAILED: port $PORT1\n" >&2 &2 \"${te}3\" &" pid3=$! eval "$CMD4 2>\"${te}4\" &" pid4=$! waittcp4port $PORT3 1 || $PRINTF "$FAILED: port $PORT3\n" >&2 \"${te}5\" &" pid5=$! waittcp4port $PORT5 1 || $PRINTF "$FAILED: port $5PORT\n" >&2 ${tf}_1 2>"${te}6_1" & pid6_1=$! echo "$da2" |$CMD6 >${tf}_2 2>"${te}6_2" & pid6_2=$! echo "$da3" |$CMD6 >${tf}_3 2>"${te}6_3" & pid6_3=$! wait $pid6_1 $pid6_2 $pid6_3 kill $pid1 $pid2 $pid3 $pid4 $pid5 2>/dev/null # (echo "$da1"; sleep 2) |diff - "${tf}_1" >"${tdiff}1" (echo "$da2"; sleep 2) |diff - "${tf}_2" >"${tdiff}2" (echo "$da3"; sleep 2) |diff - "${tf}_3" >"${tdiff}3" if test -s "${tdiff}1" -o -s "${tdiff}2" -o -s "${tdiff}3"; then # FAILED only when none of the three transfers succeeded if test -s "${tdiff}1" -a -s "${tdiff}2" -a -s "${tdiff}3"; then $PRINTF "$FAILED: $TRACE $SOCAT:\n" echo "$CMD1 &" cat "${te}1" echo "$CMD2 &" cat "${te}2" echo "$CMD3 &" cat "${te}3" echo "$CMD4 &" cat "${te}4" echo "$CMD5 &" cat "${te}5" echo "$CMD6 &" cat "${te}6_1" cat "${tdiff}1" echo "$CMD6 &" cat "${te}6_2" cat "${tdiff}2" echo "$CMD6 &" cat "${te}6_3" cat "${tdiff}3" numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" else $PRINTF "$OK ${YELLOW}(partial failure)${NORMAL}\n" if [ -n "$debug" ]; then cat "${te}1" "${te}2" "${te}3" "${te}4" "${te}5" ${te}6*; fi numOK=$((numOK+1)) fi else $PRINTF "$OK\n" if [ -n "$debug" ]; then cat "${te}1" "${te}2" "${te}3" "${te}4" "${te}5" ${te}6*; fi numOK=$((numOK+1)) fi kill $pid1 $pid2 $pid3 $pid4 $pid5 2>/dev/null wait fi ;; # NUMCOND, feats esac N=$((N+1)) # let us test the security features with -s, retry, and fork # method: first test without security feature if it works # then try with security feature, must fail # test the security features of a server address testserversec () { local N="$1" local title="$2" local opts="$3" local arg1="$4" # the server address local secopt0="$5" # option without security for server, mostly empty local secopt1="$6" # the security option for server, to be tested local arg2="$7" # the client address local ipvers="$8" # IP version, for check of listen port local proto="$9" # protocol, for check of listen port local port="${10}" # start client when this port is listening local expect="${11}" # expected behaviour of client: 0..empty output; -1..error; *: any of these local T="${12}"; [ -z "$T" ] && T=0 local tf="$td/test$N.stdout" local te="$td/test$N.stderr" local tdiff1="$td/test$N.diff1" local tdiff2="$td/test$N.diff2" local da="test$N.1 $(date) $RANDOM" local stat result $PRINTF "test $F_n %s... " $N "$title" # first: without security # start server $TRACE $SOCAT $opts "$arg1,$secopt0" echo 2>"${te}1" & spid=$! if [ "$port" ] && ! wait${proto}${ipvers}port $port 1; then kill $spid 2>/dev/null $PRINTF "$NO_RESULT (ph.1 server not working):\n" echo "$TRACE $SOCAT $opts \"$arg1,$secopt0\" echo &" cat "${te}1" numCANT=$((numCANT+1)) listCANT="$listCANT $N" wait; return fi # now use client (echo "$da"; sleep $T) |$TRACE $SOCAT $opts - "$arg2" >"$tf" 2>"${te}2" stat="$?" kill $spid 2>/dev/null #killall $TRACE $SOCAT 2>/dev/null if [ "$stat" != 0 ]; then $PRINTF "$NO_RESULT (ph.1 function fails): $TRACE $SOCAT:\n" echo "$TRACE $SOCAT $opts \"$arg1,$secopt0\" echo &" cat "${te}1" echo "$TRACE $SOCAT $opts - \"$arg2\"" cat "${te}2" numCANT=$((numCANT+1)) listCANT="$listCANT $N" wait; return elif echo "$da" |diff - "$tf" >"$tdiff1" 2>&1; then : # function without security is ok, go on else $PRINTF "$NO_RESULT (ph.1 function fails): diff:\n" echo "$TRACE $SOCAT $opts $arg1,$secopt0 echo &" cat "${te}1" echo "$TRACE $SOCAT $opts - $arg2" cat "${te}2" cat "$tdiff1" numCANT=$((numCANT+1)) listCANT="$listCANT $N" wait; return fi # then: with security if [ "$port" ] && ! wait${proto}${ipvers}port $port 0; then $PRINTF "$NO_RESULT (ph.1 port remains in use)\n" numCANT=$((numCANT+1)) listCANT="$listCANT $N" wait; return fi wait #set -vx # assemble address w/ security option; on dual, take read part: case "$arg1" in *!!*) arg="${arg1%!!*},$secopt1!!${arg1#*!!}" ;; *) arg="$arg1,$secopt1" ;; esac # start server # use -s to make sure that it fails due to a sec violation, not some other failure CMD3="$TRACE $SOCAT $opts -s $arg echo" $CMD3 2>"${te}3" & spid=$! if [ "$port" ] && ! wait${proto}${ipvers}port $port 1; then kill $spid 2>/dev/null $PRINTF "$NO_RESULT (ph.2 server not working)\n" wait echo "$CMD3" cat "${te}3" numCANT=$((numCANT+1)) listCANT="$listCANT $N" return fi # now use client da="test$N.2 $(date) $RANDOM" (echo "$da"; sleep $T) |$TRACE $SOCAT $opts - "$arg2" >"$tf" 2>"${te}4" stat=$? kill $spid 2>/dev/null #set +vx #killall $TRACE $SOCAT 2>/dev/null if [ "$stat" != 0 ]; then result=-1; # socat had error elif [ ! -s "$tf" ]; then result=0; # empty output elif echo "$da" |diff - "$tf" >"$tdiff2" 2>&1; then result=1; # output is copy of input else result=2; # output differs from input fi if [ "$expect" != '1' -a "$result" -eq 1 ]; then $PRINTF "$FAILED: SECURITY BROKEN\n" echo "$TRACE $SOCAT $opts $arg echo" cat "${te}3" echo "$TRACE $SOCAT $opts - $arg2" cat "${te}4" cat "$tdiff2" numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" elif [ "X$expect" != 'X*' -a X$result != X$expect ]; then case X$result in X-1) $PRINTF "$NO_RESULT (ph.2 client error): $TRACE $SOCAT:\n" echo "$TRACE $SOCAT $opts $arg echo" cat "${te}3" echo "$TRACE $SOCAT $opts - $arg2" cat "${te}4" numCANT=$((numCANT+1)) listCANT="$listCANT $N" ;; X0) $PRINTF "$NO_RESULT (ph.2 diff failed): diff:\n" echo "$TRACE $SOCAT $opts $arg echo" cat "${te}3" echo "$TRACE $SOCAT $opts - $arg2" cat "${te}4" cat "$tdiff2" numCANT=$((numCANT+1)) listCANT="$listCANT $N" ;; X1) $PRINTF "$FAILED: SECURITY BROKEN\n" echo "$TRACE $SOCAT $opts $arg echo" cat "${te}3" echo "$TRACE $SOCAT $opts - $arg2" cat "${te}4" cat "$tdiff2" numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" ;; X2) $PRINTF "$FAILED: diff:\n" echo "$TRACE $SOCAT $opts $arg echo" cat "${te}3" echo "$TRACE $SOCAT $opts - $arg2" cat "${te}4" cat "$tdiff2" numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" ;; esac else $PRINTF "$OK\n" [ "$VERBOSE" ] && echo " $TRACE $SOCAT $opts $arg echo" [ "$debug" ] && cat ${te}3 [ "$VERBOSE" ] && echo " $TRACE $SOCAT $opts - $arg2" [ "$debug" ] && cat ${te}4 numOK=$((numOK+1)) fi wait #set +vx } NAME=TCP4RANGEBITS case "$TESTS" in *%$N%*|*%functions%*|*%security%*|*%tcp%*|*%tcp4%*|*%ip4%*|*%range%*|*%listen%*|*%fork%*|*%$NAME%*) TEST="$NAME: security of TCP4-L with RANGE option" if ! eval $NUMCOND; then :; elif [ -z "$SECONDADDR" ]; then # we need access to a second addresses $PRINTF "test $F_n $TEST... ${YELLOW}need a second IPv4 address${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" else newport tcp4 # provide free port number in $PORT testserversec "$N" "$TEST" "$opts" "TCP4-L:$PORT,reuseaddr,fork,retry=1" "" "range=$SECONDADDR/32" "TCP4:127.0.0.1:$PORT" 4 tcp $PORT 0 fi ;; # $SECONDADDR, NUMCOND esac N=$((N+1)) NAME=TCP4RANGEMASK case "$TESTS" in *%$N%*|*%functions%*|*%security%*|*%tcp%*|*%tcp4%*|*%ip4%*|*%range%*|*%listen%*|*%fork%*|*%$NAME%*) TEST="$NAME: security of TCP4-L with RANGE option" if ! eval $NUMCOND; then :; elif [ -z "$SECONDADDR" ]; then # we need access to a second addresses $PRINTF "test $F_n $TEST... ${YELLOW}need a second IPv4 address${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" else newport tcp4 # provide free port number in $PORT testserversec "$N" "$TEST" "$opts" "TCP4-L:$PORT,reuseaddr,fork,retry=1" "" "range=$SECONDADDR:255.255.255.255" "TCP4:127.0.0.1:$PORT" 4 tcp $PORT 0 fi ;; # $SECONDADDR, NUMCOND esac N=$((N+1)) # like TCP4RANGEMASK, but the "bad" address is within the same class A network NAME=TCP4RANGEMASKHAIRY case "$TESTS" in *%$N%*|*%functions%*|*%security%*|*%tcp%*|*%tcp4%*|*%ip4%*|*%range%*|*%listen%*|*%fork%*|*%$NAME%*) TEST="$NAME: security of TCP4-L with RANGE option" if ! eval $NUMCOND; then :; else newport tcp4 # provide free port number in $PORT testserversec "$N" "$TEST" "$opts" "TCP4-L:$PORT,reuseaddr,fork,retry=1" "" "range=127.0.0.0:255.255.0.0" "TCP4:$SECONDADDR:$PORT,bind=$SECONDADDR" 4 tcp $PORT 0 fi ;; # Linux, NUMCOND esac N=$((N+1)) NAME=TCP4SOURCEPORT case "$TESTS" in *%$N%*|*%functions%*|*%security%*|*%tcp%*|*%tcp4%*|*%ip4%*|*%sourceport%*|*%listen%*|*%fork%*|*%$NAME%*) TEST="$NAME: security of TCP4-L with SOURCEPORT option" if ! eval $NUMCOND; then :; else newport tcp4 # provide free port number in $PORT testserversec "$N" "$TEST" "$opts" "TCP4-L:$PORT,reuseaddr,fork,retry=1" "" "sp=$PORT" "TCP4:127.0.0.1:$PORT" 4 tcp $PORT 0 fi ;; # NUMCOND esac N=$((N+1)) NAME=TCP4LOWPORT case "$TESTS" in *%$N%*|*%functions%*|*%security%*|*%tcp%*|*%tcp4%*|*%ip4%*|*%lowport%*|*%listen%*|*%fork%*|*%$NAME%*) TEST="$NAME: security of TCP4-L with LOWPORT option" if ! eval $NUMCOND; then :; else newport tcp4 # provide free port number in $PORT testserversec "$N" "$TEST" "$opts" "TCP4-L:$PORT,reuseaddr,fork,retry=1" "" "lowport" "TCP4:127.0.0.1:$PORT" 4 tcp $PORT 0 fi ;; # NUMCOND esac N=$((N+1)) NAME=TCP4WRAPPERS_ADDR case "$TESTS" in *%$N%*|*%functions%*|*%security%*|*%tcp%*|*%tcp4%*|*%ip4%*|*%tcpwrap%*|*%listen%*|*%fork%*|*%$NAME%*) TEST="$NAME: security of TCP4-L with TCPWRAP option" if ! eval $NUMCOND; then :; elif ! feat=$(testfeats tcp ip4 libwrap) || ! runsip4 >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}$feat not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" else ha="$td/hosts.allow" hd="$td/hosts.deny" $ECHO "socat: $SECONDADDR" >"$ha" $ECHO "ALL: ALL" >"$hd" newport tcp4 # provide free port number in $PORT testserversec "$N" "$TEST" "$opts" "TCP4-L:$PORT,reuseaddr,fork,retry=1" "" "hosts-allow=$ha,hosts-deny=$hd" "TCP4:127.0.0.1:$PORT" 4 tcp $PORT 0 fi ;; # NUMCOND, feats esac N=$((N+1)) NAME=TCP4WRAPPERS_NAME case "$TESTS" in *%$N%*|*%functions%*|*%security%*|*%tcp%*|*%tcp4%*|*%ip4%*|*%tcpwrap%*|*%listen%*|*%fork%*|*%$NAME%*) TEST="$NAME: security of TCP4-L with TCPWRAP option" if ! eval $NUMCOND; then :; elif ! feat=$(testfeats tcp ip4 libwrap) || ! runsip4 >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}$feat not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" else ha="$td/hosts.allow" hd="$td/hosts.deny" $ECHO "socat: $LOCALHOST" >"$ha" $ECHO "ALL: ALL" >"$hd" newport tcp4 # provide free port number in $PORT testserversec "$N" "$TEST" "$opts" "TCP4-L:$PORT,reuseaddr,fork,retry=1" "" "hosts-allow=$ha,hosts-deny=$hd" "TCP4:$SECONDADDR:$PORT,bind=$SECONDADDR" 4 tcp $PORT 0 fi ;; # NUMCOND, feats esac N=$((N+1)) NAME=TCP6RANGE case "$TESTS" in *%$N%*|*%functions%*|*%security%*|*%tcp%*|*%tcp6%*|*%ip6%*|*%range%*|*%listen%*|*%fork%*|*%$NAME%*) TEST="$NAME: security of TCP6-L with RANGE option" if ! eval $NUMCOND; then :; elif ! feat=$(testfeats tcp ip6) || ! runsip6 >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}TCP6 not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" else newport tcp6 # provide free port number in $PORT testserversec "$N" "$TEST" "$opts" "TCP6-L:$PORT,reuseaddr,fork,retry=1" "" "range=[::2]/128" "TCP6:[::1]:$PORT" 6 tcp $PORT 0 fi ;; # NUMCOND, feats esac N=$((N+1)) NAME=TCP6SOURCEPORT case "$TESTS" in *%$N%*|*%functions%*|*%security%*|*%tcp%*|*%tcp6%*|*%ip6%*|*%sourceport%*|*%listen%|*%fork%**|*%$NAME%*) TEST="$NAME: security of TCP6-L with SOURCEPORT option" if ! eval $NUMCOND; then :; elif ! feat=$(testfeats tcp ip6) || ! runsip6 >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}TCP6 not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" else newport tcp6 # provide free port number in $PORT testserversec "$N" "$TEST" "$opts" "TCP6-L:$PORT,reuseaddr,fork,retry=1" "" "sp=$PORT" "TCP6:[::1]:$PORT" 6 tcp $PORT 0 fi ;; # NUMCOND, feats esac N=$((N+1)) NAME=TCP6LOWPORT case "$TESTS" in *%$N%*|*%functions%*|*%security%*|*%tcp%*|*%tcp6%*|*%ip6%*|*%lowport%*|*%listen%*|*%fork%*|*%$NAME%*) TEST="$NAME: security of TCP6-L with LOWPORT option" if ! eval $NUMCOND; then :; elif ! feat=$(testfeats tcp ip6) || ! runsip6 >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}TCP6 not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" else newport tcp6 # provide free port number in $PORT testserversec "$N" "$TEST" "$opts" "TCP6-L:$PORT,reuseaddr,fork,retry=1" "" "lowport" "TCP6:[::1]:$PORT" 6 tcp $PORT 0 fi ;; # NUMCOND, feats esac N=$((N+1)) NAME=TCP6TCPWRAP case "$TESTS" in *%$N%*|*%functions%*|*%security%*|*%tcp%*|*%tcp6%*|*%ip6%*|*%tcpwrap%*|*%listen%*|*%fork%*|*%$NAME%*) TEST="$NAME: security of TCP6-L with TCPWRAP option" if ! eval $NUMCOND; then :; elif ! feat=$(testfeats tcp ip6 libwrap && runstcp6); then $PRINTF "test $F_n $TEST... ${YELLOW}$feat not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" else ha="$td/hosts.allow" hd="$td/hosts.deny" $ECHO "socat: [::2]" >"$ha" $ECHO "ALL: ALL" >"$hd" newport tcp6 # provide free port number in $PORT testserversec "$N" "$TEST" "$opts" "TCP6-L:$PORT,reuseaddr,fork,retry=1" "" "hosts-allow=$ha,hosts-deny=$hd" "TCP6:[::1]:$PORT" 6 tcp $PORT 0 fi ;; # NUMCOND, feats esac N=$((N+1)) NAME=UDP4RANGE case "$TESTS" in *%$N%*|*%functions%*|*%security%*|*%udp%*|*%udp4%*|*%ip4%*|*%range%*|*%listen%*|*%fork%*|*%$NAME%*) TEST="$NAME: security of UDP4-L with RANGE option" if ! eval $NUMCOND; then :; else newport udp4 # provide free port number in $PORT #testserversec "$N" "$TEST" "$opts" "UDP4-L:$PORT,reuseaddr,fork" "" "range=$SECONDADDR/32" "UDP4:127.0.0.1:$PORT" 4 udp $PORT 0 testserversec "$N" "$TEST" "$opts" "UDP4-L:$PORT,reuseaddr" "" "range=$SECONDADDR/32" "UDP4:127.0.0.1:$PORT" 4 udp $PORT 0 fi ;; # NUMCOND esac N=$((N+1)) NAME=UDP4SOURCEPORT case "$TESTS" in *%$N%*|*%functions%*|*%security%*|*%udp%*|*%udp4%*|*%ip4%*|*%sourceport%*|*%listen%*|*%$NAME%*) TEST="$NAME: security of UDP4-L with SOURCEPORT option" if ! eval $NUMCOND; then :; else newport udp4 # provide free port number in $PORT testserversec "$N" "$TEST" "$opts" "UDP4-L:$PORT,reuseaddr" "" "sp=$PORT" "UDP4:127.0.0.1:$PORT" 4 udp $PORT 0 fi ;; # NUMCOND esac N=$((N+1)) NAME=UDP4LOWPORT case "$TESTS" in *%$N%*|*%functions%*|*%security%*|*%udp%*|*%udp4%*|*%ip4%*|*%lowport%*|*%listen%*|*%$NAME%*) TEST="$NAME: security of UDP4-L with LOWPORT option" if ! eval $NUMCOND; then :; else newport udp4 # provide free port number in $PORT testserversec "$N" "$TEST" "$opts" "UDP4-L:$PORT,reuseaddr" "" "lowport" "UDP4:127.0.0.1:$PORT" 4 udp $PORT 0 fi ;; # NUMCOND esac N=$((N+1)) NAME=UDP4TCPWRAP case "$TESTS" in *%$N%*|*%functions%*|*%security%*|*%udp%*|*%udp4%*|*%ip4%*|*%tcpwrap%*|*%listen%*|*%$NAME%*) TEST="$NAME: security of UDP4-L with TCPWRAP option" if ! eval $NUMCOND; then :; elif ! feat=$(testfeats udp ip4 libwrap) || ! runsip4 >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}$feat not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" else ha="$td/hosts.allow" hd="$td/hosts.deny" $ECHO "socat: $SECONDADDR" >"$ha" $ECHO "ALL: ALL" >"$hd" newport udp4 # provide free port number in $PORT testserversec "$N" "$TEST" "$opts" "UDP4-L:$PORT,reuseaddr" "" "tcpwrap-etc=$td" "UDP4:127.0.0.1:$PORT" 4 udp $PORT 0 fi ;; # NUMCOND, feats esac N=$((N+1)) NAME=UDP6RANGE case "$TESTS" in *%$N%*|*%functions%*|*%security%*|*%udp%*|*%udp6%*|*%ip6%*|*%range%*|*%listen%*|*%fork%*|*%$NAME%*) TEST="$NAME: security of UDP6-L with RANGE option" if ! eval $NUMCOND; then :; elif ! feat=$(testfeats tcp ip6) || ! runsip6 >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}TCP6 not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" else newport udp6 # provide free port number in $PORT #testserversec "$N" "$TEST" "$opts" "UDP6-L:$PORT,reuseaddr,fork" "" "range=[::2]/128" "UDP6:[::1]:$PORT" 6 udp $PORT 0 testserversec "$N" "$TEST" "$opts" "UDP6-L:$PORT,reuseaddr" "" "range=[::2]/128" "UDP6:[::1]:$PORT" 6 udp $PORT 0 fi ;; # NUMCOND, feats esac N=$((N+1)) NAME=UDP6SOURCEPORT case "$TESTS" in *%$N%*|*%functions%*|*%security%*|*%udp%*|*%udp6%*|*%ip6%*|*%sourceport%*|*%listen%*|*%$NAME%*) TEST="$NAME: security of UDP6-L with SOURCEPORT option" if ! eval $NUMCOND; then :; elif ! feat=$(testfeats udp ip6) || ! runsip6 >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}UDP6 not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" else newport udp6 # provide free port number in $PORT testserversec "$N" "$TEST" "$opts" "UDP6-L:$PORT,reuseaddr" "" "sp=$PORT" "UDP6:[::1]:$PORT" 6 udp $PORT 0 fi ;; # NUMCOND, feats esac N=$((N+1)) NAME=UDP6LOWPORT case "$TESTS" in *%$N%*|*%functions%*|*%security%*|*%udp%*|*%udp6%*|*%ip6%*|*%lowport%*|*%listen%*|*%$NAME%*) TEST="$NAME: security of UDP6-L with LOWPORT option" if ! eval $NUMCOND; then :; elif ! feat=$(testfeats udp ip6) || ! runsip6 >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}UDP6 not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" else newport udp6 # provide free port number in $PORT testserversec "$N" "$TEST" "$opts" "UDP6-L:$PORT,reuseaddr" "" "lowport" "UDP6:[::1]:$PORT" 6 udp $PORT 0 fi ;; # NUMCOND, feats esac N=$((N+1)) NAME=UDP6TCPWRAP case "$TESTS" in *%$N%*|*%functions%*|*%security%*|*%udp%*|*%udp6%*|*%ip6%*|*%tcpwrap%*|*%listen%*|*%$NAME%*) TEST="$NAME: security of UDP6-L with TCPWRAP option" if ! eval $NUMCOND; then :; elif ! feat=$(testfeats tcp ip6 libwrap && runsip6); then $PRINTF "test $F_n $TEST... ${YELLOW}$feat not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" else ha="$td/hosts.allow" hd="$td/hosts.deny" $ECHO "socat: [::2]" >"$ha" $ECHO "ALL: ALL" >"$hd" newport udp6 # provide free port number in $PORT testserversec "$N" "$TEST" "$opts" "UDP6-L:$PORT,reuseaddr" "" "lowport" "UDP6:[::1]:$PORT" 6 udp $PORT 0 fi ;; # NUMCOND, feats esac N=$((N+1)) NAME=OPENSSLTCP4_RANGE case "$TESTS" in *%$N%*|*%functions%*|*%security%*|*%tcp%*|*%tcp4%*|*%ip4%*|*%openssl%*|*%range%*|*%listen%*|*%fork%*|*%$NAME%*) TEST="$NAME: security of SSL-L over TCP/IPv4 with RANGE option" if ! eval $NUMCOND; then :; elif ! testfeats openssl >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}OPENSSL not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" else gentestcert testsrv newport tcp4 # provide free port number in $PORT testserversec "$N" "$TEST" "$opts" "SSL-L:$PORT,pf=ip4,reuseaddr,fork,retry=1,$SOCAT_EGD,verify=0,cert=testsrv.crt,key=testsrv.key" "" "range=$SECONDADDR/32" "SSL:$LOCALHOST:$PORT,pf=ip4,cafile=testsrv.crt,$SOCAT_EGD" 4 tcp $PORT -1 fi ;; # NUMCOND, feats esac N=$((N+1)) NAME=OPENSSLTCP4_SOURCEPORT case "$TESTS" in *%$N%*|*%functions%*|*%security%*|*%tcp%*|*%tcp4%*|*%ip4%*|*%openssl%*|*%sourceport%*|*%listen%*|*%fork%*|*%$NAME%*) TEST="$NAME: security of SSL-L with SOURCEPORT option" if ! eval $NUMCOND; then :; elif ! testfeats openssl >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}OPENSSL not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" else gentestcert testsrv newport tcp4 # provide free port number in $PORT testserversec "$N" "$TEST" "$opts" "SSL-L:$PORT,pf=ip4,reuseaddr,fork,retry=1,$SOCAT_EGD,verify=0,cert=testsrv.crt,key=testsrv.key" "" "sp=$PORT" "SSL:$LOCALHOST:$PORT,pf=ip4,cafile=testsrv.crt,$SOCAT_EGD" 4 tcp $PORT -1 fi ;; # NUMCOND, feats esac N=$((N+1)) NAME=OPENSSLTCP4_LOWPORT case "$TESTS" in *%$N%*|*%functions%*|*%security%*|*%tcp%*|*%tcp4%*|*%ip4%*|*%openssl%*|*%lowport%*|*%listen%*|*%fork%*|*%$NAME%*) TEST="$NAME: security of SSL-L with LOWPORT option" if ! eval $NUMCOND; then :; elif ! testfeats openssl >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}OPENSSL not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" else gentestcert testsrv newport tcp4 # provide free port number in $PORT testserversec "$N" "$TEST" "$opts" "SSL-L:$PORT,pf=ip4,reuseaddr,fork,retry=1,$SOCAT_EGD,verify=0,cert=testsrv.crt,key=testsrv.key" "" "lowport" "SSL:$LOCALHOST:$PORT,pf=ip4,cafile=testsrv.crt,$SOCAT_EGD" 4 tcp $PORT -1 fi ;; # NUMCOND, feats esac N=$((N+1)) NAME=OPENSSLTCP4_TCPWRAP case "$TESTS" in *%$N%*|*%functions%*|*%security%*|*%tcp%*|*%tcp4%*|*%ip4%*|*%openssl%*|*%tcpwrap%*|*%listen%*|*%fork%*|*%$NAME%*) TEST="$NAME: security of SSL-L with TCPWRAP option" if ! eval $NUMCOND; then :; elif ! feat=$(testfeats ip4 tcp libwrap openssl); then $PRINTF "test $F_n $TEST... ${YELLOW}$feat not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" else gentestcert testsrv ha="$td/hosts.allow" hd="$td/hosts.deny" $ECHO "socat: $SECONDADDR" >"$ha" $ECHO "ALL: ALL" >"$hd" newport tcp4 # provide free port number in $PORT testserversec "$N" "$TEST" "$opts" "SSL-L:$PORT,pf=ip4,reuseaddr,fork,retry=1,$SOCAT_EGD,verify=0,cert=testsrv.crt,key=testsrv.key" "" "tcpwrap-etc=$td" "SSL:$LOCALHOST:$PORT,pf=ip4,cafile=testsrv.crt,$SOCAT_EGD" 4 tcp $PORT -1 fi ;; # NUMCOND, feats esac N=$((N+1)) NAME=OPENSSLCERTSERVER case "$TESTS" in *%$N%*|*%functions%*|*%security%*|*%tcp%*|*%tcp4%*|*%ip4%*|*%openssl%*|*%listen%*|*%fork%*|*%$NAME%*) TEST="$NAME: security of SSL-L with client certificate" if ! eval $NUMCOND; then :; elif ! testfeats openssl >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}OPENSSL not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" else gentestcert testsrv gentestcert testcli newport tcp4 # provide free port number in $PORT testserversec "$N" "$TEST" "$opts -4" "SSL-L:$PORT,pf=ip4,reuseaddr,fork,retry=1,$SOCAT_EGD,verify,cert=testsrv.crt,key=testsrv.key" "cafile=testcli.crt" "cafile=testsrv.crt" "SSL:$LOCALHOST:$PORT,pf=ip4,cafile=testsrv.crt,cert=testcli.pem,$SOCAT_EGD" 4 tcp $PORT '*' fi ;; # NUMCOND, feats esac N=$((N+1)) NAME=OPENSSLCERTCLIENT case "$TESTS" in *%$N%*|*%functions%*|*%security%*|*%tcp%*|*%tcp4%*|*%ip4%*|*%openssl%*|*%listen%*|*%fork%*|*%$NAME%*) TEST="$NAME: security of SSL with server certificate" if ! eval $NUMCOND; then :; elif ! testfeats openssl >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}OPENSSL not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" else gentestcert testsrv gentestcert testcli newport tcp4 # provide free port number in $PORT testserversec "$N" "$TEST" "$opts -t 0.5 -lu -d" "SSL:$LOCALHOST:$PORT,pf=ip4,fork,retry=2,verify,cert=testcli.pem,$SOCAT_EGD" "cafile=testsrv.crt" "cafile=testcli.crt" "SSL-L:$PORT,pf=ip4,reuseaddr,$SOCAT_EGD,cafile=testcli.crt,cert=testsrv.crt,key=testsrv.key" 4 tcp "" -1 fi ;; # NUMCOND, feats esac N=$((N+1)) NAME=OPENSSLTCP6_RANGE case "$TESTS" in *%$N%*|*%functions%*|*%security%*|*%tcp%*|*%tcp6%*|*%ip6%*|*%openssl%*|*%range%*|*%listen%*|*%fork%*|*%$NAME%*) TEST="$NAME: security of SSL-L over TCP/IPv6 with RANGE option" if ! eval $NUMCOND; then :; elif ! testfeats openssl >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}OPENSSL not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif ! feat=$(testfeats tcp ip6) || ! runsip6 >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}TCP6 not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" else gentestcert6 testsrv6 newport tcp6 # provide free port number in $PORT testserversec "$N" "$TEST" "$opts" "SSL-L:$PORT,pf=ip6,reuseaddr,fork,retry=1,$SOCAT_EGD,verify=0,cert=testsrv6.crt,key=testsrv6.key" "" "range=[::2]/128" "SSL:[::1]:$PORT,cafile=testsrv6.crt,$SOCAT_EGD" 6 tcp $PORT -1 fi ;; # NUMCOND, feats esac N=$((N+1)) NAME=OPENSSLTCP6_SOURCEPORT case "$TESTS" in *%$N%*|*%functions%*|*%security%*|*%tcp%*|*%tcp6%*|*%ip6%*|*%openssl%*|*%sourceport%*|*%listen%*|*%fork%*|*%$NAME%*) TEST="$NAME: security of SSL-L over TCP/IPv6 with SOURCEPORT option" if ! eval $NUMCOND; then :; elif ! testfeats openssl >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}OPENSSL not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif ! feat=$(testfeats tcp ip6) || ! runsip6 >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}TCP6 not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" else gentestcert6 testsrv6 newport tcp6 # provide free port number in $PORT testserversec "$N" "$TEST" "$opts" "SSL-L:$PORT,pf=ip6,reuseaddr,fork,retry=1,$SOCAT_EGD,verify=0,cert=testsrv6.crt,key=testsrv6.key" "" "sp=$PORT" "SSL:[::1]:$PORT,cafile=testsrv6.crt,$SOCAT_EGD" 6 tcp $PORT -1 fi ;; # NUMCOND, feats esac N=$((N+1)) NAME=OPENSSLTCP6_LOWPORT case "$TESTS" in *%$N%*|*%functions%*|*%security%*|*%tcp%*|*%tcp6%*|*%ip6%*|*%openssl%*|*%lowport%*|*%listen%*|*%fork%*|*%$NAME%*) TEST="$NAME: security of SSL-L over TCP/IPv6 with LOWPORT option" if ! eval $NUMCOND; then :; elif ! testfeats openssl >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}OPENSSL not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif ! feat=$(testfeats tcp ip6) || ! runsip6 >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}TCP6 not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" else gentestcert6 testsrv6 newport tcp6 # provide free port number in $PORT testserversec "$N" "$TEST" "$opts" "SSL-L:$PORT,pf=ip6,reuseaddr,fork,retry=1,$SOCAT_EGD,verify=0,cert=testsrv6.crt,key=testsrv6.key" "" "lowport" "SSL:[::1]:$PORT,cafile=testsrv6.crt,$SOCAT_EGD" 6 tcp $PORT -1 fi ;; # NUMCOND, feats esac N=$((N+1)) NAME=OPENSSLTCP6_TCPWRAP case "$TESTS" in *%$N%*|*%functions%*|*%security%*|*%tcp%*|*%tcp6%*|*%ip6%*|*%openssl%*|*%tcpwrap%*|*%listen%*|*%fork%*|*%$NAME%*) TEST="$NAME: security of SSL-L over TCP/IPv6 with TCPWRAP option" if ! eval $NUMCOND; then :; elif ! feat=$(testfeats ip6 tcp libwrap openssl && runsip6); then $PRINTF "test $F_n $TEST... ${YELLOW}$feat not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" else gentestcert6 testsrv6 ha="$td/hosts.allow" hd="$td/hosts.deny" $ECHO "socat: [::2]" >"$ha" $ECHO "ALL: ALL" >"$hd" newport tcp6 # provide free port number in $PORT testserversec "$N" "$TEST" "$opts" "SSL-L:$PORT,pf=ip6,reuseaddr,fork,retry=1,$SOCAT_EGD,verify=0,cert=testsrv6.crt,key=testsrv6.key" "" "tcpwrap-etc=$td" "SSL:[::1]:$PORT,cafile=testsrv6.crt,$SOCAT_EGD" 6 tcp $PORT -1 fi ;; # NUMCOND, feats esac N=$((N+1)) # test security with the openssl-commonname option on client side NAME=OPENSSL_CN_CLIENT_SECURITY case "$TESTS" in *%$N%*|*%functions%*|*%security%*|*%openssl%*|*%tcp%*|*%tcp4%*|*%ip4%*|*%listen%*|*%fork%*|*%$NAME%*) TEST="$NAME: security of client openssl-commonname option" # connect using non matching server name/address with commonname # options, this should succeed. Then without this option, should fail if ! eval $NUMCOND; then :; elif ! testfeats openssl >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}OPENSSL not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif ! testfeats listen tcp ip4 >/dev/null || ! runsip4 >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}TCP/IPv4 not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" else gentestcert testsrv gentestcert testcli newport tcp4 # provide free port number in $PORT testserversec "$N" "$TEST" "$opts -t 0.5 -4" "SSL:127.0.0.1:$PORT,fork,retry=2,verify,cafile=testsrv.crt" "commonname=$LOCALHOST" "" "SSL-L:$PORT,pf=ip4,$REUSEADDR,cert=testsrv.crt,key=testsrv.key,verify=0" 4 tcp "" '*' fi ;; # testfeats, NUMCOND esac N=$((N+1)) # test security with the openssl-commonname option on server side NAME=OPENSSL_CN_SERVER_SECURITY case "$TESTS" in *%$N%*|*%functions%*|*%security%*|*%openssl%*|*%tcp%*|*%tcp4%*|*%ip4%*|*%listen%*|*%$NAME%*) TEST="$NAME: security of server openssl-commonname option" # connect using with client certificate to server, this should succeed. # Then use the server with a non matching openssl-commonname option, # this must fail if ! eval $NUMCOND; then :; elif ! testfeats openssl >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}OPENSSL not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif ! testfeats listen tcp ip4 >/dev/null || ! runsip4 >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}TCP/IPv4 not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" else gentestcert testsrv gentestcert testcli newport tcp4 # provide free port number in $PORT testserversec "$N" "$TEST" "$opts -4" "SSL-L:$PORT,pf=ip4,reuseaddr,cert=testsrv.crt,key=testsrv.key,cafile=testcli.crt" "" "commonname=onlyyou" "SSL:$LOCALHOST:$PORT,pf=ip4,$REUSEADDR,verify=0,cafile=testsrv.crt,cert=testcli.crt,key=testcli.key" 4 tcp "$PORT" '*' fi ;; # testfeats, NUMCOND esac N=$((N+1)) NAME=OPENSSL_FIPS_SECURITY case "$TESTS" in *%$N%*|*%functions%*|*%security%*|*%openssl%*|*%fips%*|*%tcp%*|*%tcp4%*|*%ip4%*|*%listen%*|*%fork%*|*%$NAME%*) TEST="$NAME: OpenSSL restrictions by FIPS" if ! eval $NUMCOND; then :; elif ! testfeats openssl >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}OPENSSL not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif ! testfeats listen tcp ip4 >/dev/null || ! runsip4 >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}TCP/IPv4 not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif ! testoptions fips >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}OPENSSL/FIPS not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" else gentestcert testsrv gentestcert testcli newport tcp4 # provide free port number in $PORT # openssl client accepts a "normal" certificate only when not in fips mode testserversec "$N" "$TEST" "$opts" "SSL:$LOCALHOST:$PORT,fork,retry=2,verify,cafile=testsrv.crt" "" "fips" "SSL-L:$PORT,pf=ip4,$REUSEADDR,cert=testsrv.crt,key=testsrv.key" 4 tcp "" -1 fi ;; # testfeats, NUMCOND esac N=$((N+1)) NAME=UNIEXECEOF case "$TESTS" in *%$N%*|*%functions%*|*%$NAME%*) TEST="$NAME: give exec'd write-only process a chance to flush (-u)" testod "$N" "$TEST" "" EXEC:"$OD_C" "$opts -u" esac N=$((N+1)) NAME=REVEXECEOF case "$TESTS" in *%$N%*|*%functions%*|*%$NAME%*) TEST="$NAME: give exec'd write-only process a chance to flush (-U)" testod "$N" "$TEST" EXEC:"$OD_C" "-" "$opts -U" esac N=$((N+1)) NAME=FILANDIR case "$TESTS" in *%$N%*|*%filan%*|*%$NAME%*) TEST="$NAME: check type printed for directories" if ! eval $NUMCOND; then :; else te="$td/test$N.stderr" printf "test $F_n $TEST... " $N type=$($FILAN -f . 2>$te |tail -n 1 |awk '{print($2);}') if [ "$type" = "dir" ]; then $PRINTF "$OK\n" numOK=$((numOK+1)) else $PRINTF "$FAILED\n" cat "$te" numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" fi fi ;; # NUMCOND esac N=$((N+1)) # Test if Filan can determine UNIX domain socket in file system NAME=FILANSOCKET case "$TESTS" in *%$N%*|*%filan%*|*%unix%*|*%listen%*|*%$NAME%*) TEST="$NAME: capability to analyze named unix socket" # Run Filan on a listening UNIX domain socket. # When its output gives "socket" as type (2nd column), the test succeeded if ! eval $NUMCOND; then :; else ts="$td/test$N.socket" te1="$td/test$N.stderr1" # socat te2="$td/test$N.stderr2" # filan printf "test $F_n $TEST... " $N $TRACE $SOCAT $opts UNIX-LISTEN:"$ts" /dev/null "$te1" & spid=$! waitfile "$ts" 1 type=$($FILAN -f "$ts" 2>$te2 |tail -n 1 |awk '{print($2);}') if [ "$type" = "socket" ]; then $PRINTF "$OK\n" if [ "$VERBOSE" ]; then echo "$SOCAT $opts UNIX-LISTEN:\"$ts\" /dev/null \"$te1\"" echo "$FILAN -f "$ts" 2>$te2 |tail -n 1 |awk '{print(\$2);}'" fi numOK=$((numOK+1)) else $PRINTF "$FAILED\n" echo "$SOCAT $opts UNIX-LISTEN:\"$ts\" /dev/null \"$te1\"" >&2 cat "$te1" echo "$FILAN -f "$ts" 2>$te2 |tail -n 1 |awk '{print(\$2);}'" >&2 cat "$te2" numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" fi kill $spid 2>/dev/null wait fi ;; # NUMCOND esac N=$((N+1)) testptywaitslave () { local N="$1" local TEST="$2" local PTYTYPE="$3" # ptmx or openpty local opts="$4" local tp="$td/test$N.pty" local ts="$td/test$N.socket" local tf="$td/test$N.file" local tdiff="$td/test$N.diff" local te1="$td/test$N.stderr1" local te2="$td/test$N.stderr2" local te3="$td/test$N.stderr3" local te4="$td/test$N.stderr4" local da="test$N $(date) $RANDOM" printf "test $F_n $TEST... " $N # first generate a pty, then a socket ($TRACE $SOCAT $opts -lpsocat1 PTY,$PTYTYPE,pty-wait-slave,link="$tp" UNIX-LISTEN:"$ts" 2>"$te1"; rm -f "$tp") 2>/dev/null & pid=$! waitfile "$tp" # if pty was non-blocking, the socket is active, and socat1 will term $TRACE $SOCAT $opts -T 10 -lpsocat2 FILE:/dev/null UNIX-CONNECT:"$ts" 2>"$te2" # if pty is blocking, first socat is still active and we get a connection now #((echo "$da"; sleep 2) |$TRACE $SOCAT -lpsocat3 $opts - file:"$tp",$PTYOPTS2 >"$tf" 2>"$te3") & ( (waitfile "$ts" 1 20; echo "$da"; sleep 1) |$TRACE $SOCAT -lpsocat3 $opts - FILE:"$tp",$PTYOPTS2 >"$tf" 2>"$te3") & waitfile "$ts" 1 20 # but we need an echoer on the socket $TRACE $SOCAT $opts -lpsocat4 UNIX:"$ts" ECHO 2>"$te4" # now $tf file should contain $da #kill $pid 2>/dev/null wait # if echo "$da" |diff - "$tf"> "$tdiff"; then $PRINTF "$OK\n" if [ "$VERBOSE" ]; then echo " $TRACE $SOCAT $opts -T 10 -lpsocat2 FILE:/dev/null UNIX-CONNECT:\"$ts\"" 2>"$te2" echo " $TRACE $SOCAT $opts -lpsocat1 PTY,$PTYTYPE,pty-wait-slave,link=\"$tp\" UNIX-LISTEN:\"$ts\"" >&2 echo " $TRACE $SOCAT -lpsocat3 $opts - file:\"$tp\",$PTYOPTS2" >&2 fi numOK=$((numOK+1)) else $PRINTF "${YELLOW}FAILED${NORMAL}\n" cat "$te1" #cat "$te2" # not of interest cat "$te3" cat "$te4" cat "$tdiff" numCANT=$((numCANT+1)) listCANT="$listCANT $N" fi } NAME=PTMXWAITSLAVE PTYTYPE=ptmx case "$TESTS" in *%$N%*|*%functions%*|*%pty%*|*%unix%*|*%listen%*|*%$NAME%*) TEST="$NAME: test if master pty ($PTYTYPE) waits for slave connection" if ! eval $NUMCOND; then :; else if ! feat=$(testfeats pty); then $PRINTF "test $F_n $TEST... ${YELLOW}$(echo "$feat"| tr 'a-z' 'A-Z') not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif ! feat=$(testoptions "$PTYTYPE" pty-wait-slave); then $PRINTF "test $F_n $TEST... ${YELLOW}option $(echo "$feat"| tr 'a-z' 'A-Z') not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" else testptywaitslave "$N" "$TEST" "$PTYTYPE" "$opts" fi fi ;; # NUMCOND esac N=$((N+1)) NAME=OPENPTYWAITSLAVE PTYTYPE=openpty case "$TESTS" in *%$N%*|*%functions%*|*%pty%*|*%unix%*|*%listen%*|*%$NAME%*) TEST="$NAME: test if master pty ($PTYTYPE) waits for slave connection" if ! eval $NUMCOND; then :; elif ! feat=$(testfeats pty); then $PRINTF "test $F_n $TEST... ${YELLOW}$(echo "$feat"| tr 'a-z' 'A-Z') not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif ! feat=$(testoptions "$PTYTYPE" pty-wait-slave); then $PRINTF "test $F_n $TEST... ${YELLOW}option $(echo "$feat"| tr 'a-z' 'A-Z') not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" else testptywaitslave "$N" "$TEST" "$PTYTYPE" "$opts" fi ;; # NUMCOND, feats esac N=$((N+1)) # Test the connect-timeout address option NAME=CONNECTTIMEOUT case "$TESTS" in *%$N%*|*%functions%*|*%ip4%*|*%ipapp%*|*%tcp%*|*%timeout%*|*%listen%*|*%$NAME%*) TEST="$NAME: test the connect-timeout option" if ! eval $NUMCOND; then :; elif ! feat=$(testfeats tcp); then $PRINTF "test $F_n $TEST... ${YELLOW}$(echo "$feat"| tr 'a-z' 'A-Z') not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif ! feat=$(testoptions connect-timeout); then $PRINTF "test $F_n $TEST... ${YELLOW}$(echo "$feat"| tr 'a-z' 'A-Z') not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" else # We need a hanging connection attempt, guess an address for this case "$UNAME" in Linux) HANGIP=1.0.0.1 ;; *) HANGIP=255.255.255.254 ;; esac te1="$td/test$N.stderr1" tk1="$td/test$N.kill1" te2="$td/test$N.stderr2" tk2="$td/test$N.kill2" $PRINTF "test $F_n $TEST... " $N # First, try to make socat hang and see if it can be killed #$TRACE $SOCAT $opts - TCP:$HANGIP:1 >"$te1" 2>&1 "$te1" 2>$te1 "$tk1"; then $PRINTF "${YELLOW}does not hang${NORMAL}\n" echo "$CMD" >&2 cat "$te1" >&2 numCANT=$((numCANT+1)) listCANT="$listCANT $N" else # Second, set connect-timeout and see if socat exits before kill CMD="$TRACE $SOCAT $opts - TCP:$HANGIP:1,connect-timeout=1.0" $CMD >"$te1" 2>$te2 "$tk2"; then $PRINTF "$FAILED\n" echo "$CMD" >&2 cat "$te2" >&2 numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" else $PRINTF "$OK\n" if [ "$VERBOSE" ]; then echo "$CMD" >&2 fi numOK=$((numOK+1)) fi fi wait fi ;; # testfeats, NUMCOND esac N=$((N+1)) # version 1.7.0.0 had a bug with the connect-timeout option: while it correctly # terminated a hanging connect attempt, it prevented a successful connection # establishment from being recognized by socat, instead the timeout occurred NAME=CONNECTTIMEOUT_CONN if ! eval $NUMCOND; then :; else case "$TESTS" in *%$N%*|*%functions%*|*%ip4%*|*%ipapp%*|*%tcp%*|*%timeout%*|*%listen%*|*%$NAME%*) TEST="$NAME: TCP4 connect-timeout option when server replies" # just try a connection that is expected to succeed with the usual data # transfer; with the bug it will fail tf="$td/test$N.stdout" te="$td/test$N.stderr" tdiff="$td/test$N.diff" newport tcp4; tsl=$PORT ts="127.0.0.1:$tsl" da="test$N $(date) $RANDOM" CMD1="$TRACE $SOCAT $opts TCP4-LISTEN:$tsl,$REUSEADDR PIPE" CMD2="$TRACE $SOCAT $opts STDIO TCP4:$ts,connect-timeout=1" printf "test $F_n $TEST... " $N $CMD1 >"$tf" 2>"${te}1" & pid1=$! waittcp4port $tsl 1 echo "$da" |$CMD2 >>"$tf" 2>>"${te}2" if [ $? -ne 0 ]; then $PRINTF "$FAILED: $TRACE $SOCAT:\n" echo "$CMD1 &" cat "${te}1" echo "$CMD2" cat "${te}2" numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" elif ! echo "$da" |diff - "$tf" >"$tdiff"; then $PRINTF "$FAILED\n" cat "$tdiff" numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" else $PRINTF "$OK\n" if [ -n "$debug" ]; then cat "${te}1" "${te}2"; fi numOK=$((numOK+1)) fi kill $pid1 2>/dev/null wait ;; esac fi # NUMCOND N=$((N+1)) NAME=OPENSSLLISTENDSA case "$TESTS" in *%$N%*|*%functions%*|*%openssl%*|*%listen%*|*%$NAME%*) TEST="$NAME: openssl listen with DSA certificate" if ! eval $NUMCOND; then :; elif ! testfeats openssl >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}OPENSSL not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" else SRVCERT=testsrvdsa gentestdsacert $SRVCERT tf="$td/test$N.stdout" te="$td/test$N.stderr" tdiff="$td/test$N.diff" da="test$N $(date) $RANDOM" newport tcp4 # provide free port number in $PORT CMD2="$TRACE $SOCAT $opts OPENSSL-LISTEN:$PORT,pf=ip4,$REUSEADDR,$SOCAT_EGD,cert=$SRVCERT.pem,key=$SRVCERT.key,verify=0 pipe" CMD="$TRACE $SOCAT $opts - openssl:$LOCALHOST:$PORT,pf=ip4,verify=0,$SOCAT_EGD" $PRINTF "test $F_n $TEST... " $N eval "$CMD2 2>\"${te}1\" &" pid=$! # background process id waittcp4port $PORT echo "$da" |$CMD >$tf 2>"${te}2" if ! echo "$da" |diff - "$tf" >"$tdiff"; then $PRINTF "$FAILED\n" echo "$CMD2 &" echo "$CMD" cat "${te}1" cat "${te}2" cat "$tdiff" numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" else $PRINTF "$OK\n" if [ -n "$debug" ]; then cat ${te}1 ${te}2; fi numOK=$((numOK+1)) fi kill $pid 2>/dev/null wait fi ;; # testfeats, NUMCOND esac N=$((N+1)) # derive signal number from signal name # kill -l should provide the info signum () { if [ ! "$BASH_VERSION" -o -o posix ]; then # we expect: for i in $(POSIXLY_CORRECT=1 kill -l); do echo "$i"; done |grep -n -i "^$1$" |cut -d: -f1 else # expect: # " 1) SIGHUP 2) SIGINT 3) SIGQUIT 4) SIGILL" signam="$1" kill -l $tpp"'; echo \$$ '">$tp; read x\"",nofork 2>"$te"; stat=$? tsh="$td/test$N.sh" cat <"$tsh" #! /usr/bin/env bash echo \$PPID >"$tpp" echo \$\$ >"$tp" read x EOF chmod a+x "$tsh" #$TRACE $SOCAT $opts echo SYSTEM:"exec \"$tsh\"",pty,setsid,nofork 2>"$te"; stat=$? CMD="$TRACE $SOCAT $opts ECHO SYSTEM:\"exec\\\ \\\"$tsh\\\"\",pty,setsid,nofork" $TRACE $SOCAT $opts ECHO SYSTEM:"exec \"$tsh\"",pty,setsid,nofork 2>"$te" stat=$? sleep 1; kill -INT $(cat $tp) wait if [ "$stat" -eq $((128+$SIG)) ]; then $PRINTF "$OK\n" numOK=$((numOK+1)) else $PRINTF "$FAILED\n" echo "$CMD" cat "$te" numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" fi wait fi ;; # NUMCOND, feats esac N=$((N+1)) done NAME=READBYTES #set -vx case "$TESTS" in *%$N%*|*%functions%*|*%$NAME%*) TEST="$NAME: restrict reading from file with bytes option" if ! eval $NUMCOND; then :; elif false; then $PRINTF "test $F_n $TEST... ${YELLOW}$(echo "$feat"| tr 'a-z' 'A-Z') not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" else tr="$td/test$N.ref" ti="$td/test$N.in" to="$td/test$N.out" te="$td/test$N.err" tdiff="$td/test$N.diff" da="test$N $(date) $RANDOM"; da="$da$($ECHO '\r')" # CMD="$TRACE $SOCAT $opts -u open:$ti,readbytes=100 -" printf "test $F_n $TEST... " $N rm -f "$tf" "$ti" "$to" # echo "AAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAA" >"$tr" # 100 bytes cat "$tr" "$tr" >"$ti" # 200 bytes $CMD >"$to" 2>"$te" if ! diff "$tr" "$to" >"$tdiff" 2>&1; then $PRINTF "$FAILED: $TRACE $SOCAT:\n" echo "$CMD" cat "$te" cat "$tdiff" numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" else $PRINTF "$OK\n" if [ -n "$debug" ]; then cat $te; fi numOK=$((numOK+1)) fi fi ;; # NUMCOND, feats esac N=$((N+1)) NAME=UDPLISTENFORK case "$TESTS" in *%$N%*|*%functions%*|*%ip4%*|*%udp%*|*%listen%*|*%fork%*|*%$NAME%*) TEST="$NAME: UDP socket rebinds after first connection" if ! eval $NUMCOND; then :; elif ! F=$(testfeats STDIO IP4 UDP PIPE); then $PRINTF "test $F_n $TEST... ${YELLOW}Feature $F not available in $SOCAT${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif ! A=$(testaddrs STDIO UDP4-CONNECT UDP4-LISTEN PIPE); then $PRINTF "test $F_n $TEST... ${YELLOW}Address $A not available in $SOCAT${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif ! o=$(testoptions bind so-reuseaddr fork) >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}Option $o not available in $SOCAT${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif ! runsip4 >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}IPv4 not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" else tf="$td/test$N.stdout" te="$td/test$N.stderr" tdiff="$td/test$N.diff" da1="test$N $(date) $RANDOM" da2="test$N $(date) $RANDOM" #establish a listening and forking udp socket in background #processes hang forever without -T newport udp4 # provide free port number in $PORT CMD0="$TRACE $SOCAT -T 5 $opts -lpserver UDP4-LISTEN:$PORT,bind=$LOCALHOST,$REUSEADDR,fork PIPE" #make a first and a second connection CMD1="$TRACE $SOCAT $opts -lpclient - UDP4-CONNECT:$LOCALHOST:$PORT" $PRINTF "test $F_n $TEST... " $N eval "$CMD0 2>${te}0 &" pids=$! waitudp4port "$PORT" echo "$da1" |eval "$CMD1" >"${tf}1" 2>"${te}1" if [ $? -ne 0 ]; then kill "$pids" 2>/dev/null $PRINTF "$NO_RESULT (first conn failed):\n" echo "$CMD0 &" cat "${te}0" >&2 echo "$CMD1" cat "${te}1" >&2 numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif ! echo "$da1" |diff - "${tf}1" >"$tdiff"; then kill "$pids" 2>/dev/null $PRINTF "$NO_RESULT (first conn failed); diff:\n" echo "$CMD0 &" cat "${te}0" >&2 echo "$CMD1" cat "${te}1" >&2 cat "$tdiff" numCANT=$((numCANT+1)) listCANT="$listCANT $N" else sleep 2 # UDP-LISTEN sleeps 1s echo "$da2" |eval "$CMD1" >"${tf}2" 2>"${te}2" rc="$?"; kill "$pids" 2>/dev/null if [ $rc -ne 0 ]; then $PRINTF "$FAILED:\n" echo "$CMD0 &" cat "${te}0" >&2 echo "$CMD1" cat "${te}1" >&2 numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" elif ! echo "$da2" |diff - "${tf}2" >"$tdiff"; then $PRINTF "$FAILED: diff\n" echo "$CMD0 &" cat "${te}0" >&2 echo "$CMD1" cat "${te}1" >&2 echo "diff:" cat "$tdiff" numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" else $PRINTF "$OK\n" if [ "$VERBOSE" ]; then echo "$CMD0 &"; fi if [ "$DEBUG" ]; then cat "${te}0" >&2; fi if [ "$VERBOSE" ]; then echo "$CMD1"; fi if [ "$DEBUG" ]; then cat "${te}1" >&2; fi numOK=$((numOK+1)) fi # !( $? -ne 0) fi # !(rc -ne 0) wait fi ;; # NUMCOND, feats esac N=$((N+1)) # Is a listen address capable of forking two child processes and have both # active? while read PROTOV MAJADDR MINADDR; do if [ -z "$PROTOV" ] || [[ "$PROTOV" == \#* ]]; then continue; fi protov="$(echo "$PROTOV" |tr A-Z a-z)" proto="${protov%%[0-9]}" NAME=${PROTOV}LISTENFORK case "$TESTS" in *%$N%*|*%functions%*|*%$protov%*|*%$proto%*|*%listen%*|*%fork%*|*%$NAME%*) TEST="$NAME: $PROTOV listen handles 2 concurrent connections" # Have a listening address with fork option. connect with client1, send a piece # of data, wait 1s, connect with client2, send another piece of data, wait 1s, # and send another piece of data with client1. The server processes append all # data to the same file. Check all data are written to the file in correct # order. if ! eval $NUMCOND; then :; #elif ! feat=$(testfeats $PROTOV); then # $PRINTF "test $F_n $TEST... ${YELLOW}$(echo "$PROTOV" |tr a-z A-Z) not available${NORMAL}\n" $N # numCANT=$((numCANT+1)) elif ! runs$protov >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}$PROTOV not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" else ts="$td/test$N.sock" tref="$td/test$N.ref" tf="$td/test$N.stdout" te="$td/test$N.stderr" tdiff="$td/test$N.diff" da1a="test$N $(date) 1a $RANDOM" da1b="test$N $(date) 1b $RANDOM" da2="test$N $(date) 2 $RANDOM" case "$MAJADDR" in "FILE") tla="$ts" tca="$ts" waitproto="file" waitfor="$ts" ;; esac case "$MINADDR" in "PORT") newport $protov # provide free port number in $PORT tla="$PORT,bind=$MAJADDR" tca="$MAJADDR:$PORT" waitproto="${protov}port" waitfor="$PORT" ;; esac #set -xv echo -e "$da1a\n$da2\n$da1b" >"$tref" # establish a listening and forking listen socket in background # UDP processes hang forever without -T CMD0="$TRACE $SOCAT -T 5 $opts -lpserver $PROTOV-LISTEN:$tla,$REUSEADDR,fork PIPE" # make a first and a second connection CMD1="$TRACE $SOCAT $opts -lpclient - $PROTOV-CONNECT:$tca" $PRINTF "test $F_n $TEST... " $N eval "$CMD0 2>${te}0 &" pid0=$! wait$waitproto "$waitfor" 1 2 (echo "$da1a"; sleep 2; echo "$da1b") |eval "$CMD1" >>"${tf}" 2>"${te}1" & sleep 1 # trailing sleep req for sctp because no half close (echo "$da2"; sleep 1) |eval "$CMD1" >>"${tf}" 2>"${te}2" & sleep 2 kill $pid0 2>/dev/null wait if ! diff "$tref" "$tf" >"$tdiff"; then $PRINTF "$FAILED\n" echo "$CMD0 &" cat "${te}0" >&2 echo "$CMD1 &" cat "${te}1" >&2 echo "$CMD1" cat "${te}2" >&2 cat "$tdiff" >&2 numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" else $PRINTF "$OK\n" if [ "$VERBOSE" ]; then echo "$CMD0 &"; fi if [ "$DEBUG" ]; then cat "${te}0" >&2; fi if [ "$VERBOSE" ]; then echo "$CMD1"; fi if [ "$DEBUG" ]; then cat "${te}1" >&2; fi if [ "$VERBOSE" ]; then echo "$CMD1"; fi if [ "$DEBUG" ]; then cat "${te}2" >&2; fi numOK=$((numOK+1)) fi # !(rc -ne 0) wait fi ;; # NUMCOND, feats esac N=$((N+1)) done <<<" TCP4 $LOCALHOST PORT TCP6 $LOCALHOST6 PORT UDP4 $LOCALHOST PORT UDP6 $LOCALHOST6 PORT SCTP4 $LOCALHOST PORT SCTP6 $LOCALHOST6 PORT UNIX FILE , " NAME=UNIXTOSTREAM case "$TESTS" in *%$N%*|*%functions%*|*%unix%*|*%listen%*|*%$NAME%*) TEST="$NAME: generic UNIX client connects to stream socket" if ! eval $NUMCOND; then :; else ts="$td/test$N.socket" tf="$td/test$N.stdout" te="$td/test$N.stderr" tdiff="$td/test$N.diff" da1="test$N $(date) $RANDOM" #establish a listening unix socket in background SRV="$TRACE $SOCAT $opts -lpserver UNIX-LISTEN:\"$ts\" PIPE" #make a connection CLI="$TRACE $SOCAT $opts -lpclient - UNIX:\"$ts\"" $PRINTF "test $F_n $TEST... " $N eval "$SRV 2>${te}s &" pids=$! waitfile "$ts" echo "$da1" |eval "$CLI" >"${tf}1" 2>"${te}1" if [ $? -ne 0 ]; then kill "$pids" 2>/dev/null $PRINTF "$FAILED:\n" echo "$SRV &" echo "$CLI" cat "${te}s" "${te}1" numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" elif ! echo "$da1" |diff - "${tf}1" >"$tdiff"; then kill "$pids" 2>/dev/null $PRINTF "$FAILED; diff:\n" cat "$tdiff" numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" else $PRINTF "$OK\n" numOK=$((numOK+1)) fi # !(rc -ne 0) wait fi ;; # NUMCOND esac N=$((N+1)) NAME=UNIXTODGRAM case "$TESTS" in *%$N%*|*%functions%*|*%engine%*|*%unix%*|*%recv%*|*%$NAME%*) TEST="$NAME: generic UNIX client connects to datagram socket" if ! eval $NUMCOND; then :; else ts1="$td/test$N.socket1" ts2="$td/test$N.socket2" tf="$td/test$N.stdout" te="$td/test$N.stderr" tdiff="$td/test$N.diff" da1="test$N $(date) $RANDOM" #establish a receiving unix datagram socket in background SRV="$TRACE $SOCAT $opts -lpserver UNIX-RECVFROM:\"$ts1\" PIPE" #make a connection CLI="$TRACE $SOCAT $opts -lpclient - UNIX:\"$ts1\",bind=\"$ts2\"" #CLI="$TRACE $SOCAT $opts -lpclient - UNIX:\"$ts1\"" $PRINTF "test $F_n $TEST... " $N eval "$SRV 2>${te}s &" pids=$! waitfile "$ts1" echo "$da1" |eval "$CLI" >"${tf}1" 2>"${te}1" rc=$? kill $pids 2>/dev/null wait if [ $rc -ne 0 ]; then kill "$pids" 2>/dev/null $PRINTF "$FAILED:\n" echo "$SRV &" cat "${te}s" echo "$CLI" cat "${te}1" "${te}1" numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" elif ! echo "$da1" |diff - "${tf}1" >"$tdiff"; then kill "$pids" 2>/dev/null $PRINTF "$FAILED:\n" echo "$SRV &" cat "${te}s" echo "$CLI" cat "${te}1" cat "$tdiff" numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" else $PRINTF "$OK\n" numOK=$((numOK+1)) fi # !(rc -ne 0) fi ;; # NUMCOND esac N=$((N+1)) # there was an error in address EXEC with options pipes,stderr NAME=EXECPIPESSTDERR case "$TESTS" in *%$N%*|*%functions%*|*%$NAME%*) TEST="$NAME: simple echo via exec of cat with pipes,stderr" # this test is known to fail when logging is enabled with OPTS/opts env var. SAVE_opts="$opts" opts="$(echo "$opts" |sed 's/-dd*//g')" testecho "$N" "$TEST" "" "EXEC:$CAT,pipes,stderr" "$opts" opts="$SAVE_opts" esac N=$((N+1)) # EXEC and SYSTEM with stderr injected socat messages into the data stream. NAME=EXECSTDERRLOG case "$TESTS" in *%$N%*|*%functions%*|*%$NAME%*) TEST="$NAME: simple echo via exec of cat with pipes,stderr" SAVE_opts="$opts" # make sure at least two -d are there case "$opts" in *-d*-d*) ;; *-d*) opts="$opts -d" ;; *) opts="-d -d" ;; esac testecho "$N" "$TEST" "" "exec:$CAT,pipes,stderr" "$opts" opts="$SAVE_opts" esac N=$((N+1)) NAME=SIMPLEPARSE case "$TESTS" in *%$N%*|*%functions%*|*%PARSE%*|*%$NAME%*) TEST="$NAME: invoke socat from socat" testecho "$N" "$TEST" "" exec:"$SOCAT - exec\:$CAT,pipes" "$opts" esac N=$((N+1)) NAME=FULLPARSE case "$TESTS" in *%$N%*|*%functions%*|*%parse%*|*%$NAME%*) TEST="$NAME: correctly parse special chars" if ! eval $NUMCOND; then :; else $PRINTF "test $F_n $TEST... " $N tf="$td/test$N.stdout" te="$td/test$N.stderr" tdiff="$td/test$N.diff" # a string where commas are hidden in nesting lexical constructs # if they are scanned incorrectly, socat will see an "unknown option" dain='(,)[,]{,}","([),])hugo' daout='(,)[,]{,},([),])hugo' $TRACE "$SOCAT" $opts -u "exec:echo $dain" - >"$tf" 2>"$te" rc=$? echo "$daout" |diff "$tf" - >"$tdiff" if [ "$rc" -ne 0 ]; then $PRINTF "$FAILED:\n" echo "$TRACE $SOCAT" -u "exec:echo $da" - cat "$te" numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" elif [ -s "$tdiff" ]; then $PRINTF "$FAILED:\n" echo diff: cat "$tdiff" if [ -n "$debug" ]; then cat $te; fi numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" else $PRINTF "$OK\n" if [ -n "$debug" ]; then cat $te; fi numOK=$((numOK+1)) fi fi ;; # NUMCOND esac N=$((N+1)) NAME=NESTEDSOCATEXEC case "$TESTS" in *%parse%*|*%$N%*|*%functions%*|*%$NAME%*) TEST="$NAME: does lexical analysis work sensibly (exec)" testecho "$N" "$TEST" "" "exec:'$SOCAT - exec:$CAT,pipes'" "$opts" 1 esac N=$((N+1)) NAME=NESTEDSOCATSYSTEM case "$TESTS" in *%parse%*|*%$N%*|*%functions%*|*%$NAME%*) TEST="$NAME: does lexical analysis work sensibly (system)" testecho "$N" "$TEST" "" "system:\"$SOCAT - exec:$CAT,pipes\"" "$opts" 1 esac N=$((N+1)) NAME=TCP6BYTCP4 case "$TESTS" in *%$N%*|*%functions%*|*%tcp%*|*%tcp6%*|*%ip6%*|*%listen%*|*%$NAME%*) TEST="$NAME: TCP4 mapped into TCP6 address space" if ! eval $NUMCOND; then :; elif true; then $PRINTF "test $F_n $TEST... ${YELLOW}Feature removed${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif ! testfeats tcp ip6 >/dev/null || ! runsip6 >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}TCP6 not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" else tf="$td/test$N.stdout" te="$td/test$N.stderr" tdiff="$td/test$N.diff" newport tcp6; tsl=$PORT ts="127.0.0.1:$tsl" da="test$N $(date) $RANDOM" CMD1="$TRACE $SOCAT $opts TCP6-LISTEN:$tsl,$REUSEADDR PIPE" CMD2="$TRACE $SOCAT $opts STDIN!!STDOUT TCP6:$ts" printf "test $F_n $TEST... " $N $CMD1 >"$tf" 2>"${te}1" & pid=$! # background process id waittcp6port $tsl 1 echo "$da" |$CMD2 >>"$tf" 2>>"${te}2" if [ $? -ne 0 ]; then $PRINTF "$FAILED: $TRACE $SOCAT:\n" echo "$CMD1 &" echo "$CMD2" cat "${te}1" cat "${te}2" numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" elif ! echo "$da" |diff - "$tf" >"$tdiff"; then $PRINTF "$FAILED: diff:\n" cat "$tdiff" numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" else $PRINTF "$OK\n" if [ -n "$debug" ]; then cat $te; fi numOK=$((numOK+1)) fi kill $pid 2>/dev/null; wait fi ;; # NUMCOND, feats esac N=$((N+1)) # test the UDP4-SENDTO and UDP4-RECVFROM addresses together NAME=UDP4DGRAM case "$TESTS" in *%$N%*|*%functions%*|*%udp%*|*%udp4%*|*%ip4%*|*%dgram%*|*%$NAME%*) TEST="$NAME: UDP/IPv4 sendto and recvfrom" # start a UDP4-RECVFROM process that echoes data, and send test data using # UDP4-SENDTO. The sent data should be returned. if ! eval $NUMCOND; then :; else tf="$td/test$N.stdout" te="$td/test$N.stderr" tdiff="$td/test$N.diff" newport udp4; ts1p=$PORT ts1a="127.0.0.1" ts1="$ts1a:$ts1p" newport udp4; ts2p=$PORT ts2="127.0.0.1:$ts2p" da="test$N $(date) $RANDOM" CMD1="$TRACE $SOCAT $opts UDP4-RECVFROM:$ts1p,reuseaddr,bind=$ts1a PIPE" CMD2="$TRACE $SOCAT $opts - UDP4-SENDTO:$ts1,bind=$ts2" printf "test $F_n $TEST... " $N $CMD1 2>"${te}1" & pid1="$!" waitudp4port $ts1p 1 echo "$da" |$CMD2 >>"$tf" 2>>"${te}2" rc2="$?" kill "$pid1" 2>/dev/null; wait; if [ "$rc2" -ne 0 ]; then $PRINTF "$FAILED: $TRACE $SOCAT:\n" echo "$CMD1 &" cat "${te}1" echo "$CMD2" cat "${te}2" numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" elif ! echo "$da" |diff - "$tf" >"$tdiff"; then $PRINTF "$FAILED\n" cat "$tdiff" echo "$CMD1 &" cat "${te}1" echo "$CMD2" cat "${te}2" numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" else $PRINTF "$OK\n" if [ -n "$debug" ]; then cat $te; fi numOK=$((numOK+1)) fi fi # NUMCOND ;; esac N=$((N+1)) NAME=UDP6DGRAM case "$TESTS" in *%$N%*|*%functions%*|*%udp%*|*%udp6%*|*%ip6%*|*%dgram%*|*%$NAME%*) TEST="$NAME: UDP/IPv6 datagram" if ! eval $NUMCOND; then :; elif ! feat=$(testfeats tcp ip6) || ! runsip6 >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}TCP6 not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" else tf="$td/test$N.stdout" te="$td/test$N.stderr" tdiff="$td/test$N.diff" newport udp6; ts1p=$PORT tsa="[::1]" ts1="$tsa:$ts1p" newport udp6; ts2p=$PORT ts2="$tsa:$ts2p" da="test$N $(date) $RANDOM" CMD1="$TRACE $SOCAT $opts UDP6-RECVFROM:$ts1p,reuseaddr,bind=$tsa PIPE" CMD2="$TRACE $SOCAT $opts - UDP6-SENDTO:$ts1,bind=$ts2" printf "test $F_n $TEST... " $N $CMD1 2>"${te}1" & waitudp6port $ts1p 1 echo "$da" |$CMD2 >>"$tf" 2>>"${te}2" if [ $? -ne 0 ]; then $PRINTF "$FAILED: $TRACE $SOCAT:\n" echo "$CMD1 &" echo "$CMD2" cat "${te}1" cat "${te}2" numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" elif ! echo "$da" |diff - "$tf" >"$tdiff"; then $PRINTF "$FAILED\n" cat "$tdiff" numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" else $PRINTF "$OK\n" if [ -n "$debug" ]; then cat ${te}1 ${te}2; fi numOK=$((numOK+1)) fi fi ;; # NUMCOND, feats esac N=$((N+1)) NAME=RAWIP4RECVFROM case "$TESTS" in *%$N%*|*%functions%*|*%ip%*|*%ip4%*|*%rawip%*|*%rawip4%*|*%dgram%*|*%root%*|*%$NAME%*) TEST="$NAME: raw IPv4 datagram" if ! eval $NUMCOND; then :; elif [ $(id -u) -ne 0 -a "$withroot" -eq 0 ]; then $PRINTF "test $F_n $TEST... ${YELLOW}must be root${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" else tf="$td/test$N.stdout" te="$td/test$N.stderr" tdiff="$td/test$N.diff" ts1p=$PROTO; PROTO=$((PROTO+1)) ts1a="127.0.0.1" ts1="$ts1a:$ts1p" ts2a="$SECONDADDR" ts2="$ts2a:$ts2p" da="test$N $(date) $RANDOM" CMD1="$TRACE $SOCAT $opts IP4-RECVFROM:$ts1p,reuseaddr,bind=$ts1a PIPE" CMD2="$TRACE $SOCAT $opts - IP4-SENDTO:$ts1,bind=$ts2a" printf "test $F_n $TEST... " $N $CMD1 2>"${te}1" & pid1=$! waitip4proto $ts1p 1 echo "$da" |$CMD2 >>"$tf" 2>>"${te}2" rc2=$? kill $pid1 2>/dev/null; wait if [ $rc2 -ne 0 ]; then $PRINTF "$FAILED: $TRACE $SOCAT:\n" echo "$CMD1 &" echo "$CMD2" cat "${te}1" cat "${te}2" numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" elif ! echo "$da" |diff - "$tf" >"$tdiff"; then $PRINTF "$FAILED\n" cat "$tdiff" numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" else $PRINTF "$OK\n" if [ -n "$debug" ]; then cat $te; fi numOK=$((numOK+1)) fi fi ;; # root, NUMCOND esac N=$((N+1)) if false; then NAME=RAWIP6RECVFROM case "$TESTS" in *%$N%*|*%functions%*|*%ip%*|*%ip6%*|*%rawip%*|*%rawip6%*|*%dgram%*|*%root%*|*%$NAME%*) TEST="$NAME: raw IPv6 datagram by self addressing" if ! eval $NUMCOND; then :; elif ! feat=$(testfeats ip6 rawip && runsip6); then $PRINTF "test $F_n $TEST... ${YELLOW}$feat not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif [ $(id -u) -ne 0 -a "$withroot" -eq 0 ]; then $PRINTF "test $F_n $TEST... ${YELLOW}must be root${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" else tf="$td/test$N.stdout" te="$td/test$N.stderr" tdiff="$td/test$N.diff" ts1p=$PROTO; PROTO=$((PROTO+1)) tsa="[::1]" ts1="$tsa:$ts1p" ts2="$tsa" da="test$N $(date) $RANDOM" #CMD1="$TRACE $SOCAT $opts IP6-RECVFROM:$ts1p,reuseaddr,bind=$tsa PIPE" CMD2="$TRACE $SOCAT $opts - IP6-SENDTO:$ts1,bind=$ts2" printf "test $F_n $TEST... " $N #$CMD1 2>"${te}1" & waitip6proto $ts1p 1 echo "$da" |$CMD2 >>"$tf" 2>>"${te}2" if [ $? -ne 0 ]; then $PRINTF "$FAILED: $TRACE $SOCAT:\n" # echo "$CMD1 &" # cat "${te}1" echo "$CMD2" cat "${te}2" numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" elif ! echo "$da" |diff - "$tf" >"$tdiff"; then $PRINTF "$FAILED\n" cat "$tdiff" numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" else $PRINTF "$OK\n" if [ -n "$debug" ]; then cat "$te"; fi numOK=$((numOK+1)) fi fi ;; # root, NUMCOND esac N=$((N+1)) fi #false NAME=UNIXDGRAM case "$TESTS" in *%$N%*|*%functions%*|*%engine%*|*%unix%*|*%dgram%*|*%$NAME%*) TEST="$NAME: UNIX datagram" if ! eval $NUMCOND; then :; else tf="$td/test$N.stdout" te="$td/test$N.stderr" tdiff="$td/test$N.diff" ts1="$td/test$N.socket1" ts2="$td/test$N.socket2" da="test$N $(date) $RANDOM" CMD1="$TRACE $SOCAT $opts UNIX-RECVFROM:$ts1,reuseaddr PIPE" CMD2="$TRACE $SOCAT $opts - UNIX-SENDTO:$ts1,bind=$ts2" printf "test $F_n $TEST... " $N $CMD1 2>"${te}1" & pid1="$!" waitfile $ts1 1 echo "$da" |$CMD2 >>"$tf" 2>>"${te}2" rc2=$? kill "$pid1" 2>/dev/null; wait if [ $rc2 -ne 0 ]; then $PRINTF "$FAILED (rc=$rc2)\n" echo "$CMD1 &" cat "${te}1" >&2 echo "$CMD2" cat "${te}2" >&2 numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" elif ! echo "$da" |diff - "$tf" >"$tdiff"; then $PRINTF "$FAILED (diff)\n" echo "$CMD1 &" cat "${te}1" >&2 echo "$CMD2" cat "${te}2" >&2 echo "// diff:" >&2 cat "$tdiff" >&2 numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" else $PRINTF "$OK\n" if [ "$VERBOSE" ]; then echo "$CMD1 &"; fi if [ "$DEBUG" ]; then cat "${te}1" >&2; fi if [ "$VERBOSE" ]; then echo "$CMD2"; fi if [ "$DEBUG" ]; then cat "${te}2" >&2; fi numOK=$((numOK+1)) fi fi # NUMCOND ;; esac N=$((N+1)) NAME=UDP4RECV case "$TESTS" in *%$N%*|*%functions%*|*%engine%*|*%ip4%*|*%dgram%*|*%udp%*|*%udp4%*|*%recv%*|*%$NAME%*) TEST="$NAME: UDP/IPv4 receive" if ! eval $NUMCOND; then :; else tf="$td/test$N.stdout" te="$td/test$N.stderr" tdiff="$td/test$N.diff" newport udp4; ts1p=$PORT ts1a="127.0.0.1" ts1="$ts1a:$ts1p" da="test$N $(date) $RANDOM" CMD1="$TRACE $SOCAT $opts -u UDP4-RECV:$ts1p,reuseaddr -" CMD2="$TRACE $SOCAT $opts -u - UDP4-SENDTO:$ts1" printf "test $F_n $TEST... " $N $CMD1 >"$tf" 2>"${te}1" & pid1="$!" waitudp4port $ts1p 1 echo "$da" |$CMD2 2>>"${te}2" rc2="$?" #ls -l $tf i=0; while [ ! -s "$tf" -a "$i" -lt 10 ]; do usleep 100000; i=$((i+1)); done kill "$pid1" 2>/dev/null; wait if [ "$rc2" -ne 0 ]; then $PRINTF "$FAILED: $TRACE $SOCAT:\n" echo "$CMD1 &" echo "$CMD2" cat "${te}1" cat "${te}2" numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" elif ! echo "$da" |diff - "$tf" >"$tdiff"; then $PRINTF "$FAILED\n" cat "$tdiff" echo "$CMD1 &" echo "$CMD2" cat "${te}1" cat "${te}2" numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" else $PRINTF "$OK\n" if [ -n "$debug" ]; then cat $te; fi numOK=$((numOK+1)) fi fi # NUMCOND ;; esac N=$((N+1)) NAME=UDP6RECV case "$TESTS" in *%$N%*|*%functions%*|*%ip6%*|*%dgram%*|*%udp%*|*%udp6%*|*%recv%*|*%$NAME%*) TEST="$NAME: UDP/IPv6 receive" if ! eval $NUMCOND; then :; elif ! feat=$(testfeats tcp ip6) || ! runsip6 >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}TCP6 not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" else tf="$td/test$N.stdout" te="$td/test$N.stderr" tdiff="$td/test$N.diff" newport udp6; ts1p=$PORT ts1a="[::1]" ts1="$ts1a:$ts1p" da="test$N $(date) $RANDOM" CMD1="$TRACE $SOCAT $opts -u UDP6-RECV:$ts1p,reuseaddr -" CMD2="$TRACE $SOCAT $opts -u - UDP6-SENDTO:$ts1" printf "test $F_n $TEST... " $N $CMD1 >"$tf" 2>"${te}1" & pid1="$!" waitudp6port $ts1p 1 echo "$da" |$CMD2 2>>"${te}2" rc2="$?" #ls -l $tf i=0; while [ ! -s "$tf" -a "$i" -lt 10 ]; do usleep 100000; i=$((i+1)); done kill "$pid1" 2>/dev/null; wait if [ "$rc2" -ne 0 ]; then $PRINTF "$FAILED: $TRACE $SOCAT:\n" echo "$CMD1 &" echo "$CMD2" cat "${te}1" cat "${te}2" numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" elif ! echo "$da" |diff - "$tf" >"$tdiff"; then $PRINTF "$FAILED\n" cat "$tdiff" numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" else $PRINTF "$OK\n" if [ -n "$debug" ]; then cat $te; fi numOK=$((numOK+1)) fi fi ;; # NUMCOND, feats esac N=$((N+1)) NAME=RAWIP4RECV case "$TESTS" in *%$N%*|*%functions%*|*%ip4%*|*%dgram%*|*%rawip%*|*%rawip4%*|*%recv%*|*%root%*|*%$NAME%*) TEST="$NAME: raw IPv4 receive" if ! eval $NUMCOND; then :; elif [ $(id -u) -ne 0 -a "$withroot" -eq 0 ]; then $PRINTF "test $F_n $TEST... ${YELLOW}must be root${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" else tf="$td/test$N.stdout" te="$td/test$N.stderr" tdiff="$td/test$N.diff" ts1p=$PROTO; PROTO=$((PROTO+1)) ts1a="127.0.0.1" ts1="$ts1a:$ts1p" da="test$N $(date) $RANDOM" CMD1="$TRACE $SOCAT $opts -u IP4-RECV:$ts1p,reuseaddr -" CMD2="$TRACE $SOCAT $opts -u - IP4-SENDTO:$ts1" printf "test $F_n $TEST... " $N $CMD1 >"$tf" 2>"${te}1" & pid1="$!" waitip4proto $ts1p 1 echo "$da" |$CMD2 2>>"${te}2" rc2="$?" #ls -l $tf i=0; while [ ! -s "$tf" -a "$i" -lt 10 ]; do usleep 100000; i=$((i+1)); done kill "$pid1" 2>/dev/null; wait if [ "$rc2" -ne 0 ]; then $PRINTF "$FAILED: $TRACE $SOCAT:\n" echo "$CMD1 &" echo "$CMD2" cat "${te}1" cat "${te}2" numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" elif ! echo "$da" |diff - "$tf" >"$tdiff"; then $PRINTF "$FAILED\n" cat "$tdiff" numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" else $PRINTF "$OK\n" if [ -n "$debug" ]; then cat $te; fi numOK=$((numOK+1)) fi fi ;; # NUMCOND, root esac N=$((N+1)) NAME=RAWIP6RECV case "$TESTS" in *%$N%*|*%functions%*|*%ip6%*|*%dgram%*|*%rawip%*|*%rawip6%*|*%recv%*|*%root%*|*%$NAME%*) TEST="$NAME: raw IPv6 receive" if ! eval $NUMCOND; then :; elif ! feat=$(testfeats ip6 rawip && runsip6); then $PRINTF "test $F_n $TEST... ${YELLOW}$feat not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif [ $(id -u) -ne 0 -a "$withroot" -eq 0 ]; then $PRINTF "test $F_n $TEST... ${YELLOW}must be root${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" else tf="$td/test$N.stdout" te="$td/test$N.stderr" tdiff="$td/test$N.diff" ts1p=$PROTO; PROTO=$((PROTO+1)) ts1a="[::1]" ts1="$ts1a:$ts1p" da="test$N $(date) $RANDOM" CMD1="$TRACE $SOCAT $opts -u IP6-RECV:$ts1p,reuseaddr -" CMD2="$TRACE $SOCAT $opts -u - IP6-SENDTO:$ts1" printf "test $F_n $TEST... " $N $CMD1 >"$tf" 2>"${te}1" & pid1="$!" waitip6proto $ts1p 1 echo "$da" |$CMD2 2>>"${te}2" rc2="$?" i=0; while [ ! -s "$tf" -a "$i" -lt 10 ]; do usleep 100000; i=$((i+1)); done kill "$pid1" 2>/dev/null; wait if [ "$rc2" -ne 0 ]; then $PRINTF "$FAILED: $TRACE $SOCAT:\n" echo "$CMD1 &" echo "$CMD2" cat "${te}1" cat "${te}2" numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" elif ! echo "$da" |diff - "$tf" >"$tdiff"; then $PRINTF "$FAILED\n" cat "$tdiff" numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" else $PRINTF "$OK\n" if [ -n "$debug" ]; then cat $te; fi numOK=$((numOK+1)) fi fi ;; # NUMCOND, root esac N=$((N+1)) NAME=UNIXRECV case "$TESTS" in *%$N%*|*%functions%*|*%unix%*|*%dgram%*|*%recv%*|*%$NAME%*) TEST="$NAME: UNIX receive" if ! eval $NUMCOND; then :; else ts="$td/test$N.socket" tf="$td/test$N.stdout" te="$td/test$N.stderr" tdiff="$td/test$N.diff" ts1="$ts" da="test$N $(date) $RANDOM" CMD1="$TRACE $SOCAT $opts -u UNIX-RECV:$ts1,reuseaddr -" CMD2="$TRACE $SOCAT $opts -u - UNIX-SENDTO:$ts1" printf "test $F_n $TEST... " $N $CMD1 >"$tf" 2>"${te}1" & pid1="$!" waitfile $ts1 1 echo "$da" |$CMD2 2>>"${te}2" rc2="$?" i=0; while [ ! -s "$tf" -a "$i" -lt 10 ]; do usleep 100000; i=$((i+1)); done kill "$pid1" 2>/dev/null; wait if [ "$rc2" -ne 0 ]; then $PRINTF "$FAILED: $TRACE $SOCAT:\n" echo "$CMD1 &" echo "$CMD2" cat "${te}1" cat "${te}2" numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" elif ! echo "$da" |diff - "$tf" >"$tdiff"; then $PRINTF "$FAILED\n" cat "$tdiff" numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" else $PRINTF "$OK\n" if [ -n "$debug" ]; then cat $te; fi numOK=$((numOK+1)) fi fi # NUMCOND ;; esac N=$((N+1)) NAME=UDP4RECVFROM_SOURCEPORT case "$TESTS" in *%$N%*|*%functions%*|*%security%*|*%udp%*|*%udp4%*|*%ip4%*|*%sourceport%*|*%$NAME%*) TEST="$NAME: security of UDP4-RECVFROM with SOURCEPORT option" if ! eval $NUMCOND; then :; elif ! feat=$(testfeats udp ip4) || ! runsip4 >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}UDP4 not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" else newport udp4 # provide free port number in $PORT testserversec "$N" "$TEST" "$opts" "UDP4-RECVFROM:$PORT,reuseaddr" "" "sp=$PORT" "UDP4-SENDTO:127.0.0.1:$PORT" 4 udp $PORT 0 fi ;; # NUMCOND, feats esac N=$((N+1)) NAME=UDP4RECVFROM_LOWPORT case "$TESTS" in *%$N%*|*%functions%*|*%security%*|*%udp%*|*%udp4%*|*%ip4%*|*%lowport%*|*%$NAME%*) TEST="$NAME: security of UDP4-RECVFROM with LOWPORT option" if ! eval $NUMCOND; then :; elif ! feat=$(testfeats udp ip4) || ! runsip4 >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}UDP4 not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" else newport udp4 # provide free port number in $PORT testserversec "$N" "$TEST" "$opts" "UDP4-RECVFROM:$PORT,reuseaddr" "" "lowport" "UDP4-SENDTO:127.0.0.1:$PORT" 4 udp $PORT 0 fi ;; # NUMCOND, feats esac N=$((N+1)) NAME=UDP4RECVFROM_RANGE case "$TESTS" in *%$N%*|*%functions%*|*%security%*|*%fork%*|*%udp%*|*%udp4%*|*%ip4%*|*%range%*|*%$NAME%*) TEST="$NAME: security of UDP4-RECVFROM with RANGE option" newport udp4 # provide free port number in $PORT #testserversec "$N" "$TEST" "$opts" "UDP4-RECVFROM:$PORT,reuseaddr,fork" "" "range=$SECONDADDR/32" "UDP4-SENDTO:127.0.0.1:$PORT" 4 udp $PORT 0 if ! eval $NUMCOND; then :; else testserversec "$N" "$TEST" "$opts" "UDP4-RECVFROM:$PORT,reuseaddr" "" "range=$SECONDADDR/32" "UDP4-SENDTO:127.0.0.1:$PORT" 4 udp $PORT 0 fi ;; # NUMCOND esac N=$((N+1)) NAME=UDP4RECVFROM_TCPWRAP case "$TESTS" in *%$N%*|*%functions%*|*%security%*|*%fork%*|*%udp%*|*%udp4%*|*%ip4%*|*%tcpwrap%*|*%$NAME%*) TEST="$NAME: security of UDP4-RECVFROM with TCPWRAP option" if ! eval $NUMCOND; then :; elif ! feat=$(testfeats ip4 udp libwrap) || ! runsip4 >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}$feat not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" else ha="$td/hosts.allow" hd="$td/hosts.deny" $ECHO "socat: $SECONDADDR" >"$ha" $ECHO "ALL: ALL" >"$hd" newport udp4 # provide free port number in $PORT #testserversec "$N" "$TEST" "$opts" "UDP4-RECVFROM:$PORT,reuseaddr,fork" "" "tcpwrap=$d" "UDP4-SENDTO:127.0.0.1:$PORT" 4 udp $PORT 0 testserversec "$N" "$TEST" "$opts" "UDP4-RECVFROM:$PORT,reuseaddr" "" "tcpwrap-etc=$td" "UDP4-SENDTO:127.0.0.1:$PORT" 4 udp $PORT 0 fi ;; # NUMCOND, feats esac N=$((N+1)) NAME=UDP4RECV_SOURCEPORT case "$TESTS" in *%$N%*|*%functions%*|*%security%*|*%udp%*|*%udp4%*|*%ip4%*|*%sourceport%*|*%$NAME%*) TEST="$NAME: security of UDP4-RECV with SOURCEPORT option" if ! eval $NUMCOND; then :; elif ! feat=$(testfeats udp ip4) || ! runsip4 >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}UDP4 not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" else newport udp4; PORT1=$PORT newport udp4; PORT2=$PORT newport udp4; PORT3=$PORT # we use the forward channel (PORT1) for testing, and have a backward channel # (PORT2) to get the data back, so we get the classical echo behaviour testserversec "$N" "$TEST" "$opts" "UDP4-RECV:$PORT1,reuseaddr!!UDP4-SENDTO:127.0.0.1:$PORT2" "" "sp=$PORT3" "UDP4-RECV:$PORT2!!UDP4-SENDTO:127.0.0.1:$PORT1" 4 udp $PORT1 0 fi ;; # NUMCOND, feats esac N=$((N+1)) NAME=UDP4RECV_LOWPORT case "$TESTS" in *%$N%*|*%functions%*|*%security%*|*%udp%*|*%udp4%*|*%ip4%*|*%lowport%*|*%$NAME%*) TEST="$NAME: security of UDP4-RECV with LOWPORT option" if ! eval $NUMCOND; then :; elif ! feat=$(testfeats udp ip4) || ! runsip4 >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}UDP4 not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" else newport udp4; PORT1=$PORT newport udp4; PORT2=$PORT # we use the forward channel (PORT1) for testing, and have a backward channel # (PORT2) to get the data back, so we get the classical echo behaviour testserversec "$N" "$TEST" "$opts" "UDP4-RECV:$PORT1,reuseaddr!!UDP4-SENDTO:127.0.0.1:$PORT2" "" "lowport" "UDP4-RECV:$PORT2!!UDP4-SENDTO:127.0.0.1:$PORT1" 4 udp $PORT1 0 fi ;; # NUMCOND, feats esac N=$((N+1)) NAME=UDP4RECV_RANGE case "$TESTS" in *%$N%*|*%functions%*|*%security%*|*%udp%*|*%udp4%*|*%ip4%*|*%range%*|*%$NAME%*) TEST="$NAME: security of UDP4-RECV with RANGE option" if ! eval $NUMCOND; then :; elif ! feat=$(testfeats udp ip4) || ! runsip4 >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}UDP4 not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" else newport udp4; PORT1=$PORT newport udp4; PORT2=$PORT # we use the forward channel (PORT1) for testing, and have a backward channel # (PORT2) to get the data back, so we get the classical echo behaviour testserversec "$N" "$TEST" "$opts" "UDP4-RECV:$PORT1,reuseaddr!!UDP4-SENDTO:127.0.0.1:$PORT2" "" "range=$SECONDADDR/32" "UDP4-RECV:$PORT2!!UDP4-SENDTO:127.0.0.1:$PORT1" 4 udp $PORT1 0 fi ;; # NUMCOND, feats esac N=$((N+1)) NAME=UDP4RECV_TCPWRAP case "$TESTS" in *%$N%*|*%functions%*|*%security%*|*%udp%*|*%udp4%*|*%ip4%*|*%tcpwrap%*|*%$NAME%*) TEST="$NAME: security of UDP4-RECV with TCPWRAP option" if ! eval $NUMCOND; then :; elif ! feat=$(testfeats udp ip4 libwrap) || ! runsip4 >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}$feat not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" else newport udp4; PORT1=$PORT newport udp4; PORT2=$PORT ha="$td/hosts.allow" hd="$td/hosts.deny" $ECHO "socat: $SECONDADDR" >"$ha" $ECHO "ALL: ALL" >"$hd" # we use the forward channel (PORT1) for testing, and have a backward channel # (PORT2) to get the data back, so we get the classical echo behaviour testserversec "$N" "$TEST" "$opts" "UDP4-RECV:$PORT1,reuseaddr!!UDP4-SENDTO:127.0.0.1:$PORT2" "" "tcpwrap-etc=$td" "UDP4-RECV:$PORT2!!UDP4-SENDTO:127.0.0.1:$PORT1" 4 udp $PORT1 0 fi ;; # NUMCOND, feats esac N=$((N+1)) NAME=UDP6RECVFROM_SOURCEPORT case "$TESTS" in *%$N%*|*%functions%*|*%security%*|*%udp%*|*%udp6%*|*%ip6%*|*%sourceport%*|*%$NAME%*) TEST="$NAME: security of UDP6-RECVFROM with SOURCEPORT option" if ! eval $NUMCOND; then :; elif ! feat=$(testfeats udp ip6) || ! runsip6 >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}UDP6 not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" else newport udp6 # provide free port number in $PORT testserversec "$N" "$TEST" "$opts" "UDP6-RECVFROM:$PORT,reuseaddr" "" "sp=$PORT" "UDP6-SENDTO:[::1]:$PORT" 6 udp $PORT 0 fi ;; # NUMCOND, feats esac N=$((N+1)) NAME=UDP6RECVFROM_LOWPORT case "$TESTS" in *%$N%*|*%functions%*|*%security%*|*%udp%*|*%udp6%*|*%ip6%*|*%lowport%*|*%$NAME%*) TEST="$NAME: security of UDP6-RECVFROM with LOWPORT option" if ! eval $NUMCOND; then :; elif ! feat=$(testfeats udp ip6) || ! runsip6 >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}UDP6 not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" else newport udp6 # provide free port number in $PORT testserversec "$N" "$TEST" "$opts" "UDP6-RECVFROM:$PORT,reuseaddr" "" "lowport" "UDP6-SENDTO:[::1]:$PORT" 6 udp $PORT 0 fi ;; # NUMCOND, feats esac N=$((N+1)) NAME=UDP6RECVFROM_RANGE case "$TESTS" in *%$N%*|*%functions%*|*%security%*|*%fork%*|*%udp%*|*%udp6%*|*%ip6%*|*%range%*|*%$NAME%*) TEST="$NAME: security of UDP6-RECVFROM with RANGE option" if ! eval $NUMCOND; then :; elif ! feat=$(testfeats tcp ip6) || ! runsip6 >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}TCP6 not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" else newport udp6 # provide free port number in $PORT #testserversec "$N" "$TEST" "$opts" "UDP6-RECVFROM:$PORT,reuseaddr,fork" "" "range=[::2]/128" "UDP6-SENDTO:[::1]:$PORT" 6 udp $PORT 0 testserversec "$N" "$TEST" "$opts" "UDP6-RECVFROM:$PORT,reuseaddr" "" "range=[::2]/128" "UDP6-SENDTO:[::1]:$PORT" 6 udp $PORT 0 fi ;; # NUMCOND, feats esac N=$((N+1)) NAME=UDP6RECVFROM_TCPWRAP case "$TESTS" in *%$N%*|*%functions%*|*%security%*|*%udp%*|*%udp6%*|*%ip6%*|*%tcpwrap%*|*%$NAME%*) TEST="$NAME: security of UDP6-RECVFROM with TCPWRAP option" if ! eval $NUMCOND; then :; elif ! feat=$(testfeats udp ip6 libwrap && runsip6); then $PRINTF "test $F_n $TEST... ${YELLOW}$feat not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" else ha="$td/hosts.allow" hd="$td/hosts.deny" $ECHO "socat: [::2]" >"$ha" $ECHO "ALL: ALL" >"$hd" newport udp6 # provide free port number in $PORT testserversec "$N" "$TEST" "$opts" "UDP6-RECVFROM:$PORT,reuseaddr" "" "tcpwrap-etc=$td" "UDP6-SENDTO:[::1]:$PORT" 6 udp $PORT 0 fi ;; # NUMCOND, feats esac N=$((N+1)) NAME=UDP6RECV_SOURCEPORT case "$TESTS" in *%$N%*|*%functions%*|*%security%*|*%udp%*|*%udp6%*|*%ip6%*|*%sourceport%*|*%$NAME%*) TEST="$NAME: security of UDP6-RECV with SOURCEPORT option" if ! eval $NUMCOND; then :; elif ! feat=$(testfeats udp ip6) || ! runsip6 >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}UDP6 not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" else newport udp6; PORT1=$PORT newport udp6; PORT2=$PORT newport udp6; PORT3=$PORT # we use the forward channel (PORT1) for testing, and have a backward channel # (PORT2) to get the data back, so we get the classical echo behaviour testserversec "$N" "$TEST" "$opts" "UDP6-RECV:$PORT1,reuseaddr!!UDP6-SENDTO:[::1]:$PORT2" "" "sp=$PORT3" "UDP6-RECV:$PORT2!!UDP6-SENDTO:[::1]:$PORT1" 6 udp $PORT1 0 fi ;; # NUMCOND, feats esac N=$((N+1)) NAME=UDP6RECV_LOWPORT case "$TESTS" in *%$N%*|*%functions%*|*%security%*|*%udp%*|*%udp6%*|*%ip6%*|*%lowport%*|*%$NAME%*) TEST="$NAME: security of UDP6-RECV with LOWPORT option" if ! eval $NUMCOND; then :; elif ! feat=$(testfeats udp ip6) || ! runsip6 >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}UDP6 not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" else newport udp6; PORT1=$PORT newport udp6; PORT2=$PORT # we use the forward channel (PORT1) for testing, and have a backward channel # (PORT2) to get the data back, so we get the classical echo behaviour testserversec "$N" "$TEST" "$opts" "UDP6-RECV:$PORT1,reuseaddr!!UDP6-SENDTO:[::1]:$PORT2" "" "lowport" "UDP6-RECV:$PORT2!!UDP6-SENDTO:[::1]:$PORT1" 6 udp $PORT1 0 fi ;; # NUMCOND, feats esac N=$((N+1)) NAME=UDP6RECV_RANGE case "$TESTS" in *%$N%*|*%functions%*|*%security%*|*%udp%*|*%udp6%*|*%ip6%*|*%range%*|*%$NAME%*) TEST="$NAME: security of UDP6-RECV with RANGE option" if ! eval $NUMCOND; then :; elif ! feat=$(testfeats udp ip6) || ! runsip6 >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}UDP6 not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" else newport udp6; PORT1=$PORT newport udp6; PORT2=$PORT # we use the forward channel (PORT1) for testing, and have a backward channel # (PORT2) to get the data back, so we get the classical echo behaviour testserversec "$N" "$TEST" "$opts" "UDP6-RECV:$PORT1,reuseaddr!!UDP6-SENDTO:[::1]:$PORT2" "" "range=[::2]/128" "UDP6-RECV:$PORT2!!UDP6-SENDTO:[::1]:$PORT1" 6 udp $PORT1 0 fi ;; # NUMCOND, feats esac N=$((N+1)) NAME=UDP6RECV_TCPWRAP case "$TESTS" in *%$N%*|*%functions%*|*%security%*|*%udp%*|*%udp6%*|*%ip6%*|*%tcpwrap%*|*%$NAME%*) TEST="$NAME: security of UDP6-RECV with TCPWRAP option" if ! eval $NUMCOND; then :; elif ! feat=$(testfeats udp ip6 libwrap && runsip6); then $PRINTF "test $F_n $TEST... ${YELLOW}$feat not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" else ha="$td/hosts.allow" hd="$td/hosts.deny" $ECHO "socat: [::2]" >"$ha" $ECHO "ALL: ALL" >"$hd" newport udp6; PORT1=$PORT newport udp6; PORT2=$PORT # we use the forward channel (PORT1) for testing, and have a backward channel # (PORT2) to get the data back, so we get the classical echo behaviour testserversec "$N" "$TEST" "$opts" "UDP6-RECV:$PORT1,reuseaddr!!UDP6-SENDTO:[::1]:$PORT2" "" "tcpwrap-etc=$td" "UDP6-RECV:$PORT2!!UDP6-SENDTO:[::1]:$PORT1" 6 udp $PORT1 0 fi ;; # NUMCOND, feats esac N=$((N+1)) NAME=IP4RECVFROM_RANGE case "$TESTS" in *%$N%*|*%functions%*|*%security%*|*%fork%*|*%ip%*|*%ip4%*|*%range%*|*%root%*|*%$NAME%*) TEST="$NAME: security of IP4-RECVFROM with RANGE option" if ! eval $NUMCOND; then :; elif ! feat=$(testfeats ip4 rawip) || ! runsip4 >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}$feat not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif [ $(id -u) -ne 0 -a "$withroot" -eq 0 ]; then $PRINTF "test $F_n $TEST... ${YELLOW}must be root${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" else newport udp4 # provide free port number in $PORT #testserversec "$N" "$TEST" "$opts" "IP4-RECVFROM:$PROTO,reuseaddr,fork" "" "range=$SECONDADDR/32" "IP4-SENDTO:127.0.0.1:$PROTO" 4 ip $PROTO 0 testserversec "$N" "$TEST" "$opts" "IP4-RECVFROM:$PROTO,reuseaddr!!UDP4-SENDTO:127.0.0.1:$PORT" "" "range=$SECONDADDR/32" "UDP4-RECV:$PORT!!IP4-SENDTO:127.0.0.1:$PROTO" 4 ip $PROTO 0 fi ;; # NUMCOND, feats, root esac PROTO=$((PROTO+1)) N=$((N+1)) NAME=IP4RECVFROM_TCPWRAP case "$TESTS" in *%$N%*|*%functions%*|*%security%*|*%fork%*|*%ip%*|*%ip4%*|*%tcpwrap%*|*%root%*|*%$NAME%*) TEST="$NAME: security of IP4-RECVFROM with TCPWRAP option" if ! eval $NUMCOND; then :; elif ! feat=$(testfeats ip4 rawip libwrap) || ! runsip4 >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}$feat not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif [ $(id -u) -ne 0 -a "$withroot" -eq 0 ]; then $PRINTF "test $F_n $TEST... ${YELLOW}must be root${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" else ha="$td/hosts.allow" hd="$td/hosts.deny" $ECHO "socat: $SECONDADDR" >"$ha" $ECHO "ALL: ALL" >"$hd" newport udp4 # provide free port number in $PORT #testserversec "$N" "$TEST" "$opts" "IP4-RECVFROM:$PROTO,reuseaddr,fork" "" "tcpwrap-etc=$td" "IP4-SENDTO:127.0.0.1:$PROTO" 4 ip $PROTO 0 testserversec "$N" "$TEST" "$opts" "IP4-RECVFROM:$PROTO,reuseaddr!!UDP4-SENDTO:127.0.0.1:$PORT" "" "tcpwrap-etc=$td" "UDP4-RECV:$PORT!!IP4-SENDTO:127.0.0.1:$PROTO" 4 ip $PROTO 0 fi # NUMCOND, feats, root ;; esac PROTO=$((PROTO+1)) N=$((N+1)) NAME=IP4RECV_RANGE case "$TESTS" in *%$N%*|*%functions%*|*%security%*|*%ip%*|*%ip4%*|*%range%*|*%root%*|*%$NAME%*) TEST="$NAME: security of IP4-RECV with RANGE option" if ! eval $NUMCOND; then :; elif ! feat=$(testfeats ip4 rawip) || ! runsip4 >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}IP4 not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif [ $(id -u) -ne 0 -a "$withroot" -eq 0 ]; then $PRINTF "test $F_n $TEST... ${YELLOW}must be root${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" else PROTO1=$PROTO; PROTO=$((PROTO+1)) PROTO2=$PROTO # we use the forward channel (PROTO1) for testing, and have a backward channel # (PROTO2) to get the data back, so we get the classical echo behaviour testserversec "$N" "$TEST" "$opts" "ip4-recv:$PROTO1,reuseaddr!!ip4-sendto:127.0.0.1:$PROTO2" "" "range=$SECONDADDR/32" "ip4-recv:$PROTO2!!ip4-sendto:127.0.0.1:$PROTO1" 4 ip $PROTO1 0 fi ;; # NUMCOND, feats, root esac PROTO=$((PROTO+1)) N=$((N+1)) NAME=IP4RECV_TCPWRAP case "$TESTS" in *%$N%*|*%functions%*|*%security%*|*%ip%*|*%ip4%*|*%tcpwrap%*|*%root%*|*%$NAME%*) TEST="$NAME: security of IP4-RECV with TCPWRAP option" if ! eval $NUMCOND; then :; elif ! feat=$(testfeats ip4 rawip libwrap) || ! runsip4 >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}$feat not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif [ $(id -u) -ne 0 -a "$withroot" -eq 0 ]; then $PRINTF "test $F_n $TEST... ${YELLOW}must be root${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" else PROTO1=$PROTO; PROTO=$((PROTO+1)) PROTO2=$PROTO ha="$td/hosts.allow" hd="$td/hosts.deny" $ECHO "socat: $SECONDADDR" >"$ha" $ECHO "ALL: ALL" >"$hd" # we use the forward channel (PROTO1) for testing, and have a backward channel # (PROTO2) to get the data back, so we get the classical echo behaviour testserversec "$N" "$TEST" "$opts" "ip4-recv:$PROTO1,reuseaddr!!ip4-sendto:127.0.0.1:$PROTO2" "" "tcpwrap-etc=$td" "ip4-recv:$PROTO2!!ip4-sendto:127.0.0.1:$PROTO1" 4 ip $PROTO1 0 fi ;; # NUMCOND, feats, root esac PROTO=$((PROTO+1)) N=$((N+1)) NAME=IP6RECVFROM_RANGE case "$TESTS" in *%$N%*|*%functions%*|*%security%*|*%fork%*|*%ip%*|*%ip6%*|*%range%*|*%root%*|*%$NAME%*) TEST="$NAME: security of IP6-RECVFROM with RANGE option" if ! eval $NUMCOND; then :; elif ! feat=$(testfeats ip6 rawip && runsip6); then $PRINTF "test $F_n $TEST... ${YELLOW}$feat not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif [ $(id -u) -ne 0 -a "$withroot" -eq 0 ]; then $PRINTF "test $F_n $TEST... ${YELLOW}must be root${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" else newport udp6 # provide free port number in $PORT #testserversec "$N" "$TEST" "$opts" "IP6-RECVFROM:$PROTO,reuseaddr,fork" "" "range=[::2]/128" "IP6-SENDTO:[::1]:$PROTO" 6 ip $PROTO 0 testserversec "$N" "$TEST" "$opts" "IP6-RECVFROM:$PROTO,reuseaddr!!UDP6-SENDTO:[::1]:$PORT" "" "range=[::2]/128" "UDP6-RECV:$PORT!!IP6-SENDTO:[::1]:$PROTO" 6 ip $PROTO 0 fi ;; # NUMCOND, feats esac PROTO=$((PROTO+1)) N=$((N+1)) NAME=IP6RECVFROM_TCPWRAP case "$TESTS" in *%$N%*|*%functions%*|*%security%*|*%fork%*|*%ip%*|*%ip6%*|*%tcpwrap%*|*%root%*|*%$NAME%*) TEST="$NAME: security of IP6-RECVFROM with TCPWRAP option" if ! eval $NUMCOND; then :; elif ! feat=$(testfeats ip6 rawip libwrap && runsip6); then $PRINTF "test $F_n $TEST... ${YELLOW}$feat not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif [ $(id -u) -ne 0 -a "$withroot" -eq 0 ]; then $PRINTF "test $F_n $TEST... ${YELLOW}must be root${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" else ha="$td/hosts.allow" hd="$td/hosts.deny" $ECHO "socat: [::2]" >"$ha" $ECHO "ALL: ALL" >"$hd" newport udp6 # provide free port number in $PORT #testserversec "$N" "$TEST" "$opts" "IP6-RECVFROM:$PROTO,reuseaddr,fork" "" "tcpwrap-etc=$td" "IP6-SENDTO:[::1]:$PROTO" 6 ip $PROTO 0 testserversec "$N" "$TEST" "$opts" "IP6-RECVFROM:$PROTO,reuseaddr!!UDP6-SENDTO:[::1]:$PORT" "" "tcpwrap-etc=$td" "UDP6-RECV:$PORT!!IP6-SENDTO:[::1]:$PROTO" 6 ip $PROTO 0 fi ;; # NUMCOND, feats esac PROTO=$((PROTO+1)) N=$((N+1)) NAME=IP6RECV_RANGE case "$TESTS" in *%$N%*|*%functions%*|*%security%*|*%ip%*|*%ip6%*|*%range%*|*%root%*|*%$NAME%*) TEST="$NAME: security of IP6-RECV with RANGE option" if ! eval $NUMCOND; then :; elif ! feat=$(testfeats ip6 rawip) || ! runsip6 >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}raw IP6 not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif [ $(id -u) -ne 0 -a "$withroot" -eq 0 ]; then $PRINTF "test $F_n $TEST... ${YELLOW}must be root${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" else PROTO1=$PROTO; PROTO=$((PROTO+1)) PROTO2=$PROTO # we use the forward channel (PROTO1) for testing, and have a backward channel # (PROTO2) to get the data back, so we get the classical echo behaviour testserversec "$N" "$TEST" "$opts" "ip6-recv:$PROTO1,reuseaddr!!ip6-sendto:[::1]:$PROTO2" "" "range=[::2]/128" "ip6-recv:$PROTO2!!ip6-sendto:[::1]:$PROTO1" 6 ip $PROTO1 0 fi ;; # NUMCOND, feats esac PROTO=$((PROTO+1)) N=$((N+1)) NAME=IP6RECV_TCPWRAP case "$TESTS" in *%$N%*|*%functions%*|*%security%*|*%ip%*|*%ip6%*|*%tcpwrap%*|*%root%*|*%$NAME%*) TEST="$NAME: security of IP6-RECV with TCPWRAP option" if ! eval $NUMCOND; then :; elif ! feat=$(testfeats ip6 rawip libwrap && runsip6); then $PRINTF "test $F_n $TEST... ${YELLOW}$feat not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif [ $(id -u) -ne 0 -a "$withroot" -eq 0 ]; then $PRINTF "test $F_n $TEST... ${YELLOW}must be root${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" else PROTO1=$PROTO; PROTO=$((PROTO+1)) PROTO2=$PROTO ha="$td/hosts.allow" hd="$td/hosts.deny" $ECHO "socat: [::2]" >"$ha" $ECHO "ALL: ALL" >"$hd" # we use the forward channel (PROTO1) for testing, and have a backward channel # (PROTO2) to get the data back, so we get the classical echo behaviour testserversec "$N" "$TEST" "$opts" "ip6-recv:$PROTO1,reuseaddr!!ip6-sendto:[::1]:$PROTO2" "" "tcpwrap-etc=$td" "ip6-recv:$PROTO2!!ip6-sendto:[::1]:$PROTO1" 6 ip $PROTO1 0 fi ;; # NUMCOND, feats esac PROTO=$((PROTO+1)) N=$((N+1)) NAME=O_NOATIME_FILE case "$TESTS" in *%$N%*|*%functions%*|*%open%*|*%noatime%*|*%$NAME%*) TEST="$NAME: option O_NOATIME on file" # idea: create a file with o-noatime option; one second later create a file # without this option (using touch); one second later read from the first file. # Then we check which file has the later ATIME stamp. For this check we use # "ls -ltu" because it is more portable than "test ... -nt ..." if ! eval $NUMCOND; then :; elif ! testoptions o-noatime >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}o-noatime not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" else tf="$td/test$N.file" te="$td/test$N.stderr" tdiff="$td/test$N.diff" da="test$N $(date) $RANDOM" $PRINTF "test $F_n $TEST... " $N CMD="$TRACE $SOCAT $opts -u open:\"${tf}1\",o-noatime /dev/null" # generate a file touch "${tf}1" sleep 1 # generate a reference file touch "${tf}2" sleep 1 # read from the first file $CMD 2>"$te" if [ $? -ne 0 ]; then # command failed $PRINTF "${FAILED}:\n" echo "$CMD" cat "$te" numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" else # check which file has a later atime stamp if [ $(ls -ltu "${tf}1" "${tf}2" |head -1 |sed 's/.* //') != "${tf}2" ]; then $PRINTF "$FAILED: $TRACE $SOCAT:\n" echo "$CMD" cat "$te" numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" else $PRINTF "$OK\n" if [ -n "$debug" ]; then cat "$te"; fi numOK=$((numOK+1)) fi # wrong time stamps fi # command ok fi ;; # NUMCOND, feats esac N=$((N+1)) NAME=O_NOATIME_FD case "$TESTS" in *%$N%*|*%functions%*|*%noatime%*|*%$NAME%*) TEST="$NAME: option O_NOATIME on file descriptor" # idea: use a fd of a file with o-noatime option; one second later create a file # without this option (using touch); one second later read from the first file. # Then we check which file has the later ATIME stamp. For this check we use # "ls -ltu" because it is more portable than "test ... -nt ..." if ! eval $NUMCOND; then :; elif ! testoptions o-noatime >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}o-noatime not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" else tf="$td/test$N.file" te="$td/test$N.stderr" tdiff="$td/test$N.diff" da="test$N $(date) $RANDOM" $PRINTF "test $F_n $TEST... " $N touch ${tf}1 CMD="$TRACE $SOCAT $opts -u -,o-noatime /dev/null <${tf}1" # generate a file, len >= 1 touch "${tf}1" sleep 1 # generate a reference file touch "${tf}2" sleep 1 # read from the first file sh -c "$CMD" 2>"$te" rc=$? if [ $rc -ne 0 ]; then # command failed $PRINTF "${FAILED} (rc=$rc):\n" echo "$CMD" cat "$te" >&2 numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" else # check which file has a later atime stamp if [ $(ls -ltu "${tf}1" "${tf}2" |head -1 |sed 's/.* //') != "${tf}2" ]; then $PRINTF "$FAILED (bad order):\n" echo "$CMD" >&2 cat "$te" numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" else $PRINTF "$OK\n" if [ "$VERBOSE" ]; then echo "$CMD"; fi if [ "$DEBUG" ]; then cat "${te}" >&2; fi numOK=$((numOK+1)) fi # wrong time stamps fi # command ok fi ;; # NUMCOND, feats esac N=$((N+1)) NAME=FS_NOATIME case "$TESTS" in *%$N%*|*%functions%*|*%fs%*|*%noatime%*|*%$NAME%*) TEST="$NAME: extended file system options using fs noatime option" # idea: create a file with fs-noatime option; one second later create a file # without this option (using touch); one second later read from the first file. # Then we check which file has the later ATIME stamp. For this check we use # "ls -ltu" because it is more portable than "test ... -nt ..." if ! eval $NUMCOND; then :; elif ! testoptions fs-noatime >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}fs-noatime not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" else ts="$td/test$N.socket" tf="$td/test$N.file" te="$td/test$N.stderr" tdiff="$td/test$N.diff" ts1="$ts" da="test$N $(date) $RANDOM" $PRINTF "test $F_n $TEST... " $N CMD0="$TRACE $SOCAT $opts -u /dev/null create:\"${tf}1\"" CMD="$TRACE $SOCAT $opts -u /dev/null create:\"${tf}1\",fs-noatime" # check if this is a capable FS; lsattr does other things on AIX, thus socat $CMD0 2>"${te}0" if [ $? -ne 0 ]; then $PRINTF "${YELLOW} cannot test${NORMAL}\n" numCANT=$((numCANT+1)) listCANT="$listCANT $N" else # generate a file with noatime, len >= 1 $CMD 2>"$te" if [ $? -ne 0 ]; then # command failed $PRINTF "${YELLOW}impotent file system?${NORMAL}\n" echo "$CMD" cat "$te" numCANT=$((numCANT+1)) listCANT="$listCANT $N" else sleep 1 # generate a reference file touch "${tf}2" sleep 1 # read from the first file cat "${tf}1" >/dev/null # check which file has a later atime stamp #if [ $(ls -ltu "${tf}1" "${tf}2" |head -n 1 |awk '{print($8);}') != "${tf}2" ]; if [ $(ls -ltu "${tf}1" "${tf}2" |head -n 1 |sed "s|.*\\($td.*\\)|\1|g") != "${tf}2" ]; then $PRINTF "$FAILED: $TRACE $SOCAT:\n" echo "$CMD" cat "$te" numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" else $PRINTF "$OK\n" if [ -n "$debug" ]; then cat "$te"; fi numOK=$((numOK+1)) fi fi # not impotent fi # can test fi ;; # NUMCOND, feats esac N=$((N+1)) NAME=COOLWRITE case "$TESTS" in *%$N%*|*%functions%*|*%engine%*|*%timeout%*|*%coolwrite%*|*%$NAME%*) TEST="$NAME: option cool-write" if ! eval $NUMCOND; then :; elif ! testoptions cool-write >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}option cool-write not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" else #set -vx ti="$td/test$N.pipe" tf="$td/test$N.stdout" te="$td/test$N.stderr" tdiff="$td/test$N.diff" da="test$N $(date) $RANDOM" # a reader that will terminate after 1 byte CMD1="$TRACE $SOCAT $opts -u pipe:\"$ti\",readbytes=1 /dev/null" CMD="$TRACE $SOCAT $opts -u - file:\"$ti\",cool-write" printf "test $F_n $TEST... " $N $CMD1 2>"${te}1" & bg=$! # background process id sleep 1 (echo .; sleep 1; echo) |$CMD 2>"$te" rc=$? kill $bg 2>/dev/null; wait if [ $rc -ne 0 ]; then $PRINTF "$FAILED: $TRACE $SOCAT:\n" echo "$CMD &" cat "$te" numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" else $PRINTF "$OK\n" if [ -n "$debug" ]; then cat "$te"; fi numOK=$((numOK+1)) fi fi ;; # NUMCOND, feats esac N=$((N+1)) # test if option coolwrite can be applied to bidirectional address stdio # this failed up to socat 1.6.0.0 NAME=COOLSTDIO case "$TESTS" in *%$N%*|*%functions%*|*%engine%*|*%timeout%*|*%coolwrite%*|*%$NAME%*) TEST="$NAME: option cool-write on bidirectional stdio" # this test starts a socat reader that terminates after receiving one+ # bytes (option readbytes); and a test process that sends two bytes via # named pipe to the receiving process and, a second later, sends another # byte. The last write will fail with "broken pipe"; if option coolwrite # has been applied successfully, socat will terminate with 0 (OK), # otherwise with error. if ! eval $NUMCOND; then :; elif ! testoptions cool-write >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}option cool-write not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" else #set -vx ti="$td/test$N.pipe" tf="$td/test$N.stdout" te="$td/test$N.stderr" tdiff="$td/test$N.diff" da="test$N $(date) $RANDOM" # a reader that will terminate after 1 byte CMD1="$TRACE $SOCAT $opts -u pipe:\"$ti\",readbytes=1 /dev/null" CMD="$TRACE $SOCAT $opts -,cool-write pipe >\"$ti\"" printf "test $F_n $TEST... " $N $CMD1 2>"${te}1" & bg=$! # background process id sleep 1 (echo .; sleep 1; echo) |eval "$CMD" 2>"$te" rc=$? kill $bg 2>/dev/null; wait if [ $rc -ne 0 ]; then $PRINTF "$FAILED: $TRACE $SOCAT:\n" echo "$CMD1 &" cat "${te}1" echo "$CMD" cat "$te" numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" else $PRINTF "$OK\n" if [ -n "$debug" ]; then cat "$te"; fi numOK=$((numOK+1)) fi fi ;; # NUMCOND, feats esac N=$((N+1)) NAME=TCP4ENDCLOSE case "$TESTS" in *%$N%*|*%functions%*|*%ip4%*|*%ipapp%*|*%tcp%*|*%listen%*|*%fork%*|*%$NAME%*) TEST="$NAME: end-close keeps TCP V4 socket open" if ! eval $NUMCOND; then :; else tf="$td/test$N.stdout" te="$td/test$N.stderr" tdiff="$td/test$N.diff" newport tcp4; p0=$PORT newport tcp4; p1=$PORT da2a="$(date) $RANDOM" da2b="$(date) $RANDOM" CMD0="$TRACE $SOCAT -lp collector $opts -u TCP4-LISTEN:$p0,$REUSEADDR,bind=$LOCALHOST -" CMD1="$TRACE $SOCAT -lp forker $opts -U TCP4:$LOCALHOST:$p0,end-close TCP4-LISTEN:$p1,bind=$LOCALHOST,$REUSEADDR,fork" CMD2="$TRACE $SOCAT -lp client $opts -u - TCP4-CONNECT:$LOCALHOST:$p1" printf "test $F_n $TEST... " $N $CMD0 >"${tf}0" 2>"${te}0" & pid0=$! waittcp4port $p0 1 $CMD1 2>"${te}1" & pid1=$! usleep $MICROS waittcp4port $p1 1 echo "$da2a" |$CMD2 2>>"${te}2a" rc2a=$? echo "$da2b" |$CMD2 2>>"${te}2b" rc2b=$? sleep 1 kill "$pid0" "$pid1" 2>/dev/null wait if [ $rc2a -ne 0 -o $rc2b -ne 0 ]; then $PRINTF "$FAILED: $TRACE $SOCAT:\n" echo "$CMD0 &" cat "${te}0" >&2 echo "$CMD1" cat "${te}1" >&2 echo "$CMD2" cat "${te}2a" >&2 echo "$CMD2" cat "${te}2b" >&2 numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" elif ! $ECHO "$da2a\n$da2b" |diff - "${tf}0" >"$tdiff"; then $PRINTF "$FAILED (diff)\n" echo "$CMD0 &" cat "${te}0" >&2 echo "$CMD1" cat "${te}1" >&2 echo "$CMD2" cat "${te}2a" >&2 echo "$CMD2" cat "${te}2b" >&2 cat "$tdiff" numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" else $PRINTF "$OK\n" if [ "$VERBOSE" ]; then echo "$CMD0 &"; fi if [ "$DEBUG" ]; then cat "${te}0" >&2; fi if [ "$VERBOSE" ]; then echo "$CMD1 &"; fi if [ "$DEBUG" ]; then cat "${te}1" >&2; fi if [ "$VERBOSE" ]; then echo "$CMD2"; fi if [ "$DEBUG" ]; then cat "${te}2a" >&2; fi if [ "$VERBOSE" ]; then echo "$CMD2"; fi if [ "$DEBUG" ]; then cat "${te}2b" >&2; fi numOK=$((numOK+1)) fi fi ;; # NUMCOND esac N=$((N+1)) NAME=EXECENDCLOSE case "$TESTS" in *%$N%*|*%functions%*|*%exec%*|*%listen%*|*%unix%*|*%fork%*|*%$NAME%*) TEST="$NAME: end-close keeps EXEC child running" if ! eval $NUMCOND; then :; else tf="$td/test$N.stdout" te="$td/test$N.stderr" ts="$td/test$N.sock" tdiff="$td/test$N.diff" da1a="$(date) $RANDOM" da1b="$(date) $RANDOM" CMD1="$TRACE $SOCAT $opts - UNIX-CONNECT:$ts" CMD="$TRACE $SOCAT $opts EXEC:"$CAT",end-close UNIX-LISTEN:$ts,fork" printf "test $F_n $TEST... " $N $CMD 2>"${te}2" & pid2=$! waitfile $ts 1 echo "$da1a" |$CMD1 2>>"${te}1a" >"$tf" usleep $MICROS echo "$da1b" |$CMD1 2>>"${te}1b" >>"$tf" #usleep $MICROS kill "$pid2" 2>/dev/null wait if [ $? -ne 0 ]; then $PRINTF "$FAILED: $TRACE $SOCAT:\n" echo "$CMD1 &" echo "$CMD2" cat "${te}1a" "${te}1b" "${te}2" numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" elif ! $ECHO "$da1a\n$da1b" |diff - "$tf" >"$tdiff"; then $PRINTF "$FAILED\n" cat "$tdiff" cat "${te}1a" "${te}1b" "${te}2" numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" else $PRINTF "$OK\n" if [ -n "$debug" ]; then cat "${te}1a" "${te}1b" "${te}2"; fi numOK=$((numOK+1)) fi fi ;; # NUMCOND esac N=$((N+1)) # up to 1.7.0.0 option end-close led to an error with some address types due to # bad internal handling. here we check it for address PTY NAME=PTYENDCLOSE case "$TESTS" in *%$N%*|*%functions%*|*%bugs%*|*%pty%*|*%$NAME%*) TEST="$NAME: PTY handles option end-close" # with the bug, socat exits with error. we invoke socat in a no-op mode and # check its return status. if ! eval $NUMCOND; then :; else tf="$td/test$N.stout" te="$td/test$N.stderr" # -t must be longer than 0.1 on OpenBSD CMD="$TRACE $SOCAT $opts -d -d -t 0.5 /dev/null pty,end-close" printf "test $F_n $TEST... " $N # AIX reports the pty writeable for select() only when its slave side has been # opened, therefore we run this process in background and check its NOTICE # output for the PTY name { $CMD 2>"${te}"; echo $? >"$td/test$N.rc0"; } & waitfile "${te}" psleep 0.5 # 0.1 is too few for FreeBSD-10 PTY=$(grep "N PTY is " $te |sed 's/.*N PTY is //') [ -e "$PTY" ] && cat $PTY >/dev/null 2>/dev/null rc=$(cat "$td/test$N.rc0") if [ "$rc" = 0 ]; then $PRINTF "$OK\n" numOK=$((numOK+1)) else $PRINTF "$FAILED\n" echo "$CMD" cat "${te}" numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" fi fi # NUMCOND ;; esac N=$((N+1)) # Test the shut-null and null-eof options NAME=SHUTNULLEOF case "$TESTS" in *%$N%*|*%functions%*|*%socket%*|*%$NAME%*) TEST="$NAME: options shut-null and null-eof" # Run a receiving background process with option null-eof. # Start a sending process with option shut-null that sends a test record to the # receiving process and then terminates. # Send another test record. # When the receiving process only received and stored the first test record the # test succeeded if ! eval $NUMCOND; then :; else tf="$td/test$N.stout" te="$td/test$N.stderr" tdiff="$td/test$N.diff" da="test$N $(date) $RANDOM" newport udp4 # provide free port number in $PORT CMD0="$TRACE $SOCAT $opts -u UDP-RECV:$PORT,null-eof CREAT:$tf" CMD1="$TRACE $SOCAT $opts -u - UDP-SENDTO:127.0.0.1:$PORT,shut-null" printf "test $F_n $TEST... " $N $CMD0 >/dev/null 2>"${te}0" & pid0=$! waitudp4port $PORT 1 { echo "$da"; psleep 0.1; } |$CMD1 >"${tf}1" 2>"${te}1" rc1=$? { echo "xyz"; psleep 0.1; } |$CMD1 >"${tf}2" 2>"${te}2" rc2=$? kill $pid0 2>/dev/null; wait if [ $rc1 != 0 -o $rc2 != 0 ]; then $PRINTF "$FAILED (client(s) failed)\n" echo "$CMD0 &" cat "${te}0" >&2 echo "$CMD1" cat "${te}1" >&2 echo "$CMD1" cat "${te}2" >&2 numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" elif echo "$da" |diff - "${tf}" >"$tdiff"; then $PRINTF "$OK\n" if [ "$VERBOSE" ]; then echo "$CMD0 &"; fi if [ "$DEBUG" ]; then cat "${te}0" >&2; fi if [ "$VERBOSE" ]; then echo "$CMD1"; fi if [ "$DEBUG" ]; then cat "${te}1" >&2; fi if [ "$VERBOSE" ]; then echo "$CMD2"; fi if [ "$DEBUG" ]; then cat "${te}2" >&2; fi numOK=$((numOK+1)) else $PRINTF "$FAILED (diff)\n" echo "$CMD0 &" cat "${te}0" >&2 echo "$CMD1" cat "${te}1" >&2 echo "$CMD2" cat "${te}2" >&2 echo "// diff:" >&2 cat "${tdiff}" >&2 numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" fi fi # NUMCOND ;; esac N=$((N+1)) NAME=UDP6LISTENBIND # this tests for a bug in (up to) 1.5.0.0: # with udp*-listen, the bind option supported only IPv4 case "$TESTS" in *%$N%*|*%functions%*|*%bugs%*|*%ip6%*|*%ipapp%*|*%udp%*|*%udp6%*|*%listen%*|*%$NAME%*) TEST="$NAME: UDP6-LISTEN with bind" if ! eval $NUMCOND; then :; elif ! feat=$(testfeats udp ip6) || ! runsip6 >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}UDP6 not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" else tf="$td/test$N.stdout" te="$td/test$N.stderr" tdiff="$td/test$N.diff" newport udp6; tsl=$PORT ts="$LOCALHOST6:$tsl" da="test$N $(date) $RANDOM" CMD1="$TRACE $SOCAT $opts UDP6-LISTEN:$tsl,$REUSEADDR,bind=$LOCALHOST6 PIPE" CMD2="$TRACE $SOCAT $opts - UDP6:$ts" printf "test $F_n $TEST... " $N $CMD1 >"$tf" 2>"${te}1" & pid1=$! waitudp6port $tsl 1 echo "$da" |$CMD2 >>"$tf" 2>>"${te}2" rc2=$? kill $pid1 2>/dev/null; wait if [ $rc2 -ne 0 ]; then $PRINTF "$FAILED: $TRACE $SOCAT:\n" echo "$CMD1 &" echo "$CMD2" cat "${te}1" "${te}2" numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" elif ! echo "$da" |diff - "$tf" >"$tdiff"; then $PRINTF "$FAILED\n" cat "$tdiff" numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" else $PRINTF "$OK\n" if [ -n "$debug" ]; then cat "${te}1" "${te}2"; fi numOK=$((numOK+1)) fi fi ;; # NUMCOND, feats esac N=$((N+1)) NAME=TCPWRAPPERS_MULTIOPTS # this tests for a bug in 1.5.0.0 that let socat fail when more than one # tcp-wrappers related option was specified in one address case "$TESTS" in *%$N%*|*%functions%*|*%bugs%*|*%tcp%*|*%tcp4%*|*%ip4%*|*%tcpwrap%*|*%listen%*|*%$NAME%*) TEST="$NAME: use of multiple tcpwrapper enabling options" if ! eval $NUMCOND; then :; elif ! feat=$(testfeats tcp ip4 libwrap) || ! runsip4 >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}$feat not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" else tf="$td/test$N.stdout" te="$td/test$N.stderr" tdiff="$td/test$N.diff" da="test$N $(date) $RANDOM" ha="$td/hosts.allow" $ECHO "test : ALL : allow" >"$ha" newport tcp4 # provide free port number in $PORT CMD1="$TRACE $SOCAT $opts TCP4-LISTEN:$PORT,$REUSEADDR,hosts-allow=$ha,tcpwrap=test pipe" CMD2="$TRACE $SOCAT $opts - TCP4:$LOCALHOST:$PORT" printf "test $F_n $TEST... " $N $CMD1 2>"${te}1" & pid1=$! waittcp4port $PORT echo "$da" |$CMD2 >"$tf" 2>"${te}2" rc2=$? kill $pid1 2>/dev/null; wait if [ $rc2 -ne 0 ]; then $PRINTF "$FAILED: $TRACE $SOCAT:\n" echo "$CMD1 &" echo "$CMD2" cat "${te}1" cat "${te}2" numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" elif ! echo "$da" |diff - "$tf" >"$tdiff"; then $PRINTF "$FAILED\n" cat "$tdiff" numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" else $PRINTF "$OK\n" if [ -n "$debug" ]; then cat "${te}1" "${te}2"; fi numOK=$((numOK+1)) fi fi ;; # NUMCOND, feats esac N=$((N+1)) NAME=TCPWRAPPERS_TCP6ADDR # this tests for a bug in 1.5.0.0 that brought false results with tcp-wrappers # and IPv6 when case "$TESTS" in *%$N%*|*%functions%*|*%bugs%*|*%tcp%*|*%tcp6%*|*%ip6%*|*%tcpwrap%*|*%listen%*|*%$NAME%*) TEST="$NAME: specification of TCP6 address in hosts.allow" if ! eval $NUMCOND; then :; elif ! feat=$(testfeats tcp ip6 libwrap && runsip6); then $PRINTF "test $F_n $TEST... ${YELLOW}$feat not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" else tf="$td/test$N.stdout" te="$td/test$N.stderr" tdiff="$td/test$N.diff" da="test$N $(date) $RANDOM" ha="$td/hosts.allow" hd="$td/hosts.deny" $ECHO "socat : [::1] : allow" >"$ha" $ECHO "ALL : ALL : deny" >"$hd" newport tcp6 # provide free port number in $PORT CMD1="$TRACE $SOCAT $opts TCP6-LISTEN:$PORT,$REUSEADDR,tcpwrap-etc=$td,tcpwrappers=socat pipe" CMD2="$TRACE $SOCAT $opts - TCP6:[::1]:$PORT" printf "test $F_n $TEST... " $N $CMD1 2>"${te}1" & pid1=$! waittcp6port $PORT echo "$da" |$CMD2 >"$tf" 2>"${te}2" rc2=$? kill $pid1 2>/dev/null; wait if [ $rc2 -ne 0 ]; then $PRINTF "$FAILED: $TRACE $SOCAT:\n" echo "$CMD1 &" echo "$CMD2" cat "${te}1" cat "${te}2" numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" elif ! echo "$da" |diff - "$tf" >"$tdiff"; then $PRINTF "$FAILED\n" cat "$tdiff" numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" else $PRINTF "$OK\n" if [ -n "$debug" ]; then cat "${te}1" "${te}2"; fi numOK=$((numOK+1)) fi fi ;; # NUMCOND, feats esac N=$((N+1)) NAME=UDP4BROADCAST case "$TESTS" in *%$N%*|*%functions%*|*%udp%*|*%udp4%*|*%ip4%*|*%dgram%*|*%broadcast%*|*%$NAME%*) TEST="$NAME: UDP/IPv4 broadcast" if ! eval $NUMCOND; then :; elif [ -z "$BCADDR" ]; then $PRINTF "test $F_n $TEST... ${YELLOW}dont know a broadcast address${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" else tf="$td/test$N.stdout" te="$td/test$N.stderr" tdiff="$td/test$N.diff" newport udp4; ts1p=$PORT #ts1="$BCADDR/8:$ts1p" ts1="$BCADDR:$ts1p" newport udp4; ts2p=$PORT ts2="$BCIFADDR:$ts2p" da="test$N $(date) $RANDOM" CMD1="$TRACE $SOCAT $opts UDP4-RECVFROM:$ts1p,reuseaddr,broadcast PIPE" #CMD2="$TRACE $SOCAT $opts - UDP4-BROADCAST:$ts1" CMD2="$TRACE $SOCAT $opts - UDP4-DATAGRAM:$ts1,broadcast" printf "test $F_n $TEST... " $N $CMD1 2>"${te}1" & pid1="$!" waitudp4port $ts1p 1 echo "$da" |$CMD2 >>"$tf" 2>>"${te}2" rc2="$?" kill "$pid1" 2>/dev/null; wait; if [ "$rc2" -ne 0 ]; then $PRINTF "$FAILED: $TRACE $SOCAT:\n" echo "$CMD1 &" echo "$CMD2" cat "${te}1" cat "${te}2" numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" elif ! echo "$da" |diff - "$tf" >"$tdiff"; then $PRINTF "$FAILED\n" cat "$tdiff" numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" else $PRINTF "$OK\n" if [ -n "$tut" ]; then echo "$CMD1 &" echo "$CMD2" fi if [ -n "$debug" ]; then cat $te; fi numOK=$((numOK+1)) fi fi ;; # NUMCOND, feats esac N=$((N+1)) NAME=IP4BROADCAST # test a local broadcast of a raw IPv4 protocol. # because we receive - in addition to the regular reply - our own broadcast, # we use a token XXXX that is changed to YYYY in the regular reply packet. case "$TESTS" in *%$N%*|*%functions%*|*%engine%*|*%rawip%*|*%rawip4%*|*%ip4%*|*%dgram%*|*%broadcast%*|*%root%*|*%$NAME%*) TEST="$NAME: raw IPv4 broadcast" if ! eval $NUMCOND; then :; elif ! feat=$(testfeats ip4 rawip) || ! runsip4 >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}raw IP4 not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif [ $(id -u) -ne 0 -a "$withroot" -eq 0 ]; then $PRINTF "test $F_n $TEST... ${YELLOW}must be root${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif [ -z "$BCADDR" ]; then $PRINTF "test $F_n $TEST... ${YELLOW}dont know a broadcast address${NORMAL}\n" $N else tf="$td/test$N.stdout" te="$td/test$N.stderr" tdiff="$td/test$N.diff" ts1p=$PROTO #ts1="$BCADDR/8:$ts1p" ts1="$BCADDR:$ts1p" ts2p=$ts1p ts2="$BCIFADDR" da="test$N $(date) $RANDOM XXXX" sh="$td/test$N-sed.sh" echo 'sed s/XXXX/YYYY/' >"$sh" chmod a+x "$sh" # EXEC need not work with script (musl libc), so use SYSTEM CMD1="$TRACE $SOCAT $opts IP4-RECVFROM:$ts1p,reuseaddr,broadcast SYSTEM:$sh" #CMD2="$TRACE $SOCAT $opts - IP4-BROADCAST:$ts1" CMD2="$TRACE $SOCAT $opts - IP4-DATAGRAM:$ts1,broadcast" printf "test $F_n $TEST... " $N $CMD1 2>"${te}1" & pid1="$!" waitip4port $ts1p 1 echo "$da" |$CMD2 2>>"${te}2" |grep -v XXXX >>"$tf" rc2="$?" kill "$pid1" 2>/dev/null; wait; if [ "$rc2" -ne 0 ]; then $PRINTF "$FAILED: $TRACE $SOCAT:\n" echo "$CMD1 &" echo "$CMD2" cat "${te}1" cat "${te}2" numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" elif ! echo "$da" | sed 's/XXXX/YYYY/'|diff - "$tf" >"$tdiff"; then $PRINTF "$FAILED\n" cat "$tdiff" numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" else $PRINTF "$OK\n" if [ -n "$debug" ]; then cat $te; fi numOK=$((numOK+1)) fi fi ;; # NUMCOND, feats esac PROTO=$((PROTO+1)) N=$((N+1)) #NAME=UDP4BROADCAST_RANGE #case "$TESTS" in #*%$N%*|*%functions%*|*%security%*|*%udp%*|*%udp4%*|*%ip4%*|*%dgram%*|*%broadcast%*|*%range%*|*%$NAME%*) #TEST="$NAME: security of UDP4-BROADCAST with RANGE option" #if ! eval $NUMCOND; then :; #elif [ -z "$BCADDR" ]; then # $PRINTF "test $F_n $TEST... ${YELLOW}dont know a broadcast address${NORMAL}\n" $N #else #newport udp4 # provide free port number in $PORT #testserversec "$N" "$TEST" "$opts" "UDP4-BROADCAST:$BCADDR/8:$PORT" "" "range=127.1.0.0:255.255.0.0" "udp4:127.1.0.0:$PORT" 4 udp $PORT 0 #fi ;; # NUMCOND, feats #esac #N=$((N+1)) NAME=UDP4MULTICAST_UNIDIR case "$TESTS" in *%$N%*|*%functions%*|*%udp%*|*%udp4%*|*%ip4%*|*%dgram%*|*%multicast%*|*%$NAME%*) TEST="$NAME: UDP/IPv4 multicast, send only" if ! eval $NUMCOND; then :; elif ! feat=$(testfeats ip4 udp) || ! runsip4 >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}$feat not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif ! a=$(testaddrs UDP4-RECV UDP4-SENDTO); then $PRINTF "test $F_n $TEST... ${YELLOW}Address $a not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif ! o=$(testoptions ip-add-membership bind) >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}Option $o not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" else tf="$td/test$N.stdout" te="$td/test$N.stderr" tdiff="$td/test$N.diff" newport udp4; ts1p=$PORT ts1a="$SECONDADDR" ts1="$ts1a:$ts1p" da="test$N $(date) $RANDOM" CMD1="$TRACE $SOCAT -u $opts UDP4-RECV:$ts1p,reuseaddr,ip-add-membership=224.255.255.254:$ts1a -" CMD2="$TRACE $SOCAT -u $opts - UDP4-SENDTO:224.255.255.254:$ts1p,bind=$ts1a" printf "test $F_n $TEST... " $N $CMD1 2>"${te}1" >"${tf}" & pid1="$!" waitudp4port $ts1p 1 echo "$da" |$CMD2 2>>"${te}2" rc2="$?" usleep $MICROS kill "$pid1" 2>/dev/null; wait; if [ "$rc2" -ne 0 ]; then $PRINTF "$FAILED: $TRACE $SOCAT:\n" echo "$CMD1 &" cat "${te}1" >&2 echo "$CMD2" cat "${te}2" >&2 numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" elif ! echo "$da" |diff - "$tf" >"$tdiff"; then $PRINTF "$FAILED\n" echo "$CMD1 &" cat "${te}1" >&2 echo "$CMD2" cat "${te}2" >&2 cat "$tdiff" numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" else $PRINTF "$OK\n" if [ "$VERBOSE" ]; then echo "$CMD0 &"; fi if [ "$DEBUG" ]; then cat "${te}0" >&2; fi if [ "$VERBOSE" ]; then echo "$CMD1"; fi if [ "$DEBUG" ]; then cat "${te}1" >&2; fi numOK=$((numOK+1)) fi fi ;; # NUMCOND, feats esac N=$((N+1)) NAME=IP4MULTICAST_UNIDIR case "$TESTS" in *%$N%*|*%functions%*|*%rawip%*|*%ip4%*|*%dgram%*|*%multicast%*|*%root%*|*%$NAME%*) TEST="$NAME: IPv4 multicast" if ! eval $NUMCOND; then :; elif ! feat=$(testfeats ip4 rawip) || ! runsip4 >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}$feat not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif [ $(id -u) -ne 0 -a "$withroot" -eq 0 ]; then $PRINTF "test $F_n $TEST... ${YELLOW}must be root${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" else tf="$td/test$N.stdout" te="$td/test$N.stderr" tdiff="$td/test$N.diff" ts1p=$PROTO ts1a="$SECONDADDR" ts1="$ts1a:$ts1p" da="test$N $(date) $RANDOM" CMD1="$TRACE $SOCAT -u $opts IP4-RECV:$ts1p,reuseaddr,ip-add-membership=224.255.255.254:$ts1a -" CMD2="$TRACE $SOCAT -u $opts - IP4-SENDTO:224.255.255.254:$ts1p,bind=$ts1a" printf "test $F_n $TEST... " $N $CMD1 2>"${te}1" >"${tf}" & pid1="$!" waitip4proto $ts1p 1 usleep $MICROS echo "$da" |$CMD2 2>>"${te}2" rc2="$?" #usleep $MICROS sleep 1 kill "$pid1" 2>/dev/null; wait; if [ "$rc2" -ne 0 ]; then $PRINTF "$FAILED: $TRACE $SOCAT:\n" echo "$CMD1 &" echo "$CMD2" cat "${te}1" cat "${te}2" numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" elif ! echo "$da" |diff - "$tf" >"$tdiff"; then $PRINTF "$FAILED\n" cat "$tdiff" numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" else $PRINTF "$OK\n" if [ -n "$debug" ]; then cat $te; fi numOK=$((numOK+1)) fi fi ;; # NUMCOND, feats esac PROTO=$((PROTO+1)) N=$((N+1)) if true; then # This test succeeds, e.g., on CentOS-7 with kernel 3.10.0, Ubuntu-16.04 with 4.4.0 # but fails, e.g., on Ubuntu-18.04 with kernel 4.15.0, CentOS-8 with 4.10.0 NAME=UDP6MULTICAST_UNIDIR case "$TESTS" in *%$N%*|*%functions%*|*%udp%*|*%udp6%*|*%ip6%*|*%dgram%*|*%multicast%*|*%$NAME%*) TEST="$NAME: UDP/IPv6 multicast" if ! eval $NUMCOND; then :; elif ! f=$(testfeats ip6 udp); then $PRINTF "test $F_n $TEST... ${YELLOW}Feature $f not configured in $SOCAT${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif ! a=$(testaddrs - STDIO UDP6-RECV UDP6-SENDTO); then $PRINTF "test $F_n $TEST... ${YELLOW}Address $a not available in $SOCAT${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif ! o=$(testoptions ipv6-join-group) >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}Option $o not available in $SOCAT${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif ! runsip6 >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}IPv6 does not work on $HOSTNAME${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif ! echo |$SOCAT -u -t 0.1 - UDP6-SENDTO:[ff02::2]:12002 >/dev/null 2>&1; then $PRINTF "test $F_n $TEST... ${YELLOW}IPv6 multicasting does not work${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" else tf="$td/test$N.stdout" te="$td/test$N.stderr" tdiff="$td/test$N.diff" newport udp6; ts1p=$PORT if1="$MCINTERFACE" ts1a="[::1]" da="test$N $(date) $RANDOM" CMD1="$TRACE $SOCAT -u $opts UDP6-RECV:$ts1p,$REUSEADDR,ipv6-join-group=[ff02::2]:$if1 -" #CMD2="$TRACE $SOCAT -u $opts - UDP6-SENDTO:[ff02::2]:$ts1p,bind=$ts1a" CMD2="$TRACE $SOCAT -u $opts - UDP6-SENDTO:[ff02::2]:$ts1p" printf "test $F_n $TEST... " $N $CMD1 2>"${te}1" >"${tf}" & pid1="$!" waitudp6port $ts1p 1 echo "$da" |$CMD2 2>>"${te}2" rc2="$?" usleep $MICROS kill "$pid1" 2>/dev/null; wait; if [ "$rc2" -ne 0 ]; then $PRINTF "$FAILED: $TRACE $SOCAT:\n" echo "$CMD1 &" cat "${te}1" echo "$CMD2" cat "${te}2" numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" namesFAIL="$namesFAIL $NAME" elif ! echo "$da" |diff - "$tf" >"$tdiff"; then # if ! [ "$UNAME" = Linux ] || ! [[ $(uname -r) =~ ^2\.* ]] || ! [[ ^3\.* ]] || ! [[ ^4\.[0-4]\.* ]]; then # $PRINTF "${YELLOW}works only on Linux up to about 4.4${NORMAL}\n" $N # numCANT=$((numCANT+1)) # listCANT="$listCANT $N" # else $PRINTF "$FAILED\n" echo "$CMD1 &" cat "${te}1" echo "$CMD2" cat "${te}2" cat "$tdiff" numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" # fi else $PRINTF "$OK\n" if [ "$VERBOSE" ]; then echo "$CMD1 &"; fi if [ "$DEBUG" ]; then cat "${te}1" >&2; fi if [ "$VERBOSE" ]; then echo "$CMD2"; fi if [ "$DEBUG" ]; then cat "${te}2" >&2; fi numOK=$((numOK+1)) fi fi ;; # NUMCOND, feats esac N=$((N+1)) fi # false NAME=UDP4MULTICAST_BIDIR case "$TESTS" in *%$N%*|*%functions%*|*%udp%*|*%udp4%*|*%ip4%*|*%dgram%*|*%multicast%*|*%$NAME%*) TEST="$NAME: UDP/IPv4 multicast, with reply" if ! eval $NUMCOND; then :; else tf="$td/test$N.stdout" te="$td/test$N.stderr" tdiff="$td/test$N.diff" newport udp4; ts1p=$PORT ts1a="$SECONDADDR" ts1="$ts1a:$ts1p" newport udp4; ts2p=$PORT ts2="$BCIFADDR:$ts2p" da="test$N $(date) $RANDOM" CMD1="$TRACE $SOCAT $opts UDP4-RECVFROM:$ts1p,reuseaddr,ip-add-membership=224.255.255.254:$ts1a PIPE" #CMD2="$TRACE $SOCAT $opts - UDP4-MULTICAST:224.255.255.254:$ts1p,bind=$ts1a" CMD2="$TRACE $SOCAT $opts - UDP4-DATAGRAM:224.255.255.254:$ts1p,bind=$ts1a" printf "test $F_n $TEST... " $N $CMD1 2>"${te}1" & pid1="$!" waitudp4port $ts1p 1 echo "$da" |$CMD2 >>"$tf" 2>>"${te}2" rc2="$?" kill "$pid1" 2>/dev/null; wait; if [ "$rc2" -ne 0 ]; then $PRINTF "$FAILED: $TRACE $SOCAT:\n" echo "$CMD1 &" cat "${te}1" >&2 echo "$CMD2" cat "${te}2" >&2 numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" elif ! echo "$da" |diff - "$tf" >"$tdiff"; then $PRINTF "$FAILED\n" echo "$CMD1 &" cat "${te}1" >&2 echo "$CMD2" cat "${te}2" >&2 echo diff: >&2 cat "$tdiff" >&2 numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" else $PRINTF "$OK\n" if [ "$VERBOSE" ]; then echo "$CMD1 &"; fi if [ "$DEBUG" ]; then cat "${te}1" >&2; fi if [ "$VERBOSE" ]; then echo "$CMD2"; fi if [ "$DEBUG" ]; then cat "${te}2" >&2; fi numOK=$((numOK+1)) fi fi ;; # NUMCOND esac N=$((N+1)) NAME=IP4MULTICAST_BIDIR case "$TESTS" in *%$N%*|*%functions%*|*%rawip%*|*%ip4%*|*%dgram%*|*%multicast%*|*%root%*|*%$NAME%*) TEST="$NAME: IPv4 multicast, with reply" if ! eval $NUMCOND; then :; elif ! feat=$(testfeats ip4 rawip) || ! runsip4 >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}$feat not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif [ $(id -u) -ne 0 -a "$withroot" -eq 0 ]; then $PRINTF "test $F_n $TEST... ${YELLOW}must be root${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" else tf="$td/test$N.stdout" te="$td/test$N.stderr" tdiff="$td/test$N.diff" ts1p=$PROTO ts1a="$SECONDADDR" ts1="$ts1a:$ts1p" da="test$N $(date) $RANDOM" CMD1="$TRACE $SOCAT $opts IP4-RECVFROM:$ts1p,reuseaddr,ip-add-membership=224.255.255.254:$ts1a PIPE" #CMD2="$TRACE $SOCAT $opts - IP4-MULTICAST:224.255.255.254:$ts1p,bind=$ts1a" CMD2="$TRACE $SOCAT $opts - IP4-DATAGRAM:224.255.255.254:$ts1p,bind=$ts1a" printf "test $F_n $TEST... " $N $CMD1 2>"${te}1" & pid1="$!" waitip4port $ts1p 1 usleep 100000 # give process a chance to add multicast membership echo "$da" |$CMD2 >>"$tf" 2>>"${te}2" rc2="$?" kill "$pid1" 2>/dev/null; wait; if [ "$rc2" -ne 0 ]; then $PRINTF "$FAILED: $TRACE $SOCAT:\n" echo "$CMD1 &" echo "$CMD2" cat "${te}1" cat "${te}2" numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" elif ! echo "$da" |diff - "$tf" >"$tdiff"; then $PRINTF "$FAILED\n" cat "$tdiff" numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" else $PRINTF "$OK\n" if [ -n "$tut" ]; then echo "$CMD1 &" echo "$CMD2" fi if [ -n "$debug" ]; then cat $te; fi numOK=$((numOK+1)) fi fi ;; # NUMCOND, feats esac PROTO=$((PROTO+1)) N=$((N+1)) NAME=TUNREAD case "$TESTS" in *%$N%*|*%functions%*|*%tun%*|*%root%*|*%$NAME%*) TEST="$NAME: reading data sent through tun interface" #idea: create a TUN interface and send a datagram to one of the addresses of # its virtual network. On the tunnel side, read the packet and compare its last # bytes with the datagram payload if ! eval $NUMCOND; then :; elif ! feat=$(testfeats ip4 tun) || ! runsip4 >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}$feat not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif [ $(id -u) -ne 0 -a "$withroot" -eq 0 ]; then $PRINTF "test $F_n $TEST... ${YELLOW}must be root${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" else tf="$td/test$N.stdout" te="$td/test$N.stderr" tdiff="$td/test$N.diff" tl="$td/test$N.lock" da="test$N $(date) $RANDOM" dalen=$((${#da}+1)) TUNNET=10.255.255 newport udp4 # provide free port number in $PORT CMD1="$TRACE $SOCAT $opts -u - UDP4-SENDTO:$TUNNET.2:$PORT" #CMD="$TRACE $SOCAT $opts -u -L $tl TUN,ifaddr=$TUNNET.1,netmask=255.255.255.0,iff-up=1 -" CMD="$TRACE $SOCAT $opts -u -L $tl TUN:$TUNNET.1/24,iff-up=1 -" printf "test $F_n $TEST... " $N $CMD 2>"${te}" |tail -c $dalen >"${tf}" & sleep 1 echo "$da" |$CMD1 2>"${te}1" sleep 1 kill "$(cat $tl 2>/dev/null)" 2>/dev/null wait if [ $? -ne 0 ]; then $PRINTF "$FAILED: $TRACE $SOCAT:\n" echo "$CMD &" echo "$CMD1" cat "${te}" "${te}1" numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" elif ! echo "$da" |diff - "$tf" >"$tdiff"; then $PRINTF "$FAILED\n" echo "$CMD &" echo "$CMD1" cat "$tdiff" cat "${te}" "${te}1" numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" else $PRINTF "$OK\n" if [ -n "$debug" ]; then cat "${te}" "${te}1"; fi numOK=$((numOK+1)) fi fi ;; # NUMCOND, feats esac N=$((N+1)) # use the INTERFACE address on a tun/tap device and transfer data fully # transparent NAME=TUNINTERFACE case "$TESTS" in *%$N%*|*%functions%*|*%tun%*|*%interface%*|*%root%*|*%$NAME%*) TEST="$NAME: pass data through tun interface using INTERFACE" #idea: create a TUN interface and send a raw packet on the interface side. # It should arrive unmodified on the tunnel side. if ! eval $NUMCOND; then :; elif ! feat=$(testfeats ip4 tun interface) || ! runsip4 >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}$feat not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif [ $(id -u) -ne 0 -a "$withroot" -eq 0 ]; then $PRINTF "test $F_n $TEST... ${YELLOW}must be root${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" else tf="$td/test$N.stdout" te="$td/test$N.stderr" tdiff="$td/test$N.diff" tl="$td/test$N.lock" da="$(date) $RANDOM" TUNNET=10.255.255 TUNNAME=tun9 CMD0="$TRACE $SOCAT $opts -L $tl TUN:$TUNNET.1/24,iff-up=1,tun-type=tun,tun-name=$TUNNAME PIPE" CMD1="$TRACE $SOCAT $opts - INTERFACE:$TUNNAME" printf "test $F_n $TEST... " $N $CMD0 2>"${te}1" & pid0="$!" #waitinterface "$TUNNAME" usleep $MICROS { echo "$da"; usleep $MICROS ; } |$CMD1 >"$tf" 2>"${te}" rc1=$? usleep $MICROS kill $pid0 2>/dev/null wait if [ "$rc1" -ne 0 ]; then $PRINTF "$FAILED (rc1=$rc1):\n" echo "$CMD0 &" cat "${te}0" >&2 echo "$CMD1" cat "${te}1" >&2 numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" elif ! echo "$da" |diff - "$tf" >"$tdiff"; then $PRINTF "$FAILED (diff)\n" echo "$CMD0 &" cat "${te}0" >&2 echo "$CMD1" cat "${te}1" >&2 echo "// diff:" cat "$tdiff" numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" else $PRINTF "$OK\n" if [ "$VERBOSE" ]; then echo "$CMD0 &"; fi if [ "$DEBUG" ]; then cat "${te}0" >&2; fi if [ "$VERBOSE" ]; then echo "$CMD1"; fi if [ "$DEBUG" ]; then cat "${te}1" >&2; fi numOK=$((numOK+1)) fi fi ;; # NUMCOND, feats esac N=$((N+1)) NAME=ABSTRACTSTREAM case "$TESTS" in *%$N%*|*%functions%*|*%unix%*|*%abstract%*|*%connect%*|*%listen%*|*%$NAME%*) TEST="$NAME: abstract UNIX stream socket, listen and connect" if ! eval $NUMCOND; then :; elif ! feat=$(testfeats abstract-unixsocket); then $PRINTF "test $F_n $TEST... ${YELLOW}$feat not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" else ts="$td/test$N.socket" tf="$td/test$N.stdout" te="$td/test$N.stderr" tdiff="$td/test$N.diff" da1="test$N $(date) $RANDOM" #establish a listening abstract unix socket SRV="$TRACE $SOCAT $opts -lpserver ABSTRACT-LISTEN:\"$ts\",$REUSEADDR PIPE" #make a connection CMD="$TRACE $SOCAT $opts - ABSTRACT-CONNECT:$ts" $PRINTF "test $F_n $TEST... " $N touch "$ts" # make a file with same name, so non-abstract fails eval "$SRV 2>${te}s &" pids=$! #waitfile "$ts" sleep 1 echo "$da1" |eval "$CMD" >"${tf}1" 2>"${te}1" if [ $? -ne 0 ]; then kill "$pids" 2>/dev/null $PRINTF "$FAILED:\n" echo "$SRV &" cat "${te}s" echo "$CMD" cat "${te}1" numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" elif ! echo "$da1" |diff - "${tf}1" >"$tdiff"; then kill "$pids" 2>/dev/null $PRINTF "$FAILED:\n" echo "$SRV &" cat "${te}s" echo "$CMD" cat "${te}1" cat "$tdiff" numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" else $PRINTF "$OK\n" if [ -n "$debug" ]; then cat $te; fi numOK=$((numOK+1)) fi # !(rc -ne 0) wait fi ;; # NUMCOND, feats esac N=$((N+1)) NAME=ABSTRACTDGRAM case "$TESTS" in *%$N%*|*%functions%*|*%unix%*|*%abstract%*|*%dgram%*|*%$NAME%*) TEST="$NAME: abstract UNIX datagram" if ! eval $NUMCOND; then :; elif ! feat=$(testfeats abstract-unixsocket); then $PRINTF "test $F_n $TEST... ${YELLOW}$feat not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" else tf="$td/test$N.stdout" te="$td/test$N.stderr" tdiff="$td/test$N.diff" ts1="$td/test$N.socket1" ts2="$td/test$N.socket2" da="test$N $(date) $RANDOM" CMD1="$TRACE $SOCAT $opts ABSTRACT-RECVFROM:$ts1,reuseaddr PIPE" #CMD2="$TRACE $SOCAT $opts - ABSTRACT-SENDTO:$ts1,bind=$ts2" CMD2="$TRACE $SOCAT $opts - ABSTRACT-SENDTO:$ts1,bind=$ts2" printf "test $F_n $TEST... " $N touch "$ts1" # make a file with same name, so non-abstract fails $CMD1 2>"${te}1" & pid1="$!" sleep 1 echo "$da" |$CMD2 >>"$tf" 2>>"${te}2" rc2=$? kill "$pid1" 2>/dev/null; wait if [ $rc2 -ne 0 ]; then $PRINTF "$FAILED: $TRACE $SOCAT:\n" echo "$CMD1 &" cat "${te}1" >&2 echo "$CMD2" cat "${te}2" >&2 numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" elif ! echo "$da" |diff - "$tf" >"$tdiff"; then $PRINTF "$FAILED\n" echo "$CMD1 &" cat "${te}1" >&2 echo "$CMD2" cat "${te}2" >&2 cat "$tdiff" >&2 numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" else $PRINTF "$OK\n" if [ "$VERBOSE" ]; then echo "$CMD1 &"; fi if [ "$DEBUG" ]; then cat "${te}1" >&2; fi if [ "$VERBOSE" ]; then echo "$CMD2"; fi if [ "$DEBUG" ]; then cat "${te}2" >&2; fi numOK=$((numOK+1)) fi fi ;; # NUMCOND, feats esac N=$((N+1)) NAME=ABSTRACTRECV case "$TESTS" in *%$N%*|*%functions%*|*%unix%*|*%abstract%*|*%dgram%*|*%recv%*|*%$NAME%*) TEST="$NAME: abstract UNIX datagram receive" if ! eval $NUMCOND; then :; elif ! feat=$(testfeats abstract-unixsocket); then $PRINTF "test $F_n $TEST... ${YELLOW}$feat not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" else ts="$td/test$N.socket" tf="$td/test$N.stdout" te="$td/test$N.stderr" tdiff="$td/test$N.diff" ts1="$ts" da="test$N $(date) $RANDOM" CMD1="$TRACE $SOCAT $opts -u ABSTRACT-RECV:$ts1,reuseaddr -" CMD2="$TRACE $SOCAT $opts -u - ABSTRACT-SENDTO:$ts1" printf "test $F_n $TEST... " $N touch "$ts1" # make a file with same name, so non-abstract fails $CMD1 >"$tf" 2>"${te}1" & pid1="$!" #waitfile $ts1 1 sleep 1 echo "$da" |$CMD2 2>>"${te}2" rc2="$?" i=0; while [ ! -s "$tf" -a "$i" -lt 10 ]; do usleep 100000; i=$((i+1)); done kill "$pid1" 2>/dev/null; wait if [ "$rc2" -ne 0 ]; then $PRINTF "$FAILED: $TRACE $SOCAT:\n" echo "$CMD1 &" cat "${te}1" >&2 echo "$CMD2" cat "${te}2" >&2 numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" elif ! echo "$da" |diff - "$tf" >"$tdiff"; then $PRINTF "$FAILED\n" echo "$CMD1 &" cat "${te}1" >&2 echo "$CMD2" cat "${te}2" >&2 cat "$tdiff" numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" else $PRINTF "$OK\n" if [ "$VERBOSE" ]; then echo "$CMD1 &"; fi if [ "$DEBUG" ]; then cat "${te}1" >&2; fi if [ "$VERBOSE" ]; then echo "$CMD2"; fi if [ "$DEBUG" ]; then cat "${te}2" >&2; fi numOK=$((numOK+1)) fi fi ;; # NUMCOND, feats esac N=$((N+1)) # bind with Linux abstract UNIX domain addresses bound to filesystem socket # instead of abstract namespace NAME=ABSTRACT_BIND case "$TESTS" in *%$N%*|*%functions%*|*%bugs%*|*%socket%*|*%unix%*|*%abstract%*|*%$NAME%*) TEST="$NAME: abstract bind" # open an abstract client address with bind option, bind to the target socket. # send a datagram. # when socat outputs the datagram it got the test succeeded if ! eval $NUMCOND; then :; elif [ "$UNAME" != Linux ]; then $PRINTF "test $F_n $TEST... ${YELLOW}only on Linux${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" else tf="$td/test$N.stdout" te="$td/test$N.stderr" tdiff="$td/test$N.diff" ts1="$td/test$N.sock1" da="test$N $(date) $RANDOM" CMD1="$TRACE $SOCAT $opts - ABSTRACT-SENDTO:$ts1,bind=$ts1" printf "test $F_n $TEST... " $N echo "$da" |$CMD1 >$tf 2>"${te}1" rc1=$? if [ $rc1 -ne 0 ]; then $PRINTF "$FAILED\n" echo "$CMD1" echo "rc=$rc1" >&2 cat "${te}1" >&2 numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" elif echo "$da" |diff -q - $tf; then $PRINTF "$OK\n" if [ "$VERBOSE" ]; then echo "$CMD1 &"; fi if [ "$DEBUG" ]; then cat "${te}1" >&2; fi numOK=$((numOK+1)) else $PRINTF "$FAILED\n" echo "$CMD1" >&2 cat "${te}1" >&2 echo "$da" |diff - "$tf" >&2 numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" fi fi # NUMCOND ;; esac N=$((N+1)) NAME=OPENSSLREAD # socat determined availability of data using select(). With openssl, the # following situation might occur: # a SSL data block with more than 8192 bytes (socats default blocksize) # arrives; socat calls SSL_read, and the SSL routine reads the complete block. # socat then reads 8192 bytes from the SSL layer, the rest remains buffered. # If the TCP connection stays idle for some time, the data in the SSL layer # keeps there and is not transferred by socat until the socket indicates more # data or EOF. case "$TESTS" in *%$N%*|*%functions%*|*%openssl%*|*%listen%*|*%$NAME%*) TEST="$NAME: socat handles data buffered by openssl" #idea: have a socat process (server) that gets an SSL block that is larger than # socat transfer block size; keep the socket connection open and kill the # server process after a short time; if not the whole data block has been # transferred, the test has failed. if ! eval $NUMCOND; then :; elif ! feat=$(testfeats openssl) >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}$(echo "$feat"| tr 'a-z' 'A-Z') not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" else tf="$td/test$N.out" te="$td/test$N.err" tdiff="$td/test$N.diff" da="test$N $(date) $RANDOM" SRVCERT=testsrv gentestcert "$SRVCERT" newport tcp4 # provide free port number in $PORT CMD1="$TRACE $SOCAT $opts -u -T 1 -b $($ECHO "$da\c" |wc -c) OPENSSL-LISTEN:$PORT,pf=ip4,$REUSEADDR,cert=$SRVCERT.pem,verify=0 -" CMD2="$TRACE $SOCAT $opts -u - OPENSSL-CONNECT:$LOCALHOST:$PORT,pf=ip4,verify=0" printf "test $F_n $TEST... " $N # $CMD1 2>"${te}1" >"$tf" & pid=$! # background process id waittcp4port $PORT (echo "$da"; sleep 2) |$CMD2 2>"${te}2" kill "$pid" 2>/dev/null; wait if ! echo "$da" |diff - "$tf" >"$tdiff"; then $PRINTF "$FAILED: $TRACE $SOCAT:\n" echo "$CMD1" cat "${te}1" echo "$CMD2" cat "${te}2" cat "$tdiff" numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" else $PRINTF "$OK\n" if [ -n "$debug" ]; then cat $te; fi numOK=$((numOK+1)) fi wait fi # NUMCOND, featsesac ;; esac N=$((N+1)) # test: there is a bug with the readbytes option: when the socket delivered # exacly that many bytes as specified with readbytes and the stays idle (no # more data, no EOF), socat waits for more data instead of generating EOF on # this in put stream. NAME=READBYTES_EOF #set -vx case "$TESTS" in *%$N%*|*%functions%*|*%$NAME%*) TEST="$NAME: trigger EOF after that many bytes, even when socket idle" #idea: we deliver that many bytes to socat; the process should terminate then. # we try to transfer data in the other direction then; if transfer succeeds, # the process did not terminate and the bug is still there. if ! eval $NUMCOND; then :; elif false; then $PRINTF "test $F_n $TEST... ${YELLOW}$(echo "$feat"| tr 'a-z' 'A-Z') not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" else tr="$td/test$N.ref" ti="$td/test$N.in" to="$td/test$N.out" te="$td/test$N.err" tdiff="$td/test$N.diff" da="test$N $(date) $RANDOM"; da="$da$($ECHO '\r')" CMD="$TRACE $SOCAT $opts SYSTEM:\"echo A; sleep $((2*SECONDs))\",readbytes=2!!- -!!/dev/null" printf "test $F_n $TEST... " $N (usleep $((2*MICROS)); echo) |eval "$CMD" >"$to" 2>"$te" if test -s "$to"; then $PRINTF "$FAILED: $TRACE $SOCAT:\n" echo "$CMD" numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" else $PRINTF "$OK\n" if [ -n "$debug" ]; then cat $te; fi numOK=$((numOK+1)) fi fi ;; # NUMCOND, feats esac N=$((N+1)) # test: there was a bug with exec:...,pty that did not kill the exec'd sub # process under some circumstances. NAME=EXECPTYKILL case "$TESTS" in *%$N%*|*%functions%*|*%bugs%*|*%exec%*|*%pty%*|*%listen%*|*%unix%*|*%fork%*|*%$NAME%*) TEST="$NAME: exec:...,pty explicitely kills sub process" # we want to check if the exec'd sub process is killed in time # for this we have a shell script that generates a file after two seconds; # it should be killed after one second, so if the file was generated the test # has failed if ! eval $NUMCOND; then :; else tf="$td/test$N.stdout" te="$td/test$N.stderr" ts="$td/test$N.sock" tda="$td/test$N.data" tsh="$td/test$N.sh" tdiff="$td/test$N.diff" cat >"$tsh" <"${te}2" & pid1=$! sleep $SECONDs waitfile $ts $SECONDs $CMD 2>>"${te}1" >>"$tf" sleep $((2*SECONDs)) kill "$pid1" 2>/dev/null wait if [ $? -ne 0 ]; then $PRINTF "$FAILED: $TRACE $SOCAT:\n" echo "$CMD1 &" echo "$CMD2" cat "${te}1" "${te}2" numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" elif [ -f "$tda" ]; then $PRINTF "$FAILED\n" cat "${te}1" "${te}2" numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" else $PRINTF "$OK\n" if [ -n "$debug" ]; then cat "${te}1" "${te}2"; fi numOK=$((numOK+1)) fi fi ;; # NUMCOND esac N=$((N+1)) # test if service name resolution works; this was buggy in 1.5 and 1.6.0.0 NAME=TCP4SERVICE case "$TESTS" in *%$N%*|*%functions%*|*%ip4%*|*%ipapp%*|*%tcp%*|*%listen%*|*%$NAME%*) TEST="$NAME: echo via connection to TCP V4 socket" # select a tcp entry from /etc/services, have a server listen on the port # number and connect using the service name; with the bug, connection will to a # wrong port if ! eval $NUMCOND; then :; else tf="$td/test$N.stdout" te="$td/test$N.stderr" tdiff="$td/test$N.diff" # find a service entry we do not need root for (>=1024; here >=1100 for ease) SERVENT="$(grep '^[a-z][a-z]*[^!-~][^!-~]*[1-9][1-9][0-9][0-9]/tcp' /etc/services |head -n 1)" SERVICE="$(echo $SERVENT |cut -d' ' -f1)" _PORT="$PORT" PORT="$(echo $SERVENT |sed 's/.* \([1-9][0-9]*\).*/\1/')" tsl="$PORT" ts="127.0.0.1:$SERVICE" da="test$N $(date) $RANDOM" CMD1="$TRACE $SOCAT $opts TCP4-LISTEN:$tsl,$REUSEADDR PIPE" CMD2="$TRACE $SOCAT $opts stdin!!stdout TCP4:$ts" printf "test $F_n $TEST... " $N $CMD1 >"$tf" 2>"${te}1" & pid1=$! waittcp4port $tsl 1 echo "$da" |$CMD2 >>"$tf" 2>>"${te}2" if [ $? -ne 0 ]; then $PRINTF "$FAILED: $TRACE $SOCAT:\n" echo "$CMD1 &" cat "${te}1" echo "$CMD2" cat "${te}2" numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" elif ! echo "$da" |diff - "$tf" >"$tdiff"; then $PRINTF "$FAILED\n" cat "$tdiff" numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" else $PRINTF "$OK\n" if [ -n "$debug" ]; then cat "${te}1" "${te}2"; fi numOK=$((numOK+1)) fi kill $pid1 2>/dev/null wait PORT=$_PORT fi ;; # NUMCOND esac N=$((N+1)) # test: up to socat 1.6.0.0, the highest file descriptor supported in socats # transfer engine was FOPEN_MAX-1; this usually worked fine but would fail when # socat was invoked with many file descriptors already opened. socat would # just hang in the select() call. Thanks to Daniel Lucq for reporting this # problem. # FOPEN_MAX on different OS's: # OS FOPEN_ ulimit ulimit FD_ # MAX -H -n -S -n SETSIZE # Linux 2.6: 16 1024 1024 1024 # HP-UX 11.11: 60 2048 2048 2048 # FreeBSD: 20 11095 11095 1024 # Cygwin: 20 unlimit 256 64 # AIX: 32767 65534 65534 # SunOS 8: 20 1024 # musl libc: 1024 NAME=EXCEED_FOPEN_MAX case "$TESTS" in *%$N%*|*%functions%*|*%maxfds%*|*%$NAME%*) TEST="$NAME: more than FOPEN_MAX FDs in use" # this test opens a number of FDs before socat is invoked. socat will have to # allocate higher FD numbers and thus hang if it cannot handle them. if ! eval $NUMCOND; then :; elif [ "$UNAME" != Linux ]; then $PRINTF "test $F_n $TEST... ${YELLOW}only on Linux${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" else REDIR= #set -vx if [ -z "$FOPEN_MAX" ]; then $PRINTF "test $F_n $TEST... ${YELLOW}could not determine FOPEN_MAX${NORMAL}\n" "$N" numCANT=$((numCANT+1)) listCANT="$listCANT $N" else if [ $FOPEN_MAX -lt 270 ]; then OPEN_FILES=$FOPEN_MAX # more than the highest FOPEN_MAX else OPEN_FILES=269 # bash tends to SIGSEGV on higher value # btw, the test is obsolete anyway fi i=3; while [ "$i" -lt "$OPEN_FILES" ]; do REDIR="$REDIR $i>&2" i=$((i+1)) done #echo "$REDIR" #testecho "$N" "$TEST" "" "pipe" "$opts -T 3" "" 1 #set -vx eval testecho "\"$N\"" "\"$TEST\"" "\"\"" "pipe" "\"$opts -T $((2*SECONDs))\"" 1 $REDIR #set +vx fi # could determine FOPEN_MAX fi ;; # NUMCOND esac N=$((N+1)) # there was a bug with udp-listen and fork: terminating sub processes became # zombies because the master process did not catch SIGCHLD NAME=UDP4LISTEN_SIGCHLD case "$TESTS" in *%$N%*|*%functions%*|*%ip4%*|*%ipapp%*|*%udp%*|*%zombie%*|*%signal%*|*%listen%*|*%fork%*|*%$NAME%*) TEST="$NAME: test if UDP4-LISTEN child becomes zombie" # idea: run a udp-listen process with fork and -T. Connect once, so a sub # process is forked off. Make some transfer and wait until the -T timeout is # over. Now check for the child process: if it is zombie the test failed. # Correct is that child process terminated if ! eval $NUMCOND; then :; else tf="$td/test$N.stdout" te="$td/test$N.stderr" tdiff="$td/test$N.diff" newport udp4; tsl=$PORT ts="$LOCALHOST:$tsl" da="test$N $(date) $RANDOM" CMD1="$TRACE $SOCAT $opts -T 0.5 UDP4-LISTEN:$tsl,$REUSEADDR,fork PIPE" CMD2="$TRACE $SOCAT $opts - UDP4:$ts" printf "test $F_n $TEST... " $N $CMD1 >"$tf" 2>"${te}1" & pid1=$! waitudp4port $tsl 1 echo "$da" |$CMD2 >>"$tf" 2>>"${te}2" rc2=$? sleep 1 #read -p ">" l="$(childprocess $pid1)" kill $pid1 2>/dev/null; wait if [ $rc2 -ne 0 ]; then $PRINTF "$NO_RESULT (client failed)\n" # already handled in test UDP4STREAM numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif ! echo "$da" |diff - "$tf" >"$tdiff"; then $PRINTF "$NO_RESULT (diff failed)\n" # already handled in test UDP4STREAM numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif $(isdefunct "$l"); then $PRINTF "$FAILED: $TRACE $SOCAT:\n" echo "$CMD1 &" echo "$CMD2" cat "${te}1" "${te}2" numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" else $PRINTF "$OK\n" if [ -n "$debug" ]; then cat "${te}1" "${te}2"; fi numOK=$((numOK+1)) fi fi ;; # NUMCOND esac N=$((N+1)) #set +vx # there was a bug with udp-recvfrom and fork: terminating sub processes became # zombies because the master process caught SIGCHLD but did not wait() NAME=UDP4RECVFROM_SIGCHLD case "$TESTS" in *%$N%*|*%functions%*|*%bugs%*|*%fork%*|*%ip4%*|*%udp%*|*%dgram%*|*%zombie%*|*%signal%*|*%$NAME%*) TEST="$NAME: test if UDP4-RECVFROM child becomes zombie" # idea: run a udp-recvfrom process with fork and -T. Send it one packet, so a # sub process is forked off. Make some transfer and wait until the -T timeout # is over. Now check for the child process: if it is zombie the test failed. # Correct is that child process terminated if ! eval $NUMCOND; then :; else tf="$td/test$N.stdout" te="$td/test$N.stderr" tdiff="$td/test$N.diff" newport udp4; tsl=$PORT ts="$LOCALHOST:$tsl" da="test$N $(date) $RANDOM" CMD1="$TRACE $SOCAT $opts -T 0.5 UDP4-RECVFROM:$tsl,reuseaddr,fork PIPE" CMD2="$TRACE $SOCAT $opts - UDP4-SENDTO:$ts" printf "test $F_n $TEST... " $N $CMD1 >"$tf" 2>"${te}1" & pid1=$! waitudp4port $tsl 1 echo "$da" |$CMD2 >>"$tf" 2>>"${te}2" rc2=$? sleep 1 #read -p ">" l="$(childprocess $pid1)" #echo "l=\"$l\"" kill $pid1 2>/dev/null; wait if [ $rc2 -ne 0 ]; then $PRINTF "$NO_RESULT\n" # already handled in test UDP4DGRAM if [ "$VERBOSE" ]; then echo "$CMD1 &"; fi if [ "$DEBUG" ]; then cat "${te}1" >&2; fi if [ "$VERBOSE" ]; then echo "$CMD2"; fi if [ "$DEBUG" ]; then cat "${te}2" >&2; fi numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif ! echo "$da" |diff - "$tf" >"$tdiff"; then $PRINTF "$NO_RESULT\n" # already handled in test UDP4DGRAM if [ "$VERBOSE" ]; then echo "$CMD1 &"; fi if [ "$DEBUG" ]; then cat "${te}1" >&2; fi if [ "$VERBOSE" ]; then echo "$CMD2"; fi if [ "$DEBUG" ]; then cat "${te}2" >&2; fi numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif $(isdefunct "$l"); then $PRINTF "$FAILED: $TRACE $SOCAT:\n" echo "$CMD1 &" cat "${te}1" >&2 echo "$CMD2" cat "${te}2" >&2 cat "${te}1" "${te}2" numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" else $PRINTF "$OK\n" if [ "$VERBOSE" ]; then echo "$CMD1 &"; fi if [ "$DEBUG" ]; then cat "${te}1" >&2; fi if [ "$VERBOSE" ]; then echo "$CMD2"; fi if [ "$DEBUG" ]; then cat "${te}2" >&2; fi numOK=$((numOK+1)) fi fi ;; # NUMCOND esac N=$((N+1)) # test: there was a bug with ip*-recv and bind option: it would not bind, and # with the first received packet an error: # socket_init(): unknown address family 0 # occurred NAME=RAWIP4RECVBIND case "$TESTS" in *%$N%*|*%functions%*|*%ip4%*|*%dgram%*|*%rawip%*|*%rawip4%*|*%recv%*|*%root%*|*%$NAME%*) TEST="$NAME: raw IPv4 receive with bind" # idea: start a socat process with ip4-recv:...,bind=... and send it a packet # if the packet passes the test succeeded if ! eval $NUMCOND; then :; elif [ $(id -u) -ne 0 -a "$withroot" -eq 0 ]; then $PRINTF "test $F_n $TEST... ${YELLOW}must be root${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" else tf="$td/test$N.stdout" te="$td/test$N.stderr" tdiff="$td/test$N.diff" ts1p=$PROTO; PROTO=$((PROTO+1)) ts1a="127.0.0.1" ts1="$ts1a:$ts1p" da="test$N $(date) $RANDOM" CMD1="$TRACE $SOCAT $opts -u IP4-RECV:$ts1p,bind=$ts1a,reuseaddr -" CMD2="$TRACE $SOCAT $opts -u - IP4-SENDTO:$ts1" printf "test $F_n $TEST... " $N $CMD1 >"$tf" 2>"${te}1" & pid1="$!" waitip4proto $ts1p 1 echo "$da" |$CMD2 2>>"${te}2" rc2="$?" #ls -l $tf i=0; while [ ! -s "$tf" -a "$i" -lt 10 ]; do usleep 100000; i=$((i+1)); done kill "$pid1" 2>/dev/null; wait if [ "$rc2" -ne 0 ]; then $PRINTF "$FAILED: $TRACE $SOCAT:\n" echo "$CMD1 &" echo "$CMD2" cat "${te}1" cat "${te}2" numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" elif ! echo "$da" |diff - "$tf" >"$tdiff"; then $PRINTF "$FAILED\n" cat "$tdiff" numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" else $PRINTF "$OK\n" if [ -n "$debug" ]; then cat $te; fi numOK=$((numOK+1)) fi fi ;; # NUMCOND, root esac PROTO=$((PROTO+1)) N=$((N+1)) # there was a bug in *-recvfrom with fork: due to an error in the appropriate # signal handler the master process would hang after forking off the first # child process. NAME=UDP4RECVFROM_FORK case "$TESTS" in *%$N%*|*%functions%*|*%fork%*|*%ip4%*|*%udp%*|*%dgram%*|*%$NAME%*) TEST="$NAME: test if UDP4-RECVFROM handles more than one packet" # idea: run a UDP4-RECVFROM process with fork and -T. Send it one packet; # send it a second packet and check if this is processed properly. If yes, the # test succeeded. if ! eval $NUMCOND; then :; else tf="$td/test$N.stdout" te="$td/test$N.stderr" tdiff="$td/test$N.diff" newport udp4; tsp=$PORT ts="$LOCALHOST:$tsp" da2a="test$N $(date) $RANDOM" da2b="test$N $(date) $RANDOM" CMD1="$TRACE $SOCAT $opts -T 2 UDP4-RECVFROM:$tsp,reuseaddr,fork PIPE" CMD2="$TRACE $SOCAT $opts -T 1 - UDP4-SENDTO:$ts" printf "test $F_n $TEST... " $N $CMD1 >/dev/null 2>"${te}1" & pid1=$! waitudp4port $tsp 1 echo "$da2a" |$CMD2 >/dev/null 2>>"${te}2a" # this should always work rc2a=$? echo "$da2b" |$CMD2 >"$tf" 2>>"${te}2b" # this would fail when bug rc2b=$? kill $pid1 2>/dev/null; wait if [ $rc2b -ne 0 ]; then $PRINTF "$NO_RESULT\n" numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif ! echo "$da2b" |diff - "$tf" >"$tdiff"; then $PRINTF "$FAILED: $TRACE $SOCAT:\n" echo "$CMD1 &" >&2 cat "${te}1" >&2 echo "$CMD2" >&2 cat "${te}2b" >&2 cat "$tdiff" >&2 numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" else $PRINTF "$OK\n" if [ -n "$debug" ]; then cat "${te}1" "${te}2" "${te}3"; fi numOK=$((numOK+1)) fi fi ;; # NUMCOND esac N=$((N+1)) # there was a bug in parsing the arguments of exec: consecutive spaces resulted # in additional empty arguments NAME=EXECSPACES case "$TESTS" in *%$N%*|*%functions%*|*%exec%*|*%parse%*|*%$NAME%*) TEST="$NAME: correctly parse exec with consecutive spaces" if ! eval $NUMCOND; then :; else $PRINTF "test $F_n $TEST... " $N tf="$td/test$N.stdout" te="$td/test$N.stderr" da="test$N $(date) $RANDOM" # with a double space tdiff="$td/test$N.diff" # put the test data as first argument after two spaces. expect the data in the # first argument of the exec'd command. $TRACE $SOCAT $opts -u "exec:\"bash -c \\\"echo \\\\\\\"\$1\\\\\\\"\\\" \\\"\\\" \\\"$da\\\"\"" - >"$tf" 2>"$te" rc=$? echo "$da" |diff - "$tf" >"$tdiff" if [ "$rc" -ne 0 ]; then $PRINTF "$FAILED: $TRACE $SOCAT:\n" cat "$te" numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" elif [ -s "$tdiff" ]; then $PRINTF "$FAILED: $TRACE $SOCAT:\n" echo diff: cat "$tdiff" if [ -n "$debug" ]; then cat $te; fi numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" else $PRINTF "$OK\n" if [ -n "$debug" ]; then cat $te; fi numOK=$((numOK+1)) fi fi ;; # NUMCOND esac N=$((N+1)) # a bug was found in the way UDP-LISTEN handles the listening socket: # when UDP-LISTEN continued to listen after a packet had been dropped by, e.g., # range option, the old listen socket would not be closed but a new one created. NAME=UDP4LISTENCONT case "$TESTS" in *%$N%*|*%functions%*|*%bugs%*|*%ip4%*|*%udp%*|*%listen%*|*%$NAME%*) TEST="$NAME: let range drop a packet and see if old socket is closed" # idea: run a UDP4-LISTEN process with range option. Send it one packet from an # address outside range and check if two listening sockets are open then if ! eval $NUMCOND; then :; else tf="$td/test$N.stdout" te="$td/test$N.stderr" tdiff="$td/test$N.diff" newport udp4; tp=$PORT da1="test$N $(date) $RANDOM" a1="$LOCALHOST" a2="$SECONDADDR" #CMD0="$TRACE $SOCAT $opts UDP4-LISTEN:$tp,bind=$a1,range=$a2/32 PIPE" CMD0="$TRACE $SOCAT $opts UDP4-LISTEN:$tp,$REUSEADDR,range=$a2/32 PIPE" CMD1="$TRACE $SOCAT $opts - UDP-CONNECT:$a1:$tp" printf "test $F_n $TEST... " $N $CMD0 >/dev/null 2>"${te}0" & pid1=$! waitudp4port $tp 1 echo "$da1" |$CMD1 >"${tf}1" 2>"${te}1" # this should fail rc1=$? waitudp4port $tp 1 if [ "$SS" ]; then nsocks="$($SS -anu |grep ":$PORT\>" |wc -l)" else nsocks="$(netstat -an |grep "^udp.*[:.]$PORT\>" |wc -l)" fi kill $pid1 2>/dev/null; wait if [ $rc1 -ne 0 ]; then $PRINTF "$NO_RESULT\n" numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif [ $nsocks -eq 0 ]; then $PRINTF "$NO_RESULT\n" numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif [ $nsocks -ne 1 ]; then $PRINTF "$FAILED ($nsocks listening sockets)\n" echo "$CMD0 &" echo "$CMD1" cat "${te}0" "${te}1" numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" else $PRINTF "$OK\n" if [ -n "$debug" ]; then cat "${te}0" "${te}1" "${te}2"; fi numOK=$((numOK+1)) fi fi ;; # NUMCOND esac N=$((N+1)) # during wait for next poll time option ignoreeof blocked the data transfer in # the reverse direction NAME=IGNOREEOFNOBLOCK case "$TESTS" in *%$N%*|*%functions%*|*%engine%*|*%socket%*|*%ignoreeof%*|*%$NAME%*) TEST="$NAME: ignoreeof does not block other direction" # have socat poll in ignoreeof mode. while it waits one second for next check, # we send data in the reverse direction and then the total timeout fires. # it the data has passed, the test succeeded. if ! eval $NUMCOND; then :; else tf="$td/test$N.stout" te="$td/test$N.stderr" tdiff="$td/test$N.diff" da="test$N $(date) $RANDOM" CMD0="$TRACE $SOCAT $opts /dev/null,ignoreeof!!- -!!/dev/null" printf "test $F_n $TEST... " $N (usleep 333333; echo "$da") |$CMD0 >"$tf" 2>"${te}0" rc0=$? if [ $rc0 != 0 ]; then $PRINTF "$FAILED\n" echo "$CMD0 &" echo "$CMD1" cat "${te}0" cat "${te}1" numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" elif echo "$da" |diff - "$tf" >/dev/null; then $PRINTF "$OK\n" numOK=$((numOK+1)) else $PRINTF "$FAILED\n" echo "$CMD0 &" echo "$CMD1" cat "${te}0" numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" fi fi ;; # NUMCOND esac N=$((N+1)) # test the escape option NAME=ESCAPE case "$TESTS" in *%$N%*|*%functions%*|*%engine%*|*%escape%*|*%$NAME%*) TEST="$NAME: escape character triggers EOF" # idea: start socat just echoing input, but apply escape option. send a string # containing the escape character and check if the output is truncated if ! eval $NUMCOND; then :; else tf="$td/test$N.stdout" te="$td/test$N.stderr" tdiff="$td/test$N.diff" da="test$N $(date) $RANDOM" CMD="$TRACE $SOCAT $opts -,escape=27 pipe" printf "test $F_n $TEST... " $N $ECHO "$da\n\x1bXYZ" |$CMD >"$tf" 2>"$te" if [ $? -ne 0 ]; then $PRINTF "$FAILED: $TRACE $SOCAT:\n" echo "$CMD" cat "$te" numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" elif ! echo "$da" |diff - "$tf" >"$tdiff"; then $PRINTF "$FAILED: diff:\n" cat "$tdiff" numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" else $PRINTF "$OK\n" if [ -n "$debug" ]; then cat $te; fi numOK=$((numOK+1)) fi fi ;; # NUMCOND esac N=$((N+1)) # test the escape option combined with ignoreeof NAME=ESCAPE_IGNOREEOF case "$TESTS" in *%$N%*|*%functions%*|*%engine%*|*%ignoreeof%*|*%escape%*|*%$NAME%*) TEST="$NAME: escape character triggers EOF" # idea: start socat just echoing input, but apply escape option. send a string # containing the escape character and check if the output is truncated if ! eval $NUMCOND; then :; else ti="$td/test$N.file" tf="$td/test$N.stdout" te="$td/test$N.stderr" tdiff="$td/test$N.diff" da="test$N $(date) $RANDOM" CMD="$TRACE $SOCAT -T 5 $opts file:$ti,ignoreeof,escape=27!!- pipe" printf "test $F_n $TEST... " $N >"$ti" $CMD >"$tf" 2>"$te" & $ECHO "$da\n\x1bXYZ" >>"$ti" sleep 1 if ! echo "$da" |diff - "$tf" >"$tdiff"; then $PRINTF "$FAILED: diff:\n" cat "$tdiff" cat "$te" numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" else $PRINTF "$OK\n" if [ -n "$debug" ]; then cat $te; fi numOK=$((numOK+1)) fi fi ;; # NUMCOND esac N=$((N+1)) # test: logging of ancillary message while read PF KEYW ADDR IPPORT SCM_ENABLE SCM_RECV SCM_TYPE SCM_NAME ROOT SCM_VALUE do if [ -z "$PF" ] || [[ "$PF" == \#* ]]; then continue; fi # pf="$(echo "$PF" |tr A-Z a-z)" proto="$(echo "$KEYW" |tr A-Z a-z)" NAME=${KEYW}SCM_$SCM_TYPE case "$TESTS" in *%$N%*|*%functions%*|*%socket%*|*%$pf%*|*%dgram%*|*%udp%*|*%$proto%*|*%recv%*|*%ancillary%*|*%$ROOT%*|*%$NAME%*) TEST="$NAME: $KEYW log ancillary message $SCM_TYPE $SCM_NAME" # idea: start a socat process with *-RECV:..,... , ev. with ancillary message # enabling option and send it a packet, ev. with some option. check the info log # for the appropriate output. if ! eval $NUMCOND; then :; #elif [[ "$PF" == "#*" ]]; then : elif [ "$ROOT" = root -a $(id -u) -ne 0 -a "$withroot" -eq 0 ]; then $PRINTF "test $F_n $TEST... ${YELLOW}must be root${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif [ "$PF" = "IP6" ] && ( ! feat=$(testfeats ip6) || ! runsip6 >/dev/null ); then $PRINTF "test $F_n $TEST... ${YELLOW}IP6 not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif ! testoptions $SCM_RECV >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}option $SCM_RECV not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" else tf="$td/test$N.stdout" te="$td/test$N.stderr" case "X$IPPORT" in "XPORT") newport $proto; tra="$PORT" # test recv address tsa="$ADDR:$PORT" # test sendto address ;; "XPROTO") tra="$PROTO" # test recv address tsa="$ADDR:$PROTO" # test sendto address PROTO=$((PROTO+1)) ;; *) tra="$(eval echo "$ADDR")" # resolve $N tsa="$tra" esac CMD0="$TRACE $SOCAT $opts -d -d -d -u $KEYW-RECV:$tra,reuseaddr,$SCM_RECV -" CMD1="$TRACE $SOCAT $opts -u - $KEYW-SENDTO:$tsa,$SCM_ENABLE" printf "test $F_n $TEST... " $N # is this option supported? if $SOCAT -hhh |grep "[[:space:]]$SCM_RECV[[:space:]]" >/dev/null; then if [ "$SCM_VALUE" = "timestamp" ]; then secs="$(date '+%S')" if [ "$secs" -ge 58 -a "$secs" -le 59 ]; then dsecs=$((60-secs)) #echo "Sleeping $dsecs seconds to avoid minute change in timestamp" >/dev/tty sleep $dsecs fi fi $CMD0 >"$tf" 2>"${te}0" & pid0="$!" wait${proto}port $tra 1 echo "XYZ" |$CMD1 2>"${te}1" rc1="$?" sleep 1 i=0; while [ ! -s "${te}0" -a "$i" -lt 10 ]; do usleep 100000; i=$((i+1)); done kill "$pid0" 2>/dev/null; wait # do not show more messages than requested case "$opts" in *-d*-d*-d*-d*) LEVELS="[EWNID]" ;; *-d*-d*-d*) LEVELS="[EWNI]" ;; *-d*-d*) LEVELS="[EWN]" ;; *-d*) LEVELS="[EW]" ;; *) LEVELS="[E]" ;; esac if [ "$SCM_VALUE" = "timestamp" ]; then SCM_VALUE="$(date '+%a %b %e %H:%M:.. %Y'), ...... usecs" fi if [ "$rc1" -ne 0 ]; then $PRINTF "$NO_RESULT: $TRACE $SOCAT:\n" echo "$CMD0 &" echo "$CMD1" grep " $LEVELS " "${te}0" grep " $LEVELS " "${te}1" numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif ! grep "ancillary message: $SCM_TYPE: $SCM_NAME=" ${te}0 >/dev/null; then $PRINTF "$FAILED\n" echo "variable $SCM_TYPE: $SCM_NAME not set" echo "$CMD0 &" echo "$CMD1" grep " $LEVELS " "${te}0" grep " $LEVELS " "${te}1" numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" elif ! grep "ancillary message: $SCM_TYPE: $SCM_NAME=$SCM_VALUE\$" ${te}0 >/dev/null; then $PRINTF "$FAILED\n" badval="$(grep "ancillary message: $SCM_TYPE: $SCM_NAME" ${te}0 |sed 's/.*=//g')" echo "variable $SCM_TYPE: $SCM_NAME has value \"$badval\" instead of pattern \"$SCM_VALUE\"" >&2 echo "$CMD0 &" echo "$CMD1" grep " $LEVELS " "${te}0" grep " $LEVELS " "${te}1" numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" else $PRINTF "$OK\n" if [ "$VERBOSE" ]; then echo "$CMD0 &"; fi if [ "$DEBUG" ]; then grep " $LEVELS " "${te}0" >&2; fi if [ "$VERBOSE" ]; then echo "echo XYZ |$CMD1"; fi if [ "$DEBUG" ]; then grep " $LEVELS " "${te}1" >&2; fi numOK=$((numOK+1)) fi else # option is not supported $PRINTF "${YELLOW}$SCM_RECV not available${NORMAL}\n" numCANT=$((numCANT+1)) listCANT="$listCANT $N" fi # option is not supported fi # NUMCOND, root, feats ;; esac N=$((N+1)) # done <<<" IP4 UDP4 127.0.0.1 PORT ip-options=x01000000 ip-recvopts IP_OPTIONS options user x01000000 IP4 UDP4 127.0.0.1 PORT , so-timestamp SCM_TIMESTAMP timestamp user timestamp IP4 UDP4 127.0.0.1 PORT ip-ttl=53 ip-recvttl IP_TTL ttl user 53 IP4 UDP4 127.0.0.1 PORT ip-tos=7 ip-recvtos IP_TOS tos user 7 IP4 UDP4 127.0.0.1 PORT , ip-pktinfo IP_PKTINFO locaddr user 127.0.0.1 IP4 UDP4 127.0.0.1 PORT , ip-pktinfo IP_PKTINFO dstaddr user 127.0.0.1 IP4 UDP4 127.0.0.1 PORT , ip-pktinfo IP_PKTINFO if user lo IP4 UDP4 127.0.0.1 PORT , ip-recvif IP_RECVIF if user lo0 IP4 UDP4 127.0.0.1 PORT , ip-recvdstaddr IP_RECVDSTADDR dstaddr user 127.0.0.1 IP4 IP4 127.0.0.1 PROTO ip-options=x01000000 ip-recvopts IP_OPTIONS options root x01000000 IP4 IP4 127.0.0.1 PROTO , so-timestamp SCM_TIMESTAMP timestamp root timestamp IP4 IP4 127.0.0.1 PROTO ip-ttl=53 ip-recvttl IP_TTL ttl root 53 IP4 IP4 127.0.0.1 PROTO ip-tos=7 ip-recvtos IP_TOS tos root 7 IP4 IP4 127.0.0.1 PROTO , ip-pktinfo IP_PKTINFO locaddr root 127.0.0.1 IP4 IP4 127.0.0.1 PROTO , ip-pktinfo IP_PKTINFO dstaddr root 127.0.0.1 IP4 IP4 127.0.0.1 PROTO , ip-pktinfo IP_PKTINFO if root lo IP4 IP4 127.0.0.1 PROTO , ip-recvif IP_RECVIF if root lo0 IP4 IP4 127.0.0.1 PROTO , ip-recvdstaddr IP_RECVDSTADDR dstaddr root 127.0.0.1 IP6 UDP6 [::1] PORT , so-timestamp SCM_TIMESTAMP timestamp user timestamp IP6 UDP6 [::1] PORT , ipv6-recvpktinfo IPV6_PKTINFO dstaddr user [[]0000:0000:0000:0000:0000:0000:0000:0001[]] IP6 UDP6 [::1] PORT ipv6-unicast-hops=35 ipv6-recvhoplimit IPV6_HOPLIMIT hoplimit user 35 IP6 UDP6 [::1] PORT ipv6-tclass=0xaa ipv6-recvtclass IPV6_TCLASS tclass user x000000aa IP6 IP6 [::1] PROTO , so-timestamp SCM_TIMESTAMP timestamp root timestamp IP6 IP6 [::1] PROTO , ipv6-recvpktinfo IPV6_PKTINFO dstaddr root [[]0000:0000:0000:0000:0000:0000:0000:0001[]] IP6 IP6 [::1] PROTO ipv6-unicast-hops=35 ipv6-recvhoplimit IPV6_HOPLIMIT hoplimit root 35 IP6 IP6 [::1] PROTO ipv6-tclass=0xaa ipv6-recvtclass IPV6_TCLASS tclass root x000000aa #UNIX UNIX $td/test\$N.server - , so-timestamp SCM_TIMESTAMP timestamp user timestamp " # this one fails, appearently due to a Linux weakness: # UNIX so-timestamp # test: setting of environment variables that describe a stream socket # connection: SOCAT_SOCKADDR, SOCAT_PEERADDR; and SOCAT_SOCKPORT, # SOCAT_PEERPORT when applicable while read KEYW FEAT TEST_SOCKADDR TEST_PEERADDR PORTMETHOD; do if [ -z "$KEYW" ] || [[ "$KEYW" == \#* ]]; then continue; fi # protov="$(echo "$KEYW" |tr A-Z a-z)" proto="${protov%%[0-9]}" NAME=${KEYW}LISTENENV case "$TESTS" in *%$N%*|*%functions%*|*%ip4%*|*%ipapp%*|*%tcp%*|*%$proto%*|*%$protov%*|*%envvar%*|*%listen%*|*%$NAME%*) TEST="$NAME: $KEYW-LISTEN sets environment variables with socket addresses" # have a server accepting a connection and invoking some shell code. The shell # code extracts and prints the SOCAT related environment vars. # outside code then checks if the environment contains the variables correctly # describing the peer and local sockets. if ! eval $NUMCOND; then :; elif ! feat=$(testfeats $FEAT); then $PRINTF "test $F_n $TEST... ${YELLOW}$(echo "$feat" |tr a-z A-Z) not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif [ "$KEYW" = "TCP6" -o "$KEYW" = "UDP6" -o "$KEYW" = "SCTP6" ] && \ ! runsip6 >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}IP6 not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif [ "$KEYW" = "SCTP4" ] && ! runssctp4 >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}$KEYW not available${NORMAL}\n" $N elif [ "$KEYW" = "SCTP6" ] && ! runssctp6 >/dev/null; then #!!! branch not reached - caught above! $PRINTF "test $F_n $TEST... ${YELLOW}$KEYW not available${NORMAL}\n" $N else tf="$td/test$N.stdout" te="$td/test$N.stderr" TEST_SOCKADDR="$(echo "$TEST_SOCKADDR" |sed "s/\$N/$N/g")" # actual vars tsa="$TEST_SOCKADDR" # test server address if [ "$PORTMETHOD" == PORT ]; then newport $proto; tsp="$PORT"; # test server port tsa1="$tsp"; tsa2="$tsa"; tsa="$tsa:$tsp" # tsa2 used for server bind= else tsa1="$tsa"; tsa2= # tsa1 used for addr parameter fi TEST_PEERADDR="$(echo "$TEST_PEERADDR" |sed "s/\$N/$N/g")" # actual vars tca="$TEST_PEERADDR" # test client address if [ $PORTMETHOD = PORT ]; then newport $proto; tcp="$PORT"; # test client port tca="$tca:$tcp" fi #CMD0="$TRACE $SOCAT $opts -u $KEYW-LISTEN:$tsa1 SYSTEM:\"export -p\"" CMD0="$TRACE $SOCAT $opts -u -lpsocat $KEYW-LISTEN:$tsa1,$REUSEADDR SYSTEM:\"echo SOCAT_SOCKADDR=\\\$SOCAT_SOCKADDR; echo SOCAT_PEERADDR=\\\$SOCAT_PEERADDR; echo SOCAT_SOCKPORT=\\\$SOCAT_SOCKPORT; echo SOCAT_PEERPORT=\\\$SOCAT_PEERPORT; sleep 1\"" CMD1="$TRACE $SOCAT $opts -u - $KEYW-CONNECT:$tsa,bind=$tca" printf "test $F_n $TEST... " $N eval "$CMD0 2>\"${te}0\" >\"$tf\" &" pid0=$! wait${protov}port $tsa1 1 { echo; sleep 0.1; } |$CMD1 2>"${te}1" rc1=$? waitfile "$tf" 2 kill $pid0 2>/dev/null; wait #set -vx if [ $rc1 != 0 ]; then $PRINTF "$NO_RESULT (client failed):\n" echo "$CMD0 &" cat "${te}0" echo "$CMD1" cat "${te}1" numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif [ "$(grep SOCAT_SOCKADDR "${tf}" |sed -e 's/^[^=]*=//' |sed -e "s/[\"']//g")" = "$TEST_SOCKADDR" -a \ "$(grep SOCAT_PEERADDR "${tf}" |sed -e 's/^[^=]*=//' -e "s/[\"']//g")" = "$TEST_PEERADDR" -a \ \( "$PORTMETHOD" = ',' -o "$(grep SOCAT_SOCKPORT "${tf}" |sed -e 's/^[^=]*=//' |sed -e 's/"//g')" = "$tsp" \) -a \ \( "$PORTMETHOD" = ',' -o "$(grep SOCAT_PEERPORT "${tf}" |sed -e 's/^[^=]*=//' |sed -e 's/"//g')" = "$tcp" \) \ ]; then $PRINTF "$OK\n" if [ "$debug" ]; then echo "$CMD0 &" cat "${te}0" echo "$CMD1" cat "${te}1" fi numOK=$((numOK+1)) else $PRINTF "$FAILED\n" echo "$CMD0 &" cat "${te}0" echo "$CMD1" cat "${te}1" echo -e "SOCAT_SOCKADDR=$TEST_SOCKADDR\nSOCAT_PEERADDR=$TEST_PEERADDR\nSOCAT_SOCKPORT=$TEST_SOCKPORT\nSOCAT_PEERPORT=$TEST_PEERPORT" | diff - "${tf}" numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" fi fi # NUMCOND, feats ;; esac N=$((N+1)) #set +xv # done <<<" TCP4 TCP 127.0.0.1 $SECONDADDR PORT TCP6 IP6 [0000:0000:0000:0000:0000:0000:0000:0001] [0000:0000:0000:0000:0000:0000:0000:0001] PORT UDP6 IP6 [0000:0000:0000:0000:0000:0000:0000:0001] [0000:0000:0000:0000:0000:0000:0000:0001] PORT SCTP4 SCTP 127.0.0.1 $SECONDADDR PORT SCTP6 SCTP [0000:0000:0000:0000:0000:0000:0000:0001] [0000:0000:0000:0000:0000:0000:0000:0001] PORT UNIX UNIX $td/test\$N.server $td/test\$N.client , " # this one fails due to weakness in socats UDP4-LISTEN implementation: #UDP4 $LOCALHOST $SECONDADDR $((PORT+4)) $((PORT+5)) # test: environment variables from ancillary message while read PF KEYW ADDR IPPORT SCM_ENABLE SCM_RECV SCM_ENVNAME ROOT SCM_VALUE do if [ -z "$PF" ] || [[ "$PF" == \#* ]]; then continue; fi # pf="$(echo "$PF" |tr A-Z a-z)" proto="$(echo "$KEYW" |tr A-Z a-z)" NAME=${KEYW}ENV_$SCM_ENVNAME case "$TESTS" in *%$N%*|*%functions%*|*%socket%*|*%$pf%*|*%dgram%*|*%udp%*|*%$proto%*|*%recv%*|*%ancillary%*|*%envvar%*|*%$ROOT%*|*%$NAME%*) #set -vx TEST="$NAME: $KEYW ancillary message sets env SOCAT_$SCM_ENVNAME" # idea: start a socat process with *-RECVFROM:..,... , ev. with ancillary # message enabling option and send it a packet, ev. with some option. write # the resulting environment to a file and check its contents for the # appropriate variable. if ! eval $NUMCOND; then :; elif [ "$ROOT" = root -a $(id -u) -ne 0 -a "$withroot" -eq 0 ]; then $PRINTF "test $F_n $TEST... ${YELLOW}must be root${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif [ "$PF" = "IP6" ] && ( ! feat=$(testfeats ip6) || ! runsip6 ) >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}IP6 not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" else tf="$td/test$N.stdout" te="$td/test$N.stderr" case "X$IPPORT" in "XPORT") newport $proto; tra="$PORT" # test recv address tsa="$ADDR:$tra" # test sendto address ;; "XPROTO") tra="$PROTO" # test recv address tsa="$ADDR:$PROTO" # test sendto address PROTO=$((PROTO+1)) ;; *) tra="$(eval echo "$ADDR")" # resolve $N tsa="$tra" esac #CMD0="$TRACE $SOCAT $opts -u $KEYW-RECVFROM:$tra,reuseaddr,$SCM_RECV SYSTEM:\"export -p\"" # without that ultra escaped quote the test failed for IPv6 when there was file ./1 CMD0="$TRACE $SOCAT $opts -u -lpsocat $KEYW-RECVFROM:$tra,reuseaddr,$SCM_RECV SYSTEM:\"echo \\\\\\\"\\\$SOCAT_$SCM_ENVNAME\\\\\\\"\"" CMD1="$TRACE $SOCAT $opts -u - $KEYW-SENDTO:$tsa,$SCM_ENABLE" printf "test $F_n $TEST... " $N # is this option supported? if $SOCAT -hhh |grep "[[:space:]]$SCM_RECV[[:space:]]" >/dev/null; then if [ "$SCM_VALUE" = "timestamp" ]; then secs="$(date '+%S')" if [ "$secs" -ge 58 -a "$secs" -le 59 ]; then dsecs=$((60-secs)) #echo "Sleeping $dsecs seconds to avoid minute change in timestamp" >/dev/tty sleep $dsecs fi fi eval "$CMD0 >\"$tf\" 2>\"${te}0\" &" pid0="$!" wait${proto}port $tra 1 { echo "XYZ"; sleep 0.1; } |$CMD1 2>"${te}1" rc1="$?" waitfile "$tf" 2 #i=0; while [ ! -s "${te}0" -a "$i" -lt 10 ]; do usleep 100000; i=$((i+1)); done kill "$pid0" 2>/dev/null; wait # do not show more messages than requested if [ "$SCM_VALUE" = "timestamp" ]; then SCM_VALUE="$(date '+%a %b %e %H:%M:.. %Y'), ...... usecs" #echo "\"$SCM_VALUE\"" >&2 # debugging fi if [ "$rc1" -ne 0 ]; then $PRINTF "$NO_RESULT: $SOCAT:\n" echo "$CMD0 &" echo "$CMD1" cat "${te}0" cat "${te}1" numCANT=$((numCANT+1)) listCANT="$listCANT $N" #elif ! egrep "^export SOCAT_$SCM_ENVNAME=[\"']?$SCM_VALUE[\"']?\$" ${tf} >/dev/null; then #elif ! eval echo "$TRACE $SOCAT_\$SCM_VALUE" |diff - "${tf}" >/dev/null; then elif ! expr "$(cat "$tf")" : "$SCM_VALUE\$" >/dev/null; then $PRINTF "$FAILED\n" echo "logged value \"$(cat "$tf")\" instead of $SCM_VALUE" echo "$CMD0 &" echo "$CMD1" cat "${te}0" cat "${te}1" numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" else $PRINTF "$OK\n" if [ "$VERBOSE" ]; then echo "$CMD0 &"; fi if [ "$DEBUG" ]; then cat "${te}0" >&2; fi if [ "$VERBOSE" ]; then echo "{ echo XYZ; sleep 0.1; } |$CMD1"; fi if [ "$DEBUG" ]; then cat "${te}1" >&2; fi numOK=$((numOK+1)) fi else # option is not supported $PRINTF "${YELLOW}$SCM_RECV not available${NORMAL}\n" numCANT=$((numCANT+1)) listCANT="$listCANT $N" fi # option is not supported fi ;; # NUMCOND, feats esac N=$((N+1)) # done <<<" IP4 UDP4 127.0.0.1 PORT ip-options=x01000000 ip-recvopts IP_OPTIONS user x01000000 IP4 UDP4 127.0.0.1 PORT , so-timestamp TIMESTAMP user timestamp IP4 UDP4 127.0.0.1 PORT ip-ttl=53 ip-recvttl IP_TTL user 53 IP4 UDP4 127.0.0.1 PORT ip-tos=7 ip-recvtos IP_TOS user 7 IP4 UDP4 127.0.0.1 PORT , ip-pktinfo IP_LOCADDR user 127.0.0.1 IP4 UDP4 127.0.0.1 PORT , ip-pktinfo IP_DSTADDR user 127.0.0.1 IP4 UDP4 127.0.0.1 PORT , ip-pktinfo IP_IF user lo IP4 UDP4 127.0.0.1 PORT , ip-recvif IP_IF user lo0 IP4 UDP4 127.0.0.1 PORT , ip-recvdstaddr IP_DSTADDR user 127.0.0.1 IP4 IP4 127.0.0.1 PROTO ip-options=x01000000 ip-recvopts IP_OPTIONS root x01000000 IP4 IP4 127.0.0.1 PROTO , so-timestamp TIMESTAMP root timestamp IP4 IP4 127.0.0.1 PROTO ip-ttl=53 ip-recvttl IP_TTL root 53 IP4 IP4 127.0.0.1 PROTO ip-tos=7 ip-recvtos IP_TOS root 7 IP4 IP4 127.0.0.1 PROTO , ip-pktinfo IP_LOCADDR root 127.0.0.1 IP4 IP4 127.0.0.1 PROTO , ip-pktinfo IP_DSTADDR root 127.0.0.1 IP4 IP4 127.0.0.1 PROTO , ip-pktinfo IP_IF root lo IP4 IP4 127.0.0.1 PROTO , ip-recvif IP_IF root lo0 IP4 IP4 127.0.0.1 PROTO , ip-recvdstaddr IP_DSTADDR root 127.0.0.1 IP6 UDP6 [::1] PORT , ipv6-recvpktinfo IPV6_DSTADDR user [[]0000:0000:0000:0000:0000:0000:0000:0001[]] IP6 UDP6 [::1] PORT ipv6-unicast-hops=35 ipv6-recvhoplimit IPV6_HOPLIMIT user 35 IP6 UDP6 [::1] PORT ipv6-tclass=0xaa ipv6-recvtclass IPV6_TCLASS user x000000aa IP6 IP6 [::1] PROTO , ipv6-recvpktinfo IPV6_DSTADDR root [[]0000:0000:0000:0000:0000:0000:0000:0001[]] IP6 IP6 [::1] PROTO ipv6-unicast-hops=35 ipv6-recvhoplimit IPV6_HOPLIMIT root 35 IP6 IP6 [::1] PROTO ipv6-tclass=0xaa ipv6-recvtclass IPV6_TCLASS root x000000aa #UNIX UNIX $td/test\$N.server - , so-timestamp TIMESTAMP user timestamp " # test the SOCKET-CONNECT address (against TCP4-LISTEN) NAME=SOCKET_CONNECT_TCP4 case "$TESTS" in *%$N%*|*%functions%*|*%generic%*|*%socket%*|*%listen%*|*%$NAME%*) TEST="$NAME: socket connect with TCP/IPv4" # start a TCP4-LISTEN process that echoes data, and send test data using # SOCKET-CONNECT, selecting TCP/IPv4. The sent data should be returned. if ! eval $NUMCOND; then :; else tf="$td/test$N.stdout" te="$td/test$N.stderr" tdiff="$td/test$N.diff" newport tcp4; ts0p=$PORT ts0a="127.0.0.1" ts1p=$(printf "%04x" $ts0p); ts1a="7f000001" # "127.0.0.1" ts1="x${ts1p}${ts1a}x0000000000000000" newport tcp4; ts1b=$(printf "%04x" $PORT) da="test$N $(date) $RANDOM" CMD0="$TRACE $SOCAT $opts TCP4-LISTEN:$ts0p,$REUSEADDR,bind=$ts0a PIPE" CMD1="$TRACE $SOCAT $opts - SOCKET-CONNECT:2:6:$ts1,bind=x${ts1b}00000000x0000000000000000" printf "test $F_n $TEST... " $N $CMD0 2>"${te}0" & pid0="$!" waittcp4port $ts0p 1 echo "$da" |$CMD1 >>"$tf" 2>>"${te}1" rc1="$?" kill "$pid0" 2>/dev/null; wait; if [ "$rc1" -ne 0 ]; then $PRINTF "$FAILED: $TRACE $SOCAT:\n" echo "$CMD0 &" cat "${te}0" echo "$CMD1" cat "${te}1" numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" elif ! echo "$da" |diff - "$tf" >"$tdiff"; then $PRINTF "$FAILED\n" cat "$tdiff" echo "$CMD0 &" cat "${te}0" echo "$CMD1" cat "${te}1" numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" else $PRINTF "$OK\n" if [ -n "$debug" ]; then cat $te; fi numOK=$((numOK+1)) fi fi # NUMCOND ;; esac N=$((N+1)) # test the SOCKET-CONNECT address (against TCP6-LISTEN) NAME=SOCKET_CONNECT_TCP6 case "$TESTS" in *%$N%*|*%functions%*|*%generic%*|*%tcp6%*|*%socket%*|*%listen%*|*%$NAME%*) TEST="$NAME: socket connect with TCP/IPv6" if ! eval $NUMCOND; then :; elif ! testfeats tcp ip6 >/dev/null || ! runsip6 >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}TCP6 not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" else # start a TCP6-LISTEN process that echoes data, and send test data using # SOCKET-CONNECT, selecting TCP/IPv6. The sent data should be returned. tf="$td/test$N.stdout" te="$td/test$N.stderr" tdiff="$td/test$N.diff" newport tcp6; ts0p=$PORT ts0a="[::1]" ts1p=$(printf "%04x" $ts0p); ts1a="00000000000000000000000000000001" # "[::1]" ts1="x${ts1p}x00000000x${ts1a}x00000000" newport tcp6; ts1b=$(printf "%04x" $PORT) da="test$N $(date) $RANDOM" CMD0="$TRACE $SOCAT $opts TCP6-LISTEN:$ts0p,$REUSEADDR,bind=$ts0a PIPE" CMD1="$TRACE $SOCAT $opts - SOCKET-CONNECT:$PF_INET6:6:$ts1,bind=x${ts1b}x00000000x00000000000000000000000000000000x00000000" printf "test $F_n $TEST... " $N $CMD0 2>"${te}0" & pid0="$!" waittcp6port $ts0p 1 echo "$da" |$CMD1 >>"$tf" 2>>"${te}1" rc1="$?" kill "$pid0" 2>/dev/null; wait; if [ "$rc1" -ne 0 ]; then $PRINTF "$FAILED: $TRACE $SOCAT:\n" echo "$CMD0 &" cat "${te}0" echo "$CMD1" cat "${te}1" numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" elif ! echo "$da" |diff - "$tf" >"$tdiff"; then $PRINTF "$FAILED\n" cat "$tdiff" echo "$CMD0 &" cat "${te}0" echo "$CMD1" cat "${te}1" numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" else $PRINTF "$OK\n" if [ -n "$debug" ]; then cat $te; fi numOK=$((numOK+1)) fi fi ;; # NUMCOND esac N=$((N+1)) # test the SOCKET-CONNECT address (against UNIX-LISTEN) NAME=SOCKET_CONNECT_UNIX case "$TESTS" in *%$N%*|*%functions%*|*%generic%*|*%unix%*|*%socket%*|*%listen%*|*%$NAME%*) TEST="$NAME: socket connect with UNIX domain" # start a UNIX-LISTEN process that echoes data, and send test data using # SOCKET-CONNECT, selecting UNIX socket. The sent data should be returned. if ! eval $NUMCOND; then :; else tf="$td/test$N.stdout" te="$td/test$N.stderr" tdiff="$td/test$N.diff" ts0="$td/test$N.server" ts1="$td/test$N.client" da="test$N $(date) $RANDOM" CMD0="$TRACE $SOCAT $opts UNIX-LISTEN:$ts0,$REUSEADDR PIPE" CMD1="$TRACE $SOCAT $opts - SOCKET-CONNECT:1:0:\\\"$ts0\\\0\\\",bind=\\\"$ts1\\\0\\\"" printf "test $F_n $TEST... " $N $CMD0 2>"${te}0" & pid0="$!" waitfile $ts0 1 echo "$da" |$CMD1 >>"$tf" 2>>"${te}1" rc1="$?" kill "$pid0" 2>/dev/null; wait; if [ "$rc1" -ne 0 ]; then $PRINTF "$FAILED: $TRACE $SOCAT:\n" echo "$CMD0 &" cat "${te}0" echo "$CMD1" cat "${te}1" numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" elif ! echo "$da" |diff - "$tf" >"$tdiff"; then $PRINTF "$FAILED\n" cat "$tdiff" echo "$CMD0 &" cat "${te}0" echo "$CMD1" cat "${te}1" numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" else $PRINTF "$OK\n" if [ -n "$debug" ]; then cat $te; fi numOK=$((numOK+1)) fi fi ;; # NUMCOND esac N=$((N+1)) # test the SOCKET-LISTEN address (with TCP4-CONNECT) NAME=SOCKET_LISTEN case "$TESTS" in *%$N%*|*%functions%*|*%generic%*|*%socket%*|*%listen%*|*%$NAME%*) TEST="$NAME: socket recvfrom with TCP/IPv4" # start a SOCKET-LISTEN process that uses TCP/IPv4 and echoes data, and # send test data using TCP4-CONNECT. The sent data should be returned. if ! eval $NUMCOND; then :; else tf="$td/test$N.stdout" te="$td/test$N.stderr" tdiff="$td/test$N.diff" newport tcp4; ts1p=$PORT ts1a="127.0.0.1" ts0p=$(printf "%04x" $ts1p); ts0a="7f000001" # "127.0.0.1" ts0="x${ts0p}${ts0a}x0000000000000000" newport tcp4; ts1b=$PORT ts1="$ts1a:$ts1p" da="test$N $(date) $RANDOM" CMD0="$TRACE $SOCAT $opts SOCKET-LISTEN:2:6:$ts0,$REUSEADDR PIPE" CMD1="$TRACE $SOCAT $opts - TCP4-CONNECT:$ts1,bind=:$ts1b" printf "test $F_n $TEST... " $N $CMD0 2>"${te}0" & pid0="$!" #sleep 1 waittcp4port $ts1p 1 echo "$da" |$CMD1 >>"$tf" 2>>"${te}1" rc1="$?" kill "$pid0" 2>/dev/null; wait; if [ "$rc1" -ne 0 ]; then $PRINTF "$FAILED: $TRACE $SOCAT:\n" echo "$CMD0 &" cat "${te}0" echo "$CMD1" cat "${te}1" numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" elif ! echo "$da" |diff - "$tf" >"$tdiff"; then $PRINTF "$FAILED\n" cat "$tdiff" echo "$CMD0 &" cat "${te}0" echo "$CMD1" cat "${te}1" numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" else $PRINTF "$OK\n" if [ -n "$debug" ]; then cat $te; fi numOK=$((numOK+1)) fi fi ;; # NUMCOND esac N=$((N+1)) # test the SOCKET-SENDTO address (against UDP4-RECVFROM) NAME=SOCKET_SENDTO case "$TESTS" in *%$N%*|*%functions%*|*%generic%*|*%socket%*|*%ip4%*|*%udp%*|*%dgram%*|*%$NAME%*) TEST="$NAME: socket sendto with UDP/IPv4" # start a UDP4-RECVFROM process that echoes data, and send test data using # SOCKET-SENDTO, selecting UDP/IPv4. The sent data should be returned. if ! eval $NUMCOND; then :; else tf="$td/test$N.stdout" te="$td/test$N.stderr" tdiff="$td/test$N.diff" newport udp4; ts0p=$PORT ts0a="127.0.0.1" ts1p=$(printf "%04x" $ts0p); ts1a="7f000001" # "127.0.0.1" ts1="x${ts1p}${ts1a}x0000000000000000" newport udp4; ts1b=$(printf "%04x" $PORT) da="test$N $(date) $RANDOM" CMD0="$TRACE $SOCAT $opts UDP4-RECVFROM:$ts0p,reuseaddr,bind=$ts0a PIPE" CMD1="$TRACE $SOCAT $opts - SOCKET-SENDTO:2:$SOCK_DGRAM:17:$ts1,bind=x${ts1b}x00000000x0000000000000000" printf "test $F_n $TEST... " $N $CMD0 2>"${te}0" & pid0="$!" waitudp4port $ts0p 1 echo "$da" |$CMD1 >>"$tf" 2>>"${te}1" rc1="$?" kill "$pid0" 2>/dev/null; wait; if [ "$rc1" -ne 0 ]; then $PRINTF "$FAILED: $TRACE $SOCAT:\n" echo "$CMD0 &" cat "${te}0" echo "$CMD1" cat "${te}1" numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" elif ! echo "$da" |diff - "$tf" >"$tdiff"; then $PRINTF "$FAILED\n" cat "$tdiff" echo "$CMD0 &" cat "${te}0" echo "$CMD1" cat "${te}1" numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" else $PRINTF "$OK\n" if [ -n "$debug" ]; then cat $te; fi numOK=$((numOK+1)) fi fi ;; # NUMCOND esac N=$((N+1)) # test the SOCKET-RECVFROM address (with UDP4-SENDTO) NAME=SOCKET_RECVFROM case "$TESTS" in *%$N%*|*%functions%*|*%generic%*|*%socket%*|*%ip4%*|*%udp%*|*%dgram%*|*%$NAME%*) TEST="$NAME: socket recvfrom with UDP/IPv4" # start a SOCKET-RECVFROM process that uses UDP/IPv4 and echoes data, and # send test data using UDP4-SENDTO. The sent data should be returned. if ! eval $NUMCOND; then :; else tf="$td/test$N.stdout" te="$td/test$N.stderr" tdiff="$td/test$N.diff" newport udp4; ts1p=$PORT ts1a="127.0.0.1" ts0p=$(printf "%04x" $ts1p); ts0a="7f000001" # "127.0.0.1" ts0="x${ts0p}${ts0a}x0000000000000000" newport udp4; ts1b=$PORT ts1="$ts1a:$ts1p" da="test$N $(date) $RANDOM" CMD0="$TRACE $SOCAT $opts SOCKET-RECVFROM:2:$SOCK_DGRAM:17:$ts0,reuseaddr PIPE" CMD1="$TRACE $SOCAT $opts - UDP4-SENDTO:$ts1,bind=:$ts1b" printf "test $F_n $TEST... " $N $CMD0 2>"${te}0" & pid0="$!" sleep 1 # waitudp4port $ts1p 1 echo "$da" |$CMD1 >>"$tf" 2>>"${te}1" rc1="$?" kill "$pid0" 2>/dev/null; wait; if [ "$rc1" -ne 0 ]; then $PRINTF "$FAILED: $TRACE $SOCAT:\n" echo "$CMD0 &" cat "${te}0" echo "$CMD1" cat "${te}1" numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" elif ! echo "$da" |diff - "$tf" >"$tdiff"; then $PRINTF "$FAILED\n" cat "$tdiff" echo "$CMD0 &" cat "${te}0" echo "$CMD1" cat "${te}1" numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" else $PRINTF "$OK\n" if [ -n "$debug" ]; then cat $te; fi numOK=$((numOK+1)) fi fi ;; # NUMCOND esac N=$((N+1)) # test the SOCKET-RECV address (with UDP4-SENDTO) NAME=SOCKET_RECV case "$TESTS" in *%$N%*|*%functions%*|*%generic%*|*%socket%*|*%ip4%*|*%udp%*|*%dgram%*|*%$NAME%*) TEST="$NAME: socket recv with UDP/IPv4" # start a SOCKET-RECV process that uses UDP/IPv4 and writes received data to file, and # send test data using UDP4-SENDTO. if ! eval $NUMCOND; then :; else tf="$td/test$N.stdout" te="$td/test$N.stderr" tdiff="$td/test$N.diff" newport udp4; ts1p=$PORT ts1a="127.0.0.1" ts0p=$(printf "%04x" $ts1p); ts0a="7f000001" # "127.0.0.1" ts0="x${ts0p}${ts0a}x0000000000000000" newport udp4; ts1b=$PORT ts1="$ts1a:$ts1p" da="test$N $(date) $RANDOM" CMD0="$TRACE $SOCAT $opts -u SOCKET-RECV:2:$SOCK_DGRAM:17:$ts0,reuseaddr -" CMD1="$TRACE $SOCAT $opts -u - UDP4-SENDTO:$ts1,bind=:$ts1b" printf "test $F_n $TEST... " $N $CMD0 2>"${te}0" >"$tf" & pid0="$!" sleep 1 # waitudp4port $ts1p 1 echo "$da" |$CMD1 2>>"${te}1" rc1="$?" sleep 1 kill "$pid0" 2>/dev/null; wait; if [ "$rc1" -ne 0 ]; then $PRINTF "$FAILED: $TRACE $SOCAT:\n" echo "$CMD0 &" cat "${te}0" echo "$CMD1" cat "${te}1" numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" elif ! echo "$da" |diff - "$tf" >"$tdiff"; then $PRINTF "$FAILED\n" cat "$tdiff" echo "$CMD0 &" cat "${te}0" echo "$CMD1" cat "${te}1" numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" else $PRINTF "$OK\n" if [ -n "$debug" ]; then cat $te; fi numOK=$((numOK+1)) fi fi ;; # NUMCOND esac N=$((N+1)) # test SOCKET-DATAGRAM (with UDP4-DATAGRAM) NAME=SOCKET_DATAGRAM case "$TESTS" in *%$N%*|*%functions%*|*%generic%*|*%socket%*|*%ip4%*|*%udp%*|*%dgram%*|*%$NAME%*) TEST="$NAME: socket datagram via UDP/IPv4" # start a UDP4-DATAGRAM process that echoes data, and send test data using # SOCKET-DATAGRAM, selecting UDP/IPv4. The sent data should be returned. if ! eval $NUMCOND; then :; else tf="$td/test$N.stdout" te="$td/test$N.stderr" tdiff="$td/test$N.diff" newport udp4; ts0p=$PORT newport udp4; ts1p=$PORT ts0a="127.0.0.1" ts1b=$(printf "%04x" $ts0p); ts1a="7f000001" # "127.0.0.1" ts0b=$(printf "%04x" $ts0p) ts1b=$(printf "%04x" $ts1p) ts1="x${ts0b}${ts1a}x0000000000000000" da="test$N $(date) $RANDOM" CMD0="$TRACE $SOCAT $opts UDP4-DATAGRAM:$ts0a:$ts1p,bind=:$ts0p,reuseaddr PIPE" CMD1="$TRACE $SOCAT $opts - SOCKET-DATAGRAM:2:$SOCK_DGRAM:17:$ts1,bind=x${ts1b}x00000000x0000000000000000" printf "test $F_n $TEST... " $N $CMD0 2>"${te}0" & pid0="$!" waitudp4port $ts0p 1 echo "$da" |$CMD1 2>>"${te}1" >"$tf" rc1="$?" kill "$pid0" 2>/dev/null; wait; if [ "$rc1" -ne 0 ]; then $PRINTF "$FAILED: $TRACE $SOCAT:\n" echo "$CMD0 &" cat "${te}0" echo "$CMD1" cat "${te}1" numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" elif ! echo "$da" |diff - "$tf" >"$tdiff"; then $PRINTF "$FAILED\n" cat "$tdiff" echo "$CMD0 &" cat "${te}0" echo "$CMD1" cat "${te}1" numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" else $PRINTF "$OK\n" if [ -n "$debug" ]; then cat $te; fi numOK=$((numOK+1)) fi fi ;; # NUMCOND esac N=$((N+1)) NAME=SOCKETRANGEMASK case "$TESTS" in *%$N%*|*%functions%*|*%security%*|*%generic%*|*%tcp%*|*%tcp4%*|*%ip4%*|*%socket%*|*%range%*|*%listen%*|*%fork%*|*%$NAME%*) TEST="$NAME: security of generic socket-listen with RANGE option" if ! eval $NUMCOND; then :; elif [ -z "$SECONDADDR" ]; then # we need access to more loopback addresses $PRINTF "test $F_n $TEST... ${YELLOW}need a second IPv4 address${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" else newport tcp4; ts1p=$(printf "%04x" $PORT); testserversec "$N" "$TEST" "$opts" "SOCKET-LISTEN:2:6:x${ts1p}x00000000x0000000000000000,$REUSEADDR,fork,retry=1" "" "range=x0000x7f000000:x0000xffffffff" "SOCKET-CONNECT:2:6:x${ts1p}x${SECONDADDRHEX}x0000000000000000" 4 tcp $PORT 0 fi ;; # NUMCOND, $SECONDADDR esac N=$((N+1)) # test the generic ioctl-void option NAME=IOCTL_VOID case "$TESTS" in *%$N%*|*%functions%*|*%pty%*|*%generic%*|*%$NAME%*) TEST="$NAME: test the ioctl-void option" # there are not many ioctls that apply to non global resources and do not # require root. TIOCEXCL seems to fit: # process 0 provides a pty; # process 1 opens it with the TIOCEXCL ioctl; # process 2 opens it too and fails with "device or resource busy" only when the # previous ioctl was successful if ! eval $NUMCOND; then :; elif [ -z "$TIOCEXCL" ]; then # we use the numeric value of TIOCEXL which is system dependent $PRINTF "test $F_n $TEST... ${YELLOW}no value of TIOCEXCL${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" else tp="$td/test$N.pty" tf="$td/test$N.stdout" te="$td/test$N.stderr" tdiff="$td/test$N.diff" da="test$N $(date) $RANDOM" CMD0="$TRACE $SOCAT $opts PTY,LINK=$tp pipe" CMD1="$TRACE $SOCAT $opts - file:$tp,ioctl-void=$TIOCEXCL,raw,echo=0" CMD2="$TRACE $SOCAT $opts - file:$tp,raw,echo=0" printf "test $F_n $TEST... " $N $CMD0 >/dev/null 2>"${te}0" & pid0=$! waitfile $tp 1 (echo "$da"; sleep 2) |$CMD1 >"$tf" 2>"${te}1" & # this should always work pid1=$! usleep 1000000 $CMD2 >/dev/null 2>"${te}2" /dev/null; wait if ! echo "$da" |diff - "$tf" >/dev/null; then $PRINTF "${YELLOW}phase 1 failed${NORMAL}\n" echo "$CMD0 &" echo "$CMD1" echo "$da" |diff - "$tf" numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif [ $rc2 -eq 0 ]; then $PRINTF "$FAILED: $TRACE $SOCAT:\n" echo "$CMD0 &" echo "$CMD1" echo "$CMD2" cat "${te}0" "${te}1" "${te}2" numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" else $PRINTF "$OK\n" if [ -n "$debug" ]; then cat "${te}0" "${te}1" "${te}2"; fi numOK=$((numOK+1)) fi fi # NUMCOND, TIOCEXCL ;; esac N=$((N+1)) # Test the generic setsockopt option NAME=SETSOCKOPT case "$TESTS" in *%$N%*|*%functions%*|*%ip4%*|*%tcp%*|*%generic%*|*%listen%*|*%fork%*|*%$NAME%*) TEST="$NAME: test the setsockopt option" # Set the TCP_MAXSEG (MSS) option with a reasonable value, this should succeed. # Then try again with TCP_MAXSEG=1, this fails at least on Linux. # Thus: # process 0 provides a tcp listening,forking socket # process 1 connects to this port using reasonably MSS, data transfer should # succeed. # Then, # process 2 connects to this port using a very small MSS, this should fail if ! eval $NUMCOND; then :; elif [ -z "$TCP_MAXSEG" ]; then # we use the numeric value of TCP_MAXSEG which might be system dependent $PRINTF "test $F_n $TEST... ${YELLOW}value of TCPMAXSEG not known${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" else tf="$td/test$N.stdout" te="$td/test$N.stderr" tdiff="$td/test$N.diff" da="test$N $(date) $RANDOM" newport tcp4 CMD0="$TRACE $SOCAT $opts TCP4-L:$PORT,so-reuseaddr,fork PIPE" CMD1="$TRACE $SOCAT $opts - TCP4:$LOCALHOST:$PORT,setsockopt=6:$TCP_MAXSEG:512" CMD2="$TRACE $SOCAT $opts - TCP4:$LOCALHOST:$PORT,setsockopt=6:$TCP_MAXSEG:1" printf "test $F_n $TEST... " $N $CMD0 >/dev/null 2>"${te}0" & pid0=$! waittcp4port $PORT 1 (echo "$da"; sleep 1) |$CMD1 >"${tf}1" 2>"${te}1" # this should always work rc1=$? usleep 1000000 (echo "$da"; sleep 1) |$CMD2 >"${tf}2" 2>"${te}2" # this should fail rc2=$? kill $pid0 $pid1 $pid2 2>/dev/null; wait if ! echo "$da" |diff - "${tf}1" >"$tdiff"; then $PRINTF "${YELLOW}phase 1 failed${NORMAL}\n" echo "$CMD0 &" cat ${te}0 echo "$CMD1" cat ${te}1 cat "$tdiff" numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif [ $rc1 -ne 0 ]; then $PRINTF "$FAILED: $TRACE $SOCAT:\n" echo "$CMD0 &" cat ${te}0 echo "$CMD1" cat ${te}1 numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" elif [ $rc2 -eq 0 ]; then $PRINTF "$FAILED: $TRACE $SOCAT:\n" echo "$CMD0 &" cat ${te}0 echo "$CMD2" cat ${te}2 numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" else $PRINTF "$OK\n" if [ -n "$debug" ]; then cat "${te}0" "${te}1" "${te}2"; fi numOK=$((numOK+1)) fi fi # NUMCOND, SO_REUSEADDR ;; esac N=$((N+1)) # Test the generic setsockopt-listen option # This test, with setsockopt-int, no longer worked due to fix for options on # listening sockets # Now it got a chance again using new option setsockopt-listen #NAME=SETSOCKOPT_INT NAME=SETSOCKOPT_LISTEN case "$TESTS" in *%$N%*|*%functions%*|*%ip4%*|*%tcp%*|*%generic%*|*%listen%*|*%$NAME%*) TEST="$NAME: test the setsockopt-listen option" # there are not many socket options that apply to non global resources, do not # require root, do not require a network connection, and can easily be # tested. SO_REUSEADDR seems to fit: # process 0 provides a tcp listening socket with reuseaddr; # process 1 connects to this port; thus the port is connected but no longer # listening # process 2 tries to listen on this port with SO_REUSEADDR, will fail if the # (generically specified) SO_REUSEADDR socket options did not work # process 3 connects to this port; only if it is successful the test is ok if ! eval $NUMCOND; then :; elif [ -z "$SO_REUSEADDR" ]; then # we use the numeric value of SO_REUSEADDR which might be system dependent $PRINTF "test $F_n $TEST... ${YELLOW}value of SO_REUSEADDR not known${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" else tf="$td/test$N.stdout" te="$td/test$N.stderr" tdiff="$td/test$N.diff" da="test$N $(date) $RANDOM" newport tcp4 CMD0="$TRACE $SOCAT $opts TCP4-L:$PORT,setsockopt-listen=$SOL_SOCKET:$SO_REUSEADDR:1 PIPE" CMD1="$TRACE $SOCAT $opts - TCP4:$LOCALHOST:$PORT" CMD2="$CMD0" CMD3="$CMD1" printf "test $F_n $TEST... " $N $CMD0 >/dev/null 2>"${te}0" & pid0=$! waittcp4port $PORT 1 echo "$da" |$CMD1 >"${tf}1" 2>"${te}1" # this should always work rc1=$? kill $pid0 2>/dev/null; wait $CMD2 >/dev/null 2>"${te}2" & pid2=$! waittcp4port $PORT 1 echo "$da" |$CMD3 >"${tf}3" 2>"${te}3" rc3=$? kill $pid2 2>/dev/null; wait if ! echo "$da" |diff - "${tf}1" >"${tdiff}1"; then $PRINTF "${YELLOW}phase 1 failed${NORMAL}\n" echo "$CMD0 &" cat ${te}0 echo "$CMD1" cat ${te}1 cat "${tdiff}1" numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif [ $rc3 -ne 0 ]; then $PRINTF "$FAILED: $TRACE $SOCAT:\n" echo "$CMD0 &" cat ${te}0 echo "$CMD1" cat ${te}1 echo "$CMD2 &" cat ${te}2 echo "$CMD3" cat ${te}3 numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" elif ! echo "$da" |diff - "${tf}3" >"${tdiff}3"; then $PRINTF "$FAILED: $TRACE $SOCAT:\n" echo "$CMD0 &" cat ${te}0 echo "$CMD1" cat ${te}1 echo "$CMD2 &" cat ${te}2 echo "$CMD3" cat ${te}3 cat "${tdiff}3" numCANT=$((numCANT+1)) listCANT="$listCANT $N" else $PRINTF "$OK\n" if [ -n "$debug" ]; then cat "${te}0" "${te}1" "${te}2" "${te}3"; fi numOK=$((numOK+1)) fi fi # NUMCOND, SO_REUSEADDR ;; esac N=$((N+1)) NAME=SCTP4STREAM case "$TESTS" in *%$N%*|*%functions%*|*%ip4%*|*%ipapp%*|*%sctp%*|*%listen%*|*%$NAME%*) TEST="$NAME: echo via connection to SCTP V4 socket" if ! eval $NUMCOND; then :; elif ! testfeats sctp ip4 >/dev/null || ! runsip4 >/dev/null || ! runssctp4 >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}SCTP4 not available${NORMAL}\n" $N listCANT="$listCANT $N" numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif [ "$UNAME" = Linux ] && ! grep ^sctp /proc/modules >/dev/null; then # RHEL5 based systems became unusable when an sctp socket was created but # module sctp not loaded $PRINTF "test $F_n $TEST...${YELLOW}load sctp module!${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" else tf="$td/test$N.stdout" te="$td/test$N.stderr" tdiff="$td/test$N.diff" newport sctp4; tsl=$PORT ts="127.0.0.1:$tsl" da=$(date) CMD1="$TRACE $SOCAT $opts SCTP4-LISTEN:$tsl,$REUSEADDR PIPE" CMD2="$TRACE $SOCAT $opts STDIN!!STDOUT SCTP4:$ts" printf "test $F_n $TEST... " $N $CMD1 >"$tf" 2>"${te}1" & pid1=$! waitsctp4port $tsl 1 # SCTP does not seem to support half close, so we give it 1s to finish (echo "$da"; sleep 1) |$CMD2 >>"$tf" 2>>"${te}2" if [ $? -ne 0 ]; then $PRINTF "$FAILED: $TRACE $SOCAT:\n" echo "$CMD1 &" cat "${te}1" echo "$CMD2" cat "${te}2" numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" elif ! echo "$da" |diff - "$tf" >"$tdiff"; then $PRINTF "$FAILED\n" cat "$tdiff" numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" else $PRINTF "$OK\n" if [ -n "$debug" ]; then cat "${te}1" "${te}2"; fi numOK=$((numOK+1)) fi kill $pid1 2>/dev/null wait fi # NUMCOND, feats ;; esac N=$((N+1)) NAME=SCTP6STREAM case "$TESTS" in *%$N%*|*%functions%*|*%ip6%*|*%ipapp%*|*%sctp%*|*%listen%*|*%$NAME%*) TEST="$NAME: echo via connection to SCTP V6 socket" if ! eval $NUMCOND; then :; elif ! testfeats sctp ip6 >/dev/null || ! runsip6 >/dev/null || ! runssctp6 >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}SCTP6 not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif [ "$UNAME" = Linux ] && ! grep ^sctp /proc/modules >/dev/null; then $PRINTF "test $F_n $TEST...${YELLOW}load sctp module!${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" else tf="$td/test$N.stdout" te="$td/test$N.stderr" tdiff="$td/test$N.diff" newport sctp6; tsl=$PORT ts="[::1]:$tsl" da=$(date) CMD1="$TRACE $SOCAT $opts SCTP6-LISTEN:$tsl,$REUSEADDR PIPE" CMD2="$TRACE $SOCAT $opts STDIN!!STDOUT SCTP6:$ts" printf "test $F_n $TEST... " $N $CMD1 >"$tf" 2>"${te}1" & pid=$! # background process id waitsctp6port $tsl 1 # SCTP does not seem to support half close, so we let it 1s to finish (echo "$da"; sleep 1) |$CMD2 >>"$tf" 2>>"${te}2" if [ $? -ne 0 ]; then $PRINTF "$FAILED: $TRACE $SOCAT:\n" echo "$CMD1 &" cat "${te}1" echo "$CMD2" cat "${te}2" numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" elif ! echo "$da" |diff - "$tf" >"$tdiff"; then $PRINTF "$FAILED: diff:\n" cat "$tdiff" numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" else $PRINTF "$OK\n" if [ -n "$debug" ]; then cat "${te}1" "${te}2"; fi numOK=$((numOK+1)) fi kill $pid 2>/dev/null fi # NUMCOND, feats ;; esac N=$((N+1)) if type openssl >/dev/null 2>&1; then OPENSSL_METHOD=$(openssl s_client -help 2>&1 |egrep -e '-tls1_[012]' |sed -e 's/.*\(-tls1_[012]\).*/\1/' |sort |tail -n 1) #OPENSSL_METHOD=$(openssl s_client -help 2>&1 |egrep -o -e '-tls1(_[012])?' |sort |tail -n 1) [ -z "$OPENSSL_METHOD" ] && OPENSSL_METHOD="-tls1" # just so fi # socat up to 1.7.1.1 (and 2.0.0-b3) terminated with error when an openssl peer # performed a renegotiation. Test if this is fixed. # Note: the renegotiation feature in OpenSSL exists only up to TLSv1.2 NAME=OPENSSLRENEG1 case "$TESTS" in *%$N%*|*%functions%*|*%bugs%*|*%openssl%*|*%socket%*|*%listen%*|*%$NAME%*) TEST="$NAME: OpenSSL connections survive renogotiation" # connect with s_client to socat ssl-l; force a renog, then transfer data. When # data is passed the test succeeded if ! eval $NUMCOND; then :; elif ! testfeats openssl >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}OPENSSL not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif ! type openssl >/dev/null 2>&1; then $PRINTF "test $F_n $TEST... ${YELLOW}openssl executable not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif ! testfeats tcp ip4 >/dev/null || ! runsip4 >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}TCP/IPv4 not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" else gentestcert testsrv tf="$td/test$N.stdout" te="$td/test$N.stderr" tdiff="$td/test$N.diff" da="test$N $(date) $RANDOM" init_openssl_s_client newport tcp4 CMD0="$TRACE $SOCAT $opts OPENSSL-LISTEN:$PORT,$REUSEADDR,cert=testsrv.crt,key=testsrv.key,verify=0 PIPE" #CMD1="openssl s_client -port $PORT -verify 0" # not with openssl 1.1.0g CMD1="openssl s_client $OPENSSL_S_CLIENT_4 $OPENSSL_METHOD -port $PORT" printf "test $F_n $TEST... " $N $CMD0 >/dev/null 2>"${te}0" & pid0=$! waittcp4port $PORT 1 (echo "R"; sleep 1; echo "$da"; sleep 1) |$CMD1 2>"${te}1" |fgrep "$da" >"${tf}1" rc1=$? kill $pid0 2>/dev/null; wait if echo "$da" |diff - ${tf}1 >"$tdiff"; then $PRINTF "$OK\n" if [ "$VERBOSE" ]; then echo "$CMD0 &"; fi if [ "$DEBUG" ]; then cat "${te}0" >&2; fi if [ "$VERBOSE" ]; then echo "$CMD1"; fi if [ "$DEBUG" ]; then cat "${te}1" >&2; fi numOK=$((numOK+1)) else $PRINTF "$FAILED\n" echo "$CMD0 &" cat "${te}0" echo "$CMD1" cat "${te}1" cat "$tdiff" numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" fi fi # NUMCOND ;; esac N=$((N+1)) # socat up to 1.7.1.1 (and 2.0.0-b3) terminated with error when an openssl peer # performed a renegotiation. The first temporary fix to this problem might # leave socat in a blocking ssl-read state. Test if this has been fixed. # Note: the renegotiation feature in OpenSSL exists only up to TLSv1.2 NAME=OPENSSLRENEG2 case "$TESTS" in *%$N%*|*%functions%*|*%bugs%*|*%openssl%*|*%socket%*|*%listen%*|*%$NAME%*) TEST="$NAME: OpenSSL connections do not block after renogotiation" # connect with s_client to socat ssl-l; force a renog, then transfer data from # socat to the peer. When data is passed this means that the former ssl read no # longer blocks and the test succeeds if ! eval $NUMCOND; then :; elif ! testfeats openssl >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}OPENSSL not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif ! type openssl >/dev/null 2>&1; then $PRINTF "test $F_n $TEST... ${YELLOW}openssl executable not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif ! testfeats tcp ip4 >/dev/null || ! runsip4 >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}TCP/IPv4 not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" else gentestcert testsrv tf="$td/test$N.stdout" te="$td/test$N.stderr" tdiff="$td/test$N.diff" da="test$N $(date) $RANDOM" init_openssl_s_client newport tcp4 CMD0="$TRACE $SOCAT $opts OPENSSL-LISTEN:$PORT,$REUSEADDR,cert=testsrv.crt,key=testsrv.key,verify=0 SYSTEM:\"sleep 1; echo \\\\\\\"\\\"$da\\\"\\\\\\\"; sleep 1\"!!STDIO" #CMD1="openssl s_client -port $PORT -verify 0" # not with openssl 1.1.0g CMD1="openssl s_client $OPENSSL_S_CLIENT_4 $OPENSSL_METHOD -port $PORT" printf "test $F_n $TEST... " $N eval "$CMD0 >/dev/null 2>\"${te}0\" &" pid0=$! waittcp4port $PORT 1 (echo "R"; sleep 2) |$CMD1 2>"${te}1" |fgrep "$da" >"${tf}1" rc1=$? kill $pid0 2>/dev/null; wait if echo "$da" |diff - ${tf}1 >"$tdiff"; then $PRINTF "$OK\n" if [ "$VERBOSE" ]; then echo "$CMD0 &"; fi if [ "$DEBUG" ]; then cat "${te}0" >&2; fi if [ "$VERBOSE" ]; then echo "$CMD1"; fi if [ "$DEBUG" ]; then cat "${te}1" >&2; fi numOK=$((numOK+1)) else $PRINTF "$FAILED\n" echo "$CMD0 &" cat "${te}0" echo "$CMD1" cat "${te}1" cat "$tdiff" numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" fi fi # NUMCOND ;; esac N=$((N+1)) # socat up to 1.7.1.2 had a stack overflow vulnerability that occurred when # command line arguments (whole addresses, host names, file names) were longer # than 512 bytes. NAME=HOSTNAMEOVFL case "$TESTS" in *%$N%*|*%functions%*|*%bugs%*|*%security%*|*%socket%*|*%$NAME%*) TEST="$NAME: stack overflow on overly long host name" # provide a long host name to TCP-CONNECT and check socats exit code if ! eval $NUMCOND; then :; else tf="$td/test$N.stdout" te="$td/test$N.stderr" tdiff="$td/test$N.diff" da="test$N $(date) $RANDOM" # prepare long data - perl might not be installed rm -f "$td/test$N.dat" i=0; while [ $i -lt 64 ]; do echo -n "AAAAAAAAAAAAAAAA" >>"$td/test$N.dat"; i=$((i+1)); done newport tcp4 CMD0="$TRACE $SOCAT $opts TCP-CONNECT:$(cat "$td/test$N.dat"):$PORT STDIO" printf "test $F_n $TEST... " $N $CMD0 &0 2>"${te}0" rc0=$? if [ $rc0 -lt 128 ] || [ $rc0 -eq 255 ]; then $PRINTF "$OK\n" numOK=$((numOK+1)) else $PRINTF "$FAILED\n" echo "$CMD0" cat "${te}0" numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" fi fi # NUMCOND ;; esac N=$((N+1)) # socat up to 1.7.1.2 had a stack overflow vulnerability that occurred when # command line arguments (whole addresses, host names, file names) were longer # than 512 bytes. NAME=FILENAMEOVFL case "$TESTS" in *%$N%*|*%functions%*|*%bugs%*|*%security%*|*%openssl%*|*%$NAME%*) TEST="$NAME: stack overflow on overly long file name" # provide a 600 bytes long key file option to OPENSSL-CONNECT and check socats exit code if ! eval $NUMCOND; then :; else tf="$td/test$N.stdout" te="$td/test$N.stderr" tdiff="$td/test$N.diff" da="test$N $(date) $RANDOM" i=0; while [ $i -lt 64 ]; do echo -n "AAAAAAAAAAAAAAAA" >>"$td/test$N.dat"; i=$((i+1)); done newport tcp4 CMD0="$TRACE $SOCAT $opts OPENSSL:localhost:$PORT,key=$(cat "$td/test$N.dat") STDIO" printf "test $F_n $TEST... " $N $CMD0 &0 2>"${te}0" rc0=$? if [ $rc0 -lt 128 ] || [ $rc0 -eq 255 ]; then $PRINTF "$OK\n" numOK=$((numOK+1)) else $PRINTF "$FAILED\n" echo "$CMD0" cat "${te}0" numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" fi fi # NUMCOND ;; esac N=$((N+1)) # socat up to 1.7.3.0 had a stack overflow vulnerability that occurred when # command line arguments (whole addresses, host names, file names) were longer # than 512 bytes and specially crafted. NAME=NESTEDOVFL case "$TESTS" in *%$N%*|*%functions%*|*%bugs%*|*%security%*|*%exec%*|*%$NAME%*) TEST="$NAME: stack overflow on overly long nested arg" # provide a long host name to TCP-CONNECT and check socats exit code if ! eval $NUMCOND; then :; else tf="$td/test$N.stdout" te="$td/test$N.stderr" tdiff="$td/test$N.diff" da="test$N $(date) $RANDOM" # prepare long data - perl might not be installed rm -f "$td/test$N.dat" i=0; while [ $i -lt 64 ]; do echo -n "AAAAAAAAAAAAAAAA" >>"$td/test$N.dat"; i=$((i+1)); done CMD0="$TRACE $SOCAT $opts EXEC:[$(cat "$td/test$N.dat")] STDIO" printf "test $F_n $TEST... " $N $CMD0 &0 2>"${te}0" rc0=$? if [ $rc0 -lt 128 ] || [ $rc0 -eq 255 ]; then $PRINTF "$OK\n" numOK=$((numOK+1)) else $PRINTF "$FAILED\n" echo "$CMD0" cat "${te}0" numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" fi fi # NUMCOND ;; esac N=$((N+1)) # test for a bug in gopen that lead to crash or warning when opening a unix # domain socket with GOPEN NAME=GOPEN_UNIX_CRASH case "$TESTS" in *%$N%*|*%functions%*|*%bugs%*|*%gopen%*|*%unix%*|*%socket%*|*%listen%*|*%$NAME%*) TEST="$NAME: check crash when connecting to a unix domain socket using address GOPEN" # a unix domain server is started in background. the check process connects to # its socket. when this process crashes or issues a warning the bug is present. # please note that a clean behaviour does not proof anything; behaviour of bug # depends on the value of an uninitialized var #set -vx if ! eval $NUMCOND; then :; else tf="$td/test$N.stdout" te="$td/test$N.stderr" ts="$td/test$N.sock" tdiff="$td/test$N.diff" da="test$N $(date) $RANDOM" CMD0="$TRACE $SOCAT $opts UNIX-LISTEN:$ts PIPE" CMD1="$TRACE $SOCAT $opts -d - GOPEN:$ts" printf "test $F_n $TEST... " $N $CMD0 >/dev/null 2>"${te}0" "${tf}1" 2>"${te}1" rc1=$? kill $pid0 2>/dev/null; wait if [ $rc1 -ne 0 ]; then $PRINTF "$FAILED\n" echo "$CMD0 &" echo "$CMD1" cat "${te}0" cat "${te}1" numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" elif grep -q ' W ' "${te}1"; then $PRINTF "$FAILED\n" echo "$CMD0 &" echo "$CMD1" cat "${te}0" cat "${te}1" numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" elif ! echo "$da" |diff - ${tf}1 >"$tdiff"; then $PRINTF "$FAILED\n" echo "$CMD0 &" echo "$CMD1" cat "${te}0" cat "${te}1" cat "$tdiff" numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" else $PRINTF "$OK\n" numOK=$((numOK+1)) fi fi # NUMCOND ;; esac N=$((N+1)) # test if socat keeps an existing file where it wanted to create a UNIX socket NAME=UNIXLISTEN_KEEPFILE case "$TESTS" in *%$N%*|*%functions%*|*%bugs%*|*%unix%*|*%socket%*|*%listen%*|*%$NAME%*) TEST="$NAME: socat keeps an existing file where it wanted to create a UNIX socket" # we create a file and start socat with UNIX-LISTEN on this file. expected # behaviour: socat exits immediately with error, but keeps the file # up to 1.7.1.3, it removed the file if ! eval $NUMCOND; then :; else tf="$td/test$N.file" te="$td/test$N.stderr" CMD0="$TRACE $SOCAT $opts -u UNIX-LISTEN:$tf /dev/null" printf "test $F_n $TEST... " $N rm -f "$tf"; touch "$tf" $CMD0 >/dev/null 2>"${te}0" rc0=$? if [ $rc0 -ne 0 -a -f "$tf" ]; then $PRINTF "$OK\n" numOK=$((numOK+1)) else $PRINTF "$FAILED\n" echo "$CMD0" cat "${te}0" numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" fi fi # NUMCOND ;; esac N=$((N+1)) # PTY address allowed to specify address parameters but ignored them NAME=PTY_VOIDARG case "$TESTS" in *%$N%*|*%functions%*|*%bugs%*|*%pty%*|*%$NAME%*) TEST="$NAME: check if address params of PTY produce error" # invoke socat with address PTY and some param; expect an error if ! eval $NUMCOND; then :; else tf="$td/test$N.stdout" te="$td/test$N.stderr" tdiff="$td/test$N.diff" da="test$N $(date) $RANDOM" CMD0="$TRACE $SOCAT $opts /dev/null PTY:/tmp/xyz" printf "test $F_n $TEST... " $N $CMD0 >/dev/null 2>"${te}0" rc0=$? if [ $rc0 -ne 0 ]; then $PRINTF "$OK\n" numOK=$((numOK+1)) else $PRINTF "$FAILED\n" echo "$CMD0" cat "${te}0" numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" fi fi # NUMCOND ;; esac N=$((N+1)) # incomplete writes were reported but led to data loss NAME=INCOMPLETE_WRITE case "$TESTS" in *%$N%*|*%functions%*|*%bugs%*|*%$NAME%*) TEST="$NAME: check if incomplete writes are handled properly" # write to a nonblocking fd a block that is too large for atomic write # and check if all data arrives if ! eval $NUMCOND; then :; else tf="$td/test$N.stdout" te="$td/test$N.stderr" tp="$td/test$N.pipe" tw="$td/test$N.wc-c" # this is the size we write() in one call; data is never stored on disk, so # make it large enough to exceed any atomic write size; but higher number might # take much time bytes=100000 # for Linux 2.6.? this must be >65536 CMD0="$TRACE $SOCAT $opts -u PIPE:$tp STDOUT" CMD1="$TRACE $SOCAT $opts -u -b $bytes OPEN:/dev/zero,readbytes=$bytes FILE:$tp,o-nonblock" printf "test $F_n $TEST... " $N $CMD0 2>"${te}0" |wc -c >"$tw" & pid=$! waitfile "$tp" $CMD1 2>"${te}1" >"${tf}1" rc1=$? wait if [ $rc1 -ne 0 ]; then $PRINTF "$NO_RESULT\n" numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif [ ! -e "$tw" ]; then $PRINTF "$NO_RESULT\n" numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif [ "$bytes" -eq $(cat "$tw") ]; then $PRINTF "$OK\n" numOK=$((numOK+1)) else $PRINTF "$FAILED\n" echo "transferred only $(cat $tw) of $bytes bytes" >&2 numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" fi fi # NUMCOND ;; esac N=$((N+1)) NAME=OPENSSL_ANULL case "$TESTS" in *%$N%*|*%functions%*|*%openssl%*|*%tcp%*|*%tcp4%*|*%ip4%*|*%listen%*|*%$NAME%*) TEST="$NAME: OpenSSL server with cipher aNULL " if ! eval $NUMCOND; then :; elif ! testfeats openssl >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}OPENSSL not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif ! testfeats listen tcp ip4 >/dev/null || ! runsip4 >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}TCP/IPv4 not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" else tf="$td/test$N.stdout" te="$td/test$N.stderr" tdiff="$td/test$N.diff" da="test$N $(date) $RANDOM" newport tcp4 CMD2="$TRACE $SOCAT $opts OPENSSL-LISTEN:$PORT,$REUSEADDR,$SOCAT_EGD,ciphers=aNULL,verify=0 pipe" CMD="$TRACE $SOCAT $opts - openssl:$LOCALHOST:$PORT,ciphers=aNULL,verify=0,$SOCAT_EGD" printf "test $F_n $TEST... " $N eval "$CMD2 2>\"${te}1\" &" pid=$! # background process id waittcp4port $PORT echo "$da" |$CMD >$tf 2>"${te}2" if ! echo "$da" |diff - "$tf" >"$tdiff"; then $PRINTF "${YELLOW}FAILED${NORMAL}\n" #echo "$CMD2 &" #echo "$CMD" #cat "${te}1" #cat "${te}2" #cat "$tdiff" numOK=$((numOK+1)) else $PRINTF "$OK\n" if [ -n "$debug" ]; then cat "${te}1" "${te}2"; fi numOK=$((numOK+1)) fi kill $pid 2>/dev/null wait fi ;; # NUMCOND, feats esac N=$((N+1)) while read KEYW FEAT ADDR IPPORT; do if [ -z "$KEYW" ] || [[ "$KEYW" == \#* ]]; then continue; fi RUNS=$(tolower $KEYW) PROTO=$KEYW proto="$(echo "$PROTO" |tr A-Z a-z)" feat="$(tolower "$FEAT")" # test the max-children option on really connection oriented sockets NAME=${KEYW}MAXCHILDREN case "$TESTS" in *%$N%*|*%functions%*|*%fork%*|*%maxchildren%*|*%$feat%*|*%$proto%*|*%socket%*|*%listen%*|*%$NAME%*) TEST="$NAME: max-children option" # start a listen process with max-children=1; connect with a client, let it # sleep some time before sending data; connect with second client that sends # data immediately. If max-children is working correctly the first data should # arrive first because the second process has to wait. if ! eval $NUMCOND; then :; elif ! testfeats "$FEAT" >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}$FEAT not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif ! runs$RUNS >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}$(toupper $RUNS) not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" else case "X$IPPORT" in "XPORT") newport $proto tsl=$PORT # test socket listen address tsc="$ADDR:$PORT" # test socket connect address ;; *) tsl="$(eval echo "$ADDR")" # resolve $N tsc=$tsl esac #ts="$td/test$N.sock" tf="$td/test$N.stdout" te="$td/test$N.stderr" tdiff="$td/test$N.diff" da="test$N $(date) $RANDOM" CMD0="$TRACE $SOCAT $opts -U FILE:$tf,o-trunc,o-creat,o-append $PROTO-LISTEN:$tsl,$REUSEADDR,fork,max-children=1" CMD1="$TRACE $SOCAT $opts -u - $PROTO-CONNECT:$tsc,shut-null" printf "test $F_n $TEST... " $N $CMD0 >/dev/null 2>"${te}0" & pid0=$! wait${proto}port $tsl 1 (echo "$da 1"; sleep 2) |$CMD1 >"${tf}1" 2>"${te}1" & pid1=$! sleep 1 echo "$da 2" |$CMD1 >"${tf}2" 2>"${te}2" & pid2=$! sleep 2 kill $pid1 $pid2 $pid0 2>/dev/null; wait if echo -e "$da 1\n$da 2" |diff - $tf >$tdiff; then $PRINTF "$OK\n" numOK=$((numOK+1)) else $PRINTF "$FAILED\n" echo "$CMD0 &" echo "(echo \"$da 1\"; sleep 2) |$CMD1" echo "echo \"$da 2\" |$CMD1" cat "${te}0" cat "${te}1" cat "${te}2" cat "$tdiff" numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" fi fi # NUMCOND ;; esac N=$((N+1)) done <<<" TCP4 TCP 127.0.0.1 PORT TCP6 TCP [::1] PORT SCTP4 SCTP 127.0.0.1 PORT SCTP6 SCTP [::1] PORT UNIX unix $td/test\$N.server - " # debugging this hanging test was difficult - following lessons learned: # kill had no effect when child process existed # strace -f (on Fedora-23) sometimes writes/pads? blocks with \0, overwriting client traces # using the TRACE feature lets above kill command kill strace, not socat # care for timing, understand what you want :-) while read KEYW FEAT ADDR IPPORT SHUT; do if [ -z "$KEYW" ] || [[ "$KEYW" == \#* ]]; then continue; fi RUNS=$(tolower $KEYW) PROTO=$KEYW proto="$(echo "$PROTO" |tr A-Z a-z)" # test the max-children option on pseudo connected sockets NAME=${KEYW}MAXCHILDREN case "$TESTS" in *%$N%*|*%functions%*|*%fork%*|*%maxchildren%*|*%socket%*|*%listen%*|*%$NAME%*) TEST="$NAME: max-children option" # start a listen process with max-children=1; connect with a client, let it # send data and then sleep; connect with second client that wants to send # data immediately, but keep first client active until server terminates. #If max-children is working correctly only the first data should # arrive. if ! eval $NUMCOND; then :; elif ! testfeats "$FEAT" >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}$FEAT not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif ! runs$RUNS >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}$(toupper $RUNS) not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" else case "X$IPPORT" in "XPORT") newport $proto tsl=$PORT # test socket listen address tsc="$ADDR:$PORT" # test socket connect address ;; *) tsl="$(eval echo "$ADDR")" # resolve $N tsc=$tsl esac #ts="$td/test$N.sock" tf="$td/test$N.stdout" te="$td/test$N.stderr" tdiff="$td/test$N.diff" da="test$N $(date) $RANDOM" # on some Linux distributions it hangs, thus -T option here CMD0="$TRACE $SOCAT $opts -U -T 4 FILE:$tf,o-trunc,o-creat,o-append $PROTO-LISTEN:$tsl,$REUSEADDR,fork,max-children=1" CMD1="$TRACE $SOCAT $opts -u - $PROTO-CONNECT:$tsc,$SHUT" printf "test $F_n $TEST... " $N $CMD0 >/dev/null 2>"${te}0" & pid0=$! wait${proto}port $tsl 1 (echo "$da 1"; sleep 3) |$CMD1 >"${tf}1" 2>"${te}1" & pid1=$! sleep 1 echo "$da 2" |$CMD1 >"${tf}2" 2>"${te}2" & pid2=$! sleep 1 cpids="$(childpids $pid0)" kill $pid1 $pid2 $pid0 $cpids 2>/dev/null; wait if echo -e "$da 1" |diff - $tf >$tdiff; then $PRINTF "$OK\n" numOK=$((numOK+1)) else $PRINTF "$FAILED\n" echo "$CMD0 &" echo "(echo \"$da 1\"; sleep 2) |$CMD1" echo "echo \"$da 2\" |$CMD1" cat "${te}0" cat "${te}1" cat "${te}2" cat "$tdiff" numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" fi fi # NUMCOND ;; esac N=$((N+1)) done <<<" UDP4 UDP 127.0.0.1 PORT shut-null UDP6 UDP [::1] PORT shut-null " # debugging this hanging test was difficult - following lessons learned: # kill had no effect when child process existed # strace -f (on Fedora-23) sometimes writes/pads? blocks with \0, overwriting client traces # using the TRACE feature lets above kill command kill strace, not socat # care for timing, understand what you want :-) # socat up to 1.7.2.0 had a bug in xioscan_readline() that could be exploited # to overflow a heap based buffer (socat security advisory 3) # problem reported by Johan Thillemann NAME=READLINE_OVFL case "$TESTS" in *%$N%*|*%functions%*|*%bugs%*|*%security%*|*%readline%*|*%pty%*|*%$NAME%*) TEST="$NAME: test for buffer overflow in readline prompt handling" # address 1 is the readline where write data was handled erroneous # address 2 provides data to trigger the buffer overflow # when no SIGSEGV or so occurs the test succeeded (bug fixed) if ! eval $NUMCOND; then :; elif ! feat=$(testfeats readline pty); then $PRINTF "test $F_n $TEST... ${YELLOW}$(echo "$feat"| tr 'a-z' 'A-Z') not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" else tf="$td/test$N.stdout" te="$td/test$N.stderr" ti="$td/test$N.data" CMD0="$SOCAT $opts READLINE $ti" printf "test $F_n $TEST... " $N # prepare long data - perl might not be installed #perl -e 'print "\r","Z"x513' >"$ti" echo $E -n "\rA" >"$ti" i=0; while [ $i -lt 32 ]; do echo -n "AAAAAAAAAAAAAAAA" >>"$ti"; let i=i+1; done $TRACE $SOCAT - SYSTEM:"$CMD0; echo rc=\$? >&2",pty >/dev/null 2>"${te}0" rc=$? rc0="$(grep ^rc= "${te}0" |sed 's/.*=//')" if [ $rc -ne 0 ]; then $PRINTF "${YELLOW}framework failed${NORMAL}\n" elif [ $rc0 -eq 0 ]; then $PRINTF "$OK\n" numOK=$((numOK+1)) else $PRINTF "$FAILED\n" echo "$CMD0" grep -v ^rc= "${te}0" numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" fi fi # NUMCOND ;; esac N=$((N+1)) # Does Socat have -d0 option? opt_d0= if $SOCAT -h |grep -e -d0 >/dev/null; then opt_d0="-d0" fi # socat up to 1.7.2.1 did only shutdown() but not close() an accept() socket # that was rejected due to range, tcpwrap, lowport, or sourceport option. # This file descriptor leak could be used for a denial of service attack. NAME=FDLEAK case "$TESTS" in *%$N%*|*%functions%*|*%bugs%*|*%security%*|*%socket%*|*%listen%*|*%$NAME%*) TEST="$NAME: file descriptor leak with range option" # have a TCP-LISTEN with range option; connect with wrong source address until # "open files" limit would exceed. When server continues operation the bug is # not present. if ! eval $NUMCOND; then :; else tf="$td/test$N.stdout" te="$td/test$N.stderr" tdiff="$td/test$N.diff" da="test$N $(date) $RANDOM" RLIMIT_NOFILE="$(ulimit -n)" if ! [[ "$RLIMIT_NOFILE" =~ ^[0-9][0-9]*$ ]]; then $PRINTF "${YELLOW}cannot determine ulimit -n${NORMAL}" else if [ $RLIMIT_NOFILE -gt 1024 ]; then ulimit -n 1024 # 65536 takes too long RLIMIT_NOFILE="$(ulimit -n)" fi newport tcp4 CMD0="$TRACE $SOCAT $opt_d0 $opts TCP4-LISTEN:$PORT,$REUSEADDR,range=$LOCALHOST:255.255.255.255 PIPE" #CMD0="$TRACE $SOCAT $opts TCP-LISTEN:$PORT,pf=ip4,$REUSEADDR,range=$LOCALHOST4:255.255.255.255 PIPE" CMD1="$TRACE $SOCAT $opts -t 0 /dev/null TCP4:$SECONDADDR:$PORT,bind=$SECONDADDR" CMD2="$TRACE $SOCAT $opts - TCP:$LOCALHOST4:$PORT,bind=$LOCALHOST4" printf "test $F_n $TEST... " $N $CMD0 >/dev/null 2>"${te}0" & pid0=$! waittcp4port $PORT 1 while [ $RLIMIT_NOFILE -gt 0 ]; do $CMD1 >/dev/null 2>>"${te}1" let RLIMIT_NOFILE=RLIMIT_NOFILE-1 done echo "$da" |$CMD2 >"${tf}2" 2>"${te}2" rc2=$? kill $pid0 2>/dev/null; wait echo -e "$da" |diff "${tf}2" - >$tdiff if [ $rc2 -ne 0 ]; then $PRINTF "$FAILED (rc2=$rc2)\n" echo "$CMD0 &" cat "${te}0" >&2 echo "$CMD1" cat "${te}1" >&2 echo "$CMD2" cat "${te}2" >&2 numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" elif [ -f "$tdiff" -a ! -s "$tdiff" ]; then $PRINTF "$OK\n" if [ "$VERBOSE" ]; then echo "$CMD0 &"; fi if [ "$DEBUG" ]; then cat "${te}0" >&2; fi if [ "$VERBOSE" ]; then echo "$CMD1"; fi if [ "$DEBUG" ]; then cat "${te}1" >&2; fi if [ "$VERBOSE" ]; then echo "$CMD2"; fi if [ "$DEBUG" ]; then cat "${te}2" >&2; fi numOK=$((numOK+1)) else $PRINTF "$FAILED\n" echo "$CMD0 &" cat "${te}0" >&2 echo "$CMD1" cat "${te}1" >&2 echo "$CMD2" cat "${te}2" >&2 numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" fi fi # ulimit -n fi # NUMCOND ;; esac N=$((N+1)) if false; then # this overflow is not reliably reproducable # socat up to 2.0.0-b6 did not check the length of the PROXY-CONNECT command line paramters when copying them into the HTTP request buffer. This could lead to a buffer overflow. NAME=PROXY_ADDR_OVFL case "$TESTS" in *%$N%*|*%functions%*|*%bugs%*|*%security%*|*%socket%*|*%listen%*|*%$NAME%*) TEST="$NAME: proxy address parameters overflow" # invoke socat PROXY-CONNECT with long proxy server and target server names. If it terminates with exit code >= 128 it is vulnerable # However, even if vulnerable it often does not crash. Therefore we try to use a boundary check program like ElectricFence; only with its help we can tell that clean run proofs absence of vulnerability if ! eval $NUMCOND; then :; else tf="$td/test$N.stdout" te="$td/test$N.stderr" tdiff="$td/test$N.diff" da="test$N $(date) $RANDOM" EF=; for p in ef; do if type ef >/dev/null 2>&1; then EF="ef "; break fi done newport tcp4 CMD0="$TRACE $SOCAT $opts TCP-LISTEN:$PORT,$REUSEADDR FILE:/dev/null" #CMD1="$EF $TRACE $SOCAT $opts FILE:/dev/null PROXY-CONNECT:$(perl -e "print 'A' x 256"):$(perl -e "print 'A' x 256"):80" CMD1="$EF $TRACE $SOCAT $opts FILE:/dev/null PROXY-CONNECT:localhost:$(perl -e "print 'A' x 384"):80,proxyport=$PORT" printf "test $F_n $TEST... " $N $CMD0 >/dev/null 2>"${te}0" & pid0=$! waittcp4port $PORT 1 $CMD1 >/dev/null 2>"${te}1" rc1=$? if [ $rc1 -lt 128 ]; then if [ "$EF" ]; then $PRINTF "$OK\n" numOK=$((numOK+1)) else $PRINTF "$UNKNOWN $RED(install ElectricFEnce!)$NORMAL\n" numCANT=$((num+1)) listCANT="$listCANT $N" fi else $PRINTF "$FAILED\n" echo "$CMD1" cat "${te}" numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" fi fi # NUMCOND ;; esac N=$((N+1)) fi # false # LISTEN addresses in socat up to 1.7.2.1 applied many file descriptor, socket, # and TCP options only to the listening socket instead of the connection socket. NAME=LISTEN_KEEPALIVE case "$TESTS" in *%$N%*|*%functions%*|*%bugs%*|*%listen%*|*%keepalive%*|*%socket%*|*%listen%*|*%fork%*|*%$NAME%*) TEST="$NAME: keepalive option is applied to connection socket" # Instance 0 has TCP-LISTEN with option so-keepalive and invokes filan after # accept(). filan writes its output to the socket. instance 1 connects to # instance 0. The value of the sockets so-keepalive option is checked, it must # be 1 if ! eval $NUMCOND; then :; else tf="$td/test$N.stdout" te="$td/test$N.stderr" #tdiff="$td/test$N.diff" #da="test$N $(date) $RANDOM" newport tcp4 CMD0="$TRACE $SOCAT $opts TCP4-LISTEN:$PORT,$REUSEADDR,so-keepalive EXEC:\"$FILAN -i 1\",nofork" CMD1="$TRACE $SOCAT $opts - TCP4:$LOCALHOST:$PORT" printf "test $F_n $TEST... " $N eval $CMD0 >/dev/null 2>"${te}0" & pid0=$! waittcp4port $PORT 1 $CMD1 >"${tf}1" 2>"${te}1" KEEPALIVE="$(cat "${tf}1" |tail -n +2 |sed -e "s/.*KEEPALIVE=//" -e "s/[[:space:]].*//")" rc1=$? kill $pid0 2>/dev/null; wait if [ -z "$KEEPALIVE" ]; then $PRINTF "$NO_RESULT\n" echo "$CMD0 &" cat "${te}0" >&2 echo "$CMD1" cat "${te}1" >&2 numCANT=$((numCANT+1)) listCANT="$listCANT $N" namesCANT="$namesCANT $NAME" elif [ "$KEEPALIVE" = "1" ]; then $PRINTF "$OK\n"; if [ "$VERBOSE" ]; then echo "$CMD0 &"; fi if [ "$DEBUG" ]; then cat "${te}0" >&2; fi if [ "$VERBOSE" ]; then echo "$CMD1"; fi if [ "$DEBUG" ]; then cat "${te}1" >&2; fi numOK=$((numOK+1)) else $PRINTF "$FAILED (KEEPALIVE=$KEEPALIVE)\n" echo "$CMD0 &" cat "${te}0" >&2 echo "$CMD1" cat "${te}1" >&2 numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" namesFAIL="$namesFAIL $NAME" fi fi # NUMCOND ;; esac N=$((N+1)) # OPENSSL-CONNECT with bind option failed on some systems (eg.FreeBSD, but not # Linux) with "Invalid argument". NAME=OPENSSL_CONNECT_BIND case "$TESTS" in *%$N%*|*%functions%*|*%bugs%*|*%socket%*|*%openssl%*|*%listen%*|*%$NAME%*) TEST="$NAME: test OPENSSL-CONNECT with bind option" # have a simple SSL server that just echoes data. # connect with socat using OPENSSL-CONNECT with bind, send data and check if the # reply is identical. if ! eval $NUMCOND; then :; elif ! testfeats openssl >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}OPENSSL not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" else gentestcert testsrv tf0="$td/test$N.0.stdout" te0="$td/test$N.0.stderr" tf1="$td/test$N.1.stdout" te1="$td/test$N.1.stderr" tdiff="$td/test$N.diff" da="test$N $(date) $RANDOM" newport tcp4 CMD0="$TRACE $SOCAT $opts OPENSSL-LISTEN:$PORT,pf=ip4,$REUSEADDR,cert=testsrv.pem,verify=0 PIPE" CMD1="$TRACE $SOCAT $opts - OPENSSL-CONNECT:$LOCALHOST:$PORT,pf=ip4,bind=$LOCALHOST,verify=0" printf "test $F_n $TEST... " $N $CMD0 >/dev/null 2>"$te0" & pid0=$! waittcp4port $PORT 1 echo "$da" |$CMD1 >"$tf1" 2>"$te1" rc1=$? kill $pid0 2>/dev/null; wait if [ "$rc1" -ne 0 ]; then $PRINTF "$FAILED\n" echo "$CMD0 &" echo "$CMD1" cat "$te0" cat "$te1" numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" elif ! echo "$da" |diff - $tf1 >"$tdiff"; then $PRINTF "$FAILED\n" echo "$CMD0 &" echo "$CMD1" cat "${te}0" cat "${te}1" cat "$tdiff" numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" else $PRINTF "$OK\n" numOK=$((numOK+1)) fi fi # NUMCOND ;; esac N=$((N+1)) # socat up to version 1.7.2.3 # had a bug that converted a bit mask of 0 internally to 0xffffffff NAME=TCP4RANGE_0BITS case "$TESTS" in *%$N%*|*%functions%*|*%fork%*|*%tcp%*|*%tcp4%*|*%ip4%*|*%range%*|*%listen%*|*%$NAME%*) TEST="$NAME: correct evaluation of range mask 0" if ! eval $NUMCOND; then :; elif [ -z "$SECONDADDR" ]; then # we need access to a second address $PRINTF "test $F_n $TEST... ${YELLOW}need a second IPv4 address${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" else tf="$td/test$N.stdout" te="$td/test$N.stderr" tdiff="$td/test$N.diff" da="test$N $(date) $RANDOM" newport tcp4 #testserversec "$N" "$TEST" "$opts" "tcp4-l:$PORT,reuseaddr,fork,retry=1" "" "range=$SECONDADDR/32" "tcp4:127.0.0.1:$PORT" 4 tcp $PORT 0 CMD0="$TRACE $SOCAT $opts -u TCP4-LISTEN:$PORT,$REUSEADDR,range=127.0.0.1/0 CREATE:$tf" CMD1="$TRACE $SOCAT $opts -u - TCP4-CONNECT:$SECONDADDR:$PORT,bind=$SECONDADDR" printf "test $F_n $TEST... " $N $CMD0 2>"${te}0" & pid0=$! waittcp4port $PORT 1 echo "$da" |$CMD1 >"${tf}1" 2>"${te}1" rc1=$? sleep 1 kill $pid0 2>/dev/null; wait if [ $rc1 != 0 ]; then $PRINTF "${YELLOW}invocation failed${NORMAL}\n" numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif ! [ -f "$tf" ]; then $PRINTF "$FAILED\n" echo "$CMD0 &" echo "$CMD1" cat "${te}0" cat "${te}1" numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" elif ! echo "$da" |diff - "$tf" >"$tdiff"; then $PRINTF "${YELLOW}diff failed${NORMAL}\n" numCANT=$((numCANT+1)) listCANT="$listCANT $N" else $PRINTF "$OK\n" numOK=$((numOK+1)) fi fi ;; # $SECONDADDR, NUMCOND esac N=$((N+1)) # test: OPENSSL sets of environment variables with important values of peer certificate newport tcp4 while read ssldist MODE MODULE FIELD TESTADDRESS PEERADDRESS VALUE; do if [ -z "$ssldist" ] || [[ "$ssldist" == \#* ]]; then continue; fi # SSLDIST=$(toupper $ssldist) NAME="ENV_${SSLDIST}_${MODE}_${MODULE}_${FIELD}" case "$TESTS" in *%$N%*|*%functions%*|*%ip4%*|*%ipapp%*|*%tcp%*|*%$ssldist%*|*%envvar%*|*%listen%*|*%$NAME%*) TEST="$NAME: $SSLDIST sets env SOCAT_${SSLDIST}_${MODULE}_${FIELD}" # have a server accepting a connection and invoking some shell code. The shell # code extracts and prints the SOCAT related environment vars. # outside code then checks if the environment contains the variables correctly # describing the desired field. FEAT=$(echo "$ssldist" |tr a-z A-Z) if ! eval $NUMCOND; then :; elif ! testfeats $FEAT >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}$FEAT not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" else tf="$td/test$N.stdout" te="$td/test$N.stderr" gentestcert testsrv gentestcert testcli test_proto=tcp4 case "$MODE" in SERVER) CMD0="$SOCAT $opts -u -lp socat $TESTADDRESS SYSTEM:\"echo SOCAT_${SSLDIST}_${MODULE}_${FIELD}=\\\$SOCAT_${SSLDIST}_${MODULE}_${FIELD}; sleep 1\"" CMD1="$SOCAT $opts -u /dev/null $PEERADDRESS" printf "test $F_n $TEST... " $N eval "$CMD0 2>\"${te}0\" >\"$tf\" &" pid0=$! wait${test_proto}port $PORT 1 { $CMD1 2>"${te}1"; sleep 1; } rc1=$? waitfile "$tf" 2 kill $pid0 2>/dev/null; wait ;; CLIENT) CMD0="$SOCAT $opts -u /dev/null $PEERADDRESS" CMD1="$SOCAT $opts -u -lp socat $TESTADDRESS SYSTEM:\"echo SOCAT_${SSLDIST}_${MODULE}_${FIELD}=\\\$SOCAT_${SSLDIST}_${MODULE}_${FIELD}; sleep 1\"" printf "test $F_n $TEST... " $N $CMD0 2>"${te}0" & pid0=$! wait${test_proto}port $PORT 1 eval "$CMD1 2>\"${te}1\" >\"$tf\"" rc1=$? waitfile "$tf" 2 kill $pid0 2>/dev/null; wait ;; esac if [ $rc1 != 0 ]; then $PRINTF "$NO_RESULT (client failed):\n" echo "$CMD0 &" cat "${te}0" echo "$CMD1" cat "${te}1" numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif effval="$(grep SOCAT_${SSLDIST}_${MODULE}_${FIELD} "${tf}" |sed -e 's/^[^=]*=//' |sed -e "s/[\"']//g")"; [ "$effval" = "$VALUE" ]; then $PRINTF "$OK\n" if [ "$debug" ]; then echo "$CMD0 &" cat "${te}0" echo "$CMD1" cat "${te}1" fi numOK=$((numOK+1)) else $PRINTF "$FAILED\n" echo "expected \"$VALUE\", got \"$effval\"" >&2 echo "$CMD0 &" cat "${te}0" echo "$CMD1" cat "${te}1" numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" fi fi # NUMCOND, feats ;; esac N=$((N+1)) # done <<<" openssl SERVER X509 ISSUER OPENSSL-LISTEN:$PORT,pf=ip4,$REUSEADDR,bind=$LOCALHOST,cert=testsrv.pem,cafile=testcli.crt,verify=1 OPENSSL-CONNECT:$LOCALHOST:$PORT,pf=ip4,cert=testcli.pem,cafile=testsrv.crt,verify=1 $TESTCERT_ISSUER openssl SERVER X509 SUBJECT OPENSSL-LISTEN:$PORT,pf=ip4,$REUSEADDR,bind=$LOCALHOST,cert=testsrv.pem,cafile=testcli.crt,verify=1 OPENSSL-CONNECT:$LOCALHOST:$PORT,pf=ip4,cert=testcli.pem,cafile=testsrv.crt,verify=1 $TESTCERT_SUBJECT openssl SERVER X509 COMMONNAME OPENSSL-LISTEN:$PORT,pf=ip4,$REUSEADDR,bind=$LOCALHOST,cert=testsrv.pem,cafile=testcli.crt,verify=1 OPENSSL-CONNECT:$LOCALHOST:$PORT,pf=ip4,cert=testcli.pem,cafile=testsrv.crt,verify=1 $TESTCERT_COMMONNAME openssl SERVER X509 COUNTRYNAME OPENSSL-LISTEN:$PORT,pf=ip4,$REUSEADDR,bind=$LOCALHOST,cert=testsrv.pem,cafile=testcli.crt,verify=1 OPENSSL-CONNECT:$LOCALHOST:$PORT,pf=ip4,cert=testcli.pem,cafile=testsrv.crt,verify=1 $TESTCERT_COUNTRYNAME openssl SERVER X509 LOCALITYNAME OPENSSL-LISTEN:$PORT,pf=ip4,$REUSEADDR,bind=$LOCALHOST,cert=testsrv.pem,cafile=testcli.crt,verify=1 OPENSSL-CONNECT:$LOCALHOST:$PORT,pf=ip4,cert=testcli.pem,cafile=testsrv.crt,verify=1 $TESTCERT_LOCALITYNAME openssl SERVER X509 ORGANIZATIONALUNITNAME OPENSSL-LISTEN:$PORT,pf=ip4,$REUSEADDR,bind=$LOCALHOST,cert=testsrv.pem,cafile=testcli.crt,verify=1 OPENSSL-CONNECT:$LOCALHOST:$PORT,pf=ip4,cert=testcli.pem,cafile=testsrv.crt,verify=1 $TESTCERT_ORGANIZATIONALUNITNAME openssl SERVER X509 ORGANIZATIONNAME OPENSSL-LISTEN:$PORT,pf=ip4,$REUSEADDR,bind=$LOCALHOST,cert=testsrv.pem,cafile=testcli.crt,verify=1 OPENSSL-CONNECT:$LOCALHOST:$PORT,pf=ip4,cert=testcli.pem,cafile=testsrv.crt,verify=1 $TESTCERT_ORGANIZATIONNAME openssl CLIENT X509 SUBJECT OPENSSL-CONNECT:$LOCALHOST:$PORT,pf=ip4,cert=testcli.pem,cafile=testsrv.crt,verify=1 OPENSSL-LISTEN:$PORT,pf=ip4,$REUSEADDR,bind=$LOCALHOST,cert=testsrv.pem,cafile=testcli.crt,verify=1 $TESTCERT_SUBJECT openssl CLIENT X509 ISSUER OPENSSL-CONNECT:$LOCALHOST:$PORT,pf=ip4,cert=testcli.pem,cafile=testsrv.crt,verify=1 OPENSSL-LISTEN:$PORT,pf=ip4,$REUSEADDR,bind=$LOCALHOST,cert=testsrv.pem,cafile=testcli.crt,verify=1 $TESTCERT_ISSUER " ############################################################################### # tests: option umask with "passive" NAMED group addresses while read addr fileopt addropts proto diropt ADDR2; do if [ -z "$addr" ] || [[ "$addr" == \#* ]]; then continue; fi # some passive (listening...) filesystem based addresses did not implement the # umask option ADDR=$(toupper $addr) ADDR_=${ADDR/-/_} PROTO=$(toupper $proto) if [ "$diropt" = "." ]; then diropt=; fi if [ "$fileopt" = "." ]; then fileopt=; fi if [ "$addropts" = "." ]; then addropts=; fi NAME=${ADDR_}_UMASK case "$TESTS" in *%$N%*|*%functions%*|*%bugs%*|*%proto%*|*%socket%*|*%$proto%*|*%umask%*|*%listen%*|*%$NAME%*) TEST="$NAME: $ADDR applies option umask" # start a socat process with passive/listening file system entry. Check the # permissions of the FS entry, then terminate the process. # Test succeeds when FS entry exists and has expected permissions. if ! eval $NUMCOND; then :; else if [ $ADDR = PTY ]; then set -xv; fi tlog="$td/test$N.log" te0="$td/test$N.0.stderr" tsock="$td/test$N.sock" if [ -z "$fileopt" ]; then CMD0="$TRACE $SOCAT $opts $diropt $ADDR:$tsock,$addropts,unlink-close=0,umask=177 $ADDR2" else CMD0="$TRACE $SOCAT $opts $diropt $ADDR,$fileopt=$tsock,$addropts,unlink-close=0,umask=177 $ADDR2" fi printf "test $F_n $TEST... " $N $CMD0 >/dev/null 2>"$te0" & pid0=$! wait${proto} $tsock 1 2>"$tlog" ERRNOENT=; if ! [ -e "$tsock" ]; then ERRNOENT=1; fi perms=$(fileperms "$tsock") kill $pid0 2>>"$tlog" wait if [ "$ERRNOENT" ]; then $PRINTF "${RED}no entry${NORMAL}\n" echo "$CMD0 &" cat "$te0" cat "$tlog" let numFAIL=numFAIL+1 listFAIL="$listFAIL $N" elif [ "$perms" != "600" ]; then $PRINTF "${RED}perms \"$perms\", expected \"600\" ${NORMAL}\n" echo "$CMD0 &" cat "$te0" let numFAIL=numFAIL+1 listFAIL="$listFAIL $N" else $PRINTF "$OK\n" let numOK=numOK+1 fi set +xv fi # NUMCOND ;; esac N=$((N+1)) # done <<<" # address fileopt addropts waitfor direction ADDR2 create . . file -U FILE:/dev/null open . creat file . FILE:/dev/null gopen . creat file . FILE:/dev/null unix-listen . . unixport . FILE:/dev/null unix-recvfrom . . unixport . FILE:/dev/null unix-recv . . unixport -u FILE:/dev/null pipe . . file -u FILE:/dev/null # pty does not seem to honor umask: #pty link . file . PIPE " # tests: option perm with "passive" NAMED group addresses while read addr fileopt addropts feat waitfor diropt; do if [ -z "$addr" ] || [[ "$addr" == \#* ]]; then continue; fi # test if passive (listening...) filesystem based addresses implement option perm ADDR=$(toupper $addr) ADDR_=${ADDR/-/_} if [ "$diropt" = "." ]; then diropt=; fi if [ "$fileopt" = "." ]; then fileopt=; fi if [ "$addropts" = "." ]; then addropts=; fi NAME=${ADDR_}_PERM case "$TESTS" in *%$N%*|*%functions%*|*%bugs%*|*%socket%*|*%$feat%*|*%ignoreeof%*|*%perm%*|*%listen%*|*%$NAME%*) TEST="$NAME: $ADDR applies option perm" # start a socat process with passive/listening file system entry. Check the # permissions of the FS entry, then terminate the process. # Test succeeds when FS entry exists and has expected permissions. if ! eval $NUMCOND; then :; else tlog="$td/test$N.log" te0="$td/test$N.0.stderr" tsock="$td/test$N.sock" # set -vx if [ -z "$fileopt" ]; then CMD0="$TRACE $SOCAT $opts $diropt $ADDR:$tsock,$addropts,perm=511 FILE:/dev/null,ignoreeof" else CMD0="$TRACE $SOCAT $opts $diropt $ADDR,$fileopt=$tsock,$addropts,perm=511 FILE:/dev/null,ignoreeof" fi printf "test $F_n $TEST... " $N $CMD0 >/dev/null 2>"$te0" & pid0=$! wait${waitfor} $tsock 1 2>"$tlog" ERRNOENT=; if ! [ -e "$tsock" ]; then ERRNOENT=1; fi perms=$(fileperms "$tsock") kill $pid0 2>>"$tlog" wait if [ "$ERRNOENT" ]; then $PRINTF "${RED}no entry${NORMAL}\n" echo "$CMD0 &" cat "$te0" cat "$tlog" let numFAIL=numFAIL+1 listFAIL="$listFAIL $N" elif [ "$perms" != "511" ]; then $PRINTF "${RED}perms \"$perms\", expected \"511\" ${NORMAL}\n" echo "$CMD0 &" cat "$te0" let numFAIL=numFAIL+1 listFAIL="$listFAIL $N" else $PRINTF "$OK\n" let numOK=numOK+1 fi set +vx fi # NUMCOND ;; esac N=$((N+1)) # done <<<" # address fileopt addropts feat waitfor direction create . . file file -U open . creat file file . gopen . creat file file . unix-listen . . unix unixport . unix-recvfrom . . unix unixport . unix-recv . . unix unixport -u pipe . . pipe file -u pty link . pty file . " # tests: option user with "passive" NAMED group addresses while read addr fileopt addropts feat waitfor diropt; do if [ -z "$addr" ] || [[ "$addr" == \#* ]]; then continue; fi # test if passive (listening...) filesystem based addresses implement option user ADDR=$(toupper $addr) ADDR_=${ADDR/-/_} if [ "$diropt" = "." ]; then diropt=; fi if [ "$fileopt" = "." ]; then fileopt=; fi if [ "$addropts" = "." ]; then addropts=; fi NAME=${ADDR_}_USER case "$TESTS" in *%$N%*|*%functions%*|*%bugs%*|*%socket%*|*%$feat%*|*%root%*|*%ignoreeof%*|*%listen%*|*%$NAME%*) TEST="$NAME: $ADDR applies option user" # start a socat process with passive/listening file system entry with user option. # Check the owner of the FS entry, then terminate the process. # Test succeeds when FS entry exists and has expected owner. if ! eval $NUMCOND; then :; elif [ $(id -u) -ne 0 -a "$withroot" -eq 0 ]; then $PRINTF "test $F_n $TEST... ${YELLOW}must be root${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" else tlog="$td/test$N.log" te0="$td/test$N.0.stderr" tsock="$td/test$N.sock" # set -vx if [ -z "$fileopt" ]; then CMD0="$TRACE $SOCAT $opts $diropt $ADDR:$tsock,$addropts,user=$SUBSTUSER FILE:/dev/null,ignoreeof" else CMD0="$TRACE $SOCAT $opts $diropt $ADDR,$fileopt=$tsock,$addropts,user=$SUBSTUSER FILE:/dev/null,ignoreeof" fi printf "test $F_n $TEST... " $N $CMD0 >/dev/null 2>"$te0" & pid0=$! wait${waitfor} $tsock 1 2>"$tlog" ERRNOENT=; if ! [ -e "$tsock" ]; then ERRNOENT=1; fi user=$(fileuser "$tsock") kill $pid0 2>>"$tlog" wait if [ "$ERRNOENT" ]; then $PRINTF "${RED}no entry${NORMAL}\n" echo "$CMD0 &" cat "$te0" cat "$tlog" let numFAIL=numFAIL+1 listFAIL="$listFAIL $N" elif [ "$user" != "$SUBSTUSER" ]; then $PRINTF "${RED}user \"$user\", expected \"$SUBSTUSER\" ${NORMAL}\n" echo "$CMD0 &" cat "$te0" let numFAIL=numFAIL+1 listFAIL="$listFAIL $N" else $PRINTF "$OK\n" let numOK=numOK+1 fi set +vx fi # NUMCOND ;; esac N=$((N+1)) # done <<<" # address fileopt addropts feat waitfor direction create . . file file -U open . creat file file . gopen . creat file file . unix-listen . . unix unixport . unix-recvfrom . . unix unixport . unix-recv . . unix unixport -u pipe . . pipe file -u pty link . pty file . " # tests: is "passive" filesystem entry removed at the end? (without fork) while read addr fileopt addropts feat waitfor diropt crit ADDR2; do if [ -z "$addr" ] || [[ "$addr" == \#* ]]; then continue; fi # some passive (listening...) filesystem based addresses did not remove the file # system entry at the end ADDR=$(toupper $addr) ADDR_=${ADDR/-/_} if [ "$diropt" = "." ]; then diropt=; fi if [ "$fileopt" = "." ]; then fileopt=; fi if [ "$addropts" = "." ]; then addropts=; fi # $ADDR removes the file system entry when the process is terminated NAME=${ADDR_}_REMOVE case "$TESTS" in *%$N%*|*%functions%*|*%bugs%*|*%feat%*|*%socket%*|*%listen%*|*%$NAME%*) TEST="$NAME: $ADDR removes socket entry when terminated while waiting for connection" # start a socat process with listening unix domain socket etc. Terminate the # process and check if the file system socket entry still exists. # Test succeeds when entry does not exist. if ! eval $NUMCOND; then :; else tlog="$td/test$N.log" te0="$td/test$N.0.stderr" tsock="$td/test$N.sock" if [ -z "$fileopt" ]; then CMD0="$TRACE $SOCAT $opts $diropt $ADDR:$tsock,$addropts $ADDR2" else CMD0="$TRACE $SOCAT $opts $diropt $ADDR,$fileopt=$tsock,$addropts $ADDR2" fi printf "test $F_n $TEST... " $N $CMD0 >/dev/null 2>"$te0" & pid0=$! wait${waitfor} "$crit" $tsock 1 2>"$tlog" kill $pid0 2>>"$tlog" rc1=$? wait >>"$tlog" if [ $rc1 != 0 ]; then $PRINTF "${YELLOW}setup failed${NORMAL}\n" echo "$CMD0 &" cat "$te0" cat "$tlog" numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif ! [ $crit $tsock ]; then $PRINTF "$OK\n" let numOK=numOK+1 else $PRINTF "$FAILED\n" echo "$CMD0 &" cat "$te0" cat "$tlog" let numFAIL=numFAIL+1 listFAIL="$listFAIL $N" fi fi # NUMCOND ;; esac N=$((N+1)) # done <<<" # address fileopt addropts feat waitfor direction crit ADDR2 unix-listen . . unix unixport . -e FILE:/dev/null unix-recvfrom . . unix unixport . -e FILE:/dev/null unix-recv . . unix unixport -u -e FILE:/dev/null pipe . . pipe file -u -e FILE:/dev/null pty link . pty file . -L PIPE " # tests: is "passive" filesystem entry removed at the end? (with fork) while read addr fileopt addropts proto diropt crit ADDR2; do if [ -z "$addr" ] || [[ "$addr" == \#* ]]; then continue; fi # some passive (listening...) filesystem based addresses with fork did not remove # the file system entry at the end ADDR=$(toupper $addr) ADDR_=${ADDR/-/_} PROTO=$(toupper $proto) if [ "$diropt" = "." ]; then diropt=; fi if [ "$fileopt" = "." ]; then fileopt=; fi if [ "$addropts" = "." ]; then addropts=; fi # $ADDR with fork removes the file system entry when the process is terminated NAME=${ADDR_}_REMOVE_FORK case "$TESTS" in *%$N%*|*%functions%*|*%bugs%*|*%fork%*|*%unix%*|*%socket%*|*%listen%*|*%$NAME%*) TEST="$NAME: $ADDR with fork removes socket entry when terminated during accept" # start a socat process with listening unix domain socket etc and option fork. # Terminate the process and check if the file system socket entry still exists. # Test succeeds when entry does not exist. if ! eval $NUMCOND; then :; else tlog="$td/test$N.log" te0="$td/test$N.0.stderr" tsock="$td/test$N.sock" if [ -z "$fileopt" ]; then CMD0="$TRACE $SOCAT $opts $diropt $ADDR:$tsock,fork,$addropts $ADDR2" else CMD0="$TRACE $SOCAT $opts $diropt $ADDR,fork,$fileopt=$tsock,$addropts $ADDR2" fi printf "test $F_n $TEST... " $N $CMD0 >/dev/null 2>"$te0" & pid0=$! wait${proto} "$crit" $tsock 1 2>"$tlog" kill $pid0 2>>"$tlog" rc1=$? wait if [ $rc1 != 0 ]; then $PRINTF "${YELLOW}setup failed${NORMAL}\n" echo "$CMD0 &" cat "$te0" cat "$tlog" numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif ! [ $crit $tsock ]; then $PRINTF "$OK\n" let numOK=numOK+1 else $PRINTF "$FAILED\n" echo "$CMD0 &" cat "$te0" cat "$tlog" let numFAIL=numFAIL+1 listFAIL="$listFAIL $N" fi fi # NUMCOND ;; esac N=$((N+1)) # done <<<" # address fileopt addropts waitfor direction crit ADDR2 unix-listen . . unixport . -e FILE:/dev/null unix-recvfrom . . unixport . -e FILE:/dev/null " # bug fix: SYSTEM address child process shut down parents sockets including # SSL connection under some circumstances. NAME=SYSTEM_SHUTDOWN case "$TESTS" in *%$N%*|*%functions%*|*%bugs%*|*%system%*|*%openssl%*|*%socket%*|*%listen%*|*%$NAME%*) TEST="$NAME: SYSTEM address does not shutdown its parents addresses" # start an OpenSSL echo server using SYSTEM:cat # start an OpenSSL client that sends data # when the client recieves its data and terminates without error the test succeeded # in case of the bug the client issues an error like: # SSL_connect(): error:1408F119:SSL routines:SSL3_GET_RECORD:decryption failed or bad record mac if ! eval $NUMCOND; then :; elif ! testfeats openssl >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}OPENSSL not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" else gentestcert testsrv tf="$td/test$N.stdout" te="$td/test$N.stderr" tdiff="$td/test$N.diff" da="test$N $(date) $RANDOM" newport tcp4 CMD0="$SOCAT $opts OPENSSL-LISTEN:$PORT,pf=ip4,$REUSEADDR,cert=testsrv.pem,verify=0 SYSTEM:cat" CMD1="$SOCAT $opts - OPENSSL-CONNECT:$LOCALHOST:$PORT,pf=ip4,verify=0" printf "test $F_n $TEST... " $N $CMD0 >/dev/null 2>"${te}0" & pid0=$! waittcp4port $PORT 1 echo "$da" |$CMD1 >"${tf}1" 2>"${te}1" rc1=$? kill $pid0 2>/dev/null; wait if [ $rc1 -ne 0 ]; then $PRINTF "$FAILED\n" echo "rc1=$rc1" echo "$CMD0 &" echo "$CMD1" cat "${te}0" cat "${te}1" numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" elif ! echo "$da" |diff - "${tf}1" >"$tdiff" 2>&1; then $PRINTF "$FAILED\n" echo "diff:" cat "$tdiff" echo "$CMD0 &" echo "$CMD1" cat "${te}0" cat "${te}1" numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" else $PRINTF "$OK\n" numOK=$((numOK+1)) fi fi # NUMCOND ;; esac N=$((N+1)) # test if TCP4-LISTEN with empty port arg terminates with error NAME=TCP4_NOPORT case "$TESTS" in *%$N%*|*%functions%*|*%bugs%*|*%socket%*|*%tcp%*|*%tcp4%*|*%listen%*|*%$NAME%*) TEST="$NAME: test if TCP4-LISTEN with empty port arg bails out" # run socat with TCP4-LISTEN with empty port arg. Check if it terminates # immediately with return code 1 if ! eval $NUMCOND; then :; else tf="$td/test$N.stdout" te="$td/test$N.stderr" t0rc="$td/test$N.rc" tdiff="$td/test$N.diff" da="test$N $(date) $RANDOM" CMD0="$SOCAT $opts TCP4-LISTEN: /dev/null" printf "test $F_n $TEST... " $N { $CMD0 >/dev/null 2>"${te}0"; echo $? >"$t0rc"; } & 2>/dev/null pid0=$! sleep 1 kill $pid0 2>/dev/null; wait if [ ! -f "$t0rc" ]; then $PRINTF "$FAILED\n" echo "no return code of CMD0 stored" >&2 echo "$CMD0 &" cat "${te}0" numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" elif ! echo 1 |diff - "$t0rc" >"$tdiff"; then $PRINTF "$FAILED\n" echo "CMD0 exited with $(cat $t0rc), expected 1" echo "$CMD0 &" cat "${te}0" numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" else $PRINTF "$OK\n" numOK=$((numOK+1)) fi fi # NUMCOND ;; esac N=$((N+1)) # tests of various SSL methods; from TLS1.3 this method is not avail in OpenSSL: OPENSSL_METHODS_OBSOLETE="SSL3 SSL23" OPENSSL_METHODS_EXPECTED="TLS1 TLS1.1 TLS1.2 DTLS1 DTLS1.2" # the OPENSSL_METHOD_DTLS1 test hangs sometimes, probably depending on the openssl version. OPENSSL_VERSION="$(openssl version)" OPENSSL_VERSION="${OPENSSL_VERSION#* }" OPENSSL_VERSION="${OPENSSL_VERSION%%-*}" OPENSSL_VERSION_GOOD=1.0.2 # this is just a guess. # known bad: 1.0.1e # known good: 1.0.2j # test if the obsolete SSL methods can be used with OpenSSL for method in $OPENSSL_METHODS_OBSOLETE; do NAME=OPENSSL_METHOD_$method case "$TESTS" in *%$N%*|*%functions%*|*%bugs%*|*%socket%*|*%openssl%*|*%listen%*|*%$NAME%*) TEST="$NAME: test OpenSSL method $method" # Start a socat process with obsoelete OpenSSL method, it should fail if ! eval $NUMCOND; then :; elif ! testfeats openssl >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}OPENSSL not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif ! socat -hhh |grep -q "^[[:space:]]*openssl-method[[:space:]]"; then $PRINTF "test $F_n $TEST... ${YELLOW}Option openssl-method not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" else gentestcert testsrv tf="$td/test$N.stdout" te="$td/test$N.stderr" tdiff="$td/test$N.diff" da="test$N $(date) $RANDOM" newport tcp4 CMD0="$SOCAT $opts OPENSSL-LISTEN:$PORT,$REUSEADDR,openssl-method=$method,cert=testsrv.pem,verify=0 PIPE" CMD1="$SOCAT $opts - OPENSSL-CONNECT:$LOCALHOST:$PORT,opensslmethod=$method,verify=0" printf "test $F_n $TEST... " $N if [ "$method" = DTLS1 -a "$(echo -e "$OPENSSL_VERSION\n1.0.2" |sort |tail -n 1)" = "$OPENSSL_VERSION_GOOD" ]; then $PRINTF "${YELLOW}might hang, skipping${NORMAL}\n" numCANT=$((numCANT+1)) listCANT="$listCANT $N" else $CMD0 >/dev/null 2>"${te}0" & pid0=$! waittcp4port $PORT 1 1 2>/dev/null; w0=$? # result of waiting for process 0 if [ $w0 -eq 0 ]; then echo "$da" |$CMD1 >"${tf}1" 2>"${te}1" rc1=$? kill $pid0 2>/dev/null; wait fi echo "$da" |diff - "${tf}1" >"$tdiff" 2>/dev/null if [ $w0 -eq 0 ] && [ -f "${tf}1" ] && ! [ -s "$tdiff" ]; then $PRINTF "${YELLOW}WARN${NORMAL} (obsolete method succeeds)\n" numOK=$((numOK+1)) else $PRINTF "$OK (obsolete method fails)\n" cat "$tdiff" numOK=$((numOK+1)) fi if [ "$VERBOSE" ]; then echo " $CMD0" echo " echo \"$da\" |$CMD1" fi fi # !DTLS1 hang fi # NUMCOND ;; esac N=$((N+1)) done # test if the various SSL methods can be used with OpenSSL for method in $OPENSSL_METHODS_EXPECTED; do NAME=OPENSSL_METHOD_$method METHFAM=$(tolower "${method%%[0-9]*}") case "$TESTS" in *%$N%*|*%functions%*|*%bugs%*|*%socket%*|*%openssl%*|*%$METHFAM%*|*%listen%*|*%$NAME%*) TEST="$NAME: test OpenSSL method $method" # Start a socat process listening with OpenSSL and echoing data, # using the selected method # Start a second socat process connecting to the listener using # the same method, send some data and catch the reply. # If the reply is identical to the sent data the test succeeded. if ! eval $NUMCOND; then :; elif ! testfeats openssl >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}OPENSSL not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif ! socat -hhh |grep -q "^[[:space:]]*openssl-method[[:space:]]"; then $PRINTF "test $F_n $TEST... ${YELLOW}Option openssl-method not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" else gentestcert testsrv tf="$td/test$N.stdout" te="$td/test$N.stderr" tdiff="$td/test$N.diff" da="test$N $(date) $RANDOM" if [[ "$method" =~ DTLS* ]]; then newport udp4 else newport tcp4 fi CMD0="$SOCAT $opts OPENSSL-LISTEN:$PORT,$REUSEADDR,openssl-method=$method,cert=testsrv.pem,verify=0 PIPE" CMD1="$SOCAT $opts - OPENSSL-CONNECT:$LOCALHOST:$PORT,openssl-method=$method,verify=0" printf "test $F_n $TEST... " $N if [ "$method" = DTLS1 -a "$(echo -e "$OPENSSL_VERSION\n1.0.2" |sort |tail -n 1)" = "$OPENSSL_VERSION_GOOD" ]; then $PRINTF "${YELLOW}might hang, skipping${NORMAL}\n" numCANT=$((numCANT+1)) listCANT="$listCANT $N" else $CMD0 >/dev/null 2>"${te}0" & pid0=$! if [[ "$method" =~ DTLS* ]]; then waitudp4port $PORT 1 else waittcp4port $PORT 1 fi echo "$da" |$CMD1 >"${tf}1" 2>"${te}1" rc1=$? kill $pid0 2>/dev/null; wait if echo "$da" |diff - "${tf}1" >"$tdiff"; then $PRINTF "$OK\n" numOK=$((numOK+1)) if [ "$VERBOSE" ]; then echo " $CMD0" echo " echo \"$da\" |$CMD1" fi else $PRINTF "$FAILED\n" echo "$CMD0 &" cat "${te}0" echo "$CMD1" cat "${te}1" cat "$tdiff" numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" #esac fi fi # !DTLS1 hang fi # NUMCOND ;; esac N=$((N+1)) done # test security of option openssl-set-min-proto-version OPENSSL_LATEST_PROTO_VERSION=$(openssl s_server --help 2>&1 |grep -e -ssl[1-9] -e -tls[1-9] |awk '{print($1);}' |cut -c 2- |tr '[a-z_]' '[A-Z.]' |sort |tail -n 1) OPENSSL_BEFORELAST_PROTO_VERSION=$(openssl s_server --help 2>&1 |grep -e -ssl[1-9] -e -tls[1-9] |awk '{print($1);}' |cut -c 2- |tr '[a-z_]' '[A-Z.]' |sort |tail -n 2 |head -n 1) NAME=OPENSSL_MIN_VERSION case "$TESTS" in *%$N%*|*%functions%*|*%security%*|*%tcp%*|*%tcp4%*|*%ip4%*|*%openssl%*|*%listen%*|*%$NAME%*) TEST="$NAME: security of OpenSSL server with openssl-min-proto-version" if ! eval $NUMCOND; then :; elif ! testaddrs openssl >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}OPENSSL not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif ! feat=$(testoptions openssl-min-proto-version); then $PRINTF "test $F_n $TEST... ${YELLOW}$feat not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif ! [ "$OPENSSL_LATEST_PROTO_VERSION" -a "$OPENSSL_BEFORELAST_PROTO_VERSION" -a \ "$OPENSSL_LATEST_PROTO_VERSION" != "$OPENSSL_BEFORELAST_PROTO_VERSION" ]; then $PRINTF "test $F_n $TEST... ${YELLOW}cannot determine two available SSL/TLS versions${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" else gentestcert testsrv newport tcp4 testserversec "$N" "$TEST" "$opts -4" "SSL-L:$PORT,pf=ip4,reuseaddr,$SOCAT_EGD,verify=0,cert=testsrv.crt,key=testsrv.key" "" "openssl-min-proto-version=$OPENSSL_LATEST_PROTO_VERSION" "SSL:$LOCALHOST:$PORT,cafile=testsrv.crt,$SOCAT_EGD,openssl-max-proto-version=$OPENSSL_BEFORELAST_PROTO_VERSION" 4 tcp $PORT -1 fi ;; # NUMCOND, $fets esac N=$((N+1)) # Address options fdin and fdout were silently ignored when not applicable # due to -u or -U option. Now these combinations are caught as errors. NAME=FDOUT_ERROR case "$TESTS" in *%$N%*|*%functions%*|*%bugs%*|*%socket%*|*%$NAME%*) TEST="$NAME: fdout bails out in write-only context" # use EXEC in write-only context with option fdout. Expected behaviour: error if ! eval $NUMCOND; then :; else tf="$td/test$N.stdout" te="$td/test$N.stderr" tdiff="$td/test$N.diff" da="test$N $(date) $RANDOM" CMD="$SOCAT $opts -u /dev/null EXEC:cat,fdout=1" printf "test $F_n $TEST... " $N $CMD >/dev/null 2>"${te}" rc=$? if [ $rc -eq 1 ]; then $PRINTF "$OK\n" numOK=$((numOK+1)) else $PRINTF "$FAILED\n" echo "$CMD" cat "${te}" echo "command did not terminate with error!" numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" fi fi # NUMCOND ;; esac N=$((N+1)) # test if failure exit code of SYSTEM invocation causes socat to also exit # with !=0 NAME=SYSTEM_RC case "$TESTS" in *%$N%*|*%functions%*|*%system%*|*%$NAME%*) TEST="$NAME: promote failure of SYSTEM" # run socat with SYSTEM:false and check if socat exits with !=0 if ! eval $NUMCOND; then :; else tf="$td/test$N.stdout" te="$td/test$N.stderr" tdiff="$td/test$N.diff" da="test$N $(date) $RANDOM" # shut-none makes sure that the child is not killed by parent CMD0="$TRACE $SOCAT $opts - SYSTEM:false,shut-none" printf "test $F_n $TEST... " $N sleep 1 |$CMD0 >/dev/null 2>"${te}0" rc0=$? if [ $rc0 -eq 0 ]; then $PRINTF "$FAILED\n" echo "$CMD0" cat "${te}0" numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" else $PRINTF "$OK\n" numOK=$((numOK+1)) fi fi # NUMCOND ;; esac N=$((N+1)) # test if failure exit code of EXEC invocation causes socat to also exit # with !=0 NAME=EXEC_RC case "$TESTS" in *%$N%*|*%functions%*|*%exec%*|*%$NAME%*) TEST="$NAME: promote failure of EXEC" # run socat with EXEC:false and check if socat exits with !=0 if ! eval $NUMCOND; then :; else tf="$td/test$N.stdout" te="$td/test$N.stderr" tdiff="$td/test$N.diff" da="test$N $(date) $RANDOM" # shut-none makes sure that the child is not killed by parent CMD0="$TRACE $SOCAT $opts - EXEC:false,shut-none" printf "test $F_n $TEST... " $N sleep 1 |$CMD0 >/dev/null 2>"${te}0" rc0=$? if [ $rc0 -eq 0 ]; then $PRINTF "$FAILED\n" echo "$CMD0" cat "${te}0" numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" else $PRINTF "$OK\n" numOK=$((numOK+1)) fi fi # NUMCOND ;; esac N=$((N+1)) # test the so-reuseaddr option NAME=SO_REUSEADDR case "$TESTS" in *%$N%*|*%functions%*|*%ip4%*|*%tcp%*|*%socket%*|*%listen%*|*%$NAME%*) TEST="$NAME: test the so-reuseaddr option" # process 0 provides a tcp listening socket with so-reuseaddr; # process 1 connects to this port; thus the port is connected but no longer # listening # process 2 tries to listen on this port with SO_REUSEADDR, will fail if the # SO_REUSEADDR socket options did not work # process 3 connects to this port; only if it is successful the test is ok if ! eval $NUMCOND; then :; elif ! feat=$(testoptions so-reuseaddr); then $PRINTF "test $F_n $TEST... ${YELLOW}$feat not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" else newport tcp4; tp="$PORT" tf="$td/test$N.stdout" te="$td/test$N.stderr" tdiff="$td/test$N.diff" da="test$N $(date) $RANDOM" CMD0="$TRACE $SOCAT $opts TCP4-L:$tp,$REUSEADDR PIPE" CMD1="$TRACE $SOCAT $opts - TCP4:localhost:$tp" CMD2="$CMD0" CMD3="$CMD1" printf "test $F_n $TEST... " $N $CMD0 >/dev/null 2>"${te}0" & pid0=$! waittcp4port $tp 1 (echo "$da"; sleep 3) |$CMD1 >"$tf" 2>"${te}1" & # this should always work pid1=$! usleep 1000000 $CMD2 >/dev/null 2>"${te}2" & pid2=$! waittcp4port $tp 1 (echo "$da") |$CMD3 >"${tf}3" 2>"${te}3" rc3=$? kill $pid0 $pid1 $pid2 2>/dev/null; wait if ! echo "$da" |diff - "$tf"; then $PRINTF "${YELLOW}phase 1 failed${NORMAL}\n" echo "$CMD0 &" echo "$CMD1" numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif [ $rc3 -ne 0 ]; then $PRINTF "$FAILED: $TRACE $SOCAT:\n" echo "$CMD0 &" echo "$CMD1" echo "$CMD2 &" echo "$CMD3" cat "${te}2" "${te}3" numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" elif ! echo "$da" |diff - "${tf}3"; then $PRINTF "$FAILED: $TRACE $SOCAT:\n" echo "$CMD0 &" echo "$CMD1" echo "$CMD2 &" echo "$CMD3" echo "$da" |diff - "${tf}3" numCANT=$((numCANT+1)) listCANT="$listCANT $N" else $PRINTF "$OK\n" if [ -n "$debug" ]; then cat "${te}0" "${te}1" "${te}2" "${te}3"; fi numOK=$((numOK+1)) fi fi # NUMCOND, SO_REUSEADDR ;; esac N=$((N+1)) # test the so-reuseport option NAME=SO_REUSEPORT case "$TESTS" in *%$N%*|*%functions%*|*%ip4%*|*%tcp%*|*%socket%*|*%listen%*|*%$NAME%*) TEST="$NAME: test the so-reuseport option" # process 0 provides a tcp listening socket with so-reuseport; # process 1 provides an equivalent tcp listening socket with so-reuseport; # process 2 connects to this port and transfers data # process 3 connects to this port and transfers data # test succeeds when both data transfers work if ! eval $NUMCOND; then :; elif ! feat=$(testoptions so-reuseport); then $PRINTF "test $F_n $TEST... ${YELLOW}$feat not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" else newport tcp4; tp="$PORT" tf="$td/test$N.stdout" te="$td/test$N.stderr" tdiff="$td/test$N.diff" da2="test$N $(date) $RANDOM" da3="test$N $(date) $RANDOM" CMD0="$TRACE $SOCAT $opts TCP4-L:$tp,$REUSEADDR,so-reuseport PIPE" CMD1="$CMD0" CMD2="$TRACE $SOCAT $opts - TCP4:localhost:$tp" CMD3="$CMD2" printf "test $F_n $TEST... " $N $CMD0 >/dev/null 2>"${te}0" & pid0=$! $CMD1 >/dev/null 2>"${te}1" & pid1=$! waittcp4port $tp 1 (echo "$da2") |$CMD2 >"${tf}2" 2>"${te}2" # this should always work rc2=$? (echo "$da3") |$CMD3 >"${tf}3" 2>"${te}3" rc3=$? kill $pid0 $pid1 $pid2 2>/dev/null; wait if ! echo "$da2" |diff - "${tf}2"; then $PRINTF "${YELLOW}phase 1 failed${NORMAL}\n" echo "$CMD0 &" cat "${te}0" echo "$CMD1 &" cat "${te}1" echo "$CMD2" cat "${te}2" numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif [ $rc3 -ne 0 ]; then $PRINTF "$FAILED:\n" echo "$CMD0 &" cat "${te}0" echo "$CMD1 &" cat "${te}1" echo "$CMD2" cat "${te}2" echo "$CMD3" cat "${te}3" numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" elif ! echo "$da2" |diff - "${tf}2"; then $PRINTF "$FAILED:\n" echo "$CMD0 &" cat "${te}0" echo "$CMD1 &" cat "${te}1" echo "$CMD2" cat "${te}2" echo "$CMD3" cat "${te}3" echo "$da2" |diff - "${tf}2" numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" elif ! echo "$da3" |diff - "${tf}3"; then $PRINTF "$FAILED:\n" echo "$CMD0 &" cat "${te}0" echo "$CMD1 &" cat "${te}1" echo "$CMD2" cat "${te}2" echo "$CMD3" cat "${te}3" echo "$da3" |diff - "${tf}3" numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" else $PRINTF "$OK\n" if [ -n "$debug" ]; then cat "${te}0" "${te}1" "${te}2" "${te}3"; fi numOK=$((numOK+1)) fi fi # NUMCOND, SO_REUSEPORT ;; esac N=$((N+1)) # Programs invoked with EXEC, nofork, and -u or -U had stdin and stdout assignment swapped. NAME=EXEC_NOFORK_UNIDIR case "$TESTS" in *%$N%*|*%functions%*|*%bugs%*|*%exec%*|*%$NAME%*) TEST="$NAME: Programs invoked with EXEC, nofork, and -u or -U had stdin and stdout assignment swapped" # invoke a simple echo command with EXEC, nofork, and -u # expected behaviour: output appears on stdout if ! eval $NUMCOND; then :; else tf="$td/test$N.stdout" te="$td/test$N.stderr" tdiff="$td/test$N.diff" da="test$N $(date) $RANDOM" CMD0="$TRACE $SOCAT $opts -u /dev/null EXEC:\"echo \\\\\\\"\\\"$da\\\"\\\\\\\"\",nofork" printf "test $F_n $TEST... " $N eval "$CMD0" >"${tf}0" 2>"${te}0" rc1=$? if echo "$da" |diff - "${tf}0" >"$tdiff"; then $PRINTF "$OK\n" numOK=$((numOK+1)) else $PRINTF "$FAILED\n" echo "$CMD0" cat "${te}0" cat "$tdiff" numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" fi fi # NUMCOND ;; esac N=$((N+1)) # OpenSSL ECDHE ciphers were introduced in socat 1.7.3.0 but in the same release # they were broken by a porting effort. This test checks if OpenSSL ECDHE works # 2019-02: this does no longer work (Ubuntu-18.04) NAME=OPENSSL_ECDHE case "$TESTS" in *%$N%*|*%functions%*|*%bugs%*|*%openssl%*|*%socket%*|*%listen%*|*%$NAME%*) TEST="$NAME: test OpenSSL ECDHE" # generate a ECDHE key, start an OpenSSL server, connect with a client and try to # pass data if ! eval $NUMCOND; then :; elif ! testfeats openssl >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}OPENSSL not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif ! openssl ciphers |grep -q '\'; then $PRINTF "test $F_n $TEST... ${YELLOW}openssl: cipher ECDHE not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" else tf="$td/test$N.stdout" te="$td/test$N.stderr" tdiff="$td/test$N.diff" da="test$N $(date) $RANDOM" #TESTSRV=./testsrvec; gentesteccert $TESTSRV TESTSRV=./testsrv; gentestcert $TESTSRV newport tcp4 CMD0="$TRACE $SOCAT $opts OPENSSL-LISTEN:$PORT,pf=ip4,$REUSEADDR,cert=$TESTSRV.crt,key=$TESTSRV.pem,verify=0 PIPE" CMD1="$TRACE $SOCAT $opts - OPENSSL-CONNECT:$LOCALHOST:$PORT,pf=ip4,cipher=ECDHE-ECDSA-AES256-GCM-SHA384,cafile=$TESTSRV.crt,verify=0" printf "test $F_n $TEST... " $N $CMD0 >/dev/null 2>"${te}0" & pid0=$! waittcp4port $PORT 1 echo "$da" |$CMD1 >"${tf}1" 2>"${te}1" rc1=$? kill $pid0 2>/dev/null; wait if [ $rc1 -ne 0 ]; then $PRINTF "$FAILED\n" echo "failure symptom: client error" >&2 echo "server and stderr:" >&2 echo "$CMD0 &" cat "${te}0" echo "client and stderr:" >&2 echo "$CMD1" cat "${te}1" numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" elif echo "$da" |diff - "${tf}1" >"$tdiff"; then $PRINTF "$OK\n" numOK=$((numOK+1)) else $PRINTF "$FAILED\n" echo "server and stderr:" >&2 echo "$CMD1" cat "${te}1" echo "client and stderr:" >&2 echo "$CMD0 &" cat "${te}0" numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" fi fi # NUMCOND ;; esac N=$((N+1)) # option ipv6-join-group "could not be used" # fixed in 1.7.3.2 NAME=USE_IPV6_JOIN_GROUP case "$TESTS" in *%$N%*|*%functions%*|*%bugs%*|*%socket%*|*%ip6%*|*%udp%*|*%udp6%*|*%dgram%*|*%multicast%*|*%$NAME%*) TEST="$NAME: is option ipv6-join-group used" # Invoke socat with option ipv6-join-group on UDP6 address. # Terminate immediately, do not transfer data. # If socat exits with 0 the test succeeds. # Up to 1.7.3.1 it failed with "1 option(s) could not be used" if ! eval $NUMCOND; then :; else tf="$td/test$N.stdout" te="$td/test$N.stderr" tdiff="$td/test$N.diff" da="test$N $(date) $RANDOM" newport udp6 CMD0="$TRACE $SOCAT $opts UDP6-RECV:$PORT,ipv6-join-group=[ff02::2]:$MCINTERFACE /dev/null" printf "test $F_n $TEST... " $N $CMD0 >/dev/null 2>"${te}0" rc0=$? if [ $rc0 -eq 0 ]; then $PRINTF "$OK\n" numOK=$((numOK+1)) else $PRINTF "$FAILED\n" echo "$CMD0" cat "${te}0" numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" fi fi # NUMCOND ;; esac N=$((N+1)) # The fix to "Make code async-signal-safe" used internally FD 3 and FD 4. # Using option fdin=3 did not pass data to executed program. NAME=DIAG_FDIN case "$TESTS" in *%$N%*|*%functions%*|*%bugs%*|*%exec%*|*%$NAME%*) TEST="$NAME: test use of fdin=3" # Use FD 3 explicitely with fdin and test if Socat passes data to executed # program if ! eval $NUMCOND; then :; else tf="$td/test$N.stdout" te="$td/test$N.stderr" tdiff="$td/test$N.diff" da="test$N $(date) $RANDOM" CMD0="$TRACE $SOCAT $opts - SYSTEM:\"cat >&3 <&4\",fdin=4,fdout=3" printf "test $F_n $TEST... " $N echo "$da" |$TRACE $SOCAT $opts - SYSTEM:"cat <&3 >&4",fdin=3,fdout=4 >${tf}0 2>"${te}0" rc0=$? if [ $rc0 -ne 0 ]; then $PRINTF "$FAILED\n" echo "$CMD0" cat "${te}0" numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" elif echo "$da" |diff - ${tf}0 >$tdiff; then $PRINTF "$OK\n" numOK=$((numOK+1)) else $PRINTF "$FAILED\n" echo "$CMD0" cat "${te}0" cat "$tdiff" numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" fi fi # NUMCOND ;; esac N=$((N+1)) NAME=SOCAT_OPT_HINT case "$TESTS" in *%$N%*|*%functions%*|*%$NAME%*) TEST="$NAME: check if merging single character options is rejected" if ! eval $NUMCOND; then :; else te="$td/test$N.stderr" CMD0="$TRACE $SOCAT $opts -vx FILE:/dev/null ECHO" printf "test $F_n $TEST... " $N $CMD0 >/dev/null 2>"${te}0" rc0=$? if [ "$rc0" = "1" ]; then $PRINTF "$OK\n" numOK=$((numOK+1)) else $PRINTF "$FAILED\n" echo "$CMD0" >&2 numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" fi fi ;; # NUMCOND esac N=$((N+1)) # test for a bug in Socat version 1.7.3.3 where # termios options of the first address were applied to the second address. NAME=TERMIOS_PH_ALL case "$TESTS" in *%$N%*|*%functions%*|*%bugs%*|*%pty%*|*%termios%*|*%$NAME%*) TEST="$NAME: are termios options applied to the correct address" # add a termios option to the first address, a tty, and have a second address # with pipe. If no error occurs the termios option was not applied to the pipe, # thus the test succeeded. if ! eval $NUMCOND; then :; else tf="$td/test$N.stdout" te="$td/test$N.stderr" tdiff="$td/test$N.diff" da="test$N $(date) $RANDOM" CMD0="$TRACE $SOCAT $opts -T 1 STDIO,echo=0 EXEC:cat 2>${te}0" echo "$CMD0" >$td/test$N.sh chmod a+x $td/test$N.sh # EXEC need not work with script (musl libc), so use SYSTEM CMD1="$TRACE $SOCAT $opts /dev/null SYSTEM:$td/test$N.sh,pty,$PTYOPTS" printf "test $F_n $TEST... " $N $CMD1 2>"${te}1" rc0=$? if [ $rc0 -eq 0 ]; then $PRINTF "$OK\n" numOK=$((numOK+1)) else $PRINTF "$FAILED\n" echo "$CMD0" cat "${te}0" echo "$CMD1" cat "${te}1" numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" fi fi # NUMCOND ;; esac N=$((N+1)) # Due to a fallback logic before calling getaddrinfo(), intended to allow use # of service (port) names with SCTP, raw socket addresses where resolved with # socket type stream, which fails for protocol 6 (TCP) # Fixed after 1.7.3.3 NAME=IP_SENDTO_6 case "$TESTS" in *%$N%*|*%functions%*|*%bugs%*|*%socket%*|*%rawip%*|*%rawip4%*|*%$NAME%*) TEST="$NAME: IP-SENDTO::6 passes getaddrinfo()" # invoke socat with address IP-SENDTO:*:6; when this does not fail with # "ai_socktype not supported", the test succeeded if ! eval $NUMCOND; then :; else tf="$td/test$N.stdout" te="$td/test$N.stderr" tdiff="$td/test$N.diff" CMD0="$TRACE $SOCAT $opts -u /dev/null IP-SENDTO:127.0.0.1:6" printf "test $F_n $TEST... " $N $CMD0 >/dev/null 2>"${te}0" if ! grep -q "ai_socktype not supported" ${te}0; then $PRINTF "$OK\n" numOK=$((numOK+1)) else $PRINTF "$FAILED\n" echo "$CMD0" cat "${te}0" numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" fi fi # NUMCOND ;; esac N=$((N+1)) # test if the multiple EOF messages are fixed NAME=MULTIPLE_EOF case "$TESTS" in *%$N%*|*%functions%*|*%bugs%*|*%unix%*|*%socket%*|*%listen%*|*%$NAME%*) TEST="$NAME: multiple EOF messages" # start two processes, connected via UNIX socket. The listener gets EOF from local address immediately; the second process then sends data. If the listener reports "socket 1 (fd .*) is at EOF" only once, the test succeeded if ! eval $NUMCOND; then :; else ts="$td/test$N.sock" tf="$td/test$N.stdout" te="$td/test$N.stderr" tdiff="$td/test$N.diff" da="test$N $(date) $RANDOM" CMD0="$TRACE $SOCAT $opts -d -d UNIX-LISTEN:$ts /dev/null" CMD1="$TRACE $SOCAT $opts -d -d - UNIX-CONNECT:$ts" printf "test $F_n $TEST... " $N $CMD0 >/dev/null 2>"${te}0" & pid0=$! waitunixport $ts 1 echo "$da" |$CMD1 >"${tf}1" 2>"${te}1" rc1=$? kill $pid0 2>/dev/null; wait if [ $(grep "socket 2 (fd .*) is at EOF" ${te}0 |wc -l) -eq 1 ]; then $PRINTF "$OK\n" numOK=$((numOK+1)) else $PRINTF "$FAILED\n" echo "$CMD0 &" echo "$CMD1" cat "${te}0" cat "${te}1" numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" fi fi # NUMCOND ;; esac N=$((N+1)) # Test for integer overflow with data transfer block size parameter NAME=BLKSIZE_INT_OVERFL case "$TESTS" in *%$N%*|*%functions%*|*%bugs%*|*%security%*|*%$NAME%*) TEST="$NAME: integer overflow with buffer size parameter" # Use a buffer size that would lead to integer overflow # Test succeeds when Socat terminates with correct error message if ! eval $NUMCOND; then :; else tf="$td/test$N.stdout" te="$td/test$N.stderr" tdiff="$td/test$N.diff" dat="$td/test$N.dat" # calculate the minimal length with integer overflow case $SIZE_T in 2) CHKSIZE=32768 ;; 4) CHKSIZE=2147483648 ;; 8) CHKSIZE=9223372036854775808 ;; 16) CHKSIZE=170141183460469231731687303715884105728 ;; esac CMD0="$TRACE $SOCAT $opts -T 1 -b $CHKSIZE /dev/null PIPE" printf "test $F_n $TEST... " $N $CMD0 >/dev/null 2>"${te}0" rc0=$? if [ $rc0 -eq 0 ]; then $PRINTF "$FAILED (rc=$rc0)\n" echo "$CMD0" cat "${te}0" numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" elif [ $rc0 -eq 1 ]; then if grep -q "buffer size option (-b) to big" "${te}0"; then $PRINTF "$OK\n" numOK=$((numOK+1)) else $PRINTF "$FAILED (rc=$rc0)\n" echo "$CMD0" cat "${te}0" numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" fi fi fi # NUMCOND ;; esac N=$((N+1)) # Test if unbalanced quoting in Socat addresses is detected NAME=UNBALANCED_QUOTE case "$TESTS" in *%$N%*|*%functions%*|*%syntax%*|*%bugs%*|*%$NAME%*) TEST="$NAME: Test fix of unbalanced quoting" # Invoke Socat with an address containing unbalanced quoting. If Socat prints # a "syntax error" message, the test succeeds if ! eval $NUMCOND; then :; else tf="$td/test$N.stdout" te="$td/test$N.stderr" tdiff="$td/test$N.diff" da="test$N $(date) $RANDOM" CMD0="$TRACE $SOCAT $opts -u FILE:$td/ab\"cd FILE:/dev/null" printf "test $F_n $TEST... " $N $CMD0 >/dev/null 2>"${te}0" if grep -q -i -e "syntax error" -e "unexpected end" "${te}0"; then $PRINTF "$OK\n" if [ "$VERBOSE" ]; then echo "$CMD0" >&2; fi if [ "$debug" ]; then cat ${te} >&2; fi numOK=$((numOK+1)) else $PRINTF "$FAILED\n" echo "$CMD0" cat "${te}0" numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" fi fi # NUMCOND ;; esac N=$((N+1)) # Currently (2020) SCTP has not found its way into main distributions # /etc/services file. A fallback mechanism has been implemented in Socat # that allows use of TCP service names when service resolution for SCTP failed. # Furthermore, older getaddrinfo() implementations to not handle SCTP as SOCK_STREAM # at all, fall back to unspecified socktype then. NAME=SCTP_SERVICENAME case "$TESTS" in *%$N%*|*%functions%*|*%socket%*|*%sctp%*|*%$NAME%*) TEST="$NAME: Service name resolution works with SCTP" # invoke socat with address SCTP4-CONNECT:$LOCALHOST:http; when this fails with # "Connection refused", or does not fail at all, the test succeeded if ! eval $NUMCOND; then :; elif ! runssctp4 >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}SCTP4 not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" else tf="$td/test$N.stdout" te="$td/test$N.stderr" tdiff="$td/test$N.diff" CMD0="$TRACE $SOCAT $opts -u /dev/null SCTP4-CONNECT:$LOCALHOST:http" printf "test $F_n $TEST... " $N $CMD0 >/dev/null 2>"${te}0" if [ $? -eq 0 ]; then $PRINTF "$OK\n" numOK=$((numOK+1)) elif grep -q "Connection refused" ${te}0; then $PRINTF "$OK\n" numOK=$((numOK+1)) else $PRINTF "$FAILED\n" echo "$CMD0" cat "${te}0" numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" fi fi # NUMCOND ;; esac N=$((N+1)) # Test the o-direct option on reading NAME=O_DIRECT case "$TESTS" in *%$N%*|*%functions%*|*%engine%*|*%file%*|*%$NAME%*) TEST="$NAME: echo via file with o-direct" # Write data to a file and read it with options o-direct (and ignoreeof) # When the data read is the same as the data written the test succeeded. if ! eval $NUMCOND; then :; elif ! testoptions o-direct >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}o-direct not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" else tf="$td/test$N.file" to="$td/test$N.stdout" te="$td/test$N.stderr" tdiff="$td/test$N.diff" da="test$N $(date) $RANDOM" $PRINTF "test $F_n $TEST... " $N CMD="$TRACE $SOCAT $opts - $tf,o-direct,ignoreeof!!$tf" echo "$da" |$CMD >"$to" 2>"$te" rc=$? if [ $rc -ne 0 ] && grep -q "Invalid argument" "$te" && [ $UNAME = Linux ]; then case $(stat -f $tf |grep "Type: [^[:space:]]*" |sed -e 's/.*\(Type: [^[:space:]]*\).*/\1/' |cut -c 7-) in #case $(stat -f $tf |grep -o "Type: [^[:space:]]*" |cut -c 7-) in ext2/ext3|xfs|reiserfs) $PRINTF "${FAILED}\n" echo "$CMD" >&2 cat "$te" >&2 numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" ;; *) $PRINTF "${YELLOW}inable file system${NORMAL}\n" numCANT=$((numCANT+1)) listCANT="$listCANT $N" ;; esac elif [ $rc -ne 0 ]; then $PRINTF "${FAILED}:\n" echo "$CMD" >&2 cat "$te" >&2 numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" elif ! echo "$da" |diff - "$to" >$tdiff; then $PRINTF "${FAILED}\n" echo "$CMD" >&2 cat "$te" >&2 cat "$tdiff" >&2 numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" else $PRINTF "$OK\n" numOK=$((numOK+1)) fi # command ok fi ;; # NUMCOND, feats esac N=$((N+1)) # test if option unlink-close removes the bind socket file NAME=UNIX_SENDTO_UNLINK case "$TESTS" in *%$N%*|*%functions%*|*%bugs%*|*%socket%*|*%unix%*|*%$NAME%*) TEST="$NAME: Option unlink-close with UNIX sendto socket" # Have a recv socket with option unlink-close=0 # and a sendto socket with option unlink-close=1 # Expected beavior: the recv socket is kept, the # sendto/bind socket is removed if ! eval $NUMCOND; then :; else tf="$td/test$N.stdout" te="$td/test$N.stderr" uns="$td/test$N.server" unc="$td/test$N.client" tdiff="$td/test$N.diff" da="test$N $(date) $RANDOM" CMD0="$TRACE $SOCAT $opts -u UNIX-RECV:$uns,unlink-close=0 GOPEN:$tf" CMD1="$TRACE $SOCAT $opts - UNIX-SENDTO:$uns,bind=$unc,unlink-close=1" printf "test $F_n $TEST... " $N $CMD0 >/dev/null 2>"${te}0" & pid0=$! waitunixport $uns 1 echo "$da" |$CMD1 >"${tf}1" 2>"${te}1" rc1=$? kill $pid0 2>/dev/null; wait if test -S $uns && ! test -S $unc; then $PRINTF "$OK\n" numOK=$((numOK+1)) else $PRINTF "$FAILED\n" echo "$CMD0 &" echo "$CMD1" ls -ld $uns $unc cat "${te}0" cat "${te}1" numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" fi fi # NUMCOND ;; esac N=$((N+1)) # test if option unlink-close removes the bind socket file NAME=UNIX_CONNECT_UNLINK case "$TESTS" in *%$N%*|*%functions%*|*%bugs%*|*%socket%*|*%unix%*|*%listen%*|*%$NAME%*) TEST="$NAME: Option unlink-close with UNIX connect socket" # Have a listen socket with option unlink-close=0 # and a connect socket with option unlink-close=1 # Expected beavior: the listen socket entry is kept, the # connect/bind socket is removed if ! eval $NUMCOND; then :; else tf="$td/test$N.stdout" te="$td/test$N.stderr" uns="$td/test$N.server" unc="$td/test$N.client" tdiff="$td/test$N.diff" da="test$N $(date) $RANDOM" CMD0="$TRACE $SOCAT $opts -u UNIX-LISTEN:$uns,unlink-close=0 GOPEN:$tf" CMD1="$TRACE $SOCAT $opts - UNIX-CONNECT:$uns,bind=$unc,unlink-close=1" printf "test $F_n $TEST... " $N $CMD0 >/dev/null 2>"${te}0" & pid0=$! waitunixport $uns 1 echo "$da" |$CMD1 >"${tf}1" 2>"${te}1" rc1=$? kill $pid0 2>/dev/null; wait if test -S $uns && ! test -S $unc; then $PRINTF "$OK\n" numOK=$((numOK+1)) else $PRINTF "$FAILED\n" echo "$CMD0 &" echo "$CMD1" ls -ld $uns $unc cat "${te}0" cat "${te}1" numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" fi fi # NUMCOND ;; esac N=$((N+1)) # test the DTLS client feature NAME=OPENSSL_DTLS_CLIENT case "$TESTS" in *%$N%*|*%functions%*|*%openssl%*|*%dtls%*|*%udp%*|*%udp4%*|*%ip4%*|*%$NAME%*) TEST="$NAME: OpenSSL DTLS client" # Run openssl s_server in DTLS mode, wrapped into a simple Socat echoing command. # Start a Socat DTLS client, send data to server and check if reply is received. if ! eval $NUMCOND; then :; elif ! a=$(testfeats ip4 udp openssl); then $PRINTF "test $F_n $TEST... ${YELLOW}Feature $a not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif ! a=$(testaddrs openssl-dtls-client); then $PRINTF "test $F_n $TEST... ${YELLOW}Address $a not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif ! runsip4 >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}IPv4 not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif ! type openssl >/dev/null 2>&1; then $PRINTF "test $F_n $TEST... ${YELLOW}openssl executable not found${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" else gentestcert testsrv tf="$td/test$N.stdout" te="$td/test$N.stderr" tdiff="$td/test$N.diff" #set -vx da="test$N $(date) $RANDOM" init_openssl_s_server newport udp4 CMD1="$TRACE openssl s_server $OPENSSL_S_SERVER_4 $OPENSSL_S_SERVER_DTLS -accept $PORT -quiet $OPENSSL_S_SERVER_NO_IGN_EOF -cert testsrv.pem" CMD="$TRACE $SOCAT $opts -T 3 - OPENSSL-DTLS-CLIENT:$LOCALHOST:$PORT,pf=ip4,verify=0,$SOCAT_EGD" printf "test $F_n $TEST... " $N ( sleep 2; echo "$da"; sleep 1 ) |$CMD1 2>"${te}1" & pid1=$! # background process id waitudp4port $PORT $CMD >$tf 2>"$te" kill $pid1 2>/dev/null; wait 2>/dev/null if ! echo "$da" |diff - "$tf" >"$tdiff"; then $PRINTF "$FAILED: $TRACE $SOCAT:\n" echo "$CMD1 &" cat "${te}1" echo "$CMD" cat "$te" cat "$tdiff" numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" else $PRINTF "$OK\n" if [ -n "$debug" ]; then cat "${te}1" "$te"; fi numOK=$((numOK+1)) fi fi ;; # NUMCOND, feats esac N=$((N+1)) # test the DTLS server feature NAME=OPENSSL_DTLS_SERVER case "$TESTS" in *%$N%*|*%functions%*|*%openssl%*|*%dtls%*|*%udp%*|*%udp4%*|*%ip4%*|*%socket%*|*%$NAME%*) TEST="$NAME: OpenSSL DTLS server" # Run a socat OpenSSL DTLS server with echo function # Start an OpenSSL s_client, send data and check if repley is received. if ! eval $NUMCOND; then :; elif ! a=$(testfeats ip4 udp openssl) >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}$a not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif ! a=$(testaddrs openssl-dtls-server); then $PRINTF "test $F_n $TEST... ${YELLOW}$a not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif ! runsip4 >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}IPv4 not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif ! type openssl >/dev/null 2>&1; then $PRINTF "test $F_n $TEST... ${YELLOW}openssl executable not found${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif [[ $(openssl version |awk '{print($2);}') =~ 0.9.8[a-c] ]]; then $PRINTF "test $F_n $TEST... ${YELLOW}openssl s_client might hang${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" else gentestcert testsrv tf="$td/test$N.stdout" te="$td/test$N.stderr" tdiff="$td/test$N.diff" da="test$N $(date) $RANDOM" init_openssl_s_client newport udp4 CMD1="$TRACE $SOCAT $opts OPENSSL-DTLS-SERVER:$PORT,$REUSEADDR,cert=testsrv.crt,key=testsrv.key,verify=0 PIPE" CMD="openssl s_client $OPENSSL_S_CLIENT_4 -host $LOCALHOST -port $PORT $OPENSSL_S_CLIENT_DTLS" printf "test $F_n $TEST... " $N $CMD1 >/dev/null 2>"${te}1" & pid1=$! waitudp4port $PORT 1 ( echo "$da"; psleep 0.1 ) |$CMD 2>"$te" |grep "$da" >"$tf" rc=$? kill $pid1 2>/dev/null; wait if echo "$da" |diff - $tf >"$tdiff"; then $PRINTF "$OK\n" numOK=$((numOK+1)) else $PRINTF "$FAILED\n" echo "$CMD1 &" cat "${te}1" echo "$CMD" cat "$te" cat "$tdiff" numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" fi fi # NUMCOND ;; esac N=$((N+1)) NAME=OPENSSL_SERVERALTAUTH case "$TESTS" in *%$N%*|*%functions%*|*%openssl%*|*%tcp%*|*%tcp4%*|*%ip4%*|*%listen%*|*%$NAME%*) TEST="$NAME: OpenSSL server authentication with SubjectAltName (hostname)" if ! eval $NUMCOND; then :; elif ! testfeats openssl >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}OPENSSL not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif ! testfeats listen tcp ip4 >/dev/null || ! runsip4 >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}TCP/IPv4 not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" else gentestaltcert testalt tf="$td/test$N.stdout" te="$td/test$N.stderr" tdiff="$td/test$N.diff" da="test$N $(date) $RANDOM" newport tcp4 CMD0="$TRACE $SOCAT $opts OPENSSL-LISTEN:$PORT,pf=ip4,$REUSEADDR,$SOCAT_EGD,cert=testalt.crt,key=testalt.key,verify=0 pipe" CMD1="$TRACE $SOCAT $opts - OPENSSL:$LOCALHOST:$PORT,pf=ip4,verify=1,cafile=testalt.crt,$SOCAT_EGD" printf "test $F_n $TEST... " $N eval "$CMD0 2>\"${te}0\" &" pid=$! # background process id waittcp4port $PORT echo "$da" |$CMD1 >$tf 2>"${te}1" if ! echo "$da" |diff - "$tf" >"$tdiff"; then $PRINTF "$FAILED: $TRACE $SOCAT:\n" echo "$CMD0 &" >&2 cat "${te}0" >&2 echo "$CMD1" >&2 cat "${te}1" >&2 cat "$tdiff" >&2 numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" else $PRINTF "$OK\n" if [ -n "$debug" ]; then cat "${te}1" "${te}2"; fi numOK=$((numOK+1)) fi kill $pid 2>/dev/null wait fi ;; # NUMCOND, feats esac N=$((N+1)) NAME=OPENSSL_SERVERALTIP4AUTH case "$TESTS" in *%$N%*|*%functions%*|*%openssl%*|*%tcp%*|*%tcp4%*|*%ip4%*|*%listen%*|*%$NAME%*) TEST="$NAME: OpenSSL server authentication with SubjectAltName (IPv4 address)" if ! eval $NUMCOND; then :; elif ! testfeats openssl >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}OPENSSL not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif ! testfeats listen tcp ip4 openssl >/dev/null || ! runsip4 >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}TCP/IPv4 not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" else gentestaltcert testalt tf="$td/test$N.stdout" te="$td/test$N.stderr" tdiff="$td/test$N.diff" da="test$N $(date) $RANDOM" newport tcp4 CMD0="$TRACE $SOCAT $opts OPENSSL-LISTEN:$PORT,$REUSEADDR,$SOCAT_EGD,cert=testalt.crt,key=testalt.key,verify=0 pipe" CMD1="$TRACE $SOCAT $opts - OPENSSL:127.0.0.1:$PORT,verify=1,cafile=testalt.crt,$SOCAT_EGD" printf "test $F_n $TEST... " $N eval "$CMD0 2>\"${te}0\" &" pid=$! # background process id waittcp4port $PORT echo "$da" |$CMD1 >$tf 2>"${te}1" if ! echo "$da" |diff - "$tf" >"$tdiff"; then $PRINTF "$FAILED: $TRACE $SOCAT:\n" echo "$CMD0 &" >&2 cat "${te}0" >&2 echo "$CMD1" >&2 cat "${te}1" >&2 cat "$tdiff" >&2 numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" else $PRINTF "$OK\n" if [ -n "$debug" ]; then cat "${te}1" "${te}2"; fi numOK=$((numOK+1)) fi kill $pid 2>/dev/null wait fi ;; # NUMCOND, feats esac N=$((N+1)) NAME=OPENSSL_SERVERALTIP6AUTH case "$TESTS" in *%$N%*|*%functions%*|*%openssl%*|*%tcp%*|*%tcp6%*|*%ip6%*|*%listen%*|*%$NAME%*) TEST="$NAME: OpenSSL server authentication with SubjectAltName (IPv6 address)" if ! eval $NUMCOND; then :; elif ! testfeats openssl >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}OPENSSL not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif ! testfeats listen tcp ip6 openssl >/dev/null || ! runsip6 >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}TCP/IPv6 not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" else gentestaltcert testalt tf="$td/test$N.stdout" te="$td/test$N.stderr" tdiff="$td/test$N.diff" da="test$N $(date) $RANDOM" newport tcp6 CMD0="$TRACE $SOCAT $opts OPENSSL-LISTEN:$PORT,pf=ip6,$REUSEADDR,$SOCAT_EGD,cert=testalt.crt,key=testalt.key,verify=0 pipe" CMD1="$TRACE $SOCAT $opts - OPENSSL:[::1]:$PORT,verify=1,cafile=testalt.crt,$SOCAT_EGD" printf "test $F_n $TEST... " $N eval "$CMD0 2>\"${te}0\" &" pid=$! # background process id waittcp6port $PORT echo "$da" |$CMD1 >$tf 2>"${te}1" if ! echo "$da" |diff - "$tf" >"$tdiff"; then $PRINTF "$FAILED: $TRACE $SOCAT:\n" echo "$CMD0 &" >&2 cat "${te}0" >&2 echo "$CMD1" >&2 cat "${te}1" >&2 cat "$tdiff" >&2 numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" else $PRINTF "$OK\n" if [ -n "$debug" ]; then cat "${te}1" "${te}2"; fi numOK=$((numOK+1)) fi kill $pid 2>/dev/null wait fi ;; # NUMCOND, feats esac N=$((N+1)) # Test the -r and -R options NAME=OPTION_RAW_DUMP case "$TESTS" in *%$N%*|*%functions%*|*%option%*|*%$NAME%*) TEST="$NAME: raw dump of transferred data" # Start Socat transferring data from left named pipe to right and from right # pipe to left, use options -r and -R, and check if dump files contain correct # data if ! eval $NUMCOND; then :; elif [ $($SOCAT -h |grep -e ' -[rR] ' |wc -l) -lt 2 ]; then $PRINTF "test $F_n $TEST... ${YELLOW}Options -r, -R not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" else tf="$td/test$N.stdout" te="$td/test$N.stderr" tp1="$td/test$N.pipe1" tp2="$td/test$N.pipe2" tr1="$td/test$N.raw1" tr2="$td/test$N.raw2" tdiff1="$td/test$N.diff1" tdiff2="$td/test$N.diff2" da1="test$N $(date) $RANDOM" da2="test$N $(date) $RANDOM" CMD0="$TRACE $SOCAT $opts -r $tr1 -R $tr2 PIPE:$tp1!!/dev/null PIPE:$tp2!!/dev/null" printf "test $F_n $TEST... " $N $CMD0 >/dev/null 2>"${te}0" & pid0=$! waitfile $tp1 1 echo "$da1" >$tp1 waitfile $tp2 1 echo "$da2" >$tp2 sleep 1 kill $pid0 2>/dev/null; wait if ! echo "$da1" |diff - $tr1 >$tdiff1 || ! echo "$da2" |diff - $tr2 >$tdiff2; then $PRINTF "$FAILED\n" echo "$CMD0 &" >&2 cat "${te}0" >&2 echo "Left-to-right:" >&2 cat $tdiff1 >&2 echo "Right-to-left:" >&2 cat $tdiff2 >&2 numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" else $PRINTF "$OK\n" numOK=$((numOK+1)) fi fi # NUMCOND ;; esac N=$((N+1)) # Test the OpenSSL SNI feature NAME=OPENSSL_SNI case "$TESTS" in *%$N%*|*%functions%*|*%socket%*|*%openssl%*|*%internet%*|*%listen%*|*%$NAME%*) TEST="$NAME: Test the OpenSSL SNI feature" # Connect to a server that is known to use SNI. Use an SNI name, not the # certifications default name. When the TLS connection is established # the test succeeded. SNISERVER=badssl.com if ! eval $NUMCOND; then :; elif ! testaddrs openssl >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}OPENSSL not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif ! feat=$(testoptions openssl-snihost); then $PRINTF "test $F_n $TEST... ${YELLOW}$feat not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif [ -z "$INTERNET" ]; then $PRINTF "test $F_n $TEST... ${YELLOW}use test.sh option -internet${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" else tf="$td/test$N.stdout" te="$td/test$N.stderr" tdiff="$td/test$N.diff" da="test$N $(date) $RANDOM" CMD0="$TRACE $SOCAT $opts FILE:/dev/null OPENSSL-CONNECT:$SNISERVER:443,pf=ip4" printf "test $F_n $TEST... " $N $CMD0 >/dev/null 2>"${te}0" rc0=$? if [ $rc0 -eq 0 ]; then $PRINTF "$OK\n" numOK=$((numOK+1)) else $PRINTF "$FAILED\n" echo "$CMD0" >&2 cat "${te}0" >&2 numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" fi fi # NUMCOND ;; esac N=$((N+1)) # Test the openssl-no-sni option NAME=OPENSSL_NO_SNI case "$TESTS" in *%$N%*|*%functions%*|*%socket%*|*%openssl%*|*%internet%*|*%listen%*|*%$NAME%*) TEST="$NAME: Test the openssl-no-sni option" # Connect to a server that is known to use SNI. Use an SNI name, not the # certifications default name, and use option openssl-no-sni. # When the TLS connection failed the test succeeded. # Please note that this test is only relevant when test OPENSSL_SNI succeeded. SNISERVER=badssl.com if ! eval $NUMCOND; then :; elif ! testaddrs openssl >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}OPENSSL not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif ! feat=$(testoptions openssl-no-sni); then $PRINTF "test $F_n $TEST... ${YELLOW}$feat not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif [ -z "$INTERNET" ]; then $PRINTF "test $F_n $TEST... ${YELLOW}use test.sh option -internet${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" else tf="$td/test$N.stdout" te="$td/test$N.stderr" tdiff="$td/test$N.diff" da="test$N $(date) $RANDOM" CMD0="$TRACE $SOCAT $opts FILE:/dev/null OPENSSL-CONNECT:$SNISERVER:443,openssl-no-sni" printf "test $F_n $TEST... " $N $CMD0 >/dev/null 2>"${te}0" rc0=$? if [ $rc0 -ne 0 ]; then $PRINTF "$OK\n" numOK=$((numOK+1)) else $PRINTF "$FAILED\n" echo "$CMD0" >&2 cat "${te}0" >&2 numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" fi fi # NUMCOND ;; esac N=$((N+1)) # Test the accept-timeout (listen-timeout) address option NAME=ACCEPTTIMEOUT case "$TESTS" in *%$N%*|*%functions%*|*%ip4%*|*%ipapp%*|*%tcp%*|*%listen%*|*%timeout%*|*%$NAME%*) TEST="$NAME: test the accept-timeout option" if ! eval $NUMCOND; then :; elif ! feat=$(testaddrs tcp); then $PRINTF "test $F_n $TEST... ${YELLOW}$(echo "$feat"| tr 'a-z' 'A-Z') not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif ! feat=$(testoptions accept-timeout); then $PRINTF "test $F_n $TEST... ${YELLOW}$(echo "$feat"| tr 'a-z' 'A-Z') not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" else # Just start a process with accept-timeout 1s and check if it still runs 2s later # but before this, we test if the process waits at all te1="$td/test$N.stderr1" tk1="$td/test$N.kill1" te2="$td/test$N.stderr2" tk2="$td/test$N.kill2" $PRINTF "test $F_n $TEST... " $N # First, try to make socat hang and see if it can be killed newport tcp4 CMD1="$TRACE $SOCAT $opts TCP-LISTEN:$PORT,reuseaddr PIPE" $CMD1 >"$te1" 2>&1 "$tk1"; then $PRINTF "${YELLOW}does not hang${NORMAL}\n" echo $CMD1 >&2 cat "$te1" >&2 cat "$tk1" >&2 numCANT=$((numCANT+1)) listCANT="$listCANT $N" else # Second, set accept-timeout and see if socat exits before kill CMD2="$TRACE $SOCAT $opts TCP-LISTEN:$PORT,reuseaddr,accept-timeout=1 PIPE" $CMD2 >"$te2" 2>&1 "$tk2"; then $PRINTF "$FAILED\n" echo "$CMD2" >&2 cat "$te2" >&2 cat "$tk2" >&2 numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" else $PRINTF "$OK\n" numOK=$((numOK+1)) fi fi wait fi ;; # testaddrs, NUMCOND esac N=$((N+1)) # Test the modified UDP-DATAGRAM address: Now it ignores peerport by default NAME=UDP_DATAGRAM_PEERPORT case "$TESTS" in *%$N%*|*%functions%*|*%udp%*|*%socket%*|*%$NAME%*) TEST="$NAME: test UDP-DATAGRAM ignoring peerport" # A UDP-DATAGRAM address bound to PORT has defined peer on PORT+1 # From another Socat instance we send a packet to PORT but with source port # PORT+2. The first instance should accept the packet if ! eval $NUMCOND; then : elif [ $(echo $E "$SOCAT_VERSION\n1.7.3.4" |sort -n |tail -n 1) = 1.7.3.4 ]; then $PRINTF "test $F_n $TEST... ${YELLOW}Only with Socat 1.7.4.0 or higher${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" else tf="$td/test$N.stdout" te="$td/test$N.stderr" tdiff="$td/test$N.diff" da="test$N $(date) $RANDOM" newport udp4; PORT1=$PORT newport udp4; PORT2=$PORT newport udp4; PORT3=$PORT CMD0="$TRACE $SOCAT $opts -u UDP-DATAGRAM:$LOCALHOST:$PORT2,bind=:$PORT1 -" CMD1="$TRACE $SOCAT $opts -u - UDP-DATAGRAM:$LOCALHOST:$PORT1,bind=:$PORT3" printf "test $F_n $TEST... " $N $CMD0 >${tf}0 2>"${te}0" & pid0=$! waitudp4port $PORT1 1 echo "$da" |$CMD1 >"${tf}1" 2>"${te}1" rc1=$? psleep 0.1 kill $pid0 2>/dev/null; wait if [ -f ${tf}0 ] && echo "$da" |diff - ${tf}0 >$tdiff; then $PRINTF "$OK\n" numOK=$((numOK+1)) else $PRINTF "$FAILED\n" echo "$CMD0 &" >&2 cat "${te}0" >&2 echo "$CMD1" >&2 cat "${te}1" >&2 cat "${tdiff}" >&2 numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" fi fi # NUMCOND ;; esac N=$((N+1)) # Test the proxy-authorization-file option NAME=PROXYAUTHFILE case "$TESTS" in *%$N%*|*%functions%*|*%proxyconnect%*|*%proxy%*|*%tcp%*|*%tcp4%*|*%ip4%*|*%listen%*|*%$NAME%*) TEST="$NAME: proxy-authorization-file option" if ! eval $NUMCOND; then :; elif ! testfeats proxy >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}PROXY not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif ! testfeats listen tcp ip4 >/dev/null || ! runsip4 >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}TCP/IPv4 not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif ! testoptions proxy-authorization-file >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}Option proxy-authorization-file not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" else ta="$td/test$N.auth" tf="$td/test$N.stdout" te="$td/test$N.stderr" tdiff="$td/test$N.diff" da="test$N $(date) $RANDOM"; da="$da$($ECHO '\r')" newport tcp4 CMD0="{ echo -e \"HTTP/1.0 200 OK\\n\"; sleep 2; } |$TRACE $SOCAT $opts - TCP4-L:$PORT,$REUSEADDR,crlf" CMD1="$TRACE $SOCAT $opts FILE:/dev/null PROXY-CONNECT:$LOCALHOST:127.0.0.1:1000,pf=ip4,proxyport=$PORT,proxy-authorization-file=$ta" printf "test $F_n $TEST... " $N echo "user:s3cr3t" >$ta eval "$CMD0 >${tf}0 2>${te}0 &" pid0=$! # background process id waittcp4port $PORT 1 $CMD1 >"${tf}1" 2>"${te}1" rc1=$? kill $pid0 2>/dev/null wait $pid0 if [ $rc1 -ne 0 ]; then $PRINTF "$FAILED\n" echo "$CMD0 &" >&2 cat "${te}0" >&2 echo "$CMD1" >&2 cat "${te}1" >&2 cat "${tf}0" >&2 numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" elif ! grep -q '^Proxy-authorization: Basic dXNlcjpzM2NyM3QK$' ${tf}0; then $PRINTF "$FAILED:\n" echo "$CMD0 &" >&2 cat "${te}0" >&2 echo "$CMD1" >&2 cat "${te}1" >&2 cat "${tf}0" >&2 echo "Authorization string not in client request" >&2 numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" else $PRINTF "$OK\n" if [ -n "$debug" ]; then cat "${te}1" "${te}2"; fi numOK=$((numOK+1)) fi kill $pid 2>/dev/null wait fi ;; # NUMCOND, feats esac N=$((N+1)) # Test communication via vsock loopback socket NAME=VSOCK_ECHO case "$TESTS" in *%$N%*|*%functions%*|*%vsock%*|*%socket%*|*%listen%*|*%$NAME%*) TEST="$NAME: test communication via VSOCK loopback socket" # Start a listening echo server # Connect with a client, send data and compare reply with original data if ! eval $NUMCOND; then :; elif ! fea=$(testfeats VSOCK); then $PRINTF "test $F_n $TEST... ${YELLOW}$fea not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" else tf="$td/test$N.stdout" te="$td/test$N.stderr" tdiff="$td/test$N.diff" da="test$N $(date) $RANDOM" #newport vsock # nope CMD0="$TRACE $SOCAT $opts VSOCK-LISTEN:$PORT PIPE" CMD1="$TRACE $SOCAT $opts - VSOCK-CONNECT:1:$PORT" printf "test $F_n $TEST... " $N $CMD0 >/dev/null 2>"${te}0" & pid0=$! sleep 1 echo "$da" |$CMD1 >"${tf}1" 2>"${te}1" rc1=$? kill $pid0 2>/dev/null; wait if [ $rc1 -ne 0 ] && [ "$UNAME" != Linux ]; then $PRINTF "${YELLOW}works only on Linux?${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif [ $rc1 -ne 0 ] && [ "$UNAME" = Linux ] && ! [[ $UNAME_R =~ ^[6-9]\.* ]] && ! [[ $UNAME_R =~ ^5\.[6-]\.* ]] && ! [[ $UNAME_R =~ ^5\.[1-9][0-9].* ]]; then $PRINTF "${YELLOW}works only on Linux from 5.6${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif grep -q "No such device" "${te}1"; then $PRINTF "${YELLOW}Loopback does not work${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif [ $rc1 -ne 0 ]; then $PRINTF "$FAILED\n" echo "$CMD0 &" >&2 cat "${te}0" >&2 echo "$CMD1" >&2 cat "${te}1" >&2 numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" elif echo "$da" |diff - ${tf}1 >${tdiff}$N; then $PRINTF "$OK\n" numOK=$((numOK+1)) else $PRINTF "$FAILED\n" echo "$CMD0 &" >&2 cat "${te}0" >&2 echo "$CMD1" >&2 cat "${te}1" >&2 numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" fi fi # NUMCOND ;; esac N=$((N+1)) # File transfer with OpenSSL stream connection was incomplete # Test file transfer from client to server NAME=OPENSSL_STREAM_TO_SERVER case "$TESTS" in *%$N%*|*%functions%*|*%bugs%*|*%openssl%*|*%tcp%*|*%socket%*|*%listen%*|*%$NAME%*) TEST="$NAME: OpenSSL stream from client to server" # Start a unidirectional OpenSSL server and stream receiver # Start a unidirectional OpenSSL client that connects to the server and sends # data # Test succeeded when the data received and stored by server is the same as # sent by the client if ! eval $NUMCOND; then :; elif ! a=$(testfeats ip4 tcp openssl); then $PRINTF "test $F_n $TEST... ${YELLOW}$a not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif ! a=$(testaddrs openssl-listen openssl-connect); then $PRINTF "test $F_n $TEST... ${YELLOW}$a not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif ! runsip4 >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}IPv4 not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" else gentestcert testsrv ti="$td/test$N.datain" to="$td/test$N.dataout" te="$td/test$N.stderr" tdiff="$td/test$N.diff" da="test$N $(date) $RANDOM" newport tcp4 CMD0="$TRACE $SOCAT $opts -u OPENSSL-LISTEN:$PORT,pf=ip4,$REUSEADDR,cert=testsrv.pem,verify=0 CREAT:$to" CMD1="$TRACE $SOCAT $opts -u OPEN:$ti OPENSSL-CONNECT:$LOCALHOST:$PORT,pf=ip4,cafile=testsrv.crt" printf "test $F_n $TEST... " $N i=0; while [ $i -lt 100000 ]; do printf "%9u %9u %9u %9u %9u %9u %9u %9u %9u %9u\n" $i $i $i $i $i $i $i $i $i $i; let i+=100; done >$ti $CMD0 >/dev/null 2>"${te}0" & pid0=$! waittcp4port $PORT 1 $CMD1 >"${tf}1" 2>"${te}1" rc1=$? usleep $MICROS kill $pid0 2>/dev/null; wait if [ $rc1 -ne 0 ]; then $PRINTF "$FAILED\n" echo "$CMD0 &" >&2 cat "${te}0" >&2 echo "$CMD1" >&2 cat "${te}1" >&2 numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" elif diff $ti $to >$tdiff; then $PRINTF "$OK\n" numOK=$((numOK+1)) else $PRINTF "$FAILED\n" echo "$CMD0 &" >&2 cat "${te}0" >&2 echo "$CMD1" >&2 cat "${te}1" >&2 echo "diff:" >&2 head -n 2 $tdiff >&2 echo ... >&2 numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" fi fi # NUMCOND ;; esac N=$((N+1)) # File transfer with OpenSSL stream connection was incomplete # Test file transfer from server to client NAME=OPENSSL_STREAM_TO_CLIENT case "$TESTS" in *%$N%*|*%functions%*|*%bugs%*|*%openssl%*|*%tcp%*|*%socket%*|*%listen%*|*%$NAME%*) TEST="$NAME: OpenSSL stream from server to client" # Start a unidirectional OpenSSL server and stream sender # Start a unidirectional OpenSSL client that connects to the server and receives # data # Test succeeded when the data received and stored by client is the same as # sent by the server if ! eval $NUMCOND; then :; elif ! a=$(testfeats ip4 tcp openssl); then $PRINTF "test $F_n $TEST... ${YELLOW}$a not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif ! a=$(testaddrs openssl-listen openssl-connect); then $PRINTF "test $F_n $TEST... ${YELLOW}$a not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif ! runsip4 >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}IPv4 not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" else gentestcert testsrv ti="$td/test$N.datain" to="$td/test$N.dataout" te="$td/test$N.stderr" tdiff="$td/test$N.diff" da="test$N $(date) $RANDOM" newport tcp4 CMD0="$TRACE $SOCAT $opts -U OPENSSL-LISTEN:$PORT,pf=ip4,$REUSEADDR,cert=testsrv.pem,verify=0 OPEN:$ti" CMD1="$TRACE $SOCAT $opts -u OPENSSL-CONNECT:$LOCALHOST:$PORT,pf=ip4,cafile=testsrv.crt CREAT:$to" printf "test $F_n $TEST... " $N i=0; while [ $i -lt 100000 ]; do printf "%9u %9u %9u %9u %9u %9u %9u %9u %9u %9u\n" $i $i $i $i $i $i $i $i $i $i; let i+=100; done >$ti $CMD0 >/dev/null 2>"${te}0" & pid0=$! waittcp4port $PORT 1 $CMD1 >"${tf}1" 2>"${te}1" rc1=$? usleep $MICROS kill $pid0 2>/dev/null; wait if [ $rc1 -ne 0 ]; then $PRINTF "$FAILED\n" echo "$CMD0 &" >&2 cat "${te}0" >&2 echo "$CMD1" >&2 cat "${te}1" >&2 numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" elif diff $ti $to >$tdiff; then $PRINTF "$OK\n" numOK=$((numOK+1)) else $PRINTF "$FAILED\n" echo "$CMD0 &" >&2 cat "${te}0" >&2 echo "$CMD1" >&2 cat "${te}1" >&2 echo "diff:" >&2 head -n 2 $tdiff >&2 echo ... >&2 numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" fi fi # NUMCOND ;; esac N=$((N+1)) # Test file transfer from client to server using DTLS NAME=OPENSSL_DTLS_TO_SERVER case "$TESTS" in *%$N%*|*%functions%*|*%bugs%*|*%openssl%*|*%dtls%*|*%udp%*|*%socket%*|*%listen%*|*%$NAME%*) TEST="$NAME: OpenSSL DTLS transfer from client to server" # Start a unidirectional OpenSSL DTLS server/receiver # Start a unidirectional OpenSSL DTLS client that connects to the server and # sends data # Test succeeded when the data received and stored by server is the same as # sent by the client if ! eval $NUMCOND; then :; elif ! a=$(testfeats ip4 udp openssl); then $PRINTF "test $F_n $TEST... ${YELLOW}$a not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif ! a=$(testaddrs openssl-dtls-listen openssl-dtls-connect); then $PRINTF "test $F_n $TEST... ${YELLOW}$a not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif ! runsip4 >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}IPv4 not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif [[ $(openssl version |awk '{print($2);}') =~ 0.9.8[a-c] ]]; then $PRINTF "test $F_n $TEST... ${YELLOW}openssl s_client might hang${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" else gentestcert testsrv ti="$td/test$N.datain" to="$td/test$N.dataout" te="$td/test$N.stderr" tdiff="$td/test$N.diff" da="test$N $(date) $RANDOM" newport udp4 CMD0="$TRACE $SOCAT $opts -u OPENSSL-DTLS-LISTEN:$PORT,pf=ip4,cert=testsrv.pem,verify=0 CREAT:$to" CMD1="$TRACE $SOCAT $opts -u OPEN:$ti OPENSSL-DTLS-CONNECT:$LOCALHOST:$PORT,pf=ip4,cafile=testsrv.crt" printf "test $F_n $TEST... " $N i=0; while [ $i -lt $((2*8192)) ]; do printf "%9u %9u %9u %9u %9u %9u %9u %9u %9u %9u\n" $i $i $i $i $i $i $i $i $i $i; let i+=100; done >$ti $CMD0 >/dev/null 2>"${te}0" & pid0=$! waitudp4port $PORT 1 $CMD1 >"${tf}1" 2>"${te}1" rc1=$? usleep $MICROS kill $pid0 2>/dev/null; wait if [ $rc1 -ne 0 ]; then $PRINTF "$FAILED\n" echo "$CMD0 &" >&2 cat "${te}0" >&2 echo "$CMD1" >&2 cat "${te}1" >&2 numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" elif diff $ti $to >$tdiff; then $PRINTF "$OK\n" numOK=$((numOK+1)) else $PRINTF "$FAILED\n" echo "$CMD0 &" >&2 cat "${te}0" >&2 echo "$CMD1" >&2 cat "${te}1" >&2 echo "diff:" >&2 head -n 2 $tdiff >&2 echo ... >&2 numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" fi fi # NUMCOND ;; esac N=$((N+1)) # Test file transfer from server to client using DTLS NAME=OPENSSL_DTLS_TO_CLIENT case "$TESTS" in *%$N%*|*%functions%*|*%bugs%*|*%openssl%*|*%dtls%*|*%udp%*|*%socket%*|*%listen%*|*%$NAME%*) TEST="$NAME: OpenSSL DTLS transfer from server to client" # Start a unidirectional OpenSSL DTLS server/sender # Start a unidirectional OpenSSL DTLS client that connects to the server and # receives data # Test succeeded when the data received and stored by client is the same as # sent by the server if ! eval $NUMCOND; then :; elif ! a=$(testfeats ip4 udp openssl); then $PRINTF "test $F_n $TEST... ${YELLOW}$a not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif ! a=$(testaddrs openssl-dtls-listen openssl-dtls-connect); then $PRINTF "test $F_n $TEST... ${YELLOW}$a not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif ! runsip4 >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}IPv4 not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif [[ $(openssl version |awk '{print($2);}') =~ 0.9.8[a-c] ]]; then $PRINTF "test $F_n $TEST... ${YELLOW}openssl s_client might hang${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" else gentestcert testsrv ti="$td/test$N.datain" to="$td/test$N.dataout" te="$td/test$N.stderr" tdiff="$td/test$N.diff" da="test$N $(date) $RANDOM" newport udp4 CMD0="$TRACE $SOCAT $opts -U OPENSSL-DTLS-LISTEN:$PORT,pf=ip4,cert=testsrv.pem,verify=0 OPEN:$ti" CMD1="$TRACE $SOCAT $opts -u OPENSSL-DTLS-CONNECT:$LOCALHOST:$PORT,pf=ip4,cafile=testsrv.crt CREAT:$to" printf "test $F_n $TEST... " $N i=0; while [ $i -lt $((2*8192)) ]; do printf "%9u %9u %9u %9u %9u %9u %9u %9u %9u %9u\n" $i $i $i $i $i $i $i $i $i $i; let i+=100; done >$ti $CMD0 >/dev/null 2>"${te}0" & pid0=$! waitudp4port $PORT 1 $CMD1 >"${tf}1" 2>"${te}1" rc1=$? usleep $MICROS kill $pid0 2>/dev/null; wait if [ $rc1 -ne 0 ]; then $PRINTF "$FAILED\n" echo "$CMD0 &" >&2 cat "${te}0" >&2 echo "$CMD1" >&2 cat "${te}1" >&2 numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" elif diff $ti $to >$tdiff; then $PRINTF "$OK\n" numOK=$((numOK+1)) else $PRINTF "$FAILED\n" echo "$CMD0 &" >&2 cat "${te}0" >&2 echo "$CMD1" >&2 cat "${te}1" >&2 echo "diff:" >&2 head -n 2 $tdiff >&2 echo ... >&2 numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" fi fi # NUMCOND ;; esac N=$((N+1)) # Test if the problem with overlapping internal parameters of sockets and # openssl are fixed NAME=OPENSSL_PARA_OVERLAP case "$TESTS" in *%$N%*|*%functions%*|*%bugs%*|*%socket%*|*%ip4%*|*%tcp%*|*%tcp4%*|*%openssl%*|*%listen%*|*%$NAME%*) TEST="$NAME: test diverse of socket,openssl params" # That bug had not many effects; the simplest to use is possible SIGSEGV on # close when option accept-timeout with fractional seconds was applied if ! eval $NUMCOND; then :; elif ! testfeats openssl >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}OPENSSL not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif ! type openssl >/dev/null 2>&1; then $PRINTF "test $F_n $TEST... ${YELLOW}openssl executable not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif ! testfeats tcp ip4 >/dev/null || ! runsip4 >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}TCP/IPv4 not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" else gentestcert testsrv tf="$td/test$N.stdout" te="$td/test$N.stderr" tdiff="$td/test$N.diff" trc0="$td/test$N.rc0" da="test$N $(date) $RANDOM" newport tcp4 CMD0="$TRACE $SOCAT $opts OPENSSL-LISTEN:$PORT,pf=ip4,$REUSEADDR,accept-timeout=4.5,$SOCAT_EGD,cert=testsrv.crt,key=testsrv.key,verify=0 PIPE" CMD1="$TRACE $SOCAT $opts /dev/null OPENSSL-CONNECT:$LOCALHOST:$PORT,pf=ip4,verify=0,$SOCAT_EGD" printf "test $F_n $TEST... " $N $CMD0 >/dev/null 2>"${te}0" || echo $? >$trc0 & pid0=$! waittcp4port $PORT 1 $CMD1 >"${tf}1" 2>"${te}1" rc1=$? psleep 0.5 kill $pid0 2>/dev/null; wait if [ $rc1 -ne 0 ]; then $PRINTF "$CANT\n" numCANT=$((numCANT+1)) elif [ ! -e $trc0 ]; then $PRINTF "$OK\n" numOK=$((numOK+1)) else $PRINTF "$FAILED\n" echo "$CMD0 &" >&2 cat "${te}0" >&2 echo "$CMD1" >&2 cat "${te}1" >&2 numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" fi fi # NUMCOND ;; esac N=$((N+1)) # Bug fix, OpenSSL server could be crashed by client cert with IPv6 address in SubjectAltname NAME=OPENSSL_CLIENT_IP6_CN case "$TESTS" in *%$N%*|*%functions%*|*%bugs%*|*%openssl%*|*%ip6%*|*%socket%*|*%listen%*|*%$NAME%*) TEST="$NAME: Test if OpenSSL server may be crashed by client cert with IPv6 address" # Socat 1.7.4.1 had a bug that caused OpenSSL server to crash with SIGSEGV when # it checked a client certificate containing IPv6 address in SubjectAltName and # no openssl-commonname option was given if ! eval $NUMCOND; then :; elif ! testfeats openssl >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}OPENSSL not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif ! testfeats tcp ip4 >/dev/null || ! runsip4 >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}TCP/IPv4 not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" else gentestcert testsrv gentestaltcert testalt tf="$td/test$N.stdout" te="$td/test$N.stderr" tdiff="$td/test$N.diff" da="test$N $(date) $RANDOM" newport tcp4 CMD0="$TRACE $SOCAT $opts -u OPENSSL-LISTEN:$PORT,pf=ip4,reuseaddr,cert=./testsrv.pem,cafile=./testalt.crt -" CMD1="$TRACE $SOCAT $opts -u - OPENSSL-CONNECT:localhost:$PORT,pf=ip4,cafile=testsrv.crt,cert=testalt.pem,verify=0" printf "test $F_n $TEST... " $N $CMD0 >/dev/null >"${tf}0" 2>"${te}0" & pid0=$! waittcp4port $PORT 1 echo "$da" |$CMD1 2>"${te}1" rc1=$? kill $pid0 2>/dev/null; wait if [ $rc1 -eq 0 ] && echo "$da" |diff - "${tf}0" >$tdiff; then $PRINTF "$OK\n" numOK=$((numOK+1)) else $PRINTF "$FAILED\n" echo "$CMD0 &" >&2 cat "${te}0" >&2 echo "$CMD1" >&2 cat "${te}1" >&2 numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" fi fi # NUMCOND ;; esac N=$((N+1)) # Test if unknown service specs are handled properly NAME=BAD_SERVICE case "$TESTS" in *%$N%*|*%functions%*|*%bugs%*|*%tcp%*|*%socket%*|*%$NAME%*) TEST="$NAME: test if unknown service specs are handled properly" # Try to resolve an unspecified TCP service " if ! eval $NUMCOND; then :; else tf="$td/test$N.stdout" te="$td/test$N.stderr" tdiff="$td/test$N.diff" da="test$N $(date) $RANDOM" CMD="$TRACE $SOCAT $opts - TCP:$LOCALHOST:zyxw" printf "test $F_n $TEST... " $N $CMD >/dev/null 2>"${te}" & pid=$! sleep 1 kill -9 $pid 2>/dev/null; rc=$? # did process still exist? if [ $rc -ne 0 ]; then $PRINTF "$OK\n" if [ "$VERBOSE" ]; then echo "$CMD &" >&2 fi numOK=$((numOK+1)) else $PRINTF "$FAILED\n" echo "$CMD &" >&2 cat "${te}" >&2 numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" fi fi # NUMCOND ;; esac N=$((N+1)) # Test if the user option with abstract UNIX domain socket is not applied to # file "" (empty name) NAME=ABSTRACT_USER case "$TESTS" in *%$N%*|*%functions%*|*%bugs%*|*%socket%*|*%unix%*|*%abstract%*|*%listen%*|*%$NAME%*) TEST="$NAME: Is the fs related user option on ABSTRACT socket applied to FD" # Apply the user option to an abstract socket; check if this produces an error. # No error should occur if ! eval $NUMCOND; then :; elif [ "$UNAME" != Linux ]; then $PRINTF "test $F_n $TEST... ${YELLOW}only on Linux${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" else tf="$td/test$N.stdout" te="$td/test$N.stderr" tdiff="$td/test$N.diff" da="test$N $(date) $RANDOM" CMD="$TRACE $SOCAT ABSTRACT-LISTEN:temp,accept-timeout=0.1,user=$USER FILE:/dev/null" printf "test $F_n $TEST... " $N $CMD >/dev/null 2>"${te}" echo "$da" |$CMD >"${tf}1" 2>"${te}1" rc=$? if [ $rc -eq 0 ]; then $PRINTF "$OK\n" if [ "$VERBOSE" ]; then echo "$CMD" >&2 fi numOK=$((numOK+1)) else $PRINTF "$FAILED\n" echo "$CMD" >&2 cat "${te}" >&2 numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" fi fi # NUMCOND ;; esac N=$((N+1)) # Test if option -R does not "sniff" left-to-right traffic NAME=SNIFF_RIGHT_TO_LEFT case "$TESTS" in *%$N%*|*%functions%*|*%bugs%*|*%$NAME%*) TEST="$NAME: test if option -R does not "sniff" left-to-right traffic" # Use option -R, check if left-to-right traffic is not in output file if ! eval $NUMCOND; then :; else tf="$td/test$N.stdout" te="$td/test$N.stderr" ts="$td/test$N.sniffed" tdiff="$td/test$N.diff" da="test$N $(date) $RANDOM" CMD="$TRACE $SOCAT $opts -R $ts - /dev/null" printf "test $F_n $TEST... " $N echo "$da" |$CMD >"${tf}" 2>"${te}" rc=$? if [ ! -f "$ts" ]; then $PRINTF "$CANT\n" if [ "$VERBOSE" ]; then echo "$CMD" >&2 cat "${te}" >&2 fi numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif [ ! -s "$ts" ]; then $PRINTF "$OK\n" if [ "$VERBOSE" ]; then echo "$CMD" >&2 fi numOK=$((numOK+1)) else $PRINTF "$FAILED\n" echo "$CMD &" >&2 cat "${te}" >&2 numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" fi fi # NUMCOND ;; esac PORT=$((PORT+1)) N=$((N+1)) # Socats access to different types of file system entries using various kinds # of addresses fails in a couple of useless combinations. These failures have # to print an error message and exit with return code 1. # Up to version 1.7.4.2 this desired behaviour was found for most combinations, # however some fix in 1.7.4.3 degraded the overall result. # This group of tests checks all known compinations. while read entry method; do if [ -z "$entry" ] || [[ "$entry" == \#* ]]; then continue; fi NAME=$(toupper $method)_TO_$(toupper $entry) case "$TESTS" in *%$N%*|*%functions%*|*%bugs%*|*%socket%*|*%unix%*|*%listen%*|*%$NAME%*) #set -vx TEST="$NAME: Failure handling on $method access to $entry" # Create some kind of system entry and try to access it with some improper # address. Check if Socat returns with rc 1 and prints an error message if ! eval $NUMCOND; then :; else ts="$td/test$N.socket" tf="$td/test$N.stdout" te="$td/test$N.stderr" tdiff="$td/test$N.diff" da="test$N $(date) $RANDOM" printf "test $F_n $TEST... " $N # create an invalid or non-matching UNIX socket case "$entry" in missing) pid0=; rm -f $ts ;; denied) pid0=; rm -f $ts; touch $ts; chmod 000 $ts ;; directory) pid0=; mkdir -p $ts ;; orphaned) pid0= # the remainder of a UNIX socket in FS SOCAT_MAIN_WAIT= $SOCAT $opts UNIX-LISTEN:$ts,unlink-close=0 /dev/null >${tf}0 2>${te}0 & waitunixport $ts 1 SOCAT_MAIN_WAIT= $SOCAT $opts /dev/null UNIX-CONNECT:$ts >>${tf}0 2>>${te}0 ;; file) pid0=; rm -f $ts; touch $ts ;; stream) CMD0="$SOCAT $opts UNIX-LISTEN:$ts /dev/null" SOCAT_MAIN_WAIT= $CMD0 >${tf}0 2>${te}0 & pid0=$! ;; dgram) CMD0="$SOCAT $opts -u UNIX-RECV:$ts /dev/null" SOCAT_MAIN_WAIT= $CMD0 >${tf}0 2>${te}0 & pid0=$! ;; seqpacket) CMD0="$SOCAT $opts UNIX-LISTEN:$ts,socktype=$SOCK_SEQPACKET /dev/null" SOCAT_MAIN_WAIT= $CMD0 >${tf}0 2>${te}0 & pid0=$! ;; esac [ "$pid0" ] && waitunixport $ts 1 # try to access this socket case "$method" in connect) CMD1="$TRACE $SOCAT $opts -u - UNIX-CONNECT:$ts" ;; send) CMD1="$TRACE $SOCAT $opts -u - UNIX-SEND:$ts" ;; sendto) CMD1="$TRACE $SOCAT $opts -u - UNIX-SENDTO:$ts" ;; seqpacket) CMD1="$TRACE $SOCAT $opts -u - UNIX-CONNECT:$ts,socktype=$SOCK_SEQPACKET" ;; unix) CMD1="$TRACE $SOCAT $opts -u - UNIX-CLIENT:$ts" ;; gopen) CMD1="$TRACE $SOCAT $opts -u - GOPEN:$ts" ;; esac echo "$da" |$CMD1 >"${tf}1" 2>"${te}1" rc1=$? [ "$pid0" ] && { kill $pid0 2>/dev/null; wait; } if [ $rc1 != 1 ]; then $PRINTF "$FAILED (bad return code $rc1)\n" if [ "$pid0" ]; then echo "$CMD0 &" >&2 cat "${te}0" >&2 fi echo "$CMD1" >&2 cat "${te}1" >&2 numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" elif nerr=$(grep ' E ' "${te}1" |wc -l); test "$nerr" -ne 1; then $PRINTF "$FAILED ($nerr error message(s) instead of 1)\n" if [ "$pid0" ]; then echo "$CMD0 &" >&2 cat "${te}0" >&2 fi echo "$CMD1" >&2 cat "${te}1" >&2 numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" else $PRINTF "$OK\n" if [ "$VERBOSE" ]; then if [ "$pid0" ]; then echo "$CMD0 &" >&2; fi echo "$CMD1" >&2 fi numOK=$((numOK+1)) fi set +vx fi # NUMCOND ;; esac N=$((N+1)) done <<<" missing connect denied connect directory connect orphaned connect file connect dgram connect seqpacket connect missing send denied send directory send orphaned send file send stream send seqpacket send missing sendto denied sendto directory sendto orphaned sendto file sendto stream sendto seqpacket sendto missing seqpacket denied seqpacket directory seqpacket orphaned seqpacket file seqpacket stream seqpacket dgram seqpacket missing unix denied unix directory unix file unix orphaned unix denied gopen directory gopen orphaned gopen " # Test TCP with options connect-timeout and retry. # Up to 1.7.4.3 this terminated immediately on connection refused NAME=TCP_TIMEOUT_RETRY case "$TESTS" in *%$N%*|*%functions%*|*%bugs%*|*%tcp%*|*%socket%*|*%listen%*|*%$NAME%*) TEST="$NAME: TCP with options connect-timeout and retry" # In background run a delayed echo server # In foreground start TCP with connect-timeout and retry. On first attempt the # server is not listening; when socat makes a second attempt that succeeds, the # bug is absent and the test succeeded. if ! eval $NUMCOND; then :; else tf="$td/test$N.stdout" te="$td/test$N.stderr" tdiff="$td/test$N.diff" da="test$N $(date) $RANDOM" CMD0="sleep 1 && $TRACE $SOCAT $opts TCP4-L:$PORT,reuseaddr PIPE" CMD1="$TRACE $SOCAT $opts - TCP4:$LOCALHOST:$PORT,connect-timeout=2,retry=1,interval=2" printf "test $F_n $TEST... " $N eval "$CMD0" >/dev/null 2>"${te}0" & pid0=$! echo "$da" |$CMD1 >"${tf}1" 2>"${te}1" rc1=$? kill $pid0 2>/dev/null; wait if [ $rc1 -ne 0 ]; then $PRINTF "$FAILED\n" echo "$CMD0 &" >&2 cat "${te}0" >&2 echo "$CMD1" >&2 cat "${te}1" >&2 numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" elif echo "$da" |diff - "${tf}1" >$tdiff; then $PRINTF "$OK\n" if [ "$VERBOSE" ]; then echo "$CMD0 &" >&2 echo "$CMD1" >&2 fi numOK=$((numOK+1)) else $PRINTF "$FAILED\n" echo "$CMD0 &" >&2 cat "${te}0" >&2 echo "$CMD1" >&2 cat "${te}1" >&2 numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" fi fi # NUMCOND ;; esac N=$((N+1)) # Test if the rawer option works. Up to Socat 1.7.4.3, it failed because it # cleared the CREAD flag. NAME=RAWER case "$TESTS" in *%$N%*|*%functions%*|*%bugs%*|*%pty%*|*%$NAME%*) TEST="$NAME: Test if the rawer option fails" # Invoke Socat with a terminal address with option rawer. When it has no error # the test succeeded. if ! eval $NUMCOND; then :; else tf="$td/test$N.stdout" te="$td/test$N.stderr" tdiff="$td/test$N.diff" da="test$N $(date) $RANDOM" CMD0="$SOCAT -lp outer /dev/null EXEC:\"$SOCAT\\ -lp\\ inner\\ -\\,rawer\\ PIPE\",pty" printf "test $F_n $TEST... " $N eval "$CMD0" >/dev/null 2>"${te}0" rc0=$? if [ $rc0 -eq 0 ]; then $PRINTF "$OK\n" if [ "$VERBOSE" ]; then echo "$CMD0" >&2 fi numOK=$((numOK+1)) else $PRINTF "$FAILED\n" echo "$CMD0" >&2 cat "${te}0" >&2 numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" fi fi # NUMCOND ;; esac PORT=$((PORT+1)) N=$((N+1)) # Up to 1.7.4.3 there was a bug with the lowport option: # Active addresses UDP-SEND, UDP-SENDTO always bound to port 1 instead of # 640..1023 NAME=UDP_LOWPORT case "$TESTS" in *%$N%*|*%functions%*|*%bugs%*|*%socket%*|*%$NAME%*) TEST="$NAME: UDP4-SEND with lowport" # Run Socat with UDP4-SEND:...,lowport and full logging and check the # parameters of bind() call. If port is in the range 640..1023 the test # succeeded. # This test does not require root because it just checks log of bind() but does # not require success # This test fails if WITH_SYCLS is turned off if ! eval $NUMCOND; then :; else tf="$td/test$N.stdout" te="$td/test$N.stderr" tdiff="$td/test$N.diff" da="test$N $(date) $RANDOM" #newport udp4 # not needed in this test CMD="$TRACE $SOCAT $opts -d -d -d -d /dev/null UDP4-SENDTO:$LOCALHOST:$PORT,lowport" printf "test $F_n $TEST... " $N $CMD >/dev/null 2>"${te}" rc1=$? LOWPORT=$(grep '[DE] bind(.*:' $te |sed 's/.*:\([0-9][0-9]*\)[}]*,.*/\1/' |head -n 1) #echo "LOWPORT=\"$LOWPORT\"" >&2 #type socat >&2 if [[ $LOWPORT =~ [0-9][0-9]* ]] && [ "$LOWPORT" -ge 640 -a "$LOWPORT" -le 1023 ]; then $PRINTF "$OK\n" if [ "$VERBOSE" ]; then echo "$CMD0 &"; fi if [ "$DEBUG" ]; then cat "${te}0" >&2; fi numOK=$((numOK+1)) elif $SOCAT -V |grep -q "undef WITH_SYCLS"; then $PRINTF "$CANT (no SYCLS)\n" if [ "$VERBOSE" ]; then echo "$CMD0 &"; fi if [ "$DEBUG" ]; then cat "${te}0" >&2; fi numCANT=$((numCANT+1)) listCANT="$listCANT $N" else $PRINTF "$FAILED\n" echo "$CMD" cat "${te}" >&2 numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" fi fi # NUMCOND ;; esac PORT=$((PORT+1)) N=$((N+1)) # Test if trailing garbage in integer type options gives error NAME=MISSING_INTEGER case "$TESTS" in *%$N%*|*%functions%*|*%syntax%*|*%bugs%*|*%$NAME%*) TEST="$NAME: Error on option that's missing integer value" # Invoke Socat with pty and option ispeed=b19200. # When socat terminates with error the test succeeded if ! eval $NUMCOND; then :; else tf="$td/test$N.stdout" te="$td/test$N.stderr" tdiff="$td/test$N.diff" da="test$N $(date) $RANDOM" CMD0="$TRACE $SOCAT $opts - PTY,ispeed=b19200" printf "test $F_n $TEST... " $N $CMD0 /dev/null 2>"${te}0" if grep -q "missing numerical value" "${te}0"; then $PRINTF "$OK\n" numOK=$((numOK+1)) else $PRINTF "$FAILED\n" echo "$CMD0" cat "${te}0" numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" fi fi # NUMCOND ;; esac N=$((N+1)) # Test if trailing garbage in integer type options gives error NAME=INTEGER_GARBAGE case "$TESTS" in *%$N%*|*%functions%*|*%syntax%*|*%bugs%*|*%$NAME%*) TEST="$NAME: Error on trailing garbage" # Invoke Socat with pty and option ispeed=b19200. # When socat terminates with error the test succeeded if ! eval $NUMCOND; then :; else tf="$td/test$N.stdout" te="$td/test$N.stderr" tdiff="$td/test$N.diff" da="test$N $(date) $RANDOM" CMD0="$TRACE $SOCAT $opts - PTY,ispeed=19200B" printf "test $F_n $TEST... " $N $CMD0 /dev/null 2>"${te}0" if grep -q "trailing garbage" "${te}0"; then $PRINTF "$OK\n" if [ "$VERBOSE" ]; then echo "$CMD0" >&2; fi if [ "$debug" ]; then cat ${te} >&2; fi numOK=$((numOK+1)) else $PRINTF "$FAILED\n" echo "$CMD0" cat "${te}0" numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" fi fi # NUMCOND ;; esac N=$((N+1)) # Test if Filan can print the target of symbolic links NAME=FILANSYMLINK case "$TESTS" in *%$N%*|*%filan%*|*%$NAME%*) TEST="$NAME: capability to display symlink target" # Run Filan on a symbolic link # When its output contains "LINKTARGET=" the test succeeded if ! eval $NUMCOND; then :; else tf="$td/test$N.file" tl="$td/test$N.symlink" te="$td/test$N.stderr" printf "test $F_n $TEST... " $N touch "$tf" ln -s "$tf" "$tl" target=$($FILAN -f "$tl" 2>$te |tail -n 1 |sed 's/.*LINKTARGET=\([^ ]*\)/\1/') if [ "$target" = "$tf" ]; then $PRINTF "$OK\n" if [ "$VERBOSE" ]; then echo "touch \"$tf\"" echo "ln -s \"$tf\" \"$tl\"" echo "$FILAN -f "$tl" 2>$te |tail -n 1 |sed 's/.*LINKTARGET=\([^ ]*\)/\1/'" fi numOK=$((numOK+1)) else $PRINTF "$FAILED\n" echo "touch \"$tf\"" >&2 echo "ln -s \"$tf\" \"$tl\"" >&2 echo "$FILAN -f "$tl" 2>$te |tail -n 1 |sed 's/.*LINKTARGET=\([^ ]*\)/\1/'" >&2 cat "$te" numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" fi kill $spid 2>/dev/null wait fi ;; # NUMCOND esac N=$((N+1)) # Test preservation of packet boundaries from Socat to sub processes of # various kind and back to Socat via socketpair with socket type datagram. # (EXECSOCKETPAIRPACKETS SYSTEMSOCKETPAIRPACKETS) for addr in exec system; do ADDR=$(echo $addr |tr a-z A-Z) NAME=${ADDR}SOCKETPAIRPACKETS case "$TESTS" in *%$N%*|*%functions%*|*%exec%*|*%socketpair%*|*%unix%*|*%dgram%*|*%packets%*|*%$NAME%*) TEST="$NAME: simple echo via $addr of cat with socketpair, keeping packet boundaries" # Start a Socat process with a UNIX datagram socket on the left side and with # a sub process connected via datagram socketpair that keeps packet boundaries # (here: another Socat process in unidirectional mode). # Pass two packets to the UNIX datagram socket; let Socat wait a little time # before processing, # so the packets are at the same time in the receive queue. # The process that sends thes packet uses a short packet size (-b), # so the returned data is truncated in case the packets were merged. # When the complete data is returned, the test succeeded. if ! eval $NUMCOND; then :; else ts0="$td/test$N.sock0" ts1="$td/test$N.sock1" tf="$td/test$N.stdout" te="$td/test$N.stderr" tdiff="$td/test$N.diff" da="test$N $(date) $RANDOM" #CMD0="$TRACE $SOCAT $opts -lp server -T 2 UNIX-SENDTO:$ts1,bind=$ts0 $ADDR:\"$SOCAT -lp echoer -u - -\",pty,echo=0,pipes" # test the test CMD0="$TRACE $SOCAT $opts -lp server -T 2 UNIX-SENDTO:$ts1,bind=$ts0,null-eof $ADDR:\"$SOCAT -lp echoer -u - -\",socktype=$SOCK_DGRAM",shut-null CMD1="$SOCAT $opts -lp client -b 24 -t 2 -T 3 - UNIX-SENDTO:$ts0,bind=$ts1",shut-null printf "test $F_n $TEST... " $N export SOCAT_TRANSFER_WAIT=2 eval "$CMD0" >/dev/null 2>"${te}0" & pid0="$!" unset SOCAT_TRANSFER_WAIT waitunixport $ts0 1 { echo -n "${da:0:20}"; sleep 1; echo "${da:20}"; } |$CMD1 >"${tf}1" 2>"${te}1" rc1=$? kill $pid0 2>/dev/null; wait if [ "$rc1" -ne 0 ]; then $PRINTF "$FAILED (rc1=$rc1): $TRACE $SOCAT:\n" echo "$CMD0 &" cat "${te}0" echo "{ echo -n "${da:0:20}"; sleep 1; echo "${da:20}"; } |$CMD1" cat "${te}1" numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" elif ! echo "$da" |diff - "${tf}1" >"$tdiff"; then $PRINTF "$FAILED (diff)\n" echo "$CMD0 &" >&2 cat "${te}0" >&2 echo "{ echo -n "${da:0:20}"; sleep 1; echo "${da:20}"; } |$CMD1" >&2 cat "${te}1" >&2 echo "diff:" >&2 cat $tdiff >&2 numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" else $PRINTF "$OK\n" if [ "$VERBOSE" ]; then echo "$CMD0 &" >&2 echo "{ echo -n "${da:0:20}"; sleep 1; echo "${da:20}"; } |$CMD1" >&2 fi numOK=$((numOK+1)) fi fi # NUMCOND ;; esac N=$((N+1)) done # for # Test if a special quote based syntax error in dalan module does not raise # SIGSEGV NAME=DALAN_NO_SIGSEGV case "$TESTS" in *%$N%*|*%functions%*|*%bugs%*|*%dalan%*|*%listen%*|*%$NAME%*) TEST="$NAME: Dalan syntax error does not raise SIGSEGV" # Invoke Socat with an address that has this quote based syntax error. # When exit code is 1 (due to syntax error) the test succeeded. if ! eval $NUMCOND; then : elif ! a=$(testfeats GOPEN); then $PRINTF "test $F_n $TEST... ${YELLOW}Feature $a not available in $SOCAT${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif ! a=$(testaddrs - GOPEN SOCKET-LISTEN); then $PRINTF "test $F_n $TEST... ${YELLOW}Address $a not available in $SOCAT${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" else tf="$td/test$N.stdout" te="$td/test$N.stderr" tdiff="$td/test$N.diff" da="test$N $(date) $RANDOM" CMD="$TRACE $SOCAT $opts /dev/null SOCKET-LISTEN:1:1:'"/tmp/sock"'" printf "test $F_n $TEST... " $N $CMD >/dev/null 2>"${te}" rc1=$? if [ $rc1 -eq 1 ]; then $PRINTF "$OK\n" if [ "$VERBOSE" ]; then echo "$CMD"; fi if [ "$DEBUG" ]; then cat "${te}" >&2; fi numOK=$((numOK+1)) elif [ $rc1 -eq 139 ]; then $PRINTF "$FAILED\n" echo "$CMD" cat "${te}" >&2 numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" else # soemthing unexpected happened $PRINTF "$CANT\n" echo "$CMD" cat "${te}" >&2 numCANT=$((numCANT+1)) listCANT="$listCANT $N" fi fi # NUMCOND ;; esac N=$((N+1)) # Test if filan -s correctly displays TCP on appropriate FDs # This feature was broken in version 1.7.4.4 NAME=FILAN_SHORT_TCP case "$TESTS" in *%$N%*|*%functions%*|*%bugs%*|*%socket%*|*%filan%*|*%listen%*|*%$NAME%*) TEST="$NAME: filan -s displays TCP etc" # Establish a TCP connection using Socat server and client; on the server # exec() filan -s using nofork option, so its output appears on the client. # When the second word in the first line is "tcp" the test succeeded. if ! eval $NUMCOND; then : elif ! a=$(testfeats STDIO IP4 TCP LISTEN EXEC); then $PRINTF "test $F_n $TEST... ${YELLOW}Feature $a not available in $SOCAT${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif ! a=$(testaddrs STDIO TCP4 TCP4-LISTEN EXEC); then $PRINTF "test $F_n $TEST... ${YELLOW}Address $a not available in $SOCAT${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif ! o=$(testoptions so-reuseaddr nofork ) >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}Option $o not available in $SOCAT${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif ! runsip4 >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}IPv4 not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" else tf="$td/test$N.stdout" te="$td/test$N.stderr" tdiff="$td/test$N.diff" da="test$N $(date) $RANDOM" CMD0="$TRACE $SOCAT $opts TCP4-LISTEN:$PORT,reuseaddr EXEC:'$FILAN -s',nofork" CMD1="$TRACE $SOCAT $opts - TCP4:localhost:$PORT" printf "test $F_n $TEST... " $N eval "$CMD0" >/dev/null 2>"${te}0" & pid0=$! waittcp4port $PORT 1 $CMD1 >"${tf}1" 2>"${te}1" /dev/null; wait result="$(head -n 1 ${tf}1 |awk '{print($2);}')" if [ $rc1 -eq 0 -a "$result" = tcp ]; then $PRINTF "$OK\n" if [ "$VERBOSE" ]; then echo "$CMD0 &"; fi if [ "$DEBUG" ]; then cat "${te}0" >&2; fi if [ "$VERBOSE" ]; then echo "$CMD1"; fi if [ "$DEBUG" ]; then cat "${te}1" >&2; fi numOK=$((numOK+1)) else $PRINTF "$FAILED\n" if [ $rc1 -ne 0 ]; then echo "rc=$rc1" >&2 else echo "result is \"$result\" instead of \"tcp\"" >&2 fi echo "$CMD0 &" cat "${te}0" >&2 echo "$CMD1" cat "${te}1" >&2 numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" fi fi # NUMCOND ;; esac PORT=$((PORT+1)) N=$((N+1)) # Test if the settings of the terminal that Socat is invoked in are restored # on termination. # This failed on Open-Solaris family OSes up to 1.7.4.4 NAME=RESTORE_TTY case "$TESTS" in *%$N%*|*%functions%*|*%bugs%*|*%termios%*|*%tty%*|*%$NAME%*) TEST="$NAME: Restoring of terminal settings" # With an outer Socat command create a new pty and a bash in it. # In this bash store the current terminal settings, then invoke a temporary # inner Socat command that changes the term to raw mode and terminates. # When the terminal settings afterwards are the same as before the call the # test succeeded. if ! eval $NUMCOND; then : elif ! $(type stty >/dev/null 2>&1); then $PRINTF "test $F_n $TEST... ${YELLOW}stty not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif ! a=$(testfeats STDIO SYSTEM PTY GOPEN); then $PRINTF "test $F_n $TEST... ${YELLOW}Feature $a not available in $SOCAT${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif ! a=$(testaddrs - STDIO SYSTEM GOPEN); then $PRINTF "test $F_n $TEST... ${YELLOW}Address $a not available in $SOCAT${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif ! o=$(testoptions cfmakeraw pty setsid ctty stderr) >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}Option $o not available in $SOCAT${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" else te="$td/test$N.stderr" tx0="$td/test$N.stty0" tx1="$td/test$N.stty1" tdiff="$td/test$N.diff" da="test$N $(date) $RANDOM" CMD="$TRACE $SOCAT $opts -lp outersocat - SYSTEM:\"stty\ >$tx0;\ $SOCAT\ -\,cfmakeraw\ /dev/nul\l >${te};\ stty\ >$tx1\",pty,setsid,ctty,stderr" printf "test $F_n $TEST... " $N eval "$CMD" >/dev/null 2>${te}.outer rc=$? if diff $tx0 $tx1 >$tdiff 2>&1; then $PRINTF "$OK\n" if [ "$VERBOSE" ]; then echo "$CMD &"; fi if [ "$DEBUG" ]; then cat "${te}" >&2; fi numOK=$((numOK+1)) else $PRINTF "$FAILED\n" echo "$CMD" cat "${te}" >&2 cat "${te}.outer" >&2 cat $tdiff >&2 numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" fi fi # NUMCOND ;; esac PORT=$((PORT+1)) N=$((N+1)) # Test if EXEC'd program inherits only the stdio file descriptors # thus there are no FD leaks from Socat to EXEC'd program NAME=EXEC_FDS case "$TESTS" in *%$N%*|*%functions%*|*%bugs%*|*%socket%*|*%filan%*|*%$NAME%*) TEST="$NAME: Socat does not leak FDs to EXEC'd program" # Run Socat with EXEC address, execute Filan to display its file descriptors # Test succeeds when only FDs 0, 1, 2 are in use. if ! eval $NUMCOND; then :; elif ! a=$(testaddrs STDIO EXEC); then $PRINTF "test $F_n $TEST... ${YELLOW}Address $a not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif ! o=$(testoptions stderr) >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}Option $o not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" else tf="$td/test$N.stdout" te="$td/test$N.stderr" tdiff="$td/test$N.diff" da="test$N $(date) $RANDOM" CMD="$TRACE $SOCAT $opts - EXEC:\"$FILAN -s\"" printf "test $F_n $TEST... " $N eval "$CMD" >"${tf}" 2>"${te}" # "door" is a special FD type on Solaris/SunOS if [ "$(cat "${tf}" |grep -v ' door ' |wc -l)" -eq 3 ]; then $PRINTF "$OK\n" if [ "$VERBOSE" ]; then echo "$CMD"; fi if [ "$DEBUG" ]; then cat "${te}" >&2; fi numOK=$((numOK+1)) else $PRINTF "$FAILED\n" echo "$CMD" >&2 cat "${te}" >&2 cat "${tf}" >&2 numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" fi fi # NUMCOND ;; esac PORT=$((PORT+1)) N=$((N+1)) # Test if Socat makes the sniffing file descriptos (-r, -R) CLOEXEC to not leak # them to EXEC'd program NAME=EXEC_SNIFF case "$TESTS" in *%$N%*|*%functions%*|*%bugs%*|*%socket%*|*%filan%*|*%$NAME%*) TEST="$NAME: Socat does not leak sniffing FDs" # Run Socat sniffing both directions, with EXEC address, # execute Filan to display its file descriptors # Test succeeds when only FDs 0, 1, 2 are in use. if ! eval $NUMCOND; then :; elif ! a=$(testaddrs STDIO EXEC); then $PRINTF "test $F_n $TEST... ${YELLOW}Address $a not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif ! o=$(testoptions stderr) >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}Option $o not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" else tf="$td/test$N.stdout" te="$td/test$N.stderr" tdiff="$td/test$N.diff" da="test$N $(date) $RANDOM" CMD="$TRACE $SOCAT $opts -r $td/test$N.-r -R $td/test$N.-R - EXEC:\"$FILAN -s\"" printf "test $F_n $TEST... " $N eval "$CMD" >"${tf}" 2>"${te}" # "door" is a special FD type on Solaris/SunOS if [ "$(cat "${tf}" |grep -v ' door ' |wc -l)" -eq 3 ]; then $PRINTF "$OK\n" if [ "$VERBOSE" ]; then echo "$CMD"; fi if [ "$DEBUG" ]; then cat "${te}" >&2; fi numOK=$((numOK+1)) else $PRINTF "$FAILED\n" echo "$CMD" >&2 cat "${te}" >&2 cat "${tf}" >&2 numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" fi fi # NUMCOND ;; esac PORT=$((PORT+1)) N=$((N+1)) while read KEYW FEAT RUNS ADDR IPPORT; do if [ -z "$KEYW" ] || [[ "$KEYW" == \#* ]]; then continue; fi PROTO=$KEYW proto="$(echo "$PROTO" |tr A-Z a-z)" feat="$(tolower "$FEAT")" # test the fork option on really RECVFROM oriented sockets NAME=${KEYW}_FORK case "$TESTS" in *%$N%*|*%functions%*|*%fork%*|*%$feat%*|*%$proto%*|*%socket%*|*%$NAME%*) TEST="$NAME: ${KEYW}-RECVFROM with fork option" # Start a RECVFROM process with fork option and SYSTEM address where clients # data determines the sleep time; send a record with sleep before storing the # data, then send a record with 0 sleep before storing data. # When the second record is stored before the first one the test succeeded. if ! eval $NUMCOND; then :; elif ! F=$(testfeats $FEAT STDIO SYSTEM); then $PRINTF "test $F_n $TEST... ${YELLOW}Feature $F not configured${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif ! A=$(testaddrs - STDIO SYSTEM $PROTO-RECVFROM $PROTO-SENDTO); then $PRINTF "test $F_n $TEST... ${YELLOW}Address $A not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif ! o=$(testoptions fork ) >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}Option $o not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif ! runs$RUNS >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}$(toupper $RUNS) not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" else case "X$IPPORT" in "XPORT") newport $proto tsl=$PORT # test socket listen address tsc="$ADDR:$PORT" # test socket connect address ;; *) tsl="$(eval echo "$ADDR")" # resolve $N tsc=$tsl esac #ts="$td/test$N.sock" tf="$td/test$N.stdout" te="$td/test$N.stderr" tdiff="$td/test$N.diff" da="test$N $(date) $RANDOM" CMD0="$TRACE $SOCAT $opts -t 3 $PROTO-RECVFROM:$tsl,fork SYSTEM:'read t x; sleep \$t; echo \\\"\$x\\\" >>'\"$tf\"" CMD1="$TRACE $SOCAT $opts -t 3 - $PROTO-SENDTO:$tsc" printf "test $F_n $TEST... " $N eval $CMD0 "${te}0" & pid0=$! wait${proto}port $tsl 1 echo "2 $da 1" |$CMD1 >"${tf}1" 2>"${te}1" & pid1=$! sleep 1 echo "0 $da 2" |$CMD1 >"${tf}2" 2>"${te}2" & pid2=$! sleep 2 cpids="$(childpids $pid0 /dev/null; wait if $ECHO "$da 2\n$da 1" |diff - $tf >$tdiff; then $PRINTF "$OK\n" if [ "$VERBOSE" ]; then echo "$CMD0 &"; fi if [ "$DEBUG" ]; then cat "${te}0" >&2; fi if [ "$VERBOSE" ]; then echo "$CMD1"; fi if [ "$DEBUG" ]; then cat "${te}1" >&2; fi if [ "$VERBOSE" ]; then echo "$CMD2"; fi if [ "$DEBUG" ]; then cat "${te}2" >&2; fi numOK=$((numOK+1)) else $PRINTF "$FAILED\n" echo "$CMD0 &" cat "${te}0" >&2 echo "$CMD1" cat "${te}1" >&2 echo "$CMD2" cat "${te}2" >&2 echo "diff:" >&2 cat "$tdiff" >&2 numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" namesFAIL="$namesFAIL $NAME" fi fi # NUMCOND ;; esac N=$((N+1)) done <<<" UDP4 UDP ip4 127.0.0.1 PORT UDP6 UDP ip6 [::1] PORT UNIX unix unix $td/test\$N.server - " # Test if option -S turns off logging of SIGTERM NAME=SIGTERM_NOLOG case "$TESTS" in *%$N%*|*%functions%*|*%signal%*|*%$NAME%*) TEST="$NAME: Option -S can turn off logging of SIGTERM" # Start Socat with option -S 0x0000, kill it with SIGTERM # When no logging entry regarding this signal is there, the test succeeded if ! eval $NUMCOND; then :; elif ! $SOCAT -h | grep -e " -S\>" >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}Option -S not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif ! F=$(testfeats PIPE); then $PRINTF "test $F_n $TEST... ${YELLOW}Feature $F not configured${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif ! A=$(testaddrs PIPE); then $PRINTF "test $F_n $TEST... ${YELLOW}Address $A not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" else tf="$td/test$N.stdout" te="$td/test$N.stderr" tdiff="$td/test$N.diff" CMD0="$TRACE $SOCAT $opts -S 0x0000 PIPE PIPE" printf "test $F_n $TEST... " $N $CMD0 >/dev/null 2>"${te}0" & pid0=$! relsleep 1 # give process time to start kill -TERM $pid0 2>/dev/null; wait if ! grep "exiting on signal" ${te}0 >/dev/null; then $PRINTF "$OK\n" if [ "$VERBOSE" ]; then echo "$CMD0 &"; fi if [ "$DEBUG" ]; then cat "${te}0" >&2; fi if [ "$DEBUG" ]; then echo "kill -TERM " >&2; fi numOK=$((numOK+1)) else $PRINTF "$FAILED\n" echo "$CMD0 &" cat "${te}0" >&2 echo "kill -TERM " >&2 numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" namesFAIL="$namesFAIL $NAME" fi fi # NUMCOND ;; esac N=$((N+1)) # Test if option -S turns on logging of signal 31 NAME=SIG31_LOG case "$TESTS" in *%$N%*|*%functions%*|*%signal%*|*%$NAME%*) TEST="$NAME: Option -S can turn on logging of signal 31" # Start Socat with option -S 0x80000000, kill it with -31 # When a logging entry regarding this signal is there, the test succeeded if ! eval $NUMCOND; then :; elif ! $SOCAT -h | grep -e " -S\>" >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}Option -S not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif ! F=$(testfeats PIPE); then $PRINTF "test $F_n $TEST... ${YELLOW}Feature $F not configured${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif ! A=$(testaddrs PIPE); then $PRINTF "test $F_n $TEST... ${YELLOW}Address $A not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" else tf="$td/test$N.stdout" te="$td/test$N.stderr" tdiff="$td/test$N.diff" da="test$N $(date) $RANDOM" CMD0="$TRACE $SOCAT $opts -S 0x80000000 PIPE PIPE" printf "test $F_n $TEST... " $N $CMD0 >/dev/null 2>"${te}0" & pid0=$! relsleep 1 # give process time to start kill -31 $pid0 2>/dev/null; wait if grep "exiting on signal" ${te}0 >/dev/null; then $PRINTF "$OK\n" if [ "$VERBOSE" ]; then echo "$CMD0 &"; fi if [ "$DEBUG" ]; then cat "${te}0" >&2; fi if [ "$DEBUG" ]; then echo "kill -31 " >&2; fi numOK=$((numOK+1)) else $PRINTF "$FAILED\n" echo "$CMD0 &" cat "${te}0" >&2 echo "kill -31 " >&2 numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" namesFAIL="$namesFAIL $NAME" fi fi # NUMCOND ;; esac N=$((N+1)) # Test the http-version of the PROXY-CONNECT address NAME=PROXY_HTTPVERSION case "$TESTS" in *%$N%*|*%functions%*|*%proxy%*|*%$NAME%*) TEST="$NAME: PROXY-CONNECT with option http-version" if ! eval $NUMCOND; then :; elif ! $(type proxyecho.sh >/dev/null 2>&1); then $PRINTF "test $F_n $TEST... ${YELLOW}proxyecho.sh not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif ! F=$(testfeats IP4 TCP LISTEN EXEC STDIO PROXY); then $PRINTF "test $F_n $TEST... ${YELLOW}Feature $F not configured${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif ! A=$(testaddrs TCP4-LISTEN EXEC STDIO PROXY-CONNECT); then $PRINTF "test $F_n $TEST... ${YELLOW}Address $A not available in $SOCAT${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif ! o=$(testoptions so-reuseaddr crlf pf proxyport http-version) >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}Option $o not available in $SOCAT${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif ! runsip4 >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}IPv4 not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" else ts="$td/test$N.sh" tf="$td/test$N.stdout" te="$td/test$N.stderr" tdiff="$td/test$N.diff" da="test$N $(date) $RANDOM"; da="$da$($ECHO '\r')" CMD0="$TRACE $SOCAT $opts TCP4-L:$PORT,reuseaddr,crlf EXEC:\"/usr/bin/env bash proxyecho.sh -V 1.1\"" CMD1="$TRACE $SOCAT $opts - PROXY:$LOCALHOST:127.0.0.1:1000,pf=ip4,proxyport=$PORT,http-version=1.1" printf "test $F_n $TEST... " $N eval "$CMD0 2>\"${te}1\" &" pid=$! # background process id waittcp4port $PORT 1 echo "$da" |$CMD1 >"$tf" 2>"${te}0" if ! echo "$da" |diff - "$tf" >"$tdiff"; then $PRINTF "$FAILED: $TRACE $SOCAT:\n" echo "$CMD0 &" cat "${te}0" >&2 echo "$CMD1" cat "${te}1" >&2 echo "diff:" >&2 cat "$tdiff" >&2 numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" else $PRINTF "$OK\n" if [ "$VERBOSE" ]; then echo "$CMD0 &"; fi if [ "$debug" ]; then cat "${te}0" >&2; fi if [ "$VERBOSE" ]; then echo "$CMD1"; fi if [ "$debug" ]; then cat "${te}1" >&2; fi numOK=$((numOK+1)) fi kill $pid 2>/dev/null wait fi ;; # NUMCOND, feats esac PORT=$((PORT+1)) N=$((N+1)) # Test the so-rcvtimeo address option with DTLS NAME=RCVTIMEO_DTLS case "$TESTS" in *%$N%*|*%functions%*|*%ip4%*|*%ipapp%*|*%udp%*|*%timeout%*|*%openssl%*|*%dtls%*|*%$NAME%*) TEST="$NAME: test the so-rcvtimeo option with DTLS" if ! eval $NUMCOND; then :; elif ! F=$(testfeats STDIO OPENSSL); then $PRINTF "test $F_n $TEST... ${YELLOW}Feature $F not configured in $SOCAT${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif ! A=$(testaddrs STDIO DTLS); then $PRINTF "test $F_n $TEST... ${YELLOW}Address $A not available in $SOCAT${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif ! o=$(testoptions verify so-rcvtimeo) >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}Option $o not available in $SOCAT${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif ! runsip4 >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}IPv4 not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" else # We need a hanging connection attempt, guess an address for this HANGIP=0.0.0.1 te1="$td/test$N.stderr1" tk1="$td/test$N.kill1" te2="$td/test$N.stderr2" tk2="$td/test$N.kill2" $PRINTF "test $F_n $TEST... " $N # First, try to make socat hang and see if it can be killed CMD1="$TRACE $SOCAT $opts - DTLS:$HANGIP:1,verify=0" $CMD1 >"$te1" 2>$te1 "$tk1"; then $PRINTF "${YELLOW}does not hang${NORMAL}\n" if [ "$VERBOSE" ]; then echo "$CMD1 &"; fi if [ "$DEBUG" ]; then cat "${te}1" >&2; fi numCANT=$((numCANT+1)) listCANT="$listCANT $N" wait else # DTLS restarts read() a few times while kill $pid1 2>/dev/null; do :; done # Second, set so-rcvtimeo and see if Socat exits before kill CMD2="$TRACE $SOCAT $opts - DTLS:$HANGIP:1,verify=0,so-rcvtimeo=1.0" $CMD2 >"$te1" 2>$te2 "$tk2"; then $PRINTF "$FAILED\n" echo "$CMD2" cat "$te2" >&2 numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" while kill $pid2 2>/dev/null; do :; done wait else $PRINTF "$OK\n" if [ "$VERBOSE" ]; then echo "$CMD2 &"; fi if [ "$DEBUG" ]; then cat "${te}2" >&2; fi numOK=$((numOK+1)) fi fi wait fi ;; # testfeats, NUMCOND esac N=$((N+1)) # Test the use of interesting variables in the sniffing file names NAME=VARS_IN_SNIFFPATH case "$TESTS" in *%$N%*|*%functions%*|*%socket%*|*%listen%*|*%fork%*|*%$NAME%*) TEST="$NAME: sniff file names with variables" # Start a server process with option fork that sniffs traffic and stores it in # two files for each child process, using PID, timestamp, microseconds, and # client IP # Connect two times. # For now we say that the test succeeded when 4 log files have been generated. if ! eval $NUMCOND; then :; elif ! A=$(testfeats IP4 TCP LISTEN PIPE STDIO); then $PRINTF "test $F_n $TEST... ${YELLOW}Feature $F not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif ! A=$(testaddrs - TCP4 TCP4-LISTEN PIPE STDIO); then $PRINTF "test $F_n $TEST... ${YELLOW}Address $A not available in $SOCAT${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif ! o=$(testoptions so-reuseaddr fork) >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}Option $o not available in $SOCAT${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif ! runsip4 >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}IPv4 not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" else tf="$td/test$N.stdout" te="$td/test$N.stderr" tdiff="$td/test$N.diff" da="test$N $(date) $RANDOM" newport tcp4 # or whatever proto, or drop this line CMD0="$TRACE $SOCAT $opts -lp server0 -r \"$td/test$N.\\\$PROGNAME-\\\$TIMESTAMP.\\\$MICROS-\\\$SERVER0_PEERADDR-\\\$\\\$.in.log\" -R \"$td/test$N.\\\$PROGNAME-\\\$TIMESTAMP.\\\$MICROS-\\\$SERVER0_PEERADDR-\\\$\\\$.out.log\" TCP4-LISTEN:$PORT,so-reuseaddr,fork PIPE" CMD1="$TRACE $SOCAT $opts - TCP4-CONNECT:$LOCALHOST:$PORT" printf "test $F_n $TEST... " $N eval "$CMD0" >/dev/null 2>"${te}0" & pid0=$! waittcp4port $PORT 1 echo "$da" |$CMD1 >"${tf}1a" 2>"${te}1a" rc1a=$? echo "$da" |$CMD1 >"${tf}1b" 2>"${te}1b" rc1b=$? kill $(childpids $pid0) $pid0 2>/dev/null; wait if [ $rc1a != 0 -o $rc1b != 0 ]; then $PRINTF "$FAILED (client problem)\n" echo "$CMD0 &" cat "${te}0" >&2 echo "$CMD1" cat "${te}1a" >&2 echo "$CMD1" cat "${te}1b" >&2 numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" namesFAIL="$namesFAIL $NAME" elif test $(ls -l $td/test$N.*.log |wc -l) -eq 4 && test $(ls $td/test$N.*.log |head -n 1 |wc -c) -ge 56; then # Are the names correct? # Convert timestamps to epoch and compare # Are the contents correct? $PRINTF "$OK\n" if [ "$VERBOSE" ]; then echo "$CMD0 &"; fi if [ "$DEBUG" ]; then cat "${te}0" >&2; fi if [ "$VERBOSE" ]; then echo "$CMD1"; fi if [ "$DEBUG" ]; then cat "${te}1a" >&2; fi if [ "$VERBOSE" ]; then echo "$CMD1"; fi if [ "$DEBUG" ]; then cat "${te}1b" >&2; fi numOK=$((numOK+1)) elif test -f $td/test$N.\$PROGNAME-\$TIMESTAMP.\$MICROS-\$SERVER0_PEERADDR-\$\$.in.log; then $PRINTF "$FAILED (vars not resolved)\n" echo "$CMD0 &" cat "${te}0" >&2 echo "$CMD1" cat "${te}1a" >&2 echo "$CMD1" cat "${te}1b" >&2 numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" namesFAIL="$namesFAIL $NAME" else $PRINTF "$FAILED (unknown)\n" echo "$CMD0 &" cat "${te}0" >&2 echo "$CMD1" cat "${te}1a" >&2 echo "$CMD1" cat "${te}1b" >&2 numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" namesFAIL="$namesFAIL $NAME" fi fi # NUMCOND ;; esac N=$((N+1)) # Test logging of statistics on Socat option --statistics NAME=OPTION_STATISTICS case "$TESTS" in *%$N%*|*%functions%*|*%stats%*|*%system%*|*%stdio%*|*%$NAME%*) TEST="$NAME: Socat option --statistics" # Invoke Socat with option --statistics, transfer some date, and check the log # file for the values if ! eval $NUMCOND; then :; elif ! $(type >/dev/null 2>&1); then $PRINTF "test $F_n $TEST... ${YELLOW}tee not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif ! F=$(testfeats STATS STDIO SYSTEM); then $PRINTF "test $F_n $TEST... ${YELLOW}Feature $F not available in $SOCAT${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif ! A=$(testaddrs STDIO SYSTEM); then $PRINTF "test $F_n $TEST... ${YELLOW}Address $A not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif ! o=$(testoptions pty cfmakeraw) >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}Option $o not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" else tf="$td/test$N.stdout" te="$td/test$N.stderr" tdiff="$td/test$N.diff" da="test$N $(date) $RANDOM" CMD0="$TRACE $SOCAT $opts --statistics STDIO SYSTEM:'tee /dev/stdout',pty,cfmakeraw" printf "test $F_n $TEST... " $N echo "$da" |eval "$CMD0" >"${tf}0" 2>"${te}0" rc0=$? if [ $rc0 -ne 0 ]; then # The test could not run meaningfully $PRINTF "$CANT\n" if [ "$VERBOSE" ]; then echo "$CMD0"; fi if [ "$DEBUG" ]; then cat "${te}0" >&2; fi numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif [ $(grep STATISTICS "${te}0" |wc -l) -eq 2 ]; then $PRINTF "$OK\n" if [ "$VERBOSE" ]; then echo "$CMD0"; fi if [ "$DEBUG" ]; then cat "${te}0" >&2; fi numOK=$((numOK+1)) else $PRINTF "$FAILED\n" echo "$CMD0 &" cat "${te}0" >&2 numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" namesFAIL="$namesFAIL $NAME" fi fi # NUMCOND ;; esac N=$((N+1)) # Test logging of statistics on SIGUSR1 NAME=SIGUSR1_STATISTICS case "$TESTS" in *%$N%*|*%functions%*|*%signal%*|*%stats%*|*%system%*|*%stdio%*|*%$NAME%*) TEST="$NAME: statistics on SIGUSR1" # Invoke Socat without option --statistics, transfer some date, send signal # USR1,and check the log file for the values if ! eval $NUMCOND; then :; elif ! $(type tee >/dev/null 2>&1); then $PRINTF "test $F_n $TEST... ${YELLOW}tee not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif ! $(type pkill >/dev/null 2>&1); then $PRINTF "test $F_n $TEST... ${YELLOW}pkill not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif ! F=$(testfeats STATS STDIO SYSTEM); then $PRINTF "test $F_n $TEST... ${YELLOW}Feature $F not available in $SOCAT${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif ! A=$(testaddrs STDIO SYSTEM); then $PRINTF "test $F_n $TEST... ${YELLOW}Address $A not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif ! o=$(testoptions pty cfmakeraw) >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}Option $o not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" else tf="$td/test$N.stdout" te="$td/test$N.stderr" tdiff="$td/test$N.diff" da="test$N $(date) $RANDOM" CMD0="$TRACE $SOCAT $opts STDIO SYSTEM:'tee /dev/stdout 2>/dev/null',pty,cfmakeraw" #set -vx printf "test $F_n $TEST... " $N { echo "$da"; relsleep 3; } |eval "$CMD0" >"${tf}0" 2>"${te}0" & pid0=$! relsleep 2 TTY=$(tty |sed 's|/dev/||') pkill -USR1 -t $TTY socat || { echo "pkill -t $TTY -USR1 socat"; } relsleep 1 pkill -t $TTY socat wait if [ "$(grep STATISTICS "${te}0" |wc -l)" -eq 2 ]; then $PRINTF "$OK\n" if [ "$VERBOSE" ]; then echo "$CMD0"; fi if [ "$DEBUG" ]; then cat "${te}0" >&2; fi numOK=$((numOK+1)) else $PRINTF "$FAILED\n" echo "$CMD0 &" cat "${te}0" >&2 numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" namesFAIL="$namesFAIL $NAME" fi fi # NUMCOND ;; esac N=$((N+1)) # Test the children-shutup option NAME=CHILDREN_SHUTUP case "$TESTS" in *%$N%*|*%functions%*|*%exec%*|*%fork%*|*%socket%*|*%unix%*|*%$NAME%*) TEST="$NAME: test the children-shutup option" # Run a UNIX domain listening server with options fork and children-shutup, and # that connects to a closed TCP4 port. # Connect to the server and check if it logs the TCP4-CONNECT failure as warning. if ! eval $NUMCOND; then :; elif ! F=$(testfeats UNIX LISTEN EXEC FILE); then $PRINTF "test $F_n $TEST... ${YELLOW}Feature $F not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif ! A=$(testaddrs UNIX-LISTEN TCP4 FILE UNIX-CONNECT); then $PRINTF "test $F_n $TEST... ${YELLOW}Address $A not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif ! o=$(testoptions fork children-shutup) >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}Option $o not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" else newport tcp4 ts="$td/test$N.sock" tf="$td/test$N.stdout" te="$td/test$N.stderr" tdiff="$td/test$N.diff" da="test$N $(date) $RANDOM" CMD0="$TRACE $SOCAT $opts UNIX-LISTEN:$ts,fork,children-shutup TCP4:localhost:$PORT" CMD1="$TRACE $SOCAT $opts -u FILE:/dev/null UNIX-CONNECT:$ts" printf "test $F_n $TEST... " $N $CMD0 >/dev/null 2>"${te}0" & pid0=$! waitunixport $ts 1 { $CMD1 2>"${te}1"; sleep 1; } rc1=$? kill $pid0 2>/dev/null; wait relsleep 1 # child process might need more time if grep -q " W connect" ${te}0; then $PRINTF "$OK\n" if [ "$VERBOSE" ]; then echo "$CMD0 &"; fi if [ "$DEBUG" ]; then cat "${te}0" >&2; fi if [ "$VERBOSE" ]; then echo "$CMD1"; fi if [ "$DEBUG" ]; then cat "${te}1" >&2; fi numOK=$((numOK+1)) else $PRINTF "$FAILED\n" echo "$CMD0 &" cat "${te}0" >&2 echo "$CMD1" cat "${te}1" >&2 numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" namesFAIL="$namesFAIL $NAME" fi fi # NUMCOND ;; esac N=$((N+1)) # Socats INTERFACE address has to ignore outgoing packets if possible. # On Linux is uses socket option PACKET_IGNORE_OUTGOING or it queries per # packet the PACKET_OUTGOING flag of struct sockaddr_ll.sll_pkttype NAME=INTERFACE_IGNOREOUTGOING case "$TESTS" in *%$N%*|*%functions%*|*%interface%*|*%tun%*|*%root%*|*%$NAME%*) TEST="$NAME: INTERFACE ignores outgoing packets" #idea: create a TUN interface and hook with INTERFACE. # Send a packet out the interface, should not be seen by INTERFACE if ! eval $NUMCOND; then :; elif [ $(id -u) -ne 0 -a "$withroot" -eq 0 ]; then $PRINTF "test $F_n $TEST... ${YELLOW}must be root${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif ! $(type ping >/dev/null 2>&1); then $PRINTF "test $F_n $TEST... ${YELLOW}ping not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif ! feat=$(testfeats TUN STDIO INTERFACE); then $PRINTF "test $F_n $TEST... ${YELLOW}$feat not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif ! A=$(testaddrs - TUN STDIO INTERFACE); then $PRINTF "test $F_n $TEST... ${YELLOW}Address $A not available in $SOCAT${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif ! o=$(testoptions iff-up tun-type tun-name ) >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}Option $o not available in $SOCAT${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif ! runsip4 >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}IPv4 not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" else tf="$td/test$N.stdout" te="$td/test$N.stderr" tdiff="$td/test$N.diff" tl="$td/test$N.lock" da="$(date) $RANDOM" TUNNET=10.255.255 TUNNAME=tun9 CMD0="$TRACE $SOCAT $opts -L $tl TUN:$TUNNET.1/24,iff-up=1,tun-type=tun,tun-name=$TUNNAME -" CMD1="$TRACE $SOCAT $opts -u INTERFACE:$TUNNAME -" CMD2="ping -c 1 -w 1 -b $TUNNET.255" printf "test $F_n $TEST... " $N sleep 1 |$CMD0 2>"${te}0" >/dev/null & pid0="$!" #waitinterface "$TUNNAME" usleep $MICROS $CMD1 >"${tf}1" 2>"${te}1" & pid1="$!" usleep $MICROS $CMD2 2>"${te}2" 1>&2 kill $pid1 2>/dev/null usleep $MICROS kill $pid0 2>/dev/null wait if [ $? -ne 0 ]; then $PRINTF "$FAILED: $TRACE $SOCAT:\n" echo "$CMD0 &" cat "${te}0" >&2 echo "$CMD1" cat "${te}1" >&2 echo "$CMD2" cat "${te}2" >&2 numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif test -s "${tf}1"; then $PRINTF "$FAILED\n" echo "$CMD0 &" cat "${te}0" >&2 echo "$CMD1" cat "${te}1" >&2 echo "$CMD2" cat "${te}2" >&2 numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" else $PRINTF "$OK\n" if [ "$VERBOSE" ]; then echo "$CMD0 &"; fi if [ "$DEBUG" ]; then cat "${te}0" >&2; fi if [ "$VERBOSE" ]; then echo "$CMD1"; fi if [ "$DEBUG" ]; then cat "${te}1" >&2; fi if [ "$VERBOSE" ]; then echo "$CMD2"; fi if [ "$DEBUG" ]; then cat "${te}2" >&2; fi numOK=$((numOK+1)) fi fi ;; # NUMCOND, feats esac PORT=$((PORT+1)) N=$((N+1)) # Test if the SO_REUSEADDR socket option is applied automatically to TCP LISTEN # type addresses. NAME=TCP4_REUSEADDR case "$TESTS" in *%$N%*|*%functions%*|*%socket%*|*%ip%*|*%ip4%*|*%tcp%*|*%tcp4%*|*%listen%*|*%$NAME%*) TEST="$NAME: test if option reuseaddr's default is 1" # Start a TCP4-LISTEN server, connect with a client, have the server shutdown # the connection. Start the server on the same port again. If it starts the # test succeeded. if ! eval $NUMCOND; then :; elif ! F=$(testfeats STDIO PIPE IP4 TCP LISTEN); then $PRINTF "test $F_n $TEST... ${YELLOW}Feature $F not available in $SOCAT${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif ! A=$(testaddrs STDIO PIPE TCP4 TCP4-LISTEN); then $PRINTF "test $F_n $TEST... ${YELLOW}Address $A not available in $SOCAT${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif ! o=$(testoptions accept-timeout) >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}Option $o not available in $SOCAT${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif ! runsip4 >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}IPv4 not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" else tf="$td/test$N.stdout" te="$td/test$N.stderr" tdiff="$td/test$N.diff" da="test$N $(date) $RANDOM" newport tcp4 CMD0a="$TRACE $SOCAT $opts -T 0.1 TCP4-LISTEN:$PORT PIPE" CMD0b="$TRACE $SOCAT $opts TCP4-LISTEN:$PORT,accept-timeout=0.1 PIPE" CMD1="$TRACE $SOCAT $opts STDIO TCP4-CONNECT:$LOCALHOST:$PORT" printf "test $F_n $TEST... " $N $CMD0a >/dev/null 2>"${te}0a" & pid0=$! waittcp4port $PORT 1 $CMD1 >"${tf}1" 2>"${te}1" rc1=$? kill $pid0 2>/dev/null; wait $CMD0b >/dev/null 2>"${te}0b" rc0b=$? if [ $rc0b -eq 0 ]; then $PRINTF "$OK\n" if [ "$VERBOSE" ]; then echo "$CMD0a &"; fi if [ "$DEBUG" ]; then cat "${te}0a" >&2; fi if [ "$VERBOSE" ]; then echo "$CMD1"; fi if [ "$DEBUG" ]; then cat "${te}1" >&2; fi if [ "$VERBOSE" ]; then echo "$CMD0b"; fi if [ "$DEBUG" ]; then cat "${te}0b" >&2; fi numOK=$((numOK+1)) else $PRINTF "$FAILED\n" echo "$CMD0a &" cat "${te}0a" >&2 echo "$CMD1" cat "${te}1" >&2 echo "$CMD0b" cat "${te}0b" >&2 numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" namesFAIL="$namesFAIL $NAME" fi fi # NUMCOND ;; esac N=$((N+1)) # Test if the SO_REUSEADDR socket option is applied automatically to OPENSSL LISTEN # type addresses. NAME=OPENSSL_6_REUSEADDR case "$TESTS" in *%$N%*|*%functions%*|*%socket%*|*%ip%*|*%ip6%*|*%tcp%*|*%tcp6%*|*%listen%*|*%openssl%*|*%$NAME%*) TEST="$NAME: test if option reuseaddr's default is 1 with SSL-L" # Start an OPENSSL-LISTEN server using TCP on IPv6, connect with a client, have # the server shutdown the connection. Start the server on the same port again. # If it starts the test succeeded. if ! eval $NUMCOND; then :; elif ! F=$(testfeats PIPE IP6 TCP OPENSSL LISTEN); then $PRINTF "test $F_n $TEST... ${YELLOW}Feature $F not available in $SOCAT${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif ! A=$(testaddrs PIPE OPENSSL-CONNECT OPENSSL-LISTEN); then $PRINTF "test $F_n $TEST... ${YELLOW}Address $A not available in $SOCAT${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif ! o=$(testoptions verify cert key) >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}Option $o not available in $SOCAT${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif ! runsip6 >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}IPv6 not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" else tf="$td/test$N.stdout" te="$td/test$N.stderr" tdiff="$td/test$N.diff" da="test$N $(date) $RANDOM" printf "test $F_n $TEST... " $N newport tcp6 # Yup, it seems that with OpenSSL the side that begins with shutdown does NOT # begin shutdown of the TCP connection # therefore we let the client timeout # result is not reliable (OK seen even without any SO_REUSEADDR) CMD0a="$TRACE $SOCAT $opts -lp server1 -6 OPENSSL-LISTEN:$PORT,cert=testsrv.crt,key=testsrv.key,verify=0 PIPE" CMD0b="$TRACE $SOCAT $opts -lp server2 -6 OPENSSL-LISTEN:$PORT,accept-timeout=.01,cert=testsrv.crt,key=testsrv.key,verify=0 PIPE" CMD1="$TRACE $SOCAT $opts -lp client -6 -T 0.1 PIPE OPENSSL-CONNECT:$LOCALHOST6:$PORT,verify=0" $CMD0a >/dev/null 2>"${te}0a" & pid0=$! waittcp6port $PORT 1 $CMD1 >"${tf}1" 2>"${te}1" rc1=$? kill $pid0 2>/dev/null; wait $CMD0b >/dev/null 2>"${te}0b" rc0b=$? if [ $rc0b -eq 0 ]; then $PRINTF "$OK\n" if [ "$VERBOSE" ]; then echo "$CMD0a &"; fi if [ "$DEBUG" ]; then cat "${te}0a" >&2; fi if [ "$VERBOSE" ]; then echo "$CMD1"; fi if [ "$DEBUG" ]; then cat "${te}1" >&2; fi if [ "$VERBOSE" ]; then echo "$CMD0b"; fi if [ "$DEBUG" ]; then cat "${te}0b" >&2; fi numOK=$((numOK+1)) else $PRINTF "$FAILED\n" echo "$CMD0a &" cat "${te}0a" >&2 echo "$CMD1" cat "${te}1" >&2 echo "$CMD0b" cat "${te}0b" >&2 numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" namesFAIL="$namesFAIL $NAME" fi fi # NUMCOND ;; esac N=$((N+1)) # Test if the so-reuseaddr= option prevents the SO_REUSEADDR socket option NAME=REUSEADDR_NULL case "$TESTS" in *%$N%*|*%functions%*|*%socket%*|*%ip%*|*%ip4%*|*%tcp%*|*%tcp4%*|*%listen%*|*%$NAME%*) TEST="$NAME: test option reuseaddr without value" # Start a TCP4-LISTEN server with so-reuseaddr=, connect with a client, have # the server shutdown the connection. # Start the server on the same port again. If it fails with # "Address already in use" the test succeeded. if ! eval $NUMCOND; then :; elif ! F=$(testfeats STDIO PIPE IP4 TCP LISTEN); then $PRINTF "test $F_n $TEST... ${YELLOW}Feature $F not available in $SOCAT${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif ! A=$(testaddrs STDIO PIPE TCP4-CONNECT TCP4-LISTEN); then $PRINTF "test $F_n $TEST... ${YELLOW}Address $A not available in $SOCAT${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif ! o=$(testoptions so-reuseaddr accept-timeout) >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}Option $o not available in $SOCAT${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif ! runsip4 >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}IPv4 not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" else tf="$td/test$N.stdout" te="$td/test$N.stderr" tdiff="$td/test$N.diff" da="test$N $(date) $RANDOM" newport tcp4 CMD0a="$TRACE $SOCAT $opts -T 0.1 TCP4-LISTEN:$PORT,so-reuseaddr= PIPE" CMD0b="$TRACE $SOCAT $opts TCP4-LISTEN:$PORT,accept-timeout=0.1 PIPE" CMD1="$TRACE $SOCAT $opts STDIO TCP4-CONNECT:$LOCALHOST:$PORT" printf "test $F_n $TEST... " $N $CMD0a >/dev/null 2>"${te}0a" & pid0=$! waittcp4port $PORT 1 $CMD1 >"${tf}1" 2>"${te}1" rc1=$? kill $pid0 2>/dev/null; wait $CMD0b >/dev/null 2>"${te}0b" rc0b=$? if [ $rc0b -eq 1 ] && grep -q -e "Address already in use" -e "Address in use" "${te}0b"; then $PRINTF "$OK\n" if [ "$VERBOSE" ]; then echo "$CMD0a &"; fi if [ "$DEBUG" ]; then cat "${te}0a" >&2; fi if [ "$VERBOSE" ]; then echo "$CMD1"; fi if [ "$DEBUG" ]; then cat "${te}1" >&2; fi if [ "$VERBOSE" ]; then echo "$CMD0b"; fi if [ "$DEBUG" ]; then cat "${te}0b" >&2; fi numOK=$((numOK+1)) #elif grep -q "accept: \(Connection\|Operation\) timed out" "${te}0b"; then elif grep -q "accept: .* timed out" "${te}0b"; then # FreeBSD, Solaris do not seem to need SO_REUSEADDR with TCP at all $PRINTF "$CANT\n" if [ "$VERBOSE" ]; then echo "$CMD0a &"; fi if [ "$DEBUG" ]; then cat "${te}0a" >&2; fi if [ "$VERBOSE" ]; then echo "$CMD1"; fi if [ "$DEBUG" ]; then cat "${te}1" >&2; fi if [ "$VERBOSE" ]; then echo "$CMD0b"; fi if [ "$DEBUG" ]; then cat "${te}0b" >&2; fi numCANT=$((numCANT+1)) listCANT="$listCANT $N" else $PRINTF "$FAILED\n" echo "$CMD0a &" cat "${te}0a" >&2 echo "$CMD1" cat "${te}1" >&2 echo "$CMD0b" cat "${te}0b" >&2 numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" namesFAIL="$namesFAIL $NAME" fi fi # NUMCOND ;; esac N=$((N+1)) # Test if Socats TCP4-client tries all addresses if necessary NAME=TRY_ADDRS_4 case "$TESTS" in *%$N%*|*%functions%*|*%tcp%*|*%tcp4%*|*%socket%*|*%internet%*|*%$NAME%*) TEST="$NAME: try all available TCP4 addresses" # Connect to a TCP4 port of a hostname that resolves to two addresses where at # least on the first one the port is closed. # server-4.dest-unreach.net has been configured for this purpose, it # resolves to its public address and to 127.0.0.1; unfortunately # forwarding nameservers need not keep order of A entries, so we need a port # that is closed on both addresses. # The test succeeded when the log shows that Socat tried to connect two times. if ! eval $NUMCOND; then :; elif ! $(type nslookup >/dev/null 2>&1); then $PRINTF "test $F_n $TEST... ${YELLOW}nslookup not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" #elif ! $(type nslookup >/dev/null 2>&1) && ! $(type host >/dev/null 2>&1); then # $PRINTF "test $F_n $TEST... ${YELLOW}nslookup and host not available${NORMAL}\n" $N # numCANT=$((numCANT+1)) # listCANT="$listCANT $N" elif ! F=$(testfeats IP4 TCP GOPEN); then $PRINTF "test $F_n $TEST... ${YELLOW}Feature $F not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif ! A=$(testaddrs TCP4-CONNECT GOPEN); then $PRINTF "test $F_n $TEST... ${YELLOW}Address $A not available in $SOCAT${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif ! runsip4 >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}IPv4 not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif [ -z "$INTERNET" ]; then $PRINTF "test $F_n $TEST... ${YELLOW}use test.sh option -internet${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" else tf="$td/test$N.stdout" te="$td/test$N.stderr" tdiff="$td/test$N.diff" da="test$N $(date) $RANDOM" if type nslookup >/dev/null 2>&1; then ADDRS=$(nslookup server-4.dest-unreach.net. |sed -n '/^$/,$ p' |grep ^Address |awk '{print($2);}') elif type host >/dev/null 2>&1; then ADDRS=$(host server-4.dest-unreach.net. |sed 's/.*address //') fi while true; do newport tcp4 OPEN= for addr in $ADDRS; do if $SOCAT /dev/null TCP4:$addr:$PORT 2>/dev/null; then # port is open :-( OPEN=1 break fi done if [ -z "$OPEN" ]; then break; fi newport tcp4 done CMD="$TRACE $SOCAT $opts -d -d /dev/null TCP4:server-4.dest-unreach.net:$PORT" printf "test $F_n $TEST... " $N $CMD >/dev/null 2>"${te}" rc=$? if [ $(grep " N opening connection to .*AF=2 " ${te} |wc -l) -eq 2 ]; then $PRINTF "$OK\n" if [ "$VERBOSE" ]; then echo "$CMD"; fi if [ "$DEBUG" ]; then cat "${te}" >&2; fi numOK=$((numOK+1)) else $PRINTF "$FAILED\n" echo "$CMD" cat "${te}" >&2 numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" namesFAIL="$namesFAIL $NAME" fi fi # NUMCOND ;; esac N=$((N+1)) # Test if Socats TCP-client tries all addresses (IPv4+IPv6) if necessary NAME=TRY_ADDRS_4_6 case "$TESTS" in *%$N%*|*%functions%*|*%tcp%*|*%tcp4%*|*%tcp6%*|*%socket%*|*%internet%*|*%$NAME%*) TEST="$NAME: for TCP try all available IPv4 and IPv6 addresses" # Connect to a TCP port that is not open on localhost-4-6.dest-unreach.net, # neither IPv4 nor IPv6 # Check the log if Socat tried both addresses if ! eval $NUMCOND; then :; elif [ -z "$FOREIGN" ]; then # only needs Internet DNS $PRINTF "test $F_n $TEST... ${YELLOW}use test.sh option -foreign${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" #elif ! $(type nslookup >/dev/null 2>&1) && ! $(type host >/dev/null 2>&1); then # $PRINTF "test $F_n $TEST... ${YELLOW}nslookup and host not available${NORMAL}\n" $N # numCANT=$((numCANT+1)) # listCANT="$listCANT $N" elif ! F=$(testfeats IP4 IP6 TCP); then $PRINTF "test $F_n $TEST... ${YELLOW}Feature $F not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif ! A=$(testaddrs TCP-CONNECT GOPEN); then $PRINTF "test $F_n $TEST... ${YELLOW}Address $A not available in $SOCAT${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif ! runsip4 >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}IPv4 not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif ! runsip6 >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}IPv6 not available or not routable${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif [ -z "$INTERNET" ]; then # only needs Internet DNS $PRINTF "test $F_n $TEST... ${YELLOW}use test.sh option -internet${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" else tf="$td/test$N.stdout" te="$td/test$N.stderr" tdiff="$td/test$N.diff" da="test$N $(date) $RANDOM" LOCALHOST_4_6=localhost-4-6.dest-unreach.net if type nslookup >/dev/null 2>&1; then ADDRS=$(nslookup $LOCALHOST_4_6 |sed -n '/^$/,$ p' |grep ^Address |awk '{print($2);}') elif type host >/dev/null 2>&1; then ADDRS=$(host $LOCALHOST_4_6 |sed 's/.*address //') fi # Specific config: on Ubuntu-12.04: getaddrinfo(...AI_ADDRCONFIG) does not # resolve to IPv6 addresses even when there are link local IPv6 addresses if test -f /etc/os-release && grep -q '^NAME="Ubuntu"' /etc/os-release && grep -q '^VERSION="12\.04' /etc/os-release; then AI_ADDRCONFIG="ai-addrconfig=0," fi # Check if PORT is really closed on both addresses while true; do OPEN= for addr in $ADDRS; do case $addr in *.*) ;; *:*) addr="[$addr]" ; esac if $SOCAT /dev/null TCP:$addr:$PORT,$AI_ADDRCONFIG 2>/dev/null; then # port is open :-( OPEN=1 break fi done if [ -z "$OPEN" ]; then break; fi newport tcp4 done CMD="$TRACE $SOCAT $opts -d -d /dev/null TCP:$LOCALHOST_4_6:$PORT,$AI_ADDRCONFIG" printf "test $F_n $TEST... " $N $CMD >/dev/null 2>"${te}" rc=$? if [ $(grep " N opening connection to .*AF=[0-9]" ${te} |wc -l) -eq 2 ]; then $PRINTF "$OK\n" if [ "$VERBOSE" ]; then echo "$CMD"; fi if [ "$DEBUG" ]; then cat "${te}" >&2; fi numOK=$((numOK+1)) else $PRINTF "$FAILED\n" echo "$CMD" cat "${te}" >&2 numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" namesFAIL="$namesFAIL $NAME" fi fi # NUMCOND ;; esac N=$((N+1)) # Test the netns (net namespace) feature NAME=NETNS case "$TESTS" in *%$N%*|*%functions%*|*%root%*|*%namespace%*|*%netns%*|*%socket%*|*%$NAME%*) ns=socat-$$-test$N TEST="$NAME: option netns (net namespace $ns)" # Start a simple echo server with option netns on localhost of a net namespace; # use a client process with option netns to send data to the net namespace # net server and check the reply. if ! eval $NUMCOND; then :; elif [ "$UNAME" != Linux ]; then $PRINTF "test $F_n $TEST... ${YELLOW}Only on Linux${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif [ $(id -u) -ne 0 -a "$withroot" -eq 0 ]; then $PRINTF "test $F_n $TEST... ${YELLOW}Must be root${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif ! $(type ip >/dev/null 2>&1); then $PRINTF "test $F_n $TEST... ${YELLOW}ip program not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif ! F=$(testfeats IP4 TCP LISTEN NAMESPACES); then $PRINTF "test $F_n $TEST... ${YELLOW}Feature $F not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif ! A=$(testaddrs STDIO TCP-LISTEN TCP EXEC); then $PRINTF "test $F_n $TEST... ${YELLOW}Address $A not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif ! o=$(testoptions netns) >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}Option $o not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif ! runsip4 >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}IPv4 not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" else tf="$td/test$N.stdout" te="$td/test$N.stderr" tdiff="$td/test$N.diff" da="test$N $(date) $RANDOM" newport tcp4 # or whatever proto, or drop this line CMD0="$TRACE $SOCAT $opts --experimental TCP4-LISTEN:$PORT,netns=$ns EXEC:'od -c'" CMD1="$TRACE $SOCAT $opts --experimental - TCP4:127.0.0.1:$PORT,netns=$ns" printf "test $F_n $TEST... " $N ip netns del $ns 2>/dev/null # make sure it does not exist ip netns add $ns ip netns exec $ns ip -4 addr add dev lo 127.0.0.1/8 ip netns exec $ns ip link set lo up eval "$CMD0" >/dev/null 2>"${te}0" & pid0=$! relsleep 1 # if no matching wait*port function echo "$da" |$CMD1 >"${tf}1" 2>"${te}1" rc1=$? kill $pid0 2>/dev/null; wait ip netns del $ns if [ $rc1 -ne 0 ]; then $PRINTF "$FAILED (client failed)\n" echo "ip netns del $ns" echo "ip netns add $ns" echo "ip netns exec $ns ip -4 addr add dev lo 127.0.0.1/8" echo "ip netns exec $ns ip link set lo up" echo "$CMD0 &" cat "${te}0" >&2 echo "$CMD1" cat "${te}1" >&2 echo "ip netns del $ns" numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" namesFAIL="$namesFAIL $NAME" elif echo "$da" |od -c |diff - ${tf}1 >"$tdiff"; then $PRINTF "$OK\n" if [ "$VERBOSE" ]; then echo "ip netns del $ns" echo "ip netns add $ns" echo "ip netns exec $ns ip -4 addr add dev lo 127.0.0.1/8" echo "ip netns exec $ns ip link set lo up" fi if [ "$VERBOSE" ]; then echo "$CMD0 &"; fi if [ "$DEBUG" ]; then cat "${te}0" >&2; fi if [ "$VERBOSE" ]; then echo "$CMD1"; fi if [ "$DEBUG" ]; then cat "${te}1" >&2; fi if [ "$VERBOSE" ]; then echo "ip netns del $ns"; fi numOK=$((numOK+1)) else $PRINTF "$FAILED (bad output)\n" echo "$CMD0 &" cat "${te}0" >&2 echo "$CMD1" cat "${te}1" >&2 diff: cat "$tdiff" numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" namesFAIL="$namesFAIL $NAME" fi fi # NUMCOND ;; esac N=$((N+1)) # Test the netns (net namespace) feature with EXEC and reset NAME=NETNS_EXEC case "$TESTS" in *%$N%*|*%functions%*|*%root%*|*%namespace%*|*%netns%*|*%socket%*|*%abstract%*|*%dgram%*|*%$NAME%*) ns=socat-$$-test$N TEST="$NAME: option netns with EXEC (net namespace $ns)" # Start a simple server with option netns on localhost of a net namespace that # stores data it receives; # use a middle process that EXECs a socat client that connects to the server on # the net namespace; then it listens on default namespace. # With a third command line connect and send data to the middle process. # When the data received by the server is correct the test succeeded. if ! eval $NUMCOND; then :; elif [ "$UNAME" != Linux ]; then $PRINTF "test $F_n $TEST... ${YELLOW}Only on Linux${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif [ $(id -u) -ne 0 -a "$withroot" -eq 0 ]; then $PRINTF "test $F_n $TEST... ${YELLOW}Must be root${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif ! $(type ip >/dev/null 2>&1); then $PRINTF "test $F_n $TEST... ${YELLOW}ip program not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif ! F=$(testfeats IP4 ABSTRACT_UNIXSOCKET UDP LISTEN NAMESPACES STDIO); then $PRINTF "test $F_n $TEST... ${YELLOW}Feature $F not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif ! A=$(testaddrs ABSTRACT-RECV ABSTRACT-SENDTO CREATE EXEC UDP4-RECV STDIO UDP4); then $PRINTF "test $F_n $TEST... ${YELLOW}Address $a not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif ! o=$(testoptions netns) >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}Option $o not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif ! runsip4 >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}IPv4 not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" else tf="$td/test$N.stdout" te="$td/test$N.stderr" tdiff="$td/test$N.diff" da="test$N $(date) $RANDOM" newport udp4 CMD0="$TRACE $SOCAT $opts --experimental -u -T 1 ABSTRACT-RECV:test$N,netns=$ns CREAT:${tf}0" CMD1="$TRACE $SOCAT $opts --experimental -U -T 1 EXEC:\"$SOCAT STDIO ABSTRACT-SENDTO\:test$N\",netns=$ns UDP4-RECV:$PORT" CMD2="$TRACE $SOCAT $opts -u STDIO UDP4:127.0.0.1:$PORT" printf "test $F_n $TEST... " $N ip netns del $ns 2>/dev/null # make sure it does not exist ip netns add $ns #ip netns exec $ns ip -4 addr add dev lo 127.0.0.1/8 #ip netns exec $ns ip link set lo up eval "$CMD0" >/dev/null 2>"${te}0" & pid0=$! relsleep 1 # if no matching wait*port function eval "$CMD1" 2>${te}1 & pid1=$! relsleep 1 echo "$da" |$CMD2 >"${tf}2" 2>"${te}2" rc1=$? kill $pid0 $pid1 2>/dev/null; wait ip netns del $ns if [ $rc1 -ne 0 ]; then $PRINTF "$FAILED (client failed)\n" echo "$CMD0 &" cat "${te}0" >&2 echo "$CMD1" cat "${te}1" >&2 echo "$CMD2" cat "${te}2" >&2 numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" namesFAIL="$namesFAIL $NAME" elif echo "$da" |diff - ${tf}0 >"$tdiff" 2>/dev/null; then $PRINTF "$OK\n" if [ "$VERBOSE" ]; then echo "$CMD0 &"; fi if [ "$DEBUG" ]; then cat "${te}0" >&2; fi if [ "$VERBOSE" ]; then echo "$CMD1"; fi if [ "$DEBUG" ]; then cat "${te}1" >&2; fi if [ "$VERBOSE" ]; then echo "$CMD2"; fi if [ "$DEBUG" ]; then cat "${te}2" >&2; fi numOK=$((numOK+1)) else $PRINTF "$FAILED (bad output)\n" echo "$CMD0 &" cat "${te}0" >&2 echo "$CMD1" cat "${te}1" >&2 echo "$CMD2" cat "${te}2" >&2 echo diff: cat "$tdiff" numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" namesFAIL="$namesFAIL $NAME" fi fi # NUMCOND ;; esac N=$((N+1)) NAME=SOCKETPAIR_STREAM case "$TESTS" in *%$N%*|*%functions%*|*%stdio%*|*%socketpair%*|*%$NAME%*) TEST="$NAME: stdio and internal socketpair with stream" testecho "$N" "$TEST" "STDIO" "SOCKETPAIR" "$opts" esac N=$((N+1)) NAME=SOCKETPAIR_DATAGRAM case "$TESTS" in *%$N%*|*%functions%*|*%stdio%*|*%socketpair%*|*%$NAME%*) TEST="$NAME: stdio and internal socketpair with datagram" testecho "$N" "$TEST" "STDIO" "SOCKETPAIR,socktype=2" "$opts" esac N=$((N+1)) NAME=SOCKETPAIR_SEQPACKET case "$TESTS" in *%$N%*|*%functions%*|*%stdio%*|*%socketpair%*|*%$NAME%*) TEST="$NAME: stdio and internal socketpair with seqpacket" testecho "$N" "$TEST" "STDIO" "SOCKETPAIR,socktype=$SOCK_SEQPACKET" "$opts" esac N=$((N+1)) # Test if SOCKETPAIR address with SOCK_DGRAM keeps packet boundaries NAME=SOCKETPAIR_BOUNDARIES case "$TESTS" in *%$N%*|*%functions%*|*%socketpair%*|*%udp%*|*%udp4%*|*%ip4%*|*%dgram%*|*%$NAME%*) TEST="$NAME: Internal socketpair keeps packet boundaries" # Start a UDP4-DATAGRAM process that echoes data with datagram SOCKETPAIR; # a client sends two packets with 24 and ~18 bytes using a UDP4-DATAGRAM. The # client truncates packets to size 24, so when a large merged packet comes from # server some data will be lost. If the original data is received, the test # succeeded. if ! eval $NUMCOND; then :; elif ! F=$(testfeats STDIO IP4 UDP SOCKETPAIR); then $PRINTF "test $F_n $TEST... ${YELLOW}Feature $F not available in $SOCAT${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif ! A=$(testaddrs - STDIO UDP4-DATAGRAM SOCKETPAIR); then $PRINTF "test $F_n $TEST... ${YELLOW}Address $A not available in $SOCAT${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif ! o=$(testoptions bind socktype ) >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}Option $o not available in $SOCAT${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif ! runsip4 >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}IPv4 not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" else tf="$td/test$N.stdout" te="$td/test$N.stderr" tdiff="$td/test$N.diff" ts1p=$PORT; PORT=$((PORT+1)) ts2p=$PORT; PORT=$((PORT+1)) da="test$N $(date) $RANDOM" CMD1="$TRACE $SOCAT $opts -T 0.2 UDP4-DATAGRAM:$LOCALHOST:$ts2p,bind=$LOCALHOST:$ts1p SOCKETPAIR,socktype=$SOCK_DGRAM" CMD2="$TRACE $SOCAT $opts -b 24 -t 0.2 -T 0.3 - UDP4-DATAGRAM:$LOCALHOST:$ts1p,bind=$LOCALHOST:$ts2p" printf "test $F_n $TEST... " $N export SOCAT_TRANSFER_WAIT=0.2 $CMD1 2>"${te}1" & pid1="$!" unset SOCAT_TRANSFER_WAIT waitudp4port $ts1p 1 { echo -n "${da:0:20}"; usleep 100000; echo "${da:20}"; } |$CMD2 >>"$tf" 2>>"${te}2" rc2="$?" kill "$pid1" 2>/dev/null; wait; if [ "$rc2" -ne 0 ]; then $PRINTF "$FAILED (rc2=$rc2): $TRACE $SOCAT:\n" echo "$CMD1 &" cat "${te}1" >&2 echo "$CMD2" cat "${te}2" >&2 numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" elif ! echo "$da" |diff - "$tf" >"$tdiff"; then $PRINTF "$FAILED\n" echo "$CMD1 &" cat "${te}1" >&2 echo "$CMD2" cat "${te}2" >&2 echo diff: cat "$tdiff" numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" else $PRINTF "$OK\n" if [ "$VERBOSE" ]; then echo "$CMD1"; fi if [ "$DEBUG" ]; then cat "${te}1" >&2; fi if [ "$VERBOSE" ]; then echo "$CMD2 &"; fi if [ "$DEBUG" ]; then cat "${te}2" >&2; fi numOK=$((numOK+1)) fi fi # NUMCOND ;; esac PORT=$((PORT+1)) N=$((N+1)) # Test the ACCEPT-FD address NAME=ACCEPT_FD case "$TESTS" in *%$N%*|*%functions%*|*%bugs%*|*%socket%*|*%systemd%*|*%accept%*|*%$NAME%*) TEST="$NAME: ACCEPT-FD address" # Start Socat with address ACCEPT-FD via systemd-socket-activate for echoing # data. # Connect with a client; the test succeeds when the client gets its data back. if ! eval $NUMCOND; then :; elif ! $(type systemd-socket-activate >/dev/null 2>&1); then $PRINTF "test $F_n $TEST... ${YELLOW}systemd-socket-activate not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif ! F=$(testfeats IP4 TCP LISTEN); then $PRINTF "test $F_n $TEST... ${YELLOW}Feature $F not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif ! A=$(testaddrs ACCEPT-FD PIPE STDIO TCP4); then $PRINTF "test $F_n $TEST... ${YELLOW}Address $A not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif ! runsip4 >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}IPv4 not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" else tf="$td/test$N.stdout" te="$td/test$N.stderr" tdiff="$td/test$N.diff" da="test$N $(date) $RANDOM" newport tcp4 CMD0="systemd-socket-activate -l $PORT --inetd $TRACE $SOCAT $opts ACCEPT-FD:0 PIPE" CMD1="$TRACE $SOCAT $opts - TCP4:$LOCALHOST:$PORT" printf "test $F_n $TEST... " $N $CMD0 >/dev/null 2>"${te}0" & pid0=$! waittcp4port $PORT 1 echo "$da" |$CMD1 >"${tf}1" 2>"${te}1" rc1=$? kill $pid0 2>/dev/null; wait if echo "$da" |diff "${tf}1" - >$tdiff; then $PRINTF "$OK\n" if [ "$VERBOSE" ]; then echo "$CMD0 &"; fi if [ "$DEBUG" ]; then cat "${te}0" >&2; fi if [ "$VERBOSE" ]; then echo "$CMD1"; fi if [ "$DEBUG" ]; then cat "${te}1" >&2; fi numOK=$((numOK+1)) else $PRINTF "$FAILED\n" echo "$CMD0 &" cat "${te}0" >&2 echo "$CMD1" cat "${te}1" >&2 cat $tdiff >&2 numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" namesFAIL="$namesFAIL $NAME" fi fi # NUMCOND ;; esac N=$((N+1)) # Test the POSIX MQ feature with continuous READ and priorization on Linux NAME=LINUX_POSIXMQ_READ_PRIO case "$TESTS" in *%$N%*|*%functions%*|*%socket%*|*%posixmq%*|*%$NAME%*) TEST="$NAME: POSIX-MQ (Linux) with prio" # Run a client/sender that creates a POSIX-MQ and sends a normal message and # then a client/sender with a higher priority message. # Run a passive/listening/receiving/reading process and check if it receives # both messages and in the prioritized order if ! eval $NUMCOND; then :; elif [ "$UNAME" != Linux ]; then $PRINTF "test $F_n $TEST... ${YELLOW}Only on Linux${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif ! F=$(testfeats POSIXMQ STDIO); then $PRINTF "test $F_n $TEST... ${YELLOW}Feature $F not available in $SOCAT${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif ! A=$(testaddrs POSIXMQ-SEND POSIXMQ-READ STDIO); then $PRINTF "test $F_n $TEST... ${YELLOW}Address $A not available in $SOCAT${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif ! o=$(testoptions mq-prio unlink-early unlink-close) >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}Option $o not available in $SOCAT${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" else tf="$td/test$N.stdout" te="$td/test$N.stderr" tdiff="$td/test$N.diff" da="test$N $(date) $RANDOM" tq=/test$N CMD0a="$TRACE $SOCAT --experimental $opts -u STDIO POSIXMQ-SEND:$tq,mq-prio=0,unlink-early" CMD0b="$TRACE $SOCAT --experimental $opts -u STDIO POSIXMQ-SEND:$tq,mq-prio=1" CMD1="$TRACE $SOCAT --experimental $opts -u POSIXMQ-READ:$tq,unlink-close STDIO" printf "test $F_n $TEST... " $N echo "$da 0" |$CMD0a 2>"${te}0a" rc0a=$? echo "$da 1" |$CMD0b 2>"${te}0b" rc0b=$? $CMD1 >"${tf}1" 2>"${te}1" & pid1=$! relsleep 1 kill $pid1; wait if [ $rc0a -ne 0 -o $rc0b -ne 0 ]; then $PRINTF "$FAILED\n" echo "$CMD0a" cat "${te}0a" >&2 echo "$CMD0b" cat "${te}0b" >&2 echo "$CMD1" cat "${te}1" >&2 numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" namesFAIL="$namesFAIL $NAME" elif $ECHO "$da 1\n$da 0" |diff - ${tf}1 >${tdiff}1; then $PRINTF "$OK\n" if [ "$VERBOSE" ]; then echo "$CMD0a"; fi if [ "$DEBUG" ]; then cat "${te}0a" >&2; fi if [ "$VERBOSE" ]; then echo "$CMD0b"; fi if [ "$DEBUG" ]; then cat "${te}0b" >&2; fi if [ "$VERBOSE" ]; then echo "$CMD1"; fi if [ "$DEBUG" ]; then cat "${te}1" >&2; fi numOK=$((numOK+1)) else $PRINTF "$FAILED\n" echo "$CMD0a" cat "${te}0a" >&2 echo "$CMD0b" cat "${te}0b" >&2 echo "$CMD1" cat "${te}1" >&2 echo "difference:" >&2 cat ${tdiff}1 >&2 numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" namesFAIL="$namesFAIL $NAME" fi fi # NUMCOND ;; esac N=$((N+1)) # Test the POSIX MQ feature with RECV,fork on Linux NAME=LINUX_POSIXMQ_RECV_FORK case "$TESTS" in *%$N%*|*%functions%*|*%fork%*|*%socket%*|*%posixmq%*|*%$NAME%*) TEST="$NAME: POSIX-MQ (Linux) RECV with fork" # Start a POSIX-MQ receiver with fork that creates a POSIX-MQ and stores its # output. # Run two clients/senders each with a message. # Check if both messages are stored. if ! eval $NUMCOND; then :; elif [ "$UNAME" != Linux ]; then $PRINTF "test $F_n $TEST... ${YELLOW}Only on Linux${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif ! F=$(testfeats POSIXMQ STDIO); then $PRINTF "test $F_n $TEST... ${YELLOW}Feature $F not available in $SOCAT${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif ! A=$(testaddrs POSIXMQ-SEND POSIXMQ-RECEIVE STDIO); then $PRINTF "test $F_n $TEST... ${YELLOW}Address $A not available in $SOCAT${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif ! o=$(testoptions fork unlink-early unlink-close) >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}Option $o not available in $SOCAT${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" else tf="$td/test$N.stdout" te="$td/test$N.stderr" tdiff="$td/test$N.diff" da="test$N $(date) $RANDOM" tq=/test$N CMD0="$TRACE $SOCAT --experimental $opts -u POSIXMQ-RECV:$tq,unlink-early,fork STDIO" CMD1a="$TRACE $SOCAT --experimental $opts -u STDIO POSIXMQ-SEND:$tq" CMD1b="$TRACE $SOCAT --experimental $opts -u STDIO POSIXMQ-SEND:$tq,unlink-close" printf "test $F_n $TEST... " $N $CMD0 2>"${te}0" >"${tf}0" & pid0=$! relsleep 1 echo "$da 0" |$CMD1a >/dev/null 2>"${te}1a" rc1a=$? echo "$da 1" |$CMD1b >/dev/null 2>"${te}1b" rc1b=$? relsleep 1 kill $pid0; wait if [ $rc1a -ne 0 -o $rc1b -ne 0 ]; then $PRINTF "$FAILED\n" echo "$CMD0" cat "${te}0" >&2 echo "$CMD1a" cat "${te}1a" >&2 echo "$CMD1b" cat "${te}1b" >&2 numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" namesFAIL="$namesFAIL $NAME" elif $ECHO "$da 0\n$da 1" |diff - ${tf}0 >${tdiff}0; then $PRINTF "$OK\n" if [ "$VERBOSE" ]; then echo "$CMD0"; fi if [ "$DEBUG" ]; then cat "${te}0" >&2; fi if [ "$VERBOSE" ]; then echo "$CMD1a"; fi if [ "$DEBUG" ]; then cat "${te}1a" >&2; fi if [ "$VERBOSE" ]; then echo "$CMD1b"; fi if [ "$DEBUG" ]; then cat "${te}1b" >&2; fi numOK=$((numOK+1)) else $PRINTF "$FAILED\n" echo "$CMD0" cat "${te}0" >&2 echo "$CMD1a" cat "${te}1a" >&2 echo "$CMD1b" cat "${te}1b" >&2 echo "difference:" >&2 cat ${tdiff}0 >&2 numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" namesFAIL="$namesFAIL $NAME" fi fi # NUMCOND ;; esac N=$((N+1)) # Test the POSIX MQ feature with RECV,fork,max-children on Linux NAME=LINUX_POSIXMQ_RECV_MAXCHILDREN case "$TESTS" in *%$N%*|*%functions%*|*%fork%*|*%maxchildren%*|*%socket%*|*%posixmq%*|*%$NAME%*) TEST="$NAME: POSIX-MQ (Linux) RECV with fork,max-children" # Start a POSIX-MQ receiver with fork that creates a POSIX-MQ and stores its # output via sub processes that sleeps after writing. # Run a client/sender that sends message 1; # run a client/sender that sends message 3, has to wait; # write message 2 directly into output file; # Check if the messages are stored in order of their numbers if ! eval $NUMCOND; then :; elif [ "$UNAME" != Linux ]; then $PRINTF "test $F_n $TEST... ${YELLOW}Only on Linux${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif ! F=$(testfeats POSIXMQ STDIO SYSTEM); then $PRINTF "test $F_n $TEST... ${YELLOW}Feature $F not available in $SOCAT${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif ! A=$(testaddrs POSIXMQ-SEND POSIXMQ-RECEIVE STDIO SYSTEM); then $PRINTF "test $F_n $TEST... ${YELLOW}Address $A not available in $SOCAT${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif ! o=$(testoptions fork max-children unlink-early unlink-close) >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}Option $o not available in $SOCAT${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" else tf="$td/test$N.stdout" te="$td/test$N.stderr" tdiff="$td/test$N.diff" da="test$N $(date) $RANDOM" tq=/test$N CMD0="$TRACE $SOCAT --experimental $opts -u POSIXMQ-RECV:$tq,unlink-early,fork,max-children=1 SYSTEM:\"cat\ >>${tf}0;\ sleep\ 1\"" CMD1a="$TRACE $SOCAT --experimental $opts -u STDIO POSIXMQ-SEND:$tq" CMD1b="$TRACE $SOCAT --experimental $opts -u STDIO POSIXMQ-SEND:$tq,unlink-close" printf "test $F_n $TEST... " $N eval $CMD0 2>"${te}0" >"${tf}0" & pid0=$! relsleep 1 echo "$da 1" |$CMD1a >/dev/null 2>"${te}1a" rc1a=$? echo "$da 3" |$CMD1b >/dev/null 2>"${te}1b" rc1b=$? psleep 0.5 echo "$da 2" >>"${tf}0" sleep 1 # as in SYSTEM kill $(childpids $pid0) $pid0; wait if [ $rc1a -ne 0 -o $rc1b -ne 0 ]; then $PRINTF "$FAILED\n" echo "$CMD0" cat "${te}0" >&2 echo "$CMD1a" cat "${te}1a" >&2 echo "$CMD1b" cat "${te}1b" >&2 numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" namesFAIL="$namesFAIL $NAME" elif $ECHO "$da 1\n$da 2\n$da 3" |diff - ${tf}0 >${tdiff}0; then $PRINTF "$OK\n" if [ "$VERBOSE" ]; then echo "$CMD0"; fi if [ "$DEBUG" ]; then cat "${te}0" >&2; fi if [ "$VERBOSE" ]; then echo "$CMD1a"; fi if [ "$DEBUG" ]; then cat "${te}1a" >&2; fi if [ "$VERBOSE" ]; then echo "$CMD1b"; fi if [ "$DEBUG" ]; then cat "${te}1b" >&2; fi numOK=$((numOK+1)) else $PRINTF "$FAILED\n" echo "$CMD0" cat "${te}0" >&2 echo "$CMD1a" cat "${te}1a" >&2 echo "$CMD1b" cat "${te}1b" >&2 echo "difference:" >&2 cat ${tdiff}0 >&2 numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" namesFAIL="$namesFAIL $NAME" fi fi # NUMCOND ;; esac N=$((N+1)) # Test the POSIX MQ feature with SEND,fork,max-children on Linux NAME=LINUX_POSIXMQ_SEND_MAXCHILDREN case "$TESTS" in *%$N%*|*%functions%*|*%fork%*|*%maxchildren%*|*%socket%*|*%posixmq%*|*%$NAME%*) TEST="$NAME: POSIX-MQ (Linux) SEND with fork,max-children" # Start a POSIX-MQ receiver that creates a POSIX-MQ and transfers data from # there to an output file # Run a POSIX-MQ sender that two times forks and invokes a data generator # for messages 1 and 3 in a shell process with some trailing sleep. # Afterwards write message 2 directly into output file; message 3 should be # delayed due to max-children option # Check if the messages are stored in order of their numbers. # The data generator is implemented as a receiver from an MQ with "1", "3" if ! eval $NUMCOND; then :; elif [ "$UNAME" != Linux ]; then $PRINTF "test $F_n $TEST... ${YELLOW}Only on Linux${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif ! F=$(testfeats POSIXMQ STDIO SYSTEM); then $PRINTF "test $F_n $TEST... ${YELLOW}Feature $F not available in $SOCAT${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif ! A=$(testaddrs POSIXMQ-SEND POSIXMQ-READ STDIO SYSTEM); then $PRINTF "test $F_n $TEST... ${YELLOW}Address $A not available in $SOCAT${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif ! o=$(testoptions fork max-children mq-prio unlink-early unlink-close) >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}Option $o not available in $SOCAT${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" #elif ! runsposixmq >/dev/null; then # $PRINTF "test $F_n $TEST... ${YELLOW}IPv4 not available${NORMAL}\n" $N # numCANT=$((numCANT+1)) # listCANT="$listCANT $N" else tf="$td/test$N.stdout" te="$td/test$N.stderr" tdiff="$td/test$N.diff" da="test$N $(date) $RANDOM" tq=/test$N CMD0="$TRACE $SOCAT --experimental $opts -u POSIXMQ-READ:$tq,unlink-early STDIO" CMD1="$TRACE $SOCAT --experimental $opts -U POSIXMQ-SEND:$tq,fork,max-children=1,interval=0.1 SYSTEM:\"./socat\ --experimental\ -u\ POSIXMQ-RECV\:$tq-data\ -;\ sleep\ 1\"" printf "test $F_n $TEST... " $N # create data for the generator echo "$da 1" |$SOCAT -u --experimental - POSIXMQ-SEND:$tq-data,unlink-early echo "$da 3" |$SOCAT -u --experimental - POSIXMQ-SEND:$tq-data eval $CMD0 2>"${te}0" >>"${tf}0" & pid0=$! relsleep 1 eval $CMD1 2>"${te}1" & pid1=$! psleep 0.5 echo "$da 2" >>"${tf}0" sleep 1 # as in SYSTEM kill $pid0 $(childpids $pid0) $pid1 $(childpids $pid1) wait $SOCAT -u --experimental /dev/null POSIXMQ-SEND:$tq-data,unlink-close if $ECHO "$da 1\n$da 2\n$da 3" |diff - ${tf}0 >${tdiff}0; then $PRINTF "$OK\n" if [ "$VERBOSE" ]; then echo "$CMD0"; fi if [ "$DEBUG" ]; then cat "${te}0" >&2; fi if [ "$VERBOSE" ]; then echo "$CMD1"; fi if [ "$DEBUG" ]; then cat "${te}1" >&2; fi numOK=$((numOK+1)) else $PRINTF "$FAILED\n" echo "$CMD0" cat "${te}0" >&2 echo "$CMD1" cat "${te}1" >&2 echo "difference:" >&2 cat ${tdiff}0 >&2 numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" namesFAIL="$namesFAIL $NAME" fi fi # NUMCOND ;; esac N=$((N+1)) # Test the sigint option with SHELL address NAME=SHELL_SIGINT case "$TESTS" in *%$N%*|*%functions%*|*%socket%*|*%shell%*|*%progcall%*|*%sigint%*|*%$NAME%*) TEST="$NAME: sigint option with SHELL" # Run Socat with an EXEC address invoking Socat, with option sigint # Send the parent a SIGINT; when the child gets SIGINT too (vs.SIGTERM) # the test succeeded if ! eval $NUMCOND; then :; # Remove unneeded checks, adapt lists of the remaining ones elif ! F=$(testfeats STDIO SHELL PIPE); then $PRINTF "test $F_n $TEST... ${YELLOW}Feature $F not configured in $SOCAT${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif ! A=$(testaddrs STDIO SHELL PIPE); then $PRINTF "test $F_n $TEST... ${YELLOW}Address $A not available in $SOCAT${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif ! o=$(testoptions setsid sigint) >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}Option $o not available in $SOCAT${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" else tf="$td/test$N.stdout" te="$td/test$N.stderr" tdiff="$td/test$N.diff" da="test$N $(date) $RANDOM" #CMD0="$TRACE $SOCAT $opts -T 2 PIPE EXEC:\"socat\ -d\ -d\ -d\ -d\ -lu\ PIPE\ PIPE\",pty,setsid,sigint" #CMD0="$TRACE $SOCAT $opts -T 2 PIPE EXEC:\"$CAT\",pty,setsid,sigint" CMD0="$TRACE $SOCAT $opts -T 2 SOCKETPAIR EXEC:\"$CAT\",pty,setsid,sigint" printf "test $F_n $TEST... " $N eval $CMD0 >/dev/null 2>"${te}0" & $CMD0 >/dev/null 2>"${te}0" & pid0=$! sleep 1 kill -INT $pid0 wait if grep -q " W waitpid..: child .* exited with status 130" "${te}0" || grep -q " W waitpid..: child .* exited on signal 2" "${te}0"; then $PRINTF "$OK\n" if [ "$VERBOSE" ]; then echo "$CMD0 &"; fi if [ "$DEBUG" ]; then cat "${te}0" >&2; fi numOK=$((numOK+1)) else $PRINTF "$FAILED\n" echo "$CMD0 &" cat "${te}0" >&2 numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" namesFAIL="$namesFAIL $NAME" fi fi # NUMCOND ;; esac N=$((N+1)) # Test the SHELL address with socketpair (default) NAME=SHELL_SOCKETPAIR case "$TESTS" in *%$N%*|*%functions%*|*%shell%*|*%socketpair%*|*%$NAME%*) TEST="$NAME: simple echo via SHELL of cat with socketpair" # testecho ... if ! eval $NUMCOND; then :; elif ! F=$(testfeats STDIO SHELL); then $PRINTF "test $F_n $TEST... ${YELLOW}Feature $F not configured in $SOCAT${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif ! A=$(testaddrs STDIO SHELL); then $PRINTF "test $F_n $TEST... ${YELLOW}Address $A not available in $SOCAT${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" else testecho "$N" "$TEST" "" "SHELL:$CAT" "$opts" "$val_t" fi esac N=$((N+1)) # Test the SHELL address with pipes NAME=SHELL_PIPES case "$TESTS" in *%$N%*|*%functions%*|*%shell%*|*%pipe%*|*%$NAME%*) TEST="$NAME: simple echo via SHELL of cat with pipes" # testecho ... if ! eval $NUMCOND; then :; elif ! F=$(testfeats STDIO SHELL SOCKETPAIR); then $PRINTF "test $F_n $TEST... ${YELLOW}Feature $F not configured in $SOCAT${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif ! A=$(testaddrs STDIO SHELL PIPE); then $PRINTF "test $F_n $TEST... ${YELLOW}Address $A not available in $SOCAT${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" else testecho "$N" "$TEST" "" "SHELL:$CAT,pipes" "$opts" "$val_t" fi esac N=$((N+1)) # Test the SHELL address with pty NAME=SHELL_PTY case "$TESTS" in *%$N%*|*%functions%*|*%shell%*|*%pty%*|*%$NAME%*) TEST="$NAME: simple echo via SHELL of cat with pty" # testecho ... if ! eval $NUMCOND; then :; elif ! F=$(testfeats STDIO SHELL PTY); then $PRINTF "test $F_n $TEST... ${YELLOW}Feature $F not configured in $SOCAT${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif ! A=$(testaddrs STDIO SHELL PTY); then $PRINTF "test $F_n $TEST... ${YELLOW}Address $A not available in $SOCAT${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" else testecho "$N" "$TEST" "" "SHELL:$CAT,pty,$PTYOPTS,$PTYOPTS2" "$opts" "$val_t" fi esac N=$((N+1)) # Test the SHELL address halfclose with socketpair NAME=SHELL_SOCKETPAIR_FLUSH case "$TESTS" in *%$N%*|*%functions%*|*%shell%*|*%socketpair%*|*%halfclose%*|*%$NAME%*) TEST="$NAME: call od -c via SHELL using socketpair" # testecho ... if ! eval $NUMCOND; then :; elif ! F=$(testfeats STDIO SHELL); then $PRINTF "test $F_n $TEST... ${YELLOW}Feature $F not configured in $SOCAT${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif ! A=$(testaddrs STDIO SHELL); then $PRINTF "test $F_n $TEST... ${YELLOW}Address $A not available in $SOCAT${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" else testod "$N" "$TEST" "" "SHELL:$OD_C" "$opts" "$val_t" fi esac N=$((N+1)) # Test SHELL address halfclose with pipes NAME=SHELL_PIPES case "$TESTS" in *%$N%*|*%functions%*|*%shell%*|*%pipe%*|*%halfclose%*|*%$NAME%*) TEST="$NAME: call od -c via SHELL using pipes" # testecho ... if ! eval $NUMCOND; then :; elif ! F=$(testfeats STDIO SHELL SOCKETPAIR); then $PRINTF "test $F_n $TEST... ${YELLOW}Feature $F not configured in $SOCAT${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif ! A=$(testaddrs STDIO SHELL PIPE); then $PRINTF "test $F_n $TEST... ${YELLOW}Address $A not available in $SOCAT${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" else testod "$N" "$TEST" "" "SHELL:$OD_C,pipes" "$opts" "$val_t" fi esac N=$((N+1)) # Test the sigint option with SYSTEM address NAME=SYSTEM_SIGINT case "$TESTS" in *%$N%*|*%functions%*|*%socket%*|*%progcall%*|*%system%*|*%sigint%*|*%$NAME%*) TEST="$NAME: sigint option with SYSTEM" # Run Socat with a SYSTEM address invoking Socat, with option sigint # Send the parent a SIGINT; when the child gets SIGINT too (vs.SIGTERM) # the test succeeded # setsid is required so the initial SIGINT is not delivered to the sub process. if ! eval $NUMCOND; then :; # Remove unneeded checks, adapt lists of the remaining ones elif ! F=$(testfeats STDIO SYSTEM PIPE); then $PRINTF "test $F_n $TEST... ${YELLOW}Feature $F not configured in $SOCAT${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif ! A=$(testaddrs STDIO SYSTEM PIPE); then $PRINTF "test $F_n $TEST... ${YELLOW}Address $A not available in $SOCAT${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif ! o=$(testoptions setsid sigint) >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}Option $o not available in $SOCAT${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" else tf="$td/test$N.stdout" te="$td/test$N.stderr" tdiff="$td/test$N.diff" da="test$N $(date) $RANDOM" #CMD0="$TRACE $SOCAT $opts PIPE SHELL:\"$SOCAT\ -dddd\ -lf ${te}1\ PIPE\ PIPE\",setsid,sigint" CMD0="$TRACE $SOCAT $opts SOCKETPAIR SHELL:\"$SOCAT\ -dddd\ -lf ${te}1\ PIPE\ PIPE\",setsid,sigint" printf "test $F_n $TEST... " $N eval $CMD0 >/dev/null 2>"${te}0" & pid0=$! sleep 1 kill -INT $(childpids $pid0) wait if grep -q " W waitpid..: child .* exited with status 130" "${te}0"; then $PRINTF "$OK\n" if [ "$VERBOSE" ]; then echo "$CMD0 &"; fi if [ "$DEBUG" ]; then cat "${te}0" >&2; fi numOK=$((numOK+1)) else $PRINTF "$FAILED\n" echo "$CMD0 &" cat "${te}0" >&2 numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" namesFAIL="$namesFAIL $NAME" fi fi # NUMCOND ;; esac N=$((N+1)) # Test the res-nsaddr (resolver, dns) option NAME=RES_NSADDR case "$TESTS" in *%$N%*|*%functions%*|*%resolv%*|*%ip4%*|*%tcp4%*|*%socket%*|*%$NAME%*) TEST="$NAME: test the res-nsaddr option" # Start a supplementary Socat instance that will receive the DNS query. # Run main Socat process, opening an IPv4 socket with option res-nsaddr # directed to the aux process. # When the supplementary Socat instance received the query the test succeeded. if ! eval $NUMCOND; then :; elif ! F=$(testfeats STDIO IP4 UDP TCP); then $PRINTF "test $F_n $TEST... ${YELLOW}Feature $F not configured in $SOCAT${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif ! A=$(testaddrs STDIO TCP4 UDP-RECVFROM); then $PRINTF "test $F_n $TEST... ${YELLOW}Address $A not available in $SOCAT${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif ! o=$(testoptions res-nsaddr) >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}Option $o not available in $SOCAT${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif ! runsip4 >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}IPv4 not available on host${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" else tf="$td/test$N.stdout" te="$td/test$N.stderr" tdiff="$td/test$N.diff" da="$(echo test$N $(date) $RANDOM |tr ' :' '-')" echo "$da" >"$td/test$N.da" newport udp4 # or whatever proto, or drop this line CMD0="$TRACE $SOCAT $opts -u UDP-RECVFROM:$PORT -" CMD1="$TRACE $SOCAT $opts - TCP4:$da:0,res-nsaddr=$LOCALHOST:$PORT" printf "test $F_n $TEST... " $N $CMD0 >/dev/null 2>"${te}0" >"${tf}0" & pid0=$! waitudp4port $PORT 1 $CMD1 >"${tf}1" 2>"${te}1" rc1=$? kill $pid0 2>/dev/null; wait if grep "$da" "${tf}0" >/dev/null; then $PRINTF "$OK\n" if [ "$VERBOSE" ]; then echo "$CMD0 &"; fi if [ "$DEBUG" ]; then cat "${te}0" >&2; fi if [ "$VERBOSE" ]; then echo "$CMD1"; fi if [ "$DEBUG" ]; then cat "${te}1" >&2; fi numOK=$((numOK+1)) elif pgrep -u root nscd >/dev/null 2>&1; then $PRINTF "${YELLOW}FAILED (due to nscd?)${NORMAL}\n" if [ "$VERBOSE" ]; then echo "$CMD0 &"; fi if [ "$DEBUG" ]; then cat "${te}0" >&2; fi if [ "$VERBOSE" ]; then echo "$CMD1"; fi if [ "$DEBUG" ]; then cat "${te}1" >&2; fi numCANT=$((numCANT+1)) listCANT="$listCANT $N" namesCAnT="$namesCANT $NAME" else $PRINTF "$FAILED (query not received)\n" echo "$CMD0 &" cat "${te}0" >&2 echo "$CMD1" cat "${te}1" >&2 numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" namesFAIL="$namesFAIL $NAME" fi fi # NUMCOND ;; esac N=$((N+1)) # Some of the following tests need absolute path of Socat case "$SOCAT" in /*) absSOCAT="$SOCAT" ;; *) absSOCAT="$PWD/$SOCAT" ;; esac # Test the chdir option, in particular if chdir with the first address # (CREATE) does not affect pwd of second address, i.e. original pwd is # recovered NAME=CHDIR_ON_CREATE case "$TESTS" in *%$N%*|*%functions%*|*%creat%*|*%system%*|*%chdir%*|*%$NAME%*) TEST="$NAME: restore of pwd after CREAT with chdir option" # Run Socat with first address CREAT with modified chdir, # and second address SYSTEM (shell) with pwd command # Check if the file is created with modified pwd but shell has original pwd if ! eval $NUMCOND; then :; elif ! F=$(testfeats CREAT SYSTEM); then $PRINTF "test $F_n $TEST... ${YELLOW}Feature $F not configured in $SOCAT${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif ! A=$(testaddrs - CREAT SYSTEM); then $PRINTF "test $F_n $TEST... ${YELLOW}Address $A not available in $SOCAT${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif ! o=$(testoptions chdir) >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}Option $o not available in $SOCAT${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" else tf="$td/test$N.stdout" te="$td/test$N.stderr" tc="test$N.creat" tdd="test$N.d" tdiff="$td/test$N.diff" tdebug="$td/test$N.debug" opwd=$(pwd) CMD0="$TRACE $absSOCAT $opts -U CREAT:$tc,chdir=$td SYSTEM:pwd" printf "test $F_n $TEST... " $N mkdir "$td/$tdd" pushd "$td/$tdd" >/dev/null $CMD0 >/dev/null 2>"${te}0" rc0=$? popd >/dev/null tpwd=$(find $td -name $tc -print); tpwd=${tpwd%/*} pwd2=$(cat $tpwd/$tc >$tdebug echo "Temporary pwd: $tpwd" >>$tdebug echo "Addr2 pwd: $pwd2" >>$tdebug if [ "$rc0" -ne 0 ]; then $PRINTF "$FAILED\n" echo "$CMD0 &" cat "${te}0" >&2 numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" namesFAIL="$namesFAIL $NAME" elif [ "$tpwd" != "$td" ]; then $PRINTF "$FAILED (chdir failed)\n" echo "$CMD0 &" cat "${te}0" >&2 numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" namesFAIL="$namesFAIL $NAME" elif ! echo "$pwd2" |diff "$td/$tc" - >$tdiff; then $PRINTF "$FAILED (bad pwd2)\n" echo "$CMD0 &" cat "${te}0" >&2 echo "// diff:" >&2 cat "$tdiff" >&2 numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" namesFAIL="$namesFAIL $NAME" else $PRINTF "$OK\n" if [ "$VERBOSE" ]; then echo "$CMD0 &"; fi if [ "$DEBUG" ]; then cat "${te}0" >&2; fi numOK=$((numOK+1)) fi fi # NUMCOND ;; esac N=$((N+1)) # Test the chdir option, in particular if chdir with first address # (SHELL) does not affect pwd of second address, i.e. original pwd is # recovered NAME=CHDIR_ON_SHELL case "$TESTS" in *%$N%*|*%functions%*|*%shell%*|*%system%*|*%chdir%*|*%$NAME%*) TEST="$NAME: restore of pwd after SYSTEM with chdir option" # Run Socat with first address SYSTEM:"cat >file" with chdir, # and second address SYSTEM (shell) with pwd command. # Check if the file is created with modified pwd but shell has original pwd if ! eval $NUMCOND; then :; elif ! F=$(testfeats SHELL SYSTEM); then $PRINTF "test $F_n $TEST... ${YELLOW}Feature $F not configured in $SOCAT${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif ! A=$(testaddrs SHELL SYSTEM); then $PRINTF "test $F_n $TEST... ${YELLOW}Address $A not available in $SOCAT${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif ! o=$(testoptions chdir) >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}Option $o not available in $SOCAT${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" else tf="$td/test$N.stdout" te="$td/test$N.stderr" tc="test$N.creat" tdd="test$N.d" tdiff="$td/test$N.diff" tdebug="$td/test$N.debug" opwd=$(pwd) CMD0="$TRACE $absSOCAT $opts SHELL:\"cat\ >$tc\",chdir=$td SYSTEM:pwd" printf "test $F_n $TEST... " $N mkdir "$td/$tdd" pushd "$td/$tdd" >/dev/null eval "$CMD0" >/dev/null 2>"${te}0" rc0=$? popd >/dev/null waitfile "$td/$tc" tpwd=$(find $td -name $tc -print); tpwd=${tpwd%/*} pwd2=$(cat $tpwd/$tc >$tdebug echo "Temporary pwd: $tpwd" >>$tdebug echo "Addr2 pwd: $pwd2" >>$tdebug if [ "$rc0" -ne 0 ]; then $PRINTF "$FAILED (rc=$rc0)\n" echo "$CMD0 &" cat "${te}0" >&2 numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" namesFAIL="$namesFAIL $NAME" elif [ "$tpwd" != "$td" ]; then $PRINTF "$FAILED (chdir failed)\n" echo "$CMD0 &" cat "${te}0" >&2 numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" namesFAIL="$namesFAIL $NAME" elif ! echo "$pwd2" |diff "$td/$tc" - >$tdiff; then $PRINTF "$FAILED (bad pwd)\n" echo "$CMD0 &" cat "${te}0" >&2 echo "// diff:" >&2 cat "$tdiff" >&2 numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" namesFAIL="$namesFAIL $NAME" else $PRINTF "$OK\n" if [ "$VERBOSE" ]; then echo "$CMD0 &"; fi if [ "$DEBUG" ]; then cat "${te}0" >&2; fi numOK=$((numOK+1)) fi fi # NUMCOND ;; esac N=$((N+1)) # Test the modified umask option, in particular if umask with first address # (CREATE) does not affect umask of second address, i.e. original umask is # recovered NAME=UMASK_ON_CREATE case "$TESTS" in *%$N%*|*%functions%*|*%creat%*|*%system%*|*%umask%*|*%$NAME%*) TEST="$NAME: test restore after CREAT with umask option" # Run Socat with first address CREAT with modified umask, # and second address SYSTEM (shell) with umask command # Check if the file is created with modified umask but shell has original umask if ! eval $NUMCOND; then :; elif ! F=$(testfeats CREAT SYSTEM); then $PRINTF "test $F_n $TEST... ${YELLOW}Feature $F not configured in $SOCAT${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif ! A=$(testaddrs CREAT SYSTEM); then $PRINTF "test $F_n $TEST... ${YELLOW}Address $A not available in $SOCAT${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif ! o=$(testoptions umask) >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}Option $o not available in $SOCAT${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" else tf="$td/test$N.stdout" te="$td/test$N.stderr" tc="$td/test$N.creat" tdiff="$td/test$N.diff" tdebug="$td/test$N.debug" oumask=$(umask) # Construct a temp umask differing from original umask case oumask in *066) tumask=0026 ;; *) tumask=0066 ;; esac CMD0="$TRACE $SOCAT $opts -U CREAT:$tc,umask=$tumask SYSTEM:umask" printf "test $F_n $TEST... " $N $CMD0 >/dev/null 2>"${te}0" rc0=$? tperms=$(fileperms $tc) case $tperms in 0*) ;; *) tperms=0$tperms ;; esac echo "Original umask: $oumask" >>$tdebug echo "Temporary umask: $tumask" >>$tdebug echo "Created umask: $tperms" >>$tdebug if [ "$rc0" -ne 0 ]; then $PRINTF "$FAILED\n" echo "$CMD0 &" cat "${te}0" >&2 numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" namesFAIL="$namesFAIL $NAME" elif [ $((tumask + tperms - 0666)) -ne 0 ]; then $PRINTF "$FAILED (umask failed)\n" echo "$CMD0 &" cat "${te}0" >&2 numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" namesFAIL="$namesFAIL $NAME" elif ! echo "$oumask" |diff "$tc" - >$tdiff; then $PRINTF "$FAILED (bad umask)\n" echo "$CMD0 &" cat "${te}0" >&2 numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" namesFAIL="$namesFAIL $NAME" else $PRINTF "$OK\n" if [ "$VERBOSE" ]; then echo "$CMD0 &"; fi if [ "$DEBUG" ]; then cat "${te}0" >&2; fi numOK=$((numOK+1)) fi fi # NUMCOND ;; esac N=$((N+1)) # Test the modified umask option, in particular if umask with first address # (SHELL) does not affect umask of second address, i.e. original umask is # recovered NAME=UMASK_ON_SYSTEM case "$TESTS" in *%$N%*|*%functions%*|*%shell%*|*%system%*|*%umask%*|*%socket%*|*%$NAME%*) TEST="$NAME: test restore after SHELL with umask option" # Run Socat with first address SHELL:"cat >file" with modified umask, # and second address SYSTEM (shell) with umask command. # Check if the file is created with modified umask but shell has original umask if ! eval $NUMCOND; then :; elif ! F=$(testfeats SHELL SYSTEM); then $PRINTF "test $F_n $TEST... ${YELLOW}Feature $F not configured in $SOCAT${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif ! A=$(testaddrs SHELL SYSTEM); then $PRINTF "test $F_n $TEST... ${YELLOW}Address $A not available in $SOCAT${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif ! o=$(testoptions umask) >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}Option $o not available in $SOCAT${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" else tf="$td/test$N.stdout" te="$td/test$N.stderr" tc="$td/test$N.creat" tdiff="$td/test$N.diff" tdebug="$td/test$N.debug" oumask=$(umask) # Construct a temp umask differing from original umask case oumask in *066) tumask=0026 ;; *) tumask=0066 ;; esac CMD0="$TRACE $SOCAT $opts -U SHELL:\"cat\ >$tc\",umask=$tumask SYSTEM:umask" printf "test $F_n $TEST... " $N eval "$CMD0" >/dev/null 2>"${te}0" rc0=$? tperms=$(fileperms $tc) case $tperms in 0*) ;; *) tperms=0$tperms ;; esac echo "Original umask: $oumask" >>$tdebug echo "Temporary umask: $tumask" >>$tdebug echo "Created umask: $tperms" >>$tdebug if [ "$rc0" -ne 0 ]; then $PRINTF "$FAILED\n" echo "$CMD0 &" cat "${te}0" >&2 numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" namesFAIL="$namesFAIL $NAME" elif [ $((tumask + tperms - 0666)) -ne 0 ]; then $PRINTF "$FAILED (umask failed)\n" echo "$CMD0 &" cat "${te}0" >&2 numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" namesFAIL="$namesFAIL $NAME" elif ! echo "$oumask" |diff "$tc" - >$tdiff; then $PRINTF "$FAILED (bad umask)\n" echo "$CMD0 &" cat "${te}0" >&2 numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" namesFAIL="$namesFAIL $NAME" else $PRINTF "$OK\n" if [ "$VERBOSE" ]; then echo "$CMD0 &"; fi if [ "$DEBUG" ]; then cat "${te}0" >&2; fi numOK=$((numOK+1)) fi fi # NUMCOND ;; esac N=$((N+1)) while read _UNIX _SRV _CLI; do if [ -z "$_UNIX" ] || [[ "$_UNIX" == \#* ]]; then continue; fi SRV=${_UNIX}-$_SRV CLI=${_UNIX}-$_CLI CLI_=$(echo $CLI |tr x- x_) PROTO=${_UNIX} proto=$(tolower $PROTO) # Test the unix-bind-tempname option NAME=${_UNIX}_${_SRV}_${_CLI}_BIND_TEMPNAME case "$TESTS" in *%$N%*|*%functions%*|*%$proto%*|*%socket%*|*%tempname%*|*%listen%*|*%fork%*|*%$NAME%*) TEST="$NAME: Option unix-bind-tempname" # Start a UNIX domain service with forking # Start a TCP service with forking that relays to the UNIX domain service # Open two concurrent client sessions to the TCP service. # When both sessions work (in particular, when the UNIX domain service does not # log "Transport endpoint is not connected" and the TCP service does not fail # with "Address already in use"), the test succeeded. if ! eval $NUMCOND; then :; elif [[ $CLI_ =~ ABSTRACT-* ]] && ! feat=$(testfeats abstract-unixsocket); then $PRINTF "test $F_n $TEST... ${YELLOW}$feat not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" else ts="$td/test$N.sock" tf="$td/test$N.stdout" te="$td/test$N.stderr" tdiff="$td/test$N.diff" da="test$N $(date) $RANDOM" CMD0="$TRACE $SOCAT $opts -lp server $SRV:${ts}0,fork PIPE" # Using this command would show the principal problem: UNIX (and ABSTRACT) # datagram clients do not internally bind to a defined address and thus cannot # receive replies. Applies to all(?) Linux, (some)FreeBSD, (some)Solaris, others # not tried #CMD1="$TRACE $SOCAT $opts -lp bind-tempname TCP4-LISTEN:$PORT,reuseaddr,fork $CLI:${ts}0" # Attempt to bind the datagram client to some address works, but only for a # single client; when multiple clients are forked they conflict # The following command is the solution: option unix-bind-tempname generates # random names (like tempnam(2)) for binding the datagram client socket; # creating the XXXXXX file makes sure that the (non abstract) clients cannot # erronously bind there (part of the test) CMD1="$TRACE $SOCAT $opts -lp bind-tempname TCP4-LISTEN:$PORT,reuseaddr,fork $CLI:${ts}0,bind=${ts}1" touch ${ts}1.XXXXXX; CMD1="$TRACE $SOCAT $opts -lp tempname TCP4-LISTEN:$PORT,reuseaddr,fork $CLI:${ts}0,bind-tempname=${ts}1.XXXXXX" CMD2="$TRACE $SOCAT $opts -lp client - TCP4-CONNECT:$LOCALHOST:$PORT" printf "test $F_n $TEST... " $N $CMD0 2>"${te}0" & pid0=$! wait${proto}port ${ts}0 1 $CMD1 2>"${te}1" & pid1=$! waittcp4port $PORT 1 { echo "$da a"; sleep 2; } |$CMD2 >"${tf}2a" 2>"${te}2a" & pid2a=$! sleep 1 echo "$da b" |$CMD2 >"${tf}2b" 2>"${te}2b" rc2b=$? sleep 1 kill $pid0 $pid1 $pid2a 2>/dev/null; wait if [ $rc2b -ne 0 ]; then $PRINTF "$FAILED\n" echo "$CMD0 &" cat "${te}0" >&2 echo "$CMD1 &" cat "${te}1" >&2 echo "$CMD2 &" cat "${te}2a" >&2 echo "$CMD2" cat "${te}2b" >&2 numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" elif ! echo "$da a" |diff - ${tf}2a >${tdiff}2a; then $PRINTF "$FAILED (phase a)\n" echo "$CMD0 &" cat "${te}0" >&2 echo "$CMD1 &" cat "${te}1" >&2 echo "$CMD2" cat "${te}2a" >&2 echo "diff a:" >&2 cat ${tdiff}2a >&2 numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" elif ! echo "$da b" |diff - ${tf}2b >${tdiff}2b; then $PRINTF "$FAILED\n" echo "$CMD0 &" cat "${te}0" >&2 echo "$CMD1 &" cat "${te}1" >&2 echo "$CMD2 &" cat "${te}2a" >&2 echo "$CMD2" cat "${te}2b" >&2 echo "diff b:" >&2 cat ${tdiff}2b >&2 numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" else $PRINTF "$OK\n" if [ "$VERBOSE" ]; then echo "$CMD0 &"; fi if [ "$DEBUG" ]; then cat "${te}0" >&2; fi if [ "$VERBOSE" ]; then echo "$CMD1"; fi if [ "$DEBUG" ]; then cat "${te}1" >&2; fi if [ "$VERBOSE" ]; then echo "$CMD2"; fi if [ "$DEBUG" ]; then cat "${te}2a" >&2; fi if [ "$VERBOSE" ]; then echo "$CMD2"; fi if [ "$DEBUG" ]; then cat "${te}2b" >&2; fi numOK=$((numOK+1)) fi fi # NUMCOND ;; esac PORT=$((PORT+1)) N=$((N+1)) done <<<" UNIX LISTEN CONNECT UNIX LISTEN CLIENT UNIX RECVFROM CLIENT UNIX RECVFROM SENDTO ABSTRACT LISTEN CONNECT ABSTRACT LISTEN CLIENT ABSTRACT RECVFROM CLIENT ABSTRACT RECVFROM SENDTO " # Test if OS/libc is not prone to symlink attacks on UNIX bind() NAME=TEMPNAME_SEC case "$TESTS" in *%$N%*|*%functions%*|*%bugs%*|*%socket%*|*%unix%*|*%dgram%*|*%security%*|*%$NAME%*) TEST="$NAME: test if a symlink attack works against bind()" # Create a symlink .sock2 pointing to non-existing .sock3 # Start Socat with UNIX-SENDTO...,bind=.sock2 # When .sock3 exists the test failed if ! eval $NUMCOND; then :; else tf="$td/test$N.stdout" te="$td/test$N.stderr" ts1="$td/test$N.sock1" ts2="$td/test$N.sock2" ts3="$td/test$N.sock3" tdiff="$td/test$N.diff" da="test$N $(date) $RANDOM" CMD0a="rm -f $ts3" CMD0b="ln -s $ts3 $ts2" CMD1="$TRACE $SOCAT $opts UNIX-SENDTO:$ts1,bind=$ts2 PIPE" rc1=$? printf "test $F_n $TEST... " $N $CMD0a $CMD0b #echo; ls -l $ts2 $ts3 $CMD1 2>"${te}1" & pid1=$! waitunixport $ts1 1 1 2>/dev/null #res="$(ls -l $ts3 2>/dev/null)" kill $pid1 2>/dev/null if [ -e $ts3 ]; then $PRINTF "$FAILED\n" echo "symlink target has been created" >&2 echo "$CMD0a" >&2 cat "${te}0a" >&2 echo "$CMD0b" >&2 cat "${te}0b" >&2 echo "$CMD1" >&2 cat "${te}1" >&2 numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" elif ! grep -q " E " ${te}1; then $PRINTF "$FAILED\n" echo "Socat did not fail" echo "$CMD0a" >&2 cat "${te}0a" >&2 echo "$CMD0b" >&2 cat "${te}0b" >&2 echo "$CMD1" >&2 cat "${te}1" >&2 numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" else $PRINTF "$OK\n" if [ "$VERBOSE" ]; then echo "$CMD0a"; fi if [ "$DEBUG" ]; then cat "${te}0a" >&2; fi if [ "$VERBOSE" ]; then echo "$CMD0b"; fi if [ "$DEBUG" ]; then cat "${te}0b" >&2; fi if [ "$VERBOSE" ]; then echo "$CMD1"; fi if [ "$DEBUG" ]; then cat "${te}1" >&2; fi numOK=$((numOK+1)) fi fi # NUMCOND ;; esac PORT=$((PORT+1)) N=$((N+1)) # Test the new f-setpipe-sz option on a STDIN pipe NAME=STDIN_F_SETPIPE_SZ case "$TESTS" in *%$N%*|*%functions%*|*%filan%*|*%dual%*|*%stdio%*|*%exec%*|*%pipe%*|*%f-setpipe-sz%*|*%$NAME%*) TEST="$NAME: f-setpipe-sz on STDIN" # Start Socat in a shell pipe and have it calling Filan via EXEC and nofork # Check Filan output if pipe size of its input pipe is modified. if ! eval $NUMCOND; then :; # Remove unneeded checks, adapt lists of the remaining ones elif ! $(type true >/dev/null 2>&1); then $PRINTF "test $F_n $TEST... ${YELLOW}true not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif ! F=$(testfeats STDIO EXEC); then $PRINTF "test $F_n $TEST... ${YELLOW}Feature $F not configured in $SOCAT${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif ! A=$(testaddrs STDIO EXEC); then $PRINTF "test $F_n $TEST... ${YELLOW}Address $A not available in $SOCAT${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif ! o=$(testoptions f-setpipe-sz nofork) >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}Option $o not available in $SOCAT${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" else tf="$td/test$N.stdout" te="$td/test$N.stderr" tdiff="$td/test$N.diff" da="test$N $(date) $RANDOM" newport tcp4 # or whatever proto, or drop this line # Find the default pipe size PIPESZ="$(echo |$FILAN -n 0 |grep "0:" |head -n 1 |sed 's/.*F_GETPIPE_SZ=\([0-9][0-9]*\).*/\1/')" PIPESZ2=$((2*PIPESZ)) CMD0="$TRACE $SOCAT $opts STDIN,f-setpipe-sz=$PIPESZ2!!STDOUT EXEC:$FILAN,nofork" printf "test $F_n $TEST... " $N true |$CMD0 >"${tf}" 2>"${te}0" rc0=$? PIPESZ2b="$(cat "$tf" |grep "0:" |head -n 1 |sed 's/.*F_GETPIPE_SZ=\([0-9][0-9]*\).*/\1/')" if [ "$rc0" -ne 0 ]; then $PRINTF "$FAILED\n" echo "$CMD0" cat "${te}0" >&2 numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" namesFAIL="$namesFAIL $NAME" elif ! diff <(echo $PIPESZ2) <(echo $PIPESZ2b) >$tdiff; then $PRINTF "$FAILED\n" echo "$CMD0" cat "${te}0" >&2 echo "diff:" >&2 cat "$tdiff" >&2 numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" namesFAIL="$namesFAIL $NAME" else $PRINTF "$OK\n" if [ "$VERBOSE" ]; then echo "$CMD0"; fi if [ "$DEBUG" ]; then cat "${te}0" >&2; fi numOK=$((numOK+1)) fi fi # NUMCOND ;; esac N=$((N+1)) # Test the new f-setpipe-sz option on EXEC with pipes NAME=EXEC_F_SETPIPE_SZ case "$TESTS" in *%$N%*|*%functions%*|*%filan%*|*%stdio%*|*%exec%*|*%pipe%*|*%f-setpipe-sz%*|*%$NAME%*) TEST="$NAME: f-setpipe-sz on EXEC with pipes" # Start Socat calling Filan via EXEC and pipes and f-setpipe-sz # Check Filan output if pipe size of both pipes is modified. if ! eval $NUMCOND; then :; # Remove unneeded checks, adapt lists of the remaining ones elif ! F=$(testfeats STDIO EXEC); then $PRINTF "test $F_n $TEST... ${YELLOW}Feature $F not configured in $SOCAT${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif ! A=$(testaddrs STDIO EXEC); then $PRINTF "test $F_n $TEST... ${YELLOW}Address $A not available in $SOCAT${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif ! o=$(testoptions pipes f-setpipe-sz) >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}Option $o not available in $SOCAT${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" else tf="$td/test$N.stdout" te="$td/test$N.stderr" tdiff="$td/test$N.diff" # Find the default pipe size PIPESZ="$(echo |$FILAN -n 0 |grep "0:" |head -n 1 |sed 's/.*F_GETPIPE_SZ=\([0-9][0-9]*\).*/\1/')" PIPESZ2=$((2*PIPESZ)) CMD0="$TRACE $SOCAT $opts STDIO EXEC:$FILAN,pipes,f-setpipe-sz=$PIPESZ2" printf "test $F_n $TEST... " $N $CMD0 >"$tf" 2>"${te}0" rc0=$? PIPESZ2b="$(cat "$tf" |grep "0:" |head -n 1 |sed 's/.*F_GETPIPE_SZ=\([0-9][0-9]*\).*/\1/')" if [ "$rc0" -ne 0 ]; then $PRINTF "$FAILED\n" echo "$CMD0" cat "${te}0" >&2 numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" namesFAIL="$namesFAIL $NAME" elif ! diff <(echo $PIPESZ2) <(echo $PIPESZ2b) >$tdiff; then $PRINTF "$FAILED\n" echo "$CMD0 &" cat "${te}0" >&2 echo "diff:" >&2 cat "$tdiff" >&2 numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" namesFAIL="$namesFAIL $NAME" else $PRINTF "$OK\n" if [ "$VERBOSE" ]; then echo "$CMD0"; fi if [ "$DEBUG" ]; then cat "${te}0" >&2; fi numOK=$((numOK+1)) fi fi # NUMCOND ;; esac N=$((N+1)) # end of common tests ################################################################################## #================================================================================= # here come tests that might affect your systems integrity. Put normal tests # before this paragraph. # tests must be explicitely selected by roottough or name (not number) NAME=PTYGROUPLATE case "$TESTS" in *%roottough%*|*%$NAME%*) TEST="$NAME: pty with group-late works on pty" # up to socat 1.7.1.1 address pty changed the ownership of /dev/ptmx instead of # the pty with options user-late, group-late, or perm-late. # here we check for correct behaviour. # ATTENTION: in case of failure of this test the # group of /dev/ptmx might be changed! if ! eval $NUMCOND; then :; else # save current /dev/ptmx properties F= for f in /dev/ptmx /dev/ptc; do if [ -e $f ]; then F=$(echo "$f" |tr / ..) ls -l $f >"$td/test$N.$F.ls-l" break fi done printf "test $F_n $TEST... " $N if [ -z "$F" ]; then echo -e "${YELLOW}no /dev/ptmx or /dev/ptc${NORMAL}" else GROUP=daemon tf="$td/test$N.stdout" te="$td/test$N.stderr" tl="$td/test$N.pty" tdiff="$td/test$N.diff" da="test$N $(date) $RANDOM" CMD0="$TRACE $SOCAT $opts pty,link=$tl,group-late=$GROUP,escape=0x1a PIPE" CMD1="$TRACE $SOCAT $opts - $tl,raw,echo=0" $CMD0 >/dev/null 2>"${te}0" & pid0=$! (echo "$da"; usleep $MICROS; echo -e "\x1a") |$CMD1 >"${tf}1" 2>"${te}1" >"$tf" rc1=$? kill $pid0 2>/dev/null; wait if [ $rc1 -ne 0 ]; then $PRINTF "$FAILED\n" echo "$CMD0 &" echo "$CMD1" cat "${te}0" cat "${te}1" numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" elif echo "$da" |diff - "$tf" >$tdiff; then $PRINTF "$OK\n" numOK=$((numOK+1)) else $PRINTF "$FAILED\n" cat "$tdiff" numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" fi if ! ls -l $f |diff "$td/test$N.$F.ls-l" -; then $PRINTF "${RED}this test changed properties of $f!${NORMAL}\n" fi fi # no /dev/ptmx fi # NUMCOND ;; esac N=$((N+1)) echo "Used temp directory $TD - you might want to remove it after analysis" echo "Summary: $((N-1)) tests, $((numOK+numFAIL+numCANT)) selected; $numOK ok, $numFAIL failed, $numCANT could not be performed" set -- $listCANT; while [ "$1" ]; do echo "$1"; shift; done >"$td/cannot.lst" ln -sf "$td/cannot.lst" . set -- $listFAIL; while [ "$1" ]; do echo "$1"; shift; done >"$td/failed.lst" ln -sf "$td/failed.lst" . sort -n <(cat "$td/cannot.lst" |while read x; do echo "$x CANT"; done) <(cat "$td/failed.lst" |while read x; do echo "$x FAILED"; done) >"$td/result.txt" ln -sf "$td/result.txt" . if [ "$numCANT" -gt 0 ]; then echo "CANT: $listCANT" fi if [ "$numFAIL" -gt 0 ]; then echo "FAILED: $listFAIL" fi if [ -z "$OPT_EXPECT_FAIL" ]; then [ "$numFAIL" -eq 0 ] exit # with rc from above statement fi #set -vx if [ "$OPT_EXPECT_FAIL" ]; then diff <(set -- $(echo "$EXPECT_FAIL" |tr ',' ' '); while [ "$1" ]; do echo "$1"; shift; done) "$td/failed.lst" >"$td/failed.diff" ln -sf "$td/failed.diff" . #grep "^" grep "^> " "$td/failed.diff" |awk '{print($2);}' >"$td/failed.unexp" ln -s "$td/failed.unexp" . echo "FAILED unexpected: $(cat "$td/failed.unexp" |xargs echo)" grep "^< " "$td/failed.diff" |awk '{print($2);}' >"$td/ok.unexp" ln -s "$td/ok.unexp" . echo "OK unexpected: $(cat "$td/ok.unexp" |xargs echo)" else touch "$td/failed.diff" fi #listFAIL=$(cat "$td/failed.lst" |xargs echo) #numFAIL="$(wc -l "$td/failed.lst" |awk '{print($1);}')" ! test -s "$td/failed.unexp" exit #============================================================================== rm -f testsrv.* testcli.* testsrvdsa* testsrvfips* testclifips* # end # too dangerous - run as root and having a shell problem, it might purge your # file systems #rm -r "$td" # sometimes subprocesses hang; we want to see this wait exit #============================================================================== # test template # Give a description of what is tested (a bugfix, a new feature...) NAME=SHORT_UNIQUE_TESTNAME case "$TESTS" in *%$N%*|*%functions%*|*%bugs%*|*%socket%*|*%$NAME%*) #*%internet%*|*%root%*|*%listen%*|*%fork%*|*%ip4%*|*%tcp4%*|*%bug%*|... TEST="$NAME: give a one line description of test" # Describe how the test is performed, and what's the success criteria if ! eval $NUMCOND; then : # Remove unneeded checks, adapt lists of the remaining ones elif ! cond=$(checkconds \ "Linux,FreeBSD" \ "root" \ "nslookup" \ "IP4 TCP LISTEN STDIO PIPE" \ "TCP4-LISTEN PIPE STDIN STDOUT TCP4" \ "so-reuseaddr" \ "tcp4" ); then $PRINTF "test $F_n $TEST... ${YELLOW}$cond${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" namesCANT="$namesCANT $NAME" else tf="$td/test$N.stdout" te="$td/test$N.stderr" tdiff="$td/test$N.diff" da="test$N $(date) $RANDOM" newport tcp4 # or whatever proto, or drop this line CMD0="$TRACE $SOCAT $opts server-address PIPE" CMD1="$TRACE $SOCAT $opts - client-address" printf "test $F_n $TEST... " $N $CMD0 >/dev/null 2>"${te}0" & pid0=$! waitport $PORT 1 #relsleep 1 # if no matching wait*port function echo "$da" |$CMD1 >"${tf}1" 2>"${te}1" rc1=$? kill $pid0 2>/dev/null; wait if [ "$rc1" -ne 0 ]; then $PRINTF "$FAILED (rc1=$rc1)\n" echo "$CMD0 &" cat "${te}0" >&2 echo "$CMD1" cat "${te}1" >&2 numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" namesFAIL="$namesFAIL $NAME" elif ! echo "$da" |diff "${tf}1" - >$tdiff; then $PRINTF "$FAILED (diff)\n" echo "$CMD0 &" cat "${te}0" >&2 echo "$CMD1" cat "${te}1" >&2 echo "// diff:" >&2 cat "$tdiff" >&2 numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" namesFAIL="$namesFAIL $NAME" elif [ ??? ]; then # The test could not run meaningfully $PRINTF "$CANT\n" if [ "$VERBOSE" ]; then echo "$CMD0 &"; fi if [ "$DEBUG" ]; then cat "${te}0" >&2; fi if [ "$VERBOSE" ]; then echo "$CMD1"; fi if [ "$DEBUG" ]; then cat "${te}1" >&2; fi numCANT=$((numCANT+1)) listCANT="$listCANT $N" else $PRINTF "$OK\n" if [ "$VERBOSE" ]; then echo "$CMD0 &"; fi if [ "$DEBUG" ]; then cat "${te}0" >&2; fi if [ "$VERBOSE" ]; then echo "$CMD1"; fi if [ "$DEBUG" ]; then cat "${te}1" >&2; fi numOK=$((numOK+1)) fi fi # NUMCOND ;; esac N=$((N+1))