Trouble with IPFW or TCP?
Ian Smith
smithi at nimnet.asn.au
Fri Apr 4 16:03:32 UTC 2008
On Thu, 3 Apr 2008, Julian Elischer wrote:
> Ian Smith wrote:
> > On Thu, 3 Apr 2008, Julian Elischer wrote:
> > > Ivan Voras wrote:
> > > > Erik Trulsson wrote:
> > > >> On Fri, Apr 04, 2008 at 01:34:07AM +0200, Ivan Voras wrote:
> > > >>> In which case would an ipfw ruleset like this:
> > > >>>
> > > >>> 00100 114872026 40487887607 allow ip from any to any via lo0
> > > >>> 00200 0 0 deny ip from any to 127.0.0.0/8
> > > >>> 00300 0 0 deny ip from 127.0.0.0/8 to any
> > > >>> 00600 1585 112576 deny ip from table(0) to me
> > > >>> 01000 90279 7325972 allow icmp from any to any
> > > >>> 05000 475961039 334422494257 allow tcp from me to any setup keep-state
> > > >>> 05100 634155 65779377 allow udp from me to any keep-state
> > > >>> 06022 409604 69177326 allow tcp from any to me dst-port 22
> > > >>> setup keep-state
> > > >>> 06080 52159025 43182548092 allow tcp from any to me dst-port 80
> > > >>> setup keep-state
> > > >>> 06443 6392366 2043532158 allow tcp from any to me dst-port 443
> > > >>> setup keep-state
> > > >>> 07020 517065 292377553 allow tcp from any to me dst-port 8080
> > > >>> setup keep-state
> > > >>> 65400 12273387 629703212 deny log ip from any to any
> > > >>> 65535 0 0 deny ip from any to any
> > > >>
> > > >> If you are using 'keep-state' should there not also be some rule
> > > >> containing
> > > >> 'check-state' ?
> > > >
> > > > Not according to the ipfw(8) manual:
> > > >
> > > > """
> > > > These dynamic rules, which have a limited lifetime, are checked at the
> > > > first occurrence of a check-state, keep-state or limit rule, and
> > > > are typ-
> > > > ically used to open the firewall on-demand to legitimate traffic only.
> > > > See the STATEFUL FIREWALL and EXAMPLES Sections below for more
> > > > informa-
> > > > tion on the stateful behaviour of ipfw.
> > > > """
> > > >
> > > > I read this to mean the dynamic rules are checked at rule #5000 from the
> > > > above list. Is there an advantage to having an explicit check-state rule
> > > > in simple rulesets like this one?
> > >
> > > the docs are wrong then I think.
> >
> > If so, they've been wrong since 4.something .. certainly before 4.8.
> > It's hard to imagine nobody else has ever relied on that doc behaviour,
> > so perhaps the docs, if wrong, have become so at some more recent time?
>
> Not that I have known... keep-state does not (and never has) include
> an implicit check-state.
Sorry (and surprised!) to have to differ, but you MADE me read the code!
Bearing in mind I'm reading 5.5 sources - stop me if it's changed - but
starting with /usr/sbin/ipfw/ipfw2.c we see that adding check-state just
generates an O_CHECK_STATE, while adding keep-state or limit rules first
generate an initial O_PROBE_STATE opcode (ignored when listing rules):
/*
* Now copy stuff into the rule.
* If we have a keep-state option, the first instruction
* must be a PROBE_STATE (which is generated here).
* If we have a LOG option, it was stored as the first command,
* and now must be moved to the top of the action part.
*/
dst = (ipfw_insn *)rule->cmd;
[..]
/*
* generate O_PROBE_STATE if necessary
*/
if (have_state && have_state->opcode != O_CHECK_STATE) {
fill_cmd(dst, O_PROBE_STATE, 0, 0);
dst = next_cmd(dst);
then go on to generate the O_KEEP_STATE or O_LIMIT rule as appropriate.
Now in /sys/netinet/ip_fw2.c in ipfw_chk circa line 2400 (@5.5) we have:
* O_LIMIT and O_KEEP_STATE: these opcodes are
* not real 'actions', and are stored right
* before the 'action' part of the rule.
* These opcodes try to install an entry in the
* state tables; if successful, we continue with
* the next opcode (match=1; break;), otherwise
* the packet * must be dropped
* ('goto done' after setting retval);
*
* O_PROBE_STATE and O_CHECK_STATE: these opcodes
* cause a lookup of the state table, and a jump
* to the 'action' part of the parent rule
* ('goto check_body') if an entry is found, or
* (CHECK_STATE only) a jump to the next rule if
* the entry is not found ('goto next_rule').
* The result of the lookup is cached to make
* further instances of these opcodes are
* effectively NOPs.
*/
case O_LIMIT:
case O_KEEP_STATE:
if (install_state(f,
(ipfw_insn_limit *)cmd, args)) {
retval = IP_FW_PORT_DENY_FLAG;
goto done; /* error/limit violation */
}
match = 1;
break;
case O_PROBE_STATE:
case O_CHECK_STATE:
/*
* dynamic rules are checked at the first
* keep-state or check-state occurrence,
* with the result being stored in dyn_dir.
* The compiler introduces a PROBE_STATE
* instruction for us when we have a
* KEEP_STATE (because PROBE_STATE needs
* to be run first).
*/
if (dyn_dir == MATCH_UNKNOWN &&
(q = lookup_dyn_rule(&args->f_id,
&dyn_dir, proto == IPPROTO_TCP ?
L3HDR(struct tcphdr, ip) : NULL))
!= NULL) {
/*
* Found dynamic entry, update stats
* and jump to the 'action' part of
* the parent rule.
*/
q->pcnt++;
q->bcnt += pktlen;
f = q->rule;
cmd = ACTION_PTR(f);
l = f->cmd_len - f->act_ofs;
IPFW_DYN_UNLOCK();
goto check_body;
}
/*
* Dynamic entry not found. If CHECK_STATE,
* skip to next rule, if PROBE_STATE just
* ignore and continue with next opcode.
*/
if (cmd->opcode == O_CHECK_STATE)
goto next_rule;
match = 1;
break;
So indeed each rule with keep-state or limit options does the same probe
as a check-state in the first opcode, before then installing or checking
state in the subsequent opcode. Or so it reads to an ancient neophyte ..
> I think the document is talking about the lifetime.
> Each time a keep-state or check-state or limit is hit,
> the TTL is kicked.
That's pretty well described under keep-state and elsewhere. Good ol'
ipfw(8) has yet to let me down, and like Ivan I recall keep-state rules
(albeit only for UDP) without any check-state working just fine.
Not that any of that helps solve Ivan's problem ..
cheers, Ian
More information about the freebsd-net
mailing list