This moves the BIOCGSTATS ioctl operation done by the tcpdump process
(at ^C time, but not at -c count expiration) into a service provided
by the privsep monitor.
Had a bit of help from canacar, who wrote the original privsep code
with otto.
Will be needed for "tame".
Index: privsep.c
===================================================================
RCS file: /cvs/src/usr.sbin/tcpdump/privsep.c,v
retrieving revision 1.33
diff -u -p -u -r1.33 privsep.c
--- privsep.c 15 Mar 2015 00:41:28 -0000 1.33
+++ privsep.c 12 Jul 2015 05:42:29 -0000
@@ -20,6 +20,7 @@
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/wait.h>
+#include <sys/ioctl.h>
#include <netinet/in.h>
#include <net/if.h>
@@ -59,7 +60,8 @@ enum priv_state {
STATE_INIT, /* initial state */
STATE_BPF, /* input file/device opened */
STATE_FILTER, /* filter applied */
- STATE_RUN /* running and accepting network traffic */
+ STATE_RUN, /* running and accepting network traffic */
+ STATE_EXIT /* in the process of dying */
};
#define ALLOW(action) (1 << (action))
@@ -76,7 +78,8 @@ static const int allowed_max[] = {
ALLOW(PRIV_ETHER_NTOHOST) | ALLOW(PRIV_INIT_DONE),
/* RUN */ ALLOW(PRIV_GETHOSTBYADDR) | ALLOW(PRIV_ETHER_NTOHOST) |
ALLOW(PRIV_GETRPCBYNUMBER) | ALLOW(PRIV_GETLINES) |
- ALLOW(PRIV_LOCALTIME)
+ ALLOW(PRIV_LOCALTIME) | ALLOW(PRIV_PCAP_STATS),
+ /* EXIT */ 0
};
/*
@@ -87,7 +90,9 @@ static int allowed_ext[] = {
/* INIT */ ALLOW(PRIV_SETFILTER),
/* BPF */ ALLOW(PRIV_SETFILTER),
/* FILTER */ ALLOW(PRIV_GETSERVENTRIES),
- /* RUN */ ALLOW(PRIV_GETLINES) | ALLOW(PRIV_LOCALTIME)
+ /* RUN */ ALLOW(PRIV_GETLINES) | ALLOW(PRIV_LOCALTIME) |
+ ALLOW(PRIV_PCAP_STATS),
+ /* EXIT */ 0
};
struct ftab {
@@ -120,6 +125,7 @@ static void impl_getserventries(int);
static void impl_getprotoentries(int);
static void impl_localtime(int fd);
static void impl_getlines(int);
+static void impl_pcap_stats(int, int *);
static void test_state(int, int);
static void logmsg(int, const char *, ...);
@@ -186,6 +192,7 @@ priv_init(int argc, char **argv)
}
sigprocmask(SIG_SETMASK, &oset, NULL);
+ signal(SIGINT, SIG_IGN);
/* Child - drop suid privileges */
gid = getgid();
@@ -303,6 +310,10 @@ priv_init(int argc, char **argv)
test_state(cmd, STATE_RUN);
impl_getlines(socks[0]);
break;
+ case PRIV_PCAP_STATS:
+ test_state(cmd, STATE_RUN);
+ impl_pcap_stats(socks[0], &bpfd);
+ break;
default:
logmsg(LOG_ERR, "[priv]: unknown command %d", cmd);
_exit(1);
@@ -390,8 +401,6 @@ impl_setfilter(int fd, char *cmdbuf, int
if (setfilter(*bpfd, fd, cmdbuf))
logmsg(LOG_DEBUG, "[priv]: setfilter() failed");
- close(*bpfd); /* done with bpf descriptor */
- *bpfd = -1;
}
static void
@@ -401,8 +410,6 @@ impl_init_done(int fd, int *bpfd)
logmsg(LOG_DEBUG, "[priv]: msg PRIV_INIT_DONE received");
- close(*bpfd); /* done with bpf descriptor */
- *bpfd = -1;
ret = 0;
must_write(fd, &ret, sizeof(ret));
}
@@ -581,6 +588,19 @@ impl_getlines(int fd)
fclose(fp);
}
+static void
+impl_pcap_stats(int fd, int *bpfd)
+{
+ struct pcap_stat stats;
+
+ logmsg(LOG_DEBUG, "[priv]: msg PRIV_PCAP_STATS received");
+
+ if (ioctl(*bpfd, BIOCGSTATS, &stats) == -1)
+ write_zero(fd);
+ else
+ must_write(fd, &stats, sizeof(stats));
+}
+
void
priv_init_done(void)
{
@@ -738,6 +758,17 @@ priv_getlines(size_t sz)
write_command(priv_fd, PRIV_GETLINES);
must_write(priv_fd, &sz, sizeof(size_t));
+}
+
+int
+priv_pcap_stats(struct pcap_stat *ps)
+{
+ if (priv_fd < 0)
+ errx(1, "%s: called from privileged portion", __func__);
+
+ write_command(priv_fd, PRIV_PCAP_STATS);
+ must_read(priv_fd, ps, sizeof(*ps));
+ return (0);
}
/* retrieve a line from a file, should be called repeatedly after calling
Index: privsep.h
===================================================================
RCS file: /cvs/src/usr.sbin/tcpdump/privsep.h,v
retrieving revision 1.7
diff -u -p -u -r1.7 privsep.h
--- privsep.h 25 Aug 2009 06:59:17 -0000 1.7
+++ privsep.h 21 May 2015 01:27:53 -0000
@@ -37,7 +37,8 @@ enum cmd_types {
PRIV_GETPROTOENTRIES, /* get the ip protocol entries table */
PRIV_LOCALTIME, /* return localtime */
PRIV_GETLINES, /* get lines from a file */
- PRIV_INIT_DONE /* signal that the initialization is done */
+ PRIV_INIT_DONE, /* signal that the initialization is done */
+ PRIV_PCAP_STATS /* get pcap_stats() results */
};
struct ether_addr;
@@ -80,6 +81,9 @@ void priv_getlines(size_t);
/* Retrieve a single line from a file, should be called repeatedly after
calling priv_getlines() until it returns zero */
size_t priv_getline(char *, size_t);
+
+/* Return the pcap statistics upon completion */
+int priv_pcap_stats(struct pcap_stat *);
pcap_dumper_t *priv_pcap_dump_open(pcap_t *, char *);
Index: tcpdump.c
===================================================================
RCS file: /cvs/src/usr.sbin/tcpdump/tcpdump.c,v
retrieving revision 1.70
diff -u -p -u -r1.70 tcpdump.c
--- tcpdump.c 18 Apr 2015 18:28:38 -0000 1.70
+++ tcpdump.c 12 Jul 2015 05:41:57 -0000
@@ -515,7 +515,7 @@ cleanup(int signo)
/* Can't print the summary if reading from a savefile */
(void)write(STDERR_FILENO, "\n", 1);
if (pd != NULL && pcap_file(pd) == NULL) {
- if (pcap_stats(pd, &stat) < 0) {
+ if (priv_pcap_stats(&stat) < 0) {
(void)snprintf(buf, sizeof buf,
"pcap_stats: %s\n", pcap_geterr(pd));
write(STDERR_FILENO, buf, strlen(buf));