Add support for local outbound connections in sandbox configuration

This commit is contained in:
JY Tan
2025-12-22 15:55:01 -08:00
parent 10c571e7d9
commit b98b640f5a
4 changed files with 30 additions and 1 deletions

View File

@@ -71,6 +71,7 @@ Create `~/.fence.json` to configure allowed domains and filesystem access:
| `allowUnixSockets` | List of allowed Unix socket paths (macOS) |
| `allowAllUnixSockets` | Allow all Unix sockets |
| `allowLocalBinding` | Allow binding to local ports |
| `allowLocalOutbound` | Allow outbound connections to localhost, e.g., local DBs (defaults to `allowLocalBinding` if not set) |
| `httpProxyPort` | Fixed port for HTTP proxy (default: random available port) |
| `socksProxyPort` | Fixed port for SOCKS5 proxy (default: random available port) |
@@ -138,6 +139,12 @@ import (
)
func main() {
// Check if platform supports sandboxing (macOS/Linux)
if !fence.IsSupported() {
fmt.Println("Sandboxing not supported on this platform")
return
}
// Create config
cfg := &fence.Config{
Network: fence.NetworkConfig{

View File

@@ -25,6 +25,7 @@ type NetworkConfig struct {
AllowUnixSockets []string `json:"allowUnixSockets,omitempty"`
AllowAllUnixSockets bool `json:"allowAllUnixSockets,omitempty"`
AllowLocalBinding bool `json:"allowLocalBinding,omitempty"`
AllowLocalOutbound *bool `json:"allowLocalOutbound,omitempty"` // If nil, defaults to AllowLocalBinding value
HTTPProxyPort int `json:"httpProxyPort,omitempty"`
SOCKSProxyPort int `json:"socksProxyPort,omitempty"`
}

View File

@@ -33,6 +33,7 @@ type MacOSSandboxParams struct {
AllowUnixSockets []string
AllowAllUnixSockets bool
AllowLocalBinding bool
AllowLocalOutbound bool
ReadDenyPaths []string
WriteAllowPaths []string
WriteDenyPaths []string
@@ -419,10 +420,15 @@ func GenerateSandboxProfile(params MacOSSandboxParams) string {
profile.WriteString("(allow network*)\n")
} else {
if params.AllowLocalBinding {
// Allow binding and inbound connections on localhost (for servers)
profile.WriteString(`(allow network-bind (local ip "localhost:*"))
(allow network-inbound (local ip "localhost:*"))
(allow network-outbound (local ip "localhost:*"))
`)
// Process can make outbound connections to localhost
if params.AllowLocalOutbound {
profile.WriteString(`(allow network-outbound (local ip "localhost:*"))
`)
}
}
if params.AllowAllUnixSockets {
@@ -492,6 +498,11 @@ func WrapCommandMacOS(cfg *config.Config, command string, httpPort, socksPort in
// Enable local binding if ports are exposed or if explicitly configured
allowLocalBinding := cfg.Network.AllowLocalBinding || len(exposedPorts) > 0
allowLocalOutbound := allowLocalBinding
if cfg.Network.AllowLocalOutbound != nil {
allowLocalOutbound = *cfg.Network.AllowLocalOutbound
}
params := MacOSSandboxParams{
Command: command,
NeedsNetworkRestriction: needsNetwork || len(cfg.Network.AllowedDomains) == 0, // Block if no domains allowed
@@ -500,6 +511,7 @@ func WrapCommandMacOS(cfg *config.Config, command string, httpPort, socksPort in
AllowUnixSockets: cfg.Network.AllowUnixSockets,
AllowAllUnixSockets: cfg.Network.AllowAllUnixSockets,
AllowLocalBinding: allowLocalBinding,
AllowLocalOutbound: allowLocalOutbound,
ReadDenyPaths: cfg.Filesystem.DenyRead,
WriteAllowPaths: allowPaths,
WriteDenyPaths: cfg.Filesystem.DenyWrite,
@@ -510,6 +522,9 @@ func WrapCommandMacOS(cfg *config.Config, command string, httpPort, socksPort in
if debug && len(exposedPorts) > 0 {
fmt.Fprintf(os.Stderr, "[fence:macos] Enabling local binding for exposed ports: %v\n", exposedPorts)
}
if debug && allowLocalBinding && !allowLocalOutbound {
fmt.Fprintf(os.Stderr, "[fence:macos] Blocking localhost outbound (AllowLocalOutbound=false)\n")
}
profile := GenerateSandboxProfile(params)

View File

@@ -3,9 +3,15 @@ package fence
import (
"github.com/Use-Tusk/fence/internal/config"
"github.com/Use-Tusk/fence/internal/platform"
"github.com/Use-Tusk/fence/internal/sandbox"
)
// IsSupported returns true if the current platform supports sandboxing (macOS/Linux).
func IsSupported() bool {
return platform.IsSupported()
}
// Config is the configuration for fence.
type Config = config.Config