[docs/cli][cli/pproc] add more documentation / restructure cli to put more routing stuff into the engine for crossplatformness
This commit is contained in:
parent
c410d7bf81
commit
b642112b4d
|
@ -7,3 +7,7 @@ edition = "2021"
|
|||
|
||||
[dependencies]
|
||||
quicktap = { path = "../quicktap", version = "0.1.0" }
|
||||
clap = { version = "4.0.29", features = ["derive"]}
|
||||
daemonize = "0.4.1"
|
||||
log = "0.4.17"
|
||||
simple_logger = "4.0.0"
|
|
@ -0,0 +1,20 @@
|
|||
# Quicktap CLI
|
||||
This is a WireGuard xplatform implementation for using [Quicktap Engine](../quicktap/README.md) with as many platforms as possible.
|
||||
|
||||
Here's a support table for the CLI:
|
||||
|
||||
| | IPv4 | IPv6 |
|
||||
|---------|---------------|---------------|
|
||||
| Linux | ✓ | ✓ |
|
||||
| NetBSD | ⚠<sup>‡</sup> | x<sup>‡</sup> |
|
||||
| MacOS | x<sup>†</sup> | x<sup>†</sup> |
|
||||
| Windows | x<sup>†</sup> | x<sup>†</sup> |
|
||||
|
||||
Key:
|
||||
- ✓ - Fully supported
|
||||
- ⚠ - Partially supported
|
||||
- x - Not supported
|
||||
- ‡ - Support planned
|
||||
- † - Unmaintained
|
||||
|
||||
Help is wanted! Improve existing implementations or pick out an unmaintained or unsupported one and help the project get better.
|
|
@ -0,0 +1,9 @@
|
|||
use clap::{ArgAction, Parser};
|
||||
|
||||
#[derive(Parser)]
|
||||
#[command(author = "The Quicktap Maintainers", version, about = "A userspace WireGuard implementation written in Rust", long_about = None)]
|
||||
pub struct Cli {
|
||||
#[arg(short, long, action = ArgAction::SetTrue)]
|
||||
pub foreground: bool,
|
||||
pub interface_name: String
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
pub enum PacketThreadCommand {
|
||||
UpdateConfig(UpdateConfigCommand),
|
||||
Stop
|
||||
}
|
||||
|
||||
pub struct UpdateConfigCommand {}
|
|
@ -1,28 +0,0 @@
|
|||
use std::error::Error;
|
||||
use std::io;
|
||||
use std::net::Ipv4Addr;
|
||||
|
||||
use quicktap::cidr::{IpInet, Ipv4Inet};
|
||||
use quicktap::drivers::tun::TunDevice;
|
||||
use quicktap::drivers::tungeneric::{GenericDriver, GenericInterface};
|
||||
|
||||
pub fn packet_eventloop() -> Result<(), Box<dyn Error>> {
|
||||
let mut device = TunDevice::new(&GenericInterface {
|
||||
addresses: vec![IpInet::V4(Ipv4Inet::new(Ipv4Addr::new(10, 19, 2, 2), 16).unwrap())],
|
||||
mtu: None,
|
||||
name: "ela1".to_string(),
|
||||
}).unwrap();
|
||||
loop {
|
||||
let packet = match device.read() {
|
||||
Ok(p) => Some(p),
|
||||
Err(e) => match e.kind() {
|
||||
io::ErrorKind::WouldBlock => None,
|
||||
_ => return Err(e.into())
|
||||
}
|
||||
};
|
||||
|
||||
if let Some(p) = packet {
|
||||
println!("{:?}", p.header);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,13 +1,142 @@
|
|||
use std::net::Ipv4Addr;
|
||||
use std::collections::HashMap;
|
||||
use std::fs::File;
|
||||
use std::io;
|
||||
use std::io::Read;
|
||||
use std::net::{Ipv4Addr, SocketAddr};
|
||||
use std::os::unix::net::{UnixListener, UnixStream};
|
||||
use std::path::Path;
|
||||
use std::sync::mpsc::channel;
|
||||
use std::thread::{sleep, spawn};
|
||||
use std::time::Duration;
|
||||
|
||||
use clap::Parser;
|
||||
use daemonize::Daemonize;
|
||||
use log::{error, info};
|
||||
|
||||
use quicktap::cidr::{IpInet, Ipv4Inet};
|
||||
use quicktap::drivers::tun::TunDevice;
|
||||
use quicktap::drivers::tungeneric::{GenericDriver, GenericInterface};
|
||||
|
||||
use crate::device::packet_eventloop;
|
||||
use crate::cli::Cli;
|
||||
use crate::command::PacketThreadCommand;
|
||||
use crate::pproc::packet_thread;
|
||||
|
||||
pub mod device;
|
||||
pub mod cli;
|
||||
pub mod pproc;
|
||||
pub mod command;
|
||||
|
||||
fn main() {
|
||||
packet_eventloop().unwrap();
|
||||
simple_logger::init().unwrap();
|
||||
|
||||
let args = Cli::parse();
|
||||
|
||||
info!("Hello, world! {}", quicktap::version());
|
||||
info!("Starting up");
|
||||
|
||||
if !args.foreground {
|
||||
info!("Forking to background");
|
||||
|
||||
let stdout = match File::create("/var/log/e4.log") {
|
||||
Ok(f) => f,
|
||||
Err(e) => {
|
||||
error!("Failed to open stdout file: {}", e);
|
||||
std::process::exit(8);
|
||||
}
|
||||
};
|
||||
let stderr = match File::create("/var/log/e4.err") {
|
||||
Ok(f) => f,
|
||||
Err(e) => {
|
||||
error!("Failed to open stderr file: {}", e);
|
||||
std::process::exit(9);
|
||||
}
|
||||
};
|
||||
|
||||
let daemon_opts = Daemonize::new()
|
||||
.stdout(stdout)
|
||||
.stderr(stderr);
|
||||
match daemon_opts.start() {
|
||||
Ok(_) => info!("Forked to background successfully"),
|
||||
Err(e) => {
|
||||
error!("Failed to daemonize quicktap-cli worker process: {}", e);
|
||||
std::process::exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
info!("Creating unconfigured device");
|
||||
|
||||
let mut device = match TunDevice::new(&GenericInterface {
|
||||
addresses: vec![],
|
||||
mtu: None,
|
||||
name: args.interface_name.clone(),
|
||||
}) {
|
||||
Ok(d) => d,
|
||||
Err(e) => {
|
||||
error!("Failed to create interface: {}", e);
|
||||
std::process::exit(2);
|
||||
}
|
||||
};
|
||||
|
||||
info!("Device created; opening listening socket");
|
||||
|
||||
let mut config_listener = match UnixListener::bind(format!("/var/run/{}.sock", args.interface_name)) {
|
||||
Ok(s) => s,
|
||||
Err(e) => {
|
||||
error!("Failed to open listen socket /var/run/{}.sock: {}", args.interface_name, e);
|
||||
std::process::exit(3);
|
||||
}
|
||||
};
|
||||
match config_listener.set_nonblocking(true) {
|
||||
Ok(_) => (),
|
||||
Err(e) => {
|
||||
error!("Failed to set stream as nonblocking: {}", e);
|
||||
std::process::exit(4);
|
||||
}
|
||||
};
|
||||
|
||||
info!("Spawning packet processor thread");
|
||||
|
||||
let (tx, rx) = channel::<PacketThreadCommand>();
|
||||
|
||||
let pproc_thread = spawn(|| {
|
||||
match packet_thread(device, rx) {
|
||||
Ok(_) => (),
|
||||
Err(e) => {
|
||||
error!("Error in pproc_thread: {}", e);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
sleep(Duration::from_secs(10));
|
||||
|
||||
match tx.send(PacketThreadCommand::Stop) {
|
||||
Ok(_) => (),
|
||||
Err(e) => {
|
||||
error!("Error sending stop command to packet thread: {}", e);
|
||||
std::process::exit(6);
|
||||
}
|
||||
}
|
||||
|
||||
info!("Waiting for packet thread to stop");
|
||||
match pproc_thread.join() {
|
||||
Ok(_) => (),
|
||||
Err(e) => {
|
||||
error!("Error joining thread: {:?}", e);
|
||||
std::process::exit(5);
|
||||
}
|
||||
}
|
||||
|
||||
info!("Cleaning up");
|
||||
|
||||
if Path::new(&format!("/var/run/{}.sock", args.interface_name)).exists() {
|
||||
match std::fs::remove_file(format!("/var/run/{}.sock", args.interface_name)) {
|
||||
Ok(_) => (),
|
||||
Err(e) => {
|
||||
error!("Failed to remove existing socket: {}", e);
|
||||
std::process::exit(7);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
info!("Cya!");
|
||||
}
|
||||
|
|
|
@ -0,0 +1,42 @@
|
|||
use std::error::Error;
|
||||
use std::io;
|
||||
use std::sync::mpsc::Receiver;
|
||||
|
||||
use log::{error, info};
|
||||
|
||||
use quicktap::drivers::tun::TunDevice;
|
||||
use quicktap::drivers::tungeneric::GenericDriver;
|
||||
|
||||
use crate::command::PacketThreadCommand;
|
||||
|
||||
pub fn packet_thread(mut device: TunDevice, rx: Receiver<PacketThreadCommand>) -> Result<(), Box<dyn Error>> {
|
||||
loop {
|
||||
// Check command channel
|
||||
let command = match rx.try_recv() {
|
||||
Ok(d) => Some(d),
|
||||
Err(e) if matches!(e, std::sync::mpsc::TryRecvError::Empty) => None,
|
||||
Err(e) => return Err(e.into())
|
||||
};
|
||||
if let Some(cmd) = command {
|
||||
if let PacketThreadCommand::Stop = cmd {
|
||||
info!("packet thread: recieved command to stop by control process");
|
||||
return Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
let packet = match device.read() {
|
||||
Ok(p) => Some(p),
|
||||
Err(e) => match e.kind() {
|
||||
io::ErrorKind::WouldBlock => None,
|
||||
_ => {
|
||||
error!("Error while reading packets from interface: {}", e);
|
||||
return Err(e.into());
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
if let Some(p) = packet {
|
||||
info!("recv_packet_on_tun {:?}", p.header);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -14,6 +14,7 @@ x25519-dalek = "2.0.0-pre.1"
|
|||
rand = "0.8.5"
|
||||
hmac = "0.12.1"
|
||||
chacha20poly1305 = "0.10.1"
|
||||
build-info = "0.0.29"
|
||||
|
||||
[target.'cfg(unix)'.dependencies]
|
||||
tun = "0.5.4"
|
||||
|
@ -21,3 +22,6 @@ tun = "0.5.4"
|
|||
[dev-dependencies]
|
||||
hex_lit = "0.1.1"
|
||||
hex = "0.4.3"
|
||||
|
||||
[build-dependencies]
|
||||
build-info-build = "0.0.29"
|
|
@ -1,4 +1,4 @@
|
|||
# Quicktap
|
||||
# Quicktap Engine
|
||||
Quicktap is a (hopefully) standard-compliant Rust implementation of the [WireGuard protocol](https://wireguard.org).
|
||||
|
||||
It was designed to be a simpler alternative to Cloudflare's [boringtun](https://github.com/cloudflare/boringtun).
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
fn main() {
|
||||
build_info_build::build_script();
|
||||
}
|
|
@ -16,3 +16,8 @@ pub use cidr;
|
|||
pub mod drivers;
|
||||
pub mod qcrypto;
|
||||
pub mod noise;
|
||||
|
||||
/// Gets the compile-time versioning information for the engine build.
|
||||
pub const fn version() -> &'static str {
|
||||
build_info::format!("quicktap engine v{} ({}) built at {} with {}", $.crate_info.version, $.version_control.unwrap().git().unwrap().commit_short_id, $.timestamp, $.compiler)
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue