Default kdump's data limit to 64 bytes and document how it can be disabled.
[dragonfly.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 #if defined(__sgi) && (IRIX > 602)
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.23 2003/06/27 14:39:13 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 extern  int     optind;
65
66 void    frsync __P((void));
67 void    zerostats __P((void));
68 int     main __P((int, char *[]));
69
70 int     opts = 0;
71 int     use_inet6 = 0;
72
73 static  int     fd = -1;
74
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 *));
86
87
88 #if SOLARIS
89 # define        OPTS    "6AdDEf:F:Il:noPrsUvVyzZ"
90 #else
91 # define        OPTS    "6AdDEf:F:Il:noPrsvVyzZ"
92 #endif
93
94 static void usage(name)
95 char *name;
96 {
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]");
99         exit(1);
100 }
101
102
103 int main(argc,argv)
104 int argc;
105 char *argv[];
106 {
107         int c;
108
109         if (argc < 2)
110                 usage(argv[0]);
111
112         while ((c = getopt(argc, argv, OPTS)) != -1) {
113                 switch (c)
114                 {
115                 case '6' :
116                         use_inet6 = 1;
117                         break;
118                 case 'A' :
119                         opts &= ~OPT_INACTIVE;
120                         break;
121                 case 'E' :
122                         if (set_state((u_int)1))
123                                 exit(1);
124                         break;
125                 case 'D' :
126                         if (set_state((u_int)0))
127                                 exit(1);
128                         break;
129                 case 'd' :
130                         opts |= OPT_DEBUG;
131                         break;
132                 case 'f' :
133                         procfile(argv[0], optarg);
134                         break;
135                 case 'F' :
136                         flushfilter(optarg);
137                         break;
138                 case 'I' :
139                         opts |= OPT_INACTIVE;
140                         break;
141                 case 'l' :
142                         packetlogon(optarg);
143                         break;
144                 case 'n' :
145                         opts |= OPT_DONOTHING;
146                         break;
147                 case 'o' :
148                         break;
149                 case 'P' :
150                         ipfname = IPL_AUTH;
151                         break;
152                 case 'r' :
153                         opts |= OPT_REMOVE;
154                         break;
155                 case 's' :
156                         swapactive();
157                         break;
158 #if SOLARIS
159                 case 'U' :
160                         blockunknown();
161                         break;
162 #endif
163                 case 'v' :
164                         opts += OPT_VERBOSE;
165                         break;
166                 case 'V' :
167                         if (showversion())
168                                 exit(1);
169                         break;
170                 case 'y' :
171                         frsync();
172                         break;
173                 case 'z' :
174                         opts |= OPT_ZERORULEST;
175                         break;
176                 case 'Z' :
177                         zerostats();
178                         break;
179                 case '?' :
180                 default :
181                         usage(argv[0]);
182                         break;
183                 }
184         }
185
186         if (optind < 2)
187                 usage(argv[0]);
188
189         if (fd != -1)
190                 (void) close(fd);
191
192         exit(0);
193         /* NOTREACHED */
194 }
195
196
197 static int opendevice(ipfdev)
198 char *ipfdev;
199 {
200         if (opts & OPT_DONOTHING)
201                 return 0;
202
203         if (!ipfdev)
204                 ipfdev = ipfname;
205
206         /*
207          * shouldn't we really be testing for fd < 0 here and below?
208          */
209
210         if (fd != -1)
211                 return 0;
212
213         if ((fd = open(ipfdev, O_RDWR)) == -1) {
214                 if ((fd = open(ipfdev, O_RDONLY)) == -1) {
215                         perror("open device");
216                         if (errno == ENODEV)
217                                 fprintf(stderr, "IPFilter enabled?\n");
218                         return -1;
219                 }
220         }
221
222         return 0;
223 }
224
225
226 static void closedevice()
227 {
228         if (fd != -1)
229                 close(fd);
230         fd = -1;
231 }
232
233
234 /*
235  * Return codes:
236  *      0       Success
237  *      !0      Failure (and an error message has already been printed)
238  */
239 static  int     get_flags(i)
240 int     *i;
241 {
242
243         if (opts & OPT_DONOTHING)
244                 return 0;
245
246         if (opendevice(ipfname) < 0)
247                 return -1;
248
249         if (ioctl(fd, SIOCGETFF, i) == -1) {
250                 perror("SIOCGETFF");
251                 return -1;
252         }
253         return 0;
254 }
255
256
257 static  int     set_state(enable)
258 u_int   enable;
259 {
260         if (opts & OPT_DONOTHING)
261                 return 0;
262
263         if (opendevice(ipfname))
264                 return -1;
265
266         if (ioctl(fd, SIOCFRENB, &enable) == -1) {
267                 if (errno == EBUSY)
268                         /* Not really an error */
269                         fprintf(stderr,
270                                 "IP Filter: already initialized\n");
271                 else {
272                         perror("SIOCFRENB");
273                         return -1;
274                 }
275         }
276         return 0;
277 }
278
279 static  void    procfile(name, file)
280 char    *name, *file;
281 {
282         FILE    *fp;
283         char    line[513], *s;
284         struct  frentry *fr;
285         u_int   add, del;
286         int     linenum = 0;
287         int     parsestatus;
288
289         if (opendevice(ipfname) == -1)
290                 exit(1);
291
292         if (opts & OPT_INACTIVE) {
293                 add = SIOCADIFR;
294                 del = SIOCRMIFR;
295         } else {
296                 add = SIOCADAFR;
297                 del = SIOCRMAFR;
298         }
299         if (opts & OPT_DEBUG)
300                 printf("add %x del %x\n", add, del);
301
302         initparse();
303
304         if (!strcmp(file, "-"))
305                 fp = stdin;
306         else if (!(fp = fopen(file, "r"))) {
307                 fprintf(stderr, "%s: fopen(%s) failed: %s\n", name, file,
308                         STRERROR(errno));
309                 exit(1);
310         }
311
312         while (getline(line, sizeof(line), fp, &linenum)) {
313                 /*
314                  * treat CR as EOL.  LF is converted to NUL by getline().
315                  */
316                 if ((s = index(line, '\r')))
317                         *s = '\0';
318                 /*
319                  * # is comment marker, everything after is a ignored
320                  */
321                 if ((s = index(line, '#')))
322                         *s = '\0';
323
324                 if (!*line)
325                         continue;
326
327                 if (opts & OPT_VERBOSE)
328                         (void)fprintf(stderr, "[%s]\n", line);
329
330                 parsestatus = 1;
331                 fr = parse(line, linenum, &parsestatus);
332                 (void)fflush(stdout);
333
334                 if (parsestatus != 0) {
335                         fprintf(stderr, "%s: %s: %s error (%d), quitting\n",
336                             name, file,
337                             ((parsestatus < 0)? "parse": "internal"),
338                             parsestatus);
339                         exit(1);
340                 }
341
342                 if (fr) {
343                         if (opts & OPT_ZERORULEST)
344                                 add = SIOCZRLST;
345                         else if (opts & OPT_INACTIVE)
346                                 add = (u_int)fr->fr_hits ? SIOCINIFR :
347                                                            SIOCADIFR;
348                         else
349                                 add = (u_int)fr->fr_hits ? SIOCINAFR :
350                                                            SIOCADAFR;
351                         if (fr->fr_hits)
352                                 fr->fr_hits--;
353                         if (fr && (opts & OPT_VERBOSE))
354                                 printfr(fr);
355                         if (fr && (opts & OPT_OUTQUE))
356                                 fr->fr_flags |= FR_OUTQUE;
357
358                         if (opts & OPT_DEBUG)
359                                 binprint(fr);
360
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)");
366                                         exit(1);
367                                 } else {
368 #ifdef  USE_QUAD_T
369                                         printf("hits %qd bytes %qd ",
370                                                 (long long)fr->fr_hits,
371                                                 (long long)fr->fr_bytes);
372 #else
373                                         printf("hits %ld bytes %ld ",
374                                                 fr->fr_hits, fr->fr_bytes);
375 #endif
376                                         printfr(fr);
377                                 }
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)");
383                                         exit(1);
384                                 }
385                         } else if (!(opts & OPT_DONOTHING)) {
386                                 if (ioctl(fd, add, &fr) == -1) {
387                                         fprintf(stderr, "%d:", linenum);
388                                         perror("ioctl(add/insert rule)");
389                                         exit(1);
390                                 }
391                         }
392                 }
393         }
394         if (ferror(fp) || !feof(fp)) {
395                 fprintf(stderr, "%s: %s: file error or line too long\n",
396                     name, file);
397                 exit(1);
398         }
399         (void)fclose(fp);
400 }
401
402 /*
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.
405  */
406 static char *getline(str, size, file, linenum)
407 register char   *str;
408 size_t  size;
409 FILE    *file;
410 int     *linenum;
411 {
412         char *p;
413         int s, len;
414
415         do {
416                 for (p = str, s = size;; p += (len - 1), s -= (len - 1)) {
417                         /*
418                          * if an error occurred, EOF was encounterd, or there
419                          * was no room to put NUL, return NULL.
420                          */
421                         if (fgets(p, s, file) == NULL)
422                                 return (NULL);
423                         len = strlen(p);
424                         if (p[len - 1] != '\n') {
425                                 p[len] = '\0';
426                                 break;
427                         }
428                         (*linenum)++;
429                         p[len - 1] = '\0';
430                         if (len < 2 || p[len - 2] != '\\')
431                                 break;
432                         else
433                                 /*
434                                  * Convert '\\' to a space so words don't
435                                  * run together
436                                  */
437                                 p[len - 2] = ' ';
438                 }
439         } while (*str == '\0');
440         return (str);
441 }
442
443
444 static void packetlogon(opt)
445 char    *opt;
446 {
447         int     flag;
448
449         if (get_flags(&flag))
450                 exit(1);
451
452         if (flag != 0) {
453                 if ((opts & (OPT_DONOTHING|OPT_VERBOSE)) == OPT_VERBOSE)
454                         printf("log flag is currently %#x\n", flag);
455         }
456
457         flag &= ~(FF_LOGPASS|FF_LOGNOMATCH|FF_LOGBLOCK);
458
459         if (index(opt, 'p')) {
460                 flag |= FF_LOGPASS;
461                 if (opts & OPT_VERBOSE)
462                         printf("set log flag: pass\n");
463         }
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");
468         }
469         if (index(opt, 'b') || index(opt, 'd')) {
470                 flag |= FF_LOGBLOCK;
471                 if (opts & OPT_VERBOSE)
472                         printf("set log flag: block\n");
473         }
474
475         if (opendevice(ipfname) == -1) {
476                 exit(1);
477         }
478
479         if (!(opts & OPT_DONOTHING)) {
480                 if (ioctl(fd, SIOCSETFF, &flag) != 0) {
481                         perror("ioctl(SIOCSETFF)");
482                         exit(1);
483                 }
484         }
485
486         if ((opts & (OPT_DONOTHING|OPT_VERBOSE)) == OPT_VERBOSE) {
487                 /*
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
492                  * fails here.
493                  */
494                 if (get_flags(&flag))
495                         exit(1);
496                 printf("log flag is now %#x\n", flag);
497         }
498 }
499
500
501 static  void    flushfilter(arg)
502 char    *arg;
503 {
504         int     fl = 0, rem;
505
506         if (!arg || !*arg) {
507                 fprintf(stderr, "-F: no filter specified\n");
508                 exit(1);
509         }
510
511         if (!strcmp(arg, "s") || !strcmp(arg, "S")) {
512                 if (*arg == 'S')
513                         fl = 0;
514                 else
515                         fl = 1;
516                 rem = fl;
517
518                 closedevice();
519
520                 if (opendevice(IPL_STATE) == -1) {
521                         exit(1);
522                 }
523
524                 if (!(opts & OPT_DONOTHING)) {
525                         if (use_inet6) {
526                                 if (ioctl(fd, SIOCIPFL6, &fl) == -1) {
527                                         perror("ioctl(SIOCIPFL6)");
528                                         exit(1);
529                                 }
530                         } else {
531                                 if (ioctl(fd, SIOCIPFFL, &fl) == -1) {
532                                         perror("ioctl(SIOCIPFFL)");
533                                         exit(1);
534                                 }
535                         }
536                 }
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);
540                 }
541                 closedevice();
542                 return;
543         }
544         if (strchr(arg, 'i') || strchr(arg, 'I'))
545                 fl = FR_INQUE;
546         if (strchr(arg, 'o') || strchr(arg, 'O'))
547                 fl = FR_OUTQUE;
548         if (strchr(arg, 'a') || strchr(arg, 'A'))
549                 fl = FR_OUTQUE|FR_INQUE;
550         fl |= (opts & FR_INACTIVE);
551         rem = fl;
552
553         if (opendevice(ipfname) == -1) {
554                 exit(1);
555         }
556
557         if (!(opts & OPT_DONOTHING)) {
558                 if (use_inet6) {
559                         if (ioctl(fd, SIOCIPFL6, &fl) == -1) {
560                                 perror("ioctl(SIOCIPFL6)");
561                                 exit(1);
562                         }
563                 } else {
564                         if (ioctl(fd, SIOCIPFFL, &fl) == -1) {
565                                 perror("ioctl(SIOCIPFFL)");
566                                 exit(1);
567                         }
568                 }
569         }
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);
574         }
575         return;
576 }
577
578
579 static void swapactive()
580 {
581         int in = 2;
582
583         if (opendevice(ipfname) == -1) {
584                 exit(1);
585         }
586
587
588         if (!(opts & OPT_DONOTHING)) {
589                 if (ioctl(fd, SIOCSWAPA, &in) == -1) {
590                         perror("ioctl(SIOCSWAPA)");
591                         exit(1);
592                 }
593         }
594         printf("Set %d now inactive\n", in);
595 }
596
597
598 void frsync()
599 {
600         int frsyn = 0;
601
602         if (opendevice(ipfname) == -1)
603                 exit(1);
604
605         if (!(opts & OPT_DONOTHING)) {
606                 if (ioctl(fd, SIOCFRSYN, &frsyn) == -1) {
607                         perror("SIOCFRSYN");
608                         exit(1);
609                 }
610         }
611         printf("filter sync'd\n");
612 }
613
614
615 void zerostats()
616 {
617         friostat_t      fio;
618         friostat_t      *fiop = &fio;
619
620         if (opendevice(ipfname) == -1)
621                 exit(1);
622
623         if (!(opts & OPT_DONOTHING)) {
624                 if (ioctl(fd, SIOCFRZST, &fiop) == -1) {
625                         perror("ioctl(SIOCFRZST)");
626                         exit(-1);
627                 }
628                 showstats(fiop);
629         }
630
631 }
632
633
634 /*
635  * Read the kernel stats for packets blocked and passed
636  */
637 static void showstats(fp)
638 friostat_t      *fp;
639 {
640 #if SOLARIS
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);
647 #endif
648         printf(" input packets:\t\tblocked %lu passed %lu nomatch %lu",
649                         fp->f_st[0].fr_block, fp->f_st[0].fr_pass,
650                         fp->f_st[0].fr_nom);
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,
654                         fp->f_st[1].fr_nom);
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);
663 }
664
665
666 #if SOLARIS
667 static void blockunknown()
668 {
669         int     flag;
670
671         if (opendevice(ipfname) == -1)
672                 exit(1);
673
674         if (get_flags(&flag))
675                 exit(1);
676
677         if ((opts & (OPT_DONOTHING|OPT_VERBOSE)) == OPT_VERBOSE)
678                 printf("log flag is currently %#x\n", flag);
679
680         flag ^= FF_BLOCKNONIP;
681
682         if (opendevice(ipfname) == -1)
683                 exit(1);
684
685         if (!(opts & OPT_DONOTHING)) {
686                 if (ioctl(fd, SIOCSETFF, &flag))
687                         perror("ioctl(SIOCSETFF)");
688         }
689
690         if ((opts & (OPT_DONOTHING|OPT_VERBOSE)) == OPT_VERBOSE) {
691                 if (ioctl(fd, SIOCGETFF, &flag))
692                         perror("ioctl(SIOCGETFF)");
693
694                 printf("log flag is now %#x\n", flag);
695         }
696 }
697 #endif
698
699
700 /*
701  * nonzero return value means caller should exit with error
702  */
703 static int showversion()
704 {
705         struct friostat fio;
706         struct friostat *fiop=&fio;
707         int flags, vfd;
708         char *s;
709
710         printf("ipf: %s (%d)\n", IPL_VERSION, (int)sizeof(frentry_t));
711
712         if ((vfd = open(ipfname, O_RDONLY)) == -1) {
713                 perror("open device");
714                 return 1;
715         }
716
717         if (ioctl(vfd, SIOCGETFS, &fiop)) {
718                 perror("ioctl(SIOCGETFS)");
719                 close(vfd);
720                 return 1;
721         }
722         close(vfd);
723
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");
727
728         if (get_flags(&flags)) {
729                 return 1;
730         }
731         printf("Log Flags: %#x = ", flags);
732         s = "";
733         if (flags & FF_LOGPASS) {
734                 printf("pass");
735                 s = ", ";
736         }
737         if (flags & FF_LOGBLOCK) {
738                 printf("%sblock", s);
739                 s = ", ";
740         }
741         if (flags & FF_LOGNOMATCH) {
742                 printf("%snomatch", s);
743                 s = ", ";
744         }
745         if (flags & FF_BLOCKNONIP) {
746                 printf("%snonip", s);
747                 s = ", ";
748         }
749         if (!*s)
750                 printf("none set");
751         putchar('\n');
752
753         printf("Default: ");
754         if (fio.f_defpass & FR_PASS)
755                 s = "pass";
756         else if (fio.f_defpass & FR_BLOCK)
757                 s = "block";
758         else
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);
762
763         return 0;
764 }