1 //
2 // icmp_header.hpp
3 // ~~~~~~~~~~~~~~~
4 //
5 // Copyright (c) 2003-2021 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
11 #ifndef ICMP_HEADER_HPP
12 #define ICMP_HEADER_HPP
13
14 #include <istream>
15 #include <ostream>
16 #include <algorithm>
17
18 // ICMP header for both IPv4 and IPv6.
19 //
20 // The wire format of an ICMP header is:
21 //
22 // 0 8 16 31
23 // +---------------+---------------+------------------------------+ ---
24 // | | | | ^
25 // | type | code | checksum | |
26 // | | | | |
27 // +---------------+---------------+------------------------------+ 8 bytes
28 // | | | |
29 // | identifier | sequence number | |
30 // | | | v
31 // +-------------------------------+------------------------------+ ---
32
33 class icmp_header
34 {
35 public:
36 enum { echo_reply = 0, destination_unreachable = 3, source_quench = 4,
37 redirect = 5, echo_request = 8, time_exceeded = 11, parameter_problem = 12,
38 timestamp_request = 13, timestamp_reply = 14, info_request = 15,
39 info_reply = 16, address_request = 17, address_reply = 18 };
40
icmp_header()41 icmp_header() { std::fill(rep_, rep_ + sizeof(rep_), 0); }
42
type() const43 unsigned char type() const { return rep_[0]; }
code() const44 unsigned char code() const { return rep_[1]; }
checksum() const45 unsigned short checksum() const { return decode(2, 3); }
identifier() const46 unsigned short identifier() const { return decode(4, 5); }
sequence_number() const47 unsigned short sequence_number() const { return decode(6, 7); }
48
type(unsigned char n)49 void type(unsigned char n) { rep_[0] = n; }
code(unsigned char n)50 void code(unsigned char n) { rep_[1] = n; }
checksum(unsigned short n)51 void checksum(unsigned short n) { encode(2, 3, n); }
identifier(unsigned short n)52 void identifier(unsigned short n) { encode(4, 5, n); }
sequence_number(unsigned short n)53 void sequence_number(unsigned short n) { encode(6, 7, n); }
54
operator >>(std::istream & is,icmp_header & header)55 friend std::istream& operator>>(std::istream& is, icmp_header& header)
56 { return is.read(reinterpret_cast<char*>(header.rep_), 8); }
57
operator <<(std::ostream & os,const icmp_header & header)58 friend std::ostream& operator<<(std::ostream& os, const icmp_header& header)
59 { return os.write(reinterpret_cast<const char*>(header.rep_), 8); }
60
61 private:
decode(int a,int b) const62 unsigned short decode(int a, int b) const
63 { return (rep_[a] << 8) + rep_[b]; }
64
encode(int a,int b,unsigned short n)65 void encode(int a, int b, unsigned short n)
66 {
67 rep_[a] = static_cast<unsigned char>(n >> 8);
68 rep_[b] = static_cast<unsigned char>(n & 0xFF);
69 }
70
71 unsigned char rep_[8];
72 };
73
74 template <typename Iterator>
compute_checksum(icmp_header & header,Iterator body_begin,Iterator body_end)75 void compute_checksum(icmp_header& header,
76 Iterator body_begin, Iterator body_end)
77 {
78 unsigned int sum = (header.type() << 8) + header.code()
79 + header.identifier() + header.sequence_number();
80
81 Iterator body_iter = body_begin;
82 while (body_iter != body_end)
83 {
84 sum += (static_cast<unsigned char>(*body_iter++) << 8);
85 if (body_iter != body_end)
86 sum += static_cast<unsigned char>(*body_iter++);
87 }
88
89 sum = (sum >> 16) + (sum & 0xFFFF);
90 sum += (sum >> 16);
91 header.checksum(static_cast<unsigned short>(~sum));
92 }
93
94 #endif // ICMP_HEADER_HPP
95