1 /* $NetBSD: npfd.c,v 1.9 2017/10/16 11:18:43 christos Exp $ */
2
3 /*-
4 * Copyright (c) 2015 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Mindaugas Rasiukevicius.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 */
31
32 #include <sys/cdefs.h>
33 __RCSID("$NetBSD: npfd.c,v 1.9 2017/10/16 11:18:43 christos Exp $");
34
35 #include <stdio.h>
36 #include <string.h>
37 #include <fcntl.h>
38 #include <signal.h>
39 #include <stdlib.h>
40 #include <unistd.h>
41 #include <stdbool.h>
42 #include <poll.h>
43 #include <errno.h>
44 #include <err.h>
45 #include <syslog.h>
46 #include <util.h>
47
48 #include <net/npf.h>
49
50 #include "npfd.h"
51
52 static volatile sig_atomic_t hup, stats, done, flush;
53
54 static int
npfd_getctl(void)55 npfd_getctl(void)
56 {
57 int fd, ver;
58
59 fd = open(NPF_DEV_PATH, O_RDONLY);
60 if (fd == -1) {
61 err(EXIT_FAILURE, "cannot open '%s'", NPF_DEV_PATH);
62 }
63 if (ioctl(fd, IOC_NPF_VERSION, &ver) == -1) {
64 err(EXIT_FAILURE, "ioctl(IOC_NPF_VERSION)");
65 }
66 if (ver != NPF_VERSION) {
67 errx(EXIT_FAILURE,
68 "Incompatible NPF interface version (%d, kernel %d)\n"
69 "Hint: update userland?", NPF_VERSION, ver);
70 }
71 return fd;
72 }
73
74 static void
npfd_event_loop(npfd_log_t * log,int delay)75 npfd_event_loop(npfd_log_t *log, int delay)
76 {
77 struct pollfd pfd;
78 size_t count = 0;
79
80 pfd.fd = npfd_log_getsock(log);
81 pfd.events = POLLHUP | POLLIN;
82
83 while (!done) {
84 if (hup) {
85 hup = false;
86 npfd_log_file_reopen(log, false);
87 }
88 if (stats) {
89 stats = false;
90 npfd_log_stats(log);
91 }
92 if (flush) {
93 flush = false;
94 npfd_log_flush(log);
95 count = 0;
96 }
97 switch (poll(&pfd, 1, delay)) {
98 case -1:
99 if (errno == EINTR)
100 continue;
101 syslog(LOG_ERR, "poll failed: %m");
102 exit(EXIT_FAILURE);
103 /*NOTREACHED*/
104 case 0:
105 npfd_log_flush(log);
106 count = 0;
107 continue;
108 default:
109 if (count++ >= 100) {
110 npfd_log_flush(log);
111 count = 0;
112 }
113 if (npfd_log(log) <= 0)
114 npfd_log_pcap_reopen(log);
115 }
116
117 }
118 npfd_log_destroy(log);
119 }
120
121 static void
sighandler(int sig)122 sighandler(int sig)
123 {
124 switch (sig) {
125 case SIGHUP:
126 hup = true;
127 break;
128 case SIGTERM:
129 case SIGINT:
130 done = true;
131 break;
132 case SIGINFO:
133 stats = true;
134 break;
135 case SIGALRM:
136 flush = true;
137 break;
138 default:
139 syslog(LOG_ERR, "Unhandled signal %d", sig);
140 break;
141 }
142 }
143
144 static __dead void
usage(void)145 usage(void)
146 {
147 fprintf(stderr, "Usage: %s [-D] [-d <delay>] [-i <interface>]"
148 " [-f <filename>] [-p <pidfile>] [-s <snaplen>] expression\n",
149 getprogname());
150 exit(EXIT_FAILURE);
151 }
152
153 static char *
copyargs(int argc,char ** argv)154 copyargs(int argc, char **argv)
155 {
156 if (argc == 0)
157 return NULL;
158
159 size_t len = 0, p = 0;
160 char *buf = NULL;
161
162 for (int i = 0; i < argc; i++) {
163 size_t l = strlen(argv[i]);
164 if (p + l + 1 >= len)
165 buf = erealloc(buf, len = p + l + 1);
166 memcpy(buf + p, argv[i], l);
167 p += l;
168 buf[p++] = i == argc - 1 ? '\0' : ' ';
169 }
170 return buf;
171 }
172
173 int
main(int argc,char ** argv)174 main(int argc, char **argv)
175 {
176 bool daemon_off = false;
177 int ch;
178
179 int delay = 5 * 1000;
180 const char *iface = "npflog0";
181 int snaplen = 116;
182 char *pidname = NULL;
183 char *filename = NULL;
184
185 int fd = npfd_getctl();
186 (void)close(fd);
187
188 while ((ch = getopt(argc, argv, "Dd:f:i:p:s:")) != -1) {
189 switch (ch) {
190 case 'D':
191 daemon_off = true;
192 break;
193 case 'd':
194 delay = atoi(optarg) * 1000;
195 break;
196 case 'f':
197 filename = optarg;
198 break;
199 case 'i':
200 iface = optarg;
201 break;
202 case 'p':
203 pidname = optarg;
204 break;
205 case 's':
206 snaplen = atoi(optarg);
207 break;
208 default:
209 usage();
210 }
211 }
212
213 argc -= optind;
214 argv += optind;
215
216 char *filter = copyargs(argc, argv);
217
218 npfd_log_t *log = npfd_log_create(filename, iface, filter, snaplen);
219
220 if (!daemon_off) {
221 if (daemon(0, 0) == -1)
222 err(EXIT_FAILURE, "daemon");
223 pidfile(pidname);
224 }
225
226 openlog(argv[0], LOG_PID | LOG_NDELAY | LOG_CONS, LOG_DAEMON);
227 signal(SIGHUP, sighandler);
228 signal(SIGINT, sighandler);
229 signal(SIGTERM, sighandler);
230 signal(SIGINFO, sighandler);
231 signal(SIGQUIT, sighandler);
232
233 npfd_event_loop(log, delay);
234
235 closelog();
236
237 return 0;
238 }
239