Firewalling with ipf and nat

Table of Contents

Introduction

Prior to release 3.0, the favoured firewall tool for OpenBSD was combining ipf with nat.

For a wonderful tutorial on OpenBSD PF check out http://home.nuug.no/~peter/pf/en/ The tutorial is very thorough with many example configurations.

If you're really thinking of using these notes as the basis for firewalling, then don't. This should have been a tutorial for getting ipf, nat working but the OpenBSD FAQ came out with a real nice instructional, so grab the FAQ. I've just kept these notes as a reference hack. Besides, I don't always have an Internet connection to test configuration changes, ideas.

Why have it on the web if there wrong ? Well, some of them I've actually used and they work, and these are notes. These notes continue as an attempt to understand how the ipf rules work, and the basic configuration one would have to secure a site. The fiddles (rulesets) in this list will hopefully document what may have been a safe generic configuration.

Configuration in /etc/sysctl.conf and /etc/rc.conf
IP Filter rules in /etc/ipf.rules
Network Address Translation (NAT) rules in /etc/ipnat.rules
Examples are in /usr/share/ipf

Step 1 Turn IP Forwarding on

Uncomment the line disabling ip filter

Edit the file: /etc/sysctl.conf

#net.inet.ip.forwarding=1  # 1= Permit forwarding (routing) or packets
net.inet.ip.forwarding=1   # 1 = Permit forwarding (routing) or packets

To effect the above (do the above) without having to restart the server. Use the following command documented in the FAQ.

# sysctl -w net.inet.ip.forwarding=1

net.inet.ip.forwarding: 0 -> 1

Step 2 Turn Filtering On

To enable ipf and ipnat at boot, change the default filter settings (NO) to YES

Edit the File /etc/rc.conf.local and add the following lines to Section 2

ipfilter=YES
ipnat=YES

This will override the standard settings in /etc/rc.conf shown here:

ipfilter=NO
ipnat=NO

Start IP Filtering Manually

[ref: ipf(8)]
[File: /etc/ipf.rules]

The standard file location for the ipf.rules will reside in /etc as ipf.rules

Without restarting your computer, and after you've created your 1st set of rules, you can force ipf to start and use the new rules with a command similar to the below:

# ipf -Fa -vf /etc/ipf.rules -E

The -E, enables ipf so if you modify your rules then you can reload the new rules using the same above commands without the -E.

Note that reloading directly from file to the active ruleset is not recommended. Check the FAQ for a better method.

Start NAT manually

[File: /etc/ipnat.rules]

The standard file location for the ipnat.rules will reside in /etc as ipnat.rules

Without restarting your computer, and after you've created your 1st set of rules, you can force ipnat to start and use the new rules with a command similar to the below:

# ipnat -CF -f /etc/ipnat.rules

Sample filter rules

[files location: /usr/share/ipf]

The basic OpenBSD installation comes with a number of sample firewall rules. Samples files for ipfilter begin with firewall, while samples for NAT begin with nat.

IP filter Rules

firewall.1 - tight firewall through ppp connection
firewall.2 - heavy security firewall through a ppp connection
firewall.3 - restrictive firewall through a ppp connection

Other files (example.*) provide examples of specific block/allow scenarios with the filter system

NAT rules

nat.1 - direct-connect (ethernet card) connection to ISP
nat.2 - hints
nat.3 - ppp connection to ISP

Reviewing a sample ipf.rules

[ref: ipf(8)]

Ipf reads its ruleset sequently until it gets to the end of the ruleset (unless it has otherwise been told to stop.) Whichever is the last 'valid' rule that applies to a packet will be the applied rule. This is different from ipfwadm and ipfw who quits on the first applicable rule to incoming packets.

