2 * Copyright (C) 1993-2001 by Darren Reed.
4 * See the IPFILTER.LICENCE file for details on licencing.
7 # ifndef __FreeBSD_cc_version
8 # include <osreldate.h>
10 # if __FreeBSD_cc_version < 430000
11 # include <osreldate.h>
15 #if defined(__sgi) && (IRIX > 602)
16 # include <sys/ptimers.h>
23 #if !defined(__SVR4) && !defined(__GNUC__)
26 #include <sys/types.h>
27 #include <sys/param.h>
31 #include <sys/socket.h>
32 #include <sys/ioctl.h>
33 #include <netinet/in.h>
34 #include <netinet/in_systm.h>
37 #if __FreeBSD_version >= 300000
38 # include <net/if_var.h>
40 #include <netinet/ip.h>
42 #include <arpa/nameser.h>
44 #include "ip_compat.h"
52 static const char sccsid
[] = "@(#)ipf.c 1.23 6/5/96 (C) 1993-2000 Darren Reed";
53 static const char rcsid
[] = "@(#)$Id: ipf.c,v 2.10.2.23 2003/06/27 14:39:13 darrenr Exp $";
57 static void blockunknown
__P((void));
59 #if !defined(__SVR4) && defined(__GNUC__)
60 extern char *index
__P((const char *, int));
66 void frsync
__P((void));
67 void zerostats
__P((void));
68 int main
__P((int, char *[]));
75 static void procfile
__P((char *, char *)), flushfilter
__P((char *));
76 static int set_state
__P((u_int
));
77 static void showstats
__P((friostat_t
*));
78 static void packetlogon
__P((char *)), swapactive
__P((void));
79 static int opendevice
__P((char *));
80 static void closedevice
__P((void));
81 static char *getline
__P((char *, size_t, FILE *, int *));
82 static char *ipfname
= IPL_NAME
;
83 static void usage
__P((char *));
84 static int showversion
__P((void));
85 static int get_flags
__P((int *));
89 # define OPTS "6AdDEf:F:Il:noPrsUvVyzZ"
91 # define OPTS "6AdDEf:F:Il:noPrsvVyzZ"
94 static void usage(name
)
97 fprintf(stderr
, "usage: %s [-%s] %s %s %s\n", name
, OPTS
,
98 "[-l block|pass|nomatch]", "[-F i|o|a|s|S]", "[-f filename]");
112 while ((c
= getopt(argc
, argv
, OPTS
)) != -1) {
119 opts
&= ~OPT_INACTIVE
;
122 if (set_state((u_int
)1))
126 if (set_state((u_int
)0))
133 procfile(argv
[0], optarg
);
139 opts
|= OPT_INACTIVE
;
145 opts
|= OPT_DONOTHING
;
174 opts
|= OPT_ZERORULEST
;
197 static int opendevice(ipfdev
)
200 if (opts
& OPT_DONOTHING
)
207 * shouldn't we really be testing for fd < 0 here and below?
213 if ((fd
= open(ipfdev
, O_RDWR
)) == -1) {
214 if ((fd
= open(ipfdev
, O_RDONLY
)) == -1) {
215 perror("open device");
217 fprintf(stderr
, "IPFilter enabled?\n");
226 static void closedevice()
237 * !0 Failure (and an error message has already been printed)
239 static int get_flags(i
)
243 if (opts
& OPT_DONOTHING
)
246 if (opendevice(ipfname
) < 0)
249 if (ioctl(fd
, SIOCGETFF
, i
) == -1) {
257 static int set_state(enable
)
260 if (opts
& OPT_DONOTHING
)
263 if (opendevice(ipfname
))
266 if (ioctl(fd
, SIOCFRENB
, &enable
) == -1) {
268 /* Not really an error */
270 "IP Filter: already initialized\n");
279 static void procfile(name
, file
)
289 if (opendevice(ipfname
) == -1)
292 if (opts
& OPT_INACTIVE
) {
299 if (opts
& OPT_DEBUG
)
300 printf("add %x del %x\n", add
, del
);
304 if (!strcmp(file
, "-"))
306 else if (!(fp
= fopen(file
, "r"))) {
307 fprintf(stderr
, "%s: fopen(%s) failed: %s\n", name
, file
,
312 while (getline(line
, sizeof(line
), fp
, &linenum
)) {
314 * treat CR as EOL. LF is converted to NUL by getline().
316 if ((s
= index(line
, '\r')))
319 * # is comment marker, everything after is a ignored
321 if ((s
= index(line
, '#')))
327 if (opts
& OPT_VERBOSE
)
328 (void)fprintf(stderr
, "[%s]\n", line
);
331 fr
= parse(line
, linenum
, &parsestatus
);
332 (void)fflush(stdout
);
334 if (parsestatus
!= 0) {
335 fprintf(stderr
, "%s: %s: %s error (%d), quitting\n",
337 ((parsestatus
< 0)? "parse": "internal"),
343 if (opts
& OPT_ZERORULEST
)
345 else if (opts
& OPT_INACTIVE
)
346 add
= (u_int
)fr
->fr_hits
? SIOCINIFR
:
349 add
= (u_int
)fr
->fr_hits
? SIOCINAFR
:
353 if (fr
&& (opts
& OPT_VERBOSE
))
355 if (fr
&& (opts
& OPT_OUTQUE
))
356 fr
->fr_flags
|= FR_OUTQUE
;
358 if (opts
& OPT_DEBUG
)
361 if ((opts
& OPT_ZERORULEST
) &&
362 !(opts
& OPT_DONOTHING
)) {
363 if (ioctl(fd
, add
, &fr
) == -1) {
364 fprintf(stderr
, "%d:", linenum
);
365 perror("ioctl(SIOCZRLST)");
369 printf("hits %qd bytes %qd ",
370 (long long)fr
->fr_hits
,
371 (long long)fr
->fr_bytes
);
373 printf("hits %ld bytes %ld ",
374 fr
->fr_hits
, fr
->fr_bytes
);
378 } else if ((opts
& OPT_REMOVE
) &&
379 !(opts
& OPT_DONOTHING
)) {
380 if (ioctl(fd
, del
, &fr
) == -1) {
381 fprintf(stderr
, "%d:", linenum
);
382 perror("ioctl(delete rule)");
385 } else if (!(opts
& OPT_DONOTHING
)) {
386 if (ioctl(fd
, add
, &fr
) == -1) {
387 fprintf(stderr
, "%d:", linenum
);
388 perror("ioctl(add/insert rule)");
394 if (ferror(fp
) || !feof(fp
)) {
395 fprintf(stderr
, "%s: %s: file error or line too long\n",
403 * Similar to fgets(3) but can handle '\\' and NL is converted to NUL.
404 * Returns NULL if error occurred, EOF encounterd or input line is too long.
406 static char *getline(str
, size
, file
, linenum
)
416 for (p
= str
, s
= size
;; p
+= (len
- 1), s
-= (len
- 1)) {
418 * if an error occurred, EOF was encounterd, or there
419 * was no room to put NUL, return NULL.
421 if (fgets(p
, s
, file
) == NULL
)
424 if (p
[len
- 1] != '\n') {
430 if (len
< 2 || p
[len
- 2] != '\\')
434 * Convert '\\' to a space so words don't
439 } while (*str
== '\0');
444 static void packetlogon(opt
)
449 if (get_flags(&flag
))
453 if ((opts
& (OPT_DONOTHING
|OPT_VERBOSE
)) == OPT_VERBOSE
)
454 printf("log flag is currently %#x\n", flag
);
457 flag
&= ~(FF_LOGPASS
|FF_LOGNOMATCH
|FF_LOGBLOCK
);
459 if (index(opt
, 'p')) {
461 if (opts
& OPT_VERBOSE
)
462 printf("set log flag: pass\n");
464 if (index(opt
, 'm') && (*opt
== 'n' || *opt
== 'N')) {
465 flag
|= FF_LOGNOMATCH
;
466 if (opts
& OPT_VERBOSE
)
467 printf("set log flag: nomatch\n");
469 if (index(opt
, 'b') || index(opt
, 'd')) {
471 if (opts
& OPT_VERBOSE
)
472 printf("set log flag: block\n");
475 if (opendevice(ipfname
) == -1) {
479 if (!(opts
& OPT_DONOTHING
)) {
480 if (ioctl(fd
, SIOCSETFF
, &flag
) != 0) {
481 perror("ioctl(SIOCSETFF)");
486 if ((opts
& (OPT_DONOTHING
|OPT_VERBOSE
)) == OPT_VERBOSE
) {
488 * Even though the ioctls above succeeded, it
489 * is possible that a calling script/program
490 * relies on the following verbose mode string.
491 * Thus, we still take an error exit if get_flags
494 if (get_flags(&flag
))
496 printf("log flag is now %#x\n", flag
);
501 static void flushfilter(arg
)
507 fprintf(stderr
, "-F: no filter specified\n");
511 if (!strcmp(arg
, "s") || !strcmp(arg
, "S")) {
520 if (opendevice(IPL_STATE
) == -1) {
524 if (!(opts
& OPT_DONOTHING
)) {
526 if (ioctl(fd
, SIOCIPFL6
, &fl
) == -1) {
527 perror("ioctl(SIOCIPFL6)");
531 if (ioctl(fd
, SIOCIPFFL
, &fl
) == -1) {
532 perror("ioctl(SIOCIPFFL)");
537 if ((opts
& (OPT_DONOTHING
|OPT_VERBOSE
)) == OPT_VERBOSE
) {
538 printf("remove flags %s (%d)\n", arg
, rem
);
539 printf("removed %d filter rules\n", fl
);
544 if (strchr(arg
, 'i') || strchr(arg
, 'I'))
546 if (strchr(arg
, 'o') || strchr(arg
, 'O'))
548 if (strchr(arg
, 'a') || strchr(arg
, 'A'))
549 fl
= FR_OUTQUE
|FR_INQUE
;
550 fl
|= (opts
& FR_INACTIVE
);
553 if (opendevice(ipfname
) == -1) {
557 if (!(opts
& OPT_DONOTHING
)) {
559 if (ioctl(fd
, SIOCIPFL6
, &fl
) == -1) {
560 perror("ioctl(SIOCIPFL6)");
564 if (ioctl(fd
, SIOCIPFFL
, &fl
) == -1) {
565 perror("ioctl(SIOCIPFFL)");
570 if ((opts
& (OPT_DONOTHING
|OPT_VERBOSE
)) == OPT_VERBOSE
) {
571 printf("remove flags %s%s (%d)\n", (rem
& FR_INQUE
) ? "I" : "",
572 (rem
& FR_OUTQUE
) ? "O" : "", rem
);
573 printf("removed %d filter rules\n", fl
);
579 static void swapactive()
583 if (opendevice(ipfname
) == -1) {
588 if (!(opts
& OPT_DONOTHING
)) {
589 if (ioctl(fd
, SIOCSWAPA
, &in
) == -1) {
590 perror("ioctl(SIOCSWAPA)");
594 printf("Set %d now inactive\n", in
);
602 if (opendevice(ipfname
) == -1)
605 if (!(opts
& OPT_DONOTHING
)) {
606 if (ioctl(fd
, SIOCFRSYN
, &frsyn
) == -1) {
611 printf("filter sync'd\n");
618 friostat_t
*fiop
= &fio
;
620 if (opendevice(ipfname
) == -1)
623 if (!(opts
& OPT_DONOTHING
)) {
624 if (ioctl(fd
, SIOCFRZST
, &fiop
) == -1) {
625 perror("ioctl(SIOCFRZST)");
635 * Read the kernel stats for packets blocked and passed
637 static void showstats(fp
)
641 printf("dropped packets:\tin %lu\tout %lu\n",
642 fp
->f_st
[0].fr_drop
, fp
->f_st
[1].fr_drop
);
643 printf("non-ip packets:\t\tin %lu\tout %lu\n",
644 fp
->f_st
[0].fr_notip
, fp
->f_st
[1].fr_notip
);
645 printf(" bad packets:\t\tin %lu\tout %lu\n",
646 fp
->f_st
[0].fr_bad
, fp
->f_st
[1].fr_bad
);
648 printf(" input packets:\t\tblocked %lu passed %lu nomatch %lu",
649 fp
->f_st
[0].fr_block
, fp
->f_st
[0].fr_pass
,
651 printf(" counted %lu\n", fp
->f_st
[0].fr_acct
);
652 printf("output packets:\t\tblocked %lu passed %lu nomatch %lu",
653 fp
->f_st
[1].fr_block
, fp
->f_st
[1].fr_pass
,
655 printf(" counted %lu\n", fp
->f_st
[0].fr_acct
);
656 printf(" input packets logged:\tblocked %lu passed %lu\n",
657 fp
->f_st
[0].fr_bpkl
, fp
->f_st
[0].fr_ppkl
);
658 printf("output packets logged:\tblocked %lu passed %lu\n",
659 fp
->f_st
[1].fr_bpkl
, fp
->f_st
[1].fr_ppkl
);
660 printf(" packets logged:\tinput %lu-%lu output %lu-%lu\n",
661 fp
->f_st
[0].fr_pkl
, fp
->f_st
[0].fr_skip
,
662 fp
->f_st
[1].fr_pkl
, fp
->f_st
[1].fr_skip
);
667 static void blockunknown()
671 if (opendevice(ipfname
) == -1)
674 if (get_flags(&flag
))
677 if ((opts
& (OPT_DONOTHING
|OPT_VERBOSE
)) == OPT_VERBOSE
)
678 printf("log flag is currently %#x\n", flag
);
680 flag
^= FF_BLOCKNONIP
;
682 if (opendevice(ipfname
) == -1)
685 if (!(opts
& OPT_DONOTHING
)) {
686 if (ioctl(fd
, SIOCSETFF
, &flag
))
687 perror("ioctl(SIOCSETFF)");
690 if ((opts
& (OPT_DONOTHING
|OPT_VERBOSE
)) == OPT_VERBOSE
) {
691 if (ioctl(fd
, SIOCGETFF
, &flag
))
692 perror("ioctl(SIOCGETFF)");
694 printf("log flag is now %#x\n", flag
);
701 * nonzero return value means caller should exit with error
703 static int showversion()
706 struct friostat
*fiop
=&fio
;
710 printf("ipf: %s (%d)\n", IPL_VERSION
, (int)sizeof(frentry_t
));
712 if ((vfd
= open(ipfname
, O_RDONLY
)) == -1) {
713 perror("open device");
717 if (ioctl(vfd
, SIOCGETFS
, &fiop
)) {
718 perror("ioctl(SIOCGETFS)");
724 printf("Kernel: %-*.*s\n", (int)sizeof(fio
.f_version
),
725 (int)sizeof(fio
.f_version
), fio
.f_version
);
726 printf("Running: %s\n", fio
.f_running
? "yes" : "no");
728 if (get_flags(&flags
)) {
731 printf("Log Flags: %#x = ", flags
);
733 if (flags
& FF_LOGPASS
) {
737 if (flags
& FF_LOGBLOCK
) {
738 printf("%sblock", s
);
741 if (flags
& FF_LOGNOMATCH
) {
742 printf("%snomatch", s
);
745 if (flags
& FF_BLOCKNONIP
) {
746 printf("%snonip", s
);
754 if (fio
.f_defpass
& FR_PASS
)
756 else if (fio
.f_defpass
& FR_BLOCK
)
759 s
= "nomatch -> block";
760 printf("%s all, Logging: %savailable\n", s
, fio
.f_logging
? "" : "un");
761 printf("Active list: %d\n", fio
.f_active
);