]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/ipfilter/ipf.c
This commit was generated by cvs2svn to compensate for changes in r95415,
[FreeBSD/FreeBSD.git] / contrib / ipfilter / ipf.c
1 /*
2  * Copyright (C) 1993-2001 by Darren Reed.
3  *
4  * See the IPFILTER.LICENCE file for details on licencing.
5  */
6 #ifdef  __FreeBSD__
7 # ifndef __FreeBSD_cc_version
8 #  include <osreldate.h>
9 # else
10 #  if __FreeBSD_cc_version < 430000
11 #   include <osreldate.h>
12 #  endif
13 # endif
14 #endif
15 #ifdef __sgi
16 # include <sys/ptimers.h>
17 #endif
18 #include <stdio.h>
19 #include <unistd.h>
20 #include <string.h>
21 #include <fcntl.h>
22 #include <errno.h>
23 #if !defined(__SVR4) && !defined(__GNUC__)
24 #include <strings.h>
25 #endif
26 #include <sys/types.h>
27 #include <sys/param.h>
28 #include <sys/file.h>
29 #include <stdlib.h>
30 #include <stddef.h>
31 #include <sys/socket.h>
32 #include <sys/ioctl.h>
33 #include <netinet/in.h>
34 #include <netinet/in_systm.h>
35 #include <sys/time.h>
36 #include <net/if.h>
37 #if __FreeBSD_version >= 300000
38 # include <net/if_var.h>
39 #endif
40 #include <netinet/ip.h>
41 #include <netdb.h>
42 #include <arpa/nameser.h>
43 #include <resolv.h>
44 #include "ip_compat.h"
45 #include "ip_fil.h"
46 #include "ip_nat.h"
47 #include "ip_state.h"
48 #include "ipf.h"
49 #include "ipl.h"
50
51 #if !defined(lint)
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 $";
54 #endif
55
56 #if     SOLARIS
57 static  void    blockunknown __P((void));
58 #endif
59 #if !defined(__SVR4) && defined(__GNUC__)
60 extern  char    *index __P((const char *, int));
61 #endif
62
63 extern  char    *optarg;
64
65 void    frsync __P((void));
66 void    zerostats __P((void));
67 int     main __P((int, char *[]));
68
69 int     opts = 0;
70 int     use_inet6 = 0;
71
72 static  int     fd = -1;
73
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));
84
85
86 #if SOLARIS
87 # define        OPTS    "6AdDEf:F:Il:noPrsUvVyzZ"
88 #else
89 # define        OPTS    "6AdDEf:F:Il:noPrsvVyzZ"
90 #endif
91
92 static void usage()
93 {
94         fprintf(stderr, "usage: ipf [-%s] %s %s %s\n", OPTS,
95                 "[-l block|pass|nomatch]", "[-F i|o|a|s|S]", "[-f filename]");
96         exit(1);
97 }
98
99
100 int main(argc,argv)
101 int argc;
102 char *argv[];
103 {
104         int c;
105
106         while ((c = getopt(argc, argv, OPTS)) != -1) {
107                 switch (c)
108                 {
109                 case '6' :
110                         use_inet6 = 1;
111                         break;
112                 case 'A' :
113                         opts &= ~OPT_INACTIVE;
114                         break;
115                 case 'E' :
116                         set_state((u_int)1);
117                         break;
118                 case 'D' :
119                         set_state((u_int)0);
120                         break;
121                 case 'd' :
122                         opts |= OPT_DEBUG;
123                         break;
124                 case 'f' :
125                         procfile(argv[0], optarg);
126                         break;
127                 case 'F' :
128                         flushfilter(optarg);
129                         break;
130                 case 'I' :
131                         opts |= OPT_INACTIVE;
132                         break;
133                 case 'l' :
134                         packetlogon(optarg);
135                         break;
136                 case 'n' :
137                         opts |= OPT_DONOTHING;
138                         break;
139                 case 'o' :
140                         break;
141                 case 'P' :
142                         ipfname = IPL_AUTH;
143                         break;
144                 case 'r' :
145                         opts |= OPT_REMOVE;
146                         break;
147                 case 's' :
148                         swapactive();
149                         break;
150 #if SOLARIS
151                 case 'U' :
152                         blockunknown();
153                         break;
154 #endif
155                 case 'v' :
156                         opts += OPT_VERBOSE;
157                         break;
158                 case 'V' :
159                         if (showversion())
160                                 exit(1);
161                         break;
162                 case 'y' :
163                         frsync();
164                         break;
165                 case 'z' :
166                         opts |= OPT_ZERORULEST;
167                         break;
168                 case 'Z' :
169                         zerostats();
170                         break;
171                 default :
172                         usage();
173                         break;
174                 }
175         }
176
177         if (fd != -1)
178                 (void) close(fd);
179
180         exit(0);
181         /* NOTREACHED */
182 }
183
184
185 static int opendevice(ipfdev)
186 char *ipfdev;
187 {
188         if (opts & OPT_DONOTHING)
189                 return -2;
190
191         if (!ipfdev)
192                 ipfdev = ipfname;
193
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");
198         return fd;
199 }
200
201
202 static void closedevice()
203 {
204         close(fd);
205         fd = -1;
206 }
207
208
209 static  int     get_flags()
210 {
211         int i;
212
213         if ((opendevice(ipfname) != -2) && (ioctl(fd, SIOCGETFF, &i) == -1)) {
214                 perror("SIOCGETFF");
215                 return 0;
216         }
217         return i;
218 }
219
220
221 static  void    set_state(enable)
222 u_int   enable;
223 {
224         if (opendevice(ipfname) != -2)
225                 if (ioctl(fd, SIOCFRENB, &enable) == -1) {
226                         if (errno == EBUSY)
227                                 fprintf(stderr,
228                                         "IP FIlter: already initialized\n");
229                         else
230                                 perror("SIOCFRENB");
231                 }
232         return;
233 }
234
235 static  void    procfile(name, file)
236 char    *name, *file;
237 {
238         FILE    *fp;
239         char    line[513], *s;
240         struct  frentry *fr;
241         u_int   add, del;
242         int     linenum = 0;
243
244         (void) opendevice(ipfname);
245
246         if (opts & OPT_INACTIVE) {
247                 add = SIOCADIFR;
248                 del = SIOCRMIFR;
249         } else {
250                 add = SIOCADAFR;
251                 del = SIOCRMAFR;
252         }
253         if (opts & OPT_DEBUG)
254                 printf("add %x del %x\n", add, del);
255
256         initparse();
257
258         if (!strcmp(file, "-"))
259                 fp = stdin;
260         else if (!(fp = fopen(file, "r"))) {
261                 fprintf(stderr, "%s: fopen(%s) failed: %s\n", name, file,
262                         STRERROR(errno));
263                 exit(1);
264         }
265
266         while (getline(line, sizeof(line), fp, &linenum)) {
267                 /*
268                  * treat CR as EOL.  LF is converted to NUL by getline().
269                  */
270                 if ((s = index(line, '\r')))
271                         *s = '\0';
272                 /*
273                  * # is comment marker, everything after is a ignored
274                  */
275                 if ((s = index(line, '#')))
276                         *s = '\0';
277
278                 if (!*line)
279                         continue;
280
281                 if (opts & OPT_VERBOSE)
282                         (void)fprintf(stderr, "[%s]\n", line);
283
284                 fr = parse(line, linenum);
285                 (void)fflush(stdout);
286
287                 if (fr) {
288                         if (opts & OPT_ZERORULEST)
289                                 add = SIOCZRLST;
290                         else if (opts & OPT_INACTIVE)
291                                 add = (u_int)fr->fr_hits ? SIOCINIFR :
292                                                            SIOCADIFR;
293                         else
294                                 add = (u_int)fr->fr_hits ? SIOCINAFR :
295                                                            SIOCADAFR;
296                         if (fr->fr_hits)
297                                 fr->fr_hits--;
298                         if (fr && (opts & OPT_VERBOSE))
299                                 printfr(fr);
300                         if (fr && (opts & OPT_OUTQUE))
301                                 fr->fr_flags |= FR_OUTQUE;
302
303                         if (opts & OPT_DEBUG)
304                                 binprint(fr);
305
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)");
311                                 } else {
312 #ifdef  USE_QUAD_T
313                                         printf("hits %qd bytes %qd ",
314                                                 (long long)fr->fr_hits,
315                                                 (long long)fr->fr_bytes);
316 #else
317                                         printf("hits %ld bytes %ld ",
318                                                 fr->fr_hits, fr->fr_bytes);
319 #endif
320                                         printfr(fr);
321                                 }
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)");
327                                 }
328                         } else if (!(opts & OPT_DONOTHING)) {
329                                 if (ioctl(fd, add, &fr) == -1) {
330                                         fprintf(stderr, "%d:", linenum);
331                                         perror("ioctl(add/insert rule)");
332                                 }
333                         }
334                 }
335         }
336         if (ferror(fp) || !feof(fp)) {
337                 fprintf(stderr, "%s: %s: file error or line too long\n",
338                     name, file);
339                 exit(1);
340         }
341         (void)fclose(fp);
342 }
343
344 /*
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.
347  */
348 static char *getline(str, size, file, linenum)
349 register char   *str;
350 size_t  size;
351 FILE    *file;
352 int     *linenum;
353 {
354         char *p;
355         int s, len;
356
357         do {
358                 for (p = str, s = size;; p += (len - 1), s -= (len - 1)) {
359                         /*
360                          * if an error occured, EOF was encounterd, or there
361                          * was no room to put NUL, return NULL.
362                          */
363                         if (fgets(p, s, file) == NULL)
364                                 return (NULL);
365                         len = strlen(p);
366                         if (p[len - 1] != '\n') {
367                                 p[len] = '\0';
368                                 break;
369                         }
370                         (*linenum)++;
371                         p[len - 1] = '\0';
372                         if (len < 2 || p[len - 2] != '\\')
373                                 break;
374                         else
375                                 /*
376                                  * Convert '\\' to a space so words don't
377                                  * run together
378                                  */
379                                 p[len - 2] = ' ';
380                 }
381         } while (*str == '\0');
382         return (str);
383 }
384
385
386 static void packetlogon(opt)
387 char    *opt;
388 {
389         int     flag, err;
390
391         flag = get_flags();
392         if (flag != 0) {
393                 if ((opts & (OPT_DONOTHING|OPT_VERBOSE)) == OPT_VERBOSE)
394                         printf("log flag is currently %#x\n", flag);
395         }
396
397         flag &= ~(FF_LOGPASS|FF_LOGNOMATCH|FF_LOGBLOCK);
398
399         if (index(opt, 'p')) {
400                 flag |= FF_LOGPASS;
401                 if (opts & OPT_VERBOSE)
402                         printf("set log flag: pass\n");
403         }
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");
408         }
409         if (index(opt, 'b') || index(opt, 'd')) {
410                 flag |= FF_LOGBLOCK;
411                 if (opts & OPT_VERBOSE)
412                         printf("set log flag: block\n");
413         }
414
415         if (opendevice(ipfname) != -2 && (err = ioctl(fd, SIOCSETFF, &flag)))
416                 perror("ioctl(SIOCSETFF)");
417
418         if ((opts & (OPT_DONOTHING|OPT_VERBOSE)) == OPT_VERBOSE) {
419                 flag = get_flags();
420                 printf("log flag is now %#x\n", flag);
421         }
422 }
423
424
425 static  void    flushfilter(arg)
426 char    *arg;
427 {
428         int     fl = 0, rem;
429
430         if (!arg || !*arg)
431                 return;
432         if (!strcmp(arg, "s") || !strcmp(arg, "S")) {
433                 if (*arg == 'S')
434                         fl = 0;
435                 else
436                         fl = 1;
437                 rem = fl;
438
439                 closedevice();
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);
446                 }
447                 closedevice();
448                 return;
449         }
450         if (strchr(arg, 'i') || strchr(arg, 'I'))
451                 fl = FR_INQUE;
452         if (strchr(arg, 'o') || strchr(arg, 'O'))
453                 fl = FR_OUTQUE;
454         if (strchr(arg, 'a') || strchr(arg, 'A'))
455                 fl = FR_OUTQUE|FR_INQUE;
456         fl |= (opts & FR_INACTIVE);
457         rem = fl;
458
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);
465         }
466         return;
467 }
468
469
470 static void swapactive()
471 {
472         int in = 2;
473
474         if (opendevice(ipfname) != -2 && ioctl(fd, SIOCSWAPA, &in) == -1)
475                 perror("ioctl(SIOCSWAPA)");
476         else
477                 printf("Set %d now inactive\n", in);
478 }
479
480
481 void frsync()
482 {
483         int frsyn = 0;
484
485         if (opendevice(ipfname) != -2 && ioctl(fd, SIOCFRSYN, &frsyn) == -1)
486                 perror("SIOCFRSYN");
487         else
488                 printf("filter sync'd\n");
489 }
490
491
492 void zerostats()
493 {
494         friostat_t      fio;
495         friostat_t      *fiop = &fio;
496
497         if (opendevice(ipfname) != -2) {
498                 if (ioctl(fd, SIOCFRZST, &fiop) == -1) {
499                         perror("ioctl(SIOCFRZST)");
500                         exit(-1);
501                 }
502                 showstats(fiop);
503         }
504
505 }
506
507
508 /*
509  * read the kernel stats for packets blocked and passed
510  */
511 static void showstats(fp)
512 friostat_t      *fp;
513 {
514 #if SOLARIS
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);
521 #endif
522         printf(" input packets:\t\tblocked %lu passed %lu nomatch %lu",
523                         fp->f_st[0].fr_block, fp->f_st[0].fr_pass,
524                         fp->f_st[0].fr_nom);
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,
528                         fp->f_st[1].fr_nom);
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);
537 }
538
539
540 #if SOLARIS
541 static void blockunknown()
542 {
543         u_32_t  flag;
544
545         if (opendevice(ipfname) == -1)
546                 return;
547
548         flag = get_flags();
549         if ((opts & (OPT_DONOTHING|OPT_VERBOSE)) == OPT_VERBOSE)
550                 printf("log flag is currently %#x\n", flag);
551
552         flag ^= FF_BLOCKNONIP;
553
554         if (opendevice(ipfname) != -2 && ioctl(fd, SIOCSETFF, &flag))
555                 perror("ioctl(SIOCSETFF)");
556
557         if ((opts & (OPT_DONOTHING|OPT_VERBOSE)) == OPT_VERBOSE) {
558                 if (ioctl(fd, SIOCGETFF, &flag))
559                         perror("ioctl(SIOCGETFF)");
560
561                 printf("log flag is now %#x\n", flag);
562         }
563 }
564 #endif
565
566
567 static int showversion()
568 {
569         struct friostat fio;
570         struct friostat *fiop=&fio;
571         u_32_t flags;
572         char *s;
573         int vfd;
574
575         printf("ipf: %s (%d)\n", IPL_VERSION, (int)sizeof(frentry_t));
576
577         if ((vfd = open(ipfname, O_RDONLY)) == -1) {
578                 perror("open device");
579                 return 1;
580         }
581
582         if (ioctl(vfd, SIOCGETFS, &fiop)) {
583                 perror("ioctl(SIOCGETFS)");
584                 close(vfd);
585                 return 1;
586         }
587         close(vfd);
588         flags = get_flags();
589
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);
594         s = "";
595         if (flags & FF_LOGPASS) {
596                 printf("pass");
597                 s = ", ";
598         }
599         if (flags & FF_LOGBLOCK) {
600                 printf("%sblock", s);
601                 s = ", ";
602         }
603         if (flags & FF_LOGNOMATCH) {
604                 printf("%snomatch", s);
605                 s = ", ";
606         }
607         if (flags & FF_BLOCKNONIP) {
608                 printf("%snonip", s);
609                 s = ", ";
610         }
611         if (!*s)
612                 printf("none set");
613         putchar('\n');
614
615         printf("Default: ");
616         if (fio.f_defpass & FR_PASS)
617                 s = "pass";
618         else if (fio.f_defpass & FR_BLOCK)
619                 s = "block";
620         else
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);
624
625         return 0;
626 }