Packet Capture on Windows in Practice — Choosing Among pktmon, netsh trace, and Wireshark
· Updated: · Go Komura · Windows, Packet Capture, pktmon, netsh, Wireshark, Networking, Bug Investigation, TCP/IP
Revision history (first version, published Aug 20, 2026)
- First published
Cite this article(DOI (registered archive): 10.5281/zenodo.22170865)
The DOIs below refer to previously archived versions and may not match the current text. Use this page’s URL to reference the current text.
Go Komura (2026). Packet Capture on Windows in Practice — Choosing Among pktmon, netsh trace, and Wireshark. KomuraSoft LLC. https://comcomponent.com/en/blog/windows-packet-capture-pktmon-netsh-wireshark/
- DOI (registered archive)
- 10.5281/zenodo.22170865
- DOI (last registered version)
- 10.5281/zenodo.22170866
“The business app’s communication fails a few times a month. The log says nothing but ‘timeout’. There is no error on the server side either, and we do not know how to reproduce it.” This is a situation that comes up often in communication-failure investigations.
What you want to know at that point is whether the connection failed, or whether the response stopped after the connection was made. The same timeout leads to a different place to investigate next.
An app log keeps only what the app “decided to write.” From the single result “timeout,” you cannot tell whether the SYN got no reply, whether the server went silent on an established connection, or whether the connection was cut with a RST.
Packet capture examines what lies one layer below: the packets that actually went over the wire. Where Process Monitor looks one layer down at file and registry access, packet capture looks one layer down at communication. When you need to confirm whether a packet even reached its destination, the two-sided capture covered in chapter 7 becomes important.
flowchart TB
accTitle: The packets one layer below the app log
accDescr: An app log keeps only what the app decided to write, and whether the SYN got no reply, the peer went silent after the connection was established, a RST cut the connection, or the packet even arrived is recorded only in the packets that actually went over the wire
log["App log"] --> dec["Keeps only what the app decided to write"]
dec --> to["The result is the single word timeout"]
to -->|look one layer down| pkt["Packets that actually went over the wire"]
pkt --> q1["No reply to the SYN?"]
pkt --> q2["Silent after connecting?"]
pkt --> q3["Cut with a RST?"]
pkt --> q4["Did it reach the destination?"]
Figure 1: The log keeps only the result; the breakdown of a timeout is recorded only in the packets one layer down.
Even when “we cannot install Wireshark on the customer’s server,” there is no need to give up on capturing. Even if change control or a security policy prevents adding software, Windows has two built-in capture tools: pktmon and netsh trace.
The basic split is capture with the built-in tools on site, read in Wireshark on your own machine. Treating capture and analysis as separate tasks lets the investigation proceed even on sites with install restrictions.
This article is aimed at IT staff at small and midsize companies and at Windows app developers. It organizes how to choose among pktmon, netsh trace, and Wireshark, and the practical procedure for each. The loopback-traffic trap, deciding whether to capture on the client or the server side, how to deal with TLS hiding the contents, and correlating the capture with the app log are all covered based on primary sources as of August 2026.
Start From Your Problem
| Problem | What to check first | Where to read |
|---|---|---|
| Cannot install Wireshark on the customer server | The split of capturing with built-in tools and analyzing on your own machine | Choosing the tools, pktmon procedure |
| Need to capture traffic right after a reboot | netsh trace scenarios and persistent capture | netsh trace procedure |
| Have a capture but do not know where to start reading | Display filters and the four TCP checkpoints | Reading in Wireshark |
| Traffic to localhost does not show up | The adapter being captured and the IPv4/IPv6 mix-up | Loopback traffic |
| Can see retransmissions but not where the packets vanished | Two-sided capture and recording the clock offset | Capture location and time synchronization |
| Do not know when the problem will occur | A ring buffer with a fixed size and the stop procedure after occurrence | Long-running capture |
| Need to investigate TLS traffic / need to hand over a capture file | What you can learn without decrypting, and handling confidential data | Reading TLS, Correlating with logs and sharing |
If this is your first read, follow the flow of choosing a tool in chapter 2, capturing in chapters 3 and 4, and reading in chapter 5. Chapters 6 to 8 cover capture conditions and the limits of what can be observed, and chapter 9 is the procedure for reaching a conclusion together with the app log.
1. The Bottom Line First
Capture and Analysis Can Be Left to Different Tools
On site, capture with pktmon or netsh trace, convert to pcapng, and analyze in Wireshark on your own machine. Both tools write ETL, which Wireshark cannot open as is. For pktmon use pktmon etl2pcap; for netsh trace use etl2pcapng, Microsoft’s open-source tool.12
The order for choosing tools is pktmon first, netsh trace if that is not enough, and Wireshark for protocol analysis. Microsoft’s investigation guide recommends the same flow.3
Before Capturing, Decide What to Keep and Where to Observe
pktmon ships with Windows 10 / Windows Server 2019 and later and is used in four steps: register a filter, start, stop, convert. Its distinctive strength is telling you where in the stack a packet was discarded, together with the drop reason. However, by default only the first 128 bytes of each packet are kept. To read the contents, specify --pkt-size 0 when starting.456
netsh trace is the older built-in tool. A scenario bundles a set of ETW providers, so it can capture packets together with events from inside Windows. For a capture that spans a reboot, use persistent=yes.78
Traffic to localhost does not pass through a physical NIC, so it does not appear in a capture of a physical adapter. Use Npcap’s loopback adapter or pktmon’s in-stack capture.9
Separate What You Can Read From How You Handle the File
Even when TLS hides the contents, you can still examine connection establishment, whether the TLS handshake succeeded, RSTs, and which side went silent. Decryption via SSLKEYLOGFILE is a technique for development environments only.10
On the other hand, a capture file contains the communication itself. Assume it can include credentials and personal information, keep the target and time window to the minimum, and make narrowing it down before it leaves the company part of the capture procedure.
In the diagram a solid line marks a relation that always holds and a dashed line marks a conditional one (the conditions are given per relation on the detail page). The full list of relations (21 in total, with evidence and certainty) and the definitions of the main concepts are collected on the knowledge map detail page (in Japanese). Data: JSON-LD / Turtle
2. The Three Capture Tools and How to Choose Among Them
The criteria are “what can be installed on site” and “what do you want to keep besides packets.” First, compare the roles of the three tools.
| pktmon | netsh trace | Wireshark | |
|---|---|---|---|
| Availability | Built into Windows 10 / Windows Server 2019 and later4 | Built into Windows for a long time (usable on OS versions that predate pktmon) | Must be installed separately |
| Main role | Packet capture, drop detection, counters | Packet capture plus ETW events from Windows components | Analysis of the captured data (the main tool for that) |
| Output format | ETL (converted to pcapng with etl2pcap)1 | ETL plus .cab (converted to pcapng with etl2pcapng)82 | pcapng |
| Distinctive strength | Shows where in the stack a packet was discarded and the drop reason5 | Bundles providers per scenario, captures across reboots7 | Display filters, TCP analysis, statistics, GUI |
| Privileges | Administrator | Administrator | Administrator-equivalent for capturing (not needed for analysis alone) |
It is easiest to think of it as pktmon and netsh trace “capture,” Wireshark “reads.” Wireshark can capture too, but that is not available on sites where it cannot be installed.
You can also convert the built-in tools’ ETL to text and read it. However, converting to pcapng and analyzing in Wireshark moves the investigation along better than reading by eye without display filters or TCP analysis.
flowchart TB
accTitle: Capture with the built-in tools, read with Wireshark
accDescr: Shows the split in which pktmon or netsh trace captures ETL on site, each tool's converter turns it into pcapng, and Wireshark on your own machine analyzes it
pk["pktmon (built in)"] --> etla["ETL file"]
ns["netsh trace (built in)"] --> etlb["ETL plus .cab"]
etla -->|pktmon etl2pcap| pcap["pcapng"]
etlb -->|etl2pcapng| pcap
pcap --> ws["Analyze in Wireshark on your own machine"]
Figure 2: On site, capture ETL with the built-in tools, convert to pcapng, and read it in Wireshark on your own machine.
Microsoft’s packet-loss investigation guide follows the same structure: first capture with pktmon and isolate the cause, then if that is not enough move on to component-level tracing such as netsh trace start scenario=InternetClient, and analyze protocol behavior in Wireshark.3
As a prerequisite for reading what a packet shows, understanding goes faster if you can picture the layering of Ethernet, IP, TCP, and application data. The anatomy of those layers is illustrated in “Getting a Real Feel for the OSI Model.”
3. pktmon in Practice — Filter, Start, Stop, Convert
The basic capture is four steps: register a filter, start, stop, convert. Clean up the filters when you are done. Run the following in an elevated terminal.
Before starting, check the existing filters and how you will clean up afterward. The final pktmon filter remove does not delete a filter by name; it deletes every registered filter. In an environment shared with another investigation, check with pktmon filter list first.
:: 1. Register a filter first to narrow the target (TCP 8443 on the target server 192.168.10.20)
pktmon filter add App8443 -i 192.168.10.20 -t tcp -p 8443
pktmon filter list
:: 2. Start capturing. Record whole packets, overwrite in a 1 GB ring buffer
pktmon start --capture --pkt-size 0 --file-name C:\temp\app-timeout.etl --file-size 1024 --log-mode circular
:: 3. Reproduce the event. While waiting, the counters show traffic volume and drops
pktmon counters --drop-reason
:: 4. Stop and convert to pcapng for Wireshark
pktmon stop
pktmon etl2pcap C:\temp\app-timeout.etl --out C:\temp\app-timeout.pcapng
:: 5. Clean up the registered filters (filters persist until explicitly removed).
:: Caution: filter remove cannot take a name and deletes ALL registered filters.
:: In an environment where filters from another investigation remain, check with pktmon filter list first
pktmon filter remove
flowchart TB
accTitle: The basic pktmon procedure
accDescr: Narrow the target with a filter registration, start capturing, reproduce the event, stop, convert to pcapng with etl2pcap, and finally remove the registered filters
fa["1. Narrow the target with filter add"] --> st["2. Start capturing with start --capture"]
st --> re["3. Reproduce the event"]
re -.-> ct["Check traffic and drops with counters"]
re --> sp["4. Stop with stop"]
sp --> cv["Convert to pcapng with etl2pcap"]
cv --> rm["5. Clean up with filter remove"]
Figure 3: pktmon starts with filter registration, and after capture, stop, and convert, the filters are removed explicitly.
Deciding the following four points before running the commands reduces the need to capture again.
What to Check Before Capturing
Narrow the target: multiple filters are OR conditions
Filters are registered before the capture starts. Microsoft’s documentation also strongly recommends applying filters before starting, since capturing all traffic is far too noisy. Filters can specify IP address, port, MAC address, protocol, VLAN ID, and so on, and up to 32 can be registered. Multiple filters are an OR condition: “record if any one matches.”4
Narrow the direction: source and destination are not distinguished
pktmon filters do not distinguish source from destination. -i 192.168.10.20 means “packets where this address is the source or the destination.” Narrow the direction after conversion with a Wireshark display filter.4
Decide the recording range: headers only, or whole packets
The default packet size is 128 bytes. That is enough for analyzing headers, but to read the application data as well, record whole packets with --pkt-size 0.6
Decide the capacity: ring buffer and real-time display
The log defaults to circular (ring buffer) mode with a default size of 512 MB. --file-size changes the limit, and --log-mode real-time displays packets on screen in real time without creating a log file. Confirming first in real-time display that “the traffic I am after is visible” before setting up the real capture prevents a wasted run.6
flowchart TB
accTitle: How pktmon filters take effect
accDescr: Shows that multiple registered filters work as an OR condition that records when any one matches, that a specified address does not distinguish source from destination, and that direction is therefore narrowed after conversion with a Wireshark display filter
f1["Filter 1"] --> orc["Record if any one matches"]
f2["Filter 2"] --> orc
f3["Filter 3 (up to 32)"] --> orc
orc --> rec["Recorded in the capture log (OR condition)"]
rec -.-> nodir["Source and destination are not distinguished"]
nodir -.-> ws["Narrow the direction in Wireshark after conversion"]
Figure 4: Multiple filters work as an OR condition, and the direction, source or destination, is narrowed in Wireshark after conversion.
3.1. pktmon’s Unique Strength — Knowing Where the Packet Was Discarded
What sets pktmon apart from Wireshark is that it captures packets at multiple points inside the network stack, not at the single point of the NIC, and reports where and why a packet was discarded (dropped). Because you can see which component the packet reached and where it disappeared, drop reasons such as “MTU mismatch” or “VLAN filter” lead you to the cause without trial and error.5
flowchart TB
accTitle: pktmon captures at multiple points inside the stack
accDescr: Shows that because pktmon captures packets at multiple points inside the network stack rather than at the single point of the NIC, it can report with a reason which component a packet reached and where it was discarded
pin["Packet"] --> p1["Captured at point 1"]
p1 --> p2["Captured at point 2"]
p2 --> p3["Discarded at point 3"]
p3 -.-> rz["Reports the drop location and drop reason"]
rz -.-> ex["For example MTU mismatch or VLAN filter"]
Figure 5: Because it captures at multiple points inside the stack, you learn how far the packet got and where it was discarded, with a reason.
Check the counters first, then the text log if needed
pktmon listshows the list and IDs of the network components that can be monitored (NICs, the protocol stack, filter drivers, and so on).pktmon counters --drop-reasonlists the pass/drop counters per component and the most recent drop reason. It is a convenient first-pass triage before analyzing the log.11- Converting to text with
pktmon etl2txtoutputs discarded packets tagged withdropand a dropReason.4
The suspicion “maybe the OS is discarding it somewhere before it reaches the app” is not settled by staring at Wireshark. For example, this feature is effective for isolating the case where the firewall is dropping traffic because of a faulty inbound rule (“The Windows Firewall and Business Applications”).
Narrow the capture point before handing off to Wireshark
pktmon records the same packet at multiple points inside the stack. If you convert to pcapng as is, the same packet can appear duplicated, because pcapng does not carry over the information about which component captured it.
If the goal is to read in Wireshark, narrow the point with --component-id on pktmon etl2pcap when converting. Another option is to put only the drops into a separate file with --drop-only.1
flowchart TB
accTitle: Why the same packet appears duplicated after pcapng conversion
accDescr: Shows that pktmon records the same packet at multiple points inside the stack and pcapng does not carry over which component captured it, so packets can appear duplicated, and that the standard practice is to narrow the point with component-id or put only the drops into a separate file with drop-only when converting
same["The same packet recorded at multiple points"] --> conv["Convert to pcapng as is"]
conv --> lost["Capture point information is not carried over"]
lost --> dup["The same packet appears duplicated"]
dup --> c1["Narrow the point with --component-id"]
dup --> c2["Separate file with --drop-only"]
Figure 6: Because capture point information is not carried over to pcapng, the standard practice is to narrow the point before converting.
4. netsh trace in Practice — Scenarios, ETL, and Capturing Across a Reboot
netsh trace is a trace-collection mechanism that has been in Windows longer than pktmon. Its distinctive feature is that a unit called a “scenario” enables, all at once, the set of ETW providers related to that problem.8
:: List the available scenarios and check the providers a scenario contains
netsh trace show scenarios
netsh trace show scenario netconnection
:: Start capturing. Includes packet capture, 1 GB circular buffer
netsh trace start scenario=netconnection capture=yes tracefile=C:\temp\nettrace.etl maxSize=1024 filemode=circular
:: Reproduce the event, then stop (the merge takes a little time)
netsh trace stop
Capture Conditions to Decide for netsh trace
Add capture=yes to keep packets too
Adding capture=yes enables packet capture, and a capture filter such as ipv4.address=192.168.10.20 narrows the target. netsh trace show capturefilterHelp lists the available filters.8
The .cab environment information is kept alongside the ETL
Stopping generates a .cab file in addition to the ETL file. The .cab contains system information such as adapter configuration and the OS build, so it doubles as environment-information collection.8
Check for an existing session before starting
Only one trace session can run at a time. Before starting another capture, check with netsh trace show status that no session is still running.8
Use persistent=yes for events right after a reboot
Adding persistent=yes keeps the session alive across a reboot. For events you cannot start capturing manually in time, such as “communication fails only for a moment right after a reboot” or “the service connection fails at startup,” netsh trace is the only option.7
flowchart TB
accTitle: Scenario capture with netsh trace
accDescr: Shows the flow in which starting with a scenario enables a bundled set of ETW providers, adding capture=yes also captures packets, and stopping generates an ETL file and a .cab file
sc["Start with a scenario"] --> pv["Enable the bundled providers"]
sc -->|capture=yes| pc["Capture packets too"]
pv --> re["Reproduce the event"]
pc --> re
re --> sp["Stop with stop"]
sp --> etl["ETL file"]
sp --> cab[".cab (system information)"]
Figure 7: Starting with a scenario enables the bundled providers all at once, and stopping generates the ETL and the .cab.
4.1. Making the ETL Readable in Wireshark — etl2pcapng
netsh trace’s ETL cannot be opened in Wireshark as is. etl2pcapng, an open-source tool Microsoft publishes on GitHub, converts the packets in an ETL captured with netsh trace start capture=yes to pcapng.2
etl2pcapng.exe C:\temp\nettrace.etl C:\temp\nettrace.pcapng
During conversion, etl2pcapng writes the process ID involved with each packet as a packet comment. Because you can check “which process this traffic belongs to” in Wireshark, it helps isolate problems in environments where several apps on the same server are communicating.2
Packets and Windows internal events are read differently
Note that the ETW event side (the Windows internal events recorded by the scenario providers) is not converted to pcapng. To read the events as well, convert with netsh trace convert input=C:\temp\nettrace.etl to text or another format, or open the file in Windows Performance Analyzer or a similar tool.73
flowchart TB
accTitle: Reading a netsh trace ETL goes two ways
accDescr: Shows that the packets in the ETL are converted to pcapng with etl2pcapng and read in Wireshark, while ETW events are not converted to pcapng and are read with netsh trace convert or Windows Performance Analyzer
etl["netsh trace ETL"] --> pk["Packets"]
etl --> ev["ETW events"]
pk -->|etl2pcapng| pc["Convert to pcapng"]
pc --> ws["Read in Wireshark"]
pc -.-> pid["Process ID kept as a comment"]
ev -.-> no["Not converted to pcapng"]
no --> alt["Read with convert or WPA"]
Figure 8: The packets in the ETL are converted to pcapng and read; the ETW events are read by other means.
5. An Introduction to Reading in Wireshark — Display Filters and TCP Analysis
Analysis proceeds in this order: narrow the target, check the shape of the TCP conversation, then look at the whole conversation as needed. First open the pcapng and cut the noise with a display filter.1213
Narrow What You Read With a Display Filter
| Display filter | Meaning |
|---|---|
ip.addr == 192.168.10.20 |
Packets where this IP is the source or the destination |
tcp.port == 8443 |
Packets involving this TCP port |
dns |
DNS queries and responses only |
tcp.flags.syn == 1 && tcp.flags.ack == 0 |
Only the SYN that opens a connection |
tcp.flags.reset == 1 |
Only RST (forced teardown) |
tcp.analysis.retransmission |
Packets Wireshark judged to be retransmissions |
tcp.analysis.zero_window |
Receive window 0 (the receiver cannot accept data) |
tcp.analysis.flags |
Every packet in which some problem was detected |
tcp.analysis.* are analysis flags that Wireshark sets automatically by tracking TCP sequence numbers. Retransmissions, duplicate ACKs, out-of-order segments, ZeroWindow, and so on are picked up mechanically, so typing tcp.analysis.flags first to list the “suspicious spots” is the standard way to start reading.13
Split a Timeout Into Four Checkpoints
Once tcp.analysis.flags has pointed you somewhere, check in the following order. In particular, a retransmission is the observation “no ACK came back,” so it is important not to decide from one side alone whether the outbound or the return direction was lost.
1. Was the connection established: SYN, SYN/ACK, ACK
Did the three-way handshake complete? Are all three of SYN, SYN/ACK, and ACK present? If SYNs are repeated with no reply, the packet either did not reach the peer or was silently discarded along the way (the typical firewall pattern).
2. Was it forcibly cut: when the RST came and who sent it
Which side sent the RST? An immediate RST in reply to a SYN means nothing is listening on the destination port; a RST after establishment means one side forcibly cut the connection. The RST’s source IP is direct evidence of “which side cut it.”
3. Are ACKs coming back: continuing retransmissions
Are retransmissions continuing? Repeated retransmission of the same segment is a sign that the sender is not receiving acknowledgments (ACKs). Whether the outbound data was lost or the returning ACK was lost cannot be settled from one side’s capture alone (which is exactly why “capture on both sides” in the next chapter matters). Retransmissions and timeouts are examined in depth in “Why TCP Retransmissions Stall Industrial Camera Communication, and How to Isolate Them.”
4. Is the receiver backed up: ZeroWindow
Is ZeroWindow appearing? It is a sign that the receiving app is not reading data from the socket and the receive buffer is full. It is grounds for suspecting the design of the receiving app rather than the network (“The Misconception That TCP Lets You Receive in the Same Units You Send”).
flowchart TB
accTitle: The order of shapes to look for in a timeout investigation
accDescr: The flow of checking, in order, whether the three-way handshake completed, whether a RST is present and who sent it, whether retransmissions continue, and whether ZeroWindow appears, to narrow down the cause
hs{"Did the SYN get a reply?"} -->|No| ng["Suspect it never arrived and was discarded (typical firewall)"]
hs -->|Yes| rs{"Is a RST present?"}
rs -->|Yes| who["The RST's sender is the side that cut it"]
rs -->|No| rt{"Are retransmissions continuing?"}
rt -->|Yes| ack["Sign that ACKs are not coming back"]
rt -->|No| zw{"Is ZeroWindow appearing?"}
zw -->|Yes| app["Sign that the receiving app is not reading"]
Figure 9: Looking for shapes in the order handshake, RST, retransmission, ZeroWindow narrows down where to investigate next.
When There Is a Lot of Traffic, Get an Overview From Statistics First
Before reading packet by packet, it is also effective to find the conversation and time range you want through statistics.
| Feature | What to look at | Next action |
|---|---|---|
| Statistics > Conversations | Which IP pair and port pair talked, from when to when, and how much | Filter to just the conversation you want |
| Statistics > I/O Graph | Traffic volume over time, such as a change like “from this time, one direction went silent” | Narrow the time range to investigate |
| Right-click a conversation > Follow > TCP Stream | The exchange on that connection | Read a cleartext exchange end to end. See chapter 8 for what to do when the TLS contents are not visible |
flowchart TB
accTitle: Get an overview from statistics, then narrow to the conversation
accDescr: Shows the flow of listing in Conversations which traffic talked when and how much to identify the conversation you want, using the I/O Graph to find the time range that went silent, filtering to just the target conversation, and reading it end to end in a TCP stream
ov["Overview from statistics"] --> cv["List conversations in Conversations"]
ov --> io["View traffic volume in the I/O Graph"]
cv --> flt["Filter to just the conversation you want"]
io -.-> mute["Shows the time it went silent"]
flt --> fs["Read end to end in the TCP stream"]
Figure 10: Before reading packet by packet, get an overview from statistics, narrow to the conversation you want, then read it end to end.
6. The Loopback Trap — Traffic to localhost Does Not Pass Through the NIC
Trying to investigate communication between apps on the same PC — for example, a connection from a business app to an intermediate service at localhost:8080 — and getting stuck on “nothing shows up in Wireshark” is a classic trap.
The cause is clear. Traffic to localhost (127.0.0.1) does not pass through a physical NIC; it is turned around on the loopback path inside the OS. A normal capture that targets a physical adapter never sees it in the first place.9
flowchart TB
accTitle: Why traffic to localhost does not show up in a capture
accDescr: Shows that traffic to localhost does not pass through a physical NIC and is turned around on the loopback path inside the OS, so it does not appear in a normal capture that targets a physical adapter
app["App"] --> stack["Network stack"]
stack -->|to external hosts| nic["Physical NIC"]
nic --> seen["Appears in a normal capture"]
stack -->|to localhost| lo["Turned around inside the OS"]
lo -.-> miss["Does not appear in a normal capture"]
lo -.-> alt["Capture with Npcap loopback or pktmon"]
Figure 11: Traffic to localhost is turned around before the NIC, so it never appears in a capture of a physical adapter.
Match the Capture Method to the Loopback Path
There are two remedies.
- When capturing with Wireshark: select the “Adapter for loopback traffic capture” provided by Npcap as the capture target. The Windows installer for Wireshark (3.0 and later) bundles Npcap, so any environment that has Wireshark can use it with no additional work.9
- When capturing with the built-in tools: pktmon captures at multiple points inside the network stack rather than outside the NIC,5 so it can observe loopback traffic as well. To be sure, before setting up the wait for the real reproduction, confirm in that environment with the real-time display of
pktmon start -c -m real-timethat the loopback traffic you are after is actually visible.
Two Mix-Ups Also Exist in How the Address Is Specified
localhost does not necessarily mean 127.0.0.1
“localhost” is sometimes resolved to IPv6 ::1. The pattern is that the app connects to IPv6 ::1 while the investigator watches only 127.0.0.1 (IPv4) and wrongly concludes “there is no traffic.” Either set the display filter for both, as in ip.addr == 127.0.0.1 || ipv6.addr == ::1, or state the app’s connection target explicitly as an address.9
Specifying your own real IP does not necessarily go through the physical NIC
Traffic to your own real IP address does not go out on the wire either. When the same PC connects from 192.168.10.5 to 192.168.10.5, the traffic is turned around inside the OS even though the destination is the real IP. Remember that “it uses the real IP, so it must go through the NIC” is not necessarily true.
flowchart TB
accTitle: The mix-up of localhost resolving to IPv6
accDescr: Shows that an app's localhost is sometimes resolved to IPv6 ::1 and connected there, and an investigator who watches only 127.0.0.1 wrongly concludes there is no traffic, so set the display filter for both or state the connection target explicitly as an address
app["App connects to localhost"] --> v6["Actually resolved to ::1 (IPv6)"]
look["Investigator watches only 127.0.0.1"] --> none["Nothing appears on screen"]
v6 --> none
none --> fix1["Set the filter for both addresses"]
none --> fix2["State the target explicitly as an address"]
Figure 12: Beware the mix-up where localhost resolves to ::1 and, watching only 127.0.0.1, you wrongly conclude there is no traffic.
7. Where to Capture — One Side, Both Sides, and Time Synchronization
What one side gives you is the facts as seen from that capture point. Choose the capture location according to whether you first want the overall picture or want to determine whether the traffic vanished on the outbound or the return path.
| Capture location | What you learn | Suited to |
|---|---|---|
| Client side only | What you sent and what came back | Getting the overall picture first. When you cannot touch the server |
| Server side only | Whether the request arrived and whether a response was returned | When there are many clients or they cannot be identified |
| Both sides at once | Where on the path the packet vanished, and which side went silent | When you want to settle the demarcation of responsibility |
Even when retransmissions continue on the client side, one side alone cannot distinguish the following two cases.
- The packet you sent vanished before reaching the server.
- The packet reached the server, but the response vanished on the way back.
Capturing on both sides and correlating them settles which side went silent, as in “the client sent it, the server never received it.” When you need to settle the demarcation of responsibility (the app, the OS, network equipment, the peer), arrange a two-sided capture from the start.
flowchart TB
accTitle: What one-sided and two-sided capture tell you
accDescr: Shows that a capture from one side cannot distinguish whether the outbound packet vanished or the returning response vanished, while capturing on both sides and correlating them settles which side went silent
one["Capture on one side only"] --> fact["Only the facts as seen from your position"]
fact --> und["Cannot tell whether the outbound or the return was lost"]
both["Capture on both sides at once"] --> mt["Correlate"]
mt --> fix["Settles which side went silent"]
mt -.-> pre["Prerequisite is clock synchronization on both machines"]
Figure 13: One side shows only the facts it saw; only correlating both sides settles the demarcation of responsibility.
7.1. Correlation Requires Synchronized Clocks
To correlate captures from both sides, the clocks on both machines must agree. Before starting the capture, check and record the clock offset.
:: Check the time synchronization status (source and last sync time)
w32tm /query /status
:: Measure the clock offset against the peer server (5 samples)
w32tm /stripchart /computer:sv-app01 /dataonly /samples:5
w32tm /stripchart displays the time offset between your machine and the peer computer, and gives you the basis for a correction such as “the server-side clock was off by +0.8 seconds” when correlating.14 In an environment with a large offset, fixing time synchronization first and then capturing is the shortcut in the end.
flowchart TB
accTitle: Checking the clock offset before correlating
accDescr: Shows the flow of checking your own time synchronization status with w32tm, measuring and recording the clock offset against the peer server with stripchart, and using that offset as the basis for correction when correlating, and that in an environment with a large offset you fix time synchronization first and then capture
st["Check the sync status with query"] --> mc["Measure the clock offset with stripchart"]
mc --> rc["Record the offset"]
rc --> use["Basis for correction when correlating"]
mc -.-> big["If the offset is large, fix synchronization first"]
Figure 14: Measure and record the clock offset before capturing, and use it as the basis for correction when correlating.
7.2. A Ring Buffer for “We Do Not Know When It Happens”
For an event with unknown reproduction conditions, the basic approach is to keep capturing into a ring buffer and stop when it occurs.
- pktmon: circular mode is the default. Specify the limit (MB) with
--file-size, and the oldest packets are overwritten first.6 - netsh trace: specify it as
maxSize=1024 filemode=circular.7 - Wireshark: Capture > Options > Output lets you configure “multiple files plus ring buffer.” It rotates by file size or time and keeps only the latest N files, so it can run for a long time with a cap on disk usage.15
Decide not only the capacity but also how to stop after the event
In every case, share with the on-site staff the practice of noting the time of occurrence before stopping the capture once the event happens. The longer a ring buffer waits, the more of the past it loses, so if the procedure from occurrence to stopping is long, the critical interval gets overwritten.
flowchart TB
accTitle: Waiting with a ring buffer
accDescr: Shows the practice of keeping a capture running into a ring buffer for an event with unknown reproduction conditions, noting the time of occurrence when the event happens and stopping promptly, and that if stopping is delayed the oldest packets are overwritten first and the critical interval is lost
st["Start capturing into a ring buffer"] --> wt["Keep capturing and wait"]
wt --> ev["The event occurs"]
ev --> memo["Note the time of occurrence"]
memo --> sp["Stop promptly"]
wt -.-> ow["Oldest packets are overwritten first"]
ow -.-> late["If stopping is delayed the critical interval is lost"]
Figure 15: A ring buffer loses more of the past the longer it waits, so note the time of occurrence and stop promptly.
8. When TLS Hides the Contents — What You Can Still Learn
Check the Skeleton of the Conversation Before Decrypting
Most business communication today is TLS (HTTPS). The reflex is to assume “if it is encrypted, capturing is pointless,” but most of what you want to know in a timeout investigation is visible even with the traffic left encrypted.
- Whether the TCP connection was established (the three-way handshake)
- How far the TLS handshake got — whether a ServerHello came back for the ClientHello, whether the connection was cut during the handshake by a RST or an alert
- The destination host name carried in the ClientHello (SNI) and the negotiated TLS version
- After establishment, which side stopped sending. Where the silence is, retransmissions, RST, or a normal close (FIN)
In other words, isolating “cannot connect,” “cut off midway,” and “no response” hardly ever needs the contents decrypted. What encryption takes away is “what was said”; “who went silent and when” remains.
flowchart TB
accTitle: What a TLS capture shows and what it does not
accDescr: Shows that encryption hides only the contents of the application data, while TCP connection establishment, whether the TLS handshake succeeded, the SNI and TLS version, RSTs, and which side went silent are visible with the traffic left encrypted
tls["Capture of TLS traffic"] --> vis["Visible"]
tls --> hid["Not visible"]
vis --> v1["TCP connection establishment"]
vis --> v2["TLS success or failure and SNI"]
vis --> v3["RST and which side went silent"]
hid --> h1["Contents of the application data"]
Figure 16: Encryption takes away only the contents; the skeleton of the conversation can still be read with TLS as it is.
Check Whether Decryption Is Possible Only When You Need the Contents
If you still need the contents, Wireshark can decrypt TLS using session keys written out via the SSLKEYLOGFILE environment variable. However, only some implementations support it, such as the Firefox, Chrome, and Chromium-based Edge browsers and OpenSSL-based libraries; Windows’ built-in SChannel (apps that use WinHTTP or WinINET) does not support this mechanism.10 Because the session keys are written to a file, meaning anyone who obtains that file can decrypt all of the traffic, it should be positioned not as something to use in production, but as a tool for reproduction and debugging in a development environment.
flowchart TB
accTitle: How decryption via SSLKEYLOGFILE works and its limits
accDescr: Shows that session keys written out via SSLKEYLOGFILE let Wireshark decrypt TLS, but only some implementations such as Firefox and the Chrome family support it and SChannel does not, and because anyone holding the key file can decrypt the traffic it is a technique for development environments only
env["Set SSLKEYLOGFILE"] --> key["Session keys written to a file"]
key --> ws["Decrypt and read in Wireshark"]
key -.-> risk["Anyone holding the keys can decrypt everything"]
risk -.-> dev["Position it as development environments only"]
env -.-> sup["Supported only by some TLS implementations"]
sup -.-> sch["SChannel is not supported"]
Figure 17: Writing out session keys enables decryption, but supported implementations are limited, and by the nature of the keys it is a development-environment-only technique.
Note that for traffic through a corporate proxy, the destination seen in the capture is the proxy server, and the TLS flows inside a CONNECT tunnel. The prior question of which proxy the app heads for in the first place is organized in the companion article published the same day, “Corporate Proxies and Windows Apps — Sorting Out Proxy Resolution in WinINET, WinHTTP, and .NET.”
9. Correlating With the App Log — Putting Times on the Same Axis
A capture alone rarely produces a conclusion, in fact. What decides the matter in practice is placing one line of the app log and one round trip of packets on the same time axis.
Replace a Log Line With the Observed Facts in the Packets
First, from the time the exception occurred, find the interval in which the communication started.
Step 1: Find the start time from the exception time and the timeout value
Identify the time of the event from the app log (for example, a timeout exception at 10:23:41). If the timeout value is 30 seconds, the start should be around 10:23:11.
Step 2: Switch Wireshark to date-and-time display and narrow to that interval
Switch Wireshark’s time display with View > Time Display Format > Date and Time of Day, and narrow to the interval with a display filter (you can also narrow by time, as in frame.time >= "2026-08-20 10:23:00" && frame.time <= "2026-08-20 10:24:00").
Step 3: Check the handshake, RST, retransmissions, and ZeroWindow
In that interval, check in the order from chapter 5 (handshake, RST, retransmissions, ZeroWindow). Once you can correlate down to “a SYN was sent 30 seconds before the timeout time in the log, followed only by SYN retransmissions,” the log’s “timeout” becomes the observed fact “no reply at all came back to this capture point” (whether the SYN never reached the peer or the SYN/ACK reply was lost on the way back cannot be settled from this capture point alone; to settle it, correlate with a capture on the server side).
Step 4: Correct for the clock offset and the time zone
Always correct for the offset between the capture’s time and the log’s time (the clock offset measured in section 7.1, and the time zone notation of the log). A correlation error of a few seconds makes you blame the wrong communication.
flowchart TB
accTitle: The procedure for correlating the app log with packets
accDescr: Shows the procedure of identifying the time of the event from the app log, working back to the start time from the timeout value, narrowing to that interval in Wireshark and checking the shapes in order, and correcting for the clock offset to line everything up on the same time axis
lg["1. Identify the event time in the log"] --> rev["Work back to the start from the timeout value"]
rev --> flt["2. Narrow to the interval with a display filter"]
flt --> chk["3. Check the shapes in the chapter 5 order"]
chk --> adj["4. Correct for the clock offset"]
adj --> done["The one-word log entry becomes an observed fact"]
Figure 18: Narrow to the interval from the log time, check the shapes, correct for the clock offset, and line everything up on the same axis.
Before Handing It to a Third Party, Extract Only the Conversation You Need
When handing investigation results to a third party (a vendor, a carrier, the customer’s network staff), cutting the noise with a filter before handing over is both courtesy and a safety measure. Narrow to just the target conversation with a display filter in Wireshark, then save with File > Export Specified Packets, choosing “Displayed” packets only, and you get a small pcapng containing only the range you need.
Decide How Confidential Data Is Stored and Deleted Before Capturing
A capture file contains the communication itself. It can include credentials from cleartext protocols, HTTP cookies and API keys, the contents of email and forms, and personal information. Decide the following three points together with the capture procedure.
- Minimum-necessary capture: narrow the target with pre-capture filters (chapters 3 and 4) and keep the time window minimal. Do not do “just grab everything” in a customer environment
- Narrowing before handover: export only the target conversation and do not include unrelated third parties’ traffic. If confidential parts remain, agree with the recipient on masking or another means of delivery
- Storage and deletion: decide where capture files are stored, for how long, and how they are deleted, and delete them when the investigation is complete
flowchart TB
accTitle: Three decisions before handing over a capture file
accDescr: Shows that because a capture contains the communication itself, three points are decided together with the capture procedure, keep it to the minimum with pre-capture filters and the time window, extract only the target conversation before handing over and include no unrelated traffic, and decide the storage location and retention period and delete after the investigation is complete
cap["A capture contains the communication itself"] --> p1["Capture the minimum necessary"]
cap --> p2["Extract only the target before handing over"]
cap --> p3["Set a retention period and delete"]
p2 -.-> exp["Narrow with a display filter and export"]
Figure 19: Decide minimum capture, narrowing before handover, and storage and deletion together with the capture procedure.
10. Summary
- One layer below the “timeout” in the app log lies a fact: the packets that actually went over the wire. Whether the SYN got no reply, the connection was cut with a RST, retransmissions continued, or ZeroWindow appeared changes where you investigate next.
- Even on sites where Wireshark cannot be installed, you can capture with Windows’ built-in pktmon and netsh trace. The basic split is to capture with the built-in tools and read in Wireshark on your own machine.
- pktmon takes four steps: register a filter,
pktmon start --capture,pktmon stop,pktmon etl2pcap. By default packets are truncated to 128 bytes, so do not forget--pkt-size 0if you want to read the contents. Knowing where and why a packet was dropped is a strength only pktmon has. - netsh trace captures with a scenario that bundles ETW providers, and
persistent=yeslets it span a reboot. Convert the ETL to pcapng with etl2pcapng to read it. - In Wireshark, start reading from
tcp.analysis.flagsand look for shapes in the order handshake, RST, retransmissions, ZeroWindow. Getting an overview with Conversations and the I/O Graph before narrowing is faster. - Traffic to localhost does not pass through the NIC, so it cannot be captured the ordinary way. Use Npcap’s loopback adapter or pktmon’s in-stack capture.
- Capturing on both sides and correlating settles “which side went silent.” The prerequisite is time synchronization (w32tm). For events with unknown reproduction conditions, wait with a ring buffer.
- Even with TLS, the skeleton of the conversation is visible. Position decryption (SSLKEYLOGFILE) as a development-environment-only technique, and treat the capture file itself as confidential, building minimum capture, narrowing, and deletion into your practice.
Packet capture tends to be thought of as “a tool for network specialists,” but in reality it is an investigation tool for the app side, one that only becomes meaningful when correlated with the app log. The next time an investigation stalls at the single word “timeout,” go look one layer below it.
Related Articles
- Why TCP Retransmissions Stall Industrial Camera Communication, and How to Isolate Them
- The Misconception That TCP Lets You Receive in the Same Units You Send — Designing Reception Around a Byte Stream
- Getting a Real Feel for the OSI Model — Dissecting a Single HTTP Request Into Its Seven Layers
- A Practical Guide to Process Monitor (ProcMon) — Pinpointing “Settings Not Applied” and “ACCESS DENIED” in 10 Minutes
- The Windows Firewall and Business Applications — Register Inbound Rules From the Installer
- Corporate Proxies and Windows Apps — Sorting Out Proxy Resolution in WinINET, WinHTTP, and .NET
Related Consulting Areas
KomuraSoft LLC handles communication-related bug investigations such as “the business app’s communication fails occasionally and we do not know why” and “we want to isolate a connection error that occurs only in the customer’s environment.” We cover the whole chain from designing the capture (where, what, and how much to capture) through analysis in Wireshark, correlation with the app log, and fixing the app itself.
- Windows App Development
- Bug Investigation and Root Cause Analysis
- Technical Consulting and Design Review
- Contact
References
-
Microsoft Learn, pktmon etl2pcap. On converting pktmon’s ETL log to the pcapng format that Wireshark and other tools can analyze, and on narrowing in advance with –drop-only or –component-id before converting because the pcapng format loses the drop information and the in-stack capture point information. ↩ ↩2 ↩3
-
GitHub, microsoft/etl2pcapng. On it being a Microsoft open-source tool that converts the packets in an ETL file captured with netsh trace start capture=yes and similar to the pcapng format, preserving interface information, and writing the process ID as a packet comment. ↩ ↩2 ↩3 ↩4
-
Microsoft Learn, Diagnose packet loss. On the official investigation procedure for packet loss: first collect a trace with pktmon to check local drop reasons and statistics, combine it with protocol-level analysis in Wireshark, and if that is insufficient move on to component-level tracing with netsh trace scenarios. ↩ ↩2 ↩3
-
Microsoft Learn, Pktmon command formatting. On pktmon.exe being available on Windows 10 and Windows Server 2019 (version 1809) and later, the quick-start procedure of registering a filter, starting, reproducing, checking counters, and stopping and converting, filters being limited to 32 and working as an OR condition without distinguishing source from destination, and dropped packets carrying a dropReason in the text output. ↩ ↩2 ↩3 ↩4 ↩5
-
Microsoft Learn, Packet Monitor (Pktmon). On Packet Monitor being Windows’ built-in cross-component diagnostic tool that captures packets at multiple points inside the network stack to visualize a packet’s route, reporting drops in supported components with a drop reason (MTU Mismatch, Filtered VLAN, and so on), and providing per-point packet counters. ↩ ↩2 ↩3 ↩4
-
Microsoft Learn, pktmon start. On starting a capture with –capture, the –pkt-size default of 128 bytes and specifying 0 to record whole packets, –file-name and –file-size (default 512 MB), and the –log-mode modes (circular, multi-file, real-time, memory) with circular as the default. ↩ ↩2 ↩3 ↩4
-
Microsoft Learn, netsh trace. On the netsh trace start parameters such as scenario, capture, tracefile, maxSize, fileMode (circular acts as a ring buffer), and persistent (keeps the session across a reboot), and on converting the ETL to text and other formats with netsh trace convert. ↩ ↩2 ↩3 ↩4 ↩5
-
Microsoft Learn, Using Netsh to manage traces. On a scenario being a predefined set of providers for troubleshooting, checking with netsh trace show scenarios / show scenario, only one trace session running at a time, packet filters (ipv4.address and so on) when capture=yes, and an ETL and a .cab (containing system information) being generated on stop. ↩ ↩2 ↩3 ↩4 ↩5 ↩6
-
Wireshark Wiki, CaptureSetup/Loopback. On Windows being unable to capture loopback traffic to 127.0.0.1 in a normal capture that targets a physical NIC, Npcap’s “Adapter for loopback traffic capture” enabling loopback capture, and the Windows installer for Wireshark 3.0 and later bundling Npcap. ↩ ↩2 ↩3 ↩4
-
Wireshark Wiki, TLS. On Wireshark being able to decrypt TLS using session keys written out via the SSLKEYLOGFILE environment variable, support being limited to Firefox, Chrome, Chromium-based Edge, OpenSSL-based libraries, and the like, and Microsoft’s SChannel not supporting this mechanism. ↩ ↩2
-
Microsoft Learn, pktmon counters. On pktmon counters displaying pass and drop counters per monitored component, –drop-reason displaying the most recent drop reason for each drop counter, and real-time updates with –live. ↩
-
Wireshark, Building Display Filter Expressions (Wireshark User’s Guide). On the display filter syntax, field specifiers such as ip.addr and tcp.port, comparison operators, and combining with and/or/not. ↩
-
Wireshark, TCP Analysis (Wireshark User’s Guide). On the list of Wireshark’s TCP analysis flags (tcp.analysis.retransmission, tcp.analysis.duplicate_ack, tcp.analysis.out_of_order, tcp.analysis.zero_window, and so on) and the criteria for each. ↩ ↩2
-
Microsoft Learn, Windows Time service tools and settings. On w32tm being the recommended command-line tool for configuring, monitoring, and troubleshooting W32Time, and w32tm /stripchart displaying the time offset between your machine and the peer computer (with options such as /dataonly and /samples). ↩
-
Wireshark, Capture files and file modes (Wireshark User’s Guide). On the capture file output modes (single file, multiple files, ring buffer) and the ring buffer keeping only the latest data so that disk usage can be capped. ↩
Related Articles
Recent articles sharing the same tags. Deepen your understanding with closely related topics.
The Order of Name Resolution on Windows — hosts, the DNS Cache, LLMNR/mDNS, and DoH
Whether hosts, the DNS cache, the DNS server, or LLMNR/mDNS answered decides why some PCs fail. Learn the Windows name resolution order, ...
Getting a Real Feel for the OSI Model — Dissecting a Single HTTP Request Into Its Seven Layers
Understand the OSI model through the real thing instead of rote memorization. We assemble and dissect, in C#, the Ethernet frame carrying...
The Network Works but Windows Says "No internet" — Isolating NCSI, DNS, Proxy, and VPN on Windows
Why Windows says "No internet" while the network works, starting from the NCSI verdict. Isolate DNS, proxy, VPN, and captive portals with...
Time Travel Debugging — Recording and Rewinding the Bugs That Never Reproduce in Long-Running Apps
A once-a-month bug leaves only its result in a crash dump. Record and rewind execution with WinDbg Time Travel Debugging (TTD): TTD.exe, ...
Apps That Break on Resume from Sleep — How Power Events Work and How to Build Business Apps That Survive Resume
Why business apps break after a laptop resumes from sleep: WM_POWERBROADCAST notifications, Modern Standby, reconnect design, sleep suppr...
Related Topics
These topic pages place the article in a broader service and decision context.
Windows Technical Topics
Topic hub for KomuraSoft LLC's Windows development, investigation, and legacy-asset articles.
Bug Investigation & Long-Run Failures
Topic page for intermittent failures, communication diagnosis, long-run crashes, and failure-path test foundations.
Where This Topic Connects
This article connects naturally to the following service pages.
Windows App Development
We support Windows desktop applications that involve resident processing, device integration, operational logging, and maintainable structure.
Bug Investigation & Root Cause Analysis
We investigate difficult production issues such as intermittent failures, long-run crashes, leaks, and communication stoppages.
Frequently Asked Questions
Common questions about the topic of this article.
- How do I capture packets on a customer server where I cannot install Wireshark?
- Use the built-in Windows tools pktmon or netsh trace, and you can capture without installing any additional software. With pktmon, register a filter in an elevated terminal, start the capture with pktmon start --capture, and stop it with pktmon stop. The resulting ETL file can be converted to pcapng with pktmon etl2pcap, so you can take it back to your own company and analyze it in Wireshark on your own machine. The split of capturing with the built-in tool and reading with Wireshark is the basic pattern on sites with install restrictions.
- Should I use pktmon or netsh trace?
- If the OS has pktmon (Windows 10 / Windows Server 2019 and later), pktmon is the recommended starting point. Its commands are simple, it can tell you which network-stack component discarded a packet (the drop reason), and pcapng conversion is self-contained. netsh trace has the advantage when you are capturing on an older OS that does not have pktmon, when you also want to collect ETW events from Windows components as a scenario, or when you want the capture to survive a reboot with persistent=yes. Microsoft's troubleshooting material also recommends this order: pktmon first, then netsh trace if that is not enough.
- Why does traffic to localhost (127.0.0.1) not show up in Wireshark?
- Traffic to localhost does not pass through a physical NIC; it is turned around on the loopback path inside the OS. A normal capture that targets a physical adapter never sees it in the first place. In Wireshark, select the Adapter for loopback traffic capture provided by Npcap and you can capture loopback traffic. pktmon captures inside the network stack, so it can observe loopback traffic as well. Another common mix-up is that localhost resolves to IPv6 ::1, so the screen you were watching for 127.0.0.1 shows nothing. Confirm with the address stated explicitly.
- Can I see the contents of HTTPS (TLS) traffic in a packet capture?
- The application data itself is encrypted and cannot be seen. However, the skeleton of the conversation, such as TCP connection establishment and teardown, whether the TLS handshake succeeded, a RST teardown, and which side stopped responding, is visible even when encrypted, so most timeout investigations can proceed with TLS left as it is. If you need the contents, decryption via SSLKEYLOGFILE is an option, but only some TLS implementations such as Firefox and the Chrome family support it; Windows' built-in SChannel does not. Because the mechanism writes out secret key material, treat it as something for development environments only, if you use it at all.
- Is it safe to send a capture file to an external support desk?
- Sending it unchanged is dangerous. A capture contains the communication itself and can include credentials from cleartext protocols, cookies, API keys, and personal information. First, narrow the filter and the time window at capture time to the minimum you need, and before handing it over, extract only the target conversation with a Wireshark display filter and export that. For whatever still remains, agree with the recipient on how to handle the confidential parts (masking, or delivering them by another means) before you send it. Decide in advance how long capture files will be kept and when they will be deleted.