Basic Configuration of PF
The main configuration file for PF is /etc/pf.conf, which contains the rules and options that define how PF operates. You can edit this file with any text editor, but make sure to follow the syntax and conventions of pf.conf (5). You can also use pfctl (8), the command-line utility for controlling PF, to test, load, reload, or flush the rules from the file.
A basic pf.conf file consists of four sections:
The macros section, where you can define variables for interface names, IP addresses, port numbers, etc.
The tables section, where you can create lists of IP addresses or networks that can be referenced by rules.
The options section, where you can set global parameters for PF, such as block policy, log interface, scrubbing options, etc.
The filter rules section, where you can write the rules that determine how PF handles incoming and outgoing packets.
Here is an example of a basic pf.conf file that enables packet filtering and NAT on an OpenBSD system with two network interfaces: em0 (connected to the internet) and em1 (connected to the local network).
# Macros
ext_if = "em0"
int_if = "em1"
# Tables
table <localnet> 192.168.1.0/24
# Options
set block-policy drop
set loginterface $ext_if
set skip on lo
# Filter rules
match out on $ext_if inet from !($ext_if:network) to any nat-to ($ext_if)
block in on $ext_if from <localnet> to any
block out on $ext_if from any to <localnet>
pass in on $int_if
pass out on $ext_if
This file does the following:
Defines two macros: ext_if for the external interface and int_if for the internal interface.
Creates a table called <localnet> that contains the IP addresses of the local network (192.168.1.0/24).
Sets the block policy to drop packets silently, sets the log interface to em0, and skips filtering on the loopback interface (lo).
Matches outgoing packets on em0 that are not from the em0 network and translates their source address to the em0 address (NAT).
Blocks incoming packets on em0 that are from the local network (anti-spoofing).
Blocks outgoing packets on em0 that are destined to the local network (anti-spoofing).
Passes incoming packets on em1 (allows all traffic from the local network).
Passes outgoing packets on em0 (allows all traffic to the internet).
To load this file into PF, you can use the following command:
# pfctl -f /etc/pf.conf
To enable PF at boot time, you can add the following line to /etc/rc.conf.local:
pf=YES
Advanced Configuration of PF
The basic configuration of PF can be extended and modified to suit different scenarios and needs. Here are some examples of advanced configuration options that you can use with PF:
Traffic Redirection (Port Forwarding)
Traffic redirection allows you to forward incoming packets on a specific port or range of ports to another port or address. This is useful if you want to allow access to a service running behind your firewall, such as a web server or a SSH server.
How to configure OpenBSD firewall using PF
OpenBSD PF tutorial: routing and filtering packets
OpenBSD routing performance and optimization with PF
OpenBSD PF vs iptables: which one is better for routing?
OpenBSD routing basics: understanding PF rules and syntax
OpenBSD PF cheat sheet: common commands and examples
OpenBSD routing with multiple interfaces and gateways using PF
OpenBSD PF best practices: security and logging tips
OpenBSD routing with VPN and NAT using PF
OpenBSD PF troubleshooting: how to debug and test routing issues
OpenBSD routing with load balancing and failover using PF
OpenBSD PF advanced features: tables, queues, anchors and macros
OpenBSD routing with IPv6 and dual-stack support using PF
OpenBSD PF comparison: how does it differ from other BSD firewalls?
OpenBSD routing with wireless networks and bridges using PF
OpenBSD PF documentation: where to find official and unofficial guides
OpenBSD routing with dynamic DNS and DHCP using PF
OpenBSD PF installation and setup: how to get started with routing
OpenBSD routing with QoS and traffic shaping using PF
OpenBSD PF alternatives: what are other options for routing on OpenBSD?
OpenBSD routing with CARP and pfsync using PF
OpenBSD PF history and development: how did it evolve over time?
OpenBSD routing with multicast and broadcast using PF
OpenBSD PF integration: how to use it with other tools and services
OpenBSD routing with VLANs and trunking using PF
OpenBSD PF limitations and challenges: what are the drawbacks of routing with PF?
OpenBSD routing with BGP and OSPF using PF
OpenBSD PF customization: how to modify and extend its functionality
OpenBSD routing with DNSBL and spam filtering using PF
OpenBSD PF benefits and advantages: why use it for routing?
OpenBSD routing with IPsec and IKEv2 using PF
OpenBSD PF case studies: how do real-world users apply it for routing?
OpenBSD routing with port forwarding and redirection using PF
OpenBSD PF automation: how to manage and update routing rules programmatically
OpenBSD routing with IPv4-mapped IPv6 addresses using PF
OpenBSD PF resources: where to find online forums, blogs, podcasts and videos about routing with PF
OpenBSD routing with proxy servers and caching using PF
OpenBSD PF review: what are the pros and cons of routing with PF?
OpenBSD routing with network monitoring and analysis using PF
OpenBSD PF future: what are the plans and goals for improving routing with PF?
To enable traffic redirection, you need to use the rdr-to filter option in your pf.conf file. For example, if you want to redirect incoming HTTP requests on port 80 to a web server running on port 8080 on your local network, you can add the following rule:
pass in on $ext_if inet proto tcp from any to ($ext_if) port 80 rdr-to 192.168.1.2 port 8080
This rule passes incoming TCP packets on em0 that are destined to port 80 on em0's address and redirects them to port 8080 on 192.168.1.2 (the web server's address).
Address Pools and Load Balancing
Address pools are lists of IP addresses that can be used for NAT or traffic redirection. You can use address pools in combination with route-to or reply-to filter options to load balance two or more internet connections when a proper multi-path routing protocol (like BGP4) is unavailable.
To create an address pool, you need to use parentheses around a list of IP addresses or macros in your pf.conf file. For example, if you have two external interfaces with different IP addresses, you can create an address pool like this:
( $ext_if1 $ext_if2 )
To use this address pool for load balancing outbound connections, you need to use route-to with a round-robin option in your pf.conf file. For example:
match out on egress inet from !($egress:network) nat-to ($egress:0) route-to \ ($egress:0), ($egress2:0) \ round-robin
This rule matches outgoing packets on egress that are not from egress' network and translates their source address to egress' address (NAT). It also routes them through either egress or egress2 interfaces in a round-robin fashion.
Packet Tagging (Policy Filtering)
Packet tagging allows you to mark packets with tags that can be used by other rules or applications. This is useful if you want to apply different policies or actions based on certain criteria or conditions.
To tag packets, you need to use the tag filter option in your pf.conf file. For example, if you want to tag packets from a specific IP address or network with a tag called "trusted", you can add the following rule:
pass in quick from 192.168.1.100 tag trusted
pass in quick from 10.0.0.0/8 tag trusted
To match tagged packets, you need to use the tagged filter option in your pf.conf file. For example, if you want to allow tagged packets with "trusted" tag to access any port on your firewall, you can add the following rule:
pass in quick tagged trusted
Tips and Tricks for Optimizing Your RouterLogging and Monitoring
Logging and monitoring are essential tasks for any router administrator, as they can help to identify and troubleshoot network problems, detect and prevent security breaches, and optimize network performance. PF provides several tools and options for logging and monitoring network activity, such as:
The pflog (4) pseudo-device, which records packets that match certain rules or criteria.
The pflogd (8) daemon, which writes the packets captured by pflog to a binary file (/var/log/pflog).
The tcpdump (8) utility, which can read and analyze the packets from pflog or any other interface.
The pftop (8) utility, which can display real-time information about PF's state table, rules, queues, etc.
The pfctl (8) utility, which can show various statistics and counters about PF's operation, such as packet and byte counts, state entries, memory usage, etc.
To enable logging for PF, you need to use the log filter option in your pf.conf file. For example, if you want to log all blocked packets on em0, you can add the following rule:
block log in on $ext_if all
This rule will log all incoming packets on em0 that are blocked by PF to pflog. You can also use the log option with other keywords, such as pass, match, or rdr-to, to log different types of packets.
To view the logged packets, you can use tcpdump with the -r option to read from /var/log/pflog. For example:
# tcpdump -n -e -ttt -r /var/log/pflog
This command will display the logged packets in a human-readable format, showing the timestamp, interface, source and destination addresses and ports, protocol, flags, etc. You can also use other tcpdump options or filters to narrow down the output.
To view real-time information about PF's state table, rules, queues, etc., you can use pftop with different modes and options. For example:
# pftop -s bytes
This command will display the top rules sorted by bytes. You can also use other sorting criteria, such as packets, rate, peak, etc. You can also switch between different modes by pressing keys on the keyboard. For example, pressing '2' will switch to the queue mode, which shows the status of the packet queues.
To show various statistics and counters about PF's operation, you can use pfctl with different options. For example:
# pfctl -s info
This command will show general information about PF's status, such as running state, debug level, hostid, etc. You can also use other options to show more specific information, such as -s rules to show the filter rules, -s states to show the state table entries, -s memory to show the memory usage, etc.
Conclusion
OpenBSD Routing with PF is a powerful and flexible way to turn your OpenBSD system into a router that can perform various tasks, such as filtering, NAT, port forwarding, load balancing, packet tagging, logging, and monitoring. In this article, we have shown you how to configure PF to perform some of these tasks, using examples from the official OpenBSD documentation. We have also explained some of the key concepts and features of PF, and provided some tips and tricks for optimizing your router. We hope that this article has helped you to understand how to use PF for OpenBSD routing.
If you want to learn more about PF, you can refer to the following resources:
The pf (4) man page, which provides a detailed description of PF's syntax and options.
The pf.conf (5) man page, which provides a comprehensive guide to writing PF rules and options.
The pfctl (8) man page, which provides a reference for the command-line utility for controlling PF.
The OpenBSD PF FAQ, which provides answers to frequently asked questions about PF.
The OpenBSD PF User's Guide, which provides a general introduction to the PF system as used in OpenBSD.
The OpenBSD PF Examples, which provide practical examples of using PF for various scenarios and needs.
Thank you for reading this article. We hope that you have enjoyed it and learned something new. If you have any questions or feedback, please feel free to leave a comment below. Happy routing!
3b9bd4fbbb