]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | // |
2 | // icmp_header.hpp | |
3 | // ~~~~~~~~~~~~~~~ | |
4 | // | |
b32b8144 | 5 | // Copyright (c) 2003-2017 Christopher M. Kohlhoff (chris at kohlhoff dot com) |
7c673cae FG |
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 | ||
41 | icmp_header() { std::fill(rep_, rep_ + sizeof(rep_), 0); } | |
42 | ||
43 | unsigned char type() const { return rep_[0]; } | |
44 | unsigned char code() const { return rep_[1]; } | |
45 | unsigned short checksum() const { return decode(2, 3); } | |
46 | unsigned short identifier() const { return decode(4, 5); } | |
47 | unsigned short sequence_number() const { return decode(6, 7); } | |
48 | ||
49 | void type(unsigned char n) { rep_[0] = n; } | |
50 | void code(unsigned char n) { rep_[1] = n; } | |
51 | void checksum(unsigned short n) { encode(2, 3, n); } | |
52 | void identifier(unsigned short n) { encode(4, 5, n); } | |
53 | void sequence_number(unsigned short n) { encode(6, 7, n); } | |
54 | ||
55 | friend std::istream& operator>>(std::istream& is, icmp_header& header) | |
56 | { return is.read(reinterpret_cast<char*>(header.rep_), 8); } | |
57 | ||
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: | |
62 | unsigned short decode(int a, int b) const | |
63 | { return (rep_[a] << 8) + rep_[b]; } | |
64 | ||
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> | |
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 |