netlink: refine interface to reduce unsafe code

There are too much unsafe code in the netlink crate, we need to reduce
unsafe code as much as possible. To achieve this, methods are classified
as public interfaces and internal methods.

All public interface of RtnlHandle has been reimplemented as safe code,
only some public helper functions to manipulater Netlink message data
structures are implemented as unsafe code.

The code to parse IPv4/IPv6/MAC addresses has been moved to a dedicated
file named parser.rs.

Signed-off-by: Liu Jiang <gerry@linux.alibaba.com>
This commit is contained in:
Liu Jiang 2020-05-31 11:19:54 +08:00
parent 3fe930b946
commit 1b8c2cba60
4 changed files with 1159 additions and 1242 deletions

View File

@ -9,7 +9,7 @@ oci = { path = "oci" }
logging = { path = "logging" } logging = { path = "logging" }
rustjail = { path = "rustjail" } rustjail = { path = "rustjail" }
protocols = { path = "protocols" } protocols = { path = "protocols" }
netlink = { path = "netlink" } netlink = { path = "netlink", features = ["with-log", "with-agent-handler"] }
lazy_static = "1.3.0" lazy_static = "1.3.0"
error-chain = "0.12.1" error-chain = "0.12.1"
ttrpc = { git = "https://github.com/containerd/ttrpc-rust.git", branch="0.3.0" } ttrpc = { git = "https://github.com/containerd/ttrpc-rust.git", branch="0.3.0" }

View File

