Skip to content

Latest commit

 

History

3 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 

Repository files navigation

USP (TR-369) Wireshark Dissector

A Wireshark Lua plugin that decodes USP — User Services Platform messages carried inside MQTT publish payloads, so packet captures show the full protocol structure instead of opaque protobuf bytes.

USP (specified by the Broadband Forum in TR-369) is the successor to TR-069 / CWMP for managing CPE devices. It serializes its messages as Protocol Buffers and rides over MQTT, WebSocket, STOMP, or UDS. Wireshark's stock MQTT dissector stops at the publish payload — this plugin teaches it to keep going.

What changes when you load it

Without the plugin every USP packet looks like an MQTT publish with an opaque blob:

USP without decoding

With it loaded, packets are reclassified as USP and you get full structural decoding — for example, a controller's GET request:

USP GET decoded

…and notifications, including the inner OperationComplete / Event / ValueChange / OnBoardRequest shapes:

USP NOTIFY decoded

Indicators are also given in the packet list:

Packet list

Features

  • Decodes the full USP Record wrapper (TR-369 §5.4):
    • NoSessionContextRecord, SessionContextRecord, MQTTConnectRecord, WebSocketConnectRecord, STOMPConnectRecord, UDSConnectRecord, DisconnectRecord
  • Decodes the inner USP Msg (all 22 message types — GET / SET / ADD / DELETE / OPERATE / NOTIFY / GET_SUPPORTED_DM / GET_INSTANCES / GET_SUPPORTED_PROTO / REGISTER / DEREGISTER, each with its _RESP counterpart, plus ERROR).
  • Decodes request/response body specifics: parameter paths and values, resolved paths, unique keys, error codes, search-expression filters, notification subtypes (Event, ValueChange, ObjectCreation/Deletion, OperationComplete, OnBoardRequest), event params, and operation arguments / output args.
  • Works on plain MQTT and on MQTT-over-TLS (with a Wireshark TLS key log).

Install

OS Plugin directory
Linux ~/.local/lib/wireshark/plugins/
macOS ~/.config/wireshark/plugins/ (or ~/.local/lib/wireshark/plugins/ on Homebrew builds)
Windows %APPDATA%\Wireshark\plugins\

Copy usp_dissector.lua into the directory, then in Wireshark do Analyze → Reload Lua Plugins (Ctrl+Shift+L). No restart required.

To verify it loaded: Help → About Wireshark → Plugins should list usp_dissector.lua.

Use

Open any capture containing MQTT traffic that carries USP records and look at the Protocol column. USP-bearing packets are now classified as USP and the detail pane shows a USP Record (TR-369) subtree beneath the MQTT layer.

Useful display filters:

Filter What it shows
usp_record Every USP-bearing packet
usp_msg.msg_type == 1 Only USP GET requests
usp_msg.msg_type == 2 Only USP GET_RESP
usp_msg.param_path contains "Device.WiFi." GETs that ask for WiFi paths
usp_record.to_id == "proto::agent-1" Traffic addressed to a specific endpoint
usp_msg.body_type == "Error" USP Error messages

For MQTT-over-TLS captures, configure Wireshark to use a (Pre)-Master-Secret log file (Edit → Preferences → Protocols → TLS → (Pre)-Master-Secret log filename), point the broker / agent at the same file via SSLKEYLOGFILE, and TLS will be decrypted live — the dissector picks up the decrypted MQTT payload automatically.

Limitations

  • MQTT transport only. WebSocket / STOMP / UDS-carried USP would each need a separate post-dissector hooked into their respective payload fields. The bytes are identical — only the carriage is different.
  • No SessionContext SAR reassembly. Each SessionContextRecord is dissected independently; the dissector does not stitch segmented payloads across multiple records.
  • JSON exports lose data. When exporting dissected packets to JSON via tshark -T json, the nested usp_msg subtree's repeated sub-elements share key names and collide when consumed by standard JSON parsers. For reliable downstream processing, re-parse the raw mqtt.msg hex bytes against the official .proto files.
  • Heuristic, not deterministic. Other binary MQTT payloads whose first byte happens to look like a protobuf tag in fields 1–16 / wire type 0 or 2 will be attempted; they fail safely (no tree output) but briefly show up as USP in the protocol column. Combining with a Content-Type filter narrows scope when needed.
  • 64-bit varint precision. The pure-Lua parser uses double-precision arithmetic for varints, exact up to 2^53. Beyond that (e.g. very large session IDs) the last few bits may round. Not seen in practice.

Development notes

  • Built against TR-369 1.0 / 1.3 / 1.4 captures — version is reported as a string in the Record envelope and shown verbatim by the dissector.
  • The protobuf parser is deliberately minimal (≈80 lines of Lua) and message-specific decoders are explicit per message type. No code-gen, no .proto runtime; you can read the entire mapping inline.
  • Field-number / wire-type assertions are loose: unknown or out-of-schema fields are simply skipped rather than fatal-erroring, which keeps the dissector robust against minor TR-369 revisions and vendor extensions.

References

Author

Benedikt Strobl (NSIDE ATTACK LOGIC GmbH) — developed with AI assistance

License

MIT — feel free to use, modify, and redistribute. No warranty.

About

This repository contains a dissector / plugin to parse USP (TR-369) in Wireshark.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages