mirror of
https://repo.or.cz/socat.git
synced 2024-12-22 15:32:35 +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.
|
afterwards.
|
||||||
Tests: UMASK_ON_CREATE UMASK_ON_SYSTEM
|
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:
|
Corrections:
|
||||||
When a sub process (EXEC, SYSTEM) terminated with exit code other than
|
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/
|
0, its last sent data might have been lost depending on timing of read/
|
||||||
|
|
|
@ -22,7 +22,8 @@ srcdir = @srcdir@
|
||||||
VPATH = @srcdir@
|
VPATH = @srcdir@
|
||||||
|
|
||||||
CC = @CC@
|
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)
|
CCOPTS = $(CCOPT)
|
||||||
|
|
||||||
SYSDEFS = @SYSDEFS@
|
SYSDEFS = @SYSDEFS@
|
||||||
|
|
7
compat.h
7
compat.h
|
@ -831,6 +831,13 @@ typedef unsigned long T_sigset;
|
||||||
# endif
|
# endif
|
||||||
#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... */
|
/* Cygwin 1.3.22 has the prototypes, but not the type... */
|
||||||
#ifndef HAVE_TYPE_STAT64
|
#ifndef HAVE_TYPE_STAT64
|
||||||
# undef HAVE_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
|
Binds the socket to the given socket address using the code(bind()) system
|
||||||
call. The form of <sockname> is socket domain dependent:
|
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)),
|
IP4 and IP6 allow the form [hostname|hostaddress][:(service|port)] (link(example)(EXAMPLE_OPTION_BIND_TCP4)),
|
||||||
unixdomain() sockets require link(<filename>)(TYPE_FILENAME),
|
VSOCK allows the form [cid][:(port)].nl()
|
||||||
VSOCK allow the form [cid][:(port)].
|
See also: link(unix-bind-tempname)(OPTION_UNIX_BIND_TEMPNAME)
|
||||||
label(OPTION_CONNECT_TIMEOUT)dit(bf(tt(connect-timeout=<seconds>)))
|
label(OPTION_CONNECT_TIMEOUT)dit(bf(tt(connect-timeout=<seconds>)))
|
||||||
Abort the connection attempt after <seconds> [link(timeval)(TYPE_TIMEVAL)]
|
Abort the connection attempt after <seconds> [link(timeval)(TYPE_TIMEVAL)]
|
||||||
with error status.
|
with error status.
|
||||||
|
@ -2292,6 +2292,15 @@ label(GROUP_SOCK_UNIX)em(bf(UNIX option group))
|
||||||
|
|
||||||
These options apply to UNIX domain based addresses.
|
These options apply to UNIX domain based addresses.
|
||||||
startdit()
|
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)])))
|
label(OPTION_UNIX_TIGHTSOCKLEN)dit(bf(tt(unix-tightsocklen[=(0|1)])))
|
||||||
On socket operations, pass a socket address length that does not include the
|
On socket operations, pass a socket address length that does not include the
|
||||||
whole code(struct sockaddr_un) record but (besides other components) only
|
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_send, F_SETFL, O_NONBLOCK);
|
||||||
fcntl(diag_sock_recv, F_SETFL, O_NONBLOCK);
|
fcntl(diag_sock_recv, F_SETFL, O_NONBLOCK);
|
||||||
#endif
|
#endif
|
||||||
|
fcntl(diag_sock_send, F_SETFD, FD_CLOEXEC);
|
||||||
|
fcntl(diag_sock_recv, F_SETFD, FD_CLOEXEC);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
16
procan.c
16
procan.c
|
@ -156,13 +156,23 @@ int procan(FILE *outfile) {
|
||||||
rlim.rlim_cur, rlim.rlim_max);
|
rlim.rlim_cur, rlim.rlim_max);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef SIZE_MAX
|
#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
|
#endif
|
||||||
#ifdef PIPE_BUF
|
#ifdef PIPE_BUF
|
||||||
fprintf(outfile, "PIPE_BUF = %-24d\n", PIPE_BUF);
|
fprintf(outfile, "PIPE_BUF = %-24d\n", PIPE_BUF);
|
||||||
#endif
|
#endif
|
||||||
}
|
|
||||||
|
|
||||||
/* Name spaces */
|
/* Name spaces */
|
||||||
{
|
{
|
||||||
|
|
6
sycls.c
6
sycls.c
|
@ -1146,6 +1146,7 @@ int Listen(int s, int backlog) {
|
||||||
#if _WITH_SOCKET
|
#if _WITH_SOCKET
|
||||||
/* don't forget to handle EINTR when using Accept() ! */
|
/* don't forget to handle EINTR when using Accept() ! */
|
||||||
int Accept(int s, struct sockaddr *addr, socklen_t *addrlen) {
|
int Accept(int s, struct sockaddr *addr, socklen_t *addrlen) {
|
||||||
|
char infobuff[256];
|
||||||
int result, _errno;
|
int result, _errno;
|
||||||
fd_set accept_s;
|
fd_set accept_s;
|
||||||
if (!diag_in_handler) diag_flush();
|
if (!diag_in_handler) diag_flush();
|
||||||
|
@ -1155,15 +1156,14 @@ int Accept(int s, struct sockaddr *addr, socklen_t *addrlen) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
#if WITH_SYCLS
|
#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 */
|
#endif /* WITH_SYCLS */
|
||||||
result = accept(s, addr, addrlen);
|
result = accept(s, addr, addrlen);
|
||||||
_errno = errno;
|
_errno = errno;
|
||||||
if (!diag_in_handler) diag_flush();
|
if (!diag_in_handler) diag_flush();
|
||||||
#if WITH_SYCLS
|
#if WITH_SYCLS
|
||||||
if (result >= 0) {
|
if (result >= 0) {
|
||||||
char infobuff[256];
|
|
||||||
sockaddr_info(addr, *addrlen, infobuff, sizeof(infobuff));
|
|
||||||
Info5("accept(%d, {%d, %s}, "F_socklen") -> %d", s,
|
Info5("accept(%d, {%d, %s}, "F_socklen") -> %d", s,
|
||||||
addr->sa_family,
|
addr->sa_family,
|
||||||
sockaddr_info(addr, *addrlen, infobuff, sizeof(infobuff)),
|
sockaddr_info(addr, *addrlen, infobuff, sizeof(infobuff)),
|
||||||
|
|
220
test.sh
220
test.sh
|
@ -1462,6 +1462,11 @@ waitunixport () {
|
||||||
waitfile "$1" "$2" "$3"
|
waitfile "$1" "$2" "$3"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Not implemented
|
||||||
|
waitabstractport () {
|
||||||
|
relsleep 5
|
||||||
|
}
|
||||||
|
|
||||||
# wait until a filesystem entry exists
|
# wait until a filesystem entry exists
|
||||||
waitfile () {
|
waitfile () {
|
||||||
local crit=-e
|
local crit=-e
|
||||||
|
@ -5610,7 +5615,7 @@ N=$((N+1))
|
||||||
# Test if Filan can determine UNIX domain socket in file system
|
# Test if Filan can determine UNIX domain socket in file system
|
||||||
NAME=FILANSOCKET
|
NAME=FILANSOCKET
|
||||||
case "$TESTS" in
|
case "$TESTS" in
|
||||||
*%$N%*|*%filan%*|*%listen%*|*%$NAME%*)
|
*%$N%*|*%filan%*|*%unix%*|*%listen%*|*%$NAME%*)
|
||||||
TEST="$NAME: capability to analyze named unix socket"
|
TEST="$NAME: capability to analyze named unix socket"
|
||||||
# Run Filan on a listening UNIX domain socket.
|
# Run Filan on a listening UNIX domain socket.
|
||||||
# When its output gives "socket" as type (2nd column), the test succeeded
|
# When its output gives "socket" as type (2nd column), the test succeeded
|
||||||
|
@ -5701,7 +5706,7 @@ fi
|
||||||
NAME=PTMXWAITSLAVE
|
NAME=PTMXWAITSLAVE
|
||||||
PTYTYPE=ptmx
|
PTYTYPE=ptmx
|
||||||
case "$TESTS" in
|
case "$TESTS" in
|
||||||
*%$N%*|*%functions%*|*%pty%*|*%$NAME%*)
|
*%$N%*|*%functions%*|*%pty%*|*%unix%*|*%listen%*|*%$NAME%*)
|
||||||
TEST="$NAME: test if master pty ($PTYTYPE) waits for slave connection"
|
TEST="$NAME: test if master pty ($PTYTYPE) waits for slave connection"
|
||||||
if ! eval $NUMCOND; then :; else
|
if ! eval $NUMCOND; then :; else
|
||||||
if ! feat=$(testfeats pty); then
|
if ! feat=$(testfeats pty); then
|
||||||
|
@ -5722,7 +5727,7 @@ N=$((N+1))
|
||||||
NAME=OPENPTYWAITSLAVE
|
NAME=OPENPTYWAITSLAVE
|
||||||
PTYTYPE=openpty
|
PTYTYPE=openpty
|
||||||
case "$TESTS" in
|
case "$TESTS" in
|
||||||
*%$N%*|*%functions%*|*%pty%*|*%$NAME%*)
|
*%$N%*|*%functions%*|*%pty%*|*%unix%*|*%listen%*|*%$NAME%*)
|
||||||
TEST="$NAME: test if master pty ($PTYTYPE) waits for slave connection"
|
TEST="$NAME: test if master pty ($PTYTYPE) waits for slave connection"
|
||||||
if ! eval $NUMCOND; then :;
|
if ! eval $NUMCOND; then :;
|
||||||
elif ! feat=$(testfeats pty); then
|
elif ! feat=$(testfeats pty); then
|
||||||
|
@ -7803,7 +7808,7 @@ N=$((N+1))
|
||||||
|
|
||||||
NAME=EXECENDCLOSE
|
NAME=EXECENDCLOSE
|
||||||
case "$TESTS" in
|
case "$TESTS" in
|
||||||
*%$N%*|*%functions%*|*%exec%*|*%listen%*|*%fork%*|*%$NAME%*)
|
*%$N%*|*%functions%*|*%exec%*|*%listen%*|*%unix%*|*%fork%*|*%$NAME%*)
|
||||||
TEST="$NAME: end-close keeps EXEC child running"
|
TEST="$NAME: end-close keeps EXEC child running"
|
||||||
if ! eval $NUMCOND; then :; else
|
if ! eval $NUMCOND; then :; else
|
||||||
tf="$td/test$N.stdout"
|
tf="$td/test$N.stdout"
|
||||||
|
@ -7867,7 +7872,7 @@ printf "test $F_n $TEST... " $N
|
||||||
# output for the PTY name
|
# output for the PTY name
|
||||||
{ $CMD 2>"${te}"; echo $? >"$td/test$N.rc0"; } &
|
{ $CMD 2>"${te}"; echo $? >"$td/test$N.rc0"; } &
|
||||||
waitfile "${te}"
|
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 //')
|
PTY=$(grep "N PTY is " $te |sed 's/.*N PTY is //')
|
||||||
[ -e "$PTY" ] && cat $PTY >/dev/null 2>/dev/null
|
[ -e "$PTY" ] && cat $PTY >/dev/null 2>/dev/null
|
||||||
rc=$(cat "$td/test$N.rc0")
|
rc=$(cat "$td/test$N.rc0")
|
||||||
|
@ -9015,7 +9020,7 @@ N=$((N+1))
|
||||||
# process under some circumstances.
|
# process under some circumstances.
|
||||||
NAME=EXECPTYKILL
|
NAME=EXECPTYKILL
|
||||||
case "$TESTS" in
|
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"
|
TEST="$NAME: exec:...,pty explicitely kills sub process"
|
||||||
# we want to check if the exec'd sub process is killed in time
|
# 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;
|
# 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)
|
ADDR=$(echo $addr |tr a-z A-Z)
|
||||||
NAME=${ADDR}SOCKETPAIRPACKETS
|
NAME=${ADDR}SOCKETPAIRPACKETS
|
||||||
case "$TESTS" in
|
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"
|
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
|
# 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
|
# 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
|
# Test the netns (net namespace) feature with EXEC and reset
|
||||||
NAME=NETNS_EXEC
|
NAME=NETNS_EXEC
|
||||||
case "$TESTS" in
|
case "$TESTS" in
|
||||||
*%$N%*|*%functions%*|*%root%*|*%namespace%*|*%netns%*|*%socket%*|*%$NAME%*)
|
*%$N%*|*%functions%*|*%root%*|*%namespace%*|*%netns%*|*%socket%*|*%abstract%*|*%dgram%*|*%$NAME%*)
|
||||||
ns=socat-$$-test$N
|
ns=socat-$$-test$N
|
||||||
TEST="$NAME: option netns with EXEC (net namespace $ns)"
|
TEST="$NAME: option netns with EXEC (net namespace $ns)"
|
||||||
# Start a simple server with option netns on localhost of a net namespace that
|
# Start a simple server with option netns on localhost of a net namespace that
|
||||||
|
@ -17490,20 +17495,21 @@ else
|
||||||
tdiff="$td/test$N.diff"
|
tdiff="$td/test$N.diff"
|
||||||
tdebug="$td/test$N.debug"
|
tdebug="$td/test$N.debug"
|
||||||
opwd=$(pwd)
|
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
|
printf "test $F_n $TEST... " $N
|
||||||
mkdir "$td/$tdd"
|
mkdir "$td/$tdd"
|
||||||
pushd "$td/$tdd" >/dev/null
|
pushd "$td/$tdd" >/dev/null
|
||||||
eval "$CMD0" >/dev/null 2>"${te}0"
|
eval "$CMD0" >/dev/null 2>"${te}0"
|
||||||
rc0=$?
|
rc0=$?
|
||||||
popd >/dev/null
|
popd >/dev/null
|
||||||
|
waitfile "$td/$tc"
|
||||||
tpwd=$(find $td -name $tc -print); tpwd=${tpwd%/*}
|
tpwd=$(find $td -name $tc -print); tpwd=${tpwd%/*}
|
||||||
pwd2=$(cat $tpwd/$tc </dev/null)
|
pwd2=$(cat $tpwd/$tc </dev/null)
|
||||||
echo "Original pwd: $opwd" >>$tdebug
|
echo "Original pwd: $opwd" >>$tdebug
|
||||||
echo "Temporary pwd: $tpwd" >>$tdebug
|
echo "Temporary pwd: $tpwd" >>$tdebug
|
||||||
echo "Addr2 pwd: $pwd2" >>$tdebug
|
echo "Addr2 pwd: $pwd2" >>$tdebug
|
||||||
if [ "$rc0" -ne 0 ]; then
|
if [ "$rc0" -ne 0 ]; then
|
||||||
$PRINTF "$FAILED\n"
|
$PRINTF "$FAILED (rc=$rc0)\n"
|
||||||
echo "$CMD0 &"
|
echo "$CMD0 &"
|
||||||
cat "${te}0" >&2
|
cat "${te}0" >&2
|
||||||
numFAIL=$((numFAIL+1))
|
numFAIL=$((numFAIL+1))
|
||||||
|
@ -17696,6 +17702,200 @@ esac
|
||||||
N=$((N+1))
|
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
|
# end of common tests
|
||||||
|
|
||||||
##################################################################################
|
##################################################################################
|
||||||
|
|
|
@ -62,7 +62,8 @@ static int xioopen_gopen(
|
||||||
Info1("\"%s\" is a socket, connecting to it", filename);
|
Info1("\"%s\" is a socket, connecting to it", filename);
|
||||||
|
|
||||||
result =
|
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) {
|
if (result < 0) {
|
||||||
return result;
|
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 (error_num == EAI_SERVICE && protocol != 0) {
|
||||||
if (hints.ai_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",
|
node?node:"NULL", service?service:"NULL",
|
||||||
hints.ai_flags, hints.ai_family,
|
hints.ai_flags, hints.ai_family,
|
||||||
hints.ai_socktype, hints.ai_protocol,
|
hints.ai_socktype, hints.ai_protocol,
|
||||||
|
@ -438,7 +438,7 @@ int xioresolve(const char *node, const char *service,
|
||||||
}
|
}
|
||||||
|
|
||||||
aip = res;
|
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,
|
/* We select the first IPv6 address, if available,
|
||||||
because this might accept IPv4 connections too */
|
because this might accept IPv4 connections too */
|
||||||
while (aip != NULL) {
|
while (aip != NULL) {
|
||||||
|
|
|
@ -212,7 +212,6 @@ int _xioopen_accept_fd(
|
||||||
|
|
||||||
/* Under some circumstances (e.g., TCP listen on port 0) bind() fills empty
|
/* Under some circumstances (e.g., TCP listen on port 0) bind() fills empty
|
||||||
fields that we want to know. */
|
fields that we want to know. */
|
||||||
salen = sizeof(sa);
|
|
||||||
if (Getsockname(sfd->fd, us, &uslen) < 0) {
|
if (Getsockname(sfd->fd, us, &uslen) < 0) {
|
||||||
Warn4("getsockname(%d, %p, {%d}): %s",
|
Warn4("getsockname(%d, %p, {%d}): %s",
|
||||||
sfd->fd, &us, uslen, strerror(errno));
|
sfd->fd, &us, uslen, strerror(errno));
|
||||||
|
@ -255,7 +254,6 @@ int _xioopen_accept_fd(
|
||||||
|
|
||||||
pa = &_peername;
|
pa = &_peername;
|
||||||
la = &_sockname;
|
la = &_sockname;
|
||||||
salen = sizeof(struct sockaddr);
|
|
||||||
do {
|
do {
|
||||||
/*? int level = E_ERROR;*/
|
/*? int level = E_ERROR;*/
|
||||||
Notice1("listening on %s", sockaddr_info(us, uslen, lisname, sizeof(lisname)));
|
Notice1("listening on %s", sockaddr_info(us, uslen, lisname, sizeof(lisname)));
|
||||||
|
@ -304,6 +302,7 @@ int _xioopen_accept_fd(
|
||||||
Exit(0);
|
Exit(0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
salen = sizeof(sa);
|
||||||
ps = Accept(sfd->fd, (struct sockaddr *)&sa, &salen);
|
ps = Accept(sfd->fd, (struct sockaddr *)&sa, &salen);
|
||||||
if (ps >= 0) {
|
if (ps >= 0) {
|
||||||
/*0 Info4("accept(%d, %p, {"F_Zu"}) -> %d", sfd->fd, &sa, salen, ps);*/
|
/*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,
|
OFUNC_OFFSET,
|
||||||
OPT_SO_TYPE, OPT_SO_PROTOTYPE, OPT_USER, OPT_GROUP, OPT_CLOEXEC
|
OPT_SO_TYPE, OPT_SO_PROTOTYPE, OPT_USER, OPT_GROUP, OPT_CLOEXEC
|
||||||
Does not fork, does not retry.
|
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.
|
returns 0 on success.
|
||||||
*/
|
*/
|
||||||
int _xioopen_connect(struct single *sfd, union sockaddr_union *us, size_t uslen,
|
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
|
/* waits for incoming packet, checks its source address and port. Depending
|
||||||
on fork option, it may fork a subprocess.
|
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!
|
a new subprocess!
|
||||||
Other return values indicate a problem; this can happen in the master
|
Other return values indicate a problem; this can happen in the master
|
||||||
process or in a subprocess.
|
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 */
|
#endif /* && (WITH_TCP || WITH_UDP) && WITH_LIBWRAP */
|
||||||
|
|
||||||
if (xioparms.logopt == 'm') {
|
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';
|
diag_set('y', xioparms.syslogfac); xioparms.logopt = 'y';
|
||||||
} else {
|
} else {
|
||||||
Info("starting recvfrom loop");
|
Info("starting recv loop");
|
||||||
}
|
}
|
||||||
|
|
||||||
return STAT_OK;
|
return STAT_OK;
|
||||||
|
@ -2053,6 +2057,15 @@ xiosocketpair(struct opt *opts, int pf, int socktype, int proto, int sv[2]) {
|
||||||
return result;
|
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(
|
int xiobind(
|
||||||
struct single *sfd,
|
struct single *sfd,
|
||||||
union sockaddr_union *us,
|
union sockaddr_union *us,
|
||||||
|
@ -2065,19 +2078,89 @@ int xiobind(
|
||||||
char infobuff[256];
|
char infobuff[256];
|
||||||
int result;
|
int result;
|
||||||
|
|
||||||
|
if (false /* for canonical reasons */) {
|
||||||
|
;
|
||||||
#if WITH_UNIX
|
#if WITH_UNIX
|
||||||
if (pf == PF_UNIX && us != NULL) {
|
} else if (pf == PF_UNIX) {
|
||||||
applyopts_named(us->un.sun_path, opts, PH_PREOPEN);
|
if (alt && us != NULL) {
|
||||||
}
|
bool abstract = false;
|
||||||
|
char *usrname = NULL, *sockname;
|
||||||
|
|
||||||
|
#if WITH_ABSTRACT_UNIXSOCKET
|
||||||
|
abstract = (us->un.sun_path[0] == '\0');
|
||||||
#endif
|
#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 WITH_TCP || WITH_UDP
|
||||||
if (alt) {
|
} else if (alt) {
|
||||||
union sockaddr_union sin, *sinp;
|
union sockaddr_union sin, *sinp;
|
||||||
unsigned short *port, i, N;
|
unsigned short *port, i, N;
|
||||||
div_t dv;
|
div_t dv;
|
||||||
|
|
||||||
|
applyopts(sfd, sfd->fd, opts, PH_PREBIND);
|
||||||
|
applyopts(sfd, sfd->fd, opts, PH_BIND);
|
||||||
/* prepare sockaddr for bind probing */
|
/* prepare sockaddr for bind probing */
|
||||||
if (us) {
|
if (us) {
|
||||||
sinp = us;
|
sinp = us;
|
||||||
|
@ -2147,28 +2230,21 @@ int xiobind(
|
||||||
return STAT_RETRYLATER;
|
return STAT_RETRYLATER;
|
||||||
}
|
}
|
||||||
} while (i != N);
|
} while (i != N);
|
||||||
} else
|
|
||||||
#endif /* WITH_TCP || WITH_UDP */
|
#endif /* WITH_TCP || WITH_UDP */
|
||||||
|
|
||||||
if (us) {
|
} else {
|
||||||
#if WITH_UNIX
|
applyopts(sfd, sfd->fd, opts, PH_PREBIND);
|
||||||
if (pf == PF_UNIX && us != NULL) {
|
if (us) {
|
||||||
applyopts_named(us->un.sun_path, opts, PH_PREOPEN);
|
applyopts(sfd, sfd->fd, opts, PH_BIND);
|
||||||
}
|
if (Bind(sfd->fd, &us->soa, uslen) < 0) {
|
||||||
#endif
|
Msg4(level, "bind(%d, {%s}, "F_Zd"): %s",
|
||||||
if (Bind(sfd->fd, &us->soa, uslen) < 0) {
|
sfd->fd, sockaddr_info(&us->soa, uslen, infobuff, sizeof(infobuff)),
|
||||||
Msg4(level, "bind(%d, {%s}, "F_Zd"): %s",
|
uslen, strerror(errno));
|
||||||
sfd->fd, sockaddr_info(&us->soa, uslen, infobuff, sizeof(infobuff)),
|
Close(sfd->fd);
|
||||||
uslen, strerror(errno));
|
return STAT_RETRYLATER;
|
||||||
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);
|
applyopts(sfd, -1, opts, PH_PASTBIND);
|
||||||
return 0;
|
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>") };
|
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 */
|
#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) };
|
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);
|
len = sizeof(struct sockaddr_un);
|
||||||
}
|
}
|
||||||
return len;
|
return len;
|
||||||
}
|
} else
|
||||||
#endif /* WITH_ABSTRACT_UNIXSOCKET */
|
#endif /* WITH_ABSTRACT_UNIXSOCKET */
|
||||||
|
|
||||||
if ((pathlen = strlen(path)) > sizeof(saun->sun_path)) {
|
if ((pathlen = strlen(path)) > sizeof(saun->sun_path)) {
|
||||||
|
@ -139,7 +140,7 @@ static int xioopen_unix_listen(
|
||||||
}
|
}
|
||||||
name = argv[1];
|
name = argv[1];
|
||||||
|
|
||||||
sfd->para.socket.un.tight = true;
|
sfd->para.socket.un.tight = UNIX_TIGHTSOCKLEN;
|
||||||
retropt_socket_pf(opts, &pf);
|
retropt_socket_pf(opts, &pf);
|
||||||
sfd->howtoend = END_SHUTDOWN;
|
sfd->howtoend = END_SHUTDOWN;
|
||||||
|
|
||||||
|
@ -221,11 +222,13 @@ static int xioopen_unix_connect(
|
||||||
struct sockaddr_un them, us;
|
struct sockaddr_un them, us;
|
||||||
socklen_t themlen, uslen = sizeof(us);
|
socklen_t themlen, uslen = sizeof(us);
|
||||||
bool needbind = false;
|
bool needbind = false;
|
||||||
|
bool needtemp = false;
|
||||||
bool opt_unlink_close = (addrdesc->arg1/*abstract*/ != 1);
|
bool opt_unlink_close = (addrdesc->arg1/*abstract*/ != 1);
|
||||||
bool dofork = false;
|
bool dofork = false;
|
||||||
struct opt *opts0;
|
struct opt *opts0;
|
||||||
char infobuff[256];
|
char infobuff[256];
|
||||||
int level;
|
int level;
|
||||||
|
char *opt_bind_tempname = NULL;
|
||||||
int result;
|
int result;
|
||||||
|
|
||||||
if (argc != 2) {
|
if (argc != 2) {
|
||||||
|
@ -234,7 +237,7 @@ static int xioopen_unix_connect(
|
||||||
}
|
}
|
||||||
name = argv[1];
|
name = argv[1];
|
||||||
|
|
||||||
sfd->para.socket.un.tight = true;
|
sfd->para.socket.un.tight = UNIX_TIGHTSOCKLEN;
|
||||||
retropt_socket_pf(opts, &pf);
|
retropt_socket_pf(opts, &pf);
|
||||||
sfd->howtoend = END_SHUTDOWN;
|
sfd->howtoend = END_SHUTDOWN;
|
||||||
if (applyopts_single(sfd, opts, PH_INIT) < 0) return STAT_NORETRY;
|
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 */
|
/* Only for non abstract because abstract do not work in file system */
|
||||||
retropt_bool(opts, OPT_UNLINK_CLOSE, &opt_unlink_close);
|
retropt_bool(opts, OPT_UNLINK_CLOSE, &opt_unlink_close);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (retropt_bind(opts, pf, socktype, protocol, (struct sockaddr *)&us, &uslen,
|
if (retropt_bind(opts, pf, socktype, protocol, (struct sockaddr *)&us, &uslen,
|
||||||
(addrdesc->arg1/*abstract*/<<1)|sfd->para.socket.un.tight,
|
(addrdesc->arg1/*abstract*/<<1)|sfd->para.socket.un.tight,
|
||||||
sfd->para.socket.ip.ai_flags)
|
sfd->para.socket.ip.ai_flags)
|
||||||
|
@ -256,18 +260,25 @@ static int xioopen_unix_connect(
|
||||||
needbind = true;
|
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 &&
|
if (!needbind &&
|
||||||
(namedopt = searchopt(opts, GROUP_NAMED, 0, 0, 0))) {
|
(namedopt = searchopt(opts, GROUP_NAMED, 0, 0, 0))) {
|
||||||
Error1("Option \"%s\" only with bind option", namedopt->desc->defname);
|
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);
|
retropt_bool(opts, OPT_FORK, &dofork);
|
||||||
|
|
||||||
opts0 = copyopts(opts, GROUP_ALL);
|
opts0 = copyopts(opts, GROUP_ALL);
|
||||||
|
@ -288,7 +299,7 @@ static int xioopen_unix_connect(
|
||||||
_xioopen_connect(sfd,
|
_xioopen_connect(sfd,
|
||||||
needbind?(union sockaddr_union *)&us:NULL, uslen,
|
needbind?(union sockaddr_union *)&us:NULL, uslen,
|
||||||
(struct sockaddr *)&them, themlen,
|
(struct sockaddr *)&them, themlen,
|
||||||
opts, pf, socktype, protocol, false, level);
|
opts, pf, socktype, protocol, needtemp, level);
|
||||||
if (result != 0) {
|
if (result != 0) {
|
||||||
char infobuff[256];
|
char infobuff[256];
|
||||||
/* we caller must handle this */
|
/* we caller must handle this */
|
||||||
|
@ -382,10 +393,12 @@ static int xioopen_unix_sendto(
|
||||||
int pf = PF_UNIX;
|
int pf = PF_UNIX;
|
||||||
int socktype = SOCK_DGRAM;
|
int socktype = SOCK_DGRAM;
|
||||||
int protocol = 0;
|
int protocol = 0;
|
||||||
union sockaddr_union us;
|
struct sockaddr_un us;
|
||||||
socklen_t uslen = sizeof(us);
|
socklen_t uslen = sizeof(us);
|
||||||
bool needbind = false;
|
bool needbind = false;
|
||||||
|
bool needtemp = false;
|
||||||
bool opt_unlink_close = (addrdesc->arg1/*abstract*/ != 1);
|
bool opt_unlink_close = (addrdesc->arg1/*abstract*/ != 1);
|
||||||
|
char *opt_bind_tempname = NULL;
|
||||||
int result;
|
int result;
|
||||||
|
|
||||||
if (argc != 2) {
|
if (argc != 2) {
|
||||||
|
@ -394,7 +407,7 @@ static int xioopen_unix_sendto(
|
||||||
}
|
}
|
||||||
name = argv[1];
|
name = argv[1];
|
||||||
|
|
||||||
sfd->para.socket.un.tight = true;
|
sfd->para.socket.un.tight = UNIX_TIGHTSOCKLEN;
|
||||||
retropt_socket_pf(opts, &pf);
|
retropt_socket_pf(opts, &pf);
|
||||||
sfd->howtoend = END_SHUTDOWN;
|
sfd->howtoend = END_SHUTDOWN;
|
||||||
applyopts_offset(sfd, opts);
|
applyopts_offset(sfd, opts);
|
||||||
|
@ -408,13 +421,24 @@ static int xioopen_unix_sendto(
|
||||||
|
|
||||||
sfd->dtype = XIODATA_RECVFROM;
|
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,
|
(addrdesc->arg1/*abstract*/<<1)| sfd->para.socket.un.tight,
|
||||||
sfd->para.socket.ip.ai_flags)
|
sfd->para.socket.ip.ai_flags)
|
||||||
== STAT_OK) {
|
== STAT_OK) {
|
||||||
needbind = true;
|
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 &&
|
if (!needbind &&
|
||||||
(namedopt = searchopt(opts, GROUP_NAMED, 0, 0, 0))) {
|
(namedopt = searchopt(opts, GROUP_NAMED, 0, 0, 0))) {
|
||||||
Error1("Option \"%s\" only with bind option", namedopt->desc->defname);
|
Error1("Option \"%s\" only with bind option", namedopt->desc->defname);
|
||||||
|
@ -426,14 +450,14 @@ static int xioopen_unix_sendto(
|
||||||
result =
|
result =
|
||||||
_xioopen_dgram_sendto(needbind?(union sockaddr_union *)&us:NULL, uslen,
|
_xioopen_dgram_sendto(needbind?(union sockaddr_union *)&us:NULL, uslen,
|
||||||
opts, xioflags, sfd, addrdesc->groups,
|
opts, xioflags, sfd, addrdesc->groups,
|
||||||
pf, socktype, protocol, 0);
|
pf, socktype, protocol, needtemp);
|
||||||
if (result != 0) {
|
if (result != 0) {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (opt_unlink_close && needbind) {
|
if (opt_unlink_close && needbind) {
|
||||||
if ((sfd->unlink_close = strndup(us.un.sun_path, sizeof(us.un.sun_path))) == NULL) {
|
if ((sfd->unlink_close = strndup(us.sun_path, sizeof(us.sun_path))) == NULL) {
|
||||||
Error2("strndup(\"%s\", "F_Zu"): out of memory", name, sizeof(us.un.sun_path));
|
Error2("strndup(\"%s\", "F_Zu"): out of memory", name, sizeof(us.sun_path));
|
||||||
}
|
}
|
||||||
sfd->opt_unlink_close = true;
|
sfd->opt_unlink_close = true;
|
||||||
}
|
}
|
||||||
|
@ -468,7 +492,7 @@ int xioopen_unix_recvfrom(
|
||||||
}
|
}
|
||||||
name = argv[1];
|
name = argv[1];
|
||||||
|
|
||||||
sfd->para.socket.un.tight = true;
|
sfd->para.socket.un.tight = UNIX_TIGHTSOCKLEN;
|
||||||
retropt_socket_pf(opts, &pf);
|
retropt_socket_pf(opts, &pf);
|
||||||
sfd->howtoend = END_NONE;
|
sfd->howtoend = END_NONE;
|
||||||
if (applyopts_single(sfd, opts, PH_INIT) < 0) return STAT_NORETRY;
|
if (applyopts_single(sfd, opts, PH_INIT) < 0) return STAT_NORETRY;
|
||||||
|
@ -554,7 +578,7 @@ static int xioopen_unix_recv(
|
||||||
}
|
}
|
||||||
name = argv[1];
|
name = argv[1];
|
||||||
|
|
||||||
sfd->para.socket.un.tight = true;
|
sfd->para.socket.un.tight = UNIX_TIGHTSOCKLEN;
|
||||||
retropt_socket_pf(opts, &pf);
|
retropt_socket_pf(opts, &pf);
|
||||||
sfd->howtoend = END_SHUTDOWN;
|
sfd->howtoend = END_SHUTDOWN;
|
||||||
if (applyopts_single(sfd, opts, PH_INIT) < 0) return STAT_NORETRY;
|
if (applyopts_single(sfd, opts, PH_INIT) < 0) return STAT_NORETRY;
|
||||||
|
@ -625,7 +649,7 @@ static int xioopen_unix_client(
|
||||||
|
|
||||||
return
|
return
|
||||||
_xioopen_unix_client(&xxfd->stream, xioflags, addrdesc->groups,
|
_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
|
/* 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,
|
OPT_SO_TYPE, OPT_SO_PROTOTYPE, OPT_CLOEXEC, OPT_USER, OPT_GROUP, ?OPT_FORK,
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
_xioopen_unix_client(xiosingle_t *sfd, int xioflags, groups_t groups,
|
_xioopen_unix_client(
|
||||||
int abstract, struct opt *opts, const char *name) {
|
xiosingle_t *sfd,
|
||||||
|
int xioflags,
|
||||||
|
groups_t groups,
|
||||||
|
int abstract,
|
||||||
|
struct opt *opts,
|
||||||
|
const char *name,
|
||||||
|
const struct addrdesc *addrdesc)
|
||||||
|
{
|
||||||
const struct opt *namedopt;
|
const struct opt *namedopt;
|
||||||
int pf = PF_UNIX;
|
int pf = PF_UNIX;
|
||||||
int socktype = 0; /* to be determined by server socket type */
|
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;
|
union sockaddr_union them, us;
|
||||||
socklen_t themlen, uslen = sizeof(us);
|
socklen_t themlen, uslen = sizeof(us);
|
||||||
bool needbind = false;
|
bool needbind = false;
|
||||||
|
bool needtemp = false;
|
||||||
bool opt_unlink_close = false;
|
bool opt_unlink_close = false;
|
||||||
|
char *opt_bind_tempname = NULL;
|
||||||
struct opt *opts0;
|
struct opt *opts0;
|
||||||
int result;
|
int result;
|
||||||
|
|
||||||
sfd->para.socket.un.tight = true;
|
sfd->para.socket.un.tight = UNIX_TIGHTSOCKLEN;
|
||||||
retropt_socket_pf(opts, &pf);
|
retropt_socket_pf(opts, &pf);
|
||||||
sfd->howtoend = END_SHUTDOWN;
|
sfd->howtoend = END_SHUTDOWN;
|
||||||
if (applyopts_single(sfd, opts, PH_INIT) < 0) return STAT_NORETRY;
|
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 */
|
/* only for non abstract because abstract do not work in file system */
|
||||||
retropt_bool(opts, OPT_UNLINK_CLOSE, &opt_unlink_close);
|
retropt_bool(opts, OPT_UNLINK_CLOSE, &opt_unlink_close);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (retropt_bind(opts, pf, socktype, protocol, &us.soa, &uslen,
|
if (retropt_bind(opts, pf, socktype, protocol, &us.soa, &uslen,
|
||||||
(abstract<<1)|sfd->para.socket.un.tight,
|
(abstract<<1)|sfd->para.socket.un.tight,
|
||||||
sfd->para.socket.ip.ai_flags)
|
sfd->para.socket.ip.ai_flags)
|
||||||
|
@ -674,6 +708,15 @@ _xioopen_unix_client(xiosingle_t *sfd, int xioflags, groups_t groups,
|
||||||
needbind = true;
|
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 &&
|
if (!needbind &&
|
||||||
(namedopt = searchopt(opts, GROUP_NAMED, 0, 0, 0))) {
|
(namedopt = searchopt(opts, GROUP_NAMED, 0, 0, 0))) {
|
||||||
Error1("Option \"%s\" only with bind option", namedopt->desc->defname);
|
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 */
|
/* just a breakable block, helps to avoid goto */
|
||||||
do {
|
do {
|
||||||
/* sfd->dtype = DATA_STREAM; // is default */
|
/* 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 */
|
/* this function handles AF_UNIX with EPROTOTYPE specially for us */
|
||||||
if ((result =
|
if ((result =
|
||||||
_xioopen_connect(sfd,
|
_xioopen_connect(sfd,
|
||||||
needbind?&us:NULL, uslen,
|
needbind?&us:NULL, uslen,
|
||||||
&them.soa, themlen,
|
&them.soa, themlen,
|
||||||
opts, pf, socktype?socktype:SOCK_STREAM, protocol,
|
opts, pf, socktype?socktype:SOCK_STREAM, protocol,
|
||||||
false, E_INFO)) == 0)
|
needtemp, E_INFO)) == 0)
|
||||||
break;
|
break;
|
||||||
if (errno != EPROTOTYPE || socktype != 0)
|
if ((errno != EPROTOTYPE
|
||||||
|
#if WITH_ABSTRACT_UNIXSOCKET
|
||||||
|
&& !(abstract && errno == ECONNREFUSED)
|
||||||
|
#endif
|
||||||
|
) || socktype != 0)
|
||||||
break;
|
break;
|
||||||
if (needbind)
|
if (needbind)
|
||||||
xio_unlink(us.un.sun_path, E_ERROR);
|
xio_unlink(us.un.sun_path, E_ERROR);
|
||||||
dropopts2(opts, PH_INIT, PH_SPEC); opts = opts0;
|
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;
|
socktype = SOCK_SEQPACKET;
|
||||||
if ((result =
|
if ((result =
|
||||||
_xioopen_connect(sfd,
|
_xioopen_connect(sfd,
|
||||||
needbind?&us:NULL, uslen,
|
needbind?&us:NULL, uslen,
|
||||||
(struct sockaddr *)&them, themlen,
|
(struct sockaddr *)&them, themlen,
|
||||||
opts, pf, SOCK_SEQPACKET, protocol,
|
opts, pf, SOCK_SEQPACKET, protocol,
|
||||||
false, E_INFO)) == 0)
|
needtemp, E_INFO)) == 0)
|
||||||
break;
|
break;
|
||||||
if (errno != EPROTOTYPE && errno != EPROTONOSUPPORT/*AIX*/)
|
if (errno != EPROTOTYPE && errno != EPROTONOSUPPORT/*AIX*/
|
||||||
|
#if WITH_ABSTRACT_UNIXSOCKET
|
||||||
|
&& !(abstract && errno == ECONNREFUSED)
|
||||||
|
#endif
|
||||||
|
)
|
||||||
break;
|
break;
|
||||||
if (needbind)
|
if (needbind)
|
||||||
xio_unlink(us.un.sun_path, E_ERROR);
|
xio_unlink(us.un.sun_path, E_ERROR);
|
||||||
dropopts2(opts, PH_INIT, PH_SPEC); opts = opts0;
|
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->peersa = them;
|
||||||
sfd->salen = sizeof(struct sockaddr_un);
|
sfd->salen = themlen;
|
||||||
if ((result =
|
if ((result =
|
||||||
_xioopen_dgram_sendto(needbind?&us:NULL, uslen,
|
_xioopen_dgram_sendto(needbind?&us:NULL, uslen,
|
||||||
opts, xioflags, sfd, groups,
|
opts, xioflags, sfd, groups,
|
||||||
pf, SOCK_DGRAM, protocol, 0))
|
pf, SOCK_DGRAM, protocol, needtemp))
|
||||||
== 0) {
|
== 0) {
|
||||||
sfd->dtype = XIODATA_RECVFROM;
|
sfd->dtype = XIODATA_RECVFROM;
|
||||||
break;
|
break;
|
||||||
|
@ -733,7 +793,7 @@ _xioopen_unix_client(xiosingle_t *sfd, int xioflags, groups_t groups,
|
||||||
} while (0);
|
} while (0);
|
||||||
|
|
||||||
if (result != 0) {
|
if (result != 0) {
|
||||||
Error2("UNIX-CLIENT:%s: %s", name, strerror(errno));
|
Error3("%s: %s: %s", addrdesc->defname, name, strerror(errno));
|
||||||
if (needbind)
|
if (needbind)
|
||||||
xio_unlink(us.un.sun_path, E_ERROR);
|
xio_unlink(us.un.sun_path, E_ERROR);
|
||||||
return result;
|
return result;
|
||||||
|
@ -767,4 +827,79 @@ xiosetsockaddrenv_unix(int idx, char *namebuff, size_t namelen,
|
||||||
return 0;
|
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 */
|
#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_recv;
|
||||||
extern const struct addrdesc xioaddr_abstract_client;
|
extern const struct addrdesc xioaddr_abstract_client;
|
||||||
|
|
||||||
|
extern const struct optdesc xioopt_unix_bind_tempname;
|
||||||
extern const struct optdesc xioopt_unix_tightsocklen;
|
extern const struct optdesc xioopt_unix_tightsocklen;
|
||||||
|
|
||||||
extern socklen_t
|
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);
|
struct sockaddr_un *sa, socklen_t salen, int ipproto);
|
||||||
|
|
||||||
extern int
|
extern int
|
||||||
_xioopen_unix_client(xiosingle_t *xfd, int xioflags, groups_t groups,
|
_xioopen_unix_client(xiosingle_t *xfd, int xioflags, groups_t groups, int abstract, struct opt *opts, const char *name, const struct addrdesc *addrdesc);
|
||||||
int abstract, struct opt *opts, const char *name);
|
|
||||||
|
extern char *xio_tempnam(const char *pathx, bool donttry);
|
||||||
|
|
||||||
#endif /* !defined(__xio_unix_h_included) */
|
#endif /* !defined(__xio_unix_h_included) */
|
||||||
|
|
|
@ -48,7 +48,7 @@ int xio_chdir(
|
||||||
free(tmp_dir);
|
free(tmp_dir);
|
||||||
return -1;
|
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) {
|
if (Chdir(tmp_dir) < 0) {
|
||||||
Error2("chdir(\"%s\"): %s", tmp_dir, strerror(errno));
|
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)
|
IF_OPEN ("binary", &opt_o_binary)
|
||||||
#endif
|
#endif
|
||||||
IF_SOCKET ("bind", &opt_bind)
|
IF_SOCKET ("bind", &opt_bind)
|
||||||
|
IF_UNIX ("bind-tempname", &xioopt_unix_bind_tempname)
|
||||||
#ifdef SO_BINDTODEVICE
|
#ifdef SO_BINDTODEVICE
|
||||||
IF_SOCKET ("bindtodevice", &opt_so_bindtodevice)
|
IF_SOCKET ("bindtodevice", &opt_so_bindtodevice)
|
||||||
#endif
|
#endif
|
||||||
|
@ -1880,6 +1881,7 @@ const struct optname optionnames[] = {
|
||||||
IF_ANY ("uid-l", &opt_user_late)
|
IF_ANY ("uid-l", &opt_user_late)
|
||||||
IF_NAMED ("umask", &opt_umask)
|
IF_NAMED ("umask", &opt_umask)
|
||||||
IF_IP6 ("unicast-hops", &opt_ipv6_unicast_hops)
|
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_UNIX ("unix-tightsocklen", &xioopt_unix_tightsocklen)
|
||||||
IF_NAMED ("unlink", &opt_unlink)
|
IF_NAMED ("unlink", &opt_unlink)
|
||||||
IF_NAMED ("unlink-close", &opt_unlink_close)
|
IF_NAMED ("unlink-close", &opt_unlink_close)
|
||||||
|
@ -3223,6 +3225,7 @@ int retropt_bind(struct opt *opts,
|
||||||
3..address and port allowed
|
3..address and port allowed
|
||||||
UNIX (or'd): 1..tight
|
UNIX (or'd): 1..tight
|
||||||
2..abstract
|
2..abstract
|
||||||
|
4..templatename
|
||||||
*/
|
*/
|
||||||
const int ai_flags[2])
|
const int ai_flags[2])
|
||||||
{
|
{
|
||||||
|
@ -3313,7 +3316,17 @@ int retropt_bind(struct opt *opts,
|
||||||
{
|
{
|
||||||
bool abstract = (feats&2);
|
bool abstract = (feats&2);
|
||||||
bool tight = (feats&1);
|
bool tight = (feats&1);
|
||||||
|
bool templatename = (feats&4);
|
||||||
struct sockaddr_un *s_un = (struct sockaddr_un *)sa;
|
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);
|
*salen = xiosetunix(af, s_un, bindname, abstract, tight);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -859,7 +859,8 @@ enum e_optcode {
|
||||||
OPT_TUN_NAME, /* tun: tun0 */
|
OPT_TUN_NAME, /* tun: tun0 */
|
||||||
OPT_TUN_TYPE, /* tun: tun|tap */
|
OPT_TUN_TYPE, /* tun: tun|tap */
|
||||||
OPT_UMASK,
|
OPT_UMASK,
|
||||||
OPT_UNIX_TIGHTSOCKLEN, /* UNIX domain sockets */
|
OPT_UNIX_BIND_TEMPNAME, /* UNIX domain sockets */
|
||||||
|
OPT_UNIX_TIGHTSOCKLEN,
|
||||||
OPT_UNLINK,
|
OPT_UNLINK,
|
||||||
OPT_UNLINK_CLOSE,
|
OPT_UNLINK_CLOSE,
|
||||||
OPT_UNLINK_EARLY,
|
OPT_UNLINK_EARLY,
|
||||||
|
|
Loading…
Reference in a new issue