- CitrineOS core extracted (CSMS OCPP 2.0.1) - OpenOCPP extracted (firmware OCPP 1.6J/2.0.1) - ShapeShifter library installed (pip install -e) - ShapeShifter specification extracted - EVerest extracted TODO updated with progress
114 lines
4.5 KiB
C++
114 lines
4.5 KiB
C++
// SPDX-License-Identifier: Apache-2.0
|
|
// Copyright Pionix GmbH and Contributors to EVerest
|
|
#include "PacketSniffer.hpp"
|
|
|
|
#include <fmt/core.h>
|
|
|
|
#include <fmt/chrono.h>
|
|
|
|
namespace module {
|
|
|
|
const bool PROMISC_MODE = true;
|
|
const int PACKET_BUFFER_TIMEOUT_MS = 1000;
|
|
const int ALL_PACKETS_PROCESSED = -1;
|
|
const int WAIT_FOR_MS = 10;
|
|
const int BUFFERSIZE = 8192;
|
|
|
|
void PacketSniffer::init() {
|
|
p_handle = pcap_open_live(config.device.c_str(), BUFFERSIZE, PROMISC_MODE, PACKET_BUFFER_TIMEOUT_MS, errbuf);
|
|
std::string errb{errbuf};
|
|
if (p_handle == nullptr) {
|
|
EVLOG_error << fmt::format("Could not open device \"{}\", Sniffing disabled.{}", config.device,
|
|
errb.size() > 0 ? (std::string(" Error: ") + errb) : "");
|
|
return;
|
|
}
|
|
|
|
if (config.device != "any" && pcap_datalink(p_handle) != DLT_EN10MB) {
|
|
EVLOG_error << fmt::format("Device \"{}\" doesn't provide Ethernet headers - not supported. Sniffing disabled.",
|
|
config.device);
|
|
pcap_close(p_handle);
|
|
return;
|
|
}
|
|
|
|
EVLOG_info << fmt::format("Sniffing on device \"{}\"", config.device);
|
|
|
|
r_evse_manager->subscribe_session_event([this](types::evse_manager::SessionEvent session_event) {
|
|
if (session_event.event == types::evse_manager::SessionEventEnum::SessionStarted) {
|
|
if (!already_started) {
|
|
|
|
if (!session_event.session_started.has_value()) {
|
|
EVLOG_warning
|
|
<< "SessionStarted event type doesn't contain session_started data. Ignoring this event.";
|
|
return;
|
|
}
|
|
|
|
std::string logging_path;
|
|
if (!config.session_logging_path.empty()) {
|
|
logging_path = config.session_logging_path;
|
|
} else if (session_event.session_started->logging_path.has_value()) {
|
|
logging_path = session_event.session_started->logging_path.value();
|
|
} else {
|
|
EVLOG_warning << "No logging path configured and none provided in SessionStarted event. "
|
|
"Skipping capture.";
|
|
return;
|
|
}
|
|
|
|
capturing_stopped = false;
|
|
std::thread(&PacketSniffer::capture, this, logging_path, session_event.uuid).detach();
|
|
} else {
|
|
EVLOG_warning << fmt::format("Capturing already started. Ignoring this SessionStarted event");
|
|
}
|
|
} else if (session_event.event == types::evse_manager::SessionEventEnum::SessionFinished) {
|
|
capturing_stopped = true;
|
|
pcap_breakloop(p_handle);
|
|
}
|
|
});
|
|
}
|
|
|
|
void PacketSniffer::ready() {
|
|
}
|
|
|
|
void PacketSniffer::capture(const std::string& logpath, const std::string& session_id) {
|
|
already_started = true;
|
|
|
|
std::string fn = fmt::format("{}/ethernet-traffic.pcap", logpath);
|
|
if (not config.session_logging_path.empty()) {
|
|
const auto now = std::chrono::system_clock::now();
|
|
const auto time_t_now = std::chrono::system_clock::to_time_t(now);
|
|
std::tm local_tm{};
|
|
localtime_r(&time_t_now, &local_tm);
|
|
const auto timestamp = fmt::format("{:%Y-%m-%d_%H-%M-%S%z}", local_tm);
|
|
fn = fmt::format("{}/{}_{}.pcap", logpath, timestamp, session_id);
|
|
}
|
|
|
|
EVLOG_info << fmt::format("Starting capturing to {}", fn);
|
|
|
|
if ((pdumpfile = pcap_dump_open(p_handle, fn.c_str())) == nullptr) {
|
|
EVLOG_error << fmt::format("Error opening savefile {} for writing: {}", fn, pcap_geterr(p_handle));
|
|
return;
|
|
}
|
|
|
|
while (!capturing_stopped) {
|
|
const int ret =
|
|
pcap_dispatch(p_handle, ALL_PACKETS_PROCESSED, &pcap_dump, reinterpret_cast<u_char*>(pdumpfile));
|
|
if (ret <= PCAP_ERROR) {
|
|
const std::string base_msg = fmt::format("Error reading packets from interface \"{}\"", config.device);
|
|
if (ret == PCAP_ERROR) {
|
|
EVLOG_error << fmt::format("{}, error: {}", base_msg, pcap_geterr(p_handle));
|
|
} else if (ret == PCAP_ERROR_BREAK) {
|
|
EVLOG_warning << fmt::format("{}, interrupted but no packets received", base_msg);
|
|
} else {
|
|
EVLOG_error << fmt::format("{}, unexpected error: {}", base_msg, ret);
|
|
}
|
|
break;
|
|
}
|
|
std::this_thread::sleep_for(std::chrono::milliseconds(WAIT_FOR_MS));
|
|
}
|
|
|
|
pcap_dump_close(pdumpfile);
|
|
EVLOG_info << fmt::format("Stopped capturing to {}", fn);
|
|
already_started = false;
|
|
}
|
|
|
|
} // namespace module
|