diff options
author | luigi <luigi@FreeBSD.org> | 2001-11-04 22:56:25 +0000 |
---|---|---|
committer | luigi <luigi@FreeBSD.org> | 2001-11-04 22:56:25 +0000 |
commit | f565e0a1dff9f306dcf2a7ce69991a22170dfa34 (patch) | |
tree | c941161cecb4fb744bf3988da945ddfd0a75a240 /sys/netinet/ip_fw.c | |
parent | 473a686e79edeaa4c5a1b0e1fced3d7dcc9ef444 (diff) | |
download | FreeBSD-src-f565e0a1dff9f306dcf2a7ce69991a22170dfa34.zip FreeBSD-src-f565e0a1dff9f306dcf2a7ce69991a22170dfa34.tar.gz |
MFS: sync the ipfw/dummynet/bridge code with the one recently merged
into stable (mostly , but not only, formatting and comments changes).
Diffstat (limited to 'sys/netinet/ip_fw.c')
-rw-r--r-- | sys/netinet/ip_fw.c | 171 |
1 files changed, 95 insertions, 76 deletions
diff --git a/sys/netinet/ip_fw.c b/sys/netinet/ip_fw.c index 320672c..5a26121 100644 --- a/sys/netinet/ip_fw.c +++ b/sys/netinet/ip_fw.c @@ -155,7 +155,8 @@ SYSCTL_INT(_net_inet_ip_fw, OID_AUTO, permanent_rules, CTLFLAG_RW, static struct ipfw_dyn_rule **ipfw_dyn_v = NULL ; static u_int32_t dyn_buckets = 256 ; /* must be power of 2 */ static u_int32_t curr_dyn_buckets = 256 ; /* must be power of 2 */ -/** + +/* * timeouts for various events in handing dynamic rules. */ static u_int32_t dyn_ack_lifetime = 300 ; @@ -200,8 +201,7 @@ SYSCTL_INT(_net_inet_ip_fw, OID_AUTO, dyn_short_lifetime, CTLFLAG_RW, SYSCTL_INT(_net_inet_ip_fw, OID_AUTO, dyn_grace_time, CTLFLAG_RD, &dyn_grace_time, 0, "Grace time for dyn. rules"); - -#endif +#endif /* SYSCTL_NODE */ #define dprintf(a) do { \ if (fw_debug) \ @@ -674,22 +674,21 @@ hash_packet(struct ipfw_flow_id *id) * head is a pointer to the head of the queue. * Modifies q and potentially also head. */ -#define UNLINK_DYN_RULE(prev, head, q) { \ - struct ipfw_dyn_rule *old_q = q; \ - \ - /* remove a refcount to the parent */ \ - if (q->dyn_type == DYN_LIMIT) \ - q->parent->count--; \ - DEB(printf("-- unlink entry 0x%08x %d -> 0x%08x %d, %d left\n", \ - (q->id.src_ip), (q->id.src_port), \ - (q->id.dst_ip), (q->id.dst_port), dyn_count-1 ); ) \ - if (prev != NULL) \ - prev->next = q = q->next ; \ - else \ - ipfw_dyn_v[i] = q = q->next ; \ - dyn_count-- ; \ - free(old_q, M_IPFW); } - +#define UNLINK_DYN_RULE(prev, head, q) { \ + struct ipfw_dyn_rule *old_q = q; \ + \ + /* remove a refcount to the parent */ \ + if (q->dyn_type == DYN_LIMIT) \ + q->parent->count--; \ + DEB(printf("-- unlink entry 0x%08x %d -> 0x%08x %d, %d left\n", \ + (q->id.src_ip), (q->id.src_port), \ + (q->id.dst_ip), (q->id.dst_port), dyn_count-1 ); ) \ + if (prev != NULL) \ + prev->next = q = q->next ; \ + else \ + ipfw_dyn_v[i] = q = q->next ; \ + dyn_count-- ; \ + free(old_q, M_IPFW); } #define TIME_LEQ(a,b) ((int)((a)-(b)) <= 0) /** @@ -733,8 +732,9 @@ remove_dyn_rule(struct ip_fw *rule, int force) max_pass = 1; /* we need a second pass */ if (zap == 1 && (pass == 0 || q->count != 0) ) { zap = 0 ; - if (q->count != 0) - printf("cannot remove parent, count %d\n", q->count); + if (pass == 1) /* should not happen */ + printf("OUCH! cannot remove rule, count %d\n", + q->count); } } if (zap) { @@ -775,7 +775,7 @@ lookup_dyn_rule(struct ipfw_flow_id *pkt, int *match_direction) goto next; if (TIME_LEQ( q->expire , time_second ) ) { /* expire entry */ UNLINK_DYN_RULE(prev, ipfw_dyn_v[i], q); - continue ; + continue; } if ( pkt->proto == q->id.proto) { if (pkt->src_ip == q->id.src_ip && @@ -789,8 +789,8 @@ lookup_dyn_rule(struct ipfw_flow_id *pkt, int *match_direction) pkt->dst_ip == q->id.src_ip && pkt->src_port == q->id.dst_port && pkt->dst_port == q->id.src_port ) { - dir = 0 ; /* reverse match */ - goto found ; + dir = 0 ; /* reverse match */ + goto found ; } } next: @@ -876,9 +876,9 @@ add_dyn_rule(struct ipfw_flow_id *id, u_int8_t dyn_type, struct ip_fw *rule) dyn_buckets = curr_dyn_buckets ; /* reset */ else { curr_dyn_buckets = dyn_buckets ; - if (ipfw_dyn_v != NULL) + if (ipfw_dyn_v != NULL) free(ipfw_dyn_v, M_IPFW); - ipfw_dyn_v = malloc(curr_dyn_buckets * sizeof r, + ipfw_dyn_v = malloc(curr_dyn_buckets * sizeof r, M_IPFW, M_DONTWAIT | M_ZERO); if (ipfw_dyn_v == NULL) return NULL; /* failed ! */ @@ -888,8 +888,8 @@ add_dyn_rule(struct ipfw_flow_id *id, u_int8_t dyn_type, struct ip_fw *rule) r = malloc(sizeof *r, M_IPFW, M_DONTWAIT | M_ZERO); if (r == NULL) { - printf ("sorry cannot allocate state\n"); - return NULL ; + printf ("sorry cannot allocate state\n"); + return NULL ; } /* increase refcount on parent, and set pointer */ @@ -921,7 +921,7 @@ add_dyn_rule(struct ipfw_flow_id *id, u_int8_t dyn_type, struct ip_fw *rule) } /** - * lookup dynamic parent rule using pkt and chain as search keys. + * lookup dynamic parent rule using pkt and rule as search keys. * If the lookup fails, then install one. */ static struct ipfw_dyn_rule * @@ -986,10 +986,11 @@ install_state(struct ip_fw *rule) } return 1; /* cannot install, notify caller */ } + switch (type) { case DYN_KEEP_STATE: /* bidir rule */ - add_dyn_rule(&last_pkt, DYN_KEEP_STATE, rule); - break ; + add_dyn_rule(&last_pkt, DYN_KEEP_STATE, rule); + break ; case DYN_LIMIT: /* limit number of sessions */ { u_int16_t limit_mask = rule->limit_mask ; @@ -1014,7 +1015,7 @@ install_state(struct ip_fw *rule) parent = lookup_dyn_parent(&id, rule); if (parent == NULL) { printf("add parent failed\n"); - return 1; + return 1; } if (parent->count >= conn_limit) { EXPIRE_DYN_CHAIN(rule); /* try to expire some */ @@ -1037,7 +1038,7 @@ install_state(struct ip_fw *rule) /* * given an ip_fw *, lookup_next_rule will return a pointer * of the same type to the next one. This can be either the jump - * target (for skipto instructions) or the next one in the chain (in + * target (for skipto instructions) or the next one in the list (in * all other cases including a missing jump target). * Backward jumps are not allowed, so start looking from the next * rule... @@ -1053,7 +1054,7 @@ lookup_next_rule(struct ip_fw *me) if ( (me->fw_flg & IP_FW_F_COMMAND) == IP_FW_F_SKIPTO ) for (rule = LIST_NEXT(me,next); rule ; rule = LIST_NEXT(rule,next)) if (rule->fw_number >= rulenum) - return rule ; + return rule ; return LIST_NEXT(me,next) ; /* failure or not a skipto */ } @@ -1198,7 +1199,7 @@ ip_fw_chk(struct ip **pip, int hlen, goto dropit; } else { /* - * Go down the chain, looking for enlightment. + * Go down the list, looking for enlightment. * If we've been asked to start at a given rule, do so. */ f = LIST_FIRST(&ip_fw_chain_head); @@ -1212,7 +1213,6 @@ ip_fw_chk(struct ip **pip, int hlen, } } - for (; f; f = LIST_NEXT(f, next)) { again: if (f->fw_number == IPFW_DEFAULT_RULE) @@ -1516,7 +1516,7 @@ got_match: goto again ; case IP_FW_F_PIPE: case IP_FW_F_QUEUE: - *flow_id = f; + *flow_id = f; /* XXX set flow id */ return(f->fw_pipe_nr | IP_FW_PORT_DYNT_FLAG); #ifdef IPFIREWALL_FORWARD case IP_FW_F_FWD: @@ -1608,7 +1608,7 @@ dropit: * when a rule is added/deleted, zero the direct pointers within * all firewall rules. These will be reconstructed on the fly * as packets are matched. - * Must be called at splnet(). + * Must be called at splimp(). */ static void flush_rule_ptrs() @@ -1630,7 +1630,6 @@ add_entry(struct ip_fw_head *head, struct ip_fw *rule) ftmp = malloc(sizeof *ftmp, M_IPFW, M_DONTWAIT | M_ZERO); if (!ftmp) return (ENOSPC); - bcopy(rule, ftmp, sizeof(*ftmp)); ftmp->fw_in_if.fu_via_if.name[FW_IFNLEN - 1] = '\0'; @@ -1639,7 +1638,7 @@ add_entry(struct ip_fw_head *head, struct ip_fw *rule) ftmp->next_rule_ptr = NULL ; ftmp->pipe_ptr = NULL ; - s = splnet(); + s = splimp(); if (LIST_FIRST(head) == 0) { LIST_INSERT_HEAD(head, ftmp, next); @@ -1683,11 +1682,11 @@ done: } /** - * free storage associated with a static chain entry (including + * free storage associated with a static rule entry (including * dependent dynamic rules), and zeroes rule pointers to avoid * dangling pointer dereferences. * @return a pointer to the next entry. - * Must be called at splnet() and with a non-null argument. + * Must be called at splimp() and with a non-null argument. */ static struct ip_fw * free_chain(struct ip_fw *fcp) @@ -1698,7 +1697,7 @@ free_chain(struct ip_fw *fcp) DELETE_DYN_CHAIN(fcp); LIST_REMOVE(fcp, next); static_count--; - if (ip_dn_ruledel_ptr != NULL) + if (DUMMYNET_LOADED) ip_dn_ruledel_ptr(fcp) ; flush_rule_ptrs(); /* more efficient to do outside the loop */ free(fcp, M_IPFW); @@ -1718,7 +1717,7 @@ del_entry(struct ip_fw_head *chainptr, u_short number) if (rule->fw_number == number) { int s ; - s = splnet(); /* prevent access to rules while removing */ + s = splimp(); /* prevent access to rules while removing */ while (rule && rule->fw_number == number) rule = free_chain(rule); /* XXX could move flush_rule_ptrs() here */ @@ -1746,7 +1745,7 @@ zero_entry(struct ip_fw *frwl, int log_only) char *msg ; if (frwl == 0) { - s = splnet(); + s = splimp(); LIST_FOREACH(rule, &ip_fw_chain_head, next) { if (log_only == 0) { rule->fw_bcnt = rule->fw_pcnt = 0; @@ -1756,19 +1755,18 @@ zero_entry(struct ip_fw *frwl, int log_only) } splx(s); msg = log_only ? "ipfw: All logging counts cleared.\n" : - "ipfw: Accounting cleared.\n"; + "ipfw: Accounting cleared.\n"; } else { int cleared = 0; number = frwl->fw_number ; - /* - * It's possible to insert multiple chain entries with the + * It is possible to insert multiple chain entries with the * same number, so we don't stop after finding the first * match if zeroing a specific entry. */ LIST_FOREACH(rule, &ip_fw_chain_head, next) if (number == rule->fw_number) { - s = splnet(); + s = splimp(); while (rule && number == rule->fw_number) { if (log_only == 0) { rule->fw_bcnt = rule->fw_pcnt = 0; @@ -1781,10 +1779,10 @@ zero_entry(struct ip_fw *frwl, int log_only) cleared = 1; break; } - if (!cleared) /* we didn't find any matching rules */ + if (!cleared) /* we did not find any matching rules */ return (EINVAL); msg = log_only ? "Entry %d logging count reset.\n" : - "ipfw: Entry %d cleared.\n"; + "ipfw: Entry %d cleared.\n"; } if (fw_verbose) log(LOG_SECURITY | LOG_NOTICE, msg, number); @@ -1946,7 +1944,13 @@ ip_fw_ctl(struct sockopt *sopt) switch (sopt->sopt_name) { case IP_FW_GET: - s = splnet(); + /* + * pass up a copy of the current rules. Static rules + * come first (the last of which has number 65535), + * followed by a possibly empty list of dynamic rule. + * The last dynamic rule has NULL in the "next" field. + */ + s = splimp(); /* size of static rules */ size = static_count * sizeof(struct ip_fw) ; if (ipfw_dyn_v) /* add size of dyn.rules */ @@ -1960,9 +1964,9 @@ ip_fw_ctl(struct sockopt *sopt) */ buf = malloc(size, M_TEMP, M_WAITOK); if (buf == 0) { - splx(s); - error = ENOBUFS; - break; + splx(s); + error = ENOBUFS; + break; } bp = buf ; @@ -1979,7 +1983,12 @@ ip_fw_ctl(struct sockopt *sopt) for ( p = ipfw_dyn_v[i] ; p != NULL ; p = p->next, dst++ ) { bcopy(p, dst, sizeof *p); (int)dst->rule = p->rule->fw_number ; - dst->next = dst ; /* fake non-null pointer... */ + /* + * store a non-null value in "next". The userland + * code will interpret a NULL here as a marker + * for the last dynamic rule. + */ + dst->next = dst ; last = dst ; if (TIME_LEQ(dst->expire, time_second) ) dst->expire = 0 ; @@ -1987,12 +1996,12 @@ ip_fw_ctl(struct sockopt *sopt) dst->expire -= time_second ; } if (last != NULL) - last->next = NULL ; + last->next = NULL ; /* mark last dynamic rule */ } splx(s); error = sooptcopyout(sopt, buf, size); - FREE(buf, M_TEMP); + free(buf, M_TEMP); break; case IP_FW_FLUSH: @@ -2009,7 +2018,7 @@ ip_fw_ctl(struct sockopt *sopt) * the old list without the need for a lock. */ - s = splnet(); + s = splimp(); while ( (fcp = LIST_FIRST(&ip_fw_chain_head)) && fcp->fw_number != IPFW_DEFAULT_RULE ) free_chain(fcp); @@ -2055,7 +2064,7 @@ ip_fw_ctl(struct sockopt *sopt) if (sopt->sopt_val != 0) { error = sooptcopyin(sopt, &frwl, sizeof frwl, sizeof frwl); if (error) - break ; + break; arg = &frwl ; } error = zero_entry(arg, cmd); @@ -2130,38 +2139,48 @@ ip_fw_init(void) #endif } -static ip_fw_chk_t *old_chk_ptr; -static ip_fw_ctl_t *old_ctl_ptr; - static int ipfw_modevent(module_t mod, int type, void *unused) { int s; + int err = 0 ; struct ip_fw *fcp; switch (type) { case MOD_LOAD: - s = splnet(); - - old_chk_ptr = ip_fw_chk_ptr; - old_ctl_ptr = ip_fw_ctl_ptr; - - ip_fw_init(); - splx(s); - return 0; + printf("IPFW: MOD_LOAD\n"); + s = splimp(); + if (IPFW_LOADED) { + splx(s); + printf("IP firewall already loaded\n"); + err = EEXIST ; + } else { + ip_fw_init(); + splx(s); + } + break ; case MOD_UNLOAD: - s = splnet(); - ip_fw_chk_ptr = old_chk_ptr; - ip_fw_ctl_ptr = old_ctl_ptr; + printf("IPFW: MOD_UNLOAD\n"); +#if !defined(KLD_MODULE) + printf("ipfw statically compiled, cannot unload\n"); + err = EBUSY; +#else + s = splimp(); + ip_fw_chk_ptr = NULL ; + ip_fw_ctl_ptr = NULL ; + { + struct ip_fw *fcp; while ( (fcp = LIST_FIRST(&ip_fw_chain_head)) != NULL) free_chain(fcp); + } splx(s); printf("IP firewall unloaded\n"); - return 0; +#endif + break; default: break; } - return 0; + return err; } static moduledata_t ipfwmod = { |