Skip to content

fix(egress): switch mitmproxy to connection_strategy=eager#974

Closed
Pangjiping wants to merge 2 commits into
opensandbox-group:mainfrom
Pangjiping:fix/egress-mitmproxy-connection-strategy-eager
Closed

fix(egress): switch mitmproxy to connection_strategy=eager#974
Pangjiping wants to merge 2 commits into
opensandbox-group:mainfrom
Pangjiping:fix/egress-mitmproxy-connection-strategy-eager

Conversation

@Pangjiping
Copy link
Copy Markdown
Collaborator

Summary

Lazy was originally chosen so denied requests could short-circuit before touching upstream, but in practice the egress policy defaults to allow and denies only a small minority of requests. The savings on the deny path do not justify the cost on the allow path: lazy checks the upstream connection pool per-request, and on h1 keepalive sessions this exposes a stale-conn race where the second request (e.g. POST /git-upload-pack right after GET /info/refs) picks an upstream conn the peer has already closed, surfacing as a silent transport error with no fatal output on the client.

Eager opens the upstream connection alongside the client connection, so mitm's IO loop continuously observes upstream FIN/RST and a stale conn is detected before the client's next request arrives. The cost is a wasted TCP/TLS handshake for the small fraction of denied requests — acceptable because a denied flow still short-circuits with flow.response = ... before any HTTP write reaches upstream, so upstream sees no path / method / headers, only an unfinished handshake.

Audited the bundled addons (system.py, custom.py): no hook depends on lazy-only behavior (no server_connect routing, no flow.request.host modification, no client-SNI-based upstream decisions).

Testing

  • Not run (explain why)
  • Unit tests
  • Integration tests
  • e2e / manual verification

Breaking Changes

  • None
  • Yes (describe impact and migration path)

Checklist

  • Linked Issue or clearly described motivation
  • Added/updated docs (if needed)
  • Added/updated tests (if needed)
  • Security impact considered
  • Backward compatibility considered

Lazy was originally chosen so denied requests could short-circuit before
touching upstream, but in practice the egress policy defaults to allow and
denies only a small minority of requests. The savings on the deny path do
not justify the cost on the allow path: lazy checks the upstream connection
pool per-request, and on h1 keepalive sessions this exposes a stale-conn
race where the second request (e.g. POST /git-upload-pack right after
GET /info/refs) picks an upstream conn the peer has already closed,
surfacing as a silent transport error with no fatal output on the client.

Eager opens the upstream connection alongside the client connection, so
mitm's IO loop continuously observes upstream FIN/RST and a stale conn is
detected before the client's next request arrives. The cost is a wasted
TCP/TLS handshake for the small fraction of denied requests — acceptable
because a denied flow still short-circuits with `flow.response = ...`
before any HTTP write reaches upstream, so upstream sees no path / method /
headers, only an unfinished handshake.

Audited the bundled addons (system.py, custom.py): no hook depends on
lazy-only behavior (no server_connect routing, no flow.request.host
modification, no client-SNI-based upstream decisions).
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Jun 4, 2026

⚠️ This PR has no labels. Please add one based on the changes.

Changed directories: components.

📋 Recommended labels (based on changed files):

  • component/egress ⬅️

Other available labels:

  • bug - Something isn't working
  • dependencies - Pull requests that update a dependency file
  • documentation - Improvements or additions to documentation
  • feature - New feature or request
  • packages - Changes for package, image and configuration

💡 Tip: Use feature for new functionality or improvements, bug for fixes.

cc @Pangjiping

@Pangjiping Pangjiping force-pushed the fix/egress-mitmproxy-connection-strategy-eager branch from 218a0fd to 2ae0422 Compare June 4, 2026 02:29
…ibility

PR opensandbox-group#951 moved the egress binary from /egress to /opt/opensandbox-egress/egress
so the supervisor and binary could share a single grouped directory. External
tooling and older deployment manifests may still reference the old /egress
path; add a symlink so both paths resolve to the same binary.

Symlink rather than COPY: zero extra image size, single source of truth for
chmod and replacement, and `exec /egress` resolves to the supervisor-managed
binary like before.
@Pangjiping Pangjiping closed this Jun 4, 2026
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.

1 participant