#include "include/capture/pcapCapture.hpp" #include "include/cli/filter.hpp" #include #include #include #include #include #include #include "include/TUI/view.hpp" #include "include/cli/argsParse.hpp" int main(int argc, char **argv) { /* initialize stats */ Stats stats; /* initialize capture */ PcapCapture capture; capture.initialize(); /* initializing the command line parser */ argsParser parser(argc, argv); /* check helper flags */ if (parser.vm.contains("help")) { parser.print_help(); return 0; } if (parser.vm.contains("interfaces")) { capture.print_interfaces(); return 0; } /* take the arguments of the flags into variables */ std::string interface = parser.vm["interface"].as(); int count = parser.vm["count"].as(); int limit = parser.vm["limit"].as(); int time = parser.vm["time"].as(); std::string filterString = ""; /* get a filter, use vector for multiple */ std::vector filters; if (parser.vm.contains("filter")) { const auto &f = parser.vm["filter"].as>(); for (const auto &x : f) { filters.push_back(parse(x)); filterString += x + " "; } } /* converting the filter to a pcap readable string */ std::string expression = get_bpf_filter(filters); bool isOffline = parser.vm.contains("offline"); /* set the flags to capture engine */ capture.set_capabilities(interface, count, expression, limit, &stats); std::atomic capture_finished = false; std::atomic ui_running = true; /* if we capture packets offline, we read the file in full, then print the result */ if (isOffline) { capture.start_offline(parser.vm["offline"].as()); /* full recalculation of statistics after file processing */ stats.update_packets(); stats.update_application_stats(); stats.update_transport_stats(); stats.update_ip_stats(10); stats.update_pairs(); stats.update_bandwidth(); } /* otherwise start live capture */ else { capture.start(); } /* UI */ // Timer std::chrono::steady_clock::time_point begin = std::chrono::steady_clock::now(); std::atomic timer; auto screen = ftxui::ScreenInteractive::Fullscreen(); /* our class for UI */ View view; std::mutex render_mtx; ftxui::Element current_render = isOffline ? view.render(stats.get_snapshot(), interface, filterString, true, timer.load()) : ftxui::text("Starting capture..."); auto component = ftxui::Renderer([&] { std::lock_guard lock(render_mtx); return current_render; }); component |= ftxui::CatchEvent([&](ftxui::Event e) { if (e == ftxui::Event::Character('q') || e == ftxui::Event::Escape) { ui_running = false; screen.Exit(); return true; } return true; }); std::thread application_thread; if (!isOffline) { application_thread = std::thread([&] { while (!capture_finished && ui_running) { auto now = std::chrono::steady_clock::now(); timer.store(std::chrono::duration_cast(now - begin)); if (timer.load() >= std::chrono::seconds(time) || !capture.isRunning()) { capture_finished = true; } stats.update_packets(); stats.update_application_stats(); stats.update_transport_stats(); stats.update_ip_stats(10); stats.update_pairs(); stats.update_bandwidth(); ftxui::Element new_frame = view.render(stats.get_snapshot(), interface, filterString, capture_finished, timer.load()); { std::lock_guard lock(render_mtx); current_render = new_frame; } if (ui_running) { screen.PostEvent(ftxui::Event::Custom); } // std::this_thread::sleep_for(std::chrono::milliseconds(500)); } }); } screen.Loop(component); ui_running = false; capture_finished = true; if (application_thread.joinable()) application_thread.join(); // Export stats if needed if (parser.vm.contains("csv")) stats.export_csv(parser.vm["csv"].as()); if (parser.vm.contains("json")) stats.export_json(parser.vm["json"].as()); return 0; }