1
0
Fork 0
mirror of https://repo.or.cz/socat.git synced 2025-05-20 20:32:40 +00:00

Test script socks5server-echo.sh for new tests SOCKS5CONNECT_TCP4 and SOCKS5LISTEN_TCP4

This commit is contained in:
Gerhard Rieger 2025-01-29 22:21:19 +01:00
parent e7df880af5
commit 29f9e4db92
8 changed files with 223 additions and 51 deletions

View file

@ -30,6 +30,11 @@ Testing:
Fixed a few testing issues.
Added test script sock5server-echo.sh for SOCKS5-CONNECT and
SOCKS5-LISTEN, and appropriate tests.
SOCKS5 addresses are no longer experimental.
Tests: SOCKS5CONNECT_TCP4 SOCKS5LISTEN_TCP4
####################### V 1.8.0.2:
Security:

View file

@ -80,7 +80,7 @@ SHFILES = socat-chain.sh socat-mux.sh socat-broker.sh \
daemon.sh mail.sh ftp.sh readline.sh \
socat_buildscript_for_android.sh
TESTFILES = test.sh socks4echo.sh proxyecho.sh readline-test.sh \
proxy.sh socks4a-echo.sh
proxy.sh socks4a-echo.sh socks5server-echo.sh
all: progs doc

View file

@ -1108,7 +1108,6 @@ dit(bf(tt(SOCKS5-CONNECT:<socks-server>:<target-host>:<target-port>)))
to <target-host> [link(IPv4 address)(TYPE_IPV4_ADDRESS)]
on <target-port> [link(TCP service)(TYPE_TCP_SERVICE)],
using socks version 5 protocol over TCP. Currently no authentication mechanism is provided.nl()
This address type is experimental.nl()
Option groups: link(FD)(GROUP_FD), link(SOCKET)(GROUP_SOCKET), link(IP4)(GROUP_IP4), link(IP6)(GROUP_IP6), link(TCP)(GROUP_TCP), link(CHILD)(GROUP_CHILD), link(RETRY)(GROUP_RETRY)nl()
Useful options:
link(socksport)(OPTION_SOCKSPORT),
@ -1127,7 +1126,7 @@ dit(bf(tt(SOCKS5-LISTEN:<socks-server>:<listen-host>:<listen-port>)))
Connects to <socks-server> [link(IP address)(TYPE_IP_ADDRESS)]
using socks version 5 protocol over TCP
and makes it listen for incoming connections on <listen-port> [link(TCP service)(TYPE_TCP_SERVICE)], binding to <-listen-host> [link(IPv4 address)(TYPE_IPV4_ADDRESS)]
Currently not authentication mechanism is provided. This address type is experimental.
Currently not authentication mechanism is provided.nl()
Option groups: link(FD)(GROUP_FD), link(SOCKET)(GROUP_SOCKET), link(IP4)(GROUP_IP4), link(IP6)(GROUP_IP6), link(TCP)(GROUP_TCP), link(CHILD)(GROUP_CHILD), link(RETRY)(GROUP_RETRY)nl()
Useful options:
link(sourceport)(OPTION_SOURCEPORT),

View file

