Skip to main content
Configure a sandbox’s network stack: a first-match-wins egress/ingress policy, published ports, DNS interception, TLS interception, and secret-violation handling. See Networking for the conceptual overview and TLS Interception for proxy details.

Typical flow

The default policy denies egress except for an implicit allow-public rule (plus DNS), and allows ingress with no rules. See the defaults rationale for the asymmetry. NetworkPolicy and the builders live in microsandbox_network; NetworkPolicy is also re-exported from the crate root as microsandbox::NetworkPolicy.

NetworkPolicy static methods

A NetworkPolicy is an ordered rule list plus two per-direction defaults, evaluated first-match-wins. Compose common access shapes with from_profiles(); for anything custom, start from builder().

NetworkPolicy::builder()

Start the fluent NetworkPolicyBuilder. The primary construction path: string inputs (.ip, .cidr, .domain, .domain_suffix) are stored raw and parsed at build(), so the chain stays clean and the first parse or validation failure surfaces as BuildError.

Returns

Empty builder.

NetworkPolicy::none()

No network access: deny everything in both directions, no rules. This is the policy set by SandboxBuilder::disable_network().

NetworkPolicy::allow_all()

Unrestricted network access: allow everything in both directions, no rules.

NetworkPolicy::from_profiles()

Build a deny-by-default policy from composable NetworkProfile values. Duplicate profiles are ignored, the generated rules use canonical Public, Private, Host order, and every non-empty profile set receives exactly one narrow gateway DNS rule. An empty profile set permits no egress and adds no DNS. Ingress defaults to allow, preserving published-port behavior.

NetworkPolicy instance methods

These methods consume self and return a modified policy, so they chain off a profile or a built policy. Each prepends its rules, so a later deny outranks a catch-all allow like allow public under first-match-wins. All return Result<NetworkPolicy, DomainNameError> because the names are parsed eagerly.

policy.allow_domain()

Prepend a single allow-Domain egress rule. Single-name sugar over allow_domains().

policy.deny_domain()

Prepend a single deny-Domain egress rule. Single-name sugar over deny_domains().

policy.allow_domains()

Prepend one allow-Domain egress rule per name.

Parameters

namesIntoIterator<Item = AsRef<str>>
Exact domain names.

policy.deny_domains()

Prepend one deny-Domain egress rule per name. Prepending lets the denies outrank catch-all allows.

policy.allow_domain_suffix()

Prepend a single allow-DomainSuffix egress rule. Single-suffix sugar over allow_domain_suffixes().

policy.deny_domain_suffix()

Prepend a single deny-DomainSuffix egress rule. Single-suffix sugar over deny_domain_suffixes().

policy.allow_domain_suffixes()

Prepend one allow-DomainSuffix egress rule per suffix. Suffixes match the apex domain and every subdomain (label-aligned).

policy.deny_domain_suffixes()

Prepend one deny-DomainSuffix egress rule per suffix.

NetworkPolicyBuilder

Fluent builder for NetworkPolicy, obtained via NetworkPolicy::builder(). Defaults and rule-batch closures interleave; the build is deferred. The closure signature for rule() / egress() / ingress() / any() is FnOnce(&mut RuleBuilder) -> &mut RuleBuilder. A chain ending in any rule-adder (.allow_public(), .deny().ip(...), etc.) returns the builder reference and satisfies the bound; multi-statement bodies end with an explicit r return. State setters inside a closure (.tcp(), .port()) accumulate eagerly and are not reset between rule-adders, so a single closure can fan one state into several rules. Use separate closures for rules that need different state. See State accumulation for the rationale.

.default_deny()

Set both default_egress and default_ingress to Deny.

.default_allow()

Set both default_egress and default_ingress to Allow.

.default_egress()

Per-direction override for the egress default action.

Parameters

actionAction
Default action for egress.

.default_ingress()

Per-direction override for the ingress default action.

Parameters

