diff --git a/Cargo.lock b/Cargo.lock index 7c2b3ee..62b4893 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -61,6 +61,12 @@ dependencies = [ "windows-sys", ] +[[package]] +name = "arraydeque" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d902e3d592a523def97af8f317b08ce16b7ab854c1985a0c671e6f15cebc236" + [[package]] name = "async-channel" version = "2.3.1" @@ -79,6 +85,17 @@ version = "4.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b75356056920673b02621b35afd0f7dda9306d03c79a30f5c56c44cf256e3de" +[[package]] +name = "async-trait" +version = "0.1.88" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e539d3fca749fcee5236ab05e93a52867dd549cc157c8cb7f99595f3cedffdb5" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.99", +] + [[package]] name = "atomic-waker" version = "1.1.2" @@ -91,11 +108,29 @@ version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" +[[package]] +name = "base64" +version = "0.21.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" + [[package]] name = "bitflags" version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd" +dependencies = [ + "serde", +] + +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] [[package]] name = "blocking" @@ -148,6 +183,46 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" +[[package]] +name = "clap" +version = "4.5.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e958897981290da2a852763fe9cdb89cd36977a5d729023127095fa94d95e2ff" +dependencies = [ + "clap_builder", + "clap_derive", +] + +[[package]] +name = "clap_builder" +version = "4.5.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83b0f35019843db2160b5bb19ae09b4e6411ac33fc6a712003c33e03090e2489" +dependencies = [ + "anstream", + "anstyle", + "clap_lex", + "strsim", +] + +[[package]] +name = "clap_derive" +version = "4.5.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09176aae279615badda0765c0c0b3f6ed53f4709118af73cf4655d85d1530cd7" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn 2.0.99", +] + +[[package]] +name = "clap_lex" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f46ad14479a25103f283c0f10005961cf086d8dc42205bb44c46ac563475dca6" + [[package]] name = "colorchoice" version = "1.0.3" @@ -163,12 +238,113 @@ dependencies = [ "crossbeam-utils", ] +[[package]] +name = "config" +version = "0.15.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "595aae20e65c3be792d05818e8c63025294ac3cb7e200f11459063a352a6ef80" +dependencies = [ + "async-trait", + "convert_case", + "json5", + "pathdiff", + "ron", + "rust-ini", + "serde", + "serde_json", + "toml", + "winnow", + "yaml-rust2", +] + +[[package]] +name = "const-random" +version = "0.1.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87e00182fe74b066627d63b85fd550ac2998d4b0bd86bfed477a0ae4c7c71359" +dependencies = [ + "const-random-macro", +] + +[[package]] +name = "const-random-macro" +version = "0.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9d839f2a20b0aee515dc581a6172f2321f96cab76c1a38a4c584a194955390e" +dependencies = [ + "getrandom", + "once_cell", + "tiny-keccak", +] + +[[package]] +name = "convert_case" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec182b0ca2f35d8fc196cf3404988fd8b8c739a4d270ff118a398feb0cbec1ca" +dependencies = [ + "unicode-segmentation", +] + +[[package]] +name = "cpufeatures" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" +dependencies = [ + "libc", +] + [[package]] name = "crossbeam-utils" version = "0.8.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" +[[package]] +name = "crunchy" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43da5946c66ffcc7745f48db692ffbb10a83bfe0afd96235c5c2a4fb23994929" + +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer", + "crypto-common", +] + +[[package]] +name = "dlv-list" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "442039f5147480ba31067cb00ada1adae6892028e40e45fc5de7b7df6dcc1b5f" +dependencies = [ + "const-random", +] + +[[package]] +name = "encoding_rs" +version = "0.8.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3" +dependencies = [ + "cfg-if", +] + [[package]] name = "env_filter" version = "0.1.3" @@ -192,6 +368,12 @@ dependencies = [ "log", ] +[[package]] +name = "equivalent" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" + [[package]] name = "event-listener" version = "5.4.0" @@ -219,6 +401,12 @@ version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" +[[package]] +name = "foldhash" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" + [[package]] name = "futures" version = "0.3.31" @@ -318,19 +506,83 @@ dependencies = [ "slab", ] +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "getrandom" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "hashbrown" +version = "0.14.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" + +[[package]] +name = "hashbrown" +version = "0.15.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" +dependencies = [ + "foldhash", +] + +[[package]] +name = "hashlink" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7382cf6263419f2d8df38c55d7da83da5c18aef87fc7a7fc1fb1e344edfe14c1" +dependencies = [ + "hashbrown 0.15.2", +] + +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + [[package]] name = "humantime" version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" +[[package]] +name = "indexmap" +version = "2.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3954d50fe15b02142bf25d3b8bdadb634ec3948f103d04ffe3031bc8fe9d7058" +dependencies = [ + "equivalent", + "hashbrown 0.15.2", +] + [[package]] name = "ip-over-anything" version = "0.1.0" dependencies = [ + "clap", + "config", "env_logger", "log", "pretty-hex", + "serde", "thiserror", "tun", ] @@ -347,6 +599,23 @@ version = "1.70.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" +[[package]] +name = "itoa" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" + +[[package]] +name = "json5" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96b0db21af676c1ce64250b5f40f3ce2cf27e4e47cb91ed91eb6fe9350b430c1" +dependencies = [ + "pest", + "pest_derive", + "serde", +] + [[package]] name = "libc" version = "0.2.170" @@ -393,12 +662,73 @@ version = "1.20.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "945462a4b81e43c4e3ba96bd7b49d834c6f61198356aa858733bc4acf3cbe62e" +[[package]] +name = "ordered-multimap" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49203cdcae0030493bad186b28da2fa25645fa276a51b6fec8010d281e02ef79" +dependencies = [ + "dlv-list", + "hashbrown 0.14.5", +] + [[package]] name = "parking" version = "2.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba" +[[package]] +name = "pathdiff" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df94ce210e5bc13cb6651479fa48d14f601d9858cfe0467f43ae157023b938d3" + +[[package]] +name = "pest" +version = "2.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "198db74531d58c70a361c42201efde7e2591e976d518caf7662a47dc5720e7b6" +dependencies = [ + "memchr", + "thiserror", + "ucd-trie", +] + +[[package]] +name = "pest_derive" +version = "2.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d725d9cfd79e87dccc9341a2ef39d1b6f6353d68c4b33c177febbe1a402c97c5" +dependencies = [ + "pest", + "pest_generator", +] + +[[package]] +name = "pest_generator" +version = "2.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db7d01726be8ab66ab32f9df467ae8b1148906685bbe75c82d1e65d7f5b3f841" +dependencies = [ + "pest", + "pest_meta", + "proc-macro2", + "quote", + "syn 2.0.99", +] + +[[package]] +name = "pest_meta" +version = "2.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f9f832470494906d1fca5329f8ab5791cc60beb230c74815dff541cbd2b5ca0" +dependencies = [ + "once_cell", + "pest", + "sha2", +] + [[package]] name = "pin-project-lite" version = "0.2.16" @@ -475,6 +805,87 @@ version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" +[[package]] +name = "ron" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b91f7eff05f748767f183df4320a63d6936e9c6107d97c9e6bdd9784f4289c94" +dependencies = [ + "base64", + "bitflags", + "serde", + "serde_derive", +] + +[[package]] +name = "rust-ini" +version = "0.21.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e310ef0e1b6eeb79169a1171daf9abcb87a2e17c03bee2c4bb100b55c75409f" +dependencies = [ + "cfg-if", + "ordered-multimap", + "trim-in-place", +] + +[[package]] +name = "ryu" +version = "1.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" + +[[package]] +name = "serde" +version = "1.0.219" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.219" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.99", +] + +[[package]] +name = "serde_json" +version = "1.0.140" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373" +dependencies = [ + "itoa", + "memchr", + "ryu", + "serde", +] + +[[package]] +name = "serde_spanned" +version = "0.6.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87607cb1398ed59d48732e575a4c28a7a8ebf2454b964fe3f224f2afc07909e1" +dependencies = [ + "serde", +] + +[[package]] +name = "sha2" +version = "0.10.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + [[package]] name = "slab" version = "0.4.9" @@ -484,6 +895,12 @@ dependencies = [ "autocfg", ] +[[package]] +name = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" + [[package]] name = "syn" version = "1.0.109" @@ -526,6 +943,55 @@ dependencies = [ "syn 2.0.99", ] +[[package]] +name = "tiny-keccak" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c9d3793400a45f954c52e73d068316d76b6f4e36977e3fcebb13a2721e80237" +dependencies = [ + "crunchy", +] + +[[package]] +name = "toml" +version = "0.8.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd87a5cdd6ffab733b2f74bc4fd7ee5fff6634124999ac278c35fc78c6120148" +dependencies = [ + "serde", + "serde_spanned", + "toml_datetime", + "toml_edit", +] + +[[package]] +name = "toml_datetime" +version = "0.6.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41" +dependencies = [ + "serde", +] + +[[package]] +name = "toml_edit" +version = "0.22.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17b4795ff5edd201c7cd6dca065ae59972ce77d1b80fa0a84d94950ece7d1474" +dependencies = [ + "indexmap", + "serde", + "serde_spanned", + "toml_datetime", + "winnow", +] + +[[package]] +name = "trim-in-place" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "343e926fc669bc8cde4fa3129ab681c63671bae288b1f1081ceee6d9d37904fc" + [[package]] name = "tun" version = "0.7.13" @@ -543,18 +1009,48 @@ dependencies = [ "wintun-bindings", ] +[[package]] +name = "typenum" +version = "1.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1dccffe3ce07af9386bfd29e80c0ab1a8205a2fc34e4bcd40364df902cfa8f3f" + +[[package]] +name = "ucd-trie" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2896d95c02a80c6d6a5d6e953d479f5ddf2dfdb6a244441010e373ac0fb88971" + [[package]] name = "unicode-ident" version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" +[[package]] +name = "unicode-segmentation" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" + [[package]] name = "utf8parse" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" +[[package]] +name = "version_check" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + [[package]] name = "windows-sys" version = "0.59.0" @@ -628,6 +1124,15 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" +[[package]] +name = "winnow" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e97b544156e9bebe1a0ffbc03484fc1ffe3100cbce3ffb17eac35f7cdd7ab36" +dependencies = [ + "memchr", +] + [[package]] name = "winreg" version = "0.55.0" @@ -653,3 +1158,14 @@ dependencies = [ "windows-sys", "winreg", ] + +[[package]] +name = "yaml-rust2" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "818913695e83ece1f8d2a1c52d54484b7b46d0f9c06beeb2649b9da50d9b512d" +dependencies = [ + "arraydeque", + "encoding_rs", + "hashlink", +] diff --git a/Cargo.toml b/Cargo.toml index 8d5a2f8..2662888 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,3 +9,6 @@ thiserror = "2.0.12" log = "0.4.26" pretty-hex = "0.4.1" env_logger = "0.11.6" +clap = { version = "4.5.34", features = ["derive"] } +config = "0.15.11" +serde = { version = "1.0.219", features = ["derive"] } diff --git a/src/config.rs b/src/config.rs new file mode 100644 index 0000000..37b4cd1 --- /dev/null +++ b/src/config.rs @@ -0,0 +1,21 @@ +use crate::layers::Layers; +use crate::medium::Mediums; +use config::Config; +use serde::Deserialize; +use std::path::Path; + +#[derive(Debug, Deserialize)] +pub struct IpOverXConfig { + pub medium: Mediums, + pub layers: Vec, +} + +impl IpOverXConfig { + pub fn new(path: &Path) -> Result { + let cfg = Config::builder() + .add_source(config::File::from(path)) + .build()?; + + cfg.try_deserialize() + } +} diff --git a/src/layers/logger_layer.rs b/src/layers/logger_layer.rs new file mode 100644 index 0000000..790f54f --- /dev/null +++ b/src/layers/logger_layer.rs @@ -0,0 +1,25 @@ +use crate::layers::{Layer, LayerError}; +use log::info; + +#[derive(Clone)] +pub struct LoggerLayer; + +impl Layer for LoggerLayer { + fn frame(&mut self, data: &mut Vec) -> Result<(), LayerError> { + info!("Sending: {}", pretty_hex::pretty_hex(data)); + Ok(()) + } + + fn deframe(&mut self, data: &mut Vec) -> Result<(), LayerError> { + info!("Received: {}", pretty_hex::pretty_hex(data)); + Ok(()) + } + + fn split(&self) -> (Box, Box) { + (Box::new(self.clone()), Box::new(self.clone())) + } + + fn name(&self) -> String { + "Logging".to_string() + } +} diff --git a/src/layers/mod.rs b/src/layers/mod.rs index 979ba2b..add2206 100644 --- a/src/layers/mod.rs +++ b/src/layers/mod.rs @@ -1,10 +1,32 @@ +mod logger_layer; + +use crate::layers::logger_layer::LoggerLayer; +use serde::Deserialize; use thiserror::Error; #[derive(Debug, Error)] pub enum LayerError {} -pub trait Layer { - fn frame(&mut self, data: &mut Vec) -> Result; +pub trait Layer: Send { + fn frame(&mut self, data: &mut Vec) -> Result<(), LayerError>; - fn deframe(&mut self, data: &mut Vec) -> Result; + fn deframe(&mut self, data: &mut Vec) -> Result<(), LayerError>; + + fn split(&self) -> (Box, Box); + + fn name(&self) -> String; +} + +#[derive(Debug, Deserialize)] +#[serde(tag = "layer")] +pub enum Layers { + Logger, +} + +impl Layers { + pub fn get_layer(&self) -> Box { + match self { + Layers::Logger => Box::new(LoggerLayer {}), + } + } } diff --git a/src/main.rs b/src/main.rs index 9794a99..223e615 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,9 +1,32 @@ +mod config; mod layers; mod medium; -mod tun_tx_worker; +mod tun_worker; -use crate::tun_tx_worker::TunTxWorker; +use crate::config::IpOverXConfig; +use crate::tun_worker::tun_rx_worker::TunRxWorker; +use clap::Parser; use log::LevelFilter; +use std::net::IpAddr; +use std::path::PathBuf; +use tun::Configuration; +use tun_worker::TunWorker; +use tun_worker::tun_tx_worker::TunTxWorker; + +/// Send IP packets over anything* +#[derive(Parser, Debug)] +#[command(version, about, long_about = None)] +struct Args { + /// Net Mask to use + #[arg(long, default_value = "255.255.255.0")] + net_mask: IpAddr, + /// Config file path + cfg_path: PathBuf, + /// Local TUN device IP + local_addr: IpAddr, + /// Remote TUN device IP + remote_addr: IpAddr, +} fn main() -> Result<(), Box> { env_logger::builder() @@ -11,27 +34,59 @@ fn main() -> Result<(), Box> { .parse_default_env() .init(); - let mut config = tun::Configuration::default(); - config - .address((10, 0, 0, 9)) - .netmask((255, 255, 255, 0)) - .destination((10, 0, 0, 1)) + let args = Args::parse(); + + let config = IpOverXConfig::new(&args.cfg_path)?; + + log::info!("Creating TUN device..."); + let mut tun_config = Configuration::default(); + tun_config + .address(args.local_addr) + .netmask(args.net_mask) + .destination(args.remote_addr) .up(); #[cfg(target_os = "linux")] - config.platform_config(|config| { + tun_config.platform_config(|config| { // requiring root privilege to acquire complete functions config.ensure_root_privileges(true); }); - let dev = tun::create(&config)?; + log::info!( + "Opening tun device @ {} connecting to {}...", + args.local_addr, + args.remote_addr + ); + let dev = tun::create(&tun_config)?; - let (tx, _rx) = dev.split(); + let (tx, rx) = dev.split(); - let medium = medium::logger::Logger {}; - let tx_worker = TunTxWorker::new(tx, medium); + log::info!("Opening Medium..."); + let mut medium = config.medium.create_medium(); - tx_worker.worker_thread(); + medium.init().unwrap(); + + let (rx_medium, tx_medium) = medium.split(); + + let mut tx_worker = TunTxWorker::new(tx, tx_medium); + let mut rx_worker = TunRxWorker::new(rx, rx_medium); + + log::info!("Adding layers..."); + for layer in &config.layers { + let layer = layer.get_layer(); + log::info!("Adding '{}' layer", layer.name()); + let (rx_layer, tx_layer) = layer.split(); + tx_worker.add_layer(tx_layer); + rx_worker.add_layer(rx_layer); + } + + log::info!("Starting worker threads..."); + let tx_thread = std::thread::spawn(move || tx_worker.worker_thread()); + let rx_thread = std::thread::spawn(move || rx_worker.worker_thread()); + + log::info!("Running, waiting for exit..."); + tx_thread.join().unwrap(); + rx_thread.join().unwrap(); Ok(()) } diff --git a/src/medium/logger.rs b/src/medium/logger.rs index 00aa3ea..660c2ec 100644 --- a/src/medium/logger.rs +++ b/src/medium/logger.rs @@ -1,6 +1,8 @@ -use crate::medium::WriteMedium; +use crate::medium::{Medium, ReadMedium, WriteMedium}; use log::info; +use std::io::Read; +#[derive(Clone)] pub struct Logger; impl std::io::Write for Logger { @@ -16,3 +18,21 @@ impl std::io::Write for Logger { } impl WriteMedium for Logger {} + +impl Read for Logger { + fn read(&mut self, _buf: &mut [u8]) -> std::io::Result { + Ok(0) + } +} + +impl ReadMedium for Logger {} + +impl Medium for Logger { + fn split(&self) -> (Box, Box) { + (Box::new(self.clone()), Box::new(self.clone())) + } + + fn name(&self) -> String { + "Logger".to_string() + } +} diff --git a/src/medium/mod.rs b/src/medium/mod.rs index 956ff33..0cda170 100644 --- a/src/medium/mod.rs +++ b/src/medium/mod.rs @@ -1,11 +1,46 @@ pub mod logger; +pub mod udp; +use crate::medium::logger::Logger; +use crate::medium::udp::UdpMedium; +use log::info; +use serde::Deserialize; use std::io::{Read, Write}; +use std::net::SocketAddr; -pub trait ReadMedium: Read {} +pub trait ReadMedium: Read + Send {} -pub trait WriteMedium: Write {} +pub trait WriteMedium: Write + Send {} -pub trait Medium: Read + Write { - fn split(self) -> (Box, Box); +pub trait Medium: Read + Write + Send { + fn split(&self) -> (Box, Box); + + fn name(&self) -> String; + + fn init(&mut self) -> Result<(), std::io::Error> { + info!("Initialized {} Medium", self.name()); + Ok(()) + } +} + +#[derive(Debug, Deserialize)] +#[serde(tag = "medium")] +pub enum Mediums { + Udp { + local_addr: SocketAddr, + remote_addr: SocketAddr, + }, + Logger, +} + +impl Mediums { + pub fn create_medium(&self) -> Box { + match self { + Mediums::Udp { + local_addr, + remote_addr, + } => Box::new(UdpMedium::new(*local_addr, *remote_addr)), + Mediums::Logger => Box::new(Logger), + } + } } diff --git a/src/medium/udp.rs b/src/medium/udp.rs new file mode 100644 index 0000000..c05b746 --- /dev/null +++ b/src/medium/udp.rs @@ -0,0 +1,81 @@ +use crate::medium::{Medium, ReadMedium, WriteMedium}; +use log::info; +use std::io::{ErrorKind, Read, Write}; +use std::net::{SocketAddr, UdpSocket}; + +pub struct UdpMedium { + source_addr: SocketAddr, + dest_addr: SocketAddr, + udp_socket: Option, +} + +impl UdpMedium { + pub fn new(source_addr: SocketAddr, dest_addr: SocketAddr) -> Self { + Self { + source_addr, + dest_addr, + udp_socket: None, + } + } +} + +impl Medium for UdpMedium { + fn split(&self) -> (Box, Box) { + let rx_medium = Self { + source_addr: self.source_addr, + dest_addr: self.dest_addr, + udp_socket: Some(self.udp_socket.as_ref().unwrap().try_clone().unwrap()), + }; + + let tx_medium = Self { + source_addr: self.source_addr, + dest_addr: self.dest_addr, + udp_socket: Some(self.udp_socket.as_ref().unwrap().try_clone().unwrap()), + }; + + (Box::new(rx_medium), Box::new(tx_medium)) + } + + fn name(&self) -> String { + "Udp".to_string() + } + + fn init(&mut self) -> Result<(), std::io::Error> { + info!( + "Initializing Udp Medium @ {} connected to {}", + self.source_addr, self.dest_addr + ); + self.udp_socket = Some(UdpSocket::bind(self.source_addr)?); + + Ok(()) + } +} + +impl Write for UdpMedium { + fn write(&mut self, buf: &[u8]) -> std::io::Result { + if let Some(socket) = &mut self.udp_socket { + socket.send_to(buf, self.dest_addr) + } else { + Err(std::io::Error::from(ErrorKind::NotConnected)) + } + } + + fn flush(&mut self) -> std::io::Result<()> { + // Nothing needed + Ok(()) + } +} + +impl WriteMedium for UdpMedium {} + +impl Read for UdpMedium { + fn read(&mut self, buf: &mut [u8]) -> std::io::Result { + if let Some(socket) = &mut self.udp_socket { + socket.recv(buf) + } else { + Err(std::io::Error::from(ErrorKind::NotConnected)) + } + } +} + +impl ReadMedium for UdpMedium {} diff --git a/src/tun_tx_worker.rs b/src/tun_tx_worker.rs deleted file mode 100644 index cdd5174..0000000 --- a/src/tun_tx_worker.rs +++ /dev/null @@ -1,40 +0,0 @@ -use crate::layers::Layer; -use crate::medium::WriteMedium; -use std::io::Read; - -pub struct TunTxWorker { - layers: Vec>, - tun_reader: tun::Reader, - tx_medium: T, -} - -impl TunTxWorker { - pub fn new(tun_reader: tun::Reader, medium: T) -> Self { - Self { - layers: vec![], - tun_reader, - tx_medium: medium, - } - } - - pub fn add_layer(&mut self, layer: Box) { - self.layers.push(layer) - } - - pub fn worker_thread(mut self) { - let mut buffer = vec![0; 4096]; - loop { - buffer.resize(4096, 0); - let data_read = self.tun_reader.read(&mut buffer).unwrap(); - - if data_read == 0 { - return; - } - - // TODO: Add layer processing - - self.tx_medium.write_all(&buffer[..data_read]).unwrap(); - buffer.clear(); - } - } -} diff --git a/src/tun_worker/mod.rs b/src/tun_worker/mod.rs new file mode 100644 index 0000000..4b018eb --- /dev/null +++ b/src/tun_worker/mod.rs @@ -0,0 +1,37 @@ +use crate::layers::{Layer, LayerError}; +use thiserror::Error; + +pub mod tun_rx_worker; +pub mod tun_tx_worker; + +#[derive(Debug, Error)] +pub enum Error { + #[error("Error with layer processing: {0}")] + Layer(#[from] LayerError), + #[error("IO Error: {0}")] + IO(#[from] std::io::Error), +} + +pub trait TunWorker { + fn worker_thread(self); + #[allow(dead_code)] + fn add_layer(&mut self, layer: Box); + + fn get_layers(&mut self) -> &mut Vec>; + + fn frame_message(&mut self, msg: &mut Vec) -> Result<(), Error> { + for layer in self.get_layers() { + layer.frame(msg)?; + } + + Ok(()) + } + + fn deframe_message(&mut self, msg: &mut Vec) -> Result<(), Error> { + for layer in self.get_layers().iter_mut().rev() { + layer.deframe(msg)?; + } + + Ok(()) + } +} diff --git a/src/tun_worker/tun_rx_worker.rs b/src/tun_worker/tun_rx_worker.rs new file mode 100644 index 0000000..e30504d --- /dev/null +++ b/src/tun_worker/tun_rx_worker.rs @@ -0,0 +1,63 @@ +use crate::layers::Layer; +use crate::medium::ReadMedium; +use crate::tun_worker::TunWorker; +use std::io::Write; + +pub struct TunRxWorker { + layers: Vec>, + tun_writer: tun::Writer, + rx_medium: Box, + bytes_read: usize, + bytes_written: usize, +} + +impl TunRxWorker { + pub fn new(tun_writer: tun::Writer, medium: Box) -> Self { + Self { + layers: vec![], + tun_writer, + rx_medium: medium, + bytes_read: 0, + bytes_written: 0, + } + } +} + +impl TunWorker for TunRxWorker { + fn worker_thread(mut self) { + let mut buffer = vec![0; 4096]; + loop { + buffer.resize(4096, 0); + buffer.fill(0); + let data_read = self.rx_medium.read(&mut buffer).unwrap(); + + buffer.resize(data_read, 0); + + if data_read == 0 { + log::info!("TUN device closed exiting..."); + return; + } + + self.bytes_read += data_read; + + if let Err(e) = self.deframe_message(&mut buffer) { + log::error!("Failed to deframe message: {}", e); + continue; + } + + if let Err(e) = self.tun_writer.write_all(&buffer) { + log::error!("Failed to write message to medium: {}", e) + } + + self.bytes_written += buffer.len(); + } + } + + fn add_layer(&mut self, layer: Box) { + self.layers.push(layer) + } + + fn get_layers(&mut self) -> &mut Vec> { + &mut self.layers + } +} diff --git a/src/tun_worker/tun_tx_worker.rs b/src/tun_worker/tun_tx_worker.rs new file mode 100644 index 0000000..43e8ec4 --- /dev/null +++ b/src/tun_worker/tun_tx_worker.rs @@ -0,0 +1,63 @@ +use crate::layers::Layer; +use crate::medium::WriteMedium; +use crate::tun_worker::TunWorker; +use std::io::Read; + +pub struct TunTxWorker { + layers: Vec>, + tun_reader: tun::Reader, + tx_medium: Box, + bytes_read: usize, + bytes_written: usize, +} + +impl TunTxWorker { + pub fn new(tun_reader: tun::Reader, medium: Box) -> Self { + Self { + layers: vec![], + tun_reader, + tx_medium: medium, + bytes_read: 0, + bytes_written: 0, + } + } +} + +impl TunWorker for TunTxWorker { + fn worker_thread(mut self) { + let mut buffer = vec![0; 4096]; + loop { + buffer.resize(4096, 0); + buffer.fill(0); + let data_read = self.tun_reader.read(&mut buffer).unwrap(); + + buffer.resize(data_read, 0); + + if data_read == 0 { + log::info!("TUN device closed exiting..."); + return; + } + + self.bytes_read += data_read; + + if let Err(e) = self.frame_message(&mut buffer) { + log::error!("Failed to frame message: {}", e); + continue; + } + + if let Err(e) = self.tx_medium.write_all(&buffer) { + log::error!("Failed to write message to medium: {}", e) + } + + self.bytes_written += buffer.len(); + } + } + + fn add_layer(&mut self, layer: Box) { + self.layers.push(layer) + } + + fn get_layers(&mut self) -> &mut Vec> { + &mut self.layers + } +}