feat(network): wire ingress policy gate into publisher.rs - #621
Merged
Conversation
6 tasks
toksdotdev
force-pushed
the
spec/network-policy-cli
branch
from
April 27, 2026 01:45
5de97f4 to
3a7d231
Compare
toksdotdev
force-pushed
the
spec/network-policy-ingress
branch
from
April 27, 2026 01:45
133c231 to
b3b1c79
Compare
toksdotdev
force-pushed
the
spec/network-policy-cli
branch
from
April 27, 2026 01:54
3a7d231 to
fa179bd
Compare
toksdotdev
force-pushed
the
spec/network-policy-ingress
branch
from
April 27, 2026 01:54
b3b1c79 to
81dacf8
Compare
toksdotdev
force-pushed
the
spec/network-policy-cli
branch
from
April 27, 2026 02:29
fa179bd to
58ae900
Compare
toksdotdev
force-pushed
the
spec/network-policy-ingress
branch
from
April 27, 2026 02:29
81dacf8 to
37ab367
Compare
toksdotdev
force-pushed
the
spec/network-policy-cli
branch
from
April 27, 2026 02:35
58ae900 to
743542f
Compare
toksdotdev
force-pushed
the
spec/network-policy-ingress
branch
2 times, most recently
from
April 27, 2026 08:11
416bfa2 to
eb75fa8
Compare
toksdotdev
force-pushed
the
spec/network-policy-cli
branch
from
April 27, 2026 12:02
743542f to
17ebbb4
Compare
toksdotdev
force-pushed
the
spec/network-policy-ingress
branch
from
April 27, 2026 12:02
eb75fa8 to
f85aa7a
Compare
toksdotdev
force-pushed
the
spec/network-policy-cli
branch
from
April 27, 2026 12:46
17ebbb4 to
68f4f8a
Compare
toksdotdev
force-pushed
the
spec/network-policy-ingress
branch
from
April 27, 2026 12:46
f85aa7a to
50188d2
Compare
toksdotdev
force-pushed
the
spec/network-policy-ingress
branch
from
April 27, 2026 15:56
bfce6d2 to
a28fdac
Compare
3 tasks
every accepted tcp connection on a published port is now evaluated against `network_policy.evaluate_ingress(peer, guest_port, Protocol::Tcp)` before the listener queues it for the smoltcp accept loop. on `Action::Deny`, the listener sets `SO_LINGER(0)` and drops the stream so the kernel sends a tcp rst instead of the default fin close. peers see `ECONNRESET` rather than a graceful close that looks like the server simply went away. denials are logged at debug with the peer address and guest port. `PortPublisher::new` grew two parameters (`Arc<NetworkPolicy>`, `Arc<SharedState>`) so the spawned `tcp_listener_task` can call into the evaluator. the policy is evaluated against the freshly-accepted peer's `SocketAddr`, the guest's listening port, and `Protocol::Tcp`; the shared state carries domain cache + gateway ips that `evaluate_ingress` reads through. the existing rejection paths in `accept_inbound` (max-inbound-reached and smoltcp-connect-failure) are also tightened to use the same zero-linger drop, so all deliberate connection-rejection signaling is uniform. the helper `reject_with_rst(&TcpStream)` centralizes the linger-then-drop pattern via `socket2::SockRef` (tokio's `TcpStream::set_linger` is deprecated; socket2 is the supported path and the cast is zero-cost — it borrows the fd). ingress traffic from sources matching a `Direction::Ingress` or `Direction::Any` rule fires with first-match-wins; everything else falls through to `default_ingress` (which is `Allow` by default to preserve today's unfiltered published-port behavior, per the asymmetric-defaults rationale in §Defaults).
when a proxy task's `TcpStream::connect` to the host-side upstream fails (e.g. the guest dialed a port where nothing is listening), the smoltcp socket currently closes cleanly with FIN. the guest sees "connection accepted then closed" instead of "connection refused", and happy-eyeballs clients that picked the wrong family stall rather than fall back. track a per-connection `upstream_connected: Arc<AtomicBool>` that the proxy task flips to `true` after a successful upstream connect. when the tracker detects a dead proxy task with the flag still `false`, it aborts the smoltcp socket (RST) instead of closing it (FIN). wired through the plain tcp proxy, the tls bypass relay, and the tls intercept relay. dns / dot tasks skip the flag (they never produce a guest-visible unreachable upstream).
splits the longer #[error(..)] format strings and the --no-net conflict bail string across multiple source lines using rust's `\<newline>` escape. the rendered messages are unchanged; the source is just easier to read at the typical 100-column wrap.
toksdotdev
force-pushed
the
spec/network-policy-ingress
branch
from
May 7, 2026 02:22
807b59d to
15e3d16
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
last of four stacked PRs replacing #615. targets #620.
what's in this pr
every accepted tcp connection on a published port now runs through
policy.evaluate_ingress(peer, guest_port, Protocol::Tcp)before being queued for the smoltcp accept loop.Action::DenytriggersSO_LINGER(0)viasocket2::SockRefso the kernel sends a tcp rst — the peer seesECONNRESETrather than a graceful close.PortPublisher::newgrew two parameters (Arc<NetworkPolicy>,Arc<SharedState>)tcp_listener_taskcallsevaluate_ingresson each accept, drops with rst on denyaccept_inbound(max-inbound-reached, smoltcp-connect-failure) tightened to use the same zero-linger drop for consistencysocket2added as a network-crate depasymmetric default (
default_ingress = Allowwith no implicit rules) preserves today's unfiltered published-port behavior. workspace tests stay green.test plan
cargo test --workspace --libcargo nextest run -p microsandbox --tests --run-ignored=only host_access(kvm-gated; verifies ingress traffic still flows when allowed)--port 8080:8080 --net-rule "deny:ingress@any"rejects connections withECONNRESET