diff --git a/app/src/main.rs b/app/src/main.rs index cd1e453..63a0703 100644 --- a/app/src/main.rs +++ b/app/src/main.rs @@ -35,8 +35,8 @@ impl ServersContext for Servers2NetworkCtxTestImpl { ); } - fn report_ping(&mut self, addr: A, id: u64, ping_ms: u64) { - println!("{} {ping_ms}", addr.to_string()) + fn report_ping(&mut self, addr: A, id: u64, ping_ms: u128) { + println!("{} {ping_ms} ms", addr.to_string()) } fn report_error(&mut self, addr: A, id: u64) { diff --git a/network/abstract/src/lib.rs b/network/abstract/src/lib.rs index 5ff35e4..ad8642b 100644 --- a/network/abstract/src/lib.rs +++ b/network/abstract/src/lib.rs @@ -12,7 +12,7 @@ pub trait NetworkContext { pub trait ServersContext { fn start_measuring(&mut self) -> (u64, impl Iterator); - fn report_ping(&mut self, addr: A, id: u64, ping_ms: u64); + fn report_ping(&mut self, addr: A, id: u64, ping_ms: u128); fn report_error(&mut self, addr: A, id: u64); } diff --git a/network/icmp/src/conversions.rs b/network/icmp/src/conversions.rs new file mode 100644 index 0000000..960b7e6 --- /dev/null +++ b/network/icmp/src/conversions.rs @@ -0,0 +1,39 @@ +pub(crate) fn hton16(v: u16, b: &mut [u8]) { + b[0] = (v >> 8) as u8; + b[1] = (v & 0xFF) as u8; +} + +pub(crate) fn hton64(v: u64, b: &mut [u8]) { + hton16((v >> 48) as u16, b); + hton16(((v >> 32) & 0xFFFF) as u16, &mut b[2..4]); + hton16(((v >> 16) & 0xFFFF) as u16, &mut b[4..6]); + hton16((v & 0xFFFF) as u16, &mut b[6..8]); +} + +pub(crate) fn hton128(v: u128, b: &mut [u8]) { + hton64((v >> 64) as u64, b); + hton64((v & 0xFFFF_FFFF_FFFF_FFFF) as u64, &mut b[8..16]); +} + +pub(crate) fn ntoh16(b: &[u8]) -> u16 { + let mut v = 0u16; + v += (b[0] as u16) << 8; + v += b[1] as u16; + return v; +} + +pub(crate) fn ntoh64(b: &[u8]) -> u64 { + let mut v = 0u64; + v += (ntoh16(b) as u64) << 48; + v += (ntoh16(&b[2..4]) as u64) << 32; + v += (ntoh16(&b[4..6]) as u64) << 16; + v += ntoh16(&b[6..8]) as u64; + return v; +} + +pub(crate) fn ntoh128(b: &[u8]) -> u128 { + let mut v = 0u128; + v += (ntoh64(b) as u128) << 64; + v += ntoh64(&b[8..16]) as u128; + return v; +} diff --git a/network/icmp/src/lib.rs b/network/icmp/src/lib.rs index 6967926..97cae17 100644 --- a/network/icmp/src/lib.rs +++ b/network/icmp/src/lib.rs @@ -1,23 +1,9 @@ mod checksum; mod ping; +mod pong; +mod conversions; use checksum::IPv4ChecksumAccumulator; pub use ping::fmt_icmp_echo_req; - -fn hton16(v: u16, b: &mut [u8]) { - b[0] = (v >> 8) as u8; - b[1] = (v & 0xFF) as u8; -} - -fn hton64(v: u64, b: &mut [u8]) { - hton16((v >> 48) as u16, b); - hton16(((v >> 32) & 0xFFFF) as u16, &mut b[2..4]); - hton16(((v >> 16) & 0xFFFF) as u16, &mut b[4..6]); - hton16((v & 0xFFFF) as u16, &mut b[6..8]); -} - -fn hton128(v: u128, b: &mut [u8]) { - hton64((v >> 64) as u64, b); - hton64((v & 0xFFFF_FFFF_FFFF_FFFF) as u64, &mut b[8..16]); -} +pub use pong::{parse_icmp_echo_res, IcmpPong}; \ No newline at end of file diff --git a/network/icmp/src/ping.rs b/network/icmp/src/ping.rs index 1e14b5c..cd0b452 100644 --- a/network/icmp/src/ping.rs +++ b/network/icmp/src/ping.rs @@ -1,5 +1,5 @@ use crate::checksum::IPv4ChecksumAccumulator; -use crate::{hton128, hton16, hton64}; +use crate::conversions::{hton128, hton16, hton64}; pub fn fmt_icmp_echo_req(buff: &mut [u8], seq_no: u16, req_id: u64, timestamp: u128) -> usize{ buff[0] = 8; diff --git a/network/icmp/src/pong.rs b/network/icmp/src/pong.rs new file mode 100644 index 0000000..1520684 --- /dev/null +++ b/network/icmp/src/pong.rs @@ -0,0 +1,24 @@ +use crate::checksum::IPv4ChecksumAccumulator; +use crate::conversions::{hton16, hton64, hton128, ntoh16, ntoh64, ntoh128}; + +pub enum IcmpPong { + WrongChecksum, + Success { req_id: u64, timestamp: u128 }, +} + +pub fn parse_icmp_echo_res(buff: &[u8]) -> IcmpPong { + let expected_checksum = ntoh16(&buff[2..4]); + let mut checksum = IPv4ChecksumAccumulator::new(); + checksum.add_first_byte(buff[0]); + checksum.add_second_byte(buff[1]); + checksum.add_trailing_data(&buff[4..32]); + let actual_checksum = checksum.snapshot(); + if actual_checksum != expected_checksum { + return IcmpPong::WrongChecksum; + } + + return IcmpPong::Success { + req_id: ntoh64(&buff[8..16]), + timestamp: ntoh128(&buff[16..32]), + }; +} diff --git a/network/windows/src/eventloop/mod.rs b/network/windows/src/eventloop/mod.rs index fe29024..ddd1cba 100644 --- a/network/windows/src/eventloop/mod.rs +++ b/network/windows/src/eventloop/mod.rs @@ -12,10 +12,10 @@ use allocator::Allocator; use bgtu_networks_2_network_abstract::{Address, ServersContext}; use std::ptr::NonNull; use std::time::{SystemTime, UNIX_EPOCH}; -use windows::Win32::Networking::WinSock::{WSAEACCES, WSA_ERROR}; +use windows::Win32::Networking::WinSock::{AF_INET, AF_INET6, WSAEACCES, WSA_ERROR}; use windows::Win32::System::SystemInformation::GetTickCount; use windows::Win32::System::Threading::SleepEx; -use bgtu_networks_2_network_icmp::fmt_icmp_echo_req; +use bgtu_networks_2_network_icmp::{fmt_icmp_echo_req, parse_icmp_echo_res, IcmpPong}; pub unsafe fn run_eventloop>(ctx: *mut Ctx) { let heap = Allocator::new(); @@ -86,6 +86,29 @@ impl<'s, Ctx: ServersContext> RecvCallback<'_, Ctx> { unsafe { let this = this_ptr.cast::().as_ref(); this.bind_callback(); + + let buffer_no_ip_header; + match addr.any.native.ss_family { + AF_INET => { + let ipv4_len = ((buffer[0] & 0x0F) as usize) * 4; + buffer_no_ip_header = &buffer[ipv4_len..buffer.len()]; + } + AF_INET6 => { + buffer_no_ip_header = &buffer[40..buffer.len()]; + // todo extra headers + } + _ => panic!("Unsupported L4 header") + } + + match parse_icmp_echo_res(buffer_no_ip_header) { + IcmpPong::WrongChecksum => { + println!("Wrong checksum") + } + IcmpPong::Success { req_id, timestamp } => { + let delta = get_timestamp() - timestamp; + NonNull::new_unchecked(this.ctx).as_mut().report_ping(addr, req_id, delta); + } + } } println!("Received from addr {} data {:02X?}", addr.to_string(), buffer);