summaryrefslogtreecommitdiffstats
path: root/sbin/ipfw
diff options
context:
space:
mode:
authorjoerg <joerg@FreeBSD.org>1998-11-23 10:54:28 +0000
committerjoerg <joerg@FreeBSD.org>1998-11-23 10:54:28 +0000
commitf17aeea6de055b15cc6ea94cf29b4a7a64701f23 (patch)
tree1d71aff1d6c1e7124f035efd210433865eb23932 /sbin/ipfw
parent1ca888b5fd87b8d85f835ab5cf2f42d45ca12791 (diff)
downloadFreeBSD-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.
Diffstat (limited to 'sbin/ipfw')
-rw-r--r--sbin/ipfw/ipfw.833
-rw-r--r--sbin/ipfw/ipfw.c127
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;
OpenPOWER on IntegriCloud