A few days ago, I wrote a note detailing how to set up a simple TCP client and server using netcat. Today, I have taken things a step further by capturing packets in Wireshark and providing a step-by-step explanation of how the TCP flow works. In the table below, you can find a general overview of this process.
Flow | Packet captured from Wireshark | Explaination |
---|---|---|
client -[SYN]-> server | Transmission Control Protocol, Src Port: 24491, Dst Port: 5000, Seq: 0, Len: 0 Source Port: 24491 Destination Port: 5000 [Stream index: 0] [TCP Segment Len: 0] Sequence Number: 0 (relative sequence number) Sequence Number (raw): 4126488336 [Next Sequence Number: 1 (relative sequence number)] Acknowledgment Number: 0 Acknowledgment number (raw): 0 1000 …. = Header Length: 32 bytes (8) Flags: 0x002 (SYN) Window: 65535 [Calculated window size: 65535] Checksum: 0xd6b0 [unverified] [Checksum Status: Unverified] Urgent Pointer: 0 |
First, client says “hi there, I’d like to connect, here is my number xxxxxxx36 “ When client send a SYN packet to server. Wireshark will show you the relative sequence, or ACK number which is 0. But actually, it is a random number . |
client <-[SYN,ACK]- server | Transmission Control Protocol, Src Port: 5000, Dst Port: 24491, Seq: 0, Ack: 1, Len: 0 Source Port: 5000 Destination Port: 24491 [Stream index: 0] [TCP Segment Len: 0] Sequence Number: 0 (relative sequence number) Sequence Number (raw): 547479085 [Next Sequence Number: 1 (relative sequence number)] Acknowledgment Number: 1 (relative ack number) Acknowledgment number (raw): 4126488337 1000 …. = Header Length: 32 bytes (8) Flags: 0x012 (SYN, ACK) Window: 65535 [Calculated window size: 65535] Checksum: 0xd7d0 [unverified] [Checksum Status: Unverified] Urgent Pointer: 0 Options: (12 bytes), Maximum segment size, No-Operation (NOP), Window scale, No-Operation (NOP), No-Operation (NOP), SACK permitted [SEQ/ACK analysis] [Timestamps] |
Server responses “oh sure, I’ve received your number xxxxxxx36. And I add one to keep track, so now it is xxxxxxx37. Please take my number xxxxxxx85 “ After received the packet from client, server will send its own Sequence number 547479085 and Ackowledgement number. The Acknowledge number is the client’s Sequence number + 1 which is 4126488337 |
client -[ACK]-> server | Transmission Control Protocol, Src Port: 24491, Dst Port: 5000, Seq: 1, Ack: 1, Len: 0 Source Port: 24491 Destination Port: 5000 [Stream index: 0] [TCP Segment Len: 0] Sequence Number: 1 (relative sequence number) Sequence Number (raw): 4126488337 [Next Sequence Number: 1 (relative sequence number)] Acknowledgment Number: 1 (relative ack number) Acknowledgment number (raw): 547479086 0101 …. = Header Length: 20 bytes (5) Flags: 0x010 (ACK) Window: 10233 [Calculated window size: 2619648] [Window size scaling factor: 256] Checksum: 0xeace [unverified] [Checksum Status: Unverified] Urgent Pointer: 0 [SEQ/ACK analysis] [Timestamps] |
Client responses “I’ve received your number xxxxxxx85. And I add one to keep track, so now it is xxxxxxx86. We are synced” Client verifies receiving packet from the server by sending ACK (acknowledge) message. The ACK number is server’s Squence number + 1, 547479086 |
client -[PSH,ACK]-> server | Transmission Control Protocol, Src Port: 24491, Dst Port: 5000, Seq: 1, Ack: 1, Len: 34 Source Port: 24491 Destination Port: 5000 [Stream index: 0] [TCP Segment Len: 34] Sequence Number: 1 (relative sequence number) Sequence Number (raw): 4126488337 [Next Sequence Number: 35 (relative sequence number)] Acknowledgment Number: 1 (relative ack number) Acknowledgment number (raw): 547479086 0101 …. = Header Length: 20 bytes (5) Flags: 0x018 (PSH, ACK) Window: 10233 [Calculated window size: 2619648] [Window size scaling factor: 256] Checksum: 0xd07d [unverified] [Checksum Status: Unverified] Urgent Pointer: 0 [SEQ/ACK analysis] [Timestamps] TCP payload (34 bytes) Data (34 bytes) |
Now, client starts sending messages with flag PSH meaning “I have packed all the good stuffs, please send it imediately” Also, Next Sequence Number is expected to be 35 because it is sending out 34 bytes payload. ACK number is still 547479086 because it has not received anything from server |
client <-[ACK]- server | Transmission Control Protocol, Src Port: 5000, Dst Port: 24491, Seq: 1, Ack: 35, Len: 0 Source Port: 5000 Destination Port: 24491 [Stream index: 0] [TCP Segment Len: 0] Sequence Number: 1 (relative sequence number) Sequence Number (raw): 547479086 [Next Sequence Number: 1 (relative sequence number)] Acknowledgment Number: 35 (relative ack number) Acknowledgment number (raw): 4126488371 0101 …. = Header Length: 20 bytes (5) Flags: 0x010 (ACK) Window: 10233 [Calculated window size: 2619648] [Window size scaling factor: 256] Checksum: 0xeaac [unverified] [Checksum Status: Unverified] Urgent Pointer: 0 [SEQ/ACK analysis] [Timestamps] |
After receiving the packet, server sends the ACK with previous ACK payload size (34). 4126488337 + 34 = 4126488371 |
client -[FIN,ACK]-> server | Transmission Control Protocol, Src Port: 24491, Dst Port: 5000, Seq: 35, Ack: 1, Len: 0 Source Port: 24491 Destination Port: 5000 [Stream index: 0] [TCP Segment Len: 0] Sequence Number: 35 (relative sequence number) Sequence Number (raw): 4126488371 [Next Sequence Number: 36 (relative sequence number)] Acknowledgment Number: 1 (relative ack number) Acknowledgment number (raw): 547479086 0101 …. = Header Length: 20 bytes (5) Flags: 0x011 (FIN, ACK) Window: 10233 [Calculated window size: 2619648] [Window size scaling factor: 256] Checksum: 0xeaab [unverified] [Checksum Status: Unverified] Urgent Pointer: 0 [Timestamps] |
After sending a note, client terminal is close, so it sends FIN (finish?) and ACK to server. At this time, both Sequence number and ACK number are the same as the above because server did not send anything. |
client <-[ACK]- server | Transmission Control Protocol, Src Port: 5000, Dst Port: 24491, Seq: 1, Ack: 36, Len: 0 Source Port: 5000 Destination Port: 24491 [Stream index: 0] [TCP Segment Len: 0] Sequence Number: 1 (relative sequence number) Sequence Number (raw): 547479086 [Next Sequence Number: 1 (relative sequence number)] Acknowledgment Number: 36 (relative ack number) Acknowledgment number (raw): 4126488372 0101 …. = Header Length: 20 bytes (5) Flags: 0x010 (ACK) Window: 10233 [Calculated window size: 2619648] [Window size scaling factor: 256] Checksum: 0xeaab [unverified] [Checksum Status: Unverified] Urgent Pointer: 0 [SEQ/ACK analysis] [Timestamps] |
After receiving the FIN flag, server response with an ACK message + 1. |
client <-[FIN,ACK]- server | Transmission Control Protocol, Src Port: 5000, Dst Port: 24491, Seq: 1, Ack: 36, Len: 0 Source Port: 5000 Destination Port: 24491 [Stream index: 0] [TCP Segment Len: 0] Sequence Number: 1 (relative sequence number) Sequence Number (raw): 547479086 [Next Sequence Number: 2 (relative sequence number)] Acknowledgment Number: 36 (relative ack number) Acknowledgment number (raw): 4126488372 0101 …. = Header Length: 20 bytes (5) Flags: 0x011 (FIN, ACK) Window: 10233 [Calculated window size: 2619648] [Window size scaling factor: 256] Checksum: 0xeaaa [unverified] [Checksum Status: Unverified] Urgent Pointer: 0 [Timestamps] |
Now, server closes its portal “hey client, I’m done with you”. Notice, Seq, and ACK are the same as above because server has not received anything from client.c |
client -[ACK]- >server | Transmission Control Protocol, Src Port: 24491, Dst Port: 5000, Seq: 36, Ack: 2, Len: 0 Source Port: 24491 Destination Port: 5000 [Stream index: 0] [TCP Segment Len: 0] Sequence Number: 36 (relative sequence number) Sequence Number (raw): 4126488372 [Next Sequence Number: 36 (relative sequence number)] Acknowledgment Number: 2 (relative ack number) Acknowledgment number (raw): 547479087 0101 …. = Header Length: 20 bytes (5) Flags: 0x010 (ACK) Window: 10233 [Calculated window size: 2619648] [Window size scaling factor: 256] Checksum: 0xeaaa [unverified] [Checksum Status: Unverified] Urgent Pointer: 0 [SEQ/ACK analysis] [Timestamps] |
“Okay server, I have received your farewell letter so I will increase the ACK # to one “. Let reverse engineering, Client’s seq:36, in which we know it has sent 1 byte for SYN, 1 byte for FIN, and the rest are the payload. Client’s ack:2 shows us that it received 1 SYN and 1 FIN from server Also, Server’s seq:1 means it has sent 1 byte for SYN, and probally closes. That is why we don’t see the 2 seq. Server’s ack:36 shows that clent sent 1 SYN, 1 FIN, and 34 bytes of payload. |