Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 17 Oct 2000 15:39:06 -0700 (PDT)
From:      agifford@infowest.com
To:        freebsd-gnats-submit@FreeBSD.org
Subject:   kern/22065: Patch to add support to ipfw for per rule overriding of dynamic keep-state rule expiration lifetimes
Message-ID:  <20001017223906.D8B0E37B4F9@hub.freebsd.org>

next in thread | raw e-mail | index | archive | help

>Number:         22065
>Category:       kern
>Synopsis:       Patch to add support to ipfw for per rule overriding of dynamic keep-state rule expiration lifetimes
>Confidential:   no
>Severity:       non-critical
>Priority:       low
>Responsible:    freebsd-bugs
>State:          open
>Quarter:        
>Keywords:       
>Date-Required:
>Class:          change-request
>Submitter-Id:   current-users
>Arrival-Date:   Tue Oct 17 15:40:01 PDT 2000
>Closed-Date:
>Last-Modified:
>Originator:     Aaron D. Gifford
>Release:        FreeBSD 4.1.1-STABLE
>Organization:
>Environment:
FreeBSD my.freebsd.box 4.1.1-STABLE FreeBSD 4.1.1-STABLE #0: Thu Oct 12 11:58:29 MDT 2000     root@my.freebsd.box:/usr/src/sys/compile/LOCAL  i386
>Description:
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
>How-To-Repeat:
This is a feature request
>Fix:
--- sys/netinet/ip_fw.h.orig    Mon Aug 21 18:33:18 2000
+++ sys/netinet/ip_fw.h Tue Oct 17 16:08:36 2000
@@ -73,6 +73,7 @@
        u_short fu_skipto_rule;         /* SKIPTO command rule number */
        u_short fu_reject_code;         /* REJECT response code */
        struct sockaddr_in fu_fwd_ip;
+       u_int32_t fu_dyn_lifetime;      /* Explicit dynamic rule lifetime */
     } fw_un;
     u_char fw_prot;                    /* IP protocol */
        /*
@@ -121,6 +122,7 @@
 #define fw_reject_code fw_un.fu_reject_code
 #define fw_pipe_nr     fw_un.fu_pipe_nr
 #define fw_fwd_ip      fw_un.fu_fwd_ip
+#define fw_dyn_lifetime        fw_un.fu_dyn_lifetime

 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   */
--- sys/netinet/ip_fw.c.orig    Tue Oct 17 07:44:57 2000
+++ sys/netinet/ip_fw.c Tue Oct 17 16:08:36 2000
@@ -722,7 +722,7 @@
            break ;
        case TH_SYN | (TH_SYN << 8) :
            /* move to established */
-           q->expire = time_second + dyn_ack_lifetime ;
+           q->expire = time_second + (q->lifetime ? q->lifetime : dyn_ack_lifetime) ;
            break ;
        case TH_SYN | (TH_SYN << 8) | TH_FIN :
        case TH_SYN | (TH_SYN << 8) | (TH_FIN << 8) :
@@ -747,7 +747,7 @@
        }
     } else {
        /* should do something for UDP and others... */
-       q->expire = time_second + dyn_short_lifetime ;
+       q->expire = time_second + (q->lifetime ? q->lifetime : dyn_short_lifetime) ;
     }
     if (match_direction)
        *match_direction = dir ;
@@ -795,7 +795,13 @@
     if (mask)
        r->mask = *mask ;
     r->id = *id ;
-    r->expire = time_second + dyn_syn_lifetime ;
+    r->lifetime = chain->rule->fw_dyn_lifetime ;
+    if (r->lifetime)
+       r->expire = time_second + r->lifetime ;
+    else if (r->id.proto == IPPROTO_TCP)
+       r->expire = time_second + dyn_syn_lifetime ;
+    else
+        r->expire = time_second + dyn_short_lifetime ;
     r->chain = chain ;
     r->type = ((struct ip_fw_ext *)chain->rule)->dyn_type ;

--- sbin/ipfw/ipfw.c.orig       Tue Oct 17 07:44:55 2000
+++ sbin/ipfw/ipfw.c    Tue Oct 17 16:08:36 2000
@@ -383,6 +383,8 @@
                     printf(" keep-state %d", (int)chain->next_rule_ptr);
                 else
                     printf(" keep-state");
+               if (chain->fw_dyn_lifetime)
+                   printf(" lifetime %d", (int)chain->fw_dyn_lifetime);
         }
         /* Direction */
         if (chain->fw_flg & IP_FW_BRIDGED)
@@ -837,6 +839,7 @@
 "    ipoptions [!]{ssrr|lsrr|rr|ts},...\n"
 "    tcpoptions [!]{mss|window|sack|ts|cc},...\n"
 "    icmptypes {type[,type]}...\n"
+"    keep-state [lifetime <number>]\n"
 "  pipeconfig:\n"
 "    {bw|bandwidth} <number>{bit/s|Kbit/s|Mbit/s|Bytes/s|KBytes/s|MBytes/s}\n"
 "    {bw|bandwidth} interface_name\n"
@@ -1821,6 +1824,15 @@
                             (int)rule.next_rule_ptr = type ;
                             av++; ac--;
                         }
+                       if (ac > 0 && !strncmp(*av,"lifetime",strlen(*av))) {
+                           u_long lifetime ;
+
+                           av++; ac--;
+                           if (ac > 0 && (lifetime = atoi(*av)) != 0) {
+                               rule.fw_dyn_lifetime = lifetime;
+                               av++; ac--;
+                           }
+                       }
                         continue;
                 }
                 if (!strncmp(*av,"bridged",strlen(*av))) {
--- sbin/ipfw/ipfw.8.orig       Tue Oct 17 07:09:53 2000
+++ sbin/ipfw/ipfw.8    Tue Oct 17 16:08:36 2000
@@ -605,18 +605,38 @@
 interface.
 .It Ar options :
 .Bl -tag -width indent
-.It Cm keep-state Op Ar method
+.It Xo Cm keep-state Op Ar method
+.Op Cm lifetime Ar number
+.Xc
 Upon a match, the firewall will create a dynamic rule, whose
-default behaviour is to matching bidirectional traffic between
+default behaviour is to match bidirectional traffic between
 source and destination IP/port using the same protocol.
-The rule has a limited lifetime (controlled by a set of
+The rule has a limited lifetime controlled by a set of
 .Xr sysctl 8
-variables), and the lifetime is refreshed every time a matching
-packet is found.
+variables that may be overridden on a per-rule basis.
+The lifetime is refreshed every time a matching packet is
+found.
 .Pp
 The actual behaviour can be modified by specifying a different
 .Ar method ,
 although at the moment only the default one is specified.
+.Pp
+The default rule lifetime may be overridden for a specific
+rule by appending
+.Cm lifetime Ar number
+to explicitly set the number of seconds for the dynamic rule
+lifetime.
+.Pp
+For TCP rules, explicitly setting a rule lifetime overrides the
+default setting stored in the
+.Xr sysctl 8
+variable
+.Em net.inet.ip.fw.dyn_ack_lifetime .
+For non-TCP rules, it overrides the
+.Xr sysctl 8
+variable
+.Em net.inet.ip.fw.dyn_short_lifetime
+instead.
 .It Cm bridged
 Matches only bridged packets.
 This can be useful for multicast or broadcast traffic, which


>Release-Note:
>Audit-Trail:
>Unformatted:


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




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20001017223906.D8B0E37B4F9>