|
1 | 1 | package app |
2 | 2 |
|
3 | 3 | import ( |
| 4 | + "context" |
4 | 5 | "fmt" |
5 | 6 | "log" |
6 | 7 | "log/slog" |
7 | 8 | "os" |
8 | 9 | "os/exec" |
| 10 | + "syscall" |
| 11 | + "time" |
9 | 12 |
|
| 13 | + "github.com/cenkalti/backoff/v5" |
10 | 14 | "github.com/coder/boundary/jail" |
| 15 | + "golang.org/x/sys/unix" |
11 | 16 | ) |
12 | 17 |
|
| 18 | +// waitForInterface waits for a network interface to appear in the namespace. |
| 19 | +// It retries checking for the interface with exponential backoff up to the specified timeout. |
| 20 | +func waitForInterface(interfaceName string, timeout time.Duration) error { |
| 21 | + b := backoff.NewExponentialBackOff() |
| 22 | + b.InitialInterval = 50 * time.Millisecond |
| 23 | + b.MaxInterval = 500 * time.Millisecond |
| 24 | + b.Multiplier = 2.0 |
| 25 | + |
| 26 | + ctx, cancel := context.WithTimeout(context.Background(), timeout) |
| 27 | + defer cancel() |
| 28 | + |
| 29 | + operation := func() (bool, error) { |
| 30 | + cmd := exec.Command("ip", "link", "show", interfaceName) |
| 31 | + cmd.SysProcAttr = &syscall.SysProcAttr{ |
| 32 | + AmbientCaps: []uintptr{uintptr(unix.CAP_NET_ADMIN)}, |
| 33 | + } |
| 34 | + |
| 35 | + err := cmd.Run() |
| 36 | + if err != nil { |
| 37 | + return false, fmt.Errorf("interface %s not found: %w", interfaceName, err) |
| 38 | + } |
| 39 | + // Interface exists |
| 40 | + return true, nil |
| 41 | + } |
| 42 | + |
| 43 | + _, err := backoff.Retry(ctx, operation, backoff.WithBackOff(b)) |
| 44 | + if err != nil { |
| 45 | + return fmt.Errorf("interface %s did not appear within %v: %w", interfaceName, timeout, err) |
| 46 | + } |
| 47 | + |
| 48 | + return nil |
| 49 | +} |
| 50 | + |
13 | 51 | func RunChild(logger *slog.Logger, args []string) error { |
14 | 52 | logger.Info("boundary CHILD process is started") |
15 | 53 |
|
16 | 54 | vethNetJail := os.Getenv("VETH_JAIL_NAME") |
| 55 | + if vethNetJail == "" { |
| 56 | + return fmt.Errorf("VETH_JAIL_NAME environment variable is not set") |
| 57 | + } |
| 58 | + |
| 59 | + // Wait for the veth interface to be moved into the namespace by the parent process |
| 60 | + if err := waitForInterface(vethNetJail, 5*time.Second); err != nil { |
| 61 | + return fmt.Errorf("failed to wait for interface %s: %w", vethNetJail, err) |
| 62 | + } |
| 63 | + |
17 | 64 | err := jail.SetupChildNetworking(vethNetJail) |
18 | 65 | if err != nil { |
19 | 66 | return fmt.Errorf("failed to setup child networking: %v", err) |
|
0 commit comments