test backend changes api snivver interfaces
All checks were successful
Build and Deploy MITM Webserver / build (push) Successful in 9s
All checks were successful
Build and Deploy MITM Webserver / build (push) Successful in 9s
This commit is contained in:
@@ -1,8 +1,9 @@
|
||||
from fastapi import APIRouter, HTTPException
|
||||
from pydantic import BaseModel, Field
|
||||
from typing import Dict, Any, List, Optional
|
||||
# src/routers/sniffer.py
|
||||
from fastapi import APIRouter, HTTPException, Query
|
||||
from pydantic import BaseModel, Field, root_validator
|
||||
from typing import Dict, Any, Optional
|
||||
|
||||
from src.network_sniffer import (
|
||||
from src.sniffer import (
|
||||
get_sniffer_status,
|
||||
start_afpacket_sniffer,
|
||||
stop_afpacket_sniffer,
|
||||
@@ -10,15 +11,25 @@ from src.network_sniffer import (
|
||||
|
||||
router = APIRouter()
|
||||
|
||||
|
||||
# ------------------------------
|
||||
# Pydantic Models
|
||||
# ------------------------------
|
||||
|
||||
class SnifferStartRequest(BaseModel):
|
||||
"""
|
||||
Request model for starting the sniffer on a specific bridge.
|
||||
Request model for starting the sniffer on a specific bridge OR interface.
|
||||
Exactly one of `bridge` or `interface` must be provided.
|
||||
"""
|
||||
bridge: str = Field(..., example="br0", description="Name of the Linux bridge to sniff on")
|
||||
bridge: Optional[str] = Field(None, example="br0", description="Name of the Linux bridge to sniff on")
|
||||
interface: Optional[str] = Field(None, example="eth0", description="Name of the network interface to sniff on")
|
||||
|
||||
@root_validator
|
||||
def exactly_one_target(cls, values):
|
||||
b, i = values.get("bridge"), values.get("interface")
|
||||
if bool(b) == bool(i):
|
||||
# either both set or both unset -> error
|
||||
raise ValueError("Exactly one of 'bridge' or 'interface' must be provided")
|
||||
return values
|
||||
|
||||
|
||||
class SnifferStartResponse(BaseModel):
|
||||
@@ -26,7 +37,8 @@ class SnifferStartResponse(BaseModel):
|
||||
Response model returned when sniffer starts successfully.
|
||||
"""
|
||||
started: bool = Field(..., description="Whether the sniffer was started successfully")
|
||||
bridge: str = Field(..., description="Bridge where the sniffer was started")
|
||||
target: str = Field(..., description="Target that was started (bridge or interface)")
|
||||
target_type: str = Field(..., description="Either 'bridge' or 'interface'")
|
||||
|
||||
|
||||
class SnifferStopResponse(BaseModel):
|
||||
@@ -34,13 +46,15 @@ class SnifferStopResponse(BaseModel):
|
||||
Response model returned when the sniffer stops successfully.
|
||||
"""
|
||||
stopped: bool = Field(..., description="Whether the sniffer was stopped successfully")
|
||||
target: Optional[str] = Field(None, description="Target stopped; null if global stop")
|
||||
target_type: Optional[str] = Field(None, description="'bridge' or 'interface' or None")
|
||||
|
||||
|
||||
class InterfaceSnifferStatus(BaseModel):
|
||||
"""
|
||||
Status of an individual interface monitored by the AF_PACKET sniffer.
|
||||
"""
|
||||
running: bool = Field(..., description="Whether the sniffer thread is active")
|
||||
running: bool = Field(..., description="Whether the sniffer thread/socket is active")
|
||||
exists: bool = Field(..., description="Whether the interface exists in /sys/class/net")
|
||||
up: bool = Field(..., description="Whether the interface is operationally UP")
|
||||
|
||||
@@ -57,27 +71,49 @@ class SnifferStatusResponse(BaseModel):
|
||||
# ------------------------------
|
||||
# Endpoints
|
||||
# ------------------------------
|
||||
|
||||
@router.post("/start", response_model=SnifferStartResponse)
|
||||
def sniffer_start(req: SnifferStartRequest):
|
||||
"""
|
||||
Start the AF_PACKET sniffer for the given bridge.
|
||||
Start the AF_PACKET sniffer for the given bridge OR interface.
|
||||
"""
|
||||
try:
|
||||
start_afpacket_sniffer(req.bridge)
|
||||
return SnifferStartResponse(started=True, bridge=req.bridge)
|
||||
if req.interface:
|
||||
start_afpacket_sniffer(req.interface, target_is_interface=True)
|
||||
return SnifferStartResponse(started=True, target=req.interface, target_type="interface")
|
||||
else:
|
||||
# req.bridge is guaranteed present by validator
|
||||
start_afpacket_sniffer(req.bridge, target_is_interface=False)
|
||||
return SnifferStartResponse(started=True, target=req.bridge, target_type="bridge")
|
||||
except Exception as exc:
|
||||
raise HTTPException(status_code=500, detail=f"Failed to start sniffer: {exc}")
|
||||
|
||||
|
||||
@router.post("/stop", response_model=SnifferStopResponse)
|
||||
def sniffer_stop():
|
||||
def sniffer_stop(
|
||||
bridge: Optional[str] = Query(None, description="If provided, stop sniffer sockets for this bridge"),
|
||||
interface: Optional[str] = Query(None, description="If provided, stop sniffer socket for this interface"),
|
||||
):
|
||||
"""
|
||||
Stop the AF_PACKET sniffer (if running).
|
||||
Stop the AF_PACKET sniffer.
|
||||
|
||||
- If no query params provided: stop the global sniffer thread and clear snapshot.
|
||||
- If `?interface=eth0` provided: stop sniffing on that interface only (close socket).
|
||||
- If `?bridge=br0` provided: stop snapshot/sockets associated with that bridge.
|
||||
"""
|
||||
try:
|
||||
if interface and bridge:
|
||||
raise HTTPException(status_code=400, detail="Only one of 'bridge' or 'interface' may be provided")
|
||||
if interface:
|
||||
stop_afpacket_sniffer(target=interface, target_is_interface=True)
|
||||
return SnifferStopResponse(stopped=True, target=interface, target_type="interface")
|
||||
if bridge:
|
||||
stop_afpacket_sniffer(target=bridge, target_is_interface=False)
|
||||
return SnifferStopResponse(stopped=True, target=bridge, target_type="bridge")
|
||||
# global stop
|
||||
stop_afpacket_sniffer()
|
||||
return SnifferStopResponse(stopped=True)
|
||||
return SnifferStopResponse(stopped=True, target=None, target_type=None)
|
||||
except HTTPException:
|
||||
raise
|
||||
except Exception as exc:
|
||||
raise HTTPException(status_code=500, detail=f"Failed to stop sniffer: {exc}")
|
||||
|
||||
@@ -96,4 +132,4 @@ def sniffer_status():
|
||||
}
|
||||
return SnifferStatusResponse(interfaces=typed)
|
||||
except Exception as exc:
|
||||
raise HTTPException(status_code=500, detail=f"Failed to query sniffer status: {exc}")
|
||||
raise HTTPException(status_code=500, detail=f"Failed to query sniffer status: {exc}")
|
||||
Reference in New Issue
Block a user