]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/ipfilter/ipf.c
This commit was generated by cvs2svn to compensate for changes in r100966,
[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.16 2002/06/06 10:48:35 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                                 if (errno == ENODEV)
199                                         fprintf(stderr, "IPFilter enabled?\n");
200                         }
201         return fd;
202 }
203
204
205 static void closedevice()
206 {
207         close(fd);
208         fd = -1;
209 }
210
211
212 static  int     get_flags()
213 {
214         int i;
215
216         if ((opendevice(ipfname) != -2) && (ioctl(fd, SIOCGETFF, &i) == -1)) {
217                 perror("SIOCGETFF");
218                 return 0;
219         }
220         return i;
221 }
222
223
224 static  void    set_state(enable)
225 u_int   enable;
226 {
227         if (opendevice(ipfname) != -2)
228                 if (ioctl(fd, SIOCFRENB, &enable) == -1) {
229                         if (errno == EBUSY)
230                                 fprintf(stderr,
231                                         "IP Filter: already initialized\n");
232                         else
233                                 perror("SIOCFRENB");
234                 }
235         return;
236 }
237
238 static  void    procfile(name, file)
239 char    *name, *file;
240 {
241         FILE    *fp;
242         char    line[513], *s;
243         struct  frentry *fr;
244         u_int   add, del;
245         int     linenum = 0;
246
247         (void) opendevice(ipfname);
248
249         if (opts & OPT_INACTIVE) {
250                 add = SIOCADIFR;
251                 del = SIOCRMIFR;
252         } else {
253                 add = SIOCADAFR;
254                 del = SIOCRMAFR;
255         }
256         if (opts & OPT_DEBUG)
257                 printf("add %x del %x\n", add, del);
258
259         initparse();
260
261         if (!strcmp(file, "-"))
262                 fp = stdin;
263         else if (!(fp = fopen(file, "r"))) {
264                 fprintf(stderr, "%s: fopen(%s) failed: %s\n", name, file,
265                         STRERROR(errno));
266                 exit(1);
267         }
268
269         while (getline(line, sizeof(line), fp, &linenum)) {
270                 /*
271                  * treat CR as EOL.  LF is converted to NUL by getline().
272                  */
273                 if ((s = index(line, '\r')))
274                         *s = '\0';
275                 /*
276                  * # is comment marker, everything after is a ignored
277                  */
278                 if ((s = index(line, '#')))
279                         *s = '\0';
280
281                 if (!*line)
282                         continue;
283
284                 if (opts & OPT_VERBOSE)
285                         (void)fprintf(stderr, "[%s]\n", line);
286
287                 fr = parse(line, linenum);
288                 (void)fflush(stdout);
289
290                 if (fr) {
291                         if (opts & OPT_ZERORULEST)
292                                 add = SIOCZRLST;
293                         else if (opts & OPT_INACTIVE)
294                                 add = (u_int)fr->fr_hits ? SIOCINIFR :
295                                                            SIOCADIFR;
296                         else
297                                 add = (u_int)fr->fr_hits ? SIOCINAFR :
298                                                            SIOCADAFR;
299                         if (fr->fr_hits)
300                                 fr->fr_hits--;
301                         if (fr && (opts & OPT_VERBOSE))
302                                 printfr(fr);
303                         if (fr && (opts & OPT_OUTQUE))
304                                 fr->fr_flags |= FR_OUTQUE;
305
306                         if (opts & OPT_DEBUG)
307                                 binprint(fr);
308
309                         if ((opts & OPT_ZERORULEST) &&
310                             !(opts & OPT_DONOTHING)) {
311                                 if (ioctl(fd, add, &fr) == -1) {
312                                         fprintf(stderr, "%d:", linenum);
313                                         perror("ioctl(SIOCZRLST)");
314                                 } else {
315 #ifdef  USE_QUAD_T
316                                         printf("hits %qd bytes %qd ",
317                                                 (long long)fr->fr_hits,
318                                                 (long long)fr->fr_bytes);
319 #else
320                                         printf("hits %ld bytes %ld ",
321                                                 fr->fr_hits, fr->fr_bytes);
322 #endif
323                                         printfr(fr);
324                                 }
325                         } else if ((opts & OPT_REMOVE) &&
326                                    !(opts & OPT_DONOTHING)) {
327                                 if (ioctl(fd, del, &fr) == -1) {
328                                         fprintf(stderr, "%d:", linenum);
329                                         perror("ioctl(delete rule)");
330                                 }
331                         } else if (!(opts & OPT_DONOTHING)) {
332                                 if (ioctl(fd, add, &fr) == -1) {
333                                         fprintf(stderr, "%d:", linenum);
334                                         perror("ioctl(add/insert rule)");
335                                 }
336                         }
337                 }
338         }
339         if (ferror(fp) || !feof(fp)) {
340                 fprintf(stderr, "%s: %s: file error or line too long\n",
341                     name, file);
342                 exit(1);
343         }
344         (void)fclose(fp);
345 }
346
347 /*
348  * Similar to fgets(3) but can handle '\\' and NL is converted to NUL.
349  * Returns NULL if error occured, EOF encounterd or input line is too long.
350  */
351 static char *getline(str, size, file, linenum)
352 register char   *str;
353 size_t  size;
354 FILE    *file;
355 int     *linenum;
356 {
357         char *p;
358         int s, len;
359
360         do {
361                 for (p = str, s = size;; p += (len - 1), s -= (len - 1)) {
362                         /*
363                          * if an error occured, EOF was encounterd, or there
364                          * was no room to put NUL, return NULL.
365                          */
366                         if (fgets(p, s, file) == NULL)
367                                 return (NULL);
368                         len = strlen(p);
369                         if (p[len - 1] != '\n') {
370                                 p[len] = '\0';
371                                 break;
372                         }
373                         (*linenum)++;
374                         p[len - 1] = '\0';
375                         if (len < 2 || p[len - 2] != '\\')
376                                 break;
377                         else
378                                 /*
379                                  * Convert '\\' to a space so words don't
380                                  * run together
381                                  */
382                                 p[len - 2] = ' ';
383                 }
384         } while (*str == '\0');
385         return (str);
386 }
387
388
389 static void packetlogon(opt)
390 char    *opt;
391 {
392         int     flag, err;
393
394         flag = get_flags();
395         if (flag != 0) {
396                 if ((opts & (OPT_DONOTHING|OPT_VERBOSE)) == OPT_VERBOSE)
397                         printf("log flag is currently %#x\n", flag);
398         }
399
400         flag &= ~(FF_LOGPASS|FF_LOGNOMATCH|FF_LOGBLOCK);
401
402         if (index(opt, 'p')) {
403                 flag |= FF_LOGPASS;
404                 if (opts & OPT_VERBOSE)
405                         printf("set log flag: pass\n");
406         }
407         if (index(opt, 'm') && (*opt == 'n' || *opt == 'N')) {
408                 flag |= FF_LOGNOMATCH;
409                 if (opts & OPT_VERBOSE)
410                         printf("set log flag: nomatch\n");
411         }
412         if (index(opt, 'b') || index(opt, 'd')) {
413                 flag |= FF_LOGBLOCK;
414                 if (opts & OPT_VERBOSE)
415                         printf("set log flag: block\n");
416         }
417
418         if (opendevice(ipfname) != -2 && (err = ioctl(fd, SIOCSETFF, &flag)))
419                 perror("ioctl(SIOCSETFF)");
420
421         if ((opts & (OPT_DONOTHING|OPT_VERBOSE)) == OPT_VERBOSE) {
422                 flag = get_flags();
423                 printf("log flag is now %#x\n", flag);
424         }
425 }
426
427
428 static  void    flushfilter(arg)
429 char    *arg;
430 {
431         int     fl = 0, rem;
432
433         if (!arg || !*arg)
434                 return;
435         if (!strcmp(arg, "s") || !strcmp(arg, "S")) {
436                 if (*arg == 'S')
437                         fl = 0;
438                 else
439                         fl = 1;
440                 rem = fl;
441
442                 closedevice();
443                 if (opendevice(IPL_STATE) != -2 &&
444                     ioctl(fd, SIOCIPFFL, &fl) == -1)
445                         perror("ioctl(SIOCIPFFL)");
446                 if ((opts & (OPT_DONOTHING|OPT_VERBOSE)) == OPT_VERBOSE) {
447                         printf("remove flags %s (%d)\n", arg, rem);
448                         printf("removed %d filter rules\n", fl);
449                 }
450                 closedevice();
451                 return;
452         }
453         if (strchr(arg, 'i') || strchr(arg, 'I'))
454                 fl = FR_INQUE;
455         if (strchr(arg, 'o') || strchr(arg, 'O'))
456                 fl = FR_OUTQUE;
457         if (strchr(arg, 'a') || strchr(arg, 'A'))
458                 fl = FR_OUTQUE|FR_INQUE;
459         fl |= (opts & FR_INACTIVE);
460         rem = fl;
461
462         if (opendevice(ipfname) != -2 && ioctl(fd, SIOCIPFFL, &fl) == -1)
463                 perror("ioctl(SIOCIPFFL)");
464         if ((opts & (OPT_DONOTHING|OPT_VERBOSE)) == OPT_VERBOSE) {
465                 printf("remove flags %s%s (%d)\n", (rem & FR_INQUE) ? "I" : "",
466                         (rem & FR_OUTQUE) ? "O" : "", rem);
467                 printf("removed %d filter rules\n", fl);
468         }
469         return;
470 }
471
472
473 static void swapactive()
474 {
475         int in = 2;
476
477         if (opendevice(ipfname) != -2 && ioctl(fd, SIOCSWAPA, &in) == -1)
478                 perror("ioctl(SIOCSWAPA)");
479         else
480                 printf("Set %d now inactive\n", in);
481 }
482
483
484 void frsync()
485 {
486         int frsyn = 0;
487
488         if (opendevice(ipfname) != -2 && ioctl(fd, SIOCFRSYN, &frsyn) == -1)
489                 perror("SIOCFRSYN");
490         else
491                 printf("filter sync'd\n");
492 }
493
494
495 void zerostats()
496 {
497         friostat_t      fio;
498         friostat_t      *fiop = &fio;
499
500         if (opendevice(ipfname) != -2) {
501                 if (ioctl(fd, SIOCFRZST, &fiop) == -1) {
502                         perror("ioctl(SIOCFRZST)");
503                         exit(-1);
504                 }
505                 showstats(fiop);
506         }
507
508 }
509
510
511 /*
512  * read the kernel stats for packets blocked and passed
513  */
514 static void showstats(fp)
515 friostat_t      *fp;
516 {
517 #if SOLARIS
518         printf("dropped packets:\tin %lu\tout %lu\n",
519                         fp->f_st[0].fr_drop, fp->f_st[1].fr_drop);
520         printf("non-ip packets:\t\tin %lu\tout %lu\n",
521                         fp->f_st[0].fr_notip, fp->f_st[1].fr_notip);
522         printf("   bad packets:\t\tin %lu\tout %lu\n",
523                         fp->f_st[0].fr_bad, fp->f_st[1].fr_bad);
524 #endif
525         printf(" input packets:\t\tblocked %lu passed %lu nomatch %lu",
526                         fp->f_st[0].fr_block, fp->f_st[0].fr_pass,
527                         fp->f_st[0].fr_nom);
528         printf(" counted %lu\n", fp->f_st[0].fr_acct);
529         printf("output packets:\t\tblocked %lu passed %lu nomatch %lu",
530                         fp->f_st[1].fr_block, fp->f_st[1].fr_pass,
531                         fp->f_st[1].fr_nom);
532         printf(" counted %lu\n", fp->f_st[0].fr_acct);
533         printf(" input packets logged:\tblocked %lu passed %lu\n",
534                         fp->f_st[0].fr_bpkl, fp->f_st[0].fr_ppkl);
535         printf("output packets logged:\tblocked %lu passed %lu\n",
536                         fp->f_st[1].fr_bpkl, fp->f_st[1].fr_ppkl);
537         printf(" packets logged:\tinput %lu-%lu output %lu-%lu\n",
538                         fp->f_st[0].fr_pkl, fp->f_st[0].fr_skip,
539                         fp->f_st[1].fr_pkl, fp->f_st[1].fr_skip);
540 }
541
542
543 #if SOLARIS
544 static void blockunknown()
545 {
546         u_32_t  flag;
547
548         if (opendevice(ipfname) == -1)
549                 return;
550
551         flag = get_flags();
552         if ((opts & (OPT_DONOTHING|OPT_VERBOSE)) == OPT_VERBOSE)
553                 printf("log flag is currently %#x\n", flag);
554
555         flag ^= FF_BLOCKNONIP;
556
557         if (opendevice(ipfname) != -2 && ioctl(fd, SIOCSETFF, &flag))
558                 perror("ioctl(SIOCSETFF)");
559
560         if ((opts & (OPT_DONOTHING|OPT_VERBOSE)) == OPT_VERBOSE) {
561                 if (ioctl(fd, SIOCGETFF, &flag))
562                         perror("ioctl(SIOCGETFF)");
563
564                 printf("log flag is now %#x\n", flag);
565         }
566 }
567 #endif
568
569
570 static int showversion()
571 {
572         struct friostat fio;
573         struct friostat *fiop=&fio;
574         u_32_t flags;
575         char *s;
576         int vfd;
577
578         printf("ipf: %s (%d)\n", IPL_VERSION, (int)sizeof(frentry_t));
579
580         if ((vfd = open(ipfname, O_RDONLY)) == -1) {
581                 perror("open device");
582                 return 1;
583         }
584
585         if (ioctl(vfd, SIOCGETFS, &fiop)) {
586                 perror("ioctl(SIOCGETFS)");
587                 close(vfd);
588                 return 1;
589         }
590         close(vfd);
591         flags = get_flags();
592
593         printf("Kernel: %-*.*s\n", (int)sizeof(fio.f_version),
594                 (int)sizeof(fio.f_version), fio.f_version);
595         printf("Running: %s\n", fio.f_running ? "yes" : "no");
596         printf("Log Flags: %#x = ", flags);
597         s = "";
598         if (flags & FF_LOGPASS) {
599                 printf("pass");
600                 s = ", ";
601         }
602         if (flags & FF_LOGBLOCK) {
603                 printf("%sblock", s);
604                 s = ", ";
605         }
606         if (flags & FF_LOGNOMATCH) {
607                 printf("%snomatch", s);
608                 s = ", ";
609         }
610         if (flags & FF_BLOCKNONIP) {
611                 printf("%snonip", s);
612                 s = ", ";
613         }
614         if (!*s)
615                 printf("none set");
616         putchar('\n');
617
618         printf("Default: ");
619         if (fio.f_defpass & FR_PASS)
620                 s = "pass";
621         else if (fio.f_defpass & FR_BLOCK)
622                 s = "block";
623         else
624                 s = "nomatch -> block";
625         printf("%s all, Logging: %savailable\n", s, fio.f_logging ? "" : "un");
626         printf("Active list: %d\n", fio.f_active);
627
628         return 0;
629 }