From cb6e16b360f51e932f3adc8f940ba6baa9d9eea7 Mon Sep 17 00:00:00 2001 From: Gerhard Rieger Date: Sun, 22 Oct 2023 23:15:49 +0200 Subject: [PATCH] TCP based clients try all results of name resolution until a connection succeeded --- CHANGES | 5 + test.sh | 306 ++++++++++++++++++++++++++++++++++++++------------ xio-ip.c | 184 +++++++++++++----------------- xio-ip.h | 7 +- xio-ip4.c | 4 +- xio-ip6.c | 16 ++- xio-ipapp.c | 75 ++++++++----- xio-ipapp.h | 2 +- xio-listen.c | 5 +- xio-openssl.c | 34 ++++-- xio-proxy.c | 24 ++-- xio-rawip.c | 2 +- xio-socket.c | 9 +- xio-socks.c | 32 ++++-- xio-udp.c | 7 +- xioopts.c | 6 +- 16 files changed, 456 insertions(+), 262 deletions(-) diff --git a/CHANGES b/CHANGES index e5d5480..e62e9e7 100644 --- a/CHANGES +++ b/CHANGES @@ -70,6 +70,11 @@ Features: addresses. reuseaddr= restores the old behaviour. Tests: TCP4_REUSEADDR OPENSSL_6_REUSEADDR REUSEADDR_NULL + TCP based client addresses now try all results of name resolution until + a connection attempt succeeded. + Tests: TRY_ADDRS_4 TRY_ADDRS_4_6 + Feature recommended by Anand Buddhdev. + Corrections: When a sub process (EXEC, SYSTEM) terminated with exit code other than 0, its last sent data might have been lost depending on timing of read/ diff --git a/test.sh b/test.sh index f82db61..193fbe7 100755 --- a/test.sh +++ b/test.sh @@ -154,7 +154,7 @@ fi MCINTERFACE=$INTERFACE [ -z "$MCINTERFACE" ] && MCINTERFACE=lo # !!! Linux only - and not always #LOCALHOST=192.168.58.1 -LOCALHOST=localhost +LOCALHOST=localhost # attention: on FreeBSD-10 localhost resolves primarily to IPv6 #LOCALHOST=127.0.0.1 LOCALHOST6="[::1]" #PROTO=$(awk '{print($2);}' /etc/protocols |sort -n |tail -n 1) @@ -977,9 +977,21 @@ runssctp6 () { return 0; } -# check if UNIX domain sockets work -runsunix () { - # for now... +# check if UNIX domain sockets work - see above +#runsunix () { +# # for now... +# 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; } @@ -3481,16 +3493,18 @@ 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}1\" &" -pid=$! # background process id +eval "$CMD2 2>\"${te}2\" &" +pid2=$! # background process id $WAITCMD -echo "$da" |$CMD >$tf 2>"${te}2" +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}1" + cat "${te}" cat "$tdiff" numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" @@ -3500,10 +3514,9 @@ else echo " $CMD2 &" echo " $CMD" fi - if [ -n "$debug" ]; then cat "${te}1" "${te}2"; fi + if [ -n "$debug" ]; then cat "${te}2" "${te}"; fi numOK=$((numOK+1)) fi -kill $pid 2>/dev/null wait fi ;; # NUMCOND, feats esac @@ -3518,8 +3531,8 @@ TCP4CONNECT , tcp4 TCP4-CONNECT:\$LOCALHOST:\$PORT TCP4-LISTEN:\$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,verify=0 OPENSSL-LISTEN:\$PORT,$REUSEADDR,$SOCAT_EGD,cert=testsrv.crt,key=testsrv.key,verify=0 waittcp4port\040\$PORT -OPENSSL4SERVER OPENSSL tcp4 OPENSSL-LISTEN:\$PORT,$SOCAT_EGD,cert=testsrv.crt,key=testsrv.key,verify=0 OPENSSL:\$LOCALHOST:\$PORT,$REUSEADDR,verify=0,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 " @@ -3546,8 +3559,8 @@ 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,$REUSEADDR,$SOCAT_EGD,cert=testsrv.crt,key=testsrv.key,verify=0 pipe" -CMD1="$TRACE $SOCAT $opts - OPENSSL:$LOCALHOST:$PORT,verify=1,cafile=testsrv.crt,$SOCAT_EGD" +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 @@ -3594,8 +3607,8 @@ 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,verify=1,cert=testsrv.crt,key=testsrv.key,cafile=testcli.crt,$SOCAT_EGD PIPE" -CMD="$TRACE $SOCAT $opts - OPENSSL:$LOCALHOST:$PORT,verify=0,cert=testcli.crt,key=testcli.key,$SOCAT_EGD" +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 @@ -4684,6 +4697,7 @@ 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" @@ -5218,7 +5232,7 @@ elif ! testfeats openssl >/dev/null; then 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,cafile=testsrv.crt,$SOCAT_EGD" 4 tcp $PORT -1 +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)) @@ -5235,7 +5249,7 @@ elif ! testfeats openssl >/dev/null; then 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,cafile=testsrv.crt,$SOCAT_EGD" 4 tcp $PORT -1 +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)) @@ -5252,7 +5266,7 @@ elif ! testfeats openssl >/dev/null; then 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,cafile=testsrv.crt,$SOCAT_EGD" 4 tcp $PORT -1 +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)) @@ -5273,7 +5287,7 @@ 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,cafile=testsrv.crt,$SOCAT_EGD" 4 tcp $PORT -1 +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)) @@ -5291,7 +5305,7 @@ 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,cafile=testsrv.crt,cert=testcli.pem,$SOCAT_EGD" 4 tcp $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)) @@ -5446,7 +5460,7 @@ 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,$REUSEADDR,verify=0,cafile=testsrv.crt,cert=testcli.crt,key=testcli.key" 4 tcp "$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)) @@ -7911,7 +7925,7 @@ 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 - TCP:$LOCALHOST:$PORT" +CMD2="$TRACE $SOCAT $opts - TCP4:$LOCALHOST:$PORT" printf "test $F_n $TEST... " $N $CMD1 2>"${te}1" & pid1=$! @@ -8824,8 +8838,8 @@ 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,$REUSEADDR,cert=$SRVCERT.pem,verify=0 -" -CMD2="$TRACE $SOCAT $opts -u - OPENSSL-CONNECT:$LOCALHOST:$PORT,verify=0" +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" & @@ -10438,8 +10452,8 @@ 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 - TCP:$LOCALHOST:$PORT,setsockopt=6:$TCP_MAXSEG:512" -CMD2="$TRACE $SOCAT $opts - TCP:$LOCALHOST:$PORT,setsockopt=6:$TCP_MAXSEG:1" +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=$! @@ -10516,7 +10530,7 @@ 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 - TCP:$LOCALHOST:$PORT" +CMD1="$TRACE $SOCAT $opts - TCP4:$LOCALHOST:$PORT" CMD2="$CMD0" CMD3="$CMD1" printf "test $F_n $TEST... " $N @@ -11383,9 +11397,9 @@ if [ $RLIMIT_NOFILE -gt 1024 ]; then RLIMIT_NOFILE="$(ulimit -n)" fi newport tcp4 -CMD0="$TRACE $SOCAT $opt_d0 $opts TCP-LISTEN:$PORT,$REUSEADDR,range=$LOCALHOST:255.255.255.255 PIPE" -CMD1="$TRACE $SOCAT $opts -t 0 /dev/null TCP:$SECONDADDR:$PORT,bind=$SECONDADDR" -CMD2="$TRACE $SOCAT $opts - TCP:$LOCALHOST:$PORT,bind=$LOCALHOST" +CMD0="$TRACE $SOCAT $opt_d0 $opts TCP4-LISTEN:$PORT,$REUSEADDR,range=$LOCALHOST:255.255.255.255 PIPE" +CMD1="$TRACE $SOCAT $opts -t 0 /dev/null TCP4:$SECONDADDR:$PORT,bind=$SECONDADDR" +CMD2="$TRACE $SOCAT $opts - TCP4:$LOCALHOST:$PORT,bind=$LOCALHOST" printf "test $F_n $TEST... " $N $CMD0 >/dev/null 2>"${te}0" & pid0=$! @@ -11399,9 +11413,9 @@ rc2=$? kill $pid0 2>/dev/null; wait echo -e "$da" |diff "${tf}2" - >$tdiff if [ $rc2 -ne 0 ]; then - $PRINTF "$FAILED\n" + $PRINTF "$FAILED (rc2=$rc2)\n" echo "$CMD2 &" - cat "${te}2" + cat "${te}2" >&2 numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" elif [ -f "$tdiff" -a ! -s "$tdiff" ]; then @@ -11416,11 +11430,11 @@ elif [ -f "$tdiff" -a ! -s "$tdiff" ]; then else $PRINTF "$FAILED\n" echo "$CMD0 &" + cat "${te}0" >&2 echo "$CMD1" + cat "${te}1" >&2 echo "$CMD2" - cat "${te}0" - cat "${te}1" - cat "${te}2" + cat "${te}2" >&2 numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" fi @@ -11557,8 +11571,8 @@ 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,$REUSEADDR,cert=testsrv.pem,verify=0 PIPE" -CMD1="$TRACE $SOCAT $opts - OPENSSL-CONNECT:$LOCALHOST:$PORT,bind=$LOCALHOST,verify=0" +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=$! @@ -11734,15 +11748,15 @@ esac N=$((N+1)) # done <<<" -openssl SERVER X509 ISSUER OPENSSL-LISTEN:$PORT,$REUSEADDR,bind=$LOCALHOST,cert=testsrv.pem,cafile=testcli.crt,verify=1 OPENSSL-CONNECT:$LOCALHOST:$PORT,cert=testcli.pem,cafile=testsrv.crt,verify=1 $TESTCERT_ISSUER -openssl SERVER X509 SUBJECT OPENSSL-LISTEN:$PORT,$REUSEADDR,bind=$LOCALHOST,cert=testsrv.pem,cafile=testcli.crt,verify=1 OPENSSL-CONNECT:$LOCALHOST:$PORT,cert=testcli.pem,cafile=testsrv.crt,verify=1 $TESTCERT_SUBJECT -openssl SERVER X509 COMMONNAME OPENSSL-LISTEN:$PORT,$REUSEADDR,bind=$LOCALHOST,cert=testsrv.pem,cafile=testcli.crt,verify=1 OPENSSL-CONNECT:$LOCALHOST:$PORT,cert=testcli.pem,cafile=testsrv.crt,verify=1 $TESTCERT_COMMONNAME -openssl SERVER X509 COUNTRYNAME OPENSSL-LISTEN:$PORT,$REUSEADDR,bind=$LOCALHOST,cert=testsrv.pem,cafile=testcli.crt,verify=1 OPENSSL-CONNECT:$LOCALHOST:$PORT,cert=testcli.pem,cafile=testsrv.crt,verify=1 $TESTCERT_COUNTRYNAME -openssl SERVER X509 LOCALITYNAME OPENSSL-LISTEN:$PORT,$REUSEADDR,bind=$LOCALHOST,cert=testsrv.pem,cafile=testcli.crt,verify=1 OPENSSL-CONNECT:$LOCALHOST:$PORT,cert=testcli.pem,cafile=testsrv.crt,verify=1 $TESTCERT_LOCALITYNAME -openssl SERVER X509 ORGANIZATIONALUNITNAME OPENSSL-LISTEN:$PORT,$REUSEADDR,bind=$LOCALHOST,cert=testsrv.pem,cafile=testcli.crt,verify=1 OPENSSL-CONNECT:$LOCALHOST:$PORT,cert=testcli.pem,cafile=testsrv.crt,verify=1 $TESTCERT_ORGANIZATIONALUNITNAME -openssl SERVER X509 ORGANIZATIONNAME OPENSSL-LISTEN:$PORT,$REUSEADDR,bind=$LOCALHOST,cert=testsrv.pem,cafile=testcli.crt,verify=1 OPENSSL-CONNECT:$LOCALHOST:$PORT,cert=testcli.pem,cafile=testsrv.crt,verify=1 $TESTCERT_ORGANIZATIONNAME -openssl CLIENT X509 SUBJECT OPENSSL-CONNECT:$LOCALHOST:$PORT,cert=testcli.pem,cafile=testsrv.crt,verify=1 OPENSSL-LISTEN:$PORT,$REUSEADDR,bind=$LOCALHOST,cert=testsrv.pem,cafile=testcli.crt,verify=1 $TESTCERT_SUBJECT -openssl CLIENT X509 ISSUER OPENSSL-CONNECT:$LOCALHOST:$PORT,cert=testcli.pem,cafile=testsrv.crt,verify=1 OPENSSL-LISTEN:$PORT,$REUSEADDR,bind=$LOCALHOST,cert=testsrv.pem,cafile=testcli.crt,verify=1 $TESTCERT_ISSUER +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 " @@ -12120,8 +12134,8 @@ te="$td/test$N.stderr" tdiff="$td/test$N.diff" da="test$N $(date) $RANDOM" newport tcp4 -CMD0="$SOCAT $opts OPENSSL-LISTEN:$PORT,$REUSEADDR,cert=testsrv.pem,verify=0 SYSTEM:cat" -CMD1="$SOCAT $opts - OPENSSL-CONNECT:$LOCALHOST:$PORT,verify=0" +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=$! @@ -12505,7 +12519,7 @@ 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 - TCP:localhost:$tp" +CMD1="$TRACE $SOCAT $opts - TCP4:localhost:$tp" CMD2="$CMD0" CMD3="$CMD1" printf "test $F_n $TEST... " $N @@ -12580,7 +12594,7 @@ 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 - TCP:localhost:$tp" +CMD2="$TRACE $SOCAT $opts - TCP4:localhost:$tp" CMD3="$CMD2" printf "test $F_n $TEST... " $N $CMD0 >/dev/null 2>"${te}0" & @@ -12711,15 +12725,15 @@ da="test$N $(date) $RANDOM" #TESTSRV=./testsrvec; gentesteccert $TESTSRV TESTSRV=./testsrv; gentestcert $TESTSRV newport tcp4 -CMD0="$TRACE $SOCAT $opts OPENSSL-LISTEN:$PORT,$REUSEADDR,cert=$TESTSRV.crt,key=$TESTSRV.pem,verify=0 PIPE" -CMD1="$TRACE $SOCAT $opts - OPENSSL-CONNECT:$LOCALHOST:$PORT,cipher=ECDHE-ECDSA-AES256-GCM-SHA384,cafile=$TESTSRV.crt,verify=0" +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 +kill $pid0 2>/dev/null; wait if [ $rc1 -ne 0 ]; then $PRINTF "$FAILED\n" echo "failure symptom: client error" >&2 @@ -13237,11 +13251,11 @@ TEST="$NAME: OpenSSL DTLS client" # 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}$a not available${NORMAL}\n" $N + $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}$a not available${NORMAL}\n" $N + $PRINTF "test $F_n $TEST... ${YELLOW}Address $a not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif ! runsip4 >/dev/null; then @@ -13371,8 +13385,8 @@ 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:$LOCALHOST:$PORT,verify=1,cafile=testalt.crt,$SOCAT_EGD" +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 @@ -13915,8 +13929,8 @@ 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,$REUSEADDR,cert=testsrv.pem,verify=0 CREAT:$to" -CMD1="$TRACE $SOCAT $opts -u OPEN:$ti OPENSSL-CONNECT:$LOCALHOST:$PORT,cafile=testsrv.crt" +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" & @@ -13986,8 +14000,8 @@ 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,$REUSEADDR,cert=testsrv.pem,verify=0 OPEN:$ti" -CMD1="$TRACE $SOCAT $opts -u OPENSSL-CONNECT:$LOCALHOST:$PORT,cafile=testsrv.crt CREAT:$to" +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" & @@ -14060,8 +14074,8 @@ 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,cert=testsrv.pem,verify=0 CREAT:$to" -CMD1="$TRACE $SOCAT $opts -u OPEN:$ti OPENSSL-DTLS-CONNECT:$LOCALHOST:$PORT,cafile=testsrv.crt" +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" & @@ -14134,8 +14148,8 @@ 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,cert=testsrv.pem,verify=0 OPEN:$ti" -CMD1="$TRACE $SOCAT $opts -u OPENSSL-DTLS-CONNECT:$LOCALHOST:$PORT,cafile=testsrv.crt CREAT:$to" +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" & @@ -14259,8 +14273,8 @@ 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,reuseaddr,cert=./testsrv.pem,cafile=./testalt.crt -" -CMD1="$TRACE $SOCAT $opts -u - OPENSSL-CONNECT:localhost:$PORT,cafile=testsrv.crt,cert=testalt.pem,verify=0" +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=$! @@ -14553,8 +14567,8 @@ 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 TCP-L:$PORT,reuseaddr PIPE" -CMD1="$TRACE $SOCAT $opts - TCP:$LOCALHOST:$PORT,connect-timeout=2,retry=1,interval=2" +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=$! @@ -15260,6 +15274,7 @@ fi # NUMCOND esac N=$((N+1)) + # Test if option -S turns on logging of signal 31 NAME=SIG31_LOG case "$TESTS" in @@ -16016,6 +16031,7 @@ if [ $rc0b -eq 1 ] && grep -q -e "Address already in use" -e "Address in use" "$ 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" @@ -16045,6 +16061,156 @@ 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%*|*%foreign%*|*%$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 [ -z "$FOREIGN" ]; then + $PRINTF "test $F_n $TEST... ${YELLOW}use test.sh option -foreign${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" +else +tf="$td/test$N.stdout" +te="$td/test$N.stderr" +tdiff="$td/test$N.diff" +da="test$N $(date) $RANDOM" +ADDRS=$(nslookup server-4.dest-unreach.net. |sed -n '/^$/,$ p' |grep ^Address |awk '{print($2);}') +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%*|*%foreign%*|*%$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 ! 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" +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 +ADDRS=$(nslookup . |sed -n '/^$/,$ p' |grep ^Address |awk '{print($2);}') +while true; do + OPEN= + for addr in $ADDRS; do + case $addr in + *.*) ;; + *:*) addr="[$addr]" ; + esac + if $SOCAT /dev/null TCP:$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 TCP:localhost-4-6.dest-unreach.net:$PORT" +printf "test $F_n $TEST... " $N +$CMD >/dev/null 2>"${te}" +rc=$? +if [ $(grep " N opening connection to AF=\(2\|10\) " ${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)) + + # end of common tests ################################################################################## diff --git a/xio-ip.c b/xio-ip.c index 7962332..5e3a6c8 100644 --- a/xio-ip.c +++ b/xio-ip.c @@ -135,15 +135,13 @@ unsigned long res_opts() { */ int xiogetaddrinfo(const char *node, const char *service, int family, int socktype, int protocol, - union sockaddr_union *sau, socklen_t *socklen, + struct addrinfo **res, unsigned long res_opts0, unsigned long res_opts1) { - int port = -1; /* port number in network byte order */ char *numnode = NULL; size_t nodelen; unsigned long save_res_opts = 0; #if HAVE_GETADDRINFO struct addrinfo hints = {0}; - struct addrinfo *res = NULL; #else /* HAVE_PROTOTYPE_LIB_getipnodebyname || nothing */ struct hostent *host; #endif @@ -161,13 +159,12 @@ int xiogetaddrinfo(const char *node, const char *service, save_res_opts, _res.options); } #endif /* HAVE_RESOLV_H */ - memset(sau, 0, *socklen); - sau->soa.sa_family = family; if (service && service[0]=='\0') { Error("empty port/service"); } +#if LATER #ifdef WITH_VSOCK if (family == AF_VSOCK) { error_num = sockaddr_vm_parse(&sau->vm, node, service); @@ -177,18 +174,7 @@ int xiogetaddrinfo(const char *node, const char *service, return STAT_OK; } #endif /* WITH_VSOCK */ - - /* if service is numeric we don't want to have a lookup (might take long - with NIS), so we handle this specially */ - if (service && isdigit(service[0]&0xff)) { - char *extra; - port = htons(strtoul(service, &extra, 0)); - if (*extra != '\0') { - Warn2("xiogetaddrinfo(, \"%s\", ...): extra trailing data \"%s\"", - service, extra); - } - service = NULL; - } +#endif /* LATER */ /* the resolver functions might handle numeric forms of node names by reverse lookup, that's not what we want. @@ -220,7 +206,7 @@ int xiogetaddrinfo(const char *node, const char *service, if (node != NULL || service != NULL) { struct addrinfo *record; - hints.ai_flags |= AI_PASSIVE; + hints.ai_flags |= AI_PASSIVE; /* important for IPv4+IPv6 listen */ hints.ai_family = family; hints.ai_socktype = socktype; hints.ai_protocol = protocol; @@ -230,7 +216,7 @@ int xiogetaddrinfo(const char *node, const char *service, hints.ai_next = NULL; do { - error_num = Getaddrinfo(node, service, &hints, &res); + error_num = Getaddrinfo(node, service, &hints, res); if (error_num == 0) break; if (error_num == EAI_SOCKTYPE && socktype != 0) { /* there are systems where kernel goes SCTP but not getaddrinfo() */ @@ -244,21 +230,20 @@ int xiogetaddrinfo(const char *node, const char *service, hints.ai_flags, hints.ai_family, hints.ai_socktype, hints.ai_protocol, gai_strerror(error_num)); - if (res != NULL) freeaddrinfo(res); + if (res != NULL) freeaddrinfo(*res); if (numnode) free(numnode); return STAT_NORETRY; } hints.ai_protocol = 0; continue; } - if (error_num != 0) { + if ((error_num = Getaddrinfo(node, service, &hints, res)) != 0) { Error7("getaddrinfo(\"%s\", \"%s\", {%d,%d,%d,%d}, {}): %s", node?node:"NULL", service?service:"NULL", hints.ai_flags, hints.ai_family, hints.ai_socktype, hints.ai_protocol, (error_num == EAI_SYSTEM)? strerror(errno):gai_strerror(error_num)); - if (res != NULL) freeaddrinfo(res); if (numnode) free(numnode); #if HAVE_RESOLV_H @@ -272,65 +257,15 @@ int xiogetaddrinfo(const char *node, const char *service, } while (1); service = NULL; /* do not resolve later again */ - record = res; - if (family == PF_UNSPEC && xioparms.preferred_ip == '0') { - /* we just take the first result */ - family = res[0].ai_addr->sa_family; - } - if (family == PF_UNSPEC) { - int trypf; - trypf = (xioparms.preferred_ip=='6'?PF_INET6:PF_INET); - /* we must look for a matching entry */ - while (record != NULL) { - if (record->ai_family == trypf) { - family = trypf; - break; /* family and record set accordingly */ - } - record = record->ai_next; - } - if (record == NULL) { - /* we did not find a "preferred" entry, take the first */ - record = res; - family = res[0].ai_addr->sa_family; - } - } - - switch (family) { -#if WITH_IP4 - case PF_INET: - if (*socklen > record->ai_addrlen) { - *socklen = record->ai_addrlen; - } - memcpy(&sau->ip4, record->ai_addr, *socklen); - break; -#endif /* WITH_IP4 */ -#if WITH_IP6 - case PF_INET6: -#if _AIX - /* older AIX versions pass wrong length, so we correct it */ - record->ai_addr->sa_len = sizeof(struct sockaddr_in6); -#endif - if (*socklen > record->ai_addrlen) { - *socklen = record->ai_addrlen; - } - memcpy(&sau->ip6, record->ai_addr, *socklen); - break; -#endif /* WITH_IP6 */ - default: - Error1("address resolved to unknown protocol family %d", - record->ai_addr->sa_family); - break; - } - freeaddrinfo(res); - } else { - switch (family) { -#if WITH_IP4 - case PF_INET: *socklen = sizeof(sau->ip4); break; -#endif /* WITH_IP4 */ -#if WITH_IP6 - case PF_INET6: *socklen = sizeof(sau->ip6); break; -#endif /* WITH_IP6 */ +#if WITH_MSGLEVEL <= E_DEBUG + record = *res; + while (record) { + char buff[256/*!*/]; + sockaddr_info(record->ai_addr, record->ai_addrlen, buff, sizeof(buff)); + Debug5("getaddrinfo() -> flags=%d family=%d socktype=%d protocol=%d addr=%s", record->ai_flags, record->ai_family, record->ai_socktype, record->ai_protocol, buff); + record = record->ai_next; } +#endif /* WITH_MSGLEVEL <= E_DEBUG */ } #elif HAVE_PROTOTYPE_LIB_getipnodebyname /* !HAVE_GETADDRINFO */ @@ -381,7 +316,7 @@ int xiogetaddrinfo(const char *node, const char *service, freehostent(host); } -#else /* !HAVE_PROTOTYPE_LIB_getipnodebyname */ +#elsif 0 /* !HAVE_PROTOTYPE_LIB_getipnodebyname */ if (node != NULL) { /* this is not a typical IP6 resolver function - but Linux @@ -411,7 +346,7 @@ int xiogetaddrinfo(const char *node, const char *service, return STAT_RETRYLATER; } if (host->h_addrtype != family) { - Error2("xioaddrinfo(): \"%s\" does not resolve to %s", + Error2("xiogetaddrinfo(): \"%s\" does not resolve to %s", node, family==PF_INET?"IP4":"IP6"); } else { switch (family) { @@ -435,22 +370,6 @@ int xiogetaddrinfo(const char *node, const char *service, #endif -#if WITH_TCP || WITH_UDP - if (service) { - port = parseport(service, protocol); - } - if (port >= 0) { - switch (family) { -#if WITH_IP4 - case PF_INET: sau->ip4.sin_port = port; break; -#endif /* WITH_IP4 */ -#if WITH_IP6 - case PF_INET6: sau->ip6.sin6_port = port; break; -#endif /* WITH_IP6 */ - } - } -#endif /* WITH_TCP || WITH_UDP */ - if (numnode) free(numnode); #if HAVE_RESOLV_H @@ -462,6 +381,50 @@ int xiogetaddrinfo(const char *node, const char *service, return STAT_OK; } +void xiofreeaddrinfo(struct addrinfo *res) { +#if HAVE_GETADDRINFO + freeaddrinfo(res); +#else + ; +#endif +} + +/* A simple resolver interface that just returns one address, + the first found by calling xiogetaddrinfo(). + family may be AF_INET, AF_INET6, or AF_UNSPEC. + Returns -1 when an error occurred or when no result found. +*/ +int xioresolve(const char *node, const char *service, + int family, int socktype, int protocol, + union sockaddr_union *addr, socklen_t *addrlen, + unsigned long res_opts0, unsigned long res_opts1) { + struct addrinfo *res = NULL; + int rc; + + rc = xiogetaddrinfo(node, service, family, socktype, protocol, + &res, res_opts0, res_opts1); + if (rc != 0) { + xiofreeaddrinfo(res); + return -1; + } + if (res == NULL) { + Warn1("xioresolve(node=\"%s\", ...): No result", node); + xiofreeaddrinfo(res); + return -1; + } + if (res->ai_addrlen > *addrlen) { + Warn3("xioresolve(node=\"%s\", addrlen="F_socklen", ...): "F_socklen" bytes required", node, *addrlen, res->ai_addrlen); + xiofreeaddrinfo(res); + return -1; + } + if (res->ai_next != NULL) { + Info4("xioresolve(node=\"%s\", service=%s%s%s, ...): More than one address found", node?node:"NULL", service?"\"":"", service?service:"NULL", service?"\"":""); + } + memcpy(addr, res->ai_addr, res->ai_addrlen); + *addrlen = res->ai_addrlen; + xiofreeaddrinfo(res); + return 0; +} #if defined(HAVE_STRUCT_CMSGHDR) && defined(CMSG_DATA) /* Converts the ancillary message in *cmsg into a form useable for further @@ -773,10 +736,10 @@ mc:addr /* first parameter is alway multicast address */ /*! result */ - xiogetaddrinfo(opt->value.u_string/*multiaddr*/, NULL, + xioresolve(opt->value.u_string/*multiaddr*/, NULL, xfd->para.socket.la.soa.sa_family, SOCK_DGRAM, IPPROTO_IP, - &sockaddr1, &socklen1, 0, 0); + &sockaddr1, &socklen1, 0, 0); ip4_mreqn.mreq.imr_multiaddr = sockaddr1.ip4.sin_addr; if (0) { ; /* for canonical reasons */ @@ -784,7 +747,7 @@ mc:addr } else if (opt->value3.u_string/*ifindex*/ != NULL) { /* three parameters */ /* second parameter is interface address */ - xiogetaddrinfo(opt->value2.u_string/*param2*/, NULL, + xioresolve(opt->value2.u_string/*param2*/, NULL, xfd->para.socket.la.soa.sa_family, SOCK_DGRAM, IPPROTO_IP, &sockaddr2, &socklen2, 0, 0); @@ -812,7 +775,7 @@ mc:addr #endif /* HAVE_STRUCT_IP_MREQN */ } else { /*! result */ - xiogetaddrinfo(opt->value2.u_string/*param2*/, NULL, + xioresolve(opt->value2.u_string/*param2*/, NULL, xfd->para.socket.la.soa.sa_family, SOCK_DGRAM, IPPROTO_IP, &sockaddr2, &socklen2, 0, 0); @@ -960,25 +923,34 @@ int xioapply_ip_add_source_membership(struct single *xfd, struct opt *opt) { socklen_t socklen2 = sizeof(sockaddr2.ip4); union sockaddr_union sockaddr3; socklen_t socklen3 = sizeof(sockaddr3.ip4); + int rc; /* first parameter is always multicast address */ - /*! result */ - xiogetaddrinfo(opt->value.u_string/*mcaddr*/, NULL, + rc = xioresolve(opt->value.u_string/*mcaddr*/, NULL, xfd->para.socket.la.soa.sa_family, SOCK_DGRAM, IPPROTO_IP, &sockaddr1, &socklen1, 0, 0); + if (rc < 0) { + return -1; + } ip4_mreq_src.imr_multiaddr = sockaddr1.ip4.sin_addr; /* second parameter is interface address */ - xiogetaddrinfo(opt->value2.u_string/*ifaddr*/, NULL, + rc = xioresolve(opt->value.u_string/*ifaddr*/, NULL, xfd->para.socket.la.soa.sa_family, SOCK_DGRAM, IPPROTO_IP, &sockaddr2, &socklen2, 0, 0); + if (rc < 0) { + return -1; + } ip4_mreq_src.imr_interface = sockaddr2.ip4.sin_addr; /* third parameter is source address */ - xiogetaddrinfo(opt->value3.u_string/*srcaddr*/, NULL, + rc = xioresolve(opt->value.u_string/*srcaddr*/, NULL, xfd->para.socket.la.soa.sa_family, SOCK_DGRAM, IPPROTO_IP, &sockaddr3, &socklen3, 0, 0); + if (rc < 0) { + return -1; + } ip4_mreq_src.imr_sourceaddr = sockaddr3.ip4.sin_addr; if (Setsockopt(xfd->fd, opt->desc->major, opt->desc->minor, &ip4_mreq_src, sizeof(ip4_mreq_src)) < 0) { diff --git a/xio-ip.h b/xio-ip.h index 7ae2092..6869b45 100644 --- a/xio-ip.h +++ b/xio-ip.h @@ -39,10 +39,9 @@ extern const struct optdesc opt_res_defnames; extern const struct optdesc opt_res_stayopen; extern const struct optdesc opt_res_dnsrch; -extern int xiogetaddrinfo(const char *node, const char *service, - int family, int socktype, int protocol, - union sockaddr_union *sa, socklen_t *socklen, - unsigned long res_opts0, unsigned long res_opts1); +extern int xiogetaddrinfo(const char *node, const char *service, int family, int socktype, int protocol, struct addrinfo **res, unsigned long res_opts0, unsigned long res_opts1); +extern void xiofreeaddrinfo(struct addrinfo *res); +extern int xioresolve(const char *node, const char *service, int family, int socktype, int protocol, union sockaddr_union *addr, socklen_t *addrlen, unsigned long res_opts0, unsigned long res_opts1); extern int xiolog_ancillary_ip(struct single *sfd, struct cmsghdr *cmsg, int *num, char *typbuff, int typlen, char *nambuff, int namlen, char *envbuff, int envlen, char *valbuff, int vallen); extern int xiotype_ip_add_membership(char *token, const struct optname *ent, struct opt *opt); extern int xioapply_ip_add_membership(xiosingle_t *xfd, struct opt *opt); diff --git a/xio-ip4.c b/xio-ip4.c index 36413cb..e6338d2 100644 --- a/xio-ip4.c +++ b/xio-ip4.c @@ -45,7 +45,7 @@ int xioparsenetwork_ip4(const char *rangename, struct xiorange *range) { netmask_in->s_addr = htonl((0xffffffff << (32-bits))); } } else if (delimpos = strchr(rangename1, ':')) { - if ((rc = xiogetaddrinfo(delimpos+1, NULL, PF_UNSPEC, 0, 0, + if ((rc = xioresolve(delimpos+1, NULL, PF_INET, 0, 0, &sau, &socklen, 0, 0)) != STAT_OK) { return rc; @@ -58,7 +58,7 @@ int xioparsenetwork_ip4(const char *rangename, struct xiorange *range) { } { *delimpos = 0; - if ((rc = xiogetaddrinfo(rangename1, NULL, PF_UNSPEC, 0, 0, + if ((rc = xioresolve(rangename1, NULL, PF_INET, 0, 0, &sau, &socklen, 0, 0)) != STAT_OK) { return rc; diff --git a/xio-ip6.c b/xio-ip6.c index f648b2a..195e706 100644 --- a/xio-ip6.c +++ b/xio-ip6.c @@ -11,7 +11,7 @@ #include "xioopen.h" #include "xio-ascii.h" #include "xio-socket.h" -#include "xio-ip.h" /* xiogetaddrinfo() */ +#include "xio-ip.h" /* xioresolve() */ #include "xio-ip6.h" #include "nestlex.h" @@ -85,7 +85,6 @@ const struct optdesc opt_ipv6_recvpathmtu = { "ipv6-recvpathmtu", "recvpathmtu", int xioip6_pton(const char *src, struct in6_addr *dst) { union sockaddr_union sockaddr; socklen_t sockaddrlen = sizeof(sockaddr); - int res; if (src[0] == '[') { char plainaddr[INET6_ADDRSTRLEN]; @@ -97,9 +96,8 @@ int xioip6_pton(const char *src, struct in6_addr *dst) { *clos = '\0'; return xioip6_pton(plainaddr, dst); } - if ((res = - xiogetaddrinfo(src, NULL, PF_INET6, 0, 0, &sockaddr, &sockaddrlen, - 0, 0)) + if (xioresolve(src, NULL, PF_INET6, 0, 0, &sockaddr, &sockaddrlen, + 0, 0) != STAT_OK) { return STAT_NORETRY; } @@ -136,7 +134,7 @@ int xioparsenetwork_ip6(const char *rangename, struct xiorange *range) { return STAT_NORETRY; } baseaddr[delimind-2] = '\0'; - if (xiogetaddrinfo(baseaddr, NULL, PF_INET6, 0, 0, &sockaddr, &sockaddrlen, + if (xioresolve(baseaddr, NULL, PF_INET6, 0, 0, &sockaddr, &sockaddrlen, 0, 0) != STAT_OK) { return STAT_NORETRY; @@ -481,7 +479,7 @@ int xioapply_ipv6_join_group( /* Always two parameters */ /* First parameter is multicast address */ if ((res = - xiogetaddrinfo(opt->value.u_string/*multiaddr*/, NULL, + xioresolve(opt->value.u_string/*multiaddr*/, NULL, xfd->para.socket.la.soa.sa_family, SOCK_DGRAM, IPPROTO_IP, &sockaddr1, &socklen1, 0, 0)) != STAT_OK) { @@ -620,7 +618,7 @@ int xioapply_ip6_join_source_group(struct single *xfd, struct opt *opt) { /* First parameter is always multicast address */ if ((res = - xiogetaddrinfo(opt->value.u_string/*mcaddr*/, NULL, + xioresolve(opt->value.u_string/*mcaddr*/, NULL, xfd->para.socket.la.soa.sa_family, SOCK_DGRAM, IPPROTO_IP, &sockaddr1, &socklen1, 0, 0)) != STAT_OK) { @@ -637,7 +635,7 @@ int xioapply_ip6_join_source_group(struct single *xfd, struct opt *opt) { } /* Third parameter is source address */ if ((res = - xiogetaddrinfo(opt->value3.u_string/*srcaddr*/, NULL, + xioresolve(opt->value3.u_string/*srcaddr*/, NULL, xfd->para.socket.la.soa.sa_family, SOCK_DGRAM, IPPROTO_IP, &sockaddr2, &socklen2, 0, 0)) != STAT_OK) { diff --git a/xio-ipapp.c b/xio-ipapp.c index 98201ee..3fc3370 100644 --- a/xio-ipapp.c +++ b/xio-ipapp.c @@ -30,9 +30,9 @@ int xioopen_ipapp_connect(int argc, const char *argv[], struct opt *opts, const char *hostname = argv[1], *portname = argv[2]; bool dofork = false; union sockaddr_union us_sa, *us = &us_sa; - union sockaddr_union them_sa, *them = &them_sa; socklen_t uslen = sizeof(us_sa); - socklen_t themlen = sizeof(them_sa); + struct addrinfo *themlist, *themp; + char infobuff[256]; bool needbind = false; bool lowport = false; int level; @@ -52,7 +52,7 @@ int xioopen_ipapp_connect(int argc, const char *argv[], struct opt *opts, if (_xioopen_ipapp_prepare(opts, &opts0, hostname, portname, &pf, ipproto, xfd->para.socket.ip.res_opts[1], xfd->para.socket.ip.res_opts[0], - them, &themlen, us, &uslen, &needbind, &lowport, + &themlist, us, &uslen, &needbind, &lowport, socktype) != STAT_OK) { return STAT_NORETRY; } @@ -68,20 +68,36 @@ int xioopen_ipapp_connect(int argc, const char *argv[], struct opt *opts, Info("starting connect loop"); } - do { /* loop over retries and forks */ + do { /* loop over retries, and forks */ + + themp = themlist; + /* Loop over themlist */ + result = STAT_RETRYLATER; + while (themp != NULL) { + Notice1("opening connection to %s", + sockaddr_info(themp->ai_addr, themp->ai_addrlen, + infobuff, sizeof(infobuff))); #if WITH_RETRY - if (xfd->forever || xfd->retry) { - level = E_INFO; - } else + if (xfd->forever || xfd->retry || themp->ai_next != NULL) { + level = E_INFO; + } else #endif /* WITH_RETRY */ - level = E_ERROR; + level = E_ERROR; - result = + result = _xioopen_connect(xfd, needbind?us:NULL, uslen, - (struct sockaddr *)them, themlen, - opts, pf, socktype, ipproto, lowport, level); + themp->ai_addr, themp->ai_addrlen, + opts, pf?pf:themp->ai_family, socktype, ipproto, + lowport, level); + if (result == STAT_OK) + break; + themp = themp->ai_next; + if (themp == NULL) { + result = STAT_RETRYLATER; + } + } switch (result) { case STAT_OK: break; #if WITH_RETRY @@ -95,10 +111,10 @@ int xioopen_ipapp_connect(int argc, const char *argv[], struct opt *opts, dropopts(opts, PH_ALL); free(opts); opts = copyopts(opts0, GROUP_ALL); continue; } - return STAT_NORETRY; #endif /* WITH_RETRY */ default: - free(opts0);free(opts); + xiofreeaddrinfo(themlist); + free(opts0);free(opts); return result; } @@ -114,7 +130,8 @@ int xioopen_ipapp_connect(int argc, const char *argv[], struct opt *opts, if (xfd->forever || --xfd->retry) { Nanosleep(&xfd->intervall, NULL); continue; } - free(opts0); + xiofreeaddrinfo(themlist); + free(opts0); return STAT_RETRYLATER; } @@ -136,6 +153,7 @@ int xioopen_ipapp_connect(int argc, const char *argv[], struct opt *opts, } } while (true); /* only "active" process breaks (master without fork, or child) */ + xiofreeaddrinfo(themlist); if ((result = _xio_openlate(xfd, opts)) < 0) { free(opts0);free(opts); @@ -158,12 +176,11 @@ int int *pf, int protocol, unsigned long res_opts0, unsigned long res_opts1, - union sockaddr_union *them, socklen_t *themlen, + struct addrinfo **themlist, union sockaddr_union *us, socklen_t *uslen, bool *needbind, bool *lowport, int socktype) { uint16_t port; - char infobuff[256]; int result; retropt_socket_pf(opts, pf); @@ -171,36 +188,35 @@ int if ((result = xiogetaddrinfo(hostname, portname, *pf, socktype, protocol, - (union sockaddr_union *)them, themlen, + themlist, res_opts0, res_opts1 )) != STAT_OK) { return STAT_NORETRY; /*! STAT_RETRYLATER? */ } - if (*pf == PF_UNSPEC) { - *pf = them->soa.sa_family; - } applyopts(-1, opts, PH_EARLY); /* 3 means: IP address AND port accepted */ - if (retropt_bind(opts, *pf, socktype, protocol, (struct sockaddr *)us, uslen, 3, + if (retropt_bind(opts, (*pf!=PF_UNSPEC)?*pf:(*themlist)->ai_family, + socktype, protocol, (struct sockaddr *)us, uslen, 3, res_opts0, res_opts1) != STAT_NOACTION) { *needbind = true; } else { - switch (*pf) { + switch ((*pf!=PF_UNSPEC)?*pf:(*themlist)->ai_family) { #if WITH_IP4 case PF_INET: socket_in_init(&us->ip4); *uslen = sizeof(us->ip4); break; #endif /* WITH_IP4 */ #if WITH_IP6 case PF_INET6: socket_in6_init(&us->ip6); *uslen = sizeof(us->ip6); break; #endif /* WITH_IP6 */ + default: Error("unsupported protocol family"); } } if (retropt_2bytes(opts, OPT_SOURCEPORT, &port) >= 0) { - switch (*pf) { + switch ((*pf!=PF_UNSPEC)?*pf:(*themlist)->ai_family) { #if WITH_IP4 case PF_INET: us->ip4.sin_port = htons(port); break; #endif /* WITH_IP4 */ @@ -216,8 +232,6 @@ int *opts0 = copyopts(opts, GROUP_ALL); - Notice1("opening connection to %s", - sockaddr_info((struct sockaddr *)them, *themlen, infobuff, sizeof(infobuff))); return STAT_OK; } #endif /* WITH_IP4 */ @@ -240,15 +254,14 @@ int _xioopen_ipapp_listen_prepare(struct opt *opts, struct opt **opts0, retropt_socket_pf(opts, pf); retropt_string(opts, OPT_BIND, &bindname); - if ((result = - xiogetaddrinfo(bindname, portname, *pf, socktype, ipproto, - (union sockaddr_union *)us, uslen, - res_opts0, res_opts1)) - != STAT_OK) { + result = + xioresolve(bindname, portname, *pf, socktype, ipproto, + us, uslen, + res_opts0, res_opts1); + if (result != STAT_OK) { /*! STAT_RETRY? */ return result; } - *opts0 = copyopts(opts, GROUP_ALL); return STAT_OK; } diff --git a/xio-ipapp.h b/xio-ipapp.h index 52fc682..b064c2f 100644 --- a/xio-ipapp.h +++ b/xio-ipapp.h @@ -22,7 +22,7 @@ extern int const char *hostname, const char *portname, int *pf, int protocol, unsigned long res_opts0, unsigned long res_opts1, - union sockaddr_union *them, socklen_t *themlen, + struct addrinfo **res, union sockaddr_union *us, socklen_t *uslen, bool *needbind, bool *lowport, int socktype); diff --git a/xio-listen.c b/xio-listen.c index b0555cd..882caa5 100644 --- a/xio-listen.c +++ b/xio-listen.c @@ -145,7 +145,7 @@ int _xioopen_listen(struct single *xfd, int xioflags, struct sockaddr *us, sockl xiosetchilddied(); /* set SIGCHLD handler */ } - if ((xfd->fd = xiosocket(opts, us->sa_family, socktype, proto, level)) < 0) { + if ((xfd->fd = xiosocket(opts, pf?pf:us->sa_family, socktype, proto, level)) < 0) { return STAT_RETRYLATER; } applyopts(xfd->fd, opts, PH_PASTSOCKET); @@ -199,8 +199,7 @@ int _xioopen_listen(struct single *xfd, int xioflags, struct sockaddr *us, sockl #if WITH_IP4 /*|| WITH_IP6*/ if (retropt_string(opts, OPT_RANGE, &rangename) >= 0) { - if (xioparserange(rangename, pf, &xfd->para.socket.range) - < 0) { + if (xioparserange(rangename, pf, &xfd->para.socket.range) < 0) { free(rangename); return STAT_NORETRY; } diff --git a/xio-openssl.c b/xio-openssl.c index 3558ad2..24b6285 100644 --- a/xio-openssl.c +++ b/xio-openssl.c @@ -12,6 +12,7 @@ #include "xioopen.h" #include "xio-fd.h" +#include "xio-ip.h" #include "xio-socket.h" /* _xioopen_connect() */ #include "xio-listen.h" #include "xio-udp.h" @@ -247,9 +248,8 @@ static int int ipproto = IPPROTO_TCP; bool dofork = false; union sockaddr_union us_sa, *us = &us_sa; - union sockaddr_union them_sa, *them = &them_sa; socklen_t uslen = sizeof(us_sa); - socklen_t themlen = sizeof(them_sa); + struct addrinfo *themlist, *themp; bool needbind = false; bool lowport = false; int level; @@ -328,7 +328,7 @@ static int _xioopen_ipapp_prepare(opts, &opts0, hostname, portname, &pf, ipproto, xfd->para.socket.ip.res_opts[1], xfd->para.socket.ip.res_opts[0], - them, &themlen, us, &uslen, + &themlist, us, &uslen, &needbind, &lowport, socktype); if (result != STAT_OK) return STAT_NORETRY; @@ -348,12 +348,22 @@ static int #endif /* WITH_RETRY */ level = E_ERROR; - /* this cannot fork because we retrieved fork option above */ - result = + themp = themlist; + /* loop over themlist */ + while (themp != NULL) { + /* This cannot fork because we retrieved fork option above */ + result = _xioopen_connect(xfd, needbind?us:NULL, uslen, - (struct sockaddr *)them, themlen, - opts, pf, socktype, ipproto, lowport, level); + themp->ai_addr, themp->ai_addrlen, + opts, pf?pf:themp->ai_addr->sa_family, socktype, ipproto, lowport, level); + if (result == STAT_OK) + break; + themp = themp->ai_next; + if (themp == NULL) { + result = STAT_RETRYLATER; + } + } switch (result) { case STAT_OK: break; #if WITH_RETRY @@ -367,14 +377,16 @@ static int --xfd->retry; continue; } + xiofreeaddrinfo(themlist); return STAT_NORETRY; #endif /* WITH_RETRY */ default: + xiofreeaddrinfo(themlist); return result; } - /*! isn't this too early? */ if ((result = _xio_openlate(xfd, opts)) < 0) { + xiofreeaddrinfo(themlist); return result; } @@ -395,7 +407,9 @@ static int continue; } #endif /* WITH_RETRY */ - default: return STAT_NORETRY; + default: + xiofreeaddrinfo(themlist); + return STAT_NORETRY; } if (dofork) { @@ -413,6 +427,7 @@ static int if (xfd->forever || --xfd->retry) { Nanosleep(&xfd->intervall, NULL); continue; } + xiofreeaddrinfo(themlist); return STAT_RETRYLATER; } @@ -433,6 +448,7 @@ static int #endif /* WITH_RETRY */ break; } while (true); /* drop out on success */ + xiofreeaddrinfo(themlist); openssl_conn_loginfo(xfd->para.openssl.ssl); diff --git a/xio-proxy.c b/xio-proxy.c index 179d08f..bcda8ad 100644 --- a/xio-proxy.c +++ b/xio-proxy.c @@ -91,9 +91,8 @@ static int xioopen_proxy_connect(int argc, const char *argv[], struct opt *opts, /* */ int pf = PF_UNSPEC; union sockaddr_union us_sa, *us = &us_sa; - union sockaddr_union them_sa, *them = &them_sa; socklen_t uslen = sizeof(us_sa); - socklen_t themlen = sizeof(them_sa); + struct addrinfo *themlist, *themp; const char *proxyname; char *proxyport = NULL; const char *targetname, *targetport; int ipproto = IPPROTO_TCP; @@ -133,7 +132,7 @@ static int xioopen_proxy_connect(int argc, const char *argv[], struct opt *opts, &pf, ipproto, xfd->para.socket.ip.res_opts[1], xfd->para.socket.ip.res_opts[0], - them, &themlen, us, &uslen, + &themlist, us, &uslen, &needbind, &lowport, socktype); if (result != STAT_OK) return result; @@ -149,11 +148,20 @@ static int xioopen_proxy_connect(int argc, const char *argv[], struct opt *opts, #endif /* WITH_RETRY */ level = E_ERROR; + themp = themlist; + /* Loop over themlist */ + while (themp != NULL) { result = _xioopen_connect(xfd, needbind?us:NULL, sizeof(*us), - (struct sockaddr *)them, themlen, - opts, pf, socktype, IPPROTO_TCP, lowport, level); + themp->ai_addr, themp->ai_addrlen, + opts, pf?pf:themp->ai_family, socktype, IPPROTO_TCP, lowport, level); + if (result == STAT_OK) + break; + themp = themp->ai_next; + if (themp == NULL) { + result = STAT_RETRYLATER; + } switch (result) { case STAT_OK: break; #if WITH_RETRY @@ -165,9 +173,11 @@ static int xioopen_proxy_connect(int argc, const char *argv[], struct opt *opts, } #endif /* WITH_RETRY */ default: + xiofreeaddrinfo(themlist); return result; } - + } + xiofreeaddrinfo(themlist); applyopts(xfd->fd, opts, PH_ALL); if ((result = _xio_openlate(xfd, opts)) < 0) @@ -291,7 +301,7 @@ int _xioopen_proxy_prepare(struct proxyvars *proxyvars, struct opt *opts, /* currently we only resolve to IPv4 addresses. This is in accordance to RFC 2396; however once it becomes clear how IPv6 addresses should be represented in CONNECT commands this code might be extended */ - rc = xiogetaddrinfo(targetname, targetport, PF_UNSPEC, + rc = xioresolve(targetname, targetport, PF_INET/*!?*/, SOCK_STREAM, IPPROTO_TCP, &host, &socklen, 0, 0); if (rc != STAT_OK) { diff --git a/xio-rawip.c b/xio-rawip.c index e355476..6d60d77 100644 --- a/xio-rawip.c +++ b/xio-rawip.c @@ -121,7 +121,7 @@ int _xioopen_rawip_sendto(const char *hostname, const char *protname, xfd->salen = sizeof(xfd->peersa); if ((result = - xiogetaddrinfo(hostname, NULL, *pf, socktype, ipproto, + xioresolve(hostname, NULL, *pf, socktype, ipproto, &xfd->peersa, &xfd->salen, xfd->para.socket.ip.res_opts[0], xfd->para.socket.ip.res_opts[1])) diff --git a/xio-socket.c b/xio-socket.c index 6c1a440..572cdb7 100644 --- a/xio-socket.c +++ b/xio-socket.c @@ -541,6 +541,7 @@ int xioopen_socket_recvfrom(int argc, const char *argv[], struct opt *opts, if (retropt_string(opts, OPT_RANGE, &rangename) >= 0) { if (xioparserange(rangename, 0, &xfd->para.socket.range) < 0) { + free(rangename); return STAT_NORETRY; } xfd->para.socket.dorange = true; @@ -619,6 +620,7 @@ int xioopen_socket_recv(int argc, const char *argv[], struct opt *opts, if (retropt_string(opts, OPT_RANGE, &rangename) >= 0) { if (xioparserange(rangename, 0, &xfd->para.socket.range) < 0) { + free(rangename); return STAT_NORETRY; } xfd->para.socket.dorange = true; @@ -1167,8 +1169,7 @@ int _xioopen_dgram_recvfrom(struct single *xfd, int xioflags, /* for generic sockets, this has already been retrieved */ if (retropt_string(opts, OPT_RANGE, &rangename) >= 0) { - if (xioparserange(rangename, pf, &xfd->para.socket.range) - < 0) { + if (xioparserange(rangename, pf, &xfd->para.socket.range) < 0) { free(rangename); return STAT_NORETRY; } @@ -1370,8 +1371,7 @@ int _xioopen_dgram_recv(struct single *xfd, int xioflags, #if WITH_IP4 /*|| WITH_IP6*/ if (retropt_string(opts, OPT_RANGE, &rangename) >= 0) { - if (xioparserange(rangename, pf, &xfd->para.socket.range) - < 0) { + if (xioparserange(rangename, pf, &xfd->para.socket.range) < 0) { free(rangename); return STAT_NORETRY; } @@ -1890,6 +1890,7 @@ int xioparsenetwork(const char *rangename, int pf, struct xiorange *range) { int xioparserange(const char *rangename, int pf, struct xiorange *range) { int i; if (xioparsenetwork(rangename, pf, range) < 0) { + Error2("failed to parse or resolve range \"%s\" (pf=%d)", rangename, pf); return -1; } /* we have parsed the address and mask; now we make sure that the stored diff --git a/xio-socks.c b/xio-socks.c index fd54b9a..b7472e5 100644 --- a/xio-socks.c +++ b/xio-socks.c @@ -52,11 +52,11 @@ static int xioopen_socks4_connect(int argc, const char *argv[], struct opt *opts int ipproto = IPPROTO_TCP; bool dofork = false; union sockaddr_union us_sa, *us = &us_sa; - union sockaddr_union them_sa, *them = &them_sa; socklen_t uslen = sizeof(us_sa); - socklen_t themlen = sizeof(them_sa); + struct addrinfo *themlist, *themp; bool needbind = false; bool lowport = false; + char infobuff[256]; unsigned char buff[BUFF_LEN]; struct socks4 *sockhead = (struct socks4 *)buff; size_t buflen = sizeof(buff); @@ -87,7 +87,7 @@ static int xioopen_socks4_connect(int argc, const char *argv[], struct opt *opts &pf, ipproto, xfd->para.socket.ip.res_opts[1], xfd->para.socket.ip.res_opts[0], - them, &themlen, us, &uslen, + &themlist, us, &uslen, &needbind, &lowport, socktype); Notice5("opening connection to %s:%u via socks4 server %s:%s as user \"%s\"", @@ -123,12 +123,24 @@ static int xioopen_socks4_connect(int argc, const char *argv[], struct opt *opts return result; } + themp = themlist; + /* loop over themlist */ + while (themp != NULL) { + Notice1("opening connection to %s", + sockaddr_info(themp->ai_addr, themp->ai_addrlen, + infobuff, sizeof(infobuff))); /* this cannot fork because we retrieved fork option above */ result = - _xioopen_connect (xfd, - needbind?us:NULL, sizeof(*us), - (struct sockaddr *)them, themlen, - opts, pf, socktype, IPPROTO_TCP, lowport, level); + _xioopen_connect(xfd, + needbind?us:NULL, sizeof(*us), + themp->ai_addr, themp->ai_addrlen, + opts, pf?pf:themp->ai_family, socktype, IPPROTO_TCP, lowport, level); + if (result == STAT_OK) + break; + themp = themp->ai_next; + if (themp == NULL) { + result = STAT_RETRYLATER; + } switch (result) { case STAT_OK: break; #if WITH_RETRY @@ -140,9 +152,11 @@ static int xioopen_socks4_connect(int argc, const char *argv[], struct opt *opts } #endif /* WITH_RETRY */ default: + xiofreeaddrinfo(themlist); return result; } - + } + xiofreeaddrinfo(themlist); applyopts(xfd->fd, opts, PH_ALL); if ((result = _xio_openlate(xfd, opts)) < 0) @@ -257,7 +271,7 @@ int union sockaddr_union sau; socklen_t saulen = sizeof(sau); - if ((result = xiogetaddrinfo(hostname, NULL, + if ((result = xioresolve(hostname, NULL, PF_INET, SOCK_STREAM, IPPROTO_TCP, &sau, &saulen, xfd->para.socket.ip.res_opts[1], diff --git a/xio-udp.c b/xio-udp.c index f37602c..ee6af64 100644 --- a/xio-udp.c +++ b/xio-udp.c @@ -382,7 +382,7 @@ int _xioopen_udp_sendto(const char *hostname, const char *servname, xfd->salen = sizeof(xfd->peersa); if ((result = - xiogetaddrinfo(hostname, servname, pf, socktype, ipproto, + xioresolve(hostname, servname, pf, socktype, ipproto, &xfd->peersa, &xfd->salen, xfd->para.socket.ip.res_opts[0], xfd->para.socket.ip.res_opts[1])) @@ -515,7 +515,7 @@ int xioopen_udp_recvfrom(int argc, const char *argv[], struct opt *opts, } if ((result = - xiogetaddrinfo(NULL, argv[1], pf, socktype, ipproto, + xioresolve(NULL, argv[1], pf, socktype, ipproto, &us, &uslen, xfd->stream.para.socket.ip.res_opts[0], xfd->stream.para.socket.ip.res_opts[1])) != STAT_OK) { @@ -588,7 +588,7 @@ int xioopen_udp_recv(int argc, const char *argv[], struct opt *opts, } if ((result = - xiogetaddrinfo(NULL, argv[1], pf, socktype, ipproto, + xioresolve(NULL, argv[1], pf, socktype, ipproto, &us, &uslen, xfd->stream.para.socket.ip.res_opts[0], xfd->stream.para.socket.ip.res_opts[1])) != STAT_OK) { @@ -627,6 +627,7 @@ int xioopen_udp_recv(int argc, const char *argv[], struct opt *opts, #if WITH_IP4 /*|| WITH_IP6*/ if (retropt_string(opts, OPT_RANGE, &rangename) >= 0) { if (xioparserange(rangename, pf, &xfd->stream.para.socket.range) < 0) { + free(rangename); return STAT_NORETRY; } xfd->stream.para.socket.dorange = true; diff --git a/xioopts.c b/xioopts.c index cfb75d2..2154a12 100644 --- a/xioopts.c +++ b/xioopts.c @@ -2596,8 +2596,8 @@ int parseopts_table(const char **a, groups_t groups, struct opt **opts, Error1("trailing data in option \"%s\"", token); } *buffp = '\0'; - if (xiogetaddrinfo(buff, NULL, AF_INET, SOCK_DGRAM, IPPROTO_IP, - (union sockaddr_union *)&sa, &salen, + if (xioresolve(buff, NULL, AF_INET, SOCK_DGRAM, IPPROTO_IP, + (union sockaddr_union *)&sa, &salen, 0, 0/*!!!*/) != STAT_OK) { opt->desc = ODESC_ERROR; continue; } @@ -3174,7 +3174,7 @@ int retropt_bind(struct opt *opts, } } if ((result = - xiogetaddrinfo(hostname[0]!='\0'?hostname:NULL, portp, + xioresolve(hostname[0]!='\0'?hostname:NULL, portp, af, socktype, ipproto, (union sockaddr_union *)sa, salen, res_opts0, res_opts1))