ping.rs 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218
  1. #[macro_use]
  2. extern crate log;
  3. extern crate env_logger;
  4. extern crate getopts;
  5. extern crate smoltcp;
  6. extern crate byteorder;
  7. mod utils;
  8. use std::str::FromStr;
  9. use std::collections::BTreeMap;
  10. use std::cmp;
  11. use std::os::unix::io::AsRawFd;
  12. use smoltcp::time::{Duration, Instant};
  13. use smoltcp::phy::Device;
  14. use smoltcp::phy::wait as phy_wait;
  15. use smoltcp::wire::{EthernetAddress, IpAddress, IpCidr,
  16. Ipv6Address, Icmpv6Repr, Icmpv6Packet,
  17. Ipv4Address, Icmpv4Repr, Icmpv4Packet};
  18. use smoltcp::iface::{NeighborCache, EthernetInterfaceBuilder, Routes};
  19. use smoltcp::socket::{SocketSet, IcmpSocket, IcmpSocketBuffer, IcmpPacketMetadata, IcmpEndpoint};
  20. use std::collections::HashMap;
  21. use byteorder::{ByteOrder, NetworkEndian};
  22. macro_rules! send_icmp_ping {
  23. ( $repr_type:ident, $packet_type:ident, $ident:expr, $seq_no:expr,
  24. $echo_payload:expr, $socket:expr, $remote_addr:expr ) => {{
  25. let icmp_repr = $repr_type::EchoRequest {
  26. ident: $ident,
  27. seq_no: $seq_no,
  28. data: &$echo_payload,
  29. };
  30. let icmp_payload = $socket
  31. .send(icmp_repr.buffer_len(), $remote_addr)
  32. .unwrap();
  33. let mut icmp_packet = $packet_type::new_unchecked(icmp_payload);
  34. (icmp_repr, icmp_packet)
  35. }}
  36. }
  37. macro_rules! get_icmp_pong {
  38. ( $repr_type:ident, $repr:expr, $payload:expr, $waiting_queue:expr, $remote_addr:expr,
  39. $timestamp:expr, $received:expr ) => {{
  40. if let $repr_type::EchoReply { seq_no, data, .. } = $repr {
  41. if let Some(_) = $waiting_queue.get(&seq_no) {
  42. let packet_timestamp_ms = NetworkEndian::read_i64(data);
  43. println!("{} bytes from {}: icmp_seq={}, time={}ms",
  44. data.len(), $remote_addr, seq_no,
  45. $timestamp.total_millis() - packet_timestamp_ms);
  46. $waiting_queue.remove(&seq_no);
  47. $received += 1;
  48. }
  49. }
  50. }}
  51. }
  52. fn main() {
  53. utils::setup_logging("warn");
  54. let (mut opts, mut free) = utils::create_options();
  55. utils::add_tap_options(&mut opts, &mut free);
  56. utils::add_middleware_options(&mut opts, &mut free);
  57. opts.optopt("c", "count", "Amount of echo request packets to send (default: 4)", "COUNT");
  58. opts.optopt("i", "interval",
  59. "Interval between successive packets sent (seconds) (default: 1)", "INTERVAL");
  60. opts.optopt("", "timeout",
  61. "Maximum wait duration for an echo response packet (seconds) (default: 5)",
  62. "TIMEOUT");
  63. free.push("ADDRESS");
  64. let mut matches = utils::parse_options(&opts, free);
  65. let device = utils::parse_tap_options(&mut matches);
  66. let fd = device.as_raw_fd();
  67. let device = utils::parse_middleware_options(&mut matches, device, /*loopback=*/false);
  68. let device_caps = device.capabilities();
  69. let address = IpAddress::from_str(&matches.free[0]).expect("invalid address format");
  70. let count = matches.opt_str("count").map(|s| usize::from_str(&s).unwrap()).unwrap_or(4);
  71. let interval = matches.opt_str("interval")
  72. .map(|s| Duration::from_secs(u64::from_str(&s).unwrap()))
  73. .unwrap_or(Duration::from_secs(1));
  74. let timeout = Duration::from_secs(
  75. matches.opt_str("timeout").map(|s| u64::from_str(&s).unwrap()).unwrap_or(5)
  76. );
  77. let neighbor_cache = NeighborCache::new(BTreeMap::new());
  78. let remote_addr = address;
  79. let icmp_rx_buffer = IcmpSocketBuffer::new(vec![IcmpPacketMetadata::EMPTY], vec![0; 256]);
  80. let icmp_tx_buffer = IcmpSocketBuffer::new(vec![IcmpPacketMetadata::EMPTY], vec![0; 256]);
  81. let icmp_socket = IcmpSocket::new(icmp_rx_buffer, icmp_tx_buffer);
  82. let ethernet_addr = EthernetAddress([0x02, 0x00, 0x00, 0x00, 0x00, 0x02]);
  83. let src_ipv6 = IpAddress::v6(0xfdaa, 0, 0, 0, 0, 0, 0, 1);
  84. let ip_addrs = [IpCidr::new(IpAddress::v4(192, 168, 69, 1), 24),
  85. IpCidr::new(src_ipv6, 64),
  86. IpCidr::new(IpAddress::v6(0xfe80, 0, 0, 0, 0, 0, 0, 1), 64)];
  87. let default_v4_gw = Ipv4Address::new(192, 168, 69, 100);
  88. let default_v6_gw = Ipv6Address::new(0xfe80, 0, 0, 0, 0, 0, 0, 0x100);
  89. let mut routes_storage = [None; 2];
  90. let mut routes = Routes::new(&mut routes_storage[..]);
  91. routes.add_default_ipv4_route(default_v4_gw).unwrap();
  92. routes.add_default_ipv6_route(default_v6_gw).unwrap();
  93. let mut iface = EthernetInterfaceBuilder::new(device)
  94. .ethernet_addr(ethernet_addr)
  95. .ip_addrs(ip_addrs)
  96. .routes(routes)
  97. .neighbor_cache(neighbor_cache)
  98. .finalize();
  99. let mut sockets = SocketSet::new(vec![]);
  100. let icmp_handle = sockets.add(icmp_socket);
  101. let mut send_at = Instant::from_millis(0);
  102. let mut seq_no = 0;
  103. let mut received = 0;
  104. let mut echo_payload = [0xffu8; 40];
  105. let mut waiting_queue = HashMap::new();
  106. let ident = 0x22b;
  107. loop {
  108. let timestamp = Instant::now();
  109. match iface.poll(&mut sockets, timestamp) {
  110. Ok(_) => {},
  111. Err(e) => {
  112. debug!("poll error: {}", e);
  113. }
  114. }
  115. {
  116. let timestamp = Instant::now();
  117. let mut socket = sockets.get::<IcmpSocket>(icmp_handle);
  118. if !socket.is_open() {
  119. socket.bind(IcmpEndpoint::Ident(ident)).unwrap();
  120. send_at = timestamp;
  121. }
  122. if socket.can_send() && seq_no < count as u16 &&
  123. send_at <= timestamp {
  124. NetworkEndian::write_i64(&mut echo_payload, timestamp.total_millis());
  125. match remote_addr {
  126. IpAddress::Ipv4(_) => {
  127. let (icmp_repr, mut icmp_packet) = send_icmp_ping!(
  128. Icmpv4Repr, Icmpv4Packet, ident, seq_no,
  129. echo_payload, socket, remote_addr);
  130. icmp_repr.emit(&mut icmp_packet, &device_caps.checksum);
  131. },
  132. IpAddress::Ipv6(_) => {
  133. let (icmp_repr, mut icmp_packet) = send_icmp_ping!(
  134. Icmpv6Repr, Icmpv6Packet, ident, seq_no,
  135. echo_payload, socket, remote_addr);
  136. icmp_repr.emit(&src_ipv6, &remote_addr,
  137. &mut icmp_packet, &device_caps.checksum);
  138. },
  139. _ => unimplemented!()
  140. }
  141. waiting_queue.insert(seq_no, timestamp);
  142. seq_no += 1;
  143. send_at += interval;
  144. }
  145. if socket.can_recv() {
  146. let (payload, _) = socket.recv().unwrap();
  147. match remote_addr {
  148. IpAddress::Ipv4(_) => {
  149. let icmp_packet = Icmpv4Packet::new_checked(&payload).unwrap();
  150. let icmp_repr =
  151. Icmpv4Repr::parse(&icmp_packet, &device_caps.checksum).unwrap();
  152. get_icmp_pong!(Icmpv4Repr, icmp_repr, payload,
  153. waiting_queue, remote_addr, timestamp, received);
  154. }
  155. IpAddress::Ipv6(_) => {
  156. let icmp_packet = Icmpv6Packet::new_checked(&payload).unwrap();
  157. let icmp_repr = Icmpv6Repr::parse(&remote_addr, &src_ipv6,
  158. &icmp_packet, &device_caps.checksum).unwrap();
  159. get_icmp_pong!(Icmpv6Repr, icmp_repr, payload,
  160. waiting_queue, remote_addr, timestamp, received);
  161. },
  162. _ => unimplemented!()
  163. }
  164. }
  165. waiting_queue.retain(|seq, from| {
  166. if timestamp - *from < timeout {
  167. true
  168. } else {
  169. println!("From {} icmp_seq={} timeout", remote_addr, seq);
  170. false
  171. }
  172. });
  173. if seq_no == count as u16 && waiting_queue.is_empty() {
  174. break
  175. }
  176. }
  177. let timestamp = Instant::now();
  178. match iface.poll_at(&sockets, timestamp) {
  179. Some(poll_at) if timestamp < poll_at => {
  180. let resume_at = cmp::min(poll_at, send_at);
  181. phy_wait(fd, Some(resume_at - timestamp)).expect("wait error");
  182. },
  183. Some(_) => (),
  184. None => {
  185. phy_wait(fd, Some(send_at - timestamp)).expect("wait error");
  186. }
  187. }
  188. }
  189. println!("--- {} ping statistics ---", remote_addr);
  190. println!("{} packets transmitted, {} received, {:.0}% packet loss",
  191. seq_no, received, 100.0 * (seq_no - received) as f64 / seq_no as f64);
  192. }