LISTEN based addresses applied some address options to the listening FD instead of the connected FD

This commit is contained in:
Gerhard Rieger 2014-03-21 09:44:16 +01:00
parent 9ce2ff3492
commit 6ccae440f1
7 changed files with 88 additions and 14 deletions

View file

@ -1,5 +1,10 @@
corrections: corrections:
LISTEN based addresses applied some address options, e.g. so-keepalive,
to the listening file descriptor instead of the connected file
descriptor
Thanks to Ulises Alonso for reporting this bug
make failed after configure with non gcc compiler due to missing make failed after configure with non gcc compiler due to missing
include. Thanks to Horacio Mijail for reporting this problem include. Thanks to Horacio Mijail for reporting this problem

View file

@ -131,13 +131,12 @@ PH_LATE FD is ready, before start of data loop
PH_LATE2 FD is ready, dropping privileges PH_LATE2 FD is ready, dropping privileges
SOCKET with LISTEN and FORK: SOCKET with LISTEN and ACCEPT:
PH_INIT retrieving info from original state PH_INIT retrieving info from original state
PH_EARLY before any other processing PH_EARLY before any other processing
PH_PRESOCKET before socket call PH_PRESOCKET before socket call
PH_SOCKET for socket call PH_SOCKET for socket call
PH_PASTSOCKET after socket call
PH_PREBIND before socket bind() PH_PREBIND before socket bind()
PH_BIND during socket bind() PH_BIND during socket bind()
PH_PASTBIND past socket bind() PH_PASTBIND past socket bind()
@ -147,7 +146,9 @@ PH_PASTLISTEN after listen()
PH_PREACCEPT before accept() PH_PREACCEPT before accept()
PH_ACCEPT during accept() PH_ACCEPT during accept()
PH_PASTACCEPT after accept() PH_PASTACCEPT after accept()
# and the following on the new FD:
PH_FD soon after FD creation or identification PH_FD soon after FD creation or identification
PH_PASTSOCKET after socket call
PH_CONNECTED phase common with connect PH_CONNECTED phase common with connect
PH_PREFORK before forking PH_PREFORK before forking
PH_FORK during fork() PH_FORK during fork()

View file

@ -1,6 +1,6 @@
#! /bin/bash #! /bin/bash
# source: predialog.sh # source: predialog.sh
# Copyright Gerhard Rieger 2009 # Copyright Gerhard Rieger
# Published under the GNU General Public License V.2, see file COPYING # Published under the GNU General Public License V.2, see file COPYING
# This is an example script that shows how to write a script for use with socat # This is an example script that shows how to write a script for use with socat
@ -15,6 +15,14 @@
RINFD=3 RINFD=3
ROUTFD=4 ROUTFD=4
if [ -z "$SOCAT" ]; then
if type socat2 >/dev/null 2>&1; then
SOCAT=socat2
else
SOCAT="./socat"
fi
fi
verbose= verbose=
# parse options # parse options
SPACES=" " SPACES=" "
@ -50,4 +58,4 @@ wait
msg "starting data transfer" msg "starting data transfer"
# now just pass traffic in both directions # now just pass traffic in both directions
#SOCAT_OPTS="-lu -d -d -d -d" #SOCAT_OPTS="-lu -d -d -d -d"
exec socat $SOCAT_OPTS - "fd:$ROUTFD:$RINFD" exec $SOCAT $SOCAT_OPTS - "fd:$ROUTFD:$RINFD"

64
test.sh
View file

