A deep packet inspection engine for C.
Link libmmt_core, register the protocol fields you need, and process packets from a
pcap or a live interface. MMT‑DPI classifies 643 protocols, extracts
6,334 typed attributes, and tracks per-flow sessions — all behind one callback API.
#include "mmt_core.h" // Called after MMT classifies and extracts each packet. int on_packet(const ipacket_t *ipacket, void *args) { uint32_t *len = get_attribute_extracted_data_by_name(ipacket, "META", "PACKET_LEN"); if (len) printf("packet size: %u\n", *len); return 0; } int main(void) { init_extraction(); char errbuf[1024]; mmt_handler_t *h = mmt_init_handler(DLT_EN10MB, 0, errbuf); register_extraction_attribute_by_name(h, "META", "PACKET_LEN"); register_packet_handler(h, 1, on_packet, NULL); // ... feed packets (pcap or live) — see the API section ... }
Traffic moved on. Most parsers didn't.
Fixed-protocol tools can't follow traffic as it shifts to QUIC, HTTP/2, and 5G control planes. Hand-rolled parsers turn every new protocol into a brittle byte-offset rewrite — and they fall over on malformed or fragmented input.
Offset math everywhere
Every field is a hardcoded slice. One spec change, one option flag, and your parser silently returns garbage.
Blind to modern transports
QUIC, HTTP/2, DTLS, 5G NAS/NGAP. If your stack can't classify them, half your traffic is "unknown."
Breaks under fragmentation
Out-of-order, overlapping, duplicated segments, IP fragmentation evasion — the cases that matter most are the ones that crash naive code.
One engine you query by name.
Register the fields you care about by (protocol, attribute). The engine classifies
every packet, extracts your fields, reassembles sessions, and calls you back — battle-tested across
a decade of Montimage monitoring products.
643 protocols, auto-detected
Classification across the full TCP/IP stack and application layer — not by port number, but by payload signature. From Ethernet to QUIC to S7COMM.
6,334 named attributes
Pull any protocol field — IPs, ports, headers, payload values — by name. No manual offset math, no per-protocol glue code in your application.
Flow tracking & stats
Per-flow RTT, retransmissions, byte and packet counts, sub-session statistics. TCP reassembly handles out-of-order, overlap, and retransmission.
Extensible by design
Cover a protocol MMT doesn't ship yet by adding a module: declare its fields and classification logic and register it with the core at build time.
Mobile-core ready
NAS, S1AP, NGAP, GTPv2, Diameter, GTP — extract IMSI and control-plane fields for mobile-network monitoring and security.
Built for line rate
Lean C with a callback-driven API, static-analysis-hardened (PVS-Studio, cppcheck). Designed to run inside high-throughput probes.
From one attribute to live session analysis — in real code.
The same four calls scale from a five-line program to a live probe. Pick a tier — every
snippet compiles against libmmt_core (link with
-lmmt_core -ldl -lpcap).
#include <pcap.h> #include "mmt_core.h" // Fires after MMT classifies & extracts each packet. int on_packet(const ipacket_t *ipacket, void *args) { uint32_t *len = get_attribute_extracted_data_by_name(ipacket, "META", "PACKET_LEN"); if (len) printf("packet size: %u\n", *len); return 0; } int main(int argc, char **argv) { init_extraction(); char errbuf[1024]; mmt_handler_t *h = mmt_init_handler(DLT_EN10MB, 0, errbuf); register_extraction_attribute_by_name(h, "META", "PACKET_LEN"); register_packet_handler(h, 1, on_packet, NULL); // Feed packets from a .pcap file. pcap_t *pcap = pcap_open_offline(argv[1], errbuf); struct pcap_pkthdr ph; struct pkthdr hdr; const u_char *data; while ((data = pcap_next(pcap, &ph))) { hdr.ts = ph.ts; hdr.caplen = ph.caplen; hdr.len = ph.len; packet_process(h, &hdr, data); } mmt_close_handler(h); close_extraction(); }
Adapted from the bundled src/examples/packet_handler.c. The handler returns int (the callback contract); "META"/"PACKET_LEN" is a built-in meta attribute available on every packet.
#include "mmt_core.h" int on_packet(const ipacket_t *ipacket, void *args) { uint32_t *src = get_attribute_extracted_data_by_name(ipacket, "ip", "src"); uint32_t *dst = get_attribute_extracted_data_by_name(ipacket, "ip", "dst"); uint16_t *port = get_attribute_extracted_data_by_name(ipacket, "tcp", "dest_port"); mmt_header_line_t *host = get_attribute_extracted_data_by_name(ipacket, "http", "host"); if (src && dst && port) { uint8_t *s = (uint8_t*)src, *d = (uint8_t*)dst; // IP = 4 octets, net order // host is an mmt_header_line_t (ptr + len) — not a null-terminated string. printf("%u.%u.%u.%u → %u.%u.%u.%u:%u %.*s\n", s[0],s[1],s[2],s[3], d[0],d[1],d[2],d[3], *port, host ? (int)host->len : 1, host ? host->ptr : "-"); } return 0; } int main(void) { init_extraction(); char errbuf[1024]; mmt_handler_t *h = mmt_init_handler(DLT_EN10MB, 0, errbuf); // Register the fields you care about — by (protocol, attribute) name. register_extraction_attribute_by_name(h, "ip", "src"); register_extraction_attribute_by_name(h, "ip", "dst"); register_extraction_attribute_by_name(h, "tcp", "dest_port"); register_extraction_attribute_by_name(h, "http", "host"); register_packet_handler(h, 1, on_packet, NULL); // ... same pcap / packet_process() loop as Tier 1 ... }
Each attribute has a typed value — numeric fields come back as uint*_t*, while header strings like http/host are mmt_header_line_t* (a ptr+len pair, not null-terminated). Names map to MMT's 6,334 attributes; the engine classifies by payload signature, so these resolve regardless of port. See MMT-Attributes.
#include <pcap.h> #include <inttypes.h> // PRIu64 #include "mmt_core.h" // Called periodically per active session — read flow-level stats. void on_session(const mmt_session_t *s, void *args) { printf("session %"PRIu64": %"PRIu64" pkts, %"PRIu64" bytes\n", get_session_id(s), get_session_packet_count(s), get_session_byte_count(s)); } // pcap delivers each frame straight into MMT. void on_capture(u_char *user, const struct pcap_pkthdr *ph, const u_char *data) { mmt_handler_t *h = (mmt_handler_t*)user; struct pkthdr hdr = { .ts = ph->ts, .caplen = ph->caplen, .len = ph->len }; packet_process(h, &hdr, data); } int main(int argc, char **argv) { init_extraction(); char errbuf[1024]; mmt_handler_t *h = mmt_init_handler(DLT_EN10MB, 0, errbuf); // Report each session on a timer (0 = include incomplete packets). register_session_timer_handler(h, on_session, NULL, 0); // Capture live from an interface and pump frames into MMT. pcap_t *pcap = pcap_open_live(argv[1], 65535, 1, 1000, errbuf); pcap_loop(pcap, -1, on_capture, (u_char*)h); }
Session accessors expose packet/byte counts, uplink/downlink splits, and more. Built-in tcp/rtt and tcp/retransmission attributes add per-flow timing. Run live captures with sudo.
Adding a protocol MMT doesn't cover yet is a library-level extension: a module implements
init_proto_<name>_struct(), declares its fields, and registers with the core at
build time — see Adding New Protocols. Full runnable examples live in
src/examples/.
From Ethernet to 5G, classified out of the box.
A selection of the 643 protocols MMT‑DPI recognizes — across the TCP/IP stack, application layer, mobile core, and industrial/OT.
The extraction layer under real systems.
Intrusion detection & security monitoring
Feed classified, attribute-level events into detection engines. MMT-DPI powers Montimage's network security monitoring and IP-fragmentation evasion detection.
5G & mobile network analysis
Decode control-plane signaling (NGAP, NAS, S1AP, Diameter). Underpins 5GReplay, a 5G traffic fuzzer presented at ARES 2021.
IoT & industrial monitoring
Classify OT/industrial protocols (S7COMM, COTP) and IoT traffic. Deployed in security-monitoring frameworks on Fed4Fire+ testbeds.
Traffic analytics & QoE
Session-level RTT, retransmissions, and per-flow counters give you the raw signals for quality-of-experience and performance analytics.
A decade of peer-reviewed work runs on this engine.
MMT-DPI is the data-extraction core of the wider Montimage Monitoring Tool (MMT) suite, cited and evaluated across DPI, IoT, 5G, and intrusion-detection research.
Get the library, then compile against it.
Install the SDK to /opt/mmt/dpi (headers in include/, libmmt_core in lib/), then build your program. Linux: Debian/Ubuntu, Fedora/RHEL, Arch, Alpine, openSUSE.
Common questions
What exactly is MMT-DPI?
A high-performance C library for deep packet inspection. It classifies network traffic into 643 protocols and lets you extract 6,334 named, typed attributes from packets, server logs, and structured events — for real-time analysis. It's the extraction core inside the broader Montimage Monitoring Tool (MMT) suite.
Which platforms are supported?
Linux only. Tested across Debian/Ubuntu, Fedora/RHEL, Arch, Alpine, and openSUSE, with GCC or Clang, plus ARM cross-compilation. macOS and Windows are not currently supported.
How do I add a protocol that isn't covered?
Write a plugin. You declare the protocol's attributes and its classification logic as a modular plugin and drop it in — no changes to the core engine. See the Adding New Protocols guide.
Is it really free? What's the license?
Yes — MMT-DPI is open source under the Apache License 2.0. You can use it commercially, modify it, and ship it, subject to the license terms. No license keys, no usage caps.
Does it classify by port number?
Not by default. Classification is driven by payload signatures (with hostname- and IP-range-based methods), so it identifies protocols on non-standard ports and across modern transports. Port number is treated as the weakest signal — a last-resort hint consulted only after the signature-based methods return unknown, and only if you explicitly opt in with enable_port_classify() (disabled by default).
Can it handle fragmented or out-of-order traffic?
Yes. TCP reassembly (enable it per handler) reconstructs payloads across out-of-order, overlapping, and retransmitted segments, and the engine raises events for IP-fragmentation conditions — including evasion patterns like overlapping, duplicated, and too-many fragments.
Stop writing byte-offset parsers.
Start querying packets by name.
643 protocols, 6,334 attributes, plugin-extensible — open source under Apache-2.0. One command and you're running.