/* * BLT Memory Util for parsing DNS packets. * This software is unlikely to become part of BLT main but is provided under the BLT license (GPL 3). * Copyright (C) 2023 Brett Terpstra * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef INSANE_DNS_UTIL_H #define INSANE_DNS_UTIL_H #include namespace blt { /** * Basic parser for processing strings of bytes received from UDP sockets. This class provides a simple interface for efficiently copying the * big endian bytes from the network into the little endian bytes required by x86 processors. The class also provides basic safety guarantees * in that the program will halt execution if reading the bytes would overflow the internal buffer. */ class byte_reader { private: unsigned char* _data; const size_t _size; mutable size_t _current_byte = DNS_HEADER_END; public: explicit byte_reader(unsigned char* data, size_t size): _data(data), _size(size) {} /** * Read the next byte in the data stream then increment the internal counter by 1 * @return the next byte in the array */ inline unsigned char& next() const { BLT_ASSERT(_current_byte < _size); return _data[_current_byte++]; } /** * Reads data into the provided template parameter, reordering the byte into the correct little endian format * @tparam T type to read (deduction is automatic) * @param t variable reference to read into */ template inline void to(T& t) const { BLT_ASSERT(_current_byte + sizeof(T) <= _size); // I hate little endian. I hate dealing with converting between endianness // it is very easy to do it very slowly // So I made BLT provide a simple interface to convert between bytes dependent on the platform // for small integral types (16, 32, and 64) it will compile to 3 instructions using compiler intrinsics. // Larger POD types are supported but will use std::reverse and therefore be slow. blt::mem::fromBytes(&_data[_current_byte], t); skip(sizeof(T)); } /** * Copy from the internal data buffer, advancing the internal stream, into the provided unsigned char array. *No reordering is done* * @param out character array to write to * @param size number of bytes to copy */ inline void copy(unsigned char*& out, size_t size) const { BLT_ASSERT(_current_byte + size < _size); std::memcpy(out, &_data[_current_byte], size); skip(size); } /** * Skip bytes in the data stream, useful for skipping sections of the DNS packet we may not care about. * @param s number of bytes to skip. */ inline void skip(size_t s = 1) const { _current_byte += s; } /** * @return 1 past the last byte we wrote to, otherwise known as the next byte we will be writing to. */ inline size_t last() const { return _current_byte; } /** * @return a pointer to a location in the internal buffer starting at last() */ inline unsigned char* from() { BLT_ASSERT(_current_byte < _size); return &_data[_current_byte]; } }; } #endif //INSANE_DNS_UTIL_H