Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 10 Aug 2001 14:23:56 +0200 (CEST)
From:      Krzysztof Zaraska <kzaraska@student.uci.agh.edu.pl>
To:        Jon Loeliger <jdl@jdl.com>
Cc:        security@FreeBSD.ORG
Subject:   Re: IPFW Dynamic Rules
Message-ID:  <Pine.BSF.4.21.0108101308460.63404-100000@lhotse.zaraska.dhs.org>
In-Reply-To: <E15V26p-000ILM-00@jdl.com>

next in thread | previous in thread | raw e-mail | index | archive | help
On Thu, 9 Aug 2001, Jon Loeliger wrote:

> So if the dynamic rule has the same behaviour as the origination
> rule on the same port with the same protocol, why can't packets
> simply continue to be matched against that original base rule?
> Why does the dynamic rule even need to come into existence?
It does not have _the same_ behavior. Simply speaking, if you add
keep-state to the rule it means "pass the packet which is a reply to this
one". 

Assuming x.x.x.x is your ip, z.z.z.z is outside (client) ip.
If client sends UDP query to DNS on your machine, you get the packet:
z.z.z.z:z -> x.x.x.x:53 INCOMING
Yet in yor machine's reply
x.x.x.x:53 -> z.z.z.z:z OUTGOING

Firewall code matches data from IP/TCP/UDP header to the ruleset. If ALL
fields in packet match those in the rule the specified action (allow,
deny, deny & log, etc.) is triggered. 

So if you have a rule 
"allow INCOMING packet from ANY host ANY port to z.z.z.z port 53" 
it will pass the first packet. But the reply packet is an OUTGOING
packet from x.x.x.x:53 to z.z.z.z:z so it _doesn't_ match the rule. 

And now what keep-state does:
In our example, if you have the same rule as above but with keep-state, 
after the rule is matched and packet is let through, a new rule is added
saying:
"allow OUTGOING packet from x.x.x.x port 53 to z.z.z.z port z"
and this will match exactly the reply packet. Dynamic rules are deleted
after a given period of time. 

More typical use of this is:
	add pass udp from yourip to any keep-state
so you may initiate UDP queries and the replies will be allowed back,
without keep-state they would be dropped.  

If you're running a public DNS for example, you may just allow all traffic
to (queries to your server) port 53 and from port 53 (replies from your
server).

> How many dynamic rules do you need to allow for, roughly, based on
> some simple system paramters?  Pure heuristic and guess work here?
> Markov chain arrival rate rule decay rate blah blah tune it blah blah?
> I filled the default 256 readily, and bumped it to 1024 on a whim.
One active connection = one dynamic rule. Also take into account the rule
is deleted after connection is inactive for some time. 

I generally use keep-state for UDP traffic, not for TCP. ipfw can inspect
the state of TCP connection, so there is a better way (see below). 

> So I think I may be doing something vaguely Not Quite Right with
> some "keep-state" rules too.  I think I got to this NQR state due
> to some early wrong rule tinkering.  To be concrete:
> 
> I first made the mistake of being too uni-directional and had a
> rule like this, intending to mean "anything that is established
> between the Big Bad Outside and my net, let it through."
> 
>     00800 allow tcp from any to MY_REAL_NET/MASK established
> 
> and this one intended to allow access to a web server:
> 
>     01200 allow tcp from any to 209.39.144.0/27 80 setup
First, a brief explanation of TCP:
BEFORE ANYTHING can be sent over a TCP connection, a connection MUST be
stablished. The procedure is as follows (client connects to server):
1. client sents the packet with the SYN flag sent
2. if server wishes to open this connection, it replies with packet with
both flags SYN and ACK set; if it doesn't wish to open the connection
(e.g. no httpd running), it replies with packet with set both RST and ACK
flags. 
3. if client received SYN+ACK packet (=server wants to talk) it replies
with a packet with ACK flag set. CONNECTION ESTABLISHED.
4. all packets exchanged between client and server have ACK flag set.

The idea behind example in /etc/rc.firewall is: we allow _all_ ESTABLISHED
connections and control only the SETUP of new connections. Since nothing
may be sent without prior establishing the session (steps 1-3 above) this
provides adequate security. In other words: allow all packets with ACKs,
control only SYNs. 

So the rules read (/etc/rc.firewall, CLIENT section):
        # Allow TCP through if setup succeeded
        ${fwcmd} add pass tcp from any to any established
Then
        # Allow setup of incoming email
        ${fwcmd} add pass tcp from any to ${ip} 25 setup
At this point we allow only incoming SYNs to port 25, that is, 
the only connection that may be established is this to port 25. Any other
SYNs sent by the client will be dropped and the client never receives
SYN+ACK. A SYN to port 25 will generate the reply of SYN+ACK which will be
passed by the "established" rule above. 

Later we must allow ourselves to initiate the connections, so we have:
        # Allow setup of outgoing TCP connections only
        ${fwcmd} add pass tcp from ${ip} to any setup

Assuming everything else is blocked, we end up with: connections to port
25 allowed from outside, we may connect to everybody else, any other
connection attempts to us are forbidden. Guess this is what you want. 

UDP unfortunately, does not define connections, so we must use the
keep-state technique as above. With TCP there's no need for that, since
you may allow all enstablished connections and filter only connection
requests. 

> What I need to do is change the 800 rule to be:
> 
>     00800 allow tcp from any to any established
> 
> and take the keep-state off the 1200 rule again:
> 
>     01200 allow tcp from any to MY_REAL_NET/MASK 80 setup
Exactly! (see above)

Generally I construct firewall rules like this:
1. deny everything
2. allow all connections from inside to outside world. TEST. 
3. allow the outside world to connect to selected services. TEST. 
4. TEST. Specifically check if no unwanted connections may be initiated
from outside. 


To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-security" in the body of the message




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?Pine.BSF.4.21.0108101308460.63404-100000>