The FreeBSD Gateway - PF

This is an example of FreeBSD Internet Gateway with firewall, port forwarding and transparent proxy.

Install FreeBSD without x-server, games and packages.
Configure network interfaces and turn on ssh.
Enable PF in rc.conf:

pf_enable="YES"
pf_program="/sbin/pfctl"
pf_flags=""
pf_rules="/etc/pf.conf"
pflog_enable="YES"
pflog_logfile="/var/log/pf.log"
plog_program="/sbin/pflogd"
pflog_flags=""

Reboot system:
# shutdown -r now

Check PF:  
# pfctl -sa

Configure Caching DNS server.

# ee /etc/namedb/named.conf
...
# Forward external DNS queryes to your provider DNS servers
forwarders {
135.11.0.77;
135.11.127.77;
            };
...
query-source address * port 53;
...

Add named into rc.conf:

named_enable="YES"
named_flags="-u bind"

# ee /etc/resolv.conf
domain domain.ru
search domain.ru
nameserver 127.0.0.1

# /etc/rc.d/named restart

Configure proxy server Squid.

# cd /usr/ports/www/squid
# make install clean
# mcedit /usr/local/etc/squid/squid.conf

        acl all src all
        acl manager proto cache_object
        acl localhost src 127.0.0.1/32
        acl to_localhost dst 127.0.0.0/8
        acl localnet src 192.168.0.0/24 # RFC1918 possible internal network
        acl Safe_ports port 80 # http
        acl CONNECT method CONNECT
        acl flv urlpath_regex -i \.flv$
        acl mov urlpath_regex -i \.mov$
        acl mp3 urlpath_regex -i \.mp3$
        acl wav urlpath_regex -i \.wav$
        acl ogg urlpath_regex -i \.ogg$
        acl asf urlpath_regex -i \.asf$
        acl avi urlpath_regex -i \.avi$
        acl mpeg urlpath_regex -i \.mpeg$
        acl inet_full src "/usr/local/etc/squid/inet_full"
        acl deny_domains dstdomain "/usr/local/etc/squid/deny_domains"
        acl work_time time MTWHF 10:00-18:00

        http_access allow manager localhost
        http_access deny manager
        http_access deny !Safe_ports
        http_access allow inet_full
        http_access deny work_time deny_domains
        http_access deny avi
        http_access deny wav
        http_access deny mp3
        http_access deny mpeg
        http_access deny flv
        http_access deny mov
        http_access deny ogg
        http_access deny asf
        http_access allow localnet
        http_access deny all

        icp_access allow localnet
        icp_access deny all

        http_port 3128
        http_port 3129 transparent

        hierarchy_stoplist cgi-bin ?

        access_log /squid/logs/access.log squid

        refresh_pattern ^ftp: 1440 20% 10080
        refresh_pattern ^gopher: 1440 0% 1440
        refresh_pattern -i (/cgi-bin/|\?) 0 0% 0
        refresh_pattern . 0 20% 4320

        acl shoutcast rep_header X-HTTP09-First-Line ^ICY.[0-9]
        upgrade_http0.9 deny shoutcast

        acl apache rep_header Server ^Apache
        broken_vary_encoding allow apache

        cache_mem 256 MB
        cache_dir ufs /squid/cache 51200 64 512

I restricted multimedia content and sites from file deny_domains at work time.

# chown -R squid:squid /squid

# squid -z

# ee /etc/rc.conf
...
squid_enable="YES"

# /usr/local/etc/rc.d/squid start

# ps -waux | grep squid
squid 854 0,0 0,2 7060 2424 ?? Is 18:50 0:00,00 /usr/local/sbin/squid -D
squid 943 0,0 30,5 320404 314888 ?? S 18:50 2:24,12 (squid) -D (squid)
squid 944 0,0 0,1 1376 604 ?? Ss 18:50 0:00,94 (unlinkd) (unlinkd)
squid 945 0,0 0,1 3308 928 ?? Ss 18:50 0:06,90 (pinger) (pinger)

I have a range of external ip adresses, so I need to configure aliases:

# ee /etc/rc.conf

defaultrouter="135.61.11.222"
gateway_enable="YES"
hostname="bsd"
ifconfig_em0="inet 192.168.0.1 netmask 255.255.254.0"
ifconfig_em1="inet 135.61.11.223 netmask 255.255.255.240"
ifconfig_em1_alias0="inet 135.61.11.224 netmask 255.255.255.240"
ifconfig_em1_alias1="inet 135.61.11.225 netmask 255.255.255.240"
ifconfig_em1_alias2="inet 135.61.11.226 netmask 255.255.255.240"
.....

Write PF configuration file:

