diff options
author | Fabricio Voznika <fvoznika@google.com> | 2020-11-19 15:08:47 -0800 |
---|---|---|
committer | gVisor bot <gvisor-bot@google.com> | 2020-11-19 15:11:17 -0800 |
commit | 209a95a35a2e4d38998962f6a351766e816805d8 (patch) | |
tree | f8e3e1a88c0cea879e6e32cf63687bc3465fde4f | |
parent | 3454d572199679d6abc66c0c29539829dd9baf51 (diff) |
Propagate IP address prefix from host to netstack
Closes #4022
PiperOrigin-RevId: 343378647
-rw-r--r-- | pkg/tcpip/stack/stack.go | 10 | ||||
-rw-r--r-- | runsc/boot/network.go | 33 | ||||
-rw-r--r-- | runsc/sandbox/network.go | 25 | ||||
-rw-r--r-- | test/syscalls/linux/socket_inet_loopback.cc | 23 |
4 files changed, 74 insertions, 17 deletions
diff --git a/pkg/tcpip/stack/stack.go b/pkg/tcpip/stack/stack.go index e788344d9..c5d45ac6a 100644 --- a/pkg/tcpip/stack/stack.go +++ b/pkg/tcpip/stack/stack.go @@ -1118,6 +1118,16 @@ func (s *Stack) AddAddress(id tcpip.NICID, protocol tcpip.NetworkProtocolNumber, return s.AddAddressWithOptions(id, protocol, addr, CanBePrimaryEndpoint) } +// AddAddressWithPrefix is the same as AddAddress, but allows you to specify +// the address prefix. +func (s *Stack) AddAddressWithPrefix(id tcpip.NICID, protocol tcpip.NetworkProtocolNumber, addr tcpip.AddressWithPrefix) *tcpip.Error { + ap := tcpip.ProtocolAddress{ + Protocol: protocol, + AddressWithPrefix: addr, + } + return s.AddProtocolAddressWithOptions(id, ap, CanBePrimaryEndpoint) +} + // AddProtocolAddress adds a new network-layer protocol address to the // specified NIC. func (s *Stack) AddProtocolAddress(id tcpip.NICID, protocolAddress tcpip.ProtocolAddress) *tcpip.Error { diff --git a/runsc/boot/network.go b/runsc/boot/network.go index f58b09942..3d3a813df 100644 --- a/runsc/boot/network.go +++ b/runsc/boot/network.go @@ -40,9 +40,9 @@ var ( // "::1/8" on "lo" interface. DefaultLoopbackLink = LoopbackLink{ Name: "lo", - Addresses: []net.IP{ - net.IP("\x7f\x00\x00\x01"), - net.IPv6loopback, + Addresses: []IPWithPrefix{ + {Address: net.IP("\x7f\x00\x00\x01"), PrefixLen: 8}, + {Address: net.IPv6loopback, PrefixLen: 128}, }, Routes: []Route{ { @@ -82,7 +82,7 @@ type DefaultRoute struct { type FDBasedLink struct { Name string MTU int - Addresses []net.IP + Addresses []IPWithPrefix Routes []Route GSOMaxSize uint32 SoftwareGSOEnabled bool @@ -99,7 +99,7 @@ type FDBasedLink struct { // LoopbackLink configures a loopback li nk. type LoopbackLink struct { Name string - Addresses []net.IP + Addresses []IPWithPrefix Routes []Route } @@ -117,6 +117,19 @@ type CreateLinksAndRoutesArgs struct { Defaultv6Gateway DefaultRoute } +// IPWithPrefix is an address with its subnet prefix length. +type IPWithPrefix struct { + // Address is a network address. + Address net.IP + + // PrefixLen is the subnet prefix length. + PrefixLen int +} + +func (ip IPWithPrefix) String() string { + return fmt.Sprintf("%s/%d", ip.Address, ip.PrefixLen) +} + // Empty returns true if route hasn't been set. func (r *Route) Empty() bool { return r.Destination.IP == nil && r.Destination.Mask == nil && r.Gateway == nil @@ -264,15 +277,19 @@ func (n *Network) CreateLinksAndRoutes(args *CreateLinksAndRoutesArgs, _ *struct // createNICWithAddrs creates a NIC in the network stack and adds the given // addresses. -func (n *Network) createNICWithAddrs(id tcpip.NICID, name string, ep stack.LinkEndpoint, addrs []net.IP) error { +func (n *Network) createNICWithAddrs(id tcpip.NICID, name string, ep stack.LinkEndpoint, addrs []IPWithPrefix) error { opts := stack.NICOptions{Name: name} if err := n.Stack.CreateNICWithOptions(id, sniffer.New(ep), opts); err != nil { return fmt.Errorf("CreateNICWithOptions(%d, _, %+v) failed: %v", id, opts, err) } for _, addr := range addrs { - proto, tcpipAddr := ipToAddressAndProto(addr) - if err := n.Stack.AddAddress(id, proto, tcpipAddr); err != nil { + proto, tcpipAddr := ipToAddressAndProto(addr.Address) + ap := tcpip.AddressWithPrefix{ + Address: tcpipAddr, + PrefixLen: addr.PrefixLen, + } + if err := n.Stack.AddAddressWithPrefix(id, proto, ap); err != nil { return fmt.Errorf("AddAddress(%v, %v, %v) failed: %v", id, proto, tcpipAddr, err) } } diff --git a/runsc/sandbox/network.go b/runsc/sandbox/network.go index 8f66dd1f8..d8112e7a2 100644 --- a/runsc/sandbox/network.go +++ b/runsc/sandbox/network.go @@ -127,7 +127,7 @@ func createInterfacesAndRoutesFromNS(conn *urpc.Client, nsPath string, hardwareG // Get all interfaces in the namespace. ifaces, err := net.Interfaces() if err != nil { - return fmt.Errorf("querying interfaces: %v", err) + return fmt.Errorf("querying interfaces: %w", err) } isRoot, err := isRootNS() @@ -148,14 +148,14 @@ func createInterfacesAndRoutesFromNS(conn *urpc.Client, nsPath string, hardwareG allAddrs, err := iface.Addrs() if err != nil { - return fmt.Errorf("fetching interface addresses for %q: %v", iface.Name, err) + return fmt.Errorf("fetching interface addresses for %q: %w", iface.Name, err) } // We build our own loopback device. if iface.Flags&net.FlagLoopback != 0 { link, err := loopbackLink(iface, allAddrs) if err != nil { - return fmt.Errorf("getting loopback link for iface %q: %v", iface.Name, err) + return fmt.Errorf("getting loopback link for iface %q: %w", iface.Name, err) } args.LoopbackLinks = append(args.LoopbackLinks, link) continue @@ -209,7 +209,7 @@ func createInterfacesAndRoutesFromNS(conn *urpc.Client, nsPath string, hardwareG // Get the link for the interface. ifaceLink, err := netlink.LinkByName(iface.Name) if err != nil { - return fmt.Errorf("getting link for interface %q: %v", iface.Name, err) + return fmt.Errorf("getting link for interface %q: %w", iface.Name, err) } link.LinkAddress = ifaceLink.Attrs().HardwareAddr @@ -219,7 +219,7 @@ func createInterfacesAndRoutesFromNS(conn *urpc.Client, nsPath string, hardwareG log.Debugf("Creating Channel %d", i) socketEntry, err := createSocket(iface, ifaceLink, hardwareGSO) if err != nil { - return fmt.Errorf("failed to createSocket for %s : %v", iface.Name, err) + return fmt.Errorf("failed to createSocket for %s : %w", iface.Name, err) } if i == 0 { link.GSOMaxSize = socketEntry.gsoMaxSize @@ -241,11 +241,12 @@ func createInterfacesAndRoutesFromNS(conn *urpc.Client, nsPath string, hardwareG // Collect the addresses for the interface, enable forwarding, // and remove them from the host. for _, addr := range ipAddrs { - link.Addresses = append(link.Addresses, addr.IP) + prefix, _ := addr.Mask.Size() + link.Addresses = append(link.Addresses, boot.IPWithPrefix{Address: addr.IP, PrefixLen: prefix}) // Steal IP address from NIC. if err := removeAddress(ifaceLink, addr.String()); err != nil { - return fmt.Errorf("removing address %v from device %q: %v", iface.Name, addr, err) + return fmt.Errorf("removing address %v from device %q: %w", addr, iface.Name, err) } } @@ -254,7 +255,7 @@ func createInterfacesAndRoutesFromNS(conn *urpc.Client, nsPath string, hardwareG log.Debugf("Setting up network, config: %+v", args) if err := conn.Call(boot.NetworkCreateLinksAndRoutes, &args, nil); err != nil { - return fmt.Errorf("creating links and routes: %v", err) + return fmt.Errorf("creating links and routes: %w", err) } return nil } @@ -339,9 +340,15 @@ func loopbackLink(iface net.Interface, addrs []net.Addr) (boot.LoopbackLink, err if !ok { return boot.LoopbackLink{}, fmt.Errorf("address is not IPNet: %+v", addr) } + + prefix, _ := ipNet.Mask.Size() + link.Addresses = append(link.Addresses, boot.IPWithPrefix{ + Address: ipNet.IP, + PrefixLen: prefix, + }) + dst := *ipNet dst.IP = dst.IP.Mask(dst.Mask) - link.Addresses = append(link.Addresses, ipNet.IP) link.Routes = append(link.Routes, boot.Route{ Destination: dst, }) diff --git a/test/syscalls/linux/socket_inet_loopback.cc b/test/syscalls/linux/socket_inet_loopback.cc index 27e9816eb..51b77ad85 100644 --- a/test/syscalls/linux/socket_inet_loopback.cc +++ b/test/syscalls/linux/socket_inet_loopback.cc @@ -2830,5 +2830,28 @@ INSTANTIATE_TEST_SUITE_P( } // namespace +// Check that loopback receives connections from any address in the range: +// 127.0.0.1 to 127.254.255.255. This behavior is exclusive to IPv4. +TEST_F(SocketInetLoopbackTest, LoopbackAddressRangeConnect) { + TestAddress const& listener = V4Any(); + + in_addr_t addresses[] = { + INADDR_LOOPBACK, + INADDR_LOOPBACK + 1, // 127.0.0.2 + (in_addr_t)0x7f000101, // 127.0.1.1 + (in_addr_t)0x7f010101, // 127.1.1.1 + (in_addr_t)0x7ffeffff, // 127.254.255.255 + }; + for (const auto& address : addresses) { + TestAddress connector("V4Loopback"); + connector.addr.ss_family = AF_INET; + connector.addr_len = sizeof(sockaddr_in); + reinterpret_cast<sockaddr_in*>(&connector.addr)->sin_addr.s_addr = + htonl(address); + + tcpSimpleConnectTest(listener, connector, true); + } +} + } // namespace testing } // namespace gvisor |