Skip to content

Commit

Permalink
Merge pull request #1047 from NordSecurity/LLT-5882_refactor_teliod_c…
Browse files Browse the repository at this point in the history
…gi_structure

LLT-5882: Refactor teliod cgi structure
  • Loading branch information
lcruz99 authored Jan 8, 2025
2 parents 0fdaa9c + 7ee792d commit c3b53b0
Show file tree
Hide file tree
Showing 15 changed files with 230 additions and 99 deletions.
Empty file added .unreleased/LLT-5882
Empty file.
5 changes: 5 additions & 0 deletions Justfile
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,11 @@ black fix="false":
pylint:
docker run --rm -t -v$(pwd):/code 'ubuntu:22.04' sh -c "apt-get update && apt-get -y install python3-pip && cd code && pip3 install --no-deps -r requirements.txt && pipenv install --system && cd nat-lab && pipenv install --system && pylint -f colorized . --ignore telio_bindings.py"

# Start a dev web cgi server, for local teliod cgi development
web:
@echo "Go to http://127.0.0.1:8080/cgi-bin/teliod.cgi"
python3 -m http.server --cgi -d $(pwd)/contrib/http_root/ -b 127.0.0.1 8080

_udeps-install: _nightly-install
cargo +{{ nightly }} install cargo-udeps@0.1.47 --locked

Expand Down
File renamed without changes.
4 changes: 3 additions & 1 deletion clis/teliod/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -42,4 +42,6 @@ rand = "0.8.5"
serial_test = "3.2.0"

[features]
qnap = ["const_format", "rust-cgi"]
cgi = ["const_format", "rust-cgi"]
qnap = ["cgi"]

48 changes: 22 additions & 26 deletions clis/teliod/src/qnap.rs → clis/teliod/src/cgi/api.rs
Original file line number Diff line number Diff line change
@@ -1,28 +1,25 @@
use core::str;
use std::{
fs,
io::Write,
process::{Command, Stdio},
str,
};

use const_format::concatcp;
use rust_cgi::{http::Method, http::StatusCode, text_response, Request, Response};
use rust_cgi::{
http::{Method, StatusCode},
text_response, Response,
};

use crate::{
command_listener::CommandResponse,
config::{TeliodDaemonConfig, TeliodDaemonConfigPartial},
ClientCmd, DaemonSocket, TeliodError, TIMEOUT_SEC,
};

const QPKG_DIR: &str = "/share/CACHEDEV1_DATA/.qpkg/NordSecurityMeshnet";
const TELIOD_BIN: &str = concatcp!(QPKG_DIR, "/teliod");
const MESHNET_LOG: &str = concatcp!(QPKG_DIR, "/meshnet.log");
const TELIOD_LOG: &str = "/var/log/teliod.log";

#[cfg(not(test))]
const TELIOD_CFG: &str = concatcp!(QPKG_DIR, "/teliod.cfg");
#[cfg(test)]
use tests::TELIOD_CFG;
use super::{
constants::{MESHNET_LOG, TELIOD_BIN, TELIOD_CFG, TELIOD_LOG},
CgiRequest,
};

