Back to Microsandbox

DNS

docs/networking/dns.mdx

0.6.95.8 KB
Original Source

Microsandbox handles DNS queries on the host instead of letting the guest contact a resolver directly. This makes domain rules and DNS rebinding protection possible.

DNS as egress

Every DNS query must pass the sandbox's egress policy.

RuleHow it applies to DNS
Domain or domain suffixMatches the requested name directly. Protocol and port filters do not apply.
AnyMatches the protocol and port used for the query
Group::HostMatches the gateway that handles the query
IP or CIDRDoes not match because the name has not been resolved yet

The public, private, and host profiles already allow DNS through the gateway. With a custom deny-by-default policy, add the equivalent of allow_dns() or use allow@dns in the CLI. Otherwise, every lookup will be denied.

DNS over TLS uses TCP port 853 and needs its own allow rule. It also requires TLS interception.

DNS rebinding protection is separate from query access. Private or reserved answers are rejected unless an explicit address rule allows them. An allow-by-default policy does not disable this protection. See Network defenses for the full policy behavior.

Blocking domains

Denied domains receive a local NXDOMAIN response and are never sent to the upstream resolver. The same rules also protect connections that use TLS SNI or a recently resolved IP address.

<CodeGroup> ```rust Rust let policy = NetworkPolicy::builder() .default_allow() .egress(|e| e .deny_domains(["malware.example.com"]) .deny_domain_suffixes([".tracking.com"])) .build()?;

let sb = Sandbox::builder("safe-agent") .image("python") .network(|n| n.policy(policy)) .create() .await?;


```typescript TypeScript
import { Sandbox } from "microsandbox";

await using sb = await Sandbox.builder("safe-agent")
  .image("python")
  .network({
    denyDomains: ["malware.example.com"],
    denyDomainSuffixes: [".tracking.com"],
  })
  .create();
python
from microsandbox import Network, Sandbox

sb = await Sandbox.create(
    "safe-agent",
    image="python",
    network=Network(
        deny_domains=("malware.example.com",),
        deny_domain_suffixes=(".tracking.com",),
    ),
)
go
sb, err := m.CreateSandbox(ctx, "safe-agent",
    m.WithImage("python"),
    m.WithNetwork(&m.NetworkConfig{
        DenyDomains:        []string{"malware.example.com"},
        DenyDomainSuffixes: []string{".tracking.com"},
    }),
)
bash
msb create python --name safe-agent --net-default allow \
  --net-rule "[email protected],deny@*.tracking.com"
</CodeGroup>

Pinning nameservers

<Tooltip tip="Custom nameservers are not available on Microsandbox Cloud. Cloud sandboxes use platform-managed DNS."><span className="msb-badge-local">Local-only <Icon icon="circle-info" size={11} /></span></Tooltip>

By default, Microsandbox uses the host's resolver list. Set nameservers when you need specific resolvers.

Nameservers can be IP addresses, hostnames, or either form with a port. Hostnames are resolved once when the sandbox starts.

Resolvers are tried in order. A timeout or connection failure moves to the next resolver. DNS responses such as SERVFAIL and REFUSED do not. Each unreachable resolver can delay the query by up to query_timeout_ms.

<CodeGroup> ```rust Rust use microsandbox_network::dns::Nameserver;

let sb = Sandbox::builder("safe-agent") .image("python") .network(|n| n.dns(|d| d .nameservers([ "1.1.1.1".parse::<Nameserver>()?, "1.0.0.1".parse::<Nameserver>()?, ]) .query_timeout_ms(3000) )) .create() .await?;


```typescript TypeScript
import { Sandbox } from "microsandbox";

await using sb = await Sandbox.builder("safe-agent")
  .image("python")
  .network((n) => n.dns((d) =>
    d.nameservers(["1.1.1.1", "1.0.0.1"])
      .queryTimeoutMs(3000),
  ))
  .create();
python
from microsandbox import DnsConfig, Network, Sandbox

sb = await Sandbox.create(
    "safe-agent",
    image="python",
    network=Network(
        dns=DnsConfig(
            nameservers=("1.1.1.1", "1.0.0.1"),
            query_timeout_ms=3000,
        ),
    ),
)
go
timeout := uint64(3000)
sb, err := m.CreateSandbox(ctx, "safe-agent",
    m.WithImage("python"),
    m.WithNetwork(&m.NetworkConfig{
        DNS: &m.DNSConfig{
            Nameservers:    []string{"1.1.1.1", "1.0.0.1"},
            QueryTimeoutMs: &timeout,
        },
    }),
)
bash
msb create python --name safe-agent \
  --dns-nameserver 1.1.1.1 \
  --dns-nameserver 1.0.0.1 \
  --dns-query-timeout-ms 3000
</CodeGroup>

An application can request a specific resolver, such as with dig @1.1.1.1. That request skips the configured default list, but it still has to pass the network policy.

DNS over alternative transports

TransportBehavior
UDP or TCP on port 53Intercepted
DNS over TLS on TCP port 853Intercepted when TLS interception is enabled
DNS over QUIC, mDNS, LLMNR, and NetBIOS-NSRefused so the guest can fall back to regular DNS
DNS over HTTPSTreated as normal HTTPS traffic

Domain blocking and rebinding protection apply only to DNS traffic that Microsandbox can identify. Use network rules to control DNS over HTTPS or to restrict which resolvers the guest can reach.

Domain-based policy rules

Microsandbox records the IP addresses returned for each domain. A domain rule matches a later connection only when that sandbox resolved the domain to that IP.

An application that connects directly to a hard-coded IP does not match a domain rule. Use an IP or CIDR rule for that traffic.

See also