Pf

Aus SchnallIchNet
Version vom 16. Januar 2015, 09:55 Uhr von Cbs (Diskussion | Beiträge) (pfctl basic overview)

Wechseln zu: Navigation, Suche
Achtung.jpeg BEST rule matches!!! Not like iptables where first rule matches!

Enable PF

In OpenBSD and NetBSD, you do this by editing /etc/sysctl.conf, by changing the lines you need, like this

net.inet.ip.forwarding=1
net.inet6.ip6.forwarding=1

On FreeBSD, you conventionally do the corresponding change by putting these lines in your /etc/rc.conf

gateway_enable="YES" #for ipv4
ipv6_gateway_enable="YES" #for ipv6

/etc/rc.d/pf

Usage: /etc/rc.d/pf [fast|force|one](start|stop|restart|rcvar|check|reload|resync|status)

/etc/pf.conf

first:

block all

some macros:

tcp_services = "{ ssh, smtp, domain, www, pop3, auth, pop3s }"
udp_services = "{ domain }"
ports = "{ ssh, smtp, domain, www, pop3, auth, pop3s, domain }"

Now it's very reasonable to think that if you want traffic to pass from the network connected to ep1 to hosts on the network connected to ep0, you will need a rule like

pass in inet proto tcp on ep1 from ep1:network to ep0:network port $ports keep state

which keeps track of states as well.

However, one of the most common and most complained-about mistakes in firewall configuration is not realizing that the "to" keyword does not in itself guarantee passage all the way there. In fact, the rule we just wrote only lets the traffic pass in to the gateway itself, on the specific interface given in the rule. To let the packets get a bit further on and move into the next network over, you would need a matching rule which says something like:

pass out inet proto tcp on ep0 from ep1:network to ep0:network port $ports keep state

These rules will work, but they will not necessarily achieve what you want.

If there are good reasons why you need to have rules which are this specific in your rule set, you know you need them and why. By the end of this tutorial you should be able to articulate with some precision, in the context of your own network, just when such rules are needed. However for the basic gateway configurations we'll be dealing with here, what you really want to use is probably a rule which says

pass inet proto tcp from ep1:network to any port $ports keep state

to let your local net access the Internet and leave the detective work to the antispoof and scrub code. They are both pretty good these days, and we will get back to them later. For now we just accept the fact that for simple setups, interface bound rules with in/out rules tend to add more clutter than they are worth to your rule sets.

For a busy network admin, a readable rule set is a safer rule set. For the remainder of this tutorial, with some exceptions, we will keep the rules as simple as possible for readability.

ext_if = "ep0" # macro for external interface - use tun0 for PPPoE
int_if = "ep1"  # macro for internal interface
localnet = $int_if:network

# ext_if IP address could be dynamic, hence ($ext_if)
nat on $ext_if from $localnet to any -> ($ext_if) 
block all
pass inet proto tcp from { lo0, $localnet } to any keep state

Note the use of macros to assign logical names to the network interfaces. Here 3Com cards are used, but this is the last time during this lecture we will find this of any interest whatsoever. In truly simple setups like this one, we may not gain very much by using macros like these, but once the rule sets grow somewhat larger, you will learn to appreciate the readability this adds to the rule sets

Also note the nat rule. This is where we handle the network address translation from the non-routable address inside your local net to the sole official address we assume has been assigned to you.

The parentheses surrounding the last part of the nat rule ($ext_if) serve to compensate for the possibility that the IP address of the external interface may be dynamically assigned. This detail will ensure that your network traffic runs without serious interruptions even if the external IP address changes.

On the other hand, this rule set probably allows more traffic than what you actually want to pass out of your network. Where I work, the equivalent macro is

client_out = "{ ftp-data, ftp, ssh, domain, pop3, auth, nntp, http, https, 446, cvspserver, 2628, 5999, 8000, 8080 }"

with the rule

pass inet proto tcp from $localnet to any port $client_out flags S/SA keep state

