The idea of this project is to create easily extensible packet filter, which does not require hacking large packet checking function or even recompilation of whole thing to provide additional functionality. And even more, userfw relies on it's modules to provide even basic functionality (to prevent confusion, this modules are compiled into same binary as the core part).
Each module presents to core entities of 3 types: commands, actions and matches. Commands can be called from userspace and used to give some control on different parts. Actions and matches used to construct rules and can have arguments, including other actions and matches (but not commands). This design leads to some interesting things: complex matching constructions can be created with matches, that implements logical operations and takes other matches as arguments, functionality similar to ipfw's keep-state can be implemented in more clear way with action “keep-state”, that takes other action as argument, and so on.
For example, now there is action match-pipe, and match lookup-dst-ip that does not know anything about each other at compile time, they even implemented in independent modules, but they easily can be combined together to do some work:
# ipfw pipe 1 config delay 1000 # ipfw pipe 2 config delay 500 # ipfw table 1 add 22.214.171.124 1 # ipfw table 1 add 126.96.36.199 2 # cli/userfw add 10 match-pipe lookup-dst-ip 1 out OK % ping -c1 188.8.131.52 PING 184.108.40.206 (220.127.116.11): 56 data bytes 64 bytes from 18.104.22.168: icmp_seq=0 ttl=50 time=1077.554 ms % ping -c1 22.214.171.124 PING 126.96.36.199 (188.8.131.52): 56 data bytes 64 bytes from 184.108.40.206: icmp_seq=0 ttl=50 time=550.736 ms