use clap::Parser;
use ndisapi::{
ByteRange, DataLinkLayerFilter, DataLinkLayerFilterUnion, DirectionFlags, Eth8023Filter,
Eth802_3FilterFlags, EthRequest, EthRequestMut, FilterFlags, FilterLayerFlags, IcmpFilter,
IcmpFilterFlags, IntermediateBuffer, IpAddressV4, IpAddressV4Union, IpAddressV6, IpSubnetV4,
IpV4Filter, IpV4FilterFlags, IpV6Filter, IpV6FilterFlags, Ndisapi, NetworkLayerFilter,
NetworkLayerFilterUnion, PortRange, StaticFilter, StaticFilterTable, TcpUdpFilter,
TcpUdpFilterFlags, TransportLayerFilter, TransportLayerFilterUnion, ETHER_ADDR_LENGTH,
ETH_802_3, FILTER_PACKET_DROP, FILTER_PACKET_PASS, FILTER_PACKET_REDIRECT, ICMP, IPV4, IPV6,
IP_SUBNET_V4_TYPE, TCPUDP,
};
use smoltcp::wire::{
ArpPacket, EthernetFrame, EthernetProtocol, Icmpv4Packet, Icmpv6Packet, IpProtocol, Ipv4Packet,
Ipv6Packet, TcpPacket, UdpPacket,
};
use std::sync::{
atomic::{AtomicBool, Ordering},
Arc,
};
use windows::{
core::Result,
Win32::Foundation::{CloseHandle, HANDLE},
Win32::Networking::WinSock::{IN_ADDR, IN_ADDR_0, IN_ADDR_0_0},
Win32::System::Threading::{CreateEventW, ResetEvent, SetEvent, WaitForSingleObject},
};
#[derive(Parser)]
struct Cli {
#[clap(short, long)]
interface_index: usize,
#[clap(short, long, verbatim_doc_comment)]
filter: usize,
}
const ETH_P_RARP: u16 = 0x8035;
const ETH_P_ARP: u16 = 0x0806;
const IPPROTO_ICMP: u8 = 1;
const IPPROTO_TCP: u8 = 6;
const IPPROTO_UDP: u8 = 17;
const DNS_PORT: u16 = 53;
const HTTP_PORT: u16 = 80;
fn load_ipv4_dns_filters(ndisapi: &Ndisapi) -> Result<()> {
let filter_table = StaticFilterTable::<3>::from_filters([
StaticFilter::new(
0, DirectionFlags::PACKET_FLAG_ON_SEND,
FILTER_PACKET_REDIRECT,
FilterLayerFlags::NETWORK_LAYER_VALID | FilterLayerFlags::TRANSPORT_LAYER_VALID,
DataLinkLayerFilter::default(),
NetworkLayerFilter::new(
IPV4,
NetworkLayerFilterUnion {
ipv4: IpV4Filter::new(
IpV4FilterFlags::IP_V4_FILTER_PROTOCOL,
IpAddressV4::default(),
IpAddressV4::default(),
IPPROTO_UDP,
),
},
),
TransportLayerFilter::new(
TCPUDP,
TransportLayerFilterUnion {
tcp_udp: TcpUdpFilter::new(
TcpUdpFilterFlags::TCPUDP_DEST_PORT,
PortRange::default(),
PortRange::new(DNS_PORT, DNS_PORT),
0u8,
),
},
),
),
StaticFilter::new(
0, DirectionFlags::PACKET_FLAG_ON_RECEIVE,
FILTER_PACKET_REDIRECT,
FilterLayerFlags::NETWORK_LAYER_VALID | FilterLayerFlags::TRANSPORT_LAYER_VALID,
DataLinkLayerFilter::default(),
NetworkLayerFilter::new(
IPV4,
NetworkLayerFilterUnion {
ipv4: IpV4Filter::new(
IpV4FilterFlags::IP_V4_FILTER_PROTOCOL,
IpAddressV4::default(),
IpAddressV4::default(),
IPPROTO_UDP,
),
},
),
TransportLayerFilter::new(
TCPUDP,
TransportLayerFilterUnion {
tcp_udp: TcpUdpFilter::new(
TcpUdpFilterFlags::TCPUDP_SRC_PORT,
PortRange::new(DNS_PORT, DNS_PORT),
PortRange::default(),
0u8,
),
},
),
),
StaticFilter::new(
0, DirectionFlags::PACKET_FLAG_ON_RECEIVE | DirectionFlags::PACKET_FLAG_ON_SEND,
FILTER_PACKET_PASS,
FilterLayerFlags::empty(),
DataLinkLayerFilter::default(),
NetworkLayerFilter::default(),
TransportLayerFilter::default(),
),
]);
ndisapi.set_packet_filter_table(&filter_table)
}
fn load_http_ipv4v6_filters(ndisapi: &Ndisapi) -> Result<()> {
let filter_table = StaticFilterTable::<5>::from_filters([
StaticFilter::new(
0, DirectionFlags::PACKET_FLAG_ON_SEND,
FILTER_PACKET_REDIRECT,
FilterLayerFlags::NETWORK_LAYER_VALID | FilterLayerFlags::TRANSPORT_LAYER_VALID,
DataLinkLayerFilter::default(),
NetworkLayerFilter::new(
IPV4,
NetworkLayerFilterUnion {
ipv4: IpV4Filter::new(
IpV4FilterFlags::IP_V4_FILTER_PROTOCOL,
IpAddressV4::default(),
IpAddressV4::default(),
IPPROTO_TCP,
),
},
),
TransportLayerFilter::new(
TCPUDP,
TransportLayerFilterUnion {
tcp_udp: TcpUdpFilter::new(
TcpUdpFilterFlags::TCPUDP_DEST_PORT,
PortRange::default(),
PortRange::new(HTTP_PORT, HTTP_PORT),
0u8,
),
},
),
),
StaticFilter::new(
0, DirectionFlags::PACKET_FLAG_ON_RECEIVE,
FILTER_PACKET_REDIRECT,
FilterLayerFlags::NETWORK_LAYER_VALID | FilterLayerFlags::TRANSPORT_LAYER_VALID,
DataLinkLayerFilter::default(),
NetworkLayerFilter::new(
IPV4,
NetworkLayerFilterUnion {
ipv4: IpV4Filter::new(
IpV4FilterFlags::IP_V4_FILTER_PROTOCOL,
IpAddressV4::default(),
IpAddressV4::default(),
IPPROTO_TCP,
),
},
),
TransportLayerFilter::new(
TCPUDP,
TransportLayerFilterUnion {
tcp_udp: TcpUdpFilter::new(
TcpUdpFilterFlags::TCPUDP_SRC_PORT,
PortRange::new(HTTP_PORT, HTTP_PORT),
PortRange::default(),
0u8,
),
},
),
),
StaticFilter::new(
0, DirectionFlags::PACKET_FLAG_ON_SEND,
FILTER_PACKET_REDIRECT,
FilterLayerFlags::NETWORK_LAYER_VALID | FilterLayerFlags::TRANSPORT_LAYER_VALID,
DataLinkLayerFilter::default(),
NetworkLayerFilter::new(
IPV6,
NetworkLayerFilterUnion {
ipv6: IpV6Filter::new(
IpV6FilterFlags::IP_V6_FILTER_PROTOCOL,
IpAddressV6::default(),
IpAddressV6::default(),
IPPROTO_TCP,
),
},
),
TransportLayerFilter::new(
TCPUDP,
TransportLayerFilterUnion {
tcp_udp: TcpUdpFilter::new(
TcpUdpFilterFlags::TCPUDP_DEST_PORT,
PortRange::default(),
PortRange::new(HTTP_PORT, HTTP_PORT),
0u8,
),
},
),
),
StaticFilter::new(
0, DirectionFlags::PACKET_FLAG_ON_RECEIVE,
FILTER_PACKET_REDIRECT,
FilterLayerFlags::NETWORK_LAYER_VALID | FilterLayerFlags::TRANSPORT_LAYER_VALID,
DataLinkLayerFilter::default(),
NetworkLayerFilter::new(
IPV6,
NetworkLayerFilterUnion {
ipv6: IpV6Filter::new(
IpV6FilterFlags::IP_V6_FILTER_PROTOCOL,
IpAddressV6::default(),
IpAddressV6::default(),
IPPROTO_TCP,
),
},
),
TransportLayerFilter::new(
TCPUDP,
TransportLayerFilterUnion {
tcp_udp: TcpUdpFilter::new(
TcpUdpFilterFlags::TCPUDP_SRC_PORT,
PortRange::new(HTTP_PORT, HTTP_PORT),
PortRange::default(),
0u8,
),
},
),
),
StaticFilter::new(
0, DirectionFlags::PACKET_FLAG_ON_RECEIVE | DirectionFlags::PACKET_FLAG_ON_SEND,
FILTER_PACKET_PASS,
FilterLayerFlags::empty(),
DataLinkLayerFilter::default(),
NetworkLayerFilter::default(),
TransportLayerFilter::default(),
),
]);
ndisapi.set_packet_filter_table(&filter_table)
}
fn load_icmpv4_drop_filters(ndisapi: &Ndisapi) -> Result<()> {
let filter_table = StaticFilterTable::<1>::from_filters([
StaticFilter::new(
0, DirectionFlags::PACKET_FLAG_ON_SEND | DirectionFlags::PACKET_FLAG_ON_RECEIVE,
FILTER_PACKET_DROP,
FilterLayerFlags::NETWORK_LAYER_VALID,
DataLinkLayerFilter::default(),
NetworkLayerFilter::new(
IPV4,
NetworkLayerFilterUnion {
ipv4: IpV4Filter::new(
IpV4FilterFlags::IP_V4_FILTER_PROTOCOL,
IpAddressV4::default(),
IpAddressV4::default(),
IPPROTO_ICMP,
),
},
),
TransportLayerFilter::default(),
),
]);
ndisapi.set_packet_filter_table(&filter_table)
}
fn load_block_ntkernel_https_filters(ndisapi: &Ndisapi) -> Result<()> {
let filter_table = StaticFilterTable::<2>::from_filters([
StaticFilter::new(
0, DirectionFlags::PACKET_FLAG_ON_SEND,
FILTER_PACKET_DROP,
FilterLayerFlags::NETWORK_LAYER_VALID | FilterLayerFlags::TRANSPORT_LAYER_VALID,
DataLinkLayerFilter::default(),
NetworkLayerFilter::new(
IPV4,
NetworkLayerFilterUnion {
ipv4: IpV4Filter::new(
IpV4FilterFlags::IP_V4_FILTER_PROTOCOL
| IpV4FilterFlags::IP_V4_FILTER_DEST_ADDRESS,
IpAddressV4::default(),
IpAddressV4::new(
IP_SUBNET_V4_TYPE,
IpAddressV4Union {
ip_subnet: IpSubnetV4::new(
IN_ADDR {
S_un: IN_ADDR_0 {
S_un_b: IN_ADDR_0_0 {
s_b1: 95,
s_b2: 179,
s_b3: 146,
s_b4: 125,
},
},
},
IN_ADDR {
S_un: IN_ADDR_0 {
S_un_b: IN_ADDR_0_0 {
s_b1: 255,
s_b2: 255,
s_b3: 255,
s_b4: 255,
},
},
},
),
},
),
IPPROTO_TCP,
),
},
),
TransportLayerFilter::new(
TCPUDP,
TransportLayerFilterUnion {
tcp_udp: TcpUdpFilter::new(
TcpUdpFilterFlags::TCPUDP_DEST_PORT,
PortRange::default(),
PortRange::new(443, 443),
0u8,
),
},
),
),
StaticFilter::new(
0, DirectionFlags::PACKET_FLAG_ON_RECEIVE | DirectionFlags::PACKET_FLAG_ON_SEND,
FILTER_PACKET_PASS,
FilterLayerFlags::empty(),
DataLinkLayerFilter::default(),
NetworkLayerFilter::default(),
TransportLayerFilter::default(),
),
]);
ndisapi.set_packet_filter_table(&filter_table)
}
fn load_redirect_arp_filters(ndisapi: &Ndisapi) -> Result<()> {
let filter_table = StaticFilterTable::<3>::from_filters([
StaticFilter::new(
0, DirectionFlags::PACKET_FLAG_ON_SEND_RECEIVE,
FILTER_PACKET_REDIRECT,
FilterLayerFlags::DATA_LINK_LAYER_VALID,
DataLinkLayerFilter::new(
ETH_802_3,
DataLinkLayerFilterUnion {
eth_8023_filter: Eth8023Filter::new(
Eth802_3FilterFlags::ETH_802_3_PROTOCOL,
[0; ETHER_ADDR_LENGTH],
[0; ETHER_ADDR_LENGTH],
ETH_P_ARP,
),
},
),
NetworkLayerFilter::default(),
TransportLayerFilter::default(),
),
StaticFilter::new(
0, DirectionFlags::PACKET_FLAG_ON_SEND_RECEIVE,
FILTER_PACKET_REDIRECT,
FilterLayerFlags::DATA_LINK_LAYER_VALID,
DataLinkLayerFilter::new(
ETH_802_3,
DataLinkLayerFilterUnion {
eth_8023_filter: Eth8023Filter::new(
Eth802_3FilterFlags::ETH_802_3_PROTOCOL,
[0; ETHER_ADDR_LENGTH],
[0; ETHER_ADDR_LENGTH],
ETH_P_RARP,
),
},
),
NetworkLayerFilter::default(),
TransportLayerFilter::default(),
),
StaticFilter::new(
0, DirectionFlags::PACKET_FLAG_ON_RECEIVE | DirectionFlags::PACKET_FLAG_ON_SEND,
FILTER_PACKET_PASS,
FilterLayerFlags::empty(),
DataLinkLayerFilter::default(),
NetworkLayerFilter::default(),
TransportLayerFilter::default(),
),
]);
ndisapi.set_packet_filter_table(&filter_table)
}
fn load_redirect_icmp_req_filters(ndisapi: &Ndisapi) -> Result<()> {
let filter_table = StaticFilterTable::<2>::from_filters([
StaticFilter::new(
0, DirectionFlags::PACKET_FLAG_ON_SEND,
FILTER_PACKET_REDIRECT,
FilterLayerFlags::NETWORK_LAYER_VALID | FilterLayerFlags::TRANSPORT_LAYER_VALID,
DataLinkLayerFilter::default(),
NetworkLayerFilter::new(
IPV4,
NetworkLayerFilterUnion {
ipv4: IpV4Filter::new(
IpV4FilterFlags::IP_V4_FILTER_PROTOCOL,
IpAddressV4::default(),
IpAddressV4::default(),
IPPROTO_ICMP,
),
},
),
TransportLayerFilter::new(
ICMP,
TransportLayerFilterUnion {
icmp: IcmpFilter::new(
IcmpFilterFlags::ICMP_TYPE,
ByteRange::new(8, 8),
ByteRange::default(),
),
},
),
),
StaticFilter::new(
0, DirectionFlags::PACKET_FLAG_ON_RECEIVE | DirectionFlags::PACKET_FLAG_ON_SEND,
FILTER_PACKET_PASS,
FilterLayerFlags::empty(),
DataLinkLayerFilter::default(),
NetworkLayerFilter::default(),
TransportLayerFilter::default(),
),
]);
ndisapi.set_packet_filter_table(&filter_table)
}
fn main() -> Result<()> {
let Cli {
mut interface_index,
filter,
} = Cli::parse();
interface_index -= 1;
let driver =
Ndisapi::new("NDISRD").expect("WinpkFilter driver is not installed or failed to load!");
println!(
"Detected Windows Packet Filter version {}",
driver.get_version()?
);
let adapters = driver.get_tcpip_bound_adapters_info()?;
if interface_index + 1 > adapters.len() {
panic!("Interface index is beyond the number of available interfaces");
}
println!("Using interface {}s", adapters[interface_index].get_name());
let filter_set_result = match filter {
1 => load_ipv4_dns_filters(&driver),
2 => load_http_ipv4v6_filters(&driver),
3 => load_icmpv4_drop_filters(&driver),
4 => load_block_ntkernel_https_filters(&driver),
5 => load_redirect_arp_filters(&driver),
6 => load_redirect_icmp_req_filters(&driver),
_ => panic!("Filter set is not available"),
};
match filter_set_result {
Ok(_) => println!("Successfully loaded static filters into the driver."),
Err(err) => panic!("Failed to load static filter into the driver. Error code: {err}"),
}
let event: HANDLE;
unsafe {
event = CreateEventW(None, true, false, None)?;
}
let event_raw = event.0 as usize;
let terminate: Arc<AtomicBool> = Arc::new(AtomicBool::new(false));
let ctrlc_pressed = terminate.clone();
ctrlc::set_handler(move || {
println!("Ctrl-C was pressed. Terminating...");
ctrlc_pressed.store(true, Ordering::SeqCst);
let handle = HANDLE(event_raw as *mut std::ffi::c_void);
let _ = unsafe { SetEvent(handle) };
})
.expect("Error setting Ctrl-C handler");
driver.set_packet_event(adapters[interface_index].get_handle(), event)?;
driver.set_adapter_mode(
adapters[interface_index].get_handle(),
FilterFlags::MSTCP_FLAG_SENT_RECEIVE_TUNNEL,
)?;
let mut packet = IntermediateBuffer::default();
while !terminate.load(Ordering::SeqCst) {
unsafe {
WaitForSingleObject(event, u32::MAX);
}
loop {
let mut read_request = EthRequestMut::new(adapters[interface_index].get_handle());
read_request.set_packet(&mut packet);
if driver.read_packet(&mut read_request).ok().is_none() {
break;
}
let direction_flags = packet.get_device_flags();
if direction_flags == DirectionFlags::PACKET_FLAG_ON_SEND {
println!("\nMSTCP --> Interface ({} bytes)\n", packet.get_length());
} else {
println!("\nInterface --> MSTCP ({} bytes)\n", packet.get_length());
}
print_packet_info(&packet);
let mut write_request = EthRequest::new(adapters[interface_index].get_handle());
write_request.set_packet(&packet);
if direction_flags == DirectionFlags::PACKET_FLAG_ON_SEND {
match driver.send_packet_to_adapter(&write_request) {
Ok(_) => {}
Err(err) => println!("Error sending packet to adapter. Error code = {err}"),
};
} else {
match driver.send_packet_to_mstcp(&write_request) {
Ok(_) => {}
Err(err) => println!("Error sending packet to mstcp. Error code = {err}"),
}
}
}
let _ = unsafe { ResetEvent(event) };
}
driver.set_adapter_mode(
adapters[interface_index].get_handle(),
FilterFlags::default(),
)?;
let _ = unsafe { CloseHandle(event) };
Ok(())
}
fn print_packet_info(packet: &IntermediateBuffer) {
let eth_hdr = EthernetFrame::new_unchecked(packet.get_data());
match eth_hdr.ethertype() {
EthernetProtocol::Ipv4 => {
let ipv4_packet = Ipv4Packet::new_unchecked(eth_hdr.payload());
println!(
" Ipv4 {:?} => {:?}",
ipv4_packet.src_addr(),
ipv4_packet.dst_addr()
);
match ipv4_packet.next_header() {
IpProtocol::Icmp => {
let icmp_packet = Icmpv4Packet::new_unchecked(ipv4_packet.payload());
println!(
"ICMPv4: Type: {:?} Code: {:?}",
icmp_packet.msg_type(),
icmp_packet.msg_code()
);
}
IpProtocol::Tcp => {
let tcp_packet = TcpPacket::new_unchecked(ipv4_packet.payload());
println!(
" TCP {:?} -> {:?}",
tcp_packet.src_port(),
tcp_packet.dst_port()
);
}
IpProtocol::Udp => {
let udp_packet = UdpPacket::new_unchecked(ipv4_packet.payload());
println!(
" UDP {:?} -> {:?}",
udp_packet.src_port(),
udp_packet.dst_port()
);
}
_ => {
println!("Unknown IPv4 packet: {:?}", ipv4_packet);
}
}
}
EthernetProtocol::Ipv6 => {
let ipv6_packet = Ipv6Packet::new_unchecked(eth_hdr.payload());
println!(
" Ipv6 {:?} => {:?}",
ipv6_packet.src_addr(),
ipv6_packet.dst_addr()
);
match ipv6_packet.next_header() {
IpProtocol::Icmpv6 => {
let icmpv6_packet = Icmpv6Packet::new_unchecked(ipv6_packet.payload());
println!(
"ICMPv6 packet: Type: {:?} Code: {:?}",
icmpv6_packet.msg_type(),
icmpv6_packet.msg_code()
);
}
IpProtocol::Tcp => {
let tcp_packet = TcpPacket::new_unchecked(ipv6_packet.payload());
println!(
" TCP {:?} -> {:?}",
tcp_packet.src_port(),
tcp_packet.dst_port()
);
}
IpProtocol::Udp => {
let udp_packet = UdpPacket::new_unchecked(ipv6_packet.payload());
println!(
" UDP {:?} -> {:?}",
udp_packet.src_port(),
udp_packet.dst_port()
);
}
_ => {
println!("Unknown IPv6 packet: {:?}", ipv6_packet);
}
}
}
EthernetProtocol::Arp => {
let arp_packet = ArpPacket::new_unchecked(eth_hdr.payload());
println!("ARP packet: {:?}", arp_packet);
}
EthernetProtocol::Unknown(_) => {
println!("Unknown Ethernet packet: {:?}", eth_hdr);
}
}
}