actionAction
Default action for ingress.

.egress()

Sugar for rule() with direction pre-set to Egress.

.ingress()

Sugar for rule() with direction pre-set to Ingress.

.any()

Sugar for rule() with direction pre-set to Any. Rules committed inside apply in both directions.

.rule()

Open a multi-rule batch closure. Direction must be set inside via .egress(), .ingress(), or .any() before any rule-adder, otherwise build() returns BuildError::DirectionNotSet.

.build()

Consume the builder and produce a NetworkPolicy. Lazy-parses every .ip() / .cidr() / .domain() / .domain_suffix() input, validates the direction-set and ICMP-egress-only invariants, and emits a tracing::warn! for each shadowed rule pair (a rule fully covered by an earlier one in the same direction; only Ip / Cidr / Group destinations are checked). Builds still succeed when a shadow is detected. Returns the first BuildError encountered.

Returns

Validated policy.

RuleBuilder

The mutable builder handed to a NetworkPolicyBuilder rule-batch closure. Direction, protocol, and port setters return &mut Self and accumulate eagerly; rule-adders commit one rule each using the current state. Protocols and ports have set semantics, so duplicates dedupe.

.egress()

Set direction to Egress for subsequent rule-adders. Last-write-wins.

.ingress()

Set direction to Ingress for subsequent rule-adders. Last-write-wins.

.any()

Set direction to Any for subsequent rule-adders. Rules committed after this apply in both directions. Last-write-wins.

.tcp()

Add Tcp to the protocols set.

.udp()

Add Udp to the protocols set.

.icmpv4()

Add Icmpv4 to the protocols set. Egress-only: an ICMP protocol on an Ingress or Any rule fails build with BuildError::IngressDoesNotSupportIcmp.

.icmpv6()

Add Icmpv6 to the protocols set. Egress-only; same rule as icmpv4().

.port()

Add a single port to the ports set. Always guest-side (egress destination port / ingress listening port).

Parameters

portu16
Port number.

.port_range()

Add an inclusive port range.

Parameters

lou16
Lower bound (inclusive).
hiu16
Upper bound (inclusive). lo > hi records BuildError::InvalidPortRange.

.ports()

Add multiple single ports. Equivalent to calling port() once per element.

.allow_public()

Commit an allow rule for the Public group: every IP not in another named category. A matching deny_public() exists for each allow_* group adder below.

.allow_private()

Allow the Private group (RFC1918 + ULA + CGN).

.allow_loopback()

Allow the Loopback group (127.0.0.0/8, ::1): the guest’s own loopback, not the host. To reach a service on the host’s localhost use allow_host() instead. See the loopback-vs-host trap.
Allow the LinkLocal group (169.254.0.0/16, fe80::/10). Excludes the metadata IP 169.254.169.254.

.allow_meta()

Allow the Metadata group (169.254.169.254). Dangerous on cloud hosts: exposes IAM credentials.

.allow_multicast()

Allow the Multicast group (224.0.0.0/4, ff00::/8).

.allow_host()

Allow the Host group: per-sandbox gateway IPs that back host.microsandbox.internal. This is the right shortcut for “let the sandbox reach my host’s localhost”, not allow_loopback().

.deny_public()

Deny the Public group. Per-group deny_* adders mirror the allow_* set: deny_private(), deny_loopback(), deny_link_local(), deny_meta(), deny_multicast(), and deny_host().

.allow_local()

Commit three allow rules atomically: Loopback + LinkLocal + Host. Each uses the closure’s current state. Metadata is intentionally excluded; opt in via allow_meta() separately.

.deny_local()

Commit three deny rules atomically: Loopback + LinkLocal + Host. Metadata is intentionally excluded.

.allow_domains()

Add one allow-Domain rule per name, inheriting the closure’s current direction / protocol / port state. Lazy-parse: invalid names surface as BuildError::InvalidDomain from build().

.deny_domains()

Add one deny-Domain rule per name.

