diff --git a/include/tins/tcp_ip/stream_follower.h b/include/tins/tcp_ip/stream_follower.h index 6478396..b7e0768 100644 --- a/include/tins/tcp_ip/stream_follower.h +++ b/include/tins/tcp_ip/stream_follower.h @@ -37,6 +37,7 @@ #include #include "stream.h" +#include "stream_identifier.h" namespace Tins { @@ -75,10 +76,15 @@ namespace TCPIP { class TINS_API StreamFollower { public: /** - * \brief The type used for callbacks + * The type used for callbacks */ typedef Stream::stream_callback_type stream_callback_type; + /** + * The type used to identify streams + */ + typedef StreamIdentifier stream_id; + /** * Enum to indicate the reason why a stream was terminated */ @@ -95,47 +101,6 @@ public: */ typedef std::function stream_termination_callback_type; - /** - * \brief Unique identifies a stream. - * - * This struct is used to track TCP streams. It keeps track of minimum and maximum - * addresses/ports in a stream to match packets coming from any of the 2 endpoints - * into the same object. - */ - struct stream_id { - /** - * The type used to store each endpoint's address - */ - typedef std::array address_type; - - /** - * Default constructor - */ - stream_id(); - - /** - * Constructs a stream_id - * - * \param client_addr Client's address - * \param client_port Port's port - * \param server_addr Server's address - * \param server_port Server's port - */ - stream_id(const address_type& client_addr, uint16_t client_port, - const address_type& server_addr, uint16_t server_port); - - bool operator<(const stream_id& rhs) const; - bool operator==(const stream_id& rhs) const; - - address_type min_address; - address_type max_address; - uint16_t min_address_port; - uint16_t max_address_port; - - static address_type serialize(IPv4Address address); - static address_type serialize(const IPv6Address& address); - }; - /** * Default constructor */ @@ -228,7 +193,6 @@ private: typedef std::map streams_type; - static stream_id make_stream_id(const PDU& packet); Stream& find_stream(const stream_id& id); void process_packet(PDU& packet, const timestamp_type& ts); void cleanup_streams(const timestamp_type& now); diff --git a/include/tins/tcp_ip/stream_identifier.h b/include/tins/tcp_ip/stream_identifier.h new file mode 100644 index 0000000..a2558cc --- /dev/null +++ b/include/tins/tcp_ip/stream_identifier.h @@ -0,0 +1,105 @@ +/* + * 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_ID_H +#define TINS_TCP_IP_STREAM_ID_H + +#include "../cxxstd.h" + +// This classes use C++11 features +#if TINS_IS_CXX11 + +#include +#include + +namespace Tins { + +class PDU; +class IPv4Address; +class IPv6Address; + +namespace TCPIP { + +/** + * \brief Uniquely identifies a stream. + * + * This struct is used to track TCP/UDP streams. It keeps track of minimum and maximum + * addresses/ports in a stream to match packets coming from any of the 2 endpoints + * into the same object. + * + * This struct implements operator< so it can be used as a key on std::maps + */ +struct StreamIdentifier { + /** + * The type used to store each endpoint's address + */ + typedef std::array address_type; + + /** + * Default constructor + */ + StreamIdentifier(); + + /** + * Constructs a StreamIdentifier + * + * \param client_addr Client's address + * \param client_port Port's port + * \param server_addr Server's address + * \param server_port Server's port + */ + StreamIdentifier(const address_type& client_addr, uint16_t client_port, + const address_type& server_addr, uint16_t server_port); + + /** + * Indicates whether this stream identifier is lower than rhs + */ + bool operator<(const StreamIdentifier& rhs) const; + + /** + * Compares this stream identifier for equality + */ + bool operator==(const StreamIdentifier& rhs) const; + + address_type min_address; + address_type max_address; + uint16_t min_address_port; + uint16_t max_address_port; + + static StreamIdentifier make_identifier(const PDU& packet); + static address_type serialize(IPv4Address address); + static address_type serialize(const IPv6Address& address); +}; + +} // TCPIP +} // Tins + +#endif // TINS_IS_CXX11 +#endif // TINS_TCP_IP_STREAM_ID_H + diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index e906cf2..ed2a57a 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -57,6 +57,7 @@ ADD_LIBRARY( tcp_ip/flow.cpp tcp_ip/stream.cpp tcp_ip/stream_follower.cpp + tcp_ip/stream_identifier.cpp tcp_stream.cpp udp.cpp utils.cpp diff --git a/src/tcp_ip/stream_follower.cpp b/src/tcp_ip/stream_follower.cpp index 958d866..904b378 100644 --- a/src/tcp_ip/stream_follower.cpp +++ b/src/tcp_ip/stream_follower.cpp @@ -88,7 +88,7 @@ void StreamFollower::process_packet(PDU& packet, const timestamp_type& ts) { if (!tcp) { return; } - stream_id identifier = make_stream_id(packet); + stream_id identifier = stream_id::make_identifier(packet); streams_type::iterator iter = streams_.find(identifier); bool process = true; if (iter == streams_.end()) { @@ -173,24 +173,6 @@ Stream& StreamFollower::find_stream(const IPv6Address& client_addr, uint16_t cli return find_stream(identifier); } -StreamFollower::stream_id StreamFollower::make_stream_id(const PDU& packet) { - const TCP* tcp = packet.find_pdu(); - if (!tcp) { - throw invalid_packet(); - } - if (const IP* ip = packet.find_pdu()) { - return stream_id(stream_id::serialize(ip->src_addr()), tcp->sport(), - stream_id::serialize(ip->dst_addr()), tcp->dport()); - } - else if (const IPv6* ip = packet.find_pdu()) { - return stream_id(stream_id::serialize(ip->src_addr()), tcp->sport(), - stream_id::serialize(ip->dst_addr()), tcp->dport()); - } - else { - throw invalid_packet(); - } -} - Stream& StreamFollower::find_stream(const stream_id& id) { streams_type::iterator iter = streams_.find(id); if (iter == streams_.end()) { @@ -218,56 +200,6 @@ void StreamFollower::cleanup_streams(const timestamp_type& now) { last_cleanup_ = now; } -// stream_id - -StreamFollower::stream_id::stream_id() -: min_address_port(0), max_address_port(0) { - min_address.fill(0); - max_address.fill(0); -} - -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, max_address, min_address_port, max_address_port) < - tie(rhs.min_address, rhs.max_address, rhs.min_address_port, rhs.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); -} - -StreamFollower::stream_id::address_type StreamFollower::stream_id::serialize(IPv4Address address) { - address_type addr; - OutputMemoryStream output(addr.data(), addr.size()); - addr.fill(0); - output.write(address); - return addr; -} - -StreamFollower::stream_id::address_type StreamFollower::stream_id::serialize(const IPv6Address& address) { - address_type addr; - OutputMemoryStream output(addr.data(), addr.size()); - addr.fill(0); - output.write(address); - return addr; -} - } // TCPIP } // Tins diff --git a/src/tcp_ip/stream_identifier.cpp b/src/tcp_ip/stream_identifier.cpp new file mode 100644 index 0000000..d2dd524 --- /dev/null +++ b/src/tcp_ip/stream_identifier.cpp @@ -0,0 +1,131 @@ +/* + * 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_identifier.h" + +#if TINS_IS_CXX11 + +#include +#include +#include "memory_helpers.h" +#include "tcp.h" +#include "udp.h" +#include "ip.h" +#include "ipv6.h" +#include "exceptions.h" + +using std::swap; +using std::tie; + +using Tins::Memory::OutputMemoryStream; + +namespace Tins { +namespace TCPIP { + +StreamIdentifier::StreamIdentifier() +: min_address_port(0), max_address_port(0) { + min_address.fill(0); + max_address.fill(0); +} + +StreamIdentifier::StreamIdentifier(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 StreamIdentifier::operator<(const StreamIdentifier& rhs) const { + return tie(min_address, max_address, min_address_port, max_address_port) < + tie(rhs.min_address, rhs.max_address, rhs.min_address_port, rhs.max_address_port); +} + +bool StreamIdentifier::operator==(const StreamIdentifier& 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); +} + +StreamIdentifier StreamIdentifier::make_identifier(const PDU& packet) { + uint16_t source_port; + uint16_t dest_port; + // Extract source and dest ports + if (const TCP* tcp = packet.find_pdu()) { + source_port = tcp->sport(); + dest_port = tcp->dport(); + } + else if (const UDP* udp = packet.find_pdu()) { + source_port = udp->sport(); + dest_port = udp->dport(); + } + else { + throw invalid_packet(); + } + // Extract layer 3 and build the identifier + if (const IP* ip = packet.find_pdu()) { + return StreamIdentifier(serialize(ip->src_addr()), source_port, + serialize(ip->dst_addr()), dest_port); + } + else if (const IPv6* ip = packet.find_pdu()) { + return StreamIdentifier(serialize(ip->src_addr()), source_port, + serialize(ip->dst_addr()), dest_port); + } + else { + throw invalid_packet(); + } +} + +StreamIdentifier::address_type StreamIdentifier::serialize(IPv4Address address) { + address_type addr; + OutputMemoryStream output(addr.data(), addr.size()); + addr.fill(0); + output.write(address); + return addr; +} + +StreamIdentifier::address_type StreamIdentifier::serialize(const IPv6Address& address) { + address_type addr; + OutputMemoryStream output(addr.data(), addr.size()); + addr.fill(0); + output.write(address); + return addr; +} + +} // TCPIP +} // Tins + +#endif // TINS_IS_CXX11