From 524b1d242115e5a96c97839059bd0063ea75c34f Mon Sep 17 00:00:00 2001 From: John Gallagher Date: Wed, 2 Oct 2019 15:17:36 -0700 Subject: [PATCH 1/2] Print IPv4 address correctly on little-endian systems --- src/ptools.rs | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/src/ptools.rs b/src/ptools.rs index 39522de..3785414 100644 --- a/src/ptools.rs +++ b/src/ptools.rs @@ -646,17 +646,15 @@ fn parse_sock_type(type_code: &str) -> SockType { } } -// Parse a socket address of the form "0100007F:1538" (i.e. 127.0.0.1:1538) +// Parse a socket address of the form "0100007F:1538" (i.e. 127.0.0.1:5432) fn parse_ipv4_sock_addr(s: &str) -> Result> { + // Port is always printed with most-significant byte first. let port = u16::from_str_radix(s.split(':').collect::>()[1], 16).unwrap(); - let addr = u32::from_str_radix(s.split(':').collect::>()[0], 16).unwrap(); - // TODO do we need to change 'addr' to network order? - let addr = Ipv4Addr::new( - ((addr >> 24) & 0xFF) as u8, - ((addr >> 16) & 0xFF) as u8, - ((addr >> 8) & 0xFF) as u8, - (addr & 0xFF) as u8, - ); + + // Address is printed with most-significant byte first on big-endian systems and vice-versa on + // little-endian systems. + let addr_native_endian = u32::from_str_radix(s.split(':').collect::>()[0], 16).unwrap(); + let addr = Ipv4Addr::from(addr_native_endian.to_be()); Ok(SocketAddr::new(IpAddr::V4(addr), port)) } From c4e001fb575de13a28026e7ab0485808d22a3b4d Mon Sep 17 00:00:00 2001 From: John Gallagher Date: Wed, 2 Oct 2019 15:35:10 -0700 Subject: [PATCH 2/2] Cleanup error handling in parse_ipv4_sock_addr --- src/ptools.rs | 46 ++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 40 insertions(+), 6 deletions(-) diff --git a/src/ptools.rs b/src/ptools.rs index 3785414..8b25c86 100644 --- a/src/ptools.rs +++ b/src/ptools.rs @@ -133,7 +133,12 @@ struct ParseError { } impl ParseError { - fn new(file: &str, reason: &str) -> Self { + fn new(item: &str, reason: &str) -> Self { + ParseError { + reason: format!("Error parsing {}: {}", item, reason), + } + } + fn in_file(file: &str, reason: &str) -> Self { ParseError { reason: format!("Error parsing /proc/[pid]/{}: {}", file, reason), } @@ -182,7 +187,7 @@ impl ProcStat { let s: String = s?; let substrs = s.splitn(2, ":").collect::>(); if substrs.len() < 2 { - Err(ParseError::new( + Err(ParseError::in_file( "status", &format!( "Fewer fields than expected in line '{}' of file {}", @@ -208,7 +213,7 @@ impl ProcStat { fn get_field(&self, field: &str) -> Result<&str, Box> { match self.fields.get(field) { Some(val) => Ok(val), - None => Err(From::from(ParseError::new( + None => Err(From::from(ParseError::in_file( "status", &format!( "Missing expected field '{}' file {}", @@ -647,13 +652,25 @@ fn parse_sock_type(type_code: &str) -> SockType { } // Parse a socket address of the form "0100007F:1538" (i.e. 127.0.0.1:5432) -fn parse_ipv4_sock_addr(s: &str) -> Result> { +fn parse_ipv4_sock_addr(s: &str) -> Result { + let mk_err = || { + ParseError::new( + "IPv4 address", + &format!("expected address in form '0100007F:1538', got {}", s), + ) + }; + + let fields = s.split(':').collect::>(); + if fields.len() != 2 { + return Err(mk_err()); + } + // Port is always printed with most-significant byte first. - let port = u16::from_str_radix(s.split(':').collect::>()[1], 16).unwrap(); + let port = u16::from_str_radix(fields[1], 16).map_err(|_| mk_err())?; // Address is printed with most-significant byte first on big-endian systems and vice-versa on // little-endian systems. - let addr_native_endian = u32::from_str_radix(s.split(':').collect::>()[0], 16).unwrap(); + let addr_native_endian = u32::from_str_radix(fields[0], 16).map_err(|_| mk_err())?; let addr = Ipv4Addr::from(addr_native_endian.to_be()); Ok(SocketAddr::new(IpAddr::V4(addr), port)) @@ -914,3 +931,20 @@ pub fn ptree_main() { } } } + +mod test { + use super::*; + use std::net::SocketAddr; + + #[test] + fn test_parse_ipv4_sock_addr() { + assert_eq!( + parse_ipv4_sock_addr("0100007F:1538").unwrap(), + "127.0.0.1:5432".parse::().unwrap() + ); + + assert!(parse_ipv4_sock_addr("0100007F 1538").is_err()); + assert!(parse_ipv4_sock_addr("010000YY:1538").is_err()); + assert!(parse_ipv4_sock_addr("0100007F:15YY").is_err()); + } +}