fork download
  1. #include <array>
  2. #include <cassert>
  3. #include <cstdint>
  4. #include <cstring>
  5. #include <iostream>
  6. #include <stdexcept>
  7. #include <type_traits>
  8. #include <vector>
  9. #include <arpa/inet.h>
  10.  
  11.  
  12. // Convert between network and host encoding.
  13. inline uint8_t NetworkToHost(uint8_t inValue) { return inValue; }
  14. inline uint16_t NetworkToHost(uint16_t inValue) { return ntohs(inValue); }
  15. inline uint32_t NetworkToHost(uint32_t inValue) { return ntohl(inValue); }
  16. inline uint8_t HostToNetwork(uint8_t inValue) { return inValue; }
  17. inline uint16_t HostToNetwork(uint16_t inValue) { return htons(inValue); }
  18. inline uint32_t HostToNetwork(uint32_t inValue) { return htonl(inValue); }
  19.  
  20.  
  21. /**
  22.  * @brief The NetEncoded class wraps a network-encoded value.
  23.  * Can be constructed from a host-encoded value using the "NetEncode" factory function.
  24.  * This class meets pod requirements and can be used to represent fields in packet headers.
  25.  */
  26. template<typename T>
  27. class NetEncoded {
  28. public:
  29. NetEncoded() = default;
  30.  
  31. T hostValue() const {
  32. return NetworkToHost(mValue);
  33. }
  34.  
  35. private:
  36. friend NetEncoded<uint16_t> NetEncode(uint16_t);
  37. friend NetEncoded<uint32_t> NetEncode(uint32_t);
  38. friend NetEncoded<uint64_t> NetEncode(uint64_t);
  39.  
  40. NetEncoded(const T & inValue) : mValue(inValue)
  41. {
  42. }
  43.  
  44. friend bool operator<(const NetEncoded & lhs, const NetEncoded & rhs) {
  45. return lhs.mValue < rhs.mValue;
  46. }
  47.  
  48. friend bool operator==(const NetEncoded & lhs, const NetEncoded & rhs) {
  49. return lhs.mValue == rhs.mValue;
  50. }
  51.  
  52. friend bool operator!=(const NetEncoded & lhs, const NetEncoded & rhs) {
  53. return lhs.mValue != rhs.mValue;
  54. }
  55.  
  56. T mValue;
  57. };
  58.  
  59.  
  60. /**
  61.  * @brief Net16 holds a 16-bit network-encoded value.
  62.  */
  63. typedef NetEncoded<uint16_t> Net16;
  64.  
  65.  
  66. /**
  67.  * @brief Net32 holds a 32-bit network-encoded value.
  68.  */
  69. typedef NetEncoded<uint32_t> Net32;
  70.  
  71.  
  72. /**
  73.  * @brief NetEncode overload for creating Net16 from uint16_t
  74.  */
  75. inline Net16 NetEncode(uint16_t value) {
  76. return HostToNetwork(value);
  77. }
  78.  
  79.  
  80. /**
  81.  * @brief NetEncode overload for creating Net32 from uint32_t
  82.  */
  83. inline Net32 NetEncode(uint32_t value) {
  84. return HostToNetwork(value);
  85. }
  86.  
  87.  
  88. /**
  89.  * @brief NetEncode overload for creating Net16 from a 2-byte object.
  90.  * @param An 16-bit object with host-encoding that is explictly convertible to uint16_t.
  91.  */
  92. template<typename T>
  93. inline Net16 NetEncode(T inValue, typename std::enable_if<sizeof (T) == sizeof (uint16_t)>::type * = 0) {
  94. return NetEncode(static_cast<uint16_t> (inValue));
  95. }
  96.  
  97.  
  98. /**
  99.  * @brief NetEncode overload for creating Net32 from a 4-byte object.
  100.  * @param An 32-bit object with host-encoding that is explictly convertible to uint32_t.
  101.  */
  102. template<typename T>
  103. inline Net32 NetEncode(T inValue, typename std::enable_if<sizeof (T) == sizeof (uint32_t)>::type * = 0) {
  104. return NetEncode(static_cast<uint32_t> (inValue));
  105. }
  106.  
  107.  
  108. //
  109. // Usage example
  110. //
  111. enum class IPProtNum : uint8_t
  112. {
  113. ICMP = 1,
  114. TCP = 6,
  115. UDP = 17
  116. };
  117.  
  118. typedef std::array<uint8_t, 4> IPv4Address;
  119.  
  120. struct IPv4Header
  121. {
  122. uint8_t VersionAndIHL; // 0
  123. uint8_t TypeOfService; // 1
  124. Net16 TotalLength; // 2
  125. Net16 Identification; // 4
  126. Net16 FlagsAndFragmentOffset; // 6
  127. uint8_t TTL; // 8
  128. IPProtNum Protocol; // 9
  129. Net16 HeaderChecksum; // 10
  130. IPv4Address SourceAddress; // 12
  131. IPv4Address DestinationAddress; // 16
  132. };
  133.  
  134.  
  135. static_assert(std::is_pod<IPv4Header>::value, "IPv4Header is not a POD type!");
  136. static_assert(sizeof(IPv4Header) == 20, "IPv4header must have size 20.");
  137.  
  138.  
  139. IPv4Header ParseIPv4Packet(const std::vector<uint8_t> & data)
  140. {
  141. IPv4Header hdr;
  142. if (data.size() < sizeof(hdr)) {
  143. throw std::logic_error("Buffer too small");
  144. }
  145. std::memcpy(&hdr, data.data(), sizeof(hdr));
  146. return hdr;
  147. }
  148.  
  149.  
  150. const uint8_t cIPv4Packet[] =
  151. {
  152. 0x45, 0x00, 0x00, 0x54, 0x00, 0x00, 0x40, 0x00, 0x40, 0x01, 0x21, 0xdd, 0x0a, 0x04, 0x01, 0x9e, 0x0a, 0x04, 0x03, 0x27, 0x08, 0x00, 0x2d, 0xa2, 0x59, 0x4e, 0x00, 0x01, 0x68, 0xda, 0xd1, 0x4f, 0x00, 0x00, 0x00, 0x00, 0x6d, 0x11, 0x0b, 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
  153. };
  154.  
  155. int main()
  156. {
  157. std::vector<uint8_t> data(&cIPv4Packet[0], &cIPv4Packet[0] + sizeof(cIPv4Packet));
  158. IPv4Header hdr = ParseIPv4Packet(data);
  159. std::cout << "Length = " << hdr.TotalLength.hostValue();
  160. assert(hdr.TotalLength.hostValue() == sizeof(cIPv4Packet));
  161. }
Success #stdin #stdout 0s 3064KB
stdin
Standard input is empty
stdout
Length = 84