1
0
mirror of https://github.com/mfontanini/libtins synced 2026-01-29 04:54:28 +01:00

Add initial ACK tracking code

This commit is contained in:
Matias Fontanini
2016-02-13 20:24:15 -08:00
parent 48c068b84a
commit 116eb9f1c1
14 changed files with 578 additions and 19 deletions

View File

@@ -53,6 +53,7 @@ ADD_LIBRARY(
snap.cpp
sniffer.cpp
tcp.cpp
tcp_ip/ack_tracker.cpp
tcp_ip/flow.cpp
tcp_ip/stream.cpp
tcp_ip/stream_follower.cpp

View File

@@ -349,6 +349,20 @@ bool decrement(IPv6Address& addr) {
return decrement_buffer(addr);
}
int seq_compare(uint32_t seq1, uint32_t seq2) {
// As defined by RFC 1982 - 2 ^ (SERIAL_BITS - 1)
static const uint32_t seq_number_diff = 2147483648U;
if (seq1 == seq2) {
return 0;
}
if (seq1 < seq2) {
return (seq2 - seq1 < seq_number_diff) ? -1 : 1;
}
else {
return (seq1 - seq2 > seq_number_diff) ? -1 : 1;
}
}
IPv4Address last_address_from_mask(IPv4Address addr, IPv4Address mask) {
uint32_t addr_int = Endian::be_to_host<uint32_t>(addr),
mask_int = Endian::be_to_host<uint32_t>(mask);

146
src/tcp_ip/ack_tracker.cpp Normal file
View File

@@ -0,0 +1,146 @@
/*
* Copyright (c) 2016, Matias Fontanini
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include "tcp_ip/ack_tracker.h"
#ifdef HAVE_ACK_TRACKER
#include <limits>
#include "tcp.h"
#include "internals.h"
using std::vector;
using std::numeric_limits;
using Tins::Internals::seq_compare;
namespace Tins {
namespace TCPIP {
// AckedRange
AckedRange::AckedRange(uint32_t first, uint32_t last)
: first_(first), last_(last) {
}
AckedRange::interval_type AckedRange::next() {
uint32_t interval_first = first_;
// Regular case
if (first_ <= last_) {
first_ = last_ + 1;
return interval_type::closed(interval_first, last_);
}
else {
// Range wraps around
first_ = 0;
return interval_type::closed(interval_first, numeric_limits<uint32_t>::max());
}
}
bool AckedRange::has_next() const {
return seq_compare(first_, last_) <= 0;
}
uint32_t AckedRange::first() const {
return first_;
}
uint32_t AckedRange::last() const {
return last_;
}
// AckTracker
AckTracker::AckTracker()
: ack_number_(0), use_sack_(false) {
}
AckTracker::AckTracker(uint32_t initial_ack, bool use_sack)
: ack_number_(initial_ack), use_sack_(use_sack) {
}
void AckTracker::process_packet(const PDU& packet) {
const TCP* tcp = packet.find_pdu<TCP>();
if (!tcp) {
return;
}
if (seq_compare(tcp->ack_seq(), ack_number_) > 0) {
cleanup_sacked_intervals(ack_number_, tcp->ack_seq());
ack_number_ = tcp->ack_seq();
}
if (use_sack_) {
const TCP::option* sack_option = tcp->search_option(TCP::SACK);
if (sack_option) {
TCP::sack_type sack = sack_option->to<TCP::sack_type>();
process_sack(sack);
}
}
}
void AckTracker::process_sack(const vector<uint32_t>& sack) {
for (size_t i = 1; i < sack.size(); i += 2) {
// Left edge must be lower than right edge
if (seq_compare(sack[i - 1], sack[i]) < 0) {
AckedRange range(sack[i - 1], sack[i] - 1);
// If this range starts after our current ack number
if (seq_compare(range.first(), ack_number_) > 0) {
while (range.has_next()) {
acked_intervals_.insert(range.next());
}
}
}
}
}
void AckTracker::cleanup_sacked_intervals(uint32_t old_ack, uint32_t new_ack) {
AckedRange range(old_ack, new_ack);
while (range.has_next()) {
acked_intervals_.erase(range.next());
}
}
void AckTracker::use_sack() {
use_sack_ = true;
}
uint32_t AckTracker::ack_number() const {
return ack_number_;
}
const AckTracker::interval_set_type& AckTracker::acked_intervals() const {
return acked_intervals_;
}
} // TCPIP
} // Tins
#endif // HAVE_ACK_TRACKER

View File

@@ -40,6 +40,7 @@
#include "ip.h"
#include "ipv6.h"
#include "rawpdu.h"
#include "internals.h"
#include "exceptions.h"
#include "memory_helpers.h"
@@ -53,26 +54,11 @@ using std::swap;
using Tins::Memory::OutputMemoryStream;
using Tins::Memory::InputMemoryStream;
using Tins::Internals::seq_compare;
namespace Tins {
namespace TCPIP {
// As defined by RFC 1982 - 2 ^ (SERIAL_BITS - 1)
static const uint32_t seq_number_diff = 2147483648U;
// Compares sequence numbers as defined by RFC 1982.
int seq_compare(uint32_t seq1, uint32_t seq2) {
if (seq1 == seq2) {
return 0;
}
if (seq1 < seq2) {
return (seq2 - seq1 < seq_number_diff) ? -1 : 1;
}
else {
return (seq1 - seq2 > seq_number_diff) ? -1 : 1;
}
}
Flow::Flow(const IPv4Address& dest_address, uint16_t dest_port,
uint32_t sequence_number)
: seq_number_(sequence_number), dest_port_(dest_port) {
@@ -111,6 +97,11 @@ void Flow::process_packet(PDU& pdu) {
// Update the internal state first
if (tcp) {
update_state(*tcp);
#ifdef HAVE_ACK_TRACKER
if (flags_.ack_tracking) {
ack_tracker_.process_packet(*tcp);
}
#endif // HAVE_ACK_TRACKER
}
if (flags_.ignore_data_packets) {
return;
@@ -316,6 +307,18 @@ bool Flow::sack_permitted() const {
return flags_.sack_permitted;
}
void Flow::enable_ack_tracking() {
#ifdef HAVE_ACK_TRACKER
flags_.ack_tracking = 1;
#else
throw feature_disabled();
#endif
}
bool Flow::ack_tracking_enabled() const {
return flags_.ack_tracking;
}
} // TCPIP
} // Tins

View File

@@ -256,6 +256,15 @@ void Stream::auto_cleanup_payloads(bool value) {
auto_cleanup_ = value;
}
void Stream::enable_ack_tracking() {
client_flow().enable_ack_tracking();
server_flow().enable_ack_tracking();
}
bool Stream::ack_tracking_enabled() const {
return client_flow().ack_tracking_enabled() && server_flow().ack_tracking_enabled();
}
void Stream::on_client_flow_data(const Flow& /*flow*/) {
if (on_client_data_callback_) {
on_client_data_callback_(*this);