PF - Packet Tagging (Policy Filtering)
- Introduction
- Assigning Tags to Packets
- Checking for Applied Tags
- Policy Filtering
- Tagging Ethernet Frames
Introduction
Packet tagging is a way of marking packets with an internal identifier that can later be used in filter and translation rule criteria. With tagging it's possible to do things such as create "trusts" between interfaces and determine if packets have been processed by translation rules. It's also possible to move away from rule-based filtering and to start doing policy-based filtering.Assigning Tags to Packets
To add a tag to a packet, use thetag keyword:
pass in on $int_if all tag INTERNAL_NETThe tag
INTERNAL_NET will be added to any packet which matches
the above rule.
A tag can also be assigned using a macro. For instance:
name = "INTERNAL_NET" pass in on $int_if all tag $nameThere is a set of predefined macros which can also be used.
$if- The interface$srcaddr- Source IP address$dstaddr- Destination IP address$srcport- The source port specification$dstport- The destination port specification$proto- The protocol$nr- The rule number
Tagging follows these rules:
- Tags are "sticky." Once a tag is applied to a packet by a matching rule, it is never removed. It can, however, be replaced with a different tag.
- Because of a tag's "stickiness," a packet can have a tag even if the
last matching rule doesn't use the
tagkeyword. - A packet is only ever assigned a maximum of one tag at a time.
- Tags are internal identifiers. Tags are not sent out over the wire.
- Tag names can be up to 63 characters long.
pass in on $int_if tag INT_NET pass in quick on $int_if proto tcp to port 80 tag INT_NET_HTTP pass in quick on $int_if from 192.168.1.5
- Packets coming in on
$int_ifwill be assigned a tag ofINT_NETby rule #1. - TCP packets coming in on
$int_ifand destined for port 80 will first be assigned a tag ofINT_NETby rule #1. That tag will then be replaced with theINT_NET_HTTPtag by rule #2. - Packets coming in on
$int_iffrom 192.168.1.5 will be tagged one of two ways. If the packet is destined for TCP port 80 it will match rule #2 and be tagged withINT_NET_HTTP. Otherwise, the packet will match rule #3 but will be tagged withINT_NET. Because the packet matches rule #1, theINT_NETtag is applied and is not removed unless a subsequently matching rule specifies a tag (this is the "stickiness" of a tag).
Checking for Applied Tags
To check for previously applied tags, use thetagged keyword:
pass out on egress tagged INT_NETOutgoing packets on the external interface must be tagged with the
INT_NET tag in order to match the above rule.
Inverse matching can also be done by using the ! operator:
pass out on egress ! tagged WIFI_NET
Policy Filtering
Policy filtering takes a different approach to writing a filter ruleset. A policy is defined which sets the rules for what types of traffic are passed and what types are blocked. Packets are then classified into the policy based on the traditional criteria of source/destination IP address/port, protocol, etc. For example, examine the following firewall policy:- Traffic from the internal LAN to the internet is permitted (LAN_INET) and must be translated (LAN_INET_NAT).
- Traffic from the internal LAN to the DMZ is permitted (LAN_DMZ).
- Traffic from the internet to servers in the DMZ is permitted (INET_DMZ).
- Traffic from the internet that's being redirected to spamd(8) is permitted (SPAMD).
- All other traffic is blocked.
Rules now need to be written to classify packets into the policy.
block all pass out on egress inet tag LAN_INET_NAT tagged LAN_INET nat-to ($ext_if) pass in on $int_if from $int_net tag LAN_INET pass in on $int_if from $int_net to $dmz_net tag LAN_DMZ pass in on egress proto tcp to $www_server port 80 tag INET_DMZ pass in on egress proto tcp from <spamd> to port smtp tag SPAMD rdr-to 127.0.0.1 port 8025Now the rules that define the policy are set.
pass in quick on egress tagged SPAMD pass out quick on egress tagged LAN_INET_NAT pass out quick on $dmz_if tagged LAN_DMZ pass out quick on $dmz_if tagged INET_DMZNow that the whole ruleset is set up, changes are a matter of modifying the classification rules. For example, if a POP3/SMTP server is added to the DMZ, it will be necessary to add classification rules for POP3 and SMTP traffic, like so:
mail_server = "192.168.0.10"
[...]
pass in on egress proto tcp to $mail_server port { smtp, pop3 } tag INET_DMZ
Email traffic will now be passed as part of the INET_DMZ policy entry.
The complete ruleset:
int_if = "dc0" dmz_if = "dc1" int_net = "10.0.0.0/24" dmz_net = "192.168.0.0/24" www_server = "192.168.0.5" mail_server = "192.168.0.10" table <spamd> persist file "/etc/spammers" # classification -- classify packets based on the defined firewall policy. block all pass out on egress inet tag LAN_INET_NAT tagged LAN_INET nat-to (egress) pass in on $int_if from $int_net tag LAN_INET pass in on $int_if from $int_net to $dmz_net tag LAN_DMZ pass in on egress proto tcp to $www_server port 80 tag INET_DMZ pass in on egress proto tcp from <spamd> to port smtp tag SPAMD rdr-to 127.0.0.1 port 8025 # policy enforcement -- pass/block based on the defined firewall policy. pass in quick on egress tagged SPAMD pass out quick on egress tagged LAN_INET_NAT pass out quick on $dmz_if tagged LAN_DMZ pass out quick on $dmz_if tagged INET_DMZ
Tagging Ethernet Frames
Tagging can be performed at the ethernet level if the machine doing the tagging/filtering is also acting as a bridge(4). By creating bridge filter rules that use thetag keyword, PF
can be made to filter based on the source or destination MAC address.
Bridge rules are created using the
ifconfig(8) command:
# ifconfig bridge0 rule pass in on fxp0 src 0:de:ad:be:ef:0 tag USER1And then in
pf.conf:
pass in on fxp0 tagged USER1