Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/133 mock traffic #134

Merged
merged 4 commits into from
Nov 1, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/inputs/pcap/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ set(VISOR_STATIC_PLUGINS ${VISOR_STATIC_PLUGINS} Visor::Input::Pcap PARENT_SCOPE
## TEST SUITE
add_executable(unit-tests-input-pcap
tests/main.cpp
tests/test_mock_traffic.cpp
tests/test_parse_pcap.cpp
tests/test_utils.cpp
)
Expand Down
118 changes: 107 additions & 11 deletions src/inputs/pcap/PcapInputStream.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
#pragma GCC diagnostic ignored "-Wunused-parameter"
#pragma clang diagnostic ignored "-Wc99-extensions"
#pragma GCC diagnostic ignored "-Wpedantic"
#include <DnsLayer.h> // used only for mock generator
#include <EthLayer.h>
#include <IPv4Layer.h>
#include <IPv6Layer.h>
#include <Logger.h>
Expand Down Expand Up @@ -99,16 +101,6 @@ void PcapInputStream::start()
pcpp::LoggerPP::getInstance().setAllModlesToLogLevel(pcpp::LoggerPP::LogLevel::Debug);
}

// live capture
assert(config_exists("iface"));
if (!config_exists("bpf")) {
config_set("bpf", "");
}
parse_host_spec();
std::string TARGET(config_get<std::string>("iface"));
pcpp::IPv4Address interfaceIP4(TARGET);
pcpp::IPv6Address interfaceIP6(TARGET);

_cur_pcap_source = PcapInputStream::DefaultPcapSource;

if (config_exists("pcap_source")) {
Expand All @@ -121,11 +113,30 @@ void PcapInputStream::start()
#else
_cur_pcap_source = PcapSource::af_packet;
#endif
} else if (req_source == "mock") {
_cur_pcap_source = PcapSource::mock;
} else {
throw PcapException("unknown pcap source");
}
}

parse_host_spec();

std::string TARGET;
pcpp::IPv4Address interfaceIP4;
pcpp::IPv6Address interfaceIP6;
if (_cur_pcap_source == PcapSource::libpcap || _cur_pcap_source == PcapSource::af_packet) {
if (!config_exists("iface")) {
throw PcapException("no iface was specified for live capture");
}
if (!config_exists("bpf")) {
config_set("bpf", "");
}
TARGET = config_get<std::string>("iface");
interfaceIP4 = TARGET;
interfaceIP6 = TARGET;
}

if (_cur_pcap_source == PcapSource::libpcap) {
pcpp::PcapLiveDevice *pcapDevice;
// extract pcap live device by interface name or IP address
Expand Down Expand Up @@ -178,6 +189,14 @@ void PcapInputStream::start()
#else
_open_af_packet_iface(TARGET, config_get<std::string>("bpf"));
#endif
} else if (_cur_pcap_source == PcapSource::mock) {
_mock_generator_thread = std::make_unique<std::thread>([this] {
while (_running) {
_generate_mock_traffic();
// 10 qps. could be configurable in future.
std::this_thread::sleep_for(100ms);
}
});
} else {
assert(true);
}
Expand Down Expand Up @@ -207,6 +226,11 @@ void PcapInputStream::stop()
_tcp_reassembly.closeAllConnections();

_running = false;

if (_mock_generator_thread) {
_mock_generator_thread->join();
_mock_generator_thread.reset(nullptr);
}
}

void PcapInputStream::tcp_message_ready(int8_t side, const pcpp::TcpStreamData &tcpData)
Expand All @@ -229,6 +253,76 @@ void PcapInputStream::process_pcap_stats(const pcpp::IPcapDevice::PcapStats &sta
pcap_stats_signal(stats);
}

