xref: /netbsd-src/usr.sbin/npf/npfctl/npfctl.c (revision 4817a0b0b8fe9612e8ebe21a9bf2d97b95038a97)
1 /*	$NetBSD: npfctl.c,v 1.3 2010/12/18 01:07:26 rmind Exp $	*/
2 
3 /*-
4  * Copyright (c) 2009-2010 The NetBSD Foundation, Inc.
5  * All rights reserved.
6  *
7  * This material is based upon work partially supported by The
8  * NetBSD Foundation under a contract with 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: npfctl.c,v 1.3 2010/12/18 01:07:26 rmind Exp $");
34 
35 #include <sys/ioctl.h>
36 #include <sys/stat.h>
37 #include <sys/types.h>
38 
39 #include <stdio.h>
40 #include <stdlib.h>
41 #include <string.h>
42 #include <err.h>
43 #include <fcntl.h>
44 #include <unistd.h>
45 
46 #include "npfctl.h"
47 
48 #define	NPFCTL_START		1
49 #define	NPFCTL_STOP		2
50 #define	NPFCTL_RELOAD		3
51 #define	NPFCTL_FLUSH		4
52 #define	NPFCTL_TABLE		5
53 #define	NPFCTL_STATS		6
54 #define	NPFCTL_SESSIONS_SAVE	7
55 #define	NPFCTL_SESSIONS_LOAD	8
56 
57 static struct operations_s {
58 	const char *		cmd;
59 	int			action;
60 } operations[] = {
61 	/* Start, stop, reload */
62 	{	"start",		NPFCTL_START		},
63 	{	"stop",			NPFCTL_STOP		},
64 	{	"reload",		NPFCTL_RELOAD		},
65 	{	"flush",		NPFCTL_FLUSH		},
66 	/* Table */
67 	{	"table",		NPFCTL_TABLE		},
68 	/* Stats */
69 	{	"stats",		NPFCTL_STATS		},
70 	/* Sessions */
71 	{	"sess-save",		NPFCTL_SESSIONS_SAVE	},
72 	{	"sess-load",		NPFCTL_SESSIONS_LOAD	},
73 	/* --- */
74 	{	NULL,			0			}
75 };
76 
77 void *
78 zalloc(size_t sz)
79 {
80 	void *p;
81 
82 	p = malloc(sz);
83 	if (p == NULL) {
84 		perror("zalloc");
85 		exit(EXIT_FAILURE);
86 	}
87 	memset(p, 0, sz);
88 	return p;
89 }
90 
91 char *
92 xstrdup(const char *s)
93 {
94 	char *p;
95 
96 	p = strdup(s);
97 	if (p == NULL) {
98 		perror("xstrdup");
99 		exit(EXIT_FAILURE);
100 	}
101 	return p;
102 }
103 
104 static void
105 usage(void)
106 {
107 	const char *progname = getprogname();
108 
109 	fprintf(stderr,
110 	    "usage:\t%s [ start | stop | reload | flush | stats ]\n",
111 	    progname);
112 	fprintf(stderr,
113 	    "usage:\t%s [ sess-save | sess-load ]\n",
114 	    progname);
115 	fprintf(stderr,
116 	    "\t%s table <tid> [ flush ]\n",
117 	    progname);
118 	fprintf(stderr,
119 	    "\t%s table <tid> { add | rem } <address/mask>\n",
120 	    progname);
121 
122 	exit(EXIT_FAILURE);
123 }
124 
125 static void
126 npfctl_parsecfg(const char *cfg)
127 {
128 	char *buf, *p;
129 	FILE *fp;
130 	size_t n;
131 	int l;
132 
133 	fp = fopen(cfg, "r");
134 	if (fp == NULL) {
135 		err(EXIT_FAILURE, "fopen");
136 	}
137 	l = 0;
138 	buf = NULL;
139 	while (getline(&buf, &n, fp) != -1) {
140 		l++;
141 		p = strpbrk(buf, "#\n");
142 		if (p != NULL) {
143 			*p = '\0';
144 		}
145 		if (npf_parseline(buf)) {
146 			fprintf(stderr, "invalid syntax at line %d\n", l);
147 			exit(EXIT_FAILURE);
148 		}
149 	}
150 	if (buf != NULL) {
151 		free(buf);
152 	}
153 }
154 
155 static int
156 npfctl_print_stats(int fd)
157 {
158 	uint64_t *st = malloc(NPF_STATS_SIZE);
159 
160 	if (ioctl(fd, IOC_NPF_STATS, &st) != 0) {
161 		err(EXIT_FAILURE, "ioctl(IOC_NPF_STATS)");
162 	}
163 
164 	printf("Packets passed:\n\t%"PRIu64" default pass\n\t"
165 	    "%"PRIu64 " ruleset pass\n\t%"PRIu64" session pass\n\n",
166 	    st[NPF_STAT_PASS_DEFAULT], st[NPF_STAT_PASS_RULESET],
167 	    st[NPF_STAT_PASS_SESSION]);
168 
169 	printf("Packets blocked:\n\t%"PRIu64" default block\n\t"
170 	    "%"PRIu64 " ruleset block\n\n", st[NPF_STAT_BLOCK_DEFAULT],
171 	    st[NPF_STAT_BLOCK_RULESET]);
172 
173 	printf("Session and NAT entries:\n\t%"PRIu64" session allocations\n\t"
174 	    "%"PRIu64" session destructions\n\t%"PRIu64" NAT entry allocations\n\t"
175 	    "%"PRIu64" NAT entry destructions\n\n", st[NPF_STAT_SESSION_CREATE],
176 	    st[NPF_STAT_SESSION_DESTROY], st[NPF_STAT_NAT_CREATE],
177 	    st[NPF_STAT_NAT_DESTROY]);
178 
179 	printf("Invalid packet state cases:\n\t%"PRIu64" cases in total\n\t"
180 	    "%"PRIu64" TCP case I\n\t%"PRIu64" TCP case II\n\t%"PRIu64
181 	    " TCP case III\n\n", st[NPF_STAT_INVALID_STATE],
182 	    st[NPF_STAT_INVALID_STATE_TCP1], st[NPF_STAT_INVALID_STATE_TCP2],
183 	    st[NPF_STAT_INVALID_STATE_TCP3]);
184 
185 	printf("Packet race cases:\n\t%"PRIu64" NAT association race\n\t"
186 	    "%"PRIu64" duplicate session race\n", st[NPF_STAT_RACE_NAT],
187 	    st[NPF_STAT_RACE_SESSION]);
188 
189 	free(st);
190 	return 0;
191 }
192 
193 static void
194 npfctl(int action, int argc, char **argv)
195 {
196 	int fd, ret, ver, boolval;
197 	npf_ioctl_table_t tbl;
198 	char *arg;
199 
200 #ifndef DEBUG
201 	fd = open(NPF_DEV_PATH, O_RDONLY);
202 	if (fd == -1) {
203 		err(EXIT_FAILURE, "cannot open " NPF_DEV_PATH);
204 	}
205 	ret = ioctl(fd, IOC_NPF_VERSION, &ver);
206 	if (ver != NPF_VERSION) {
207 		errx(EXIT_FAILURE, "incompatible npf interface version "
208 		    "(%d, kernel %d)", NPF_VERSION, ver);
209 	}
210 #endif
211 	switch (action) {
212 	case NPFCTL_START:
213 		boolval = true;
214 		ret = ioctl(fd, IOC_NPF_SWITCH, &boolval);
215 		break;
216 	case NPFCTL_STOP:
217 		boolval = false;
218 		ret = ioctl(fd, IOC_NPF_SWITCH, &boolval);
219 		break;
220 	case NPFCTL_RELOAD:
221 		npfctl_init_data();
222 #ifdef DEBUG
223 		npfctl_parsecfg("npf.conf");
224 		return npfctl_ioctl_send(0);
225 #endif
226 		npfctl_parsecfg(argc < 3 ? NPF_CONF_PATH : argv[2]);
227 		ret = npfctl_ioctl_send(fd);
228 		break;
229 	case NPFCTL_FLUSH:
230 		/* Pass empty configuration to flush. */
231 		npfctl_init_data();
232 		ret = npfctl_ioctl_send(fd);
233 		break;
234 	case NPFCTL_TABLE:
235 		if (argc < 5) {
236 			usage();
237 		}
238 		tbl.nct_tid = atoi(argv[2]);
239 		if (strcmp(argv[3], "add") == 0) {
240 			tbl.nct_action = NPF_IOCTL_TBLENT_ADD;
241 			arg = argv[4];
242 		} else if (strcmp(argv[3], "rem") == 0) {
243 			tbl.nct_action = NPF_IOCTL_TBLENT_REM;
244 			arg = argv[4];
245 		} else {
246 			tbl.nct_action = 0;
247 			arg = argv[3];
248 		}
249 		if (!npfctl_parse_v4mask(arg,
250 		    &tbl.nct_addr, &tbl.nct_mask)) {
251 			errx(EXIT_FAILURE, "invalid CIDR '%s'", arg);
252 		}
253 		ret = ioctl(fd, IOC_NPF_TABLE, &tbl);
254 		break;
255 	case NPFCTL_STATS:
256 		ret = npfctl_print_stats(fd);
257 		break;
258 	case NPFCTL_SESSIONS_SAVE:
259 		ret = npfctl_ioctl_recvse(fd);
260 		break;
261 	case NPFCTL_SESSIONS_LOAD:
262 		ret = npfctl_ioctl_sendse(fd);
263 		break;
264 	}
265 	if (ret == -1) {
266 		err(EXIT_FAILURE, "ioctl");
267 	}
268 	close(fd);
269 }
270 
271 int
272 main(int argc, char **argv)
273 {
274 	char *cmd;
275 	int n;
276 
277 	if (argc < 2) {
278 		usage();
279 	}
280 	cmd = argv[1];
281 
282 	/* Find and call the subroutine */
283 	for (n = 0; operations[n].cmd != NULL; n++) {
284 		if (strcmp(cmd, operations[n].cmd) != 0)
285 			continue;
286 		npfctl(operations[n].action, argc, argv);
287 		return 0;
288 	}
289 	usage();
290 	return 0;
291 }
292