Skip to content

feat: reserve loopback ephemeral listeners for managed proxy#11269

Merged
bolinfest merged 1 commit intomainfrom
pr11269
Feb 10, 2026
Merged

feat: reserve loopback ephemeral listeners for managed proxy#11269
bolinfest merged 1 commit intomainfrom
pr11269

Conversation

@bolinfest
Copy link
Collaborator

@bolinfest bolinfest commented Feb 10, 2026

Codex may run many per-thread proxy instances, so hardcoded proxy ports are brittle and conflict-prone. The previous "ephemeral" approach still had a race: build() read local_addr() from temporary listeners and dropped them before run() rebound the ports. That left a TOCTOU window where the OS (or another process) could reuse the same port, causing intermittent EADDRINUSE and partial proxy startup.

Change the managed proxy path to reserve real listener sockets up front and keep them alive until startup:

  • add ReservedListeners on NetworkProxy to hold HTTP/SOCKS/admin std listeners allocated during build()
  • in managed mode, bind 127.0.0.1:0 for each listener and carry those bound sockets into run() instead of rebinding by address later
  • add run_*_with_std_listener entry points for HTTP, SOCKS5, and admin servers so run() can start services from already-reserved sockets
  • keep static/configured ports only when managed_by_codex(false), including explicit socks_addr override support
  • remove fallback synthetic port allocation and add tests for managed ephemeral loopback binding and unmanaged configured-port behavior

This makes managed startup deterministic, avoids port collisions, and preserves the intended distinction between Codex-managed ephemeral ports and externally managed fixed ports.

@bolinfest bolinfest requested a review from viyatb-oai February 10, 2026 04:10
@viyatb-oai
Copy link
Collaborator

@codex review

Copy link
Contributor

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

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: aac057d136

ℹ️ 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 on lines +131 to +133
Ok(listener) => listener
.local_addr()
.context("failed to get loopback ephemeral port"),
Copy link
Contributor

Choose a reason for hiding this comment

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

P1 Badge Reserve ephemeral ports instead of only reading local_addr

build() requests three "ephemeral" addresses and later starts separate listeners on them, but reserve_loopback_ephemeral_addr() drops its TcpListener immediately after calling local_addr(). Because the port is released before run() binds, the OS can hand out the same port twice (or another process can claim it), which causes intermittent EADDRINUSE when HTTP/admin/SOCKS tasks start and can leave the proxy partially broken.

Useful? React with 👍 / 👎.

@bolinfest bolinfest changed the title feat: prefer ephemeral port for network-proxy feat: reserve loopback ephemeral listeners for managed proxy Feb 10, 2026
@bolinfest bolinfest marked this pull request as ready for review February 10, 2026 06:02
@bolinfest bolinfest enabled auto-merge (squash) February 10, 2026 06:04
Copy link
Contributor

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

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: 90e4dce3f7

ℹ️ 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 on lines +134 to +137
if self.managed_by_codex {
let (http_listener, socks_listener, admin_listener) =
reserve_loopback_ephemeral_listeners()
.context("reserve managed loopback proxy listeners")?;
Copy link
Contributor

Choose a reason for hiding this comment

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

P2 Badge Avoid reserving listeners before checking enabled settings

In managed mode, build() unconditionally calls reserve_loopback_ephemeral_listeners() and binds all three sockets before any network.enabled or enable_socks5 gating happens, so configs that should effectively disable parts of the proxy can still fail at build time (for example with Operation not permitted under restricted sandbox policies) even though run() would no-op for disabled networking. This regresses startup robustness and should be guarded so disabled listeners are not bound.

Useful? React with 👍 / 👎.

@bolinfest bolinfest merged commit 503186b into main Feb 10, 2026
32 checks passed
@bolinfest bolinfest deleted the pr11269 branch February 10, 2026 06:11
@github-actions github-actions bot locked and limited conversation to collaborators Feb 10, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants