Hello tech@
I've noticed different behavior of pf rule counters between IPv4 and
IPv6. The easiest ruleset would look like:
block
match on em0 inet6 tag potazmo
match on em0 inet tag ausfahrt
pass on em0 from any to any tagged potazmo
pass on em0 from any to any tagged ausfahrt
where ping4s are counted to both rules, ping6s are counted only to the
last rule.
I noticed the code repeats, so made a function from it. Please report
if it's alright and of any use. Apologies for possible spaces instead
of tabs :-(
Index: pf.c
===================================================================
RCS file: /cvs/src/sys/net/pf.c,v
retrieving revision 1.696
diff -u -p -r1.696 pf.c
--- pf.c 5 Aug 2010 17:21:19 -0000 1.696
+++ pf.c 1 Sep 2010 12:49:59 -0000
@@ -5517,6 +5517,62 @@ pf_get_divert(struct mbuf *m)
return ((struct pf_divert *)(mtag + 1));
}
+void
+pf_increase_counters(int dir, int action, struct pf_pdesc *pd,
+ struct pfi_kif *kif, struct pf_state *s,
+ struct pf_rule *r, struct pf_rule *a)
+{
+ int dirndx;
+ kif->pfik_bytes[pd->af == AF_INET6][dir == PF_OUT][action != PF_PASS]
+ += pd->tot_len;
+ kif->pfik_packets[pd->af == AF_INET6][dir == PF_OUT][action !=
PF_PASS]++;
+
+ if (action == PF_PASS || r->action == PF_DROP) {
+ dirndx = (dir == PF_OUT);
+ r->packets[dirndx]++;
+ r->bytes[dirndx] += pd->tot_len;
+ if (a != NULL) {
+ a->packets[dirndx]++;
+ a->bytes[dirndx] += pd->tot_len;
+ }
+ if (s != NULL) {
+ struct pf_rule_item *ri;
+ struct pf_sn_item *sni;
+
+ SLIST_FOREACH(sni, &s->src_nodes, next) {
+ sni->sn->packets[dirndx]++;
+ sni->sn->bytes[dirndx] += pd->tot_len;
+ }
+ dirndx = (dir == s->direction) ? 0 : 1;
+ s->packets[dirndx]++;
+ s->bytes[dirndx] += pd->tot_len;
+
+ /*
+ * We want to increase counters on _all_ rules
+ * that were matched during processing.
+ */
+ SLIST_FOREACH(ri, &s->match_rules, entry) {
+ ri->r->packets[dirndx]++;
+ ri->r->bytes[dirndx] += pd->tot_len;
+ }
+ }
+ if (r->src.addr.type == PF_ADDR_TABLE)
+ pfr_update_stats(r->src.addr.p.tbl,
+ (s == NULL) ? pd->src :
+ &s->key[(s->direction == PF_IN)]->
+ addr[(s->direction == PF_OUT)],
+ pd->af, pd->tot_len, dir == PF_OUT,
+ r->action == PF_PASS, r->src.neg);
+ if (r->dst.addr.type == PF_ADDR_TABLE)
+ pfr_update_stats(r->dst.addr.p.tbl,
+ (s == NULL) ? pd->dst :
+ &s->key[(s->direction == PF_IN)]->
+ addr[(s->direction == PF_IN)],
+ pd->af, pd->tot_len, dir == PF_OUT,
+ r->action == PF_PASS, r->dst.neg);
+ }
+}
+
#ifdef INET
int
pf_test(int dir, struct ifnet *ifp, struct mbuf **m0,
@@ -5530,7 +5586,7 @@ pf_test(int dir, struct ifnet *ifp, stru
struct pf_state *s = NULL;
struct pf_ruleset *ruleset = NULL;
struct pf_pdesc pd;
- int off, dirndx, pqid = 0;
+ int off, pqid = 0;
u_int16_t qid;
if (!pf_status.running)
@@ -5812,48 +5868,7 @@ done:
}
}
- kif->pfik_bytes[0][dir == PF_OUT][action != PF_PASS] += pd.tot_len;
- kif->pfik_packets[0][dir == PF_OUT][action != PF_PASS]++;
-
- if (action == PF_PASS || r->action == PF_DROP) {
- dirndx = (dir == PF_OUT);
- r->packets[dirndx]++;
- r->bytes[dirndx] += pd.tot_len;
- if (a != NULL) {
- a->packets[dirndx]++;
- a->bytes[dirndx] += pd.tot_len;
- }
- if (s != NULL) {
- struct pf_rule_item *ri;
- struct pf_sn_item *sni;
-
- SLIST_FOREACH(sni, &s->src_nodes, next) {
- sni->sn->packets[dirndx]++;
- sni->sn->bytes[dirndx] += pd.tot_len;
- }
- dirndx = (dir == s->direction) ? 0 : 1;
- s->packets[dirndx]++;
- s->bytes[dirndx] += pd.tot_len;
- SLIST_FOREACH(ri, &s->match_rules, entry) {
- ri->r->packets[dirndx]++;
- ri->r->bytes[dirndx] += pd.tot_len;
- }
- }
- if (r->src.addr.type == PF_ADDR_TABLE)
- pfr_update_stats(r->src.addr.p.tbl,
- (s == NULL) ? pd.src :
- &s->key[(s->direction == PF_IN)]->
- addr[(s->direction == PF_OUT)],
- pd.af, pd.tot_len, dir == PF_OUT,
- r->action == PF_PASS, r->src.neg);
- if (r->dst.addr.type == PF_ADDR_TABLE)
- pfr_update_stats(r->dst.addr.p.tbl,
- (s == NULL) ? pd.dst :
- &s->key[(s->direction == PF_IN)]->
- addr[(s->direction == PF_IN)],
- pd.af, pd.tot_len, dir == PF_OUT,
- r->action == PF_PASS, r->dst.neg);
- }
+ pf_increase_counters(dir, action, &pd, kif, s, r, a);
switch (action) {
case PF_SYNPROXY_DROP:
@@ -5891,7 +5906,7 @@ pf_test6(int dir, struct ifnet *ifp, str
struct pf_state *s = NULL;
struct pf_ruleset *ruleset = NULL;
struct pf_pdesc pd;
- int off, terminal = 0, dirndx, rh_cnt = 0;
+ int off, terminal = 0, rh_cnt = 0;
if (!pf_status.running)
return (PF_PASS);
@@ -6255,41 +6270,7 @@ done:
}
}
- kif->pfik_bytes[1][dir == PF_OUT][action != PF_PASS] += pd.tot_len;
- kif->pfik_packets[1][dir == PF_OUT][action != PF_PASS]++;
-
- if (action == PF_PASS || r->action == PF_DROP) {
- dirndx = (dir == PF_OUT);
- r->packets[dirndx]++;
- r->bytes[dirndx] += pd.tot_len;
- if (a != NULL) {
- a->packets[dirndx]++;
- a->bytes[dirndx] += pd.tot_len;
- }
- if (s != NULL) {
- struct pf_sn_item *sni;
-
- SLIST_FOREACH(sni, &s->src_nodes, next) {
- sni->sn->packets[dirndx]++;
- sni->sn->bytes[dirndx] += pd.tot_len;
- }
- dirndx = (dir == s->direction) ? 0 : 1;
- s->packets[dirndx]++;
- s->bytes[dirndx] += pd.tot_len;
- }
- if (r->src.addr.type == PF_ADDR_TABLE)
- pfr_update_stats(r->src.addr.p.tbl,
- (s == NULL) ? pd.src :
- &s->key[(s->direction == PF_IN)]->addr[0],
- pd.af, pd.tot_len, dir == PF_OUT,
- r->action == PF_PASS, r->src.neg);
- if (r->dst.addr.type == PF_ADDR_TABLE)
- pfr_update_stats(r->dst.addr.p.tbl,
- (s == NULL) ? pd.dst :
- &s->key[(s->direction == PF_IN)]->addr[1],
- pd.af, pd.tot_len, dir == PF_OUT,
- r->action == PF_PASS, r->dst.neg);
- }
+ pf_increase_counters(dir, action, &pd, kif, s, r, a);
switch (action) {
case PF_SYNPROXY_DROP:
Index: pfvar.h
===================================================================
RCS file: /cvs/src/sys/net/pfvar.h,v
retrieving revision 1.311
diff -u -p -r1.311 pfvar.h
--- pfvar.h 28 Jun 2010 23:21:41 -0000 1.311
+++ pfvar.h 1 Sep 2010 12:49:59 -0000
@@ -1735,6 +1735,10 @@ extern void
pf_addrcpy(struct pf_addr
void pf_rm_rule(struct pf_rulequeue *,
struct pf_rule *);
struct pf_divert *pf_find_divert(struct mbuf *);
+void pf_increase_counters(int, int,
+ struct pf_pdesc *, struct pfi_kif *,
+ struct pf_state *, struct pf_rule *,
+ struct pf_rule *);
#ifdef INET
int pf_test(int, struct ifnet *, struct mbuf **, struct ether_header *);
--
Martin Pelikan