summaryrefslogtreecommitdiffhomepage
path: root/ci/ios/test-router/raas/src/web/firewall.rs
blob: 0bba64a85986d193324b3c2253ac01364f551825 (plain)
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
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
use std::{collections::BTreeSet, net::IpAddr};

use axum::{
    body::Body,
    extract::{Json, Path, State},
    http::{header, StatusCode},
    response::IntoResponse,
};
use uuid::Uuid;

#[derive(serde::Deserialize, Clone)]
pub struct NewCapture {
    pub label: Uuid,
}

pub async fn start(
    State(state): State<super::State>,
    Json(capture): Json<NewCapture>,
) -> impl IntoResponse {
    let label = capture.label;

    let result = async {
        let mut state = state.capture.lock().await;
        state.start(label).await?;
        log::info!("Started capture for label {label}");
        Ok(())
    }
    .await;

    respond_with_result(result, StatusCode::OK)
}

pub async fn stop(Path(label): Path<Uuid>, State(state): State<super::State>) -> impl IntoResponse {
    let result = async {
        let mut state = state.capture.lock().await;
        state.stop(label).await?;
        log::info!("Stopped capture for label {label}");
        Ok(())
    }
    .await;

    respond_with_result(result, StatusCode::OK)
}

pub async fn get(Path(label): Path<Uuid>, State(state): State<super::State>) -> impl IntoResponse {
    let state = state.capture.lock().await;

    let stream = match state.get(label).await {
        Ok(stream) => stream,
        Err(err) => {
            return (StatusCode::SERVICE_UNAVAILABLE, format!("{err}\n")).into_response();
        }
    };

    let body = Body::from_stream(tokio_util::io::ReaderStream::new(stream));
    let mut headers = header::HeaderMap::new();
    headers.insert(
        header::CONTENT_TYPE,
        header::HeaderValue::from_static("application/pcap"),
    );
    headers.insert(
        header::CONTENT_DISPOSITION,
        header::HeaderValue::from_static("attachment; filename=\"dump.pcap\""),
    );

    (headers, body).into_response()
}

pub async fn parse(
    Path(label): Path<Uuid>,
    State(state): State<super::State>,
    Json(host_addrs): Json<BTreeSet<IpAddr>>,
) -> impl IntoResponse {
    let state = state.capture.lock().await;

    let stream = match state.get(label).await {
        Ok(stream) => stream,
        Err(err) => {
            return (StatusCode::SERVICE_UNAVAILABLE, format!("{err}\n")).into_response();
        }
    };

    match crate::capture::parse_pcap(stream, host_addrs).await {
        Ok(parsed_connections) => (StatusCode::OK, Json(parsed_connections)).into_response(),
        Err(err) => (StatusCode::SERVICE_UNAVAILABLE, format!("{err}\n")).into_response(),
    }
}

fn respond_with_result(result: anyhow::Result<()>, success_code: StatusCode) -> impl IntoResponse {
    match result {
        Ok(_) => (success_code, String::new()),
        Err(err) => (StatusCode::SERVICE_UNAVAILABLE, format!("{err}\n")),
    }
}