This may be a somewhat peculiar selection of ports, but it's exactly what my colleagues and I need. Some of the numbered ports are needed for systems I am not allowed to discuss any further. Your needs probably differ at least in some specifics, but this should cover at least some of the more useful services.

In addition, we have a few other pass rules. We will be returning to some of the more interesting ones rather soon. One pass rule which is useful to those of us who want the ability to administer our machines from elsewhere is

pass in inet proto tcp from any to any port ssh

or for that matter

pass in inet proto tcp from any to $ext_if port ssh

whichever you like. Lastly we need to make the name service and time keeping work for our clients

udp_services = "{ domain, ntp }"

supplemented with a rule which passes the traffic we want through our firewall:

pass quick inet proto { tcp, udp } to any port $udp_services keep state

Note the quick keyword in this rule. We have started writing rule sets which consist of several rules, and it is time to take a look at the relationships between the rules in a rule set. The rules are evaluated from top to bottom, in the sequence they are written in the configuration file. For each packet or connection evaluated by PF, the last matching rule in the rule set is the one which is applied. The quick keyword offers an escape from the ordinary sequence. When a packet matches a quick rule, the packet is treated according to the present rule. The rule processing stops without considering any further rules which might have matched the packet. Quite handy when you need a few isolated exceptions to your general rules.

