File: 04-kflag

package info (click to toggle)
netcat-openbsd 1.229-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 1,560 kB
  • sloc: ansic: 31,646; sh: 678; makefile: 68
file content (148 lines) | stat: -rw-r--r-- 4,736 bytes parent folder | download
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 :