---
title: Networking
description: Python SDK - Network API reference
---

Configure a sandbox's network stack: a first-match-wins egress/ingress policy, published ports, DNS interception, TLS interception, and secret-violation handling. Pass a [`Network`](#network) as the `network=` kwarg to [`Sandbox.create()`](/sdk/python/sandbox#sandbox-create). See [Networking](/networking/overview) for the conceptual overview and [TLS Interception](/networking/tls) for proxy details.

<div className="msb-glance">

  <p className="msb-gl"><span className="msb-dot static"></span>Factory · Network<span className="msb-ct">3</span></p>
  <a className="msb-row" href="#network-none"><span className="msb-rn">Network.none()</span><span className="msb-rg">deny everything, no interface</span></a>
  <a className="msb-row" href="#network-public_only"><span className="msb-rn">Network.public_only()</span><span className="msb-rg">public internet only (default)</span></a>
  <a className="msb-row" href="#network-allow_all"><span className="msb-rn">Network.allow_all()</span><span className="msb-rg">allow everything</span></a>

  <p className="msb-gl"><span className="msb-dot static"></span>Factory · Rule<span className="msb-ct">3</span></p>
  <a className="msb-row" href="#rule-allow"><span className="msb-rn">Rule.allow()</span><span className="msb-rg">permit matching traffic</span></a>
  <a className="msb-row" href="#rule-deny"><span className="msb-rn">Rule.deny()</span><span className="msb-rg">block matching traffic</span></a>
  <a className="msb-row" href="#rule-allow_dns"><span className="msb-rn">Rule.allow_dns()</span><span className="msb-rg">open plain DNS to gateway</span></a>

  <p className="msb-gl"><span className="msb-dot static"></span>Factory · Destination<span className="msb-ct">6</span></p>
  <a className="msb-row" href="#destination-any"><span className="msb-rn">Destination.any()</span><span className="msb-rg">match any destination</span></a>
  <a className="msb-row" href="#destination-ip"><span className="msb-rn">Destination.ip()</span><span className="msb-rg">match an exact IP</span></a>
  <a className="msb-row" href="#destination-cidr"><span className="msb-rn">Destination.cidr()</span><span className="msb-rg">match an IP range</span></a>
  <a className="msb-row" href="#destination-domain"><span className="msb-rn">Destination.domain()</span><span className="msb-rg">match an exact domain</span></a>
  <a className="msb-row" href="#destination-domain_suffix"><span className="msb-rn">Destination.domain_suffix()</span><span className="msb-rg">match apex + subdomains</span></a>
  <a className="msb-row" href="#destination-group"><span className="msb-rn">Destination.group()</span><span className="msb-rg">match an address group</span></a>

  <p className="msb-gl"><span className="msb-dot static"></span>Factory · PortBinding<span className="msb-ct">2</span></p>
  <a className="msb-row" href="#portbinding-tcp"><span className="msb-rn">PortBinding.tcp()</span><span className="msb-rg">published TCP port</span></a>
  <a className="msb-row" href="#portbinding-udp"><span className="msb-rn">PortBinding.udp()</span><span className="msb-rg">published UDP port</span></a>

  <p className="msb-gl"><span className="msb-dot type"></span>Types</p>
  <div className="msb-chiprow">
    <a className="msb-typepill" href="#network">Network</a>
    <a className="msb-typepill" href="#networkpolicy">NetworkPolicy</a>
    <a className="msb-typepill" href="#rule">Rule</a>
    <a className="msb-typepill" href="#destination">Destination</a>
    <a className="msb-typepill" href="#networkdestination">NetworkDestination</a>
    <a className="msb-typepill" href="#portbinding">PortBinding</a>
    <a className="msb-typepill" href="#dnsconfig">DnsConfig</a>
    <a className="msb-typepill" href="#tlsconfig">TlsConfig</a>
    <a className="msb-typepill" href="#action">Action</a>
    <a className="msb-typepill" href="#direction">Direction</a>
    <a className="msb-typepill" href="#protocol">Protocol</a>
    <a className="msb-typepill" href="#portprotocol">PortProtocol</a>
    <a className="msb-typepill" href="#destgroup">DestGroup</a>
    <a className="msb-typepill" href="/sdk/python/secrets#violationaction">ViolationAction</a>
    <a className="msb-typepill" href="/sdk/python/secrets#violationpolicy">ViolationPolicy</a>
  </div>

</div>

<p className="msb-label" id="typical-flow">Typical flow</p>

