[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
|
@ -6,4 +6,8 @@ edition = "2021"
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
quicktap = { path = "../quicktap", version = "0.1.0" }
|
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::cidr::{IpInet, Ipv4Inet};
|
||||||
use quicktap::drivers::tun::TunDevice;
|
use quicktap::drivers::tun::TunDevice;
|
||||||
use quicktap::drivers::tungeneric::{GenericDriver, GenericInterface};
|
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() {
|
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,10 +14,14 @@ x25519-dalek = "2.0.0-pre.1"
|
||||||
rand = "0.8.5"
|
rand = "0.8.5"
|
||||||
hmac = "0.12.1"
|
hmac = "0.12.1"
|
||||||
chacha20poly1305 = "0.10.1"
|
chacha20poly1305 = "0.10.1"
|
||||||
|
build-info = "0.0.29"
|
||||||
|
|
||||||
[target.'cfg(unix)'.dependencies]
|
[target.'cfg(unix)'.dependencies]
|
||||||
tun = "0.5.4"
|
tun = "0.5.4"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
hex_lit = "0.1.1"
|
hex_lit = "0.1.1"
|
||||||
hex = "0.4.3"
|
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).
|
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).
|
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();
|
||||||
|
}
|
|
@ -15,4 +15,9 @@ pub use cidr;
|
||||||
|
|
||||||
pub mod drivers;
|
pub mod drivers;
|
||||||
pub mod qcrypto;
|
pub mod qcrypto;
|
||||||
pub mod noise;
|
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