diff --git a/Cargo.toml b/Cargo.toml index d8e48c1..3f4527d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,6 +2,7 @@ resolver = "3" members = [ "app", + "network/icmp", "network/abstract", "network/windows" ] diff --git a/network/icmp/Cargo.toml b/network/icmp/Cargo.toml new file mode 100644 index 0000000..dbaa1fc --- /dev/null +++ b/network/icmp/Cargo.toml @@ -0,0 +1,7 @@ +[package] +name = "bgtu-networks-2-network-icmp" +version = "0.0.0" +edition = "2024" + +[lints] +workspace = true diff --git a/network/icmp/src/checksum.rs b/network/icmp/src/checksum.rs new file mode 100644 index 0000000..3791af4 --- /dev/null +++ b/network/icmp/src/checksum.rs @@ -0,0 +1,44 @@ + +pub(crate) struct IPv4ChecksumAccumulator { + acc: u32, +} + +impl IPv4ChecksumAccumulator { + pub fn new() -> Self { + return Self { acc: 0 }; + } + + pub fn add_first_byte(&mut self, b: u8) { + self.acc += (b as u32) << 8; + } + + pub fn add_second_byte(&mut self, b: u8) { + self.acc += b as u32; + } + + pub fn add_last_byte(&mut self, b: u8) { + self.acc += b as u32; + } + + pub fn add_word(&mut self, b: u16) { + self.acc += b as u32; + } + + pub fn add_trailing_data(&mut self, data: &[u8]) { + for i in (0..(data.len() / 2)).into_iter().map(|i| i * 2) { + self.add_first_byte(data[i]); + self.add_second_byte(data[i + 1]); + } + if data.len() % 2 != 0 { + self.add_last_byte(data[data.len() - 1]); + } + } + + pub fn snapshot(&self) -> u16 { + let mut out = self.acc; + while out > 0x0000FFFFu32 { + out = (out & 0x0000FFFFu32) + (out >> 16); + } + return !(out as u16); + } +} diff --git a/network/icmp/src/lib.rs b/network/icmp/src/lib.rs new file mode 100644 index 0000000..6967926 --- /dev/null +++ b/network/icmp/src/lib.rs @@ -0,0 +1,23 @@ +mod checksum; +mod ping; + +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]); +} diff --git a/network/icmp/src/ping.rs b/network/icmp/src/ping.rs new file mode 100644 index 0000000..1e14b5c --- /dev/null +++ b/network/icmp/src/ping.rs @@ -0,0 +1,19 @@ +use crate::checksum::IPv4ChecksumAccumulator; +use crate::{hton128, hton16, hton64}; + +pub fn fmt_icmp_echo_req(buff: &mut [u8], seq_no: u16, req_id: u64, timestamp: u128) -> usize{ + buff[0] = 8; + buff[1] = 0; + hton16(0, &mut buff[4..6]); + hton16(seq_no, &mut buff[6..8]); + hton64(req_id, &mut buff[8..16]); + hton128(timestamp, &mut buff[16..32]); + + let mut checksum = IPv4ChecksumAccumulator::new(); + checksum.add_first_byte(buff[0]); + checksum.add_second_byte(buff[1]); + checksum.add_trailing_data(&buff[4..32]); + hton16(checksum.snapshot(), &mut buff[2..4]); + + return 32; +} diff --git a/network/windows/Cargo.toml b/network/windows/Cargo.toml index 7f8952a..c6c41f9 100644 --- a/network/windows/Cargo.toml +++ b/network/windows/Cargo.toml @@ -8,6 +8,7 @@ workspace = true [dependencies] bgtu-networks-2-network-abstract = { path = "../abstract" } +bgtu-networks-2-network-icmp = { path = "../icmp" } [dependencies.windows] version = ">=0.41.0, <=0.62.2" diff --git a/network/windows/src/eventloop/mod.rs b/network/windows/src/eventloop/mod.rs index 21af2e3..fe29024 100644 --- a/network/windows/src/eventloop/mod.rs +++ b/network/windows/src/eventloop/mod.rs @@ -9,10 +9,13 @@ use std::ffi::c_void; use crate::address::WindowsAddressKnown; use crate::errors::format_windows_err_code; use allocator::Allocator; -use bgtu_networks_2_network_abstract::ServersContext; +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::System::SystemInformation::GetTickCount; use windows::Win32::System::Threading::SleepEx; +use bgtu_networks_2_network_icmp::fmt_icmp_echo_req; pub unsafe fn run_eventloop>(ctx: *mut Ctx) { let heap = Allocator::new(); @@ -25,15 +28,17 @@ pub unsafe fn run_eventloop>(ctx: *mut ctx, }; + let mut seq_no = 0u16; + loop { - let (id, it) = (*ctx).start_measuring(); + let (round_id, addrs_it) = (*ctx).start_measuring(); let mut should_recv_being_enabled = false; - for address in it { + for address in addrs_it { socket.send( address, - |buff| {}, - |err, _| println!("Otpravlena hujnya: {}", format_windows_err_code(err)), + |buff| fmt_icmp_echo_req(buff, seq_no, round_id, get_timestamp()), + send_callback, ); should_recv_being_enabled = true; } @@ -61,6 +66,8 @@ pub unsafe fn run_eventloop>(ctx: *mut } } } + + seq_no = seq_no.wrapping_add(1); } } @@ -80,6 +87,13 @@ impl<'s, Ctx: ServersContext> RecvCallback<'_, Ctx> { let this = this_ptr.cast::().as_ref(); this.bind_callback(); } + + println!("Received from addr {} data {:02X?}", addr.to_string(), buffer); + + match WSA_ERROR(errcode.cast_signed()) { + WSA_ERROR(0) => {} + errcode => panic!("Unhandled exception on send: [{}] {}", errcode.0, format_windows_err_code(errcode)) + } } // I <3 borrow checker @@ -98,3 +112,19 @@ impl<'s, Ctx: ServersContext> RecvCallback<'_, Ctx> { Self::_bind_callback(self_ptr.cast(), self.sock, Self::_callback_body); } } + +fn send_callback(errcode: u32, addr: WindowsAddressKnown) { + match WSA_ERROR(errcode.cast_signed()) { + WSAEACCES => panic!("Need admin privileges to send ICMP"), // todo without panic, + WSA_ERROR(0) => {} + errcode => panic!("Unhandled exception on send: [{}] {}", errcode.0, format_windows_err_code(errcode)) + } +} + +fn get_timestamp() -> u128 { + let start = SystemTime::now(); + let since_the_epoch = start + .duration_since(UNIX_EPOCH) + .expect("time should go forward"); + return since_the_epoch.as_millis(); +} \ No newline at end of file diff --git a/network/windows/src/eventloop/socket.rs b/network/windows/src/eventloop/socket.rs index bd7148e..1dac417 100644 --- a/network/windows/src/eventloop/socket.rs +++ b/network/windows/src/eventloop/socket.rs @@ -2,19 +2,18 @@ use crate::address::WindowsAddressKnown; use crate::errors::throw_from_windows_err_code; use crate::eventloop::allocator::Allocator; use crate::eventloop::task::IoTask; -use bgtu_networks_2_network_abstract::ServersContext; use std::mem::uninitialized; use std::pin::Pin; use std::ptr::NonNull; use std::slice; use windows::Win32::Networking::WinSock::{ - WSAGetLastError, WSARecvFrom, WSASendTo, WSASocketW, AF_UNSPEC, - IPPROTO_ICMP, LPWSAOVERLAPPED_COMPLETION_ROUTINE, SOCKADDR, SOCKADDR_STORAGE, SOCKET, - SOCKET_ERROR, SOCK_RAW, WSAEACCES, WSAEADDRNOTAVAIL, WSAEAFNOSUPPORT, + AF_UNSPEC, IPPROTO_ICMP, LPWSAOVERLAPPED_COMPLETION_ROUTINE, SOCK_RAW, SOCKADDR, + SOCKADDR_STORAGE, SOCKET, SOCKET_ERROR, WSA_FLAG_NO_HANDLE_INHERIT, WSA_FLAG_OVERLAPPED, + WSA_IO_PENDING, WSA_OPERATION_ABORTED, WSAEACCES, WSAEADDRNOTAVAIL, WSAEAFNOSUPPORT, WSAECONNRESET, WSAEDESTADDRREQ, WSAEFAULT, WSAEHOSTUNREACH, WSAEINPROGRESS, WSAEINTR, WSAEINVAL, WSAEMSGSIZE, WSAENETDOWN, WSAENETRESET, WSAENETUNREACH, WSAENOBUFS, WSAENOTCONN, - WSAENOTSOCK, WSAESHUTDOWN, WSAEWOULDBLOCK, WSANOTINITIALISED, WSA_FLAG_NO_HANDLE_INHERIT, WSA_FLAG_OVERLAPPED, - WSA_IO_PENDING, WSA_OPERATION_ABORTED, + WSAENOTSOCK, WSAESHUTDOWN, WSAEWOULDBLOCK, WSAGetLastError, WSANOTINITIALISED, WSARecvFrom, + WSASendTo, WSASocketW, }; use windows::Win32::System::IO::OVERLAPPED; @@ -78,7 +77,7 @@ impl<'a> WindowsOverlappingIcmpSocket<'a> { pub unsafe fn send( &mut self, addr: WindowsAddressKnown, - init_data: impl FnOnce(&mut [u8]), + init_data: impl FnOnce(&mut [u8]) -> usize, on_sent: impl FnOnce(u32, WindowsAddressKnown) + 'static, ) { let task = self.heap.alloc(|p| { @@ -91,7 +90,7 @@ impl<'a> WindowsOverlappingIcmpSocket<'a> { }); let task_p = task.get_unchecked_mut(); - init_data(&mut task_p.buff); + task_p.buff_d[0].len = init_data(&mut task_p.buff) as u32; let result = WSASendTo( self.socket, @@ -138,7 +137,6 @@ impl<'a> WindowsOverlappingIcmpSocket<'a> { &self, on_received: impl for<'xx> FnOnce(u32, WindowsAddressKnown, &'xx [u8]) + 'static, ) { - let task = self.heap.alloc(|p| { IoTask::init( p, @@ -149,7 +147,6 @@ impl<'a> WindowsOverlappingIcmpSocket<'a> { }); let task_p = task.get_unchecked_mut(); - task_p._addr_size = size_of::() as i32; task_p._flags = 0; let result = WSARecvFrom(