diff options
Diffstat (limited to 'sbin/pfctl/parse.y')
-rw-r--r-- | sbin/pfctl/parse.y | 536 |
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) { |