mirror of
https://github.com/LibreQoE/LibreQoS.git
synced 2025-02-25 18:55:32 -06:00
Implement packet capture per IP, and download pcap format file at the end.
This commit is contained in:
parent
6359118147
commit
1b7a6f5098
1
src/rust/Cargo.lock
generated
1
src/rust/Cargo.lock
generated
@ -2069,6 +2069,7 @@ dependencies = [
|
||||
"lqos_sys",
|
||||
"lqos_utils",
|
||||
"lts_client",
|
||||
"mime_guess",
|
||||
"nix 0.29.0",
|
||||
"once_cell",
|
||||
"rand",
|
||||
|
@ -44,6 +44,7 @@ strum = { version = "0.26.3", features = ["derive"] }
|
||||
default-net = { workspace = true }
|
||||
surge-ping = "0.8.1"
|
||||
rand = "0.8.5"
|
||||
mime_guess = "2.0.4"
|
||||
|
||||
# Support JemAlloc on supported platforms
|
||||
[target.'cfg(any(target_arch = "x86", target_arch = "x86_64"))'.dependencies]
|
||||
|
@ -48,7 +48,7 @@ function connectPrivateChannel() {
|
||||
});
|
||||
}
|
||||
|
||||
function connectPingers(circuits) {
|
||||
function fullIpList(circuits) {
|
||||
let ipList = [];
|
||||
circuits.forEach((circuit) => {
|
||||
circuit.ipv4.forEach((ip) => {
|
||||
@ -58,6 +58,11 @@ function connectPingers(circuits) {
|
||||
ipList.push([ip[0], circuit.device_id]);
|
||||
});
|
||||
});
|
||||
return ipList;
|
||||
}
|
||||
|
||||
function connectPingers(circuits) {
|
||||
let ipList = fullIpList(circuits);
|
||||
|
||||
pinger = new DirectChannel({
|
||||
PingMonitor: {
|
||||
@ -595,6 +600,84 @@ function subscribeToCake() {
|
||||
});
|
||||
}
|
||||
|
||||
function wireupAnalysis(circuits) {
|
||||
let ipAddresses = fullIpList(circuits);
|
||||
let list = document.createElement("div");
|
||||
let listBtn = document.createElement("button");
|
||||
listBtn.type = "button";
|
||||
listBtn.id = "CaptureTopBtn";
|
||||
listBtn.classList.add("btn", "btn-primary", "dropdown-toggle", "btn-sm");
|
||||
listBtn.setAttribute("data-bs-toggle", "dropdown");
|
||||
listBtn.innerHTML = "<i class='fa fa-search'></i> Packet Capture";
|
||||
list.appendChild(listBtn);
|
||||
|
||||
let listUl = document.createElement("ul");
|
||||
listUl.classList.add("dropdown-menu", "dropdown-menu-sized");
|
||||
ipAddresses.forEach((ip) => {
|
||||
let entry = document.createElement("li");
|
||||
let item = document.createElement("a");
|
||||
item.classList.add("dropdown-item");
|
||||
item.innerHTML = "<i class='fa fa-search'></i> Capture packets from " + ip[0];
|
||||
let address = ip[0]; // For closure capture
|
||||
item.onclick = () => {
|
||||
//console.log("Clicky " + address);
|
||||
$.get("/local-api/requestAnalysis/" + encodeURI(address), (data) => {
|
||||
//console.log(data);
|
||||
if (data === "Fail") {
|
||||
alert("Packet capture is already active for another IP. Please try again when it is finished.")
|
||||
return;
|
||||
}
|
||||
let counter = parseInt(data.Ok.countdown)+1;
|
||||
let sessionId = data.Ok.session_id;
|
||||
let btn = document.getElementById("CaptureTopBtn");
|
||||
btn.disabled = true;
|
||||
btn.innerHTML = "<i class='fa fa-spinner fa-spin'></i> Capturing Packets (" + counter + ")";
|
||||
let interval = setInterval(() => {
|
||||
counter--;
|
||||
if (counter === -1) {
|
||||
clearInterval(interval);
|
||||
btn.disabled = false;
|
||||
btn.innerHTML = "<i class='fa fa-download'></i> Download Packet Capture for " + address;
|
||||
btn.classList.remove("btn-primary");
|
||||
btn.classList.add("btn-success");
|
||||
btn.onclick = () => {
|
||||
let url = "/local-api/pcapDump/" + sessionId;
|
||||
download(url, "capture.pcap");
|
||||
//console.log(url);
|
||||
|
||||
// Restore the buttons
|
||||
$.ajax({
|
||||
type: "POST",
|
||||
url: "/local-api/circuitById",
|
||||
data: JSON.stringify({id: circuit_id}),
|
||||
contentType: 'application/json',
|
||||
success: (circuits) => {
|
||||
wireupAnalysis(circuits);
|
||||
}
|
||||
});
|
||||
}
|
||||
return;
|
||||
}
|
||||
btn.innerHTML = "<i class='fa fa-spinner fa-spin'></i> Capturing Packets (" + counter + ")";
|
||||
}, 1000);
|
||||
});
|
||||
}
|
||||
entry.appendChild(item);
|
||||
listUl.appendChild(entry);
|
||||
});
|
||||
list.appendChild(listUl);
|
||||
let parent = document.getElementById("captureButton");
|
||||
clearDiv(parent);
|
||||
parent.appendChild(list);
|
||||
}
|
||||
|
||||
function download(dataurl, filename) {
|
||||
const link = document.createElement("a");
|
||||
link.href = dataurl;
|
||||
link.download = filename;
|
||||
link.click();
|
||||
}
|
||||
|
||||
function loadInitial() {
|
||||
$.ajax({
|
||||
type: "POST",
|
||||
@ -623,6 +706,7 @@ function loadInitial() {
|
||||
connectFlowChannel();
|
||||
initialFunnel(circuit.parent_node);
|
||||
subscribeToCake();
|
||||
wireupAnalysis(circuits);
|
||||
},
|
||||
error: () => {
|
||||
alert("Circuit with id " + circuit_id + " not found");
|
||||
|
@ -10,6 +10,7 @@ mod unknown_ips;
|
||||
mod reload_libreqos;
|
||||
mod config;
|
||||
mod circuit;
|
||||
mod packet_analysis;
|
||||
|
||||
use axum::Router;
|
||||
use axum::routing::{get, post};
|
||||
@ -41,5 +42,7 @@ pub fn local_api() -> Router {
|
||||
.route("/updateConfig", post(config::update_lqosd_config))
|
||||
.route("/updateNetworkAndDevices", post(config::update_network_and_devices))
|
||||
.route("/circuitById", post(circuit::get_circuit_by_id))
|
||||
.route("/requestAnalysis/:ip", get(packet_analysis::request_analysis))
|
||||
.route("/pcapDump/:id", get(packet_analysis::pcap_dump))
|
||||
.route_layer(axum::middleware::from_fn(auth_layer))
|
||||
}
|
31
src/rust/lqosd/src/node_manager/local_api/packet_analysis.rs
Normal file
31
src/rust/lqosd/src/node_manager/local_api/packet_analysis.rs
Normal file
@ -0,0 +1,31 @@
|
||||
use std::net::IpAddr;
|
||||
use axum::body::Body;
|
||||
use axum::extract::Path;
|
||||
use axum::http::{HeaderMap, Request};
|
||||
use axum::Json;
|
||||
use axum::response::IntoResponse;
|
||||
use serde::Serialize;
|
||||
use tower_http::services::ServeFile;
|
||||
use lqos_heimdall::n_second_pcap;
|
||||
|
||||
#[derive(Serialize, Clone)]
|
||||
pub enum RequestAnalysisResult {
|
||||
Fail,
|
||||
Ok{ session_id: usize, countdown: usize }
|
||||
}
|
||||
|
||||
pub async fn request_analysis(Path(ip): Path<String>) -> Json<RequestAnalysisResult> {
|
||||
if let Ok(ip) = ip.parse::<IpAddr>() {
|
||||
if let Some((session_id, countdown)) = lqos_heimdall::hyperfocus_on_target(ip.into()) {
|
||||
return Json(RequestAnalysisResult::Ok{ session_id, countdown });
|
||||
}
|
||||
}
|
||||
Json(RequestAnalysisResult::Fail)
|
||||
}
|
||||
|
||||
pub async fn pcap_dump(Path(id): Path<usize>, headers: HeaderMap) -> impl IntoResponse {
|
||||
let filename = n_second_pcap(id).unwrap();
|
||||
let mut req = Request::new(Body::empty());
|
||||
*req.headers_mut() = headers;
|
||||
ServeFile::new(filename).try_call(req).await.unwrap()
|
||||
}
|
@ -14,6 +14,10 @@
|
||||
<td style="font-weight: bold">Minimum Speed</td>
|
||||
<td><span id="bwMin"></span></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="2" id="captureButton">
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
<div class="col-3">
|
||||
|
Loading…
Reference in New Issue
Block a user