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"
members = [
"app",
"network/icmp",
"network/abstract",
"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]
bgtu-networks-2-network-abstract = { path = "../abstract" }
bgtu-networks-2-network-icmp = { path = "../icmp" }
[dependencies.windows]
version = ">=0.41.0, <=0.62.2"

View File

@ -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: ServersContext<WindowsAddressKnown>>(ctx: *mut Ctx) {
let heap = Allocator::new();
@ -25,15 +28,17 @@ pub unsafe fn run_eventloop<Ctx: ServersContext<WindowsAddressKnown>>(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: 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();
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<WindowsAddressKnown>> 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();
}

View File

@ -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::<SOCKADDR_STORAGE>() as i32;
task_p._flags = 0;
let result = WSARecvFrom(