work
This commit is contained in:
1 parent
2644b17818
commit
4f1f89588c
7 files changed
+569
-230
No files matched your search
Generated
+182
-5
@@ -2,12 +2,30 @@
|
||||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
|
||||
[[package]]
|
||||
name = "aho-corasick"
|
||||
version = "0.7.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "autocfg"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
|
||||
|
||||
[[package]]
|
||||
name = "bincode"
|
||||
version = "1.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "1.3.2"
|
||||
@@ -24,10 +42,14 @@ checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610"
|
||||
name = "cake-autorate-rust"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"bincode",
|
||||
"byteorder",
|
||||
"libc",
|
||||
"neli",
|
||||
"nix",
|
||||
"pnet",
|
||||
"pnet_transport",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -42,6 +64,21 @@ version = "1.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3f107b87b6afc2a64fd13cac55fe06d6c8859f12d4b14cbcdd2c67d0976781be"
|
||||
|
||||
[[package]]
|
||||
name = "glob"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574"
|
||||
|
||||
[[package]]
|
||||
name = "ipnetwork"
|
||||
version = "0.19.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1f84f1612606f3753f205a4e9a2efd6fe5b4c573a6269b2cc6c3003d44a0d127"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.132"
|
||||
@@ -57,6 +94,12 @@ dependencies = [
|
||||
"cfg-if",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "2.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d"
|
||||
|
||||
[[package]]
|
||||
name = "memoffset"
|
||||
version = "0.6.5"
|
||||
@@ -103,12 +146,107 @@ dependencies = [
|
||||
"pin-utils",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "no-std-net"
|
||||
version = "0.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "43794a0ace135be66a25d3ae77d41b91615fb68ae937f904090203e81f755b65"
|
||||
|
||||
[[package]]
|
||||
name = "pin-utils"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
|
||||
|
||||
[[package]]
|
||||
name = "pnet"
|
||||
version = "0.31.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0caaf5b11fd907ff15cf14a4477bfabca4b37ab9e447a4f8dead969a59cdafad"
|
||||
dependencies = [
|
||||
"pnet_base",
|
||||
"pnet_datalink",
|
||||
"pnet_packet",
|
||||
"pnet_transport",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pnet_base"
|
||||
version = "0.31.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f9d3a993d49e5fd5d4d854d6999d4addca1f72d86c65adf224a36757161c02b6"
|
||||
dependencies = [
|
||||
"no-std-net",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pnet_datalink"
|
||||
version = "0.31.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e466faf03a98ad27f6e15cd27a2b7cc89e73e640a43527742977bc503c37f8aa"
|
||||
dependencies = [
|
||||
"ipnetwork",
|
||||
"libc",
|
||||
"pnet_base",
|
||||
"pnet_sys",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pnet_macros"
|
||||
version = "0.31.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "48dd52a5211fac27e7acb14cfc9f30ae16ae0e956b7b779c8214c74559cef4c3"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"regex",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pnet_macros_support"
|
||||
version = "0.31.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "89de095dc7739349559913aed1ef6a11e73ceade4897dadc77c5e09de6740750"
|
||||
dependencies = [
|
||||
"pnet_base",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pnet_packet"
|
||||
version = "0.31.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bc3b5111e697c39c8b9795b9fdccbc301ab696699e88b9ea5a4e4628978f495f"
|
||||
dependencies = [
|
||||
"glob",
|
||||
"pnet_base",
|
||||
"pnet_macros",
|
||||
"pnet_macros_support",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pnet_sys"
|
||||
version = "0.31.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "328e231f0add6d247d82421bf3790b4b33b39c8930637f428eef24c4c6a90805"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pnet_transport"
|
||||
version = "0.31.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ff597185e6f1f5671b3122e4dba892a1c73e17c17e723d7669bd9299cbe7f124"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"pnet_base",
|
||||
"pnet_packet",
|
||||
"pnet_sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.43"
|
||||
@@ -128,19 +266,36 @@ dependencies = [
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.143"
|
||||
name = "regex"
|
||||
version = "1.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "53e8e5d5b70924f74ff5c6d64d9a5acd91422117c60f48c4e07855238a254553"
|
||||
checksum = "4c4eb3267174b8c6c2f654116623910a0fef09c4753f8dd83db29c48a0df988b"
|
||||
dependencies = [
|
||||
"aho-corasick",
|
||||
"memchr",
|
||||
"regex-syntax",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex-syntax"
|
||||
version = "0.6.27"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a3f87b73ce11b1619a3c6332f45341e0047173771e8b8b73f87bfeefb7b56244"
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.144"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0f747710de3dcd43b88c9168773254e809d8ddbdf9653b84e2554ab219f17860"
|
||||
dependencies = [
|
||||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.143"
|
||||
version = "1.0.144"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d3d8e8de557aee63c26b85b947f5e59b690d0454c753f3adeb5cd7835ab88391"
|
||||
checksum = "94ed3a816fb1d101812f83e789f888322c34e291f894f19590dc310963e87a00"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@@ -163,3 +318,25 @@ name = "unicode-ident"
|
||||
version = "1.0.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c4f5b37a154999a8f3f98cc23a628d850e154479cd94decf3414696e12e31aaf"
|
||||
|
||||
[[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"
|
||||
@@ -13,10 +13,14 @@ strip = "symbols"
|
||||
|
||||
|
||||
[dependencies]
|
||||
bincode = "1.3.3"
|
||||
byteorder = "1.4.3"
|
||||
libc = "0.2.132"
|
||||
neli = "0.6.2"
|
||||
nix = { version = "0.25.0", features = ["net", "socket", "time"] }
|
||||
pnet = "0.31.0"
|
||||
pnet_transport = "0.31.0"
|
||||
serde = { version = "1.0.144", features = ["derive"] }
|
||||
|
||||
[patch.crates-io]
|
||||
nix = { path = "../nix" }
|
||||
+28
-12
@@ -4,14 +4,18 @@ mod cake;
|
||||
mod config;
|
||||
mod netlink;
|
||||
mod pinger;
|
||||
mod pinger_icmp;
|
||||
mod pinger_icmp_ts;
|
||||
|
||||
use std::net::IpAddr;
|
||||
use std::str::FromStr;
|
||||
use std::{thread, time};
|
||||
use std::{process, thread, time};
|
||||
|
||||
use crate::config::Config;
|
||||
use crate::netlink::{find_interface, find_qdisc, set_qdisc_rate};
|
||||
use crate::pinger::{Pinger, PingerICMPEcho};
|
||||
use crate::netlink::{find_interface, find_qdisc, get_interface_stats, set_qdisc_rate};
|
||||
use crate::pinger::Pinger;
|
||||
use crate::pinger_icmp::PingerICMPEcho;
|
||||
use crate::pinger_icmp_ts::PingerICMPTimestamps;
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! error {
|
||||
@@ -30,7 +34,7 @@ fn main() {
|
||||
println!("starting up");
|
||||
|
||||
let config = Config::new();
|
||||
test(config);
|
||||
test(&config);
|
||||
|
||||
let mut reflectors: Vec<IpAddr> = Vec::new();
|
||||
|
||||
@@ -39,18 +43,30 @@ fn main() {
|
||||
reflectors.push(IpAddr::from_str("9.9.9.9").unwrap());
|
||||
reflectors.push(IpAddr::from_str("9.9.9.10").unwrap());
|
||||
|
||||
let pinger = PingerICMPEcho::new(reflectors);
|
||||
let pinger_receiver = pinger.clone();
|
||||
let pinger_sender = pinger.clone();
|
||||
get_interface_stats(config.upload_interface.as_str()).unwrap();
|
||||
|
||||
let receiver_handle = thread::spawn(move || pinger_receiver.receive_loop());
|
||||
let sender_handle = thread::spawn(move || pinger_sender.sender_loop());
|
||||
let mut pinger_receiver =
|
||||
PingerICMPTimestamps::new((process::id() & 0xFFFF) as u16, reflectors.clone());
|
||||
let mut pinger_sender =
|
||||
PingerICMPTimestamps::new((process::id() & 0xFFFF) as u16, reflectors.clone());
|
||||
|
||||
receiver_handle.join().unwrap();
|
||||
sender_handle.join().unwrap();
|
||||
let receiver_handle = thread::Builder::new()
|
||||
.name("receiver".to_string())
|
||||
.spawn(move || pinger_receiver.receive_loop())
|
||||
.unwrap();
|
||||
let sender_handle = thread::Builder::new()
|
||||
.name("sender".to_string())
|
||||
.spawn(move || pinger_sender.sender_loop())
|
||||
.unwrap();
|
||||
|
||||
let threads = vec![receiver_handle, sender_handle];
|
||||
|
||||
for thread in threads {
|
||||
thread.join().unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
fn test(config: Config) {
|
||||
fn test(config: &Config) {
|
||||
if true {
|
||||
return;
|
||||
}
|
||||
|
||||
+73
-2
@@ -8,9 +8,11 @@ use neli::nl::{NlPayload, Nlmsghdr};
|
||||
use neli::rtnl::{Ifinfomsg, Rtattr, Tcmsg};
|
||||
use neli::socket::NlSocketHandle;
|
||||
use neli::types::{Buffer, RtBuffer};
|
||||
use serde::Deserialize;
|
||||
use std::error::Error;
|
||||
use std::fmt::Display;
|
||||
|
||||
use bincode::deserialize;
|
||||
use std::fmt;
|
||||
|
||||
#[derive(Default, Debug)]
|
||||
@@ -30,6 +32,34 @@ impl Display for NoQdiscFoundError {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Copy, Clone, Default, Debug)]
|
||||
pub struct RtnlLinkStats64 {
|
||||
pub rx_packets: u64,
|
||||
pub tx_packets: u64,
|
||||
pub rx_bytes: u64,
|
||||
pub tx_bytes: u64,
|
||||
pub rx_errors: u64,
|
||||
pub tx_errors: u64,
|
||||
pub rx_dropped: u64,
|
||||
pub tx_dropped: u64,
|
||||
pub multicast: u64,
|
||||
pub collisions: u64,
|
||||
pub rx_length_errors: u64,
|
||||
pub rx_over_errors: u64,
|
||||
pub rx_crc_errors: u64,
|
||||
pub rx_frame_errors: u64,
|
||||
pub rx_fifo_errors: u64,
|
||||
pub rx_missed_errors: u64,
|
||||
pub tx_aborted_errors: u64,
|
||||
pub tx_carrier_errors: u64,
|
||||
pub tx_fifo_errors: u64,
|
||||
pub tx_heartbeat_errors: u64,
|
||||
pub tx_window_errors: u64,
|
||||
pub rx_compressed: u64,
|
||||
pub tx_compressed: u64,
|
||||
pub rx_nohandler: u64,
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub struct Qdisc {
|
||||
ifindex: i32,
|
||||
@@ -39,8 +69,7 @@ pub struct Qdisc {
|
||||
parent: u32,
|
||||
}
|
||||
|
||||
pub fn find_interface(ifname: &str) -> Result<i32, Box<dyn Error>> {
|
||||
let mut socket = NlSocketHandle::connect(NlFamily::Route, None, &[]).unwrap();
|
||||
fn nl_interface_get(socket: &mut NlSocketHandle, ifname: &str) -> Result<(), Box<dyn Error>> {
|
||||
let mut attrs = RtBuffer::new();
|
||||
|
||||
const RTEXT_FILTER_VF: i32 = 1 << 0;
|
||||
@@ -70,6 +99,14 @@ pub fn find_interface(ifname: &str) -> Result<i32, Box<dyn Error>> {
|
||||
|
||||
socket.send(nlhdr)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn find_interface(ifname: &str) -> Result<i32, Box<dyn Error>> {
|
||||
let mut socket = NlSocketHandle::connect(NlFamily::Route, None, &[]).unwrap();
|
||||
|
||||
nl_interface_get(&mut socket, ifname).expect("Wrong when sending intf");
|
||||
|
||||
for response in socket.iter(false) {
|
||||
let header: Nlmsghdr<Rtm, Ifinfomsg> = response?;
|
||||
|
||||
@@ -86,6 +123,40 @@ pub fn find_interface(ifname: &str) -> Result<i32, Box<dyn Error>> {
|
||||
Ok(-1)
|
||||
}
|
||||
|
||||
pub fn get_interface_stats(ifname: &str) -> Result<RtnlLinkStats64, Box<dyn Error>> {
|
||||
let mut socket = NlSocketHandle::connect(NlFamily::Route, None, &[]).unwrap();
|
||||
|
||||
nl_interface_get(&mut socket, ifname).expect("Wrong when sending intf");
|
||||
|
||||
for response in socket.iter(false) {
|
||||
let header: Nlmsghdr<Rtm, Ifinfomsg> = response?;
|
||||
|
||||
if header.nl_type != Rtm::Newlink {
|
||||
return Err(Box::new(NlError::msg("Netlink error retrieving link")));
|
||||
}
|
||||
|
||||
if let NlPayload::Payload(p) = header.nl_payload {
|
||||
for attr in p.rtattrs.iter() {
|
||||
//println!("{:?}", attr.rta_type);
|
||||
|
||||
if attr.rta_type == Ifla::Stats64 {
|
||||
println!("{:?}", attr.rta_payload.as_ref());
|
||||
let buf = attr.rta_payload.as_ref();
|
||||
|
||||
let stats: RtnlLinkStats64 = deserialize(buf).unwrap();
|
||||
|
||||
println!("stats rx: {}", stats.rx_bytes);
|
||||
println!("stats tx: {}", stats.tx_bytes);
|
||||
|
||||
return Ok(stats);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Err(Box::new(NlError::msg("Error getting stats")))
|
||||
}
|
||||
|
||||
pub fn find_qdisc(ifindex: i32) -> Result<Qdisc, Box<dyn Error>> {
|
||||
let mut socket = NlSocketHandle::connect(NlFamily::Route, None, &[]).unwrap();
|
||||
let tc_msg = Tcmsg::new(
|
||||
|
||||
+5
-211
@@ -1,215 +1,9 @@
|
||||
use byteorder::{BigEndian, ReadBytesExt};
|
||||
use nix::sys::socket::{
|
||||
recvfrom, sendto, AddressFamily, MsgFlags, SockFlag, SockProtocol, SockType, SockaddrIn,
|
||||
SockaddrIn6, SockaddrLike,
|
||||
};
|
||||
use nix::sys::time::TimeValLike;
|
||||
use nix::time::{clock_gettime, ClockId};
|
||||
use std::error::Error;
|
||||
use std::mem::size_of;
|
||||
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddrV4, SocketAddrV6};
|
||||
use std::os::unix::io::RawFd;
|
||||
use std::str::FromStr;
|
||||
use std::{thread, time};
|
||||
|
||||
struct ICMP {
|
||||
icmp_type: u8,
|
||||
code: u8,
|
||||
checksum: u16,
|
||||
identifier: u16,
|
||||
sequence: u16,
|
||||
payload: u64,
|
||||
}
|
||||
|
||||
impl ICMP {
|
||||
fn to_bytes(&self) -> Box<[u8; 16]> {
|
||||
let checksum = self.checksum.to_be_bytes();
|
||||
let identifier = self.identifier.to_be_bytes();
|
||||
let sequence = self.sequence.to_be_bytes();
|
||||
let payload = self.payload.to_be_bytes();
|
||||
|
||||
let buf = [
|
||||
self.icmp_type,
|
||||
self.code,
|
||||
checksum[0],
|
||||
checksum[1],
|
||||
identifier[0],
|
||||
identifier[1],
|
||||
sequence[0],
|
||||
sequence[1],
|
||||
payload[0],
|
||||
payload[1],
|
||||
payload[2],
|
||||
payload[3],
|
||||
payload[4],
|
||||
payload[5],
|
||||
payload[6],
|
||||
payload[7],
|
||||
];
|
||||
|
||||
return Box::new(buf);
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&[u8]> for ICMP {
|
||||
fn from(buf: &[u8]) -> Self {
|
||||
ICMP {
|
||||
icmp_type: buf[0],
|
||||
code: buf[1],
|
||||
checksum: (&buf[2..3]).read_u16::<BigEndian>().unwrap(),
|
||||
identifier: (&buf[4..5]).read_u16::<BigEndian>().unwrap(),
|
||||
sequence: (&buf[6..7]).read_u16::<BigEndian>().unwrap(),
|
||||
payload: (&buf[8..16]).read_u64::<BigEndian>().unwrap(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&mut [u8]> for ICMP {
|
||||
fn from(buf: &mut [u8]) -> Self {
|
||||
ICMP {
|
||||
icmp_type: buf[0],
|
||||
code: buf[1],
|
||||
checksum: (&buf[2..3]).read_u16::<BigEndian>().unwrap(),
|
||||
identifier: (&buf[4..5]).read_u16::<BigEndian>().unwrap(),
|
||||
sequence: (&buf[6..7]).read_u16::<BigEndian>().unwrap(),
|
||||
payload: (&buf[8..16]).read_u64::<BigEndian>().unwrap(),
|
||||
}
|
||||
}
|
||||
}
|
||||
use std::net::IpAddr;
|
||||
|
||||
pub trait Pinger {
|
||||
fn new(reflectors: Vec<IpAddr>) -> Self;
|
||||
fn receive_loop(&self);
|
||||
fn receive_ping(&self) -> Result<(), Box<dyn Error>>;
|
||||
fn sender_loop(&self);
|
||||
fn send_ping(&self, reflector: &IpAddr, seq: u16) -> Result<(), Box<dyn Error>>;
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct PingerICMPEcho {
|
||||
reflectors: Vec<IpAddr>,
|
||||
socket: RawFd,
|
||||
}
|
||||
|
||||
impl PingerICMPEcho {
|
||||
fn calculate_checksum(buffer: &mut [u8]) -> u16 {
|
||||
let mut sum = 0u32;
|
||||
for word in buffer.chunks(2) {
|
||||
let mut part = u16::from(word[0]) << 8;
|
||||
if word.len() > 1 {
|
||||
part += u16::from(word[1]);
|
||||
}
|
||||
sum = sum.wrapping_add(u32::from(part));
|
||||
}
|
||||
|
||||
while (sum >> 16) > 0 {
|
||||
sum = (sum & 0xffff) + (sum >> 16);
|
||||
}
|
||||
|
||||
!sum as u16
|
||||
}
|
||||
}
|
||||
|
||||
impl Pinger for PingerICMPEcho {
|
||||
fn new(reflectors: Vec<IpAddr>) -> Self {
|
||||
let socket = nix::sys::socket::socket(
|
||||
AddressFamily::Inet,
|
||||
SockType::Raw,
|
||||
SockFlag::empty(),
|
||||
SockProtocol::ICMP,
|
||||
)
|
||||
.expect("Couldn't open a socket");
|
||||
|
||||
PingerICMPEcho { reflectors, socket }
|
||||
}
|
||||
|
||||
fn receive_loop(&self) {
|
||||
loop {
|
||||
let mut v: Vec<u8> = vec![0; size_of::<ICMP>()];
|
||||
let buf = v.as_mut_slice();
|
||||
|
||||
println!("buf len: {}", buf.len());
|
||||
|
||||
let res = recvfrom::<SockaddrIn>(self.socket, buf).unwrap();
|
||||
let remote = res.1.unwrap();
|
||||
|
||||
let ip = IpAddr::from(remote.ip().to_ne_bytes());
|
||||
|
||||
if self.reflectors.contains(&ip) {
|
||||
println!("ip: {}", ip.to_string());
|
||||
println!("usize: {}", res.0);
|
||||
println!("{:?}", buf);
|
||||
|
||||
let hdr: ICMP = buf.into();
|
||||
println!("Type: {}", hdr.icmp_type);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn receive_ping(&self) -> Result<(), Box<dyn Error>> {
|
||||
// Process ping RTT
|
||||
/*let ping_rtt = SystemTime::now()
|
||||
.duration_since(ping_start_time)
|
||||
.unwrap_or(Duration::from_secs(0));*/
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn sender_loop(&self) {
|
||||
let mut seq: u16 = 0;
|
||||
let tick_duration_ms: u16 = 500;
|
||||
let sleep_duration = time::Duration::from_millis(tick_duration_ms as u64);
|
||||
|
||||
loop {
|
||||
for reflector in self.reflectors.iter() {
|
||||
self.send_ping(reflector, seq).expect("TODO: panic message");
|
||||
}
|
||||
|
||||
thread::sleep(sleep_duration);
|
||||
|
||||
seq += 1;
|
||||
|
||||
if seq > std::u16::MAX {
|
||||
seq = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn send_ping(&self, reflector: &IpAddr, seq: u16) -> Result<(), Box<dyn Error>> {
|
||||
let time = clock_gettime(ClockId::CLOCK_MONOTONIC).unwrap();
|
||||
|
||||
let mut hdr = ICMP {
|
||||
icmp_type: 8,
|
||||
code: 0,
|
||||
checksum: 0,
|
||||
identifier: 0xBABE,
|
||||
sequence: seq,
|
||||
payload: time.num_milliseconds() as u64,
|
||||
};
|
||||
|
||||
let mut bytes = hdr.to_bytes();
|
||||
let buf: &mut [u8] = bytes.as_mut_slice();
|
||||
|
||||
hdr.checksum = PingerICMPEcho::calculate_checksum(buf);
|
||||
let bytes = hdr.to_bytes();
|
||||
let buf = bytes.as_slice();
|
||||
|
||||
let addr: Box<dyn SockaddrLike>;
|
||||
|
||||
match reflector.is_ipv4() {
|
||||
true => {
|
||||
let ip4 = Ipv4Addr::from_str(&*reflector.to_string()).unwrap();
|
||||
let sock4 = SocketAddrV4::new(ip4, 0);
|
||||
addr = Box::new(SockaddrIn::from(sock4));
|
||||
}
|
||||
false => {
|
||||
let ip6 = Ipv6Addr::from_str(&*reflector.to_string()).unwrap();
|
||||
let sock6 = SocketAddrV6::new(ip6, 0, 0, 0);
|
||||
addr = Box::new(SockaddrIn6::from(sock6));
|
||||
}
|
||||
}
|
||||
|
||||
sendto(self.socket, buf, addr.as_ref(), MsgFlags::empty()).expect("TODO: F message");
|
||||
|
||||
Ok(())
|
||||
}
|
||||
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>>;
|
||||
}
|
||||
@@ -0,0 +1,124 @@
|
||||
use std::error::Error;
|
||||
use std::net::{IpAddr, Ipv6Addr, SocketAddrV4, SocketAddrV6};
|
||||
use std::{process, thread, time};
|
||||
|
||||
use crate::Pinger;
|
||||
use byteorder::*;
|
||||
use nix::sys::time::TimeValLike;
|
||||
use nix::time::{clock_gettime, ClockId};
|
||||
use pnet::packet::icmp::IcmpType;
|
||||
use pnet::packet::icmp::IcmpTypes::EchoReply;
|
||||
use pnet::packet::ip::IpNextHeaderProtocols;
|
||||
use pnet::packet::*;
|
||||
use pnet_transport::TransportChannelType::Layer4;
|
||||
use pnet_transport::TransportProtocol::Ipv4;
|
||||
use pnet_transport::*;
|
||||
|
||||
pub struct PingerICMPEcho {
|
||||
id: u16,
|
||||
reflectors: Vec<IpAddr>,
|
||||
rx: TransportReceiver,
|
||||
tx: TransportSender,
|
||||
}
|
||||
|
||||
impl Pinger for PingerICMPEcho {
|
||||
fn new(id: u16, reflectors: Vec<IpAddr>) -> Self {
|
||||
let protocol = Layer4(Ipv4(IpNextHeaderProtocols::Icmp));
|
||||
|
||||
// Create a new transport channel, dealing with layer 4 packets on a test protocol
|
||||
// It has a receive buffer of 4096 bytes.
|
||||
let (tx, rx) = match transport_channel(4096, protocol) {
|
||||
Ok((tx, rx)) => (tx, rx),
|
||||
Err(e) => panic!(
|
||||
"An error occurred when creating the transport channel: {}",
|
||||
e
|
||||
),
|
||||
};
|
||||
|
||||
PingerICMPEcho {
|
||||
id,
|
||||
reflectors,
|
||||
rx,
|
||||
tx,
|
||||
}
|
||||
}
|
||||
|
||||
fn receive_loop(&mut self) {
|
||||
let mut iter = icmp_packet_iter(&mut self.rx);
|
||||
loop {
|
||||
let (packet, sender) = match iter.next() {
|
||||
Ok(res) => res,
|
||||
Err(_) => continue,
|
||||
};
|
||||
|
||||
let curr_time: u64 = clock_gettime(ClockId::CLOCK_MONOTONIC)
|
||||
.unwrap()
|
||||
.num_milliseconds() as u64;
|
||||
|
||||
if packet.get_icmp_type() != EchoReply {
|
||||
continue;
|
||||
}
|
||||
|
||||
let icmp_response = icmp::echo_reply::EchoReplyPacket::new(packet.packet()).unwrap();
|
||||
|
||||
if icmp_response.get_identifier() != self.id {
|
||||
continue;
|
||||
}
|
||||
|
||||
let sent_time: u64 = icmp_response.payload().read_u64::<NativeEndian>().unwrap();
|
||||
let rtt = curr_time - sent_time;
|
||||
|
||||
println!("Type: {:4} | Reflector IP: {:>15} | Seq: {:5} | Current time: {:8} | Sent time: {:8} | RTT: {:8}", "ICMP", sender.to_string(), icmp_response.get_sequence_number(), curr_time, sent_time, rtt);
|
||||
}
|
||||
}
|
||||
|
||||
fn sender_loop(&mut self) {
|
||||
println!("My ID is: {}", self.id);
|
||||
|
||||
let mut seq: u16 = 0;
|
||||
let tick_duration_ms: u16 = 500;
|
||||
let sleep_duration = time::Duration::from_millis(tick_duration_ms as u64);
|
||||
|
||||
loop {
|
||||
let reflectors = self.reflectors.clone();
|
||||
|
||||
for reflector in reflectors.iter() {
|
||||
self.send_ping(reflector, self.id, seq)
|
||||
.expect("TODO: panic message");
|
||||
}
|
||||
|
||||
thread::sleep(sleep_duration);
|
||||
|
||||
seq += 1;
|
||||
|
||||
if seq > u16::MAX {
|
||||
seq = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn send_ping(&mut self, reflector: &IpAddr, id: u16, seq: u16) -> Result<(), Box<dyn Error>> {
|
||||
let time = clock_gettime(ClockId::CLOCK_MONOTONIC).unwrap();
|
||||
|
||||
let mut buf = [0u8; 8 + 56];
|
||||
|
||||
let mut packet = icmp::echo_request::MutableEchoRequestPacket::new(&mut buf).unwrap();
|
||||
|
||||
packet.populate(&icmp::echo_request::EchoRequest {
|
||||
icmp_type: icmp::IcmpTypes::EchoRequest,
|
||||
icmp_code: icmp::IcmpCode::new(0),
|
||||
checksum: 0,
|
||||
identifier: id,
|
||||
sequence_number: seq,
|
||||
payload: Vec::from(time.num_milliseconds().to_ne_bytes()),
|
||||
});
|
||||
|
||||
packet.set_checksum(icmp::checksum(
|
||||
&icmp::IcmpPacket::new(&packet.packet()).unwrap(),
|
||||
));
|
||||
|
||||
self.tx.send_to(packet, *reflector).expect("Error sending");
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,153 @@
|
||||
use bincode::{deserialize, serialize};
|
||||
use std::error::Error;
|
||||
use std::net::{IpAddr, Ipv6Addr, SocketAddrV4, SocketAddrV6};
|
||||
use std::{process, thread, time};
|
||||
|
||||
use crate::Pinger;
|
||||
use byteorder::*;
|
||||
use nix::sys::time::TimeValLike;
|
||||
use nix::time::{clock_gettime, ClockId};
|
||||
use pnet::packet::icmp::IcmpTypes::{Timestamp, TimestampReply};
|
||||
use pnet::packet::ip::IpNextHeaderProtocols;
|
||||
use pnet::packet::*;
|
||||
use pnet_transport::TransportChannelType::Layer4;
|
||||
use pnet_transport::TransportProtocol::Ipv4;
|
||||
use pnet_transport::*;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Deserialize, Serialize, Copy, Clone, Default, Debug)]
|
||||
pub struct ICMPTimestamp {
|
||||
type_: u8,
|
||||
code: u8,
|
||||
checksum: u16,
|
||||
identifier: u16,
|
||||
sequence: u16,
|
||||
originate_time: u32,
|
||||
receive_time: u32,
|
||||
transmit_time: u32,
|
||||
}
|
||||
|
||||
pub struct PingerICMPTimestamps {
|
||||
id: u16,
|
||||
reflectors: Vec<IpAddr>,
|
||||
rx: TransportReceiver,
|
||||
tx: TransportSender,
|
||||
}
|
||||
|
||||
impl Pinger for PingerICMPTimestamps {
|
||||
fn new(id: u16, reflectors: Vec<IpAddr>) -> Self {
|
||||
let protocol = Layer4(Ipv4(IpNextHeaderProtocols::Icmp));
|
||||
|
||||
// Create a new transport channel, dealing with layer 4 packets on a test protocol
|
||||
// It has a receive buffer of 4096 bytes.
|
||||
let (tx, rx) = match transport_channel(4096, protocol) {
|
||||
Ok((tx, rx)) => (tx, rx),
|
||||
Err(e) => panic!(
|
||||
"An error occurred when creating the transport channel: {}",
|
||||
e
|
||||
),
|
||||
};
|
||||
|
||||
PingerICMPTimestamps {
|
||||
id,
|
||||
reflectors,
|
||||
rx,
|
||||
tx,
|
||||
}
|
||||
}
|
||||
|
||||
fn receive_loop(&mut self) {
|
||||
let mut iter = icmp_packet_iter(&mut self.rx);
|
||||
loop {
|
||||
let (packet, sender) = match iter.next() {
|
||||
Ok(res) => res,
|
||||
Err(_) => continue,
|
||||
};
|
||||
|
||||
let time = clock_gettime(ClockId::CLOCK_REALTIME).unwrap();
|
||||
let time_since_midnight: i64 =
|
||||
((time.tv_sec() % 86400 * 1000) + (time.tv_nsec() / 1000000));
|
||||
|
||||
if packet.get_icmp_type() != TimestampReply {
|
||||
continue;
|
||||
}
|
||||
|
||||
let hdr: ICMPTimestamp = deserialize(packet.packet()).unwrap();
|
||||
|
||||
if hdr.identifier != self.id {
|
||||
println!("wrong id: {} != {}", hdr.identifier, self.id);
|
||||
continue;
|
||||
}
|
||||
|
||||
let rtt: i64 = time_since_midnight - hdr.originate_time as i64;
|
||||
let dl_time: i64 = time_since_midnight - hdr.transmit_time as i64;
|
||||
let ul_time: i64 = hdr.receive_time as i64 - hdr.originate_time as i64;
|
||||
|
||||
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", sender.to_string(), hdr.sequence, time_since_midnight, hdr.originate_time, hdr.receive_time, hdr.transmit_time, rtt, ul_time, dl_time);
|
||||
}
|
||||
}
|
||||
|
||||
fn sender_loop(&mut self) {
|
||||
println!("My ID is: {}", self.id);
|
||||
|
||||
let mut seq: u16 = 0;
|
||||
let tick_duration_ms: u16 = 500;
|
||||
let sleep_duration = time::Duration::from_millis(tick_duration_ms as u64);
|
||||
|
||||
loop {
|
||||
let reflectors = self.reflectors.clone();
|
||||
|
||||
for reflector in reflectors.iter() {
|
||||
self.send_ping(reflector, self.id, seq)
|
||||
.expect("TODO: panic message");
|
||||
}
|
||||
|
||||
thread::sleep(sleep_duration);
|
||||
|
||||
seq += 1;
|
||||
|
||||
if seq > u16::MAX {
|
||||
seq = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn send_ping(&mut self, reflector: &IpAddr, id: u16, seq: u16) -> Result<(), Box<dyn Error>> {
|
||||
let mut buf = [0u8; 8 + 56];
|
||||
|
||||
let mut packet = pnet::packet::icmp::MutableIcmpPacket::new(&mut buf).unwrap();
|
||||
|
||||
let time = clock_gettime(ClockId::CLOCK_REALTIME).unwrap();
|
||||
let time_since_midnight: u32 =
|
||||
((time.tv_sec() % 86400 * 1000) + (time.tv_nsec() / 1000000)) as u32;
|
||||
|
||||
let mut icmp = ICMPTimestamp {
|
||||
type_: 255,
|
||||
code: 255,
|
||||
checksum: 65535,
|
||||
identifier: id,
|
||||
sequence: seq,
|
||||
originate_time: time_since_midnight,
|
||||
receive_time: 0,
|
||||
transmit_time: 0,
|
||||
};
|
||||
|
||||
let buf_v: Vec<u8> = serialize(&icmp).unwrap();
|
||||
let payload = &buf_v[4..];
|
||||
|
||||
packet.populate(&icmp::Icmp {
|
||||
icmp_type: Timestamp,
|
||||
icmp_code: icmp::IcmpCode::new(0),
|
||||
checksum: 0,
|
||||
payload: Vec::from(payload),
|
||||
});
|
||||
|
||||
packet.set_checksum(icmp::checksum(
|
||||
&icmp::IcmpPacket::new(&packet.packet()).unwrap(),
|
||||
));
|
||||
|
||||
self.tx.send_to(packet, *reflector).expect("Error sending");
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user