.allow_domain_suffixes()

Add one allow-DomainSuffix rule per suffix.

.deny_domain_suffixes()

Add one deny-DomainSuffix rule per suffix.

.allow()

Begin an explicit-destination rule with action Allow. The returned RuleDestinationBuilder requires exactly one destination call to commit; dropping it without one adds no rule.

.deny()

Begin an explicit-destination rule with action Deny.

RuleDestinationBuilder

Returned by RuleBuilder::allow() / RuleBuilder::deny(). Requires exactly one destination method call to commit the rule, then returns the &mut RuleBuilder so the chain continues. The type is #[must_use]: dropping it without a destination call adds no rule.

.ip()

Commit with Destination::Cidr of the IP as /32 (v4) or /128 (v6). The string is parsed at build(); invalid values surface as BuildError::InvalidIp.

.cidr()

Commit with Destination::Cidr. Invalid values surface as BuildError::InvalidCidr.

.domain()

Commit with Destination::Domain. Matches only when a cached hostname for the remote IP equals this name (after canonicalization).

.domain_suffix()

Commit with Destination::DomainSuffix. Matches the apex domain itself and any subdomain. A single-label suffix (e.g. com) is rejected at build as BuildError::InvalidDomain.

.group()

Commit with Destination::Group for callers who already hold a DestinationGroup value.

.any()

Commit with Destination::Any: matches every remote.

NetworkBuilder

Builder for the sandbox’s network stack, used in SandboxBuilder::network(|n| n...). Every setter returns Self, so calls chain. Errors accumulated by nested builders cascade up: the outermost SandboxBuilder::build() surfaces them as MicrosandboxError::NetworkBuilder(BuildError).

.policy()

Set the network access policy. Pass a profile-composed or builder-constructed NetworkPolicy.

Parameters

Access policy.

.port()

Publish a TCP port from the sandbox to the host. The default host bind address is 127.0.0.1. Equivalent to SandboxBuilder::port().

Parameters

host_portu16
Port on the host.
guest_portu16
Port inside the sandbox.

.port_udp()

Publish a UDP port. The default host bind address is 127.0.0.1.

.port_bind()

Publish a TCP port on a specific host bind address, such as 0.0.0.0.

Parameters

host_bindIpAddr
Host bind address.
host_portu16
Port on the host.
guest_portu16
Port inside the sandbox.

.port_udp_bind()

Publish a UDP port on a specific host bind address.

.dns()

Configure DNS interception. See DnsBuilder.

.tls()

Configure TLS interception. See TlsBuilder.

.trust_host_cas()

Whether to ship the host’s trusted root CAs into the guest at boot. Default: false. Opt in when egress HTTPS inside the sandbox needs to work behind corporate MITM proxies (Cloudflare Warp Zero Trust, Zscaler, Netskope, etc.): those proxies install a gateway CA on the host that’s unknown to the guest’s stock Mozilla bundle.

.max_connections()

Limit the maximum number of concurrent network connections from the sandbox. Default: 256.

Parameters

maxusize
Maximum concurrent connections.

.ipv4_pool()

Set the IPv4 pool used to derive per-sandbox /30 guest subnets. Defaults to 172.16.0.0/12. A pool with a prefix longer than /30 records BuildError::InvalidIpv4Pool.

Parameters

poolIpv4Network
IPv4 pool, prefix /30 or shorter.

.ipv6_pool()

Set the IPv6 pool used to derive per-sandbox /64 guest prefixes. Defaults to fd42:6d73:62::/48. A pool with a prefix longer than /64 records BuildError::InvalidIpv6Pool.

.interface()

Override the guest interface settings wholesale: MAC, MTU, IPv4/IPv6 addresses, and the derivation pools. A low-level escape hatch. For the common case of changing only the address pools, prefer ipv4_pool() and ipv6_pool(), which validate the prefix. Unset fields fall back to values derived deterministically from the sandbox slot. See InterfaceOverrides.

