tshark is the command-line sibling to the graphical Wireshark, and it’s a powerhouse for scripting packet analysis.

Let’s say you’ve got a capture file, capture.pcapng, and you want to extract all HTTP POST requests, specifically those with a Content-Type of application/json.

tshark -r capture.pcapng -Y "http.request.method == POST and http.content_type == \"application/json\"" -T fields -e frame.number -e ip.src -e ip.dst -e tcp.srcport -e tcp.dstport -e http.request.uri -e http.request.method -e http.content_type

Here’s what’s happening:

  • -r capture.pcapng: This tells tshark to read from the capture.pcapng file.
  • -Y "http.request.method == POST and http.content_type == \"application/json\"": This is the display filter. It’s the heart of your query, telling tshark to only consider packets that match both conditions: the HTTP request method is POST, AND the Content-Type header is exactly application/json. Notice the escaped double quotes around application/json – essential for passing the filter string correctly on the command line.
  • -T fields: This specifies the output format. fields means we’ll be outputting specific fields.
  • -e frame.number -e ip.src -e ip.dst -e tcp.srcport -e tcp.dstport -e http.request.uri -e http.request.method -e http.content_type: These are the fields you want to extract for each matching packet. frame.number is the packet number, ip.src and ip.dst are source and destination IP addresses, tcp.srcport and tcp.dstport are the TCP ports, and the http fields give you details about the HTTP request itself.

The output will be a tab-separated list of these fields for every packet that meets your filter criteria. This makes it incredibly easy to pipe into other tools like awk, grep, or even load into a spreadsheet.

If you want to see the raw HTTP POST data for these requests, you’d add -e http.file_data (or http.request.entity for older versions).

tshark -r capture.pcapng -Y "http.request.method == POST and http.content_type == \"application/json\"" -T fields -e frame.number -e http.file_data

This will dump the raw JSON payload for each matching POST request. Be mindful that this can be verbose.

The real magic of tshark in scripting comes from its ability to precisely target what you need without having to manually sift through a graphical interface. For instance, finding specific DNS queries for a particular domain across a large capture:

tshark -r dns_traffic.pcapng -Y "dns.qry.name == \"www.example.com\"" -T fields -e frame.time -e ip.src -e ip.dst -e dns.qry.name

This extracts the timestamp, source/destination IPs, and the queried name for all DNS requests for www.example.com.

You can also use tshark to count occurrences of specific events. To count all TCP retransmissions in a file:

tshark -r network.pcapng -Y "tcp.analysis.retransmission" -T fields -e frame.number | wc -l

This uses the wc -l command to count the lines of output, effectively counting the retransmissions.

The power of tshark extends to its ability to process live traffic as well. Instead of -r, you’d use -i <interface>:

tshark -i eth0 -Y "tcp.flags.syn == 1 and tcp.flags.ack == 0" -T fields -e frame.time -e ip.src -e ip.dst -c 10

This command captures the first 10 (due to -c 10) TCP SYN packets on eth0 and prints their timestamps and IP addresses. The -c <count> option is invaluable for limiting the amount of live data processed in a script.

One subtle but powerful feature is the ability to use tshark’s internal dissector fields directly in your filters. For example, to find HTTP requests where the User-Agent header contains "curl":

tshark -r web_traffic.pcapng -Y "http.user_agent contains \"curl\"" -T fields -e frame.number -e http.user_agent

This demonstrates how you can leverage specific protocol fields that tshark understands. The contains operator is particularly useful for substring matching within header values.

When dealing with very large capture files, performance becomes critical. Using specific filters (-Y) is far more efficient than capturing everything and filtering later in a script. Similarly, requesting only the necessary fields (-e) reduces the amount of data tshark has to process and output. The -n flag, which disables name resolution for IPs and ports, can also significantly speed up processing if you don’t need human-readable hostnames or service names.

tshark -n -r large_capture.pcapng -Y "dns" -T fields -e frame.time -e ip.src -e ip.dst -e dns.qry.name -e dns.resp.len

This command will be noticeably faster than one that attempts to resolve all IP addresses and port numbers.

The -z option is another scripting workhorse, providing built-in statistics. For example, to get a list of all unique HTTP hostnames and the number of requests to each:

tshark -r web_traffic.pcapng -z http_hosts

This output is nicely formatted and provides an immediate summary. You can pipe this into awk or grep for further processing.

The next step in mastering tshark for scripting is understanding how to combine its output with other command-line tools for more complex analysis.

Want structured learning?

Take the full Wireshark course →