# Generic NAT firewall pf config / template



## diizzy (Mar 15, 2017)

People seem to run into issues from time to time so I figured that I'd provide a sample config that pretty much mimics your generic SOHO router/gateway.


```
#################################
#### Packet Firewall Ruleset ####
#################################

###################
#### Variables ####
###################

# External interface
ext_if="CHANGEME"

# Internal interface
int_if="CHANGEME"

# Follow RFC1918 and don't route to non-routable IPs
# http://www.iana.org/assignments/ipv4-address-space
# http://rfc.net/rfc1918.html
nonroute= "{ 0.0.0.0/8, 20.20.20.0/24, 127.0.0.0/8, 169.254.0.0/16,
        172.16.0.0/12, 192.0.2.0/24, 192.168.0.0/16, 224.0.0.0/3,
        255.255.255.255 }"

# Set allowed ICMP types
# Blocking ICMP entirely is bad practice and will break things,
# FreeBSD applies rate limiting by default to mitigate attacks.
icmp_types = "{ 0, 3, 4, 8, 11, 12 }"

####################################
#### Options and optimizations #####
####################################

# Set interface for logging (statistics)
set loginterface $ext_if

# Drop states as fast as possible without having excessively low timeouts
set optimization aggressive

# Block policy, either silently drop packets or tell sender that request is blocked
set block-policy return

# Don't bother to process (filter) following interfaces such as loopback:
set skip on lo0

# Scrub traffic
# Add special exception for game consoles such as PS3 and PS4 (NAT type 2 vs 3)
# scrub from CHANGEME to any no-df random-id fragment reassemble
scrub on $ext_if all no-df fragment reassemble

#######################
#### NAT & Proxies ####
#######################

# Enable NAT and tell pf not to change ports if needed
# Add special exception for game consoles such as PS3 and PS4 (NAT type 2 vs 3)
# ie static-port mapping. Do NOT enable both rules.
# nat on $ext_if from $int_if:network to any -> ($ext_if) static-port
nat on $ext_if from $int_if:network to any -> ($ext_if)

# Redirect ftp connections to ftp-proxy
rdr pass on $int_if inet proto tcp from $int_if:network to any port 21 -> 127.0.0.1 port 8021

# Enable ftp-proxy (active connections)
# nat-anchor "ftp-proxy/*"
# rdr-anchor "ftp-proxy/*"

# Enable UPnP (requires miniupnpd, game consoles needs this)
# rdr-anchor "miniupnpd"

# Anchors needs to be set after nat/rdr-anchor
# Same as above regarding miniupnpd
# anchor "ftp-proxy/*"
# anchor "miniupnpd"

################################
#### Rules inbound (int_if) ####
################################

# Pass on everything incl multicast
pass in quick on $int_if from any to 239.0.0.0/8
pass in quick on $int_if inet all keep state

#################################
#### Rules outbound (int_if) ####
#################################

# Pass on everything incl multicast
pass out quick on $int_if from any to 239.0.0.0/8
pass out quick on $int_if inet all keep state

################################
#### Rules inbound (ext_if) ####
################################

# Drop packets from non-routable addresses immediately
block drop in quick on $ext_if from $nonroute to any

# Allow DHCP
pass in quick on $ext_if inet proto udp to ($ext_if) port { 67, 68 }

# Allow ICMP
pass in quick on $ext_if inet proto icmp all icmp-type $icmp_types

# Allow FTPs to connect to the FTP-proxy
# pass in quick on $ext_if inet proto tcp to ($ext_if) port ftp-data user proxy

# Block everything else
block in on $ext_if all

#################################
#### Rules outbound (ext_if) ####
#################################

# Drop packets to non-routable addresses immediately, allow everything else
block drop out quick on $ext_if from any to $nonroute
pass out on $ext_if all
```


----------



## SirDice (Mar 15, 2017)

Nice, clean, rule set. I'm only wondering why you're specifically allowing some multicast (239.0.0.0/8) in/out of int_if?


----------



## diizzy (Mar 15, 2017)

Thanks, it's from when I played around with IGMP, UPNP, IPTV and such. I don't have the notes in front of me but I have a vague memory of running into some odd issues not having those rules.


----------



## SirDice (Mar 15, 2017)

Thanks for clearing that up. Everything had notes what it does except that one


----------



## horseflesh (Mar 15, 2017)

Thanks for posting this. I recently had to switch to pf and am still learning the ropes, so studying quality examples like this is very useful. (I based my rule set on a similar config that I found elsewhere on this forum.)

