Skip to content

Add dynamic Softnet policy control - #181

Merged
fkorotkov-oai merged 12 commits into
mainfrom
dev/fkorotkov/dynamic-softnet-policy
Jul 21, 2026
Merged

Add dynamic Softnet policy control#181
fkorotkov-oai merged 12 commits into
mainfrom
dev/fkorotkov/dynamic-softnet-policy

Conversation

@fkorotkov-oai

@fkorotkov-oai fkorotkov-oai commented Jul 21, 2026

Copy link
Copy Markdown
Collaborator

Summary

Adds an optional, bounded JSON-RPC 2.0 control channel for updating a running Softnet instance's complete allow/block policy without restarting the VM. The protocol intentionally exposes only two methods for now: softnet.policy.get and softnet.policy.set. The existing VM packet socket remains on stdin; control uses a separate connected Unix stream socket.

Follow-on integrations: openai/tart#1287

Changes

  • add --control-fd with strict connected-AF_UNIX/SOCK_STREAM validation and safe descriptor ownership
  • implement newline-delimited softnet.policy.get and atomic softnet.policy.set; there is no capabilities RPC
  • use jsonrpsee-types for request parsing, parameter decoding, standard error codes, typed errors, and response construction while retaining the existing nonblocking FD reader, framing, and backpressure bounds
  • explicitly reject unknown/duplicate envelope fields, null/fractional/negative/oversized IDs, and unknown policy parameters; accepted IDs are bounded strings or non-negative integers, which matches Orchard's string-ID client
  • normalize/deduplicate IPv4 CIDRs and @host, preserve longest-prefix/block precedence, validate revisions, and bound requests, targets, and queued output
  • reject isolation-mode transitions that require recreating vmnet, allowing callers to fall back to a restart
  • keep the last applied policy on control-channel EOF and service control traffic fairly alongside packets
  • refresh Cargo.lock for jsonrpsee-types and its required serde_json version without adding a Tokio/HTTP-server stack

Validation

  • cargo fmt --check
  • cargo check --locked --all-targets --all-features
  • cargo clippy --locked --all-targets --all-features -- -D warnings
  • 25 library tests and 2 binary tests passed serially, including ID-boundary, unknown/duplicate-field, framing, and policy-atomicity coverage
  • cargo tree --locked -i jsonrpsee-types
  • cross-repo stale-RPC-reference check and git diff --check

Three existing vmnet-backed tests require privileged execution and were skipped locally because passwordless sudo is unavailable. The existing block v0.1.6 future-incompatibility warning remains.

@fkorotkov-oai
fkorotkov-oai marked this pull request as ready for review July 21, 2026 17:48

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 8ac47c46ff

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread lib/proxy/control.rs Outdated
continue;
}

self.enqueue(handle_request(policy, &line[..newline]))?;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Reserve response capacity before applying a policy

When the peer applies write backpressure and pending responses approach the 4 MiB limit, handle_request executes before enqueue checks that limit. A softnet.policy.set can therefore replace the live egress rules and then fail to enqueue its response; Proxy::service_control subsequently disables the channel, leaving the controller without an acknowledgment or a way to query which revision is active. Stop reading while output is blocked or stage the mutation until its response can be queued.

Useful? React with 👍 / 👎.

Comment thread lib/proxy/control.rs Outdated

while bytes_read < MAX_SERVICE_BYTES {
match self.stream.read(&mut buf) {
Ok(0) => return Ok(false),

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Flush accepted requests before handling EOF

When a client sends a complete newline-framed request and then half-closes its write side, the first read processes the request and queues its response, but the next read returns EOF here and service returns false without flushing that newly queued response. The proxy then drops the control channel, so a valid duplex client waiting for the acknowledgment never receives it even though a policy update may already have been applied.

Useful? React with 👍 / 👎.

Comment thread lib/proxy/control.rs Outdated
let bridge_isolation = !allow.contains(&Target::Prefix(Ipv4Net::zero()));
let rules = build_rules(self.gateway_ip, &allow, &block);

if self.desired_revision.as_deref() == Some(desired_revision.as_str()) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Reject reuse of any previously bound revision

After revisions A and then B have been accepted, a request that reuses A with different policy contents bypasses this check because only the current revision B is retained. The request silently overwrites the live policy and rebinds A, contrary to the documented guarantee that reusing a revision with a different policy returns a conflict; retain prior revision bindings or otherwise reject their reoccurrence.

Useful? React with 👍 / 👎.

@fkorotkov-oai
fkorotkov-oai requested a review from edi-oai July 21, 2026 17:56
@fkorotkov-oai
fkorotkov-oai enabled auto-merge (squash) July 21, 2026 19:25

@edi-oai edi-oai left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think lib/proxy/control.rs is more complex than it needs to be, but let's move forward and address this in separate PRs.

@fkorotkov-oai
fkorotkov-oai merged commit 08200b7 into main Jul 21, 2026
2 checks passed
@fkorotkov-oai
fkorotkov-oai deleted the dev/fkorotkov/dynamic-softnet-policy branch July 21, 2026 20:30
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.

2 participants