conntrackd is a small, efficient conntrack event fanout logger written in Go. It listens for Linux conntrack/netfilter connection tracking events and optional enriches them with GEO location information before emitting structured logs. It's intended for lightweight monitoring, auditing, and integration with log pipelines.
- Listen for conntrack events (new/updated/destroyed connections)
- Enrich IP addresses with GEO location data
- Fanout to multiple log sinks (stream, syslog, journald, Loki)
- Linux (netlink/conntrack support required)
- Root privileges
- (Optional) MaxMind GeoIP2/GeoLite2 City database
Download the latest release from the releases page.
Start the event listener and logger.
sudo conntrackd run --sink.journal.enableFor further configuration, see the command-line options below.
conntrackd logs conntrack events to various sinks.
Protocol Support: Only TCP and UDP events are processed. All other protocols (ICMP, IGMP, etc.) are automatically ignored and never logged, regardless of filter rules.
You can use filters to control which TCP/UDP events are logged using a
Domain-Specific Language (DSL).
The --filter flag lets you specify filter rules:
sudo conntrackd run \
--filter "drop destination address 8.8.8.8" \
--filter "log protocol TCP and destination network PUBLIC" \
--filter "drop any" \
--sink.journal.enableFilter Rules:
- Rules are evaluated in order (first-match wins)
- Events are logged by default when no rule matches
--filterflag can be repeated for multiple rules- Use
drop anyas a final rule to block all non-matching events from being logged
Important: Filters control which conntrack events are logged, not network traffic. Traffic always flows normally; filters only affect logging.
Common Filter Examples:
# Don't log events to a specific IP
--filter "drop destination address 8.8.8.8"
# Log only NEW TCP connections (deny everything else)
--filter "log type NEW and protocol TCP"
--filter "drop any"
# Don't log DNS to specific server
--filter "drop destination address 10.19.80.100 on port 53"
# Don't log any traffic to private networks
--filter "drop destination network PRIVATE"
# Log only traffic from public IPs using TCP
--filter "log source network PUBLIC and protocol TCP"
--filter "drop any"See docs/filter.md for complete DSL documentation, including grammar, operators, and advanced examples.
conntrackd can be configured via command-line flags, configuration files, environment variables, or a combination of these methods.
By default, conntrackd searches for a configuration file named
conntrackd.(yaml|yml|json|toml) in /etc/conntrackd directory.
You can also specify a custom config file using the --config flag:
sudo conntrackd run --config /path/to/config.yamlConfiguration files support YAML, JSON, and TOML formats. See contrib/config.yaml for a complete example configuration file.
Configuration values can be set via environment variables with the
CONNTRACKD_ prefix:
export CONNTRACKD_LOG_LEVEL=debug
export CONNTRACKD_SINK_STREAM_WRITER=discard
sudo -E conntrackd runUse underscores (_) to represent nested keys:
sink.stream.writer β CONNTRACKD_SINK_STREAM_WRITER
Configuration values are applied in the following order (later overrides earlier):
- Default values
- Configuration file
- Environment variables
- Command-line flags
Note: Command-line flags always have the highest priority.
| Flag | Description | Default |
|---|---|---|
--config |
Path to configuration file | |
--filter |
Filter rule in DSL format (repeatable) | |
--geoip.database |
Path to GeoIP database | |
--log.level |
Log level (debug, info, warn, error) | info |
--sink.journal.enable |
Enable journald sink | |
--sink.syslog.enable |
Enable syslog sink | |
--sink.loki.enable |
Enable Loki sink | |
--sink.stream.enable |
Enable stream sink | |
--sink.syslog.address |
Syslog address | udp://localhost:514 |
--sink.loki.address |
Loki address | http://localhost:3100 |
--sink.loki.labels |
Loki labels (comma-separated key=value pairs) | |
--sink.stream.writer |
Stream writer (stdout, stderr, discard) | stdout |
conntrackd emits structured logs for each conntrack event. A typical log entry includes:
- type (connection event type)
- flow (connection flow identifier)
- src_addr, dst_addr (IP addresses)
- src_port, dst_port (port numbers)
- prot (transport protocol)
Additionally TCP field:
- state (TCP connection state)
GEO location fields for source and destination if applicable with prefixes
src_ and dst_:
- city (city name)
- country (country name)
- lat (latitude)
- lon (longitude)
Example log entry recorded by sink `syslog`
{
"event": {
"dst_port": 443,
"dst_addr": "2600:1901:0:b3ea::",
"flow": 221193769,
"prot": "TCP",
"src_port": 41348,
"src_addr": "2003:cf:1716:7b64:da80:83ff:fecd:da51",
"tcp_state": "LAST_ACK",
"type": "UPDATE"
},
"level": "INFO",
"logger.name": "samber/slog-syslog",
"logger.version": "v2.5.2",
"message": "UPDATE TCP connection from [2003:cf:1716:7b64:da80:83ff:fecd...",
"timestamp": "2025-11-15T09:55:25.647544937Z"
}Example log entry recorded by sink `journal`
{
"__CURSOR" : "s=b3c7821dbfce47a59b06797aea9028ca;i=6772d3;b=100da27bd...",
"_CAP_EFFECTIVE" : "1ffffffffff",
"EVENT_SRC_PORT" : "39790",
"_SOURCE_REALTIME_TIMESTAMP" : "1763200187611509",
"_SYSTEMD_CGROUP" : "/user.slice/user-1000.slice/session-1.scope",
"_SYSTEMD_OWNER_UID" : "1000",
"_SYSTEMD_SESSION" : "1",
"_EXE" : "/home/tschaefer/.env/bin/conntrackd",
"_HOSTNAME" : "bullseye",
"_GID" : "0",
"PRIORITY" : "6",
"_SYSTEMD_UNIT" : "session-1.scope",
"EVENT_DST_PORT" : "443",
"SLOG_LOGGER" : "tschaefer/slog-journal:v1.0.0",
"_TRANSPORT" : "journal",
"EVENT_SRC_ADDR" : "2003:cf:1716:7b64:da80:83ff:fecd:da51",
"_COMM" : "conntrackd",
"__MONOTONIC_TIMESTAMP" : "352829248481",
"EVENT_TCP_STATE" : "LAST_ACK",
"_MACHINE_ID" : "75b649379b874beea04d95463e59c3a1",
"_SYSTEMD_SLICE" : "user-1000.slice",
"_SYSTEMD_USER_SLICE" : "-.slice",
"__SEQNUM_ID" : "b3c7821dbfce47a59b06797aea9028ca",
"__REALTIME_TIMESTAMP" : "1763200187611631",
"__SEQNUM" : "6779603",
"_SYSTEMD_INVOCATION_ID" : "021760b3373342b98aaeabf9d12d8d74",
"EVENT_FLOW" : "3478798157",
"_PID" : "3794900",
"_CMDLINE" : "conntrackd run --service.log.level debug --service.log....",
"EVENT_PROT" : "TCP",
"_AUDIT_SESSION" : "1",
"_BOOT_ID" : "100da27bd8b94096b5c80cdac34d6063",
"_RUNTIME_SCOPE" : "system",
"_SELINUX_CONTEXT" : "unconfined\n",
"EVENT_DST_ADDR" : "2600:1901:0:b3ea::",
"_AUDIT_LOGINUID" : "1000",
"_UID" : "0",
"EVENT_TYPE" : "UPDATE",
"MESSAGE" : "UPDATE TCP connection from [2003:cf:1716:7b64:da80:83ff:fe..."
}
Example log entry recorded by sink `loki`
Loki allows maximum 15 labels per log entry. Therefore, location fields are attached as structured metadata to each log line.
{
"stream": {
"detected_level": "INFO",
"dst_addr": "2a01:4f8:160:5372::2",
"dst_addr_extracted": "2a01:4f8:160:5372::2",
"dst_city": "Falkenstein",
"dst_country": "Germany",
"dst_lat": "50.4777",
"dst_lon": "12.3649",
"dst_port": "443",
"dst_port_extracted": "443",
"flow": "4198226788",
"flow_extracted": "4198226788",
"host": "bullseye.u.coresec.zone",
"level": "INFO",
"prot": "TCP",
"prot_extracted": "TCP",
"service_name": "conntrackd",
"src_addr": "2003:cf:1716:7b64:da80:83ff:fecd:da51",
"src_addr_extracted": "2003:cf:1716:7b64:da80:83ff:fecd:da51",
"src_city": "Garmisch-Partenkirchen",
"src_country": "Germany",
"src_lat": "47.4906",
"src_lon": "11.1026",
"src_port": "56110",
"src_port_extracted": "56110",
"tcp_state": "SYN_SENT",
"tcp_state_extracted": "SYN_SENT",
"type": "NEW",
"type_extracted": "NEW"
},
"values": [
[
"1764163739570953291",
"NEW TCP connection from [2003:cf:1716:7b64:da80:83ff:fecd:da51]:56110..."
]
]
}Example log entry recorded by sink `stream`
{
"time": "2025-11-25T12:35:11.082791653+01:00",
"level": "INFO",
"msg": "NEW TCP connection from [2003:cf:1716:7b64:da80:83ff:fecd:da51]:4...",
"type": "NEW",
"flow": 4000057915,
"prot": "TCP",
"src_addr": "2003:cf:1716:7b64:da80:83ff:fecd:da51",
"dst_addr": "2a01:4f8:160:5372::2",
"src_port": 41756,
"dst_port": 443,
"tcp_state": "SYN_SENT",
"src_city": "Garmisch-Partenkirchen",
"src_country": "Germany",
"src_lat": 47.4906,
"src_lon": 11.1026,
"dst_city": "Falkenstein",
"dst_country": "Germany",
"dst_lat": 50.4777,
"dst_lon": 12.3649
}- Observing conntrack/netlink events typically requires elevated privileges.
- Keep GeoIP databases updated.
- Be careful with log storage; connection events may contain sensitive network metadata.
Contributions are welcome! Please fork the repository and submit a pull request. For major changes, open an issue first to discuss what you would like to change.
Ensure that your code adheres to the existing style and includes appropriate tests.
This project is licensed under the MIT License.