Skip to content

Commit

Permalink
Add XDP example (#1265)
Browse files Browse the repository at this point in the history
* XdpDevice::receivePackets - return true if poll returns EINTR

* XdpExample - initial commit

* Add match criteria to args

* Add the rest of the features

* Add:
- Print usage
- App version
- List interfaces

* - Collect device stats (RX and TX)
- Add in-code documentation

* Add README

* Pre-commit fixes

* Add general info in `main.cpp`
  • Loading branch information
seladb authored Dec 14, 2023
1 parent 5fa0f7d commit 36913c3
Show file tree
Hide file tree
Showing 7 changed files with 752 additions and 3 deletions.
4 changes: 4 additions & 0 deletions Examples/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -52,3 +52,7 @@ endif()
if(PCAPPP_USE_PF_RING)
add_subdirectory(PfRingExample-FilterTraffic)
endif()

if(PCAPPP_USE_XDP)
add_subdirectory(XdpExample-FilterTraffic)
endif()
2 changes: 1 addition & 1 deletion Examples/PfRingExample-FilterTraffic/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ void printUsage()
<< std::endl
<< " -h|--help : Displays this help message and exits" << std::endl
<< " -v|--version : Displays the current version and exits" << std::endl
<< " -l|--list : Print the list of PF_RING devices and exists" << std::endl
<< " -l|--list : Print the list of PF_RING devices and exit" << std::endl
<< " -n|--interface-name INTERFACE_NAME : A PF_RING interface name to receive packets from." << std::endl
<< " To see all available interfaces use the -l switch" << std::endl
<< " -s|--send-matched-packets INTERFACE_NAME : PF_RING interface name to send matched packets to" << std::endl
Expand Down
12 changes: 12 additions & 0 deletions Examples/XdpExample-FilterTraffic/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
add_executable(XdpTrafficFilter main.cpp)

target_link_libraries(XdpTrafficFilter PUBLIC PcapPlusPlus::Pcap++)

set_target_properties(XdpTrafficFilter PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${PCAPPP_BINARY_EXAMPLES_DIR}")

if(PCAPPP_INSTALL)
install(
TARGETS XdpTrafficFilter
EXPORT PcapPlusPlusTargets
RUNTIME DESTINATION ${PCAPPP_INSTALL_BINDIR})
endif()
105 changes: 105 additions & 0 deletions Examples/XdpExample-FilterTraffic/PacketMatchingEngine.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
#pragma once

#include "Packet.h"
#include "IPv4Layer.h"
#include "TcpLayer.h"
#include "UdpLayer.h"
#include "SystemUtils.h"

/**
* Responsible for matching packets by match criteria received from the user. Current match criteria are a combination of zero or more of the
* following parameters: source IP, dest IP, source TCP/UDP port, dest TCP/UDP port and TCP/UDP protocol.
*/
class PacketMatchingEngine
{
private:
pcpp::IPv4Address m_SrcIpToMatch, m_DstIpToMatch;
uint16_t m_SrcPortToMatch, m_DstPortToMatch;
pcpp::ProtocolType m_ProtocolToMatch;
bool m_MatchSrcIp, m_MatchDstIp;
bool m_MatchSrcPort, m_MatchDstPort;
bool m_MatchProtocol;
public:
PacketMatchingEngine(const pcpp::IPv4Address& srcIpToMatch, const pcpp::IPv4Address& dstIpToMatch, uint16_t srcPortToMatch, uint16_t dstPortToMatch, pcpp::ProtocolType protocolToMatch)
: m_SrcIpToMatch(srcIpToMatch), m_DstIpToMatch(dstIpToMatch),
m_SrcPortToMatch(srcPortToMatch), m_DstPortToMatch(dstPortToMatch), m_ProtocolToMatch(protocolToMatch),
m_MatchSrcIp(false), m_MatchDstIp(false), m_MatchSrcPort(false), m_MatchDstPort(false), m_MatchProtocol(false)
{
if (m_SrcIpToMatch != pcpp::IPv4Address::Zero)
m_MatchSrcIp = true;
if (m_DstIpToMatch != pcpp::IPv4Address::Zero)
m_MatchDstIp = true;
if (m_SrcPortToMatch != 0)
m_MatchSrcPort = true;
if (m_DstPortToMatch != 0)
m_MatchDstPort = true;
if (m_ProtocolToMatch == pcpp::TCP || m_ProtocolToMatch == pcpp::UDP)
m_MatchProtocol = true;
}

bool isMatched(pcpp::Packet& packet)
{
if (m_MatchSrcIp || m_MatchDstIp)
{
if (!packet.isPacketOfType(pcpp::IPv4))
{
return false;
}

pcpp::IPv4Layer* ip4Layer = packet.getLayerOfType<pcpp::IPv4Layer>();
if (m_MatchSrcIp && (ip4Layer->getSrcIPv4Address() != m_SrcIpToMatch))
{
return false;
}

if (m_MatchDstIp && (ip4Layer->getDstIPv4Address() != m_DstIpToMatch))
{
return false;
}
}

if (m_MatchSrcPort || m_MatchDstPort)
{
uint16_t srcPort, dstPort;
if (packet.isPacketOfType(pcpp::TCP))
{
srcPort = packet.getLayerOfType<pcpp::TcpLayer>()->getSrcPort();
dstPort = packet.getLayerOfType<pcpp::TcpLayer>()->getDstPort();
}
else if (packet.isPacketOfType(pcpp::UDP))
{
srcPort = packet.getLayerOfType<pcpp::UdpLayer>()->getSrcPort();
dstPort = packet.getLayerOfType<pcpp::UdpLayer>()->getDstPort();
}
else
{
return false;
}

if (m_MatchSrcPort && (srcPort != m_SrcPortToMatch))
{
return false;
}

if (m_MatchDstPort && (dstPort != m_DstPortToMatch))
{
return false;
}
}

if (m_MatchProtocol)
{
if (m_ProtocolToMatch == pcpp::TCP && (!packet.isPacketOfType(pcpp::TCP)))
{
return false;
}

if (m_ProtocolToMatch == pcpp::UDP && (!packet.isPacketOfType(pcpp::UDP)))
{
return false;
}
}

return true;
}
};
36 changes: 36 additions & 0 deletions Examples/XdpExample-FilterTraffic/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
Filter Traffic AF_XDP example application
=========================================

This application demonstrates PcapPlusPlus AF_XDP APIs.

It opens an AF_XDP socket, receives all packets on the socket and matches them by user-defined matching criteria such as source/dest IP, source/dest TCP/UDP port and more.
Matched packets can be sent to another AF_XDP socket (or to the same socket), and/or be saved to a pcap file.

In addition, the application collect statistics on received, sent and matched packets: total RX/TX, number of packets per protocol, number of matched flows and number of matched packets.

Important:
----------
- This application runs only on Linux (XDP is not supported on non-Linux platforms)
- In order to build this application follow the instructions on how to build PcapPlusPlus with XDP
- This application (like all applications using XDP) should be run as 'sudo'

Using the utility
-----------------
Basic usage:
XdpTrafficFilter [-hvl] [-s INTERFACE_NAME] [-f FILENAME] [-i IPV4_ADDR] [-I IPV4_ADDR] [-p PORT] [-P PORT] [-r PROTOCOL] -n INTERFACE_NAME

Options:
-h|--help : Displays this help message and exits
-v|--version : Displays the current version and exits
-l|--list : Print the list of network interfaces and exit
-n|--interface-name INTERFACE_NAME : An interface name to open AF_XDP socket and receive packets from.
To see all available interfaces use the -l switch
-s|--send-matched-packets INTERFACE_NAME : Network interface name to send matched packets to.
The app will open another AF_XDP socket for sending packets.
Note: this interface can be the same one used to receive packets.
-f|--save-matched-packets FILEPATH : Save matched packets to pcap files under FILEPATH.
-i|--match-source-ip IPV4_ADDR : Match source IPv4 address
-I|--match-dest-ip IPV4_ADDR : Match destination IPv4 address
-p|--match-source-port PORT : Match source TCP/UDP port
-P|--match-dest-port PORT : Match destination TCP/UDP port
-r|--match-protocol PROTOCOL : Match protocol. Valid values are 'TCP' or 'UDP'
Loading

0 comments on commit 36913c3

Please sign in to comment.