From 8b2e0593f39e21ddb2461f88ed8603aaa6a83b77 Mon Sep 17 00:00:00 2001 From: Gerhard Rieger Date: Thu, 26 Oct 2023 22:16:21 +0200 Subject: [PATCH] Added configure option --with-default-ipv --- CHANGES | 3 +++ config.h.in | 2 ++ configure.ac | 10 ++++++++ socat.c | 9 ++++++++ test.sh | 61 ++++++++++++++++++++++++++++++++----------------- xio-ip.c | 30 ++++++++++++++++++++++-- xio-ip4.c | 4 ++-- xio-ipapp.c | 6 ++++- xio-openssl.c | 10 ++++++-- xio-rawip.c | 6 ++++- xio-udp.c | 18 ++++++++++++--- xio.h | 2 +- xioinitialize.c | 10 +++++++- xioparam.c | 4 ++-- 14 files changed, 139 insertions(+), 36 deletions(-) diff --git a/CHANGES b/CHANGES index e62e9e7..19006c7 100644 --- a/CHANGES +++ b/CHANGES @@ -75,6 +75,9 @@ Features: Tests: TRY_ADDRS_4 TRY_ADDRS_4_6 Feature recommended by Anand Buddhdev. + configure option --with-default-ipv allows to specify at build time if + IPv4, IPv6, or none of these is the preferred default. + 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/config.h.in b/config.h.in index 5535e9b..6342635 100644 --- a/config.h.in +++ b/config.h.in @@ -723,6 +723,8 @@ #undef WITH_MSGLEVEL +#undef WITH_DEFAULT_IPV /* default IP version: undef, "4", "6" */ + #define BUILD_DATE __DATE__ " " __TIME__ #endif /* !defined(__config_h_included) */ diff --git a/configure.ac b/configure.ac index eaad7b4..f5fae83 100644 --- a/configure.ac +++ b/configure.ac @@ -820,6 +820,16 @@ AC_ARG_ENABLE(msglevel, [ --enable-msglevel=N set max verbosity to debug,in esac], [AC_DEFINE(WITH_MSGLEVEL,0) AC_MSG_RESULT(debug)]) +AC_MSG_CHECKING(default IP version) +AC_ARG_ENABLE(ip-version, [ --enable-ip-version=N set default IP version to undef, "4", "6"], + [case "$enableval" in + "") AC_DEFINE(WITH_DEFAULT_IPV, 0) AC_MSG_RESULT("0");; + 4) AC_DEFINE(WITH_DEFAULT_IPV, '4') AC_MSG_RESULT("4");; + 6) AC_DEFINE(WITH_DEFAULT_IPV, '6') AC_MSG_RESULT("6");; + *) AC_DEFINE(WITH_DEFAULT_IPV, 0) AC_MSG_RESULT("0");; + esac], + [AC_DEFINE(WITH_DEFAULT_IPV, '0') AC_MSG_RESULT("0")]) + #AC_SUBST(V_INCL) dnl Checks for typedefs, structures, and compiler characteristics. diff --git a/socat.c b/socat.c index 4e0e618..c61fc21 100644 --- a/socat.c +++ b/socat.c @@ -676,6 +676,15 @@ void socat_version(FILE *fd) { #else fputs(" #undef WITH_MSGLEVEL\n", fd); #endif +#ifdef WITH_DEFAULT_IPV +# if WITH_DEFAULT_IPV + fprintf(fd, " #define WITH_DEFAULT_IPV %c\n", WITH_DEFAULT_IPV); +# else + fprintf(fd, " #define WITH_DEFAULT_IPV '\\0'\n"); +# endif +#else + fputs(" #undef WITH_DEFAULT_IPV\n", fd); +#endif } diff --git a/test.sh b/test.sh index 193fbe7..439a2c2 100755 --- a/test.sh +++ b/test.sh @@ -44,7 +44,7 @@ usage() { $ECHO "\t-foreign \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 invokations, e.'g:" + $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" @@ -155,7 +155,7 @@ 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 -#LOCALHOST=127.0.0.1 +LOCALHOST4=127.0.0.1 LOCALHOST6="[::1]" #PROTO=$(awk '{print($2);}' /etc/protocols |sort -n |tail -n 1) #PROTO=$(($PROTO+1)) @@ -972,17 +972,11 @@ runssctp4 () { # check if SCTP on IPv6 is available on host runssctp6 () { runsip6 >/dev/null || { echo SCTP6; return 1; } - $SOCAT -h |grep ' SCTP6-' >/dev/null || 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; } -# 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; } @@ -3457,6 +3451,8 @@ 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 @@ -11398,8 +11394,9 @@ if [ $RLIMIT_NOFILE -gt 1024 ]; then 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 - TCP4:$LOCALHOST:$PORT,bind=$LOCALHOST" +CMD2="$TRACE $SOCAT $opts - TCP:$LOCALHOST4:$PORT,bind=$LOCALHOST4" printf "test $F_n $TEST... " $N $CMD0 >/dev/null 2>"${te}0" & pid0=$! @@ -11414,7 +11411,11 @@ kill $pid0 2>/dev/null; wait echo -e "$da" |diff "${tf}2" - >$tdiff if [ $rc2 -ne 0 ]; then $PRINTF "$FAILED (rc2=$rc2)\n" - echo "$CMD2 &" + echo "$CMD0 &" + cat "${te}0" >&2 + echo "$CMD1" + cat "${te}1" >&2 + echo "$CMD2" cat "${te}2" >&2 numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" @@ -11690,20 +11691,20 @@ gentestcert testcli test_proto=tcp4 case "$MODE" in SERVER) - CMD0="$SOCAT $opts -u $TESTADDRESS system:\"echo SOCAT_${SSLDIST}_${MODULE}_${FIELD}=\\\$SOCAT_${SSLDIST}_${MODULE}_${FIELD}; sleep 1\"" + 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" + { $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 $TESTADDRESS system:\"echo SOCAT_${SSLDIST}_${MODULE}_${FIELD}=\\\$SOCAT_${SSLDIST}_${MODULE}_${FIELD}; sleep 1\"" + 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=$! @@ -14663,7 +14664,7 @@ CMD="$TRACE $SOCAT $opts -d -d -d -d /dev/null UDP4-SENDTO:$LOCALHOST:$PORT,lowp printf "test $F_n $TEST... " $N $CMD >/dev/null 2>"${te}" rc1=$? -LOWPORT=$(grep '[DE] bind(.*:' $te |sed 's/.*:\([0-9][0-9]*\),.*/\1/') +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 @@ -15937,10 +15938,12 @@ 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" @@ -16078,6 +16081,10 @@ 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 ! $(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)) @@ -16095,7 +16102,11 @@ 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);}') +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= @@ -16115,7 +16126,7 @@ 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 +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 @@ -16143,8 +16154,12 @@ TEST="$NAME: for TCP try all available IPv4 and IPv6 addresses" # 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 +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 @@ -16169,7 +16184,11 @@ 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);}') +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 OPEN= for addr in $ADDRS; do @@ -16192,7 +16211,7 @@ CMD="$TRACE $SOCAT $opts -d -d /dev/null TCP:localhost-4-6.dest-unreach.net:$POR 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 +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 diff --git a/xio-ip.c b/xio-ip.c index 5e3a6c8..0d68338 100644 --- a/xio-ip.c +++ b/xio-ip.c @@ -104,6 +104,24 @@ const struct optdesc opt_res_dnsrch = { "res-dnsrch", "dnsrch", OPT_RES_DN #endif /* WITH_IP4 || WITH_IP6 */ +int xioinit_ip( + struct single *sfd, + int *pf) +{ + if (*pf == PF_UNSPEC) { + switch (xioparms.preferred_ip) { + case '0': *pf = PF_UNSPEC; break; +#if WITH_IP4 + case '4': *pf = PF_INET; break; +#endif +#if WITH_IP6 + case '6': *pf = PF_INET6; break; +#endif + } + } + return 0; +} + #if HAVE_RESOLV_H int Res_init(void) { int result; @@ -274,7 +292,11 @@ int xiogetaddrinfo(const char *node, const char *service, /* first fallback is getipnodebyname() */ if (family == PF_UNSPEC) { #if WITH_IP4 && WITH_IP6 - family = xioparms.default_ip=='6'?PF_INET6:PF_INET; + switch (xioparms.default_ip) { + case '4': pf = PF_INET; break; + case '6': pf = PF_INET6; break; + default: break; /* includes \0 */ + } #elif WITH_IP6 family = PF_INET6; #else @@ -325,7 +347,11 @@ int xiogetaddrinfo(const char *node, const char *service, be useful somewhere sometimes in a future even for IP6 */ if (family == PF_UNSPEC) { #if WITH_IP4 && WITH_IP6 - family = xioparms.default_ip=='6'?PF_INET6:PF_INET; + switch (xioparms.default_ip) { + case '4': pf = PF_INET; break; + case '6': pf = PF_INET6; break; + default: break; /* includes \0 */ + } #elif WITH_IP6 family = PF_INET6; #else diff --git a/xio-ip4.c b/xio-ip4.c index e6338d2..264a00d 100644 --- a/xio-ip4.c +++ b/xio-ip4.c @@ -33,10 +33,10 @@ int xioparsenetwork_ip4(const char *rangename, struct xiorange *range) { char *endptr; bits = strtoul(delimpos+1, &endptr, 10); if (! ((*(delimpos+1) != '\0') && (*endptr == '\0'))) { - Error1("not a valid netmask in \"%s\"", rangename); + Error1("not a valid IPv4 netmask in \"%s\"", rangename); bits = 32; /* most secure selection */ } else if (bits > 32) { - Error1("netmask \"%s\" is too large", rangename); + Error1("IPv4 netmask \"%s\" is too large", rangename); bits = 32; } if (bits <= 0) { diff --git a/xio-ipapp.c b/xio-ipapp.c index 3fc3370..c0a6b59 100644 --- a/xio-ipapp.c +++ b/xio-ipapp.c @@ -284,7 +284,11 @@ int xioopen_ipapp_listen(int argc, const char *argv[], struct opt *opts, if (pf == PF_UNSPEC) { #if WITH_IP4 && WITH_IP6 - pf = xioparms.default_ip=='6'?PF_INET6:PF_INET; + switch (xioparms.default_ip) { + case '4': pf = PF_INET; break; + case '6': pf = PF_INET6; break; + default: break; /* includes \0 */ + } #elif WITH_IP6 pf = PF_INET6; #else diff --git a/xio-openssl.c b/xio-openssl.c index 24b6285..479cd67 100644 --- a/xio-openssl.c +++ b/xio-openssl.c @@ -548,7 +548,7 @@ static int struct opt *opts0 = NULL; union sockaddr_union us_sa, *us = &us_sa; socklen_t uslen = sizeof(us_sa); - int pf; + int pf = PF_UNSPEC; bool use_dtls = (protogrp != 0); int socktype = SOCK_STREAM; int ipproto = IPPROTO_TCP; @@ -572,7 +572,11 @@ static int } #if WITH_IP4 && WITH_IP6 - pf = xioparms.default_ip=='6'?PF_INET6:PF_INET; + switch (xioparms.default_ip) { + case '4': pf = PF_INET; break; + case '6': pf = PF_INET6; break; + default: break; /* includes \0 */ + } #elif WITH_IP6 pf = PF_INET6; #else @@ -612,6 +616,8 @@ static int != STAT_OK) { return STAT_NORETRY; } + if (pf == 0) + pf = us->soa.sa_family; xfd->dtype = XIODATA_OPENSSL; diff --git a/xio-rawip.c b/xio-rawip.c index 6d60d77..76984f9 100644 --- a/xio-rawip.c +++ b/xio-rawip.c @@ -226,7 +226,11 @@ int xioopen_rawip_recvfrom(int argc, const char *argv[], struct opt *opts, retropt_socket_pf(opts, &pf); if (pf == PF_UNSPEC) { #if WITH_IP4 && WITH_IP6 - pf = xioparms.default_ip=='6'?PF_INET6:PF_INET; + switch (xioparms.default_ip) { + case '4': pf = PF_INET; break; + case '6': pf = PF_INET6; break; + default: break; /* includes \0 */ + } #elif WITH_IP6 pf = PF_INET6; #else diff --git a/xio-udp.c b/xio-udp.c index ee6af64..5a3215f 100644 --- a/xio-udp.c +++ b/xio-udp.c @@ -296,7 +296,11 @@ int xioopen_ipdgram_listen(int argc, const char *argv[], struct opt *opts, if (pf == PF_UNSPEC) { #if WITH_IP4 && WITH_IP6 - pf = xioparms.default_ip=='6'?PF_INET6:PF_INET; + switch (xioparms.default_ip) { + case '4': pf = PF_INET; break; + case '6': pf = PF_INET6; break; + default: break; /* includes \0 */ + } #elif WITH_IP6 pf = PF_INET6; #else @@ -506,7 +510,11 @@ int xioopen_udp_recvfrom(int argc, const char *argv[], struct opt *opts, retropt_socket_pf(opts, &pf); if (pf == PF_UNSPEC) { #if WITH_IP4 && WITH_IP6 - pf = xioparms.default_ip=='6'?PF_INET6:PF_INET; + switch (xioparms.default_ip) { + case '4': pf = PF_INET; break; + case '6': pf = PF_INET6; break; + default: break; /* includes \0 */ + } #elif WITH_IP6 pf = PF_INET6; #else @@ -579,7 +587,11 @@ int xioopen_udp_recv(int argc, const char *argv[], struct opt *opts, retropt_socket_pf(opts, &pf); if (pf == PF_UNSPEC) { #if WITH_IP4 && WITH_IP6 - pf = xioparms.default_ip=='6'?PF_INET6:PF_INET; + switch (xioparms.default_ip) { + case '4': pf = PF_INET; break; + case '6': pf = PF_INET6; break; + default: break; /* includes \0 */ + } #elif WITH_IP6 pf = PF_INET6; #else diff --git a/xio.h b/xio.h index 596d101..910909c 100644 --- a/xio.h +++ b/xio.h @@ -109,7 +109,7 @@ typedef struct { char ip6portsep; /* do not change, might be hardcoded somewhere! */ char logopt; /* 'm' means "switch to syslog when entering daemon mode" */ const char *syslogfac; /* syslog facility (only with mixed mode) */ - char default_ip; /* default prot.fam for IP based listen ('4' or '6') */ + char default_ip; /* default prot.fam for IP based listen ('4' '6' or '\0') */ char preferred_ip; /* preferred prot.fam. for name resolution ('0' for unspecified, '4', or '6') */ bool experimental; /* enable some features */ diff --git a/xioinitialize.c b/xioinitialize.c index 880f828..ec06c7b 100644 --- a/xioinitialize.c +++ b/xioinitialize.c @@ -71,17 +71,25 @@ int xioinitialize(void) { { const char *default_ip; + + // xioparms.default_ip = WITH_DEFAULT_IPV; default_ip = getenv("SOCAT_DEFAULT_LISTEN_IP"); if (default_ip != NULL) { switch (default_ip[0]) { case '4': case '6': - xioparms.default_ip = default_ip[0]; break; + xioparms.default_ip = default_ip[0]; + break; + default: + xioparms.default_ip = '0'; + break; } } } { const char *preferred_ip; + + // xioparms.preferred_ip = WITH_DEFAULT_IPV; preferred_ip = getenv("SOCAT_PREFERRED_RESOLVE_IP"); if (preferred_ip != NULL) { switch (preferred_ip[0]) { diff --git a/xioparam.c b/xioparam.c index 5a4d3da..11830c5 100644 --- a/xioparam.c +++ b/xioparam.c @@ -19,8 +19,8 @@ xioparms_t xioparms = { ':', /* ip6portsep */ '\0', /* logopt */ NULL, /* syslogfac */ - '4', /* default_ip */ - '4', /* preferred_ip */ + WITH_DEFAULT_IPV, /* default_ip */ + WITH_DEFAULT_IPV, /* preferred_ip */ false, /* experimental */ NULL, /* sniffleft_name */ NULL /* sniffright_name */