fix(macos): skip PKTAP when BPF filter is specified (#100)

BPF filters are incompatible with PKTAP (linktype 149) on macOS.
When a filter is specified, fall back to regular interface capture.
This commit is contained in:
Marco Cadetg
2025-12-19 07:53:16 +01:00
committed by GitHub
parent 925d721670
commit 9089403d32
3 changed files with 20 additions and 5 deletions

View File

@@ -177,10 +177,17 @@ Apply a BPF (Berkeley Packet Filter) expression to filter packets at capture tim
**Common filter expressions:**
```bash
# Filter by port
# Filter by port (matches source OR destination)
rustnet --bpf-filter "port 443"
rustnet --bpf-filter "port 80 or port 8080"
# Filter by destination port specifically
rustnet --bpf-filter "dst port 443"
rustnet --bpf-filter "tcp dst port 80"
# Filter by source port specifically
rustnet --bpf-filter "src port 443"
# Filter by host
rustnet --bpf-filter "host 192.168.1.1"
rustnet --bpf-filter "net 10.0.0.0/8"
@@ -196,7 +203,9 @@ rustnet --bpf-filter "tcp port 443 and host github.com"
rustnet --bpf-filter "not port 22"
```
**Note:** BPF filter syntax follows the pcap-filter(7) format. Invalid filters will cause RustNet to exit with an error. Use `man pcap-filter` for complete syntax documentation.
**Notes:**
- BPF filter syntax follows the pcap-filter(7) format. Invalid filters will cause RustNet to exit with an error. Use `man pcap-filter` for complete syntax documentation.
- **macOS limitation:** BPF filters are incompatible with PKTAP (linktype 149). When you specify a BPF filter on macOS, RustNet automatically falls back to regular interface capture. This means process identification uses `lsof` instead of PKTAP's direct process metadata, which may be slightly less accurate for short-lived connections.
#### `-l, --log-level <LEVEL>`

View File

@@ -61,7 +61,7 @@ pub fn build_cli() -> Command {
.short('f')
.long("bpf-filter")
.value_name("FILTER")
.help("BPF filter expression for packet capture (e.g., \"tcp port 443\")")
.help("BPF filter expression for packet capture (e.g., \"tcp port 443\", \"dst port 80\"). Note: On macOS, using a BPF filter disables PKTAP (process info falls back to lsof)")
.required(false),
)
.arg(

View File

@@ -162,9 +162,11 @@ fn find_best_device() -> Result<Device> {
/// Setup packet capture with the given configuration
pub fn setup_packet_capture(config: CaptureConfig) -> Result<(Capture<Active>, String, i32)> {
// Try PKTAP first on macOS for process metadata, but only when no interface is explicitly specified
// Try PKTAP first on macOS for process metadata, but only when:
// - No interface is explicitly specified
// - No BPF filter is specified (BPF filters don't work with PKTAP's linktype 149)
#[cfg(target_os = "macos")]
if config.interface.is_none() {
if config.interface.is_none() && config.filter.is_none() {
log::info!("Attempting to use PKTAP for process metadata on macOS");
match Capture::from_device("pktap") {
@@ -227,6 +229,10 @@ pub fn setup_packet_capture(config: CaptureConfig) -> Result<(Capture<Active>, S
}
// Fallback to regular capture (original code)
#[cfg(target_os = "macos")]
if config.filter.is_some() {
log::warn!("BPF filter specified - using regular capture instead of PKTAP (BPF filters don't work with PKTAP)");
}
log::info!("Setting up regular packet capture");
let device = find_capture_device(&config.interface)?;