[PATCH] limit N connections without dropping N+1
Pawel Malachowski
pawmal-posting at freebsd.lublin.pl
Sun Nov 7 11:20:14 PST 2004
Hello,
ipfw limit option allows limiting number of states generated by a rule.
If packet belongs to a registered state, it is matched; otherwise, it is
dropped.
I believie this behaviour is too restrictive. My proposal is to:
. perform rule action on matched (belonging to states) packet;
. continue packets journey through firewall if it is unmatched.
With this, we have additional possibilities, e.g. to pass first
N connections (flows) to dummynet queue with high weight and
next (starting from N+1) connections to queue with low weight.
Previous behaviour can be emulated with additional deny rule.
Current behaviour:
ipfw add 100 skipto 300 ip from any to any out xmit rl0 limit src-addr 10
This will allow 10 outgoing flows per source IP. Packet creating 11th
state will be dropped.
After change:
ipfw add 100 skipto 300 ip from any to any out xmit rl0 limit src-addr 10
ipfw add 200 deny ip from any to any out xmit fxp0
This will allow 10 outgoing flows per source IP. Packet creating 11th
state will not match rule 100, so it will be check against next rule, 200.
And it will be dropped.
However, this kind of setup is possible *only* with new behaviour:
ipfw pipe 1 config bw 1Mbit/s queue 20KB
ipfw pipe 2 config bw 128Kbit/s queue 5KB
ipfw add 100 pipe 1 ip from any to any out xmit fxp0
ipfw add 150 skipto 300 ip from any to any out xmit fxp0 limit src-addr 10
ipfw add 200 pipe 2 ip from any to any out xmit fxp0
(This example assumes one_pass=0.)
Pass all outgoing traffic to pipe 1, additionally, if source IP generates
more than 10 states (possible P2P or download accelerator traffic), pass
all these additional connections to pipe 2 to enforce restrictive limit.
Example from live system:
ipfw -f flush
ipfw add 65000 allow ip from any to any
ipfw add 1000 skipto 10000 ip from any to any out xmit fxp0 limit src-addr 1
ipfw add 2000 skipto 20000 ip from any to any out xmit fxp0 limit src-addr 2
ipfw add 3000 count ip from any to any out xmit fxp0
// Now run pings from 10.1.4.106 to 10.1.0.1, 10.1.2.1, 10.1.7.1 hosts,
// 4th ping -c 5 from 10.1.4.106 to some other host, it matches 3000 only.
% ipfw -d show
01000 348 29232 skipto 10000 ip from any to any out xmit fxp0 limit src-addr 1
02000 694 58296 skipto 20000 ip from any to any out xmit fxp0 limit src-addr 2
03000 5 420 count ip from any to any out xmit fxp0
65000 1308 122154 allow ip from any to any
65535 25 2076 deny ip from any to any
## Dynamic rules (5):
02000 0 0 (3s) PARENT 2 icmp 10.1.4.106 0 <-> 0.0.0.0 0
01000 0 0 (3s) PARENT 1 icmp 10.1.4.106 0 <-> 0.0.0.0 0
02000 347 29148 (5s) LIMIT icmp 10.1.4.106 0 <-> 10.1.2.1 0
01000 347 29148 (5s) LIMIT icmp 10.1.4.106 0 <-> 10.1.0.1 0
02000 345 28980 (5s) LIMIT icmp 10.1.4.106 0 <-> 10.1.7.1 0
Patch is against 5.3RC2.
Probably no man page changes needed. ;)
--
Paweł Małachowski
-------------- next part --------------
--- /sys/netinet/ip_fw2.c-orig Fri Oct 29 21:29:56 2004
+++ /sys/netinet/ip_fw2.c Sun Nov 7 19:21:56 2004
@@ -2281,8 +2281,8 @@
* These opcodes try to install an entry in the
* state tables; if successful, we continue with
* the next opcode (match=1; break;), otherwise
- * the packet * must be dropped
- * ('goto done' after setting retval);
+ * the packet will not match, however, it will
+ * travel through firewall.
*
* O_PROBE_STATE and O_CHECK_STATE: these opcodes
* cause a lookup of the state table, and a jump
@@ -2296,12 +2296,10 @@
*/
case O_LIMIT:
case O_KEEP_STATE:
- if (install_state(f,
- (ipfw_insn_limit *)cmd, args)) {
- retval = IP_FW_PORT_DENY_FLAG;
- goto done; /* error/limit violation */
- }
match = 1;
+ if (install_state(f,
+ (ipfw_insn_limit *)cmd, args))
+ match = 0;
break;
case O_PROBE_STATE:
More information about the freebsd-ipfw
mailing list