diff --git a/pkg/sentry/socket/netstack/netstack.go b/pkg/sentry/socket/netstack/netstack.go index 59d2e5e4b..a785a85e3 100644 --- a/pkg/sentry/socket/netstack/netstack.go +++ b/pkg/sentry/socket/netstack/netstack.go @@ -1343,6 +1343,19 @@ func getSockOptIPv6(t *kernel.Task, s socket.SocketOps, ep commonEndpoint, name } switch name { + case linux.IPV6_CHECKSUM: + if outLen < sizeOfInt32 { + return nil, syserr.ErrInvalidArgument + } + + v, err := ep.GetSockOptInt(tcpip.IPv6Checksum) + if err != nil { + return nil, syserr.TranslateNetstackError(err) + } + + vP := primitive.Int32(v) + return &vP, nil + case linux.IPV6_V6ONLY: if outLen < sizeOfInt32 { return nil, syserr.ErrInvalidArgument @@ -2151,6 +2164,15 @@ func setSockOptIPv6(t *kernel.Task, s socket.SocketOps, ep commonEndpoint, name } switch name { + case linux.IPV6_CHECKSUM: + if len(optVal) < sizeOfInt32 { + return syserr.ErrInvalidArgument + } + + // int may not be 32-bits so we cast the uint32 to an int32 before casting + // to an int. + return syserr.TranslateNetstackError(ep.SetSockOptInt(tcpip.IPv6Checksum, int(int32(hostarch.ByteOrder.Uint32(optVal))))) + case linux.IPV6_V6ONLY: if len(optVal) < sizeOfInt32 { return syserr.ErrInvalidArgument diff --git a/pkg/tcpip/header/checksum.go b/pkg/tcpip/header/checksum.go index ff283160d..38e39242d 100644 --- a/pkg/tcpip/header/checksum.go +++ b/pkg/tcpip/header/checksum.go @@ -24,6 +24,11 @@ import ( "gvisor.dev/gvisor/pkg/tcpip/buffer" ) +// ChecksumSize is the size of a checksum. +// +// The checksum is held in a uint16 which is 2 bytes. +const ChecksumSize = 2 + // PutChecksum puts the checksum in the provided byte slice. func PutChecksum(b []byte, xsum uint16) { binary.BigEndian.PutUint16(b, xsum) diff --git a/pkg/tcpip/header/icmpv6.go b/pkg/tcpip/header/icmpv6.go index 5beaf8cf5..26b27ee07 100644 --- a/pkg/tcpip/header/icmpv6.go +++ b/pkg/tcpip/header/icmpv6.go @@ -67,9 +67,9 @@ const ( // packet-too-big packet. ICMPv6PacketTooBigMinimumSize = ICMPv6MinimumSize - // icmpv6ChecksumOffset is the offset of the checksum field + // ICMPv6ChecksumOffset is the offset of the checksum field // in an ICMPv6 message. - icmpv6ChecksumOffset = 2 + ICMPv6ChecksumOffset = 2 // icmpv6PointerOffset is the offset of the pointer // in an ICMPv6 Parameter problem message. @@ -194,12 +194,12 @@ func (b ICMPv6) SetTypeSpecific(val uint32) { // Checksum is the ICMP checksum field. func (b ICMPv6) Checksum() uint16 { - return binary.BigEndian.Uint16(b[icmpv6ChecksumOffset:]) + return binary.BigEndian.Uint16(b[ICMPv6ChecksumOffset:]) } // SetChecksum sets the ICMP checksum field. func (b ICMPv6) SetChecksum(checksum uint16) { - PutChecksum(b[icmpv6ChecksumOffset:], checksum) + PutChecksum(b[ICMPv6ChecksumOffset:], checksum) } // SourcePort implements Transport.SourcePort. diff --git a/pkg/tcpip/tcpip.go b/pkg/tcpip/tcpip.go index 697bad7ee..d94ad1136 100644 --- a/pkg/tcpip/tcpip.go +++ b/pkg/tcpip/tcpip.go @@ -757,6 +757,10 @@ const ( // // NOTE: This option is currently only stubed out and is a no-op TCPWindowClampOption + + // IPv6Checksum is used to request the stack to populate and validate the IPv6 + // checksum for transport level headers. + IPv6Checksum ) const ( diff --git a/pkg/tcpip/transport/raw/endpoint.go b/pkg/tcpip/transport/raw/endpoint.go index 2f309bf11..5b902b3f9 100644 --- a/pkg/tcpip/transport/raw/endpoint.go +++ b/pkg/tcpip/transport/raw/endpoint.go @@ -85,6 +85,13 @@ type endpoint struct { rcvDisabled bool mu sync.RWMutex `state:"nosave"` + + // ipv6ChecksumOffset indicates the offset to populate the IPv6 checksum at. + // + // A negative value indicates no checksum should be calculated. + // + // +checklocks:mu + ipv6ChecksumOffset int // icmp6Filter holds the filter for ICMPv6 packets. // // +checklocks:mu @@ -97,11 +104,24 @@ func NewEndpoint(stack *stack.Stack, netProto tcpip.NetworkProtocolNumber, trans } func newEndpoint(s *stack.Stack, netProto tcpip.NetworkProtocolNumber, transProto tcpip.TransportProtocolNumber, waiterQueue *waiter.Queue, associated bool) (tcpip.Endpoint, tcpip.Error) { + // Calculating the upper-layer checksum is disabled by default for raw IPv6 + // endpoints, unless the upper-layer protocol is ICMPv6. + // + // As per RFC 3542 section 3.1, + // + // The kernel will calculate and insert the ICMPv6 checksum for ICMPv6 + // raw sockets, since this checksum is mandatory. + ipv6ChecksumOffset := -1 + if netProto == header.IPv6ProtocolNumber && transProto == header.ICMPv6ProtocolNumber { + ipv6ChecksumOffset = header.ICMPv6ChecksumOffset + } + e := &endpoint{ - stack: s, - transProto: transProto, - waiterQueue: waiterQueue, - associated: associated, + stack: s, + transProto: transProto, + waiterQueue: waiterQueue, + associated: associated, + ipv6ChecksumOffset: ipv6ChecksumOffset, } e.ops.InitHandler(e, e.stack, tcpip.GetStackSendBufferLimits, tcpip.GetStackReceiveBufferLimits) e.ops.SetHeaderIncluded(!associated) @@ -274,7 +294,10 @@ func (e *endpoint) Write(p tcpip.Payloader, opts tcpip.WriteOptions) (int64, tcp } func (e *endpoint) write(p tcpip.Payloader, opts tcpip.WriteOptions) (int64, tcpip.Error) { + e.mu.Lock() ctx, err := e.net.AcquireContextForWrite(opts) + ipv6ChecksumOffset := e.ipv6ChecksumOffset + e.mu.Unlock() if err != nil { return 0, err } @@ -285,6 +308,18 @@ func (e *endpoint) write(p tcpip.Payloader, opts tcpip.WriteOptions) (int64, tcp return 0, &tcpip.ErrBadBuffer{} } + if packetInfo := ctx.PacketInfo(); packetInfo.NetProto == header.IPv6ProtocolNumber && ipv6ChecksumOffset >= 0 { + // Make sure we can fit the checksum. + if len(payloadBytes) < ipv6ChecksumOffset+header.ChecksumSize { + return 0, &tcpip.ErrInvalidOptionValue{} + } + + xsum := header.PseudoHeaderChecksum(e.transProto, packetInfo.LocalAddress, packetInfo.RemoteAddress, uint16(len(payloadBytes))) + header.PutChecksum(payloadBytes[ipv6ChecksumOffset:], 0) + xsum = header.Checksum(payloadBytes, xsum) + header.PutChecksum(payloadBytes[ipv6ChecksumOffset:], ^xsum) + } + pkt := stack.NewPacketBuffer(stack.PacketBufferOptions{ ReserveHeaderBytes: int(ctx.PacketInfo().MaxHeaderLength), Data: buffer.View(payloadBytes).ToVectorisedView(), @@ -415,7 +450,31 @@ func (e *endpoint) SetSockOpt(opt tcpip.SettableSocketOption) tcpip.Error { } func (e *endpoint) SetSockOptInt(opt tcpip.SockOptInt, v int) tcpip.Error { - return e.net.SetSockOptInt(opt, v) + switch opt { + case tcpip.IPv6Checksum: + if e.net.NetProto() != header.IPv6ProtocolNumber { + return &tcpip.ErrUnknownProtocolOption{} + } + + if e.transProto == header.ICMPv6ProtocolNumber { + // As per RFC 3542 section 3.1, + // + // An attempt to set IPV6_CHECKSUM for an ICMPv6 socket will fail. + return &tcpip.ErrInvalidOptionValue{} + } + + // Make sure the offset is aligned properly if checksum is requested. + if v > 0 && v%header.ChecksumSize != 0 { + return &tcpip.ErrInvalidOptionValue{} + } + + e.mu.Lock() + defer e.mu.Unlock() + e.ipv6ChecksumOffset = v + return nil + default: + return e.net.SetSockOptInt(opt, v) + } } // GetSockOpt implements tcpip.Endpoint.GetSockOpt. @@ -453,6 +512,15 @@ func (e *endpoint) GetSockOptInt(opt tcpip.SockOptInt) (int, tcpip.Error) { e.rcvMu.Unlock() return v, nil + case tcpip.IPv6Checksum: + if e.net.NetProto() != header.IPv6ProtocolNumber { + return 0, &tcpip.ErrUnknownProtocolOption{} + } + + e.mu.Lock() + defer e.mu.Unlock() + return e.ipv6ChecksumOffset, nil + default: return e.net.GetSockOptInt(opt) } @@ -552,6 +620,7 @@ func (e *endpoint) HandlePacket(pkt *stack.PacketBuffer) { headers = append(headers, networkHeader...) headers = append(headers, transportHeader...) combinedVV = headers.ToVectorisedView() + combinedVV.Append(pkt.Data().ExtractVV()) case header.IPv6ProtocolNumber: if e.transProto == header.ICMPv6ProtocolNumber { if len(transportHeader) < header.ICMPv6MinimumSize { @@ -564,10 +633,26 @@ func (e *endpoint) HandlePacket(pkt *stack.PacketBuffer) { } combinedVV = append(buffer.View(nil), transportHeader...).ToVectorisedView() + combinedVV.Append(pkt.Data().ExtractVV()) + + if checksumOffset := e.ipv6ChecksumOffset; checksumOffset >= 0 { + vvSize := combinedVV.Size() + if vvSize < checksumOffset+header.ChecksumSize { + // Message too small to fit checksum. + return false + } + + xsum := header.PseudoHeaderChecksum(e.transProto, srcAddr, dstAddr, uint16(vvSize)) + xsum = header.ChecksumVV(combinedVV, xsum) + if xsum != 0xFFFF { + // Invalid checksum. + return false + } + } default: panic(fmt.Sprintf("unrecognized protocol number = %d", info.NetProto)) } - combinedVV.Append(pkt.Data().ExtractVV()) + packet.data = combinedVV packet.receivedAt = e.stack.Clock().Now() diff --git a/test/syscalls/linux/raw_socket.cc b/test/syscalls/linux/raw_socket.cc index ef176cbee..8b21b1dc9 100644 --- a/test/syscalls/linux/raw_socket.cc +++ b/test/syscalls/linux/raw_socket.cc @@ -1186,6 +1186,179 @@ TEST(RawSocketTest, ReceiveIPv6PacketInfo) { EXPECT_THAT(CMSG_NXTHDR(&recv_msg, cmsg), IsNull()); } +TEST(RawSocketTest, SetIPv6ChecksumError_MultipleOf2) { + SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveRawIPSocketCapability())); + + FileDescriptor fd = + ASSERT_NO_ERRNO_AND_VALUE(Socket(AF_INET6, SOCK_RAW, IPPROTO_UDP)); + + int intV = 3; + ASSERT_THAT( + setsockopt(fd.get(), SOL_IPV6, IPV6_CHECKSUM, &intV, sizeof(intV)), + SyscallFailsWithErrno(EINVAL)); + + intV = 5; + ASSERT_THAT( + setsockopt(fd.get(), SOL_IPV6, IPV6_CHECKSUM, &intV, sizeof(intV)), + SyscallFailsWithErrno(EINVAL)); + + intV = 2; + ASSERT_THAT( + setsockopt(fd.get(), SOL_IPV6, IPV6_CHECKSUM, &intV, sizeof(intV)), + SyscallSucceeds()); + + intV = 4; + ASSERT_THAT( + setsockopt(fd.get(), SOL_IPV6, IPV6_CHECKSUM, &intV, sizeof(intV)), + SyscallSucceeds()); +} + +TEST(RawSocketTest, SetIPv6ChecksumError_ReadShort) { + SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveRawIPSocketCapability())); + + FileDescriptor fd = + ASSERT_NO_ERRNO_AND_VALUE(Socket(AF_INET6, SOCK_RAW, IPPROTO_UDP)); + + int intV = 2; + if (IsRunningOnGvisor() && !IsRunningWithHostinet()) { + // TODO(https://gvisor.dev/issue/6982): This is a deviation from Linux. We + // should determine if we want to match the behaviour or handle the error + // more gracefully. + ASSERT_THAT( + setsockopt(fd.get(), SOL_IPV6, IPV6_CHECKSUM, &intV, sizeof(intV) - 1), + SyscallFailsWithErrno(EINVAL)); + return; + } + + intV = std::numeric_limits::max(); + if (intV % 2) { + intV--; + } + + if (const char* val = getenv("IPV6_CHECKSUM_SETSOCKOPT_SHORT_EXCEPTION"); + val != nullptr && strcmp(val, "1") == 0) { + // TODO(https://issuetracker.google.com/issues/212585236): As of writing, it + // seems like at least one Linux environment considers optlen unlike a local + // Linux environment. In this case we call setsockopt with the full int so + // that the rest of the test passes. Once the root cause for this difference + // is found, we can update this check. + ASSERT_THAT( + setsockopt(fd.get(), SOL_IPV6, IPV6_CHECKSUM, &intV, sizeof(intV)), + SyscallSucceeds()); + } else { + ASSERT_THAT( + setsockopt(fd.get(), SOL_IPV6, IPV6_CHECKSUM, &intV, sizeof(intV) - 1), + SyscallSucceeds()); + } + + { + int got; + socklen_t got_len = sizeof(got); + ASSERT_THAT(getsockopt(fd.get(), SOL_IPV6, IPV6_CHECKSUM, &got, &got_len), + SyscallSucceeds()); + ASSERT_EQ(got_len, sizeof(got)); + // Even though we called setsockopt with a length smaller than an int, Linux + // seems to read the full int. + EXPECT_EQ(got, intV); + } + + // If we have pass a pointer that points to memory less than the size of an + // int, we get a bad address error. + std::unique_ptr u8V; + // Linux seems to assume a full int but doesn't check the passed length. + // + // https://github.com/torvalds/linux/blob/a52a8e9eaf4a12dd58953fc622bb2bc08fd1d32c/net/ipv6/raw.c#L1023 + // shows that Linux copies optVal to an int without first checking optLen. + ASSERT_THAT( + setsockopt(fd.get(), SOL_IPV6, IPV6_CHECKSUM, u8V.get(), sizeof(*u8V)), + SyscallFailsWithErrno(EFAULT)); +} + +TEST(RawSocketTest, IPv6Checksum_ValidateAndCalculate) { + SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveRawIPSocketCapability())); + + FileDescriptor checksum_set = + ASSERT_NO_ERRNO_AND_VALUE(Socket(AF_INET6, SOCK_RAW, IPPROTO_UDP)); + + FileDescriptor checksum_not_set = + ASSERT_NO_ERRNO_AND_VALUE(Socket(AF_INET6, SOCK_RAW, IPPROTO_UDP)); + + const sockaddr_in6 addr = { + .sin6_family = AF_INET6, + .sin6_addr = IN6ADDR_LOOPBACK_INIT, + }; + + auto bind_and_set_checksum = [&](const FileDescriptor& fd, int v) { + ASSERT_THAT( + bind(fd.get(), reinterpret_cast(&addr), sizeof(addr)), + SyscallSucceeds()); + + int got; + socklen_t got_len = sizeof(got); + ASSERT_THAT(getsockopt(fd.get(), SOL_IPV6, IPV6_CHECKSUM, &got, &got_len), + SyscallSucceeds()); + ASSERT_EQ(got_len, sizeof(got)); + EXPECT_EQ(got, -1); + + ASSERT_THAT(setsockopt(fd.get(), SOL_IPV6, IPV6_CHECKSUM, &v, sizeof(v)), + SyscallSucceeds()); + ASSERT_THAT(getsockopt(fd.get(), SOL_IPV6, IPV6_CHECKSUM, &got, &got_len), + SyscallSucceeds()); + ASSERT_EQ(got_len, sizeof(got)); + EXPECT_EQ(got, v); + }; + + struct udp_packet { + udphdr udp; + uint32_t value; + } ABSL_ATTRIBUTE_PACKED; + + ASSERT_NO_FATAL_FAILURE(bind_and_set_checksum( + checksum_set, offsetof(udp_packet, udp) + offsetof(udphdr, uh_sum))); + ASSERT_NO_FATAL_FAILURE(bind_and_set_checksum(checksum_not_set, -1)); + + auto send = [&](const FileDescriptor& fd, uint32_t v) { + const udp_packet packet = { + .value = v, + }; + + ASSERT_THAT(sendto(fd.get(), &packet, sizeof(packet), /*flags=*/0, + reinterpret_cast(&addr), sizeof(addr)), + SyscallSucceedsWithValue(sizeof(packet))); + }; + + auto expect_receive = [&](const FileDescriptor& fd, uint32_t v, + bool should_check_xsum) { + udp_packet packet; + sockaddr_in6 sender; + socklen_t sender_len = sizeof(sender); + ASSERT_THAT( + RetryEINTR(recvfrom)(fd.get(), &packet, sizeof(packet), /*flags=*/0, + reinterpret_cast(&sender), &sender_len), + SyscallSucceedsWithValue(sizeof(packet))); + ASSERT_EQ(sender_len, sizeof(sender)); + EXPECT_EQ(memcmp(&sender, &addr, sizeof(addr)), 0); + EXPECT_EQ(packet.value, v); + if (should_check_xsum) { + EXPECT_NE(packet.udp.uh_sum, 0); + } else { + EXPECT_EQ(packet.udp.uh_sum, 0); + } + }; + + uint32_t counter = 1; + // Packets sent through checksum_not_set will not have a valid checksum set so + // checksum_set should not accept those packets. + ASSERT_NO_FATAL_FAILURE(send(checksum_not_set, counter)); + ASSERT_NO_FATAL_FAILURE(expect_receive(checksum_not_set, counter, false)); + + // Packets sent through checksum_set will have a valid checksum so both + // sockets should accept them. + ASSERT_NO_FATAL_FAILURE(send(checksum_set, ++counter)); + ASSERT_NO_FATAL_FAILURE(expect_receive(checksum_set, counter, true)); + ASSERT_NO_FATAL_FAILURE(expect_receive(checksum_not_set, counter, true)); +} + } // namespace } // namespace testing diff --git a/test/syscalls/linux/raw_socket_icmp.cc b/test/syscalls/linux/raw_socket_icmp.cc index 2206a32d1..8c8daf5d2 100644 --- a/test/syscalls/linux/raw_socket_icmp.cc +++ b/test/syscalls/linux/raw_socket_icmp.cc @@ -109,7 +109,7 @@ void RawSocketICMPTest::TearDown() { } } -TEST_F(RawSocketICMPTest, SockOptIPv6Checksum) { +TEST_F(RawSocketICMPTest, IPv6ChecksumNotSupported) { int v; EXPECT_THAT(setsockopt(s_, SOL_IPV6, IPV6_CHECKSUM, &v, sizeof(v)), SyscallFailsWithErrno(ENOPROTOOPT)); @@ -633,6 +633,92 @@ TEST_F(RawSocketICMPv6Test, GetPartialFilterSucceeds) { FieldsAre(ElementsAreArray(expected_filter.icmp6_filt))); } +TEST_F(RawSocketICMPv6Test, SetSockOptIPv6ChecksumFails) { + int v = 2; + EXPECT_THAT(setsockopt(fd().get(), SOL_IPV6, IPV6_CHECKSUM, &v, sizeof(v)), + SyscallFailsWithErrno(EINVAL)); + socklen_t len = sizeof(v); + EXPECT_THAT(getsockopt(fd().get(), SOL_IPV6, IPV6_CHECKSUM, &v, &len), + SyscallSucceeds()); + ASSERT_EQ(len, sizeof(v)); + EXPECT_EQ(v, offsetof(icmp6_hdr, icmp6_cksum)); +} + +TEST_F(RawSocketICMPv6Test, MsgTooSmallToFillChecksumFailsSend) { + char buf[offsetof(icmp6_hdr, icmp6_cksum) + + sizeof((icmp6_hdr{}).icmp6_cksum) - 1]; + + const sockaddr_in6 addr = { + .sin6_family = AF_INET6, + .sin6_addr = IN6ADDR_LOOPBACK_INIT, + }; + + ASSERT_THAT(sendto(fd().get(), &buf, sizeof(buf), /*flags=*/0, + reinterpret_cast(&addr), sizeof(addr)), + SyscallFailsWithErrno(EINVAL)); +} + +constexpr uint8_t kUnusedICMPCode = 0; + +TEST_F(RawSocketICMPv6Test, PingSuccessfully) { + // Only observe echo packets. + { + icmp6_filter set_filter; + ICMP6_FILTER_SETBLOCKALL(&set_filter); + ICMP6_FILTER_SETPASS(ICMP6_ECHO_REQUEST, &set_filter); + ICMP6_FILTER_SETPASS(ICMP6_ECHO_REPLY, &set_filter); + ASSERT_THAT(setsockopt(fd().get(), SOL_ICMPV6, ICMP6_FILTER, &set_filter, + sizeof(set_filter)), + SyscallSucceeds()); + } + + const sockaddr_in6 addr = { + .sin6_family = AF_INET6, + .sin6_addr = IN6ADDR_LOOPBACK_INIT, + }; + + auto send_with_checksum = [&](uint16_t checksum) { + const icmp6_hdr echo_request = { + .icmp6_type = ICMP6_ECHO_REQUEST, + .icmp6_code = kUnusedICMPCode, + .icmp6_cksum = checksum, + }; + + ASSERT_THAT(RetryEINTR(sendto)(fd().get(), &echo_request, + sizeof(echo_request), /*flags=*/0, + reinterpret_cast(&addr), + sizeof(addr)), + SyscallSucceedsWithValue(sizeof(echo_request))); + }; + + auto check_recv = [&](uint8_t expected_type) { + icmp6_hdr got_echo; + sockaddr_in6 sender; + socklen_t sender_len = sizeof(sender); + ASSERT_THAT(RetryEINTR(recvfrom)( + fd().get(), &got_echo, sizeof(got_echo), /*flags=*/0, + reinterpret_cast(&sender), &sender_len), + SyscallSucceedsWithValue(sizeof(got_echo))); + ASSERT_EQ(sender_len, sizeof(sender)); + EXPECT_EQ(memcmp(&sender, &addr, sizeof(addr)), 0); + EXPECT_THAT(got_echo, + FieldsAre(expected_type, kUnusedICMPCode, + // The stack should have populated the checksum. + /*icmp6_cksum=*/Not(0), /*icmp6_dataun=*/_)); + EXPECT_THAT(got_echo.icmp6_data32, ElementsAre(0)); + }; + + // Send a request and observe the request followed by the response. + ASSERT_NO_FATAL_FAILURE(send_with_checksum(0)); + ASSERT_NO_FATAL_FAILURE(check_recv(ICMP6_ECHO_REQUEST)); + ASSERT_NO_FATAL_FAILURE(check_recv(ICMP6_ECHO_REPLY)); + + // The stack ignores the checksum set by the user. + ASSERT_NO_FATAL_FAILURE(send_with_checksum(1)); + ASSERT_NO_FATAL_FAILURE(check_recv(ICMP6_ECHO_REQUEST)); + ASSERT_NO_FATAL_FAILURE(check_recv(ICMP6_ECHO_REPLY)); +} + class RawSocketICMPv6TypeTest : public RawSocketICMPv6Test, public WithParamInterface {}; @@ -664,7 +750,6 @@ TEST_P(RawSocketICMPv6TypeTest, FilterDeliveredPackets) { // Send an ICMP packet for each type. uint8_t icmp_type = 0; - constexpr uint8_t kUnusedICMPCode = 0; do { const icmp6_hdr packet = { .icmp6_type = icmp_type, @@ -685,25 +770,15 @@ TEST_P(RawSocketICMPv6TypeTest, FilterDeliveredPackets) { sockaddr_in6 sender; socklen_t sender_len = sizeof(sender); ASSERT_THAT(RetryEINTR(recvfrom)( - fd().get(), &got_packet, sizeof(got_packet), 0 /* flags */, + fd().get(), &got_packet, sizeof(got_packet), /*flags=*/0, reinterpret_cast(&sender), &sender_len), SyscallSucceedsWithValue(sizeof(got_packet))); ASSERT_EQ(sender_len, sizeof(sender)); EXPECT_EQ(memcmp(&sender, &addr, sizeof(addr)), 0); // The stack should have populated the checksum. - if (IsRunningOnGvisor() && !IsRunningWithHostinet()) { - // TODO(https://github.com/google/gvisor/pull/6957): Use same check as - // Linux. - EXPECT_THAT(got_packet, - FieldsAre(allowed_type, kUnusedICMPCode, 0 /* icmp6_cksum */, - _ /* icmp6_dataun */ - )); - } else { - EXPECT_THAT(got_packet, - FieldsAre(allowed_type, kUnusedICMPCode, - Not(0) /* icmp6_cksum */, _ /* icmp6_dataun */ - )); - } + EXPECT_THAT(got_packet, + FieldsAre(allowed_type, kUnusedICMPCode, + /*icmp6_cksum=*/Not(0), /*icmp6_dataun=*/_)); EXPECT_THAT(got_packet.icmp6_data32, ElementsAre(0)); } }