]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sbin/ipf/ipf/ipf.c
ipfilter userland: Style(9) requires a space after return
[FreeBSD/FreeBSD.git] / sbin / ipf / ipf / ipf.c
1 /*      $FreeBSD$       */
2
3 /*
4  * Copyright (C) 2012 by Darren Reed.
5  *
6  * See the IPFILTER.LICENCE file for details on licencing.
7  */
8 #include "ipf.h"
9 #include <fcntl.h>
10 #include <ctype.h>
11 #include <sys/ioctl.h>
12 #include "netinet/ipl.h"
13
14 #if !defined(lint)
15 static const char sccsid[] = "@(#)ipf.c 1.23 6/5/96 (C) 1993-2000 Darren Reed";
16 static const char rcsid[] = "@(#)$Id$";
17 #endif
18
19 #if !defined(__SVR4) && defined(__GNUC__)
20 extern  char    *index(const char *, int);
21 #endif
22
23 extern  char    *optarg;
24 extern  int     optind;
25 extern  frentry_t *frtop;
26
27
28 void    ipf_frsync(void);
29 void    zerostats(void);
30 int     main(int, char *[]);
31
32 int     opts = 0;
33 int     outputc = 0;
34 int     use_inet6 = 0;
35 int     exitstatus = 0;
36
37 static  void    procfile(char *);
38 static  void    flushfilter(char *, int *);
39 static  void    set_state(u_int);
40 static  void    showstats(friostat_t *);
41 static  void    packetlogon(char *);
42 static  void    swapactive(void);
43 static  int     opendevice(char *, int);
44 static  void    closedevice(void);
45 static  char    *ipfname = IPL_NAME;
46 static  void    usage(void);
47 static  int     showversion(void);
48 static  int     get_flags(void);
49 static  int     ipf_interceptadd(int, ioctlfunc_t, void *);
50
51 static  int     fd = -1;
52 static  ioctlfunc_t     iocfunctions[IPL_LOGSIZE] = { ioctl, ioctl, ioctl,
53                                                       ioctl, ioctl, ioctl,
54                                                       ioctl, ioctl };
55
56 /* XXX  The following was added to satisfy a rescue/rescue/ build
57    XXX  requirement.  */
58 int     nohdrfields;
59
60 static void usage()
61 {
62         fprintf(stderr, "usage: ipf [-6AdDEInoPrRsvVyzZ] %s %s %s\n",
63                 "[-l block|pass|nomatch|state|nat]", "[-cc] [-F i|o|a|s|S|u]",
64                 "[-f filename] [-T <tuneopts>]");
65         exit(1);
66 }
67
68
69 int
70 main(int argc, char *argv[])
71 {
72         int c, *filter = NULL;
73
74         if (argc < 2)
75                 usage();
76
77         assigndefined(getenv("IPF_PREDEFINED"));
78
79         while ((c = getopt(argc, argv, "46Ac:dDEf:F:Il:m:noPrRsT:vVyzZ")) != -1) {
80                 switch (c)
81                 {
82                 case '?' :
83                         usage();
84                         break;
85                 case '4' :
86                         use_inet6 = -1;
87                         break;
88                 case '6' :
89                         use_inet6 = 1;
90                         break;
91                 case 'A' :
92                         opts &= ~OPT_INACTIVE;
93                         break;
94                 case 'c' :
95                         if (strcmp(optarg, "c") == 0)
96                                 outputc = 1;
97                         break;
98                 case 'E' :
99                         set_state((u_int)1);
100                         break;
101                 case 'D' :
102                         set_state((u_int)0);
103                         break;
104                 case 'd' :
105                         opts ^= OPT_DEBUG;
106                         break;
107                 case 'f' :
108                         procfile(optarg);
109                         break;
110                 case 'F' :
111                         flushfilter(optarg, filter);
112                         break;
113                 case 'I' :
114                         opts ^= OPT_INACTIVE;
115                         break;
116                 case 'l' :
117                         packetlogon(optarg);
118                         break;
119                 case 'm' :
120                         filter = parseipfexpr(optarg, NULL);
121                         break;
122                 case 'n' :
123                         opts ^= OPT_DONOTHING|OPT_DONTOPEN;
124                         break;
125                 case 'o' :
126                         break;
127                 case 'P' :
128                         ipfname = IPAUTH_NAME;
129                         break;
130                 case 'R' :
131                         opts ^= OPT_NORESOLVE;
132                         break;
133                 case 'r' :
134                         opts ^= OPT_REMOVE;
135                         break;
136                 case 's' :
137                         swapactive();
138                         break;
139                 case 'T' :
140                         if (opendevice(ipfname, 1) >= 0)
141                                 ipf_dotuning(fd, optarg, ioctl);
142                         break;
143                 case 'v' :
144                         opts += OPT_VERBOSE;
145                         break;
146                 case 'V' :
147                         if (showversion())
148                                 exit(1);
149                         break;
150                 case 'y' :
151                         ipf_frsync();
152                         break;
153                 case 'z' :
154                         opts ^= OPT_ZERORULEST;
155                         break;
156                 case 'Z' :
157                         zerostats();
158                         break;
159                 }
160         }
161
162         if (optind < 2)
163                 usage();
164
165         if (fd != -1)
166                 (void) close(fd);
167
168         return (exitstatus);
169         /* NOTREACHED */
170 }
171
172
173 static int
174 opendevice(char *ipfdev, int check)
175 {
176         if (opts & OPT_DONOTHING)
177                 return (-2);
178
179         if (check && checkrev(ipfname) == -1) {
180                 fprintf(stderr, "User/kernel version check failed\n");
181                 return (-2);
182         }
183
184         if (!ipfdev)
185                 ipfdev = ipfname;
186
187         if (fd == -1)
188                 if ((fd = open(ipfdev, O_RDWR)) == -1)
189                         if ((fd = open(ipfdev, O_RDONLY)) == -1)
190                                 ipferror(fd, "open device");
191         return (fd);
192 }
193
194
195 static void
196 closedevice(void)
197 {
198         close(fd);
199         fd = -1;
200 }
201
202
203 static int
204 get_flags(void)
205 {
206         int i = 0;
207
208         if ((opendevice(ipfname, 1) != -2) &&
209             (ioctl(fd, SIOCGETFF, &i) == -1)) {
210                 ipferror(fd, "SIOCGETFF");
211                 return (0);
212         }
213         return (i);
214 }
215
216
217 static void
218 set_state(u_int enable)
219 {
220         if (opendevice(ipfname, 0) != -2) {
221                 if (ioctl(fd, SIOCFRENB, &enable) == -1) {
222                         if (errno == EBUSY) {
223                                 fprintf(stderr,
224                                         "IP FIlter: already initialized\n");
225                         } else {
226                                 ipferror(fd, "SIOCFRENB");
227                         }
228                 }
229         }
230         return;
231 }
232
233
234 static void
235 procfile(char *file)
236 {
237         (void) opendevice(ipfname, 1);
238
239         initparse();
240
241         ipf_parsefile(fd, ipf_interceptadd, iocfunctions, file);
242
243         if (outputc) {
244                 printC(0);
245                 printC(1);
246                 emit(-1, -1, NULL, NULL);
247         }
248 }
249
250
251 static int
252 ipf_interceptadd(int fd, ioctlfunc_t ioctlfunc, void *ptr)
253 {
254         if (outputc)
255                 printc(ptr);
256
257         if (ipf_addrule(fd, ioctlfunc, ptr) != 0)
258                 exitstatus = 1;
259         return (0);
260 }
261
262
263 static void
264 packetlogon(char *opt)
265 {
266         int     flag, xfd, logopt, change = 0;
267
268         flag = get_flags();
269         if (flag != 0) {
270                 if ((opts & (OPT_DONOTHING|OPT_VERBOSE)) == OPT_VERBOSE)
271                         printf("log flag is currently %#x\n", flag);
272         }
273
274         flag &= ~(FF_LOGPASS|FF_LOGNOMATCH|FF_LOGBLOCK);
275
276         if (strstr(opt, "pass")) {
277                 flag |= FF_LOGPASS;
278                 if (opts & OPT_VERBOSE)
279                         printf("set log flag: pass\n");
280                 change = 1;
281         }
282         if (strstr(opt, "nomatch")) {
283                 flag |= FF_LOGNOMATCH;
284                 if (opts & OPT_VERBOSE)
285                         printf("set log flag: nomatch\n");
286                 change = 1;
287         }
288         if (strstr(opt, "block") || strchr(opt, 'd')) {
289                 flag |= FF_LOGBLOCK;
290                 if (opts & OPT_VERBOSE)
291                         printf("set log flag: block\n");
292                 change = 1;
293         }
294         if (strstr(opt, "none")) {
295                 if (opts & OPT_VERBOSE)
296                         printf("disable all log flags\n");
297                 change = 1;
298         }
299
300         if (change == 1) {
301                 if (opendevice(ipfname, 1) != -2 &&
302                     (ioctl(fd, SIOCSETFF, &flag) != 0))
303                         ipferror(fd, "ioctl(SIOCSETFF)");
304         }
305
306         if ((opts & (OPT_DONOTHING|OPT_VERBOSE)) == OPT_VERBOSE) {
307                 flag = get_flags();
308                 printf("log flags are now %#x\n", flag);
309         }
310
311         if (strstr(opt, "state")) {
312                 if (opts & OPT_VERBOSE)
313                         printf("set state log flag\n");
314                 xfd = open(IPSTATE_NAME, O_RDWR);
315                 if (xfd >= 0) {
316                         logopt = 0;
317                         if (ioctl(xfd, SIOCGETLG, &logopt))
318                                 ipferror(fd, "ioctl(SIOCGETLG)");
319                         else {
320                                 logopt = 1 - logopt;
321                                 if (ioctl(xfd, SIOCSETLG, &logopt))
322                                         ipferror(xfd, "ioctl(SIOCSETLG)");
323                         }
324                         close(xfd);
325                 }
326         }
327
328         if (strstr(opt, "nat")) {
329                 if (opts & OPT_VERBOSE)
330                         printf("set nat log flag\n");
331                 xfd = open(IPNAT_NAME, O_RDWR);
332                 if (xfd >= 0) {
333                         logopt = 0;
334                         if (ioctl(xfd, SIOCGETLG, &logopt))
335                                 ipferror(xfd, "ioctl(SIOCGETLG)");
336                         else {
337                                 logopt = 1 - logopt;
338                                 if (ioctl(xfd, SIOCSETLG, &logopt))
339                                         ipferror(xfd, "ioctl(SIOCSETLG)");
340                         }
341                         close(xfd);
342                 }
343         }
344 }
345
346
347 static void
348 flushfilter(char *arg, int *filter)
349 {
350         int     fl = 0, rem;
351
352         if (!arg || !*arg)
353                 return;
354         if (!strcmp(arg, "s") || !strcmp(arg, "S") || ISDIGIT(*arg)) {
355                 if (*arg == 'S')
356                         fl = 0;
357                 else if (*arg == 's')
358                         fl = 1;
359                 else
360                         fl = atoi(arg);
361                 rem = fl;
362
363                 closedevice();
364                 if (opendevice(IPSTATE_NAME, 1) == -2)
365                         exit(1);
366
367                 if (!(opts & OPT_DONOTHING)) {
368                         if (use_inet6) {
369                                 fprintf(stderr,
370                                         "IPv6 rules are no longer seperate\n");
371                         } else if (filter != NULL) {
372                                 ipfobj_t obj;
373
374                                 obj.ipfo_rev = IPFILTER_VERSION;
375                                 obj.ipfo_size = filter[0] * sizeof(int);
376                                 obj.ipfo_type = IPFOBJ_IPFEXPR;
377                                 obj.ipfo_ptr = filter;
378                                 if (ioctl(fd, SIOCMATCHFLUSH, &obj) == -1) {
379                                         ipferror(fd, "ioctl(SIOCMATCHFLUSH)");
380                                         fl = -1;
381                                 } else {
382                                         fl = obj.ipfo_retval;
383                                 }
384                         } else {
385                                 if (ioctl(fd, SIOCIPFFL, &fl) == -1) {
386                                         ipferror(fd, "ioctl(SIOCIPFFL)");
387                                         exit(1);
388                                 }
389                         }
390                 }
391                 if ((opts & (OPT_DONOTHING|OPT_DEBUG)) == OPT_DEBUG) {
392                         printf("remove flags %s (%d)\n", arg, rem);
393                 }
394                 if ((opts & (OPT_DONOTHING|OPT_VERBOSE)) == OPT_VERBOSE) {
395                         printf("%d state entries removed\n", fl);
396                 }
397                 closedevice();
398                 return;
399         } else if (strchr(arg, 'i') || strchr(arg, 'I'))
400                 fl = FR_INQUE;
401         else if (strchr(arg, 'o') || strchr(arg, 'O'))
402                 fl = FR_OUTQUE;
403         else if (strchr(arg, 'a') || strchr(arg, 'A'))
404                 fl = FR_OUTQUE|FR_INQUE;
405         else {
406                 fprintf(stderr, "Incorrect flush argument: %s\n", arg);
407                 usage();
408         }
409         if (opts & OPT_INACTIVE)
410                 fl |= FR_INACTIVE;
411         rem = fl;
412
413         if (opendevice(ipfname, 1) == -2)
414                 exit(1);
415
416         if (!(opts & OPT_DONOTHING)) {
417                 if (use_inet6) {
418                         if (ioctl(fd, SIOCIPFL6, &fl) == -1) {
419                                 ipferror(fd, "ioctl(SIOCIPFL6)");
420                                 exit(1);
421                         }
422                 } else {
423                         if (ioctl(fd, SIOCIPFFL, &fl) == -1) {
424                                 ipferror(fd, "ioctl(SIOCIPFFL)");
425                                 exit(1);
426                         }
427                 }
428         }
429
430         if ((opts & (OPT_DONOTHING|OPT_DEBUG)) == OPT_DEBUG) {
431                 printf("remove flags %s%s (%d)\n", (rem & FR_INQUE) ? "I" : "",
432                         (rem & FR_OUTQUE) ? "O" : "", rem);
433         }
434         if ((opts & (OPT_DONOTHING|OPT_VERBOSE)) == OPT_VERBOSE) {
435                 printf("%d filter rules removed\n", fl);
436         }
437         return;
438 }
439
440
441 static void
442 swapactive(void)
443 {
444         int in = 2;
445
446         if (opendevice(ipfname, 1) != -2 && ioctl(fd, SIOCSWAPA, &in) == -1)
447                 ipferror(fd, "ioctl(SIOCSWAPA)");
448         else
449                 printf("Set %d now inactive\n", in);
450 }
451
452
453 void
454 ipf_frsync(void)
455 {
456         int frsyn = 0;
457
458         if (opendevice(ipfname, 1) != -2 && ioctl(fd, SIOCFRSYN, &frsyn) == -1)
459                 ipferror(fd, "SIOCFRSYN");
460         else
461                 printf("filter sync'd\n");
462 }
463
464
465 void
466 zerostats(void)
467 {
468         ipfobj_t        obj;
469         friostat_t      fio;
470
471         obj.ipfo_rev = IPFILTER_VERSION;
472         obj.ipfo_type = IPFOBJ_IPFSTAT;
473         obj.ipfo_size = sizeof(fio);
474         obj.ipfo_ptr = &fio;
475         obj.ipfo_offset = 0;
476
477         if (opendevice(ipfname, 1) != -2) {
478                 if (ioctl(fd, SIOCFRZST, &obj) == -1) {
479                         ipferror(fd, "ioctl(SIOCFRZST)");
480                         exit(-1);
481                 }
482                 showstats(&fio);
483         }
484
485 }
486
487
488 /*
489  * read the kernel stats for packets blocked and passed
490  */
491 static void
492 showstats(friostat_t *fp)
493 {
494         printf("bad packets:\t\tin %lu\tout %lu\n",
495                         fp->f_st[0].fr_bad, fp->f_st[1].fr_bad);
496         printf(" input packets:\t\tblocked %lu passed %lu nomatch %lu",
497                         fp->f_st[0].fr_block, fp->f_st[0].fr_pass,
498                         fp->f_st[0].fr_nom);
499         printf(" counted %lu\n", fp->f_st[0].fr_acct);
500         printf("output packets:\t\tblocked %lu passed %lu nomatch %lu",
501                         fp->f_st[1].fr_block, fp->f_st[1].fr_pass,
502                         fp->f_st[1].fr_nom);
503         printf(" counted %lu\n", fp->f_st[0].fr_acct);
504         printf(" input packets logged:\tblocked %lu passed %lu\n",
505                         fp->f_st[0].fr_bpkl, fp->f_st[0].fr_ppkl);
506         printf("output packets logged:\tblocked %lu passed %lu\n",
507                         fp->f_st[1].fr_bpkl, fp->f_st[1].fr_ppkl);
508 }
509
510
511 static int
512 showversion(void)
513 {
514         struct friostat fio;
515         ipfobj_t ipfo;
516         u_32_t flags;
517         char *s;
518         int vfd;
519
520         bzero((caddr_t)&ipfo, sizeof(ipfo));
521         ipfo.ipfo_rev = IPFILTER_VERSION;
522         ipfo.ipfo_size = sizeof(fio);
523         ipfo.ipfo_ptr = (void *)&fio;
524         ipfo.ipfo_type = IPFOBJ_IPFSTAT;
525
526         printf("ipf: %s (%d)\n", IPL_VERSION, (int)sizeof(frentry_t));
527
528         if ((vfd = open(ipfname, O_RDONLY)) == -1) {
529                 perror("open device");
530                 return (1);
531         }
532
533         if (ioctl(vfd, SIOCGETFS, &ipfo)) {
534                 ipferror(vfd, "ioctl(SIOCGETFS)");
535                 close(vfd);
536                 return (1);
537         }
538         close(vfd);
539         flags = get_flags();
540
541         printf("Kernel: %-*.*s\n", (int)sizeof(fio.f_version),
542                 (int)sizeof(fio.f_version), fio.f_version);
543         printf("Running: %s\n", (fio.f_running > 0) ? "yes" : "no");
544         printf("Log Flags: %#x = ", flags);
545         s = "";
546         if (flags & FF_LOGPASS) {
547                 printf("pass");
548                 s = ", ";
549         }
550         if (flags & FF_LOGBLOCK) {
551                 printf("%sblock", s);
552                 s = ", ";
553         }
554         if (flags & FF_LOGNOMATCH) {
555                 printf("%snomatch", s);
556                 s = ", ";
557         }
558         if (flags & FF_BLOCKNONIP) {
559                 printf("%snonip", s);
560                 s = ", ";
561         }
562         if (!*s)
563                 printf("none set");
564         putchar('\n');
565
566         printf("Default: ");
567         if (FR_ISPASS(fio.f_defpass))
568                 s = "pass";
569         else if (FR_ISBLOCK(fio.f_defpass))
570                 s = "block";
571         else
572                 s = "nomatch -> block";
573         printf("%s all, Logging: %savailable\n", s, fio.f_logging ? "" : "un");
574         printf("Active list: %d\n", fio.f_active);
575         printf("Feature mask: %#x\n", fio.f_features);
576
577         return (0);
578 }