From a181f2f6c9fa6e5e6e04c63366e3ad1c89cab7b5 Mon Sep 17 00:00:00 2001 From: Leo Parente <23251360+leoparente@users.noreply.github.com> Date: Wed, 28 Oct 2026 14:23:26 -0300 Subject: [PATCH] fix(inputs/pcap): look up iface by name unless it is an address PcapInputStream::start assigned the iface string to both an IPv4Address and an IPv6Address. Since PcapPlusPlus 24.09 those constructors throw std::invalid_argument on a string that is not an address, so live capture failed for every value: "eth0", "auto" and an IPv4 literal with "Not a valid IPv4/IPv6 address". Parse the value as an address only when it is one, as the flow and netprobe inputs already do; anything else is looked up by name, as with PcapPlusPlus 23.09. Co-Authored-By: Claude Opus 5.5 --- src/inputs/pcap/CMakeLists.txt | 1 + src/inputs/pcap/PcapInputStream.cpp | 8 ++++-- src/inputs/pcap/tests/test_iface.cpp | 39 ++++++++++++++++++++++++++++ 3 files changed, 46 insertions(+), 2 deletions(-) create mode 100644 src/inputs/pcap/tests/test_iface.cpp diff --git a/src/inputs/pcap/CMakeLists.txt b/src/inputs/pcap/CMakeLists.txt index 72667035f..789a992e2 100644 --- a/src/inputs/pcap/CMakeLists.txt +++ b/src/inputs/pcap/CMakeLists.txt @@ -22,6 +22,7 @@ set(VISOR_STATIC_PLUGINS ${VISOR_STATIC_PLUGINS} Visor::Input::Pcap PARENT_SCOPE ## TEST SUITE add_executable(unit-tests-input-pcap + tests/test_iface.cpp tests/test_mock_traffic.cpp tests/test_parse_pcap.cpp) diff --git a/src/inputs/pcap/PcapInputStream.cpp b/src/inputs/pcap/PcapInputStream.cpp index 5deb2f40b..95f695692 100644 --- a/src/inputs/pcap/PcapInputStream.cpp +++ b/src/inputs/pcap/PcapInputStream.cpp @@ -155,8 +155,12 @@ void PcapInputStream::start() } config_set("iface", TARGET); } - interfaceIP4 = TARGET; - interfaceIP6 = TARGET; + // iface is an interface name or an address; parsing a name as an address throws + if (pcpp::IPv4Address::isValidIPv4Address(TARGET)) { + interfaceIP4 = pcpp::IPv4Address(TARGET); + } else if (pcpp::IPv6Address::isValidIPv6Address(TARGET)) { + interfaceIP6 = pcpp::IPv6Address(TARGET); + } } std::string ifNameList = _get_interface_list(); diff --git a/src/inputs/pcap/tests/test_iface.cpp b/src/inputs/pcap/tests/test_iface.cpp new file mode 100644 index 000000000..9b913a22c --- /dev/null +++ b/src/inputs/pcap/tests/test_iface.cpp @@ -0,0 +1,39 @@ +#include "PcapInputStream.h" +#include +#include + +using namespace visor::input::pcap; +using Catch::Matchers::StartsWith; + +// iface may be an interface name or an address, and only an address may be parsed as one. The addresses +// are reserved for documentation (RFC 5737, RFC 3849), so the lookup fails before any capture opens. +TEST_CASE("iface accepts a name, an IPv4 address or an IPv6 address", "[pcap][iface]") +{ + SECTION("name") + { + PcapInputStream stream{"pcap-test"}; + stream.config_set("iface", "pktvisor-test0"); + CHECK_THROWS_WITH(stream.start(), StartsWith("Couldn't find interface by provided name: \"pktvisor-test0\"")); + } + + SECTION("IPv4 address") + { + PcapInputStream stream{"pcap-test"}; + stream.config_set("iface", "192.0.2.1"); + CHECK_THROWS_WITH(stream.start(), "Couldn't find interface by provided IP: 192.0.2.1"); + } + + SECTION("IPv6 address") + { + PcapInputStream stream{"pcap-test"}; + stream.config_set("iface", "2001:db8::1"); + CHECK_THROWS_WITH(stream.start(), "Couldn't find interface by provided IP: 2001:db8::1"); + } + + SECTION("the zero address is looked up as a name") + { + PcapInputStream stream{"pcap-test"}; + stream.config_set("iface", "0.0.0.0"); + CHECK_THROWS_WITH(stream.start(), StartsWith("Couldn't find interface by provided name: \"0.0.0.0\"")); + } +}