347 lines
10 KiB
C++
347 lines
10 KiB
C++
/*
|
|
* Copyright (c) 2017, 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.
|
|
*
|
|
*/
|
|
|
|
#ifndef TINS_TCP_IP_FLOW_H
|
|
#define TINS_TCP_IP_FLOW_H
|
|
|
|
#include <tins/config.h>
|
|
|
|
#ifdef TINS_HAVE_TCPIP
|
|
|
|
#include <array>
|
|
#include <functional>
|
|
#include <stdint.h>
|
|
#include <tins/macros.h>
|
|
#include <tins/tcp_ip/ack_tracker.h>
|
|
#include <tins/tcp_ip/data_tracker.h>
|
|
|
|
namespace Tins {
|
|
|
|
class PDU;
|
|
class TCP;
|
|
class IPv4Address;
|
|
class IPv6Address;
|
|
|
|
namespace TCPIP {
|
|
|
|
/**
|
|
* \brief Represents an unidirectional TCP flow between 2 endpoints
|
|
*
|
|
* This class will keep the state for all the traffic sent by
|
|
* one of the peers in a TCP connection. This contains the sequence number,
|
|
* payload ready to be read and buffered payload, along with some other
|
|
* properties of the flow.
|
|
*
|
|
* A TCP stream (see class Stream) is made out of 2 Flows, so you should
|
|
* probably have a look at that class first.
|
|
*
|
|
* You shouldn't normally need to interact with this class. Stream already
|
|
* provides proxys to most of its Flow's attributes.
|
|
*/
|
|
class TINS_API Flow {
|
|
public:
|
|
/**
|
|
* \brief Enum that indicates the state of this flow.
|
|
*
|
|
* Note that although similar, this is not mapped to a TCP state-machine
|
|
* state. This is mostly used internally to know which packets the flow is
|
|
* expecting and to know when it's done sending data.
|
|
*/
|
|
enum State {
|
|
UNKNOWN,
|
|
SYN_SENT,
|
|
ESTABLISHED,
|
|
FIN_SENT,
|
|
RST_SENT
|
|
};
|
|
|
|
/**
|
|
* The type used to store the payload
|
|
*/
|
|
typedef DataTracker::payload_type payload_type;
|
|
|
|
/**
|
|
* The type used to store the buffered payload
|
|
*/
|
|
typedef DataTracker::buffered_payload_type buffered_payload_type;
|
|
|
|
/**
|
|
* The type used to store the callback called when new data is available
|
|
*/
|
|
typedef std::function<void(Flow&)> data_available_callback_type;
|
|
|
|
/**
|
|
* \brief The type used to store the callback called when data is buffered
|
|
*
|
|
* The arguments are the flow, the sequence number and payload that will
|
|
* be buffered.
|
|
*/
|
|
typedef std::function<void(Flow&,
|
|
uint32_t,
|
|
const payload_type&)> flow_packet_callback_type;
|
|
|
|
/**
|
|
* Construct a Flow from an IPv4 address
|
|
*
|
|
* \param dst_address This flow's destination address
|
|
* \param dst_port This flow's destination port
|
|
* \param sequence_number The initial sequence number to be used
|
|
*/
|
|
Flow(const IPv4Address& dst_address, uint16_t dst_port,
|
|
uint32_t sequence_number);
|
|
|
|
/**
|
|
* Construct a Flow from an IPv6 address
|
|
*
|
|
* \param dst_address This flow's destination address
|
|
* \param dst_port This flow's destination port
|
|
* \param sequence_number The initial sequence number to be used
|
|
*/
|
|
Flow(const IPv6Address& dst_address, uint16_t dst_port,
|
|
uint32_t sequence_number);
|
|
|
|
/**
|
|
* \brief Sets the callback that will be executed when data is readable
|
|
*
|
|
* Whenever this flow has readable data, this callback will be executed.
|
|
* By readable, this means that there's non-out-of-order data captured.
|
|
*
|
|
* \param callback The callback to be executed
|
|
*/
|
|
void data_callback(const data_available_callback_type& callback);
|
|
|
|
/**
|
|
* \brief Sets the callback that will be executed when out of order data arrives
|
|
*
|
|
* Whenever this flow receives out-of-order data, this callback will be
|
|
* executed.
|
|
*
|
|
* \param callback The callback to be executed
|
|
*/
|
|
void out_of_order_callback(const flow_packet_callback_type& callback);
|
|
|
|
/**
|
|
* \brief Processes a packet.
|
|
*
|
|
* If this packet contains data and starts or overlaps with the current
|
|
* sequence number, then the data will be appended to this flow's payload
|
|
* and the data_callback will be executed.
|
|
*
|
|
* If this packet contains out-of-order data, it will be buffered and the
|
|
* buffering_callback will be executed.
|
|
*
|
|
* \param pdu The packet to be processed
|
|
* \sa Flow::data_callback
|
|
* \sa Flow::buffering_callback
|
|
*/
|
|
void process_packet(PDU& pdu);
|
|
|
|
/**
|
|
* \brief Skip forward to a sequence number
|
|
*
|
|
* This allows to recover from packet loss, if we just do not see all packets of
|
|
* an original stream. This recovery can only sensibly triggered from the application
|
|
* layer.
|
|
*
|
|
* This method is particularly useful to call from an out of order callback, if
|
|
* the application wants to skip forward to this out of order block. The application
|
|
* will then get the normal data callback!
|
|
*
|
|
* IMPORTANT: If you call this method with a sequence number that is not exactly a
|
|
* TCP fragment boundary, the flow will never recover from this.
|
|
*
|
|
* \param seq The sequence number to skip to.
|
|
*/
|
|
void advance_sequence(uint32_t seq);
|
|
|
|
/**
|
|
* Indicates whether this flow uses IPv6 addresses
|
|
*/
|
|
bool is_v6() const;
|
|
|
|
/**
|
|
* \brief Indicates whether this flow is finished
|
|
*
|
|
* A finished is considered to be finished if either it sent a
|
|
* packet with the FIN or RST flags on.
|
|
*/
|
|
bool is_finished() const;
|
|
|
|
/**
|
|
* \brief Indicates whether a packet belongs to this flow
|
|
*
|
|
* Since Flow represents a unidirectional stream, this will only check
|
|
* the destination endpoint and not the source one.
|
|
*
|
|
* \param packet The packet to be checked
|
|
*/
|
|
bool packet_belongs(const PDU& packet) const;
|
|
|
|
/**
|
|
* \brief Retrieves the IPv4 destination address
|
|
*
|
|
* Note that it's only safe to execute this method if is_v6() == false
|
|
*/
|
|
IPv4Address dst_addr_v4() const;
|
|
|
|
/**
|
|
* \brief Retrieves the IPv6 destination address
|
|
*
|
|
* Note that it's only safe to execute this method if is_v6() == true
|
|
*/
|
|
IPv6Address dst_addr_v6() const;
|
|
|
|
/**
|
|
* Retrieves this flow's destination port
|
|
*/
|
|
uint16_t dport() const;
|
|
|
|
/**
|
|
* Retrieves this flow's payload (const)
|
|
*/
|
|
const payload_type& payload() const;
|
|
|
|
/**
|
|
* Retrieves this flow's payload
|
|
*/
|
|
payload_type& payload();
|
|
|
|
/**
|
|
* Retrieves this flow's state
|
|
*/
|
|
State state() const;
|
|
|
|
/**
|
|
* Retrieves this flow's sequence number
|
|
*/
|
|
uint32_t sequence_number() const;
|
|
|
|
/**
|
|
* Retrieves this flow's buffered payload (const)
|
|
*/
|
|
const buffered_payload_type& buffered_payload() const;
|
|
|
|
/**
|
|
* Retrieves this flow's buffered payload
|
|
*/
|
|
buffered_payload_type& buffered_payload();
|
|
|
|
/**
|
|
* Retrieves this flow's total buffered bytes
|
|
*/
|
|
uint32_t total_buffered_bytes() const;
|
|
|
|
/**
|
|
* Sets the state of this flow
|
|
*
|
|
* \param new_state The new state of this flow
|
|
*/
|
|
void state(State new_state);
|
|
|
|
/**
|
|
* \brief Sets whether this flow should ignore data packets
|
|
*
|
|
* If the data packets are ignored then the flow will just be
|
|
* followed to keep track of its state.
|
|
*/
|
|
void ignore_data_packets();
|
|
|
|
/**
|
|
* \brief Returns the MSS for this Flow.
|
|
*
|
|
* If the MSS option wasn't provided by the peer, -1 is returned
|
|
*/
|
|
int mss() const;
|
|
|
|
/**
|
|
* \brief Indicates whether this Flow supports selective acknowledgements
|
|
*/
|
|
bool sack_permitted() const;
|
|
|
|
/**
|
|
* \brief Enables tracking of ACK numbers
|
|
*
|
|
* This requires having the boost.icl library. If the library is not installed
|
|
* or ACK tracking was disabled when compiling the library, then this method
|
|
* will throw an exception.
|
|
*/
|
|
void enable_ack_tracking();
|
|
|
|
/**
|
|
* \brief Indicates whether ACK number tracking is enabled
|
|
*/
|
|
bool ack_tracking_enabled() const;
|
|
|
|
#ifdef TINS_HAVE_ACK_TRACKER
|
|
/**
|
|
* Retrieves the ACK tracker for this Flow (const)
|
|
*/
|
|
const AckTracker& ack_tracker() const;
|
|
|
|
/**
|
|
* Retrieves the ACK tracker for this Flow
|
|
*/
|
|
AckTracker& ack_tracker();
|
|
#endif // TINS_HAVE_ACK_TRACKER
|
|
private:
|
|
// Compress all flags into just one struct using bitfields
|
|
struct flags {
|
|
flags() : is_v6(0), ignore_data_packets(0), sack_permitted(0), ack_tracking(0) {
|
|
|
|
}
|
|
|
|
uint32_t is_v6:1,
|
|
ignore_data_packets:1,
|
|
sack_permitted:1,
|
|
ack_tracking:1;
|
|
};
|
|
|
|
void update_state(const TCP& tcp);
|
|
void initialize();
|
|
|
|
DataTracker data_tracker_;
|
|
std::array<uint8_t, 16> dest_address_;
|
|
uint16_t dest_port_;
|
|
data_available_callback_type on_data_callback_;
|
|
flow_packet_callback_type on_out_of_order_callback_;
|
|
State state_;
|
|
int mss_;
|
|
flags flags_;
|
|
#ifdef TINS_HAVE_ACK_TRACKER
|
|
AckTracker ack_tracker_;
|
|
#endif // TINS_HAVE_ACK_TRACKER
|
|
};
|
|
|
|
} // TCPIP
|
|
} // TINS
|
|
|
|
#endif // TINS_HAVE_TCPIP
|
|
#endif // TINS_TCP_IP_FLOW_H
|
|
|