@@ -13,12 +13,42 @@ import (
13
13
"golang.org/x/sys/unix"
14
14
)
15
15
16
+ type command struct {
17
+ description string
18
+ cmd * exec.Cmd
19
+ ambientCaps []uintptr
20
+ }
21
+
22
+ type commandRunner struct {
23
+ commands []* command
24
+ }
25
+
26
+ func newCommandRunner (commands []* command ) * commandRunner {
27
+ return & commandRunner {
28
+ commands : commands ,
29
+ }
30
+ }
31
+
32
+ func (r * commandRunner ) run () error {
33
+ for _ , command := range r .commands {
34
+ command .cmd .SysProcAttr = & syscall.SysProcAttr {
35
+ AmbientCaps : command .ambientCaps ,
36
+ }
37
+
38
+ if err := command .cmd .Run (); err != nil {
39
+ return fmt .Errorf ("failed to %s: %v" , command .description , err )
40
+ }
41
+ }
42
+
43
+ return nil
44
+ }
45
+
16
46
// LinuxJail implements Jailer using Linux network namespaces
17
47
type LinuxJail struct {
18
48
logger * slog.Logger
19
49
namespace string
20
- vethHost string // Host-side veth interface name for iptables rules
21
- vethNetJail string // Host -side veth interface name for iptables rules
50
+ vethHostName string // Host-side veth interface name for iptables rules
51
+ vethJailName string // Jail -side veth interface name for iptables rules
22
52
commandEnv []string
23
53
httpProxyPort int
24
54
configDir string
@@ -44,7 +74,7 @@ func NewLinuxJail(config Config) (*LinuxJail, error) {
44
74
}
45
75
46
76
// Start creates network namespace and configures iptables rules
47
- func (l * LinuxJail ) Start () error {
77
+ func (l * LinuxJail ) ConfigureBeforeCommandExecution () error {
48
78
l .logger .Debug ("Setup called" )
49
79
50
80
e := getEnvs (l .configDir , l .caCertPath )
@@ -53,43 +83,32 @@ func (l *LinuxJail) Start() error {
53
83
// Create veth pair with short names (Linux interface names limited to 15 chars)
54
84
// Generate unique ID to avoid conflicts
55
85
uniqueID := fmt .Sprintf ("%d" , time .Now ().UnixNano ()% 10000000 ) // 7 digits max
56
- vethHost := fmt .Sprintf ("veth_h_%s" , uniqueID ) // veth_h_1234567 = 14 chars
57
- vethNetJail := fmt .Sprintf ("veth_n_%s" , uniqueID ) // veth_n_1234567 = 14 chars
86
+ vethHostName := fmt .Sprintf ("veth_h_%s" , uniqueID ) // veth_h_1234567 = 14 chars
87
+ vethJailName := fmt .Sprintf ("veth_n_%s" , uniqueID ) // veth_n_1234567 = 14 chars
58
88
59
89
// Store veth interface name for iptables rules
60
- l .vethHost = vethHost
61
- l .vethNetJail = vethNetJail
90
+ l .vethHostName = vethHostName
91
+ l .vethJailName = vethJailName
62
92
63
- setupCmds := []struct {
64
- description string
65
- command * exec.Cmd
66
- ambientCaps []uintptr
67
- }{
93
+ runner := newCommandRunner ([]* command {
68
94
{
69
95
"create veth pair" ,
70
- exec .Command ("ip" , "link" , "add" , vethHost , "type" , "veth" , "peer" , "name" , vethNetJail ),
96
+ exec .Command ("ip" , "link" , "add" , vethHostName , "type" , "veth" , "peer" , "name" , vethJailName ),
71
97
[]uintptr {uintptr (unix .CAP_NET_ADMIN )},
72
98
},
73
99
{
74
100
"configure host veth" ,
75
- exec .Command ("ip" , "addr" , "add" , "192.168.100.1/24" , "dev" , vethHost ),
101
+ exec .Command ("ip" , "addr" , "add" , "192.168.100.1/24" , "dev" , vethHostName ),
76
102
[]uintptr {uintptr (unix .CAP_NET_ADMIN )},
77
103
},
78
104
{
79
105
"bring up host veth" ,
80
- exec .Command ("ip" , "link" , "set" , vethHost , "up" ),
106
+ exec .Command ("ip" , "link" , "set" , vethHostName , "up" ),
81
107
[]uintptr {uintptr (unix .CAP_NET_ADMIN )},
82
108
},
83
- }
84
-
85
- for _ , command := range setupCmds {
86
- command .command .SysProcAttr = & syscall.SysProcAttr {
87
- AmbientCaps : command .ambientCaps ,
88
- }
89
-
90
- if err := command .command .Run (); err != nil {
91
- return fmt .Errorf ("failed to %s: %v" , command .description , err )
92
- }
109
+ })
110
+ if err := runner .run (); err != nil {
111
+ return err
93
112
}
94
113
95
114
return nil
@@ -99,10 +118,6 @@ func (l *LinuxJail) Start() error {
99
118
func (l * LinuxJail ) Command (command []string ) * exec.Cmd {
100
119
l .logger .Debug ("Creating command with namespace" , "namespace" , l .namespace )
101
120
102
- //cmdArgs := []string{"netns", "exec", l.namespace}
103
- //cmdArgs = append(cmdArgs, command...)
104
- //
105
- //cmd := exec.Command("ip", cmdArgs...)
106
121
cmd := exec .Command (command [0 ], command [1 :]... )
107
122
cmd .Env = l .commandEnv
108
123
cmd .Env = append (cmd .Env , "CHILD=true" )
@@ -120,7 +135,7 @@ func (l *LinuxJail) Command(command []string) *exec.Cmd {
120
135
return cmd
121
136
}
122
137
123
- func (l * LinuxJail ) ConfigureAfterRun (pidInt int ) {
138
+ func (l * LinuxJail ) ConfigureAfterCommandExecution (pidInt int ) {
124
139
err := l .setupParentNetworking (pidInt )
125
140
if err != nil {
126
141
fmt .Fprintf (os .Stderr , "failed setupParentNetworking: %v\n " , err )
@@ -136,7 +151,7 @@ func (l *LinuxJail) ConfigureAfterRun(pidInt int) {
136
151
137
152
func (l * LinuxJail ) GetNetworkConfiguration () NetworkConfiguration {
138
153
return NetworkConfiguration {
139
- VethNetJail : l .vethNetJail ,
154
+ VethNetJail : l .vethJailName ,
140
155
}
141
156
}
142
157
@@ -189,38 +204,23 @@ func (l *LinuxJail) createNamespace() error {
189
204
func (l * LinuxJail ) setupParentNetworking (pidInt int ) error {
190
205
PID := fmt .Sprintf ("%v" , pidInt )
191
206
192
- setupCmds := []struct {
193
- description string
194
- command * exec.Cmd
195
- ambientCaps []uintptr
196
- }{
207
+ runner := newCommandRunner ([]* command {
197
208
{
198
209
"move veth to namespace" ,
199
- exec .Command ("ip" , "link" , "set" , l .vethNetJail , "netns" , PID ),
210
+ exec .Command ("ip" , "link" , "set" , l .vethJailName , "netns" , PID ),
200
211
[]uintptr {uintptr (unix .CAP_NET_ADMIN )},
201
212
},
202
- }
203
-
204
- for _ , command := range setupCmds {
205
- command .command .SysProcAttr = & syscall.SysProcAttr {
206
- AmbientCaps : command .ambientCaps ,
207
- }
208
-
209
- if err := command .command .Run (); err != nil {
210
- return fmt .Errorf ("failed to %s: %v" , command .description , err )
211
- }
213
+ })
214
+ if err := runner .run (); err != nil {
215
+ return err
212
216
}
213
217
214
218
return nil
215
219
}
216
220
217
221
// setupChildNetworking configures networking within the namespace
218
222
func SetupChildNetworking (vethNetJail string ) error {
219
- setupCmds := []struct {
220
- description string
221
- command * exec.Cmd
222
- ambientCaps []uintptr
223
- }{
223
+ runner := newCommandRunner ([]* command {
224
224
{
225
225
"configure namespace veth" ,
226
226
exec .Command ("ip" , "addr" , "add" , "192.168.100.2/24" , "dev" , vethNetJail ),
@@ -241,16 +241,9 @@ func SetupChildNetworking(vethNetJail string) error {
241
241
exec .Command ("ip" , "route" , "add" , "default" , "via" , "192.168.100.1" ),
242
242
[]uintptr {uintptr (unix .CAP_NET_ADMIN )},
243
243
},
244
- }
245
-
246
- for _ , command := range setupCmds {
247
- command .command .SysProcAttr = & syscall.SysProcAttr {
248
- AmbientCaps : command .ambientCaps ,
249
- }
250
-
251
- if output , err := command .command .CombinedOutput (); err != nil {
252
- return fmt .Errorf ("failed to %s: %v, output: %s, args: %v" , command .description , err , output , command .command .Args )
253
- }
244
+ })
245
+ if err := runner .run (); err != nil {
246
+ return err
254
247
}
255
248
256
249
return nil
@@ -304,7 +297,7 @@ func (l *LinuxJail) setupIptables() error {
304
297
305
298
// COMPREHENSIVE APPROACH: Route ALL TCP traffic to HTTP proxy
306
299
// The HTTP proxy will intelligently handle both HTTP and TLS traffic
307
- cmd = exec .Command ("iptables" , "-t" , "nat" , "-A" , "PREROUTING" , "-i" , l .vethHost , "-p" , "tcp" , "-j" , "REDIRECT" , "--to-ports" , fmt .Sprintf ("%d" , l .httpProxyPort ))
300
+ cmd = exec .Command ("iptables" , "-t" , "nat" , "-A" , "PREROUTING" , "-i" , l .vethHostName , "-p" , "tcp" , "-j" , "REDIRECT" , "--to-ports" , fmt .Sprintf ("%d" , l .httpProxyPort ))
308
301
cmd .SysProcAttr = & syscall.SysProcAttr {
309
302
AmbientCaps : []uintptr {uintptr (unix .CAP_NET_ADMIN )},
310
303
}
@@ -332,14 +325,14 @@ func (l *LinuxJail) setupIptables() error {
332
325
return fmt .Errorf ("forward -r error: %v" , err )
333
326
}
334
327
335
- l .logger .Debug ("Comprehensive TCP boundarying enabled" , "interface" , l .vethHost , "proxy_port" , l .httpProxyPort )
328
+ l .logger .Debug ("Comprehensive TCP boundarying enabled" , "interface" , l .vethHostName , "proxy_port" , l .httpProxyPort )
336
329
return nil
337
330
}
338
331
339
332
// cleanupIptables removes iptables rules
340
333
func (l * LinuxJail ) cleanupIptables () error {
341
334
// Remove comprehensive TCP redirect rule
342
- cmd := exec .Command ("iptables" , "-t" , "nat" , "-D" , "PREROUTING" , "-i" , l .vethHost , "-p" , "tcp" , "-j" , "REDIRECT" , "--to-ports" , fmt .Sprintf ("%d" , l .httpProxyPort ))
335
+ cmd := exec .Command ("iptables" , "-t" , "nat" , "-D" , "PREROUTING" , "-i" , l .vethHostName , "-p" , "tcp" , "-j" , "REDIRECT" , "--to-ports" , fmt .Sprintf ("%d" , l .httpProxyPort ))
343
336
err := cmd .Run ()
344
337
if err != nil {
345
338
l .logger .Error ("Failed to remove TCP redirect rule" , "error" , err )
0 commit comments