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