Added configure option --with-default-ipv

This commit is contained in:
Gerhard Rieger 2023-10-26 22:16:21 +02:00
parent cb6e16b360
commit 8b2e0593f3
14 changed files with 139 additions and 36 deletions

View file

@ -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/

View file

@ -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) */

View file

@ -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.

View file

@ -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
}

61
test.sh
View file

@ -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

View file

@ -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

View file

@ -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) {

View file

@ -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

View file

@ -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;

View file

@ -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

View file

@ -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

2
xio.h
View file

@ -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 */

View file

@ -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]) {

View file

@ -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 */