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