Outcall
SpecificationsS007 · DNS Filter

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) -- if true, 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 cache

All 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  291s

outcall 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:0

The 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 only
  • mode: proxy keeps enforcement at L7 (proxy/SNI path), with no direct L3/L4 hole.
  • mode: direct_ip inserts dynamic nftables allows from resolved IPv4 (A) and IPv6 (AAAA) answers. IPv4 rules use ip saddr/daddr; IPv6 rules use ip6 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).

On this page