1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148
|
PORT=$(random_port)
declare -a ARGS
if [ "$NETCAT_UNIX" = "y" ]; then
FAM="AF_UNIX"
ARGS=( -${NETCAT_DGRAM:+u}U "$TEMPDIR/$PORT.sock" )
else
FAM="AF_INET"
ARGS=( ${NETCAT_DGRAM:+-u} "127.0.0.1" "$PORT" )
fi
start_server() {
#echo nc "$@"
if [ -z "$NETCAT_DGRAM" ]; then
STRACE_LINGER="n" PIPES="y" netcat_listen "$@"
else
STRACE_LINGER="y" PIPES="y" netcat_listen "$@"
fi
if [ "${BIND_ADDRESS#"{sa_family=$FAM"[,\}]}" = "$BIND_ADDRESS" ]; then # sanity check
printf "ERROR at line %d: address \"%s\" isn't %s\\n" ${BASH_LINENO[0]} "$BIND_ADDRESS" "$FAM" >&2
exit 1
fi
}
start_client() {
local in="$TEMPDIR/client.in" out="$TEMPDIR/client.out"
mkfifo -- "$in" "$out"
if [ -z "$NETCAT_DGRAM" ]; then
$NC "$@" <"$in" >"$out" {LISTEN_IN}>&- {LISTEN_OUT}<&- & CLIENT_PID=$!
else
$NC "$@" <"$in" >"$out" {LISTEN_IN}>&- {LISTEN_OUT}<&- {STRACE_FD}<&- & CLIENT_PID=$!
fi
exec {CONNECT_IN}>"$in" {CONNECT_OUT}<"$out"
rm -f -- "$in" "$out"
}
stop_client() {
kill_and_wait $CLIENT_PID
exec {CONNECT_IN}>&- {CONNECT_OUT}<&-
}
extract_source() {
local strace_recvfrom peer="" IFS_old="$IFS"
while IFS="" read -r strace_recvfrom; do
# we don't want to use `grep -m1` here because its input is
# buffered so it consumes multiple lines from the FIFO
test "${strace_recvfrom#"recvfrom($BIND_FD,"}" = "$strace_recvfrom" || break
done <&$STRACE_FD
if [[ "$strace_recvfrom" =~ ^[A-Za-z0-9_]+\([0-9]+,[[:blank:]]*\"[^\"]*\",[[:blank:]]*[0-9]+,[[:blank:]]*[^,[:blank:]]+,[[:blank:]]*(\{sa_family=([^{},[:blank:]]+)(,[^{}]+)?\}), ]]; then
peer="${BASH_REMATCH[1]}"
fi
if [ "$FAM" = "AF_INET" ] && [[ "$peer" =~ ^\{sa_family=$FAM,[[:blank:]]*sin_port=htons\(([0-9]+)\),[[:blank:]]*sin_addr=inet_addr\(\"([^\"]+)\"\)\}$ ]]; then
SPORT=${BASH_REMATCH[1]}
SADDR="${BASH_REMATCH[2]}"
elif [ "$FAM" = "AF_UNIX" ] && [[ "$peer" =~ ^\{sa_family=$FAM,[[:blank:]]*sun_path=\"([^\"]+)\"\}$ ]]; then
SPORT=""
SADDR="${BASH_REMATCH[1]}"
else
printf "ERROR at line %d: Can't extract source port from \"%s\"\\n" ${BASH_LINENO[0]} "${peer:-"$strace_recvfrom"}" >&2
exit 1
fi
IFS="$IFS_old"
PEER_ADDR="$peer"
}
#######################################################################
# without -k
start_server "${ARGS[@]}"
start_client "${ARGS[@]}"
greet server
greet client
stop_client
if [ -z "$NETCAT_DGRAM" ]; then
# the server accepts a single connection and terminates afterwards
wait $PID
else
# for UDP and not -k, the recvfrom() is followed with a connect()
extract_source
grep -m1 -E "^connect\\($BIND_FD,[[:blank:]]*\\{sa_family=$FAM," <&$STRACE_FD >"$TEMPDIR/conn"
grep -Fq -e "$PEER_ADDR" <"$TEMPDIR/conn"
if [ "$NETCAT_UNIX" = "y" ]; then
# XXX for some reason reconnecting yields EPERM with UNIX domain datagram sockets
! strace -o"$TEMPDIR/strace.log" -Z $NC -s "$SADDR" "${ARGS[@]}" 2>/dev/null
grep -Eq '^connect\([0-9]+,\s*\{sa_family='"$FAM"',[^{}]+\},\s*[0-9]+\)\s*=\s*-1\s+EPERM\s' <"$TEMPDIR/strace.log"
else
# reconnecting from a different source is a no-op (we make sure later that "foo"
# isn't read from the server) -- the test will fail if we reconnect from the
# server address+port but that should be seldom enough
$NC "${ARGS[@]}" <<<"foo"
# make sure '-vz' reports it can't connect
if $NC -vz "${ARGS[@]}" <<<"bar" 2>/dev/null; then
printf "ERROR at line %d: Could reconnect!\\n" $LINENO >&2
exit 1
fi
# can keep talking when reusing the same source though
start_client -s "$SADDR" -p $SPORT "${ARGS[@]}"
greet server
greet client
stop_client
fi
kill_and_wait "$PID"
exec {STRACE_FD}<&-
fi
exec {LISTEN_IN}>&- {LISTEN_OUT}<&-
#######################################################################
# with -k
start_server -k "${ARGS[@]}"
if [ -z "$NETCAT_DGRAM" ]; then
start_client "${ARGS[@]}"
greet server
greet client
stop_client
start_client "${ARGS[@]}"
greet client
greet server
stop_client
start_client "${ARGS[@]}"
greet server
stop_client
start_client "${ARGS[@]}"
greet client
stop_client
else
# for UDP and not -k, the recvfrom() is not connected and while it can
# receive UDP datagrams from multiple clients it cannot write to them
for ((i=0; i<4; i++)); do
start_client "${ARGS[@]}"
greet server
stop_client
done
fi
kill_and_wait $PID
# vim: set filetype=bash :
|