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>