Other Confusing documentation

decuser I think the expectation to get "recipes" just doesn't apply too well to firewalling. For a real firewall, you WILL write a ruleset, and it will be your own.

On my firewall box, supporting several zones (internal clients, internal servers, guests, management and dmz), it currently looks like this:
Code:
# wc -l /etc/pf.conf
     163 /etc/pf.conf
(yes, it includes blank lines and comments…)

JFTR, the functionally same thing as a script configuring iptables on Linux was several times larger. I like PF :cool:
 
Maybe this is just a copy/paste error but you have spaces surrounding the slashes, those shouldn't be there.
Code:
sysrc firewall_myservices="22 / tcp 80 / tcp 443 / tcp"
This should be correct:
Code:
sysrc firewall_myservices="22/tcp 80/tcp 443/tcp"
 
decuser I think the expectation to get "recipes" just doesn't apply too well to firewalling. For a real firewall, you WILL write a ruleset, and it will be your own.
Got it. I am not interested in recipes. I think it would help to start with a simple scenario, as was suggested above, with beginner level discussion, before going deep. I’ll work on it and see if it makes sense after I put more effort into it. The discussion has helped a lot to refine my understanding of what I really think the problem is as well as why it is the way it is.
 
Maybe this is just a copy/paste error but you have spaces surrounding the slashes, those shouldn't be there.
Code:
sysrc firewall_myservices="22 / tcp 80 / tcp 443 / tcp"
This should be correct:
Code:
sysrc firewall_myservices="22/tcp 80/tcp 443/tcp"
Interesting. I had the same issue with copying the example I borrowed it from. Some artifact of the copy/paste buffer between my Mac terminal, the ssh session, and bash. I’ll be more careful in the future.
 
Got it. I am not interested in recipes. I think it would help to start with a simple scenario, as was suggested above, with beginner level discussion, before going deep. I’ll work on it and see if it makes sense after I put more effort into it. The discussion has helped a lot to refine my understanding of what I really think the problem is as well as why it is the way it is.
Maybe you can replace your router's firewall some day. It might be just me, but I don't really trust "consumer plastic".
One pitfall is that there's still a certain logic to the precedence rules in firewalls. A misplaced rule may end up working differently than expected.
Indeed, and this logic is pretty much the opposite between IPFW and PF, so, pay attention to that ?
 
I'm in the process of learning how to configure PF on a couple of FreeBSD servers. Here's what I've done so far, in order:

