[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: optimizing pf firewall

Hi Jon,
Thanks for your reply. For my nameservers line i don't really think only utilizing 3 addresses should make that much of a difference.
As for my scrub lines:
scrub on $ext_if all random-id reassemble tcp
scrub on $int_if inet no-df
I didn't think the internal interface needed fragment reassemble. Was this an error? Which interface would you scrub on/what options would you use?
I'll reorganize my block rules so that block all is right at the top, and delete the interface-specific block rules and the nmap rule.
Thanks for the info on tcp 53 vs. just udp 53! I'll change that rule, that might explain why i was having network weirdness. Should i also allow tcp/udp on dhcpclient and ntp as well as dns?
Good idea on stylistic strings, i'll add those that will be quite a time saver!
Any idea on why my active ftp isn't working? As i think i mentioned passive is, active isn't. I'd also like to integrate altq in to this, but am uncertain how to manage queues for two interfaces. I think i would want to use cbq so i can assign bandwidth to specific types of traffic, ssh, http, etc. But i'm uncertain how to do this as i've got traffic from both the internal network machines and traffic from the firewall itself, do i queue on the internal interface as well as the external or just one or the other?
Thanks a lot.

----- Original Message ----- From: "Jon Hart" <[email protected]>
To: "Dave" <[email protected]>
Cc: <[email protected]>
Sent: Friday, October 07, 2005 6:52 PM
Subject: Re: optimizing pf firewall

On Thu, Oct 06, 2005 at 03:48:17PM -0400, Dave wrote:
# pf.conf
# for use on gateway box

# Required order: options, normalization, queueing, translation, filtering.
# Macros and tables may be defined and used anywhere.
# Note that translation rules are first match while filter rules are last

# define the two network interfaces
ext_if = "rl0"
int_if = "rl1"

# define some address macros
lan_server = ""
# define services
int_to_lan_services = "{ ssh, smtp, www, pop3, https, pop3s, 1194, 1723,
8000 }"
lan_to_int_services = "{ ftp-data, ftp, ssh, smtp, 43, domain, http, pop3,
nntp, imap, https, imaps, pop3s, 1790, 1791, 1792, 1793, 1794, 1795, 2401,
4000, 4662, 4711,
5000, 5001, 5190, cvsup, 6112, 6667, 8000, 8021, 8080, 8505, 8880, 9102 }"
lan_to_fw_services = "{ ssh }"
fw_to_lan_services = "{ ssh, 9101, 9102, 9103 }"
nameservers = "{ xxx.xxx.xxx.xxx, xxx.xxx.xxx.xxx, xxx.xxx.xxx.xxx }"
isp_dhcp_server = ""

Wherever you have multiple addresses listed, it is my preference to use tables. Not only are they faster, they'll also allow you to add to them on the fly, control them from a single separate file, etc. Though, for 3 addresses, you may not even care.

# options
set optimization normal
set block-policy drop
set require-order yes
set fingerprints "/etc/pf.os"

# normalize packets to prevent fragmentation attacks
scrub on $ext_if all random-id reassemble tcp
scrub on $int_if inet no-df

Any particular reason you are not 'fragment reassemble' here?

# Thwart nmap scans block in log quick on $ext_if proto tcp all flags FUP/FUP

IMO, a good ruleset should never need something like this. Unless you are in a very weird environment, your default policy should *always* be drop/return and log. If that were the case, provided you didn't explicitly allow traffic that is supposedly generated from nmap, your default policy would catch it and log it.

The rest of the rules, which I've deleted for brevity, look reasonable.
The only suggestion I'd have is to, at the very top of your rules
section, clearly define your default policies.  In your case, you've got
default block rules scattered amongst allow rules which makes getting
the overall picture difficult.

Also, the following rule will likely come back to haunt you:

# allow UDP requests to port 53 from lan clients to enter LAN
# in order to perform dns queries on the firewall (keep state on this
pass in quick on $int_if inet proto udp from $int_if:network to $int_if
port 53 keep state

See the archives for the past week as to why this is bad. In short, if the query is too large (>512 bytes) (hint: nslookup pool.ntp.org), the RFC states that the client must(?) then try the same query using TCP. If you don't allow 53/tcp, you ntp connections might mysteriously stop working.

Just some general style hints, too.  These are just my personal
preferences but you may find them useful:

  * If you find yourself typing the same string more than, say,
    3 times, its probably worthy of a macro IMO.  Ones that
    I commonly use include:

        TCP_STATE="flags S/SA modulate state"
        UDP_STATE="keep state"
        PING="icmp-type 8 code 0"


  * If you find yourself routinely typing things like $int_if:network,
    I usually also make those a macro.  i.e.:


As far as performance optimization goes, I'm not sure there is much you
can do.  Some say that a good ordering can help with this, but
probably is only worthwhile if you've got tons of rules.  Even then, the
pain of having, say, your "allow" rules before your "default block"
rules, while it may make a difference performance wise (I'm not saying
it does, but others may say so...), is probably going to bring you
a world of hurt as far as maintenence and correctness goes.

Hope this helps...