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