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
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.
Thanks to Kush Upadhyay from Amazon Bottlerocket team for providing the
patch.

86
test.sh
View file

@ -13543,7 +13543,7 @@ te="$td/test$N.stderr"
tdiff="$td/test$N.diff"
da="test$N $(date) $RANDOM"
newport udp6
CMD0="$TRACE $SOCAT $opts UDP6-RECV:$PORT,ipv6-join-group=[ff02::2]:$MCINTERFACE /dev/null"
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
$CMD0 >/dev/null 2>"${te}0"
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
numCANT=$((numCANT+1))
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
$PRINTF "test $F_n $TEST... ${YELLOW}IPv4 not available${NORMAL}\n" $N
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)
# the test succeeded
if ! eval $NUMCOND; then :;
# Remove unneeded checks, adapt lists of the remaining ones
elif ! F=$(testfeats STDIO SHELL PIPE); then
$PRINTF "test $F_n $TEST... ${YELLOW}Feature $F not configured in $SOCAT${NORMAL}\n" $N
numCANT=$((numCANT+1))
@ -18028,7 +18031,6 @@ TEST="$NAME: sigint option with SYSTEM"
# the test succeeded
# setsid is required so the initial SIGINT is not delivered to the sub process.
if ! eval $NUMCOND; then :;
# Remove unneeded checks, adapt lists of the remaining ones
elif [ "$UNAME" = "NetBSD" ]; then
# On NetBSD-4.0 and NetBSD-9.3 this test hangs (signal has no effect)
# (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
# Check Filan output if pipe size of its input pipe is modified.
if ! eval $NUMCOND; then :;
# Remove unneeded checks, adapt lists of the remaining ones
elif ! $(type true >/dev/null 2>&1); then
$PRINTF "test $F_n $TEST... ${YELLOW}true not available${NORMAL}\n" $N
numCANT=$((numCANT+1))
@ -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
# Check Filan output if pipe size of both pipes is modified.
if ! eval $NUMCOND; then :;
# Remove unneeded checks, adapt lists of the remaining ones
elif ! F=$(testfeats STDIO EXEC); then
$PRINTF "test $F_n $TEST... ${YELLOW}Feature $F not configured in $SOCAT${NORMAL}\n" $N
numCANT=$((numCANT+1))
@ -18885,7 +18885,6 @@ case "$TESTS" in
*%$N%*|*%functions%*|*%ip4%*|*%ipapp%*|*%udplite%*|*%$NAME%*)
TEST="$NAME: echo via connection to UDP-Lite V4 socket"
if ! eval $NUMCOND; then :;
# Remove unneeded checks, adapt lists of the remaining ones
elif ! cond=$(checkconds \
"" \
"" \
@ -18953,7 +18952,6 @@ case "$TESTS" in
*%$N%*|*%functions%*|*%ip4%*|*%ipapp%*|*%udplite%*|*%$NAME%*)
TEST="$NAME: echo via connection to UDP-Lite V4 socket"
if ! eval $NUMCOND; then :;
# Remove unneeded checks, adapt lists of the remaining ones
elif ! cond=$(checkconds \
"" \
"" \
@ -19021,7 +19019,6 @@ case "$TESTS" in
*%$N%*|*%functions%*|*%ip4%*|*%ipapp%*|*%udplite%*|*%$NAME%*)
TEST="$NAME: echo via connection to UDP-Lite V4 socket"
if ! eval $NUMCOND; then :;
# Remove unneeded checks, adapt lists of the remaining ones
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
# Connect with socat-chain.sh; check if data transfer is correct
if ! eval $NUMCOND; then :
# Remove unneeded checks, adapt lists of the remaining ones
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;
# check if data transfer is correct
if ! eval $NUMCOND; then :
# Remove unneeded checks, adapt lists of the remaining ones
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.
# Check if both clients received both records in order.
if ! eval $NUMCOND; then :
# Remove unneeded checks, adapt lists of the remaining ones
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.
# Check if both client received both records in order.
if ! eval $NUMCOND; then :
# Remove unneeded checks, adapt lists of the remaining ones
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
##################################################################################

View file

@ -516,8 +516,11 @@ int xiogetaddrinfo(const char *node, const char *service,
continue;
}
if ((error_num = Getaddrinfo(node, service, &hints, res)) != 0) {
if (*res != NULL)
freeaddrinfo(*res);
Warn7("getaddrinfo(\"%s\", \"%s\", {0x%02x,%d,%d,%d}, {}): %d",
node?node:"NULL", service?service:"NULL",
hints.ai_flags, hints.ai_family,
hints.ai_socktype, hints.ai_protocol,
error_num);
if (numnode)
free(numnode);
@ -664,7 +667,7 @@ void xiofreeaddrinfo(struct addrinfo *res) {
}
/* 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;
on failure logs error message;
returns STAT_OK, STAT_RETRYLATER, STAT_NORETRY
@ -683,13 +686,11 @@ int xioresolve(const char *node, const char *service,
if (rc == EAI_AGAIN) {
Warn3("xioresolve(node=\"%s\", pf=%d, ...): %s",
node?node:"NULL", pf, gai_strerror(rc));
xiofreeaddrinfo(res);
return STAT_RETRYLATER;
} else if (rc != 0) {
Error3("xioresolve(node=\"%s\", pf=%d, ...): %s",
node?node:"NULL", pf,
(rc == EAI_SYSTEM)?strerror(errno):gai_strerror(rc));
xiofreeaddrinfo(res);
return STAT_NORETRY;
}
if (res == NULL) {

View file

@ -230,18 +230,24 @@ int
bool *lowport,
int socktype) {
uint16_t port;
int result;
int rc;
retropt_socket_pf(opts, pf);
if (hostname != NULL || portname != NULL) {
if ((result =
xiogetaddrinfo(hostname, portname,
*pf, socktype, protocol,
themlist, ai_flags))
!= STAT_OK) {
return STAT_NORETRY; /*! STAT_RETRYLATER? */
}
rc = xiogetaddrinfo(hostname, portname, *pf, socktype, protocol,
themlist, ai_flags);
if (rc == EAI_AGAIN) {
Warn4("_xioopen_ipapp_prepare(node=\"%s\", service=\"%s\", pf=%d, ...): %s",
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? */
}
}
applyopts(NULL, -1, opts, PH_EARLY);