@ -37,7 +37,7 @@ esac
if [ $(echo "x\c") = "x" ]; then E=""
elif [ $(echo -e "x\c") = "x" ]; then E="-e"
else
echo "cannot suppress trailing newline on echo" >&2
echo "$0: cannot suppress trailing newline on echo" >&2
exit 1
fi
ECHO="echo $E"
@ -58,7 +58,7 @@ else
fi
if [ "$vn" != $($ECHO "\04") ]; then
$ECHO "$SOCKSREPLY_FAILED"
echo "invalid socks version requested" >&2
echo "$0 invalid socks version requested" >&2
exit
fi
@ -69,7 +69,7 @@ else
fi
if [ "$cd" != $($ECHO "\01") ]; then
$ECHO "$SOCKSREPLY_FAILED"
echo "invalid socks operation requested" >&2
echo "$0: invalid socks operation requested" >&2
exit
fi
@ -82,7 +82,7 @@ a=$(dd bs=1 count=6 2>/dev/null)
if [ "$a" != "$($ECHO "}m\0\0\0\01")" ]; then
sleep 1
$ECHO "$SOCKSREPLY_FAILED"
echo "wrong socks address or port requested" >&2
echo "$0: wrong socks address or port requested" >&2
exit
fi
@ -93,7 +93,7 @@ else
fi
if [ "$u" != "nobody" ]; then
$ECHO "$SOCKSREPLY_FAILED"
echo "wrong socks user requested" >&2
echo "$0: wrong socks user requested" >&2
exit
fi
@ -104,7 +104,7 @@ else
fi
if [ "$h" != "localhost" ]; then
$ECHO "$SOCKSREPLY_FAILED"
echo "wrong socks address requested" >&2
echo "$0: wrong socks address requested" >&2
exit
fi

View file

@ -36,7 +36,7 @@ esac
if [ $(echo "x\c") = "x" ]; then E=""
elif [ $(echo -e "x\c") = "x" ]; then E="-e"
else
echo "cannot suppress trailing newline on echo" >&2
echo "$0: cannot suppress trailing newline on echo" >&2
exit 1
fi
ECHO="echo $E"
@ -57,7 +57,7 @@ else
fi
if [ "$vn" != $($ECHO "\04") ]; then
$ECHO "$SOCKSREPLY_FAILED"
echo "invalid socks version requested" >&2
echo "$0: invalid socks version requested" >&2
exit
fi
@ -68,7 +68,7 @@ else
fi
if [ "$cd" != $($ECHO "\01") ]; then
$ECHO "$SOCKSREPLY_FAILED"
echo "invalid socks operation requested" >&2
echo "$0: invalid socks operation requested" >&2
exit
fi
@ -91,7 +91,7 @@ else
fi
if [ "$u" != "nobody" ]; then
$ECHO "$SOCKSREPLY_FAILED"
echo "wrong socks user requested (expected \"nobody\")" >&2
echo "$0: wrong socks user requested (expected \"nobody\")" >&2
exit
fi

67
socks5server-echo.sh Executable file
View file

@ -0,0 +1,67 @@
#! /usr/bin/env bash
# Source: socks5connect-echo.sh
# Copyright Gerhard Rieger and contributors (see file CHANGES)
# Published under the GNU General Public License V.2, see file COPYING
# Performs primitive simulation of a socks5 server with echo function via stdio.
# Accepts and answers SOCKS5 CONNECT request without authentication to
# 8.8.8.8:80, however is does not connect there but just echoes data.
# It is required for test.sh
# For TCP, use this script as:
# socat TCP-L:1080,reuseaddr EXEC:"socks5connect-echo.sh"
#set -vx
if [ "$SOCAT" ]; then
:
elif type socat >/dev/null 2>&1; then
SOCAT=socat
else
SOCAT=./socat
fi
case `uname` in
HP-UX|OSF1)
CAT="$SOCAT -u STDIN STDOUT"
;;
*)
CAT=cat
;;
esac
A="7f000001"
P="0050"
# Read and parse SOCKS5 greeting
read _ v b c _ <<<"$($SOCAT -u -,readbytes=3 - |od -t x1)"
#echo "$v $b $c" >&2
if [ "$v" != 05 ]; then echo "$0: Packet1: expected version x05, got \"$v\"" >&2; exit 1; fi
if [ "$b" != 01 ]; then echo "$0: Packet1: expected 01 auth methods, got \"$b\"" >&2; exit 1; fi
if [ "$c" != 00 ]; then echo "$0: Packet1: expected auth method 00, got \"$c\"" >&2; exit 1; fi
# Send answer
echo -en "\x05\x00"
# Read and parse SOCKS5 connect request
read _ v b c d a1 a2 a3 a4 p1 p2 _ <<<"$($SOCAT -u -,readbytes=10 - |od -t x1)"
#echo "$v $b $c $d $a1 $a2 $a3 $a4 $p1 $p2" >&2
a="$a1$a2$a3$a4"
p="$p1$p2"
if [ "$v" != 05 ]; then echo "$0: Packet2: expected version x05, got \"$v\"" >&2; exit 1; fi
if [ "$b" != 01 ] && [ "$b" != 02 ]; then echo "$0: Packet2: expected connect request 01 or bind request 02, got \"$b\"" >&2; exit 1; fi
if [ "$c" != 00 ]; then echo "$0: Packet2: expected reserved 00, got \"$c\"" >&2; exit 1; fi
if [ "$d" != 01 ]; then echo "$0: Packet2: expected address type 01, got \"$d\"" >&2; exit 1; fi
if [ "$a" != "$A" ]; then echo "$0: Packet2: expected address $A, got \"$a\"" >&2; exit 1; fi
if [ "$p" != "$P" ]; then echo "$0: Packet2: expected port $P, got \"$p\"" >&2; exit 1; fi
if [ "$z" != "" ]; then echo "$0: Packet2: trailing data \"$z\"" >&2; exit 1; fi
# Send answer
echo -en "\x05\x00\x00\x01\x10\x00\x1f\x64\x1f\x64"
# Bind/listen/passive mode
if [ "$b" == 02 ]; then
sleep 1 # pretend to be waiting for connection
echo -en "\x05\x00\x00\x01\x10\xff\x1f\x64\x23\x28"
fi
# perform echo function
$CAT

