mirror of
https://github.com/opnsense/src.git
synced 2026-05-28 04:12:45 -04:00
pfctl: add -T reset to touch pfras_tzero only for non-zero entries
This will make it easier for scripts to detect idle hosts in tables. PR: 282984 Reviewed by: kp MFC after: 2 weeks (cherry picked from commit 5b59b0c61e29f684a019afdd2848ffe2d5604e0c)
This commit is contained in:
parent
816c116633
commit
d3d3ef2b33
5 changed files with 132 additions and 3 deletions
|
|
@ -24,7 +24,7 @@
|
|||
.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
.\"
|
||||
.Dd November 20, 2024
|
||||
.Dd November 25, 2024
|
||||
.Dt PFCTL 8
|
||||
.Os
|
||||
.Sh NAME
|
||||
|
|
@ -503,6 +503,11 @@ Show the content (addresses) of a table.
|
|||
Test if the given addresses match a table.
|
||||
.It Fl T Cm zero Op Ar address ...
|
||||
Clear all the statistics of a table, or only for specified addresses.
|
||||
.It Fl T Cm reset
|
||||
Clear statistics only for addresses with non-zero statistics. Addresses
|
||||
with counter values at zero and their
|
||||
.Dq Cleared
|
||||
timestamp are left untouched.
|
||||
.It Fl T Cm load
|
||||
Load only the table definitions from
|
||||
.Xr pf.conf 5 .
|
||||
|
|
|
|||
|
|
@ -238,7 +238,7 @@ static const char * const showopt_list[] = {
|
|||
|
||||
static const char * const tblcmdopt_list[] = {
|
||||
"kill", "flush", "add", "delete", "load", "replace", "show",
|
||||
"test", "zero", "expire", NULL
|
||||
"test", "zero", "expire", "reset", NULL
|
||||
};
|
||||
|
||||
static const char * const debugopt_list[] = {
|
||||
|
|
|
|||
|
|
@ -293,7 +293,7 @@ pfr_clr_astats(struct pfr_table *tbl, struct pfr_addr *addr, int size,
|
|||
{
|
||||
struct pfioc_table io;
|
||||
|
||||
if (size < 0 || (size && !tbl) || addr == NULL) {
|
||||
if (size < 0 || !tbl || (size && !addr)) {
|
||||
errno = EINVAL;
|
||||
return (-1);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -61,6 +61,7 @@ static void print_table(struct pfr_table *, int, int);
|
|||
static void print_tstats(struct pfr_tstats *, int);
|
||||
static int load_addr(struct pfr_buffer *, int, char *[], char *, int);
|
||||
static void print_addrx(struct pfr_addr *, struct pfr_addr *, int);
|
||||
static int nonzero_astats(struct pfr_astats *);
|
||||
static void print_astats(struct pfr_astats *, int);
|
||||
static void radix_perror(void);
|
||||
static void xprintf(int, const char *, ...);
|
||||
|
|
@ -294,6 +295,36 @@ pfctl_table(int argc, char *argv[], char *tname, const char *command,
|
|||
if ((opts & PF_OPT_VERBOSE2) || a->pfra_fback)
|
||||
print_addrx(a, NULL,
|
||||
opts & PF_OPT_USEDNS);
|
||||
} else if (!strcmp(command, "reset")) {
|
||||
struct pfr_astats *as;
|
||||
|
||||
b.pfrb_type = PFRB_ASTATS;
|
||||
b2.pfrb_type = PFRB_ADDRS;
|
||||
if (argc || file != NULL)
|
||||
usage();
|
||||
do {
|
||||
pfr_buf_grow(&b, b.pfrb_size);
|
||||
b.pfrb_size = b.pfrb_msize;
|
||||
RVTEST(pfr_get_astats(&table, b.pfrb_caddr,
|
||||
&b.pfrb_size, flags));
|
||||
} while (b.pfrb_size > b.pfrb_msize);
|
||||
PFRB_FOREACH(as, &b) {
|
||||
as->pfras_a.pfra_fback = 0;
|
||||
if (nonzero_astats(as))
|
||||
if (pfr_buf_add(&b2, &as->pfras_a))
|
||||
err(1, "duplicate buffer");
|
||||
}
|
||||
|
||||
if (opts & PF_OPT_VERBOSE)
|
||||
flags |= PFR_FLAG_FEEDBACK;
|
||||
RVTEST(pfr_clr_astats(&table, b2.pfrb_caddr, b2.pfrb_size,
|
||||
&nzero, flags));
|
||||
xprintf(opts, "%d/%d stats cleared", nzero, b.pfrb_size);
|
||||
if (opts & PF_OPT_VERBOSE)
|
||||
PFRB_FOREACH(a, &b2)
|
||||
if ((opts & PF_OPT_VERBOSE2) || a->pfra_fback)
|
||||
print_addrx(a, NULL,
|
||||
opts & PF_OPT_USEDNS);
|
||||
} else if (!strcmp(command, "show")) {
|
||||
b.pfrb_type = (opts & PF_OPT_VERBOSE) ?
|
||||
PFRB_ASTATS : PFRB_ADDRS;
|
||||
|
|
@ -485,6 +516,19 @@ print_addrx(struct pfr_addr *ad, struct pfr_addr *rad, int dns)
|
|||
printf("\n");
|
||||
}
|
||||
|
||||
int
|
||||
nonzero_astats(struct pfr_astats *as)
|
||||
{
|
||||
uint64_t s = 0;
|
||||
|
||||
for (int dir = 0; dir < PFR_DIR_MAX; dir++)
|
||||
for (int op = 0; op < PFR_OP_ADDR_MAX; op++)
|
||||
s |= as->pfras_packets[dir][op] |
|
||||
as->pfras_bytes[dir][op];
|
||||
|
||||
return (!!s);
|
||||
}
|
||||
|
||||
void
|
||||
print_astats(struct pfr_astats *as, int dns)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -165,6 +165,85 @@ zero_one_cleanup()
|
|||
pft_cleanup
|
||||
}
|
||||
|
||||
atf_test_case "reset_nonzero" "cleanup"
|
||||
reset_nonzero_head()
|
||||
{
|
||||
atf_set descr 'Test zeroing an address with non-zero counters'
|
||||
atf_set require.user root
|
||||
}
|
||||
|
||||
reset_nonzero_body()
|
||||
{
|
||||
epair_send=$(vnet_mkepair)
|
||||
ifconfig ${epair_send}a 192.0.2.1/24 up
|
||||
ifconfig ${epair_send}a inet alias 192.0.2.3/24
|
||||
|
||||
vnet_mkjail alcatraz ${epair_send}b
|
||||
jexec alcatraz ifconfig ${epair_send}b 192.0.2.2/24 up
|
||||
jexec alcatraz pfctl -e
|
||||
|
||||
pft_set_rules alcatraz \
|
||||
"table <foo> counters { 192.0.2.1, 192.0.2.3 }" \
|
||||
"table <bar> counters { }" \
|
||||
"block all" \
|
||||
"pass in from <foo> to any" \
|
||||
"pass out from any to <foo>" \
|
||||
"pass on notReallyAnIf from <bar> to <bar>" \
|
||||
"set skip on lo"
|
||||
|
||||
# Nonexisting table can't be reset, following `-T show`.
|
||||
atf_check -o ignore \
|
||||
-s not-exit:0 \
|
||||
-e inline:"pfctl: Table does not exist.\n" \
|
||||
jexec alcatraz pfctl -t nonexistent -T reset
|
||||
|
||||
atf_check -o ignore \
|
||||
-s exit:0 \
|
||||
-e inline:"0/0 stats cleared.\n" \
|
||||
jexec alcatraz pfctl -t bar -T reset
|
||||
|
||||
# No-op is a valid operation.
|
||||
atf_check -s exit:0 \
|
||||
-e inline:"0/2 stats cleared.\n" \
|
||||
jexec alcatraz pfctl -t foo -T reset
|
||||
|
||||
atf_check -s exit:0 -o ignore ping -c 3 -S 192.0.2.3 192.0.2.2
|
||||
|
||||
atf_check -s exit:0 -e ignore \
|
||||
-o match:'In/Pass:.*'"$TABLE_STATS_ZERO_REGEXP" \
|
||||
-o match:'In/Pass:.*'"$TABLE_STATS_NONZERO_REGEXP" \
|
||||
-o match:'Out/Pass:.*'"$TABLE_STATS_ZERO_REGEXP" \
|
||||
-o match:'Out/Pass:.*'"$TABLE_STATS_NONZERO_REGEXP" \
|
||||
jexec alcatraz pfctl -t foo -vvT show
|
||||
|
||||
local clrd uniq
|
||||
clrd=`jexec alcatraz pfctl -t foo -vvT show | grep -c Cleared`
|
||||
uniq=`jexec alcatraz pfctl -t foo -vvT show | sort -u | grep -c Cleared`
|
||||
atf_check_equal "$clrd" 2
|
||||
atf_check_equal "$uniq" 1 # time they were added
|
||||
|
||||
atf_check -s exit:0 -e ignore \
|
||||
-e inline:"1/2 stats cleared.\n" \
|
||||
jexec alcatraz pfctl -t foo -T reset
|
||||
|
||||
clrd=`jexec alcatraz pfctl -t foo -vvT show | grep -c Cleared`
|
||||
uniq=`jexec alcatraz pfctl -t foo -vvT show | sort -u | grep -c Cleared`
|
||||
atf_check_equal "$clrd" 2
|
||||
atf_check_equal "$uniq" 2 # 192.0.2.3 should get new timestamp
|
||||
|
||||
atf_check -s exit:0 -e ignore \
|
||||
-o not-match:'In/Pass:.*'"$TABLE_STATS_NONZERO_REGEXP" \
|
||||
-o not-match:'Out/Pass:.*'"$TABLE_STATS_NONZERO_REGEXP" \
|
||||
-o match:'In/Pass:.*'"$TABLE_STATS_ZERO_REGEXP" \
|
||||
-o match:'Out/Pass:.*'"$TABLE_STATS_ZERO_REGEXP" \
|
||||
jexec alcatraz pfctl -t foo -vvT show
|
||||
}
|
||||
|
||||
reset_nonzero_cleanup()
|
||||
{
|
||||
pft_cleanup
|
||||
}
|
||||
|
||||
atf_test_case "pr251414" "cleanup"
|
||||
pr251414_head()
|
||||
{
|
||||
|
|
@ -381,6 +460,7 @@ atf_init_test_cases()
|
|||
atf_add_test_case "v4_counters"
|
||||
atf_add_test_case "v6_counters"
|
||||
atf_add_test_case "zero_one"
|
||||
atf_add_test_case "reset_nonzero"
|
||||
atf_add_test_case "pr251414"
|
||||
atf_add_test_case "automatic"
|
||||
atf_add_test_case "network"
|
||||
|
|
|
|||
Loading…
Reference in a new issue