I have a few questions if anyone's game. 

- Looks like the philosophy here to to trust everything on the LAN--the ext_if outbound traffic is allowing everything out unless a you precede the last _pass _command with a _block drop out quick_ rule for a special case. Correct? (I cannot imagine a default deny stance on outbound traffic... Imagine looking up every port everything uses.)

- In _Rules inbound (ext_if)_ you are allowing DHCP traffic, I assume so that the system can pick up an IP address from the ISP? (I'm on a static IP.)

- Can you explain the NAT type 2/3 difference? I have a couple of game consoles and via miniUPnP they seem to be operating OK... but I haven't really wrung them out yet with multiplayer. If the consoles benefit from the static-port directive, what's the reason for not making that the default config?

- This is the first config I have seen that addresses scrub configs for game consoles, which are alleged to have problems with the usual _scrub on $ext_if all_. Cool. Let me make sure I understand the syntax. 


```
# Scrub traffic
# Add special exception for game consoles such as PS3 and PS4 (NAT type 2 vs 3)
# scrub from CHANGEME to any no-df random-id fragment reassemble
scrub on $ext_if all
```

Looks like _all _should actually be _CHANGEME _in this template? And the comment key would be something like:


```
# Change scrub from CHANGEME to "all" for normal use
# or "any no-df random-id fragment reassemble" for game consoles
```

SO, the actual scrub config would look like this for game console optimization:


```
scrub on $ext_if any no-df random-id fragment reassemble
```

Thanks for the confirmation. Seems remedial, but the syntax is new to me and the scrub options especially are kind of black magic. 

In my own config I have added references to external files for IP blacklists and I am playing with the idea of adding geo-IP blacklists... More for the fun of configuration than actual worry about Chinese hackers.


----------



## diizzy (Mar 15, 2017)

You're correct, "everything" is allowed by default just like your standard off the shelf router. The "quick" keyword basically means stop doing further matches of rules and adhere this one.
Correct
In short it affects certain functions, usually in game features and chat. I'll leave a few links below where this is explained. The downside with static-port is that it is potentially slightly more unsecure, pfsense pretty much explains the pros and cons. UPnP is more of a security concern in that regard.
No, you use both. CHANGEME is the (local) IP address of your console. Preferably using a "static" IP using a DHCP server.
There's no need to do it overly complex, while I doubt you'll even see a major DDoS keep in mind that more rules also slows the overall processing down. Keep in mind that inaccurate lists may also lead to Internet services not working as expected as you're blocking something else than what you think you're blocking if that makes any sense. 
http://manuals.playstation.net/document/en/ps4/settings/nw_test.html
https://support.ubi.com/en-US/Faqs/000024696/Connection-Issues-PS4-R6S
https://support.activision.com/articles/en_US/FAQ/Port-Forward-and-NAT-FAQ/

https://doc.pfsense.org/index.php/Static_Port


----------



## aht0 (May 26, 2017)

Much appreciated. Do you still have some pf conf examples with functional IPTV setup around?


----------



## diizzy (May 28, 2017)

Unfortunately I don't have any IPTV setups available to test on but keep in mind that most providers are using a different VLAN than Internet access in general.


----------



## debguy (Jun 26, 2018)

your not supposed to silently drop according to RFCs, you send a drop.  you drop silently to hosts "you don't like" like a spam server.  also your not supposed to block ICMP your supposed to reply with a reject if your rejecting.

(those blocks can end up confusing certain web browers or net softwares.  use them only if you understand that and don't care - ie, on a server that don't want to talk)

if you had hackers on your system, they'd attack loopback - it's one of the oldest satan(1) tricks.  it's not safe to say loopback isn't a problem: it's a subject of the 2nd tier of things a sysadmin should attend.  i do the same: but it should be noted that it's NOT a safe policy.

addiing an exception for game consoles is only appropriate if your using BSD as a home router and have a game console that is attached to that rather than by WIFI to ISP modem: which isn't suggested.  also: don't enable IRC, irc is the favorite app of root hackers.

don't use FTP even proxied unless required.  ftp servers and clients have never been "safe" (they get hacked and are not %100 resilient) compared to getting files by HTTP or curl(1) or wget(1).  ftp was made safe-ER by the proxy not totally safe and the ftp server/clients: were not - they may or may not be susceptible and have same bugs they did 20 years ago.

you can't "ignore private addresses" (like 127.0.0.x 10.x.x.x).  you have to route them within the LAN if you have a LAN but route them only (back to them, not out on the internet by RFC).  this is simplified if you have two NICs one for each address class.  firewalls are a little more complicated if your bridging across classes (and note: if your using ipv6 - all get out - that's so complicated it takes a team to configure correctly, damn)

