[docs/cli][cli/pproc] add more documentation / restructure cli to put more routing stuff into the engine for crossplatformness

This commit is contained in:
core 2022-12-21 12:26:10 -05:00
parent c410d7bf81
commit b642112b4d
Signed by: core
GPG Key ID: FDBF740DADDCEECF
11 changed files with 230 additions and 36 deletions

View File

@ -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"

20
quicktap-cli/README.md Normal file
View File

@ -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.

9
quicktap-cli/src/cli.rs Normal file
View File

@ -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
}

View File

@ -0,0 +1,6 @@
pub enum PacketThreadCommand {
UpdateConfig(UpdateConfigCommand),
Stop
}
pub struct UpdateConfigCommand {}

View File

@ -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);
}
}
}

View File

@ -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!");
}

42
quicktap-cli/src/pproc.rs Normal file
View File

@ -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);
}
}
}

View File

@ -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"

View File

@ -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).

3
quicktap/build.rs Normal file
View File

@ -0,0 +1,3 @@
fn main() {
build_info_build::build_script();
}

View File

@ -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)
}