This repository has no description
0

Configure Feed

Select the types of activity you want to include in your feed.

core / spindle / engines / microvm / networking.go
2.5 kB 119 lines
1package microvm 2 3import ( 4 "bytes" 5 "context" 6 _ "embed" 7 "fmt" 8 "log/slog" 9 "os" 10 "os/exec" 11 "text/template" 12 13 "tangled.org/core/spindle/netguard" 14) 15 16var ( 17 blockedNamespaceRoutes = netguard.BlockedRoutes 18 blockedNamespaceNets = netguard.BlockedNets 19) 20 21//go:embed netns_wrapper.sh.tmpl 22var netnsWrapperTemplate string 23 24type netnsWrapperData struct { 25 TapName string 26 BlockedRoutes []string 27} 28 29func writeNetnsWrapper(path string, dev bool) error { 30 tmpl, err := template.New("netns-wrapper").Parse(netnsWrapperTemplate) 31 if err != nil { 32 return fmt.Errorf("parse qemu network namespace wrapper template: %w", err) 33 } 34 35 var script bytes.Buffer 36 37 var routes []string 38 if !dev { 39 routes = blockedNamespaceRoutes 40 } 41 42 err = tmpl.Execute(&script, netnsWrapperData{ 43 TapName: netnsTapName, 44 BlockedRoutes: routes, 45 }) 46 if err != nil { 47 return fmt.Errorf("render qemu network namespace wrapper template: %w", err) 48 } 49 50 if err := os.WriteFile(path, script.Bytes(), 0o700); err != nil { 51 return fmt.Errorf("write qemu network namespace wrapper: %w", err) 52 } 53 54 return nil 55} 56 57type slirpNamespace struct { 58 spec ImageSpec 59 pidFile string 60 dev bool 61} 62 63func (n *slirpNamespace) Start(ctx context.Context, logFile *os.File, logger *slog.Logger) (*exec.Cmd, *os.File, error) { 64 pid, err := waitForPIDFile(ctx, n.pidFile) 65 if err != nil { 66 return nil, nil, err 67 } 68 69 exitR, exitW, err := os.Pipe() 70 if err != nil { 71 return nil, nil, fmt.Errorf("create slirp4netns exit pipe: %w", err) 72 } 73 defer exitR.Close() // always close our read end; child gets it via ExtraFiles dup 74 75 var ok bool 76 defer func() { 77 if !ok { 78 _ = exitW.Close() 79 } 80 }() 81 82 slirpPath, err := exec.LookPath("slirp4netns") 83 if err != nil { 84 return nil, nil, fmt.Errorf("slirp4netns command not found in PATH: %w", err) 85 } 86 87 args := slirpArgs(n.dev, pid) 88 89 cmd := exec.CommandContext(ctx, slirpPath, args...) 90 cmd.ExtraFiles = []*os.File{exitR} 91 cmd.Stdout = logFile 92 cmd.Stderr = logFile 93 if err := cmd.Start(); err != nil { 94 return nil, nil, fmt.Errorf("start slirp4netns: %w", err) 95 } 96 logger.Info("started slirp4netns network namespace", "pid", pid, "cidr", outerSlirpCIDR, "tap", netnsTapName) 97 98 ok = true 99 return cmd, exitW, nil 100} 101 102func slirpArgs(dev bool, pid string) []string { 103 args := []string{ 104 "--configure", 105 "--mtu=" + netnsMTU, 106 } 107 if !dev { 108 args = append(args, "--disable-host-loopback") 109 } 110 args = append(args, 111 "--disable-dns", 112 "--enable-seccomp", 113 "--exit-fd=3", 114 "--cidr="+outerSlirpCIDR, 115 pid, 116 netnsTapName, 117 ) 118 return args 119}