Bug 22065

Summary: Patch to add support to ipfw for per rule overriding of dynamic keep-state rule expiration lifetimes
Product: Base System Reporter: agifford
Component: kernAssignee: Luigi Rizzo <luigi>
Status: Closed FIXED    
Severity: Affects Only Me    
Priority: Normal    
Version: 4.1.1-STABLE   
Hardware: Any   
OS: Any   
Attachments:
Description Flags
file.diff
none
file.diff
none
file.diff none

Description agifford 2000-10-17 23:40:01 UTC
Hello,

When using ipfw's dynamic stateful rules, while users CAN use the sysctl
variables to control expiration times globally, it cannot yet be done
on a rule-by-rule basis.  The patch below fixes this, adding the ability
to append "lifetime X" (where X is a number) to any keep-state rule.
For keep-state rules that do NOT append this new option, the old behavior
guided by the sysctl variables remains.  For those rules that add this
option, on a rule-by-rule basis the expiration time may be customized.

While writing these patches, I came across what LOOKS like a bug but
may not. In ip_fw.c, I noticed that both TCP and non-TCP keep-state
rules are updated using the net.inet.ip.fw_syn_lifetime where I
would think that non-TCP keep-state rules should instead be using
the net.inet.ip.fw.dyn_short_lifetime variable instead.  This patch
also fixes this issue.  If this is NOT a bug but is deliberate,
I would encourage that it be documented as such.  I believe it is
around line 798 of ip_fw.c (at least on FreeBSD-4.1.1-STABLE as of
17 Oct. 2000).

This patch also adds documentation for the "lifetime X" option
to the ipfw man page.

I have been using these patches on several moderate-traffic Internet
hosts and on several firewall boxes, all running various versions of
FreeBSD 4.0 and 4.1 for several months now with absolutely no problems
at all.  I belive these changes to be VERY stable.

This change would be extremely useful.  I use it right now like this:
(This is a small subset of my rules, edited for this example)

  ipfw add check-state
  ### UDP filters:
  # Keep state on UDP sent to ICQ servers for up to 5 minutes
  # so ICQ clients won't keep getting disconnected:
  ipfw add pass udp from ${MYIP} to ${ICQ_NETWORK} out keep-state lifetime 300
  # All other UDP will use the default net.inet.ip.fw.dyn_short_lifetime
  # expiration:
  ipfw add pass udp from ${MYIP} to any out keep-state
  ### TCP filters:
  # Drop bogus "established" traffic:
  ipfw add deny tcp from any to any established
  # Keep my SSH sessions around for up to a whole day:
  ipfw add pass tcp from ${MYIP} to any out setup keep-state lifetime 86400
  # All other outgoing TCP gets the default expiration as set in the
  # system variable net.inet.ip.fw_syn_lifetime:
  ipfw add pass tcp from ${MYIP} to any out setup keep-state

I really hope that this new feature will be adopted.  It has been very
useful.  And that would also let me be more lazy -- I wouldn't have to
patch my system after each cvsup.  :)

If the patch submitted below (in the "Fix to the problem if known:" part) doesn't come through clearly, email me and I'll email the patch to you.

Sincerely,
Aaron Gifford

Fix: struct ip_fw_chain {
         LIST_ENTRY(ip_fw_chain) chain;
@@ -147,6 +149,7 @@
     struct ipfw_flow_id mask ;
     struct ip_fw_chain *chain ;                /* pointer to parent rule       */
     u_int32_t type ;                   /* rule type                    */
+    u_int32_t lifetime ;               /* per-rule specified lifetime  */
     u_int32_t expire ;                 /* expire time                  */
     u_int64_t pcnt, bcnt;              /* match counters               */
     u_int32_t bucket ;                 /* which bucket in hash table   */
How-To-Repeat: This is a feature request
Comment 1 Johan Karlsson freebsd_committer freebsd_triage 2000-10-22 19:38:30 UTC
Responsible Changed
From-To: freebsd-bugs->luigi

Over to ipfw maintainer.
Comment 2 agifford 2001-02-17 19:48:52 UTC
Looks like this proposed patch (PR 22065) is still open.  I suppose that 
means no one has decided whether it is useful or not, or (far more likely) 
folks are extremely busy doing other fun and useful stuff for FreeBSD.

The patch in the PR is still mostly valid for FreeBSD 4.2-STABLE with a few 
line offset changes.  I've got an updated version of the patch against 
4.2-STABLE as of 17 FEB 2001 at the following web address:

  http://www.aarongifford.com/computers/ipfwpatch.html

I have been using the patch successfully on several moderate-traffic hosts 
with no noticable problems.

I do still have two questions that no one has yet answered.  Still, it would 
be nice to know the following (with regard to the patch):

  1. Am I safe using the union fw_un in the ip_fw structure (in ip_fw.h) to 
store the dynamic rule's lifetime setting or will this overlap with one of 
the other uses of that union and thus require that I modify the patch to 
create a new structure member for storing the setting?

  2. Am I correct in assuming that in ip_fw.c at roughly line 800 where UDP 
and TCP matches to the dynamic rule extend the rule expiration by the 
dyn_syn_lifetime amount that this should instead only extend TCP matches by 
dyn_syn_lifetime and should extend UDP matches by dyn_short_lifetime instead? 
 I believe this to be the case.  The snippet of code from ip_fw.c in question 
looks like (beginning at line 800 of ip_fw.c as of FreeBSD 4.2-STABLE on 17 
FEB 2001):
 
        }
        bzero (r, sizeof (*r) );
 
        if (mask)
            r->mask = *mask ;
        r->id = *id ;
        r->expire = time_second + dyn_syn_lifetime ;  /*<<<THIS LINE<<<*/
        r->chain = chain ;
        r->type = ((struct ip_fw_ext *)chain->rule)->dyn_type ;
  
        r->bucket = i ;
        r->next = ipfw_dyn_v[i] ;
        ipfw_dyn_v[i] = r ;
        dyn_count++ ;
         DEB(printf("-- add entry 0x%08x %d -> 0x%08x %d, %d left\n",
            (r->id.src_ip), (r->id.src_port),
            (r->id.dst_ip), (r->id.dst_port),
            dyn_count ); )
    }   

I assume that the line above (flagged above with "<<<THIS LINE<<<") should 
instead read something like:

    r->expire = time_second + (r->id.proto == IPPROTO_TCP ?
        dyn_syn_lifetime : dyn_short_lifetime) ;

My patch assumes that this is the case and modifies the behavior so that 
non-TCP rule match expiration lifetimes are incremented by the 
dyn_short_lifetime sysctl setting (if no per-rule lifetime is specified).

I would appreciate any answers to the two above questions, question #1 in 
particular, as well as any other commentary or suggestions.

Thanks,
Aaron out.

-- 
InfoWest, Inc.  *  596 E. Tabernacle  *  St. George, UT 84790
Voice: 435-674-0165  *  FAX: 435-674-9654
Web: www.infowest.com  *  E-mail: support@infowest.com
Comment 3 agifford 2002-02-02 00:52:35 UTC
I suggest this PR be closed in favor of the more up-to-date one (#28713) at:

  http://www.FreeBSD.org/cgi/query-pr.cgi?pr=kern/28713

Aaron out.
Comment 4 Luigi Rizzo freebsd_committer freebsd_triage 2002-09-03 02:54:59 UTC
State Changed
From-To: open->closed

this replicates kern/28713 and it is made almost completely 
unnecessary by ipfw2's keepalives.