Successfully sent ICMP ping packets

This commit is contained in:
Andrew Golovashevich 2026-03-09 21:44:18 +03:00
parent 7f8187a43e
commit 2b376a2239
8 changed files with 137 additions and 15 deletions

View File

@ -2,6 +2,7 @@
resolver = "3" resolver = "3"
members = [ members = [
"app", "app",
"network/icmp",
"network/abstract", "network/abstract",
"network/windows" "network/windows"
] ]

7
network/icmp/Cargo.toml Normal file
View File

@ -0,0 +1,7 @@
[package]
name = "bgtu-networks-2-network-icmp"
version = "0.0.0"
edition = "2024"
[lints]
workspace = true

View File

@ -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);
}
}

23
network/icmp/src/lib.rs Normal file
View File

@ -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]);
}

19
network/icmp/src/ping.rs Normal file
View File

@ -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;
}

View File

@ -8,6 +8,7 @@ workspace = true
[dependencies] [dependencies]
bgtu-networks-2-network-abstract = { path = "../abstract" } bgtu-networks-2-network-abstract = { path = "../abstract" }
bgtu-networks-2-network-icmp = { path = "../icmp" }
[dependencies.windows] [dependencies.windows]
version = ">=0.41.0, <=0.62.2" version = ">=0.41.0, <=0.62.2"

View File

