diff options
author | Toby Vincent <tobyv@tobyvin.dev> | 2024-04-21 15:13:11 -0500 |
---|---|---|
committer | Toby Vincent <tobyv@tobyvin.dev> | 2024-04-21 15:13:11 -0500 |
commit | e8cddad2374f8a440c8dbc688a5827af8a938c5b (patch) | |
tree | 6b1fec08640e93db5b8b4b6d2cc5abb3fe51c786 | |
parent | c34b0b3704499279aa675ff920479d84d8131ded (diff) |
feat: add ICMP fallback and handle unspecified netnetlink
-rw-r--r-- | Cargo.lock | 267 | ||||
-rw-r--r-- | Cargo.toml | 1 | ||||
-rw-r--r-- | src/config.rs | 14 | ||||
-rw-r--r-- | src/error.rs | 6 | ||||
-rw-r--r-- | src/main.rs | 8 | ||||
-rw-r--r-- | src/netlink.rs | 3 | ||||
-rw-r--r-- | src/scanner.rs | 8 |
7 files changed, 294 insertions, 13 deletions
@@ -18,6 +18,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" [[package]] +name = "aho-corasick" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" +dependencies = [ + "memchr", +] + +[[package]] name = "anstream" version = "0.6.11" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -94,6 +103,12 @@ dependencies = [ [[package]] name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bitflags" version = "2.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed570934406eb16438a4e976b1b4500774099c13b8cb96eec99f620f05090ddf" @@ -279,12 +294,29 @@ dependencies = [ ] [[package]] +name = "getrandom" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94b22e06ecb0110981051723910cbf0b5f5e09a2062dd7663334ee79a9d1286c" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] name = "gimli" version = "0.28.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" [[package]] +name = "glob" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" + +[[package]] name = "heck" version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -297,6 +329,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bd5256b483761cd23699d0da46cc6fd2ee3be420bbe6d020ae4a091e70b7e9fd" [[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + +[[package]] name = "ipnet" version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -321,6 +359,16 @@ dependencies = [ ] [[package]] +name = "lock_api" +version = "0.4.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c168f8615b12bc01f9c17e2eb0cc07dcae1940121185446edc3744920e8ef45" +dependencies = [ + "autocfg", + "scopeguard", +] + +[[package]] name = "log" version = "0.4.20" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -448,12 +496,18 @@ version = "0.27.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2eb04e9c688eff1c89d72b407f168cf79bb9e867a9d3323ed6c01519eb9cc053" dependencies = [ - "bitflags", + "bitflags 2.4.2", "cfg-if", "libc", ] [[package]] +name = "no-std-net" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43794a0ace135be66a25d3ae77d41b91615fb68ae937f904090203e81f755b65" + +[[package]] name = "num_cpus" version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -473,6 +527,35 @@ dependencies = [ ] [[package]] +name = "once_cell" +version = "1.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" + +[[package]] +name = "parking_lot" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c42a9226546d68acdd9c0a280d17ce19bfe27a46bf68784e4066115788d008e" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-targets 0.48.5", +] + +[[package]] name = "paste" version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -491,6 +574,54 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" [[package]] +name = "pnet_base" +version = "0.34.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe4cf6fb3ab38b68d01ab2aea03ed3d1132b4868fa4e06285f29f16da01c5f4c" +dependencies = [ + "no-std-net", +] + +[[package]] +name = "pnet_macros" +version = "0.34.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "688b17499eee04a0408aca0aa5cba5fc86401d7216de8a63fdf7a4c227871804" +dependencies = [ + "proc-macro2", + "quote", + "regex", + "syn 2.0.48", +] + +[[package]] +name = "pnet_macros_support" +version = "0.34.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eea925b72f4bd37f8eab0f221bbe4c78b63498350c983ffa9dd4bcde7e030f56" +dependencies = [ + "pnet_base", +] + +[[package]] +name = "pnet_packet" +version = "0.34.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9a005825396b7fe7a38a8e288dbc342d5034dac80c15212436424fef8ea90ba" +dependencies = [ + "glob", + "pnet_base", + "pnet_macros", + "pnet_macros_support", +] + +[[package]] +name = "ppv-lite86" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" + +[[package]] name = "proc-macro2" version = "1.0.78" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -509,6 +640,74 @@ dependencies = [ ] [[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "redox_syscall" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" +dependencies = [ + "bitflags 1.3.2", +] + +[[package]] +name = "regex" +version = "1.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c117dbdfde9c8308975b6a18d71f3f385c89461f7b3fb054288ecf2a2058ba4c" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86b83b8b9847f9bf95ef68afb0b8e6cdb80f498442f5179a29fad448fcc1eaea" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adad44e29e4c806119491a7f06f03de4d1af22c3a680dd47f1e6e179439d1f56" + +[[package]] name = "rtnetlink" version = "0.14.1" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -533,6 +732,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" [[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[package]] name = "serde" version = "1.0.197" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -562,13 +767,19 @@ dependencies = [ ] [[package]] +name = "smallvec" +version = "1.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" + +[[package]] name = "socket2" -version = "0.5.5" +version = "0.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b5fac59a5cb5dd637972e5fca70daf0523c9067fcdc4842f053dae04a18f8e9" +checksum = "05ffd9c0a93b7543e062e759284fcf5f5e3b098501104bfbdde4d404db792871" dependencies = [ "libc", - "windows-sys 0.48.0", + "windows-sys 0.52.0", ] [[package]] @@ -583,6 +794,7 @@ dependencies = [ "local-ip-address", "netlink-packet-route", "rtnetlink", + "surge-ping", "thiserror", "tokio", ] @@ -594,6 +806,22 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" [[package]] +name = "surge-ping" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "efbf95ce4c7c5b311d2ce3f088af2b93edef0f09727fa50fbe03c7a979afce77" +dependencies = [ + "hex", + "parking_lot", + "pnet_packet", + "rand", + "socket2", + "thiserror", + "tokio", + "tracing", +] + +[[package]] name = "syn" version = "1.0.109" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -664,6 +892,37 @@ dependencies = [ ] [[package]] +name = "tracing" +version = "0.1.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" +dependencies = [ + "pin-project-lite", + "tracing-attributes", + "tracing-core", +] + +[[package]] +name = "tracing-attributes" +version = "0.1.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.48", +] + +[[package]] +name = "tracing-core" +version = "0.1.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" +dependencies = [ + "once_cell", +] + +[[package]] name = "unicode-ident" version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -18,3 +18,4 @@ netlink-packet-route = "0.19.0" thiserror = "1.0.57" ipnet = "2.9.0" local-ip-address = "0.6.1" +surge-ping = "0.8.1" diff --git a/src/config.rs b/src/config.rs index 5d49042..e7ee2e9 100644 --- a/src/config.rs +++ b/src/config.rs @@ -14,13 +14,17 @@ pub struct Config { #[arg(short, long)] pub port: Option<u16>, - /// wait <TIMEOUT> (ms) when checking for open ports in ms (requires --port=<PORT>) - #[arg(short, long, default_value_t = 250, requires = "port")] + /// <TIMEOUT> (ms) used for ICMP (or TCP when using --port=<PORT>) + #[arg(short, long, default_value_t = 250)] pub timeout: u64, - /// Discover hosts on <NETWORK> with <PORT> (requires --port=<PORT>) - #[arg(short, long, id = "NETWORK", requires = "port")] - pub scan: Option<IpNet>, + /// Include network neighbours + #[arg(short, long)] + pub neigh: bool, + + /// Discover hosts on <NETWORK> + #[arg(short, long, id = "NETWORK")] + pub scan: Option<Option<IpNet>>, /// include <NAME>. If <NAME> is a valid path or '-', hosts with be read from the file or /// stdin, respectivly. diff --git a/src/error.rs b/src/error.rs index e98fe68..048440c 100644 --- a/src/error.rs +++ b/src/error.rs @@ -10,6 +10,12 @@ pub enum Error { #[error("IO error: {0}")] IO(#[from] std::io::Error), + #[error("Local IP error: {0}")] + LocalIp(#[from] local_ip_address::Error), + + #[error("IpNet error: {0}")] + IpNet(#[from] ipnet::PrefixLenError), + #[error("Join error: {0}")] Join(#[from] tokio::task::JoinError), diff --git a/src/main.rs b/src/main.rs index 6f60514..529c1ed 100644 --- a/src/main.rs +++ b/src/main.rs @@ -15,6 +15,8 @@ use tokio::{ mod config; +const PAYLOAD: [u8; 8] = [0; 8]; + #[tokio::main] async fn main() -> Result<(), anyhow::Error> { let config = Config::parse(); @@ -53,7 +55,9 @@ async fn main() -> Result<(), anyhow::Error> { let cache = Arc::new(Mutex::new(cache)); let names = Arc::new(Mutex::new(names)); - join_set.spawn(sshr::netlink::neighbours(tx.clone())); + if config.neigh { + join_set.spawn(sshr::netlink::neighbours(tx.clone())); + } if let Some(ip_net) = config.scan { join_set.spawn(sshr::scanner::scan(tx.clone(), ip_net)); @@ -76,6 +80,8 @@ async fn main() -> Result<(), anyhow::Error> { if block_in_place(|| TcpStream::connect_timeout(&addr, timeout)).is_err() { return Ok(()); } + } else if surge_ping::ping(ip_addr, &PAYLOAD).await.is_err() { + return Ok(()); } if let Some(s) = config.resolve.then(|| lookup_addr(&ip_addr).ok()).flatten() { diff --git a/src/netlink.rs b/src/netlink.rs index 2945a09..9e21dbc 100644 --- a/src/netlink.rs +++ b/src/netlink.rs @@ -1,8 +1,7 @@ -use std::{collections::HashSet, net::IpAddr}; +use std::net::IpAddr; use futures::stream::TryStreamExt; use netlink_packet_route::{ - address::AddressAttribute, neighbour::{NeighbourAddress, NeighbourAttribute, NeighbourMessage, NeighbourState}, route::RouteType, }; diff --git a/src/scanner.rs b/src/scanner.rs index fa801e5..c51dffc 100644 --- a/src/scanner.rs +++ b/src/scanner.rs @@ -5,7 +5,13 @@ use tokio::{sync::mpsc::Sender, task::JoinSet}; use crate::Result; -pub async fn scan(tx: Sender<IpAddr>, ip_net: IpNet) -> Result<()> { +pub async fn scan(tx: Sender<IpAddr>, ip_net: Option<IpNet>) -> Result<()> { + let ip_net = match ip_net { + Some(net) if !net.addr().is_unspecified() => net, + Some(net) => IpNet::new(local_ip_address::local_ip()?, net.prefix_len())?, + None => IpNet::new(local_ip_address::local_ip()?, 24)?, + }; + let mut join_set = JoinSet::new(); for ip_addr in ip_net.hosts() { let tx = tx.clone(); |