From owner-freebsd-net@FreeBSD.ORG Sat Apr 5 09:20:03 2008 Return-Path: Delivered-To: freebsd-net@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 9BD36106566C; Sat, 5 Apr 2008 09:20:03 +0000 (UTC) (envelope-from smithi@nimnet.asn.au) Received: from gaia.nimnet.asn.au (nimbin.lnk.telstra.net [139.130.45.143]) by mx1.freebsd.org (Postfix) with ESMTP id 407B08FC17; Sat, 5 Apr 2008 09:20:00 +0000 (UTC) (envelope-from smithi@nimnet.asn.au) Received: from localhost (smithi@localhost) by gaia.nimnet.asn.au (8.8.8/8.8.8R1.5) with SMTP id TAA12951; Sat, 5 Apr 2008 19:19:52 +1000 (EST) (envelope-from smithi@nimnet.asn.au) Date: Sat, 5 Apr 2008 19:19:51 +1000 (EST) From: Ian Smith To: Julian Elischer In-Reply-To: <47F667FA.6020208@elischer.org> Message-ID: MIME-Version: 1.0 Content-Type: TEXT/PLAIN; charset=US-ASCII Cc: freebsd-net@freebsd.org, Ivan Voras Subject: Re: Trouble with IPFW or TCP? X-BeenThere: freebsd-net@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: Networking and TCP/IP with FreeBSD List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sat, 05 Apr 2008 09:20:03 -0000 On Fri, 4 Apr 2008, Julian Elischer wrote: > Ian Smith wrote: > > On Thu, 3 Apr 2008, Julian Elischer wrote: > > > > > 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! > > yep you are right.. > boy is that ever a broken feature.. > there is no way to set a new session without leaping off into the > previously declared sessions. > > I just tested it and it does as you say... > > 00001 166 17438 skipto 1000 tcp from any to 10.2.2.2 keep-state > 00002 9 886 allow ip from any to any > 01000 166 17438 count log ip from any to any > 01001 93 7727 count log tcp from any to 10.2.2.2 > 01002 73 9711 count log tcp from 10.2.2.2 to any > 65535 166 17438 allow ip from any to any > > I'm stunned.. > boy is that ever a broken feature.. > There is no way to set a new session without leaping off into the > previously declared sessions. > > I also have to check my firewalls to see if I'm hitting unexpeced > behaviour. I don't see why you think it's broken? Apart from obvious efficiency of having a check-state rule earlier, to get on with matching this packet against existing dynamic rules without wading through intervening rules, state is still only checked once; like it says, the O_PROBE_STATE opcode only causes a state check at the first check-state, keep-state or limit rule (encountered); any others found then become a short-path NOP. Personally I like to do traffic accounting before any packet is whisked off to be dealt with (and accounted by) any keep-state rules, though as your example shows that can be done afterwards, if not piped or such. But I can't see why you ever wouldn't want to check the existing state of any src-addr/src-port <-> dst-addr/dst-port packet before attempting to add a new dynamic rule for that same session? cheers, Ian > > > > 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 > > > > _______________________________________________ > > freebsd-net@freebsd.org mailing list > > http://lists.freebsd.org/mailman/listinfo/freebsd-net > > To unsubscribe, send any mail to "freebsd-net-unsubscribe@freebsd.org" >