@@ -13,121 +13,6 @@ 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
- output , err := command .cmd .CombinedOutput ()
39
- if err != nil {
40
- return fmt .Errorf ("failed to %s: %v, output: %s" , command .description , err , output )
41
- }
42
- }
43
-
44
- return nil
45
- }
46
-
47
- func (l * LinuxJail ) configureParentNetworkingStep1 () error {
48
- // Create veth pair with short names (Linux interface names limited to 15 chars)
49
- // Generate unique ID to avoid conflicts
50
- uniqueID := fmt .Sprintf ("%d" , time .Now ().UnixNano ()% 10000000 ) // 7 digits max
51
- vethHostName := fmt .Sprintf ("veth_h_%s" , uniqueID ) // veth_h_1234567 = 14 chars
52
- vethJailName := fmt .Sprintf ("veth_n_%s" , uniqueID ) // veth_n_1234567 = 14 chars
53
-
54
- // Store veth interface name for iptables rules
55
- l .vethHostName = vethHostName
56
- l .vethJailName = vethJailName
57
-
58
- runner := newCommandRunner ([]* command {
59
- {
60
- "create veth pair" ,
61
- exec .Command ("ip" , "link" , "add" , vethHostName , "type" , "veth" , "peer" , "name" , vethJailName ),
62
- []uintptr {uintptr (unix .CAP_NET_ADMIN )},
63
- },
64
- {
65
- "configure host veth" ,
66
- exec .Command ("ip" , "addr" , "add" , "192.168.100.1/24" , "dev" , vethHostName ),
67
- []uintptr {uintptr (unix .CAP_NET_ADMIN )},
68
- },
69
- {
70
- "bring up host veth" ,
71
- exec .Command ("ip" , "link" , "set" , vethHostName , "up" ),
72
- []uintptr {uintptr (unix .CAP_NET_ADMIN )},
73
- },
74
- })
75
- if err := runner .run (); err != nil {
76
- return err
77
- }
78
-
79
- return nil
80
- }
81
-
82
- // setupNetworking configures networking within the namespace
83
- func (l * LinuxJail ) configureParentNetworkingStep2 (pidInt int ) error {
84
- PID := fmt .Sprintf ("%v" , pidInt )
85
-
86
- runner := newCommandRunner ([]* command {
87
- {
88
- "move veth to namespace" ,
89
- exec .Command ("ip" , "link" , "set" , l .vethJailName , "netns" , PID ),
90
- []uintptr {uintptr (unix .CAP_NET_ADMIN )},
91
- },
92
- })
93
- if err := runner .run (); err != nil {
94
- return err
95
- }
96
-
97
- return nil
98
- }
99
-
100
- // setupChildNetworking configures networking within the namespace
101
- func SetupChildNetworking (vethNetJail string ) error {
102
- runner := newCommandRunner ([]* command {
103
- {
104
- "configure namespace veth" ,
105
- exec .Command ("ip" , "addr" , "add" , "192.168.100.2/24" , "dev" , vethNetJail ),
106
- []uintptr {uintptr (unix .CAP_NET_ADMIN )},
107
- },
108
- {
109
- "bring up namespace veth" ,
110
- exec .Command ("ip" , "link" , "set" , vethNetJail , "up" ),
111
- []uintptr {uintptr (unix .CAP_NET_ADMIN )},
112
- },
113
- {
114
- "bring up loopback" ,
115
- exec .Command ("ip" , "link" , "set" , "lo" , "up" ),
116
- []uintptr {uintptr (unix .CAP_NET_ADMIN )},
117
- },
118
- {
119
- "set default route in namespace" ,
120
- exec .Command ("ip" , "route" , "add" , "default" , "via" , "192.168.100.1" ),
121
- []uintptr {uintptr (unix .CAP_NET_ADMIN )},
122
- },
123
- })
124
- if err := runner .run (); err != nil {
125
- return err
126
- }
127
-
128
- return nil
129
- }
130
-
131
16
// LinuxJail implements Jailer using Linux network namespaces
132
17
type LinuxJail struct {
133
18
logger * slog.Logger
@@ -167,7 +52,7 @@ func (l *LinuxJail) ConfigureBeforeCommandExecution() error {
167
52
168
53
l .commandEnv = getEnvs (l .configDir , l .caCertPath )
169
54
170
- if err := l .configureParentNetworkingStep1 (); err != nil {
55
+ if err := l .configureHostNetworkBeforeCmdExec (); err != nil {
171
56
return err
172
57
}
173
58
if err := l .configureIptables (); err != nil {
@@ -202,7 +87,7 @@ func (l *LinuxJail) Command(command []string) *exec.Cmd {
202
87
// With the child PID known, it moves the jail-side veth into the child’s network
203
88
// namespace.
204
89
func (l * LinuxJail ) ConfigureAfterCommandExecution (pidInt int ) error {
205
- err := l .configureParentNetworkingStep2 (pidInt )
90
+ err := l .configureHostNetworkAfterCmdExec (pidInt )
206
91
if err != nil {
207
92
return fmt .Errorf ("failed to configure parent networking: %v" , err )
208
93
}
@@ -354,3 +239,126 @@ func (l *LinuxJail) removeNamespace() error {
354
239
}
355
240
return nil
356
241
}
242
+
243
+ type command struct {
244
+ description string
245
+ cmd * exec.Cmd
246
+ ambientCaps []uintptr
247
+ }
248
+
249
+ type commandRunner struct {
250
+ commands []* command
251
+ }
252
+
253
+ func newCommandRunner (commands []* command ) * commandRunner {
254
+ return & commandRunner {
255
+ commands : commands ,
256
+ }
257
+ }
258
+
259
+ func (r * commandRunner ) run () error {
260
+ for _ , command := range r .commands {
261
+ command .cmd .SysProcAttr = & syscall.SysProcAttr {
262
+ AmbientCaps : command .ambientCaps ,
263
+ }
264
+
265
+ output , err := command .cmd .CombinedOutput ()
266
+ if err != nil {
267
+ return fmt .Errorf ("failed to %s: %v, output: %s" , command .description , err , output )
268
+ }
269
+ }
270
+
271
+ return nil
272
+ }
273
+
274
+ // configureHostNetworkBeforeCmdExec prepares host-side networking before the target
275
+ // process is started. At this point the target process is not running, so its PID and network
276
+ // namespace ID are not yet known.
277
+ func (l * LinuxJail ) configureHostNetworkBeforeCmdExec () error {
278
+ // Create veth pair with short names (Linux interface names limited to 15 chars)
279
+ // Generate unique ID to avoid conflicts
280
+ uniqueID := fmt .Sprintf ("%d" , time .Now ().UnixNano ()% 10000000 ) // 7 digits max
281
+ vethHostName := fmt .Sprintf ("veth_h_%s" , uniqueID ) // veth_h_1234567 = 14 chars
282
+ vethJailName := fmt .Sprintf ("veth_n_%s" , uniqueID ) // veth_n_1234567 = 14 chars
283
+
284
+ // Store veth interface name for iptables rules
285
+ l .vethHostName = vethHostName
286
+ l .vethJailName = vethJailName
287
+
288
+ runner := newCommandRunner ([]* command {
289
+ {
290
+ "create veth pair" ,
291
+ exec .Command ("ip" , "link" , "add" , vethHostName , "type" , "veth" , "peer" , "name" , vethJailName ),
292
+ []uintptr {uintptr (unix .CAP_NET_ADMIN )},
293
+ },
294
+ {
295
+ "configure host veth" ,
296
+ exec .Command ("ip" , "addr" , "add" , "192.168.100.1/24" , "dev" , vethHostName ),
297
+ []uintptr {uintptr (unix .CAP_NET_ADMIN )},
298
+ },
299
+ {
300
+ "bring up host veth" ,
301
+ exec .Command ("ip" , "link" , "set" , vethHostName , "up" ),
302
+ []uintptr {uintptr (unix .CAP_NET_ADMIN )},
303
+ },
304
+ })
305
+ if err := runner .run (); err != nil {
306
+ return err
307
+ }
308
+
309
+ return nil
310
+ }
311
+
312
+ // configureHostNetworkAfterCmdExec finalizes host-side networking after the target
313
+ // process has started. It moves the jail-side veth into the target process's network
314
+ // namespace using the provided PID. This requires the process to be running so
315
+ // its PID (and thus its netns) are available.
316
+ func (l * LinuxJail ) configureHostNetworkAfterCmdExec (pidInt int ) error {
317
+ PID := fmt .Sprintf ("%v" , pidInt )
318
+
319
+ runner := newCommandRunner ([]* command {
320
+ {
321
+ "move veth to namespace" ,
322
+ exec .Command ("ip" , "link" , "set" , l .vethJailName , "netns" , PID ),
323
+ []uintptr {uintptr (unix .CAP_NET_ADMIN )},
324
+ },
325
+ })
326
+ if err := runner .run (); err != nil {
327
+ return err
328
+ }
329
+
330
+ return nil
331
+ }
332
+
333
+ // SetupChildNetworking configures networking within the target process's network
334
+ // namespace. This runs inside the child process after it has been
335
+ // created and moved to its own network namespace.
336
+ func SetupChildNetworking (vethNetJail string ) error {
337
+ runner := newCommandRunner ([]* command {
338
+ {
339
+ "configure namespace veth" ,
340
+ exec .Command ("ip" , "addr" , "add" , "192.168.100.2/24" , "dev" , vethNetJail ),
341
+ []uintptr {uintptr (unix .CAP_NET_ADMIN )},
342
+ },
343
+ {
344
+ "bring up namespace veth" ,
345
+ exec .Command ("ip" , "link" , "set" , vethNetJail , "up" ),
346
+ []uintptr {uintptr (unix .CAP_NET_ADMIN )},
347
+ },
348
+ {
349
+ "bring up loopback" ,
350
+ exec .Command ("ip" , "link" , "set" , "lo" , "up" ),
351
+ []uintptr {uintptr (unix .CAP_NET_ADMIN )},
352
+ },
353
+ {
354
+ "set default route in namespace" ,
355
+ exec .Command ("ip" , "route" , "add" , "default" , "via" , "192.168.100.1" ),
356
+ []uintptr {uintptr (unix .CAP_NET_ADMIN )},
357
+ },
358
+ })
359
+ if err := runner .run (); err != nil {
360
+ return err
361
+ }
362
+
363
+ return nil
364
+ }
0 commit comments