From 3b848060aa0920b7f223c5c9eb313c19646be0ac Mon Sep 17 00:00:00 2001 From: Matias Fontanini Date: Tue, 9 Feb 2016 19:56:30 -0800 Subject: [PATCH] Change tcp_ip directory structure --- examples/CMakeLists.txt | 4 +- examples/{http_dump.cpp => stream_dump.cpp} | 14 +- include/tins/CMakeLists.txt | 1 + include/tins/tcp_ip/CMakeLists.txt | 6 + include/tins/{tcp_ip.h => tcp_ip/stream.h} | 125 +----------- include/tins/tcp_ip/stream_follower.h | 168 ++++++++++++++++ src/CMakeLists.txt | 3 +- src/{tcp_ip.cpp => tcp_ip/stream.cpp} | 139 +------------- src/tcp_ip/stream_follower.cpp | 202 ++++++++++++++++++++ tests/src/tcp_ip.cpp | 2 +- 10 files changed, 399 insertions(+), 265 deletions(-) rename examples/{http_dump.cpp => stream_dump.cpp} (92%) create mode 100644 include/tins/tcp_ip/CMakeLists.txt rename include/tins/{tcp_ip.h => tcp_ip/stream.h} (81%) create mode 100644 include/tins/tcp_ip/stream_follower.h rename src/{tcp_ip.cpp => tcp_ip/stream.cpp} (75%) create mode 100644 src/tcp_ip/stream_follower.cpp diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index 8baf71e..3e2a9bf 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -15,7 +15,7 @@ IF(libtins_FOUND) dns_queries dns_spoof dns_stats - http_dump + stream_dump icmp_responses interfaces_info tcp_connection_close @@ -41,7 +41,7 @@ IF(libtins_FOUND) ADD_EXECUTABLE(arpmonitor EXCLUDE_FROM_ALL arpmonitor.cpp) ADD_EXECUTABLE(dns_queries EXCLUDE_FROM_ALL dns_queries.cpp) ADD_EXECUTABLE(dns_spoof EXCLUDE_FROM_ALL dns_spoof.cpp) - ADD_EXECUTABLE(http_dump EXCLUDE_FROM_ALL http_dump.cpp) + ADD_EXECUTABLE(stream_dump EXCLUDE_FROM_ALL stream_dump.cpp) ADD_EXECUTABLE(icmp_responses EXCLUDE_FROM_ALL icmp_responses.cpp) ADD_EXECUTABLE(interfaces_info EXCLUDE_FROM_ALL interfaces_info.cpp) ADD_EXECUTABLE(tcp_connection_close EXCLUDE_FROM_ALL tcp_connection_close.cpp) diff --git a/examples/http_dump.cpp b/examples/stream_dump.cpp similarity index 92% rename from examples/http_dump.cpp rename to examples/stream_dump.cpp index 5daad0a..d76ee70 100644 --- a/examples/http_dump.cpp +++ b/examples/stream_dump.cpp @@ -29,7 +29,7 @@ #include #include -#include "tins/tcp_ip.h" +#include "tins/tcp_ip/stream_follower.h" #include "tins/sniffer.h" #include "tins/ip_address.h" #include "tins/ipv6_address.h" @@ -47,6 +47,11 @@ using Tins::SnifferConfiguration; using Tins::TCPIP::StreamFollower; using Tins::TCPIP::Stream; +// This example takes an interface and a port as an argument and +// it listens for TCP streams on the given interface and port. +// It will reassemble TCP streams and show the traffic sent by +// both the client and the server. + // Convert the client endpoint to a readable string string client_endpoint(const Stream& stream) { ostringstream output; @@ -94,6 +99,7 @@ void on_client_data(Stream& stream) { // Whenever there's new server data on the stream, this callback is executed. // This does the same thing as on_client_data void on_server_data(Stream& stream) { + std::cout << "server data\n"; string data(stream.server_payload().begin(), stream.server_payload().end()); cout << server_endpoint(stream) << " >> " << client_endpoint(stream) << ": " << endl << data << endl; @@ -118,8 +124,8 @@ void on_new_connection(Stream& stream) { } int main(int argc, char* argv[]) { - if (argc != 2) { - cout << "Usage: " << argv[0] << " " << endl; + if (argc != 3) { + cout << "Usage: " << argv[0] << " " << endl; return 1; } using std::placeholders::_1; @@ -128,7 +134,7 @@ int main(int argc, char* argv[]) { // Construct the sniffer configuration object SnifferConfiguration config; // Only capture TCP traffic sent from/to port 80 - config.set_filter("tcp port 80"); + config.set_filter("tcp port " + string(argv[2])); // Construct the sniffer we'll use Sniffer sniffer(argv[1], config); diff --git a/include/tins/CMakeLists.txt b/include/tins/CMakeLists.txt index 3737ced..54f8c42 100644 --- a/include/tins/CMakeLists.txt +++ b/include/tins/CMakeLists.txt @@ -5,3 +5,4 @@ INSTALL( COMPONENT Headers ) ADD_SUBDIRECTORY(dot11) +ADD_SUBDIRECTORY(tcp_ip) diff --git a/include/tins/tcp_ip/CMakeLists.txt b/include/tins/tcp_ip/CMakeLists.txt new file mode 100644 index 0000000..db9c3a7 --- /dev/null +++ b/include/tins/tcp_ip/CMakeLists.txt @@ -0,0 +1,6 @@ +FILE(GLOB INCLUDE_FILES "*.h") +INSTALL( + FILES ${INCLUDE_FILES} + DESTINATION include/tins/tcp_ip + COMPONENT Headers +) diff --git a/include/tins/tcp_ip.h b/include/tins/tcp_ip/stream.h similarity index 81% rename from include/tins/tcp_ip.h rename to include/tins/tcp_ip/stream.h index d72b2ba..bdd9e4e 100644 --- a/include/tins/tcp_ip.h +++ b/include/tins/tcp_ip/stream.h @@ -27,10 +27,10 @@ * */ -#ifndef TINS_TCP_IP_H -#define TINS_TCP_IP_H +#ifndef TINS_TCP_IP_STREAM_H +#define TINS_TCP_IP_STREAM_H -#include "cxxstd.h" +#include "../cxxstd.h" // This classes use C++11 features #if TINS_IS_CXX11 @@ -40,8 +40,8 @@ #include #include #include -#include "macros.h" -#include "hw_address.h" +#include "../macros.h" +#include "../hw_address.h" namespace Tins { @@ -541,122 +541,9 @@ private: bool auto_cleanup_; }; -/** - * \brief Represents a class that follows TCP and reassembles streams - * - * This class processes packets and whenever it detects a new connection - * being open, it starts tracking it. This will follow all data sent by - * each peer and make it available to the user in a simple way. - * - * In order to use this class, just create an instance and set the - * new stream callback to some function that you want: - * - * \code - * void on_new_stream(TCPStream& stream) { - * // Do something with it. - * // This is the perfect time to set the stream's client/server - * // write callbacks so you are notified whenever there's new - * // data on the stream - * } - * - * // Create it - * StreamFollower follower; - * // Set the callback - * follower.new_stream_callback(&on_new_stream); - * \endcode - */ -class TINS_API StreamFollower { -public: - /** - * \brief The type used for callbacks - */ - typedef Stream::stream_callback_type stream_callback_type; - - /** - * Default constructor - */ - StreamFollower(); - - /** - * \brief Processes a packet - * - * This will detect if this packet belongs to an existing stream - * and process it, or if it belongs to a new one, in which case it - * starts tracking it. - * - * This method always returns true so it can be easily plugged as - * the argument to Sniffer::sniff_loop. - * - * \param packet The packet to be processed - * \return Always true - */ - bool process_packet(PDU& packet); - - /** - * \brief Sets the callback to be executed when a new stream is captured. - * - * Whenever a new stream is captured, the provided callback will be - * executed. - * - * \param callback The callback to be set - */ - void new_stream_callback(const stream_callback_type& callback); - - /** - * Finds the stream identified by the provided arguments. - * - * \param client_addr The client's address - * \param client_port The client's port - * \param server_addr The server's address - * \param server_addr The server's port - */ - Stream& find_stream(IPv4Address client_addr, uint16_t client_port, - IPv4Address server_addr, uint16_t server_port); - - /** - * Finds the stream identified by the provided arguments. - * - * \param client_addr The client's address - * \param client_port The client's port - * \param server_addr The server's address - * \param server_addr The server's port - */ - Stream& find_stream(IPv6Address client_addr, uint16_t client_port, - IPv6Address server_addr, uint16_t server_port); -private: - static const size_t DEFAULT_MAX_BUFFERED_CHUNKS; - typedef std::array address_type; - - struct stream_id { - stream_id(const address_type& client_addr, uint16_t client_port, - const address_type& server_addr, uint16_t server_port); - - address_type min_address; - address_type max_address; - uint16_t min_address_port; - uint16_t max_address_port; - - bool operator<(const stream_id& rhs) const; - - static size_t hash(const stream_id& id); - }; - - typedef std::map streams_type; - - stream_id make_stream_id(const PDU& packet); - Stream& find_stream(const stream_id& id); - static address_type serialize(IPv4Address address); - static address_type serialize(const IPv6Address& address); - - streams_type streams_; - stream_callback_type on_new_connection_; - size_t max_buffered_chunks_; - bool attach_to_flows_; -}; - } // TCPIP } // Tins #endif // TINS_IS_CXX11 -#endif // TINS_TCP_IP_H +#endif // TINS_TCP_IP_STREAM_H diff --git a/include/tins/tcp_ip/stream_follower.h b/include/tins/tcp_ip/stream_follower.h new file mode 100644 index 0000000..a277f43 --- /dev/null +++ b/include/tins/tcp_ip/stream_follower.h @@ -0,0 +1,168 @@ +/* + * 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. + * + */ + +#ifndef TINS_TCP_IP_STREAM_FOLLOWER_H +#define TINS_TCP_IP_STREAM_FOLLOWER_H + +#include "../cxxstd.h" + +// This classes use C++11 features +#if TINS_IS_CXX11 + +#include +#include "stream.h" + +namespace Tins { + +class PDU; +class TCP; +class IPv4Address; +class IPv6Address; + +namespace TCPIP { + +/** + * \brief Represents a class that follows TCP and reassembles streams + * + * This class processes packets and whenever it detects a new connection + * being open, it starts tracking it. This will follow all data sent by + * each peer and make it available to the user in a simple way. + * + * In order to use this class, just create an instance and set the + * new stream callback to some function that you want: + * + * \code + * void on_new_stream(TCPStream& stream) { + * // Do something with it. + * // This is the perfect time to set the stream's client/server + * // write callbacks so you are notified whenever there's new + * // data on the stream + * } + * + * // Create it + * StreamFollower follower; + * // Set the callback + * follower.new_stream_callback(&on_new_stream); + * \endcode + */ +class TINS_API StreamFollower { +public: + /** + * \brief The type used for callbacks + */ + typedef Stream::stream_callback_type stream_callback_type; + + /** + * Default constructor + */ + StreamFollower(); + + /** + * \brief Processes a packet + * + * This will detect if this packet belongs to an existing stream + * and process it, or if it belongs to a new one, in which case it + * starts tracking it. + * + * This method always returns true so it can be easily plugged as + * the argument to Sniffer::sniff_loop. + * + * \param packet The packet to be processed + * \return Always true + */ + bool process_packet(PDU& packet); + + /** + * \brief Sets the callback to be executed when a new stream is captured. + * + * Whenever a new stream is captured, the provided callback will be + * executed. + * + * \param callback The callback to be set + */ + void new_stream_callback(const stream_callback_type& callback); + + /** + * Finds the stream identified by the provided arguments. + * + * \param client_addr The client's address + * \param client_port The client's port + * \param server_addr The server's address + * \param server_addr The server's port + */ + Stream& find_stream(IPv4Address client_addr, uint16_t client_port, + IPv4Address server_addr, uint16_t server_port); + + /** + * Finds the stream identified by the provided arguments. + * + * \param client_addr The client's address + * \param client_port The client's port + * \param server_addr The server's address + * \param server_addr The server's port + */ + Stream& find_stream(IPv6Address client_addr, uint16_t client_port, + IPv6Address server_addr, uint16_t server_port); +private: + static const size_t DEFAULT_MAX_BUFFERED_CHUNKS; + typedef std::array address_type; + + struct stream_id { + stream_id(const address_type& client_addr, uint16_t client_port, + const address_type& server_addr, uint16_t server_port); + + address_type min_address; + address_type max_address; + uint16_t min_address_port; + uint16_t max_address_port; + + bool operator<(const stream_id& rhs) const; + + static size_t hash(const stream_id& id); + }; + + typedef std::map streams_type; + + stream_id make_stream_id(const PDU& packet); + Stream& find_stream(const stream_id& id); + static address_type serialize(IPv4Address address); + static address_type serialize(const IPv6Address& address); + + streams_type streams_; + stream_callback_type on_new_connection_; + size_t max_buffered_chunks_; + bool attach_to_flows_; +}; + +} // TCPIP +} // Tins + +#endif // TINS_IS_CXX11 + +#endif // TINS_TCP_IP_STREAM_FOLLOWER_H diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index bc3da02..d436f0d 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -53,7 +53,8 @@ ADD_LIBRARY( snap.cpp sniffer.cpp tcp.cpp - tcp_ip.cpp + tcp_ip/stream.cpp + tcp_ip/stream_follower.cpp tcp_stream.cpp udp.cpp utils.cpp diff --git a/src/tcp_ip.cpp b/src/tcp_ip/stream.cpp similarity index 75% rename from src/tcp_ip.cpp rename to src/tcp_ip/stream.cpp index 7b93db1..abfd097 100644 --- a/src/tcp_ip.cpp +++ b/src/tcp_ip/stream.cpp @@ -27,7 +27,7 @@ * */ -#include "tcp_ip.h" +#include "tcp_ip/stream.h" #if TINS_IS_CXX11 @@ -515,143 +515,6 @@ void Stream::on_server_out_of_order(const Flow& flow, } } -// StreamFollower - -const size_t StreamFollower::DEFAULT_MAX_BUFFERED_CHUNKS = 512; - -StreamFollower::StreamFollower() -: max_buffered_chunks_(DEFAULT_MAX_BUFFERED_CHUNKS), attach_to_flows_(false) { - -} - -bool StreamFollower::process_packet(PDU& packet) { - stream_id identifier = make_stream_id(packet); - streams_type::iterator iter = streams_.find(identifier); - bool process = true; - if (iter == streams_.end()) { - const TCP& tcp = packet.rfind_pdu(); - // Start tracking if they're either SYNs or they contain data (attach - // to an already running flow). - if (tcp.flags() == TCP::SYN || (attach_to_flows_ && tcp.find_pdu() != 0)) { - iter = streams_.insert(make_pair(identifier, Stream(packet))).first; - iter->second.setup_flows_callbacks(); - if (on_new_connection_) { - on_new_connection_(iter->second); - } - else { - // TODO: use proper exception - throw runtime_error("No new connection callback set"); - } - if (tcp.flags() == TCP::SYN) { - process = false; - } - else { - // Otherwise, assume the connection is established - iter->second.client_flow().state(Flow::ESTABLISHED); - iter->second.server_flow().state(Flow::ESTABLISHED); - } - } - else { - process = false; - } - } - // We'll process it if we had already seen this stream or if we just attached to - // it and it contains payload - if (process) { - Stream& stream = iter->second; - stream.process_packet(packet); - size_t total_chunks = stream.client_flow().buffered_payload().size() + - stream.server_flow().buffered_payload().size(); - if (stream.is_finished() || total_chunks > max_buffered_chunks_) { - streams_.erase(iter); - } - } - return true; -} - -void StreamFollower::new_stream_callback(const stream_callback_type& callback) { - on_new_connection_ = callback; -} - -Stream& StreamFollower::find_stream(IPv4Address client_addr, uint16_t client_port, - IPv4Address server_addr, uint16_t server_port) { - stream_id identifier(serialize(client_addr), client_port, - serialize(server_addr), server_port); - return find_stream(identifier); -} - -Stream& StreamFollower::find_stream(IPv6Address client_addr, uint16_t client_port, - IPv6Address server_addr, uint16_t server_port) { - stream_id identifier(serialize(client_addr), client_port, - serialize(server_addr), server_port); - return find_stream(identifier); -} - -StreamFollower::stream_id StreamFollower::make_stream_id(const PDU& packet) { - const TCP* tcp = packet.find_pdu(); - if (!tcp) { - // TODO: define proper exception - throw runtime_error("No TCP"); - } - if (const IP* ip = packet.find_pdu()) { - return stream_id(serialize(ip->src_addr()), tcp->sport(), - serialize(ip->dst_addr()), tcp->dport()); - } - else if (const IPv6* ip = packet.find_pdu()) { - return stream_id(serialize(ip->src_addr()), tcp->sport(), - serialize(ip->dst_addr()), tcp->dport()); - } - else { - // TODO: define proper exception - throw runtime_error("No layer 3"); - } -} - -Stream& StreamFollower::find_stream(const stream_id& id) { - streams_type::iterator iter = streams_.find(id); - if (iter == streams_.end()) { - throw stream_not_found(); - } - else { - return iter->second; - } -} - -StreamFollower::address_type StreamFollower::serialize(IPv4Address address) { - address_type addr; - OutputMemoryStream output(addr.data(), addr.size()); - addr.fill(0); - output.write(address); - return addr; -} - -StreamFollower::address_type StreamFollower::serialize(const IPv6Address& address) { - address_type addr; - OutputMemoryStream output(addr.data(), addr.size()); - addr.fill(0); - output.write(address); - return addr; -} - -// stream_id - -StreamFollower::stream_id::stream_id(const address_type& client_addr, - uint16_t client_port, - const address_type& server_addr, - uint16_t server_port) -: min_address(client_addr), max_address(server_addr), min_address_port(client_port), - max_address_port(server_port) { - if (min_address > max_address) { - swap(min_address, max_address); - swap(min_address_port, max_address_port); - } -} - -bool StreamFollower::stream_id::operator<(const stream_id& rhs) const { - return tie(min_address, min_address_port, max_address, max_address_port) < - tie(rhs.min_address, rhs.min_address_port, rhs.max_address, rhs.max_address_port); -} - } // TCPIP } // Tins diff --git a/src/tcp_ip/stream_follower.cpp b/src/tcp_ip/stream_follower.cpp new file mode 100644 index 0000000..b7b2404 --- /dev/null +++ b/src/tcp_ip/stream_follower.cpp @@ -0,0 +1,202 @@ +/* + * 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/stream_follower.h" + +#if TINS_IS_CXX11 + +#include +#include +#include "memory.h" +#include "ip_address.h" +#include "ipv6_address.h" +#include "tcp.h" +#include "ip.h" +#include "ipv6.h" +#include "rawpdu.h" +#include "exceptions.h" +#include "memory_helpers.h" + +using std::make_pair; +using std::bind; +using std::pair; +using std::runtime_error; +using std::numeric_limits; +using std::max; +using std::swap; + +using Tins::Memory::OutputMemoryStream; +using Tins::Memory::InputMemoryStream; + +namespace Tins { +namespace TCPIP { + +const size_t StreamFollower::DEFAULT_MAX_BUFFERED_CHUNKS = 512; + +StreamFollower::StreamFollower() +: max_buffered_chunks_(DEFAULT_MAX_BUFFERED_CHUNKS), attach_to_flows_(false) { + +} + +bool StreamFollower::process_packet(PDU& packet) { + stream_id identifier = make_stream_id(packet); + streams_type::iterator iter = streams_.find(identifier); + bool process = true; + if (iter == streams_.end()) { + const TCP& tcp = packet.rfind_pdu(); + // Start tracking if they're either SYNs or they contain data (attach + // to an already running flow). + if (tcp.flags() == TCP::SYN || (attach_to_flows_ && tcp.find_pdu() != 0)) { + iter = streams_.insert(make_pair(identifier, Stream(packet))).first; + iter->second.setup_flows_callbacks(); + if (on_new_connection_) { + on_new_connection_(iter->second); + } + else { + // TODO: use proper exception + throw runtime_error("No new connection callback set"); + } + if (tcp.flags() == TCP::SYN) { + process = false; + } + else { + // Otherwise, assume the connection is established + iter->second.client_flow().state(Flow::ESTABLISHED); + iter->second.server_flow().state(Flow::ESTABLISHED); + } + } + else { + process = false; + } + } + // We'll process it if we had already seen this stream or if we just attached to + // it and it contains payload + if (process) { + Stream& stream = iter->second; + stream.process_packet(packet); + size_t total_chunks = stream.client_flow().buffered_payload().size() + + stream.server_flow().buffered_payload().size(); + if (stream.is_finished() || total_chunks > max_buffered_chunks_) { + streams_.erase(iter); + } + } + return true; +} + +void StreamFollower::new_stream_callback(const stream_callback_type& callback) { + on_new_connection_ = callback; +} + +Stream& StreamFollower::find_stream(IPv4Address client_addr, uint16_t client_port, + IPv4Address server_addr, uint16_t server_port) { + stream_id identifier(serialize(client_addr), client_port, + serialize(server_addr), server_port); + return find_stream(identifier); +} + +Stream& StreamFollower::find_stream(IPv6Address client_addr, uint16_t client_port, + IPv6Address server_addr, uint16_t server_port) { + stream_id identifier(serialize(client_addr), client_port, + serialize(server_addr), server_port); + return find_stream(identifier); +} + +StreamFollower::stream_id StreamFollower::make_stream_id(const PDU& packet) { + const TCP* tcp = packet.find_pdu(); + if (!tcp) { + // TODO: define proper exception + throw runtime_error("No TCP"); + } + if (const IP* ip = packet.find_pdu()) { + return stream_id(serialize(ip->src_addr()), tcp->sport(), + serialize(ip->dst_addr()), tcp->dport()); + } + else if (const IPv6* ip = packet.find_pdu()) { + return stream_id(serialize(ip->src_addr()), tcp->sport(), + serialize(ip->dst_addr()), tcp->dport()); + } + else { + // TODO: define proper exception + throw runtime_error("No layer 3"); + } +} + +Stream& StreamFollower::find_stream(const stream_id& id) { + streams_type::iterator iter = streams_.find(id); + if (iter == streams_.end()) { + throw stream_not_found(); + } + else { + return iter->second; + } +} + +StreamFollower::address_type StreamFollower::serialize(IPv4Address address) { + address_type addr; + OutputMemoryStream output(addr.data(), addr.size()); + addr.fill(0); + output.write(address); + return addr; +} + +StreamFollower::address_type StreamFollower::serialize(const IPv6Address& address) { + address_type addr; + OutputMemoryStream output(addr.data(), addr.size()); + addr.fill(0); + output.write(address); + return addr; +} + +// stream_id + +StreamFollower::stream_id::stream_id(const address_type& client_addr, + uint16_t client_port, + const address_type& server_addr, + uint16_t server_port) +: min_address(client_addr), max_address(server_addr), min_address_port(client_port), + max_address_port(server_port) { + if (min_address > max_address) { + swap(min_address, max_address); + swap(min_address_port, max_address_port); + } + else if (min_address == max_address && min_address_port > max_address_port) { + // If the address is the same, just sort ports + swap(min_address_port, max_address_port); + } +} + +bool StreamFollower::stream_id::operator<(const stream_id& rhs) const { + return tie(min_address, min_address_port, max_address, max_address_port) < + tie(rhs.min_address, rhs.min_address_port, rhs.max_address, rhs.max_address_port); +} + +} // TCPIP +} // Tins + +#endif // TINS_IS_CXX11 diff --git a/tests/src/tcp_ip.cpp b/tests/src/tcp_ip.cpp index d31246a..9163aa2 100644 --- a/tests/src/tcp_ip.cpp +++ b/tests/src/tcp_ip.cpp @@ -8,7 +8,7 @@ #include #include #include -#include "tcp_ip.h" +#include "tcp_ip/stream_follower.h" #include "tcp.h" #include "ip.h" #include "ip_address.h"