1
0
mirror of https://github.com/mfontanini/libtins synced 2026-01-23 02:35:57 +01:00

Added OfflinePacketFilter class.

This commit is contained in:
Matias Fontanini
2014-08-30 23:01:46 -03:00
parent 07be8e244c
commit a7a4105cf8
6 changed files with 303 additions and 0 deletions

View File

@@ -44,6 +44,9 @@ class PPI;
/**
* \brief Maps a libtins link layer PDU to a libpcap data link identifier.
*
* This should be instantiated with any object that represents a
* link layer PDU (EthernetII, Dot11, RadioTap, etc)
*/
template<typename T>
struct DataLinkType;

View File

@@ -0,0 +1,133 @@
/*
* Copyright (c) 2014, 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_OFFLINE_PACKET_FILTER_H
#define TINS_OFFLINE_PACKET_FILTER_H
#include <string>
#include <stdint.h>
#include "data_link_type.h"
namespace Tins {
class PDU;
/**
* \class OfflinePacketFilter
*
* \brief Wraps a pcap filter and matches it against a packet or buffer.
*
* This is a thin wrapper over <i>pcap_offline_filter</i>. You can use
* it to perform packet filtering outside of Sniffer instances.
*
* A potential use case would be if you are capturing packets that are
* sent from another host over UDP. You would recieve UDP packets, then
* parse their content, and apply the OfflinePacketFilter over the
* wrapped packet.
*/
class OfflinePacketFilter {
public:
/**
* Constructs an OfflinePacketFilter object.
*
* \param filter The pcap filter to use.
* \param lt The link layer type to use.
* \param snap_len The snapshot length to use.
*/
template<typename T>
OfflinePacketFilter(const std::string& filter, const DataLinkType<T>& lt,
unsigned int snap_len = 65535)
: string_filter(filter)
{
init(filter, lt.get_type(), snap_len);
}
/**
* \brief Copy constructor.
*
* Note that during copy construction the pcap filter is
* recompiled. Therefore, it might be somehow expensive to
* copy OfflinePacketFilters.
*
* \param other The filter to be copied.
*/
OfflinePacketFilter(const OfflinePacketFilter& other);
/**
* \brief Copy assignment operator.
*
* \param other The filter to be copied.
*
* \sa OfflinePacketFilter
*/
OfflinePacketFilter& operator=(const OfflinePacketFilter& other);
/**
* Releases the compiled pcap filter and handle.
*/
~OfflinePacketFilter();
/**
* \brief Applies the compiled filter on the provided buffer.
*
* This method uses <i>pcap_offline_filter</i> on the provided buffer
* and returns a bool indicating if the packet pointed by the buffer
* matches the filter.
*
* \param buffer A pointer to a buffer which holds a raw packet.
* \param total_sz The length of the buffer pointed by buffer.
* \return true iff the packet matches the filter.
*/
bool matches_filter(const uint8_t* buffer, uint32_t total_sz) const;
/**
* \brief Applies the compiled filter on the provided packet.
*
* This method checks whether the provided packet matches the filter.
* Since this uses pcap filters and they work over a raw data buffer,
* this method serialices the packet and then applies the filter.
* Therefore, this can be quite expensive to use. If you have access
* to the packet before constructing a PDU from it, it is recommended
* to use the other overload over the raw buffer.
*
* \param pdu The packet to be matched against the filter.
* \return true iff the packet matches the filter.
*/
bool matches_filter(PDU& pdu) const;
private:
void init(const std::string& pcap_filter, int link_type,
unsigned int snap_len);
pcap_t* handle;
mutable bpf_program filter;
std::string string_filter;
};
} // Tins
#endif // TINS_OFFLINE_PACKET_FILTER_H

View File

