VBVX 0.1.0
Header-only C++23 library for safe, zero-copy parsing of packet buffers.
Loading...
Searching...
No Matches
buffer_view.hxx
Go to the documentation of this file.
1#pragma once
2
3#include <concepts>
4#include <optional>
5#include <span>
6#include <utility>
7#include <cstring>
8
9#include "header_view.hxx"
10
11#include "arp.hxx"
12#include "ether.hxx"
13#include "icmp4.hxx"
14#include "icmp6.hxx"
15#include "ip_protocol.hxx"
16#include "ip4_header.hxx"
17#include "ip6_header.hxx"
18#include "srv6_header.hxx"
19#include "tcp_header.hxx"
20#include "udp_header.hxx"
21
22namespace vbvx {
23
29 using buffer_t = uint8_t;
30
31public:
32 constexpr BufferView(const void* data, uint16_t length) noexcept
33 : data_{static_cast<const buffer_t*>(data)}, length_{length} {}
34
36 constexpr auto data() const noexcept -> std::span<const buffer_t> {
37 if (!data_) {
38 return {};
39 }
40 return {data_, length_};
41 }
42
44 constexpr auto length() const noexcept -> uint16_t { return length_; }
45
47 constexpr auto ether_header() const noexcept -> HeaderView<EtherHeader> {
48 return header_at<EtherHeader>(0);
49 }
50
52 constexpr auto ether_type() const noexcept -> std::optional<EtherType> {
53 auto eth = ether_header();
54 if (!eth) {
55 return std::nullopt;
56 }
57
58 auto type = eth->type();
59 if (type == std::to_underlying(EtherType::VLAN)) {
60 auto vlan = vlan_header();
61 if (!vlan) {
62 return std::nullopt;
63 }
64 return static_cast<EtherType>(vlan->type());
65 }
66
67 return static_cast<EtherType>(type);
68 }
69
71 constexpr auto vlan_header() const noexcept -> HeaderView<VlanHeader> {
72 auto eth = ether_header();
73 if (!eth) {
74 return {};
75 }
76
77 auto type = eth->type();
78 if (type != std::to_underlying(EtherType::VLAN)) {
79 return {};
80 }
81
82 return header_at<VlanHeader>(sizeof(EtherHeader));
83 }
84
86 constexpr auto vlan_id() const noexcept -> std::optional<uint16_t> {
87 auto vlan = vlan_header();
88 if (!vlan) {
89 return std::nullopt;
90 }
91 return static_cast<uint16_t>(vlan->tci() & 0x0FFFu);
92 }
93
95 constexpr auto l3_offset() const noexcept -> uint16_t {
96 auto eth = ether_header();
97 if (!eth) {
98 return 0;
99 }
100 auto type = eth->type();
101 return (type == std::to_underlying(EtherType::VLAN))
102 ? static_cast<uint16_t>(sizeof(EtherHeader) + sizeof(VlanHeader))
103 : static_cast<uint16_t>(sizeof(EtherHeader));
104 }
105
107 constexpr auto arp_header() const noexcept -> HeaderView<ArpHeader> {
108 auto et = ether_type();
109 if (!et || *et != EtherType::ARP) {
110 return {};
111 }
112 return header_at<ArpHeader>(l3_offset());
113 }
114
116 constexpr auto ip4_header() const noexcept -> HeaderView<IPv4Header> {
117 auto et = ether_type();
118 if (!et || *et != EtherType::IPv4) {
119 return {};
120 }
121 return header_at<IPv4Header>(l3_offset());
122 }
123
125 constexpr auto ip6_header() const noexcept -> HeaderView<IPv6Header> {
126 auto et = ether_type();
127 if (!et || *et != EtherType::IPv6) {
128 return {};
129 }
130 return header_at<IPv6Header>(l3_offset());
131 }
132
134 constexpr auto ip4_ihl_bytes() const noexcept -> std::optional<uint8_t> {
135 auto ip = ip4_header();
136 if (!ip) {
137 return std::nullopt;
138 }
139 const buffer_t ihl = static_cast<uint8_t>(ip->version_ihl & 0x0Fu);
140 const buffer_t bytes = static_cast<uint8_t>(ihl * 4u);
141 if (bytes < 20) {
142 return std::nullopt;
143 }
144 return bytes;
145 }
146
148 constexpr auto ip_protocol() const noexcept -> std::optional<IpProtocol> {
149 if (auto ip4 = ip4_header()) {
150 return static_cast<IpProtocol>(ip4->protocol);
151 }
152 if (auto ip6 = ip6_header()) {
153 return static_cast<IpProtocol>(ip6->next_header);
154 }
155 return std::nullopt;
156 }
157
159 constexpr auto l4_offset() const noexcept -> std::optional<uint16_t> {
160 if (ip4_header()) {
161 auto ihl = ip4_ihl_bytes();
162 if (!ihl) {
163 return std::nullopt;
164 }
165 return l3_offset() + *ihl;
166 }
167 if (ip6_header()) {
168 return l3_offset() + static_cast<uint16_t>(sizeof(IPv6Header));
169 }
170 return std::nullopt;
171 }
172
174 constexpr auto tcp_header() const noexcept -> HeaderView<TCPHeader> {
175 auto proto = ip_protocol();
176 auto off = l4_offset();
177 if (!proto || !off) {
178 return {};
179 }
180 if (*proto != IpProtocol::TCP) {
181 return {};
182 }
183 return header_at<TCPHeader>(*off);
184 }
185
187 constexpr auto udp_header() const noexcept -> HeaderView<UDPHeader> {
188 auto proto = ip_protocol();
189 auto off = l4_offset();
190 if (!proto || !off) {
191 return {};
192 }
193 if (*proto != IpProtocol::UDP) {
194 return {};
195 }
196 return header_at<UDPHeader>(*off);
197 }
198
200 constexpr auto icmp4_header() const noexcept -> HeaderView<ICMPv4Header> {
201 auto proto = ip_protocol();
202 auto off = l4_offset();
203 if (!proto || !off || *proto != IpProtocol::ICMPv4) {
204 return {};
205 }
206
207 return header_at<ICMPv4Header>(*off);
208 }
209
211 constexpr auto icmp6_header() const noexcept -> HeaderView<ICMPv6Header> {
212 auto proto = ip_protocol();
213 auto off = l4_offset();
214 if (!proto || !off || *proto != IpProtocol::ICMPv6) {
215 return {};
216 }
217
218 return header_at<ICMPv6Header>(*off);
219 }
220
222 constexpr auto srv6_header() const noexcept -> HeaderView<SRv6Header> {
223 auto ip6 = ip6_header();
224 if (!ip6) {
225 return {};
226 }
227 if (ip6->next_header != static_cast<uint8_t>(IpProtocol::IPv6_Route)) {
228 return {};
229 }
230
231 auto offset = static_cast<uint16_t>(l3_offset() + sizeof(IPv6Header));
232 return header_at<SRv6Header>(offset);
233 }
234
235private:
236 template <WireHeader H>
237 constexpr auto header_at(uint16_t offset) const noexcept -> HeaderView<H> {
238 auto _data = data();
239 if (offset + sizeof(H) > _data.size()) {
240 return {};
241 }
242 return HeaderView<H>{_data.data() + offset};
243 }
244
245 const buffer_t* data_{};
246 uint16_t length_{};
247};
248
249} // namespace vbvx
constexpr auto ip4_ihl_bytes() const noexcept -> std::optional< uint8_t >
Get the number of bytes in the IPv4 header.
Definition buffer_view.hxx:134
constexpr auto l4_offset() const noexcept -> std::optional< uint16_t >
Get the offset of the Layer 4 header.
Definition buffer_view.hxx:159
constexpr auto ip_protocol() const noexcept -> std::optional< IpProtocol >
Get the IP protocol (IPv4 or IPv6).
Definition buffer_view.hxx:148
constexpr auto length() const noexcept -> uint16_t
Get the length of the buffer.
Definition buffer_view.hxx:44
constexpr auto ether_header() const noexcept -> HeaderView< EtherHeader >
Get Ethernet header view.
Definition buffer_view.hxx:47
constexpr auto arp_header() const noexcept -> HeaderView< ArpHeader >
Get ARP header view.
Definition buffer_view.hxx:107
constexpr auto tcp_header() const noexcept -> HeaderView< TCPHeader >
Get TCP header view.
Definition buffer_view.hxx:174
constexpr auto vlan_header() const noexcept -> HeaderView< VlanHeader >
Get VLAN header view.
Definition buffer_view.hxx:71
constexpr auto ether_type() const noexcept -> std::optional< EtherType >
Get the EtherType of the packet for possible VLAN tag.
Definition buffer_view.hxx:52
constexpr auto srv6_header() const noexcept -> HeaderView< SRv6Header >
Get SRv6 Header view if present.
Definition buffer_view.hxx:222
constexpr auto icmp6_header() const noexcept -> HeaderView< ICMPv6Header >
Get ICMPv6 header view.
Definition buffer_view.hxx:211
constexpr auto icmp4_header() const noexcept -> HeaderView< ICMPv4Header >
Get ICMPv4 header view.
Definition buffer_view.hxx:200
constexpr auto ip6_header() const noexcept -> HeaderView< IPv6Header >
Get IPv6 header view.
Definition buffer_view.hxx:125
constexpr auto vlan_id() const noexcept -> std::optional< uint16_t >
Get VLAN ID if VLAN tag is present.
Definition buffer_view.hxx:86
constexpr auto ip4_header() const noexcept -> HeaderView< IPv4Header >
Get IPv4 header view.
Definition buffer_view.hxx:116
constexpr auto l3_offset() const noexcept -> uint16_t
Get the offset of the Layer 3 header.
Definition buffer_view.hxx:95
constexpr auto udp_header() const noexcept -> HeaderView< UDPHeader >
Get UDP header view.
Definition buffer_view.hxx:187
constexpr BufferView(const void *data, uint16_t length) noexcept
Definition buffer_view.hxx:32
constexpr auto data() const noexcept -> std::span< const buffer_t >
Get the underlying buffer data as a span.
Definition buffer_view.hxx:36
A lightweight view over a header inside a packet buffer.
Definition header_view.hxx:19
Definition arp.hxx:11
EtherType
Ethernet frame EtherType values (network byte order).
Definition ether.hxx:19
@ IPv4
Definition ether.hxx:20
@ VLAN
Definition ether.hxx:22
@ ARP
Definition ether.hxx:21
@ IPv6
Definition ether.hxx:23
IpProtocol
IP protocol (Next Header) numbers.
Definition ip_protocol.hxx:13
@ IPv6_Route
Definition ip_protocol.hxx:57
@ ICMPv4
Definition ip_protocol.hxx:15
@ TCP
Definition ip_protocol.hxx:20
@ ICMPv6
Definition ip_protocol.hxx:72
@ UDP
Definition ip_protocol.hxx:31
Address Resolution Protocol (ARP) header.
Definition arp.hxx:27
Ethernet frame header (14 bytes).
Definition ether.hxx:34
ICMP header (type, code, checksum) (4 bytes).
Definition icmp4.hxx:64
ICMPv6 header (type, code, checksum) (4 bytes).
Definition icmp6.hxx:77
IPv4 header (minimum 20 bytes).
Definition ip4_header.hxx:35
IPv6 header (40 bytes).
Definition ip6_header.hxx:18
IPv6 Segment Routing Header (SRH) as defined in RFC 8754.
Definition srv6_header.hxx:21
TCP header (minimum 20 bytes).
Definition tcp_header.hxx:32
UDP header (8 bytes).
Definition udp_header.hxx:17
VLAN (802.1Q) header (4 bytes after Ethernet header).
Definition ether.hxx:114