diff --git a/.githooks/pre-commit b/.githooks/pre-commit index f7eafe59..e964ca9c 100755 --- a/.githooks/pre-commit +++ b/.githooks/pre-commit @@ -13,12 +13,14 @@ cargo fmt -- --check \ && ./target/debug/examples/ctrl-list \ && ./target/debug/examples/error_packet \ && ./target/debug/examples/nl80211 \ + && ./target/debug/examples/getlink \ && cargo build --examples --features=async \ && ./target/debug/examples/getips \ && ./target/debug/examples/route-list \ && ./target/debug/examples/ctrl-list \ && ./target/debug/examples/error_packet \ && ./target/debug/examples/nl80211 \ + && ./target/debug/examples/getlink \ && cargo test \ && cargo test --all-targets --all-features \ || exit 1 diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 9efa3d4b..aa7c8d67 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -88,6 +88,8 @@ jobs: run: ./target/debug/examples/route-list - name: Run error_packet run: ./target/debug/examples/error_packet + - name: Run getlink + run: ./target/debug/examples/getlink # nl80211 not included due to no wireless interfaces on test machines musl-checks: strategy: @@ -143,6 +145,8 @@ jobs: run: ./target/debug/examples/route-list - name: Run error_packet run: ./target/debug/examples/error_packet + - name: Run getlink + run: ./target/debug/examples/getlink # nl80211 not included due to no wireless interfaces on test machines concurrency: diff --git a/examples/getlink.rs b/examples/getlink.rs new file mode 100644 index 00000000..b9eb5d23 --- /dev/null +++ b/examples/getlink.rs @@ -0,0 +1,41 @@ +use neli::{ + consts::{ + nl::NlmF, + rtnl::{Ifla, RtAddrFamily, Rtm}, + socket::NlFamily, + }, + nl::NlPayload, + router::synchronous::NlRouter, + rtnl::{Ifinfomsg, IfinfomsgBuilder}, + utils::Groups, +}; + +fn main() -> Result<(), Box> { + env_logger::init(); + + let (rtnl, _) = NlRouter::connect(NlFamily::Route, None, Groups::empty())?; + rtnl.enable_ext_ack(true)?; + rtnl.enable_strict_checking(true)?; + let ifinfomsg = IfinfomsgBuilder::default() + .ifi_family(RtAddrFamily::Inet) + .build()?; + + let recv = rtnl.send::<_, _, Rtm, Ifinfomsg>( + Rtm::Getlink, + NlmF::DUMP | NlmF::ACK, + NlPayload::Payload(ifinfomsg), + )?; + for response in recv { + if let Some(payload) = response?.get_payload() { + println!( + "{:?}", + payload + .rtattrs() + .get_attr_handle() + .get_attr_payload_as_with_len::(Ifla::Ifname)?, + ) + } + } + + Ok(()) +} diff --git a/src/rtnl.rs b/src/rtnl.rs index f110ae0f..45910371 100644 --- a/src/rtnl.rs +++ b/src/rtnl.rs @@ -34,9 +34,11 @@ pub struct Ifinfomsg { padding: u8, /// Interface type #[getset(get = "pub")] + #[builder(default = "Arphrd::from(0)")] ifi_type: Arphrd, /// Interface index #[getset(get = "pub")] + #[builder(default = "0")] ifi_index: libc::c_int, /// Interface flags #[getset(get = "pub")] @@ -428,6 +430,7 @@ mod test { use crate::{ consts::{nl::NlmF, socket::NlFamily}, + err::RouterError, nl::NlPayload, router::synchronous::NlRouter, test::setup, @@ -474,31 +477,41 @@ mod test { let (sock, _) = NlRouter::connect(NlFamily::Route, None, Groups::empty()).unwrap(); sock.enable_strict_checking(true).unwrap(); - let recv = sock + let mut recv = sock .send::<_, _, Rtm, Ifinfomsg>( Rtm::Getlink, NlmF::DUMP | NlmF::ACK, NlPayload::Payload( IfinfomsgBuilder::default() .ifi_family(RtAddrFamily::Unspecified) - .ifi_type(Arphrd::None) - .ifi_index(0) .build() .unwrap(), ), ) .unwrap(); - for msg in recv { - let msg = msg.unwrap(); - if let Some(payload) = msg.get_payload() { - let handle = payload.rtattrs.get_attr_handle(); - handle - .get_attr_payload_as_with_len::(Ifla::Ifname) - .unwrap(); - // Assert length of ethernet address - if let Ok(attr) = handle.get_attr_payload_as_with_len::>(Ifla::Address) { - assert_eq!(attr.len(), 6); - } + let all_msgs = recv + .try_fold(Vec::new(), |mut v, m| { + v.push(m?); + Result::<_, RouterError>::Ok(v) + }) + .unwrap(); + let non_err_payloads = all_msgs.iter().fold(Vec::new(), |mut v, m| { + if let Some(p) = m.get_payload() { + v.push(p); + } + v + }); + if non_err_payloads.is_empty() { + panic!("Only received done message and no additional information"); + } + for payload in non_err_payloads { + let handle = payload.rtattrs.get_attr_handle(); + handle + .get_attr_payload_as_with_len::(Ifla::Ifname) + .unwrap(); + // Assert length of ethernet address + if let Ok(attr) = handle.get_attr_payload_as_with_len::>(Ifla::Address) { + assert_eq!(attr.len(), 6); } } } diff --git a/src/socket/synchronous.rs b/src/socket/synchronous.rs index 2ec394c5..1e9e5d55 100644 --- a/src/socket/synchronous.rs +++ b/src/socket/synchronous.rs @@ -76,6 +76,7 @@ impl NlSocketHandle { let mut buffer = Cursor::new(vec![0; msg.padded_size()]); msg.to_bytes(&mut buffer)?; + trace!("Buffer sent: {:?}", buffer.get_ref()); self.socket.send(buffer.get_ref(), Msg::empty())?; Ok(())