const_assert!(size_of::<nlmsghdr>() <= u8::MAX as usize);
const_assert!(size_of::<rtmsg>() <= u8::MAX as usize);
const_assert!(size_of::<rtattr>() <= u8::MAX as usize);
const_assert!(size_of::<ifinfomsg>() <= u8::MAX as usize);
const NETLINK_BUFFER_SIZE: usize = 8192; // See netlink(7) man page.
fn parse_c_int(buf: &[u8]) -> Result<c_int> { if buf.len() < size_of::<c_int>() { return Err(default_err());
} let bytes = <&[u8] as TryInto<[u8; size_of::<c_int>()]>>::try_into(&buf[..size_of::<c_int>()])
.map_err(|_| default_err())?;
Ok(c_int::from_ne_bytes(bytes))
}
fn read_msg_with_seq(fd: &mut RouteSocket, seq: u32, kind: u16) -> Result<(nlmsghdr, Vec<u8>)> { loop { let buf = &mut [0u8; NETLINK_BUFFER_SIZE]; let len = fd.read(buf.as_mut_slice())?; letmut next = &buf[..len]; while size_of::<nlmsghdr>() <= next.len() { let (hdr, mut msg) = next.split_at(size_of::<nlmsghdr>()); let hdr: nlmsghdr = hdr.try_into()?; // `msg` has the remainder of this message plus any following messages. // Strip those it off and assign them to `next`.
debug_assert!(size_of::<nlmsghdr>() <= hdr.nlmsg_len as usize);
(msg, next) = msg.split_at(hdr.nlmsg_len as usize - size_of::<nlmsghdr>());
if hdr.nlmsg_seq != seq { continue;
}
if hdr.nlmsg_type == NLMSG_ERROR { // Extract the error code and return it. let err = parse_c_int(msg)?; if err != 0 { return Err(Error::from_raw_os_error(-err));
}
} elseif hdr.nlmsg_type == kind { // Return the header and the message. return Ok((hdr, msg.to_vec()));
}
}
}
}
impl TryFrom<&[u8]> for rtattr { type Error = Error;
fn if_index(remote: IpAddr, fd: &mut RouteSocket) -> Result<i32> { // Send RTM_GETROUTE message to get the interface index associated with the destination. let msg_seq = RouteSocket::new_seq(); let msg = IfIndexMsg::new(remote, msg_seq);
fd.write_all((&msg).into())?;
// Receive RTM_GETROUTE response. let (_hdr, mut buf) = read_msg_with_seq(fd, msg_seq, RTM_NEWROUTE)?;
debug_assert!(size_of::<rtmsg>() <= buf.len()); let buf = buf.split_off(size_of::<rtmsg>());
// Parse through the attributes to find the interface index. for attr in RtAttrs(buf.as_slice()).by_ref() { if attr.hdr.rta_type == RTA_OIF { // We have our interface index. return parse_c_int(attr.msg);
}
}
Err(default_err())
}
fn if_name_mtu(if_index: i32, fd: &mut RouteSocket) -> Result<(String, usize)> { // Send RTM_GETLINK message to get interface information for the given interface index. let msg_seq = RouteSocket::new_seq(); let msg = IfInfoMsg::new(if_index, msg_seq);
fd.write_all((&msg).into())?;
// Receive RTM_GETLINK response. let (_hdr, mut buf) = read_msg_with_seq(fd, msg_seq, RTM_NEWLINK)?;
debug_assert!(size_of::<ifinfomsg>() <= buf.len()); let buf = buf.split_off(size_of::<ifinfomsg>());
// Parse through the attributes to find the interface name and MTU. letmut ifname = None; letmut mtu = None; for attr in RtAttrs(buf.as_slice()).by_ref() { match attr.hdr.rta_type {
IFLA_IFNAME => { let name = CStr::from_bytes_until_nul(attr.msg).map_err(Error::other)?;
ifname = Some(name.to_str().map_err(Error::other)?.to_string());
}
IFLA_MTU => {
mtu = Some(
parse_c_int(attr.msg)?
.try_into()
.map_err(|e: TryFromIntError| unlikely_err(e.to_string()))?,
);
}
_ => (),
} iflet (Some(ifname), Some(mtu)) = (ifname.as_ref(), mtu.as_ref()) { return Ok((ifname.clone(), *mtu));
}
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.