Skip to content

Commit e8591e2

Browse files
committed
Switch to pnet for network interface telemetry
Fixes #38
1 parent e1a9892 commit e8591e2

File tree

15 files changed

+35
-232
lines changed

15 files changed

+35
-232
lines changed

Cargo.toml

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,7 @@ zdaemon = "0.0.2"
3232
zfilexfer = "0.0.2"
3333
hostname = "0.1"
3434
czmq = { version = "0.1", optional = true }
35-
interfaces = "0.0.1"
36-
ipnetwork = "0.12"
35+
pnet = "0.16"
3736

3837
[lib]
3938
name = "inapi"

src/error.rs

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@ use std::ffi::CString;
1919
use zdaemon;
2020
#[cfg(feature = "remote-run")]
2121
use zfilexfer;
22-
use interfaces;
2322

2423
pub type Result<T> = result::Result<T, Error>;
2524

@@ -97,8 +96,6 @@ pub enum Error {
9796
#[cfg(feature = "remote-run")]
9897
/// ZFileXfer error
9998
ZFileXfer(zfilexfer::Error),
100-
/// Network interface error
101-
Interfaces(interfaces::InterfacesError),
10299
}
103100

104101
unsafe impl Send for Error {}
@@ -138,7 +135,6 @@ impl fmt::Display for Error {
138135
Error::ZDaemon(ref e) => write!(f, "ZDaemon error: {}", e),
139136
#[cfg(feature = "remote-run")]
140137
Error::ZFileXfer(ref e) => write!(f, "ZFileXfer error: {}", e),
141-
Error::Interfaces(ref e) => write!(f, "Interfaces error: {}", e),
142138
}
143139
}
144140
}
@@ -178,7 +174,6 @@ impl error::Error for Error {
178174
Error::ZDaemon(ref e) => e.description(),
179175
#[cfg(feature = "remote-run")]
180176
Error::ZFileXfer(ref e) => e.description(),
181-
Error::Interfaces(ref e) => e.description(),
182177
}
183178
}
184179
}
@@ -283,12 +278,6 @@ impl convert::From<zfilexfer::Error> for Error {
283278
}
284279
}
285280