163
test.sh
View file

@ -66,6 +66,7 @@ VERBOSE=
DEBUG=
DEFS=
INTERNET=
EXPERIMENTAL=
OPT_EXPECT_FAIL= EXPECT_FAIL=
while [ "$1" ]; do
case "X$1" in
@ -4295,46 +4296,62 @@ esac
N=$((N+1))
# Test the SOCKS address with IPv4
NAME=SOCKS4CONNECT_TCP4
case "$TESTS" in
*%$N%*|*%functions%*|*%socks%*|*%socks4%*|*%tcp%*|*%tcp4%*|*%ip4%*|*%listen%*|*%$NAME%*)
TEST="$NAME: socks4 connect over TCP/IPv4"
if ! eval $NUMCOND; then :;
elif ! testfeats socks4 >/dev/null; then
$PRINTF "test $F_n $TEST... ${YELLOW}SOCKS4 not available${NORMAL}\n" $N
cant
elif ! testfeats listen tcp ip4 >/dev/null || ! runsip4 >/dev/null; then
$PRINTF "test $F_n $TEST... ${YELLOW}TCP/IPv4 not available${NORMAL}\n" $N
elif ! cond=$(checkconds \
"" \
"" \
"socks4echo.sh" \
"SOCKS4 IP4 TCP LISTEN STDIO" \
"TCP4-LISTEN EXEC STDIN SOCKS4" \
"so-reuseaddr" \
"tcp4" ); then
$PRINTF "test $F_n $TEST... ${YELLOW}$cond${NORMAL}\n" $N
cant
else
tf="$td/test$N.stdout"
te="$td/test$N.stderr"
tdiff="$td/test$N.diff"
da="test$N $(date) $RANDOM"; da="$da$($ECHO '\r')"
# we have a normal tcp echo listening - so the socks header must appear in answer
newport tcp4 # provide free port number in $PORT
CMD2="$TRACE $SOCAT $opts TCP4-L:$PORT,$REUSEADDR EXEC:\"./socks4echo.sh\""
CMD="$TRACE $SOCAT $opts - SOCKS4:$LOCALHOST:32.98.76.54:32109,pf=ip4,socksport=$PORT",socksuser="nobody"
printf "test $F_n $TEST... " $N
eval "$CMD2 2>\"${te}1\" &"
pid=$! # background process id
waittcp4port $PORT 1
echo "$da" |$CMD >$tf 2>"${te}2"
if ! echo "$da" |diff - "$tf" >"$tdiff"; then
$PRINTF "$FAILED: $TRACE $SOCAT:\n"
echo "$CMD2 &"
echo "$CMD"
cat "${te}1"
cat "${te}2"
cat "$tdiff"
failed
else
$PRINTF "$OK\n"
if [ -n "$debug" ]; then cat "${te}1" "${te}2"; fi
ok
fi
kill $pid 2>/dev/null
wait
tf="$td/test$N.stdout"
te="$td/test$N.stderr"
tdiff="$td/test$N.diff"
da="test$N $(date) $RANDOM"; da="$da$($ECHO '\r')"
newport tcp4 # provide free port number in $PORT
CMD0="$TRACE $SOCAT $opts TCP4-LISTEN:$PORT,$REUSEADDR EXEC:\"./socks4echo.sh\""
CMD1="$TRACE $SOCAT $opts STDIO SOCKS4:$LOCALHOST:32.98.76.54:32109,pf=ip4,socksport=$PORT",socksuser="nobody"
printf "test $F_n $TEST... " $N
eval "$CMD0 2>\"${te}0\" &"
pid0=$! # background process id
waittcp4port $PORT 1
echo "$da" |$CMD1 >${tf}1 2>"${te}1"
rc1=$?
kill $pid0 2>/dev/null
wait
if [ "$rc1" -ne 0 ]; then
$PRINTF "$FAILED (rc1=$rc1)\n"
echo "$CMD0 &"
cat "${te}0" >&2
echo "$CMD1"
cat "${te}1" >&2
failed
elif ! echo "$da" |diff - "${tf}1" >"$tdiff"; then
$PRINTF "$FAILED (diff)\n"
echo "$CMD0 &"
cat "${te}0" >&2
echo "$CMD1"
cat "${te}1" >&2
echo "// diff:" >&2
cat "$tdiff" >&2
failed
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
ok
fi
fi ;; # NUMCOND, feats
esac
N=$((N+1))
@ -19292,6 +19309,86 @@ fi # NUMCOND
esac
N=$((N+1))
# Above test introduced with 1.8.0.2
# Below tests introduced with 1.8.0.3 (or later)
# Test the SOCKS5-CONNECT and SOCKS5-LISTEN addresses with IPv4
for SUFFIX in CONNECT LISTEN; do
suffix=$(tolower $SUFFIX)
if [ "$SUFFIX" = LISTEN ]; then
test=listen
LISTEN=LISTEN
listen=listen
else
test=dont
LISTEN=
listen=
fi
NAME=SOCKS5${SUFFIX}_TCP4
case "$TESTS" in
*%$N%*|*%functions%*|*%socks%*|*%socks5%*|*%tcp%*|*%tcp4%*|*%ip4%*|*%$test%*|*%$NAME%*)
TEST="$NAME: SOCKS5-$SUFFIX over TCP/IPv4"
if ! eval $NUMCOND; then :;
elif ! cond=$(checkconds \
"" \
"" \
"od ./socks5server-echo.sh" \
"SOCKS5 IP4 TCP $LISTEN STDIO" \
"TCP4-LISTEN EXEC STDIN SOCKS5-$SUFFIX" \
"so-reuseaddr readbytes" \
"tcp4" ); then
$PRINTF "test $F_n $TEST... ${YELLOW}$cond${NORMAL}\n" $N
cant
else
tf="$td/test$N.stdout"
te="$td/test$N.stderr"
tdiff="$td/test$N.diff"
da="test$N $(date) $RANDOM"; da="$da$($ECHO '\r')"
newport tcp4 # provide free port number in $PORT
CMD0="$TRACE $SOCAT $opts TCP4-LISTEN:$PORT,$REUSEADDR EXEC:\"./socks5server-echo.sh\""
CMD1="$TRACE $SOCAT $opts STDIO SOCKS5-$SUFFIX:$LOCALHOST:127.0.0.1:80,pf=ip4,socksport=$PORT"
printf "test $F_n $TEST... " $N
eval "$CMD0 2>\"${te}0\" &"
pid0=$! # background process id
waittcp4port $PORT 1
echo "$da" |$CMD1 >${tf}1 2>"${te}1"
rc1=$?
kill $pid0 2>/dev/null
wait
if [ "$rc1" -ne 0 ]; then
$PRINTF "$FAILED (rc1=$rc1)\n"
echo "$CMD0 &"
cat "${te}0" >&2
echo "$CMD1"
cat "${te}1" >&2
failed
elif ! echo "$da" |diff - "${tf}1" >"$tdiff"; then
$PRINTF "$FAILED (diff)\n"
echo "$CMD0 &"
cat "${te}0" >&2
echo "$CMD1"
cat "${te}1" >&2
echo "// diff:" >&2
cat "$tdiff" >&2
failed
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
ok
fi
fi ;; # NUMCOND, feats
esac
N=$((N+1))
done # CONNECT LISTEN
# end of common tests
##################################################################################

