icmp_header.hpp 3.3 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394
  1. //
  2. // icmp_header.hpp
  3. // ~~~~~~~~~~~~~~~
  4. //
  5. // Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
  6. //
  7. // Distributed under the Boost Software License, Version 1.0. (See accompanying
  8. // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  9. //
  10. #ifndef ICMP_HEADER_HPP
  11. #define ICMP_HEADER_HPP
  12. #include <istream>
  13. #include <ostream>
  14. #include <algorithm>
  15. // ICMP header for both IPv4 and IPv6.
  16. //
  17. // The wire format of an ICMP header is:
  18. //
  19. // 0 8 16 31
  20. // +---------------+---------------+------------------------------+ ---
  21. // | | | | ^
  22. // | type | code | checksum | |
  23. // | | | | |
  24. // +---------------+---------------+------------------------------+ 8 bytes
  25. // | | | |
  26. // | identifier | sequence number | |
  27. // | | | v
  28. // +-------------------------------+------------------------------+ ---
  29. class icmp_header
  30. {
  31. public:
  32. enum { echo_reply = 0, destination_unreachable = 3, source_quench = 4,
  33. redirect = 5, echo_request = 8, time_exceeded = 11, parameter_problem = 12,
  34. timestamp_request = 13, timestamp_reply = 14, info_request = 15,
  35. info_reply = 16, address_request = 17, address_reply = 18 };
  36. icmp_header() { std::fill(rep_, rep_ + sizeof(rep_), 0); }
  37. unsigned char type() const { return rep_[0]; }
  38. unsigned char code() const { return rep_[1]; }
  39. unsigned short checksum() const { return decode(2, 3); }
  40. unsigned short identifier() const { return decode(4, 5); }
  41. unsigned short sequence_number() const { return decode(6, 7); }
  42. void type(unsigned char n) { rep_[0] = n; }
  43. void code(unsigned char n) { rep_[1] = n; }
  44. void checksum(unsigned short n) { encode(2, 3, n); }
  45. void identifier(unsigned short n) { encode(4, 5, n); }
  46. void sequence_number(unsigned short n) { encode(6, 7, n); }
  47. friend std::istream& operator>>(std::istream& is, icmp_header& header)
  48. { return is.read(reinterpret_cast<char*>(header.rep_), 8); }
  49. friend std::ostream& operator<<(std::ostream& os, const icmp_header& header)
  50. { return os.write(reinterpret_cast<const char*>(header.rep_), 8); }
  51. private:
  52. unsigned short decode(int a, int b) const
  53. { return (rep_[a] << 8) + rep_[b]; }
  54. void encode(int a, int b, unsigned short n)
  55. {
  56. rep_[a] = static_cast<unsigned char>(n >> 8);
  57. rep_[b] = static_cast<unsigned char>(n & 0xFF);
  58. }
  59. unsigned char rep_[8];
  60. };
  61. template <typename Iterator>
  62. void compute_checksum(icmp_header& header,
  63. Iterator body_begin, Iterator body_end)
  64. {
  65. unsigned int sum = (header.type() << 8) + header.code()
  66. + header.identifier() + header.sequence_number();
  67. Iterator body_iter = body_begin;
  68. while (body_iter != body_end)
  69. {
  70. sum += (static_cast<unsigned char>(*body_iter++) << 8);
  71. if (body_iter != body_end)
  72. sum += static_cast<unsigned char>(*body_iter++);
  73. }
  74. sum = (sum >> 16) + (sum & 0xFFFF);
  75. sum += (sum >> 16);
  76. header.checksum(static_cast<unsigned short>(~sum));
  77. }
  78. #endif // ICMP_HEADER_HPP