Parameters

Guest interface overrides.

.enabled()

Enable or disable networking. Default: true. To fully turn networking off, prefer SandboxBuilder::disable_network(), which also sets the policy to NetworkPolicy::none().

.on_secret_violation()

Set the sandbox-wide action taken when a secret placeholder is detected in traffic to a host not in the secret’s allow list. See ViolationActionBuilder. Passthrough hosts receive the placeholder unchanged. They do not receive real secret values.

.secret()

Add a secret via a closure builder. Mirrors SandboxBuilder::secret(). See SecretBuilder for the full API. A companion secret_env(env_var, value, placeholder, allowed_host) shorthand and secret_entry(SecretEntry) are also available on NetworkBuilder.

Parameters

Configure the secret.

DnsBuilder

Builder for DNS interception, used in NetworkBuilder::dns(|d| d...). Owns rebind protection, nameserver pinning, and the per-query timeout. Every setter returns Self.

.nameservers()

Set the upstream nameservers to forward DNS queries to. Replaces any previously-set nameservers. When empty, the interceptor falls back to the host’s /etc/resolv.conf (or, on macOS, the SystemConfiguration dynamic store). Each element converts into Nameserver: a SocketAddr, an IpAddr, or a parsed string via "dns.google:53".parse::<Nameserver>()?.

Parameters

nameserversIntoIterator<Item = Into<Nameserver>>
Upstream resolvers.

.query_timeout_ms()

Set the per-DNS-query timeout in milliseconds. Default: 5000.

.rebind_protection()

When enabled, DNS responses that resolve to private IP addresses are blocked, preventing DNS rebinding attacks. Default: true.

TlsBuilder

Builder for TLS interception, used in NetworkBuilder::tls(|t| t...). Creating it enables interception. Every setter returns Self.

.bypass()

Skip TLS interception for hosts matching this glob (e.g. "*.internal.corp"). Use for domains with certificate pinning. Can be called multiple times.

Parameters

patternimpl Into<String>
Host glob. Supports exact match and *.suffix wildcards.

.intercepted_ports()

TCP ports where TLS interception is active. Default: [443].

.verify_upstream()

Whether the proxy verifies upstream server certificates. Default: true. Set to false only for self-signed servers.

.block_quic()

Block QUIC/HTTP3 on intercepted ports, forcing TCP/TLS fallback. Default: true.

.intercept_ca_cert()

PEM file used as the intercepting CA’s certificate. Pair with intercept_ca_key() to provide a stable CA across sandbox restarts. If unset, a CA is auto-generated and persisted.

.intercept_ca_key()

PEM file used as the intercepting CA’s private key.

.upstream_ca_cert()

PEM file with extra root CAs the proxy should trust when verifying every upstream server. Useful for self-signed or private upstream CAs. Can be called multiple times.

.upstream_ca_cert_for()

PEM file with extra root CAs the proxy should trust only when the upstream SNI matches pattern. Pattern syntax matches bypass(): exact hosts and *.suffix wildcards are supported.

.verify_upstream_for()

Whether the proxy verifies upstream server certificates only when the upstream SNI matches pattern. Pattern syntax matches bypass(): exact hosts and *.suffix wildcards are supported. Setting verify to false is the proxy-side equivalent of curl -k for matching hosts; TLS interception still runs.

ViolationActionBuilder

Builder for secret-violation behavior, used by NetworkBuilder::on_secret_violation() and SecretBuilder::on_violation(). A blocking call (block, block_and_log, block_and_terminate) replaces any accumulated passthrough hosts; passthrough calls accumulate. When passthrough hosts are configured, non-matching hosts use the default action. Every setter returns Self. Produces a ViolationAction.

.block()

Block the request silently.

.block_and_log()

Block the request and emit a warning log on the host. This is the ViolationAction default.

.block_and_terminate()

Block the request and terminate the entire sandbox.

