Enable SOCKS defaults for common local network proxy use cases (#11362)

## Summary
- enable local-use defaults in network proxy settings: SOCKS5 on, SOCKS5
UDP on, upstream proxying on, and local binding on
- add a regression test that asserts the full
`NetworkProxySettings::default()` baseline
- Fixed managed listener reservation behavior.
Before: we always reserved a loopback SOCKS listener, even when
enable_socks5 = false.
Now: SOCKS listener is only reserved when SOCKS is enabled.
- Fixed /debug-config env output for SOCKS-disabled sessions.
ALL_PROXY now shows the HTTP proxy URL when SOCKS is disabled (instead
of incorrectly showing socks5h://...).


## Validation
- just fmt
- cargo test -p codex-network-proxy
- cargo clippy -p codex-network-proxy --all-targets
This commit is contained in:
viyatb-oai
2026-02-10 15:13:52 -08:00
committed by GitHub
parent 623d3f4071
commit 1d47927aa0
5 changed files with 152 additions and 29 deletions

View File

@@ -29,10 +29,10 @@ struct ReservedListeners {
}
impl ReservedListeners {
fn new(http: StdTcpListener, socks: StdTcpListener, admin: StdTcpListener) -> Self {
fn new(http: StdTcpListener, socks: Option<StdTcpListener>, admin: StdTcpListener) -> Self {
Self {
http: Mutex::new(Some(http)),
socks: Mutex::new(Some(socks)),
socks: Mutex::new(socks),
admin: Mutex::new(Some(admin)),
}
}
@@ -133,15 +133,20 @@ impl NetworkProxyBuilder {
let current_cfg = state.current_cfg().await?;
let (requested_http_addr, requested_socks_addr, requested_admin_addr, reserved_listeners) =
if self.managed_by_codex {
let runtime = config::resolve_runtime(&current_cfg)?;
let (http_listener, socks_listener, admin_listener) =
reserve_loopback_ephemeral_listeners()
reserve_loopback_ephemeral_listeners(current_cfg.network.enable_socks5)
.context("reserve managed loopback proxy listeners")?;
let http_addr = http_listener
.local_addr()
.context("failed to read reserved HTTP proxy address")?;
let socks_addr = socks_listener
.local_addr()
.context("failed to read reserved SOCKS5 proxy address")?;
let socks_addr = if let Some(socks_listener) = socks_listener.as_ref() {
socks_listener
.local_addr()
.context("failed to read reserved SOCKS5 proxy address")?
} else {
runtime.socks_addr
};
let admin_addr = admin_listener
.local_addr()
.context("failed to read reserved admin API address")?;
@@ -186,13 +191,19 @@ impl NetworkProxyBuilder {
}
}
fn reserve_loopback_ephemeral_listeners() -> Result<(StdTcpListener, StdTcpListener, StdTcpListener)>
{
Ok((
reserve_loopback_ephemeral_listener().context("reserve HTTP proxy listener")?,
reserve_loopback_ephemeral_listener().context("reserve SOCKS5 proxy listener")?,
reserve_loopback_ephemeral_listener().context("reserve admin API listener")?,
))
fn reserve_loopback_ephemeral_listeners(
reserve_socks_listener: bool,
) -> Result<(StdTcpListener, Option<StdTcpListener>, StdTcpListener)> {
let http_listener =
reserve_loopback_ephemeral_listener().context("reserve HTTP proxy listener")?;
let socks_listener = if reserve_socks_listener {
Some(reserve_loopback_ephemeral_listener().context("reserve SOCKS5 proxy listener")?)
} else {
None
};
let admin_listener =
reserve_loopback_ephemeral_listener().context("reserve admin API listener")?;
Ok((http_listener, socks_listener, admin_listener))
}
fn reserve_loopback_ephemeral_listener() -> Result<StdTcpListener> {
@@ -612,6 +623,43 @@ mod tests {
);
}
#[tokio::test]
async fn managed_proxy_builder_does_not_reserve_socks_listener_when_disabled() {
let settings = NetworkProxySettings {
enable_socks5: false,
socks_url: "http://127.0.0.1:43129".to_string(),
..NetworkProxySettings::default()
};
let state = Arc::new(network_proxy_state_for_policy(settings));
let proxy = match NetworkProxy::builder().state(state).build().await {
Ok(proxy) => proxy,
Err(err) => {
if err
.chain()
.any(|cause| cause.to_string().contains("Operation not permitted"))
{
return;
}
panic!("failed to build managed proxy: {err:#}");
}
};
assert!(proxy.http_addr.ip().is_loopback());
assert!(proxy.admin_addr.ip().is_loopback());
assert_eq!(
proxy.socks_addr,
"127.0.0.1:43129".parse::<SocketAddr>().unwrap()
);
assert!(
proxy
.reserved_listeners
.as_ref()
.expect("managed builder should reserve listeners")
.take_socks()
.is_none()
);
}
#[test]
fn proxy_url_env_value_resolves_lowercase_aliases() {
let mut env = HashMap::new();