#![deny(missing_docs)]
use failure::{
Error,
Fail,
};
use pest::{
iterators::Pair,
Parser,
};
use pnet::datalink::{
self,
NetworkInterface,
};
use std::{
cmp::Ordering,
net::IpAddr,
rc::Rc,
str::FromStr,
};
pub mod rfc;
mod routes;
use crate::{
rfc::WithRfc6890,
routes::read_default_interface_name,
};
mod grammar;
use crate::grammar::{
IfTParser,
Rule,
};
#[derive(Debug, Fail)]
pub enum IfTError {
#[fail(display = "{}", _0)]
Utf8(#[fail(cause)] ::std::string::FromUtf8Error),
#[fail(display = "{}", _0)]
Io(#[fail(cause)] ::std::io::Error),
#[fail(display = "{}", _0)]
Pest(::pest::error::Error<Rule>),
#[fail(display = "unable to parse flag {}", _0)]
IfTFlagError(String),
#[fail(display = "unable to use argument {}", _0)]
IfTArgumentError(String),
}
pub fn eval(s: &str) -> Result<Vec<IpAddr>, Error> {
let parsed = parse_ift_string(s)?;
Ok(parsed.result.into_iter().map(|ip2ni| ip2ni.ip_addr).collect())
}
pub fn evals(s: &str) -> Option<IpAddr> { eval(s).unwrap().into_iter().next() }
#[derive(Debug)]
struct Ip2NetworkInterface {
ip_addr: IpAddr,
interface: Option<Rc<NetworkInterface>>,
}
#[derive(Debug)]
struct IfTResult {
result: Vec<Ip2NetworkInterface>,
}
fn parse_ift_string(template_str: &str) -> Result<IfTResult, Error> {
let template = IfTParser::parse(Rule::template, template_str)?.next().unwrap();
let rfc: WithRfc6890 = WithRfc6890::create();
Ok(parse_expression(template, &rfc)?)
}
enum IfTFlag {
UP,
DOWN,
}
impl FromStr for IfTFlag {
type Err = IfTError;
fn from_str(flag: &str) -> ::std::result::Result<Self, Self::Err> {
match flag {
"up" => Ok(IfTFlag::UP),
"down" => Ok(IfTFlag::DOWN),
_ => Err(IfTError::IfTFlagError(flag.to_owned())),
}
}
}
fn filter_by_flag(ip: &Ip2NetworkInterface, flag: &IfTFlag) -> bool {
match ip.interface.clone() {
Some(int) => match flag {
IfTFlag::UP => int.is_up(),
IfTFlag::DOWN => !int.is_up(),
},
_ => false,
}
}
fn filter_by_name(ip: &Ip2NetworkInterface, interface_name: &str) -> bool {
match ip.interface.clone() {
Some(int) => int.name == interface_name,
_ => false,
}
}
fn all_interfaces() -> Vec<Ip2NetworkInterface> {
let interfaces = datalink::interfaces();
let mut ret: Vec<Ip2NetworkInterface> = vec![];
for interface in interfaces {
let rc = Rc::new(interface);
for ipn in (*rc.ips).iter() {
ret.push(Ip2NetworkInterface {
ip_addr: ipn.ip(),
interface: Some(rc.clone()),
})
}
}
ret
}
fn rule_filter_name(iter: Vec<Ip2NetworkInterface>, name: &str) -> IfTResult {
IfTResult {
result: iter.into_iter().filter(|ip| filter_by_name(ip, name)).collect(),
}
}
fn parse_expression(pair: Pair<'_, Rule>, rfc: &WithRfc6890) -> Result<IfTResult, Error> {
match pair.as_rule() {
Rule::expression => {
let mut iter = pair.into_inner();
let producer_pair = iter.next().unwrap().into_inner().next().unwrap();
let mut base: IfTResult = parse_producer(producer_pair)?;
for p in iter {
match p.as_rule() {
Rule::filter => base = parse_filter(base, p.into_inner().next().unwrap(), rfc)?,
Rule::sort => base = parse_sort(base, p.into_inner().next().unwrap())?,
_ => unreachable!("only filters and sorts should follow. saw {:?}", p.as_rule()),
}
}
Ok(base)
}
_ => unreachable!("unable to parse rule {:?}", pair.as_rule()),
}
}
fn parse_producer(pair: Pair<'_, Rule>) -> Result<IfTResult, Error> {
let rfc = WithRfc6890::create();
match pair.as_rule() {
Rule::GetInterface => {
let interface_name = pair.into_inner().next().unwrap().as_str();
Ok(rule_filter_name(all_interfaces(), interface_name))
}
Rule::GetAllInterfaces => Ok(IfTResult {
result: all_interfaces(),
}),
Rule::GetPrivateInterfaces => rule_sort_by_attribute(
IfTResult {
result: all_interfaces()
.into_iter()
.filter(|ip| filter_by_flag(&ip, &IfTFlag::UP))
.filter(|ip| rfc.is_forwardable(&ip.ip_addr))
.collect(),
},
"default",
),
_ => unreachable!("unable to parse rule {:?}", pair.as_rule()),
}
}
fn parse_filter(prev: IfTResult, pair: Pair<'_, Rule>, rfc: &WithRfc6890) -> Result<IfTResult, Error> {
Ok(match pair.as_rule() {
Rule::FilterIPv4 => IfTResult {
result: prev
.result
.into_iter()
.filter(|ip2if| ip2if.ip_addr.is_ipv4())
.collect(),
},
Rule::FilterIPv6 => IfTResult {
result: prev
.result
.into_iter()
.filter(|ip2if| ip2if.ip_addr.is_ipv6())
.collect(),
},
Rule::FilterName => {
let name = pair.into_inner().next().unwrap().as_str();
rule_filter_name(prev.result, name)
}
Rule::FilterFlags => {
let flag = pair.into_inner().next().unwrap().as_str();
let flag: IfTFlag = flag.parse()?;
IfTResult {
result: prev.result.into_iter().filter(|ip| filter_by_flag(ip, &flag)).collect(),
}
}
Rule::FilterForwardable => IfTResult {
result: prev
.result
.into_iter()
.filter(|ip| rfc.is_forwardable(&ip.ip_addr))
.collect(),
},
Rule::FilterGlobal => IfTResult {
result: prev
.result
.into_iter()
.filter(|ip| rfc.is_global(&ip.ip_addr))
.collect(),
},
Rule::FilterFirst => IfTResult {
result: prev.result.into_iter().next().into_iter().collect(),
},
Rule::FilterLast => IfTResult {
result: prev.result.into_iter().last().into_iter().collect(),
},
_ => unreachable!("unable to parse rule {:?}", pair.as_rule()),
})
}
fn sort_default_less(
default_interface_name: String,
) -> impl FnMut(&Ip2NetworkInterface, &Ip2NetworkInterface) -> Ordering {
move |a, b| {
if let Some(ref ifa) = a.interface {
if let Some(ref ifb) = b.interface {
if ifa.name == default_interface_name {
return Ordering::Less;
} else if ifb.name == default_interface_name {
return Ordering::Greater;
}
}
}
Ordering::Equal
}
}
fn parse_sort(prev: IfTResult, pair: Pair<'_, Rule>) -> Result<IfTResult, Error> {
match pair.as_rule() {
Rule::SortBy => {
let attribute: &str = pair.into_inner().next().unwrap().as_str();
rule_sort_by_attribute(prev, attribute)
}
_ => unreachable!("unable to parse rule {:?}", pair.as_rule()),
}
}
fn rule_sort_by_attribute(prev: IfTResult, attribute: &str) -> Result<IfTResult, Error> {
let default_interface = read_default_interface_name()?;
let sorter = match attribute {
"default" => Ok(sort_default_less(default_interface)),
_ => Err(IfTError::IfTArgumentError(attribute.to_owned())),
}?;
let mut result = prev.result;
result.sort_by(sorter);
Ok(IfTResult { result })
}