diff options
author | joerg <joerg@FreeBSD.org> | 1998-11-23 10:54:28 +0000 |
---|---|---|
committer | joerg <joerg@FreeBSD.org> | 1998-11-23 10:54:28 +0000 |
commit | f17aeea6de055b15cc6ea94cf29b4a7a64701f23 (patch) | |
tree | 1d71aff1d6c1e7124f035efd210433865eb23932 | |
parent | 1ca888b5fd87b8d85f835ab5cf2f42d45ca12791 (diff) | |
download | FreeBSD-src-f17aeea6de055b15cc6ea94cf29b4a7a64701f23.zip FreeBSD-src-f17aeea6de055b15cc6ea94cf29b4a7a64701f23.tar.gz |
Preprocessor support for `ipfw [-q] ... file'.
This allows for more flexible ipfw configuration files using
`variables' to describe frequently used items in the file, like the
local IP address(es), interface names etc. Both m4 and cpp are useful
and supported; with m4 being a little more unusual to the common C
programmer, things like automatic rule numbering can be achieved
fairly easy.
While i was at it, i've also untangled some of the ugly style inside
main(), and fixed a bug or two (like not being able to use blank lines
when running with -q).
A typical call with preprocessor invocation looks like
ipfw -p m4 -Dhostname=$(hostname) /etc/fwrules
Someone should probably add support for this feature to /etc/rc.firewall.
-rw-r--r-- | sbin/ipfw/ipfw.8 | 33 | ||||
-rw-r--r-- | sbin/ipfw/ipfw.c | 127 |
2 files changed, 145 insertions, 15 deletions
diff --git a/sbin/ipfw/ipfw.8 b/sbin/ipfw/ipfw.8 index bd70c58..d7f8cd8 100644 --- a/sbin/ipfw/ipfw.8 +++ b/sbin/ipfw/ipfw.8 @@ -6,8 +6,11 @@ .Nd controlling utility for IP firewall .Sh SYNOPSIS .Nm ipfw +.Op Fl q .Oo -.Fl q +.Fl p Ar preproc +.Op Fl D Ar macro Ns Op Ns =value +.Op Fl U Ar macro .Oc file .Nm ipfw @@ -58,6 +61,32 @@ will be read line by line and applied as arguments to the .Nm command. .Pp +Optionally, a preprocessor can be specified using +.Fl p Ar preproc +where +.Ar file +is to be piped through. Useful preprocessors include +.Xr cpp 1 +and +.Xr m4 1 . +If +.Ar preproc +doesn't start with a slash as its first character, the usual +.Ev PATH +name search is performed. Care should be taken with this in environments +where not all filesystems are mounted (yet) by the time +.Nm +is being run (e. g. since they are mounted over NFS). Once +.Fl p +has been specified, optional +.Fl D +and +.Fl U +specifcations can follow and will be passed on to the preprocessor. +This allows for flexible configuration files (like conditionalizing +them on the local hostname) and the use of macros to centralize +frequently required arguments like IP addresses. +.Pp The .Nm code works by going through the rule-list for each packet, @@ -515,6 +544,8 @@ This rule diverts all incoming packets from 192.168.2.0/24 to divert port 5000: .Pp .Dl ipfw divert 5000 all from 192.168.2.0/24 to any in .Sh SEE ALSO +.Xr cpp 1 , +.Xr m4 1 , .Xr divert 4 , .Xr ip 4 , .Xr ipfirewall 4 , diff --git a/sbin/ipfw/ipfw.c b/sbin/ipfw/ipfw.c index 3f6807b..d0f06ce 100644 --- a/sbin/ipfw/ipfw.c +++ b/sbin/ipfw/ipfw.c @@ -16,7 +16,7 @@ * * NEW command line interface for IP firewall facility * - * $Id: ipfw.c,v 1.59 1998/08/04 14:41:37 thepish Exp $ + * $Id: ipfw.c,v 1.60 1998/09/28 22:56:37 alex Exp $ * */ @@ -25,18 +25,21 @@ #include <sys/socket.h> #include <sys/sockio.h> #include <sys/time.h> +#include <sys/wait.h> #include <ctype.h> #include <err.h> +#include <errno.h> #include <limits.h> #include <netdb.h> +#include <signal.h> #include <stdio.h> #include <stdlib.h> #include <stdarg.h> #include <string.h> +#include <sysexits.h> #include <time.h> #include <unistd.h> -#include <sysexits.h> #include <net/if.h> #include <netinet/in.h> @@ -1199,7 +1202,7 @@ ipfw_main(ac,av) { int ch; - extern int optind; + extern int optreset; /* XXX should be declared in <unistd.h> */ if ( ac == 1 ) { show_usage(NULL); @@ -1208,7 +1211,7 @@ ipfw_main(ac,av) /* Set the force flag for non-interactive processes */ do_force = !isatty(STDIN_FILENO); - optind = 1; + optind = optreset = 1; while ((ch = getopt(ac, av, "afqtN")) != -1) switch(ch) { case 'a': @@ -1289,10 +1292,11 @@ main(ac, av) #define MAX_ARGS 32 #define WHITESP " \t\f\v\n\r" char buf[BUFSIZ]; - char *a, *args[MAX_ARGS]; + char *a, *p, *args[MAX_ARGS], *cmd = NULL; char linename[10]; - int i, qflag=0; - FILE *f; + int i, c, qflag, pflag, status; + FILE *f = NULL; + pid_t preproc = 0; s = socket( AF_INET, SOCK_RAW, IPPROTO_RAW ); if ( s < 0 ) @@ -1300,14 +1304,94 @@ main(ac, av) setbuf(stdout,0); - if (av[1] && (!access(av[1], R_OK) || - (av[2] && (qflag=!strcmp(av[1],"-q")) && !access(av[2], R_OK)))){ + if (ac > 1 && access(av[ac - 1], R_OK) == 0) { + qflag = pflag = i = 0; lineno = 0; - if ((f = fopen(av[ac-1], "r")) == NULL) - err(EX_UNAVAILABLE, "fopen: %s", av[ac-1]); - while (fgets(buf, BUFSIZ, f)) { - char *p; + while ((c = getopt(ac, av, "D:U:p:q")) != -1) + switch(c) { + case 'D': + if (!pflag) + errx(EX_USAGE, "-D requires -p"); + if (i > MAX_ARGS - 2) + errx(EX_USAGE, + "too many -D or -U options"); + args[i++] = "-D"; + args[i++] = optarg; + break; + + case 'U': + if (!pflag) + errx(EX_USAGE, "-U requires -p"); + if (i > MAX_ARGS - 2) + errx(EX_USAGE, + "too many -D or -U options"); + args[i++] = "-U"; + args[i++] = optarg; + break; + + case 'p': + pflag = 1; + cmd = optarg; + args[0] = cmd; + i = 1; + break; + + case 'q': + qflag = 1; + break; + + default: + show_usage(NULL); + } + + av += optind; + ac -= optind; + if (ac != 1) + show_usage("extraneous filename arguments"); + + if ((f = fopen(av[0], "r")) == NULL) + err(EX_UNAVAILABLE, "fopen: %s", av[0]); + + if (pflag) { + /* pipe through preprocessor (cpp or m4) */ + int pipedes[2]; + + args[i] = 0; + + if (pipe(pipedes) == -1) + err(EX_OSERR, "cannot create pipe"); + + switch((preproc = fork())) { + case -1: + err(EX_OSERR, "cannot fork"); + + case 0: + /* child */ + if (dup2(fileno(f), 0) == -1 || + dup2(pipedes[1], 1) == -1) + err(EX_OSERR, "dup2()"); + fclose(f); + close(pipedes[1]); + close(pipedes[0]); + execvp(cmd, args); + err(EX_OSERR, "execvp(%s) failed", cmd); + + default: + /* parent */ + fclose(f); + close(pipedes[1]); + if ((f = fdopen(pipedes[0], "r")) == NULL) { + int savederrno = errno; + + (void)kill(preproc, SIGTERM); + errno = savederrno; + err(EX_OSERR, "fdopen()"); + } + } + } + + while (fgets(buf, BUFSIZ, f)) { lineno++; sprintf(linename, "Line %d", lineno); args[0] = linename; @@ -1321,7 +1405,7 @@ main(ac, av) for (a = strtok(buf, WHITESP); a && i < MAX_ARGS; a = strtok(NULL, WHITESP), i++) args[i] = a; - if (i == 1) + if (i == (qflag? 2: 1)) continue; if (i == MAX_ARGS) errx(EX_USAGE, "%s: too many arguments", linename); @@ -1330,6 +1414,21 @@ main(ac, av) ipfw_main(i, args); } fclose(f); + if (pflag) { + if (waitpid(preproc, &status, 0) != -1) { + if (WIFEXITED(status)) { + if (WEXITSTATUS(status) != EX_OK) + errx(EX_UNAVAILABLE, + "preprocessor exited with status %d", + WEXITSTATUS(status)); + } else if (WIFSIGNALED(status)) { + errx(EX_UNAVAILABLE, + "preprocessor exited with signal %d", + WTERMSIG(status)); + } + } + } + } else ipfw_main(ac,av); return EX_OK; |