SENDTO addresses now prefer IPv4 over IPv6 name resolution

This commit is contained in:
Gerhard Rieger 2024-08-20 16:10:22 +02:00
parent 868998eb60
commit 127280088c
4 changed files with 99 additions and 25 deletions

View file

@ -11,6 +11,11 @@ Corrections:
Added Socat option -0 to allow version 1.8.0.0 behaviour (no preferred Added Socat option -0 to allow version 1.8.0.0 behaviour (no preferred
IP version). IP version).
UDP-SENDTO, UDPLITE-SENDTO, and IP-SENDTO addresses now select an IPv4
address in case the server name resolves to both IPv4 and IPv6
addresses.
Tests: V1800_*_SENDTO_RESOLV_6_4
Guard applyopts_termios_value() with WITH_TERMIOS. Guard applyopts_termios_value() with WITH_TERMIOS.
Thanks to Kush Upadhyay from Amazon Bottlerocket team for providing the Thanks to Kush Upadhyay from Amazon Bottlerocket team for providing the
patch. patch.

86
test.sh
View file

@ -13543,7 +13543,7 @@ te="$td/test$N.stderr"
tdiff="$td/test$N.diff" tdiff="$td/test$N.diff"
da="test$N $(date) $RANDOM" da="test$N $(date) $RANDOM"
newport udp6 newport udp6
CMD0="$TRACE $SOCAT $opts UDP6-RECV:$PORT,ipv6-join-group=[ff02::2]:$MCINTERFACE /dev/null" CMD0="$TRACE $SOCAT $opts -T 0.001 -u UDP6-RECV:$PORT,ipv6-join-group=[ff02::2]:$MCINTERFACE /dev/null"
printf "test $F_n $TEST... " $N printf "test $F_n $TEST... " $N
$CMD0 >/dev/null 2>"${te}0" $CMD0 >/dev/null 2>"${te}0"
rc0=$? rc0=$?
@ -17011,6 +17011,10 @@ elif ! A=$(testaddrs TCP-CONNECT GOPEN); then
$PRINTF "test $F_n $TEST... ${YELLOW}Address $A not available in $SOCAT${NORMAL}\n" $N $PRINTF "test $F_n $TEST... ${YELLOW}Address $A not available in $SOCAT${NORMAL}\n" $N
numCANT=$((numCANT+1)) numCANT=$((numCANT+1))
listCANT="$listCANT $N" listCANT="$listCANT $N"
elif ! o=$(testoptions ai-addrconfig) >/dev/null; then
$PRINTF "test $F_n $TEST... ${YELLOW}Option $o not available in $SOCAT${NORMAL}\n" $N
numCANT=$((numCANT+1))
listCANT="$listCANT $N"
elif ! runsip4 >/dev/null; then elif ! runsip4 >/dev/null; then
$PRINTF "test $F_n $TEST... ${YELLOW}IPv4 not available${NORMAL}\n" $N $PRINTF "test $F_n $TEST... ${YELLOW}IPv4 not available${NORMAL}\n" $N
numCANT=$((numCANT+1)) numCANT=$((numCANT+1))
@ -17858,7 +17862,6 @@ TEST="$NAME: sigint option with SHELL"
# Send the parent a SIGINT; when the child gets SIGINT too (vs.SIGTERM) # Send the parent a SIGINT; when the child gets SIGINT too (vs.SIGTERM)
# the test succeeded # the test succeeded
if ! eval $NUMCOND; then :; if ! eval $NUMCOND; then :;
# Remove unneeded checks, adapt lists of the remaining ones
elif ! F=$(testfeats STDIO SHELL PIPE); then elif ! F=$(testfeats STDIO SHELL PIPE); then
$PRINTF "test $F_n $TEST... ${YELLOW}Feature $F not configured in $SOCAT${NORMAL}\n" $N $PRINTF "test $F_n $TEST... ${YELLOW}Feature $F not configured in $SOCAT${NORMAL}\n" $N
numCANT=$((numCANT+1)) numCANT=$((numCANT+1))
@ -18028,7 +18031,6 @@ TEST="$NAME: sigint option with SYSTEM"
# the test succeeded # the test succeeded
# setsid is required so the initial SIGINT is not delivered to the sub process. # setsid is required so the initial SIGINT is not delivered to the sub process.
if ! eval $NUMCOND; then :; if ! eval $NUMCOND; then :;
# Remove unneeded checks, adapt lists of the remaining ones
elif [ "$UNAME" = "NetBSD" ]; then elif [ "$UNAME" = "NetBSD" ]; then
# On NetBSD-4.0 and NetBSD-9.3 this test hangs (signal has no effect) # On NetBSD-4.0 and NetBSD-9.3 this test hangs (signal has no effect)
# (other versions not tried) # (other versions not tried)
@ -18696,7 +18698,6 @@ TEST="$NAME: f-setpipe-sz on STDIN"
# Start Socat in a shell pipe and have it calling Filan via EXEC and nofork # Start Socat in a shell pipe and have it calling Filan via EXEC and nofork
# Check Filan output if pipe size of its input pipe is modified. # Check Filan output if pipe size of its input pipe is modified.
if ! eval $NUMCOND; then :; if ! eval $NUMCOND; then :;
# Remove unneeded checks, adapt lists of the remaining ones
elif ! $(type true >/dev/null 2>&1); then elif ! $(type true >/dev/null 2>&1); then
$PRINTF "test $F_n $TEST... ${YELLOW}true not available${NORMAL}\n" $N $PRINTF "test $F_n $TEST... ${YELLOW}true not available${NORMAL}\n" $N
numCANT=$((numCANT+1)) numCANT=$((numCANT+1))
@ -18763,7 +18764,6 @@ TEST="$NAME: f-setpipe-sz on EXEC with pipes"
# Start Socat calling Filan via EXEC and pipes and f-setpipe-sz # Start Socat calling Filan via EXEC and pipes and f-setpipe-sz
# Check Filan output if pipe size of both pipes is modified. # Check Filan output if pipe size of both pipes is modified.
if ! eval $NUMCOND; then :; if ! eval $NUMCOND; then :;
# Remove unneeded checks, adapt lists of the remaining ones
elif ! F=$(testfeats STDIO EXEC); then elif ! F=$(testfeats STDIO EXEC); then
$PRINTF "test $F_n $TEST... ${YELLOW}Feature $F not configured in $SOCAT${NORMAL}\n" $N $PRINTF "test $F_n $TEST... ${YELLOW}Feature $F not configured in $SOCAT${NORMAL}\n" $N
numCANT=$((numCANT+1)) numCANT=$((numCANT+1))
@ -18885,7 +18885,6 @@ case "$TESTS" in
*%$N%*|*%functions%*|*%ip4%*|*%ipapp%*|*%udplite%*|*%$NAME%*) *%$N%*|*%functions%*|*%ip4%*|*%ipapp%*|*%udplite%*|*%$NAME%*)
TEST="$NAME: echo via connection to UDP-Lite V4 socket" TEST="$NAME: echo via connection to UDP-Lite V4 socket"
if ! eval $NUMCOND; then :; if ! eval $NUMCOND; then :;
# Remove unneeded checks, adapt lists of the remaining ones
elif ! cond=$(checkconds \ elif ! cond=$(checkconds \
"" \ "" \
"" \ "" \
@ -18953,7 +18952,6 @@ case "$TESTS" in
*%$N%*|*%functions%*|*%ip4%*|*%ipapp%*|*%udplite%*|*%$NAME%*) *%$N%*|*%functions%*|*%ip4%*|*%ipapp%*|*%udplite%*|*%$NAME%*)
TEST="$NAME: echo via connection to UDP-Lite V4 socket" TEST="$NAME: echo via connection to UDP-Lite V4 socket"
if ! eval $NUMCOND; then :; if ! eval $NUMCOND; then :;
# Remove unneeded checks, adapt lists of the remaining ones
elif ! cond=$(checkconds \ elif ! cond=$(checkconds \
"" \ "" \
"" \ "" \
@ -19021,7 +19019,6 @@ case "$TESTS" in
*%$N%*|*%functions%*|*%ip4%*|*%ipapp%*|*%udplite%*|*%$NAME%*) *%$N%*|*%functions%*|*%ip4%*|*%ipapp%*|*%udplite%*|*%$NAME%*)
TEST="$NAME: echo via connection to UDP-Lite V4 socket" TEST="$NAME: echo via connection to UDP-Lite V4 socket"
if ! eval $NUMCOND; then :; if ! eval $NUMCOND; then :;
# Remove unneeded checks, adapt lists of the remaining ones
elif ! cond=$(checkconds \ elif ! cond=$(checkconds \
"" \ "" \
"" \ "" \
@ -19338,7 +19335,6 @@ TEST="$NAME: test socat-chain.sh with SOCKS4 over UNIX-socket"
# Run a socks4 server on UNIX-listen # Run a socks4 server on UNIX-listen
# Connect with socat-chain.sh; check if data transfer is correct # Connect with socat-chain.sh; check if data transfer is correct
if ! eval $NUMCOND; then : if ! eval $NUMCOND; then :
# Remove unneeded checks, adapt lists of the remaining ones
elif ! cond=$(checkconds \ elif ! cond=$(checkconds \
"" \ "" \
"" \ "" \
@ -19410,7 +19406,6 @@ TEST="$NAME: test socat-chain.sh with SSL over PTY"
# open the PTY with socat-chain.sh using SSL; # open the PTY with socat-chain.sh using SSL;
# check if data transfer is correct # check if data transfer is correct
if ! eval $NUMCOND; then : if ! eval $NUMCOND; then :
# Remove unneeded checks, adapt lists of the remaining ones
elif ! cond=$(checkconds \ elif ! cond=$(checkconds \
"" \ "" \
"" \ "" \
@ -19492,7 +19487,6 @@ TEST="$NAME: test the socat-mux.sh script"
# Connect with two clients to mux, send different data records from both. # Connect with two clients to mux, send different data records from both.
# Check if both clients received both records in order. # Check if both clients received both records in order.
if ! eval $NUMCOND; then : if ! eval $NUMCOND; then :
# Remove unneeded checks, adapt lists of the remaining ones
elif ! cond=$(checkconds \ elif ! cond=$(checkconds \
"" \ "" \
"" \ "" \
@ -19604,7 +19598,6 @@ TEST="$NAME: test the socat-broker.sh script"
# Connect with two clients, send different data records from both. # Connect with two clients, send different data records from both.
# Check if both client received both records in order. # Check if both client received both records in order.
if ! eval $NUMCOND; then : if ! eval $NUMCOND; then :
# Remove unneeded checks, adapt lists of the remaining ones
elif ! cond=$(checkconds \ elif ! cond=$(checkconds \
"" \ "" \
"" \ "" \
@ -20195,6 +20188,75 @@ IP-DATAGRAM:1.2.3.4 ip4 PROTO . bind=127.0.0.1
" "
# Test if datagram SENDTO to a server name that resolves to IPv6 first and IPv4
# as second address, binding to an IPv4 address, uses IPv4
# This failed in Socat 1.8.0.0
while read ADDR protov IPPORT _; do
if [ -z "$ADDR" ] || [[ "$ADDR" == \#* ]]; then continue; fi
FEATS=
ADDR_="$(echo $ADDR |tr - _)" # UDP_SENDTO
PROTO="${ADDR%%-*}" # UDP
proto=$(tolower $PROTO) # udp
FEATS="$FEATS $PROTO"
NAME="$(echo "V1800_${ADDR_}_RESOLV_6_4" |sed 's/:[.0-8]*//')"
case "$TESTS" in
*%$N%*|*%functions%*|*%bugs%*|*%ip4%*|*%$protov%*|*%$proto%*|*%socket%*|*%$NAME%*)
TEST="$NAME: test regression of $ADDR with IPv6,4 and binding to IPv4"
# Start a SENDTO command to (internal) test name localhost-6-4.dest-unreach.net
# and bind to an IPv4 address, and terminate immediately.
# When no error occurs the test succeeded.
if ! eval $NUMCOND; then :
elif ! cond=$(checkconds \
"" \
"$([ $IPPORT = PROTO ] && echo root)" \
"" \
"$FEATS DEVTESTS IP4" \
"$ADDR GOPEN" \
"bind" \
"$protov" ); then
$PRINTF "test $F_n $TEST... ${YELLOW}$cond${NORMAL}\n" $N
numCANT=$((numCANT+1))
listCANT="$listCANT $N"
namesCANT="$namesCANT $NAME"
else
tf="$td/test$N.stdout"
te="$td/test$N.stderr"
tdiff="$td/test$N.diff"
da="test$N $(date) $RANDOM"
case X$IPPORT in
XPORT) newport $(tolower $PROTO); _PORT=$PORT ;;
XPROTO) echo "IPPROTO=\"$IPPROTO\""
_PORT=$IPPROTO ;;
esac
CMD0="$TRACE $SOCAT $opts -u /dev/null $ADDR:localhost-6-4.dest-unreach.net:$_PORT,bind=127.0.0.1"
printf "test $F_n $TEST... " $N
$CMD0 2>"${te}0" </dev/null
rc0=$?
if [ "$rc0" -ne 0 ]; then
$PRINTF "$FAILED (rc0=$rc0)\n"
echo "$CMD0 &"
cat "${te}0" >&2
numFAIL=$((numFAIL+1))
listFAIL="$listFAIL $N"
namesFAIL="$namesFAIL $NAME"
else
$PRINTF "$OK\n"
if [ "$VERBOSE" ]; then echo "$CMD0 &"; fi
if [ "$DEBUG" ]; then cat "${te}0" >&2; fi
numOK=$((numOK+1))
listOK="$listOK $N"
fi
fi # NUMCOND
;;
esac
PORT=$((PORT+1))
N=$((N+1))
done <<<"
UDP-SENDTO udp4 PORT
UDPLITE-SENDTO udplite4 PORT
IP-SENDTO ip4 PROTO
"
# end of common tests # end of common tests
################################################################################## ##################################################################################

View file

@ -516,8 +516,11 @@ int xiogetaddrinfo(const char *node, const char *service,
continue; continue;
} }
if ((error_num = Getaddrinfo(node, service, &hints, res)) != 0) { if ((error_num = Getaddrinfo(node, service, &hints, res)) != 0) {
if (*res != NULL) Warn7("getaddrinfo(\"%s\", \"%s\", {0x%02x,%d,%d,%d}, {}): %d",
freeaddrinfo(*res); node?node:"NULL", service?service:"NULL",
hints.ai_flags, hints.ai_family,
hints.ai_socktype, hints.ai_protocol,
error_num);
if (numnode) if (numnode)
free(numnode); free(numnode);
@ -664,7 +667,7 @@ void xiofreeaddrinfo(struct addrinfo *res) {
} }
/* A simple resolver interface that just returns one address, /* A simple resolver interface that just returns one address,
the first found by calling xiogetaddrinfo(). the first found by calling xiogetaddrinfo(), but ev.respects preferred_ip;
pf may be AF_INET, AF_INET6, or AF_UNSPEC; pf may be AF_INET, AF_INET6, or AF_UNSPEC;
on failure logs error message; on failure logs error message;
returns STAT_OK, STAT_RETRYLATER, STAT_NORETRY returns STAT_OK, STAT_RETRYLATER, STAT_NORETRY
@ -683,13 +686,11 @@ int xioresolve(const char *node, const char *service,
if (rc == EAI_AGAIN) { if (rc == EAI_AGAIN) {
Warn3("xioresolve(node=\"%s\", pf=%d, ...): %s", Warn3("xioresolve(node=\"%s\", pf=%d, ...): %s",
node?node:"NULL", pf, gai_strerror(rc)); node?node:"NULL", pf, gai_strerror(rc));
xiofreeaddrinfo(res);
return STAT_RETRYLATER; return STAT_RETRYLATER;
} else if (rc != 0) { } else if (rc != 0) {
Error3("xioresolve(node=\"%s\", pf=%d, ...): %s", Error3("xioresolve(node=\"%s\", pf=%d, ...): %s",
node?node:"NULL", pf, node?node:"NULL", pf,
(rc == EAI_SYSTEM)?strerror(errno):gai_strerror(rc)); (rc == EAI_SYSTEM)?strerror(errno):gai_strerror(rc));
xiofreeaddrinfo(res);
return STAT_NORETRY; return STAT_NORETRY;
} }
if (res == NULL) { if (res == NULL) {

View file

@ -230,16 +230,22 @@ int
bool *lowport, bool *lowport,
int socktype) { int socktype) {
uint16_t port; uint16_t port;
int result; int rc;
retropt_socket_pf(opts, pf); retropt_socket_pf(opts, pf);
if (hostname != NULL || portname != NULL) { if (hostname != NULL || portname != NULL) {
if ((result = rc = xiogetaddrinfo(hostname, portname, *pf, socktype, protocol,
xiogetaddrinfo(hostname, portname, themlist, ai_flags);
*pf, socktype, protocol, if (rc == EAI_AGAIN) {
themlist, ai_flags)) Warn4("_xioopen_ipapp_prepare(node=\"%s\", service=\"%s\", pf=%d, ...): %s",
!= STAT_OK) { hostname?hostname:"NULL", portname?portname:"NULL",
*pf, gai_strerror(rc));
return STAT_RETRYLATER;
} else if (rc != 0) {
Error4("_xioopen_ipapp_prepare(node=\"%s\", service=\"%s\", pf=%d, ...): %s",
hostname?hostname:"NULL", portname?portname:"NULL",
*pf, (rc == EAI_SYSTEM)?strerror(errno):gai_strerror(rc));
return STAT_NORETRY; /*! STAT_RETRYLATER? */ return STAT_NORETRY; /*! STAT_RETRYLATER? */
} }
} }