.passthrough_host()

Allow an exact host to receive secret placeholders unchanged (no substitution).

Parameters

hostimpl Into<String>
Exact host.

.passthrough_host_pattern()

Allow hosts matching a wildcard pattern (e.g. *.example.com) to receive placeholders unchanged.

.passthrough_all_hosts()

Allow any host to receive placeholders unchanged. Takes effect only when i_understand_the_risk is true.

Parameters

i_understand_the_riskbool
Must be true to take effect.

Types

NetworkPolicy

Built by NetworkPolicy::builder() · used by policy()

An ordered rule list plus two per-direction defaults, evaluated first-match-wins. Egress evaluation considers rules where direction ∈ {Egress, Any}; ingress considers {Ingress, Any}. If no rule matches, the direction-specific default applies. Default is from_profiles([NetworkProfile::Public]).

NetworkProfile

Composable high-level access category accepted by NetworkPolicy::from_profiles().

Rule

Held by NetworkPolicy

A single policy rule. The destination interpretation is direction-dependent: egress destination, or ingress peer/source. ports is always the guest-side port (egress destination port / ingress listening port). Convenience constructors build any-protocol, any-port rules:

Action

Used by Rule · NetworkPolicy · default_egress()

Direction

Used by Rule

Destination

Held by Rule · committed by RuleDestinationBuilder

DestinationGroup

Held by Destination · committed by RuleBuilder group adders

Groups are disjoint with one carve-out: Metadata takes precedence over LinkLocal for 169.254.169.254, and Host over Private when the gateway IPs sit in CGN/ULA ranges.

Protocol

Held by Rule · set by RuleBuilder protocol setters

ICMP protocols are egress-only. A rule with direction Ingress or Any carrying an ICMP protocol fails build with BuildError::IngressDoesNotSupportIcmp.

PortRange

Held by Rule · added by port() · port_range()

An inclusive port range.

DomainName

Held by Destination::Domain / DomainSuffix

A validated DNS name. Construction goes through str::parse (or TryFrom<String>), which delegates to hickory_proto::rr::Name and canonicalizes the input (lowercased ASCII, leading and trailing dots stripped) so rule matching is a byte-wise compare against the DNS cache. Invalid inputs return a DomainNameError.
Labels follow the permissive DNS grammar (RFC 2181 §11), so underscore-prefixed names like _service._tcp.example.com are accepted. The builder methods (.domain(&str), .domain_suffix(&str)) take strings and parse them lazily at build(), so callers rarely construct DomainName directly.

Nameserver

Used by nameservers()

An upstream DNS server, either a literal address or a hostname resolved at interceptor startup via the host’s OS resolver. Serializes as a single string. Construct via From<SocketAddr>, From<IpAddr>, or str::parse (errors with ParseNameserverError). Accepted parse forms: 1.1.1.1, 1.1.1.1:5353, 2606:4700:4700::1111, [2606:4700:4700::1111]:53, dns.google, dns.google:53. A bare IP or hostname defaults to port 53.

InterfaceOverrides

Used by interface()

Per-sandbox guest interface overrides. Every field is optional; an omitted field is derived deterministically from the sandbox slot. Most callers only touch the pools via ipv4_pool() / ipv6_pool() rather than constructing this directly.

BuildError

Returned by NetworkPolicyBuilder::build() · wrapped by NetworkBuilder

Errors surfaced by the builders’ build() methods. The same enum covers NetworkPolicy::builder(), DnsBuilder, and NetworkBuilder; the network and DNS builders accumulate lazily, so the first failure surfaces from the outermost build() in the chain. Inside SandboxBuilder::build(), BuildError is wrapped as MicrosandboxError::NetworkBuilder(BuildError).

ViolationAction

Built by ViolationActionBuilder · used by on_secret_violation()

Action taken when a secret placeholder is sent to a disallowed host. Also documented on the Secrets page, where it pairs with SecretBuilder.