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>
index | next in thread | raw e-mail
>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
help
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20001017223906.D8B0E37B4F9>
