-
Notifications
You must be signed in to change notification settings - Fork 18
/
Copy pathfailed-connection-attempts.sh
executable file
·418 lines (341 loc) · 17.1 KB
/
failed-connection-attempts.sh
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
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
#!/bin/bash
# find failed connection attempts.sh begins on the previous line
#
# This macro searchs a packet trace looking for connection attempts that
# failed.
# Output is a table of failed connection attempts. The first column is the
# TCP stream number followed by the server-ip:server-port and
# client-ip:client-port. The 4th coloumn is an indicator of why the stream
# made it into the table.
# RST - first response from the server is a ReSeT without ACKing any
# data
# CHA - first response from the server is a CHAllenge ACK
# IMC - server just accepts and then IMmediately Closes the connection
# with a FIN. Note there are two versions of this IMC if the
# determination is made by looking at the Server's segments and
# imc (lower case) if the determination is made by looking at the
# client's segments.
# SYN - the only response from the server is an ACK-SYN
# SaR - server sends both and only ACK-SYNs and resets
# NOS - there are NO tcp Segments from the server
# CLR - The server responds with an ACK-SYN but then the CLient sends
# a Reset or an ACK and then a reset
# CIC - Client Immediatelty Closes the connection with a FIN after
# the Server's ACK-SYN
# MAR - short for martian, if we get to this point there is a hole
# in the algorithm since its not determined to be a good
# connection and its not one of the above failures
# The presence or absense of an ACK-SYN is not enough to determine if a
# connect attempt succeeded or not. It is possible that the ACK-SYN is not
# captured for some reason. Also if the listen backlog is filled it is
# possible that server will send a ACK-SYNs but then still not complete the
# 3-way-handshake and continue to retransmit ACK-SYNs. You also cannot just
# look for retransmitted SYNs. First a SYN may be retransmitted multiple
# times before being accepted. Second, if the server responds with an ICMP
# destination unreachable or a reset the SYN may not be retransmitted.
# Also if the server responds with a challenge ACK instead of a ACK-SYN the
# client can send its own reset.
# You can monitor the progress of the script by looking at
# /tmp/failed-connection-attempts-4. As each stream number with a SYN is
# processed the number is written to the -4 file.
# tail -f /tmp/failed-connection-attempts-4 2>/dev/null
# is your friend. Note that if its a large file with just a few connection
# attempts -4 may not update very fast.
# Version 1.0 April 2, 2017
# Version 1.1 April 3, 2017
# Added scenario 7
# Version 1.2 April 9, 2017
# Added labels to each TCP stream number indicating the scenario.
# Version 1.3 April 11, 2017
# fixed bug that incorrectly identified valid connections as scenario 7
# if there were more than 999 bytes ACKed by server.
# Version 1.4 April 13, 2017
# Redid the internal logic, added scenario 8 and removed the "suspected"
# list
# Version 1.5 April 14, 2017
# Added scenario 9 and 10 added the suspected list back
# Version 2.0 April 16, 2017
# Completelty rewritten, removed the scenarios in favor of a simpler approach
# and removed the suspected list (again).
# Version 2.1 August 22, 2017
# Added the server:port client:port columns to the output
# Version 2.2 September 10, 2017
# Added CLR test
# Version 2.3 October 1, 2017
# Added a check for the case where the server's 1 data packet is missing but
# but the client ACKs it so we know its a good. This was previsouly
# incorrectly flagged as SYN. Also the case where no server packets are
# captured but the client is ACKing data. This was previsouly incorrectly
# flagged as NOS.
# Version 2.4 Decemeber 12, 2017
# Added the CIC and MAR flags, also reworked algorthim to hopefully make
# it faster.
# Version 2.5 January 4, 2018
# Added a check right at the start for a client segment with seq and ack
# numbers > 2 and the reset flag == 0. This indicates a good connection.
# Should speed up processing and also correctly identify the case where
# where the only captured server side segment is the SYN-ACK but the client
# is ACKing segments that the trace does not see. It also catches the case
# where the first server response is a challenge ACK but the client tries
# again instead of sending a reset and the connection completes.
# Version 2.6 January 10, 2016
# Changed that first client segment check to check is ACK and SEQ > 2 and
# the ACK flag is set, I droped the reset flag must not be set.
# Version 2.7 February 6, 2018
# Fixed false positive where client and server both send data but do not ACK
# the data -- there may be an issue with the connection BUT the connection
# attemp succeeded OK.
# Version 2.8 March 28, 2018
# Fixed typos in comments. Corrected false CLR when client sends a SYN
# followed by reset but server never sends anything, should be NOS not CLR
# Version 2.9 April 8, 2018
# Fixed failure to correctly recognize when the server responses with just
# a reset. Added the SaR failure scenario when the server sends both SYN-ACKs
# and resets but only SYN-ACKs and resets.
FAILEDCONNECTIONATTEMPTSVERSION="2.9_2018-04-08"
# from https://github.com/noahdavids/packet-analysis.git
# Copyright (C) 2017 Noah Davids
# This program is free software: you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the Free
# Software Foundation, version 3, https://www.gnu.org/licenses/gpl-3.0.html
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
if [ $# -lt 1 -o $# -gt 2 ]
then echo "Usage:"
echo " failed-connection-attempts.sh FILE [ FILTER ]"
echo " FILE is the name of the trace file"
echo " FILTER is an optional tshark filter, it will be ANDed"
echo " tcp && not icmp"
fi
# just making sure that the file exists.
if [ ! -e "$1" ]
then echo "Could not find input file $1"
exit
fi
FILE=$1
# echo the command line to confirm the arguments
if [ $# -eq 2 ]
then
echo "failed-connection-attempts.sh $FILE \"$2\" "
else
echo "failed-connection-attempts.sh $FILE"
fi
# Figure out if we can use "-Y" as the display filter argument or we need
# "-R". Basically look at the help output and if we do not find the "-Y"
# we use "-R"
DASH="-Y"
if [ $(tshark -help | egrep "\-Y <display filter>" | wc -l) -eq 0 ]
then DASH="-R"
fi
# Call tshark writing the TCP stream number, source and destination IP
# addresses and ports, all the flags the ACK number and the TCP length.
# and sequence number. Enclose the stream value in "_" characters so that
# so when we match on stream 10 we do not also select streams 110, 210,
# 310, etc. Write everything out to the temporary file
# /tmp/fail-connection-attempts-1.
#
# The not icmp is to make sure we aren't confused by an ICMP response
# from the server.
if [ $# -eq 2 ]
then
tshark -r "$FILE" $DASH "tcp && not icmp && ($2)" -T fields \
-e tcp.stream -e ip.src -e ip.dst -e tcp.srcport -e tcp.dstport \
-e tcp.flags.ack -e tcp.flags.push -e tcp.flags.reset \
-e tcp.flags.syn -e tcp.flags.fin -e tcp.ack -e tcp.len -e tcp.seq \
-o tcp.relative_sequence_numbers:TRUE 2>/dev/null | \
awk '{print "_" $1 "_ " $2 " " $3 " " $4 " " $5 " " $6 " " $7 " " $8 \
" " $9 " " $10 " " $11 " " $12 " " $13}' \
> /tmp/failed-connection-attempts-1
else
tshark -r "$FILE" $DASH "tcp && not icmp" -T fields \
-e tcp.stream -e ip.src -e ip.dst -e tcp.srcport -e tcp.dstport \
-e tcp.flags.ack -e tcp.flags.push -e tcp.flags.reset \
-e tcp.flags.syn -e tcp.flags.fin -e tcp.ack -e tcp.len -e tcp.seq \
-o tcp.relative_sequence_numbers:TRUE 2>/dev/null | \
awk '{print "_" $1 "_ " $2 " " $3 " " $4 " " $5 " " $6 " " $7 " " $8 \
" " $9 " " $10 " " $11 " " $12 " " $13}' \
> /tmp/failed-connection-attempts-1
fi
# If the output file doesn't exist or is empty report that an exit
if [ ! -e /tmp/failed-connection-attempts-1 ]
then echo "tshark did not find any packets - exiting"
exit
fi
if [ $(head -1 /tmp/failed-connection-attempts-1 | wc -l) -eq 0 ]
then echo "tshark did not find any packets - exiting"
exit
fi
# initialize the LASTSTREAM variable and clear out the temporary file used to
# accumulate the failed connection attempts
LASTSTREAM=-1
echo -n "" > /tmp/failed-connection-attempts-3
echo -n "" > /tmp/failed-connection-attempts-4
# Find segments where the SYN flag is set and the ACK flag is not.
cat /tmp/failed-connection-attempts-1 | \
while read stream client server cport sport ack push reset \
syn fin ackno tcplen seqno
do
if [ "$ack" == 0 -a "$syn" == 1 ]
then echo $stream >> /dev/null
else continue
fi
# record the stream number so we do not process the same stream again. Also
# send it to -4 so we can know what the script is doing.
CURRENTSTREAM=$(echo $stream | tr "_" " ")
if [ $CURRENTSTREAM -le $LASTSTREAM ]
then continue
fi
echo $CURRENTSTREAM > /tmp/failed-connection-attempts-4
LASTSTREAM=$CURRENTSTREAM
# Find the first 200 segments for that stream and then separate into server
# sourced and client sourced segments. Yes, 200 is an arbitrary number but if
# we cannot figure out it out after 200 segments we have a bigger problem and
# yes 200 is probably over kill but I wanted to be sure.
grep -E "$stream" -m 200 /tmp/failed-connection-attempts-1 > \
/tmp/failed-connection-attempts-1a
grep -E "$stream $server $client $sport $cport" \
/tmp/failed-connection-attempts-1a > /tmp/failed-connection-attempts-2s
grep -E "$stream $client $server $cport $sport" \
/tmp/failed-connection-attempts-1a > /tmp/failed-connection-attempts-2c
# If a client side segment has sequence and ACK numbers > 2 and the ACK
# flag is set we know this is a good connection so just continue
if [ $(awk '($11 > 2 && $13 > 2 && $6 == 1) {print $0}' \
/tmp/failed-connection-attempts-2c | wc -l) -gt 0 ]
then continue
fi
# If there are server sourced segments
if [ $(cat /tmp/failed-connection-attempts-2s | wc -l) -gt 0 ]
then
# If the only Server segments are ACK-SYNs or just ACKs with an ACK of 1
# and no data is sent it is either a SYN or CLR scenario. Check the
# client side, if there is a reset with a sequence number of 1 its a CLR
# else its a SYN. Note if th eserver sent data $12 > 0 it thinks there is
# a good connection so we do too.
if [ $(awk '(!(($6 == 1 && $7 == 0 && $8 == 0 && $9 == 1) || \
($6 == 1 && $7 == 0 && $8 == 0 && $9 == 0 && $11 == 1)) || \
($12 > 0)) {print $0}' /tmp/failed-connection-attempts-2s | \
wc -l) -eq 0 ]
then if [ $(awk '(($8 == 1) && ($13 == 1)) {print $0}' \
/tmp/failed-connection-attempts-2c| wc -l) -gt 0 ]
then echo $stream $server:$sport $client:$cport "CLR" | \
tr "_" " " >> /tmp/failed-connection-attempts-3
else echo $stream $server:$sport $client:$cport "SYN" | \
tr "_" " " >> /tmp/failed-connection-attempts-3
fi
continue
fi
# If the first segment has the ACK flag is set and the RST, SYN and FIN
# flags are not set and the ACK number > 65535, it is probably
# (99.9984741% (1-65535÷4294967295)) a challenge ACK so mark it as failed
if [ $(head -1 /tmp/failed-connection-attempts-2s | \
awk '($6 == 1 && $8 == 0 && $9 == 0 && $10 == 0 && \
$11 > 65535) {print $0}' \
| wc -l) -gt 0 ]
then echo $stream $server:$sport $client:$cport "CHA" | \
tr "_" " " >> /tmp/failed-connection-attempts-3
continue
fi
# If we have a server segment with either the PUSH flag set or data,
# or it is ACKing data from client (something more than a FIN) treat it
# as a good connection
if [ $(awk '(($7 == 1) || ($11 > 2) || ($12 > 0)) {print $0}' \
/tmp/failed-connection-attempts-2s | wc -l) -gt 0 ]
then continue
fi
# If the only server segments are resets without an ACK or an ACK of 1
if [ $(grep -v "$cport 0 0 1 0 0 0" /tmp/failed-connection-attempts-2s \
| grep -v "$cport 1 0 1 0 0 1" | wc -l) -eq 0 ]
then echo $stream $server:$sport $client:$cport "RST" | \
tr "_" " " >> /tmp/failed-connection-attempts-3
continue
fi
# If the only server segments are ACK-SYNS and resets without an ACK or an
# ACK of 1
if [ $(grep -v "$cport 1 0 0 1 0" /tmp/failed-connection-attempts-2s \
| grep -v "$cport 0 0 1 0 0 0" | grep -v "$cport 1 0 1 0 0 1" \
| wc -l) -eq 0 ]
then echo $stream $server:$sport $client:$cport "SaR" | \
tr "_" " " >> /tmp/failed-connection-attempts-3
continue
fi
# At this point we only care about the first non-SYN packet from the server
grep -E "$stream $server $client $sport $cport . . . 0" -m 1 \
/tmp/failed-connection-attempts-1a > \
/tmp/failed-connection-attempts-2s
# FIN flag is set and the ACK number == 1 so server closed the connection
# without accepting any data so make this as failed
if [ $(awk '($10 == 1 && $11 == 1 && $12 == 0) {print $0}' \
/tmp/failed-connection-attempts-2s | wc -l) -gt 0 ]
then echo $stream $server:$sport $client:$cport "IMC" | \
tr "_" " " >> /tmp/failed-connection-attempts-3
continue
fi
fi
# If we are here then either the server sent no segments or all the above
# tests failed. Lets look at the client's packets
# Client did send something besides a SYN, could be a FIN, reset, or data or
# ACK of data
if [ $(cat /tmp/failed-connection-attempts-2c | wc -l) -gt 0 ]
then
# If there are any segments (from client) with an ACK > 2 or with TCP data
# we have a good connection
if [ $(awk '($11 > 2 || $12 > 0) {print $0}' \
/tmp/failed-connection-attempts-2c | wc -l) -gt 0 ]
then continue
fi
# Did the client send a FIN with an ACK of 1 indicating that it closed
# the connection immediately
if [ $(awk '($10 == 1 && $11 == 1) {print $0}' \
/tmp/failed-connection-attempts-2c | wc -l) -gt 0 ]
then echo $stream $server:$sport $client:$cport \
"CIC" | tr "_" " " >> /tmp/failed-connection-attempts-3
continue
fi
# Did the client send a FIN with an ACK of 2 indicating that it closed
# the connection in response to an immediate FIN from the server. Keep
# in mind that we are only here if the client never sent any data so
# the only reason for a FIN with an ACK of 2 is that neither side sent
# any data and the server sent an immediate FIN. We should have spotted
# this already but only if the server didn't send an ACK before the FIN.
# I flag this with a lower case IMC so I can tell the difference.
if [ $(awk '($10 == 1 && $11 == 2) {print $0}' \
/tmp/failed-connection-attempts-2c | wc -l) -gt 0 ]
then echo $stream $server:$sport $client:$cport \
"imc" | tr "_" " " >> /tmp/failed-connection-attempts-3
continue
fi
# If the client sent a reset and did not send data (sequence# == 1) or ACKed
# data (ACK# == 0 or 1, I have seen both scenarios depending on client) then
# this is a no segments from the server
if [ $(awk '($8 == 1 && $11 < 2 && $13 == 1) {print $0}' \
/tmp/failed-connection-attempts-2c | wc -l) -gt 0 ]
then echo $stream $server:$sport $client:$cport \
"NOS" | tr "_" " " >> /tmp/failed-connection-attempts-3
continue
fi
# If the client sent a reset but sent data (sequence# > 1) or ACKed data
# this is not a failed connection
if [ $(awk '($8 == 1 && $11 > 1 && $13 > 1) {print $0}' \
/tmp/failed-connection-attempts-2c | wc -l) -gt 0 ]
then continue
fi
fi
# If we are here either the trace file has no segments (of any type from
# the server or all of the above tests failed. Double check there are
# no segments from the server. Assuming there are none flag the connection
# as NOS. If there are flag it as MAR since we should be there.
if [ $(grep -E "$stream $server $client $sport $cport" \
/tmp/failed-connection-attempts-1a | wc -l) -eq 0 ]
then echo $stream $server:$sport $client:$cport \
"NOS" | tr "_" " " >> /tmp/failed-connection-attempts-3
else echo $stream $server:$sport $client:$cport \
"MAR" | tr "_" " " >> /tmp/failed-connection-attempts-3
fi
done
# output the results
if [ $(head -1 /tmp/failed-connection-attempts-3 | wc -l) -eq 0 ]
then echo No failed connection attempts found
else cat /tmp/failed-connection-attempts-3 | column -t
fi