summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sbin/pfctl/Makefile8
-rw-r--r--sbin/pfctl/parse.y673
-rw-r--r--sbin/pfctl/pfctl.c228
-rw-r--r--sbin/pfctl/pfctl_parser.c788
-rw-r--r--sbin/pfctl/pfctl_parser.h38
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 = &pr;
+ 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 = &pr;
+ 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_ */