Wireshark Introduction
“Packets don't lie.” ― Laura Chappell
Warning! Be sure to get the appropriate system administrator’s permission before using any of these tools! You have been advised!
Wireshark is a tool I’ve used for decades to debug network programs. It used to be called Ethereal and you can learn all about it at Wikipedia. It is a packet analyzer which is a tool I first learned about in the 1990s when my company password was sniffed off an unencrypted Telnet session. Since then I have striven to always encrypt my communications with tools such as Secure Shell.
This was done on a Windows 11 machine with Wireshark version 4.2.3.
Avoid the temptation to be frustrated if you don’t get this all at once. I myself am still learning about computer network protocols!
First Steps
See: Setup and Build Instructions in the Wireshark online documentation.
After installation, the first screen of Wireshark should look something like this:
There may be more or less info on your screen depending on your network configuration. I will select the interface on my machine I wish to analyze. Your selection will depend on what network interface you wish to look at.
With no filter your screen should fill up fast if you are connected to the Internet! You should see something like this:
Some details about this frame are:
1. Ethernet II Header:
Source MAC address: 2c:16:db:a0:6a:41
Destination MAC Address: 58:60:d8:7e:f4:40
2. IPv4 Header:
Source IP Address: 192.168.1.150
Destination IP Address: 67.222.250.2
Protocol: Transmission Control Protocol (TCP)
Total Length: 1500 bytes
010. .... = Flags: 0x2, Don't fragment
Time to Live: 128
3. TCP Segment:
Source Port: 22958
Destination Port: 4287
Sequence Number: 619767 (see: Understanding TCP Sequence Number with Examples)
Acknowledgment Number: 1
Flags: ACK (Acknowledgment)
Understanding TCP Seq & Ack Numbers [Packet-by-Packet]Data Length: 1460 bytes
[Conversation completeness: Incomplete (12)]
..0. .... = RST: Absent
networking - What causes a TCP/IP reset (RST) flag to be sent?...0 .... = FIN: Absent
What is TCP FIN PACKET? - IP With Ease.... 1... = Data: Present
.... .1.. = ACK: Present
TCP Sequence and Acknowledgement Numbers Explained – MadPackets.... ..0. = SYN-ACK: Absent
TCP 3-Way Handshake (SYN, SYN-ACK,ACK) (guru99.com).... ...0 = SYN: Absent
Understanding TCP Flags SYN ACK RST FIN URG PSH - howtouselinux[Completeness Flags: ··DA··]
Using Wireshark's TCP Conversation Completeness (chappell-university.com)
This packet represents a TCP acknowledgment (ACK) from your local IP address (192.168.1.150) to the destination IP address (67.222.250.2) on port 4287. The sequence number indicates the relative position of this segment in the stream.
Another PDU (see: Understanding PDU at Every TCP/IP Layer: A Comprehensive Guide - Cyber Insight) relevant to this frame (because it is fragmented) is frame 13. Packet fragmentation is outside the scope of this article but you can learn more about it here IP fragmentation - Wikipedia.
Again, there is not time to get into the nitty gritty details of the frame or packet, but there are resources on the Internet you can study including my blog post on network sockets: https://www.keypuncher.net/blog/network-sockets
An Example Analysis:
Why don’t we stop drowning ourselves in traffic and implement some filtering? For that we are going to need some actual traffic to filter on.
Here keypuncher/C++/Networking/httpSocket/crossPlatform you can find my cross platform — Winsock for Windows or Berkeley sockets for Linux — library for setting up and tearing down a simple Hypertext Transfer Protocol (HTTP) socket. Code provided includes the socket code and the Makefile. The below sample Wireshark capture is included as file httpCapExamleDotCom.pcapng as well.
Put the following C++ code into your Integrated Development Environment (IDE) of choice:
#include <iostream>
#include <cstring> // for strlen
#ifdef _WIN32
#include <winsock2.h>
#pragma comment(lib,"ws2_32.lib") //Winsock Library
#else
#include <sys/socket.h>
#include <arpa/inet.h> //for inet_addr
#include <unistd.h> // for close
#endif
#define MAX_BUFFER 1024
int main() {
#ifdef _WIN32
WSADATA wsa;
SOCKET s;
#else
int s;
#endif
struct sockaddr_in server;
const char *message;
char server_reply[MAX_BUFFER];
int recv_size;
std::cout << "Initialising Socket...";
#ifdef _WIN32
if (WSAStartup(MAKEWORD(2,2),&wsa) != 0) {
std::cout << "Failed. Error Code : " << WSAGetLastError();
return 1;
}
#endif
std::cout << "Initialised.\n";
//Create a socket
if((s = socket(AF_INET , SOCK_STREAM , 0 )) < 0) {
std::cout << "Could not create socket";
return 1;
}
std::cout << "Socket created.\n";
server.sin_addr.s_addr = inet_addr("93.184.216.34"); // example.com's IP
server.sin_family = AF_INET;
server.sin_port = htons(80); // HTTP Port
//Connect to remote server
if (connect(s, (struct sockaddr *)&server, sizeof(server)) < 0) {
std::cout << "connect error";
return 1;
}
std::cout << "Connected\n";
//Send some data
message = "GET / HTTP/1.1\r\nHost: example.com\r\nConnection: close\r\n\r\n";
if (send(s, message, strlen(message), 0) < 0) {
std::cout << "Send failed";
return 1;
}
std::cout << "Data Send\n";
//Receive a reply from the server
while((recv_size = recv(s, server_reply, MAX_BUFFER-1, 0)) > 0) {
server_reply[recv_size] = '\0';
std::cout << server_reply;
}
if(recv_size < 0) {
std::cout << "recv failed";
return 1;
}
// Cleanup and close the connection
#ifdef _WIN32
closesocket(s);
WSACleanup();
#else
close(s);
#endif
return 0;
}
Save the file as http-start.cpp or similar. Then build it with this Makefile (see GNU Make):
all:
g++ http-start.cpp -o http-start -lws2_32
#For Linux builds remove "-lws2_32"
Now set up the Wireshark filter:
Open Wireshark
set capture filter to http.host == "example.com"
push the right-facing arrow near the top right
push the shark’s dorsal fin near the top left
build http_start.cpp with the Makefile:
cd <path to http code>
make
If building on Linux be sure to comment out or remove the -lws2_32!
Then run the program httpStart.exe (drop the .exe if on Linux) and you should get a single packet something like this:
Double click on the packet and you will get all the juicy details about it. For simplicity, we will limit our analysis to the Application layer of the TCP/IP protocol suite. In this case that corresponds to the HTTP protocol. An overview of the chatter on the line for this particular packet as captured by Wireshark can be obtained by double clicking on the packet number on the capture screen. After expansion the packet looks something like this:
note that \r\n scattered throughout the line endings means “carriage return” and “line feed.” See: Does Windows carriage return \r\n consist of two characters or one character?
Here we can see an HTTP GET request. For other types of requests see here: HTTP Methods GET vs POST (w3schools.com) -- the most common one I’ve seen other than GET is POST. GET is used to request data from a web site, POST is for sending data to it.
The text we are interested in is as follows:
Request Method: GET: The method the client is using to request information from the server.
Request URI: /: The Uniform Resource Identifier, which specifies the resource the client wants. In this case, it’s the root directory of the server.
Request Version: HTTP 1.1: This is the version of HTTP protocol that the client is using to make the request.
Host: example.com: This is the domain name of the server that the client is trying to connect to.
Connection: close: This directive tells the server to close the connection after the response.
“Severity Level” might be used in a debugging logger local to example.com -- see: logging - When to use the different log levels.
I don’t know what “Group: Sequence” is. Microsoft co-pilot speculates it is:
Group: This term could refer to the team or department responsible for handling the incident or bug.
I am skeptical of this definition. Most likely it is just an unused HTTP field.
There is a reference to another frame as well, frame 85. For that we need to remove our filter to get an expanded view of the entire traffic capture of our full HTTP GET request. To do so, simply delete the text:
http.host == “example.com”
in the bar near the top and push enter. This will remove our filter but don’t despair! We now have a reference frame, 82. Scrolling down to that frame reveals something interesting on my screen, color coding for frames 79-89! This means that Wireshark has recognized these frames likely are all part of the same request. See below image:
Frames 79-81 are the TCP 3-Way Handshake.
Frame 82 was discussed above.
Frames 83-84 are not going to be discussed. In a nutshell they are setting up for the server responding to the HTTP GET request.
Frame 85 is the actual response to our request from example.com and an analysis will be done a little farther down the page.
And finally Frames 86-89 are not going to be discussed in detail but they are chatter between the server and client to close the connection.
Deep Dive on Server Response
Frame 85 is formatted as an HTTP response status code that looks like this in the Wireshark GUI:
A summary of the HTTP traffic follows.
HTTP/1.1: This is the version of HTTP that’s being used.
200: This is the status code. A status code of 200 means OK, indicating that the request was successful.
OK: This is the reason phrase associated with the status code. For a status code of 200, the reason phrase is OK. Since this is a GET request, it contains the requested resource in the data Payload.
The Age field in an HTTP header indicates the time in seconds the object has been in a proxy cache. The Age header is usually included by proxies, not by origin servers.
In this case, Age: 101317 means that the object has been in the cache for 101,317 seconds. This is approximately 28.14 hours or about 1.17 days.
Cache-Control
is an HTTP header used to specify browser caching policies in both client requests and server responses1. It holds directives (instructions) that control caching in browsers and shared caches (e.g., Proxies, CDNs). Here are some common directives that can be used in theCache-Control
header:max-age
: Specifies the maximum amount of time (in seconds) that a resource is considered fresh. After this time, the browser will contact the server to see if the resource has been updated.s-maxage
: Similar tomax-age
, but it applies to shared caches (e.g., CDN) and overridesmax-age
orExpires
header.no-cache
: The cache must verify the status of the stale resources before using it and expired ones should not be used.no-store
: No caches can store the request or response. This directive is used for sensitive data.must-revalidate
: The cache must verify the status of the stale resources before using it.public
: The response may be stored by any cache, even if the response is normally non-cacheable or cacheable only within a private cache.private
: The response may be stored only by a browser’s cache, even if the response is normally non-cacheable.
The
Content-Type
header indicates that the returned content is HTML text in UTF-8 encoding.Etag
is an HTTP response header that provides a unique identifier for a specific version of a resource. It’s used to determine whether a resource has changed since the last time it was requested, which can help save bandwidth and improve efficiency. See:Etag
.In this case,
Etag: "3147526947+gzip+ident"
is the unique identifier for the specific version of the resource you requested. The server generates this tag, and it changes every time the resource does. If you were to request the same resource again, the server would compare the Etag in your request with the Etag for the current version of the resource. If they match, the server would return a304 Not Modified
status, indicating that your cached version of the resource is still valid.The method by which Etag values are generated is not specified in the HTTP specification. Common methods include using a collision-resistant hash function of the resource’s content, a hash of the last modification timestamp, or even just a revision number.
Expires
is an HTTP header that provides the date/time after which the response is considered stale. This header is used to control the caching of the resource by the client. SeeExpires
.In this case,
Expires: Mon, 01 Apr 2024 14:09:11 GMT
means the resource will be considered stale after Monday, April 1, 2024 at 14:09:11 GMT. After this time, the client (usually a web browser) should check back with the server to see if the resource has been updated.Please note that if there is a
Cache-Control
header with themax-age
ors-maxage
directive in the response, theExpires
header is ignored.
Last-Modified
is an HTTP response header that provides the date and time at which the origin server believes the resource was last modified. It is used as a validator to determine if a resource received or stored is the same. Less accurate than anETag
header, it is essentially a fallback mechanism. See:Last-Modified
.In your case,
Last-Modified: Thu, 17 Oct 2019 07:18:26 GMT
means the resource was last modified on Thursday, October 17, 2019 at 07:18:26 GMT. If a request is made after this timestamp, the server will check if the resource has been modified. If it hasn’t, the server can return a304 Not Modified
status, indicating that the cached version of the resource is still valid
The
Server
HTTP response header provides information about the software used by the origin server to handle the request. This can include the name of the server software, and information about other technologies used by the server.In your case,
Server: ECS (agb/A437)
indicates that the server software isECS.
This could possibly refer to the Amazon Elastic Container Service.The
(agb/A437)
part could be an internal identifier used by the server, but without more context, it’s hard to say exactly what it represents.
Vary: Accept-Encoding
is an HTTP response header that informs the client that the server’s response may be different based on theAccept-Encoding
request header. SeeVary: Accept-Encoding
.The
Accept-Encoding
request header indicates the content encoding (usually a compression algorithm) that the client can understand. The server uses this information to decide how to encode the content of the response. For example, if the client indicates that it can acceptgzip
encoding, and the server hasgzip
capability, the server may choose to compress the response body usinggzip
. This is important for caching purposes. If a cache sees two requests with differentAccept-Encoding
headers, it needs to treat them as two separate cache entries, even if the rest of the request is identical.
X-Cache: HIT
is a non-standard HTTP response header that indicates the status of the requested resource in the cache. See:X-Cache.
HIT
means that the requested resource was served from the cache, not directly from the origin server. This typically results in faster response times because the server doesn’t have to process the request and generate a full response.This header is often added by Content Delivery Networks (CDNs) or caching proxies to indicate whether they were able to serve the requested resource from their cache.
Connection: close
is an HTTP header that indicates the client or the server would like to close the network connection after the current transaction finishes. This is the default behavior in HTTP/1.0. See:Connection: close
.When a client sends a request with
Connection: close
, it’s signaling that it will close the connection after receiving the response. Similarly, if a server includesConnection: close
in its response, it’s indicating that it will close the connection after sending the response.In the code sent in our http socket, we explicitly asked the server to do this (see bolded text):
message = "GET / HTTP/1.1\r\nHost: example.com\r\nConnection: close\r\n\r\n";
The
Content-Length
header indicates that the length of the response body is1256
bytes.
This concludes our traffic analysis via Wireshark (specifically HTTP traffic). Hope you enjoyed it!