# ipf filtering example Generic System 1:
#      * stateless version (does not keep state information)
#      * class: heavy duty firewalling
# Definitions
# XTL_LINK    - interface with the external to the world eg. xl0
# XTL_IPADDR  - IP to external interface  eg. 207.124.66.1
# INT_LINK1   - interface_1 on the internal network      eg. xl1
# INT_LINK2   - interface_2 on the internal network      eg. xl2
# INT_NETWORK - Internal IP network       eg. 192.168.101.0
# INT_BMASK0  - Broadcast Mask on 0       eg. 192.168.101.0/16
# INT_BMASK255 - Broadcast Mask on 255    eg. 192.168.101.255/32

The above are the definitions used in this example.

pass in  quick on lo0
pass out quick on lo0

Allow any inbound/outbound on the loopback interface

pass in  quick on INT_LINK1
pass out quick on INT_LINK1

Allow any inbound/outbound on the LAN interface (we can tighten this up further, but for now we're looking after that evil external connection.)

Invalid External Links (mostly hostile)

block in     quick on XTL_LINK from 192.168.0.0/16 to any
block in     quick on XTL_LINK from 172.16.0.0/12 to any
block in     quick on XTL_LINK from 10.0.0.0/8 to any
block in     quick on XTL_LINK from 127.0.0.0/8 to any
block in     quick on XTL_LINK from localhost to any
block in     quick on XTL_LINK from 255.255.255.255/32 to any
block in log quick on XTL_LINK from INT_NETWORK to any

This ruleset prevents 'spoofing' of private internet addresses from the outside world. We should not be receiving these through the external link because private IP addresses are not routeable.  

block in log quick on XTL_LINK from INT_BMASK0 to any

There shouldn't be anyone from our Network trying to get through on the outside network card either. This takes into consideration that we are using legitimate/routeable addresses on our internal network.

block in log quick on XTL_LINK from any to INT_BMASK0
block in log quick on XTL_LINK from any to INT_BMASK255

The outside should not be broadcasting on our network either

block out log quick on XTL_LINK from any to INT_NETWORK
block out     quick on XTL_LINK from any to 192.168.0.0/16
block out     quick on XTL_LINK from any to 172.16.0.0/12
block out     quick on XTL_LINK from any to 10.0.0.0/8
block out     quick on XTL_LINK from any to 127.0.0.0/8
block out     quick on XTL_LINK from any to localhost
#[ERROR]block out     quick on XTL_LINK from any to 0.0.0.0/32
block out     quick on XTL_LINK from any to 255.255.255.255/32

Likewise, there should be no reason to find a private address on the outside, so don't waste bandwidth sending stuff that is not going to get routed.

Our two settings should help us diagnose problems with our  rulesets or find some attack attempts from outside?

block out log quick on XTL_LINK from any to INT_BMASK0

Since all our ip address should be inside our network, there is no need for sending information for our LAN out on the wire (external link.)

Bad Packets

block in     quick on XTL_LINK proto icmp from any to any icmp-type redir
block in     quick on XTL_LINK proto tcp/udp all with short
block in     quick on XTL_LINK from any to any with ipopts

Block any inherently bad packets coming in from the outside world. These include ICMP redirect packets, IP fragments so short the filtering rules won't be able to examine the whole UDP/TCP header, and anything with IP options.

OS Fingerprinting Attempts

block in quick on fxp0 proto tcp from any to any flags FUP

From the FAQ: If you wanted to deny all packets with the FIN, URG, and
PSH flags set (like for instance an nmap OS fingerprinting attempt) you could use a rule like the above.

Limiting Access

#pass in      quick on XTL_LINK proto icmp from any to INT_NETWORK icmp-type 0
block in log  quick on XTL_LINK proto icmp from any to XTL_IPADDR
#pass in      quick on XTL_LINK proto icmp from any to INT_NETWORK icmp-type 11

LIMIT ACCESS so there is no smurfing ? (ICMP attacks) let in 0 (ping) and 11 (trace-route) but kill it for people who want to bash on the server. Because my sample network uses non-routeable we really shouldn't be allowing in any 'pings' or 'trace-route' from the outside.

block in           on XTL_LINK proto udp from any to any
block in log quick on XTL_LINK proto udp from any to any port = sunrpc
block in log quick on XTL_LINK proto tcp/udp from any to any port = nfsd
block in log quick on XTL_LINK proto tcp/udp from any to any port = msp
block in log quick on XTL_LINK proto tcp/udp from any to any port = chargen
block in log quick on XTL_LINK proto tcp/udp from any to any port = time
 
pass in            on XTL_LINK proto udp from any to any port = domain
pass in            on XTL_LINK proto udp from any to any port = talk
pass in            on XTL_LINK proto udp from any to any port = ntalk

[UDP PACKETS] Block all incoming UDP traffic except talk and DNS traffic. NFS  and portmap are special-cased and logged.

block in log quick on XTL_LINK proto tcp from any to INT_NETWORK port = 513
block in log quick on XTL_LINK proto tcp from any to INT_NETWORK port = 514
block in log quick on XTL_LINK proto tcp from any to INT_NETWORK port = 23
block in log quick on XTL_LINK proto tcp/udp from any to XTL_IPADDR port = 109
block in log quick on XTL_LINK proto tcp/udp from any to XTL_IPADDR port = 110
block in log quick on XTL_LINK proto tcp/udp from any to XTL_IPADDR port = 143
block in log quick on XTL_LINK proto tcp/udp from any to XTL_IPADDR port = 220
block in log quick on XTL_LINK proto tcp/udp from any to XTL_IPADDR port = 901

[PORTS WITH BAD SECURITY] Block ports with clear-text password transfers from coming in on  the external link

              513  rlogin      109 pop2             901 swat
              514  rsh         110 pop3         
               23  telnet      220/143 imap
block return-rst in log on XTL_LINK proto tcp from any to any flags S/SA
block return-rst in on XTL_LINK proto tcp from any to any port = auth flags S/SA
 
block in log quick on XTL_LINK proto tcp/udp from any to INT_NETWORK port = 111
block in log quick on XTL_LINK proto udp from any to INT_NETWORK port = 514
block in log quick on XTL_LINK proto tcp from any to INT_NETWORK port = 515
block in log quick on XTL_LINK proto tcp/udp from any to INT_NETWORK port = 2049
block in log quick on XTL_LINK proto tcp from any to INT_NETWORK port = 6000

[KNOWN SERVICES]  Block all incoming TCP traffic connections to known services,  returning a connection reset so things like ident don't take forever timing out.  Don't log ident (auth port) as it's so common.

pass in on XTL_LINK proto tcp from any to any port 1024 >< 5000
#pass in on XTL_LINK proto tcp from any port = ftp-data to any port 1024 >< 5000

Allow incoming TCP connections to ports between 1024 and 5000, as these don't have daemons listening but are used by outgoing services like ftp and talk.  For slightly more obscurity (though not much more security), the second commented out rule can chosen instead.

pass out    on XTL_LINK from INT_NETWORK to any keep state
pass in     on XTL_LINK from any to INT_NETWORK
 
pass out    on INT_LINK1 from INT_NETWORK to any
pass in     on INT_LINK1 from any to INT_NETWORK
 
#pass out    on INT_LINK2 from INT_NETWORK to any
#pass in     on INT_LINK2 from any to INT_NETWORK

[GENERAL SETTINGS] Pass any packets from Internal Network to the world. Let in any packets for Internal Network from the world

Reviewing a sample ipnat.rules

[ref: ipnat(8)]

# ipnat Name Address Translation example Generic System 1:
#
# Definitions
# XTL_LINK  - interface with the external connection to the world eg. xl0
# INTL_LINK - interface with the internal connection (LAN) e.g. xl1
# INT_NETWORK - Internal IP network       eg. 192.168.101.0/16
# EXT_NETWORK - External IP network       eg. 207.124.66.1
#
# INT_RDR_MAIL - ip addr of Mail Server   eg. 192.168.101.25
# INT_RDR_FTP  - ip addr of FTP  Server   eg. 192.168.101.21
# INT_RDR_DNS  - ip addr of DNS  Server

Outgoing Traffic

map XTL_LINK INT_NETWORK -> XTL_LINK/32 portmap tcp/udp 10000:60000
map XTL_LINK INT_NETWORK -> EXT_NETWORK/32

map tells the NAT how a range of addresses should be translated.  The entries use the following format:

map ifname internal/mask -> external/mask options

The ifname field is the interface to which packets are sent. Since we are trying to connect to the rest of the world, we use our external interface as 'ifname'.

map xl0 192.168.101.0/16 -> 207.124.66.1/32 portmap tcp/udp 10000:60000
map xl0 192.168.101.0/16 -> 207.124.66.1/32

Our above rule remaps all connections originating from INT_NETWORK (192.168.101.0 through to 192.168.101.254) to the externally-connected network

The external address is the offically assigned IP number of the gateway or network.

mask is the netmask of the address. This mask is 32 bits long, and is divided into four 8-bit numbers.

The option portmap used in the above example solves the problem of trying to shove a large number of ip addresses (your LAN) into a one small 'external ip address' address space (the external interface.)

Redirecting Traffic

rdr tells the NAT how to redirect incoming packets.  It is useful if one wishes to redirect a connection through a proxy, or to another box on the  private network.  The format of this directive is:

rdr ifname external/mask port service -> internal port service protocol

This setup is best described by an example of an actual entry:

# rdr XTL_LINK EXT_NETWORK/32 port ftp -> INT_RDR_FTP  port ftp

 

rdr xl0 204.124.66.1/32 port ftp  -> 192.168.101.21 port ftp

This redirects all ftp packets received on XTL_LINK to EXT_NETWORK, port ftp.  A netmask is not needed on the internal address; it is always 32. The external and internal fields, similar to the map directive, may be actual addresses, hostnames, or interfaces. Likewise, the service field may be the name of a service, or a port number.  The protocol of the service may be selected by appending tcp, udp, tcp/udp, or tcpudp (the last two have the same effect) to the end of the line.  TCP is the default.

I am using EXT_NETWORK above, as we are only accepting the ports access from real ip addresses to real ip addresses (no internal service should be directly accessible due to the firewall ipf rulesets)

rdr XTL_LINK EXT_NETWORK/32 port www  -> INT_RDR_WWW  port www
rdr XTL_LINK EXT_NETWORK/32 port smtp -> INT_RDR_MAIL port smtp
rdr XTL_LINK EXT_NETWORK/32 port ssh  -> INT_RDR_SSH  port ssh

Redirect www, smtp, ssh to the internal boxes that will be handling these services (keep the load off the gateway box.)

Sample by James Deucker

The following sample was published by Mr. James Deucker on the OpenBSD misc mailing list.

From: "Deucker, James H." 
To: "'misc@openbsd.org'" 
Subject: ipf.rules 
Date: Mon, 14 Aug 2000 22:43:16


-0500 I hear people asking for example rules sets for ipf, and they're really
not that hard to put together from the manuals, faq and ipfilter web
page. However, as I see so many people ask so often, I thought I'd post
my ipf.rules set for perusal in the

archives. I don't claim this set to be complete, I don't even claim that they
secure. They seem to do what I want at the moment, and I'd certainly appreciate
any comments on them. I'm here to have fun and learn

heaps. Notes: my internal network is 172.16.2.0/24, on interface ep1. My
external interface is on ep2, the ip changes, and it's hooked up to my cable
modem (telstra bigpond [australia] cable

network). I don't care what goes on in my internal network, and at the moment I
don't use NAT, that's a project for next week when things have calmed down
at

work. I use Squid 2.3 from Ports for http, I use SOCKS5 for ICQ and napster. I
run ssh on its normal port and a high one (2022). I use sendmail to send
mail out from my network, and fetchmail to pull all our mailboxes down. I
use homeip.net dyndns to give me a name to point to ssh in. I allow
ident packets to the

firewall. So, for your enjoyment, here they

are.#----ipf.rules----8*<----snip-below-this-line----

#
# LOOPBACK
#

# allow any inbound/outbound on the loopback interface
pass in quick on lo0
pass out quick on lo0

# --------------------------------------------------------

#
# LAN
#

# allow any inbound/outbound on the LAN interface
pass in quick on ep1
pass out quick on ep1

# --------------------------------------------------------

#
# HOSTILE
#

# prevent spoofing in and out
# from unroutable addresses
block in log quick on ep2 from 127.0.0.0/8 to any
block in log quick on ep2 from 192.168.0.0/16 to any
block in log quick on ep2 from 169.254.0.0/16 to any
block in log quick on ep2 from 172.16.0.0/12 to any
block in log quick on ep2 from 10.0.0.0/8 to any

block out log quick on ep2 from 127.0.0.0/8 to any
block out log quick on ep2 from 192.168.0.0/16 to any
block out log quick on ep2 from 169.254.0.0/16 to any
block out log quick on ep2 from 172.16.0.0/12 to any
block out log quick on ep2 from 10.0.0.0/8 to any

# explicit allow
pass in quick on ep2 from any to any port = ssh
pass in quick on ep2 from any to any port = 2022 # ssh high port
pass in quick on ep2 proto tcp from any to any port = 

auth # block too-small
fragments block in log quick proto tcp all with

short # block source routed
packets block in log quick on ep2 all with opt
lsrr block in log quick on ep2 all with opt

ssrr # block OS
fingerprinting block in log quick on ep2 proto tcp from any to any flags

FUP # default
deny block return-icmp-as-dest(port-unr) in log quick on ep2 proto udp from
any to
any block return-rst in log quick on ep2 proto tcp from any to
any block in log quick on ep2 from any to

any # allow traffic
out pass out on ep2 proto tcp from any to any keep
state pass out on ep2 proto udp from any to any keep
state pass out on ep2 proto icmp from any to any keep

state#----ipf.rules---->*8----snip-above-this-line----

If people would so desire, I can also post my squid.conf, socks5.conf,
fetchmail.conf and m4 for sendmail. (though I'd probably just post a diff
against squid.conf from the default ports one)

And just to reiterate, please if you have any comments or suggestions as to
how I can do this any better, tell me :)

