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
4.2 kB 159 lines
1//go:build linux 2 3package microvm 4 5import ( 6 "bytes" 7 "context" 8 _ "embed" 9 "fmt" 10 "log/slog" 11 "net" 12 "os" 13 "os/exec" 14 "text/template" 15) 16 17// https://www.iana.org/assignments/iana-ipv4-special-registry/iana-ipv4-special-registry.xhtml 18// https://www.iana.org/assignments/iana-ipv6-special-registry/iana-ipv6-special-registry.xhtml 19// https://datatracker.ietf.org/doc/rfc6890/ 20var blockedNamespaceRoutes = []string{ 21 "0.0.0.0/8", // unspecified / "this network" addresses 22 "10.0.0.0/8", // private network 23 "100.64.0.0/10", // shared carrier-grade nat space 24 "127.0.0.0/8", // loopback 25 "169.254.0.0/16", // link-local / autoconfiguration 26 "172.16.0.0/12", // private network 27 "192.0.0.0/24", // ietf protocol assignments 28 "192.0.2.0/24", // documentation / examples 29 "192.88.99.0/24", // deprecated 6to4 relay anycast 30 "192.168.0.0/16", // private network 31 "198.18.0.0/15", // benchmarking / testing 32 "198.51.100.0/24", // documentation / examples 33 "203.0.113.0/24", // documentation / examples 34 "224.0.0.0/4", // multicast 35 "240.0.0.0/4", // reserved / future use, includes limited broadcast 36 "::/128", // unspecified address 37 "::1/128", // loopback 38 "::ffff:0:0/96", // ipv4-mapped addresses 39 "64:ff9b::/96", // ipv4/ipv6 translation prefix 40 "100::/64", // discard-only prefix 41 "2001::/23", // ietf protocol assignments 42 "2001:db8::/32", // documentation / examples 43 "2002::/16", // deprecated 6to4 addressing 44 "fc00::/7", // unique local addresses 45 "fe80::/10", // link-local unicast 46 "ff00::/8", // multicast 47} 48 49var blockedNamespaceNets = func() []*net.IPNet { 50 nets := make([]*net.IPNet, 0, len(blockedNamespaceRoutes)) 51 for _, route := range blockedNamespaceRoutes { 52 _, ipnet, err := net.ParseCIDR(route) 53 if err != nil { 54 panic(fmt.Sprintf("parse blocked route %q: %v", route, err)) 55 } 56 nets = append(nets, ipnet) 57 } 58 return nets 59}() 60 61//go:embed netns_wrapper.sh.tmpl 62var netnsWrapperTemplate string 63 64type netnsWrapperData struct { 65 TapName string 66 BlockedRoutes []string 67} 68 69func writeNetnsWrapper(path string, dev bool) error { 70 tmpl, err := template.New("netns-wrapper").Parse(netnsWrapperTemplate) 71 if err != nil { 72 return fmt.Errorf("parse qemu network namespace wrapper template: %w", err) 73 } 74 75 var script bytes.Buffer 76 77 var routes []string 78 if !dev { 79 routes = blockedNamespaceRoutes 80 } 81 82 err = tmpl.Execute(&script, netnsWrapperData{ 83 TapName: netnsTapName, 84 BlockedRoutes: routes, 85 }) 86 if err != nil { 87 return fmt.Errorf("render qemu network namespace wrapper template: %w", err) 88 } 89 90 if err := os.WriteFile(path, script.Bytes(), 0o700); err != nil { 91 return fmt.Errorf("write qemu network namespace wrapper: %w", err) 92 } 93 94 return nil 95} 96 97type slirpNamespace struct { 98 spec ImageSpec 99 pidFile string 100 dev bool 101} 102 103func (n *slirpNamespace) Start(ctx context.Context, logFile *os.File, logger *slog.Logger) (*exec.Cmd, *os.File, error) { 104 pid, err := waitForPIDFile(ctx, n.pidFile) 105 if err != nil { 106 return nil, nil, err 107 } 108 109 exitR, exitW, err := os.Pipe() 110 if err != nil { 111 return nil, nil, fmt.Errorf("create slirp4netns exit pipe: %w", err) 112 } 113 defer exitR.Close() // always close our read end; child gets it via ExtraFiles dup 114 115 var ok bool 116 defer func() { 117 if !ok { 118 _ = exitW.Close() 119 } 120 }() 121 122 slirpPath, err := exec.LookPath("slirp4netns") 123 if err != nil { 124 return nil, nil, fmt.Errorf("slirp4netns command not found in PATH: %w", err) 125 } 126 127 args := slirpArgs(n.dev, pid) 128 129 cmd := exec.CommandContext(ctx, slirpPath, args...) 130 cmd.ExtraFiles = []*os.File{exitR} 131 cmd.Stdout = logFile 132 cmd.Stderr = logFile 133 if err := cmd.Start(); err != nil { 134 return nil, nil, fmt.Errorf("start slirp4netns: %w", err) 135 } 136 logger.Info("started slirp4netns network namespace", "pid", pid, "cidr", outerSlirpCIDR, "tap", netnsTapName) 137 138 ok = true 139 return cmd, exitW, nil 140} 141 142func slirpArgs(dev bool, pid string) []string { 143 args := []string{ 144 "--configure", 145 "--mtu=" + netnsMTU, 146 } 147 if !dev { 148 args = append(args, "--disable-host-loopback") 149 } 150 args = append(args, 151 "--disable-dns", 152 "--enable-seccomp", 153 "--exit-fd=3", 154 "--cidr="+outerSlirpCIDR, 155 pid, 156 netnsTapName, 157 ) 158 return args 159}