dns

package
v0.5.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 14, 2026 License: Apache-2.0 Imports: 25 Imported by: 0

README

Actor DNS

Actor DNS relays DNS requests from the actor to the external world.

Code structure

Relay
  • Relay -- one per Ateom, holds upstream resolvers, and is used to create the per-Actor Server.
  • Relay.Serve() -- creates a per-Actor Server that manages DNS requests for the Actor, checked against the Actor's egress policy (see Egress policy). Returns a *Server.
Server

Server is the per-Actor state for the DNS traffic, including per-Actor concurrency limits (maxInFlightDNS and maxDNSConnections).

  • Server.pendingRequests map (UDP only):
    • Allocates a rewritten upstreamID (uint16) per in-flight UDP query to avoid transaction ID collisions across different actor source ports on the shared egress socket (and prevent predictable upstream IDs).
    • Maps upstreamID -> pending request entry:
      • clientRequestID (uint16) and clientAddr (net.Addr) to restore the original ID and route the response back.
      • Question metadata (QNAME, QTYPE, QCLASS) to validate that the response matches the query (RFC 5452).
      • upstreamIdx and deferredResp to track multi-upstream failover (SERVFAIL, NOTIMP, REFUSED, or timeout) and return the last failure response if all upstreams fail.
      • expiry timestamp for timing out stale entries and triggering failover via a periodic sweep ticker.
  • Server.Stop() -- cancels in-flight work, closes sockets, and stops serving DNS requests.
Implementation details
UDP handling
  • udphandler.go: struct udpHandler
  • Two goroutines per Server (plus a sweep ticker for timeouts/failover):
    • Ingress reader: reads datagrams from the actor-facing gateway net.PacketConn, runs onUDPRequest() (which validates the query, rewrites the transaction ID to upstreamID, and records the entry in pendingRequests), and sends the query on the egress socket.
    • Egress reader: reads datagrams from an unconnected worker-namespace net.PacketConn, runs onUDPResponse() to match and validate against pendingRequests, either fails over to the next upstream or restores clientRequestID and writes the answer back to clientAddr.
TCP handling
  • tcphandler.go: struct tcpHandler
  • Framing: each DNS message on a TCP stream is prefixed with a 2-byte big-endian length (uint16, RFC 1035 §4.2.2).
  • Dedicated upstream stream per connection (with pipelining and out-of-order response support per RFC 7766 §6.2.1.1):
    • Two goroutines per accepted TCP connection sharing a per-connection downstream write mutex:
      • Downstream reader: loops reading length-prefixed frames from the actor connection and calls onTCPRequest().
        • If forwarded: writes the unmodified frame directly to the dedicated upstream TCP connection.
        • If rejected with a synthesized reply (FORMERR, NOTIMP, REFUSED): writes the framed error response directly to the actor connection under the write mutex without contacting upstream.
        • On client EOF: half-closes the upstream write side (CloseWrite()) so in-flight pipelined responses can finish draining.
      • Upstream reader: loops reading length-prefixed frames from the upstream TCP connection, validates each frame via onTCPResponse(), and writes valid responses back to the actor connection under the write mutex.
DNS protocol layer

dnshandler.go: struct dnsHandler

UDP and TCP call up to the DNS protocol layer (golang.org/x/net/dns/dnsmessage), which inspects packets and returns transport-agnostic decisions:

  • Shared request validation (validateRequest):
    • Drop: packet < 12 bytes or QR == 1 (response bit set on a query).
    • Reply (synthesized response without upstream round-trip):
      • FORMERR (RCode = 1): malformed header/question or QDCOUNT != 1.
      • NOTIMP (RCode = 4): OpCode != 0 (non-standard query) or zone transfer QTYPE (AXFR, IXFR).
      • REFUSED (RCode = 5): disallowed by the Actor's egress policy (see Egress policy).
  • onUDPRequest(raw []byte, clientAddr net.Addr, upstreams []string) -> action:
    • Acquires an inFlight slot, runs validateRequest(), and on actionForward records the query in pendingRequests with a rewritten upstreamID.
  • onUDPResponse(raw []byte, from net.Addr) -> action:
    • Validates QR == 1, parses header + question, and matches against pendingRequests (verifying upstreamID, expected upstream source, and matching QNAME/QTYPE/QCLASS).
    • Returns Drop, Failover (on SERVFAIL, NOTIMP, or REFUSED when fallback upstreams remain), or Deliver (restoring clientRequestID and returning clientAddr).
  • onTCPRequest(raw []byte) -> action:
    • Runs validateRequest() and returns Drop, Reply, or Forward (unmodified frame).
  • onTCPResponse(raw []byte) -> action:
    • Validates QR == 1 and parses header + question, returning Drop or Deliver.
