1/*	$FreeBSD: stable/11/contrib/ipfilter/tools/ipf.c 369245 2021-02-09 13:47:46Z git2svn $	*/
2
3/*
4 * Copyright (C) 2012 by Darren Reed.
5 *
6 * See the IPFILTER.LICENCE file for details on licencing.
7 */
8#include "ipf.h"
9#include <fcntl.h>
10#include <ctype.h>
11#include <sys/ioctl.h>
12#include "netinet/ipl.h"
13
14#if !defined(lint)
15static const char sccsid[] = "@(#)ipf.c	1.23 6/5/96 (C) 1993-2000 Darren Reed";
16static const char rcsid[] = "@(#)$Id$";
17#endif
18
19#if !defined(__SVR4) && defined(__GNUC__)
20extern	char	*index(const char *, int);
21#endif
22
23extern	char	*optarg;
24extern	int	optind;
25extern	frentry_t *frtop;
26
27
28void	ipf_frsync(void);
29void	zerostats(void);
30int	main(int, char *[]);
31
32int	opts = 0;
33int	outputc = 0;
34int	use_inet6 = 0;
35int	exitstatus = 0;
36
37static	void	procfile(char *);
38static	void	flushfilter(char *, int *);
39static	void	set_state(u_int);
40static	void	showstats(friostat_t *);
41static	void	packetlogon(char *);
42static	void	swapactive(void);
43static	int	opendevice(char *, int);
44static	void	closedevice(void);
45static	char	*ipfname = IPL_NAME;
46static	void	usage(void);
47static	int	showversion(void);
48static	int	get_flags(void);
49static	int	ipf_interceptadd(int, ioctlfunc_t, void *);
50
51static	int	fd = -1;
52static	ioctlfunc_t	iocfunctions[IPL_LOGSIZE] = { ioctl, ioctl, ioctl,
53						      ioctl, ioctl, ioctl,
54						      ioctl, ioctl };
55
56/* XXX	The following was added to satisfy a rescue/rescue/ build
57   XXX	requirement.  */
58int	nohdrfields;
59
60static void usage()
61{
62	fprintf(stderr, "usage: ipf [-6AdDEInoPrRsvVyzZ] %s %s %s\n",
63		"[-l block|pass|nomatch|state|nat]", "[-cc] [-F i|o|a|s|S|u]",
64		"[-f filename] [-T <tuneopts>]");
65	exit(1);
66}
67
68
69int main(argc,argv)
70	int argc;
71	char *argv[];
72{
73	int c, *filter = NULL;
74
75	if (argc < 2)
76		usage();
77
78	assigndefined(getenv("IPF_PREDEFINED"));
79
80	while ((c = getopt(argc, argv, "46Ac:dDEf:F:Il:m:noPrRsT:vVyzZ")) != -1) {
81		switch (c)
82		{
83		case '?' :
84			usage();
85			break;
86		case '4' :
87			use_inet6 = -1;
88			break;
89		case '6' :
90			use_inet6 = 1;
91			break;
92		case 'A' :
93			opts &= ~OPT_INACTIVE;
94			break;
95		case 'c' :
96			if (strcmp(optarg, "c") == 0)
97				outputc = 1;
98			break;
99		case 'E' :
100			set_state((u_int)1);
101			break;
102		case 'D' :
103			set_state((u_int)0);
104			break;
105		case 'd' :
106			opts ^= OPT_DEBUG;
107			break;
108		case 'f' :
109			procfile(optarg);
110			break;
111		case 'F' :
112			flushfilter(optarg, filter);
113			break;
114		case 'I' :
115			opts ^= OPT_INACTIVE;
116			break;
117		case 'l' :
118			packetlogon(optarg);
119			break;
120		case 'm' :
121			filter = parseipfexpr(optarg, NULL);
122			break;
123		case 'n' :
124			opts ^= OPT_DONOTHING|OPT_DONTOPEN;
125			break;
126		case 'o' :
127			break;
128		case 'P' :
129			ipfname = IPAUTH_NAME;
130			break;
131		case 'R' :
132			opts ^= OPT_NORESOLVE;
133			break;
134		case 'r' :
135			opts ^= OPT_REMOVE;
136			break;
137		case 's' :
138			swapactive();
139			break;
140		case 'T' :
141			if (opendevice(ipfname, 1) >= 0)
142				ipf_dotuning(fd, optarg, ioctl);
143			break;
144		case 'v' :
145			opts += OPT_VERBOSE;
146			break;
147		case 'V' :
148			if (showversion())
149				exit(1);
150			break;
151		case 'y' :
152			ipf_frsync();
153			break;
154		case 'z' :
155			opts ^= OPT_ZERORULEST;
156			break;
157		case 'Z' :
158			zerostats();
159			break;
160		}
161	}
162
163	if (optind < 2)
164		usage();
165
166	if (fd != -1)
167		(void) close(fd);
168
169	return(exitstatus);
170	/* NOTREACHED */
171}
172
173
174static int opendevice(ipfdev, check)
175	char *ipfdev;
176	int check;
177{
178	if (opts & OPT_DONOTHING)
179		return -2;
180
181	if (check && checkrev(ipfname) == -1) {
182		fprintf(stderr, "User/kernel version check failed\n");
183		return -2;
184	}
185
186	if (!ipfdev)
187		ipfdev = ipfname;
188
189	if (fd == -1)
190		if ((fd = open(ipfdev, O_RDWR)) == -1)
191			if ((fd = open(ipfdev, O_RDONLY)) == -1)
192				ipferror(fd, "open device");
193	return fd;
194}
195
196
197static void closedevice()
198{
199	close(fd);
200	fd = -1;
201}
202
203
204static	int	get_flags()
205{
206	int i = 0;
207
208	if ((opendevice(ipfname, 1) != -2) &&
209	    (ioctl(fd, SIOCGETFF, &i) == -1)) {
210		ipferror(fd, "SIOCGETFF");
211		return 0;
212	}
213	return i;
214}
215
216
217static	void	set_state(enable)
218	u_int	enable;
219{
220	if (opendevice(ipfname, 0) != -2) {
221		if (ioctl(fd, SIOCFRENB, &enable) == -1) {
222			if (errno == EBUSY) {
223				fprintf(stderr,
224					"IP FIlter: already initialized\n");
225			} else {
226				ipferror(fd, "SIOCFRENB");
227			}
228		}
229	}
230	return;
231}
232
233
234static	void	procfile(file)
235	char	*file;
236{
237	(void) opendevice(ipfname, 1);
238
239	initparse();
240
241	ipf_parsefile(fd, ipf_interceptadd, iocfunctions, file);
242
243	if (outputc) {
244		printC(0);
245		printC(1);
246		emit(-1, -1, NULL, NULL);
247	}
248}
249
250
251static int ipf_interceptadd(fd, ioctlfunc, ptr)
252	int fd;
253	ioctlfunc_t ioctlfunc;
254	void *ptr;
255{
256	if (outputc)
257		printc(ptr);
258
259	if (ipf_addrule(fd, ioctlfunc, ptr) != 0)
260		exitstatus = 1;
261	return 0;
262}
263
264
265static void packetlogon(opt)
266	char	*opt;
267{
268	int	flag, xfd, logopt, change = 0;
269
270	flag = get_flags();
271	if (flag != 0) {
272		if ((opts & (OPT_DONOTHING|OPT_VERBOSE)) == OPT_VERBOSE)
273			printf("log flag is currently %#x\n", flag);
274	}
275
276	flag &= ~(FF_LOGPASS|FF_LOGNOMATCH|FF_LOGBLOCK);
277
278	if (strstr(opt, "pass")) {
279		flag |= FF_LOGPASS;
280		if (opts & OPT_VERBOSE)
281			printf("set log flag: pass\n");
282		change = 1;
283	}
284	if (strstr(opt, "nomatch")) {
285		flag |= FF_LOGNOMATCH;
286		if (opts & OPT_VERBOSE)
287			printf("set log flag: nomatch\n");
288		change = 1;
289	}
290	if (strstr(opt, "block") || strchr(opt, 'd')) {
291		flag |= FF_LOGBLOCK;
292		if (opts & OPT_VERBOSE)
293			printf("set log flag: block\n");
294		change = 1;
295	}
296	if (strstr(opt, "none")) {
297		if (opts & OPT_VERBOSE)
298			printf("disable all log flags\n");
299		change = 1;
300	}
301
302	if (change == 1) {
303		if (opendevice(ipfname, 1) != -2 &&
304		    (ioctl(fd, SIOCSETFF, &flag) != 0))
305			ipferror(fd, "ioctl(SIOCSETFF)");
306	}
307
308	if ((opts & (OPT_DONOTHING|OPT_VERBOSE)) == OPT_VERBOSE) {
309		flag = get_flags();
310		printf("log flags are now %#x\n", flag);
311	}
312
313	if (strstr(opt, "state")) {
314		if (opts & OPT_VERBOSE)
315			printf("set state log flag\n");
316		xfd = open(IPSTATE_NAME, O_RDWR);
317		if (xfd >= 0) {
318			logopt = 0;
319			if (ioctl(xfd, SIOCGETLG, &logopt))
320				ipferror(fd, "ioctl(SIOCGETLG)");
321			else {
322				logopt = 1 - logopt;
323				if (ioctl(xfd, SIOCSETLG, &logopt))
324					ipferror(xfd, "ioctl(SIOCSETLG)");
325			}
326			close(xfd);
327		}
328	}
329
330	if (strstr(opt, "nat")) {
331		if (opts & OPT_VERBOSE)
332			printf("set nat log flag\n");
333		xfd = open(IPNAT_NAME, O_RDWR);
334		if (xfd >= 0) {
335			logopt = 0;
336			if (ioctl(xfd, SIOCGETLG, &logopt))
337				ipferror(xfd, "ioctl(SIOCGETLG)");
338			else {
339				logopt = 1 - logopt;
340				if (ioctl(xfd, SIOCSETLG, &logopt))
341					ipferror(xfd, "ioctl(SIOCSETLG)");
342			}
343			close(xfd);
344		}
345	}
346}
347
348
349static void flushfilter(arg, filter)
350	char *arg;
351	int *filter;
352{
353	int	fl = 0, rem;
354
355	if (!arg || !*arg)
356		return;
357	if (!strcmp(arg, "s") || !strcmp(arg, "S") || ISDIGIT(*arg)) {
358		if (*arg == 'S')
359			fl = 0;
360		else if (*arg == 's')
361			fl = 1;
362		else
363			fl = atoi(arg);
364		rem = fl;
365
366		closedevice();
367		if (opendevice(IPSTATE_NAME, 1) == -2)
368			exit(1);
369
370		if (!(opts & OPT_DONOTHING)) {
371			if (use_inet6) {
372				fprintf(stderr,
373					"IPv6 rules are no longer seperate\n");
374			} else if (filter != NULL) {
375				ipfobj_t obj;
376
377				obj.ipfo_rev = IPFILTER_VERSION;
378				obj.ipfo_size = filter[0] * sizeof(int);
379				obj.ipfo_type = IPFOBJ_IPFEXPR;
380				obj.ipfo_ptr = filter;
381				if (ioctl(fd, SIOCMATCHFLUSH, &obj) == -1) {
382					ipferror(fd, "ioctl(SIOCMATCHFLUSH)");
383					fl = -1;
384				} else {
385					fl = obj.ipfo_retval;
386				}
387			} else {
388				if (ioctl(fd, SIOCIPFFL, &fl) == -1) {
389					ipferror(fd, "ioctl(SIOCIPFFL)");
390					exit(1);
391				}
392			}
393		}
394		if ((opts & (OPT_DONOTHING|OPT_DEBUG)) == OPT_DEBUG) {
395			printf("remove flags %s (%d)\n", arg, rem);
396		}
397		if ((opts & (OPT_DONOTHING|OPT_VERBOSE)) == OPT_VERBOSE) {
398			printf("%d state entries removed\n", fl);
399		}
400		closedevice();
401		return;
402	} else if (strchr(arg, 'i') || strchr(arg, 'I'))
403		fl = FR_INQUE;
404	else if (strchr(arg, 'o') || strchr(arg, 'O'))
405		fl = FR_OUTQUE;
406	else if (strchr(arg, 'a') || strchr(arg, 'A'))
407		fl = FR_OUTQUE|FR_INQUE;
408	else {
409		fprintf(stderr, "Incorrect flush argument: %s\n", arg);
410		usage();
411	}
412	if (opts & OPT_INACTIVE)
413		fl |= FR_INACTIVE;
414	rem = fl;
415
416	if (opendevice(ipfname, 1) == -2)
417		exit(1);
418
419	if (!(opts & OPT_DONOTHING)) {
420		if (use_inet6) {
421			if (ioctl(fd, SIOCIPFL6, &fl) == -1) {
422				ipferror(fd, "ioctl(SIOCIPFL6)");
423				exit(1);
424			}
425		} else {
426			if (ioctl(fd, SIOCIPFFL, &fl) == -1) {
427				ipferror(fd, "ioctl(SIOCIPFFL)");
428				exit(1);
429			}
430		}
431	}
432
433	if ((opts & (OPT_DONOTHING|OPT_DEBUG)) == OPT_DEBUG) {
434		printf("remove flags %s%s (%d)\n", (rem & FR_INQUE) ? "I" : "",
435			(rem & FR_OUTQUE) ? "O" : "", rem);
436	}
437	if ((opts & (OPT_DONOTHING|OPT_VERBOSE)) == OPT_VERBOSE) {
438		printf("%d filter rules removed\n", fl);
439	}
440	return;
441}
442
443
444static void swapactive()
445{
446	int in = 2;
447
448	if (opendevice(ipfname, 1) != -2 && ioctl(fd, SIOCSWAPA, &in) == -1)
449		ipferror(fd, "ioctl(SIOCSWAPA)");
450	else
451		printf("Set %d now inactive\n", in);
452}
453
454
455void ipf_frsync()
456{
457	int frsyn = 0;
458
459	if (opendevice(ipfname, 1) != -2 && ioctl(fd, SIOCFRSYN, &frsyn) == -1)
460		ipferror(fd, "SIOCFRSYN");
461	else
462		printf("filter sync'd\n");
463}
464
465
466void zerostats()
467{
468	ipfobj_t	obj;
469	friostat_t	fio;
470
471	obj.ipfo_rev = IPFILTER_VERSION;
472	obj.ipfo_type = IPFOBJ_IPFSTAT;
473	obj.ipfo_size = sizeof(fio);
474	obj.ipfo_ptr = &fio;
475	obj.ipfo_offset = 0;
476
477	if (opendevice(ipfname, 1) != -2) {
478		if (ioctl(fd, SIOCFRZST, &obj) == -1) {
479			ipferror(fd, "ioctl(SIOCFRZST)");
480			exit(-1);
481		}
482		showstats(&fio);
483	}
484
485}
486
487
488/*
489 * read the kernel stats for packets blocked and passed
490 */
491static void showstats(fp)
492	friostat_t	*fp;
493{
494	printf("bad packets:\t\tin %lu\tout %lu\n",
495			fp->f_st[0].fr_bad, fp->f_st[1].fr_bad);
496	printf(" input packets:\t\tblocked %lu passed %lu nomatch %lu",
497			fp->f_st[0].fr_block, fp->f_st[0].fr_pass,
498			fp->f_st[0].fr_nom);
499	printf(" counted %lu\n", fp->f_st[0].fr_acct);
500	printf("output packets:\t\tblocked %lu passed %lu nomatch %lu",
501			fp->f_st[1].fr_block, fp->f_st[1].fr_pass,
502			fp->f_st[1].fr_nom);
503	printf(" counted %lu\n", fp->f_st[0].fr_acct);
504	printf(" input packets logged:\tblocked %lu passed %lu\n",
505			fp->f_st[0].fr_bpkl, fp->f_st[0].fr_ppkl);
506	printf("output packets logged:\tblocked %lu passed %lu\n",
507			fp->f_st[1].fr_bpkl, fp->f_st[1].fr_ppkl);
508}
509
510
511static int showversion()
512{
513	struct friostat fio;
514	ipfobj_t ipfo;
515	u_32_t flags;
516	char *s;
517	int vfd;
518
519	bzero((caddr_t)&ipfo, sizeof(ipfo));
520	ipfo.ipfo_rev = IPFILTER_VERSION;
521	ipfo.ipfo_size = sizeof(fio);
522	ipfo.ipfo_ptr = (void *)&fio;
523	ipfo.ipfo_type = IPFOBJ_IPFSTAT;
524
525	printf("ipf: %s (%d)\n", IPL_VERSION, (int)sizeof(frentry_t));
526
527	if ((vfd = open(ipfname, O_RDONLY)) == -1) {
528		perror("open device");
529		return 1;
530	}
531
532	if (ioctl(vfd, SIOCGETFS, &ipfo)) {
533		ipferror(vfd, "ioctl(SIOCGETFS)");
534		close(vfd);
535		return 1;
536	}
537	close(vfd);
538	flags = get_flags();
539
540	printf("Kernel: %-*.*s\n", (int)sizeof(fio.f_version),
541		(int)sizeof(fio.f_version), fio.f_version);
542	printf("Running: %s\n", (fio.f_running > 0) ? "yes" : "no");
543	printf("Log Flags: %#x = ", flags);
544	s = "";
545	if (flags & FF_LOGPASS) {
546		printf("pass");
547		s = ", ";
548	}
549	if (flags & FF_LOGBLOCK) {
550		printf("%sblock", s);
551		s = ", ";
552	}
553	if (flags & FF_LOGNOMATCH) {
554		printf("%snomatch", s);
555		s = ", ";
556	}
557	if (flags & FF_BLOCKNONIP) {
558		printf("%snonip", s);
559		s = ", ";
560	}
561	if (!*s)
562		printf("none set");
563	putchar('\n');
564
565	printf("Default: ");
566	if (FR_ISPASS(fio.f_defpass))
567		s = "pass";
568	else if (FR_ISBLOCK(fio.f_defpass))
569		s = "block";
570	else
571		s = "nomatch -> block";
572	printf("%s all, Logging: %savailable\n", s, fio.f_logging ? "" : "un");
573	printf("Active list: %d\n", fio.f_active);
574	printf("Feature mask: %#x\n", fio.f_features);
575
576	return 0;
577}
578