github.com/SagerNet/gvisor@v0.0.0-20210707092255-7731c139d75c/runsc/boot/network.go (about) 1 // Copyright 2018 The gVisor Authors. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package boot 16 17 import ( 18 "fmt" 19 "net" 20 "runtime" 21 "strings" 22 23 "golang.org/x/sys/unix" 24 "github.com/SagerNet/gvisor/pkg/log" 25 "github.com/SagerNet/gvisor/pkg/tcpip" 26 "github.com/SagerNet/gvisor/pkg/tcpip/link/fdbased" 27 "github.com/SagerNet/gvisor/pkg/tcpip/link/loopback" 28 "github.com/SagerNet/gvisor/pkg/tcpip/link/packetsocket" 29 "github.com/SagerNet/gvisor/pkg/tcpip/link/qdisc/fifo" 30 "github.com/SagerNet/gvisor/pkg/tcpip/link/sniffer" 31 "github.com/SagerNet/gvisor/pkg/tcpip/network/ipv4" 32 "github.com/SagerNet/gvisor/pkg/tcpip/network/ipv6" 33 "github.com/SagerNet/gvisor/pkg/tcpip/stack" 34 "github.com/SagerNet/gvisor/pkg/urpc" 35 "github.com/SagerNet/gvisor/runsc/config" 36 ) 37 38 var ( 39 // DefaultLoopbackLink contains IP addresses and routes of "127.0.0.1/8" and 40 // "::1/8" on "lo" interface. 41 DefaultLoopbackLink = LoopbackLink{ 42 Name: "lo", 43 Addresses: []IPWithPrefix{ 44 {Address: net.IP("\x7f\x00\x00\x01"), PrefixLen: 8}, 45 {Address: net.IPv6loopback, PrefixLen: 128}, 46 }, 47 Routes: []Route{ 48 { 49 Destination: net.IPNet{ 50 IP: net.IPv4(0x7f, 0, 0, 0), 51 Mask: net.IPv4Mask(0xff, 0, 0, 0), 52 }, 53 }, 54 { 55 Destination: net.IPNet{ 56 IP: net.IPv6loopback, 57 Mask: net.IPMask(strings.Repeat("\xff", net.IPv6len)), 58 }, 59 }, 60 }, 61 } 62 ) 63 64 // Network exposes methods that can be used to configure a network stack. 65 type Network struct { 66 Stack *stack.Stack 67 } 68 69 // Route represents a route in the network stack. 70 type Route struct { 71 Destination net.IPNet 72 Gateway net.IP 73 } 74 75 // DefaultRoute represents a catch all route to the default gateway. 76 type DefaultRoute struct { 77 Route Route 78 Name string 79 } 80 81 // FDBasedLink configures an fd-based link. 82 type FDBasedLink struct { 83 Name string 84 MTU int 85 Addresses []IPWithPrefix 86 Routes []Route 87 GSOMaxSize uint32 88 SoftwareGSOEnabled bool 89 TXChecksumOffload bool 90 RXChecksumOffload bool 91 LinkAddress net.HardwareAddr 92 QDisc config.QueueingDiscipline 93 94 // NumChannels controls how many underlying FD's are to be used to 95 // create this endpoint. 96 NumChannels int 97 } 98 99 // LoopbackLink configures a loopback li nk. 100 type LoopbackLink struct { 101 Name string 102 Addresses []IPWithPrefix 103 Routes []Route 104 } 105 106 // CreateLinksAndRoutesArgs are arguments to CreateLinkAndRoutes. 107 type CreateLinksAndRoutesArgs struct { 108 // FilePayload contains the fds associated with the FDBasedLinks. The 109 // number of fd's should match the sum of the NumChannels field of the 110 // FDBasedLink entries below. 111 urpc.FilePayload 112 113 LoopbackLinks []LoopbackLink 114 FDBasedLinks []FDBasedLink 115 116 Defaultv4Gateway DefaultRoute 117 Defaultv6Gateway DefaultRoute 118 } 119 120 // IPWithPrefix is an address with its subnet prefix length. 121 type IPWithPrefix struct { 122 // Address is a network address. 123 Address net.IP 124 125 // PrefixLen is the subnet prefix length. 126 PrefixLen int 127 } 128 129 func (ip IPWithPrefix) String() string { 130 return fmt.Sprintf("%s/%d", ip.Address, ip.PrefixLen) 131 } 132 133 // Empty returns true if route hasn't been set. 134 func (r *Route) Empty() bool { 135 return r.Destination.IP == nil && r.Destination.Mask == nil && r.Gateway == nil 136 } 137 138 func (r *Route) toTcpipRoute(id tcpip.NICID) (tcpip.Route, error) { 139 subnet, err := tcpip.NewSubnet(ipToAddress(r.Destination.IP), ipMaskToAddressMask(r.Destination.Mask)) 140 if err != nil { 141 return tcpip.Route{}, err 142 } 143 return tcpip.Route{ 144 Destination: subnet, 145 Gateway: ipToAddress(r.Gateway), 146 NIC: id, 147 }, nil 148 } 149 150 // CreateLinksAndRoutes creates links and routes in a network stack. It should 151 // only be called once. 152 func (n *Network) CreateLinksAndRoutes(args *CreateLinksAndRoutesArgs, _ *struct{}) error { 153 wantFDs := 0 154 for _, l := range args.FDBasedLinks { 155 wantFDs += l.NumChannels 156 } 157 if got := len(args.FilePayload.Files); got != wantFDs { 158 return fmt.Errorf("args.FilePayload.Files has %d FD's but we need %d entries based on FDBasedLinks", got, wantFDs) 159 } 160 161 var nicID tcpip.NICID 162 nicids := make(map[string]tcpip.NICID) 163 164 // Collect routes from all links. 165 var routes []tcpip.Route 166 167 // Loopback normally appear before other interfaces. 168 for _, link := range args.LoopbackLinks { 169 nicID++ 170 nicids[link.Name] = nicID 171 172 linkEP := loopback.New() 173 174 log.Infof("Enabling loopback interface %q with id %d on addresses %+v", link.Name, nicID, link.Addresses) 175 if err := n.createNICWithAddrs(nicID, link.Name, linkEP, link.Addresses); err != nil { 176 return err 177 } 178 179 // Collect the routes from this link. 180 for _, r := range link.Routes { 181 route, err := r.toTcpipRoute(nicID) 182 if err != nil { 183 return err 184 } 185 routes = append(routes, route) 186 } 187 } 188 189 fdOffset := 0 190 for _, link := range args.FDBasedLinks { 191 nicID++ 192 nicids[link.Name] = nicID 193 194 FDs := []int{} 195 for j := 0; j < link.NumChannels; j++ { 196 // Copy the underlying FD. 197 oldFD := args.FilePayload.Files[fdOffset].Fd() 198 newFD, err := unix.Dup(int(oldFD)) 199 if err != nil { 200 return fmt.Errorf("failed to dup FD %v: %v", oldFD, err) 201 } 202 FDs = append(FDs, newFD) 203 fdOffset++ 204 } 205 206 mac := tcpip.LinkAddress(link.LinkAddress) 207 log.Infof("gso max size is: %d", link.GSOMaxSize) 208 209 linkEP, err := fdbased.New(&fdbased.Options{ 210 FDs: FDs, 211 MTU: uint32(link.MTU), 212 EthernetHeader: true, 213 Address: mac, 214 PacketDispatchMode: fdbased.RecvMMsg, 215 GSOMaxSize: link.GSOMaxSize, 216 SoftwareGSOEnabled: link.SoftwareGSOEnabled, 217 TXChecksumOffload: link.TXChecksumOffload, 218 RXChecksumOffload: link.RXChecksumOffload, 219 }) 220 if err != nil { 221 return err 222 } 223 224 switch link.QDisc { 225 case config.QDiscNone: 226 case config.QDiscFIFO: 227 log.Infof("Enabling FIFO QDisc on %q", link.Name) 228 linkEP = fifo.New(linkEP, runtime.GOMAXPROCS(0), 1000) 229 } 230 231 // Enable support for AF_PACKET sockets to receive outgoing packets. 232 linkEP = packetsocket.New(linkEP) 233 234 log.Infof("Enabling interface %q with id %d on addresses %+v (%v) w/ %d channels", link.Name, nicID, link.Addresses, mac, link.NumChannels) 235 if err := n.createNICWithAddrs(nicID, link.Name, linkEP, link.Addresses); err != nil { 236 return err 237 } 238 239 // Collect the routes from this link. 240 for _, r := range link.Routes { 241 route, err := r.toTcpipRoute(nicID) 242 if err != nil { 243 return err 244 } 245 routes = append(routes, route) 246 } 247 } 248 249 if !args.Defaultv4Gateway.Route.Empty() { 250 nicID, ok := nicids[args.Defaultv4Gateway.Name] 251 if !ok { 252 return fmt.Errorf("invalid interface name %q for default route", args.Defaultv4Gateway.Name) 253 } 254 route, err := args.Defaultv4Gateway.Route.toTcpipRoute(nicID) 255 if err != nil { 256 return err 257 } 258 routes = append(routes, route) 259 } 260 261 if !args.Defaultv6Gateway.Route.Empty() { 262 nicID, ok := nicids[args.Defaultv6Gateway.Name] 263 if !ok { 264 return fmt.Errorf("invalid interface name %q for default route", args.Defaultv6Gateway.Name) 265 } 266 route, err := args.Defaultv6Gateway.Route.toTcpipRoute(nicID) 267 if err != nil { 268 return err 269 } 270 routes = append(routes, route) 271 } 272 273 log.Infof("Setting routes %+v", routes) 274 n.Stack.SetRouteTable(routes) 275 return nil 276 } 277 278 // createNICWithAddrs creates a NIC in the network stack and adds the given 279 // addresses. 280 func (n *Network) createNICWithAddrs(id tcpip.NICID, name string, ep stack.LinkEndpoint, addrs []IPWithPrefix) error { 281 opts := stack.NICOptions{Name: name} 282 if err := n.Stack.CreateNICWithOptions(id, sniffer.New(ep), opts); err != nil { 283 return fmt.Errorf("CreateNICWithOptions(%d, _, %+v) failed: %v", id, opts, err) 284 } 285 286 for _, addr := range addrs { 287 proto, tcpipAddr := ipToAddressAndProto(addr.Address) 288 ap := tcpip.AddressWithPrefix{ 289 Address: tcpipAddr, 290 PrefixLen: addr.PrefixLen, 291 } 292 if err := n.Stack.AddAddressWithPrefix(id, proto, ap); err != nil { 293 return fmt.Errorf("AddAddress(%v, %v, %v) failed: %v", id, proto, tcpipAddr, err) 294 } 295 } 296 return nil 297 } 298 299 // ipToAddressAndProto converts IP to tcpip.Address and a protocol number. 300 // 301 // Note: don't use 'len(ip)' to determine IP version because length is always 16. 302 func ipToAddressAndProto(ip net.IP) (tcpip.NetworkProtocolNumber, tcpip.Address) { 303 if i4 := ip.To4(); i4 != nil { 304 return ipv4.ProtocolNumber, tcpip.Address(i4) 305 } 306 return ipv6.ProtocolNumber, tcpip.Address(ip) 307 } 308 309 // ipToAddress converts IP to tcpip.Address, ignoring the protocol. 310 func ipToAddress(ip net.IP) tcpip.Address { 311 _, addr := ipToAddressAndProto(ip) 312 return addr 313 } 314 315 // ipMaskToAddressMask converts IPMask to tcpip.AddressMask, ignoring the 316 // protocol. 317 func ipMaskToAddressMask(ipMask net.IPMask) tcpip.AddressMask { 318 return tcpip.AddressMask(ipToAddress(net.IP(ipMask))) 319 }