summaryrefslogtreecommitdiffhomepage
path: root/test/syscalls/linux/raw_socket_hdrincl.cc
diff options
context:
space:
mode:
authorIan Lewis <ianmlewis@gmail.com>2020-08-17 21:44:31 -0400
committerIan Lewis <ianmlewis@gmail.com>2020-08-17 21:44:31 -0400
commitac324f646ee3cb7955b0b45a7453aeb9671cbdf1 (patch)
tree0cbc5018e8807421d701d190dc20525726c7ca76 /test/syscalls/linux/raw_socket_hdrincl.cc
parent352ae1022ce19de28fc72e034cc469872ad79d06 (diff)
parent6d0c5803d557d453f15ac6f683697eeb46dab680 (diff)
Merge branch 'master' into ip-forwarding
- Merges aleksej-paschenko's with HEAD - Adds vfs2 support for ip_forward
Diffstat (limited to 'test/syscalls/linux/raw_socket_hdrincl.cc')
-rw-r--r--test/syscalls/linux/raw_socket_hdrincl.cc101
1 files changed, 65 insertions, 36 deletions
diff --git a/test/syscalls/linux/raw_socket_hdrincl.cc b/test/syscalls/linux/raw_socket_hdrincl.cc
index 0a27506aa..2f25aceb2 100644
--- a/test/syscalls/linux/raw_socket_hdrincl.cc
+++ b/test/syscalls/linux/raw_socket_hdrincl.cc
@@ -167,7 +167,7 @@ TEST_F(RawHDRINCL, NotReadable) {
// nothing to be read.
char buf[117];
ASSERT_THAT(RetryEINTR(recv)(socket_, buf, sizeof(buf), MSG_DONTWAIT),
- SyscallFailsWithErrno(EINVAL));
+ SyscallFailsWithErrno(EAGAIN));
}
// Test that we can connect() to a valid IP (loopback).
@@ -178,6 +178,9 @@ TEST_F(RawHDRINCL, ConnectToLoopback) {
}
TEST_F(RawHDRINCL, SendWithoutConnectSucceeds) {
+ // FIXME(gvisor.dev/issue/3159): Test currently flaky.
+ SKIP_IF(true);
+
struct iphdr hdr = LoopbackHeader();
ASSERT_THAT(send(socket_, &hdr, sizeof(hdr), 0),
SyscallSucceedsWithValue(sizeof(hdr)));
@@ -273,14 +276,17 @@ TEST_F(RawHDRINCL, SendAndReceive) {
// The network stack should have set the source address.
EXPECT_EQ(src.sin_family, AF_INET);
EXPECT_EQ(absl::gbswap_32(src.sin_addr.s_addr), INADDR_LOOPBACK);
- // The packet ID should be 0, as the packet is less than 68 bytes.
- struct iphdr iphdr = {};
- memcpy(&iphdr, recv_buf, sizeof(iphdr));
- EXPECT_EQ(iphdr.id, 0);
+ // The packet ID should not be 0, as the packet has DF=0.
+ struct iphdr* iphdr = reinterpret_cast<struct iphdr*>(recv_buf);
+ EXPECT_NE(iphdr->id, 0);
}
-// Send and receive a packet with nonzero IP ID.
-TEST_F(RawHDRINCL, SendAndReceiveNonzeroID) {
+// Send and receive a packet where the sendto address is not the same as the
+// provided destination.
+TEST_F(RawHDRINCL, SendAndReceiveDifferentAddress) {
+ // FIXME(gvisor.dev/issue/3160): Test currently flaky.
+ SKIP_IF(true);
+
int port = 40000;
if (!IsRunningOnGvisor()) {
port = static_cast<short>(ASSERT_NO_ERRNO_AND_VALUE(
@@ -292,19 +298,24 @@ TEST_F(RawHDRINCL, SendAndReceiveNonzeroID) {
FileDescriptor udp_sock =
ASSERT_NO_ERRNO_AND_VALUE(Socket(AF_INET, SOCK_RAW, IPPROTO_UDP));
- // Construct a packet with an IP header, UDP header, and payload. Make the
- // payload large enough to force an IP ID to be assigned.
- constexpr char kPayload[128] = {};
+ // Construct a packet with an IP header, UDP header, and payload.
+ constexpr char kPayload[] = "toto";
char packet[sizeof(struct iphdr) + sizeof(struct udphdr) + sizeof(kPayload)];
ASSERT_TRUE(
FillPacket(packet, sizeof(packet), port, kPayload, sizeof(kPayload)));
+ // Overwrite the IP destination address with an IP we can't get to.
+ struct iphdr iphdr = {};
+ memcpy(&iphdr, packet, sizeof(iphdr));
+ iphdr.daddr = 42;
+ memcpy(packet, &iphdr, sizeof(iphdr));
socklen_t addrlen = sizeof(addr_);
ASSERT_NO_FATAL_FAILURE(sendto(socket_, &packet, sizeof(packet), 0,
reinterpret_cast<struct sockaddr*>(&addr_),
addrlen));
- // Receive the payload.
+ // Receive the payload, since sendto should replace the bad destination with
+ // localhost.
char recv_buf[sizeof(packet)];
struct sockaddr_in src;
socklen_t src_size = sizeof(src);
@@ -318,47 +329,58 @@ TEST_F(RawHDRINCL, SendAndReceiveNonzeroID) {
// The network stack should have set the source address.
EXPECT_EQ(src.sin_family, AF_INET);
EXPECT_EQ(absl::gbswap_32(src.sin_addr.s_addr), INADDR_LOOPBACK);
- // The packet ID should not be 0, as the packet was more than 68 bytes.
- struct iphdr* iphdr = reinterpret_cast<struct iphdr*>(recv_buf);
- EXPECT_NE(iphdr->id, 0);
+ // The packet ID should not be 0, as the packet has DF=0.
+ struct iphdr recv_iphdr = {};
+ memcpy(&recv_iphdr, recv_buf, sizeof(recv_iphdr));
+ EXPECT_NE(recv_iphdr.id, 0);
+ // The destination address should be localhost, not the bad IP we set
+ // initially.
+ EXPECT_EQ(absl::gbswap_32(recv_iphdr.daddr), INADDR_LOOPBACK);
}
-// Send and receive a packet where the sendto address is not the same as the
-// provided destination.
-TEST_F(RawHDRINCL, SendAndReceiveDifferentAddress) {
+// Send and receive a packet w/ the IP_HDRINCL option set.
+TEST_F(RawHDRINCL, SendAndReceiveIPHdrIncl) {
int port = 40000;
if (!IsRunningOnGvisor()) {
port = static_cast<short>(ASSERT_NO_ERRNO_AND_VALUE(
PortAvailable(0, AddressFamily::kIpv4, SocketType::kUdp, false)));
}
- // IPPROTO_RAW sockets are write-only. We'll have to open another socket to
- // read what we write.
- FileDescriptor udp_sock =
+ FileDescriptor recv_sock =
+ ASSERT_NO_ERRNO_AND_VALUE(Socket(AF_INET, SOCK_RAW, IPPROTO_UDP));
+
+ FileDescriptor send_sock =
ASSERT_NO_ERRNO_AND_VALUE(Socket(AF_INET, SOCK_RAW, IPPROTO_UDP));
+ // Enable IP_HDRINCL option so that we can build and send w/ an IP
+ // header.
+ constexpr int kSockOptOn = 1;
+ ASSERT_THAT(setsockopt(send_sock.get(), SOL_IP, IP_HDRINCL, &kSockOptOn,
+ sizeof(kSockOptOn)),
+ SyscallSucceeds());
+ // This is not strictly required but we do it to make sure that setting
+ // IP_HDRINCL on a non IPPROTO_RAW socket does not prevent it from receiving
+ // packets.
+ ASSERT_THAT(setsockopt(recv_sock.get(), SOL_IP, IP_HDRINCL, &kSockOptOn,
+ sizeof(kSockOptOn)),
+ SyscallSucceeds());
+
// Construct a packet with an IP header, UDP header, and payload.
constexpr char kPayload[] = "toto";
char packet[sizeof(struct iphdr) + sizeof(struct udphdr) + sizeof(kPayload)];
ASSERT_TRUE(
FillPacket(packet, sizeof(packet), port, kPayload, sizeof(kPayload)));
- // Overwrite the IP destination address with an IP we can't get to.
- struct iphdr iphdr = {};
- memcpy(&iphdr, packet, sizeof(iphdr));
- iphdr.daddr = 42;
- memcpy(packet, &iphdr, sizeof(iphdr));
socklen_t addrlen = sizeof(addr_);
- ASSERT_NO_FATAL_FAILURE(sendto(socket_, &packet, sizeof(packet), 0,
+ ASSERT_NO_FATAL_FAILURE(sendto(send_sock.get(), &packet, sizeof(packet), 0,
reinterpret_cast<struct sockaddr*>(&addr_),
addrlen));
- // Receive the payload, since sendto should replace the bad destination with
- // localhost.
+ // Receive the payload.
char recv_buf[sizeof(packet)];
struct sockaddr_in src;
socklen_t src_size = sizeof(src);
- ASSERT_THAT(recvfrom(udp_sock.get(), recv_buf, sizeof(recv_buf), 0,
+ ASSERT_THAT(recvfrom(recv_sock.get(), recv_buf, sizeof(recv_buf), 0,
reinterpret_cast<struct sockaddr*>(&src), &src_size),
SyscallSucceedsWithValue(sizeof(packet)));
EXPECT_EQ(
@@ -368,13 +390,20 @@ TEST_F(RawHDRINCL, SendAndReceiveDifferentAddress) {
// The network stack should have set the source address.
EXPECT_EQ(src.sin_family, AF_INET);
EXPECT_EQ(absl::gbswap_32(src.sin_addr.s_addr), INADDR_LOOPBACK);
- // The packet ID should be 0, as the packet is less than 68 bytes.
- struct iphdr recv_iphdr = {};
- memcpy(&recv_iphdr, recv_buf, sizeof(recv_iphdr));
- EXPECT_EQ(recv_iphdr.id, 0);
- // The destination address should be localhost, not the bad IP we set
- // initially.
- EXPECT_EQ(absl::gbswap_32(recv_iphdr.daddr), INADDR_LOOPBACK);
+ struct iphdr iphdr = {};
+ memcpy(&iphdr, recv_buf, sizeof(iphdr));
+ EXPECT_NE(iphdr.id, 0);
+
+ // Also verify that the packet we just sent was not delivered to the
+ // IPPROTO_RAW socket.
+ {
+ char recv_buf[sizeof(packet)];
+ struct sockaddr_in src;
+ socklen_t src_size = sizeof(src);
+ ASSERT_THAT(recvfrom(socket_, recv_buf, sizeof(recv_buf), MSG_DONTWAIT,
+ reinterpret_cast<struct sockaddr*>(&src), &src_size),
+ SyscallFailsWithErrno(EAGAIN));
+ }
}
} // namespace