From c12c26069665ad85362f8501d1d496da345bd93b Mon Sep 17 00:00:00 2001 From: Evan Pratten Date: Tue, 1 Aug 2023 20:05:28 -0400 Subject: [PATCH] wip --- Cargo.toml | 58 +-------------------- libs/easy-tun/Cargo.toml | 20 +++++++ libs/easy-tun/README.md | 0 libs/easy-tun/src/lib.rs | 110 +++++++++++++++++++++++++++++++++++++++ protomask/Cargo.toml | 56 ++++++++++++++++++++ 5 files changed, 188 insertions(+), 56 deletions(-) create mode 100644 libs/easy-tun/Cargo.toml create mode 100644 libs/easy-tun/README.md create mode 100644 libs/easy-tun/src/lib.rs create mode 100644 protomask/Cargo.toml diff --git a/Cargo.toml b/Cargo.toml index 37458a9..ad09f92 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,56 +1,2 @@ -[package] -name = "protomask" -version = "0.2.0" -authors = ["Evan Pratten "] -edition = "2021" -description = "A user space NAT64 implementation" -readme = "README.md" -homepage = "https://github.com/ewpratten/protomask" -documentation = "https://docs.rs/protomask" -repository = "https://github.com/ewpratten/protomask" -license = "GPL-3.0" -keywords = [] -categories = [] - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html -[dependencies] -protomask-tun = { path = "protomask-tun", version = "0.1.0" } -tokio = { version = "1.29.1", features = [ - "macros", - "rt-multi-thread", - # "process", - "sync" -] } -clap = { version = "4.3.11", features = ["derive"] } -serde = { version = "1.0.171", features = ["derive"] } -ipnet = { version = "2.8.0", features = ["serde"] } -hyper = { version = "0.14.27", features = ["server", "http1", "tcp"] } -owo-colors = { version = "3.5.0", features = ["supports-colors"] } -toml = "0.7.6" -log = "0.4.19" -fern = "0.6.2" -serde_path_to_error = "0.1.13" -thiserror = "1.0.43" -tun-tap = "0.1.3" -bimap = "0.6.3" -pnet_packet = "0.34.0" -rtnetlink = "0.13.0" -futures = "0.3.28" -prometheus = "0.13.3" -lazy_static = "1.4.0" - -[[bin]] -name = "protomask" -path = "src/cli/main.rs" - -[package.metadata.deb] -section = "network" -assets = [ - ["target/release/protomask", "/usr/local/bin/protomask", "755"], - ["./protomask.toml", "/etc/protomask.toml", "644"], - ["README.md", "usr/share/doc/protomask/README.md", "644"] -] -conf-files = ["/etc/protomask.toml"] -depends = [] -maintainer-scripts = "./debian/" -systemd-units = { enable = false } \ No newline at end of file +[workspace] +members = ["libs/easy-tun"] \ No newline at end of file diff --git a/libs/easy-tun/Cargo.toml b/libs/easy-tun/Cargo.toml new file mode 100644 index 0000000..12fdfa0 --- /dev/null +++ b/libs/easy-tun/Cargo.toml @@ -0,0 +1,20 @@ +[package] +name = "easy-tun" +version = "0.1.0" +authors = ["Evan Pratten "] +edition = "2021" +description = "TUN interfaces made easy" +readme = "README.md" +homepage = "https://github.com/ewpratten/protomask/libs/easy-tun" +documentation = "https://docs.rs/easy-tun" +repository = "https://github.com/ewpratten/protomask" +license = "GPL-3.0" +keywords = [] +categories = [] + +[dependencies] +tokio = { version = "^1.29.1", features = ["sync", "rt"] } +log = "^0.4" +libc = "^0.2" +ioctl-gen = "^0.1.1" +rtnetlink = "^0.13.0" \ No newline at end of file diff --git a/libs/easy-tun/README.md b/libs/easy-tun/README.md new file mode 100644 index 0000000..e69de29 diff --git a/libs/easy-tun/src/lib.rs b/libs/easy-tun/src/lib.rs new file mode 100644 index 0000000..557c57c --- /dev/null +++ b/libs/easy-tun/src/lib.rs @@ -0,0 +1,110 @@ +use std::{ + fs::{File, OpenOptions}, + future::Future, + mem::size_of, + os::fd::{AsRawFd, IntoRawFd, RawFd}, +}; + +use ioctl_gen::{ioc, iow}; +use libc::{__c_anonymous_ifr_ifru, ifreq, ioctl, IFF_NO_PI, IFF_TUN, IF_NAMESIZE}; + +/// A TUN device +pub struct Tun { + /// Internal file descriptor for the TUN device + fd: File, + /// Device name + name: String, + /// Handle on the RTNETLINK connection + rt_connection_future: Box>, + /// Handle on the RTNETLINK socket + rt_handle: rtnetlink::Handle, + /// Link index of the TUN device + link_index: u32, +} + +impl Tun { + /// Creates a new Tun device with the given name. + /// + /// The `name` argument must be less than the system's `IFNAMSIZ` constant, + /// and may contain a `%d` format specifier to allow for multiple devices with the same name. + pub fn new(dev: &str) -> Result { + // Get a file descriptor for `/dev/net/tun` + log::trace!("Opening /dev/net/tun"); + let fd = OpenOptions::new() + .read(true) + .write(true) + .open("/dev/net/tun")?; + + // Copy the device name into a C string with padding + // NOTE: No zero padding is needed because we pre-init the array to all 0s + let mut dev_cstr = [0i8; IF_NAMESIZE]; + let dev_bytes: Vec = dev.as_bytes().iter().map(|c| *c as i8).collect(); + let dev_len = dev_bytes.len().min(IF_NAMESIZE); + log::trace!("Device name length after truncation: {}", dev_len); + dev_cstr[..dev_len].copy_from_slice(&dev_bytes[..dev_len]); + + // Build an `ifreq` struct to send to the kernel + let mut ifr = ifreq { + ifr_name: dev_cstr, + ifr_ifru: __c_anonymous_ifr_ifru { + ifru_flags: (IFF_TUN | IFF_NO_PI) as i16, + }, + }; + + // Make an ioctl call to create the TUN device + log::trace!("Calling ioctl to create TUN device"); + let err = unsafe { + ioctl( + fd.as_raw_fd(), + iow!('T', 202, size_of::()) as u64, + &mut ifr, + ) + }; + log::trace!("ioctl returned: {}", err); + + // Check for errors + if err < 0 { + log::error!("ioctl failed: {}", err); + return Err(std::io::Error::last_os_error()); + } + + // Get the name of the device + let name = unsafe { std::ffi::CStr::from_ptr(ifr.ifr_name.as_ptr()) } + .to_str() + .unwrap() + .to_string(); + + // Create an rtnetlink connection + let (rt_connection, rt_handle, _) = rtnetlink::new_connection().map_err(|err| { + log::error!("Failed to open rtnetlink connection"); + log::error!("{}", err); + err + })?; + + // Build the TUN struct + Ok(Self { + fd, + name, + rt_connection_future: Box::new(rt_connection), + rt_handle, + link_index: 0, + }) + } + + /// Get the name of the TUN device + pub fn name(&self) -> &str { + &self.name + } +} + +impl AsRawFd for Tun { + fn as_raw_fd(&self) -> RawFd { + self.fd.as_raw_fd() + } +} + +impl IntoRawFd for Tun { + fn into_raw_fd(self) -> RawFd { + self.fd.into_raw_fd() + } +} diff --git a/protomask/Cargo.toml b/protomask/Cargo.toml new file mode 100644 index 0000000..37458a9 --- /dev/null +++ b/protomask/Cargo.toml @@ -0,0 +1,56 @@ +[package] +name = "protomask" +version = "0.2.0" +authors = ["Evan Pratten "] +edition = "2021" +description = "A user space NAT64 implementation" +readme = "README.md" +homepage = "https://github.com/ewpratten/protomask" +documentation = "https://docs.rs/protomask" +repository = "https://github.com/ewpratten/protomask" +license = "GPL-3.0" +keywords = [] +categories = [] + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html +[dependencies] +protomask-tun = { path = "protomask-tun", version = "0.1.0" } +tokio = { version = "1.29.1", features = [ + "macros", + "rt-multi-thread", + # "process", + "sync" +] } +clap = { version = "4.3.11", features = ["derive"] } +serde = { version = "1.0.171", features = ["derive"] } +ipnet = { version = "2.8.0", features = ["serde"] } +hyper = { version = "0.14.27", features = ["server", "http1", "tcp"] } +owo-colors = { version = "3.5.0", features = ["supports-colors"] } +toml = "0.7.6" +log = "0.4.19" +fern = "0.6.2" +serde_path_to_error = "0.1.13" +thiserror = "1.0.43" +tun-tap = "0.1.3" +bimap = "0.6.3" +pnet_packet = "0.34.0" +rtnetlink = "0.13.0" +futures = "0.3.28" +prometheus = "0.13.3" +lazy_static = "1.4.0" + +[[bin]] +name = "protomask" +path = "src/cli/main.rs" + +[package.metadata.deb] +section = "network" +assets = [ + ["target/release/protomask", "/usr/local/bin/protomask", "755"], + ["./protomask.toml", "/etc/protomask.toml", "644"], + ["README.md", "usr/share/doc/protomask/README.md", "644"] +] +conf-files = ["/etc/protomask.toml"] +depends = [] +maintainer-scripts = "./debian/" +systemd-units = { enable = false } \ No newline at end of file