tests: Match IPv6 connections in netstat output
[ctdb.git] / tests / complex / scripts / local.bash
1 # Hey Emacs, this is a -*- shell-script -*- !!!  :-)
2
3 get_src_socket ()
4 {
5     local proto="$1"
6     local dst_socket="$2"
7     local pid="$3"
8     local prog="$4"
9
10     local pat="^${proto}6?[[:space:]]+[[:digit:]]+[[:space:]]+[[:digit:]]+[[:space:]]+[^[:space:]]+[[:space:]]+${dst_socket//./\\.}[[:space:]]+ESTABLISHED[[:space:]]+${pid}/${prog}[[:space:]]*\$"
11     out=$(netstat -tanp |
12         egrep "$pat" |
13         awk '{ print $4 }')
14
15     [ -n "$out" ]
16 }
17
18 wait_until_get_src_socket ()
19 {
20     local proto="$1"
21     local dst_socket="$2"
22     local pid="$3"
23     local prog="$4"
24
25     echo "Waiting for ${prog} to establish connection to ${dst_socket}..."
26
27     wait_until 5 get_src_socket "$@"
28 }
29
30 #######################################
31
32 check_tickles ()
33 {
34     local node="$1"
35     local test_ip="$2"
36     local test_port="$3"
37     local src_socket="$4"
38     try_command_on_node $node ctdb gettickles $test_ip $test_port
39     # SRC: 10.0.2.45:49091   DST: 10.0.2.143:445
40     [ "${out/SRC: ${src_socket} /}" != "$out" ]
41 }
42
43 check_tickles_all ()
44 {
45     local numnodes="$1"
46     local test_ip="$2"
47     local test_port="$3"
48     local src_socket="$4"
49
50     try_command_on_node all ctdb gettickles $test_ip $test_port
51     # SRC: 10.0.2.45:49091   DST: 10.0.2.143:445
52     local t="${src_socket//./\\.}"
53     local count=$(grep -E -c "SRC: ${t} " <<<"$out" || true)
54     [ $count -eq $numnodes ]
55 }
56
57
58
59 #######################################
60
61 # filename will be in $tcpdump_filename, pid in $tcpdump_pid
62 tcpdump_start ()
63 {
64     tcpdump_filter="$1" # global
65
66     echo "Running tcpdump..."
67     tcpdump_filename=$(mktemp)
68     ctdb_test_exit_hook_add "rm -f $tcpdump_filename"
69
70     # The only way of being sure that tcpdump is listening is to send
71     # some packets that it will see.  So we use dummy pings - the -U
72     # option to tcpdump ensures that packets are flushed to the file
73     # as they are captured.
74     local dummy_addr="127.3.2.1"
75     local dummy="icmp and dst host ${dummy_addr} and icmp[icmptype] == icmp-echo"
76     tcpdump -n -p -s 0 -e -U -w $tcpdump_filename -i any "($tcpdump_filter) or ($dummy)" &
77     ctdb_test_exit_hook_add "kill $! >/dev/null 2>&1"
78
79     echo "Waiting for tcpdump output file to be ready..."
80     ping -q "$dummy_addr" >/dev/null 2>&1 &
81     ctdb_test_exit_hook_add "kill $! >/dev/null 2>&1"
82
83     tcpdump_listen_for_dummy ()
84     {
85         tcpdump -n -r $tcpdump_filename -c 1 "$dummy" >/dev/null 2>&1
86     }
87
88     wait_until 10 tcpdump_listen_for_dummy
89 }
90
91 # By default, wait for 1 matching packet.
92 tcpdump_wait ()
93 {
94     local count="${1:-1}"
95     local filter="${2:-${tcpdump_filter}}"
96
97     tcpdump_check ()
98     {
99         local found=$(tcpdump -n -r $tcpdump_filename "$filter" 2>/dev/null | wc -l)
100         [ $found -ge $count ]
101     }
102
103     echo "Waiting for tcpdump to capture some packets..."
104     if ! wait_until 30 tcpdump_check ; then
105         echo "DEBUG AT $(date '+%F %T'):"
106         local i
107         for i in "onnode -q 0 $CTDB status" "netstat -tanp" "tcpdump -n -e -r $tcpdump_filename" ; do
108             echo "$i"
109             $i || true
110         done
111         return 1
112     fi
113 }
114
115 tcpdump_show ()
116 {
117     local filter="${1:-${tcpdump_filter}}"
118
119     tcpdump -n -r $tcpdump_filename  "$filter" 2>/dev/null
120 }
121
122 tcptickle_sniff_start ()
123 {
124     local src="$1"
125     local dst="$2"
126
127     local in="src host ${dst%:*} and tcp src port ${dst##*:} and dst host ${src%:*} and tcp dst port ${src##*:}"
128     local out="src host ${src%:*} and tcp src port ${src##*:} and dst host ${dst%:*} and tcp dst port ${dst##*:}"
129     local tickle_ack="${in} and (tcp[tcpflags] & tcp-ack != 0) and (tcp[14] == 4) and (tcp[15] == 210)" # win == 1234
130     local ack_ack="${out} and (tcp[tcpflags] & tcp-ack != 0)"
131     tcptickle_reset="${in} and tcp[tcpflags] & tcp-rst != 0"
132     local filter="(${tickle_ack}) or (${ack_ack}) or (${tcptickle_reset})"
133
134     tcpdump_start "$filter"
135 }
136
137 tcptickle_sniff_wait_show ()
138 {
139     tcpdump_wait 1 "$tcptickle_reset"
140
141     echo "GOOD: here are some TCP tickle packets:"
142     tcpdump_show
143 }
144
145 gratarp_sniff_start ()
146 {
147     tcpdump_start "arp host ${test_ip}"
148 }
149
150 gratarp_sniff_wait_show ()
151 {
152     tcpdump_wait 2
153
154     echo "GOOD: this should be the some gratuitous ARPs:"
155     tcpdump_show
156 }
157
158
159 ctdb_test_check_real_cluster ()
160 {
161     [ -z "$TEST_LOCAL_DAEMONS" ] || \
162         die "ERROR: This test must be run against a real/virtual cluster, not local daemons."
163
164     local h=$(hostname)
165
166     local i
167     for i in $(onnode -q all hostname) ; do
168         [ "$h" != "$i" ] || \
169             die "ERROR: This test must not be run from a cluster node."
170     done
171 }
172
173 ping_wrapper ()
174 {
175     case "$*" in
176         *:*) ping6 "$@"   ;;
177         *)   ping  "$@"   ;;
178     esac
179 }