From 71d53382bfb3a6f05e90e31df8f39d22c0131040 Mon Sep 17 00:00:00 2001 From: Ian Gudger Date: Sat, 9 Mar 2019 11:39:41 -0800 Subject: Fix getsockopt(IP_MULTICAST_IF). getsockopt(IP_MULTICAST_IF) only supports struct in_addr. Also adds support for setsockopt(IP_MULTICAST_IF) with struct in_addr. PiperOrigin-RevId: 237620230 Change-Id: I75e7b5b3e08972164eb1906f43ddd67aedffc27c --- test/syscalls/linux/socket_ipv4_udp_unbound.cc | 174 ++++++++++++++++++++++++- 1 file changed, 172 insertions(+), 2 deletions(-) (limited to 'test/syscalls') diff --git a/test/syscalls/linux/socket_ipv4_udp_unbound.cc b/test/syscalls/linux/socket_ipv4_udp_unbound.cc index 38bc85ce9..c99958ed5 100644 --- a/test/syscalls/linux/socket_ipv4_udp_unbound.cc +++ b/test/syscalls/linux/socket_ipv4_udp_unbound.cc @@ -893,7 +893,7 @@ TEST_P(IPv4UDPUnboundSocketPairTest, IpMulticastDropAddr) { receiver_addr.addr_len), SyscallSucceeds()); socklen_t receiver_addr_len = receiver_addr.addr_len; - EXPECT_THAT(getsockname(sockets->second_fd(), + ASSERT_THAT(getsockname(sockets->second_fd(), reinterpret_cast(&receiver_addr.addr), &receiver_addr_len), SyscallSucceeds()); @@ -951,7 +951,7 @@ TEST_P(IPv4UDPUnboundSocketPairTest, IpMulticastDropNic) { receiver_addr.addr_len), SyscallSucceeds()); socklen_t receiver_addr_len = receiver_addr.addr_len; - EXPECT_THAT(getsockname(sockets->second_fd(), + ASSERT_THAT(getsockname(sockets->second_fd(), reinterpret_cast(&receiver_addr.addr), &receiver_addr_len), SyscallSucceeds()); @@ -1016,6 +1016,176 @@ TEST_P(IPv4UDPUnboundSocketPairTest, IpMulticastIfInvalidAddr) { SyscallFailsWithErrno(EADDRNOTAVAIL)); } +TEST_P(IPv4UDPUnboundSocketPairTest, IpMulticastIfSetShort) { + auto sockets = ASSERT_NO_ERRNO_AND_VALUE(NewSocketPair()); + + // Create a valid full-sized request. + ip_mreqn iface = {}; + iface.imr_ifindex = ASSERT_NO_ERRNO_AND_VALUE(InterfaceIndex("lo")); + + // Send an optlen of 1 to check that optlen is enforced. + EXPECT_THAT( + setsockopt(sockets->first_fd(), IPPROTO_IP, IP_MULTICAST_IF, &iface, 1), + SyscallFailsWithErrno(EINVAL)); +} + +TEST_P(IPv4UDPUnboundSocketPairTest, IpMulticastIfDefault) { + auto sockets = ASSERT_NO_ERRNO_AND_VALUE(NewSocketPair()); + + in_addr get = {}; + socklen_t size = sizeof(get); + ASSERT_THAT( + getsockopt(sockets->first_fd(), IPPROTO_IP, IP_MULTICAST_IF, &get, &size), + SyscallSucceeds()); + EXPECT_EQ(size, sizeof(get)); + EXPECT_EQ(get.s_addr, 0); +} + +TEST_P(IPv4UDPUnboundSocketPairTest, IpMulticastIfDefaultReqn) { + auto sockets = ASSERT_NO_ERRNO_AND_VALUE(NewSocketPair()); + + ip_mreqn get = {}; + socklen_t size = sizeof(get); + ASSERT_THAT( + getsockopt(sockets->first_fd(), IPPROTO_IP, IP_MULTICAST_IF, &get, &size), + SyscallSucceeds()); + + // getsockopt(IP_MULTICAST_IF) can only return an in_addr, so it treats the + // first sizeof(struct in_addr) bytes of struct ip_mreqn as a struct in_addr. + // Conveniently, this corresponds to the field ip_mreqn::imr_multiaddr. + EXPECT_EQ(size, sizeof(in_addr)); + + // getsockopt(IP_MULTICAST_IF) will only return the interface address which + // hasn't been set. + EXPECT_EQ(get.imr_multiaddr.s_addr, 0); + EXPECT_EQ(get.imr_address.s_addr, 0); + EXPECT_EQ(get.imr_ifindex, 0); +} + +TEST_P(IPv4UDPUnboundSocketPairTest, IpMulticastIfSetAddrGetReqn) { + auto sockets = ASSERT_NO_ERRNO_AND_VALUE(NewSocketPair()); + + in_addr set = {}; + set.s_addr = htonl(INADDR_LOOPBACK); + ASSERT_THAT(setsockopt(sockets->first_fd(), IPPROTO_IP, IP_MULTICAST_IF, &set, + sizeof(set)), + SyscallSucceeds()); + + ip_mreqn get = {}; + socklen_t size = sizeof(get); + ASSERT_THAT( + getsockopt(sockets->first_fd(), IPPROTO_IP, IP_MULTICAST_IF, &get, &size), + SyscallSucceeds()); + + // getsockopt(IP_MULTICAST_IF) can only return an in_addr, so it treats the + // first sizeof(struct in_addr) bytes of struct ip_mreqn as a struct in_addr. + // Conveniently, this corresponds to the field ip_mreqn::imr_multiaddr. + EXPECT_EQ(size, sizeof(in_addr)); + EXPECT_EQ(get.imr_multiaddr.s_addr, set.s_addr); + EXPECT_EQ(get.imr_address.s_addr, 0); + EXPECT_EQ(get.imr_ifindex, 0); +} + +TEST_P(IPv4UDPUnboundSocketPairTest, IpMulticastIfSetReqAddrGetReqn) { + auto sockets = ASSERT_NO_ERRNO_AND_VALUE(NewSocketPair()); + + ip_mreq set = {}; + set.imr_interface.s_addr = htonl(INADDR_LOOPBACK); + ASSERT_THAT(setsockopt(sockets->first_fd(), IPPROTO_IP, IP_MULTICAST_IF, &set, + sizeof(set)), + SyscallSucceeds()); + + ip_mreqn get = {}; + socklen_t size = sizeof(get); + ASSERT_THAT( + getsockopt(sockets->first_fd(), IPPROTO_IP, IP_MULTICAST_IF, &get, &size), + SyscallSucceeds()); + + // getsockopt(IP_MULTICAST_IF) can only return an in_addr, so it treats the + // first sizeof(struct in_addr) bytes of struct ip_mreqn as a struct in_addr. + // Conveniently, this corresponds to the field ip_mreqn::imr_multiaddr. + EXPECT_EQ(size, sizeof(in_addr)); + EXPECT_EQ(get.imr_multiaddr.s_addr, set.imr_interface.s_addr); + EXPECT_EQ(get.imr_address.s_addr, 0); + EXPECT_EQ(get.imr_ifindex, 0); +} + +TEST_P(IPv4UDPUnboundSocketPairTest, IpMulticastIfSetNicGetReqn) { + auto sockets = ASSERT_NO_ERRNO_AND_VALUE(NewSocketPair()); + + ip_mreqn set = {}; + set.imr_ifindex = ASSERT_NO_ERRNO_AND_VALUE(InterfaceIndex("lo")); + ASSERT_THAT(setsockopt(sockets->first_fd(), IPPROTO_IP, IP_MULTICAST_IF, &set, + sizeof(set)), + SyscallSucceeds()); + + ip_mreqn get = {}; + socklen_t size = sizeof(get); + ASSERT_THAT( + getsockopt(sockets->first_fd(), IPPROTO_IP, IP_MULTICAST_IF, &get, &size), + SyscallSucceeds()); + EXPECT_EQ(size, sizeof(in_addr)); + EXPECT_EQ(get.imr_multiaddr.s_addr, 0); + EXPECT_EQ(get.imr_address.s_addr, 0); + EXPECT_EQ(get.imr_ifindex, 0); +} + +TEST_P(IPv4UDPUnboundSocketPairTest, IpMulticastIfSetAddr) { + auto sockets = ASSERT_NO_ERRNO_AND_VALUE(NewSocketPair()); + + in_addr set = {}; + set.s_addr = htonl(INADDR_LOOPBACK); + ASSERT_THAT(setsockopt(sockets->first_fd(), IPPROTO_IP, IP_MULTICAST_IF, &set, + sizeof(set)), + SyscallSucceeds()); + + in_addr get = {}; + socklen_t size = sizeof(get); + ASSERT_THAT( + getsockopt(sockets->first_fd(), IPPROTO_IP, IP_MULTICAST_IF, &get, &size), + SyscallSucceeds()); + + EXPECT_EQ(size, sizeof(get)); + EXPECT_EQ(get.s_addr, set.s_addr); +} + +TEST_P(IPv4UDPUnboundSocketPairTest, IpMulticastIfSetReqAddr) { + auto sockets = ASSERT_NO_ERRNO_AND_VALUE(NewSocketPair()); + + ip_mreq set = {}; + set.imr_interface.s_addr = htonl(INADDR_LOOPBACK); + ASSERT_THAT(setsockopt(sockets->first_fd(), IPPROTO_IP, IP_MULTICAST_IF, &set, + sizeof(set)), + SyscallSucceeds()); + + in_addr get = {}; + socklen_t size = sizeof(get); + ASSERT_THAT( + getsockopt(sockets->first_fd(), IPPROTO_IP, IP_MULTICAST_IF, &get, &size), + SyscallSucceeds()); + + EXPECT_EQ(size, sizeof(get)); + EXPECT_EQ(get.s_addr, set.imr_interface.s_addr); +} + +TEST_P(IPv4UDPUnboundSocketPairTest, IpMulticastIfSetNic) { + auto sockets = ASSERT_NO_ERRNO_AND_VALUE(NewSocketPair()); + + ip_mreqn set = {}; + set.imr_ifindex = ASSERT_NO_ERRNO_AND_VALUE(InterfaceIndex("lo")); + ASSERT_THAT(setsockopt(sockets->first_fd(), IPPROTO_IP, IP_MULTICAST_IF, &set, + sizeof(set)), + SyscallSucceeds()); + + in_addr get = {}; + socklen_t size = sizeof(get); + ASSERT_THAT( + getsockopt(sockets->first_fd(), IPPROTO_IP, IP_MULTICAST_IF, &get, &size), + SyscallSucceeds()); + EXPECT_EQ(size, sizeof(get)); + EXPECT_EQ(get.s_addr, 0); +} + TEST_P(IPv4UDPUnboundSocketPairTest, TestJoinGroupNoIf) { auto sockets = ASSERT_NO_ERRNO_AND_VALUE(NewSocketPair()); -- cgit v1.2.3