@ -2835,10 +2835,13 @@ esac
PORT=$((PORT+1)) PORT=$((PORT+1))
N=$((N+1)) N=$((N+1))
# TCP6-LISTEN may also listen for IPv4 connections. Test if option
# ipv6-v6only=0 shows this behaviour.
NAME=IPV6ONLY0 NAME=IPV6ONLY0
case "$TESTS" in case "$TESTS" in
*%$N%*|*%functions%*|*%ip6%*|*%ipapp%*|*%tcp%*|*%$NAME%*) *%$N%*|*%functions%*|*%ip6%*|*%ipapp%*|*%tcp%*|*%$NAME%*)
TEST="$NAME: option ipv6-v6only=0 listens on IPv4" TEST="$NAME: option ipv6-v6only=0 listens on IPv4"
# create a listening TCP6 socket and try to connect to the port using TCP4
if ! eval $NUMCOND; then :; if ! eval $NUMCOND; then :;
elif ! testaddrs tcp ip4 >/dev/null || ! runsip4 >/dev/null; then elif ! testaddrs tcp ip4 >/dev/null || ! runsip4 >/dev/null; then
$PRINTF "test $F_n $TEST... ${YELLOW}TCP4 not available${NORMAL}\n" $N $PRINTF "test $F_n $TEST... ${YELLOW}TCP4 not available${NORMAL}\n" $N
@ -2856,8 +2859,8 @@ tdiff="$td/test$N.diff"
tsl=$PORT tsl=$PORT
ts="127.0.0.1:$tsl" ts="127.0.0.1:$tsl"
da="test$N $(date) $RANDOM" da="test$N $(date) $RANDOM"
CMD1="$SOCAT $opts TCP6-listen:$tsl,ipv6-v6only=0,reuseaddr PIPE" CMD1="$SOCAT $opts TCP6-LISTEN:$tsl,ipv6-v6only=0,reuseaddr PIPE"
CMD2="$SOCAT $opts stdout%stdin TCP4:$ts" CMD2="$SOCAT $opts STDOUT%STDIN TCP4:$ts"
printf "test $F_n $TEST... " $N printf "test $F_n $TEST... " $N
$CMD1 >"$tf" 2>"${te}1" & $CMD1 >"$tf" 2>"${te}1" &
pid=$! # background process id pid=$! # background process id
@ -2886,6 +2889,8 @@ esac
PORT=$((PORT+1)) PORT=$((PORT+1))
N=$((N+1)) N=$((N+1))
# TCP6-LISTEN may also listen for IPv4 connections. Test if option
# ipv6-v6only=1 turns off this behaviour.
NAME=IPV6ONLY1 NAME=IPV6ONLY1
case "$TESTS" in case "$TESTS" in
*%$N%*|*%functions%*|*%ip6%*|*%ipapp%*|*%tcp%*|*%$NAME%*) *%$N%*|*%functions%*|*%ip6%*|*%ipapp%*|*%tcp%*|*%$NAME%*)
@ -10559,6 +10564,8 @@ SOL_SOCKET="$($PROCAN -c |grep "^#define[[:space:]]*SOL_SOCKET[[:space:]]" |cut
SO_REUSEADDR="$($PROCAN -c |grep "^#define[[:space:]]*SO_REUSEADDR[[:space:]]" |cut -d' ' -f3)" SO_REUSEADDR="$($PROCAN -c |grep "^#define[[:space:]]*SO_REUSEADDR[[:space:]]" |cut -d' ' -f3)"
# test the generic setsockopt-int option # test the generic setsockopt-int option
if false; then
# this test no longer works due to fix for options on listening sockets
NAME=SETSOCKOPT_INT NAME=SETSOCKOPT_INT
case "$TESTS" in case "$TESTS" in
*%$N%*|*%functions%*|*%ip4%*|*%tcp%*|*%generic%*|*%$NAME%*) *%$N%*|*%functions%*|*%ip4%*|*%tcp%*|*%generic%*|*%$NAME%*)
@ -10628,6 +10635,8 @@ fi # NUMCOND, SO_REUSEADDR
esac esac
PORT=$((PORT+1)) PORT=$((PORT+1))
N=$((N+1)) N=$((N+1))
#
fi
NAME=SCTP4STREAM NAME=SCTP4STREAM
@ -11562,6 +11571,57 @@ N=$((N+1))
fi # false fi # false
# LISTEN addresses in socat up to 1.7.2.1 and 2.0.0-b7 applied many file
# descriptor, socket, and TCP options only to the listening socket instead of the
# connection socket.
NAME=LISTEN_KEEPALIVE
case "$TESTS" in
*%functions%*|*%bugs%*|*%listen%*|*%keepalive%*|*%socket%*|*%$NAME%*)
TEST="$NAME: keepalive option is applied to connection socket"
# instance 0 has TCP-LISTEN with option so-keepalive and invokes filan after
# accept(). filan writes its output to the socket. instance 1 connects to
# instance 0. The value of the sockets so-keepalive option is checked, it must
# be 1
if ! eval $NUMCOND; then :; else
tf="$td/test$N.stdout"
te="$td/test$N.stderr"
#tdiff="$td/test$N.diff"
#da="test$N $(date) $RANDOM"
CMD0="$SOCAT $opts TCP4-LISTEN:$PORT,reuseaddr,so-keepalive EXEC:\"$FILAN -i 1\",nofork"
CMD1="$SOCAT $opts - TCP4:$LOCALHOST:$PORT"
printf "test $F_n $TEST... " $N
eval $CMD0 >/dev/null 2>"${te}0" &
pid0=$!
waittcp4port $PORT 1
$CMD1 >"${tf}1" 2>"${te}1"
KEEPALIVE="$(cat "${tf}1" |tail -n +2 |sed -e "s/.*KEEPALIVE=//" -e "s/[[:space:]].*//")"
rc1=$?
kill $pid0 2>/dev/null; wait
if [ -z "$KEEPALIVE" ]; then
$PRINTF "$NO_RESULT\n"
echo "$CMD0 &"
echo "$CMD1"
cat "${te}0"
cat "${te}1"
numWARN=$((numWARN+1))
elif [ "$KEEPALIVE" = "1" ]; then
$PRINTF "$OK\n";
numOK=$((numOK+1))
else
$PRINTF "$FAILED\n"
echo "$CMD0 &"
echo "$CMD1"
cat "${te}0"
cat "${te}1"
numFAIL=$((numFAIL+1))
fi
fi # NUMCOND
;;
esac
PORT=$((PORT+1))
N=$((N+1))
############################################################################### ###############################################################################
# here come tests that might affect your systems integrity. Put normal tests # here come tests that might affect your systems integrity. Put normal tests
# before this paragraph. # before this paragraph.

