summaryrefslogtreecommitdiffstats
path: root/sys/netinet/ip_fw.c
diff options
context:
space:
mode:
authorluigi <luigi@FreeBSD.org>2001-09-27 23:44:27 +0000
committerluigi <luigi@FreeBSD.org>2001-09-27 23:44:27 +0000
commit0fb106cc3f40524759012ac12baf28dccec9e571 (patch)
treea41a22ccd419ef5d2a0238988e2c3fae83a51ade /sys/netinet/ip_fw.c
parent2854bb2840809c802db31285bc55e9fc5e73ac20 (diff)
downloadFreeBSD-src-0fb106cc3f40524759012ac12baf28dccec9e571.zip
FreeBSD-src-0fb106cc3f40524759012ac12baf28dccec9e571.tar.gz
Two main changes here:
+ implement "limit" rules, which permit to limit the number of sessions between certain host pairs (according to masks). These are a special type of stateful rules, which might be of interest in some cases. See the ipfw manpage for details. + merge the list pointers and ipfw rule descriptors in the kernel, so the code is smaller, faster and more readable. This patch basically consists in replacing "foo->rule->bar" with "rule->bar" all over the place. I have been willing to do this for ages! MFC after: 1 week
Diffstat (limited to 'sys/netinet/ip_fw.c')
-rw-r--r--sys/netinet/ip_fw.c406
1 files changed, 242 insertions, 164 deletions
diff --git a/sys/netinet/ip_fw.c b/sys/netinet/ip_fw.c
index cb21e56..0ad3aae 100644
--- a/sys/netinet/ip_fw.c
+++ b/sys/netinet/ip_fw.c
@@ -2,7 +2,7 @@
* Copyright (c) 1993 Daniel Boulet
* Copyright (c) 1994 Ugen J.S.Antsilevich
* Copyright (c) 1996 Alex Nash
- * Copyright (c) 2000 Luigi Rizzo
+ * Copyright (c) 2000-2001 Luigi Rizzo
*
* Redistribution and use in source forms, with and without modification,
* are permitted provided that this entire comment appears intact.
@@ -92,7 +92,7 @@ struct ipfw_flow_id last_pkt ;
#define IPFW_DEFAULT_RULE ((u_int)(u_short)~0)
-LIST_HEAD (ip_fw_head, ip_fw_chain) ip_fw_chain_head;
+LIST_HEAD (ip_fw_head, ip_fw) ip_fw_chain_head;
MALLOC_DEFINE(M_IPFW, "IpFw/IpAcct", "IpFw/IpAcct chain's");
@@ -211,31 +211,30 @@ SYSCTL_INT(_net_inet_ip_fw, OID_AUTO, dyn_grace_time, CTLFLAG_RD,
} while (0)
#define SNPARGS(buf, len) buf + len, sizeof(buf) > len ? sizeof(buf) - len : 0
-static int add_entry __P((struct ip_fw_head *chainptr, struct ip_fw *frwl));
-static int del_entry __P((struct ip_fw_head *chainptr, u_short number));
-static int zero_entry __P((struct ip_fw *, int));
-static int check_ipfw_struct __P((struct ip_fw *m));
+static int add_entry (struct ip_fw_head *chainptr, struct ip_fw *frwl);
+static int del_entry (struct ip_fw_head *chainptr, u_short number);
+static int zero_entry (struct ip_fw *, int);
+static int check_ipfw_struct (struct ip_fw *m);
+static int iface_match (struct ifnet *ifp, union ip_fw_if *ifu,
+ int byname);
+static int ipopts_match (struct ip *ip, struct ip_fw *f);
+static int iptos_match (struct ip *ip, struct ip_fw *f);
static __inline int
- iface_match __P((struct ifnet *ifp, union ip_fw_if *ifu,
- int byname));
-static int ipopts_match __P((struct ip *ip, struct ip_fw *f));
-static int iptos_match __P((struct ip *ip, struct ip_fw *f));
-static __inline int
- port_match __P((u_short *portptr, int nports, u_short port,
- int range_flag, int mask));
-static int tcpflg_match __P((struct tcphdr *tcp, struct ip_fw *f));
-static int icmptype_match __P((struct icmp * icmp, struct ip_fw * f));
-static void ipfw_report __P((struct ip_fw *f, struct ip *ip, int offset,
+ port_match (u_short *portptr, int nports, u_short port,
+ int range_flag, int mask);
+static int tcpflg_match (struct tcphdr *tcp, struct ip_fw *f);
+static int icmptype_match (struct icmp * icmp, struct ip_fw * f);
+static void ipfw_report (struct ip_fw *f, struct ip *ip, int offset,
int ip_len, struct ifnet *rif,
- struct ifnet *oif));
+ struct ifnet *oif);
static void flush_rule_ptrs(void);
-static int ip_fw_chk __P((struct ip **pip, int hlen,
+static int ip_fw_chk (struct ip **pip, int hlen,
struct ifnet *oif, u_int16_t *cookie, struct mbuf **m,
- struct ip_fw_chain **flow_id,
- struct sockaddr_in **next_hop));
-static int ip_fw_ctl __P((struct sockopt *sopt));
+ struct ip_fw **flow_id,
+ struct sockaddr_in **next_hop);
+static int ip_fw_ctl (struct sockopt *sopt);
static char err_prefix[] = "ip_fw_ctl:";
@@ -254,17 +253,14 @@ port_match(u_short *portptr, int nports, u_short port, int range_flag, int mask)
portptr += 2;
}
if (range_flag) {
- if (portptr[0] <= port && port <= portptr[1]) {
+ if (portptr[0] <= port && port <= portptr[1])
return 1;
- }
nports -= 2;
portptr += 2;
}
- while (nports-- > 0) {
- if (*portptr++ == port) {
+ while (nports-- > 0)
+ if (*portptr++ == port)
return 1;
- }
- }
return 0;
}
@@ -481,7 +477,7 @@ tcpopts_match(struct tcphdr *tcp, struct ip_fw *f)
return 0;
}
-static __inline int
+static int
iface_match(struct ifnet *ifp, union ip_fw_if *ifu, int byname)
{
/* Check by name or by IP address */
@@ -683,7 +679,10 @@ hash_packet(struct ipfw_flow_id *id)
#define UNLINK_DYN_RULE(prev, head, q) { \
struct ipfw_dyn_rule *old_q = q; \
\
- DEB(printf("-- unlink 0x%08x %d -> 0x%08x %d, %d left\n", \
+ /* 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) \
@@ -696,15 +695,15 @@ hash_packet(struct ipfw_flow_id *id)
#define TIME_LEQ(a,b) ((int)((a)-(b)) <= 0)
/**
- * Remove all dynamic rules pointing to a given chain, or all
- * rules if chain == NULL. Second parameter is 1 if we want to
+ * Remove all dynamic rules pointing to a given rule, or all
+ * rules if rule == NULL. Second parameter is 1 if we want to
* delete unconditionally, otherwise only expired rules are removed.
*/
static void
-remove_dyn_rule(struct ip_fw_chain *chain, int force)
+remove_dyn_rule(struct ip_fw *rule, int force)
{
struct ipfw_dyn_rule *prev, *q;
- int i ;
+ int i, pass, max_pass ;
static u_int32_t last_remove = 0 ;
if (ipfw_dyn_v == NULL || dyn_count == 0)
@@ -714,18 +713,32 @@ remove_dyn_rule(struct ip_fw_chain *chain, int force)
return ;
last_remove = time_second ;
+ /*
+ * because DYN_LIMIT refer to parent rules, during the first pass only
+ * remove child and mark any pending LIMIT_PARENT, and remove
+ * them in a second pass.
+ */
+ for (pass = max_pass = 0; pass <= max_pass ; pass++ ) {
for (i = 0 ; i < curr_dyn_buckets ; i++) {
for (prev=NULL, q = ipfw_dyn_v[i] ; q ; ) {
/*
* logic can become complex here, so we split tests.
- * First, test if we match any chain,
+ * First, test if we match any rule,
* then make sure the rule is expired or we want to kill it,
* and possibly more in the future.
*/
- int zap = ( chain == NULL || chain == q->chain);
+ 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 (q->count != 0)
+ printf("cannot remove parent, count %d\n", q->count);
+ }
+ }
if (zap) {
UNLINK_DYN_RULE(prev, ipfw_dyn_v[i], q);
} else {
@@ -734,11 +747,12 @@ remove_dyn_rule(struct ip_fw_chain *chain, int force)
}
}
}
+ }
}
-#define EXPIRE_DYN_CHAIN(chain) remove_dyn_rule(chain, 0 /* expired ones */)
+#define EXPIRE_DYN_CHAIN(rule) remove_dyn_rule(rule, 0 /* expired ones */)
#define EXPIRE_DYN_CHAINS() remove_dyn_rule(NULL, 0 /* expired ones */)
-#define DELETE_DYN_CHAIN(chain) remove_dyn_rule(chain, 1 /* force removal */)
+#define DELETE_DYN_CHAIN(rule) remove_dyn_rule(rule, 1 /* force removal */)
#define DELETE_DYN_CHAINS() remove_dyn_rule(NULL, 1 /* force removal */)
/**
@@ -759,9 +773,11 @@ lookup_dyn_rule(struct ipfw_flow_id *pkt, int *match_direction)
return NULL ;
i = hash_packet( pkt );
for (prev=NULL, q = ipfw_dyn_v[i] ; q != NULL ; ) {
- if (TIME_LEQ( q->expire , time_second ) ) { /* expire entry */
- UNLINK_DYN_RULE(prev, ipfw_dyn_v[i], q);
- continue ;
+ if (q->dyn_type == DYN_LIMIT_PARENT)
+ goto next;
+ if (TIME_LEQ( q->expire , time_second ) ) { /* expire entry */
+ UNLINK_DYN_RULE(prev, ipfw_dyn_v[i], q);
+ continue ;
}
if ( pkt->proto == q->id.proto) {
if (pkt->src_ip == q->id.src_ip &&
@@ -779,6 +795,7 @@ lookup_dyn_rule(struct ipfw_flow_id *pkt, int *match_direction)
goto found ;
}
}
+next:
prev = q ;
q = q->next ;
}
@@ -834,13 +851,19 @@ found:
return q ;
}
-/*
- * Install state for a dynamic session.
+/**
+ * Install state of type 'type' for a dynamic session.
+ * The hash table contains two type of rules:
+ * - regular rules (DYN_KEEP_STATE)
+ * - rules for sessions with limited number of sess per user
+ * (DYN_LIMIT). When they are created, the parent is
+ * increased by 1, and decreased on delete. In this case,
+ * the third parameter is the parent rule and not the chain.
+ * - "parent" rules for the above (DYN_LIMIT_PARENT).
*/
static struct ipfw_dyn_rule *
-add_dyn_rule(struct ipfw_flow_id *id, u_int8_t dyn_type,
- struct ip_fw_chain *chain)
+add_dyn_rule(struct ipfw_flow_id *id, u_int8_t dyn_type, struct ip_fw *rule)
{
struct ipfw_dyn_rule *r ;
@@ -871,40 +894,79 @@ add_dyn_rule(struct ipfw_flow_id *id, u_int8_t dyn_type,
return NULL ;
}
+ /* increase refcount on parent, and set pointer */
+ if (dyn_type == DYN_LIMIT) {
+ struct ipfw_dyn_rule *parent = (struct ipfw_dyn_rule *)rule;
+ if ( parent->dyn_type != DYN_LIMIT_PARENT)
+ panic("invalid parent");
+ parent->count++ ;
+ r->parent = parent ;
+ rule = parent->rule;
+ }
+
r->id = *id ;
r->expire = time_second + dyn_syn_lifetime ;
- r->chain = chain ;
+ r->rule = rule ;
r->dyn_type = dyn_type ;
r->pcnt = r->bcnt = 0 ;
+ r->count = 0 ;
r->bucket = i ;
r->next = ipfw_dyn_v[i] ;
ipfw_dyn_v[i] = r ;
dyn_count++ ;
- DEB(printf("-- add entry 0x%08x %d -> 0x%08x %d, %d left\n",
+ 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 ); )
return r;
}
+/**
+ * lookup dynamic parent rule using pkt and chain as search keys.
+ * If the lookup fails, then install one.
+ */
+static struct ipfw_dyn_rule *
+lookup_dyn_parent(struct ipfw_flow_id *pkt, struct ip_fw *rule)
+{
+ struct ipfw_dyn_rule *q;
+ int i;
+
+ if (ipfw_dyn_v) {
+ i = hash_packet( pkt );
+ for (q = ipfw_dyn_v[i] ; q != NULL ; q=q->next)
+ if (q->dyn_type == DYN_LIMIT_PARENT && rule == q->rule &&
+ pkt->proto == q->id.proto &&
+ pkt->src_ip == q->id.src_ip &&
+ pkt->dst_ip == q->id.dst_ip &&
+ pkt->src_port == q->id.src_port &&
+ pkt->dst_port == q->id.dst_port) {
+ q->expire = time_second + dyn_short_lifetime ;
+ DEB(printf("lookup_dyn_parent found 0x%p\n", q);)
+ return q;
+ }
+ }
+ return add_dyn_rule(pkt, DYN_LIMIT_PARENT, rule);
+}
+
/*
* Install dynamic state.
* There are different types of dynamic rules which can be installed.
- * The type is in chain->dyn_type.
+ * The type is in rule->dyn_type.
* Type 0 (default) is a bidirectional rule
*
- * Returns 1 (failure) if state is not installed.
+ * Returns 1 (failure) if state is not installed because of errors or because
+ * session limitations are enforced.
*/
static int
-install_state(struct ip_fw_chain *chain)
+install_state(struct ip_fw *rule)
{
struct ipfw_dyn_rule *q ;
static int last_log ;
- u_int8_t type = ((struct ip_fw_ext *)chain->rule)->dyn_type ;
+ u_int8_t type = rule->dyn_type ;
- DEB(printf("-- install state type %d 0x%08lx %u -> 0x%08lx %u\n",
+ DEB(printf("-- install state type %d 0x%08x %u -> 0x%08x %u\n",
type,
(last_pkt.src_ip), (last_pkt.src_port),
(last_pkt.dst_ip), (last_pkt.dst_port) );)
@@ -927,34 +989,73 @@ install_state(struct ip_fw_chain *chain)
return 1; /* cannot install, notify caller */
}
switch (type) {
- default: /* bidir rule */
- add_dyn_rule(&last_pkt, DYN_KEEP_STATE, chain);
- break ;
+ case DYN_KEEP_STATE: /* bidir rule */
+ 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 ;
+ u_int16_t conn_limit = rule->conn_limit ;
+ struct ipfw_flow_id id;
+ struct ipfw_dyn_rule *parent;
+
+ DEB(printf("installing dyn-limit rule %d\n", conn_limit);)
+
+ id.dst_ip = id.src_ip = 0;
+ id.dst_port = id.src_port = 0 ;
+ id.proto = last_pkt.proto ;
+
+ if (limit_mask & DYN_SRC_ADDR)
+ id.src_ip = last_pkt.src_ip;
+ if (limit_mask & DYN_DST_ADDR)
+ id.dst_ip = last_pkt.dst_ip;
+ if (limit_mask & DYN_SRC_PORT)
+ id.src_port = last_pkt.src_port;
+ if (limit_mask & DYN_DST_PORT)
+ id.dst_port = last_pkt.dst_port;
+ parent = lookup_dyn_parent(&id, rule);
+ if (parent == NULL) {
+ printf("add parent failed\n");
+ return 1;
+ }
+ if (parent->count >= conn_limit) {
+ EXPIRE_DYN_CHAIN(rule); /* try to expire some */
+ if (parent->count >= conn_limit) {
+ printf("drop session, too many entries\n");
+ return 1;
+ }
+ }
+ add_dyn_rule(&last_pkt, DYN_LIMIT, (struct ip_fw *)parent);
+ }
+ break ;
+ default:
+ printf("unknown dynamic rule type %u\n", type);
+ return 1 ;
}
lookup_dyn_rule(&last_pkt, NULL) ; /* XXX just set the lifetime */
return 0;
}
/*
- * given an ip_fw_chain *, lookup_next_rule will return a pointer
+ * 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
* all other cases including a missing jump target).
* Backward jumps are not allowed, so start looking from the next
* rule...
*/
-static struct ip_fw_chain * lookup_next_rule(struct ip_fw_chain *me);
+static struct ip_fw * lookup_next_rule(struct ip_fw *me);
-static struct ip_fw_chain *
-lookup_next_rule(struct ip_fw_chain *me)
+static struct ip_fw *
+lookup_next_rule(struct ip_fw *me)
{
- struct ip_fw_chain *chain ;
- int rule = me->rule->fw_skipto_rule ; /* guess... */
+ struct ip_fw *rule ;
+ int rulenum = me->fw_skipto_rule ; /* guess... */
- if ( (me->rule->fw_flg & IP_FW_F_COMMAND) == IP_FW_F_SKIPTO )
- for (chain = LIST_NEXT(me,next); chain ; chain = LIST_NEXT(chain,next))
- if (chain->rule->fw_number >= rule)
- return chain ;
+ 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 LIST_NEXT(me,next) ; /* failure or not a skipto */
}
@@ -989,14 +1090,14 @@ lookup_next_rule(struct ip_fw_chain *me)
static int
ip_fw_chk(struct ip **pip, int hlen,
struct ifnet *oif, u_int16_t *cookie, struct mbuf **m,
- struct ip_fw_chain **flow_id,
+ struct ip_fw **flow_id,
struct sockaddr_in **next_hop)
{
- struct ip_fw_chain *chain;
- struct ip_fw *f = NULL, *rule = NULL;
+ struct ip_fw *f = NULL; /* matching rule */
struct ip *ip = *pip;
struct ifnet *const rif = (*m)->m_pkthdr.rcvif;
struct ifnet *tif;
+
u_short offset = 0 ;
u_short src_port = 0, dst_port = 0;
struct in_addr src_ip, dst_ip; /* XXX */
@@ -1085,38 +1186,37 @@ ip_fw_chk(struct ip **pip, int hlen,
last_pkt.flags = flags;
if (*flow_id) {
- /*
- * Packet has already been tagged. Look for the next rule
- * to restart processing.
- */
- if (fw_one_pass) /* just accept if fw_one_pass is set */
- return 0;
+ /*
+ * Packet has already been tagged. Look for the next rule
+ * to restart processing.
+ */
+ if (fw_one_pass) /* just accept if fw_one_pass is set */
+ return 0;
- if ((chain = (*flow_id)->rule->next_rule_ptr) == NULL)
- chain = (*flow_id)->rule->next_rule_ptr =
- lookup_next_rule(*flow_id);
- if (chain == NULL)
- goto dropit;
+ f = (*flow_id)->next_rule_ptr ;
+ if (f == NULL)
+ f = (*flow_id)->next_rule_ptr = lookup_next_rule(*flow_id);
+ if (f == NULL)
+ goto dropit;
} else {
- /*
- * Go down the chain, looking for enlightment.
- * If we've been asked to start at a given rule, do so.
- */
- chain = LIST_FIRST(&ip_fw_chain_head);
- if (skipto != 0) {
- if (skipto >= IPFW_DEFAULT_RULE)
- goto dropit;
- while (chain && chain->rule->fw_number <= skipto)
- chain = LIST_NEXT(chain, next);
- if (chain == NULL)
- goto dropit;
- }
+ /*
+ * Go down the chain, looking for enlightment.
+ * If we've been asked to start at a given rule, do so.
+ */
+ f = LIST_FIRST(&ip_fw_chain_head);
+ if (skipto != 0) {
+ if (skipto >= IPFW_DEFAULT_RULE)
+ goto dropit;
+ while (f && f->fw_number <= skipto)
+ f = LIST_NEXT(f, next);
+ if (f == NULL)
+ goto dropit;
+ }
}
- for (; chain; chain = LIST_NEXT(chain, next)) {
+ for (; f; f = LIST_NEXT(f, next)) {
again:
- f = chain->rule;
if (f->fw_number == IPFW_DEFAULT_RULE)
goto got_match ;
@@ -1133,8 +1233,7 @@ again:
(q->id.src_ip), (q->id.src_port),
(direction == MATCH_FORWARD ? "-->" : "<--"),
(q->id.dst_ip), (q->id.dst_port) ); )
- chain = q->chain ;
- f = chain->rule ;
+ f = q->rule ;
q->pcnt++ ;
q->bcnt += ip_len;
goto got_match ; /* random not allowed here */
@@ -1308,7 +1407,7 @@ again:
* packet -- if this rule specified either one,
* we consider the rule a non-match.
*/
- if (f->fw_nports != 0 ||
+ if (IP_FW_HAVEPORTS(f) != 0 ||
f->fw_ipflg & IP_FW_IF_TCPMSK)
continue;
@@ -1338,7 +1437,7 @@ again:
* rule specifies a port, we consider the rule
* a non-match.
*/
- if (f->fw_nports != 0)
+ if (IP_FW_HAVEPORTS(f) )
continue;
break;
@@ -1379,8 +1478,7 @@ bogusfrag:
}
rnd_then_got_match:
- if ( ((struct ip_fw_ext *)f)->dont_match_prob &&
- random() < ((struct ip_fw_ext *)f)->dont_match_prob )
+ if ( f->dont_match_prob && random() < f->dont_match_prob )
continue ;
got_match:
/*
@@ -1388,7 +1486,7 @@ got_match:
* a new dynamic entry.
*/
if (q == NULL && f->fw_flg & IP_FW_F_KEEP_S) {
- if (install_state(chain)) /* error or limit violation */
+ if (install_state(f)) /* error or limit violation */
goto dropit;
}
/* Update statistics */
@@ -1415,15 +1513,15 @@ got_match:
return(f->fw_divert_port | IP_FW_PORT_TEE_FLAG);
#endif
case IP_FW_F_SKIPTO: /* XXX check */
- chain = f->next_rule_ptr ? f->next_rule_ptr :
- lookup_next_rule(chain) ;
- if (! chain)
+ f = f->next_rule_ptr ? f->next_rule_ptr :
+ lookup_next_rule(f) ;
+ if (!f)
goto dropit;
goto again ;
#ifdef DUMMYNET
case IP_FW_F_PIPE:
case IP_FW_F_QUEUE:
- *flow_id = chain;
+ *flow_id = f;
return(f->fw_pipe_nr | IP_FW_PORT_DYNT_FLAG);
#endif
#ifdef IPFIREWALL_FORWARD
@@ -1437,6 +1535,9 @@ got_match:
* ip_output.c. We hope to high [name the abode of
* your favourite deity] that ip_output doesn't modify
* the new value of next_hop (which is dst there)
+ * XXX warning-- there is a dangerous reference here
+ * from next_hop to a field within the rule. If the
+ * rule is deleted, weird things might occur.
*/
if (next_hop != NULL /* Make sure, first... */
&& (q == NULL || direction == MATCH_FORWARD) )
@@ -1446,13 +1547,11 @@ got_match:
}
/* Deny/reject this packet using this rule */
- rule = f;
break;
-
}
/* Rule IPFW_DEFAULT_RULE should always be there and match */
- KASSERT(chain != NULL, ("ip_fw: no chain"));
+ KASSERT(f != NULL, ("ip_fw: no chain"));
/*
* At this point, we're going to drop the packet.
@@ -1462,11 +1561,11 @@ got_match:
* - The packet is not an ICMP packet, or is an ICMP query packet
* - The packet is not a multicast or broadcast packet
*/
- if ((rule->fw_flg & IP_FW_F_COMMAND) == IP_FW_F_REJECT
+ if ((f->fw_flg & IP_FW_F_COMMAND) == IP_FW_F_REJECT
&& (proto != IPPROTO_ICMP || is_icmp_query(ip))
&& !((*m)->m_flags & (M_BCAST|M_MCAST))
&& !IN_MULTICAST(ntohl(ip->ip_dst.s_addr))) {
- switch (rule->fw_reject_code) {
+ switch (f->fw_reject_code) {
case IP_FW_REJECT_RST:
{
/* XXX warning, this code writes into the mbuf */
@@ -1497,7 +1596,7 @@ got_match:
}
default: /* Send an ICMP unreachable using code */
icmp_error(*m, ICMP_UNREACH,
- rule->fw_reject_code, 0L, 0);
+ f->fw_reject_code, 0L, 0);
*m = NULL;
break;
}
@@ -1520,39 +1619,25 @@ dropit:
static void
flush_rule_ptrs()
{
- struct ip_fw_chain *fcp ;
+ struct ip_fw *fcp ;
LIST_FOREACH(fcp, &ip_fw_chain_head, next) {
- fcp->rule->next_rule_ptr = NULL ;
+ fcp->next_rule_ptr = NULL ;
}
}
static int
add_entry(struct ip_fw_head *head, struct ip_fw *rule)
{
- struct ip_fw *ftmp = 0;
- struct ip_fw_ext *ftmp_ext = 0 ;
- struct ip_fw_chain *fwc, *fcp, *fcpl;
+ struct ip_fw *ftmp, *fcp, *fcpl;
u_short nbr = 0;
int s;
- fwc = malloc(sizeof *fwc, M_IPFW, M_DONTWAIT);
- if (!fwc)
- return (ENOSPC);
- ftmp_ext = malloc(sizeof *ftmp_ext, M_IPFW, M_DONTWAIT | M_ZERO);
- if (!ftmp_ext) {
- free(fwc, M_IPFW);
+ ftmp = malloc(sizeof *ftmp, M_IPFW, M_DONTWAIT | M_ZERO);
+ if (!ftmp)
return (ENOSPC);
- }
- fwc->rule = ftmp = &ftmp_ext->rule ;
bcopy(rule, ftmp, sizeof(*ftmp));
- if (ftmp->fw_flg & IP_FW_F_RND_MATCH)
- ftmp_ext->dont_match_prob = (intptr_t)ftmp->pipe_ptr;
- if (ftmp->fw_flg & IP_FW_F_KEEP_S) {
- u_long type = (u_long)(ftmp->next_rule_ptr) ;
- ftmp_ext->dyn_type = type & 0xff;
- }
ftmp->fw_in_if.fu_via_if.name[FW_IFNLEN - 1] = '\0';
ftmp->fw_pcnt = 0L;
@@ -1563,15 +1648,15 @@ add_entry(struct ip_fw_head *head, struct ip_fw *rule)
s = splnet();
if (LIST_FIRST(head) == 0) {
- LIST_INSERT_HEAD(head, fwc, next);
+ LIST_INSERT_HEAD(head, ftmp, next);
goto done;
}
/* If entry number is 0, find highest numbered rule and add 100 */
if (ftmp->fw_number == 0) {
- LIST_FOREACH(fcp, head, next) {
- if (fcp->rule->fw_number != IPFW_DEFAULT_RULE)
- nbr = fcp->rule->fw_number;
+ LIST_FOREACH(ftmp, head, next) {
+ if (ftmp->fw_number != IPFW_DEFAULT_RULE)
+ nbr = ftmp->fw_number;
else
break;
}
@@ -1583,11 +1668,11 @@ add_entry(struct ip_fw_head *head, struct ip_fw *rule)
/* Got a valid number; now insert it, keeping the list ordered */
fcpl = NULL ;
LIST_FOREACH(fcp, head, next) {
- if (fcp->rule->fw_number > ftmp->fw_number) {
+ if (fcp->fw_number > ftmp->fw_number) {
if (fcpl) {
- LIST_INSERT_AFTER(fcpl, fwc, next);
+ LIST_INSERT_AFTER(fcpl, ftmp, next);
} else {
- LIST_INSERT_HEAD(head, fwc, next);
+ LIST_INSERT_HEAD(head, ftmp, next);
}
break;
} else {
@@ -1610,10 +1695,10 @@ done:
* @return a pointer to the next entry.
* Must be called at splnet() and with a non-null argument.
*/
-static struct ip_fw_chain *
-free_chain(struct ip_fw_chain *fcp)
+static struct ip_fw *
+free_chain(struct ip_fw *fcp)
{
- struct ip_fw_chain *n;
+ struct ip_fw *n;
n = LIST_NEXT(fcp, next);
DELETE_DYN_CHAIN(fcp);
@@ -1623,7 +1708,6 @@ free_chain(struct ip_fw_chain *fcp)
dn_rule_delete(fcp) ;
#endif
flush_rule_ptrs(); /* more efficient to do outside the loop */
- free(fcp->rule, M_IPFW);
free(fcp, M_IPFW);
return n;
}
@@ -1634,16 +1718,16 @@ free_chain(struct ip_fw_chain *fcp)
static int
del_entry(struct ip_fw_head *chainptr, u_short number)
{
- struct ip_fw_chain *fcp;
+ struct ip_fw *rule;
if (number != IPFW_DEFAULT_RULE) {
- LIST_FOREACH(fcp, chainptr, next) {
- if (fcp->rule->fw_number == number) {
+ LIST_FOREACH(rule, chainptr, next) {
+ if (rule->fw_number == number) {
int s ;
s = splnet(); /* prevent access to rules while removing */
- while (fcp && fcp->rule->fw_number == number)
- fcp = free_chain(fcp);
+ while (rule && rule->fw_number == number)
+ rule = free_chain(rule);
/* XXX could move flush_rule_ptrs() here */
splx(s);
return 0 ;
@@ -1663,7 +1747,6 @@ del_entry(struct ip_fw_head *chainptr, u_short number)
static int
zero_entry(struct ip_fw *frwl, int log_only)
{
- struct ip_fw_chain *fcp;
struct ip_fw *rule;
int s;
u_short number = 0 ;
@@ -1671,8 +1754,7 @@ zero_entry(struct ip_fw *frwl, int log_only)
if (frwl == 0) {
s = splnet();
- LIST_FOREACH(fcp, &ip_fw_chain_head, next) {
- rule = fcp->rule;
+ LIST_FOREACH(rule, &ip_fw_chain_head, next) {
if (log_only == 0) {
rule->fw_bcnt = rule->fw_pcnt = 0;
rule->timestamp = 0;
@@ -1691,16 +1773,16 @@ zero_entry(struct ip_fw *frwl, int log_only)
* same number, so we don't stop after finding the first
* match if zeroing a specific entry.
*/
- LIST_FOREACH(fcp, &ip_fw_chain_head, next)
- if (number == fcp->rule->fw_number) {
+ LIST_FOREACH(rule, &ip_fw_chain_head, next)
+ if (number == rule->fw_number) {
s = splnet();
- while (fcp && number == (rule=fcp->rule)->fw_number) {
+ while (rule && number == rule->fw_number) {
if (log_only == 0) {
rule->fw_bcnt = rule->fw_pcnt = 0;
rule->timestamp = 0;
}
rule->fw_loghighest = rule->fw_pcnt+ rule->fw_logamount;
- fcp = LIST_NEXT(fcp, next);
+ rule = LIST_NEXT(rule, next);
}
splx(s);
cleared = 1;
@@ -1791,7 +1873,7 @@ check_ipfw_struct(struct ip_fw *frwl)
if ((frwl->fw_flg & IP_FW_F_FRAG) &&
(frwl->fw_prot == IPPROTO_UDP || frwl->fw_prot == IPPROTO_TCP)) {
- if (frwl->fw_nports) {
+ if (IP_FW_HAVEPORTS(frwl)) {
dprintf(("%s cannot mix 'frag' and ports\n", err_prefix));
return (EINVAL);
}
@@ -1857,7 +1939,7 @@ ip_fw_ctl(struct sockopt *sopt)
{
int error, s;
size_t size;
- struct ip_fw_chain *fcp;
+ struct ip_fw *fcp;
struct ip_fw frwl, *bp , *buf;
/*
@@ -1896,11 +1978,7 @@ ip_fw_ctl(struct sockopt *sopt)
bp = buf ;
LIST_FOREACH(fcp, &ip_fw_chain_head, next) {
- struct ip_fw_ext *e = (struct ip_fw_ext *)fcp->rule;
-
- bcopy(e, bp, sizeof *fcp->rule);
- bp->pipe_ptr = (void *)(intptr_t) e->dont_match_prob;
- bp->next_rule_ptr = (void *)(intptr_t) (e->dyn_type);
+ bcopy(fcp, bp, sizeof *fcp);
bp++;
}
if (ipfw_dyn_v) {
@@ -1911,7 +1989,7 @@ ip_fw_ctl(struct sockopt *sopt)
for (i = 0 ; i < curr_dyn_buckets ; i++ )
for ( p = ipfw_dyn_v[i] ; p != NULL ; p = p->next, dst++ ) {
bcopy(p, dst, sizeof *p);
- (int)dst->chain = p->chain->rule->fw_number ;
+ (int)dst->rule = p->rule->fw_number ;
dst->next = dst ; /* fake non-null pointer... */
last = dst ;
if (TIME_LEQ(dst->expire, time_second) )
@@ -1944,7 +2022,7 @@ ip_fw_ctl(struct sockopt *sopt)
s = splnet();
while ( (fcp = LIST_FIRST(&ip_fw_chain_head)) &&
- fcp->rule->fw_number != IPFW_DEFAULT_RULE )
+ fcp->fw_number != IPFW_DEFAULT_RULE )
free_chain(fcp);
splx(s);
break;
@@ -2011,7 +2089,7 @@ ip_fw_ctl(struct sockopt *sopt)
* NULL pointer, but this way we do not need to check for the special
* case, plus here he have info on the default behaviour.
*/
-struct ip_fw_chain *ip_fw_default_rule ;
+struct ip_fw *ip_fw_default_rule ;
void
ip_fw_init(void)
@@ -2070,7 +2148,7 @@ static int
ipfw_modevent(module_t mod, int type, void *unused)
{
int s;
- struct ip_fw_chain *fcp;
+ struct ip_fw *fcp;
switch (type) {
case MOD_LOAD:
OpenPOWER on IntegriCloud