NATS.io Support in Wireshark
About NATS
NATS.io is a lightweight messaging system gaining adoption in multiple industries. It is listed as an incubating project at the Cloud Native Computing Foundation.1 The server handles most of the logic and comes as a single binary written in Go which allows for an easy installation on many different systems. Clients are available in many programming languages because a simple, text-based protocol, the NATS Client Protocol, is used for communication between a client and the server. This keeps the effort of porting one to a new language manageable.
NATS is fundamentally engineered around the publish–subscribe pattern, where subscriptions are based on subjects2. The request-reply pattern is supported as well but it also uses subscriptions under the hood.
NATS Subjects
Subjects in NATS are organized into a hierarchy by separating components of the subject name with . characters. Wildcards can be used to match any component while filtering for subjects. * is a placeholder for any (complete) component and can be used multiple times in a filter. A > matches any components that come at or after its place. It can therefore be used only at the end of the subject name. Consider a subject structure like home.firstfloor.livingroom.temperature.
home.firstfloor.*.temperaturematches any room temperature on the first floorhome.*.*.temperaturematches the temperature anywhere in the homehome.firstfloor.>matches any sensor value from the first floor>matches any subject
Publish-Subscribe
The publish-subscribe mechanism works by clients telling the server the subjects they're interested in. Wildcards can be used to subscribe to a group of subjects at once. In addition to the subject, the clients generate and transmit a unique subscription ID. This ID is later used to identify messages as part of that subscription or to cancel the subscription.
The server keeps track of all active subscriptions and forwards each message published by a client to all clients subscribed to the relevant subject. This is the way how payload data is transmitted in NATS. Payload serialization, however, is not handled by NATS; any format (JSON, Protobuf, etc.) may be used.
Operation Overview
Messages are sent as UTF-8 encoded text through a TCP/IP socket. They take the general form OPERATION <arguments>␍␊[headers␍␊␍␊][payload␍␊], where arguments are separated by whitespace and headers are separated by ␍␊.3
| Operation | Direction | Headers | Payload |
|---|---|---|---|
INFO | C ← S | ||
CONNECT | C → S | ||
PUB | C → S | ✅ | |
HPUB | C → S | ✅ | ✅ |
SUB | C → S | ||
UNSUB | C → S | ||
MSG | C ← S | ✅ | |
HMSG | C ← S | ✅ | ✅ |
PING | C ↔ S | ||
PONG | C ↔ S | ||
+OK | C ← S | ||
-ERR | C ← S |
Motivation
As an engineer I see it as essential to keep up with technology as choices become more varied. While key ideas such as the publish-subscribe pattern are common across many protocols, their implementations differ. Knowing these differences is crucial when selecting the right protocol for a specific application.
My preferred way of learning about a technology is through experimentation. NATS offers a demo server to connect to,4 and because the protocol is text-based, you can simply interact with it over telnet. While I was following the demo tutorial, I recorded the traffic with Wireshark. I realized NATS support had just been added recently; right as I was about to write my own dissector and already had a working prototype. Some features from that prototype were missing, so I decided to port them into the official dissector. Tell me a better way to internalize how the protocol works!
Improving the NATS Dissector for Wireshark
Before sharing the details about the improvements I made, I briefly want to acknowledge that the official dissector is far more polished than my prototype. Reading its code, I discovered that Wireshark already exposes a built-in API for several functionalities I had implemented from scratch. The overall structure, however, closely mirrors my prototype which made porting the new features almost trivial.
Parsing the Options in INFO and CONNECT as JSON
The first enhancement is to parse the options found in INFO and CONNECT messages as JSON. Doing so makes it easy to filter on specific options. Wireshark already ships with a built-in JSON dissector, so the only work is to register it as a sub-dissector and pass the option bytes to it.

Writing the Operations in the Info Column
The second enhancement writes each NATS operation name into the Info column, giving you a quick, at-a-glance view of the traffic.

Adding Operations for +OK and -ERR
While experimenting I discovered that the dissector omitted the +OK and -ERRoperations. Because these messages are trivial, I added short functions for them to complete the protocol support.

Showing One Tree Item per Operation
Filtering for an operation name with the standard == operator is error-prone because it is case-sensitive, whereas NATS operation names are case-insensitive. To account for every variation you must either use Wireshark's matches filter or compare the string to an upper- or lower-cased variant.5
To sidestep this problem, the dissector now creates a dedicated tree item for each operation. Users can then filter by the concise field name (e.g., nats.msg) without worrying about case.

Dissecting Headers
Finally, I realized that each header can be dissected into its own proto item. This allows users to filter on a header’s name or its value directly (e.g., nats.header.name == "LUNCH" or nats.header.value == "burger"). The very first header field is always the NATS version string, which I parsed into separate major and minor fields so the version can be inspected and filtered in the usual numeric‑field style.

Conclusion
During this project, I had the opportunity to:
- familiarize myself with the NATS Client Protocol
- learn the basics of Go by diving into the inner workings of the NATS server
- get hands‑on experience with the C programming language again
- contribute to the Wireshark project
I expect the NATS Client Protocol support, along with my contributions, to land in Wireshark's 4.7 release, which is currently under development.
Subjects are comparable to topics in MQTT.