View file

@ -1,5 +1,5 @@
/* source: xio-ip6.c */ /* source: xio-ip6.c */
/* Copyright Gerhard Rieger 2001-2012 */ /* Copyright Gerhard Rieger */
/* Published under the GNU General Public License V.2, see file COPYING */ /* Published under the GNU General Public License V.2, see file COPYING */
/* this file contains the source for IP6 related functions */ /* this file contains the source for IP6 related functions */
@ -20,7 +20,7 @@ static char *inet6addr_info(const struct in6_addr *sa, char *buff, size_t blen);
#ifdef IPV6_V6ONLY #ifdef IPV6_V6ONLY
const struct optdesc opt_ipv6_v6only = { "ipv6-v6only", "ipv6only", OPT_IPV6_V6ONLY, GROUP_SOCK_IP6, PH_PASTSOCKET, TYPE_BOOL, OFUNC_SOCKOPT, SOL_IPV6, IPV6_V6ONLY }; const struct optdesc opt_ipv6_v6only = { "ipv6-v6only", "ipv6only", OPT_IPV6_V6ONLY, GROUP_SOCK_IP6, PH_PREBIND, TYPE_BOOL, OFUNC_SOCKOPT, SOL_IPV6, IPV6_V6ONLY };
#endif #endif
#ifdef IPV6_JOIN_GROUP #ifdef IPV6_JOIN_GROUP
const struct optdesc opt_ipv6_join_group = { "ipv6-join-group", "join-group", OPT_IPV6_JOIN_GROUP, GROUP_SOCK_IP6, PH_PASTBIND, TYPE_IP_MREQN, OFUNC_SOCKOPT, SOL_IPV6, IPV6_JOIN_GROUP }; const struct optdesc opt_ipv6_join_group = { "ipv6-join-group", "join-group", OPT_IPV6_JOIN_GROUP, GROUP_SOCK_IP6, PH_PASTBIND, TYPE_IP_MREQN, OFUNC_SOCKOPT, SOL_IPV6, IPV6_JOIN_GROUP };

View file

