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__)
15 extern char *index(const char *, int);
16 #endif
17
18 extern char *optarg;
19 extern int optind;
20 extern frentry_t *frtop;
21
22
23 void ipf_frsync(void);
24 void zerostats(void);
25 int main(int, char *[]);
26
27 int opts = 0;
28 int outputc = 0;
29 int use_inet6 = 0;
30 int exitstatus = 0;
31
32 static void procfile(char *);
33 static void flushfilter(char *, int *);
34 static void set_state(u_int);
35 static void showstats(friostat_t *);
36 static void packetlogon(char *);
37 static void swapactive(void);
38 static int opendevice(char *, int);
39 static void closedevice(void);
40 static char *ipfname = IPL_NAME;
41 static void usage(void);
42 static int showversion(void);
43 static int get_flags(void);
44 static int ipf_interceptadd(int, ioctlfunc_t, void *);
45
46 static int fd = -1;
47 static 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. */
53 int nohdrfields;
54
usage()55 static 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
64 int
main(int argc,char * argv[])65 main(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
168 static int
opendevice(char * ipfdev,int check)169 opendevice(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
190 static void
closedevice(void)191 closedevice(void)
192 {
193 close(fd);
194 fd = -1;
195 }
196
197
198 static int
get_flags(void)199 get_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
212 static void
set_state(u_int enable)213 set_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
229 static void
procfile(char * file)230 procfile(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
246 static int
ipf_interceptadd(int fd,ioctlfunc_t ioctlfunc,void * ptr)247 ipf_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
258 static void
packetlogon(char * opt)259 packetlogon(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
342 static void
flushfilter(char * arg,int * filter)343 flushfilter(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
436 static void
swapactive(void)437 swapactive(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
448 void
ipf_frsync(void)449 ipf_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
460 void
zerostats(void)461 zerostats(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 */
486 static void
showstats(friostat_t * fp)487 showstats(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
506 static int
showversion(void)507 showversion(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