From eb46c3d1ecc8aea4c49ae038344cb085a2bee4d8 Mon Sep 17 00:00:00 2001 From: Christian Ebner Date: Tue, 23 Apr 2019 12:44:56 +0200 Subject: [PATCH] src/tools/procfs.rs: implement read_proc_net_ipv6_route() Signed-off-by: Christian Ebner --- src/tools/procfs.rs | 82 +++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 80 insertions(+), 2 deletions(-) diff --git a/src/tools/procfs.rs b/src/tools/procfs.rs index ab855e31..94be5bf1 100644 --- a/src/tools/procfs.rs +++ b/src/tools/procfs.rs @@ -1,10 +1,11 @@ use failure::*; +use std::u32; use std::fs::OpenOptions; use std::io::{BufRead, BufReader}; use std::collections::HashSet; use std::process; -use std::net::Ipv4Addr; +use std::net::{Ipv4Addr, Ipv6Addr}; use crate::tools; use lazy_static::lazy_static; use regex::Regex; @@ -277,7 +278,7 @@ fn hex_nibble(c: u8) -> Result { fn hexstr_to_ipv4addr>(hex: T) -> Result { let hex = hex.as_ref(); if hex.len() != 8 { - bail!("Error while converting hex string to IP address: unexpected string length"); + bail!("Error while converting hex string to IPv4 address: unexpected string length"); } let mut addr: [u8; 4] = unsafe { std::mem::uninitialized() }; @@ -329,3 +330,80 @@ pub fn read_proc_net_route() -> Result, Error> { Ok(result) } + +fn hexstr_to_ipv6addr>(hex: T) -> Result { + let hex = hex.as_ref(); + if hex.len() != 32 { + bail!("Error while converting hex string to IPv6 address: unexpected string length"); + } + + let mut addr: [u8; 16] = unsafe { std::mem::uninitialized() }; + for i in 0..16 { + addr[i] = (hex_nibble(hex[i * 2])? << 4) + hex_nibble(hex[i * 2 + 1])?; + } + + Ok(Ipv6Addr::from(addr)) +} + +fn hexstr_to_u8>(hex: T) -> Result { + let hex = hex.as_ref(); + if hex.len() != 2 { + bail!("Error while converting hex string to u8: unexpected string length"); + } + + Ok((hex_nibble(hex[0])? << 4) + hex_nibble(hex[1])?) +} + +fn hexstr_to_u32>(hex: T) -> Result { + let hex = hex.as_ref(); + if hex.len() != 8 { + bail!("Error while converting hex string to u32: unexpected string length"); + } + + let mut bytes: [u8; 4] = unsafe { std::mem::uninitialized() }; + for i in 0..4 { + bytes[i] = (hex_nibble(hex[i * 2])? << 4) + hex_nibble(hex[i * 2 + 1])?; + } + + Ok(u32::from_be_bytes(bytes)) +} + +#[derive(Debug)] +pub struct ProcFsNetIPv6Route { + pub dest: Ipv6Addr, + pub prefix: u8, + pub gateway: Ipv6Addr, + pub metric: u32, + pub iface: String, +} + +pub fn read_proc_net_ipv6_route() -> Result, Error> { + let path = "/proc/net/ipv6_route"; + let file = OpenOptions::new().read(true).open(&path)?; + let err = "Error while parsing '/proc/net/ipv6_route"; + + let mut result = Vec::new(); + for line in BufReader::new(&file).lines() { + let content = line?; + if content.is_empty() { continue; } + let mut iter = content.split_whitespace(); + + let dest = iter.next().ok_or(format_err!("{}", err))?; + let dest_prefix_len = iter.next().ok_or(format_err!("{}", err))?; + for _ in 0..2 { iter.next(); } + let nexthop = iter.next().ok_or(format_err!("{}", err))?; + let metric = iter.next().ok_or(format_err!("{}", err))?; + for _ in 0..3 { iter.next(); } + let iface = iter.next().ok_or(format_err!("{}", err))?; + + result.push(ProcFsNetIPv6Route { + dest: hexstr_to_ipv6addr(dest)?, + prefix: hexstr_to_u8(dest_prefix_len)?, + gateway: hexstr_to_ipv6addr(nexthop)?, + metric: hexstr_to_u32(metric)?, + iface: iface.to_string(), + }); + } + + Ok(result) +}