Skip to content

Commit da85697

Browse files
refactor: improve cleanup
1 parent e92bf2d commit da85697

File tree

3 files changed

+127
-17
lines changed

3 files changed

+127
-17
lines changed

e2e_tests/boundary_integration_test.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,11 @@ func TestBoundaryIntegration(t *testing.T) {
150150
require.Contains(t, string(output), "Request Blocked by Boundary")
151151
})
152152

153+
// Gracefully close process, call cleanup methods
154+
err = boundaryCmd.Process.Signal(os.Interrupt)
155+
require.NoError(t, err, "Failed to interrupt boundary process")
156+
time.Sleep(time.Second * 1)
157+
153158
// Clean up
154159
cancel() // This will terminate the boundary process
155160
err = boundaryCmd.Wait() // Wait for process to finish

e2e_tests/iptables_cleanup_test.go

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
package e2e_tests
2+
3+
import (
4+
"context"
5+
"os"
6+
"os/exec"
7+
"testing"
8+
"time"
9+
10+
"github.com/stretchr/testify/require"
11+
)
12+
13+
func TestIPTablesCleanup(t *testing.T) {
14+
// Step 1: Capture initial iptables rules
15+
initialCmd := exec.Command("sudo", "iptables", "-L", "-n")
16+
initialOutput, err := initialCmd.Output()
17+
require.NoError(t, err, "Failed to get initial iptables rules")
18+
initialRules := string(initialOutput)
19+
//fmt.Printf("Initial iptables rules:\n%s", initialRules)
20+
21+
// Step 2: Run Boundary
22+
// Find project root by looking for go.mod file
23+
projectRoot := findProjectRoot(t)
24+
25+
// Build the boundary binary
26+
buildCmd := exec.Command("go", "build", "-o", "/tmp/boundary-test", "./cmd/...")
27+
buildCmd.Dir = projectRoot
28+
err = buildCmd.Run()
29+
require.NoError(t, err, "Failed to build boundary binary")
30+
31+
// Create context for boundary process
32+
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
33+
defer cancel()
34+
35+
// Start boundary process with sudo
36+
boundaryCmd := exec.CommandContext(ctx, "/tmp/boundary-test",
37+
"--allow", "dev.coder.com",
38+
"--allow", "jsonplaceholder.typicode.com",
39+
"--log-level", "debug",
40+
"--", "/bin/bash", "-c", "/usr/bin/sleep 10 && /usr/bin/echo 'Test completed'")
41+
42+
boundaryCmd.Stdin = os.Stdin
43+
boundaryCmd.Stdout = os.Stdout
44+
boundaryCmd.Stderr = os.Stderr
45+
46+
// Start the process
47+
err = boundaryCmd.Start()
48+
require.NoError(t, err, "Failed to start boundary process")
49+
50+
// Give boundary time to start
51+
time.Sleep(2 * time.Second)
52+
53+
// Gracefully close process, call cleanup methods
54+
err = boundaryCmd.Process.Signal(os.Interrupt)
55+
require.NoError(t, err, "Failed to interrupt boundary process")
56+
time.Sleep(time.Second * 1)
57+
58+
// Step 3: Clean up
59+
cancel() // This will terminate the boundary process
60+
err = boundaryCmd.Wait() // Wait for process to finish
61+
if err != nil {
62+
t.Logf("Boundary process finished with error: %v", err)
63+
}
64+
65+
// Clean up binary
66+
err = os.Remove("/tmp/boundary-test")
67+
require.NoError(t, err, "Failed to remove /tmp/boundary-test")
68+
69+
// Step 4: Capture iptables rules after boundary has executed
70+
iptablesCmd := exec.Command("sudo", "iptables", "-L", "-n")
71+
iptablesOutput, err := iptablesCmd.Output()
72+
require.NoError(t, err, "Failed to get iptables rules")
73+
iptablesRules := string(iptablesOutput)
74+
75+
require.Equal(t, initialRules, iptablesRules)
76+
}

jail/linux.go

Lines changed: 46 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ package jail
44

