summaryrefslogtreecommitdiffhomepage
path: root/test/syscalls
diff options
context:
space:
mode:
Diffstat (limited to 'test/syscalls')
-rw-r--r--test/syscalls/linux/BUILD8
-rw-r--r--test/syscalls/linux/ip_socket_test_util.cc97
-rw-r--r--test/syscalls/linux/ip_socket_test_util.h19
-rw-r--r--test/syscalls/linux/socket_ip_udp_unbound_external_networking.cc59
-rw-r--r--test/syscalls/linux/socket_ip_udp_unbound_external_networking.h18
-rw-r--r--test/syscalls/linux/socket_ipv4_udp_unbound_external_networking.cc212
-rw-r--r--test/syscalls/linux/socket_ipv4_udp_unbound_external_networking.h18
-rw-r--r--test/syscalls/linux/socket_ipv6_udp_unbound_external_networking.cc2
8 files changed, 200 insertions, 233 deletions
diff --git a/test/syscalls/linux/BUILD b/test/syscalls/linux/BUILD
index 5b882875f..d844a61a7 100644
--- a/test/syscalls/linux/BUILD
+++ b/test/syscalls/linux/BUILD
@@ -2660,16 +2660,11 @@ cc_library(
cc_library(
name = "socket_ip_udp_unbound_external_networking",
testonly = 1,
- srcs = [
- "socket_ip_udp_unbound_external_networking.cc",
- ],
hdrs = [
"socket_ip_udp_unbound_external_networking.h",
],
deps = [
":ip_socket_test_util",
- "//test/util:socket_util",
- "//test/util:test_util",
],
alwayslink = 1,
)
@@ -2685,6 +2680,9 @@ cc_library(
],
deps = [
":socket_ip_udp_unbound_external_networking",
+ "//test/util:socket_util",
+ "//test/util:test_util",
+ "@com_google_absl//absl/cleanup",
gtest,
],
alwayslink = 1,
diff --git a/test/syscalls/linux/ip_socket_test_util.cc b/test/syscalls/linux/ip_socket_test_util.cc
index a1216d23f..d18e616d0 100644
--- a/test/syscalls/linux/ip_socket_test_util.cc
+++ b/test/syscalls/linux/ip_socket_test_util.cc
@@ -16,6 +16,7 @@
#include <net/if.h>
#include <netinet/in.h>
+#include <netpacket/packet.h>
#include <sys/socket.h>
#include <cstring>
@@ -196,75 +197,53 @@ SocketKind IPv6TCPUnboundSocket(int type) {
UnboundSocketCreator(AF_INET6, type | SOCK_STREAM, IPPROTO_TCP)};
}
-PosixError IfAddrHelper::Load() {
- Release();
-#ifndef ANDROID
- RETURN_ERROR_IF_SYSCALL_FAIL(getifaddrs(&ifaddr_));
-#else
- // Android does not support getifaddrs in r22.
- return PosixError(ENOSYS, "getifaddrs");
-#endif
- return NoError();
-}
-
-void IfAddrHelper::Release() {
- if (ifaddr_) {
-#ifndef ANDROID
- // Android does not support freeifaddrs in r22.
- freeifaddrs(ifaddr_);
-#endif
- ifaddr_ = nullptr;
- }
-}
-
-std::vector<std::string> IfAddrHelper::InterfaceList(int family) const {
- std::vector<std::string> names;
- for (auto ifa = ifaddr_; ifa != NULL; ifa = ifa->ifa_next) {
- if (ifa->ifa_addr == NULL || ifa->ifa_addr->sa_family != family) {
- continue;
- }
- names.emplace(names.end(), ifa->ifa_name);
- }
- return names;
-}
-
-const sockaddr* IfAddrHelper::GetAddr(int family, std::string name) const {
- for (auto ifa = ifaddr_; ifa != NULL; ifa = ifa->ifa_next) {
- if (ifa->ifa_addr == NULL || ifa->ifa_addr->sa_family != family) {
- continue;
- }
- if (name == ifa->ifa_name) {
- return ifa->ifa_addr;
- }
- }
- return nullptr;
-}
-
-PosixErrorOr<int> IfAddrHelper::GetIndex(std::string name) const {
- return InterfaceIndex(name);
-}
-
std::string GetAddr4Str(const in_addr* a) {
char str[INET_ADDRSTRLEN];
- inet_ntop(AF_INET, a, str, sizeof(str));
- return std::string(str);
+ return inet_ntop(AF_INET, a, str, sizeof(str));
}
std::string GetAddr6Str(const in6_addr* a) {
char str[INET6_ADDRSTRLEN];
- inet_ntop(AF_INET6, a, str, sizeof(str));
- return std::string(str);
+ return inet_ntop(AF_INET6, a, str, sizeof(str));
}
std::string GetAddrStr(const sockaddr* a) {
- if (a->sa_family == AF_INET) {
- auto src = &(reinterpret_cast<const sockaddr_in*>(a)->sin_addr);
- return GetAddr4Str(src);
- } else if (a->sa_family == AF_INET6) {
- auto src = &(reinterpret_cast<const sockaddr_in6*>(a)->sin6_addr);
- return GetAddr6Str(src);
+ switch (a->sa_family) {
+ case AF_INET: {
+ return GetAddr4Str(&(reinterpret_cast<const sockaddr_in*>(a)->sin_addr));
+ }
+ case AF_INET6: {
+ return GetAddr6Str(
+ &(reinterpret_cast<const sockaddr_in6*>(a)->sin6_addr));
+ }
+ case AF_PACKET: {
+ const sockaddr_ll& ll = *reinterpret_cast<const sockaddr_ll*>(a);
+ std::ostringstream ss;
+ ss << std::hex;
+ ss << std::showbase;
+ ss << '{';
+ ss << " protocol=" << ntohs(ll.sll_protocol);
+ ss << " ifindex=" << ll.sll_ifindex;
+ ss << " hatype=" << ll.sll_hatype;
+ ss << " pkttype=" << static_cast<unsigned short>(ll.sll_pkttype);
+ if (ll.sll_halen != 0) {
+ ss << " addr=";
+ for (unsigned char i = 0; i < ll.sll_halen; ++i) {
+ if (i != 0) {
+ ss << ':';
+ }
+ ss << static_cast<unsigned short>(ll.sll_addr[i]);
+ }
+ }
+ ss << " }";
+ return ss.str();
+ }
+ default: {
+ std::ostringstream ss;
+ ss << "invalid(sa_family=" << a->sa_family << ")";
+ return ss.str();
+ }
}
- return std::string("<invalid>");
}
} // namespace testing
diff --git a/test/syscalls/linux/ip_socket_test_util.h b/test/syscalls/linux/ip_socket_test_util.h
index 556838356..957006e25 100644
--- a/test/syscalls/linux/ip_socket_test_util.h
+++ b/test/syscalls/linux/ip_socket_test_util.h
@@ -115,25 +115,6 @@ SocketKind IPv4TCPUnboundSocket(int 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
-// and provides functions to obtain their names, index numbers, and IP address.
-class IfAddrHelper {
- public:
- IfAddrHelper() : ifaddr_(nullptr) {}
- ~IfAddrHelper() { Release(); }
-
- PosixError Load();
- void Release();
-
- std::vector<std::string> InterfaceList(int family) const;
-
- const sockaddr* GetAddr(int family, std::string name) const;
- PosixErrorOr<int> GetIndex(std::string name) const;
-
- private:
- struct ifaddrs* ifaddr_;
-};
-
// GetAddr4Str returns the given IPv4 network address structure as a string.
std::string GetAddr4Str(const in_addr* a);
diff --git a/test/syscalls/linux/socket_ip_udp_unbound_external_networking.cc b/test/syscalls/linux/socket_ip_udp_unbound_external_networking.cc
deleted file mode 100644
index af2459a2f..000000000
--- a/test/syscalls/linux/socket_ip_udp_unbound_external_networking.cc
+++ /dev/null
@@ -1,59 +0,0 @@
-// Copyright 2020 The gVisor Authors.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#include "test/syscalls/linux/socket_ip_udp_unbound_external_networking.h"
-
-#include "test/util/socket_util.h"
-#include "test/util/test_util.h"
-
-namespace gvisor {
-namespace testing {
-
-void IPUDPUnboundExternalNetworkingSocketTest::SetUp() {
- // FIXME(b/137899561): Linux instance for syscall tests sometimes misses its
- // IPv4 address on eth0.
- found_net_interfaces_ = false;
-
- // Get interface list.
- ASSERT_NO_ERRNO(if_helper_.Load());
- std::vector<std::string> if_names = if_helper_.InterfaceList(AF_INET);
- if (if_names.size() != 2) {
- return;
- }
-
- // Figure out which interface is where.
- std::string lo = if_names[0];
- std::string eth = if_names[1];
- if (lo != "lo") std::swap(lo, eth);
- if (lo != "lo") return;
-
- lo_if_idx_ = ASSERT_NO_ERRNO_AND_VALUE(if_helper_.GetIndex(lo));
- auto lo_if_addr = if_helper_.GetAddr(AF_INET, lo);
- if (lo_if_addr == nullptr) {
- return;
- }
- lo_if_addr_ = *reinterpret_cast<const sockaddr_in*>(lo_if_addr);
-
- eth_if_idx_ = ASSERT_NO_ERRNO_AND_VALUE(if_helper_.GetIndex(eth));
- auto eth_if_addr = if_helper_.GetAddr(AF_INET, eth);
- if (eth_if_addr == nullptr) {
- return;
- }
- eth_if_addr_ = *reinterpret_cast<const sockaddr_in*>(eth_if_addr);
-
- found_net_interfaces_ = true;
-}
-
-} // namespace testing
-} // namespace gvisor
diff --git a/test/syscalls/linux/socket_ip_udp_unbound_external_networking.h b/test/syscalls/linux/socket_ip_udp_unbound_external_networking.h
index 2e8aab129..92c20eba9 100644
--- a/test/syscalls/linux/socket_ip_udp_unbound_external_networking.h
+++ b/test/syscalls/linux/socket_ip_udp_unbound_external_networking.h
@@ -16,29 +16,13 @@
#define GVISOR_TEST_SYSCALLS_LINUX_SOCKET_IP_UDP_UNBOUND_EXTERNAL_NETWORKING_H_
#include "test/syscalls/linux/ip_socket_test_util.h"
-#include "test/util/socket_util.h"
namespace gvisor {
namespace testing {
// Test fixture for tests that apply to unbound IP UDP sockets in a sandbox
// with external networking support.
-class IPUDPUnboundExternalNetworkingSocketTest : public SimpleSocketTest {
- protected:
- void SetUp() override;
-
- IfAddrHelper if_helper_;
-
- // found_net_interfaces_ is set to false if SetUp() could not obtain
- // all interface infos that we need.
- bool found_net_interfaces_;
-
- // Interface infos.
- int lo_if_idx_;
- int eth_if_idx_;
- sockaddr_in lo_if_addr_;
- sockaddr_in eth_if_addr_;
-};
+class IPUDPUnboundExternalNetworkingSocketTest : public SimpleSocketTest {};
} // namespace testing
} // namespace gvisor
diff --git a/test/syscalls/linux/socket_ipv4_udp_unbound_external_networking.cc b/test/syscalls/linux/socket_ipv4_udp_unbound_external_networking.cc
index d440932da..6c67ec51e 100644
--- a/test/syscalls/linux/socket_ipv4_udp_unbound_external_networking.cc
+++ b/test/syscalls/linux/socket_ipv4_udp_unbound_external_networking.cc
@@ -14,9 +14,62 @@
#include "test/syscalls/linux/socket_ipv4_udp_unbound_external_networking.h"
+#include <net/if.h>
+
+#include "absl/cleanup/cleanup.h"
+#include "test/util/socket_util.h"
+#include "test/util/test_util.h"
+
namespace gvisor {
namespace testing {
+void IPv4UDPUnboundExternalNetworkingSocketTest::SetUp() {
+#ifdef ANDROID
+ GTEST_SKIP() << "Android does not support getifaddrs in r22";
+#endif
+
+ ifaddrs* ifaddr;
+ ASSERT_THAT(getifaddrs(&ifaddr), SyscallSucceeds());
+ auto cleanup = absl::MakeCleanup([ifaddr] { freeifaddrs(ifaddr); });
+
+ for (const ifaddrs* ifa = ifaddr; ifa != nullptr; ifa = ifa->ifa_next) {
+ ASSERT_NE(ifa->ifa_name, nullptr);
+ ASSERT_NE(ifa->ifa_addr, nullptr);
+
+ if (ifa->ifa_addr->sa_family != AF_INET) {
+ continue;
+ }
+
+ std::optional<std::pair<int, sockaddr_in>>& if_pair = *[this, ifa]() {
+ if (strcmp(ifa->ifa_name, "lo") == 0) {
+ return &lo_if_;
+ }
+ return &eth_if_;
+ }();
+
+ const int if_index =
+ ASSERT_NO_ERRNO_AND_VALUE(InterfaceIndex(ifa->ifa_name));
+
+ std::cout << " name=" << ifa->ifa_name
+ << " addr=" << GetAddrStr(ifa->ifa_addr) << " index=" << if_index
+ << " has_value=" << if_pair.has_value() << std::endl;
+
+ if (if_pair.has_value()) {
+ continue;
+ }
+
+ if_pair = std::make_pair(
+ if_index, *reinterpret_cast<const sockaddr_in*>(ifa->ifa_addr));
+ }
+
+ if (!(eth_if_.has_value() && lo_if_.has_value())) {
+ // FIXME(b/137899561): Linux instance for syscall tests sometimes misses its
+ // IPv4 address on eth0.
+ GTEST_SKIP() << " eth_if_.has_value()=" << eth_if_.has_value()
+ << " lo_if_.has_value()=" << lo_if_.has_value();
+ }
+}
+
TestAddress V4EmptyAddress() {
TestAddress t("V4Empty");
t.addr.ss_family = AF_INET;
@@ -28,7 +81,6 @@ TestAddress V4EmptyAddress() {
// the destination port number.
TEST_P(IPv4UDPUnboundExternalNetworkingSocketTest,
UDPBroadcastReceivedOnExpectedPort) {
- SKIP_IF(!found_net_interfaces_);
auto sender = ASSERT_NO_ERRNO_AND_VALUE(NewSocket());
auto rcvr1 = ASSERT_NO_ERRNO_AND_VALUE(NewSocket());
auto rcvr2 = ASSERT_NO_ERRNO_AND_VALUE(NewSocket());
@@ -101,8 +153,6 @@ TEST_P(IPv4UDPUnboundExternalNetworkingSocketTest,
// not a unicast address.
TEST_P(IPv4UDPUnboundExternalNetworkingSocketTest,
UDPBroadcastReceivedOnExpectedAddresses) {
- SKIP_IF(!found_net_interfaces_);
-
auto sender = ASSERT_NO_ERRNO_AND_VALUE(NewSocket());
auto rcvr1 = ASSERT_NO_ERRNO_AND_VALUE(NewSocket());
auto rcvr2 = ASSERT_NO_ERRNO_AND_VALUE(NewSocket());
@@ -149,7 +199,7 @@ TEST_P(IPv4UDPUnboundExternalNetworkingSocketTest,
// Bind the non-receiving socket to the unicast ethernet address.
auto norecv_addr = rcv1_addr;
reinterpret_cast<sockaddr_in*>(&norecv_addr.addr)->sin_addr =
- eth_if_addr_.sin_addr;
+ eth_if_addr().sin_addr;
ASSERT_THAT(
bind(norcv->get(), AsSockAddr(&norecv_addr.addr), norecv_addr.addr_len),
SyscallSucceedsWithValue(0));
@@ -184,7 +234,6 @@ TEST_P(IPv4UDPUnboundExternalNetworkingSocketTest,
// (UDPBroadcastSendRecvOnSocketBoundToAny).
TEST_P(IPv4UDPUnboundExternalNetworkingSocketTest,
UDPBroadcastSendRecvOnSocketBoundToBroadcast) {
- SKIP_IF(!found_net_interfaces_);
auto sender = ASSERT_NO_ERRNO_AND_VALUE(NewSocket());
// Enable SO_BROADCAST.
@@ -224,7 +273,6 @@ TEST_P(IPv4UDPUnboundExternalNetworkingSocketTest,
// (UDPBroadcastSendRecvOnSocketBoundToBroadcast).
TEST_P(IPv4UDPUnboundExternalNetworkingSocketTest,
UDPBroadcastSendRecvOnSocketBoundToAny) {
- SKIP_IF(!found_net_interfaces_);
auto sender = ASSERT_NO_ERRNO_AND_VALUE(NewSocket());
// Enable SO_BROADCAST.
@@ -261,7 +309,6 @@ TEST_P(IPv4UDPUnboundExternalNetworkingSocketTest,
// Verifies that a UDP broadcast fails to send on a socket with SO_BROADCAST
// disabled.
TEST_P(IPv4UDPUnboundExternalNetworkingSocketTest, TestSendBroadcast) {
- SKIP_IF(!found_net_interfaces_);
auto sender = ASSERT_NO_ERRNO_AND_VALUE(NewSocket());
// Broadcast a test message without having enabled SO_BROADCAST on the sending
@@ -306,8 +353,6 @@ TEST_P(IPv4UDPUnboundExternalNetworkingSocketTest, TestSendUnicastOnUnbound) {
// set interface or group membership.
TEST_P(IPv4UDPUnboundExternalNetworkingSocketTest,
TestSendMulticastSelfNoGroup) {
- SKIP_IF(!found_net_interfaces_);
-
auto socket = ASSERT_NO_ERRNO_AND_VALUE(NewSocket());
auto bind_addr = V4Any();
@@ -341,7 +386,6 @@ TEST_P(IPv4UDPUnboundExternalNetworkingSocketTest,
// Check that multicast packets will be delivered to the sending socket without
// setting an interface.
TEST_P(IPv4UDPUnboundExternalNetworkingSocketTest, TestSendMulticastSelf) {
- SKIP_IF(!found_net_interfaces_);
auto socket = ASSERT_NO_ERRNO_AND_VALUE(NewSocket());
auto bind_addr = V4Any();
@@ -384,7 +428,6 @@ TEST_P(IPv4UDPUnboundExternalNetworkingSocketTest, TestSendMulticastSelf) {
// set interface and IP_MULTICAST_LOOP disabled.
TEST_P(IPv4UDPUnboundExternalNetworkingSocketTest,
TestSendMulticastSelfLoopOff) {
- SKIP_IF(!found_net_interfaces_);
auto socket = ASSERT_NO_ERRNO_AND_VALUE(NewSocket());
auto bind_addr = V4Any();
@@ -430,8 +473,6 @@ TEST_P(IPv4UDPUnboundExternalNetworkingSocketTest,
// Check that multicast packets won't be delivered to another socket with no
// set interface or group membership.
TEST_P(IPv4UDPUnboundExternalNetworkingSocketTest, TestSendMulticastNoGroup) {
- SKIP_IF(!found_net_interfaces_);
-
auto sender = ASSERT_NO_ERRNO_AND_VALUE(NewSocket());
auto receiver = ASSERT_NO_ERRNO_AND_VALUE(NewSocket());
@@ -468,7 +509,6 @@ TEST_P(IPv4UDPUnboundExternalNetworkingSocketTest, TestSendMulticastNoGroup) {
// Check that multicast packets will be delivered to another socket without
// setting an interface.
TEST_P(IPv4UDPUnboundExternalNetworkingSocketTest, TestSendMulticast) {
- SKIP_IF(!found_net_interfaces_);
auto sender = ASSERT_NO_ERRNO_AND_VALUE(NewSocket());
auto receiver = ASSERT_NO_ERRNO_AND_VALUE(NewSocket());
@@ -514,7 +554,6 @@ TEST_P(IPv4UDPUnboundExternalNetworkingSocketTest, TestSendMulticast) {
// set interface and IP_MULTICAST_LOOP disabled on the sending socket.
TEST_P(IPv4UDPUnboundExternalNetworkingSocketTest,
TestSendMulticastSenderNoLoop) {
- SKIP_IF(!found_net_interfaces_);
auto sender = ASSERT_NO_ERRNO_AND_VALUE(NewSocket());
auto receiver = ASSERT_NO_ERRNO_AND_VALUE(NewSocket());
@@ -564,8 +603,6 @@ TEST_P(IPv4UDPUnboundExternalNetworkingSocketTest,
// setting an interface and IP_MULTICAST_LOOP disabled on the receiving socket.
TEST_P(IPv4UDPUnboundExternalNetworkingSocketTest,
TestSendMulticastReceiverNoLoop) {
- SKIP_IF(!found_net_interfaces_);
-
auto sender = ASSERT_NO_ERRNO_AND_VALUE(NewSocket());
auto receiver = ASSERT_NO_ERRNO_AND_VALUE(NewSocket());
@@ -616,7 +653,6 @@ TEST_P(IPv4UDPUnboundExternalNetworkingSocketTest,
// and both will receive data on it when bound to the ANY address.
TEST_P(IPv4UDPUnboundExternalNetworkingSocketTest,
TestSendMulticastToTwoBoundToAny) {
- SKIP_IF(!found_net_interfaces_);
auto sender = ASSERT_NO_ERRNO_AND_VALUE(NewSocket());
std::unique_ptr<FileDescriptor> receivers[2] = {
ASSERT_NO_ERRNO_AND_VALUE(NewSocket()),
@@ -681,7 +717,6 @@ TEST_P(IPv4UDPUnboundExternalNetworkingSocketTest,
// and both will receive data on it when bound to the multicast address.
TEST_P(IPv4UDPUnboundExternalNetworkingSocketTest,
TestSendMulticastToTwoBoundToMulticastAddress) {
- SKIP_IF(!found_net_interfaces_);
auto sender = ASSERT_NO_ERRNO_AND_VALUE(NewSocket());
std::unique_ptr<FileDescriptor> receivers[2] = {
ASSERT_NO_ERRNO_AND_VALUE(NewSocket()),
@@ -749,7 +784,6 @@ TEST_P(IPv4UDPUnboundExternalNetworkingSocketTest,
// multicast address, both will receive data.
TEST_P(IPv4UDPUnboundExternalNetworkingSocketTest,
TestSendMulticastToTwoBoundToAnyAndMulticastAddress) {
- SKIP_IF(!found_net_interfaces_);
auto sender = ASSERT_NO_ERRNO_AND_VALUE(NewSocket());
std::unique_ptr<FileDescriptor> receivers[2] = {
ASSERT_NO_ERRNO_AND_VALUE(NewSocket()),
@@ -821,8 +855,6 @@ TEST_P(IPv4UDPUnboundExternalNetworkingSocketTest,
// is not a multicast address.
TEST_P(IPv4UDPUnboundExternalNetworkingSocketTest,
IpMulticastLoopbackFromAddr) {
- SKIP_IF(!found_net_interfaces_);
-
auto sender = ASSERT_NO_ERRNO_AND_VALUE(NewSocket());
auto receiver = ASSERT_NO_ERRNO_AND_VALUE(NewSocket());
@@ -885,8 +917,6 @@ TEST_P(IPv4UDPUnboundExternalNetworkingSocketTest,
// interface, a multicast packet sent out uses the latter as its source address.
TEST_P(IPv4UDPUnboundExternalNetworkingSocketTest,
IpMulticastLoopbackIfNicAndAddr) {
- SKIP_IF(!found_net_interfaces_);
-
// Create receiver, bind to ANY and join the multicast group.
auto receiver = ASSERT_NO_ERRNO_AND_VALUE(NewSocket());
auto receiver_addr = V4Any();
@@ -898,11 +928,15 @@ TEST_P(IPv4UDPUnboundExternalNetworkingSocketTest,
&receiver_addr_len),
SyscallSucceeds());
EXPECT_EQ(receiver_addr_len, receiver_addr.addr_len);
- int receiver_port =
+ const in_port_t receiver_port =
reinterpret_cast<sockaddr_in*>(&receiver_addr.addr)->sin_port;
- ip_mreqn group = {};
- group.imr_multiaddr.s_addr = inet_addr(kMulticastAddress);
- group.imr_ifindex = lo_if_idx_;
+ const ip_mreqn group = {
+ .imr_multiaddr =
+ {
+ .s_addr = inet_addr(kMulticastAddress),
+ },
+ .imr_ifindex = lo_if_idx(),
+ };
ASSERT_THAT(setsockopt(receiver->get(), IPPROTO_IP, IP_ADD_MEMBERSHIP, &group,
sizeof(group)),
SyscallSucceeds());
@@ -910,9 +944,10 @@ TEST_P(IPv4UDPUnboundExternalNetworkingSocketTest,
// Set outgoing multicast interface config, with NIC and addr pointing to
// different interfaces.
auto sender = ASSERT_NO_ERRNO_AND_VALUE(NewSocket());
- ip_mreqn iface = {};
- iface.imr_ifindex = lo_if_idx_;
- iface.imr_address = eth_if_addr_.sin_addr;
+ const ip_mreqn iface = {
+ .imr_address = eth_if_addr().sin_addr,
+ .imr_ifindex = lo_if_idx(),
+ };
ASSERT_THAT(setsockopt(sender->get(), IPPROTO_IP, IP_MULTICAST_IF, &iface,
sizeof(iface)),
SyscallSucceeds());
@@ -920,67 +955,104 @@ TEST_P(IPv4UDPUnboundExternalNetworkingSocketTest,
// Send a multicast packet.
auto sendto_addr = V4Multicast();
reinterpret_cast<sockaddr_in*>(&sendto_addr.addr)->sin_port = receiver_port;
- char send_buf[4] = {};
+ char send_buf[4];
ASSERT_THAT(
RetryEINTR(sendto)(sender->get(), send_buf, sizeof(send_buf), 0,
AsSockAddr(&sendto_addr.addr), sendto_addr.addr_len),
SyscallSucceedsWithValue(sizeof(send_buf)));
// Receive a multicast packet.
- char recv_buf[sizeof(send_buf)] = {};
+ char recv_buf[sizeof(send_buf) + 1];
auto src_addr = V4EmptyAddress();
ASSERT_THAT(
RetryEINTR(recvfrom)(receiver->get(), recv_buf, sizeof(recv_buf), 0,
AsSockAddr(&src_addr.addr), &src_addr.addr_len),
- SyscallSucceedsWithValue(sizeof(recv_buf)));
- ASSERT_EQ(sizeof(struct sockaddr_in), src_addr.addr_len);
- sockaddr_in* src_addr_in = reinterpret_cast<sockaddr_in*>(&src_addr.addr);
-
- // FIXME (b/137781162): When sending a multicast packet use the proper logic
- // to determine the packet's src-IP.
- SKIP_IF(IsRunningOnGvisor());
+ SyscallSucceedsWithValue(sizeof(send_buf)));
+ ASSERT_EQ(src_addr.addr_len, sizeof(struct sockaddr_in));
// Verify the received source address.
- EXPECT_EQ(eth_if_addr_.sin_addr.s_addr, src_addr_in->sin_addr.s_addr);
+ //
+ // TODO(https://gvisor.dev/issue/6686): gVisor is a strong host, preventing
+ // the packet from being sent from the loopback device using the ethernet
+ // device's address.
+ if (IsRunningOnGvisor()) {
+ EXPECT_EQ(GetAddrStr(AsSockAddr(&src_addr.addr)),
+ GetAddr4Str(&lo_if_addr().sin_addr));
+ } else {
+ EXPECT_EQ(GetAddrStr(AsSockAddr(&src_addr.addr)),
+ GetAddr4Str(&eth_if_addr().sin_addr));
+ }
}
// Check that when we are bound to one interface we can set IP_MULTICAST_IF to
// another interface.
TEST_P(IPv4UDPUnboundExternalNetworkingSocketTest,
IpMulticastLoopbackBindToOneIfSetMcastIfToAnother) {
- SKIP_IF(!found_net_interfaces_);
-
- // FIXME (b/137790511): When bound to one interface it is not possible to set
- // IP_MULTICAST_IF to a different interface.
- SKIP_IF(IsRunningOnGvisor());
-
- // Create sender and bind to eth interface.
- auto sender = ASSERT_NO_ERRNO_AND_VALUE(NewSocket());
- ASSERT_THAT(
- bind(sender->get(), AsSockAddr(&eth_if_addr_), sizeof(eth_if_addr_)),
- SyscallSucceeds());
-
// Run through all possible combinations of index and address for
// IP_MULTICAST_IF that selects the loopback interface.
- struct {
- int imr_ifindex;
- struct in_addr imr_address;
- } test_data[] = {
- {lo_if_idx_, {}},
- {0, lo_if_addr_.sin_addr},
- {lo_if_idx_, lo_if_addr_.sin_addr},
- {lo_if_idx_, eth_if_addr_.sin_addr},
+ ip_mreqn ifaces[] = {
+ {
+ .imr_address = {},
+ .imr_ifindex = lo_if_idx(),
+ },
+ {
+ .imr_address = lo_if_addr().sin_addr,
+ .imr_ifindex = 0,
+ },
+ {
+ .imr_address = lo_if_addr().sin_addr,
+ .imr_ifindex = lo_if_idx(),
+ },
+ {
+ .imr_address = eth_if_addr().sin_addr,
+ .imr_ifindex = lo_if_idx(),
+ },
};
- for (auto t : test_data) {
- ip_mreqn iface = {};
- iface.imr_ifindex = t.imr_ifindex;
- iface.imr_address = t.imr_address;
- EXPECT_THAT(setsockopt(sender->get(), IPPROTO_IP, IP_MULTICAST_IF, &iface,
- sizeof(iface)),
- SyscallSucceeds())
- << "imr_index=" << iface.imr_ifindex
- << " imr_address=" << GetAddr4Str(&iface.imr_address);
+
+ {
+ auto sender = ASSERT_NO_ERRNO_AND_VALUE(NewSocket());
+ ASSERT_THAT(
+ bind(sender->get(), AsSockAddr(&eth_if_addr()), sizeof(eth_if_addr())),
+ SyscallSucceeds());
+
+ for (const ip_mreqn& iface : ifaces) {
+ EXPECT_THAT(setsockopt(sender->get(), IPPROTO_IP, IP_MULTICAST_IF, &iface,
+ sizeof(iface)),
+ SyscallSucceeds())
+ << " imr_index=" << iface.imr_ifindex
+ << " imr_address=" << GetAddr4Str(&iface.imr_address);
+ }
+ }
+
+ {
+ char eth_if_name[IF_NAMESIZE];
+ memset(eth_if_name, 0xAA, sizeof(eth_if_name));
+ ASSERT_NE(if_indextoname(eth_if_idx(), eth_if_name), nullptr)
+ << strerror(errno);
+ auto sender = ASSERT_NO_ERRNO_AND_VALUE(NewSocket());
+ ASSERT_THAT(setsockopt(sender->get(), SOL_SOCKET, SO_BINDTODEVICE,
+ eth_if_name, sizeof(eth_if_name)),
+ SyscallSucceeds());
+
+ for (const ip_mreqn& iface : ifaces) {
+ // FIXME(b/137790511): Disallow mismatching IP_MULTICAST_IF and
+ // SO_BINDTODEVICE.
+ if (IsRunningOnGvisor()) {
+ EXPECT_THAT(setsockopt(sender->get(), IPPROTO_IP, IP_MULTICAST_IF,
+ &iface, sizeof(iface)),
+ SyscallSucceeds())
+ << " imr_index=" << iface.imr_ifindex
+ << " imr_address=" << GetAddr4Str(&iface.imr_address);
+ } else {
+ EXPECT_THAT(setsockopt(sender->get(), IPPROTO_IP, IP_MULTICAST_IF,
+ &iface, sizeof(iface)),
+ SyscallFailsWithErrno(EINVAL))
+ << " imr_index=" << iface.imr_ifindex
+ << " imr_address=" << GetAddr4Str(&iface.imr_address);
+ }
+ }
}
}
+
} // namespace testing
} // namespace gvisor
diff --git a/test/syscalls/linux/socket_ipv4_udp_unbound_external_networking.h b/test/syscalls/linux/socket_ipv4_udp_unbound_external_networking.h
index 20922ac1f..ac917b32c 100644
--- a/test/syscalls/linux/socket_ipv4_udp_unbound_external_networking.h
+++ b/test/syscalls/linux/socket_ipv4_udp_unbound_external_networking.h
@@ -22,8 +22,22 @@ namespace testing {
// Test fixture for tests that apply to unbound IPv4 UDP sockets in a sandbox
// with external networking support.
-using IPv4UDPUnboundExternalNetworkingSocketTest =
- IPUDPUnboundExternalNetworkingSocketTest;
+class IPv4UDPUnboundExternalNetworkingSocketTest
+ : public IPUDPUnboundExternalNetworkingSocketTest {
+ protected:
+ void SetUp() override;
+
+ int lo_if_idx() const { return std::get<0>(lo_if_.value()); }
+ int eth_if_idx() const { return std::get<0>(eth_if_.value()); }
+
+ const sockaddr_in& lo_if_addr() const { return std::get<1>(lo_if_.value()); }
+ const sockaddr_in& eth_if_addr() const {
+ return std::get<1>(eth_if_.value());
+ }
+
+ private:
+ std::optional<std::pair<int, sockaddr_in>> lo_if_, eth_if_;
+};
} // namespace testing
} // namespace gvisor
diff --git a/test/syscalls/linux/socket_ipv6_udp_unbound_external_networking.cc b/test/syscalls/linux/socket_ipv6_udp_unbound_external_networking.cc
index d72b6b53f..c6e563cd3 100644
--- a/test/syscalls/linux/socket_ipv6_udp_unbound_external_networking.cc
+++ b/test/syscalls/linux/socket_ipv6_udp_unbound_external_networking.cc
@@ -18,8 +18,6 @@ namespace gvisor {
namespace testing {
TEST_P(IPv6UDPUnboundExternalNetworkingSocketTest, TestJoinLeaveMulticast) {
- SKIP_IF(!found_net_interfaces_);
-
auto sender = ASSERT_NO_ERRNO_AND_VALUE(NewSocket());
auto receiver = ASSERT_NO_ERRNO_AND_VALUE(NewSocket());