partly working implementation
This commit is contained in:
1 parent
27aa972fe6
commit
b147006a69
13 files changed
+1542
-678
No files matched your search
+77
-34
@@ -4,68 +4,118 @@ use nix::sys::socket::{
|
||||
};
|
||||
use std::error::Error;
|
||||
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddrV4, SocketAddrV6};
|
||||
use std::os::unix::io::RawFd;
|
||||
use std::str::FromStr;
|
||||
use std::sync::mpsc::Sender;
|
||||
use std::sync::{Arc, Mutex};
|
||||
use std::thread;
|
||||
use std::time::Duration;
|
||||
|
||||
pub enum SocketType {
|
||||
ICMP,
|
||||
UDP,
|
||||
}
|
||||
|
||||
pub struct PingReply {
|
||||
pub(crate) reflector: IpAddr,
|
||||
pub(crate) seq: u16,
|
||||
pub(crate) rtt: i64,
|
||||
pub(crate) current_time: i64,
|
||||
pub(crate) down_time: f64,
|
||||
pub(crate) up_time: f64,
|
||||
pub(crate) originate_timestamp: i64,
|
||||
pub(crate) receive_timestamp: i64,
|
||||
pub(crate) transmit_timestamp: i64,
|
||||
pub(crate) last_receive_time_s: f64,
|
||||
}
|
||||
|
||||
fn open_socket(type_: SocketType) -> RawFd {
|
||||
match type_ {
|
||||
ICMP => {
|
||||
socket(
|
||||
AddressFamily::Inet,
|
||||
SockType::Raw,
|
||||
SockFlag::empty(), /* value */
|
||||
SockProtocol::ICMP,
|
||||
)
|
||||
}
|
||||
UDP => {
|
||||
socket(
|
||||
AddressFamily::Inet,
|
||||
SockType::Datagram,
|
||||
SockFlag::empty(), /* value */
|
||||
SockProtocol::Udp,
|
||||
)
|
||||
}
|
||||
}
|
||||
.expect("Couldn't open socket")
|
||||
}
|
||||
|
||||
pub trait PingListener {
|
||||
fn new(id: u16, reflectors: Vec<IpAddr>) -> Self;
|
||||
|
||||
fn new(id: u16) -> Self;
|
||||
fn get_id(&self) -> u16;
|
||||
fn get_reflectors(&self) -> Vec<IpAddr>;
|
||||
|
||||
fn listen(&mut self) {
|
||||
let socket = socket(
|
||||
AddressFamily::Inet,
|
||||
SockType::Raw,
|
||||
SockFlag::empty(), /* value */
|
||||
SockProtocol::ICMP,
|
||||
)
|
||||
.expect("Couldn't open socket");
|
||||
fn listen(
|
||||
&mut self,
|
||||
type_: SocketType,
|
||||
reflectors_lock: Arc<Mutex<Vec<IpAddr>>>,
|
||||
stats_sender: Sender<PingReply>,
|
||||
) {
|
||||
let socket = open_socket(type_);
|
||||
|
||||
loop {
|
||||
let mut v: Vec<u8> = vec![0; 128];
|
||||
let buf = v.as_mut_slice();
|
||||
let mut v: Vec<u8> = vec![0; 40];
|
||||
let mut buf = v.as_mut_slice();
|
||||
|
||||
let (size, sender) = match recvfrom::<SockaddrIn>(socket, buf) {
|
||||
Ok(val) => val,
|
||||
Err(_) => continue,
|
||||
};
|
||||
|
||||
let (rtt, down_time, up_time) = match Self::parse_packet(buf, size) {
|
||||
// etherparse doesn't like when the size in the header doesn't match the buffer
|
||||
// so resize the buffer when actual packet size is known
|
||||
buf = buf[..size].as_mut();
|
||||
|
||||
let addr_bytes = sender.expect("Should be an address here").ip();
|
||||
let addr = IpAddr::from(addr_bytes.to_be_bytes());
|
||||
|
||||
let reflectors = reflectors_lock.lock().unwrap();
|
||||
if !reflectors.contains(&addr) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let reply = match Self::parse_packet(addr, buf, size) {
|
||||
Ok(val) => val,
|
||||
Err(e) => {
|
||||
println!("Shit went to hell: {}", e.to_string());
|
||||
continue;
|
||||
}
|
||||
};
|
||||
|
||||
println!("Type: {:4} | Reflector IP: {:>15} | Seq: {:5} | Current time: {:8} | Originate: {:8} | Received time: {:8} | Transmit time : {:8} | RTT: {:8} | UL time: {:5} | DL time: {:5}", "ICMP", addr.to_string(), reply.seq, reply.current_time, reply.originate_timestamp, reply.receive_timestamp, reply.transmit_timestamp, reply.rtt, reply.up_time, reply.down_time);
|
||||
stats_sender.send(reply).unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_packet(buf: &[u8], len: usize) -> Result<(i64, i64, i64), Box<dyn Error>>;
|
||||
fn parse_packet(reflector: IpAddr, buf: &[u8], len: usize)
|
||||
-> Result<PingReply, Box<dyn Error>>;
|
||||
}
|
||||
|
||||
pub trait PingSender {
|
||||
fn new(id: u16, reflectors: Vec<IpAddr>) -> Self;
|
||||
|
||||
fn new(id: u16) -> Self;
|
||||
fn get_id(&self) -> u16;
|
||||
fn get_reflectors(&self) -> Vec<IpAddr>;
|
||||
|
||||
fn send(&mut self) {
|
||||
let socket = socket(
|
||||
AddressFamily::Inet,
|
||||
SockType::Raw,
|
||||
SockFlag::empty(), /* value */
|
||||
SockProtocol::ICMP,
|
||||
)
|
||||
.expect("Couldn't open socket");
|
||||
fn send(&mut self, type_: SocketType, reflectors_lock: Arc<Mutex<Vec<IpAddr>>>) {
|
||||
let socket = open_socket(type_);
|
||||
|
||||
let mut seq: u16 = 0;
|
||||
let tick_duration_ms: u16 = 500;
|
||||
let sleep_duration = Duration::from_millis(tick_duration_ms as u64);
|
||||
|
||||
loop {
|
||||
let reflectors = Self::get_reflectors(self);
|
||||
let reflectors_unlocked = reflectors_lock.lock().unwrap();
|
||||
let reflectors = reflectors_unlocked.clone();
|
||||
drop(reflectors_unlocked);
|
||||
|
||||
for reflector in reflectors.iter() {
|
||||
let addr: Box<dyn SockaddrLike>;
|
||||
@@ -101,10 +151,3 @@ pub trait PingSender {
|
||||
|
||||
fn craft_packet(&self, seq: u16) -> Vec<u8>;
|
||||
}
|
||||
|
||||
pub trait Pinger {
|
||||
fn new(id: u16, reflectors: Vec<IpAddr>) -> Self;
|
||||
fn receive_loop(&mut self);
|
||||
fn sender_loop(&mut self);
|
||||
fn send_ping(&mut self, reflector: &IpAddr, id: u16, seq: u16) -> Result<(), Box<dyn Error>>;
|
||||
}
|
||||
Reference in new issue
Block a user