summaryrefslogtreecommitdiffstats
path: root/sbin/pfctl/parse.y
diff options
context:
space:
mode:
Diffstat (limited to 'sbin/pfctl/parse.y')
-rw-r--r--sbin/pfctl/parse.y536
1 files changed, 492 insertions, 44 deletions
diff --git a/sbin/pfctl/parse.y b/sbin/pfctl/parse.y
index 99c26c0..b5577e2 100644
--- a/sbin/pfctl/parse.y
+++ b/sbin/pfctl/parse.y
@@ -37,6 +37,8 @@ __FBSDID("$FreeBSD$");
#include <sys/sysctl.h>
#endif
#include <net/if.h>
+#include <net/ethernet.h>
+#include <net/if_vlan_var.h>
#include <netinet/in.h>
#include <netinet/in_systm.h>
#include <netinet/ip.h>
@@ -46,8 +48,10 @@ __FBSDID("$FreeBSD$");
#include <arpa/inet.h>
#include <altq/altq.h>
#include <altq/altq_cbq.h>
+#include <altq/altq_codel.h>
#include <altq/altq_priq.h>
#include <altq/altq_hfsc.h>
+#include <altq/altq_fairq.h>
#include <stdio.h>
#include <unistd.h>
@@ -158,6 +162,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_CONN,
PF_STATE_OPT_MAX_SRC_CONN_RATE, PF_STATE_OPT_MAX_SRC_NODES,
+ PF_STATE_OPT_MAX_PACKETS,
PF_STATE_OPT_OVERLOAD, PF_STATE_OPT_STATELOCK,
PF_STATE_OPT_TIMEOUT, PF_STATE_OPT_SLOPPY, };
@@ -169,6 +174,7 @@ struct node_state_opt {
u_int32_t max_states;
u_int32_t max_src_states;
u_int32_t max_src_conn;
+ u_int32_t max_packets;
struct {
u_int32_t limit;
u_int32_t seconds;
@@ -215,6 +221,7 @@ struct filter_opts {
#define FOM_TOS 0x04
#define FOM_KEEP 0x08
#define FOM_SRCTRACK 0x10
+#define FOM_DSCP 0x20
struct node_uid *uid;
struct node_gid *gid;
struct {
@@ -225,7 +232,9 @@ struct filter_opts {
} flags;
struct node_icmp *icmpspec;
u_int32_t tos;
+ u_int32_t dscp;
u_int32_t prob;
+ u_int32_t tracker;
struct {
int action;
struct node_state_opt *options;
@@ -233,10 +242,19 @@ struct filter_opts {
int fragment;
int allowopts;
char *label;
+ char *schedule;
struct node_qassign queues;
char *tag;
char *match_tag;
u_int8_t match_tag_not;
+ struct {
+ uint8_t pcp[2];
+ uint8_t op;
+ uint8_t setpcp;
+ } ieee8021q_pcp;
+ u_int32_t dnpipe;
+ u_int32_t pdnpipe;
+ u_int32_t free_flags;
u_int rtableid;
struct {
struct node_host *addr;
@@ -246,6 +264,7 @@ struct filter_opts {
struct antispoof_opts {
char *label;
+ u_int32_t tracker;
u_int rtableid;
} antispoof_opts;
@@ -298,8 +317,9 @@ struct pool_opts {
} pool_opts;
-
+struct codel_opts codel_opts;
struct node_hfsc_opts hfsc_opts;
+struct node_fairq_opts fairq_opts;
struct node_state_opt *keep_state_defaults = NULL;
int disallow_table(struct node_host *, const char *);
@@ -337,6 +357,7 @@ int expand_skip_interface(struct node_if *);
int check_rulestate(int);
int getservice(char *);
int rule_label(struct pf_rule *, char *);
+int rule_schedule(struct pf_rule *, char *);
int rt_tableid_max(void);
void mv_rules(struct pf_ruleset *, struct pf_ruleset *);
@@ -422,6 +443,8 @@ typedef struct {
struct table_opts table_opts;
struct pool_opts pool_opts;
struct node_hfsc_opts hfsc_opts;
+ struct node_fairq_opts fairq_opts;
+ struct codel_opts codel_opts;
} v;
int lineno;
} YYSTYPE;
@@ -436,29 +459,31 @@ int parseport(char *, struct range *r, int);
%}
-%token PASS BLOCK SCRUB RETURN IN OS OUT LOG QUICK ON FROM TO FLAGS
+%token PASS BLOCK MATCH SCRUB RETURN IN OS OUT LOG QUICK ON FROM TO FLAGS
%token RETURNRST RETURNICMP RETURNICMP6 PROTO INET INET6 ALL ANY ICMPTYPE
%token ICMP6TYPE CODE KEEP MODULATE STATE PORT RDR NAT BINAT ARROW NODF
-%token MINTTL ERROR ALLOWOPTS FASTROUTE FILENAME ROUTETO DUPTO REPLYTO NO LABEL
-%token NOROUTE URPFFAILED FRAGMENT USER GROUP MAXMSS MAXIMUM TTL TOS DROP TABLE
+%token MINTTL ERROR ALLOWOPTS FASTROUTE FILENAME ROUTETO DUPTO REPLYTO NO LABEL SCHEDULE
+%token NOROUTE URPFFAILED FRAGMENT USER GROUP MAXMSS MAXIMUM TTL TOS DSCP DROP TABLE TRACKER
%token REASSEMBLE FRAGDROP FRAGCROP ANCHOR NATANCHOR RDRANCHOR BINATANCHOR
%token SET OPTIMIZATION TIMEOUT LIMIT LOGINTERFACE BLOCKPOLICY RANDOMID
%token REQUIREORDER SYNPROXY FINGERPRINTS NOSYNC DEBUG SKIP HOSTID
%token ANTISPOOF FOR INCLUDE
%token BITMASK RANDOM SOURCEHASH ROUNDROBIN STATICPORT PROBABILITY
-%token ALTQ CBQ PRIQ HFSC BANDWIDTH TBRSIZE LINKSHARE REALTIME UPPERLIMIT
-%token QUEUE PRIORITY QLIMIT RTABLE
+%token ALTQ CBQ CODEL PRIQ HFSC FAIRQ BANDWIDTH TBRSIZE LINKSHARE REALTIME
+%token UPPERLIMIT QUEUE PRIORITY QLIMIT HOGS BUCKETS RTABLE TARGET INTERVAL
+%token DNPIPE DNQUEUE
%token LOAD RULESET_OPTIMIZATION
%token STICKYADDRESS MAXSRCSTATES MAXSRCNODES SOURCETRACK GLOBAL RULE
%token MAXSRCCONN MAXSRCCONNRATE OVERLOAD FLUSH SLOPPY
-%token TAGGED TAG IFBOUND FLOATING STATEPOLICY STATEDEFAULTS ROUTE SETTOS
+%token TAGGED TAG IFBOUND FLOATING STATEPOLICY STATEDEFAULTS ROUTE SETTOS MAXPCKT
+%token IEEE8021QPCP IEEE8021QSETPCP
%token DIVERTTO DIVERTREPLY
%token <v.string> STRING
%token <v.number> NUMBER
%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
+%type <v.number> tos dscp not yesno
%type <v.probability> probability
%type <v.i> no dir af fragcache optimizer
%type <v.i> sourcetrack flush unaryop statelock
@@ -473,8 +498,8 @@ int parseport(char *, struct range *r, int);
%type <v.icmp> icmp6_list icmp6_item
%type <v.number> reticmpspec reticmp6spec
%type <v.fromto> fromto
-%type <v.peer> ipportspec from to
-%type <v.host> ipspec toipspec xhost host dynaddr host_list
+%type <v.peer> ipportspec from to toipportspec
+%type <v.host> ipspec xhost host dynaddr host_list
%type <v.host> redir_host_list redirspec
%type <v.host> route_host route_host_list routespec
%type <v.os> os xos os_list
@@ -483,7 +508,7 @@ int parseport(char *, struct range *r, int);
%type <v.gid> gids gid_list gid_item
%type <v.route> route
%type <v.redirection> redirection redirpool
-%type <v.string> label stringall tag anchorname
+%type <v.string> label schedule stringall tag anchorname
%type <v.string> string varstring numberstring
%type <v.keep_state> keep
%type <v.state_opt> state_opt_spec state_opt_list state_opt_item
@@ -495,6 +520,8 @@ int parseport(char *, struct range *r, int);
%type <v.number> cbqflags_list cbqflags_item
%type <v.number> priqflags_list priqflags_item
%type <v.hfsc_opts> hfscopts_list hfscopts_item hfsc_opts
+%type <v.fairq_opts> fairqopts_list fairqopts_item fairq_opts
+%type <v.codel_opts> codelopts_list codelopts_item codel_opts
%type <v.queue_bwspec> bandwidth
%type <v.filter_opts> filter_opts filter_opt filter_opts_l
%type <v.antispoof_opts> antispoof_opts antispoof_opt antispoof_opts_l
@@ -874,6 +901,11 @@ anchorrule : ANCHOR anchorname dir quick interface af proto fromto
YYERROR;
}
+ r.ieee8021q_pcp.pcp[0] = $9.ieee8021q_pcp.pcp[0];
+ r.ieee8021q_pcp.pcp[1] = $9.ieee8021q_pcp.pcp[1];
+ r.ieee8021q_pcp.op = $9.ieee8021q_pcp.op;
+ r.ieee8021q_pcp.setpcp = $9.ieee8021q_pcp.setpcp;
+
if ($9.match_tag)
if (strlcpy(r.match_tagname, $9.match_tag,
PF_TAG_NAME_SIZE) >= PF_TAG_NAME_SIZE) {
@@ -1214,6 +1246,7 @@ antispoof : ANTISPOOF logquick antispoof_ifspc af antispoof_opts {
if (rule_label(&r, $5.label))
YYERROR;
r.rtableid = $5.rtableid;
+ r.cuid = $5.tracker;
j = calloc(1, sizeof(struct node_if));
if (j == NULL)
err(1, "antispoof: calloc");
@@ -1263,6 +1296,7 @@ antispoof : ANTISPOOF logquick antispoof_ifspc af antispoof_opts {
r.logif = $2.logif;
r.quick = $2.quick;
r.af = $4;
+ r.cuid = $5.tracker;
if (rule_label(&r, $5.label))
YYERROR;
r.rtableid = $5.rtableid;
@@ -1324,6 +1358,9 @@ antispoof_opt : label {
}
antispoof_opts.label = $1;
}
+ | TRACKER number {
+ antispoof_opts.tracker = $2;
+ }
| RTABLE NUMBER {
if ($2 < 0 || $2 > rt_tableid_max()) {
yyerror("invalid rtable id");
@@ -1466,7 +1503,7 @@ altqif : ALTQ interface queue_opts QUEUE qassign {
a.scheduler = $3.scheduler.qtype;
a.qlimit = $3.qlimit;
a.tbrsize = $3.tbrsize;
- if ($5 == NULL) {
+ if ($5 == NULL && $3.scheduler.qtype != ALTQT_CODEL) {
yyerror("no child queues specified");
YYERROR;
}
@@ -1598,14 +1635,22 @@ bandwidth : STRING {
bps = strtod($1, &cp);
if (cp != NULL) {
- if (!strcmp(cp, "b"))
+ if (!strcmp(cp, "b") || !strcmp(cp, "bit"))
; /* nothing */
- else if (!strcmp(cp, "Kb"))
+ else if (!strcmp(cp, "Kb") || !strcmp(cp, "Kbit"))
bps *= 1000;
- else if (!strcmp(cp, "Mb"))
+ else if (!strcmp(cp, "Mb") || !strcmp(cp, "Mbit"))
bps *= 1000 * 1000;
- else if (!strcmp(cp, "Gb"))
+ else if (!strcmp(cp, "Gb") || !strcmp(cp, "Gbit"))
bps *= 1000 * 1000 * 1000;
+ else if (!strcmp(cp, "B") || !strcmp(cp, "Byte"))
+ ; /* nothing */
+ else if (!strcmp(cp, "KB") || !strcmp(cp, "Kbyte"))
+ bps *= 1024;
+ else if (!strcmp(cp, "MB") || !strcmp(cp, "Mbyte"))
+ bps *= 1024 * 1024;
+ else if (!strcmp(cp, "GB") || !strcmp(cp, "Gbyte"))
+ bps *= 1024 * 1024 * 1024;
else if (!strcmp(cp, "%")) {
if (bps < 0 || bps > 100) {
yyerror("bandwidth spec "
@@ -1659,6 +1704,24 @@ scheduler : CBQ {
$$.qtype = ALTQT_HFSC;
$$.data.hfsc_opts = $3;
}
+ | FAIRQ {
+ $$.qtype = ALTQT_FAIRQ;
+ bzero(&$$.data.fairq_opts,
+ sizeof(struct node_fairq_opts));
+ }
+ | FAIRQ '(' fairq_opts ')' {
+ $$.qtype = ALTQT_FAIRQ;
+ $$.data.fairq_opts = $3;
+ }
+ | CODEL {
+ $$.qtype = ALTQT_CODEL;
+ bzero(&$$.data.codel_opts,
+ sizeof(struct codel_opts));
+ }
+ | CODEL '(' codel_opts ')' {
+ $$.qtype = ALTQT_CODEL;
+ $$.data.codel_opts = $3;
+ }
;
cbqflags_list : cbqflags_item { $$ |= $1; }
@@ -1676,6 +1739,8 @@ cbqflags_item : STRING {
$$ = CBQCLF_RED|CBQCLF_ECN;
else if (!strcmp($1, "rio"))
$$ = CBQCLF_RIO;
+ else if (!strcmp($1, "codel"))
+ $$ = CBQCLF_CODEL;
else {
yyerror("unknown cbq flag \"%s\"", $1);
free($1);
@@ -1698,6 +1763,8 @@ priqflags_item : STRING {
$$ = PRCF_RED|PRCF_ECN;
else if (!strcmp($1, "rio"))
$$ = PRCF_RIO;
+ else if (!strcmp($1, "codel"))
+ $$ = PRCF_CODEL;
else {
yyerror("unknown priq flag \"%s\"", $1);
free($1);
@@ -1798,6 +1865,8 @@ hfscopts_item : LINKSHARE bandwidth {
hfsc_opts.flags |= HFCF_RED|HFCF_ECN;
else if (!strcmp($1, "rio"))
hfsc_opts.flags |= HFCF_RIO;
+ else if (!strcmp($1, "codel"))
+ hfsc_opts.flags |= HFCF_CODEL;
else {
yyerror("unknown hfsc flag \"%s\"", $1);
free($1);
@@ -1807,6 +1876,102 @@ hfscopts_item : LINKSHARE bandwidth {
}
;
+fairq_opts : {
+ bzero(&fairq_opts,
+ sizeof(struct node_fairq_opts));
+ }
+ fairqopts_list {
+ $$ = fairq_opts;
+ }
+ ;
+
+fairqopts_list : fairqopts_item
+ | fairqopts_list comma fairqopts_item
+ ;
+
+fairqopts_item : LINKSHARE bandwidth {
+ if (fairq_opts.linkshare.used) {
+ yyerror("linkshare already specified");
+ YYERROR;
+ }
+ fairq_opts.linkshare.m2 = $2;
+ fairq_opts.linkshare.used = 1;
+ }
+ | LINKSHARE '(' bandwidth number bandwidth ')' {
+ if (fairq_opts.linkshare.used) {
+ yyerror("linkshare already specified");
+ YYERROR;
+ }
+ fairq_opts.linkshare.m1 = $3;
+ fairq_opts.linkshare.d = $4;
+ fairq_opts.linkshare.m2 = $5;
+ fairq_opts.linkshare.used = 1;
+ }
+ | HOGS bandwidth {
+ fairq_opts.hogs_bw = $2;
+ }
+ | BUCKETS number {
+ fairq_opts.nbuckets = $2;
+ }
+ | STRING {
+ if (!strcmp($1, "default"))
+ fairq_opts.flags |= FARF_DEFAULTCLASS;
+ else if (!strcmp($1, "red"))
+ fairq_opts.flags |= FARF_RED;
+ else if (!strcmp($1, "ecn"))
+ fairq_opts.flags |= FARF_RED|FARF_ECN;
+ else if (!strcmp($1, "rio"))
+ fairq_opts.flags |= FARF_RIO;
+ else if (!strcmp($1, "codel"))
+ fairq_opts.flags |= FARF_CODEL;
+ else {
+ yyerror("unknown fairq flag \"%s\"", $1);
+ free($1);
+ YYERROR;
+ }
+ free($1);
+ }
+ ;
+
+codel_opts : {
+ bzero(&codel_opts,
+ sizeof(struct codel_opts));
+ }
+ codelopts_list {
+ $$ = codel_opts;
+ }
+ ;
+
+codelopts_list : codelopts_item
+ | codelopts_list comma codelopts_item
+ ;
+
+codelopts_item : INTERVAL number {
+ if (codel_opts.interval) {
+ yyerror("interval already specified");
+ YYERROR;
+ }
+ codel_opts.interval = $2;
+ }
+ | TARGET number {
+ if (codel_opts.target) {
+ yyerror("target already specified");
+ YYERROR;
+ }
+ codel_opts.target = $2;
+ }
+ | STRING {
+ if (!strcmp($1, "ecn"))
+ codel_opts.ecn = 1;
+ else {
+ yyerror("unknown codel option \"%s\"", $1);
+ free($1);
+ YYERROR;
+ }
+ free($1);
+ }
+ ;
+
qassign : /* empty */ { $$ = NULL; }
| qassign_item { $$ = $1; }
| '{' optnl qassign_list '}' { $$ = $3; }
@@ -1878,6 +2043,11 @@ pfrule : action dir logquick interface route af proto fromto
r.prob = $9.prob;
r.rtableid = $9.rtableid;
+ r.ieee8021q_pcp.pcp[0] = $9.ieee8021q_pcp.pcp[0];
+ r.ieee8021q_pcp.pcp[1] = $9.ieee8021q_pcp.pcp[1];
+ r.ieee8021q_pcp.op = $9.ieee8021q_pcp.op;
+ r.ieee8021q_pcp.setpcp = $9.ieee8021q_pcp.setpcp;
+
r.af = $6;
if ($9.tag)
if (strlcpy(r.tagname, $9.tag,
@@ -1897,6 +2067,11 @@ pfrule : action dir logquick interface route af proto fromto
if (rule_label(&r, $9.label))
YYERROR;
free($9.label);
+ if (rule_schedule(&r, $9.schedule))
+ YYERROR;
+ free($9.schedule);
+ if ($9.tracker)
+ r.cuid = $9.tracker;
r.flags = $9.flags.b1;
r.flagset = $9.flags.b2;
if (($9.flags.b1 & $9.flags.b2) != $9.flags.b1) {
@@ -1928,7 +2103,14 @@ pfrule : action dir logquick interface route af proto fromto
#endif
}
- r.tos = $9.tos;
+ if ($9.tos) {
+ r.tos = $9.tos;
+ r.rule_flag |= PFRULE_TOS;
+ }
+ if ($9.dscp) {
+ r.tos = $9.dscp;
+ r.rule_flag |= PFRULE_DSCP;
+ }
r.keep_state = $9.keep.action;
o = $9.keep.options;
@@ -1960,6 +2142,14 @@ pfrule : action dir logquick interface route af proto fromto
}
r.rule_flag |= PFRULE_NOSYNC;
break;
+ case PF_STATE_OPT_MAX_PACKETS:
+ if (o->data.max_packets == 0) {
+ yyerror("max_packets must be"
+ "greater than 0");
+ YYERROR;
+ }
+ r.spare2 = o->data.max_packets;
+ break;
case PF_STATE_OPT_SRCTRACK:
if (srctrack) {
yyerror("state option "
@@ -2246,6 +2436,15 @@ pfrule : action dir logquick interface route af proto fromto
}
#endif
+ if ($9.dnpipe) {
+ r.dnpipe = $9.dnpipe;
+ if ($9.free_flags & PFRULE_DN_IS_PIPE)
+ r.free_flags |= PFRULE_DN_IS_PIPE;
+ else
+ r.free_flags |= PFRULE_DN_IS_QUEUE;
+ r.pdnpipe = $9.pdnpipe;
+ }
+
expand_rule(&r, $4, $5.host, $7, $8.src_os,
$8.src.host, $8.src.port, $8.dst.host, $8.dst.port,
$9.uid, $9.gid, $9.icmpspec, "");
@@ -2306,6 +2505,14 @@ filter_opt : USER uids {
filter_opts.marker |= FOM_TOS;
filter_opts.tos = $2;
}
+ | dscp {
+ if (filter_opts.marker & FOM_DSCP) {
+ yyerror("dscp cannot be redefined");
+ YYERROR;
+ }
+ filter_opts.marker |= FOM_DSCP;
+ filter_opts.dscp = $1;
+ }
| keep {
if (filter_opts.marker & FOM_KEEP) {
yyerror("modulate or keep cannot be redefined");
@@ -2315,6 +2522,9 @@ filter_opt : USER uids {
filter_opts.keep.action = $1.action;
filter_opts.keep.options = $1.options;
}
+ | TRACKER number {
+ filter_opts.tracker = $2;
+ }
| FRAGMENT {
filter_opts.fragment = 1;
}
@@ -2328,6 +2538,13 @@ filter_opt : USER uids {
}
filter_opts.label = $1;
}
+ | schedule {
+ if (filter_opts.schedule) {
+ yyerror("schedule label cannot be redefined");
+ YYERROR;
+ }
+ filter_opts.schedule = $1;
+ }
| qname {
if (filter_opts.queues.qname) {
yyerror("queue cannot be redefined");
@@ -2335,6 +2552,32 @@ filter_opt : USER uids {
}
filter_opts.queues = $1;
}
+ | DNPIPE number {
+ filter_opts.dnpipe = $2;
+ filter_opts.free_flags |= PFRULE_DN_IS_PIPE;
+ }
+ | DNPIPE '(' number ')' {
+ filter_opts.dnpipe = $3;
+ filter_opts.free_flags |= PFRULE_DN_IS_PIPE;
+ }
+ | DNPIPE '(' number comma number ')' {
+ filter_opts.pdnpipe = $5;
+ filter_opts.dnpipe = $3;
+ filter_opts.free_flags |= PFRULE_DN_IS_PIPE;
+ }
+ | DNQUEUE number {
+ filter_opts.dnpipe = $2;
+ filter_opts.free_flags |= PFRULE_DN_IS_QUEUE;
+ }
+ | DNQUEUE '(' number comma number ')' {
+ filter_opts.pdnpipe = $5;
+ filter_opts.dnpipe = $3;
+ filter_opts.free_flags |= PFRULE_DN_IS_QUEUE;
+ }
+ | DNQUEUE '(' number ')' {
+ filter_opts.dnpipe = $3;
+ filter_opts.free_flags |= PFRULE_DN_IS_QUEUE;
+ }
| TAG string {
filter_opts.tag = $2;
}
@@ -2354,6 +2597,98 @@ filter_opt : USER uids {
if (filter_opts.prob == 0)
filter_opts.prob = 1;
}
+ | IEEE8021QPCP STRING {
+ u_int pcp;
+
+ /*
+ * XXXRW: More complete set of operations, similar to
+ * ports.
+ */
+ if (!strcmp($2, "be"))
+ pcp = IEEE8021Q_PCP_BE;
+ else if (!strcmp($2, "bk"))
+ pcp = IEEE8021Q_PCP_BK;
+ else if (!strcmp($2, "ee"))
+ pcp = IEEE8021Q_PCP_EE;
+ else if (!strcmp($2, "ca"))
+ pcp = IEEE8021Q_PCP_CA;
+ else if (!strcmp($2, "vi"))
+ pcp = IEEE8021Q_PCP_VI;
+ else if (!strcmp($2, "vo"))
+ pcp = IEEE8021Q_PCP_VO;
+ else if (!strcmp($2, "ic"))
+ pcp = IEEE8021Q_PCP_IC;
+ else if (!strcmp($2, "nc"))
+ pcp = IEEE8021Q_PCP_NC;
+ else
+ pcp = 8; /* flag bad argument */
+ if (pcp > 7) {
+ yyerror("invalid ieee8021q_pcp value %s", $2);
+ free($2);
+ YYERROR;
+ }
+ free($2);
+ filter_opts.ieee8021q_pcp.pcp[0] = pcp;
+ filter_opts.ieee8021q_pcp.pcp[1] = 0;
+ filter_opts.ieee8021q_pcp.op = PF_OP_EQ;
+ }
+ | IEEE8021QPCP number {
+ u_int pcp;
+
+ pcp = $2;
+ if (pcp > 7) {
+ yyerror("invalid ieee8021q_pcp value %u", pcp);
+ YYERROR;
+ }
+ filter_opts.ieee8021q_pcp.pcp[0] = pcp;
+ filter_opts.ieee8021q_pcp.pcp[1] = 0;
+ filter_opts.ieee8021q_pcp.op = PF_OP_EQ;
+ }
+ | IEEE8021QSETPCP STRING {
+ u_int pcp;
+
+ /*
+ * XXXRW: More complete set of operations, similar to
+ * ports.
+ */
+ if (!strcmp($2, "be"))
+ pcp = IEEE8021Q_PCP_BE;
+ else if (!strcmp($2, "bk"))
+ pcp = IEEE8021Q_PCP_BK;
+ else if (!strcmp($2, "ee"))
+ pcp = IEEE8021Q_PCP_EE;
+ else if (!strcmp($2, "ca"))
+ pcp = IEEE8021Q_PCP_CA;
+ else if (!strcmp($2, "vi"))
+ pcp = IEEE8021Q_PCP_VI;
+ else if (!strcmp($2, "vo"))
+ pcp = IEEE8021Q_PCP_VO;
+ else if (!strcmp($2, "ic"))
+ pcp = IEEE8021Q_PCP_IC;
+ else if (!strcmp($2, "nc"))
+ pcp = IEEE8021Q_PCP_NC;
+ else
+ pcp = 8; /* flag bad argument */
+ if (pcp > 7) {
+ yyerror("invalid ieee8021q_setpcp value %s",
+ $2);
+ free($2);
+ YYERROR;
+ }
+ free($2);
+ filter_opts.ieee8021q_pcp.setpcp = pcp | SETPCP_VALID;
+ }
+ | IEEE8021QSETPCP number {
+ u_int pcp;
+
+ pcp = $2;
+ if (pcp > 7) {
+ yyerror("invalid ieee8021q_setpcp value %u",
+ pcp);
+ YYERROR;
+ }
+ filter_opts.ieee8021q_pcp.setpcp = pcp | SETPCP_VALID;
+ }
| RTABLE NUMBER {
if ($2 < 0 || $2 > rt_tableid_max()) {
yyerror("invalid rtable id");
@@ -2421,6 +2756,7 @@ probability : STRING {
action : PASS { $$.b1 = PF_PASS; $$.b2 = $$.w = 0; }
+ | MATCH { $$.b1 = PF_MATCH; $$.b2 = $$.w = 0; }
| BLOCK blockspec { $$ = $2; $$.b1 = PF_DROP; }
;
@@ -2749,8 +3085,8 @@ ipspec : ANY { $$ = NULL; }
| '{' optnl host_list '}' { $$ = $3; }
;
-toipspec : TO ipspec { $$ = $2; }
- | /* empty */ { $$ = NULL; }
+toipportspec : TO ipportspec { $$ = $2; }
+ | /* empty */ { $$.host = NULL; $$.port = NULL; }
;
host_list : ipspec optnl { $$ = $1; }
@@ -3398,6 +3734,48 @@ tos : STRING {
}
;
+dscp : DSCP STRING {
+ if (!strcmp($2, "EF"))
+ $$ = DSCP_EF;
+ else if (!strcmp($2, "VA"))
+ $$ = DSCP_VA;
+ else if (!strcmp($2, "af11"))
+ $$ = DSCP_AF11;
+ else if (!strcmp($2, "af12"))
+ $$ = DSCP_AF12;
+ else if (!strcmp($2, "af13"))
+ $$ = DSCP_AF13;
+ else if (!strcmp($2, "af21"))
+ $$ = DSCP_AF21;
+ else if (!strcmp($2, "af22"))
+ $$ = DSCP_AF22;
+ else if (!strcmp($2, "af23"))
+ $$ = DSCP_AF23;
+ else if (!strcmp($2, "af31"))
+ $$ = DSCP_AF31;
+ else if (!strcmp($2, "af32"))
+ $$ = DSCP_AF32;
+ else if (!strcmp($2, "af33"))
+ $$ = DSCP_AF33;
+ else if (!strcmp($2, "af41"))
+ $$ = DSCP_AF41;
+ else if (!strcmp($2, "af42"))
+ $$ = DSCP_AF42;
+ else if (!strcmp($2, "af43"))
+ $$ = DSCP_AF43;
+ else if ($2[0] == '0' && $2[1] == 'x')
+ $$ = strtoul($2, NULL, 16) * 4;
+ else
+ $$ = strtoul($2, NULL, 10) * 4;
+ if (!$$ || $$ > 255) {
+ yyerror("illegal dscp value %s", $2);
+ free($2);
+ YYERROR;
+ }
+ free($2);
+ }
+ ;
+
sourcetrack : SOURCETRACK { $$ = PF_SRCTRACK; }
| SOURCETRACK GLOBAL { $$ = PF_SRCTRACK_GLOBAL; }
| SOURCETRACK RULE { $$ = PF_SRCTRACK_RULE; }
@@ -3482,6 +3860,15 @@ state_opt_item : MAXIMUM NUMBER {
$$->next = NULL;
$$->tail = $$;
}
+ | MAXPCKT NUMBER {
+ $$ = calloc(1, sizeof(struct node_state_opt));
+ if ($$ == NULL)
+ err(1, "state_opt_item: calloc");
+ $$->type = PF_STATE_OPT_MAX_PACKETS;
+ $$->data.max_packets = $2;
+ $$->next = NULL;
+ $$->tail = $$;
+ }
| MAXSRCCONN NUMBER {
if ($2 < 0 || $2 > UINT_MAX) {
yyerror("only positive values permitted");
@@ -3604,6 +3991,11 @@ label : LABEL STRING {
}
;
+schedule : SCHEDULE STRING {
+ $$ = $2;
+ }
+ ;
+
qname : QUEUE STRING {
$$.qname = $2;
$$.pqname = NULL;
@@ -3979,7 +4371,7 @@ natrule : nataction interface af proto fromto tag tagged rtable
}
;
-binatrule : no BINAT natpasslog interface af proto FROM host toipspec tag
+binatrule : no BINAT natpasslog interface af proto FROM ipportspec toipportspec tag
tagged rtable redirection
{
struct pf_rule binat;
@@ -3987,7 +4379,7 @@ binatrule : no BINAT natpasslog interface af proto FROM host toipspec tag
if (check_rulestate(PFCTL_STATE_NAT))
YYERROR;
- if (disallow_urpf_failed($9, "\"urpf-failed\" is not "
+ if (disallow_urpf_failed($9.host, "\"urpf-failed\" is not "
"permitted as a binat destination"))
YYERROR;
@@ -4005,10 +4397,10 @@ binatrule : no BINAT natpasslog interface af proto FROM host toipspec tag
binat.log = $3.b2;
binat.logif = $3.w2;
binat.af = $5;
- if (!binat.af && $8 != NULL && $8->af)
- binat.af = $8->af;
- if (!binat.af && $9 != NULL && $9->af)
- binat.af = $9->af;
+ if (!binat.af && $8.host != NULL && $8.host->af)
+ binat.af = $8.host->af;
+ if (!binat.af && $9.host != NULL && $9.host->af)
+ binat.af = $9.host->af;
if (!binat.af && $13 != NULL && $13->host)
binat.af = $13->host->af;
@@ -4047,10 +4439,10 @@ binatrule : no BINAT natpasslog interface af proto FROM host toipspec tag
free($6);
}
- if ($8 != NULL && disallow_table($8, "invalid use of "
+ if ($8.host != NULL && disallow_table($8.host, "invalid use of "
"table <%s> as the source address of a binat rule"))
YYERROR;
- if ($8 != NULL && disallow_alias($8, "invalid use of "
+ if ($8.host != NULL && disallow_alias($8.host, "invalid use of "
"interface (%s) as the source address of a binat "
"rule"))
YYERROR;
@@ -4063,38 +4455,46 @@ binatrule : no BINAT natpasslog interface af proto FROM host toipspec tag
"redirect address of a binat rule"))
YYERROR;
- if ($8 != NULL) {
- if ($8->next) {
+ if ($8.host != NULL) {
+ if ($8.host->next) {
yyerror("multiple binat ip addresses");
YYERROR;
}
- if ($8->addr.type == PF_ADDR_DYNIFTL)
- $8->af = binat.af;
- if ($8->af != binat.af) {
+ if ($8.host->addr.type == PF_ADDR_DYNIFTL)
+ $8.host->af = binat.af;
+ if ($8.host->af != binat.af) {
yyerror("binat ip versions must match");
YYERROR;
}
- if (check_netmask($8, binat.af))
+ if (check_netmask($8.host, binat.af))
YYERROR;
- memcpy(&binat.src.addr, &$8->addr,
+ memcpy(&binat.src.addr, &$8.host->addr,
sizeof(binat.src.addr));
- free($8);
+ binat.src.neg = $8.host->not;
+ free($8.host);
}
- if ($9 != NULL) {
- if ($9->next) {
+ if ($9.host != NULL) {
+ if ($9.host->next) {
yyerror("multiple binat ip addresses");
YYERROR;
}
- if ($9->af != binat.af && $9->af) {
+ if ($9.host->af != binat.af && $9.host->af) {
yyerror("binat ip versions must match");
YYERROR;
}
- if (check_netmask($9, binat.af))
+ if (check_netmask($9.host, binat.af))
YYERROR;
- memcpy(&binat.dst.addr, &$9->addr,
+ memcpy(&binat.dst.addr, &$9.host->addr,
sizeof(binat.dst.addr));
- binat.dst.neg = $9->not;
- free($9);
+ binat.dst.neg = $9.host->not;
+ free($9.host);
+ }
+
+ if ($9.port != NULL) {
+ binat.dst.port[0] = $9.port->port[0];
+ binat.dst.port[1] = $9.port->port[1];
+ binat.dst.port_op = $9.port->op;
+ free($9.port);
}
if (binat.action == PF_NOBINAT) {
@@ -4440,6 +4840,15 @@ filter_consistent(struct pf_rule *r, int anchor_call)
"synproxy state or modulate state");
problems++;
}
+ if ((r->rule_flag & PFRULE_TOS) && (r->rule_flag & PFRULE_DSCP)) {
+ yyerror("tos and dscp cannot be used together");
+ problems++;
+ }
+ if (r->dnpipe && r->pdnpipe && !r->direction) {
+ yyerror("dummynet cannot be specified without direction");
+ problems++;
+ }
+
return (-problems);
}
@@ -4732,7 +5141,8 @@ expand_altq(struct pf_altq *a, struct node_if *interfaces,
if ((pf->loadopt & PFCTL_FLAG_ALTQ) == 0) {
FREE_LIST(struct node_if, interfaces);
- FREE_LIST(struct node_queue, nqueues);
+ if (nqueues)
+ FREE_LIST(struct node_queue, nqueues);
return (0);
}
@@ -4823,7 +5233,8 @@ expand_altq(struct pf_altq *a, struct node_if *interfaces,
}
);
FREE_LIST(struct node_if, interfaces);
- FREE_LIST(struct node_queue, nqueues);
+ if (nqueues)
+ FREE_LIST(struct node_queue, nqueues);
return (errs);
}
@@ -4983,6 +5394,7 @@ expand_rule(struct pf_rule *r,
int added = 0, error = 0;
char ifname[IF_NAMESIZE];
char label[PF_RULE_LABEL_SIZE];
+ char schedule[PF_RULE_LABEL_SIZE];
char tagname[PF_TAG_NAME_SIZE];
char match_tagname[PF_TAG_NAME_SIZE];
struct pf_pooladdr *pa;
@@ -4991,6 +5403,8 @@ expand_rule(struct pf_rule *r,
if (strlcpy(label, r->label, sizeof(label)) >= sizeof(label))
errx(1, "expand_rule: strlcpy");
+ if (strlcpy(schedule, r->schedule, sizeof(schedule)) > sizeof(schedule))
+ errx(1, "expand_rule: strlcpy");
if (strlcpy(tagname, r->tagname, sizeof(tagname)) >= sizeof(tagname))
errx(1, "expand_rule: strlcpy");
if (strlcpy(match_tagname, r->match_tagname, sizeof(match_tagname)) >=
@@ -5042,6 +5456,9 @@ expand_rule(struct pf_rule *r,
if (strlcpy(r->label, label, sizeof(r->label)) >=
sizeof(r->label))
errx(1, "expand_rule: strlcpy");
+ if (strlcpy(r->schedule, schedule, sizeof(r->schedule)) >=
+ sizeof(r->schedule))
+ errx(1, "expand_rule: strlcpy");
if (strlcpy(r->tagname, tagname, sizeof(r->tagname)) >=
sizeof(r->tagname))
errx(1, "expand_rule: strlcpy");
@@ -5050,6 +5467,8 @@ expand_rule(struct pf_rule *r,
errx(1, "expand_rule: strlcpy");
expand_label(r->label, PF_RULE_LABEL_SIZE, r->ifname, r->af,
src_host, src_port, dst_host, dst_port, proto->proto);
+ expand_label(r->schedule, PF_RULE_LABEL_SIZE, r->ifname, r->af,
+ src_host, src_port, dst_host, dst_port, proto->proto);
expand_label(r->tagname, PF_TAG_NAME_SIZE, r->ifname, r->af,
src_host, src_port, dst_host, dst_port, proto->proto);
expand_label(r->match_tagname, PF_TAG_NAME_SIZE, r->ifname,
@@ -5226,15 +5645,21 @@ lookup(char *s)
{ "bitmask", BITMASK},
{ "block", BLOCK},
{ "block-policy", BLOCKPOLICY},
+ { "buckets", BUCKETS},
{ "cbq", CBQ},
{ "code", CODE},
+ { "codelq", CODEL},
{ "crop", FRAGCROP},
{ "debug", DEBUG},
{ "divert-reply", DIVERTREPLY},
{ "divert-to", DIVERTTO},
+ { "dnpipe", DNPIPE},
+ { "dnqueue", DNQUEUE},
{ "drop", DROP},
{ "drop-ovl", FRAGDROP},
+ { "dscp", DSCP},
{ "dup-to", DUPTO},
+ { "fairq", FAIRQ},
{ "fastroute", FASTROUTE},
{ "file", FILENAME},
{ "fingerprints", FINGERPRINTS},
@@ -5247,14 +5672,18 @@ lookup(char *s)
{ "global", GLOBAL},
{ "group", GROUP},
{ "hfsc", HFSC},
+ { "hogs", HOGS},
{ "hostid", HOSTID},
{ "icmp-type", ICMPTYPE},
{ "icmp6-type", ICMP6TYPE},
+ { "ieee8021q-pcp", IEEE8021QPCP},
+ { "ieee8021q-setpcp", IEEE8021QSETPCP},
{ "if-bound", IFBOUND},
{ "in", IN},
{ "include", INCLUDE},
{ "inet", INET},
{ "inet6", INET6},
+ { "interval", INTERVAL},
{ "keep", KEEP},
{ "label", LABEL},
{ "limit", LIMIT},
@@ -5262,8 +5691,10 @@ lookup(char *s)
{ "load", LOAD},
{ "log", LOG},
{ "loginterface", LOGINTERFACE},
+ { "match", MATCH},
{ "max", MAXIMUM},
{ "max-mss", MAXMSS},
+ { "max-packets", MAXPCKT},
{ "max-src-conn", MAXSRCCONN},
{ "max-src-conn-rate", MAXSRCCONNRATE},
{ "max-src-nodes", MAXSRCNODES},
@@ -5308,6 +5739,7 @@ lookup(char *s)
{ "rtable", RTABLE},
{ "rule", RULE},
{ "ruleset-optimization", RULESET_OPTIMIZATION},
+ { "schedule", SCHEDULE},
{ "scrub", SCRUB},
{ "set", SET},
{ "set-tos", SETTOS},
@@ -5324,10 +5756,12 @@ lookup(char *s)
{ "table", TABLE},
{ "tag", TAG},
{ "tagged", TAGGED},
+ { "target", TARGET},
{ "tbrsize", TBRSIZE},
{ "timeout", TIMEOUT},
{ "to", TO},
{ "tos", TOS},
+ { "tracker", TRACKER},
{ "ttl", TTL},
{ "upperlimit", UPPERLIMIT},
{ "urpf-failed", URPFFAILED},
@@ -5939,6 +6373,20 @@ rule_label(struct pf_rule *r, char *s)
return (0);
}
+int
+rule_schedule(struct pf_rule *r, char *s)
+{
+ if (s) {
+ if (strlcpy(r->schedule, s, sizeof(r->label)) >=
+ sizeof(r->label)) {
+ yyerror("rule schedule label too long (max %d chars)",
+ sizeof(r->label)-1);
+ return (-1);
+ }
+ }
+ return (0);
+}
+
u_int16_t
parseicmpspec(char *w, sa_family_t af)
{
OpenPOWER on IntegriCloud