Extension system
May 29, 2026 ยท View on GitHub
Glutton's extension model has three layers, kept deliberately separate:
rules decide which named target should handle traffic
Go handlers own connection lifecycle, logging, producers, and fake responses
Spicy parsers extract structured fields from selected byte streams
Most extensions are a Go handler plus a rule. A Spicy parser is optional and only worthwhile when byte-level field extraction will be reused downstream. See Adding a protocol for the end-to-end walkthrough.
Handler responsibilities
A Go protocol handler owns runtime behavior:
- read from the connection or packet
- update timeouts when appropriate
- decide what response to write
- log process-level details
- call
ProduceTCP(...)orProduceUDP(...) - close the connection when done
- preserve fallback behavior for malformed or unknown input
TCP handler shape:
func HandleExample(ctx context.Context, conn net.Conn, md connection.Metadata, logger interfaces.Logger, h interfaces.Honeypot) error
UDP handler shape:
func HandleExample(ctx context.Context, srcAddr, dstAddr *net.UDPAddr, data []byte, md connection.Metadata) error
Registration happens through MapTCPProtocolHandlers(...) or MapUDPProtocolHandlers(...) in protocols/protocols.go.
Rule responsibilities
Rules route traffic before a handler runs. A conn_handler rule sends traffic to a registered handler key; a proxy_tcp rule sends it to an upstream host:port:
rules:
- match: tcp dst port 11211
type: conn_handler
target: memcache
- match: tcp dst port 9889
type: proxy_tcp
target: 127.0.0.1:9889
If the conn_handler target isn't registered in the handler map, the listener doesn't run a handler. See Configuration โ Rules for matching details.
Spicy responsibilities
Spicy parsers own byte-level structure, not honeypot behavior. A parser turns raw payload bytes into named fields like method, uri.path, headers[0].name. The Go side still decides how many bytes to read, which parser to call, what to log, which producer event to emit, and what response to write.
Current Spicy-backed paths:
HTTP::Requestis registered as parser keyhttp.TCP::Protocolis registered as parser keytcp.- The generic TCP handler path can use
TCP::Protocolto detect HTTP, RDP, or MongoDB. - HTTP payloads detected through the generic TCP path can be handled by
protocols/spicy/handlers/http.go.
A rule target of http calls the Go HTTP handler in protocols/tcp/http.go; it does not auto-select the Spicy HTTP handler.
Producer responsibilities
Handlers choose what to pass to producers. The envelope is fixed (producer.Event); the decoded payload is handler-specific. When adding a handler, decide what raw payload to include, what decoded structure is stable enough for downstream consumers, whether public addresses need sanitization, and what protocol name to pass to ProduceTCP(...) / ProduceUDP(...).
Tests
For a new handler or parser:
- handler registration test in
protocols/protocols_test.gowhen adding map keys - handler behavior tests beside the handler package
- parser tests under
protocols/spicy/for Spicy field contracts - rules tests under
rules/when rule behavior changes
Cover both successful and malformed input.