Interface requirements
S007 Interface Requirements
S007-IF-001 GET /api/v1/dns [P1]
Query the DNS filter status.
Success response (ApiResponse<DnsFilterStatus>):
{
"success": true,
"data": {
"running": true,
"listen_address": "10.200.0.1",
"listen_port": 53,
"upstreams": ["8.8.8.8:53", "8.8.4.4:53"],
"cache_entries": 142,
"queries_total": 5823,
"queries_allowed": 4901,
"queries_blocked": 922
}
}When the DNS filter is not running (e.g., bridge is down), running is false and counters are zero.
S007-IF-002 GET /api/v1/dns/cache [P2]
Query cache statistics and optionally list cached entries.
Query parameters:
entries(optional, boolean) -- iftrue, include the list of cached entries
Success response (ApiResponse<DnsCacheStats>) without entries:
{
"success": true,
"data": {
"entries": 142,
"max_entries": 10000,
"hits": 3201,
"misses": 1700,
"evictions": 12
}
}Success response with ?entries=true (ApiResponse<DnsCacheDetail>):
{
"success": true,
"data": {
"stats": {
"entries": 142,
"max_entries": 10000,
"hits": 3201,
"misses": 1700,
"evictions": 12
},
"entries": [
{
"hostname": "api.github.com",
"record_type": "A",
"ttl_remaining_secs": 187,
"cached_at": "2026-04-21T14:32:01Z"
}
]
}
}S007-IF-003 POST /api/v1/dns/cache/flush [P2]
Flush the DNS response cache.
Request body: none
Success response (ApiResponse<DnsCacheFlushResult>):
{
"success": true,
"data": {
"entries_flushed": 142
}
}S007-IF-004 CLI commands [P1]
outcall dns status # show DNS filter status
outcall dns test api.github.com # test a hostname against the rule engine
outcall dns test api.github.com --type MX # test with a specific record type
outcall dns cache # show cache statistics
outcall dns cache --entries # show cache statistics and list entries
outcall dns flush # flush the DNS cacheAll commands accept the global --socket <path> flag.
S007-IF-005 CLI output format [P1]
outcall dns status (running):
DNS Filter: active
Listen: 10.200.0.1:53
Upstreams: 8.8.8.8:53, 8.8.4.4:53
Cache: 142 entries
Queries: 5823 total (4901 allowed, 922 blocked)outcall dns status (not running):
DNS Filter: inactive (bridge not up)outcall dns test api.github.com (allowed):
Hostname: api.github.com
Record type: A
Decision: ALLOW
Matched rule: allow-github-api (10-github.yaml)outcall dns test evil.com (blocked):
Hostname: evil.com
Record type: A
Decision: BLOCK
Matched rule: (default policy)outcall dns cache:
Entries: 142 / 10000
Hits: 3201
Misses: 1700
Evictions: 12
Hit rate: 65.3%outcall dns cache --entries:
Entries: 142 / 10000
Hits: 3201
Misses: 1700
Evictions: 12
Hit rate: 65.3%
HOSTNAME TYPE TTL
api.github.com A 187s
registry.npmjs.org A 42s
pypi.org AAAA 291soutcall dns flush:
DNS cache flushed (142 entries cleared).All error output goes to stderr. Exit code 1 on error, 0 on success.
S007-IF-006 DNS wire protocol (RFC 1035) [P1]
The DNS server MUST comply with RFC 1035 for DNS message format. Specifically:
- Query and response messages MUST use the standard 12-byte header format
- The QR bit MUST be set to 1 (response) in all outgoing messages
- The AA (Authoritative Answer) bit MUST be set in NXDOMAIN responses
- The RA (Recursion Available) bit MUST be set in all responses
- The RD (Recursion Desired) bit from the query MUST be echoed in the response
- NXDOMAIN responses MUST use RCODE 3
- SERVFAIL responses (upstream failure) MUST use RCODE 2
S007-IF-007 resolv.conf format [P1]
The generated /etc/resolv.conf for agent containers MUST follow this exact format:
# Generated by outcalld -- do not edit
nameserver 10.200.0.1
options ndots:0The IP address is the bridge gateway IP, which varies by network configuration. No search or domain directives MUST be present.
S007-IF-008 DNS allow rule egress config [P1]
DNS policy rules may include an egress block to choose follow-up egress behavior:
version: "1"
rules:
- id: allow-dns-ports-ubuntu-com
condition: 'dns.query == "ports.ubuntu.com"'
action: allow
egress:
mode: direct_ip # or proxy
ports: [80, 443] # optional, direct_ip onlymode: proxykeeps enforcement at L7 (proxy/SNI path), with no direct L3/L4 hole.mode: direct_ipinserts dynamic nftables allows from resolved IPv4 (A) and IPv6 (AAAA) answers. IPv4 rules useip saddr/daddr; IPv6 rules useip6 saddr/daddr. When an IPv4 source address is used in an IPv6 rule context, it is expressed as an IPv4-mapped IPv6 address (::ffff:x.x.x.x).