From ea657bbf78707c65dd9748c933aff8fc7ac50bce Mon Sep 17 00:00:00 2001 From: Gerhard Rieger Date: Sun, 22 Jul 2012 15:46:52 +0200 Subject: [PATCH] UDP-LISTEN would alway set SO_REUSEADDR even without fork option and when user set it to 0 --- CHANGES | 3 +++ test.sh | 58 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ xio-udp.c | 20 ++++++++++++------- 3 files changed, 74 insertions(+), 7 deletions(-) diff --git a/CHANGES b/CHANGES index 4bf62a9..6575bb1 100644 --- a/CHANGES +++ b/CHANGES @@ -37,6 +37,9 @@ corrections: fixed a bug where socat might crash when connecting to a unix domain socket using address GOPEN. Thanks to Martin Forssen for bug report and patch. + + UDP-LISTEN would alway set SO_REUSEADDR even without fork option and + when user set it to 0. Thanks to Michal Svoboda for reporting this bug. docu mentions option so-bindtodev but correct name is so-bindtodevice. Thanks to Jim Zimmerman for reporting. diff --git a/test.sh b/test.sh index d258831..ef3c2ea 100755 --- a/test.sh +++ b/test.sh @@ -6115,6 +6115,63 @@ esac N=$((N+1)) +NAME=UDPLISTENFORK +case "$TESTS" in +*%functions%*|*%ip4%*|*%udp%*|*%listen%*|*%fork%*|*%$NAME%*) +TEST="$NAME: UDP socket rebinds after first connection" +if ! eval $NUMCOND; then :; else +tf="$td/test$N.stdout" +te="$td/test$N.stderr" +tdiff="$td/test$N.diff" +da1="test$N $(date) $RANDOM" +da2="test$N $(date) $RANDOM" +#establish a listening and forking udp socket in background +SRV="$SOCAT $opts -lpserver UDP4-LISTEN:$PORT,bind=$LOCALHOST,fork PIPE" +#make a first and a second connection +CLI="$SOCAT $opts -lpclient - UDP4-CONNECT:$LOCALHOST:$PORT" +$PRINTF "test $F_n $TEST... " $N +eval "$SRV 2>${te}s &" +pids=$! +waitudp4port "$PORT" +echo "$da1" |eval "$CLI" >"${tf}1" 2>"${te}1" +if [ $? -ne 0 ]; then + kill "$pids" 2>/dev/null + $PRINTF "$NO_RESULT (first conn failed):\n" + echo "$SRV &" + echo "$CLI" + cat "${te}s" "${te}1" + numCANT=$((numCANT+1)) +elif ! echo "$da1" |diff - "${tf}1" >"$tdiff"; then + kill "$pids" 2>/dev/null + $PRINTF "$NO_RESULT (first conn failed); diff:\n" + cat "$tdiff" + numCANT=$((numCANT+1)) +else +sleep 2 # UDP-LISTEN sleeps 1s +echo "$da2" |eval "$CLI" >"${tf}2" 2>"${te}2" +rc="$?"; kill "$pids" 2>/dev/null +if [ $rc -ne 0 ]; then + $PRINTF "$FAILED:\n" + echo "$SRV &" + echo "$CLI" + cat "${te}s" "${te}2" + numFAIL=$((numFAIL+1)) +elif ! echo "$da2" |diff - "${tf}2" >"$tdiff"; then + $PRINTF "$FAILED: diff\n" + cat "$tdiff" + numFAIL=$((numFAIL+1)) +else + $PRINTF "$OK\n" + numOK=$((numOK+1)) +fi # !( $? -ne 0) +fi # !(rc -ne 0) +wait +fi ;; # NUMCOND, feats +esac +PORT=$((PORT+1)) +N=$((N+1)) + + NAME=UNIXLISTENFORK case "$TESTS" in *%functions%*|*%unix%*|*%listen%*|*%fork%*|*%$NAME%*) @@ -10786,6 +10843,7 @@ esac N=$((N+1)) + # socat up to 1.7.2.0 and 2.0.0-b4 had a bug in xioscan_readline() that could # be exploited # to overflow a heap based buffer (socat security advisory 3) diff --git a/xio-udp.c b/xio-udp.c index 2c0d6ff..aa1ab0c 100644 --- a/xio-udp.c +++ b/xio-udp.c @@ -1,5 +1,5 @@ /* source: xio-udp.c */ -/* Copyright Gerhard Rieger 2001-2009 */ +/* Copyright Gerhard Rieger 2001-2012 */ /* Published under the GNU General Public License V.2, see file COPYING */ /* this file contains the source for handling UDP addresses */ @@ -188,7 +188,8 @@ int xioopen_ipdgram_listen(int argc, const char *argv[], struct opt *opts, while (true) { /* we loop with fork or prohibited packets */ /* now wait for some packet on this datagram socket, get its sender address, connect there, and return */ - int one = 1; + int reuseaddr = dofork; + int doreuseaddr = (dofork != 0); char infobuff[256]; union sockaddr_union _sockname; union sockaddr_union *la = &_sockname; /* local address */ @@ -197,12 +198,17 @@ int xioopen_ipdgram_listen(int argc, const char *argv[], struct opt *opts, return STAT_RETRYLATER; } /*0 Info4("socket(%d, %d, %d) -> %d", pf, socktype, ipproto, fd->stream.fd);*/ + doreuseaddr |= (retropt_int(opts, OPT_SO_REUSEADDR, &reuseaddr) >= 0); applyopts(fd->stream.rfd, opts, PH_PASTSOCKET); - if (Setsockopt(fd->stream.rfd, opt_so_reuseaddr.major, - opt_so_reuseaddr.minor, &one, sizeof(one)) < 0) { - Warn6("setsockopt(%d, %d, %d, {%d}, "F_Zd"): %s", - fd->stream.rfd, opt_so_reuseaddr.major, - opt_so_reuseaddr.minor, one, sizeof(one), strerror(errno)); + if (doreuseaddr) { + if (Setsockopt(fd->stream.rfd, opt_so_reuseaddr.major, + opt_so_reuseaddr.minor, &reuseaddr, sizeof(reuseaddr)) + < 0) { + Warn6("setsockopt(%d, %d, %d, {%d}, "F_Zd"): %s", + fd->stream.rfd, opt_so_reuseaddr.major, + opt_so_reuseaddr.minor, reuseaddr, sizeof(reuseaddr), + strerror(errno)); + } } applyopts_cloexec(fd->stream.rfd, opts); applyopts(fd->stream.rfd, opts, PH_PREBIND);