286-
impl From<interfaces::InterfacesError> for Error {
287-
fn from(err: interfaces::InterfacesError) -> Error {
288-
Error::Interfaces(err)
289-
}
290-
}
291-
292281
#[cfg(feature = "remote-run")]
293282
#[derive(Debug)]
294283
pub struct MissingFrame {

src/host/telemetry.rs

Lines changed: 12 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ use host::Host;
1212
use serde_json::Map;
1313
use serde_json::Value;
1414
use target::Target;
15+
#[cfg(feature = "local-run")]
1516

1617
#[cfg(feature = "local-run")]
1718
#[derive(Debug, RustcEncodable)]
@@ -80,25 +81,15 @@ impl Telemetry {
8081
let mut net = Vec::new();
8182
for netif in self.net {
8283
let mut map: Map<String, Value> = Map::new();
83-
map.insert("interface".into(), json!(netif.interface));
84-
map.insert("mac".into(), json!(netif.mac));
85-
if let Some(inet) = netif.inet {
86-
let mut map1: Map<String, Value> = Map::new();
87-
map1.insert("address".into(), json!(inet.address));
88-
map1.insert("netmask".into(), json!(inet.netmask));
89-
map.insert("inet".into(), json!(map1));
90-
}
91-
if let Some(inet6) = netif.inet6 {
92-
let mut map1: Map<String, Value> = Map::new();
93-
map1.insert("address".into(), json!(inet6.address));
94-
map1.insert("prefixlen".into(), json!(inet6.prefixlen));
95-
map1.insert("scopeid".into(), json!(inet6.scopeid));
96-
map.insert("inet6".into(), json!(map1));
84+
map.insert("name".into(), json!(netif.name));
85+
map.insert("index".into(), json!(netif.index));
86+
if let Some(mac) = netif.mac {
87+
map.insert("mac".into(), json!(mac));
9788
}
98-
if let Some(status) = netif.status {
99-
let status = if status == NetifStatus::Active { "Active".to_string() } else { "Inactive".to_string() };
100-
map.insert("status".into(), json!(status));
89+
if let Some(ips) = netif.ips {
90+
map.insert("ips".into(), json!(ips));
10191
}
92+
map.insert("flags".into(), json!(netif.flags));
10293
net.push(map);
10394
}
10495

@@ -159,33 +150,11 @@ pub struct FsMount {
159150
#[cfg(feature = "local-run")]
160151
#[derive(Debug, RustcEncodable)]
161152
pub struct Netif {
162-
pub interface: String,
153+
pub name: String,
154+
pub index: u32,
163155
pub mac: Option<String>,
164-
pub inet: Option<NetifIPv4>,
165-
pub inet6: Option<NetifIPv6>,
166-
pub status: Option<NetifStatus>,
167-
}
168-
169-
#[cfg(feature = "local-run")]
170-
#[derive(Debug, RustcEncodable, PartialEq)]
171-
pub enum NetifStatus {
172-
Active,
173-
Inactive,
174-
}
175-
176-
#[cfg(feature = "local-run")]
177-
#[derive(Debug, RustcEncodable)]
178-
pub struct NetifIPv4 {
179-
pub address: String,
180-
pub netmask: String,
181-
}
182-
183-
#[cfg(feature = "local-run")]
184-
#[derive(Debug, RustcEncodable)]
185-
pub struct NetifIPv6 {
186-
pub address: String,
187-
pub prefixlen: u8,
188-
pub scopeid: Option<String>,
156+
pub ips: Option<Vec<String>>,
157+
pub flags: u32,
189158
}
190159

191160
#[cfg(feature = "local-run")]

src/lib.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,8 +42,7 @@ extern crate tempfile;
4242
extern crate zdaemon;
4343
extern crate zfilexfer;
4444
extern crate hostname;
45-
extern crate interfaces;
46-
extern crate ipnetwork;
45+
extern crate pnet;
4746

4847
#[macro_use]
4948
mod ffi_helpers;

src/target/centos.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -181,7 +181,7 @@ impl TelemetryTarget for CentosTarget {
181181
try!(default::fs()),
182182
&hostname,
183183
try!(linux::memory()),
184-
try!(linux::net()),
184+
default::net(),
185185
Os::new(
186186
env::consts::ARCH,
187187
"redhat",

src/target/debian.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -182,7 +182,7 @@ impl TelemetryTarget for DebianTarget {
182182
try!(default::fs()),
183183
&hostname,
184184
try!(linux::memory()),
185-
try!(linux::net()),
185+
default::net(),
186186
Os::new(env::consts::ARCH, "debian", "debian", &version_str, version_maj, version_min, 0), // No known patch version
187187
);
188188

src/target/default_base.rs

Lines changed: 12 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,13 @@
99
use command::CommandResult;
1010
use error::{Error, Result};
1111
use host::Host;
12-
use host::telemetry::{FsMount, Netif, NetifIPv4, NetifIPv6, NetifStatus};
12+
use host::telemetry::{FsMount, Netif};
1313
use package::providers::{ProviderFactory, Providers};
1414
use regex::Regex;
1515
use std::{fs, process, str};
1616
use std::path::Path;
1717
use hostname::get_hostname;
18+
use pnet::datalink::interfaces;
1819

1920
pub fn default_provider(host: &mut Host, providers: Vec<Providers>) -> Result<Providers> {
2021
for p in providers {
@@ -204,79 +205,16 @@ pub fn parse_fs(fields: Vec<FsFieldOrder>) -> Result<Vec<FsMount>> {
204205
Ok(fs)
205206
}
206207

207-
pub fn parse_nettools_net(if_pattern: &str, kv_pattern: &str, ipv4_pattern: &str, ipv6_pattern: &str) -> Result<Vec<Netif>> {
208-
let ifconfig_out = try!(process::Command::new("ifconfig").output());
209-
let ifconfig = try!(str::from_utf8(&ifconfig_out.stdout));
210-
211-
// Rust Regex doesn't support negative lookahead, so we are
212-
// forced to pass this line by line.
213-
// Match interfaces:
214-
// (?m:^([a-z]+[0-9]+):((?:(?!^[a-z]+[0-9]+:).)+))
215-
// Match options:
216-
// (?m:^\s*([a-z0-9]+)(?:\s|:\s|=)(.+))
217-
let if_regex = Regex::new(if_pattern).unwrap();
218-
219-
let mut net = vec!();
220-
221-
for cap in if_regex.captures_iter(ifconfig) {
222-
net.push(try!(parse_nettools_netif(cap.name("if").unwrap().as_str(), cap.name("content").unwrap().as_str(), kv_pattern, ipv4_pattern, ipv6_pattern)));
223-
}
224-
225-
Ok(net)
226-
}
227-
228-
fn parse_nettools_netif(iface: &str, content: &str, kv_pattern: &str, ipv4_pattern: &str, ipv6_pattern: &str) -> Result<Netif> {
229-
let mut netif = Netif {
230-
interface: iface.to_string(),
231-
mac: None,
232-
inet: None,
233-
inet6: None,
234-
status: None,
235-
};
236-
237-
let kv_regex = Regex::new(kv_pattern).unwrap();
238-
let ipv4_regex = Regex::new(ipv4_pattern).unwrap();
239-
let ipv6_regex = Regex::new(ipv6_pattern).unwrap();
240-
241-
let lines: Vec<&str> = content.lines().collect();
242-
for line in lines {
243-
if let Some(kv_capture) = kv_regex.captures(line) {
244-
let value = kv_capture.name("value").unwrap().as_str().trim();
245-
246-
match kv_capture.name("key").unwrap().as_str() {
247-
"ether" | "HWaddr" => netif.mac = Some(value.to_string()),
248-
"inet" => {
249-
if let Some(ipv4_capture) = ipv4_regex.captures(value) {
250-
netif.inet = Some(NetifIPv4 {
251-
address: ipv4_capture.name("ip").unwrap().as_str().to_string(),
252-
netmask: ipv4_capture.name("mask").unwrap().as_str().to_string(),
253-
});
254-
}
255-
},
256-
"inet6" => {
257-
if let Some(ipv6_capture) = ipv6_regex.captures(value) {
258-
netif.inet6 = Some(NetifIPv6 {
259-
address: ipv6_capture.name("ip").unwrap().as_str().to_string(),
260-
prefixlen: try!(ipv6_capture.name("prefix").unwrap().as_str().parse::<u8>()),
261-
scopeid: if ipv6_capture.name("scope").is_some() {
262-
Some(ipv6_capture.name("scope").unwrap().as_str().to_string())
263-
} else {
264-
None
265-
},
266-
});
267-
}
268-
},
269-
"status" => netif.status = match value {
270-
"active" => Some(NetifStatus::Active),
271-
"inactive" => Some(NetifStatus::Inactive),
272-
_ => unreachable!(),
273-
},
274-
_ => (),
275-
}
276-
}
277-
}
278-
279-
Ok(netif)
208+
pub fn net() -> Vec<Netif> {
209+
interfaces().into_iter()
210+
.map(|iface| Netif {
211+
name: iface.name,
212+
index: iface.index,
213+
mac: iface.mac.map(|addr| addr.to_string()),
214+
ips: iface.ips.map(|ips| ips.into_iter().map(|ip| ip.to_string()).collect()),
215+
flags: iface.flags,
216+
})
217+
.collect()
280218
}
281219

282220
#[cfg(test)]

src/target/fedora.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -181,7 +181,7 @@ impl TelemetryTarget for FedoraTarget {
181181
try!(default::fs()),
182182
&hostname,
183183
try!(linux::memory()),
184-
try!(linux::net()),
184+
default::net(),
185185
Os::new(
186186
env::consts::ARCH,
187187
"redhat",

src/target/freebsd.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -221,7 +221,7 @@ impl TelemetryTarget for Target {
221221
try!(default::fs()),
222222
&hostname,
223223
try!(try!(unix::get_sysctl_item("hw\\.physmem")).parse::<u64>()),
224-
try!(unix::net()),
224+
default::net(),
225225
Os::new(env::consts::ARCH, "unix", "freebsd", &version_str, version_maj, version_min, 0),
226226
);
227227

src/target/linux_base.rs

Lines changed: 1 addition & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -9,17 +9,12 @@
99
use command::CommandResult;
1010
use error::{Error, Result};
1111
use file::FileOwner;
12-
use host::telemetry::{Netif, NetifIPv4, NetifIPv6, NetifStatus};
1312
use regex::Regex;
1413
use std::{process, str};
1514
use std::fs::File;
1615
use std::io::prelude::*;
1716
use std::path::Path;
18-
use std::net::SocketAddr;
1917
use target::default_base as default;
20-
use ipnetwork::ipv6_mask_to_prefix;
21-
use interfaces::Kind::{Ipv4, Ipv6};
22-
use interfaces::{Address, Interface, flags};
2318

2419
pub fn file_get_owner<P: AsRef<Path>>(path: P) -> Result<FileOwner> {
2520
Ok(FileOwner {
@@ -110,78 +105,6 @@ fn get_cpu_item(item: &str) -> Result<String> {
110105
}
111106
}
112107

113-
fn ipv4(a: &Address) -> Option<NetifIPv4> {
114-
match a.addr {
115-
Some(addr) => {
116-
let address = addr.ip().to_string();
117-
let netmask = a.mask
118-
.and_then(|mask| Some(mask.ip().to_string()))
119-
.unwrap_or(String::new());
120-
121-
Some(NetifIPv4 {
122-
address: address,
123-
netmask: netmask,
124-
})
125-
},
126-
None => None,
127-
}
128-
}
129-
130-
fn ipv6(a: &Address) -> Option<NetifIPv6> {
131-
if let Some(SocketAddr::V6(address)) = a.addr {
132-
if let Some(SocketAddr::V6(mask)) = a.mask {
133-
if let Ok(prefixlen) = ipv6_mask_to_prefix(*mask.ip()) {
134-
return Some(NetifIPv6 {
135-
address: address.ip().to_string(),
136-
prefixlen: prefixlen,
137-
scopeid: Some(address.scope_id().to_string()),
138-
});
139-
}
140-
}
141-
}
142-
None
143-
}
144-
145-
pub fn net() -> Result<Vec<Netif>> {
146-
let mut ifaces = Vec::new();
147-
148-
for iface in Interface::get_all()? {
149-
let mac = match iface.hardware_addr() {
150-
Ok(addr) => Some(addr.as_string()),
151-
Err(_) => None,
152-
};
153-
154-
let inet = iface.addresses.iter()
155-
.filter(|addr| addr.kind == Ipv4)
156-
.next()
157-
.and_then(|addr| ipv4(addr));
158-
159-
let inet6 = iface.addresses.iter()
160-
.filter(|addr| addr.kind == Ipv6)
161-
.next()
162-
.and_then(|addr| ipv6(addr));
163-
164-
let up = iface.is_up();
165-
let running = iface.flags.contains(flags::IFF_RUNNING);
166-
167-
let status = if up && running {
168-
Some(NetifStatus::Active)
169-
} else {
170-
Some(NetifStatus::Inactive)
171-
};
172-
173-
ifaces.push(Netif {
174-
interface: iface.name.to_string(),
175-
mac: mac,
176-
inet: inet,
177-
inet6: inet6,
178-
status: status,
179-
});
180-
}
181-
182-
Ok(ifaces)
183-
}
184-
185108
#[cfg(test)]
186109
mod tests {
187110
use super::*;
@@ -219,6 +142,6 @@ mod tests {
219142
#[test]
220143
fn test_net() {
221144
// XXX Not a proper test. Requires mocking.
222-
assert!(net().is_ok());
145+
assert!(!net().is_empty());
223146
}
224147
}

0 commit comments

Comments
 (0)