blob: 86505fe05ba8cbca591a59b043ef565a3a52bc9b [file] [log] [blame]
// Copyright 2018 The Chromium OS 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 "portier/ipv6_util.h"
#include <arpa/inet.h>
#include <netinet/icmp6.h>
#include <gtest/gtest.h>
#include <shill/net/byte_string.h>
#include <shill/net/ip_address.h>
namespace portier {
using shill::IPAddress;
using shill::ByteString;
using Code = Status::Code;
// Test data.
namespace {
// Checksum test data.
// The zero packet.
const IPAddress kSourceAddress1 = IPAddress("::");
const IPAddress kDestinationAddress1 = IPAddress("::");
constexpr uint8_t kNextHeader1 = 0;
constexpr uint8_t kData1[] = {};
constexpr uint16_t kExpectedChecksum1 = 0;
// A more realistic zero packet.
const IPAddress kSourceAddress2 = IPAddress("::");
const IPAddress kDestinationAddress2 =
IPAddress("ff02::1"); // All node link-local multicast.
constexpr uint8_t kNextHeader2 = 59; // No next header. (0x3b)
constexpr uint8_t kData2[] = {};
constexpr uint16_t kExpectedChecksum2 = 0xff3e;
// All 1s (where valid) pseudo-header packet.
const IPAddress kSourceAddress3 =
IPAddress("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff");
const IPAddress kDestinationAddress3 =
IPAddress("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff");
constexpr uint8_t kNextHeader3 = 0xff; // No next header. (0x3b)
constexpr uint8_t kData3[] = {};
constexpr uint16_t kExpectedChecksum3 = 0x00ff;
// ICMPv6 Echo Request
const IPAddress kSourceAddress4 =
IPAddress("2401:fa00:480:56:c1dd:402b:cc2f:7209");
const IPAddress kDestinationAddress4 = IPAddress("fe80::aef2:c5ff:fe71:17bf");
constexpr uint8_t kNextHeader4 = 58; // ICMPv6.
// clang-format off
constexpr uint8_t kData4[] = {
// Type=Echo Request (128), Code=0, Checksum=0.
0x80, 0x00, 0x00, 0x00,
// Id=1337, Sequence=9001.
0x05, 0x39, 0x23, 0x29,
// Data.
0x11, 0x22, 0x33, 0x44,
0x55, 0x66, 0x77, 0x88
};
// clang-format on
constexpr uint16_t kExpectedChecksum4 = 0xa6c0;
// Odd byte length packet.
const IPAddress kSourceAddress5 = IPAddress("fe80::1");
const IPAddress kDestinationAddress5 = IPAddress("ff02::1");
constexpr uint8_t kNextHeader5 = 58;
constexpr uint8_t kData5[] = {0x11, 0x22, 0x33};
constexpr uint16_t kExpectedChecksum5 = 0x41e5;
// IP type test data.
const IPAddress kUnspecifiedAddress = IPAddress("::");
const IPAddress kLocalHostAddress = IPAddress("::1");
const IPAddress kLinkLocalAddress1 = IPAddress("fe80::3c20:87b0:b0ce:23f4");
const IPAddress kLinkLocalAddress2 = IPAddress("fe80::f155:a038:ae18:faf2");
const IPAddress kLinkLocalAddress3 = IPAddress("fe80::5a6d:8fff:fe99:e5be");
const IPAddress kNonLinkLocalAddress1 =
IPAddress("2620:15c:202:201:f155:a038:ae18:faf2");
const IPAddress kNonLinkLocalAddress2 =
IPAddress("2401:fa00:480:56:5a6d:8fff:fe99:e5be");
// Well-known multicast addresses.
const IPAddress kAllNodesLinkLocalMulticastAddress = IPAddress("ff02::1");
const IPAddress kAllRoutersLinkLocalMulticastAddress = IPAddress("ff02::2");
const IPAddress kAllRoutersSiteLocalMulticastAddress = IPAddress("ff05::2");
const LLAddress kAllNodesLinkLocalMulticastLLAddress =
LLAddress(LLAddress::Type::kEui48, "33:33:00:00:00:01");
const LLAddress kAllRouterLinkLocalMulticastLLAddress =
LLAddress(LLAddress::Type::kEui48, "33:33:00:00:00:02");
const LLAddress kAllRouterSiteLocalMulticastLLAddress =
LLAddress(LLAddress::Type::kEui48, "33:33:00:00:00:02");
// Addresses which are "close" to being multicast address, missing only
// a few bits.
const IPAddress kNonMulticastAddress1 = IPAddress("fe05::1");
const IPAddress kNonMulticastAddress2 = IPAddress("7f05::2");
const IPAddress kNonMulticastAddress3 = IPAddress("ee05::3");
const IPAddress kSolicitedNodeMulticast1 =
IPAddress("ff02:0:0:0:0:1:ff18:faf2");
const IPAddress kSolicitedNodeMulticast2 =
IPAddress("ff02:0:0:0:0:1:ff99:e5be");
const IPAddress kNotSolicitedNodeMulticast1 =
IPAddress("ff02:0:0:0:0:0:ff18:faf2");
const IPAddress kNotSolicitedNodeMulticast2 =
IPAddress("ff02:0:0:0:0:0:ff99:e5be");
const IPAddress kSolicitedAddress1 =
IPAddress("2620:15c:202:201:f155:a038:ae18:faf2");
const IPAddress kSolicitedAddress2 =
IPAddress("2401:fa00:480:56:5a6d:8fff:fe99:e5be");
const LLAddress kSolicitedNodeMulticastLL1 =
LLAddress(LLAddress::Type::kEui48, "33:33:ff:18:fa:f2");
const LLAddress kSolicitedNodeMulticastLL2 =
LLAddress(LLAddress::Type::kEui48, "33:33:ff:99:e5:be");
} // namespace
// Test using valid input.
TEST(IPv6UpperLayerChecksum16Test, ZeroPacket) {
uint16_t checksum = 0;
const Status status =
IPv6UpperLayerChecksum16(kSourceAddress1, kDestinationAddress1,
kNextHeader1, kData1, 0, &checksum);
EXPECT_TRUE(status);
EXPECT_EQ(ntohs(checksum), kExpectedChecksum1);
}
TEST(IPv6UpperLayerChecksum16Test, RealisticZeroPacket) {
uint16_t checksum = 0;
const Status status =
IPv6UpperLayerChecksum16(kSourceAddress2, kDestinationAddress2,
kNextHeader2, kData2, 0, &checksum);
EXPECT_TRUE(status);
EXPECT_EQ(ntohs(checksum), kExpectedChecksum2);
}
TEST(IPv6UpperLayerChecksum16Test, AllOnesPacket) {
uint16_t checksum = 0;
const Status status =
IPv6UpperLayerChecksum16(kSourceAddress3, kDestinationAddress3,
kNextHeader3, kData3, 0, &checksum);
EXPECT_TRUE(status);
EXPECT_EQ(ntohs(checksum), kExpectedChecksum3);
}
TEST(IPv6UpperLayerChecksum16Test, EchoRequestPacket) {
uint16_t checksum = 0;
const Status status =
IPv6UpperLayerChecksum16(kSourceAddress4, kDestinationAddress4,
kNextHeader4, kData4, sizeof(kData4), &checksum);
EXPECT_TRUE(status);
EXPECT_EQ(ntohs(checksum), kExpectedChecksum4);
}
TEST(IPv6UpperLayerChecksum16Test, OddByteLength) {
uint16_t checksum = 0;
const Status status =
IPv6UpperLayerChecksum16(kSourceAddress5, kDestinationAddress5,
kNextHeader5, kData5, sizeof(kData5), &checksum);
EXPECT_TRUE(status);
EXPECT_EQ(ntohs(checksum), kExpectedChecksum5);
}
TEST(IPv6UpperLayerChecksum16Test, ChecksumProcess) {
// Create generic ICMPv6 header.
struct icmp6_hdr icmp6_hdr;
memset(&icmp6_hdr, 0, sizeof(icmp6_hdr));
icmp6_hdr.icmp6_type = ICMP6_DST_UNREACH;
icmp6_hdr.icmp6_data32[0] = 0x12345678;
// Calculate the checksum.
uint16_t checksum = 0;
Status status = IPv6UpperLayerChecksum16(
kSourceAddress5, kDestinationAddress5, kNextHeader5,
reinterpret_cast<const uint8_t*>(&icmp6_hdr), sizeof(icmp6_hdr),
&checksum);
EXPECT_TRUE(status);
// Provide the checksum to the ICMP header.
icmp6_hdr.icmp6_cksum = ~checksum;
// Recalculate.
status = IPv6UpperLayerChecksum16(
kSourceAddress5, kDestinationAddress5, kNextHeader5,
reinterpret_cast<const uint8_t*>(&icmp6_hdr), sizeof(icmp6_hdr),
&checksum);
EXPECT_TRUE(status);
EXPECT_EQ(checksum, 0);
}
TEST(IPv6AddressTypeTest, UnspecifiedAddress) {
EXPECT_TRUE(IPv6AddressIsUnspecified(kUnspecifiedAddress));
}
TEST(IPv6AddressTypeTest, NotUnspecifiedAddress) {
EXPECT_FALSE(IPv6AddressIsUnspecified(kLocalHostAddress));
EXPECT_FALSE(IPv6AddressIsUnspecified(kLinkLocalAddress1));
EXPECT_FALSE(IPv6AddressIsUnspecified(kLinkLocalAddress2));
EXPECT_FALSE(IPv6AddressIsUnspecified(kLinkLocalAddress3));
EXPECT_FALSE(IPv6AddressIsUnspecified(kNonLinkLocalAddress1));
EXPECT_FALSE(IPv6AddressIsUnspecified(kNonLinkLocalAddress2));
}
TEST(IPv6AddressTypeTest, LinkLocalAddress) {
EXPECT_TRUE(IPv6AddressIsLinkLocal(kLinkLocalAddress1));
EXPECT_TRUE(IPv6AddressIsLinkLocal(kLinkLocalAddress2));
EXPECT_TRUE(IPv6AddressIsLinkLocal(kLinkLocalAddress3));
}
TEST(IPv6AddressTypeTest, NotLinkLocalAddress) {
EXPECT_FALSE(IPv6AddressIsLinkLocal(kNonLinkLocalAddress1));
EXPECT_FALSE(IPv6AddressIsLinkLocal(kNonLinkLocalAddress2));
EXPECT_FALSE(IPv6AddressIsLinkLocal(kUnspecifiedAddress));
EXPECT_FALSE(IPv6AddressIsLinkLocal(kLocalHostAddress));
}
TEST(IPv6AddressTypeTest, MulticastAddress) {
EXPECT_TRUE(IPv6AddressIsMulticast(kAllNodesLinkLocalMulticastAddress));
EXPECT_TRUE(IPv6AddressIsMulticast(kAllRoutersLinkLocalMulticastAddress));
EXPECT_TRUE(IPv6AddressIsMulticast(kAllRoutersSiteLocalMulticastAddress));
EXPECT_TRUE(IPv6AddressIsMulticast(kSolicitedNodeMulticast1));
EXPECT_TRUE(IPv6AddressIsMulticast(kSolicitedNodeMulticast2));
EXPECT_TRUE(IPv6AddressIsMulticast(kNotSolicitedNodeMulticast1));
EXPECT_TRUE(IPv6AddressIsMulticast(kNotSolicitedNodeMulticast2));
}
TEST(IPv6AddressTypeTest, NotMulticastAddress) {
EXPECT_FALSE(IPv6AddressIsMulticast(kUnspecifiedAddress));
EXPECT_FALSE(IPv6AddressIsMulticast(kLocalHostAddress));
EXPECT_FALSE(IPv6AddressIsMulticast(kLinkLocalAddress1));
EXPECT_FALSE(IPv6AddressIsMulticast(kLinkLocalAddress2));
EXPECT_FALSE(IPv6AddressIsMulticast(kLinkLocalAddress3));
EXPECT_FALSE(IPv6AddressIsMulticast(kNonMulticastAddress1));
EXPECT_FALSE(IPv6AddressIsMulticast(kNonMulticastAddress2));
EXPECT_FALSE(IPv6AddressIsMulticast(kNonMulticastAddress3));
}
TEST(IPv6AddressTypeTest, SolicitedNode) {
EXPECT_TRUE(IPv6AddressIsSolicitedNodeMulticast(kSolicitedNodeMulticast1,
kSolicitedAddress1));
EXPECT_TRUE(IPv6AddressIsSolicitedNodeMulticast(kSolicitedNodeMulticast2,
kSolicitedAddress2));
}
TEST(IPv6AddressTypeTest, NotSolicitedNode) {
// Mixed multicast and solicited.
EXPECT_FALSE(IPv6AddressIsSolicitedNodeMulticast(kSolicitedAddress1,
kSolicitedNodeMulticast1));
EXPECT_FALSE(IPv6AddressIsSolicitedNodeMulticast(kSolicitedAddress2,
kSolicitedNodeMulticast2));
// Not a solicitation of provided address.
EXPECT_FALSE(IPv6AddressIsSolicitedNodeMulticast(kSolicitedNodeMulticast1,
kSolicitedAddress2));
EXPECT_FALSE(IPv6AddressIsSolicitedNodeMulticast(kSolicitedNodeMulticast2,
kSolicitedAddress1));
// Not a solicited-node address, but bottom 24-bits match.
EXPECT_FALSE(IPv6AddressIsSolicitedNodeMulticast(kNotSolicitedNodeMulticast1,
kSolicitedAddress1));
EXPECT_FALSE(IPv6AddressIsSolicitedNodeMulticast(kNotSolicitedNodeMulticast2,
kSolicitedAddress2));
}
TEST(IPv6AddressToLinkLayerTest, MulticastLinkLayer) {
LLAddress ll_address;
EXPECT_TRUE(IPv6GetMulticastLinkLayerAddress(
kAllNodesLinkLocalMulticastAddress, &ll_address));
EXPECT_TRUE(kAllNodesLinkLocalMulticastLLAddress.Equals(ll_address));
EXPECT_TRUE(IPv6GetMulticastLinkLayerAddress(
kAllRoutersLinkLocalMulticastAddress, &ll_address));
EXPECT_TRUE(kAllRouterLinkLocalMulticastLLAddress.Equals(ll_address));
EXPECT_TRUE(IPv6GetMulticastLinkLayerAddress(
kAllRoutersSiteLocalMulticastAddress, &ll_address));
EXPECT_TRUE(kAllRouterSiteLocalMulticastLLAddress.Equals(ll_address));
EXPECT_TRUE(
IPv6GetMulticastLinkLayerAddress(kSolicitedNodeMulticast1, &ll_address));
EXPECT_TRUE(kSolicitedNodeMulticastLL1.Equals(ll_address));
EXPECT_TRUE(
IPv6GetMulticastLinkLayerAddress(kSolicitedNodeMulticast2, &ll_address));
EXPECT_TRUE(kSolicitedNodeMulticastLL2.Equals(ll_address));
}
} // namespace portier