In this exercise we will capture network traffic with Tcpdump, analyze it with Wireshark and discuss encapsulation in network protocols.
This is exercise 2.2 for the AWS Advanced Networking Specialty training. For an explanation and overview of all exercises, see the overview post.
The exercises are built on the assumption that you’re already familiar with the AWS basics and have achieved at least one associate level AWS certification.
In this exercise we will set up a simple EC2 instance with Amazon Linux. It will be directly connected to an Internet Gateway. On the instance, we will run Tcpdump to capture some network traffic and store it in a PCAP (packet capture) file. Then we will download the file and analyze it with Wireshark.
The goal of this exercise is to get you familliar with Tcpdump and Wireshark, which are essential tools in network engineering. Additionally, we will dive into the workings of network protocol encapsulation, one of the core principles of networking.
Deploy an EC2 instance running Amazon Linux 2, connected directly to an Internet Gateway. You can use the default VPC if you like. Make sure the instance has a public IP address, that the security group allows SSH from your IP, and select a valid key pair. When done, open two SSH sessions in separate terminal windows.
In one of the sessions, execute
sudo tcpdump -nn port 80. Let’s unpack what we’re telling Tcpdump to do:
sudomeans run as root, which is required to capture packets
-nnwill make sure the output displays hostnames as numeric IP addresses (the first n) and the ports as port numbers (the second n)
port 80is the expression that tells tcpdump what to capture. In this case, only traffic to and from port 80.
While the tcpdump command is running in one session, run
curl -I google.com in the other. This will execute a HEAD request on http://google.com. As soon as you press enter, the other screen should explode with information.
Experienced engineers will be able to tell a lot from this output. For example:
10.0.0.179.40364 > 18.104.22.168.80: Flags [S]means IP address 10.0.0.179 is using port 40364 to send a frame to IP 22.214.171.124 on port 80, and the SYN flag is set.
126.96.36.199.80 > 10.0.0.179.40364: Flags [S.]means remote IP address is responding on the same ports, and the SYN and ACK flags are set.
Not entirely coincidently, these are the two first steps of the TCP Three-Way Handshake which we’ll talk more about later.
The most important takeaway from the output above is that bidirectional communication is functioning correctly. For example, if a NACL would be blocking return traffic we would see outbound traffic, but no responses from the remote server. This can help to quickly localize issues on the network.
The point of this part of the exercise is to show you that Tcpdump can very easily show you some usable information, but it’s hard to drill down into the details. If the output would be much more verbose (which it easily could!) it would very quickly become impossible to find relevant info.
Capture to file and open with Wireshark
To make the output of Tcpdump more usable, we will not use stdout to analyse the traffic. Instead we will dump the output to a PCAP file and download that to our local machine.
Note: Wireshark is perfectly capable of capturing packets itself. However, it comes with a GUI so you need a Windows or Linux desktop to run it. Most EC2 instances run a shell-only version of Linux, which is why we’re capturing data with Tcpdump.
If your previous capture is still running, cancel it with ctrl-c. Then execute the following command:
sudo tcpdump port 80 -w my_capture.pcap. This does almost the same as the previous command, but writes the captured packages to a file named my_capture.pcap.
In the other window, run
curl -I google.com again. Then stop the tcpdump recording with ctrl-c. Execute
ls -la my_capture.pcap to verify that the file has been created.
Download the file to your local machine by executing
scp firstname.lastname@example.org:~/my_capture.pcap ~/Desktop (on Mac or Linux, replace with something equivalent or use a GUI on Windows).
Download and install Wireshark and open the file you just downloaded. The result should look like this:
Data encapsulation in TCP/IP
Before we continue with Wireshark, let’s talk about data encapsulation. When an application transmits data to another device (like we did with our
curl command), the data moves through a number of layers.
By en:User:Kbrose - Prior Wikipedia artwork by en:User:Cburnett, CC BY-SA 3.0, https://commons.wikimedia.org/w/index.php?curid=1831900
Data moving from one application to another follows these steps:
- The application layer sends the data to the transport layer
- The transport layer adds additional data (the TCP header)
- The transport layer sends the data to the internet layer
- The internet layer adds additional data (the IP header)
- The internet layer sends the data to the link layer
- The link layer adds additional data (the Ethernet header)
- The link layer sends the data to the physical layer
On the receiving end, the host receives a frame from the physical layer. Then:
- The link layer reads and removes the Ethernet header
- The link layer sends the data to the internet layer
- The internet layer reads and removes the IP header
- The internet layer sends the data to the transport layer
- The transport layer reads and removes the TCP header
- The transport layer sends the data to the application layer
- The application layer reads and processes the data
This process of adding and stripping data is called encapsulation, because each data unit is encapsulated, or wrapped, with additional data. To visualize this:
In the capture above (you can download the PCAP here), we see ten packets being exchanged. The first three are the TCP establishment handshake, the next three are data exchange, and the final four are TCP termination handshake.
This shows us what is called ‘TCP overhead’. We only want to send one packet to a server and receive one packet back, but we need to send a total of ten packets to make it work.
Let’s look at the first frame being sent. Click the first line in the top section and select the line that says
Frame 1: 74 bytes on wire (592 bits), 74 bytes captured (592 bits) in the middle section. This will select the entire frame, including all layers. As it says, this frame is 74 bytes in size.
Now select the bottom line, which is the TCP data. This is the actual request sent by the TCP layer, before the IP and Ethernet headers have been added. This section consists of 40 bytes.
Click the IP and Ethernet sections to see their values and size. When you fold open any of these sections, you can select a field to see exactly which values are being sent. For an explanation of these values, see TCP segment structure, IP Header Format and Ethernet II framing .
Now let’s look at the fourth frame: the HTTP request. We will go through the headers on by one, starting with the HTTP protocol itself.
Select the bottom line in the middle section and fold it open. In the request, you can see that all the application ‘knows’ is that it wants to connect to google.com. In this example, the HTTP data is 75 bytes in size.
The TCP header is between 20 and 60 bytes in size (depending on the amount of optional values). In the case of this HTTP request, it adds 32 bytes of information to the frame. This consists of information about the source (local) port, the destination (remote) port and some additional values regarding sequences and checksums.
The IP header adds information about the IP version (IPv4 or IPv6), the IP addresses, the inner protocol (TCP) and some additional values to the frame.
What’s interesting to realize here is that regardless of the IP version, the structure of anything below this header (TCP and HTTP) will be the same for any HTTP/1 request.
The last header to be added is Ethernet. This only adds three fields: the destination MAC address, the source MAC address and the EtherType, which is IPv4 in our example.
The receiving end of this frame will first look at the outer layer (Ethernet). As we saw in the previous chapter, this header has an EtherType field, which will tell the next layer (the internet layer) how to read the next header.
In our case this is an IPv4 header, so the internet layer parses it according to the IPv4 protocol. In the IPv4 header, it will find the Internet Header Length (IHL) field, which will tell it exactly how long the IPv4 header is and where the next part starts. It also reads the Protocol field to know that the next part is in TCP format.
The transport layer then receives the HTTP data with the TCP header, and through the destination port it knows to send the data to the webserver application.
The webserver receives the HTTP request, and will process it according to its contents.
Through a lot of theory and some hands-on experience, we’ve shown how an application sends and receives data over the TCP/IP stack. With Tcpdump and Wireshark we have been able to almost ‘touch’ the packets and frames as they traverse the networks.
This should give us a good grasp of how encapsulation works, which we will need later, when we’re looking at VPNs, VLANs and QinQ.