diff --git a/sbin/pfctl/pfctl.h b/sbin/pfctl/pfctl.h --- a/sbin/pfctl/pfctl.h +++ b/sbin/pfctl/pfctl.h @@ -60,6 +60,7 @@ int pfr_get_tables(struct pfr_table *, struct pfr_table *, int *, int); int pfr_get_tstats(struct pfr_table *, struct pfr_tstats *, int *, int); int pfr_clr_tstats(struct pfr_table *, int, int *, int); +int pfr_clr_astats(struct pfr_table *, struct pfr_addr *, int, int *, int); int pfr_clr_addrs(struct pfr_table *, int *, int); int pfr_add_addrs(struct pfr_table *, struct pfr_addr *, int, int *, int); int pfr_del_addrs(struct pfr_table *, struct pfr_addr *, int, int *, int); diff --git a/sbin/pfctl/pfctl.8 b/sbin/pfctl/pfctl.8 --- a/sbin/pfctl/pfctl.8 +++ b/sbin/pfctl/pfctl.8 @@ -506,8 +506,8 @@ Show the content (addresses) of a table. .It Fl T Cm test Test if the given addresses match a table. -.It Fl T Cm zero -Clear all the statistics of 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 load Load only the table definitions from .Xr pf.conf 5 . diff --git a/sbin/pfctl/pfctl_radix.c b/sbin/pfctl/pfctl_radix.c --- a/sbin/pfctl/pfctl_radix.c +++ b/sbin/pfctl/pfctl_radix.c @@ -286,6 +286,29 @@ return (0); } +int +pfr_clr_astats(struct pfr_table *tbl, struct pfr_addr *addr, int size, + int *nzero, int flags) +{ + struct pfioc_table io; + + if (size < 0 || (size && !tbl) || addr == NULL) { + errno = EINVAL; + return (-1); + } + bzero(&io, sizeof io); + io.pfrio_flags = flags; + io.pfrio_table = *tbl; + io.pfrio_buffer = addr; + io.pfrio_esize = sizeof(*addr); + io.pfrio_size = size; + if (ioctl(dev, DIOCRCLRASTATS, &io) == -1) + return (-1); + if (nzero) + *nzero = io.pfrio_nzero; + return (0); +} + int pfr_clr_tstats(struct pfr_table *tbl, int size, int *nzero, int flags) { diff --git a/sbin/pfctl/pfctl_table.c b/sbin/pfctl/pfctl_table.c --- a/sbin/pfctl/pfctl_table.c +++ b/sbin/pfctl/pfctl_table.c @@ -344,9 +344,22 @@ } if (nmatch < b.pfrb_size) rv = 2; + } else if (!strcmp(command, "zero") && (argc || file != NULL)) { + b.pfrb_type = PFRB_ADDRS; + if (load_addr(&b, argc, argv, file, 0)) + goto _error; + if (opts & PF_OPT_VERBOSE) + flags |= PFR_FLAG_FEEDBACK; + RVTEST(pfr_clr_astats(&table, b.pfrb_caddr, b.pfrb_size, + &nzero, flags)); + xprintf(opts, "%d/%d addresses cleared", nzero, b.pfrb_size); + if (opts & PF_OPT_VERBOSE) + PFRB_FOREACH(a, &b) + if (opts & PF_OPT_VERBOSE2 || + a->pfra_fback != PFR_FB_NONE) + print_addrx(a, NULL, + opts & PF_OPT_USEDNS); } else if (!strcmp(command, "zero")) { - if (argc || file != NULL) - usage(); flags |= PFR_FLAG_ADDRSTOO; RVTEST(pfr_clr_tstats(&table, 1, &nzero, flags)); xprintf(opts, "%d table/stats cleared", nzero);