1 /* $FreeBSD$ */
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)
15 static const char sccsid[] = "@(#)ipf.c 1.23 6/5/96 (C) 1993-2000 Darren Reed";
16 static const char rcsid[] = "@(#)$Id$";
17 #endif
18
19 #if !defined(__SVR4) && defined(__GNUC__)
20 extern char *index __P((const char *, int));
21 #endif
22
23 extern char *optarg;
24 extern int optind;
25 extern frentry_t *frtop;
26
27
28 void ipf_frsync __P((void));
29 void zerostats __P((void));
30 int main __P((int, char *[]));
31
32 int opts = 0;
33 int outputc = 0;
34 int use_inet6 = 0;
35 int exitstatus = 0;
36
37 static void procfile __P((char *));
38 static void flushfilter __P((char *, int *));
39 static void set_state __P((u_int));
40 static void showstats __P((friostat_t *));
41 static void packetlogon __P((char *));
42 static void swapactive __P((void));
43 static int opendevice __P((char *, int));
44 static void closedevice __P((void));
45 static char *ipfname = IPL_NAME;
46 static void usage __P((void));
47 static int showversion __P((void));
48 static int get_flags __P((void));
49 static int ipf_interceptadd __P((int, ioctlfunc_t, void *));
50
51 static int fd = -1;
52 static 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. */
58 int nohdrfields;
59
usage()60 static 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
main(argc,argv)69 int 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
opendevice(ipfdev,check)174 static 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
closedevice()197 static void closedevice()
198 {
199 close(fd);
200 fd = -1;
201 }
202
203
get_flags()204 static 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
set_state(enable)217 static 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
procfile(file)234 static 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
ipf_interceptadd(fd,ioctlfunc,ptr)251 static 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
packetlogon(opt)265 static 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
flushfilter(arg,filter)349 static 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
swapactive()444 static 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
ipf_frsync()455 void 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
zerostats()466 void 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 */
showstats(fp)491 static 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
showversion()511 static 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