/ src / noderequest.cpp
noderequest.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 "noderequest.hpp"
  6  #include <iostream>
  7  
  8  using namespace crazytrace;
  9  
 10  crazytrace::NodeRequest::NodeRequest(const Tins::EthernetII& packet) :
 11      _type(NodeRequestType::UNKNOWN),
 12      _hoplimit(0),
 13      _udp_dport(0),
 14      _udp_sport(0),
 15      _icmp_identifier(0),
 16      _icmp_sequence(0)
 17  {
 18      this->_source_mac = packet.src_addr();
 19      this->_destination_mac = packet.dst_addr();
 20  
 21      if (packet.find_pdu<Tins::IPv6>() != nullptr)
 22      {
 23          const Tins::IPv6& ipv6 = packet.rfind_pdu<Tins::IPv6>();
 24  
 25          this->_source_address = ipv6.src_addr();
 26          this->_destination_address = ipv6.dst_addr();
 27          this->_hoplimit = ipv6.hop_limit();
 28  
 29          switch (ipv6.next_header())
 30          {
 31              case Tins::Constants::IP::PROTO_ICMPV6:
 32              {
 33                  const Tins::ICMPv6& icmpv6 = ipv6.rfind_pdu<Tins::ICMPv6>();
 34                  switch (icmpv6.type())
 35                  {
 36                      case Tins::ICMPv6::Types::NEIGHBOUR_SOLICIT:
 37                          this->_type = NodeRequestType::ICMP_NDP;
 38                          if (!icmpv6.has_target_addr())
 39                              throw std::runtime_error(
 40                                  "ICMP NDP packet has no target address "
 41                                  "attribute.");
 42  
 43                          this->_destination_address = icmpv6.target_addr();
 44                          break;
 45                      case Tins::ICMPv6::Types::ECHO_REQUEST:
 46                      {
 47                          this->_type = NodeRequestType::ICMP_ECHO_REQUEST;
 48                          this->_icmp_identifier = icmpv6.identifier();
 49                          this->_icmp_sequence = icmpv6.sequence();
 50                          const Tins::RawPDU& raw_icmpv6 =
 51                              icmpv6.rfind_pdu<Tins::RawPDU>();
 52                          this->_payload = raw_icmpv6.payload();
 53                          break;
 54                      }
 55                      default:
 56                          /* Not supported */
 57                          break;
 58                  }
 59                  break;
 60              }
 61              case Tins::Constants::IP::PROTO_UDP:
 62              {
 63                  const Tins::UDP& udp = packet.rfind_pdu<Tins::UDP>();
 64                  const Tins::RawPDU& raw_udp = udp.rfind_pdu<Tins::RawPDU>();
 65                  this->_type = NodeRequestType::UDP;
 66                  this->_udp_dport = udp.dport();
 67                  this->_udp_sport = udp.sport();
 68                  this->_payload = raw_udp.payload();
 69                  break;
 70              }
 71              default:
 72                  /* Not supported */
 73                  break;
 74          }
 75      }
 76  }
 77  
 78  NodeRequestType crazytrace::NodeRequest::get_type() const noexcept
 79  {
 80      return this->_type;
 81  }
 82  
 83  const Tins::HWAddress<6>&
 84      crazytrace::NodeRequest::get_source_mac() const noexcept
 85  {
 86      return this->_source_mac;
 87  }
 88  
 89  const Tins::HWAddress<6>&
 90      crazytrace::NodeRequest::get_destination_mac() const noexcept
 91  {
 92      return this->_destination_mac;
 93  }
 94  
 95  const Tins::IPv6Address&
 96      crazytrace::NodeRequest::get_source_address() const noexcept
 97  {
 98      return this->_source_address;
 99  }
100  
101  const Tins::IPv6Address&
102      crazytrace::NodeRequest::get_destination_address() const noexcept
103  {
104      return this->_destination_address;
105  }
106  
107  uint8_t crazytrace::NodeRequest::get_hoplimit() const noexcept
108  {
109      return this->_hoplimit;
110  }
111  
112  uint16_t crazytrace::NodeRequest::get_udp_sport() const noexcept
113  {
114      return this->_udp_sport;
115  }
116  
117  uint16_t crazytrace::NodeRequest::get_udp_dport() const noexcept
118  {
119      return this->_udp_dport;
120  }
121  
122  uint16_t crazytrace::NodeRequest::get_icmp_identifier() const noexcept
123  {
124      return this->_icmp_identifier;
125  }
126  
127  uint16_t crazytrace::NodeRequest::get_icmp_sequence() const noexcept
128  {
129      return this->_icmp_sequence;
130  }
131  
132  const Tins::RawPDU::payload_type&
133      crazytrace::NodeRequest::get_payload() const noexcept
134  {
135      return this->_payload;
136  }
137  
138  std::ostream& crazytrace::operator<<(std::ostream& os,
139                                       NodeRequest const & noderequest)
140  {
141      std::string type_string;
142      switch (noderequest._type)
143      {
144          case NodeRequestType::ICMP_ECHO_REQUEST:
145              type_string = "ICMP_ECHO_REQUEST";
146              break;
147          case NodeRequestType::ICMP_NDP:
148              type_string = "ICMP_NDP";
149              break;
150          case NodeRequestType::UDP:
151              type_string = "UDP";
152              break;
153          default:
154              type_string = "UNKNOWN";
155              break;
156      }
157      os << "REQUEST " << type_string << ": " << noderequest._source_address
158         << " (" << noderequest._source_mac << ") -> "
159         << noderequest._destination_address << " ("
160         << noderequest._destination_mac << ") "
161         << "Hoplimit=" << static_cast<unsigned>(noderequest._hoplimit);
162  
163      switch (noderequest._type)
164      {
165          case NodeRequestType::ICMP_ECHO_REQUEST:
166          {
167              os << ": ID=" << noderequest._icmp_identifier
168                 << " SEQ=" << noderequest._icmp_sequence << " Payload:";
169              for (const auto& byte : noderequest._payload)
170              {
171                  os << std::format(" {:02x}", static_cast<int>(byte));
172              }
173              break;
174          }
175          case NodeRequestType::ICMP_NDP:
176              os << ": Looking for " << noderequest._destination_address;
177              break;
178          case NodeRequestType::UDP:
179              os << ": DPORT=" << noderequest._udp_dport
180                 << " SPORT=" << noderequest._udp_sport
181                 << " LENGTH=" << noderequest._payload.size();
182              break;
183          default:
184              break;
185      }
186  
187      return os;
188  }