diff options
-rw-r--r-- | sbin/pfctl/Makefile | 8 | ||||
-rw-r--r-- | sbin/pfctl/parse.y | 673 | ||||
-rw-r--r-- | sbin/pfctl/pfctl.c | 228 | ||||
-rw-r--r-- | sbin/pfctl/pfctl_parser.c | 788 | ||||
-rw-r--r-- | sbin/pfctl/pfctl_parser.h | 38 |
5 files changed, 817 insertions, 918 deletions
diff --git a/sbin/pfctl/Makefile b/sbin/pfctl/Makefile index 2c581314669..97b1b6338a5 100644 --- a/sbin/pfctl/Makefile +++ b/sbin/pfctl/Makefile @@ -1,10 +1,14 @@ # -# $OpenBSD: Makefile,v 1.3 2001/06/26 22:38:28 smart Exp $ +# $OpenBSD: Makefile,v 1.4 2001/07/16 21:09:36 markus Exp $ + +CLEANFILES+=parse.c y.tab.h PROG= pfctl -SRCS= pfctl.c pfctl_parser.c +SRCS= pfctl.c parse.c pfctl_parser.c MAN= pfctl.8 +DEBUG=-g + CFLAGS+= -Wall .include <bsd.prog.mk> diff --git a/sbin/pfctl/parse.y b/sbin/pfctl/parse.y new file mode 100644 index 00000000000..fc9bcd79f3f --- /dev/null +++ b/sbin/pfctl/parse.y @@ -0,0 +1,673 @@ +/* $OpenBSD: parse.y,v 1.1 2001/07/16 21:09:37 markus Exp $ */ + +/* + * Copyright (c) 2001 Markus Friedl. All rights reserved. + * Copyright (c) 2001 Daniel Hartmeier. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +%{ +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/ioctl.h> +#include <net/if.h> +#include <netinet/in.h> +#include <netinet/in_systm.h> +#include <netinet/ip.h> +#include <netinet/ip_icmp.h> +#include <net/pfvar.h> +#include <arpa/inet.h> + +#include <stdio.h> +#include <netdb.h> +#include <errno.h> +#include <string.h> +#include <ctype.h> +#include <err.h> + +#include "pfctl_parser.h" + +static struct pfctl *pf = NULL; +static FILE *fin = NULL; +static int debug = 0; +static int lineno = 1; +static int errors = 0; +static int natmode = 0; + +static int proto = 0; /* this is a synthesysed attribute */ + +int rule_consistent(struct pf_rule *); +int yyparse(void); +struct pf_rule_addr *new_addr(void); +u_int32_t ipmask(u_int8_t); + +%} +%union { + u_int32_t number; + int i; + char *string; + struct pf_rule_addr *addr; + struct { + struct pf_rule_addr *src, *dst; + } addr2; + struct { + char *string; + int not; + } iface; + struct { + u_int8_t b1; + u_int8_t b2; + u_int16_t w; + } b; + struct { + int a; + int b; + int t; + } range; +} +%token PASS BLOCK SCRUB RETURN IN OUT LOG LOGALL QUICK ON FROM TO FLAGS +%token RETURNRST RETURNICMP PROTO ALL ANY ICMPTYPE CODE KEEP STATE PORT +%token RDR NAT ARROW +%token <string> STRING +%token <number> NUMBER +%token <i> PORTUNARY PORTBINARY +%type <addr> ipportspec ipspec host portspec +%type <addr2> fromto +%type <iface> iface +%type <number> address port icmptype +%type <i> direction log quick keep proto +%type <b> action icmpspec flags blockspec +%type <range> dport rport +%% + +ruleset: /* empty */ + | ruleset '\n' + | ruleset pfrule '\n' + | ruleset natrule '\n' + | ruleset rdrrule '\n' + ; + +pfrule: action direction log quick iface proto fromto flags icmpspec keep + { + struct pf_rule r; + + if (natmode) + errx(1, "line %d: filter rule in nat mode", + lineno); + + memset(&r, 0, sizeof(r)); + + r.action = $1.b1; + if ($1.b2) + r.return_rst = 1; + else + r.return_icmp = $1.w; + r.direction = $2; + r.log = $3; + r.quick = $4; + if ($5.string) + memcpy(r.ifname, $5.string, sizeof(r.ifname)); + r.proto = $6; + proto = 0; /* reset syntesysed attribute */ + + memcpy(&r.src, $7.src, sizeof(r.src)); + free($7.src); + memcpy(&r.dst, $7.dst, sizeof(r.dst)); + free($7.dst); + + r.flags = $8.b1; + r.flagset = $8.b2; + r.type = $9.b1; + r.code = $9.b2; + r.keep_state = $10; + + if (rule_consistent(&r) < 0) + yyerror("skipping rule due to errors"); + else + pfctl_add_rule(pf, &r); + } + ; + +action: PASS { $$.b1 = PF_PASS; } + | BLOCK blockspec { $$ = $2; $$.b1 = PF_DROP; } + | SCRUB { $$.b1 = PF_SCRUB; } + ; + +blockspec: { $$.b2 = 0; $$.w = 0; } + | RETURNRST { $$.b2 = 1; $$.w = 0;} + | RETURNICMP { + $$.b2 = 0; + $$.w = (ICMP_UNREACH << 8) | ICMP_UNREACH_PORT; + } + | RETURNICMP '(' STRING ')' { + struct icmpcodeent *ic; + + ic = geticmpcodebyname(ICMP_UNREACH, $3); + if (ic == NULL) + errx(1, "line %d: unknown icmp code %s", + lineno, $3); + $$.b2 = 0; + $$.w = (ic->type << 8) | ic->code; + } + ; + +direction: IN { $$ = PF_IN; } + | OUT { $$ = PF_OUT; } + ; + +log: { $$ = 0; } + | LOG { $$ = 1; } + | LOGALL { $$ = 2; } + ; + +quick: { $$ = 0; } + | QUICK { $$ = 1; } + ; + +iface: { $$.string = NULL; } + | ON STRING { $$.string = strdup($2); } + | ON '!' STRING { $$.string = strdup($3); $$.not = 1;} + ; + +proto: { proto = $$ = natmode ? IPPROTO_TCP : 0; } + | PROTO NUMBER { + struct protoent *p; + + p = getprotobynumber($2); + if (p == NULL) + errx(1, "line %d: unknown protocol %d", lineno, + $2); + proto = $$ = p->p_proto; + } + | PROTO STRING { + struct protoent *p; + + p = getprotobyname($2); + if (p == NULL) + errx(1, "line %d: unknown protocol %s", lineno, + $2); + proto = $$ = p->p_proto; + } + ; + +fromto: ALL { + $$.src = new_addr(); + $$.dst = new_addr(); + } + | FROM ipportspec TO ipportspec { + $$.src = $2; + $$.dst = $4; + } + ; + +ipportspec: ipspec { $$ = $1; } + | ipspec portspec { + $$ = $1; + if ($2) { + $$->port[0] = $2->port[0]; + $$->port[1] = $2->port[1]; + $$->port_op = $2->port_op; + free($2); + } + } + ; + +ipspec: ANY { $$ = new_addr(); } + | '!' host { $$ = $2; $$->not = 1; } + | host { $$ = $1; } + ; + +host: address { + $$ = new_addr(); + $$->addr = $1; + $$->mask = 0xffffffff; + } + | + address '/' NUMBER { + $$ = new_addr(); + $$->addr = $1; + $$->mask = ipmask($3); + } + ; + +address: STRING { + struct hostent *hp; + + if (inet_pton(AF_INET, $1, &$$) != 1) { + if ((hp = gethostbyname($1)) == NULL) + errx(1, "line %d: cannot resolve %s", + lineno, $1); + memcpy(&$$, hp->h_addr, sizeof(u_int32_t)); + } + } + | NUMBER '.' NUMBER '.' NUMBER '.' NUMBER { + $$ = (htonl(($1 << 24) | ($3 << 16) | ($5 << 8) | $7)); + } + ; + +portspec: PORT PORTUNARY port { + $$ = new_addr(); + $$->port_op = $2; + $$->port[0] = $3; + $$->port[1] = $3; + } + | PORT port PORTBINARY port { + $$ = new_addr(); + $$->port[0] = $2; + $$->port_op = $3; + $$->port[1] = $4; + } + ; + +port: NUMBER { $$ = htons($1); } + | STRING { + struct servent *s = NULL; + + /* use synthesysed attribute */ + if (proto) + s = getservbyname($1, + proto == IPPROTO_TCP ? "tcp" : "udp"); + $$ = (s == NULL) ? 0 : s->s_port; + } + ; + +flags: { $$.b1 = 0; $$.b2 = 0; } + | FLAGS STRING { $$.b1 = parse_flags($2); $$.b2 = 63; } + | FLAGS STRING "/" STRING { + $$.b1 = parse_flags($2); + $$.b2 = parse_flags($4); + } + ; + +icmpspec: { $$.b1 = 0; $$.b2 = 0; } + | ICMPTYPE icmptype { $$.b1 = $2; $$.b2 = 0; } + | ICMPTYPE icmptype CODE NUMBER { + $$.b1 = $2; + $$.b2 = $4 + 1; + } + | ICMPTYPE icmptype CODE STRING { + struct icmpcodeent *ic; + + $$.b1 = $2; + ic = geticmpcodebyname($2, $4); + if (ic == NULL) + errx(1, "line %d: unknown icmp-code %s", + lineno, $4); + $$.b2 = ic->code + 1; + } + ; + +icmptype: STRING { + struct icmptypeent *te; + + te = geticmptypebyname($1); + if (te == NULL) + errx(1, "line %d: unknown icmp-type %s", + lineno, $1); + $$ = te->type + 1; + } + | NUMBER { $$ = $1 + 1; } + ; + + +keep: { $$ = 0; } + | KEEP STATE { $$ = 1; } + ; + +natrule: NAT iface proto FROM ipspec TO ipspec ARROW address + { + struct pf_nat nat; + + if (!natmode) + errx(1, "line %d: nat rule in filter mode", + lineno); + + memset(&nat, 0, sizeof(nat)); + + if ($2.string) { + memcpy(nat.ifname, $2.string, + sizeof(nat.ifname)); + nat.ifnot = $2.not; + } + nat.proto = $3; + proto = 0; /* reset syntesysed attribute */ + + nat.saddr = $5->addr; + nat.smask = $5->mask; + nat.snot = $5->not; + free($5); + + nat.daddr = $7->addr; + nat.dmask = $7->mask; + nat.dnot = $7->not; + free($7); + + nat.raddr = $9; + + pfctl_add_nat(pf, &nat); + } + ; + +rdrrule: RDR iface proto FROM ipspec TO ipspec dport ARROW address rport + { + struct pf_rdr rdr; + + if (!natmode) + errx(1, "line %d: nat rule in filter mode", + lineno); + + memset(&rdr, 0, sizeof(rdr)); + + if ($2.string) { + memcpy(rdr.ifname, $2.string, + sizeof(rdr.ifname)); + rdr.ifnot = $2.not; + } + rdr.proto = $3; + proto = 0; /* reset syntesysed attribute */ + + rdr.saddr = $5->addr; + rdr.smask = $5->mask; + rdr.snot = $5->not; + free($5); + + rdr.daddr = $7->addr; + rdr.dmask = $7->mask; + rdr.dnot = $7->not; + free($7); + + rdr.dport = $8.a; + rdr.dport2 = $8.b; + rdr.opts |= $8.t; + + rdr.raddr = $10; + + rdr.rport = $11.a; + rdr.opts |= $11.t; + + pfctl_add_rdr(pf, &rdr); + } + ; + +dport: PORT port { + $$.a = $2; + $$.b = $$.t = 0; + } + | PORT port ':' port { + $$.a = $2; + $$.b = $4; + $$.t = PF_DPORT_RANGE; + } + ; + +rport: PORT port { + $$.a = $2; + $$.b = $$.t = 0; + } + | PORT port ':' '*' { + $$.a = $2; + $$.b = 0; + $$.t = PF_RPORT_RANGE; + } + ; + +%% + +int +yyerror(char *s) +{ + errors = 1; + warnx("%s near line %d", s, lineno); + return 0; +} + +int +rule_consistent(struct pf_rule *r) +{ + int problems = 0; + + if (r->action == PF_SCRUB) { + if (r->quick) { + yyerror("quick does not apply to scrub"); + problems++; + } + if (r->keep_state) { + yyerror("keep state does not apply to scrub"); + problems++; + } + if (r->src.port_op) { + yyerror("src port does not apply to scrub"); + problems++; + } + if (r->dst.port_op) { + yyerror("dst port does not apply to scrub"); + problems++; + } + if (r->type || r->code) { + yyerror("icmp-type/code does not apply to scrub"); + problems++; + } + } + if (r->proto != IPPROTO_TCP && r->proto != IPPROTO_UDP && + (r->src.port_op || r->dst.port_op)) { + yyerror("ports do only apply to tcp/udp"); + problems++; + } + if (r->proto != IPPROTO_ICMP && (r->type || r->code)) { + yyerror("icmp-type/code does only apply to icmp"); + problems++; + } + return -problems; +} + +int +lookup(char *s) +{ + int i; + struct keywords { + char *k_name; + int k_val; + } keywords[] = { + { "all", ALL}, + { "any", ANY}, + { "block", BLOCK}, + { "code", CODE}, + { "flags", FLAGS}, + { "from", FROM}, + { "icmp-type", ICMPTYPE}, + { "in", IN}, + { "keep", KEEP}, + { "log", LOG}, + { "log-all", LOGALL}, + { "nat", NAT}, + { "on", ON}, + { "out", OUT}, + { "pass", PASS}, + { "port", PORT}, + { "proto", PROTO}, + { "quick", QUICK}, + { "rdr", RDR}, + { "return", RETURN}, + { "return-icmp",RETURNICMP}, + { "return-rst", RETURNRST}, + { "scrub", SCRUB}, + { "state", STATE}, + { "to", TO}, + { NULL, 0 }, + }; + + for (i = 0; keywords[i].k_name != NULL; i++) { + if (strcmp(s, keywords[i].k_name) == 0) { + if (debug > 1) + fprintf(stderr, "%s: %d\n", s, + keywords[i].k_val); + return keywords[i].k_val; + } + } + if (debug > 1) + fprintf(stderr, "string: %s\n", s); + return STRING; +} + +int +yylex(void) +{ + char *p, buf[8096]; + int c, next; + int token; + + while ((c = getc(fin)) == ' ' || c == '\t') + ; + if (c == '#') + while ((c = getc(fin)) != '\n' && c != EOF) + ; + if (c == '-') { + next = getc(fin); + if (next == '>') + return ARROW; + ungetc(next, fin); + } + switch (c) { + case '=': + yylval.i = PF_OP_EQ; + return PORTUNARY; + case '!': + next = getc(fin); + if (next == '=') { + yylval.i = PF_OP_NE; + return PORTUNARY; + } + ungetc(next, fin); + break; + case '<': + next = getc(fin); + if (next == '>') { + yylval.i = PF_OP_GL; + return PORTBINARY; + } else if (next == '=') { + yylval.i = PF_OP_LE; + } else { + yylval.i = PF_OP_LT; + ungetc(next, fin); + } + return PORTUNARY; + break; + case '>': + next = getc(fin); + if (next == '<') { + yylval.i = PF_OP_GL; + return PORTBINARY; + } else if (next == '=') { + yylval.i = PF_OP_GE; + } else { + yylval.i = PF_OP_GT; + ungetc(next, fin); + } + return PORTUNARY; + break; + } + if (isdigit(c)) { + yylval.number = 0; + do { + yylval.number *= 10; + yylval.number += c - '0'; + } while ((c = getc(fin)) != EOF && isdigit(c)); + ungetc(c, fin); + if (debug > 1) + fprintf(stderr, "number: %d\n", yylval.number); + return NUMBER; + } + +#define allowed_in_string(x) \ + isalnum(x) || \ + ( ispunct(x) && \ + x != '(' && \ + x != ')' && \ + x != '<' && \ + x != '>' && \ + x != '!' && \ + x != '=' && \ + x != '#' ) + + if (isalnum(c)) { + p = buf; + do { + *p++ = c; + if (p-buf >= sizeof buf) + errx(1, "line %d: string too long", lineno); + } while ((c = getc(fin)) != EOF && (allowed_in_string(c))); + ungetc(c, fin); + *p = '\0'; + token = lookup(buf); + yylval.string = strdup(buf); + return token; + } + if (c == '\n') + lineno++; + if (c == EOF) + return 0; + return c; +} + +int +parse_rules(FILE *input, struct pfctl *xpf) +{ + natmode = 0; + fin = input; + pf = xpf; + errors = 0; + yyparse(); + return errors ? -1 : 0; +} + +int +parse_nat(FILE *input, struct pfctl *xpf) +{ + natmode = 1; + fin = input; + pf = xpf; + errors = 0; + yyparse(); + return errors ? -1 : 0; +} + +u_int32_t +ipmask(u_int8_t b) +{ + u_int32_t m = 0; + int i; + + for (i = 31; i > 31-b; --i) + m |= (1 << i); + return (htonl(m)); +} + +struct pf_rule_addr * +new_addr(void) +{ + struct pf_rule_addr *ra; + + ra = malloc(sizeof(struct pf_rule_addr)); + if (ra == NULL) + errx(1, "new_addr: malloc failed: %s", strerror(errno)); + memset(ra, 0, sizeof(*ra)); + return ra; +} diff --git a/sbin/pfctl/pfctl.c b/sbin/pfctl/pfctl.c index f93d1d1756a..7b16417fb30 100644 --- a/sbin/pfctl/pfctl.c +++ b/sbin/pfctl/pfctl.c @@ -1,4 +1,4 @@ -/* $OpenBSD: pfctl.c,v 1.27 2001/07/05 11:40:25 ho Exp $ */ +/* $OpenBSD: pfctl.c,v 1.28 2001/07/16 21:09:37 markus Exp $ */ /* * Copyright (c) 2001, Daniel Hartmeier @@ -54,7 +54,6 @@ #define PF_OPT_QUIET 0x0010 void usage(void); -char *load_file(char *, size_t *); int pfctl_enable(int, int); int pfctl_disable(int, int); int pfctl_clear_stats(int, int); @@ -84,73 +83,6 @@ usage() exit(1); } -char * -load_file(char *name, size_t *len) -{ - FILE *file; - char *buf = 0, *buf2 = 0; - u_int32_t i; - - if (!strcmp(name, "-")) - file = stdin; - else - file = fopen(name, "r"); - - *len = 0; - if (file == NULL) { - fprintf(stderr, "ERROR: couldn't open file %s (%s)\n", - name, strerror(errno)); - return (0); - } - - i = 512; /* Start with this. Grow it as req'd */ - *len = 0; - if ((buf = malloc(i)) == NULL) { - fprintf(stderr, "ERROR: could not allocate space " - "for rules file\n"); - return (0); - } - while (!feof(file)) { - *len += fread((buf + *len), 1, (i - *len), file); - if (*len == i) { - /* Out of space - realloc time */ - i *= 2; - if ((buf2 = realloc(buf, i)) == NULL) { - if (buf) - free(buf); - buf = NULL; - fprintf(stderr, "ERROR: realloc of " - "stdin buffer failed\n"); - return (0); - } - buf = buf2; - } - } - if (*len == i) { - /* - * file is exactly the size of our buffer. - * grow ours one so we can null terminate it - */ - if ((buf2 = realloc(buf, i+1)) == NULL) { - if (buf) - free(buf); - buf = NULL; - fprintf(stderr, "ERROR: realloc of " - "stdin buffer failed\n"); - return (0); - } - buf = buf2; - } - if (file != stdin) - fclose(file); - buf[*len]='\0'; - if (strlen(buf) != *len) { - fprintf(stderr, "WARNING: nulls embedded in rules file\n"); - *len = strlen(buf); - } - return (buf); -} - int pfctl_enable(int dev, int opts) { @@ -303,56 +235,97 @@ pfctl_show_status(int dev) return (0); } +/* callbacks for rule/nat/rdr */ + int -pfctl_rules(int dev, char *filename, int opts) +pfctl_add_rule(struct pfctl *pf, struct pf_rule *r) { - struct pfioc_rule pr; - char *buf, *s; - size_t len; - unsigned n, nr; + memcpy(&pf->prule->rule, r, sizeof(pf->prule->rule)); + if ((pf->opts & PF_OPT_NOACTION) == 0) { + if (ioctl(pf->dev, DIOCADDRULE, pf->prule)) + err(1, "DIOCADDRULE"); + } + if (pf->opts & PF_OPT_VERBOSE) + print_rule(&pf->prule->rule); + return 0; +} - buf = load_file(filename, &len); - if (buf == NULL) +int +pfctl_add_nat(struct pfctl *pf, struct pf_nat *n) +{ + memcpy(&pf->pnat->nat, n, sizeof(pf->pnat->nat)); + if ((pf->opts & PF_OPT_NOACTION) == 0) { + if (ioctl(pf->dev, DIOCADDNAT, pf->pnat)) + err(1, "DIOCADDNAT"); + } + if (pf->opts & PF_OPT_VERBOSE) + print_nat(&pf->pnat->nat); + return 0; +} + +int +pfctl_add_rdr(struct pfctl *pf, struct pf_rdr *r) +{ + memcpy(&pf->prdr->rdr, r, sizeof(pf->prdr->rdr)); + if ((pf->opts & PF_OPT_NOACTION) == 0) { + if (ioctl(pf->dev, DIOCADDRDR, pf->prdr)) + err(1, "DIOCADDRDR"); + } + if (pf->opts & PF_OPT_VERBOSE) + print_rdr(&pf->prdr->rdr); + return 0; +} + +int +pfctl_rules(int dev, char *filename, int opts) +{ + FILE *fin; + struct pfioc_rule pr; + struct pfctl pf; + + if (strcmp(filename, "-") == 0) + fin = stdin; + else + fin = fopen(filename, "r"); + if (fin == NULL) return (1); if ((opts & PF_OPT_NOACTION) == 0) { if (ioctl(dev, DIOCBEGINRULES, &pr.ticket)) err(1, "DIOCBEGINRULES"); } - n = 0; - nr = 0; - s = buf; - do { - char *line = next_line(&s); - nr++; - if (*line && (*line != '#')) - if (parse_rule(nr, line, &pr.rule)) { - if ((opts & PF_OPT_NOACTION) == 0) { - if (ioctl(dev, DIOCADDRULE, &pr)) - err(1, "DIOCADDRULE"); - } - if (opts & PF_OPT_VERBOSE) - print_rule(&pr.rule); - n++; - } - } while (s < (buf + len)); - free(buf); + /* fill in callback data */ + pf.dev = dev; + pf.opts = opts; + pf.prule = ≺ + if (parse_rules(fin, &pf) < 0) + errx(1, "syntax error in rule file: pf rules not loaded"); if ((opts & PF_OPT_NOACTION) == 0) { if (ioctl(dev, DIOCCOMMITRULES, &pr.ticket)) err(1, "DIOCCOMMITRULES"); +#if 0 if ((opts & PF_OPT_QUIET) == 0) printf("%u rules loaded\n", n); +#endif } + if (fin != stdin) + fclose(fin); return (0); } int pfctl_nat(int dev, char *filename, int opts) { - struct pfioc_nat pn; - struct pfioc_rdr pr; - char *buf, *s; - size_t len; - unsigned n, r, nr; + FILE *fin; + struct pfioc_nat pn; + struct pfioc_rdr pr; + struct pfctl pf; + + if (strcmp(filename, "-") == 0) + fin = stdin; + else + fin = fopen(filename, "r"); + if (fin == NULL) + return (1); if ((opts & PF_OPT_NOACTION) == 0) { if (ioctl(dev, DIOCBEGINNATS, &pn.ticket)) @@ -361,48 +334,27 @@ pfctl_nat(int dev, char *filename, int opts) if (ioctl(dev, DIOCBEGINRDRS, &pr.ticket)) err(1, "DIOCBEGINRDRS"); } - - buf = load_file(filename, &len); - if (buf == NULL) - return (1); - n = 0; - r = 0; - nr = 0; - s = buf; - do { - char *line = next_line(&s); - nr++; - if (*line && (*line == 'n')) - if (parse_nat(nr, line, &pn.nat)) { - if ((opts & PF_OPT_NOACTION) == 0) - if (ioctl(dev, DIOCADDNAT, &pn)) - err(1, "DIOCADDNAT"); - if (opts & PF_OPT_VERBOSE) - print_nat(&pn.nat); - n++; - } - if (*line && (*line == 'r')) - if (parse_rdr(nr, line, &pr.rdr)) { - if ((opts & PF_OPT_NOACTION) == 0) - if (ioctl(dev, DIOCADDRDR, &pr)) - err(1, "DIOCADDRDR"); - if (opts & PF_OPT_VERBOSE) - print_rdr(&pr.rdr); - r++; - } - } while (s < (buf + len)); - + /* fill in callback data */ + pf.dev = dev; + pf.opts = opts; + pf.pnat = &pn; + pf.prdr = ≺ + if (parse_nat(fin, &pf) < 0) + errx(1, "syntax error in file: nat rules not loaded"); if ((opts & PF_OPT_NOACTION) == 0) { if (ioctl(dev, DIOCCOMMITNATS, &pn.ticket)) err(1, "DIOCCOMMITNATS"); if (ioctl(dev, DIOCCOMMITRDRS, &pr.ticket)) err(1, "DIOCCOMMITRDRS"); +#if 0 if ((opts & PF_OPT_QUIET) == 0) { printf("%u nat entries loaded\n", n); printf("%u rdr entries loaded\n", r); } +#endif } - free(buf); + if (fin != stdin) + fclose(fin); return (0); } @@ -425,7 +377,7 @@ main(int argc, char *argv[]) extern char *optarg; extern int optind; int error = 0; - int dev; + int dev = -1; int ch; if (argc < 2) @@ -470,9 +422,15 @@ main(int argc, char *argv[]) } } - dev = open("/dev/pf", O_RDWR); - if (dev == -1) - err(1, "open(\"/dev/pf\")"); + if ((opts & PF_OPT_NOACTION) == 0) { + dev = open("/dev/pf", O_RDWR); + if (dev == -1) + err(1, "open(\"/dev/pf\")"); + } else { + /* turn off options */ + opts &= ~ (PF_OPT_DISABLE | PF_OPT_ENABLE); + clearopt = logopt = showopt = NULL; + } if (opts & PF_OPT_DISABLE) if (pfctl_disable(dev, opts)) diff --git a/sbin/pfctl/pfctl_parser.c b/sbin/pfctl/pfctl_parser.c index ca69fff779c..d60cf229c45 100644 --- a/sbin/pfctl/pfctl_parser.c +++ b/sbin/pfctl/pfctl_parser.c @@ -1,4 +1,4 @@ -/* $OpenBSD: pfctl_parser.c,v 1.34 2001/07/11 21:30:14 csapuntz Exp $ */ +/* $OpenBSD: pfctl_parser.c,v 1.35 2001/07/16 21:09:38 markus Exp $ */ /* * Copyright (c) 2001, Daniel Hartmeier @@ -47,6 +47,7 @@ #include <netdb.h> #include <stdarg.h> #include <errno.h> +#include <err.h> #include "pfctl_parser.h" @@ -55,26 +56,9 @@ void print_host (struct pf_state_host *); void print_seq (struct pf_state_peer *); void print_port (u_int8_t, u_int16_t, u_int16_t, char *); void print_flags (u_int8_t); -char *next_word (char **); -int next_addr (char **, u_int32_t *); -u_int16_t next_number (char **); -u_int8_t next_flags (char **); -int rule_port (char *, u_int8_t, u_int16_t *); -u_int32_t rule_mask (u_int8_t); char *tcpflags = "FSRPAU"; -struct icmptypeent { - char *name; - u_int8_t type; -}; - -struct icmpcodeent { - char *name; - u_int8_t type; - u_int8_t code; -}; - struct icmptypeent icmp_type[] = { { "echoreq", ICMP_ECHO }, { "echorep", ICMP_ECHOREPLY }, @@ -137,19 +121,6 @@ struct icmpcodeent icmp_code[] = { { "decrypt-fail", ICMP_PHOTURIS, ICMP_PHOTURIS_DECRYPT_FAILED } }; -int -error(int n, char *fmt, ...) -{ - extern char *__progname; - va_list ap; - - va_start(ap, fmt); - fprintf(stderr, "%s: line %d ", __progname, n); - vfprintf(stderr, fmt, ap); - va_end(ap); - return (0); -} - struct icmptypeent * geticmptypebynumber(u_int8_t type) { @@ -577,752 +548,17 @@ print_rule(struct pf_rule *r) printf("\n"); } -char * -next_line(char **s) -{ - char *l = *s; - - while (**s && (**s != '\n')) - (*s)++; - if (**s) { - **s = 0; - (*s)++; - } - return (l); -} - -char * -next_word(char **s) -{ - char *w; - - while ((**s == ' ') || (**s == '\t') || (**s == '\n')) - (*s)++; - w = *s; - while (**s && (**s != ' ') && (**s != '\t') && (**s != '\n')) - (*s)++; - if (**s) { - **s = 0; - (*s)++; - } - return (w); -} - -u_int16_t -next_number(char **s) -{ - u_int16_t n = 0; - - while (**s && !isdigit(**s)) - (*s)++; - while (**s && isdigit(**s)) { - n *= 10; - n += **s - '0'; - (*s)++; - } - return (n); -} - -int -next_addr(char **w, u_int32_t *a) -{ - struct hostent *hp; - char *slash; - - if ((slash = strchr(*w, '/'))) - *slash = '\0'; - if (inet_pton(AF_INET, *w, a) != 1) { - if ((hp = gethostbyname(*w)) == NULL) - return(0); - memcpy(a, hp->h_addr, sizeof(*a)); - } - if (slash) { - *slash = '/'; - *w = slash; - } else - *w += strlen(*w); - return(1); -} - -u_int8_t -next_flags(char **s) -{ - u_int8_t f = 0; - char *p; - - while (**s && !strchr(tcpflags, **s)) - (*s)++; - while (**s && ((p = strchr(tcpflags, **s)) != NULL)) { - f |= 1 << (p-tcpflags); - (*s)++; - } - return (f ? f : 63); -} - -int -rule_port(char *w, u_int8_t p, u_int16_t *result) -{ - struct servent *s; - u_long ul; - char *ep; - - errno = 0; - ul = strtoul(w, &ep, 10); - if (*w == '\0' || *ep != '\0') { - s = getservbyname(w, p == IPPROTO_TCP ? "tcp" : "udp"); - if (s == NULL) - return (0); - - *result = s->s_port; - return (1); - } - if (errno == ERANGE && ul == ULONG_MAX) - return (0); - if (ul > USHRT_MAX) { - errno = ERANGE; - return (0); - } - - *result = htons(ul); - return (1); -} - -u_int32_t -rule_mask(u_int8_t b) -{ - u_int32_t m = 0; - int i; - - for (i = 31; i > 31-b; --i) - m |= (1 << i); - return (htonl(m)); -} - -int -parse_rule(int n, char *l, struct pf_rule *r) -{ - char *w; - memset(r, 0, sizeof(struct pf_rule)); - w = next_word(&l); - - /* pass / block */ - if (!strcmp(w, "pass" )) - r->action = PF_PASS; - else if (!strcmp(w, "block")) - r->action = PF_DROP; - else if (!strcmp(w, "scrub")) - r->action = PF_SCRUB; - else { - error(n, "expected pass/block/scrub, got %s\n", w); - return (0); - } - w = next_word(&l); - - /* return-rst/return-icmp */ - if (r->action == PF_DROP) { - if (!strcmp(w, "return-rst")) { - r->return_rst = 1; - w = next_word(&l); - } else if (!strncmp(w, "return-icmp", 11)) { - w += 11; - if ((strlen(w) > 2) && (w[0] == '(') && - (w[strlen(w)-1] == ')')) { - struct icmpcodeent *ic; - - w[strlen(w)-1] = 0; - w++; - ic = geticmpcodebyname(ICMP_UNREACH, w); - if (ic == NULL) { - error(n, "expected icmp code, got %s\n", - w); - return (0); - } - r->return_icmp = ic->type << 8; - r->return_icmp |= ic->code; - } else - r->return_icmp = (ICMP_UNREACH << 8) | - ICMP_UNREACH_PORT; - w = next_word(&l); - } - } - - /* in / out */ - if (!strcmp(w, "in" )) - r->direction = 0; - else if (!strcmp(w, "out")) - r->direction = 1; - else { - error(n, "expected in/out, got %s\n", w); - return (0); - } - w = next_word(&l); - - /* log */ - if (!strcmp(w, "log")) { - r->log = 1; - w = next_word(&l); - } else if (!strcmp(w, "log-all")) { - r->log = 2; - w = next_word(&l); - } - - /* quick */ - if (!strcmp(w, "quick")) { - if (r->action == PF_SCRUB) { - error(n, "quick does not apply to scrub\n"); - return (0); - } - r->quick = 1; - w = next_word(&l); - } - - /* on <if> */ - if (!strcmp(w, "on")) { - w = next_word(&l); - strncpy(r->ifname, w, 16); - w = next_word(&l); - } - - /* proto tcp/udp/icmp */ - if (!strcmp(w, "proto")) { - struct protoent *p; - w = next_word(&l); - p = getprotobyname(w); - if (p == NULL) { - int proto = atoi(w); - if (proto > 0) - p = getprotobynumber(proto); - } - if (p == NULL) { - error(n, "unknown protocol %s\n", w); - return (0); - } - r->proto = p->p_proto; - w = next_word(&l); - } - - /* all / from src to dst */ - if (!strcmp(w, "all" )) - w = next_word(&l); - else if (!strcmp(w, "from")) { - w = next_word(&l); - - /* source address */ - if (!strcmp(w, "any")) - w = next_word(&l); - else { - if (!strcmp(w, "!")) { - r->src.not = 1; - w = next_word(&l); - } - if (!next_addr(&w, &r->src.addr)) { - error(n, "unresolvable host %s\n", w); - return (0); - } - if (!*w) - r->src.mask = 0xFFFFFFFF; - else if (*w == '/') - r->src.mask = rule_mask(next_number(&w)); - else { - error(n, "expected /, got '%c'\n", *w); - return (0); - } - w = next_word(&l); - } - - if (r->action == PF_SCRUB) - goto skip_fromport; - - /* source port */ - if (((r->proto == IPPROTO_TCP) || (r->proto == IPPROTO_UDP)) && - !strcmp(w, "port")) { - w = next_word(&l); - if (!strcmp(w, "=" )) - r->src.port_op = PF_OP_EQ; - else if (!strcmp(w, "!=")) - r->src.port_op = PF_OP_NE; - else if (!strcmp(w, "<" )) - r->src.port_op = PF_OP_LT; - else if (!strcmp(w, "<=")) - r->src.port_op = PF_OP_LE; - else if (!strcmp(w, ">" )) - r->src.port_op = PF_OP_GT; - else if (!strcmp(w, ">=")) - r->src.port_op = PF_OP_GE; - else - r->src.port_op = PF_OP_GL; - if (r->src.port_op != 1) - w = next_word(&l); - if (!rule_port(w, r->proto, &r->src.port[0])) { - error(n, "invalid port '%s'\n", w); - return (0); - } - w = next_word(&l); - if (r->src.port_op == PF_OP_GL) { - if (strcmp(w, "<>") && strcmp(w, "><")) { - error(n, "expected <>/><, got %s\n", - w); - return (0); - } - w = next_word(&l); - if (!rule_port(w, r->proto, &r->src.port[1])) { - error(n, "invalid port '%s'\n", w); - return (0); - } - w = next_word(&l); - } - } - - skip_fromport: - - /* destination address */ - if (strcmp(w, "to")) { - error(n, "expected to, got %s\n", w); - return (0); - } - w = next_word(&l); - if (!strcmp(w, "any")) - w = next_word(&l); - else { - if (!strcmp(w, "!")) { - r->dst.not = 1; - w = next_word(&l); - } - if (!next_addr(&w, &r->dst.addr)) { - error(n, "unresolvable host %s\n", w); - return (0); - } - if (!*w) - r->dst.mask = 0xFFFFFFFF; - else if (*w == '/') - r->dst.mask = rule_mask(next_number(&w)); - else { - error(n, "expected /, got '%c'\n", *w); - return (0); - } - w = next_word(&l); - } - - if (r->action == PF_SCRUB) - goto skip_toport; - - /* destination port */ - if (((r->proto == IPPROTO_TCP) || (r->proto == IPPROTO_UDP)) && - !strcmp(w, "port")) { - w = next_word(&l); - if (!strcmp(w, "=" )) - r->dst.port_op = PF_OP_EQ; - else if (!strcmp(w, "!=")) - r->dst.port_op = PF_OP_NE; - else if (!strcmp(w, "<" )) - r->dst.port_op = PF_OP_LT; - else if (!strcmp(w, "<=")) - r->dst.port_op = PF_OP_LE; - else if (!strcmp(w, ">" )) - r->dst.port_op = PF_OP_GT; - else if (!strcmp(w, ">=")) - r->dst.port_op = PF_OP_GE; - else - r->dst.port_op = PF_OP_GL; - if (r->dst.port_op != PF_OP_GL) - w = next_word(&l); - if (!rule_port(w, r->proto, &r->dst.port[0])) { - error(n, "invalid port '%s'\n", w); - return (0); - } - w = next_word(&l); - if (r->dst.port_op == PF_OP_GL) { - if (strcmp(w, "<>") && strcmp(w, "><")) { - error(n, "expected <>/><, got %s\n", - w); - return (0); - } - w = next_word(&l); - if (!rule_port(w, r->proto, &r->dst.port[1])) { - error(n, "invalid port '%s'\n", w); - return (0); - } - w = next_word(&l); - } - } - skip_toport: - - } else { - error(n, "expected all/from, got %s\n", w); - return (0); - } - - /* flags */ - if (!strcmp(w, "flags")) { - if (r->proto != IPPROTO_TCP || r->action == PF_SCRUB) { - error(n, "flags only valid for proto tcp\n"); - return (0); - } else { - w = next_word(&l); - r->flags = next_flags(&w); - r->flagset = next_flags(&w); - w = next_word(&l); - } - } - - /* icmp type/code */ - if (!strcmp(w, "icmp-type")) { - if (r->proto != IPPROTO_ICMP || r->action == PF_SCRUB) { - error(n, "icmp-type only valid for proto icmp\n"); - return (0); - } else { - u_long ul; - char *ep; - - w = next_word(&l); - - errno = 0; - ul = strtoul(w, &ep, 10); - if (w[0] == '\0' || *ep != '\0') { - struct icmptypeent *p; - - p = geticmptypebyname(w); - if (p == NULL) { - error(n, "unknown icmp-type %s\n", w); - return (0); - } - ul = p->type; - } else if ((errno == ERANGE && ul == ULONG_MAX) || - ul > ICMP_MAXTYPE) { - error(n, "icmp-type type wrong\n"); - return (0); - } - r->type = ul+1; - - w = next_word(&l); - if (!strcmp(w, "code")) { - w = next_word(&l); - - errno = 0; - ul = strtoul(w, &ep, 10); - if (w[0] == '\0' || *ep != '\0') { - struct icmpcodeent *p; - - p = geticmpcodebyname(r->type-1, w); - if (p == NULL) { - error(n, "unknown code %s\n", w); - return (0); - } - ul = p->code; - } else if ((errno == ERANGE && ul == ULONG_MAX) || - ul > 255) { - error(n, "icmp-type code wrong\n"); - return (0); - } - r->code = ul + 1; - - w = next_word(&l); - } - } - } - - /* keep */ - if (!strcmp(w, "keep") && r->action != PF_SCRUB) { - w = next_word(&l); - if (!strcmp(w, "state")) { - w = next_word(&l); - r->keep_state = 1; - } else { - error(n, "expected state, got %s\n", w); - return (0); - } - } - - /* no further options expected */ - while (*w) { - error(n, "unexpected %s\n", w); - w = next_word(&l); - } - - return (1); -} - -int -parse_nat(int n, char *l, struct pf_nat *nat) -{ - char *w; - - memset(nat, 0, sizeof(struct pf_nat)); - w = next_word(&l); - - /* nat */ - if (strcmp(w, "nat" )) { - error(n, "expected nat, got %s\n", w); - return (0); - } - w = next_word(&l); - - /* interface */ - if (!strcmp(w, "on")) { - w = next_word(&l); - if (!strcmp(w, "!")) { - nat->ifnot = 1; - w = next_word(&l); - } - strncpy(nat->ifname, w, 16); - w = next_word(&l); - } - - /* proto */ - if (!strcmp(w, "proto")) { - w = next_word(&l); - if (!strcmp(w, "tcp")) - nat->proto = IPPROTO_TCP; - else if (!strcmp(w, "udp")) - nat->proto = IPPROTO_UDP; - else if (!strcmp(w, "icmp")) - nat->proto = IPPROTO_ICMP; - else { - error(n, "expected tcp/udp/icmp, got %s\n", w); - return (0); - } - w = next_word(&l); - } - - /* source addr/mask */ - if (strcmp(w, "from")) { - error(n, "expected from, got %s\n", w); - return (0); - } - w = next_word(&l); - if (!strcmp(w, "any")) - w = next_word(&l); - else { - if (!strcmp(w, "!")) { - nat->snot = 1; - w = next_word(&l); - } - if (!next_addr(&w, &nat->saddr)) { - error(n, "unresolvable host %s\n", w); - return (0); - } - if (!*w) - nat->smask = 0xFFFFFFFF; - else if (*w == '/') - nat->smask = rule_mask(next_number(&w)); - else { - error(n, "expected /, get '%c'\n", *w); - return (0); - } - w = next_word(&l); - } - - /* destination addr/mask */ - if (strcmp(w, "to")) { - error(n, "expected to, got %s\n", w); - return (0); - } - w = next_word(&l); - if (!strcmp(w, "any")) - w = next_word(&l); - else { - if (!strcmp(w, "!")) { - nat->dnot = 1; - w = next_word(&l); - } - if (!next_addr(&w, &nat->daddr)) { - error(n, "unresolvable host %s\n", w); - return (0); - } - if (!*w) - nat->dmask = 0xFFFFFFFF; - else if (*w == '/') - nat->dmask = rule_mask(next_number(&w)); - else { - error(n, "expected /, get '%c'\n", *w); - return (0); - } - w = next_word(&l); - } - - /* -> */ - if (strcmp(w, "->")) { - error(n, "expected ->, got %s\n", w); - return (0); - } - w = next_word(&l); - - /* external addr */ - if (!next_addr(&w, &nat->raddr)) { - error(n, "unresolvable host %s\n", w); - return (0); - } - w = next_word(&l); - - /* no further options expected */ - while (*w) { - error(n, "unexpected %s\n", w); - w = next_word(&l); - } - - return (1); -} - int -parse_rdr(int n, char *l, struct pf_rdr *rdr) +parse_flags(char *s) { - char *w, *s; - - memset(rdr, 0, sizeof(struct pf_rdr)); - w = next_word(&l); - - /* rdr */ - if (strcmp(w, "rdr" )) { - error(n, "expected rdr, got %s\n", w); - return (0); - } - w = next_word(&l); - - /* interface */ - if (!strcmp(w, "on")) { - w = next_word(&l); - if (!strcmp(w, "!")) { - rdr->ifnot = 1; - w = next_word(&l); - } - strncpy(rdr->ifname, w, 16); - w = next_word(&l); - } + char *p, *q; + u_int8_t f = 0; - /* source addr/mask */ - if (strcmp(w, "from")) { - error(n, "expected from, got %s\n", w); - return (0); - } - w = next_word(&l); - if (!strcmp(w, "any")) - w = next_word(&l); - else { - if (!strcmp(w, "!")) { - rdr->snot = 1; - w = next_word(&l); - } - if (!next_addr(&w, &rdr->saddr)) { - error(n, "unresolvable host %s\n", w); - return (0); - } - if (!*w) - rdr->smask = 0xFFFFFFFF; - else if (*w == '/') - rdr->smask = rule_mask(next_number(&w)); - else { - error(n, "expected /, get '%c'\n", *w); - return (0); - } - w = next_word(&l); - } - - /* proto (default is tcp) */ - if (!strcmp(w, "proto")) { - w = next_word(&l); - if (!strcmp(w, "tcp")) - rdr->proto = IPPROTO_TCP; - else if (!strcmp(w, "udp")) - rdr->proto = IPPROTO_UDP; - else { - error(n, "expected tcp/udp, got %s\n", w); - return (0); - } - w = next_word(&l); - } else - rdr->proto = IPPROTO_TCP; - - /* external addr/mask */ - if (strcmp(w, "to")) { - error(n, "expected to, got %s\n", w); - return (0); - } - w = next_word(&l); - if (!strcmp(w, "any")) - w = next_word(&l); - else { - if (!strcmp(w, "!")) { - rdr->dnot = 1; - w = next_word(&l); - } - if (!next_addr(&w, &rdr->daddr)) { - error(n, "unresolvable host %s\n", w); - return (0); - } - if (!*w) - rdr->dmask = 0xFFFFFFFF; - else if (*w == '/') - rdr->dmask = rule_mask(next_number(&w)); - else { - error(n, "expected /, get '%c'\n", *w); - return (0); - } - w = next_word(&l); - } - - /* external port (range) */ - if (strcmp(w, "port")) { - error(n, "expected port, got %s\n", w); - return (0); - } - w = next_word(&l); - /* check for port range */ - if ((s = strchr(w, ':')) == NULL) { - if (!rule_port(w, rdr->proto, &rdr->dport)) { - error(n, "invalid destination port '%s'\n", w); - return (0); - } - rdr->dport2 = rdr->dport; - } else { - *s++ = '\0'; - if (!rule_port(w, rdr->proto, &rdr->dport)) { - error(n, "invalid destination port '%s'\n", w); - return (0); - } - if (!rule_port(s, rdr->proto, &rdr->dport2)) { - error(n, "invalid destination port '%s'\n", s); - return (0); - } - rdr->opts |= PF_DPORT_RANGE; - } - w = next_word(&l); - - /* -> */ - if (strcmp(w, "->")) { - error(n, "expected ->, got %s\n", w); - return (0); - } - w = next_word(&l); - - /* internal addr */ - if (!next_addr(&w, &rdr->raddr)) { - error(n, "unresolvable host %s\n", w); - return (0); - } - w = next_word(&l); - - /* internal port */ - if (strcmp(w, "port")) { - error(n, "expected port, got %s\n", w); - return (0); - } - w = next_word(&l); - /* check if redirected port is a range */ - if ((s = strchr(w, ':')) != NULL) { - rdr->opts |= PF_RPORT_RANGE; - } - - if (!rule_port(w, rdr->proto, &rdr->rport)) { - error(n, "invalid port '%s'\n", w); - return (0); - } - w = next_word(&l); - - /* no further options expected */ - while (*w) { - error(n, "unexpected %s\n", w); - w = next_word(&l); - } - - return (1); + for (p = s; *p; p++) { + if ((q = strchr(tcpflags, *p)) == NULL) + return -1; + else + f |= 1 << (q - tcpflags); + } + return (f ? f : 63); } diff --git a/sbin/pfctl/pfctl_parser.h b/sbin/pfctl/pfctl_parser.h index dffd412ed42..ce7eab8a4b2 100644 --- a/sbin/pfctl/pfctl_parser.h +++ b/sbin/pfctl/pfctl_parser.h @@ -1,4 +1,4 @@ -/* $OpenBSD: pfctl_parser.h,v 1.5 2001/06/25 18:02:44 dhartmei Exp $ */ +/* $OpenBSD: pfctl_parser.h,v 1.6 2001/07/16 21:09:38 markus Exp $ */ /* * Copyright (c) 2001, Daniel Hartmeier @@ -33,14 +33,42 @@ #ifndef _PFCTL_PARSER_H_ #define _PFCTL_PARSER_H_ -char *next_line (char **); -int parse_rule (int, char *, struct pf_rule *); -int parse_nat (int, char *, struct pf_nat *); -int parse_rdr (int, char *, struct pf_rdr *); +struct pfctl { + int dev; + int opts; + struct pfioc_rule *prule; + struct pfioc_nat *pnat; + struct pfioc_rdr *prdr; +}; + +int pfctl_add_rule(struct pfctl *, struct pf_rule *); +int pfctl_add_nat(struct pfctl *, struct pf_nat *); +int pfctl_add_rdr(struct pfctl *, struct pf_rdr *); + +int parse_rules(FILE *, struct pfctl *); +int parse_nat(FILE *, struct pfctl *); +int parse_flags(char *); + void print_rule (struct pf_rule *); void print_nat (struct pf_nat *); void print_rdr (struct pf_rdr *); void print_state (struct pf_state *); void print_status (struct pf_status *); +struct icmptypeent { + char *name; + u_int8_t type; +}; + +struct icmpcodeent { + char *name; + u_int8_t type; + u_int8_t code; +}; + +struct icmptypeent * geticmptypebynumber(u_int8_t); +struct icmptypeent * geticmptypebyname(char *); +struct icmpcodeent * geticmpcodebynumber(u_int8_t, u_int8_t); +struct icmpcodeent * geticmpcodebyname(u_long, char *); + #endif /* _PFCTL_PARSER_H_ */ |