#freebsd #pf #networking #packet-filter

pf-rs

FreeBSD lib to access OpenBSD's implementation of the PF (Packet Filter) directly via /dev/pf

3 releases

13.2.1 Aug 22, 2023
13.0.4 Apr 22, 2022
13.0.2 Aug 6, 2021
0.2.4 Feb 6, 2024
0.2.3 Dec 4, 2023

#481 in Network programming

BSD-2-Clause

100KB
2K SLoC

#pf-rs

V 0.2.2 - updated to support FREEBSD 14.0-RELEASE.

A crate which provides userspace interface to FreeBSD port of the OpendBSD's PF (Packet Filter) which allows to control PF directly without executing pfctl(8) every time when it is required to block network host or to check the list.

This is experimental crate and is used in "logdaemon" project.

At the moment the following is supported:

  • Add, Remove, Test commands on tables (a list of hosts: IP/IPv6/DNS at the moment)
  • Add, Remove, Test commands on tables from file (a list of hosts: IP/IPv6/DNS at the moment)
  • Kill state by source IP or by source IP and dest IP
  • Flush table

Prioritiesed ToDo list:

  • Add tables reload command (requires config parser)
  • Add full reaload command (requires config parser)
  • Add config test command (requires config parser)
  • Consifer to use safe list type for the c-linked lists if it is not passed to PF kernel module in such manner.

Code safity.

This crate uses a lot of unsafe code because it is using a lot of C-structures.

Probably some approaches like std::mem::zeroed() can be dodgy but it is true only on some cases.

So, below is a list of which code-approaches were used and why it is considered safe enough.

std::mem::zeroed() on structure initialization

In most cases, all structures required to be initialized with zeroes. Also it is usefull because it may contain fixed string buffer where in C, string is always null-terminated and pointers which are required to be pointed to NULL in some cases.
This method can be used on structires which does not contain references!

Working with pointers

When working with raw pointers it is better to keep track when any C code is initializing memory on its side and deallocate it with either free() or specially provided function.

Padding

In some cases rust may leave structure padded not to n^2 but for example to 44 when C will pad it to 48.

Example


fn test()
{
  let pf = Pf::new(false).unwrap();

  let res = pf.pfctl_table("table_test", PfCmd::Add{ hosts: vec!["192.168.2.44".to_string()] }).unrap();

  if res == 1
  {
    println!("added!");
  }
  else
  {
    println!("was not added, but no error generated");
  }
}

Dependencies

~1.5MB
~35K SLoC