|  | // Copyright (c) 2019 The Chromium Authors. All rights reserved. | 
|  | // Use of this source code is governed by a BSD-style license that can be | 
|  | // found in the LICENSE file. | 
|  |  | 
|  | #include "quic/qbone/platform/icmp_packet.h" | 
|  |  | 
|  | #include <netinet/ip6.h> | 
|  |  | 
|  | #include <cstdint> | 
|  |  | 
|  | #include "absl/strings/string_view.h" | 
|  | #include "quic/platform/api/quic_test.h" | 
|  | #include "common/quiche_text_utils.h" | 
|  |  | 
|  | namespace quic { | 
|  | namespace { | 
|  |  | 
|  | constexpr char kReferenceSourceAddress[] = "fe80:1:2:3:4::1"; | 
|  | constexpr char kReferenceDestinationAddress[] = "fe80:4:3:2:1::1"; | 
|  |  | 
|  | // clang-format off | 
|  | constexpr  uint8_t kReferenceICMPMessageBody[] { | 
|  | 0xd2, 0x61, 0x29, 0x5b, 0x00, 0x00, 0x00, 0x00, | 
|  | 0x0d, 0x59, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, | 
|  | 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, | 
|  | 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, | 
|  | 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, | 
|  | 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, | 
|  | 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37 | 
|  | }; | 
|  |  | 
|  | constexpr uint8_t kReferenceICMPPacket[] = { | 
|  | // START IPv6 Header | 
|  | // IPv6 with zero TOS and flow label. | 
|  | 0x60, 0x00, 0x00, 0x00, | 
|  | // Payload is 64 bytes | 
|  | 0x00, 0x40, | 
|  | // Next header is 58 | 
|  | 0x3a, | 
|  | // Hop limit is 255 | 
|  | 0xFF, | 
|  | // Source address of fe80:1:2:3:4::1 | 
|  | 0xfe, 0x80, 0x00, 0x01, 0x00, 0x02, 0x00, 0x03, | 
|  | 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, | 
|  | // Destination address of fe80:4:3:2:1::1 | 
|  | 0xfe, 0x80, 0x00, 0x04, 0x00, 0x03, 0x00, 0x02, | 
|  | 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, | 
|  | // END IPv6 Header | 
|  | // START ICMPv6 Header | 
|  | // Echo Request, zero code | 
|  | 0x80, 0x00, | 
|  | // Checksum | 
|  | 0xec, 0x00, | 
|  | // Identifier | 
|  | 0xcb, 0x82, | 
|  | // Sequence Number | 
|  | 0x00, 0x01, | 
|  | // END ICMPv6 Header | 
|  | // Message body | 
|  | 0xd2, 0x61, 0x29, 0x5b, 0x00, 0x00, 0x00, 0x00, | 
|  | 0x0d, 0x59, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, | 
|  | 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, | 
|  | 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, | 
|  | 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, | 
|  | 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, | 
|  | 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37 | 
|  | }; | 
|  | // clang-format on | 
|  |  | 
|  | }  // namespace | 
|  |  | 
|  | TEST(IcmpPacketTest, CreatedPacketMatchesReference) { | 
|  | QuicIpAddress src; | 
|  | ASSERT_TRUE(src.FromString(kReferenceSourceAddress)); | 
|  | in6_addr src_addr; | 
|  | memcpy(src_addr.s6_addr, src.ToPackedString().data(), sizeof(in6_addr)); | 
|  |  | 
|  | QuicIpAddress dst; | 
|  | ASSERT_TRUE(dst.FromString(kReferenceDestinationAddress)); | 
|  | in6_addr dst_addr; | 
|  | memcpy(dst_addr.s6_addr, dst.ToPackedString().data(), sizeof(in6_addr)); | 
|  |  | 
|  | icmp6_hdr icmp_header{}; | 
|  | icmp_header.icmp6_type = ICMP6_ECHO_REQUEST; | 
|  | icmp_header.icmp6_id = 0x82cb; | 
|  | icmp_header.icmp6_seq = 0x0100; | 
|  |  | 
|  | absl::string_view message_body = absl::string_view( | 
|  | reinterpret_cast<const char*>(kReferenceICMPMessageBody), 56); | 
|  | absl::string_view expected_packet = absl::string_view( | 
|  | reinterpret_cast<const char*>(kReferenceICMPPacket), 104); | 
|  | CreateIcmpPacket(src_addr, dst_addr, icmp_header, message_body, | 
|  | [&expected_packet](absl::string_view packet) { | 
|  | QUIC_LOG(INFO) << quiche::QuicheTextUtils::HexDump(packet); | 
|  | ASSERT_EQ(packet, expected_packet); | 
|  | }); | 
|  | } | 
|  |  | 
|  | TEST(IcmpPacketTest, NonZeroChecksumIsIgnored) { | 
|  | QuicIpAddress src; | 
|  | ASSERT_TRUE(src.FromString(kReferenceSourceAddress)); | 
|  | in6_addr src_addr; | 
|  | memcpy(src_addr.s6_addr, src.ToPackedString().data(), sizeof(in6_addr)); | 
|  |  | 
|  | QuicIpAddress dst; | 
|  | ASSERT_TRUE(dst.FromString(kReferenceDestinationAddress)); | 
|  | in6_addr dst_addr; | 
|  | memcpy(dst_addr.s6_addr, dst.ToPackedString().data(), sizeof(in6_addr)); | 
|  |  | 
|  | icmp6_hdr icmp_header{}; | 
|  | icmp_header.icmp6_type = ICMP6_ECHO_REQUEST; | 
|  | icmp_header.icmp6_id = 0x82cb; | 
|  | icmp_header.icmp6_seq = 0x0100; | 
|  | // Set the checksum to a bogus value | 
|  | icmp_header.icmp6_cksum = 0x1234; | 
|  |  | 
|  | absl::string_view message_body = absl::string_view( | 
|  | reinterpret_cast<const char*>(kReferenceICMPMessageBody), 56); | 
|  | absl::string_view expected_packet = absl::string_view( | 
|  | reinterpret_cast<const char*>(kReferenceICMPPacket), 104); | 
|  | CreateIcmpPacket(src_addr, dst_addr, icmp_header, message_body, | 
|  | [&expected_packet](absl::string_view packet) { | 
|  | QUIC_LOG(INFO) << quiche::QuicheTextUtils::HexDump(packet); | 
|  | ASSERT_EQ(packet, expected_packet); | 
|  | }); | 
|  | } | 
|  |  | 
|  | }  // namespace quic |