Implement probabilistic rule match in ipfw. Each rule can be associated

with a match probability to achieve non-deterministic behaviour of
the firewall. This can be extremely useful for testing purposes
such as simulating random packet drop without having to use dummynet
(which already does the same thing), and simulating multipath effects
and the associated out-of-order delivery (this time in conjunction
with dummynet).

The overhead on normal rules is just one comparison with 0.

Since it would have been trivial to implement this by just adding
a field to the ip_fw structure, I decided to do it in a
backward-compatible way (i.e. struct ip_fw is unchanged, and as a
consequence you don't need to recompile ipfw if you don't want to
use this feature), since this was also useful for -STABLE.

When, at some point, someone decides to change struct ip_fw, please
add a length field and a version number at the beginning, so userland
apps can keep working even if they are out of sync with the kernel.
This commit is contained in:
Luigi Rizzo 1999-08-11 15:34:47 +00:00
parent 706aa7f870
commit 772759420f
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=49630
2 changed files with 38 additions and 9 deletions

View File

@ -12,7 +12,7 @@
*
* This software is provided ``AS IS'' without any warranties of any kind.
*
* $Id: ip_fw.c,v 1.115 1999/07/28 22:27:27 green Exp $
* $Id: ip_fw.c,v 1.116 1999/08/01 16:57:15 green Exp $
*/
/*
@ -626,7 +626,7 @@ non_ip: ip = NULL ;
/* Check protocol; if wildcard, and no [ug]id, match */
if (f->fw_prot == IPPROTO_IP) {
if (!(f->fw_flg & (IP_FW_F_UID|IP_FW_F_GID)))
goto got_match;
goto rnd_then_got_match;
} else
/* If different, don't match */
if (ip->ip_p != f->fw_prot)
@ -812,6 +812,10 @@ non_ip: ip = NULL ;
goto dropit;
}
rnd_then_got_match:
if ( ((struct ip_fw_ext *)f)->dont_match_prob &&
random() < ((struct ip_fw_ext *)f)->dont_match_prob )
continue ;
got_match:
*flow_id = chain ; /* XXX set flow id */
/* Update statistics */
@ -967,12 +971,14 @@ static int
add_entry(struct ip_fw_head *chainptr, struct ip_fw *frwl)
{
struct ip_fw *ftmp = 0;
struct ip_fw_ext *ftmp_ext = 0 ;
struct ip_fw_chain *fwc = 0, *fcp, *fcpl = 0;
u_short nbr = 0;
int s;
fwc = malloc(sizeof *fwc, M_IPFW, M_DONTWAIT);
ftmp = malloc(sizeof *ftmp, M_IPFW, M_DONTWAIT);
ftmp_ext = malloc(sizeof *ftmp_ext, M_IPFW, M_DONTWAIT);
ftmp = &ftmp_ext->rule ;
if (!fwc || !ftmp) {
dprintf(("%s malloc said no\n", err_prefix));
if (fwc) free(fwc, M_IPFW);
@ -980,7 +986,11 @@ add_entry(struct ip_fw_head *chainptr, struct ip_fw *frwl)
return (ENOSPC);
}
bcopy(frwl, ftmp, sizeof(struct ip_fw));
bzero(ftmp_ext, sizeof(*ftmp_ext)); /* play safe! */
bcopy(frwl, ftmp, sizeof(*ftmp));
if (ftmp->fw_flg & IP_FW_F_RND_MATCH)
ftmp_ext->dont_match_prob = (long)(ftmp->pipe_ptr) ;
ftmp->fw_in_if.fu_via_if.name[FW_IFNLEN - 1] = '\0';
ftmp->fw_pcnt = 0L;
ftmp->fw_bcnt = 0L;
@ -1293,9 +1303,8 @@ ip_fw_ctl(struct sockopt *sopt)
{
int error, s;
size_t size;
char *buf, *bp;
struct ip_fw_chain *fcp;
struct ip_fw frwl;
struct ip_fw frwl, *bp , *buf;
/*
* Disallow sets in really-really secure mode, but still allow
@ -1320,7 +1329,9 @@ ip_fw_ctl(struct sockopt *sopt)
for (fcp = LIST_FIRST(&ip_fw_chain), bp = buf; fcp;
fcp = LIST_NEXT(fcp, chain)) {
bcopy(fcp->rule, bp, sizeof *fcp->rule);
bp += sizeof *fcp->rule;
(long)bp->pipe_ptr =
((struct ip_fw_ext *)fcp->rule)->dont_match_prob;
bp ++ ;
}
error = sooptcopyout(sopt, buf, size);
FREE(buf, M_TEMP);

View File

@ -11,7 +11,7 @@
*
* This software is provided ``AS IS'' without any warranties of any kind.
*
* $Id: ip_fw.h,v 1.39 1999/07/28 22:22:57 green Exp $
* $Id: ip_fw.h,v 1.40 1999/08/01 16:57:16 green Exp $
*/
#ifndef _IP_FW_H
@ -89,6 +89,22 @@ struct ip_fw {
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_int param1; /* unused at the moment */
};
#define IP_FW_GETNSRCP(rule) ((rule)->fw_nports & 0x0f)
#define IP_FW_SETNSRCP(rule, n) do { \
(rule)->fw_nports &= ~0x0f; \
@ -154,7 +170,9 @@ struct ip_fw_chain {
#define IP_FW_F_GID 0x00400000 /* filter by uid */
#define IP_FW_F_MASK 0x007FFFFF /* All possible flag bits mask */
#define IP_FW_F_RND_MATCH 0x00800000 /* probabilistic rule match */
#define IP_FW_F_MASK 0x00FFFFFF /* All possible flag bits mask */
/*
* For backwards compatibility with rules specifying "via iface" but