summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaniel Hartmeier <dhartmei@cvs.openbsd.org>2001-08-19 16:16:42 +0000
committerDaniel Hartmeier <dhartmei@cvs.openbsd.org>2001-08-19 16:16:42 +0000
commit4be5f22c01e1c906e44ff61dd9b32dea7ac62757 (patch)
treedf28f8ac15e0a9ec91c50ec57a55602066d40630
parentdc7d2f83954a761466ca0e0e497a0dfd72a0ec2a (diff)
Add parameter list support to parser. Handles lists for protocol, hosts
and ports in filter rules, like block in from { 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16 } to any pass in proto tcp from any to any port { ssh, 1024 >< 2000, > 65000 } block in proto { udp, igmp } and does rule expansion (generate all needed rule combinations).
-rw-r--r--sbin/pfctl/parse.y371
1 files changed, 256 insertions, 115 deletions
diff --git a/sbin/pfctl/parse.y b/sbin/pfctl/parse.y
index 72e3910b961..10459cc7067 100644
--- a/sbin/pfctl/parse.y
+++ b/sbin/pfctl/parse.y
@@ -1,4 +1,4 @@
-/* $OpenBSD: parse.y,v 1.19 2001/08/16 11:46:56 deraadt Exp $ */
+/* $OpenBSD: parse.y,v 1.20 2001/08/19 16:16:41 dhartmei Exp $ */
/*
* Copyright (c) 2001 Markus Friedl. All rights reserved.
@@ -53,22 +53,42 @@ static int lineno = 1;
static int errors = 0;
static int natmode = 0;
-static int proto = 0; /* this is a synthesized attribute */
+struct node_proto {
+ u_int8_t proto;
+ struct node_proto *next;
+};
+
+struct node_host {
+ u_int32_t addr;
+ u_int32_t mask;
+ u_int8_t not;
+ struct node_host *next;
+};
+
+struct node_port {
+ u_int16_t port[2];
+ u_int8_t op;
+ struct node_port *next;
+};
+
+struct peer {
+ struct node_host *host;
+ struct node_port *port;
+};
int rule_consistent(struct pf_rule *);
int yyparse(void);
struct pf_rule_addr *new_addr(void);
u_int32_t ipmask(u_int8_t);
+void expand_rule(struct pf_rule *, struct node_proto *,
+ struct node_host *, struct node_port *,
+ struct node_host *, struct node_port *);
typedef struct {
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;
@@ -83,6 +103,13 @@ typedef struct {
int b;
int t;
} range;
+ struct node_proto *proto;
+ struct node_host *host;
+ struct node_port *port;
+ struct peer peer;
+ struct {
+ struct peer src, dst;
+ } fromto;
} v;
int lineno;
} YYSTYPE;
@@ -95,13 +122,16 @@ typedef struct {
%token <v.string> STRING
%token <v.number> NUMBER
%token <v.i> PORTUNARY PORTBINARY
-%type <v.addr> ipportspec ipspec host portspec
-%type <v.addr2> fromto
%type <v.iface> iface natiface
-%type <v.number> address port icmptype minttl
-%type <v.i> direction log quick keep proto nodf
+%type <v.number> port icmptype minttl
+%type <v.i> direction log quick keep nodf
%type <v.b> action icmpspec flag flags blockspec
%type <v.range> dport rport
+%type <v.proto> proto proto_list proto_item
+%type <v.fromto> fromto
+%type <v.peer> ipportspec
+%type <v.host> ipspec host address host_list
+%type <v.port> portspec port_list port_item
%%
ruleset: /* empty */
@@ -132,13 +162,6 @@ pfrule: action direction log quick iface proto fromto flags icmpspec keep nodf
r.quick = $4;
if ($5.string)
memcpy(r.ifname, $5.string, sizeof(r.ifname));
- r.proto = $6;
- proto = 0; /* reset synthesized 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;
@@ -151,10 +174,8 @@ pfrule: action direction log quick iface proto fromto flags icmpspec keep nodf
if ($12)
r.min_ttl = $12;
- if (rule_consistent(&r) < 0)
- yyerror("skipping rule due to errors");
- else
- pfctl_add_rule(pf, &r);
+ expand_rule(&r, $6, $7.src.host, $7.src.port,
+ $7.dst.host, $7.dst.port);
}
;
@@ -203,67 +224,77 @@ iface: { $$.string = NULL; }
| ON STRING { $$.string = strdup($2); }
;
-proto: { $$ = proto; }
- | PROTO NUMBER {
+proto: { $$ = NULL; }
+ | PROTO proto_item { $$ = $2; }
+ | PROTO '{' proto_list '}' { $$ = $3; }
+ ;
+
+proto_list: proto_item { $$ = $1; }
+ | proto_list ',' proto_item { $3->next = $1; $$ = $3; }
+ ;
+
+proto_item: NUMBER {
struct protoent *p;
- if ((p = getprotobynumber($2)) == NULL) {
- yyerror("unknown protocol %d", $2);
+ if ((p = getprotobynumber($1)) == NULL) {
+ yyerror("unknown protocol %d", $1);
YYERROR;
}
- proto = $$ = p->p_proto;
+ $$ = malloc(sizeof(struct node_proto));
+ $$->proto = p->p_proto;
+ $$->next = NULL;
}
- | PROTO STRING {
+ | STRING {
struct protoent *p;
- if ((p = getprotobyname($2)) == NULL) {
- yyerror("unknown protocol %s", $2);
+ if ((p = getprotobyname($1)) == NULL) {
+ yyerror("unknown protocol %s", $1);
YYERROR;
}
- proto = $$ = p->p_proto;
+ $$ = malloc(sizeof(struct node_proto));
+ $$->proto = p->p_proto;
+ $$->next = NULL;
}
;
fromto: ALL {
- $$.src = new_addr();
- $$.dst = new_addr();
+ $$.src.host = NULL;
+ $$.src.port = NULL;
+ $$.dst.host = NULL;
+ $$.dst.port = NULL;
}
- | FROM ipportspec TO ipportspec {
+ | 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);
- }
+ipportspec: ipspec { $$.host = $1; $$.port = NULL; }
+ | ipspec PORT portspec {
+ $$.host = $1;
+ $$.port = $3;
}
;
-ipspec: ANY { $$ = new_addr(); }
+ipspec: ANY { $$ = NULL; }
| '!' host { $$ = $2; $$->not = 1; }
- | host { $$ = $1; }
+ | host { $$ = $1; $$->not = 0; }
+ | '{' host_list '}' { $$ = $2; }
;
-host: address {
- $$ = new_addr();
- $$->addr = $1;
+host_list: host { $$ = $1; }
+ | host_list ',' host { $3->next = $1; $$ = $3; }
+
+host: address {
+ $$ = $1;
$$->mask = 0xffffffff;
}
- |
- address '/' NUMBER {
+ | address '/' NUMBER {
if ($3 < 0 || $3 > 32) {
yyerror("illegal netmask value %d", $3);
YYERROR;
}
- $$ = new_addr();
- $$->addr = $1;
+ $$ = $1;
$$->mask = ipmask($3);
}
;
@@ -271,13 +302,12 @@ host: address {
address: STRING {
struct hostent *hp;
- if (inet_pton(AF_INET, $1, &$$) != 1) {
- if ((hp = gethostbyname($1)) == NULL) {
- yyerror("cannot resolve %s", $1);
- YYERROR;
- }
- memcpy(&$$, hp->h_addr, sizeof(u_int32_t));
+ if ((hp = gethostbyname($1)) == NULL) {
+ yyerror("cannot resolve %s", $1);
+ YYERROR;
}
+ $$ = malloc(sizeof(struct node_host));
+ memcpy(&$$->addr, hp->h_addr, sizeof(u_int32_t));
}
| NUMBER '.' NUMBER '.' NUMBER '.' NUMBER {
if ($1 < 0 || $3 < 0 || $5 < 0 || $7 < 0 ||
@@ -286,25 +316,40 @@ address: STRING {
$1, $3, $5, $7);
YYERROR;
}
- $$ = (htonl(($1 << 24) | ($3 << 16) | ($5 << 8) | $7));
+ $$ = malloc(sizeof(struct node_host));
+ $$->addr = htonl(($1 << 24) | ($3 << 16) | ($5 << 8) | $7);
}
;
-portspec: PORT PORTUNARY port {
- $$ = new_addr();
- $$->port_op = $2;
- $$->port[0] = $3;
- $$->port[1] = $3;
+portspec: port_item { $$ = $1; }
+ | '{' port_list '}' { $$ = $2; }
+ ;
+
+port_list: port_item { $$ = $1; }
+ | port_list ',' port_item { $3->next = $1; $$ = $3; }
+ ;
+
+port_item: port {
+ $$ = malloc(sizeof(struct node_port));
+ $$->port[0] = $1;
+ $$->port[1] = $1;
+ $$->op = PF_OP_EQ;
}
- | PORT port PORTBINARY port {
- $$ = new_addr();
+ | PORTUNARY port {
+ $$ = malloc(sizeof(struct node_port));
$$->port[0] = $2;
- $$->port_op = $3;
- $$->port[1] = $4;
+ $$->port[1] = $2;
+ $$->op = $1;
+ }
+ | port PORTBINARY port {
+ $$ = malloc(sizeof(struct node_port));
+ $$->port[0] = $1;
+ $$->port[1] = $3;
+ $$->op = $2;
}
;
-port: NUMBER {
+port: NUMBER {
if (0 > $1 || $1 > 65535) {
yyerror("illegal port value %d", $1);
YYERROR;
@@ -314,18 +359,14 @@ port: NUMBER {
| STRING {
struct servent *s = NULL;
- /* use synthesized attribute */
- if (proto) {
- s = getservbyname($1,
- proto == IPPROTO_TCP ? "tcp" : "udp");
- if (s == NULL) {
- yyerror("unknown protocol %s", $1);
- YYERROR;
- }
- $$ = s->s_port;
- } else {
- $$ = 0;
+ s = getservbyname($1, "tcp");
+ if (s == NULL)
+ s = getservbyname($1, "udp");
+ if (s == NULL) {
+ yyerror("unknown protocol %s", $1);
+ YYERROR;
}
+ $$ = s->s_port;
}
;
@@ -421,26 +462,35 @@ natrule: NAT natiface proto FROM ipspec TO ipspec ARROW address
sizeof(nat.ifname));
nat.ifnot = $2.not;
}
- nat.proto = $3;
- proto = 0; /* reset synthesized 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);
+ if ($3 != NULL) {
+ nat.proto = $3->proto;
+ free($3);
+ }
+ if ($5 != NULL) {
+ nat.saddr = $5->addr;
+ nat.smask = $5->mask;
+ nat.snot = $5->not;
+ free($5);
+ }
+ if ($7 != NULL) {
+ nat.daddr = $7->addr;
+ nat.dmask = $7->mask;
+ nat.dnot = $7->not;
+ free($7);
+ }
- nat.raddr = $9;
+ if ($9 == NULL) {
+ yyerror("nat rule requires redirection address");
+ YYERROR;
+ }
+ nat.raddr = $9->addr;
+ free($9);
pfctl_add_nat(pf, &nat);
}
;
-rdrrule: RDR { proto = IPPROTO_TCP; } natiface proto FROM ipspec TO ipspec dport ARROW address rport
+rdrrule: RDR natiface proto FROM ipspec TO ipspec dport ARROW address rport
{
struct pf_rdr rdr;
@@ -451,32 +501,41 @@ rdrrule: RDR { proto = IPPROTO_TCP; } natiface proto FROM ipspec TO ipspec dport
memset(&rdr, 0, sizeof(rdr));
- if ($3.string) {
- memcpy(rdr.ifname, $3.string,
+ if ($2.string) {
+ memcpy(rdr.ifname, $2.string,
sizeof(rdr.ifname));
- rdr.ifnot = $3.not;
+ rdr.ifnot = $2.not;
+ }
+ if ($3 != NULL) {
+ rdr.proto = $3->proto;
+ free($3);
+ }
+ if ($5 != NULL) {
+ rdr.saddr = $5->addr;
+ rdr.smask = $5->mask;
+ rdr.snot = $5->not;
+ free($5);
+ }
+ if ($7 != NULL) {
+ rdr.daddr = $7->addr;
+ rdr.dmask = $7->mask;
+ rdr.dnot = $7->not;
+ free($7);
}
- rdr.proto = $4;
- proto = 0; /* reset synthesized attribute */
-
- rdr.saddr = $6->addr;
- rdr.smask = $6->mask;
- rdr.snot = $6->not;
- free($6);
-
- rdr.daddr = $8->addr;
- rdr.dmask = $8->mask;
- rdr.dnot = $8->not;
- free($8);
- rdr.dport = $9.a;
- rdr.dport2 = $9.b;
- rdr.opts |= $9.t;
+ rdr.dport = $8.a;
+ rdr.dport2 = $8.b;
+ rdr.opts |= $8.t;
- rdr.raddr = $11;
+ if ($10 == NULL) {
+ yyerror("rdr rule requires redirection address");
+ YYERROR;
+ }
+ rdr.raddr = $10->addr;
+ free($10);
- rdr.rport = $12.a;
- rdr.opts |= $12.t;
+ rdr.rport = $11.a;
+ rdr.opts |= $11.t;
pfctl_add_rdr(pf, &rdr);
}
@@ -569,6 +628,88 @@ rule_consistent(struct pf_rule *r)
return (-problems);
}
+#define CHECK_ROOT(T,r) \
+ do { \
+ if (r == NULL) { \
+ r = malloc(sizeof(T)); \
+ memset(r, 0, sizeof(T)); \
+ } \
+ } while (0)
+
+#define FREE_LIST(T,r) \
+ do { \
+ T *p, *n = r; \
+ while (n != NULL) { \
+ p = n; \
+ n = n->next; \
+ free(p); \
+ } \
+ } while (0)
+
+void
+expand_rule(struct pf_rule *r, struct node_proto *protos,
+ struct node_host *src_hosts, struct node_port *src_ports,
+ struct node_host *dst_hosts, struct node_port *dst_ports)
+{
+ struct node_proto *proto;
+ struct node_host *src_host, *dst_host;
+ struct node_port *src_port, *dst_port;
+
+ CHECK_ROOT(struct node_proto, protos);
+ CHECK_ROOT(struct node_host, src_hosts);
+ CHECK_ROOT(struct node_port, src_ports);
+ CHECK_ROOT(struct node_host, dst_hosts);
+ CHECK_ROOT(struct node_port, dst_ports);
+
+ proto = protos;
+ while (proto != NULL) {
+ src_host = src_hosts;
+ while (src_host != NULL) {
+ src_port = src_ports;
+ while (src_port != NULL) {
+ dst_host = dst_hosts;
+ while (dst_host != NULL) {
+ dst_port = dst_ports;
+ while (dst_port != NULL) {
+ r->proto = proto->proto;
+ r->src.addr = src_host->addr;
+ r->src.mask = src_host->mask;
+ r->src.not = src_host->not;
+ r->src.port[0] = src_port->port[0];
+ r->src.port[1] = src_port->port[1];
+ r->src.port_op = src_port->op;
+ r->dst.addr = dst_host->addr;
+ r->dst.mask = dst_host->mask;
+ r->dst.not = dst_host->not;
+ r->dst.port[0] = dst_port->port[0];
+ r->dst.port[1] = dst_port->port[1];
+ r->dst.port_op = dst_port->op;
+ if (rule_consistent(r) < 0)
+ yyerror("skipping rule "
+ "due to errors");
+ else
+ pfctl_add_rule(pf, r);
+ dst_port = dst_port->next;
+ }
+ dst_host = dst_host->next;
+ }
+ src_port = src_port->next;
+ }
+ src_host = src_host->next;
+ }
+ proto = proto->next;
+ }
+
+ FREE_LIST(struct node_proto, protos);
+ FREE_LIST(struct node_host, src_hosts);
+ FREE_LIST(struct node_port, src_ports);
+ FREE_LIST(struct node_host, dst_hosts);
+ FREE_LIST(struct node_port, dst_ports);
+}
+
+#undef FREE_LIST
+#undef CHECK_ROOT
+
int
lookup(char *s)
{
@@ -717,7 +858,7 @@ yylex(void)
#define allowed_in_string(x) \
isalnum(x) || (ispunct(x) && x != '(' && x != ')' && x != '<' \
- && x != '>' && x != '!' && x != '=' && x != '/' && x != '#')
+ && x != '>' && x != '!' && x != '=' && x != '/' && x != '#' && x != ',')
if (isalnum(c)) {
p = buf;