55
import (
66
"fmt"
7+
"log"
78
"log/slog"
89
"os"
910
"os/exec"
@@ -171,6 +172,22 @@ func (r *commandRunner) run() error {
171172
return nil
172173
}
173174

175+
func (r *commandRunner) runIgnoreErrors() error {
176+
for _, command := range r.commands {
177+
command.cmd.SysProcAttr = &syscall.SysProcAttr{
178+
AmbientCaps: command.ambientCaps,
179+
}
180+
181+
output, err := command.cmd.CombinedOutput()
182+
if err != nil {
183+
log.Printf("failed to %s: %v, output: %s", command.description, err, output)
184+
continue
185+
}
186+
}
187+
188+
return nil
189+
}
190+
174191
// configureHostNetworkBeforeCmdExec prepares host-side networking before the target
175192
// process is started. At this point the target process is not running, so its PID and network
176193
// namespace ID are not yet known.
@@ -283,7 +300,6 @@ func (l *LinuxJail) configureIptables() error {
283300
exec.Command("iptables", "-t", "nat", "-A", "PREROUTING", "-i", l.vethHostName, "-p", "tcp", "-j", "REDIRECT", "--to-ports", fmt.Sprintf("%d", l.httpProxyPort)),
284301
[]uintptr{uintptr(unix.CAP_NET_ADMIN)},
285302
},
286-
// TODO: clean up this rules
287303
{
288304
"iptables FORWARD -s",
289305
exec.Command("iptables", "-A", "FORWARD", "-s", "192.168.100.0/24", "-j", "ACCEPT"),
@@ -314,12 +330,15 @@ func (l *LinuxJail) cleanupNetworking() error {
314330
description string
315331
command *exec.Cmd
316332
}{
317-
{"delete veth pair", exec.Command("ip", "link", "del", vethHost)},
333+
{
334+
"delete veth pair",
335+
exec.Command("ip", "link", "del", vethHost),
336+
},
318337
}
319338

320339
for _, command := range cleanupCmds {
321340
if err := command.command.Run(); err != nil {
322-
return fmt.Errorf("failed to %s: %v", command.description, err)
341+
l.logger.Error("failed to execute command", "command", command.description, "error", err)
323342
}
324343
}
325344

@@ -328,20 +347,30 @@ func (l *LinuxJail) cleanupNetworking() error {
328347

329348
// cleanupIptables removes iptables rules
330349
func (l *LinuxJail) cleanupIptables() error {
331-
// Remove comprehensive TCP redirect rule
332-
cmd := exec.Command("iptables", "-t", "nat", "-D", "PREROUTING", "-i", l.vethHostName, "-p", "tcp", "-j", "REDIRECT", "--to-ports", fmt.Sprintf("%d", l.httpProxyPort))
333-
err := cmd.Run()
334-
if err != nil {
335-
l.logger.Error("Failed to remove TCP redirect rule", "error", err)
336-
// Continue with other cleanup even if this fails
337-
}
338-
339-
// Remove NAT rule
340-
cmd = exec.Command("iptables", "-t", "nat", "-D", "POSTROUTING", "-s", "192.168.100.0/24", "-j", "MASQUERADE")
341-
err = cmd.Run()
342-
if err != nil {
343-
l.logger.Error("Failed to remove NAT rule", "error", err)
344-
// Continue with other cleanup even if this fails
350+
runner := newCommandRunner([]*command{
351+
{
352+
"Remove comprehensive TCP redirect rule",
353+
exec.Command("iptables", "-t", "nat", "-D", "PREROUTING", "-i", l.vethHostName, "-p", "tcp", "-j", "REDIRECT", "--to-ports", fmt.Sprintf("%d", l.httpProxyPort)),
354+
[]uintptr{uintptr(unix.CAP_NET_ADMIN)},
355+
},
356+
{
357+
"Remove NAT rule",
358+
exec.Command("iptables", "-t", "nat", "-D", "POSTROUTING", "-s", "192.168.100.0/24", "-j", "MASQUERADE"),
359+
[]uintptr{uintptr(unix.CAP_NET_ADMIN)},
360+
},
361+
{
362+
"Remove iptables FORWARD -s",
363+
exec.Command("iptables", "-D", "FORWARD", "-s", "192.168.100.0/24", "-j", "ACCEPT"),
364+
[]uintptr{uintptr(unix.CAP_NET_ADMIN)},
365+
},
366+
{
367+
"Remove iptables FORWARD -d",
368+
exec.Command("iptables", "-D", "FORWARD", "-d", "192.168.100.0/24", "-j", "ACCEPT"),
369+
[]uintptr{uintptr(unix.CAP_NET_ADMIN)},
370+
},
371+
})
372+
if err := runner.runIgnoreErrors(); err != nil {
373+
return err
345374
}
346375

347376
return nil

0 commit comments

Comments
 (0)