1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
|
use std::{
io::{stdout, Write},
net::TcpStream,
sync::{Arc, Mutex},
time::Duration,
};
use clap::Parser;
use config::Config;
use dns_lookup::{lookup_addr, lookup_host};
use tokio::{
sync::mpsc,
task::{block_in_place, JoinSet},
};
mod config;
#[tokio::main]
async fn main() -> Result<(), anyhow::Error> {
let config = Config::parse();
let mut join_set = JoinSet::new();
let (tx, mut rx) = mpsc::channel(100);
let (mut cache, mut names) = config.excluded()?;
cache.extend(
local_ip_address::list_afinet_netifas()
.into_iter()
.flatten()
.map(|(_, i)| i),
);
let (included_ip, included_hostname) = config.included()?;
for ip_addr in included_ip {
tx.send(ip_addr).await?;
}
for hostname in included_hostname {
if names.insert(hostname.clone()) {
let mut stdout = stdout().lock();
writeln!(stdout, "{hostname}")?;
}
if config.resolve {
for ip in lookup_host(&hostname)? {
cache.insert(ip);
}
}
}
let cache = Arc::new(Mutex::new(cache));
let names = Arc::new(Mutex::new(names));
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));
}
drop(tx);
let timeout = Duration::from_millis(config.timeout);
while let Some(ip_addr) = rx.recv().await {
let names = names.clone();
let cache = cache.clone();
join_set.spawn(async move {
if !cache.lock()?.insert(ip_addr) {
return Ok(());
}
if let Some(port) = config.port {
let addr = (ip_addr, port).into();
if block_in_place(|| TcpStream::connect_timeout(&addr, timeout)).is_err() {
return Ok(());
}
}
if let Some(s) = config.resolve.then(|| lookup_addr(&ip_addr).ok()).flatten() {
if names.lock()?.insert(s.clone()) {
let mut stdout = stdout().lock();
writeln!(stdout, "{s}")?;
}
} else {
let mut stdout = stdout().lock();
writeln!(stdout, "{ip_addr}")?;
};
Ok(())
});
}
while let Some(res) = join_set.join_next().await {
res??;
}
Ok(())
}
|