-------------------------

my advice: your inexpensive home route has a web address and web configuration, likely your ISP modem does too.  configure your _BASIC firewall and network essentials there.  it's easy and setup for you to do (sometimes schemes are offered).  it's quick.  it's a good backup if your BSD stops firewalling for some reason, as a backup.

"block everything else" ... will prevent any (ports) installed that do otherwise from working

you can of course "block all" and enable what you use, or allow all and block what you don't want

my advise there is: don't run older unix unprotected services (telnet, rsh, sendmail, ftp) or any new services (ANYTHING that has a long history of bugs in releases - which is most GPL software).  then you don't need a firewall because: nothing is there listening on the port to answer the call   and what is (say a web browser) isn't broken and won't allow intrusion (ie, firefox should (we hope) reject any attempt for a remote website to use java to login to your pc: infact firefox does this, if it is imperfect, it's designed to use port 80 and not trust port 80 - filtered or not.  it can be fooled by spoofing perhaps: but ICMP hacks can just blur that line not make it better.  the fact is any continuation after start is ... CONTINUED, and you can't really know who is on the other side talking ... not really, ip can be spoofed)

-------------------------------------

i like the script and firewalling.  i suggest freeBSD newbies read the freeBSD handbook and do what it says when it comes to firewalling and leave it alone until they are very studied in ipv6


----------



## debguy (Jun 26, 2018)

i just saw someone refer to 

https://en.wikipedia.org/wiki/PfSense

which is a "high quality graphical freeBSD open source firewall"


----------



## debguy (Jun 26, 2018)

another thing to know about firewalling (and QoS) is that significant filtering (hundreds of rules, hundreds of routes) will SIGNIFICANLY affect your network speed unless conditions are right (CPU is un-deterred, responsive, and over-capable - which it isn't on one CPU in the lower Ghz range with apps running)

you don't want to add #98749 rules and then find out: wow, i don't like the trade-off here


----------



## debguy (Jun 26, 2018)

Internet backbones are more specialized equipment rather than PC servers (though some FreeBSD and Linux distros are setup to operate as "high test routers" as purported Cisco alternates): they may have a LOT of memory to hold huge tables of numeric to name tables, CPUs dedicated to filtering without losing latency, many inbound/outbound ports, etc. they need non-priveleged (non-root) processes to handle ipv6 routing "run code to route" (which can attempt to crash router so can't run as root), as IPv6 has "payload code patches" embedded in IPv6 (a feature I don't like - it breaks the IPv4 rules of separation and requires routers to run code from a foreign server). IPv6 has "I'll write your route table for you" requests which your IPv6 will do if you don't stop it (ugh! - remote users can reroute your network's packets with IPv6), etc,  then also they have to support more than IPv6: but many other protocols. It's a big deal nothing simple. Also: Cisco uses a completely different language and toolset (though much of it would seem familiar to a 'nix net hack). Simple firewall ... can become something not so simple 

Today your home wifi is likely encrypted (soft though) to your ISP modem, your ISP modem encrypted out to internet, and both support internal (web browser accessible) firewalling - which is a "good start" as I said before if not just to see what the default setting / them is on the unit

If you got the cash and time get a Cisco router and set it up to server a crowd !   You'll need many tons of equipment to serve a big enough crowd to pay bills if I'm not incorrect.


----------



## diizzy (Jun 30, 2018)

I fail to see how this is related, it's a plain _simple_ ruleset that doesn't touch IPv6 at all.
If you have remarks, make them short and informative without going off topic or ranting.


----------



## ShelLuser (Jun 30, 2018)

I'm not going to reply to all your posts but you share a lot of theory which plain out doesn't work in the real world and which is in my opinion actually border lining bad advice.



debguy said:


> your not supposed to silently drop according to RFCs, you send a drop.  you drop silently to hosts "you don't like" like a spam server.  also your not supposed to block ICMP your supposed to reply with a reject if your rejecting.


