Outcall
SpecificationsS007 · DNS Filter

Acceptance scenarios

S007 Acceptance Scenarios

S007-AS-001 Allowed query resolved [P1]

Given outcalld is running with the bridge up and DNS filter active And a rule exists: condition: dns.query == "api.github.com", action: allow When a container on the outcall network sends a DNS query for A api.github.com Then outcalld evaluates the query against the rule engine And the rule engine returns ALLOW And outcalld forwards the query to the upstream resolver And the upstream response (with the real IP address) is returned to the container And a debug-level log entry records the query, decision, matched rule, and upstream latency.

S007-AS-002 Blocked query returns NXDOMAIN [P1]

Given outcalld is running with the bridge up and DNS filter active And a rule exists: condition: dns.query.endsWith(".evil.com"), action: block When a container sends a DNS query for A malware.evil.com Then outcalld evaluates the query against the rule engine And the rule engine returns BLOCK And outcalld returns an NXDOMAIN response with an SOA record in the authority section And the container receives NXDOMAIN and does not learn the real IP And a debug-level log entry records the query, decision, and matched rule.

S007-AS-003 No matching rule defaults to block [P1]

Given outcalld is running with the bridge up and DNS filter active And no rule matches the hostname random-unknown-site.com When a container sends a DNS query for A random-unknown-site.com Then the rule engine returns BLOCK (default policy) And outcalld returns NXDOMAIN And the log entry shows matched_rule: null and decision: block.

S007-AS-004 DNS server starts with bridge [P1]

Given outcalld is running but the bridge is not yet up When the user runs outcall bridge up And the bridge comes up with gateway 10.200.0.1 Then the DNS server binds to 10.200.0.1:53 on both UDP and TCP And outcall dns status shows running: true with the correct listen address And an info-level log entry records the DNS server startup.

S007-AS-005 Graceful shutdown drains queries [P1]

Given outcalld is running with the DNS filter active And a DNS query is currently being forwarded to an upstream When outcalld receives a shutdown signal Then the DNS server stops accepting new queries And the in-flight query completes (or times out within 5 seconds) And all UDP and TCP sockets are closed And an info-level log entry records the DNS server shutdown.

S007-AS-006 Container resolv.conf points at outcalld [P1]

Given outcalld is running with bridge gateway 10.200.0.1 When a container is started on an outcall network Then the container's /etc/resolv.conf contains nameserver 10.200.0.1 And no other nameserver lines are present And options ndots:0 is set And DNS queries from the container go through outcalld.

S007-AS-007 Upstream failover on timeout [P2]

Given outcalld is configured with --dns-upstream 10.0.0.1:53,8.8.8.8:53 And the first upstream (10.0.0.1) is unreachable When a container sends an allowed DNS query Then outcalld attempts the first upstream And after DNS_UPSTREAM_TIMEOUT_MS elapses, falls back to the second upstream (8.8.8.8) And the response from the second upstream is returned to the container And a warn-level log entry records the first upstream's failure.

S007-AS-008 Cached response served [P2]

Given outcalld has previously resolved A api.github.com and cached the response And the cache entry has not expired When a container sends another DNS query for A api.github.com Then outcalld evaluates the query against the rule engine (cache does not bypass policy) And the rule engine returns ALLOW And the cached response is returned without contacting the upstream And the TTL values in the response are decremented to reflect elapsed time And the log entry shows cached: true.

S007-AS-009 Cache invalidated on rule reload [P2]

Given outcalld has cached DNS responses for several hostnames When the rule engine reloads rules (via API or file watch) Then the entire DNS cache is flushed And subsequent queries are forwarded to upstream resolvers And an info-level log entry records the cache flush with the number of entries cleared.

S007-AS-010 TCP fallback for large responses [P1]

Given outcalld is running with the DNS filter active When a container sends a UDP DNS query for a hostname whose response exceeds 512 bytes And the upstream returns a truncated response (TC bit set) Then outcalld retries the query to the upstream over TCP And the full response is returned to the container over TCP.

S007-AS-011 CLI DNS filter status [P1]

Given outcalld is running with the DNS filter active When the user runs outcall dns status Then the CLI prints the DNS filter status including listen address, upstreams, cache entries, and query counters And the command exits with code 0.

S007-AS-012 CLI DNS test query [P1]

Given outcalld is running with the DNS filter active When the user runs outcall dns test api.github.com Then outcalld evaluates the hostname against the rule engine (without actually sending a DNS query) And the CLI prints the decision (allow/block) and the matched rule And the command exits with code 0.

S007-AS-013 Daemon not running (CLI) [P1]

Given outcalld is not running When the user runs any outcall dns subcommand Then the CLI prints Error: cannot connect to outcalld at <socket> -- is it running? And the command exits with code 1.

S007-AS-014 DNSSEC records passed through [P2]

Given outcalld is running with the DNS filter active And a query is allowed by the rule engine When a container sends a DNS query with the DO (DNSSEC OK) bit set Then outcalld forwards the query to the upstream with the DO bit preserved And the upstream response including RRSIG, DNSKEY, DS, NSEC, or NSEC3 records is returned to the container unmodified.

S007-AS-015 Multiple query types handled [P1]

Given outcalld is running with the DNS filter active And a rule allows dns.query == "mail.example.com" When a container sends an MX query for mail.example.com Then outcalld evaluates with dns.record_type == "MX" And the query is forwarded to the upstream And the MX response is returned to the container.

On this page