macro_rules! teliod_blocking_query {
($command:expr) => {{
Expand All @@ -37,26 +34,26 @@ macro_rules! teliod_blocking_query {
}};
}

pub(crate) fn handle_request(request: Request) -> Response {
match (request.method(), request.uri().query()) {
(&Method::POST, _) => start_daemon(),
(&Method::DELETE, _) => stop_daemon(),
(&Method::PATCH, _) => {
pub(crate) fn handle_api(request: &CgiRequest) -> Option<Response> {
match (request.method(), request.route()) {
(&Method::POST, "" | "/") => Some(start_daemon()),
(&Method::DELETE, "" | "/") => Some(stop_daemon()),
(&Method::PATCH, "" | "/") => {
let body = match str::from_utf8(request.body()) {
Ok(body) => body,
Err(error) => {
return text_response(
return Some(text_response(
StatusCode::BAD_REQUEST,
format!("Invalid UTF-8 in request body: {}", error),
)
))
}
};
update_config(body)
Some(update_config(body))
}
(&Method::GET, Some("info=get-status")) => get_status(),
(&Method::GET, Some("info=get-teliod-logs")) => get_teliod_logs(),
(&Method::GET, Some("info=get-meshnet-logs")) => get_meshnet_logs(),
(_, _) => text_response(StatusCode::BAD_REQUEST, "Invalid request."),
(&Method::GET, "/get-status") => Some(get_status()),
(&Method::GET, "/get-teliod-logs") => Some(get_teliod_logs()),
(&Method::GET, "/get-meshnet-logs") => Some(get_meshnet_logs()),
(_, _) => Some(text_response(StatusCode::BAD_REQUEST, "Invalid request.")),
}
}

Expand Down Expand Up @@ -237,12 +234,11 @@ mod tests {

use super::{update_config, TeliodDaemonConfig};
use crate::{
cgi::constants::TELIOD_CFG,
config::{InterfaceConfig, MqttConfig, Percentage},
configure_interface::InterfaceConfigurationProvider,
};

pub const TELIOD_CFG: &str = "/tmp/teliod_config.json";

#[test]
#[serial]
fn test_update_config() {
Expand Down
15 changes: 15 additions & 0 deletions clis/teliod/src/cgi/constants.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
use const_format::concatcp;

#[cfg(feature = "qnap")]
pub const APP_DIR: &str = "/share/CACHEDEV1_DATA/.qpkg/NordSecurityMeshnet";
#[cfg(not(feature = "qnap"))]
pub const APP_DIR: &str = concat!(env!("CARGO_MANIFEST_DIR"), "/target/debug");

pub const TELIOD_BIN: &str = concatcp!(APP_DIR, "/teliod");
pub const MESHNET_LOG: &str = concatcp!(APP_DIR, "/meshnet.log");
pub const TELIOD_LOG: &str = "/var/log/teliod.log";

#[cfg(not(test))]
pub const TELIOD_CFG: &str = concatcp!(APP_DIR, "/teliod.cfg");
#[cfg(test)]
pub const TELIOD_CFG: &str = "/tmp/teliod_config.json";
73 changes: 73 additions & 0 deletions clis/teliod/src/cgi/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
use std::{env::var, ops::Deref};

use rust_cgi::{http::StatusCode, text_response, Request, Response};

mod api;
pub(crate) mod constants;

pub struct CgiRequest {
pub inner: Request,
route: String,
}

impl CgiRequest {
fn new(inner: Request) -> Self {
Self {
inner,
route: var("PATH_INFO").unwrap_or_default(),
}
}

pub fn route(&self) -> &str {
&self.route
}
}

impl Deref for CgiRequest {
type Target = Request;
fn deref(&self) -> &Self::Target {
&self.inner
}
}

pub fn handle_request(request: Request) -> Response {
let request = CgiRequest::new(request);

if let Some(response) = api::handle_api(&request) {
#[cfg(debug_assertions)]
let response = trace_request(&request, &response).unwrap_or(text_response(
StatusCode::INTERNAL_SERVER_ERROR,
"Tracing request failed.",
));
return response;
}

text_response(StatusCode::BAD_REQUEST, "Invalid request.")
}

#[cfg(debug_assertions)]
fn trace_request(request: &CgiRequest, response: &Response) -> Option<Response> {
use std::{env::vars, fmt::Write};
let mut msg = String::new();
let _ = writeln!(
&mut msg,
"ENVIRONMENT:\n{:#?}\n",
vars().collect::<Vec<_>>(),
);
let _ = writeln!(
&mut msg,
"REQUEST:\nmethod: {:?}\nuri: {:?}\npath: {:?}\nroute: {:?}\nquery: {:?}\n",
request.method(),
request.uri(),
request.uri().path(),
request.route(),
request.uri().query(),
);
let _ = writeln!(
&mut msg,
"RESPONSE:\nstatus_code: {:?}\nbody: {:?}\n",
response.status(),
std::str::from_utf8(response.body()).unwrap_or("[Error] Response with invalid UTF-8."),
);
Some(text_response(StatusCode::OK, msg))
}
16 changes: 8 additions & 8 deletions clis/teliod/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,15 @@ use tokio::{
};
use tracing::{debug, error};

#[cfg(feature = "cgi")]
mod cgi;
mod command_listener;
mod comms;
mod config;
mod configure_interface;
mod core_api;
mod daemon;
mod nc;
#[cfg(feature = "qnap")]
mod qnap;

use crate::{
command_listener::CommandResponse,
Expand Down Expand Up @@ -50,9 +50,9 @@ enum Cmd {
Daemon { config_path: String },
#[clap(flatten)]
Client(ClientCmd),
#[cfg(feature = "qnap")]
#[cfg(feature = "cgi")]
#[clap(about = "Receive and parse http requests")]
QnapCgi,
Cgi,
}

#[derive(Debug, ThisError)]
Expand All @@ -63,7 +63,7 @@ enum TeliodError {
InvalidCommand(String),
#[error("Invalid response received: {0}")]
InvalidResponse(String),
#[error("Client failed to receive response in {TIMEOUT_SEC}")]
#[error("Client failed to receive response in {TIMEOUT_SEC}s")]
ClientTimeoutError,
#[error("Broken signal stream")]
BrokenSignalStream,
Expand Down Expand Up @@ -149,9 +149,9 @@ async fn main() -> Result<(), TeliodError> {
Err(TeliodError::DaemonIsNotRunning)
}
}
#[cfg(feature = "qnap")]
Cmd::QnapCgi => {
rust_cgi::handle(qnap::handle_request);
#[cfg(feature = "cgi")]
Cmd::Cgi => {
rust_cgi::handle(cgi::handle_request);
Ok(())
}
}
Expand Down
1 change: 1 addition & 0 deletions contrib/http_root/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
**/*.log
17 changes: 17 additions & 0 deletions contrib/http_root/cgi-bin/teliod.cgi
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#!/usr/bin/env bash

set -eu -o pipefail

fail() {
cat $DEV_DIR/cargo.log
exit 0
}

DEV_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
BIN_DIR="$(realpath $DEV_DIR/../../../target/debug/)"

cargo build -F cgi -p teliod >"$DEV_DIR/cargo.log" 2>&1 || fail

export PATH=$BIN_DIR:$PATH

exec teliod cgi
2 changes: 1 addition & 1 deletion qnap/build_sign.csv
Original file line number Diff line number Diff line change
@@ -1 +1 @@
,/NordSecMeshnet.sh,
,/NordSecurityMeshnet.sh,
2 changes: 1 addition & 1 deletion qnap/qpkg.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ QPKG_LICENSE="GPL-3.0-only"
# Preferred number in start/stop sequence.
QPKG_RC_NUM="101"
# Init-script used to control the start and stop of the installed application.
QPKG_SERVICE_PROGRAM="NordSecMeshnet.sh"
QPKG_SERVICE_PROGRAM="NordSecurityMeshnet.sh"

# Optional 1 is enable. Path of starting/ stopping shall script. (no start/stop on App Center)
#QPKG_DISABLE_APPCENTER_UI_SERVICE=1
Expand Down
61 changes: 0 additions & 61 deletions qnap/shared/NordSecMeshnet.sh

This file was deleted.

Loading

0 comments on commit c3b53b0

Please sign in to comment.