Capture a TCP connection from SYN to TIME_WAIT and read every number
LinuxCore
Tasks
- Capture every segment of one HTTP request between PC1 and SRV1 with absolute sequence numbers.
- Identify the options each side announced in the handshake.
- Check the sequence and acknowledgment arithmetic for the request, the response and the close.
- Find out which side closed first and show its TIME_WAIT socket with the remaining timer.
- Read the listen queue of nginx on SRV1.
Solution
1Start the capture on SRV1SRV1
SRV1 on Linux sudo tcpdump -ni eth0 -S 'tcp port 80 and host 10.0.0.10'-nskips name lookups,-Sprints absolute sequence numbers instead of relative ones, so the arithmetic is visible on every line.2Make one request from PC1PC1
PC1 on Linux curl -s -o /dev/null -w '%{http_code}\n' http://10.0.0.20/curl prints
200, closes the connection and exits.3Look for TIME_WAIT on the clientPC1
PC1 on Linux ss -tano state time-wait '( dport = :80 )'-oadds timer information. With a single-state filter, ss leaves out the State column.4Read the listening socket on the serverSRV1
SRV1 on Linux ss -lnt '( sport = :80 )'For a LISTEN socket, Recv-Q is the number of connections waiting for accept() and Send-Q is the backlog limit.
Verify
SRV1# sudo tcpdump -ni eth0 -S 'tcp port 80 and host 10.0.0.10'
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on eth0, link-type EN10MB (Ethernet), snapshot length 262144 bytes
14:02:11.401223 IP 10.0.0.10.51862 > 10.0.0.20.80: Flags [S], seq 2864012710, win 64240, options [mss 1460,sackOK,TS val 3071459120 ecr 0,nop,wscale 7], length 0
14:02:11.401260 IP 10.0.0.20.80 > 10.0.0.10.51862: Flags [S.], seq 1093385227, ack 2864012711, win 65160, options [mss 1460,sackOK,TS val 2290115532 ecr 3071459120,nop,wscale 7], length 0
14:02:11.401498 IP 10.0.0.10.51862 > 10.0.0.20.80: Flags [.], ack 1093385228, win 502, options [nop,nop,TS val 3071459121 ecr 2290115532], length 0
14:02:11.401577 IP 10.0.0.10.51862 > 10.0.0.20.80: Flags [P.], seq 2864012711:2864012783, ack 1093385228, win 502, options [nop,nop,TS val 3071459121 ecr 2290115532], length 72: HTTP: GET / HTTP/1.1
14:02:11.401802 IP 10.0.0.20.80 > 10.0.0.10.51862: Flags [P.], seq 1093385228:1093386080, ack 2864012783, win 509, options [nop,nop,TS val 2290115533 ecr 3071459121], length 852: HTTP: HTTP/1.1 200 OK
14:02:11.402011 IP 10.0.0.10.51862 > 10.0.0.20.80: Flags [.], ack 1093386080, win 501, options [nop,nop,TS val 3071459122 ecr 2290115533], length 0
14:02:11.402264 IP 10.0.0.10.51862 > 10.0.0.20.80: Flags [F.], seq 2864012783, ack 1093386080, win 501, options [nop,nop,TS val 3071459122 ecr 2290115533], length 0
14:02:11.402371 IP 10.0.0.20.80 > 10.0.0.10.51862: Flags [F.], seq 1093386080, ack 2864012784, win 509, options [nop,nop,TS val 2290115533 ecr 3071459122], length 0
14:02:11.402533 IP 10.0.0.10.51862 > 10.0.0.20.80: Flags [.], ack 1093386081, win 501, options [nop,nop,TS val 3071459123 ecr 2290115533], length 0- Handshake: both sides announce MSS 1460, SACK, timestamps and window scale 7. The SYN-ACK acknowledges 2864012711, the client ISN plus one; the client's ACK is the server ISN plus one.
- Request: 72 bytes from 2864012711 to 2864012782, so the next byte is 2864012783, which is what the server acknowledges.
- Response: 852 bytes from 1093385228; the client acknowledges 1093386080.
- Close: the client sends FIN first at seq 2864012783. The server's FIN carries the ACK for it (2864012784), so the close takes three segments. The client's last ACK is 1093386081.
win 502after the handshake is the raw field: 502 x 128 = 64,256 bytes.
PC1# ss -tano state time-wait '( dport = :80 )'
Recv-Q Send-Q Local Address:Port Peer Address:Port Process
0 0 10.0.0.10:51862 10.0.0.20:80 timer:(timewait,57sec,0)PC1 sent the first FIN, so PC1 holds TIME_WAIT. The timer counts down from 60 seconds, Linux's fixed TIME_WAIT length. SRV1 has no entry for this connection any more.
SRV1# ss -lnt '( sport = :80 )'
State Recv-Q Send-Q Local Address:Port Peer Address:Port Process
LISTEN 0 511 0.0.0.0:80 0.0.0.0:*
LISTEN 0 511 [::]:80 [::]:*nginx listens with a backlog of 511 on IPv4 and IPv6. Recv-Q 0 means no completed connections are waiting for nginx to accept them.
Mistakes people make
- Reading relative sequence numbers (starting at 0 or 1) and quoting them as the real ISN. Use
-Sin tcpdump or turn off relative numbers in Wireshark. - Adding 1 to the sequence number for a pure ACK. Only SYN, FIN and data bytes consume sequence numbers.
- Expecting TIME_WAIT on the server. It sits on whichever side sends the first FIN, here the client.
- Treating
win 502as 502 bytes. Multiply by the window scale agreed in the handshake.
On other platforms
A router can show its own TCP sessions (SSH, BGP), not transit traffic.
R1# show tcp brief
R1# show tcp brief allSay it in the interview
"I captured with absolute sequence numbers so I could check the arithmetic. The SYN and SYN-ACK carry MSS, SACK, timestamps and window scale, each acknowledged as ISN plus one. The 72-byte request moves the client's sequence by 72, the server acknowledges the next byte, and the FINs each consume one number. The client closed first, so the TIME_WAIT socket with its 60-second timer is on the client."