Stash commit 📦

This commit is contained in:
Sivert V. Sæther 2023-01-13 17:55:57 +01:00
parent 23ce3ef304
commit b49f55796f
6 changed files with 149 additions and 81 deletions

View File

@ -1,3 +1,4 @@
#[allow(clippy::upper_case_acronyms)]
use std::{
io, net::IpAddr,
time::Duration,

View File

@ -1,9 +1,6 @@
use std::{
sync::{Mutex, Arc},
time::Duration,
thread::sleep,
net::IpAddr,
vec::Vec, io};
sync::{Mutex, Arc}, time::Duration, thread::sleep,
net::{Ipv4Addr, IpAddr}, vec::Vec, io};
use log::{trace, warn, error};
use tokio::{
@ -12,13 +9,8 @@ use tokio::{
use nbd::server::Blocks;
use icmp::IcmpSocket;
use crate::{
ICMP_PACKET, IPStore,
pinger::connect,
checksum,
get_rt};
const SIZE: usize = 64; // Bits of data in each ping
static WORD_COUNT: usize = SIZE / 8; // Number of 16-bit words in each ping
ICMP_PACKET, BYTE_COUNT, PACKET_SIZE, SIZE,
IPStore, checksum, connect, get_rt};
type Message = (usize, usize, Vec<u8>); // Message type for the write channel
@ -56,7 +48,7 @@ impl PingStore {
let offset = store.pings.lock().unwrap().len() * 7;
let mut ping = Ping::new();
for j in 0..7 {
ping.add(ips.dsts[offset + j].ip);
ping.add(IpAddr::V4(ips.dsts[offset + j].ip));
}
store.pings.lock().unwrap().push(ping);
store.size += 1;
@ -124,7 +116,7 @@ impl PingStore {
impl Blocks for PingStore {
fn read_at(&self, buf: &mut [u8], off: u64) -> io::Result<()> {
let addr = (off as usize).div_floor(WORD_COUNT);
let addr = (off as usize).div_floor(BYTE_COUNT);
let buflen = buf.len();
let mut res = vec![];
for pingspan in 0..buflen.div_ceil(SIZE) {
@ -136,10 +128,10 @@ impl Blocks for PingStore {
}
fn write_at(&self, buf: &[u8], off: u64) -> io::Result<()> {
let addr = (off as usize).div_ceil(WORD_COUNT);
let addr = (off as usize).div_ceil(BYTE_COUNT);
let buflen = buf.len();
get_rt("channel pusher", num_cpus::get().div_floor(3) + 1).block_on(
self.write(buf, addr, (addr * WORD_COUNT) - off as usize, buflen))?;
self.write(buf, addr, (addr * BYTE_COUNT) - off as usize, buflen))?;
Ok(())
}

View File

@ -1,20 +1,68 @@
#![feature(bigint_helper_methods)]
#![feature(async_closure)]
//#![feature(async_closure)]
#![feature(int_roundings)]
#![feature(never_type)]
#![feature(ip)]
pub mod scanner;
pub mod pinger;
//pub mod pinger;
pub mod blocks;
pub mod store;
mod store;
pub use blocks::PingStore;
pub use scanner::Scanner;
pub use pinger::{
ICMP_PACKET, TIMEOUT, Pinger};
//pub use pinger::Pinger;
pub use store::IPStore;
/// ICMP packet header template
pub const ICMP_PACKET: [u8; 8] = [
8, 0, // 8 Echo ping request, code 0
0, 0, // Index 2 and 3 are for ICMP checksum
0xde, 0xad, // Identifier
0, 1, // Sequence numbers
];
pub const SIZE: usize = 64; // Bytes of echo data in each ping
pub const PACKET_SIZE: usize = SIZE + 16; // Echo data size plus rest of ICMP packet
pub const BYTE_COUNT: usize = SIZE / 8;
pub static mut TIMEOUT: Option<std::time::Duration> = None;
/// Get an IcmpSocket from IpAddr and set the global timeout on the socket
pub fn connect(ip: std::net::IpAddr) -> icmp::IcmpSocket {
let sock = match icmp::IcmpSocket::connect(ip) {
Err(err) => panic!("Unable to open ICMP socket: {err:?}"),
Ok(sock) => sock,
};
let timeout = unsafe { TIMEOUT };
if timeout.is_none() {
return sock;
}
if let Err(err) = sock.set_write_timeout(timeout) {
log::debug!("unable to set write timeout on socket: {}", err);
};
if let Err(err) = sock.set_read_timeout(timeout) {
log::debug!("unable to set read timeout on socket: {}", err);
};
sock
}
#[inline]
/// Get a random IPv4 address
pub fn rand_ip4() -> std::net::Ipv4Addr {
std::net::Ipv4Addr::new(rand::random(), rand::random(), rand::random(), rand::random())
}
#[inline]
/// Get a random globaly accessible IP address
pub fn rand_ip() -> std::net::Ipv4Addr {
let mut ip = rand_ip4();
while !ip.is_global() { ip = rand_ip4() };
//std::net::IpAddr::V4(ip)
ip
}
#[inline]
/// Calculate the "internet checksum"
pub fn checksum(bytes: &[u8]) -> [u8; 2] {
let mut calc = internet_checksum::Checksum::new();
calc.add_bytes(bytes);
@ -22,12 +70,13 @@ pub fn checksum(bytes: &[u8]) -> [u8; 2] {
}
#[inline]
/// Get a new tokio multi thread runtime
pub fn get_rt(name: &str, threads: usize) -> tokio::runtime::Runtime {
match tokio::runtime::Builder::new_multi_thread()
.worker_threads(threads)
.thread_name(name)
.build() {
Err(err) => panic!("Unable to build tokio runtime! {:?}", err),
Err(err) => panic!("Unable to build tokio runtime! {err:?}"),
Ok(rt) => rt,
}
}

View File

@ -6,40 +6,33 @@ use std::{
use log::{trace, debug, info};
use icmp::IcmpSocket;
use rand::random;
use crate::checksum;
pub static mut TIMEOUT: Option<Duration> = None;
pub static ICMP_PACKET: [u8; 8] = [
8, 0, // 8 Echo ping request, code 0
0, 0, // Index 2 and 3 are for ICMP checksum
0xde, 0xad, // Identifier
0, 1, // Sequence numbers
];
use crate::{
ICMP_PACKET, PACKET_SIZE,
TIMEOUT, SIZE, checksum};
pub struct PingResponse {
pub round_trip: usize,
pub corrupt: bool,
pub small: bool,
pub data: [u8; 84],
pub data: [u8; PACKET_SIZE],
}
pub type PingResult = Result<PingResponse, io::Error>;
pub struct Pinger {
pub data: [u8; 64],
pub data: [u8; SIZE],
pub seq: [u8; 2],
}
impl Pinger {
pub fn new() -> Self {
Self {
data: [0; 64],
data: [0; SIZE],
seq: [1, 0],
}
}
pub fn data(mut self, data: [u8; 64]) -> Self {
pub fn data(mut self, data: [u8; SIZE]) -> Self {
self.data = data;
self
}
@ -68,7 +61,7 @@ impl Pinger {
};
self.inc_seq();
let mut response: [u8; 64 + 20] = [0; 64 + 20];
let mut response: [u8; PACKET_SIZE] = [0; PACKET_SIZE];
match socket.recv(&mut response) {
Err(err) => {
@ -78,7 +71,7 @@ impl Pinger {
Ok(size) => {
let mut result = PingResponse::new(response, start.elapsed().as_millis() as usize);
if size != 84 {
if size != PACKET_SIZE {
debug!("Didn't revice full response from \"{}\"", ip);
trace!("Response in question: {:?}", response);
result.corrupt = true;
@ -141,7 +134,7 @@ pub fn rand_ip() -> IpAddr {
}
impl PingResponse {
fn new(data: [u8; 84], round_trip: usize) -> Self {
fn new(data: [u8; PACKET_SIZE], round_trip: usize) -> Self {
Self {
round_trip,
corrupt: false,
@ -153,7 +146,7 @@ impl PingResponse {
impl Default for PingResponse {
fn default() -> Self {
Self::new([0; 84], 0)
Self::new([0; PACKET_SIZE], 0)
}
}

View File

@ -1,32 +1,43 @@
use std::{
vec::Vec, net::{Ipv4Addr, IpAddr},
time::Duration, thread::sleep};
time::{Duration, Instant},
net::{Ipv4Addr, IpAddr},
thread::sleep, io,
vec::Vec};
use serde::{Deserialize, Serialize};
use log::{trace, debug, info, error};
use tokio::task;
use icmp::IcmpSocket;
use tokio::{task, };
use crate::{
pinger::rand_ip,
IPStore, Pinger};
ICMP_PACKET, PACKET_SIZE, SIZE,
IPStore, checksum, connect,
rand_ip};
//static PROBE_CHK: [u8; 2] = [0x51, 0x59];
static PROBE: [u8; 64] = [0x66; 64];
static PROBE: [u8; SIZE] = [0x66; SIZE];
#[derive(Clone)]
pub struct Scanner {
pub dsts: Vec<Destination>,
pub dead: Vec<IpAddr>,
pub dead: Vec<Ipv4Addr>,
}
#[derive(Deserialize, Serialize, Clone)]
pub struct Destination {
pub round_trip: usize, // Round trip in ms
pub small: bool,
pub ip: IpAddr,
pub ip: Ipv4Addr,
}
pub type ScanResult = Result<Destination, IpAddr>;
struct PingResponse {
pub round_trip: usize,
pub corrupt: bool,
pub small: bool,
pub data: [u8; PACKET_SIZE],
}
pub type PingResult = Result<PingResponse, io::Error>;
pub type ScanResult = Result<Destination, Ipv4Addr>;
impl Scanner {
pub fn new() -> Self {
@ -43,16 +54,16 @@ impl Scanner {
}
#[inline]
fn next_ip(&self) -> IpAddr {
// let mut ip = rand_ip();
let mut ip = IpAddr::V4(Ipv4Addr::new(10, 0, 0, 138));
fn next_ip(&self) -> Ipv4Addr {
let mut ip = rand_ip();
// let mut ip = IpAddr::V4(Ipv4Addr::new(10, 0, 0, 138));
while self.scanned(&ip) {
ip = rand_ip(); }
ip
}
#[inline]
fn scanned(&self, ip: &IpAddr) -> bool {
fn scanned(&self, ip: &Ipv4Addr) -> bool {
for dead in &self.dead {
if ip == dead { return true; }
}
@ -64,43 +75,65 @@ impl Scanner {
false
}
async fn pop_futs(&mut self, futs: &mut Vec<task::JoinHandle<ScanResult>>) {
let fut = futs.pop().expect("Unable to pop of futures vec during mass_scan()!");
match fut.await {
Err(err) => {
error!("Joing future: {:?}", err);
},
Ok(res) => match res {
Ok(dst) => self.dsts.push(dst),
Err(ip) => self.dead.push(ip),
}
}
}
pub async fn mass_scan(&mut self, throttle: usize, parallel: usize, limit: usize, rand: bool) {
info!("Starting mass scan with a limit of {} and {} to randomized IP order!", limit, rand);
let duration = Duration::from_millis(throttle as u64);
let mut futs: Vec<task::JoinHandle<ScanResult>> = vec![];
let mut futs: Vec<task::JoinHandle<()>> = vec![];
let listner = task::spawn(listner());
for _i in 0..limit {
if futs.len() >= parallel {
self.pop_futs(&mut futs).await;
pop_futs(&mut futs).await;
}
futs.push(task::spawn(scan(self.next_ip())));
futs.push(task::spawn(ping(self.next_ip(), &PROBE)));
sleep(duration);
}
while !futs.is_empty() {
self.pop_futs(&mut futs).await }
while !futs.is_empty() { pop_futs(&mut futs).await; }
listner.abort();
}
}
pub async fn scan(ip: IpAddr) -> Result<Destination, IpAddr> {
trace!("Scanning IP \"{}\"", ip);
if let Ok(res) = Pinger::new().data(PROBE).ping(ip) {
info!("Good result scanning IP \"{}\": {}ms", ip, res.round_trip);
if res.corrupt { return Err(ip) }
Ok(Destination { ip, small: res.small, round_trip: res.round_trip })
} else { Err(ip) }
async fn pop_futs(futs: &mut Vec<task::JoinHandle<()>>) {
futs.pop().expect("Unable to pop of futures vec during mass_scan()!").await;
}
async fn ping(ip: Ipv4Addr, data: &[u8]) {
trace!("Scanning IP \"{ip}\"");
let mut pack = ICMP_PACKET.to_vec();
pack[4..7].copy_from_slice(&ip.octets());
pack.append(&mut data.to_vec());
let checksum = checksum(&pack);
pack[2] = checksum[0];
pack[3] = checksum[1];
let mut socket = connect(IpAddr::V4(ip));
let start = Instant::now();
match socket.send(&pack) {
Ok(size) => if size != pack.len() { debug!("Sent {size} bytes of {} bytes to {ip}", pack.len()) },
Err(err) => debug!("Unable to ping IP {ip}: {err:?}"),
}
}
async fn listner() -> ! {
let socket = match IcmpSocket::connect(IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0))) {
Err(err) => panic!("Unable to open listening socket: {err:?}"),
Ok(sock) => sock,
};
let mut handles = vec![];
loop {
let mut response: [u8; PACKET_SIZE] = [0; PACKET_SIZE];
match socket.recv(&mut response) {
Ok(size) => handles.push(task::spawn(handler(response, size))),
Err(err) => info!("Error reading a ping reply: {err:?}"),
}
}
}
async fn handler(response: [u8; PACKET_SIZE], size: usize) {
todo!();
}
impl Default for Scanner {

View File

@ -2,7 +2,7 @@ use std::{
fs::OpenOptions,
io::{Write, Read},
str::from_utf8,
net::IpAddr,
net::Ipv4Addr,
vec::Vec};
use log::{trace, debug, error};
@ -14,7 +14,7 @@ use crate::{
#[derive(Deserialize, Serialize)]
pub struct IPStore {
pub dsts: Vec<Destination>,
pub dead: Vec<IpAddr>,
pub dead: Vec<Ipv4Addr>,
}
impl IPStore {