-
Notifications
You must be signed in to change notification settings - Fork 391
Add parsing of well known IPv6 extension headers #287
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -69,6 +69,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 = std::vector<uint8_t>(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 +212,33 @@ uint32_t IPv6::get_padding_size(const ext_header& header) { | |
return padding == 0 ? 0 : (8 - padding); | ||
} | ||
|
||
std::vector<IPv6::header_option_type> IPv6::parse_header_options(const uint8_t* data, size_t size) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm trying to keep cpp files away from using "namespace specifiers" everywhere and instead just have There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Will do. |
||
{ | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can you move this brace up to the end of the previous line? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sure. Tried to keep the same coding style as the existing code, but I'm not surprised if I've missed a few places. |
||
Memory::InputMemoryStream stream(data, size); | ||
std::vector<header_option_type> options; | ||
|
||
while (stream.size() > 0) { | ||
try { | ||
uint8_t option = stream.read<uint8_t>(); | ||
if (option == OptionType::PAD_1) { | ||
continue; | ||
} | ||
uint8_t size = stream.read<uint8_t>(); | ||
if (size > stream.size()) { | ||
throw invalid_ipv6_extension_header(); | ||
} | ||
if (option != PAD_N) { | ||
std::vector<uint8_t> value(stream.pointer(), stream.pointer() + size); | ||
options.push_back(std::make_pair(option, value)); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. So this sucks because I'm trying to keep the codebase both C++03 and C++11 compliant. If this was C++11 you would do: options.push_back(make_pair(option, move(value))); So you avoid creating an unnecessary copy of the vector. So in this case you can either have some ugly options.push_back(make_pair(option, vector<uint8_t>(stream.pointer(), stream.pointer() + size))); Possibly having to split that in multiple lines if it's too long. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I thought a bit about that actually and was pretty sure the compiler could probably optimize the copy away, but I never tested that. Anyway since this library has to support C++03, I much prefer your second option over ugly #ifdefs, so I'll go with that. Well spotted. |
||
} | ||
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; | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can just do
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Of course. Thanks for pointing this out.