| 1 | /**************************************************************************
|
|---|
| 2 | * Copyright (C) 2004-2007 by Michael Medin <michael@medin.name> *
|
|---|
| 3 | * *
|
|---|
| 4 | * This code is part of NSClient++ - http://trac.nakednuns.org/nscp *
|
|---|
| 5 | * *
|
|---|
| 6 | * This program is free software; you can redistribute it and/or modify *
|
|---|
| 7 | * it under the terms of the GNU General Public License as published by *
|
|---|
| 8 | * the Free Software Foundation; either version 2 of the License, or *
|
|---|
| 9 | * (at your option) any later version. *
|
|---|
| 10 | * *
|
|---|
| 11 | * This program is distributed in the hope that it will be useful, *
|
|---|
| 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
|---|
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
|---|
| 14 | * GNU General Public License for more details. *
|
|---|
| 15 | * *
|
|---|
| 16 | * You should have received a copy of the GNU General Public License *
|
|---|
| 17 | * along with this program; if not, write to the *
|
|---|
| 18 | * Free Software Foundation, Inc., *
|
|---|
| 19 | * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
|---|
| 20 | ***************************************************************************/
|
|---|
| 21 | #pragma once
|
|---|
| 22 |
|
|---|
| 23 | #include <types.hpp>
|
|---|
| 24 | #include <string>
|
|---|
| 25 | #include <unicode_char.hpp>
|
|---|
| 26 | #include <boost/asio/buffer.hpp>
|
|---|
| 27 |
|
|---|
| 28 |
|
|---|
| 29 | namespace nrpe {
|
|---|
| 30 | // this function swap the bytes of values given it's size as a template
|
|---|
| 31 | // parameter (could sizeof be used?).
|
|---|
| 32 | template <class T, unsigned int size>
|
|---|
| 33 | inline T SwapBytes(T value) {
|
|---|
| 34 | union {
|
|---|
| 35 | T value;
|
|---|
| 36 | char bytes[size];
|
|---|
| 37 | } in, out;
|
|---|
| 38 |
|
|---|
| 39 | in.value = value;
|
|---|
| 40 |
|
|---|
| 41 | for (unsigned int i = 0; i < size / 2; ++i) {
|
|---|
| 42 | out.bytes[i] = in.bytes[size - 1 - i];
|
|---|
| 43 | out.bytes[size - 1 - i] = in.bytes[i];
|
|---|
| 44 | }
|
|---|
| 45 |
|
|---|
| 46 | return out.value;
|
|---|
| 47 | }
|
|---|
| 48 |
|
|---|
| 49 | template<EEndian from, EEndian to, class T>
|
|---|
| 50 | inline T EndianSwapBytes(T value) {
|
|---|
| 51 | BOOST_STATIC_ASSERT(sizeof(T) == 2 || sizeof(T) == 4 || sizeof(T) == 8);
|
|---|
| 52 | BOOST_STATIC_ASSERT(boost::is_arithmetic<T>::value);
|
|---|
| 53 | if (from == to)
|
|---|
| 54 | return value;
|
|---|
| 55 | return SwapBytes<T, sizeof(T)>(value);
|
|---|
| 56 | }
|
|---|
| 57 | template<class T>
|
|---|
| 58 | inline T ntoh(T value) {
|
|---|
| 59 | std::cout << "Swaping (in): " << value << " => " << EndianSwapBytes<EEndian::BIG_ENDIAN_ORDER, EEndian::HOST_ENDIAN_ORDER, T>(value) << std::endl;
|
|---|
| 60 | return EndianSwapBytes<EEndian::BIG_ENDIAN_ORDER, EEndian::HOST_ENDIAN_ORDER, T>(value);
|
|---|
| 61 | }
|
|---|
| 62 | template<class T>
|
|---|
| 63 | inline T hton(T value) {
|
|---|
| 64 | std::cout << "Swaping (out): " << value << " => " << EndianSwapBytes<EEndian::HOST_ENDIAN_ORDER, EEndian::BIG_ENDIAN_ORDER, T>(value) << std::endl;
|
|---|
| 65 | return EndianSwapBytes<EEndian::HOST_ENDIAN_ORDER, EEndian::BIG_ENDIAN_ORDER, T>(value);
|
|---|
| 66 | }
|
|---|
| 67 |
|
|---|
| 68 |
|
|---|
| 69 |
|
|---|
| 70 | class data {
|
|---|
| 71 | public:
|
|---|
| 72 | static const short unknownPacket = 0;
|
|---|
| 73 | static const short queryPacket = 1;
|
|---|
| 74 | static const short responsePacket = 2;
|
|---|
| 75 | static const short version2 = 2;
|
|---|
| 76 |
|
|---|
| 77 | typedef struct packet {
|
|---|
| 78 | int16_t packet_version;
|
|---|
| 79 | int16_t packet_type;
|
|---|
| 80 | u_int32_t crc32_value;
|
|---|
| 81 | int16_t result_code;
|
|---|
| 82 | char buffer[];
|
|---|
| 83 | } packet;
|
|---|
| 84 |
|
|---|
| 85 | };
|
|---|
| 86 |
|
|---|
| 87 | class length {
|
|---|
| 88 | typedef unsigned int size_type;
|
|---|
| 89 | static size_type payload_length_;
|
|---|
| 90 | public:
|
|---|
| 91 | static void set_payload_length(size_type length) {
|
|---|
| 92 | payload_length_ = length;
|
|---|
| 93 | }
|
|---|
| 94 | static size_type get_packet_length() {
|
|---|
| 95 | return get_packet_length(payload_length_);
|
|---|
| 96 | }
|
|---|
| 97 | static size_type get_packet_length(size_type payload_length) {
|
|---|
| 98 | std::cout << "get_packet: " << sizeof(nrpe::data::packet) << ":" << payload_length << std::endl;
|
|---|
| 99 | return sizeof(nrpe::data::packet)+payload_length*sizeof(char);
|
|---|
| 100 | }
|
|---|
| 101 | static size_type get_payload_length() {
|
|---|
| 102 | return payload_length_;
|
|---|
| 103 | }
|
|---|
| 104 | static size_type get_payload_length(size_type packet_length) {
|
|---|
| 105 | std::cout << "get_payload: " << sizeof(nrpe::data::packet) << ":" << packet_length << std::endl;
|
|---|
| 106 | return (packet_length-sizeof(nrpe::data::packet))/sizeof(char);
|
|---|
| 107 | }
|
|---|
| 108 | };
|
|---|
| 109 |
|
|---|
| 110 | class nrpe_packet_exception {
|
|---|
| 111 | std::wstring error_;
|
|---|
| 112 | public:
|
|---|
| 113 | nrpe_packet_exception(std::wstring error) : error_(error) {}
|
|---|
| 114 | std::wstring getMessage() {
|
|---|
| 115 | return error_;
|
|---|
| 116 | }
|
|---|
| 117 | };
|
|---|
| 118 |
|
|---|
| 119 | class packet {
|
|---|
| 120 | public:
|
|---|
| 121 |
|
|---|
| 122 |
|
|---|
| 123 | private:
|
|---|
| 124 | std::wstring payload_;
|
|---|
| 125 | short type_;
|
|---|
| 126 | short version_;
|
|---|
| 127 | int result_;
|
|---|
| 128 | unsigned int crc32_;
|
|---|
| 129 | unsigned int calculatedCRC32_;
|
|---|
| 130 | char *tmpBuffer;
|
|---|
| 131 | unsigned int payload_length_;
|
|---|
| 132 | public:
|
|---|
| 133 | packet(unsigned int payload_length) : tmpBuffer(NULL), payload_length_(payload_length) {};
|
|---|
| 134 | packet(std::vector<char> buffer, unsigned int payload_length) : tmpBuffer(NULL), payload_length_(payload_length) {
|
|---|
| 135 | char *tmp = new char[buffer.size()+1];
|
|---|
| 136 | copy( buffer.begin(), buffer.end(), tmp);
|
|---|
| 137 | readFrom(tmp, buffer.size());
|
|---|
| 138 | delete [] tmp;
|
|---|
| 139 | };
|
|---|
| 140 | packet(const char *buffer, unsigned int buffer_length, unsigned int payload_length) : tmpBuffer(NULL), payload_length_(payload_length) {
|
|---|
| 141 | readFrom(buffer, buffer_length);
|
|---|
| 142 | };
|
|---|
| 143 | packet(short type, short version, int result, std::wstring payLoad, unsigned int payload_length)
|
|---|
| 144 | : tmpBuffer(NULL)
|
|---|
| 145 | ,type_(type)
|
|---|
| 146 | ,version_(version)
|
|---|
| 147 | ,result_(result)
|
|---|
| 148 | ,payload_(payLoad)
|
|---|
| 149 | ,payload_length_(payload_length)
|
|---|
| 150 | {
|
|---|
| 151 | }
|
|---|
| 152 | packet()
|
|---|
| 153 | : tmpBuffer(NULL)
|
|---|
| 154 | ,type_(nrpe::data::unknownPacket)
|
|---|
| 155 | ,version_(nrpe::data::version2)
|
|---|
| 156 | ,result_(0)
|
|---|
| 157 | ,payload_length_(nrpe::length::get_payload_length())
|
|---|
| 158 | {
|
|---|
| 159 | }
|
|---|
| 160 | packet(const packet &other) : tmpBuffer(NULL) {
|
|---|
| 161 | payload_ = other.payload_;
|
|---|
| 162 | type_ = other.type_;
|
|---|
| 163 | version_ = other.version_;
|
|---|
| 164 | result_ = other.result_;
|
|---|
| 165 | crc32_ = other.crc32_;
|
|---|
| 166 | calculatedCRC32_ = other.calculatedCRC32_;
|
|---|
| 167 | payload_length_ = other.payload_length_;
|
|---|
| 168 | }
|
|---|
| 169 | packet& operator=(packet const& other) {
|
|---|
| 170 | tmpBuffer=NULL;
|
|---|
| 171 | payload_ = other.payload_;
|
|---|
| 172 | type_ = other.type_;
|
|---|
| 173 | version_ = other.version_;
|
|---|
| 174 | result_ = other.result_;
|
|---|
| 175 | crc32_ = other.crc32_;
|
|---|
| 176 | calculatedCRC32_ = other.calculatedCRC32_;
|
|---|
| 177 | payload_length_ = other.payload_length_;
|
|---|
| 178 | return *this;
|
|---|
| 179 | }
|
|---|
| 180 |
|
|---|
| 181 | ~packet() {
|
|---|
| 182 | delete [] tmpBuffer;
|
|---|
| 183 | }
|
|---|
| 184 | static packet make_request(std::wstring payload, unsigned int buffer_length) {
|
|---|
| 185 | return packet(nrpe::data::queryPacket, nrpe::data::version2, -1, payload, buffer_length);
|
|---|
| 186 | }
|
|---|
| 187 |
|
|---|
| 188 | const char* create_buffer() {
|
|---|
| 189 | delete [] tmpBuffer;
|
|---|
| 190 | unsigned int packet_length = nrpe::length::get_packet_length(payload_length_);
|
|---|
| 191 | tmpBuffer = new char[packet_length+1];
|
|---|
| 192 | //TODO readd this ZeroMemory(tmpBuffer, getBufferLength()+1);
|
|---|
| 193 | nrpe::data::packet *p = reinterpret_cast<nrpe::data::packet*>(tmpBuffer);
|
|---|
| 194 | p->result_code = nrpe::hton<int16_t>(result_);
|
|---|
| 195 | p->packet_type = nrpe::hton<int16_t>(type_);
|
|---|
| 196 | p->packet_version = nrpe::hton<int16_t>(version_);
|
|---|
| 197 | if (payload_.length() >= payload_length_-1)
|
|---|
| 198 | throw nrpe::nrpe_packet_exception(_T("To much data cant create return packet (truncate datat)"));
|
|---|
| 199 | //ZeroMemory(p->buffer, payload_length_-1);
|
|---|
| 200 | strncpy(p->buffer, ::to_string(payload_).c_str(), payload_.length());
|
|---|
| 201 | p->buffer[payload_.length()] = 0;
|
|---|
| 202 | p->crc32_value = 0;
|
|---|
| 203 | p->crc32_value = nrpe::hton<u_int32_t>(calculate_crc32(tmpBuffer, packet_length));
|
|---|
| 204 | std::wcout << _T("About to send: ") << to_string() << std::endl;
|
|---|
| 205 | std::wcout << _T("About to send: ")
|
|---|
| 206 | << _T("") << strEx::ihextos(tmpBuffer[0])
|
|---|
| 207 | << _T(", ") << strEx::ihextos(tmpBuffer[1])
|
|---|
| 208 | << _T(", ") << strEx::ihextos(tmpBuffer[2])
|
|---|
| 209 | << _T(", ") << strEx::ihextos(tmpBuffer[3])
|
|---|
| 210 | << std::endl;
|
|---|
| 211 | return tmpBuffer;
|
|---|
| 212 | }
|
|---|
| 213 |
|
|---|
| 214 | void readFrom(const char *buffer, unsigned int length) {
|
|---|
| 215 | std::wcout << _T("Just read: ")
|
|---|
| 216 | << _T("") << strEx::ihextos(buffer[0])
|
|---|
| 217 | << _T(", ") << strEx::ihextos(buffer[1])
|
|---|
| 218 | << _T(", ") << strEx::ihextos(buffer[2])
|
|---|
| 219 | << _T(", ") << strEx::ihextos(buffer[3])
|
|---|
| 220 | << std::endl;
|
|---|
| 221 | if (buffer == NULL)
|
|---|
| 222 | throw nrpe::nrpe_packet_exception(_T("No buffer."));
|
|---|
| 223 | if (length != get_packet_length())
|
|---|
| 224 | throw nrpe::nrpe_packet_exception(_T("Invalid packet length: ") + strEx::itos(length) + _T(" != ") + strEx::itos(get_packet_length()) + _T(" configured payload is: ") + to_wstring(get_payload_length()));
|
|---|
| 225 | const nrpe::data::packet *p = reinterpret_cast<const nrpe::data::packet*>(buffer);
|
|---|
| 226 | type_ = nrpe::ntoh<int16_t>(p->packet_type);
|
|---|
| 227 | if ((type_ != nrpe::data::queryPacket)&&(type_ != nrpe::data::responsePacket))
|
|---|
| 228 | throw nrpe::nrpe_packet_exception(_T("Invalid packet type: ") + strEx::itos(type_));
|
|---|
| 229 | version_ = nrpe::ntoh<int16_t>(p->packet_version);
|
|---|
| 230 | if (version_ != nrpe::data::version2)
|
|---|
| 231 | throw nrpe::nrpe_packet_exception(_T("Invalid packet version.") + strEx::itos(version_));
|
|---|
| 232 | crc32_ = nrpe::ntoh<u_int32_t>(p->crc32_value);
|
|---|
| 233 | // Verify CRC32
|
|---|
| 234 | // @todo Fix this, currently we need a const buffer so we cannot change the CRC to 0.
|
|---|
| 235 | char * tb = new char[length+1];
|
|---|
| 236 | memcpy(tb, buffer, length);
|
|---|
| 237 | nrpe::data::packet *p2 = reinterpret_cast<nrpe::data::packet*>(tb);
|
|---|
| 238 | p2->crc32_value = 0;
|
|---|
| 239 | calculatedCRC32_ = calculate_crc32(tb, get_packet_length());
|
|---|
| 240 | delete [] tb;
|
|---|
| 241 | std::wcout << _T("Just read: ") << to_string() << std::endl;
|
|---|
| 242 | if (crc32_ != calculatedCRC32_)
|
|---|
| 243 | throw nrpe::nrpe_packet_exception(_T("Invalid checksum in NRPE packet: ") + strEx::ihextos(crc32_)
|
|---|
| 244 | + _T("!=") + strEx::ihextos(calculatedCRC32_));
|
|---|
| 245 | // Verify CRC32 end
|
|---|
| 246 | result_ = nrpe::ntoh<u_int32_t>(p->result_code);
|
|---|
| 247 | payload_ = strEx::string_to_wstring(std::string(p->buffer));
|
|---|
| 248 | }
|
|---|
| 249 |
|
|---|
| 250 | unsigned short getVersion() const { return version_; }
|
|---|
| 251 | unsigned short getType() const { return type_; }
|
|---|
| 252 | unsigned short getResult() const { return result_; }
|
|---|
| 253 | std::wstring getPayload() const { return payload_; }
|
|---|
| 254 | bool verifyCRC() { return calculatedCRC32_ == crc32_; }
|
|---|
| 255 | unsigned int get_packet_length() const { return nrpe::length::get_packet_length(payload_length_); }
|
|---|
| 256 | unsigned int get_payload_length() const { return payload_length_; }
|
|---|
| 257 |
|
|---|
| 258 | boost::asio::const_buffer to_buffers() {
|
|---|
| 259 | return boost::asio::buffer(create_buffer(), get_packet_length());
|
|---|
| 260 | }
|
|---|
| 261 | std::wstring to_string() {
|
|---|
| 262 | std::wstringstream ss;
|
|---|
| 263 | ss << _T("type: ") << type_;
|
|---|
| 264 | ss << _T(", version: ") << version_;
|
|---|
| 265 | ss << _T(", result: ") << result_;
|
|---|
| 266 | ss << _T(", payload: ") << payload_;
|
|---|
| 267 | return ss.str();
|
|---|
| 268 | }
|
|---|
| 269 | static nrpe::packet create_response(int ret, std::wstring string, int buffer_length) {
|
|---|
| 270 | return packet(nrpe::data::responsePacket, nrpe::data::version2, ret, string, buffer_length);
|
|---|
| 271 | }
|
|---|
| 272 | };
|
|---|
| 273 | }
|
|---|
| 274 |
|
|---|