diff --git a/src/agent/Cargo.lock b/src/agent/Cargo.lock index 05bf8d6edd..89578fb9cd 100644 --- a/src/agent/Cargo.lock +++ b/src/agent/Cargo.lock @@ -564,7 +564,6 @@ dependencies = [ "libc", "log", "logging", - "netlink", "netlink-packet-utils", "netlink-sys 0.4.0", "nix 0.17.0", @@ -775,18 +774,6 @@ dependencies = [ "winapi 0.3.9", ] -[[package]] -name = "netlink" -version = "0.1.0" -dependencies = [ - "libc", - "nix 0.17.0", - "protobuf", - "protocols", - "slog", - "slog-scope", -] - [[package]] name = "netlink-packet-core" version = "0.2.2" diff --git a/src/agent/Cargo.toml b/src/agent/Cargo.toml index 4798aacd50..0a6946b057 100644 --- a/src/agent/Cargo.toml +++ b/src/agent/Cargo.toml @@ -9,7 +9,6 @@ oci = { path = "oci" } logging = { path = "../../pkg/logging" } rustjail = { path = "rustjail" } protocols = { path = "protocols" } -netlink = { path = "netlink", features = ["with-log", "with-agent-handler"] } lazy_static = "1.3.0" ttrpc = { version = "0.4.14", features = ["async", "protobuf-codec"], default-features = false } protobuf = "=2.14.0" @@ -51,7 +50,6 @@ cgroups = { package = "cgroups-rs", version = "0.2.1" } [workspace] members = [ - "netlink", "oci", "protocols", "rustjail", diff --git a/src/agent/netlink/Cargo.toml b/src/agent/netlink/Cargo.toml deleted file mode 100644 index a5845fb5f4..0000000000 --- a/src/agent/netlink/Cargo.toml +++ /dev/null @@ -1,20 +0,0 @@ -[package] -name = "netlink" -version = "0.1.0" -authors = ["The Kata Containers community "] -edition = "2018" - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[dependencies] -libc = "0.2.58" -nix = "0.17.0" - -protobuf = { version = "=2.14.0", optional = true } -protocols = { path = "../protocols", optional = true } -slog = { version = "2.5.2", features = ["dynamic-keys", "max_level_trace", "release_max_level_info"], optional = true } -slog-scope = { version = "4.1.2", optional = true } - -[features] -with-log = ["slog", "slog-scope"] -with-agent-handler = ["protobuf", "protocols"] diff --git a/src/agent/netlink/src/agent_handler.rs b/src/agent/netlink/src/agent_handler.rs deleted file mode 100644 index a8fffb071f..0000000000 --- a/src/agent/netlink/src/agent_handler.rs +++ /dev/null @@ -1,572 +0,0 @@ -// Copyright (c) 2020 Ant Financial -// Copyright (C) 2020 Alibaba Cloud. All rights reserved. -// -// SPDX-License-Identifier: Apache-2.0 -// - -//! Dedicated Netlink interfaces for Kata agent protocol handler. - -use std::convert::TryFrom; - -use protobuf::RepeatedField; -use protocols::types::{ARPNeighbor, IPAddress, IPFamily, Interface, Route}; - -use super::*; - -#[cfg(feature = "with-log")] -// Convenience macro to obtain the scope logger -macro_rules! sl { - () => { - slog_scope::logger().new(o!("subsystem" => "netlink")) - }; -} - -impl super::RtnlHandle { - pub fn update_interface(&mut self, iface: &Interface) -> Result { - // the reliable way to find link is using hardware address - // as filter. However, hardware filter might not be supported - // by netlink, we may have to dump link list and the find the - // target link. filter using name or family is supported, but - // we cannot use that to find target link. - // let's try if hardware address filter works. -_- - - let ifinfo = self.find_link_by_hwaddr(iface.hwAddr.as_str())?; - - // bring down interface if it is up - if ifinfo.ifi_flags & libc::IFF_UP as u32 != 0 { - self.set_link_status(&ifinfo, false)?; - } - - // delete all addresses associated with the link - let del_addrs: Vec = self.get_link_addresses(&ifinfo)?; - self.delete_all_addrs(&ifinfo, del_addrs.as_ref())?; - - // add new ip addresses in request - for grpc_addr in &iface.IPAddresses { - let rtip = RtIPAddr::try_from(grpc_addr.clone())?; - self.add_one_address(&ifinfo, &rtip)?; - } - - let mut v: Vec = vec![0; DEFAULT_NETLINK_BUF_SIZE]; - // Safe because we have allocated enough buffer space. - let nlh = unsafe { &mut *(v.as_mut_ptr() as *mut nlmsghdr) }; - let ifi = unsafe { &mut *(NLMSG_DATA!(nlh) as *mut ifinfomsg) }; - - // set name, set mtu, IFF_NOARP. in one rtnl_talk. - nlh.nlmsg_len = NLMSG_LENGTH!(mem::size_of::() as u32) as __u32; - nlh.nlmsg_type = RTM_NEWLINK; - nlh.nlmsg_flags = NLM_F_REQUEST; - self.assign_seqnum(nlh); - - ifi.ifi_family = ifinfo.ifi_family; - ifi.ifi_type = ifinfo.ifi_type; - ifi.ifi_index = ifinfo.ifi_index; - if iface.raw_flags & libc::IFF_NOARP as u32 != 0 { - ifi.ifi_change |= libc::IFF_NOARP as u32; - ifi.ifi_flags |= libc::IFF_NOARP as u32; - } - - // Safe because we have allocated enough buffer space. - unsafe { - nlh.addattr32(IFLA_MTU, iface.mtu as u32); - - // if str is null terminated, use addattr_var. - // otherwise, use addattr_str - nlh.addattr_var(IFLA_IFNAME, iface.name.as_ref()); - } - - self.rtnl_talk(v.as_mut_slice(), false)?; - - // TODO: why the result is ignored here? - let _ = self.set_link_status(&ifinfo, true); - - Ok(iface.clone()) - } - - /// Delete this interface/link per request - pub fn remove_interface(&mut self, iface: &Interface) -> Result { - let ifinfo = self.find_link_by_hwaddr(iface.hwAddr.as_str())?; - - self.set_link_status(&ifinfo, false)?; - - let mut v: Vec = vec![0; DEFAULT_NETLINK_BUF_SIZE]; - // Safe because we have allocated enough buffer space. - let nlh = unsafe { &mut *(v.as_mut_ptr() as *mut nlmsghdr) }; - let ifi = unsafe { &mut *(NLMSG_DATA!(nlh) as *mut ifinfomsg) }; - - // No attributes needed? - nlh.nlmsg_len = NLMSG_LENGTH!(mem::size_of::()) as __u32; - nlh.nlmsg_type = RTM_DELLINK; - nlh.nlmsg_flags = NLM_F_REQUEST; - self.assign_seqnum(nlh); - - ifi.ifi_family = ifinfo.ifi_family; - ifi.ifi_index = ifinfo.ifi_index; - ifi.ifi_type = ifinfo.ifi_type; - - self.rtnl_talk(v.as_mut_slice(), false)?; - - Ok(iface.clone()) - } - - pub fn list_interfaces(&mut self) -> Result> { - let mut ifaces: Vec = Vec::new(); - let (_slv, lv) = self.dump_all_links()?; - let (_sav, av) = self.dump_all_addresses(0)?; - - for link in &lv { - // Safe because dump_all_links() returns valid pointers. - let nlh = unsafe { &**link }; - if nlh.nlmsg_type != RTM_NEWLINK && nlh.nlmsg_type != RTM_DELLINK { - continue; - } - - if nlh.nlmsg_len < NLMSG_SPACE!(mem::size_of::()) { - info!( - sl!(), - "invalid nlmsg! nlmsg_len: {}, nlmsg_space: {}", - nlh.nlmsg_len, - NLMSG_SPACE!(mem::size_of::()) - ); - break; - } - - // Safe because we have just validated available buffer space above. - let ifi = unsafe { &*(NLMSG_DATA!(nlh) as *const ifinfomsg) }; - let rta: *mut rtattr = IFLA_RTA!(ifi as *const ifinfomsg) as *mut rtattr; - let rtalen = IFLA_PAYLOAD!(nlh) as u32; - let attrs = unsafe { parse_attrs(rta, rtalen, (IFLA_MAX + 1) as usize)? }; - - // fill out some fields of Interface, - let mut iface: Interface = Interface::default(); - - // Safe because parse_attrs() returns valid pointers. - unsafe { - if !attrs[IFLA_IFNAME as usize].is_null() { - let t = attrs[IFLA_IFNAME as usize]; - iface.name = String::from_utf8(getattr_var(t as *const rtattr))?; - } - - if !attrs[IFLA_MTU as usize].is_null() { - let t = attrs[IFLA_MTU as usize]; - iface.mtu = getattr32(t) as u64; - } - - if !attrs[IFLA_ADDRESS as usize].is_null() { - let alen = RTA_PAYLOAD!(attrs[IFLA_ADDRESS as usize]); - let a: *const u8 = RTA_DATA!(attrs[IFLA_ADDRESS as usize]) as *const u8; - iface.hwAddr = parser::format_address(a, alen as u32)?; - } - } - - // get ip address info from av - let mut ads: Vec = Vec::new(); - for address in &av { - // Safe because dump_all_addresses() returns valid pointers. - let alh = unsafe { &**address }; - if alh.nlmsg_type != RTM_NEWADDR { - continue; - } - - let tlen = NLMSG_SPACE!(mem::size_of::()); - if alh.nlmsg_len < tlen { - info!( - sl!(), - "invalid nlmsg! nlmsg_len: {}, nlmsg_space: {}", alh.nlmsg_len, tlen - ); - break; - } - - // Safe becahse we have checked avialable buffer space by NLMSG_SPACE above. - let ifa = unsafe { &*(NLMSG_DATA!(alh) as *const ifaddrmsg) }; - let arta: *mut rtattr = IFA_RTA!(ifa) as *mut rtattr; - let artalen = IFA_PAYLOAD!(alh) as u32; - - if ifa.ifa_index as u32 == ifi.ifi_index as u32 { - // found target addresses, parse attributes and fill out Interface - let addrs = unsafe { parse_attrs(arta, artalen, (IFA_MAX + 1) as usize)? }; - - // fill address field of Interface - let mut one: IPAddress = IPAddress::default(); - let tattr: *const rtattr = if !addrs[IFA_ADDRESS as usize].is_null() { - addrs[IFA_ADDRESS as usize] - } else { - addrs[IFA_LOCAL as usize] - }; - - one.mask = format!("{}", ifa.ifa_prefixlen); - one.family = IPFamily::v4; - if ifa.ifa_family == libc::AF_INET6 as u8 { - one.family = IPFamily::v6; - } - - // Safe because parse_attrs() returns valid pointers. - unsafe { - let a: *const u8 = RTA_DATA!(tattr) as *const u8; - let alen = RTA_PAYLOAD!(tattr); - one.address = parser::format_address(a, alen as u32)?; - } - - ads.push(one); - } - } - - iface.IPAddresses = RepeatedField::from_vec(ads); - ifaces.push(iface); - } - - Ok(ifaces) - } - - pub fn update_routes(&mut self, rt: &[Route]) -> Result> { - let rs = self.get_all_routes()?; - self.delete_all_routes(&rs)?; - - for grpcroute in rt { - if grpcroute.gateway.as_str() == "" { - let r = RtRoute::try_from(grpcroute.clone())?; - if r.index == -1 { - continue; - } - self.add_one_route(&r)?; - } - } - - for grpcroute in rt { - if grpcroute.gateway.as_str() != "" { - let r = RtRoute::try_from(grpcroute.clone())?; - if r.index == -1 { - continue; - } - self.add_one_route(&r)?; - } - } - - Ok(rt.to_owned()) - } - - pub fn list_routes(&mut self) -> Result> { - // currently, only dump routes from main table for ipv4 - // ie, rtmsg.rtmsg_family = AF_INET, set RT_TABLE_MAIN - // attribute in dump request - // Fix Me: think about othe tables, ipv6.. - let mut rs: Vec = Vec::new(); - let (_srv, rv) = self.dump_all_routes()?; - - // parse out routes and store in rs - for r in &rv { - // Safe because dump_all_routes() returns valid pointers. - let nlh = unsafe { &**r }; - if nlh.nlmsg_type != RTM_NEWROUTE && nlh.nlmsg_type != RTM_DELROUTE { - info!(sl!(), "not route message!"); - continue; - } - let tlen = NLMSG_SPACE!(mem::size_of::()); - if nlh.nlmsg_len < tlen { - info!( - sl!(), - "invalid nlmsg! nlmsg_len: {}, nlmsg_spae: {}", nlh.nlmsg_len, tlen - ); - break; - } - - // Safe because we have just validated available buffer space above. - let rtm = unsafe { &mut *(NLMSG_DATA!(nlh) as *mut rtmsg) }; - if rtm.rtm_table != RT_TABLE_MAIN as u8 { - continue; - } - let rta: *mut rtattr = RTM_RTA!(rtm) as *mut rtattr; - let rtalen = RTM_PAYLOAD!(nlh) as u32; - let attrs = unsafe { parse_attrs(rta, rtalen, (RTA_MAX + 1) as usize)? }; - - let t = attrs[RTA_TABLE as usize]; - if !t.is_null() { - // Safe because parse_attrs() returns valid pointers - let table = unsafe { getattr32(t) }; - if table != RT_TABLE_MAIN { - continue; - } - } - - // find source, destination, gateway, scope, and and device name - let mut t = attrs[RTA_DST as usize]; - let mut rte: Route = Route::default(); - - // Safe because parse_attrs() returns valid pointers - unsafe { - // destination - if !t.is_null() { - let data: *const u8 = RTA_DATA!(t) as *const u8; - let len = RTA_PAYLOAD!(t) as u32; - rte.dest = - format!("{}/{}", parser::format_address(data, len)?, rtm.rtm_dst_len); - } - - // gateway - t = attrs[RTA_GATEWAY as usize]; - if !t.is_null() { - let data: *const u8 = RTA_DATA!(t) as *const u8; - let len = RTA_PAYLOAD!(t) as u32; - rte.gateway = parser::format_address(data, len)?; - - // for gateway, destination is 0.0.0.0 - rte.dest = "0.0.0.0".to_string(); - } - - // source - t = attrs[RTA_SRC as usize]; - if t.is_null() { - t = attrs[RTA_PREFSRC as usize]; - } - if !t.is_null() { - let data: *const u8 = RTA_DATA!(t) as *const u8; - let len = RTA_PAYLOAD!(t) as u32; - rte.source = parser::format_address(data, len)?; - - if rtm.rtm_src_len != 0 { - rte.source = format!("{}/{}", rte.source.as_str(), rtm.rtm_src_len); - } - } - - // scope - rte.scope = rtm.rtm_scope as u32; - - // oif - t = attrs[RTA_OIF as usize]; - if !t.is_null() { - let data = &*(RTA_DATA!(t) as *const i32); - assert_eq!(RTA_PAYLOAD!(t), 4); - - rte.device = self - .get_name_by_index(*data) - .unwrap_or_else(|_| "unknown".to_string()); - } - } - - rs.push(rte); - } - - Ok(rs) - } - - pub fn add_arp_neighbors(&mut self, neighs: &[ARPNeighbor]) -> Result<()> { - for neigh in neighs { - self.add_one_arp_neighbor(&neigh)?; - } - - Ok(()) - } - - pub fn add_one_arp_neighbor(&mut self, neigh: &ARPNeighbor) -> Result<()> { - let to_ip = match neigh.toIPAddress.as_ref() { - None => return nix_errno(Errno::EINVAL), - Some(v) => { - if v.address.is_empty() { - return nix_errno(Errno::EINVAL); - } - v.address.as_ref() - } - }; - - let dev = self.find_link_by_name(&neigh.device)?; - - let mut v: Vec = vec![0; DEFAULT_NETLINK_BUF_SIZE]; - // Safe because we have allocated enough buffer space. - let nlh = unsafe { &mut *(v.as_mut_ptr() as *mut nlmsghdr) }; - let ndm = unsafe { &mut *(NLMSG_DATA!(nlh) as *mut ndmsg) }; - - nlh.nlmsg_len = NLMSG_LENGTH!(std::mem::size_of::()) as u32; - nlh.nlmsg_type = RTM_NEWNEIGH; - nlh.nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE | NLM_F_EXCL; - self.assign_seqnum(nlh); - - ndm.ndm_family = libc::AF_UNSPEC as __u8; - ndm.ndm_state = IFA_F_PERMANENT as __u16; - // process lladdr - if neigh.lladdr != "" { - let llabuf = parser::parse_mac_addr(&neigh.lladdr)?; - - // Safe because we have allocated enough buffer space. - unsafe { nlh.addattr_var(NDA_LLADDR, llabuf.as_ref()) }; - } - - let (family, ip_data) = parser::parse_ip_addr_with_family(&to_ip)?; - ndm.ndm_family = family; - // Safe because we have allocated enough buffer space. - unsafe { nlh.addattr_var(NDA_DST, ip_data.as_ref()) }; - - // process state - if neigh.state != 0 { - ndm.ndm_state = neigh.state as __u16; - } - - // process flags - ndm.ndm_flags = (*ndm).ndm_flags | neigh.flags as __u8; - - // process dev - ndm.ndm_ifindex = dev.ifi_index; - - // send - self.rtnl_talk(v.as_mut_slice(), false)?; - - Ok(()) - } -} - -impl TryFrom for RtIPAddr { - type Error = nix::Error; - - fn try_from(ipi: IPAddress) -> std::result::Result { - let ip_family = if ipi.family == IPFamily::v4 { - libc::AF_INET - } else { - libc::AF_INET6 - } as __u8; - - let ip_mask = parser::parse_u8(ipi.mask.as_str(), 10)?; - let addr = parser::parse_ip_addr(ipi.address.as_ref())?; - - Ok(Self { - ip_family, - ip_mask, - addr, - }) - } -} - -impl TryFrom for RtRoute { - type Error = nix::Error; - - fn try_from(r: Route) -> std::result::Result { - // only handle ipv4 - - let index = { - let mut rh = RtnlHandle::new(NETLINK_ROUTE, 0)?; - match rh.find_link_by_name(r.device.as_str()) { - Ok(ifi) => ifi.ifi_index, - Err(_) => -1, - } - }; - - let (dest, dst_len) = if r.dest.is_empty() { - (Some(vec![0 as u8; 4]), 0) - } else { - let (dst, mask) = parser::parse_cidr(r.dest.as_str())?; - (Some(dst), mask) - }; - - let (source, src_len) = if r.source.is_empty() { - (None, 0) - } else { - let (src, mask) = parser::parse_cidr(r.source.as_str())?; - (Some(src), mask) - }; - - let gateway = if r.gateway.is_empty() { - None - } else { - Some(parser::parse_ip_addr(r.gateway.as_str())?) - }; - - Ok(Self { - dest, - source, - src_len, - dst_len, - index, - gateway, - scope: r.scope as u8, - protocol: RTPROTO_UNSPEC, - }) - } -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::{RtnlHandle, NETLINK_ROUTE}; - use protocols::types::IPAddress; - use std::process::Command; - - fn clean_env_for_test_add_one_arp_neighbor(dummy_name: &str, ip: &str) { - // ip link delete dummy - Command::new("ip") - .args(&["link", "delete", dummy_name]) - .output() - .expect("prepare: failed to delete dummy"); - - // ip neigh del dev dummy ip - Command::new("ip") - .args(&["neigh", "del", dummy_name, ip]) - .output() - .expect("prepare: failed to delete neigh"); - } - - fn prepare_env_for_test_add_one_arp_neighbor(dummy_name: &str, ip: &str) { - clean_env_for_test_add_one_arp_neighbor(dummy_name, ip); - // modprobe dummy - Command::new("modprobe") - .arg("dummy") - .output() - .expect("failed to run modprobe dummy"); - - // ip link add dummy type dummy - Command::new("ip") - .args(&["link", "add", dummy_name, "type", "dummy"]) - .output() - .expect("failed to add dummy interface"); - - // ip addr add 192.168.0.2/16 dev dummy - Command::new("ip") - .args(&["addr", "add", "192.168.0.2/16", "dev", dummy_name]) - .output() - .expect("failed to add ip for dummy"); - - // ip link set dummy up; - Command::new("ip") - .args(&["link", "set", dummy_name, "up"]) - .output() - .expect("failed to up dummy"); - } - - #[test] - fn test_add_one_arp_neighbor() { - // skip_if_not_root - if !nix::unistd::Uid::effective().is_root() { - println!("INFO: skipping {} which needs root", module_path!()); - return; - } - - let mac = "6a:92:3a:59:70:aa"; - let to_ip = "169.254.1.1"; - let dummy_name = "dummy_for_arp"; - - prepare_env_for_test_add_one_arp_neighbor(dummy_name, to_ip); - - let mut ip_address = IPAddress::new(); - ip_address.set_address(to_ip.to_string()); - - let mut neigh = ARPNeighbor::new(); - neigh.set_toIPAddress(ip_address); - neigh.set_device(dummy_name.to_string()); - neigh.set_lladdr(mac.to_string()); - neigh.set_state(0x80); - - let mut rtnl = RtnlHandle::new(NETLINK_ROUTE, 0).unwrap(); - - rtnl.add_one_arp_neighbor(&neigh).unwrap(); - - // ip neigh show dev dummy ip - let stdout = Command::new("ip") - .args(&["neigh", "show", "dev", dummy_name, to_ip]) - .output() - .expect("failed to show neigh") - .stdout; - - let stdout = std::str::from_utf8(&stdout).expect("failed to conveert stdout"); - - assert_eq!(stdout, format!("{} lladdr {} PERMANENT\n", to_ip, mac)); - - clean_env_for_test_add_one_arp_neighbor(dummy_name, to_ip); - } -} diff --git a/src/agent/netlink/src/lib.rs b/src/agent/netlink/src/lib.rs deleted file mode 100644 index 37268286fa..0000000000 --- a/src/agent/netlink/src/lib.rs +++ /dev/null @@ -1,2354 +0,0 @@ -// Copyright (c) 2019 Ant Financial -// -// SPDX-License-Identifier: Apache-2.0 -// - -//! Structs, consts to support Linux Netlink operations -//! -//! The netlink library makes heavy use of unsafe functions, we trust the Linux kernel and assume: -//! - all pointers/buffers generated by kernel are valid -//! - all offsets are within legal range -//! - all fields have been correctly aligned - -#![allow(non_camel_case_types)] -// NOTE!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -// By default, there are many warnings for incorrect alignment like: -// casting from `*mut u8` to a more-strictly-aligned pointer (`*mut nlmsghdr`) (1 < 4 bytes) -// -// The root cause is that we use a Vec buffer to receive netlink message from the kernel. -// The data buffer for a Vec may be 1-byte aligned, which doesn't match the alignment -// requirement for netlink message fields. The reason it works without failure now is that -// rust memory allocation is 16-byte aligned by default. -// -// But please do pay attention here, it's no guarantee that it will be 16-byte aligned, just works -// in this way. For safety, we should use something like the FamStruct from the vmm-sys-util crate. -#![allow(clippy::cast_ptr_alignment)] - -extern crate libc; -extern crate nix; - -#[cfg(feature = "with-agent-handler")] -extern crate protobuf; -#[cfg(feature = "with-agent-handler")] -extern crate protocols; - -#[cfg(feature = "with-log")] -#[macro_use] -extern crate slog; -#[cfg(feature = "with-log")] -extern crate slog_scope; - -use nix::errno::Errno; -use std::borrow::Borrow; -use std::ffi::CString; -use std::fmt; -use std::mem; -use std::os::unix::io::RawFd; - -#[cfg(feature = "with-log")] -// Convenience macro to obtain the scope logger -macro_rules! sl { - () => { - slog_scope::logger().new(o!("subsystem" => "netlink")) - }; -} - -#[cfg(not(feature = "with-log"))] -#[macro_export] -macro_rules! info { - ($l:expr, #$tag:expr, $($args:tt)*) => {}; - ($l:expr, $($args:tt)*) => {}; -} - -#[cfg(feature = "with-agent-handler")] -mod agent_handler; -pub mod parser; - -pub const DEFAULT_NETLINK_BUF_SIZE: usize = 2048; - -/// Specialized std::result::Result for Netlink related operations. -pub type Result = std::result::Result; - -pub type __s8 = libc::c_char; -pub type __u8 = libc::c_uchar; -pub type __s16 = libc::c_short; -pub type __u16 = libc::c_ushort; -pub type __s32 = libc::c_int; -pub type __u32 = libc::c_uint; -pub type __s64 = libc::c_longlong; -pub type __u64 = libc::c_ulonglong; - -// we need ifaddrmsg, ifinfomasg, rtmsg -// we need some constant - -pub const RTM_BASE: libc::c_ushort = 16; -pub const RTM_NEWLINK: libc::c_ushort = 16; -pub const RTM_DELLINK: libc::c_ushort = 17; -pub const RTM_GETLINK: libc::c_ushort = 18; -pub const RTM_SETLINK: libc::c_ushort = 19; -pub const RTM_NEWADDR: libc::c_ushort = 20; -pub const RTM_DELADDR: libc::c_ushort = 21; -pub const RTM_GETADDR: libc::c_ushort = 22; -pub const RTM_NEWROUTE: libc::c_ushort = 24; -pub const RTM_DELROUTE: libc::c_ushort = 25; -pub const RTM_GETROUTE: libc::c_ushort = 26; -pub const RTM_NEWNEIGH: libc::c_ushort = 28; -pub const RTM_DELNEIGH: libc::c_ushort = 29; -pub const RTM_GETNEIGH: libc::c_ushort = 30; -pub const RTM_NEWRULE: libc::c_ushort = 32; -pub const RTM_DELRULE: libc::c_ushort = 33; -pub const RTM_GETRULE: libc::c_ushort = 34; -pub const RTM_NEWQDISC: libc::c_ushort = 36; -pub const RTM_DELQDISC: libc::c_ushort = 37; -pub const RTM_GETQDISC: libc::c_ushort = 38; -pub const RTM_NEWTCLASS: libc::c_ushort = 40; -pub const RTM_DELTCLASS: libc::c_ushort = 41; -pub const RTM_GETTCLASS: libc::c_ushort = 42; -pub const RTM_NEWTFILTER: libc::c_ushort = 44; -pub const RTM_DELTFILTER: libc::c_ushort = 45; -pub const RTM_GETTFILTER: libc::c_ushort = 46; -pub const RTM_NEWACTION: libc::c_ushort = 48; -pub const RTM_DELACTION: libc::c_ushort = 49; -pub const RTM_GETACTION: libc::c_ushort = 50; -pub const RTM_NEWPREFIX: libc::c_ushort = 52; -pub const RTM_GETMULTICAST: libc::c_ushort = 58; -pub const RTM_GETANYCAST: libc::c_ushort = 62; -pub const RTM_NEWNEIGHTBL: libc::c_ushort = 64; -pub const RTM_GETNEIGHTBL: libc::c_ushort = 66; -pub const RTM_SETNEIGHTBL: libc::c_ushort = 67; -pub const RTM_NEWNDUSEROPT: libc::c_ushort = 68; -pub const RTM_NEWADDRLABEL: libc::c_ushort = 72; -pub const RTM_DELADDRLABEL: libc::c_ushort = 73; -pub const RTM_GETADDRLABEL: libc::c_ushort = 74; -pub const RTM_GETDCB: libc::c_ushort = 78; -pub const RTM_SETDCB: libc::c_ushort = 79; -pub const RTM_NEWNETCONF: libc::c_ushort = 80; -pub const RTM_GETNETCONF: libc::c_ushort = 82; -pub const RTM_NEWMDB: libc::c_ushort = 84; -pub const RTM_DELMDB: libc::c_ushort = 85; -pub const RTM_GETMDB: libc::c_ushort = 86; -pub const RTM_NEWNSID: libc::c_ushort = 88; -pub const RTM_DELNSID: libc::c_ushort = 89; -pub const RTM_GETNSID: libc::c_ushort = 90; -pub const RTM_NEWSTATS: libc::c_ushort = 92; -pub const RTM_GETSTATS: libc::c_ushort = 94; -pub const RTM_NEWCACHEREPORT: libc::c_ushort = 96; -pub const RTM_NEWCHAIN: libc::c_ushort = 100; -pub const RTM_DELCHAIN: libc::c_ushort = 101; -pub const RTM_GETCHAIN: libc::c_ushort = 102; -pub const __RTM_MAX: libc::c_ushort = 103; - -pub const RTM_MAX: libc::c_ushort = ((__RTM_MAX + 3) & !3) - 1; -pub const RTM_NR_MSGTYPES: libc::c_ushort = (RTM_MAX + 1) - RTM_BASE; -pub const RTM_NR_FAMILIES: libc::c_ushort = RTM_NR_MSGTYPES >> 2; - -#[macro_export] -macro_rules! RTM_FAM { - ($cmd: expr) => { - ($cmd - RTM_BASE) >> 2 - }; -} - -#[repr(C)] -#[derive(Copy)] -pub struct rtattr { - rta_len: libc::c_ushort, - rta_type: libc::c_ushort, -} - -impl Clone for rtattr { - fn clone(&self) -> Self { - Self { ..*self } - } -} - -impl Default for rtattr { - fn default() -> Self { - Self { - ..unsafe { mem::zeroed::() } - } - } -} - -#[repr(C)] -#[derive(Copy)] -pub struct rtmsg { - rtm_family: libc::c_uchar, - rtm_dst_len: libc::c_uchar, - rtm_src_len: libc::c_uchar, - rtm_tos: libc::c_uchar, - rtm_table: libc::c_uchar, - rtm_protocol: libc::c_uchar, - rtm_scope: libc::c_uchar, - rtm_type: libc::c_uchar, - rtm_flags: libc::c_uint, -} - -impl Clone for rtmsg { - fn clone(&self) -> Self { - Self { ..*self } - } -} - -impl Default for rtmsg { - fn default() -> Self { - Self { - ..unsafe { mem::zeroed::() } - } - } -} - -// rtm_type c_uchar -pub const RTN_UNSPEC: libc::c_uchar = 0; -pub const RTN_UNICAST: libc::c_uchar = 1; -pub const RTN_LOCAL: libc::c_uchar = 2; -pub const RTN_BROADCAST: libc::c_uchar = 3; -pub const RTN_ANYCAST: libc::c_uchar = 4; -pub const RTN_MULTICAST: libc::c_uchar = 5; -pub const RTN_BLACKHOLE: libc::c_uchar = 6; -pub const RTN_UNREACHABLE: libc::c_uchar = 7; -pub const RTN_PROHIBIT: libc::c_uchar = 8; -pub const RTN_THROW: libc::c_uchar = 9; -pub const RTN_NAT: libc::c_uchar = 10; -pub const RTN_XRESOLVE: libc::c_uchar = 11; -pub const __RTN_MAX: libc::c_uchar = 12; -pub const RTN_MAX: libc::c_uchar = __RTN_MAX - 1; - -// rtm_protocol c_uchar -pub const RTPROTO_UNSPEC: libc::c_uchar = 0; -pub const RTPROTO_REDIRECT: libc::c_uchar = 1; -pub const RTPROTO_KERNEL: libc::c_uchar = 2; -pub const RTPROTO_BOOT: libc::c_uchar = 3; -pub const RTPROTO_STATIC: libc::c_uchar = 4; - -pub const RTPROTO_GATED: libc::c_uchar = 8; -pub const RTPROTO_RA: libc::c_uchar = 9; -pub const RTPROTO_MRT: libc::c_uchar = 10; -pub const RTPROTO_ZEBRA: libc::c_uchar = 11; -pub const RTPROTO_BIRD: libc::c_uchar = 12; -pub const RTPROTO_DNROUTED: libc::c_uchar = 13; -pub const RTPROTO_XORP: libc::c_uchar = 14; -pub const RTPROTO_NTK: libc::c_uchar = 15; -pub const RTPROTO_DHCP: libc::c_uchar = 16; -pub const RTPROTO_MROUTED: libc::c_uchar = 17; -pub const RTPROTO_BABEL: libc::c_uchar = 42; -pub const RTPROTO_BGP: libc::c_uchar = 186; -pub const RTPROTO_ISIS: libc::c_uchar = 187; -pub const RTPROTO_OSPF: libc::c_uchar = 188; -pub const RTPROTO_RIP: libc::c_uchar = 189; -pub const RTPROTO_EIGRP: libc::c_uchar = 192; - -//rtm_scope c_uchar -pub const RT_SCOPE_UNIVERSE: libc::c_uchar = 0; -pub const RT_SCOPE_SITE: libc::c_uchar = 200; -pub const RT_SCOPE_LINK: libc::c_uchar = 253; -pub const RT_SCOPE_HOST: libc::c_uchar = 254; -pub const RT_SCOPE_NOWHERE: libc::c_uchar = 255; - -// rtm_flags c_uint -pub const RTM_F_NOTIFY: libc::c_uint = 0x100; -pub const RTM_F_CLONED: libc::c_uint = 0x200; -pub const RTM_F_EQUALIZE: libc::c_uint = 0x400; -pub const RTM_F_PREFIX: libc::c_uint = 0x800; -pub const RTM_F_LOOKUP_TABLE: libc::c_uint = 0x1000; -pub const RTM_F_FIB_MATCH: libc::c_uint = 0x2000; - -// table identifier -pub const RT_TABLE_UNSPEC: libc::c_uint = 0; -pub const RT_TABLE_COMPAT: libc::c_uint = 252; -pub const RT_TABLE_DEFAULT: libc::c_uint = 253; -pub const RT_TABLE_MAIN: libc::c_uint = 254; -pub const RT_TABLE_LOCAL: libc::c_uint = 255; -pub const RT_TABLE_MAX: libc::c_uint = 0xffff_ffff; - -// rat_type c_ushort -pub const RTA_UNSPEC: libc::c_ushort = 0; -pub const RTA_DST: libc::c_ushort = 1; -pub const RTA_SRC: libc::c_ushort = 2; -pub const RTA_IIF: libc::c_ushort = 3; -pub const RTA_OIF: libc::c_ushort = 4; -pub const RTA_GATEWAY: libc::c_ushort = 5; -pub const RTA_PRIORITY: libc::c_ushort = 6; -pub const RTA_PREFSRC: libc::c_ushort = 7; -pub const RTA_METRICS: libc::c_ushort = 8; -pub const RTA_MULTIPATH: libc::c_ushort = 9; -pub const RTA_PROTOINFO: libc::c_ushort = 10; -pub const RTA_FLOW: libc::c_ushort = 11; -pub const RTA_CACHEINFO: libc::c_ushort = 12; -pub const RTA_SESSION: libc::c_ushort = 13; -pub const RTA_MP_ALGO: libc::c_ushort = 14; -pub const RTA_TABLE: libc::c_ushort = 15; -pub const RTA_MARK: libc::c_ushort = 16; -pub const RTA_MFC_STATS: libc::c_ushort = 17; -pub const RTA_VIA: libc::c_ushort = 18; -pub const RTA_NEWDST: libc::c_ushort = 19; -pub const RTA_PREF: libc::c_ushort = 20; -pub const RTA_ENCAP_TYPE: libc::c_ushort = 21; -pub const RTA_ENCAP: libc::c_ushort = 22; -pub const RTA_EXPIRES: libc::c_ushort = 23; -pub const RTA_PAD: libc::c_ushort = 24; -pub const RTA_UID: libc::c_ushort = 25; -pub const RTA_TTL_PROPAGATE: libc::c_ushort = 26; -pub const RTA_IP_PROTO: libc::c_ushort = 27; -pub const RTA_SPORT: libc::c_ushort = 28; -pub const RTA_DPORT: libc::c_ushort = 29; -pub const __RTA_MAX: libc::c_ushort = 30; -pub const RTA_MAX: libc::c_ushort = __RTA_MAX - 1; - -#[macro_export] -macro_rules! RTM_RTA { - ($rtm: expr) => {{ - let mut p = $rtm as *mut rtmsg as i64; - p += NLMSG_ALIGN!(mem::size_of::()) as i64; - p as *mut rtattr - }}; -} - -#[macro_export] -macro_rules! RTM_PAYLOAD { - ($h: expr) => { - NLMSG_PAYLOAD!($h, mem::size_of::()) - }; -} - -// RTA_MULTIPATH -#[repr(C)] -#[derive(Copy)] -pub struct rtnexthop { - rtnh_len: libc::c_ushort, - rtnh_flags: libc::c_uchar, - rtnh_hops: libc::c_uchar, - rtnh_ifindex: libc::c_int, -} - -impl Clone for rtnexthop { - fn clone(&self) -> Self { - Self { ..*self } - } -} - -impl Default for rtnexthop { - fn default() -> Self { - Self { - ..unsafe { mem::zeroed::() } - } - } -} - -// rtnh_flags -pub const RTNH_F_DEAD: libc::c_uchar = 1; -pub const RTNH_F_PERVASIVE: libc::c_uchar = 2; -pub const RTNH_F_ONLINK: libc::c_uchar = 4; -pub const RTNH_F_OFFLOAD: libc::c_uchar = 8; -pub const RTNH_F_LINKDOWN: libc::c_uchar = 16; -pub const RTNH_F_UNRESOLVED: libc::c_uchar = 32; - -pub const RTNH_COMPARE_MASK: libc::c_uchar = RTNH_F_DEAD | RTNH_F_LINKDOWN | RTNH_F_OFFLOAD; - -pub const RTNH_ALIGN: i32 = 4; -#[macro_export] -macro_rules! RTNH_ALIGN { - ($len: expr) => { - (($len as u32 + (RTNH_ALIGN - 1) as u32) & !(RTNH_ALIGN - 1) as u32) - }; -} - -#[macro_export] -macro_rules! RTNH_OK { - ($rtnh: expr, $len: expr) => { - $rtnh.rtnh_len >= mem::size_of::() && $rtnh.rtnh_len <= $len - }; -} - -#[macro_export] -macro_rules! RTNH_NEXT { - ($rtnh: expr) => { - unsafe { - let mut p = $rtnh as *mut rtnexthop as i64; - p += RTNH_ALIGN!($rtnh.rtnh_len); - p as *mut rtnexthop - } - }; -} - -#[macro_export] -macro_rules! RTNH_LENGTH { - ($len: expr) => { - RTNH_ALIGN!(mem::size_of::()) + $len - }; -} - -#[macro_export] -macro_rules! RTNH_SPACE { - ($len: expr) => { - RTNH_ALIGN!(RTNH_LENGTH!($len)) - }; -} - -#[macro_export] -macro_rules! RTNH_DATA { - ($rtnh: expr) => {{ - let mut p = $rtnh as *mut rtnexthop as i64; - p += RTNH_LENGTH!(0); - p as *mut rtattr - }}; -} - -// RTA_VIA -type __kernel_sa_family_t = libc::c_ushort; -#[repr(C)] -#[derive(Copy)] -pub struct rtvia { - rtvia_family: __kernel_sa_family_t, - // array with size 0. omitted here. be careful - // with how to access it. cannot use rtvia.rtvia_addr -} - -impl Clone for rtvia { - fn clone(&self) -> Self { - Self { ..*self } - } -} - -impl Default for rtvia { - fn default() -> Self { - Self { - ..unsafe { mem::zeroed::() } - } - } -} - -// rta_cacheinfo -#[repr(C)] -#[derive(Copy)] -pub struct rta_cacheinfo { - rta_clntref: __u32, - rta_lastuse: __u32, - rta_expires: __u32, - rta_error: __u32, - rta_used: __u32, - - rta_id: __u32, - rta_ts: __u32, - rta_tsage: __u32, -} - -impl Clone for rta_cacheinfo { - fn clone(&self) -> Self { - Self { ..*self } - } -} - -impl Default for rta_cacheinfo { - fn default() -> Self { - Self { - ..unsafe { mem::zeroed::() } - } - } -} - -// RTA_METRICS -pub const RTAX_UNSPEC: libc::c_ushort = 0; -pub const RTAX_LOCK: libc::c_ushort = 1; -pub const RTAX_MTU: libc::c_ushort = 2; -pub const RTAX_WINDOW: libc::c_ushort = 3; -pub const RTAX_RTT: libc::c_ushort = 4; -pub const RTAX_RTTVAR: libc::c_ushort = 5; -pub const RTAX_SSTHRESH: libc::c_ushort = 6; -pub const RTAX_CWND: libc::c_ushort = 7; -pub const RTAX_ADVMSS: libc::c_ushort = 8; -pub const RTAX_REORDERING: libc::c_ushort = 9; -pub const RTAX_HOPLIMIT: libc::c_ushort = 10; -pub const RTAX_INITCWND: libc::c_ushort = 11; -pub const RTAX_FEATURES: libc::c_ushort = 12; -pub const RTAX_RTO_MIN: libc::c_ushort = 13; -pub const RTAX_INITRWND: libc::c_ushort = 14; -pub const RTAX_QUICKACK: libc::c_ushort = 15; -pub const RTAX_CC_ALGO: libc::c_ushort = 16; -pub const RTAX_FASTOPEN_NO_COOKIE: libc::c_ushort = 17; -pub const __RTAX_MAX: libc::c_ushort = 18; - -pub const RTAX_MAX: libc::c_ushort = __RTAX_MAX - 1; -pub const RTAX_FEATURE_ECN: libc::c_ushort = 0x1; -pub const RTAX_FEATURE_SACK: libc::c_ushort = 0x2; -pub const RTAX_FEATURE_TIMESTAMP: libc::c_ushort = 0x4; -pub const RTAX_FEATURE_ALLFRAG: libc::c_ushort = 0x8; -pub const RTAX_FEATURE_MASK: libc::c_ushort = - RTAX_FEATURE_ECN | RTAX_FEATURE_SACK | RTAX_FEATURE_TIMESTAMP | RTAX_FEATURE_ALLFRAG; - -// RTA_SESSION -#[repr(C)] -#[derive(Copy)] -pub struct Ports { - sport: __u16, - dport: __u16, -} - -impl Clone for Ports { - fn clone(&self) -> Self { - Self { ..*self } - } -} - -impl Default for Ports { - fn default() -> Self { - Self { - ..unsafe { mem::zeroed::() } - } - } -} - -#[repr(C)] -#[derive(Copy)] -pub struct Icmpt { - r#type: __u8, - code: __u8, - ident: __u16, -} - -impl Clone for Icmpt { - fn clone(&self) -> Self { - Self { ..*self } - } -} - -impl Default for Icmpt { - fn default() -> Self { - Self { - ..unsafe { mem::zeroed::() } - } - } -} - -#[repr(C)] -#[derive(Copy)] -pub union U { - pub ports: Ports, - pub icmpt: Icmpt, - spi: __u32, -} - -impl Clone for U { - fn clone(&self) -> Self { - Self { - spi: unsafe { self.spi }, - } - } -} - -impl Default for U { - fn default() -> Self { - let s = unsafe { mem::zeroed::() }; - Self { - spi: unsafe { s.spi }, - } - } -} - -#[repr(C)] -#[derive(Copy)] -pub struct rta_session { - proto: __u8, - pad1: __u8, - pad2: __u16, - u: U, -} - -impl Clone for rta_session { - fn clone(&self) -> Self { - Self { ..*self } - } -} - -impl Default for rta_session { - fn default() -> Self { - Self { - ..unsafe { mem::zeroed::() } - } - } -} - -#[repr(C)] -#[derive(Copy)] -pub struct rta_mfc_stats { - mfcs_packets: __u64, - mfcs_bytes: __u64, - mfcs_wrong_if: __u64, -} - -impl Clone for rta_mfc_stats { - fn clone(&self) -> Self { - Self { ..*self } - } -} - -impl Default for rta_mfc_stats { - fn default() -> Self { - Self { - ..unsafe { mem::zeroed::() } - } - } -} - -#[repr(C)] -#[derive(Copy)] -pub struct ifinfomsg { - ifi_family: libc::c_uchar, - __ifi_pad: libc::c_uchar, - ifi_type: libc::c_ushort, - ifi_index: libc::c_int, - ifi_flags: libc::c_uint, - ifi_change: libc::c_uint, -} - -impl Clone for ifinfomsg { - fn clone(&self) -> Self { - Self { ..*self } - } -} - -impl Default for ifinfomsg { - fn default() -> Self { - Self { - ..unsafe { mem::zeroed::() } - } - } -} - -#[repr(C)] -#[derive(Copy)] -pub struct rtnl_link_stats64 { - rx_packets: __u64, - tx_packets: __u64, - rx_bytes: __u64, - tx_bytes: __u64, - rx_errors: __u64, - tx_errors: __u64, - rx_dropped: __u64, - tx_dropped: __u64, - multicast: __u64, - collisions: __u64, - - // detailed rx_errors - rx_length_errors: __u64, - rx_over_errors: __u64, - rx_crc_errors: __u64, - rx_frame_errrors: __u64, - rx_fifo_errors: __u64, - rx_missed_errors: __u64, - - // detailed tx_errors - tx_aborted_errors: __u64, - tx_carrier_errors: __u64, - tx_fifo_errors: __u64, - tx_heartbeat_errors: __u64, - tx_window_errors: __u64, - - rx_compressed: __u64, - tx_compressed: __u64, - rx_nohandler: __u64, -} - -impl Clone for rtnl_link_stats64 { - fn clone(&self) -> Self { - Self { ..*self } - } -} - -impl Default for rtnl_link_stats64 { - fn default() -> Self { - Self { - ..unsafe { mem::zeroed::() } - } - } -} - -#[repr(C)] -#[derive(Copy)] -pub struct rtnl_link_stats { - rx_packets: __u32, - tx_packets: __u32, - rx_bytes: __u32, - tx_bytes: __u32, - rx_errors: __u32, - tx_errors: __u32, - rx_dropped: __u32, - tx_dropped: __u32, - multicast: __u32, - collisions: __u32, - - // detailed rx_errors - rx_length_errors: __u32, - rx_over_errors: __u32, - rx_crc_errors: __u32, - rx_frame_errrors: __u32, - rx_fifo_errors: __u32, - rx_missed_errors: __u32, - - // detailed tx_errors - tx_aborted_errors: __u32, - tx_carrier_errors: __u32, - tx_fifo_errors: __u32, - tx_heartbeat_errors: __u32, - tx_window_errors: __u32, - - rx_compressed: __u32, - tx_compressed: __u32, - rx_nohandler: __u32, -} - -impl Clone for rtnl_link_stats { - fn clone(&self) -> Self { - Self { ..*self } - } -} - -impl Default for rtnl_link_stats { - fn default() -> Self { - Self { - ..unsafe { mem::zeroed::() } - } - } -} - -#[repr(C)] -#[derive(Copy)] -pub struct ifaddrmsg { - ifa_family: __u8, - ifa_prefixlen: __u8, - ifa_flags: __u8, - ifa_scope: __u8, - ifa_index: __u32, -} - -impl Clone for ifaddrmsg { - fn clone(&self) -> Self { - Self { ..*self } - } -} - -impl Default for ifaddrmsg { - fn default() -> Self { - Self { - ..unsafe { mem::zeroed::() } - } - } -} - -#[repr(C)] -#[derive(Copy)] -pub struct ifa_cacheinfo { - ifa_prefered: __u32, - ifa_valid: __u32, - cstamp: __u32, - tstamp: __u32, -} - -impl Clone for ifa_cacheinfo { - fn clone(&self) -> Self { - Self { ..*self } - } -} - -impl Default for ifa_cacheinfo { - fn default() -> Self { - Self { - ..unsafe { mem::zeroed::() } - } - } -} - -pub const RTA_ALIGNTO: libc::c_uint = 4; -#[macro_export] -macro_rules! RTA_ALIGN { - ($x: expr) => { - ($x as u32 + (RTA_ALIGNTO - 1) as u32) & !((RTA_ALIGNTO - 1) as u32) - }; -} - -#[macro_export] -macro_rules! RTA_OK { - ($attr: expr, $len: expr) => { - ($len as u32 >= mem::size_of::() as u32) - && ((*$attr).rta_len as u32 >= mem::size_of::() as u32) - && ((*$attr).rta_len as u32 <= $len as u32) - }; -} - -#[macro_export] -macro_rules! RTA_NEXT { - ($attr: expr, $len: expr) => {{ - $len -= RTA_ALIGN!((*$attr).rta_len) as u32; - let mut p = $attr as *mut libc::c_char as i64; - p += RTA_ALIGN!((*$attr).rta_len) as i64; - p as *mut rtattr - }}; -} - -#[macro_export] -macro_rules! RTA_LENGTH { - ($len: expr) => { - RTA_ALIGN!($len as u32 + mem::size_of::() as u32) - }; -} - -#[macro_export] -macro_rules! RTA_SPACE { - ($len: expr) => { - RTA_ALIGN!(RTA_LENGTH!($len)) - }; -} - -#[macro_export] -macro_rules! RTA_DATA { - ($attr: expr) => {{ - let mut p = $attr as *mut libc::c_char as i64; - p += RTA_LENGTH!(0) as i64; - p as *mut libc::c_char - }}; -} - -#[macro_export] -macro_rules! RTA_PAYLOAD { - ($attr: expr) => { - ((*$attr).rta_len as u32 - RTA_LENGTH!(0) as u32) - }; -} - -pub const NLMSGERR_ATTR_UNUSED: libc::c_uchar = 0; -pub const NLMSGERR_ATTR_MASG: libc::c_uchar = 1; -pub const NLMSGERR_ATTR_OFFS: libc::c_uchar = 2; -pub const NLMSGERR_ATTR_COOKIE: libc::c_uchar = 3; -pub const __NLMSGERR_ATTR_MAX: libc::c_uchar = 4; -pub const NLMSGERR_ATTR_MAX: libc::c_uchar = __NLMSGERR_ATTR_MAX - 1; - -pub const NLMSG_ALIGNTO: libc::c_uint = 4; -#[macro_export] -macro_rules! NLMSG_ALIGN { - ($len: expr) => { - ($len as u32 + NLMSG_ALIGNTO - 1) & !(NLMSG_ALIGNTO - 1) - }; -} - -// weird, static link cannot find libc::nlmsghdr -// define macro here ro work around it for now -// till someone can find out the reason -// pub const NLMSG_HDRLEN: libc::c_int = NLMSG_ALIGN!(mem::size_of::() as libc::c_uint) as libc::c_int; - -#[macro_export] -macro_rules! NLMSG_HDRLEN { - () => { - NLMSG_ALIGN!(mem::size_of::()) - }; -} - -#[macro_export] -macro_rules! NLMSG_LENGTH { - ($len: expr) => { - ($len as u32 + NLMSG_HDRLEN!()) - }; -} - -#[macro_export] -macro_rules! NLMSG_SPACE { - ($len: expr) => { - NLMSG_ALIGN!(NLMSG_LENGTH!($len)) - }; -} - -#[macro_export] -macro_rules! NLMSG_DATA { - ($nlh: expr) => {{ - let mut p = $nlh as *const nlmsghdr as i64; - p += NLMSG_LENGTH!(0) as i64; - p as *mut libc::c_void - }}; -} - -#[macro_export] -macro_rules! NLMSG_NEXT { - ($nlh: expr, $len: expr) => {{ - $len -= NLMSG_ALIGN!($nlh.nlmsg_len) as u32; - let mut p = $nlh as *const nlmsghdr as *mut libc::c_char; - p = (p as i64 + NLMSG_ALIGN!($nlh.nlmsg_len) as i64) as *mut libc::c_char; - unsafe { &mut *(p as *mut nlmsghdr) } - }}; -} - -#[macro_export] -macro_rules! NLMSG_OK { - ($nlh: expr, $len: expr) => { - $len as usize >= mem::size_of::() - && (*$nlh).nlmsg_len as usize >= mem::size_of::() - && (*$nlh).nlmsg_len as usize <= $len as usize - }; -} - -#[macro_export] -macro_rules! NLMSG_PAYLOAD { - ($nlh: expr, $len: expr) => { - ((*$nlh).nlmsg_len - NLMSG_SPACE!($len)) - }; -} - -#[macro_export] -macro_rules! RTA_TAIL { - ($attr: expr) => { - unsafe { - let mut p = $attr as *mut rtattr as i64; - p += RTA_ALIGN!($attr->rta_len) as i64; - p as *mut rtattr - } - } -} - -#[macro_export] -macro_rules! NLMSG_TAIL { - ($msg: expr) => {{ - let mut p = $msg as *mut nlmsghdr as i64; - p += NLMSG_ALIGN!((*$msg).nlmsg_len) as i64; - p as *mut rtattr - }}; -} - -#[macro_export] -macro_rules! IFA_RTA { - ($ifmsg: expr) => {{ - let mut p = $ifmsg as *const ifaddrmsg as *const libc::c_char; - p = (p as i64 + NLMSG_ALIGN!(mem::size_of::()) as i64) as *mut libc::c_char; - p as *const rtattr - }}; -} - -#[macro_export] -macro_rules! IFA_PAYLOAD { - ($h: expr) => { - NLMSG_PAYLOAD!($h, mem::size_of::()) - }; -} - -#[macro_export] -macro_rules! IFLA_RTA { - ($ifinfo: expr) => {{ - let mut p = $ifinfo as *mut ifinfomsg as i64; - p += NLMSG_ALIGN!(mem::size_of::()) as i64; - p as *mut rtattr - }}; -} - -#[macro_export] -macro_rules! IFLA_PAYLOAD { - ($h: expr) => { - (NLMSG_PAYLOAD!($h, mem::size_of::())) - }; -} - -#[macro_export] -macro_rules! IFLA_STATS_RTA { - ($stats: expr) => {{ - let mut p = $stats as *mut if_stats_msg as i64; - p += NLMSG_ALIGN!(mem::size_of::()) as i64; - p as *mut rtattr - }}; -} - -#[repr(C)] -#[derive(Copy)] -pub struct nlmsghdr { - pub nlmsg_len: __u32, - pub nlmsg_type: __u16, - pub nlmsg_flags: __u16, - pub nlmsg_seq: __u32, - pub nlmsg_pid: __u32, -} - -impl Clone for nlmsghdr { - fn clone(&self) -> Self { - Self { ..*self } - } -} - -impl Default for nlmsghdr { - fn default() -> Self { - unsafe { mem::zeroed::() } - } -} - -impl Borrow for Vec { - fn borrow(&self) -> &nlmsghdr { - let ptr = self.as_ptr(); - assert_eq!(ptr.align_offset(std::mem::align_of::()), 0); - unsafe { &*(ptr as *const nlmsghdr) } - } -} - -// nlmsg_flags -pub const NLM_F_REQUEST: __u16 = 0x01; -pub const NLM_F_MULTI: __u16 = 0x02; -pub const NLM_F_ACK: __u16 = 0x04; -pub const NLM_F_ECHO: __u16 = 0x08; -pub const NLM_F_DUMP_INTR: __u16 = 0x10; -pub const NLM_F_DUMP_FILTERED: __u16 = 0x20; - -// Get Request -pub const NLM_F_ROOT: __u16 = 0x100; -pub const NLM_F_MATCH: __u16 = 0x200; -pub const NLM_F_ATOMIC: __u16 = 0x400; -pub const NLM_F_DUMP: __u16 = NLM_F_ROOT | NLM_F_MATCH; - -// New Request -pub const NLM_F_REPLACE: __u16 = 0x100; -pub const NLM_F_EXCL: __u16 = 0x200; -pub const NLM_F_CREATE: __u16 = 0x400; -pub const NLM_F_APPEND: __u16 = 0x800; - -// Delete Request -pub const NLM_F_NONREC: __u16 = 0x100; - -//ACK message -pub const NLM_F_CAPPED: __u16 = 0x100; -pub const NLM_F_ACK_TLVS: __u16 = 0x200; - -// error message type -pub const NLMSG_NOOP: __u16 = 0x1; -pub const NLMSG_ERROR: __u16 = 0x2; -pub const NLMSG_DONE: __u16 = 0x3; -pub const NLMSG_OVERRUN: __u16 = 0x4; - -pub const NLMSG_MIN_TYPE: __u16 = 0x10; - -// IFLA_EXT_MASK -pub const RTEXT_FILTER_VF: __u32 = 0x1; -pub const RTEXT_FILTER_BRVLAN: __u32 = 0x2; -pub const RTEXT_FILTER_BRVLAN_COMPRESSED: __u32 = 0x4; -pub const RTEXT_FILTER_SKIP_STATS: __u32 = 0x8; - -// IFLA attr -pub const IFLA_UNSPEC: __u16 = 0; -pub const IFLA_ADDRESS: __u16 = 1; -pub const IFLA_BROADCAST: __u16 = 2; -pub const IFLA_IFNAME: __u16 = 3; -pub const IFLA_MTU: __u16 = 4; -pub const IFLA_LINK: __u16 = 5; -pub const IFLA_QDISC: __u16 = 6; -pub const IFLA_STATS: __u16 = 7; -pub const IFLA_COST: __u16 = 8; -pub const IFLA_PRIORITY: __u16 = 9; -pub const IFLA_MASTER: __u16 = 10; -pub const IFLA_WIRELESS: __u16 = 11; -pub const IFLA_PROTINFO: __u16 = 12; -pub const IFLA_TXQLEN: __u16 = 13; -pub const IFLA_MAP: __u16 = 14; -pub const IFLA_WEIGHT: __u16 = 15; -pub const IFLA_OPERSTATE: __u16 = 16; -pub const IFLA_LINKMODE: __u16 = 17; -pub const IFLA_LINKINFO: __u16 = 18; -pub const IFLA_NET_NS_PID: __u16 = 19; -pub const IFLA_IFALIAS: __u16 = 20; -pub const IFLA_NUM_VF: __u16 = 21; -pub const IFLA_VFINFO_LIST: __u16 = 22; -pub const IFLA_STATS64: __u16 = 23; -pub const IFLA_VF_PORTS: __u16 = 24; -pub const IFLA_PORT_SELF: __u16 = 25; -pub const IFLA_AF_SPEC: __u16 = 26; -pub const IFLA_GROUP: __u16 = 27; -pub const IFLA_NET_NS_FD: __u16 = 28; -pub const IFLA_EXT_MASK: __u16 = 29; -pub const IFLA_PROMISCUITY: __u16 = 30; -pub const IFLA_NUM_TX_QUEUES: __u16 = 31; -pub const IFLA_NUM_RX_QUEUES: __u16 = 32; -pub const IFLA_CARRIER: __u16 = 33; -pub const IFLA_PHYS_PORT_ID: __u16 = 34; -pub const IFLA_CARRIER_CHANGES: __u16 = 35; -pub const IFLA_PHYS_SWITCH_ID: __u16 = 36; -pub const IFLA_LINK_NETNSID: __u16 = 37; -pub const IFLA_PHYS_PORT_NAME: __u16 = 38; -pub const IFLA_PROTO_DOWN: __u16 = 39; -pub const IFLA_GSO_MAX_SEGS: __u16 = 40; -pub const IFLA_GSO_MAX_SIZE: __u16 = 41; -pub const IFLA_PAD: __u16 = 42; -pub const IFLA_XDP: __u16 = 43; -pub const IFLA_EVENT: __u16 = 44; -pub const IFLA_NEW_NETNSID: __u16 = 45; -pub const IFLA_IF_NETNSID: __u16 = 46; -pub const IFLA_CARRIER_UP_COUNT: __u16 = 47; -pub const IFLA_CARRIER_DOWN_COUNT: __u16 = 48; -pub const IFLA_NEW_IFINDEX: __u16 = 49; -pub const IFLA_MIN_MTU: __u16 = 50; -pub const IFLA_MAX_MTU: __u16 = 51; -pub const __IFLA_MAX: __u16 = 52; -pub const IFLA_MAX: __u16 = __IFLA_MAX - 1; - -pub const IFA_UNSPEC: __u16 = 0; -pub const IFA_ADDRESS: __u16 = 1; -pub const IFA_LOCAL: __u16 = 2; -pub const IFA_LABEL: __u16 = 3; -pub const IFA_BROADCAST: __u16 = 4; -pub const IFA_ANYCAST: __u16 = 5; -pub const IFA_CACHEINFO: __u16 = 6; -pub const IFA_MULTICAST: __u16 = 7; -pub const IFA_FLAGS: __u16 = 8; -pub const IFA_RT_PRIORITY: __u16 = 9; -pub const __IFA_MAX: __u16 = 10; -pub const IFA_MAX: __u16 = __IFA_MAX - 1; - -// ifa_flags -pub const IFA_F_SECONDARY: __u32 = 0x01; -pub const IFA_F_TEMPORARY: __u32 = IFA_F_SECONDARY; -pub const IFA_F_NODAD: __u32 = 0x02; -pub const IFA_F_OPTIMISTIC: __u32 = 0x04; -pub const IFA_F_DADFAILED: __u32 = 0x08; -pub const IFA_F_HOMEADDRESS: __u32 = 0x10; -pub const IFA_F_DEPRECATED: __u32 = 0x20; -pub const IFA_F_TENTATIVE: __u32 = 0x40; -pub const IFA_F_PERMANENT: __u32 = 0x80; -pub const IFA_F_MANAGETEMPADDR: __u32 = 0x100; -pub const IFA_F_NOPREFIXROUTE: __u32 = 0x200; -pub const IFA_F_MCAUTOJOIN: __u32 = 0x400; -pub const IFA_F_STABLE_PRIVACY: __u32 = 0x800; - -#[repr(C)] -#[derive(Copy)] -pub struct ndmsg { - ndm_family: __u8, - ndm_pad1: __u8, - ndm_pad: __u16, - ndm_ifindex: __s32, - ndm_state: __u16, - ndm_flags: __u8, - ndm_type: __u8, -} - -pub const NDA_UNSPEC: __u16 = 0; -pub const NDA_DST: __u16 = 1; -pub const NDA_LLADDR: __u16 = 2; -pub const NDA_CACHEINFO: __u16 = 3; -pub const NDA_PROBES: __u16 = 4; -pub const NDA_VLAN: __u16 = 5; -pub const NDA_PORT: __u16 = 6; -pub const NDA_VNI: __u16 = 7; -pub const NDA_IFINDEX: __u16 = 8; -pub const NDA_MASTER: __u16 = 9; -pub const NDA_LINK_NETNSID: __u16 = 10; -pub const NDA_SRC_VNI: __u16 = 11; -pub const __NDA_MAX: __u16 = 12; - -impl Clone for ndmsg { - fn clone(&self) -> Self { - Self { ..*self } - } -} - -impl Default for ndmsg { - fn default() -> Self { - unsafe { mem::zeroed::() } - } -} - -#[repr(C)] -#[derive(Copy)] -pub struct nlmsgerr { - pub error: libc::c_int, - pub msg: nlmsghdr, -} - -impl Clone for nlmsgerr { - fn clone(&self) -> Self { - Self { ..*self } - } -} - -impl Default for nlmsgerr { - fn default() -> Self { - unsafe { mem::zeroed::() } - } -} - -pub const NETLINK_ROUTE: libc::c_int = 0; -pub const NETLINK_EXT_ACK: libc::c_int = 11; -pub const NETLINK_UEVENT: libc::c_int = 15; - -pub struct RtRoute { - pub dest: Option>, - pub source: Option>, - pub gateway: Option>, - pub index: i32, - pub scope: u8, - pub dst_len: u8, - pub src_len: u8, - pub protocol: u8, -} - -impl Default for RtRoute { - fn default() -> Self { - unsafe { mem::zeroed::() } - } -} - -pub struct RtIPAddr { - pub ip_family: __u8, - pub ip_mask: __u8, - pub addr: Vec, -} - -/// Handle to access the Linux Netlink subsystem. -// #[derive(Copy)] -pub struct RtnlHandle { - pub fd: RawFd, - local: libc::sockaddr_nl, - seq: __u32, - dump: __u32, -} - -impl Clone for RtnlHandle { - fn clone(&self) -> Self { - Self { ..*self } - } -} - -impl Default for RtnlHandle { - fn default() -> Self { - Self { - ..unsafe { mem::zeroed::() } - } - } -} - -impl fmt::Debug for RtnlHandle { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!( - f, - "fd: {}\nadrr:{{pid: {}, family: {}}}\nseq:{}\ndump:{}", - self.fd, self.local.nl_family, self.local.nl_pid, self.seq, self.dump - ) - } -} - -impl RtnlHandle { - pub fn new(protocal: libc::c_int, group: u32) -> Result { - // open netlink_route socket - let mut sa: libc::sockaddr_nl = unsafe { mem::zeroed::() }; - let fd = unsafe { - let tmpfd = libc::socket( - libc::AF_NETLINK, - libc::SOCK_DGRAM | libc::SOCK_CLOEXEC, - protocal, - ); - - let sndbuf: libc::c_int = 32768; - let rcvbuf: libc::c_int = 1024 * 1024; - let one: libc::c_int = 1; - let mut addrlen: libc::socklen_t = - mem::size_of::() as libc::socklen_t; - - if tmpfd < 0 { - return nix_last_os_err(); - } - - let mut err = libc::setsockopt( - tmpfd, - libc::SOL_SOCKET, - libc::SO_SNDBUF, - &sndbuf as *const libc::c_int as *const libc::c_void, - mem::size_of::() as libc::socklen_t, - ); - - if err < 0 { - libc::close(tmpfd); - return nix_last_os_err(); - } - - err = libc::setsockopt( - tmpfd, - libc::SOL_SOCKET, - libc::SO_RCVBUF, - &rcvbuf as *const libc::c_int as *const libc::c_void, - mem::size_of::() as libc::socklen_t, - ); - - if err < 0 { - libc::close(tmpfd); - return nix_last_os_err(); - } - - libc::setsockopt( - tmpfd, - libc::SOL_NETLINK, - NETLINK_EXT_ACK, - &one as *const libc::c_int as *const libc::c_void, - mem::size_of::() as libc::socklen_t, - ); - - sa.nl_family = libc::AF_NETLINK as __u16; - sa.nl_groups = group; - - err = libc::bind( - tmpfd, - (&sa as *const libc::sockaddr_nl) as *const libc::sockaddr, - mem::size_of::() as libc::socklen_t, - ); - if err < 0 { - libc::close(tmpfd); - return nix_last_os_err(); - } - - err = libc::getsockname( - tmpfd, - &mut sa as *mut libc::sockaddr_nl as *mut libc::sockaddr, - &mut addrlen as *mut libc::socklen_t, - ); - if err < 0 { - libc::close(tmpfd); - return nix_last_os_err(); - } - - if sa.nl_family as i32 != libc::AF_NETLINK - || addrlen as usize != mem::size_of::() - { - libc::close(tmpfd); - return nix_errno(Errno::EINVAL); - } - - tmpfd - }; - - Ok(Self { - fd, - local: sa, - seq: unsafe { libc::time(std::ptr::null_mut::()) } as __u32, - dump: 0, - }) - } - - pub fn rtnl_talk(&mut self, data: &mut [u8], answer: bool) -> Result> { - if data.len() < std::mem::size_of::() { - return nix_errno(Errno::EINVAL); - } - // Safe because we have just validated buffer size above. - let nlh = unsafe { &mut *(data.as_mut_ptr() as *mut nlmsghdr) }; - if !answer { - nlh.nlmsg_flags |= NLM_F_ACK; - } - self.send_message(data)?; - - loop { - let buf = self.recv_message()?; - let mut msglen = buf.len() as u32; - if (msglen as usize) < std::mem::size_of::() { - return nix_errno(Errno::EBADMSG); - } - // Safe because we have just validated buffer size above. - let mut nlh = unsafe { &*(buf.as_ptr() as *const nlmsghdr) }; - - while NLMSG_OK!(nlh, msglen) { - if nlh.nlmsg_pid != self.local.nl_pid { - nlh = NLMSG_NEXT!(nlh, msglen); - continue; - } - - if nlh.nlmsg_type == NLMSG_ERROR { - if nlh.nlmsg_len < NLMSG_LENGTH!(mem::size_of::()) { - // truncated - return nix_errno(Errno::EBADMSG); - } - - // Safe because we have just validated buffer size above. - let el = unsafe { &*(NLMSG_DATA!(nlh) as *const nlmsgerr) }; - - // this is ack. -_- - if el.error == 0 { - return Ok(Vec::new()); - } - - return nix_errno(Errno::from_i32(-el.error)); - } - - // good message - let mut result = Vec::new(); - if answer { - // need to copy out data - result.resize(nlh.nlmsg_len as usize, 0); - let dp: *mut libc::c_void = result.as_mut_ptr() as *mut libc::c_void; - // Safe because the source and destination buffers are valid. - unsafe { - libc::memcpy( - dp, - nlh as *const nlmsghdr as *const libc::c_void, - nlh.nlmsg_len as libc::size_t, - ) - }; - }; - - return Ok(result); - } - - if !(NLMSG_OK!(nlh, msglen)) { - return nix_errno(Errno::EINVAL); - } - } - } - - pub fn send_message(&self, data: &mut [u8]) -> Result<()> { - if data.len() < std::mem::size_of::() { - return nix_errno(Errno::EINVAL); - } - - let mut sa: libc::sockaddr_nl = unsafe { mem::zeroed::() }; - let mut h = unsafe { mem::zeroed::() }; - - // Safe because we have validated the data buffer size is bigger then nlmsghdr. - let nh = unsafe { &mut *(data.as_mut_ptr() as *mut nlmsghdr) }; - if nh.nlmsg_len as usize > data.len() { - return nix_errno(Errno::EINVAL); - } - let mut iov: libc::iovec = libc::iovec { - iov_base: nh as *mut nlmsghdr as *mut libc::c_void, - iov_len: nh.nlmsg_len as libc::size_t, - }; - - h.msg_name = &mut sa as *mut libc::sockaddr_nl as *mut libc::c_void; - h.msg_namelen = mem::size_of::() as libc::socklen_t; - h.msg_iov = &mut iov as *mut libc::iovec; - h.msg_iovlen = 1; - - sa.nl_family = libc::AF_NETLINK as u16; - - let err = unsafe { libc::sendmsg(self.fd, &h as *const libc::msghdr, 0) }; - if err < 0 { - return nix_last_os_err(); - } - - Ok(()) - } - - pub fn recv_message(&self) -> Result> { - let mut sa: libc::sockaddr_nl = unsafe { mem::zeroed::() }; - let mut h = unsafe { mem::zeroed::() }; - let mut iov = libc::iovec { - iov_base: std::ptr::null_mut::(), - iov_len: 0 as libc::size_t, - }; - - h.msg_name = &mut sa as *mut libc::sockaddr_nl as *mut libc::c_void; - h.msg_namelen = mem::size_of::() as libc::socklen_t; - h.msg_iov = &mut iov as *mut libc::iovec; - h.msg_iovlen = 1; - - let mut rlen = unsafe { - libc::recvmsg( - self.fd, - &mut h as *mut libc::msghdr, - libc::MSG_PEEK | libc::MSG_TRUNC, - ) - }; - - if rlen < 0 { - return nix_last_os_err(); - } - - let mut v: Vec = vec![0; rlen as usize]; - iov.iov_base = v.as_mut_ptr() as *mut libc::c_void; - iov.iov_len = rlen as libc::size_t; - - rlen = unsafe { libc::recvmsg(self.fd, &mut h as *mut libc::msghdr, 0) }; - if rlen < 0 { - return nix_last_os_err(); - } - - if sa.nl_pid != 0 { - // not our netlink message - return nix_errno(Errno::EBADMSG); - } - - if h.msg_flags & libc::MSG_TRUNC != 0 { - return nix_errno(Errno::EBADMSG); - } - - v.resize(rlen as usize, 0); - - Ok(v) - } - - fn recv_dump_message(&self) -> Result<(Vec>, Vec<*const nlmsghdr>)> { - let mut slv: Vec> = Vec::new(); - let mut lv: Vec<*const nlmsghdr> = Vec::new(); - - loop { - let buf = self.recv_message()?; - - let mut msglen = buf.len() as u32; - let mut nlh: &nlmsghdr = buf.borrow(); - let mut dump_intr = false; - let mut done = false; - - while NLMSG_OK!(nlh, msglen) { - // Make sure we are interested in the message first. - if nlh.nlmsg_pid != self.local.nl_pid || nlh.nlmsg_seq != self.dump { - nlh = NLMSG_NEXT!(nlh, msglen); - continue; - } - - if nlh.nlmsg_flags & NLM_F_DUMP_INTR > 0 { - dump_intr = true; - } - - if nlh.nlmsg_type == NLMSG_DONE { - done = true; - } - - if nlh.nlmsg_type == NLMSG_ERROR { - // error message, better to return error code in error messages - if nlh.nlmsg_len < NLMSG_LENGTH!(mem::size_of::()) { - // truncated - return nix_errno(Errno::EBADMSG); - } - - // Safe because we have validated buffer size. - let el = unsafe { &*(NLMSG_DATA!(nlh) as *const nlmsgerr) }; - return nix_errno(Errno::from_i32(-el.error)); - } - - lv.push(nlh); - - if done { - break; - } - - nlh = NLMSG_NEXT!(nlh, msglen); - } - - slv.push(buf); - - if done { - if dump_intr { - info!(sl!(), "dump interrupted, maybe incomplete"); - } - - break; - } - - // still remain some bytes? - if msglen != 0 { - return nix_errno(Errno::EINVAL); - } - } - - Ok((slv, lv)) - } - - fn dump_all_links(&mut self) -> Result<(Vec>, Vec<*const nlmsghdr>)> { - let mut v: Vec = vec![0; DEFAULT_NETLINK_BUF_SIZE]; - // Safe because we have allocated enough buffer space. - let nlh = unsafe { &mut *(v.as_mut_ptr() as *mut nlmsghdr) }; - let ifi = unsafe { &mut *(NLMSG_DATA!(nlh) as *mut ifinfomsg) }; - - nlh.nlmsg_len = NLMSG_LENGTH!(mem::size_of::() as i32) as __u32; - nlh.nlmsg_type = RTM_GETLINK; - nlh.nlmsg_flags = (NLM_F_DUMP | NLM_F_REQUEST) as __u16; - self.assign_seqnum(nlh); - - ifi.ifi_family = libc::AF_UNSPEC as u8; - - // Safe because we have allocated enough buffer space. - unsafe { - nlh.addattr32(IFLA_EXT_MASK, RTEXT_FILTER_VF); - } - - self.send_message(v.as_mut_slice())?; - self.recv_dump_message() - } - - fn dump_all_addresses( - &mut self, - ifindex: __u32, - ) -> Result<(Vec>, Vec<*const nlmsghdr>)> { - let mut v: Vec = vec![0; 2048]; - // Safe because we have allocated enough buffer space. - let nlh = unsafe { &mut *(v.as_mut_ptr() as *mut nlmsghdr) }; - let ifa = unsafe { &mut *(NLMSG_DATA!(nlh) as *mut ifaddrmsg) }; - - nlh.nlmsg_len = NLMSG_LENGTH!(mem::size_of::()); - nlh.nlmsg_type = RTM_GETADDR; - nlh.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST; - self.assign_seqnum(nlh); - - ifa.ifa_family = libc::AF_UNSPEC as u8; - ifa.ifa_index = ifindex; - - self.send_message(v.as_mut_slice())?; - - self.recv_dump_message() - } - - fn dump_all_routes(&mut self) -> Result<(Vec>, Vec<*const nlmsghdr>)> { - let mut v: Vec = vec![0; 2048]; - // Safe because we have allocated enough buffer space. - let nlh = unsafe { &mut *(v.as_mut_ptr() as *mut nlmsghdr) }; - let rtm = unsafe { &mut *(NLMSG_DATA!(nlh) as *mut rtmsg) }; - - nlh.nlmsg_len = NLMSG_LENGTH!(mem::size_of::()) as u32; - nlh.nlmsg_type = RTM_GETROUTE; - nlh.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP; - self.assign_seqnum(nlh); - - rtm.rtm_family = libc::AF_INET as u8; - rtm.rtm_table = RT_TABLE_MAIN as u8; - - // Safe because we have allocated enough buffer space. - unsafe { - nlh.addattr32(RTA_TABLE, RT_TABLE_MAIN); - } - - self.send_message(v.as_mut_slice())?; - - self.recv_dump_message() - } - - pub fn find_link_by_hwaddr(&mut self, hwaddr: &str) -> Result { - let hw = parser::parse_mac_addr(hwaddr)?; - let (_slv, lv) = self.dump_all_links()?; - - for link in &lv { - // Safe because dump_all_links() return valid pointers. - let nlh = unsafe { &**link }; - if nlh.nlmsg_type != RTM_NEWLINK && nlh.nlmsg_type != RTM_DELLINK { - continue; - } - - if nlh.nlmsg_len < NLMSG_SPACE!(mem::size_of::()) { - info!( - sl!(), - "invalid nlmsg! nlmsg_len: {}, nlmsg_space: {}", - nlh.nlmsg_len, - NLMSG_SPACE!(mem::size_of::()) - ); - break; - } - - let ifi: *const ifinfomsg = NLMSG_DATA!(nlh) as *const ifinfomsg; - let rta: *mut rtattr = IFLA_RTA!(ifi) as *mut rtattr; - let rtalen = IFLA_PAYLOAD!(nlh) as u32; - // Safe because IFLA_RTA and IFLA_PAYLOAD have validated the buffer. - unsafe { - let attrs = parse_attrs(rta, rtalen, (IFLA_MAX + 1) as usize)?; - - // find the target ifinfomsg - if !attrs[IFLA_ADDRESS as usize].is_null() { - let p = hw.as_ptr() as *const u8 as *const libc::c_void; - let a = RTA_DATA!(attrs[IFLA_ADDRESS as usize]) as *const libc::c_void; - let sz = RTA_PAYLOAD!(attrs[IFLA_ADDRESS as usize]) as libc::size_t; - if libc::memcmp(p, a, sz) == 0 { - return Ok(ifinfomsg { ..*ifi }); - } - } - } - } - - nix_errno(Errno::ENODEV) - } - - pub fn find_link_by_name(&mut self, name: &str) -> Result { - let mut v: Vec = vec![0; DEFAULT_NETLINK_BUF_SIZE]; - // Safe because we have allocated enough buffer size. - let nlh = unsafe { &mut *(v.as_mut_ptr() as *mut nlmsghdr) }; - let ifi = unsafe { &mut *(NLMSG_DATA!(nlh) as *mut ifinfomsg) }; - - nlh.nlmsg_len = NLMSG_LENGTH!(mem::size_of::()) as __u32; - nlh.nlmsg_type = RTM_GETLINK; - nlh.nlmsg_flags = NLM_F_REQUEST; - self.assign_seqnum(nlh); - - ifi.ifi_family = libc::AF_UNSPEC as u8; - - // Safe because the data buffer should be big enough. - unsafe { - if let Ok(cname) = CString::new(name.as_bytes()) { - nlh.addattr_var(IFLA_IFNAME, cname.as_bytes()); - } else { - return nix_errno(Errno::EINVAL); - } - nlh.addattr32(IFLA_EXT_MASK, RTEXT_FILTER_VF | RTEXT_FILTER_SKIP_STATS); - } - - let ret_val = self.rtnl_talk(v.as_mut_slice(), true)?; - if ret_val.len() < std::mem::size_of::() { - return nix_errno(Errno::EBADMSG); - } - // Safe because we have just validated the returned buffer size. - let nlh = unsafe { &*(ret_val.as_ptr() as *const nlmsghdr) }; - if nlh.nlmsg_len < NLMSG_LENGTH!(mem::size_of::()) { - return nix_errno(Errno::EBADMSG); - } - // Safe because we have just validated the returned buffer size. - let ifi = unsafe { &*(NLMSG_DATA!(nlh) as *const ifinfomsg) }; - - Ok(ifinfomsg { ..*ifi }) - } - - pub fn set_link_status(&mut self, ifinfo: &ifinfomsg, up: bool) -> Result<()> { - let mut v: Vec = vec![0; DEFAULT_NETLINK_BUF_SIZE]; - // Safe because we have allocated a big enough data buffer. - let nlh = unsafe { &mut *(v.as_mut_ptr() as *mut u8 as *mut nlmsghdr) }; - let ifi = unsafe { &mut *(NLMSG_DATA!(nlh) as *mut ifinfomsg) }; - - nlh.nlmsg_len = NLMSG_LENGTH!(mem::size_of::() as u32) as __u32; - nlh.nlmsg_type = RTM_NEWLINK; - nlh.nlmsg_flags = NLM_F_REQUEST; - self.assign_seqnum(nlh); - - ifi.ifi_family = ifinfo.ifi_family; - ifi.ifi_type = ifinfo.ifi_type; - ifi.ifi_index = ifinfo.ifi_index; - ifi.ifi_change |= libc::IFF_UP as u32; - if up { - ifi.ifi_flags |= libc::IFF_UP as u32; - } else { - ifi.ifi_flags &= !libc::IFF_UP as u32; - } - - self.rtnl_talk(v.as_mut_slice(), false).map(|_| ()) - } - - pub fn get_link_addresses(&mut self, ifinfo: &ifinfomsg) -> Result> { - let mut addrs: Vec = Vec::new(); - let (_sav, av) = self.dump_all_addresses(ifinfo.ifi_index as __u32)?; - - for a in &av { - // Safe because dump_all_addresses returns valid pointers. - let nlh = unsafe { &**a }; - if nlh.nlmsg_type != RTM_NEWADDR { - continue; - } - - let tlen = NLMSG_SPACE!(mem::size_of::()); - if nlh.nlmsg_len < tlen { - info!( - sl!(), - "invalid nlmsg! nlmsg_len: {}, nlmsg_space: {}", nlh.nlmsg_len, tlen - ); - break; - } - - // Safe because we have just validate the buffer size above. - let ifa = unsafe { &*(NLMSG_DATA!(nlh) as *const ifaddrmsg) }; - if ifa.ifa_flags as u32 & IFA_F_SECONDARY != 0 { - continue; - } - - let rta: *const rtattr = IFA_RTA!(ifa) as *mut rtattr; - let rtalen = IFA_PAYLOAD!(nlh) as u32; - - if ifinfo.ifi_index as u32 == ifa.ifa_index { - // Safe because dump_all_addresses returns valid pointers. - let addr = unsafe { - let attrs = parse_attrs(rta, rtalen, (IFA_MAX + 1) as usize)?; - let t = if !attrs[IFA_ADDRESS as usize].is_null() { - attrs[IFA_ADDRESS as usize] - } else { - attrs[IFA_LOCAL as usize] - }; - getattr_var(t as *const rtattr) - }; - - addrs.push(RtIPAddr { - ip_family: ifa.ifa_family, - ip_mask: ifa.ifa_prefixlen, - addr, - }); - } - } - - Ok(addrs) - } - - pub fn delete_one_addr(&mut self, ifinfo: &ifinfomsg, addr: &RtIPAddr) -> Result<()> { - let mut v: Vec = vec![0; DEFAULT_NETLINK_BUF_SIZE]; - // Safe because we have allocated a big enough data buffer. - let nlh = unsafe { &mut *(v.as_mut_ptr() as *mut nlmsghdr) }; - let ifa = unsafe { &mut *(NLMSG_DATA!(nlh) as *mut ifaddrmsg) }; - - nlh.nlmsg_len = NLMSG_LENGTH!(mem::size_of::() as u32) as __u32; - nlh.nlmsg_type = RTM_DELADDR; - nlh.nlmsg_flags = NLM_F_REQUEST; - self.assign_seqnum(nlh); - - ifa.ifa_family = addr.ip_family; - ifa.ifa_prefixlen = addr.ip_mask; - ifa.ifa_index = ifinfo.ifi_index as u32; - - // Safe because we have allocated a big enough data buffer. - unsafe { - nlh.addattr_var(IFA_ADDRESS, addr.addr.as_ref()); - } - - // ignore EADDRNOTAVAIL here.. - self.rtnl_talk(v.as_mut_slice(), false)?; - - Ok(()) - } - - pub fn delete_all_addrs(&mut self, ifinfo: &ifinfomsg, addrs: &[RtIPAddr]) -> Result<()> { - for a in addrs { - self.delete_one_addr(ifinfo, a)?; - } - - Ok(()) - } - - pub fn add_one_address(&mut self, ifinfo: &ifinfomsg, ip: &RtIPAddr) -> Result<()> { - let mut v: Vec = vec![0; DEFAULT_NETLINK_BUF_SIZE]; - // Safe because we have allocated a big enough data buffer. - let nlh = unsafe { &mut *(v.as_mut_ptr() as *mut nlmsghdr) }; - let ifa = unsafe { &mut *(NLMSG_DATA!(nlh) as *mut ifaddrmsg) }; - - nlh.nlmsg_len = NLMSG_LENGTH!(mem::size_of::() as u32) as __u32; - nlh.nlmsg_type = RTM_NEWADDR; - nlh.nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE | NLM_F_EXCL; - self.assign_seqnum(nlh); - - ifa.ifa_family = ip.ip_family; - ifa.ifa_prefixlen = ip.ip_mask; - ifa.ifa_index = ifinfo.ifi_index as __u32; - - // Safe because we have allocated a big enough data buffer. - unsafe { - nlh.addattr_var(IFA_ADDRESS, ip.addr.as_ref()); - // don't know why need IFA_LOCAL, without it kernel returns -EINVAL... - nlh.addattr_var(IFA_LOCAL, ip.addr.as_ref()); - } - - self.rtnl_talk(v.as_mut_slice(), false)?; - - Ok(()) - } - - pub fn get_name_by_index(&mut self, index: i32) -> Result { - let mut v: Vec = vec![0; DEFAULT_NETLINK_BUF_SIZE]; - let mut i = 0; - - while i < 5 { - i += 1; - // Safe because we have allocated enough buffer space. - let nlh = unsafe { &mut *(v.as_mut_ptr() as *mut nlmsghdr) }; - let ifi = unsafe { &mut *(NLMSG_DATA!(nlh) as *mut ifinfomsg) }; - - nlh.nlmsg_len = NLMSG_LENGTH!(mem::size_of::()) as __u32; - nlh.nlmsg_type = RTM_GETLINK; - nlh.nlmsg_flags = NLM_F_REQUEST; - self.assign_seqnum(nlh); - - ifi.ifi_index = index; - - unsafe { - nlh.addattr32(IFLA_EXT_MASK, RTEXT_FILTER_VF | RTEXT_FILTER_SKIP_STATS); - } - - let mut retv = self.rtnl_talk(v.as_mut_slice(), true)?; - if retv.len() < std::mem::size_of::() { - return nix_errno(Errno::EBADMSG); - } - - let nlh = unsafe { &mut *(retv.as_mut_ptr() as *mut nlmsghdr) }; - if nlh.nlmsg_type != RTM_NEWLINK && nlh.nlmsg_type != RTM_DELLINK { - info!(sl!(), "wrong message!"); - continue; - } - - let tlen = NLMSG_SPACE!(mem::size_of::()); - if nlh.nlmsg_len < tlen { - info!(sl!(), "corrupt message?"); - continue; - } - - let ifi = unsafe { &mut *(NLMSG_DATA!(nlh) as *mut ifinfomsg) }; - let rta: *mut rtattr = IFLA_RTA!(ifi) as *mut rtattr; - let rtalen = IFLA_PAYLOAD!(nlh) as u32; - - let attrs = unsafe { parse_attrs(rta, rtalen, (IFLA_MAX + 1) as usize)? }; - - let t = attrs[IFLA_IFNAME as usize]; - if !t.is_null() { - // we have a name - let tdata = unsafe { getattr_var(t) }; - return Ok(String::from_utf8(tdata)?); - } - } - - nix_errno(Errno::ENOENT) - } - - pub fn get_all_routes(&mut self) -> Result> { - let mut rs: Vec = Vec::new(); - let (_srv, rv) = self.dump_all_routes()?; - - for r in &rv { - // Safe because dump_all_routes() return valid pointers. - let nlh = unsafe { &**r }; - let rtm = unsafe { &mut *(NLMSG_DATA!(nlh) as *mut rtmsg) }; - - if nlh.nlmsg_type != RTM_NEWROUTE && nlh.nlmsg_type != RTM_DELROUTE { - info!(sl!(), "not route message!"); - continue; - } - - let tlen = NLMSG_SPACE!(mem::size_of::()); - if nlh.nlmsg_len < tlen { - info!( - sl!(), - "invalid nlmsg! nlmsg_len: {}, nlmsg_spae: {}", nlh.nlmsg_len, tlen - ); - break; - } - - if rtm.rtm_table != RT_TABLE_MAIN as u8 { - continue; - } - - let rta: *mut rtattr = RTM_RTA!(rtm) as *mut rtattr; - let rtalen = RTM_PAYLOAD!(nlh) as u32; - - let attrs = unsafe { parse_attrs(rta, rtalen, (RTA_MAX + 1) as usize)? }; - - let t = attrs[RTA_TABLE as usize]; - if !t.is_null() { - let table = unsafe { getattr32(t) }; - if table != RT_TABLE_MAIN { - continue; - } - } - - // find source, destination, gateway, scope, and device name - let mut t = attrs[RTA_DST as usize]; - let mut rte: RtRoute = RtRoute::default(); - - rte.dst_len = (*rtm).rtm_dst_len; - rte.src_len = (*rtm).rtm_src_len; - rte.dest = None; - rte.protocol = (*rtm).rtm_protocol; - // destination - if !t.is_null() { - rte.dest = Some(unsafe { getattr_var(t as *const rtattr) }); - } - - // gateway - t = attrs[RTA_GATEWAY as usize]; - if !t.is_null() { - rte.gateway = Some(unsafe { getattr_var(t as *const rtattr) }); - if rte.dest.is_none() { - rte.dest = Some(vec![0 as u8; 4]); - } - } - - // source - t = attrs[RTA_SRC as usize]; - if t.is_null() { - t = attrs[RTA_PREFSRC as usize]; - } - if !t.is_null() { - rte.source = Some(unsafe { getattr_var(t as *const rtattr) }); - } - - // scope - rte.scope = rtm.rtm_scope; - - // oif - t = attrs[RTA_OIF as usize]; - if !t.is_null() { - rte.index = unsafe { getattr32(t as *const rtattr) as i32 }; - } - - rs.push(rte); - } - - Ok(rs) - } - - pub fn delete_all_routes(&mut self, rs: &[RtRoute]) -> Result<()> { - for r in rs { - let name = self.get_name_by_index(r.index)?; - if name.as_str().contains("lo") || name.as_str().contains("::1") { - continue; - } - - if r.protocol == RTPROTO_KERNEL { - continue; - } - - self.delete_one_route(r)?; - } - - Ok(()) - } - - pub fn add_one_route(&mut self, r: &RtRoute) -> Result<()> { - let mut v: Vec = vec![0; DEFAULT_NETLINK_BUF_SIZE]; - // Safe because we have allocated a big enough data buffer. - let nlh = unsafe { &mut *(v.as_mut_ptr() as *mut nlmsghdr) }; - let rtm = unsafe { &mut *(NLMSG_DATA!(nlh) as *mut rtmsg) }; - - nlh.nlmsg_len = NLMSG_LENGTH!(mem::size_of::()) as u32; - nlh.nlmsg_type = RTM_NEWROUTE; - nlh.nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE | NLM_F_EXCL; - self.assign_seqnum(nlh); - - rtm.rtm_family = libc::AF_INET as u8; - rtm.rtm_table = RT_TABLE_MAIN as u8; - rtm.rtm_scope = RT_SCOPE_NOWHERE; - rtm.rtm_protocol = RTPROTO_BOOT; - rtm.rtm_scope = RT_SCOPE_UNIVERSE; - rtm.rtm_type = RTN_UNICAST; - - rtm.rtm_dst_len = r.dst_len; - rtm.rtm_src_len = r.src_len; - rtm.rtm_scope = r.scope; - - unsafe { - if let Some(source) = r.source.as_ref() { - if r.src_len > 0 { - nlh.addattr_var(RTA_SRC, source.as_ref()); - } else { - nlh.addattr_var(RTA_PREFSRC, source.as_ref()); - } - } - - if let Some(dest) = r.dest.as_ref() { - nlh.addattr_var(RTA_DST, dest.as_ref()); - } - - if let Some(gateway) = r.gateway.as_ref() { - nlh.addattr_var(RTA_GATEWAY, gateway.as_ref()); - } - - nlh.addattr32(RTA_OIF, r.index as u32); - } - - self.rtnl_talk(v.as_mut_slice(), false)?; - - Ok(()) - } - - pub fn delete_one_route(&mut self, r: &RtRoute) -> Result<()> { - info!(sl!(), "delete route"); - let mut v: Vec = vec![0; DEFAULT_NETLINK_BUF_SIZE]; - // Safe because we have allocated a big enough data buffer. - let nlh = unsafe { &mut *(v.as_mut_ptr() as *mut nlmsghdr) }; - let rtm = unsafe { &mut *(NLMSG_DATA!(nlh) as *mut rtmsg) }; - - nlh.nlmsg_len = NLMSG_LENGTH!(mem::size_of::()) as u32; - nlh.nlmsg_type = RTM_DELROUTE; - nlh.nlmsg_flags = NLM_F_REQUEST; - self.assign_seqnum(nlh); - - rtm.rtm_family = libc::AF_INET as u8; - rtm.rtm_table = RT_TABLE_MAIN as u8; - rtm.rtm_scope = RT_SCOPE_NOWHERE; - - rtm.rtm_dst_len = r.dst_len; - rtm.rtm_src_len = r.src_len; - rtm.rtm_scope = r.scope; - - // Safe because we have allocated a big enough data buffer. - unsafe { - if let Some(source) = r.source.as_ref() { - if r.src_len > 0 { - nlh.addattr_var(RTA_SRC, source.as_ref()); - } else { - nlh.addattr_var(RTA_PREFSRC, source.as_ref()); - } - } - - if let Some(dest) = r.dest.as_ref() { - nlh.addattr_var(RTA_DST, dest.as_ref()); - } - - if let Some(gateway) = r.gateway.as_ref() { - nlh.addattr_var(RTA_GATEWAY, gateway.as_ref()); - } - - nlh.addattr32(RTA_OIF, r.index as u32); - } - - self.rtnl_talk(v.as_mut_slice(), false)?; - - Ok(()) - } - - pub fn handle_localhost(&mut self) -> Result<()> { - let ifi = self.find_link_by_name("lo")?; - - self.set_link_status(&ifi, true) - } - - fn assign_seqnum(&mut self, nlh: &mut nlmsghdr) { - self.seq += 1; - self.dump = self.seq; - nlh.nlmsg_seq = self.seq; - } -} - -impl Drop for RtnlHandle { - fn drop(&mut self) { - if self.fd >= 0 { - unsafe { - libc::close(self.fd); - } - self.fd = -1; - } - } -} - -/// Parse netlink attributes from raw buffer. -/// -/// # Safety -/// Caller needs to ensure that rta and rtalen are valid. -pub unsafe fn parse_attrs( - mut rta: *const rtattr, - mut rtalen: u32, - max: usize, -) -> Result> { - let mut attrs: Vec<*const rtattr> = vec![std::ptr::null(); max as usize]; - - while RTA_OK!(rta, rtalen) { - let rtype = (*rta).rta_type as usize; - - if rtype < max && attrs[rtype].is_null() { - attrs[rtype] = rta as *const rtattr; - } - - rta = RTA_NEXT!(rta, rtalen) - } - - Ok(attrs) -} - -impl nlmsghdr { - /// Add an variable attribute to the netlink message. - /// - /// # Safety - /// Caller needs to ensure that there are enough space after `self` to store the attribute. - pub unsafe fn addattr_var(&mut self, cat: u16, data: &[u8]) { - let mut rta: *mut rtattr = NLMSG_TAIL!(self) as *mut rtattr; - let alen = RTA_LENGTH!(data.len()) as u16; - - (*rta).rta_type = cat; - (*rta).rta_len = alen; - - if !data.is_empty() { - libc::memcpy( - RTA_DATA!(rta) as *mut libc::c_void, - data.as_ptr() as *const libc::c_void, - data.len(), - ); - } - - self.nlmsg_len = NLMSG_ALIGN!(self.nlmsg_len) + RTA_ALIGN!(alen); - } - - /// Add a string attribute to the netlink message. - /// - /// # Safety - /// Caller needs to ensure that there are enough space after `self` to store the attribute. - pub unsafe fn addattr_str(&mut self, cat: u16, data: &str) { - let mut rta: *mut rtattr = NLMSG_TAIL!(self) as *mut rtattr; - let len = data.len(); - let alen = RTA_LENGTH!(len + 1) as u16; - let tp: *mut libc::c_void = RTA_DATA!(rta) as *mut libc::c_void; - - (*rta).rta_type = cat; - (*rta).rta_len = alen; - - libc::memcpy( - tp, - data.as_ptr() as *const libc::c_void, - len as libc::size_t, - ); - - self.nlmsg_len = NLMSG_ALIGN!(self.nlmsg_len) + RTA_ALIGN!(alen); - } - - /// Add an 1/2/4/8 bytes attribute to the netlink message. - /// - /// # Safety - /// Caller needs to ensure that there are enough space after `self` to store the attribute. - pub unsafe fn addattr_size(&mut self, cat: u16, val: u64, size: u8) { - assert_eq!(size == 1 || size == 2 || size == 4 || size == 8, true); - - let mut rta: *mut rtattr = NLMSG_TAIL!(self) as *mut rtattr; - (*rta).rta_type = cat; - - if size == 1 { - let data: *mut u8 = RTA_DATA!(rta) as *mut u8; - *data = val as u8; - let len = RTA_LENGTH!(1) as u16; - (*rta).rta_len = len; - } - - if size == 2 { - let data: *mut u16 = RTA_DATA!(rta) as *mut u16; - *data = val as u16; - let len = RTA_LENGTH!(2) as u16; - (*rta).rta_len = len; - } - - if size == 4 { - let data: *mut u32 = RTA_DATA!(rta) as *mut u32; - *data = val as u32; - let len = RTA_LENGTH!(4) as u16; - (*rta).rta_len = len; - } - - if size == 8 { - let data: *mut u64 = RTA_DATA!(rta) as *mut u64; - *data = val as u64; - let len = RTA_LENGTH!(8) as u16; - (*rta).rta_len = len; - } - - self.nlmsg_len = NLMSG_ALIGN!(self.nlmsg_len) + RTA_ALIGN!((*rta).rta_len); - } - - /// Add a 8-bit attribute. - /// - /// # Safety - /// Caller needs to ensure that there are enough space after `self` to store the attribute. - pub unsafe fn addattr8(&mut self, cat: u16, val: u8) { - self.addattr_size(cat, val as u64, 1); - } - - /// Add a 16-bit attribute. - /// - /// # Safety - /// Caller needs to ensure that there are enough space after `self` to store the attribute. - pub unsafe fn addattr16(&mut self, cat: u16, val: u16) { - self.addattr_size(cat, val as u64, 2); - } - - /// Add a 32-bit attribute. - /// - /// # Safety - /// Caller needs to ensure that there are enough space after `self` to store the attribute. - pub unsafe fn addattr32(&mut self, cat: u16, val: u32) { - self.addattr_size(cat, val as u64, 4); - } - - /// Add a 64-bit attribute. - /// - /// # Safety - /// Caller needs to ensure that there are enough space after `self` to store the attribute. - pub unsafe fn addattr64(&mut self, cat: u16, val: u64) { - self.addattr_size(cat, val, 8); - } -} - -unsafe fn getattr_size(rta: *const rtattr) -> u64 { - let alen: usize = RTA_PAYLOAD!(rta) as usize; - assert!(alen == 1 || alen == 2 || alen == 4 || alen == 8); - let tp: *const u8 = RTA_DATA!(rta) as *const u8; - - if alen == 1 { - let data: *const u8 = tp as *const u8; - return *data as u64; - } - - if alen == 2 { - let data: *const u16 = tp as *const u16; - return *data as u64; - } - - if alen == 4 { - let data: *const u32 = tp as *const u32; - return *data as u64; - } - - if alen == 8 { - let data: *const u64 = tp as *const u64; - return *data; - } - - panic!("impossible!"); -} - -/// Get a 8-bit attribute. -/// -/// # Safety -/// Caller needs to ensure that there are enough space after `rta` to read the attribute. -pub unsafe fn getattr8(rta: *const rtattr) -> u8 { - let alen = RTA_PAYLOAD!(rta); - assert_eq!(alen, 1); - getattr_size(rta) as u8 -} - -/// Get a 16-bit attribute. -/// -/// # Safety -/// Caller needs to ensure that there are enough space after `rta` to read the attribute. -pub unsafe fn getattr16(rta: *const rtattr) -> u16 { - let alen = RTA_PAYLOAD!(rta); - assert_eq!(alen, 2); - getattr_size(rta) as u16 -} - -/// Get a 32-bit attribute. -/// -/// # Safety -/// Caller needs to ensure that there are enough space after `rta` to read the attribute. -pub unsafe fn getattr32(rta: *const rtattr) -> u32 { - let alen = RTA_PAYLOAD!(rta); - assert_eq!(alen, 4); - getattr_size(rta) as u32 -} - -/// Get a 64-bit attribute. -/// -/// # Safety -/// Caller needs to ensure that there are enough space after `rta` to read the attribute. -pub unsafe fn getattr64(rta: *const rtattr) -> u64 { - let alen = RTA_PAYLOAD!(rta); - assert_eq!(alen, 8); - getattr_size(rta) -} - -/// Get a variable length attribute. -/// -/// # Safety -/// Caller needs to ensure that there are enough space after `rta` to read the attribute. -pub unsafe fn getattr_var(rta: *const rtattr) -> Vec { - assert_ne!(rta as i64, 0); - let data: *const libc::c_void = RTA_DATA!(rta) as *const libc::c_void; - let alen: usize = RTA_PAYLOAD!(rta) as usize; - - let mut v: Vec = vec![0; alen]; - let tp: *mut libc::c_void = v.as_mut_ptr() as *mut libc::c_void; - - libc::memcpy(tp, data, alen as libc::size_t); - - v -} - -#[inline] -fn nix_last_os_err() -> Result { - Err(nix::Error::Sys(Errno::last())) -} - -#[inline] -fn nix_errno(err: Errno) -> Result { - Err(nix::Error::Sys(err)) -} - -#[cfg(test)] -mod tests { - use super::*; - use libc; - use std::mem; - - #[test] - fn test_macro() { - println!("{}", RTA_ALIGN!(10)); - assert_eq!(RTA_ALIGN!(6), 8); - assert_eq!(RTM_FAM!(36), 5); - assert_eq!( - NLMSG_HDRLEN!(), - NLMSG_ALIGN!(mem::size_of::() as libc::c_uint) - ); - } -} diff --git a/src/agent/netlink/src/parser.rs b/src/agent/netlink/src/parser.rs deleted file mode 100644 index 0786c0396b..0000000000 --- a/src/agent/netlink/src/parser.rs +++ /dev/null @@ -1,201 +0,0 @@ -// Copyright (c) 2019 Ant Financial -// -// SPDX-License-Identifier: Apache-2.0 - -//! Parser for IPv4/IPv6/MAC addresses. - -use std::net::{Ipv4Addr, Ipv6Addr}; -use std::str::FromStr; - -use super::{Errno, Result, __u8, nix_errno}; - -#[inline] -pub(crate) fn parse_u8(s: &str, radix: u32) -> Result { - if radix >= 2 && radix <= 36 { - u8::from_str_radix(s, radix).map_err(|_| nix::Error::Sys(Errno::EINVAL)) - } else { - u8::from_str(s).map_err(|_| nix::Error::Sys(Errno::EINVAL)) - } -} - -pub fn parse_ipv4_addr(s: &str) -> Result> { - match Ipv4Addr::from_str(s) { - Ok(v) => Ok(Vec::from(v.octets().as_ref())), - Err(_e) => nix_errno(Errno::EINVAL), - } -} - -pub fn parse_ip_addr(s: &str) -> Result> { - if let Ok(v6) = Ipv6Addr::from_str(s) { - Ok(Vec::from(v6.octets().as_ref())) - } else { - parse_ipv4_addr(s) - } -} - -pub fn parse_ip_addr_with_family(ip_address: &str) -> Result<(__u8, Vec)> { - if let Ok(v6) = Ipv6Addr::from_str(ip_address) { - Ok((libc::AF_INET6 as __u8, Vec::from(v6.octets().as_ref()))) - } else { - parse_ipv4_addr(ip_address).map(|v| (libc::AF_INET as __u8, v)) - } -} - -pub fn parse_ipv4_cidr(s: &str) -> Result<(Vec, u8)> { - let fields: Vec<&str> = s.split('/').collect(); - - if fields.len() != 2 { - nix_errno(Errno::EINVAL) - } else { - Ok((parse_ipv4_addr(fields[0])?, parse_u8(fields[1], 10)?)) - } -} - -pub fn parse_cidr(s: &str) -> Result<(Vec, u8)> { - let fields: Vec<&str> = s.split('/').collect(); - - if fields.len() != 2 { - nix_errno(Errno::EINVAL) - } else { - Ok((parse_ip_addr(fields[0])?, parse_u8(fields[1], 10)?)) - } -} - -pub fn parse_mac_addr(hwaddr: &str) -> Result> { - let fields: Vec<&str> = hwaddr.split(':').collect(); - - if fields.len() != 6 { - nix_errno(Errno::EINVAL) - } else { - Ok(vec![ - parse_u8(fields[0], 16)?, - parse_u8(fields[1], 16)?, - parse_u8(fields[2], 16)?, - parse_u8(fields[3], 16)?, - parse_u8(fields[4], 16)?, - parse_u8(fields[5], 16)?, - ]) - } -} - -/// Format an IPv4/IPv6/MAC address. -/// -/// # Safety -/// Caller needs to ensure that addr and len are valid. -pub unsafe fn format_address(addr: *const u8, len: u32) -> Result { - let mut a: String; - if len == 4 { - // ipv4 - let mut i = 1; - let mut p = addr as i64; - - a = format!("{}", *(p as *const u8)); - while i < len { - p += 1; - i += 1; - a.push_str(format!(".{}", *(p as *const u8)).as_str()); - } - - return Ok(a); - } - - if len == 6 { - // hwaddr - let mut i = 1; - let mut p = addr as i64; - - a = format!("{:0>2X}", *(p as *const u8)); - while i < len { - p += 1; - i += 1; - a.push_str(format!(":{:0>2X}", *(p as *const u8)).as_str()); - } - - return Ok(a); - } - - if len == 16 { - // ipv6 - let p = addr as *const u8 as *const libc::c_void; - let mut ar: [u8; 16] = [0; 16]; - let mut v: Vec = vec![0; 16]; - let dp: *mut libc::c_void = v.as_mut_ptr() as *mut libc::c_void; - libc::memcpy(dp, p, 16); - - ar.copy_from_slice(v.as_slice()); - - return Ok(Ipv6Addr::from(ar).to_string()); - } - - nix_errno(Errno::EINVAL) -} - -#[cfg(test)] -mod tests { - use super::*; - use libc; - - #[test] - fn test_ip_addr() { - let ip = parse_ipv4_addr("1.2.3.4").unwrap(); - assert_eq!(ip, vec![0x1u8, 0x2u8, 0x3u8, 0x4u8]); - parse_ipv4_addr("1.2.3.4.5").unwrap_err(); - parse_ipv4_addr("1.2.3-4").unwrap_err(); - parse_ipv4_addr("1.2.3.a").unwrap_err(); - parse_ipv4_addr("1.2.3.x").unwrap_err(); - parse_ipv4_addr("-1.2.3.4").unwrap_err(); - parse_ipv4_addr("+1.2.3.4").unwrap_err(); - - let (family, _) = parse_ip_addr_with_family("192.168.1.1").unwrap(); - assert_eq!(family, libc::AF_INET as __u8); - - let (family, ip) = - parse_ip_addr_with_family("2001:0db8:85a3:0000:0000:8a2e:0370:7334").unwrap(); - assert_eq!(family, libc::AF_INET6 as __u8); - assert_eq!(ip.len(), 16); - parse_ip_addr_with_family("2001:0db8:85a3:0000:0000:8a2e:0370:73345").unwrap_err(); - - let ip = parse_ip_addr("::1").unwrap(); - assert_eq!(ip[0], 0x0); - assert_eq!(ip[15], 0x1); - } - - #[test] - fn test_parse_cidr() { - let (_, mask) = parse_ipv4_cidr("1.2.3.4/31").unwrap(); - assert_eq!(mask, 31); - - parse_ipv4_cidr("1.2.3/4/31").unwrap_err(); - parse_ipv4_cidr("1.2.3.4/f").unwrap_err(); - parse_ipv4_cidr("1.2.3/8").unwrap_err(); - parse_ipv4_cidr("1.2.3.4.8").unwrap_err(); - - let (ip, mask) = parse_cidr("2001:db8:a::123/64").unwrap(); - assert_eq!(mask, 64); - assert_eq!(ip[0], 0x20); - assert_eq!(ip[15], 0x23); - } - - #[test] - fn test_parse_mac_addr() { - let mac = parse_mac_addr("FF:FF:FF:FF:FF:FE").unwrap(); - assert_eq!(mac.len(), 6); - assert_eq!(mac[0], 0xff); - assert_eq!(mac[5], 0xfe); - - parse_mac_addr("FF:FF:FF:FF:FF:FE:A0").unwrap_err(); - parse_mac_addr("FF:FF:FF:FF:FF:FX").unwrap_err(); - parse_mac_addr("FF:FF:FF:FF:FF").unwrap_err(); - } - - #[test] - fn test_format_address() { - let buf = [1u8, 2u8, 3u8, 4u8]; - let addr = unsafe { format_address(&buf as *const u8, 4).unwrap() }; - assert_eq!(addr, "1.2.3.4"); - - let buf = [1u8, 2u8, 3u8, 4u8, 5u8, 6u8]; - let addr = unsafe { format_address(&buf as *const u8, 6).unwrap() }; - assert_eq!(addr, "01:02:03:04:05:06"); - } -} diff --git a/src/agent/src/main.rs b/src/agent/src/main.rs index 4675f785ab..cf7248f349 100644 --- a/src/agent/src/main.rs +++ b/src/agent/src/main.rs @@ -24,7 +24,6 @@ extern crate scopeguard; #[macro_use] extern crate slog; -extern crate netlink; use anyhow::{anyhow, Context, Result}; use nix::fcntl::{self, OFlag}; @@ -54,7 +53,7 @@ mod linux_abi; mod metrics; mod mount; mod namespace; -mod netlink2; +mod netlink; mod network; pub mod random; mod sandbox; diff --git a/src/agent/src/netlink2.rs b/src/agent/src/netlink.rs similarity index 100% rename from src/agent/src/netlink2.rs rename to src/agent/src/netlink.rs diff --git a/src/agent/src/sandbox.rs b/src/agent/src/sandbox.rs index bbdfd39652..5e42881281 100644 --- a/src/agent/src/sandbox.rs +++ b/src/agent/src/sandbox.rs @@ -6,7 +6,7 @@ use crate::linux_abi::*; use crate::mount::{get_mount_fs_type, remove_mounts, TYPEROOTFS}; use crate::namespace::Namespace; -use crate::netlink2::Handle; +use crate::netlink::Handle; use crate::network::Network; use anyhow::{anyhow, Context, Result}; use libc::pid_t;