@ -9,10 +9,13 @@ use std::ffi::c_void;
use crate::address::WindowsAddressKnown; use crate::address::WindowsAddressKnown;
use crate::errors::format_windows_err_code; use crate::errors::format_windows_err_code;
use allocator::Allocator; use allocator::Allocator;
use bgtu_networks_2_network_abstract::ServersContext; use bgtu_networks_2_network_abstract::{Address, ServersContext};
use std::ptr::NonNull; 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::SystemInformation::GetTickCount;
use windows::Win32::System::Threading::SleepEx; use windows::Win32::System::Threading::SleepEx;
use bgtu_networks_2_network_icmp::fmt_icmp_echo_req;
pub unsafe fn run_eventloop<Ctx: ServersContext<WindowsAddressKnown>>(ctx: *mut Ctx) { pub unsafe fn run_eventloop<Ctx: ServersContext<WindowsAddressKnown>>(ctx: *mut Ctx) {
let heap = Allocator::new(); let heap = Allocator::new();
@ -25,15 +28,17 @@ pub unsafe fn run_eventloop<Ctx: ServersContext<WindowsAddressKnown>>(ctx: *mut
ctx, ctx,
}; };
let mut seq_no = 0u16;
loop { loop {
let (id, it) = (*ctx).start_measuring(); let (round_id, addrs_it) = (*ctx).start_measuring();
let mut should_recv_being_enabled = false; let mut should_recv_being_enabled = false;
for address in it { for address in addrs_it {
socket.send( socket.send(
address, address,
|buff| {}, |buff| fmt_icmp_echo_req(buff, seq_no, round_id, get_timestamp()),
|err, _| println!("Otpravlena hujnya: {}", format_windows_err_code(err)), send_callback,
); );
should_recv_being_enabled = true; should_recv_being_enabled = true;
} }
@ -61,6 +66,8 @@ pub unsafe fn run_eventloop<Ctx: ServersContext<WindowsAddressKnown>>(ctx: *mut
} }
} }
} }
seq_no = seq_no.wrapping_add(1);
} }
} }
@ -80,6 +87,13 @@ impl<'s, Ctx: ServersContext<WindowsAddressKnown>> RecvCallback<'_, Ctx> {
let this = this_ptr.cast::<Self>().as_ref(); let this = this_ptr.cast::<Self>().as_ref();
this.bind_callback(); 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 // I <3 borrow checker
@ -98,3 +112,19 @@ impl<'s, Ctx: ServersContext<WindowsAddressKnown>> RecvCallback<'_, Ctx> {
Self::_bind_callback(self_ptr.cast(), self.sock, Self::_callback_body); 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();
}

View File

@ -2,19 +2,18 @@ use crate::address::WindowsAddressKnown;
use crate::errors::throw_from_windows_err_code; use crate::errors::throw_from_windows_err_code;
use crate::eventloop::allocator::Allocator; use crate::eventloop::allocator::Allocator;
use crate::eventloop::task::IoTask; use crate::eventloop::task::IoTask;
use bgtu_networks_2_network_abstract::ServersContext;
use std::mem::uninitialized; use std::mem::uninitialized;
use std::pin::Pin; use std::pin::Pin;
use std::ptr::NonNull; use std::ptr::NonNull;
use std::slice; use std::slice;
use windows::Win32::Networking::WinSock::{ use windows::Win32::Networking::WinSock::{
WSAGetLastError, WSARecvFrom, WSASendTo, WSASocketW, AF_UNSPEC, AF_UNSPEC, IPPROTO_ICMP, LPWSAOVERLAPPED_COMPLETION_ROUTINE, SOCK_RAW, SOCKADDR,
IPPROTO_ICMP, LPWSAOVERLAPPED_COMPLETION_ROUTINE, SOCKADDR, SOCKADDR_STORAGE, SOCKET, SOCKADDR_STORAGE, SOCKET, SOCKET_ERROR, WSA_FLAG_NO_HANDLE_INHERIT, WSA_FLAG_OVERLAPPED,
SOCKET_ERROR, SOCK_RAW, WSAEACCES, WSAEADDRNOTAVAIL, WSAEAFNOSUPPORT, WSA_IO_PENDING, WSA_OPERATION_ABORTED, WSAEACCES, WSAEADDRNOTAVAIL, WSAEAFNOSUPPORT,
WSAECONNRESET, WSAEDESTADDRREQ, WSAEFAULT, WSAEHOSTUNREACH, WSAEINPROGRESS, WSAEINTR, WSAECONNRESET, WSAEDESTADDRREQ, WSAEFAULT, WSAEHOSTUNREACH, WSAEINPROGRESS, WSAEINTR,
WSAEINVAL, WSAEMSGSIZE, WSAENETDOWN, WSAENETRESET, WSAENETUNREACH, WSAENOBUFS, WSAENOTCONN, WSAEINVAL, WSAEMSGSIZE, WSAENETDOWN, WSAENETRESET, WSAENETUNREACH, WSAENOBUFS, WSAENOTCONN,
WSAENOTSOCK, WSAESHUTDOWN, WSAEWOULDBLOCK, WSANOTINITIALISED, WSA_FLAG_NO_HANDLE_INHERIT, WSA_FLAG_OVERLAPPED, WSAENOTSOCK, WSAESHUTDOWN, WSAEWOULDBLOCK, WSAGetLastError, WSANOTINITIALISED, WSARecvFrom,
WSA_IO_PENDING, WSA_OPERATION_ABORTED, WSASendTo, WSASocketW,
}; };
use windows::Win32::System::IO::OVERLAPPED; use windows::Win32::System::IO::OVERLAPPED;
@ -78,7 +77,7 @@ impl<'a> WindowsOverlappingIcmpSocket<'a> {
pub unsafe fn send( pub unsafe fn send(
&mut self, &mut self,
addr: WindowsAddressKnown, addr: WindowsAddressKnown,
init_data: impl FnOnce(&mut [u8]), init_data: impl FnOnce(&mut [u8]) -> usize,
on_sent: impl FnOnce(u32, WindowsAddressKnown) + 'static, on_sent: impl FnOnce(u32, WindowsAddressKnown) + 'static,
) { ) {
let task = self.heap.alloc(|p| { let task = self.heap.alloc(|p| {
@ -91,7 +90,7 @@ impl<'a> WindowsOverlappingIcmpSocket<'a> {
}); });
let task_p = task.get_unchecked_mut(); 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( let result = WSASendTo(
self.socket, self.socket,
@ -138,7 +137,6 @@ impl<'a> WindowsOverlappingIcmpSocket<'a> {
&self, &self,
on_received: impl for<'xx> FnOnce(u32, WindowsAddressKnown, &'xx [u8]) + 'static, on_received: impl for<'xx> FnOnce(u32, WindowsAddressKnown, &'xx [u8]) + 'static,
) { ) {
let task = self.heap.alloc(|p| { let task = self.heap.alloc(|p| {
IoTask::init( IoTask::init(
p, p,
@ -149,7 +147,6 @@ impl<'a> WindowsOverlappingIcmpSocket<'a> {
}); });
let task_p = task.get_unchecked_mut(); let task_p = task.get_unchecked_mut();
task_p._addr_size = size_of::<SOCKADDR_STORAGE>() as i32; task_p._addr_size = size_of::<SOCKADDR_STORAGE>() as i32;
task_p._flags = 0; task_p._flags = 0;
let result = WSARecvFrom( let result = WSARecvFrom(