mirror of
https://github.com/pchuan98/codex.git
synced 2026-07-01 00:31:56 +08:00
fix: unblock private DNS in macOS sandbox (#17370)
## Summary - keep hostname targets proxied by default by removing hostname suffixes from the managed `NO_PROXY` value while preserving private/link-local CIDRs - make the macOS `allow_local_binding` sandbox rules match the local socket shape used by DNS tools by allowing wildcard local binds - allow raw DNS egress to remote port 53 only when `allow_local_binding` is enabled, without opening blanket outbound network access ## Root cause Raw DNS tools do not honor `HTTP_PROXY` or `ALL_PROXY`, so the proxy-only Seatbelt policy blocked their resolver traffic before it could reach host DNS. In the affected managed config, `allow_local_binding = true`, but the existing rule only allowed `localhost:*` binds; `dig`/BIND can bind sockets in a way that needs wildcard local binding. Separately, hostname suffixes in `NO_PROXY` could force internal hostnames to resolve locally instead of through the proxy path. --------- Co-authored-by: Codex <noreply@openai.com>
This commit is contained in:
@@ -249,11 +249,15 @@ fn dynamic_network_policy_for_network(
|
||||
if should_use_restricted_network_policy {
|
||||
let mut policy = String::new();
|
||||
if proxy.allow_local_binding {
|
||||
policy.push_str("; allow loopback local binding and loopback traffic\n");
|
||||
policy.push_str("(allow network-bind (local ip \"localhost:*\"))\n");
|
||||
policy.push_str("; allow local binding and loopback traffic\n");
|
||||
policy.push_str("(allow network-bind (local ip \"*:*\"))\n");
|
||||
policy.push_str("(allow network-inbound (local ip \"localhost:*\"))\n");
|
||||
policy.push_str("(allow network-outbound (remote ip \"localhost:*\"))\n");
|
||||
}
|
||||
if proxy.allow_local_binding && !proxy.ports.is_empty() {
|
||||
policy.push_str("; allow DNS lookups while application traffic remains proxy-routed\n");
|
||||
policy.push_str("(allow network-outbound (remote ip \"*:53\"))\n");
|
||||
}
|
||||
for port in &proxy.ports {
|
||||
policy.push_str(&format!(
|
||||
"(allow network-outbound (remote ip \"localhost:{port}\"))\n"
|
||||
|
||||
@@ -99,13 +99,17 @@ fn create_seatbelt_args_routes_network_through_proxy_ports() {
|
||||
"policy should not include blanket outbound allowance when proxy ports are present:\n{policy}"
|
||||
);
|
||||
assert!(
|
||||
!policy.contains("(allow network-bind (local ip \"localhost:*\"))"),
|
||||
"policy should not allow loopback binding unless explicitly enabled:\n{policy}"
|
||||
!policy.contains("(allow network-bind (local ip \"*:*\"))"),
|
||||
"policy should not allow local binding unless explicitly enabled:\n{policy}"
|
||||
);
|
||||
assert!(
|
||||
!policy.contains("(allow network-inbound (local ip \"localhost:*\"))"),
|
||||
"policy should not allow loopback inbound unless explicitly enabled:\n{policy}"
|
||||
);
|
||||
assert!(
|
||||
!policy.contains("(allow network-outbound (remote ip \"*:53\"))"),
|
||||
"policy should not allow raw DNS unless local binding is explicitly enabled:\n{policy}"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -290,7 +294,7 @@ fn create_seatbelt_args_allows_local_binding_when_explicitly_enabled() {
|
||||
);
|
||||
|
||||
assert!(
|
||||
policy.contains("(allow network-bind (local ip \"localhost:*\"))"),
|
||||
policy.contains("(allow network-bind (local ip \"*:*\"))"),
|
||||
"policy should allow loopback local binding when explicitly enabled:\n{policy}"
|
||||
);
|
||||
assert!(
|
||||
@@ -301,6 +305,10 @@ fn create_seatbelt_args_allows_local_binding_when_explicitly_enabled() {
|
||||
policy.contains("(allow network-outbound (remote ip \"localhost:*\"))"),
|
||||
"policy should allow loopback outbound when explicitly enabled:\n{policy}"
|
||||
);
|
||||
assert!(
|
||||
policy.contains("(allow network-outbound (remote ip \"*:53\"))"),
|
||||
"policy should allow DNS egress when local binding is explicitly enabled:\n{policy}"
|
||||
);
|
||||
assert!(
|
||||
!policy.contains("\n(allow network-outbound)\n"),
|
||||
"policy should keep proxy-routed behavior without blanket outbound allowance:\n{policy}"
|
||||
@@ -338,6 +346,39 @@ fn dynamic_network_policy_preserves_restricted_policy_when_proxy_config_without_
|
||||
!policy.contains("(allow network-outbound (remote ip \"localhost:"),
|
||||
"policy should not include proxy port allowance when proxy config is present without ports:\n{policy}"
|
||||
);
|
||||
assert!(
|
||||
!policy.contains("(allow network-outbound (remote ip \"*:53\"))"),
|
||||
"policy should stay fail-closed for DNS when no proxy ports are available:\n{policy}"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn dynamic_network_policy_blocks_dns_when_local_binding_has_no_proxy_ports() {
|
||||
let policy = dynamic_network_policy(
|
||||
&SandboxPolicy::WorkspaceWrite {
|
||||
writable_roots: vec![],
|
||||
read_only_access: Default::default(),
|
||||
network_access: true,
|
||||
exclude_tmpdir_env_var: false,
|
||||
exclude_slash_tmp: false,
|
||||
},
|
||||
/*enforce_managed_network*/ false,
|
||||
&ProxyPolicyInputs {
|
||||
ports: vec![],
|
||||
has_proxy_config: true,
|
||||
allow_local_binding: true,
|
||||
..ProxyPolicyInputs::default()
|
||||
},
|
||||
);
|
||||
|
||||
assert!(
|
||||
policy.contains("(allow network-bind (local ip \"*:*\"))"),
|
||||
"policy should still allow explicitly configured local binding:\n{policy}"
|
||||
);
|
||||
assert!(
|
||||
!policy.contains("(allow network-outbound (remote ip \"*:53\"))"),
|
||||
"policy should not allow DNS egress when no proxy ports are available:\n{policy}"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -367,6 +408,10 @@ fn dynamic_network_policy_preserves_restricted_policy_for_managed_network_withou
|
||||
!policy.contains("\n(allow network-outbound)\n"),
|
||||
"policy should not include blanket outbound allowance when managed network is active without proxy endpoints:\n{policy}"
|
||||
);
|
||||
assert!(
|
||||
!policy.contains("(allow network-outbound (remote ip \"*:53\"))"),
|
||||
"policy should stay fail-closed for DNS when no proxy endpoints are available:\n{policy}"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
Reference in New Issue
Block a user