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
This commit is contained in:
parent
2854bb2840
commit
0fb106cc3f
@ -69,14 +69,20 @@ traffic shaper in
|
||||
Each incoming or outgoing packet is passed through the
|
||||
.Nm
|
||||
rules.
|
||||
If host is acting as a gateway, packets forwarded by
|
||||
the gateway are processed by
|
||||
The number of times a packet is processed by
|
||||
.Nm
|
||||
twice.
|
||||
In case a host is acting as a bridge, packets forwarded by
|
||||
the bridge are processed by
|
||||
varies -- basically,
|
||||
.Nm
|
||||
once.
|
||||
is invoked every time the kernel functions
|
||||
.Em ip_input() , ip_output()
|
||||
and
|
||||
.Em bdg_forward()
|
||||
are invoked.
|
||||
This means that packets are processed once for connections having
|
||||
only one endpoint on the local host, twice for connections with
|
||||
both endpoints on the local host, or for packet routed by the host
|
||||
(acting as a gateway), and once for packets bridged by the host
|
||||
(acting as a bridge).
|
||||
.Pp
|
||||
A firewall configuration is made of a list of numbered rules,
|
||||
which is scanned for each packet until a match is found and
|
||||
@ -90,8 +96,8 @@ way as to minimize the number of checks.
|
||||
.Pp
|
||||
A configuration always includes a
|
||||
.Em DEFAULT
|
||||
rule (numbered 65535) which cannot be modified by the programmer
|
||||
and always matches packets.
|
||||
rule (numbered 65535) which cannot be modified,
|
||||
and matches all packets.
|
||||
The action associated with the default rule can be either
|
||||
.Cm deny
|
||||
or
|
||||
@ -100,11 +106,13 @@ depending on how the kernel is configured.
|
||||
.Pp
|
||||
If the ruleset includes one or more rules with the
|
||||
.Cm keep-state
|
||||
or
|
||||
.Cm limit
|
||||
option, then
|
||||
.Nm
|
||||
assumes a
|
||||
.Em stateful
|
||||
behaviour, i.e. upon a match will create dynamic rules matching
|
||||
behaviour, i.e. upon a match it will create dynamic rules matching
|
||||
the exact parameters (addresses and ports) of the matching packet.
|
||||
.Pp
|
||||
These dynamic rules, which have a limited lifetime, are checked
|
||||
@ -632,7 +640,7 @@ while packets destined for the local host have no transmit
|
||||
interface.
|
||||
.It Ar options :
|
||||
.Bl -tag -width indent
|
||||
.It Cm keep-state Op Ar method
|
||||
.It Cm keep-state
|
||||
Upon a match, the firewall will create a dynamic rule, whose
|
||||
default behaviour is to matching bidirectional traffic between
|
||||
source and destination IP/port using the same protocol.
|
||||
@ -641,9 +649,11 @@ The rule has a limited lifetime (controlled by a set of
|
||||
variables), and 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.
|
||||
.It Cm limit {src-addr src-port dst-addr dst-port} N
|
||||
The firewall will only allow N connections with the same
|
||||
set of parameters as specified in the rule. One or more
|
||||
of source and destination addresses and ports can be
|
||||
specified.
|
||||
.It Cm bridged
|
||||
Matches only bridged packets.
|
||||
This can be useful for multicast or broadcast traffic, which
|
||||
@ -1118,8 +1128,10 @@ dropped.
|
||||
A set of
|
||||
.Xr sysctl 8
|
||||
variables controls the behaviour of the firewall.
|
||||
These are shown below together with their default value and
|
||||
meaning:
|
||||
These are shown below together with their default value
|
||||
(but always check with the
|
||||
.Nm sysctl
|
||||
command what value is actually in use) and meaning:
|
||||
.Bl -tag -width indent
|
||||
.It Em net.inet.ip.fw.debug : No 1
|
||||
Controls debugging messages produced by
|
||||
@ -1156,8 +1168,9 @@ When you hit this limit, no more dynamic rules can be
|
||||
installed until old ones expire.
|
||||
.It Em net.inet.ip.fw.dyn_ack_lifetime : No 300
|
||||
.It Em net.inet.ip.fw.dyn_syn_lifetime : No 20
|
||||
.It Em net.inet.ip.fw.dyn_fin_lifetime : No 20
|
||||
.It Em net.inet.ip.fw.dyn_rst_lifetime : No 5
|
||||
.It Em net.inet.ip.fw.dyn_fin_lifetime : No 1
|
||||
.It Em net.inet.ip.fw.dyn_rst_lifetime : No 1
|
||||
.It Em net.inet.ip.fw.dyn_udp_lifetime : No 5
|
||||
.It Em net.inet.ip.fw.dyn_short_lifetime : No 30
|
||||
These variables control the lifetime, in seconds, of dynamic
|
||||
rules.
|
||||
@ -1218,6 +1231,17 @@ rule should be usually placed near the beginning of the
|
||||
ruleset to minimize the amount of work scanning the ruleset.
|
||||
Your mileage may vary.
|
||||
.Pp
|
||||
To limit the number of connections a user can open
|
||||
you can use the following type of rules:
|
||||
.Pp
|
||||
.Dl "ipfw add allow tcp from my-net/24 to any setup limit src-addr 10"
|
||||
.Dl "ipfw add allow tcp from any to me setup limit src-addr 4"
|
||||
.Pp
|
||||
The former (assuming it runs on a gateway) will allow each host
|
||||
on a /24 net to open at most 10 TCP connections.
|
||||
The latter can be placed on a server to make sure that a single
|
||||
client does not use more than 4 simultaneous connections.
|
||||
.Pp
|
||||
.Em BEWARE :
|
||||
stateful rules can be subject to denial-of-service attacks
|
||||
by a SYN-flood which opens a huge number of dynamic rules.
|
||||
|
@ -168,6 +168,18 @@ print_reject_code(int code)
|
||||
printf("%u", code);
|
||||
}
|
||||
|
||||
/**
|
||||
* _s_x holds a string-int pair for various lookups.
|
||||
* s=NULL terminates the struct.
|
||||
*/
|
||||
struct _s_x { char *s; int x; };
|
||||
static struct _s_x limit_masks[] = {
|
||||
{"src-addr", DYN_SRC_ADDR},
|
||||
{"src-port", DYN_SRC_PORT},
|
||||
{"dst-addr", DYN_DST_ADDR},
|
||||
{"dst-port", DYN_DST_PORT},
|
||||
{NULL, 0} };
|
||||
|
||||
static void
|
||||
show_ipfw(struct ip_fw *chain)
|
||||
{
|
||||
@ -204,7 +216,7 @@ show_ipfw(struct ip_fw *chain)
|
||||
}
|
||||
|
||||
if (chain->fw_flg & IP_FW_F_RND_MATCH) {
|
||||
double d = 1.0 * (int)(chain->pipe_ptr);
|
||||
double d = 1.0 * chain->dont_match_prob;
|
||||
d = 1 - (d / 0x7fffffff);
|
||||
printf("prob %f ", d);
|
||||
}
|
||||
@ -373,16 +385,22 @@ show_ipfw(struct ip_fw *chain)
|
||||
}
|
||||
|
||||
if (chain->fw_flg & IP_FW_F_KEEP_S) {
|
||||
u_long x = (u_long)chain->next_rule_ptr;
|
||||
u_char type = (x) & 0xff ;
|
||||
struct _s_x *p = limit_masks;
|
||||
|
||||
switch(type) {
|
||||
switch(chain->dyn_type) {
|
||||
default:
|
||||
printf(" *** unknown type ***");
|
||||
break ;
|
||||
case DYN_KEEP_STATE:
|
||||
printf(" keep-state");
|
||||
break;
|
||||
case DYN_LIMIT:
|
||||
printf(" limit");
|
||||
for ( ; p->s != NULL ; p++)
|
||||
if (chain->limit_mask & p->x)
|
||||
printf(" %s", p->s);
|
||||
printf(" %d", chain->conn_limit);
|
||||
break ;
|
||||
}
|
||||
}
|
||||
/* Direction */
|
||||
@ -573,11 +591,17 @@ show_dyn_ipfw(struct ipfw_dyn_rule *d)
|
||||
return;
|
||||
|
||||
printf("%05d %qu %qu (T %ds, slot %d)",
|
||||
(int)(d->chain),
|
||||
(int)(d->rule),
|
||||
d->pcnt, d->bcnt,
|
||||
d->expire,
|
||||
d->bucket);
|
||||
switch (d->dyn_type) {
|
||||
case DYN_LIMIT_PARENT:
|
||||
printf(" PARENT %d", d->count);
|
||||
break;
|
||||
case DYN_LIMIT:
|
||||
printf(" LIMIT");
|
||||
break;
|
||||
case DYN_KEEP_STATE: /* bidir, no mask */
|
||||
printf(" <->");
|
||||
break;
|
||||
@ -589,17 +613,10 @@ show_dyn_ipfw(struct ipfw_dyn_rule *d)
|
||||
printf(" %u,", d->id.proto);
|
||||
|
||||
a.s_addr = htonl(d->id.src_ip);
|
||||
printf(" %s", inet_ntoa(a));
|
||||
printf(" %d", d->id.src_port);
|
||||
printf(" %si %d", inet_ntoa(a), d->id.src_port);
|
||||
|
||||
switch (d->dyn_type) {
|
||||
default: /* bidir, no mask */
|
||||
printf(" <->");
|
||||
break;
|
||||
}
|
||||
a.s_addr = htonl(d->id.dst_ip);
|
||||
printf(" %s", inet_ntoa(a));
|
||||
printf(" %d", d->id.dst_port);
|
||||
printf("<-> %s %d", inet_ntoa(a), d->id.dst_port);
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
@ -864,9 +881,9 @@ list(int ac, char *av[])
|
||||
/* already warned */
|
||||
continue;
|
||||
for (n = 0, d = dynrules; n < ndyn; n++, d++) {
|
||||
if ((int)(d->chain) > rnum)
|
||||
if ((int)(d->rule) > rnum)
|
||||
break;
|
||||
if ((int)(d->chain) == rnum)
|
||||
if ((int)(d->rule) == rnum)
|
||||
show_dyn_ipfw(d);
|
||||
}
|
||||
}
|
||||
@ -1714,8 +1731,7 @@ add(int ac, char *av[])
|
||||
errx(EX_DATAERR, "illegal match prob. %s", av[1]);
|
||||
if (d != 1) { /* 1 means always match */
|
||||
rule.fw_flg |= IP_FW_F_RND_MATCH;
|
||||
/* we really store dont_match probability */
|
||||
(long)rule.pipe_ptr = (long)((1 - d) * 0x7fffffff);
|
||||
rule.dont_match_prob = (long)((1 - d) * 0x7fffffff);
|
||||
}
|
||||
av += 2; ac -= 2;
|
||||
}
|
||||
@ -1976,13 +1992,39 @@ add(int ac, char *av[])
|
||||
} else if (!strncmp(*av, "in", strlen(*av))) {
|
||||
rule.fw_flg |= IP_FW_F_IN;
|
||||
av++; ac--;
|
||||
} else if (!strncmp(*av,"limit",strlen(*av))) {
|
||||
/* keep-state rules used to limit number of connections. */
|
||||
rule.fw_flg |= IP_FW_F_KEEP_S;
|
||||
rule.dyn_type = DYN_LIMIT ;
|
||||
rule.limit_mask = 0 ;
|
||||
av++; ac--;
|
||||
for (; ac >1 ;) {
|
||||
struct _s_x *p = limit_masks;
|
||||
int found = 0;
|
||||
for ( ; p->s != NULL ; p++)
|
||||
if (!strncmp(*av, p->s, strlen(*av))) {
|
||||
rule.limit_mask |= p->x ;
|
||||
av++; ac-- ;
|
||||
}
|
||||
if (found == 0) {
|
||||
if (rule.limit_mask == 0)
|
||||
errx(EX_USAGE, "missing limit mask");
|
||||
break ;
|
||||
}
|
||||
}
|
||||
if (ac < 1)
|
||||
errx(EX_USAGE, "limit needs mask and # of connections");
|
||||
rule.conn_limit = atoi(*av);
|
||||
if (rule.conn_limit == 0)
|
||||
errx(EX_USAGE, "limit: limit must be >0");
|
||||
av++; ac--;
|
||||
} else if (!strncmp(*av, "keep-state", strlen(*av))) {
|
||||
u_long type;
|
||||
rule.fw_flg |= IP_FW_F_KEEP_S;
|
||||
|
||||
av++; ac--;
|
||||
if (ac > 0 && (type = atoi(*av)) != 0) {
|
||||
(int)rule.next_rule_ptr = type;
|
||||
rule.dyn_type = type;
|
||||
av++; ac--;
|
||||
}
|
||||
} else if (!strncmp(*av, "bridged", strlen(*av))) {
|
||||
|
@ -616,7 +616,7 @@ bdg_forward(struct mbuf *m0, struct ether_header *const eh, struct ifnet *dst)
|
||||
int once = 0; /* loop only once */
|
||||
struct ifnet *real_dst = dst ; /* real dst from ether_output */
|
||||
#ifdef IPFIREWALL
|
||||
struct ip_fw_chain *rule = NULL ; /* did we match a firewall rule ? */
|
||||
struct ip_fw *rule = NULL ; /* did we match a firewall rule ? */
|
||||
#endif
|
||||
|
||||
/*
|
||||
@ -631,7 +631,7 @@ bdg_forward(struct mbuf *m0, struct ether_header *const eh, struct ifnet *dst)
|
||||
#if defined(IPFIREWALL) && defined(DUMMYNET)
|
||||
if (m0->m_type == MT_DUMMYNET) {
|
||||
/* extract info from dummynet header */
|
||||
rule = (struct ip_fw_chain *)(m0->m_data) ;
|
||||
rule = (struct ip_fw *)(m0->m_data) ;
|
||||
m0 = m0->m_next ;
|
||||
src = m0->m_pkthdr.rcvif;
|
||||
shared = 0 ; /* For sure this is our own mbuf. */
|
||||
|
@ -162,10 +162,10 @@ void dummynet_drain(void);
|
||||
int if_tx_rdy(struct ifnet *ifp);
|
||||
|
||||
/*
|
||||
* ip_fw_chain is used when deleting a pipe, because ipfw rules can
|
||||
* ip_fw_chain_head is used when deleting a pipe, because ipfw rules can
|
||||
* hold references to the pipe.
|
||||
*/
|
||||
extern LIST_HEAD (ip_fw_head, ip_fw_chain) ip_fw_chain_head;
|
||||
extern LIST_HEAD (ip_fw_head, ip_fw) ip_fw_chain_head;
|
||||
|
||||
static void
|
||||
rt_unref(struct rtentry *rt)
|
||||
@ -1005,11 +1005,11 @@ red_drops(struct dn_flow_set *fs, struct dn_flow_queue *q, int len)
|
||||
|
||||
static __inline
|
||||
struct dn_flow_set *
|
||||
locate_flowset(int pipe_nr, struct ip_fw_chain *rule)
|
||||
locate_flowset(int pipe_nr, struct ip_fw *rule)
|
||||
{
|
||||
struct dn_flow_set *fs = NULL ;
|
||||
|
||||
if ( (rule->rule->fw_flg & IP_FW_F_COMMAND) == IP_FW_F_QUEUE )
|
||||
if ( (rule->fw_flg & IP_FW_F_COMMAND) == IP_FW_F_QUEUE )
|
||||
for (fs=all_flow_sets; fs && fs->fs_nr != pipe_nr; fs=fs->next)
|
||||
;
|
||||
else {
|
||||
@ -1020,7 +1020,7 @@ locate_flowset(int pipe_nr, struct ip_fw_chain *rule)
|
||||
fs = &(p1->fs) ;
|
||||
}
|
||||
if (fs != NULL)
|
||||
rule->rule->pipe_ptr = fs ; /* record for the future */
|
||||
rule->pipe_ptr = fs ; /* record for the future */
|
||||
return fs ;
|
||||
}
|
||||
|
||||
@ -1032,7 +1032,7 @@ int
|
||||
dummynet_io(int pipe_nr, int dir, /* pipe_nr can also be a fs_nr */
|
||||
struct mbuf *m, struct ifnet *ifp, struct route *ro,
|
||||
struct sockaddr_in *dst,
|
||||
struct ip_fw_chain *rule, int flags)
|
||||
struct ip_fw *rule, int flags)
|
||||
{
|
||||
struct dn_pkt *pkt;
|
||||
struct dn_flow_set *fs;
|
||||
@ -1045,7 +1045,7 @@ dummynet_io(int pipe_nr, int dir, /* pipe_nr can also be a fs_nr */
|
||||
|
||||
pipe_nr &= 0xffff ;
|
||||
|
||||
if ( (fs = rule->rule->pipe_ptr) == NULL ) {
|
||||
if ( (fs = rule->pipe_ptr) == NULL ) {
|
||||
fs = locate_flowset(pipe_nr, rule);
|
||||
if (fs == NULL)
|
||||
goto dropit ; /* this queue/pipe does not exist! */
|
||||
@ -1090,7 +1090,7 @@ dummynet_io(int pipe_nr, int dir, /* pipe_nr can also be a fs_nr */
|
||||
/* ok, i can handle the pkt now... */
|
||||
/* build and enqueue packet + parameters */
|
||||
pkt->hdr.mh_type = MT_DUMMYNET ;
|
||||
(struct ip_fw_chain *)pkt->hdr.mh_data = rule ;
|
||||
(struct ip_fw *)pkt->hdr.mh_data = rule ;
|
||||
DN_NEXT(pkt) = NULL;
|
||||
pkt->dn_m = m;
|
||||
pkt->dn_dir = dir ;
|
||||
@ -1126,7 +1126,7 @@ dummynet_io(int pipe_nr, int dir, /* pipe_nr can also be a fs_nr */
|
||||
* to schedule it. This involves different actions for fixed-rate or
|
||||
* WF2Q queues.
|
||||
*/
|
||||
if ( (rule->rule->fw_flg & IP_FW_F_COMMAND) == IP_FW_F_PIPE ) {
|
||||
if ( (rule->fw_flg & IP_FW_F_COMMAND) == IP_FW_F_PIPE ) {
|
||||
/*
|
||||
* Fixed-rate queue: just insert into the ready_heap.
|
||||
*/
|
||||
@ -1276,15 +1276,15 @@ static void
|
||||
dummynet_flush()
|
||||
{
|
||||
struct dn_pipe *curr_p, *p ;
|
||||
struct ip_fw_chain *chain ;
|
||||
struct ip_fw *rule ;
|
||||
struct dn_flow_set *fs, *curr_fs;
|
||||
int s ;
|
||||
|
||||
s = splimp() ;
|
||||
|
||||
/* remove all references to pipes ...*/
|
||||
LIST_FOREACH(chain, &ip_fw_chain_head, next)
|
||||
chain->rule->pipe_ptr = NULL ;
|
||||
LIST_FOREACH(rule, &ip_fw_chain_head, next)
|
||||
rule->pipe_ptr = NULL ;
|
||||
/* prevent future matches... */
|
||||
p = all_pipes ;
|
||||
all_pipes = NULL ;
|
||||
@ -1313,7 +1313,7 @@ dummynet_flush()
|
||||
}
|
||||
|
||||
|
||||
extern struct ip_fw_chain *ip_fw_default_rule ;
|
||||
extern struct ip_fw *ip_fw_default_rule ;
|
||||
static void
|
||||
dn_rule_delete_fs(struct dn_flow_set *fs, void *r)
|
||||
{
|
||||
@ -1635,7 +1635,7 @@ static int
|
||||
delete_pipe(struct dn_pipe *p)
|
||||
{
|
||||
int s ;
|
||||
struct ip_fw_chain *chain ;
|
||||
struct ip_fw *rule ;
|
||||
|
||||
if (p->pipe_nr == 0 && p->fs.fs_nr == 0)
|
||||
return EINVAL ;
|
||||
@ -1659,9 +1659,9 @@ delete_pipe(struct dn_pipe *p)
|
||||
else
|
||||
a->next = b->next ;
|
||||
/* remove references to this pipe from the ip_fw rules. */
|
||||
LIST_FOREACH(chain, &ip_fw_chain_head, next)
|
||||
if (chain->rule->pipe_ptr == &(b->fs))
|
||||
chain->rule->pipe_ptr = NULL ;
|
||||
LIST_FOREACH(rule, &ip_fw_chain_head, next)
|
||||
if (rule->pipe_ptr == &(b->fs))
|
||||
rule->pipe_ptr = NULL ;
|
||||
|
||||
/* remove all references to this pipe from flow_sets */
|
||||
for (fs = all_flow_sets; fs; fs= fs->next )
|
||||
@ -1693,9 +1693,9 @@ delete_pipe(struct dn_pipe *p)
|
||||
else
|
||||
a->next = b->next ;
|
||||
/* remove references to this flow_set from the ip_fw rules. */
|
||||
LIST_FOREACH(chain, &ip_fw_chain_head, next)
|
||||
if (chain->rule->pipe_ptr == b)
|
||||
chain->rule->pipe_ptr = NULL ;
|
||||
LIST_FOREACH(rule, &ip_fw_chain_head, next)
|
||||
if (rule->pipe_ptr == b)
|
||||
rule->pipe_ptr = NULL ;
|
||||
|
||||
if (b->pipe != NULL) {
|
||||
/* Update total weight on parent pipe and cleanup parent heaps */
|
||||
|
@ -343,14 +343,14 @@ struct dn_pipe { /* a pipe */
|
||||
|
||||
MALLOC_DECLARE(M_IPFW);
|
||||
|
||||
typedef int ip_dn_ctl_t __P((struct sockopt *)) ;
|
||||
typedef int ip_dn_ctl_t (struct sockopt *) ;
|
||||
extern ip_dn_ctl_t *ip_dn_ctl_ptr;
|
||||
|
||||
void dn_rule_delete(void *r); /* used in ip_fw.c */
|
||||
int dummynet_io(int pipe, int dir,
|
||||
struct mbuf *m, struct ifnet *ifp, struct route *ro,
|
||||
struct sockaddr_in * dst,
|
||||
struct ip_fw_chain *rule, int flags);
|
||||
struct ip_fw *rule, int flags);
|
||||
#endif
|
||||
|
||||
#endif /* _IP_DUMMYNET_H */
|
||||
|
@ -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 @@ lookup_dyn_rule(struct ipfw_flow_id *pkt, int *match_direction)
|
||||
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 @@ ip_fw_chk(struct ip **pip, int hlen,
|
||||
(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 @@ ip_fw_chk(struct ip **pip, int hlen,
|
||||
* 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 @@ ip_fw_chk(struct ip **pip, int hlen,
|
||||
* 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 @@ ip_fw_chk(struct ip **pip, int hlen,
|
||||
}
|
||||
|
||||
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 @@ ip_fw_chk(struct ip **pip, int hlen,
|
||||
* 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 @@ ip_fw_chk(struct ip **pip, int hlen,
|
||||
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 @@ ip_fw_chk(struct ip **pip, int hlen,
|
||||
* 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 @@ ip_fw_chk(struct ip **pip, int hlen,
|
||||
}
|
||||
|
||||
/* 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 @@ ip_fw_chk(struct ip **pip, int hlen,
|
||||
* - 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 @@ ip_fw_chk(struct ip **pip, int hlen,
|
||||
}
|
||||
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 @@ ip_fw_chk(struct ip **pip, int hlen,
|
||||
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)
|
||||
ftmp = malloc(sizeof *ftmp, M_IPFW, M_DONTWAIT | M_ZERO);
|
||||
if (!ftmp)
|
||||
return (ENOSPC);
|
||||
ftmp_ext = malloc(sizeof *ftmp_ext, M_IPFW, M_DONTWAIT | M_ZERO);
|
||||
if (!ftmp_ext) {
|
||||
free(fwc, M_IPFW);
|
||||
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 @@ add_entry(struct ip_fw_head *head, struct ip_fw *rule)
|
||||
* @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:
|
||||
|
@ -50,28 +50,59 @@ union ip_fw_if {
|
||||
*/
|
||||
|
||||
struct ip_fw {
|
||||
u_int64_t fw_pcnt,fw_bcnt; /* Packet and byte counters */
|
||||
struct in_addr fw_src, fw_dst; /* Source and destination IP addr */
|
||||
struct in_addr fw_smsk, fw_dmsk; /* Mask for src and dest IP addr */
|
||||
u_short fw_number; /* Rule number */
|
||||
u_int fw_flg; /* Operational Flags word */
|
||||
#define IP_FW_MAX_PORTS 10 /* A reasonable maximum */
|
||||
union {
|
||||
u_short fw_pts[IP_FW_MAX_PORTS]; /* Array of port numbers to match */
|
||||
LIST_ENTRY(ip_fw) next; /* bidirectional list of rules */
|
||||
u_int fw_flg; /* Operational Flags word */
|
||||
|
||||
u_int64_t fw_pcnt,fw_bcnt; /* Packet and byte counters */
|
||||
struct in_addr fw_src, fw_dst; /* Source and dest. IP addr */
|
||||
struct in_addr fw_smsk, fw_dmsk; /* Mask for above addresses */
|
||||
u_short fw_number; /* Rule number */
|
||||
u_char fw_prot; /* IP protocol */
|
||||
#if 1
|
||||
u_char fw_nports; /* # of src/dst port in array */
|
||||
#define IP_FW_GETNSRCP(rule) ((rule)->fw_nports & 0x0f)
|
||||
#define IP_FW_SETNSRCP(rule, n) do { \
|
||||
(rule)->fw_nports &= ~0x0f; \
|
||||
(rule)->fw_nports |= (n); \
|
||||
} while (0)
|
||||
#define IP_FW_GETNDSTP(rule) ((rule)->fw_nports >> 4)
|
||||
#define IP_FW_SETNDSTP(rule, n) do { \
|
||||
(rule)->fw_nports &= ~0xf0; \
|
||||
(rule)->fw_nports |= (n) << 4;\
|
||||
} while (0)
|
||||
#define IP_FW_HAVEPORTS(rule) ((rule)->fw_nports != 0)
|
||||
#else
|
||||
u_char __pad[1];
|
||||
u_int _nsrcp, _ndstp;
|
||||
#define IP_FW_GETNSRCP(rule) (rule)->_nsrcp
|
||||
#define IP_FW_SETNSRCP(rule,n) (rule)->_nsrcp = n
|
||||
#define IP_FW_GETNDSTP(rule) (rule)->_ndstp
|
||||
#define IP_FW_SETNDSTP(rule,n) (rule)->_ndstp = n
|
||||
#define IP_FW_HAVEPORTS(rule) ((rule)->_ndstp + (rule)->_nsrcp != 0)
|
||||
#endif
|
||||
#define IP_FW_MAX_PORTS 10 /* A reasonable maximum */
|
||||
union {
|
||||
u_short fw_pts[IP_FW_MAX_PORTS]; /* port numbers to match */
|
||||
#define IP_FW_ICMPTYPES_MAX 128
|
||||
#define IP_FW_ICMPTYPES_DIM (IP_FW_ICMPTYPES_MAX / (sizeof(unsigned) * 8))
|
||||
unsigned fw_icmptypes[IP_FW_ICMPTYPES_DIM]; /* ICMP types bitmap */
|
||||
} fw_uar;
|
||||
u_int fw_ipflg; /* IP flags word */
|
||||
u_char fw_ipopt,fw_ipnopt; /* IP options set/unset */
|
||||
u_short fw_iplen, fw_ipid; /* IP length, identification */
|
||||
} fw_uar;
|
||||
|
||||
u_int fw_ipflg; /* IP flags word */
|
||||
|
||||
u_short fw_iplen, fw_ipid; /* IP length, identification */
|
||||
|
||||
u_char fw_ipopt,fw_ipnopt; /* IP options set/unset */
|
||||
u_char fw_iptos, fw_ipntos; /* IP type of service set/unset */
|
||||
|
||||
u_char fw_ipttl; /* IP time to live */
|
||||
u_int fw_ipver:4; /* IP version */
|
||||
u_char fw_tcpopt,fw_tcpnopt; /* TCP options set/unset */
|
||||
|
||||
u_char fw_tcpf,fw_tcpnf; /* TCP flags set/unset */
|
||||
u_int32_t fw_tcpseq, fw_tcpack; /* TCP sequence and acknowledgement */
|
||||
u_short fw_tcpwin; /* TCP window size */
|
||||
|
||||
u_int32_t fw_tcpseq, fw_tcpack; /* TCP sequence and acknowledgement */
|
||||
long timestamp; /* timestamp (tv_sec) of last match */
|
||||
union ip_fw_if fw_in_if, fw_out_if; /* Incoming and outgoing interfaces */
|
||||
union {
|
||||
@ -81,51 +112,29 @@ struct ip_fw {
|
||||
u_short fu_reject_code; /* REJECT response code */
|
||||
struct sockaddr_in fu_fwd_ip;
|
||||
} fw_un;
|
||||
u_char fw_prot; /* IP protocol */
|
||||
/*
|
||||
* N'of src ports and # of dst ports in ports array (dst ports
|
||||
* follow src ports; max of 10 ports in all; count of 0 means
|
||||
* match all ports)
|
||||
*/
|
||||
u_char fw_nports;
|
||||
void *pipe_ptr; /* flow_set ptr for dummynet pipe */
|
||||
void *next_rule_ptr ; /* next rule in case of match */
|
||||
void *pipe_ptr; /* flow_set ptr for dummynet pipe */
|
||||
void *next_rule_ptr ; /* next rule in case of match */
|
||||
uid_t fw_uid; /* uid to match */
|
||||
gid_t fw_gid; /* gid to match */
|
||||
int fw_logamount; /* amount to log */
|
||||
u_int64_t fw_loghighest; /* highest number packet to log */
|
||||
};
|
||||
|
||||
/*
|
||||
* extended ipfw structure... some fields in the original struct
|
||||
* can be used to pass parameters up/down, namely pointers
|
||||
* void *pipe_ptr
|
||||
* void *next_rule_ptr
|
||||
* some others can be used to pass parameters down, namely counters etc.
|
||||
* u_int64_t fw_pcnt,fw_bcnt;
|
||||
* long timestamp;
|
||||
*/
|
||||
|
||||
struct ip_fw_ext { /* extended structure */
|
||||
struct ip_fw rule; /* must be at offset 0 */
|
||||
long dont_match_prob; /* 0x7fffffff means 1.0, always fail */
|
||||
u_char dyn_type; /* type for dynamic rule */
|
||||
#define DYN_KEEP_STATE 0 /* type for keep-state rules */
|
||||
u_char _pad1 ; /* for future use */
|
||||
u_short _pad2 ; /* for future use */
|
||||
#define DYN_KEEP_STATE 0 /* type for keep-state rules */
|
||||
#define DYN_LIMIT 1 /* type for limit connection rules */
|
||||
#define DYN_LIMIT_PARENT 2 /* parent entry for limit connection rules */
|
||||
/* following two fields are used to limit number of connections
|
||||
* basing on either src,srcport,dst,dstport.
|
||||
*/
|
||||
u_char limit_mask ; /* mask type for limit rule, can have many */
|
||||
#define DYN_SRC_ADDR 0x1
|
||||
#define DYN_SRC_PORT 0x2
|
||||
#define DYN_DST_ADDR 0x4
|
||||
#define DYN_DST_PORT 0x8
|
||||
u_short conn_limit ; /* # of connections for limit rule */
|
||||
};
|
||||
|
||||
#define IP_FW_GETNSRCP(rule) ((rule)->fw_nports & 0x0f)
|
||||
#define IP_FW_SETNSRCP(rule, n) do { \
|
||||
(rule)->fw_nports &= ~0x0f; \
|
||||
(rule)->fw_nports |= (n); \
|
||||
} while (0)
|
||||
#define IP_FW_GETNDSTP(rule) ((rule)->fw_nports >> 4)
|
||||
#define IP_FW_SETNDSTP(rule, n) do { \
|
||||
(rule)->fw_nports &= ~0xf0; \
|
||||
(rule)->fw_nports |= (n) << 4;\
|
||||
} while (0)
|
||||
|
||||
#define fw_divert_port fw_un.fu_divert_port
|
||||
#define fw_skipto_rule fw_un.fu_skipto_rule
|
||||
#define fw_reject_code fw_un.fu_reject_code
|
||||
@ -134,21 +143,14 @@ struct ip_fw_ext { /* extended structure */
|
||||
|
||||
/**
|
||||
*
|
||||
* chain_ptr -------------+
|
||||
* rule_ptr -------------+
|
||||
* V
|
||||
* [ next.le_next ]---->[ next.le_next ]---- [ next.le_next ]--->
|
||||
* [ next.le_prev ]<----[ next.le_prev ]<----[ next.le_prev ]<---
|
||||
* +--[ rule ] +--[ rule ] +--[ rule ]
|
||||
* | | |
|
||||
* +->[ <ip_fw> ] +->[ <ip_fw> ] +->[ <ip_fw> ]
|
||||
* [ <ip_fw> body ] [ <ip_fw> body ] [ <ip_fw> body ]
|
||||
*
|
||||
*/
|
||||
|
||||
struct ip_fw_chain {
|
||||
LIST_ENTRY(ip_fw_chain) next;
|
||||
struct ip_fw *rule;
|
||||
};
|
||||
|
||||
/*
|
||||
* Flow mask/flow id for each queue.
|
||||
*/
|
||||
@ -166,7 +168,8 @@ struct ipfw_dyn_rule {
|
||||
struct ipfw_dyn_rule *next ;
|
||||
|
||||
struct ipfw_flow_id id ; /* (masked) flow id */
|
||||
struct ip_fw_chain *chain ; /* pointer to chain */
|
||||
struct ip_fw *rule ; /* pointer to rule */
|
||||
struct ipfw_dyn_rule *parent ; /* pointer to parent rule */
|
||||
u_int32_t expire ; /* expire time */
|
||||
u_int64_t pcnt, bcnt; /* match counters */
|
||||
u_int32_t bucket ; /* which bucket in hash table */
|
||||
@ -311,9 +314,9 @@ void ip_fw_init __P((void));
|
||||
/* Firewall hooks */
|
||||
struct ip;
|
||||
struct sockopt;
|
||||
typedef int ip_fw_chk_t __P((struct ip **, int, struct ifnet *, u_int16_t *,
|
||||
struct mbuf **, struct ip_fw_chain **, struct sockaddr_in **));
|
||||
typedef int ip_fw_ctl_t __P((struct sockopt *));
|
||||
typedef int ip_fw_chk_t (struct ip **, int, struct ifnet *, u_int16_t *,
|
||||
struct mbuf **, struct ip_fw **, struct sockaddr_in **);
|
||||
typedef int ip_fw_ctl_t (struct sockopt *);
|
||||
extern ip_fw_chk_t *ip_fw_chk_ptr;
|
||||
extern ip_fw_ctl_t *ip_fw_ctl_ptr;
|
||||
extern int fw_one_pass;
|
||||
|
@ -280,7 +280,7 @@ ip_input(struct mbuf *m)
|
||||
#ifdef IPDIVERT
|
||||
u_int32_t divert_info = 0; /* packet divert/tee info */
|
||||
#endif
|
||||
struct ip_fw_chain *rule = NULL;
|
||||
struct ip_fw *rule = NULL;
|
||||
#ifdef PFIL_HOOKS
|
||||
struct packet_filter_hook *pfh;
|
||||
struct mbuf *m0;
|
||||
@ -302,7 +302,7 @@ ip_input(struct mbuf *m)
|
||||
* rule.
|
||||
*/
|
||||
if (m->m_type == MT_DUMMYNET) {
|
||||
rule = (struct ip_fw_chain *)(m->m_data) ;
|
||||
rule = (struct ip_fw *)(m->m_data) ;
|
||||
m = m->m_next ;
|
||||
ip = mtod(m, struct ip *);
|
||||
hlen = IP_VHL_HL(ip->ip_vhl) << 2;
|
||||
|
@ -143,7 +143,7 @@ ip_output(m0, opt, ro, flags, imo)
|
||||
#ifdef IPFIREWALL_FORWARD
|
||||
int fwd_rewrite_src = 0;
|
||||
#endif
|
||||
struct ip_fw_chain *rule = NULL;
|
||||
struct ip_fw *rule = NULL;
|
||||
|
||||
#ifdef IPDIVERT
|
||||
/* Get and reset firewall cookie */
|
||||
@ -165,7 +165,7 @@ ip_output(m0, opt, ro, flags, imo)
|
||||
* processing was already done, and we need to go down.
|
||||
* Get parameters from the header.
|
||||
*/
|
||||
rule = (struct ip_fw_chain *)(m->m_data) ;
|
||||
rule = (struct ip_fw *)(m->m_data) ;
|
||||
opt = NULL ;
|
||||
ro = & ( ((struct dn_pkt *)m)->ro ) ;
|
||||
imo = NULL ;
|
||||
|
Loading…
Reference in New Issue
Block a user