Академический Документы
Профессиональный Документы
Культура Документы
html
It's my hope that this guide will not only get you started, but give you
enough of a grasp of using pf so that you will then be able to go to
those more advanced guides and perfect your firewalling skills.
The pf packet filter was developed for OpenBSD but is now included in
FreeBSD, which is where I've used it. Having it run at boot and the like
is covered in the various documents, however I'll quickly run through
the steps for FreeBSD.
pf_enable="YES"
pf_rules="/etc/pf.conf"
pflog_enable="YES"
pflog_logfile="/var/log/pflog"
This will start the pf filter at boot. We'll cover starting it while running
after we put in some rules.
A few precautions
If your user name is john, then add a line (below any other lines giving
you less privileges--sudo processes the sudoers file from top to bottom)
crontab -e
1 of 11 29/09/2018 19:02
A Beginner's Guide to Firewalling with pf http://srobb.net/pf.html
This has the same effect, to stop pf after 2 minutes. (Change the time as
desired.)
Ok, now that we've ensured we'll be able to get back in the box, let's
create an /etc/pf.conf file. In FreeBSD, the file already exists. What I
usually do is start in my home directory, create the rules, and then test
them, loading them with sudo. Then, when it's working the way I want
it to work, I backup the default pf.conf and copy it over.
mv /etc/pf.conf /etc/pf.conf.bak
cp pf.conf /etc
A simple ruleset
In your home directory, open up your favorite text editor and create a
file called pf.conf to start setting your rules. We start with some macros.
Macros are similar to variables in programming. A brief example
tcp_pass = "{ 80 22 }"
We've created a macro. Later, when we make rules, rather than having
to make one rule for port 80 and a second for port 22 we can simply do
something like
The pf filter will read the rules we create from top to bottom. So, we
start with a rule to block everything
block all
This keeps the box pretty secure, but we won't be able to do anything.
So, in order to access web pages, allow the Network Time Protocol to
connect to a time server and to ssh to an outside machine, we can use
the macro we defined. Our pf.conf looks like this.
2 of 11 29/09/2018 19:02
A Beginner's Guide to Firewalling with pf http://srobb.net/pf.html
block all
pass out on fxp0 proto tcp to any port $tcp_pass keep state
Let's look at what we've done so far. First, we defined a macro. We used
port numbers. While one can mix and match if they want, for clarity's
sake, we try to use the same pattern for all ports. We can also put in
commas if we want or the protocol name if it's defined in /etc/services.
So, that macro could actually read
My personal habit is to have one white space between left bracket and
first port and another space between the last port listed and the white
bracket. (However, that white space, as shown in the example above, is
also optional--that is one can do { 80 or {80 and they will both work.
Also, keeping in them in numerical order helps you remember what
you're doing. So, let's clean up the above example a little bit.
tcp_pass= "{ 22 25 80 110 123 }"
You can only use a name if the port is defined in /etc/services. For
instance, if you decide to set ssh to only accept connections on port
1222, you would have to put 1222 in that macro, NOT ssh. Port 1222 is
defined in /etc/services as nerv, the SNI R&D network, so if you check
your rules with pfctl, it'll show that you have a rule to pass out to nerv.
To avoid confusion, if you're going to use a non-standard port, use
something that isn't listed in /etc/services.
You can also specify a range of ports with a colon. For instance, if I
wanted to add samba, which uses ports 137, 138 and 139, I could have
added 137:139.
So, we are allowing out web traffic, ssh connections, sending mail,
getting mail with pop3, and we're able to contact time servers.
So, we start with the action, pass. We're passing, not blocking. The
order of syntax is important. I'm just giving the basic options here,
again, this article can be considered a prep for more advanced tutorials.
pass out means we're allowing things out, not necessarily in. The next
part, on fxp0 refers to the interface--in this case, a network card that in
FreeBSD parlance is called fxp0. (An Intel card).
The keep state part can be important. It means that once we've
established the connection, pf is going to keep track of it, so the answer
from, for example, a web page, doesn't have to go through checking
each rule, but can just be opened. The same with pop3. One uses pop3
to contact a pop3 server (hrrm, obviously), and the server answers. As
3 of 11 29/09/2018 19:02
A Beginner's Guide to Firewalling with pf http://srobb.net/pf.html
we have the keep state keywords, the server's answer can go right
through once the connection is established.
If you look through /etc/services, you'll see that some things, such as
ipp, port 631 used with CUPS, use both tcp and udp. To deal with such
things, we could insert another macro
The same holds true for any other ports that you've forgotten. For
instance, these rules don't allow DNS, port 53. We grep domain in
/etc/services, and see that it uses both tcp and udp so we add 53 to both
macros
Packets going in and out are matched against an entire ruleset before
4 of 11 29/09/2018 19:02
A Beginner's Guide to Firewalling with pf http://srobb.net/pf.html
In such cases, you can use the quick keyword. If a packet matches
something in that line, it stops going through the rules and processes
the packet. For example, let's say that you have a web server on your
LAN behind a firewall, and you are sure that all requests for port 80 are
coming from your internal network, so you want to quickly pass them
through. (I can't see that being true in real life, but this is for an
example of using quick).
Put that above the other rules, right after the macro definitions. Now,
requests coming in for the LAN webserver will be passed right though
(note that in this case it was pass in) without being matched against the
rest of the ruleset.
Tables
Tables are useful and fast. They are used to hold a group of addresses.
For instance, suppose you want to allow everything in from your local
networks, 192.168.8.0 and 192.168.9.0
table <local> { 192.168.8.0/24, 192.168.9.0/24 }
Insert that line above your rules. Now, to allow everything from those
two networks (and we'll make use of the quick keyword as well) add a
rule. Since we're using quick we want this rule towards the top. If it was
at the end, there's no point in using the quick keyword, for the packets
would have already been matched against every rule above this one
will show you the contents of your table. Note that if you edit your
pf.conf, adding a table, and then simply pfctl -d and -e, to disable and
re-enable pf, the table rules may not be applied. The way to do it is
pfctl -t local -Tl -f /etc/pf.conf
The -t is for the table name, in this case, local. The -T is used to give
various commands. In this case, we are using l for load. That is a lower
case letter L, not the numeral one. The -f is for file, in this case,
/etc/pf.conf where we have added the table.
We can use pfctl for various useful table commands. We've already
mentioned the show command.
pfctl -t mytable -T show
will show you the current working contents of a table called mytable. If
you keep mytable in a static file, for example, /etc/pf.mytable, and edit
the file, the way to get pf to use it is
5 of 11 29/09/2018 19:02
A Beginner's Guide to Firewalling with pf http://srobb.net/pf.html
Tables can be added and deleted on the fly, see the links at the end of
this article for more details. To add or delete an address to a table on the
fly, one can use, to add the address 192.168.1.115 to a table called
mytable
pfctl -t mytable -T add 192.168.1.115
This all takes effect immediately. As mentioned above, you can confirm
that the desired address has been added or deleted with
pfctl -t mytable -T show
Anchors
Like tables, anchors can be added on the fly. However, tables are more
for addresses and anchors are for rules. They can be handy while
testing rulesets.
For example, I have an anchor to allow me to use ftp. I create a file that
reads
pass out proto tcp from any to port 21 keep state
pass out proto tcp from any to port > 1023 keep state
6 of 11 29/09/2018 19:02
A Beginner's Guide to Firewalling with pf http://srobb.net/pf.html
The -a is for anchor. In the first command the -f was for the file that we
are using. The second command uses -s as in show to show the rules. I
should get a reponse to that command showing the anchor ruleset of
passing out proto tcp on ports 21 and everything above port 1023
One can edit the anchor ruleset and reload and unload it at will without
having to restart pf or reload the entire pf.conf ruleset. It's handy for
testing various rules. For example, perhaps I also need to allow out udp
to do what I want. Rather than adding a line to pf.conf and reloading
the entire ruleset, I can edit /etc/ftp-anchor, add a line to allow out udp,
then reload the anchor with pfctl -a -f /etc/ftp-anchor again. Once again,
when finished, I can flush the anchor rules and my pf ruleset is back to
normal. (One doesn't need udp for ftp, but this is for example.)
If you think you will usually want to have the anchor in place, and only
unload it on rare occasions, you would add, below the anchor line
load anchor ftpanchor from "/etc/ftp-anchor"
Anchors are quite flexible. The above gives very simple examples. The
more detailed guides listed at the end of this article go into greater
detail.
To put the packet filter we've created into effect, assuming you are user
john and you've created it in your home directory, as john
The -f stands for file. Say we've checked it out and we don't like it so
we want to go back to our default rules, in /etc/
7 of 11 29/09/2018 19:02
A Beginner's Guide to Firewalling with pf http://srobb.net/pf.html
It used to be pfctl -Rf /etc/pf.conf but (and last I looked the man page
doesn't mention that) if you do so you'll get a message that you must
enable table loading for optimization. So, just use pfctl -f /etc/pf.conf
There are a variety of uses for pfctl. Doing pfctl -s info gives you a
quick look at what's going on. Doing pfctl -vs rules shows you your
rules and what's happening, for example
pass out proto tcp from any to any port = http keep state
[ Evaluations: 96 Packets: 906 Bytes: 496407 States: 0 ]
pass out proto tcp from any to any port = pop3 keep state
[ Evaluations: 96 Packets: 514 Bytes: 71260 States: 0 ]
Now it's time to test this. It's early morning, and I'm not thinking that
clearly. Hopefully, however, I've remembered to add myself to sudoers
as being able to run pfctl without a password and remember to quickly
set up the cronjob so that if I make a mistake, pf will be disabled
shortly. (VERY necessary if you're testing this on a machine to which
you don't have physical access). So, I put these rules which I've saved
into a file pf.conf in my home directory into operation.
I find that I've locked myself out of the box. Oops. I forgot to allow ssh
connections in, and the connection that I was using has just been
blocked.
So, I wait a few minutes for the crontab to disable pf and log back into
the remote machine. This time, I remember to add a rule
Listing the rules will show me that it's doing what I want to do.
8 of 11 29/09/2018 19:02
A Beginner's Guide to Firewalling with pf http://srobb.net/pf.html
There is also the scrub keyword. Again, while this is more fully
explained in the references below in a nutshell it normalizes fragmented
packets. The usual line is
scrub in all
This rule must also go above the filtering rules (and above the rdr to
redirect ftp if you use it.) It is the "normalization" referred to in that
error message. At the top of the ruleset you define your macros, tables
and the like. Then would come the scrub rule, then the rdr rule, then
your filtering rules (the group that in our example begins with block
all). Using the scrub keyword can help protect against certain kinds of
attacks, and it's a good line to have.
device pf
device pflog
device pfsync
I also have
options ALTQ
(I'm not sure if this is still needed or not, all the boxes I have still have
it in their custom kernels and I've never removed it.)
If you use the module, it assumes the presence of device bpf, INET and
INET6 in the kernel. (See the handbook page on pf.)
Logging
The log keyword comes after pass or block in or out. For example, we
have a rule
pass out proto tcp from any to port 21 keep state
9 of 11 29/09/2018 19:02
A Beginner's Guide to Firewalling with pf http://srobb.net/pf.html
pass out log proto tcp from any to port 21 keep state
To read it in realtime
tcpdump -n -e -ttt -i pflog0
It's pretty easy to use pf for NAT and redirection. One common use I've
seen is with a FreeBSD jail server, cloning its lo interface to give said
interface a private range of addresses. Then use pf to redirect queries on
say, 80 (and/or 443) to that address. First we clone the interface. In the
system's /etc/rc.conf we put
cloned_interfaces=lo1"
ipv4_addrs_lo1="192.168.1.1-9/29"
I haven't needed this often enough to figure out the syntax of creating
multiple lo1 addresses with ifconfig. If I were doing it on the fly, I
would set up rc.conf as mentioned, but use an alias on the command
line, e.g.
ifconfig lo1 alias 192.168.1.2/29.
(You could also use aliases in /etc/rc.conf instead of the syntax I have--
as the saying goes, in Unix there's always more than one way to do
something with a corollary that someone thinks your way is stupid, but
I digress.)
We'll assume you have a public address of 5.6.7.8 and you will redirect
inquiries to your webserver running on cloned lo1 interface
192.168.1.1. Our public network interface will be bce0. We'll assume
the reader has built a jail to host their web server. I have a page on jails
for readers looking to get started with them.
scrub in all
nat pass on bce0 proto tcp from $NETJAIL to any -> $IP_PUB
nat pass on bce0 proto udp from $NETJAIL to any -> $IP_PUB
rdr pass on bce0 proto tcp from any to $IP_PUB port $WEBPORT -> $NETJAIL
10 of 11 29/09/2018 19:02
A Beginner's Guide to Firewalling with pf http://srobb.net/pf.html
These two lines allow things from the jail to go out through the
public interface, in case that wasn't clear. It may not even be necessary.
In some cases, you may need tcp but not udp. The user can adapt it to
their needs.
These should all be added above rules, otherwise, one gets an error that
rules must be in order; options, normalization, queueing, translation,
filtering.
We can add other jails. For example, if we did give lo1 a range of
addresses, we might have 192.168.1.2 be a jail running MySQL. Create
a couple of new macros.
SQLJAIL="192.168.1.2"
SQLPORT="{ 3306 }"
Then add
rdr pass on bce0 proto tcp from any to $IP_PUB port $SQLPORT -> $SQLJAIL
(Or, as we expect 3306 to be the only port used, don't bother making a
macro for it, just have the rule read from any to $IP_PUB port 3306. As
long as the reader understands the syntax, they can do adapt it to their
needs.)
url:http://srobb.net/pf.html
11 of 11 29/09/2018 19:02