-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathicmp_header.hpp
136 lines (114 loc) · 4.48 KB
/
icmp_header.hpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
//
// icmp_header.hpp
// ~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef ICMP_HEADER_HPP
#define ICMP_HEADER_HPP
#include <istream>
#include <ostream>
#include <algorithm>
namespace pingloop
{
// ICMP header for both IPv4 and IPv6.
//
// The wire format of an ICMP header is:
//
// 0 8 16 31
// +---------------+---------------+------------------------------+ ---
// | | | | ^
// | type | code | checksum | |
// | | | | |
// +---------------+---------------+------------------------------+ 8 bytes
// | | | |
// | identifier | sequence number | |
// | | | v
// +-------------------------------+------------------------------+ ---
class icmp_header
{
public:
enum {
echo_reply = 0, destination_unreachable = 3, source_quench = 4,
redirect = 5, echo_request = 8, time_exceeded = 11, parameter_problem = 12,
timestamp_request = 13, timestamp_reply = 14, info_request = 15,
info_reply = 16, address_request = 17, address_reply = 18
};
icmp_header() { std::fill(rep_, rep_ + sizeof(rep_), 0); }
unsigned char type() const { return rep_[0]; }
unsigned char code() const { return rep_[1]; }
unsigned short checksum() const { return decode(2, 3); }
unsigned short identifier() const { return decode(4, 5); }
unsigned short sequence_number() const { return decode(6, 7); }
void type(unsigned char n) { rep_[0] = n; }
void code(unsigned char n) { rep_[1] = n; }
void checksum(unsigned short n) { encode(2, 3, n); }
void identifier(unsigned short n) { encode(4, 5, n); }
void sequence_number(unsigned short n) { encode(6, 7, n); }
friend std::istream& operator>>(std::istream& is, icmp_header& header)
{
return is.read(reinterpret_cast<char*>(header.rep_), 8);
}
friend std::ostream& operator<<(std::ostream& os, const icmp_header& header)
{
return os.write(reinterpret_cast<const char*>(header.rep_), 8);
}
private:
ushort decode(int a, int b) const
{
return (ushort)((rep_[a] << 8) + rep_[b]);
}
void encode(int a, int b, unsigned short n)
{
rep_[a] = static_cast<unsigned char>(n >> 8);
rep_[b] = static_cast<unsigned char>(n & 0xFF);
}
protected:
unsigned char rep_[8];
};
template <typename Iterator>
void compute_checksum(icmp_header& header, const int file_id, Iterator body_begin, Iterator body_end)
{
unsigned int sum = (header.type() << 8) + header.code() + header.identifier() + header.sequence_number();
Iterator intIterator = (const char*)&file_id;
sum += (static_cast<unsigned char>(*intIterator++) << 8);
sum += static_cast<unsigned char>(*intIterator++);
sum += (static_cast<unsigned char>(*intIterator++) << 8);
sum += static_cast<unsigned char>(*intIterator++);
Iterator body_iter = body_begin;
while (body_iter != body_end)
{
sum += (static_cast<unsigned char>(*body_iter++) << 8);
if (body_iter != body_end)
sum += static_cast<unsigned char>(*body_iter++);
}
sum = (sum >> 16) + (sum & 0xFFFF);
sum += (sum >> 16);
header.checksum(static_cast<unsigned short>(~sum));
}
class icmp_echo_header : public icmp_header
{
public:
icmp_echo_header(int file_id, ushort id, ushort sequence_number, const char* data, ushort length)
{
this->type(icmp_header::echo_request);
this->code(0);
this->identifier(id);
this->sequence_number(sequence_number);
// Compute checksum, including header and data
compute_checksum(*this, file_id, data, data + length);
}
friend std::istream& operator>>(std::istream& is, icmp_echo_header& header)
{
return is.read(reinterpret_cast<char*>(header.rep_), 8);
}
friend std::ostream& operator<<(std::ostream& os, const icmp_echo_header& header)
{
return os.write(reinterpret_cast<const char*>(header.rep_), 8);
}
};
}
#endif // ICMP_HEADER_HPP