@ -148,8 +148,6 @@ int _xioopen_listen(struct single *xfd, int xioflags, struct sockaddr *us, sockl
return STAT_RETRYLATER; return STAT_RETRYLATER;
} }
applyopts(xfd->rfd, opts, PH_PASTSOCKET);
applyopts_cloexec(xfd->rfd, opts); applyopts_cloexec(xfd->rfd, opts);
applyopts(xfd->rfd, opts, PH_PREBIND); applyopts(xfd->rfd, opts, PH_PREBIND);
@ -184,6 +182,7 @@ int _xioopen_listen(struct single *xfd, int xioflags, struct sockaddr *us, sockl
} }
#endif /* WITH_UNIX */ #endif /* WITH_UNIX */
applyopts(xfd->rfd, opts, PH_PRELISTEN);
retropt_int(opts, OPT_BACKLOG, &backlog); retropt_int(opts, OPT_BACKLOG, &backlog);
if (Listen(xfd->rfd, backlog) < 0) { if (Listen(xfd->rfd, backlog) < 0) {
Error3("listen(%d, %d): %s", xfd->rfd, backlog, strerror(errno)); Error3("listen(%d, %d): %s", xfd->rfd, backlog, strerror(errno));
@ -284,9 +283,6 @@ int _xioopen_listen(struct single *xfd, int xioflags, struct sockaddr *us, sockl
sockaddr_info((struct sockaddr *)pa, pas, sockaddr_info((struct sockaddr *)pa, pas,
infobuff, sizeof(infobuff))); infobuff, sizeof(infobuff)));
applyopts(xfd->rfd, opts, PH_FD);
applyopts(xfd->rfd, opts, PH_CONNECTED);
if (dofork) { if (dofork) {
pid_t pid; /* mostly int; only used with fork */ pid_t pid; /* mostly int; only used with fork */
sigset_t mask_sigchld; sigset_t mask_sigchld;
@ -352,6 +348,10 @@ int _xioopen_listen(struct single *xfd, int xioflags, struct sockaddr *us, sockl
break; break;
} }
} }
applyopts(xfd->rfd, opts, PH_FD);
applyopts(xfd->rfd, opts, PH_PASTSOCKET);
applyopts(xfd->rfd, opts, PH_CONNECTED);
if ((result = _xio_openlate(xfd, opts)) < 0) if ((result = _xio_openlate(xfd, opts)) < 0)
return result; return result;

View file

@ -115,7 +115,7 @@ const struct optdesc opt_so_debug = { "so-debug", "debug", OPT_SO_DEBUG,
const struct optdesc opt_so_acceptconn={ "so-acceptconn","acceptconn",OPT_SO_ACCEPTCONN,GROUP_SOCKET,PH_PASTSOCKET,TYPE_INT, OFUNC_SOCKOPT, SOL_SOCKET, SO_ACCEPTCONN}; const struct optdesc opt_so_acceptconn={ "so-acceptconn","acceptconn",OPT_SO_ACCEPTCONN,GROUP_SOCKET,PH_PASTSOCKET,TYPE_INT, OFUNC_SOCKOPT, SOL_SOCKET, SO_ACCEPTCONN};
#endif /* SO_ACCEPTCONN */ #endif /* SO_ACCEPTCONN */
const struct optdesc opt_so_broadcast= { "so-broadcast", "broadcast", OPT_SO_BROADCAST,GROUP_SOCKET, PH_PASTSOCKET, TYPE_INT, OFUNC_SOCKOPT, SOL_SOCKET, SO_BROADCAST}; const struct optdesc opt_so_broadcast= { "so-broadcast", "broadcast", OPT_SO_BROADCAST,GROUP_SOCKET, PH_PASTSOCKET, TYPE_INT, OFUNC_SOCKOPT, SOL_SOCKET, SO_BROADCAST};
const struct optdesc opt_so_reuseaddr= { "so-reuseaddr", "reuseaddr", OPT_SO_REUSEADDR,GROUP_SOCKET, PH_PASTSOCKET, TYPE_INT, OFUNC_SOCKOPT, SOL_SOCKET, SO_REUSEADDR}; const struct optdesc opt_so_reuseaddr= { "so-reuseaddr", "reuseaddr", OPT_SO_REUSEADDR,GROUP_SOCKET, PH_PREBIND, TYPE_INT, OFUNC_SOCKOPT, SOL_SOCKET, SO_REUSEADDR};
const struct optdesc opt_so_keepalive= { "so-keepalive", "keepalive", OPT_SO_KEEPALIVE,GROUP_SOCKET, PH_FD, TYPE_INT, OFUNC_SOCKOPT, SOL_SOCKET, SO_KEEPALIVE}; const struct optdesc opt_so_keepalive= { "so-keepalive", "keepalive", OPT_SO_KEEPALIVE,GROUP_SOCKET, PH_FD, TYPE_INT, OFUNC_SOCKOPT, SOL_SOCKET, SO_KEEPALIVE};
#if HAVE_STRUCT_LINGER #if HAVE_STRUCT_LINGER
const struct optdesc opt_so_linger = { "so-linger", "linger", OPT_SO_LINGER, GROUP_SOCKET, PH_PASTSOCKET, TYPE_LINGER,OFUNC_SOCKOPT,SOL_SOCKET, SO_LINGER }; const struct optdesc opt_so_linger = { "so-linger", "linger", OPT_SO_LINGER, GROUP_SOCKET, PH_PASTSOCKET, TYPE_LINGER,OFUNC_SOCKOPT,SOL_SOCKET, SO_LINGER };