mirror of
https://repo.or.cz/socat.git
synced 2024-12-22 07:22:34 +00:00
New option bind-tempname for parallel UNIX domain SENDTO clients
This commit is contained in:
parent
8641344c73
commit
b2914a0cf3
17 changed files with 551 additions and 86 deletions
9
CHANGES
9
CHANGES
|
@ -152,6 +152,15 @@ Features:
|
|||
afterwards.
|
||||
Tests: UMASK_ON_CREATE UMASK_ON_SYSTEM
|
||||
|
||||
Added option unix-bind-tempname (bind-tempname) to allow UNIX (and
|
||||
ABSTRACT) client addresses to bind to unique addresses even when
|
||||
invoked in forked off sub processes.
|
||||
Tests: UNIX_LISTEN_CONNECT_BIND_TEMPNAME UNIX_LISTEN_CLIENT_BIND_TEMPNAME
|
||||
UNIX_RECVFROM_CLIENT_BIND_TEMPNAME UNIX_RECVFROM_SENDTO_BIND_TEMPNAME
|
||||
ABSTRACT_LISTEN_CONNECT_BIND_TEMPNAME ABSTRACT_LISTEN_CLIENT_BIND_TEMPNAME
|
||||
ABSTRACT_RECVFROM_CLIENT_BIND_TEMPNAME ABSTRACT_RECVFROM_SENDTO_BIND_TEMPNAME
|
||||
Thanks to Kai Lüke for sending an initial patch.
|
||||
|
||||
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/
|
||||
|
|
|
@ -22,7 +22,8 @@ srcdir = @srcdir@
|
|||
VPATH = @srcdir@
|
||||
|
||||
CC = @CC@
|
||||
#CCOPT=-fcf-protection=none # for gdb on Ubuntu-20.04
|
||||
#CCOPT1=-no-pie -fstack-protector
|
||||
#CCOPT=$(CCOPT1) -fcf-protection=none # for gdb on Ubuntu-20.04
|
||||
CCOPTS = $(CCOPT)
|
||||
|
||||
SYSDEFS = @SYSDEFS@
|
||||
|
|
7
compat.h
7
compat.h
|
@ -831,6 +831,13 @@ typedef unsigned long T_sigset;
|
|||
# endif
|
||||
#endif
|
||||
|
||||
/* OpenBSD (at least 7.2) does better with this special setting */
|
||||
#if __FreeBSD__ || __OpenBSD__
|
||||
# define UNIX_TIGHTSOCKLEN false
|
||||
#else
|
||||
# define UNIX_TIGHTSOCKLEN true
|
||||
#endif
|
||||
|
||||
/* Cygwin 1.3.22 has the prototypes, but not the type... */
|
||||
#ifndef HAVE_TYPE_STAT64
|
||||
# undef HAVE_STAT64
|
||||
|
|
13
doc/socat.yo
13
doc/socat.yo
|
@ -2136,8 +2136,8 @@ label(OPTION_BIND)dit(bf(tt(bind=<sockname>)))
|
|||
Binds the socket to the given socket address using the code(bind()) system
|
||||
call. The form of <sockname> is socket domain dependent:
|
||||
IP4 and IP6 allow the form [hostname|hostaddress][:(service|port)] (link(example)(EXAMPLE_OPTION_BIND_TCP4)),
|
||||
unixdomain() sockets require link(<filename>)(TYPE_FILENAME),
|
||||
VSOCK allow the form [cid][:(port)].
|
||||
VSOCK allows the form [cid][:(port)].nl()
|
||||
See also: link(unix-bind-tempname)(OPTION_UNIX_BIND_TEMPNAME)
|
||||
label(OPTION_CONNECT_TIMEOUT)dit(bf(tt(connect-timeout=<seconds>)))
|
||||
Abort the connection attempt after <seconds> [link(timeval)(TYPE_TIMEVAL)]
|
||||
with error status.
|
||||
|
@ -2292,6 +2292,15 @@ label(GROUP_SOCK_UNIX)em(bf(UNIX option group))
|
|||
|
||||
These options apply to UNIX domain based addresses.
|
||||
startdit()
|
||||
label(OPTION_UNIX_BIND_TEMPNAME)dit(bf(tt(bind-tempname[=/tmp/pre-XXXXXX],
|
||||
unix-bind-tempname[=/tmp/pre-XXXXXX])))
|
||||
Binds to a random path or random address (on abstract namespace sockets).
|
||||
This is useful with datagram client addresses (tt(SENDTO), or tt(CLIENT))
|
||||
that are opened in child processes forked off from a common
|
||||
parent process where the child processes cannot have different bind options.
|
||||
In the path code(X)'s get replaced with a random character sequence
|
||||
similar to NOEXPAND(tempnam(3)). When no argument is given socat() takes a
|
||||
default like code(/tmp/fileXXXXXX).nl()
|
||||
label(OPTION_UNIX_TIGHTSOCKLEN)dit(bf(tt(unix-tightsocklen[=(0|1)])))
|
||||
On socket operations, pass a socket address length that does not include the
|
||||
whole code(struct sockaddr_un) record but (besides other components) only
|
||||
|
|
2
error.c
2
error.c
|
@ -128,6 +128,8 @@ static int diag_sock_pair(void) {
|
|||
fcntl(diag_sock_send, F_SETFL, O_NONBLOCK);
|
||||
fcntl(diag_sock_recv, F_SETFL, O_NONBLOCK);
|
||||
#endif
|
||||
fcntl(diag_sock_send, F_SETFD, FD_CLOEXEC);
|
||||
fcntl(diag_sock_recv, F_SETFD, FD_CLOEXEC);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
16
procan.c
16
procan.c
|
@ -156,13 +156,23 @@ int procan(FILE *outfile) {
|
|||
rlim.rlim_cur, rlim.rlim_max);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef SIZE_MAX
|
||||
fprintf(outfile, "SIZE_MAX = %-24lu\n", SIZE_MAX);
|
||||
fprintf(outfile, "SIZE_MAX = %-24lu\n", SIZE_MAX);
|
||||
#endif
|
||||
#ifdef P_tmpdir
|
||||
fprintf(outfile, "P_tmpdir = \"%s\"\n", P_tmpdir);
|
||||
#endif
|
||||
#ifdef L_tmpnam
|
||||
fprintf(outfile, "L_tmpnam = %u\n", L_tmpnam);
|
||||
#endif
|
||||
#ifdef TMP_MAX
|
||||
fprintf(outfile, "TMP_MAX = %d\n", TMP_MAX);
|
||||
#endif
|
||||
#ifdef PIPE_BUF
|
||||
fprintf(outfile, "PIPE_BUF = %-24d\n", PIPE_BUF);
|
||||
fprintf(outfile, "PIPE_BUF = %-24d\n", PIPE_BUF);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Name spaces */
|
||||
{
|
||||
|
|
6
sycls.c
6
sycls.c
|
@ -1146,6 +1146,7 @@ int Listen(int s, int backlog) {
|
|||
#if _WITH_SOCKET
|
||||
/* don't forget to handle EINTR when using Accept() ! */
|
||||
int Accept(int s, struct sockaddr *addr, socklen_t *addrlen) {
|
||||
char infobuff[256];
|
||||
int result, _errno;
|
||||
fd_set accept_s;
|
||||
if (!diag_in_handler) diag_flush();
|
||||
|
@ -1155,15 +1156,14 @@ int Accept(int s, struct sockaddr *addr, socklen_t *addrlen) {
|
|||
return -1;
|
||||
}
|
||||
#if WITH_SYCLS
|
||||
Debug3("accept(%d, %p, %p)", s, addr, addrlen);
|
||||
sockaddr_info(addr, *addrlen, infobuff, sizeof(infobuff));
|
||||
Debug3("accept(%d, %p, %p)", s, infobuff, addrlen);
|
||||
#endif /* WITH_SYCLS */
|
||||
result = accept(s, addr, addrlen);
|
||||
_errno = errno;
|
||||
if (!diag_in_handler) diag_flush();
|
||||
#if WITH_SYCLS
|
||||
if (result >= 0) {
|
||||
char infobuff[256];
|
||||
sockaddr_info(addr, *addrlen, infobuff, sizeof(infobuff));
|
||||
Info5("accept(%d, {%d, %s}, "F_socklen") -> %d", s,
|
||||
addr->sa_family,
|
||||
sockaddr_info(addr, *addrlen, infobuff, sizeof(infobuff)),
|
||||
|
|
220
test.sh
220
test.sh
|
@ -1462,6 +1462,11 @@ waitunixport () {
|
|||
waitfile "$1" "$2" "$3"
|
||||
}
|
||||
|
||||
# Not implemented
|
||||
waitabstractport () {
|
||||
relsleep 5
|
||||
}
|
||||
|
||||
# wait until a filesystem entry exists
|
||||
waitfile () {
|
||||
local crit=-e
|
||||
|
@ -5610,7 +5615,7 @@ N=$((N+1))
|
|||
# Test if Filan can determine UNIX domain socket in file system
|
||||
NAME=FILANSOCKET
|
||||
case "$TESTS" in
|
||||
*%$N%*|*%filan%*|*%listen%*|*%$NAME%*)
|
||||
*%$N%*|*%filan%*|*%unix%*|*%listen%*|*%$NAME%*)
|
||||
TEST="$NAME: capability to analyze named unix socket"
|
||||
# Run Filan on a listening UNIX domain socket.
|
||||
# When its output gives "socket" as type (2nd column), the test succeeded
|
||||
|
@ -5701,7 +5706,7 @@ fi
|
|||
NAME=PTMXWAITSLAVE
|
||||
PTYTYPE=ptmx
|
||||
case "$TESTS" in
|
||||
*%$N%*|*%functions%*|*%pty%*|*%$NAME%*)
|
||||
*%$N%*|*%functions%*|*%pty%*|*%unix%*|*%listen%*|*%$NAME%*)
|
||||
TEST="$NAME: test if master pty ($PTYTYPE) waits for slave connection"
|
||||
if ! eval $NUMCOND; then :; else
|
||||
if ! feat=$(testfeats pty); then
|
||||
|
@ -5722,7 +5727,7 @@ N=$((N+1))
|
|||
NAME=OPENPTYWAITSLAVE
|
||||
PTYTYPE=openpty
|
||||
case "$TESTS" in
|
||||
*%$N%*|*%functions%*|*%pty%*|*%$NAME%*)
|
||||
*%$N%*|*%functions%*|*%pty%*|*%unix%*|*%listen%*|*%$NAME%*)
|
||||
TEST="$NAME: test if master pty ($PTYTYPE) waits for slave connection"
|
||||
if ! eval $NUMCOND; then :;
|
||||
elif ! feat=$(testfeats pty); then
|
||||
|
@ -7803,7 +7808,7 @@ N=$((N+1))
|
|||
|
||||
NAME=EXECENDCLOSE
|
||||
case "$TESTS" in
|
||||
*%$N%*|*%functions%*|*%exec%*|*%listen%*|*%fork%*|*%$NAME%*)
|
||||
*%$N%*|*%functions%*|*%exec%*|*%listen%*|*%unix%*|*%fork%*|*%$NAME%*)
|
||||
TEST="$NAME: end-close keeps EXEC child running"
|
||||
if ! eval $NUMCOND; then :; else
|
||||
tf="$td/test$N.stdout"
|
||||
|
@ -7867,7 +7872,7 @@ printf "test $F_n $TEST... " $N
|
|||
# output for the PTY name
|
||||
{ $CMD 2>"${te}"; echo $? >"$td/test$N.rc0"; } &
|
||||
waitfile "${te}"
|
||||
psleep 0.1
|
||||
psleep 0.5 # 0.1 is too few for FreeBSD-10
|
||||
PTY=$(grep "N PTY is " $te |sed 's/.*N PTY is //')
|
||||
[ -e "$PTY" ] && cat $PTY >/dev/null 2>/dev/null
|
||||
rc=$(cat "$td/test$N.rc0")
|
||||
|
@ -9015,7 +9020,7 @@ N=$((N+1))
|
|||
# process under some circumstances.
|
||||
NAME=EXECPTYKILL
|
||||
case "$TESTS" in
|
||||
*%$N%*|*%functions%*|*%bugs%*|*%exec%*|*%pty%*|*%listen%*|*%fork%*|*%$NAME%*)
|
||||
*%$N%*|*%functions%*|*%bugs%*|*%exec%*|*%pty%*|*%listen%*|*%unix%*|*%fork%*|*%$NAME%*)
|
||||
TEST="$NAME: exec:...,pty explicitely kills sub process"
|
||||
# we want to check if the exec'd sub process is killed in time
|
||||
# for this we have a shell script that generates a file after two seconds;
|
||||
|
@ -14920,7 +14925,7 @@ for addr in exec system; do
|
|||
ADDR=$(echo $addr |tr a-z A-Z)
|
||||
NAME=${ADDR}SOCKETPAIRPACKETS
|
||||
case "$TESTS" in
|
||||
*%$N%*|*%functions%*|*%exec%*|*%socketpair%*|*%packets%*|*%$NAME%*)
|
||||
*%$N%*|*%functions%*|*%exec%*|*%socketpair%*|*%unix%*|*%dgram%*|*%packets%*|*%$NAME%*)
|
||||
TEST="$NAME: simple echo via $addr of cat with socketpair, keeping packet boundaries"
|
||||
# Start a Socat process with a UNIX datagram socket on the left side and with
|
||||
# a sub process connected via datagram socketpair that keeps packet boundaries
|
||||
|
@ -16478,7 +16483,7 @@ N=$((N+1))
|
|||
# Test the netns (net namespace) feature with EXEC and reset
|
||||
NAME=NETNS_EXEC
|
||||
case "$TESTS" in
|
||||
*%$N%*|*%functions%*|*%root%*|*%namespace%*|*%netns%*|*%socket%*|*%$NAME%*)
|
||||
*%$N%*|*%functions%*|*%root%*|*%namespace%*|*%netns%*|*%socket%*|*%abstract%*|*%dgram%*|*%$NAME%*)
|
||||
ns=socat-$$-test$N
|
||||
TEST="$NAME: option netns with EXEC (net namespace $ns)"
|
||||
# Start a simple server with option netns on localhost of a net namespace that
|
||||
|
@ -17490,20 +17495,21 @@ else
|
|||
tdiff="$td/test$N.diff"
|
||||
tdebug="$td/test$N.debug"
|
||||
opwd=$(pwd)
|
||||
CMD0="$TRACE $absSOCAT $opts -U SHELL:\"cat\ >$tc\",chdir=$td SYSTEM:pwd"
|
||||
CMD0="$TRACE $absSOCAT $opts SHELL:\"cat\ >$tc\",chdir=$td SYSTEM:pwd"
|
||||
printf "test $F_n $TEST... " $N
|
||||
mkdir "$td/$tdd"
|
||||
pushd "$td/$tdd" >/dev/null
|
||||
eval "$CMD0" >/dev/null 2>"${te}0"
|
||||
rc0=$?
|
||||
popd >/dev/null
|
||||
waitfile "$td/$tc"
|
||||
tpwd=$(find $td -name $tc -print); tpwd=${tpwd%/*}
|
||||
pwd2=$(cat $tpwd/$tc </dev/null)
|
||||
echo "Original pwd: $opwd" >>$tdebug
|
||||
echo "Temporary pwd: $tpwd" >>$tdebug
|
||||
echo "Addr2 pwd: $pwd2" >>$tdebug
|
||||
if [ "$rc0" -ne 0 ]; then
|
||||
$PRINTF "$FAILED\n"
|
||||
$PRINTF "$FAILED (rc=$rc0)\n"
|
||||
echo "$CMD0 &"
|
||||
cat "${te}0" >&2
|
||||
numFAIL=$((numFAIL+1))
|
||||
|
@ -17696,6 +17702,200 @@ esac
|
|||
N=$((N+1))
|
||||
|
||||
|
||||
while read _UNIX _SRV _CLI; do
|
||||
if [ -z "$_UNIX" ] || [[ "$_UNIX" == \#* ]]; then continue; fi
|
||||
SRV=${_UNIX}-$_SRV
|
||||
CLI=${_UNIX}-$_CLI
|
||||
CLI_=$(echo $CLI |tr x- x_)
|
||||
PROTO=${_UNIX}
|
||||
proto=$(tolower $PROTO)
|
||||
|
||||
# Test the unix-bind-tempname option
|
||||
NAME=${_UNIX}_${_SRV}_${_CLI}_BIND_TEMPNAME
|
||||
case "$TESTS" in
|
||||
*%$N%*|*%functions%*|*%$proto%*|*%socket%*|*%tempname%*|*%listen%*|*%fork%*|*%$NAME%*)
|
||||
TEST="$NAME: Option unix-bind-tempname"
|
||||
# Start a UNIX domain service with forking
|
||||
# Start a TCP service with forking that relays to the UNIX domain service
|
||||
# Open two concurrent client sessions to the TCP service.
|
||||
# When both sessions work (in particular, when the UNIX domain service does not
|
||||
# log "Transport endpoint is not connected" and the TCP service does not fail
|
||||
# with "Address already in use"), the test succeeded.
|
||||
if ! eval $NUMCOND; then :;
|
||||
elif [[ $CLI_ =~ ABSTRACT-* ]] && ! feat=$(testfeats abstract-unixsocket); then
|
||||
$PRINTF "test $F_n $TEST... ${YELLOW}$feat not available${NORMAL}\n" $N
|
||||
numCANT=$((numCANT+1))
|
||||
listCANT="$listCANT $N"
|
||||
else
|
||||
ts="$td/test$N.sock"
|
||||
tf="$td/test$N.stdout"
|
||||
te="$td/test$N.stderr"
|
||||
tdiff="$td/test$N.diff"
|
||||
da="test$N $(date) $RANDOM"
|
||||
CMD0="$TRACE $SOCAT $opts -lp server $SRV:${ts}0,fork PIPE"
|
||||
# Using this command would show the principal problem: UNIX (and ABSTRACT)
|
||||
# datagram clients do not internally bind to a defined address and thus cannot
|
||||
# receive replies. Applies to all(?) Linux, (some)FreeBSD, (some)Solaris, others
|
||||
# not tried
|
||||
#CMD1="$TRACE $SOCAT $opts -lp bind-tempname TCP4-LISTEN:$PORT,reuseaddr,fork $CLI:${ts}0"
|
||||
# Attempt to bind the datagram client to some address works, but only for a
|
||||
# single client; when multiple clients are forked they conflict
|
||||
# The following command is the solution: option unix-bind-tempname generates
|
||||
# random names (like tempnam(2)) for binding the datagram client socket;
|
||||
# creating the XXXXXX file makes sure that the (non abstract) clients cannot
|
||||
# erronously bind there (part of the test)
|
||||
CMD1="$TRACE $SOCAT $opts -lp bind-tempname TCP4-LISTEN:$PORT,reuseaddr,fork $CLI:${ts}0,bind=${ts}1"
|
||||
touch ${ts}1.XXXXXX; CMD1="$TRACE $SOCAT $opts -lp tempname TCP4-LISTEN:$PORT,reuseaddr,fork $CLI:${ts}0,bind-tempname=${ts}1.XXXXXX"
|
||||
CMD2="$TRACE $SOCAT $opts -lp client - TCP4-CONNECT:$LOCALHOST:$PORT"
|
||||
printf "test $F_n $TEST... " $N
|
||||
$CMD0 2>"${te}0" &
|
||||
pid0=$!
|
||||
wait${proto}port ${ts}0 1
|
||||
$CMD1 2>"${te}1" &
|
||||
pid1=$!
|
||||
waittcp4port $PORT 1
|
||||
{ echo "$da a"; sleep 2; } |$CMD2 >"${tf}2a" 2>"${te}2a" &
|
||||
pid2a=$!
|
||||
sleep 1
|
||||
echo "$da b" |$CMD2 >"${tf}2b" 2>"${te}2b"
|
||||
rc2b=$?
|
||||
sleep 1
|
||||
kill $pid0 $pid1 $pid2a 2>/dev/null; wait
|
||||
if [ $rc2b -ne 0 ]; then
|
||||
$PRINTF "$FAILED\n"
|
||||
echo "$CMD0 &"
|
||||
cat "${te}0" >&2
|
||||
echo "$CMD1 &"
|
||||
cat "${te}1" >&2
|
||||
echo "$CMD2 &"
|
||||
cat "${te}2a" >&2
|
||||
echo "$CMD2"
|
||||
cat "${te}2b" >&2
|
||||
numFAIL=$((numFAIL+1))
|
||||
listFAIL="$listFAIL $N"
|
||||
elif ! echo "$da a" |diff - ${tf}2a >${tdiff}2a; then
|
||||
$PRINTF "$FAILED (phase a)\n"
|
||||
echo "$CMD0 &"
|
||||
cat "${te}0" >&2
|
||||
echo "$CMD1 &"
|
||||
cat "${te}1" >&2
|
||||
echo "$CMD2"
|
||||
cat "${te}2a" >&2
|
||||
echo "diff a:" >&2
|
||||
cat ${tdiff}2a >&2
|
||||
numFAIL=$((numFAIL+1))
|
||||
listFAIL="$listFAIL $N"
|
||||
elif ! echo "$da b" |diff - ${tf}2b >${tdiff}2b; then
|
||||
$PRINTF "$FAILED\n"
|
||||
echo "$CMD0 &"
|
||||
cat "${te}0" >&2
|
||||
echo "$CMD1 &"
|
||||
cat "${te}1" >&2
|
||||
echo "$CMD2 &"
|
||||
cat "${te}2a" >&2
|
||||
echo "$CMD2"
|
||||
cat "${te}2b" >&2
|
||||
echo "diff b:" >&2
|
||||
cat ${tdiff}2b >&2
|
||||
numFAIL=$((numFAIL+1))
|
||||
listFAIL="$listFAIL $N"
|
||||
else
|
||||
$PRINTF "$OK\n"
|
||||
if [ "$VERBOSE" ]; then echo "$CMD0 &"; fi
|
||||
if [ "$DEBUG" ]; then cat "${te}0" >&2; fi
|
||||
if [ "$VERBOSE" ]; then echo "$CMD1"; fi
|
||||
if [ "$DEBUG" ]; then cat "${te}1" >&2; fi
|
||||
if [ "$VERBOSE" ]; then echo "$CMD2"; fi
|
||||
if [ "$DEBUG" ]; then cat "${te}2a" >&2; fi
|
||||
if [ "$VERBOSE" ]; then echo "$CMD2"; fi
|
||||
if [ "$DEBUG" ]; then cat "${te}2b" >&2; fi
|
||||
numOK=$((numOK+1))
|
||||
fi
|
||||
fi # NUMCOND
|
||||
;;
|
||||
esac
|
||||
PORT=$((PORT+1))
|
||||
N=$((N+1))
|
||||
|
||||
done <<<"
|
||||
UNIX LISTEN CONNECT
|
||||
UNIX LISTEN CLIENT
|
||||
UNIX RECVFROM CLIENT
|
||||
UNIX RECVFROM SENDTO
|
||||
ABSTRACT LISTEN CONNECT
|
||||
ABSTRACT LISTEN CLIENT
|
||||
ABSTRACT RECVFROM CLIENT
|
||||
ABSTRACT RECVFROM SENDTO
|
||||
"
|
||||
|
||||
# Test if OS/libc is not prone to symlink attacks on UNIX bind()
|
||||
NAME=TEMPNAME_SEC
|
||||
case "$TESTS" in
|
||||
*%$N%*|*%functions%*|*%bugs%*|*%socket%*|*%unix%*|*%dgram%*|*%security%*|*%$NAME%*)
|
||||
TEST="$NAME: test if a symlink attack works against bind()"
|
||||
# Create a symlink .sock2 pointing to non-existing .sock3
|
||||
# Start Socat with UNIX-SENDTO...,bind=.sock2
|
||||
# When .sock3 exists the test failed
|
||||
if ! eval $NUMCOND; then :; else
|
||||
tf="$td/test$N.stdout"
|
||||
te="$td/test$N.stderr"
|
||||
ts1="$td/test$N.sock1"
|
||||
ts2="$td/test$N.sock2"
|
||||
ts3="$td/test$N.sock3"
|
||||
tdiff="$td/test$N.diff"
|
||||
da="test$N $(date) $RANDOM"
|
||||
CMD0a="rm -f $ts3"
|
||||
CMD0b="ln -s $ts3 $ts2"
|
||||
CMD1="$TRACE $SOCAT $opts UNIX-SENDTO:$ts1,bind=$ts2 PIPE"
|
||||
rc1=$?
|
||||
printf "test $F_n $TEST... " $N
|
||||
$CMD0a
|
||||
$CMD0b
|
||||
#echo; ls -l $ts2 $ts3
|
||||
$CMD1 2>"${te}1" &
|
||||
pid1=$!
|
||||
waitunixport $ts1 1 1 2>/dev/null
|
||||
#res="$(ls -l $ts3 2>/dev/null)"
|
||||
kill $pid1 2>/dev/null
|
||||
if [ -e $ts3 ]; then
|
||||
$PRINTF "$FAILED\n"
|
||||
echo "symlink target has been created" >&2
|
||||
echo "$CMD0a" >&2
|
||||
cat "${te}0a" >&2
|
||||
echo "$CMD0b" >&2
|
||||
cat "${te}0b" >&2
|
||||
echo "$CMD1" >&2
|
||||
cat "${te}1" >&2
|
||||
numFAIL=$((numFAIL+1))
|
||||
listFAIL="$listFAIL $N"
|
||||
elif ! grep -q " E " ${te}1; then
|
||||
$PRINTF "$FAILED\n"
|
||||
echo "Socat did not fail"
|
||||
echo "$CMD0a" >&2
|
||||
cat "${te}0a" >&2
|
||||
echo "$CMD0b" >&2
|
||||
cat "${te}0b" >&2
|
||||
echo "$CMD1" >&2
|
||||
cat "${te}1" >&2
|
||||
numFAIL=$((numFAIL+1))
|
||||
listFAIL="$listFAIL $N"
|
||||
else
|
||||
$PRINTF "$OK\n"
|
||||
if [ "$VERBOSE" ]; then echo "$CMD0a"; fi
|
||||
if [ "$DEBUG" ]; then cat "${te}0a" >&2; fi
|
||||
if [ "$VERBOSE" ]; then echo "$CMD0b"; fi
|
||||
if [ "$DEBUG" ]; then cat "${te}0b" >&2; fi
|
||||
if [ "$VERBOSE" ]; then echo "$CMD1"; fi
|
||||
if [ "$DEBUG" ]; then cat "${te}1" >&2; fi
|
||||
numOK=$((numOK+1))
|
||||
fi
|
||||
fi # NUMCOND
|
||||
;;
|
||||
esac
|
||||
PORT=$((PORT+1))
|
||||
N=$((N+1))
|
||||
|
||||
|
||||
# end of common tests
|
||||
|
||||
##################################################################################
|
||||
|
|
|
@ -62,7 +62,8 @@ static int xioopen_gopen(
|
|||
Info1("\"%s\" is a socket, connecting to it", filename);
|
||||
|
||||
result =
|
||||
_xioopen_unix_client(sfd, xioflags, addrdesc->groups, 0, opts, filename);
|
||||
_xioopen_unix_client(sfd, xioflags, addrdesc->groups, 0, opts,
|
||||
filename, addrdesc);
|
||||
if (result < 0) {
|
||||
return result;
|
||||
}
|
||||
|
|
4
xio-ip.c
4
xio-ip.c
|
@ -244,7 +244,7 @@ int xiogetaddrinfo(const char *node, const char *service,
|
|||
}
|
||||
if (error_num == EAI_SERVICE && protocol != 0) {
|
||||
if (hints.ai_protocol == 0) {
|
||||
Error7("getaddrinfo\"%s\", \"%s\", {0x%02x,%d,%d,%d}, {}): %s",
|
||||
Error7("getaddrinfo(\"%s\", \"%s\", {0x%02x,%d,%d,%d}, {}): %s",
|
||||
node?node:"NULL", service?service:"NULL",
|
||||
hints.ai_flags, hints.ai_family,
|
||||
hints.ai_socktype, hints.ai_protocol,
|
||||
|
@ -438,7 +438,7 @@ int xioresolve(const char *node, const char *service,
|
|||
}
|
||||
|
||||
aip = res;
|
||||
if (ai_flags[0] & AI_PASSIVE && family == PF_UNSPEC) {
|
||||
if (ai_flags != NULL && ai_flags[0] & AI_PASSIVE && family == PF_UNSPEC) {
|
||||
/* We select the first IPv6 address, if available,
|
||||
because this might accept IPv4 connections too */
|
||||
while (aip != NULL) {
|
||||
|
|
|
@ -212,7 +212,6 @@ int _xioopen_accept_fd(
|
|||
|
||||
/* Under some circumstances (e.g., TCP listen on port 0) bind() fills empty
|
||||
fields that we want to know. */
|
||||
salen = sizeof(sa);
|
||||
if (Getsockname(sfd->fd, us, &uslen) < 0) {
|
||||
Warn4("getsockname(%d, %p, {%d}): %s",
|
||||
sfd->fd, &us, uslen, strerror(errno));
|
||||
|
@ -255,7 +254,6 @@ int _xioopen_accept_fd(
|
|||
|
||||
pa = &_peername;
|
||||
la = &_sockname;
|
||||
salen = sizeof(struct sockaddr);
|
||||
do {
|
||||
/*? int level = E_ERROR;*/
|
||||
Notice1("listening on %s", sockaddr_info(us, uslen, lisname, sizeof(lisname)));
|
||||
|
@ -304,6 +302,7 @@ int _xioopen_accept_fd(
|
|||
Exit(0);
|
||||
}
|
||||
}
|
||||
salen = sizeof(sa);
|
||||
ps = Accept(sfd->fd, (struct sockaddr *)&sa, &salen);
|
||||
if (ps >= 0) {
|
||||
/*0 Info4("accept(%d, %p, {"F_Zu"}) -> %d", sfd->fd, &sa, salen, ps);*/
|
||||
|
|
130
xio-socket.c
130
xio-socket.c
|
@ -775,6 +775,10 @@ int xiogetpacketinfo(struct single *sfd, int fd)
|
|||
OFUNC_OFFSET,
|
||||
OPT_SO_TYPE, OPT_SO_PROTOTYPE, OPT_USER, OPT_GROUP, OPT_CLOEXEC
|
||||
Does not fork, does not retry.
|
||||
Alternate (alt) bind semantics are:
|
||||
with IP sockets: lowport (selects randomly a free port from 640 to 1023)
|
||||
with UNIX and abstract sockets: uses tmpname() to find a free file system
|
||||
entry.
|
||||
returns 0 on success.
|
||||
*/
|
||||
int _xioopen_connect(struct single *sfd, union sockaddr_union *us, size_t uslen,
|
||||
|
@ -1113,7 +1117,7 @@ int _xioopen_dgram_sendto(/* them is already in xfd->peersa */
|
|||
|
||||
/* waits for incoming packet, checks its source address and port. Depending
|
||||
on fork option, it may fork a subprocess.
|
||||
Returns STAT_OK if a the packet was accepted; with fork option, this is already in
|
||||
Returns STAT_OK if a packet was accepted; with fork option, this is already in
|
||||
a new subprocess!
|
||||
Other return values indicate a problem; this can happen in the master
|
||||
process or in a subprocess.
|
||||
|
@ -1393,10 +1397,10 @@ int _xioopen_dgram_recv(struct single *sfd, int xioflags,
|
|||
#endif /* && (WITH_TCP || WITH_UDP) && WITH_LIBWRAP */
|
||||
|
||||
if (xioparms.logopt == 'm') {
|
||||
Info("starting recvfrom loop, switching to syslog");
|
||||
Info("starting recv loop, switching to syslog");
|
||||
diag_set('y', xioparms.syslogfac); xioparms.logopt = 'y';
|
||||
} else {
|
||||
Info("starting recvfrom loop");
|
||||
Info("starting recv loop");
|
||||
}
|
||||
|
||||
return STAT_OK;
|
||||
|
@ -2053,6 +2057,15 @@ xiosocketpair(struct opt *opts, int pf, int socktype, int proto, int sv[2]) {
|
|||
return result;
|
||||
}
|
||||
|
||||
/* Binds a socket to a socket address. Handles IP (internet protocol), UNIX
|
||||
domain, Linux abstract UNIX domain.
|
||||
The bind address us may be NULL in which case no bind() happens, except with
|
||||
alt (on option unix-bind-tempname (bind-tempname)).
|
||||
Alternate (atl) bind semantics are:
|
||||
with IP sockets: lowport (selects randomly a free port from 640 to 1023)
|
||||
with UNIX and abstract sockets: uses a method similar to tmpname() to
|
||||
find a free file system entry.
|
||||
*/
|
||||
int xiobind(
|
||||
struct single *sfd,
|
||||
union sockaddr_union *us,
|
||||
|
@ -2065,19 +2078,89 @@ int xiobind(
|
|||
char infobuff[256];
|
||||
int result;
|
||||
|
||||
if (false /* for canonical reasons */) {
|
||||
;
|
||||
#if WITH_UNIX
|
||||
if (pf == PF_UNIX && us != NULL) {
|
||||
applyopts_named(us->un.sun_path, opts, PH_PREOPEN);
|
||||
}
|
||||
} else if (pf == PF_UNIX) {
|
||||
if (alt && us != NULL) {
|
||||
bool abstract = false;
|
||||
char *usrname = NULL, *sockname;
|
||||
|
||||
#if WITH_ABSTRACT_UNIXSOCKET
|
||||
abstract = (us->un.sun_path[0] == '\0');
|
||||
#endif
|
||||
applyopts(sfd, sfd->fd, opts, PH_PREBIND);
|
||||
applyopts(sfd, sfd->fd, opts, PH_BIND);
|
||||
|
||||
if (uslen == ((char *)&us->un.sun_path-(char *)us)) {
|
||||
usrname = NULL;
|
||||
} else {
|
||||
#if WITH_ABSTRACT_UNIXSOCKET
|
||||
if (abstract)
|
||||
usrname = strndup(us->un.sun_path+1, sizeof(us->un.sun_path)-1);
|
||||
else
|
||||
#endif
|
||||
usrname = strndup(us->un.sun_path, sizeof(us->un.sun_path));
|
||||
if (usrname == NULL) {
|
||||
int _errno = errno;
|
||||
Error2("strndup(\"%s\", "F_Zu"): out of memory",
|
||||
us->un.sun_path, sizeof(us->un.sun_path));
|
||||
errno = _errno;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
do { /* loop over tempnam bind() attempts */
|
||||
sockname = xio_tempnam(usrname, abstract);
|
||||
if (sockname == NULL) {
|
||||
Error2("tempnam(\"%s\"): %s", usrname, strerror(errno));
|
||||
free(usrname);
|
||||
return -1;
|
||||
}
|
||||
strncpy(us->un.sun_path+(abstract?1:0), sockname, sizeof(us->un.sun_path));
|
||||
uslen = sizeof(&((struct sockaddr_un *)0)->sun_path) +
|
||||
Min(strlen(sockname), sizeof(us->un.sun_path)); /*?*/
|
||||
free(sockname);
|
||||
|
||||
if (Bind(sfd->fd, (struct sockaddr *)us, uslen) < 0) {
|
||||
Msg4(errno==EADDRINUSE?E_INFO:level, "bind(%d, {%s}, "F_Zd"): %s",
|
||||
sfd->fd, sockaddr_info((struct sockaddr *)us, uslen,
|
||||
infobuff, sizeof(infobuff)),
|
||||
uslen, strerror(errno));
|
||||
if (errno != EADDRINUSE) {
|
||||
free(usrname);
|
||||
Close(sfd->fd);
|
||||
return STAT_RETRYLATER;
|
||||
}
|
||||
} else {
|
||||
break; /* could bind to path, good, continue past loop */
|
||||
}
|
||||
} while (true);
|
||||
free(usrname);
|
||||
applyopts_named(us->un.sun_path, opts, PH_PREOPEN);
|
||||
} else
|
||||
|
||||
if (us != NULL) {
|
||||
if (Bind(sfd->fd, &us->soa, uslen) < 0) {
|
||||
Msg4(level, "bind(%d, {%s}, "F_Zd"): %s",
|
||||
sfd->fd, sockaddr_info(&us->soa, uslen, infobuff, sizeof(infobuff)),
|
||||
uslen, strerror(errno));
|
||||
Close(sfd->fd);
|
||||
return STAT_RETRYLATER;
|
||||
}
|
||||
applyopts_named(us->un.sun_path, opts, PH_PREOPEN);
|
||||
}
|
||||
|
||||
applyopts(sfd, sfd->fd, opts, PH_PREBIND);
|
||||
applyopts(sfd, sfd->fd, opts, PH_BIND);
|
||||
#endif /* WITH_UNIX */
|
||||
|
||||
#if WITH_TCP || WITH_UDP
|
||||
if (alt) {
|
||||
} else if (alt) {
|
||||
union sockaddr_union sin, *sinp;
|
||||
unsigned short *port, i, N;
|
||||
div_t dv;
|
||||
|
||||
applyopts(sfd, sfd->fd, opts, PH_PREBIND);
|
||||
applyopts(sfd, sfd->fd, opts, PH_BIND);
|
||||
/* prepare sockaddr for bind probing */
|
||||
if (us) {
|
||||
sinp = us;
|
||||
|
@ -2147,28 +2230,21 @@ int xiobind(
|
|||
return STAT_RETRYLATER;
|
||||
}
|
||||
} while (i != N);
|
||||
} else
|
||||
#endif /* WITH_TCP || WITH_UDP */
|
||||
|
||||
if (us) {
|
||||
#if WITH_UNIX
|
||||
if (pf == PF_UNIX && us != NULL) {
|
||||
applyopts_named(us->un.sun_path, opts, PH_PREOPEN);
|
||||
}
|
||||
#endif
|
||||
if (Bind(sfd->fd, &us->soa, uslen) < 0) {
|
||||
Msg4(level, "bind(%d, {%s}, "F_Zd"): %s",
|
||||
sfd->fd, sockaddr_info(&us->soa, uslen, infobuff, sizeof(infobuff)),
|
||||
uslen, strerror(errno));
|
||||
Close(sfd->fd);
|
||||
return STAT_RETRYLATER;
|
||||
} else {
|
||||
applyopts(sfd, sfd->fd, opts, PH_PREBIND);
|
||||
if (us) {
|
||||
applyopts(sfd, sfd->fd, opts, PH_BIND);
|
||||
if (Bind(sfd->fd, &us->soa, uslen) < 0) {
|
||||
Msg4(level, "bind(%d, {%s}, "F_Zd"): %s",
|
||||
sfd->fd, sockaddr_info(&us->soa, uslen, infobuff, sizeof(infobuff)),
|
||||
uslen, strerror(errno));
|
||||
Close(sfd->fd);
|
||||
return STAT_RETRYLATER;
|
||||
}
|
||||
}
|
||||
}
|
||||
#if WITH_UNIX
|
||||
if (pf == PF_UNIX && us != NULL) {
|
||||
applyopts_named(us->un.sun_path, opts, PH_PASTOPEN);
|
||||
}
|
||||
#endif
|
||||
|
||||
applyopts(sfd, -1, opts, PH_PASTBIND);
|
||||
return 0;
|
||||
|
|
197
xio-unix.c
197
xio-unix.c
|
@ -53,6 +53,7 @@ const struct addrdesc xioaddr_abstract_recv = { "ABSTRACT-RECV", 1+XIO_RD
|
|||
const struct addrdesc xioaddr_abstract_client = { "ABSTRACT-CLIENT", 1+XIO_RDWR, xioopen_unix_client, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_UNIX|GROUP_RETRY, 1, 0, 0 HELP(":<filename>") };
|
||||
#endif /* WITH_ABSTRACT_UNIXSOCKET */
|
||||
|
||||
const struct optdesc xioopt_unix_bind_tempname = { "unix-bind-tempname", "bind-tempname", OPT_UNIX_BIND_TEMPNAME, GROUP_SOCK_UNIX, PH_PREOPEN, TYPE_STRING_NULL, OFUNC_SPEC };
|
||||
const struct optdesc xioopt_unix_tightsocklen = { "unix-tightsocklen", "tightsocklen", OPT_UNIX_TIGHTSOCKLEN, GROUP_SOCK_UNIX, PH_PREBIND, TYPE_BOOL, OFUNC_OFFSET, XIO_OFFSETOF(para.socket.un.tight), XIO_SIZEOF(para.socket.un.tight) };
|
||||
|
||||
|
||||
|
@ -90,7 +91,7 @@ xiosetunix(int pf,
|
|||
len = sizeof(struct sockaddr_un);
|
||||
}
|
||||
return len;
|
||||
}
|
||||
} else
|
||||
#endif /* WITH_ABSTRACT_UNIXSOCKET */
|
||||
|
||||
if ((pathlen = strlen(path)) > sizeof(saun->sun_path)) {
|
||||
|
@ -139,7 +140,7 @@ static int xioopen_unix_listen(
|
|||
}
|
||||
name = argv[1];
|
||||
|
||||
sfd->para.socket.un.tight = true;
|
||||
sfd->para.socket.un.tight = UNIX_TIGHTSOCKLEN;
|
||||
retropt_socket_pf(opts, &pf);
|
||||
sfd->howtoend = END_SHUTDOWN;
|
||||
|
||||
|
@ -221,11 +222,13 @@ static int xioopen_unix_connect(
|
|||
struct sockaddr_un them, us;
|
||||
socklen_t themlen, uslen = sizeof(us);
|
||||
bool needbind = false;
|
||||
bool needtemp = false;
|
||||
bool opt_unlink_close = (addrdesc->arg1/*abstract*/ != 1);
|
||||
bool dofork = false;
|
||||
struct opt *opts0;
|
||||
char infobuff[256];
|
||||
int level;
|
||||
char *opt_bind_tempname = NULL;
|
||||
int result;
|
||||
|
||||
if (argc != 2) {
|
||||
|
@ -234,7 +237,7 @@ static int xioopen_unix_connect(
|
|||
}
|
||||
name = argv[1];
|
||||
|
||||
sfd->para.socket.un.tight = true;
|
||||
sfd->para.socket.un.tight = UNIX_TIGHTSOCKLEN;
|
||||
retropt_socket_pf(opts, &pf);
|
||||
sfd->howtoend = END_SHUTDOWN;
|
||||
if (applyopts_single(sfd, opts, PH_INIT) < 0) return STAT_NORETRY;
|
||||
|
@ -249,6 +252,7 @@ static int xioopen_unix_connect(
|
|||
/* Only for non abstract because abstract do not work in file system */
|
||||
retropt_bool(opts, OPT_UNLINK_CLOSE, &opt_unlink_close);
|
||||
}
|
||||
|
||||
if (retropt_bind(opts, pf, socktype, protocol, (struct sockaddr *)&us, &uslen,
|
||||
(addrdesc->arg1/*abstract*/<<1)|sfd->para.socket.un.tight,
|
||||
sfd->para.socket.ip.ai_flags)
|
||||
|
@ -256,18 +260,25 @@ static int xioopen_unix_connect(
|
|||
needbind = true;
|
||||
}
|
||||
|
||||
if (retropt_string(opts, OPT_UNIX_BIND_TEMPNAME, &opt_bind_tempname) == 0) {
|
||||
if (needbind) {
|
||||
Error("do not use both options bind and unix-bind-tempnam");
|
||||
return -1;
|
||||
}
|
||||
needbind = true;
|
||||
needtemp = true;
|
||||
xiosetunix(pf, &us, opt_bind_tempname?opt_bind_tempname:"",
|
||||
addrdesc->arg1/*abstract*/, sfd->para.socket.un.tight);
|
||||
if (opt_bind_tempname == NULL && !addrdesc->arg1/*abstract*/) {
|
||||
us.sun_path[0] = 0x01; /* mark as non abstract */
|
||||
}
|
||||
}
|
||||
|
||||
if (!needbind &&
|
||||
(namedopt = searchopt(opts, GROUP_NAMED, 0, 0, 0))) {
|
||||
Error1("Option \"%s\" only with bind option", namedopt->desc->defname);
|
||||
}
|
||||
|
||||
if (opt_unlink_close && needbind) {
|
||||
if ((sfd->unlink_close = strdup(us.sun_path)) == NULL) {
|
||||
Error1("strdup(\"%s\"): out of memory", name);
|
||||
}
|
||||
sfd->opt_unlink_close = true;
|
||||
}
|
||||
|
||||
retropt_bool(opts, OPT_FORK, &dofork);
|
||||
|
||||
opts0 = copyopts(opts, GROUP_ALL);
|
||||
|
@ -288,7 +299,7 @@ static int xioopen_unix_connect(
|
|||
_xioopen_connect(sfd,
|
||||
needbind?(union sockaddr_union *)&us:NULL, uslen,
|
||||
(struct sockaddr *)&them, themlen,
|
||||
opts, pf, socktype, protocol, false, level);
|
||||
opts, pf, socktype, protocol, needtemp, level);
|
||||
if (result != 0) {
|
||||
char infobuff[256];
|
||||
/* we caller must handle this */
|
||||
|
@ -382,10 +393,12 @@ static int xioopen_unix_sendto(
|
|||
int pf = PF_UNIX;
|
||||
int socktype = SOCK_DGRAM;
|
||||
int protocol = 0;
|
||||
union sockaddr_union us;
|
||||
struct sockaddr_un us;
|
||||
socklen_t uslen = sizeof(us);
|
||||
bool needbind = false;
|
||||
bool needtemp = false;
|
||||
bool opt_unlink_close = (addrdesc->arg1/*abstract*/ != 1);
|
||||
char *opt_bind_tempname = NULL;
|
||||
int result;
|
||||
|
||||
if (argc != 2) {
|
||||
|
@ -394,7 +407,7 @@ static int xioopen_unix_sendto(
|
|||
}
|
||||
name = argv[1];
|
||||
|
||||
sfd->para.socket.un.tight = true;
|
||||
sfd->para.socket.un.tight = UNIX_TIGHTSOCKLEN;
|
||||
retropt_socket_pf(opts, &pf);
|
||||
sfd->howtoend = END_SHUTDOWN;
|
||||
applyopts_offset(sfd, opts);
|
||||
|
@ -408,13 +421,24 @@ static int xioopen_unix_sendto(
|
|||
|
||||
sfd->dtype = XIODATA_RECVFROM;
|
||||
|
||||
if (retropt_bind(opts, pf, socktype, protocol, &us.soa, &uslen,
|
||||
if (retropt_bind(opts, pf, socktype, protocol, (struct sockaddr *)&us, &uslen,
|
||||
(addrdesc->arg1/*abstract*/<<1)| sfd->para.socket.un.tight,
|
||||
sfd->para.socket.ip.ai_flags)
|
||||
== STAT_OK) {
|
||||
== STAT_OK) {
|
||||
needbind = true;
|
||||
}
|
||||
|
||||
if (retropt_string(opts, OPT_UNIX_BIND_TEMPNAME, &opt_bind_tempname) == 0) {
|
||||
if (needbind) {
|
||||
Error("do not use both options bind and bind-tempnam");
|
||||
return STAT_NORETRY;
|
||||
}
|
||||
needbind = true;
|
||||
needtemp = true;
|
||||
xiosetunix(pf, &us, opt_bind_tempname?opt_bind_tempname:"",
|
||||
addrdesc->arg1/*abstract*/, sfd->para.socket.un.tight);
|
||||
}
|
||||
|
||||
if (!needbind &&
|
||||
(namedopt = searchopt(opts, GROUP_NAMED, 0, 0, 0))) {
|
||||
Error1("Option \"%s\" only with bind option", namedopt->desc->defname);
|
||||
|
@ -426,14 +450,14 @@ static int xioopen_unix_sendto(
|
|||
result =
|
||||
_xioopen_dgram_sendto(needbind?(union sockaddr_union *)&us:NULL, uslen,
|
||||
opts, xioflags, sfd, addrdesc->groups,
|
||||
pf, socktype, protocol, 0);
|
||||
pf, socktype, protocol, needtemp);
|
||||
if (result != 0) {
|
||||
return result;
|
||||
}
|
||||
|
||||
if (opt_unlink_close && needbind) {
|
||||
if ((sfd->unlink_close = strndup(us.un.sun_path, sizeof(us.un.sun_path))) == NULL) {
|
||||
Error2("strndup(\"%s\", "F_Zu"): out of memory", name, sizeof(us.un.sun_path));
|
||||
if ((sfd->unlink_close = strndup(us.sun_path, sizeof(us.sun_path))) == NULL) {
|
||||
Error2("strndup(\"%s\", "F_Zu"): out of memory", name, sizeof(us.sun_path));
|
||||
}
|
||||
sfd->opt_unlink_close = true;
|
||||
}
|
||||
|
@ -468,7 +492,7 @@ int xioopen_unix_recvfrom(
|
|||
}
|
||||
name = argv[1];
|
||||
|
||||
sfd->para.socket.un.tight = true;
|
||||
sfd->para.socket.un.tight = UNIX_TIGHTSOCKLEN;
|
||||
retropt_socket_pf(opts, &pf);
|
||||
sfd->howtoend = END_NONE;
|
||||
if (applyopts_single(sfd, opts, PH_INIT) < 0) return STAT_NORETRY;
|
||||
|
@ -554,7 +578,7 @@ static int xioopen_unix_recv(
|
|||
}
|
||||
name = argv[1];
|
||||
|
||||
sfd->para.socket.un.tight = true;
|
||||
sfd->para.socket.un.tight = UNIX_TIGHTSOCKLEN;
|
||||
retropt_socket_pf(opts, &pf);
|
||||
sfd->howtoend = END_SHUTDOWN;
|
||||
if (applyopts_single(sfd, opts, PH_INIT) < 0) return STAT_NORETRY;
|
||||
|
@ -625,7 +649,7 @@ static int xioopen_unix_client(
|
|||
|
||||
return
|
||||
_xioopen_unix_client(&xxfd->stream, xioflags, addrdesc->groups,
|
||||
addrdesc->arg1/*abstract*/, opts, argv[1]);
|
||||
addrdesc->arg1/*abstract*/, opts, argv[1], addrdesc);
|
||||
}
|
||||
|
||||
/* establishes communication with an existing UNIX type socket. supports stream
|
||||
|
@ -639,8 +663,15 @@ static int xioopen_unix_client(
|
|||
OPT_SO_TYPE, OPT_SO_PROTOTYPE, OPT_CLOEXEC, OPT_USER, OPT_GROUP, ?OPT_FORK,
|
||||
*/
|
||||
int
|
||||
_xioopen_unix_client(xiosingle_t *sfd, int xioflags, groups_t groups,
|
||||
int abstract, struct opt *opts, const char *name) {
|
||||
_xioopen_unix_client(
|
||||
xiosingle_t *sfd,
|
||||
int xioflags,
|
||||
groups_t groups,
|
||||
int abstract,
|
||||
struct opt *opts,
|
||||
const char *name,
|
||||
const struct addrdesc *addrdesc)
|
||||
{
|
||||
const struct opt *namedopt;
|
||||
int pf = PF_UNIX;
|
||||
int socktype = 0; /* to be determined by server socket type */
|
||||
|
@ -648,11 +679,13 @@ _xioopen_unix_client(xiosingle_t *sfd, int xioflags, groups_t groups,
|
|||
union sockaddr_union them, us;
|
||||
socklen_t themlen, uslen = sizeof(us);
|
||||
bool needbind = false;
|
||||
bool needtemp = false;
|
||||
bool opt_unlink_close = false;
|
||||
char *opt_bind_tempname = NULL;
|
||||
struct opt *opts0;
|
||||
int result;
|
||||
|
||||
sfd->para.socket.un.tight = true;
|
||||
sfd->para.socket.un.tight = UNIX_TIGHTSOCKLEN;
|
||||
retropt_socket_pf(opts, &pf);
|
||||
sfd->howtoend = END_SHUTDOWN;
|
||||
if (applyopts_single(sfd, opts, PH_INIT) < 0) return STAT_NORETRY;
|
||||
|
@ -667,6 +700,7 @@ _xioopen_unix_client(xiosingle_t *sfd, int xioflags, groups_t groups,
|
|||
/* only for non abstract because abstract do not work in file system */
|
||||
retropt_bool(opts, OPT_UNLINK_CLOSE, &opt_unlink_close);
|
||||
}
|
||||
|
||||
if (retropt_bind(opts, pf, socktype, protocol, &us.soa, &uslen,
|
||||
(abstract<<1)|sfd->para.socket.un.tight,
|
||||
sfd->para.socket.ip.ai_flags)
|
||||
|
@ -674,6 +708,15 @@ _xioopen_unix_client(xiosingle_t *sfd, int xioflags, groups_t groups,
|
|||
needbind = true;
|
||||
}
|
||||
|
||||
if (retropt_string(opts, OPT_UNIX_BIND_TEMPNAME, &opt_bind_tempname) == 0) {
|
||||
if (needbind) {
|
||||
Error("do not use both options bind and unix-bind-tempname");
|
||||
return STAT_NORETRY;
|
||||
}
|
||||
needbind = true;
|
||||
needtemp = true;
|
||||
}
|
||||
|
||||
if (!needbind &&
|
||||
(namedopt = searchopt(opts, GROUP_NAMED, 0, 0, 0))) {
|
||||
Error1("Option \"%s\" only with bind option", namedopt->desc->defname);
|
||||
|
@ -692,40 +735,57 @@ _xioopen_unix_client(xiosingle_t *sfd, int xioflags, groups_t groups,
|
|||
/* just a breakable block, helps to avoid goto */
|
||||
do {
|
||||
/* sfd->dtype = DATA_STREAM; // is default */
|
||||
if (needtemp)
|
||||
xiosetunix(pf, &us.un, opt_bind_tempname?opt_bind_tempname:"",
|
||||
abstract, sfd->para.socket.un.tight);
|
||||
/* this function handles AF_UNIX with EPROTOTYPE specially for us */
|
||||
if ((result =
|
||||
_xioopen_connect(sfd,
|
||||
needbind?&us:NULL, uslen,
|
||||
&them.soa, themlen,
|
||||
opts, pf, socktype?socktype:SOCK_STREAM, protocol,
|
||||
false, E_INFO)) == 0)
|
||||
needtemp, E_INFO)) == 0)
|
||||
break;
|
||||
if (errno != EPROTOTYPE || socktype != 0)
|
||||
if ((errno != EPROTOTYPE
|
||||
#if WITH_ABSTRACT_UNIXSOCKET
|
||||
&& !(abstract && errno == ECONNREFUSED)
|
||||
#endif
|
||||
) || socktype != 0)
|
||||
break;
|
||||
if (needbind)
|
||||
xio_unlink(us.un.sun_path, E_ERROR);
|
||||
dropopts2(opts, PH_INIT, PH_SPEC); opts = opts0;
|
||||
|
||||
if (needtemp)
|
||||
xiosetunix(pf, &us.un, opt_bind_tempname?opt_bind_tempname:"",
|
||||
abstract, sfd->para.socket.un.tight);
|
||||
socktype = SOCK_SEQPACKET;
|
||||
if ((result =
|
||||
_xioopen_connect(sfd,
|
||||
needbind?&us:NULL, uslen,
|
||||
(struct sockaddr *)&them, themlen,
|
||||
opts, pf, SOCK_SEQPACKET, protocol,
|
||||
false, E_INFO)) == 0)
|
||||
needtemp, E_INFO)) == 0)
|
||||
break;
|
||||
if (errno != EPROTOTYPE && errno != EPROTONOSUPPORT/*AIX*/)
|
||||
if (errno != EPROTOTYPE && errno != EPROTONOSUPPORT/*AIX*/
|
||||
#if WITH_ABSTRACT_UNIXSOCKET
|
||||
&& !(abstract && errno == ECONNREFUSED)
|
||||
#endif
|
||||
)
|
||||
break;
|
||||
if (needbind)
|
||||
xio_unlink(us.un.sun_path, E_ERROR);
|
||||
dropopts2(opts, PH_INIT, PH_SPEC); opts = opts0;
|
||||
|
||||
if (needtemp)
|
||||
xiosetunix(pf, &us.un, opt_bind_tempname?opt_bind_tempname:"",
|
||||
abstract, sfd->para.socket.un.tight);
|
||||
sfd->peersa = them;
|
||||
sfd->salen = sizeof(struct sockaddr_un);
|
||||
sfd->salen = themlen;
|
||||
if ((result =
|
||||
_xioopen_dgram_sendto(needbind?&us:NULL, uslen,
|
||||
opts, xioflags, sfd, groups,
|
||||
pf, SOCK_DGRAM, protocol, 0))
|
||||
pf, SOCK_DGRAM, protocol, needtemp))
|
||||
== 0) {
|
||||
sfd->dtype = XIODATA_RECVFROM;
|
||||
break;
|
||||
|
@ -733,7 +793,7 @@ _xioopen_unix_client(xiosingle_t *sfd, int xioflags, groups_t groups,
|
|||
} while (0);
|
||||
|
||||
if (result != 0) {
|
||||
Error2("UNIX-CLIENT:%s: %s", name, strerror(errno));
|
||||
Error3("%s: %s: %s", addrdesc->defname, name, strerror(errno));
|
||||
if (needbind)
|
||||
xio_unlink(us.un.sun_path, E_ERROR);
|
||||
return result;
|
||||
|
@ -767,4 +827,79 @@ xiosetsockaddrenv_unix(int idx, char *namebuff, size_t namelen,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static const char tmpchars[] =
|
||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
|
||||
static size_t numchars = sizeof(tmpchars)-1;
|
||||
|
||||
/* Simplyfied version of tempnam(). Uses the current directory when pathx is
|
||||
not absolute.
|
||||
Returns a malloc()'ed string with a probably free name,
|
||||
or NULL when an error occurred */
|
||||
char *xio_tempnam(
|
||||
const char *pathx,
|
||||
bool donttry) /* for abstract, do not check if it exists */
|
||||
{
|
||||
int len;
|
||||
char *X; /* begin of XXXXXX */
|
||||
unsigned int i = TMP_MAX;
|
||||
unsigned int r1, r2;
|
||||
uint64_t v;
|
||||
char *patht;
|
||||
char readl[PATH_MAX];
|
||||
int rlc;
|
||||
|
||||
if (pathx == NULL || pathx[0] == '\0')
|
||||
pathx = "/tmp/socat-bind.XXXXXX";
|
||||
|
||||
len = strlen(pathx);
|
||||
if (len < 6 || strstr(pathx, "XXXXXX") == NULL) {
|
||||
Warn1("xio_tempnam(\"%s\"): path pattern is not valid", pathx);
|
||||
errno = EINVAL;
|
||||
return NULL;
|
||||
}
|
||||
patht = strdup(pathx);
|
||||
if (patht == NULL) {
|
||||
Error1("strdup("F_Zu"): out of memory", strlen(pathx));
|
||||
return patht;
|
||||
}
|
||||
X = strstr(patht, "XXXXXX");
|
||||
|
||||
Debug1("xio_tempnam(\"%s\"): trying path names, suppressing stat() logs",
|
||||
patht);
|
||||
while (i > 0) {
|
||||
r1 = random();
|
||||
r2 = random();
|
||||
v = r2*RAND_MAX + r1;
|
||||
X[0] = tmpchars[v%numchars];
|
||||
v /= numchars;
|
||||
X[1] = tmpchars[v%numchars];
|
||||
v /= numchars;
|
||||
X[2] = tmpchars[v%numchars];
|
||||
v /= numchars;
|
||||
X[3] = tmpchars[v%numchars];
|
||||
v /= numchars;
|
||||
X[4] = tmpchars[v%numchars];
|
||||
v /= numchars;
|
||||
X[5] = tmpchars[v%numchars];
|
||||
v /= numchars;
|
||||
|
||||
if (donttry)
|
||||
return patht;
|
||||
|
||||
/* readlink() might be faster than lstat() */
|
||||
rlc = readlink(patht, readl, sizeof(readl));
|
||||
if (rlc < 0 && errno == ENOENT)
|
||||
break;
|
||||
|
||||
--i;
|
||||
}
|
||||
|
||||
if (i == 0) {
|
||||
errno = EEXIST;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return patht;
|
||||
}
|
||||
|
||||
#endif /* WITH_UNIX */
|
||||
|
|
|
@ -18,6 +18,7 @@ extern const struct addrdesc xioaddr_abstract_recvfrom;
|
|||
extern const struct addrdesc xioaddr_abstract_recv;
|
||||
extern const struct addrdesc xioaddr_abstract_client;
|
||||
|
||||
extern const struct optdesc xioopt_unix_bind_tempname;
|
||||
extern const struct optdesc xioopt_unix_tightsocklen;
|
||||
|
||||
extern socklen_t
|
||||
|
@ -32,7 +33,8 @@ xiosetsockaddrenv_unix(int idx, char *namebuff, size_t namelen,
|
|||
struct sockaddr_un *sa, socklen_t salen, int ipproto);
|
||||
|
||||
extern int
|
||||
_xioopen_unix_client(xiosingle_t *xfd, int xioflags, groups_t groups,
|
||||
int abstract, struct opt *opts, const char *name);
|
||||
_xioopen_unix_client(xiosingle_t *xfd, int xioflags, groups_t groups, int abstract, struct opt *opts, const char *name, const struct addrdesc *addrdesc);
|
||||
|
||||
extern char *xio_tempnam(const char *pathx, bool donttry);
|
||||
|
||||
#endif /* !defined(__xio_unix_h_included) */
|
||||
|
|
|
@ -48,7 +48,7 @@ int xio_chdir(
|
|||
free(tmp_dir);
|
||||
return -1;
|
||||
}
|
||||
*orig_dir = Realloc(*orig_dir, strlen(*orig_dir+1));
|
||||
*orig_dir = Realloc(*orig_dir, strlen(*orig_dir)+1);
|
||||
|
||||
if (Chdir(tmp_dir) < 0) {
|
||||
Error2("chdir(\"%s\"): %s", tmp_dir, strerror(errno));
|
||||
|
|
13
xioopts.c
13
xioopts.c
|
@ -292,6 +292,7 @@ const struct optname optionnames[] = {
|
|||
IF_OPEN ("binary", &opt_o_binary)
|
||||
#endif
|
||||
IF_SOCKET ("bind", &opt_bind)
|
||||
IF_UNIX ("bind-tempname", &xioopt_unix_bind_tempname)
|
||||
#ifdef SO_BINDTODEVICE
|
||||
IF_SOCKET ("bindtodevice", &opt_so_bindtodevice)
|
||||
#endif
|
||||
|
@ -1880,6 +1881,7 @@ const struct optname optionnames[] = {
|
|||
IF_ANY ("uid-l", &opt_user_late)
|
||||
IF_NAMED ("umask", &opt_umask)
|
||||
IF_IP6 ("unicast-hops", &opt_ipv6_unicast_hops)
|
||||
IF_UNIX ("unix-bind-tempname", &xioopt_unix_bind_tempname)
|
||||
IF_UNIX ("unix-tightsocklen", &xioopt_unix_tightsocklen)
|
||||
IF_NAMED ("unlink", &opt_unlink)
|
||||
IF_NAMED ("unlink-close", &opt_unlink_close)
|
||||
|
@ -3223,6 +3225,7 @@ int retropt_bind(struct opt *opts,
|
|||
3..address and port allowed
|
||||
UNIX (or'd): 1..tight
|
||||
2..abstract
|
||||
4..templatename
|
||||
*/
|
||||
const int ai_flags[2])
|
||||
{
|
||||
|
@ -3313,7 +3316,17 @@ int retropt_bind(struct opt *opts,
|
|||
{
|
||||
bool abstract = (feats&2);
|
||||
bool tight = (feats&1);
|
||||
bool templatename = (feats&4);
|
||||
struct sockaddr_un *s_un = (struct sockaddr_un *)sa;
|
||||
if (templatename) {
|
||||
int i = 0;
|
||||
srandom(getpid());
|
||||
for (; i < strlen(bindname); i++) {
|
||||
if (bindname[i] == 'X') {
|
||||
bindname[i] = 'a' + (char) (random() % ('z' - 'a'));
|
||||
}
|
||||
}
|
||||
}
|
||||
*salen = xiosetunix(af, s_un, bindname, abstract, tight);
|
||||
}
|
||||
break;
|
||||
|
|
|
@ -859,7 +859,8 @@ enum e_optcode {
|
|||
OPT_TUN_NAME, /* tun: tun0 */
|
||||
OPT_TUN_TYPE, /* tun: tun|tap */
|
||||
OPT_UMASK,
|
||||
OPT_UNIX_TIGHTSOCKLEN, /* UNIX domain sockets */
|
||||
OPT_UNIX_BIND_TEMPNAME, /* UNIX domain sockets */
|
||||
OPT_UNIX_TIGHTSOCKLEN,
|
||||
OPT_UNLINK,
|
||||
OPT_UNLINK_CLOSE,
|
||||
OPT_UNLINK_EARLY,
|
||||
|
|
Loading…
Reference in a new issue