Program Listing for File packet.hh¶
↰ Return to documentation for file (pcap/packet.hh)
// SPDX-License-Identifier: LGPL-3.0-or-later
/* pcap/packet.hh - libnokogiri pcap packets */
#if !defined(LIBNOKOGIRI_PCAP_PACKET_HH)
#define LIBNOKOGIRI_PCAP_PACKET_HH
#include <cstdint>
#include <optional>
#include <variant>
#include <vector>
#include <array>
#include <string_view>
#include <libnokogiri/config.hh>
#include <libnokogiri/common.hh>
#include <libnokogiri/internal/defs.hh>
namespace libnokogiri::pcap {
using libnokogiri::internal::enum_pair_t;
enum struct packet_type_t : uint8_t {
Standard = 0x00,
Modified = 0x01,
};
const std::array<const enum_pair_t<packet_type_t>, 2> packet_type_s{{
{ packet_type_t::Standard, "Standard"sv },
{ packet_type_t::Modified, "Modified"sv }
}};
struct packet_header_t final {
private:
std::uint32_t _timestamp;
std::uint32_t _usecs;
std::uint32_t _have;
std::uint32_t _was;
public:
constexpr packet_header_t() noexcept :
_timestamp{0U}, _usecs{0U}, _have{0U}, _was{0U}
{ /* NOP */ }
constexpr packet_header_t(std::uint32_t timestamp, std::uint32_t useconds,
std::uint32_t pkt_len_have, std::uint32_t pkt_len_actual) noexcept :
_timestamp{timestamp}, _usecs{useconds}, _have{pkt_len_have}, _was{pkt_len_actual}
{ /* NOP */ }
packet_header_t(const packet_header_t&) = delete;
packet_header_t& operator=(const packet_header_t&) = delete;
packet_header_t(packet_header_t&&) = default;
packet_header_t& operator=(packet_header_t&&) = default;
[[nodiscard]]
std::uint32_t timestamp() const noexcept { return _timestamp; }
void timestamp(const std::uint32_t timestamp) noexcept { _timestamp = timestamp; }
[[nodiscard]]
std::uint32_t useconds() const noexcept { return _usecs; }
void useconds(const std::uint32_t useconds) noexcept { _usecs = useconds; }
[[nodiscard]]
std::uint32_t captured_len() const noexcept { return _have; }
void captured_len(const std::uint32_t captured_len) noexcept { _have = captured_len; }
[[nodiscard]]
std::uint32_t actual_len() const noexcept { return _was; }
void actual_len(const std::uint32_t actual_len) noexcept { _was = actual_len; }
[[nodiscard]]
bool full_packet() const noexcept { return _was == _have; }
};
struct packet_header_modified_t final {
private:
packet_header_t _base_header;
std::uint32_t _if_index;
std::uint16_t _proto;
std::uint8_t _type;
std::uint8_t _padding;
public:
constexpr packet_header_modified_t() noexcept :
_base_header{}, _if_index{0U}, _proto{0U}, _type{0U}, _padding{0U}
{ /* NOP */ }
constexpr packet_header_modified_t(packet_header_t&& base_header, std::uint32_t if_index,
std::uint16_t protocol, std::uint8_t type) noexcept :
_base_header{std::move(base_header)}, _if_index{if_index}, _proto{protocol}, _type{type},
_padding{0U} { /* NOP */ }
packet_header_modified_t(std::nullptr_t) noexcept { /* NOP */ }
packet_header_modified_t(const packet_header_modified_t&) = delete;
packet_header_modified_t& operator=(const packet_header_modified_t&) = delete;
packet_header_modified_t(packet_header_modified_t&&) = default;
packet_header_modified_t& operator=(packet_header_modified_t&&) = default;
[[nodiscard]]
const packet_header_t& base_header() const noexcept { return _base_header; }
void base_header(packet_header_t&& base_header) noexcept { _base_header = std::move(base_header); }
[[nodiscard]]
std::uint32_t interface_index() const noexcept { return _if_index; }
void interface_index(std::uint32_t interface_index) noexcept { _if_index = interface_index; }
[[nodiscard]]
std::uint16_t protocol() const noexcept { return _proto; }
void protocol(std::uint16_t protocol) noexcept { _proto = protocol; }
[[nodiscard]]
std::uint8_t type() const noexcept { return _type; }
void type(std::uint8_t type) noexcept { _type = type; }
};
// /*! \struct libnokogiri::pcap::packet_t
// \brief pcap packet template
// This template provides the framework for reading and writing packets.
// They can have custom headers, but the two standardized packets are already
// specified as libnokogiri::pcap::generic_packet_t and libnokogiri::pcap::modified_packet_t .
// All this template does is change out the packet header type, the rest of the logic is identical.
// */
// template<typename T, typename U>
// struct packet_t final {
// public:
// using data_t = std::optional<std::unique_ptr<U>>;
// private:
// T _packet_header;
// std::uintptr_t _offset;
// data_t _data;
// public:
// constexpr packet_t() noexcept :
// _packet_header{}, _offset{0U}, _data{std::nullopt}
// { /* NOP */ }
// constexpr packet_t(T header, std::uintptr_t offset, data_t data) noexcept :
// _packet_header{header}, _offset{offset}, _data{data}
// { /* NOP */ }
// /*! Retrieve the packet header */
// [[nodiscard]]
// T header() const noexcept { return _packet_header; }
// /*! Set the packet header */
// void header(T header) noexcept { _packet_header = header; }
// /*! Retrieve the offset in the file the packet is located at */
// [[nodiscard]]
// std::uintptr_t packet_offset() const noexcept { return _offset; }
// /*! Set the offset in the file the packet is located at */
// void packet_offset(std::uintptr_t packet_offset) noexcept { _offset = packet_offset; }
// /*! Retrieve the packet data */
// [[nodiscard]]
// data_t packet_data() const noexcept { return _data; }
// /*! Set the packet data */
// void packet_data(data_t packet_data) noexcept { _data = packet_data; }
// };
// /*! Type alias for generic conforming pcap packets with the standard header */
// template<typename T>
// using generic_packet_t = packet_t<packet_header_t, T>;
// /*! Type alias for packets from the modified pcap files */
// template<typename T>
// using modified_packet_t = packet_t<packet_header_modified_t, T>;
struct packet_t {
public:
using pkt_header_t = std::variant<
std::monostate,
packet_header_t,
packet_header_modified_t
>;
private:
std::vector<std::uint8_t> _raw_data;
pkt_header_t _packet_header;
template<typename T>
[[nodiscard]]
std::enable_if_t<
std::is_pod_v<T> &&
!libnokogiri::internal::has_nullable_ctor_v<T> &&
!std::is_same_v<T, void*>,
T*>
index(const std::size_t offset) {
if (offset < _raw_data.size()) {
return new (reinterpret_cast<std::uint8_t *>(_raw_data.data()) + (offset * sizeof(T))) T{};
}
return nullptr;
}
template<typename T>
[[nodiscard]]
std::enable_if_t<
libnokogiri::internal::has_nullable_ctor_v<T> &&
!std::is_same_v<T, void*>,
T*>
index(const std::size_t offset) {
if (offset < _raw_data.size()) {
return new (reinterpret_cast<std::uint8_t *>(_raw_data.data()) + (offset * sizeof(T))) T{nullptr};
}
return nullptr;
}
template<typename T>
[[nodiscard]]
std::enable_if_t<std::is_same_v<T, void*>, void*>
index(const std::size_t offset) {
if (offset < _raw_data.size()) {
return reinterpret_cast<std::uint8_t *>(_raw_data.data()) + offset;
}
return nullptr;
}
public:
packet_t(std::size_t length, pkt_header_t header = {}) noexcept :
_raw_data{std::vector<std::uint8_t>(length)},
_packet_header{std::move(header)} { /* NOP */ }
packet_t(const packet_t&) = delete;
packet_t& operator=(const packet_t&) = delete;
packet_t(packet_t&&) = default;
packet_t& operator=(packet_t&&) = default;
[[nodiscard]]
std::size_t length() const noexcept { return _raw_data.size(); }
[[nodiscard]]
pkt_header_t& header() noexcept { return _packet_header; }
[[nodiscard]]
bool is_complete() const noexcept {
return std::visit([](auto& header) -> bool {
using T = std::decay_t<decltype(header)>;
if constexpr (std::is_same_v<T, packet_header_modified_t>) {
return header.base_header().full_packet();
} else if constexpr (std::is_same_v<T, packet_header_t>) {
return header.full_packet();
} else {
return false;
}
}, _packet_header);
}
template<typename T>
[[nodiscard]]
T& as() { *index<T>(); }
template<typename T>
[[nodiscard]]
T *operator [](const off_t idx) { return index<T>(idx); }
[[nodiscard]]
auto begin() noexcept { return _raw_data.begin(); }
[[nodiscard]]
auto end() noexcept { return _raw_data.end(); }
template<typename T>
[[nodiscard]]
const T *operator [](const off_t idx) const { return index<const T>(idx); }
template<typename T>
[[nodiscard]]
T *at(const off_t idx) { return index<T>(idx); }
template<typename T>
[[nodiscard]]
const T *at(const off_t idx) const { return index<const T>(idx); }
void *address(const off_t offset) noexcept { return index<void *>(offset); }
};
struct packet_storage_t final {
private:
std::uint32_t _len;
std::uintptr_t _offset;
packet_t _packet_cache;
public:
packet_storage_t() noexcept :
_len{0U}, _offset{0U}, _packet_cache{0}
{ /* NOP */ }
packet_storage_t(std::uint32_t len, std::uintptr_t offset) noexcept :
_len{len}, _offset{offset}, _packet_cache{0}
{ /* NOP */ }
packet_storage_t(std::uint32_t len, std::uintptr_t offset, packet_t&& packet) noexcept :
_len{len}, _offset{offset}, _packet_cache{std::move(packet)}
{ /* NOP */ }
packet_storage_t(const packet_storage_t&) = delete;
packet_storage_t& operator=(const packet_storage_t&) = delete;
packet_storage_t(packet_storage_t&&) = default;
packet_storage_t& operator=(packet_storage_t&&) = default;
[[nodiscard]]
std::uint32_t length() const noexcept { return _len; }
[[nodiscard]]
std::uintptr_t offset() const noexcept { return _offset; }
[[nodiscard]]
packet_t& get_packet() noexcept { return _packet_cache; }
void set_packet(packet_t&& pkt) noexcept { _packet_cache = std::move(pkt); }
};
}
#endif /* LIBNOKOGIRI_PCAP_PACKET_HH */