Skip to content

Commit

Permalink
Changed BpfFilterWrapper to use smart pointers internally. (#1382)
Browse files Browse the repository at this point in the history
* Changed BpfFilterWrapper to use unique_ptr with custom deleter instead of manually handling the raw bpf_program pointer.
Added BpfProgramDeleter class to clean up bpf_program's held inside unique_ptr objects.

* Marked deleter method as const.

* Renamed namespace 'detail' to 'internal', merging it with the existing 'internal' namespace.

* Added deleter struct for 'pcap_t' calling 'pcap_close'.

Changed 'pcap_t' raw ptr to use smart pointer in 'setFilter'.

* Changed bpf_program construction to utilize unique_ptrs everywhere.

* Removed unnessesary call to `freeProgram`.

* Added copy ctor and assignment operators as the inclusion of 'unique_ptr' disabled the implicitly declared ones.

* Documentation update.

* Simplified BpfFilterWrapper default ctor.
  • Loading branch information
Dimi1010 authored May 6, 2024
1 parent 0d1ed9a commit 6d924cf
Show file tree
Hide file tree
Showing 2 changed files with 55 additions and 25 deletions.
30 changes: 25 additions & 5 deletions Pcap++/header/PcapFilter.h
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,18 @@ namespace pcpp
LESS_OR_EQUAL
} FilterOperator;

namespace internal
{
/**
* @class BpfProgramDeleter
* A deleter that cleans up a bpf_program object.
*/
struct BpfProgramDeleter
{
void operator()(bpf_program* ptr) const;
};
}

/**
* @class BpfFilterWrapper
* A wrapper class for BPF filtering. Enables setting a BPF filter and matching it against a packet
Expand All @@ -78,7 +90,7 @@ namespace pcpp
private:
std::string m_FilterStr;
LinkLayerType m_LinkType;
bpf_program* m_Program;
std::unique_ptr<bpf_program, internal::BpfProgramDeleter> m_Program;

void freeProgram();

Expand All @@ -90,9 +102,17 @@ namespace pcpp
BpfFilterWrapper();

/**
* A d'tor for this class. Makes sure to clear the bpf_program object if was previously set.
* A copy constructor for this class.
* @param[in] other The instance to copy from
*/
BpfFilterWrapper(const BpfFilterWrapper& other);

/**
* A copy assignment operator for this class.
* @param[in] other An instance of IPNetwork to assign
* @return A reference to the assignee
*/
~BpfFilterWrapper();
BpfFilterWrapper& operator=(const BpfFilterWrapper& other);

/**
* Set a filter. This method receives a filter in BPF syntax (https://biot.com/capstats/bpf.html) and an optional link type,
Expand Down Expand Up @@ -618,7 +638,7 @@ namespace pcpp
OR,
};

namespace detail
namespace internal
{
/* Could potentially be moved into CompositeLogicFilter as a private member function, with if constexpr when C++17 is the minimum supported standard.*/
/**
Expand Down Expand Up @@ -651,7 +671,7 @@ namespace pcpp
result += '(' + innerFilter + ')';
if (m_FilterList.cend() - 1 != it)
{
result += detail::getCompositeLogicOpDelimiter<op>();
result += internal::getCompositeLogicOpDelimiter<op>();
}
}
}
Expand Down
50 changes: 30 additions & 20 deletions Pcap++/src/PcapFilter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,15 +28,32 @@ bool GeneralFilter::matchPacketWithFilter(RawPacket* rawPacket)
return m_BpfWrapper.matchPacketWithFilter(rawPacket);
}

BpfFilterWrapper::BpfFilterWrapper()
namespace internal
{
m_Program = nullptr;
m_LinkType = LINKTYPE_ETHERNET;
void BpfProgramDeleter::operator()(bpf_program* ptr) const
{
pcap_freecode(ptr);
delete ptr;
}

/**
* @class PcapTDeleter
* A deleter that cleans up a pcap_t structure by calling pcap_close.
*/
struct PcapTDeleter
{
void operator()(pcap_t* ptr) const { pcap_close(ptr); }
};
}

BpfFilterWrapper::~BpfFilterWrapper()
BpfFilterWrapper::BpfFilterWrapper() : m_LinkType(LinkLayerType::LINKTYPE_ETHERNET) {}

BpfFilterWrapper::BpfFilterWrapper(const BpfFilterWrapper& other) : BpfFilterWrapper() { setFilter(other.m_FilterStr, other.m_LinkType); }

BpfFilterWrapper& BpfFilterWrapper::operator=(const BpfFilterWrapper &other)
{
freeProgram();
setFilter(other.m_FilterStr, other.m_LinkType);
return *this;
}

bool BpfFilterWrapper::setFilter(const std::string& filter, LinkLayerType linkType)
Expand All @@ -49,23 +66,21 @@ bool BpfFilterWrapper::setFilter(const std::string& filter, LinkLayerType linkTy

if (filter != m_FilterStr || linkType != m_LinkType)
{
pcap_t* pcap = pcap_open_dead(linkType, DEFAULT_SNAPLEN);
std::unique_ptr<pcap_t, internal::PcapTDeleter> pcap = std::unique_ptr<pcap_t, internal::PcapTDeleter>(pcap_open_dead(linkType, DEFAULT_SNAPLEN));
if (pcap == nullptr)
{
return false;
}

bpf_program* newProg = new bpf_program;
int ret = pcap_compile(pcap, newProg, filter.c_str(), 1, 0);
pcap_close(pcap);
std::unique_ptr<bpf_program> newProg = std::unique_ptr<bpf_program>(new bpf_program);
int ret = pcap_compile(pcap.get(), newProg.get(), filter.c_str(), 1, 0);
if (ret < 0)
{
delete newProg;
return false;
}

freeProgram();
m_Program = newProg;
// Reassigns ownership of the bpf program to a new unique_ptr with a custom deleter as it now requires specialized cleanup.
m_Program = std::unique_ptr<bpf_program, internal::BpfProgramDeleter>(newProg.release());
m_FilterStr = filter;
m_LinkType = linkType;
}
Expand All @@ -75,13 +90,8 @@ bool BpfFilterWrapper::setFilter(const std::string& filter, LinkLayerType linkTy

void BpfFilterWrapper::freeProgram()
{
if (m_Program != nullptr)
{
pcap_freecode(m_Program);
delete m_Program;
m_Program = nullptr;
m_FilterStr.clear();
}
m_Program = nullptr;
m_FilterStr.clear();
}

bool BpfFilterWrapper::matchPacketWithFilter(const RawPacket* rawPacket)
Expand All @@ -104,7 +114,7 @@ bool BpfFilterWrapper::matchPacketWithFilter(const uint8_t* packetData, uint32_t
pktHdr.len = packetDataLength;
TIMESPEC_TO_TIMEVAL(&pktHdr.ts, &packetTimestamp);

return (pcap_offline_filter(m_Program, &pktHdr, packetData) != 0);
return (pcap_offline_filter(m_Program.get(), &pktHdr, packetData) != 0);
}

void BPFStringFilter::parseToString(std::string& result)
Expand Down

0 comments on commit 6d924cf

Please sign in to comment.