summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorFabricio Voznika <fvoznika@google.com>2020-11-19 15:08:47 -0800
committergVisor bot <gvisor-bot@google.com>2020-11-19 15:11:17 -0800
commit209a95a35a2e4d38998962f6a351766e816805d8 (patch)
treef8e3e1a88c0cea879e6e32cf63687bc3465fde4f
parent3454d572199679d6abc66c0c29539829dd9baf51 (diff)
Propagate IP address prefix from host to netstack
Closes #4022 PiperOrigin-RevId: 343378647
-rw-r--r--pkg/tcpip/stack/stack.go10
-rw-r--r--runsc/boot/network.go33
-rw-r--r--runsc/sandbox/network.go25
-rw-r--r--test/syscalls/linux/socket_inet_loopback.cc23
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