From f1933597d5d64839d5d3eeb126f8b95582d664c4 Mon Sep 17 00:00:00 2001 From: gennyble Date: Sun, 18 May 2025 14:35:47 -0500 Subject: little api --- Cargo.lock | 193 +++++++++++++ Cargo.toml | 12 +- skim-cli/Cargo.toml | 8 + skim-cli/src/main.rs | 22 ++ skim/Cargo.lock | 754 ++++++++++++++++++++++++++++++++++++++++++++++++++ skim/Cargo.toml | 11 + skim/src/count.rs | 71 +++++ skim/src/ethertype.rs | 20 ++ skim/src/interface.rs | 18 ++ skim/src/ippacket.rs | 99 +++++++ skim/src/layer3.rs | 65 +++++ skim/src/main.rs | 215 ++++++++++++++ src/count.rs | 67 ----- src/ethertype.rs | 20 -- src/ippacket.rs | 99 ------- src/layer3.rs | 65 ----- src/main.rs | 172 ------------ 17 files changed, 1479 insertions(+), 432 deletions(-) create mode 100644 skim-cli/Cargo.toml create mode 100644 skim-cli/src/main.rs create mode 100644 skim/Cargo.lock create mode 100644 skim/Cargo.toml create mode 100644 skim/src/count.rs create mode 100644 skim/src/ethertype.rs create mode 100644 skim/src/interface.rs create mode 100644 skim/src/ippacket.rs create mode 100644 skim/src/layer3.rs create mode 100644 skim/src/main.rs delete mode 100644 src/count.rs delete mode 100644 src/ethertype.rs delete mode 100644 src/ippacket.rs delete mode 100644 src/layer3.rs delete mode 100644 src/main.rs diff --git a/Cargo.lock b/Cargo.lock index dc4f752..06d12a5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,6 +2,16 @@ # It is not intended for manual editing. version = 4 +[[package]] +name = "ariadne" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36f5e3dca4e09a6f340a61a0e9c7b61e030c69fc27bf29d73218f7e5e3b7638f" +dependencies = [ + "unicode-width", + "yansi", +] + [[package]] name = "async-channel" version = "2.3.1" @@ -154,6 +164,12 @@ dependencies = [ "piper", ] +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + [[package]] name = "cfg-if" version = "1.0.0" @@ -206,6 +222,104 @@ dependencies = [ "pin-project-lite", ] +[[package]] +name = "facet" +version = "0.27.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3b6c2b369db9a689ae02c361ec39a4a4a8ef6ae6df6c2f37e13d260bed04010" +dependencies = [ + "facet-core", + "facet-derive", + "static_assertions", +] + +[[package]] +name = "facet-core" +version = "0.27.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a04229b2c0ffd5637cdceea91ca3ab3fcb9dcaa536b5533508d9d6af7e2be625" +dependencies = [ + "bitflags", + "impls", +] + +[[package]] +name = "facet-derive" +version = "0.27.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e163232211167805793e00f068b1e0c8d91b008a991df9546798119f5d4eda5a" +dependencies = [ + "facet-core", + "facet-derive-emit", +] + +[[package]] +name = "facet-derive-emit" +version = "0.27.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "243f825b1cceb0aba1b6cc5ae8b9ff261169cd79f4a160cc651d856c0ccc8012" +dependencies = [ + "facet-derive-parse", + "quote", +] + +[[package]] +name = "facet-derive-parse" +version = "0.27.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbc5155804f381e601dd5a2a017590c6b4405516e0914b4c321b3a0005e1c7c5" +dependencies = [ + "unsynn", +] + +[[package]] +name = "facet-deserialize" +version = "0.24.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8881e8984877595cb62b2f51b21d02f6be93bc2d06c2d96f1d160f3bd8f805a9" +dependencies = [ + "ariadne", + "facet-core", + "facet-reflect", + "log", + "owo-colors", +] + +[[package]] +name = "facet-json" +version = "0.24.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf1bf18c808e13e7c2e4d6902743a188f6d3ec7374aa12de7397b86fab732be2" +dependencies = [ + "facet-core", + "facet-deserialize", + "facet-reflect", + "facet-serialize", + "log", +] + +[[package]] +name = "facet-reflect" +version = "0.27.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d71620e9c8e435d3b8745f7d0ce40ec2e21320802768ebfdb0d9e6de038106b" +dependencies = [ + "bitflags", + "facet-core", + "owo-colors", +] + +[[package]] +name = "facet-serialize" +version = "0.24.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd5324136b9ea1963ca40218afe8b26a3411ce1cbf523ad09d04c413f7b13f82" +dependencies = [ + "facet-core", + "facet-reflect", + "log", +] + [[package]] name = "fastrand" version = "2.3.0" @@ -237,10 +351,21 @@ dependencies = [ "pin-project-lite", ] +[[package]] +name = "fxhash" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c31b6d751ae2c7f11320402d34e41349dd1016f8d5d45e48c4312bc8625af50c" +dependencies = [ + "byteorder", +] + [[package]] name = "headlice" version = "0.1.0" dependencies = [ + "facet", + "facet-json", "pnet_datalink", "scurvy", "smol", @@ -252,6 +377,12 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fbf6a919d6cf397374f7dfeeea91d974c7c0a7221d0d0f4f20d859d329e53fcc" +[[package]] +name = "impls" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a46645bbd70538861a90d0f26c31537cdf1e44aae99a794fb75a664b70951bc" + [[package]] name = "ipnetwork" version = "0.20.0" @@ -273,12 +404,30 @@ version = "0.4.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab" +[[package]] +name = "log" +version = "0.4.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94" + +[[package]] +name = "mutants" +version = "0.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc0287524726960e07b119cebd01678f852f147742ae0d925e6a520dca956126" + [[package]] name = "no-std-net" version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "43794a0ace135be66a25d3ae77d41b91615fb68ae937f904090203e81f755b65" +[[package]] +name = "owo-colors" +version = "4.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26995317201fa17f3656c36716aed4a7c81743a9634ac4c99c0eeda495db0cec" + [[package]] name = "parking" version = "2.2.1" @@ -405,6 +554,12 @@ dependencies = [ "syn", ] +[[package]] +name = "shadow_counted" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "65da48d447333cebe1aadbdd3662f3ba56e76e67f53bc46f3dd5f67c74629d6b" + [[package]] name = "signal-hook-registry" version = "1.4.5" @@ -414,6 +569,14 @@ dependencies = [ "libc", ] +[[package]] +name = "skim-cli" +version = "0.1.0" +dependencies = [ + "facet", + "facet-json", +] + [[package]] name = "slab" version = "0.4.9" @@ -440,6 +603,12 @@ dependencies = [ "futures-lite", ] +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + [[package]] name = "syn" version = "2.0.101" @@ -473,6 +642,24 @@ version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" +[[package]] +name = "unicode-width" +version = "0.1.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af" + +[[package]] +name = "unsynn" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7940603a9e25cf11211cc43b81f4fcad2b8ab4df291ca855f32c40e1ac22d5bc" +dependencies = [ + "fxhash", + "mutants", + "proc-macro2", + "shadow_counted", +] + [[package]] name = "winapi" version = "0.3.9" @@ -567,3 +754,9 @@ name = "windows_x86_64_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" + +[[package]] +name = "yansi" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfe53a6657fd280eaa890a3bc59152892ffa3e30101319d168b781ed6529b049" diff --git a/Cargo.toml b/Cargo.toml index 43a9b92..4e3bc8b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,9 +1,3 @@ -[package] -name = "headlice" -version = "0.1.0" -edition = "2024" - -[dependencies] -pnet_datalink = "0.35.0" -scurvy = { git = "https://git.dreamy.place/scurvy/" } -smol = "2.0.2" +[workspace] +members = ["skim", "skim-cli"] +resolver = "3" diff --git a/skim-cli/Cargo.toml b/skim-cli/Cargo.toml new file mode 100644 index 0000000..df13b36 --- /dev/null +++ b/skim-cli/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "skim-cli" +version = "0.1.0" +edition = "2024" + +[dependencies] +facet = "0.27.1" +facet-json = { version = "0.24.2" } diff --git a/skim-cli/src/main.rs b/skim-cli/src/main.rs new file mode 100644 index 0000000..880b99f --- /dev/null +++ b/skim-cli/src/main.rs @@ -0,0 +1,22 @@ +use std::{ + io::{Read, Write}, + net::TcpStream, +}; + +fn main() { + let mut tcp = TcpStream::connect("127.0.0.1:6666").unwrap(); + + let query = r#"{"tcp": [80, 443], "udp":[443]}"#; + let len = query.len() as u32; + + tcp.write_all(&len.to_be_bytes()).unwrap(); + tcp.write_all(query.as_bytes()).unwrap(); + + let mut size_bytes = [0u8; 4]; + tcp.read_exact(&mut size_bytes).unwrap(); + let size = u32::from_be_bytes(size_bytes); + let mut response = vec![0; size as usize]; + tcp.read_exact(&mut response).unwrap(); + + println!("{}", unsafe { String::from_utf8_unchecked(response) }); +} diff --git a/skim/Cargo.lock b/skim/Cargo.lock new file mode 100644 index 0000000..0f2befa --- /dev/null +++ b/skim/Cargo.lock @@ -0,0 +1,754 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "ariadne" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36f5e3dca4e09a6f340a61a0e9c7b61e030c69fc27bf29d73218f7e5e3b7638f" +dependencies = [ + "unicode-width", + "yansi", +] + +[[package]] +name = "async-channel" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89b47800b0be77592da0afd425cc03468052844aff33b84e33cc696f64e77b6a" +dependencies = [ + "concurrent-queue", + "event-listener-strategy", + "futures-core", + "pin-project-lite", +] + +[[package]] +name = "async-executor" +version = "1.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb812ffb58524bdd10860d7d974e2f01cc0950c2438a74ee5ec2e2280c6c4ffa" +dependencies = [ + "async-task", + "concurrent-queue", + "fastrand", + "futures-lite", + "pin-project-lite", + "slab", +] + +[[package]] +name = "async-fs" +version = "2.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebcd09b382f40fcd159c2d695175b2ae620ffa5f3bd6f664131efff4e8b9e04a" +dependencies = [ + "async-lock", + "blocking", + "futures-lite", +] + +[[package]] +name = "async-io" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43a2b323ccce0a1d90b449fd71f2a06ca7faa7c54c2751f06c9bd851fc061059" +dependencies = [ + "async-lock", + "cfg-if", + "concurrent-queue", + "futures-io", + "futures-lite", + "parking", + "polling", + "rustix", + "slab", + "tracing", + "windows-sys", +] + +[[package]] +name = "async-lock" +version = "3.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff6e472cdea888a4bd64f342f09b3f50e1886d32afe8df3d663c01140b811b18" +dependencies = [ + "event-listener", + "event-listener-strategy", + "pin-project-lite", +] + +[[package]] +name = "async-net" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b948000fad4873c1c9339d60f2623323a0cfd3816e5181033c6a5cb68b2accf7" +dependencies = [ + "async-io", + "blocking", + "futures-lite", +] + +[[package]] +name = "async-process" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63255f1dc2381611000436537bbedfe83183faa303a5a0edaf191edef06526bb" +dependencies = [ + "async-channel", + "async-io", + "async-lock", + "async-signal", + "async-task", + "blocking", + "cfg-if", + "event-listener", + "futures-lite", + "rustix", + "tracing", +] + +[[package]] +name = "async-signal" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "637e00349800c0bdf8bfc21ebbc0b6524abea702b0da4168ac00d070d0c0b9f3" +dependencies = [ + "async-io", + "async-lock", + "atomic-waker", + "cfg-if", + "futures-core", + "futures-io", + "rustix", + "signal-hook-registry", + "slab", + "windows-sys", +] + +[[package]] +name = "async-task" +version = "4.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b75356056920673b02621b35afd0f7dda9306d03c79a30f5c56c44cf256e3de" + +[[package]] +name = "atomic-waker" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" + +[[package]] +name = "autocfg" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" + +[[package]] +name = "bitflags" +version = "2.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b8e56985ec62d17e9c1001dc89c88ecd7dc08e47eba5ec7c29c7b5eeecde967" + +[[package]] +name = "blocking" +version = "1.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "703f41c54fc768e63e091340b424302bb1c29ef4aa0c7f10fe849dfb114d29ea" +dependencies = [ + "async-channel", + "async-task", + "futures-io", + "futures-lite", + "piper", +] + +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "concurrent-queue" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ca0197aee26d1ae37445ee532fefce43251d24cc7c166799f4d46817f1d3973" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" + +[[package]] +name = "errno" +version = "0.3.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cea14ef9355e3beab063703aa9dab15afd25f0667c341310c1e5274bb1d0da18" +dependencies = [ + "libc", + "windows-sys", +] + +[[package]] +name = "event-listener" +version = "5.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3492acde4c3fc54c845eaab3eed8bd00c7a7d881f78bfc801e43a93dec1331ae" +dependencies = [ + "concurrent-queue", + "parking", + "pin-project-lite", +] + +[[package]] +name = "event-listener-strategy" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8be9f3dfaaffdae2972880079a491a1a8bb7cbed0b8dd7a347f668b4150a3b93" +dependencies = [ + "event-listener", + "pin-project-lite", +] + +[[package]] +name = "facet" +version = "0.27.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3b6c2b369db9a689ae02c361ec39a4a4a8ef6ae6df6c2f37e13d260bed04010" +dependencies = [ + "facet-core", + "facet-derive", + "static_assertions", +] + +[[package]] +name = "facet-core" +version = "0.27.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a04229b2c0ffd5637cdceea91ca3ab3fcb9dcaa536b5533508d9d6af7e2be625" +dependencies = [ + "bitflags", + "impls", +] + +[[package]] +name = "facet-derive" +version = "0.27.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e163232211167805793e00f068b1e0c8d91b008a991df9546798119f5d4eda5a" +dependencies = [ + "facet-core", + "facet-derive-emit", +] + +[[package]] +name = "facet-derive-emit" +version = "0.27.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "243f825b1cceb0aba1b6cc5ae8b9ff261169cd79f4a160cc651d856c0ccc8012" +dependencies = [ + "facet-derive-parse", + "quote", +] + +[[package]] +name = "facet-derive-parse" +version = "0.27.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbc5155804f381e601dd5a2a017590c6b4405516e0914b4c321b3a0005e1c7c5" +dependencies = [ + "unsynn", +] + +[[package]] +name = "facet-deserialize" +version = "0.24.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8881e8984877595cb62b2f51b21d02f6be93bc2d06c2d96f1d160f3bd8f805a9" +dependencies = [ + "ariadne", + "facet-core", + "facet-reflect", + "log", + "owo-colors", +] + +[[package]] +name = "facet-json" +version = "0.24.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf1bf18c808e13e7c2e4d6902743a188f6d3ec7374aa12de7397b86fab732be2" +dependencies = [ + "facet-core", + "facet-deserialize", + "facet-reflect", + "facet-serialize", + "log", +] + +[[package]] +name = "facet-reflect" +version = "0.27.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d71620e9c8e435d3b8745f7d0ce40ec2e21320802768ebfdb0d9e6de038106b" +dependencies = [ + "bitflags", + "facet-core", + "owo-colors", +] + +[[package]] +name = "facet-serialize" +version = "0.24.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd5324136b9ea1963ca40218afe8b26a3411ce1cbf523ad09d04c413f7b13f82" +dependencies = [ + "facet-core", + "facet-reflect", + "log", +] + +[[package]] +name = "fastrand" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" + +[[package]] +name = "futures-core" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" + +[[package]] +name = "futures-io" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" + +[[package]] +name = "futures-lite" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f5edaec856126859abb19ed65f39e90fea3a9574b9707f13539acf4abf7eb532" +dependencies = [ + "fastrand", + "futures-core", + "futures-io", + "parking", + "pin-project-lite", +] + +[[package]] +name = "fxhash" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c31b6d751ae2c7f11320402d34e41349dd1016f8d5d45e48c4312bc8625af50c" +dependencies = [ + "byteorder", +] + +[[package]] +name = "headlice" +version = "0.1.0" +dependencies = [ + "facet", + "facet-json", + "pnet_datalink", + "scurvy", + "smol", +] + +[[package]] +name = "hermit-abi" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fbf6a919d6cf397374f7dfeeea91d974c7c0a7221d0d0f4f20d859d329e53fcc" + +[[package]] +name = "impls" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a46645bbd70538861a90d0f26c31537cdf1e44aae99a794fb75a664b70951bc" + +[[package]] +name = "ipnetwork" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf466541e9d546596ee94f9f69590f89473455f88372423e0008fc1a7daf100e" +dependencies = [ + "serde", +] + +[[package]] +name = "libc" +version = "0.2.172" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa" + +[[package]] +name = "linux-raw-sys" +version = "0.4.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab" + +[[package]] +name = "log" +version = "0.4.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94" + +[[package]] +name = "mutants" +version = "0.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc0287524726960e07b119cebd01678f852f147742ae0d925e6a520dca956126" + +[[package]] +name = "no-std-net" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43794a0ace135be66a25d3ae77d41b91615fb68ae937f904090203e81f755b65" + +[[package]] +name = "owo-colors" +version = "4.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26995317201fa17f3656c36716aed4a7c81743a9634ac4c99c0eeda495db0cec" + +[[package]] +name = "parking" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba" + +[[package]] +name = "pin-project-lite" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" + +[[package]] +name = "piper" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96c8c490f422ef9a4efd2cb5b42b76c8613d7e7dfc1caf667b8a3350a5acc066" +dependencies = [ + "atomic-waker", + "fastrand", + "futures-io", +] + +[[package]] +name = "pnet_base" +version = "0.35.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffc190d4067df16af3aba49b3b74c469e611cad6314676eaf1157f31aa0fb2f7" +dependencies = [ + "no-std-net", +] + +[[package]] +name = "pnet_datalink" +version = "0.35.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e79e70ec0be163102a332e1d2d5586d362ad76b01cec86f830241f2b6452a7b7" +dependencies = [ + "ipnetwork", + "libc", + "pnet_base", + "pnet_sys", + "winapi", +] + +[[package]] +name = "pnet_sys" +version = "0.35.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d4643d3d4db6b08741050c2f3afa9a892c4244c085a72fcda93c9c2c9a00f4b" +dependencies = [ + "libc", + "winapi", +] + +[[package]] +name = "polling" +version = "3.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a604568c3202727d1507653cb121dbd627a58684eb09a820fd746bee38b4442f" +dependencies = [ + "cfg-if", + "concurrent-queue", + "hermit-abi", + "pin-project-lite", + "rustix", + "tracing", + "windows-sys", +] + +[[package]] +name = "proc-macro2" +version = "1.0.95" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rustix" +version = "0.38.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154" +dependencies = [ + "bitflags", + "errno", + "libc", + "linux-raw-sys", + "windows-sys", +] + +[[package]] +name = "scurvy" +version = "0.1.0" +source = "git+https://git.dreamy.place/scurvy/#c97099648a2117d44b3bc8bef033afde66c2339a" + +[[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", +] + +[[package]] +name = "shadow_counted" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "65da48d447333cebe1aadbdd3662f3ba56e76e67f53bc46f3dd5f67c74629d6b" + +[[package]] +name = "signal-hook-registry" +version = "1.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9203b8055f63a2a00e2f593bb0510367fe707d7ff1e5c872de2f537b339e5410" +dependencies = [ + "libc", +] + +[[package]] +name = "slab" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" +dependencies = [ + "autocfg", +] + +[[package]] +name = "smol" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a33bd3e260892199c3ccfc487c88b2da2265080acb316cd920da72fdfd7c599f" +dependencies = [ + "async-channel", + "async-executor", + "async-fs", + "async-io", + "async-lock", + "async-net", + "async-process", + "blocking", + "futures-lite", +] + +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + +[[package]] +name = "syn" +version = "2.0.101" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ce2b7fc941b3a24138a0a7cf8e858bfc6a992e7978a068a5c760deb0ed43caf" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "tracing" +version = "0.1.41" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" +dependencies = [ + "pin-project-lite", + "tracing-core", +] + +[[package]] +name = "tracing-core" +version = "0.1.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e672c95779cf947c5311f83787af4fa8fffd12fb27e4993211a84bdfd9610f9c" + +[[package]] +name = "unicode-ident" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" + +[[package]] +name = "unicode-width" +version = "0.1.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af" + +[[package]] +name = "unsynn" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7940603a9e25cf11211cc43b81f4fcad2b8ab4df291ca855f32c40e1ac22d5bc" +dependencies = [ + "fxhash", + "mutants", + "proc-macro2", + "shadow_counted", +] + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "windows-sys" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_gnullvm", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" + +[[package]] +name = "yansi" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfe53a6657fd280eaa890a3bc59152892ffa3e30101319d168b781ed6529b049" diff --git a/skim/Cargo.toml b/skim/Cargo.toml new file mode 100644 index 0000000..3371e79 --- /dev/null +++ b/skim/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "headlice" +version = "0.1.0" +edition = "2024" + +[dependencies] +facet = "0.27.1" +facet-json = { version = "0.24.2" } +pnet_datalink = "0.35.0" +scurvy = { git = "https://git.dreamy.place/scurvy/" } +smol = "2.0.2" diff --git a/skim/src/count.rs b/skim/src/count.rs new file mode 100644 index 0000000..8f133bc --- /dev/null +++ b/skim/src/count.rs @@ -0,0 +1,71 @@ +const U16_MAX: usize = u16::MAX as usize; + +pub struct Count { + tcp_tx: Box<[usize]>, + tcp_rx: Box<[usize]>, + udp_tx: Box<[usize]>, + udp_rx: Box<[usize]>, +} + +impl Count { + pub fn new() -> Self { + Self { + tcp_tx: Box::new([0; U16_MAX]), + tcp_rx: Box::new([0; U16_MAX]), + udp_tx: Box::new([0; U16_MAX]), + udp_rx: Box::new([0; U16_MAX]), + } + } + + pub fn push_tcp(&self, tx_flag: bool, src: u16, dst: u16, len: usize) { + if tx_flag { + let bad_mut = unsafe { &mut *(self.tcp_tx.as_ptr() as *mut [usize; U16_MAX]) }; + bad_mut[src as usize] += len; + } else { + let bad_mut = unsafe { &mut *(self.tcp_rx.as_ptr() as *mut [usize; U16_MAX]) }; + bad_mut[dst as usize] += len; + } + } + + pub fn push_udp(&self, tx_flag: bool, src: u16, dst: u16, len: usize) { + if tx_flag { + let bad_mut = unsafe { &mut *(self.udp_tx.as_ptr() as *mut [usize; U16_MAX]) }; + bad_mut[src as usize] += len; + } else { + let bad_mut = unsafe { &mut *(self.udp_rx.as_ptr() as *mut [usize; U16_MAX]) }; + bad_mut[dst as usize] += len; + } + } + + pub fn tcp_tx_slice(&self) -> &[usize] { + &self.tcp_tx + } + + pub fn tcp_rx_slice(&self) -> &[usize] { + &self.tcp_rx + } + + pub fn udp_tx_slice(&self) -> &[usize] { + &self.udp_tx + } + + pub fn udp_rx_slice(&self) -> &[usize] { + &self.udp_rx + } + + pub fn many_tcp_tx(&self, ports: &[u16]) -> usize { + ports.iter().fold(0, |acc, port| acc + self.tcp_tx[*port as usize]) + } + + pub fn many_tcp_rx(&self, ports: &[u16]) -> usize { + ports.iter().fold(0, |acc, port| acc + self.tcp_rx[*port as usize]) + } + + pub fn many_udp_tx(&self, ports: &[u16]) -> usize { + ports.iter().fold(0, |acc, port| acc + self.udp_tx[*port as usize]) + } + + pub fn many_udp_rx(&self, ports: &[u16]) -> usize { + ports.iter().fold(0, |acc, port| acc + self.udp_rx[*port as usize]) + } +} diff --git a/skim/src/ethertype.rs b/skim/src/ethertype.rs new file mode 100644 index 0000000..0d728f3 --- /dev/null +++ b/skim/src/ethertype.rs @@ -0,0 +1,20 @@ +#[derive(Copy, Clone, Debug, PartialEq)] +pub enum EtherType { + /// The frame type is IEEE 802.3 and this is it's length + Length(u16), + IPv4, + IPv6, + Unknown(u16), +} + +impl EtherType { + //TODO: check ethertype is correct + pub fn new(n: u16) -> Self { + match n { + n if n <= 1500 => Self::Length(n), + 0x0800 => Self::IPv4, + 0x86DD => Self::IPv6, + n => Self::Unknown(n), + } + } +} diff --git a/skim/src/interface.rs b/skim/src/interface.rs new file mode 100644 index 0000000..514896e --- /dev/null +++ b/skim/src/interface.rs @@ -0,0 +1,18 @@ +#[derive(facet::Facet)] +pub struct Query { + pub tcp: Option>, + pub udp: Option>, +} + +#[derive(facet::Facet)] +pub struct Response { + pub tcp: Vec, + pub udp: Vec, +} + +#[derive(facet::Facet)] +pub struct PortNetworkPair { + pub port: u16, + pub tx: usize, + pub rx: usize, +} diff --git a/skim/src/ippacket.rs b/skim/src/ippacket.rs new file mode 100644 index 0000000..60858d2 --- /dev/null +++ b/skim/src/ippacket.rs @@ -0,0 +1,99 @@ +use std::net::Ipv4Addr; + +pub struct Ipv4Packet<'p> { + /// The computed size of the IP packet + header_length: usize, + /// The total length of the IP packet when all fragments are combined + total_length: u16, + more_fragments: bool, + fragment_offset: usize, + next_header: IpNextHeader, + pub src: Ipv4Addr, + pub dst: Ipv4Addr, + payload: &'p [u8], +} + +impl<'p> Ipv4Packet<'p> { + pub fn new(buffer: &'p [u8]) -> Self { + let ihl = buffer[0].to_be() & 0b0000_1111; + let header_length = ihl as usize * 4; + + let total_length = u16::from_be_bytes([buffer[2], buffer[3]]); + + // Fragmentation + let more_fragments = (buffer[6] & 0b0010_0000) > 0; + let fragment_offset = u16::from_be_bytes([buffer[6] & 0b0001_1111, buffer[7]]); + // Fragments are in units of 8 bytes + let true_frag_offset = fragment_offset as usize * 8; + + let next_header = IpNextHeader::new(buffer[9]); + + let src = Ipv4Addr::new(buffer[12], buffer[13], buffer[14], buffer[15]); + let dst = Ipv4Addr::new(buffer[16], buffer[17], buffer[18], buffer[19]); + + Self { + header_length, + total_length, + more_fragments, + fragment_offset: true_frag_offset, + next_header, + src, + dst, + payload: &buffer[header_length..], + } + } + + pub fn get_source(&self) -> Ipv4Addr { + self.src + } + + pub fn get_destination(&self) -> Ipv4Addr { + self.dst + } + + pub fn has_more_fragments(&self) -> bool { + self.more_fragments + } + + pub fn get_fragment_offset(&self) -> usize { + self.fragment_offset + } + + pub fn get_next_header(&self) -> IpNextHeader { + self.next_header + } + + pub fn get_payload(&self) -> &[u8] { + &self.payload + } + + pub fn get_packet_len(&self) -> usize { + self.total_length as usize + } + + pub fn get_payload_len(&self) -> usize { + // An IPv4 header is always 20 bytes long + self.total_length as usize - 20 + } +} + +#[derive(Copy, Clone, Debug, PartialEq)] +pub enum IpNextHeader { + Icmp, + Igmp, + Tcp, + Udp, + Unknown(u8), +} + +impl IpNextHeader { + pub fn new(n: u8) -> Self { + match n { + 1 => Self::Icmp, + 2 => Self::Igmp, + 6 => Self::Tcp, + 17 => Self::Udp, + n => Self::Unknown(n), + } + } +} diff --git a/skim/src/layer3.rs b/skim/src/layer3.rs new file mode 100644 index 0000000..7521c0d --- /dev/null +++ b/skim/src/layer3.rs @@ -0,0 +1,65 @@ +pub struct Tcp<'p> { + src: u16, + dst: u16, + payload: &'p [u8], +} + +impl<'p> Tcp<'p> { + pub fn new(buffer: &'p [u8]) -> Self { + let src = u16::from_be_bytes([buffer[0], buffer[1]]); + let dst = u16::from_be_bytes([buffer[2], buffer[3]]); + let data_offset = (buffer[12].to_be() & 0b1111_0000) >> 4; + // Offset is number of 32-bit words + let true_offset = data_offset as usize * 4; + + Self { + src, + dst, + payload: &buffer[true_offset..], + } + } + + pub fn source_port(&self) -> u16 { + self.src + } + + pub fn destination_port(&self) -> u16 { + self.dst + } + + pub fn payload(&self) -> &[u8] { + self.payload + } +} + +pub struct Udp<'p> { + src: u16, + dst: u16, + payload: &'p [u8], +} + +impl<'p> Udp<'p> { + pub fn new(buffer: &'p [u8]) -> Self { + let src = u16::from_be_bytes([buffer[0], buffer[1]]); + let dst = u16::from_be_bytes([buffer[2], buffer[3]]); + let _len = u16::from_be_bytes([buffer[4], buffer[5]]); + + Self { + src, + dst, + payload: &buffer[8..], + } + } + + pub fn source_port(&self) -> u16 { + self.src + } + + pub fn destination_port(&self) -> u16 { + self.dst + } + + pub fn payload(&self) -> &[u8] { + self.payload + } +} diff --git a/skim/src/main.rs b/skim/src/main.rs new file mode 100644 index 0000000..4a82106 --- /dev/null +++ b/skim/src/main.rs @@ -0,0 +1,215 @@ +use std::{cell::UnsafeCell, error::Error, net::Ipv4Addr, rc::Rc, thread::JoinHandle}; + +use count::Count; +use ethertype::EtherType; +use interface::{PortNetworkPair, Query, Response}; +use ippacket::{IpNextHeader, Ipv4Packet}; +use layer3::{Tcp, Udp}; +use pnet_datalink::{Channel, Config}; +use scurvy::{Argument, Scurvy}; +use smol::{ + LocalExecutor, + channel::{self, Receiver, Sender}, + io::{AsyncReadExt, AsyncWriteExt}, + net::TcpListener, +}; + +mod count; +mod ethertype; +mod interface; +mod ippacket; +mod layer3; + +fn main() -> Result<(), Box> { + let args = vec![ + Argument::new(&["interface", "iface"]).arg("dev"), + Argument::new("ip").arg("addr"), + ]; + let scurvy = Scurvy::make(args); + + let interface_name = scurvy.get("interface").unwrap(); + let interface = match pnet_datalink::interfaces().iter().find(|i| i.name == interface_name) { + None => { + eprintln!("No interface found named '{interface_name}'"); + return Ok(()); + } + Some(i) => i.clone(), + }; + + let ip_want: Ipv4Addr = scurvy.get("ip").unwrap().parse()?; + + let mut channel = match pnet_datalink::channel(&interface, Config::default())? { + Channel::Ethernet(_tx, rx) => rx, + _ => unimplemented!(), + }; + + let stat = stat_thread(); + + loop { + let pkt = channel.next()?; + + let ethertype = EtherType::new(u16::from_be_bytes([pkt[12], pkt[13]])); + let eth_payload = &pkt[14..]; + + match ethertype { + EtherType::IPv4 => { + let ip = Ipv4Packet::new(eth_payload); + let ip_payload = ip.get_payload(); + + let ip_tx = if ip.src == ip_want { + true + } else if ip.dst == ip_want { + false + } else { + continue; + }; + + // 6 byte per MAC (x2), 2 byte ethertype, 2 byte crc + let total_l2_len = ip.get_packet_len() + 18; + + match ip.get_next_header() { + IpNextHeader::Tcp => { + let tcp = Tcp::new(ip_payload); + + stat.tx.send_blocking(Meow::Tcp { + tx: ip_tx, + src: tcp.source_port(), + dst: tcp.destination_port(), + len: total_l2_len, + })?; + } + IpNextHeader::Udp => { + let udp = Udp::new(ip_payload); + + stat.tx.send_blocking(Meow::Udp { + tx: ip_tx, + src: udp.source_port(), + dst: udp.destination_port(), + len: total_l2_len, + })?; + } + _ => (), + } + } + _ => (), + } + } +} + +#[allow(dead_code)] +struct StatHandle { + hwnd: JoinHandle<()>, + tx: Sender, +} + +enum Meow { + Tcp { + tx: bool, + src: u16, + dst: u16, + len: usize, + }, + Udp { + tx: bool, + src: u16, + dst: u16, + len: usize, + }, +} + +fn stat_thread() -> StatHandle { + let (tx, rx) = channel::unbounded(); + + let hwnd = std::thread::spawn(|| stat(rx)); + + StatHandle { hwnd, tx } +} + +fn stat(rx: Receiver) { + println!("started stat thread"); + let cat = Rc::new(Count::new()); + let ex = Rc::new(LocalExecutor::new()); + + let mut adder_cat = Rc::clone(&cat); + ex.spawn(async move { + println!("ready to receive events"); + loop { + match rx.recv().await { + Err(_e) => { + eprintln!("error receiving! breaking from loop"); + break; + } + Ok(Meow::Tcp { tx, src, dst, len }) => { + adder_cat.push_tcp(tx, src, dst, len); + } + Ok(Meow::Udp { tx, src, dst, len }) => { + adder_cat.push_udp(tx, src, dst, len); + } + } + } + }) + .detach(); + + let run_cat = Rc::clone(&cat); + let run_ex = Rc::clone(&ex); + let run = ex.run(async move { + let socket = TcpListener::bind("127.0.0.1:6666").await.unwrap(); + + println!("listening on 127.0.0.1:6666"); + loop { + let (mut stream, _caddr) = socket.accept().await.unwrap(); + let per_spawn_cat = Rc::clone(&run_cat); + + run_ex + .spawn(async move { + let mut size_bytes = [0u8; 4]; + stream.read_exact(&mut size_bytes).await.unwrap(); + let size = u32::from_be_bytes(size_bytes); + + let mut json_raw = vec![0u8; size as usize]; + stream.read_exact(&mut json_raw).await.unwrap(); + + let json_str = String::from_utf8(json_raw).unwrap(); + let json: Query = facet_json::from_str(&json_str).unwrap(); + + let mut resp = Response { + tcp: vec![], + udp: vec![], + }; + + if let Some(tcp_ports) = json.tcp { + let tcp_tx = per_spawn_cat.tcp_tx_slice(); + let tcp_rx = per_spawn_cat.tcp_rx_slice(); + + tcp_ports.into_iter().for_each(|p| { + resp.tcp.push(PortNetworkPair { + port: p, + tx: tcp_tx[p as usize], + rx: tcp_rx[p as usize], + }); + }); + } + + if let Some(udp_ports) = json.udp { + let udp_tx = per_spawn_cat.udp_tx_slice(); + let udp_rx = per_spawn_cat.udp_rx_slice(); + + udp_ports.into_iter().for_each(|p| { + resp.tcp.push(PortNetworkPair { + port: p, + tx: udp_tx[p as usize], + rx: udp_rx[p as usize], + }); + }); + } + + let response_json = facet_json::to_string(&resp); + stream.write_all(&(response_json.len() as u32).to_be_bytes()).await.unwrap(); + stream.write_all(response_json.as_bytes()).await.unwrap(); + }) + .detach(); + } + }); + + smol::block_on(run); +} diff --git a/src/count.rs b/src/count.rs deleted file mode 100644 index c3d92bf..0000000 --- a/src/count.rs +++ /dev/null @@ -1,67 +0,0 @@ -const U16_MAX: usize = u16::MAX as usize; - -pub struct Count { - tcp_tx: Box<[usize]>, - tcp_rx: Box<[usize]>, - udp_tx: Box<[usize]>, - udp_rx: Box<[usize]>, -} - -impl Count { - pub fn new() -> Self { - Self { - tcp_tx: Box::new([0; U16_MAX]), - tcp_rx: Box::new([0; U16_MAX]), - udp_tx: Box::new([0; U16_MAX]), - udp_rx: Box::new([0; U16_MAX]), - } - } - - pub fn push_tcp(&mut self, tx_flag: bool, src: u16, dst: u16, len: usize) { - // The unsafe code here is bad and not good. As far as I am aware, this - // is safe except for allowing race conditions. - if tx_flag { - let bad_mut = unsafe { &mut *(self.tcp_tx.as_ptr() as *mut [usize; U16_MAX]) }; - bad_mut[src as usize] += len; - } else { - let bad_mut = unsafe { &mut *(self.tcp_rx.as_ptr() as *mut [usize; U16_MAX]) }; - bad_mut[dst as usize] += len; - } - } - - pub fn push_udp(&mut self, tx_flag: bool, src: u16, dst: u16, len: usize) { - // The unsafe code here is bad and not good. As far as I am aware, this - // is safe except for allowing race conditions. - if tx_flag { - let bad_mut = unsafe { &mut *(self.udp_tx.as_ptr() as *mut [usize; U16_MAX]) }; - bad_mut[src as usize] += len; - } else { - let bad_mut = unsafe { &mut *(self.udp_rx.as_ptr() as *mut [usize; U16_MAX]) }; - bad_mut[dst as usize] += len; - } - } - - pub fn tcp_tx(&self, port: u16) -> usize { - self.tcp_tx[port as usize] - } - - pub fn tcp_rx(&self, port: u16) -> usize { - self.tcp_rx[port as usize] - } - - pub fn udp_tx(&self, port: u16) -> usize { - self.udp_tx[port as usize] - } - - pub fn udp_rx(&self, port: u16) -> usize { - self.udp_rx[port as usize] - } - - pub fn many_tcp_tx(&self, ports: &[u16]) -> usize { - ports.iter().fold(0, |acc, port| acc + self.tcp_tx[*port as usize]) - } - - pub fn many_tcp_rx(&self, ports: &[u16]) -> usize { - ports.iter().fold(0, |acc, port| acc + self.tcp_rx[*port as usize]) - } -} diff --git a/src/ethertype.rs b/src/ethertype.rs deleted file mode 100644 index 0d728f3..0000000 --- a/src/ethertype.rs +++ /dev/null @@ -1,20 +0,0 @@ -#[derive(Copy, Clone, Debug, PartialEq)] -pub enum EtherType { - /// The frame type is IEEE 802.3 and this is it's length - Length(u16), - IPv4, - IPv6, - Unknown(u16), -} - -impl EtherType { - //TODO: check ethertype is correct - pub fn new(n: u16) -> Self { - match n { - n if n <= 1500 => Self::Length(n), - 0x0800 => Self::IPv4, - 0x86DD => Self::IPv6, - n => Self::Unknown(n), - } - } -} diff --git a/src/ippacket.rs b/src/ippacket.rs deleted file mode 100644 index 60858d2..0000000 --- a/src/ippacket.rs +++ /dev/null @@ -1,99 +0,0 @@ -use std::net::Ipv4Addr; - -pub struct Ipv4Packet<'p> { - /// The computed size of the IP packet - header_length: usize, - /// The total length of the IP packet when all fragments are combined - total_length: u16, - more_fragments: bool, - fragment_offset: usize, - next_header: IpNextHeader, - pub src: Ipv4Addr, - pub dst: Ipv4Addr, - payload: &'p [u8], -} - -impl<'p> Ipv4Packet<'p> { - pub fn new(buffer: &'p [u8]) -> Self { - let ihl = buffer[0].to_be() & 0b0000_1111; - let header_length = ihl as usize * 4; - - let total_length = u16::from_be_bytes([buffer[2], buffer[3]]); - - // Fragmentation - let more_fragments = (buffer[6] & 0b0010_0000) > 0; - let fragment_offset = u16::from_be_bytes([buffer[6] & 0b0001_1111, buffer[7]]); - // Fragments are in units of 8 bytes - let true_frag_offset = fragment_offset as usize * 8; - - let next_header = IpNextHeader::new(buffer[9]); - - let src = Ipv4Addr::new(buffer[12], buffer[13], buffer[14], buffer[15]); - let dst = Ipv4Addr::new(buffer[16], buffer[17], buffer[18], buffer[19]); - - Self { - header_length, - total_length, - more_fragments, - fragment_offset: true_frag_offset, - next_header, - src, - dst, - payload: &buffer[header_length..], - } - } - - pub fn get_source(&self) -> Ipv4Addr { - self.src - } - - pub fn get_destination(&self) -> Ipv4Addr { - self.dst - } - - pub fn has_more_fragments(&self) -> bool { - self.more_fragments - } - - pub fn get_fragment_offset(&self) -> usize { - self.fragment_offset - } - - pub fn get_next_header(&self) -> IpNextHeader { - self.next_header - } - - pub fn get_payload(&self) -> &[u8] { - &self.payload - } - - pub fn get_packet_len(&self) -> usize { - self.total_length as usize - } - - pub fn get_payload_len(&self) -> usize { - // An IPv4 header is always 20 bytes long - self.total_length as usize - 20 - } -} - -#[derive(Copy, Clone, Debug, PartialEq)] -pub enum IpNextHeader { - Icmp, - Igmp, - Tcp, - Udp, - Unknown(u8), -} - -impl IpNextHeader { - pub fn new(n: u8) -> Self { - match n { - 1 => Self::Icmp, - 2 => Self::Igmp, - 6 => Self::Tcp, - 17 => Self::Udp, - n => Self::Unknown(n), - } - } -} diff --git a/src/layer3.rs b/src/layer3.rs deleted file mode 100644 index 7521c0d..0000000 --- a/src/layer3.rs +++ /dev/null @@ -1,65 +0,0 @@ -pub struct Tcp<'p> { - src: u16, - dst: u16, - payload: &'p [u8], -} - -impl<'p> Tcp<'p> { - pub fn new(buffer: &'p [u8]) -> Self { - let src = u16::from_be_bytes([buffer[0], buffer[1]]); - let dst = u16::from_be_bytes([buffer[2], buffer[3]]); - let data_offset = (buffer[12].to_be() & 0b1111_0000) >> 4; - // Offset is number of 32-bit words - let true_offset = data_offset as usize * 4; - - Self { - src, - dst, - payload: &buffer[true_offset..], - } - } - - pub fn source_port(&self) -> u16 { - self.src - } - - pub fn destination_port(&self) -> u16 { - self.dst - } - - pub fn payload(&self) -> &[u8] { - self.payload - } -} - -pub struct Udp<'p> { - src: u16, - dst: u16, - payload: &'p [u8], -} - -impl<'p> Udp<'p> { - pub fn new(buffer: &'p [u8]) -> Self { - let src = u16::from_be_bytes([buffer[0], buffer[1]]); - let dst = u16::from_be_bytes([buffer[2], buffer[3]]); - let _len = u16::from_be_bytes([buffer[4], buffer[5]]); - - Self { - src, - dst, - payload: &buffer[8..], - } - } - - pub fn source_port(&self) -> u16 { - self.src - } - - pub fn destination_port(&self) -> u16 { - self.dst - } - - pub fn payload(&self) -> &[u8] { - self.payload - } -} diff --git a/src/main.rs b/src/main.rs deleted file mode 100644 index 3b0f63c..0000000 --- a/src/main.rs +++ /dev/null @@ -1,172 +0,0 @@ -use std::{cell::UnsafeCell, error::Error, net::Ipv4Addr, rc::Rc, thread::JoinHandle}; - -use count::Count; -use ethertype::EtherType; -use ippacket::{IpNextHeader, Ipv4Packet}; -use layer3::{Tcp, Udp}; -use pnet_datalink::{Channel, Config}; -use scurvy::{Argument, Scurvy}; -use smol::{ - LocalExecutor, - channel::{self, Receiver, Sender}, - io::AsyncWriteExt, - net::TcpListener, -}; - -mod count; -mod ethertype; -mod ippacket; -mod layer3; - -fn main() -> Result<(), Box> { - let args = vec![ - Argument::new(&["interface", "iface"]).arg("dev"), - Argument::new("ip").arg("addr"), - ]; - let scurvy = Scurvy::make(args); - - let interface_name = scurvy.get("interface").unwrap(); - let interface = match pnet_datalink::interfaces().iter().find(|i| i.name == interface_name) { - None => { - eprintln!("No interface found named '{interface_name}'"); - return Ok(()); - } - Some(i) => i.clone(), - }; - - let ip_want: Ipv4Addr = scurvy.get("ip").unwrap().parse()?; - - let mut channel = match pnet_datalink::channel(&interface, Config::default())? { - Channel::Ethernet(_tx, rx) => rx, - _ => unimplemented!(), - }; - - let stat = stat_thread(); - - loop { - let pkt = channel.next()?; - - let ethertype = EtherType::new(u16::from_be_bytes([pkt[12], pkt[13]])); - let eth_payload = &pkt[14..]; - - match ethertype { - EtherType::IPv4 => { - let ip = Ipv4Packet::new(eth_payload); - let ip_payload = ip.get_payload(); - - let ip_tx = if ip.src == ip_want { - true - } else if ip.dst == ip_want { - false - } else { - continue; - }; - - // 6 byte per MAC (x2), 2 byte ethertype, 2 byte crc - let total_l2_len = ip.get_packet_len() + 18; - - match ip.get_next_header() { - IpNextHeader::Tcp => { - let tcp = Tcp::new(ip_payload); - - stat.tx.send_blocking(Meow::Tcp { - tx: ip_tx, - src: tcp.source_port(), - dst: tcp.destination_port(), - len: total_l2_len, - })?; - } - IpNextHeader::Udp => { - let udp = Udp::new(ip_payload); - - stat.tx.send_blocking(Meow::Udp { - tx: ip_tx, - src: udp.source_port(), - dst: udp.destination_port(), - len: total_l2_len, - })?; - } - _ => (), - } - } - _ => (), - } - } -} - -#[allow(dead_code)] -struct StatHandle { - hwnd: JoinHandle<()>, - tx: Sender, -} - -enum Meow { - Tcp { - tx: bool, - src: u16, - dst: u16, - len: usize, - }, - Udp { - tx: bool, - src: u16, - dst: u16, - len: usize, - }, -} - -fn stat_thread() -> StatHandle { - let (tx, rx) = channel::unbounded(); - - let hwnd = std::thread::spawn(|| stat(rx)); - - StatHandle { hwnd, tx } -} - -fn stat(rx: Receiver) { - let cat = Rc::new(UnsafeCell::new(Count::new())); - - let ex = Rc::new(LocalExecutor::new()); - - ex.spawn(async { - loop { - match rx.recv().await { - Err(_e) => { - eprintln!("error receiving! breaking from loop"); - break; - } - Ok(Meow::Tcp { tx, src, dst, len }) => { - unsafe { &mut *cat.get() }.push_tcp(tx, src, dst, len); - } - Ok(Meow::Udp { tx, src, dst, len }) => { - unsafe { &mut *cat.get() }.push_udp(tx, src, dst, len); - } - } - } - }) - .detach(); - - let run_cat = Rc::clone(&cat); - let run_ex = Rc::clone(&ex); - let run = ex.run(async move { - let socket = TcpListener::bind("127.0.0.1:6666").await.unwrap(); - - loop { - let (mut stream, _caddr) = socket.accept().await.unwrap(); - let per_spawn_cat = Rc::clone(&run_cat); - - run_ex - .spawn(async move { - let cat = unsafe { &mut *per_spawn_cat.get() }; - let http_tx = cat.many_tcp_tx(&[80, 443]); - let http_rx = cat.many_tcp_rx(&[80, 443]); - - let str = format!("{http_tx}\n{http_rx}"); - stream.write_all(str.as_bytes()).await.unwrap(); - }) - .detach(); - } - }); - - smol::block_on(run); -} -- cgit 1.4.1-3-g733a5