It is worth noting that we used one rule for both the domain name service (domain and time synchronization (ntp). The most important reason for this is that both protocols under certain circumstances communicate alternately over TCP and UDP.

FTP-Proxy (old style)

Achtung.jpeg OpenBSD 3.8 or earlier equivalents only This section is headed for purely historical status when the last PF port to other systems has caught up. In November 2005, the old ftp-proxy (/usr/libexec/ftp-proxy) was replaced in OpenBSD-current with the new ftp-proxy, which lives in /usr/sbin. This is the software which is included in OpenBSD 3.9 onwards and what you will be using on modern PF versions. See the Section called ftp-proxy, new style for details.

The old style ftp-proxy which is a part of the base system on systems which offer a PF version based on OpenBSD3.8 or earlier is usually called via the inetd "super server" via an appropriate /etc/inetd.conf entry.[14]

The line quoted here specifies that ftp-proxy runs in NAT mode on the loopback interface, lo0:

127.0.0.1:8021 stream tcp nowait root /usr/libexec/ftp-proxy ftp-proxy -n

This line is by default in your inetd.conf, commented out with a # character at the beginning of the line. To enable your change, you restart inetd.

On FreeBSD, NetBSD and other rcNG based BSDs you do this with the command

FreeBSD$ sudo /etc/rc.d/inetd restart

or equivalent. Consult man 8 inetd if you are unsure. At this point inetd is running with your new settings loaded.

Now for the actual redirection. Redirection rules and NAT rules fall into the same rule class. These rules may be referenced directly by other rules, and filtering rules may depend on these rules. Logically, rdr and nat rules need to be defined before the filtering rules.

We insert our rdr rule immediately after the nat rule in our /etc/pf.conf

rdr on $int_if proto tcp from any to any port ftp -> 127.0.0.1 port 8021

In addition, the redirected traffic must be allowed to pass. We achive this with

pass in on $ext_if inet proto tcp from port ftp-data to ($ext_if) \
   user proxy flags S/SA keep state

Save pf.conf, then load the new rules with

$ sudo pfctl -f /etc/pf.conf

At this point you will probably have users noticing that FTP works before you get around to telling them what you've done.

This example assumes you are using NAT on a gateway with non routable addresses on the inside.

FTP-Proxy (new style)

Achtung.jpeg For OpenBSD 3.9 and newer If you are upgrading to OpenBSD 3.9 or newer equivalents or working from a fresh OpenBSD install, this is the ftp-proxy version to use.

Just like its predecessor, the pftpx successor ftp-proxy configuration is mainly a matter of cut and paste from the man page.

If you are upgrading to the new ftp-proxy from an earlier version, you need to remove the ftp-proxy line from your inetd.conf file and restart inetd or disable it altogether if your setup does not require a running inetd.

Next, enable ftp-proxy by adding the following line to your /etc/rc.conf.local or /etc/rc.conf

ftpproxy_flags=""

You can start the proxy manually by running /usr/sbin/ftp-proxy if you like.

Moving on to the pf.conf file, you need two anchor definitions in the NAT section:

nat-anchor "ftp-proxy/*"
rdr-anchor "ftp-proxy/*"

Both are needed, even if your setup does not use NAT. If you are migrating from a previous version, your rule set probably contains the appropriate redirection already. If it does not, you add it:

rdr pass on $int_if proto tcp from any to any port ftp -> 127.0.0.1 port 8021

Moving on down to the filtering rules, you add an anchor for the proxy to fill in,

anchor "ftp-proxy/*"

and finally a pass rule to let the packets pass from the proxy to the rest of the world

pass out proto tcp from $proxy to any port 21 keep state

where $proxy expands to the address the proxy daemon is bound to.

This example covers the simple setup with clients who need to contact FTP servers elsewhere. For other variations and more complicated setups, see the ftp-proxy man page.

If you are looking for ways to run an FTP server protected by PF and ftp-proxy, you could look into running a separate ftp-proxy in reverse mode (using the -R option).

Achtung.jpeg To be continued...

Sample (full)

#       $FreeBSD: src/etc/pf.conf,v 1.2.2.1 2006/04/04 20:31:20 mlaier Exp $
#       $OpenBSD: pf.conf,v 1.21 2003/09/02 20:38:44 david Exp $
#
# See pf.conf(5) and /usr/share/examples/pf for syntax and examples.
# 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 match.

# Macros: define common values, so they can be referenced and changed easily.
#ext_if="ext0"  # replace with actual external interface name i.e., dc0
#int_if="int0"  # replace with actual internal interface name i.e., dc1
#internal_net="10.1.1.1/8"
#external_addr="192.168.1.1"

# Tables: similar to macros, but more flexible for many addresses.
#table <foo> { 10.0.0.0/8, !10.1.0.0/16, 192.168.0.0/24, 192.168.1.18 }

# Options: tune the behavior of pf, default values are given.
#set timeout { interval 10, frag 30 }
#set timeout { tcp.first 120, tcp.opening 30, tcp.established 86400 }
#set timeout { tcp.closing 900, tcp.finwait 45, tcp.closed 90 }
#set timeout { udp.first 60, udp.single 30, udp.multiple 60 }
#set timeout { icmp.first 20, icmp.error 10 }
#set timeout { other.first 60, other.single 30, other.multiple 60 }
#set timeout { adaptive.start 0, adaptive.end 0 }
#set limit { states 10000, frags 5000 }
#set loginterface none
#set optimization normal
#set block-policy drop
#set require-order yes
#set fingerprints "/etc/pf.os"

# Normalization: reassemble fragments and resolve or reduce traffic ambiguities.
#scrub in all

# Queueing: rule-based bandwidth control.
#altq on $ext_if bandwidth 2Mb cbq queue { dflt, developers, marketing }
#queue dflt bandwidth 5% cbq(default)
#queue developers bandwidth 80%
#queue marketing  bandwidth 15%

# Translation: specify how addresses are to be mapped or redirected.
# nat: packets going out through $ext_if with source address $internal_net will
# get translated as coming from the address of $ext_if, a state is created for
# such packets, and incoming packets will be redirected to the internal address.
#nat on $ext_if from $internal_net to any -> ($ext_if)

# rdr: packets coming in on $ext_if with destination $external_addr:1234 will
# be redirected to 10.1.1.1:5678. A state is created for such packets, and
# outgoing packets will be translated as coming from the external address.
#rdr on $ext_if proto tcp from any to $external_addr/32 port 1234 -> 10.1.1.1 port 5678

# rdr outgoing FTP requests to the ftp-proxy
#rdr on $int_if proto tcp from any to any port ftp -> 127.0.0.1 port 8021

# spamd-setup puts addresses to be redirected into table <spamd>.
#table <spamd> persist
#no rdr on { lo0, lo1 } from any to any
#rdr inet proto tcp from <spamd> to any port smtp -> 127.0.0.1 port 8025

# Filtering: the implicit first two rules are
#pass in all
#pass out all

# block all incoming packets but allow ssh, pass all outgoing tcp and udp
# connections and keep state, logging blocked packets.
#block in log all
#pass  in  on $ext_if proto tcp from any to $ext_if port 22 keep state
#pass  out on $ext_if proto { tcp, udp } all keep state

# pass incoming packets destined to the addresses given in table <foo>.
#pass in on $ext_if proto { tcp, udp } from any to <foo> port 80 keep state

# pass incoming ports for ftp-proxy
#pass in on $ext_if inet proto tcp from any to $ext_if port > 49151 keep state

# Alternate rule to pass incoming ports for ftp-proxy
# NOTE: Please see pf.conf(5) BUGS section before using user/group rules.
#pass in on $ext_if inet proto tcp from any to $ext_if user proxy keep state

# assign packets to a queue.
#pass out on $ext_if from 192.168.0.0/24 to any keep state queue developers
#pass out on $ext_if from 192.168.1.0/24 to any keep state queue marketing

#ext_if = "tun0"
#vpn_if = "enc0"

ext_if = "re2"
int_if = "re0"
vpn_if = "tun7"

priv_net =  "{ 127.0.0.0/8, 192.168.0.0/24, 172.16.0.0/12, 10.0.0.0/8 }"
local_net = "{ 10.0.0.0/16, 10.3.0.0/16 }"
netcar24_net = "{ 10.0.0.0/16, 10.3.0.0/24, 192.168.0.0/16 }"

nat_net = "{ 82.115.106.130, 82.115.106.190, 82.115.106.189, 82.115.106.188, 82.115.106.187, 82.115.106.186 }"
ext_master_ip = "82.115.106.130"

icmp_types = "{ echoreq, echorep, unreach, timex, paramprob }"

# wsmc
forced_proxy = "{ 10.0.2.12 }"


webservers="{ 10.0.2.252, 10.0.2.11 }"


set timeout { tcp.first 120, tcp.opening 30, tcp.established 86400 }
set limit { states 60000, frags 30000 }

#options
set block-policy return
#set loginterface $ext_if

#Scrubs
scrub in all

### queuing ##########################

#queue std_out priority 4 priq (default)
#queue low_pri_out priority 1
#queue ssh_out priority 6
#queue tcp_ack_out priority 7
#
#altq on $ext_if priq bandwidth 192Kb
#
#queue std_in priority 4 priq (default)
#queue low_pri_in priority 1
#queue ssh_in priority 6
#
#altq on $intif priq bandwidth 240Kb queue {std_in, voip_in, low_pri_in}

# pass out on $intif proto {tcp udp} from any port $low_pri to $intif:network queue low_pri_in

## XXX queuing
##altq on $ext_if priq bandwidth 188Kb queue { q_pri, q_vpn, q_def }
##      queue q_pri priority 7
##      queue q_vpn priority 4
##      queue q_def priority 1 priq(default)

### nat ##############################

nat-anchor "pftpx/*"
rdr-anchor "pftpx/*"

# relayd test
rdr-anchor "relayd/*"

#nat on $ext_if from ($int_if:network) to any -> ($ext_if)
# nat on $ext_if from !($ext_if) to any -> ($ext_if)
nat on $ext_if from $local_net to any -> $nat_net sticky-address

# ftp
rdr on $int_if proto tcp from any to any port 21 -> 127.0.0.1 port 8021

# transparent squid
rdr on $int_if inet proto tcp from $forced_proxy to any port 80 -> 127.0.0.1 port 3128

### rules ############################

#pass in log quick on $int_if inet proto tcp from any to 127.0.0.1 port 6161 keep state
# immediately prevent IPv6 traffic from entering or leaving all interfaces
block in log quick on $ext_if inet6 all
block out log quick on $ext_if inet6 all

#default to deny
block in log all
block out log all

# ftp proxy incoming
#pass in log quick on $ext_if inet proto tcp from any to ($ext_if) port > 49151 user proxy flags S/SA keep state
anchor "pftpx/*"

# Block bad tcp flags from malicious people and nmap scans
block in log quick on $ext_if proto tcp from any to any flags /S
block in log quick on $ext_if proto tcp from any to any flags /SFRA
block in log quick on $ext_if proto tcp from any to any flags /SFRAU
block in log quick on $ext_if proto tcp from any to any flags A/A
block in log quick on $ext_if proto tcp from any to any flags F/SFRA
block in log quick on $ext_if proto tcp from any to any flags U/SFRAU
block in log quick on $ext_if proto tcp from any to any flags SF/SF
block in log quick on $ext_if proto tcp from any to any flags SF/SFRA
block in log quick on $ext_if proto tcp from any to any flags SR/SR
block in log quick on $ext_if proto tcp from any to any flags FUP/FUP
block in log quick on $ext_if proto tcp from any to any flags FUP/SFRAUPEW
block in log quick on $ext_if proto tcp from any to any flags SFRAU/SFRAU
block in log quick on $ext_if proto tcp from any to any flags SFRAUP/SFRAUP
block in log quick on $ext_if proto tcp all flags FUP/FUP

#allow loopback
pass quick on lo0 all

# allow usv heartbeat
pass in quick on $int_if proto tcp from 10.0.0.1 port 3551 to any

# let 'previous' tagged traffic in
pass in  quick on $ext_if tagged VPN keep state
pass out quick on $ext_if tagged VPN keep state

# relayd
#pass in quick on $ext_if proto tcp from any to any port 80 flags S/SA synproxy state
#pass out quick on $int_if inet proto tcp from any to $webservers port 80 flags S/SA keep state

#block private networks from inside out
block drop in log quick on $ext_if from $priv_net to any
block drop out log quick on $ext_if from any to $priv_net

#allow interal network out
pass in log on $int_if from ($int_if:network) to any keep state

# squid transparent proxy
pass in on $int_if proto tcp from any to 127.0.0.1 port 3128 keep state

# ???
pass out on $int_if from ($int_if:network) to any keep state
pass out on $int_if from $netcar24_net to $netcar24_net keep state

# allow windoze
pass in log on $int_if from 10.3.0.0/24 to any keep state
pass out on $int_if from 10.3.0.0/24 to any keep state

# openvpn
pass out on $int_if from 10.1.0.0/16 to any keep state

#VPN out from internal network
#pass in log on $int_if proto gre keep state
#pass in log on $int_if proto tcp from any to any port 1723 keep state
#pass out log on $ext_if proto gre keep state
#pass out log on $ext_if proto tcp from any to any port 1723 keep state

# allow ssh
#pass in log  on $ext_if proto tcp from $admin_mweb to ($ext_if) port 22 keep state
# ssh
pass in log   on $ext_if proto tcp from any to $ext_master_ip port 62327 flags S/SA keep state
## queue (q_def, q_pri)
# openvpn
pass in quick on $ext_if proto udp from any to $ext_master_ip port 1194 keep state
## queue q_vpn
# isakmp
pass in quick on $ext_if proto udp from any to $ext_master_ip port 500 keep state
# esp is stateless
pass in  quick proto esp from any to $ext_master_ip
pass out quick proto esp from $ext_master_ip to any
# gre
pass in on $ext_if inet proto gre from any to $ext_master_ip
pass out on $ext_if inet proto gre from $ext_master_ip to any
# ip in ip
pass out on $ext_if inet proto ipencap from $ext_master_ip to any
pass in  on $ext_if inet proto ipencap from any to $ext_master_ip

# tag ipsec traffic as such
pass in  log on $vpn_if from any to any tag VPN keep state
pass out log on $vpn_if from any to any tag VPN keep state

# icmp
pass in inet proto icmp all icmp-type $icmp_types keep state

pass out log on $ext_if from ($int_if:network) to any keep state
pass out log on $ext_if from ($ext_if) to any keep state

#allow from fw to out
pass out on $ext_if inet proto tcp from any to any port www keep state
pass out on $ext_if inet proto udp from $ext_master_ip to any port 1194 keep state
## queue q_vpn
pass out log on $ext_if proto tcp all modulate state flags S/SA
## queue (q_def, q_pri)
pass out log on $ext_if proto { udp, icmp } all keep state


pf(ctl) command

some pfctl-commands


show all tables incl. table-members

for i in `pfctl -s Tables`; do 
   echo $i ; 
   pfctl -t $i -T show ; 
done

or one-liner:

for i in `pfctl -s Tables` ; do echo $i ; pfctl -t $i -T show ; done


to show contents of a defined table

pfctl -t badguys -T show


add/delete an entry from defined table

pfctl -t badguys -T [add|delete] 2.201.83.17


pfctl basic overview

Related: http://www.OpenBSD.org
Last update: Tue Dec 28, 2004
Note:
this document is only provided as a basic overview
for some common pfctl commands and is by no means
a replacement for the pfctl and pf manual pages.


General PFCTL Commands

  1. pfctl -d disable packet-filtering
  2. pfctl -e enable packet-filtering
  3. pfctl -q run quiet
  4. pfctl -v -v run even more verbose


Loading PF Rules

  1. pfctl -f /etc/pf.conf load /etc/pf.conf
  2. pfctl -n -f /etc/pf.conf parse /etc/pf.conf, but dont load it
  3. pfctl -R -f /etc/pf.conf load only the FILTER rules
  4. pfctl -N -f /etc/pf.conf load only the NAT rules
  5. pfctl -O -f /etc/pf.conf load only the OPTION rules


Clearing PF Rules & Counters

  1. pfctl -F all flush ALL
  2. pfctl -F rules flush only the RULES
  3. pfctl -F queue flush only queue’s
  4. pfctl -F nat flush only NAT
  5. pfctl -F info flush all stats that are not part of any rule.
  6. pfctl -z clear all counters
Achtung.jpeg note: flushing rules do not touch any existing stateful connections

Output PF Information

  1. pfctl -s rules show filter information
  2. pfctl -v -s rules show filter information for what FILTER rules hit..
  3. pfctl -vvsr show filter information as above and prepend rule numbers
  4. pfctl -v -s nat show NAT information, for which NAT rules hit..
  5. pfctl -s nat -i xl1 show NAT information for interface xl1
  6. pfctl -s queue show QUEUE information
  7. pfctl -s label show LABEL information
  8. pfctl -s state show contents of the STATE table
  9. pfctl -s info show statistics for state tables and packet normalization
  10. pfctl -s all show everything


Maintaining PF Tables

  1. pfctl -t addvhosts -T show show table addvhosts
  2. pfctl -vvsTables view global information about all tables
  3. pfctl -t addvhosts -T add 192.168.1.50 add entry to table addvhosts
  4. pfctl -t addvhosts -T add 192.168.1.0/16 add a network to table addvhosts
  5. pfctl -t addvhosts -T delete 192.168.1.0/16 delete nework from table addvhosts
  6. pfctl -t addvhosts -T flush remove all entries from table addvhosts
  7. pfctl -t addvhosts -T kill delete table addvhosts entirely
  8. pfctl -t addvhosts -T replace -f /etc/addvhosts reload table addvhosts on the fly
  9. pfctl -t addvhosts -T test 192.168.1.40 find ip address 192.168.1.40 in table addvhosts
  10. pfctl -T load -f /etc/pf.conf load a new table definition
  11. pfctl -t addvhosts -T show -v output stats for each ip address in table addvhosts
  12. pfctl -t addvhosts -T zero reset all counters for table addvhosts