use std::net::{Ipv4Addr, Ipv6Addr};
use windows_sys::core::GUID;
use wfp::*;
#[test]
#[cfg_attr(not(feature = "wfp-integration-tests"), ignore)]
fn test_add_filters_and_sublayer() {
let mut engine = FilterEngineBuilder::default()
.dynamic()
.open()
.expect("Should be able to open filter engine");
let transaction = Transaction::new(&mut engine).expect("Should be able to create transaction");
let test_guid = GUID::from_u128(0x12345678_1234_5678_9abc_def012345678);
SubLayerBuilder::default()
.name("Test Sublayer")
.description("Test sublayer for integration tests")
.weight(100)
.guid(test_guid)
.add(&transaction)
.expect("Should be able to add sublayer");
let http_condition = PortConditionBuilder::remote().equal(80).build();
let https_condition = PortConditionBuilder::remote().equal(443).build();
let tcp_condition = ProtocolConditionBuilder::tcp().build();
FilterBuilder::default()
.name("HTTP Block Filter")
.description("Blocks HTTP traffic")
.action(ActionType::Block)
.layer(Layer::ConnectV4)
.condition(http_condition)
.condition(tcp_condition.clone())
.sublayer(test_guid)
.add(&transaction)
.expect("Should be able to add HTTP filter");
FilterBuilder::default()
.name("HTTPS Permit Filter")
.description("Permits HTTPS traffic")
.action(ActionType::Permit)
.layer(Layer::ConnectV4)
.condition(https_condition)
.condition(tcp_condition)
.sublayer(test_guid)
.weight(FilterWeight::Exact(12345))
.add(&transaction)
.expect("Should be able to add HTTPS filter");
transaction
.commit()
.expect("Should be able to commit multiple filters");
}
#[test]
#[cfg_attr(not(feature = "wfp-integration-tests"), ignore)]
fn test_add_provider_and_attach_filters() {
let mut engine = FilterEngineBuilder::default()
.dynamic()
.open()
.expect("Should be able to open filter engine");
let transaction = Transaction::new(&mut engine).expect("Should be able to create transaction");
let test_provider_guid = GUID::from_u128(0xdeadbeef_1111_2222_3333_444455556666);
let test_sublayer_guid = GUID::from_u128(0xdeadbeef_aaaa_bbbb_cccc_ddddeeeeffff);
let test_filter_guid = GUID::from_u128(0xdeadbeef_1234_5678_9abc_def012345678);
ProviderBuilder::default()
.name("Test Provider")
.description("Provider for integration tests")
.guid(test_provider_guid)
.add(&transaction)
.expect("Should be able to add provider");
SubLayerBuilder::default()
.name("Test Provider Sublayer")
.description("Sublayer attached to test provider")
.weight(100)
.guid(test_sublayer_guid)
.provider(test_provider_guid)
.add(&transaction)
.expect("Should be able to add sublayer");
FilterBuilder::default()
.name("Test Provider Filter")
.description("Filter attached to test provider")
.action(ActionType::Block)
.layer(Layer::ConnectV4)
.sublayer(test_sublayer_guid)
.provider(test_provider_guid)
.guid(test_filter_guid)
.add(&transaction)
.expect("Should be able to add filter");
transaction
.commit()
.expect("Should be able to commit provider transaction");
}
#[test]
#[cfg_attr(not(feature = "wfp-integration-tests"), ignore)]
fn test_app_id_condition() {
let mut engine = FilterEngineBuilder::default()
.dynamic()
.open()
.expect("Should be able to open filter engine");
let transaction = Transaction::new(&mut engine).expect("Should be able to create transaction");
let test_guid = windows_sys::core::GUID::from_u128(0xaabbccdd_1234_5678_9abc_def012345678);
SubLayerBuilder::default()
.name("Test AppId Sublayer")
.description("Test sublayer for app ID integration tests")
.weight(100)
.guid(test_guid)
.add(&transaction)
.expect("Should be able to add sublayer");
let bad_result = AppIdConditionBuilder::default().equal(r"C:\nonexistent\fake.exe");
assert!(
bad_result.is_err(),
"Should return Err for a nonexistent executable path"
);
let app_condition = AppIdConditionBuilder::default()
.equal(r"C:\Windows\System32\ping.exe")
.expect("Should be able to get app ID from ping.exe");
FilterBuilder::default()
.name("Ping Block Filter")
.description("Blocks ping.exe outbound traffic")
.action(ActionType::Block)
.layer(Layer::ConnectV4)
.condition(app_condition.build())
.sublayer(test_guid)
.weight(WeightRange::try_from(15).unwrap())
.add(&transaction)
.expect("Should be able to add app ID filter");
transaction
.commit()
.expect("Should be able to commit app ID filter transaction");
}
#[test]
#[cfg_attr(not(feature = "wfp-integration-tests"), ignore)]
fn test_ndp_filter() {
let mut engine = FilterEngineBuilder::default()
.dynamic()
.open()
.expect("Should be able to open filter engine");
let transaction = Transaction::new(&mut engine).expect("Should be able to create transaction");
let test_guid = GUID::from_u128(0xfeed1234_5678_9abc_def0_123456789abc);
SubLayerBuilder::default()
.name("Test NDP Sublayer")
.description("Test sublayer for NDP integration test")
.weight(100)
.guid(test_guid)
.add(&transaction)
.expect("Should be able to add sublayer");
let outbound_types = [133u8, 135, 136];
let inbound_types = [134u8, 135, 136, 137];
for t in outbound_types {
FilterBuilder::default()
.name("NDP (outbound)")
.description("Permits outbound ICMPv6 NDP traffic")
.action(ActionType::Permit)
.layer(Layer::ConnectV6)
.condition(ProtocolConditionBuilder::icmpv6().build())
.condition(IcmpConditionBuilder::r#type().equal(t).build())
.condition(IcmpConditionBuilder::code().equal(0).build())
.sublayer(test_guid)
.add(&transaction)
.expect("Should be able to add outbound NDP filter");
}
for t in inbound_types {
FilterBuilder::default()
.name("NDP (inbound)")
.description("Permits inbound ICMPv6 NDP traffic")
.action(ActionType::Permit)
.layer(Layer::AcceptV6)
.condition(ProtocolConditionBuilder::icmpv6().build())
.condition(IcmpConditionBuilder::r#type().equal(t).build())
.condition(IcmpConditionBuilder::code().equal(0).build())
.sublayer(test_guid)
.add(&transaction)
.expect("Should be able to add inbound NDP filter");
}
transaction
.commit()
.expect("Should be able to commit NDP filter transaction");
}
#[test]
#[cfg_attr(not(feature = "wfp-integration-tests"), ignore)]
fn test_local_interface_condition() {
let mut engine = FilterEngineBuilder::default()
.dynamic()
.open()
.expect("Should be able to open filter engine");
let transaction = Transaction::new(&mut engine).expect("Should be able to create transaction");
let test_guid = GUID::from_u128(0xbbccddee_2345_6789_abcd_ef0123456789);
SubLayerBuilder::default()
.name("Test Interface Sublayer")
.description("Test sublayer for interface condition integration tests")
.weight(100)
.guid(test_guid)
.add(&transaction)
.expect("Should be able to add sublayer");
let bad_result = InterfaceConditionBuilder::local().alias("definitely-not-an-interface-xyz");
assert!(
bad_result.is_err(),
"Should return Err for a nonexistent interface alias"
);
let iface_condition = InterfaceConditionBuilder::local()
.alias("Loopback Pseudo-Interface 1")
.expect("Should be able to resolve loopback interface alias to a LUID");
FilterBuilder::default()
.name("Loopback Permit Filter")
.description("Permits traffic bound to the loopback interface")
.action(ActionType::Permit)
.layer(Layer::ConnectV4)
.condition(iface_condition.build())
.sublayer(test_guid)
.add(&transaction)
.expect("Should be able to add interface filter");
transaction
.commit()
.expect("Should be able to commit interface filter transaction");
}
#[test]
#[cfg_attr(not(feature = "wfp-integration-tests"), ignore)]
fn test_ip_address_subnet_condition() {
let mut engine = FilterEngineBuilder::default()
.dynamic()
.open()
.expect("Should be able to open filter engine");
let transaction = Transaction::new(&mut engine).expect("Should be able to create transaction");
let test_guid = GUID::from_u128(0xbbccddee_1234_5678_9abc_def012345678);
SubLayerBuilder::default()
.name("Test IP Address Sublayer")
.description("Test sublayer for IP-prefix integration tests")
.weight(100)
.guid(test_guid)
.add(&transaction)
.expect("Should be able to add sublayer");
FilterBuilder::default()
.name("Permit 192.168.0.0/16")
.description("Permits the 192.168/16 range")
.action(ActionType::Permit)
.layer(Layer::ConnectV4)
.condition(
IpAddressConditionBuilder::remote()
.subnet_v4(Ipv4Addr::new(192, 168, 0, 0), 16)
.build(),
)
.sublayer(test_guid)
.add(&transaction)
.expect("Should be able to add v4 LAN filter");
FilterBuilder::default()
.name("Permit fe80::/10")
.description("Permits the IPv6 link-local range")
.action(ActionType::Permit)
.layer(Layer::ConnectV6)
.condition(
IpAddressConditionBuilder::remote()
.subnet_v6("fe80::".parse::<Ipv6Addr>().unwrap(), 10)
.build(),
)
.sublayer(test_guid)
.add(&transaction)
.expect("Should be able to add v6 link-local filter");
transaction
.commit()
.expect("Should be able to commit IP-address filter transaction");
}