#Network access
<subtitle>Control and restrict outbound internet access from the sandbox. </subtitle>

By default, every sandbox has outbound internet access. You can control and restrict this access to suit security-sensitive workloads—from a simple switch to fine-grained allow and deny lists.

To expose services running within a sandbox to the outside world, see [Sandbox Public URL](/docs/agent-sandbox/network/public-url.md).

## Control Internet access

When creating a sandbox, you can use the `allow_internet_access` parameter to control whether the sandbox can access the Internet. Internet access is enabled by default, but you can disable it for security-sensitive workloads.

```python
from ucloud_sandbox import Sandbox

# Create a sandbox with internet access enabled (default)
sandbox = Sandbox.create(allow_internet_access=True)

# Create a sandbox without internet access
isolated_sandbox = Sandbox.create(allow_internet_access=False)
```

When internet access is disabled, the sandbox is unable to establish outbound network connections, which provides an additional layer of security against sensitive code execution.

> Setting `allow_internet_access` to false is equivalent to setting `network.deny_out` to `['0.0.0.0/0']` (deny all traffic).

## Fine-grained network control

For more granular control over network access, you can use the network configuration options to specify allow and deny lists for outbound traffic.

### Allow and deny lists

You can specify the IP addresses, CIDR blocks, or domain names allowed by the sandbox:

```python
from ucloud_sandbox import Sandbox

# Deny all traffic except specific IPs
sandbox = Sandbox.create(
    network={
        "deny_out": lambda ctx: [ctx.all_traffic],  # ctx.all_traffic == "0.0.0.0/0"
        "allow_out": ["1.1.1.1", "8.8.8.0/24"]
    }
)

# Deny only specific IPs
restricted_sandbox = Sandbox.create(
    network={
        "deny_out": ["8.8.8.8"]
    }
)
```

> The selector callback (`lambda ctx: [ctx.all_traffic]`) is the recommended way of expressing "all traffic" (`0.0.0.0/0`). `ALL_TRAFFIC` constants are still exported to maintain backward compatibility.

### Filtering based on domain name

You can allow traffic to a specific domain name by specifying the hostname in `allow_out`. When using domain-based filtering, you must deny all other traffic in `deny_out`. Domain names are not supported in the deny list.

```python
from ucloud_sandbox import Sandbox

# Only allow traffic to google.com
sandbox = Sandbox.create(
    network={
        "allow_out": ["google.com"],
        "deny_out": lambda ctx: [ctx.all_traffic]
    }
)
```

> When using any domain name, the default name server `8.8.8.8` is automatically allowed to ensure correct DNS resolution.

You can also use wildcards to allow all subdomains of a domain name:

```python
from ucloud_sandbox import Sandbox

# Allow traffic to any subdomain of mydomain.com
sandbox = Sandbox.create(
    network={
        "allow_out": ["*.mydomain.com"],
        "deny_out": lambda ctx: [ctx.all_traffic]
    }
)
```

You can combine domain names with IP addresses and CIDR blocks:

```python
from ucloud_sandbox import Sandbox

# Allow traffic to specific domain names and IPs
sandbox = Sandbox.create(
    network={
        "allow_out": ["api.example.com", "*.github.com", "8.8.8.8"],
        "deny_out": lambda ctx: [ctx.all_traffic]
    }
)
```

> Domain name-based filtering only applies to HTTP traffic on port 80 (via Host header inspection) and TLS traffic on port 443 (via SNI inspection). Traffic on other ports uses CIDR-based filtering only. UDP-based protocols such as QUIC/HTTP3 do not support domain name filtering.

### Behavior of blocked TCP connections

Due to the design of the firewall, blocked connections may appear successful from inside the sandbox.

The firewall must accept the connection before it can decide whether the target is allowed. This means that, from inside the sandbox, even if the target is denied, the TCP connection can succeed and report that the socket is open - but no packets actually reach the target.

To verify that traffic reaches its destination, examine the application layer response (such as HTTP status code, TLS handshake, or expected protocol bytes) instead of relying on TCP connection success.

This is currently a limitation of the way outbound traffic is routed from the sandbox to the firewall and may change in the future.

### Priority rules

When both allow and deny rules are specified, the **allow rules always take precedence over the **deny rules. This means that if an IP address appears in both lists, it will be allowed.

```python
from ucloud_sandbox import Sandbox

# Although all traffic is denied, 1.1.1.1 and 8.8.8.8 are explicitly allowed
sandbox = Sandbox.create(
    network={
        "deny_out": lambda ctx: [ctx.all_traffic],
        "allow_out": ["1.1.1.1", "8.8.8.8"]
    }
)
```

### Convert according to host request

> Per-host request conversion is currently in public beta. You can get started right away, no need to request access.
>
> Please note that this feature is still under active development and its functionality and interaction may change during this time.

You can register per-host rules under `network.rules` to apply transformations (for example, inject HTTP headers) to outbound requests matching a certain host. The rule is keyed by the host, and the registration rule itself does not grant outbound permissions - the host must still be referenced via `allow_out`.

The `transform.headers` object is sent over the network unchanged and injected by the outbound proxy on matching HTTP/HTTPS requests.

```python
from ucloud_sandbox import Sandbox

sandbox = Sandbox.create(
    network={
        # Allow outbound traffic only to hosts with registered rules
        "allow_out": lambda ctx: list(ctx.rules.keys()),
        # Deny all other traffic
        "deny_out": lambda ctx: [ctx.all_traffic],
        #Register according to host rules
        "rules": {
            "api.example.com": [
                {
                    "transform": {
                        "headers": {"X-Header": "Content"},
                    },
                },
            ],
        },
    },
)
```

### Update the network settings of the running sandbox

You can use `update_network` to update the network configuration of a running sandbox. This replaces the current outbound rules with the provided configuration without restarting the sandbox.

```python
from ucloud_sandbox import Sandbox

sandbox = Sandbox.create()

# Tighten outbound traffic from running sandbox: block 8.8.8.8
sandbox.update_network({"deny_out": ["8.8.8.8"]})

# Replace with allow list only
sandbox.update_network({
    "deny_out": lambda ctx: [ctx.all_traffic],
    "allow_out": ["api.example.com"],
})

# Switch internet access without re-creating the sandbox
sandbox.update_network({"allow_internet_access": False})
```

> `update_network` will **replace** the current outbound configuration - it will not be merged with existing rules. Calling it (`update_network({})`) with an empty object clears all allow and deny rules set at creation time.

Options such as network rules in `allow_public_traffic`, `mask_request_host`, and `network.rules` are only available at creation time and cannot be changed after the sandbox is created.
