@@ -7,44 +7,33 @@ import (
7
7
"log/slog"
8
8
"os"
9
9
"os/exec"
10
- "strings"
11
- "syscall"
12
10
"time"
13
11
)
14
12
15
13
// Linux implements jail.Commander using Linux network namespaces
16
14
type Linux struct {
17
- namespace string
18
- vethHost string // Host-side veth interface name for iptables rules
19
- logger * slog.Logger
20
- preparedEnv map [string ]string
21
- procAttr * syscall.SysProcAttr
22
- httpProxyPort int
23
- httpsProxyPort int
24
- user string
25
- homeDir string
26
- uid int
27
- gid int
15
+ logger * slog.Logger
16
+ namespace string
17
+ vethHost string // Host-side veth interface name for iptables rules
18
+ commandEnv []string
19
+ httpProxyPort int
20
+ tlsConfigDir string
21
+ caCertPath string
22
+ userInfo UserInfo
28
23
}
29
24
30
- // NewLinux creates a new Linux network jail instance
31
25
func NewLinux (config Config ) (* Linux , error ) {
32
- // Initialize preparedEnv with config environment variables
33
- preparedEnv := make (map [string ]string )
34
- for key , value := range config .Env {
35
- preparedEnv [key ] = value
36
- }
37
-
38
26
return & Linux {
39
- namespace : newNamespaceName (),
40
- logger : config .Logger ,
41
- preparedEnv : preparedEnv ,
42
- httpProxyPort : config .HttpProxyPort ,
43
- httpsProxyPort : config .HttpsProxyPort ,
27
+ logger : config .Logger ,
28
+ namespace : newNamespaceName (),
29
+ httpProxyPort : config .HttpProxyPort ,
30
+ tlsConfigDir : config .TlsConfigDir ,
31
+ caCertPath : config .CACertPath ,
32
+ userInfo : config .UserInfo ,
44
33
}, nil
45
34
}
46
35
47
- // Setup creates network namespace and configures iptables rules
36
+ // Start creates network namespace and configures iptables rules
48
37
func (l * Linux ) Start () error {
49
38
l .logger .Debug ("Setup called" )
50
39
@@ -75,30 +64,12 @@ func (l *Linux) Start() error {
75
64
76
65
// Prepare environment once during setup
77
66
l .logger .Debug ("Preparing environment" )
78
-
79
- // Start with current environment
80
- for _ , envVar := range os .Environ () {
81
- if parts := strings .SplitN (envVar , "=" , 2 ); len (parts ) == 2 {
82
- // Only set if not already set by config
83
- if _ , exists := l .preparedEnv [parts [0 ]]; ! exists {
84
- l .preparedEnv [parts [0 ]] = parts [1 ]
85
- }
86
- }
87
- }
88
-
89
- // Set HOME to original user's home directory
90
- l .preparedEnv ["HOME" ] = l .homeDir
91
- // Set USER to original username
92
- l .preparedEnv ["USER" ] = l .user
93
- // Set LOGNAME to original username (some tools check this instead of USER)
94
- l .preparedEnv ["LOGNAME" ] = l .user
95
-
96
- l .procAttr = & syscall.SysProcAttr {
97
- Credential : & syscall.Credential {
98
- Uid : uint32 (l .uid ),
99
- Gid : uint32 (l .gid ),
100
- },
101
- }
67
+ e := getEnvs (l .tlsConfigDir , l .caCertPath )
68
+ l .commandEnv = mergeEnvs (e , map [string ]string {
69
+ "HOME" : l .userInfo .HomeDir ,
70
+ "USER" : l .userInfo .Username ,
71
+ "LOGNAME" : l .userInfo .Username ,
72
+ })
102
73
103
74
l .logger .Debug ("Setup completed successfully" )
104
75
return nil
@@ -116,23 +87,15 @@ func (l *Linux) Command(command []string) *exec.Cmd {
116
87
117
88
cmd := exec .Command ("ip" , cmdArgs [1 :]... )
118
89
119
- // Use prepared environment from Open method
120
- env := make ([]string , 0 , len (l .preparedEnv ))
121
- for key , value := range l .preparedEnv {
122
- env = append (env , fmt .Sprintf ("%s=%s" , key , value ))
123
- }
124
- cmd .Env = env
90
+ cmd .Env = l .commandEnv
125
91
cmd .Stdin = os .Stdin
126
92
cmd .Stdout = os .Stdout
127
93
cmd .Stderr = os .Stderr
128
94
129
- // Use prepared process attributes from Open method
130
- cmd .SysProcAttr = l .procAttr
131
-
132
95
return cmd
133
96
}
134
97
135
- // Cleanup removes the network namespace and iptables rules
98
+ // Close removes the network namespace and iptables rules
136
99
func (l * Linux ) Close () error {
137
100
// Remove iptables rules
138
101
err := l .removeIptables ()
@@ -246,23 +209,22 @@ func (l *Linux) setupIptables() error {
246
209
return fmt .Errorf ("failed to add NAT rule: %v" , err )
247
210
}
248
211
249
- // COMPREHENSIVE APPROACH: Intercept ALL TCP traffic from namespace
250
- // Use PREROUTING on host to catch traffic after it exits namespace but before routing
251
- // This ensures NO TCP traffic can bypass the proxy
252
- cmd = exec .Command ("iptables" , "-t" , "nat" , "-A" , "PREROUTING" , "-i" , l .vethHost , "-p" , "tcp" , "-j" , "REDIRECT" , "--to-ports" , fmt .Sprintf ("%d" , l .httpsProxyPort ))
212
+ // COMPREHENSIVE APPROACH: Route ALL TCP traffic to HTTP proxy
213
+ // The HTTP proxy will intelligently handle both HTTP and TLS traffic
214
+ cmd = exec .Command ("iptables" , "-t" , "nat" , "-A" , "PREROUTING" , "-i" , l .vethHost , "-p" , "tcp" , "-j" , "REDIRECT" , "--to-ports" , fmt .Sprintf ("%d" , l .httpProxyPort ))
253
215
err = cmd .Run ()
254
216
if err != nil {
255
217
return fmt .Errorf ("failed to add comprehensive TCP redirect rule: %v" , err )
256
218
}
257
219
258
- l .logger .Debug ("Comprehensive TCP jailing enabled" , "interface" , l .vethHost , "proxy_port" , l .httpsProxyPort )
220
+ l .logger .Debug ("Comprehensive TCP jailing enabled" , "interface" , l .vethHost , "proxy_port" , l .httpProxyPort )
259
221
return nil
260
222
}
261
223
262
224
// removeIptables removes iptables rules
263
225
func (l * Linux ) removeIptables () error {
264
226
// Remove comprehensive TCP redirect rule
265
- cmd := exec .Command ("iptables" , "-t" , "nat" , "-D" , "PREROUTING" , "-i" , l .vethHost , "-p" , "tcp" , "-j" , "REDIRECT" , "--to-ports" , fmt .Sprintf ("%d" , l .httpsProxyPort ))
227
+ cmd := exec .Command ("iptables" , "-t" , "nat" , "-D" , "PREROUTING" , "-i" , l .vethHost , "-p" , "tcp" , "-j" , "REDIRECT" , "--to-ports" , fmt .Sprintf ("%d" , l .httpProxyPort ))
266
228
cmd .Run () // Ignore errors during cleanup
267
229
268
230
// Remove NAT rule
@@ -280,4 +242,4 @@ func (l *Linux) removeNamespace() error {
280
242
return fmt .Errorf ("failed to remove namespace: %v" , err )
281
243
}
282
244
return nil
283
- }
245
+ }
0 commit comments