1. I read chapter 31. I kinda agree with decuser because I had no idea which of the 3 firewalls/packet filters to choose. But I did some Googling and people generally said PF was easier to configure (I have no idea if that's true of course) so I went with PF. I'd say chapter 31 is a bit... sparse. I had lots of unanswered questions.

2. I tried the example and BOOM I blocked myself from connecting to the server at my office. I had to get dressed and drive to my office at 2am, sit down at the terminal, and turn off PF. After returning home and sleeping a bit, I decided to Google some PF guides or tutorials. I found the one sidetone linked above, and...
- http://artemisa.unicauca.edu.co/~mtrujillo/OpenBSD/pf/filter.html
- http://home.nuug.no/~peter/pf/en/intro.html (many pages of info)
- https://www.digitalocean.com/community/tutorials/how-to-configure-packet-filter-pf-on-freebsd-12-1 (recent)

3. I made a FreeBSD virtual machine on my home computer. Then I opened a second terminal window, connected to the VM over SSH and kept playing with pf.conf. After the 4th or 5th time of locking myself out of the SSH connection, I was REALLY HAPPY I could just click in the VM window to turn off PF instead of driving to my office in the middle of the night.

4. Once I had a reasonably working set of rules for my VM, I made a new ruleset for the server at our office. The office server has a few web sites so it needs to be public facing. No one except me needs SSH access outside of the office, and only a couple workstations in the office need FTP access (for reasons lol). Here's what I did:
(for anyone new to PF reading this, these are NOT ACTUAL RULES, I'm just summarizing)
- created a whitelist with the office workstations on the local network
- pass my home IP on my custom SSH port
- pass the whitelist for all ports (this lets FTP work on the local network without any weird FTP rules)
- block martians
- block IPs on the blocklist
- block return in log all (<--- that one's an actual rule)
- pass on tcp ports 80, 443, etc
- pass on udp ports 53, 123, etc

I'm still figuring this out and I have LOTS of questions that don't seem to be answered in any of the tutorials. Yes, everyone's firewall rules are going to be different. But I think there's a LOT of room for improvement to the docs. For example...
- should I always use "return" or should I use "drop" sometimes?
- why are the lists of martians slightly different in almost every guide/tutorial?
- why doesn't traceroute work on the server when PF is running?
- should I still use antispoof if I'm blocking all the martians? (someone gave a good reason in another thread)
- should I use the built-in blacklistd or should I use fail2ban?
- do I need to use fail2ban if no one outside of the local network is accessing SSH or FTP?
- and many more... but I'm still studying and learning.

Anyway, I hope this helps someone.
 
- should I always use "return" or should I use "drop" sometimes?
It depends. Drop is if there's a strategic need for it to be silent, and to let the other side assume the packet got lost. For example, if something can test the system, and you don't want the firewall to return information by giving an error message. It's like a submarine receiving a ping, and staying silent. Return gives back an error. This can be found in pf(5).

There was something else that came to mind, about waiting for a response to packets, that allowed responses within a given time from the same port from a computer that a message was sent to. It was a stateful connection, which if the reply took too long, and the rules otherwise blocked it, it would be dropped. It could just be that any type of outgoing data went to another computer on a port, and any kind of response could come back from it, given a small window. That isn't reliable, however, for receiving data back.
- why doesn't traceroute work on the server when PF is running?
You can do a macro of variables or equivalencies of imcp and imcp6 types, which can go into the rulesets. trace for traceroute is in imcp(4).
Code:
# Macros section
icmptypeallow="{ unreach echoreq trace }"
The macro variable can be anything you choose, apart from icmptypeallow. Then, this would have to be allowed in a ruleset, which the macro is a convenient way to reference it.
- should I use the built-in blacklistd or should I use fail2ban?
Whichever works for you, has the features you need, is easier for you to use, or is to your style.
 
I'm still figuring this out and I have LOTS of questions that don't seem to be answered in any of the tutorials. Yes, everyone's firewall rules are going to be different. But I think there's a LOT of room for improvement to the docs. For example...
- should I always use "return" or should I use "drop" sometimes?
Depends on the firewall you choose.

- why are the lists of martians slightly different in almost every guide/tutorial?
Tutorials are meant as a guide. Following a tutorial to the letter may not fit your scenario exactly (Different paths, different options, etc.). You gotta be able to extract useful info and be able to connect it to your own setup. There's still a logical pattern that all those tutorials have in common, and yeah, it's on you to figure out how to mate that pattern to your system. Integrity of your system takes priority, BTW.
- why doesn't traceroute work on the server when PF is running?
Most likely, that's because ICMP (or port 33434, traceroute's default (see traceroute(8) for more info)) is blocked as a net effect of all the rules you set up.

Debugging a firewall is a MAJOR pain. So, in keeping with the Keep It Simple, Stupid principle, I can suggest an overall approach to make things a bit easier: Start by securing individual applications first. You wanna limit access to XDMCP to a list of specific users? Look at xorg.conf first. You wanna have an Apache subdomain be internal-only (but also have a public-facing site) ? look at httpd.conf before messing with the firewall.

A good analogy (with limitations, of course!) would be airport security. The firewall is TSA - they will check your luggage for guns and other prohibited items, but they will not stop you from going to the wrong gate and missing your flight. Applications are the airlines - If you have a ticket to fly on Delta, you won't be allowed to board a United flight, even if it goes to the same destination. TSA won't enforce that - it's up to the airline, not TSA. Same with firewalls - don't ask a firewall to enforce application-specific rules.

Oh, and pay attention to post #31, it contains really good and concise info:
 
- why are the lists of martians slightly different in almost every guide/tutorial?
Tutorials are meant as a guide. Following a tutorial to the letter may not fit your scenario exactly (Different paths, different options, etc.). You gotta be able to extract useful info and be able to connect it to your own setup. There's still a logical pattern that all those tutorials have in common, and yeah, it's on you to figure out how to mate that pattern to your system. Integrity of your system takes priority, BTW.

There's nothing really *wrong* with astyle's answer, but there's a little more to this, which is worth exploring a bit.

Many of the online tutorials are written by people relatively early in their journey to becoming proficient (or even experts!) in pf (or packet filtering firewalls in general).

The wide variance in the approaches to filtering martians (aka bogons (Wikipedia: bogon filtering)) is a fascinating case study. It makes a great example because in principle *and* in practice it's relatively straightforward. This makes it a great example for learning the basics, and for *teaching* the basics, too.

Unfortunately along one particular axis, it's deceptively simple. The difference that careful observers often notice is that the *list* of martians to block is wildly variant from example to example. Even experts with years of pf firewall configuration experience will post examples that are incomplete.

How can I say with confidence that any given example is incomplete or even wrong? Let's take a closer look at the objective of the rule.

The purpose of a martians rule is to protect a network or a host from a spoofing attack (Wikipedia), where an outside system tries to reach a host by way of forgery of the source IP address (Wikipedia: IP address spoofing).

This type of attack can work because the networks *behind* a firewall are often mapped out in address ranges defined by the standards as *private* or sometimes in other reserved IP address ranges (Wikipedia) which are allocated for other purposes. If you can trick the router and firewall into thinking the packet came from the inside, it stands a pretty good chance of being passed and processed by hosts on the inside.

Consider this example:

table <martians> const { 0.0.0.0/8 10.0.0.0/8 100.64.0.0/10 127.0.0.0/8 169.254.0.0/16 172.16.0.0/12 192.0.0.0/24 192.0.0.0/29 192.0.2.0/24 192.88.99.0/24 192.168.0.0/16 198.18.0.0/15 198.51.100.0/24 203.0.113.0/24 240.0.0.0/4 255.255.255.255/32 }

This, so far as I'm able to tell, is a complete and current list of ipv4 reserved address ranges.

To start with, it's not really very easy for a beginner to make this determination of completeness. If you google your way on that, there are many highly ranked, authoritative, but incomplete (wrong) answers! Why does this happen? Because the allocations have occasionally been amended, and the amendments are, mostly, buried in an RFC that nobody has read and nobody links to and the original RFC which everybody *does* link to doesn't get updated with a big bold headline THIS IS AMENDED BY or THIS IS SUPERSEDED BY. So you can land on what *looks* like an authoritative source, and never know there exist other ranges not included.

There are two specific technical errors in this example.

1. It doesn't include reserved ipv6 ranges.
2. It does include the broadcast range (255.255.255.255/32) which I *think* would be appropriate for a gateway or border firewall, but *not* appropriate for a workstation, or host firewall. It may or may not be appropriate for a host firewall on an internet-facing web server (if it's stand-alone, probably OK, but if it's part of a cluster, probably not.)

Another thing that you'll notice is that some firewall administrators include in their martians list one or more of the several IP address ranges allocated for multicast. I'm of the opinion that this is strictly incorrect because it makes the firewall rules difficult to understand, because *some* of the IP address ranges allocated for multicast are defined in the standards as routable.

A separate rule should be used, if one wants to block multicast, for clarity, and for ease of maintenance going forward.

One last observation. Some pf experts assert that a martians rule is unnecessary or obsoleted by the pf built-in function which you can activate with a simple rule like this one:

# automatically drop spoofed packets
antispoof for $ext_if inet

I suspect the pf built-in antispoof system is more sophisticated and handles more cases than merely blocking the documented non-routable IP address ranges, but I've not looked into that. It probably blocks all of the non-routable allocations, but I haven't tested it.

I've been intrigued by this phenomenon for years, and I think a martians rule makes a great learning exercise for people new to pf or firewalls.

Thanks for humoring me in this exploration of why it's an important example of how to approach learning pf (or other packet filtering firewalls).
 
RFC that nobody has read and nobody links to and the original RFC which everybody *does* link to doesn't get updated with a big bold headline THIS IS AMENDED BY or THIS IS SUPERSEDED BY. So you can land on what *looks* like an authoritative source, and never know there exist other ranges not included.
IETF RFCs are actually supposed to updated with that text ("This is obsoleted by this RFC", or "This obsoletes that RFC"). Sometimes, that text is in the heading of the document, sometimes in the end... Thing is, those documents originally don't contain hyperlinks, just plain ASCII text. It's still on the human reader to pay attention and catch on to that. At least that was the expectation back in the day when IETF RFCs were first published. There are a few attempts to automate that attention and insert hyperlinks to the target RFCs, like archive copies with textual analysis engines and other phone apps of similar capabilities.
 
Back
Top