1 | /* $NetBSD: ipf.c,v 1.3 2018/02/04 08:19:42 mrg 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 | |
66 | static void usage() |
67 | { |
68 | fprintf(stderr, "usage: ipf [-6AdDEInoPrRsvVyzZ] %s %s %s\n" , |
69 | "[-l block|pass|nomatch|state|nat]" , "[-cc] [-F i|o|a|s|S|u]" , |
70 | "[-f filename] [-T <tuneopts>]" ); |
71 | exit(1); |
72 | } |
73 | |
74 | |
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 | |
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 | |
203 | static void closedevice() |
204 | { |
205 | close(fd); |
206 | fd = -1; |
207 | } |
208 | |
209 | |
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 | |
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 | |
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 | |
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 | |
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 | |
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 | |
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 | |
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 | |
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 | */ |
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 | |
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 | |