View file

@ -53,7 +53,7 @@ static int xioopen_socks5(int argc, const char *argv[], struct opt *opts, int xi
const struct addrdesc xioaddr_socks5_connect = { "SOCKS5-CONNECT", 1+XIO_RDWR, xioopen_socks5, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP4|GROUP_SOCK_IP6|GROUP_IP_TCP|GROUP_IP_SOCKS|GROUP_CHILD|GROUP_RETRY, SOCKS5_COMMAND_CONNECT, 0, 0 HELP(":<socks-server>[:<socks-port>]:<target-host>:<target-port>") };
const struct addrdesc xioaddr_socks5_listen = { "SOCKS5-LISTEN", 1+XIO_RDWR, xioopen_socks5, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP4|GROUP_SOCK_IP6|GROUP_IP_TCP|GROUP_CHILD|GROUP_RETRY, SOCKS5_COMMAND_BIND, 0, 0 HELP(":<socks-server>[:<socks-port>]:<listen-host>:<listen-port>") };
const struct addrdesc xioaddr_socks5_listen = { "SOCKS5-LISTEN", 1+XIO_RDWR, xioopen_socks5, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP4|GROUP_SOCK_IP6|GROUP_IP_TCP|GROUP_IP_SOCKS|GROUP_CHILD|GROUP_RETRY, SOCKS5_COMMAND_BIND, 0, 0 HELP(":<socks-server>[:<socks-port>]:<listen-host>:<listen-port>") };
static const char * _xioopen_socks5_strerror(uint8_t r)
{
@ -188,6 +188,8 @@ static int _xioopen_socks5_handshake(struct single *sfd, int level)
return STAT_RETRYLATER;
}
Debug2("received SOCKS5 server hello %02x %02x",
server_hello_ptr[0], server_hello_ptr[1]);
Info2("received SOCKS5 server hello version=%d method=%d",
server_hello.version,
server_hello.method);
@ -332,6 +334,12 @@ static int _xioopen_socks5_read_reply(
}
return STAT_RETRYLATER;
}
Debug5("received SOCKS5 reply %02x %02x %02x %02x %02x",
((unsigned char *)reply+bytes_read)[0],
((unsigned char *)reply+bytes_read)[1],
((unsigned char *)reply+bytes_read)[2],
((unsigned char *)reply+bytes_read)[3],
((unsigned char *)reply+bytes_read)[4]);
bytes_read += result;
/* Once we've read 5 bytes, figure out total message length and
@ -518,10 +526,6 @@ static int xioopen_socks5(
bool lowport = false;
char infobuff[256];
if (!xioparms.experimental) {
Error1("%s: use option --experimental to acknowledge unmature state", argv[0]);
return STAT_NORETRY;
}
if (argc < 4 || argc > 5) {
xio_syntax(argv[0], 4, argc-1, addrdesc->syntax);
return STAT_NORETRY;