backend: Begin server process work
The backend will be split into two processes: * The privileged daemon * The unprivileged web server These processes will communicate using JSON-RPC over a UNIX socket. The web server is unprivileged to mitigate the risk of vulnerabilities being exploited to gain control of the system. The privileged daemon will handle all actual firewall management. Additionally, the backend also acts as a command-line interface for communicating with the daemon. The application's main entry point determines which process to launch based on the name of the executable. This can be controlled, e.g. by creating symbolic links pointing to the binary, or using the `@` prefix in the `ExecStart` setting in a systemd unit. This first commit introduces the Rocket framework for the web process. Unfortunately, Rocket is rather inflexible in how it is started. It expects to have complete control of the `main` function, and does not provide any mechanism for passing data to its initialization routines. Thus, in order to configure it using command-line arguments, arguments have to be parsed inside Rocket's main function; they cannot be parsed ahead of time and passed in.backend
parent
4cae646778
commit
ed142322bd
|
@ -0,0 +1,4 @@
|
|||
/target/
|
||||
weywot-daemon
|
||||
weywot-web
|
||||
weywot-web.toml
|
File diff suppressed because it is too large
Load Diff
|
@ -3,6 +3,11 @@ name = "weywot"
|
|||
version = "0.1.0"
|
||||
edition = "2018"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
argh = "^0.1"
|
||||
figment = "^0.10"
|
||||
serde = "^1.0"
|
||||
|
||||
[dependencies.rocket]
|
||||
version = "^0.5.0-rc.1"
|
||||
features = ["json", "secrets", "tls"]
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
max_width = 79
|
|
@ -1,3 +1,39 @@
|
|||
mod server;
|
||||
|
||||
use std::env;
|
||||
use std::path::Path;
|
||||
|
||||
const NAME: &'static str = "weywot";
|
||||
|
||||
fn main() {
|
||||
println!("Hello, world!");
|
||||
let mut args = env::args();
|
||||
let arg0 = args.next();
|
||||
let command = Path::new(arg0.as_ref().map_or(NAME, |x| x.as_str()))
|
||||
.file_name()
|
||||
.map_or(NAME, |x| x.to_str().unwrap_or(NAME));
|
||||
match command {
|
||||
"weywot-daemon" => daemon_main(),
|
||||
"weywot-web" => web_main(),
|
||||
_ => cli_main(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Main entry point for the privileged daemon
|
||||
fn daemon_main() {
|
||||
/* start the privileged daemon */
|
||||
}
|
||||
|
||||
/// Main entry point for the web server
|
||||
fn web_main() {
|
||||
match server::main() {
|
||||
Ok(_) => {}
|
||||
Err(e) => {
|
||||
eprintln!("Failed to start web server: {}", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Main entry point for the CLI/REPL
|
||||
fn cli_main() {
|
||||
/* start the CLI */
|
||||
}
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Debug, Deserialize, Serialize)]
|
||||
pub struct Config {
|
||||
pub address: String,
|
||||
pub port: u16,
|
||||
}
|
||||
|
||||
impl Default for Config {
|
||||
fn default() -> Config {
|
||||
Config {
|
||||
address: "::".into(),
|
||||
port: 8998,
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,53 @@
|
|||
mod config;
|
||||
mod routes;
|
||||
use config::Config;
|
||||
|
||||
use argh::FromArgs;
|
||||
use rocket;
|
||||
use rocket::fairing::AdHoc;
|
||||
use rocket::figment::providers::{Env, Format, Serialized, Toml};
|
||||
use rocket::figment::Figment;
|
||||
|
||||
const DEFAULT_CONFIG: &'static str = "weywot-web.toml";
|
||||
|
||||
#[derive(Debug, FromArgs)]
|
||||
/// Weywot web server
|
||||
struct Arguments {
|
||||
/// bind address
|
||||
#[argh(option)]
|
||||
address: Option<String>,
|
||||
|
||||
/// bind port
|
||||
#[argh(option)]
|
||||
port: Option<u16>,
|
||||
|
||||
/// configuration file
|
||||
#[argh(option, short = 'c')]
|
||||
config: Option<String>,
|
||||
}
|
||||
|
||||
#[rocket::main]
|
||||
pub async fn main() -> Result<(), rocket::Error> {
|
||||
let args: Arguments = argh::from_env();
|
||||
let mut figment = Figment::from(rocket::Config::default())
|
||||
.merge(Serialized::defaults(Config::default()))
|
||||
.merge(Toml::file(
|
||||
args.config.as_ref().map_or(DEFAULT_CONFIG, |x| x.as_str()),
|
||||
))
|
||||
.merge(Env::prefixed("WEYWOT_WEB_").global())
|
||||
.merge(("ident", "Weywot/web"));
|
||||
if let Some(address) = args.address {
|
||||
figment = figment.merge(("address", address));
|
||||
}
|
||||
if let Some(port) = args.port {
|
||||
figment = figment.merge(("port", port));
|
||||
}
|
||||
|
||||
rocket::custom(figment)
|
||||
.mount("/", rocket::routes![routes::hello::hello])
|
||||
.attach(AdHoc::config::<Config>())
|
||||
.ignite()
|
||||
.await?
|
||||
.launch()
|
||||
.await
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
use rocket;
|
||||
|
||||
#[rocket::get("/")]
|
||||
pub async fn hello() -> &'static str {
|
||||
"Hello, world!"
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
pub mod hello;
|
Loading…
Reference in New Issue