The Firewall (pf)
The firewall? Already ?
Absolutely. You want to keep your fresh system safe, don't you?
We'll start with simple examples and suggest a few more for thoses interested.
On OpenBSD, the firewall is pf as in "packet filter". It is configured in "/etc/pf.conf". You will see, it's syntax is much easier than Linux's iptables.
First, you have to ask yourself what do you need. A web server (http)? Mail server? Depending on your answers, you won't open the same port number. We actually will close every port except the ones you really need.
To find the ports on which services listen, look at the contents of the "/etc/services" file. Thus, writing "www" or "80" is the same for pf, but is more readable for humans.
The rules you will define will be applied in the order they are written.
A first example
Ready? Let's go for a detailed but simple example. We are going to configure the firewall for a website with access on ports 80 (www) and 443 (https).
We start by blocking everything, and recording in the log the prohibited connections with the word "log" (obvious đ).
block log
To make our life easier, we are going to put the ports to be opened in a variable. This will be particularly practical when there are more ports to manage.
tcp_pass = "{ 80 443 }"
Note that this is identical to 'tcp_pass = "{ www https }"'
Then, we allow potential visitors to access your server. These will be so-called "incoming" connections, so we will use the "in" keyword. Instead of looking for the name of your network interface (which depends on your hardware), we will specify the name of the group that these interfaces belongs to so that it works without worry: "egress".
pass in quick on egress proto tcp to port $tcp_pass
You're cute eh, but that's all gibberish!
Okay, we'll explain what this syntax means. We can translate the previous configuration line as follows: "let pass inward (pass in) without taking into account the rules that could follow (quick) through the egress interface (on egress) for the tcp protocol (proto tcp) to the ports in $tcp_pass (to port $tcp_pass).
Fiew! đ
Finally, we allow all the output traffic (keyword "out"):
pass out on egress
Finally :
tcp_pass = "{80,443}" block log pass in quick on egress proto tcp port $tcp_pass pass out on egress all
Easy, right? đ
I suggest that you replace the last line with something a little more restrictive:
pass out on egress proto {tcp udp icmp ipv6-icmp} modulate state
We simply specify the protocols authorized on exit with a precaution for each outgoing connection (modulate state).
You will understand, pf allows us a first order control on our server. At first, you'll just want to choose which ports should be opened.
This makes a lot of new concepts, take the time to reread what has been written so far if necessary.
When you are more comfortable, know that we can filter incoming and outgoing traffic, and even redirect part of it to internal services (eg anti-spam). I invite you to read the part "going-further-with-pf". You will see how to ignore certain lists of IPs known as harmful that will be recorded in tables, rules against bruteforce attacks or even a proposed tool that adds potential hackers to the blacklist in real time.
I let you build your /etc/pf.conf file according to your needs. Start from the example seen above then add the ports to open. Do not hesitate to consult the example provided at the end of this document.
To be sure, can we have an example to open the SSH port?
If the configured SSH port is 22, then you will have in the pf configuration:
pass in quick on egress proto tcp to port 22
Of course, you can also just change the tcp_pass variable:
tcp_pass = "{80 443 22}" pass in ...
Convenient commands for pf
Find below suggestions of useful commands to manage pf:
- Disable the firewall: "# pfctl -d"
- Activate the firewall with the /etc/pf.conf file: "# pfctl -ef /etc/pf.conf"
- Restart the firewall: "# pfctl -d && pfctl -ef /etc/pf.conf"
- Reload the firewall configuration: "# pfctl -f /etc/pf.conf"
- Empty the firewall rules (â Warning!), It can be useful when you self-ban yourself from the server (yes, it happens even to the best ...): "# pfctl -F all"
- See in real time what the firewall is blocking (provided you have put the "log" keyword in the configuration): "# tcpdump -n -e -ttt -i pflog0"
- View the saved logs at any time: "# tcpdump -n -e -ttt -r / var / log / pflog"
- Display the list of blocked IPs in a table: "# pfctl -t table_name -T show"
- Add an IP in a table: "# pfctl -t name_of_the_table -T add 123.456.678.909"
- Remove an IP from a table "# pfctl -t table_name -T delete 123.456.678.909"
- List all active rules: "# pfctl -sr"
Go further with pf
pf-badhost: IP blacklist
Some IPs are known to be harmful. Between those that scan for an open port or those that attempt bruteforce attacks, the list goes on. Fortunately, we can configure the firewall so that it completely ignores these IPs and thus protect and lighten the load on our server.
This is what allows the pf-badhost project.
Author's blacklists
I keep up to date lists of IP who recentrly tried bad stuff on my server.
Bruteforce
One method hackers use to attack a server is called "bruteforce". Suck attacks consist of trying all possible username / password combinations until they find the correct one.
If you choosed strong passphrases, you should be safe. However, these attacks abuse resources on your server and can potentially succeed one day (admit that it would be bad luck).
In order to thwart these attacks, you should take the time to analyze the logs of the services you host (in "/var/log" and "/var/www/logs") for identification failures and notice where these attacks are coming from to banish the source. But let's be honest, it's both painful and time consuming.
Ideally, a tool that monitors logs for you and takes care of blacklisting "attacker" IPs on your firewall. Good thing, you can use vilain or sshguard which are made for that.
In the meantime, pf already integrates a protection which limits the number of connections on a port during a given time. It is very effective and remains light. Read the next paragraph đ.
Anti-Bruteforce integrated into pf
pf has a very interesting feature: "tables". This will allow us to remember certain IP addresses of hackers who would try to compromise the server. For example, to protect the SSH service, we will proceed as follows:
- 1. Creation of a table to record abusive IPs with our SSH server.
- 2. Block all the IPs that would be in the previous table, and do not go further for them.
- 3. Open the ssh port, but record in the previous table all the IPs that attempt to connect more than 3 times per minute (bruteforce attack).
So that gives us this:
ssh_port = "22" table <ssh_abuse> persist block in log quick proto tcp from <ssh_abuse> to any port $ssh_port pass in on egress proto tcp to any port $ssh_port flags S/SA keep state (max-src-conn-rate 3/60, overload <ssh_abuse> flush global)
Note that we have recorded the port number used for the SSH server. It is useless, because one can put in the place of "$ssh_port" simply "ssh", the name of the service. However, you may want to change the default port of the SSH server, as described in the chapter on this service.
Here is another example for a website (http and https ports):
http_ports = "{www https}" # ports http (s) # If more than 40 connections every 5 seconds on the http (s) ports # or if she tries to connect more than 100 times # we add the ip to block it. pass in on egress proto tcp to any port $http_ports flags S/SA keep state (max-src-conn 100, max-src-conn-rate 40/5, overload <http_abuse> flush global)
Anti-bruteforce in real time with vilain
I would like to offer you a tool that I wrote with the help of Vincent Delft in order to blacklist possible hackers when the attack takes place.
The script in question is called vilain.
Anti-bruteforce in real time with sshguard
Its installation in OpenBSD is not very complicated to set up. You will need to create a table in pf that will contain all the blacklisted IPs. Thus, we add in the /etc/pf.conf file a new table containing the IPs of the attackers who are immediately blocked:
table <sshguard> persist block in from <sshguard>
Reload the firewall with pfctl -f /etc/pf.conf.
Now, we install sshguard as we usually do:
# pkg_add sshguard
Copy the configuration file given as an example:
# cp /usr/local/share/examples/sshguard/sshguard.conf.sample /etc/sshguard.conf
Edit this file if you want to make it more or less harsh. The default options are quite reasonable.
We can now enable and run sshguard:
# rcctl enable sshguard # rcctl start sshguard
And there you go, your server is now safer.
You may want to whitelist some IP addresses with the "-w" option. Do this (this option can be used more than once).
rcctl set sshguard flags -w 192.168.1.0/24 -w 123.123.123.123
Trap with iblock
solene@ wrote a tool named iblock.
iblock ban every IP trying to access your server on ports that are actually unused.
This is definitely a must-have.