watchers
watchers
¶
Live blocked-access event stream for shield watch.
Multiplexes three event sources into a single JSON-lines stream:
- DNS log — tails the per-container dnsmasq query log and emits events for blocked domain lookups.
- Audit log — tails
audit.jsonland surfaces shield lifecycle events (allow, deny, up, down, setup, teardown). - NFLOG — reads denied packets via
AF_NETLINKand emits events for raw-IP connections that bypassed DNS. Optional — graceful degradation when netlink is unavailable.
__all__ = ['AuditLogWatcher', 'DnsLogWatcher', 'DomainCache', 'NflogWatcher', 'WatchEvent']
module-attribute
¶
WatchEvent(ts, source, action, container, domain='', query_type='', dest='', detail='', port=0, proto=0, extra=dict())
dataclass
¶
A single watch event emitted to the output stream.
Core fields (always present): ts, source, action, container.
DNS-specific: domain, query_type.
Audit/NFLOG: dest, detail, port, proto.
ts
instance-attribute
¶
source
instance-attribute
¶
action
instance-attribute
¶
container
instance-attribute
¶
domain = ''
class-attribute
instance-attribute
¶
query_type = ''
class-attribute
instance-attribute
¶
dest = ''
class-attribute
instance-attribute
¶
detail = ''
class-attribute
instance-attribute
¶
port = 0
class-attribute
instance-attribute
¶
proto = 0
class-attribute
instance-attribute
¶
extra = field(default_factory=dict)
class-attribute
instance-attribute
¶
to_json()
¶
Serialise to a compact JSON line, omitting empty optional fields.
Every string value passes through the producer-side
WIRE_SPEC(safe-string) sanitiser — container-controlled
bytes (DNS query name, dest IP, audit detail) reach this
method straight from kernel logs / dnsmasq output, so the
boundary lives here, not in any caller.
Source code in src/terok_shield/watchers/_event.py
AuditLogWatcher(audit_path, container)
¶
Tail audit.jsonl and yield events for shield lifecycle changes.
Open audit_path and seek to end.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
audit_path
|
Path
|
Path to the per-container |
required |
container
|
str
|
Container name (for event metadata). |
required |
Source code in src/terok_shield/watchers/audit_log.py
fileno()
¶
close()
¶
poll()
¶
Read new audit lines and return watch events.
Source code in src/terok_shield/watchers/audit_log.py
DnsLogWatcher(log_path, state_dir, container)
¶
Tail the dnsmasq query log and yield events for blocked domains.
Opens the log file, seeks to the end, and watches for new query lines.
Open log_path, seek to end, and load the initial allowed domain set.
Source code in src/terok_shield/watchers/dns_log.py
fileno()
¶
close()
¶
poll()
¶
Read new lines and return events for blocked queries.
Source code in src/terok_shield/watchers/dns_log.py
DomainCache(state_dir)
¶
IP-to-domain reverse lookup cache.
Initialise with the dnsmasq log path derived from state_dir.
Source code in src/terok_shield/watchers/domain_cache.py
lookup(ip)
¶
refresh()
¶
Reload the IP-to-domain mapping from the dnsmasq query log.
On OSError the previous cache is preserved.
Source code in src/terok_shield/watchers/domain_cache.py
NflogWatcher(sock, container)
¶
Read NFLOG messages via AF_NETLINK and yield events for denied packets.
Wrap an already-bound NFLOG netlink socket.
Use create instead of calling this directly.
Source code in src/terok_shield/watchers/nflog.py
create(container, group=NFLOG_GROUP)
classmethod
¶
Create and bind an NFLOG watcher, or return None on failure.
Failure is expected in environments without AF_NETLINK support,
unprivileged containers, or missing kernel modules.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
container
|
str
|
Container name (for event metadata). |
required |
group
|
int
|
NFLOG group number to subscribe to. |
NFLOG_GROUP
|
Source code in src/terok_shield/watchers/nflog.py
fileno()
¶
close()
¶
poll()
¶
Read pending NFLOG messages and return watch events.