| Summary: | [PATCH] incorrect handling of parent rules in ipfw | ||||||
|---|---|---|---|---|---|---|---|
| Product: | Base System | Reporter: | Dan Pelleg <peldan> | ||||
| Component: | kern | Assignee: | Luigi Rizzo <luigi> | ||||
| Status: | Closed FIXED | ||||||
| Severity: | Affects Only Me | ||||||
| Priority: | Normal | ||||||
| Version: | 4.4-STABLE | ||||||
| Hardware: | Any | ||||||
| OS: | Any | ||||||
| Attachments: |
|
||||||
|
Description
Dan Pelleg
2001-12-08 12:50:00 UTC
Responsible Changed From-To: freebsd-bugs->luigi The attached patch was suggested by Mr Rizzo. Following up to my own PR, I'm providing a patch that applies cleanly
against 4.5-R. It doesn't differ from the previous one in any significant
way (well, except for the fact that it applies cleanly).
--- sys/netinet/ip_fw.c.orig Mon Feb 11 06:39:33 2002
+++ sys/netinet/ip_fw.c Mon Feb 11 06:41:21 2002
@@ -694,17 +694,23 @@
* and possibly more in the future.
*/
int zap = ( rule == NULL || rule == q->rule);
- if (zap)
- zap = force || TIME_LEQ( q->expire , time_second );
+
/* do not zap parent in first pass, record we need a second pass */
if (q->dyn_type == DYN_LIMIT_PARENT) {
max_pass = 1; /* we need a second pass */
if (zap == 1 && (pass == 0 || q->count != 0) ) {
zap = 0 ;
- if (pass == 1) /* should not happen */
- printf("OUCH! cannot remove rule, count %d\n",
- q->count);
+ if (force && pass == 1) { /* should not happen */
+ printf("OUCH! cannot remove rule 0x%08x %d -> 0x%08x %d, count %d, bucket %d\n",
+ (q->id.src_ip), (q->id.src_port),
+ (q->id.dst_ip), (q->id.dst_port),
+ q->count,
+ i);
+ }
}
+ } else {
+ if (zap)
+ zap = force || TIME_LEQ( q->expire , time_second );
}
if (zap) {
UNLINK_DYN_RULE(prev, ipfw_dyn_v[i], q);
@@ -885,7 +891,7 @@
DEB(printf("-- add entry 0x%08x %d -> 0x%08x %d, total %d\n",
(r->id.src_ip), (r->id.src_port),
(r->id.dst_ip), (r->id.dst_port),
- dyn_count ); )
+ dyn_count); )
return r;
}
@@ -988,8 +994,20 @@
}
if (parent->count >= conn_limit) {
EXPIRE_DYN_CHAIN(rule); /* try to expire some */
+ /*
+ The expiry might have removed the parent too.
+ We lookup again, which will re-create if necessary.
+ */
+ parent = lookup_dyn_parent(&id, rule);
+ if (parent == NULL) {
+ printf("add parent failed\n");
+ return 1;
+ }
if (parent->count >= conn_limit) {
- printf("drop session, too many entries\n");
+ if (last_log != time_second) {
+ last_log = time_second ;
+ printf("drop session, too many entries\n");
+ }
return 1;
}
}
@@ -1928,6 +1946,12 @@
for ( p = ipfw_dyn_v[i] ; p != NULL ; p = p->next, dst++ ) {
bcopy(p, dst, sizeof *p);
(int)dst->rule = p->rule->fw_number ;
+ /*
+ * we should really set the parent field
+ * to the corresponding parent in the new
+ * structure. For now, just set it to NULL.
+ */
+ dst->parent = NULL ;
/*
* store a non-null value in "next". The userland
* code will interpret a NULL here as a marker
--- sbin/ipfw/ipfw.c.orig Mon Feb 11 06:39:56 2002
+++ sbin/ipfw/ipfw.c Mon Feb 11 06:42:58 2002
@@ -813,10 +813,18 @@
(struct ipfw_dyn_rule *)&rules[num];
struct in_addr a;
struct protoent *pe;
+ int skip;
printf("## Dynamic rules:\n");
for (;; d++) {
- if (d->expire == 0 && !do_expired) {
+ /* determine whether to skip this rule */
+ skip = !do_expired;
+ if( d->dyn_type == DYN_LIMIT_PARENT) {
+ skip = skip && d->count == 0;
+ } else {
+ skip = skip && d->expire == 0;
+ }
+ if(skip) {
if (d->next == NULL)
break;
continue;
State Changed From-To: open->closed this is fixed in ipfw2. |