If you got this far, congratulations! We'll explore one of the main features of OPNsense – the firewall! In this chapter, we will learn which packet filter system OPNsense uses for firewalling, what type is it, how it works, what aliases or Packet Filter (pf) tables are, create our first rule, and explore diagnostics and troubleshooting. Through this chapter, you'll learn the firewalling basics that will be required to move on in this book, so pay attention reading it, practice the suggested exercises, and if you are unsure about some of the concepts presented here, please try to read it twice – it will be very important for you in the next chapters.
There will also be practical elements, so start your OPNsense virtual machine to follow all the topics explored here:
This chapter requires basic knowledge of networks, such as networking (for example, IP and IPv6) and transport protocols (for example, Transmission Control Protocol (TCP), User Datagram Protocol (UDP), Internet Control Message Protocol (ICMP), and ICMPv6), how they work, how to execute commands in the CLI, and a running OPNsense machine.
The word firewall is one of the most used ones to define OPNsense; even with a lot of other features, it is very common to hear from someone curious about your network topology asking, which firewall are you using in the network? The firewall feature is so important that it defines a whole network security platform. Let's find out why, beginning with the basics.
Every connection that a stateful firewall permits to pass will create a connection state, which means that the firewall will monitor all the connection information, such as the source, the destination, the protocol, the port number, and the protocol state. The protocols that a stateful firewall can handle are the ones that run on layers 3 and 4, using the OSI model as a reference. OPNsense running only with core features is considered a stateful firewall.
For example, monitoring the connection states will prevent common attacks that use the packet spoofing technique. If a packet is sent to a stateful firewall with an established state but doesn't exist in the firewall state table, then it will be blocked by the firewall.
Note
By default, OPNsense reserves 10% of the system RAM to the firewall state table; this setting can be changed, as we will see in the Firewall settings section.
As OPNsense contains a stateful firewall, you're able to check connections states in WebGUI at Firewall | Diagnostics | States Dump.
You will be able to check every state that OPNsense is monitoring. It will show the following columns:
OPNsense has another page on WebGUI that summarizes the state table connections: Firewall | Diagnostics | States Summary.
On this page, you will be able to find connections summarized by By Source IP, By Destination IP, and By IP Pair (source and destination).
Note
Depending on the number of connections handled by your state table size, this page can take a long time to load.
Sometimes, it is necessary to reset all connections on the state table. You can do it without rebooting OPNsense; to do so, go to Firewall | Diagnostics | States Reset.
On this page, you have two checkboxes:
Note
It will reset your WebGUI connection too, so it will be necessary to refresh the page after resetting the connections.
To reset the connections state table, just click on the Reset button.
Note
Be cautious using this – it will interrupt connections between the hosts that are using OPNsense as a network gateway. This can cause a lot of complaints from your boss, so think twice before pressing this button!
Now that we have learned what a stateful firewall is and how to check connection states, let's move on and talk about the packet filtering system used by OPNsense – the powerful pf!
pf's history starts from the OpenBSD project in 2001; it was designed to replace the IPFilter, which was removed from OpenBSD due to licensing concerns. The first FreeBSD version to have a ported version of pf was 5.3 in 2004, so, as you can see, this is a packet filtering platform with a long history, which brings reassurance of great reliability and trustworthiness. Despite FreeBSD's pf version originating from OpenBSD, the actual versions differ a lot on both platforms.
pf is what OPNsense uses to filter packets and to do network address translation, and you can find options related to it in WebGUI in the Firewall menu. It's not the purpose of this book to dive into pf's CLI utilities; one of the best features in OPNsense is its WebGUI, which makes managing firewalls very easy. But if you are interested in how to use pf command utilities, don't worry – during this chapter, we will learn a little bit about it.
This is an important thing to understand before we start creating firewall rules – what is an incoming packet? And what about the outgoing packets? Which ones are filtered by default? Let's understand from the firewall perspective first:
Note
By default, all incoming traffic, if not matched with some pass action rule, will be blocked by the default deny rule.
Note
By default, all outgoing traffic is allowed, if not matched with some block rule.
After finishing with these basic firewall concepts, let's learn about firewall aliases and pf tables.
To introduce you to aliases, let's start with a little story.
Let's imagine that you oversee an OPNsense firewall in a network with thousands of hosts, dozens of network segments, and a lot of VPN tunnels. This scenario will probably (considering good security practices) demand a lot of different rules to control host traffic, right? So, this will easily produce more than a thousand rules (yes – this part is based on a real example!), and managing each host individually using the one rule per host approach can increase this number to tens of thousands of rules incredibly quickly, becoming a nightmare to anyone in charge of managing the firewall!
Now, imagine it being possible to group hosts by access profile, selecting both source and destination hosts and adding them to lists, and then creating firewall rules based only on these lists.
This will drastically reduce the number of rules, turning the nightmare into the firewall ruleset of dreams! Now, you are probably feeling relieved thinking about the possibility of doing that. Well, we can do it!
Let me tell you about OPNsense aliases.
Aliases (also known as tables in the pf world) can group not only hosts but also networks, ports, fetch IPs from URLs, regions (using GeoIP), and much more! Let's see how to use them.
From the web browser, head to Firewall | Aliases:
Click on the + icon to open the new aliases dialog; in it, you will be able to create a new firewall alias using the following options:
Note
You can consult the MAC OUI on the internet using websites such as https://www.wireshark.org/tools/oui-lookup.html.
Users can easily spoof MAC addresses to bypass firewall rules based only on these criteria.
Note
Custom pf tables are not managed by the WebGUI and will not be saved in the configuration file (config.xml).
You can check the alias content in Firewall | Diagnostics: Aliases – we will see how to do this later in the chapter.
Now that we have learned how to create an alias, let's learn how to import and export it.
Let's think about the following scenario: you need to migrate from another firewall platform – let's say a brand name x, for example – and the configuration of it is sent to you with a lot of existing objects and with tons of IP addresses inside each one. If you decide to add each object IP list using just the WebGUI, then you'll spend a lot of time converting these objects into aliases. So, if you have programming skills (or hire professional support from a company that does), you can convert it quickly to JSON file format, which is the one OPNsense uses, and import all these objects, saving a lot of time.
Let's take an example to practice this concept:
Tip
While adding alias content, type a comma (,) or just hit the Enter key to add new values in the Content textbox.
Done! But wait – oh no! We forgot to add a port – the 465 SMTP port! Let's say we want to add the forgotten port in ascending order. So, we must add it between ports 25 and 587 – how can we do it? Let's see:
"aliases": {
"alias": {
"c0f60f78-c62b-4768-b9cf-b5c34df1f3bb": {
"enabled": "1",
"name": "SMTP_ports",
"type": "port",
"proto": "",
"counters": "1",
"updatefreq": "",
"content": "25 587",
"description": ""
},
"content": "25 587",
"content": "25 465 587",
Note
The special character represents a new line.
And what about the external (advanced) type of alias I mentioned before? Let's look at it.
To manage an external (advanced) alias type, it is necessary to look at the pf tables directly. There are two different ways of doing that:
The numbers marked in Figure 5.6 are explained here:
Notes
On this page, only aliases with an IP address in their content will be listed. You can also edit their content here, but remember that changes made here are not saved in the configuration file.
root@OPNsense:~ # pfctl -t bogons -T show
0.0.0.0/8
127.0.0.0/8
169.254.0.0/16
192.0.0.0/24
192.0.2.0/24
198.18.0.0/15
198.51.100.0/24
203.0.113.0/24
224.0.0.0/4
240.0.0.0/4
The command syntax to manage tables is as follows:
pfctl -t <table> -T <action>
In this book, we will be covering just three pfctl actions:
Now that you have learned all about aliases and tables, it's time to learn how to use them in the firewall rules.
One of the most important and useful features in OPNsense is the firewall rules. With them, OPNsense can control network traffic, and block, allow, or forward packets based on the firewall ruleset.
Before we start creating firewall rules, let's learn about some rule concepts used in OPNsense.
OPNsense uses the pf with the quick parameter set by default, which means that the matched rule will be processed immediately, on a first-match basis. Otherwise, if we leave the Quick option unchecked in the rule, the last-match basis will be used, which means that all the rules will be processed.
OPNsense divides rules by network interfaces, except for the floating rules, which permit creating rules on any interface and are processed before the rules defined in the interfaces ruleset.
The rule processing order is as follows:
To see the complete list of rules created in your OPNsense using the CLI, you can run the pfctl sa command:
root@OPNsense:~ # pfctl -sa | less
TRANSLATION RULES:
no nat proto carp all
nat on em0 inet from (em1:network) to any port = isakmp -> (em0:0) static-port
nat on em0 inet from (lo1:network) to any port = isakmp -> (em0:0) static-port
…
FILTER RULES:
scrub on em1 all fragment reassemble
scrub on lo1 all fragment reassemble
scrub on em2 all fragment reassemble
scrub on em0 all fragment reassemble
block drop in log on ! em1 inet from 192.168.56.0/24 to any
…
pass out log quick inet6 proto ipv6-icmp from (self) to fe80::/10 icmp6-type echorep keep state label "acdbb900b50d8fb4ae21ddfdc609ecf8"
It will output the complete ruleset, including the translation rules Network Address Translation (NAT).
If you want to only see the firewall rules, type pfctl -sr.
Let's now look at the rule actions.
There are three types of rule actions available:
Let's see how to create a firewall rule in WebGUI:
Let's create our first rule to practice the concepts learned in previous sections:
A new page will be opened, with the following options:
Note
The source port range option will be only available if you selected a compatible protocol in the Protocol option – for example, TCP or UDP.
Note
If you never heard about RFC1918, refer to https://datatracker.ietf.org/doc/html/rfc1918.
Note
The destination port range option will be only available if you selected a compatible protocol in the Protocol option – for example, TCP or UDP.
Now that we have described each option, let's create a LAN rule:
The numbers in the preceding screenshot refer to various options:
After the rule is created, try to run a ping command to your OPNsense LAN's IP address (in my case, the LAN is 192.168.56.3; change it to your OPNsense LAN's IP address):
$ ping -c 3 192.168.56.3
PING 192.168.56.3 (192.168.56.3): 56 data bytes
64 bytes from 192.168.56.3: icmp_seq=0 ttl=64 time=71.023 ms
64 bytes from 192.168.56.3: icmp_seq=1 ttl=64 time=1.205 ms
64 bytes from 192.168.56.3: icmp_seq=2 ttl=64 time=1.326 ms
--- 192.168.56.3 ping statistics ---
3 packets transmitted, 3 packets received, 0% packet loss
round-trip min/avg/max/stddev = 1.205/24.518/71.023/32.884 ms
The rule you have just created isn't blocking packets yet because the ICMP packets are matching the default allow rule created before the new rule. Let's try to move it to the first position in the LAN's ruleset and see what happens:
To move the rule position in the ruleset, follow these steps:
ping -c 3 192.168.56.3
PING 192.168.56.3 (192.168.56.3): 56 data bytes
--- 192.168.56.3 ping statistics ---
3 packets transmitted, 0 packets received, 100% packet loss
Now, let's look at the firewall settings and tweaks.
In the firewall settings options, you see how to adjust some firewall configurations such as optimization, firewall's behavior and maximum values to settings such as states and table entries.
In the following section, we will learn how each option can change the firewall settings and behavior globally in the system:
Note
To learn more about the available pf systems on FreeBSD, refer to https://docs.freebsd.org/en/books/handbook/firewalls/.
Note
The ruleset is reloaded every 15 minutes, so this will be the period of time a schedule can take to become active. Another detail to consider while using schedules is that an active connection will stay active until it closes, or until the state is killed on the firewall!
Congratulations! We just learned how to create a scheduled rule! Let's get back to the Firewall | Settings | Advanced page to move on with the schedule options:
Note
If you need to temporarily disable the firewall and NAT, you can run on the CLI the pfctl -d command, and to re-enable it, just run pfctl -e. When OPNsense is intended to be used as just a network router, this option may increase the throughput. Be careful running those commands in a production environment!
end value: 1000
current states number: 750
start value: 500
(1000 – 750) / (1000 – 500) = 0,5
In this case, when the state's number reaches 500, it will start to apply scaling. In the preceding example, the scale factor (with 750 current states) will be 50% (0,5), which means that the default timeout value will be decreased by 50%. The default value is 0.
That's all the available options on the firewall advanced settings page. Now, let's move on and look at some of the traffic normalization options available in WebGUI.
Go to Firewall | Settings | Normalization. On this page, it will be possible to change some traffic normalization (also known as scrubbing) settings and create new scrub rules for very specific cases when needed. Traffic normalization is useful to normalize packets that may be malformed or created intentionally – for example, for attacks.
The options available in General settings are as follows:
Now, we'll explore a little bit about firewall diagnostics and troubleshooting in the next section.
Truth has no answer – against facts, it's difficult to argue, so always count on logs and diagnostics tools to help you solve issues related to firewalls. Based on facts, your troubleshooting will be as sharp as a katana (a samurai's sword). As an airplane pilot, aviation experience taught me that things must be checked using a checklist based on facts, and as a firewall administrator, experience has taught me that a firewall will be blamed for network problems in 99.9% of cases. So, don't guess a problem – check it! OPNsense has a lot of tools that can help you with your troubleshooting. In time, users will start relying on just your word and not blame the firewall for any network (or maybe entire internet) problems. This is my advice for you based on a couple of decades of personal experience.
Starting at Diagnostic tools, go to Firewall | the Diagnostics menu:
Let's move on to the log options; head to Firewall | Log Files | Live View to start.
On this page, we will be able to see in real time all events generated by rules with the log option enabled or by system default rules, such as the default deny rule. This is a useful page and is the starting point for most firewall troubleshooting:
To see the raw log output, go to Firewall | Log Files | Plain view. As you can see in the preceding screenshot, the output of the live view is formatted and much easier to understand. The red lines are blocked traffic and the green lines are the allowed ones. OPNsense has a page that outputs graphics of the firewall logging; you can explore these graphics by going to Firewall | Log Files | Overview. Let's now explore some troubleshooting cases to see how to use diagnostic tools and log files to find firewall issues.
Let's look at some real use cases of issues relating to firewalls and see how we can try to solve each one using OPNsense tools.
In cases like this, a good start is looking at the firewall logs, specifically on the Live View page; this will help to filter the information about the connectivity issue. It is important to know what the source or destination address is (both is better), and the port number will help a lot but isn't essential to know in most cases. If you can't see connections being blocked, it means that the firewall is passing the traffic, or it isn't arriving in the firewall. If the traffic is passing, let's move on to the next item to be checked.
If a connection is passing through the firewall, it will generate a connection state. To check it, go to Firewall | Diagnostics | States Dump and filter for connections using a source or destination address, or even the port number. Here's a hint – you can filter for port numbers by typing :port (For example, 443 to filter port 443) in the Filter expression textbox. If traffic isn't arriving in the firewall, you probably will need to check other connectivity issues in the network to find out what is happening. Going to Interfaces | Diagnostics | Packet Capture may help you.
If traffic is blocked, then check the ruleset of the related interface. Maybe you'll need to create a new rule, adjust an existing one, or even change the rule order. Common issues related to rules are wrong protocols or port numbers, typos in addresses (source or destination), and so on; when reviewing a rule, be focused. I have seen good analysts take a long time to solve a firewall issue because they were not paying enough attention to the rule reviewing process.
In very rare cases, it's necessary to double-check whether a rule is applied to the pf reviewing the /tmp/rules.debug file in the CLI. Another way to check it is by running the pfctl -sr command. It's very rare in OPNsense to see rules not being loaded, but if you are in doubt, check it.
You can also check whether a rule has been matched with traffic by clicking on the Inspect button on the Rules page.
To end this topic, the last piece of advice is to always use your knowledge and experience. The OSI model is a good guide to follow when troubleshooting connectivity issues. If you don't know the OSI model yet, take a break from this chapter and start studying it; it will save you a lot of time. You can start here: https://en.wikipedia.org/wiki/OSI_model.
In this chapter, we learned about the OPNsense packet filtering system (the pf). We also learned what a stateful firewall is and how to check states on OPNsense, how to manage aliases and rules, how they are processed in OPNsense, creating rules' schedules, changing firewall settings, and explored firewall diagnostics and troubleshooting. Now you understand how OPNsense's firewalling works, how to create aliases and rules, how to adjust firewall settings, and how to troubleshoot firewall issues. Understanding firewalling is important in preparation for moving on to the next chapters.
In the next chapter, we'll continue the firewalling saga by exploring NAT rules!
3.21.159.25