Skip to content

network: replace net_allow_hosts/net_connect with unified net_allow (#32)#34

Merged
congwang-mk merged 4 commits intomainfrom
issue-32-net-allow-host
May 2, 2026
Merged

network: replace net_allow_hosts/net_connect with unified net_allow (#32)#34
congwang-mk merged 4 commits intomainfrom
issue-32-net-allow-host

Conversation

@congwang-mk
Copy link
Copy Markdown
Contributor

@congwang-mk congwang-mk commented May 1, 2026

Closes #32.

Summary

Pre-1.0 breaking redesign of the network policy surface. Two commits:

1. Unify --net-allow-host and --net-connect into --net-allow (40c837f)

```
--net-allow repeatable; no rules = deny all outbound TCP
= host:port[,port,...] (IP-restricted)
| :port | *:port (any IP)
```

A connection is permitted iff the destination (IP, port) matches at least one rule. Endpoints are first-class — there is no silent over-permissive mode.

2. Default-deny UDP; collapse --net-*-proto to --allow-{udp,icmp} (cf052aa)

UDP previously defaulted to allowed, which conflicted with deny-by-default elsewhere. Now denied; opt in via --allow-udp. The string-matched --net-allow-proto/--net-deny-proto flags are replaced with scalar booleans --allow-udp and --allow-icmp.

Why

Issue #32 surfaced two real problems with the old surface:

  1. The seccomp on-behalf path bypasses Landlock for connect(), so --net-allow-host github.com (without --net-connect) silently permitted SSH, SMTP, and any other port to the resolved IPs.
  2. AND-ing --net-allow-host with --net-connect to fix that produced an awkward back-compat hatch where single-flag use was still permissive.

Unifying the two into one endpoint primitive makes invalid configurations unrepresentable. Hosts and ports always travel as a pair. The proto flags were a parallel cleanup that fell out naturally — UDP is now consistent with TCP's deny-by-default.

Behavior

Command Outcome
--net-allow api.openai.com:443 HTTPS to OpenAI only
--net-allow github.com:22,443 SSH and HTTPS to GitHub
--net-allow :8080 Any IP on port 8080
--net-allow api.openai.com:443 --net-allow redis.local:6379 OpenAI HTTPS plus Redis
(no flags) Landlock denies all outbound TCP
--http-allow "GET api.example.com/*" Auto-extends with api.example.com:80,443
--http-allow "GET *.foo.com/*" Auto-extends with :80,443 (wildcard host)
(no --allow-udp) UDP socket creation denied
--allow-udp UDP allowed; destinations gated by --net-allow
--allow-icmp Raw IP sockets allowed (still requires CAP_NET_RAW from kernel)

What changed

Commit 1 — net-allow unification:

  • Core types (policy.rs, seccomp/notif.rs, seccomp/state.rs): new NetAllow { host: Option<String>, ports: Vec<u16> }. Policy::net_allow: Vec<NetAllow> replaces both net_allow_hosts and net_connect. NetworkPolicy is now AllowList { per_ip, any_ip_ports } with .allows(ip, port).
  • On-behalf path (network.rs): connect_on_behalf, sendto_on_behalf, sendmsg_on_behalf all check (ip, port) against the resolved allowlist.
  • HTTP auto-merge (policy.rs::build()): each HTTP rule with a concrete host auto-adds host:80 (and host:443 with --https-ca); wildcards add :80/:443.
  • CLI (main.rs): new --net-allow grammar; old --net-allow-host / --net-connect removed.
  • FFI: sandlock_policy_builder_net_allow(b, spec) replaces three old setters.
  • Python SDK + TOML profiles + MCP capabilities: net_allow: list[str] replaces both old fields.

Commit 2 — proto-flag redesign:

  • Policy::no_udp default flipped from FalseTrue.
  • --allow-udp / --allow-icmp boolean flags replace --net-allow-proto / --net-deny-proto.
  • Documentation and tests updated accordingly.

Tests

  • Rust: 184 integration tests pass.
  • Python: 226 tests pass.
  • End-to-end matrix on the release CLI (TCP, UDP, ICMP, defaults, bad specs, HTTP auto-merge) all pass.

Migration

Old New
--net-allow-host api.example.com --net-connect 443 --net-allow api.example.com:443
--net-allow-host api.example.com (any port) --net-allow api.example.com:80,443,... (list each port)
--net-connect 443 (any IP) --net-allow :443
--net-allow icmp --allow-icmp
--net-deny udp (and the previous default that allowed UDP) --allow-udp to opt in (UDP now denied by default)
--net-deny raw already the default; drop

🤖 Generated with Claude Code

@congwang-mk congwang-mk changed the title policy: auto-add ports 80/443 when net_allow_hosts is set (#32) docs: clarify net_allow_hosts vs net_connect layering (#32) May 1, 2026
@congwang-mk congwang-mk force-pushed the issue-32-net-allow-host branch 3 times, most recently from 8ede71b to 0007562 Compare May 1, 2026 22:13
@congwang-mk congwang-mk changed the title docs: clarify net_allow_hosts vs net_connect layering (#32) docs: document the two-path network enforcement model (#32) May 1, 2026
@congwang-mk congwang-mk force-pushed the issue-32-net-allow-host branch 2 times, most recently from 679dee7 to dc2da57 Compare May 1, 2026 22:33
@congwang-mk congwang-mk changed the title docs: document the two-path network enforcement model (#32) network: enforce net_connect in on-behalf path; document model (#32) May 1, 2026
@congwang-mk congwang-mk force-pushed the issue-32-net-allow-host branch from dc2da57 to 40c837f Compare May 1, 2026 23:06
@congwang-mk congwang-mk changed the title network: enforce net_connect in on-behalf path; document model (#32) network: replace net_allow_hosts/net_connect with unified net_allow (#32) May 1, 2026
)

Signed-off-by: Cong Wang <cwang@multikernel.io>
…,icmp}

Signed-off-by: Cong Wang <cwang@multikernel.io>
@congwang-mk congwang-mk force-pushed the issue-32-net-allow-host branch from cf052aa to 98a9474 Compare May 1, 2026 23:24
…h positive flags

Signed-off-by: Cong Wang <cwang@multikernel.io>
Signed-off-by: Cong Wang <cwang@multikernel.io>
@congwang-mk congwang-mk merged commit dea4811 into main May 2, 2026
8 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

The network restrictions do not seem to be working as expected.

1 participant