Skip to content

Commit

Permalink
Centralize code for fetching pcap devices. (#1434)
Browse files Browse the repository at this point in the history
* Added device utilities header for pcap device utility functions.

Added memory utilities header for smart pointer utilities.

* Replaced usages of pcap_findalldevs(_ex) with internal::getAll(Local/Remote)PcapDevices.

* Removed code creating pcap_capture string as it is unused.

* Fixed returning nullptr on clone fail.

* Renamed MemoryUtils to PcapUtils.

* Moved getAllRemotePcapDevices to anonymous namespace in PcapRemoteDeviceList.cpp

* Removed duplicate of PcapCloseDeleter.

* Remoted internal utilitiy headers from the public header list.

* Removed unused forward declare.

* Added doxygen conditionals to exclude the internal classes from the public documentation.
  • Loading branch information
Dimi1010 authored Jun 8, 2024
1 parent 62c874f commit 93eca5b
Show file tree
Hide file tree
Showing 9 changed files with 178 additions and 65 deletions.
2 changes: 2 additions & 0 deletions Pcap++/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
add_library(
Pcap++
src/DeviceUtils.cpp
$<$<BOOL:${PCAPPP_USE_DPDK}>:src/DpdkDevice.cpp>
$<$<BOOL:${PCAPPP_USE_DPDK}>:src/DpdkDeviceList.cpp>
$<$<BOOL:${PCAPPP_USE_DPDK_KNI}>:src/KniDevice.cpp>
$<$<BOOL:${PCAPPP_USE_DPDK_KNI}>:src/KniDeviceList.cpp>
$<$<BOOL:${LINUX}>:src/LinuxNicInformationSocket.cpp>
$<$<BOOL:${PCAPPP_USE_DPDK}>:src/MBufRawPacket.cpp>
src/PcapUtils.cpp
src/NetworkUtils.cpp
src/PcapFileDevice.cpp
src/PcapDevice.cpp
Expand Down
24 changes: 24 additions & 0 deletions Pcap++/header/DeviceUtils.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
#pragma once

/// @file

#include <memory>
#include "IpAddress.h"
#include "PcapUtils.h"

namespace pcpp
{
/// @cond PCPP_INTERNAL

namespace internal
{
/**
* Fetches a list of all network devices on the local machine that LibPcap/WinPcap/NPcap can find.
* @return A smart pointer to an interface list structure.
* @throws std::runtime_error The system encountered an error fetching the devices.
*/
std::unique_ptr<pcap_if_t, PcapFreeAllDevsDeleter> getAllLocalPcapDevices();
}

/// @endcond
}
35 changes: 35 additions & 0 deletions Pcap++/header/PcapUtils.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
#pragma once

// Forward declarations
struct pcap;
typedef pcap pcap_t;
struct pcap_if;
typedef pcap_if pcap_if_t;

namespace pcpp
{
/// @cond PCPP_INTERNAL

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

/**
* @class PcapFreeAllDevsDeleter
* A deleter that frees an interface list of pcap_if_t ptr by calling 'pcap_freealldevs' function on it.
*/
struct PcapFreeAllDevsDeleter
{
void operator()(pcap_if_t* ptr) const;
};
}

/// @endcond
}
27 changes: 27 additions & 0 deletions Pcap++/src/DeviceUtils.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
#include "DeviceUtils.h"

#include <array>
#include <string>

#include "pcap.h"
#include "Logger.h"
#include "IpAddress.h"

namespace pcpp
{
namespace internal
{
std::unique_ptr<pcap_if_t, PcapFreeAllDevsDeleter> getAllLocalPcapDevices()
{
pcap_if_t* interfaceListRaw;
std::array<char, PCAP_ERRBUF_SIZE> errbuf;
int err = pcap_findalldevs(&interfaceListRaw, errbuf.data());
if (err < 0)
{
throw std::runtime_error("Error searching for devices: " + std::string(errbuf.begin(), errbuf.end()));
}
// Assigns the raw pointer to the smart pointer with specialized deleter.
return std::unique_ptr<pcap_if_t, internal::PcapFreeAllDevsDeleter>(interfaceListRaw);
}
}
}
12 changes: 2 additions & 10 deletions Pcap++/src/PcapFilter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#include "PcapFilter.h"
#include "Logger.h"
#include "IPv4Layer.h"
#include "PcapUtils.h"
#include <sstream>
#include <array>
#if defined(_WIN32)
Expand Down Expand Up @@ -35,15 +36,6 @@ namespace internal
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() : m_LinkType(LinkLayerType::LINKTYPE_ETHERNET) {}
Expand All @@ -66,7 +58,7 @@ bool BpfFilterWrapper::setFilter(const std::string& filter, LinkLayerType linkTy

if (filter != m_FilterStr || linkType != m_LinkType)
{
std::unique_ptr<pcap_t, internal::PcapTDeleter> pcap = std::unique_ptr<pcap_t, internal::PcapTDeleter>(pcap_open_dead(linkType, DEFAULT_SNAPLEN));
auto pcap = std::unique_ptr<pcap_t, internal::PcapCloseDeleter>(pcap_open_dead(linkType, DEFAULT_SNAPLEN));
if (pcap == nullptr)
{
return false;
Expand Down
37 changes: 17 additions & 20 deletions Pcap++/src/PcapLiveDevice.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
#define LOG_MODULE PcapLogModuleLiveDevice

#include "IpUtils.h"
#include "DeviceUtils.h"
#include "PcapUtils.h"
#include "PcapLiveDevice.h"
#include "PcapLiveDeviceList.h"
#include "Packet.h"
Expand All @@ -11,7 +13,7 @@
#include <thread>
#include "Logger.h"
#include "SystemUtils.h"
#include <string.h>
#include <cstring>
#include <iostream>
#include <fstream>
#include <chrono>
Expand Down Expand Up @@ -405,32 +407,27 @@ void PcapLiveDevice::close()

PcapLiveDevice* PcapLiveDevice::clone() const
{
PcapLiveDevice* retval = nullptr;

pcap_if_t* interfaceList;
char errbuf[PCAP_ERRBUF_SIZE];
int err = pcap_findalldevs(&interfaceList, errbuf);
if (err < 0)
std::unique_ptr<pcap_if_t, internal::PcapFreeAllDevsDeleter> interfaceList;
try
{
interfaceList = internal::getAllLocalPcapDevices();
}
catch (const std::exception& e)
{
PCPP_LOG_ERROR("Error searching for devices: " << errbuf);
PCPP_LOG_ERROR(e.what());
return nullptr;
}

pcap_if_t* currInterface = interfaceList;
while (currInterface != nullptr)
for (pcap_if_t* currInterface = interfaceList.get(); currInterface != nullptr; currInterface = currInterface->next)
{
if(!strcmp(currInterface->name, getName().c_str()))
break;
currInterface = currInterface->next;
if (!std::strcmp(currInterface->name, getName().c_str()))
{
return cloneInternal(*currInterface);
}
}

if(currInterface)
retval = cloneInternal(*currInterface);
else
PCPP_LOG_ERROR("Can't find interface " << getName().c_str());

pcap_freealldevs(interfaceList);
return retval;
PCPP_LOG_ERROR("Can't find interface " << getName().c_str());
return nullptr;
}

PcapLiveDevice* PcapLiveDevice::cloneInternal(pcap_if_t& devInterface) const
Expand Down
22 changes: 11 additions & 11 deletions Pcap++/src/PcapLiveDeviceList.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
#include "IpAddressUtils.h"
#include "PcapLiveDeviceList.h"
#include "Logger.h"
#include "PcapUtils.h"
#include "DeviceUtils.h"
#include "SystemUtils.h"
#include "pcap.h"
#include <string.h>
Expand Down Expand Up @@ -39,32 +41,30 @@ PcapLiveDeviceList::~PcapLiveDeviceList()

void PcapLiveDeviceList::init()
{
pcap_if_t* interfaceList;
char errbuf[PCAP_ERRBUF_SIZE];
int err = pcap_findalldevs(&interfaceList, errbuf);
if (err < 0)
std::unique_ptr<pcap_if_t, internal::PcapFreeAllDevsDeleter> interfaceList;
try
{
interfaceList = internal::getAllLocalPcapDevices();
}
catch (const std::exception& e)
{
PCPP_LOG_ERROR("Error searching for devices: " << errbuf);
PCPP_LOG_ERROR(e.what());
}

PCPP_LOG_DEBUG("Pcap lib version info: " << IPcapDevice::getPcapLibVersionInfo());

pcap_if_t* currInterface = interfaceList;
while (currInterface != nullptr)

for (pcap_if_t* currInterface = interfaceList.get(); currInterface != nullptr; currInterface = currInterface->next)
{
#if defined(_WIN32)
PcapLiveDevice* dev = new WinPcapLiveDevice(currInterface, true, true, true);
#else //__linux__, __APPLE__, __FreeBSD__
PcapLiveDevice* dev = new PcapLiveDevice(currInterface, true, true, true);
#endif
currInterface = currInterface->next;
m_LiveDeviceList.insert(m_LiveDeviceList.end(), dev);
}

setDnsServers();

PCPP_LOG_DEBUG("Freeing live device data");
pcap_freealldevs(interfaceList);
}

void PcapLiveDeviceList::setDnsServers()
Expand Down
71 changes: 47 additions & 24 deletions Pcap++/src/PcapRemoteDeviceList.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include "PcapRemoteDeviceList.h"
#include "Logger.h"
#include "IpUtils.h"
#include "PcapUtils.h"
#include "IpAddressUtils.h"
#include "pcap.h"
#include <array>
Expand All @@ -13,58 +14,80 @@
namespace pcpp
{

namespace
{
/**
* Fetches a list of all network devices on a remote machine that WinPcap/NPcap can find.
* @param[in] ipAddress IP address of the remote machine.
* @param[in] port Port to use when connecting to the remote machine.
* @param[in] pRmAuth Pointer to an authentication structure to use when connecting to the remote machine. Nullptr if no authentication is required.
* @return A smart pointer to an interface list structure.
* @throws std::runtime_error The system encountered an error fetching the devices.
*/
std::unique_ptr<pcap_if_t, internal::PcapFreeAllDevsDeleter> getAllRemotePcapDevices(const IPAddress& ipAddress, uint16_t port, pcap_rmtauth* pRmAuth = nullptr)
{
PCPP_LOG_DEBUG("Searching remote devices on IP: " << ipAddress << " and port: " << port);
std::array<char, PCAP_BUF_SIZE> remoteCaptureString;
std::array<char, PCAP_ERRBUF_SIZE> errorBuf;
if (pcap_createsrcstr(remoteCaptureString.data(), PCAP_SRC_IFREMOTE, ipAddress.toString().c_str(),
std::to_string(port).c_str(), nullptr, errorBuf.data()) != 0)
{
throw std::runtime_error("Error creating the remote connection string. Error: " +
std::string(errorBuf.begin(), errorBuf.end()));
}

PCPP_LOG_DEBUG("Remote capture string: " << remoteCaptureString.data());

pcap_if_t* interfaceListRaw;
if (pcap_findalldevs_ex(remoteCaptureString.data(), pRmAuth, &interfaceListRaw, errorBuf.data()) < 0)
{
throw std::runtime_error("Error retrieving device on remote machine. Error: " +
std::string(errorBuf.begin(), errorBuf.end()));
}
return std::unique_ptr<pcap_if_t, internal::PcapFreeAllDevsDeleter>(interfaceListRaw);
}
}

PcapRemoteDeviceList* PcapRemoteDeviceList::getRemoteDeviceList(const IPAddress& ipAddress, uint16_t port)
{
return PcapRemoteDeviceList::getRemoteDeviceList(ipAddress, port, NULL);
}

PcapRemoteDeviceList* PcapRemoteDeviceList::getRemoteDeviceList(const IPAddress& ipAddress, uint16_t port, PcapRemoteAuthentication* remoteAuth)
{
PCPP_LOG_DEBUG("Searching remote devices on IP: " << ipAddress << " and port: " << port);
char remoteCaptureString[PCAP_BUF_SIZE];
char errbuf[PCAP_ERRBUF_SIZE];
std::ostringstream portAsString;
portAsString << port;
if (pcap_createsrcstr(remoteCaptureString, PCAP_SRC_IFREMOTE, ipAddress.toString().c_str(), portAsString.str().c_str(), NULL, errbuf) != 0)
{
PCPP_LOG_ERROR("Error in creating the remote connection string. Error was: " << errbuf);
return NULL;
}

PCPP_LOG_DEBUG("Remote capture string: " << remoteCaptureString);

pcap_rmtauth* pRmAuth = NULL;
pcap_rmtauth* pRmAuth = nullptr;
pcap_rmtauth rmAuth;
if (remoteAuth != NULL)
if (remoteAuth != nullptr)
{
PCPP_LOG_DEBUG("Authentication requested. Username: " << remoteAuth->userName << ", Password: " << remoteAuth->password);
rmAuth = remoteAuth->getPcapRmAuth();
pRmAuth = &rmAuth;
}

pcap_if_t* interfaceList;
char errorBuf[PCAP_ERRBUF_SIZE];
if (pcap_findalldevs_ex(remoteCaptureString, pRmAuth, &interfaceList, errorBuf) < 0)
std::unique_ptr<pcap_if_t, internal::PcapFreeAllDevsDeleter> interfaceList;
try
{
PCPP_LOG_ERROR("Error retrieving device on remote machine. Error string is: " << errorBuf);
return NULL;
interfaceList = getAllRemotePcapDevices(ipAddress, port, pRmAuth);
}
catch (const std::exception& e)
{
PCPP_LOG_ERROR(e.what());
return nullptr;
}

PcapRemoteDeviceList* resultList = new PcapRemoteDeviceList();
resultList->setRemoteMachineIpAddress(ipAddress);
resultList->setRemoteMachinePort(port);
resultList->setRemoteAuthentication(remoteAuth);

pcap_if_t* currInterface = interfaceList;
while (currInterface != NULL)

for (pcap_if_t* currInterface = interfaceList.get(); currInterface != nullptr; currInterface = currInterface->next)
{
PcapRemoteDevice* pNewRemoteDevice = new PcapRemoteDevice(currInterface, resultList->m_RemoteAuthentication,
resultList->getRemoteMachineIpAddress(), resultList->getRemoteMachinePort());
resultList->m_RemoteDeviceList.push_back(pNewRemoteDevice);
currInterface = currInterface->next;
}

pcap_freealldevs(interfaceList);
return resultList;
}

Expand Down
13 changes: 13 additions & 0 deletions Pcap++/src/PcapUtils.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#include "PcapUtils.h"

#include "pcap.h"

namespace pcpp
{
namespace internal
{
void PcapCloseDeleter::operator()(pcap_t* ptr) const { pcap_close(ptr); }

void PcapFreeAllDevsDeleter::operator()(pcap_if_t* ptr) const { pcap_freealldevs(ptr); }
}
}

0 comments on commit 93eca5b

Please sign in to comment.