mirror of
https://github.com/netbirdio/gvisor.git
synced 2026-05-22 17:12:49 -07:00
netlink: socket controls a network namespace where it has been created
Each socket has to hold a reference on its network namespace. PiperOrigin-RevId: 640691038
This commit is contained in:
@@ -22,6 +22,7 @@ go_library(
|
||||
"//pkg/marshal/primitive",
|
||||
"//pkg/sentry/arch",
|
||||
"//pkg/sentry/fsimpl/sockfs",
|
||||
"//pkg/sentry/inet",
|
||||
"//pkg/sentry/kernel",
|
||||
"//pkg/sentry/kernel/auth",
|
||||
"//pkg/sentry/kernel/time",
|
||||
|
||||
@@ -44,7 +44,7 @@ type Protocol interface {
|
||||
// If err == nil, any messages added to ms will be sent back to the
|
||||
// other end of the socket. Setting ms.Multi will cause an NLMSG_DONE
|
||||
// message to be sent even if ms contains no messages.
|
||||
ProcessMessage(ctx context.Context, msg *nlmsg.Message, ms *nlmsg.MessageSet) *syserr.Error
|
||||
ProcessMessage(ctx context.Context, s *Socket, msg *nlmsg.Message, ms *nlmsg.MessageSet) *syserr.Error
|
||||
}
|
||||
|
||||
// Provider is a function that creates a new Protocol for a specific netlink
|
||||
|
||||
@@ -70,7 +70,7 @@ func (p *Protocol) CanSend() bool {
|
||||
}
|
||||
|
||||
// dumpLinks handles RTM_GETLINK dump requests.
|
||||
func (p *Protocol) dumpLinks(ctx context.Context, msg *nlmsg.Message, ms *nlmsg.MessageSet) *syserr.Error {
|
||||
func (p *Protocol) dumpLinks(ctx context.Context, s *netlink.Socket, msg *nlmsg.Message, ms *nlmsg.MessageSet) *syserr.Error {
|
||||
// NLM_F_DUMP + RTM_GETLINK messages are supposed to include an
|
||||
// ifinfomsg. However, Linux <3.9 only checked for rtgenmsg, and some
|
||||
// userspace applications (including glibc) still include rtgenmsg.
|
||||
@@ -88,7 +88,7 @@ func (p *Protocol) dumpLinks(ctx context.Context, msg *nlmsg.Message, ms *nlmsg.
|
||||
// We always send back an NLMSG_DONE.
|
||||
ms.Multi = true
|
||||
|
||||
stack := inet.StackFromContext(ctx)
|
||||
stack := s.Stack()
|
||||
if stack == nil {
|
||||
// No network devices.
|
||||
return nil
|
||||
@@ -102,8 +102,8 @@ func (p *Protocol) dumpLinks(ctx context.Context, msg *nlmsg.Message, ms *nlmsg.
|
||||
}
|
||||
|
||||
// getLinks handles RTM_GETLINK requests.
|
||||
func (p *Protocol) getLink(ctx context.Context, msg *nlmsg.Message, ms *nlmsg.MessageSet) *syserr.Error {
|
||||
stack := inet.StackFromContext(ctx)
|
||||
func (p *Protocol) getLink(ctx context.Context, s *netlink.Socket, msg *nlmsg.Message, ms *nlmsg.MessageSet) *syserr.Error {
|
||||
stack := s.Stack()
|
||||
if stack == nil {
|
||||
// No network devices.
|
||||
return nil
|
||||
@@ -162,8 +162,8 @@ func (p *Protocol) getLink(ctx context.Context, msg *nlmsg.Message, ms *nlmsg.Me
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *Protocol) newLink(ctx context.Context, msg *nlmsg.Message, ms *nlmsg.MessageSet) *syserr.Error {
|
||||
stack := inet.StackFromContext(ctx)
|
||||
func (p *Protocol) newLink(ctx context.Context, s *netlink.Socket, msg *nlmsg.Message, ms *nlmsg.MessageSet) *syserr.Error {
|
||||
stack := s.Stack()
|
||||
if stack == nil {
|
||||
// No network stack.
|
||||
return syserr.ErrProtocolNotSupported
|
||||
@@ -173,8 +173,8 @@ func (p *Protocol) newLink(ctx context.Context, msg *nlmsg.Message, ms *nlmsg.Me
|
||||
}
|
||||
|
||||
// delLink handles RTM_DELLINK requests.
|
||||
func (p *Protocol) delLink(ctx context.Context, msg *nlmsg.Message, ms *nlmsg.MessageSet) *syserr.Error {
|
||||
stack := inet.StackFromContext(ctx)
|
||||
func (p *Protocol) delLink(ctx context.Context, s *netlink.Socket, msg *nlmsg.Message, ms *nlmsg.MessageSet) *syserr.Error {
|
||||
stack := s.Stack()
|
||||
if stack == nil {
|
||||
// No network stack.
|
||||
return syserr.ErrProtocolNotSupported
|
||||
@@ -243,7 +243,7 @@ func addNewLinkMessage(ms *nlmsg.MessageSet, idx int32, i inet.Interface) {
|
||||
}
|
||||
|
||||
// dumpAddrs handles RTM_GETADDR dump requests.
|
||||
func (p *Protocol) dumpAddrs(ctx context.Context, msg *nlmsg.Message, ms *nlmsg.MessageSet) *syserr.Error {
|
||||
func (p *Protocol) dumpAddrs(ctx context.Context, s *netlink.Socket, msg *nlmsg.Message, ms *nlmsg.MessageSet) *syserr.Error {
|
||||
// RTM_GETADDR dump requests need not contain anything more than the
|
||||
// netlink header and 1 byte protocol family common to all
|
||||
// NETLINK_ROUTE requests.
|
||||
@@ -257,7 +257,7 @@ func (p *Protocol) dumpAddrs(ctx context.Context, msg *nlmsg.Message, ms *nlmsg.
|
||||
// We always send back an NLMSG_DONE.
|
||||
ms.Multi = true
|
||||
|
||||
stack := inet.StackFromContext(ctx)
|
||||
stack := s.Stack()
|
||||
if stack == nil {
|
||||
// No network devices.
|
||||
return nil
|
||||
@@ -382,12 +382,12 @@ func parseForDestination(msg *nlmsg.Message) ([]byte, *syserr.Error) {
|
||||
}
|
||||
|
||||
// dumpRoutes handles RTM_GETROUTE requests.
|
||||
func (p *Protocol) dumpRoutes(ctx context.Context, msg *nlmsg.Message, ms *nlmsg.MessageSet) *syserr.Error {
|
||||
func (p *Protocol) dumpRoutes(ctx context.Context, s *netlink.Socket, msg *nlmsg.Message, ms *nlmsg.MessageSet) *syserr.Error {
|
||||
// RTM_GETROUTE dump requests need not contain anything more than the
|
||||
// netlink header and 1 byte protocol family common to all
|
||||
// NETLINK_ROUTE requests.
|
||||
|
||||
stack := inet.StackFromContext(ctx)
|
||||
stack := s.Stack()
|
||||
if stack == nil {
|
||||
// No network routes.
|
||||
return nil
|
||||
@@ -457,8 +457,8 @@ func (p *Protocol) dumpRoutes(ctx context.Context, msg *nlmsg.Message, ms *nlmsg
|
||||
}
|
||||
|
||||
// newAddr handles RTM_NEWADDR requests.
|
||||
func (p *Protocol) newAddr(ctx context.Context, msg *nlmsg.Message, ms *nlmsg.MessageSet) *syserr.Error {
|
||||
stack := inet.StackFromContext(ctx)
|
||||
func (p *Protocol) newAddr(ctx context.Context, s *netlink.Socket, msg *nlmsg.Message, ms *nlmsg.MessageSet) *syserr.Error {
|
||||
stack := s.Stack()
|
||||
if stack == nil {
|
||||
// No network stack.
|
||||
return syserr.ErrProtocolNotSupported
|
||||
@@ -500,6 +500,7 @@ func (p *Protocol) newAddr(ctx context.Context, msg *nlmsg.Message, ms *nlmsg.Me
|
||||
}
|
||||
case linux.IFA_ADDRESS:
|
||||
default:
|
||||
ctx.Warningf("Unknown attribute: %v", ahdr.Type)
|
||||
return syserr.ErrNotSupported
|
||||
}
|
||||
}
|
||||
@@ -507,8 +508,8 @@ func (p *Protocol) newAddr(ctx context.Context, msg *nlmsg.Message, ms *nlmsg.Me
|
||||
}
|
||||
|
||||
// delAddr handles RTM_DELADDR requests.
|
||||
func (p *Protocol) delAddr(ctx context.Context, msg *nlmsg.Message, ms *nlmsg.MessageSet) *syserr.Error {
|
||||
stack := inet.StackFromContext(ctx)
|
||||
func (p *Protocol) delAddr(ctx context.Context, s *netlink.Socket, msg *nlmsg.Message, ms *nlmsg.MessageSet) *syserr.Error {
|
||||
stack := s.Stack()
|
||||
if stack == nil {
|
||||
// No network stack.
|
||||
return syserr.ErrProtocolNotSupported
|
||||
@@ -553,7 +554,7 @@ func (p *Protocol) delAddr(ctx context.Context, msg *nlmsg.Message, ms *nlmsg.Me
|
||||
}
|
||||
|
||||
// ProcessMessage implements netlink.Protocol.ProcessMessage.
|
||||
func (p *Protocol) ProcessMessage(ctx context.Context, msg *nlmsg.Message, ms *nlmsg.MessageSet) *syserr.Error {
|
||||
func (p *Protocol) ProcessMessage(ctx context.Context, s *netlink.Socket, msg *nlmsg.Message, ms *nlmsg.MessageSet) *syserr.Error {
|
||||
hdr := msg.Header()
|
||||
|
||||
// All messages start with a 1 byte protocol family.
|
||||
@@ -577,28 +578,30 @@ func (p *Protocol) ProcessMessage(ctx context.Context, msg *nlmsg.Message, ms *n
|
||||
// supported.
|
||||
switch hdr.Type {
|
||||
case linux.RTM_GETLINK:
|
||||
return p.dumpLinks(ctx, msg, ms)
|
||||
return p.dumpLinks(ctx, s, msg, ms)
|
||||
case linux.RTM_GETADDR:
|
||||
return p.dumpAddrs(ctx, msg, ms)
|
||||
return p.dumpAddrs(ctx, s, msg, ms)
|
||||
case linux.RTM_GETROUTE:
|
||||
return p.dumpRoutes(ctx, msg, ms)
|
||||
return p.dumpRoutes(ctx, s, msg, ms)
|
||||
default:
|
||||
return syserr.ErrNotSupported
|
||||
}
|
||||
} else if hdr.Flags&linux.NLM_F_REQUEST == linux.NLM_F_REQUEST {
|
||||
switch hdr.Type {
|
||||
case linux.RTM_NEWLINK:
|
||||
return p.newLink(ctx, msg, ms)
|
||||
return p.newLink(ctx, s, msg, ms)
|
||||
case linux.RTM_GETLINK:
|
||||
return p.getLink(ctx, msg, ms)
|
||||
return p.getLink(ctx, s, msg, ms)
|
||||
case linux.RTM_DELLINK:
|
||||
return p.delLink(ctx, msg, ms)
|
||||
return p.delLink(ctx, s, msg, ms)
|
||||
case linux.RTM_GETROUTE:
|
||||
return p.dumpRoutes(ctx, msg, ms)
|
||||
return p.dumpRoutes(ctx, s, msg, ms)
|
||||
case linux.RTM_NEWADDR:
|
||||
return p.newAddr(ctx, msg, ms)
|
||||
return p.newAddr(ctx, s, msg, ms)
|
||||
case linux.RTM_DELADDR:
|
||||
return p.delAddr(ctx, msg, ms)
|
||||
return p.delAddr(ctx, s, msg, ms)
|
||||
case linux.RTM_SETLINK:
|
||||
return nil
|
||||
default:
|
||||
return syserr.ErrNotSupported
|
||||
}
|
||||
|
||||
@@ -28,6 +28,7 @@ import (
|
||||
"gvisor.dev/gvisor/pkg/marshal"
|
||||
"gvisor.dev/gvisor/pkg/marshal/primitive"
|
||||
"gvisor.dev/gvisor/pkg/sentry/arch"
|
||||
"gvisor.dev/gvisor/pkg/sentry/inet"
|
||||
"gvisor.dev/gvisor/pkg/sentry/kernel"
|
||||
"gvisor.dev/gvisor/pkg/sentry/kernel/auth"
|
||||
ktime "gvisor.dev/gvisor/pkg/sentry/kernel/time"
|
||||
@@ -109,6 +110,9 @@ type Socket struct {
|
||||
// TODO(gvisor.dev/issue/1119): We don't actually support filtering,
|
||||
// this is just bookkeeping for tracking add/remove.
|
||||
filter bool
|
||||
|
||||
// netns is the network namespace associated with the socket.
|
||||
netns *inet.Namespace
|
||||
}
|
||||
|
||||
var _ socket.Socket = (*Socket)(nil)
|
||||
@@ -140,11 +144,17 @@ func New(t *kernel.Task, skType linux.SockType, protocol Protocol) (*Socket, *sy
|
||||
ep: ep,
|
||||
connection: connection,
|
||||
sendBufferSize: defaultSendBufferSize,
|
||||
netns: t.GetNetworkNamespace(),
|
||||
}
|
||||
fd.LockFD.Init(&vfs.FileLocks{})
|
||||
return fd, nil
|
||||
}
|
||||
|
||||
// Stack returns the network stack associated with the socket.
|
||||
func (s *Socket) Stack() inet.Stack {
|
||||
return s.netns.Stack()
|
||||
}
|
||||
|
||||
// Release implements vfs.FileDescriptionImpl.Release.
|
||||
func (s *Socket) Release(ctx context.Context) {
|
||||
t := kernel.TaskFromContext(ctx)
|
||||
@@ -155,6 +165,7 @@ func (s *Socket) Release(ctx context.Context) {
|
||||
if s.bound {
|
||||
s.ports.Release(s.protocol.Protocol(), s.portID)
|
||||
}
|
||||
s.netns.DecRef(ctx)
|
||||
}
|
||||
|
||||
// Epollable implements FileDescriptionImpl.Epollable.
|
||||
@@ -744,7 +755,7 @@ func (s *Socket) processMessages(ctx context.Context, buf []byte) *syserr.Error
|
||||
}
|
||||
|
||||
ms := nlmsg.NewMessageSet(s.portID, hdr.Seq)
|
||||
if err := s.protocol.ProcessMessage(ctx, msg, ms); err != nil {
|
||||
if err := s.protocol.ProcessMessage(ctx, s, msg, ms); err != nil {
|
||||
dumpErrorMessage(hdr, ms, err)
|
||||
} else if hdr.Flags&linux.NLM_F_ACK == linux.NLM_F_ACK {
|
||||
dumpAckMessage(hdr, ms)
|
||||
|
||||
@@ -50,7 +50,7 @@ func (p *Protocol) CanSend() bool {
|
||||
}
|
||||
|
||||
// ProcessMessage implements netlink.Protocol.ProcessMessage.
|
||||
func (p *Protocol) ProcessMessage(ctx context.Context, msg *nlmsg.Message, ms *nlmsg.MessageSet) *syserr.Error {
|
||||
func (p *Protocol) ProcessMessage(ctx context.Context, s *netlink.Socket, msg *nlmsg.Message, ms *nlmsg.MessageSet) *syserr.Error {
|
||||
// Silently ignore all messages.
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -2742,8 +2742,11 @@ cc_library(
|
||||
],
|
||||
deps = select_gtest() + [
|
||||
":socket_netlink_route_util",
|
||||
":socket_netlink_util",
|
||||
"//test/util:capability_util",
|
||||
"//test/util:cleanup",
|
||||
"//test/util:file_descriptor",
|
||||
"//test/util:posix_error",
|
||||
"//test/util:socket_util",
|
||||
],
|
||||
alwayslink = 1,
|
||||
@@ -2760,7 +2763,10 @@ cc_library(
|
||||
],
|
||||
deps = select_gtest() + [
|
||||
":socket_netlink_route_util",
|
||||
":socket_netlink_util",
|
||||
"//test/util:capability_util",
|
||||
"//test/util:file_descriptor",
|
||||
"//test/util:posix_error",
|
||||
"//test/util:socket_util",
|
||||
],
|
||||
alwayslink = 1,
|
||||
@@ -3247,7 +3253,10 @@ cc_binary(
|
||||
deps = select_gtest() + [
|
||||
":ip_socket_test_util",
|
||||
":socket_netlink_route_util",
|
||||
":socket_netlink_util",
|
||||
"//test/util:capability_util",
|
||||
"//test/util:file_descriptor",
|
||||
"//test/util:posix_error",
|
||||
"//test/util:socket_util",
|
||||
"//test/util:test_main",
|
||||
"//test/util:test_util",
|
||||
@@ -4094,6 +4103,7 @@ cc_binary(
|
||||
malloc = "//test/util:errno_safe_allocator",
|
||||
deps = select_gtest() + [
|
||||
":socket_netlink_route_util",
|
||||
":socket_netlink_util",
|
||||
"//test/util:capability_util",
|
||||
"//test/util:file_descriptor",
|
||||
"//test/util:fs_util",
|
||||
|
||||
@@ -20,12 +20,16 @@
|
||||
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
#include <utility>
|
||||
|
||||
#include "gmock/gmock.h"
|
||||
#include "gtest/gtest.h"
|
||||
#include "test/syscalls/linux/ip_socket_test_util.h"
|
||||
#include "test/syscalls/linux/socket_netlink_route_util.h"
|
||||
#include "test/syscalls/linux/socket_netlink_util.h"
|
||||
#include "test/util/capability_util.h"
|
||||
#include "test/util/file_descriptor.h"
|
||||
#include "test/util/posix_error.h"
|
||||
#include "test/util/socket_util.h"
|
||||
#include "test/util/test_util.h"
|
||||
|
||||
@@ -42,14 +46,17 @@ TEST_P(IPv6UnboundSocketTest, ConnectToBadLocalAddress) {
|
||||
// across save/restore.
|
||||
DisableSave ds;
|
||||
|
||||
FileDescriptor nlsk =
|
||||
ASSERT_NO_ERRNO_AND_VALUE(NetlinkBoundSocket(NETLINK_ROUTE));
|
||||
|
||||
// Delete the loopback address from the loopback interface.
|
||||
Link loopback_link = ASSERT_NO_ERRNO_AND_VALUE(LoopbackLink());
|
||||
EXPECT_NO_ERRNO(LinkDelLocalAddr(loopback_link.index, AF_INET6,
|
||||
EXPECT_NO_ERRNO(LinkDelLocalAddr(nlsk, loopback_link.index, AF_INET6,
|
||||
/*prefixlen=*/128, &in6addr_loopback,
|
||||
sizeof(in6addr_loopback)));
|
||||
Cleanup defer_addr_removal =
|
||||
Cleanup([loopback_link = std::move(loopback_link)] {
|
||||
EXPECT_NO_ERRNO(LinkAddLocalAddr(loopback_link.index, AF_INET6,
|
||||
Cleanup([loopback_link = std::move(loopback_link), &nlsk] {
|
||||
EXPECT_NO_ERRNO(LinkAddLocalAddr(nlsk, loopback_link.index, AF_INET6,
|
||||
/*prefixlen=*/128, &in6addr_loopback,
|
||||
sizeof(in6addr_loopback)));
|
||||
});
|
||||
@@ -75,15 +82,18 @@ TEST_P(IPv4UnboundSocketTest, ConnectToBadLocalAddress) {
|
||||
// across save/restore.
|
||||
DisableSave ds;
|
||||
|
||||
FileDescriptor nlsk =
|
||||
ASSERT_NO_ERRNO_AND_VALUE(NetlinkBoundSocket(NETLINK_ROUTE));
|
||||
// Delete the loopback address from the loopback interface.
|
||||
Link loopback_link = ASSERT_NO_ERRNO_AND_VALUE(LoopbackLink());
|
||||
struct in_addr laddr;
|
||||
laddr.s_addr = htonl(INADDR_LOOPBACK);
|
||||
EXPECT_NO_ERRNO(LinkDelLocalAddr(loopback_link.index, AF_INET,
|
||||
EXPECT_NO_ERRNO(LinkDelLocalAddr(nlsk, loopback_link.index, AF_INET,
|
||||
/*prefixlen=*/8, &laddr, sizeof(laddr)));
|
||||
Cleanup defer_addr_removal = Cleanup(
|
||||
[loopback_link = std::move(loopback_link), addr = std::move(laddr)] {
|
||||
EXPECT_NO_ERRNO(LinkAddLocalAddr(loopback_link.index, AF_INET,
|
||||
Cleanup defer_addr_removal =
|
||||
Cleanup([loopback_link = std::move(loopback_link),
|
||||
addr = std::move(laddr), &nlsk] {
|
||||
EXPECT_NO_ERRNO(LinkAddLocalAddr(nlsk, loopback_link.index, AF_INET,
|
||||
/*prefixlen=*/8, &addr, sizeof(addr)));
|
||||
});
|
||||
TestAddress addr = V4Loopback();
|
||||
|
||||
@@ -17,10 +17,15 @@
|
||||
#include <arpa/inet.h>
|
||||
#include <poll.h>
|
||||
|
||||
#include <utility>
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
#include "test/syscalls/linux/socket_netlink_route_util.h"
|
||||
#include "test/syscalls/linux/socket_netlink_util.h"
|
||||
#include "test/util/capability_util.h"
|
||||
#include "test/util/cleanup.h"
|
||||
#include "test/util/file_descriptor.h"
|
||||
#include "test/util/posix_error.h"
|
||||
|
||||
namespace gvisor {
|
||||
namespace testing {
|
||||
@@ -31,19 +36,21 @@ constexpr size_t kSendBufSize = 200;
|
||||
// associated subnet.
|
||||
TEST_P(IPv4UDPUnboundSocketNetlinkTest, JoinSubnet) {
|
||||
SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_NET_ADMIN)));
|
||||
FileDescriptor nlsk =
|
||||
ASSERT_NO_ERRNO_AND_VALUE(NetlinkBoundSocket(NETLINK_ROUTE));
|
||||
|
||||
// Add an IP address to the loopback interface.
|
||||
Link loopback_link = ASSERT_NO_ERRNO_AND_VALUE(LoopbackLink());
|
||||
struct in_addr addr;
|
||||
ASSERT_EQ(1, inet_pton(AF_INET, "192.0.2.1", &addr));
|
||||
ASSERT_NO_ERRNO(LinkAddLocalAddr(loopback_link.index, AF_INET,
|
||||
ASSERT_NO_ERRNO(LinkAddLocalAddr(nlsk, loopback_link.index, AF_INET,
|
||||
/*prefixlen=*/24, &addr, sizeof(addr)));
|
||||
Cleanup defer_addr_removal = Cleanup(
|
||||
[loopback_link = std::move(loopback_link), addr = std::move(addr)] {
|
||||
EXPECT_NO_ERRNO(LinkDelLocalAddr(loopback_link.index, AF_INET,
|
||||
/*prefixlen=*/24, &addr,
|
||||
sizeof(addr)));
|
||||
});
|
||||
Cleanup defer_addr_removal = Cleanup([loopback_link =
|
||||
std::move(loopback_link),
|
||||
addr = std::move(addr), &nlsk] {
|
||||
EXPECT_NO_ERRNO(LinkDelLocalAddr(nlsk, loopback_link.index, AF_INET,
|
||||
/*prefixlen=*/24, &addr, sizeof(addr)));
|
||||
});
|
||||
|
||||
auto snd_sock = ASSERT_NO_ERRNO_AND_VALUE(NewSocket());
|
||||
auto rcv_sock = ASSERT_NO_ERRNO_AND_VALUE(NewSocket());
|
||||
@@ -103,19 +110,21 @@ TEST_P(IPv4UDPUnboundSocketNetlinkTest, ReuseAddrSubnetDirectedBroadcast) {
|
||||
constexpr int kNumSocketsPerType = 2;
|
||||
|
||||
SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_NET_ADMIN)));
|
||||
FileDescriptor nlsk =
|
||||
ASSERT_NO_ERRNO_AND_VALUE(NetlinkBoundSocket(NETLINK_ROUTE));
|
||||
|
||||
// Add an IP address to the loopback interface.
|
||||
Link loopback_link = ASSERT_NO_ERRNO_AND_VALUE(LoopbackLink());
|
||||
struct in_addr addr;
|
||||
ASSERT_EQ(1, inet_pton(AF_INET, "192.0.2.1", &addr));
|
||||
ASSERT_NO_ERRNO(LinkAddLocalAddr(loopback_link.index, AF_INET,
|
||||
ASSERT_NO_ERRNO(LinkAddLocalAddr(nlsk, loopback_link.index, AF_INET,
|
||||
24 /* prefixlen */, &addr, sizeof(addr)));
|
||||
Cleanup defer_addr_removal = Cleanup(
|
||||
[loopback_link = std::move(loopback_link), addr = std::move(addr)] {
|
||||
EXPECT_NO_ERRNO(LinkDelLocalAddr(loopback_link.index, AF_INET,
|
||||
/*prefixlen=*/24, &addr,
|
||||
sizeof(addr)));
|
||||
});
|
||||
Cleanup defer_addr_removal = Cleanup([loopback_link =
|
||||
std::move(loopback_link),
|
||||
addr = std::move(addr), &nlsk] {
|
||||
EXPECT_NO_ERRNO(LinkDelLocalAddr(nlsk, loopback_link.index, AF_INET,
|
||||
/*prefixlen=*/24, &addr, sizeof(addr)));
|
||||
});
|
||||
|
||||
TestAddress broadcast_address("SubnetBroadcastAddress");
|
||||
broadcast_address.addr.ss_family = AF_INET;
|
||||
|
||||
@@ -18,7 +18,10 @@
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
#include "test/syscalls/linux/socket_netlink_route_util.h"
|
||||
#include "test/syscalls/linux/socket_netlink_util.h"
|
||||
#include "test/util/capability_util.h"
|
||||
#include "test/util/file_descriptor.h"
|
||||
#include "test/util/posix_error.h"
|
||||
|
||||
namespace gvisor {
|
||||
namespace testing {
|
||||
@@ -27,12 +30,14 @@ namespace testing {
|
||||
// in an associated subnet.
|
||||
TEST_P(IPv6UDPUnboundSocketNetlinkTest, JoinSubnet) {
|
||||
SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_NET_ADMIN)));
|
||||
FileDescriptor nlsk =
|
||||
ASSERT_NO_ERRNO_AND_VALUE(NetlinkBoundSocket(NETLINK_ROUTE));
|
||||
|
||||
// Add an IP address to the loopback interface.
|
||||
Link loopback_link = ASSERT_NO_ERRNO_AND_VALUE(LoopbackLink());
|
||||
struct in6_addr addr;
|
||||
EXPECT_EQ(1, inet_pton(AF_INET6, "2001:db8::1", &addr));
|
||||
EXPECT_NO_ERRNO(LinkAddLocalAddr(loopback_link.index, AF_INET6,
|
||||
EXPECT_NO_ERRNO(LinkAddLocalAddr(nlsk, loopback_link.index, AF_INET6,
|
||||
/*prefixlen=*/64, &addr, sizeof(addr)));
|
||||
|
||||
// Binding to an unassigned address but an address that is in the subnet
|
||||
|
||||
@@ -657,6 +657,8 @@ TEST(NetlinkRouteTest, AddAndRemoveAddr) {
|
||||
// Don't do cooperative save/restore because netstack state is not restored.
|
||||
// TODO(gvisor.dev/issue/4595): enable cooperative save tests.
|
||||
const DisableSave ds;
|
||||
FileDescriptor fd =
|
||||
ASSERT_NO_ERRNO_AND_VALUE(NetlinkBoundSocket(NETLINK_ROUTE));
|
||||
|
||||
Link loopback_link = ASSERT_NO_ERRNO_AND_VALUE(LoopbackLink());
|
||||
|
||||
@@ -664,32 +666,67 @@ TEST(NetlinkRouteTest, AddAndRemoveAddr) {
|
||||
ASSERT_EQ(inet_pton(AF_INET, "10.0.0.1", &addr), 1);
|
||||
|
||||
// Create should succeed, as no such address in kernel.
|
||||
ASSERT_NO_ERRNO(LinkAddLocalAddr(loopback_link.index, AF_INET,
|
||||
ASSERT_NO_ERRNO(LinkAddLocalAddr(fd, loopback_link.index, AF_INET,
|
||||
/*prefixlen=*/24, &addr, sizeof(addr)));
|
||||
|
||||
Cleanup defer_addr_removal = Cleanup(
|
||||
[loopback_link = std::move(loopback_link), addr = std::move(addr)] {
|
||||
// First delete should succeed, as address exists.
|
||||
EXPECT_NO_ERRNO(LinkDelLocalAddr(loopback_link.index, AF_INET,
|
||||
/*prefixlen=*/24, &addr,
|
||||
sizeof(addr)));
|
||||
Cleanup defer_addr_removal = Cleanup([&] {
|
||||
// First delete should succeed, as address exists.
|
||||
EXPECT_NO_ERRNO(LinkDelLocalAddr(fd, loopback_link.index, AF_INET,
|
||||
/*prefixlen=*/24, &addr, sizeof(addr)));
|
||||
|
||||
// Second delete should fail, as address no longer exists.
|
||||
EXPECT_THAT(LinkDelLocalAddr(loopback_link.index, AF_INET,
|
||||
/*prefixlen=*/24, &addr, sizeof(addr)),
|
||||
PosixErrorIs(EADDRNOTAVAIL, _));
|
||||
});
|
||||
// Second delete should fail, as address no longer exists.
|
||||
EXPECT_THAT(LinkDelLocalAddr(fd, loopback_link.index, AF_INET,
|
||||
/*prefixlen=*/24, &addr, sizeof(addr)),
|
||||
PosixErrorIs(EADDRNOTAVAIL, _));
|
||||
});
|
||||
|
||||
// Replace an existing address should succeed.
|
||||
ASSERT_NO_ERRNO(LinkReplaceLocalAddr(loopback_link.index, AF_INET,
|
||||
ASSERT_NO_ERRNO(LinkReplaceLocalAddr(fd, loopback_link.index, AF_INET,
|
||||
/*prefixlen=*/24, &addr, sizeof(addr)));
|
||||
|
||||
// Create exclusive should fail, as we created the address above.
|
||||
EXPECT_THAT(LinkAddExclusiveLocalAddr(loopback_link.index, AF_INET,
|
||||
EXPECT_THAT(LinkAddExclusiveLocalAddr(fd, loopback_link.index, AF_INET,
|
||||
/*prefixlen=*/24, &addr, sizeof(addr)),
|
||||
PosixErrorIs(EEXIST, _));
|
||||
}
|
||||
|
||||
TEST(NetlinkRouteTest, LinkedToNetns) {
|
||||
SKIP_IF(IsRunningWithHostinet());
|
||||
SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_NET_ADMIN)));
|
||||
// Don't do cooperative save/restore because netstack state is not restored.
|
||||
// TODO(gvisor.dev/issue/4595): enable cooperative save tests.
|
||||
const DisableSave ds;
|
||||
|
||||
FileDescriptor root_netns_nlsk =
|
||||
ASSERT_NO_ERRNO_AND_VALUE(NetlinkBoundSocket(NETLINK_ROUTE));
|
||||
|
||||
const FileDescriptor nsfd =
|
||||
ASSERT_NO_ERRNO_AND_VALUE(Open("/proc/thread-self/ns/net", O_RDONLY));
|
||||
Cleanup defer_netns = Cleanup([&] {
|
||||
ASSERT_THAT(setns(nsfd.get(), CLONE_NEWNET), SyscallSucceedsWithValue(0));
|
||||
});
|
||||
ASSERT_THAT(unshare(CLONE_NEWNET), SyscallSucceedsWithValue(0));
|
||||
FileDescriptor nlsk =
|
||||
ASSERT_NO_ERRNO_AND_VALUE(NetlinkBoundSocket(NETLINK_ROUTE));
|
||||
|
||||
Link loopback_link = ASSERT_NO_ERRNO_AND_VALUE(LoopbackLink());
|
||||
|
||||
struct in_addr addr;
|
||||
ASSERT_EQ(inet_pton(AF_INET, "10.0.0.1", &addr), 1);
|
||||
|
||||
// Create should succeed, as no such address in kernel.
|
||||
ASSERT_NO_ERRNO(LinkAddLocalAddr(nlsk, loopback_link.index, AF_INET,
|
||||
/*prefixlen=*/24, &addr, sizeof(addr)));
|
||||
|
||||
// No such address in the root network namespace.
|
||||
EXPECT_THAT(LinkDelLocalAddr(root_netns_nlsk, loopback_link.index, AF_INET,
|
||||
/*prefixlen=*/24, &addr, sizeof(addr)),
|
||||
PosixErrorIs(EADDRNOTAVAIL, _));
|
||||
// The address exists in the current namespace.
|
||||
EXPECT_NO_ERRNO(LinkDelLocalAddr(nlsk, loopback_link.index, AF_INET,
|
||||
/*prefixlen=*/24, &addr, sizeof(addr)));
|
||||
}
|
||||
|
||||
// GetRouteDump tests a RTM_GETROUTE + NLM_F_DUMP request.
|
||||
TEST(NetlinkRouteTest, GetRouteDump) {
|
||||
FileDescriptor fd =
|
||||
|
||||
@@ -118,11 +118,9 @@ PosixError PopulateRuleNlmsghdr(NetlinkModification modification,
|
||||
}
|
||||
|
||||
// Adds or removes the specified address from the specified interface.
|
||||
PosixError LinkModifyLocalAddr(int index, int family, int prefixlen,
|
||||
const void* addr, int addrlen,
|
||||
PosixError LinkModifyLocalAddr(FileDescriptor& fd, int index, int family,
|
||||
int prefixlen, const void* addr, int addrlen,
|
||||
NetlinkModification modification) {
|
||||
ASSIGN_OR_RETURN_ERRNO(FileDescriptor fd, NetlinkBoundSocket(NETLINK_ROUTE));
|
||||
|
||||
struct request {
|
||||
struct nlmsghdr hdr;
|
||||
struct ifaddrmsg ifaddr;
|
||||
@@ -297,27 +295,28 @@ PosixErrorOr<Link> LoopbackLink() {
|
||||
return PosixError(ENOENT, "loopback link not found");
|
||||
}
|
||||
|
||||
PosixError LinkAddLocalAddr(int index, int family, int prefixlen,
|
||||
const void* addr, int addrlen) {
|
||||
return LinkModifyLocalAddr(index, family, prefixlen, addr, addrlen,
|
||||
PosixError LinkAddLocalAddr(FileDescriptor& fd, int index, int family,
|
||||
int prefixlen, const void* addr, int addrlen) {
|
||||
return LinkModifyLocalAddr(fd, index, family, prefixlen, addr, addrlen,
|
||||
NetlinkModification::kAdd);
|
||||
}
|
||||
|
||||
PosixError LinkAddExclusiveLocalAddr(int index, int family, int prefixlen,
|
||||
const void* addr, int addrlen) {
|
||||
return LinkModifyLocalAddr(index, family, prefixlen, addr, addrlen,
|
||||
PosixError LinkAddExclusiveLocalAddr(FileDescriptor& fd, int index, int family,
|
||||
int prefixlen, const void* addr,
|
||||
int addrlen) {
|
||||
return LinkModifyLocalAddr(fd, index, family, prefixlen, addr, addrlen,
|
||||
NetlinkModification::kAddExclusive);
|
||||
}
|
||||
|
||||
PosixError LinkReplaceLocalAddr(int index, int family, int prefixlen,
|
||||
const void* addr, int addrlen) {
|
||||
return LinkModifyLocalAddr(index, family, prefixlen, addr, addrlen,
|
||||
PosixError LinkReplaceLocalAddr(FileDescriptor& fd, int index, int family,
|
||||
int prefixlen, const void* addr, int addrlen) {
|
||||
return LinkModifyLocalAddr(fd, index, family, prefixlen, addr, addrlen,
|
||||
NetlinkModification::kReplace);
|
||||
}
|
||||
|
||||
PosixError LinkDelLocalAddr(int index, int family, int prefixlen,
|
||||
const void* addr, int addrlen) {
|
||||
return LinkModifyLocalAddr(index, family, prefixlen, addr, addrlen,
|
||||
PosixError LinkDelLocalAddr(FileDescriptor& fd, int index, int family,
|
||||
int prefixlen, const void* addr, int addrlen) {
|
||||
return LinkModifyLocalAddr(fd, index, family, prefixlen, addr, addrlen,
|
||||
NetlinkModification::kDelete);
|
||||
}
|
||||
|
||||
|
||||
@@ -40,21 +40,22 @@ PosixErrorOr<std::vector<Link>> DumpLinks();
|
||||
PosixErrorOr<Link> LoopbackLink();
|
||||
|
||||
// LinkAddLocalAddr adds a new IFA_LOCAL address to the interface.
|
||||
PosixError LinkAddLocalAddr(int index, int family, int prefixlen,
|
||||
const void* addr, int addrlen);
|
||||
PosixError LinkAddLocalAddr(FileDescriptor& fd, int index, int family,
|
||||
int prefixlen, const void* addr, int addrlen);
|
||||
|
||||
// LinkAddExclusiveLocalAddr adds a new IFA_LOCAL address with NLM_F_EXCL flag
|
||||
// to the interface.
|
||||
PosixError LinkAddExclusiveLocalAddr(int index, int family, int prefixlen,
|
||||
const void* addr, int addrlen);
|
||||
PosixError LinkAddExclusiveLocalAddr(FileDescriptor& fd, int index, int family,
|
||||
int prefixlen, const void* addr,
|
||||
int addrlen);
|
||||
|
||||
// LinkReplaceLocalAddr replaces an IFA_LOCAL address on the interface.
|
||||
PosixError LinkReplaceLocalAddr(int index, int family, int prefixlen,
|
||||
const void* addr, int addrlen);
|
||||
PosixError LinkReplaceLocalAddr(FileDescriptor& fd, int index, int family,
|
||||
int prefixlen, const void* addr, int addrlen);
|
||||
|
||||
// LinkDelLocalAddr removes IFA_LOCAL attribute on the interface.
|
||||
PosixError LinkDelLocalAddr(int index, int family, int prefixlen,
|
||||
const void* addr, int addrlen);
|
||||
PosixError LinkDelLocalAddr(FileDescriptor& fd, int index, int family,
|
||||
int prefixlen, const void* addr, int addrlen);
|
||||
|
||||
// LinkChangeFlags changes interface flags. E.g. IFF_UP.
|
||||
PosixError LinkChangeFlags(int index, unsigned int flags, unsigned int change);
|
||||
|
||||
@@ -33,6 +33,7 @@
|
||||
#include "absl/strings/ascii.h"
|
||||
#include "absl/strings/str_split.h"
|
||||
#include "test/syscalls/linux/socket_netlink_route_util.h"
|
||||
#include "test/syscalls/linux/socket_netlink_util.h"
|
||||
#include "test/util/capability_util.h"
|
||||
#include "test/util/file_descriptor.h"
|
||||
#include "test/util/fs_util.h"
|
||||
@@ -328,9 +329,10 @@ PosixErrorOr<TunTapInterface> OpenAndAttachTunTap(const std::string& dev_name,
|
||||
|
||||
ASSIGN_OR_RETURN_ERRNO(auto link, GetLinkByName(dev_name));
|
||||
|
||||
ASSIGN_OR_RETURN_ERRNO(auto nlsk, NetlinkBoundSocket(NETLINK_ROUTE));
|
||||
const struct in_addr dev_ipv4_addr = {.s_addr = dev_addr};
|
||||
// Interface setup.
|
||||
EXPECT_NO_ERRNO(LinkAddLocalAddr(link.index, AF_INET, /*prefixlen=*/24,
|
||||
EXPECT_NO_ERRNO(LinkAddLocalAddr(nlsk, link.index, AF_INET, /*prefixlen=*/24,
|
||||
&dev_ipv4_addr, sizeof(dev_ipv4_addr)));
|
||||
|
||||
if (!IsRunningOnGvisor()) {
|
||||
@@ -501,8 +503,10 @@ TEST_F(TuntapTest, TUNNoPacketInfo) {
|
||||
// Interface setup.
|
||||
auto link = ASSERT_NO_ERRNO_AND_VALUE(GetLinkByName(kTunName));
|
||||
const struct in_addr dev_ipv4_addr = {.s_addr = kTapIPAddr};
|
||||
EXPECT_NO_ERRNO(LinkAddLocalAddr(link.index, AF_INET, 24, &dev_ipv4_addr,
|
||||
sizeof(dev_ipv4_addr)));
|
||||
FileDescriptor nlsk =
|
||||
ASSERT_NO_ERRNO_AND_VALUE(NetlinkBoundSocket(NETLINK_ROUTE));
|
||||
EXPECT_NO_ERRNO(LinkAddLocalAddr(nlsk, link.index, AF_INET, 24,
|
||||
&dev_ipv4_addr, sizeof(dev_ipv4_addr)));
|
||||
|
||||
ping_ip_pkt ping_req = CreatePingIPPacket(kTapPeerIPAddr, kTapIPAddr);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user