void PcapInputStream::_generate_mock_traffic()
{

PacketDirection dir = (std::rand() % 2 == 0) ? PacketDirection::toHost : PacketDirection::fromHost;

pcpp::MacAddress host_mac("00:50:43:11:22:33");
pcpp::IPv4Address host_ip("192.168.0.1");

pcpp::MacAddress other_mac("aa:bb:cc:dd:" + std::string('a' + std::rand() % 26, 2));
pcpp::IPv4Address other_ip("10.0.0." + std::to_string(std::rand() % 255));

// create a new Ethernet layer
pcpp::EthLayer *newEthernetLayer{nullptr};
if (dir == PacketDirection::toHost) {
newEthernetLayer = new pcpp::EthLayer(other_mac, host_mac);
} else {
newEthernetLayer = new pcpp::EthLayer(host_mac, other_mac);
}

// create a new IPv4 layer
pcpp::IPv4Layer *newIPLayer;
if (dir == PacketDirection::toHost) {
newIPLayer = new pcpp::IPv4Layer(other_ip, host_ip);
} else {
newIPLayer = new pcpp::IPv4Layer(host_ip, other_ip);
}
newIPLayer->getIPv4Header()->ipId = pcpp::hostToNet16(2000);
newIPLayer->getIPv4Header()->timeToLive = 64;

// create a new UDP layer
pcpp::UdpLayer *newUdpLayer;
if (dir == PacketDirection::toHost) {
newUdpLayer = new pcpp::UdpLayer(std::rand() % 65536, 53);
} else {
newUdpLayer = new pcpp::UdpLayer(53, std::rand() % 65536);
}

// create a new DNS layer
std::random_device rd;
std::mt19937 g(rd());
pcpp::DnsLayer *newDnsLayer = new pcpp::DnsLayer();
std::vector<pcpp::DnsType> types{pcpp::DNS_TYPE_A, pcpp::DNS_TYPE_AAAA, pcpp::DNS_TYPE_PTR, pcpp::DNS_TYPE_MX, pcpp::DNS_TYPE_TXT};
std::shuffle(types.begin(), types.end(), g);
newDnsLayer->addQuery(std::to_string(std::rand() % 20) + ".pktvisor-mock.dev", types[0], pcpp::DNS_CLASS_IN);
newDnsLayer->getDnsHeader()->transactionID = std::rand() % 65536; // note this does not work with our transaction tracking
if (dir == PacketDirection::fromHost) {
// mocking a server
newDnsLayer->getDnsHeader()->queryOrResponse = 1;
newDnsLayer->getDnsHeader()->responseCode = std::rand() % 6;
}

// create a packet with initial capacity of 100 bytes (will grow automatically if needed)
pcpp::Packet newPacket(100);

// add all the layers we created. newPacket takes ownership and frees them.
newPacket.addLayer(newEthernetLayer, true);
newPacket.addLayer(newIPLayer, true);
newPacket.addLayer(newUdpLayer, true);
newPacket.addLayer(newDnsLayer, true);
newPacket.computeCalculateFields();

pcpp::Packet packet(newPacket.getRawPacket());
pcpp::ProtocolType l3 = pcpp::IPv4;
pcpp::ProtocolType l4 = pcpp::UDP;
timespec ts;
timespec_get(&ts, TIME_UTC);
packet_signal(packet, dir, l3, l4, ts);
udp_signal(packet, dir, l3, pcpp::hash5Tuple(&packet), ts);
}

void PcapInputStream::process_raw_packet(pcpp::RawPacket *rawPacket)
{

Expand Down Expand Up @@ -463,6 +557,9 @@ void PcapInputStream::info_json(json &j) const
case PcapSource::af_packet:
info["pcap_source"] = "af_packet";
break;
case PcapSource::mock:
info["pcap_source"] = "mock";
break;
}
j[schema_key()] = info;
}
Expand All @@ -473,5 +570,4 @@ void PcapInputStream::parse_host_spec()
parseHostSpec(config_get<std::string>("host_spec"), _hostIPv4, _hostIPv6);
}
}

}
7 changes: 6 additions & 1 deletion src/inputs/pcap/PcapInputStream.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@ namespace visor::input::pcap {
enum class PcapSource {
unknown,
libpcap,
af_packet
af_packet,
mock
};

enum class PacketDirection {
Expand All @@ -51,6 +52,9 @@ class PcapInputStream : public visor::InputStream
std::unique_ptr<pcpp::PcapLiveDevice> _pcapDevice;
bool _pcapFile = false;

// mock source
std::unique_ptr<std::thread> _mock_generator_thread;

#ifdef __linux__
// af_packet source
std::unique_ptr<AFPacket> _af_device;
Expand All @@ -62,6 +66,7 @@ class PcapInputStream : public visor::InputStream
void _open_pcap(const std::string &fileName, const std::string &bpfFilter);
void _open_libpcap_iface(const std::string &bpfFilter = "");
void _get_hosts_from_libpcap_iface();
void _generate_mock_traffic();

#ifdef __linux__
void _open_af_packet_iface(const std::string &iface, const std::string &bpfFilter);
Expand Down
21 changes: 21 additions & 0 deletions src/inputs/pcap/tests/test_mock_traffic.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
#include "PcapInputStream.h"
#include <arpa/inet.h>
#include <catch2/catch.hpp>

using namespace visor::input::pcap;
using namespace std::chrono;

TEST_CASE("Test mock traffic generator", "[pcap][mock]")
{

PcapInputStream stream{"pcap-test"};
stream.config_set("host_spec", "192.168.0.0/24");
stream.config_set("pcap_source", "mock");
stream.parse_host_spec();

stream.start();
std::this_thread::sleep_for(1s);
stream.stop();

}