Skip to main content

simple_ping/
simple_ping.rs

1//! Example: send an ICMP Echo Request and wait for Echo Reply.
2//!
3//! Linux only. Usage: `sudo cargo run --example simple_ping -- <target_ip>`
4//!
5//! ```sh
6//! sudo cargo run --example simple_ping -- 8.8.8.8
7//! ```
8
9#[cfg(target_os = "linux")]
10fn main() -> Result<(), Box<dyn std::error::Error>> {
11    use std::net::Ipv4Addr;
12    use std::time::{Duration, Instant};
13    use wireforge_core::icmp::{IcmpPacket, IcmpPacketBuilder};
14    use wireforge_core::ipv4::{Ipv4Packet, Ipv4PacketBuilder};
15    use wireforge_core::types::IpProtocol;
16    use wireforge_io::{L3Receiver, L3Sender};
17
18    let target: Ipv4Addr = std::env::args()
19        .nth(1)
20        .unwrap_or_else(|| "8.8.8.8".into())
21        .parse()?;
22    let src = Ipv4Addr::new(0, 0, 0, 0); // kernel fills source
23
24    let mut rx = L3Receiver::new(IpProtocol::Icmp)?;
25    rx.set_timeout(Some(Duration::from_secs(2)))?;
26
27    let tx = L3Sender::new()?;
28
29    let icmp = IcmpPacketBuilder::echo_request()
30        .identifier(0x0001)
31        .sequence_number(1)
32        .payload(b"wireforge-ping!")
33        .build();
34
35    let ip = Ipv4PacketBuilder::new()
36        .source(src)
37        .destination(target)
38        .protocol(IpProtocol::Icmp)
39        .ttl(64)
40        .payload(&icmp)
41        .unwrap()
42        .build();
43
44    let start = Instant::now();
45    tx.send_to(&ip, std::net::SocketAddrV4::new(target, 0))?;
46    println!("PING {} ...", target);
47
48    loop {
49        let reply = rx.recv()?;
50        if reply.protocol() == IpProtocol::Icmp && reply.destination() == src {
51            if let Some(icmp_reply) = IcmpPacket::new(reply.payload()) {
52                if icmp_reply.type_() == 0 {
53                    // Echo Reply
54                    let rtt = start.elapsed();
55                    println!(
56                        "Reply from {}: seq={} ttl={} rtt={:.2}ms",
57                        reply.source(),
58                        1,
59                        reply.ttl(),
60                        rtt.as_secs_f64() * 1000.0,
61                    );
62                    break;
63                }
64            }
65        }
66    }
67    Ok(())
68}
69
70#[cfg(not(target_os = "linux"))]
71fn main() {
72    eprintln!("simple_ping requires Linux (raw sockets).");
73}