pf: Optionally attempt to preserve rule counter values across ruleset updates
Usually rule counters are reset to zero on every update of the ruleset. With keepcounters set pf will attempt to find matching rules between old and new rulesets and preserve the rule counters. MFC after: 4 weeks Sponsored by: Rubicon Communications, LLC ("Netgate") Differential Revision: https://reviews.freebsd.org/D29780
This commit is contained in:
parent
8bb0f1b87b
commit
42ec75f83a
@ -569,3 +569,25 @@ int pfctl_get_clear_rule(int dev, u_int32_t nr, u_int32_t ticket,
|
|||||||
|
|
||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
pfctl_set_keepcounters(int dev, bool keep)
|
||||||
|
{
|
||||||
|
struct pfioc_nv nv;
|
||||||
|
nvlist_t *nvl;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
nvl = nvlist_create(0);
|
||||||
|
|
||||||
|
nvlist_add_bool(nvl, "keep_counters", keep);
|
||||||
|
|
||||||
|
nv.data = nvlist_pack(nvl, &nv.len);
|
||||||
|
nv.size = nv.len;
|
||||||
|
|
||||||
|
nvlist_destroy(nvl);
|
||||||
|
|
||||||
|
ret = ioctl(dev, DIOCKEEPCOUNTERS, &nv);
|
||||||
|
|
||||||
|
free(nv.data);
|
||||||
|
return (ret);
|
||||||
|
}
|
||||||
|
@ -188,5 +188,6 @@ int pfctl_get_clear_rule(int dev, u_int32_t nr, u_int32_t ticket,
|
|||||||
int pfctl_add_rule(int dev, const struct pfctl_rule *r,
|
int pfctl_add_rule(int dev, const struct pfctl_rule *r,
|
||||||
const char *anchor, const char *anchor_call, u_int32_t ticket,
|
const char *anchor, const char *anchor_call, u_int32_t ticket,
|
||||||
u_int32_t pool_ticket);
|
u_int32_t pool_ticket);
|
||||||
|
int pfctl_set_keepcounters(int dev, bool keep);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -461,7 +461,7 @@ int parseport(char *, struct range *r, int);
|
|||||||
%token REASSEMBLE FRAGDROP FRAGCROP ANCHOR NATANCHOR RDRANCHOR BINATANCHOR
|
%token REASSEMBLE FRAGDROP FRAGCROP ANCHOR NATANCHOR RDRANCHOR BINATANCHOR
|
||||||
%token SET OPTIMIZATION TIMEOUT LIMIT LOGINTERFACE BLOCKPOLICY FAILPOLICY
|
%token SET OPTIMIZATION TIMEOUT LIMIT LOGINTERFACE BLOCKPOLICY FAILPOLICY
|
||||||
%token RANDOMID REQUIREORDER SYNPROXY FINGERPRINTS NOSYNC DEBUG SKIP HOSTID
|
%token RANDOMID REQUIREORDER SYNPROXY FINGERPRINTS NOSYNC DEBUG SKIP HOSTID
|
||||||
%token ANTISPOOF FOR INCLUDE
|
%token ANTISPOOF FOR INCLUDE KEEPCOUNTERS
|
||||||
%token BITMASK RANDOM SOURCEHASH ROUNDROBIN STATICPORT PROBABILITY MAPEPORTSET
|
%token BITMASK RANDOM SOURCEHASH ROUNDROBIN STATICPORT PROBABILITY MAPEPORTSET
|
||||||
%token ALTQ CBQ CODEL PRIQ HFSC FAIRQ BANDWIDTH TBRSIZE LINKSHARE REALTIME
|
%token ALTQ CBQ CODEL PRIQ HFSC FAIRQ BANDWIDTH TBRSIZE LINKSHARE REALTIME
|
||||||
%token UPPERLIMIT QUEUE PRIORITY QLIMIT HOGS BUCKETS RTABLE TARGET INTERVAL
|
%token UPPERLIMIT QUEUE PRIORITY QLIMIT HOGS BUCKETS RTABLE TARGET INTERVAL
|
||||||
@ -719,6 +719,9 @@ option : SET OPTIMIZATION STRING {
|
|||||||
}
|
}
|
||||||
keep_state_defaults = $3;
|
keep_state_defaults = $3;
|
||||||
}
|
}
|
||||||
|
| SET KEEPCOUNTERS {
|
||||||
|
pf->keep_counters = true;
|
||||||
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
stringall : STRING { $$ = $1; }
|
stringall : STRING { $$ = $1; }
|
||||||
@ -5593,6 +5596,7 @@ lookup(char *s)
|
|||||||
{ "inet6", INET6},
|
{ "inet6", INET6},
|
||||||
{ "interval", INTERVAL},
|
{ "interval", INTERVAL},
|
||||||
{ "keep", KEEP},
|
{ "keep", KEEP},
|
||||||
|
{ "keepcounters", KEEPCOUNTERS},
|
||||||
{ "label", LABEL},
|
{ "label", LABEL},
|
||||||
{ "limit", LIMIT},
|
{ "limit", LIMIT},
|
||||||
{ "linkshare", LINKSHARE},
|
{ "linkshare", LINKSHARE},
|
||||||
|
@ -1745,6 +1745,10 @@ pfctl_load_options(struct pfctl *pf)
|
|||||||
if (pfctl_load_hostid(pf, pf->hostid))
|
if (pfctl_load_hostid(pf, pf->hostid))
|
||||||
error = 1;
|
error = 1;
|
||||||
|
|
||||||
|
/* load keepcounters */
|
||||||
|
if (pfctl_set_keepcounters(pf->dev, pf->keep_counters))
|
||||||
|
error = 1;
|
||||||
|
|
||||||
return (error);
|
return (error);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -98,6 +98,7 @@ struct pfctl {
|
|||||||
u_int32_t debug;
|
u_int32_t debug;
|
||||||
u_int32_t hostid;
|
u_int32_t hostid;
|
||||||
char *ifname;
|
char *ifname;
|
||||||
|
bool keep_counters;
|
||||||
|
|
||||||
u_int8_t timeout_set[PFTM_MAX];
|
u_int8_t timeout_set[PFTM_MAX];
|
||||||
u_int8_t limit_set[PF_LIMIT_MAX];
|
u_int8_t limit_set[PF_LIMIT_MAX];
|
||||||
|
@ -28,7 +28,7 @@
|
|||||||
.\" ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
.\" ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
.\" POSSIBILITY OF SUCH DAMAGE.
|
.\" POSSIBILITY OF SUCH DAMAGE.
|
||||||
.\"
|
.\"
|
||||||
.Dd December 7, 2019
|
.Dd April 19, 2021
|
||||||
.Dt PF.CONF 5
|
.Dt PF.CONF 5
|
||||||
.Os
|
.Os
|
||||||
.Sh NAME
|
.Sh NAME
|
||||||
@ -618,6 +618,13 @@ Generate debug messages for various errors.
|
|||||||
.It Ar loud
|
.It Ar loud
|
||||||
Generate debug messages for common conditions.
|
Generate debug messages for common conditions.
|
||||||
.El
|
.El
|
||||||
|
.It Ar set keepcounters
|
||||||
|
Preserve rule counters across rule updates.
|
||||||
|
Usually rule counters are reset to zero on every update of the ruleset.
|
||||||
|
With
|
||||||
|
.Ar keepcounters
|
||||||
|
set pf will attempt to find matching rules between old and new rulesets
|
||||||
|
and preserve the rule counters.
|
||||||
.El
|
.El
|
||||||
.Sh TRAFFIC NORMALIZATION
|
.Sh TRAFFIC NORMALIZATION
|
||||||
Traffic normalization is used to sanitize packet content in such
|
Traffic normalization is used to sanitize packet content in such
|
||||||
@ -2888,7 +2895,8 @@ option = "set" ( [ "timeout" ( timeout | "{" timeout-list "}" ) ] |
|
|||||||
[ "require-order" ( "yes" | "no" ) ]
|
[ "require-order" ( "yes" | "no" ) ]
|
||||||
[ "fingerprints" filename ] |
|
[ "fingerprints" filename ] |
|
||||||
[ "skip on" ifspec ] |
|
[ "skip on" ifspec ] |
|
||||||
[ "debug" ( "none" | "urgent" | "misc" | "loud" ) ] )
|
[ "debug" ( "none" | "urgent" | "misc" | "loud" ) ]
|
||||||
|
[ "keepcounters" ] )
|
||||||
|
|
||||||
pf-rule = action [ ( "in" | "out" ) ]
|
pf-rule = action [ ( "in" | "out" ) ]
|
||||||
[ "log" [ "(" logopts ")"] ] [ "quick" ]
|
[ "log" [ "(" logopts ")"] ] [ "quick" ]
|
||||||
|
@ -996,6 +996,7 @@ struct pf_kstatus {
|
|||||||
uint32_t hostid;
|
uint32_t hostid;
|
||||||
char ifname[IFNAMSIZ];
|
char ifname[IFNAMSIZ];
|
||||||
uint8_t pf_chksum[PF_MD5_DIGEST_LENGTH];
|
uint8_t pf_chksum[PF_MD5_DIGEST_LENGTH];
|
||||||
|
bool keep_counters;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct pf_divert {
|
struct pf_divert {
|
||||||
@ -1304,6 +1305,8 @@ struct pfioc_iface {
|
|||||||
#define DIOCSETIFFLAG _IOWR('D', 89, struct pfioc_iface)
|
#define DIOCSETIFFLAG _IOWR('D', 89, struct pfioc_iface)
|
||||||
#define DIOCCLRIFFLAG _IOWR('D', 90, struct pfioc_iface)
|
#define DIOCCLRIFFLAG _IOWR('D', 90, struct pfioc_iface)
|
||||||
#define DIOCKILLSRCNODES _IOWR('D', 91, struct pfioc_src_node_kill)
|
#define DIOCKILLSRCNODES _IOWR('D', 91, struct pfioc_src_node_kill)
|
||||||
|
#define DIOCKEEPCOUNTERS _IOWR('D', 92, struct pfioc_nv)
|
||||||
|
|
||||||
struct pf_ifspeed_v0 {
|
struct pf_ifspeed_v0 {
|
||||||
char ifname[IFNAMSIZ];
|
char ifname[IFNAMSIZ];
|
||||||
u_int32_t baudrate;
|
u_int32_t baudrate;
|
||||||
|
@ -197,6 +197,7 @@ static void pf_clear_states(void);
|
|||||||
static int pf_clear_tables(void);
|
static int pf_clear_tables(void);
|
||||||
static void pf_clear_srcnodes(struct pf_ksrc_node *);
|
static void pf_clear_srcnodes(struct pf_ksrc_node *);
|
||||||
static void pf_kill_srcnodes(struct pfioc_src_node_kill *);
|
static void pf_kill_srcnodes(struct pfioc_src_node_kill *);
|
||||||
|
static int pf_keepcounters(struct pfioc_nv *);
|
||||||
static void pf_tbladdr_copyout(struct pf_addr_wrap *);
|
static void pf_tbladdr_copyout(struct pf_addr_wrap *);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -1022,11 +1023,27 @@ pf_hash_rule(MD5_CTX *ctx, struct pf_krule *rule)
|
|||||||
PF_MD5_UPD(rule, tos);
|
PF_MD5_UPD(rule, tos);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool
|
||||||
|
pf_krule_compare(struct pf_krule *a, struct pf_krule *b)
|
||||||
|
{
|
||||||
|
MD5_CTX ctx[2];
|
||||||
|
u_int8_t digest[2][PF_MD5_DIGEST_LENGTH];
|
||||||
|
|
||||||
|
MD5Init(&ctx[0]);
|
||||||
|
MD5Init(&ctx[1]);
|
||||||
|
pf_hash_rule(&ctx[0], a);
|
||||||
|
pf_hash_rule(&ctx[1], b);
|
||||||
|
MD5Final(digest[0], &ctx[0]);
|
||||||
|
MD5Final(digest[1], &ctx[1]);
|
||||||
|
|
||||||
|
return (memcmp(digest[0], digest[1], PF_MD5_DIGEST_LENGTH) == 0);
|
||||||
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
pf_commit_rules(u_int32_t ticket, int rs_num, char *anchor)
|
pf_commit_rules(u_int32_t ticket, int rs_num, char *anchor)
|
||||||
{
|
{
|
||||||
struct pf_kruleset *rs;
|
struct pf_kruleset *rs;
|
||||||
struct pf_krule *rule, **old_array;
|
struct pf_krule *rule, **old_array, *tail;
|
||||||
struct pf_krulequeue *old_rules;
|
struct pf_krulequeue *old_rules;
|
||||||
int error;
|
int error;
|
||||||
u_int32_t old_rcount;
|
u_int32_t old_rcount;
|
||||||
@ -1058,6 +1075,29 @@ pf_commit_rules(u_int32_t ticket, int rs_num, char *anchor)
|
|||||||
rs->rules[rs_num].inactive.ptr_array;
|
rs->rules[rs_num].inactive.ptr_array;
|
||||||
rs->rules[rs_num].active.rcount =
|
rs->rules[rs_num].active.rcount =
|
||||||
rs->rules[rs_num].inactive.rcount;
|
rs->rules[rs_num].inactive.rcount;
|
||||||
|
|
||||||
|
/* Attempt to preserve counter information. */
|
||||||
|
if (V_pf_status.keep_counters) {
|
||||||
|
TAILQ_FOREACH(rule, rs->rules[rs_num].active.ptr,
|
||||||
|
entries) {
|
||||||
|
tail = TAILQ_FIRST(old_rules);
|
||||||
|
while ((tail != NULL) && ! pf_krule_compare(tail, rule))
|
||||||
|
tail = TAILQ_NEXT(tail, entries);
|
||||||
|
if (tail != NULL) {
|
||||||
|
counter_u64_add(rule->evaluations,
|
||||||
|
counter_u64_fetch(tail->evaluations));
|
||||||
|
counter_u64_add(rule->packets[0],
|
||||||
|
counter_u64_fetch(tail->packets[0]));
|
||||||
|
counter_u64_add(rule->packets[1],
|
||||||
|
counter_u64_fetch(tail->packets[1]));
|
||||||
|
counter_u64_add(rule->bytes[0],
|
||||||
|
counter_u64_fetch(tail->bytes[0]));
|
||||||
|
counter_u64_add(rule->bytes[1],
|
||||||
|
counter_u64_fetch(tail->bytes[1]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
rs->rules[rs_num].inactive.ptr = old_rules;
|
rs->rules[rs_num].inactive.ptr = old_rules;
|
||||||
rs->rules[rs_num].inactive.ptr_array = old_array;
|
rs->rules[rs_num].inactive.ptr_array = old_array;
|
||||||
rs->rules[rs_num].inactive.rcount = old_rcount;
|
rs->rules[rs_num].inactive.rcount = old_rcount;
|
||||||
@ -4948,6 +4988,10 @@ pfioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flags, struct thread *td
|
|||||||
pf_kill_srcnodes((struct pfioc_src_node_kill *)addr);
|
pf_kill_srcnodes((struct pfioc_src_node_kill *)addr);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case DIOCKEEPCOUNTERS:
|
||||||
|
error = pf_keepcounters((struct pfioc_nv *)addr);
|
||||||
|
break;
|
||||||
|
|
||||||
case DIOCSETHOSTID: {
|
case DIOCSETHOSTID: {
|
||||||
u_int32_t *hostid = (u_int32_t *)addr;
|
u_int32_t *hostid = (u_int32_t *)addr;
|
||||||
|
|
||||||
@ -5227,6 +5271,41 @@ pf_kill_srcnodes(struct pfioc_src_node_kill *psnk)
|
|||||||
psnk->psnk_killed = pf_free_src_nodes(&kill);
|
psnk->psnk_killed = pf_free_src_nodes(&kill);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
pf_keepcounters(struct pfioc_nv *nv)
|
||||||
|
{
|
||||||
|
nvlist_t *nvl = NULL;
|
||||||
|
void *nvlpacked = NULL;
|
||||||
|
int error = 0;
|
||||||
|
|
||||||
|
#define ERROUT(x) do { error = (x); goto on_error; } while (0)
|
||||||
|
|
||||||
|
if (nv->len > pf_ioctl_maxcount)
|
||||||
|
ERROUT(ENOMEM);
|
||||||
|
|
||||||
|
nvlpacked = malloc(nv->len, M_TEMP, M_WAITOK);
|
||||||
|
if (nvlpacked == NULL)
|
||||||
|
ERROUT(ENOMEM);
|
||||||
|
|
||||||
|
error = copyin(nv->data, nvlpacked, nv->len);
|
||||||
|
if (error)
|
||||||
|
ERROUT(error);
|
||||||
|
|
||||||
|
nvl = nvlist_unpack(nvlpacked, nv->len, 0);
|
||||||
|
if (nvl == NULL)
|
||||||
|
ERROUT(EBADMSG);
|
||||||
|
|
||||||
|
if (! nvlist_exists_bool(nvl, "keep_counters"))
|
||||||
|
ERROUT(EBADMSG);
|
||||||
|
|
||||||
|
V_pf_status.keep_counters = nvlist_get_bool(nvl, "keep_counters");
|
||||||
|
|
||||||
|
on_error:
|
||||||
|
nvlist_destroy(nvl);
|
||||||
|
free(nvlpacked, M_TEMP);
|
||||||
|
return (error);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* XXX - Check for version missmatch!!!
|
* XXX - Check for version missmatch!!!
|
||||||
*/
|
*/
|
||||||
|
Loading…
Reference in New Issue
Block a user