Bad idea. If you'd do that you'd open yourself WIDE open to a DoS attack, and it wouldn't even take any effort at all. RFC's are best practices, not laws which people have to follow. Heck, if people actually did then the Internet would be a much worse place. According to the RFC's you're also not supposed to block e-mail but accept it, process it and then return it where some addresses should not be blocked at all (like postmaster@ for example). Needless to say that pretty much no one does that because it's a plain out stupid idea which would only lead up to much more spam processing.

Theories don't always reflect the real world.



debguy said:


> if you had hackers on your system, they'd attack loopback - it's one of the oldest satan(1) tricks.  it's not safe to say loopback isn't a problem: it's a subject of the 2nd tier of things a sysadmin should attend.  i do the same: but it should be noted that it's NOT a safe policy.


Depends on what services are running on the server. Context is key and as you can see the OP's intent was to mimic a router/gateway. Those are normally not used for anything else but network traffic. Besides: if you have a hacker on your console you got bigger issues to deal with anyway. I'm not saying you're wrong, but if you criticize someone it helps if you also keep context in mind. Otherwise it looks as if you're outing criticism just for the sake of it.



debguy said:


> also: don't enable IRC, irc is the favorite app of root hackers.


LOL

And this is where I stop taking you serious. You _do_ realize that there are many of us who still use IRC to communicate on a daily basis?



debguy said:


> you can't "ignore private addresses" (like 127.0.0.x 10.x.x.x).  you have to route them within the LAN if you have a LAN but route them only (back to them, not out on the internet by RFC).


Do you even understand what this firewall script is all about?  Because I have some serious doubts here.

See, the script doesn't ignore private addresses. It only makes sure that no attempts are made to access those addresses on the external interface. You know; where the Internet connection resides? And those blocks are called private for a reason; they don't exist on the Internet and as such should not be routed onto the Internet. This script makes sure that doesn't happen.

Seriously.. it's good to point out some possible points for improvements but please do make sure you actually understand what you're commenting on. Otherwise it's merely a rant which serves no purpose at all.


----------



## Snurg (Dec 26, 2019)

II am trying to get FTP proxying working on 12.1.
My config done according the pf.conf() manpage fails to do this.
So I looked for a generic config that seems to be okay and found this one.
I changed the "CHANGEME" parts and after that PF complained about the last line, where I had to change "all" to "from any to any".
Except for these changes, the pf configuration is exactly the same as shown above.
So my impression intensified that there might have been some change with PF, as I noticed that "all" seems no longer being accepted.

FTPing from the lan still fails trying and then timing out.
What is wrong with this pf.conf ?


----------



## diizzy (Dec 27, 2019)

```
all
```
 works just fine, can you paste the line pf complains about?


----------



## Snurg (Dec 27, 2019)

It is the very last line "pass out on $ext_if all". PF then complains "syntax error".

I first tried to use my old pf.conf which I took from my 11.0 box. To me it appears as if PF does no longer accept "all" in some contexts, complaining about "syntax error". I had to change a few "all" to "from any to any" to make PF work with that.

Another thought: the computer is behind a DSL router, with PAT on port 80 for some web stuff. With 11.0 I do not remember any issues with that, FTP proxying just worked fine. My gut feeling tells me, maybe some changes between 11.0 and could have 12.1 broken something?
Of course, there is the possibility to configure the DSL router to work as direct connection modem to test whether this would make FTP proxying work.
But I don't really like to do this, it would be like removing an additional layer of security, as port 80 PAT would be fully sufficient to serve the web pages.


----------



## SirDice (Dec 27, 2019)

Snurg said:


> It is the very last line "pass out on $ext_if all". PF then complains "syntax error".


Nothing wrong with that line. What's the content of your $ext_if? I suspect that's the cause of the error, not the `all`, `all` is just short for `from any to any`.


```
root@maelcum:~/test # cat pf.test.conf
ext_if="em0"
pass out on $ext_if all
root@maelcum:~/test # pfctl -nf pf.test.conf
root@maelcum:~/test #
```




Snurg said:


> Of course, there is the possibility to configure the DSL router to work as direct connection modem to test whether this would make FTP proxying work.


FTP opens a dynamic port for the data transfers. The double NAT you have (once on the modem and again on the FreeBSD firewall) makes this next to impossible to get working. I highly recommend setting your DSL modem/router in direct/pass-through mode and do all your NAT on the FreeBSD firewall. Then you only have to worry about one NAT layer. Even better would be to forgo FTP and switch to SFTP (which is basically FTP over SSH), SFTP only requires port 22. 



			Active FTP vs. Passive FTP, a Definitive Explanation


----------

