1
0
mirror of https://github.com/mfontanini/libtins synced 2026-01-30 13:34:27 +01:00

Set proper value for length field

This commit is contained in:
Matias Fontanini
2015-12-19 16:46:13 -08:00
parent 0a16d8f462
commit 530cc56922
6 changed files with 188 additions and 7 deletions

View File

@@ -149,7 +149,12 @@ uint32_t ICMP::trailer_size() const {
if (has_extensions()) {
output += extensions_.size();
if (inner_pdu()) {
output += 128 - std::min(inner_pdu()->size(), 128U);
// This gets how much padding we'll use.
// If the next pdu size is lower than 128 bytes, then padding = 128 - pdu size
// If the next pdu size is greater than 128 bytes,
// then padding = pdu size padded to next 32 bit boundary - pdu size
const uint32_t upper_bound = std::max(get_adjusted_inner_pdu_size(), 128U);
output += upper_bound - inner_pdu()->size();
}
}
return output;
@@ -210,6 +215,12 @@ void ICMP::set_redirect(uint8_t icode, address_type address) {
gateway(address);
}
void ICMP::use_length_field(bool value) {
// We just need a non 0 value here, we'll use the right value on
// write_serialization
_icmp.un.rfc4884.length = value ? 1 : 0;
}
void ICMP::write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *) {
#ifdef TINS_DEBUG
assert(total_sz >= sizeof(icmphdr));
@@ -229,16 +240,36 @@ void ICMP::write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *)
memcpy(buffer + sizeof(icmphdr), &uint32_t_buffer, sizeof(uint32_t));
}
// If extensions are allowed and we have to set the length field
if (are_extensions_allowed()) {
uint32_t length_value = get_adjusted_inner_pdu_size();
// If the next pdu size is greater than 128, we are forced to set the length field
if (length() != 0 || length_value > 128) {
length_value = length_value ? std::max(length_value, 128U) : 0;
// This field uses 32 bit words as the unit
_icmp.un.rfc4884.length = length_value / sizeof(uint32_t);
}
}
if (has_extensions()) {
uint8_t* extensions_ptr = buffer + sizeof(icmphdr);
if (inner_pdu()) {
uint32_t inner_pdu_size = inner_pdu()->size();
// Get the size of the next pdu, padded to the next 32 bit boundary
uint32_t inner_pdu_size = get_adjusted_inner_pdu_size();
// If it's lower than 128, we need to padd enough zeroes to make it 128 bytes long
if (inner_pdu_size < 128) {
memset(buffer + sizeof(icmphdr) + inner_pdu_size, 0, 128 - inner_pdu_size);
inner_pdu_size = 128;
}
else {
// If the packet has to be padded to 32 bits, append the amount
// of zeroes we need
uint32_t diff = inner_pdu_size - inner_pdu()->size();
memset(buffer + sizeof(icmphdr) + inner_pdu_size, 0, diff);
}
extensions_ptr += inner_pdu_size;
}
// Now serialize the exensions where they should be
extensions_.serialize(extensions_ptr, total_sz - (extensions_ptr - buffer));
}
@@ -254,12 +285,25 @@ void ICMP::write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *)
memcpy(buffer + 2, &_icmp.check, sizeof(uint16_t));
}
uint32_t ICMP::get_adjusted_inner_pdu_size() const {
// This gets the size of the next pdu, padded to the next 32 bit word boundary
if (inner_pdu()) {
uint32_t inner_pdu_size = inner_pdu()->size();
uint32_t padding = inner_pdu_size % 4;
inner_pdu_size = padding ? (inner_pdu_size - padding + 4) : inner_pdu_size;
return inner_pdu_size;
}
else {
return 0;
}
}
void ICMP::try_parse_extensions(const uint8_t* buffer, uint32_t& total_sz) {
if (total_sz == 0) {
return;
}
// Check if this is one of the types defined in RFC 4884
if (type() == DEST_UNREACHABLE || type() == TIME_EXCEEDED || type() == PARAM_PROBLEM) {
if (are_extensions_allowed()) {
uint32_t actual_length = length() * sizeof(uint32_t);
// Check if we actually have this amount of data and whether it's more than
// the minimum encapsulated packet size
@@ -286,6 +330,10 @@ void ICMP::try_parse_extensions(const uint8_t* buffer, uint32_t& total_sz) {
}
}
bool ICMP::are_extensions_allowed() const {
return type() == DEST_UNREACHABLE || type() == TIME_EXCEEDED || type() == PARAM_PROBLEM;
}
bool ICMP::matches_response(const uint8_t *ptr, uint32_t total_sz) const {
if(total_sz < sizeof(icmphdr))
return false;