summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorEmīls Piņķis <emils@mullvad.net>2019-09-30 12:26:23 +0100
committerEmīls Piņķis <emils@mullvad.net>2019-09-30 14:50:37 +0100
commita28b7f1a8720219a5e9416d77c3e8ea780fb2189 (patch)
tree1bd71b894c513d75de0d8b7cecf500f038e4783d
parent3164047b1eae8ce7fb4e10f89f86c4a39158576b (diff)
downloadmullvadvpn-a28b7f1a8720219a5e9416d77c3e8ea780fb2189.tar.xz
mullvadvpn-a28b7f1a8720219a5e9416d77c3e8ea780fb2189.zip
Add Windows implementation for ping_monitor
-rw-r--r--Cargo.lock125
-rw-r--r--talpid-core/Cargo.toml4
-rw-r--r--talpid-core/src/lib.rs1
-rw-r--r--talpid-core/src/ping_monitor/mod.rs2
-rw-r--r--talpid-core/src/ping_monitor/win.rs157
5 files changed, 288 insertions, 1 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 74dec12dda..0c28150f5f 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -131,6 +131,11 @@ dependencies = [
[[package]]
name = "bitflags"
+version = "0.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "bitflags"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -664,6 +669,11 @@ dependencies = [
]
[[package]]
+name = "glob"
+version = "0.2.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
name = "globset"
version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1697,6 +1707,41 @@ version = "0.3.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
+name = "pnet_base"
+version = "0.22.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "pnet_macros"
+version = "0.21.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "regex 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
+ "syntex 0.42.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "syntex_syntax 0.42.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "pnet_macros_support"
+version = "0.22.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "pnet_base 0.22.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "pnet_packet"
+version = "0.22.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
+ "pnet_base 0.22.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "pnet_macros 0.21.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "pnet_macros_support 0.22.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "syntex 0.42.2 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
name = "ppv-lite86"
version = "0.2.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2035,6 +2080,11 @@ version = "0.1.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
+name = "rustc-serialize"
+version = "0.3.24"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
name = "rustc_version"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2266,6 +2316,51 @@ dependencies = [
]
[[package]]
+name = "syntex"
+version = "0.42.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "syntex_errors 0.42.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "syntex_syntax 0.42.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "syntex_errors"
+version = "0.42.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)",
+ "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)",
+ "syntex_pos 0.42.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "term 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "unicode-xid 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "syntex_pos"
+version = "0.42.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "syntex_syntax"
+version = "0.42.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "bitflags 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)",
+ "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)",
+ "syntex_errors 0.42.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "syntex_pos 0.42.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "term 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "unicode-xid 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
name = "system-configuration"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2318,10 +2413,13 @@ dependencies = [
"os_pipe 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)",
"parking_lot 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
"pfctl 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "pnet_packet 0.22.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rand 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
"regex 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
"resolv-conf 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)",
"rtnetlink 0.1.1 (git+https://github.com/mullvad/netlink?rev=f768adfcc8c6b064ef7ae3c792c4c21d0d96d0b5)",
"shell-escape 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
+ "socket2 0.3.11 (registry+https://github.com/rust-lang/crates.io-index)",
"system-configuration 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"talpid-ipc 0.1.0",
"talpid-types 0.1.0",
@@ -2404,6 +2502,15 @@ dependencies = [
]
[[package]]
+name = "term"
+version = "0.4.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
name = "termcolor"
version = "1.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2772,6 +2879,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "unicode-xid"
+version = "0.0.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "unicode-xid"
version = "0.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -3016,6 +3128,7 @@ dependencies = [
"checksum backtrace-sys 0.1.31 (registry+https://github.com/rust-lang/crates.io-index)" = "82a830b4ef2d1124a711c71d263c5abdc710ef8e907bd508c88be475cebc422b"
"checksum base64 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0b25d992356d2eb0ed82172f5248873db5560c4721f564b13cb5193bda5e668e"
"checksum base64 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)" = "489d6c0ed21b11d038c31b6ceccca973e65d73ba3bd8ecb9a2babf5546164643"
+"checksum bitflags 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4f67931368edf3a9a51d29886d245f1c3db2f1ef0dcc9e35ff70341b78c10d23"
"checksum bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3d155346769a6855b86399e9bc3814ab343cd3d62c7e985113d46a0ec3c281fd"
"checksum blake2b_simd 0.5.8 (registry+https://github.com/rust-lang/crates.io-index)" = "5850aeee1552f495dd0250014cf64b82b7c8879a89d83b33bbdace2cc4f63182"
"checksum bstr 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "8d6c2c5b58ab920a4f5aeaaca34b4488074e8cc7596af94e6f8c6ff247c60245"
@@ -3077,6 +3190,7 @@ dependencies = [
"checksum gcc 0.3.55 (registry+https://github.com/rust-lang/crates.io-index)" = "8f5f3913fa0bfe7ee1fd8248b6b9f42a5af4b9d65ec2dd2c3c26132b950ecfc2"
"checksum generic-array 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c68f0274ae0e023facc3c97b2e00f076be70e254bc851d972503b328db79b2ec"
"checksum getrandom 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "473a1265acc8ff1e808cd0a1af8cee3c2ee5200916058a2ca113c29f2d903571"
+"checksum glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "8be18de09a56b60ed0edf84bc9df007e30040691af7acd1c41874faac5895bfb"
"checksum globset 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "90d069fe6beb9be359ef505650b3f73228c5591a3c4b1f32be2f4f44459ffa3a"
"checksum globset 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "925aa2cac82d8834e2b2a4415b6f6879757fb5c0928fc445ae76461a12eed8f2"
"checksum hex 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "023b39be39e3a2da62a94feb433e91e8bcd37676fbc8bea371daf52b7a769a3e"
@@ -3161,6 +3275,10 @@ dependencies = [
"checksum percent-encoding 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "31010dd2e1ac33d5b46a5b413495239882813e0369f8ed8a5e266f173602f831"
"checksum pfctl 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4410511aea78cbc7b1d192315034607be78537336590ebfc7fc92496768c45af"
"checksum pkg-config 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)" = "72d5370d90f49f70bd033c3d75e87fc529fbfff9d6f7cccef07d6170079d91ea"
+"checksum pnet_base 0.22.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4df28acf2fcc77436dd2b91a9a0c2bb617f9ca5f2acefee1a4135058b9f9801f"
+"checksum pnet_macros 0.21.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5d228096fd739d4e3e60dee9e1e4f07d9ae0f3f309c876834192538748e561e4"
+"checksum pnet_macros_support 0.22.0 (registry+https://github.com/rust-lang/crates.io-index)" = "84684f2cddefc37a06f2fe2ca4dcc3457fc3b282734b5246507d8ee75d2780ae"
+"checksum pnet_packet 0.22.0 (registry+https://github.com/rust-lang/crates.io-index)" = "08a6cdcdaddc5174f18286298842a4e31cd3cc018933d42af51434b1fa07dcbe"
"checksum ppv-lite86 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "e3cbf9f658cdb5000fcf6f362b8ea2ba154b9f146a61c7a20d647034c6b6561b"
"checksum proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)" = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759"
"checksum proc-macro2 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "afdc77cc74ec70ed262262942ebb7dac3d479e9e5cfa2da1841c0806f6cdabcc"
@@ -3200,6 +3318,7 @@ dependencies = [
"checksum rtnetlink 0.1.1 (git+https://github.com/mullvad/netlink?rev=f768adfcc8c6b064ef7ae3c792c4c21d0d96d0b5)" = "<none>"
"checksum rust-argon2 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4ca4eaef519b494d1f2848fc602d18816fed808a981aedf4f1f00ceb7c9d32cf"
"checksum rustc-demangle 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "4c691c0e608126e00913e33f0ccf3727d5fc84573623b8d65b2df340b5201783"
+"checksum rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)" = "dcf128d1287d2ea9d80910b5f1120d0b8eede3fbf1abe91c40d39ea7d51e6fda"
"checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a"
"checksum ryu 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c92464b447c0ee8c4fb3824ecc8383b81717b9f1e74ba2e72540aef7b9f82997"
"checksum safemem 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d2b08423011dae9a5ca23f07cf57dac3857f5c885d352b76f6d95f4aea9434d0"
@@ -3232,10 +3351,15 @@ dependencies = [
"checksum syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "66850e97125af79138385e9b88339cbcd037e3f28ceab8c5ad98e64f0f1f80bf"
"checksum synom 0.11.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a393066ed9010ebaed60b9eafa373d4b1baac186dd7e008555b0f702b51945b6"
"checksum synstructure 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)" = "02353edf96d6e4dc81aea2d8490a7e9db177bf8acb0e951c24940bf866cb313f"
+"checksum syntex 0.42.2 (registry+https://github.com/rust-lang/crates.io-index)" = "0a30b08a6b383a22e5f6edc127d169670d48f905bb00ca79a00ea3e442ebe317"
+"checksum syntex_errors 0.42.0 (registry+https://github.com/rust-lang/crates.io-index)" = "04c48f32867b6114449155b2a82114b86d4b09e1bddb21c47ff104ab9172b646"
+"checksum syntex_pos 0.42.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3fd49988e52451813c61fecbe9abb5cfd4e1b7bb6cdbb980a6fbcbab859171a6"
+"checksum syntex_syntax 0.42.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7628a0506e8f9666fdabb5f265d0059b059edac9a3f810bda077abb5d826bd8d"
"checksum system-configuration 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8ce91c23e42859a5b8a7da032096d34f776512239e89de6c7bec817d6089cf9c"
"checksum system-configuration-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "114702b56796b5cf377b6ae266a319fa687edd4d9f18f4d5658193e65dcaf006"
"checksum take 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b157868d8ac1f56b64604539990685fa7611d8fa9e5476cf0c02cf34d32917c5"
"checksum tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e24d9338a0a5be79593e2fa15a648add6138caa803e2d5bc782c371732ca9"
+"checksum term 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "fa63644f74ce96fbeb9b794f66aff2a52d601cbd5e80f4b97123e3899f4570f1"
"checksum termcolor 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "96d6098003bde162e4277c70665bd87c326f5a0c3f3fbfb285787fa482d54e6e"
"checksum textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060"
"checksum thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c6b53e329000edc2b34dbe8545fd20e55a333362d0a321909685a19bd28c3f1b"
@@ -3269,6 +3393,7 @@ dependencies = [
"checksum ucd-util 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "fa9b3b49edd3468c0e6565d85783f51af95212b6fa3986a5500954f00b460874"
"checksum unicase 2.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2e2e6bd1e59e56598518beb94fd6db628ded570326f0a98c679a304bd9f00150"
"checksum unicode-width 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "7007dbd421b92cc6e28410fe7362e2e0a2503394908f417b68ec8d1c364c4e20"
+"checksum unicode-xid 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "36dff09cafb4ec7c8cf0023eb0b686cb6ce65499116a12201c9e11840ca01beb"
"checksum unicode-xid 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f860d7d29cf02cb2f3f359fd35991af3d30bac52c57d265a3c461074cb4dc"
"checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc"
"checksum unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c"
diff --git a/talpid-core/Cargo.toml b/talpid-core/Cargo.toml
index ad033f2ce3..1ccf689a0b 100644
--- a/talpid-core/Cargo.toml
+++ b/talpid-core/Cargo.toml
@@ -63,7 +63,9 @@ tun = "0.4.3"
widestring = "0.4"
winreg = "0.6"
winapi = { version = "0.3.6", features = ["handleapi", "libloaderapi", "synchapi", "winbase", "winuser"] }
-
+socket2 = "0.3"
+rand = "0.7"
+pnet_packet = "0.22"
[dev-dependencies]
tempfile = "3.0"
diff --git a/talpid-core/src/lib.rs b/talpid-core/src/lib.rs
index cd88277d9d..5fdbd3030d 100644
--- a/talpid-core/src/lib.rs
+++ b/talpid-core/src/lib.rs
@@ -23,6 +23,7 @@ mod winnet;
#[cfg(any(target_os = "linux", target_os = "macos"))]
/// Working with IP interface devices
pub mod network_interface;
+#[cfg(not(windows))]
/// Abstraction over operating system routing table.
pub mod routing;
diff --git a/talpid-core/src/ping_monitor/mod.rs b/talpid-core/src/ping_monitor/mod.rs
index 25b33be0bb..8cdc766ad4 100644
--- a/talpid-core/src/ping_monitor/mod.rs
+++ b/talpid-core/src/ping_monitor/mod.rs
@@ -2,6 +2,8 @@
#[path = "unix.rs"]
mod imp;
+
+#[cfg(target_os = "windows")]
#[path = "win.rs"]
mod imp;
diff --git a/talpid-core/src/ping_monitor/win.rs b/talpid-core/src/ping_monitor/win.rs
new file mode 100644
index 0000000000..e98161fae6
--- /dev/null
+++ b/talpid-core/src/ping_monitor/win.rs
@@ -0,0 +1,157 @@
+#![allow(dead_code)]
+// TODO: Remove lint exemption once ping monitor is used on Windows
+use pnet_packet::{
+ icmp::{
+ self,
+ echo_reply::EchoReplyPacket,
+ echo_request::{EchoRequestPacket, MutableEchoRequestPacket},
+ IcmpCode, IcmpPacket, IcmpType,
+ },
+ Packet,
+};
+use socket2::{Domain, Protocol, Socket, Type};
+use std::{
+ io,
+ net::{IpAddr, Ipv4Addr, SocketAddr},
+ sync::mpsc,
+ thread,
+ time::{Duration, Instant},
+};
+
+#[derive(err_derive::Error, Debug)]
+pub enum Error {
+ /// Failed to open raw socket
+ #[error(display = "Failed to open raw socket")]
+ OpenError(#[error(cause)] io::Error),
+
+ /// Failed to read from raw socket
+ #[error(display = "Failed to read from socket")]
+ ReadError(#[error(cause)] io::Error),
+
+ /// Failed to write to raw socket
+ #[error(display = "Failed to write to socket")]
+ WriteError(#[error(cause)] io::Error),
+
+ #[error(display = "Timed out")]
+ TimeoutError,
+}
+
+pub fn monitor_ping(
+ ip: Ipv4Addr,
+ timeout_secs: u16,
+ _interface: &str,
+ close_receiver: mpsc::Receiver<()>,
+) -> Result<()> {
+ let mut pinger = Pinger::new(ip)?;
+ while let Err(mpsc::TryRecvError::Empty) = close_receiver.try_recv() {
+ let start = Instant::now();
+ pinger.send_ping(Duration::from_secs(timeout_secs.into()))?;
+ if let Some(remaining) =
+ Duration::from_secs(timeout_secs.into()).checked_sub(start.elapsed())
+ {
+ thread::sleep(remaining);
+ }
+ }
+
+ Ok(())
+}
+
+pub fn ping(ip: Ipv4Addr, timeout_secs: u16, _interface: &str) -> Result<()> {
+ Pinger::new(ip)?.send_ping(Duration::from_secs(timeout_secs.into()))
+}
+
+type Result<T> = std::result::Result<T, Error>;
+
+pub struct Pinger {
+ sock: Socket,
+ addr: Ipv4Addr,
+ id: u16,
+ seq: u16,
+}
+
+impl Pinger {
+ pub fn new(addr: Ipv4Addr) -> Result<Self> {
+ let sock = Socket::new(Domain::ipv4(), Type::raw(), Some(Protocol::icmpv4()))
+ .map_err(Error::OpenError)?;
+ sock.set_nonblocking(true).map_err(Error::OpenError)?;
+ Ok(Self {
+ sock,
+ id: rand::random(),
+ addr,
+ seq: 0,
+ })
+ }
+
+ /// Sends an ICMP echo request
+ pub fn send_ping(&mut self, timeout: Duration) -> Result<()> {
+ let dest = SocketAddr::new(IpAddr::from(self.addr), 0);
+ let request = self.next_ping_request();
+ self.sock
+ .send_to(request.packet(), &dest.into())
+ .map_err(Error::WriteError)?;
+ self.wait_for_response(Instant::now() + timeout, &request)
+ }
+
+ /// returns the next ping packet
+ fn next_ping_request(&mut self) -> EchoRequestPacket<'static> {
+ const ICMP_HEADER_LENGTH: usize = 8;
+ const ICMP_PAYLOAD_LENGTH: usize = 24;
+ const ICMP_PACKET_LENGTH: usize = ICMP_HEADER_LENGTH + ICMP_PAYLOAD_LENGTH;
+ let payload: [u8; ICMP_PAYLOAD_LENGTH] = rand::random();
+ let mut packet = MutableEchoRequestPacket::owned(vec![0u8; ICMP_PACKET_LENGTH])
+ .expect("Failed to construct an empty packet");
+ packet.set_icmp_type(IcmpType::new(8));
+ packet.set_icmp_code(IcmpCode::new(0));
+ packet.set_sequence_number(self.next_seq());
+ packet.set_identifier(self.id);
+ packet.set_payload(&payload);
+ packet.set_checksum(icmp::checksum(&IcmpPacket::new(&packet.packet()).unwrap()));
+ packet.consume_to_immutable()
+ }
+
+ fn next_seq(&mut self) -> u16 {
+ let seq = self.seq;
+ self.seq += 1;
+ seq
+ }
+
+
+ fn wait_for_response(&mut self, deadline: Instant, req: &EchoRequestPacket<'_>) -> Result<()> {
+ let mut recv_buffer = [0u8; 4096];
+ while Instant::now() < deadline {
+ match self.sock.recv(&mut recv_buffer) {
+ Ok(recv_len) => {
+ if recv_len > 20 {
+ // have to slice off first 20 bytes for the IP header.
+ if let Some(reply) = Self::parse_response(&recv_buffer[20..recv_len]) {
+ if reply.get_identifier() == req.get_identifier()
+ && reply.get_sequence_number() == req.get_sequence_number()
+ && req.payload() == reply.payload()
+ {
+ return Ok(());
+ }
+ }
+ }
+ }
+ Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => {
+ std::thread::sleep(Duration::from_millis(100));
+ continue;
+ }
+ Err(e) => {
+ return Err(Error::ReadError(e));
+ }
+ }
+ }
+ Err(Error::TimeoutError)
+ }
+
+ fn parse_response<'a>(buffer: &'a [u8]) -> Option<EchoReplyPacket<'a>> {
+ let icmp_checksum = icmp::checksum(&IcmpPacket::new(buffer)?);
+ let reply = EchoReplyPacket::new(buffer)?;
+ if reply.get_checksum() == icmp_checksum {
+ Some(reply)
+ } else {
+ None
+ }
+ }
+}