enjoy,

James Deucker
Patrician of Networks


Relative References

OpenBSD FAQ
IP Filter Based Firewalls HOWTO
Internet Firewalls: FAQ

[Posted 2002-07-23]

I was able to create a firewall/router combination that handles both
Ethernet and wireless traffic by using OpenBSD 3.1 and pf. A full
description of my experience is at the URL that follows. Please feel free
to link to it, or contact me with comments or corrections:

http://www.well.com/~jbyrd/firewall.html

I have no opinion about which firewall solution or filtering package is
"best". I merely report what worked in my case, and I'm confident that
other methods could have been used to achieve a similar result.

I don't subscribe to this list, so please feel free to contact me
out-of-band with comments or additions.

Sincerely,

John Byrd

Author and Copyright

Copyright (c) 2000/1/2 Samiuela LV Taufa. All Rights Reserved.

I reserve the right to be totally incorrect even at the best advice of betters. In other words, I'm probably wrong in enough places for you to call me an idiot, but don't 'cause you'll hurt my sensibilities, just tell me where I went wrong and I'll try again.

You are permitted and encouraged to use this guide for fun or for profit as you see fit. If you republish this work in what-ever form, it would be nice (though not enforceable) to be credited.

 Firewalling - Keeping the BAD GUYS out

Copyright  © 2000/1/2 NoMoa.COM All rights reserved.