From owner-freebsd-bugs Sat Oct 14 10: 0:15 2000 Delivered-To: freebsd-bugs@freebsd.org Received: from freefall.freebsd.org (freefall.FreeBSD.org [216.136.204.21]) by hub.freebsd.org (Postfix) with ESMTP id A53C137B66F for ; Sat, 14 Oct 2000 10:00:01 -0700 (PDT) Received: (from gnats@localhost) by freefall.freebsd.org (8.9.3/8.9.2) id KAA02702; Sat, 14 Oct 2000 10:00:01 -0700 (PDT) (envelope-from gnats@FreeBSD.org) Received: from mail.gmx.net (pop.gmx.net [194.221.183.20]) by hub.freebsd.org (Postfix) with SMTP id 021C237B503 for ; Sat, 14 Oct 2000 09:55:20 -0700 (PDT) Received: (qmail 10232 invoked by uid 0); 14 Oct 2000 16:55:17 -0000 Received: from p3ee21601.dip.t-dialin.net (HELO speedy.gsinet) (62.226.22.1) by mail.gmx.net with SMTP; 14 Oct 2000 16:55:17 -0000 Received: (from sittig@localhost) by speedy.gsinet (8.8.8/8.8.8) id SAA29587 for FreeBSD-gnats-submit@freebsd.org; Sat, 14 Oct 2000 18:24:39 +0200 Message-Id: <20001014182439.Q25237@speedy.gsinet> Date: Sat, 14 Oct 2000 18:24:39 +0200 From: Gerhard Sittig To: FreeBSD-gnats-submit@freebsd.org Subject: bin/21989: [PATCH] preprocessor for ipfilter rules Sender: owner-freebsd-bugs@FreeBSD.ORG Precedence: bulk X-Loop: FreeBSD.org >Number: 21989 >Category: bin >Synopsis: preprocessor for ipfilter rules >Confidential: no >Severity: non-critical >Priority: medium >Responsible: freebsd-bugs >State: open >Quarter: >Keywords: >Date-Required: >Class: change-request >Submitter-Id: current-users >Arrival-Date: Sat Oct 14 10:00:01 PDT 2000 >Closed-Date: >Last-Modified: >Originator: Gerhard Sittig >Release: FreeBSD 4.1-STABLE i386 >Organization: in private >Environment: Any FreeBSD version with ipfilter included as well as any other platform ipfilter runs on, I guess. :) It's just that FreeBSD users might notice the absense (lack?) of a preprocessor more than others since ipfw has the -p option. :> >Description: When loading (or manipulating) rules with ipf(8) and handing a rules file to the command, the input has to be in exact ipf language. There's no possibility to have - variables substituted - loops unrolled - translation from some more abstract language down to ipf syntax done All of this of couse could be done by specifying "-" as the file (or omitting the -f option) and feeding ipf's stdin from the appropriate source. But this doesn't fit well into the (typical?) command invocation in the rc.conf and rc.network environment (or whatever the boot scripts are called on the platform ipf is used at). >How-To-Repeat: It should be obvious. :) And reading "man ipfw" with a search for "/-p" will give the idea that there's something "that would be useful here, too". >Fix: Apply the following patch. The code got tested here, but the doc wasn't. For some reason "man -M . ipf" refused to work from within the src/contrib/ipfilter directory. But it needs rewording and markup corrections, anyway, and doesn't fit for immediate application. :) Since many option flags were in use already I had to do the passing with one command line string. But this is not a real drawback. And I slowly get the feeling that "-" isn't even an exception to the passing to the preprocessor. Index: ../../contrib/ipfilter/ipf.c =================================================================== RCS file: /home/fcvs/src/contrib/ipfilter/ipf.c,v retrieving revision 1.1.1.9 diff -u -r1.1.1.9 ipf.c --- ../../contrib/ipfilter/ipf.c 2000/08/13 04:57:48 1.1.1.9 +++ ../../contrib/ipfilter/ipf.c 2000/10/14 15:19:07 @@ -66,7 +66,8 @@ static int fd = -1; -static void procfile __P((char *, char *)), flushfilter __P((char *)); +static void procfile __P((char *, char *, char *)); +static void flushfilter __P((char *)); static void set_state __P((u_int)), showstats __P((friostat_t *)); static void packetlogon __P((char *)), swapactive __P((void)); static int opendevice __P((char *)); @@ -81,7 +82,8 @@ static void usage() { fprintf(stderr, "usage: ipf [-6AdDEInoPrsUvVyzZ] %s %s %s\n", - "[-l block|pass|nomatch]", "[-F i|o|a|s|S]", "[-f filename]"); + "[-l block|pass|nomatch]", "[-F i|o|a|s|S]", + "[-p preprocessor_command] [-f filename]"); exit(1); } @@ -91,8 +93,9 @@ char *argv[]; { int c; + char *pp_name = NULL; - while ((c = getopt(argc, argv, "6AdDEf:F:Il:noPrsUvVyzZ")) != -1) { + while ((c = getopt(argc, argv, "6AdDEf:F:Il:nop:PrsUvVyzZ")) != -1) { switch (c) { case '?' : @@ -115,7 +118,7 @@ opts |= OPT_DEBUG; break; case 'f' : - procfile(argv[0], optarg); + procfile(argv[0], optarg, pp_name); break; case 'F' : flushfilter(optarg); @@ -131,6 +134,9 @@ break; case 'o' : break; + case 'p' : + pp_name = optarg; + break; case 'P' : ipfname = IPL_AUTH; break; @@ -221,14 +227,21 @@ return; } -static void procfile(name, file) -char *name, *file; +static void procfile(name, file, pp_fn) +char *name, *file, *pp_fn; { FILE *fp; char line[513], *s; struct frentry *fr; u_int add, del; int linenum = 0; +#define PP_ARG_MAX 32 +#define PP_ARG_SEP " \t" + int pp_pipe[2]; + int pp_pid; + int pp_argc; + char *pp_argv[PP_ARG_MAX + 1]; + char *pp_tmp; (void) opendevice(ipfname); @@ -250,6 +263,69 @@ fprintf(stderr, "%s: fopen(%s) failed: %s\n", name, file, STRERROR(errno)); exit(1); + } + + /* pipe the rules through a preprocessor if specified */ + if (pp_fn && *pp_fn) { + + if (pipe(pp_pipe) == -1) { + fprintf(stderr, "%s: pipe() failed: %s\n", + name, STRERROR(errno)); + exit(1); + } + + /* + * FreeBSD has strsep(3), but others might not; + * maybe we could use system(3) or popen(3) + * and get rid of all the dimensioning/strtok stuff? + */ + for ( pp_argc = 0, pp_tmp = strtok(pp_fn, PP_ARG_SEP); + (pp_tmp) && (pp_argc < PP_ARG_MAX); + pp_tmp = strtok(NULL, PP_ARG_SEP) + ) { + /* cope with adjacent delimiters */ + if (*pp_tmp) + pp_argv[pp_argc++] = pp_tmp; + } + pp_argv[pp_argc] = NULL; + if (pp_tmp) { + fprintf(stderr, "%s: too many preprocessor args, " + "ignored \"%s\" and following\n", + name, pp_tmp); + } + + switch(pp_pid = fork()) { + case -1: + fprintf(stderr, "%s: fork() failed: %s\n", + name, STRERROR(errno)); + exit(1); + + case 0: /* preprocessor job (child) */ + if ((dup2(fileno(fp), 0) == -1) || + (dup2(pp_pipe[1], 1) == -1)) { + fprintf(stderr, "%s: dup2() failed: %s\n", + name, STRERROR(errno)); + exit(1); + } + fclose(fp); + close(pp_pipe[1]); + close(pp_pipe[0]); + execvp(pp_argv[0], pp_argv); + fprintf(stderr, "%s: exec(%s) failed: %s\n", + name, pp_argv[0], STRERROR(errno)); + exit(1); + + default: /* ipf job (parent) */ + fclose(fp); + close(pp_pipe[1]); + if (! (fp = fdopen(pp_pipe[0], "r"))) { + fprintf(stderr, "%s: fdopen() failed: %s\n", + name, STRERROR(errno)); + kill(pp_pid, SIGTERM); + exit(1); + } + break; + } } while (getline(line, sizeof(line), fp)) { Index: ../../contrib/ipfilter/man/ipf.8 =================================================================== RCS file: /home/fcvs/src/contrib/ipfilter/man/ipf.8,v retrieving revision 1.4 diff -u -r1.4 ipf.8 --- ../../contrib/ipfilter/man/ipf.8 2000/05/24 02:19:15 1.4 +++ ../../contrib/ipfilter/man/ipf.8 2000/10/14 15:58:17 @@ -12,6 +12,9 @@ ] [ .B \-F +] [ +.B \-p +<\fIpreprocessor\fP> ] .B \-f <\fIfilename\fP> @@ -84,6 +87,17 @@ .B \-o Force rules by default to be added/deleted to/from the output list, rather than the (default) input list. +.TP +.BR \-p \0 +All of the files in subsequent \fB-f\fP options +are fed into this command's stdin, its stdout +is read back and processed instead of the file's content. +This command gets invoked anew for every specified filename. +This option only applies to real files, +not to stdin specified with its "-" alias. +Specifying an empty command will turn this feature off, again. +Shell escapes are needed when passing arguments to this command. +Up to 31 parameters (like \fB-D\fP and \fB-U\fP) can be passed. .TP .B \-P Add rules as temporary entries in the authentication rule table. The test case looks like this: $ head pp_in.txt #define WORLD world #define HELLO hello HELLO WORLD EXTDEF works too $ ./ipf -v -p /usr/bin/cpp -f ./pp_in.txt open device: Permission denied [hello world ] 2: unknown keyword (hello) [EXTDEF works too] 3: unknown keyword (EXTDEF) $ ./ipf -v -p '/usr/bin/cpp -DEXTDEF=external' -f ./pp_in.txt open device: Permission denied [hello world ] 2: unknown keyword (hello) [external works too] 3: unknown keyword (external) $ And of course it doesn't touch the ones who don't use -p: $ ./ipf -v -f ./pp_in.txt open device: Permission denied [HELLO WORLD] 3: unknown keyword (HELLO) [EXTDEF works too] 4: unknown keyword (EXTDEF) $ virtually yours 82D1 9B9C 01DC 4FB4 D7B4 61BE 3F49 4F77 72DE DA76 Gerhard Sittig true | mail -s "get gpg key" Gerhard.Sittig@gmx.net -- If you don't understand or are scared by any of the above ask your parents or an adult to help you. >Release-Note: >Audit-Trail: >Unformatted: To Unsubscribe: send mail to majordomo@FreeBSD.org with "unsubscribe freebsd-bugs" in the body of the message