xref: /netbsd-src/usr.sbin/npf/npfd/npfd.c (revision bdc22b2e01993381dcefeff2bc9b56ca75a4235c)
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
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
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
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
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 *
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
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