Egress policy

policy.go and evaluator.go: DNS bypasses the egress gateway, so the relay enforces the Actor's egress policy itself.

  • PolicySource supplies the Actor's EgressPolicy. The ateom passes atunnel's per-Actor source, which caches the policy for a few seconds so a policy created, updated, or deleted while the Actor runs takes effect without a restart, and keeps serving the stale cached entry if atelet is temporarily unreachable.
  • evaluator (evaluator.go) compiles the hostname and wildcard patterns from an EgressPolicy's http, https, and tls_passthrough rules and evaluates normalized QNAMEs via allowsHostname(qname).
  • egressPolicyCheck adapts the source to the dnsHandler's queryPolicy hook, caching the compiled *evaluator for the current *ateletpb.EgressPolicy pointer and consulting it for every query. Fetching uses the Server's context, so Stop() cancels a fetch in progress.
  • allowQuery evaluates a single dnsmessage.Question against a policy using evaluator.

Documentation

Overview

Package dns answers an actor's DNS from its sandbox's gateway namespace and writes the resolv.conf that points the actor at it.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func SandboxResolvConf

func SandboxResolvConf(nameserver string, podResolvConf []byte) []byte

SandboxResolvConf replaces the pod's nameservers with nameserver, the address the sandbox's DNS is served on, while preserving the pod's search domains and options for Kubernetes DNS.

func WriteRootfsResolvConf

func WriteRootfsResolvConf(rootfs string, content []byte) error

WriteRootfsResolvConf installs content at /etc/resolv.conf inside rootfs.

os.Root confines path traversal; unlinking prevents writes through existing links.

Types

type PolicySource added in v0.5.0

type PolicySource interface {
	// EgressPolicy returns the actor's current policy.
	//
	// Callers must not modify the policy.
	EgressPolicy(ctx context.Context) (*ateletpb.EgressPolicy, error)
}

PolicySource supplies the egress policy an actor's DNS queries are checked against.

type Relay added in v0.4.0

type Relay struct {
	// contains filtered or unexported fields
}

Relay validates and forwards UDP and TCP DNS queries to the worker pod's resolvers. It listens in the sandbox's gateway netns and dials from the worker's netns.

func NewRelay added in v0.4.0

func NewRelay(resolvConfPath string) (*Relay, error)

NewRelay reads nameservers from resolvConfPath and forwards to each on port 53.

func NewRelayForUpstreams added in v0.4.0

func NewRelayForUpstreams(upstreams []string) (*Relay, error)

NewRelayForUpstreams forwards to upstreams, each "host:port", tried in order.

func (*Relay) Serve added in v0.4.0

func (r *Relay) Serve(ctx context.Context, ns netns.Handle, policy PolicySource) (*Server, error)

Serve serves UDP and TCP DNS in the sandbox's local gateway namespace.

type Server

type Server struct {
	// contains filtered or unexported fields
}

Server is one sandbox's running DNS relay, returned by Relay.Serve.

func (*Server) Stop added in v0.4.0

func (s *Server) Stop(ctx context.Context) error

Stop cancels in-flight queries and connections, closes the sockets, and waits for the serving goroutines to exit or ctx to expire.

Directories

Path Synopsis
Package freemap implements an efficient mechanism for maintaining a map of free slots.
Package freemap implements an efficient mechanism for maintaining a map of free slots.
Package protocol contains helpers to manage encoding/decoding DNS protocol to/from a byte array.
Package protocol contains helpers to manage encoding/decoding DNS protocol to/from a byte array.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL