diff options
Diffstat (limited to 'test')
-rw-r--r-- | test/syscalls/linux/socket_ipv6_udp_unbound.cc | 80 |
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()); |