Allow exec-server to proxy permitted private IPs upstream (#48568)

## Why

Private IP destinations always bypassed inherited upstream proxies, preventing their use for private networks reachable through an upstream VPN proxy.

## What changed

- Add `codex exec-server --proxy-private-ips-via-upstream`, also configurable with `CODEX_EXEC_SERVER_PROXY_PRIVATE_IPS_VIA_UPSTREAM=true`. The setting defaults to disabled.
- Allow permitted RFC 1918, carrier-grade NAT, and IPv6 unique-local destinations to use an applicable upstream proxy. Loopback and link-local destinations retain direct routing, and destination access policy still applies.
- Keep connections direct when no valid upstream proxy applies or `allow_upstream_proxy=false`. Errors after selecting an upstream proxy do not trigger a direct retry.
- Rename `ExecServerRuntimePaths` to `ExecServerRuntimeOptions` and carry the routing setting from executor startup into the managed network proxy.

## Testing

Add routing coverage for private address ranges, special-use addresses, and public targets with the option enabled and disabled. Verify that HTTP and CONNECT requests still enforce destination allowlists and denylists, and update the CLI help snapshot.

GitOrigin-RevId: b7c9cc7da0e0f545694a6521b74c9b36b7b92769
This commit is contained in:
open-matt
2026-09-26 23:17:41 +00:00
committed by copyberry
parent 228ae3da8d
commit b8d5e3f12e
65 changed files with 359 additions and 213 deletions
+5 -1
View File
@@ -22,7 +22,11 @@ fn exec_server_help_documents_remote_options() {
let command = MultitoolCli::command()
.term_width(80)
.mut_subcommand("exec-server", |command| {
command.mut_arg("exit_on_stdin_close", |arg| arg.hide_env_values(true))
command
.mut_arg("exit_on_stdin_close", |arg| arg.hide_env_values(true))
.mut_arg("proxy_private_ips_via_upstream", |arg| {
arg.hide_env_values(true)
})
});
let help = command
.try_get_matches_from(["codex", "exec-server", "--help"])
+14 -3
View File
@@ -14,7 +14,7 @@ use codex_core::config::ConfigLoadOptions;
use codex_core::config::bootstrap_auth_config;
use codex_core::config::find_codex_home;
use codex_core::config::load_config_toml_with_layer_stack;
use codex_exec_server::ExecServerRuntimePaths;
use codex_exec_server::ExecServerRuntimeOptions;
use codex_http_client::HttpClientFactory;
use codex_http_client::OutboundProxyPolicy;
use codex_login::AuthManager;
@@ -48,6 +48,16 @@ pub(super) struct ExecServerCommand {
#[arg(long, value_name = "MODE", default_value = "isolate", global = true)]
linux_sandbox_pid_namespace: codex_sandboxing::LinuxSandboxPidNamespace,
/// Allow permitted private IP destinations to use the configured upstream proxy.
/// If no valid upstream proxy applies to the request protocol, connect directly.
/// Loopback stays local. This flag does not require upstream routing.
#[arg(
long,
env = "CODEX_EXEC_SERVER_PROXY_PRIVATE_IPS_VIA_UPSTREAM",
global = true
)]
proxy_private_ips_via_upstream: bool,
/// Maximum number of requests to process concurrently on each connection.
#[arg(
long = "concurrent-requests",
@@ -164,11 +174,12 @@ impl ExecServerCommand {
.codex_self_exe
.clone()
.ok_or_else(|| anyhow::anyhow!("Codex executable path is not configured"))?;
let runtime_paths = ExecServerRuntimePaths::new(
let runtime_paths = ExecServerRuntimeOptions::new(
codex_self_exe,
arg0_paths.codex_linux_sandbox_exe.clone(),
)?
.with_linux_sandbox_pid_namespace(self.linux_sandbox_pid_namespace);
.with_linux_sandbox_pid_namespace(self.linux_sandbox_pid_namespace)
.with_proxy_private_ips_via_upstream(self.proxy_private_ips_via_upstream);
if let Some(base_url) = self.remote.take() {
let environment_id = self.environment_id.take().ok_or_else(|| {
anyhow::anyhow!("--environment-id is required when --remote is set")
@@ -1,6 +1,5 @@
---
source: cli/src/exec_server_args_tests.rs
assertion_line: 36
expression: help_text
---
[EXPERIMENTAL] Run the standalone exec-server service
@@ -40,6 +39,14 @@ Options:
[default: isolate]
--proxy-private-ips-via-upstream
Allow permitted private IP destinations to use the configured upstream
proxy. If no valid upstream proxy applies to the request protocol,
connect directly. Loopback stays local. This flag does not require
upstream routing
[env: CODEX_EXEC_SERVER_PROXY_PRIVATE_IPS_VIA_UPSTREAM]
--concurrent-requests <COUNT>
Maximum number of requests to process concurrently on each connection