1use std::{
15 net::Ipv6Addr,
16 time::{Duration, Instant},
17};
18
19use icmp_socket::packet::WithEchoRequest;
20use icmp_socket::socket::IcmpSocket;
21use icmp_socket::*;
22
23pub fn main() {
24 let address = std::env::args().nth(1).unwrap_or("::1".to_owned());
25 let parsed_addr = address.parse::<Ipv6Addr>().unwrap();
26 let packet_handler = |pkt: Icmpv6Packet, send_time: Instant, addr: Ipv6Addr| -> Option<()> {
27 let now = Instant::now();
28 let elapsed = now - send_time;
29 if addr == parsed_addr {
30 if let Icmpv6Message::EchoReply {
32 identifier: _,
33 sequence,
34 payload,
35 } = pkt.message
36 {
37 println!(
38 "Ping {} seq={} time={}ms size={}",
39 addr,
40 sequence,
41 (elapsed.as_micros() as f64) / 1000.0,
42 payload.len()
43 );
44 } else {
45 return None;
47 }
48 Some(())
49 } else {
50 eprintln!("Discarding packet from {}", addr);
51 None
52 }
53 };
54 let mut socket6 = IcmpSocket6::new().unwrap();
55 socket6.bind("::0".parse::<Ipv6Addr>().unwrap()).unwrap();
56 let mut sequence = 0 as u16;
59 loop {
60 let packet = Icmpv6Packet::with_echo_request(
61 42,
62 sequence,
63 vec![
64 0x20, 0x20, 0x75, 0x73, 0x74, 0x20, 0x61, 0x20, 0x66, 0x6c, 0x65, 0x73, 0x68, 0x20,
65 0x77, 0x6f, 0x75, 0x6e, 0x64, 0x20, 0x20, 0x74, 0x69, 0x73, 0x20, 0x62, 0x75, 0x74,
66 0x20, 0x61, 0x20, 0x73, 0x63, 0x72, 0x61, 0x74, 0x63, 0x68, 0x20, 0x20, 0x6b, 0x6e,
67 0x69, 0x67, 0x68, 0x74, 0x73, 0x20, 0x6f, 0x66, 0x20, 0x6e, 0x69, 0x20, 0x20, 0x20,
68 ],
69 )
70 .unwrap();
71 let send_time = Instant::now();
72 socket6
73 .send_to(address.parse::<Ipv6Addr>().unwrap(), packet)
74 .unwrap();
75 socket6.set_timeout(Some(Duration::from_secs(1)));
76 loop {
77 let (resp, sock_addr) = match socket6.rcv_from() {
78 Ok(tpl) => tpl,
79 Err(e) => {
80 eprintln!("{:?}", e);
81 break;
82 }
83 };
84 if packet_handler(resp, send_time, *sock_addr.as_socket_ipv6().unwrap().ip()).is_some()
85 {
86 std::thread::sleep(Duration::from_millis(1000));
87 break;
88 }
89 }
90 sequence = sequence.wrapping_add(1);
91 }
92}