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
10 #ifdef __FreeBSD__
11 # ifndef __FreeBSD_cc_version
12 # include <osreldate.h>
13 # else
14 # if __FreeBSD_cc_version < 430000
15 # include <osreldate.h>
16 # endif
17 # endif
18 #endif
19 #include "ipf.h"
20 #include <fcntl.h>
21 #include <sys/ioctl.h>
22 #include "netinet/ipl.h"
23
24 #if !defined(lint)
25 static const char sccsid[] = "@(#)ipf.c 1.23 6/5/96 (C) 1993-2000 Darren Reed";
26 static const char rcsid[] = "@(#)$Id: ipf.c,v 1.35.2.3 2004/12/15 18:27:17 darrenr Exp $";
27 #endif
28
29 #if !defined(__SVR4) && defined(__GNUC__)
30 extern char *index __P((const char *, int));
31 #endif
32
33 extern char *optarg;
34 extern int optind;
35 extern frentry_t *frtop;
36
37
38 void ipf_frsync __P((void));
39 void zerostats __P((void));
40 int main __P((int, char *[]));
41
42 int opts = 0;
43 int outputc = 0;
44 int use_inet6 = 0;
45
46 static void procfile __P((char *, char *)), flushfilter __P((char *));
47 static void set_state __P((u_int)), showstats __P((friostat_t *));
48 static void packetlogon __P((char *)), swapactive __P((void));
49 static int opendevice __P((char *, int));
50 static void closedevice __P((void));
51 static char *ipfname = IPL_NAME;
52 static void usage __P((void));
53 static int showversion __P((void));
54 static int get_flags __P((void));
55 static void ipf_interceptadd __P((int, ioctlfunc_t, void *));
56
57 static int fd = -1;
58 static ioctlfunc_t iocfunctions[IPL_LOGSIZE] = { ioctl, ioctl, ioctl,
59 ioctl, ioctl, ioctl,
60 ioctl, ioctl };
61
62
usage()63 static void usage()
64 {
65 fprintf(stderr, "usage: ipf [-6AdDEInoPrRsvVyzZ] %s %s %s\n",
66 "[-l block|pass|nomatch|state|nat]", "[-cc] [-F i|o|a|s|S|u]",
67 "[-f filename] [-T <tuneopts>]");
68 exit(1);
69 }
70
71
main(argc,argv)72 int main(argc,argv)
73 int argc;
74 char *argv[];
75 {
76 int c;
77
78 if (argc < 2)
79 usage();
80
81 while ((c = getopt(argc, argv, "6Ac:dDEf:F:Il:noPrRsT:vVyzZ")) != -1) {
82 switch (c)
83 {
84 case '?' :
85 usage();
86 break;
87 #ifdef USE_INET6
88 case '6' :
89 use_inet6 = 1;
90 break;
91 #endif
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(argv[0], optarg);
110 break;
111 case 'F' :
112 flushfilter(optarg);
113 break;
114 case 'I' :
115 opts ^= OPT_INACTIVE;
116 break;
117 case 'l' :
118 packetlogon(optarg);
119 break;
120 case 'n' :
121 opts ^= OPT_DONOTHING;
122 break;
123 case 'o' :
124 break;
125 case 'P' :
126 ipfname = IPAUTH_NAME;
127 break;
128 case 'R' :
129 opts ^= OPT_NORESOLVE;
130 break;
131 case 'r' :
132 opts ^= OPT_REMOVE;
133 break;
134 case 's' :
135 swapactive();
136 break;
137 case 'T' :
138 if (opendevice(ipfname, 1) >= 0)
139 ipf_dotuning(fd, optarg, ioctl);
140 break;
141 case 'v' :
142 opts += OPT_VERBOSE;
143 break;
144 case 'V' :
145 if (showversion())
146 exit(1);
147 break;
148 case 'y' :
149 ipf_frsync();
150 break;
151 case 'z' :
152 opts ^= OPT_ZERORULEST;
153 break;
154 case 'Z' :
155 zerostats();
156 break;
157 }
158 }
159
160 if (optind < 2)
161 usage();
162
163 if (fd != -1)
164 (void) close(fd);
165
166 return(0);
167 /* NOTREACHED */
168 }
169
170
opendevice(ipfdev,check)171 static int opendevice(ipfdev, check)
172 char *ipfdev;
173 int check;
174 {
175 if (opts & OPT_DONOTHING)
176 return -2;
177
178 if (check && checkrev(ipfname) == -1) {
179 fprintf(stderr, "User/kernel version check failed\n");
180 return -2;
181 }
182
183 if (!ipfdev)
184 ipfdev = ipfname;
185
186 if (fd == -1)
187 if ((fd = open(ipfdev, O_RDWR)) == -1)
188 if ((fd = open(ipfdev, O_RDONLY)) == -1)
189 perror("open device");
190 return fd;
191 }
192
193
closedevice()194 static void closedevice()
195 {
196 close(fd);
197 fd = -1;
198 }
199
200
get_flags()201 static int get_flags()
202 {
203 int i;
204
205 if ((opendevice(ipfname, 1) != -2) &&
206 (ioctl(fd, SIOCGETFF, &i) == -1)) {
207 perror("SIOCGETFF");
208 return 0;
209 }
210 return i;
211 }
212
213
set_state(enable)214 static void set_state(enable)
215 u_int enable;
216 {
217 if (opendevice(ipfname, 0) != -2)
218 if (ioctl(fd, SIOCFRENB, &enable) == -1) {
219 if (errno == EBUSY)
220 fprintf(stderr,
221 "IP FIlter: already initialized\n");
222 else
223 perror("SIOCFRENB");
224 }
225 return;
226 }
227
228
procfile(name,file)229 static void procfile(name, file)
230 char *name, *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
ipf_interceptadd(fd,ioctlfunc,ptr)246 static void ipf_interceptadd(fd, ioctlfunc, ptr)
247 int fd;
248 ioctlfunc_t ioctlfunc;
249 void *ptr;
250 {
251 if (outputc)
252 printc(ptr);
253
254 ipf_addrule(fd, ioctlfunc, ptr);
255 }
256
257
packetlogon(opt)258 static void packetlogon(opt)
259 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") || index(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 perror("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 perror("ioctl(SIOCGETLG)");
314 else {
315 logopt = 1 - logopt;
316 if (ioctl(xfd, SIOCSETLG, &logopt))
317 perror("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 perror("ioctl(SIOCGETLG)");
331 else {
332 logopt = 1 - logopt;
333 if (ioctl(xfd, SIOCSETLG, &logopt))
334 perror("ioctl(SIOCSETLG)");
335 }
336 close(xfd);
337 }
338 }
339 }
340
341
flushfilter(arg)342 static void flushfilter(arg)
343 char *arg;
344 {
345 int fl = 0, rem;
346
347 if (!arg || !*arg)
348 return;
349 if (!strcmp(arg, "s") || !strcmp(arg, "S")) {
350 if (*arg == 'S')
351 fl = FLUSH_TABLE_ALL;
352 else
353 fl = FLUSH_TABLE_CLOSING;
354 rem = fl;
355
356 closedevice();
357 if (opendevice(IPSTATE_NAME, 1) == -2)
358 exit(1);
359
360 if (!(opts & OPT_DONOTHING)) {
361 if (use_inet6) {
362 if (ioctl(fd, SIOCIPFL6, &fl) == -1) {
363 perror("ioctl(SIOCIPFL6)");
364 exit(1);
365 }
366 } else {
367 if (ioctl(fd, SIOCIPFFL, &fl) == -1) {
368 perror("ioctl(SIOCIPFFL)");
369 exit(1);
370 }
371 }
372 }
373 if ((opts & (OPT_DONOTHING|OPT_VERBOSE)) == OPT_VERBOSE) {
374 printf("remove flags %s (%d)\n", arg, rem);
375 printf("removed %d filter rules\n", fl);
376 }
377 closedevice();
378 return;
379 }
380
381 #ifdef SIOCIPFFA
382 if (!strcmp(arg, "u")) {
383 closedevice();
384 /*
385 * Flush auth rules and packets
386 */
387 if (opendevice(IPL_AUTH, 1) == -1)
388 perror("open(IPL_AUTH)");
389 else {
390 if (ioctl(fd, SIOCIPFFA, &fl) == -1)
391 perror("ioctl(SIOCIPFFA)");
392 }
393 closedevice();
394 return;
395 }
396 #endif
397
398 if (strchr(arg, 'i') || strchr(arg, 'I'))
399 fl = FR_INQUE;
400 if (strchr(arg, 'o') || strchr(arg, 'O'))
401 fl = FR_OUTQUE;
402 if (strchr(arg, 'a') || strchr(arg, 'A'))
403 fl = FR_OUTQUE|FR_INQUE;
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 perror("ioctl(SIOCIPFL6)");
415 exit(1);
416 }
417 } else {
418 if (ioctl(fd, SIOCIPFFL, &fl) == -1) {
419 perror("ioctl(SIOCIPFFL)");
420 exit(1);
421 }
422 }
423 }
424
425 if ((opts & (OPT_DONOTHING|OPT_VERBOSE)) == OPT_VERBOSE) {
426 printf("remove flags %s%s (%d)\n", (rem & FR_INQUE) ? "I" : "",
427 (rem & FR_OUTQUE) ? "O" : "", rem);
428 printf("removed %d filter rules\n", fl);
429 }
430 return;
431 }
432
433
swapactive()434 static void swapactive()
435 {
436 int in = 2;
437
438 if (opendevice(ipfname, 1) != -2 && ioctl(fd, SIOCSWAPA, &in) == -1)
439 perror("ioctl(SIOCSWAPA)");
440 else
441 printf("Set %d now inactive\n", in);
442 }
443
444
ipf_frsync()445 void ipf_frsync()
446 {
447 int frsyn = 0;
448
449 if (opendevice(ipfname, 1) != -2 && ioctl(fd, SIOCFRSYN, &frsyn) == -1)
450 perror("SIOCFRSYN");
451 else
452 printf("filter sync'd\n");
453 }
454
455
zerostats()456 void zerostats()
457 {
458 friostat_t fio;
459 friostat_t *fiop = &fio;
460
461 if (opendevice(ipfname, 1) != -2) {
462 if (ioctl(fd, SIOCFRZST, &fiop) == -1) {
463 perror("ioctl(SIOCFRZST)");
464 exit(-1);
465 }
466 showstats(fiop);
467 }
468
469 }
470
471
472 /*
473 * read the kernel stats for packets blocked and passed
474 */
showstats(fp)475 static void showstats(fp)
476 friostat_t *fp;
477 {
478 printf("bad packets:\t\tin %lu\tout %lu\n",
479 fp->f_st[0].fr_bad, fp->f_st[1].fr_bad);
480 printf(" input packets:\t\tblocked %lu passed %lu nomatch %lu",
481 fp->f_st[0].fr_block, fp->f_st[0].fr_pass,
482 fp->f_st[0].fr_nom);
483 printf(" counted %lu\n", fp->f_st[0].fr_acct);
484 printf("output packets:\t\tblocked %lu passed %lu nomatch %lu",
485 fp->f_st[1].fr_block, fp->f_st[1].fr_pass,
486 fp->f_st[1].fr_nom);
487 printf(" counted %lu\n", fp->f_st[0].fr_acct);
488 printf(" input packets logged:\tblocked %lu passed %lu\n",
489 fp->f_st[0].fr_bpkl, fp->f_st[0].fr_ppkl);
490 printf("output packets logged:\tblocked %lu passed %lu\n",
491 fp->f_st[1].fr_bpkl, fp->f_st[1].fr_ppkl);
492 printf(" packets logged:\tinput %lu-%lu output %lu-%lu\n",
493 fp->f_st[0].fr_pkl, fp->f_st[0].fr_skip,
494 fp->f_st[1].fr_pkl, fp->f_st[1].fr_skip);
495 }
496
497
showversion()498 static int showversion()
499 {
500 struct friostat fio;
501 ipfobj_t ipfo;
502 u_32_t flags;
503 char *s;
504 int vfd;
505
506 bzero((caddr_t)&ipfo, sizeof(ipfo));
507 ipfo.ipfo_rev = IPFILTER_VERSION;
508 ipfo.ipfo_size = sizeof(fio);
509 ipfo.ipfo_ptr = (void *)&fio;
510 ipfo.ipfo_type = IPFOBJ_IPFSTAT;
511
512 printf("ipf: %s (%d)\n", IPL_VERSION, (int)sizeof(frentry_t));
513
514 if ((vfd = open(ipfname, O_RDONLY)) == -1) {
515 perror("open device");
516 return 1;
517 }
518
519 if (ioctl(vfd, SIOCGETFS, &ipfo)) {
520 perror("ioctl(SIOCGETFS)");
521 close(vfd);
522 return 1;
523 }
524 close(vfd);
525 flags = get_flags();
526
527 printf("Kernel: %-*.*s\n", (int)sizeof(fio.f_version),
528 (int)sizeof(fio.f_version), fio.f_version);
529 printf("Running: %s\n", (fio.f_running > 0) ? "yes" : "no");
530 printf("Log Flags: %#x = ", flags);
531 s = "";
532 if (flags & FF_LOGPASS) {
533 printf("pass");
534 s = ", ";
535 }
536 if (flags & FF_LOGBLOCK) {
537 printf("%sblock", s);
538 s = ", ";
539 }
540 if (flags & FF_LOGNOMATCH) {
541 printf("%snomatch", s);
542 s = ", ";
543 }
544 if (flags & FF_BLOCKNONIP) {
545 printf("%snonip", s);
546 s = ", ";
547 }
548 if (!*s)
549 printf("none set");
550 putchar('\n');
551
552 printf("Default: ");
553 if (FR_ISPASS(fio.f_defpass))
554 s = "pass";
555 else if (FR_ISBLOCK(fio.f_defpass))
556 s = "block";
557 else
558 s = "nomatch -> block";
559 printf("%s all, Logging: %savailable\n", s, fio.f_logging ? "" : "un");
560 printf("Active list: %d\n", fio.f_active);
561 printf("Feature mask: %#x\n", fio.f_features);
562
563 return 0;
564 }
565