@@ -7,7 +7,10 @@ import (
7
7
"log/slog"
8
8
"os"
9
9
"os/exec"
10
+ "syscall"
10
11
"time"
12
+
13
+ "golang.org/x/sys/unix"
11
14
)
12
15
13
16
// LinuxJail implements Jailer using Linux network namespaces
@@ -46,47 +49,48 @@ func (l *LinuxJail) Start() error {
46
49
e := getEnvs (l .configDir , l .caCertPath )
47
50
l .commandEnv = mergeEnvs (e , map [string ]string {})
48
51
49
- // Setup DNS configuration BEFORE creating namespace
50
- // This ensures the namespace-specific resolv.conf is available when namespace is created
51
- err := l .setupDNS ()
52
- if err != nil {
53
- return fmt .Errorf ("failed to setup DNS: %v" , err )
54
- }
55
-
56
- // Create namespace
57
- err = l .createNamespace ()
58
- if err != nil {
59
- return fmt .Errorf ("failed to create namespace: %v" , err )
60
- }
61
-
62
- // Setup networking within namespace
63
- err = l .setupNetworking ()
64
- if err != nil {
65
- return fmt .Errorf ("failed to setup networking: %v" , err )
66
- }
67
-
68
- // Setup iptables rules on host
69
- err = l .setupIptables ()
70
- if err != nil {
71
- return fmt .Errorf ("failed to setup iptables: %v" , err )
72
- }
73
-
74
52
return nil
75
53
}
76
54
77
55
// Command returns an exec.Cmd configured to run within the network namespace
78
56
func (l * LinuxJail ) Command (command []string ) * exec.Cmd {
79
57
l .logger .Debug ("Creating command with namespace" , "namespace" , l .namespace )
80
58
81
- cmdArgs := []string {"netns" , "exec" , l .namespace }
82
- cmdArgs = append (cmdArgs , command ... )
83
-
84
- cmd := exec .Command ("ip" , cmdArgs ... )
59
+ //cmdArgs := []string{"netns", "exec", l.namespace}
60
+ //cmdArgs = append(cmdArgs, command...)
61
+ //
62
+ //cmd := exec.Command("ip", cmdArgs...)
63
+ cmd := exec .Command (command [0 ], command [1 :]... )
85
64
cmd .Env = l .commandEnv
65
+ cmd .Env = append (cmd .Env , "CHILD=true" )
66
+
67
+ cmd .SysProcAttr = & syscall.SysProcAttr {
68
+ Cloneflags : syscall .CLONE_NEWUSER | syscall .CLONE_NEWNET ,
69
+ UidMappings : []syscall.SysProcIDMap {
70
+ {ContainerID : 0 , HostID : os .Getuid (), Size : 1 },
71
+ },
72
+ GidMappings : []syscall.SysProcIDMap {
73
+ {ContainerID : 0 , HostID : os .Getgid (), Size : 1 },
74
+ },
75
+ }
86
76
87
77
return cmd
88
78
}
89
79
80
+ func (l * LinuxJail ) ConfigureAfterRun (pidInt int ) {
81
+ err := l .setupParentNetworking (pidInt )
82
+ if err != nil {
83
+ fmt .Fprintf (os .Stderr , "failed setupParentNetworking: %v\n " , err )
84
+ os .Exit (1 )
85
+ }
86
+
87
+ err = l .setupIptables ()
88
+ if err != nil {
89
+ fmt .Fprintf (os .Stderr , "can't setup iptables: %v\n " , err )
90
+ os .Exit (1 )
91
+ }
92
+ }
93
+
90
94
// Close removes the network namespace and iptables rules
91
95
func (l * LinuxJail ) Close () error {
92
96
l .logger .Debug ("Close called" )
@@ -133,31 +137,51 @@ func (l *LinuxJail) createNamespace() error {
133
137
}
134
138
135
139
// setupNetworking configures networking within the namespace
136
- func (l * LinuxJail ) setupNetworking () error {
140
+ func (l * LinuxJail ) setupParentNetworking (pidInt int ) error {
141
+ PID := fmt .Sprintf ("%v" , pidInt )
142
+
137
143
// Create veth pair with short names (Linux interface names limited to 15 chars)
138
144
// Generate unique ID to avoid conflicts
139
145
uniqueID := fmt .Sprintf ("%d" , time .Now ().UnixNano ()% 10000000 ) // 7 digits max
140
- vethHost := fmt .Sprintf ("veth_h_%s" , uniqueID ) // veth_h_1234567 = 14 chars
141
- vethNetJail := fmt .Sprintf ("veth_n_%s" , uniqueID ) // veth_n_1234567 = 14 chars
146
+ uniqueID = "1111111"
147
+ vethHost := fmt .Sprintf ("veth_h_%s" , uniqueID ) // veth_h_1234567 = 14 chars
148
+ vethNetJail := fmt .Sprintf ("veth_n_%s" , uniqueID ) // veth_n_1234567 = 14 chars
142
149
143
150
// Store veth interface name for iptables rules
144
151
l .vethHost = vethHost
145
152
146
153
setupCmds := []struct {
147
154
description string
148
155
command * exec.Cmd
156
+ ambientCaps []uintptr
149
157
}{
150
- {"create veth pair" , exec .Command ("ip" , "link" , "add" , vethHost , "type" , "veth" , "peer" , "name" , vethNetJail )},
151
- {"move veth to namespace" , exec .Command ("ip" , "link" , "set" , vethNetJail , "netns" , l .namespace )},
152
- {"configure host veth" , exec .Command ("ip" , "addr" , "add" , "192.168.100.1/24" , "dev" , vethHost )},
153
- {"bring up host veth" , exec .Command ("ip" , "link" , "set" , vethHost , "up" )},
154
- {"configure namespace veth" , exec .Command ("ip" , "netns" , "exec" , l .namespace , "ip" , "addr" , "add" , "192.168.100.2/24" , "dev" , vethNetJail )},
155
- {"bring up namespace veth" , exec .Command ("ip" , "netns" , "exec" , l .namespace , "ip" , "link" , "set" , vethNetJail , "up" )},
156
- {"bring up loopback" , exec .Command ("ip" , "netns" , "exec" , l .namespace , "ip" , "link" , "set" , "lo" , "up" )},
157
- {"set default route in namespace" , exec .Command ("ip" , "netns" , "exec" , l .namespace , "ip" , "route" , "add" , "default" , "via" , "192.168.100.1" )},
158
+ {
159
+ "create veth pair" ,
160
+ exec .Command ("ip" , "link" , "add" , vethHost , "type" , "veth" , "peer" , "name" , vethNetJail ),
161
+ []uintptr {uintptr (unix .CAP_NET_ADMIN )},
162
+ },
163
+ {
164
+ "move veth to namespace" ,
165
+ exec .Command ("ip" , "link" , "set" , vethNetJail , "netns" , PID ),
166
+ []uintptr {uintptr (unix .CAP_NET_ADMIN )},
167
+ },
168
+ {
169
+ "configure host veth" ,
170
+ exec .Command ("ip" , "addr" , "add" , "192.168.100.1/24" , "dev" , vethHost ),
171
+ []uintptr {uintptr (unix .CAP_NET_ADMIN )},
172
+ },
173
+ {
174
+ "bring up host veth" ,
175
+ exec .Command ("ip" , "link" , "set" , vethHost , "up" ),
176
+ []uintptr {uintptr (unix .CAP_NET_ADMIN )},
177
+ },
158
178
}
159
179
160
180
for _ , command := range setupCmds {
181
+ command .command .SysProcAttr = & syscall.SysProcAttr {
182
+ AmbientCaps : command .ambientCaps ,
183
+ }
184
+
161
185
if err := command .command .Run (); err != nil {
162
186
return fmt .Errorf ("failed to %s: %v" , command .description , err )
163
187
}
@@ -166,6 +190,48 @@ func (l *LinuxJail) setupNetworking() error {
166
190
return nil
167
191
}
168
192
193
+ // setupChildNetworking configures networking within the namespace
194
+ func SetupChildNetworking (vethNetJail string ) error {
195
+ setupCmds := []struct {
196
+ description string
197
+ command * exec.Cmd
198
+ ambientCaps []uintptr
199
+ }{
200
+ {
201
+ "configure namespace veth" ,
202
+ exec .Command ("ip" , "addr" , "add" , "192.168.100.2/24" , "dev" , vethNetJail ),
203
+ []uintptr {uintptr (unix .CAP_NET_ADMIN )},
204
+ },
205
+ {
206
+ "bring up namespace veth" ,
207
+ exec .Command ("ip" , "link" , "set" , vethNetJail , "up" ),
208
+ []uintptr {uintptr (unix .CAP_NET_ADMIN )},
209
+ },
210
+ {
211
+ "bring up loopback" ,
212
+ exec .Command ("ip" , "link" , "set" , "lo" , "up" ),
213
+ []uintptr {uintptr (unix .CAP_NET_ADMIN )},
214
+ },
215
+ {
216
+ "set default route in namespace" ,
217
+ exec .Command ("ip" , "route" , "add" , "default" , "via" , "192.168.100.1" ),
218
+ []uintptr {uintptr (unix .CAP_NET_ADMIN )},
219
+ },
220
+ }
221
+
222
+ for _ , command := range setupCmds {
223
+ command .command .SysProcAttr = & syscall.SysProcAttr {
224
+ AmbientCaps : command .ambientCaps ,
225
+ }
226
+
227
+ if output , err := command .command .CombinedOutput (); err != nil {
228
+ return fmt .Errorf ("failed to %s: %v, output: %s, args: %v" , command .description , err , output , command .command .Args )
229
+ }
230
+ }
231
+
232
+ return nil
233
+ }
234
+
169
235
// setupDNS configures DNS resolution for the namespace
170
236
// This ensures reliable DNS resolution by using public DNS servers
171
237
// instead of relying on the host's potentially complex DNS configuration
@@ -204,6 +270,9 @@ func (l *LinuxJail) setupIptables() error {
204
270
205
271
// NAT rules for outgoing traffic (MASQUERADE for return traffic)
206
272
cmd = exec .Command ("iptables" , "-t" , "nat" , "-A" , "POSTROUTING" , "-s" , "192.168.100.0/24" , "-j" , "MASQUERADE" )
273
+ cmd .SysProcAttr = & syscall.SysProcAttr {
274
+ AmbientCaps : []uintptr {uintptr (unix .CAP_NET_ADMIN )},
275
+ }
207
276
err := cmd .Run ()
208
277
if err != nil {
209
278
return fmt .Errorf ("failed to add NAT rule: %v" , err )
@@ -212,22 +281,31 @@ func (l *LinuxJail) setupIptables() error {
212
281
// COMPREHENSIVE APPROACH: Route ALL TCP traffic to HTTP proxy
213
282
// The HTTP proxy will intelligently handle both HTTP and TLS traffic
214
283
cmd = exec .Command ("iptables" , "-t" , "nat" , "-A" , "PREROUTING" , "-i" , l .vethHost , "-p" , "tcp" , "-j" , "REDIRECT" , "--to-ports" , fmt .Sprintf ("%d" , l .httpProxyPort ))
284
+ cmd .SysProcAttr = & syscall.SysProcAttr {
285
+ AmbientCaps : []uintptr {uintptr (unix .CAP_NET_ADMIN )},
286
+ }
215
287
err = cmd .Run ()
216
288
if err != nil {
217
289
return fmt .Errorf ("failed to add comprehensive TCP redirect rule: %v" , err )
218
290
}
219
291
220
292
// TODO: clean up this rules
221
293
cmd = exec .Command ("iptables" , "-A" , "FORWARD" , "-s" , "192.168.100.0/24" , "-j" , "ACCEPT" )
294
+ cmd .SysProcAttr = & syscall.SysProcAttr {
295
+ AmbientCaps : []uintptr {uintptr (unix .CAP_NET_ADMIN )},
296
+ }
222
297
err = cmd .Run ()
223
298
if err != nil {
224
- return err
299
+ return fmt . Errorf ( "forward -s error: %v, output: %v" )
225
300
}
226
301
227
302
cmd = exec .Command ("iptables" , "-A" , "FORWARD" , "-d" , "192.168.100.0/24" , "-j" , "ACCEPT" )
303
+ cmd .SysProcAttr = & syscall.SysProcAttr {
304
+ AmbientCaps : []uintptr {uintptr (unix .CAP_NET_ADMIN )},
305
+ }
228
306
err = cmd .Run ()
229
307
if err != nil {
230
- return err
308
+ return fmt . Errorf ( "forward -r error: %v" , err )
231
309
}
232
310
233
311
l .logger .Debug ("Comprehensive TCP boundarying enabled" , "interface" , l .vethHost , "proxy_port" , l .httpProxyPort )
0 commit comments