Compare commits
20 Commits
ede4b3e78d
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9106cac2a2 | ||
| 68827ed7e3 | |||
| a4b19f8c3e | |||
| 6e7a1ccb1b | |||
| c9c1d346fd | |||
| a900fb8f8b | |||
| f24a230f9d | |||
| 8929878f13 | |||
| a9ff3a2987 | |||
| 10f0e518c7 | |||
| c40ddf4ded | |||
| bf63c7c1a9 | |||
| 1614d22257 | |||
| b4e4e27c4b | |||
| 3eb39a71ad | |||
| 945b259ebb | |||
| b5c6409f85 | |||
| 9c982e361c | |||
| 76256d56f2 | |||
| 3ca1d52972 |
@@ -0,0 +1 @@
|
||||
netfilterqueue
|
||||
54
backend/example_scripts/chaos_delay_jitter.py
Normal file
@@ -0,0 +1,54 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Minimal NFQUEUE example: add random delay and jitter, but do not drop packets."""
|
||||
|
||||
import random
|
||||
import signal
|
||||
import sys
|
||||
import time
|
||||
|
||||
from netfilterqueue import NetfilterQueue
|
||||
|
||||
# Demo tuning values.
|
||||
BASE_DELAY_MS = 40
|
||||
JITTER_MS = 120
|
||||
|
||||
nfq = NetfilterQueue()
|
||||
|
||||
|
||||
def _handle_packet(packet) -> None:
|
||||
delay_ms = BASE_DELAY_MS + random.uniform(0, JITTER_MS)
|
||||
time.sleep(delay_ms / 1000.0)
|
||||
packet.accept()
|
||||
|
||||
|
||||
def _stop(_sig, _frame) -> None:
|
||||
raise SystemExit(0)
|
||||
|
||||
|
||||
def main() -> int:
|
||||
if len(sys.argv) != 2:
|
||||
print("Usage: chaos_delay_jitter.py <qnum>", file=sys.stderr)
|
||||
return 1
|
||||
|
||||
try:
|
||||
qnum = int(sys.argv[1])
|
||||
except ValueError:
|
||||
print("qnum must be an integer", file=sys.stderr)
|
||||
return 1
|
||||
|
||||
signal.signal(signal.SIGINT, _stop)
|
||||
signal.signal(signal.SIGTERM, _stop)
|
||||
|
||||
nfq.bind(qnum, _handle_packet)
|
||||
try:
|
||||
nfq.run()
|
||||
except KeyboardInterrupt:
|
||||
pass
|
||||
finally:
|
||||
nfq.unbind()
|
||||
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
@@ -0,0 +1,2 @@
|
||||
netfilterqueue
|
||||
scapy
|
||||
68
backend/example_scripts/dns_rewrite_example_to_pwned.py
Normal file
@@ -0,0 +1,68 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Minimal NFQUEUE example: rewrite DNS queries from example.com to pwned.com."""
|
||||
|
||||
import signal
|
||||
import sys
|
||||
|
||||
from netfilterqueue import NetfilterQueue
|
||||
from scapy.all import DNS, DNSQR, IP, UDP
|
||||
|
||||
SOURCE_QNAME = b"example.com."
|
||||
TARGET_QNAME = b"pwned.com."
|
||||
|
||||
nfq = NetfilterQueue()
|
||||
|
||||
|
||||
def _handle_packet(packet) -> None:
|
||||
try:
|
||||
ip = IP(packet.get_payload())
|
||||
if ip.haslayer(UDP) and ip.haslayer(DNS) and ip.haslayer(DNSQR):
|
||||
dns = ip[DNS]
|
||||
query = ip[DNSQR]
|
||||
|
||||
# Only touch DNS requests for exactly example.com.
|
||||
if dns.qr == 0 and query.qname == SOURCE_QNAME:
|
||||
query.qname = TARGET_QNAME
|
||||
# delete fields so scapy re-calculates them
|
||||
del ip.len
|
||||
del ip.chksum
|
||||
del ip[UDP].len
|
||||
del ip[UDP].chksum
|
||||
packet.set_payload(bytes(ip))
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
packet.accept()
|
||||
|
||||
|
||||
def _stop(_sig, _frame) -> None:
|
||||
raise SystemExit(0)
|
||||
|
||||
|
||||
def main() -> int:
|
||||
if len(sys.argv) != 2:
|
||||
print("Usage: dns_rewrite_example_to_pwned.py <qnum>", file=sys.stderr)
|
||||
return 1
|
||||
|
||||
try:
|
||||
qnum = int(sys.argv[1])
|
||||
except ValueError:
|
||||
print("qnum must be an integer", file=sys.stderr)
|
||||
return 1
|
||||
|
||||
signal.signal(signal.SIGINT, _stop)
|
||||
signal.signal(signal.SIGTERM, _stop)
|
||||
|
||||
nfq.bind(qnum, _handle_packet)
|
||||
try:
|
||||
nfq.run()
|
||||
except KeyboardInterrupt:
|
||||
pass
|
||||
finally:
|
||||
nfq.unbind()
|
||||
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
@@ -1,42 +1,29 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Minimal NFQUEUE example script.
|
||||
"""Minimal NFQUEUE example: accept every packet from a queue."""
|
||||
|
||||
Expected argv:
|
||||
argv[1] = queue number
|
||||
Any extra args are optional.
|
||||
"""
|
||||
|
||||
import logging
|
||||
import signal
|
||||
import sys
|
||||
from typing import Optional
|
||||
|
||||
try:
|
||||
from netfilterqueue import NetfilterQueue
|
||||
except Exception as exc: # pragma: no cover
|
||||
except Exception as exc:
|
||||
print(f"Failed to import netfilterqueue: {exc}", file=sys.stderr)
|
||||
sys.exit(2)
|
||||
|
||||
logging.basicConfig(level=logging.INFO, format="%(asctime)s %(levelname)s %(message)s")
|
||||
logger = logging.getLogger("hello-nfqueue")
|
||||
|
||||
_running = True
|
||||
|
||||
|
||||
def _stop(_sig: int, _frame: Optional[object]) -> None:
|
||||
global _running
|
||||
_running = False
|
||||
nfq = NetfilterQueue()
|
||||
|
||||
|
||||
def _handle_packet(packet) -> None:
|
||||
# This demo accepts all packets and logs basic metadata.
|
||||
logger.info("packet id=%s len=%s", packet.get_id(), len(packet.get_payload()))
|
||||
packet.accept()
|
||||
|
||||
|
||||
def _stop(_sig, _frame) -> None:
|
||||
raise SystemExit(0)
|
||||
|
||||
|
||||
def main() -> int:
|
||||
if len(sys.argv) < 2:
|
||||
print("Usage: hello_nfqueue.py <qnum> [extra args...]", file=sys.stderr)
|
||||
if len(sys.argv) != 2:
|
||||
print("Usage: hello_nfqueue.py <qnum>", file=sys.stderr)
|
||||
return 1
|
||||
|
||||
try:
|
||||
@@ -48,19 +35,13 @@ def main() -> int:
|
||||
signal.signal(signal.SIGINT, _stop)
|
||||
signal.signal(signal.SIGTERM, _stop)
|
||||
|
||||
nfq = NetfilterQueue()
|
||||
logger.info("Binding to NFQUEUE %d", qnum)
|
||||
nfq.bind(qnum, _handle_packet)
|
||||
|
||||
try:
|
||||
while _running:
|
||||
nfq.run(block=True)
|
||||
nfq.run()
|
||||
except KeyboardInterrupt:
|
||||
pass
|
||||
finally:
|
||||
logger.info("Unbinding NFQUEUE %d", qnum)
|
||||
nfq.unbind()
|
||||
|
||||
return 0
|
||||
|
||||
|
||||
|
||||
1
backend/example_scripts/packet_loss-requirements.txt
Normal file
@@ -0,0 +1 @@
|
||||
netfilterqueue
|
||||
67
backend/example_scripts/packet_loss.py
Normal file
@@ -0,0 +1,67 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Minimal NFQUEUE example: randomly drop packets by percentage."""
|
||||
|
||||
import random
|
||||
import signal
|
||||
import sys
|
||||
|
||||
from netfilterqueue import NetfilterQueue
|
||||
|
||||
DEFAULT_LOSS_PERCENT = 10.0
|
||||
|
||||
nfq = NetfilterQueue()
|
||||
loss_percent = DEFAULT_LOSS_PERCENT
|
||||
|
||||
|
||||
def _handle_packet(packet) -> None:
|
||||
if random.random() < (loss_percent / 100.0):
|
||||
packet.drop()
|
||||
return
|
||||
|
||||
packet.accept()
|
||||
|
||||
|
||||
def _stop(_sig, _frame) -> None:
|
||||
raise SystemExit(0)
|
||||
|
||||
|
||||
def main() -> int:
|
||||
global loss_percent
|
||||
|
||||
if len(sys.argv) not in (2, 3):
|
||||
print("Usage: packet_loss.py <qnum> [loss_percent]", file=sys.stderr)
|
||||
return 1
|
||||
|
||||
try:
|
||||
qnum = int(sys.argv[1])
|
||||
except ValueError:
|
||||
print("qnum must be an integer", file=sys.stderr)
|
||||
return 1
|
||||
|
||||
if len(sys.argv) == 3:
|
||||
try:
|
||||
loss_percent = float(sys.argv[2])
|
||||
except ValueError:
|
||||
print("loss_percent must be a number between 0 and 100", file=sys.stderr)
|
||||
return 1
|
||||
|
||||
if not 0.0 <= loss_percent <= 100.0:
|
||||
print("loss_percent must be between 0 and 100", file=sys.stderr)
|
||||
return 1
|
||||
|
||||
signal.signal(signal.SIGINT, _stop)
|
||||
signal.signal(signal.SIGTERM, _stop)
|
||||
|
||||
nfq.bind(qnum, _handle_packet)
|
||||
try:
|
||||
nfq.run()
|
||||
except KeyboardInterrupt:
|
||||
pass
|
||||
finally:
|
||||
nfq.unbind()
|
||||
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
@@ -376,6 +376,7 @@ Type=simple
|
||||
ExecStart={exec_start}
|
||||
Restart=always
|
||||
RestartSec=2
|
||||
TimeoutStopSec=10
|
||||
StandardOutput=syslog
|
||||
StandardError=syslog
|
||||
|
||||
|
||||
@@ -35,6 +35,13 @@ class SnifferStartRequest(BaseModel):
|
||||
example="tc_ebpf",
|
||||
description="Bridge capture mode: 'tc_ebpf' or 'af_packet'. Ignored for interface capture.",
|
||||
)
|
||||
benchmark_mode: bool = Field(
|
||||
False,
|
||||
description=(
|
||||
"Run capture hooks for measurement while skipping packet parsing, DB persistence, "
|
||||
"DPI enrichment, and live packet publication."
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
class SnifferStartResponse(BaseModel):
|
||||
@@ -45,6 +52,7 @@ class SnifferStartResponse(BaseModel):
|
||||
target: str = Field(..., description="Started target name.")
|
||||
target_type: str = Field(..., description="Either 'bridge' or 'interface'.")
|
||||
capture_mode: str = Field(..., description="The effective capture mode used by the session.")
|
||||
benchmark_mode: bool = Field(False, description="Whether userspace packet processing is skipped.")
|
||||
|
||||
|
||||
class SnifferStopRequest(BaseModel):
|
||||
@@ -71,6 +79,7 @@ class InterfaceSnifferStatus(BaseModel):
|
||||
session_id: Optional[str] = Field(None, description="Owning capture session ID.")
|
||||
session_label: Optional[str] = Field(None, description="Human-readable session label.")
|
||||
capture_mode: Optional[str] = Field(None, description="Capture mode used by the owning session.")
|
||||
benchmark_mode: Optional[bool] = Field(None, description="Whether the owning session skips userspace processing.")
|
||||
|
||||
|
||||
class SnifferStatusResponse(BaseModel):
|
||||
@@ -90,13 +99,18 @@ def sniffer_start(req: SnifferStartRequest) -> SnifferStartResponse:
|
||||
|
||||
try:
|
||||
if req.interface:
|
||||
session_id = start_capture_session(req.interface, target_is_interface=True)
|
||||
session_id = start_capture_session(
|
||||
req.interface,
|
||||
target_is_interface=True,
|
||||
benchmark_mode=req.benchmark_mode,
|
||||
)
|
||||
return SnifferStartResponse(
|
||||
started=True,
|
||||
session_id=session_id,
|
||||
target=req.interface,
|
||||
target_type="interface",
|
||||
capture_mode="af_packet",
|
||||
benchmark_mode=req.benchmark_mode,
|
||||
)
|
||||
|
||||
effective_capture_mode = req.bridge_capture_mode or BRIDGE_CAPTURE_MODE_TC_EBPF
|
||||
@@ -106,6 +120,7 @@ def sniffer_start(req: SnifferStartRequest) -> SnifferStartResponse:
|
||||
req.bridge,
|
||||
target_is_interface=False,
|
||||
bridge_capture_mode=effective_capture_mode,
|
||||
benchmark_mode=req.benchmark_mode,
|
||||
)
|
||||
return SnifferStartResponse(
|
||||
started=True,
|
||||
@@ -113,6 +128,7 @@ def sniffer_start(req: SnifferStartRequest) -> SnifferStartResponse:
|
||||
target=req.bridge,
|
||||
target_type="bridge",
|
||||
capture_mode=effective_capture_mode,
|
||||
benchmark_mode=req.benchmark_mode,
|
||||
)
|
||||
except Exception as exc:
|
||||
raise HTTPException(status_code=500, detail=f"Failed to start sniffer: {exc}") from exc
|
||||
|
||||
@@ -43,6 +43,14 @@ class BackendSettings:
|
||||
packet_tracker_retention_seconds: float
|
||||
packet_tracker_min_flush_interval_seconds: float
|
||||
packet_tracker_persist_timeout_seconds: float
|
||||
packet_tracker_batch_persist_timeout_seconds: float
|
||||
packet_tracker_persist_retry_backoff_seconds: float
|
||||
packet_tracker_persist_retry_backoff_max_seconds: float
|
||||
packet_tracker_error_log_interval_seconds: float
|
||||
packet_tracker_flush_batch_size: int
|
||||
packet_tracker_max_entries: int
|
||||
packet_tracker_max_persist_failures: int
|
||||
packet_tracker_max_dirty_age_seconds: float
|
||||
packet_tracker_stop_join_timeout_seconds: float
|
||||
packet_tracker_reject_correlation_window_seconds: float
|
||||
sniffer_buffer_capacity: int
|
||||
@@ -52,6 +60,13 @@ class BackendSettings:
|
||||
sniffer_buffer_drain_interval_seconds: float
|
||||
sniffer_thread_join_timeout_seconds: float
|
||||
bridge_bpf_build_dir: str
|
||||
bridge_telemetry_raw_sample_every: int
|
||||
bridge_telemetry_meta_sample_every: int
|
||||
bridge_telemetry_ingress_perf_pages: int
|
||||
bridge_telemetry_meta_perf_pages: int
|
||||
bridge_telemetry_event_queue_maxsize: int
|
||||
bridge_telemetry_queue_recovery_size: int
|
||||
bridge_telemetry_drop_log_interval_seconds: float
|
||||
bridge_link_state_thread_join_timeout_seconds: float
|
||||
bridge_link_state_failure_holdoff_seconds: float
|
||||
bridge_link_state_recovery_holdoff_seconds: float
|
||||
@@ -78,6 +93,23 @@ def load_settings() -> BackendSettings:
|
||||
packet_tracker_retention_seconds=_env_float("BACKEND_PACKET_TRACKER_RETENTION_SECONDS", 10.0),
|
||||
packet_tracker_min_flush_interval_seconds=_env_float("BACKEND_PACKET_TRACKER_MIN_FLUSH_INTERVAL_SECONDS", 0.05),
|
||||
packet_tracker_persist_timeout_seconds=_env_float("BACKEND_PACKET_TRACKER_PERSIST_TIMEOUT_SECONDS", 2.0),
|
||||
packet_tracker_batch_persist_timeout_seconds=_env_float(
|
||||
"BACKEND_PACKET_TRACKER_BATCH_PERSIST_TIMEOUT_SECONDS",
|
||||
10.0,
|
||||
),
|
||||
packet_tracker_persist_retry_backoff_seconds=_env_float(
|
||||
"BACKEND_PACKET_TRACKER_PERSIST_RETRY_BACKOFF_SECONDS",
|
||||
0.25,
|
||||
),
|
||||
packet_tracker_persist_retry_backoff_max_seconds=_env_float(
|
||||
"BACKEND_PACKET_TRACKER_PERSIST_RETRY_BACKOFF_MAX_SECONDS",
|
||||
5.0,
|
||||
),
|
||||
packet_tracker_error_log_interval_seconds=_env_float("BACKEND_PACKET_TRACKER_ERROR_LOG_INTERVAL_SECONDS", 5.0),
|
||||
packet_tracker_flush_batch_size=max(1, _env_int("BACKEND_PACKET_TRACKER_FLUSH_BATCH_SIZE", 500)),
|
||||
packet_tracker_max_entries=max(1, _env_int("BACKEND_PACKET_TRACKER_MAX_ENTRIES", 50_000)),
|
||||
packet_tracker_max_persist_failures=max(1, _env_int("BACKEND_PACKET_TRACKER_MAX_PERSIST_FAILURES", 3)),
|
||||
packet_tracker_max_dirty_age_seconds=_env_float("BACKEND_PACKET_TRACKER_MAX_DIRTY_AGE_SECONDS", 60.0),
|
||||
packet_tracker_stop_join_timeout_seconds=_env_float("BACKEND_PACKET_TRACKER_STOP_JOIN_TIMEOUT_SECONDS", 2.0),
|
||||
packet_tracker_reject_correlation_window_seconds=_env_float(
|
||||
"BACKEND_PACKET_TRACKER_REJECT_CORRELATION_WINDOW_SECONDS",
|
||||
@@ -90,6 +122,13 @@ def load_settings() -> BackendSettings:
|
||||
sniffer_buffer_drain_interval_seconds=_env_float("BACKEND_SNIFFER_BUFFER_DRAIN_INTERVAL_SECONDS", 5.0),
|
||||
sniffer_thread_join_timeout_seconds=_env_float("BACKEND_SNIFFER_THREAD_JOIN_TIMEOUT_SECONDS", 2.0),
|
||||
bridge_bpf_build_dir=_env_str("BACKEND_BRIDGE_BPF_BUILD_DIR", "/tmp/mitm-bpf"),
|
||||
bridge_telemetry_raw_sample_every=max(0, _env_int("BACKEND_BRIDGE_TELEMETRY_RAW_SAMPLE_EVERY", 1)),
|
||||
bridge_telemetry_meta_sample_every=max(0, _env_int("BACKEND_BRIDGE_TELEMETRY_META_SAMPLE_EVERY", 1)),
|
||||
bridge_telemetry_ingress_perf_pages=max(1, _env_int("BACKEND_BRIDGE_TELEMETRY_INGRESS_PERF_PAGES", 256)),
|
||||
bridge_telemetry_meta_perf_pages=max(1, _env_int("BACKEND_BRIDGE_TELEMETRY_META_PERF_PAGES", 128)),
|
||||
bridge_telemetry_event_queue_maxsize=max(1, _env_int("BACKEND_BRIDGE_TELEMETRY_EVENT_QUEUE_MAXSIZE", 20_000)),
|
||||
bridge_telemetry_queue_recovery_size=max(0, _env_int("BACKEND_BRIDGE_TELEMETRY_QUEUE_RECOVERY_SIZE", 1_000)),
|
||||
bridge_telemetry_drop_log_interval_seconds=_env_float("BACKEND_BRIDGE_TELEMETRY_DROP_LOG_INTERVAL_SECONDS", 5.0),
|
||||
bridge_link_state_thread_join_timeout_seconds=_env_float(
|
||||
"BACKEND_BRIDGE_LINK_STATE_THREAD_JOIN_TIMEOUT_SECONDS",
|
||||
2.0,
|
||||
|
||||
@@ -630,8 +630,16 @@ def _sync_bridge_telemetry() -> None:
|
||||
for session_id, session in sessions.items()
|
||||
if session.get("is_bridge") and session.get("capture_mode") == BRIDGE_CAPTURE_MODE_TC_EBPF
|
||||
}
|
||||
benchmark_session_ids = {
|
||||
session_id
|
||||
for session_id, session in sessions.items()
|
||||
if session.get("benchmark_mode")
|
||||
}
|
||||
try:
|
||||
bridge_telemetry_manager.update_sessions(bridge_session_interfaces)
|
||||
bridge_telemetry_manager.update_sessions(
|
||||
bridge_session_interfaces,
|
||||
benchmark_session_ids=benchmark_session_ids,
|
||||
)
|
||||
except Exception:
|
||||
logger.exception("Failed to update bridge telemetry collector")
|
||||
|
||||
@@ -639,6 +647,7 @@ def _sync_bridge_telemetry() -> None:
|
||||
{
|
||||
iface
|
||||
for session in sessions.values()
|
||||
if not session.get("benchmark_mode")
|
||||
for iface in (
|
||||
list(session.get("capture_ifaces", []))
|
||||
+ (
|
||||
@@ -667,8 +676,9 @@ def _session_reader_loop(session_id: str) -> None:
|
||||
stop_event: threading.Event = session["stop_event"]
|
||||
sockets: Dict[str, socket.socket] = session["sockets"]
|
||||
label: str = session["label"]
|
||||
benchmark_mode = bool(session.get("benchmark_mode"))
|
||||
|
||||
logger.info("Session %s reader starting (label=%s)", session_id, label)
|
||||
logger.info("Session %s reader starting (label=%s benchmark_mode=%s)", session_id, label, benchmark_mode)
|
||||
sel = selectors.DefaultSelector()
|
||||
|
||||
# register existing sockets
|
||||
@@ -729,6 +739,11 @@ def _session_reader_loop(session_id: str) -> None:
|
||||
logger.exception("Recv error on %s in session %s", iface, session_id)
|
||||
continue
|
||||
|
||||
if benchmark_mode:
|
||||
session["benchmark_packets"] = int(session.get("benchmark_packets") or 0) + 1
|
||||
session["benchmark_bytes"] = int(session.get("benchmark_bytes") or 0) + len(raw)
|
||||
continue
|
||||
|
||||
# parse with scapy
|
||||
try:
|
||||
recv_ts = datetime.now(timezone.utc)
|
||||
@@ -775,6 +790,7 @@ def start_capture_session(
|
||||
target: str,
|
||||
target_is_interface: bool = False,
|
||||
bridge_capture_mode: str = BRIDGE_CAPTURE_MODE_TC_EBPF,
|
||||
benchmark_mode: bool = False,
|
||||
) -> str:
|
||||
"""
|
||||
Start a packet capture session. Returns session_id string.
|
||||
@@ -796,6 +812,9 @@ def start_capture_session(
|
||||
"label": target,
|
||||
"is_bridge": not target_is_interface,
|
||||
"capture_mode": effective_capture_mode,
|
||||
"benchmark_mode": bool(benchmark_mode),
|
||||
"benchmark_packets": 0,
|
||||
"benchmark_bytes": 0,
|
||||
"ports": [],
|
||||
"capture_ifaces": [],
|
||||
}
|
||||
@@ -834,10 +853,11 @@ def start_capture_session(
|
||||
session["thread"] = None
|
||||
_sync_bridge_telemetry()
|
||||
logger.info(
|
||||
"Started capture session %s label=%s capture_mode=%s ports=%s capture_ifaces=%s",
|
||||
"Started capture session %s label=%s capture_mode=%s benchmark_mode=%s ports=%s capture_ifaces=%s",
|
||||
session_id,
|
||||
target,
|
||||
effective_capture_mode,
|
||||
bool(benchmark_mode),
|
||||
ports,
|
||||
capture_ifaces,
|
||||
)
|
||||
@@ -946,6 +966,7 @@ def get_capture_session_status() -> Dict[str, Dict[str, object]]:
|
||||
"session_id": sid,
|
||||
"session_label": s.get("label"),
|
||||
"capture_mode": s.get("capture_mode"),
|
||||
"benchmark_mode": bool(s.get("benchmark_mode")),
|
||||
}
|
||||
if not s.get("sockets") and s.get("is_bridge"):
|
||||
for iface in s.get("ports", []):
|
||||
@@ -956,6 +977,7 @@ def get_capture_session_status() -> Dict[str, Dict[str, object]]:
|
||||
"session_id": sid,
|
||||
"session_label": s.get("label"),
|
||||
"capture_mode": s.get("capture_mode"),
|
||||
"benchmark_mode": bool(s.get("benchmark_mode")),
|
||||
}
|
||||
return out
|
||||
|
||||
@@ -970,6 +992,9 @@ def get_internal_debug_state() -> dict:
|
||||
"label": s.get("label"),
|
||||
"is_bridge": s.get("is_bridge"),
|
||||
"capture_mode": s.get("capture_mode"),
|
||||
"benchmark_mode": bool(s.get("benchmark_mode")),
|
||||
"benchmark_packets": int(s.get("benchmark_packets") or 0),
|
||||
"benchmark_bytes": int(s.get("benchmark_bytes") or 0),
|
||||
"ports": list(s.get("ports", [])),
|
||||
"capture_ifaces": list(s.get("capture_ifaces", [])),
|
||||
"sockets": list(s.get("sockets", {}).keys()),
|
||||
@@ -993,6 +1018,7 @@ def get_internal_debug_state() -> dict:
|
||||
}
|
||||
),
|
||||
"tshark": tshark_manager.get_debug_snapshot(),
|
||||
"bridge_telemetry": bridge_telemetry_manager.get_debug_snapshot(),
|
||||
"packet_tracker": packet_tracker.get_debug_snapshot(),
|
||||
}
|
||||
|
||||
@@ -1001,12 +1027,14 @@ def start_afpacket_sniffer(
|
||||
target: str,
|
||||
target_is_interface: bool = False,
|
||||
bridge_capture_mode: str = BRIDGE_CAPTURE_MODE_TC_EBPF,
|
||||
benchmark_mode: bool = False,
|
||||
) -> str:
|
||||
"""Backward-compatible wrapper for start_capture_session()."""
|
||||
return start_capture_session(
|
||||
target,
|
||||
target_is_interface=target_is_interface,
|
||||
bridge_capture_mode=bridge_capture_mode,
|
||||
benchmark_mode=benchmark_mode,
|
||||
)
|
||||
|
||||
|
||||
|
||||
@@ -6,10 +6,12 @@ import base64
|
||||
import json
|
||||
import logging
|
||||
import os
|
||||
import queue
|
||||
import signal
|
||||
import subprocess
|
||||
import sys
|
||||
import threading
|
||||
import time
|
||||
from pathlib import Path
|
||||
from typing import Iterable, Mapping, Optional
|
||||
|
||||
@@ -25,12 +27,32 @@ class BridgeTelemetryManager:
|
||||
def __init__(self) -> None:
|
||||
self._interfaces: set[str] = set()
|
||||
self._session_ids_by_interface: dict[str, tuple[str, ...]] = {}
|
||||
self._benchmark_by_interface: dict[str, bool] = {}
|
||||
self._process: Optional[subprocess.Popen[str]] = None
|
||||
self._reader_thread: Optional[threading.Thread] = None
|
||||
self._event_queue: queue.Queue = queue.Queue(maxsize=settings.bridge_telemetry_event_queue_maxsize)
|
||||
self._worker_thread = threading.Thread(
|
||||
target=self._event_worker_loop,
|
||||
daemon=True,
|
||||
name="bridge-telemetry-worker",
|
||||
)
|
||||
self._worker_thread.start()
|
||||
self._dropped_events = 0
|
||||
self._dropped_raw_payloads = 0
|
||||
self._benchmark_events = 0
|
||||
self._benchmark_raw_payloads = 0
|
||||
self._last_drop_log_at = 0.0
|
||||
self._suppressed_collector_messages = 0
|
||||
self._last_collector_warning_at = 0.0
|
||||
self._lock = threading.Lock()
|
||||
|
||||
def update_sessions(self, session_interfaces: Mapping[str, Iterable[str]]) -> None:
|
||||
def update_sessions(
|
||||
self,
|
||||
session_interfaces: Mapping[str, Iterable[str]],
|
||||
benchmark_session_ids: Optional[set[str]] = None,
|
||||
) -> None:
|
||||
"""Restart the collector when the active bridge interface set changes."""
|
||||
benchmark_session_ids = benchmark_session_ids or set()
|
||||
normalized: dict[str, set[str]] = {}
|
||||
for session_id, interfaces in session_interfaces.items():
|
||||
if not session_id:
|
||||
@@ -44,11 +66,17 @@ class BridgeTelemetryManager:
|
||||
iface: tuple(sorted(session_id for session_id, ifaces in normalized.items() if iface in ifaces))
|
||||
for iface in normalized_interfaces
|
||||
}
|
||||
benchmark_by_interface = {
|
||||
iface: bool(session_ids_by_interface.get(iface))
|
||||
and all(session_id in benchmark_session_ids for session_id in session_ids_by_interface.get(iface, ()))
|
||||
for iface in normalized_interfaces
|
||||
}
|
||||
|
||||
with self._lock:
|
||||
interfaces_changed = set(normalized_interfaces) != self._interfaces
|
||||
self._interfaces = set(normalized_interfaces)
|
||||
self._session_ids_by_interface = session_ids_by_interface
|
||||
self._benchmark_by_interface = benchmark_by_interface
|
||||
if not interfaces_changed:
|
||||
return
|
||||
self._restart_locked()
|
||||
@@ -80,8 +108,21 @@ class BridgeTelemetryManager:
|
||||
",".join(sorted(self._interfaces)),
|
||||
"--build-dir",
|
||||
settings.bridge_bpf_build_dir,
|
||||
"--raw-sample-every",
|
||||
str(settings.bridge_telemetry_raw_sample_every),
|
||||
"--meta-sample-every",
|
||||
str(settings.bridge_telemetry_meta_sample_every),
|
||||
"--ingress-pages",
|
||||
str(settings.bridge_telemetry_ingress_perf_pages),
|
||||
"--meta-pages",
|
||||
str(settings.bridge_telemetry_meta_perf_pages),
|
||||
]
|
||||
logger.info("Starting bridge telemetry collector for interfaces=%s", sorted(self._interfaces))
|
||||
logger.info(
|
||||
"Starting bridge telemetry collector for interfaces=%s raw_sample_every=%s meta_sample_every=%s",
|
||||
sorted(self._interfaces),
|
||||
settings.bridge_telemetry_raw_sample_every,
|
||||
settings.bridge_telemetry_meta_sample_every,
|
||||
)
|
||||
try:
|
||||
self._process = subprocess.Popen(
|
||||
cmd,
|
||||
@@ -158,6 +199,118 @@ class BridgeTelemetryManager:
|
||||
except Exception:
|
||||
logger.exception("Failed to process ingress raw packet event")
|
||||
|
||||
def _event_worker_loop(self) -> None:
|
||||
while True:
|
||||
event = self._event_queue.get()
|
||||
try:
|
||||
if not isinstance(event, dict):
|
||||
continue
|
||||
|
||||
iface = str(event.get("iface") or "")
|
||||
with self._lock:
|
||||
benchmark_mode = bool(self._benchmark_by_interface.get(iface))
|
||||
if benchmark_mode:
|
||||
raw_b64 = event.pop("raw_b64", None)
|
||||
with self._lock:
|
||||
self._benchmark_events += 1
|
||||
if raw_b64:
|
||||
self._benchmark_raw_payloads += 1
|
||||
continue
|
||||
|
||||
if event.get("event_type") == "ingress":
|
||||
self._handle_ingress_packet(event)
|
||||
|
||||
try:
|
||||
packet_tracker.observe_telemetry(event)
|
||||
except Exception:
|
||||
logger.exception("Failed to process telemetry event: %s", event)
|
||||
finally:
|
||||
self._event_queue.task_done()
|
||||
|
||||
def _enqueue_event(self, event: dict[str, object]) -> None:
|
||||
try:
|
||||
self._event_queue.put_nowait(event)
|
||||
return
|
||||
except queue.Full:
|
||||
pass
|
||||
|
||||
raw_b64 = event.pop("raw_b64", None)
|
||||
dropped_raw = isinstance(raw_b64, str) and bool(raw_b64)
|
||||
dropped_events, dropped_raw_payloads = self._drain_overloaded_queue()
|
||||
|
||||
try:
|
||||
self._event_queue.put_nowait(event)
|
||||
except queue.Full:
|
||||
with self._lock:
|
||||
self._dropped_events += dropped_events + 1
|
||||
self._dropped_raw_payloads += dropped_raw_payloads
|
||||
self._log_drop_summary()
|
||||
return
|
||||
|
||||
with self._lock:
|
||||
self._dropped_events += dropped_events + 1
|
||||
self._dropped_raw_payloads += dropped_raw_payloads
|
||||
if dropped_raw:
|
||||
self._dropped_raw_payloads += 1
|
||||
self._log_drop_summary()
|
||||
|
||||
def _drain_overloaded_queue(self) -> tuple[int, int]:
|
||||
target_size = min(
|
||||
settings.bridge_telemetry_queue_recovery_size,
|
||||
max(settings.bridge_telemetry_event_queue_maxsize - 1, 0),
|
||||
)
|
||||
dropped_events = 0
|
||||
dropped_raw_payloads = 0
|
||||
while self._event_queue.qsize() > target_size:
|
||||
try:
|
||||
stale_event = self._event_queue.get_nowait()
|
||||
self._event_queue.task_done()
|
||||
except queue.Empty:
|
||||
break
|
||||
|
||||
dropped_events += 1
|
||||
if isinstance(stale_event, dict) and stale_event.get("raw_b64"):
|
||||
dropped_raw_payloads += 1
|
||||
|
||||
return dropped_events, dropped_raw_payloads
|
||||
|
||||
def _log_drop_summary(self) -> None:
|
||||
now_ts = time.time()
|
||||
if now_ts - self._last_drop_log_at < settings.bridge_telemetry_drop_log_interval_seconds:
|
||||
return
|
||||
|
||||
self._last_drop_log_at = now_ts
|
||||
with self._lock:
|
||||
dropped_events = self._dropped_events
|
||||
dropped_raw_payloads = self._dropped_raw_payloads
|
||||
queue_size = self._event_queue.qsize()
|
||||
|
||||
logger.warning(
|
||||
"Bridge telemetry is overloaded; queue=%s dropped_events=%s dropped_raw_payloads=%s",
|
||||
queue_size,
|
||||
dropped_events,
|
||||
dropped_raw_payloads,
|
||||
)
|
||||
|
||||
def _log_collector_message(self, text: str) -> None:
|
||||
lower_text = text.lower()
|
||||
is_loss_message = "lost" in lower_text and "sample" in lower_text
|
||||
if not is_loss_message:
|
||||
logger.info("bridge-telemetry: %s", text)
|
||||
return
|
||||
|
||||
now_ts = time.time()
|
||||
if now_ts - self._last_collector_warning_at < settings.bridge_telemetry_drop_log_interval_seconds:
|
||||
with self._lock:
|
||||
self._suppressed_collector_messages += 1
|
||||
return
|
||||
|
||||
with self._lock:
|
||||
suppressed = self._suppressed_collector_messages
|
||||
self._suppressed_collector_messages = 0
|
||||
self._last_collector_warning_at = now_ts
|
||||
logger.warning("bridge-telemetry: %s (suppressed similar messages=%s)", text, suppressed)
|
||||
|
||||
def _read_loop(self, process: subprocess.Popen[str]) -> None:
|
||||
stdout = process.stdout
|
||||
if stdout is None:
|
||||
@@ -170,24 +323,30 @@ class BridgeTelemetryManager:
|
||||
try:
|
||||
event = json.loads(text)
|
||||
except json.JSONDecodeError:
|
||||
logger.info("bridge-telemetry: %s", text)
|
||||
self._log_collector_message(text)
|
||||
continue
|
||||
|
||||
if "event_type" not in event:
|
||||
logger.info("bridge-telemetry: %s", event)
|
||||
continue
|
||||
|
||||
if event.get("event_type") == "ingress":
|
||||
self._handle_ingress_packet(event)
|
||||
|
||||
try:
|
||||
packet_tracker.observe_telemetry(event)
|
||||
except Exception:
|
||||
logger.exception("Failed to process telemetry event: %s", event)
|
||||
self._enqueue_event(event)
|
||||
|
||||
rc = process.poll()
|
||||
if rc not in (0, None):
|
||||
logger.warning("Bridge telemetry collector exited with code %s", rc)
|
||||
|
||||
def get_debug_snapshot(self) -> dict[str, object]:
|
||||
with self._lock:
|
||||
return {
|
||||
"interfaces": sorted(self._interfaces),
|
||||
"benchmark_by_interface": dict(self._benchmark_by_interface),
|
||||
"queue_size": self._event_queue.qsize(),
|
||||
"dropped_events": self._dropped_events,
|
||||
"dropped_raw_payloads": self._dropped_raw_payloads,
|
||||
"benchmark_events": self._benchmark_events,
|
||||
"benchmark_raw_payloads": self._benchmark_raw_payloads,
|
||||
}
|
||||
|
||||
|
||||
bridge_telemetry_manager = BridgeTelemetryManager()
|
||||
|
||||
@@ -20,6 +20,10 @@ from src.Models.packets import PacketDBModel
|
||||
logger = logging.getLogger("packet_capture")
|
||||
|
||||
|
||||
def _utcnow() -> datetime:
|
||||
return datetime.now(timezone.utc)
|
||||
|
||||
|
||||
def _db_text(value: Any) -> Any:
|
||||
if value is None:
|
||||
return None
|
||||
@@ -168,6 +172,9 @@ def _derive_flow_id(payload: Dict[str, Any]) -> Optional[str]:
|
||||
|
||||
|
||||
def _attach_derived_fields(payload: Dict[str, Any]) -> None:
|
||||
if payload.get("timestamp") in (None, ""):
|
||||
payload["timestamp"] = _utcnow()
|
||||
|
||||
flow_id = _derive_flow_id(payload)
|
||||
if flow_id is not None:
|
||||
current_flow_id = payload.get("flow_id")
|
||||
@@ -228,6 +235,20 @@ class DatabasePool:
|
||||
max_size=self._max_size,
|
||||
)
|
||||
async with self._pool.acquire() as conn:
|
||||
await conn.execute(
|
||||
"""
|
||||
DO $$
|
||||
BEGIN
|
||||
IF to_regclass('packets') IS NOT NULL THEN
|
||||
UPDATE packets
|
||||
SET timestamp = COALESCE(updated_at, NOW())
|
||||
WHERE timestamp IS NULL;
|
||||
END IF;
|
||||
END $$;
|
||||
"""
|
||||
)
|
||||
await conn.execute("ALTER TABLE IF EXISTS packets ALTER COLUMN timestamp SET DEFAULT NOW()")
|
||||
await conn.execute("ALTER TABLE IF EXISTS packets ALTER COLUMN timestamp SET NOT NULL")
|
||||
await conn.execute(
|
||||
"""
|
||||
ALTER TABLE IF EXISTS packets
|
||||
@@ -263,6 +284,41 @@ class DatabasePool:
|
||||
if self._pool is None:
|
||||
await self.init_pool()
|
||||
|
||||
if self._pool is None:
|
||||
return
|
||||
|
||||
try:
|
||||
async with self._pool.acquire() as conn:
|
||||
row = await self._upsert_packet_with_conn(conn, pkt_info)
|
||||
except Exception:
|
||||
logger.exception("DB upsert failed")
|
||||
return
|
||||
|
||||
self._publish_packet_row(pkt_info, row)
|
||||
|
||||
async def upsert_packets(self, packets: List[Dict[str, Any]]) -> None:
|
||||
"""Insert or update packet records using one database round-trip optimized batch path."""
|
||||
if not packets:
|
||||
return
|
||||
if self._pool is None:
|
||||
await self.init_pool()
|
||||
if self._pool is None:
|
||||
return
|
||||
|
||||
try:
|
||||
params = [self._packet_upsert_params(pkt_info) for pkt_info in packets]
|
||||
async with self._pool.acquire() as conn:
|
||||
await conn.executemany(self._packet_upsert_sql(returning=False), params)
|
||||
except Exception:
|
||||
logger.exception("DB packet batch upsert failed")
|
||||
raise
|
||||
|
||||
async def _upsert_packet_with_conn(self, conn: asyncpg.Connection, pkt_info: Dict[str, Any]) -> Optional[Dict[str, Any]]:
|
||||
"""Insert or update one packet record using an already-acquired connection."""
|
||||
row = await conn.fetchrow(self._packet_upsert_sql(returning=True), *self._packet_upsert_params(pkt_info))
|
||||
return dict(row) if row else None
|
||||
|
||||
def _packet_upsert_params(self, pkt_info: Dict[str, Any]) -> tuple[Any, ...]:
|
||||
_normalize_json_fields(pkt_info)
|
||||
_attach_derived_fields(pkt_info)
|
||||
|
||||
@@ -270,154 +326,154 @@ class DatabasePool:
|
||||
telemetry_metadata = pkt_info.get("telemetry_metadata")
|
||||
capture_observations = pkt_info.get("capture_observations")
|
||||
|
||||
try:
|
||||
async with self._pool.acquire() as conn:
|
||||
row = await conn.fetchrow(
|
||||
"""
|
||||
INSERT INTO packets (
|
||||
timestamp,
|
||||
correlation_key,
|
||||
packet_id,
|
||||
packet_uid,
|
||||
flow_id,
|
||||
capture_session_id,
|
||||
correlation_source,
|
||||
skb_mark,
|
||||
capture_iface,
|
||||
ingress_if,
|
||||
egress_if,
|
||||
verdict,
|
||||
verdict_reason,
|
||||
verdict_confidence,
|
||||
ingress_seen_at,
|
||||
egress_seen_at,
|
||||
verdict_seen_at,
|
||||
src_mac,
|
||||
dst_mac,
|
||||
eth_type_raw,
|
||||
vlan_id,
|
||||
src_ip,
|
||||
dst_ip,
|
||||
ip_proto_raw,
|
||||
src_port,
|
||||
dst_port,
|
||||
length,
|
||||
capture_sources,
|
||||
app_protocol,
|
||||
app_category,
|
||||
app_confidence,
|
||||
app_hostname,
|
||||
app_is_encrypted,
|
||||
app_risk_score,
|
||||
dpi_metadata,
|
||||
capture_metadata,
|
||||
telemetry_metadata,
|
||||
capture_observations,
|
||||
raw
|
||||
) VALUES(
|
||||
$1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14,$15,$16,$17,$18,$19,$20,
|
||||
$21,$22,$23,$24,$25,$26,$27,$28,$29,$30,$31,$32,$33,$34,$35::jsonb,$36::jsonb,$37::jsonb,$38::jsonb,$39
|
||||
)
|
||||
ON CONFLICT (correlation_key) DO UPDATE SET
|
||||
updated_at = NOW(),
|
||||
timestamp = CASE
|
||||
WHEN packets.timestamp IS NULL THEN EXCLUDED.timestamp
|
||||
WHEN EXCLUDED.timestamp IS NULL THEN packets.timestamp
|
||||
ELSE LEAST(packets.timestamp, EXCLUDED.timestamp)
|
||||
END,
|
||||
packet_id = COALESCE(EXCLUDED.packet_id, packets.packet_id),
|
||||
packet_uid = COALESCE(EXCLUDED.packet_uid, packets.packet_uid),
|
||||
flow_id = COALESCE(EXCLUDED.flow_id, packets.flow_id),
|
||||
capture_session_id = COALESCE(EXCLUDED.capture_session_id, packets.capture_session_id),
|
||||
correlation_source = COALESCE(EXCLUDED.correlation_source, packets.correlation_source),
|
||||
skb_mark = COALESCE(EXCLUDED.skb_mark, packets.skb_mark),
|
||||
capture_iface = COALESCE(EXCLUDED.capture_iface, packets.capture_iface),
|
||||
ingress_if = COALESCE(EXCLUDED.ingress_if, packets.ingress_if),
|
||||
egress_if = COALESCE(EXCLUDED.egress_if, packets.egress_if),
|
||||
verdict = COALESCE(EXCLUDED.verdict, packets.verdict),
|
||||
verdict_reason = COALESCE(EXCLUDED.verdict_reason, packets.verdict_reason),
|
||||
verdict_confidence = COALESCE(EXCLUDED.verdict_confidence, packets.verdict_confidence),
|
||||
ingress_seen_at = COALESCE(EXCLUDED.ingress_seen_at, packets.ingress_seen_at),
|
||||
egress_seen_at = COALESCE(EXCLUDED.egress_seen_at, packets.egress_seen_at),
|
||||
verdict_seen_at = COALESCE(EXCLUDED.verdict_seen_at, packets.verdict_seen_at),
|
||||
src_mac = COALESCE(EXCLUDED.src_mac, packets.src_mac),
|
||||
dst_mac = COALESCE(EXCLUDED.dst_mac, packets.dst_mac),
|
||||
eth_type_raw = COALESCE(EXCLUDED.eth_type_raw, packets.eth_type_raw),
|
||||
vlan_id = COALESCE(EXCLUDED.vlan_id, packets.vlan_id),
|
||||
src_ip = COALESCE(EXCLUDED.src_ip, packets.src_ip),
|
||||
dst_ip = COALESCE(EXCLUDED.dst_ip, packets.dst_ip),
|
||||
ip_proto_raw = COALESCE(EXCLUDED.ip_proto_raw, packets.ip_proto_raw),
|
||||
src_port = COALESCE(EXCLUDED.src_port, packets.src_port),
|
||||
dst_port = COALESCE(EXCLUDED.dst_port, packets.dst_port),
|
||||
length = COALESCE(EXCLUDED.length, packets.length),
|
||||
capture_sources = (
|
||||
SELECT ARRAY(
|
||||
SELECT DISTINCT source
|
||||
FROM unnest(
|
||||
COALESCE(packets.capture_sources, ARRAY[]::text[]) ||
|
||||
COALESCE(EXCLUDED.capture_sources, ARRAY[]::text[])
|
||||
) AS source
|
||||
)
|
||||
),
|
||||
app_protocol = COALESCE(EXCLUDED.app_protocol, packets.app_protocol),
|
||||
app_category = COALESCE(EXCLUDED.app_category, packets.app_category),
|
||||
app_confidence = COALESCE(EXCLUDED.app_confidence, packets.app_confidence),
|
||||
app_hostname = COALESCE(EXCLUDED.app_hostname, packets.app_hostname),
|
||||
app_is_encrypted = COALESCE(EXCLUDED.app_is_encrypted, packets.app_is_encrypted),
|
||||
app_risk_score = COALESCE(EXCLUDED.app_risk_score, packets.app_risk_score),
|
||||
dpi_metadata = COALESCE(EXCLUDED.dpi_metadata, packets.dpi_metadata),
|
||||
capture_metadata = COALESCE(EXCLUDED.capture_metadata, packets.capture_metadata),
|
||||
telemetry_metadata = COALESCE(EXCLUDED.telemetry_metadata, packets.telemetry_metadata),
|
||||
capture_observations = COALESCE(EXCLUDED.capture_observations, packets.capture_observations),
|
||||
raw = COALESCE(EXCLUDED.raw, packets.raw)
|
||||
RETURNING *
|
||||
""",
|
||||
pkt_info.get("timestamp"),
|
||||
pkt_info["correlation_key"],
|
||||
pkt_info.get("packet_id"),
|
||||
pkt_info.get("packet_uid"),
|
||||
pkt_info.get("flow_id"),
|
||||
pkt_info.get("capture_session_id"),
|
||||
pkt_info.get("correlation_source"),
|
||||
pkt_info.get("skb_mark"),
|
||||
pkt_info.get("capture_iface"),
|
||||
pkt_info.get("ingress_if"),
|
||||
pkt_info.get("egress_if"),
|
||||
pkt_info.get("verdict"),
|
||||
pkt_info.get("verdict_reason"),
|
||||
pkt_info.get("verdict_confidence"),
|
||||
pkt_info.get("ingress_seen_at"),
|
||||
pkt_info.get("egress_seen_at"),
|
||||
pkt_info.get("verdict_seen_at"),
|
||||
pkt_info.get("src_mac"),
|
||||
pkt_info.get("dst_mac"),
|
||||
pkt_info.get("eth_type_raw"),
|
||||
pkt_info.get("vlan_id"),
|
||||
pkt_info.get("src_ip"),
|
||||
pkt_info.get("dst_ip"),
|
||||
pkt_info.get("protocol_raw"),
|
||||
pkt_info.get("src_port"),
|
||||
pkt_info.get("dst_port"),
|
||||
pkt_info.get("length"),
|
||||
pkt_info.get("capture_sources"),
|
||||
pkt_info.get("app_protocol"),
|
||||
pkt_info.get("app_category"),
|
||||
pkt_info.get("app_confidence"),
|
||||
pkt_info.get("app_hostname"),
|
||||
pkt_info.get("app_is_encrypted"),
|
||||
pkt_info.get("app_risk_score"),
|
||||
json.dumps(dpi_metadata) if dpi_metadata is not None else None,
|
||||
json.dumps(pkt_info.get("capture_metadata")) if pkt_info.get("capture_metadata") is not None else None,
|
||||
json.dumps(telemetry_metadata) if telemetry_metadata is not None else None,
|
||||
json.dumps(capture_observations) if capture_observations is not None else None,
|
||||
pkt_info.get("raw"),
|
||||
)
|
||||
except Exception:
|
||||
logger.exception("DB upsert failed")
|
||||
return
|
||||
return (
|
||||
pkt_info.get("timestamp"),
|
||||
pkt_info["correlation_key"],
|
||||
pkt_info.get("packet_id"),
|
||||
pkt_info.get("packet_uid"),
|
||||
pkt_info.get("flow_id"),
|
||||
pkt_info.get("capture_session_id"),
|
||||
pkt_info.get("correlation_source"),
|
||||
pkt_info.get("skb_mark"),
|
||||
pkt_info.get("capture_iface"),
|
||||
pkt_info.get("ingress_if"),
|
||||
pkt_info.get("egress_if"),
|
||||
pkt_info.get("verdict"),
|
||||
pkt_info.get("verdict_reason"),
|
||||
pkt_info.get("verdict_confidence"),
|
||||
pkt_info.get("ingress_seen_at"),
|
||||
pkt_info.get("egress_seen_at"),
|
||||
pkt_info.get("verdict_seen_at"),
|
||||
pkt_info.get("src_mac"),
|
||||
pkt_info.get("dst_mac"),
|
||||
pkt_info.get("eth_type_raw"),
|
||||
pkt_info.get("vlan_id"),
|
||||
pkt_info.get("src_ip"),
|
||||
pkt_info.get("dst_ip"),
|
||||
pkt_info.get("protocol_raw"),
|
||||
pkt_info.get("src_port"),
|
||||
pkt_info.get("dst_port"),
|
||||
pkt_info.get("length"),
|
||||
pkt_info.get("capture_sources"),
|
||||
pkt_info.get("app_protocol"),
|
||||
pkt_info.get("app_category"),
|
||||
pkt_info.get("app_confidence"),
|
||||
pkt_info.get("app_hostname"),
|
||||
pkt_info.get("app_is_encrypted"),
|
||||
pkt_info.get("app_risk_score"),
|
||||
json.dumps(dpi_metadata) if dpi_metadata is not None else None,
|
||||
json.dumps(pkt_info.get("capture_metadata")) if pkt_info.get("capture_metadata") is not None else None,
|
||||
json.dumps(telemetry_metadata) if telemetry_metadata is not None else None,
|
||||
json.dumps(capture_observations) if capture_observations is not None else None,
|
||||
pkt_info.get("raw"),
|
||||
)
|
||||
|
||||
def _packet_upsert_sql(self, *, returning: bool) -> str:
|
||||
sql = """
|
||||
INSERT INTO packets (
|
||||
timestamp,
|
||||
correlation_key,
|
||||
packet_id,
|
||||
packet_uid,
|
||||
flow_id,
|
||||
capture_session_id,
|
||||
correlation_source,
|
||||
skb_mark,
|
||||
capture_iface,
|
||||
ingress_if,
|
||||
egress_if,
|
||||
verdict,
|
||||
verdict_reason,
|
||||
verdict_confidence,
|
||||
ingress_seen_at,
|
||||
egress_seen_at,
|
||||
verdict_seen_at,
|
||||
src_mac,
|
||||
dst_mac,
|
||||
eth_type_raw,
|
||||
vlan_id,
|
||||
src_ip,
|
||||
dst_ip,
|
||||
ip_proto_raw,
|
||||
src_port,
|
||||
dst_port,
|
||||
length,
|
||||
capture_sources,
|
||||
app_protocol,
|
||||
app_category,
|
||||
app_confidence,
|
||||
app_hostname,
|
||||
app_is_encrypted,
|
||||
app_risk_score,
|
||||
dpi_metadata,
|
||||
capture_metadata,
|
||||
telemetry_metadata,
|
||||
capture_observations,
|
||||
raw
|
||||
) VALUES(
|
||||
$1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14,$15,$16,$17,$18,$19,$20,
|
||||
$21,$22,$23,$24,$25,$26,$27,$28,$29,$30,$31,$32,$33,$34,$35::jsonb,$36::jsonb,$37::jsonb,$38::jsonb,$39
|
||||
)
|
||||
ON CONFLICT (correlation_key) DO UPDATE SET
|
||||
updated_at = NOW(),
|
||||
timestamp = CASE
|
||||
WHEN packets.timestamp IS NULL THEN EXCLUDED.timestamp
|
||||
WHEN EXCLUDED.timestamp IS NULL THEN packets.timestamp
|
||||
ELSE LEAST(packets.timestamp, EXCLUDED.timestamp)
|
||||
END,
|
||||
packet_id = COALESCE(EXCLUDED.packet_id, packets.packet_id),
|
||||
packet_uid = COALESCE(EXCLUDED.packet_uid, packets.packet_uid),
|
||||
flow_id = COALESCE(EXCLUDED.flow_id, packets.flow_id),
|
||||
capture_session_id = COALESCE(EXCLUDED.capture_session_id, packets.capture_session_id),
|
||||
correlation_source = COALESCE(EXCLUDED.correlation_source, packets.correlation_source),
|
||||
skb_mark = COALESCE(EXCLUDED.skb_mark, packets.skb_mark),
|
||||
capture_iface = COALESCE(EXCLUDED.capture_iface, packets.capture_iface),
|
||||
ingress_if = COALESCE(EXCLUDED.ingress_if, packets.ingress_if),
|
||||
egress_if = COALESCE(EXCLUDED.egress_if, packets.egress_if),
|
||||
verdict = COALESCE(EXCLUDED.verdict, packets.verdict),
|
||||
verdict_reason = COALESCE(EXCLUDED.verdict_reason, packets.verdict_reason),
|
||||
verdict_confidence = COALESCE(EXCLUDED.verdict_confidence, packets.verdict_confidence),
|
||||
ingress_seen_at = COALESCE(EXCLUDED.ingress_seen_at, packets.ingress_seen_at),
|
||||
egress_seen_at = COALESCE(EXCLUDED.egress_seen_at, packets.egress_seen_at),
|
||||
verdict_seen_at = COALESCE(EXCLUDED.verdict_seen_at, packets.verdict_seen_at),
|
||||
src_mac = COALESCE(EXCLUDED.src_mac, packets.src_mac),
|
||||
dst_mac = COALESCE(EXCLUDED.dst_mac, packets.dst_mac),
|
||||
eth_type_raw = COALESCE(EXCLUDED.eth_type_raw, packets.eth_type_raw),
|
||||
vlan_id = COALESCE(EXCLUDED.vlan_id, packets.vlan_id),
|
||||
src_ip = COALESCE(EXCLUDED.src_ip, packets.src_ip),
|
||||
dst_ip = COALESCE(EXCLUDED.dst_ip, packets.dst_ip),
|
||||
ip_proto_raw = COALESCE(EXCLUDED.ip_proto_raw, packets.ip_proto_raw),
|
||||
src_port = COALESCE(EXCLUDED.src_port, packets.src_port),
|
||||
dst_port = COALESCE(EXCLUDED.dst_port, packets.dst_port),
|
||||
length = COALESCE(EXCLUDED.length, packets.length),
|
||||
capture_sources = (
|
||||
SELECT ARRAY(
|
||||
SELECT DISTINCT source
|
||||
FROM unnest(
|
||||
COALESCE(packets.capture_sources, ARRAY[]::text[]) ||
|
||||
COALESCE(EXCLUDED.capture_sources, ARRAY[]::text[])
|
||||
) AS source
|
||||
)
|
||||
),
|
||||
app_protocol = COALESCE(EXCLUDED.app_protocol, packets.app_protocol),
|
||||
app_category = COALESCE(EXCLUDED.app_category, packets.app_category),
|
||||
app_confidence = COALESCE(EXCLUDED.app_confidence, packets.app_confidence),
|
||||
app_hostname = COALESCE(EXCLUDED.app_hostname, packets.app_hostname),
|
||||
app_is_encrypted = COALESCE(EXCLUDED.app_is_encrypted, packets.app_is_encrypted),
|
||||
app_risk_score = COALESCE(EXCLUDED.app_risk_score, packets.app_risk_score),
|
||||
dpi_metadata = COALESCE(EXCLUDED.dpi_metadata, packets.dpi_metadata),
|
||||
capture_metadata = COALESCE(EXCLUDED.capture_metadata, packets.capture_metadata),
|
||||
telemetry_metadata = COALESCE(EXCLUDED.telemetry_metadata, packets.telemetry_metadata),
|
||||
capture_observations = COALESCE(EXCLUDED.capture_observations, packets.capture_observations),
|
||||
raw = COALESCE(EXCLUDED.raw, packets.raw)
|
||||
"""
|
||||
if returning:
|
||||
sql += "\nRETURNING *"
|
||||
return sql
|
||||
|
||||
def _publish_packet_row(self, pkt_info: Dict[str, Any], row: Optional[Dict[str, Any]]) -> None:
|
||||
if row:
|
||||
persisted = _serialize_row_for_broadcast(dict(row))
|
||||
persisted = _serialize_row_for_broadcast(row)
|
||||
pkt_info.update(persisted)
|
||||
|
||||
if self.broadcaster:
|
||||
|
||||
@@ -13,6 +13,7 @@ import signal
|
||||
import socket
|
||||
import subprocess
|
||||
import sys
|
||||
from datetime import datetime, timezone
|
||||
from pathlib import Path
|
||||
from typing import Iterable
|
||||
|
||||
@@ -76,6 +77,8 @@ BPF_SOURCE = r"""
|
||||
#define EVENT_INGRESS 1
|
||||
#define EVENT_EGRESS 2
|
||||
#define EVENT_DROP 3
|
||||
#define RAW_SAMPLE_EVERY __RAW_SAMPLE_EVERY__
|
||||
#define META_SAMPLE_EVERY __META_SAMPLE_EVERY__
|
||||
|
||||
struct vlan_hdr_t {
|
||||
__be16 h_vlan_TCI;
|
||||
@@ -112,6 +115,16 @@ struct event_t {
|
||||
BPF_PERF_OUTPUT(ingress_events);
|
||||
BPF_PERF_OUTPUT(meta_events);
|
||||
|
||||
static __always_inline int should_emit_sample(__u32 packet_mark, __u32 every) {
|
||||
if (every == 0) {
|
||||
return 0;
|
||||
}
|
||||
if (every == 1) {
|
||||
return 1;
|
||||
}
|
||||
return (packet_mark % every) == 0;
|
||||
}
|
||||
|
||||
static __always_inline __u32 ensure_packet_mark(struct __sk_buff *skb) {
|
||||
__u32 next = skb->mark;
|
||||
|
||||
@@ -346,7 +359,11 @@ int handle_ingress(struct __sk_buff *skb) {
|
||||
return TC_ACT_OK;
|
||||
}
|
||||
|
||||
ingress_events.perf_submit_skb(skb, skb->len, &event, sizeof(event));
|
||||
if (should_emit_sample(event.skb_mark, RAW_SAMPLE_EVERY)) {
|
||||
ingress_events.perf_submit_skb(skb, skb->len, &event, sizeof(event));
|
||||
} else if (should_emit_sample(event.skb_mark, META_SAMPLE_EVERY)) {
|
||||
meta_events.perf_submit(skb, &event, sizeof(event));
|
||||
}
|
||||
return TC_ACT_OK;
|
||||
}
|
||||
|
||||
@@ -368,7 +385,9 @@ int handle_egress(struct __sk_buff *skb) {
|
||||
return TC_ACT_OK;
|
||||
}
|
||||
|
||||
meta_events.perf_submit(skb, &event, sizeof(event));
|
||||
if (should_emit_sample(event.skb_mark, META_SAMPLE_EVERY)) {
|
||||
meta_events.perf_submit(skb, &event, sizeof(event));
|
||||
}
|
||||
return TC_ACT_OK;
|
||||
}
|
||||
|
||||
@@ -397,7 +416,9 @@ TRACEPOINT_PROBE(skb, kfree_skb) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
meta_events.perf_submit(args, &event, sizeof(event));
|
||||
if (should_emit_sample(event.skb_mark, META_SAMPLE_EVERY)) {
|
||||
meta_events.perf_submit(args, &event, sizeof(event));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
"""
|
||||
@@ -427,6 +448,7 @@ class Event(ct.Structure):
|
||||
|
||||
TARGET_INTERFACES: set[str] = set()
|
||||
IPR: IPRoute | None = None
|
||||
OMIT_RAW_PAYLOAD = False
|
||||
|
||||
|
||||
def _run_checked(cmd: list[str]) -> None:
|
||||
@@ -484,6 +506,8 @@ def _build_payload(event: Event) -> dict[str, object] | None:
|
||||
|
||||
payload: dict[str, object] = {
|
||||
"event_type": _event_name(int(event.event_type)),
|
||||
"timestamp": datetime.now(timezone.utc).isoformat(),
|
||||
"kernel_ts_ns": int(event.ts_ns),
|
||||
"iface": iface,
|
||||
"skb_mark": int(event.skb_mark) or None,
|
||||
"length": int(event.length),
|
||||
@@ -523,7 +547,7 @@ def _emit_ingress_event(cpu: int, data: int, size: int) -> None:
|
||||
return
|
||||
|
||||
raw_size = size - ct.sizeof(Event)
|
||||
if raw_size > 0:
|
||||
if raw_size > 0 and not OMIT_RAW_PAYLOAD:
|
||||
raw = ct.string_at(data + ct.sizeof(Event), min(raw_size, int(event.length)))
|
||||
payload["raw_b64"] = base64.b64encode(raw).decode("ascii")
|
||||
|
||||
@@ -539,10 +563,46 @@ def _emit_meta_event(cpu: int, data: int, size: int) -> None:
|
||||
print(json.dumps(payload, separators=(",", ":")), flush=True)
|
||||
|
||||
|
||||
def _build_bpf_source(raw_sample_every: int, meta_sample_every: int) -> str:
|
||||
return (
|
||||
BPF_SOURCE.replace("__RAW_SAMPLE_EVERY__", str(max(0, raw_sample_every)))
|
||||
.replace("__META_SAMPLE_EVERY__", str(max(0, meta_sample_every)))
|
||||
)
|
||||
|
||||
|
||||
def _parse_args() -> argparse.Namespace:
|
||||
parser = argparse.ArgumentParser(description="tc/eBPF bridge telemetry collector")
|
||||
parser.add_argument("--ifaces", required=True, help="Comma-separated list of interfaces to instrument")
|
||||
parser.add_argument("--build-dir", required=True, help="Directory for compiled tc BPF objects")
|
||||
parser.add_argument(
|
||||
"--raw-sample-every",
|
||||
type=int,
|
||||
default=1,
|
||||
help="Emit full raw ingress packets every Nth marked packet. Use 0 to disable raw packet export.",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--meta-sample-every",
|
||||
type=int,
|
||||
default=1,
|
||||
help="Emit metadata events every Nth marked packet. Use 0 to disable metadata-only events.",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--ingress-pages",
|
||||
type=int,
|
||||
default=256,
|
||||
help="Perf-buffer page count for raw ingress packet events.",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--meta-pages",
|
||||
type=int,
|
||||
default=128,
|
||||
help="Perf-buffer page count for metadata events.",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--omit-raw-payload",
|
||||
action="store_true",
|
||||
help="Drain raw ingress events but do not base64-encode or print raw packet bytes.",
|
||||
)
|
||||
return parser.parse_args()
|
||||
|
||||
|
||||
@@ -621,6 +681,13 @@ def _cleanup_tc(ifaces: Iterable[str]) -> None:
|
||||
|
||||
def main() -> int:
|
||||
args = _parse_args()
|
||||
global OMIT_RAW_PAYLOAD
|
||||
OMIT_RAW_PAYLOAD = bool(args.omit_raw_payload)
|
||||
raw_sample_every = max(0, args.raw_sample_every)
|
||||
meta_sample_every = max(0, args.meta_sample_every)
|
||||
ingress_pages = max(1, args.ingress_pages)
|
||||
meta_pages = max(1, args.meta_pages)
|
||||
|
||||
global TARGET_INTERFACES
|
||||
TARGET_INTERFACES = {iface.strip() for iface in args.ifaces.split(",") if iface.strip()}
|
||||
if not TARGET_INTERFACES:
|
||||
@@ -630,7 +697,7 @@ def main() -> int:
|
||||
signal.signal(signal.SIGTERM, _sigterm)
|
||||
signal.signal(signal.SIGINT, _sigterm)
|
||||
|
||||
bpf = BPF(text=BPF_SOURCE)
|
||||
bpf = BPF(text=_build_bpf_source(raw_sample_every, meta_sample_every))
|
||||
ingress_prog_name = ""
|
||||
egress_prog_name = ""
|
||||
try:
|
||||
@@ -643,14 +710,19 @@ def main() -> int:
|
||||
"ingress_program": _json_safe(ingress_prog_name),
|
||||
"egress_program": _json_safe(egress_prog_name),
|
||||
"build_dir": str(args.build_dir),
|
||||
"raw_sample_every": raw_sample_every,
|
||||
"meta_sample_every": meta_sample_every,
|
||||
"ingress_pages": ingress_pages,
|
||||
"meta_pages": meta_pages,
|
||||
"omit_raw_payload": OMIT_RAW_PAYLOAD,
|
||||
},
|
||||
separators=(",", ":"),
|
||||
),
|
||||
flush=True,
|
||||
)
|
||||
|
||||
bpf["ingress_events"].open_perf_buffer(_emit_ingress_event, page_cnt=256)
|
||||
bpf["meta_events"].open_perf_buffer(_emit_meta_event, page_cnt=128)
|
||||
bpf["ingress_events"].open_perf_buffer(_emit_ingress_event, page_cnt=ingress_pages)
|
||||
bpf["meta_events"].open_perf_buffer(_emit_meta_event, page_cnt=meta_pages)
|
||||
while True:
|
||||
bpf.perf_buffer_poll()
|
||||
except KeyboardInterrupt:
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import asyncio
|
||||
import concurrent.futures
|
||||
import logging
|
||||
import threading
|
||||
import time
|
||||
@@ -52,6 +53,18 @@ def _parse_observation_timestamp(value: Any) -> datetime:
|
||||
return datetime.max.replace(tzinfo=timezone.utc)
|
||||
|
||||
|
||||
def _coerce_payload_timestamp(value: Any) -> datetime:
|
||||
if isinstance(value, datetime):
|
||||
return value if value.tzinfo is not None else value.replace(tzinfo=timezone.utc)
|
||||
if value not in (None, ""):
|
||||
try:
|
||||
parsed = datetime.fromisoformat(str(value).replace("Z", "+00:00"))
|
||||
return parsed if parsed.tzinfo is not None else parsed.replace(tzinfo=timezone.utc)
|
||||
except Exception:
|
||||
pass
|
||||
return _utcnow()
|
||||
|
||||
|
||||
def _bridge_af_packet_observation_groups(payload: Dict[str, Any]) -> Dict[str, set[str]]:
|
||||
groups: Dict[str, set[str]] = {}
|
||||
observations = payload.get("capture_observations") or []
|
||||
@@ -174,7 +187,17 @@ class PacketTracker:
|
||||
"persisted_without_raw": 0,
|
||||
"persisted_kernel_mark": 0,
|
||||
"persisted_legacy_hash": 0,
|
||||
"persist_failed_total": 0,
|
||||
"persist_timeout_total": 0,
|
||||
"persist_failure_log_suppressed": 0,
|
||||
"persist_batch_total": 0,
|
||||
"persist_batch_failed_total": 0,
|
||||
"evicted_persisted_total": 0,
|
||||
"evicted_unpersisted_total": 0,
|
||||
"dropped_failed_persist_total": 0,
|
||||
"dropped_stale_dirty_total": 0,
|
||||
}
|
||||
self._last_persist_error_log_at = 0.0
|
||||
self._lock = threading.Lock()
|
||||
self._stop_event = threading.Event()
|
||||
self._thread = threading.Thread(target=self._run, daemon=True, name="packet-tracker")
|
||||
@@ -233,6 +256,7 @@ class PacketTracker:
|
||||
self._merge_packet_info(entry, pkt_info, now_ts)
|
||||
self._maybe_promote_reject_from_reply(pkt_info, now_ts)
|
||||
self._maybe_mark_complete(entry)
|
||||
self._enforce_entry_limit_locked()
|
||||
return correlation_key
|
||||
|
||||
def observe_telemetry(self, event: Dict[str, Any]) -> Optional[str]:
|
||||
@@ -257,6 +281,10 @@ class PacketTracker:
|
||||
payload["skb_mark"] = event.get("skb_mark") or payload.get("skb_mark")
|
||||
payload["telemetry_metadata"] = event
|
||||
payload["last_observed_at"] = now_ts
|
||||
event_timestamp = _coerce_payload_timestamp(event.get("timestamp"))
|
||||
current_timestamp = payload.get("timestamp")
|
||||
if current_timestamp in (None, "") or event_timestamp < _coerce_payload_timestamp(current_timestamp):
|
||||
payload["timestamp"] = event_timestamp
|
||||
self._add_capture_source(payload, "telemetry")
|
||||
self._add_capture_observation(
|
||||
payload,
|
||||
@@ -313,15 +341,18 @@ class PacketTracker:
|
||||
payload["verdict_seen_at"] = _utcnow()
|
||||
|
||||
entry["last_observed_at"] = now_ts
|
||||
if not entry["dirty"]:
|
||||
entry["first_dirty_at"] = now_ts
|
||||
entry["dirty"] = True
|
||||
self._maybe_mark_complete(entry)
|
||||
self._enforce_entry_limit_locked()
|
||||
return correlation_key
|
||||
|
||||
def _new_entry(self, correlation_key: str, now_ts: float) -> Dict[str, Any]:
|
||||
return {
|
||||
"correlation_key": correlation_key,
|
||||
"payload": {
|
||||
"timestamp": None,
|
||||
"timestamp": _utcnow(),
|
||||
"correlation_key": correlation_key,
|
||||
"correlation_source": None,
|
||||
"packet_id": None,
|
||||
@@ -344,8 +375,36 @@ class PacketTracker:
|
||||
"created_at": now_ts,
|
||||
"last_observed_at": now_ts,
|
||||
"last_persisted_at": 0.0,
|
||||
"last_persist_attempt_at": 0.0,
|
||||
"first_dirty_at": now_ts,
|
||||
"persist_failures": 0,
|
||||
}
|
||||
|
||||
def _enforce_entry_limit_locked(self) -> None:
|
||||
overflow = len(self._entries) - settings.packet_tracker_max_entries
|
||||
if overflow <= 0:
|
||||
return
|
||||
eviction_chunk = max(1, min(settings.packet_tracker_flush_batch_size, settings.packet_tracker_max_entries))
|
||||
evict_count = min(len(self._entries), max(overflow, eviction_chunk))
|
||||
|
||||
candidates = sorted(
|
||||
self._entries.items(),
|
||||
key=lambda item: (
|
||||
0 if item[1].get("persisted") else 1,
|
||||
0 if item[1].get("finalized") else 1,
|
||||
float(item[1].get("last_observed_at") or 0.0),
|
||||
),
|
||||
)
|
||||
for correlation_key, entry in candidates[:evict_count]:
|
||||
if entry.get("persisted"):
|
||||
self._stats["evicted_persisted_total"] += 1
|
||||
if entry.get("finalized") and not entry.get("stats_recorded"):
|
||||
self._record_stats(entry["payload"])
|
||||
entry["stats_recorded"] = True
|
||||
else:
|
||||
self._stats["evicted_unpersisted_total"] += 1
|
||||
self._entries.pop(correlation_key, None)
|
||||
|
||||
def _ensure_correlation(self, payload: Dict[str, Any]) -> Optional[str]:
|
||||
skb_mark = payload.get("skb_mark")
|
||||
if payload.get("packet_id") is None and skb_mark is not None:
|
||||
@@ -454,6 +513,8 @@ class PacketTracker:
|
||||
|
||||
payload["last_observed_at"] = now_ts
|
||||
entry["last_observed_at"] = now_ts
|
||||
if changed and not entry["dirty"]:
|
||||
entry["first_dirty_at"] = now_ts
|
||||
entry["dirty"] = entry["dirty"] or changed
|
||||
|
||||
def _maybe_backfill_bridge_af_packet_path(self, payload: Dict[str, Any]) -> bool:
|
||||
@@ -628,20 +689,32 @@ class PacketTracker:
|
||||
entry["payload"]["verdict_reason"] = "timeout"
|
||||
entry["payload"]["verdict_confidence"] = "low"
|
||||
entry["payload"]["verdict_seen_at"] = _utcnow()
|
||||
if not entry["dirty"]:
|
||||
entry["first_dirty_at"] = now_ts
|
||||
entry["dirty"] = True
|
||||
|
||||
if self._should_drop_dirty_entry(entry, now_ts):
|
||||
if int(entry.get("persist_failures") or 0) >= settings.packet_tracker_max_persist_failures:
|
||||
self._stats["dropped_failed_persist_total"] += 1
|
||||
else:
|
||||
self._stats["dropped_stale_dirty_total"] += 1
|
||||
expired_keys.append(correlation_key)
|
||||
continue
|
||||
|
||||
should_flush = entry["dirty"] and (
|
||||
not entry["persisted"]
|
||||
or entry["finalized"]
|
||||
or (now_ts - entry["last_persisted_at"]) >= self._min_flush_interval_seconds
|
||||
)
|
||||
if should_flush:
|
||||
due_entries.append(
|
||||
{
|
||||
"correlation_key": entry["correlation_key"],
|
||||
"payload": dict(entry["payload"]),
|
||||
}
|
||||
)
|
||||
if should_flush and self._persist_backoff_elapsed(entry, now_ts):
|
||||
if len(due_entries) < settings.packet_tracker_flush_batch_size:
|
||||
due_entries.append(
|
||||
{
|
||||
"correlation_key": entry["correlation_key"],
|
||||
"payload": dict(entry["payload"]),
|
||||
}
|
||||
)
|
||||
entry["last_persist_attempt_at"] = now_ts
|
||||
elif entry["persisted"] and age >= self._retention_seconds:
|
||||
if entry["finalized"] and not entry["stats_recorded"]:
|
||||
self._record_stats(entry["payload"])
|
||||
@@ -651,28 +724,101 @@ class PacketTracker:
|
||||
for correlation_key in expired_keys:
|
||||
self._entries.pop(correlation_key, None)
|
||||
|
||||
for entry in due_entries:
|
||||
self._persist(entry)
|
||||
self._persist_batch(due_entries)
|
||||
|
||||
def _persist(self, entry: Dict[str, Any]) -> None:
|
||||
payload = dict(entry["payload"])
|
||||
def _persist_backoff_elapsed(self, entry: Dict[str, Any], now_ts: float) -> bool:
|
||||
failures = int(entry.get("persist_failures") or 0)
|
||||
if failures <= 0:
|
||||
return True
|
||||
|
||||
base = max(0.0, settings.packet_tracker_persist_retry_backoff_seconds)
|
||||
if base <= 0:
|
||||
return True
|
||||
|
||||
backoff = min(
|
||||
settings.packet_tracker_persist_retry_backoff_max_seconds,
|
||||
base * (2 ** min(failures - 1, 6)),
|
||||
)
|
||||
return now_ts - float(entry.get("last_persist_attempt_at") or 0.0) >= backoff
|
||||
|
||||
def _persist_batch(self, entries: List[Dict[str, Any]]) -> None:
|
||||
if not entries:
|
||||
return
|
||||
|
||||
payloads = [dict(entry["payload"]) for entry in entries]
|
||||
web_loop = getattr(shared_objects, "web_loop", None)
|
||||
web_db = getattr(shared_objects, "db", None)
|
||||
if web_loop is None or web_db is None:
|
||||
return
|
||||
|
||||
fut: concurrent.futures.Future[Any]
|
||||
try:
|
||||
fut = asyncio.run_coroutine_threadsafe(web_db.upsert_packet(payload), web_loop)
|
||||
fut.result(timeout=settings.packet_tracker_persist_timeout_seconds)
|
||||
if hasattr(web_db, "upsert_packets"):
|
||||
fut = asyncio.run_coroutine_threadsafe(web_db.upsert_packets(payloads), web_loop)
|
||||
else:
|
||||
fut = asyncio.run_coroutine_threadsafe(self._persist_payloads_one_by_one(web_db, payloads), web_loop)
|
||||
timeout = max(
|
||||
settings.packet_tracker_persist_timeout_seconds,
|
||||
settings.packet_tracker_batch_persist_timeout_seconds,
|
||||
)
|
||||
fut.result(timeout=timeout)
|
||||
with self._lock:
|
||||
current = self._entries.get(entry["correlation_key"])
|
||||
if current is not None:
|
||||
current["persisted"] = True
|
||||
current["dirty"] = False
|
||||
current["last_persisted_at"] = time.time()
|
||||
except Exception:
|
||||
logger.exception("Failed to persist packet %s", entry["correlation_key"])
|
||||
self._stats["persist_batch_total"] += 1
|
||||
persisted_at = time.time()
|
||||
for entry in entries:
|
||||
current = self._entries.get(entry["correlation_key"])
|
||||
if current is not None:
|
||||
current["persisted"] = True
|
||||
current["dirty"] = False
|
||||
current["last_persisted_at"] = persisted_at
|
||||
current["persist_failures"] = 0
|
||||
except Exception as exc:
|
||||
try:
|
||||
fut.cancel()
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
is_timeout = isinstance(exc, (TimeoutError, concurrent.futures.TimeoutError, asyncio.TimeoutError))
|
||||
with self._lock:
|
||||
self._stats["persist_batch_failed_total"] += 1
|
||||
self._stats["persist_failed_total"] += len(entries)
|
||||
if is_timeout:
|
||||
self._stats["persist_timeout_total"] += len(entries)
|
||||
for entry in entries:
|
||||
current = self._entries.get(entry["correlation_key"])
|
||||
if current is not None:
|
||||
if not current["dirty"]:
|
||||
current["first_dirty_at"] = time.time()
|
||||
current["dirty"] = True
|
||||
current["persist_failures"] = int(current.get("persist_failures") or 0) + 1
|
||||
|
||||
now_ts = time.time()
|
||||
if now_ts - self._last_persist_error_log_at >= settings.packet_tracker_error_log_interval_seconds:
|
||||
self._last_persist_error_log_at = now_ts
|
||||
logger.warning(
|
||||
"Packet persistence is overloaded; failed to persist batch of %s packets (%s). Further errors are rate-limited.",
|
||||
len(entries),
|
||||
type(exc).__name__,
|
||||
)
|
||||
else:
|
||||
with self._lock:
|
||||
self._stats["persist_failure_log_suppressed"] += 1
|
||||
|
||||
async def _persist_payloads_one_by_one(self, web_db: Any, payloads: List[Dict[str, Any]]) -> None:
|
||||
for payload in payloads:
|
||||
await web_db.upsert_packet(payload)
|
||||
|
||||
def _should_drop_dirty_entry(self, entry: Dict[str, Any], now_ts: float) -> bool:
|
||||
if not entry.get("dirty"):
|
||||
return False
|
||||
if entry.get("persisted"):
|
||||
return False
|
||||
if int(entry.get("persist_failures") or 0) >= settings.packet_tracker_max_persist_failures:
|
||||
return True
|
||||
max_dirty_age = settings.packet_tracker_max_dirty_age_seconds
|
||||
if max_dirty_age <= 0:
|
||||
return False
|
||||
return now_ts - float(entry.get("first_dirty_at") or entry.get("created_at") or now_ts) >= max_dirty_age
|
||||
|
||||
def _record_stats(self, payload: Dict[str, Any]) -> None:
|
||||
capture_sources = set(payload.get("capture_sources") or [])
|
||||
|
||||
39
documentation/backend/README.md
Normal file
@@ -0,0 +1,39 @@
|
||||
# Backend documentation
|
||||
|
||||
This directory documents the Python service in `backend/src`. It is written for
|
||||
developers and operators of the inline MITM test system. The source code remains
|
||||
the implementation authority; this documentation records the externally useful
|
||||
contracts, lifecycle, Linux integration, and data semantics that are easy to lose
|
||||
when reading individual modules.
|
||||
|
||||
## Reading order
|
||||
|
||||
1. [Architecture](architecture.md) explains the process, responsibilities, and
|
||||
lifecycle.
|
||||
2. [Sniffing modes](sniffing.md) gives the complete technical behavior and
|
||||
implications of AF_PACKET and TC/eBPF capture.
|
||||
3. [Capture pipeline](capture-pipeline.md) follows a packet from observation to
|
||||
persistence and realtime delivery.
|
||||
4. [HTTP and WebSocket API](api.md) lists every router mounted by the application.
|
||||
5. [Data and analysis](data-and-analysis.md) describes the packet record, database
|
||||
operations, and derived analysis views.
|
||||
6. [Host integration](host-integration.md) covers network, eBPF, nftables, tshark,
|
||||
and systemd side effects.
|
||||
7. [Configuration and deployment](configuration.md) records dependencies and all
|
||||
`BACKEND_*` settings.
|
||||
8. [Source reference](source-reference.md) documents every backend source module,
|
||||
including modules not mounted by the current application.
|
||||
|
||||
## Scope and conventions
|
||||
|
||||
All HTTP paths below include the FastAPI `root_path`, `/api`. The interactive
|
||||
schema is available at `/api/docs`, the alternative reference UI at `/api/redoc`,
|
||||
and the machine-readable contract at `/api/openapi.json`.
|
||||
|
||||
"Live" means a router is included by `src.main`. `nft_api.py` and
|
||||
`nftables_api.py` contain independent routers but are not included by the current
|
||||
entrypoint; they are documented as available-but-unmounted implementation paths.
|
||||
|
||||
Packet capture, firewall changes, bridge changes, and script deployment alter the
|
||||
host system. They must be used only in a controlled environment with explicit
|
||||
operator authorization.
|
||||
112
documentation/backend/api.md
Normal file
@@ -0,0 +1,112 @@
|
||||
# HTTP and WebSocket API
|
||||
|
||||
The application is served below `/api`. FastAPI validates request models and
|
||||
publishes the complete JSON Schema at `/api/openapi.json`; use it for exact field
|
||||
types and the current response schema. This page documents semantics and all
|
||||
mounted operations.
|
||||
|
||||
## General endpoints
|
||||
|
||||
| Method/path | Meaning |
|
||||
| --- | --- |
|
||||
| `GET /api/hello` | Simple application health response. |
|
||||
| `GET /api/versions` | Returns the Python runtime version. |
|
||||
|
||||
## Network: `/api/network`
|
||||
|
||||
| Method/path | Parameters/body | Behaviour |
|
||||
| --- | --- | --- |
|
||||
| `GET /interfaces` | none | Lists interfaces, addresses, flags, MTU, MAC, state and Ethernet profile. |
|
||||
| `GET /routes` | none | Lists kernel route entries and resolved output-interface names. |
|
||||
| `GET /links` | none | Lists raw link information. |
|
||||
| `GET /bridges` | none | Lists Linux bridges, STP state and current member details. |
|
||||
| `GET /full-state` | none | Combines interfaces, routes, links and bridges into one snapshot. |
|
||||
| `POST /interfaces/reset-defaults` | `{ interfaces: string[] }` | Resets each requested interface to MTU 1500 and attempts to restore an automatic Ethernet profile through `ethtool`. |
|
||||
| `POST /bridge/create` | `{ name, interfaces }` | Creates a Linux bridge and attaches listed interfaces. |
|
||||
| `POST /bridge/remove` | `{ name }` | Removes an existing bridge. |
|
||||
| `GET /bridge/link-state-watchers` | none | Returns all watcher states. |
|
||||
| `GET /bridge/{bridge_name}/link-state-watcher` | path name | Returns one bridge watcher state. |
|
||||
| `POST /bridge/{bridge_name}/link-state-watcher/enable` | optional recovery holdoff | Enables member failure/recovery propagation. |
|
||||
| `POST /bridge/{bridge_name}/link-state-watcher/disable` | path name | Stops and removes that watcher. |
|
||||
| `WS /ws/state` | none | Receives full network-state update payloads after network mutations. |
|
||||
|
||||
An interface object includes its kernel index, name, state, MAC, MTU, decoded flags,
|
||||
assigned IPv4/IPv6 addresses, and, where available, speed/duplex/autoneg data.
|
||||
|
||||
## Sniffer: `/api/sniffer`
|
||||
|
||||
| Method/path | Parameters/body | Behaviour |
|
||||
| --- | --- | --- |
|
||||
| `POST /start` | exactly one of `bridge` or `interface`; optional `bridge_capture_mode`, `benchmark_mode` | Creates a capture session. Bridge modes are `tc_ebpf` and `af_packet`. |
|
||||
| `POST /stop` | optional session ID or bridge/interface selector | Stops an identified session, target sessions, or all sessions according to the request. |
|
||||
| `GET /status` | none | Returns status keyed by captured interface: running/existing/up state, owner session, mode, and benchmark mode. |
|
||||
| `GET /debug` | none | Returns internal session, buffered-record, tshark, telemetry, and tracker state. Treat as diagnostic output, not a stable client contract. |
|
||||
|
||||
The start endpoint rejects requests containing both a bridge and an interface, or
|
||||
neither. A bridge defaults to `tc_ebpf`; an interface always captures using
|
||||
AF_PACKET.
|
||||
|
||||
## Packets: `/api/packets`
|
||||
|
||||
| Method/path | Parameters/body | Behaviour |
|
||||
| --- | --- | --- |
|
||||
| `GET /packets?limit=100` | `limit` 1–10,000 | Fetches most-recent normalized packet rows. |
|
||||
| `DELETE /packets?reset_id=true` | optional boolean | Clears packet history; can reset database identity state. |
|
||||
| `WS /ws/packets` | none | Receives packet updates from the in-process broadcaster. |
|
||||
|
||||
REST history is authoritative. WebSocket clients must expect connection loss and
|
||||
dropped messages for a slow subscriber, then refill missed state with `GET`.
|
||||
|
||||
## Analysis: `/api/analysis`
|
||||
|
||||
Every analysis endpoint accepts `since_minutes` when shown; its valid range is
|
||||
1 minute to 30 days. Results are derived from the stored packet history and do not
|
||||
claim ground truth about a physical topology or attack.
|
||||
|
||||
| Method/path | Main query controls | Result |
|
||||
| --- | --- | --- |
|
||||
| `GET /interface-hosts` | `since_minutes`, `limit_per_interface` | Likely hosts attached to each MITM-side interface. |
|
||||
| `GET /interface-host-protocols` | plus `limit_protocols_per_host` | Attachment inference with per-host protocol evidence. |
|
||||
| `GET /interface-protocol-paths` | `limit_paths` | Directional aggregated paths for a Sankey-style view. |
|
||||
| `GET /conversations` | `limit` | Aggregated directional endpoint conversations. |
|
||||
| `GET /conversation-flow-detail` | `flow_id` or directional endpoint/port fields; `protocol`, `limit_packets` | Ordered packets, subflows, and derived request/response events. |
|
||||
| `GET /host-intelligence` | `limit_hosts` | Host-centric peers, service and hostname hints. |
|
||||
| `GET /discovery` | `limit` | Discovery, naming and service-advertisement activity. |
|
||||
| `GET /anomalies` | `limit` | Heuristic scan, beacon, rare service, reset-heavy and drop-heavy candidates. |
|
||||
|
||||
`conversation-flow-detail` requires a `flow_id` or enough directional fields to
|
||||
identify a conversation. All analysis endpoints return 503 while the database is
|
||||
unavailable and 500 when their underlying query fails.
|
||||
|
||||
## Firewall: `/api/firewall`
|
||||
|
||||
| Method/path | Body/query | Behaviour |
|
||||
| --- | --- | --- |
|
||||
| `GET /rules` | none | Lists nftables ruleset in a predictable structured representation, enriched with textual rule data where possible. |
|
||||
| `DELETE /rules/{handle}` | optional family/table/chain defaults | Deletes the rule identified by its nft handle. |
|
||||
| `POST /raw` | `{ cmd: string }` | Executes an arbitrary textual nft command and returns stdout/stderr/return code. |
|
||||
|
||||
The raw endpoint is intentionally powerful and must not be exposed to untrusted
|
||||
clients. It changes the host firewall, not an application-local simulation.
|
||||
|
||||
## Scripts: `/api/scripts/scripts`
|
||||
|
||||
The doubled path is produced by the current combination of router and application
|
||||
prefixes. Scripts are Python NFQUEUE workers installed under `/srv/fw-scripts` and
|
||||
can have systemd units and isolated virtual environments.
|
||||
|
||||
| Method/path | Behaviour |
|
||||
| --- | --- |
|
||||
| `GET /` | Lists scripts and their unit mappings/status. |
|
||||
| `POST /` | Uploads a script multipart payload; accepts a script, optional requirements file and required name form field. |
|
||||
| `GET /{name}` | Downloads script source. |
|
||||
| `GET /{name}/requirements` | Downloads its requirements file. |
|
||||
| `PUT /{name}/requirements` | Replaces requirements and runs pip install in the script venv. |
|
||||
| `DELETE /{name}/requirements` | Deletes requirements and removes the venv. |
|
||||
| `POST /{name}/enable` | Creates/starts an NFQUEUE systemd service for a requested queue number. |
|
||||
| `POST /{name}/disable` | Stops/disables the service for a queue number. |
|
||||
| `DELETE /{name}` | Removes all, or one requested queue-number unit, then cleans script-related files as appropriate. |
|
||||
|
||||
Names allow letters, digits, `.`, `_`, and `-`; `.` and `..` are prohibited.
|
||||
Repository example scripts are protected from API modification. Enabling/uploading
|
||||
requirements has code-execution and host-service consequences.
|
||||
70
documentation/backend/architecture.md
Normal file
@@ -0,0 +1,70 @@
|
||||
# Backend architecture
|
||||
|
||||
## Process model
|
||||
|
||||
`src.main` constructs one FastAPI application with `root_path="/api"`. During
|
||||
startup it stores the running asyncio loop in `src.shared_objects`, creates an
|
||||
asyncpg `DatabasePool`, attaches a packet broadcaster to it, creates a second
|
||||
network-state broadcaster, and drains any capture records buffered before the DB
|
||||
became available. Shutdown stops capture, network resources, telemetry, tshark,
|
||||
and the packet tracker; then closes WebSocket broadcasters and the DB pool.
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
UI[Frontend/client] --> API[FastAPI /api]
|
||||
API --> NET[Network and bridge API]
|
||||
API --> CAP[Sniffer API]
|
||||
API --> FW[Firewall API]
|
||||
API --> SCR[Script API]
|
||||
CAP --> NS[network_sniffer]
|
||||
NS --> PT[PacketTracker]
|
||||
EBPF[tc/eBPF telemetry process] --> PT
|
||||
NS <--> TS[tshark workers]
|
||||
PT --> DB[(PostgreSQL packets)]
|
||||
DB --> PB[PacketBroadcaster]
|
||||
PB --> WS1[Packet WebSocket]
|
||||
NET --> NB[Network broadcaster]
|
||||
NB --> WS2[Network WebSocket]
|
||||
API --> DB
|
||||
```
|
||||
|
||||
## Component boundaries
|
||||
|
||||
| Component | Responsibility | Persistent state | Important side effects |
|
||||
| --- | --- | --- | --- |
|
||||
| `main.py` | app construction and lifecycle wiring | shared object references | starts/stops resources |
|
||||
| `api/` | validates requests and presents HTTP/WebSocket contracts | none by default | may alter Linux networking, nftables, or services |
|
||||
| `network_sniffer.py` | owns capture sessions and AF_PACKET sockets | in-process session map and pre-DB buffer | raw sockets, reader threads |
|
||||
| `packet_tracker.py` | merges capture and telemetry observations | bounded in-memory pending entries | asynchronous database persistence |
|
||||
| `database.py` | packet upsert/retrieval and SQL analysis | PostgreSQL `packets` table | WebSocket publication after single-row upserts |
|
||||
| `tshark_manager.py` | optional application-protocol enrichment | worker and metadata caches | `tshark` subprocesses/threads |
|
||||
| `bridge_telemetry.py` and `ebpf_bridge_events.py` | bridge tc/eBPF event collection | subprocess state and event queue | compiles/attaches tc programs |
|
||||
| `bridge_link_state_manager.py` | optionally propagates member failure/recovery state | watcher registry | link and Ethernet-profile changes |
|
||||
|
||||
## Shared runtime state
|
||||
|
||||
`shared_objects.py` intentionally holds process-wide references rather than using
|
||||
request-scoped dependency injection:
|
||||
|
||||
- `db`: initialized `DatabasePool`, or `None` after shutdown.
|
||||
- `web_loop`: FastAPI event loop used when worker threads need to schedule work.
|
||||
- `broadcaster`: packet update broadcaster.
|
||||
- `network_broadcaster`: network-state update broadcaster.
|
||||
|
||||
Endpoints that require the database return HTTP 503 when `shared_objects.db` is
|
||||
unavailable. Worker components should tolerate the DB not being ready by buffering
|
||||
or logging failure, rather than assuming the application has fully started.
|
||||
|
||||
## Router mounting
|
||||
|
||||
| Router module | Prefix added by `main.py` | Router-local prefix | Result |
|
||||
| --- | --- | --- | --- |
|
||||
| `network_api` | `/network` | none | `/api/network/...` |
|
||||
| `sniffer_api` | `/sniffer` | none | `/api/sniffer/...` |
|
||||
| `packet_api` | `/packets` | none | `/api/packets/...` |
|
||||
| `analysis_api` | `/analysis` | none | `/api/analysis/...` |
|
||||
| `nft_manager` | none | `/firewall` | `/api/firewall/...` |
|
||||
| `packet_scripting_api` | `/scripts` | `/scripts` | `/api/scripts/scripts/...` |
|
||||
|
||||
The last row reflects the current code exactly. It is worth preserving this fact in
|
||||
examples until the duplicated prefix is deliberately changed.
|
||||
82
documentation/backend/capture-pipeline.md
Normal file
@@ -0,0 +1,82 @@
|
||||
# Packet capture and correlation pipeline
|
||||
|
||||
## Capture modes
|
||||
|
||||
A sniffer session targets exactly one interface or bridge.
|
||||
|
||||
- **Interface target:** an `AF_PACKET` raw socket is opened on that interface;
|
||||
its effective mode is always `af_packet`.
|
||||
- **Bridge target with `af_packet`:** the bridge's member interfaces are captured
|
||||
with raw sockets.
|
||||
- **Bridge target with `tc_ebpf` (default):** no raw socket is opened for bridge
|
||||
ports. `BridgeTelemetryManager` manages an eBPF/tc helper that exports ingress
|
||||
raw data and egress/drop verdict-related events.
|
||||
- **Benchmark mode:** preserves session accounting but skips the normal userspace
|
||||
packet processing path, allowing capture-overhead measurements.
|
||||
|
||||
Sessions have UUIDs and record their label, target type, mode, snapshot of bridge
|
||||
ports, capture interfaces, socket map, thread, and stop event. Stopping by session
|
||||
ID is preferred. A target-specific stop finds matching sessions; an unqualified
|
||||
stop stops every session.
|
||||
|
||||
## End-to-end lifecycle
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant C as Capture socket or tc/eBPF
|
||||
participant N as network_sniffer
|
||||
participant T as tshark manager
|
||||
participant P as PacketTracker
|
||||
participant D as DatabasePool
|
||||
participant W as packet WebSocket
|
||||
C->>N: frame / telemetry event
|
||||
N->>N: parse headers, identity, observation metadata
|
||||
N->>T: lookup or schedule enrichment
|
||||
N->>P: capture observation
|
||||
C->>P: ingress/egress/verdict telemetry
|
||||
P->>P: correlate, merge and finalize record
|
||||
P->>D: upsert packet
|
||||
D->>W: publish normalized row
|
||||
```
|
||||
|
||||
`network_sniffer.parse_packet` parses Scapy packet objects, while
|
||||
`parse_packet_bytes` supports raw data. It extracts link, network, and transport
|
||||
fields; adds capture session/observation data; calculates or obtains correlation
|
||||
identifiers; and hands observations to `PacketTracker`. If the shared database or
|
||||
event loop is not yet usable, records are retained in a bounded in-memory buffer;
|
||||
`drain_buffer_to_shared_db` flushes it at application startup.
|
||||
|
||||
## Identity and merging
|
||||
|
||||
`packet_identity.build_packet_uid` makes a stable hash-based fallback identity
|
||||
from normalized packet fields. `packet_mark` decodes the shared skb-mark layout:
|
||||
it normalizes an observed mark, extracts a packet ID, and extracts a verdict hint.
|
||||
Kernel-mark identity is preferred when present; the hash fallback keeps capture and
|
||||
telemetry correlation possible when it is not.
|
||||
|
||||
`PacketTracker` aggregates observations in a bounded dictionary. It deduplicates
|
||||
observations, keeps capture and telemetry provenance, combines ingress/egress and
|
||||
verdict timing, and delays finalization briefly so companion events can arrive.
|
||||
It writes finalized or aged dirty records in batches, retries failed persistence
|
||||
with bounded exponential backoff, discards pending records for stopped interfaces,
|
||||
and exposes a debug snapshot. Its limits and timings are all configured through
|
||||
`BACKEND_PACKET_TRACKER_*` settings.
|
||||
|
||||
## tshark enrichment
|
||||
|
||||
`TsharkManager` starts one long-lived `tshark` process per enabled interface. It
|
||||
reads JSON output in a thread, derives protocol stacks, HTTP/TLS/DNS information,
|
||||
TCP flags, and stream context, then caches matching data for a configurable time
|
||||
window. The capture parser can use a heuristic immediately and the manager can
|
||||
backfill metadata or stream context into already stored rows. tshark is optional in
|
||||
the logical pipeline but enabled by default; a missing executable or worker failure
|
||||
is logged and does not stop capture.
|
||||
|
||||
## Realtime delivery
|
||||
|
||||
`PacketBroadcaster` maintains a bounded asyncio queue per subscriber. A successful
|
||||
single-row database upsert serializes the row and publishes it to subscribers.
|
||||
Slow consumers lose queued messages when their individual queue is full rather than
|
||||
blocking the capture or database path. `/api/packets/ws/packets` is therefore a
|
||||
live-update channel, not a lossless event log; clients should retrieve history over
|
||||
REST and use the WebSocket for incremental updates.
|
||||
73
documentation/backend/configuration.md
Normal file
@@ -0,0 +1,73 @@
|
||||
# Configuration and deployment
|
||||
|
||||
## Runtime dependencies
|
||||
|
||||
The service runs with Python 3.11 in the supplied Dockerfile and starts Uvicorn as
|
||||
`src.main:app` on port 8000 with reload enabled. Python dependencies include
|
||||
FastAPI/Pydantic, asyncpg, pyroute2, Scapy, pip-nftables, multipart handling, and
|
||||
WebSocket support. The image installs build tools, libpcap development headers,
|
||||
pkg-config, and `tshark`.
|
||||
|
||||
The host also needs facilities that a minimal application container normally does
|
||||
not have: a reachable PostgreSQL database, Linux network namespace permissions,
|
||||
raw-socket capability, access to `ip`/pyroute2 netlink operations, nftables and
|
||||
appropriate capability, `ethtool` where profile/reset functions are used,
|
||||
systemd/systemctl for scripts, and BCC/eBPF/tc tooling for `tc_ebpf` capture.
|
||||
|
||||
## Environment variables
|
||||
|
||||
All settings are loaded once by `src.config.load_settings`. Empty values use their
|
||||
default. Boolean true values are `1`, `true`, `yes`, or `on` (case-insensitive).
|
||||
|
||||
| Variable | Default | Purpose |
|
||||
| --- | --- | --- |
|
||||
| `BACKEND_DB_DSN` | `postgresql://mitm_user:mitm_password@localhost:5432/mitm_db` | PostgreSQL connection string. |
|
||||
| `BACKEND_LOG_LEVEL` | `DEBUG` | Python logging level. |
|
||||
| `BACKEND_DB_POOL_MIN_SIZE` / `MAX_SIZE` | `1` / `5` | asyncpg pool bounds. |
|
||||
| `BACKEND_BROADCAST_QUEUE_MAXSIZE` | `1024` | Per-WebSocket broadcast queue size. |
|
||||
| `BACKEND_PACKET_TRACKER_FINALIZE_DELAY_SECONDS` | `0.25` | Wait for related observations before finalizing. |
|
||||
| `BACKEND_PACKET_TRACKER_RETENTION_SECONDS` | `10.0` | Pending-entry retention. |
|
||||
| `BACKEND_PACKET_TRACKER_MIN_FLUSH_INTERVAL_SECONDS` | `0.05` | Minimum persistence flush interval. |
|
||||
| `BACKEND_PACKET_TRACKER_PERSIST_TIMEOUT_SECONDS` | `2.0` | One persistence attempt timeout. |
|
||||
| `BACKEND_PACKET_TRACKER_BATCH_PERSIST_TIMEOUT_SECONDS` | `10.0` | Batch persistence timeout. |
|
||||
| `BACKEND_PACKET_TRACKER_PERSIST_RETRY_BACKOFF_SECONDS` / `MAX_SECONDS` | `0.25` / `5.0` | Retry backoff bounds. |
|
||||
| `BACKEND_PACKET_TRACKER_ERROR_LOG_INTERVAL_SECONDS` | `5.0` | Failure-log throttling interval. |
|
||||
| `BACKEND_PACKET_TRACKER_FLUSH_BATCH_SIZE` | `500` | Maximum batch size; clamped to at least 1. |
|
||||
| `BACKEND_PACKET_TRACKER_MAX_ENTRIES` | `50000` | Bounded in-memory correlation capacity; clamped to at least 1. |
|
||||
| `BACKEND_PACKET_TRACKER_MAX_PERSIST_FAILURES` | `3` | Failure threshold; clamped to at least 1. |
|
||||
| `BACKEND_PACKET_TRACKER_MAX_DIRTY_AGE_SECONDS` | `60.0` | Maximum age before dirty data must be flushed. |
|
||||
| `BACKEND_PACKET_TRACKER_STOP_JOIN_TIMEOUT_SECONDS` | `2.0` | Tracker thread join timeout. |
|
||||
| `BACKEND_PACKET_TRACKER_REJECT_CORRELATION_WINDOW_SECONDS` | `1.0` | Rejection-event matching window. |
|
||||
| `BACKEND_SNIFFER_BUFFER_CAPACITY` | `20000` | Pre-DB capture buffer capacity. |
|
||||
| `BACKEND_SNIFFER_SOCKET_RCVBUF_BYTES` | `4194304` | Requested raw-socket receive buffer. |
|
||||
| `BACKEND_SNIFFER_SELECTOR_TIMEOUT_SECONDS` | `1.0` | Reader select timeout. |
|
||||
| `BACKEND_SNIFFER_RECV_BYTES` | `65536` | Maximum raw receive length. |
|
||||
| `BACKEND_SNIFFER_BUFFER_DRAIN_INTERVAL_SECONDS` | `5.0` | Buffered-record drain frequency. |
|
||||
| `BACKEND_SNIFFER_THREAD_JOIN_TIMEOUT_SECONDS` | `2.0` | Session reader join timeout. |
|
||||
| `BACKEND_BRIDGE_BPF_BUILD_DIR` | `/tmp/mitm-bpf` | eBPF build artifacts directory. |
|
||||
| `BACKEND_BRIDGE_TELEMETRY_RAW_SAMPLE_EVERY` / `META_SAMPLE_EVERY` | `1` / `1` | Raw/meta sampling rates; zero is allowed. |
|
||||
| `BACKEND_BRIDGE_TELEMETRY_INGRESS_PERF_PAGES` / `META_PERF_PAGES` | `256` / `128` | eBPF perf-buffer page counts. |
|
||||
| `BACKEND_BRIDGE_TELEMETRY_EVENT_QUEUE_MAXSIZE` | `20000` | Telemetry event queue cap. |
|
||||
| `BACKEND_BRIDGE_TELEMETRY_QUEUE_RECOVERY_SIZE` | `1000` | Queue recovery threshold. |
|
||||
| `BACKEND_BRIDGE_TELEMETRY_DROP_LOG_INTERVAL_SECONDS` | `5.0` | Telemetry-drop log throttling. |
|
||||
| `BACKEND_BRIDGE_LINK_STATE_THREAD_JOIN_TIMEOUT_SECONDS` | `2.0` | Link watcher join timeout. |
|
||||
| `BACKEND_BRIDGE_LINK_STATE_FAILURE_HOLDOFF_SECONDS` / `RECOVERY_HOLDOFF_SECONDS` | `0.75` / `1.0` | Delay before propagating failure/recovery. |
|
||||
| `BACKEND_BRIDGE_LINK_STATE_DEGRADED_RECHECK_SECONDS` | `0.5` | Degraded-link polling period. |
|
||||
| `BACKEND_TELEMETRY_PROCESS_STOP_TIMEOUT_SECONDS` / `READER_JOIN_TIMEOUT_SECONDS` | `3.0` / `2.0` | Telemetry subprocess shutdown limits. |
|
||||
| `BACKEND_TSHARK_ENABLED` | `true` | Enables tshark worker management. |
|
||||
| `BACKEND_TSHARK_DISPLAY_FILTER` | empty | Optional tshark display filter. |
|
||||
| `BACKEND_TSHARK_TRY_HEURISTIC_FIRST` | `true` | Applies local heuristic before tshark match. |
|
||||
| `BACKEND_TSHARK_CACHE_TTL_SECONDS` | `5.0` | Enrichment cache lifetime. |
|
||||
| `BACKEND_TSHARK_MATCH_WINDOW_MS` | `5000` | Capture-to-tshark matching window. |
|
||||
| `BACKEND_TSHARK_READER_JOIN_TIMEOUT_SECONDS` / `PROCESS_STOP_TIMEOUT_SECONDS` | `2.0` / `3.0` | tshark shutdown limits. |
|
||||
|
||||
## Operational safeguards
|
||||
|
||||
Run the API behind an authenticated, access-controlled boundary. The configured
|
||||
CORS policy currently permits every origin, method, and header; it is convenient
|
||||
for development but should not be treated as an authorization control. Keep DB
|
||||
credentials out of version control and use a production-specific DSN.
|
||||
|
||||
Before starting capture, verify target interface/bridge names and ensure recovery
|
||||
access to the host. Before using firewall or script endpoints, snapshot the nft
|
||||
ruleset and understand which systemd units and filesystem paths are in scope.
|
||||
65
documentation/backend/data-and-analysis.md
Normal file
@@ -0,0 +1,65 @@
|
||||
# Packet data, persistence, and analysis
|
||||
|
||||
## Packet record
|
||||
|
||||
`Models/packets.py` defines the normalized `PacketDBModel` returned by packet
|
||||
history APIs. It represents one correlated packet record, not necessarily one raw
|
||||
capture callback. A record may combine several observations.
|
||||
|
||||
| Field group | Fields | Meaning |
|
||||
| --- | --- | --- |
|
||||
| Identity | `id`, `timestamp`, `updated_at`, `correlation_key`, `correlation_source`, `packet_id`, `packet_uid`, `skb_mark` | Database identity and the evidence used to correlate capture/telemetry data. |
|
||||
| Path | `capture_iface`, `ingress_if`, `egress_if`, `capture_session_id`, `capture_sources` | Where and how it was observed. |
|
||||
| Link/network/transport | MACs, EtherType, IP protocol, IPs, ports, VLAN, length | Parsed packet headers. Raw numeric values are retained beside human-readable names. |
|
||||
| Application enrichment | `flow_id`, app protocol/master protocol/category/confidence/hostname/encryption/risk, `dpi_metadata` | tshark-derived context when available. |
|
||||
| Evidence | `raw_b64`, `raw_present`, capture/telemetry metadata and `capture_observations` | Raw bytes and provenance; may be absent. |
|
||||
| Outcome | `verdict`, reason/confidence, ingress/egress/verdict timestamps | Forwarding outcome inferred from telemetry. |
|
||||
|
||||
Each `PacketObservationModel` identifies whether its contribution was `capture` or
|
||||
`telemetry`, the source, interface, timestamp, event type, capture mode, session,
|
||||
and optional reason. Consumers should not assume that every optional field exists:
|
||||
AF_PACKET, tc/eBPF, and enrichment sources provide different evidence.
|
||||
|
||||
## DatabasePool
|
||||
|
||||
`DatabasePool` is an asyncpg wrapper initialized from `BACKEND_DB_DSN`. Startup
|
||||
makes compatibility changes to an existing `packets` table: fills missing
|
||||
timestamps, sets timestamp defaults/non-null constraints, adds
|
||||
`capture_observations` JSONB if needed, and creates an index on `packet_uid`.
|
||||
|
||||
Writes use an upsert keyed by `correlation_key`. `upsert_packet` returns a row and
|
||||
publishes it to the packet broadcaster; `upsert_packets` is a batched performance
|
||||
path and does not individually publish rows. Before writing, it normalizes JSON
|
||||
fields and attaches derived protocol, flow, and analysis fields.
|
||||
|
||||
Read/analysis methods are:
|
||||
|
||||
- `fetch_latest(limit)` for history.
|
||||
- `backfill_packet_metadata` and `backfill_stream_metadata` for late tshark data.
|
||||
- `infer_interface_hosts`, `infer_interface_host_protocols`, and
|
||||
`infer_interface_protocol_paths` for topology/protocol views.
|
||||
- `analyze_conversations` and `fetch_conversation_flow_detail` for directional
|
||||
communication views.
|
||||
- `analyze_host_intelligence`, `analyze_discovery_activity`, and
|
||||
`analyze_anomalies` for investigation aids.
|
||||
- `clear_all_packets(reset_identity)` for destructive history cleanup.
|
||||
|
||||
## Analysis interpretation
|
||||
|
||||
The analysis API runs SQL aggregations over what the system captured. It infers
|
||||
attachment from traffic evidence, groups protocol paths and conversations, and
|
||||
derives host/service/hostname hints. Its anomaly queries rank plausible scan,
|
||||
beacon, rare-service, TCP-reset, and drop-heavy patterns. These are leads for an
|
||||
operator—not assertions of a network's real topology, attribution, or malicious
|
||||
intent. Missing capture events, encrypted traffic, NAT, asymmetric paths, and
|
||||
limits change the output.
|
||||
|
||||
## Enumerations and configuration models
|
||||
|
||||
`Models/etherType.py` provides a string-valued `EtherTypeEnum` and
|
||||
`ethertype_from_int`; `Models/ip_protocol.py` provides `IPProtocolEnum` and
|
||||
`protocol_from_number`. They turn numeric protocol fields into readable labels
|
||||
while keeping raw values. `Models/netplan.py` provides Pydantic schemas for
|
||||
nameservers, Ethernet settings, bridge settings, and a full Netplan-style network
|
||||
configuration. These models are reusable schemas; they are not a substitute for
|
||||
applying a Netplan configuration in the currently mounted API.
|
||||
90
documentation/backend/host-integration.md
Normal file
@@ -0,0 +1,90 @@
|
||||
# Linux host integration and side effects
|
||||
|
||||
## Network and bridge control
|
||||
|
||||
`api/network_api.py` retains process-wide pyroute2 `IPRoute` and `NDB` objects.
|
||||
It reads addresses, link flags, routes and bridge membership through netlink, and
|
||||
uses NDB/pyroute2 to create or remove bridges. Resetting interfaces executes
|
||||
`ethtool` and changes MTU/profile values. These operations affect the host's live
|
||||
connectivity; API errors must be treated as operational failures, not merely input
|
||||
validation failures.
|
||||
|
||||
`utilities/interface_bridge_helpers.py` is the low-level read layer. It checks
|
||||
interface presence/up state, reads sysfs operational/carrier/admin/MTU values,
|
||||
obtains Ethernet profile data using `ethtool`, caches profile data, and reads bridge
|
||||
members from sysfs. It deliberately supplies best-effort information when a driver
|
||||
or platform cannot report every property.
|
||||
|
||||
`bridge_link_state_manager.py` owns optional event-driven bridge watchers. Each
|
||||
watcher tracks Ethernet profile and member readiness, uses failure and recovery
|
||||
holdoffs to avoid flapping, and adjusts selected peer state so an inline bridge
|
||||
reacts coherently to member link loss. `BridgeLinkStateManager` indexes watchers,
|
||||
enables/disables them, reports individual/all status, and stops all during shutdown.
|
||||
|
||||
## eBPF/tc telemetry
|
||||
|
||||
`bridge_telemetry.py` manages the lifecycle of the telemetry helper. Its
|
||||
`update_sessions` method reconciles currently requested bridge ports with the
|
||||
subprocess; `stop` terminates it and `get_debug_snapshot` provides operator
|
||||
diagnostics. It does not itself parse kernel events.
|
||||
|
||||
`ebpf_bridge_events.py` is the helper process. It builds BPF source, attaches tc
|
||||
programs to requested interfaces, reads perf events, and writes JSON-safe event
|
||||
payloads. Events cover ingress raw capture plus egress/drop metadata, including
|
||||
interfaces, MAC/IP information, packet identity, event/reason names, and timing.
|
||||
It cleans existing clsact qdiscs/program attachment as part of setup/cleanup. This
|
||||
requires an appropriate kernel, BCC Python bindings/toolchain, tc, and privileges.
|
||||
|
||||
`tools/ebpf/mark_packet_id.c` is related kernel-side support for packet marking;
|
||||
the mark is decoded by `utilities/packet_mark.py` and used in tracker correlation.
|
||||
|
||||
## nftables
|
||||
|
||||
The mounted `api/nft_manager.py` uses `pip-nftables` to list JSON/text rulesets,
|
||||
normalize them into stable table/chain/rule models, parse rule priorities/text, and
|
||||
delete a rule by handle. Its raw-command endpoint forwards textual nft commands.
|
||||
It therefore needs capability to inspect and change the host nftables ruleset.
|
||||
|
||||
Two alternative implementations exist but are currently unmounted:
|
||||
|
||||
- `api/nft_api.py` is bridge-family oriented. It models meta, Ethernet, IP, port,
|
||||
conntrack, verdict, reject, log, and raw expressions; can generate previews,
|
||||
list rules with authoritative handles, add/delete/update rules, and uses the
|
||||
`nft` CLI.
|
||||
- `api/nftables_api.py` is a stateless typed replacement API. It models matches and
|
||||
actions, chooses a pyroute2 binding when viable or a CLI wrapper otherwise,
|
||||
ensures table/chain presence, reconstructs readable rules, and replaces a chain's
|
||||
ruleset. Its own source warns that a running asyncio loop may force CLI fallback.
|
||||
|
||||
Do not mount more than one firewall router without an explicit API versioning and
|
||||
conflict review: all manipulate shared kernel state and have overlapping concepts.
|
||||
|
||||
## NFQUEUE script services
|
||||
|
||||
`api/packet_scripting_api.py` manages executable Python scripts. It makes these
|
||||
directories at import time: `/srv/fw-scripts`, `/srv/fw-scripts/venvs`, and the
|
||||
repository's `backend/example_scripts`. Scripts are named `<name>.py`; requirements
|
||||
are `<name>-requirements.txt`; virtual environments are per-script. Units use the
|
||||
deterministic name `fw-script-<name>-q<queue>.service` and are written under
|
||||
`/etc/systemd/system`.
|
||||
|
||||
The module discovers services through `systemctl`, writes/parses unit `ExecStart`,
|
||||
runs `daemon-reload`, starts/stops/enables/disables units, creates virtualenvs, and
|
||||
uses pip to install user-provided requirements. Startup can copy protected example
|
||||
scripts and optionally deploy them from `<name>.deploy.json`. This API is a remote
|
||||
code/service-management surface and requires strict authentication plus host-level
|
||||
least privilege.
|
||||
|
||||
## External subprocesses
|
||||
|
||||
| Integration | Commands/facility | Used by |
|
||||
| --- | --- | --- |
|
||||
| tshark | long-lived `tshark` subprocesses | DPI enrichment |
|
||||
| nftables | `nft` CLI and/or pip-nftables bindings | firewall APIs |
|
||||
| Ethernet control | `ethtool` | interface profile/reset |
|
||||
| system services | `systemctl`, virtualenv, pip | script lifecycle |
|
||||
| BPF/tc | BCC, tc, qdisc/program attachment | bridge telemetry |
|
||||
|
||||
Failures are generally logged and translated to endpoint failures or degraded
|
||||
capture. Operators should collect `/api/sniffer/debug`, service logs, nftables
|
||||
state, and interface state when investigating a problem.
|
||||
233
documentation/backend/sniffing.md
Normal file
@@ -0,0 +1,233 @@
|
||||
# Technical reference: packet sniffing modes
|
||||
|
||||
This document specifies the implemented capture behavior in `network_sniffer.py`,
|
||||
`bridge_telemetry.py`, `ebpf_bridge_events.py`, and `packet_tracker.py`. It makes a
|
||||
deliberate distinction between observed facts and inferred forwarding results.
|
||||
|
||||
## Session model and mode selection
|
||||
|
||||
A capture session has a UUID and targets exactly one interface or exactly one
|
||||
bridge. A bridge is expanded once with `get_bridge_ports_once`; its member list is
|
||||
a creation-time snapshot. Later bridge membership changes are not added to the
|
||||
existing session. Session state includes target label/type, effective mode, benchmark
|
||||
flag, port snapshot, AF_PACKET sockets, optional reader thread, stop event, and
|
||||
benchmark counters.
|
||||
|
||||
| Request | Effective mode | Capture source | Path/outcome evidence |
|
||||
| --- | --- | --- | --- |
|
||||
| Interface, any requested mode | `af_packet` | One raw socket on the interface | Packet-socket type labels an outgoing copy as egress; no kernel verdict telemetry. |
|
||||
| Bridge, `af_packet` | `af_packet` | One raw socket per snapshot bridge port | Two matching port observations can infer forwarding. |
|
||||
| Bridge, `tc_ebpf` (default) | `tc_ebpf` | One tc/eBPF helper across snapshot bridge ports | TC ingress/egress and skb-free/drop events, normally matched by skb mark. |
|
||||
| Any mode with benchmark enabled | Same hook/socket setup | Counted but not processed | No parsing, enrichment, DB write, or WebSocket event. |
|
||||
|
||||
Interface targets always use AF_PACKET. The TC/eBPF mode is only selected for a
|
||||
bridge target. A stop by session ID is the safest selector. Stopping a session also
|
||||
discards pending tracker entries relating to its interfaces, so unpersisted data can
|
||||
be lost deliberately at shutdown.
|
||||
|
||||
Multiple sessions may overlap on an interface. This is not an independent-capture
|
||||
guarantee: the TC manager maps an interface to several sessions but assigns raw
|
||||
ingress parsing to the first sorted session ID.
|
||||
|
||||
## AF_PACKET capture
|
||||
|
||||
### Socket behavior
|
||||
|
||||
For each capture interface the service opens `AF_PACKET` / `SOCK_RAW` with protocol
|
||||
`htons(0x0003)` (`ETH_P_ALL`), requests the configured receive buffer (default
|
||||
4 MiB), best-effort requests `TPACKET_V3`, binds to `(ifname, 0)`, and makes the
|
||||
socket non-blocking. Failure to set the buffer or TPACKET version is non-fatal.
|
||||
Failure to create or bind leaves the interface uncaptured; session creation can still
|
||||
complete. This requires raw-socket privilege, commonly `CAP_NET_RAW`.
|
||||
|
||||
One daemon reader thread is started only when the session has sockets. It uses a
|
||||
selector, receives at most `BACKEND_SNIFFER_RECV_BYTES` bytes per event (default
|
||||
65,536), stamps the frame with userspace UTC receive time, creates Scapy `Ether`,
|
||||
and calls the common parser. `ENODEV`, `ENETDOWN`, and `EBADF` close the affected
|
||||
socket; it is not reopened in that session. The thread periodically attempts a
|
||||
pre-DB-buffer drain during selector idle time.
|
||||
|
||||
### Direction and bridge inference
|
||||
|
||||
Packet-socket address metadata is used only as follows: `PACKET_OUTGOING` (normally
|
||||
4) becomes `path_role: egress`; every other packet type becomes `path_role:
|
||||
ingress`. This is a packet-socket perspective, not proof of a Linux bridge decision.
|
||||
|
||||
For a bridge session, the tracker groups AF_PACKET observations by session ID. It
|
||||
uses an explicit ingress observation if available, otherwise the earliest one. It
|
||||
prefers an explicit egress observation on a different port, otherwise a later
|
||||
different-port observation. If one correlated packet is seen on at least two ports,
|
||||
the tracker records:
|
||||
|
||||
```text
|
||||
verdict = accept
|
||||
verdict_reason = bridge-af_packet-forwarded-observed
|
||||
verdict_confidence = medium
|
||||
```
|
||||
|
||||
This means matching evidence was observed on two bridge ports. It does not prove a
|
||||
particular kernel forwarding verdict and can be affected by duplicate copies, loops,
|
||||
or fallback-identity collisions. A single-interface AF_PACKET record has no terminal
|
||||
verdict from AF_PACKET itself.
|
||||
|
||||
### AF_PACKET implications
|
||||
|
||||
AF_PACKET provides full observed frame bytes without BCC or tc changes and is the
|
||||
only interface-capture mode. It neither alters packets nor controls forwarding. It
|
||||
also has no definitive drop visibility, reports userspace rather than kernel event
|
||||
time, can observe local/outgoing copies, and can lose traffic under socket/userspace
|
||||
load. The full-frame Scapy parse, tshark lookup, tracking and persistence path makes
|
||||
it more expensive than sampled telemetry.
|
||||
|
||||
## TC/eBPF bridge capture
|
||||
|
||||
### Collector lifecycle and destructive qdisc behavior
|
||||
|
||||
Bridge sessions in `tc_ebpf` mode are aggregated into one helper process. Any change
|
||||
to the active *interface set* stops the helper and recreates it for the new set;
|
||||
there is a capture gap during that restart. The helper attaches direct-action
|
||||
`BPF.SCHED_CLS` programs at TC ingress (`ffff:fff2`, handle `:20`) and egress
|
||||
(`ffff:fff3`, handle `:30`) to every bridge **member interface**, not the bridge
|
||||
device itself.
|
||||
|
||||
Before attachment the helper runs `tc qdisc del dev <iface> clsact` (ignoring its
|
||||
result), then `tc qdisc add dev <iface> clsact`. It deletes `clsact` again for every
|
||||
instrumented interface at helper shutdown and after an attachment failure.
|
||||
|
||||
> Starting, restarting, failing, or stopping TC/eBPF capture can remove pre-existing
|
||||
> clsact qdiscs and their filters. Do not use it on interfaces with unrelated TC
|
||||
> configuration unless coexistence and recovery are explicitly managed.
|
||||
|
||||
The BCC Python runtime, a compatible kernel, BPF/tracepoint access, TC and netlink
|
||||
privileges are required. Session creation does not wait for a collector health
|
||||
acknowledgement, so a successful start response is not proof that BPF attached.
|
||||
|
||||
### Kernel event generation
|
||||
|
||||
The helper opens a raw-ingress perf buffer and a metadata perf buffer. The ingress
|
||||
TC program creates an skb mark only when it is zero, using the low 28 bits of
|
||||
`bpf_ktime_get_ns()` and replacing zero with one. It preserves any existing nonzero
|
||||
mark. It extracts Ethernet addresses, EtherType, a single 802.1Q/802.1AD VLAN ID,
|
||||
ARP IPv4 addresses, and IPv4/IPv6 addresses with TCP/UDP ports. IPv6 extension
|
||||
headers are not traversed; the base next-header is used as protocol.
|
||||
|
||||
The egress TC program never creates a mark. It exports metadata only for marked
|
||||
packets. The `skb:kfree_skb` tracepoint reads the linear skb representation and
|
||||
exports a drop event only for marked skbs whose device is a selected interface.
|
||||
The emitted payload contains userspace and kernel-monotonic timestamps, interface,
|
||||
mark, length, parsed L2–L4 fields, and event type. Drop events add a numerical
|
||||
reason and `skb_drop_reason_<n>` label. Ingress events may contain `raw_b64`; egress
|
||||
and drop events do not.
|
||||
|
||||
A kfree_skb event is evidence that a marked skb was freed in the kernel context. It
|
||||
is not automatically evidence that nftables caused the outcome; interpret the
|
||||
reason code in the context of kernel behavior and other instrumentation.
|
||||
|
||||
### Sampling
|
||||
|
||||
Raw and metadata sampling are independent settings.
|
||||
|
||||
| Value | Effect |
|
||||
| --- | --- |
|
||||
| `0` | Never emits that sample category. |
|
||||
| `1` | Emits every marked packet in that category. |
|
||||
| `N > 1` | Emits when `skb_mark % N == 0`. |
|
||||
|
||||
At ingress, a raw-selected packet emits a raw event; only a packet not chosen for
|
||||
raw can emit an ingress metadata event. Egress and drop use metadata sampling only.
|
||||
Therefore raw-enabled/meta-disabled capture stores sampled ingress frame records
|
||||
without egress/drop visibility; raw-disabled/meta-enabled capture produces
|
||||
metadata-only rows without raw bytes. Both enabled does not make raw and metadata
|
||||
populations identical.
|
||||
|
||||
Sampling uses the entire existing skb mark. The documented mark layout reserves
|
||||
bits 0–27 for packet ID and upper bits for drop/reject hints. This capture program
|
||||
creates only the low-28-bit value for previously zero marks; it does not set verdict
|
||||
hints. Any other mark-using subsystem must coordinate its mark semantics, because
|
||||
it can change both sampling and correlation.
|
||||
|
||||
### Userspace event handling and loss
|
||||
|
||||
The manager reads JSON helper output into a bounded queue. For a non-benchmark
|
||||
ingress event with `raw_b64`, it decodes the frame and sends it into the common Scapy
|
||||
parser as source `tc_ingress_raw`, with `packet_id`, `skb_mark`, and capture mode
|
||||
`tc_ingress`. It then sends every non-benchmark ingress/egress/drop event to the
|
||||
tracker. A sampled raw ingress packet usually therefore has both a parsed capture
|
||||
observation and a telemetry observation under the same mark-derived key.
|
||||
|
||||
When the telemetry queue is full, the manager drops oldest queued events down to
|
||||
`BACKEND_BRIDGE_TELEMETRY_QUEUE_RECOVERY_SIZE`, attempts to keep the new event, and
|
||||
counts dropped events and raw payloads. Perf buffers can also lose samples before
|
||||
userspace. Neither loss mechanism is recovered. `/api/sniffer/debug` reports queue
|
||||
size, queue drops, benchmark counts, collector interfaces, and tracker statistics.
|
||||
|
||||
### TC/eBPF implications
|
||||
|
||||
This mode yields better within-host correlation and explicit TC egress evidence. A
|
||||
matching egress produces `accept`, `egress-observed`, confidence `high`; a matching
|
||||
drop produces `drop` (or mark hint), confidence `high`. Absence of egress is not
|
||||
proof of a drop: sampling, perf loss, queue loss, an uninstrumented path, teardown,
|
||||
or collector failure can all explain it. Raw bytes are ingress-only and sampled.
|
||||
|
||||
## Common parsing, enrichment, and identity
|
||||
|
||||
Both modes use `parse_packet` / `parse_packet_bytes`. The parser records Ethernet
|
||||
addresses, EtherType and VLAN, ARP operation/addressing, IPv4 ID or IPv6 base
|
||||
header, TCP sequence/acknowledgement/flags, UDP ports, ICMP/ICMPv6 type/code, and
|
||||
an embedded IPv4 tuple from eligible ICMP errors. It stores full raw frame bytes
|
||||
when supplied by AF_PACKET or sampled TC ingress.
|
||||
|
||||
tshark workers are enabled for non-benchmark capture interfaces. They may add
|
||||
application protocol, category, confidence, hostname, encryption/risk, and flow/DPI
|
||||
metadata. They are optional and asynchronous; a failure or late match does not
|
||||
discard underlying capture, and later backfill can enrich stored records.
|
||||
|
||||
The preferred identity is `pid:<packet-id>`, where the ID is bits 0–27 of skb mark.
|
||||
Without it, a SHA-1 `uid` is calculated. The Scapy fallback includes L2–L4 fields,
|
||||
IPv4 ID, ARP/ICMP fields and TCP sequence/ack/flags; eBPF metadata's fallback uses
|
||||
only the smaller L2–L4 tuple and length. Hash-only correlation is consequently a
|
||||
best-effort fallback, weaker for repeated/identical/fragmented traffic.
|
||||
|
||||
## Tracker outcomes and persistence
|
||||
|
||||
The tracker deduplicates observations, merges available fields, retains the earliest
|
||||
timestamp, and waits the configured finalization delay (default 250 ms).
|
||||
|
||||
| Evidence | Verdict | Confidence |
|
||||
| --- | --- | --- |
|
||||
| TC egress telemetry | `accept`; `egress-observed` | high |
|
||||
| TC drop telemetry | mark hint or `drop`; kernel reason / `kfree_skb` | high |
|
||||
| Matching recent TCP RST or ICMP unreachable after drop | `reject` | medium |
|
||||
| Same AF_PACKET bridge record on two ports | `accept`; forwarding observed | medium |
|
||||
| No terminal evidence before delay expires | `unknown`; `timeout` | low |
|
||||
|
||||
It asynchronously upserts batches to PostgreSQL. Entry-cap pressure, persistence
|
||||
failure/retry limits, dirty-age expiry, collector queue loss, socket loss, and
|
||||
shutdown can all cause incompleteness. A packet history or WebSocket feed is never
|
||||
a proof of lossless capture. Batch upserts also do not individually publish packet
|
||||
updates, so realtime consumers must use history reconciliation.
|
||||
|
||||
## Benchmark mode
|
||||
|
||||
Benchmark mode still creates sockets or TC hooks but bypasses normal processing.
|
||||
AF_PACKET increments received frame and byte counters. TC/eBPF increments helper
|
||||
event counters and raw-payload-event counters. It does not parse Scapy, invoke
|
||||
tshark, call the tracker, persist rows, or publish updates. AF_PACKET counters count
|
||||
socket frames; TC counters count emitted sampled events. They are not comparable as
|
||||
equal packet totals without accounting for sampling and multiple event types.
|
||||
|
||||
## Selection guidance
|
||||
|
||||
| Need | Mode | Important caveat |
|
||||
| --- | --- | --- |
|
||||
| Full raw visibility for a single interface | AF_PACKET | No definitive kernel egress/drop verdict. |
|
||||
| Full raw frames across bridge ports | Bridge AF_PACKET | High userspace work; bridge forwarding is inferred. |
|
||||
| Ingress/egress/drop evidence on a controlled bridge | TC/eBPF | Requires BPF/TC privileges and resets clsact. |
|
||||
| Reduced overhead / sampled observability | TC/eBPF sampling | Data is intentionally incomplete. |
|
||||
| Hook-overhead measurement | Benchmark mode | Counts differ between AF_PACKET and TC. |
|
||||
|
||||
Before TC/eBPF capture, inspect `tc qdisc` and filters for every target port,
|
||||
coordinate skb-mark ownership, verify BCC/kernel support, and plan recovery of the
|
||||
TC configuration. For every mode, monitor sniffer debug counters, system logs,
|
||||
capture/process health, DB persistence failures, and expected traffic rate before
|
||||
making operational or security conclusions.
|
||||
70
documentation/backend/source-reference.md
Normal file
@@ -0,0 +1,70 @@
|
||||
# Source reference
|
||||
|
||||
This index covers every Python module under `backend/src`, including helper and
|
||||
unmounted-router code. Function names prefixed with `_` are private implementation
|
||||
details; they are described by their owning module's responsibility rather than as
|
||||
separate public contracts.
|
||||
|
||||
## Application and configuration
|
||||
|
||||
| Module | Public surface and role |
|
||||
| --- | --- |
|
||||
| `main.py` | Creates FastAPI, enables permissive CORS, registers startup/shutdown handlers, provides `/hello` and `/versions`, includes live routers, and registers script lifecycle hooks. |
|
||||
| `config.py` | Parses environment strings/integers/floats/booleans; immutable `BackendSettings`; `load_settings`; module-global `settings`. See [configuration](configuration.md). |
|
||||
| `shared_objects.py` | Process-global `db`, `web_loop`, packet broadcaster, and network broadcaster references initialized by `main`. |
|
||||
|
||||
## Models
|
||||
|
||||
| Module | Public surface and role |
|
||||
| --- | --- |
|
||||
| `Models/packets.py` | `PacketObservationModel` and `PacketDBModel`, the normalized persisted/API packet schemas. |
|
||||
| `Models/ip_protocol.py` | `IPProtocolEnum` and `protocol_from_number`, translating IANA protocol numbers to labels. |
|
||||
| `Models/etherType.py` | `EtherTypeEnum` and `ethertype_from_int`, translating Ethernet type values to labels. |
|
||||
| `Models/netplan.py` | `Nameservers`, `EthernetConfig`, `BridgeConfig`, and `NetworkConfig` Pydantic schemas for Netplan-shaped network data. |
|
||||
|
||||
## API routers
|
||||
|
||||
| Module | Public surface and role |
|
||||
| --- | --- |
|
||||
| `api/network_api.py` | Network inspection, bridge create/remove, default reset, link-state watcher control, and network-state WebSocket. Holds shared `IPRoute`/`NDB`; converts netlink messages to Pydantic interface/route/bridge models; publishes state after mutations. |
|
||||
| `api/sniffer_api.py` | Pydantic start/stop/status models and endpoints. Validates one capture target and calls the capture-session API. |
|
||||
| `api/packet_api.py` | Latest packet retrieval, packet-history deletion, and packet-update WebSocket. Serialization handles database records and Pydantic values safely for JSON. |
|
||||
| `api/analysis_api.py` | Pydantic evidence/response models for attachment, protocols, paths, conversations, flow detail, hosts, discovery and anomaly views; delegates each endpoint to `DatabasePool`. |
|
||||
| `api/nft_manager.py` | **Mounted.** `NftManager` wrapper, normalized ruleset models and functions to list rules, delete by handle, and run textual nft. It parses JSON and textual output to enrich rule data. |
|
||||
| `api/packet_scripting_api.py` | **Mounted with doubled prefix.** Name/path validation, example deployment, systemd unit management, venv/pip operations, script status models, and upload/download/enable/disable/delete endpoints. |
|
||||
| `api/nft_api.py` | **Not mounted.** Bridge nftables typed expression model, command generator, handle mapping, and CRUD/preview endpoint functions. `RuleModel.only_bridge` rejects other families. |
|
||||
| `api/nftables_api.py` | **Not mounted.** Generic typed match/action models, resilient binding/CLI wrapper selection, rule reconstruction, and list/replace endpoint functions. |
|
||||
|
||||
## Capture, telemetry, and broadcasting utilities
|
||||
|
||||
| Module | Public surface and role |
|
||||
| --- | --- |
|
||||
| `network_sniffer.py` | Defines flexible `PacketInfo`; parses packet objects/bytes; opens/closes AF_PACKET sockets; owns session reader loops; coordinates telemetry; exposes `start_capture_session`, `stop_capture_session`, status and debug accessors. Legacy `*_afpacket_sniffer` functions delegate to current session functions. |
|
||||
| `utilities/packet_tracker.py` | `PacketTracker` observes capture or telemetry events, aggregates observations, schedules persistence, stops/discards state, and exposes diagnostics. The module-global tracker is the correlation entrypoint. |
|
||||
| `utilities/packet_identity.py` | Builds deterministic fallback packet UID and the minimum fields used to calculate it. |
|
||||
| `utilities/packet_mark.py` | Decodes numeric skb marks into a normalized mark, packet ID, and verdict hint according to the shared mark layout. |
|
||||
| `utilities/tshark_manager.py` | `TsharkManager` owns optional worker processes and caches. Parsing helpers safely coerce nested tshark JSON, extract protocol/HTTP/TLS/DNS/TCP data, derive stream context, and merge enrichment. Module-global `tshark_manager` is used by capture. |
|
||||
| `utilities/bridge_telemetry.py` | `BridgeTelemetryManager` starts/reconciles/stops the eBPF helper and reports subprocess/queue state. Module-global manager is invoked by sniffer lifecycle. |
|
||||
| `utilities/ebpf_bridge_events.py` | Standalone helper program: ctypes event format, BPF-source construction, tc attach/cleanup, perf callbacks, JSON output, signal handling, and `main`. |
|
||||
| `utilities/packet_broadcaster.py` | `PacketBroadcaster` manages subscriber queues. `subscribe`/`unsubscribe`, async `publish`, cross-thread `sync_publish`, and async `close` provide the WebSocket transport primitive. |
|
||||
|
||||
## Network and persistence utilities
|
||||
|
||||
| Module | Public surface and role |
|
||||
| --- | --- |
|
||||
| `utilities/interface_bridge_helpers.py` | Interface existence/up tests; sysfs readers for operational/carrier/admin/MTU state; Ethernet profile retrieval/cache; bridge-port discovery. |
|
||||
| `utilities/bridge_link_state_manager.py` | `EthernetProfile` and `MemberLinkState` data objects; `BridgeLinkStateWatcher` start/stop/status; `BridgeLinkStateManager` enable/disable/query/stop. It embodies debounce, failure, recovery, and profile propagation logic. |
|
||||
| `utilities/database.py` | `DatabasePool` initialization/closure, upsert/batch-upsert, enrichment backfills, latest-packet query, all analysis SQL, and history clearing. Internal helpers normalize values, derive protocol/flow/analysis fields, serialize outgoing rows, and classify discovery activity. |
|
||||
|
||||
## Extension points and maintenance notes
|
||||
|
||||
- New API functionality should live in an `APIRouter`, use Pydantic request and
|
||||
response models, and be explicitly included from `main.py`; otherwise it is not
|
||||
live.
|
||||
- New capture fields must be updated consistently in packet parsing, tracker merge,
|
||||
database upsert SQL, `PacketDBModel`, broadcaster serialization, and analysis
|
||||
queries where relevant.
|
||||
- Any new Linux side effect belongs in [host integration](host-integration.md),
|
||||
including required binary/capability, rollback behavior, and its API exposure.
|
||||
- If an unmounted nft router is adopted, document the migration and remove or
|
||||
version conflicting endpoints instead of silently mounting another implementation.
|
||||
@@ -1,19 +1,48 @@
|
||||
\chapter*{List of Acronyms}
|
||||
\addcontentsline{toc}{chapter}{List of Acronyms}
|
||||
|
||||
\begin{acronym}[HTTPS] % Give the longest label here so that the list is nicely aligned
|
||||
\begin{acronym}[NFQUEUE] % Give the longest label here so that the list is nicely aligned
|
||||
\acro{API}{Application Programming Interface}
|
||||
\acro{ARP}{Address Resolution Protocol}
|
||||
\acro{BPF}{Berkeley Packet Filter}
|
||||
\acro{BPDU}{Bridge Protocol Data Unit}
|
||||
\acro{CA}{Certificate Authority}
|
||||
\acro{CPU}{Central Processing Unit}
|
||||
\acro{DMA}{Direct Memory Access}
|
||||
\acro{eBPF}{extended Berkeley Packet Filter}
|
||||
\acro{FDB}{Forwarding Database}
|
||||
\acro{FIB}{Forwarding Information Base}
|
||||
\acro{HTML}{HyperText Markup Language}
|
||||
\acro{HTTPS}{Hypertext Transfer Protocol Secure}
|
||||
\acro{HTTP}{Hypertext Transfer Protocol}
|
||||
\acro{IEEE}{Institute of Electrical and Electronics Engineers}
|
||||
\acro{IP}{Internet Protocol}
|
||||
\acro{IPv4}{Internet Protocol version 4}
|
||||
\acro{IPv6}{Internet Protocol version 6}
|
||||
\acro{LAN}{Local Area Network}
|
||||
\acro{LSM}{Linux Security Module}
|
||||
\acro{MAC}{Media Access Control}
|
||||
\acro{MITM}{Man-in-the-Middle}
|
||||
\acro{MTU}{Maximum Transmission Unit}
|
||||
\acro{NAPI}{New API}
|
||||
\acro{NAT}{Network Address Translation}
|
||||
\acro{NFQUEUE}{Netfilter Queue}
|
||||
\acro{NIC}{Network Interface Card}
|
||||
\acro{OSI}{Open Systems Interconnection}
|
||||
\acro{PVID}{Port VLAN Identifier}
|
||||
\acro{RSTP}{Rapid Spanning Tree Protocol}
|
||||
\acro{RSS}{Receive Side Scaling}
|
||||
\acro{SPAN}{Switched Port Analyzer}
|
||||
\acro{SSID}{Service Set Identifier}
|
||||
\acro{SSL}{Secure Sockets Layer}
|
||||
\acro{STP}{Spanning Tree Protocol}
|
||||
\acro{TAP}{Test Access Point}
|
||||
\acro{TCP}{Transmission Control Protocol}
|
||||
\acro{TLS}{Transport Layer Security}
|
||||
\acro{TTL}{Time To Live}
|
||||
\acro{UDP}{User Datagram Protocol}
|
||||
\acro{URI}{Uniform Resource Identifier}
|
||||
\acro{URL}{Uniform Resource Locator}
|
||||
\acro{VLAN}{Virtual Local Area Network}
|
||||
\acro{XDP}{eXpress Data Path}
|
||||
\end{acronym}
|
||||
|
||||
@@ -3,43 +3,304 @@
|
||||
|
||||
In this chapter, the necessary background and foundational concepts underlying the research presented in this thesis are introduced. First, the theoretical frameworks and methodologies guiding the approach are discussed, followed by an overview of the key technologies and tools used in this work. The chapter is intended to establish a common understanding and provide context for the subsequent chapters, in which the specific contributions and findings of the research are presented.
|
||||
|
||||
\section{\ac{OSI} Model}
|
||||
\section[OSI Model]{\ac{OSI} Model}
|
||||
\label{sec:osi}
|
||||
|
||||
The \ac{OSI} Basic Reference Model, defined in X.200, provides a conceptual framework for understanding and standardizing communication between open systems. Its central purpose is to describe network communication in a structured and interoperable way by dividing the communication process into seven layers, each with a distinct function and relationship to the adjacent layers. This layered approach makes it possible to separate communication tasks into manageable parts, thereby supporting the design, specification, and implementation of interoperable systems.
|
||||
The \ac{OSI} Basic Reference Model provides a conceptual framework for describing communication between open systems in a structured and interoperable way. Instead of treating network communication as a single process, it divides it into seven layers with clearly separated responsibilities. This layered view simplifies the analysis of communication systems and provides a common terminology for discussing protocols and interfaces.
|
||||
|
||||
The \ac{OSI} model is not a concrete protocol suite but a reference architecture. In other words, it does not prescribe a specific technology for network communication; instead, it establishes a common conceptual model that can be used to describe how communication functions should be organized. The seven-layer structure is one of its most important features, because it defines a hierarchy of services and interfaces that together form a complete communication system. Each layer performs a defined set of functions and provides services to the layer above while relying on the services of the layer below.
|
||||
The \ac{OSI} model is not itself a concrete protocol suite, but rather a reference architecture. It does not prescribe which technologies must be used in practice. Instead, it provides a general structure that can be used to classify communication functions and to explain how different protocols relate to one another. Each layer offers services to the layer above while relying on the services of the layer below.
|
||||
|
||||
\subsection{Physical Layer}
|
||||
|
||||
The Physical Layer is the lowest layer of the \ac{OSI} model and is concerned with the transmission of raw bit streams over a physical medium. It defines the electrical, mechanical, procedural, and functional characteristics of the physical connection. In practical terms, this layer deals with how bits are represented as signals and how they are transmitted across cables, optical fibers, or wireless links. It therefore forms the foundation of all higher-level communication, since no data can be exchanged without a functioning physical transmission path.
|
||||
The Physical Layer is concerned with the transmission of raw bit streams over the physical medium. It defines how signals are represented and transferred, for example over cables, optical fibers, or wireless links. It therefore forms the foundation of all higher-level communication.
|
||||
|
||||
\subsection{Data Link Layer}
|
||||
|
||||
The Data Link Layer provides reliable transfer of data over a direct physical connection between two adjacent nodes. Its role is to organize raw bits from the Physical Layer into structured units and to support local communication across a single link. This layer is also responsible for controlling access to the transmission medium and for detecting and correcting errors that may occur during local transmission. By doing so, it helps ensure that data can be transferred efficiently and with a defined degree of reliability between neighboring systems.
|
||||
The Data Link Layer organizes the raw bits received from the Physical Layer into structured units and supports communication between adjacent nodes on the same link. It is responsible for local addressing, medium access control, and error detection on the local transmission path.
|
||||
|
||||
\subsection{Network Layer}
|
||||
|
||||
The Network Layer extends communication beyond a single local link by providing routing and path selection across multiple interconnected networks. It is responsible for addressing and delivering data from a source to a destination that may be separated by several intermediate systems. This layer therefore introduces the concept of logical network-wide communication, which is essential for interconnection across larger infrastructures. In the \ac{OSI} architecture, the Network Layer plays a central role in enabling internetwork communication by determining how information should travel through the network.
|
||||
The Network Layer enables communication beyond a single local link. It provides logical addressing and routing functions that allow data to be forwarded across interconnected networks from a source to a destination.
|
||||
|
||||
\subsection{Transport Layer}
|
||||
|
||||
The Transport Layer provides end-to-end communication services between application entities in different systems. Its purpose is to support the transfer of data across the complete communication path, independent of the underlying network structure. This layer may provide functions such as segmentation, reassembly, flow control, and error recovery, depending on the service required. It ensures that data can be delivered between hosts in a way that is suitable for the needs of the communicating applications.
|
||||
The Transport Layer provides end-to-end communication services between application entities in different systems. Depending on the protocol and service model, this can include segmentation, reassembly, flow control, and error recovery.
|
||||
|
||||
\subsection{Session Layer}
|
||||
|
||||
The Session Layer is responsible for managing communication sessions between application processes. It establishes, maintains, and terminates sessions, allowing two systems to organize their dialogue in a coordinated manner. This includes controlling the interaction between applications and supporting synchronization during communication. The session concept is important because many communication tasks require a structured exchange rather than isolated data transfers.
|
||||
The Session Layer is responsible for establishing, managing, and terminating communication sessions between applications. It structures the dialogue between communicating systems and can support synchronization during longer exchanges.
|
||||
|
||||
\subsection{Presentation Layer}
|
||||
|
||||
The Presentation Layer provides services related to the representation of data. Its function is to ensure that information sent by one system can be interpreted correctly by another system, even when the two systems use different internal data formats. This layer may therefore handle data translation, formatting, and representation issues. By separating presentation concerns from application logic, the \ac{OSI} model allows the communication process to remain flexible and independent of specific machine representations.
|
||||
The Presentation Layer deals with the representation of data. It ensures that information exchanged between systems can be interpreted correctly even when internal data formats differ. Typical functions include formatting, translation, and related representation issues.
|
||||
|
||||
\subsection{Application Layer}
|
||||
|
||||
The Application Layer is the highest layer of the \ac{OSI} model and provides services directly to user-oriented application processes. It represents the point at which network communication becomes visible to the software used by the end user. This layer supports communication functions that are needed by applications and forms the interface between the communication system and the application domain. In the \ac{OSI} framework, it completes the layered communication path by enabling services that are directly relevant to user interaction.
|
||||
The Application Layer is the highest layer of the model and contains the communication functions used directly by application processes. It forms the interface between the communication system and the software that uses network services.
|
||||
|
||||
\subsection{Layered Structure and Function}
|
||||
|
||||
A key principle of the \ac{OSI} Basic Reference Model is that each layer has a specific scope of responsibility and interacts primarily with the layers immediately above and below it. This design reduces complexity by distributing communication tasks across separate functional levels. It also promotes standardization, because each layer can be specified and analyzed independently within the overall architecture. As a result, the model provides a clear conceptual basis for understanding how communication systems are structured and how interoperability can be achieved.
|
||||
A key principle of the \ac{OSI} model is that each layer has a defined scope of responsibility and interacts mainly with the layers directly above and below it. This reduces complexity and supports standardization by allowing communication functions to be discussed separately while still being part of one overall architecture.
|
||||
|
||||
The significance of the \ac{OSI} model lies in its ability to describe communication in a modular and systematic way. Rather than treating network communication as a single undivided process, the model breaks it into coordinated functions that are easier to define, implement, and study. This makes the \ac{OSI} Basic Reference Model particularly valuable in technical writing, education, and system analysis. Even where modern protocols do not follow the model exactly, the \ac{OSI} structure remains an important reference for explaining communication principles.
|
||||
For the present thesis, the \ac{OSI} model is mainly used as a conceptual orientation for the discussion of communication layers and network functions. Even though the implemented system is better described using the practical \ac{TCP}/\ac{IP} stack, the \ac{OSI} structure remains useful for introducing the general principles of layered communication.
|
||||
|
||||
\section{Transparent Network Interception Models}
|
||||
\label{sec:transparent-network-interception-models}
|
||||
|
||||
\subsection{Man-in-the-Middle Terminology}
|
||||
|
||||
The term \ac{MITM} describes a communication setting in which an intermediate system is positioned between two endpoints and can observe, relay, insert, or modify messages exchanged between them \cite{conti2016mitmsurvey}. In security literature, this position is often discussed as an adversarial capability \cite{conti2016mitmsurvey}. In the present thesis, the term is used in a controlled experimental sense: the system is intentionally placed in the communication path in order to observe, correlate, and selectively manipulate traffic. The relevant distinction is therefore not only whether traffic can be observed, but also at which layer the intermediate system is inserted and whether it becomes visible to the endpoints.
|
||||
|
||||
\subsection[Passive Capture with TAP and SPAN]{Passive Capture with \ac{TAP} and \ac{SPAN}}
|
||||
|
||||
Passive monitoring systems obtain a copy of network traffic without becoming the forwarding element. A \ac{TAP} is a dedicated device inserted directly into the monitored physical link, for example between a host and a switch or between two switches. It copies the traffic that crosses this link to one or more monitoring interfaces while the original traffic continues between the connected endpoints. In contrast, \ac{SPAN}, also known as port mirroring, is configured on a switch. The monitored devices remain connected to their normal switch ports, and the switch duplicates selected ingress, egress, or bidirectional traffic from these ports to a separate monitoring port. The main difference is therefore where the traffic copy is produced. A \ac{TAP} observes the link directly at its physical position in the path, whereas \ac{SPAN} observes traffic indirectly from inside the switch forwarding and mirroring implementation. Neither mechanism gives the monitoring device direct control over the original forwarding decision, so passive capture cannot directly block or modify packets in the original stream. Zhang and Moore show that \ac{SPAN}-based monitoring can also introduce measurement artifacts, including inter-packet timings, packet reordering, and packet loss \cite{zhang2007portmirroring}.
|
||||
|
||||
\subsection{Layer-3 Routed Interception}
|
||||
|
||||
In a routed interception model, the intermediate system is part of the \ac{IP} forwarding path. An \ac{IP} router receives a packet, determines the next hop based on the destination \ac{IP} address and routing information, and transmits the packet through the selected outgoing interface \cite{rfc1812}. From the perspective of the endpoints, a routed intermediary therefore behaves as a router or gateway rather than as an Ethernet switch. Traffic must either be configured to use this system as its next hop, for example through a default gateway setting, or the surrounding network must otherwise be changed so that packets are routed through it.
|
||||
|
||||
This placement has visible protocol effects. In \ac{IPv4}, every router that forwards a packet decrements the \ac{TTL} field \cite{rfc1812}. Therefore, a routed intermediary can appear as an additional \ac{IP} hop to tools and diagnostics that inspect hop-count behavior.
|
||||
|
||||
A routed intermediary may also modify packet headers. If \ac{NAT} is used, address information is rewritten as packets traverse the translator \cite{rfc3022}. Depending on the configuration, this can affect source or destination \ac{IP} addresses, transport-layer ports, and the reverse mapping needed for return traffic \cite{rfc3022}. Even without \ac{NAT}, routed forwarding changes the Layer-2 next hop because the packet is emitted through the outgoing link selected by the routing decision \cite{rfc1812}. Consequently, the intermediary is not merely observing an existing Ethernet segment; it actively participates in \ac{IP} forwarding. This makes routed interception useful when the intermediate system is intended to enforce Layer-3 policy, apply firewalling, perform \ac{NAT}, or deliberately act as a gateway.
|
||||
|
||||
\subsection{Proxy-Based Interception}
|
||||
|
||||
Proxy-based interception moves the intermediary even higher in the stack. An \ac{HTTP} proxy terminates or relays application-layer requests rather than merely forwarding Ethernet frames. For \ac{HTTPS}, interception typically requires a \ac{TLS} proxy that presents itself as the server to the client and as the client to the external server, thereby creating two separate \ac{TLS} connections \cite{waked2018tlsinterception}. This model can expose plaintext to the proxy when the client trusts a signing \ac{CA} controlled by the proxy \cite{waked2018tlsinterception}. At the same time, it changes the end-to-end security model of \ac{TLS} \cite{decarnedecarnavalet2023tlsinterception}. Empirical studies show that \ac{HTTPS} interception can be detected through inconsistencies between \ac{HTTP} \texttt{User-Agent} information and \ac{TLS} client behavior \cite{durumeric2017httpsinterception}, and that interception appliances may introduce certificate-validation and parameter-mapping weaknesses \cite{waked2018tlsinterception}. Proxy-based interception is therefore powerful for application-layer inspection, but it is not transparent in the same sense as Layer-2 forwarding.
|
||||
|
||||
\subsection{Transparent Layer-2 Inline Bridges}
|
||||
|
||||
A transparent inline bridge occupies the forwarding path without acting as an \ac{IP} router or application proxy. Such a bridge connects network segments at the data link layer and forwards frames based on bridge state and destination \ac{MAC} addresses \cite{ieee8021q2022}. The Linux bridge implements this behavior by learning source \ac{MAC} addresses, maintaining an \ac{FDB}, and forwarding, filtering, flooding, or locally delivering frames according to the bridge configuration \cite{linuxkernelbridgedocs}. In this model, the bridge does not have to be configured as the endpoints' \ac{IP} gateway or as an application proxy, because forwarding is performed below the \ac{IP} layer.
|
||||
|
||||
\subsection{Transparency and Detectability}
|
||||
|
||||
Transparency should not be understood as complete undetectability. An inline bridge can affect latency, packet ordering, loss behavior, link-state propagation, and bridge-control behavior. If \ac{STP} is enabled, \acp{BPDU} and forwarding-delay behavior may become externally visible \cite{linuxkernelbridgedocs}. If \ac{TLS} proxying is added on top of forwarding, certificate and handshake artifacts can reveal the interception point \cite{durumeric2017httpsinterception}. The transparency goal in this thesis is therefore narrower and technical: the system should forward traffic as a Layer-2 inline bridge without introducing an additional \ac{IP} hop, without requiring endpoint proxy configuration, and without terminating application-layer sessions unless a later manipulation component explicitly does so.
|
||||
|
||||
\section{Linux Packet Filtering with \texttt{nftables}}
|
||||
\label{sec:nftables}
|
||||
|
||||
% cites noch ergänzen: nftables_manpage und nf queue noch
|
||||
|
||||
\texttt{nftables} is a framework for packet filtering and classification in Linux.
|
||||
The \texttt{nft} command-line tool is used to set up, maintain, and inspect packet-filtering and classification rules in the Linux kernel.
|
||||
The corresponding Linux kernel subsystem is called \texttt{nf\_tables} and is part of Netfilter.
|
||||
|
||||
An \texttt{nftables} ruleset is organized using several types of objects.
|
||||
In particular, \textbf{tables} are containers for chains, sets, and stateful objects, while \textbf{chains} are containers for rules.
|
||||
Tables are identified by an address family and a name.
|
||||
The supported table families are \texttt{ip}, \texttt{ip6}, \texttt{inet}, \texttt{arp}, \texttt{bridge}, and \texttt{netdev}.
|
||||
If no family is specified, the \texttt{ip} family is used by default.
|
||||
|
||||
|
||||
\subsection{Address Families and Hooks}
|
||||
\label{sec:nftables-address-families}
|
||||
|
||||
Address families determine the type of packets that \texttt{nftables} processes.
|
||||
For each address family, the kernel provides hooks at particular stages of the packet-processing path.
|
||||
These hooks invoke \texttt{nftables} when rules for the respective hooks exist.
|
||||
The \texttt{ip} family processes IPv4 packets, \texttt{ip6} processes IPv6 packets, and \texttt{inet} provides a combined IPv4/IPv6 family.
|
||||
The \texttt{arp} family handles IPv4 ARP packets, the \texttt{bridge} family handles packets traversing a bridge device, and the \texttt{netdev} family handles packets on the ingress and egress paths.
|
||||
\texttt{nftables} objects exist in address-family-specific namespaces.
|
||||
|
||||
For the IPv4, IPv6, and \texttt{inet} address families, \texttt{nftables} defines hooks at different stages of packet processing.
|
||||
The \texttt{prerouting} hook processes packets entering the system before the routing process.
|
||||
Packets delivered to the local system are processed by the \texttt{input} hook, while packets forwarded to another host are processed by the \texttt{forward} hook.
|
||||
Packets generated by local processes pass through the \texttt{output} hook, and packets leaving the system pass through the \texttt{postrouting} hook.
|
||||
The \texttt{inet} family additionally supports an \texttt{ingress} hook, which is invoked before the Layer-3 protocol handlers and therefore before \texttt{prerouting}.
|
||||
|
||||
The \texttt{bridge} address family handles Ethernet packets traversing bridge devices.
|
||||
According to the \texttt{nftables} documentation, its list of supported hooks is identical to that of the IPv4, IPv6, and \texttt{inet} families described above.
|
||||
|
||||
|
||||
\subsection{Tables, Chains, and Rules}
|
||||
\label{sec:nftables-tables-chains-rules}
|
||||
|
||||
Chains exist in two forms: base chains and regular chains.
|
||||
A base chain is an entry point for packets from the networking stack.
|
||||
A regular chain can be used as a jump target and for organizing rules.
|
||||
When a chain is created with a hook and priority, it becomes a base chain and is connected to the networking stack.
|
||||
For base chains, the chain type, hook, and priority parameters are mandatory.
|
||||
|
||||
The \texttt{filter} chain type is supported by all families and hooks.
|
||||
Other chain types have additional restrictions.
|
||||
For example, \texttt{nat} chains are supported by the \texttt{ip}, \texttt{ip6}, and \texttt{inet} families, while \texttt{route} chains are restricted to the \texttt{output} hook of those families.
|
||||
|
||||
A base chain has a priority that determines its evaluation order relative to other chains attached to the same hook.
|
||||
Lower numerical priority values are evaluated before higher values.
|
||||
The evaluation order of chains with identical priorities is undefined.
|
||||
\texttt{nftables} provides names for several standard priority values, and the priority values used by the \texttt{bridge} family differ from those used by the other families.
|
||||
|
||||
For the \texttt{bridge} family, the predefined priorities include \texttt{dstnat} with a value of $-300$ for \texttt{prerouting}, \texttt{filter} with a value of $-200$ for all hooks, \texttt{out} with a value of $100$ for \texttt{output}, and \texttt{srcnat} with a value of $300$ for \texttt{postrouting}.
|
||||
|
||||
A base chain can also specify a policy.
|
||||
The supported policies are \texttt{accept} and \texttt{drop}, with \texttt{accept} being the default.
|
||||
The policy determines what happens to packets for which the rules in the chain do not explicitly produce an acceptance or refusal.
|
||||
|
||||
Rules are contained within chains.
|
||||
According to the \texttt{nftables} documentation, rules consist of two types of components: expressions and statements.
|
||||
|
||||
|
||||
\subsection{Expressions and Statements}
|
||||
\label{sec:nftables-expressions-statements}
|
||||
|
||||
Expressions represent values.
|
||||
These values may be constants, such as network addresses and port numbers, or information obtained from a packet during ruleset evaluation.
|
||||
Expressions can be combined to construct match expressions and can also be used as arguments for operations such as NAT or packet marking.
|
||||
Each expression has a data type that determines properties including its size, parsing, representation, and compatibility with other expressions.
|
||||
|
||||
\texttt{nftables} provides, among others, meta expressions and payload expressions.
|
||||
A meta expression accesses metadata associated with a packet.
|
||||
Available metadata includes the packet length, protocol family, Layer-4 protocol, packet mark, input and output interfaces, and packet type.
|
||||
|
||||
The input and output interfaces can be accessed using \texttt{iif}, \texttt{oif}, \texttt{iifname}, and \texttt{oifname}.
|
||||
\texttt{iif} and \texttt{oif} operate on interface indices, whereas \texttt{iifname} and \texttt{oifname} operate on interface names.
|
||||
\texttt{nftables} also provides \texttt{ibrname} and \texttt{obrname}, representing the input and output bridge interface names, respectively.
|
||||
|
||||
Payload expressions refer to information contained in a packet's payload.
|
||||
For Ethernet headers, \texttt{nftables} provides expressions for the destination address (\texttt{ether daddr}), source address (\texttt{ether saddr}), and EtherType (\texttt{ether type}).
|
||||
|
||||
Further payload expressions provide access to fields of higher-layer protocols.
|
||||
For example, IPv4 expressions can access fields including source and destination addresses and the upper-layer protocol, while IPv6 expressions provide access to fields including source and destination addresses and the next-header field.
|
||||
TCP and UDP expressions provide access to source and destination ports as well as additional protocol-specific header fields.
|
||||
|
||||
Statements represent actions that are performed during rule evaluation.
|
||||
They may alter the control flow by accepting or dropping a packet or by transferring evaluation to another chain.
|
||||
Statements may also perform other actions, including logging and rejecting packets.
|
||||
nftables distinguishes between terminal and non-terminal statements.
|
||||
Terminal statements unconditionally terminate evaluation of the current rule, whereas non-terminal statements either conditionally terminate evaluation or allow it to continue.
|
||||
|
||||
|
||||
\subsection{Ruleset Evaluation and Verdicts}
|
||||
\label{sec:nftables-ruleset-evaluation}
|
||||
|
||||
Packets traverse the networking stack and are evaluated by base chains attached to the hooks they encounter.
|
||||
If multiple base chains are attached to the same hook, the chains are evaluated according to their priorities, with lower priority values evaluated first.
|
||||
Base chains may call regular chains using \texttt{jump} and \texttt{goto}, and regular chains may in turn call other regular chains.
|
||||
Chains in different tables cannot call each other.
|
||||
|
||||
nftables provides the verdict statements \texttt{accept}, \texttt{drop}, \texttt{continue}, \texttt{return}, \texttt{jump}, and \texttt{goto}.
|
||||
The \texttt{accept} and \texttt{drop} verdicts terminate chain evaluation, but their effects on subsequent processing differ.
|
||||
|
||||
An \texttt{accept} verdict terminates evaluation of the current base chain.
|
||||
Processing can subsequently continue in another base chain attached to the same hook or in a base chain attached to a later hook.
|
||||
Consequently, a packet that receives an \texttt{accept} verdict may still subsequently receive a \texttt{drop} verdict from another base chain.
|
||||
|
||||
A \texttt{drop} verdict immediately drops the packet and terminates evaluation of the ruleset.
|
||||
No further chains are evaluated, and the verdict cannot be overridden by a later \texttt{accept} verdict.
|
||||
|
||||
The \texttt{jump} statement stores the current evaluation position and continues evaluation at the beginning of another regular chain.
|
||||
When that chain ends, evaluation can return to the stored position.
|
||||
\texttt{goto} similarly transfers evaluation to another chain but does not store the current position.
|
||||
\texttt{return} terminates evaluation of the current chain and, where a stored position exists, continues evaluation from that position.
|
||||
|
||||
|
||||
\subsection{Queueing Packets to Userspace}
|
||||
\label{sec:nftables-queue}
|
||||
|
||||
In addition to issuing verdicts directly in the ruleset, nftables provides a \texttt{queue} statement.
|
||||
The \texttt{queue} statement passes a packet to userspace using the \texttt{nfnetlink\_queue} handler.
|
||||
The packet is placed into a queue identified by a 16-bit queue number.
|
||||
The default queue number is 0.
|
||||
|
||||
A userspace application receiving a queued packet can inspect it and may optionally modify it.
|
||||
The userspace application must subsequently provide either an \texttt{accept} or a \texttt{drop} verdict.
|
||||
If the packet is accepted, nftables processing resumes with the next base-chain hook rather than with the rule following the \texttt{queue} statement.
|
||||
The nftables documentation refers to the \texttt{libnetfilter\_queue} documentation for further details concerning userspace queue processing.
|
||||
|
||||
The \texttt{queue} statement can specify a single queue number, a range of queue numbers, or an expression that determines the queue number.
|
||||
Queue numbers may be computed at runtime using \texttt{numgen}, \texttt{hash}, or \texttt{symhash} expressions, and a map statement can be used to select fixed queue numbers based on inputs such as source IP addresses or interface names.
|
||||
|
||||
Two flags are defined for the \texttt{queue} statement: \texttt{bypass} and \texttt{fanout}.
|
||||
The \texttt{fanout} flag distributes packets between several queues.
|
||||
The \texttt{bypass} flag allows packets to proceed when the userspace application cannot process them; the documentation recommends consulting the \texttt{libnetfilter\_queue} documentation for performance-tuning recommendations before using this flag.
|
||||
```
|
||||
consulting the \texttt{libnetfilter\_queue} documentation for performance-tuning recommendations before using this flag.
|
||||
|
||||
|
||||
\section{Linux Packet Processing Path}
|
||||
\label{sec:linux-packet-processing-path}
|
||||
|
||||
The following section explains how network packets are processed by the Linux kernel. First, the internal packet representation is described. Next, the receive path from the \ac{NIC} into the kernel is outlined. Then, the local delivery, forwarding, and bridge paths are distinguished. Lastly, the relevant programmable hook points are explained because they define where a transparent traffic capture and manipulation platform can observe, mark, forward, or drop packets.
|
||||
|
||||
Linux networking is not a single processing step. Instead, packets move through device drivers, protocol implementations, routing or bridge logic, filtering hooks, queueing disciplines, and user space socket interfaces \cite{linuxkernelnetworkingdocs}. The exact path depends on whether a packet is locally generated, locally delivered, routed, or bridged \cite{stephan2024packetpath}. This distinction is important for the present thesis because a transparent \ac{MITM} system should normally forward frames at Layer 2, while still observing and manipulating packets at selected kernel hook points.
|
||||
|
||||
\subsection{Packet Representation}
|
||||
|
||||
On an Ethernet-based system, the bytes on the wire are structured as a frame. The Ethernet header contains source and destination \ac{MAC} addresses and an \texttt{EtherType} field. Depending on the \texttt{EtherType}, the frame may contain an \ac{ARP} message, an \ac{IPv4} packet, an \ac{IPv6} packet, or another payload. For \ac{IP} traffic, the network-layer header is followed by a transport-layer header such as \ac{TCP} or \ac{UDP}. The remaining bytes form the payload delivered to the application or forwarded to another interface.
|
||||
|
||||
Inside the Linux kernel, packets are mainly represented by \texttt{struct sk\_buff} \cite{linuxkernelskbuffdocs}. This structure does not contain the packet bytes directly. Instead, it stores metadata and pointers to one or more buffers that contain the actual headers and payload \cite{linuxkernelskbuffdocs}. The \texttt{head}, \texttt{data}, \texttt{tail}, and \texttt{end} pointers describe the usable packet buffer, while header offsets such as \texttt{mac\_header}, \texttt{network\_header}, and \texttt{transport\_header} indicate where individual protocol headers begin \cite{linuxkernelskbuffdocs}. As a result, protocol layers can prepend or remove headers by adjusting pointers instead of copying the complete packet \cite{stephan2024packetpath}.
|
||||
|
||||
The \texttt{sk\_buff} also carries processing metadata such as the receiving or transmitting network device, the packet length, protocol information, checksum state, priority values, and marks \cite{linuxkernelskbuffdocs}. Such metadata is not visible on the wire, but it can influence routing, filtering, queueing, and later processing stages. This property is useful for packet correlation because a mark stored in \texttt{skb->mark} can follow a packet through multiple kernel stages without changing the actual Ethernet frame.
|
||||
|
||||
Furthermore, Linux can clone an \texttt{sk\_buff} efficiently. A clone gets its own metadata structure while sharing the packet data buffer until modification becomes necessary. This is relevant for packet capture. Passive observers such as raw packet sockets can receive a clone of the packet while the original packet continues through the normal kernel path. Hence, capturing a packet does not necessarily mean that the packet was consumed by the capture process \cite{linuxkernelskbuffdocs}.
|
||||
|
||||
\subsection{Ingress Path}
|
||||
|
||||
The ingress path begins when the \ac{NIC} receives a frame from the physical medium. Modern \acp{NIC} often use multiple receive queues. With \ac{RSS}, the device can assign packets to queues based on a hash over packet header fields, allowing receive processing to be distributed over multiple \acp{CPU} \cite{linuxkernelscalingdocs}. The received bytes are transferred into main memory using \ac{DMA}, and the driver notifies the kernel that new receive work is available. Drivers commonly process this work through \ac{NAPI}, which combines interrupt notification with polling under load.
|
||||
|
||||
Before the regular networking stack processes the packet, \ac{XDP} may run in supported drivers \cite{hoilandjorgensen2018xdp}. Native \ac{XDP} executes an \ac{eBPF} program very early in the receive path, before the kernel allocates the normal \texttt{sk\_buff} structure \cite{hoilandjorgensen2018xdp}. The program can return a verdict to pass the packet to the kernel stack, drop it, transmit it back out, or redirect it to another target \cite{hoilandjorgensen2018xdp}. This makes \ac{XDP} useful for high-performance packet processing \cite{scholz2018ebpfpacketfiltering}. However, the early position also means that normal \texttt{sk\_buff} metadata is not yet available in native mode.
|
||||
|
||||
If the packet continues into the regular networking stack, the driver creates or completes an \texttt{sk\_buff} and passes it into the generic receive path, commonly through functions such as \texttt{netif\_receive\_skb()} \cite{stephan2024packetpath}. At this stage, Linux has metadata about the receiving interface and can expose the packet to early ingress processing. This includes \texttt{tc} ingress programs and the \texttt{nftables} \texttt{netdev} \texttt{ingress} hook \cite{nftableshooks}. In contrast to native \ac{XDP}, these hooks operate after the \texttt{sk\_buff} exists and can therefore read or write metadata such as \texttt{skb->mark}.
|
||||
|
||||
After early ingress processing, the packet may be cloned for packet sockets, handled by \ac{VLAN} logic, passed to a receive handler associated with a master device, or delivered to a protocol handler \cite{stephan2024packetpath}. The receive handler is particularly relevant for Linux bridges. If the ingress interface is enslaved to a bridge, the bridge receive handler can take ownership of the packet before the packet is delivered to the local \ac{IP} stack \cite{linuxkernelbridgedocs}.
|
||||
|
||||
\subsection{Local Delivery and \ac{IP} Forwarding}
|
||||
|
||||
If the packet is an \ac{IP} packet and is not taken over by a bridge or another master device, the \ac{IP} receive function processes it. For \ac{IPv4}, this path includes \texttt{ip\_rcv()}. The kernel validates essential header fields, checks packet length and checksum information, sets the transport header pointer, and invokes the \texttt{netfilter} \texttt{PRE\_ROUTING} hook. Afterwards, the routing decision determines whether the packet is locally delivered, forwarded to another interface, or handled as multicast traffic \cite{stephan2024packetpath}.
|
||||
|
||||
For local delivery, the packet follows the input path. Fragmented packets may first be reassembled. The packet then reaches the \texttt{netfilter} \texttt{LOCAL\_IN} hook and is passed to the appropriate transport-layer handler. For \ac{TCP}, Linux performs socket lookup, checksum validation, state-machine processing, sequence-number handling, and receive-queue insertion. For \ac{UDP}, the path is shorter and mainly consists of checksum validation, socket lookup, and datagram delivery. Finally, a user-space application reads the data through a system call such as \texttt{recv()} or \texttt{read()} \cite{stephan2024packetpath}.
|
||||
|
||||
For routed forwarding, the packet follows a different path. After the routing decision, \texttt{netfilter} can inspect the packet at the \texttt{FORWARD} hook. If the packet is accepted, Linux applies post-routing processing, performs neighbor resolution if necessary, and sends the packet to the selected output device. The kernel documentation on \texttt{netfilter} \texttt{flowtable} processing describes this classic forwarding path as a sequence of ingress, prerouting, routing decision, forward, postrouting, and neighbor transmission, while also describing how \texttt{flowtable} offload can bypass parts of that path for later packets of a flow \cite{linuxkernelflowtabledocs}.
|
||||
|
||||
\subsection{Ethernet Switching Concepts}
|
||||
|
||||
Ethernet switching is based on forwarding at the data link layer. The \ac{IEEE} \texttt{802.1Q-2022} standard specifies the operation of \ac{MAC} bridges and \ac{VLAN} bridges, which interconnect \acp{LAN} below the \ac{MAC} service boundary \cite{ieee8021q2022}. From the perspective of higher-layer protocols, such a bridge should be transparent: endpoints do not need to know that an intermediate bridge forwards the frame. Consequently, forwarding decisions are based on Ethernet destination addresses and bridge state rather than on \ac{IP} routes.
|
||||
|
||||
A learning bridge builds forwarding state from the source address of received frames. When a frame enters a bridge port, the bridge can associate the source \ac{MAC} address with the ingress port and store this association in the \ac{FDB} \cite{linuxkernelbridgedocs}. In \ac{VLAN}-aware operation, the relevant forwarding identity also includes the \ac{VLAN}; the Linux switch device documentation describes a bridge \ac{FDB} entry as a \texttt{\{port, mac, vlan\}} forwarding destination \cite{linuxkernelswitchdevdocs}. This distinction matters because the same \ac{MAC} address can belong to different Layer-2 domains when \acp{VLAN} are used.
|
||||
|
||||
If the destination address is known, the bridge can forward a unicast frame only to the port associated with that destination. If the destination is located on the same port as the source, the frame can be filtered instead of being sent back to the segment from which it arrived. If no matching destination entry exists, the frame is an unknown unicast and must be flooded to eligible ports in the same forwarding domain. Broadcast frames are also flooded within that domain, and multicast frames are flooded or forwarded according to multicast bridge state \cite{linuxkernelswitchdevdocs}. Thus, a bridge extends a broadcast domain unless \ac{VLAN} filtering or another separation mechanism divides the traffic into distinct Layer-2 domains.
|
||||
|
||||
\ac{VLAN} awareness allows one physical or virtual bridge to represent multiple separated broadcast domains. With \texttt{vlan\_filtering} enabled, forwarding decisions depend on both the destination \ac{MAC} address and the \ac{VLAN} tag \cite{linuxkernelbridgedocs}. The \texttt{ip-link(8)} manual describes the same configuration point as \texttt{vlan\_filtering}; when it is disabled, the bridge does not consider the \ac{VLAN} tag during packet handling \cite{man7iplink}.
|
||||
|
||||
Layer-2 loops are especially problematic because Ethernet frames do not contain a hop limit comparable to the \ac{IP} \ac{TTL} field. In a looped topology, flooded broadcast, multicast, or unknown-unicast frames can therefore circulate and be replicated until the network becomes unusable. \ac{STP} was introduced to let bridges compute a loop-free active topology in an extended \ac{LAN} \cite{perlman1985spanningtree}. \ac{RSTP} later improved reconfiguration behavior and is part of the modern bridge standards lineage described by \texttt{802.1Q} \cite{ieee8021q2022}. In Linux, \ac{STP} controls bridge port states such as blocking, learning, and forwarding, and it uses \acp{BPDU} to exchange topology information \cite{linuxkernelbridgedocs}.
|
||||
|
||||
\subsection{Linux Bridge Forwarding Path}
|
||||
|
||||
A Linux bridge implements the switching behavior described above inside the kernel. The bridge receives Ethernet frames from enslaved interfaces, learns source addresses, consults the \ac{FDB}, and either forwards, filters, floods, or locally delivers frames depending on the destination address and bridge configuration \cite{linuxkernelbridgedocs}. The \texttt{bridge} command exposes this state through objects such as \texttt{fdb}, \texttt{vlan}, and \texttt{link} \cite{man7bridge}.
|
||||
|
||||
This Layer-2 behavior is central for transparent interception. When two hosts communicate through a Linux bridge, their packets do not need to be routed by the bridge. Therefore, no additional \ac{IP} hop is introduced and the \ac{TTL} or hop-limit value is not decremented by normal bridge forwarding. From the perspective of the endpoints, the bridge behaves like an Ethernet segment or switch, although the kernel can still inspect, mark, filter, and capture frames while they traverse the bridge.
|
||||
|
||||
The bridge path has its own \texttt{netfilter} integration \cite{nftablesbridgefiltering}. The \texttt{nftables} \texttt{bridge} family provides hook points before and after the \ac{FDB} decision \cite{nftablesbridgefiltering}. In the \texttt{prerouting} hook, packets can be filtered before the bridge decides the output port. In the \texttt{forward} hook, packets can be filtered when they are bridged from one port to another. The \texttt{input} hook covers frames passed to the local stack, \texttt{output} covers frames coming from the local stack toward a bridge port, and \texttt{postrouting} covers both locally generated and forwarded bridge traffic \cite{nftablesbridgefiltering}.
|
||||
|
||||
The distinction between the \texttt{inet}, \texttt{ip}, and \texttt{bridge} \texttt{nftables} families is important. Rules in the \texttt{ip} or \texttt{inet} family operate on packets that enter the \ac{IP} stack. Rules in the \texttt{bridge} family operate on Ethernet frames in the bridge path. A transparent bridge that should inspect traffic without acting as an \ac{IP} router therefore needs \texttt{bridge}-family rules for Layer-2 forwarding decisions.
|
||||
|
||||
For the setup used in the present thesis, \ac{STP} is not required because the bridge is used as a controlled inline bridge between two network segments and no redundant Layer-2 path is intentionally introduced. Disabling \ac{STP} through \texttt{stp\_state} avoids topology negotiation, \ac{BPDU} processing, and forwarding-delay behavior that would otherwise add configuration-dependent effects to packet timing \cite{man7iplink}. This is only safe under the assumption that the physical and virtual topology is loop-free. If additional bridge ports or redundant links are added, \ac{STP} or \ac{RSTP} should remain enabled because Linux uses it to prevent loops and broadcast storms in Ethernet networks \cite{linuxkernelbridgedocs}.
|
||||
|
||||
\subsection{Egress Path}
|
||||
|
||||
The egress path depends on where the packet originates. For locally generated traffic, the path begins when an application writes to a socket. The socket layer calls functions such as \texttt{sock\_sendmsg()}, which select the transport-layer implementation. At this point, \acp{LSM} may already apply security checks. The \ac{TCP} implementation segments data, maintains connection state, enforces congestion-control behavior, and enqueues \texttt{sk\_buff} structures in the socket write queue. The \ac{UDP} implementation builds datagrams with less connection state and less protocol machinery \cite{stephan2024packetpath}.
|
||||
|
||||
After transport-layer processing, the packet enters the \ac{IP} output path. Linux determines the route, often by consulting the \ac{FIB}, and builds the \ac{IP} header. \texttt{Netfilter} can inspect locally generated traffic at \texttt{LOCAL\_OUT} and later at \texttt{POST\_ROUTING}. If the destination is on an Ethernet network, the neighbor subsystem resolves the next-hop \ac{MAC} address, for example through \ac{ARP}. Then the Ethernet header is prepared and the packet is passed to the device transmission path \cite{stephan2024packetpath}.
|
||||
|
||||
For both locally generated and forwarded packets, the final transmission path goes through the network device queueing layer. Linux calls \texttt{dev\_queue\_xmit()}, where queueing disciplines can schedule, delay, classify, or drop packets. \texttt{tc} egress programs can also run at this stage. Afterwards, the driver transmission function, commonly exposed as \texttt{ndo\_start\_xmit}, places the packet into the transmit ring of the \ac{NIC}. The packet buffer is mapped for \ac{DMA}, and the hardware transmits the frame onto the physical medium \cite{stephan2024packetpath}.
|
||||
|
||||
For bridged packets, the local socket and transport-layer construction steps are skipped. The packet already exists as an Ethernet frame. After the bridge has selected an output port and the frame has passed the relevant bridge filtering hooks, the packet enters the output device path and is eventually queued for transmission on the selected interface. Consequently, \texttt{tc} egress and device-level queueing remain relevant even for purely bridged traffic.
|
||||
|
||||
\subsection{Programmable Hook Points}
|
||||
|
||||
Linux provides several hook points that allow packet processing to be extended without modifying the kernel source code. \ac{eBPF}, the successor of \ac{BPF}, is one of the main mechanisms for this \cite{man7tcbpf}. It allows user-supplied programs to be loaded into the kernel and executed at designated hooks after verification by the kernel \cite{gbadamosi2024ebpfruntime}. The verifier is intended to ensure that programs cannot corrupt kernel memory or run without bounds, while just-in-time compilation can provide efficient execution \cite{man7tcbpf}.
|
||||
|
||||
\texttt{Netfilter} and \texttt{nftables} provide another programmable processing layer. The \texttt{nftables} hook model distinguishes packet families, hook names, chain types, and priorities. Locally delivered packets pass through \texttt{prerouting} and \texttt{input}; forwarded routed packets pass through \texttt{prerouting}, \texttt{forward}, and \texttt{postrouting}; locally generated packets pass through \texttt{output} and \texttt{postrouting}. Within a hook, priorities determine the order in which \texttt{nftables} chains and internal \texttt{netfilter} operations run \cite{nftableshooks}.
|
||||
|
||||
The earliest hook point considered here is \ac{XDP}. Native \ac{XDP} programs are executed in the driver receive path before the normal \texttt{sk\_buff} is allocated \cite{hoilandjorgensen2018xdp}. This position allows very early pass, drop, transmit, and redirect decisions \cite{hoilandjorgensen2018xdp}. Because of this position, \ac{XDP} is suitable for high packet-rate processing \cite{scholz2018ebpfpacketfiltering}. However, because the packet has not yet entered the regular \texttt{sk\_buff}-based networking stack, normal \texttt{sk\_buff} metadata is not available in native \ac{XDP} mode.
|
||||
|
||||
After an \texttt{sk\_buff} exists, \texttt{tc} ingress and egress programs can process packets as \ac{eBPF} classifiers \cite{man7tcbpf}. The ingress side is reached shortly after the packet enters the receive path, while the egress side is reached after routing or bridge forwarding has selected an output interface \cite{stephan2024packetpath}. Since these programs operate on an \texttt{\_\_sk\_buff} context, they can inspect packet bytes and use metadata such as \texttt{skb->mark} \cite{man7tcbpf}. This makes \texttt{tc}/\ac{eBPF} useful for low-overhead telemetry and packet correlation without changing the frame transmitted on the wire.
|
||||
|
||||
For bridged traffic, \texttt{nftables} \texttt{bridge} hooks provide the main verdict mechanism. Rules in the \texttt{bridge} family are evaluated in the bridge path and can therefore affect Ethernet frames that are forwarded between bridge ports without entering the routed \ac{IP} path \cite{nftablesbridgefiltering}. In particular, \texttt{bridge}-family rules can be attached before or after the \ac{FDB} decision \cite{nftablesbridgefiltering}. They can be used to accept, drop, or redirect frames at Layer 2 \cite{westphal2016bridgefiltering}.
|
||||
|
||||
For passive raw capture, Linux provides packet sockets through \texttt{AF\_PACKET}. Packet sockets are used to receive or send raw packets at the device-driver level and can be bound to a specific interface \cite{man7packet}. This makes them suitable for Layer-2 observation of Ethernet frames. In the context of a forwarding bridge, such capture is conceptually separate from the bridge forwarding decision, because observing a packet through a packet socket does not itself define the packet's forwarding verdict.
|
||||
|
||||
Lastly, \texttt{tracepoint} hooks expose selected kernel events to tracing tools and \ac{eBPF} programs \cite{linuxkerneltracepointsdocs}. They are useful for events that are difficult to infer from raw packet captures alone, for example packet free or drop paths. In such cases, \texttt{tracepoint}-based telemetry can complement ingress and egress observations by providing metadata about what happened to an \texttt{sk\_buff} inside the kernel \cite{gbadamosi2024ebpfruntime}.
|
||||
|
||||
\ac{NFQUEUE} is built on top of \texttt{netfilter}. A rule can queue a packet to user space, where an application inspects the packet and returns a verdict such as accept, drop, or modified accept. This is more flexible than a purely in-kernel rule, but it also introduces user-kernel transfer overhead and makes packet latency depend on the user-space application. Therefore, \ac{NFQUEUE} is suitable for programmable manipulation, while early in-kernel hooks are better suited for low-overhead telemetry or simple filtering.
|
||||
|
||||
For the present thesis, these hook points explain the structure of the developed system. Raw packet capture observes frame contents, \texttt{tc}/\ac{eBPF} telemetry observes kernel metadata on ingress and egress, \texttt{nftables} \texttt{bridge} rules can decide the fate of bridged packets, and packet marks can connect observations from different stages of the same kernel path. Since a single Ethernet frame can be captured, cloned, forwarded, marked, and later observed again on another interface, reliable correlation requires an explicit packet identity or a stable reconstruction from packet fields.
|
||||
|
||||
326
documentation/thesis/ba.bib
Normal file
@@ -0,0 +1,326 @@
|
||||
@article{cerf1974protocol,
|
||||
author = {Cerf, Vinton G. and Kahn, Robert E.},
|
||||
title = {A Protocol for Packet Network Intercommunication},
|
||||
journaltitle = {IEEE Transactions on Communications},
|
||||
volume = {22},
|
||||
number = {5},
|
||||
pages = {637--648},
|
||||
date = {1974-05},
|
||||
doi = {10.1109/TCOM.1974.1092259}
|
||||
}
|
||||
|
||||
@techreport{rfc791,
|
||||
author = {Postel, Jon},
|
||||
title = {Internet Protocol},
|
||||
type = {RFC},
|
||||
number = {791},
|
||||
institution = {RFC Editor},
|
||||
date = {1981-09},
|
||||
doi = {10.17487/RFC0791}
|
||||
}
|
||||
|
||||
@techreport{rfc793,
|
||||
author = {Postel, Jon},
|
||||
title = {Transmission Control Protocol},
|
||||
type = {RFC},
|
||||
number = {793},
|
||||
institution = {RFC Editor},
|
||||
date = {1981-09},
|
||||
doi = {10.17487/RFC0793}
|
||||
}
|
||||
|
||||
@techreport{rfc1122,
|
||||
author = {Braden, Robert},
|
||||
title = {Requirements for Internet Hosts -- Communication Layers},
|
||||
type = {RFC},
|
||||
number = {1122},
|
||||
institution = {RFC Editor},
|
||||
date = {1989-10},
|
||||
doi = {10.17487/RFC1122}
|
||||
}
|
||||
|
||||
@techreport{rfc1812,
|
||||
author = {Baker, Fred},
|
||||
title = {Requirements for {IP} Version 4 Routers},
|
||||
type = {RFC},
|
||||
number = {1812},
|
||||
institution = {RFC Editor},
|
||||
date = {1995-06},
|
||||
doi = {10.17487/RFC1812}
|
||||
}
|
||||
|
||||
@techreport{rfc3022,
|
||||
author = {Srisuresh, Pyda and Egevang, Kjeld},
|
||||
title = {Traditional {IP} Network Address Translator ({Traditional NAT})},
|
||||
type = {RFC},
|
||||
number = {3022},
|
||||
institution = {RFC Editor},
|
||||
date = {2001-01},
|
||||
doi = {10.17487/RFC3022}
|
||||
}
|
||||
|
||||
@inproceedings{stephan2024packetpath,
|
||||
author = {Stephan, Alexander and W{\"u}strich, Lars},
|
||||
title = {The Path of a Packet Through the Linux Kernel},
|
||||
booktitle = {Seminar IITM WS 23},
|
||||
date = {2024},
|
||||
doi = {10.2313/NET-2024-04-1\_16},
|
||||
url = {https://www.net.in.tum.de/fileadmin/TUM/NET/NET-2024-04-1/NET-2024-04-1_16.pdf}
|
||||
}
|
||||
|
||||
@inproceedings{hoilandjorgensen2018xdp,
|
||||
author = {H{\o}iland-J{\o}rgensen, Toke and Brouer, Jesper Dangaard and Borkmann, Daniel and Fastabend, John and Herbert, Tom and Ahern, David and Miller, David},
|
||||
title = {The {eXpress} Data Path: Fast Programmable Packet Processing in the Operating System Kernel},
|
||||
booktitle = {Proceedings of the 14th International Conference on Emerging Networking Experiments and Technologies},
|
||||
series = {CoNEXT '18},
|
||||
pages = {54--66},
|
||||
publisher = {Association for Computing Machinery},
|
||||
location = {Heraklion, Greece},
|
||||
date = {2018},
|
||||
doi = {10.1145/3281411.3281443},
|
||||
url = {https://doi.org/10.1145/3281411.3281443}
|
||||
}
|
||||
|
||||
@inproceedings{scholz2018ebpfpacketfiltering,
|
||||
author = {Scholz, Dominik and Raumer, Daniel and Emmerich, Paul and Kurtz, Alexander and Lesiak, Krzysztof and Carle, Georg},
|
||||
title = {Performance Implications of Packet Filtering with {Linux eBPF}},
|
||||
booktitle = {2018 30th International Teletraffic Congress},
|
||||
series = {ITC 30},
|
||||
pages = {209--217},
|
||||
publisher = {IEEE},
|
||||
location = {Vienna, Austria},
|
||||
date = {2018},
|
||||
doi = {10.1109/ITC30.2018.00039},
|
||||
url = {https://www.net.in.tum.de/fileadmin/bibtex/publications/papers/ITC30-Packet-Filtering-eBPF-XDP.pdf}
|
||||
}
|
||||
|
||||
@online{gbadamosi2024ebpfruntime,
|
||||
author = {Gbadamosi, Bolaji and Leonardi, Luigi and Pulls, Tobias and H{\o}iland-J{\o}rgensen, Toke and Ferlin-Reiter, Simone and Sorce, Simo and Brunstr{\"o}m, Anna},
|
||||
title = {The {eBPF} Runtime in the {Linux} Kernel},
|
||||
date = {2024-10-03},
|
||||
eprint = {2410.00026},
|
||||
eprinttype = {arXiv},
|
||||
doi = {10.48550/arXiv.2410.00026},
|
||||
url = {https://arxiv.org/abs/2410.00026},
|
||||
urldate = {2026-05-15}
|
||||
}
|
||||
|
||||
@inproceedings{westphal2016bridgefiltering,
|
||||
author = {Westphal, Florian},
|
||||
title = {Bridge Filtering with {nftables}},
|
||||
booktitle = {Proceedings of Netdev 1.1},
|
||||
location = {Seville, Spain},
|
||||
date = {2016},
|
||||
url = {https://netdevconf.org/1.1/proceedings/papers/Bridge-filter-with-nftables.pdf},
|
||||
urldate = {2026-05-15}
|
||||
}
|
||||
|
||||
@article{conti2016mitmsurvey,
|
||||
author = {Conti, Mauro and Dragoni, Nicola and Lesyk, Viktor},
|
||||
title = {A Survey of {Man In The Middle} Attacks},
|
||||
journaltitle = {IEEE Communications Surveys \& Tutorials},
|
||||
volume = {18},
|
||||
number = {3},
|
||||
pages = {2027--2051},
|
||||
date = {2016},
|
||||
doi = {10.1109/COMST.2016.2548426},
|
||||
url = {https://doi.org/10.1109/COMST.2016.2548426}
|
||||
}
|
||||
|
||||
@article{nam2012arpmitm,
|
||||
author = {Nam, Seung Yeob and Jurayev, Sirojiddin and Kim, Seung-Sik and Choi, Kwonhue and Choi, Gyu Sang},
|
||||
title = {Mitigating {ARP} Poisoning-Based {Man-in-the-Middle} Attacks in Wired or Wireless {LAN}},
|
||||
journaltitle = {EURASIP Journal on Wireless Communications and Networking},
|
||||
volume = {2012},
|
||||
number = {1},
|
||||
eid = {89},
|
||||
date = {2012},
|
||||
doi = {10.1186/1687-1499-2012-89},
|
||||
url = {https://doi.org/10.1186/1687-1499-2012-89}
|
||||
}
|
||||
|
||||
@inproceedings{zhang2007portmirroring,
|
||||
author = {Zhang, Jian and Moore, Andrew W.},
|
||||
title = {Traffic Trace Artifacts due to Monitoring Via Port Mirroring},
|
||||
booktitle = {2007 Workshop on End-to-End Monitoring Techniques and Services},
|
||||
series = {E2EMON '07},
|
||||
pages = {1--8},
|
||||
publisher = {IEEE},
|
||||
date = {2007},
|
||||
doi = {10.1109/E2EMON.2007.375317},
|
||||
url = {https://www.cl.cam.ac.uk/research/srg/netos/papers/2007-zhang2007traffic.pdf},
|
||||
urldate = {2026-05-16}
|
||||
}
|
||||
|
||||
@inproceedings{durumeric2017httpsinterception,
|
||||
author = {Durumeric, Zakir and Ma, Zane and Springall, Drew and Barnes, Richard and Sullivan, Nick and Bursztein, Elie and Bailey, Michael and Halderman, J. Alex and Paxson, Vern},
|
||||
title = {The Security Impact of {HTTPS} Interception},
|
||||
booktitle = {Proceedings of the Network and Distributed System Security Symposium},
|
||||
series = {NDSS '17},
|
||||
date = {2017},
|
||||
doi = {10.14722/ndss.2017.23456},
|
||||
url = {https://doi.org/10.14722/ndss.2017.23456}
|
||||
}
|
||||
|
||||
@inproceedings{waked2018tlsinterception,
|
||||
author = {Waked, Louis and Mannan, Mohammad and Youssef, Amr},
|
||||
title = {To Intercept or Not to Intercept: Analyzing {TLS} Interception in Network Appliances},
|
||||
booktitle = {Proceedings of the 2018 {ACM Asia} Conference on Computer and Communications Security},
|
||||
series = {ASIACCS '18},
|
||||
pages = {399--412},
|
||||
publisher = {Association for Computing Machinery},
|
||||
location = {Incheon, Republic of Korea},
|
||||
date = {2018},
|
||||
doi = {10.1145/3196494.3196528},
|
||||
url = {https://doi.org/10.1145/3196494.3196528}
|
||||
}
|
||||
|
||||
@article{decarnedecarnavalet2023tlsinterception,
|
||||
author = {de Carn{\'e} de Carnavalet, Xavier and van Oorschot, Paul C.},
|
||||
title = {A Survey and Analysis of {TLS} Interception Mechanisms and Motivations},
|
||||
journaltitle = {ACM Computing Surveys},
|
||||
volume = {55},
|
||||
number = {13s},
|
||||
articleno = {269},
|
||||
pages = {1--40},
|
||||
date = {2023},
|
||||
doi = {10.1145/3580522},
|
||||
url = {https://doi.org/10.1145/3580522}
|
||||
}
|
||||
|
||||
@manual{ieee8021q2022,
|
||||
author = {{IEEE}},
|
||||
title = {{IEEE Standard for Local and Metropolitan Area Networks--Bridges and Bridged Networks}},
|
||||
organization = {IEEE},
|
||||
type = {IEEE Std 802.1Q-2022},
|
||||
date = {2022-12-22},
|
||||
url = {https://standards.ieee.org/ieee/802.1Q/10323/},
|
||||
urldate = {2026-05-16}
|
||||
}
|
||||
|
||||
@inproceedings{perlman1985spanningtree,
|
||||
author = {Perlman, Radia},
|
||||
title = {An Algorithm for Distributed Computation of a Spanningtree in an Extended {LAN}},
|
||||
booktitle = {Proceedings of the Ninth Symposium on Data Communications},
|
||||
series = {SIGCOMM '85},
|
||||
pages = {44--53},
|
||||
publisher = {Association for Computing Machinery},
|
||||
location = {Whistler Mountain, British Columbia, Canada},
|
||||
date = {1985},
|
||||
doi = {10.1145/319056.319004},
|
||||
url = {https://doi.org/10.1145/319056.319004}
|
||||
}
|
||||
|
||||
@online{linuxkernelnetworkingdocs,
|
||||
author = {{The Linux Kernel Documentation Authors}},
|
||||
title = {Networking --- The Linux Kernel documentation},
|
||||
year = {2026},
|
||||
url = {https://docs.kernel.org/networking/index.html},
|
||||
urldate = {2026-04-18}
|
||||
}
|
||||
|
||||
@online{linuxkernelskbuffdocs,
|
||||
author = {{The Linux Kernel Documentation Authors}},
|
||||
title = {struct sk\_buff --- The Linux Kernel documentation},
|
||||
year = {2026},
|
||||
url = {https://docs.kernel.org/networking/skbuff.html},
|
||||
urldate = {2026-04-18}
|
||||
}
|
||||
|
||||
@online{linuxkernelbridgedocs,
|
||||
author = {{The Linux Kernel Documentation Authors}},
|
||||
title = {Ethernet Bridging --- The Linux Kernel documentation},
|
||||
year = {2026},
|
||||
url = {https://docs.kernel.org/networking/bridge.html},
|
||||
urldate = {2026-04-18}
|
||||
}
|
||||
|
||||
@online{linuxkernelswitchdevdocs,
|
||||
author = {{The Linux Kernel Documentation Authors}},
|
||||
title = {Ethernet switch device driver model (switchdev) --- The Linux Kernel documentation},
|
||||
year = {2026},
|
||||
url = {https://www.kernel.org/doc/html/latest/networking/switchdev.html},
|
||||
urldate = {2026-05-16}
|
||||
}
|
||||
|
||||
@online{linuxkernelflowtabledocs,
|
||||
author = {{The Linux Kernel Documentation Authors}},
|
||||
title = {Netfilter's Flowtable Infrastructure --- The Linux Kernel documentation},
|
||||
year = {2026},
|
||||
url = {https://docs.kernel.org/networking/nf_flowtable.html},
|
||||
urldate = {2026-05-15}
|
||||
}
|
||||
|
||||
@online{linuxkernelscalingdocs,
|
||||
author = {{The Linux Kernel Documentation Authors}},
|
||||
title = {Scaling in the Linux Networking Stack --- The Linux Kernel documentation},
|
||||
year = {2026},
|
||||
url = {https://docs.kernel.org/networking/scaling.html},
|
||||
urldate = {2026-05-15}
|
||||
}
|
||||
|
||||
@online{linuxkerneltracepointsdocs,
|
||||
author = {{The Linux Kernel Documentation Authors}},
|
||||
title = {Using the Linux Kernel Tracepoints --- The Linux Kernel documentation},
|
||||
year = {2026},
|
||||
url = {https://www.kernel.org/doc/html/latest/trace/tracepoints.html},
|
||||
urldate = {2026-05-16}
|
||||
}
|
||||
|
||||
@online{man7packet,
|
||||
author = {{Linux man-pages project}},
|
||||
title = {packet(7) --- Linux manual page},
|
||||
date = {2025-09-21},
|
||||
url = {https://man7.org/linux/man-pages/man7/packet.7.html},
|
||||
urldate = {2026-05-16}
|
||||
}
|
||||
|
||||
@online{man7tcbpf,
|
||||
author = {{Linux man-pages project}},
|
||||
title = {tc-bpf(8) --- Linux manual page},
|
||||
date = {2025-08-08},
|
||||
url = {https://man7.org/linux/man-pages/man8/tc-bpf.8.html},
|
||||
urldate = {2026-05-16}
|
||||
}
|
||||
|
||||
@online{man7bridge,
|
||||
author = {{Linux man-pages project}},
|
||||
title = {bridge(8) --- Linux manual page},
|
||||
date = {2012-08-01},
|
||||
url = {https://man7.org/linux/man-pages/man8/bridge.8.html},
|
||||
urldate = {2026-05-16}
|
||||
}
|
||||
|
||||
@online{man7iplink,
|
||||
author = {{Linux man-pages project}},
|
||||
title = {ip-link(8) --- Linux manual page},
|
||||
date = {2012-12-13},
|
||||
url = {https://man7.org/linux/man-pages/man8/ip-link.8.html},
|
||||
urldate = {2026-05-16}
|
||||
}
|
||||
|
||||
@online{nftableshooks,
|
||||
author = {{The nftables Project}},
|
||||
title = {Netfilter Hooks},
|
||||
year = {2023},
|
||||
url = {https://wiki.nftables.org/wiki-nftables/index.php/Netfilter_hooks},
|
||||
urldate = {2026-05-15}
|
||||
}
|
||||
|
||||
@online{nftablesbridgefiltering,
|
||||
author = {{The nftables Project}},
|
||||
title = {Bridge Filtering},
|
||||
year = {2021},
|
||||
url = {https://wiki.nftables.org/wiki-nftables/index.php/Bridge_filtering},
|
||||
urldate = {2026-05-15}
|
||||
}
|
||||
|
||||
@online{nftables_manpage,
|
||||
title = {nft(8) -- Administration Tool of the nftables Framework
|
||||
for Packet Filtering and Classification},
|
||||
author = {{The Netfilter Project}},
|
||||
organization = {The Netfilter Project},
|
||||
year = {2026},
|
||||
url = {https://netfilter.org/projects/nftables/manpage.html},
|
||||
note = {Accessed: 2026-08-08}
|
||||
}
|
||||
BIN
documentation/thesis/figures/benchmark/added_one_way_delay.png
Normal file
|
After Width: | Height: | Size: 59 KiB |
1143
documentation/thesis/figures/benchmark/added_one_way_delay.svg
Normal file
|
After Width: | Height: | Size: 29 KiB |
@@ -0,0 +1,91 @@
|
||||
setup,category,metric,unit,direction,payload_size_bytes,protocol,count,mean,median,min,max,std
|
||||
bridge-new,flent,data_file_exists,bool,,,,3,1.0,1.0,1.0,1.0,0.0
|
||||
bridge-new,iperf_tcp,retransmits,count,forward,,,1,0.0,0.0,0.0,0.0,
|
||||
bridge-new,iperf_tcp,retransmits,count,reverse,,,1,0.0,0.0,0.0,0.0,
|
||||
bridge-new,iperf_tcp,throughput,Mbit/s,forward,,,1,941.2170773518191,941.2170773518191,941.2170773518191,941.2170773518191,
|
||||
bridge-new,iperf_tcp,throughput,Mbit/s,reverse,,,1,941.223044856063,941.223044856063,941.223044856063,941.223044856063,
|
||||
bridge-new,iperf_udp,jitter,ms,forward,,,1,329.1133542566476,329.1133542566476,329.1133542566476,329.1133542566476,
|
||||
bridge-new,iperf_udp,jitter,ms,reverse,,,1,0.011945675546752457,0.011945675546752457,0.011945675546752457,0.011945675546752457,
|
||||
bridge-new,iperf_udp,loss,percent,forward,,,1,0.00552541229203311,0.00552541229203311,0.00552541229203311,0.00552541229203311,
|
||||
bridge-new,iperf_udp,loss,percent,reverse,,,1,0.0,0.0,0.0,0.0,
|
||||
bridge-new,iperf_udp,throughput,Mbit/s,forward,,,1,691.7975032635362,691.7975032635362,691.7975032635362,691.7975032635362,
|
||||
bridge-new,iperf_udp,throughput,Mbit/s,reverse,,,1,899.980891114048,899.980891114048,899.980891114048,899.980891114048,
|
||||
bridge-new,ping,jitter_mean_abs_delta,ms,,56.0,,1,0.25014242848569707,0.25014242848569707,0.25014242848569707,0.25014242848569707,
|
||||
bridge-new,ping,jitter_mean_abs_delta,ms,,512.0,,1,0.20838367673534708,0.20838367673534708,0.20838367673534708,0.20838367673534708,
|
||||
bridge-new,ping,jitter_mean_abs_delta,ms,,1472.0,,1,0.18928945789157833,0.18928945789157833,0.18928945789157833,0.18928945789157833,
|
||||
bridge-new,ping,loss,percent,,56.0,,1,0.0,0.0,0.0,0.0,
|
||||
bridge-new,ping,loss,percent,,512.0,,1,0.0,0.0,0.0,0.0,
|
||||
bridge-new,ping,loss,percent,,1472.0,,1,0.0,0.0,0.0,0.0,
|
||||
bridge-new,ping,rtt_iqr,ms,,56.0,,1,0.20999999999999974,0.20999999999999974,0.20999999999999974,0.20999999999999974,
|
||||
bridge-new,ping,rtt_iqr,ms,,512.0,,1,0.17000000000000015,0.17000000000000015,0.17000000000000015,0.17000000000000015,
|
||||
bridge-new,ping,rtt_iqr,ms,,1472.0,,1,0.15999999999999992,0.15999999999999992,0.15999999999999992,0.15999999999999992,
|
||||
bridge-new,ping,rtt_mad,ms,,56.0,,1,0.06999999999999984,0.06999999999999984,0.06999999999999984,0.06999999999999984,
|
||||
bridge-new,ping,rtt_mad,ms,,512.0,,1,0.050000000000000266,0.050000000000000266,0.050000000000000266,0.050000000000000266,
|
||||
bridge-new,ping,rtt_mad,ms,,1472.0,,1,0.040000000000000036,0.040000000000000036,0.040000000000000036,0.040000000000000036,
|
||||
bridge-new,ping,rtt_max,ms,,56.0,,1,2.24,2.24,2.24,2.24,
|
||||
bridge-new,ping,rtt_max,ms,,512.0,,1,2.31,2.31,2.31,2.31,
|
||||
bridge-new,ping,rtt_max,ms,,1472.0,,1,2.36,2.36,2.36,2.36,
|
||||
bridge-new,ping,rtt_mean,ms,,56.0,,1,1.7996464,1.7996464,1.7996464,1.7996464,
|
||||
bridge-new,ping,rtt_mean,ms,,512.0,,1,1.866984,1.866984,1.866984,1.866984,
|
||||
bridge-new,ping,rtt_mean,ms,,1472.0,,1,1.910105,1.910105,1.910105,1.910105,
|
||||
bridge-new,ping,rtt_median,ms,,56.0,,1,1.98,1.98,1.98,1.98,
|
||||
bridge-new,ping,rtt_median,ms,,512.0,,1,2.03,2.03,2.03,2.03,
|
||||
bridge-new,ping,rtt_median,ms,,1472.0,,1,2.08,2.08,2.08,2.08,
|
||||
bridge-new,ping,rtt_min,ms,,56.0,,1,0.279,0.279,0.279,0.279,
|
||||
bridge-new,ping,rtt_min,ms,,512.0,,1,0.306,0.306,0.306,0.306,
|
||||
bridge-new,ping,rtt_min,ms,,1472.0,,1,0.373,0.373,0.373,0.373,
|
||||
bridge-new,ping,rtt_p95,ms,,56.0,,1,2.09,2.09,2.09,2.09,
|
||||
bridge-new,ping,rtt_p95,ms,,512.0,,1,2.13,2.13,2.13,2.13,
|
||||
bridge-new,ping,rtt_p95,ms,,1472.0,,1,2.18,2.18,2.18,2.18,
|
||||
bridge-new,ping,rtt_p99,ms,,56.0,,1,2.14,2.14,2.14,2.14,
|
||||
bridge-new,ping,rtt_p99,ms,,512.0,,1,2.17,2.17,2.17,2.17,
|
||||
bridge-new,ping,rtt_p99,ms,,1472.0,,1,2.21,2.21,2.21,2.21,
|
||||
bridge-new,ping,rtt_stdev,ms,,56.0,,1,0.42052572542496,0.42052572542496,0.42052572542496,0.42052572542496,
|
||||
bridge-new,ping,rtt_stdev,ms,,512.0,,1,0.38826014131180947,0.38826014131180947,0.38826014131180947,0.38826014131180947,
|
||||
bridge-new,ping,rtt_stdev,ms,,1472.0,,1,0.40225082364120024,0.40225082364120024,0.40225082364120024,0.40225082364120024,
|
||||
bridge-new,sockperf,avg_latency_usec,us,,,tcp,1,242.02,242.02,242.02,242.02,
|
||||
direct,flent,data_file_exists,bool,,,,3,1.0,1.0,1.0,1.0,0.0
|
||||
direct,iperf_tcp,retransmits,count,forward,,,1,0.0,0.0,0.0,0.0,
|
||||
direct,iperf_tcp,retransmits,count,reverse,,,1,0.0,0.0,0.0,0.0,
|
||||
direct,iperf_tcp,throughput,Mbit/s,forward,,,1,941.4052500378058,941.4052500378058,941.4052500378058,941.4052500378058,
|
||||
direct,iperf_tcp,throughput,Mbit/s,reverse,,,1,941.4233862520524,941.4233862520524,941.4233862520524,941.4233862520524,
|
||||
direct,iperf_udp,jitter,ms,forward,,,1,0.010443516671235937,0.010443516671235937,0.010443516671235937,0.010443516671235937,
|
||||
direct,iperf_udp,jitter,ms,reverse,,,1,0.010410725838564765,0.010410725838564765,0.010410725838564765,0.010410725838564765,
|
||||
direct,iperf_udp,loss,percent,forward,,,1,0.0,0.0,0.0,0.0,
|
||||
direct,iperf_udp,loss,percent,reverse,,,1,0.002895969068476154,0.002895969068476154,0.002895969068476154,0.002895969068476154,
|
||||
direct,iperf_udp,throughput,Mbit/s,forward,,,1,899.951785108759,899.951785108759,899.951785108759,899.951785108759,
|
||||
direct,iperf_udp,throughput,Mbit/s,reverse,,,1,899.961104896446,899.961104896446,899.961104896446,899.961104896446,
|
||||
direct,ping,jitter_mean_abs_delta,ms,,56.0,,1,0.16798879775955192,0.16798879775955192,0.16798879775955192,0.16798879775955192,
|
||||
direct,ping,jitter_mean_abs_delta,ms,,512.0,,1,0.18655691138227648,0.18655691138227648,0.18655691138227648,0.18655691138227648,
|
||||
direct,ping,jitter_mean_abs_delta,ms,,1472.0,,1,0.18377075415083016,0.18377075415083016,0.18377075415083016,0.18377075415083016,
|
||||
direct,ping,loss,percent,,56.0,,1,0.0,0.0,0.0,0.0,
|
||||
direct,ping,loss,percent,,512.0,,1,0.0,0.0,0.0,0.0,
|
||||
direct,ping,loss,percent,,1472.0,,1,0.0,0.0,0.0,0.0,
|
||||
direct,ping,rtt_iqr,ms,,56.0,,1,0.14000000000000012,0.14000000000000012,0.14000000000000012,0.14000000000000012,
|
||||
direct,ping,rtt_iqr,ms,,512.0,,1,0.16000000000000014,0.16000000000000014,0.16000000000000014,0.16000000000000014,
|
||||
direct,ping,rtt_iqr,ms,,1472.0,,1,0.1200000000000001,0.1200000000000001,0.1200000000000001,0.1200000000000001,
|
||||
direct,ping,rtt_mad,ms,,56.0,,1,0.040000000000000036,0.040000000000000036,0.040000000000000036,0.040000000000000036,
|
||||
direct,ping,rtt_mad,ms,,512.0,,1,0.08000000000000007,0.08000000000000007,0.08000000000000007,0.08000000000000007,
|
||||
direct,ping,rtt_mad,ms,,1472.0,,1,0.05999999999999983,0.05999999999999983,0.05999999999999983,0.05999999999999983,
|
||||
direct,ping,rtt_max,ms,,56.0,,1,1.74,1.74,1.74,1.74,
|
||||
direct,ping,rtt_max,ms,,512.0,,1,1.78,1.78,1.78,1.78,
|
||||
direct,ping,rtt_max,ms,,1472.0,,1,1.81,1.81,1.81,1.81,
|
||||
direct,ping,rtt_mean,ms,,56.0,,1,1.3608360000000002,1.3608360000000002,1.3608360000000002,1.3608360000000002,
|
||||
direct,ping,rtt_mean,ms,,512.0,,1,1.3263896000000002,1.3263896000000002,1.3263896000000002,1.3263896000000002,
|
||||
direct,ping,rtt_mean,ms,,1472.0,,1,1.335693,1.335693,1.335693,1.335693,
|
||||
direct,ping,rtt_median,ms,,56.0,,1,1.51,1.51,1.51,1.51,
|
||||
direct,ping,rtt_median,ms,,512.0,,1,1.48,1.48,1.48,1.48,
|
||||
direct,ping,rtt_median,ms,,1472.0,,1,1.43,1.43,1.43,1.43,
|
||||
direct,ping,rtt_min,ms,,56.0,,1,0.027,0.027,0.027,0.027,
|
||||
direct,ping,rtt_min,ms,,512.0,,1,0.043,0.043,0.043,0.043,
|
||||
direct,ping,rtt_min,ms,,1472.0,,1,0.077,0.077,0.077,0.077,
|
||||
direct,ping,rtt_p95,ms,,56.0,,1,1.59,1.59,1.59,1.59,
|
||||
direct,ping,rtt_p95,ms,,512.0,,1,1.6,1.6,1.6,1.6,
|
||||
direct,ping,rtt_p95,ms,,1472.0,,1,1.63,1.63,1.63,1.63,
|
||||
direct,ping,rtt_p99,ms,,56.0,,1,1.66,1.66,1.66,1.66,
|
||||
direct,ping,rtt_p99,ms,,512.0,,1,1.65,1.65,1.65,1.65,
|
||||
direct,ping,rtt_p99,ms,,1472.0,,1,1.68,1.68,1.68,1.68,
|
||||
direct,ping,rtt_stdev,ms,,56.0,,1,0.38241341543944507,0.38241341543944507,0.38241341543944507,0.38241341543944507,
|
||||
direct,ping,rtt_stdev,ms,,512.0,,1,0.41370645730808175,0.41370645730808175,0.41370645730808175,0.41370645730808175,
|
||||
direct,ping,rtt_stdev,ms,,1472.0,,1,0.36380108603059363,0.36380108603059363,0.36380108603059363,0.36380108603059363,
|
||||
direct,sockperf,avg_latency_usec,us,,,tcp,1,21.286,21.286,21.286,21.286,
|
||||
|
95
documentation/thesis/figures/benchmark/benchmark_metrics.csv
Normal file
@@ -0,0 +1,95 @@
|
||||
setup,category,metric,value,unit,direction,payload_size_bytes,protocol,test,source
|
||||
direct,flent,data_file_exists,1.0,bool,,,,rrul,measurments/20260508-221054-direct/summary.json
|
||||
direct,flent,data_file_exists,1.0,bool,,,,tcp_upload,measurments/20260508-221054-direct/summary.json
|
||||
direct,flent,data_file_exists,1.0,bool,,,,tcp_download,measurments/20260508-221054-direct/summary.json
|
||||
direct,iperf_tcp,retransmits,0.0,count,forward,,,,measurments/20260508-221054-direct/summary.json
|
||||
direct,iperf_tcp,retransmits,0.0,count,reverse,,,,measurments/20260508-221054-direct/summary.json
|
||||
direct,iperf_tcp,throughput,941.4052500378058,Mbit/s,forward,,,,measurments/20260508-221054-direct/summary.json
|
||||
direct,iperf_tcp,throughput,941.4233862520524,Mbit/s,reverse,,,,measurments/20260508-221054-direct/summary.json
|
||||
direct,iperf_udp,jitter,0.010443516671235937,ms,forward,,,,measurments/20260508-221054-direct/summary.json
|
||||
direct,iperf_udp,jitter,0.010410725838564765,ms,reverse,,,,measurments/20260508-221054-direct/summary.json
|
||||
direct,iperf_udp,loss,0.0,percent,forward,,,,measurments/20260508-221054-direct/summary.json
|
||||
direct,iperf_udp,loss,0.002895969068476154,percent,reverse,,,,measurments/20260508-221054-direct/summary.json
|
||||
direct,iperf_udp,throughput,899.951785108759,Mbit/s,forward,,,,measurments/20260508-221054-direct/summary.json
|
||||
direct,iperf_udp,throughput,899.961104896446,Mbit/s,reverse,,,,measurments/20260508-221054-direct/summary.json
|
||||
direct,ping,jitter_mean_abs_delta,0.16798879775955192,ms,,56.0,,,measurments/20260508-221054-direct/summary.json
|
||||
direct,ping,jitter_mean_abs_delta,0.18655691138227648,ms,,512.0,,,measurments/20260508-221054-direct/summary.json
|
||||
direct,ping,jitter_mean_abs_delta,0.18377075415083016,ms,,1472.0,,,measurments/20260508-221054-direct/summary.json
|
||||
direct,ping,loss,0.0,percent,,56.0,,,measurments/20260508-221054-direct/summary.json
|
||||
direct,ping,loss,0.0,percent,,512.0,,,measurments/20260508-221054-direct/summary.json
|
||||
direct,ping,loss,0.0,percent,,1472.0,,,measurments/20260508-221054-direct/summary.json
|
||||
direct,ping,rtt_iqr,0.14000000000000012,ms,,56.0,,,measurments/20260508-221054-direct/summary.json
|
||||
direct,ping,rtt_iqr,0.16000000000000014,ms,,512.0,,,measurments/20260508-221054-direct/summary.json
|
||||
direct,ping,rtt_iqr,0.1200000000000001,ms,,1472.0,,,measurments/20260508-221054-direct/summary.json
|
||||
direct,ping,rtt_mad,0.040000000000000036,ms,,56.0,,,measurments/20260508-221054-direct/summary.json
|
||||
direct,ping,rtt_mad,0.08000000000000007,ms,,512.0,,,measurments/20260508-221054-direct/summary.json
|
||||
direct,ping,rtt_mad,0.05999999999999983,ms,,1472.0,,,measurments/20260508-221054-direct/summary.json
|
||||
direct,ping,rtt_max,1.74,ms,,56.0,,,measurments/20260508-221054-direct/summary.json
|
||||
direct,ping,rtt_max,1.78,ms,,512.0,,,measurments/20260508-221054-direct/summary.json
|
||||
direct,ping,rtt_max,1.81,ms,,1472.0,,,measurments/20260508-221054-direct/summary.json
|
||||
direct,ping,rtt_mean,1.3608360000000002,ms,,56.0,,,measurments/20260508-221054-direct/summary.json
|
||||
direct,ping,rtt_mean,1.3263896000000002,ms,,512.0,,,measurments/20260508-221054-direct/summary.json
|
||||
direct,ping,rtt_mean,1.335693,ms,,1472.0,,,measurments/20260508-221054-direct/summary.json
|
||||
direct,ping,rtt_median,1.51,ms,,56.0,,,measurments/20260508-221054-direct/summary.json
|
||||
direct,ping,rtt_median,1.48,ms,,512.0,,,measurments/20260508-221054-direct/summary.json
|
||||
direct,ping,rtt_median,1.43,ms,,1472.0,,,measurments/20260508-221054-direct/summary.json
|
||||
direct,ping,rtt_min,0.027,ms,,56.0,,,measurments/20260508-221054-direct/summary.json
|
||||
direct,ping,rtt_min,0.043,ms,,512.0,,,measurments/20260508-221054-direct/summary.json
|
||||
direct,ping,rtt_min,0.077,ms,,1472.0,,,measurments/20260508-221054-direct/summary.json
|
||||
direct,ping,rtt_p95,1.59,ms,,56.0,,,measurments/20260508-221054-direct/summary.json
|
||||
direct,ping,rtt_p95,1.6,ms,,512.0,,,measurments/20260508-221054-direct/summary.json
|
||||
direct,ping,rtt_p95,1.63,ms,,1472.0,,,measurments/20260508-221054-direct/summary.json
|
||||
direct,ping,rtt_p99,1.66,ms,,56.0,,,measurments/20260508-221054-direct/summary.json
|
||||
direct,ping,rtt_p99,1.65,ms,,512.0,,,measurments/20260508-221054-direct/summary.json
|
||||
direct,ping,rtt_p99,1.68,ms,,1472.0,,,measurments/20260508-221054-direct/summary.json
|
||||
direct,ping,rtt_stdev,0.38241341543944507,ms,,56.0,,,measurments/20260508-221054-direct/summary.json
|
||||
direct,ping,rtt_stdev,0.41370645730808175,ms,,512.0,,,measurments/20260508-221054-direct/summary.json
|
||||
direct,ping,rtt_stdev,0.36380108603059363,ms,,1472.0,,,measurments/20260508-221054-direct/summary.json
|
||||
direct,sockperf,avg_latency_usec,21.286,us,,,tcp,,measurments/20260508-221054-direct/summary.json
|
||||
bridge-new,flent,data_file_exists,1.0,bool,,,,rrul,measurments/20260508-215553-bridge-new/summary.json
|
||||
bridge-new,flent,data_file_exists,1.0,bool,,,,tcp_upload,measurments/20260508-215553-bridge-new/summary.json
|
||||
bridge-new,flent,data_file_exists,1.0,bool,,,,tcp_download,measurments/20260508-215553-bridge-new/summary.json
|
||||
bridge-new,iperf_tcp,retransmits,0.0,count,forward,,,,measurments/20260508-215553-bridge-new/summary.json
|
||||
bridge-new,iperf_tcp,retransmits,0.0,count,reverse,,,,measurments/20260508-215553-bridge-new/summary.json
|
||||
bridge-new,iperf_tcp,throughput,941.2170773518191,Mbit/s,forward,,,,measurments/20260508-215553-bridge-new/summary.json
|
||||
bridge-new,iperf_tcp,throughput,941.223044856063,Mbit/s,reverse,,,,measurments/20260508-215553-bridge-new/summary.json
|
||||
bridge-new,iperf_udp,jitter,329.1133542566476,ms,forward,,,,measurments/20260508-215553-bridge-new/summary.json
|
||||
bridge-new,iperf_udp,jitter,0.011945675546752457,ms,reverse,,,,measurments/20260508-215553-bridge-new/summary.json
|
||||
bridge-new,iperf_udp,loss,0.00552541229203311,percent,forward,,,,measurments/20260508-215553-bridge-new/summary.json
|
||||
bridge-new,iperf_udp,loss,0.0,percent,reverse,,,,measurments/20260508-215553-bridge-new/summary.json
|
||||
bridge-new,iperf_udp,throughput,691.7975032635362,Mbit/s,forward,,,,measurments/20260508-215553-bridge-new/summary.json
|
||||
bridge-new,iperf_udp,throughput,899.980891114048,Mbit/s,reverse,,,,measurments/20260508-215553-bridge-new/summary.json
|
||||
bridge-new,ping,jitter_mean_abs_delta,0.25014242848569707,ms,,56.0,,,measurments/20260508-215553-bridge-new/summary.json
|
||||
bridge-new,ping,jitter_mean_abs_delta,0.20838367673534708,ms,,512.0,,,measurments/20260508-215553-bridge-new/summary.json
|
||||
bridge-new,ping,jitter_mean_abs_delta,0.18928945789157833,ms,,1472.0,,,measurments/20260508-215553-bridge-new/summary.json
|
||||
bridge-new,ping,loss,0.0,percent,,56.0,,,measurments/20260508-215553-bridge-new/summary.json
|
||||
bridge-new,ping,loss,0.0,percent,,512.0,,,measurments/20260508-215553-bridge-new/summary.json
|
||||
bridge-new,ping,loss,0.0,percent,,1472.0,,,measurments/20260508-215553-bridge-new/summary.json
|
||||
bridge-new,ping,rtt_iqr,0.20999999999999974,ms,,56.0,,,measurments/20260508-215553-bridge-new/summary.json
|
||||
bridge-new,ping,rtt_iqr,0.17000000000000015,ms,,512.0,,,measurments/20260508-215553-bridge-new/summary.json
|
||||
bridge-new,ping,rtt_iqr,0.15999999999999992,ms,,1472.0,,,measurments/20260508-215553-bridge-new/summary.json
|
||||
bridge-new,ping,rtt_mad,0.06999999999999984,ms,,56.0,,,measurments/20260508-215553-bridge-new/summary.json
|
||||
bridge-new,ping,rtt_mad,0.050000000000000266,ms,,512.0,,,measurments/20260508-215553-bridge-new/summary.json
|
||||
bridge-new,ping,rtt_mad,0.040000000000000036,ms,,1472.0,,,measurments/20260508-215553-bridge-new/summary.json
|
||||
bridge-new,ping,rtt_max,2.24,ms,,56.0,,,measurments/20260508-215553-bridge-new/summary.json
|
||||
bridge-new,ping,rtt_max,2.31,ms,,512.0,,,measurments/20260508-215553-bridge-new/summary.json
|
||||
bridge-new,ping,rtt_max,2.36,ms,,1472.0,,,measurments/20260508-215553-bridge-new/summary.json
|
||||
bridge-new,ping,rtt_mean,1.7996464,ms,,56.0,,,measurments/20260508-215553-bridge-new/summary.json
|
||||
bridge-new,ping,rtt_mean,1.866984,ms,,512.0,,,measurments/20260508-215553-bridge-new/summary.json
|
||||
bridge-new,ping,rtt_mean,1.910105,ms,,1472.0,,,measurments/20260508-215553-bridge-new/summary.json
|
||||
bridge-new,ping,rtt_median,1.98,ms,,56.0,,,measurments/20260508-215553-bridge-new/summary.json
|
||||
bridge-new,ping,rtt_median,2.03,ms,,512.0,,,measurments/20260508-215553-bridge-new/summary.json
|
||||
bridge-new,ping,rtt_median,2.08,ms,,1472.0,,,measurments/20260508-215553-bridge-new/summary.json
|
||||
bridge-new,ping,rtt_min,0.279,ms,,56.0,,,measurments/20260508-215553-bridge-new/summary.json
|
||||
bridge-new,ping,rtt_min,0.306,ms,,512.0,,,measurments/20260508-215553-bridge-new/summary.json
|
||||
bridge-new,ping,rtt_min,0.373,ms,,1472.0,,,measurments/20260508-215553-bridge-new/summary.json
|
||||
bridge-new,ping,rtt_p95,2.09,ms,,56.0,,,measurments/20260508-215553-bridge-new/summary.json
|
||||
bridge-new,ping,rtt_p95,2.13,ms,,512.0,,,measurments/20260508-215553-bridge-new/summary.json
|
||||
bridge-new,ping,rtt_p95,2.18,ms,,1472.0,,,measurments/20260508-215553-bridge-new/summary.json
|
||||
bridge-new,ping,rtt_p99,2.14,ms,,56.0,,,measurments/20260508-215553-bridge-new/summary.json
|
||||
bridge-new,ping,rtt_p99,2.17,ms,,512.0,,,measurments/20260508-215553-bridge-new/summary.json
|
||||
bridge-new,ping,rtt_p99,2.21,ms,,1472.0,,,measurments/20260508-215553-bridge-new/summary.json
|
||||
bridge-new,ping,rtt_stdev,0.42052572542496,ms,,56.0,,,measurments/20260508-215553-bridge-new/summary.json
|
||||
bridge-new,ping,rtt_stdev,0.38826014131180947,ms,,512.0,,,measurments/20260508-215553-bridge-new/summary.json
|
||||
bridge-new,ping,rtt_stdev,0.40225082364120024,ms,,1472.0,,,measurments/20260508-215553-bridge-new/summary.json
|
||||
bridge-new,sockperf,avg_latency_usec,242.02,us,,,tcp,,measurments/20260508-215553-bridge-new/summary.json
|
||||
|
BIN
documentation/thesis/figures/benchmark/ping_rtt_percentiles.png
Normal file
|
After Width: | Height: | Size: 53 KiB |
1327
documentation/thesis/figures/benchmark/ping_rtt_percentiles.svg
Normal file
|
After Width: | Height: | Size: 35 KiB |
BIN
documentation/thesis/figures/benchmark/sockperf_latency.png
Normal file
|
After Width: | Height: | Size: 50 KiB |
910
documentation/thesis/figures/benchmark/sockperf_latency.svg
Normal file
@@ -0,0 +1,910 @@
|
||||
<?xml version="1.0" encoding="utf-8" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
|
||||
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg xmlns:xlink="http://www.w3.org/1999/xlink" width="510.348pt" height="297.523321pt" viewBox="0 0 510.348 297.523321" xmlns="http://www.w3.org/2000/svg" version="1.1">
|
||||
<metadata>
|
||||
<rdf:RDF xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:cc="http://creativecommons.org/ns#" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
|
||||
<cc:Work>
|
||||
<dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage"/>
|
||||
<dc:date>2026-05-10T16:24:20.591445</dc:date>
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:creator>
|
||||
<cc:Agent>
|
||||
<dc:title>Matplotlib v3.6.3, https://matplotlib.org/</dc:title>
|
||||
</cc:Agent>
|
||||
</dc:creator>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<defs>
|
||||
<style type="text/css">*{stroke-linejoin: round; stroke-linecap: butt}</style>
|
||||
</defs>
|
||||
<g id="figure_1">
|
||||
<g id="patch_1">
|
||||
<path d="M 0 297.523321
|
||||
L 510.348 297.523321
|
||||
L 510.348 0
|
||||
L 0 0
|
||||
z
|
||||
" style="fill: #ffffff"/>
|
||||
</g>
|
||||
<g id="axes_1">
|
||||
<g id="patch_2">
|
||||
<path d="M 45.588 253.3425
|
||||
L 503.148 253.3425
|
||||
L 503.148 20.4945
|
||||
L 45.588 20.4945
|
||||
z
|
||||
" style="fill: #ffffff"/>
|
||||
</g>
|
||||
<g id="matplotlib.axis_1">
|
||||
<g id="xtick_1">
|
||||
<g id="text_1">
|
||||
<!-- direct -->
|
||||
<g style="fill: #262626" transform="translate(149.605476 278.333286) rotate(-25) scale(0.088 -0.088)">
|
||||
<defs>
|
||||
<path id="DejaVuSans-64" d="M 2906 2969
|
||||
L 2906 4863
|
||||
L 3481 4863
|
||||
L 3481 0
|
||||
L 2906 0
|
||||
L 2906 525
|
||||
Q 2725 213 2448 61
|
||||
Q 2172 -91 1784 -91
|
||||
Q 1150 -91 751 415
|
||||
Q 353 922 353 1747
|
||||
Q 353 2572 751 3078
|
||||
Q 1150 3584 1784 3584
|
||||
Q 2172 3584 2448 3432
|
||||
Q 2725 3281 2906 2969
|
||||
z
|
||||
M 947 1747
|
||||
Q 947 1113 1208 752
|
||||
Q 1469 391 1925 391
|
||||
Q 2381 391 2643 752
|
||||
Q 2906 1113 2906 1747
|
||||
Q 2906 2381 2643 2742
|
||||
Q 2381 3103 1925 3103
|
||||
Q 1469 3103 1208 2742
|
||||
Q 947 2381 947 1747
|
||||
z
|
||||
" transform="scale(0.015625)"/>
|
||||
<path id="DejaVuSans-69" d="M 603 3500
|
||||
L 1178 3500
|
||||
L 1178 0
|
||||
L 603 0
|
||||
L 603 3500
|
||||
z
|
||||
M 603 4863
|
||||
L 1178 4863
|
||||
L 1178 4134
|
||||
L 603 4134
|
||||
L 603 4863
|
||||
z
|
||||
" transform="scale(0.015625)"/>
|
||||
<path id="DejaVuSans-72" d="M 2631 2963
|
||||
Q 2534 3019 2420 3045
|
||||
Q 2306 3072 2169 3072
|
||||
Q 1681 3072 1420 2755
|
||||
Q 1159 2438 1159 1844
|
||||
L 1159 0
|
||||
L 581 0
|
||||
L 581 3500
|
||||
L 1159 3500
|
||||
L 1159 2956
|
||||
Q 1341 3275 1631 3429
|
||||
Q 1922 3584 2338 3584
|
||||
Q 2397 3584 2469 3576
|
||||
Q 2541 3569 2628 3553
|
||||
L 2631 2963
|
||||
z
|
||||
" transform="scale(0.015625)"/>
|
||||
<path id="DejaVuSans-65" d="M 3597 1894
|
||||
L 3597 1613
|
||||
L 953 1613
|
||||
Q 991 1019 1311 708
|
||||
Q 1631 397 2203 397
|
||||
Q 2534 397 2845 478
|
||||
Q 3156 559 3463 722
|
||||
L 3463 178
|
||||
Q 3153 47 2828 -22
|
||||
Q 2503 -91 2169 -91
|
||||
Q 1331 -91 842 396
|
||||
Q 353 884 353 1716
|
||||
Q 353 2575 817 3079
|
||||
Q 1281 3584 2069 3584
|
||||
Q 2775 3584 3186 3129
|
||||
Q 3597 2675 3597 1894
|
||||
z
|
||||
M 3022 2063
|
||||
Q 3016 2534 2758 2815
|
||||
Q 2500 3097 2075 3097
|
||||
Q 1594 3097 1305 2825
|
||||
Q 1016 2553 972 2059
|
||||
L 3022 2063
|
||||
z
|
||||
" transform="scale(0.015625)"/>
|
||||
<path id="DejaVuSans-63" d="M 3122 3366
|
||||
L 3122 2828
|
||||
Q 2878 2963 2633 3030
|
||||
Q 2388 3097 2138 3097
|
||||
Q 1578 3097 1268 2742
|
||||
Q 959 2388 959 1747
|
||||
Q 959 1106 1268 751
|
||||
Q 1578 397 2138 397
|
||||
Q 2388 397 2633 464
|
||||
Q 2878 531 3122 666
|
||||
L 3122 134
|
||||
Q 2881 22 2623 -34
|
||||
Q 2366 -91 2075 -91
|
||||
Q 1284 -91 818 406
|
||||
Q 353 903 353 1747
|
||||
Q 353 2603 823 3093
|
||||
Q 1294 3584 2113 3584
|
||||
Q 2378 3584 2631 3529
|
||||
Q 2884 3475 3122 3366
|
||||
z
|
||||
" transform="scale(0.015625)"/>
|
||||
<path id="DejaVuSans-74" d="M 1172 4494
|
||||
L 1172 3500
|
||||
L 2356 3500
|
||||
L 2356 3053
|
||||
L 1172 3053
|
||||
L 1172 1153
|
||||
Q 1172 725 1289 603
|
||||
Q 1406 481 1766 481
|
||||
L 2356 481
|
||||
L 2356 0
|
||||
L 1766 0
|
||||
Q 1100 0 847 248
|
||||
Q 594 497 594 1153
|
||||
L 594 3053
|
||||
L 172 3053
|
||||
L 172 3500
|
||||
L 594 3500
|
||||
L 594 4494
|
||||
L 1172 4494
|
||||
z
|
||||
" transform="scale(0.015625)"/>
|
||||
</defs>
|
||||
<use xlink:href="#DejaVuSans-64"/>
|
||||
<use xlink:href="#DejaVuSans-69" x="63.476562"/>
|
||||
<use xlink:href="#DejaVuSans-72" x="91.259766"/>
|
||||
<use xlink:href="#DejaVuSans-65" x="130.123047"/>
|
||||
<use xlink:href="#DejaVuSans-63" x="191.646484"/>
|
||||
<use xlink:href="#DejaVuSans-74" x="246.626953"/>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
<g id="xtick_2">
|
||||
<g id="text_2">
|
||||
<!-- bridge-new -->
|
||||
<g style="fill: #262626" transform="translate(367.30762 288.664665) rotate(-25) scale(0.088 -0.088)">
|
||||
<defs>
|
||||
<path id="DejaVuSans-62" d="M 3116 1747
|
||||
Q 3116 2381 2855 2742
|
||||
Q 2594 3103 2138 3103
|
||||
Q 1681 3103 1420 2742
|
||||
Q 1159 2381 1159 1747
|
||||
Q 1159 1113 1420 752
|
||||
Q 1681 391 2138 391
|
||||
Q 2594 391 2855 752
|
||||
Q 3116 1113 3116 1747
|
||||
z
|
||||
M 1159 2969
|
||||
Q 1341 3281 1617 3432
|
||||
Q 1894 3584 2278 3584
|
||||
Q 2916 3584 3314 3078
|
||||
Q 3713 2572 3713 1747
|
||||
Q 3713 922 3314 415
|
||||
Q 2916 -91 2278 -91
|
||||
Q 1894 -91 1617 61
|
||||
Q 1341 213 1159 525
|
||||
L 1159 0
|
||||
L 581 0
|
||||
L 581 4863
|
||||
L 1159 4863
|
||||
L 1159 2969
|
||||
z
|
||||
" transform="scale(0.015625)"/>
|
||||
<path id="DejaVuSans-67" d="M 2906 1791
|
||||
Q 2906 2416 2648 2759
|
||||
Q 2391 3103 1925 3103
|
||||
Q 1463 3103 1205 2759
|
||||
Q 947 2416 947 1791
|
||||
Q 947 1169 1205 825
|
||||
Q 1463 481 1925 481
|
||||
Q 2391 481 2648 825
|
||||
Q 2906 1169 2906 1791
|
||||
z
|
||||
M 3481 434
|
||||
Q 3481 -459 3084 -895
|
||||
Q 2688 -1331 1869 -1331
|
||||
Q 1566 -1331 1297 -1286
|
||||
Q 1028 -1241 775 -1147
|
||||
L 775 -588
|
||||
Q 1028 -725 1275 -790
|
||||
Q 1522 -856 1778 -856
|
||||
Q 2344 -856 2625 -561
|
||||
Q 2906 -266 2906 331
|
||||
L 2906 616
|
||||
Q 2728 306 2450 153
|
||||
Q 2172 0 1784 0
|
||||
Q 1141 0 747 490
|
||||
Q 353 981 353 1791
|
||||
Q 353 2603 747 3093
|
||||
Q 1141 3584 1784 3584
|
||||
Q 2172 3584 2450 3431
|
||||
Q 2728 3278 2906 2969
|
||||
L 2906 3500
|
||||
L 3481 3500
|
||||
L 3481 434
|
||||
z
|
||||
" transform="scale(0.015625)"/>
|
||||
<path id="DejaVuSans-2d" d="M 313 2009
|
||||
L 1997 2009
|
||||
L 1997 1497
|
||||
L 313 1497
|
||||
L 313 2009
|
||||
z
|
||||
" transform="scale(0.015625)"/>
|
||||
<path id="DejaVuSans-6e" d="M 3513 2113
|
||||
L 3513 0
|
||||
L 2938 0
|
||||
L 2938 2094
|
||||
Q 2938 2591 2744 2837
|
||||
Q 2550 3084 2163 3084
|
||||
Q 1697 3084 1428 2787
|
||||
Q 1159 2491 1159 1978
|
||||
L 1159 0
|
||||
L 581 0
|
||||
L 581 3500
|
||||
L 1159 3500
|
||||
L 1159 2956
|
||||
Q 1366 3272 1645 3428
|
||||
Q 1925 3584 2291 3584
|
||||
Q 2894 3584 3203 3211
|
||||
Q 3513 2838 3513 2113
|
||||
z
|
||||
" transform="scale(0.015625)"/>
|
||||
<path id="DejaVuSans-77" d="M 269 3500
|
||||
L 844 3500
|
||||
L 1563 769
|
||||
L 2278 3500
|
||||
L 2956 3500
|
||||
L 3675 769
|
||||
L 4391 3500
|
||||
L 4966 3500
|
||||
L 4050 0
|
||||
L 3372 0
|
||||
L 2619 2869
|
||||
L 1863 0
|
||||
L 1184 0
|
||||
L 269 3500
|
||||
z
|
||||
" transform="scale(0.015625)"/>
|
||||
</defs>
|
||||
<use xlink:href="#DejaVuSans-62"/>
|
||||
<use xlink:href="#DejaVuSans-72" x="63.476562"/>
|
||||
<use xlink:href="#DejaVuSans-69" x="104.589844"/>
|
||||
<use xlink:href="#DejaVuSans-64" x="132.373047"/>
|
||||
<use xlink:href="#DejaVuSans-67" x="195.849609"/>
|
||||
<use xlink:href="#DejaVuSans-65" x="259.326172"/>
|
||||
<use xlink:href="#DejaVuSans-2d" x="320.849609"/>
|
||||
<use xlink:href="#DejaVuSans-6e" x="356.933594"/>
|
||||
<use xlink:href="#DejaVuSans-65" x="420.3125"/>
|
||||
<use xlink:href="#DejaVuSans-77" x="481.835938"/>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
<g id="matplotlib.axis_2">
|
||||
<g id="ytick_1">
|
||||
<g id="line2d_1">
|
||||
<path d="M 45.588 253.3425
|
||||
L 503.148 253.3425
|
||||
" clip-path="url(#p093f8268c7)" style="fill: none; stroke: #cccccc; stroke-opacity: 0.25; stroke-width: 0.8; stroke-linecap: round"/>
|
||||
</g>
|
||||
<g id="text_3">
|
||||
<!-- 0 -->
|
||||
<g style="fill: #262626" transform="translate(31.689 256.685812) scale(0.088 -0.088)">
|
||||
<defs>
|
||||
<path id="DejaVuSans-30" d="M 2034 4250
|
||||
Q 1547 4250 1301 3770
|
||||
Q 1056 3291 1056 2328
|
||||
Q 1056 1369 1301 889
|
||||
Q 1547 409 2034 409
|
||||
Q 2525 409 2770 889
|
||||
Q 3016 1369 3016 2328
|
||||
Q 3016 3291 2770 3770
|
||||
Q 2525 4250 2034 4250
|
||||
z
|
||||
M 2034 4750
|
||||
Q 2819 4750 3233 4129
|
||||
Q 3647 3509 3647 2328
|
||||
Q 3647 1150 3233 529
|
||||
Q 2819 -91 2034 -91
|
||||
Q 1250 -91 836 529
|
||||
Q 422 1150 422 2328
|
||||
Q 422 3509 836 4129
|
||||
Q 1250 4750 2034 4750
|
||||
z
|
||||
" transform="scale(0.015625)"/>
|
||||
</defs>
|
||||
<use xlink:href="#DejaVuSans-30"/>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
<g id="ytick_2">
|
||||
<g id="line2d_2">
|
||||
<path d="M 45.588 207.528104
|
||||
L 503.148 207.528104
|
||||
" clip-path="url(#p093f8268c7)" style="fill: none; stroke: #cccccc; stroke-opacity: 0.25; stroke-width: 0.8; stroke-linecap: round"/>
|
||||
</g>
|
||||
<g id="text_4">
|
||||
<!-- 50 -->
|
||||
<g style="fill: #262626" transform="translate(26.09 210.871417) scale(0.088 -0.088)">
|
||||
<defs>
|
||||
<path id="DejaVuSans-35" d="M 691 4666
|
||||
L 3169 4666
|
||||
L 3169 4134
|
||||
L 1269 4134
|
||||
L 1269 2991
|
||||
Q 1406 3038 1543 3061
|
||||
Q 1681 3084 1819 3084
|
||||
Q 2600 3084 3056 2656
|
||||
Q 3513 2228 3513 1497
|
||||
Q 3513 744 3044 326
|
||||
Q 2575 -91 1722 -91
|
||||
Q 1428 -91 1123 -41
|
||||
Q 819 9 494 109
|
||||
L 494 744
|
||||
Q 775 591 1075 516
|
||||
Q 1375 441 1709 441
|
||||
Q 2250 441 2565 725
|
||||
Q 2881 1009 2881 1497
|
||||
Q 2881 1984 2565 2268
|
||||
Q 2250 2553 1709 2553
|
||||
Q 1456 2553 1204 2497
|
||||
Q 953 2441 691 2322
|
||||
L 691 4666
|
||||
z
|
||||
" transform="scale(0.015625)"/>
|
||||
</defs>
|
||||
<use xlink:href="#DejaVuSans-35"/>
|
||||
<use xlink:href="#DejaVuSans-30" x="63.623047"/>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
<g id="ytick_3">
|
||||
<g id="line2d_3">
|
||||
<path d="M 45.588 161.713709
|
||||
L 503.148 161.713709
|
||||
" clip-path="url(#p093f8268c7)" style="fill: none; stroke: #cccccc; stroke-opacity: 0.25; stroke-width: 0.8; stroke-linecap: round"/>
|
||||
</g>
|
||||
<g id="text_5">
|
||||
<!-- 100 -->
|
||||
<g style="fill: #262626" transform="translate(20.491 165.057021) scale(0.088 -0.088)">
|
||||
<defs>
|
||||
<path id="DejaVuSans-31" d="M 794 531
|
||||
L 1825 531
|
||||
L 1825 4091
|
||||
L 703 3866
|
||||
L 703 4441
|
||||
L 1819 4666
|
||||
L 2450 4666
|
||||
L 2450 531
|
||||
L 3481 531
|
||||
L 3481 0
|
||||
L 794 0
|
||||
L 794 531
|
||||
z
|
||||
" transform="scale(0.015625)"/>
|
||||
</defs>
|
||||
<use xlink:href="#DejaVuSans-31"/>
|
||||
<use xlink:href="#DejaVuSans-30" x="63.623047"/>
|
||||
<use xlink:href="#DejaVuSans-30" x="127.246094"/>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
<g id="ytick_4">
|
||||
<g id="line2d_4">
|
||||
<path d="M 45.588 115.899313
|
||||
L 503.148 115.899313
|
||||
" clip-path="url(#p093f8268c7)" style="fill: none; stroke: #cccccc; stroke-opacity: 0.25; stroke-width: 0.8; stroke-linecap: round"/>
|
||||
</g>
|
||||
<g id="text_6">
|
||||
<!-- 150 -->
|
||||
<g style="fill: #262626" transform="translate(20.491 119.242626) scale(0.088 -0.088)">
|
||||
<use xlink:href="#DejaVuSans-31"/>
|
||||
<use xlink:href="#DejaVuSans-35" x="63.623047"/>
|
||||
<use xlink:href="#DejaVuSans-30" x="127.246094"/>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
<g id="ytick_5">
|
||||
<g id="line2d_5">
|
||||
<path d="M 45.588 70.084918
|
||||
L 503.148 70.084918
|
||||
" clip-path="url(#p093f8268c7)" style="fill: none; stroke: #cccccc; stroke-opacity: 0.25; stroke-width: 0.8; stroke-linecap: round"/>
|
||||
</g>
|
||||
<g id="text_7">
|
||||
<!-- 200 -->
|
||||
<g style="fill: #262626" transform="translate(20.491 73.42823) scale(0.088 -0.088)">
|
||||
<defs>
|
||||
<path id="DejaVuSans-32" d="M 1228 531
|
||||
L 3431 531
|
||||
L 3431 0
|
||||
L 469 0
|
||||
L 469 531
|
||||
Q 828 903 1448 1529
|
||||
Q 2069 2156 2228 2338
|
||||
Q 2531 2678 2651 2914
|
||||
Q 2772 3150 2772 3378
|
||||
Q 2772 3750 2511 3984
|
||||
Q 2250 4219 1831 4219
|
||||
Q 1534 4219 1204 4116
|
||||
Q 875 4013 500 3803
|
||||
L 500 4441
|
||||
Q 881 4594 1212 4672
|
||||
Q 1544 4750 1819 4750
|
||||
Q 2544 4750 2975 4387
|
||||
Q 3406 4025 3406 3419
|
||||
Q 3406 3131 3298 2873
|
||||
Q 3191 2616 2906 2266
|
||||
Q 2828 2175 2409 1742
|
||||
Q 1991 1309 1228 531
|
||||
z
|
||||
" transform="scale(0.015625)"/>
|
||||
</defs>
|
||||
<use xlink:href="#DejaVuSans-32"/>
|
||||
<use xlink:href="#DejaVuSans-30" x="63.623047"/>
|
||||
<use xlink:href="#DejaVuSans-30" x="127.246094"/>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
<g id="ytick_6">
|
||||
<g id="line2d_6">
|
||||
<path d="M 45.588 24.270522
|
||||
L 503.148 24.270522
|
||||
" clip-path="url(#p093f8268c7)" style="fill: none; stroke: #cccccc; stroke-opacity: 0.25; stroke-width: 0.8; stroke-linecap: round"/>
|
||||
</g>
|
||||
<g id="text_8">
|
||||
<!-- 250 -->
|
||||
<g style="fill: #262626" transform="translate(20.491 27.613835) scale(0.088 -0.088)">
|
||||
<use xlink:href="#DejaVuSans-32"/>
|
||||
<use xlink:href="#DejaVuSans-35" x="63.623047"/>
|
||||
<use xlink:href="#DejaVuSans-30" x="127.246094"/>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
<g id="text_9">
|
||||
<!-- Average latency [us] -->
|
||||
<g style="fill: #262626" transform="translate(14.4945 186.6015) rotate(-90) scale(0.096 -0.096)">
|
||||
<defs>
|
||||
<path id="DejaVuSans-41" d="M 2188 4044
|
||||
L 1331 1722
|
||||
L 3047 1722
|
||||
L 2188 4044
|
||||
z
|
||||
M 1831 4666
|
||||
L 2547 4666
|
||||
L 4325 0
|
||||
L 3669 0
|
||||
L 3244 1197
|
||||
L 1141 1197
|
||||
L 716 0
|
||||
L 50 0
|
||||
L 1831 4666
|
||||
z
|
||||
" transform="scale(0.015625)"/>
|
||||
<path id="DejaVuSans-76" d="M 191 3500
|
||||
L 800 3500
|
||||
L 1894 563
|
||||
L 2988 3500
|
||||
L 3597 3500
|
||||
L 2284 0
|
||||
L 1503 0
|
||||
L 191 3500
|
||||
z
|
||||
" transform="scale(0.015625)"/>
|
||||
<path id="DejaVuSans-61" d="M 2194 1759
|
||||
Q 1497 1759 1228 1600
|
||||
Q 959 1441 959 1056
|
||||
Q 959 750 1161 570
|
||||
Q 1363 391 1709 391
|
||||
Q 2188 391 2477 730
|
||||
Q 2766 1069 2766 1631
|
||||
L 2766 1759
|
||||
L 2194 1759
|
||||
z
|
||||
M 3341 1997
|
||||
L 3341 0
|
||||
L 2766 0
|
||||
L 2766 531
|
||||
Q 2569 213 2275 61
|
||||
Q 1981 -91 1556 -91
|
||||
Q 1019 -91 701 211
|
||||
Q 384 513 384 1019
|
||||
Q 384 1609 779 1909
|
||||
Q 1175 2209 1959 2209
|
||||
L 2766 2209
|
||||
L 2766 2266
|
||||
Q 2766 2663 2505 2880
|
||||
Q 2244 3097 1772 3097
|
||||
Q 1472 3097 1187 3025
|
||||
Q 903 2953 641 2809
|
||||
L 641 3341
|
||||
Q 956 3463 1253 3523
|
||||
Q 1550 3584 1831 3584
|
||||
Q 2591 3584 2966 3190
|
||||
Q 3341 2797 3341 1997
|
||||
z
|
||||
" transform="scale(0.015625)"/>
|
||||
<path id="DejaVuSans-20" transform="scale(0.015625)"/>
|
||||
<path id="DejaVuSans-6c" d="M 603 4863
|
||||
L 1178 4863
|
||||
L 1178 0
|
||||
L 603 0
|
||||
L 603 4863
|
||||
z
|
||||
" transform="scale(0.015625)"/>
|
||||
<path id="DejaVuSans-79" d="M 2059 -325
|
||||
Q 1816 -950 1584 -1140
|
||||
Q 1353 -1331 966 -1331
|
||||
L 506 -1331
|
||||
L 506 -850
|
||||
L 844 -850
|
||||
Q 1081 -850 1212 -737
|
||||
Q 1344 -625 1503 -206
|
||||
L 1606 56
|
||||
L 191 3500
|
||||
L 800 3500
|
||||
L 1894 763
|
||||
L 2988 3500
|
||||
L 3597 3500
|
||||
L 2059 -325
|
||||
z
|
||||
" transform="scale(0.015625)"/>
|
||||
<path id="DejaVuSans-5b" d="M 550 4863
|
||||
L 1875 4863
|
||||
L 1875 4416
|
||||
L 1125 4416
|
||||
L 1125 -397
|
||||
L 1875 -397
|
||||
L 1875 -844
|
||||
L 550 -844
|
||||
L 550 4863
|
||||
z
|
||||
" transform="scale(0.015625)"/>
|
||||
<path id="DejaVuSans-75" d="M 544 1381
|
||||
L 544 3500
|
||||
L 1119 3500
|
||||
L 1119 1403
|
||||
Q 1119 906 1312 657
|
||||
Q 1506 409 1894 409
|
||||
Q 2359 409 2629 706
|
||||
Q 2900 1003 2900 1516
|
||||
L 2900 3500
|
||||
L 3475 3500
|
||||
L 3475 0
|
||||
L 2900 0
|
||||
L 2900 538
|
||||
Q 2691 219 2414 64
|
||||
Q 2138 -91 1772 -91
|
||||
Q 1169 -91 856 284
|
||||
Q 544 659 544 1381
|
||||
z
|
||||
M 1991 3584
|
||||
L 1991 3584
|
||||
z
|
||||
" transform="scale(0.015625)"/>
|
||||
<path id="DejaVuSans-73" d="M 2834 3397
|
||||
L 2834 2853
|
||||
Q 2591 2978 2328 3040
|
||||
Q 2066 3103 1784 3103
|
||||
Q 1356 3103 1142 2972
|
||||
Q 928 2841 928 2578
|
||||
Q 928 2378 1081 2264
|
||||
Q 1234 2150 1697 2047
|
||||
L 1894 2003
|
||||
Q 2506 1872 2764 1633
|
||||
Q 3022 1394 3022 966
|
||||
Q 3022 478 2636 193
|
||||
Q 2250 -91 1575 -91
|
||||
Q 1294 -91 989 -36
|
||||
Q 684 19 347 128
|
||||
L 347 722
|
||||
Q 666 556 975 473
|
||||
Q 1284 391 1588 391
|
||||
Q 1994 391 2212 530
|
||||
Q 2431 669 2431 922
|
||||
Q 2431 1156 2273 1281
|
||||
Q 2116 1406 1581 1522
|
||||
L 1381 1569
|
||||
Q 847 1681 609 1914
|
||||
Q 372 2147 372 2553
|
||||
Q 372 3047 722 3315
|
||||
Q 1072 3584 1716 3584
|
||||
Q 2034 3584 2315 3537
|
||||
Q 2597 3491 2834 3397
|
||||
z
|
||||
" transform="scale(0.015625)"/>
|
||||
<path id="DejaVuSans-5d" d="M 1947 4863
|
||||
L 1947 -844
|
||||
L 622 -844
|
||||
L 622 -397
|
||||
L 1369 -397
|
||||
L 1369 4416
|
||||
L 622 4416
|
||||
L 622 4863
|
||||
L 1947 4863
|
||||
z
|
||||
" transform="scale(0.015625)"/>
|
||||
</defs>
|
||||
<use xlink:href="#DejaVuSans-41"/>
|
||||
<use xlink:href="#DejaVuSans-76" x="62.533203"/>
|
||||
<use xlink:href="#DejaVuSans-65" x="121.712891"/>
|
||||
<use xlink:href="#DejaVuSans-72" x="183.236328"/>
|
||||
<use xlink:href="#DejaVuSans-61" x="224.349609"/>
|
||||
<use xlink:href="#DejaVuSans-67" x="285.628906"/>
|
||||
<use xlink:href="#DejaVuSans-65" x="349.105469"/>
|
||||
<use xlink:href="#DejaVuSans-20" x="410.628906"/>
|
||||
<use xlink:href="#DejaVuSans-6c" x="442.416016"/>
|
||||
<use xlink:href="#DejaVuSans-61" x="470.199219"/>
|
||||
<use xlink:href="#DejaVuSans-74" x="531.478516"/>
|
||||
<use xlink:href="#DejaVuSans-65" x="570.6875"/>
|
||||
<use xlink:href="#DejaVuSans-6e" x="632.210938"/>
|
||||
<use xlink:href="#DejaVuSans-63" x="695.589844"/>
|
||||
<use xlink:href="#DejaVuSans-79" x="750.570312"/>
|
||||
<use xlink:href="#DejaVuSans-20" x="809.75"/>
|
||||
<use xlink:href="#DejaVuSans-5b" x="841.537109"/>
|
||||
<use xlink:href="#DejaVuSans-75" x="880.550781"/>
|
||||
<use xlink:href="#DejaVuSans-73" x="943.929688"/>
|
||||
<use xlink:href="#DejaVuSans-5d" x="996.029297"/>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
<g id="patch_3">
|
||||
<path d="M 68.466 253.3425
|
||||
L 251.49 253.3425
|
||||
L 251.49 233.838396
|
||||
L 68.466 233.838396
|
||||
z
|
||||
" clip-path="url(#p093f8268c7)" style="fill: #2f837f; stroke: #ffffff; stroke-width: 0.8; stroke-linejoin: miter"/>
|
||||
</g>
|
||||
<g id="patch_4">
|
||||
<path d="M 297.246 253.3425
|
||||
L 480.27 253.3425
|
||||
L 480.27 31.5825
|
||||
L 297.246 31.5825
|
||||
z
|
||||
" clip-path="url(#p093f8268c7)" style="fill: #2f837f; stroke: #ffffff; stroke-width: 0.8; stroke-linejoin: miter"/>
|
||||
</g>
|
||||
<g id="patch_5">
|
||||
<path d="M 159.978 253.3425
|
||||
L 159.978 253.3425
|
||||
L 159.978 253.3425
|
||||
L 159.978 253.3425
|
||||
z
|
||||
" clip-path="url(#p093f8268c7)" style="fill: #2f837f; stroke: #ffffff; stroke-width: 0.8; stroke-linejoin: miter"/>
|
||||
</g>
|
||||
<g id="patch_6">
|
||||
<path d="M 45.588 253.3425
|
||||
L 45.588 20.4945
|
||||
" style="fill: none; stroke: #cccccc; stroke-linejoin: miter; stroke-linecap: square"/>
|
||||
</g>
|
||||
<g id="patch_7">
|
||||
<path d="M 45.588 253.3425
|
||||
L 503.148 253.3425
|
||||
" style="fill: none; stroke: #cccccc; stroke-linejoin: miter; stroke-linecap: square"/>
|
||||
</g>
|
||||
<g id="text_10">
|
||||
<!-- Sockperf Application Latency -->
|
||||
<g style="fill: #262626" transform="translate(204.45675 14.4945) scale(0.096 -0.096)">
|
||||
<defs>
|
||||
<path id="DejaVuSans-53" d="M 3425 4513
|
||||
L 3425 3897
|
||||
Q 3066 4069 2747 4153
|
||||
Q 2428 4238 2131 4238
|
||||
Q 1616 4238 1336 4038
|
||||
Q 1056 3838 1056 3469
|
||||
Q 1056 3159 1242 3001
|
||||
Q 1428 2844 1947 2747
|
||||
L 2328 2669
|
||||
Q 3034 2534 3370 2195
|
||||
Q 3706 1856 3706 1288
|
||||
Q 3706 609 3251 259
|
||||
Q 2797 -91 1919 -91
|
||||
Q 1588 -91 1214 -16
|
||||
Q 841 59 441 206
|
||||
L 441 856
|
||||
Q 825 641 1194 531
|
||||
Q 1563 422 1919 422
|
||||
Q 2459 422 2753 634
|
||||
Q 3047 847 3047 1241
|
||||
Q 3047 1584 2836 1778
|
||||
Q 2625 1972 2144 2069
|
||||
L 1759 2144
|
||||
Q 1053 2284 737 2584
|
||||
Q 422 2884 422 3419
|
||||
Q 422 4038 858 4394
|
||||
Q 1294 4750 2059 4750
|
||||
Q 2388 4750 2728 4690
|
||||
Q 3069 4631 3425 4513
|
||||
z
|
||||
" transform="scale(0.015625)"/>
|
||||
<path id="DejaVuSans-6f" d="M 1959 3097
|
||||
Q 1497 3097 1228 2736
|
||||
Q 959 2375 959 1747
|
||||
Q 959 1119 1226 758
|
||||
Q 1494 397 1959 397
|
||||
Q 2419 397 2687 759
|
||||
Q 2956 1122 2956 1747
|
||||
Q 2956 2369 2687 2733
|
||||
Q 2419 3097 1959 3097
|
||||
z
|
||||
M 1959 3584
|
||||
Q 2709 3584 3137 3096
|
||||
Q 3566 2609 3566 1747
|
||||
Q 3566 888 3137 398
|
||||
Q 2709 -91 1959 -91
|
||||
Q 1206 -91 779 398
|
||||
Q 353 888 353 1747
|
||||
Q 353 2609 779 3096
|
||||
Q 1206 3584 1959 3584
|
||||
z
|
||||
" transform="scale(0.015625)"/>
|
||||
<path id="DejaVuSans-6b" d="M 581 4863
|
||||
L 1159 4863
|
||||
L 1159 1991
|
||||
L 2875 3500
|
||||
L 3609 3500
|
||||
L 1753 1863
|
||||
L 3688 0
|
||||
L 2938 0
|
||||
L 1159 1709
|
||||
L 1159 0
|
||||
L 581 0
|
||||
L 581 4863
|
||||
z
|
||||
" transform="scale(0.015625)"/>
|
||||
<path id="DejaVuSans-70" d="M 1159 525
|
||||
L 1159 -1331
|
||||
L 581 -1331
|
||||
L 581 3500
|
||||
L 1159 3500
|
||||
L 1159 2969
|
||||
Q 1341 3281 1617 3432
|
||||
Q 1894 3584 2278 3584
|
||||
Q 2916 3584 3314 3078
|
||||
Q 3713 2572 3713 1747
|
||||
Q 3713 922 3314 415
|
||||
Q 2916 -91 2278 -91
|
||||
Q 1894 -91 1617 61
|
||||
Q 1341 213 1159 525
|
||||
z
|
||||
M 3116 1747
|
||||
Q 3116 2381 2855 2742
|
||||
Q 2594 3103 2138 3103
|
||||
Q 1681 3103 1420 2742
|
||||
Q 1159 2381 1159 1747
|
||||
Q 1159 1113 1420 752
|
||||
Q 1681 391 2138 391
|
||||
Q 2594 391 2855 752
|
||||
Q 3116 1113 3116 1747
|
||||
z
|
||||
" transform="scale(0.015625)"/>
|
||||
<path id="DejaVuSans-66" d="M 2375 4863
|
||||
L 2375 4384
|
||||
L 1825 4384
|
||||
Q 1516 4384 1395 4259
|
||||
Q 1275 4134 1275 3809
|
||||
L 1275 3500
|
||||
L 2222 3500
|
||||
L 2222 3053
|
||||
L 1275 3053
|
||||
L 1275 0
|
||||
L 697 0
|
||||
L 697 3053
|
||||
L 147 3053
|
||||
L 147 3500
|
||||
L 697 3500
|
||||
L 697 3744
|
||||
Q 697 4328 969 4595
|
||||
Q 1241 4863 1831 4863
|
||||
L 2375 4863
|
||||
z
|
||||
" transform="scale(0.015625)"/>
|
||||
<path id="DejaVuSans-4c" d="M 628 4666
|
||||
L 1259 4666
|
||||
L 1259 531
|
||||
L 3531 531
|
||||
L 3531 0
|
||||
L 628 0
|
||||
L 628 4666
|
||||
z
|
||||
" transform="scale(0.015625)"/>
|
||||
</defs>
|
||||
<use xlink:href="#DejaVuSans-53"/>
|
||||
<use xlink:href="#DejaVuSans-6f" x="63.476562"/>
|
||||
<use xlink:href="#DejaVuSans-63" x="124.658203"/>
|
||||
<use xlink:href="#DejaVuSans-6b" x="179.638672"/>
|
||||
<use xlink:href="#DejaVuSans-70" x="237.548828"/>
|
||||
<use xlink:href="#DejaVuSans-65" x="301.025391"/>
|
||||
<use xlink:href="#DejaVuSans-72" x="362.548828"/>
|
||||
<use xlink:href="#DejaVuSans-66" x="403.662109"/>
|
||||
<use xlink:href="#DejaVuSans-20" x="438.867188"/>
|
||||
<use xlink:href="#DejaVuSans-41" x="470.654297"/>
|
||||
<use xlink:href="#DejaVuSans-70" x="539.0625"/>
|
||||
<use xlink:href="#DejaVuSans-70" x="602.539062"/>
|
||||
<use xlink:href="#DejaVuSans-6c" x="666.015625"/>
|
||||
<use xlink:href="#DejaVuSans-69" x="693.798828"/>
|
||||
<use xlink:href="#DejaVuSans-63" x="721.582031"/>
|
||||
<use xlink:href="#DejaVuSans-61" x="776.5625"/>
|
||||
<use xlink:href="#DejaVuSans-74" x="837.841797"/>
|
||||
<use xlink:href="#DejaVuSans-69" x="877.050781"/>
|
||||
<use xlink:href="#DejaVuSans-6f" x="904.833984"/>
|
||||
<use xlink:href="#DejaVuSans-6e" x="966.015625"/>
|
||||
<use xlink:href="#DejaVuSans-20" x="1029.394531"/>
|
||||
<use xlink:href="#DejaVuSans-4c" x="1061.181641"/>
|
||||
<use xlink:href="#DejaVuSans-61" x="1116.894531"/>
|
||||
<use xlink:href="#DejaVuSans-74" x="1178.173828"/>
|
||||
<use xlink:href="#DejaVuSans-65" x="1217.382812"/>
|
||||
<use xlink:href="#DejaVuSans-6e" x="1278.90625"/>
|
||||
<use xlink:href="#DejaVuSans-63" x="1342.285156"/>
|
||||
<use xlink:href="#DejaVuSans-79" x="1397.265625"/>
|
||||
</g>
|
||||
</g>
|
||||
<g id="legend_1">
|
||||
<g id="patch_8">
|
||||
<path d="M 51.748 54.14225
|
||||
L 94.424 54.14225
|
||||
Q 96.184 54.14225 96.184 52.38225
|
||||
L 96.184 26.6545
|
||||
Q 96.184 24.8945 94.424 24.8945
|
||||
L 51.748 24.8945
|
||||
Q 49.988 24.8945 49.988 26.6545
|
||||
L 49.988 52.38225
|
||||
Q 49.988 54.14225 51.748 54.14225
|
||||
z
|
||||
" style="fill: #ffffff; opacity: 0.8; stroke: #cccccc; stroke-width: 0.8; stroke-linejoin: miter"/>
|
||||
</g>
|
||||
<g id="text_11">
|
||||
<!-- protocol -->
|
||||
<g style="fill: #262626" transform="translate(53.508 35.709) scale(0.096 -0.096)">
|
||||
<use xlink:href="#DejaVuSans-70"/>
|
||||
<use xlink:href="#DejaVuSans-72" x="63.476562"/>
|
||||
<use xlink:href="#DejaVuSans-6f" x="102.339844"/>
|
||||
<use xlink:href="#DejaVuSans-74" x="163.521484"/>
|
||||
<use xlink:href="#DejaVuSans-6f" x="202.730469"/>
|
||||
<use xlink:href="#DejaVuSans-63" x="263.912109"/>
|
||||
<use xlink:href="#DejaVuSans-6f" x="318.892578"/>
|
||||
<use xlink:href="#DejaVuSans-6c" x="380.074219"/>
|
||||
</g>
|
||||
</g>
|
||||
<g id="patch_9">
|
||||
<path d="M 53.828438 48.792125
|
||||
L 71.428438 48.792125
|
||||
L 71.428438 42.632125
|
||||
L 53.828438 42.632125
|
||||
z
|
||||
" style="fill: #2f837f; stroke: #ffffff; stroke-width: 0.8; stroke-linejoin: miter"/>
|
||||
</g>
|
||||
<g id="text_12">
|
||||
<!-- tcp -->
|
||||
<g style="fill: #262626" transform="translate(78.468438 48.792125) scale(0.088 -0.088)">
|
||||
<use xlink:href="#DejaVuSans-74"/>
|
||||
<use xlink:href="#DejaVuSans-63" x="39.208984"/>
|
||||
<use xlink:href="#DejaVuSans-70" x="94.189453"/>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
<defs>
|
||||
<clipPath id="p093f8268c7">
|
||||
<rect x="45.588" y="20.4945" width="457.56" height="232.848"/>
|
||||
</clipPath>
|
||||
</defs>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 22 KiB |
BIN
documentation/thesis/figures/benchmark/throughput.png
Normal file
|
After Width: | Height: | Size: 60 KiB |
1181
documentation/thesis/figures/benchmark/throughput.svg
Normal file
|
After Width: | Height: | Size: 30 KiB |
BIN
documentation/thesis/figures/benchmark/udp_jitter_loss.png
Normal file
|
After Width: | Height: | Size: 65 KiB |
1231
documentation/thesis/figures/benchmark/udp_jitter_loss.svg
Normal file
|
After Width: | Height: | Size: 32 KiB |
50
documentation/thesis/notes/preliminaries ideas.md
Normal file
@@ -0,0 +1,50 @@
|
||||
Your project is already much richer than a generic “MITM tool.” From the code, it is really a transparent inline Layer-2 observation and manipulation platform: it creates a Linux bridge with STP disabled, manages bridge member behavior, captures traffic either via `AF_PACKET` or `tc/eBPF`, correlates packet observations with kernel telemetry, applies `nftables`/`NFQUEUE` manipulation, and builds higher-level traffic intelligence on top of that. You can see those pillars in [network_api.py](/home/marcus/Desktop/Masterarbeit/mitm-webserver/backend/src/api/network_api.py:498), [bridge_link_state_manager.py](/home/marcus/Desktop/Masterarbeit/mitm-webserver/backend/src/utilities/bridge_link_state_manager.py:86), [network_sniffer.py](/home/marcus/Desktop/Masterarbeit/mitm-webserver/backend/src/network_sniffer.py:774), [bridge_telemetry.py](/home/marcus/Desktop/Masterarbeit/mitm-webserver/backend/src/utilities/bridge_telemetry.py:22), [packet_tracker.py](/home/marcus/Desktop/Masterarbeit/mitm-webserver/backend/src/utilities/packet_tracker.py:238), [nftables_api.py](/home/marcus/Desktop/Masterarbeit/mitm-webserver/backend/src/api/nftables_api.py:47), [packet_scripting_api.py](/home/marcus/Desktop/Masterarbeit/mitm-webserver/backend/src/api/packet_scripting_api.py:2), and [analysis_api.py](/home/marcus/Desktop/Masterarbeit/mitm-webserver/backend/src/api/analysis_api.py:145). Compared with your current [02-preliminaries.tex](/home/marcus/Desktop/Masterarbeit/mitm-webserver/documentation/thesis/02-preliminaries.tex:1), the thesis would benefit from moving beyond a mainly OSI-focused introduction.
|
||||
|
||||
**What I would definitely add to the preliminaries**
|
||||
|
||||
- `Transparent Layer-2 MITM / inline bridge systems`: difference between routed MITM, proxying, TAP/SPAN capture, and transparent bridging.
|
||||
- `Ethernet switching and Linux bridge internals`: MAC learning, forwarding database, flooding, broadcast domains, unknown unicast, VLAN awareness, STP/RSTP, and why disabling STP matters for your setup.
|
||||
- `Stealth / transparency criteria`: what “hidden” means technically in your thesis. For example: no IP hop added, no TTL change, minimal forwarding delay, preserved link properties, no obvious protocol artifacts.
|
||||
- `Link-state propagation and fail behavior`: your code actively mirrors link failures and synchronizes MTU / speed / duplex / autoneg, which is unusually relevant for an inline appliance and worth explaining conceptually.
|
||||
- `Linux packet-processing path`: NIC, driver, `sk_buff`, bridge forwarding path, netfilter hooks, `tc` ingress/egress, and where capture/manipulation can be attached.
|
||||
- `AF_PACKET raw sockets`: why they are suitable for passive L2 capture, and their trade-offs.
|
||||
- `nftables and the bridge family`: tables, chains, hooks, priorities, verdicts, and why bridge-family filtering is important in a transparent bridge scenario.
|
||||
- `NFQUEUE`: how packets are punted to user space, latency/performance implications, and the difference between passive observation and inline modification.
|
||||
- `eBPF at tc`: attach points, maps, helpers, packet metadata access, and why eBPF is useful for low-overhead telemetry and packet correlation.
|
||||
- `Packet marking and correlation`: your project uses `skb->mark`-based packet IDs and verdict bits, which is a very strong thesis concept because it ties kernel events to captured packets ([mark_packet_id.c](/home/marcus/Desktop/Masterarbeit/mitm-webserver/tools/ebpf/mark_packet_id.c:20)).
|
||||
- `Protocol parsing and enrichment`: Ethernet, ARP, IPv4/IPv6, TCP/UDP/ICMP, plus DPI/enrichment with Scapy and `tshark` ([tshark_manager.py](/home/marcus/Desktop/Masterarbeit/mitm-webserver/backend/src/utilities/tshark_manager.py:690)).
|
||||
- `Flow/conversation reconstruction`: packet identity, deduplication, ingress/egress inference, flow IDs, conversations, and discovery traffic classification.
|
||||
- `Threat model and limitations`: what kinds of traffic can be observed/manipulated, how encryption limits analysis, and where the bridge can still become detectable.
|
||||
|
||||
**Very thesis-relevant concepts that are specific to your implementation**
|
||||
|
||||
- `Bridge transparency vs detectability`
|
||||
- `Bridge member synchronization`
|
||||
- `Event-driven network control via netlink / pyroute2`
|
||||
- `Hybrid observation pipeline: raw capture + kernel telemetry + DPI enrichment`
|
||||
- `Correlation of data-plane and control-plane evidence`
|
||||
- `Programmable packet handling with nftables + NFQUEUE scripts`
|
||||
- `Traffic-intelligence extraction from passive observations`
|
||||
- `Discovery protocol analysis`: ARP, DHCP, mDNS, SSDP, LLMNR, NBNS, ICMPv6 discovery
|
||||
|
||||
**What I would keep short or move to implementation**
|
||||
|
||||
- FastAPI, React, WebSockets, Docker, and general UI architecture
|
||||
- PostgreSQL schema details
|
||||
- systemd service deployment details for scripts
|
||||
|
||||
Those matter, but they feel more like implementation chapter material than preliminaries unless your thesis is explicitly about the full software platform architecture.
|
||||
|
||||
**A strong chapter structure could be**
|
||||
|
||||
1. Communication models: brief OSI and TCP/IP mapping
|
||||
2. Ethernet and transparent bridging
|
||||
3. Linux bridge architecture and link-state behavior
|
||||
4. Linux packet path: raw sockets, netfilter, `tc`, and `sk_buff`
|
||||
5. `nftables`, bridge-family filtering, and `NFQUEUE`
|
||||
6. eBPF for packet telemetry and correlation
|
||||
7. Packet parsing, DPI, and flow reconstruction
|
||||
8. Stealth, detectability, and operational limitations
|
||||
9. Ethical and legal boundaries of MITM experimentation
|
||||
|
||||
If you want, I can turn this directly into a thesis-ready rewrite for [02-preliminaries.tex](/home/marcus/Desktop/Masterarbeit/mitm-webserver/documentation/thesis/02-preliminaries.tex:1) with subsection titles and short starter paragraphs.
|
||||
136
documentation/thesis/notes/style_baseline_bachelor_thesis.md
Normal file
@@ -0,0 +1,136 @@
|
||||
# Bachelor Thesis Style Baseline
|
||||
|
||||
Source: Marcus Jan Almert, "An Investigation of the Security of Smart Doorbells", bachelor's thesis, 2022.
|
||||
|
||||
Use this note as the baseline when drafting or revising the master's thesis. The goal is not to copy sentences from the bachelor's thesis, but to preserve its academic voice, explanatory rhythm, and technical clarity.
|
||||
|
||||
## Overall Voice
|
||||
|
||||
- Formal, technical, and objective.
|
||||
- Prefer an impersonal academic perspective: "this thesis", "the present thesis", "the analysis", "the developed system".
|
||||
- Avoid first-person singular. First-person plural is rare and should only be used when the surrounding section genuinely calls for it.
|
||||
- Use present tense for general concepts, protocols, system properties, and chapter purpose.
|
||||
- Use past tense for performed experiments, observations, implementations, and measurements.
|
||||
- Use cautious language when evidence is partial: "could", "may", "potentially", "was not proven", "was observed".
|
||||
|
||||
## Chapter and Section Openings
|
||||
|
||||
The bachelor's thesis often starts chapters with a short roadmap:
|
||||
|
||||
- State what the chapter or section explains.
|
||||
- Then list the sequence of topics with "First", "Next", "Then", "Lastly", or "Thereafter".
|
||||
- Keep the opening practical and close to the technical purpose of the chapter.
|
||||
|
||||
Preferred pattern:
|
||||
|
||||
> The following chapter explains essential concepts used in this thesis. First, ..., Next, ..., Lastly, ...
|
||||
|
||||
For the master's thesis, prefer this direct roadmap style over broader phrases such as "foundational concepts underlying the research".
|
||||
|
||||
## Paragraph Rhythm
|
||||
|
||||
- Begin paragraphs with a clear topic sentence.
|
||||
- Follow with mechanism, implementation detail, or evidence.
|
||||
- End with consequence, relevance, or transition to the next point.
|
||||
- Background paragraphs are medium length and explanatory.
|
||||
- Analysis and evaluation paragraphs are more compact and evidence-driven.
|
||||
- Use lists only when they make capabilities, attack effects, requirements, or result categories easier to scan.
|
||||
|
||||
## Common Transitions
|
||||
|
||||
Useful connective phrases matching the bachelor's thesis style:
|
||||
|
||||
- "For this purpose, ..."
|
||||
- "Using this setup, ..."
|
||||
- "As described in Section ..."
|
||||
- "In the following section, ..."
|
||||
- "Furthermore, ..."
|
||||
- "Additionally, ..."
|
||||
- "However, ..."
|
||||
- "In contrast, ..."
|
||||
- "Consequently, ..."
|
||||
- "Therefore, ..."
|
||||
- "Lastly, ..."
|
||||
- "This allows ..."
|
||||
- "This is evidenced by ..."
|
||||
- "An example of ... is shown in ..."
|
||||
- "Similar to ..."
|
||||
|
||||
Use these naturally; do not over-stack them in every paragraph.
|
||||
|
||||
## Technical Explanation Style
|
||||
|
||||
- Define a concept before relying on it later.
|
||||
- Introduce acronyms on first use, then use the acronym consistently.
|
||||
- In LaTeX, introduce acronyms with the `acronym` package using `\ac{...}` or `\acp{...}`. Do not write acronym short forms manually in running text when an acronym entry exists.
|
||||
- Write tool names, command names, kernel symbols, hook names, protocol constants, and code-level identifiers in `\texttt{...}`. This includes names such as `\texttt{nftables}`, `\texttt{tc}`, `\texttt{sk_buff}`, and `\texttt{AF_PACKET}`. Acronym short forms such as `NFQUEUE` should still be produced with `\ac{NFQUEUE}`, because the thesis settings render acronym short forms in typewriter font automatically.
|
||||
- Prefer exact technical nouns over stylistic synonym changes.
|
||||
- When explaining protocols or implementation paths, move from general role to concrete fields, functions, tools, or messages.
|
||||
- Use listings, tables, and figures to make protocol messages, APIs, measurements, and system paths concrete.
|
||||
- Mention tool names and versions when they matter for reproducibility.
|
||||
|
||||
## Evidence and Claim Strength
|
||||
|
||||
- Tie claims to observations, measurements, listings, figures, tables, or cited sources.
|
||||
- Avoid unsupported adjectives such as "robust", "novel", "seamless", or "powerful" unless the section proves them.
|
||||
- Distinguish clearly between demonstrated findings and plausible implications.
|
||||
- For security-related statements, state the adversary capability or system assumption before the impact.
|
||||
|
||||
## Citation Style
|
||||
|
||||
- Use numeric citation style through LaTeX references.
|
||||
- Place citations near the factual claim they support.
|
||||
- Standards, protocol details, and external tool behavior should be cited.
|
||||
- Implementation descriptions and own measurements usually do not need external citations, but should reference the relevant listing, figure, table, or section.
|
||||
|
||||
## Analysis Section Pattern
|
||||
|
||||
The bachelor's thesis uses a repeatable analysis rhythm:
|
||||
|
||||
1. Introduce the investigated object, version, setup, or scope.
|
||||
2. Describe the observed behavior.
|
||||
3. Explain the technical mechanism.
|
||||
4. Demonstrate the issue or result with concrete evidence.
|
||||
5. State the impact or relevance.
|
||||
6. If appropriate, compare to earlier sections.
|
||||
|
||||
For the master's thesis, this maps well to platform features and evaluation sections:
|
||||
|
||||
1. Introduce the component or measurement scenario.
|
||||
2. Describe where it sits in the packet path or application architecture.
|
||||
3. Explain how it was implemented or measured.
|
||||
4. Show the relevant data, interface, figure, or listing.
|
||||
5. State what this means for correctness, timing, usability, or security analysis.
|
||||
|
||||
## Summary and Future Work Pattern
|
||||
|
||||
The conclusion style is concise and retrospective:
|
||||
|
||||
- Restate the thesis goal.
|
||||
- Summarize the method.
|
||||
- Summarize the main findings or contributions.
|
||||
- Name limitations or unresolved questions.
|
||||
- Present future work as concrete continuation paths.
|
||||
|
||||
Prefer "A future work possibility would be ..." or "Another future work possibility would be ..." when matching the older style, but use it sparingly to avoid repetition.
|
||||
|
||||
## Phrases to Prefer
|
||||
|
||||
- "The goal of this thesis was ..."
|
||||
- "To achieve this, ..."
|
||||
- "The analysis considered ..."
|
||||
- "It was shown that ..."
|
||||
- "It was discovered that ..."
|
||||
- "The following section focuses on ..."
|
||||
- "For the present thesis, ..."
|
||||
- "This is particularly important because ..."
|
||||
- "In preparation for ..."
|
||||
- "The captured data was then examined for ..."
|
||||
|
||||
## Phrases to Avoid or Reduce
|
||||
|
||||
- Marketing-style claims: "seamless", "cutting-edge", "state-of-the-art" unless cited and justified.
|
||||
- Overly abstract openings: "This chapter establishes the theoretical foundation for ..."
|
||||
- Personal narration: "I implemented", "we wanted to".
|
||||
- Unqualified certainty for uncertain findings: use cautious modality where appropriate.
|
||||
- Long rhetorical motivation before the technical problem is clear.
|
||||
@@ -2,6 +2,7 @@ import {
|
||||
DeleteOutlined,
|
||||
DownloadOutlined,
|
||||
EditOutlined,
|
||||
EyeOutlined,
|
||||
FileAddOutlined,
|
||||
PauseCircleOutlined,
|
||||
PlayCircleOutlined,
|
||||
@@ -72,6 +73,7 @@ export default function ScriptsManager({ onOpenInEditor }: { onOpenInEditor?: (c
|
||||
const [editorModalVisible, setEditorModalVisible] = useState(false);
|
||||
const [editorValue, setEditorValue] = useState<string>('');
|
||||
const [currentEditingName, setCurrentEditingName] = useState<string | null>(null);
|
||||
const [editorReadOnly, setEditorReadOnly] = useState(false);
|
||||
|
||||
const [useInlineReqEditor, setUseInlineReqEditor] = useState(false);
|
||||
const [inlineReqValue, setInlineReqValue] = useState<string>('');
|
||||
@@ -166,8 +168,7 @@ export default function ScriptsManager({ onOpenInEditor }: { onOpenInEditor?: (c
|
||||
const val = ta.value ?? '';
|
||||
ta.setSelectionRange(val.length, val.length);
|
||||
}
|
||||
} catch {
|
||||
}
|
||||
} catch {}
|
||||
}, 80);
|
||||
}, []);
|
||||
|
||||
@@ -384,6 +385,7 @@ export default function ScriptsManager({ onOpenInEditor }: { onOpenInEditor?: (c
|
||||
const blob = await downloadScript(name);
|
||||
const text = await blob.text();
|
||||
setEditorValue(text);
|
||||
setEditorReadOnly(false);
|
||||
setEditorModalVisible(true);
|
||||
setCurrentEditingName(name);
|
||||
if (onOpenInEditor) onOpenInEditor(text);
|
||||
@@ -394,6 +396,19 @@ export default function ScriptsManager({ onOpenInEditor }: { onOpenInEditor?: (c
|
||||
[onOpenInEditor],
|
||||
);
|
||||
|
||||
const openReadOnlyViewerFromServer = useCallback(async (name: string) => {
|
||||
try {
|
||||
const blob = await downloadScript(name);
|
||||
const text = await blob.text();
|
||||
setEditorValue(text);
|
||||
setEditorReadOnly(true);
|
||||
setEditorModalVisible(true);
|
||||
setCurrentEditingName(name);
|
||||
} catch (err: any) {
|
||||
notification.error({ message: 'Failed to open', description: err?.message ?? String(err) });
|
||||
}
|
||||
}, []);
|
||||
|
||||
const handleSaveFromEditorAs = useCallback(
|
||||
async (name: string) => {
|
||||
try {
|
||||
@@ -489,7 +504,10 @@ export default function ScriptsManager({ onOpenInEditor }: { onOpenInEditor?: (c
|
||||
return <Badge color={isActive ? '#52c41a' : '#ff4d4f'} text={isActive ? 'Active' : 'Inactive'} />;
|
||||
}, []);
|
||||
|
||||
const isScriptActive = useCallback((record: ScriptWithStatus) => record.mappings.some((mapping) => mapping.active), []);
|
||||
const isScriptActive = useCallback(
|
||||
(record: ScriptWithStatus) => record.mappings.some((mapping) => mapping.active),
|
||||
[],
|
||||
);
|
||||
|
||||
const saveAddRequirements = useCallback(async () => {
|
||||
if (!addReqTarget) return;
|
||||
@@ -539,7 +557,6 @@ export default function ScriptsManager({ onOpenInEditor }: { onOpenInEditor?: (c
|
||||
render: (_: unknown, record: ScriptWithStatus) => (
|
||||
<Space>
|
||||
<code>{record.name}</code>
|
||||
{record.is_protected_example ? <Badge color="#1677ff" text="Protected" /> : null}
|
||||
</Space>
|
||||
),
|
||||
},
|
||||
@@ -607,6 +624,13 @@ export default function ScriptsManager({ onOpenInEditor }: { onOpenInEditor?: (c
|
||||
onClick={() => handleDownload(record.name)}
|
||||
icon={<DownloadOutlined />}
|
||||
/>
|
||||
{record.is_protected_example ? (
|
||||
<IconButtonTooltip
|
||||
title="View script"
|
||||
onClick={() => openReadOnlyViewerFromServer(record.name)}
|
||||
icon={<EyeOutlined />}
|
||||
/>
|
||||
) : null}
|
||||
{!record.is_protected_example ? (
|
||||
<IconButtonTooltip
|
||||
title="Open in editor"
|
||||
@@ -641,6 +665,7 @@ export default function ScriptsManager({ onOpenInEditor }: { onOpenInEditor?: (c
|
||||
handleEditRequirements,
|
||||
isScriptActive,
|
||||
openAddRequirements,
|
||||
openReadOnlyViewerFromServer,
|
||||
openInEditorFromServer,
|
||||
renderStatus,
|
||||
],
|
||||
@@ -741,7 +766,6 @@ export default function ScriptsManager({ onOpenInEditor }: { onOpenInEditor?: (c
|
||||
expandable={expandable}
|
||||
/>
|
||||
|
||||
|
||||
<Modal
|
||||
open={uploadModalVisible}
|
||||
title="Upload or create script"
|
||||
@@ -817,65 +841,90 @@ export default function ScriptsManager({ onOpenInEditor }: { onOpenInEditor?: (c
|
||||
</Form>
|
||||
</Modal>
|
||||
|
||||
|
||||
<Modal
|
||||
open={editorModalVisible}
|
||||
title={currentEditingName ? `Editing — ${currentEditingName}` : 'Editor'}
|
||||
onCancel={() => setEditorModalVisible(false)}
|
||||
title={
|
||||
currentEditingName
|
||||
? `${editorReadOnly ? 'Viewing' : 'Editing'} — ${currentEditingName}`
|
||||
: editorReadOnly
|
||||
? 'Viewer'
|
||||
: 'Editor'
|
||||
}
|
||||
onCancel={() => {
|
||||
setEditorModalVisible(false);
|
||||
setEditorReadOnly(false);
|
||||
}}
|
||||
width={900}
|
||||
footer={
|
||||
<Space>
|
||||
<Button onClick={() => setEditorModalVisible(false)}>Close</Button>
|
||||
editorReadOnly ? (
|
||||
<Button
|
||||
type="default"
|
||||
onClick={() =>
|
||||
Modal.confirm({
|
||||
title: 'Save as',
|
||||
content: (
|
||||
<Form
|
||||
layout="vertical"
|
||||
onFinish={(values) => {
|
||||
handleSaveFromEditorAs(values.name);
|
||||
Modal.destroyAll();
|
||||
}}
|
||||
>
|
||||
<Form.Item name="name" label="Name" rules={[{ required: true }]}>
|
||||
<Input placeholder="new_name.py" />
|
||||
</Form.Item>
|
||||
<Form.Item>
|
||||
<Button htmlType="submit" type="primary">
|
||||
Save
|
||||
</Button>
|
||||
</Form.Item>
|
||||
</Form>
|
||||
),
|
||||
icon: null,
|
||||
okButtonProps: { style: { display: 'none' } },
|
||||
cancelButtonProps: { style: { display: 'none' } },
|
||||
})
|
||||
}
|
||||
>
|
||||
Save as...
|
||||
</Button>
|
||||
<Button
|
||||
type="primary"
|
||||
onClick={() => {
|
||||
if (!currentEditingName) {
|
||||
notification.warning({ message: 'No filename to overwrite' });
|
||||
return;
|
||||
}
|
||||
handleSaveFromEditorAs(currentEditingName);
|
||||
setEditorModalVisible(false);
|
||||
setEditorReadOnly(false);
|
||||
}}
|
||||
>
|
||||
Save
|
||||
Close
|
||||
</Button>
|
||||
</Space>
|
||||
) : (
|
||||
<Space>
|
||||
<Button
|
||||
onClick={() => {
|
||||
setEditorModalVisible(false);
|
||||
setEditorReadOnly(false);
|
||||
}}
|
||||
>
|
||||
Close
|
||||
</Button>
|
||||
<Button
|
||||
type="default"
|
||||
onClick={() =>
|
||||
Modal.confirm({
|
||||
title: 'Save as',
|
||||
content: (
|
||||
<Form
|
||||
layout="vertical"
|
||||
onFinish={(values) => {
|
||||
handleSaveFromEditorAs(values.name);
|
||||
Modal.destroyAll();
|
||||
}}
|
||||
>
|
||||
<Form.Item name="name" label="Name" rules={[{ required: true }]}>
|
||||
<Input placeholder="new_name.py" />
|
||||
</Form.Item>
|
||||
<Form.Item>
|
||||
<Button htmlType="submit" type="primary">
|
||||
Save
|
||||
</Button>
|
||||
</Form.Item>
|
||||
</Form>
|
||||
),
|
||||
icon: null,
|
||||
okButtonProps: { style: { display: 'none' } },
|
||||
cancelButtonProps: { style: { display: 'none' } },
|
||||
})
|
||||
}
|
||||
>
|
||||
Save as...
|
||||
</Button>
|
||||
<Button
|
||||
type="primary"
|
||||
onClick={() => {
|
||||
if (!currentEditingName) {
|
||||
notification.warning({ message: 'No filename to overwrite' });
|
||||
return;
|
||||
}
|
||||
handleSaveFromEditorAs(currentEditingName);
|
||||
}}
|
||||
>
|
||||
Save
|
||||
</Button>
|
||||
</Space>
|
||||
)
|
||||
}
|
||||
>
|
||||
<PythonEditor value={editorValue} onChange={setEditorValue} height={520} />
|
||||
<PythonEditor value={editorValue} onChange={setEditorValue} height={520} readOnly={editorReadOnly} />
|
||||
</Modal>
|
||||
|
||||
|
||||
<Modal
|
||||
open={reqModalVisible}
|
||||
title={reqEditingName ? `requirements.txt — ${reqEditingName}` : 'requirements.txt'}
|
||||
@@ -914,7 +963,6 @@ export default function ScriptsManager({ onOpenInEditor }: { onOpenInEditor?: (c
|
||||
<PythonEditor value={reqEditorValue} onChange={setReqEditorValue} height={420} />
|
||||
</Modal>
|
||||
|
||||
|
||||
<Modal
|
||||
open={addReqModalVisible}
|
||||
title={addReqTarget ? `Add requirements — ${addReqTarget}` : 'Add requirements'}
|
||||
@@ -968,7 +1016,6 @@ export default function ScriptsManager({ onOpenInEditor }: { onOpenInEditor?: (c
|
||||
</div>
|
||||
</Modal>
|
||||
|
||||
|
||||
<Modal
|
||||
open={pipModalVisible}
|
||||
title="pip install output"
|
||||
@@ -987,7 +1034,6 @@ export default function ScriptsManager({ onOpenInEditor }: { onOpenInEditor?: (c
|
||||
</div>
|
||||
</Modal>
|
||||
|
||||
|
||||
<Modal
|
||||
open={enableModalVisible}
|
||||
title={`Enable ${enableTarget ?? ''}`}
|
||||
|
||||
@@ -17,6 +17,7 @@ import {
|
||||
Select,
|
||||
Space,
|
||||
Spin,
|
||||
Switch,
|
||||
Tag,
|
||||
Tooltip,
|
||||
Typography,
|
||||
@@ -62,8 +63,13 @@ export default function SnifferManager(props: SnifferManagerProps): ReactElement
|
||||
setIsModalOpen(false);
|
||||
};
|
||||
|
||||
const handleStartSubmit = async (values: { target?: string; bridgeCaptureMode?: 'tc_ebpf' | 'af_packet' }) => {
|
||||
const handleStartSubmit = async (values: {
|
||||
target?: string;
|
||||
bridgeCaptureMode?: 'tc_ebpf' | 'af_packet';
|
||||
benchmarkMode?: boolean;
|
||||
}) => {
|
||||
const target = values.target;
|
||||
const benchmarkMode = Boolean(values.benchmarkMode);
|
||||
if (!target) {
|
||||
notification.warning({ message: 'Warning', description: 'Please select a target to start capture on.' });
|
||||
return;
|
||||
@@ -72,12 +78,14 @@ export default function SnifferManager(props: SnifferManagerProps): ReactElement
|
||||
try {
|
||||
const payload =
|
||||
startMode === 'interface'
|
||||
? { interface: target }
|
||||
: { bridge: target, bridge_capture_mode: values.bridgeCaptureMode ?? bridgeCaptureMode };
|
||||
? { interface: target, benchmark_mode: benchmarkMode }
|
||||
: { bridge: target, bridge_capture_mode: values.bridgeCaptureMode ?? bridgeCaptureMode, benchmark_mode: benchmarkMode };
|
||||
const result = await startSniffer(payload);
|
||||
notification.success({
|
||||
message: 'Capture started',
|
||||
description: `Capture started on ${target} via ${result.capture_mode} (session ${result.session_id})`,
|
||||
description: `Capture started on ${target} via ${result.capture_mode}${
|
||||
result.benchmark_mode ? ' in benchmark mode' : ''
|
||||
} (session ${result.session_id})`,
|
||||
});
|
||||
await props.refreshAll();
|
||||
setIsModalOpen(false);
|
||||
@@ -241,6 +249,7 @@ export default function SnifferManager(props: SnifferManagerProps): ReactElement
|
||||
{status.capture_mode === 'af_packet' ? 'AF_PACKET' : 'tc/eBPF'}
|
||||
</Tag>
|
||||
)}
|
||||
{status.benchmark_mode && <Tag color="gold">benchmark</Tag>}
|
||||
</Space>
|
||||
}
|
||||
description={<Text type="secondary">interface: {name}</Text>}
|
||||
@@ -260,7 +269,12 @@ export default function SnifferManager(props: SnifferManagerProps): ReactElement
|
||||
confirmLoading={props.loading}
|
||||
okText="Start"
|
||||
>
|
||||
<Form form={form} layout="vertical" onFinish={handleStartSubmit} initialValues={{ target: undefined }}>
|
||||
<Form
|
||||
form={form}
|
||||
layout="vertical"
|
||||
onFinish={handleStartSubmit}
|
||||
initialValues={{ target: undefined, benchmarkMode: false }}
|
||||
>
|
||||
<Form.Item label="Mode" name="mode">
|
||||
<Radio.Group
|
||||
value={startMode}
|
||||
@@ -323,6 +337,19 @@ export default function SnifferManager(props: SnifferManagerProps): ReactElement
|
||||
</Radio.Group>
|
||||
</Form.Item>
|
||||
)}
|
||||
|
||||
<Form.Item
|
||||
label="Benchmark Mode"
|
||||
name="benchmarkMode"
|
||||
valuePropName="checked"
|
||||
extra={
|
||||
startMode === 'bridge' && bridgeCaptureMode === 'tc_ebpf'
|
||||
? 'Keeps tc/eBPF raw export and JSON emission, but skips backend parsing, telemetry merge, DB persistence, DPI enrichment, and live packet publishing.'
|
||||
: 'Receives packets for measurement, but skips packet parsing, packet tracking, DB persistence, DPI enrichment, and live packet publishing.'
|
||||
}
|
||||
>
|
||||
<Switch checkedChildren="Benchmark" unCheckedChildren="Normal" />
|
||||
</Form.Item>
|
||||
</Form>
|
||||
</Modal>
|
||||
</div>
|
||||
|
||||
@@ -1,9 +1,162 @@
|
||||
import Title from 'antd/lib/typography/Title';
|
||||
import { ApartmentOutlined, AreaChartOutlined, HomeOutlined, MonitorOutlined, RightOutlined } from '@ant-design/icons';
|
||||
import { Button, Card, Col, List, Row, Space, Typography } from 'antd';
|
||||
import type { ReactElement, ReactNode } from 'react';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
|
||||
export default function Home() {
|
||||
import FirewallIcon from '../icons/FirewallIcon';
|
||||
import TerminalIcon from '../icons/TerminalIcon';
|
||||
import { PATHS } from '../routes';
|
||||
|
||||
const { Title, Paragraph, Text } = Typography;
|
||||
|
||||
type SectionCard = {
|
||||
key: string;
|
||||
title: string;
|
||||
route?: string;
|
||||
icon: ReactNode;
|
||||
summary: string;
|
||||
bullets: string[];
|
||||
};
|
||||
|
||||
const mainSections: SectionCard[] = [
|
||||
{
|
||||
key: 'home',
|
||||
title: 'Home',
|
||||
route: PATHS.HOME,
|
||||
icon: <HomeOutlined style={{ fontSize: 22 }} />,
|
||||
summary: 'Landing page with a overview of the platform and its main functionalities.',
|
||||
bullets: [''],
|
||||
},
|
||||
{
|
||||
key: 'network',
|
||||
title: 'Network',
|
||||
route: PATHS.NETWORK,
|
||||
icon: <ApartmentOutlined style={{ fontSize: 22 }} />,
|
||||
summary: 'Inspect interfaces, routes, and link-state, create brdiges and enable bridge link state propagation.',
|
||||
bullets: [
|
||||
'Shows the current network state and interface details.',
|
||||
'Creates and removes bridges for traffic interception setups.',
|
||||
'Manages bridge link-state watcher behavior and interface reset operations.',
|
||||
],
|
||||
},
|
||||
{
|
||||
key: 'firewall',
|
||||
title: 'Firewall',
|
||||
route: PATHS.FIREWALL,
|
||||
icon: <FirewallIcon style={{ fontSize: 22 }} />,
|
||||
summary: 'Build and inspect nftables rules that steer or control packet handling.',
|
||||
bullets: [
|
||||
'Display the current nftables ruleset.',
|
||||
'Create tables, chains and rules without writing everything by hand.',
|
||||
'Push packets into NFQUEUEs.',
|
||||
],
|
||||
},
|
||||
{
|
||||
key: 'sniffing',
|
||||
title: 'Sniffing',
|
||||
route: PATHS.SNIFFING,
|
||||
icon: <MonitorOutlined style={{ fontSize: 22 }} />,
|
||||
summary: 'Start live packet capture sessions and inspect captured traffic across interfaces and bridges.',
|
||||
bullets: [
|
||||
'Start and stop capture sessions per interface or bridge.',
|
||||
'Show capture status to see where packets are currently being collected.',
|
||||
'Displays captured packets for live inspection.',
|
||||
],
|
||||
},
|
||||
{
|
||||
key: 'scripting',
|
||||
title: 'Scripting',
|
||||
route: PATHS.SCRIPTING,
|
||||
icon: <TerminalIcon style={{ fontSize: 22 }} width={22} height={22} />,
|
||||
summary: 'Manage NFQUEUE Python scripts that can inspect, modify, delay, or drop packets inline.',
|
||||
bullets: [
|
||||
'Upload and download saved scripts and optional requirements.',
|
||||
'Enable and disable scripts as systemd-backed queue workers.',
|
||||
'Example scripts as baseline for developing new use-cases.',
|
||||
],
|
||||
},
|
||||
{
|
||||
key: 'analysis',
|
||||
title: 'Analysis',
|
||||
route: PATHS.ANALYSIS,
|
||||
icon: <AreaChartOutlined style={{ fontSize: 22 }} />,
|
||||
summary:
|
||||
'Turn captured traffic into higher-level insights such as hosts, paths, conversations, and protocol usage.',
|
||||
bullets: ['Display visualizations from observed traffic.'],
|
||||
},
|
||||
];
|
||||
|
||||
function OverviewCard({ section, onOpen }: { section: SectionCard; onOpen?: (route: string) => void }): ReactElement {
|
||||
return (
|
||||
<div>
|
||||
<Title level={2}>TBD</Title>
|
||||
<Card
|
||||
title={
|
||||
<Space align="center">
|
||||
{section.icon}
|
||||
<span>{section.title}</span>
|
||||
</Space>
|
||||
}
|
||||
extra={
|
||||
section.route && onOpen ? (
|
||||
<Button type="link" onClick={() => onOpen(section.route!)}>
|
||||
Open <RightOutlined />
|
||||
</Button>
|
||||
) : null
|
||||
}
|
||||
style={{ height: '100%' }}
|
||||
>
|
||||
<Paragraph style={{ minHeight: 66 }}>{section.summary}</Paragraph>
|
||||
<List
|
||||
size="small"
|
||||
dataSource={section.bullets}
|
||||
renderItem={(item) => (
|
||||
<List.Item style={{ paddingInline: 0 }}>
|
||||
<Text>{item}</Text>
|
||||
</List.Item>
|
||||
)}
|
||||
/>
|
||||
</Card>
|
||||
);
|
||||
}
|
||||
|
||||
export default function Home(): ReactElement {
|
||||
const navigate = useNavigate();
|
||||
|
||||
return (
|
||||
<div style={{ padding: 16 }}>
|
||||
<Row gutter={[16, 16]}>
|
||||
<Col span={24}>
|
||||
<Card>
|
||||
<Title level={2} style={{ marginTop: 0 }}>
|
||||
MITM Webserver App Overview
|
||||
</Title>
|
||||
<Paragraph>
|
||||
This application is a proof-of-concept platform for network traffic configuration, interception,
|
||||
manipulation, and analyzation. It combines network setup, firewall control, packet capture, inline NFQUEUE
|
||||
scripting, and higher-level traffic analysis in one app while trying to stay hidden from the communicating
|
||||
entities.
|
||||
</Paragraph>
|
||||
</Card>
|
||||
</Col>
|
||||
|
||||
<Col span={24}>
|
||||
<Card>
|
||||
<Title level={4} style={{ marginTop: 0 }}>
|
||||
Main Pages
|
||||
</Title>
|
||||
<Paragraph>
|
||||
These are the core working areas of the application. Each page supports a different phase of network
|
||||
experimentation, monitoring, or analysis.
|
||||
</Paragraph>
|
||||
<Row gutter={[16, 16]}>
|
||||
{mainSections.map((section) => (
|
||||
<Col xs={24} md={12} xl={8} key={section.key}>
|
||||
<OverviewCard section={section} onOpen={(route) => navigate(route)} />
|
||||
</Col>
|
||||
))}
|
||||
</Row>
|
||||
</Card>
|
||||
</Col>
|
||||
</Row>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ export interface SnifferStartRequest {
|
||||
bridge?: string;
|
||||
interface?: string;
|
||||
bridge_capture_mode?: 'tc_ebpf' | 'af_packet';
|
||||
benchmark_mode?: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -17,6 +18,7 @@ export interface SnifferStartResponse {
|
||||
target: string;
|
||||
target_type: 'bridge' | 'interface';
|
||||
capture_mode: 'tc_ebpf' | 'af_packet';
|
||||
benchmark_mode?: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -47,6 +49,7 @@ export interface InterfaceSnifferStatus {
|
||||
session_id?: string | null;
|
||||
session_label?: string | null;
|
||||
capture_mode?: 'tc_ebpf' | 'af_packet' | null;
|
||||
benchmark_mode?: boolean | null;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
64
measurments/20260508-215553-bridge-new/arping.command.json
Normal file
@@ -0,0 +1,64 @@
|
||||
{
|
||||
"command": [
|
||||
"arping",
|
||||
"-I",
|
||||
"enp1s0",
|
||||
"-c",
|
||||
"100",
|
||||
"10.11.11.2"
|
||||
],
|
||||
"returncode": 0,
|
||||
"timed_out": false,
|
||||
"error": null,
|
||||
"start_time": "2026-05-08T19:57:18.174634+00:00",
|
||||
"duration_seconds": 100.02195465000023,
|
||||
"interface_counters_before": {
|
||||
"rx_packets": 24939346,
|
||||
"tx_packets": 5558375,
|
||||
"rx_bytes": 36511818631,
|
||||
"tx_bytes": 34933644481,
|
||||
"rx_dropped": 0,
|
||||
"tx_dropped": 6,
|
||||
"rx_errors": 0,
|
||||
"tx_errors": 0
|
||||
},
|
||||
"interface_counters_after": {
|
||||
"rx_packets": 24939446,
|
||||
"tx_packets": 5558475,
|
||||
"rx_bytes": 36511824631,
|
||||
"tx_bytes": 34933648681,
|
||||
"rx_dropped": 0,
|
||||
"tx_dropped": 6,
|
||||
"rx_errors": 0,
|
||||
"tx_errors": 0
|
||||
},
|
||||
"interface_counters_delta": {
|
||||
"rx_bytes": 6000,
|
||||
"rx_dropped": 0,
|
||||
"rx_errors": 0,
|
||||
"rx_packets": 100,
|
||||
"tx_bytes": 4200,
|
||||
"tx_dropped": 0,
|
||||
"tx_errors": 0,
|
||||
"tx_packets": 100
|
||||
},
|
||||
"system": {
|
||||
"sample_count": 198,
|
||||
"cpu_percent": {
|
||||
"count": 198,
|
||||
"min": 0.2525252525252486,
|
||||
"max": 12.5,
|
||||
"mean": 1.6394533982210147,
|
||||
"median": 1.2499999999999956,
|
||||
"stdev": 1.6075112817414134,
|
||||
"mad": 0.2500000000000002,
|
||||
"iqr": 0.7387872666741457,
|
||||
"cv_percent": 98.05166060137715,
|
||||
"p90": 1.9900497512437831,
|
||||
"p95": 2.4770947243978143,
|
||||
"p99": 10.92217227883908
|
||||
}
|
||||
},
|
||||
"raw_output": "/home/ubuntu/Desktop/mitm-webserver/tools/measurements/20260508-215553-bridge-new/arping.txt",
|
||||
"system_samples_csv": "/home/ubuntu/Desktop/mitm-webserver/tools/measurements/20260508-215553-bridge-new/arping.system_samples.csv"
|
||||
}
|
||||
199
measurments/20260508-215553-bridge-new/arping.system_samples.csv
Normal file
@@ -0,0 +1,199 @@
|
||||
timestamp,cpu_percent,rx_bytes,rx_dropped,rx_errors,rx_packets,tx_bytes,tx_dropped,tx_errors,tx_packets
|
||||
1778270238.6769638,3.508771929824561,36511818691,0,0,24939347,34933644523,6,0,5558376
|
||||
1778270239.17994,2.487562189054726,36511818691,0,0,24939347,34933644565,6,0,5558377
|
||||
1778270239.6828685,1.9900497512437831,36511818751,0,0,24939348,34933644565,6,0,5558377
|
||||
1778270240.1856477,2.2332506203473934,36511818811,0,0,24939349,34933644607,6,0,5558378
|
||||
1778270240.6885135,1.4962593516209433,36511818811,0,0,24939349,34933644607,6,0,5558378
|
||||
1778270241.1916077,1.985111662531014,36511818871,0,0,24939350,34933644649,6,0,5558379
|
||||
1778270241.6945865,1.980198019801982,36511818871,0,0,24939350,34933644649,6,0,5558379
|
||||
1778270242.1976247,1.741293532338306,36511818931,0,0,24939351,34933644691,6,0,5558380
|
||||
1778270242.7005966,1.741293532338306,36511818931,0,0,24939351,34933644691,6,0,5558380
|
||||
1778270243.20362,1.741293532338306,36511818991,0,0,24939352,34933644733,6,0,5558381
|
||||
1778270243.7067602,1.741293532338306,36511818991,0,0,24939352,34933644733,6,0,5558381
|
||||
1778270244.2101665,1.7369727047146455,36511819051,0,0,24939353,34933644775,6,0,5558382
|
||||
1778270244.7132158,1.9900497512437831,36511819051,0,0,24939353,34933644775,6,0,5558382
|
||||
1778270245.2162201,1.985111662531014,36511819111,0,0,24939354,34933644817,6,0,5558383
|
||||
1778270245.7193394,1.741293532338306,36511819111,0,0,24939354,34933644817,6,0,5558383
|
||||
1778270246.2223127,1.985111662531014,36511819171,0,0,24939355,34933644859,6,0,5558384
|
||||
1778270246.7254057,1.9900497512437831,36511819171,0,0,24939355,34933644859,6,0,5558384
|
||||
1778270247.2285762,1.985111662531014,36511819231,0,0,24939356,34933644901,6,0,5558385
|
||||
1778270247.7319043,1.985111662531014,36511819231,0,0,24939356,34933644901,6,0,5558385
|
||||
1778270248.2349281,1.985111662531014,36511819291,0,0,24939357,34933644943,6,0,5558386
|
||||
1778270248.7380457,1.741293532338306,36511819291,0,0,24939357,34933644943,6,0,5558386
|
||||
1778270249.241157,1.7369727047146455,36511819351,0,0,24939358,34933644985,6,0,5558387
|
||||
1778270249.744151,1.9900497512437831,36511819351,0,0,24939358,34933644985,6,0,5558387
|
||||
1778270250.2472215,2.2277227722772297,36511819411,0,0,24939359,34933645027,6,0,5558388
|
||||
1778270250.7502813,2.2332506203473934,36511819411,0,0,24939359,34933645027,6,0,5558388
|
||||
1778270251.2533658,1.741293532338306,36511819471,0,0,24939360,34933645069,6,0,5558389
|
||||
1778270251.756469,1.985111662531014,36511819471,0,0,24939360,34933645069,6,0,5558389
|
||||
1778270252.259499,1.741293532338306,36511819531,0,0,24939361,34933645111,6,0,5558390
|
||||
1778270252.7625349,1.985111662531014,36511819531,0,0,24939361,34933645111,6,0,5558390
|
||||
1778270253.2656074,2.2222222222222254,36511819591,0,0,24939362,34933645153,6,0,5558391
|
||||
1778270253.7685757,1.7456359102244412,36511819591,0,0,24939362,34933645153,6,0,5558391
|
||||
1778270254.271681,1.985111662531014,36511819651,0,0,24939363,34933645195,6,0,5558392
|
||||
1778270254.7749019,2.2332506203473934,36511819651,0,0,24939363,34933645195,6,0,5558392
|
||||
1778270255.2777953,1.985111662531014,36511819711,0,0,24939364,34933645237,6,0,5558393
|
||||
1778270255.7810318,1.985111662531014,36511819711,0,0,24939364,34933645237,6,0,5558393
|
||||
1778270256.2841895,1.7369727047146455,36511819771,0,0,24939365,34933645279,6,0,5558394
|
||||
1778270256.7872133,2.4752475247524774,36511819771,0,0,24939365,34933645279,6,0,5558394
|
||||
1778270257.2902215,1.985111662531014,36511819831,0,0,24939366,34933645321,6,0,5558395
|
||||
1778270257.7932253,1.9900497512437831,36511819831,0,0,24939366,34933645321,6,0,5558395
|
||||
1778270258.2962468,2.2277227722772297,36511819891,0,0,24939367,34933645363,6,0,5558396
|
||||
1778270258.7993443,1.741293532338306,36511819891,0,0,24939367,34933645363,6,0,5558396
|
||||
1778270259.3023252,1.985111662531014,36511819951,0,0,24939368,34933645405,6,0,5558397
|
||||
1778270259.8053074,1.7369727047146455,36511819951,0,0,24939368,34933645405,6,0,5558397
|
||||
1778270260.3084214,1.741293532338306,36511820011,0,0,24939369,34933645447,6,0,5558398
|
||||
1778270260.8114014,1.985111662531014,36511820011,0,0,24939369,34933645447,6,0,5558398
|
||||
1778270261.3144476,1.741293532338306,36511820071,0,0,24939370,34933645489,6,0,5558399
|
||||
1778270261.817532,1.4925373134328401,36511820071,0,0,24939370,34933645489,6,0,5558399
|
||||
1778270262.3205433,1.9900497512437831,36511820131,0,0,24939371,34933645531,6,0,5558400
|
||||
1778270262.823517,1.5000000000000013,36511820131,0,0,24939371,34933645531,6,0,5558400
|
||||
1778270263.3264887,1.4925373134328401,36511820191,0,0,24939372,34933645573,6,0,5558401
|
||||
1778270263.8295004,1.2499999999999956,36511820191,0,0,24939372,34933645573,6,0,5558401
|
||||
1778270264.3325343,1.2499999999999956,36511820251,0,0,24939373,34933645615,6,0,5558402
|
||||
1778270264.8356524,1.0025062656641603,36511820251,0,0,24939373,34933645615,6,0,5558402
|
||||
1778270265.3387365,1.2468827930174564,36511820311,0,0,24939374,34933645657,6,0,5558403
|
||||
1778270265.8421292,1.4962593516209433,36511820311,0,0,24939374,34933645657,6,0,5558403
|
||||
1778270266.34514,1.253132832080206,36511820371,0,0,24939375,34933645699,6,0,5558404
|
||||
1778270266.8481362,1.5000000000000013,36511820371,0,0,24939375,34933645699,6,0,5558404
|
||||
1778270267.3512926,1.2499999999999956,36511820431,0,0,24939376,34933645741,6,0,5558405
|
||||
1778270267.8543272,1.2499999999999956,36511820431,0,0,24939376,34933645741,6,0,5558405
|
||||
1778270268.3572934,1.2468827930174564,36511820491,0,0,24939377,34933645783,6,0,5558406
|
||||
1778270268.860485,1.0025062656641603,36511820491,0,0,24939377,34933645783,6,0,5558406
|
||||
1778270269.363494,1.2499999999999956,36511820551,0,0,24939378,34933645825,6,0,5558407
|
||||
1778270269.8665473,1.2499999999999956,36511820551,0,0,24939378,34933645825,6,0,5558407
|
||||
1778270270.3696206,1.2468827930174564,36511820611,0,0,24939379,34933645867,6,0,5558408
|
||||
1778270270.8725848,1.253132832080206,36511820611,0,0,24939379,34933645867,6,0,5558408
|
||||
1778270271.3758974,1.2468827930174564,36511820671,0,0,24939380,34933645909,6,0,5558409
|
||||
1778270271.8790588,1.2499999999999956,36511820671,0,0,24939380,34933645909,6,0,5558409
|
||||
1778270272.3820553,1.2499999999999956,36511820731,0,0,24939381,34933645951,6,0,5558410
|
||||
1778270272.8855135,1.2468827930174564,36511820731,0,0,24939381,34933645951,6,0,5558410
|
||||
1778270273.388522,1.0025062656641603,36511820791,0,0,24939382,34933645993,6,0,5558411
|
||||
1778270273.891554,1.0025062656641603,36511820791,0,0,24939382,34933645993,6,0,5558411
|
||||
1778270274.3951657,1.4925373134328401,36511820851,0,0,24939383,34933646035,6,0,5558412
|
||||
1778270274.8982785,1.5000000000000013,36511820851,0,0,24939383,34933646035,6,0,5558412
|
||||
1778270275.4012313,1.2499999999999956,36511820911,0,0,24939384,34933646077,6,0,5558413
|
||||
1778270275.9043174,1.0025062656641603,36511820911,0,0,24939384,34933646077,6,0,5558413
|
||||
1778270276.4073832,1.2468827930174564,36511820971,0,0,24939385,34933646119,6,0,5558414
|
||||
1778270276.9104052,1.5000000000000013,36511820971,0,0,24939385,34933646119,6,0,5558414
|
||||
1778270277.4139507,1.2468827930174564,36511821031,0,0,24939386,34933646161,6,0,5558415
|
||||
1778270277.9169807,1.2499999999999956,36511821031,0,0,24939386,34933646161,6,0,5558415
|
||||
1778270278.4199595,1.2499999999999956,36511821091,0,0,24939387,34933646203,6,0,5558416
|
||||
1778270278.9229867,1.2499999999999956,36511821091,0,0,24939387,34933646203,6,0,5558416
|
||||
1778270279.426079,1.0025062656641603,36511821151,0,0,24939388,34933646245,6,0,5558417
|
||||
1778270279.929159,1.2468827930174564,36511821151,0,0,24939388,34933646245,6,0,5558417
|
||||
1778270280.432267,1.5075376884422065,36511821211,0,0,24939389,34933646287,6,0,5558418
|
||||
1778270280.9352372,1.741293532338306,36511821211,0,0,24939389,34933646287,6,0,5558418
|
||||
1778270281.4383302,1.2499999999999956,36511821271,0,0,24939390,34933646329,6,0,5558419
|
||||
1778270281.94146,1.0025062656641603,36511821271,0,0,24939390,34933646329,6,0,5558419
|
||||
1778270282.4445436,1.4962593516209433,36511821331,0,0,24939391,34933646371,6,0,5558420
|
||||
1778270282.9474952,0.7537688442211032,36511821331,0,0,24939391,34933646371,6,0,5558420
|
||||
1778270283.4505324,1.4962593516209433,36511821391,0,0,24939392,34933646413,6,0,5558421
|
||||
1778270283.9536169,1.0025062656641603,36511821391,0,0,24939392,34933646413,6,0,5558421
|
||||
1778270284.456588,1.2499999999999956,36511821451,0,0,24939393,34933646455,6,0,5558422
|
||||
1778270284.9596806,1.2468827930174564,36511821451,0,0,24939393,34933646455,6,0,5558422
|
||||
1778270285.4628205,1.2499999999999956,36511821511,0,0,24939394,34933646497,6,0,5558423
|
||||
1778270285.9659252,1.0025062656641603,36511821511,0,0,24939394,34933646497,6,0,5558423
|
||||
1778270286.469044,1.2499999999999956,36511821571,0,0,24939395,34933646539,6,0,5558424
|
||||
1778270286.9721816,1.2499999999999956,36511821571,0,0,24939395,34933646539,6,0,5558424
|
||||
1778270287.47529,1.2499999999999956,36511821631,0,0,24939396,34933646581,6,0,5558425
|
||||
1778270287.9782617,1.2499999999999956,36511821631,0,0,24939396,34933646581,6,0,5558425
|
||||
1778270288.4813213,1.2499999999999956,36511821691,0,0,24939397,34933646623,6,0,5558426
|
||||
1778270288.984365,1.2499999999999956,36511821691,0,0,24939397,34933646623,6,0,5558426
|
||||
1778270289.4873116,1.2499999999999956,36511821751,0,0,24939398,34933646665,6,0,5558427
|
||||
1778270289.9903169,1.2468827930174564,36511821751,0,0,24939398,34933646665,6,0,5558427
|
||||
1778270290.49336,1.749999999999996,36511821811,0,0,24939399,34933646707,6,0,5558428
|
||||
1778270290.9964695,1.0025062656641603,36511821811,0,0,24939399,34933646707,6,0,5558428
|
||||
1778270291.4995499,1.2499999999999956,36511821871,0,0,24939400,34933646749,6,0,5558429
|
||||
1778270292.0025027,1.2499999999999956,36511821871,0,0,24939400,34933646749,6,0,5558429
|
||||
1778270292.5055432,1.4962593516209433,36511821931,0,0,24939401,34933646791,6,0,5558430
|
||||
1778270293.0086646,1.2499999999999956,36511821931,0,0,24939401,34933646791,6,0,5558430
|
||||
1778270293.5116274,1.5000000000000013,36511821991,0,0,24939402,34933646833,6,0,5558431
|
||||
1778270294.0145802,1.2499999999999956,36511821991,0,0,24939402,34933646833,6,0,5558431
|
||||
1778270294.517666,1.0025062656641603,36511822051,0,0,24939403,34933646875,6,0,5558432
|
||||
1778270295.0206237,1.2499999999999956,36511822051,0,0,24939403,34933646875,6,0,5558432
|
||||
1778270295.5236125,1.4962593516209433,36511822111,0,0,24939404,34933646917,6,0,5558433
|
||||
1778270296.0266464,1.2499999999999956,36511822111,0,0,24939404,34933646917,6,0,5558433
|
||||
1778270296.5298243,1.2499999999999956,36511822171,0,0,24939405,34933646959,6,0,5558434
|
||||
1778270297.0329738,1.2499999999999956,36511822171,0,0,24939405,34933646959,6,0,5558434
|
||||
1778270297.5360053,1.2499999999999956,36511822231,0,0,24939406,34933647001,6,0,5558435
|
||||
1778270298.0391011,1.0025062656641603,36511822231,0,0,24939406,34933647001,6,0,5558435
|
||||
1778270298.542101,1.5000000000000013,36511822291,0,0,24939407,34933647043,6,0,5558436
|
||||
1778270299.0452275,1.0000000000000009,36511822291,0,0,24939407,34933647043,6,0,5558436
|
||||
1778270299.548189,1.741293532338306,36511822351,0,0,24939408,34933647085,6,0,5558437
|
||||
1778270300.0515664,1.005025125628145,36511822351,0,0,24939408,34933647085,6,0,5558437
|
||||
1778270300.5545945,1.0025062656641603,36511822411,0,0,24939409,34933647127,6,0,5558438
|
||||
1778270301.0578985,1.0000000000000009,36511822411,0,0,24939409,34933647127,6,0,5558438
|
||||
1778270301.5608187,1.0025062656641603,36511822471,0,0,24939410,34933647169,6,0,5558439
|
||||
1778270302.0637956,1.2499999999999956,36511822471,0,0,24939410,34933647169,6,0,5558439
|
||||
1778270302.5670989,1.2499999999999956,36511822531,0,0,24939411,34933647211,6,0,5558440
|
||||
1778270303.070127,1.7543859649122862,36511822531,0,0,24939411,34933647211,6,0,5558440
|
||||
1778270303.573153,1.2499999999999956,36511822591,0,0,24939412,34933647253,6,0,5558441
|
||||
1778270304.07614,1.2499999999999956,36511822591,0,0,24939412,34933647253,6,0,5558441
|
||||
1778270304.5792048,1.253132832080206,36511822651,0,0,24939413,34933647295,6,0,5558442
|
||||
1778270305.0822303,0.7537688442211032,36511822651,0,0,24939413,34933647295,6,0,5558442
|
||||
1778270305.5853286,1.2499999999999956,36511822711,0,0,24939414,34933647337,6,0,5558443
|
||||
1778270306.0883648,1.2499999999999956,36511822711,0,0,24939414,34933647337,6,0,5558443
|
||||
1778270306.5914037,1.005025125628145,36511822771,0,0,24939415,34933647379,6,0,5558444
|
||||
1778270307.0943704,1.0025062656641603,36511822771,0,0,24939415,34933647379,6,0,5558444
|
||||
1778270307.597478,0.7537688442211032,36511822831,0,0,24939416,34933647421,6,0,5558445
|
||||
1778270308.1005352,1.0025062656641603,36511822831,0,0,24939416,34933647421,6,0,5558445
|
||||
1778270308.6035342,1.995012468827928,36511822891,0,0,24939417,34933647463,6,0,5558446
|
||||
1778270309.106413,0.7537688442211032,36511822891,0,0,24939417,34933647463,6,0,5558446
|
||||
1778270309.609511,0.7537688442211032,36511822951,0,0,24939418,34933647505,6,0,5558447
|
||||
1778270310.1125262,2.506265664160401,36511822951,0,0,24939418,34933647505,6,0,5558447
|
||||
1778270310.615511,1.005025125628145,36511823011,0,0,24939419,34933647547,6,0,5558448
|
||||
1778270311.11854,1.0025062656641603,36511823011,0,0,24939419,34933647547,6,0,5558448
|
||||
1778270311.6215909,5.974025974025976,36511823071,0,0,24939420,34933647589,6,0,5558449
|
||||
1778270312.1246872,10.91370558375635,36511823071,0,0,24939420,34933647589,6,0,5558449
|
||||
1778270312.6277146,12.5,36511823131,0,0,24939421,34933647631,6,0,5558450
|
||||
1778270313.1307282,1.7632241813602012,36511823131,0,0,24939421,34933647631,6,0,5558450
|
||||
1778270313.6338098,0.7537688442211032,36511823191,0,0,24939422,34933647673,6,0,5558451
|
||||
1778270314.1380684,7.57575757575758,36511823191,0,0,24939422,34933647673,6,0,5558451
|
||||
1778270314.6429842,6.091370558375631,36511823251,0,0,24939423,34933647715,6,0,5558452
|
||||
1778270315.1462681,1.253132832080206,36511823251,0,0,24939423,34933647715,6,0,5558452
|
||||
1778270315.6492803,0.7556675062972307,36511823311,0,0,24939424,34933647757,6,0,5558453
|
||||
1778270316.1523073,0.5037783375314908,36511823311,0,0,24939424,34933647757,6,0,5558453
|
||||
1778270316.6555123,10.606060606060607,36511823371,0,0,24939425,34933647799,6,0,5558454
|
||||
1778270317.1589756,11.195928753180661,36511823371,0,0,24939425,34933647799,6,0,5558454
|
||||
1778270317.6619165,1.2594458438287104,36511823431,0,0,24939426,34933647841,6,0,5558455
|
||||
1778270318.1647773,0.5050505050505083,36511823431,0,0,24939426,34933647841,6,0,5558455
|
||||
1778270318.6677492,0.5050505050505083,36511823491,0,0,24939427,34933647883,6,0,5558456
|
||||
1778270319.17088,0.5025125628140725,36511823491,0,0,24939427,34933647883,6,0,5558456
|
||||
1778270319.6737635,0.5050505050505083,36511823551,0,0,24939428,34933647925,6,0,5558457
|
||||
1778270320.1766603,0.7537688442211032,36511823551,0,0,24939428,34933647925,6,0,5558457
|
||||
1778270320.6795382,1.005025125628145,36511823611,0,0,24939429,34933647967,6,0,5558458
|
||||
1778270321.1824522,0.7556675062972307,36511823671,0,0,24939430,34933648009,6,0,5558459
|
||||
1778270321.68539,0.5025125628140725,36511823671,0,0,24939430,34933648009,6,0,5558459
|
||||
1778270322.188361,0.5037783375314908,36511823731,0,0,24939431,34933648051,6,0,5558460
|
||||
1778270322.691336,0.5037783375314908,36511823731,0,0,24939431,34933648051,6,0,5558460
|
||||
1778270323.1943004,0.7537688442211032,36511823791,0,0,24939432,34933648093,6,0,5558461
|
||||
1778270323.6972399,0.2525252525252486,36511823791,0,0,24939432,34933648093,6,0,5558461
|
||||
1778270324.2001712,0.7537688442211032,36511823851,0,0,24939433,34933648135,6,0,5558462
|
||||
1778270324.7032042,0.5037783375314908,36511823851,0,0,24939433,34933648135,6,0,5558462
|
||||
1778270325.2060804,0.7537688442211032,36511823911,0,0,24939434,34933648177,6,0,5558463
|
||||
1778270325.7090976,0.7537688442211032,36511823911,0,0,24939434,34933648177,6,0,5558463
|
||||
1778270326.2120802,0.5037783375314908,36511823971,0,0,24939435,34933648219,6,0,5558464
|
||||
1778270326.7150471,0.7537688442211032,36511823971,0,0,24939435,34933648219,6,0,5558464
|
||||
1778270327.2180643,0.7537688442211032,36511824031,0,0,24939436,34933648261,6,0,5558465
|
||||
1778270327.721136,1.0000000000000009,36511824031,0,0,24939436,34933648261,6,0,5558465
|
||||
1778270328.2240272,0.7556675062972307,36511824091,0,0,24939437,34933648303,6,0,5558466
|
||||
1778270328.727058,0.7518796992481258,36511824091,0,0,24939437,34933648303,6,0,5558466
|
||||
1778270329.2301168,1.0025062656641603,36511824151,0,0,24939438,34933648345,6,0,5558467
|
||||
1778270329.7331533,0.7537688442211032,36511824151,0,0,24939438,34933648345,6,0,5558467
|
||||
1778270330.23604,1.2499999999999956,36511824211,0,0,24939439,34933648387,6,0,5558468
|
||||
1778270330.7389503,1.2499999999999956,36511824211,0,0,24939439,34933648387,6,0,5558468
|
||||
1778270331.241756,1.2499999999999956,36511824271,0,0,24939440,34933648429,6,0,5558469
|
||||
1778270331.7446892,1.2499999999999956,36511824271,0,0,24939440,34933648429,6,0,5558469
|
||||
1778270332.2476368,1.2499999999999956,36511824331,0,0,24939441,34933648471,6,0,5558470
|
||||
1778270332.7505891,1.4962593516209433,36511824331,0,0,24939441,34933648471,6,0,5558470
|
||||
1778270333.2534916,1.0025062656641603,36511824391,0,0,24939442,34933648513,6,0,5558471
|
||||
1778270333.7564404,1.741293532338306,36511824391,0,0,24939442,34933648513,6,0,5558471
|
||||
1778270334.2594457,1.2499999999999956,36511824451,0,0,24939443,34933648555,6,0,5558472
|
||||
1778270334.762405,1.4962593516209433,36511824451,0,0,24939443,34933648555,6,0,5558472
|
||||
1778270335.2653015,1.4962593516209433,36511824511,0,0,24939444,34933648597,6,0,5558473
|
||||
1778270335.7682714,1.2499999999999956,36511824511,0,0,24939444,34933648597,6,0,5558473
|
||||
1778270336.2711442,1.741293532338306,36511824571,0,0,24939445,34933648639,6,0,5558474
|
||||
1778270336.7740483,1.5000000000000013,36511824571,0,0,24939445,34933648639,6,0,5558474
|
||||
1778270337.2770793,1.4925373134328401,36511824631,0,0,24939446,34933648681,6,0,5558475
|
||||
1778270337.7799752,1.4962593516209433,36511824631,0,0,24939446,34933648681,6,0,5558475
|
||||
|
108
measurments/20260508-215553-bridge-new/arping.txt
Normal file
@@ -0,0 +1,108 @@
|
||||
$ arping -I enp1s0 -c 100 10.11.11.2
|
||||
|
||||
STDOUT
|
||||
ARPING 10.11.11.2 from 10.11.11.3 enp1s0
|
||||
Unicast reply from 10.11.11.2 [18:60:24:E1:47:4A] 2.689ms
|
||||
Unicast reply from 10.11.11.2 [18:60:24:E1:47:4A] 2.794ms
|
||||
Unicast reply from 10.11.11.2 [18:60:24:E1:47:4A] 2.726ms
|
||||
Unicast reply from 10.11.11.2 [18:60:24:E1:47:4A] 2.797ms
|
||||
Unicast reply from 10.11.11.2 [18:60:24:E1:47:4A] 2.822ms
|
||||
Unicast reply from 10.11.11.2 [18:60:24:E1:47:4A] 2.844ms
|
||||
Unicast reply from 10.11.11.2 [18:60:24:E1:47:4A] 2.794ms
|
||||
Unicast reply from 10.11.11.2 [18:60:24:E1:47:4A] 2.757ms
|
||||
Unicast reply from 10.11.11.2 [18:60:24:E1:47:4A] 2.777ms
|
||||
Unicast reply from 10.11.11.2 [18:60:24:E1:47:4A] 2.578ms
|
||||
Unicast reply from 10.11.11.2 [18:60:24:E1:47:4A] 2.821ms
|
||||
Unicast reply from 10.11.11.2 [18:60:24:E1:47:4A] 2.819ms
|
||||
Unicast reply from 10.11.11.2 [18:60:24:E1:47:4A] 2.792ms
|
||||
Unicast reply from 10.11.11.2 [18:60:24:E1:47:4A] 2.903ms
|
||||
Unicast reply from 10.11.11.2 [18:60:24:E1:47:4A] 2.745ms
|
||||
Unicast reply from 10.11.11.2 [18:60:24:E1:47:4A] 2.684ms
|
||||
Unicast reply from 10.11.11.2 [18:60:24:E1:47:4A] 2.763ms
|
||||
Unicast reply from 10.11.11.2 [18:60:24:E1:47:4A] 2.829ms
|
||||
Unicast reply from 10.11.11.2 [18:60:24:E1:47:4A] 2.826ms
|
||||
Unicast reply from 10.11.11.2 [18:60:24:E1:47:4A] 2.830ms
|
||||
Unicast reply from 10.11.11.2 [18:60:24:E1:47:4A] 2.779ms
|
||||
Unicast reply from 10.11.11.2 [18:60:24:E1:47:4A] 2.851ms
|
||||
Unicast reply from 10.11.11.2 [18:60:24:E1:47:4A] 2.790ms
|
||||
Unicast reply from 10.11.11.2 [18:60:24:E1:47:4A] 2.791ms
|
||||
Unicast reply from 10.11.11.2 [18:60:24:E1:47:4A] 2.488ms
|
||||
Unicast reply from 10.11.11.2 [18:60:24:E1:47:4A] 2.791ms
|
||||
Unicast reply from 10.11.11.2 [18:60:24:E1:47:4A] 2.788ms
|
||||
Unicast reply from 10.11.11.2 [18:60:24:E1:47:4A] 1.364ms
|
||||
Unicast reply from 10.11.11.2 [18:60:24:E1:47:4A] 1.616ms
|
||||
Unicast reply from 10.11.11.2 [18:60:24:E1:47:4A] 2.840ms
|
||||
Unicast reply from 10.11.11.2 [18:60:24:E1:47:4A] 2.797ms
|
||||
Unicast reply from 10.11.11.2 [18:60:24:E1:47:4A] 2.795ms
|
||||
Unicast reply from 10.11.11.2 [18:60:24:E1:47:4A] 2.783ms
|
||||
Unicast reply from 10.11.11.2 [18:60:24:E1:47:4A] 2.740ms
|
||||
Unicast reply from 10.11.11.2 [18:60:24:E1:47:4A] 2.800ms
|
||||
Unicast reply from 10.11.11.2 [18:60:24:E1:47:4A] 2.801ms
|
||||
Unicast reply from 10.11.11.2 [18:60:24:E1:47:4A] 2.744ms
|
||||
Unicast reply from 10.11.11.2 [18:60:24:E1:47:4A] 2.363ms
|
||||
Unicast reply from 10.11.11.2 [18:60:24:E1:47:4A] 2.811ms
|
||||
Unicast reply from 10.11.11.2 [18:60:24:E1:47:4A] 2.798ms
|
||||
Unicast reply from 10.11.11.2 [18:60:24:E1:47:4A] 2.686ms
|
||||
Unicast reply from 10.11.11.2 [18:60:24:E1:47:4A] 2.759ms
|
||||
Unicast reply from 10.11.11.2 [18:60:24:E1:47:4A] 2.753ms
|
||||
Unicast reply from 10.11.11.2 [18:60:24:E1:47:4A] 2.789ms
|
||||
Unicast reply from 10.11.11.2 [18:60:24:E1:47:4A] 2.805ms
|
||||
Unicast reply from 10.11.11.2 [18:60:24:E1:47:4A] 2.778ms
|
||||
Unicast reply from 10.11.11.2 [18:60:24:E1:47:4A] 2.795ms
|
||||
Unicast reply from 10.11.11.2 [18:60:24:E1:47:4A] 2.874ms
|
||||
Unicast reply from 10.11.11.2 [18:60:24:E1:47:4A] 2.717ms
|
||||
Unicast reply from 10.11.11.2 [18:60:24:E1:47:4A] 2.735ms
|
||||
Unicast reply from 10.11.11.2 [18:60:24:E1:47:4A] 2.818ms
|
||||
Unicast reply from 10.11.11.2 [18:60:24:E1:47:4A] 2.828ms
|
||||
Unicast reply from 10.11.11.2 [18:60:24:E1:47:4A] 2.808ms
|
||||
Unicast reply from 10.11.11.2 [18:60:24:E1:47:4A] 2.798ms
|
||||
Unicast reply from 10.11.11.2 [18:60:24:E1:47:4A] 2.710ms
|
||||
Unicast reply from 10.11.11.2 [18:60:24:E1:47:4A] 2.802ms
|
||||
Unicast reply from 10.11.11.2 [18:60:24:E1:47:4A] 2.540ms
|
||||
Unicast reply from 10.11.11.2 [18:60:24:E1:47:4A] 2.855ms
|
||||
Unicast reply from 10.11.11.2 [18:60:24:E1:47:4A] 2.789ms
|
||||
Unicast reply from 10.11.11.2 [18:60:24:E1:47:4A] 2.838ms
|
||||
Unicast reply from 10.11.11.2 [18:60:24:E1:47:4A] 2.920ms
|
||||
Unicast reply from 10.11.11.2 [18:60:24:E1:47:4A] 2.819ms
|
||||
Unicast reply from 10.11.11.2 [18:60:24:E1:47:4A] 2.743ms
|
||||
Unicast reply from 10.11.11.2 [18:60:24:E1:47:4A] 2.701ms
|
||||
Unicast reply from 10.11.11.2 [18:60:24:E1:47:4A] 2.784ms
|
||||
Unicast reply from 10.11.11.2 [18:60:24:E1:47:4A] 2.802ms
|
||||
Unicast reply from 10.11.11.2 [18:60:24:E1:47:4A] 2.777ms
|
||||
Unicast reply from 10.11.11.2 [18:60:24:E1:47:4A] 2.756ms
|
||||
Unicast reply from 10.11.11.2 [18:60:24:E1:47:4A] 2.919ms
|
||||
Unicast reply from 10.11.11.2 [18:60:24:E1:47:4A] 2.760ms
|
||||
Unicast reply from 10.11.11.2 [18:60:24:E1:47:4A] 2.807ms
|
||||
Unicast reply from 10.11.11.2 [18:60:24:E1:47:4A] 2.769ms
|
||||
Unicast reply from 10.11.11.2 [18:60:24:E1:47:4A] 2.781ms
|
||||
Unicast reply from 10.11.11.2 [18:60:24:E1:47:4A] 2.754ms
|
||||
Unicast reply from 10.11.11.2 [18:60:24:E1:47:4A] 2.742ms
|
||||
Unicast reply from 10.11.11.2 [18:60:24:E1:47:4A] 2.771ms
|
||||
Unicast reply from 10.11.11.2 [18:60:24:E1:47:4A] 2.776ms
|
||||
Unicast reply from 10.11.11.2 [18:60:24:E1:47:4A] 2.796ms
|
||||
Unicast reply from 10.11.11.2 [18:60:24:E1:47:4A] 2.963ms
|
||||
Unicast reply from 10.11.11.2 [18:60:24:E1:47:4A] 2.773ms
|
||||
Unicast reply from 10.11.11.2 [18:60:24:E1:47:4A] 2.904ms
|
||||
Unicast reply from 10.11.11.2 [18:60:24:E1:47:4A] 2.789ms
|
||||
Unicast reply from 10.11.11.2 [18:60:24:E1:47:4A] 2.836ms
|
||||
Unicast reply from 10.11.11.2 [18:60:24:E1:47:4A] 2.784ms
|
||||
Unicast reply from 10.11.11.2 [18:60:24:E1:47:4A] 2.775ms
|
||||
Unicast reply from 10.11.11.2 [18:60:24:E1:47:4A] 2.807ms
|
||||
Unicast reply from 10.11.11.2 [18:60:24:E1:47:4A] 2.954ms
|
||||
Unicast reply from 10.11.11.2 [18:60:24:E1:47:4A] 2.784ms
|
||||
Unicast reply from 10.11.11.2 [18:60:24:E1:47:4A] 2.911ms
|
||||
Unicast reply from 10.11.11.2 [18:60:24:E1:47:4A] 2.832ms
|
||||
Unicast reply from 10.11.11.2 [18:60:24:E1:47:4A] 2.923ms
|
||||
Unicast reply from 10.11.11.2 [18:60:24:E1:47:4A] 2.798ms
|
||||
Unicast reply from 10.11.11.2 [18:60:24:E1:47:4A] 2.213ms
|
||||
Unicast reply from 10.11.11.2 [18:60:24:E1:47:4A] 2.859ms
|
||||
Unicast reply from 10.11.11.2 [18:60:24:E1:47:4A] 2.748ms
|
||||
Unicast reply from 10.11.11.2 [18:60:24:E1:47:4A] 2.754ms
|
||||
Unicast reply from 10.11.11.2 [18:60:24:E1:47:4A] 2.921ms
|
||||
Unicast reply from 10.11.11.2 [18:60:24:E1:47:4A] 2.855ms
|
||||
Unicast reply from 10.11.11.2 [18:60:24:E1:47:4A] 2.809ms
|
||||
Unicast reply from 10.11.11.2 [18:60:24:E1:47:4A] 2.834ms
|
||||
Sent 100 probes (1 broadcast(s))
|
||||
Received 100 response(s)
|
||||
|
||||
STDERR
|
||||
@@ -0,0 +1,33 @@
|
||||
{
|
||||
"command": [
|
||||
"ethtool",
|
||||
"enp1s0"
|
||||
],
|
||||
"returncode": 0,
|
||||
"timed_out": false,
|
||||
"error": null,
|
||||
"start_time": "2026-05-08T19:55:53.039103+00:00",
|
||||
"duration_seconds": 0.0016709730002730794,
|
||||
"interface_counters_before": {},
|
||||
"interface_counters_after": {},
|
||||
"interface_counters_delta": {},
|
||||
"system": {
|
||||
"sample_count": 0,
|
||||
"cpu_percent": {
|
||||
"count": 0,
|
||||
"min": null,
|
||||
"max": null,
|
||||
"mean": null,
|
||||
"median": null,
|
||||
"stdev": null,
|
||||
"mad": null,
|
||||
"iqr": null,
|
||||
"cv_percent": null,
|
||||
"p90": null,
|
||||
"p95": null,
|
||||
"p99": null
|
||||
}
|
||||
},
|
||||
"raw_output": "/home/ubuntu/Desktop/mitm-webserver/tools/measurements/20260508-215553-bridge-new/environment/env_ethtool_iface.txt",
|
||||
"system_samples_csv": "/home/ubuntu/Desktop/mitm-webserver/tools/measurements/20260508-215553-bridge-new/environment/env_ethtool_iface.system_samples.csv"
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
timestamp,cpu_percent
|
||||
|
@@ -0,0 +1,36 @@
|
||||
$ ethtool enp1s0
|
||||
|
||||
STDOUT
|
||||
Settings for enp1s0:
|
||||
Supported ports: [ TP MII ]
|
||||
Supported link modes: 10baseT/Half 10baseT/Full
|
||||
100baseT/Half 100baseT/Full
|
||||
1000baseT/Full
|
||||
Supported pause frame use: Symmetric Receive-only
|
||||
Supports auto-negotiation: Yes
|
||||
Supported FEC modes: Not reported
|
||||
Advertised link modes: 10baseT/Half 10baseT/Full
|
||||
100baseT/Half 100baseT/Full
|
||||
1000baseT/Full
|
||||
Advertised pause frame use: Symmetric Receive-only
|
||||
Advertised auto-negotiation: Yes
|
||||
Advertised FEC modes: Not reported
|
||||
Link partner advertised link modes: 10baseT/Half 10baseT/Full
|
||||
100baseT/Half 100baseT/Full
|
||||
1000baseT/Full
|
||||
Link partner advertised pause frame use: Symmetric Receive-only
|
||||
Link partner advertised auto-negotiation: Yes
|
||||
Link partner advertised FEC modes: Not reported
|
||||
Speed: 1000Mb/s
|
||||
Duplex: Full
|
||||
Auto-negotiation: on
|
||||
master-slave cfg: preferred slave
|
||||
master-slave status: slave
|
||||
Port: Twisted Pair
|
||||
PHYAD: 0
|
||||
Transceiver: external
|
||||
MDI-X: Unknown
|
||||
Link detected: yes
|
||||
|
||||
STDERR
|
||||
netlink error: Operation not permitted
|
||||
@@ -0,0 +1,34 @@
|
||||
{
|
||||
"command": [
|
||||
"ethtool",
|
||||
"-k",
|
||||
"enp1s0"
|
||||
],
|
||||
"returncode": 0,
|
||||
"timed_out": false,
|
||||
"error": null,
|
||||
"start_time": "2026-05-08T19:55:53.041214+00:00",
|
||||
"duration_seconds": 0.0015542820001428481,
|
||||
"interface_counters_before": {},
|
||||
"interface_counters_after": {},
|
||||
"interface_counters_delta": {},
|
||||
"system": {
|
||||
"sample_count": 0,
|
||||
"cpu_percent": {
|
||||
"count": 0,
|
||||
"min": null,
|
||||
"max": null,
|
||||
"mean": null,
|
||||
"median": null,
|
||||
"stdev": null,
|
||||
"mad": null,
|
||||
"iqr": null,
|
||||
"cv_percent": null,
|
||||
"p90": null,
|
||||
"p95": null,
|
||||
"p99": null
|
||||
}
|
||||
},
|
||||
"raw_output": "/home/ubuntu/Desktop/mitm-webserver/tools/measurements/20260508-215553-bridge-new/environment/env_ethtool_offloads_iface.txt",
|
||||
"system_samples_csv": "/home/ubuntu/Desktop/mitm-webserver/tools/measurements/20260508-215553-bridge-new/environment/env_ethtool_offloads_iface.system_samples.csv"
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
timestamp,cpu_percent
|
||||
|
@@ -0,0 +1,69 @@
|
||||
$ ethtool -k enp1s0
|
||||
|
||||
STDOUT
|
||||
Features for enp1s0:
|
||||
rx-checksumming: on
|
||||
tx-checksumming: on
|
||||
tx-checksum-ipv4: on
|
||||
tx-checksum-ip-generic: off [fixed]
|
||||
tx-checksum-ipv6: on
|
||||
tx-checksum-fcoe-crc: off [fixed]
|
||||
tx-checksum-sctp: off [fixed]
|
||||
scatter-gather: on
|
||||
tx-scatter-gather: on
|
||||
tx-scatter-gather-fraglist: off [fixed]
|
||||
tcp-segmentation-offload: on
|
||||
tx-tcp-segmentation: on
|
||||
tx-tcp-ecn-segmentation: off [fixed]
|
||||
tx-tcp-mangleid-segmentation: off
|
||||
tx-tcp6-segmentation: on
|
||||
tx-tcp-accecn-segmentation: off [fixed]
|
||||
generic-segmentation-offload: on
|
||||
generic-receive-offload: on
|
||||
large-receive-offload: off [fixed]
|
||||
rx-vlan-offload: on
|
||||
tx-vlan-offload: on
|
||||
ntuple-filters: off [fixed]
|
||||
receive-hashing: off [fixed]
|
||||
highdma: on [fixed]
|
||||
rx-vlan-filter: off [fixed]
|
||||
vlan-challenged: off [fixed]
|
||||
tx-gso-robust: off [fixed]
|
||||
tx-fcoe-segmentation: off [fixed]
|
||||
tx-gre-segmentation: off [fixed]
|
||||
tx-gre-csum-segmentation: off [fixed]
|
||||
tx-ipxip4-segmentation: off [fixed]
|
||||
tx-ipxip6-segmentation: off [fixed]
|
||||
tx-udp_tnl-segmentation: off [fixed]
|
||||
tx-udp_tnl-csum-segmentation: off [fixed]
|
||||
tx-gso-partial: off [fixed]
|
||||
tx-tunnel-remcsum-segmentation: off [fixed]
|
||||
tx-sctp-segmentation: off [fixed]
|
||||
tx-esp-segmentation: off [fixed]
|
||||
tx-udp-segmentation: off [fixed]
|
||||
tx-gso-list: off [fixed]
|
||||
tx-nocache-copy: off
|
||||
loopback: off [fixed]
|
||||
rx-fcs: off
|
||||
rx-all: off
|
||||
tx-vlan-stag-hw-insert: off [fixed]
|
||||
rx-vlan-stag-hw-parse: off [fixed]
|
||||
rx-vlan-stag-filter: off [fixed]
|
||||
l2-fwd-offload: off [fixed]
|
||||
hw-tc-offload: off [fixed]
|
||||
esp-hw-offload: off [fixed]
|
||||
esp-tx-csum-hw-offload: off [fixed]
|
||||
rx-udp_tunnel-port-offload: off [fixed]
|
||||
tls-hw-tx-offload: off [fixed]
|
||||
tls-hw-rx-offload: off [fixed]
|
||||
rx-gro-hw: off [fixed]
|
||||
tls-hw-record: off [fixed]
|
||||
rx-gro-list: off
|
||||
macsec-hw-offload: off [fixed]
|
||||
rx-udp-gro-forwarding: off
|
||||
hsr-tag-ins-offload: off [fixed]
|
||||
hsr-tag-rm-offload: off [fixed]
|
||||
hsr-fwd-offload: off [fixed]
|
||||
hsr-dup-offload: off [fixed]
|
||||
|
||||
STDERR
|
||||
@@ -0,0 +1,34 @@
|
||||
{
|
||||
"command": [
|
||||
"ethtool",
|
||||
"-S",
|
||||
"enp1s0"
|
||||
],
|
||||
"returncode": 0,
|
||||
"timed_out": false,
|
||||
"error": null,
|
||||
"start_time": "2026-05-08T19:55:53.043205+00:00",
|
||||
"duration_seconds": 0.0014122029997452046,
|
||||
"interface_counters_before": {},
|
||||
"interface_counters_after": {},
|
||||
"interface_counters_delta": {},
|
||||
"system": {
|
||||
"sample_count": 0,
|
||||
"cpu_percent": {
|
||||
"count": 0,
|
||||
"min": null,
|
||||
"max": null,
|
||||
"mean": null,
|
||||
"median": null,
|
||||
"stdev": null,
|
||||
"mad": null,
|
||||
"iqr": null,
|
||||
"cv_percent": null,
|
||||
"p90": null,
|
||||
"p95": null,
|
||||
"p99": null
|
||||
}
|
||||
},
|
||||
"raw_output": "/home/ubuntu/Desktop/mitm-webserver/tools/measurements/20260508-215553-bridge-new/environment/env_ethtool_stats_iface.txt",
|
||||
"system_samples_csv": "/home/ubuntu/Desktop/mitm-webserver/tools/measurements/20260508-215553-bridge-new/environment/env_ethtool_stats_iface.system_samples.csv"
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
timestamp,cpu_percent
|
||||
|
@@ -0,0 +1,19 @@
|
||||
$ ethtool -S enp1s0
|
||||
|
||||
STDOUT
|
||||
NIC statistics:
|
||||
tx_packets: 24688327
|
||||
rx_packets: 24924341
|
||||
tx_errors: 0
|
||||
rx_errors: 0
|
||||
rx_missed: 0
|
||||
align_errors: 0
|
||||
tx_single_collisions: 0
|
||||
tx_multi_collisions: 0
|
||||
unicast: 24924317
|
||||
broadcast: 3
|
||||
multicast: 21
|
||||
tx_aborted: 0
|
||||
tx_underrun: 0
|
||||
|
||||
STDERR
|
||||
@@ -0,0 +1,34 @@
|
||||
{
|
||||
"command": [
|
||||
"ip",
|
||||
"addr",
|
||||
"show"
|
||||
],
|
||||
"returncode": 0,
|
||||
"timed_out": false,
|
||||
"error": null,
|
||||
"start_time": "2026-05-08T19:55:53.010104+00:00",
|
||||
"duration_seconds": 0.00286572699997123,
|
||||
"interface_counters_before": {},
|
||||
"interface_counters_after": {},
|
||||
"interface_counters_delta": {},
|
||||
"system": {
|
||||
"sample_count": 0,
|
||||
"cpu_percent": {
|
||||
"count": 0,
|
||||
"min": null,
|
||||
"max": null,
|
||||
"mean": null,
|
||||
"median": null,
|
||||
"stdev": null,
|
||||
"mad": null,
|
||||
"iqr": null,
|
||||
"cv_percent": null,
|
||||
"p90": null,
|
||||
"p95": null,
|
||||
"p99": null
|
||||
}
|
||||
},
|
||||
"raw_output": "/home/ubuntu/Desktop/mitm-webserver/tools/measurements/20260508-215553-bridge-new/environment/env_ip_addr.txt",
|
||||
"system_samples_csv": "/home/ubuntu/Desktop/mitm-webserver/tools/measurements/20260508-215553-bridge-new/environment/env_ip_addr.system_samples.csv"
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
timestamp,cpu_percent
|
||||
|
@@ -0,0 +1,21 @@
|
||||
$ ip addr show
|
||||
|
||||
STDOUT
|
||||
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
|
||||
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
|
||||
inet 127.0.0.1/8 scope host lo
|
||||
valid_lft forever preferred_lft forever
|
||||
inet6 ::1/128 scope host noprefixroute
|
||||
valid_lft forever preferred_lft forever
|
||||
2: enp1s0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
|
||||
link/ether ac:e2:d3:6c:05:0c brd ff:ff:ff:ff:ff:ff
|
||||
inet 10.11.11.3/24 brd 10.11.11.255 scope global noprefixroute enp1s0
|
||||
valid_lft forever preferred_lft forever
|
||||
3: wlp2s0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
|
||||
link/ether 9c:da:3e:a4:e5:11 brd ff:ff:ff:ff:ff:ff
|
||||
inet 192.168.178.42/24 brd 192.168.178.255 scope global dynamic noprefixroute wlp2s0
|
||||
valid_lft 40292sec preferred_lft 40292sec
|
||||
inet6 fe80::5148:fd89:e1fa:d668/64 scope link noprefixroute
|
||||
valid_lft forever preferred_lft forever
|
||||
|
||||
STDERR
|
||||
@@ -0,0 +1,37 @@
|
||||
{
|
||||
"command": [
|
||||
"ip",
|
||||
"-details",
|
||||
"link",
|
||||
"show",
|
||||
"dev",
|
||||
"enp1s0"
|
||||
],
|
||||
"returncode": 0,
|
||||
"timed_out": false,
|
||||
"error": null,
|
||||
"start_time": "2026-05-08T19:55:53.028952+00:00",
|
||||
"duration_seconds": 0.0021718110001529567,
|
||||
"interface_counters_before": {},
|
||||
"interface_counters_after": {},
|
||||
"interface_counters_delta": {},
|
||||
"system": {
|
||||
"sample_count": 0,
|
||||
"cpu_percent": {
|
||||
"count": 0,
|
||||
"min": null,
|
||||
"max": null,
|
||||
"mean": null,
|
||||
"median": null,
|
||||
"stdev": null,
|
||||
"mad": null,
|
||||
"iqr": null,
|
||||
"cv_percent": null,
|
||||
"p90": null,
|
||||
"p95": null,
|
||||
"p99": null
|
||||
}
|
||||
},
|
||||
"raw_output": "/home/ubuntu/Desktop/mitm-webserver/tools/measurements/20260508-215553-bridge-new/environment/env_ip_link_iface.txt",
|
||||
"system_samples_csv": "/home/ubuntu/Desktop/mitm-webserver/tools/measurements/20260508-215553-bridge-new/environment/env_ip_link_iface.system_samples.csv"
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
timestamp,cpu_percent
|
||||
|
@@ -0,0 +1,7 @@
|
||||
$ ip -details link show dev enp1s0
|
||||
|
||||
STDOUT
|
||||
2: enp1s0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP mode DEFAULT group default qlen 1000
|
||||
link/ether ac:e2:d3:6c:05:0c brd ff:ff:ff:ff:ff:ff promiscuity 0 allmulti 0 minmtu 68 maxmtu 9194 addrgenmode none numtxqueues 1 numrxqueues 1 gso_max_size 64000 gso_max_segs 64 tso_max_size 64000 tso_max_segs 64 gro_max_size 65536 parentbus pci parentdev 0000:01:00.0
|
||||
|
||||
STDERR
|
||||
@@ -0,0 +1,34 @@
|
||||
{
|
||||
"command": [
|
||||
"ip",
|
||||
"neigh",
|
||||
"show"
|
||||
],
|
||||
"returncode": 0,
|
||||
"timed_out": false,
|
||||
"error": null,
|
||||
"start_time": "2026-05-08T19:55:53.016144+00:00",
|
||||
"duration_seconds": 0.002227852000032726,
|
||||
"interface_counters_before": {},
|
||||
"interface_counters_after": {},
|
||||
"interface_counters_delta": {},
|
||||
"system": {
|
||||
"sample_count": 0,
|
||||
"cpu_percent": {
|
||||
"count": 0,
|
||||
"min": null,
|
||||
"max": null,
|
||||
"mean": null,
|
||||
"median": null,
|
||||
"stdev": null,
|
||||
"mad": null,
|
||||
"iqr": null,
|
||||
"cv_percent": null,
|
||||
"p90": null,
|
||||
"p95": null,
|
||||
"p99": null
|
||||
}
|
||||
},
|
||||
"raw_output": "/home/ubuntu/Desktop/mitm-webserver/tools/measurements/20260508-215553-bridge-new/environment/env_ip_neigh.txt",
|
||||
"system_samples_csv": "/home/ubuntu/Desktop/mitm-webserver/tools/measurements/20260508-215553-bridge-new/environment/env_ip_neigh.system_samples.csv"
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
timestamp,cpu_percent
|
||||
|
@@ -0,0 +1,8 @@
|
||||
$ ip neigh show
|
||||
|
||||
STDOUT
|
||||
192.168.178.138 dev wlp2s0 lladdr d8:bb:c1:16:f3:7b REACHABLE
|
||||
10.11.11.2 dev enp1s0 lladdr 18:60:24:e1:47:4a STALE
|
||||
192.168.178.1 dev wlp2s0 lladdr 94:83:c4:a3:bc:ea REACHABLE
|
||||
|
||||
STDERR
|
||||
@@ -0,0 +1,36 @@
|
||||
{
|
||||
"command": [
|
||||
"ip",
|
||||
"route",
|
||||
"show",
|
||||
"table",
|
||||
"all"
|
||||
],
|
||||
"returncode": 0,
|
||||
"timed_out": false,
|
||||
"error": null,
|
||||
"start_time": "2026-05-08T19:55:53.013452+00:00",
|
||||
"duration_seconds": 0.0021849139998266764,
|
||||
"interface_counters_before": {},
|
||||
"interface_counters_after": {},
|
||||
"interface_counters_delta": {},
|
||||
"system": {
|
||||
"sample_count": 0,
|
||||
"cpu_percent": {
|
||||
"count": 0,
|
||||
"min": null,
|
||||
"max": null,
|
||||
"mean": null,
|
||||
"median": null,
|
||||
"stdev": null,
|
||||
"mad": null,
|
||||
"iqr": null,
|
||||
"cv_percent": null,
|
||||
"p90": null,
|
||||
"p95": null,
|
||||
"p99": null
|
||||
}
|
||||
},
|
||||
"raw_output": "/home/ubuntu/Desktop/mitm-webserver/tools/measurements/20260508-215553-bridge-new/environment/env_ip_route.txt",
|
||||
"system_samples_csv": "/home/ubuntu/Desktop/mitm-webserver/tools/measurements/20260508-215553-bridge-new/environment/env_ip_route.system_samples.csv"
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
timestamp,cpu_percent
|
||||
|
@@ -0,0 +1,19 @@
|
||||
$ ip route show table all
|
||||
|
||||
STDOUT
|
||||
default via 192.168.178.1 dev wlp2s0 proto dhcp src 192.168.178.42 metric 600
|
||||
10.11.11.0/24 dev enp1s0 proto kernel scope link src 10.11.11.3 metric 100
|
||||
192.168.178.0/24 dev wlp2s0 proto kernel scope link src 192.168.178.42 metric 600
|
||||
local 10.11.11.3 dev enp1s0 table local proto kernel scope host src 10.11.11.3
|
||||
broadcast 10.11.11.255 dev enp1s0 table local proto kernel scope link src 10.11.11.3
|
||||
local 127.0.0.0/8 dev lo table local proto kernel scope host src 127.0.0.1
|
||||
local 127.0.0.1 dev lo table local proto kernel scope host src 127.0.0.1
|
||||
broadcast 127.255.255.255 dev lo table local proto kernel scope link src 127.0.0.1
|
||||
local 192.168.178.42 dev wlp2s0 table local proto kernel scope host src 192.168.178.42
|
||||
broadcast 192.168.178.255 dev wlp2s0 table local proto kernel scope link src 192.168.178.42
|
||||
fe80::/64 dev wlp2s0 proto kernel metric 1024 pref medium
|
||||
local ::1 dev lo table local proto kernel metric 0 pref medium
|
||||
local fe80::5148:fd89:e1fa:d668 dev wlp2s0 table local proto kernel metric 0 pref medium
|
||||
multicast ff00::/8 dev wlp2s0 table local proto kernel metric 256 pref medium
|
||||
|
||||
STDERR
|
||||
@@ -0,0 +1,34 @@
|
||||
{
|
||||
"command": [
|
||||
"nft",
|
||||
"list",
|
||||
"ruleset"
|
||||
],
|
||||
"returncode": 1,
|
||||
"timed_out": false,
|
||||
"error": null,
|
||||
"start_time": "2026-05-08T19:55:53.025488+00:00",
|
||||
"duration_seconds": 0.0029797420002068975,
|
||||
"interface_counters_before": {},
|
||||
"interface_counters_after": {},
|
||||
"interface_counters_delta": {},
|
||||
"system": {
|
||||
"sample_count": 0,
|
||||
"cpu_percent": {
|
||||
"count": 0,
|
||||
"min": null,
|
||||
"max": null,
|
||||
"mean": null,
|
||||
"median": null,
|
||||
"stdev": null,
|
||||
"mad": null,
|
||||
"iqr": null,
|
||||
"cv_percent": null,
|
||||
"p90": null,
|
||||
"p95": null,
|
||||
"p99": null
|
||||
}
|
||||
},
|
||||
"raw_output": "/home/ubuntu/Desktop/mitm-webserver/tools/measurements/20260508-215553-bridge-new/environment/env_nft_ruleset.txt",
|
||||
"system_samples_csv": "/home/ubuntu/Desktop/mitm-webserver/tools/measurements/20260508-215553-bridge-new/environment/env_nft_ruleset.system_samples.csv"
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
timestamp,cpu_percent
|
||||
|
@@ -0,0 +1,7 @@
|
||||
$ nft list ruleset
|
||||
|
||||
STDOUT
|
||||
|
||||
STDERR
|
||||
Operation not permitted (you must be root)
|
||||
netlink: Error: cache initialization failed: Operation not permitted
|
||||
@@ -0,0 +1,37 @@
|
||||
{
|
||||
"command": [
|
||||
"tc",
|
||||
"filter",
|
||||
"show",
|
||||
"dev",
|
||||
"enp1s0",
|
||||
"egress"
|
||||
],
|
||||
"returncode": 0,
|
||||
"timed_out": false,
|
||||
"error": null,
|
||||
"start_time": "2026-05-08T19:55:53.036545+00:00",
|
||||
"duration_seconds": 0.0020781439998245332,
|
||||
"interface_counters_before": {},
|
||||
"interface_counters_after": {},
|
||||
"interface_counters_delta": {},
|
||||
"system": {
|
||||
"sample_count": 0,
|
||||
"cpu_percent": {
|
||||
"count": 0,
|
||||
"min": null,
|
||||
"max": null,
|
||||
"mean": null,
|
||||
"median": null,
|
||||
"stdev": null,
|
||||
"mad": null,
|
||||
"iqr": null,
|
||||
"cv_percent": null,
|
||||
"p90": null,
|
||||
"p95": null,
|
||||
"p99": null
|
||||
}
|
||||
},
|
||||
"raw_output": "/home/ubuntu/Desktop/mitm-webserver/tools/measurements/20260508-215553-bridge-new/environment/env_tc_filter_egress_iface.txt",
|
||||
"system_samples_csv": "/home/ubuntu/Desktop/mitm-webserver/tools/measurements/20260508-215553-bridge-new/environment/env_tc_filter_egress_iface.system_samples.csv"
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
timestamp,cpu_percent
|
||||
|
@@ -0,0 +1,5 @@
|
||||
$ tc filter show dev enp1s0 egress
|
||||
|
||||
STDOUT
|
||||
|
||||
STDERR
|
||||
@@ -0,0 +1,37 @@
|
||||
{
|
||||
"command": [
|
||||
"tc",
|
||||
"filter",
|
||||
"show",
|
||||
"dev",
|
||||
"enp1s0",
|
||||
"ingress"
|
||||
],
|
||||
"returncode": 0,
|
||||
"timed_out": false,
|
||||
"error": null,
|
||||
"start_time": "2026-05-08T19:55:53.034081+00:00",
|
||||
"duration_seconds": 0.0020320580001680355,
|
||||
"interface_counters_before": {},
|
||||
"interface_counters_after": {},
|
||||
"interface_counters_delta": {},
|
||||
"system": {
|
||||
"sample_count": 0,
|
||||
"cpu_percent": {
|
||||
"count": 0,
|
||||
"min": null,
|
||||
"max": null,
|
||||
"mean": null,
|
||||
"median": null,
|
||||
"stdev": null,
|
||||
"mad": null,
|
||||
"iqr": null,
|
||||
"cv_percent": null,
|
||||
"p90": null,
|
||||
"p95": null,
|
||||
"p99": null
|
||||
}
|
||||
},
|
||||
"raw_output": "/home/ubuntu/Desktop/mitm-webserver/tools/measurements/20260508-215553-bridge-new/environment/env_tc_filter_ingress_iface.txt",
|
||||
"system_samples_csv": "/home/ubuntu/Desktop/mitm-webserver/tools/measurements/20260508-215553-bridge-new/environment/env_tc_filter_ingress_iface.system_samples.csv"
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
timestamp,cpu_percent
|
||||
|
@@ -0,0 +1,5 @@
|
||||
$ tc filter show dev enp1s0 ingress
|
||||
|
||||
STDOUT
|
||||
|
||||
STDERR
|
||||
@@ -0,0 +1,34 @@
|
||||
{
|
||||
"command": [
|
||||
"tc",
|
||||
"qdisc",
|
||||
"show"
|
||||
],
|
||||
"returncode": 0,
|
||||
"timed_out": false,
|
||||
"error": null,
|
||||
"start_time": "2026-05-08T19:55:53.019007+00:00",
|
||||
"duration_seconds": 0.005839450999701512,
|
||||
"interface_counters_before": {},
|
||||
"interface_counters_after": {},
|
||||
"interface_counters_delta": {},
|
||||
"system": {
|
||||
"sample_count": 0,
|
||||
"cpu_percent": {
|
||||
"count": 0,
|
||||
"min": null,
|
||||
"max": null,
|
||||
"mean": null,
|
||||
"median": null,
|
||||
"stdev": null,
|
||||
"mad": null,
|
||||
"iqr": null,
|
||||
"cv_percent": null,
|
||||
"p90": null,
|
||||
"p95": null,
|
||||
"p99": null
|
||||
}
|
||||
},
|
||||
"raw_output": "/home/ubuntu/Desktop/mitm-webserver/tools/measurements/20260508-215553-bridge-new/environment/env_tc_qdisc.txt",
|
||||
"system_samples_csv": "/home/ubuntu/Desktop/mitm-webserver/tools/measurements/20260508-215553-bridge-new/environment/env_tc_qdisc.system_samples.csv"
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
timestamp,cpu_percent
|
||||
|
@@ -0,0 +1,8 @@
|
||||
$ tc qdisc show
|
||||
|
||||
STDOUT
|
||||
qdisc noqueue 0: dev lo root refcnt 2
|
||||
qdisc fq_codel 0: dev enp1s0 root refcnt 2 limit 10240p flows 1024 quantum 1514 target 5ms interval 100ms memory_limit 32Mb ecn drop_batch 64
|
||||
qdisc noqueue 0: dev wlp2s0 root refcnt 2
|
||||
|
||||
STDERR
|
||||
@@ -0,0 +1,36 @@
|
||||
{
|
||||
"command": [
|
||||
"tc",
|
||||
"qdisc",
|
||||
"show",
|
||||
"dev",
|
||||
"enp1s0"
|
||||
],
|
||||
"returncode": 0,
|
||||
"timed_out": false,
|
||||
"error": null,
|
||||
"start_time": "2026-05-08T19:55:53.031580+00:00",
|
||||
"duration_seconds": 0.002074567999898136,
|
||||
"interface_counters_before": {},
|
||||
"interface_counters_after": {},
|
||||
"interface_counters_delta": {},
|
||||
"system": {
|
||||
"sample_count": 0,
|
||||
"cpu_percent": {
|
||||
"count": 0,
|
||||
"min": null,
|
||||
"max": null,
|
||||
"mean": null,
|
||||
"median": null,
|
||||
"stdev": null,
|
||||
"mad": null,
|
||||
"iqr": null,
|
||||
"cv_percent": null,
|
||||
"p90": null,
|
||||
"p95": null,
|
||||
"p99": null
|
||||
}
|
||||
},
|
||||
"raw_output": "/home/ubuntu/Desktop/mitm-webserver/tools/measurements/20260508-215553-bridge-new/environment/env_tc_qdisc_iface.txt",
|
||||
"system_samples_csv": "/home/ubuntu/Desktop/mitm-webserver/tools/measurements/20260508-215553-bridge-new/environment/env_tc_qdisc_iface.system_samples.csv"
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
timestamp,cpu_percent
|
||||
|
@@ -0,0 +1,6 @@
|
||||
$ tc qdisc show dev enp1s0
|
||||
|
||||
STDOUT
|
||||
qdisc fq_codel 0: root refcnt 2 limit 10240p flows 1024 quantum 1514 target 5ms interval 100ms memory_limit 32Mb ecn drop_batch 64
|
||||
|
||||
STDERR
|
||||
@@ -0,0 +1,33 @@
|
||||
{
|
||||
"command": [
|
||||
"uname",
|
||||
"-a"
|
||||
],
|
||||
"returncode": 0,
|
||||
"timed_out": false,
|
||||
"error": null,
|
||||
"start_time": "2026-05-08T19:55:53.007638+00:00",
|
||||
"duration_seconds": 0.001855410999723972,
|
||||
"interface_counters_before": {},
|
||||
"interface_counters_after": {},
|
||||
"interface_counters_delta": {},
|
||||
"system": {
|
||||
"sample_count": 0,
|
||||
"cpu_percent": {
|
||||
"count": 0,
|
||||
"min": null,
|
||||
"max": null,
|
||||
"mean": null,
|
||||
"median": null,
|
||||
"stdev": null,
|
||||
"mad": null,
|
||||
"iqr": null,
|
||||
"cv_percent": null,
|
||||
"p90": null,
|
||||
"p95": null,
|
||||
"p99": null
|
||||
}
|
||||
},
|
||||
"raw_output": "/home/ubuntu/Desktop/mitm-webserver/tools/measurements/20260508-215553-bridge-new/environment/env_uname.txt",
|
||||
"system_samples_csv": "/home/ubuntu/Desktop/mitm-webserver/tools/measurements/20260508-215553-bridge-new/environment/env_uname.system_samples.csv"
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
timestamp,cpu_percent
|
||||
|
@@ -0,0 +1,6 @@
|
||||
$ uname -a
|
||||
|
||||
STDOUT
|
||||
Linux ubuntu-HP-ProBook-440-G5 6.17.0-20-generic #20~24.04.1-Ubuntu SMP PREEMPT_DYNAMIC Thu Mar 19 01:28:37 UTC 2 x86_64 x86_64 x86_64 GNU/Linux
|
||||
|
||||
STDERR
|
||||
@@ -0,0 +1,644 @@
|
||||
{
|
||||
"host": {
|
||||
"hostname": "ubuntu-HP-ProBook-440-G5",
|
||||
"platform": "Linux-6.17.0-20-generic-x86_64-with-glibc2.39",
|
||||
"python": "3.12.3 (main, Mar 23 2026, 19:04:32) [GCC 13.3.0]",
|
||||
"kernel": "6.17.0-20-generic"
|
||||
},
|
||||
"target": "10.11.11.2",
|
||||
"interface": "enp1s0",
|
||||
"interface_sysfs": {
|
||||
"address": "ac:e2:d3:6c:05:0c",
|
||||
"operstate": "up",
|
||||
"mtu": "1500",
|
||||
"speed": "1000",
|
||||
"duplex": "full",
|
||||
"carrier": "1",
|
||||
"flags": "0x1003",
|
||||
"statistics": {
|
||||
"rx_packets": 24924341,
|
||||
"tx_packets": 5543370,
|
||||
"rx_bytes": 36500988331,
|
||||
"tx_bytes": 34922814271,
|
||||
"rx_dropped": 0,
|
||||
"tx_dropped": 6,
|
||||
"rx_errors": 0,
|
||||
"tx_errors": 0
|
||||
}
|
||||
},
|
||||
"proc_snapshots": {
|
||||
"net/dev": "/home/ubuntu/Desktop/mitm-webserver/tools/measurements/20260508-215553-bridge-new/environment/proc_net_dev.txt",
|
||||
"net/softnet_stat": "/home/ubuntu/Desktop/mitm-webserver/tools/measurements/20260508-215553-bridge-new/environment/proc_net_softnet_stat.txt",
|
||||
"interrupts": "/home/ubuntu/Desktop/mitm-webserver/tools/measurements/20260508-215553-bridge-new/environment/proc_interrupts.txt",
|
||||
"softirqs": "/home/ubuntu/Desktop/mitm-webserver/tools/measurements/20260508-215553-bridge-new/environment/proc_softirqs.txt"
|
||||
},
|
||||
"tool_availability": {
|
||||
"ping": true,
|
||||
"arping": true,
|
||||
"iperf3": true,
|
||||
"flent": true,
|
||||
"sockperf": true,
|
||||
"mtr": true,
|
||||
"traceroute": true,
|
||||
"ip": true,
|
||||
"tc": true,
|
||||
"nft": true,
|
||||
"ethtool": true
|
||||
},
|
||||
"commands": [
|
||||
{
|
||||
"name": "uname",
|
||||
"command": [
|
||||
"uname",
|
||||
"-a"
|
||||
],
|
||||
"returncode": 0,
|
||||
"meta": {
|
||||
"command": [
|
||||
"uname",
|
||||
"-a"
|
||||
],
|
||||
"returncode": 0,
|
||||
"timed_out": false,
|
||||
"error": null,
|
||||
"start_time": "2026-05-08T19:55:53.007638+00:00",
|
||||
"duration_seconds": 0.001855410999723972,
|
||||
"interface_counters_before": {},
|
||||
"interface_counters_after": {},
|
||||
"interface_counters_delta": {},
|
||||
"system": {
|
||||
"sample_count": 0,
|
||||
"cpu_percent": {
|
||||
"count": 0,
|
||||
"min": null,
|
||||
"max": null,
|
||||
"mean": null,
|
||||
"median": null,
|
||||
"stdev": null,
|
||||
"mad": null,
|
||||
"iqr": null,
|
||||
"cv_percent": null,
|
||||
"p90": null,
|
||||
"p95": null,
|
||||
"p99": null
|
||||
}
|
||||
},
|
||||
"raw_output": "/home/ubuntu/Desktop/mitm-webserver/tools/measurements/20260508-215553-bridge-new/environment/env_uname.txt",
|
||||
"system_samples_csv": "/home/ubuntu/Desktop/mitm-webserver/tools/measurements/20260508-215553-bridge-new/environment/env_uname.system_samples.csv"
|
||||
},
|
||||
"error": null
|
||||
},
|
||||
{
|
||||
"name": "ip_addr",
|
||||
"command": [
|
||||
"ip",
|
||||
"addr",
|
||||
"show"
|
||||
],
|
||||
"returncode": 0,
|
||||
"meta": {
|
||||
"command": [
|
||||
"ip",
|
||||
"addr",
|
||||
"show"
|
||||
],
|
||||
"returncode": 0,
|
||||
"timed_out": false,
|
||||
"error": null,
|
||||
"start_time": "2026-05-08T19:55:53.010104+00:00",
|
||||
"duration_seconds": 0.00286572699997123,
|
||||
"interface_counters_before": {},
|
||||
"interface_counters_after": {},
|
||||
"interface_counters_delta": {},
|
||||
"system": {
|
||||
"sample_count": 0,
|
||||
"cpu_percent": {
|
||||
"count": 0,
|
||||
"min": null,
|
||||
"max": null,
|
||||
"mean": null,
|
||||
"median": null,
|
||||
"stdev": null,
|
||||
"mad": null,
|
||||
"iqr": null,
|
||||
"cv_percent": null,
|
||||
"p90": null,
|
||||
"p95": null,
|
||||
"p99": null
|
||||
}
|
||||
},
|
||||
"raw_output": "/home/ubuntu/Desktop/mitm-webserver/tools/measurements/20260508-215553-bridge-new/environment/env_ip_addr.txt",
|
||||
"system_samples_csv": "/home/ubuntu/Desktop/mitm-webserver/tools/measurements/20260508-215553-bridge-new/environment/env_ip_addr.system_samples.csv"
|
||||
},
|
||||
"error": null
|
||||
},
|
||||
{
|
||||
"name": "ip_route",
|
||||
"command": [
|
||||
"ip",
|
||||
"route",
|
||||
"show",
|
||||
"table",
|
||||
"all"
|
||||
],
|
||||
"returncode": 0,
|
||||
"meta": {
|
||||
"command": [
|
||||
"ip",
|
||||
"route",
|
||||
"show",
|
||||
"table",
|
||||
"all"
|
||||
],
|
||||
"returncode": 0,
|
||||
"timed_out": false,
|
||||
"error": null,
|
||||
"start_time": "2026-05-08T19:55:53.013452+00:00",
|
||||
"duration_seconds": 0.0021849139998266764,
|
||||
"interface_counters_before": {},
|
||||
"interface_counters_after": {},
|
||||
"interface_counters_delta": {},
|
||||
"system": {
|
||||
"sample_count": 0,
|
||||
"cpu_percent": {
|
||||
"count": 0,
|
||||
"min": null,
|
||||
"max": null,
|
||||
"mean": null,
|
||||
"median": null,
|
||||
"stdev": null,
|
||||
"mad": null,
|
||||
"iqr": null,
|
||||
"cv_percent": null,
|
||||
"p90": null,
|
||||
"p95": null,
|
||||
"p99": null
|
||||
}
|
||||
},
|
||||
"raw_output": "/home/ubuntu/Desktop/mitm-webserver/tools/measurements/20260508-215553-bridge-new/environment/env_ip_route.txt",
|
||||
"system_samples_csv": "/home/ubuntu/Desktop/mitm-webserver/tools/measurements/20260508-215553-bridge-new/environment/env_ip_route.system_samples.csv"
|
||||
},
|
||||
"error": null
|
||||
},
|
||||
{
|
||||
"name": "ip_neigh",
|
||||
"command": [
|
||||
"ip",
|
||||
"neigh",
|
||||
"show"
|
||||
],
|
||||
"returncode": 0,
|
||||
"meta": {
|
||||
"command": [
|
||||
"ip",
|
||||
"neigh",
|
||||
"show"
|
||||
],
|
||||
"returncode": 0,
|
||||
"timed_out": false,
|
||||
"error": null,
|
||||
"start_time": "2026-05-08T19:55:53.016144+00:00",
|
||||
"duration_seconds": 0.002227852000032726,
|
||||
"interface_counters_before": {},
|
||||
"interface_counters_after": {},
|
||||
"interface_counters_delta": {},
|
||||
"system": {
|
||||
"sample_count": 0,
|
||||
"cpu_percent": {
|
||||
"count": 0,
|
||||
"min": null,
|
||||
"max": null,
|
||||
"mean": null,
|
||||
"median": null,
|
||||
"stdev": null,
|
||||
"mad": null,
|
||||
"iqr": null,
|
||||
"cv_percent": null,
|
||||
"p90": null,
|
||||
"p95": null,
|
||||
"p99": null
|
||||
}
|
||||
},
|
||||
"raw_output": "/home/ubuntu/Desktop/mitm-webserver/tools/measurements/20260508-215553-bridge-new/environment/env_ip_neigh.txt",
|
||||
"system_samples_csv": "/home/ubuntu/Desktop/mitm-webserver/tools/measurements/20260508-215553-bridge-new/environment/env_ip_neigh.system_samples.csv"
|
||||
},
|
||||
"error": null
|
||||
},
|
||||
{
|
||||
"name": "tc_qdisc",
|
||||
"command": [
|
||||
"tc",
|
||||
"qdisc",
|
||||
"show"
|
||||
],
|
||||
"returncode": 0,
|
||||
"meta": {
|
||||
"command": [
|
||||
"tc",
|
||||
"qdisc",
|
||||
"show"
|
||||
],
|
||||
"returncode": 0,
|
||||
"timed_out": false,
|
||||
"error": null,
|
||||
"start_time": "2026-05-08T19:55:53.019007+00:00",
|
||||
"duration_seconds": 0.005839450999701512,
|
||||
"interface_counters_before": {},
|
||||
"interface_counters_after": {},
|
||||
"interface_counters_delta": {},
|
||||
"system": {
|
||||
"sample_count": 0,
|
||||
"cpu_percent": {
|
||||
"count": 0,
|
||||
"min": null,
|
||||
"max": null,
|
||||
"mean": null,
|
||||
"median": null,
|
||||
"stdev": null,
|
||||
"mad": null,
|
||||
"iqr": null,
|
||||
"cv_percent": null,
|
||||
"p90": null,
|
||||
"p95": null,
|
||||
"p99": null
|
||||
}
|
||||
},
|
||||
"raw_output": "/home/ubuntu/Desktop/mitm-webserver/tools/measurements/20260508-215553-bridge-new/environment/env_tc_qdisc.txt",
|
||||
"system_samples_csv": "/home/ubuntu/Desktop/mitm-webserver/tools/measurements/20260508-215553-bridge-new/environment/env_tc_qdisc.system_samples.csv"
|
||||
},
|
||||
"error": null
|
||||
},
|
||||
{
|
||||
"name": "nft_ruleset",
|
||||
"command": [
|
||||
"nft",
|
||||
"list",
|
||||
"ruleset"
|
||||
],
|
||||
"returncode": 1,
|
||||
"meta": {
|
||||
"command": [
|
||||
"nft",
|
||||
"list",
|
||||
"ruleset"
|
||||
],
|
||||
"returncode": 1,
|
||||
"timed_out": false,
|
||||
"error": null,
|
||||
"start_time": "2026-05-08T19:55:53.025488+00:00",
|
||||
"duration_seconds": 0.0029797420002068975,
|
||||
"interface_counters_before": {},
|
||||
"interface_counters_after": {},
|
||||
"interface_counters_delta": {},
|
||||
"system": {
|
||||
"sample_count": 0,
|
||||
"cpu_percent": {
|
||||
"count": 0,
|
||||
"min": null,
|
||||
"max": null,
|
||||
"mean": null,
|
||||
"median": null,
|
||||
"stdev": null,
|
||||
"mad": null,
|
||||
"iqr": null,
|
||||
"cv_percent": null,
|
||||
"p90": null,
|
||||
"p95": null,
|
||||
"p99": null
|
||||
}
|
||||
},
|
||||
"raw_output": "/home/ubuntu/Desktop/mitm-webserver/tools/measurements/20260508-215553-bridge-new/environment/env_nft_ruleset.txt",
|
||||
"system_samples_csv": "/home/ubuntu/Desktop/mitm-webserver/tools/measurements/20260508-215553-bridge-new/environment/env_nft_ruleset.system_samples.csv"
|
||||
},
|
||||
"error": "Operation not permitted (you must be root)\nnetlink: Error: cache initialization failed: Operation not permitted"
|
||||
},
|
||||
{
|
||||
"name": "ip_link_iface",
|
||||
"command": [
|
||||
"ip",
|
||||
"-details",
|
||||
"link",
|
||||
"show",
|
||||
"dev",
|
||||
"enp1s0"
|
||||
],
|
||||
"returncode": 0,
|
||||
"meta": {
|
||||
"command": [
|
||||
"ip",
|
||||
"-details",
|
||||
"link",
|
||||
"show",
|
||||
"dev",
|
||||
"enp1s0"
|
||||
],
|
||||
"returncode": 0,
|
||||
"timed_out": false,
|
||||
"error": null,
|
||||
"start_time": "2026-05-08T19:55:53.028952+00:00",
|
||||
"duration_seconds": 0.0021718110001529567,
|
||||
"interface_counters_before": {},
|
||||
"interface_counters_after": {},
|
||||
"interface_counters_delta": {},
|
||||
"system": {
|
||||
"sample_count": 0,
|
||||
"cpu_percent": {
|
||||
"count": 0,
|
||||
"min": null,
|
||||
"max": null,
|
||||
"mean": null,
|
||||
"median": null,
|
||||
"stdev": null,
|
||||
"mad": null,
|
||||
"iqr": null,
|
||||
"cv_percent": null,
|
||||
"p90": null,
|
||||
"p95": null,
|
||||
"p99": null
|
||||
}
|
||||
},
|
||||
"raw_output": "/home/ubuntu/Desktop/mitm-webserver/tools/measurements/20260508-215553-bridge-new/environment/env_ip_link_iface.txt",
|
||||
"system_samples_csv": "/home/ubuntu/Desktop/mitm-webserver/tools/measurements/20260508-215553-bridge-new/environment/env_ip_link_iface.system_samples.csv"
|
||||
},
|
||||
"error": null
|
||||
},
|
||||
{
|
||||
"name": "tc_qdisc_iface",
|
||||
"command": [
|
||||
"tc",
|
||||
"qdisc",
|
||||
"show",
|
||||
"dev",
|
||||
"enp1s0"
|
||||
],
|
||||
"returncode": 0,
|
||||
"meta": {
|
||||
"command": [
|
||||
"tc",
|
||||
"qdisc",
|
||||
"show",
|
||||
"dev",
|
||||
"enp1s0"
|
||||
],
|
||||
"returncode": 0,
|
||||
"timed_out": false,
|
||||
"error": null,
|
||||
"start_time": "2026-05-08T19:55:53.031580+00:00",
|
||||
"duration_seconds": 0.002074567999898136,
|
||||
"interface_counters_before": {},
|
||||
"interface_counters_after": {},
|
||||
"interface_counters_delta": {},
|
||||
"system": {
|
||||
"sample_count": 0,
|
||||
"cpu_percent": {
|
||||
"count": 0,
|
||||
"min": null,
|
||||
"max": null,
|
||||
"mean": null,
|
||||
"median": null,
|
||||
"stdev": null,
|
||||
"mad": null,
|
||||
"iqr": null,
|
||||
"cv_percent": null,
|
||||
"p90": null,
|
||||
"p95": null,
|
||||
"p99": null
|
||||
}
|
||||
},
|
||||
"raw_output": "/home/ubuntu/Desktop/mitm-webserver/tools/measurements/20260508-215553-bridge-new/environment/env_tc_qdisc_iface.txt",
|
||||
"system_samples_csv": "/home/ubuntu/Desktop/mitm-webserver/tools/measurements/20260508-215553-bridge-new/environment/env_tc_qdisc_iface.system_samples.csv"
|
||||
},
|
||||
"error": null
|
||||
},
|
||||
{
|
||||
"name": "tc_filter_ingress_iface",
|
||||
"command": [
|
||||
"tc",
|
||||
"filter",
|
||||
"show",
|
||||
"dev",
|
||||
"enp1s0",
|
||||
"ingress"
|
||||
],
|
||||
"returncode": 0,
|
||||
"meta": {
|
||||
"command": [
|
||||
"tc",
|
||||
"filter",
|
||||
"show",
|
||||
"dev",
|
||||
"enp1s0",
|
||||
"ingress"
|
||||
],
|
||||
"returncode": 0,
|
||||
"timed_out": false,
|
||||
"error": null,
|
||||
"start_time": "2026-05-08T19:55:53.034081+00:00",
|
||||
"duration_seconds": 0.0020320580001680355,
|
||||
"interface_counters_before": {},
|
||||
"interface_counters_after": {},
|
||||
"interface_counters_delta": {},
|
||||
"system": {
|
||||
"sample_count": 0,
|
||||
"cpu_percent": {
|
||||
"count": 0,
|
||||
"min": null,
|
||||
"max": null,
|
||||
"mean": null,
|
||||
"median": null,
|
||||
"stdev": null,
|
||||
"mad": null,
|
||||
"iqr": null,
|
||||
"cv_percent": null,
|
||||
"p90": null,
|
||||
"p95": null,
|
||||
"p99": null
|
||||
}
|
||||
},
|
||||
"raw_output": "/home/ubuntu/Desktop/mitm-webserver/tools/measurements/20260508-215553-bridge-new/environment/env_tc_filter_ingress_iface.txt",
|
||||
"system_samples_csv": "/home/ubuntu/Desktop/mitm-webserver/tools/measurements/20260508-215553-bridge-new/environment/env_tc_filter_ingress_iface.system_samples.csv"
|
||||
},
|
||||
"error": null
|
||||
},
|
||||
{
|
||||
"name": "tc_filter_egress_iface",
|
||||
"command": [
|
||||
"tc",
|
||||
"filter",
|
||||
"show",
|
||||
"dev",
|
||||
"enp1s0",
|
||||
"egress"
|
||||
],
|
||||
"returncode": 0,
|
||||
"meta": {
|
||||
"command": [
|
||||
"tc",
|
||||
"filter",
|
||||
"show",
|
||||
"dev",
|
||||
"enp1s0",
|
||||
"egress"
|
||||
],
|
||||
"returncode": 0,
|
||||
"timed_out": false,
|
||||
"error": null,
|
||||
"start_time": "2026-05-08T19:55:53.036545+00:00",
|
||||
"duration_seconds": 0.0020781439998245332,
|
||||
"interface_counters_before": {},
|
||||
"interface_counters_after": {},
|
||||
"interface_counters_delta": {},
|
||||
"system": {
|
||||
"sample_count": 0,
|
||||
"cpu_percent": {
|
||||
"count": 0,
|
||||
"min": null,
|
||||
"max": null,
|
||||
"mean": null,
|
||||
"median": null,
|
||||
"stdev": null,
|
||||
"mad": null,
|
||||
"iqr": null,
|
||||
"cv_percent": null,
|
||||
"p90": null,
|
||||
"p95": null,
|
||||
"p99": null
|
||||
}
|
||||
},
|
||||
"raw_output": "/home/ubuntu/Desktop/mitm-webserver/tools/measurements/20260508-215553-bridge-new/environment/env_tc_filter_egress_iface.txt",
|
||||
"system_samples_csv": "/home/ubuntu/Desktop/mitm-webserver/tools/measurements/20260508-215553-bridge-new/environment/env_tc_filter_egress_iface.system_samples.csv"
|
||||
},
|
||||
"error": null
|
||||
},
|
||||
{
|
||||
"name": "ethtool_iface",
|
||||
"command": [
|
||||
"ethtool",
|
||||
"enp1s0"
|
||||
],
|
||||
"returncode": 0,
|
||||
"meta": {
|
||||
"command": [
|
||||
"ethtool",
|
||||
"enp1s0"
|
||||
],
|
||||
"returncode": 0,
|
||||
"timed_out": false,
|
||||
"error": null,
|
||||
"start_time": "2026-05-08T19:55:53.039103+00:00",
|
||||
"duration_seconds": 0.0016709730002730794,
|
||||
"interface_counters_before": {},
|
||||
"interface_counters_after": {},
|
||||
"interface_counters_delta": {},
|
||||
"system": {
|
||||
"sample_count": 0,
|
||||
"cpu_percent": {
|
||||
"count": 0,
|
||||
"min": null,
|
||||
"max": null,
|
||||
"mean": null,
|
||||
"median": null,
|
||||
"stdev": null,
|
||||
"mad": null,
|
||||
"iqr": null,
|
||||
"cv_percent": null,
|
||||
"p90": null,
|
||||
"p95": null,
|
||||
"p99": null
|
||||
}
|
||||
},
|
||||
"raw_output": "/home/ubuntu/Desktop/mitm-webserver/tools/measurements/20260508-215553-bridge-new/environment/env_ethtool_iface.txt",
|
||||
"system_samples_csv": "/home/ubuntu/Desktop/mitm-webserver/tools/measurements/20260508-215553-bridge-new/environment/env_ethtool_iface.system_samples.csv"
|
||||
},
|
||||
"error": null
|
||||
},
|
||||
{
|
||||
"name": "ethtool_offloads_iface",
|
||||
"command": [
|
||||
"ethtool",
|
||||
"-k",
|
||||
"enp1s0"
|
||||
],
|
||||
"returncode": 0,
|
||||
"meta": {
|
||||
"command": [
|
||||
"ethtool",
|
||||
"-k",
|
||||
"enp1s0"
|
||||
],
|
||||
"returncode": 0,
|
||||
"timed_out": false,
|
||||
"error": null,
|
||||
"start_time": "2026-05-08T19:55:53.041214+00:00",
|
||||
"duration_seconds": 0.0015542820001428481,
|
||||
"interface_counters_before": {},
|
||||
"interface_counters_after": {},
|
||||
"interface_counters_delta": {},
|
||||
"system": {
|
||||
"sample_count": 0,
|
||||
"cpu_percent": {
|
||||
"count": 0,
|
||||
"min": null,
|
||||
"max": null,
|
||||
"mean": null,
|
||||
"median": null,
|
||||
"stdev": null,
|
||||
"mad": null,
|
||||
"iqr": null,
|
||||
"cv_percent": null,
|
||||
"p90": null,
|
||||
"p95": null,
|
||||
"p99": null
|
||||
}
|
||||
},
|
||||
"raw_output": "/home/ubuntu/Desktop/mitm-webserver/tools/measurements/20260508-215553-bridge-new/environment/env_ethtool_offloads_iface.txt",
|
||||
"system_samples_csv": "/home/ubuntu/Desktop/mitm-webserver/tools/measurements/20260508-215553-bridge-new/environment/env_ethtool_offloads_iface.system_samples.csv"
|
||||
},
|
||||
"error": null
|
||||
},
|
||||
{
|
||||
"name": "ethtool_stats_iface",
|
||||
"command": [
|
||||
"ethtool",
|
||||
"-S",
|
||||
"enp1s0"
|
||||
],
|
||||
"returncode": 0,
|
||||
"meta": {
|
||||
"command": [
|
||||
"ethtool",
|
||||
"-S",
|
||||
"enp1s0"
|
||||
],
|
||||
"returncode": 0,
|
||||
"timed_out": false,
|
||||
"error": null,
|
||||
"start_time": "2026-05-08T19:55:53.043205+00:00",
|
||||
"duration_seconds": 0.0014122029997452046,
|
||||
"interface_counters_before": {},
|
||||
"interface_counters_after": {},
|
||||
"interface_counters_delta": {},
|
||||
"system": {
|
||||
"sample_count": 0,
|
||||
"cpu_percent": {
|
||||
"count": 0,
|
||||
"min": null,
|
||||
"max": null,
|
||||
"mean": null,
|
||||
"median": null,
|
||||
"stdev": null,
|
||||
"mad": null,
|
||||
"iqr": null,
|
||||
"cv_percent": null,
|
||||
"p90": null,
|
||||
"p95": null,
|
||||
"p99": null
|
||||
}
|
||||
},
|
||||
"raw_output": "/home/ubuntu/Desktop/mitm-webserver/tools/measurements/20260508-215553-bridge-new/environment/env_ethtool_stats_iface.txt",
|
||||
"system_samples_csv": "/home/ubuntu/Desktop/mitm-webserver/tools/measurements/20260508-215553-bridge-new/environment/env_ethtool_stats_iface.system_samples.csv"
|
||||
},
|
||||
"error": null
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
CPU0 CPU1 CPU2 CPU3 CPU4 CPU5 CPU6 CPU7
|
||||
1: 0 0 0 0 0 0 0 1326 IR-IO-APIC 1-edge i8042
|
||||
8: 0 0 0 0 0 0 0 0 IR-IO-APIC 8-edge rtc0
|
||||
9: 540088 0 0 0 0 0 0 0 IR-IO-APIC 9-fasteoi acpi
|
||||
12: 0 0 0 0 0 0 238 0 IR-IO-APIC 12-edge i8042
|
||||
14: 0 5687 0 0 0 0 0 0 IR-IO-APIC 14-fasteoi INT344B:00
|
||||
16: 0 0 0 6 0 0 0 0 IR-IO-APIC 16-fasteoi idma64.0, i2c_designware.0, i801_smbus
|
||||
17: 0 0 0 0 324066 0 0 0 IR-IO-APIC 17-fasteoi idma64.1, i2c_designware.1
|
||||
94: 0 0 0 0 0 0 0 0 IR-IO-APIC 94-edge lis3lv02d
|
||||
120: 0 0 0 0 0 0 0 0 DMAR-MSI 1-edge dmar1
|
||||
121: 0 0 1 0 0 0 0 0 IR-PCI-MSI-0000:00:1c.0 0-edge PCIe PME, aerdrv, PCIe bwctrl
|
||||
122: 0 0 0 1 0 0 0 0 IR-PCI-MSI-0000:00:1c.5 0-edge PCIe PME, aerdrv, PCIe bwctrl
|
||||
123: 0 0 0 0 1 0 0 0 IR-PCI-MSI-0000:00:1d.0 0-edge PCIe PME, aerdrv, PCIe bwctrl
|
||||
124: 0 0 0 0 0 3 0 0 IR-PCI-MSI-0000:00:1d.3 0-edge PCIe PME, aerdrv, pciehp, PCIe bwctrl
|
||||
125: 0 0 0 0 0 0 37357 0 IR-PCI-MSI-0000:00:14.0 0-edge xhci_hcd
|
||||
133: 0 0 1797 0 0 0 0 0 IR-PCI-MSI-0000:00:17.0 0-edge ahci[0000:00:17.0]
|
||||
134: 0 5687 0 0 0 0 0 0 intel-gpio 62 SYNA3064:00
|
||||
135: 0 0 0 0 14012558 0 0 0 IR-PCI-MSIX-0000:01:00.0 0-edge enp1s0
|
||||
136: 0 0 0 0 0 6 0 0 IR-PCI-MSI-0000:04:00.0 0-edge rtsx_pci
|
||||
137: 0 0 0 0 0 0 52 0 IR-PCI-MSIX-0000:03:00.0 0-edge nvme0q0
|
||||
138: 30938 0 0 0 0 0 0 0 IR-PCI-MSIX-0000:03:00.0 1-edge nvme0q1
|
||||
139: 0 33660 0 0 0 0 0 0 IR-PCI-MSIX-0000:03:00.0 2-edge nvme0q2
|
||||
140: 0 0 22080 0 0 0 0 0 IR-PCI-MSIX-0000:03:00.0 3-edge nvme0q3
|
||||
141: 0 0 0 16140 0 0 0 0 IR-PCI-MSIX-0000:03:00.0 4-edge nvme0q4
|
||||
142: 0 0 0 0 43666 0 0 0 IR-PCI-MSIX-0000:03:00.0 5-edge nvme0q5
|
||||
143: 0 0 0 0 0 34405 0 0 IR-PCI-MSIX-0000:03:00.0 6-edge nvme0q6
|
||||
144: 0 0 0 0 0 0 20733 0 IR-PCI-MSIX-0000:03:00.0 7-edge nvme0q7
|
||||
145: 0 0 0 0 0 0 0 19614 IR-PCI-MSIX-0000:03:00.0 8-edge nvme0q8
|
||||
146: 0 0 0 0 0 0 0 76 IR-PCI-MSI-0000:00:16.0 0-edge mei_me
|
||||
147: 0 77944 0 0 0 0 0 0 IR-PCI-MSI-0000:02:00.0 0-edge iwlwifi
|
||||
148: 0 0 180974 0 0 0 0 0 IR-PCI-MSI-0000:00:02.0 0-edge i915
|
||||
149: 0 0 0 878 0 0 0 0 IR-PCI-MSI-0000:00:1f.3 0-edge snd_hda_intel:card0
|
||||
NMI: 15 15 12 12 42 25 16 17 Non-maskable interrupts
|
||||
LOC: 479501 487105 390587 377713 12746290 539954 399603 514590 Local timer interrupts
|
||||
SPU: 0 0 0 0 0 0 0 0 Spurious interrupts
|
||||
PMI: 15 15 12 12 42 25 16 17 Performance monitoring interrupts
|
||||
IWI: 4548 6770 90438 6704 7315 6898 1093 4328 IRQ work interrupts
|
||||
RTR: 0 0 0 0 0 0 0 0 APIC ICR read retries
|
||||
RES: 2765 2150 2329 2285 2430 2486 5644 3788 Rescheduling interrupts
|
||||
CAL: 69335 50544 46743 55142 43854 51807 41678 57867 Function call interrupts
|
||||
TLB: 13399 12951 13070 11823 12570 14024 13435 14473 TLB shootdowns
|
||||
TRM: 58 58 58 58 58 58 58 58 Thermal event interrupts
|
||||
THR: 0 0 0 0 0 0 0 0 Threshold APIC interrupts
|
||||
DFR: 0 0 0 0 0 0 0 0 Deferred Error APIC interrupts
|
||||
MCE: 0 0 0 0 0 0 0 0 Machine check exceptions
|
||||
MCP: 12 13 13 13 13 13 13 13 Machine check polls
|
||||
ERR: 0
|
||||
MIS: 0
|
||||
PIN: 0 0 0 0 0 0 0 0 Posted-interrupt notification event
|
||||
NPI: 0 0 0 0 0 0 0 0 Nested posted-interrupt event
|
||||
PIW: 0 0 0 0 0 0 0 0 Posted-interrupt wakeup event
|
||||
@@ -0,0 +1,5 @@
|
||||
Inter-| Receive | Transmit
|
||||
face |bytes packets errs drop fifo frame compressed multicast|bytes packets errs drop fifo colls carrier compressed
|
||||
lo: 2107531905 99288 0 0 0 0 0 0 2107531905 99288 0 0 0 0 0 0
|
||||
enp1s0: 36500988331 24924341 0 0 0 0 0 21 34922814271 5543370 0 6 0 0 0 0
|
||||
wlp2s0: 1338955753 899563 0 0 0 0 0 0 13478450 58456 0 4 0 0 0 0
|
||||
@@ -0,0 +1,8 @@
|
||||
00003724 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
|
||||
00015924 00000000 00000005 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000001 00000000 00000000
|
||||
00003f28 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000002 00000000 00000000
|
||||
000000a1 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000003 00000000 00000000
|
||||
00616fc2 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000004 00000000 00000000
|
||||
00005960 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000005 00000000 00000000
|
||||
00001a80 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000006 00000000 00000000
|
||||
000049ff 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000007 00000000 00000000
|
||||
@@ -0,0 +1,11 @@
|
||||
CPU0 CPU1 CPU2 CPU3 CPU4 CPU5 CPU6 CPU7
|
||||
HI: 14610 23102 111237 22814 23306 34467 43657 25638
|
||||
TIMER: 93468 62599 53190 38759 138010 44999 28689 46936
|
||||
NET_TX: 19 4797 3997 442 4119077 15117 16778 3959
|
||||
NET_RX: 14076 84787 16129 157 25986420 16412 6765 12909
|
||||
BLOCK: 2085 3164 6070 5538 3382 4480 2020 7147
|
||||
IRQ_POLL: 0 0 0 0 0 0 0 0
|
||||
TASKLET: 31 904 33 12 455508 51 5087 1023
|
||||
SCHED: 497825 240559 138527 118940 269906 195247 125097 150240
|
||||
HRTIMER: 0 543 0 0 0 0 0 0
|
||||
RCU: 98850 99884 93710 85440 90946 83655 83688 87038
|
||||
@@ -0,0 +1,68 @@
|
||||
{
|
||||
"command": [
|
||||
"flent",
|
||||
"rrul",
|
||||
"-l",
|
||||
"60",
|
||||
"-H",
|
||||
"10.11.11.2",
|
||||
"-t",
|
||||
"bridge-new-rrul",
|
||||
"-D",
|
||||
"/home/ubuntu/Desktop/mitm-webserver/tools/measurements/20260508-215553-bridge-new"
|
||||
],
|
||||
"returncode": 0,
|
||||
"timed_out": false,
|
||||
"error": null,
|
||||
"start_time": "2026-05-08T20:01:51.910935+00:00",
|
||||
"duration_seconds": 70.98015862700049,
|
||||
"interface_counters_before": {
|
||||
"rx_packets": 28238692,
|
||||
"tx_packets": 6909186,
|
||||
"rx_bytes": 41296983025,
|
||||
"tx_bytes": 39078559501,
|
||||
"rx_dropped": 0,
|
||||
"tx_dropped": 6,
|
||||
"rx_errors": 0,
|
||||
"tx_errors": 0
|
||||
},
|
||||
"interface_counters_after": {
|
||||
"rx_packets": 33267973,
|
||||
"tx_packets": 7199062,
|
||||
"rx_bytes": 48664171337,
|
||||
"tx_bytes": 46124192591,
|
||||
"rx_dropped": 0,
|
||||
"tx_dropped": 6,
|
||||
"rx_errors": 0,
|
||||
"tx_errors": 0
|
||||
},
|
||||
"interface_counters_delta": {
|
||||
"rx_bytes": 7367188312,
|
||||
"rx_dropped": 0,
|
||||
"rx_errors": 0,
|
||||
"rx_packets": 5029281,
|
||||
"tx_bytes": 7045633090,
|
||||
"tx_dropped": 0,
|
||||
"tx_errors": 0,
|
||||
"tx_packets": 289876
|
||||
},
|
||||
"system": {
|
||||
"sample_count": 141,
|
||||
"cpu_percent": {
|
||||
"count": 141,
|
||||
"min": 0.5050505050505083,
|
||||
"max": 15.07537688442211,
|
||||
"mean": 3.7564203318770377,
|
||||
"median": 3.8363171355498715,
|
||||
"stdev": 1.4821658736220156,
|
||||
"mad": 0.4674803328045596,
|
||||
"iqr": 0.761421319796951,
|
||||
"cv_percent": 39.456869643802484,
|
||||
"p90": 4.556962025316458,
|
||||
"p95": 4.797979797979801,
|
||||
"p99": 7.538677918424738
|
||||
}
|
||||
},
|
||||
"raw_output": "/home/ubuntu/Desktop/mitm-webserver/tools/measurements/20260508-215553-bridge-new/flent_rrul.txt",
|
||||
"system_samples_csv": "/home/ubuntu/Desktop/mitm-webserver/tools/measurements/20260508-215553-bridge-new/flent_rrul.system_samples.csv"
|
||||
}
|
||||
@@ -0,0 +1,142 @@
|
||||
timestamp,cpu_percent,rx_bytes,rx_dropped,rx_errors,rx_packets,tx_bytes,tx_dropped,tx_errors,tx_packets
|
||||
1778270512.4127975,15.07537688442211,41296983025,0,0,28238692,39078559501,6,0,6909186
|
||||
1778270512.9142883,4.282115869017633,41296984542,0,0,28238708,39078560986,6,0,6909202
|
||||
1778270513.4171731,1.5037593984962405,41296985350,0,0,28238716,39078561794,6,0,6909210
|
||||
1778270513.9201343,1.5000000000000013,41296986562,0,0,28238728,39078563006,6,0,6909222
|
||||
1778270514.4230337,1.749999999999996,41296987370,0,0,28238736,39078563814,6,0,6909230
|
||||
1778270514.9259238,1.5037593984962405,41296988582,0,0,28238748,39078565026,6,0,6909242
|
||||
1778270515.428943,1.741293532338306,41296989390,0,0,28238756,39078565834,6,0,6909250
|
||||
1778270515.9319737,1.7456359102244412,41296990602,0,0,28238768,39078567046,6,0,6909262
|
||||
1778270516.4350202,1.253132832080206,41296991410,0,0,28238776,39078567854,6,0,6909270
|
||||
1778270516.9380722,1.5000000000000013,41296992622,0,0,28238788,39078569066,6,0,6909282
|
||||
1778270517.4410214,2.2332506203473934,41296993430,0,0,28238796,39078569874,6,0,6909290
|
||||
1778270517.9436564,5.555555555555558,41353615206,0,0,28277705,39133276804,6,0,6912033
|
||||
1778270518.4451911,4.545454545454541,41415222242,0,0,28319785,39192114574,6,0,6914482
|
||||
1778270518.9467843,4.314720812182737,41476822236,0,0,28361823,39250922992,6,0,6916901
|
||||
1778270519.44836,4.7858942065491235,41538421500,0,0,28403874,39309735350,6,0,6919316
|
||||
1778270519.949877,4.534005037783373,41599989630,0,0,28445869,39368608198,6,0,6921699
|
||||
1778270520.4514282,5.05050505050505,41661583890,0,0,28487910,39427484536,6,0,6924143
|
||||
1778270520.9530299,4.797979797979801,41723209511,0,0,28529962,39486358704,6,0,6926549
|
||||
1778270521.4546824,4.7858942065491235,41784790937,0,0,28572009,39545231697,6,0,6928936
|
||||
1778270521.9562643,4.545454545454541,41846376583,0,0,28614052,39604044855,6,0,6931362
|
||||
1778270522.4578254,4.0506329113924044,41907968211,0,0,28656089,39662917167,6,0,6933740
|
||||
1778270522.959571,4.303797468354431,41969556687,0,0,28698137,39721793843,6,0,6936188
|
||||
1778270523.461165,4.534005037783373,42031135015,0,0,28740155,39780606993,6,0,6938615
|
||||
1778270523.9628546,4.303797468354431,42092666153,0,0,28782139,39839544481,6,0,6941037
|
||||
1778270524.4645705,4.060913705583758,42154283185,0,0,28824177,39898417651,6,0,6943427
|
||||
1778270524.966243,3.8167938931297662,42215867383,0,0,28866219,39957230083,6,0,6945843
|
||||
1778270525.467942,4.545454545454541,42277445513,0,0,28908235,40016044553,6,0,6948291
|
||||
1778270525.9694748,4.060913705583758,42339017665,0,0,28950268,40074920437,6,0,6950720
|
||||
1778270526.4709723,3.57142857142857,42400600861,0,0,28992273,40133730947,6,0,6953106
|
||||
1778270526.9725618,4.060913705583758,42462155563,0,0,29034261,40192603201,6,0,6955484
|
||||
1778270527.4741755,4.303797468354431,42523733895,0,0,29076308,40251415823,6,0,6957904
|
||||
1778270527.9757414,3.8167938931297662,42585270463,0,0,29118304,40310289757,6,0,6960309
|
||||
1778270528.477355,4.0506329113924044,42646828519,0,0,29160324,40369100927,6,0,6962706
|
||||
1778270528.979041,3.57142857142857,42708356761,0,0,29202308,40428039075,6,0,6965138
|
||||
1778270529.4806132,4.292929292929292,42769913369,0,0,29244327,40486912641,6,0,6967534
|
||||
1778270529.9821825,4.071246819338425,42831468479,0,0,29286395,40545789647,6,0,6969986
|
||||
1778270530.4837449,4.060913705583758,42893072153,0,0,29328442,40604601081,6,0,6972387
|
||||
1778270530.9853415,3.544303797468351,42954649045,0,0,29370483,40663415031,6,0,6974824
|
||||
1778270531.4868705,3.30788804071247,43016190385,0,0,29412514,40722229699,6,0,6977274
|
||||
1778270531.988406,3.5532994923857864,43077795053,0,0,29454557,40781102745,6,0,6979663
|
||||
1778270532.4899104,3.2994923857868064,43139332247,0,0,29496592,40839979881,6,0,6982113
|
||||
1778270532.9913938,3.797468354430378,43200903409,0,0,29538605,40898791977,6,0,6984525
|
||||
1778270533.492908,3.7878787878787845,43262438533,0,0,29580610,40957606225,6,0,6986965
|
||||
1778270533.9944587,3.30788804071247,43324012487,0,0,29622650,41016482067,6,0,6989400
|
||||
1778270534.495961,3.30788804071247,43385554129,0,0,29664661,41075295919,6,0,6991836
|
||||
1778270534.9974856,3.30788804071247,43447122155,0,0,29706678,41134172685,6,0,6994281
|
||||
1778270535.4990883,3.30788804071247,43508697729,0,0,29748720,41192924633,6,0,6996725
|
||||
1778270536.0005705,3.7878787878787845,43570267889,0,0,29790729,41251797007,6,0,6999104
|
||||
1778270536.5019848,3.797468354430378,43631823879,0,0,29832734,41310552027,6,0,7001591
|
||||
1778270537.0034535,3.5532994923857864,43693339179,0,0,29874718,41369423249,6,0,7003955
|
||||
1778270537.504988,3.8071065989847663,43754884443,0,0,29916747,41428178533,6,0,7006447
|
||||
1778270538.0065084,4.030226700251893,43816401529,0,0,29958782,41487055629,6,0,7008899
|
||||
1778270538.5079381,3.797468354430378,43877977465,0,0,30000806,41545866313,6,0,7011288
|
||||
1778270539.0095003,3.797468354430378,43939523445,0,0,30042839,41604676723,6,0,7013672
|
||||
1778270539.511019,2.8061224489795866,44001120053,0,0,30084892,41663492423,6,0,7016136
|
||||
1778270540.0125325,4.040404040404044,44062753177,0,0,30126927,41722364239,6,0,7018510
|
||||
1778270540.5140705,3.797468354430378,44124309765,0,0,30168971,41781240091,6,0,7020942
|
||||
1778270541.0155258,3.0612244897959218,44185899651,0,0,30211034,41840052283,6,0,7023354
|
||||
1778270541.5169926,3.5532994923857864,44247505479,0,0,30253117,41898868907,6,0,7025832
|
||||
1778270542.0183897,3.797468354430378,44309077123,0,0,30295123,41957678987,6,0,7028212
|
||||
1778270542.519922,3.2994923857868064,44370627189,0,0,30337133,42016616575,6,0,7030636
|
||||
1778270543.021459,3.544303797468351,44432208709,0,0,30379155,42075490767,6,0,7033041
|
||||
1778270543.5230153,3.562340966921118,44493728503,0,0,30421190,42134366421,6,0,7035471
|
||||
1778270544.0244756,3.5532994923857864,44555306929,0,0,30463208,42193239689,6,0,7037865
|
||||
1778270544.526016,2.8061224489795866,44616884973,0,0,30505244,42252051429,6,0,7040269
|
||||
1778270545.0275054,3.30788804071247,44678460903,0,0,30547290,42310864941,6,0,7042700
|
||||
1778270545.529033,3.5532994923857864,44739997273,0,0,30589266,42369674899,6,0,7045080
|
||||
1778270546.030522,3.544303797468351,44801529029,0,0,30631259,42428546187,6,0,7047443
|
||||
1778270546.5319932,2.813299232736577,44863089957,0,0,30673280,42487295861,6,0,7049851
|
||||
1778270547.0334651,3.5532994923857864,44924624803,0,0,30715253,42546171175,6,0,7052276
|
||||
1778270547.5349886,3.30788804071247,44986197979,0,0,30757303,42604983179,6,0,7054684
|
||||
1778270548.0365067,3.0456852791878153,45047817023,0,0,30799368,42663794975,6,0,7057090
|
||||
1778270548.5380416,4.303797468354431,45109401325,0,0,30841435,42722671355,6,0,7059528
|
||||
1778270549.0396552,4.081632653061229,45170923873,0,0,30883463,42781548451,6,0,7061980
|
||||
1778270549.5413496,3.57142857142857,45232523575,0,0,30925519,42840424369,6,0,7064413
|
||||
1778270550.0430222,3.5805626598465423,45294130833,0,0,30967562,42899298825,6,0,7066823
|
||||
1778270550.5446987,3.8363171355498715,45355674393,0,0,31009625,42958111489,6,0,7069243
|
||||
1778270551.046365,4.071246819338425,45417278033,0,0,31051672,43016987529,6,0,7071681
|
||||
1778270551.5480156,3.826530612244894,45478841465,0,0,31093712,43075863843,6,0,7074118
|
||||
1778270552.049758,4.071246819338425,45540429635,0,0,31135744,43134738563,6,0,7076536
|
||||
1778270552.5515647,4.081632653061229,45602029865,0,0,31177812,43193613161,6,0,7078946
|
||||
1778270553.0531964,4.060913705583758,45663632119,0,0,31219843,43252426013,6,0,7081371
|
||||
1778270553.5547955,4.314720812182737,45725221025,0,0,31261892,43311301733,6,0,7083798
|
||||
1778270554.0564175,4.314720812182737,45786844083,0,0,31303950,43370113793,6,0,7086211
|
||||
1778270554.558062,4.071246819338425,45848328333,0,0,31345969,43428929097,6,0,7088669
|
||||
1778270555.0597188,4.314720812182737,45909928677,0,0,31387995,43487804939,6,0,7091102
|
||||
1778270555.5612905,3.826530612244894,45971501651,0,0,31430023,43546618395,6,0,7093532
|
||||
1778270556.0629194,4.071246819338425,46033101339,0,0,31472055,43605430653,6,0,7095945
|
||||
1778270556.5644495,4.325699745547073,46094701693,0,0,31514076,43664303535,6,0,7098332
|
||||
1778270557.0661414,3.589743589743588,46156324095,0,0,31556151,43723179179,6,0,7100762
|
||||
1778270557.5677521,4.556962025316458,46217888773,0,0,31598160,43782114325,6,0,7103146
|
||||
1778270558.0694685,4.545454545454541,46279432703,0,0,31640139,43840926979,6,0,7105568
|
||||
1778270558.5710652,4.314720812182737,46341002517,0,0,31682163,43899864699,6,0,7107992
|
||||
1778270559.0729005,4.314720812182737,46402616157,0,0,31724187,43958737373,6,0,7110379
|
||||
1778270559.574554,4.071246819338425,46464178995,0,0,31766217,44017676017,6,0,7112815
|
||||
1778270560.07617,3.826530612244894,46525763019,0,0,31808257,44076488077,6,0,7115229
|
||||
1778270560.5777826,4.325699745547073,46587373381,0,0,31850299,44135307473,6,0,7117749
|
||||
1778270561.0793772,3.8363171355498715,46649005321,0,0,31892336,44194180147,6,0,7120132
|
||||
1778270561.5811129,4.060913705583758,46710576451,0,0,31934361,44253117867,6,0,7122557
|
||||
1778270562.0827367,3.826530612244894,46772118933,0,0,31976339,44311988891,6,0,7124916
|
||||
1778270562.5844467,3.8363171355498715,46833643797,0,0,32018382,44370799773,6,0,7127311
|
||||
1778270563.08607,3.8167938931297662,46895158643,0,0,32060403,44429674823,6,0,7129730
|
||||
1778270563.587966,4.071246819338425,46956817589,0,0,32102501,44488487553,6,0,7132151
|
||||
1778270564.0895967,3.826530612244894,47018345049,0,0,32144565,44547363137,6,0,7134576
|
||||
1778270564.591183,5.037783375314864,47079953861,0,0,32186603,44606238587,6,0,7137005
|
||||
1778270565.0927734,3.5805626598465423,47141540097,0,0,32228635,44665111303,6,0,7139387
|
||||
1778270565.594337,4.325699745547073,47203097889,0,0,32270652,44724049179,6,0,7141818
|
||||
1778270566.0961256,4.060913705583758,47264704269,0,0,32312699,44782922093,6,0,7144205
|
||||
1778270566.5977662,3.826530612244894,47326291417,0,0,32354717,44841735903,6,0,7146644
|
||||
1778270567.099446,4.314720812182737,47387872451,0,0,32396735,44900607365,6,0,7149009
|
||||
1778270567.6011143,4.556962025316458,47449477903,0,0,32438795,44959483703,6,0,7151450
|
||||
1778270568.1027482,4.071246819338425,47511094093,0,0,32480860,45018358399,6,0,7153864
|
||||
1778270568.604306,3.5805626598465423,47572635619,0,0,32522828,45077231833,6,0,7156261
|
||||
1778270569.1059415,4.556962025316458,47634242853,0,0,32564865,45136168331,6,0,7158666
|
||||
1778270569.6075091,4.314720812182737,47695835401,0,0,32606904,45194979831,6,0,7161067
|
||||
1778270570.1090376,4.325699745547073,47757362327,0,0,32648891,45253854461,6,0,7163483
|
||||
1778270570.6106088,4.071246819338425,47818963501,0,0,32690944,45312669195,6,0,7165934
|
||||
1778270571.1121912,4.303797468354431,47880524065,0,0,32732961,45371481627,6,0,7168348
|
||||
1778270571.613774,3.826530612244894,47942123527,0,0,32775014,45430354863,6,0,7170742
|
||||
1778270572.1153474,4.5685279187817285,48003644537,0,0,32817041,45489230021,6,0,7173161
|
||||
1778270572.6170533,3.8167938931297662,48065253805,0,0,32859089,45548104973,6,0,7175579
|
||||
1778270573.1186934,4.303797468354431,48126769473,0,0,32901059,45606915755,6,0,7177970
|
||||
1778270573.6202724,4.556962025316458,48188330553,0,0,32943059,45665792687,6,0,7180422
|
||||
1778270574.1219523,4.314720812182737,48249936333,0,0,32985100,45724665529,6,0,7182809
|
||||
1778270574.6236005,4.797979797979801,48311560213,0,0,33027148,45783601293,6,0,7185204
|
||||
1778270575.1254313,4.314720812182737,48373186795,0,0,33069173,45842535217,6,0,7187573
|
||||
1778270575.6273308,4.545454545454541,48434850893,0,0,33111228,45901470123,6,0,7189957
|
||||
1778270576.1297581,5.037783375314864,48496580563,0,0,33153349,45960406225,6,0,7192361
|
||||
1778270576.6322424,4.060913705583758,48558307197,0,0,33195455,46019465131,6,0,7194734
|
||||
1778270577.1346521,4.071246819338425,48620008039,0,0,33237587,46078400639,6,0,7197127
|
||||
1778270577.6374567,4.030226700251893,48664161743,0,0,33267878,46124182835,6,0,7198964
|
||||
1778270578.1404245,1.0075566750629705,48664162853,0,0,33267889,46124183945,6,0,7198975
|
||||
1778270578.643498,0.7556675062972307,48664163661,0,0,33267897,46124184753,6,0,7198983
|
||||
1778270579.1466146,0.5050505050505083,48664164873,0,0,33267909,46124185965,6,0,7198995
|
||||
1778270579.6496735,0.7556675062972307,48664165681,0,0,33267917,46124186773,6,0,7199003
|
||||
1778270580.1526458,1.2594458438287104,48664166893,0,0,33267929,46124187985,6,0,7199015
|
||||
1778270580.6556818,0.7575757575757569,48664167701,0,0,33267937,46124188793,6,0,7199023
|
||||
1778270581.1587634,0.7556675062972307,48664168913,0,0,33267949,46124190005,6,0,7199035
|
||||
1778270581.6618168,1.005025125628145,48664169721,0,0,33267957,46124190813,6,0,7199043
|
||||
1778270582.1650527,0.7556675062972307,48664170933,0,0,33267969,46124192025,6,0,7199055
|
||||
1778270582.6676493,8.860759493670889,48664171337,0,0,33267973,46124192591,6,0,7199062
|
||||
|
31
measurments/20260508-215553-bridge-new/flent_rrul.txt
Normal file
@@ -0,0 +1,31 @@
|
||||
$ flent rrul -l 60 -H 10.11.11.2 -t bridge-new-rrul -D /home/ubuntu/Desktop/mitm-webserver/tools/measurements/20260508-215553-bridge-new
|
||||
|
||||
STDOUT
|
||||
Starting Flent 2.1.1 using Python 3.12.3.
|
||||
Starting rrul test. Expected run time: 70 seconds.
|
||||
Data file written to /home/ubuntu/Desktop/mitm-webserver/tools/measurements/20260508-215553-bridge-new/rrul-2026-05-08T220152.262140.bridge-new-rrul.flent.gz
|
||||
|
||||
Summary of rrul test run from 2026-05-08 20:01:52.262140
|
||||
Title: 'bridge-new-rrul'
|
||||
|
||||
avg median 99th % # data pts
|
||||
Ping (ms) ICMP : 2.85 2.94 3.65 ms 350
|
||||
Ping (ms) UDP BE : 2.91 3.01 3.78 ms 350
|
||||
Ping (ms) UDP BK : 3.00 3.17 3.85 ms 350
|
||||
Ping (ms) UDP EF : 5.99 6.49 7.84 ms 350
|
||||
Ping (ms) avg : 3.69 N/A N/A ms 350
|
||||
TCP download BE : 234.64 234.48 236.47 Mbits/s 350
|
||||
TCP download BK : 234.58 234.44 236.45 Mbits/s 350
|
||||
TCP download CS5 : 234.56 234.40 236.53 Mbits/s 350
|
||||
TCP download EF : 234.02 234.44 236.45 Mbits/s 350
|
||||
TCP download avg : 234.45 N/A N/A Mbits/s 350
|
||||
TCP download sum : 937.80 N/A N/A Mbits/s 350
|
||||
TCP totals : 1873.92 N/A N/A Mbits/s 350
|
||||
TCP upload BE : 234.12 234.12 235.75 Mbits/s 350
|
||||
TCP upload BK : 234.13 234.19 238.51 Mbits/s 350
|
||||
TCP upload CS5 : 234.12 234.17 237.24 Mbits/s 350
|
||||
TCP upload EF : 233.75 233.77 242.11 Mbits/s 350
|
||||
TCP upload avg : 234.03 N/A N/A Mbits/s 350
|
||||
TCP upload sum : 936.12 N/A N/A Mbits/s 350
|
||||
|
||||
STDERR
|
||||
@@ -0,0 +1,68 @@
|
||||
{
|
||||
"command": [
|
||||
"flent",
|
||||
"tcp_download",
|
||||
"-l",
|
||||
"60",
|
||||
"-H",
|
||||
"10.11.11.2",
|
||||
"-t",
|
||||
"bridge-new-tcp_download",
|
||||
"-D",
|
||||
"/home/ubuntu/Desktop/mitm-webserver/tools/measurements/20260508-215553-bridge-new"
|
||||
],
|
||||
"returncode": 0,
|
||||
"timed_out": false,
|
||||
"error": null,
|
||||
"start_time": "2026-05-08T20:04:13.592350+00:00",
|
||||
"duration_seconds": 70.69276734699997,
|
||||
"interface_counters_before": {
|
||||
"rx_packets": 33429760,
|
||||
"tx_packets": 7312874,
|
||||
"rx_bytes": 48674861769,
|
||||
"tx_bytes": 53194708135,
|
||||
"rx_dropped": 0,
|
||||
"tx_dropped": 6,
|
||||
"rx_errors": 0,
|
||||
"tx_errors": 0
|
||||
},
|
||||
"interface_counters_after": {
|
||||
"rx_packets": 38306460,
|
||||
"tx_packets": 7468005,
|
||||
"rx_bytes": 56057679675,
|
||||
"tx_bytes": 53204958561,
|
||||
"rx_dropped": 0,
|
||||
"tx_dropped": 6,
|
||||
"rx_errors": 0,
|
||||
"tx_errors": 0
|
||||
},
|
||||
"interface_counters_delta": {
|
||||
"rx_bytes": 7382817906,
|
||||
"rx_dropped": 0,
|
||||
"rx_errors": 0,
|
||||
"rx_packets": 4876700,
|
||||
"tx_bytes": 10250426,
|
||||
"tx_dropped": 0,
|
||||
"tx_errors": 0,
|
||||
"tx_packets": 155131
|
||||
},
|
||||
"system": {
|
||||
"sample_count": 140,
|
||||
"cpu_percent": {
|
||||
"count": 140,
|
||||
"min": 0.5037783375314908,
|
||||
"max": 16.080402010050253,
|
||||
"mean": 3.4395028181493923,
|
||||
"median": 3.674703440476035,
|
||||
"stdev": 1.4922380731248872,
|
||||
"mad": 0.4017362957237922,
|
||||
"iqr": 1.0152284263959337,
|
||||
"cv_percent": 43.385284211739034,
|
||||
"p90": 4.325699745547073,
|
||||
"p95": 4.556962025316458,
|
||||
"p99": 4.964556962025317
|
||||
}
|
||||
},
|
||||
"raw_output": "/home/ubuntu/Desktop/mitm-webserver/tools/measurements/20260508-215553-bridge-new/flent_tcp_download.txt",
|
||||
"system_samples_csv": "/home/ubuntu/Desktop/mitm-webserver/tools/measurements/20260508-215553-bridge-new/flent_tcp_download.system_samples.csv"
|
||||
}
|
||||
@@ -0,0 +1,141 @@
|
||||
timestamp,cpu_percent,rx_bytes,rx_dropped,rx_errors,rx_packets,tx_bytes,tx_dropped,tx_errors,tx_packets
|
||||
1778270654.0928795,16.080402010050253,48674861769,0,0,33429760,53194708135,6,0,7312874
|
||||
1778270654.5946639,1.5037593984962405,48674862063,0,0,33429763,53194708429,6,0,7312877
|
||||
1778270655.097574,1.005025125628145,48674862259,0,0,33429765,53194708625,6,0,7312879
|
||||
1778270655.6005235,1.0075566750629705,48674862553,0,0,33429768,53194708919,6,0,7312882
|
||||
1778270656.1033664,1.005025125628145,48674862749,0,0,33429770,53194709115,6,0,7312884
|
||||
1778270656.6064212,1.0025062656641603,48674863043,0,0,33429773,53194709409,6,0,7312887
|
||||
1778270657.1093035,0.7537688442211032,48674863239,0,0,33429775,53194709605,6,0,7312889
|
||||
1778270657.612443,0.7556675062972307,48674863533,0,0,33429778,53194709899,6,0,7312892
|
||||
1778270658.11532,0.5037783375314908,48674863729,0,0,33429780,53194710095,6,0,7312894
|
||||
1778270658.618267,1.005025125628145,48674864023,0,0,33429783,53194710389,6,0,7312897
|
||||
1778270659.120883,1.005025125628145,48675478391,0,0,33430169,53194714557,6,0,7312947
|
||||
1778270659.6225548,4.292929292929292,48737233231,0,0,33470954,53194802829,6,0,7314285
|
||||
1778270660.124634,4.773869346733672,48799004627,0,0,33511757,53194890475,6,0,7315612
|
||||
1778270660.6266682,4.556962025316458,48860786719,0,0,33552565,53194977493,6,0,7316929
|
||||
1778270661.128711,4.556962025316458,48922556601,0,0,33593370,53195061707,6,0,7318203
|
||||
1778270661.630742,4.060913705583758,48984335665,0,0,33634178,53195149781,6,0,7319536
|
||||
1778270662.132776,4.060913705583758,49046111603,0,0,33674984,53195237295,6,0,7320861
|
||||
1778270662.634852,3.544303797468351,49107887639,0,0,33715792,53195325633,6,0,7322198
|
||||
1778270663.136689,3.7688442211055273,49169631783,0,0,33756577,53195415061,6,0,7323553
|
||||
1778270663.6384056,4.030226700251893,49231386623,0,0,33797361,53195502145,6,0,7324869
|
||||
1778270664.1404045,3.562340966921118,49293139851,0,0,33838150,53195586953,6,0,7326154
|
||||
1778270664.6424372,4.303797468354431,49354921943,0,0,33878961,53195672189,6,0,7327445
|
||||
1778270665.1444263,4.060913705583758,49416688797,0,0,33919752,53195758977,6,0,7328758
|
||||
1778270665.646785,4.081632653061229,49478502683,0,0,33960590,53195842827,6,0,7330027
|
||||
1778270666.1491318,4.336734693877553,49540301331,0,0,34001414,53195926183,6,0,7331288
|
||||
1778270666.6511862,4.5685279187817285,49602081909,0,0,34042221,53196009571,6,0,7332551
|
||||
1778270667.153248,3.8461538461538436,49663851791,0,0,34083020,53196093059,6,0,7333814
|
||||
1778270667.6553168,5.063291139240511,49725629341,0,0,34123830,53196176711,6,0,7335080
|
||||
1778270668.1573772,4.092071611253201,49787411335,0,0,34164636,53196260331,6,0,7336347
|
||||
1778270668.6594145,4.325699745547073,49849188885,0,0,34205444,53196344181,6,0,7337616
|
||||
1778270669.161474,4.081632653061229,49910967851,0,0,34246251,53196427471,6,0,7338878
|
||||
1778270669.6635168,4.092071611253201,49972746915,0,0,34287058,53196510793,6,0,7340139
|
||||
1778270670.1655307,4.325699745547073,50034519825,0,0,34327863,53196594743,6,0,7341409
|
||||
1778270670.6676393,4.556962025316458,50096315543,0,0,34368681,53196681035,6,0,7342715
|
||||
1778270671.169752,4.081632653061229,50158094509,0,0,34409491,53196764259,6,0,7343976
|
||||
1778270671.6717882,4.325699745547073,50219872059,0,0,34450297,53196847779,6,0,7345240
|
||||
1778270672.1738055,4.336734693877553,50281634371,0,0,34491095,53196930937,6,0,7346498
|
||||
1778270672.675891,4.325699745547073,50343413435,0,0,34531903,53197014457,6,0,7347762
|
||||
1778270673.1779177,4.336734693877553,50405186345,0,0,34572704,53197097945,6,0,7349026
|
||||
1778270673.6799827,4.810126582278484,50466966923,0,0,34613513,53197181729,6,0,7350294
|
||||
1778270674.1820488,4.081632653061229,50528747403,0,0,34654323,53197265943,6,0,7351569
|
||||
1778270674.6840663,3.57142857142857,50590514355,0,0,34695126,53197352631,6,0,7352881
|
||||
1778270675.1858253,3.535353535353536,50652250929,0,0,34735903,53197440145,6,0,7354206
|
||||
1778270675.6876392,2.7989821882951627,50713996685,0,0,34776692,53197527427,6,0,7355528
|
||||
1778270676.1894042,3.7878787878787845,50775739315,0,0,34817475,53197614545,6,0,7356845
|
||||
1778270676.6911945,3.535353535353536,50837488099,0,0,34858260,53197701827,6,0,7358167
|
||||
1778270677.192991,3.2994923857868064,50899212561,0,0,34899033,53197789671,6,0,7359498
|
||||
1778270677.6947749,4.020100502512558,50960967401,0,0,34939824,53197877019,6,0,7360819
|
||||
1778270678.1965964,3.7783375314861423,51022711545,0,0,34980608,53197964599,6,0,7362146
|
||||
1778270678.6983447,3.544303797468351,51084454273,0,0,35021392,53198051881,6,0,7363466
|
||||
1778270679.2001028,4.2713567839196,51146178735,0,0,35062164,53198139791,6,0,7364797
|
||||
1778270679.701896,3.7783375314861423,51207926005,0,0,35102950,53198227337,6,0,7366123
|
||||
1778270680.2036395,3.535353535353536,51269668635,0,0,35143733,53198314719,6,0,7367445
|
||||
1778270680.7054958,3.7878787878787845,51331423475,0,0,35184524,53198402463,6,0,7368774
|
||||
1778270681.2072563,4.020100502512558,51393158535,0,0,35225298,53198489877,6,0,7370095
|
||||
1778270681.7090642,4.030226700251893,51454901263,0,0,35266087,53198577127,6,0,7371417
|
||||
1778270682.2109323,3.7783375314861423,51516659033,0,0,35306879,53198664805,6,0,7372744
|
||||
1778270682.7127185,4.292929292929292,51578404789,0,0,35347668,53198750141,6,0,7374036
|
||||
1778270683.2144916,4.292929292929292,51640150447,0,0,35388450,53198834651,6,0,7375316
|
||||
1778270683.7163217,4.282115869017633,51701905287,0,0,35429241,53198919921,6,0,7376605
|
||||
1778270684.218071,4.292929292929292,51763631263,0,0,35470017,53199004365,6,0,7377885
|
||||
1778270684.7199414,3.562340966921118,51825386103,0,0,35510810,53199088579,6,0,7379159
|
||||
1778270685.2217095,4.0506329113924044,51887112177,0,0,35551580,53199173221,6,0,7380440
|
||||
1778270685.7235134,4.0506329113924044,51948853293,0,0,35592362,53199257765,6,0,7381721
|
||||
1778270686.2252424,4.0506329113924044,52010592993,0,0,35633145,53199342539,6,0,7383003
|
||||
1778270686.727051,3.797468354430378,52072341679,0,0,35673932,53199428733,6,0,7384308
|
||||
1778270687.2288175,3.2994923857868064,52134087435,0,0,35714719,53199516279,6,0,7385633
|
||||
1778270687.7306042,3.7783375314861423,52195836121,0,0,35755502,53199603859,6,0,7386959
|
||||
1778270688.2323637,3.544303797468351,52257577335,0,0,35796286,53199691801,6,0,7388290
|
||||
1778270688.7341387,3.316326530612246,52319319965,0,0,35837072,53199776807,6,0,7389577
|
||||
1778270689.2359033,4.0506329113924044,52381065721,0,0,35877856,53199861515,6,0,7390860
|
||||
1778270689.7376418,3.8071065989847663,52442809865,0,0,35918639,53199945795,6,0,7392135
|
||||
1778270690.2394118,3.797468354430378,52504537453,0,0,35959412,53200031097,6,0,7393425
|
||||
1778270690.7411342,4.040404040404044,52566277055,0,0,36000193,53200116895,6,0,7394726
|
||||
1778270691.242981,3.324808184143224,52628025899,0,0,36040983,53200201513,6,0,7396006
|
||||
1778270691.744777,3.8071065989847663,52689773071,0,0,36081772,53200285991,6,0,7397285
|
||||
1778270692.246538,3.562340966921118,52751508229,0,0,36122547,53200370435,6,0,7398564
|
||||
1778270692.7482917,3.8071065989847663,52813246317,0,0,36163330,53200454781,6,0,7399840
|
||||
1778270693.250029,3.562340966921118,52874990559,0,0,36204114,53200539225,6,0,7401119
|
||||
1778270693.7517786,3.0612244897959218,52936734703,0,0,36244897,53200624495,6,0,7402409
|
||||
1778270694.2535863,3.316326530612246,52998463805,0,0,36285673,53200709071,6,0,7403689
|
||||
1778270694.755324,3.8071065989847663,53060201893,0,0,36326455,53200793483,6,0,7404966
|
||||
1778270695.257093,3.069053708439895,53121950677,0,0,36367239,53200878323,6,0,7406252
|
||||
1778270695.7588944,3.562340966921118,53183696335,0,0,36408027,53200963131,6,0,7407535
|
||||
1778270696.2606733,3.2994923857868064,53245445119,0,0,36448814,53201050611,6,0,7408859
|
||||
1778270696.7624512,3.5532994923857864,53307189263,0,0,36489598,53201135617,6,0,7410146
|
||||
1778270697.264238,3.316326530612246,53368921393,0,0,36530376,53201221117,6,0,7411440
|
||||
1778270697.7661657,3.8167938931297662,53430686733,0,0,36571173,53201305925,6,0,7412724
|
||||
1778270698.2680023,3.797468354430378,53492443087,0,0,36611962,53201390501,6,0,7414005
|
||||
1778270698.76987,3.316326530612246,53554191773,0,0,36652754,53201475309,6,0,7415288
|
||||
1778270699.2716029,3.8071065989847663,53615936015,0,0,36693538,53201559621,6,0,7416565
|
||||
1778270699.7732904,3.8167938931297662,53677675617,0,0,36734316,53201643835,6,0,7417839
|
||||
1778270700.2751195,3.037974683544309,53739397149,0,0,36775095,53201734219,6,0,7419207
|
||||
1778270700.7767189,2.784810126582282,53801121611,0,0,36815864,53201820941,6,0,7420520
|
||||
1778270701.2782698,2.538071065989844,53862835573,0,0,36856629,53201908949,6,0,7421851
|
||||
1778270701.7798483,3.0456852791878153,53924557007,0,0,36897399,53201995671,6,0,7423166
|
||||
1778270702.2813597,2.7918781725888353,53986287623,0,0,36938165,53202082953,6,0,7424486
|
||||
1778270702.783153,3.2828282828282873,54048018141,0,0,36978948,53202168685,6,0,7425785
|
||||
1778270703.2846944,3.0303030303030276,54109727561,0,0,37019711,53202255901,6,0,7427105
|
||||
1778270703.7862365,2.777777777777779,54171448995,0,0,37060475,53202343943,6,0,7428437
|
||||
1778270704.2878962,2.777777777777779,54233128135,0,0,37101224,53202432479,6,0,7429777
|
||||
1778270704.7893972,3.0303030303030276,54294843513,0,0,37141987,53202520521,6,0,7431110
|
||||
1778270705.290929,2.777777777777779,54356558989,0,0,37182753,53202608529,6,0,7432442
|
||||
1778270705.79253,2.5316455696202556,54418283451,0,0,37223524,53202697099,6,0,7433782
|
||||
1778270706.294025,3.7688442211055273,54479994385,0,0,37264287,53202782731,6,0,7435079
|
||||
1778270706.7956011,2.784810126582282,54541715819,0,0,37305055,53202869651,6,0,7436395
|
||||
1778270707.2971587,2.784810126582282,54603434323,0,0,37345823,53202957791,6,0,7437729
|
||||
1778270707.7987087,2.5316455696202556,54665157271,0,0,37386593,53203046427,6,0,7439071
|
||||
1778270708.3002772,3.037974683544309,54726875775,0,0,37427361,53203131927,6,0,7440364
|
||||
1778270708.8018594,3.0456852791878153,54788595695,0,0,37468129,53203217395,6,0,7441659
|
||||
1778270709.3033257,3.7688442211055273,54850283919,0,0,37508879,53203303093,6,0,7442956
|
||||
1778270709.8047361,2.7918781725888353,54911987185,0,0,37549635,53203388231,6,0,7444246
|
||||
1778270710.3061843,3.037974683544309,54973692063,0,0,37590394,53203473467,6,0,7445536
|
||||
1778270710.807823,3.562340966921118,55035443777,0,0,37631176,53203560717,6,0,7446856
|
||||
1778270711.3097553,3.562340966921118,55097188019,0,0,37671961,53203645755,6,0,7448143
|
||||
1778270711.8116663,4.071246819338425,55158948817,0,0,37712759,53203730101,6,0,7449420
|
||||
1778270712.3135574,3.5805626598465423,55220709713,0,0,37753551,53203814347,6,0,7450696
|
||||
1778270712.815514,3.8167938931297662,55282476567,0,0,37794351,53203898363,6,0,7451968
|
||||
1778270713.3174586,3.3333333333333326,55344238977,0,0,37835149,53203982543,6,0,7453241
|
||||
1778270713.8192732,3.8167938931297662,55405989177,0,0,37875937,53204067285,6,0,7454523
|
||||
1778270714.3211155,4.303797468354431,55467737961,0,0,37916725,53204152653,6,0,7455815
|
||||
1778270714.8231122,3.57142857142857,55529506329,0,0,37957526,53204236603,6,0,7457087
|
||||
1778270715.325006,3.826530612244894,55591238459,0,0,37998302,53204320651,6,0,7458359
|
||||
1778270715.8269167,4.060913705583758,55652997743,0,0,38039097,53204405063,6,0,7459637
|
||||
1778270716.3287895,3.5805626598465423,55714767723,0,0,38079897,53204489639,6,0,7460917
|
||||
1778270716.830976,3.8071065989847663,55776558801,0,0,38120711,53204573721,6,0,7462189
|
||||
1778270717.333048,3.826530612244894,55838339379,0,0,38161522,53204657967,6,0,7463464
|
||||
1778270717.8351002,4.060913705583758,55900119859,0,0,38202327,53204742181,6,0,7464740
|
||||
1778270718.3371568,3.8167938931297662,55961900437,0,0,38243136,53204826163,6,0,7466011
|
||||
1778270718.8392365,3.5805626598465423,56023688487,0,0,38283946,53204910311,6,0,7467284
|
||||
1778270719.3417218,2.5316455696202556,56057677421,0,0,38306437,53204956307,6,0,7467982
|
||||
1778270719.8446267,1.2499999999999956,56057677617,0,0,38306439,53204956503,6,0,7467984
|
||||
1778270720.347497,1.2499999999999956,56057677911,0,0,38306442,53204956797,6,0,7467987
|
||||
1778270720.8503606,1.253132832080206,56057678107,0,0,38306444,53204956993,6,0,7467989
|
||||
1778270721.3533645,1.2499999999999956,56057678401,0,0,38306447,53204957287,6,0,7467992
|
||||
1778270721.8563206,1.253132832080206,56057678597,0,0,38306449,53204957483,6,0,7467994
|
||||
1778270722.3592465,1.2499999999999956,56057678891,0,0,38306452,53204957777,6,0,7467997
|
||||
1778270722.8623083,1.2499999999999956,56057679087,0,0,38306454,53204957973,6,0,7467999
|
||||
1778270723.3652961,1.2499999999999956,56057679381,0,0,38306457,53204958267,6,0,7468002
|
||||
1778270723.8682377,1.0025062656641603,56057679577,0,0,38306459,53204958463,6,0,7468004
|
||||
|
@@ -0,0 +1,15 @@
|
||||
$ flent tcp_download -l 60 -H 10.11.11.2 -t bridge-new-tcp_download -D /home/ubuntu/Desktop/mitm-webserver/tools/measurements/20260508-215553-bridge-new
|
||||
|
||||
STDOUT
|
||||
Starting Flent 2.1.1 using Python 3.12.3.
|
||||
Starting tcp_download test. Expected run time: 70 seconds.
|
||||
Data file written to /home/ubuntu/Desktop/mitm-webserver/tools/measurements/20260508-215553-bridge-new/tcp_download-2026-05-08T220413.922585.bridge-new-tcp_download.flent.gz
|
||||
|
||||
Summary of tcp_download test run from 2026-05-08 20:04:13.922585
|
||||
Title: 'bridge-new-tcp_download'
|
||||
|
||||
avg median 99th % # data pts
|
||||
Ping (ms) ICMP : 2.03 2.12 2.32 ms 350
|
||||
TCP download : 941.39 941.48 941.93 Mbits/s 350
|
||||
|
||||
STDERR
|
||||
@@ -0,0 +1,68 @@
|
||||
{
|
||||
"command": [
|
||||
"flent",
|
||||
"tcp_upload",
|
||||
"-l",
|
||||
"60",
|
||||
"-H",
|
||||
"10.11.11.2",
|
||||
"-t",
|
||||
"bridge-new-tcp_upload",
|
||||
"-D",
|
||||
"/home/ubuntu/Desktop/mitm-webserver/tools/measurements/20260508-215553-bridge-new"
|
||||
],
|
||||
"returncode": 0,
|
||||
"timed_out": false,
|
||||
"error": null,
|
||||
"start_time": "2026-05-08T20:03:02.896101+00:00",
|
||||
"duration_seconds": 70.69148080899959,
|
||||
"interface_counters_before": {
|
||||
"rx_packets": 33267973,
|
||||
"tx_packets": 7199062,
|
||||
"rx_bytes": 48664171337,
|
||||
"tx_bytes": 46124192591,
|
||||
"rx_dropped": 0,
|
||||
"tx_dropped": 6,
|
||||
"rx_errors": 0,
|
||||
"tx_errors": 0
|
||||
},
|
||||
"interface_counters_after": {
|
||||
"rx_packets": 33429760,
|
||||
"tx_packets": 7312874,
|
||||
"rx_bytes": 48674861769,
|
||||
"tx_bytes": 53194708135,
|
||||
"rx_dropped": 0,
|
||||
"tx_dropped": 6,
|
||||
"rx_errors": 0,
|
||||
"tx_errors": 0
|
||||
},
|
||||
"interface_counters_delta": {
|
||||
"rx_bytes": 10690432,
|
||||
"rx_dropped": 0,
|
||||
"rx_errors": 0,
|
||||
"rx_packets": 161787,
|
||||
"tx_bytes": 7070515544,
|
||||
"tx_dropped": 0,
|
||||
"tx_errors": 0,
|
||||
"tx_packets": 113812
|
||||
},
|
||||
"system": {
|
||||
"sample_count": 141,
|
||||
"cpu_percent": {
|
||||
"count": 141,
|
||||
"min": 0.2525252525252486,
|
||||
"max": 15.86901763224181,
|
||||
"mean": 3.790393719732066,
|
||||
"median": 4.010025062656641,
|
||||
"stdev": 1.5643750454038898,
|
||||
"mad": 0.23997493734335684,
|
||||
"iqr": 0.4811557788944709,
|
||||
"cv_percent": 41.272098918380216,
|
||||
"p90": 4.488778054862841,
|
||||
"p95": 4.5000000000000036,
|
||||
"p99": 5.800321699771805
|
||||
}
|
||||
},
|
||||
"raw_output": "/home/ubuntu/Desktop/mitm-webserver/tools/measurements/20260508-215553-bridge-new/flent_tcp_upload.txt",
|
||||
"system_samples_csv": "/home/ubuntu/Desktop/mitm-webserver/tools/measurements/20260508-215553-bridge-new/flent_tcp_upload.system_samples.csv"
|
||||
}
|
||||
@@ -0,0 +1,142 @@
|
||||
timestamp,cpu_percent,rx_bytes,rx_dropped,rx_errors,rx_packets,tx_bytes,tx_dropped,tx_errors,tx_packets
|
||||
1778270583.3966472,15.86901763224181,48664171337,0,0,33267973,46124192591,6,0,7199062
|
||||
1778270583.898197,1.5037593984962405,48664171631,0,0,33267976,46124192885,6,0,7199065
|
||||
1778270584.4011018,0.7556675062972307,48664171827,0,0,33267978,46124193081,6,0,7199067
|
||||
1778270584.9040034,1.0075566750629705,48664172121,0,0,33267981,46124193375,6,0,7199070
|
||||
1778270585.4068823,0.5025125628140725,48664172317,0,0,33267983,46124193571,6,0,7199072
|
||||
1778270585.909736,0.5050505050505083,48664172611,0,0,33267986,46124193865,6,0,7199075
|
||||
1778270586.412604,0.7537688442211032,48664172807,0,0,33267988,46124194061,6,0,7199077
|
||||
1778270586.915527,0.2525252525252486,48664173101,0,0,33267991,46124194355,6,0,7199080
|
||||
1778270587.4185076,0.5037783375314908,48664173297,0,0,33267993,46124194551,6,0,7199082
|
||||
1778270587.9215906,0.5050505050505083,48664173591,0,0,33267996,46124194845,6,0,7199085
|
||||
1778270588.4243963,1.253132832080206,48664176043,0,0,33268022,46124375821,6,0,7199105
|
||||
1778270588.9269238,4.5000000000000036,48664268869,0,0,33269426,46183361661,6,0,7200060
|
||||
1778270589.4279335,4.477611940298509,48664357109,0,0,33270762,46242388367,6,0,7201009
|
||||
1778270589.9289098,4.249999999999998,48664445315,0,0,33272097,46301415171,6,0,7201959
|
||||
1778270590.4299078,4.5000000000000036,48664536723,0,0,33273482,46360441877,6,0,7202908
|
||||
1778270590.9309673,4.2394014962593545,48664625259,0,0,33274821,46419468681,6,0,7203858
|
||||
1778270591.4319572,4.249999999999998,48664713367,0,0,33276155,46478433057,6,0,7204807
|
||||
1778270591.9329336,4.477611940298509,48664803025,0,0,33277513,46537459861,6,0,7205757
|
||||
1778270592.4339201,4.249999999999998,48664896215,0,0,33278924,46596486567,6,0,7206706
|
||||
1778270592.9348764,4.249999999999998,48664989107,0,0,33280330,46655513371,6,0,7207656
|
||||
1778270593.435878,3.759398496240607,48665081901,0,0,33281735,46714540077,6,0,7208605
|
||||
1778270593.9369287,4.2394014962593545,48665174991,0,0,33283144,46773566881,6,0,7209555
|
||||
1778270594.437938,4.726368159203975,48665267851,0,0,33284550,46832593587,6,0,7210504
|
||||
1778270594.938931,4.010025062656641,48665355925,0,0,33285882,46891620391,6,0,7211454
|
||||
1778270595.439929,4.477611940298509,48665445881,0,0,33287244,46950647097,6,0,7212403
|
||||
1778270595.9409099,4.249999999999998,48665536133,0,0,33288610,47009673901,6,0,7213352
|
||||
1778270596.4418619,4.488778054862841,48665625825,0,0,33289969,47068700607,6,0,7214301
|
||||
1778270596.942888,4.2394014962593545,48665715219,0,0,33291322,47127727411,6,0,7215251
|
||||
1778270597.4438486,4.249999999999998,48665803987,0,0,33292666,47186754117,6,0,7216200
|
||||
1778270597.9448183,4.714640198511166,48665896351,0,0,33294064,47245718591,6,0,7217150
|
||||
1778270598.4458015,4.488778054862841,48665986307,0,0,33295426,47304745297,6,0,7218099
|
||||
1778270598.946813,4.488778054862841,48666074381,0,0,33296759,47363772101,6,0,7219049
|
||||
1778270599.447804,3.759398496240607,48666163941,0,0,33298115,47422798807,6,0,7219998
|
||||
1778270599.9488237,4.488778054862841,48666253863,0,0,33299476,47481825611,6,0,7220948
|
||||
1778270600.4497793,4.488778054862841,48666342235,0,0,33300813,47540852317,6,0,7221897
|
||||
1778270600.9506955,4.477611940298509,48666430441,0,0,33302148,47599879121,6,0,7222846
|
||||
1778270601.4516587,4.726368159203975,48666519077,0,0,33303491,47658905827,6,0,7223795
|
||||
1778270601.952656,4.2394014962593545,48666607019,0,0,33304821,47717932631,6,0,7224745
|
||||
1778270602.4536614,4.249999999999998,48666695523,0,0,33306162,47776959337,6,0,7225694
|
||||
1778270602.954655,4.488778054862841,48666783861,0,0,33307499,47835923811,6,0,7226644
|
||||
1778270603.4556863,4.714640198511166,48666872233,0,0,33308837,47894950517,6,0,7227593
|
||||
1778270603.956686,4.2394014962593545,48666960835,0,0,33310178,47953977321,6,0,7228543
|
||||
1778270604.4576669,4.488778054862841,48667049339,0,0,33311518,48013004027,6,0,7229492
|
||||
1778270604.9587114,4.488778054862841,48667137875,0,0,33312858,48072030831,6,0,7230442
|
||||
1778270605.4596717,4.0000000000000036,48667226247,0,0,33314196,48131057537,6,0,7231391
|
||||
1778270605.9606273,4.477611940298509,48667315377,0,0,33315545,48190084341,6,0,7232341
|
||||
1778270606.4616024,4.249999999999998,48667404145,0,0,33316888,48249111047,6,0,7233290
|
||||
1778270606.9626193,4.477611940298509,48667493209,0,0,33318236,48308137851,6,0,7234240
|
||||
1778270607.4636042,4.249999999999998,48667581449,0,0,33319572,48367164557,6,0,7235188
|
||||
1778270607.9646268,4.0000000000000036,48667669721,0,0,33320909,48426191361,6,0,7236138
|
||||
1778270608.465636,3.7688442211055273,48667758027,0,0,33322245,48485218067,6,0,7237087
|
||||
1778270608.9666252,4.488778054862841,48667848411,0,0,33323614,48544244871,6,0,7238037
|
||||
1778270609.4676592,4.0000000000000036,48667941799,0,0,33325028,48603271577,6,0,7238986
|
||||
1778270609.968623,3.759398496240607,48668030995,0,0,33326378,48662236051,6,0,7239936
|
||||
1778270610.469593,4.249999999999998,48668119367,0,0,33327716,48721262757,6,0,7240885
|
||||
1778270610.9706469,3.759398496240607,48668208035,0,0,33329058,48780289561,6,0,7241835
|
||||
1778270611.4715943,4.249999999999998,48668296671,0,0,33330400,48839316267,6,0,7242784
|
||||
1778270611.9725301,4.0000000000000036,48668387055,0,0,33331767,48898343071,6,0,7243734
|
||||
1778270612.4735045,3.5175879396984966,48668477143,0,0,33333131,48957369777,6,0,7244683
|
||||
1778270612.974479,4.010025062656641,48668565943,0,0,33334475,49016396581,6,0,7245632
|
||||
1778270613.475469,4.2394014962593545,48668654381,0,0,33335815,49075423287,6,0,7246581
|
||||
1778270613.9764018,3.990024937655856,48668742917,0,0,33337155,49134450091,6,0,7247531
|
||||
1778270614.4773831,4.249999999999998,48668831883,0,0,33338502,49193414467,6,0,7248480
|
||||
1778270614.9783618,4.2394014962593545,48668920089,0,0,33339837,49252441271,6,0,7249430
|
||||
1778270615.4793143,4.0000000000000036,48669008791,0,0,33341180,49311467977,6,0,7250379
|
||||
1778270615.980222,4.010025062656641,48669096799,0,0,33342510,49370494781,6,0,7251329
|
||||
1778270616.4811969,4.0000000000000036,48669185039,0,0,33343846,49429521487,6,0,7252278
|
||||
1778270616.9821985,4.488778054862841,48669273905,0,0,33345192,49488548291,6,0,7253227
|
||||
1778270617.4831748,4.0000000000000036,48669362673,0,0,33346536,49547574997,6,0,7254176
|
||||
1778270617.9841936,3.759398496240607,48669451407,0,0,33347879,49606601801,6,0,7255126
|
||||
1778270618.4851687,4.010025062656641,48669539515,0,0,33349214,49665566177,6,0,7256075
|
||||
1778270618.9861114,4.2394014962593545,48669628777,0,0,33350564,49724592981,6,0,7257025
|
||||
1778270619.4870958,4.0000000000000036,48669717281,0,0,33351905,49783619687,6,0,7257974
|
||||
1778270619.9880707,4.010025062656641,48669807269,0,0,33353266,49842646491,6,0,7258924
|
||||
1778270620.489008,4.477611940298509,48669896895,0,0,33354624,49901673197,6,0,7259873
|
||||
1778270620.9899588,4.0000000000000036,48669985629,0,0,33355965,49960700001,6,0,7260822
|
||||
1778270621.4909213,3.5175879396984966,48670073539,0,0,33357298,50019726707,6,0,7261771
|
||||
1778270621.991924,4.249999999999998,48670163131,0,0,33358652,50078753511,6,0,7262721
|
||||
1778270622.4928935,4.0000000000000036,48670252163,0,0,33360001,50137780217,6,0,7263670
|
||||
1778270622.9939134,3.7688442211055273,48670340435,0,0,33361338,50196744691,6,0,7264620
|
||||
1778270623.4949007,4.2394014962593545,48670429071,0,0,33362680,50255771397,6,0,7265569
|
||||
1778270623.9958563,4.0000000000000036,48670517079,0,0,33364011,50314798201,6,0,7266519
|
||||
1778270624.4968596,4.249999999999998,48670605979,0,0,33365357,50373824907,6,0,7267468
|
||||
1778270624.9978244,3.759398496240607,48670695175,0,0,33366708,50432851711,6,0,7268418
|
||||
1778270625.4987783,4.010025062656641,48670783481,0,0,33368044,50491878417,6,0,7269367
|
||||
1778270625.999734,4.0000000000000036,48670871357,0,0,33369374,50550905221,6,0,7270316
|
||||
1778270626.5007434,4.477611940298509,48670959663,0,0,33370711,50609931927,6,0,7271265
|
||||
1778270627.0017157,3.2745591939546626,48671048991,0,0,33372064,50668958731,6,0,7272215
|
||||
1778270627.5026803,4.010025062656641,48671138017,0,0,33373412,50727923149,6,0,7273165
|
||||
1778270628.0036728,4.477611940298509,48671228665,0,0,33374784,50786949953,6,0,7274115
|
||||
1778270628.504654,4.0000000000000036,48671318951,0,0,33376151,50845976659,6,0,7275064
|
||||
1778270629.0056589,3.7688442211055273,48671407355,0,0,33377489,50905003463,6,0,7276014
|
||||
1778270629.5066588,4.477611940298509,48671495925,0,0,33378829,50964030169,6,0,7276963
|
||||
1778270630.0076284,4.2394014962593545,48671584065,0,0,33380163,51023056973,6,0,7277913
|
||||
1778270630.5086179,3.5264483627204024,48671673229,0,0,33381514,51082083679,6,0,7278862
|
||||
1778270631.0096092,4.0000000000000036,48671762161,0,0,33382859,51141110483,6,0,7279811
|
||||
1778270631.5105746,4.0000000000000036,48671850401,0,0,33384195,51200137189,6,0,7280760
|
||||
1778270632.0115623,4.249999999999998,48671941115,0,0,33385568,51259163993,6,0,7281710
|
||||
1778270632.5125597,4.477611940298509,48672034701,0,0,33386985,51318190699,6,0,7282659
|
||||
1778270633.0135367,4.010025062656641,48672125481,0,0,33388360,51377155173,6,0,7283609
|
||||
1778270633.514507,4.2394014962593545,48672214381,0,0,33389706,51436181879,6,0,7284558
|
||||
1778270634.015505,4.2394014962593545,48672303049,0,0,33391048,51495208683,6,0,7285508
|
||||
1778270634.516537,4.010025062656641,48672392543,0,0,33392403,51554235389,6,0,7286457
|
||||
1778270635.0175493,4.466501240694787,48672481013,0,0,33393742,51613262193,6,0,7287407
|
||||
1778270635.5185328,4.0000000000000036,48672569847,0,0,33395087,51672288899,6,0,7288356
|
||||
1778270636.0194833,4.249999999999998,48672658779,0,0,33396432,51731315703,6,0,7289306
|
||||
1778270636.5204585,4.0000000000000036,48672746755,0,0,33397765,51790342409,6,0,7290254
|
||||
1778270637.021408,4.249999999999998,48672836215,0,0,33399118,51849369213,6,0,7291204
|
||||
1778270637.522411,4.2394014962593545,48672925049,0,0,33400464,51908395919,6,0,7292153
|
||||
1778270638.0233717,4.010025062656641,48673014245,0,0,33401814,51967360393,6,0,7293103
|
||||
1778270638.5243185,4.2394014962593545,48673102947,0,0,33403157,52026387099,6,0,7294052
|
||||
1778270639.025326,4.0000000000000036,48673192077,0,0,33404506,52085413903,6,0,7295002
|
||||
1778270639.5263002,4.0000000000000036,48673281307,0,0,33405856,52144440609,6,0,7295951
|
||||
1778270640.0273383,4.020100502512558,48673370239,0,0,33407203,52203467413,6,0,7296901
|
||||
1778270640.5284667,4.2394014962593545,48673459337,0,0,33408552,52262494119,6,0,7297850
|
||||
1778270641.0294502,3.7688442211055273,48673548335,0,0,33409899,52321520923,6,0,7298800
|
||||
1778270641.5304134,4.477611940298509,48673637169,0,0,33411243,52380547629,6,0,7299749
|
||||
1778270642.0314236,4.2394014962593545,48673725375,0,0,33412578,52439574433,6,0,7300699
|
||||
1778270642.5324569,4.010025062656641,48673813945,0,0,33413920,52498601139,6,0,7301648
|
||||
1778270643.0334523,1.2886597938144284,48673902613,0,0,33415261,52557627943,6,0,7302598
|
||||
1778270643.534454,3.0303030303030276,48673991117,0,0,33416601,52616654649,6,0,7303547
|
||||
1778270644.0354507,4.249999999999998,48674079323,0,0,33417937,52675681453,6,0,7304497
|
||||
1778270644.5364473,3.5175879396984966,48674167563,0,0,33419272,52734708159,6,0,7305445
|
||||
1778270645.0374596,3.037974683544309,48674256099,0,0,33420613,52793734963,6,0,7306395
|
||||
1778270645.5384262,4.249999999999998,48674344933,0,0,33421958,52852761669,6,0,7307344
|
||||
1778270646.0393918,4.0000000000000036,48674433799,0,0,33423303,52911726143,6,0,7308294
|
||||
1778270646.5404067,4.2394014962593545,48674522501,0,0,33424646,52970752849,6,0,7309243
|
||||
1778270647.041363,4.010025062656641,48674610773,0,0,33425982,53029779653,6,0,7310193
|
||||
1778270647.5423565,4.2394014962593545,48674700003,0,0,33427333,53088806359,6,0,7311142
|
||||
1778270648.043377,4.0000000000000036,48674788341,0,0,33428669,53147833163,6,0,7312092
|
||||
1778270648.5448928,3.500000000000003,48674859417,0,0,33429736,53194705783,6,0,7312850
|
||||
1778270649.047792,0.5050505050505083,48674859711,0,0,33429739,53194706077,6,0,7312853
|
||||
1778270649.5507166,1.2499999999999956,48674859907,0,0,33429741,53194706273,6,0,7312855
|
||||
1778270650.053662,1.0025062656641603,48674860201,0,0,33429744,53194706567,6,0,7312858
|
||||
1778270650.556618,1.7456359102244412,48674860397,0,0,33429746,53194706763,6,0,7312860
|
||||
1778270651.0595233,1.253132832080206,48674860691,0,0,33429749,53194707057,6,0,7312863
|
||||
1778270651.562481,0.7537688442211032,48674860887,0,0,33429751,53194707253,6,0,7312865
|
||||
1778270652.065512,1.5075376884422065,48674861181,0,0,33429754,53194707547,6,0,7312868
|
||||
1778270652.568471,1.2499999999999956,48674861377,0,0,33429756,53194707743,6,0,7312870
|
||||
1778270653.0713758,1.2499999999999956,48674861671,0,0,33429759,53194708037,6,0,7312873
|
||||
1778270653.5739338,6.516290726817042,48674861769,0,0,33429760,53194708135,6,0,7312874
|
||||
|