Tracing WSL Network Traffic Across Windows with Pktmon
Capture one reproducible WSL flow with Pktmon and Linux tools, interpret stack-level packet snapshots, and avoid false conclusions across NAT and mirrored mode.
When an application in WSL cannot reach a service, a successful ping, a failed curl, and a Windows firewall event can point to different layers. A packet capture is useful only when its vantage point is understood. Linux tcpdump sees traffic at Linux interfaces. Windows Packet Monitor (Pktmon) can observe packet flow and drops across Windows networking components. Neither tool, by itself, explains every transition between Linux, the WSL virtual network, Windows filtering, and a physical adapter.
This guide uses both tools to follow one bounded reproduction. It focuses on evidence collection and interpretation, not on changing WSL’s networking mode or applying a generic DNS fix. The chosen flow, address family, protocol, and WSL mode must match the failure being investigated.
First identify the flow and networking mode
Before capturing, record the WSL release, Windows build, distro, and whether networking is using default NAT or mirrored mode. Microsoft documents NAT as the default architecture and describes mirrored mode as a different networking model. DNS tunneling is another distinction: on supported configurations, DNS queries can be carried through a virtualization channel rather than an ordinary packet sent to a DNS server address. A packet capture that does not show a DNS packet therefore does not prove that name resolution was never attempted.
Choose a single test that is easy to reproduce, such as one curl request to a known HTTPS endpoint or a connection to a controlled internal service. Record the resolved destination, port, protocol, start time, and exact command. Avoid combining a DNS lookup, package update, browser session, and ping into one capture; unrelated traffic makes packet ordering ambiguous. If the failure is specific to IPv6, capture and reproduce IPv6 rather than silently testing IPv4 only.
From WSL, record the Linux view:
ip -brief address
ip route
getent ahosts example.com
Use getent because it exercises the configured name-service path rather than bypassing it with a manually selected resolver. Note that getent can succeed through a DNS mechanism that Pktmon does not observe as guest-originated UDP/TCP DNS traffic. Record the active networking settings from .wslconfig and the state of DNS tunneling if the incident concerns name resolution.
What Pktmon can and cannot tell you
Pktmon is an in-box Windows packet monitor designed to expose traffic across the networking stack. Microsoft specifically describes it as useful in virtualization and container networking scenarios. It can list active networking components, capture packet snapshots, count traffic and drops, and write an ETL log that can be converted to pcapng for inspection in a packet analyzer.
The word “snapshot” matters. A packet may be visible at multiple components as it traverses a binding stack, so multiple records do not necessarily mean the application retransmitted it. The Pktmon component list and packet metadata help connect those observations. Component IDs are runtime observations, not durable interface identities: Microsoft notes that IDs can change after a reboot or when the monitor driver restarts. Save pktmon list --json with each capture and do not interpret a remembered numeric ID as the same NIC on another system or boot.
Pktmon’s ETL is the richer evidence artifact. Conversion to pcapng is useful for Wireshark, but Microsoft documents that dropped packets are not included by default in the converted file. Keep the original ETL and the component listing when investigating a drop. If a pcapng is needed for the dropped-packet subset, export it separately with --drop-only; do not discard the ETL after conversion.
Capture a short Windows-side trace
Open an elevated PowerShell terminal if required by the Windows build and capture scenario. Save the component topology and inspect the current filters before changing them:
pktmon list --json | Out-File -Encoding utf8 .\wsl-components.json
pktmon filter list | Out-File -Encoding utf8 .\wsl-filters-before.txt
# This removes every Pktmon filter; run it only if a full reset is intended.
pktmon filter remove
pktmon filter add -p 443
pktmon filter remove removes all active packet filters, not just filters considered stale. Save the initial list and recreate any filters needed by another diagnostic session. The port filter matches traffic on port 443 whether it is a source or destination port; it does not distinguish direction. If you need a narrow host or protocol condition, use the supported pktmon filter add syntax for that build and verify the filter before starting. Filters can be applied to encapsulated inner traffic with the documented encapsulation option, but do not assume that a filter on an inner packet also explains the outer transport.
Start a bounded capture, reproduce once, inspect counters, and stop collection:
pktmon start --capture
# Reproduce the single failing flow from a WSL terminal.
pktmon counters --json | Out-File -Encoding utf8 .\wsl-counters.json
pktmon stop
Pktmon writes an ETL log in the configured/default output location. Confirm the actual file name and timestamp rather than assuming an old PktMon.etl is the new capture. Convert it for packet-level analysis while retaining the source file:
pktmon etl2pcap .\PktMon.etl --out .\wsl-flow.pcapng
pktmon etl2pcap .\PktMon.etl --drop-only --out .\wsl-drops.pcapng
The second export can be empty if no drops were logged. Capture duration and packet size should be limited to what the incident needs. Packet logs can contain application payload, internal hostnames, addresses, and timing metadata; preserve them as diagnostic evidence and avoid attaching an unrestricted trace to a public issue.
Capture the Linux-side view too
Where the relevant interface and privileges allow it, start a focused Linux capture just before reproducing the request:
sudo timeout 30 tcpdump -ni any -s 128 \
-w /tmp/wsl-flow.pcap 'tcp port 443'
This example captures a short window, uses Linux’s any pseudo-interface, and keeps only the first 128 bytes of each packet. That is generally useful for transport headers and a short protocol prefix, but it is not a complete-payload capture. Install tcpdump from the distribution’s package repository if it is not present. If the incident uses a specific interface, replace any after checking ip -brief address; if it uses UDP or another port, change the BPF filter accordingly.
Linux and Windows capture clocks should be compared using timestamps and an explicit time zone. Start both traces, emit one identifiable connection, and stop promptly. The Linux capture may show an address before NAT or other host processing, while the Windows capture can show different addresses at different components. Do not expect the guest source address, Windows virtual interface address, and physical network address to be identical throughout a NAT path. In mirrored mode, do not import assumptions from NAT mode either.
For a request that fails, compare the sequence rather than the packet count alone: Did the Linux process emit a SYN? Did a response reach the Linux interface? Did Windows observe a corresponding packet on a relevant component? Did a drop counter increment? Did the application fail before opening a socket? Pktmon counters provide a high-level view of packet propagation and reported drops; the detailed log is needed to investigate an individual flow. A counter difference narrows where to look but does not, by itself, prove which policy caused the drop.
Read the trace without over-interpreting it
Follow a flow using protocol, addresses, ports, TCP sequence progression, and timing. Compare component IDs with the saved topology. If a packet appears at adjacent Windows components, that can reflect observation at stack boundaries rather than duplicate application sends. If a SYN leaves Linux but there is no reply at the guest interface, the failure lies somewhere after that observation point, but the trace may not identify the responsible firewall, route, VPN filter, remote service, or return path without additional evidence.
For DNS, first distinguish three questions: did the application request name resolution, did the resolver select an address, and did the resulting connection work? getent ahosts helps test the name-service result. A conventional packet capture may show UDP/TCP DNS in some configurations, but a WSL DNS tunnel can bypass that packet path. If resolution works yet HTTPS fails, focus on the resolved address and transport flow rather than changing resolv.conf at random.
For localhost, do not assume the same capture points apply as for an Internet-bound packet. WSL localhost forwarding and mirrored networking can take paths that differ from NAT traffic through a physical adapter. Test the specific direction: Windows to a WSL listener, WSL to a Windows listener, or a Linux client to a Linux container. Record where the listening socket is bound with ss -lntup and include that evidence with the trace.
A measurable diagnostic closeout
A useful capture bundle contains a short incident timeline, WSL/Windows versions, networking mode, the exact reproduction command, Linux interface and route output, pktmon list --json, the original ETL, any pcapng exports, relevant Pktmon counters, and the Linux pcap if collected. Record whether DNS tunneling was enabled and whether the failure involved NAT, mirrored mode, localhost forwarding, VPN, or an external destination. State which observations are absent as carefully as those present.
Define success before trying a repair: for example, the same one-request reproduction completes, the Linux capture shows the expected handshake and response, and the Windows capture shows the flow crossing the expected components without a relevant drop. Re-run after one controlled configuration change, not a bundle of firewall, DNS, route, and mode changes. A short before-and-after trace can identify which layer changed; a large unfiltered capture usually cannot.
The practical discipline is to capture at two known vantage points, preserve native evidence, and interpret each observation within the configured WSL network architecture. Pktmon is most valuable as stack-level evidence, not as a magic packet decoder that collapses the Linux guest and Windows host into one interface.
Related:
- WSL2’s Networking Modes: NAT and Mirrored, Explained
- Fixing WSL2 Networking and DNS Resolution Failures
Sources: