/ tests / noderequest_test.cpp
noderequest_test.cpp
  1  // SPDX-FileCopyrightText: Copyright (C) 2024-2025 Marek Küthe <m.k@mk16.de>
  2  //
  3  // SPDX-License-Identifier: GPL-3.0-or-later
  4  
  5  #include <gtest/gtest.h>
  6  #include <limits>
  7  #include <tins/tins.h>
  8  #include "noderequest.hpp"
  9  
 10  using namespace crazytrace;
 11  
 12  TEST(NodeRequestTest, EchoRequest)
 13  {
 14      const Tins::HWAddress<6> source_mac("52:54:00:b2:fa:7f");
 15      const Tins::HWAddress<6> destination_mac("52:54:00:b2:fa:7e");
 16      const Tins::IPv6Address source_address("fd00::1");
 17      const Tins::IPv6Address destination_address("fd00::2");
 18      constexpr int hoplimit = 55;
 19      constexpr int icmp_identifier = 56;
 20      constexpr int icmp_sequence = 1;
 21      const Tins::RawPDU::payload_type payload = {8, 4, 5, 9, 255, 0, 0, 0, 0, 0};
 22  
 23      Tins::EthernetII packet = Tins::EthernetII(destination_mac, source_mac) /
 24                                Tins::IPv6(destination_address, source_address) /
 25                                Tins::ICMPv6(Tins::ICMPv6::Types::ECHO_REQUEST);
 26      Tins::IPv6& inner_ipv6 = packet.rfind_pdu<Tins::IPv6>();
 27      inner_ipv6.hop_limit(hoplimit);
 28      Tins::ICMPv6& inner_icmpv6 = inner_ipv6.rfind_pdu<Tins::ICMPv6>();
 29      inner_icmpv6.identifier(icmp_identifier);
 30      inner_icmpv6.sequence(icmp_sequence);
 31      inner_icmpv6.inner_pdu(Tins::RawPDU(payload));
 32  
 33      /* Serializing the package is necessary to automatically calculate checksums
 34       * and other fields. */
 35      const Tins::PDU::serialization_type serialized_packet = packet.serialize();
 36      ASSERT_LE(serialized_packet.size(), std::numeric_limits<uint32_t>::max());
 37      const Tins::EthernetII final_packet(
 38          serialized_packet.data(),
 39          static_cast<uint32_t>(serialized_packet.size()));
 40  
 41      const NodeRequest request(final_packet);
 42  
 43      EXPECT_EQ(request.get_type(), NodeRequestType::ICMP_ECHO_REQUEST);
 44      EXPECT_EQ(request.get_source_mac(), source_mac);
 45      EXPECT_EQ(request.get_destination_mac(), destination_mac);
 46      EXPECT_EQ(request.get_source_address(), source_address);
 47      EXPECT_EQ(request.get_destination_address(), destination_address);
 48      EXPECT_EQ(request.get_hoplimit(), hoplimit);
 49      EXPECT_EQ(request.get_udp_sport(), 0);
 50      EXPECT_EQ(request.get_udp_dport(), 0);
 51      EXPECT_EQ(request.get_icmp_identifier(), icmp_identifier);
 52      EXPECT_EQ(request.get_icmp_sequence(), icmp_sequence);
 53      EXPECT_EQ(request.get_payload(), payload);
 54  
 55      std::ostringstream test_output;
 56      test_output << request;
 57      EXPECT_EQ(test_output.str(),
 58                "REQUEST ICMP_ECHO_REQUEST: fd00::1 (52:54:00:b2:fa:7f) -> "
 59                "fd00::2 (52:54:00:b2:fa:7e) Hoplimit=55: ID=56 SEQ=1 Payload: "
 60                "08 04 05 09 ff 00 00 00 00 00");
 61  }
 62  
 63  TEST(NodeRequestTest, NdpRequest)
 64  {
 65      const Tins::HWAddress<6> source_mac("52:54:00:b2:fa:7f");
 66      const Tins::HWAddress<6> destination_mac("33:33:ff:48:b2:ae");
 67      const Tins::IPv6Address source_address("fd00::1");
 68      const Tins::IPv6Address destination_address("ff02::1:ff48:b2ae");
 69      const Tins::IPv6Address target_address("fd00::2");
 70      constexpr int hoplimit = 2;
 71  
 72      Tins::EthernetII packet =
 73          Tins::EthernetII(destination_mac, source_mac) /
 74          Tins::IPv6(destination_address, source_address) /
 75          Tins::ICMPv6(Tins::ICMPv6::Types::NEIGHBOUR_SOLICIT);
 76      Tins::IPv6& inner_ipv6 = packet.rfind_pdu<Tins::IPv6>();
 77      inner_ipv6.hop_limit(hoplimit);
 78      Tins::ICMPv6& inner_icmpv6 = inner_ipv6.rfind_pdu<Tins::ICMPv6>();
 79      inner_icmpv6.target_addr(target_address);
 80  
 81      /* Serializing the package is necessary to automatically calculate checksums
 82       * and other fields. */
 83      const Tins::PDU::serialization_type serialized_packet = packet.serialize();
 84      ASSERT_LE(serialized_packet.size(), std::numeric_limits<uint32_t>::max());
 85      const Tins::EthernetII final_packet(
 86          serialized_packet.data(),
 87          static_cast<uint32_t>(serialized_packet.size()));
 88  
 89      const NodeRequest request(final_packet);
 90  
 91      EXPECT_EQ(request.get_type(), NodeRequestType::ICMP_NDP);
 92      EXPECT_EQ(request.get_source_mac(), source_mac);
 93      EXPECT_EQ(request.get_destination_mac(), destination_mac);
 94      EXPECT_EQ(request.get_source_address(), source_address);
 95      EXPECT_EQ(request.get_destination_address(), target_address);
 96      EXPECT_EQ(request.get_hoplimit(), hoplimit);
 97      EXPECT_EQ(request.get_udp_sport(), 0);
 98      EXPECT_EQ(request.get_udp_dport(), 0);
 99      EXPECT_EQ(request.get_icmp_identifier(), 0);
100      EXPECT_EQ(request.get_icmp_sequence(), 0);
101      EXPECT_TRUE(request.get_payload().empty());
102  
103      std::ostringstream test_output;
104      test_output << request;
105      EXPECT_EQ(test_output.str(),
106                "REQUEST ICMP_NDP: fd00::1 (52:54:00:b2:fa:7f) -> fd00::2 "
107                "(33:33:ff:48:b2:ae) Hoplimit=2: Looking for fd00::2");
108  }
109  
110  TEST(NodeRequestTest, UdpRequest)
111  {
112      const Tins::HWAddress<6> source_mac("52:54:00:b2:fa:7f");
113      const Tins::HWAddress<6> destination_mac("52:54:00:b2:fa:7e");
114      const Tins::IPv6Address source_address("fd00::1");
115      const Tins::IPv6Address destination_address("fd00::2");
116      constexpr int hoplimit = 55;
117      constexpr int udp_sport = 54739;
118      constexpr int udp_dport = 33434;
119      const Tins::RawPDU::payload_type payload = {8, 4, 5, 9, 255, 0, 0, 0, 0, 0};
120  
121      Tins::EthernetII packet = Tins::EthernetII(destination_mac, source_mac) /
122                                Tins::IPv6(destination_address, source_address) /
123                                Tins::UDP(udp_dport, udp_sport);
124      Tins::IPv6& inner_ipv6 = packet.rfind_pdu<Tins::IPv6>();
125      inner_ipv6.hop_limit(hoplimit);
126      Tins::UDP& inner_udp = inner_ipv6.rfind_pdu<Tins::UDP>();
127      inner_udp.inner_pdu(Tins::RawPDU(payload));
128  
129      /* Serializing the package is necessary to automatically calculate checksums
130       * and other fields. */
131      const Tins::PDU::serialization_type serialized_packet = packet.serialize();
132      ASSERT_LE(serialized_packet.size(), std::numeric_limits<uint32_t>::max());
133      const Tins::EthernetII final_packet(
134          serialized_packet.data(),
135          static_cast<uint32_t>(serialized_packet.size()));
136  
137      const NodeRequest request(final_packet);
138  
139      EXPECT_EQ(request.get_type(), NodeRequestType::UDP);
140      EXPECT_EQ(request.get_source_mac(), source_mac);
141      EXPECT_EQ(request.get_destination_mac(), destination_mac);
142      EXPECT_EQ(request.get_source_address(), source_address);
143      EXPECT_EQ(request.get_destination_address(), destination_address);
144      EXPECT_EQ(request.get_hoplimit(), hoplimit);
145      EXPECT_EQ(request.get_udp_sport(), udp_sport);
146      EXPECT_EQ(request.get_udp_dport(), udp_dport);
147      EXPECT_EQ(request.get_icmp_identifier(), 0);
148      EXPECT_EQ(request.get_icmp_sequence(), 0);
149      EXPECT_EQ(request.get_payload(), payload);
150  
151      std::ostringstream test_output;
152      test_output << request;
153      EXPECT_EQ(
154          test_output.str(),
155          "REQUEST UDP: fd00::1 (52:54:00:b2:fa:7f) -> fd00::2 "
156          "(52:54:00:b2:fa:7e) Hoplimit=55: DPORT=33434 SPORT=54739 LENGTH=10");
157  }
158  
159  TEST(NodeRequestTest, UnknownRequest)
160  {
161      const Tins::HWAddress<6> source_mac("52:54:00:b2:fa:7f");
162      const Tins::HWAddress<6> destination_mac("52:54:00:b2:fa:7e");
163      const Tins::IPv6Address source_address("fd00::1");
164      const Tins::IPv6Address destination_address("fd00::2");
165      constexpr int hoplimit = 2;
166  
167      Tins::EthernetII packet =
168          Tins::EthernetII(destination_mac, source_mac) /
169          Tins::IPv6(destination_address, source_address) /
170          Tins::ICMPv6(Tins::ICMPv6::Types::NEIGHBOUR_ADVERT);
171      Tins::IPv6& inner_ipv6 = packet.rfind_pdu<Tins::IPv6>();
172      inner_ipv6.hop_limit(hoplimit);
173  
174      /* Serializing the package is necessary to automatically calculate checksums
175       * and other fields. */
176      const Tins::PDU::serialization_type serialized_packet = packet.serialize();
177      ASSERT_LE(serialized_packet.size(), std::numeric_limits<uint32_t>::max());
178      const Tins::EthernetII final_packet(
179          serialized_packet.data(),
180          static_cast<uint32_t>(serialized_packet.size()));
181  
182      const NodeRequest request(final_packet);
183  
184      EXPECT_EQ(request.get_type(), NodeRequestType::UNKNOWN);
185      EXPECT_EQ(request.get_source_mac(), source_mac);
186      EXPECT_EQ(request.get_destination_mac(), destination_mac);
187      EXPECT_EQ(request.get_source_address(), source_address);
188      EXPECT_EQ(request.get_destination_address(), destination_address);
189      EXPECT_EQ(request.get_hoplimit(), hoplimit);
190      EXPECT_EQ(request.get_udp_sport(), 0);
191      EXPECT_EQ(request.get_udp_dport(), 0);
192      EXPECT_EQ(request.get_icmp_identifier(), 0);
193      EXPECT_EQ(request.get_icmp_sequence(), 0);
194      EXPECT_TRUE(request.get_payload().empty());
195  
196      std::ostringstream test_output;
197      test_output << request;
198      EXPECT_EQ(test_output.str(),
199                "REQUEST UNKNOWN: fd00::1 (52:54:00:b2:fa:7f) -> fd00::2 "
200                "(52:54:00:b2:fa:7e) Hoplimit=2");
201  }