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.*.temperature matches any room temperature on the first floor
  • home.*.*.temperature matches the temperature anywhere in the home
  • home.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.

subscribe

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.

publish

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

OperationDirectionHeadersPayload
INFOC S
CONNECTC S
PUBC S
HPUBC S
SUBC S
UNSUBC S
MSGC S
HMSGC S
PINGC S
PONGC S
+OKC S
-ERRC 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.

INFO and CONNECT options are now dissected as JSON

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.

Operation name is now written in the Info column

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.

OK and ERR operations are supported

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.

Operations now have their own tree in the detail view

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.

Header fields are now completely dissected

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.

2

Subjects are comparable to topics in MQTT.