summaryrefslogtreecommitdiffhomepage
path: root/test/syscalls
diff options
context:
space:
mode:
Diffstat (limited to 'test/syscalls')
-rw-r--r--test/syscalls/linux/socket_ipv6_udp_unbound.cc80
1 files changed, 80 insertions, 0 deletions
diff --git a/test/syscalls/linux/socket_ipv6_udp_unbound.cc b/test/syscalls/linux/socket_ipv6_udp_unbound.cc
index 612fd531c..c431bf771 100644
--- a/test/syscalls/linux/socket_ipv6_udp_unbound.cc
+++ b/test/syscalls/linux/socket_ipv6_udp_unbound.cc
@@ -39,6 +39,86 @@
namespace gvisor {
namespace testing {
+using ::testing::IsNull;
+using ::testing::NotNull;
+
+TEST_P(IPv6UDPUnboundSocketTest, IPv6PacketInfo) {
+ auto sender_socket = ASSERT_NO_ERRNO_AND_VALUE(NewSocket());
+ auto receiver_socket = ASSERT_NO_ERRNO_AND_VALUE(NewSocket());
+
+ auto sender_addr = V6Loopback();
+ ASSERT_THAT(bind(sender_socket->get(), AsSockAddr(&sender_addr.addr),
+ sender_addr.addr_len),
+ SyscallSucceeds());
+
+ auto receiver_addr = V6Loopback();
+ ASSERT_THAT(bind(receiver_socket->get(), AsSockAddr(&receiver_addr.addr),
+ receiver_addr.addr_len),
+ SyscallSucceeds());
+ socklen_t receiver_addr_len = receiver_addr.addr_len;
+ ASSERT_THAT(getsockname(receiver_socket->get(),
+ AsSockAddr(&receiver_addr.addr), &receiver_addr_len),
+ SyscallSucceeds());
+ ASSERT_EQ(receiver_addr_len, receiver_addr.addr_len);
+
+ // Make sure we get IPv6 packet information as control messages.
+ constexpr int one = 1;
+ ASSERT_THAT(setsockopt(receiver_socket->get(), IPPROTO_IPV6, IPV6_RECVPKTINFO,
+ &one, sizeof(one)),
+ SyscallSucceeds());
+
+ // Send a packet - we don't care about the packet itself, only the returned
+ // IPV6_PKTINFO control message.
+ char send_buf[200];
+ RandomizeBuffer(send_buf, sizeof(send_buf));
+ ASSERT_THAT(RetryEINTR(sendto)(
+ sender_socket->get(), send_buf, sizeof(send_buf), 0,
+ AsSockAddr(&receiver_addr.addr), receiver_addr.addr_len),
+ SyscallSucceedsWithValue(sizeof(send_buf)));
+
+ // Check that we received the packet with the packet information control
+ // message.
+ char recv_buf[sizeof(send_buf) + 1];
+ in6_pktinfo received_pktinfo;
+ char recv_cmsg_buf[CMSG_SPACE(sizeof(received_pktinfo))];
+ iovec recv_iov = {
+ .iov_base = recv_buf,
+ .iov_len = sizeof(recv_buf),
+ };
+ msghdr recv_msg = {
+ .msg_iov = &recv_iov,
+ .msg_iovlen = 1,
+ .msg_control = recv_cmsg_buf,
+ .msg_controllen = sizeof(recv_cmsg_buf),
+ };
+ ASSERT_THAT(
+ RetryEINTR(recvmsg)(receiver_socket->get(), &recv_msg, 0 /* flags */),
+ SyscallSucceedsWithValue(sizeof(send_buf)));
+ EXPECT_EQ(memcmp(send_buf, recv_buf, sizeof(send_buf)), 0);
+
+ cmsghdr* cmsg = CMSG_FIRSTHDR(&recv_msg);
+ ASSERT_THAT(cmsg, NotNull());
+ EXPECT_EQ(cmsg->cmsg_len, CMSG_LEN(sizeof(in6_pktinfo)));
+ EXPECT_EQ(cmsg->cmsg_level, IPPROTO_IPV6);
+ EXPECT_EQ(cmsg->cmsg_type, IPV6_PKTINFO);
+ // As per cmsg(3) (https://www.man7.org/linux/man-pages/man3/cmsg.3.html),
+ //
+ // CMSG_DATA() returns a pointer to the data portion of a cmsghdr. The
+ // pointer returned cannot be assumed to be suitably aligned for accessing
+ // arbitrary payload data types. Applications should not cast it to a
+ // pointer type matching the payload, but should instead use memcpy(3) to
+ // copy data to or from a suitably declared object.
+ memcpy(&received_pktinfo, CMSG_DATA(cmsg), sizeof(received_pktinfo));
+ EXPECT_EQ(
+ memcmp(&received_pktinfo.ipi6_addr,
+ &(reinterpret_cast<sockaddr_in6*>(&sender_addr.addr)->sin6_addr),
+ sizeof(received_pktinfo.ipi6_addr)),
+ 0);
+ EXPECT_EQ(received_pktinfo.ipi6_ifindex,
+ ASSERT_NO_ERRNO_AND_VALUE(GetLoopbackIndex()));
+ EXPECT_THAT(CMSG_NXTHDR(&recv_msg, cmsg), IsNull());
+}
+
// Test that socket will receive IP_RECVORIGDSTADDR control message.
TEST_P(IPv6UDPUnboundSocketTest, SetAndReceiveIPReceiveOrigDstAddr) {
auto sender = ASSERT_NO_ERRNO_AND_VALUE(NewSocket());