mirror of
https://github.com/mfontanini/libtins
synced 2026-01-26 12:01:34 +01:00
Add parsing of well known IPv6 extension headers (#287)
* Add parsing of well known IPv6 extension headers Add classes for IPv6 extension headers defined in the IPv6 protocol specification (RFC 2460) as well as functions for creating them from the IPv6 class' ext_header type. The currently known extension headers are Hop-By-Hop Option, Destination Routing, Routing and Fragment. * Cleanup after PR #287 comments Pull in stuff from the std namespace with "using" instead of qualifying with std::. Keep starting braces on the same line. Avoid potential copy when appending to vector.
This commit is contained in:
committed by
Matias Fontanini
parent
342e2c77a7
commit
fa79582b89
71
src/ipv6.cpp
71
src/ipv6.cpp
@@ -43,6 +43,7 @@
|
||||
#include <tins/memory_helpers.h>
|
||||
#include <tins/detail/pdu_helpers.h>
|
||||
|
||||
using std::make_pair;
|
||||
using std::vector;
|
||||
|
||||
using Tins::Memory::InputMemoryStream;
|
||||
@@ -69,6 +70,49 @@ PDU::metadata IPv6::extract_metadata(const uint8_t *buffer, uint32_t total_sz) {
|
||||
return metadata(header_size, pdu_flag, PDU::UNKNOWN);
|
||||
}
|
||||
|
||||
IPv6::hop_by_hop_header IPv6::hop_by_hop_header::from_extension_header(const ext_header& hdr) {
|
||||
if (TINS_UNLIKELY(hdr.option() != HOP_BY_HOP)) {
|
||||
throw invalid_ipv6_extension_header();
|
||||
}
|
||||
hop_by_hop_header header;
|
||||
header.options = parse_header_options(hdr.data_ptr(), hdr.data_size());
|
||||
return header;
|
||||
}
|
||||
|
||||
IPv6::destination_routing_header IPv6::destination_routing_header::from_extension_header(const ext_header& hdr) {
|
||||
if (TINS_UNLIKELY(hdr.option() != DESTINATION_ROUTING_OPTIONS)) {
|
||||
throw invalid_ipv6_extension_header();
|
||||
}
|
||||
destination_routing_header header;
|
||||
header.options = parse_header_options(hdr.data_ptr(), hdr.data_size());
|
||||
return header;
|
||||
}
|
||||
|
||||
IPv6::routing_header IPv6::routing_header::from_extension_header(const ext_header& hdr) {
|
||||
if (TINS_UNLIKELY(hdr.option() != ROUTING)) {
|
||||
throw invalid_ipv6_extension_header();
|
||||
}
|
||||
Memory::InputMemoryStream stream(hdr.data_ptr(), hdr.data_size());
|
||||
routing_header header;
|
||||
header.routing_type = stream.read<uint8_t>();
|
||||
header.segments_left = stream.read<uint8_t>();
|
||||
header.data.assign(stream.pointer(), stream.pointer() + stream.size());
|
||||
return header;
|
||||
}
|
||||
|
||||
IPv6::fragment_header IPv6::fragment_header::from_extension_header(const ext_header& hdr) {
|
||||
if (TINS_UNLIKELY(hdr.option() != FRAGMENT)) {
|
||||
throw invalid_ipv6_extension_header();
|
||||
}
|
||||
Memory::InputMemoryStream stream(hdr.data_ptr(), hdr.data_size());
|
||||
fragment_header header;
|
||||
uint16_t field = stream.read_be<uint16_t>();
|
||||
header.fragment_offset = field >> 3;
|
||||
header.more_fragments = field & 1;
|
||||
header.identification = stream.read_be<uint32_t>();
|
||||
return header;
|
||||
}
|
||||
|
||||
IPv6::IPv6(address_type ip_dst, address_type ip_src, PDU* /*child*/)
|
||||
: header_(), next_header_() {
|
||||
version(6);
|
||||
@@ -169,6 +213,33 @@ uint32_t IPv6::get_padding_size(const ext_header& header) {
|
||||
return padding == 0 ? 0 : (8 - padding);
|
||||
}
|
||||
|
||||
vector<IPv6::header_option_type> IPv6::parse_header_options(const uint8_t* data, size_t size) {
|
||||
Memory::InputMemoryStream stream(data, size);
|
||||
vector<header_option_type> options;
|
||||
|
||||
while (stream.size() > 0) {
|
||||
try {
|
||||
uint8_t option = stream.read<uint8_t>();
|
||||
if (option == PAD_1) {
|
||||
continue;
|
||||
}
|
||||
uint8_t size = stream.read<uint8_t>();
|
||||
if (size > stream.size()) {
|
||||
throw invalid_ipv6_extension_header();
|
||||
}
|
||||
if (option != PAD_N) {
|
||||
options.push_back(make_pair(option, vector<uint8_t>(stream.pointer(),
|
||||
stream.pointer() +
|
||||
size)));
|
||||
}
|
||||
stream.skip(size);
|
||||
} catch (const malformed_packet&) {
|
||||
throw invalid_ipv6_extension_header();
|
||||
}
|
||||
}
|
||||
return options;
|
||||
}
|
||||
|
||||
void IPv6::version(small_uint<4> new_version) {
|
||||
header_.version = new_version;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user