Skip site navigation (1)Skip section navigation (2)
Date:      Thu,  5 Jul 2001 00:36:19 -0600 (MDT)
From:      Aaron Gifford <agifford@infowest.com>
To:        FreeBSD-gnats-submit@freebsd.org
Subject:   kern/28713: NEW IPFW FEATURE [PATCHES]: Dynamic rule expiration lifetime fine-grained control
Message-ID:  <20010705063619.A9A31210EC@ns1.infowest.com>

next in thread | raw e-mail | index | archive | help
	Note: There was a bad value `non-criticial' for the field `>Severity:'.
	It was set to the default value of `serious'.


>Number:         28713
>Category:       kern
>Synopsis:       NEW IPFW FEATURE [PATCHES]: Dynamic rule expiration lifetime fine-grained control
>Confidential:   no
>Severity:       serious
>Priority:       medium
>Responsible:    freebsd-bugs
>State:          open
>Quarter:        
>Keywords:       
>Date-Required:
>Class:          change-request
>Submitter-Id:   current-users
>Arrival-Date:   Wed Jul 04 23:40:01 PDT 2001
>Closed-Date:
>Last-Modified:
>Originator:     Aaron Gifford
>Release:        FreeBSD 4.3-STABLE i386
>Organization:
N/A
>Environment:
System: FreeBSD my.host.name 4.3-STABLE FreeBSD 4.3-STABLE #0: Thu Jun 21 20:14:40 MDT 2001 root@my.host.name:/usr/obj/usr/src/sys/CUSTOM i386


>Description:


  NEW FEATURE:  Fine-grained control over dynamic rule expiration using
                an optional per-rule expiration lifetime


  When using stateful ipfw rules, the dynamic rule expiration times
  are governed by the values of the net.inet.ip.fw.dyn_*_lifetime
  variables.  This is an excellent attribute of the ipfw stateful
  rule system.  System administrators can tune overall system
  rule expiration times to tailor ipfw to best suit their needs.

  Unfortunately, this global tuning of rule expiration times just does
  not give the ipfw power user the fine-grained control he or she needs
  or wants.  For example, the default 300-second (5-minute) expiration
  for TCP sessions (governed by the net.inet.ip.fw.dyn_ack_lifetime
  sysctl variable) in the connected state works well for TCP protocols
  like HTTP where the TCP session will very likely not idle beyond
  that default expiration time.  But for TCP sessions like telnet or
  ssh where a user may let his or her connection idle longer than
  that, it is extremely annoying to discover the session frozen
  because the firewall expired the dynamic rule for the session.
  The system administrator could just increase the rule expiration
  time, but that breaks the elegance of the default (or admin.-tuned)
  global expiration setting that works well and is desireable for
  most connections.

  The solution is quite simple: add an option to override the default
  sysctl variable settings for TCP sessions in the connected state,
  and also for UDP sessions.  With such an option, ipfw rules that
  do not use the option behave as they do now.  Rules that use the
  option can override the default sysctl settings on a per-rule basis.

  Here's an example:

    OLD IPFW RULES:
      ipfw add check-state
      ipfw add deny tcp from any to any established
      ipfw add allow tcp from me to any keep-state out setup
      ...
      ipfw add allow udp from me to any 53 keep-state out
      ipfw add allow udp from me to ${icq} 4000 keep-state out
      ...

    With the above rules, the host can create new outbound TCP sessions
    using the default expiration times.  However, users on the host who
    make outbound telnet/ssh sessions (or other long-idleing sessions)
    will be frusterated unless the admin. increases the global default
    expiration lifetime.  And if the admin. does this, he/she increases
    consumption of system resources in cases of outbound TCP sessions
    where the remote side of the connection dies during the connected
    state without any indication or response, leaving the state as
    connected, the dynamic rule persisting longer than would otherwise
    be needed.

    NEW IPFW RULES:
      ipfw add check-state
      ipfw add deny tcp from any to any established
      ipfw add allow tcp from me to any 22,23 keep-state lifetime 3600 out setup
      ipfw add allow tcp from me to any keep-state out setup
      ...
      ipfw add allow udp from me to any 53 keep-state out
      ipfw add allow udp from me to ${icq} 4000 keep-state lifetime 600 out
      ...

    Now the administrator can use the default settings for most TCP and
    UDP sessions, but override the settings for specific uses.  This
    flexibility is very desirable.


  This feature is currently in use on several FreeBSD-STABLE machines
  where I work, as well as on my home machine.  I know that several
  other FreeBSD users have at least downloaded and looked at the patches
  that add this feature.  I do not know if anyone else is using it
  currently.

  The patches below implement this feature.  The patches included here
  are against the latest CVS versions of the various files as of Wed.
  4 July 2001 8:00 PM MST (-0600).  I also have patches against -STABLE
  if anyone wants them.  I have been running this patch (the only changes
  over time were very minimal, line offsets, etc. to keep the patch
  working against -STABLE source changes over time) for well over a
  year now and it has been rock solid on Internet web server hosts as
  well as on various border firewall machines.

  IPFW MAINTAINERS: PLEASE, please examine the patches.  If there are
  no glaring errors or omissions, please consider committing them.
  
   * The patches update the 'ipfw' man page to document the new
     feature.

   * Compatibility: using an unpatched ipfw with a patched kernel
     or using a patched ipfw with an unpatched kernel should work
     just fine with normal rules (the 'lifetime' feature will not
     work).

 
  Thank you.

  Aaron Gifford
  <agifford@infowest.com>


*** NOTE: Patches to the latest CVS versions of the relevant source
*** files are included below in the "Fix:" section.  These patches
*** should apply cleanly to FreeBSD-CURRENT.  Feel free to e-mail
*** me for patches that apply cleanly to FreeBSD-STABLE.
	
>How-To-Repeat:
        N/A - See above description or patches below
>Fix:
	Commit the patches below.

--- /usr/src/sys/netinet/ip_fw.h.orig	Tue Feb 20 11:39:17 2001
+++ /usr/src/sys/netinet/ip_fw.h	Thu Jul  5 03:46:51 2001
@@ -74,6 +74,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 */
 	/*
@@ -122,6 +123,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) next;
@@ -148,6 +150,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	*/
--- /usr/src/sys/netinet/ip_fw.c.orig	Mon Jul  2 15:50:31 2001
+++ /usr/src/sys/netinet/ip_fw.c	Thu Jul  5 03:46:51 2001
@@ -763,7 +763,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) :
@@ -788,7 +788,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 ;
@@ -834,7 +834,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 ;
 
--- /usr/src/sbin/ipfw/ipfw.c.orig	Sun Jul  1 22:00:26 2001
+++ /usr/src/sbin/ipfw/ipfw.c	Thu Jul  5 03:46:51 2001
@@ -377,6 +377,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)
@@ -917,6 +919,7 @@
 "    tcpack {acknowledgement number}\n"
 "    tcpwin {window size}\n"
 "    icmptypes {type[, type]}...\n"
+"    keep-state [lifetime {number of seconds}]\n"
 "  pipeconfig:\n"
 "    {bw|bandwidth} <number>{bit/s|Kbit/s|Mbit/s|Bytes/s|KBytes/s|MBytes/s}\n"
 "    {bw|bandwidth} interface_name\n"
@@ -1971,6 +1974,15 @@
 			if (ac > 0 && (type = atoi(*av)) != 0) {
 			    (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--;
+			    }
 			}
 		} else if (!strncmp(*av, "bridged", strlen(*av))) {
 			rule.fw_flg |= IP_FW_BRIDGED;
--- /usr/src/sbin/ipfw/ipfw.8.orig	Wed Jun  6 20:56:56 2001
+++ /usr/src/sbin/ipfw/ipfw.8	Thu Jul  5 03:46:51 2001
@@ -640,18 +640,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 each 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:
 Please read the bulk of my message in the "Description:" section below...
 
 

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?20010705063619.A9A31210EC>