95 lines
3.3 KiB
C++
95 lines
3.3 KiB
C++
//
|
|
// icmp_header.hpp
|
|
// ~~~~~~~~~~~~~~~
|
|
//
|
|
// Copyright (c) 2003-2019 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>
|
|
|
|
// 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:
|
|
unsigned short decode(int a, int b) const
|
|
{ return (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);
|
|
}
|
|
|
|
unsigned char rep_[8];
|
|
};
|
|
|
|
template <typename Iterator>
|
|
void compute_checksum(icmp_header& header,
|
|
Iterator body_begin, Iterator body_end)
|
|
{
|
|
unsigned int sum = (header.type() << 8) + header.code()
|
|
+ header.identifier() + header.sequence_number();
|
|
|
|
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));
|
|
}
|
|
|
|
#endif // ICMP_HEADER_HPP
|