feat(localip): use reserved remote address (#4648)

Instead of the remote address of 8.8.8.8 (Google DNS) in the crate
local_ipaddress use a reserved IPv4 address, that should never be
assigned.
Also forward the underlying error on failure.

Supersedes: #4614
This commit is contained in:
cgzones 2022-12-01 19:51:04 +01:00 committed by GitHub
parent 9484e7eb01
commit ddd54e9b20
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 40 additions and 25 deletions

7
Cargo.lock generated
View File

@ -1630,12 +1630,6 @@ version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f9f08d8963a6c613f4b1a78f4f4a4dbfadf8e6545b2d72861731e4858b8b47f"
[[package]]
name = "local_ipaddress"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f6a104730949fbc4c78e4fa98ed769ca0faa02e9818936b61032d2d77526afa9"
[[package]]
name = "lock_api"
version = "0.4.8"
@ -2770,7 +2764,6 @@ dependencies = [
"guess_host_triple",
"home",
"indexmap",
"local_ipaddress",
"log",
"mockall",
"nix 0.26.1",

View File

@ -52,7 +52,6 @@ git-features = { version = "0.24.1", optional = true }
# default feature restriction addresses https://github.com/starship/starship/issues/4251
git-repository = { version = "0.29.0", default-features = false, features = ["max-performance-safe"] }
indexmap = { version = "1.9.2", features = ["serde"] }
local_ipaddress = "0.1.3"
log = { version = "0.4.17", features = ["std"] }
# nofity-rust is optional (on by default) because the crate doesn't currently build for darwin with nix
# see: https://github.com/NixOS/nixpkgs/issues/160876

View File

@ -4,14 +4,27 @@ use crate::config::ModuleConfig;
use crate::configs::localip::LocalipConfig;
use crate::formatter::StringFormatter;
use std::io::Error;
use std::net::UdpSocket;
fn get_local_ipv4() -> Result<String, Error> {
let socket = UdpSocket::bind("0.0.0.0:0")?;
socket.connect("192.0.2.0:80")?;
let addr = socket.local_addr()?;
Ok(addr.ip().to_string())
}
/// Creates a module with the ipv4 address of the local machine.
///
/// The `local_ipaddress` crate is used to determine the local IP address of your machine.
/// An accurate and fast way, especially if there are multiple IP addresses available,
/// is to connect a UDP socket and then reading its local endpoint.
/// The IP address is gathered from the local endpoint of an UDP socket
/// connected to a reserved IPv4 remote address, which is an accurate and fast
/// way, especially if there are multiple IP addresses available.
/// There should be no actual packets send over the wire.
///
/// Will display the ip if all of the following criteria are met:
/// - localip.disabled is false
/// - `localip.disabled` is false
/// - `localip.ssh_only` is false OR the user is currently connected as an SSH session (`$SSH_CONNECTION`)
pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
let mut module = context.new_module("localip");
@ -28,11 +41,18 @@ pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
return None;
}
let localip = local_ipaddress::get().unwrap_or_default();
if localip.is_empty() {
log::warn!("unable to determine local ipv4 address");
return None;
}
let localip = match get_local_ipv4() {
Ok(ip) => ip,
Err(e) => {
// ErrorKind::NetworkUnreachable is unstable
if cfg!(target_os = "linux") && e.raw_os_error() == Some(101) {
"NetworkUnreachable".to_string()
} else {
log::warn!("unable to determine local ipv4 address: {e}");
return None;
}
}
};
let parsed = StringFormatter::new(config.format).and_then(|formatter| {
formatter
@ -60,19 +80,22 @@ pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
#[cfg(test)]
mod tests {
use crate::modules::localip::get_local_ipv4;
use crate::test::ModuleRenderer;
use nu_ansi_term::{Color, Style};
macro_rules! get_localip {
() => {
if let Some(localip) = local_ipaddress::get() {
localip
} else {
println!(
"localip was not tested because socket connection failed! \
This could be caused by an unconventional network setup."
);
return;
match get_local_ipv4() {
Ok(ip) => ip,
Err(e) => {
println!(
"localip was not tested because socket connection failed! \
This could be caused by an unconventional network setup. \
Error: {e}"
);
return;
}
}
};
}