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.
This commit is contained in:
parent
c2906d55d0
commit
aa045fa499
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=41308
@ -6,8 +6,11 @@
|
|||||||
.Nd controlling utility for IP firewall
|
.Nd controlling utility for IP firewall
|
||||||
.Sh SYNOPSIS
|
.Sh SYNOPSIS
|
||||||
.Nm ipfw
|
.Nm ipfw
|
||||||
|
.Op Fl q
|
||||||
.Oo
|
.Oo
|
||||||
.Fl q
|
.Fl p Ar preproc
|
||||||
|
.Op Fl D Ar macro Ns Op Ns =value
|
||||||
|
.Op Fl U Ar macro
|
||||||
.Oc
|
.Oc
|
||||||
file
|
file
|
||||||
.Nm ipfw
|
.Nm ipfw
|
||||||
@ -58,6 +61,32 @@ will be read line by line and applied as arguments to the
|
|||||||
.Nm
|
.Nm
|
||||||
command.
|
command.
|
||||||
.Pp
|
.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
|
The
|
||||||
.Nm
|
.Nm
|
||||||
code works by going through the rule-list for each packet,
|
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
|
.Pp
|
||||||
.Dl ipfw divert 5000 all from 192.168.2.0/24 to any in
|
.Dl ipfw divert 5000 all from 192.168.2.0/24 to any in
|
||||||
.Sh SEE ALSO
|
.Sh SEE ALSO
|
||||||
|
.Xr cpp 1 ,
|
||||||
|
.Xr m4 1 ,
|
||||||
.Xr divert 4 ,
|
.Xr divert 4 ,
|
||||||
.Xr ip 4 ,
|
.Xr ip 4 ,
|
||||||
.Xr ipfirewall 4 ,
|
.Xr ipfirewall 4 ,
|
||||||
|
127
sbin/ipfw/ipfw.c
127
sbin/ipfw/ipfw.c
@ -16,7 +16,7 @@
|
|||||||
*
|
*
|
||||||
* NEW command line interface for IP firewall facility
|
* 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/socket.h>
|
||||||
#include <sys/sockio.h>
|
#include <sys/sockio.h>
|
||||||
#include <sys/time.h>
|
#include <sys/time.h>
|
||||||
|
#include <sys/wait.h>
|
||||||
|
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
#include <err.h>
|
#include <err.h>
|
||||||
|
#include <errno.h>
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
#include <netdb.h>
|
#include <netdb.h>
|
||||||
|
#include <signal.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <sysexits.h>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <sysexits.h>
|
|
||||||
|
|
||||||
#include <net/if.h>
|
#include <net/if.h>
|
||||||
#include <netinet/in.h>
|
#include <netinet/in.h>
|
||||||
@ -1199,7 +1202,7 @@ ipfw_main(ac,av)
|
|||||||
{
|
{
|
||||||
|
|
||||||
int ch;
|
int ch;
|
||||||
extern int optind;
|
extern int optreset; /* XXX should be declared in <unistd.h> */
|
||||||
|
|
||||||
if ( ac == 1 ) {
|
if ( ac == 1 ) {
|
||||||
show_usage(NULL);
|
show_usage(NULL);
|
||||||
@ -1208,7 +1211,7 @@ ipfw_main(ac,av)
|
|||||||
/* Set the force flag for non-interactive processes */
|
/* Set the force flag for non-interactive processes */
|
||||||
do_force = !isatty(STDIN_FILENO);
|
do_force = !isatty(STDIN_FILENO);
|
||||||
|
|
||||||
optind = 1;
|
optind = optreset = 1;
|
||||||
while ((ch = getopt(ac, av, "afqtN")) != -1)
|
while ((ch = getopt(ac, av, "afqtN")) != -1)
|
||||||
switch(ch) {
|
switch(ch) {
|
||||||
case 'a':
|
case 'a':
|
||||||
@ -1289,10 +1292,11 @@ main(ac, av)
|
|||||||
#define MAX_ARGS 32
|
#define MAX_ARGS 32
|
||||||
#define WHITESP " \t\f\v\n\r"
|
#define WHITESP " \t\f\v\n\r"
|
||||||
char buf[BUFSIZ];
|
char buf[BUFSIZ];
|
||||||
char *a, *args[MAX_ARGS];
|
char *a, *p, *args[MAX_ARGS], *cmd = NULL;
|
||||||
char linename[10];
|
char linename[10];
|
||||||
int i, qflag=0;
|
int i, c, qflag, pflag, status;
|
||||||
FILE *f;
|
FILE *f = NULL;
|
||||||
|
pid_t preproc = 0;
|
||||||
|
|
||||||
s = socket( AF_INET, SOCK_RAW, IPPROTO_RAW );
|
s = socket( AF_INET, SOCK_RAW, IPPROTO_RAW );
|
||||||
if ( s < 0 )
|
if ( s < 0 )
|
||||||
@ -1300,14 +1304,94 @@ main(ac, av)
|
|||||||
|
|
||||||
setbuf(stdout,0);
|
setbuf(stdout,0);
|
||||||
|
|
||||||
if (av[1] && (!access(av[1], R_OK) ||
|
if (ac > 1 && access(av[ac - 1], R_OK) == 0) {
|
||||||
(av[2] && (qflag=!strcmp(av[1],"-q")) && !access(av[2], R_OK)))){
|
qflag = pflag = i = 0;
|
||||||
lineno = 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++;
|
lineno++;
|
||||||
sprintf(linename, "Line %d", lineno);
|
sprintf(linename, "Line %d", lineno);
|
||||||
args[0] = linename;
|
args[0] = linename;
|
||||||
@ -1321,7 +1405,7 @@ main(ac, av)
|
|||||||
for (a = strtok(buf, WHITESP);
|
for (a = strtok(buf, WHITESP);
|
||||||
a && i < MAX_ARGS; a = strtok(NULL, WHITESP), i++)
|
a && i < MAX_ARGS; a = strtok(NULL, WHITESP), i++)
|
||||||
args[i] = a;
|
args[i] = a;
|
||||||
if (i == 1)
|
if (i == (qflag? 2: 1))
|
||||||
continue;
|
continue;
|
||||||
if (i == MAX_ARGS)
|
if (i == MAX_ARGS)
|
||||||
errx(EX_USAGE, "%s: too many arguments", linename);
|
errx(EX_USAGE, "%s: too many arguments", linename);
|
||||||
@ -1330,6 +1414,21 @@ main(ac, av)
|
|||||||
ipfw_main(i, args);
|
ipfw_main(i, args);
|
||||||
}
|
}
|
||||||
fclose(f);
|
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
|
} else
|
||||||
ipfw_main(ac,av);
|
ipfw_main(ac,av);
|
||||||
return EX_OK;
|
return EX_OK;
|
||||||
|
Loading…
Reference in New Issue
Block a user