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>
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.13 2002/02/22 15:32:53 darrenr Exp $";
57 static void blockunknown __P((void));
59 #if !defined(__SVR4) && defined(__GNUC__)
60 extern char *index __P((const char *, int));
65 void frsync __P((void));
66 void zerostats __P((void));
67 int main __P((int, char *[]));
74 static void procfile __P((char *, char *)), flushfilter __P((char *));
75 static void set_state __P((u_int)), showstats __P((friostat_t *));
76 static void packetlogon __P((char *)), swapactive __P((void));
77 static int opendevice __P((char *));
78 static void closedevice __P((void));
79 static char *getline __P((char *, size_t, FILE *, int *));
80 static char *ipfname = IPL_NAME;
81 static void usage __P((void));
82 static int showversion __P((void));
83 static int get_flags __P((void));
87 # define OPTS "6AdDEf:F:Il:noPrsUvVyzZ"
89 # define OPTS "6AdDEf:F:Il:noPrsvVyzZ"
94 fprintf(stderr, "usage: ipf [-%s] %s %s %s\n", OPTS,
95 "[-l block|pass|nomatch]", "[-F i|o|a|s|S]", "[-f filename]");
106 while ((c = getopt(argc, argv, OPTS)) != -1) {
113 opts &= ~OPT_INACTIVE;
125 procfile(argv[0], optarg);
131 opts |= OPT_INACTIVE;
137 opts |= OPT_DONOTHING;
166 opts |= OPT_ZERORULEST;
185 static int opendevice(ipfdev)
188 if (opts & OPT_DONOTHING)
194 if (!(opts & OPT_DONOTHING) && fd == -1)
195 if ((fd = open(ipfdev, O_RDWR)) == -1)
196 if ((fd = open(ipfdev, O_RDONLY)) == -1)
197 perror("open device");
202 static void closedevice()
209 static int get_flags()
213 if ((opendevice(ipfname) != -2) && (ioctl(fd, SIOCGETFF, &i) == -1)) {
221 static void set_state(enable)
224 if (opendevice(ipfname) != -2)
225 if (ioctl(fd, SIOCFRENB, &enable) == -1) {
228 "IP FIlter: already initialized\n");
235 static void procfile(name, file)
244 (void) opendevice(ipfname);
246 if (opts & OPT_INACTIVE) {
253 if (opts & OPT_DEBUG)
254 printf("add %x del %x\n", add, del);
258 if (!strcmp(file, "-"))
260 else if (!(fp = fopen(file, "r"))) {
261 fprintf(stderr, "%s: fopen(%s) failed: %s\n", name, file,
266 while (getline(line, sizeof(line), fp, &linenum)) {
268 * treat CR as EOL. LF is converted to NUL by getline().
270 if ((s = index(line, '\r')))
273 * # is comment marker, everything after is a ignored
275 if ((s = index(line, '#')))
281 if (opts & OPT_VERBOSE)
282 (void)fprintf(stderr, "[%s]\n", line);
284 fr = parse(line, linenum);
285 (void)fflush(stdout);
288 if (opts & OPT_ZERORULEST)
290 else if (opts & OPT_INACTIVE)
291 add = (u_int)fr->fr_hits ? SIOCINIFR :
294 add = (u_int)fr->fr_hits ? SIOCINAFR :
298 if (fr && (opts & OPT_VERBOSE))
300 if (fr && (opts & OPT_OUTQUE))
301 fr->fr_flags |= FR_OUTQUE;
303 if (opts & OPT_DEBUG)
306 if ((opts & OPT_ZERORULEST) &&
307 !(opts & OPT_DONOTHING)) {
308 if (ioctl(fd, add, &fr) == -1) {
309 fprintf(stderr, "%d:", linenum);
310 perror("ioctl(SIOCZRLST)");
313 printf("hits %qd bytes %qd ",
314 (long long)fr->fr_hits,
315 (long long)fr->fr_bytes);
317 printf("hits %ld bytes %ld ",
318 fr->fr_hits, fr->fr_bytes);
322 } else if ((opts & OPT_REMOVE) &&
323 !(opts & OPT_DONOTHING)) {
324 if (ioctl(fd, del, &fr) == -1) {
325 fprintf(stderr, "%d:", linenum);
326 perror("ioctl(delete rule)");
328 } else if (!(opts & OPT_DONOTHING)) {
329 if (ioctl(fd, add, &fr) == -1) {
330 fprintf(stderr, "%d:", linenum);
331 perror("ioctl(add/insert rule)");
336 if (ferror(fp) || !feof(fp)) {
337 fprintf(stderr, "%s: %s: file error or line too long\n",
345 * Similar to fgets(3) but can handle '\\' and NL is converted to NUL.
346 * Returns NULL if error occured, EOF encounterd or input line is too long.
348 static char *getline(str, size, file, linenum)
358 for (p = str, s = size;; p += (len - 1), s -= (len - 1)) {
360 * if an error occured, EOF was encounterd, or there
361 * was no room to put NUL, return NULL.
363 if (fgets(p, s, file) == NULL)
366 if (p[len - 1] != '\n') {
372 if (len < 2 || p[len - 2] != '\\')
376 * Convert '\\' to a space so words don't
381 } while (*str == '\0');
386 static void packetlogon(opt)
393 if ((opts & (OPT_DONOTHING|OPT_VERBOSE)) == OPT_VERBOSE)
394 printf("log flag is currently %#x\n", flag);
397 flag &= ~(FF_LOGPASS|FF_LOGNOMATCH|FF_LOGBLOCK);
399 if (index(opt, 'p')) {
401 if (opts & OPT_VERBOSE)
402 printf("set log flag: pass\n");
404 if (index(opt, 'm') && (*opt == 'n' || *opt == 'N')) {
405 flag |= FF_LOGNOMATCH;
406 if (opts & OPT_VERBOSE)
407 printf("set log flag: nomatch\n");
409 if (index(opt, 'b') || index(opt, 'd')) {
411 if (opts & OPT_VERBOSE)
412 printf("set log flag: block\n");
415 if (opendevice(ipfname) != -2 && (err = ioctl(fd, SIOCSETFF, &flag)))
416 perror("ioctl(SIOCSETFF)");
418 if ((opts & (OPT_DONOTHING|OPT_VERBOSE)) == OPT_VERBOSE) {
420 printf("log flag is now %#x\n", flag);
425 static void flushfilter(arg)
432 if (!strcmp(arg, "s") || !strcmp(arg, "S")) {
440 if (opendevice(IPL_STATE) != -2 &&
441 ioctl(fd, SIOCIPFFL, &fl) == -1)
442 perror("ioctl(SIOCIPFFL)");
443 if ((opts & (OPT_DONOTHING|OPT_VERBOSE)) == OPT_VERBOSE) {
444 printf("remove flags %s (%d)\n", arg, rem);
445 printf("removed %d filter rules\n", fl);
450 if (strchr(arg, 'i') || strchr(arg, 'I'))
452 if (strchr(arg, 'o') || strchr(arg, 'O'))
454 if (strchr(arg, 'a') || strchr(arg, 'A'))
455 fl = FR_OUTQUE|FR_INQUE;
456 fl |= (opts & FR_INACTIVE);
459 if (opendevice(ipfname) != -2 && ioctl(fd, SIOCIPFFL, &fl) == -1)
460 perror("ioctl(SIOCIPFFL)");
461 if ((opts & (OPT_DONOTHING|OPT_VERBOSE)) == OPT_VERBOSE) {
462 printf("remove flags %s%s (%d)\n", (rem & FR_INQUE) ? "I" : "",
463 (rem & FR_OUTQUE) ? "O" : "", rem);
464 printf("removed %d filter rules\n", fl);
470 static void swapactive()
474 if (opendevice(ipfname) != -2 && ioctl(fd, SIOCSWAPA, &in) == -1)
475 perror("ioctl(SIOCSWAPA)");
477 printf("Set %d now inactive\n", in);
485 if (opendevice(ipfname) != -2 && ioctl(fd, SIOCFRSYN, &frsyn) == -1)
488 printf("filter sync'd\n");
495 friostat_t *fiop = &fio;
497 if (opendevice(ipfname) != -2) {
498 if (ioctl(fd, SIOCFRZST, &fiop) == -1) {
499 perror("ioctl(SIOCFRZST)");
509 * read the kernel stats for packets blocked and passed
511 static void showstats(fp)
515 printf("dropped packets:\tin %lu\tout %lu\n",
516 fp->f_st[0].fr_drop, fp->f_st[1].fr_drop);
517 printf("non-ip packets:\t\tin %lu\tout %lu\n",
518 fp->f_st[0].fr_notip, fp->f_st[1].fr_notip);
519 printf(" bad packets:\t\tin %lu\tout %lu\n",
520 fp->f_st[0].fr_bad, fp->f_st[1].fr_bad);
522 printf(" input packets:\t\tblocked %lu passed %lu nomatch %lu",
523 fp->f_st[0].fr_block, fp->f_st[0].fr_pass,
525 printf(" counted %lu\n", fp->f_st[0].fr_acct);
526 printf("output packets:\t\tblocked %lu passed %lu nomatch %lu",
527 fp->f_st[1].fr_block, fp->f_st[1].fr_pass,
529 printf(" counted %lu\n", fp->f_st[0].fr_acct);
530 printf(" input packets logged:\tblocked %lu passed %lu\n",
531 fp->f_st[0].fr_bpkl, fp->f_st[0].fr_ppkl);
532 printf("output packets logged:\tblocked %lu passed %lu\n",
533 fp->f_st[1].fr_bpkl, fp->f_st[1].fr_ppkl);
534 printf(" packets logged:\tinput %lu-%lu output %lu-%lu\n",
535 fp->f_st[0].fr_pkl, fp->f_st[0].fr_skip,
536 fp->f_st[1].fr_pkl, fp->f_st[1].fr_skip);
541 static void blockunknown()
545 if (opendevice(ipfname) == -1)
549 if ((opts & (OPT_DONOTHING|OPT_VERBOSE)) == OPT_VERBOSE)
550 printf("log flag is currently %#x\n", flag);
552 flag ^= FF_BLOCKNONIP;
554 if (opendevice(ipfname) != -2 && ioctl(fd, SIOCSETFF, &flag))
555 perror("ioctl(SIOCSETFF)");
557 if ((opts & (OPT_DONOTHING|OPT_VERBOSE)) == OPT_VERBOSE) {
558 if (ioctl(fd, SIOCGETFF, &flag))
559 perror("ioctl(SIOCGETFF)");
561 printf("log flag is now %#x\n", flag);
567 static int showversion()
570 struct friostat *fiop=&fio;
575 printf("ipf: %s (%d)\n", IPL_VERSION, (int)sizeof(frentry_t));
577 if ((vfd = open(ipfname, O_RDONLY)) == -1) {
578 perror("open device");
582 if (ioctl(vfd, SIOCGETFS, &fiop)) {
583 perror("ioctl(SIOCGETFS)");
590 printf("Kernel: %-*.*s\n", (int)sizeof(fio.f_version),
591 (int)sizeof(fio.f_version), fio.f_version);
592 printf("Running: %s\n", fio.f_running ? "yes" : "no");
593 printf("Log Flags: %#x = ", flags);
595 if (flags & FF_LOGPASS) {
599 if (flags & FF_LOGBLOCK) {
600 printf("%sblock", s);
603 if (flags & FF_LOGNOMATCH) {
604 printf("%snomatch", s);
607 if (flags & FF_BLOCKNONIP) {
608 printf("%snonip", s);
616 if (fio.f_defpass & FR_PASS)
618 else if (fio.f_defpass & FR_BLOCK)
621 s = "nomatch -> block";
622 printf("%s all, Logging: %savailable\n", s, fio.f_logging ? "" : "un");
623 printf("Active list: %d\n", fio.f_active);