#[macro_use]
#[allow(dead_code)]
mod helper;
use crate::helper::pfcli;
use assert_matches::assert_matches;
use std::net::{Ipv4Addr, Ipv6Addr};
static ANCHOR_NAME: &str = "pfctl-rs.integration.testing.redirect-rules";
fn port_mapping_rule(ip: pfctl::Ip) -> pfctl::RedirectRule {
pfctl::RedirectRuleBuilder::default()
.action(pfctl::RedirectRuleAction::Redirect)
.to(pfctl::Endpoint::new(ip, 3000))
.redirect_to(pfctl::Endpoint::new(ip, 4000))
.build()
.unwrap()
}
fn redirect_rule_ipv4() -> pfctl::RedirectRule {
port_mapping_rule(pfctl::Ip::from(Ipv4Addr::new(127, 0, 0, 1)))
}
fn redirect_rule_ipv6() -> pfctl::RedirectRule {
port_mapping_rule(pfctl::Ip::from(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1)))
}
fn before_each() {
pfctl::PfCtl::new()
.unwrap()
.try_add_anchor(ANCHOR_NAME, pfctl::AnchorKind::Redirect)
.unwrap();
}
fn after_each() {
pfcli::flush_rules(ANCHOR_NAME, pfcli::FlushOptions::Nat);
pfctl::PfCtl::new()
.unwrap()
.try_remove_anchor(ANCHOR_NAME, pfctl::AnchorKind::Redirect)
.unwrap();
}
test!(flush_redirect_rules {
let mut pf = pfctl::PfCtl::new().unwrap();
let test_rules = [redirect_rule_ipv4(), redirect_rule_ipv6()];
for rule in test_rules.iter() {
assert_matches!(pf.add_redirect_rule(ANCHOR_NAME, rule), Ok(()));
assert_eq!(pfcli::get_nat_rules(ANCHOR_NAME).len(), 1);
assert_matches!(pf.flush_rules(ANCHOR_NAME, pfctl::RulesetKind::Redirect), Ok(()));
assert_eq!(
pfcli::get_nat_rules(ANCHOR_NAME),
&[] as &[&str]
);
}
});
test!(add_redirect_rule_ipv4 {
let mut pf = pfctl::PfCtl::new().unwrap();
let rule = redirect_rule_ipv4();
assert_matches!(pf.add_redirect_rule(ANCHOR_NAME, &rule), Ok(()));
assert_eq!(
pfcli::get_nat_rules(ANCHOR_NAME),
&["rdr inet from any to 127.0.0.1 port = 3000 -> 127.0.0.1 port 4000"]
);
});
test!(add_redirect_rule_ipv6 {
let mut pf = pfctl::PfCtl::new().unwrap();
let rule = redirect_rule_ipv6();
assert_matches!(pf.add_redirect_rule(ANCHOR_NAME, &rule), Ok(()));
assert_eq!(
pfcli::get_nat_rules(ANCHOR_NAME),
&["rdr inet6 from any to ::1 port = 3000 -> ::1 port 4000"]
);
});
test!(add_redirect_rule_on_interface {
let mut pf = pfctl::PfCtl::new().unwrap();
let rule = pfctl::RedirectRuleBuilder::default()
.action(pfctl::RedirectRuleAction::Redirect)
.log(pfctl::RuleLog::ExcludeMatchingState)
.interface("lo0")
.from(Ipv4Addr::new(1, 2, 3, 4))
.redirect_to(pfctl::Port::from(1237))
.build()
.unwrap();
assert_matches!(pf.add_redirect_rule(ANCHOR_NAME, &rule), Ok(()));
assert_eq!(
pfcli::get_nat_rules(ANCHOR_NAME),
&["rdr log on lo0 inet from 1.2.3.4 to any -> any port 1237"]
);
});