Index: share/man/man4/bpf.4 =================================================================== RCS file: /cvs/src/share/man/man4/bpf.4,v retrieving revision 1.41 diff -u -p -r1.41 bpf.4 --- share/man/man4/bpf.4 25 Apr 2019 18:26:16 -0000 1.41 +++ share/man/man4/bpf.4 20 Jul 2020 09:11:30 -0000 @@ -216,6 +216,7 @@ The allowable ioctls are .Dv BIOCGHDRCMPLT , .Dv BIOCGRSIG , .Dv BIOCGRTIMEOUT , +.Dv BIOCGSAMPLE , .Dv BIOCGSTATS , .Dv BIOCIMMEDIATE , .Dv BIOCLOCK , @@ -420,6 +421,15 @@ If non-zero, packets matching the specif or .Dv BPF_DIRECTION_OUT ) will be ignored. +.Pp +.It Dv BIOCSSAMPLE Fa "u_int *" +.It Dv BIOCGSAMPLE Fa "u_int *" +Sets or gets the threshold for sampling matched packets. +If non-zero, a random value will be generated for comparison against +the threshold value when a packet is being filtered. +Random values less than the threshold allow packet filtering to +continue; values above the threshold will skip filter processing. +By default sampling is disabled. .El .Ss Standard ioctls .Nm Index: usr.sbin/tcpdump/tcpdump.8 =================================================================== RCS file: /cvs/src/usr.sbin/tcpdump/tcpdump.8,v retrieving revision 1.110 diff -u -p -r1.110 tcpdump.8 --- usr.sbin/tcpdump/tcpdump.8 21 Jun 2020 05:00:18 -0000 1.110 +++ usr.sbin/tcpdump/tcpdump.8 20 Jul 2020 09:11:30 -0000 @@ -34,6 +34,7 @@ .Op Fl E Oo Ar espalg : Oc Ns Ar espkey .Op Fl F Ar file .Op Fl i Ar interface +.Op Fl R Ar samplerate .Op Fl r Ar file .Op Fl s Ar snaplen .Op Fl T Ar type @@ -193,6 +194,11 @@ Quick .Pq quiet? output. Print less protocol information so output lines are shorter. +.It Fl R Ar samplerate +Configure the rate at which packets are selected or sampled to 1 per +.Ar samplerate +packets during live captures. +The default is to sample every packet. .It Fl r Ar file Read packets from a .Ar file Index: usr.sbin/tcpdump/privsep.c =================================================================== RCS file: /cvs/src/usr.sbin/tcpdump/privsep.c,v retrieving revision 1.54 diff -u -p -r1.54 privsep.c --- usr.sbin/tcpdump/privsep.c 28 Jun 2019 13:32:51 -0000 1.54 +++ usr.sbin/tcpdump/privsep.c 20 Jul 2020 09:11:30 -0000 @@ -224,7 +224,7 @@ priv_exec(int argc, char *argv[]) /* parse the arguments for required options */ opterr = 0; while ((i = getopt(argc, argv, - "aB:c:D:deE:fF:i:lLnNOopPqr:s:StT:vw:xXy:Y")) != -1) { + "aB:c:D:deE:fF:i:lLnNOopPqr:R:s:StT:vw:xXy:Y")) != -1) { switch (i) { case 'n': nflag++; @@ -366,7 +366,7 @@ static void impl_open_bpf(int fd, int *bpfd) { int snaplen, promisc, err; - u_int dlt, dirfilt, fildrop; + u_int dlt, dirfilt, fildrop, samplerate; char device[IFNAMSIZ]; size_t iflen; @@ -377,10 +377,12 @@ impl_open_bpf(int fd, int *bpfd) must_read(fd, &dlt, sizeof(u_int)); must_read(fd, &dirfilt, sizeof(u_int)); must_read(fd, &fildrop, sizeof(fildrop)); + must_read(fd, &samplerate, sizeof(samplerate)); iflen = read_string(fd, device, sizeof(device), __func__); if (iflen == 0) errx(1, "Invalid interface size specified"); - *bpfd = pcap_live(device, snaplen, promisc, dlt, dirfilt, fildrop); + *bpfd = pcap_live(device, snaplen, promisc, dlt, dirfilt, fildrop, + samplerate); err = errno; if (*bpfd < 0) logmsg(LOG_DEBUG, Index: usr.sbin/tcpdump/privsep.h =================================================================== RCS file: /cvs/src/usr.sbin/tcpdump/privsep.h,v retrieving revision 1.12 diff -u -p -r1.12 privsep.h --- usr.sbin/tcpdump/privsep.h 18 Mar 2019 00:09:22 -0000 1.12 +++ usr.sbin/tcpdump/privsep.h 20 Jul 2020 09:11:30 -0000 @@ -45,11 +45,11 @@ __dead void priv_exec(int, char **); void priv_init_done(void); int setfilter(int, int, char *); -int pcap_live(const char *, int, int, u_int, u_int, u_int); +int pcap_live(const char *, int, int, u_int, u_int, u_int, u_int); struct bpf_program *priv_pcap_setfilter(pcap_t *, int, u_int32_t); pcap_t *priv_pcap_live(const char *, int, int, int, char *, u_int, - u_int, u_int); + u_int, u_int, u_int); pcap_t *priv_pcap_offline(const char *, char *); size_t priv_gethostbyaddr(char *, size_t, int, char *, size_t); Index: usr.sbin/tcpdump/privsep_pcap.c =================================================================== RCS file: /cvs/src/usr.sbin/tcpdump/privsep_pcap.c,v retrieving revision 1.25 diff -u -p -r1.25 privsep_pcap.c --- usr.sbin/tcpdump/privsep_pcap.c 28 Jun 2019 13:32:51 -0000 1.25 +++ usr.sbin/tcpdump/privsep_pcap.c 20 Jul 2020 09:11:30 -0000 @@ -173,7 +173,7 @@ priv_pcap_setfilter(pcap_t *hpcap, int o /* privileged part of priv_pcap_live */ int pcap_live(const char *device, int snaplen, int promisc, u_int dlt, - u_int dirfilt, u_int fildrop) + u_int dirfilt, u_int fildrop, u_int samplerate) { int fd; struct ifreq ifr; @@ -204,6 +204,9 @@ pcap_live(const char *device, int snaple if (ioctl(fd, BIOCSFILDROP, &fildrop) == -1) goto error; + if (samplerate && ioctl(fd, BIOCSSAMPLE, &samplerate) == -1) + goto error; + /* lock the descriptor */ if (ioctl(fd, BIOCLOCK, NULL) == -1) goto error; @@ -221,7 +224,7 @@ pcap_live(const char *device, int snaple */ pcap_t * priv_pcap_live(const char *dev, int slen, int prom, int to_ms, - char *ebuf, u_int dlt, u_int dirfilt, u_int fildrop) + char *ebuf, u_int dlt, u_int dirfilt, u_int fildrop, u_int samplerate) { int fd, err; struct bpf_version bv; @@ -251,6 +254,7 @@ priv_pcap_live(const char *dev, int slen must_write(priv_fd, &dlt, sizeof(u_int)); must_write(priv_fd, &dirfilt, sizeof(u_int)); must_write(priv_fd, &fildrop, sizeof(fildrop)); + must_write(priv_fd, &samplerate, sizeof(samplerate)); write_string(priv_fd, dev); fd = receive_fd(priv_fd); Index: usr.sbin/tcpdump/tcpdump.c =================================================================== RCS file: /cvs/src/usr.sbin/tcpdump/tcpdump.c,v retrieving revision 1.93 diff -u -p -r1.93 tcpdump.c --- usr.sbin/tcpdump/tcpdump.c 21 Jun 2020 05:00:18 -0000 1.93 +++ usr.sbin/tcpdump/tcpdump.c 20 Jul 2020 09:11:30 -0000 @@ -203,6 +203,19 @@ pcap_list_linktypes(pcap_t *p) } } +u_int +strtorate(const char *arg) +{ + long long rate; + const char *errstr; + + rate = strtonum(arg, 2, 0x1000000, &errstr); + if (errstr != NULL) + errx(1, "sample rate %s: %s", arg, errstr); + + return (0x100000000LL / rate); +} + int main(int argc, char **argv) { @@ -213,7 +226,7 @@ main(int argc, char **argv) pcap_handler printer; struct bpf_program *fcode; u_char *pcap_userdata; - u_int dirfilt = 0, dlt = (u_int) -1; + u_int dirfilt = 0, samplerate = 0, dlt = (u_int) -1; const char *errstr; if ((cp = strrchr(argv[0], '/')) != NULL) @@ -232,7 +245,7 @@ main(int argc, char **argv) opterr = 0; while ((op = getopt(argc, argv, - "AaB:c:D:deE:fF:i:IlLnNOopqr:s:StT:vw:xXy:Y")) != -1) + "AaB:c:D:deE:fF:i:IlLnNOopqr:R:s:StT:vw:xXy:Y")) != -1) switch (op) { case 'A': @@ -330,6 +343,11 @@ main(int argc, char **argv) RFileName = optarg; break; + case 'R': + samplerate = strtorate(optarg); + /* strtorate will err on failure */ + break; + case 's': snaplen = strtonum(optarg, 1, INT_MAX, &errstr); if (errstr) @@ -458,7 +476,7 @@ main(int argc, char **argv) error("%s", ebuf); } pd = priv_pcap_live(device, snaplen, !pflag, 1000, ebuf, - dlt, dirfilt, Bflag); + dlt, dirfilt, Bflag, samplerate); if (pd == NULL) error("%s", ebuf); @@ -723,6 +741,7 @@ usage(void) (void)fprintf(stderr, "\t [-E [espalg:]espkey] [-F file] [-i interface] [-r file]\n"); (void)fprintf(stderr, -"\t [-s snaplen] [-T type] [-w file] [-y datalinktype] [expression]\n"); +"\t [-R samplerate] [-s snaplen] [-T type] [-w file]\n" +"\t [-y datalinktype] [expression]\n"); exit(1); } Index: sys/net/bpf.c =================================================================== RCS file: /cvs/src/sys/net/bpf.c,v retrieving revision 1.192 diff -u -p -r1.192 bpf.c --- sys/net/bpf.c 18 Jun 2020 23:32:00 -0000 1.192 +++ sys/net/bpf.c 20 Jul 2020 09:11:30 -0000 @@ -700,6 +700,7 @@ bpfioctl(dev_t dev, u_long cmd, caddr_t case BIOCIMMEDIATE: case TIOCGPGRP: case BIOCGDIRFILT: + case BIOCGSAMPLE: break; default: return (EPERM); @@ -959,6 +960,14 @@ bpfioctl(dev_t dev, u_long cmd, caddr_t (BPF_DIRECTION_IN|BPF_DIRECTION_OUT); break; + case BIOCGSAMPLE: /* get sample threshold */ + *(u_int *)addr = d->bd_sample; + break; + + case BIOCSSAMPLE: /* set sample threshold */ + d->bd_sample = *(u_int *)addr; + break; + case FIONBIO: /* Non-blocking I/O */ if (*(int *)addr) d->bd_rnonblock = 1; @@ -1284,6 +1293,7 @@ _bpf_mtap(caddr_t arg, const struct mbuf SMR_SLIST_FOREACH(d, &bp->bif_dlist, bd_next) { struct bpf_program_smr *bps; struct bpf_insn *fcode = NULL; + unsigned int sample; atomic_inc_long(&d->bd_rcount); @@ -1294,9 +1304,13 @@ _bpf_mtap(caddr_t arg, const struct mbuf if (bps != NULL) fcode = bps->bps_bf.bf_insns; slen = bpf_mfilter(fcode, m, pktlen); - if (slen == 0) continue; + + sample = d->bd_sample; + if (sample && arc4random() > sample) + continue; + if (d->bd_fildrop != BPF_FILDROP_PASS) drop = 1; if (d->bd_fildrop != BPF_FILDROP_DROP) { Index: sys/net/bpf.h =================================================================== RCS file: /cvs/src/sys/net/bpf.h,v retrieving revision 1.69 diff -u -p -r1.69 bpf.h --- sys/net/bpf.h 18 Jun 2020 23:27:58 -0000 1.69 +++ sys/net/bpf.h 20 Jul 2020 09:11:30 -0000 @@ -119,6 +119,8 @@ struct bpf_version { #define BIOCGDLTLIST _IOWR('B',123, struct bpf_dltlist) #define BIOCGDIRFILT _IOR('B',124, u_int) #define BIOCSDIRFILT _IOW('B',125, u_int) +#define BIOCGSAMPLE _IOR('B',126, u_int) /* get sample threshold */ +#define BIOCSSAMPLE _IOW('B',126, u_int) /* set sample threshold */ /* * Direction filters for BIOCSDIRFILT/BIOCGDIRFILT Index: sys/net/bpfdesc.h =================================================================== RCS file: /cvs/src/sys/net/bpfdesc.h,v retrieving revision 1.41 diff -u -p -r1.41 bpfdesc.h --- sys/net/bpfdesc.h 13 May 2020 21:34:37 -0000 1.41 +++ sys/net/bpfdesc.h 20 Jul 2020 09:11:30 -0000 @@ -88,6 +88,7 @@ struct bpf_d { u_char bd_locked; /* true if descriptor is locked */ u_char bd_fildrop; /* true if filtered packets will be dropped */ u_char bd_dirfilt; /* direction filter */ + unsigned int bd_sample; /* sample rate */ int bd_hdrcmplt; /* false to fill in src lladdr automatically */ int bd_async; /* non-zero if packet reception should generate signal */ int bd_sig; /* signal to send upon packet reception */