TCP handshake
Introduction
This articles will be about two important networking protocols; TCP and UDP. I will try to make it concise, given the amount of information that there is related to these two particular protocols. I will try to approach this subject in a graphical way, trying to appeal to your love for pretty sketches.
Prerequisite
- Pyton 3.
- Wireshark or any other packet sniffer, choose one that you know how to use it.
I will be using python for simplicity, but this can be achieved with any other programming language of your choice.
What is a protocol?
Well, a protocol is a standard set of rules that allow the communication between electronic devices. So at the end, TCP is just a set of rules that is used by electronic devices to communicate between each other. Let’s see some of these rules.
Description of TCP handshake
Establishing connection
Suppose we have two parts, and one is trying to reach out the other one using the rules of TCP, how could we achieve that? If you’ve read some information about TCP, then I’m sure you’ve read that
A TCP connection uses a three-way handshake to introduce both parts on the conversation…
Or something similar to that, right? Let’s call one part the client, which is the node or part that start the communication, while the other node will be called server. Now, when the client try to start the conversation, he first sends a SYN flag to the server. If you are a curious person I’m sure you wonder what information goes on this first packet, so let’s find out.
In order to be able to reproduce this situation, a simple TCP connection, I’m going to create an extremely simple server and client with Python using the socket library, which is part of the Pyton Standard Library so just having Pyton is good enough.
# server.py
import socket
def main():
# creating the socket
sck = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# binding the socket to the port 7456
# notice that bind() take a tuple as argument
sck.bind(('localhost', 7456))
# now is time to say, I'm ready for connection OS, could you let me please?
# the 1 specified how many connection it will queue up, until
# start rejecting attempts of connections.
sck.listen(1)
print("Hey you I'm listening on 7456...weird port by the way")
# accepting the incoming connection
(client_sock, address) = sck.accept()
while True:
# 1024 is a magic number used on every networking tutorial out there
# so here I also make use of it. Also in this case means that the socket
# will process up to 1024 bytes of the incoming message from the client
msg = client_sock.recv(1024)
if not msg:
break
print(f"FROM: {address} MSG: {msg}")
print()
# good bye socket
client_sock.close()
if __name__ == "__main__":
main()
This is more comments than code itself, so don’t freak out. This is the part corresponding to the server.py
file, nothing fancy here, we create the socket, bind the socket, etc… read the comments. Now for the client.py
:
# client.py
import socket
def main():
# creating the socket
sck = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# just connecting
sck.connect(("localhost", 7456))
print("Sending data...")
sck.sendall(b"Hola server, are you bored?")
# I don't care about your response server, I'm closing
sck.close()
if __name__ == "__main__":
main()
Even simpler, the client just send one message to the server, a pretty silly message but a message we don’t need to be serious now.
The idea is to reproduce the situation as follows:
Open Wireshark, you may need to use
sudo
command in order to be able to sniff a network interface.Given that the traffic that we want to sniff it is only local, we will be sniffing the loopback interface, here is a photo just in case.
We need to filter the traffic, given that we are using TCP on port 7456, so
tcp.port == 7456
would be an appropriate filter for our case.Now we are good to go, start the script with the server code. If you take a look at Wireshark right now, it won’t be any traffic given that the client haven’t tried to connect.
python server.py
Run the client script,
python client.py
Now you should see something like this,
First SYN packet
If you look back, all this was done with the idea of looking at the first SYN packet sent by the client, right? Now let’s look at it. If you give click on this first packet, Wireshark will show you all the info related to it, and let me tell you it’s a lot. In order to simplify the analysis let’s focus on Sequence number, Acknowledge number, Flags and Window size value.
Sequence number: Is a number identifying a TCP segment, this is used to ensure that part of the data is not missed. It is like a way to keep track of the order in which the packets were sent.
Acknowledge number: The sequence number that is expected in the next packet from the other device.
Flags: Used to identify the type of TCP packet that is been transmitted.
Window size: The size of the TCP receiver buffer in bytes. This is a really tricky one, I didn’t get it at first, I actually had a hard time trying to understand it. So I use the master of knowledge(Google or any other search engine), and found this question, Window Size and ACK
The Window Size(that the Receiver sets) is a hard limit on how many bytes the Sender can send without being forced to stop to wait for an acknowledgement.
I recommend you to read the whole question, because it clarifies some misunderstanding related to the Window size.
All this is handled by the library that you are using, so you won’t need to handle this by yourself. So this first SYN packet sent by the client to the server, act like a simple presentation
SYN, ACK by the server
In response to this SYN the server respond with a SYN, ACK packet. If you take a look at the same info mentioned before, you will notice that in this case the Flags Syn and Acknowledgement were marked as set
The server say, “ok I saw you, this is my Sequence number(Seq), and I expect this sequence number from you(Ack)”
ACK from client
This is the last part of the handshake, in this part the client reply with its current Seq which is the previous plus one, and also include the expected sequence number from the server(Ack).
Conclusion
Understanding a protocol is not an easy task, even here we try to simplify this task to the most, focusing only on the connection of the two parts and analyzing the packets involved on this connection. Still knowing the ins and outs of the protocol worth it. Next time I will try to to the same with UDP.
Until the next time folks :wave:.
Bibliography
- Practical packet analysis, third edition by Chris Sanders.
- Network Programming with Go Learn to Code Secure and Reliable Network Services from Scratch by Adam Woodbeck.
- Socket Programming HOWTO. Release 3.7.3rc1. From the Python Standard Library documentation.
- Window size and ACK.
- Loopback Ubuntu.
- TCP in a nutshell.