Add bind syscall tests for ICMP and ICMPv6

Updates #5711
Updates #6021
Updates #6022

PiperOrigin-RevId: 377582446
This commit is contained in:
Sam Balana
2021-06-04 13:53:17 -07:00
committed by gVisor bot
parent 86cf56eb71
commit 2406295249
6 changed files with 335 additions and 64 deletions
+4 -1
View File
@@ -1572,10 +1572,13 @@ cc_binary(
srcs = ["ping_socket.cc"],
linkstatic = 1,
deps = [
":ip_socket_test_util",
":socket_test_util",
"//test/util:file_descriptor",
"@com_google_absl//absl/algorithm:container",
"@com_google_absl//absl/strings",
"@com_google_absl//absl/types:optional",
gtest,
"//test/util:save_util",
"//test/util:test_main",
"//test/util:test_util",
],
@@ -140,6 +140,22 @@ SocketPairKind IPv4UDPUnboundSocketPair(int type) {
/* dual_stack = */ false)};
}
SocketKind ICMPUnboundSocket(int type) {
std::string description =
absl::StrCat(DescribeSocketType(type), "ICMP socket");
return SocketKind{
description, AF_INET, type | SOCK_DGRAM, IPPROTO_ICMP,
UnboundSocketCreator(AF_INET, type | SOCK_DGRAM, IPPROTO_ICMP)};
}
SocketKind ICMPv6UnboundSocket(int type) {
std::string description =
absl::StrCat(DescribeSocketType(type), "ICMPv6 socket");
return SocketKind{
description, AF_INET6, type | SOCK_DGRAM, IPPROTO_ICMPV6,
UnboundSocketCreator(AF_INET6, type | SOCK_DGRAM, IPPROTO_ICMPV6)};
}
SocketKind IPv4UDPUnboundSocket(int type) {
std::string description =
absl::StrCat(DescribeSocketType(type), "IPv4 UDP socket");
+12 -4
View File
@@ -84,20 +84,28 @@ SocketPairKind DualStackUDPBidirectionalBindSocketPair(int type);
// SocketPairs created with AF_INET and the given type.
SocketPairKind IPv4UDPUnboundSocketPair(int type);
// ICMPUnboundSocket returns a SocketKind that represents a SimpleSocket created
// with AF_INET, SOCK_DGRAM, IPPROTO_ICMP, and the given type.
SocketKind ICMPUnboundSocket(int type);
// ICMPv6UnboundSocket returns a SocketKind that represents a SimpleSocket
// created with AF_INET6, SOCK_DGRAM, IPPROTO_ICMPV6, and the given type.
SocketKind ICMPv6UnboundSocket(int type);
// IPv4UDPUnboundSocket returns a SocketKind that represents a SimpleSocket
// created with AF_INET, SOCK_DGRAM, and the given type.
// created with AF_INET, SOCK_DGRAM, IPPROTO_UDP, and the given type.
SocketKind IPv4UDPUnboundSocket(int type);
// IPv6UDPUnboundSocket returns a SocketKind that represents a SimpleSocket
// created with AF_INET6, SOCK_DGRAM, and the given type.
// created with AF_INET6, SOCK_DGRAM, IPPROTO_UDP, and the given type.
SocketKind IPv6UDPUnboundSocket(int type);
// IPv4TCPUnboundSocket returns a SocketKind that represents a SimpleSocket
// created with AF_INET, SOCK_STREAM and the given type.
// created with AF_INET, SOCK_STREAM, IPPROTO_TCP and the given type.
SocketKind IPv4TCPUnboundSocket(int type);
// IPv6TCPUnboundSocket returns a SocketKind that represents a SimpleSocket
// created with AF_INET6, SOCK_STREAM and the given type.
// created with AF_INET6, SOCK_STREAM, IPPROTO_TCP and the given type.
SocketKind IPv6TCPUnboundSocket(int type);
// IfAddrHelper is a helper class that determines the local interfaces present
+218 -3
View File
@@ -12,6 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
#include <errno.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <netinet/ip_icmp.h>
@@ -19,14 +20,22 @@
#include <sys/types.h>
#include <unistd.h>
#include <cctype>
#include <cstring>
#include <vector>
#include "gtest/gtest.h"
#include "absl/algorithm/container.h"
#include "absl/strings/str_join.h"
#include "absl/types/optional.h"
#include "test/syscalls/linux/ip_socket_test_util.h"
#include "test/syscalls/linux/socket_test_util.h"
#include "test/util/file_descriptor.h"
#include "test/util/save_util.h"
#include "test/util/test_util.h"
// Note: These tests require /proc/sys/net/ipv4/ping_group_range to be
// configured to allow the tester to create ping sockets (see icmp(7)).
namespace gvisor {
namespace testing {
namespace {
@@ -42,7 +51,8 @@ TEST(PingSocket, ICMPPortExhaustion) {
auto s = Socket(AF_INET, SOCK_DGRAM, IPPROTO_ICMP);
if (!s.ok()) {
ASSERT_EQ(s.error().errno_value(), EACCES);
GTEST_SKIP();
GTEST_SKIP() << "TODO(gvisor.dev/issue/6126): Buildkite does not allow "
"creation of ICMP or ICMPv6 sockets";
}
}
@@ -70,7 +80,212 @@ TEST(PingSocket, ICMPPortExhaustion) {
}
}
} // namespace
struct BindTestCase {
TestAddress bind_to;
int want = 0;
absl::optional<int> want_gvisor;
};
// Test fixture for socket binding.
class Fixture
: public ::testing::TestWithParam<std::tuple<SocketKind, BindTestCase>> {};
TEST_P(Fixture, Bind) {
auto [socket_factory, test_case] = GetParam();
auto socket = socket_factory.Create();
if (!socket.ok()) {
ASSERT_EQ(socket.error().errno_value(), EACCES);
GTEST_SKIP() << "TODO(gvisor.dev/issue/6126): Buildkite does not allow "
"creation of ICMP or ICMPv6 sockets";
}
auto socket_fd = std::move(socket).ValueOrDie();
const int want = test_case.want_gvisor.has_value() && IsRunningOnGvisor()
? *test_case.want_gvisor
: test_case.want;
if (want == 0) {
EXPECT_THAT(bind(socket_fd->get(), AsSockAddr(&test_case.bind_to.addr),
test_case.bind_to.addr_len),
SyscallSucceeds());
} else {
EXPECT_THAT(bind(socket_fd->get(), AsSockAddr(&test_case.bind_to.addr),
test_case.bind_to.addr_len),
SyscallFailsWithErrno(want));
}
}
std::vector<std::tuple<SocketKind, BindTestCase>> ICMPTestCases() {
return ApplyVec<std::tuple<SocketKind, BindTestCase>>(
[](const BindTestCase& test_case) {
return std::make_tuple(ICMPUnboundSocket(0), test_case);
},
std::vector<BindTestCase>{
{
.bind_to = V4Any(),
.want = 0,
.want_gvisor = 0,
},
{
.bind_to = V4Broadcast(),
.want = EADDRNOTAVAIL,
// TODO(gvisor.dev/issue/5711): Remove want_gvisor once ICMP
// sockets are no longer allowed to bind to broadcast addresses.
.want_gvisor = 0,
},
{
.bind_to = V4Loopback(),
.want = 0,
},
{
.bind_to = V4LoopbackSubnetBroadcast(),
.want = EADDRNOTAVAIL,
// TODO(gvisor.dev/issue/5711): Remove want_gvisor once ICMP
// sockets are no longer allowed to bind to broadcast addresses.
.want_gvisor = 0,
},
{
.bind_to = V4Multicast(),
.want = EADDRNOTAVAIL,
},
{
.bind_to = V4MulticastAllHosts(),
.want = EADDRNOTAVAIL,
},
{
.bind_to = V4AddrStr("IPv4UnknownUnicast", "192.168.1.1"),
.want = EADDRNOTAVAIL,
},
// TODO(gvisor.dev/issue/6021): Remove want_gvisor from all the test
// cases below once ICMP sockets return EAFNOSUPPORT when binding to
// IPv6 addresses.
{
.bind_to = V6Any(),
.want = EAFNOSUPPORT,
.want_gvisor = EINVAL,
},
{
.bind_to = V6Loopback(),
.want = EAFNOSUPPORT,
.want_gvisor = EINVAL,
},
{
.bind_to = V6Multicast(),
.want = EAFNOSUPPORT,
.want_gvisor = EINVAL,
},
{
.bind_to = V6MulticastInterfaceLocalAllNodes(),
.want = EAFNOSUPPORT,
.want_gvisor = EINVAL,
},
{
.bind_to = V6MulticastLinkLocalAllNodes(),
.want = EAFNOSUPPORT,
.want_gvisor = EINVAL,
},
{
.bind_to = V6MulticastLinkLocalAllRouters(),
.want = EAFNOSUPPORT,
.want_gvisor = EINVAL,
},
{
.bind_to = V6AddrStr("IPv6UnknownUnicast", "fc00::1"),
.want = EAFNOSUPPORT,
.want_gvisor = EINVAL,
},
});
}
std::vector<std::tuple<SocketKind, BindTestCase>> ICMPv6TestCases() {
return ApplyVec<std::tuple<SocketKind, BindTestCase>>(
[](const BindTestCase& test_case) {
return std::make_tuple(ICMPv6UnboundSocket(0), test_case);
},
std::vector<BindTestCase>{
{
.bind_to = V4Any(),
.want = EINVAL,
},
{
.bind_to = V4Broadcast(),
.want = EINVAL,
},
{
.bind_to = V4Loopback(),
.want = EINVAL,
},
{
.bind_to = V4LoopbackSubnetBroadcast(),
.want = EINVAL,
},
{
.bind_to = V4Multicast(),
.want = EINVAL,
},
{
.bind_to = V4MulticastAllHosts(),
.want = EINVAL,
},
{
.bind_to = V4AddrStr("IPv4UnknownUnicast", "192.168.1.1"),
.want = EINVAL,
},
{
.bind_to = V6Any(),
.want = 0,
},
{
.bind_to = V6Loopback(),
.want = 0,
},
// TODO(gvisor.dev/issue/6021): Remove want_gvisor from all the
// multicast test cases below once ICMPv6 sockets return EINVAL when
// binding to IPv6 multicast addresses.
{
.bind_to = V6Multicast(),
.want = EINVAL,
.want_gvisor = EADDRNOTAVAIL,
},
{
.bind_to = V6MulticastInterfaceLocalAllNodes(),
.want = EINVAL,
.want_gvisor = EADDRNOTAVAIL,
},
{
.bind_to = V6MulticastLinkLocalAllNodes(),
.want = EINVAL,
.want_gvisor = EADDRNOTAVAIL,
},
{
.bind_to = V6MulticastLinkLocalAllRouters(),
.want = EINVAL,
.want_gvisor = EADDRNOTAVAIL,
},
{
.bind_to = V6AddrStr("IPv6UnknownUnicast", "fc00::1"),
.want = EADDRNOTAVAIL,
},
});
}
std::vector<std::tuple<SocketKind, BindTestCase>> AllTestCases() {
return VecCat<std::tuple<SocketKind, BindTestCase>>(ICMPTestCases(),
ICMPv6TestCases());
}
std::string TestDescription(
const ::testing::TestParamInfo<Fixture::ParamType>& info) {
auto [socket_factory, test_case] = info.param;
std::string name = absl::StrJoin(
{socket_factory.description, test_case.bind_to.description}, "_");
absl::c_replace_if(
name, [](char c) { return !std::isalnum(c); }, '_');
return name;
}
INSTANTIATE_TEST_SUITE_P(PingSockets, Fixture,
::testing::ValuesIn(AllTestCases()), TestDescription);
} // namespace
} // namespace testing
} // namespace gvisor
+55 -56
View File
@@ -15,6 +15,7 @@
#include "test/syscalls/linux/socket_test_util.h"
#include <arpa/inet.h>
#include <netinet/in.h>
#include <poll.h>
#include <sys/socket.h>
@@ -798,84 +799,82 @@ TestAddress TestAddress::WithPort(uint16_t port) const {
return addr;
}
TestAddress V4Any() {
TestAddress t("V4Any");
namespace {
TestAddress V4Addr(std::string description, in_addr_t addr) {
TestAddress t(std::move(description));
t.addr.ss_family = AF_INET;
t.addr_len = sizeof(sockaddr_in);
reinterpret_cast<sockaddr_in*>(&t.addr)->sin_addr.s_addr = htonl(INADDR_ANY);
reinterpret_cast<sockaddr_in*>(&t.addr)->sin_addr.s_addr = addr;
return t;
}
TestAddress V6Addr(std::string description, const in6_addr& addr) {
TestAddress t(std::move(description));
t.addr.ss_family = AF_INET6;
t.addr_len = sizeof(sockaddr_in6);
reinterpret_cast<sockaddr_in6*>(&t.addr)->sin6_addr = addr;
return t;
}
} // namespace
TestAddress V4AddrStr(std::string description, const char* addr) {
in_addr_t s_addr;
inet_pton(AF_INET, addr, &s_addr);
return V4Addr(description, s_addr);
}
TestAddress V6AddrStr(std::string description, const char* addr) {
struct in6_addr s_addr;
inet_pton(AF_INET6, addr, &s_addr);
return V6Addr(description, s_addr);
}
TestAddress V4Any() { return V4Addr("V4Any", htonl(INADDR_ANY)); }
TestAddress V4Broadcast() {
return V4Addr("V4Broadcast", htonl(INADDR_BROADCAST));
}
TestAddress V4Loopback() {
TestAddress t("V4Loopback");
t.addr.ss_family = AF_INET;
t.addr_len = sizeof(sockaddr_in);
reinterpret_cast<sockaddr_in*>(&t.addr)->sin_addr.s_addr =
htonl(INADDR_LOOPBACK);
return t;
return V4Addr("V4Loopback", htonl(INADDR_LOOPBACK));
}
TestAddress V4MappedAny() {
TestAddress t("V4MappedAny");
t.addr.ss_family = AF_INET6;
t.addr_len = sizeof(sockaddr_in6);
inet_pton(AF_INET6, "::ffff:0.0.0.0",
reinterpret_cast<sockaddr_in6*>(&t.addr)->sin6_addr.s6_addr);
return t;
TestAddress V4LoopbackSubnetBroadcast() {
return V4AddrStr("V4LoopbackSubnetBroadcast", "127.255.255.255");
}
TestAddress V4MappedAny() { return V6AddrStr("V4MappedAny", "::ffff:0.0.0.0"); }
TestAddress V4MappedLoopback() {
TestAddress t("V4MappedLoopback");
t.addr.ss_family = AF_INET6;
t.addr_len = sizeof(sockaddr_in6);
inet_pton(AF_INET6, "::ffff:127.0.0.1",
reinterpret_cast<sockaddr_in6*>(&t.addr)->sin6_addr.s6_addr);
return t;
return V6AddrStr("V4MappedLoopback", "::ffff:127.0.0.1");
}
TestAddress V4Multicast() {
TestAddress t("V4Multicast");
t.addr.ss_family = AF_INET;
t.addr_len = sizeof(sockaddr_in);
reinterpret_cast<sockaddr_in*>(&t.addr)->sin_addr.s_addr =
inet_addr(kMulticastAddress);
return t;
return V4Addr("V4Multicast", inet_addr(kMulticastAddress));
}
TestAddress V4Broadcast() {
TestAddress t("V4Broadcast");
t.addr.ss_family = AF_INET;
t.addr_len = sizeof(sockaddr_in);
reinterpret_cast<sockaddr_in*>(&t.addr)->sin_addr.s_addr =
htonl(INADDR_BROADCAST);
return t;
TestAddress V4MulticastAllHosts() {
return V4Addr("V4MulticastAllHosts", htonl(INADDR_ALLHOSTS_GROUP));
}
TestAddress V6Any() {
TestAddress t("V6Any");
t.addr.ss_family = AF_INET6;
t.addr_len = sizeof(sockaddr_in6);
reinterpret_cast<sockaddr_in6*>(&t.addr)->sin6_addr = in6addr_any;
return t;
TestAddress V6Any() { return V6Addr("V6Any", in6addr_any); }
TestAddress V6Loopback() { return V6Addr("V6Loopback", in6addr_loopback); }
TestAddress V6Multicast() { return V6AddrStr("V6Multicast", "ff05::1234"); }
TestAddress V6MulticastInterfaceLocalAllNodes() {
return V6AddrStr("V6MulticastInterfaceLocalAllNodes", "ff01::1");
}
TestAddress V6Loopback() {
TestAddress t("V6Loopback");
t.addr.ss_family = AF_INET6;
t.addr_len = sizeof(sockaddr_in6);
reinterpret_cast<sockaddr_in6*>(&t.addr)->sin6_addr = in6addr_loopback;
return t;
TestAddress V6MulticastLinkLocalAllNodes() {
return V6AddrStr("V6MulticastLinkLocalAllNodes", "ff02::1");
}
TestAddress V6Multicast() {
TestAddress t("V6Multicast");
t.addr.ss_family = AF_INET6;
t.addr_len = sizeof(sockaddr_in6);
EXPECT_EQ(
1,
inet_pton(AF_INET6, "ff05::1234",
reinterpret_cast<sockaddr_in6*>(&t.addr)->sin6_addr.s6_addr));
return t;
TestAddress V6MulticastLinkLocalAllRouters() {
return V6AddrStr("V6MulticastLinkLocalAllRouters", "ff02::2");
}
// Checksum computes the internet checksum of a buffer.
+30
View File
@@ -499,15 +499,45 @@ struct TestAddress {
constexpr char kMulticastAddress[] = "224.0.2.1";
constexpr char kBroadcastAddress[] = "255.255.255.255";
// Returns a TestAddress with `addr` parsed as an IPv4 address described by
// `description`.
TestAddress V4AddrStr(std::string description, const char* addr);
// Returns a TestAddress with `addr` parsed as an IPv6 address described by
// `description`.
TestAddress V6AddrStr(std::string description, const char* addr);
// Returns a TestAddress for the IPv4 any address.
TestAddress V4Any();
// Returns a TestAddress for the IPv4 limited broadcast address.
TestAddress V4Broadcast();
// Returns a TestAddress for the IPv4 loopback address.
TestAddress V4Loopback();
// Returns a TestAddress for the subnet broadcast of the IPv4 loopback address.
TestAddress V4LoopbackSubnetBroadcast();
// Returns a TestAddress for the IPv4-mapped IPv6 any address.
TestAddress V4MappedAny();
// Returns a TestAddress for the IPv4-mapped IPv6 loopback address.
TestAddress V4MappedLoopback();
// Returns a TestAddress for a IPv4 multicast address.
TestAddress V4Multicast();
// Returns a TestAddress for the IPv4 all-hosts multicast group address.
TestAddress V4MulticastAllHosts();
// Returns a TestAddress for the IPv6 any address.
TestAddress V6Any();
// Returns a TestAddress for the IPv6 loopback address.
TestAddress V6Loopback();
// Returns a TestAddress for a IPv6 multicast address.
TestAddress V6Multicast();
// Returns a TestAddress for the IPv6 interface-local all-nodes multicast group
// address.
TestAddress V6MulticastInterfaceLocalAllNodes();
// Returns a TestAddress for the IPv6 link-local all-nodes multicast group
// address.
TestAddress V6MulticastLinkLocalAllNodes();
// Returns a TestAddress for the IPv6 link-local all-routers multicast group
// address.
TestAddress V6MulticastLinkLocalAllRouters();
// Compute the internet checksum of an IP header.
uint16_t IPChecksum(struct iphdr ip);