Skip to content

Allowing a host does not authorize its _service._proto.<host> SRV lookups — apt mirror discovery is denied under the enforcing firewall #288

Description

@Lupus

What

Under an enforcing izba firewall, DNS queries for RFC 2782 service-discovery names (_service._proto.<host>, e.g. _http._tcp.archive.ubuntu.com) are denied even when <host> itself is on the allow-list, because the authorization check matches the QNAME literally against host_rules/wildcard globs and a two-label _service._proto. prefix never matches either form. Real clients (apt is the reported case; other SRV/service-discovery-aware clients are equally affected) that legitimately query this shape before connecting to an allowed host are broken, while the failure surfaces only as opaque denied-DNS netlog noise rather than a clear signal.

This item covers narrowing the DNS authorization gate so that a leading RFC 2782 _service._proto. (and equivalently shaped RFC 9460 _port._proto.) label pair is stripped once, with the remainder then authorized exactly as any other queried name — no widening of the allow-list, no rewriting of policy.yaml, no change to the existing exact/wildcard matching semantics for ordinary names. It also covers making a real client's dependence on this working (apt/mirror discovery) verifiable end to end, and closing the related decision gap for HTTPS/SVCB query types under the same enforcing path.

Why

The documented user workflow — seed the allow-list from observed traffic, enable the firewall, expect the previously-observed traffic to keep working — currently fails for any client that performs service discovery via SRV-shaped DNS queries before connecting to an allowed host. The reporting user hit this directly with apt-get update against an allowed archive.ubuntu.com/security.ubuntu.com. apt itself tolerates the failure via fallback, which is why the breakage went unnoticed until observed live, but the same gate would hard-fail any client that actually depends on the SRV answer, and today's netlog denial gives the user no actionable signal that "the host is allowed, but this particular name form isn't." Since the underscore-prefixed name is controlled by the same domain owner as the host it's derived from, authorizing it once the host is authorized does not meaningfully widen the exfiltration surface the QNAME-gate exists to close.

In Scope

  • When an enforcing policy evaluates a DNS query whose name has a leading service-discovery label pair in the RFC 2782 shape (_service._tcp/_service._udp) or the equivalent RFC 9460 shape, authorization is derived from whether the remaining (stripped) name is authorized under today's exact/wildcard rules — not from a separate allow-list entry.
  • The QNAME-regardless-of-qtype posture is preserved for every other query shape; this change only narrows what counts as "the queried name" for this one prefix pattern, and only strips a single such prefix (a doubled or malformed prefix, or a non-RFC-shaped underscore label, does not qualify and is denied as today).
  • The netlog continues to record the full literal queried name for a derived-allow decision (never hides or collapses it), with a verdict and rule explanation that make clear the allow was derived from the parent host being allowed.
  • Test coverage proving: the RFC-shaped prefix is stripped and authorized against an allowed host; the same prefix against a non-allowed host is still denied; a non-RFC-shaped underscore label is still denied; a doubled prefix is still denied; the derivation happens without touching the rego policy-compilation path (existing byte-identity guarantees for that path are preserved).
  • An end-to-end test that seeds the allow-list the way the documented workflow instructs, enables enforcement, and confirms a real apt-based client succeeds against a real image — plus confirms the netlog shows the SRV-shaped queries as allowed.
  • An explicit, documented decision on how HTTPS/SVCB-type queries are handled under the same enforcing path (kept as today, or changed), with a test pinning whichever behavior is chosen.

Out of Scope

  • Any change to the GUI netlog's presentation of denied-DNS rows or its allow/seed actions on port-53 rows — tracked separately.
  • Making the permitted DNS query-type set itself policy-driven/configurable.
  • DNSSEC or EDNS passthrough behavior.
  • Changing the existing NXDOMAIN-vs-REFUSED decision for denied queries.

Acceptance Criteria

  • A DNS query of the form _service._proto.<host> (RFC 2782 shape) is allowed under an enforcing policy when <host> is allowed (exact or wildcard match), without any new allow-list entry being required or written.
  • The same prefix against a host that is NOT allowed is still denied (NXDOMAIN), and this is covered by a test.
  • A leading underscore label that is not in the RFC-shaped _service._proto form is still denied, and this is covered by a test.
  • A doubled/malformed prefix (e.g. two consecutive _service._proto. pairs) is still denied, and this is covered by a test.
  • The rego policy-compilation output is unchanged for this class of input (existing byte-identity/parity guarantee still holds) — the derivation happens only in the pre-rego authorization step.
  • The netlog entry for a derived-allow decision shows the full literal queried name, an allow verdict, and an explanation that the allow was derived from the parent host's authorization.
  • A real-VM end-to-end test seeds the allow-list per the documented workflow (allowing the mirror host(s) apt uses), enables enforcement, runs apt-get update in a real Ubuntu-based image, and asserts it succeeds; the test also asserts the netlog shows the SRV-shaped lookups as allowed.
  • A written decision on HTTPS/SVCB query-type handling under enforcement is recorded, with a test pinning the chosen behavior.

INVEST Notes

Code pointers gathered during discovery, for implementer reference only (non-binding, may have shifted by execution time): DNS authorization gate around crates/izba-core/src/daemon/egress/router.rs:617-651 (dns_loop, policy.allows_name); rego resolvable logic in egress.rego:104-127; NXDOMAIN-vs-REFUSED decision in crates/izba-proto/src/dns.rs:56-64 and docs/superpowers/specs/2026-07-24-izba-dns-egress-enforcement-design.md:196-202; qtype permitting/NOTIMP logic in sys_resolver.rs:25-44,490-539 (HTTPS/SVCB currently answer NOTIMP); existing but insufficient e2e coverage at crates/izba-core/tests/integration.rs:1683-1788 (mitm_firewall_allows_and_denies_real_vm); documented user workflow in README.md:159 and docs/superpowers/specs/2026-07-20-bare-host-web-ports-design.md:7,53.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    effort:MMedium: multiple files or components; some design thoughtpriority:P2Medium: planned work; not blocking anything criticaltype:bugIncorrect behaviour deviating from a documented or expected contract

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions