/* $OpenBSD: ipf.c,v 1.10 1997/02/26 04:35:39 kstailey Exp $ */ /* * (C)opyright 1993,1994,1995 by Darren Reed. * * Redistribution and use in source and binary forms are permitted * provided that this notice is preserved and due credit is given * to the original author and the contributors. */ #include #include #include #include #include #if !defined(__SVR4) && !defined(__GNUC__) #include #endif #if !defined(__SVR4) && defined(__GNUC__) && !defined(__OpenBSD__) extern char *index(); #endif #include #include #include #include #include #include #include #include #include #include #include #include #include "ip_fil_compat.h" #include "ip_fil.h" #include #include #include #include "ipf.h" #if !defined(lint) && defined(LIBC_SCCS) static char sccsid[] = "@(#)ipf.c 1.23 6/5/96 (C) 1993-1995 Darren Reed"; static char rcsid[] = "$DRId: ipf.c,v 2.0.1.2 1997/02/04 14:37:46 darrenr Exp $"; #endif #if SOLARIS void frsync(), blockunknown(); #endif void zerostats(); extern char *optarg; int opts = 0; static int fd = -1; static void procfile(), flushfilter(), set_state(); static void packetlogon(), swapactive(), showstats(); static char *getline(); int main(argc,argv) int argc; char *argv[]; { char c; while ((c = getopt(argc, argv, "AdDEf:F:Il:noprsUvyzZ")) != -1) { switch (c) { case 'E' : set_state(1); break; case 'D' : set_state(0); break; case 'A' : opts &= ~OPT_INACTIVE; break; case 'd' : opts |= OPT_DEBUG; break; case 'f' : procfile(argv[0], optarg); break; case 'F' : flushfilter(optarg); break; case 'I' : opts |= OPT_INACTIVE; break; case 'l' : packetlogon(optarg); break; case 'n' : opts |= OPT_DONOTHING; break; case 'o' : opts |= OPT_OUTQUE; break; case 'p' : opts |= OPT_PRINTFR; break; case 'r' : opts |= OPT_REMOVE; break; case 's' : swapactive(); break; #if SOLARIS case 'U' : blockunknown(); break; #endif case 'v' : opts |= OPT_VERBOSE; break; #if SOLARIS case 'y' : frsync(); break; #endif case 'z' : opts |= OPT_ZERORULEST; break; case 'Z' : zerostats(); break; } } if (fd != -1) (void) close(fd); exit(0); /* NOTREACHED */ } static int opendevice() { if (opts & OPT_DONOTHING) return -2; if (!(opts & OPT_DONOTHING) && fd == -1) if ((fd = open(IPL_NAME, O_RDWR)) == -1) if ((fd = open(IPL_NAME, O_RDONLY)) == -1) perror("open device"); return fd; } static void set_state(enable) u_int enable; { if (opendevice() != -2) if (ioctl(fd, SIOCFRENB, &enable) == -1) perror("SIOCFRENB"); return; } static void procfile(name, file) char *name, *file; { FILE *fp; char line[513], *s; struct frentry *fr; u_int add = SIOCADAFR, del = SIOCRMAFR; (void) opendevice(); if (opts & OPT_INACTIVE) { add = SIOCADIFR; del = SIOCRMIFR; } if (opts & OPT_DEBUG) printf("add %x del %x\n", add, del); initparse(); if (!strcmp(file, "-")) fp = stdin; else if (!(fp = fopen(file, "r"))) { fprintf(stderr, "%s: fopen(%s) failed: %s\n", name, file, STRERROR(errno)); exit(1); } while (getline(line, sizeof(line)-1, fp)) { /* * treat both CR and LF as EOL */ if ((s = strchr(line, '\n'))) *s = '\0'; if ((s = strchr(line, '\r'))) *s = '\0'; /* * # is comment marker, everything after is a ignored */ if ((s = strchr(line, '#'))) *s = '\0'; if (!*line) continue; if (opts & OPT_VERBOSE) (void)fprintf(stderr, "[%s]\n",line); fr = parse(line); (void)fflush(stdout); if (fr) { if (opts & OPT_ZERORULEST) add = SIOCZRLST; else if (opts & OPT_INACTIVE) add = fr->fr_hits ? SIOCINIFR : SIOCADIFR; else add = fr->fr_hits ? SIOCINAFR : SIOCADAFR; if (fr->fr_hits) fr->fr_hits--; if (fr && (opts & OPT_VERBOSE)) printfr(fr); if (fr && (opts & OPT_OUTQUE)) fr->fr_flags |= FR_OUTQUE; if (opts & OPT_DEBUG) binprint(fr); if ((opts & OPT_ZERORULEST) && !(opts & OPT_DONOTHING)) { if (ioctl(fd, add, fr) == -1) perror("ioctl(SIOCZRLST)"); else { printf("hits %ld bytes %ld ", fr->fr_hits, fr->fr_bytes); printfr(fr); } } else if ((opts & OPT_REMOVE) && !(opts & OPT_DONOTHING)) { if (ioctl(fd, del, fr) == -1) perror("ioctl(SIOCDELFR)"); } else if (!(opts & OPT_DONOTHING)) { if (ioctl(fd, add, fr) == -1) perror("ioctl(SIOCADDFR)"); } } } (void)fclose(fp); } /* * Similar to fgets(3) but can handle '\\' */ static char *getline(str, size, file) register char *str; size_t size; FILE *file; { register char *p; do { for (p = str;; p+= strlen(p) - 1) { if (!fgets(p, size, file)) return(NULL); p[strlen(p) -1] = '\0'; if (p[strlen(p) - 1] != '\\') break; } } while (*str == '\0' || *str == '\n'); return(str); } static void packetlogon(opt) char *opt; { int err, flag = 0; if ((opts & (OPT_DONOTHING|OPT_VERBOSE)) == OPT_VERBOSE) { if ((err = ioctl(fd, SIOCGETFF, &flag))) perror("ioctl(SIOCGETFF)"); printf("log flag is currently %#x\n", flag); } flag &= ~(FF_LOGPASS|FF_LOGNOMATCH|FF_LOGBLOCK); if (strchr(opt, 'p')) { flag |= FF_LOGPASS; if (opts & OPT_VERBOSE) printf("set log flag: pass\n"); } if (strchr(opt, 'm') && (*opt == 'n' || *opt == 'N')) { flag |= FF_LOGNOMATCH; if (opts & OPT_VERBOSE) printf("set log flag: nomatch\n"); } if (strchr(opt, 'b') || strchr(opt, 'd')) { flag |= FF_LOGBLOCK; if (opts & OPT_VERBOSE) printf("set log flag: block\n"); } if (opendevice() != -2 && (err = ioctl(fd, SIOCSETFF, &flag))) perror("ioctl(SIOCSETFF)"); if ((opts & (OPT_DONOTHING|OPT_VERBOSE)) == OPT_VERBOSE) { if ((err = ioctl(fd, SIOCGETFF, &flag))) perror("ioctl(SIOCGETFF)"); printf("log flag is now %#x\n", flag); } } static void flushfilter(arg) char *arg; { int fl = 0, rem; if (!arg || !*arg) return; if (strchr(arg, 'i') || strchr(arg, 'I')) fl = FR_INQUE; if (strchr(arg, 'o') || strchr(arg, 'O')) fl = FR_OUTQUE; if (strchr(arg, 'a') || strchr(arg, 'A')) fl = FR_OUTQUE|FR_INQUE; fl |= (opts & FR_INACTIVE); rem = fl; if (opendevice() != -2 && ioctl(fd, SIOCIPFFL, &fl) == -1) perror("ioctl(SIOCIPFFL)"); if ((opts & (OPT_DONOTHING|OPT_VERBOSE)) == OPT_VERBOSE) { printf("remove flags %s%s (%d)\n", (rem & FR_INQUE) ? "I" : "", (rem & FR_OUTQUE) ? "O" : "", rem); printf("removed %d filter rules\n", fl); } return; } static void swapactive() { int in = 2; if (opendevice() != -2 && ioctl(fd, SIOCSWAPA, &in) == -1) perror("ioctl(SIOCSWAPA)"); else printf("Set %d now inactive\n", in); } #if defined(sun) && (defined(__SVR4) || defined(__svr4__)) void frsync() { if (opendevice() != -2 && ioctl(fd, SIOCFRSYN, 0) == -1) perror("SIOCFRSYN"); else printf("filter sync'd\n"); } #endif void zerostats() { friostat_t fio; if (opendevice() != -2) { if (ioctl(fd, SIOCFRZST, &fio) == -1) { perror("ioctl(SIOCFRZST)"); exit(-1); } showstats(&fio); } } /* * read the kernel stats for packets blocked and passed */ static void showstats(fp) friostat_t *fp; { #if SOLARIS printf("dropped packets:\tin %lu\tout %lu\n", fp->f_st[0].fr_drop, fp->f_st[1].fr_drop); printf("non-ip packets:\t\tin %lu\tout %lu\n", fp->f_st[0].fr_notip, fp->f_st[1].fr_notip); printf(" bad packets:\t\tin %lu\tout %lu\n", fp->f_st[0].fr_bad, fp->f_st[1].fr_bad); #endif printf(" input packets:\t\tblocked %lu passed %lu nomatch %lu", fp->f_st[0].fr_block, fp->f_st[0].fr_pass, fp->f_st[0].fr_nom); printf(" counted %lu\n", fp->f_st[0].fr_acct); printf("output packets:\t\tblocked %lu passed %lu nomatch %lu", fp->f_st[1].fr_block, fp->f_st[1].fr_pass, fp->f_st[1].fr_nom); printf(" counted %lu\n", fp->f_st[0].fr_acct); printf(" input packets logged:\tblocked %lu passed %lu\n", fp->f_st[0].fr_bpkl, fp->f_st[0].fr_ppkl); printf("output packets logged:\tblocked %lu passed %lu\n", fp->f_st[1].fr_bpkl, fp->f_st[1].fr_ppkl); printf(" packets logged:\tinput %lu-%lu output %lu-%lu\n", fp->f_st[0].fr_pkl, fp->f_st[0].fr_skip, fp->f_st[1].fr_pkl, fp->f_st[1].fr_skip); } #if SOLARIS void blockunknown() { int flag; if (opendevice() == -1) return; if ((opts & (OPT_DONOTHING|OPT_VERBOSE)) == OPT_VERBOSE) { if (ioctl(fd, SIOCGETFF, &flag)) perror("ioctl(SIOCGETFF)"); printf("log flag is currently %#x\n", flag); } flag ^= FF_BLOCKNONIP; if (opendevice() != -2 && ioctl(fd, SIOCSETFF, &flag)) perror("ioctl(SIOCSETFF)"); if ((opts & (OPT_DONOTHING|OPT_VERBOSE)) == OPT_VERBOSE) { if (ioctl(fd, SIOCGETFF, &flag)) perror("ioctl(SIOCGETFF)"); printf("log flag is now %#x\n", flag); } } #endif