ndisapi_rs/driver/
filters.rs

1//! # Submodule: Basic NDISAPI static filter definitions
2//!
3//! This submodule contains various structures used for static filters in the NDISAPI Rust library.
4//!
5//! The `filters` submodule provides a Rust interface for configuring static filters for the Windows Packet
6//! Filter driver. It contains structures for specifying filter conditions and actions for various protocols,
7//! including Ethernet 802.3, IPv4, IPv6, TCP, UDP, and ICMP. These structures allow users to define complex
8//! filtering rules based on multiple packet fields and layers.
9//!
10//! # Structures
11//!
12//! * [`Eth8023Filter`] - Represents a static filter for Ethernet 802.3 frames.
13//! * [`IpV4Filter`] - Represents a static filter for IPv4 packets.
14//! * [`IpV6Filter`] - Represents a static filter for IPv6 packets.
15//! * [`TcpUdpFilter`] - Represents a static filter for TCP and UDP packets.
16//! * [`IcmpFilter`] - Represents a static filter for ICMP packets.
17//! * [`StaticFilter`] - Represents a single static filter entry that combines filter conditions for various
18//! layers and the filter action to be taken.
19//! * [`StaticFilterTable`] - Represents a table of static filters, used for managing multiple static filter entries.
20
21// Import required external crates and types
22use windows::{Win32::Networking::WinSock::IN6_ADDR, Win32::Networking::WinSock::IN_ADDR};
23
24use super::constants::*;
25
26/// This structure is used to define an Ethernet 802.3 filter based on various fields like source and destination addresses, and protocol.
27///
28/// A Rust equivalent for the [_ETH_802_3_FILTER](https://www.ntkernel.com/docs/windows-packet-filter-documentation/structures/_eth_802_3_filter/) structure.
29#[repr(C, packed)]
30#[derive(Debug, Copy, Clone)]
31pub struct Eth8023Filter {
32    /// A bitmask indicating which fields in the filter are valid.
33    pub valid_fields: Eth802_3FilterFlags,
34    /// The source address to filter on.
35    pub src_address: [u8; ETHER_ADDR_LENGTH],
36    /// The destination address to filter on.
37    pub dest_address: [u8; ETHER_ADDR_LENGTH],
38    /// The protocol (Ethertype) to filter on.
39    pub protocol: u16,
40    /// Padding to align the structure.
41    pub padding: u16,
42}
43
44impl Default for Eth8023Filter {
45    /// Returns a zero-initialized instance of `Eth8023Filter`.
46    ///
47    /// # Safety
48    ///
49    /// It is safe to zero-initialize this structure because it contains only values and arrays that
50    /// can be default initialized with zeroes.
51    fn default() -> Self {
52        unsafe { std::mem::zeroed() }
53    }
54}
55
56/// This structure is used to represent an IPv4 subnet based on an IP address and a subnet mask.
57///
58/// A Rust equivalent for the [_IP_SUBNET_V4](https://www.ntkernel.com/docs/windows-packet-filter-documentation/structures/_ip_subnet_v4/) structure.
59#[repr(C, packed)]
60#[derive(Default, Copy, Clone)]
61pub struct IpSubnetV4 {
62    /// The IPv4 address.
63    pub ip: IN_ADDR,
64    /// The subnet mask.
65    pub ip_mask: IN_ADDR,
66}
67
68/// This structure is used to represent an IPv4 address range based on a start and end IP address.
69///
70/// A Rust equivalent for the [_IP_RANGE_V4](https://www.ntkernel.com/docs/windows-packet-filter-documentation/structures/_ip_range_v4/) structure.
71#[repr(C, packed)]
72#[derive(Default, Copy, Clone)]
73pub struct IpRangeV4 {
74    /// The start of the IPv4 address range.
75    pub start_ip: IN_ADDR,
76    /// The end of the IPv4 address range.
77    pub end_ip: IN_ADDR,
78}
79
80/// A Rust union representing either an IPv4 subnet (IpSubnetV4) or an IPv4 address range (IpRangeV4).
81#[repr(C, packed)]
82#[derive(Copy, Clone)]
83pub union IpAddressV4Union {
84    /// The IPv4 subnet representation.
85    pub ip_subnet: IpSubnetV4,
86    /// The IPv4 address range representation.
87    pub ip_range: IpRangeV4,
88}
89
90impl Default for IpAddressV4Union {
91    fn default() -> Self {
92        // SAFETY: This union contains either a `IpSubnetV4` or a `IpRangeV4`
93        // IpSubnetV4: when zeroed is equivalent to 0.0.0.0/0
94        // IpRangeV4: when zeroed is equivalent to 0.0.0.0 - 0.0.0.0
95        unsafe { std::mem::zeroed() }
96    }
97}
98
99/// Represents an IPv4 address in a format used by the packet filtering mechanism.
100///
101/// A Rust equivalent for [_IP_ADDRESS_V4](https://www.ntkernel.com/docs/windows-packet-filter-documentation/structures/_ip_address_v4/).
102///
103/// The `address_type` field indicates whether the address is a subnet or a range.
104/// The `address` field contains the actual IPv4 address information in a union format.
105#[repr(C, packed)]
106#[derive(Default, Copy, Clone)]
107pub struct IpAddressV4 {
108    pub address_type: u32, // IP_SUBNET_V4_TYPE or IP_RANGE_V4_TYPE
109    pub address: IpAddressV4Union,
110}
111
112/// Represents an IPv4 filter used by the packet filtering mechanism.
113///
114/// A Rust equivalent for [_IP_V4_FILTER](https://www.ntkernel.com/docs/windows-packet-filter-documentation/structures/_ip_v4_filter/).
115///
116/// The `valid_fields` field specifies which fields in the filter structure are used for filtering.
117/// The `src_address` field contains the source IPv4 address information.
118/// The `dest_address` field contains the destination IPv4 address information.
119/// The `protocol` field represents the IP protocol number.
120/// The `padding` field is used for alignment purposes.
121#[repr(C, packed)]
122#[derive(Default, Copy, Clone)]
123pub struct IpV4Filter {
124    pub valid_fields: IpV4FilterFlags,
125    pub src_address: IpAddressV4,
126    pub dest_address: IpAddressV4,
127    pub protocol: u8,
128    pub padding: [u8; 3usize],
129}
130
131/// Represents an IPv6 subnet used by the packet filtering mechanism.
132///
133/// A Rust equivalent for [_IP_SUBNET_V6](https://www.ntkernel.com/docs/windows-packet-filter-documentation/structures/_ip_subnet_v6/).
134///
135/// The `ip` field contains the IPv6 address.
136/// The `ip_mask` field contains the subnet mask.
137#[repr(C, packed)]
138#[derive(Copy, Clone)]
139pub struct IpSubnetV6 {
140    pub ip: IN6_ADDR,
141    pub ip_mask: IN6_ADDR,
142}
143
144/// Represents an IPv6 address range used by the packet filtering mechanism.
145///
146/// A Rust equivalent for [_IP_RANGE_V6](https://www.ntkernel.com/docs/windows-packet-filter-documentation/structures/_ip_range_v6/).
147///
148/// The `start_ip` field contains the starting IPv6 address of the range.
149/// The `end_ip` field contains the ending IPv6 address of the range.
150#[repr(C, packed)]
151#[derive(Copy, Clone)]
152pub struct IpRangeV6 {
153    pub start_ip: IN6_ADDR,
154    pub end_ip: IN6_ADDR,
155}
156
157/// This structure is used to store information about a particular address space
158/// for packet filtering purposes.
159///
160/// A Rust union that represents either an IPv6 subnet or an IPv6 address range.
161///
162/// The `ip_subnet` field contains the IPv6 subnet if the address space is a subnet.
163/// The `ip_range` field contains the IPv6 address range if the address space is a range.
164#[repr(C, packed)]
165#[derive(Copy, Clone)]
166pub union IpAddressV6Union {
167    pub ip_subnet: IpSubnetV6,
168    pub ip_range: IpRangeV6,
169}
170
171impl Default for IpAddressV6Union {
172    fn default() -> Self {
173        // SAFETY: This union contains either a `IpSubnetV6` or a `IpRangeV6`
174        // IpSubnetV6: when zeroed is equivalent to ::/0
175        // IpRangeV6: when zeroed is equivalent to :: - ::
176        unsafe { std::mem::zeroed() }
177    }
178}
179
180/// This structure is used to store information about an IPv6 address for packet filtering purposes.
181///
182/// Rust equivalent for [_IP_ADDRESS_V6](https://www.ntkernel.com/docs/windows-packet-filter-documentation/structures/_ip_address_v6/).
183///
184/// The `address_type` field indicates whether the address is a subnet (IP_SUBNET_V6_TYPE) or a range (IP_RANGE_V6_TYPE).
185/// The `address` field contains the specific IPv6 address data, either a subnet or an address range, depending on the `address_type`.
186#[repr(C, packed)]
187#[derive(Default, Copy, Clone)]
188pub struct IpAddressV6 {
189    pub address_type: u32, // IP_SUBNET_V6_TYPE or IP_RANGE_V6_TYPE
190    pub address: IpAddressV6Union,
191}
192
193/// This structure is used to define packet filtering rules for IPv6 packets.
194///
195/// Rust equivalent for [_IP_V6_FILTER](https://www.ntkernel.com/docs/windows-packet-filter-documentation/structures/_ip_v6_filter/).
196///
197/// The `valid_fields` field contains flags that specify which fields of the filter are active.
198/// The `src_address` and `dest_address` fields store information about the source and destination IPv6 addresses respectively.
199/// The `protocol` field represents the protocol used in the packet (e.g., TCP, UDP).
200/// The `padding` field is reserved for padding to ensure the correct alignment of the structure.
201#[repr(C, packed)]
202#[derive(Default, Copy, Clone)]
203pub struct IpV6Filter {
204    pub valid_fields: IpV6FilterFlags,
205    pub src_address: IpAddressV6,
206    pub dest_address: IpAddressV6,
207    pub protocol: u8,
208    pub padding: [u8; 3usize],
209}
210
211/// This structure is used to define a range of port numbers for packet filtering rules.
212///
213/// Rust equivalent for [_PORT_RANGE](https://www.ntkernel.com/docs/windows-packet-filter-documentation/structures/_port_range/).
214///
215/// The `start_range` field represents the starting port number in the range.
216/// The `end_range` field represents the ending port number in the range.
217#[repr(C, packed)]
218#[derive(Default, Debug, Copy, Clone)]
219pub struct PortRange {
220    pub start_range: u16,
221    pub end_range: u16,
222}
223
224/// This structure is used to define filtering rules for TCP and UDP packets.
225///
226/// Rust equivalent for [_TCPUDP_FILTER](https://www.ntkernel.com/docs/windows-packet-filter-documentation/structures/_tcpudp_filter/).
227///
228/// The `valid_fields` field specifies which fields in the structure are valid for filtering.
229/// The `source_port` field represents the range of source port numbers to filter.
230/// The `dest_port` field represents the range of destination port numbers to filter.
231/// The `tcp_flags` field is used to filter TCP packets based on their flags.
232/// The `padding` field ensures proper alignment of the structure.
233#[repr(C, packed)]
234#[derive(Default, Debug, Copy, Clone)]
235pub struct TcpUdpFilter {
236    pub valid_fields: TcpUdpFilterFlags,
237    pub source_port: PortRange,
238    pub dest_port: PortRange,
239    pub tcp_flags: u8,
240    pub padding: [u8; 3usize],
241}
242
243/// A Rust struct that represents a range of byte values.
244///
245/// Rust equivalent for _BYTE_RANGE. This structure can be used to define
246/// filtering rules based on byte ranges, such as ICMP type or code ranges.
247///
248/// The `start_range` field represents the start of the byte range.
249/// The `end_range` field represents the end of the byte range.
250#[repr(C)]
251#[derive(Default, Debug, Copy, Clone)]
252pub struct ByteRange {
253    pub start_range: u8,
254    pub end_range: u8,
255}
256
257/// A Rust struct that represents an ICMP filter.
258///
259/// Rust equivalent for _ICMP_FILTER. This structure can be used to define
260/// filtering rules for ICMP packets based on ICMP type and code ranges.
261///
262/// The `valid_fields` field specifies which fields in the filter are valid for filtering.
263/// The `type_range` field represents a range of ICMP types for filtering.
264/// The `code_range` field represents a range of ICMP codes for filtering.
265#[repr(C, packed)]
266#[derive(Default, Debug, Copy, Clone)]
267pub struct IcmpFilter {
268    pub valid_fields: IcmpFilterFlags,
269    pub type_range: ByteRange,
270    pub code_range: ByteRange,
271}
272
273/// A Rust union that holds an `Eth8023Filter`.
274///
275/// This union can be extended to include other data link layer filters if needed.
276/// Currently, it only contains an `Eth8023Filter` for filtering Ethernet/802.3 packets.
277#[repr(C, packed)]
278#[derive(Copy, Clone)]
279pub union DataLinkLayerFilterUnion {
280    pub eth_8023_filter: Eth8023Filter,
281}
282
283impl Default for DataLinkLayerFilterUnion {
284    fn default() -> Self {
285        // SAFETY: This union contains an `Eth8023Filter`
286        // Eth8023Filter: when zeroed is meaningless and ignored by code
287        unsafe { std::mem::zeroed() }
288    }
289}
290
291/// A Rust struct that represents a data link layer filter.
292///
293/// Rust equivalent for [_DATA_LINK_LAYER_FILTER](https://www.ntkernel.com/docs/windows-packet-filter-documentation/structures/data_link_layer_filter/)
294/// This struct can be used to filter packets at the data link layer (e.g., Ethernet/802.3) by specifying the filter type in `union_selector`.
295#[repr(C, packed)]
296#[derive(Default, Copy, Clone)]
297pub struct DataLinkLayerFilter {
298    pub union_selector: u32, // ETH_802_3 for Eth8023Filter
299    pub data_link_layer: DataLinkLayerFilterUnion,
300}
301
302/// A Rust union that holds either an `IpV4Filter` or an `IpV6Filter`.
303///
304/// This union can be used to filter packets at the network layer by specifying the appropriate filter type (IPv4 or IPv6).
305#[repr(C, packed)]
306#[derive(Copy, Clone)]
307pub union NetworkLayerFilterUnion {
308    pub ipv4: IpV4Filter,
309    pub ipv6: IpV6Filter,
310}
311
312impl Default for NetworkLayerFilterUnion {
313    fn default() -> Self {
314        // SAFETY: This union contains either a `IpV4Filter` or `IpV6Filter'
315        // IpV4Filter: when zeroed is meaningless and ignored by code
316        // IpV6Filter: when zeroed is meaningless and ignored by code
317        unsafe { std::mem::zeroed() }
318    }
319}
320
321/// A Rust struct that represents a network layer filter.
322///
323/// Rust equivalent for [_NETWORK_LAYER_FILTER](https://www.ntkernel.com/docs/windows-packet-filter-documentation/structures/_network_layer_filter/).
324#[repr(C, packed)]
325#[derive(Default, Copy, Clone)]
326pub struct NetworkLayerFilter {
327    /// union_selector: A field that determines the type of the network layer filter.
328    /// Set to IPV4 for IpV4Filter, and IPV6 for IpV6Filter.
329    pub union_selector: u32,
330    /// network_layer: A union that holds either an IpV4Filter or an IpV6Filter,
331    /// depending on the value of the union_selector field.
332    pub network_layer: NetworkLayerFilterUnion,
333}
334
335/// A Rust union that represents a transport layer filter.
336///
337/// Holds either a `TcpUdpFilter` or an `IcmpFilter`.
338#[repr(C, packed)]
339#[derive(Copy, Clone)]
340pub union TransportLayerFilterUnion {
341    /// tcp_udp: A TcpUdpFilter struct that represents a TCP/UDP filter.
342    pub tcp_udp: TcpUdpFilter,
343    /// icmp: An IcmpFilter struct that represents an ICMP filter.
344    pub icmp: IcmpFilter,
345}
346
347impl Default for TransportLayerFilterUnion {
348    fn default() -> Self {
349        // SAFETY: This union contains either a `TcpUdpFilter` or an `IcmpFilter`
350        // TcpUdpFilter: when zeroed is meaningless and ignored by code
351        // IcmpFilter: when zeroed is meaningless and ignored by code
352        unsafe { std::mem::zeroed() }
353    }
354}
355
356/// A Rust struct that represents a transport layer filter.
357///
358/// Rust equivalent for [_TRANSPORT_LAYER_FILTER](https://www.ntkernel.com/docs/windows-packet-filter-documentation/structures/_transport_layer_filter/)
359#[repr(C, packed)]
360#[derive(Default, Copy, Clone)]
361pub struct TransportLayerFilter {
362    /// union_selector: A u32 flag that selects the appropriate filter.
363    /// Use TCPUDP for TcpUdpFilter and ICMP for IcmpFilter.
364    pub union_selector: u32,
365    /// transport_layer: A TransportLayerFilterUnion that holds either a `TcpUdpFilter` or an `IcmpFilter`.
366    pub transport_layer: TransportLayerFilterUnion,
367}
368
369/// This structure is used to define a single static filter rule for packet filtering. Each rule can specify filtering criteria at
370/// the data link, network, and transport layers. The structure also includes counters for incoming and outgoing packets and bytes
371/// that match the filter rule.
372///
373/// * Rust equivalent for [_STATIC_FILTER](https://www.ntkernel.com/docs/windows-packet-filter-documentation/structures/_static_filter/)
374#[repr(C, packed)]
375#[derive(Default, Copy, Clone)]
376pub struct StaticFilter {
377    /// Adapter handle extended to 64 bit size for structure compatibility across x64 and x86 architectures
378    pub adapter_handle: u64,
379    /// PACKET_FLAG_ON_SEND or/and PACKET_FLAG_ON_RECEIVE to specify the direction of packets to match
380    pub direction_flags: DirectionFlags,
381    /// FILTER_PACKET_XXX to define the action to take when a packet matches the filter
382    pub filter_action: u32,
383    /// Specifies which of the fields below contain valid values and should be matched against the packet
384    pub valid_fields: FilterLayerFlags,
385    /// Time of the last counters reset (in seconds passed since 1 Jan 1980)
386    pub last_reset: u32,
387    /// Incoming packets passed through this filter
388    pub packets_in: u64,
389    /// Incoming bytes passed through this filter
390    pub bytes_in: u64,
391    /// Outgoing packets passed through this filter
392    pub packets_out: u64,
393    /// Outgoing bytes passed through this filter
394    pub bytes_out: u64,
395    /// Filter criteria for the data link layer (e.g., Ethernet)
396    pub data_link_filter: DataLinkLayerFilter,
397    /// Filter criteria for the network layer (e.g., IPv4, IPv6)
398    pub network_filter: NetworkLayerFilter,
399    /// Filter criteria for the transport layer (e.g., TCP, UDP, ICMP)
400    pub transport_filter: TransportLayerFilter,
401}
402
403/// This structure represents an array of static filter rules, each of which is defined by a `StaticFilter` structure.
404/// It is used to manage multiple filter rules for packet filtering in a table format.
405///
406/// * Rust equivalent to the [_STATIC_FILTER_TABLE](https://www.ntkernel.com/docs/windows-packet-filter-documentation/structures/_static_filter_table/)
407#[repr(C, packed)]
408#[derive(Copy, Clone)]
409pub struct StaticFilterTable<const N: usize> {
410    /// The number of elements in the static_filters array
411    pub table_size: u32,
412    /// Padding to ensure correct memory alignment
413    pub padding: u32,
414    /// Array of static filter rules
415    pub static_filters: [StaticFilter; N],
416}
417
418impl<const N: usize> StaticFilterTable<N> {
419    /// Creates a new `StaticFilterTable` with the specified number of elements.
420    pub fn new() -> Self {
421        Self {
422            table_size: N as u32,
423            padding: 0u32,
424            static_filters: [StaticFilter::default(); N],
425        }
426    }
427}
428
429impl<const N: usize> Default for StaticFilterTable<N> {
430    /// Initializes a new `StaticFilterTable` with the specified number of elements and default values for each element.
431    fn default() -> Self {
432        Self::new()
433    }
434}