@ -31,14 +31,12 @@ impl super::RtnlHandle {
let ifinfo = self.find_link_by_hwaddr(iface.hwAddr.as_str())?; let ifinfo = self.find_link_by_hwaddr(iface.hwAddr.as_str())?;
// bring down interface if it is up // bring down interface if it is up
if ifinfo.ifi_flags & libc::IFF_UP as u32 != 0 { if ifinfo.ifi_flags & libc::IFF_UP as u32 != 0 {
self.set_link_status(&ifinfo, false)?; self.set_link_status(&ifinfo, false)?;
} }
// delete all addresses associated with the link // delete all addresses associated with the link
let del_addrs: Vec<RtIPAddr> = self.get_link_addresses(&ifinfo)?; let del_addrs: Vec<RtIPAddr> = self.get_link_addresses(&ifinfo)?;
self.delete_all_addrs(&ifinfo, del_addrs.as_ref())?; self.delete_all_addrs(&ifinfo, del_addrs.as_ref())?;
// add new ip addresses in request // add new ip addresses in request
@ -47,191 +45,175 @@ impl super::RtnlHandle {
self.add_one_address(&ifinfo, &rtip)?; self.add_one_address(&ifinfo, &rtip)?;
} }
let mut v: Vec<u8> = 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. // set name, set mtu, IFF_NOARP. in one rtnl_talk.
let mut v: Vec<u8> = vec![0; 2048]; nlh.nlmsg_len = NLMSG_LENGTH!(mem::size_of::<ifinfomsg>() 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 { unsafe {
let p: *mut u8 = v.as_mut_ptr() as *mut u8; nlh.addattr32(IFLA_MTU, iface.mtu as u32);
let mut nlh: *mut nlmsghdr = p as *mut nlmsghdr;
let mut ifi: *mut ifinfomsg = NLMSG_DATA!(nlh) as *mut ifinfomsg;
(*nlh).nlmsg_len = NLMSG_LENGTH!(mem::size_of::<ifinfomsg>() as u32) as __u32; // if str is null terminated, use addattr_var.
(*nlh).nlmsg_type = RTM_NEWLINK;
(*nlh).nlmsg_flags = NLM_F_REQUEST;
self.seq += 1;
(*nlh).nlmsg_seq = self.seq;
(*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;
}
addattr32(nlh, IFLA_MTU, iface.mtu as u32);
// if str is null terminated, use addattr_var
// otherwise, use addattr_str // otherwise, use addattr_str
addattr_var( nlh.addattr_var(
nlh,
IFLA_IFNAME, IFLA_IFNAME,
iface.name.as_ptr() as *const u8, iface.name.as_ptr() as *const u8,
iface.name.len(), iface.name.len(),
); );
// addattr_str(nlh, IFLA_IFNAME, iface.name.as_str());
} }
self.rtnl_talk(v.as_mut_slice(), false)?; self.rtnl_talk(v.as_mut_slice(), false)?;
// TODO: why the result is ignored here?
let _ = self.set_link_status(&ifinfo, true); let _ = self.set_link_status(&ifinfo, true);
// test remove this link
// let _ = self.remove_interface(iface)?;
Ok(iface.clone()) Ok(iface.clone())
//return Err(ErrorKind::Nix(nix::Error::Sys(
// Errno::EOPNOTSUPP)).into());
} }
/// Delete this interface/link per request
pub fn remove_interface(&mut self, iface: &Interface) -> Result<Interface> { pub fn remove_interface(&mut self, iface: &Interface) -> Result<Interface> {
let ifinfo = self.find_link_by_hwaddr(iface.hwAddr.as_str())?; let ifinfo = self.find_link_by_hwaddr(iface.hwAddr.as_str())?;
self.set_link_status(&ifinfo, false)?; self.set_link_status(&ifinfo, false)?;
// delete this link per request let mut v: Vec<u8> = vec![0; DEFAULT_NETLINK_BUF_SIZE];
let mut v: Vec<u8> = vec![0; 2048]; // Safe because we have allocated enough buffer space.
unsafe { let nlh = unsafe { &mut *(v.as_mut_ptr() as *mut nlmsghdr) };
let mut nlh: *mut nlmsghdr = v.as_mut_ptr() as *mut nlmsghdr; let ifi = unsafe { &mut *(NLMSG_DATA!(nlh) as *mut ifinfomsg) };
let mut ifi: *mut ifinfomsg = NLMSG_DATA!(nlh) as *mut ifinfomsg;
// No attributes needed?
(*nlh).nlmsg_len = NLMSG_LENGTH!(mem::size_of::<ifinfomsg>()) as __u32;
(*nlh).nlmsg_type = RTM_DELLINK;
(*nlh).nlmsg_flags = NLM_F_REQUEST;
self.seq += 1; // No attributes needed?
(*nlh).nlmsg_seq = self.seq; nlh.nlmsg_len = NLMSG_LENGTH!(mem::size_of::<ifinfomsg>()) 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_family = ifinfo.ifi_family;
(*ifi).ifi_index = ifinfo.ifi_index; ifi.ifi_index = ifinfo.ifi_index;
(*ifi).ifi_type = ifinfo.ifi_type; ifi.ifi_type = ifinfo.ifi_type;
self.rtnl_talk(v.as_mut_slice(), false)?; self.rtnl_talk(v.as_mut_slice(), false)?;
}
Ok(iface.clone()) Ok(iface.clone())
} }
pub fn list_interfaces(&mut self) -> Result<Vec<Interface>> { pub fn list_interfaces(&mut self) -> Result<Vec<Interface>> {
let mut ifaces: Vec<Interface> = Vec::new(); let mut ifaces: Vec<Interface> = Vec::new();
let (_slv, lv) = self.dump_all_links()?;
let (_sav, av) = self.dump_all_addresses(0)?;
unsafe { for link in &lv {
// get link info // Safe because dump_all_links() returns valid pointers.
let (_slv, lv) = self.dump_all_links()?; let nlh = unsafe { &**link };
if nlh.nlmsg_type != RTM_NEWLINK && nlh.nlmsg_type != RTM_DELLINK {
continue;
}
// get addrinfo if nlh.nlmsg_len < NLMSG_SPACE!(mem::size_of::<ifinfomsg>()) {
let (_sav, av) = self.dump_all_addresses(0)?; info!(
sl!(),
"invalid nlmsg! nlmsg_len: {}, nlmsg_space: {}",
nlh.nlmsg_len,
NLMSG_SPACE!(mem::size_of::<ifinfomsg>())
);
break;
}
// got all the link message and address message // Safe because we have just validated available buffer space above.
// into lv and av respectively, parse attributes let ifi = unsafe { &*(NLMSG_DATA!(nlh) as *const ifinfomsg) };
for link in &lv { let rta: *mut rtattr = IFLA_RTA!(ifi as *const ifinfomsg) as *mut rtattr;
let nlh: *const nlmsghdr = *link; let rtalen = IFLA_PAYLOAD!(nlh) as u32;
let ifi: *const ifinfomsg = NLMSG_DATA!(nlh) as *const ifinfomsg; let attrs = unsafe { parse_attrs(rta, rtalen, (IFLA_MAX + 1) as usize)? };
if (*nlh).nlmsg_type != RTM_NEWLINK && (*nlh).nlmsg_type != RTM_DELLINK { // fill out some fields of Interface,
continue; let mut iface: Interface = Interface::default();
}
if (*nlh).nlmsg_len < NLMSG_SPACE!(mem::size_of::<ifinfomsg>()) { // Safe because parse_attrs() returns valid pointers.
info!( unsafe {
sl!(), if !attrs[IFLA_IFNAME as usize].is_null() {
"invalid nlmsg! nlmsg_len: {}, nlmsg_space: {}",
(*nlh).nlmsg_len,
NLMSG_SPACE!(mem::size_of::<ifinfomsg>())
);
break;
}
let rta: *mut rtattr = IFLA_RTA!(ifi) as *mut rtattr;
let rtalen = IFLA_PAYLOAD!(nlh) as u32;
let attrs = parse_attrs(rta, rtalen, (IFLA_MAX + 1) as usize)?;
// fill out some fields of Interface,
let mut iface: Interface = Interface::default();
if attrs[IFLA_IFNAME as usize] as i64 != 0 {
let t = attrs[IFLA_IFNAME as usize]; let t = attrs[IFLA_IFNAME as usize];
iface.name = String::from_utf8(getattr_var(t as *const rtattr))?; iface.name = String::from_utf8(getattr_var(t as *const rtattr))?;
} }
if attrs[IFLA_MTU as usize] as i64 != 0 { if !attrs[IFLA_MTU as usize].is_null() {
let t = attrs[IFLA_MTU as usize]; let t = attrs[IFLA_MTU as usize];
iface.mtu = getattr32(t) as u64; iface.mtu = getattr32(t) as u64;
} }
if attrs[IFLA_ADDRESS as usize] as i64 != 0 { if !attrs[IFLA_ADDRESS as usize].is_null() {
let alen = RTA_PAYLOAD!(attrs[IFLA_ADDRESS as usize]); let alen = RTA_PAYLOAD!(attrs[IFLA_ADDRESS as usize]);
let a: *const u8 = RTA_DATA!(attrs[IFLA_ADDRESS as usize]) as *const u8; let a: *const u8 = RTA_DATA!(attrs[IFLA_ADDRESS as usize]) as *const u8;
iface.hwAddr = format_address(a, alen as u32)?; iface.hwAddr = parser::format_address(a, alen as u32)?;
}
}
// get ip address info from av
let mut ads: Vec<IPAddress> = 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;
} }
// get ip address info from av let tlen = NLMSG_SPACE!(mem::size_of::<ifaddrmsg>());
let mut ads: Vec<IPAddress> = Vec::new(); if alh.nlmsg_len < tlen {
info!(
sl!(),
"invalid nlmsg! nlmsg_len: {}, nlmsg_space: {}", alh.nlmsg_len, tlen
);
break;
}
for address in &av { // Safe becahse we have checked avialable buffer space by NLMSG_SPACE above.
let alh: *const nlmsghdr = *address; let ifa = unsafe { &*(NLMSG_DATA!(alh) as *const ifaddrmsg) };
let ifa: *const ifaddrmsg = NLMSG_DATA!(alh) as *const ifaddrmsg; let arta: *mut rtattr = IFA_RTA!(ifa) as *mut rtattr;
let arta: *mut rtattr = IFA_RTA!(ifa) as *mut rtattr; let artalen = IFA_PAYLOAD!(alh) as u32;
if (*alh).nlmsg_type != RTM_NEWADDR { if ifa.ifa_index as u32 == ifi.ifi_index as u32 {
continue; // 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 mut tattr: *const rtattr = addrs[IFA_LOCAL as usize];
if !addrs[IFA_ADDRESS as usize].is_null() {
tattr = addrs[IFA_ADDRESS as usize];
} }
let tlen = NLMSG_SPACE!(mem::size_of::<ifaddrmsg>()); one.mask = format!("{}", ifa.ifa_prefixlen);
if (*alh).nlmsg_len < tlen { one.family = IPFamily::v4;
info!( if ifa.ifa_family == libc::AF_INET6 as u8 {
sl!(), one.family = IPFamily::v6;
"invalid nlmsg! nlmsg_len: {}, nlmsg_space: {}",
(*alh).nlmsg_len,
tlen
);
break;
} }
let artalen = IFA_PAYLOAD!(alh) as u32; // Safe because parse_attrs() returns valid pointers.
unsafe {
if (*ifa).ifa_index as u32 == (*ifi).ifi_index as u32 {
// found target addresses
// parse attributes and fill out Interface
let addrs = parse_attrs(arta, artalen, (IFA_MAX + 1) as usize)?;
// fill address field of Interface
let mut one: IPAddress = IPAddress::default();
let mut tattr: *const rtattr = addrs[IFA_LOCAL as usize];
if addrs[IFA_ADDRESS as usize] as i64 != 0 {
tattr = addrs[IFA_ADDRESS as usize];
}
one.mask = format!("{}", (*ifa).ifa_prefixlen);
let a: *const u8 = RTA_DATA!(tattr) as *const u8; let a: *const u8 = RTA_DATA!(tattr) as *const u8;
let alen = RTA_PAYLOAD!(tattr); let alen = RTA_PAYLOAD!(tattr);
one.family = IPFamily::v4; one.address = parser::format_address(a, alen as u32)?;
if (*ifa).ifa_family == libc::AF_INET6 as u8 {
one.family = IPFamily::v6;
}
// only handle IPv4 for now
// if (*ifa).ifa_family == libc::AF_INET as u8{
one.address = format_address(a, alen as u32)?;
//}
ads.push(one);
} }
}
iface.IPAddresses = RepeatedField::from_vec(ads); ads.push(one);
ifaces.push(iface); }
} }
iface.IPAddresses = RepeatedField::from_vec(ads);
ifaces.push(iface);
} }
Ok(ifaces) Ok(ifaces)
@ -270,67 +252,63 @@ impl super::RtnlHandle {
// attribute in dump request // attribute in dump request
// Fix Me: think about othe tables, ipv6.. // Fix Me: think about othe tables, ipv6..
let mut rs: Vec<Route> = Vec::new(); let mut rs: Vec<Route> = Vec::new();
let (_srv, rv) = self.dump_all_routes()?;
unsafe { // parse out routes and store in rs
let (_srv, rv) = self.dump_all_route_msgs()?; 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::<rtmsg>());
if nlh.nlmsg_len < tlen {
info!(
sl!(),
"invalid nlmsg! nlmsg_len: {}, nlmsg_spae: {}", nlh.nlmsg_len, tlen
);
break;
}
// parse out routes and store in rs // Safe because we have just validated available buffer space above.
for r in &rv { let rtm = unsafe { &mut *(NLMSG_DATA!(nlh) as *mut rtmsg) };
let nlh: *const nlmsghdr = *r; if rtm.rtm_table != RT_TABLE_MAIN as u8 {
let rtm: *const rtmsg = NLMSG_DATA!(nlh) as *const rtmsg; 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)? };
if (*nlh).nlmsg_type != RTM_NEWROUTE && (*nlh).nlmsg_type != RTM_DELROUTE { let t = attrs[RTA_TABLE as usize];
info!(sl!(), "not route message!"); if !t.is_null() {
// Safe because parse_attrs() returns valid pointers
let table = unsafe { getattr32(t) };
if table != RT_TABLE_MAIN {
continue; continue;
} }
}
let tlen = NLMSG_SPACE!(mem::size_of::<rtmsg>()); // find source, destination, gateway, scope, and and device name
if (*nlh).nlmsg_len < tlen { let mut t = attrs[RTA_DST as usize];
info!( let mut rte: Route = Route::default();
sl!(),
"invalid nlmsg! nlmsg_len: {}, nlmsg_spae: {}",
(*nlh).nlmsg_len,
tlen
);
break;
}
let rta: *mut rtattr = RTM_RTA!(rtm) as *mut rtattr;
if (*rtm).rtm_table != RT_TABLE_MAIN as u8 {
continue;
}
let rtalen = RTM_PAYLOAD!(nlh) as u32;
let attrs = parse_attrs(rta, rtalen, (RTA_MAX + 1) as usize)?;
let t = attrs[RTA_TABLE as usize];
if t as i64 != 0 {
let table = 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 // destination
if t as i64 != 0 { if !t.is_null() {
let data: *const u8 = RTA_DATA!(t) as *const u8; let data: *const u8 = RTA_DATA!(t) as *const u8;
let len = RTA_PAYLOAD!(t) as u32; let len = RTA_PAYLOAD!(t) as u32;
rte.dest = format!("{}/{}", format_address(data, len)?, (*rtm).rtm_dst_len); rte.dest =
format!("{}/{}", parser::format_address(data, len)?, rtm.rtm_dst_len);
} }
// gateway // gateway
t = attrs[RTA_GATEWAY as usize]; t = attrs[RTA_GATEWAY as usize];
if t as i64 != 0 { if !t.is_null() {
let data: *const u8 = RTA_DATA!(t) as *const u8; let data: *const u8 = RTA_DATA!(t) as *const u8;
let len = RTA_PAYLOAD!(t) as u32; let len = RTA_PAYLOAD!(t) as u32;
rte.gateway = format_address(data, len)?; rte.gateway = parser::format_address(data, len)?;
// for gateway, destination is 0.0.0.0 // for gateway, destination is 0.0.0.0
rte.dest = "0.0.0.0".to_string(); rte.dest = "0.0.0.0".to_string();
@ -338,53 +316,35 @@ impl super::RtnlHandle {
// source // source
t = attrs[RTA_SRC as usize]; t = attrs[RTA_SRC as usize];
if t.is_null() {
if t as i64 == 0 {
t = attrs[RTA_PREFSRC as usize]; t = attrs[RTA_PREFSRC as usize];
} }
if !t.is_null() {
if t as i64 != 0 {
let data: *const u8 = RTA_DATA!(t) as *const u8; let data: *const u8 = RTA_DATA!(t) as *const u8;
let len = RTA_PAYLOAD!(t) as u32; let len = RTA_PAYLOAD!(t) as u32;
rte.source = parser::format_address(data, len)?;
rte.source = format_address(data, len)?; if rtm.rtm_src_len != 0 {
rte.source = format!("{}/{}", rte.source.as_str(), rtm.rtm_src_len);
if (*rtm).rtm_src_len != 0 {
rte.source = format!("{}/{}", rte.source.as_str(), (*rtm).rtm_src_len);
} }
} }
// scope // scope
rte.scope = (*rtm).rtm_scope as u32; rte.scope = rtm.rtm_scope as u32;
// oif // oif
t = attrs[RTA_OIF as usize]; t = attrs[RTA_OIF as usize];
if t as i64 != 0 { if !t.is_null() {
let data: *const i32 = RTA_DATA!(t) as *const i32; let data = &*(RTA_DATA!(t) as *const i32);
assert_eq!(RTA_PAYLOAD!(t), 4); assert_eq!(RTA_PAYLOAD!(t), 4);
/*
let mut n: Vec<u8> = vec![0; libc::IF_NAMESIZE];
let np: *mut libc::c_char = n.as_mut_ptr() as *mut libc::c_char;
let tn = libc::if_indextoname(*data as u32,
np);
if tn as i64 == 0 {
info!(sl!(), "no name?");
} else {
info!(sl!(), "name(indextoname): {}", String::from_utf8(n)?);
}
// std::process::exit(-1);
*/
rte.device = self rte.device = self
.get_name_by_index(*data) .get_name_by_index(*data)
.unwrap_or("unknown".to_string()); .unwrap_or("unknown".to_string());
} }
rs.push(rte);
} }
rs.push(rte);
} }
Ok(rs) Ok(rs)
@ -399,60 +359,57 @@ impl super::RtnlHandle {
} }
pub fn add_one_arp_neighbor(&mut self, neigh: &ARPNeighbor) -> Result<()> { pub fn add_one_arp_neighbor(&mut self, neigh: &ARPNeighbor) -> Result<()> {
if neigh.toIPAddress.is_none() { let to_ip = match neigh.toIPAddress.as_ref() {
return nix_errno(Errno::EINVAL); None => return nix_errno(Errno::EINVAL),
} Some(v) => {
let to_ip = &neigh.toIPAddress.as_ref().unwrap().address; if v.address.is_empty() {
if to_ip.is_empty() { return nix_errno(Errno::EINVAL);
return nix_errno(Errno::EINVAL); }
} v.address.as_ref()
}
};
let dev = self.find_link_by_name(&neigh.device)?; let dev = self.find_link_by_name(&neigh.device)?;
let mut v: Vec<u8> = vec![0; 2048]; let mut v: Vec<u8> = vec![0; DEFAULT_NETLINK_BUF_SIZE];
unsafe { // Safe because we have allocated enough buffer space.
// init let nlh = unsafe { &mut *(v.as_mut_ptr() as *mut nlmsghdr) };
let mut nlh: *mut nlmsghdr = v.as_mut_ptr() as *mut nlmsghdr; let ndm = unsafe { &mut *(NLMSG_DATA!(nlh) as *mut ndmsg) };
let mut ndm: *mut ndmsg = NLMSG_DATA!(nlh) as *mut ndmsg;
(*nlh).nlmsg_len = NLMSG_LENGTH!(std::mem::size_of::<ndmsg>()) as u32; nlh.nlmsg_len = NLMSG_LENGTH!(std::mem::size_of::<ndmsg>()) as u32;
(*nlh).nlmsg_type = RTM_NEWNEIGH; nlh.nlmsg_type = RTM_NEWNEIGH;
(*nlh).nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE | NLM_F_EXCL; nlh.nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE | NLM_F_EXCL;
self.assign_seqnum(nlh);
self.seq += 1; ndm.ndm_family = libc::AF_UNSPEC as __u8;
self.dump = self.seq; ndm.ndm_state = IFA_F_PERMANENT as __u16;
(*nlh).nlmsg_seq = self.seq; // process lladdr
if neigh.lladdr != "" {
let llabuf = parser::parse_mac_addr(&neigh.lladdr)?;
(*ndm).ndm_family = libc::AF_UNSPEC as __u8; // Safe because we have allocated enough buffer space.
(*ndm).ndm_state = IFA_F_PERMANENT as __u16; unsafe { nlh.addattr_var(NDA_LLADDR, llabuf.as_ptr() as *const u8, llabuf.len()) };
// process lladdr
if neigh.lladdr != "" {
let llabuf = parse_mac_addr(&neigh.lladdr)?;
addattr_var(nlh, NDA_LLADDR, llabuf.as_ptr() as *const u8, llabuf.len());
}
// process destination
let (family, ip_data) = parse_addr(&to_ip)?;
(*ndm).ndm_family = family;
addattr_var(nlh, NDA_DST, ip_data.as_ptr() as *const u8, ip_data.len());
// 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)?;
} }
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_ptr() as *const u8, ip_data.len()) };
// 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(()) Ok(())
} }
} }
@ -465,9 +422,8 @@ impl From<IPAddress> for RtIPAddr {
libc::AF_INET6 libc::AF_INET6
} as __u8; } as __u8;
let ip_mask = scan_fmt!(ipi.mask.as_str(), "{}", u8).unwrap(); let ip_mask = parser::parse_u8(ipi.mask.as_str(), 10).unwrap();
let addr = parser::parse_ip_addr(ipi.address.as_ref()).unwrap();
let addr = parse_ipaddr(ipi.address.as_ref()).unwrap();
Self { Self {
ip_family, ip_family,
@ -492,21 +448,21 @@ impl From<Route> for RtRoute {
let (dest, dst_len) = if r.dest.is_empty() { let (dest, dst_len) = if r.dest.is_empty() {
(Some(vec![0 as u8; 4]), 0) (Some(vec![0 as u8; 4]), 0)
} else { } else {
let (dst, mask) = parse_cider(r.dest.as_str()).unwrap(); let (dst, mask) = parser::parse_cidr(r.dest.as_str()).unwrap();
(Some(dst), mask) (Some(dst), mask)
}; };
let (source, src_len) = if r.source.is_empty() { let (source, src_len) = if r.source.is_empty() {
(None, 0) (None, 0)
} else { } else {
let (src, mask) = parse_cider(r.source.as_str()).unwrap(); let (src, mask) = parser::parse_cidr(r.source.as_str()).unwrap();
(Some(src), mask) (Some(src), mask)
}; };
let gateway = if r.gateway.is_empty() { let gateway = if r.gateway.is_empty() {
None None
} else { } else {
Some(parse_ipaddr(r.gateway.as_str()).unwrap()) Some(parser::parse_ip_addr(r.gateway.as_str()).unwrap())
}; };
/* /*
@ -618,4 +574,3 @@ mod tests {
clean_env_for_test_add_one_arp_neighbor(dummy_name, to_ip); clean_env_for_test_add_one_arp_neighbor(dummy_name, to_ip);
} }
} }
//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,203 @@
// 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<u8> {
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<Vec<u8>> {
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<Vec<u8>> {
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<u8>)> {
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>, 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>, 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<Vec<u8>> {
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 addr and len are valid.
pub unsafe fn format_address(addr: *const u8, len: u32) -> Result<String> {
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<u8> = 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");
}
*/
}