# ee /etc/pf.conf

        # pf.conf
        # Written By Alexander Lipovetskiy at 20.03.2009
        # http://ithouse.spb.ru/
        #################################################################
      
        #################################################################
        # Options
        #################################################################
      
        # Interfaces
        ext_if = "em1"
        int_if = "em0"
      
        # IP
        extnet = "135.61.11.222/28"
        lannet = "192.168.0.0/24"
        ext_ip = "135.61.24.223/32"
        ext_ip_bserv = "135.61.11.225/32"
        ext_ip_963 = "135.61.11.226/32"
        ext_ip_pbx = "135.61.11.227/32"
        bsd = "192.168.0.1/32"
        mail = "192.168.0.100/32"
        dc = "192.168.0.2/32"
        pbx = "192.168.0.3/32"
        serv1 = "192.168.0.4/32"
        serv2 = "192.168.0.5/32"
        terminal = "192.168.0.6/32"
        root = "192.168.0.10/32"
        serv3 = "192.168.0.7/32"
        friends = "{ XXX, XXX }"
        private_nets= "{ 127.0.0.0/8, 192.168.0.0/16, 172.16.0.0/12, 10.0.0.0/8, 169.254.0.0/16, 192.0.2.0/24, 0.0.0.0/8, 240.0.0.0/4 }"
      
        # Ports
        client_ports = "{ 21, 22, 25, 110, 123, 80, 443, 3128, 3129, 3389,8080, >=49151 }"
        admin_ports = "{ 5190, 33330:33340 }"
        pbx_udp = "{ 2727, 4520, 4569, 5036, 5060, 10000:20000 }"
        pbx_tcp = "{ 5060 }"

        #------------------------------  
        # Normalization
        #------------------------------  
      
        set block-policy drop
        set state-policy floating
        set loginterface $ext_if
        set limit { frags 100000, states 100000 }
        set optimization normal
        set skip on lo0
        scrub in all
      
        #------------------------------  
        # NAT & RDR
        #------------------------------  

        # BiNAT for Asterisk
        binat on $ext_if inet from $pbx to any -> $ext_ip_pbx

        # NAT for local net
        nat on $ext_if inet from $lannet to any -> $ext_ip
      
        # Transparent proxy forwarding
        rdr on $int_if proto tcp from $lannet to any port www -> 127.0.0.1 port 3129
      
        # Asterisk port forwarding
        rdr on $ext_if from any to $ext_ip_pbx -> $pbx

        # Web serve port forwarding
        rdr on $ext_if proto tcp from any to $ext_ip_bserv port www -> $bserv

        # Mail server port forwarding - smtp
        rdr on $ext_if proto tcp from any to $ext_ip port smtp -> $mail

        # Mail server port forwarding - pop3
        rdr on $ext_if proto tcp from $friends to $ext_ip port pop3 -> $mail

        # Mail server port forwarding - webamil
        rdr on $ext_if proto tcp from any to $ext_ip port https -> $mail

        # Windows RDP forwarding
        rdr on $ext_if proto tcp from any to $ext_ip port rdp -> $terminal

        # SSH
        rdr on $ext_if proto tcp from any to $ext_ip port 33330 -> $mail port 22
        rdr on $ext_if proto tcp from any to $ext_ip port 33331 -> $pbx port 22
        rdr on $ext_if proto tcp from any to $ext_ip port 33332 -> $dc port 22
        rdr on $ext_if proto tcp from any to $ext_ip port 33333 -> $serv1 port 22
        rdr on $ext_if proto tcp from any to $ext_ip port 33334 -> $serv2 port 22
        rdr on $ext_if proto tcp from any to $ext_ip port 33335 -> $pdc port 22

        #------------------------------  
        # Filtration rules
        #------------------------------  

        # Spoofing protection
        antispoof quick for { lo0, $int_if, $ext_if }

        # Block all
        block log all

        # Block privete ip
        block drop in quick on $ext_if from $private_nets to any
      
        # Allow icmp types
        pass inet proto icmp icmp-type echoreq

        # Allow DNS from local net
        pass in on $int_if proto udp from $lannet to $bsd port domain

        # Allow NTP from local net
        pass in on $int_if proto udp from $lannet to $bsd port ntp

        # It's for temporary test
        #pass in on $int_if from $lannet to any

        # Allow Asterisk output
        pass in on $int_if from $pbx to any

        # Allow Mail server output
        pass in on $int_if proto tcp from $mail to any port smtp

        # Allow Admin output
        pass in on $int_if proto tcp from $root to any port $admin_ports

        # Allow user output
        pass in on $int_if proto tcp from $lannet to any port $client_ports

        # Full output access for our gateway
        pass out on $ext_if proto tcp from any to any
        pass out on $ext_if proto udp from any to any keep state
        pass out on $int_if proto tcp from any to any
        pass out on $int_if proto udp from any to any keep state

        #------------------------------  
        # Icoming #

        # Allow incoming ssh
        pass in log on $ext_if proto tcp from any to $ext_ip port 33339 flags S/SA synproxy state
        pass in log on $ext_if proto tcp from any to $mail port 22 flags S/SA synproxy state
        pass in log on $ext_if proto tcp from any to $pbx port 22 flags S/SA synproxy state
        pass in log on $ext_if proto tcp from any to $dc port 22 flags S/SA synproxy state
        pass in log on $ext_if proto tcp from any to $serv1 port 22 flags S/SA synproxy state
        pass in log on $ext_if proto tcp from any to $serv2 port 22 flags S/SA synproxy state

        # # Allow incoming smtp
        pass in on $ext_if proto tcp from any to $mail port smtp flags S/SA synproxy state

        # Allow incoming https
        pass in on $ext_if proto tcp from any to $mail port https flags S/SA synproxy state

        # Allow incoming http
        pass in on $ext_if proto tcp from any to $ext_ip port www flags S/SA synproxy state

        # Allow incoming ftp
        pass in on $ext_if proto tcp from any to $ext_ip port ftp flags S/SA synproxy state

        # Allow incoming pop3
        pass in on $ext_if proto tcp from $friends to $mail port pop3 flags S/SA synproxy state

        # Allow incoming rdp
        pass in log on $ext_if proto tcp from $friends to $terminal port rdp flags S/SA synproxy state

        # Allow incoming Asterisk services
        pass in on $ext_if proto tcp from any to $pbx port $pbx_tcp flags S/SA synproxy state
        pass in on $ext_if proto udp from any to $pbx port $pbx_udp keep state

       
Check rules before load it:
# pfctl -nf /etc/pf.conf

Load rules if all is ok:
# pfctl -f /etc/pf.conf

# pfctl -sn
# pfctl -sr
# pfctl -si
# pfctl -sa