@@ -33,6 +33,7 @@ ADD_LIBRARY(
llc.cpp
loopback.cpp
network_interface.cpp
offline_packet_filter.cpp
packet_sender.cpp
packet_writer.cpp
ppi.cpp

View File

@@ -0,0 +1,86 @@
/*
* Copyright (c) 2014, 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 <stdexcept>
#include "offline_packet_filter.h"
#include "pdu.h"
namespace Tins {
OfflinePacketFilter::OfflinePacketFilter(const OfflinePacketFilter& other)
{
*this = other;
}
OfflinePacketFilter& OfflinePacketFilter::operator=(const OfflinePacketFilter& other)
{
string_filter = other.string_filter;
init(string_filter, pcap_datalink(other.handle), pcap_snapshot(other.handle));
return *this;
}
OfflinePacketFilter::~OfflinePacketFilter()
{
pcap_freecode(&filter);
pcap_close(handle);
}
void OfflinePacketFilter::init(const std::string& pcap_filter, int link_type,
unsigned int snap_len)
{
handle = pcap_open_dead(
link_type,
snap_len
);
if(pcap_compile(handle, &filter, pcap_filter.c_str(), 1, 0xffffffff) == -1)
{
throw std::runtime_error(pcap_geterr(handle));
}
}
bool OfflinePacketFilter::matches_filter(const uint8_t* buffer,
uint32_t total_sz) const
{
pcap_pkthdr header = {};
header.len = total_sz;
header.caplen = total_sz;
return pcap_offline_filter(
&filter,
&header,
buffer
);
}
bool OfflinePacketFilter::matches_filter(PDU& pdu) const
{
PDU::serialization_type buffer = pdu.serialize();
return matches_filter(&buffer[0], buffer.size());
}
} // Tins

View File

@@ -54,6 +54,7 @@ ADD_CUSTOM_TARGET(
LLCTest
MatchesResponseTest
NetworkInterfaceTest
OfflinePacketFilterTest
PDUTest
PPITest
PPPoETest
@@ -93,6 +94,7 @@ ADD_EXECUTABLE(IPv6AddressTest EXCLUDE_FROM_ALL ipv6address.cpp)
ADD_EXECUTABLE(LLCTest EXCLUDE_FROM_ALL llc.cpp)
ADD_EXECUTABLE(MatchesResponseTest EXCLUDE_FROM_ALL matches_response.cpp)
ADD_EXECUTABLE(NetworkInterfaceTest EXCLUDE_FROM_ALL network_interface.cpp)
ADD_EXECUTABLE(OfflinePacketFilterTest EXCLUDE_FROM_ALL offline_packet_filter.cpp)
ADD_EXECUTABLE(PDUTest EXCLUDE_FROM_ALL pdu.cpp)
ADD_EXECUTABLE(PPITest EXCLUDE_FROM_ALL ppi.cpp)
ADD_EXECUTABLE(PPPoETest EXCLUDE_FROM_ALL pppoe.cpp)
@@ -170,6 +172,7 @@ ADD_TEST(IPv6Address IPv6AddressTest)
ADD_TEST(LLC LLCTest)
ADD_TEST(MatchesResponse MatchesResponseTest)
ADD_TEST(NetworkInterface NetworkInterfaceTest)
ADD_TEST(OfflinePacketFilter OfflinePacketFilterTest)
ADD_TEST(PDU PDUTest)
ADD_TEST(PPI PPITest)
ADD_TEST(PPPoE PPPoETest)

View File

@@ -0,0 +1,77 @@
#include <gtest/gtest.h>
#include <cstring>
#include <string>
#include <stdint.h>
#include "offline_packet_filter.h"
#include "ip.h"
#include "tcp.h"
#include "ethernetII.h"
#include "dot3.h"
#include "sll.h"
#include "llc.h"
#include "udp.h"
#include "rawpdu.h"
using namespace Tins;
class OfflinePacketFilterTest : public testing::Test {
public:
};
TEST_F(OfflinePacketFilterTest, CopyConstructor) {
OfflinePacketFilter filter1("udp and port 111", DataLinkType<EthernetII>());
OfflinePacketFilter filter2(filter1);
OfflinePacketFilter filter3("tcp", DataLinkType<RadioTap>());
filter3 = filter1;
{
EthernetII pkt = EthernetII() / IP() / UDP(111, 11) / RawPDU("test");
EXPECT_TRUE(filter1.matches_filter(pkt));
EXPECT_TRUE(filter2.matches_filter(pkt));
EXPECT_TRUE(filter3.matches_filter(pkt));
}
{
EthernetII pkt = EthernetII() / IP() / TCP(111, 11) / RawPDU("test");
EXPECT_FALSE(filter1.matches_filter(pkt));
EXPECT_FALSE(filter2.matches_filter(pkt));
EXPECT_FALSE(filter3.matches_filter(pkt));
}
}
TEST_F(OfflinePacketFilterTest, MatchesFilterEthTcp) {
OfflinePacketFilter filter("ip and port 55", DataLinkType<EthernetII>());
{
EthernetII pkt = EthernetII() / IP() / TCP(55, 11) / RawPDU("test");
EXPECT_TRUE(filter.matches_filter(pkt));
}
{
EthernetII pkt = EthernetII() / IP() / TCP(45, 11) / RawPDU("test");
EXPECT_FALSE(filter.matches_filter(pkt));
}
}
TEST_F(OfflinePacketFilterTest, MatchesFilterEth) {
OfflinePacketFilter filter("ether dst 00:01:02:03:04:05", DataLinkType<EthernetII>());
{
EthernetII pkt = EthernetII("00:01:02:03:04:05") / IP() / TCP(55, 11) / RawPDU("test");
EXPECT_TRUE(filter.matches_filter(pkt));
}
{
EthernetII pkt = EthernetII() / IP() / TCP(45, 11) / RawPDU("test");
EXPECT_FALSE(filter.matches_filter(pkt));
}
}
TEST_F(OfflinePacketFilterTest, MatchesFilterSLLTcp) {
OfflinePacketFilter filter("ip and port 55", DataLinkType<SLL>());
{
SLL pkt = SLL() / IP() / TCP(55, 11) / RawPDU("test");
EXPECT_TRUE(filter.matches_filter(pkt));
}
{
SLL pkt = SLL() / IP() / TCP(45, 11) / RawPDU("test");
EXPECT_FALSE(filter.matches_filter(pkt));
}
}