summaryrefslogtreecommitdiff
path: root/sbin/pfctl/parse.y
diff options
context:
space:
mode:
Diffstat (limited to 'sbin/pfctl/parse.y')
-rw-r--r--sbin/pfctl/parse.y217
1 files changed, 139 insertions, 78 deletions
diff --git a/sbin/pfctl/parse.y b/sbin/pfctl/parse.y
index b869827cbca..9989f4ef7a5 100644
--- a/sbin/pfctl/parse.y
+++ b/sbin/pfctl/parse.y
@@ -1,4 +1,4 @@
-/* $OpenBSD: parse.y,v 1.432 2003/12/30 16:59:38 henning Exp $ */
+/* $OpenBSD: parse.y,v 1.433 2003/12/31 11:18:24 cedric Exp $ */
/*
* Copyright (c) 2001 Markus Friedl. All rights reserved.
@@ -69,6 +69,7 @@ static u_int16_t returnicmp6default =
(ICMP6_DST_UNREACH << 8) | ICMP6_DST_UNREACH_NOPORT;
static int blockpolicy = PFRULE_DROP;
static int require_order = 1;
+static int default_statelock;
enum {
PFCTL_STATE_NONE,
@@ -116,7 +117,7 @@ struct node_icmp {
enum { PF_STATE_OPT_MAX, PF_STATE_OPT_NOSYNC, PF_STATE_OPT_SRCTRACK,
PF_STATE_OPT_MAX_SRC_STATES, PF_STATE_OPT_MAX_SRC_NODES,
- PF_STATE_OPT_TIMEOUT };
+ PF_STATE_OPT_STATELOCK, PF_STATE_OPT_TIMEOUT };
struct node_state_opt {
int type;
@@ -125,6 +126,7 @@ struct node_state_opt {
u_int32_t max_src_states;
u_int32_t max_src_nodes;
u_int8_t src_track;
+ u_int32_t statelock;
struct {
int number;
u_int32_t seconds;
@@ -236,6 +238,7 @@ struct node_hfsc_opts hfsc_opts;
int yyerror(const char *, ...);
int disallow_table(struct node_host *, const char *);
+int disallow_alias(struct node_host *, const char *);
int rule_consistent(struct pf_rule *);
int filter_consistent(struct pf_rule *);
int nat_consistent(struct pf_rule *);
@@ -376,6 +379,10 @@ typedef struct {
} \
} while (0)
+#define DYNIF_MULTIADDR(addr) ((addr).type == PF_ADDR_DYNIFTL && \
+ (!((addr).iflags & PFI_AFLAG_NOALIAS) || \
+ !isdigit((addr).v.ifname[strlen((addr).v.ifname)-1])))
+
%}
%token PASS BLOCK SCRUB RETURN IN OS OUT LOG LOGALL QUICK ON FROM TO FLAGS
@@ -392,14 +399,14 @@ typedef struct {
%token QUEUE PRIORITY QLIMIT
%token LOAD
%token STICKYADDRESS MAXSRCSTATES MAXSRCNODES SOURCETRACK GLOBAL RULE
-%token TAGGED TAG
+%token TAGGED TAG IFBOUND GRBOUND FLOATING STATEPOLICY
%token <v.string> STRING
%token <v.i> PORTBINARY
%type <v.interface> interface if_list if_item_not if_item
%type <v.number> number icmptype icmp6type uid gid
%type <v.number> tos not yesno natpass
%type <v.i> no dir log af fragcache sourcetrack
-%type <v.i> unaryop
+%type <v.i> unaryop statelock
%type <v.b> action nataction flags flag blockspec
%type <v.range> port rport
%type <v.hashkey> hashkey
@@ -470,7 +477,7 @@ option : SET OPTIMIZATION STRING {
| SET LOGINTERFACE STRING {
if (check_rulestate(PFCTL_STATE_OPTION))
YYERROR;
- if ((ifa_exists($3) == NULL) && strcmp($3, "none")) {
+ if ((ifa_exists($3, 0) == NULL) && strcmp($3, "none")) {
yyerror("interface %s doesn't exist", $3);
YYERROR;
}
@@ -519,6 +526,22 @@ option : SET OPTIMIZATION STRING {
YYERROR;
}
}
+ | SET STATEPOLICY statelock {
+ if (pf->opts & PF_OPT_VERBOSE)
+ switch($3) {
+ case 0:
+ printf("set state-policy floating\n");
+ break;
+ case PFRULE_IFBOUND:
+ printf("set state-policy if-bound\n");
+ break;
+ case PFRULE_GRBOUND:
+ printf("set state-policy "
+ "group-bound\n");
+ break;
+ }
+ default_statelock = $3;
+ }
| SET DEBUG STRING {
if (check_rulestate(PFCTL_STATE_OPTION))
YYERROR;
@@ -706,13 +729,6 @@ scrubrule : SCRUB dir logquick interface af proto fromto scrub_opts
YYERROR;
}
- if ($4) {
- if ($4->not) {
- yyerror("scrub rules do not support "
- "'! <if>'");
- YYERROR;
- }
- }
r.af = $5;
if ($8.nodf)
r.rule_flag |= PFRULE_NODF;
@@ -844,7 +860,7 @@ antispoof : ANTISPOOF logquick antispoof_ifspc af antispoof_opts {
YYERROR;
}
j->not = 1;
- h = ifa_lookup(j->ifname, PFCTL_IFLOOKUP_NET);
+ h = ifa_lookup(j->ifname, PFI_AFLAG_NETWORK);
if (h != NULL)
expand_rule(&r, j, NULL, NULL, NULL, h,
@@ -860,8 +876,7 @@ antispoof : ANTISPOOF logquick antispoof_ifspc af antispoof_opts {
r.af = $4;
if (rule_label(&r, $5.label))
YYERROR;
- h = ifa_lookup(i->ifname,
- PFCTL_IFLOOKUP_HOST);
+ h = ifa_lookup(i->ifname, 0);
expand_rule(&r, NULL, NULL, NULL, NULL,
h, NULL, NULL, NULL, NULL, NULL,
NULL);
@@ -1361,6 +1376,7 @@ pfrule : action dir logquick interface route af proto fromto
struct node_state_opt *o;
struct node_proto *proto;
int srctrack = 0;
+ int statelock = 0;
if (check_rulestate(PFCTL_STATE_FILTER))
YYERROR;
@@ -1499,6 +1515,15 @@ pfrule : action dir logquick interface route af proto fromto
o->data.max_src_nodes;
r.rule_flag |= PFRULE_SRCTRACK;
break;
+ case PF_STATE_OPT_STATELOCK:
+ if (statelock) {
+ yyerror("state locking option: "
+ "multiple definitons");
+ YYERROR;
+ }
+ statelock = 1;
+ r.rule_flag |= o->data.statelock;
+ break;
case PF_STATE_OPT_TIMEOUT:
if (r.timeout[o->data.timeout.number]) {
yyerror("state timeout %s "
@@ -1513,6 +1538,8 @@ pfrule : action dir logquick interface route af proto fromto
o = o->next;
free(p);
}
+ if (r.keep_state && !statelock)
+ r.rule_flag |= default_statelock;
if ($9.fragment)
r.rule_flag |= PFRULE_FRAGMENT;
@@ -1543,13 +1570,20 @@ pfrule : action dir logquick interface route af proto fromto
}
if ((r.rpool.opts & PF_POOL_TYPEMASK) ==
PF_POOL_NONE && ($5.host->next != NULL ||
- $5.host->addr.type == PF_ADDR_TABLE))
- r.rpool.opts = PF_POOL_ROUNDROBIN;
+ $5.host->addr.type == PF_ADDR_TABLE ||
+ DYNIF_MULTIADDR($5.host->addr)))
+ r.rpool.opts |= PF_POOL_ROUNDROBIN;
if ((r.rpool.opts & PF_POOL_TYPEMASK) !=
PF_POOL_ROUNDROBIN &&
disallow_table($5.host, "tables are only "
"supported in round-robin routing pools"))
- YYERROR;
+ YYERROR;
+ if ((r.rpool.opts & PF_POOL_TYPEMASK) !=
+ PF_POOL_ROUNDROBIN &&
+ disallow_alias($5.host, "interface (%s) "
+ "is only supported in round-robin "
+ "routing pools"))
+ YYERROR;
if ($5.host->next != NULL) {
if ((r.rpool.opts & PF_POOL_TYPEMASK) !=
PF_POOL_ROUNDROBIN) {
@@ -1771,7 +1805,7 @@ if_item_not : not if_item { $$ = $2; $$->not = $1; }
if_item : STRING {
struct node_host *n;
- if ((n = ifa_exists($1)) == NULL) {
+ if ((n = ifa_exists($1, 1)) == NULL) {
yyerror("unknown interface %s", $1);
YYERROR;
}
@@ -2005,7 +2039,31 @@ number : STRING {
;
dynaddr : '(' STRING ')' {
- if (ifa_exists($2) == NULL) {
+ int flags = 0;
+ char *p;
+
+ while ((p = strrchr($2, ':')) != NULL) {
+ if (!strcmp(p+1, "network"))
+ flags |= PFI_AFLAG_NETWORK;
+ else if (!strcmp(p+1, "broadcast"))
+ flags |= PFI_AFLAG_BROADCAST;
+ else if (!strcmp(p+1, "peer"))
+ flags |= PFI_AFLAG_PEER;
+ else if (!strcmp(p+1, "0"))
+ flags |= PFI_AFLAG_NOALIAS;
+ else {
+ yyerror("interface %s has bad modifier",
+ $2);
+ YYERROR;
+ }
+ *p = '\0';
+ }
+ if (flags & (flags - 1) & PFI_AFLAG_MODEMASK) {
+ yyerror("illegal combination of "
+ "interface modifiers");
+ YYERROR;
+ }
+ if (ifa_exists($2, 1) == NULL && strcmp($2, "self")) {
yyerror("interface %s does not exist", $2);
YYERROR;
}
@@ -2015,6 +2073,7 @@ dynaddr : '(' STRING ')' {
$$->af = 0;
set_ipmask($$, 128);
$$->addr.type = PF_ADDR_DYNIFTL;
+ $$->addr.iflags = flags;
if (strlcpy($$->addr.v.ifname, $2,
sizeof($$->addr.v.ifname)) >=
sizeof($$->addr.v.ifname)) {
@@ -2466,6 +2525,17 @@ sourcetrack : SOURCETRACK {
}
;
+statelock : IFBOUND {
+ $$ = PFRULE_IFBOUND;
+ }
+ | GRBOUND {
+ $$ = PFRULE_GRBOUND;
+ }
+ | FLOATING {
+ $$ = 0;
+ }
+ ;
+
keep : KEEP STATE state_opt_spec {
$$.action = PF_STATE_NORMAL;
$$.options = $3;
@@ -2536,6 +2606,15 @@ state_opt_item : MAXIMUM number {
$$->next = NULL;
$$->tail = $$;
}
+ | statelock {
+ $$ = calloc(1, sizeof(struct node_state_opt));
+ if ($$ == NULL)
+ err(1, "state_opt_item: calloc");
+ $$->type = PF_STATE_OPT_STATELOCK;
+ $$->data.statelock = $1;
+ $$->next = NULL;
+ $$->tail = $$;
+ }
| STRING number {
int i;
@@ -2869,13 +2948,21 @@ natrule : nataction interface af proto fromto tag redirpool pool_opts
r.rpool.opts = $8.type;
if ((r.rpool.opts & PF_POOL_TYPEMASK) ==
PF_POOL_NONE && ($7->host->next != NULL ||
- $7->host->addr.type == PF_ADDR_TABLE))
+ $7->host->addr.type == PF_ADDR_TABLE ||
+ DYNIF_MULTIADDR($7->host->addr)))
r.rpool.opts = PF_POOL_ROUNDROBIN;
if ((r.rpool.opts & PF_POOL_TYPEMASK) !=
PF_POOL_ROUNDROBIN &&
disallow_table($7->host, "tables are only "
- "supported in round-robin redirction pools"))
- YYERROR;
+ "supported in round-robin redirection "
+ "pools"))
+ YYERROR;
+ if ((r.rpool.opts & PF_POOL_TYPEMASK) !=
+ PF_POOL_ROUNDROBIN &&
+ disallow_alias($7->host, "interface (%s) "
+ "is only supported in round-robin "
+ "redirection pools"))
+ YYERROR;
if ($7->host->next != NULL) {
if ((r.rpool.opts & PF_POOL_TYPEMASK) !=
PF_POOL_ROUNDROBIN) {
@@ -2884,15 +2971,6 @@ natrule : nataction interface af proto fromto tag redirpool pool_opts
"redirection addresses");
YYERROR;
}
- } else {
- if ((r.af == AF_INET &&
- unmask(&$7->host->addr.v.a.mask,
- r.af) == 32) ||
- (r.af == AF_INET6 &&
- unmask(&$7->host->addr.v.a.mask,
- r.af) == 128)) {
- r.rpool.opts = PF_POOL_NONE;
- }
}
}
@@ -2979,10 +3057,18 @@ binatrule : no BINAT natpass interface af proto FROM host TO ipspec tag
if ($8 != NULL && disallow_table($8, "invalid use of "
"table <%s> as the source address of a binat rule"))
YYERROR;
+ if ($8 != NULL && disallow_alias($8, "invalid use of "
+ "interface (%s) as the source address of a binat "
+ "rule"))
+ YYERROR;
if ($12 != NULL && $12->host != NULL && disallow_table(
$12->host, "invalid use of table <%s> as the "
"redirect address of a binat rule"))
YYERROR;
+ if ($12 != NULL && $12->host != NULL && disallow_alias(
+ $12->host, "invalid use of interface (%s) as the "
+ "redirect address of a binat rule"))
+ YYERROR;
if ($8 != NULL) {
if ($8->next) {
@@ -3072,14 +3158,12 @@ tag : /* empty */ { $$ = NULL; }
;
route_host : STRING {
- struct node_host *n;
-
$$ = calloc(1, sizeof(struct node_host));
if ($$ == NULL)
err(1, "route_host: calloc");
if (($$->ifname = strdup($1)) == NULL)
err(1, "routeto: strdup");
- if ((n = ifa_exists($$->ifname)) == NULL) {
+ if (ifa_exists($$->ifname, 0) == NULL) {
yyerror("routeto: unknown interface %s",
$$->ifname);
YYERROR;
@@ -3089,12 +3173,10 @@ route_host : STRING {
$$->tail = $$;
}
| '(' STRING host ')' {
- struct node_host *n;
-
$$ = $3;
if (($$->ifname = strdup($2)) == NULL)
err(1, "routeto: strdup");
- if ((n = ifa_exists($$->ifname)) == NULL) {
+ if (ifa_exists($$->ifname, 0) == NULL) {
yyerror("routeto: unknown interface %s",
$$->ifname);
YYERROR;
@@ -3235,6 +3317,17 @@ disallow_table(struct node_host *h, const char *fmt)
}
int
+disallow_alias(struct node_host *h, const char *fmt)
+{
+ for (; h != NULL; h = h->next)
+ if (DYNIF_MULTIADDR(h->addr)) {
+ yyerror(fmt, h->addr.v.tblname);
+ return (1);
+ }
+ return (0);
+}
+
+int
rule_consistent(struct pf_rule *r)
{
int problems = 0;
@@ -3297,12 +3390,6 @@ filter_consistent(struct pf_rule *r)
yyerror("allow-opts can only be specified for pass rules");
problems++;
}
- if (!r->af && (r->src.addr.type == PF_ADDR_DYNIFTL ||
- r->dst.addr.type == PF_ADDR_DYNIFTL)) {
- yyerror("dynamic addresses require address family "
- "(inet/inet6)");
- problems++;
- }
if (r->rule_flag & PFRULE_FRAGMENT && (r->src.port_op ||
r->dst.port_op || r->flagset || r->type || r->code)) {
yyerror("fragments can be filtered only on IP header fields");
@@ -3327,27 +3414,13 @@ filter_consistent(struct pf_rule *r)
int
nat_consistent(struct pf_rule *r)
{
- int problems = 0;
- struct pf_pooladdr *pa;
-
- if (!r->af) {
- TAILQ_FOREACH(pa, &r->rpool.list, entries) {
- if (pa->addr.type == PF_ADDR_DYNIFTL) {
- yyerror("dynamic addresses require "
- "address family (inet/inet6)");
- problems++;
- break;
- }
- }
- }
- return (-problems);
+ return (0); /* yeah! */
}
int
rdr_consistent(struct pf_rule *r)
{
int problems = 0;
- struct pf_pooladdr *pa;
if (r->proto != IPPROTO_TCP && r->proto != IPPROTO_UDP) {
if (r->src.port_op) {
@@ -3368,23 +3441,6 @@ rdr_consistent(struct pf_rule *r)
yyerror("invalid port operator for rdr destination port");
problems++;
}
- if (!r->af) {
- if (r->src.addr.type == PF_ADDR_DYNIFTL ||
- r->dst.addr.type == PF_ADDR_DYNIFTL) {
- yyerror("dynamic addresses require address family "
- "(inet/inet6)");
- problems++;
- } else {
- TAILQ_FOREACH(pa, &r->rpool.list, entries) {
- if (pa->addr.type == PF_ADDR_DYNIFTL) {
- yyerror("dynamic addresses require "
- "address family (inet/inet6)");
- problems++;
- break;
- }
- }
- }
- }
return (-problems);
}
@@ -4085,15 +4141,18 @@ lookup(char *s)
{ "file", FILENAME},
{ "fingerprints", FINGERPRINTS},
{ "flags", FLAGS},
+ { "floating", FLOATING},
{ "for", FOR},
{ "fragment", FRAGMENT},
{ "from", FROM},
{ "global", GLOBAL},
{ "group", GROUP},
+ { "group-bound", GRBOUND},
{ "hfsc", HFSC},
{ "hostid", HOSTID},
{ "icmp-type", ICMPTYPE},
{ "icmp6-type", ICMP6TYPE},
+ { "if-bound", IFBOUND},
{ "in", IN},
{ "inet", INET},
{ "inet6", INET6},
@@ -4149,6 +4208,7 @@ lookup(char *s)
{ "source-hash", SOURCEHASH},
{ "source-track", SOURCETRACK},
{ "state", STATE},
+ { "state-policy", STATEPOLICY},
{ "static-port", STATICPORT},
{ "sticky-address", STICKYADDRESS},
{ "synproxy", SYNPROXY},
@@ -4554,9 +4614,10 @@ invalid_redirect(struct node_host *nh, sa_family_t af)
if (!af) {
struct node_host *n;
- /* only tables are ok without an address family */
+ /* tables and dyniftl are ok without an address family */
for (n = nh; n != NULL; n = n->next) {
- if (n->addr.type != PF_ADDR_TABLE) {
+ if (n->addr.type != PF_ADDR_TABLE &&
+ n->addr.type != PF_ADDR_DYNIFTL) {
yyerror("address family not given and "
"translation address expands to multiple "
"address families");