FreeBSD 6 PF Firewall/NAT Configuration:
1. Kernel Compilation Configuration:
/usr/src/sys/i386/conf – MYKERNEL
options ALTQ
options ALTQ_CBQ # Class-Based Queuing (CBQ)
options ALTQ_RED # Random Early Detection (RED)
options ALTQ_RIO # RED for incoming and outgoing packets
options ALTQ_HFSC # Hierarchical Packet Scheduler (HFSC)
options ALTQ_PRIQ # Priority Queuing (PRIQ)
options ALTQ_NOPCC # Required when compiling the SMP kernel, disables clock reads
The first step is configuring the kernel.
device pf
device pflog
device pfsync
Recompile
2. Modify /etc/sysctl.conf by adding:
net.inet.ip.forwarding=1
3. In /etc/inetd.conf, enable the ftp-proxy functionality (just uncomment the last line by removing the “#”):
ftp-proxy stream tcp nowait root /usr/libexec/ftp-proxy ftp-proxy
4. Then, modify /etc/rc.conf:
inetd_enable=”YES”
pf_enable=”YES”
pf_rules=”/etc/pf.conf”
pf_flags=””
pflog_enable=”YES”
pflog_logfile=”/var/log/pflog”
pflog_flags=””
# Enable the following to utilize NAT
gateway_enable=”YES”
5. Finally, write the PF firewall rules:
ext_if = “vr0” # Interface connected to ADSL
int_if = “vr1” # Interface connected to the internal network
# Define the internal network ranges that should never appear on the external interface $ext_if
priv_nets = “{ 127.0.0.0/8, 192.168.0.0/16, 172.16.0.0/12, 10.0.0.0/8 }”
# ——————– Define the services to be opened
# These are the services we want to expose to the Internet. For example, we have Apache running, so we open HTTP.
# As for port 113, it’s IDENT, which is needed for services like IRC or some Bulletin Board Systems in Taiwan.
tcp_services = “{ http, https, 113 }”
# MLDonkey required ports:
# 6881-6889 are used by BitTorrent; 33333 is the eD2k port I configured, while UDP is 33333+4.
# Port 44444 is the Kad port I configured, used both for TCP and UDP.
# For other MLDonkey ports, refer to:
mldonkey_tcp_ports = “{ 6881, 6882, 6883, 6884, 6885, 6886, 6887, 6888, 6889, 33333, 44444 }”
mldonkey_udp_ports = “{ 33337, 44444 }”
# The following are services intended for internal use only:
# 4001 and 4080 are MLDonkey’s control interfaces.
priv_tcp_services = “{ ssh, 4001, 4080, http }”
# Allowed ICMP types (used primarily for tools like ping and traceroute)
icmp_types = “echoreq”
# ——————– Settings
# Use this setting for proper usage. Those with tight security policies can replace `return` with `drop`.
set block-policy return
# Only log traffic on $ext_if
set loginterface $ext_if
# ——————– Normalization actions
# Basic actions: organize all packets.
scrub in all
# ——————– Address Translation (NAT) Section
# Configure NAT
nat on $ext_if from $int_if:network to any -> ($ext_if)
# Redirection needed for ftp-proxy
rdr on $int_if proto tcp from any to any port ftp -> 127.0.0.1 port 8021
# ——————– Packet Filtering Rules
# Begin filtering packets, block all by default.
block all
# Allow everything for loopback interface
pass quick on lo0 all
# Block IPs that should never appear on external interfaces to avoid IP spoofing:
block drop in quick on $ext_if from $priv_nets to any
block drop out quick on $ext_if from any to $priv_nets
# Enable services available to external users:
pass in on $ext_if inet proto tcp from any to ($ext_if) port $tcp_services flags S/SA keep state
# Enable connections needed by MLDonkey:
pass in on $ext_if inet proto tcp from any to ($ext_if) port $mldonkey_tcp_ports flags S/SA keep state
pass in on $ext_if inet proto udp from any to ($ext_if) port $mldonkey_udp_ports keep state
# Enable services for internal network users:
pass in on $int_if inet proto tcp from any to ($int_if) port $priv_tcp_services flags S/SA keep state
# Allow ICMP packets:
pass in inet proto icmp all icmp-type $icmp_types keep state
# Looser rules assuming that internal network users are trustworthy. These can be tightened later.
pass in on $int_if from $int_if:network to any keep state
pass out on $int_if from any to $int_if:network keep state
# Allow outbound traffic on the external interface:
pass out on $ext_if proto tcp all modulate state flags S/SA
pass out on $ext_if proto { udp, icmp } all keep state
5. Reboot
6. Use the following PF control commands:
pfctl -e # Enable PF
pfctl -d # Disable PF
pfctl -f /etc/pf.conf
inetd_enable=”YES”
pf_enable=”YES”
pf_rules=”/etc/pf.conf”
pf_flags=””
pflog_enable=”YES”
pflog_logfile=”/var/log/pflog”
pflog_flags=””
# Enable the following to utilize NAT:
gateway_enable=”YES”