diff options
| author | Kristof Provost <kp@FreeBSD.org> | 2026-01-12 19:37:08 +0000 |
|---|---|---|
| committer | Kristof Provost <kp@FreeBSD.org> | 2026-01-14 06:44:43 +0000 |
| commit | 8716d8c7d97eec231820ecd1dc50c67beb95d58c (patch) | |
| tree | 2568106cfd450333b70c8803e86ce559837fb695 /sbin/pfctl | |
| parent | 1ee4405a00d7bcfa5545bba7a78b71cdd4cfdc20 (diff) | |
Diffstat (limited to 'sbin/pfctl')
| -rw-r--r-- | sbin/pfctl/parse.y | 83 | ||||
| -rw-r--r-- | sbin/pfctl/pfctl_parser.c | 12 | ||||
| -rw-r--r-- | sbin/pfctl/tests/files/pf1076.ok | 2 | ||||
| -rw-r--r-- | sbin/pfctl/tests/files/pf1077.ok | 2 |
4 files changed, 66 insertions, 33 deletions
diff --git a/sbin/pfctl/parse.y b/sbin/pfctl/parse.y index ded74a6391f1..67e0d30890a8 100644 --- a/sbin/pfctl/parse.y +++ b/sbin/pfctl/parse.y @@ -257,6 +257,11 @@ struct redirspec { bool binat; }; +struct limiterspec { + uint32_t id; + int limiter_action; +}; + static struct filter_opts { int marker; #define FOM_FLAGS 0x0001 @@ -287,8 +292,8 @@ static struct filter_opts { u_int32_t tos; u_int32_t prob; u_int32_t ridentifier; - u_int32_t statelim; - u_int32_t sourcelim; + struct limiterspec statelim; + struct limiterspec sourcelim; struct { int action; struct node_state_opt *options; @@ -566,6 +571,7 @@ typedef struct { struct statelim_opts *statelim_opts; struct sourcelim_opts *sourcelim_opts; struct pfctl_watermarks *watermarks; + struct limiterspec limiterspec; } v; int lineno; } YYSTYPE; @@ -600,7 +606,7 @@ int parseport(char *, struct range *r, int); %token TAGGED TAG IFBOUND FLOATING STATEPOLICY STATEDEFAULTS ROUTE SETTOS %token DIVERTTO DIVERTREPLY BRIDGE_TO RECEIVEDON NE LE GE AFTO NATTO RDRTO %token BINATTO MAXPKTRATE MAXPKTSIZE IPV6NH -%token LIMITER ID RATE SOURCE ENTRIES ABOVE BELOW MASK +%token LIMITER ID RATE SOURCE ENTRIES ABOVE BELOW MASK NOMATCH %token <v.string> STRING %token <v.number> NUMBER %token <v.i> PORTBINARY @@ -664,8 +670,8 @@ int parseport(char *, struct range *r, int); %type <v.bridge_to> bridge %type <v.mac> xmac mac mac_list macspec %type <v.string> statelim_nm sourcelim_nm -%type <v.number> statelim_id sourcelim_id -%type <v.number> statelim_filter_opt sourcelim_filter_opt +%type <v.number> statelim_id sourcelim_id limiter_opt limiter_opt_spec +%type <v.limiterspec> statelim_filter_opt sourcelim_filter_opt %type <v.statelim_opts> statelim_opts %type <v.sourcelim_opts> sourcelim_opts %% @@ -2515,20 +2521,22 @@ statelim_opt : statelim_id { ; statelim_filter_opt - : statelim_nm { + : STATE LIMITER STRING limiter_opt_spec { struct pfctl_statelim *stlim; - stlim = pfctl_get_statelim_nm(pf, $1); - free($1); + stlim = pfctl_get_statelim_nm(pf, $3); + free($3); if (stlim == NULL) { yyerror("state limiter not found"); YYERROR; } - $$ = stlim->ioc.id; + $$.id = stlim->ioc.id; + $$.limiter_action = $4; } - | STATE LIMITER statelim_id { - $$ = $3; + | STATE LIMITER statelim_id limiter_opt_spec { + $$.id = $3; + $$.limiter_action = $4; } ; @@ -2760,20 +2768,34 @@ sourcelim_opt_below ; sourcelim_filter_opt - : sourcelim_nm { + : SOURCE LIMITER STRING limiter_opt_spec { struct pfctl_sourcelim *srlim; - srlim = pfctl_get_sourcelim_nm(pf, $1); - free($1); + srlim = pfctl_get_sourcelim_nm(pf, $3); + free($3); if (srlim == NULL) { yyerror("source limiter not found"); YYERROR; } - $$ = srlim->ioc.id; + $$.id = srlim->ioc.id; + $$.limiter_action = $4; } - | SOURCE LIMITER sourcelim_id { - $$ = $3; + | SOURCE LIMITER sourcelim_id limiter_opt_spec { + $$.id = $3; + $$.limiter_action = $4; + } + ; + +limiter_opt_spec: /* empty */ { $$ = PF_LIMITER_NOMATCH; } + | '(' limiter_opt ')' { $$ = $2; } + ; + +limiter_opt: BLOCK { + $$ = PF_LIMITER_BLOCK; + } + | NOMATCH { + $$ = PF_LIMITER_NOMATCH; } ; @@ -3169,16 +3191,20 @@ pfrule : action dir logquick interface route af proto fromto filter_opts : { bzero(&filter_opts, sizeof filter_opts); - filter_opts.statelim = PF_STATELIM_ID_NONE; - filter_opts.sourcelim = PF_SOURCELIM_ID_NONE; + filter_opts.statelim.id = PF_STATELIM_ID_NONE; + filter_opts.statelim.limiter_action = PF_LIMITER_NOMATCH; + filter_opts.sourcelim.id = PF_SOURCELIM_ID_NONE; + filter_opts.sourcelim.limiter_action = PF_LIMITER_NOMATCH; filter_opts.rtableid = -1; } filter_opts_l { $$ = filter_opts; } | /* empty */ { bzero(&filter_opts, sizeof filter_opts); - filter_opts.statelim = PF_STATELIM_ID_NONE; - filter_opts.sourcelim = PF_SOURCELIM_ID_NONE; + filter_opts.statelim.id = PF_STATELIM_ID_NONE; + filter_opts.statelim.limiter_action = PF_LIMITER_NOMATCH; + filter_opts.sourcelim.id = PF_SOURCELIM_ID_NONE; + filter_opts.sourcelim.limiter_action = PF_LIMITER_NOMATCH; filter_opts.rtableid = -1; $$ = filter_opts; } @@ -3323,14 +3349,14 @@ filter_opt : USER uids { filter_opts.prob = 1; } | statelim_filter_opt { - if (filter_opts.statelim != PF_STATELIM_ID_NONE) { + if (filter_opts.statelim.id != PF_STATELIM_ID_NONE) { yyerror("state limiter already specified"); YYERROR; } filter_opts.statelim = $1; } | sourcelim_filter_opt { - if (filter_opts.sourcelim != PF_SOURCELIM_ID_NONE) { + if (filter_opts.sourcelim.id != PF_SOURCELIM_ID_NONE) { yyerror("source limiter already specified"); YYERROR; } @@ -7175,6 +7201,7 @@ lookup(char *s) { "nat-to", NATTO}, { "no", NO}, { "no-df", NODF}, + { "no-match", NOMATCH}, { "no-route", NOROUTE}, { "no-sync", NOSYNC}, { "on", ON}, @@ -8202,11 +8229,11 @@ filteropts_to_rule(struct pfctl_rule *r, struct filter_opts *opts) r->rule_flag |= PFRULE_ONCE; } - if (opts->statelim != PF_STATELIM_ID_NONE && r->action != PF_PASS) { + if (opts->statelim.id != PF_STATELIM_ID_NONE && r->action != PF_PASS) { yyerror("state limiter only applies to pass rules"); return (1); } - if (opts->sourcelim != PF_SOURCELIM_ID_NONE && r->action != PF_PASS) { + if (opts->sourcelim.id != PF_SOURCELIM_ID_NONE && r->action != PF_PASS) { yyerror("source limiter only applies to pass rules"); return (1); } @@ -8215,8 +8242,10 @@ filteropts_to_rule(struct pfctl_rule *r, struct filter_opts *opts) r->pktrate.limit = opts->pktrate.limit; r->pktrate.seconds = opts->pktrate.seconds; r->prob = opts->prob; - r->statelim = opts->statelim; - r->sourcelim = opts->sourcelim; + r->statelim.id = opts->statelim.id; + r->statelim.limiter_action = opts->statelim.limiter_action; + r->sourcelim.id = opts->sourcelim.id; + r->sourcelim.limiter_action = opts->sourcelim.limiter_action; r->rtableid = opts->rtableid; r->ridentifier = opts->ridentifier; r->max_pkt_size = opts->max_pkt_size; diff --git a/sbin/pfctl/pfctl_parser.c b/sbin/pfctl/pfctl_parser.c index f85c50652944..78a1034a3b43 100644 --- a/sbin/pfctl/pfctl_parser.c +++ b/sbin/pfctl/pfctl_parser.c @@ -1112,7 +1112,7 @@ print_rule(struct pfctl_rule *r, const char *anchor_call, int opts, int numeric) } printf(" probability %s%%", buf); } - if (r->statelim != PF_STATELIM_ID_NONE) { + if (r->statelim.id != PF_STATELIM_ID_NONE) { #if 0 /* XXX need pf to find statelims */ struct pfctl_statelim *stlim = pfctl_get_statelim_id(pf, r->statelim); @@ -1121,9 +1121,11 @@ print_rule(struct pfctl_rule *r, const char *anchor_call, int opts, int numeric) printf(" state limiter %s", stlim->ioc.name); else #endif - printf(" state limiter id %u", r->statelim); + printf(" state limiter id %u (%s)", r->statelim.id, + (r->statelim.limiter_action == PF_LIMITER_BLOCK) ? + "block" : "no-match"); } - if (r->sourcelim != PF_SOURCELIM_ID_NONE) { + if (r->sourcelim.id != PF_SOURCELIM_ID_NONE) { #if 0 /* XXX need pf to find sourcelims */ struct pfctl_sourcelim *srlim = pfctl_get_sourcelim_id(pf, r->sourcelim); @@ -1132,7 +1134,9 @@ print_rule(struct pfctl_rule *r, const char *anchor_call, int opts, int numeric) printf(" source limiter %s", srlim->ioc.name); else #endif - printf(" source limiter id %u", r->sourcelim); + printf(" source limiter id %u (%s)", r->sourcelim.id, + (r->sourcelim.limiter_action == PF_LIMITER_BLOCK) ? + "block" : "no-match"); } ropts = 0; diff --git a/sbin/pfctl/tests/files/pf1076.ok b/sbin/pfctl/tests/files/pf1076.ok index def9533b1e60..9f1a8c8fb5cf 100644 --- a/sbin/pfctl/tests/files/pf1076.ok +++ b/sbin/pfctl/tests/files/pf1076.ok @@ -1,2 +1,2 @@ state limiter dns-server id 1 limit 1000 rate 1/10 -pass in proto tcp from any to any port = domain flags S/SA keep state state limiter id 1 +pass in proto tcp from any to any port = domain flags S/SA keep state state limiter id 1 (no-match) diff --git a/sbin/pfctl/tests/files/pf1077.ok b/sbin/pfctl/tests/files/pf1077.ok index e52afb6bff9c..dc8882e1b87b 100644 --- a/sbin/pfctl/tests/files/pf1077.ok +++ b/sbin/pfctl/tests/files/pf1077.ok @@ -1,2 +1,2 @@ source limiter dns-server id 1 limit 2 states 3 rate 4/5 inet mask 16 -pass in proto tcp from any to any port = domain flags S/SA keep state source limiter id 1 +pass in proto tcp from any to any port = domain flags S/SA keep state source limiter id 1 (no-match) |