```python
from microsandbox import (
    Action,
    DestGroup,
    Destination,
    Network,
    NetworkPolicy,
    PortBinding,
    Protocol,
    Rule,
    Sandbox,
)

policy = NetworkPolicy(                             # 1. compose a policy
    default_egress=Action.DENY,
    rules=(
        *Rule.allow_dns(),
        Rule.allow(
            protocol=Protocol.TCP,
            port=443,
            destination=Destination.group(DestGroup.PUBLIC),
        ),
    ),
)

sb = await Sandbox.create(                          # 2. wire it into the sandbox
    "api",
    image="python",
    network=Network(
        policy=policy,
        ports=(PortBinding.tcp(8080, 80),),
    ),
)
```

The default policy denies egress except for an implicit allow-public rule, and allows ingress with no rules. See the [defaults rationale](/networking/overview#defaults) for the asymmetry. `Network`, `Rule`, `Destination`, and `PortBinding` are all frozen dataclasses re-exported from `microsandbox`, each carrying class-method or static-method constructors for the common cases.

## Network factory

[`Network`](#network) is a frozen dataclass. The presets below return a `Network` for the common policy shapes; construct one directly for custom policies, ports, DNS, or TLS.

---

#### <span className="msb-recv">Network.</span><span className="msb-hn">none()</span>
<div className="msb-tags"><span className="msb-tag is-static">classmethod</span></div>

```python
@classmethod
def none() -> Network
```

Deny all traffic. No network interface is created; the guest is fully offline. `exec` and `fs` still work since they use the host-guest channel, not the network.

<p className="msb-label">Returns</p>

<div className="msb-params">
  <div className="msb-param">
    <div className="msb-param-key"><a className="msb-type" href="#network">Network</a></div>
    <div className="msb-param-desc">Fully airgapped network configuration.</div>
  </div>
</div>

<Accordion title="Example">

```python
sb = await Sandbox.create("offline", image="python", network=Network.none())
```

</Accordion>

---

#### <span className="msb-recv">Network.</span><span className="msb-hn">public_only()</span>
<div className="msb-tags"><span className="msb-tag is-static">classmethod</span></div>

```python
@classmethod
def public_only() -> Network
```

Block private address ranges and cloud metadata endpoints. Allow everything else. This is the **default** policy.

<p className="msb-label">Returns</p>

<div className="msb-params">
  <div className="msb-param">
    <div className="msb-param-key"><a className="msb-type" href="#network">Network</a></div>
    <div className="msb-param-desc">Public-only network configuration.</div>
  </div>
</div>

---

#### <span className="msb-recv">Network.</span><span className="msb-hn">allow_all()</span>
<div className="msb-tags"><span className="msb-tag is-static">classmethod</span></div>

```python
@classmethod
def allow_all() -> Network
```

Unrestricted network access, including to private addresses and the host machine.

<p className="msb-label">Returns</p>

<div className="msb-params">
  <div className="msb-param">
    <div className="msb-param-key"><a className="msb-type" href="#network">Network</a></div>
    <div className="msb-param-desc">Unrestricted network configuration.</div>
  </div>
</div>

## Rule factory

A [`NetworkPolicy`](#networkpolicy) is an ordered list of [`Rule`](#rule) values plus two per-direction defaults, evaluated first-match-wins per direction. The class methods below build rules; assemble them into `NetworkPolicy(rules=(...))` and pass it as `Network(policy=...)`.

```python
from microsandbox import Action, Destination, NetworkPolicy, Protocol, Rule

policy = NetworkPolicy(
    default_egress=Action.DENY,
    default_ingress=Action.ALLOW,
    rules=(
        Rule.allow(protocol=Protocol.TCP, port=443, destination=Destination.ip("1.1.1.1")),
        Rule.deny(destination=Destination.domain("api.example.com")),
    ),
)
```

### Rule order matters

The first matching rule wins, so a broad rule placed before a narrow one swallows it:

```python
policy = NetworkPolicy(
    default_egress=Action.DENY,
    default_ingress=Action.ALLOW,
    rules=(
        Rule.allow(destination="10.0.0.0/8"),     # matches everything in 10.x
        Rule.deny(destination="10.0.0.5"),        # never reached
    ),
)
```

Put specific rules before general ones.

---

#### <span className="msb-recv">Rule.</span><span className="msb-hn">allow()</span>
<div className="msb-tags"><span className="msb-tag is-static">classmethod</span></div>

```python
@classmethod
def allow(
    *,
    direction: Direction = Direction.EGRESS,
    protocol: Protocol | None = None,
    port: int | str | None = None,
    destination: str | NetworkDestination | None = None,
) -> Rule
```

Create a rule that permits matching traffic. All filters are keyword-only.

<p className="msb-label">Parameters</p>

<div className="msb-params">
  <div className="msb-param">
    <div className="msb-param-key"><code>direction</code><a className="msb-type" href="#direction">Direction</a></div>
    <div className="msb-param-desc">Which evaluator considers the rule. Defaults to <code>EGRESS</code>.</div>
  </div>
  <div className="msb-param">
    <div className="msb-param-key"><code>protocol</code><a className="msb-type" href="#protocol">Protocol | None</a></div>
    <div className="msb-param-desc">Protocol filter.</div>
  </div>
  <div className="msb-param">
    <div className="msb-param-key"><code>port</code><span className="msb-type">int | str | None</span></div>
    <div className="msb-param-desc">Single port (<code>443</code>) or range (<code>"8000-9000"</code>).</div>
  </div>
  <div className="msb-param">
    <div className="msb-param-key"><code>destination</code><a className="msb-type" href="#networkdestination">str | NetworkDestination | None</a></div>
    <div className="msb-param-desc">Target filter. Prefer the typed <a className="msb-type" href="#destination">Destination</a> helpers; string shorthand is also accepted.</div>
  </div>
</div>

<p className="msb-label">Returns</p>

<div className="msb-params">
  <div className="msb-param">
    <div className="msb-param-key"><a className="msb-type" href="#rule">Rule</a></div>
    <div className="msb-param-desc">An allow rule.</div>
  </div>
</div>

<Accordion title="Example">

```python
from microsandbox import Destination, Protocol, Rule

r = Rule.allow(protocol=Protocol.TCP, port=443, destination=Destination.domain("api.example.com"))
```

</Accordion>

---

#### <span className="msb-recv">Rule.</span><span className="msb-hn">deny()</span>
<div className="msb-tags"><span className="msb-tag is-static">classmethod</span></div>

```python
@classmethod
def deny(
    *,
    direction: Direction = Direction.EGRESS,
    protocol: Protocol | None = None,
    port: int | str | None = None,
    destination: str | NetworkDestination | None = None,
) -> Rule
```

Create a rule that blocks matching traffic. Same keyword-only filters as [`allow()`](#rule-allow).

<p className="msb-label">Parameters</p>

<div className="msb-params">
  <div className="msb-param">
    <div className="msb-param-key"><code>direction</code><a className="msb-type" href="#direction">Direction</a></div>
    <div className="msb-param-desc">Which evaluator considers the rule. Defaults to <code>EGRESS</code>.</div>
  </div>
  <div className="msb-param">
    <div className="msb-param-key"><code>protocol</code><a className="msb-type" href="#protocol">Protocol | None</a></div>
    <div className="msb-param-desc">Protocol filter.</div>
  </div>
  <div className="msb-param">
    <div className="msb-param-key"><code>port</code><span className="msb-type">int | str | None</span></div>
    <div className="msb-param-desc">Single port or port range.</div>
  </div>
  <div className="msb-param">
    <div className="msb-param-key"><code>destination</code><a className="msb-type" href="#networkdestination">str | NetworkDestination | None</a></div>
    <div className="msb-param-desc">Target filter.</div>
  </div>
</div>

<p className="msb-label">Returns</p>

<div className="msb-params">
  <div className="msb-param">
    <div className="msb-param-key"><a className="msb-type" href="#rule">Rule</a></div>
    <div className="msb-param-desc">A deny rule.</div>
  </div>
</div>

---

#### <span className="msb-recv">Rule.</span><span className="msb-hn">allow_dns()</span>
<div className="msb-tags"><span className="msb-tag is-static">classmethod</span></div>

```python
@classmethod
def allow_dns() -> tuple[Rule, Rule]
```

Allow plain DNS (UDP/53 and TCP/53) to the sandbox gateway, i.e. the in-process DNS forwarder. The standard one-liner for opening DNS under a deny-by-default policy. See [DNS as egress](/networking/dns#dns-as-egress) for the underlying semantics.

Returns the pair `(udp_rule, tcp_rule)` since this SDK's [`Rule`](#rule) shape carries a single protocol; splat into `NetworkPolicy.rules`. DoT (TCP/853) is intentionally not included; add an explicit `Rule.allow(destination=Destination.group(DestGroup.HOST), protocol=Protocol.TCP, port=853)` if needed (and pair with TLS interception).

<p className="msb-label">Returns</p>

<div className="msb-params">
  <div className="msb-param">
    <div className="msb-param-key"><a className="msb-type" href="#rule">tuple[Rule, Rule]</a></div>
    <div className="msb-param-desc"><code>(udp_rule, tcp_rule)</code> for <code>DestGroup.HOST</code> on port 53.</div>
  </div>
</div>

<Accordion title="Example">

```python
from microsandbox import Action, DestGroup, Destination, NetworkPolicy, Protocol, Rule

policy = NetworkPolicy(
    default_egress=Action.DENY,
    rules=(
        *Rule.allow_dns(),
        Rule.allow(
            protocol=Protocol.TCP,
            port=443,
            destination=Destination.group(DestGroup.PUBLIC),
        ),
    ),
)
```

</Accordion>

## Destination factory

Factory namespace for typed network policy destinations. Typed destinations avoid string-shorthand ambiguity and match the TypeScript SDK shape. Each method returns a [`NetworkDestination`](#networkdestination).

```python
from microsandbox import DestGroup, Destination

Destination.any()
Destination.ip("1.1.1.1")
Destination.cidr("10.0.0.0/8")
Destination.domain("api.example.com")
Destination.domain_suffix(".example.com")
Destination.group(DestGroup.LINK_LOCAL)
```

Bare IP strings such as `"1.1.1.1"` remain supported on [`Rule`](#rule) destinations and are parsed like `Destination.ip("1.1.1.1")`. Prefer the typed helper when the value is known to be an IP.

---

#### <span className="msb-recv">Destination.</span><span className="msb-hn">any()</span>
<div className="msb-tags"><span className="msb-tag is-static">staticmethod</span></div>

```python
@staticmethod
def any() -> NetworkDestination
```

Match any destination.

---

#### <span className="msb-recv">Destination.</span><span className="msb-hn">ip()</span>
<div className="msb-tags"><span className="msb-tag is-static">staticmethod</span></div>

```python
@staticmethod
def ip(ip: str) -> NetworkDestination
```

Match an exact IPv4 or IPv6 address. Stored as `/32` for IPv4 or `/128` for IPv6.

<p className="msb-label">Parameters</p>

<div className="msb-params">
  <div className="msb-param">
    <div className="msb-param-key"><code>ip</code><span className="msb-type">str</span></div>
    <div className="msb-param-desc">IPv4 or IPv6 address.</div>
  </div>
</div>

---

#### <span className="msb-recv">Destination.</span><span className="msb-hn">cidr()</span>
<div className="msb-tags"><span className="msb-tag is-static">staticmethod</span></div>

```python
@staticmethod
def cidr(cidr: str) -> NetworkDestination
```

Match a CIDR range.

<p className="msb-label">Parameters</p>

<div className="msb-params">
  <div className="msb-param">
    <div className="msb-param-key"><code>cidr</code><span className="msb-type">str</span></div>
    <div className="msb-param-desc">CIDR notation, e.g. <code>"10.0.0.0/8"</code>.</div>
  </div>
</div>

---

#### <span className="msb-recv">Destination.</span><span className="msb-hn">domain()</span>
<div className="msb-tags"><span className="msb-tag is-static">staticmethod</span></div>

```python
@staticmethod
def domain(domain: str) -> NetworkDestination
```

Match an exact domain. Domain strings are validated at sandbox creation; invalid names raise `ValueError`.

<p className="msb-label">Parameters</p>

<div className="msb-params">
  <div className="msb-param">
    <div className="msb-param-key"><code>domain</code><span className="msb-type">str</span></div>
    <div className="msb-param-desc">Fully qualified domain name.</div>
  </div>
</div>

---

#### <span className="msb-recv">Destination.</span><span className="msb-hn">domain_suffix()</span>
<div className="msb-tags"><span className="msb-tag is-static">staticmethod</span></div>

```python
@staticmethod
def domain_suffix(suffix: str) -> NetworkDestination
```

Match the apex domain and all subdomains.

<p className="msb-label">Parameters</p>

<div className="msb-params">
  <div className="msb-param">
    <div className="msb-param-key"><code>suffix</code><span className="msb-type">str</span></div>
    <div className="msb-param-desc">Domain suffix, e.g. <code>".example.com"</code>.</div>
  </div>
</div>

---

#### <span className="msb-recv">Destination.</span><span className="msb-hn">group()</span>
<div className="msb-tags"><span className="msb-tag is-static">staticmethod</span></div>

```python
@staticmethod
def group(group: DestGroup | str) -> NetworkDestination
```

Match a well-known [`DestGroup`](#destgroup) address group.

<p className="msb-label">Parameters</p>

<div className="msb-params">
  <div className="msb-param">
    <div className="msb-param-key"><code>group</code><a className="msb-type" href="#destgroup">DestGroup | str</a></div>
    <div className="msb-param-desc">Group keyword.</div>
  </div>
</div>

## PortBinding factory

[`PortBinding`](#portbinding) is a frozen dataclass for published ports that need an explicit host bind address or UDP. Prefer the protocol-specific constructors over building one by hand.

```python
PortBinding.tcp(8001, 8001, bind="0.0.0.0")
PortBinding.udp(5353, 5353, bind="0.0.0.0")
```

Pass them to `Network(ports=(...))`. A plain `dict[int, int]` is also accepted for the common case, binding TCP to `127.0.0.1`.

---

#### <span className="msb-recv">PortBinding.</span><span className="msb-hn">tcp()</span>
<div className="msb-tags"><span className="msb-tag is-static">classmethod</span></div>

```python
@classmethod
def tcp(cls, host_port: int, guest_port: int, *, bind: str = "127.0.0.1") -> PortBinding
```

Publish a TCP port from the sandbox to the host.

<p className="msb-label">Parameters</p>

<div className="msb-params">
  <div className="msb-param">
    <div className="msb-param-key"><code>host_port</code><span className="msb-type">int</span></div>
    <div className="msb-param-desc">Port on the host.</div>
  </div>
  <div className="msb-param">
    <div className="msb-param-key"><code>guest_port</code><span className="msb-type">int</span></div>
    <div className="msb-param-desc">Port inside the sandbox.</div>
  </div>
  <div className="msb-param">
    <div className="msb-param-key"><code>bind</code><span className="msb-type">str</span></div>
    <div className="msb-param-desc">Host bind address. Defaults to <code>127.0.0.1</code>; use <code>0.0.0.0</code> for all IPv4 interfaces.</div>
  </div>
</div>

<p className="msb-label">Returns</p>

<div className="msb-params">
  <div className="msb-param">
    <div className="msb-param-key"><a className="msb-type" href="#portbinding">PortBinding</a></div>
    <div className="msb-param-desc">A TCP port binding.</div>
  </div>
</div>

---

#### <span className="msb-recv">PortBinding.</span><span className="msb-hn">udp()</span>
<div className="msb-tags"><span className="msb-tag is-static">classmethod</span></div>

```python
@classmethod
def udp(cls, host_port: int, guest_port: int, *, bind: str = "127.0.0.1") -> PortBinding
```

Publish a UDP port from the sandbox to the host.

<p className="msb-label">Parameters</p>

<div className="msb-params">
  <div className="msb-param">
    <div className="msb-param-key"><code>host_port</code><span className="msb-type">int</span></div>
    <div className="msb-param-desc">Port on the host.</div>
  </div>
  <div className="msb-param">
    <div className="msb-param-key"><code>guest_port</code><span className="msb-type">int</span></div>
    <div className="msb-param-desc">Port inside the sandbox.</div>
  </div>
  <div className="msb-param">
    <div className="msb-param-key"><code>bind</code><span className="msb-type">str</span></div>
    <div className="msb-param-desc">Host bind address. Defaults to <code>127.0.0.1</code>.</div>
  </div>
</div>

<p className="msb-label">Returns</p>

<div className="msb-params">
  <div className="msb-param">
    <div className="msb-param-key"><a className="msb-type" href="#portbinding">PortBinding</a></div>
    <div className="msb-param-desc">A UDP port binding.</div>
  </div>
</div>

## Types

### Network

<div className="msb-tags"><span className="msb-tag is-type">dataclass</span></div>

<p className="msb-backref">Used by <a href="/sdk/python/sandbox#sandbox-create">Sandbox.create(network=...)</a></p>

Frozen dataclass for sandbox network configuration. Use a [class-method preset](#network-factory) for the common cases, or construct directly with custom options.

```python
Network(
    policy: str | NetworkPolicy | None = None,
    ports: Mapping[int, int] | Sequence[PortBinding] = {},
    deny_domains: tuple[str, ...] = (),
    deny_domain_suffixes: tuple[str, ...] = (),
    dns: DnsConfig | None = None,
    tls: TlsConfig | None = None,
    ipv4_pool: str | None = None,
    ipv6_pool: str | None = None,
    max_connections: int | None = None,
    on_secret_violation: ViolationAction | ViolationPolicy = ViolationAction.BLOCK_AND_LOG,
)
```

| Field | Type | Default | Description |
|-------|------|---------|-------------|
| policy | `str \| `[`NetworkPolicy`](#networkpolicy)` \| None` | `None` | Preset name (`"none"`, `"public_only"`, `"allow_all"`) or a custom [`NetworkPolicy`](#networkpolicy) |
| ports | `Mapping[int, int] \| Sequence[`[`PortBinding`](#portbinding)`]` | `{}` | Port mappings from host to guest. Mapping form binds TCP to `127.0.0.1`; [`PortBinding`](#portbinding) can set an explicit bind address or UDP |
| deny_domains | `tuple[str, ...]` | `()` | Deny egress to these exact domains. Each entry adds a `deny Domain("...")` policy rule that fires at DNS resolution (NXDOMAIN), TLS first-flight (SNI), and TCP egress (cache fallback). Prepended onto the policy so it takes precedence over later allow rules |
| deny_domain_suffixes | `tuple[str, ...]` | `()` | Deny egress to all subdomains of these suffixes. Adds `deny DomainSuffix("...")` rules; same enforcement layers as `deny_domains` |
| dns | [`DnsConfig`](#dnsconfig)` \| None` | `None` | DNS interception configuration |
| tls | [`TlsConfig`](#tlsconfig)` \| None` | `None` | TLS interception configuration |
| ipv4_pool | `str \| None` | `None` | IPv4 pool used for per-sandbox `/30` guest subnets. Defaults to `172.16.0.0/12` |
| ipv6_pool | `str \| None` | `None` | IPv6 pool used for per-sandbox `/64` guest prefixes. Defaults to `fd42:6d73:62::/48` |
| max_connections | `int \| None` | `None` | Maximum concurrent connections |
| on_secret_violation | [`ViolationAction`](/sdk/python/secrets#violationaction)` \| `[`ViolationPolicy`](/sdk/python/secrets#violationpolicy) | `BLOCK_AND_LOG` | Sandbox-wide action when a secret placeholder reaches a disallowed host |

| Class method | Returns | Description |
|--------------|---------|-------------|
| [none()](#network-none) | [`Network`](#network) | Deny all traffic, no interface |
| [public_only()](#network-public_only) | [`Network`](#network) | Public destinations only (default) |
| [allow_all()](#network-allow_all) | [`Network`](#network) | Unrestricted access |

### NetworkPolicy

<div className="msb-tags"><span className="msb-tag is-type">dataclass</span></div>

<p className="msb-backref">Used by <a href="#network">Network(policy=...)</a></p>

Frozen dataclass: an ordered list of [`Rule`](#rule) values plus two per-direction defaults, evaluated first-match-wins. The defaults are asymmetric to preserve today's behavior: egress falls through to deny (public_only reachability when paired with the implicit allow-public rule); ingress falls through to allow (unfiltered published-port behavior).

```python
NetworkPolicy(
    default_egress: Action = Action.DENY,
    default_ingress: Action = Action.ALLOW,
    rules: tuple[Rule, ...] = (),
)
```

| Field | Type | Default | Description |
|-------|------|---------|-------------|
| default_egress | [`Action`](#action) | `DENY` | Action when no egress-applicable rule matches |
| default_ingress | [`Action`](#action) | `ALLOW` | Action when no ingress-applicable rule matches |
| rules | `tuple[`[`Rule`](#rule)`, ...]` | `()` | Rules evaluated first-match-wins per direction |

### Rule

<div className="msb-tags"><span className="msb-tag is-type">dataclass</span></div>

<p className="msb-backref">Used by <a href="#networkpolicy">NetworkPolicy(rules=...)</a></p>

Frozen dataclass for a single network policy rule. Prefer the [`Rule.allow()`](#rule-allow) / [`Rule.deny()`](#rule-deny) class methods over the positional constructor.

```python
Rule(
    action: Action,
    direction: Direction = Direction.EGRESS,
    destination: str | NetworkDestination | None = None,
    protocol: Protocol | None = None,
    port: int | str | None = None,
)
```

| Field | Type | Default | Description |
|-------|------|---------|-------------|
| action | [`Action`](#action) | - | What to do when this rule matches |
| direction | [`Direction`](#direction) | `EGRESS` | Which evaluator considers this rule. `Direction.ANY` matches in either direction |
| destination | `str \| `[`NetworkDestination`](#networkdestination)` \| None` | `None` | Target filter. Prefer typed [`Destination`](#destination) helpers; string shorthand also works ([`DestGroup`](#destgroup) values, exact IPs, domains, CIDR ranges, domain suffixes prefixed with `"."`, or `"*"` for any). Domain and suffix strings are validated at sandbox creation; invalid names raise `ValueError` |
| protocol | [`Protocol`](#protocol)` \| None` | `None` | Protocol filter |
| port | `int \| str \| None` | `None` | Single port (`443`) or range (`"8000-9000"`) |

Ingress rules carrying ICMP protocols are rejected at sandbox creation; the host has no inbound ICMP path. Use `Direction.EGRESS` for ICMP allow/deny.

| Class method | Returns | Description |
|--------------|---------|-------------|
| [allow(...)](#rule-allow) | [`Rule`](#rule) | Permit matching traffic |
| [deny(...)](#rule-deny) | [`Rule`](#rule) | Block matching traffic |
| [allow_dns()](#rule-allow_dns) | `tuple[`[`Rule`](#rule)`, `[`Rule`](#rule)`]` | Open plain DNS to the gateway |

### Destination

<div className="msb-tags"><span className="msb-tag is-type">factory</span></div>

<p className="msb-backref">Returns <a href="#networkdestination">NetworkDestination</a> · used by <a href="#rule">Rule.allow() / Rule.deny()</a></p>

Factory namespace ([static methods](#destination-factory)) producing typed [`NetworkDestination`](#networkdestination) values.

| Method | Returns | Description |
|--------|---------|-------------|
| [any()](#destination-any) | [`NetworkDestination`](#networkdestination) | Match any destination |
| [ip(ip)](#destination-ip) | [`NetworkDestination`](#networkdestination) | Match an exact IPv4 or IPv6 address (`/32` or `/128`) |
| [cidr(cidr)](#destination-cidr) | [`NetworkDestination`](#networkdestination) | Match a CIDR range |
| [domain(domain)](#destination-domain) | [`NetworkDestination`](#networkdestination) | Match an exact domain |
| [domain_suffix(suffix)](#destination-domain_suffix) | [`NetworkDestination`](#networkdestination) | Match the apex domain and all subdomains |
| [group(group)](#destination-group) | [`NetworkDestination`](#networkdestination) | Match a [`DestGroup`](#destgroup) value |

### NetworkDestination

<div className="msb-tags"><span className="msb-tag is-type">dataclass</span></div>

<p className="msb-backref">Produced by <a href="#destination">Destination</a> helpers</p>

Frozen dataclass produced by [`Destination`](#destination) helpers.

```python
NetworkDestination(
    kind: Literal["any", "ip", "cidr", "domain", "domain_suffix", "group"],
    value: str | None = None,
)
```

| Field | Type | Default | Description |
|-------|------|---------|-------------|
| kind | `Literal["any", "ip", "cidr", "domain", "domain_suffix", "group"]` | - | Destination variant |
| value | `str \| None` | `None` | Variant value, omitted for `Destination.any()` |

### PortBinding

<div className="msb-tags"><span className="msb-tag is-type">dataclass</span></div>

<p className="msb-backref">Used by <a href="#network">Network(ports=...)</a></p>

Frozen dataclass for a published host-to-guest port with an optional host bind address. Prefer the [`PortBinding.tcp()`](#portbinding-tcp) / [`PortBinding.udp()`](#portbinding-udp) class methods.

```python
PortBinding(
    host_port: int,
    guest_port: int,
    bind: str = "127.0.0.1",
    protocol: PortProtocol = PortProtocol.TCP,
)
```

| Field | Type | Default | Description |
|-------|------|---------|-------------|
| host_port | `int` | - | Port on the host |
| guest_port | `int` | - | Port inside the sandbox |
| bind | `str` | `"127.0.0.1"` | Host address to bind. Use `0.0.0.0` for all IPv4 interfaces |
| protocol | [`PortProtocol`](#portprotocol) | `TCP` | Published port protocol |

| Class method | Returns | Description |
|--------------|---------|-------------|
| [tcp(host_port, guest_port, *, bind)](#portbinding-tcp) | [`PortBinding`](#portbinding) | A TCP port binding |
| [udp(host_port, guest_port, *, bind)](#portbinding-udp) | [`PortBinding`](#portbinding) | A UDP port binding |

### DnsConfig

<div className="msb-tags"><span className="msb-tag is-type">dataclass</span></div>

<p className="msb-backref">Used by <a href="#network">Network(dns=...)</a></p>

Frozen dataclass for DNS interception settings. The value type of [`Network.dns`](#network); import it from `microsandbox.types`.

```python
DnsConfig(
    rebind_protection: bool = True,
    nameservers: tuple[str, ...] = (),
    query_timeout_ms: int | None = None,
)
```

| Field | Type | Default | Description |
|-------|------|---------|-------------|
| rebind_protection | `bool` | `True` | Block DNS responses resolving to private IPs |
| nameservers | `tuple[str, ...]` | `()` | Nameservers (`IP`, `IP:PORT`, `HOST`, or `HOST:PORT`). Overrides the host's `/etc/resolv.conf` when set. Hostnames are resolved once at startup via the host's OS resolver |
| query_timeout_ms | `int \| None` | `None` | Per-DNS-query timeout in milliseconds. Defaults to `5000` |

### TlsConfig

<div className="msb-tags"><span className="msb-tag is-type">dataclass</span></div>

<p className="msb-backref">Used by <a href="#network">Network(tls=...)</a></p>

Frozen dataclass for TLS interception settings within [`Network`](#network).

```python
TlsConfig(
    bypass: tuple[str, ...] = (),
    verify_upstream: bool = True,
    intercepted_ports: tuple[int, ...] = (443,),
    block_quic: bool = False,
    ca_cert: str | None = None,
    ca_key: str | None = None,
    ca_cn: str | None = None,
)
```

| Field | Type | Default | Description |
|-------|------|---------|-------------|
| bypass | `tuple[str, ...]` | `()` | Domains to skip interception. Use for domains with certificate pinning |
| verify_upstream | `bool` | `True` | Verify upstream server certificates. Set to `False` only for self-signed servers |
| intercepted_ports | `tuple[int, ...]` | `(443,)` | TCP ports where TLS interception is active |
| block_quic | `bool` | `False` | Block QUIC/HTTP3 (UDP) on intercepted ports, forcing TCP/TLS fallback |
| ca_cert | `str \| None` | `None` | Path to a custom interception CA certificate PEM file |
| ca_key | `str \| None` | `None` | Path to a custom interception CA private key PEM file |
| ca_cn | `str \| None` | `None` | Common name for the generated interception CA |

### Action

<div className="msb-tags"><span className="msb-tag is-type">enum</span></div>

<p className="msb-backref">Used by <a href="#networkpolicy">NetworkPolicy</a> · <a href="#rule">Rule</a></p>

String enum (`StrEnum`) for policy actions, so the string values are accepted directly.

| Value | Description |
|-------|-------------|
| `"allow"` | Permit the traffic |
| `"deny"` | Drop the traffic silently |

### Direction

<div className="msb-tags"><span className="msb-tag is-type">enum</span></div>

<p className="msb-backref">Used by <a href="#rule">Rule</a></p>

String enum for traffic direction.

| Value | Description |
|-------|-------------|
| `"egress"` | Traffic leaving the sandbox |
| `"ingress"` | Traffic entering the sandbox (via published ports) |
| `"any"` | Rule applies in either direction |

### Protocol

<div className="msb-tags"><span className="msb-tag is-type">enum</span></div>

<p className="msb-backref">Used by <a href="#rule">Rule</a></p>

String enum for network protocols in policy rules.

| Value | Description |
|-------|-------------|
| `"tcp"` | TCP traffic |
| `"udp"` | UDP traffic |
| `"icmpv4"` | ICMPv4 traffic |
| `"icmpv6"` | ICMPv6 traffic |

### PortProtocol

<div className="msb-tags"><span className="msb-tag is-type">enum</span></div>

<p className="msb-backref">Used by <a href="#portbinding">PortBinding</a></p>

String enum for port-level protocol selection.

| Value | Description |
|-------|-------------|
| `"tcp"` | TCP port |
| `"udp"` | UDP port |

### DestGroup

<div className="msb-tags"><span className="msb-tag is-type">enum</span></div>

<p className="msb-backref">Used by <a href="#destination">Destination.group()</a></p>

String enum for well-known destination groups used in [`Destination.group()`](#destination-group) or string-shorthand [`Rule.destination`](#rule).

| Value | Description |
|-------|-------------|
| `"public"` | Complement of the named categories: every address not in any other group |
| `"private"` | Private/RFC 1918 addresses + ULA + CGN (`10.0.0.0/8`, `172.16.0.0/12`, `192.168.0.0/16`, `100.64.0.0/10`, `fc00::/7`) |
| `"loopback"` | Loopback addresses (`127.0.0.0/8`, `::1`); the **guest's own** loopback, not the host. See the [loopback-vs-host watch-out](/networking/overview#loopback-vs-host-a-common-trap) |
| `"link-local"` | Link-local addresses (`169.254.0.0/16`, `fe80::/10`) excluding metadata |
| `"metadata"` | Cloud metadata endpoints (`169.254.169.254`) |
| `"multicast"` | Multicast addresses (`224.0.0.0/4`, `ff00::/8`) |
| `"host"` | The host machine, reached via `host.microsandbox.internal`. This is the right group for "let the sandbox reach my host's localhost", not `"loopback"` |
