1 /* $NetBSD: parse.y,v 1.11 2008/06/18 09:06:26 yamt Exp $ */
2 /* $OpenBSD: parse.y,v 1.519 2007/06/21 19:30:03 henning Exp $ */
5 * Copyright (c) 2001 Markus Friedl. All rights reserved.
6 * Copyright (c) 2001 Daniel Hartmeier. All rights reserved.
7 * Copyright (c) 2001 Theo de Raadt. All rights reserved.
8 * Copyright (c) 2002,2003 Henning Brauer. All rights reserved.
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
20 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
23 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
24 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 #include <sys/types.h>
32 #include <sys/socket.h>
34 #include <netinet/in.h>
35 #include <netinet/in_systm.h>
36 #include <netinet/ip.h>
37 #include <netinet/ip_icmp.h>
38 #include <netinet/icmp6.h>
39 #include <net/pfvar.h>
40 #include <arpa/inet.h>
41 #include <altq/altq.h>
42 #include <altq/altq_cbq.h>
43 #include <altq/altq_priq.h>
44 #include <altq/altq_hfsc.h>
60 #include "pfctl_parser.h"
63 #ifndef RT_TABLEID_MAX
64 #define RT_TABLEID_MAX 255
65 #endif /* !RT_TABLEID_MAX */
67 static struct pfctl
*pf
= NULL
;
68 static FILE *fin
= NULL
;
70 static int lineno
= 1;
71 static int errors
= 0;
72 static int rulestate
= 0;
73 static u_int16_t returnicmpdefault
=
74 (ICMP_UNREACH
<< 8) | ICMP_UNREACH_PORT
;
75 static u_int16_t returnicmp6default
=
76 (ICMP6_DST_UNREACH
<< 8) | ICMP6_DST_UNREACH_NOPORT
;
77 static int blockpolicy
= PFRULE_DROP
;
78 static int require_order
= 1;
79 static int default_statelock
;
92 struct node_proto
*next
;
93 struct node_proto
*tail
;
99 struct node_port
*next
;
100 struct node_port
*tail
;
106 struct node_uid
*next
;
107 struct node_uid
*tail
;
113 struct node_gid
*next
;
114 struct node_gid
*tail
;
121 struct node_icmp
*next
;
122 struct node_icmp
*tail
;
125 enum { PF_STATE_OPT_MAX
, PF_STATE_OPT_NOSYNC
, PF_STATE_OPT_SRCTRACK
,
126 PF_STATE_OPT_MAX_SRC_STATES
, PF_STATE_OPT_MAX_SRC_CONN
,
127 PF_STATE_OPT_MAX_SRC_CONN_RATE
, PF_STATE_OPT_MAX_SRC_NODES
,
128 PF_STATE_OPT_OVERLOAD
, PF_STATE_OPT_STATELOCK
,
129 PF_STATE_OPT_TIMEOUT
};
131 enum { PF_SRCTRACK_NONE
, PF_SRCTRACK
, PF_SRCTRACK_GLOBAL
, PF_SRCTRACK_RULE
};
133 struct node_state_opt
{
136 u_int32_t max_states
;
137 u_int32_t max_src_states
;
138 u_int32_t max_src_conn
;
145 char tblname
[PF_TABLE_NAME_SIZE
];
147 u_int32_t max_src_nodes
;
155 struct node_state_opt
*next
;
156 struct node_state_opt
*tail
;
160 struct node_host
*host
;
161 struct node_port
*port
;
165 char queue
[PF_QNAME_SIZE
];
166 char parent
[PF_QNAME_SIZE
];
167 char ifname
[IFNAMSIZ
];
169 struct node_queue
*next
;
170 struct node_queue
*tail
;
173 struct node_qassign
{
180 #define FOM_FLAGS 0x01
181 #define FOM_ICMP 0x02
183 #define FOM_KEEP 0x08
184 #define FOM_SRCTRACK 0x10
185 struct node_uid
*uid
;
186 struct node_gid
*gid
;
193 struct node_icmp
*icmpspec
;
198 struct node_state_opt
*options
;
203 struct node_qassign queues
;
206 u_int8_t match_tag_not
;
210 struct antispoof_opts
{
217 #define SOM_MINTTL 0x01
218 #define SOM_MAXMSS 0x02
219 #define SOM_FRAGCACHE 0x04
231 #define QOM_BWSPEC 0x01
232 #define QOM_SCHEDULER 0x02
233 #define QOM_PRIORITY 0x04
234 #define QOM_TBRSIZE 0x08
235 #define QOM_QLIMIT 0x10
236 struct node_queue_bw queue_bwspec
;
237 struct node_queue_opt scheduler
;
246 struct node_tinithead init_nodes
;
251 #define POM_TYPE 0x01
252 #define POM_STICKYADDRESS 0x02
256 struct pf_poolhashkey
*key
;
261 struct node_hfsc_opts hfsc_opts
;
263 int yyerror(const char *, ...
);
264 int disallow_table
(struct node_host
*, const char *);
265 int disallow_urpf_failed
(struct node_host
*, const char *);
266 int disallow_alias
(struct node_host
*, const char *);
267 int rule_consistent
(struct pf_rule
*, int);
268 int filter_consistent
(struct pf_rule
*, int);
269 int nat_consistent
(struct pf_rule
*);
270 int rdr_consistent
(struct pf_rule
*);
271 int process_tabledef
(char *, struct table_opts
*);
273 void expand_label_str
(char *, size_t, const char *, const char *);
274 void expand_label_if
(const char *, char *, size_t, const char *);
275 void expand_label_addr
(const char *, char *, size_t, u_int8_t
,
277 void expand_label_port
(const char *, char *, size_t, struct node_port
*);
278 void expand_label_proto
(const char *, char *, size_t, u_int8_t
);
279 void expand_label_nr
(const char *, char *, size_t);
280 void expand_label
(char *, size_t, const char *, u_int8_t
, struct node_host
*,
281 struct node_port
*, struct node_host
*, struct node_port
*,
283 void expand_rule
(struct pf_rule
*, struct node_if
*, struct node_host
*,
284 struct node_proto
*, struct node_os
*, struct node_host
*,
285 struct node_port
*, struct node_host
*, struct node_port
*,
286 struct node_uid
*, struct node_gid
*, struct node_icmp
*,
288 int expand_altq
(struct pf_altq
*, struct node_if
*, struct node_queue
*,
289 struct node_queue_bw bwspec
, struct node_queue_opt
*);
290 int expand_queue
(struct pf_altq
*, struct node_if
*, struct node_queue
*,
291 struct node_queue_bw
, struct node_queue_opt
*);
292 int expand_skip_interface
(struct node_if
*);
294 int check_rulestate
(int);
295 int kw_cmp
(const void *, const void *);
301 int atoul
(char *, u_long
*);
302 int getservice
(char *);
303 int rule_label
(struct pf_rule
*, char *);
305 TAILQ_HEAD
(symhead
, sym
) symhead
= TAILQ_HEAD_INITIALIZER
(symhead
);
307 TAILQ_ENTRY
(sym
) entries
;
315 int symset
(const char *, const char *, int);
316 char *symget
(const char *);
318 void mv_rules
(struct pf_ruleset
*, struct pf_ruleset
*);
319 void decide_address_family
(struct node_host
*, sa_family_t
*);
320 void remove_invalid_hosts
(struct node_host
**, sa_family_t
*);
321 int invalid_redirect
(struct node_host
*, sa_family_t
);
322 u_int16_t parseicmpspec
(char *, sa_family_t
);
324 TAILQ_HEAD
(loadanchorshead
, loadanchors
)
325 loadanchorshead
= TAILQ_HEAD_INITIALIZER
(loadanchorshead
);
328 TAILQ_ENTRY
(loadanchors
) entries
;
350 struct node_if
*interface
;
351 struct node_proto
*proto
;
352 struct node_icmp
*icmp
;
353 struct node_host
*host
;
355 struct node_port
*port
;
356 struct node_uid
*uid
;
357 struct node_gid
*gid
;
358 struct node_state_opt
*state_opt
;
361 struct peer src
, dst
;
362 struct node_os
*src_os
;
365 struct node_host
*host
;
369 struct pf_poolhashkey
*key
;
372 struct node_host
*host
;
377 struct node_state_opt
*options
;
388 struct pf_poolhashkey
*hashkey
;
389 struct node_queue
*queue
;
390 struct node_queue_opt queue_options
;
391 struct node_queue_bw queue_bwspec
;
392 struct node_qassign qassign
;
393 struct filter_opts filter_opts
;
394 struct antispoof_opts antispoof_opts
;
395 struct queue_opts queue_opts
;
396 struct scrub_opts scrub_opts
;
397 struct table_opts table_opts
;
398 struct pool_opts pool_opts
;
399 struct node_hfsc_opts hfsc_opts
;
404 #define DYNIF_MULTIADDR(addr) ((addr).type == PF_ADDR_DYNIFTL && \
405 (!((addr
).iflags
& PFI_AFLAG_NOALIAS
) || \
406 !isdigit
((unsigned char)(addr
).v.ifname
[strlen
((addr
).v.ifname
)-1])))
410 %token PASS BLOCK SCRUB RETURN IN OS OUT LOG QUICK ON FROM TO FLAGS
411 %token RETURNRST RETURNICMP RETURNICMP6 PROTO INET INET6 ALL ANY ICMPTYPE
412 %token ICMP6TYPE CODE KEEP MODULATE STATE PORT RDR NAT BINAT ARROW NODF
413 %token MINTTL ERROR ALLOWOPTS FASTROUTE FILENAME ROUTETO DUPTO REPLYTO NO LABEL
414 %token NOROUTE URPFFAILED FRAGMENT USER GROUP MAXMSS MAXIMUM TTL TOS DROP TABLE
415 %token REASSEMBLE FRAGDROP FRAGCROP ANCHOR NATANCHOR RDRANCHOR BINATANCHOR
416 %token SET OPTIMIZATION TIMEOUT LIMIT LOGINTERFACE BLOCKPOLICY RANDOMID
417 %token REQUIREORDER SYNPROXY FINGERPRINTS NOSYNC DEBUG SKIP HOSTID
419 %token BITMASK RANDOM SOURCEHASH ROUNDROBIN STATICPORT PROBABILITY
420 %token ALTQ CBQ PRIQ HFSC BANDWIDTH TBRSIZE LINKSHARE REALTIME UPPERLIMIT
421 %token QUEUE PRIORITY QLIMIT RTABLE
422 %token LOAD RULESET_OPTIMIZATION
423 %token STICKYADDRESS MAXSRCSTATES MAXSRCNODES SOURCETRACK GLOBAL RULE
424 %token MAXSRCCONN MAXSRCCONNRATE OVERLOAD FLUSH
425 %token TAGGED TAG IFBOUND FLOATING STATEPOLICY ROUTE
426 %token
<v.
string> STRING
427 %token
<v.i
> PORTBINARY
428 %type
<v.interface
> interface if_list if_item_not if_item
429 %type
<v.number
> number icmptype icmp6type uid gid
430 %type
<v.number
> tos not yesno
431 %type
<v.i
> no dir af fragcache optimizer
432 %type
<v.i
> sourcetrack flush unaryop statelock
433 %type
<v.b
> action nataction natpasslog scrubaction
434 %type
<v.b
> flags flag blockspec
435 %type
<v.range
> port rport
436 %type
<v.hashkey
> hashkey
437 %type
<v.proto
> proto proto_list proto_item
438 %type
<v.icmp
> icmpspec
439 %type
<v.icmp
> icmp_list icmp_item
440 %type
<v.icmp
> icmp6_list icmp6_item
441 %type
<v.fromto
> fromto
442 %type
<v.peer
> ipportspec from to
443 %type
<v.host
> ipspec xhost host dynaddr host_list
444 %type
<v.host
> redir_host_list redirspec
445 %type
<v.host
> route_host route_host_list routespec
446 %type
<v.os
> os xos os_list
447 %type
<v.port
> portspec port_list port_item
448 %type
<v.uid
> uids uid_list uid_item
449 %type
<v.gid
> gids gid_list gid_item
450 %type
<v.route
> route
451 %type
<v.redirection
> redirection redirpool
452 %type
<v.
string> label
string tag anchorname
453 %type
<v.keep_state
> keep
454 %type
<v.state_opt
> state_opt_spec state_opt_list state_opt_item
455 %type
<v.state_opt
> opt_statelock
456 %type
<v.logquick
> logquick quick log logopts logopt
457 %type
<v.interface
> antispoof_ifspc antispoof_iflst antispoof_if
458 %type
<v.qassign
> qname
459 %type
<v.queue
> qassign qassign_list qassign_item
460 %type
<v.queue_options
> scheduler
461 %type
<v.number
> cbqflags_list cbqflags_item
462 %type
<v.number
> priqflags_list priqflags_item
463 %type
<v.hfsc_opts
> hfscopts_list hfscopts_item hfsc_opts
464 %type
<v.queue_bwspec
> bandwidth
465 %type
<v.filter_opts
> filter_opts filter_opt filter_opts_l
466 %type
<v.antispoof_opts
> antispoof_opts antispoof_opt antispoof_opts_l
467 %type
<v.queue_opts
> queue_opts queue_opt queue_opts_l
468 %type
<v.scrub_opts
> scrub_opts scrub_opt scrub_opts_l
469 %type
<v.table_opts
> table_opts table_opt table_opts_l
470 %type
<v.pool_opts
> pool_opts pool_opt pool_opts_l
471 %type
<v.tagged
> tagged
472 %type
<v.rtableid
> rtable
475 ruleset
: /* empty */
477 | ruleset option
'\n'
478 | ruleset scrubrule
'\n'
479 | ruleset natrule
'\n'
480 | ruleset binatrule
'\n'
481 | ruleset pfrule
'\n'
482 | ruleset anchorrule
'\n'
483 | ruleset loadrule
'\n'
484 | ruleset altqif
'\n'
485 | ruleset queuespec
'\n'
486 | ruleset varset
'\n'
487 | ruleset antispoof
'\n'
488 | ruleset tabledef
'\n'
489 |
'{' fakeanchor
'}' '\n';
490 | ruleset
error '\n' { errors
++; }
494 * apply to previouslys specified rule: must be careful to note
495 * what that is: pf or nat or binat or rdr
497 fakeanchor
: fakeanchor
'\n'
498 | fakeanchor anchorrule
'\n'
499 | fakeanchor binatrule
'\n'
500 | fakeanchor natrule
'\n'
501 | fakeanchor pfrule
'\n'
502 | fakeanchor
error '\n'
506 if
(!strcmp
($1, "none"))
508 else if
(!strcmp
($1, "basic"))
509 $$
= PF_OPTIMIZE_BASIC
;
510 else if
(!strcmp
($1, "profile"))
511 $$
= PF_OPTIMIZE_BASIC | PF_OPTIMIZE_PROFILE
;
513 yyerror("unknown ruleset-optimization %s", $$
);
519 option
: SET OPTIMIZATION STRING
{
520 if
(check_rulestate
(PFCTL_STATE_OPTION
)) {
524 if
(pfctl_set_optimization
(pf
, $3) != 0) {
525 yyerror("unknown optimization %s", $3);
531 | SET RULESET_OPTIMIZATION optimizer
{
532 if
(!(pf
->opts
& PF_OPT_OPTIMIZE
)) {
533 pf
->opts |
= PF_OPT_OPTIMIZE
;
537 | SET TIMEOUT timeout_spec
538 | SET TIMEOUT
'{' timeout_list
'}'
539 | SET LIMIT limit_spec
540 | SET LIMIT
'{' limit_list
'}'
541 | SET LOGINTERFACE STRING
{
542 if
(check_rulestate
(PFCTL_STATE_OPTION
)) {
546 if
(pfctl_set_logif
(pf
, $3) != 0) {
547 yyerror("error setting loginterface %s", $3);
553 | SET HOSTID number
{
555 yyerror("hostid must be non-zero");
558 if
(pfctl_set_hostid
(pf
, $3) != 0) {
559 yyerror("error setting hostid %08x", $3);
563 | SET BLOCKPOLICY DROP
{
564 if
(pf
->opts
& PF_OPT_VERBOSE
)
565 printf
("set block-policy drop\n");
566 if
(check_rulestate
(PFCTL_STATE_OPTION
))
568 blockpolicy
= PFRULE_DROP
;
570 | SET BLOCKPOLICY RETURN
{
571 if
(pf
->opts
& PF_OPT_VERBOSE
)
572 printf
("set block-policy return\n");
573 if
(check_rulestate
(PFCTL_STATE_OPTION
))
575 blockpolicy
= PFRULE_RETURN
;
577 | SET REQUIREORDER yesno
{
578 if
(pf
->opts
& PF_OPT_VERBOSE
)
579 printf
("set require-order %s\n",
580 $3 == 1 ?
"yes" : "no");
583 | SET FINGERPRINTS STRING
{
584 if
(pf
->opts
& PF_OPT_VERBOSE
)
585 printf
("set fingerprints \"%s\"\n", $3);
586 if
(check_rulestate
(PFCTL_STATE_OPTION
)) {
590 if
(!pf
->anchor
->name
[0]) {
591 if
(pfctl_file_fingerprints
(pf
->dev
,
593 yyerror("error loading "
594 "fingerprints %s", $3);
601 | SET STATEPOLICY statelock
{
602 if
(pf
->opts
& PF_OPT_VERBOSE
)
605 printf
("set state-policy floating\n");
608 printf
("set state-policy if-bound\n");
611 default_statelock
= $3;
614 if
(check_rulestate
(PFCTL_STATE_OPTION
)) {
618 if
(pfctl_set_debug
(pf
, $3) != 0) {
619 yyerror("error setting debuglevel %s", $3);
625 | SET SKIP interface
{
626 if
(expand_skip_interface
($3) != 0) {
627 yyerror("error setting skip interface(s)");
633 string : string STRING
{
634 if
(asprintf
(&$$
, "%s %s", $1, $2) == -1)
635 err
(1, "string: asprintf");
642 varset
: STRING
'=' string {
643 if
(pf
->opts
& PF_OPT_VERBOSE
)
644 printf
("%s = \"%s\"\n", $1, $3);
645 if
(symset
($1, $3, 0) == -1)
646 err
(1, "cannot store variable %s", $1);
652 anchorname
: STRING
{ $$
= $1; }
653 |
/* empty */ { $$
= NULL
; }
660 pfa_anchorlist
: pfrule optnl
662 | pfa_anchorlist pfrule optnl
663 | pfa_anchorlist anchorrule optnl
668 char ta
[PF_ANCHOR_NAME_SIZE
];
669 struct pf_ruleset
*rs
;
671 /* steping into a brace anchor */
676 /* create a holding ruleset in the root */
677 snprintf
(ta
, PF_ANCHOR_NAME_SIZE
, "_%d", pf
->bn
);
678 rs
= pf_find_or_create_ruleset
(ta
);
680 err
(1, "pfa_anchor: pf_find_or_create_ruleset");
681 pf
->astack
[pf
->asd
] = rs
->anchor
;
682 pf
->anchor
= rs
->anchor
;
683 } '\n' pfa_anchorlist
'}'
685 pf
->alast
= pf
->anchor
;
687 pf
->anchor
= pf
->astack
[pf
->asd
];
692 anchorrule
: ANCHOR anchorname dir quick interface af proto fromto
693 filter_opts pfa_anchor
697 if
(check_rulestate
(PFCTL_STATE_FILTER
)) {
703 if
($2 && ($2[0] == '_' || strstr
($2, "/_") != NULL
)) {
705 yyerror("anchor names beginning with '_' "
706 "are reserved for internal use");
710 memset
(&r
, 0, sizeof
(r
));
711 if
(pf
->astack
[pf
->asd
+ 1]) {
712 /* move inline rules into relative location */
714 &pf
->astack
[pf
->asd
]->ruleset
,
715 $2 ?
$2 : pf
->alast
->name
);
717 if
(r.anchor
== NULL
)
718 err
(1, "anchorrule: unable to "
721 if
(pf
->alast
!= r.anchor
) {
722 if
(r.anchor
->match
) {
723 yyerror("inline anchor '%s' "
728 mv_rules
(&pf
->alast
->ruleset
,
731 pf_remove_if_empty_ruleset
(&pf
->alast
->ruleset
);
732 pf
->alast
= r.anchor
;
735 yyerror("anchors without explicit "
736 "rules must specify a name");
744 r.rtableid
= $9.rtableid
;
747 if
(strlcpy
(r.match_tagname
, $9.match_tag
,
748 PF_TAG_NAME_SIZE
) >= PF_TAG_NAME_SIZE
) {
749 yyerror("tag too long, max %u chars",
750 PF_TAG_NAME_SIZE
- 1);
753 r.match_tag_not
= $9.match_tag_not
;
755 decide_address_family
($8.src.host
, &r.af
);
756 decide_address_family
($8.dst.host
, &r.af
);
758 expand_rule
(&r
, $5, NULL
, $7, $8.src_os
,
759 $8.src.host
, $8.src.port
, $8.dst.host
, $8.dst.port
,
760 0, 0, 0, pf
->astack
[pf
->asd
+ 1] ?
761 pf
->alast
->name
: $2);
763 pf
->astack
[pf
->asd
+ 1] = NULL
;
765 | NATANCHOR
string interface af proto fromto rtable
{
768 if
(check_rulestate
(PFCTL_STATE_NAT
)) {
773 memset
(&r
, 0, sizeof
(r
));
778 decide_address_family
($6.src.host
, &r.af
);
779 decide_address_family
($6.dst.host
, &r.af
);
781 expand_rule
(&r
, $3, NULL
, $5, $6.src_os
,
782 $6.src.host
, $6.src.port
, $6.dst.host
, $6.dst.port
,
786 | RDRANCHOR
string interface af proto fromto rtable
{
789 if
(check_rulestate
(PFCTL_STATE_NAT
)) {
794 memset
(&r
, 0, sizeof
(r
));
799 decide_address_family
($6.src.host
, &r.af
);
800 decide_address_family
($6.dst.host
, &r.af
);
802 if
($6.src.port
!= NULL
) {
803 yyerror("source port parameter not supported"
807 if
($6.dst.port
!= NULL
) {
808 if
($6.dst.port
->next
!= NULL
) {
809 yyerror("destination port list "
810 "expansion not supported in "
813 } else if
($6.dst.port
->op
!= PF_OP_EQ
) {
814 yyerror("destination port operators"
815 " not supported in rdr-anchor");
818 r.dst.port
[0] = $6.dst.port
->port
[0];
819 r.dst.port
[1] = $6.dst.port
->port
[1];
820 r.dst.port_op
= $6.dst.port
->op
;
823 expand_rule
(&r
, $3, NULL
, $5, $6.src_os
,
824 $6.src.host
, $6.src.port
, $6.dst.host
, $6.dst.port
,
828 | BINATANCHOR
string interface af proto fromto rtable
{
831 if
(check_rulestate
(PFCTL_STATE_NAT
)) {
836 memset
(&r
, 0, sizeof
(r
));
841 if
($5->next
!= NULL
) {
842 yyerror("proto list expansion"
843 " not supported in binat-anchor");
850 if
($6.src.host
!= NULL ||
$6.src.port
!= NULL ||
851 $6.dst.host
!= NULL ||
$6.dst.port
!= NULL
) {
852 yyerror("fromto parameter not supported"
857 decide_address_family
($6.src.host
, &r.af
);
858 decide_address_family
($6.dst.host
, &r.af
);
860 pfctl_add_rule
(pf
, &r
, $2);
865 loadrule
: LOAD ANCHOR
string FROM
string {
866 struct loadanchors
*loadanchor
;
868 if
(strlen
(pf
->anchor
->name
) + 1 +
869 strlen
($3) >= MAXPATHLEN
) {
870 yyerror("anchorname %s too long, max %u\n",
875 loadanchor
= calloc
(1, sizeof
(struct loadanchors
));
876 if
(loadanchor
== NULL
)
877 err
(1, "loadrule: calloc");
878 if
((loadanchor
->anchorname
= malloc
(MAXPATHLEN
)) ==
880 err
(1, "loadrule: malloc");
881 if
(pf
->anchor
->name
[0])
882 snprintf
(loadanchor
->anchorname
, MAXPATHLEN
,
883 "%s/%s", pf
->anchor
->name
, $3);
885 strlcpy
(loadanchor
->anchorname
, $3, MAXPATHLEN
);
886 if
((loadanchor
->filename
= strdup
($5)) == NULL
)
887 err
(1, "loadrule: strdup");
889 TAILQ_INSERT_TAIL
(&loadanchorshead
, loadanchor
,
896 scrubaction
: no SCRUB
{
905 scrubrule
: scrubaction dir logquick interface af proto fromto scrub_opts
909 if
(check_rulestate
(PFCTL_STATE_SCRUB
))
912 memset
(&r
, 0, sizeof
(r
));
920 yyerror("scrub rules do not support 'quick'");
926 r.rule_flag |
= PFRULE_NODF
;
928 r.rule_flag |
= PFRULE_RANDOMID
;
929 if
($8.reassemble_tcp
) {
930 if
(r.direction
!= PF_INOUT
) {
931 yyerror("reassemble tcp rules can not "
932 "specify direction");
935 r.rule_flag |
= PFRULE_REASSEMBLE_TCP
;
938 r.min_ttl
= $8.minttl
;
940 r.max_mss
= $8.maxmss
;
942 r.rule_flag |
= $8.fragcache
;
943 r.rtableid
= $8.rtableid
;
945 expand_rule
(&r
, $4, NULL
, $6, $7.src_os
,
946 $7.src.host
, $7.src.port
, $7.dst.host
, $7.dst.port
,
947 NULL
, NULL
, NULL
, "");
952 bzero
(&scrub_opts
, sizeof scrub_opts
);
953 scrub_opts.rtableid
= -1;
958 bzero
(&scrub_opts
, sizeof scrub_opts
);
959 scrub_opts.rtableid
= -1;
964 scrub_opts_l
: scrub_opts_l scrub_opt
969 if
(scrub_opts.nodf
) {
970 yyerror("no-df cannot be respecified");
976 if
(scrub_opts.marker
& SOM_MINTTL
) {
977 yyerror("min-ttl cannot be respecified");
981 yyerror("illegal min-ttl value %d", $2);
984 scrub_opts.marker |
= SOM_MINTTL
;
985 scrub_opts.minttl
= $2;
988 if
(scrub_opts.marker
& SOM_MAXMSS
) {
989 yyerror("max-mss cannot be respecified");
993 yyerror("illegal max-mss value %d", $2);
996 scrub_opts.marker |
= SOM_MAXMSS
;
997 scrub_opts.maxmss
= $2;
1000 if
(scrub_opts.marker
& SOM_FRAGCACHE
) {
1001 yyerror("fragcache cannot be respecified");
1004 scrub_opts.marker |
= SOM_FRAGCACHE
;
1005 scrub_opts.fragcache
= $1;
1007 | REASSEMBLE STRING
{
1008 if
(strcasecmp
($2, "tcp") != 0) {
1009 yyerror("scrub reassemble supports only tcp, "
1015 if
(scrub_opts.reassemble_tcp
) {
1016 yyerror("reassemble tcp cannot be respecified");
1019 scrub_opts.reassemble_tcp
= 1;
1022 if
(scrub_opts.randomid
) {
1023 yyerror("random-id cannot be respecified");
1026 scrub_opts.randomid
= 1;
1029 if
($2 > RT_TABLEID_MAX ||
$2 < 0) {
1030 yyerror("invalid rtable id");
1033 scrub_opts.rtableid
= $2;
1037 fragcache
: FRAGMENT REASSEMBLE
{ $$
= 0; /* default */ }
1038 | FRAGMENT FRAGCROP
{ $$
= PFRULE_FRAGCROP
; }
1039 | FRAGMENT FRAGDROP
{ $$
= PFRULE_FRAGDROP
; }
1042 antispoof
: ANTISPOOF logquick antispoof_ifspc af antispoof_opts
{
1044 struct node_host
*h
= NULL
, *hh
;
1045 struct node_if
*i
, *j
;
1047 if
(check_rulestate
(PFCTL_STATE_FILTER
))
1050 for
(i
= $3; i
; i
= i
->next
) {
1051 bzero
(&r
, sizeof
(r
));
1054 r.direction
= PF_IN
;
1059 if
(rule_label
(&r
, $5.label
))
1061 r.rtableid
= $5.rtableid
;
1062 j
= calloc
(1, sizeof
(struct node_if
));
1064 err
(1, "antispoof: calloc");
1065 if
(strlcpy
(j
->ifname
, i
->ifname
,
1066 sizeof
(j
->ifname
)) >= sizeof
(j
->ifname
)) {
1068 yyerror("interface name too long");
1073 h
= calloc
(1, sizeof
(*h
));
1075 err
(1, "address: calloc");
1076 h
->addr.type
= PF_ADDR_DYNIFTL
;
1078 if
(strlcpy
(h
->addr.v.ifname
, i
->ifname
,
1079 sizeof
(h
->addr.v.ifname
)) >=
1080 sizeof
(h
->addr.v.ifname
)) {
1083 "interface name too long");
1086 hh
= malloc
(sizeof
(*hh
));
1088 err
(1, "address: malloc");
1089 bcopy
(h
, hh
, sizeof
(*hh
));
1090 h
->addr.iflags
= PFI_AFLAG_NETWORK
;
1092 h
= ifa_lookup
(j
->ifname
,
1098 expand_rule
(&r
, j
, NULL
, NULL
, NULL
, h
,
1099 NULL
, NULL
, NULL
, NULL
, NULL
,
1102 if
((i
->ifa_flags
& IFF_LOOPBACK
) == 0) {
1103 bzero
(&r
, sizeof
(r
));
1106 r.direction
= PF_IN
;
1110 if
(rule_label
(&r
, $5.label
))
1112 r.rtableid
= $5.rtableid
;
1116 h
= ifa_lookup
(i
->ifname
, 0);
1118 expand_rule
(&r
, NULL
, NULL
,
1119 NULL
, NULL
, h
, NULL
, NULL
,
1120 NULL
, NULL
, NULL
, NULL
, "");
1128 antispoof_ifspc
: FOR antispoof_if
{ $$
= $2; }
1129 | FOR
'{' antispoof_iflst
'}' { $$
= $3; }
1132 antispoof_iflst
: antispoof_if
{ $$
= $1; }
1133 | antispoof_iflst comma antispoof_if
{
1134 $1->tail
->next
= $3;
1140 antispoof_if
: if_item
{ $$
= $1; }
1148 bzero
(&antispoof_opts
, sizeof antispoof_opts
);
1149 antispoof_opts.rtableid
= -1;
1152 { $$
= antispoof_opts
; }
1154 bzero
(&antispoof_opts
, sizeof antispoof_opts
);
1155 antispoof_opts.rtableid
= -1;
1156 $$
= antispoof_opts
;
1160 antispoof_opts_l
: antispoof_opts_l antispoof_opt
1164 antispoof_opt
: label
{
1165 if
(antispoof_opts.label
) {
1166 yyerror("label cannot be redefined");
1169 antispoof_opts.label
= $1;
1172 if
($2 > RT_TABLEID_MAX ||
$2 < 0) {
1173 yyerror("invalid rtable id");
1176 antispoof_opts.rtableid
= $2;
1180 not
: '!' { $$
= 1; }
1181 |
/* empty */ { $$
= 0; }
1184 tabledef
: TABLE
'<' STRING
'>' table_opts
{
1185 struct node_host
*h
, *nh
;
1186 struct node_tinit
*ti
, *nti
;
1188 if
(strlen
($3) >= PF_TABLE_NAME_SIZE
) {
1189 yyerror("table name too long, max %d chars",
1190 PF_TABLE_NAME_SIZE
- 1);
1194 if
(pf
->loadopt
& PFCTL_FLAG_TABLE
)
1195 if
(process_tabledef
($3, &$5)) {
1200 for
(ti
= SIMPLEQ_FIRST
(&$5.init_nodes
);
1201 ti
!= NULL
; ti
= nti
) {
1204 for
(h
= ti
->host
; h
!= NULL
; h
= nh
) {
1208 nti
= SIMPLEQ_NEXT
(ti
, entries
);
1215 bzero
(&table_opts
, sizeof table_opts
);
1216 SIMPLEQ_INIT
(&table_opts.init_nodes
);
1219 { $$
= table_opts
; }
1222 bzero
(&table_opts
, sizeof table_opts
);
1223 SIMPLEQ_INIT
(&table_opts.init_nodes
);
1228 table_opts_l
: table_opts_l table_opt
1232 table_opt
: STRING
{
1233 if
(!strcmp
($1, "const"))
1234 table_opts.flags |
= PFR_TFLAG_CONST
;
1235 else if
(!strcmp
($1, "persist"))
1236 table_opts.flags |
= PFR_TFLAG_PERSIST
;
1238 yyerror("invalid table option '%s'", $1);
1244 |
'{' '}' { table_opts.init_addr
= 1; }
1245 |
'{' host_list
'}' {
1246 struct node_host
*n
;
1247 struct node_tinit
*ti
;
1249 for
(n
= $2; n
!= NULL
; n
= n
->next
) {
1250 switch
(n
->addr.type
) {
1251 case PF_ADDR_ADDRMASK
:
1253 case PF_ADDR_DYNIFTL
:
1254 yyerror("dynamic addresses are not "
1255 "permitted inside tables");
1258 yyerror("tables cannot contain tables");
1260 case PF_ADDR_NOROUTE
:
1261 yyerror("\"no-route\" is not permitted "
1264 case PF_ADDR_URPFFAILED
:
1265 yyerror("\"urpf-failed\" is not "
1266 "permitted inside tables");
1269 yyerror("unknown address type %d",
1274 if
(!(ti
= calloc
(1, sizeof
(*ti
))))
1275 err
(1, "table_opt: calloc");
1277 SIMPLEQ_INSERT_TAIL
(&table_opts.init_nodes
, ti
,
1279 table_opts.init_addr
= 1;
1282 struct node_tinit
*ti
;
1284 if
(!(ti
= calloc
(1, sizeof
(*ti
))))
1285 err
(1, "table_opt: calloc");
1287 SIMPLEQ_INSERT_TAIL
(&table_opts.init_nodes
, ti
,
1289 table_opts.init_addr
= 1;
1293 altqif
: ALTQ interface queue_opts QUEUE qassign
{
1296 if
(check_rulestate
(PFCTL_STATE_QUEUE
))
1299 memset
(&a
, 0, sizeof
(a
));
1300 if
($3.scheduler.qtype
== ALTQT_NONE
) {
1301 yyerror("no scheduler specified!");
1304 a.scheduler
= $3.scheduler.qtype
;
1305 a.qlimit
= $3.qlimit
;
1306 a.tbrsize
= $3.tbrsize
;
1308 yyerror("no child queues specified");
1311 if
(expand_altq
(&a
, $2, $5, $3.queue_bwspec
,
1317 queuespec
: QUEUE STRING interface queue_opts qassign
{
1320 if
(check_rulestate
(PFCTL_STATE_QUEUE
)) {
1325 memset
(&a
, 0, sizeof
(a
));
1327 if
(strlcpy
(a.qname
, $2, sizeof
(a.qname
)) >=
1329 yyerror("queue name too long (max "
1330 "%d chars)", PF_QNAME_SIZE
-1);
1336 yyerror("cannot specify tbrsize for queue");
1339 if
($4.priority
> 255) {
1340 yyerror("priority out of range: max 255");
1343 a.priority
= $4.priority
;
1344 a.qlimit
= $4.qlimit
;
1345 a.scheduler
= $4.scheduler.qtype
;
1346 if
(expand_queue
(&a
, $3, $5, $4.queue_bwspec
,
1348 yyerror("errors in queue definition");
1355 bzero
(&queue_opts
, sizeof queue_opts
);
1356 queue_opts.priority
= DEFAULT_PRIORITY
;
1357 queue_opts.qlimit
= DEFAULT_QLIMIT
;
1358 queue_opts.scheduler.qtype
= ALTQT_NONE
;
1359 queue_opts.queue_bwspec.bw_percent
= 100;
1362 { $$
= queue_opts
; }
1364 bzero
(&queue_opts
, sizeof queue_opts
);
1365 queue_opts.priority
= DEFAULT_PRIORITY
;
1366 queue_opts.qlimit
= DEFAULT_QLIMIT
;
1367 queue_opts.scheduler.qtype
= ALTQT_NONE
;
1368 queue_opts.queue_bwspec.bw_percent
= 100;
1373 queue_opts_l
: queue_opts_l queue_opt
1377 queue_opt
: BANDWIDTH bandwidth
{
1378 if
(queue_opts.marker
& QOM_BWSPEC
) {
1379 yyerror("bandwidth cannot be respecified");
1382 queue_opts.marker |
= QOM_BWSPEC
;
1383 queue_opts.queue_bwspec
= $2;
1386 if
(queue_opts.marker
& QOM_PRIORITY
) {
1387 yyerror("priority cannot be respecified");
1391 yyerror("priority out of range: max 255");
1394 queue_opts.marker |
= QOM_PRIORITY
;
1395 queue_opts.priority
= $2;
1398 if
(queue_opts.marker
& QOM_QLIMIT
) {
1399 yyerror("qlimit cannot be respecified");
1403 yyerror("qlimit out of range: max 65535");
1406 queue_opts.marker |
= QOM_QLIMIT
;
1407 queue_opts.qlimit
= $2;
1410 if
(queue_opts.marker
& QOM_SCHEDULER
) {
1411 yyerror("scheduler cannot be respecified");
1414 queue_opts.marker |
= QOM_SCHEDULER
;
1415 queue_opts.scheduler
= $1;
1418 if
(queue_opts.marker
& QOM_TBRSIZE
) {
1419 yyerror("tbrsize cannot be respecified");
1423 yyerror("tbrsize too big: max 65535");
1426 queue_opts.marker |
= QOM_TBRSIZE
;
1427 queue_opts.tbrsize
= $2;
1431 bandwidth
: STRING
{
1437 bps
= strtod
($1, &cp
);
1439 if
(!strcmp
(cp
, "b"))
1441 else if
(!strcmp
(cp
, "Kb"))
1443 else if
(!strcmp
(cp
, "Mb"))
1445 else if
(!strcmp
(cp
, "Gb"))
1446 bps
*= 1000 * 1000 * 1000;
1447 else if
(!strcmp
(cp
, "%")) {
1448 if
(bps
< 0 || bps
> 100) {
1449 yyerror("bandwidth spec "
1454 $$.bw_percent
= bps
;
1457 yyerror("unknown unit %s", cp
);
1463 $$.bw_absolute
= (u_int32_t
)bps
;
1468 $$.qtype
= ALTQT_CBQ
;
1469 $$.data.cbq_opts.flags
= 0;
1471 | CBQ
'(' cbqflags_list
')' {
1472 $$.qtype
= ALTQT_CBQ
;
1473 $$.data.cbq_opts.flags
= $3;
1476 $$.qtype
= ALTQT_PRIQ
;
1477 $$.data.priq_opts.flags
= 0;
1479 | PRIQ
'(' priqflags_list
')' {
1480 $$.qtype
= ALTQT_PRIQ
;
1481 $$.data.priq_opts.flags
= $3;
1484 $$.qtype
= ALTQT_HFSC
;
1485 bzero
(&$$.data.hfsc_opts
,
1486 sizeof
(struct node_hfsc_opts
));
1488 | HFSC
'(' hfsc_opts
')' {
1489 $$.qtype
= ALTQT_HFSC
;
1490 $$.data.hfsc_opts
= $3;
1494 cbqflags_list
: cbqflags_item
{ $$ |
= $1; }
1495 | cbqflags_list comma cbqflags_item
{ $$ |
= $3; }
1498 cbqflags_item
: STRING
{
1499 if
(!strcmp
($1, "default"))
1500 $$
= CBQCLF_DEFCLASS
;
1501 #ifdef CBQCLF_BORROW
1502 else if
(!strcmp
($1, "borrow"))
1505 else if
(!strcmp
($1, "red"))
1507 else if
(!strcmp
($1, "ecn"))
1508 $$
= CBQCLF_RED|CBQCLF_ECN
;
1509 else if
(!strcmp
($1, "rio"))
1512 yyerror("unknown cbq flag \"%s\"", $1);
1520 priqflags_list
: priqflags_item
{ $$ |
= $1; }
1521 | priqflags_list comma priqflags_item
{ $$ |
= $3; }
1524 priqflags_item
: STRING
{
1525 if
(!strcmp
($1, "default"))
1526 $$
= PRCF_DEFAULTCLASS
;
1527 else if
(!strcmp
($1, "red"))
1529 else if
(!strcmp
($1, "ecn"))
1530 $$
= PRCF_RED|PRCF_ECN
;
1531 else if
(!strcmp
($1, "rio"))
1534 yyerror("unknown priq flag \"%s\"", $1);
1544 sizeof
(struct node_hfsc_opts
));
1551 hfscopts_list
: hfscopts_item
1552 | hfscopts_list comma hfscopts_item
1555 hfscopts_item
: LINKSHARE bandwidth
{
1556 if
(hfsc_opts.linkshare.used
) {
1557 yyerror("linkshare already specified");
1560 hfsc_opts.linkshare.m2
= $2;
1561 hfsc_opts.linkshare.used
= 1;
1563 | LINKSHARE
'(' bandwidth comma number comma bandwidth
')'
1565 if
(hfsc_opts.linkshare.used
) {
1566 yyerror("linkshare already specified");
1569 hfsc_opts.linkshare.m1
= $3;
1570 hfsc_opts.linkshare.d
= $5;
1571 hfsc_opts.linkshare.m2
= $7;
1572 hfsc_opts.linkshare.used
= 1;
1574 | REALTIME bandwidth
{
1575 if
(hfsc_opts.realtime.used
) {
1576 yyerror("realtime already specified");
1579 hfsc_opts.realtime.m2
= $2;
1580 hfsc_opts.realtime.used
= 1;
1582 | REALTIME
'(' bandwidth comma number comma bandwidth
')'
1584 if
(hfsc_opts.realtime.used
) {
1585 yyerror("realtime already specified");
1588 hfsc_opts.realtime.m1
= $3;
1589 hfsc_opts.realtime.d
= $5;
1590 hfsc_opts.realtime.m2
= $7;
1591 hfsc_opts.realtime.used
= 1;
1593 | UPPERLIMIT bandwidth
{
1594 if
(hfsc_opts.upperlimit.used
) {
1595 yyerror("upperlimit already specified");
1598 hfsc_opts.upperlimit.m2
= $2;
1599 hfsc_opts.upperlimit.used
= 1;
1601 | UPPERLIMIT
'(' bandwidth comma number comma bandwidth
')'
1603 if
(hfsc_opts.upperlimit.used
) {
1604 yyerror("upperlimit already specified");
1607 hfsc_opts.upperlimit.m1
= $3;
1608 hfsc_opts.upperlimit.d
= $5;
1609 hfsc_opts.upperlimit.m2
= $7;
1610 hfsc_opts.upperlimit.used
= 1;
1613 if
(!strcmp
($1, "default"))
1614 hfsc_opts.flags |
= HFCF_DEFAULTCLASS
;
1615 else if
(!strcmp
($1, "red"))
1616 hfsc_opts.flags |
= HFCF_RED
;
1617 else if
(!strcmp
($1, "ecn"))
1618 hfsc_opts.flags |
= HFCF_RED|HFCF_ECN
;
1619 else if
(!strcmp
($1, "rio"))
1620 hfsc_opts.flags |
= HFCF_RIO
;
1622 yyerror("unknown hfsc flag \"%s\"", $1);
1630 qassign
: /* empty */ { $$
= NULL
; }
1631 | qassign_item
{ $$
= $1; }
1632 |
'{' qassign_list
'}' { $$
= $2; }
1635 qassign_list
: qassign_item
{ $$
= $1; }
1636 | qassign_list comma qassign_item
{
1637 $1->tail
->next
= $3;
1643 qassign_item
: STRING
{
1644 $$
= calloc
(1, sizeof
(struct node_queue
));
1646 err
(1, "qassign_item: calloc");
1647 if
(strlcpy
($$
->queue
, $1, sizeof
($$
->queue
)) >=
1648 sizeof
($$
->queue
)) {
1649 yyerror("queue name '%s' too long (max "
1650 "%d chars)", $1, sizeof
($$
->queue
)-1);
1661 pfrule
: action dir logquick interface route af proto fromto
1665 struct node_state_opt
*o
;
1666 struct node_proto
*proto
;
1671 if
(check_rulestate
(PFCTL_STATE_FILTER
))
1674 memset
(&r
, 0, sizeof
(r
));
1678 case PFRULE_RETURNRST
:
1679 r.rule_flag |
= PFRULE_RETURNRST
;
1680 r.return_ttl
= $1.w
;
1682 case PFRULE_RETURNICMP
:
1683 r.rule_flag |
= PFRULE_RETURNICMP
;
1684 r.return_icmp
= $1.w
;
1685 r.return_icmp6
= $1.w2
;
1688 r.rule_flag |
= PFRULE_RETURN
;
1689 r.return_icmp
= $1.w
;
1690 r.return_icmp6
= $1.w2
;
1698 r.rtableid
= $9.rtableid
;
1702 if
(strlcpy
(r.tagname
, $9.tag
,
1703 PF_TAG_NAME_SIZE
) >= PF_TAG_NAME_SIZE
) {
1704 yyerror("tag too long, max %u chars",
1705 PF_TAG_NAME_SIZE
- 1);
1709 if
(strlcpy
(r.match_tagname
, $9.match_tag
,
1710 PF_TAG_NAME_SIZE
) >= PF_TAG_NAME_SIZE
) {
1711 yyerror("tag too long, max %u chars",
1712 PF_TAG_NAME_SIZE
- 1);
1715 r.match_tag_not
= $9.match_tag_not
;
1716 if
(rule_label
(&r
, $9.label
))
1719 r.flags
= $9.flags.b1
;
1720 r.flagset
= $9.flags.b2
;
1721 if
(($9.flags.b1
& $9.flags.b2
) != $9.flags.b1
) {
1722 yyerror("flags always false");
1725 if
($9.flags.b1 ||
$9.flags.b2 ||
$8.src_os
) {
1726 for
(proto
= $7; proto
!= NULL
&&
1727 proto
->proto
!= IPPROTO_TCP
;
1728 proto
= proto
->next
)
1730 if
(proto
== NULL
&& $7 != NULL
) {
1731 if
($9.flags.b1 ||
$9.flags.b2
)
1733 "flags only apply to tcp");
1736 "OS fingerprinting only "
1741 if
(($9.flags.b1
& parse_flags
("S")) == 0 &&
1743 yyerror("OS fingerprinting requires "
1744 "the SYN TCP flag (flags S/SA)");
1751 r.keep_state
= $9.keep.action
;
1753 /* 'keep state' by default on pass rules. */
1754 if
(!r.keep_state
&& !r.action
&&
1755 !($9.marker
& FOM_KEEP
))
1756 r.keep_state
= PF_STATE_NORMAL
;
1758 o
= $9.keep.options
;
1760 struct node_state_opt
*p
= o
;
1763 case PF_STATE_OPT_MAX
:
1765 yyerror("state option 'max' "
1766 "multiple definitions");
1769 r.max_states
= o
->data.max_states
;
1771 case PF_STATE_OPT_NOSYNC
:
1772 if
(r.rule_flag
& PFRULE_NOSYNC
) {
1773 yyerror("state option 'sync' "
1774 "multiple definitions");
1777 r.rule_flag |
= PFRULE_NOSYNC
;
1779 case PF_STATE_OPT_SRCTRACK
:
1781 yyerror("state option "
1783 "multiple definitions");
1786 srctrack
= o
->data.src_track
;
1787 r.rule_flag |
= PFRULE_SRCTRACK
;
1789 case PF_STATE_OPT_MAX_SRC_STATES
:
1790 if
(r.max_src_states
) {
1791 yyerror("state option "
1793 "multiple definitions");
1796 if
(o
->data.max_src_states
== 0) {
1797 yyerror("'max-src-states' must "
1802 o
->data.max_src_states
;
1803 r.rule_flag |
= PFRULE_SRCTRACK
;
1805 case PF_STATE_OPT_OVERLOAD
:
1806 if
(r.overload_tblname
[0]) {
1807 yyerror("multiple 'overload' "
1808 "table definitions");
1811 if
(strlcpy
(r.overload_tblname
,
1812 o
->data.overload.tblname
,
1813 PF_TABLE_NAME_SIZE
) >=
1814 PF_TABLE_NAME_SIZE
) {
1815 yyerror("state option: "
1819 r.flush
= o
->data.overload.flush
;
1821 case PF_STATE_OPT_MAX_SRC_CONN
:
1822 if
(r.max_src_conn
) {
1823 yyerror("state option "
1825 "multiple definitions");
1828 if
(o
->data.max_src_conn
== 0) {
1829 yyerror("'max-src-conn' "
1834 o
->data.max_src_conn
;
1835 r.rule_flag |
= PFRULE_SRCTRACK |
1836 PFRULE_RULESRCTRACK
;
1838 case PF_STATE_OPT_MAX_SRC_CONN_RATE
:
1839 if
(r.max_src_conn_rate.limit
) {
1840 yyerror("state option "
1841 "'max-src-conn-rate' "
1842 "multiple definitions");
1845 if
(!o
->data.max_src_conn_rate.limit ||
1846 !o
->data.max_src_conn_rate.seconds
) {
1847 yyerror("'max-src-conn-rate' "
1848 "values must be > 0");
1851 if
(o
->data.max_src_conn_rate.limit
>
1853 yyerror("'max-src-conn-rate' "
1854 "maximum rate must be < %u",
1858 r.max_src_conn_rate.limit
=
1859 o
->data.max_src_conn_rate.limit
;
1860 r.max_src_conn_rate.seconds
=
1861 o
->data.max_src_conn_rate.seconds
;
1862 r.rule_flag |
= PFRULE_SRCTRACK |
1863 PFRULE_RULESRCTRACK
;
1865 case PF_STATE_OPT_MAX_SRC_NODES
:
1866 if
(r.max_src_nodes
) {
1867 yyerror("state option "
1869 "multiple definitions");
1872 if
(o
->data.max_src_nodes
== 0) {
1873 yyerror("'max-src-nodes' must "
1878 o
->data.max_src_nodes
;
1879 r.rule_flag |
= PFRULE_SRCTRACK |
1880 PFRULE_RULESRCTRACK
;
1882 case PF_STATE_OPT_STATELOCK
:
1884 yyerror("state locking option: "
1885 "multiple definitions");
1889 r.rule_flag |
= o
->data.statelock
;
1891 case PF_STATE_OPT_TIMEOUT
:
1892 if
(o
->data.timeout.number
==
1893 PFTM_ADAPTIVE_START ||
1894 o
->data.timeout.number
==
1897 if
(r.timeout
[o
->data.timeout.number
]) {
1898 yyerror("state timeout %s "
1899 "multiple definitions",
1900 pf_timeouts
[o
->data.
1901 timeout.number
].name
);
1904 r.timeout
[o
->data.timeout.number
] =
1905 o
->data.timeout.seconds
;
1911 /* 'flags S/SA' by default on stateful rules */
1912 if
(!r.action
&& !r.flags
&& !r.flagset
&&
1913 !$9.fragment
&& !($9.marker
& FOM_FLAGS
) &&
1915 r.flags
= parse_flags
("S");
1916 r.flagset
= parse_flags
("SA");
1918 if
(!adaptive
&& r.max_states
) {
1919 r.timeout
[PFTM_ADAPTIVE_START
] =
1920 (r.max_states
/ 10) * 6;
1921 r.timeout
[PFTM_ADAPTIVE_END
] =
1922 (r.max_states
/ 10) * 12;
1924 if
(r.rule_flag
& PFRULE_SRCTRACK
) {
1925 if
(srctrack
== PF_SRCTRACK_GLOBAL
&&
1927 yyerror("'max-src-nodes' is "
1928 "incompatible with "
1929 "'source-track global'");
1932 if
(srctrack
== PF_SRCTRACK_GLOBAL
&&
1934 yyerror("'max-src-conn' is "
1935 "incompatible with "
1936 "'source-track global'");
1939 if
(srctrack
== PF_SRCTRACK_GLOBAL
&&
1940 r.max_src_conn_rate.seconds
) {
1941 yyerror("'max-src-conn-rate' is "
1942 "incompatible with "
1943 "'source-track global'");
1946 if
(r.timeout
[PFTM_SRC_NODE
] <
1947 r.max_src_conn_rate.seconds
)
1948 r.timeout
[PFTM_SRC_NODE
] =
1949 r.max_src_conn_rate.seconds
;
1950 r.rule_flag |
= PFRULE_SRCTRACK
;
1951 if
(srctrack
== PF_SRCTRACK_RULE
)
1952 r.rule_flag |
= PFRULE_RULESRCTRACK
;
1954 if
(r.keep_state
&& !statelock
)
1955 r.rule_flag |
= default_statelock
;
1958 r.rule_flag |
= PFRULE_FRAGMENT
;
1959 r.allow_opts
= $9.allowopts
;
1961 decide_address_family
($8.src.host
, &r.af
);
1962 decide_address_family
($8.dst.host
, &r.af
);
1966 yyerror("direction must be explicit "
1967 "with rules that specify routing");
1971 r.rpool.opts
= $5.pool_opts
;
1973 memcpy
(&r.rpool.key
, $5.key
,
1974 sizeof
(struct pf_poolhashkey
));
1976 if
(r.rt
&& r.rt
!= PF_FASTROUTE
) {
1977 decide_address_family
($5.host
, &r.af
);
1978 remove_invalid_hosts
(&$5.host
, &r.af
);
1979 if
($5.host
== NULL
) {
1980 yyerror("no routing address with "
1981 "matching address family found.");
1984 if
((r.rpool.opts
& PF_POOL_TYPEMASK
) ==
1985 PF_POOL_NONE
&& ($5.host
->next
!= NULL ||
1986 $5.host
->addr.type
== PF_ADDR_TABLE ||
1987 DYNIF_MULTIADDR
($5.host
->addr
)))
1988 r.rpool.opts |
= PF_POOL_ROUNDROBIN
;
1989 if
((r.rpool.opts
& PF_POOL_TYPEMASK
) !=
1990 PF_POOL_ROUNDROBIN
&&
1991 disallow_table
($5.host
, "tables are only "
1992 "supported in round-robin routing pools"))
1994 if
((r.rpool.opts
& PF_POOL_TYPEMASK
) !=
1995 PF_POOL_ROUNDROBIN
&&
1996 disallow_alias
($5.host
, "interface (%s) "
1997 "is only supported in round-robin "
2000 if
($5.host
->next
!= NULL
) {
2001 if
((r.rpool.opts
& PF_POOL_TYPEMASK
) !=
2002 PF_POOL_ROUNDROBIN
) {
2003 yyerror("r.rpool.opts must "
2004 "be PF_POOL_ROUNDROBIN");
2009 if
($9.queues.qname
!= NULL
) {
2010 if
(strlcpy
(r.qname
, $9.queues.qname
,
2011 sizeof
(r.qname
)) >= sizeof
(r.qname
)) {
2012 yyerror("rule qname too long (max "
2013 "%d chars)", sizeof
(r.qname
)-1);
2016 free
($9.queues.qname
);
2018 if
($9.queues.pqname
!= NULL
) {
2019 if
(strlcpy
(r.pqname
, $9.queues.pqname
,
2020 sizeof
(r.pqname
)) >= sizeof
(r.pqname
)) {
2021 yyerror("rule pqname too long (max "
2022 "%d chars)", sizeof
(r.pqname
)-1);
2025 free
($9.queues.pqname
);
2028 expand_rule
(&r
, $4, $5.host
, $7, $8.src_os
,
2029 $8.src.host
, $8.src.port
, $8.dst.host
, $8.dst.port
,
2030 $9.uid
, $9.gid
, $9.icmpspec
, "");
2034 opt_statelock
: statelock
2036 $$
= calloc
(1, sizeof
(struct node_state_opt
));
2038 err
(EXIT_FAILURE
, "opt_statelock: calloc");
2039 $$
->type
= PF_STATE_OPT_STATELOCK
;
2040 $$
->data.statelock
= $1;
2050 bzero
(&filter_opts
, sizeof filter_opts
);
2051 filter_opts.rtableid
= -1;
2054 { $$
= filter_opts
; }
2056 bzero
(&filter_opts
, sizeof filter_opts
);
2057 filter_opts.rtableid
= -1;
2062 filter_opts_l
: filter_opts_l filter_opt
2066 filter_opt
: USER uids
{
2067 if
(filter_opts.uid
)
2068 $2->tail
->next
= filter_opts.uid
;
2069 filter_opts.uid
= $2;
2072 if
(filter_opts.gid
)
2073 $2->tail
->next
= filter_opts.gid
;
2074 filter_opts.gid
= $2;
2077 if
(filter_opts.marker
& FOM_FLAGS
) {
2078 yyerror("flags cannot be redefined");
2081 filter_opts.marker |
= FOM_FLAGS
;
2082 filter_opts.flags.b1 |
= $1.b1
;
2083 filter_opts.flags.b2 |
= $1.b2
;
2084 filter_opts.flags.w |
= $1.w
;
2085 filter_opts.flags.w2 |
= $1.w2
;
2088 if
(filter_opts.marker
& FOM_ICMP
) {
2089 yyerror("icmp-type cannot be redefined");
2092 filter_opts.marker |
= FOM_ICMP
;
2093 filter_opts.icmpspec
= $1;
2096 if
(filter_opts.marker
& FOM_TOS
) {
2097 yyerror("tos cannot be redefined");
2100 filter_opts.marker |
= FOM_TOS
;
2101 filter_opts.tos
= $1;
2104 if
(filter_opts.marker
& FOM_KEEP
) {
2105 yyerror("modulate or keep cannot be redefined");
2108 filter_opts.marker |
= FOM_KEEP
;
2109 filter_opts.keep.action
= $1.action
;
2110 filter_opts.keep.options
= $1.options
;
2113 filter_opts.fragment
= 1;
2116 filter_opts.allowopts
= 1;
2119 if
(filter_opts.label
) {
2120 yyerror("label cannot be redefined");
2123 filter_opts.label
= $1;
2126 if
(filter_opts.queues.qname
) {
2127 yyerror("queue cannot be redefined");
2130 filter_opts.queues
= $1;
2133 filter_opts.tag
= $2;
2135 | not TAGGED
string {
2136 filter_opts.match_tag
= $3;
2137 filter_opts.match_tag_not
= $1;
2139 | PROBABILITY STRING
{
2141 double p
= strtod
($2, &e
);
2148 yyerror("invalid probability: %s", $2);
2152 p
= floor
(p
* (UINT_MAX
+1.0) + 0.5);
2153 if
(p
< 1.0 || p
>= (UINT_MAX
+1.0)) {
2154 yyerror("invalid probability: %s", $2);
2158 filter_opts.prob
= (u_int32_t
)p
;
2162 if
($2 > RT_TABLEID_MAX ||
$2 < 0) {
2163 yyerror("invalid rtable id");
2166 filter_opts.rtableid
= $2;
2170 action
: PASS
{ $$.b1
= PF_PASS
; $$.b2
= $$.w
= 0; }
2171 | BLOCK blockspec
{ $$
= $2; $$.b1
= PF_DROP
; }
2174 blockspec
: /* empty */ {
2175 $$.b2
= blockpolicy
;
2176 $$.w
= returnicmpdefault
;
2177 $$.w2
= returnicmp6default
;
2180 $$.b2
= PFRULE_DROP
;
2185 $$.b2
= PFRULE_RETURNRST
;
2189 | RETURNRST
'(' TTL number
')' {
2191 yyerror("illegal ttl value %d", $4);
2194 $$.b2
= PFRULE_RETURNRST
;
2199 $$.b2
= PFRULE_RETURNICMP
;
2200 $$.w
= returnicmpdefault
;
2201 $$.w2
= returnicmp6default
;
2204 $$.b2
= PFRULE_RETURNICMP
;
2205 $$.w
= returnicmpdefault
;
2206 $$.w2
= returnicmp6default
;
2208 | RETURNICMP
'(' STRING
')' {
2209 $$.b2
= PFRULE_RETURNICMP
;
2210 if
(!($$.w
= parseicmpspec
($3, AF_INET
))) {
2215 $$.w2
= returnicmp6default
;
2217 | RETURNICMP6
'(' STRING
')' {
2218 $$.b2
= PFRULE_RETURNICMP
;
2219 $$.w
= returnicmpdefault
;
2220 if
(!($$.w2
= parseicmpspec
($3, AF_INET6
))) {
2226 | RETURNICMP
'(' STRING comma STRING
')' {
2227 $$.b2
= PFRULE_RETURNICMP
;
2228 if
(!($$.w
= parseicmpspec
($3, AF_INET
)) ||
2229 !($$.w2
= parseicmpspec
($5, AF_INET6
))) {
2238 $$.b2
= PFRULE_RETURN
;
2239 $$.w
= returnicmpdefault
;
2240 $$.w2
= returnicmp6default
;
2244 dir
: /* empty */ { $$
= 0; }
2245 | IN
{ $$
= PF_IN
; }
2246 | OUT
{ $$
= PF_OUT
; }
2249 quick
: /* empty */ { $$.quick
= 0; }
2250 | QUICK
{ $$.quick
= 1; }
2253 logquick
: /* empty */ { $$.log
= 0; $$.quick
= 0; $$.logif
= 0; }
2254 | log
{ $$
= $1; $$.quick
= 0; }
2255 | QUICK
{ $$.quick
= 1; $$.log
= 0; $$.logif
= 0; }
2256 | log QUICK
{ $$
= $1; $$.quick
= 1; }
2257 | QUICK log
{ $$
= $2; $$.quick
= 1; }
2260 log
: LOG
{ $$.log
= PF_LOG
; $$.logif
= 0; }
2261 | LOG
'(' logopts
')' {
2262 $$.log
= PF_LOG |
$3.log
;
2263 $$.logif
= $3.logif
;
2267 logopts
: logopt
{ $$
= $1; }
2268 | logopts comma logopt
{
2269 $$.log
= $1.log |
$3.log
;
2270 $$.logif
= $3.logif
;
2272 $$.logif
= $1.logif
;
2276 logopt
: ALL
{ $$.log
= PF_LOG_ALL
; $$.logif
= 0; }
2277 | USER
{ $$.log
= PF_LOG_SOCKET_LOOKUP
; $$.logif
= 0; }
2278 | GROUP
{ $$.log
= PF_LOG_SOCKET_LOOKUP
; $$.logif
= 0; }
2280 const char *errstr
= NULL
; /* XXX gcc */
2284 if
(strncmp
($2, "pflog", 5)) {
2285 yyerror("%s: should be a pflog interface", $2);
2289 i
= strtonum
($2 + 5, 0, 255, &errstr
);
2291 yyerror("%s: %s", $2, errstr
);
2300 interface
: /* empty */ { $$
= NULL
; }
2301 | ON if_item_not
{ $$
= $2; }
2302 | ON
'{' if_list
'}' { $$
= $3; }
2305 if_list
: if_item_not
{ $$
= $1; }
2306 | if_list comma if_item_not
{
2307 $1->tail
->next
= $3;
2313 if_item_not
: not if_item
{ $$
= $2; $$
->not
= $1; }
2317 struct node_host
*n
;
2319 $$
= calloc
(1, sizeof
(struct node_if
));
2321 err
(1, "if_item: calloc");
2322 if
(strlcpy
($$
->ifname
, $1, sizeof
($$
->ifname
)) >=
2323 sizeof
($$
->ifname
)) {
2326 yyerror("interface name too long");
2330 if
((n
= ifa_exists
($1)) != NULL
)
2331 $$
->ifa_flags
= n
->ifa_flags
;
2340 af
: /* empty */ { $$
= 0; }
2341 | INET
{ $$
= AF_INET
; }
2342 | INET6
{ $$
= AF_INET6
; }
2345 proto
: /* empty */ { $$
= NULL
; }
2346 | PROTO proto_item
{ $$
= $2; }
2347 | PROTO
'{' proto_list
'}' { $$
= $3; }
2350 proto_list
: proto_item
{ $$
= $1; }
2351 | proto_list comma proto_item
{
2352 $1->tail
->next
= $3;
2358 proto_item
: STRING
{
2362 if
(atoul
($1, &ulval
) == 0) {
2364 yyerror("protocol outside range");
2368 pr
= (u_int8_t
)ulval
;
2372 p
= getprotobyname
($1);
2374 yyerror("unknown protocol %s", $1);
2382 yyerror("proto 0 cannot be used");
2385 $$
= calloc
(1, sizeof
(struct node_proto
));
2387 err
(1, "proto_item: calloc");
2408 os
: /* empty */ { $$
= NULL
; }
2409 | OS xos
{ $$
= $2; }
2410 | OS
'{' os_list
'}' { $$
= $3; }
2414 $$
= calloc
(1, sizeof
(struct node_os
));
2416 err
(1, "os: calloc");
2422 os_list
: xos
{ $$
= $1; }
2423 | os_list comma xos
{
2424 $1->tail
->next
= $3;
2430 from
: /* empty */ {
2444 if
(disallow_urpf_failed
($2.host
, "\"urpf-failed\" is "
2445 "not permitted in a destination address"))
2451 ipportspec
: ipspec
{
2455 | ipspec PORT portspec
{
2465 ipspec
: ANY
{ $$
= NULL
; }
2466 | xhost
{ $$
= $1; }
2467 |
'{' host_list
'}' { $$
= $2; }
2470 host_list
: ipspec
{ $$
= $1; }
2471 | host_list comma ipspec
{
2474 else if
($1 == NULL
)
2477 $1->tail
->next
= $3;
2478 $1->tail
= $3->tail
;
2485 struct node_host
*n
;
2487 for
(n
= $2; n
!= NULL
; n
= n
->next
)
2492 $$
= calloc
(1, sizeof
(struct node_host
));
2494 err
(1, "xhost: calloc");
2495 $$
->addr.type
= PF_ADDR_NOROUTE
;
2501 $$
= calloc
(1, sizeof
(struct node_host
));
2503 err
(1, "xhost: calloc");
2504 $$
->addr.type
= PF_ADDR_URPFFAILED
;
2512 if
(($$
= host
($1)) == NULL
) {
2513 /* error. "any" is handled elsewhere */
2515 yyerror("could not parse host specification");
2521 | STRING
'/' number
{
2524 if
(asprintf
(&buf
, "%s/%u", $1, $3) == -1)
2525 err
(1, "host: asprintf");
2527 if
(($$
= host
(buf
)) == NULL
) {
2528 /* error. "any" is handled elsewhere */
2530 yyerror("could not parse host specification");
2536 | dynaddr
'/' number
{
2537 struct node_host
*n
;
2540 for
(n
= $1; n
!= NULL
; n
= n
->next
)
2544 if
(strlen
($2) >= PF_TABLE_NAME_SIZE
) {
2545 yyerror("table name '%s' too long", $2);
2549 $$
= calloc
(1, sizeof
(struct node_host
));
2551 err
(1, "host: calloc");
2552 $$
->addr.type
= PF_ADDR_TABLE
;
2553 if
(strlcpy
($$
->addr.v.tblname
, $2,
2554 sizeof
($$
->addr.v.tblname
)) >=
2555 sizeof
($$
->addr.v.tblname
))
2556 errx
(1, "host: strlcpy");
2562 $$
= calloc
(1, sizeof
(struct node_host
));
2565 err
(1, "host: calloc");
2567 $$
->addr.type
= PF_ADDR_RTLABEL
;
2568 if
(strlcpy
($$
->addr.v.rtlabelname
, $2,
2569 sizeof
($$
->addr.v.rtlabelname
)) >=
2570 sizeof
($$
->addr.v.rtlabelname
)) {
2571 yyerror("route label too long, max %u chars",
2572 sizeof
($$
->addr.v.rtlabelname
) - 1);
2586 if
(atoul
($1, &ulval
) == -1) {
2587 yyerror("%s is not a number", $1);
2596 dynaddr
: '(' STRING
')' {
2601 if
(!isalpha
((unsigned char)op
[0])) {
2602 yyerror("invalid interface name '%s'", op
);
2606 while
((p
= strrchr
($2, ':')) != NULL
) {
2607 if
(!strcmp
(p
+1, "network"))
2608 flags |
= PFI_AFLAG_NETWORK
;
2609 else if
(!strcmp
(p
+1, "broadcast"))
2610 flags |
= PFI_AFLAG_BROADCAST
;
2611 else if
(!strcmp
(p
+1, "peer"))
2612 flags |
= PFI_AFLAG_PEER
;
2613 else if
(!strcmp
(p
+1, "0"))
2614 flags |
= PFI_AFLAG_NOALIAS
;
2616 yyerror("interface %s has bad modifier",
2623 if
(flags
& (flags
- 1) & PFI_AFLAG_MODEMASK
) {
2625 yyerror("illegal combination of "
2626 "interface modifiers");
2629 $$
= calloc
(1, sizeof
(struct node_host
));
2631 err
(1, "address: calloc");
2633 set_ipmask
($$
, 128);
2634 $$
->addr.type
= PF_ADDR_DYNIFTL
;
2635 $$
->addr.iflags
= flags
;
2636 if
(strlcpy
($$
->addr.v.ifname
, $2,
2637 sizeof
($$
->addr.v.ifname
)) >=
2638 sizeof
($$
->addr.v.ifname
)) {
2641 yyerror("interface name too long");
2650 portspec
: port_item
{ $$
= $1; }
2651 |
'{' port_list
'}' { $$
= $2; }
2654 port_list
: port_item
{ $$
= $1; }
2655 | port_list comma port_item
{
2656 $1->tail
->next
= $3;
2663 $$
= calloc
(1, sizeof
(struct node_port
));
2665 err
(1, "port_item: calloc");
2677 yyerror("':' cannot be used with an other "
2681 $$
= calloc
(1, sizeof
(struct node_port
));
2683 err
(1, "port_item: calloc");
2690 | port PORTBINARY port
{
2692 yyerror("':' cannot be used with an other "
2696 $$
= calloc
(1, sizeof
(struct node_port
));
2698 err
(1, "port_item: calloc");
2708 char *p
= strchr
($1, ':');
2711 if
(($$.a
= getservice
($1)) == -1) {
2720 if
((port
[0] = getservice
($1)) == -1 ||
2721 (port
[1] = getservice
(p
)) == -1) {
2733 uids
: uid_item
{ $$
= $1; }
2734 |
'{' uid_list
'}' { $$
= $2; }
2737 uid_list
: uid_item
{ $$
= $1; }
2738 | uid_list comma uid_item
{
2739 $1->tail
->next
= $3;
2746 $$
= calloc
(1, sizeof
(struct node_uid
));
2748 err
(1, "uid_item: calloc");
2756 if
($2 == UID_MAX
&& $1 != PF_OP_EQ
&& $1 != PF_OP_NE
) {
2757 yyerror("user unknown requires operator = or "
2761 $$
= calloc
(1, sizeof
(struct node_uid
));
2763 err
(1, "uid_item: calloc");
2770 | uid PORTBINARY uid
{
2771 if
($1 == UID_MAX ||
$3 == UID_MAX
) {
2772 yyerror("user unknown requires operator = or "
2776 $$
= calloc
(1, sizeof
(struct node_uid
));
2778 err
(1, "uid_item: calloc");
2790 if
(atoul
($1, &ulval
) == -1) {
2791 if
(!strcmp
($1, "unknown"))
2796 if
((pw
= getpwnam
($1)) == NULL
) {
2797 yyerror("unknown user %s", $1);
2804 if
(ulval
>= UID_MAX
) {
2806 yyerror("illegal uid value %lu", ulval
);
2815 gids
: gid_item
{ $$
= $1; }
2816 |
'{' gid_list
'}' { $$
= $2; }
2819 gid_list
: gid_item
{ $$
= $1; }
2820 | gid_list comma gid_item
{
2821 $1->tail
->next
= $3;
2828 $$
= calloc
(1, sizeof
(struct node_gid
));
2830 err
(1, "gid_item: calloc");
2838 if
($2 == GID_MAX
&& $1 != PF_OP_EQ
&& $1 != PF_OP_NE
) {
2839 yyerror("group unknown requires operator = or "
2843 $$
= calloc
(1, sizeof
(struct node_gid
));
2845 err
(1, "gid_item: calloc");
2852 | gid PORTBINARY gid
{
2853 if
($1 == GID_MAX ||
$3 == GID_MAX
) {
2854 yyerror("group unknown requires operator = or "
2858 $$
= calloc
(1, sizeof
(struct node_gid
));
2860 err
(1, "gid_item: calloc");
2872 if
(atoul
($1, &ulval
) == -1) {
2873 if
(!strcmp
($1, "unknown"))
2878 if
((grp
= getgrnam
($1)) == NULL
) {
2879 yyerror("unknown group %s", $1);
2886 if
(ulval
>= GID_MAX
) {
2887 yyerror("illegal gid value %lu", ulval
);
2900 if
((f
= parse_flags
($1)) < 0) {
2901 yyerror("bad flags %s", $1);
2910 flags
: FLAGS flag
'/' flag
{ $$.b1
= $2.b1
; $$.b2
= $4.b1
; }
2911 | FLAGS
'/' flag
{ $$.b1
= 0; $$.b2
= $3.b1
; }
2912 | FLAGS ANY
{ $$.b1
= 0; $$.b2
= 0; }
2915 icmpspec
: ICMPTYPE icmp_item
{ $$
= $2; }
2916 | ICMPTYPE
'{' icmp_list
'}' { $$
= $3; }
2917 | ICMP6TYPE icmp6_item
{ $$
= $2; }
2918 | ICMP6TYPE
'{' icmp6_list
'}' { $$
= $3; }
2921 icmp_list
: icmp_item
{ $$
= $1; }
2922 | icmp_list comma icmp_item
{
2923 $1->tail
->next
= $3;
2929 icmp6_list
: icmp6_item
{ $$
= $1; }
2930 | icmp6_list comma icmp6_item
{
2931 $1->tail
->next
= $3;
2937 icmp_item
: icmptype
{
2938 $$
= calloc
(1, sizeof
(struct node_icmp
));
2940 err
(1, "icmp_item: calloc");
2943 $$
->proto
= IPPROTO_ICMP
;
2947 | icmptype CODE STRING
{
2948 const struct icmpcodeent
*p
;
2951 if
(atoul
($3, &ulval
) == 0) {
2954 yyerror("illegal icmp-code %lu", ulval
);
2958 if
((p
= geticmpcodebyname
($1-1, $3,
2959 AF_INET
)) == NULL
) {
2960 yyerror("unknown icmp-code %s", $3);
2967 $$
= calloc
(1, sizeof
(struct node_icmp
));
2969 err
(1, "icmp_item: calloc");
2971 $$
->code
= ulval
+ 1;
2972 $$
->proto
= IPPROTO_ICMP
;
2978 icmp6_item
: icmp6type
{
2979 $$
= calloc
(1, sizeof
(struct node_icmp
));
2981 err
(1, "icmp_item: calloc");
2984 $$
->proto
= IPPROTO_ICMPV6
;
2988 | icmp6type CODE STRING
{
2989 const struct icmpcodeent
*p
;
2992 if
(atoul
($3, &ulval
) == 0) {
2994 yyerror("illegal icmp6-code %lu",
3000 if
((p
= geticmpcodebyname
($1-1, $3,
3001 AF_INET6
)) == NULL
) {
3002 yyerror("unknown icmp6-code %s", $3);
3009 $$
= calloc
(1, sizeof
(struct node_icmp
));
3011 err
(1, "icmp_item: calloc");
3013 $$
->code
= ulval
+ 1;
3014 $$
->proto
= IPPROTO_ICMPV6
;
3021 const struct icmptypeent
*p
;
3024 if
(atoul
($1, &ulval
) == 0) {
3026 yyerror("illegal icmp-type %lu", ulval
);
3032 if
((p
= geticmptypebyname
($1, AF_INET
)) ==
3034 yyerror("unknown icmp-type %s", $1);
3044 icmp6type
: STRING
{
3045 const struct icmptypeent
*p
;
3048 if
(atoul
($1, &ulval
) == 0) {
3050 yyerror("illegal icmp6-type %lu",
3057 if
((p
= geticmptypebyname
($1, AF_INET6
)) ==
3059 yyerror("unknown icmp6-type %s", $1);
3070 if
(!strcmp
($2, "lowdelay"))
3071 $$
= IPTOS_LOWDELAY
;
3072 else if
(!strcmp
($2, "throughput"))
3073 $$
= IPTOS_THROUGHPUT
;
3074 else if
(!strcmp
($2, "reliability"))
3075 $$
= IPTOS_RELIABILITY
;
3076 else if
($2[0] == '0' && $2[1] == 'x')
3077 $$
= strtoul
($2, NULL
, 16);
3079 $$
= strtoul
($2, NULL
, 10);
3080 if
(!$$ || $$
> 255) {
3081 yyerror("illegal tos value %s", $2);
3089 sourcetrack
: SOURCETRACK
{ $$
= PF_SRCTRACK
; }
3090 | SOURCETRACK GLOBAL
{ $$
= PF_SRCTRACK_GLOBAL
; }
3091 | SOURCETRACK RULE
{ $$
= PF_SRCTRACK_RULE
; }
3094 statelock
: IFBOUND
{
3095 $$
= PFRULE_IFBOUND
;
3106 | KEEP STATE state_opt_spec
{
3107 $$.action
= PF_STATE_NORMAL
;
3110 | MODULATE STATE state_opt_spec
{
3111 $$.action
= PF_STATE_MODULATE
;
3114 | SYNPROXY STATE state_opt_spec
{
3115 $$.action
= PF_STATE_SYNPROXY
;
3120 flush
: /* empty */ { $$
= 0; }
3121 | FLUSH
{ $$
= PF_FLUSH
; }
3123 $$
= PF_FLUSH | PF_FLUSH_GLOBAL
;
3127 state_opt_spec
: '(' state_opt_list
')' { $$
= $2; }
3128 |
/* empty */ { $$
= NULL
; }
3131 state_opt_list
: state_opt_item
{ $$
= $1; }
3132 | state_opt_list comma state_opt_item
{
3133 $1->tail
->next
= $3;
3139 state_opt_item
: MAXIMUM number
{
3140 $$
= calloc
(1, sizeof
(struct node_state_opt
));
3142 err
(1, "state_opt_item: calloc");
3143 $$
->type
= PF_STATE_OPT_MAX
;
3144 $$
->data.max_states
= $2;
3149 $$
= calloc
(1, sizeof
(struct node_state_opt
));
3151 err
(1, "state_opt_item: calloc");
3152 $$
->type
= PF_STATE_OPT_NOSYNC
;
3156 | MAXSRCSTATES number
{
3157 $$
= calloc
(1, sizeof
(struct node_state_opt
));
3159 err
(1, "state_opt_item: calloc");
3160 $$
->type
= PF_STATE_OPT_MAX_SRC_STATES
;
3161 $$
->data.max_src_states
= $2;
3165 | MAXSRCCONN number
{
3166 $$
= calloc
(1, sizeof
(struct node_state_opt
));
3168 err
(1, "state_opt_item: calloc");
3169 $$
->type
= PF_STATE_OPT_MAX_SRC_CONN
;
3170 $$
->data.max_src_conn
= $2;
3174 | MAXSRCCONNRATE number
'/' number
{
3175 $$
= calloc
(1, sizeof
(struct node_state_opt
));
3177 err
(1, "state_opt_item: calloc");
3178 $$
->type
= PF_STATE_OPT_MAX_SRC_CONN_RATE
;
3179 $$
->data.max_src_conn_rate.limit
= $2;
3180 $$
->data.max_src_conn_rate.seconds
= $4;
3184 | OVERLOAD
'<' STRING
'>' flush
{
3185 if
(strlen
($3) >= PF_TABLE_NAME_SIZE
) {
3186 yyerror("table name '%s' too long", $3);
3190 $$
= calloc
(1, sizeof
(struct node_state_opt
));
3192 err
(1, "state_opt_item: calloc");
3193 if
(strlcpy
($$
->data.overload.tblname
, $3,
3194 PF_TABLE_NAME_SIZE
) >= PF_TABLE_NAME_SIZE
)
3195 errx
(1, "state_opt_item: strlcpy");
3197 $$
->type
= PF_STATE_OPT_OVERLOAD
;
3198 $$
->data.overload.flush
= $5;
3202 | MAXSRCNODES number
{
3203 $$
= calloc
(1, sizeof
(struct node_state_opt
));
3205 err
(1, "state_opt_item: calloc");
3206 $$
->type
= PF_STATE_OPT_MAX_SRC_NODES
;
3207 $$
->data.max_src_nodes
= $2;
3212 $$
= calloc
(1, sizeof
(struct node_state_opt
));
3214 err
(1, "state_opt_item: calloc");
3215 $$
->type
= PF_STATE_OPT_SRCTRACK
;
3216 $$
->data.src_track
= $1;
3221 $$
= calloc
(1, sizeof
(struct node_state_opt
));
3223 err
(1, "state_opt_item: calloc");
3224 $$
->type
= PF_STATE_OPT_STATELOCK
;
3225 $$
->data.statelock
= $1;
3232 for
(i
= 0; pf_timeouts
[i
].name
&&
3233 strcmp
(pf_timeouts
[i
].name
, $1); ++i
)
3235 if
(!pf_timeouts
[i
].name
) {
3236 yyerror("illegal timeout name %s", $1);
3240 if
(strchr
(pf_timeouts
[i
].name
, '.') == NULL
) {
3241 yyerror("illegal state timeout %s", $1);
3246 $$
= calloc
(1, sizeof
(struct node_state_opt
));
3248 err
(1, "state_opt_item: calloc");
3249 $$
->type
= PF_STATE_OPT_TIMEOUT
;
3250 $$
->data.timeout.number
= pf_timeouts
[i
].timeout
;
3251 $$
->data.timeout.seconds
= $2;
3257 label
: LABEL STRING
{
3262 qname
: QUEUE STRING
{
3265 | QUEUE
'(' STRING
')' {
3268 | QUEUE
'(' STRING comma STRING
')' {
3274 no
: /* empty */ { $$
= 0; }
3279 char *p
= strchr
($1, ':');
3282 if
(($$.a
= getservice
($1)) == -1) {
3287 } else if
(!strcmp
(p
+1, "*")) {
3289 if
(($$.a
= getservice
($1)) == -1) {
3297 if
(($$.a
= getservice
($1)) == -1 ||
3298 ($$.b
= getservice
(p
)) == -1) {
3310 redirspec
: host
{ $$
= $1; }
3311 |
'{' redir_host_list
'}' { $$
= $2; }
3314 redir_host_list
: host
{ $$
= $1; }
3315 | redir_host_list comma host
{
3316 $1->tail
->next
= $3;
3317 $1->tail
= $3->tail
;
3322 redirpool
: /* empty */ { $$
= NULL
; }
3324 $$
= calloc
(1, sizeof
(struct redirection
));
3326 err
(1, "redirection: calloc");
3328 $$
->rport.a
= $$
->rport.b
= $$
->rport.t
= 0;
3330 | ARROW redirspec PORT rport
{
3331 $$
= calloc
(1, sizeof
(struct redirection
));
3333 err
(1, "redirection: calloc");
3339 hashkey
: /* empty */
3341 $$
= calloc
(1, sizeof
(struct pf_poolhashkey
));
3343 err
(1, "hashkey: calloc");
3344 $$
->key32
[0] = arc4random
();
3345 $$
->key32
[1] = arc4random
();
3346 $$
->key32
[2] = arc4random
();
3347 $$
->key32
[3] = arc4random
();
3351 if
(!strncmp
($1, "0x", 2)) {
3352 if
(strlen
($1) != 34) {
3354 yyerror("hex key must be 128 bits "
3355 "(32 hex digits) long");
3358 $$
= calloc
(1, sizeof
(struct pf_poolhashkey
));
3360 err
(1, "hashkey: calloc");
3362 if
(sscanf
($1, "0x%8x%8x%8x%8x",
3363 &$$
->key32
[0], &$$
->key32
[1],
3364 &$$
->key32
[2], &$$
->key32
[3]) != 4) {
3367 yyerror("invalid hex key");
3373 $$
= calloc
(1, sizeof
(struct pf_poolhashkey
));
3375 err
(1, "hashkey: calloc");
3377 MD5Update
(&context
, (unsigned char *)$1,
3379 MD5Final
((unsigned char *)$$
, &context
);
3380 HTONL
($$
->key32
[0]);
3381 HTONL
($$
->key32
[1]);
3382 HTONL
($$
->key32
[2]);
3383 HTONL
($$
->key32
[3]);
3389 pool_opts
: { bzero
(&pool_opts
, sizeof pool_opts
); }
3393 bzero
(&pool_opts
, sizeof pool_opts
);
3398 pool_opts_l
: pool_opts_l pool_opt
3402 pool_opt
: BITMASK
{
3403 if
(pool_opts.type
) {
3404 yyerror("pool type cannot be redefined");
3407 pool_opts.type
= PF_POOL_BITMASK
;
3410 if
(pool_opts.type
) {
3411 yyerror("pool type cannot be redefined");
3414 pool_opts.type
= PF_POOL_RANDOM
;
3416 | SOURCEHASH hashkey
{
3417 if
(pool_opts.type
) {
3418 yyerror("pool type cannot be redefined");
3421 pool_opts.type
= PF_POOL_SRCHASH
;
3425 if
(pool_opts.type
) {
3426 yyerror("pool type cannot be redefined");
3429 pool_opts.type
= PF_POOL_ROUNDROBIN
;
3432 if
(pool_opts.staticport
) {
3433 yyerror("static-port cannot be redefined");
3436 pool_opts.staticport
= 1;
3439 if
(filter_opts.marker
& POM_STICKYADDRESS
) {
3440 yyerror("sticky-address cannot be redefined");
3443 pool_opts.marker |
= POM_STICKYADDRESS
;
3444 pool_opts.opts |
= PF_POOL_STICKYADDR
;
3448 redirection
: /* empty */ { $$
= NULL
; }
3450 $$
= calloc
(1, sizeof
(struct redirection
));
3452 err
(1, "redirection: calloc");
3454 $$
->rport.a
= $$
->rport.b
= $$
->rport.t
= 0;
3456 | ARROW host PORT rport
{
3457 $$
= calloc
(1, sizeof
(struct redirection
));
3459 err
(1, "redirection: calloc");
3465 natpasslog
: /* empty */ { $$.b1
= $$.b2
= 0; $$.w2
= 0; }
3466 | PASS
{ $$.b1
= 1; $$.b2
= 0; $$.w2
= 0; }
3467 | PASS log
{ $$.b1
= 1; $$.b2
= $2.log
; $$.w2
= $2.logif
; }
3468 | log
{ $$.b1
= 0; $$.b2
= $1.log
; $$.w2
= $1.logif
; }
3471 nataction
: no NAT natpasslog
{
3473 yyerror("\"pass\" not valid with \"no\"");
3484 | no RDR natpasslog
{
3486 yyerror("\"pass\" not valid with \"no\"");
3499 natrule
: nataction interface af proto fromto tag tagged rtable
3500 redirpool pool_opts opt_statelock
3504 if
(check_rulestate
(PFCTL_STATE_NAT
))
3507 memset
(&r
, 0, sizeof
(r
));
3516 if
($5.src.host
&& $5.src.host
->af
&&
3517 !$5.src.host
->ifindex
)
3518 r.af
= $5.src.host
->af
;
3519 else if
($5.dst.host
&& $5.dst.host
->af
&&
3520 !$5.dst.host
->ifindex
)
3521 r.af
= $5.dst.host
->af
;
3525 if
(strlcpy
(r.tagname
, $6, PF_TAG_NAME_SIZE
) >=
3527 yyerror("tag too long, max %u chars",
3528 PF_TAG_NAME_SIZE
- 1);
3533 if
(strlcpy
(r.match_tagname
, $7.name
,
3534 PF_TAG_NAME_SIZE
) >= PF_TAG_NAME_SIZE
) {
3535 yyerror("tag too long, max %u chars",
3536 PF_TAG_NAME_SIZE
- 1);
3539 r.match_tag_not
= $7.neg
;
3542 if
(r.action
== PF_NONAT || r.action
== PF_NORDR
) {
3544 yyerror("translation rule with 'no' "
3545 "does not need '->'");
3549 if
($9 == NULL ||
$9->host
== NULL
) {
3550 yyerror("translation rule requires '-> "
3554 if
(!r.af
&& ! $9->host
->ifindex
)
3555 r.af
= $9->host
->af
;
3557 remove_invalid_hosts
(&$9->host
, &r.af
);
3558 if
(invalid_redirect
($9->host
, r.af
))
3560 if
(check_netmask
($9->host
, r.af
))
3563 r.rpool.proxy_port
[0] = ntohs
($9->rport.a
);
3567 if
(!$9->rport.b
&& $9->rport.t
&&
3568 $5.dst.port
!= NULL
) {
3569 r.rpool.proxy_port
[1] =
3570 ntohs
($9->rport.a
) +
3572 $5.dst.port
->port
[1]) -
3574 $5.dst.port
->port
[0]));
3576 r.rpool.proxy_port
[1] =
3580 r.rpool.proxy_port
[1] =
3582 if
(!r.rpool.proxy_port
[0] &&
3583 !r.rpool.proxy_port
[1]) {
3584 r.rpool.proxy_port
[0] =
3585 PF_NAT_PROXY_PORT_LOW
;
3586 r.rpool.proxy_port
[1] =
3587 PF_NAT_PROXY_PORT_HIGH
;
3588 } else if
(!r.rpool.proxy_port
[1])
3589 r.rpool.proxy_port
[1] =
3590 r.rpool.proxy_port
[0];
3596 r.rpool.opts
= $10.type
;
3597 if
((r.rpool.opts
& PF_POOL_TYPEMASK
) ==
3598 PF_POOL_NONE
&& ($9->host
->next
!= NULL ||
3599 $9->host
->addr.type
== PF_ADDR_TABLE ||
3600 DYNIF_MULTIADDR
($9->host
->addr
)))
3601 r.rpool.opts
= PF_POOL_ROUNDROBIN
;
3602 if
((r.rpool.opts
& PF_POOL_TYPEMASK
) !=
3603 PF_POOL_ROUNDROBIN
&&
3604 disallow_table
($9->host
, "tables are only "
3605 "supported in round-robin redirection "
3608 if
((r.rpool.opts
& PF_POOL_TYPEMASK
) !=
3609 PF_POOL_ROUNDROBIN
&&
3610 disallow_alias
($9->host
, "interface (%s) "
3611 "is only supported in round-robin "
3612 "redirection pools"))
3614 if
($9->host
->next
!= NULL
) {
3615 if
((r.rpool.opts
& PF_POOL_TYPEMASK
) !=
3616 PF_POOL_ROUNDROBIN
) {
3617 yyerror("only round-robin "
3618 "valid for multiple "
3619 "redirection addresses");
3625 if
($10.key
!= NULL
)
3626 memcpy
(&r.rpool.key
, $10.key
,
3627 sizeof
(struct pf_poolhashkey
));
3630 r.rpool.opts |
= $10.opts
;
3632 if
($10.staticport
) {
3633 if
(r.action
!= PF_NAT
) {
3634 yyerror("the 'static-port' option is "
3635 "only valid with nat rules");
3638 if
(r.rpool.proxy_port
[0] !=
3639 PF_NAT_PROXY_PORT_LOW
&&
3640 r.rpool.proxy_port
[1] !=
3641 PF_NAT_PROXY_PORT_HIGH
) {
3642 yyerror("the 'static-port' option can't"
3643 " be used when specifying a port"
3647 r.rpool.proxy_port
[0] = 0;
3648 r.rpool.proxy_port
[1] = 0;
3652 r.rule_flag |
= default_statelock
;
3654 r.rule_flag |
= $11->data.statelock
;
3658 expand_rule
(&r
, $2, $9 == NULL ? NULL
: $9->host
, $4,
3659 $5.src_os
, $5.src.host
, $5.src.port
, $5.dst.host
,
3660 $5.dst.port
, 0, 0, 0, "");
3665 binatrule
: no BINAT natpasslog interface af proto FROM host TO ipspec tag
3666 tagged rtable redirection
3668 struct pf_rule binat
;
3669 struct pf_pooladdr
*pa
;
3671 if
(check_rulestate
(PFCTL_STATE_NAT
))
3673 if
(disallow_urpf_failed
($10, "\"urpf-failed\" is not "
3674 "permitted as a binat destination"))
3677 memset
(&binat
, 0, sizeof
(binat
));
3680 yyerror("\"pass\" not valid with \"no\"");
3684 binat.action
= PF_NOBINAT
;
3686 binat.action
= PF_BINAT
;
3687 binat.natpass
= $3.b1
;
3689 binat.logif
= $3.w2
;
3691 if
(!binat.af
&& $8 != NULL
&& $8->af
)
3693 if
(!binat.af
&& $10 != NULL
&& $10->af
)
3696 if
(!binat.af
&& $14 != NULL
&& $14->host
)
3697 binat.af
= $14->host
->af
;
3699 yyerror("address family (inet/inet6) "
3705 memcpy
(binat.ifname
, $4->ifname
,
3706 sizeof
(binat.ifname
));
3707 binat.ifnot
= $4->not
;
3712 if
(strlcpy
(binat.tagname
, $11,
3713 PF_TAG_NAME_SIZE
) >= PF_TAG_NAME_SIZE
) {
3714 yyerror("tag too long, max %u chars",
3715 PF_TAG_NAME_SIZE
- 1);
3719 if
(strlcpy
(binat.match_tagname
, $12.name
,
3720 PF_TAG_NAME_SIZE
) >= PF_TAG_NAME_SIZE
) {
3721 yyerror("tag too long, max %u chars",
3722 PF_TAG_NAME_SIZE
- 1);
3725 binat.match_tag_not
= $12.neg
;
3726 binat.rtableid
= $13;
3729 binat.proto
= $6->proto
;
3733 if
($8 != NULL
&& disallow_table
($8, "invalid use of "
3734 "table <%s> as the source address of a binat rule"))
3736 if
($8 != NULL
&& disallow_alias
($8, "invalid use of "
3737 "interface (%s) as the source address of a binat "
3740 if
($14 != NULL
&& $14->host
!= NULL
&& disallow_table
(
3741 $14->host
, "invalid use of table <%s> as the "
3742 "redirect address of a binat rule"))
3744 if
($14 != NULL
&& $14->host
!= NULL
&& disallow_alias
(
3745 $14->host
, "invalid use of interface (%s) as the "
3746 "redirect address of a binat rule"))
3751 yyerror("multiple binat ip addresses");
3754 if
($8->addr.type
== PF_ADDR_DYNIFTL
)
3756 if
($8->af
!= binat.af
) {
3757 yyerror("binat ip versions must match");
3760 if
(check_netmask
($8, binat.af
))
3762 memcpy
(&binat.src.addr
, &$8->addr
,
3763 sizeof
(binat.src.addr
));
3768 yyerror("multiple binat ip addresses");
3771 if
($10->af
!= binat.af
&& $10->af
) {
3772 yyerror("binat ip versions must match");
3775 if
(check_netmask
($10, binat.af
))
3777 memcpy
(&binat.dst.addr
, &$10->addr
,
3778 sizeof
(binat.dst.addr
));
3779 binat.dst.neg
= $10->not
;
3783 if
(binat.action
== PF_NOBINAT
) {
3785 yyerror("'no binat' rule does not need"
3790 if
($14 == NULL ||
$14->host
== NULL
) {
3791 yyerror("'binat' rule requires"
3796 remove_invalid_hosts
(&$14->host
, &binat.af
);
3797 if
(invalid_redirect
($14->host
, binat.af
))
3799 if
($14->host
->next
!= NULL
) {
3800 yyerror("binat rule must redirect to "
3801 "a single address");
3804 if
(check_netmask
($14->host
, binat.af
))
3807 if
(!PF_AZERO
(&binat.src.addr.v.a.mask
,
3809 !PF_AEQ
(&binat.src.addr.v.a.mask
,
3810 &$14->host
->addr.v.a.mask
, binat.af
)) {
3811 yyerror("'binat' source mask and "
3812 "redirect mask must be the same");
3816 TAILQ_INIT
(&binat.rpool.list
);
3817 pa
= calloc
(1, sizeof
(struct pf_pooladdr
));
3819 err
(1, "binat: calloc");
3820 pa
->addr
= $14->host
->addr
;
3822 TAILQ_INSERT_TAIL
(&binat.rpool.list
,
3828 pfctl_add_rule
(pf
, &binat
, "");
3832 tag
: /* empty */ { $$
= NULL
; }
3833 | TAG STRING
{ $$
= $2; }
3836 tagged
: /* empty */ { $$.neg
= 0; $$.name
= NULL
; }
3837 | not TAGGED
string { $$.neg
= $1; $$.name
= $3; }
3840 rtable
: /* empty */ { $$
= -1; }
3842 if
($2 > RT_TABLEID_MAX ||
$2 < 0) {
3843 yyerror("invalid rtable id");
3850 route_host
: STRING
{
3851 $$
= calloc
(1, sizeof
(struct node_host
));
3853 err
(1, "route_host: calloc");
3855 set_ipmask
($$
, 128);
3859 |
'(' STRING host
')' {
3865 route_host_list
: route_host
{ $$
= $1; }
3866 | route_host_list comma route_host
{
3869 if
($1->af
!= $3->af
) {
3870 yyerror("all pool addresses must be in the "
3871 "same address family");
3874 $1->tail
->next
= $3;
3875 $1->tail
= $3->tail
;
3880 routespec
: route_host
{ $$
= $1; }
3881 |
'{' route_host_list
'}' { $$
= $2; }
3884 route
: /* empty */ {
3891 $$.rt
= PF_FASTROUTE
;
3894 | ROUTETO routespec pool_opts
{
3897 $$.pool_opts
= $3.type |
$3.opts
;
3901 | REPLYTO routespec pool_opts
{
3904 $$.pool_opts
= $3.type |
$3.opts
;
3908 | DUPTO routespec pool_opts
{
3911 $$.pool_opts
= $3.type |
$3.opts
;
3917 timeout_spec
: STRING number
3919 if
(check_rulestate
(PFCTL_STATE_OPTION
)) {
3923 if
(pfctl_set_timeout
(pf
, $1, $2, 0) != 0) {
3924 yyerror("unknown timeout %s", $1);
3932 timeout_list
: timeout_list comma timeout_spec
3936 limit_spec
: STRING number
3938 if
(check_rulestate
(PFCTL_STATE_OPTION
)) {
3942 if
(pfctl_set_limit
(pf
, $1, $2) != 0) {
3943 yyerror("unable to set limit %s %u", $1, $2);
3951 limit_list
: limit_list comma limit_spec
3959 yesno
: NO
{ $$
= 0; }
3961 if
(!strcmp
($1, "yes"))
3964 yyerror("invalid value '%s', expected 'yes' "
3973 unaryop
: '=' { $$
= PF_OP_EQ
; }
3974 |
'!' '=' { $$
= PF_OP_NE
; }
3975 |
'<' '=' { $$
= PF_OP_LE
; }
3976 |
'<' { $$
= PF_OP_LT
; }
3977 |
'>' '=' { $$
= PF_OP_GE
; }
3978 |
'>' { $$
= PF_OP_GT
; }
3984 yyerror(const char *fmt
, ...
)
3987 extern
const char *infile
;
3991 fprintf
(stderr
, "%s:%d: ", infile
, yylval.lineno
);
3992 vfprintf
(stderr
, fmt
, ap
);
3993 fprintf
(stderr
, "\n");
3999 disallow_table
(struct node_host
*h
, const char *fmt
)
4001 for
(; h
!= NULL
; h
= h
->next
)
4002 if
(h
->addr.type
== PF_ADDR_TABLE
) {
4003 yyerror(fmt
, h
->addr.v.tblname
);
4010 disallow_urpf_failed
(struct node_host
*h
, const char *fmt
)
4012 for
(; h
!= NULL
; h
= h
->next
)
4013 if
(h
->addr.type
== PF_ADDR_URPFFAILED
) {
4021 disallow_alias
(struct node_host
*h
, const char *fmt
)
4023 for
(; h
!= NULL
; h
= h
->next
)
4024 if
(DYNIF_MULTIADDR
(h
->addr
)) {
4025 yyerror(fmt
, h
->addr.v.tblname
);
4032 rule_consistent
(struct pf_rule
*r
, int anchor_call
)
4036 switch
(r
->action
) {
4041 problems
= filter_consistent
(r
, anchor_call
);
4045 problems
= nat_consistent
(r
);
4049 problems
= rdr_consistent
(r
);
4060 filter_consistent
(struct pf_rule
*r
, int anchor_call
)
4064 if
(r
->proto
!= IPPROTO_TCP
&& r
->proto
!= IPPROTO_UDP
&&
4065 (r
->src.port_op || r
->dst.port_op
)) {
4066 yyerror("port only applies to tcp/udp");
4069 if
(r
->proto
!= IPPROTO_ICMP
&& r
->proto
!= IPPROTO_ICMPV6
&&
4070 (r
->type || r
->code
)) {
4071 yyerror("icmp-type/code only applies to icmp");
4074 if
(!r
->af
&& (r
->type || r
->code
)) {
4075 yyerror("must indicate address family with icmp-type/code");
4078 if
(r
->overload_tblname
[0] &&
4079 r
->max_src_conn
== 0 && r
->max_src_conn_rate.seconds
== 0) {
4080 yyerror("'overload' requires 'max-src-conn' "
4081 "or 'max-src-conn-rate'");
4084 if
((r
->proto
== IPPROTO_ICMP
&& r
->af
== AF_INET6
) ||
4085 (r
->proto
== IPPROTO_ICMPV6
&& r
->af
== AF_INET
)) {
4086 yyerror("proto %s doesn't match address family %s",
4087 r
->proto
== IPPROTO_ICMP ?
"icmp" : "icmp6",
4088 r
->af
== AF_INET ?
"inet" : "inet6");
4091 if
(r
->allow_opts
&& r
->action
!= PF_PASS
) {
4092 yyerror("allow-opts can only be specified for pass rules");
4095 if
(r
->rule_flag
& PFRULE_FRAGMENT
&& (r
->src.port_op ||
4096 r
->dst.port_op || r
->flagset || r
->type || r
->code
)) {
4097 yyerror("fragments can be filtered only on IP header fields");
4100 if
(r
->rule_flag
& PFRULE_RETURNRST
&& r
->proto
!= IPPROTO_TCP
) {
4101 yyerror("return-rst can only be applied to TCP rules");
4104 if
(r
->max_src_nodes
&& !(r
->rule_flag
& PFRULE_RULESRCTRACK
)) {
4105 yyerror("max-src-nodes requires 'source-track rule'");
4108 if
(r
->action
== PF_DROP
&& r
->keep_state
) {
4109 yyerror("keep state on block rules doesn't make sense");
4116 nat_consistent
(struct pf_rule
*r
)
4118 return
(0); /* yeah! */
4122 rdr_consistent
(struct pf_rule
*r
)
4126 if
(r
->proto
!= IPPROTO_TCP
&& r
->proto
!= IPPROTO_UDP
) {
4127 if
(r
->src.port_op
) {
4128 yyerror("src port only applies to tcp/udp");
4131 if
(r
->dst.port_op
) {
4132 yyerror("dst port only applies to tcp/udp");
4135 if
(r
->rpool.proxy_port
[0]) {
4136 yyerror("rpool port only applies to tcp/udp");
4140 if
(r
->dst.port_op
&&
4141 r
->dst.port_op
!= PF_OP_EQ
&& r
->dst.port_op
!= PF_OP_RRG
) {
4142 yyerror("invalid port operator for rdr destination port");
4149 process_tabledef
(char *name
, struct table_opts
*opts
)
4151 struct pfr_buffer ab
;
4152 struct node_tinit
*ti
;
4154 bzero
(&ab
, sizeof
(ab
));
4155 ab.pfrb_type
= PFRB_ADDRS
;
4156 SIMPLEQ_FOREACH
(ti
, &opts
->init_nodes
, entries
) {
4158 if
(pfr_buf_load
(&ab
, ti
->file
, 0, append_addr
)) {
4160 yyerror("cannot load \"%s\": %s",
4161 ti
->file
, strerror
(errno
));
4163 yyerror("file \"%s\" contains bad data",
4168 if
(append_addr_host
(&ab
, ti
->host
, 0, 0)) {
4169 yyerror("cannot create address buffer: %s",
4174 if
(pf
->opts
& PF_OPT_VERBOSE
)
4175 print_tabledef
(name
, opts
->flags
, opts
->init_addr
,
4177 if
(!(pf
->opts
& PF_OPT_NOACTION
) &&
4178 pfctl_define_table
(name
, opts
->flags
, opts
->init_addr
,
4179 pf
->anchor
->name
, &ab
, pf
->anchor
->ruleset.tticket
)) {
4180 yyerror("cannot define table %s: %s", name
,
4181 pfr_strerror
(errno
));
4197 /* macro gore, but you should've seen the prior indentation nightmare... */
4199 #define FREE_LIST(T,r) \
4202 while
(node
!= NULL
) { \
4204 node
= node
->next
; \
4209 #define LOOP_THROUGH(T,n,r,C) \
4213 r
= calloc
(1, sizeof
(T
)); \
4215 err
(1, "LOOP: calloc"); \
4219 while
(n
!= NULL
) { \
4228 expand_label_str
(char *label
, size_t len
, const char *srch
, const char *repl
)
4233 if
((tmp
= calloc
(1, len
)) == NULL
)
4234 err
(1, "expand_label_str: calloc");
4236 while
((q
= strstr
(p
, srch
)) != NULL
) {
4238 if
((strlcat
(tmp
, p
, len
) >= len
) ||
4239 (strlcat
(tmp
, repl
, len
) >= len
))
4240 errx
(1, "expand_label: label too long");
4244 if
(strlcat
(tmp
, p
, len
) >= len
)
4245 errx
(1, "expand_label: label too long");
4246 strlcpy
(label
, tmp
, len
); /* always fits */
4251 expand_label_if
(const char *name
, char *label
, size_t len
, const char *ifname
)
4253 if
(strstr
(label
, name
) != NULL
) {
4255 expand_label_str
(label
, len
, name
, "any");
4257 expand_label_str
(label
, len
, name
, ifname
);
4262 expand_label_addr
(const char *name
, char *label
, size_t len
, sa_family_t af
,
4263 struct node_host
*h
)
4265 char tmp
[64], tmp_not
[66];
4267 if
(strstr
(label
, name
) != NULL
) {
4268 switch
(h
->addr.type
) {
4269 case PF_ADDR_DYNIFTL
:
4270 snprintf
(tmp
, sizeof
(tmp
), "(%s)", h
->addr.v.ifname
);
4273 snprintf
(tmp
, sizeof
(tmp
), "<%s>", h
->addr.v.tblname
);
4275 case PF_ADDR_NOROUTE
:
4276 snprintf
(tmp
, sizeof
(tmp
), "no-route");
4278 case PF_ADDR_URPFFAILED
:
4279 snprintf
(tmp
, sizeof
(tmp
), "urpf-failed");
4281 case PF_ADDR_ADDRMASK
:
4282 if
(!af ||
(PF_AZERO
(&h
->addr.v.a.addr
, af
) &&
4283 PF_AZERO
(&h
->addr.v.a.mask
, af
)))
4284 snprintf
(tmp
, sizeof
(tmp
), "any");
4289 if
(inet_ntop
(af
, &h
->addr.v.a.addr
, a
,
4291 snprintf
(tmp
, sizeof
(tmp
), "?");
4293 bits
= unmask
(&h
->addr.v.a.mask
, af
);
4294 if
((af
== AF_INET
&& bits
< 32) ||
4295 (af
== AF_INET6
&& bits
< 128))
4296 snprintf
(tmp
, sizeof
(tmp
),
4299 snprintf
(tmp
, sizeof
(tmp
),
4305 snprintf
(tmp
, sizeof
(tmp
), "?");
4310 snprintf
(tmp_not
, sizeof
(tmp_not
), "! %s", tmp
);
4311 expand_label_str
(label
, len
, name
, tmp_not
);
4313 expand_label_str
(label
, len
, name
, tmp
);
4318 expand_label_port
(const char *name
, char *label
, size_t len
,
4319 struct node_port
*port
)
4321 char a1
[6], a2
[6], op
[13] = "";
4323 if
(strstr
(label
, name
) != NULL
) {
4324 snprintf
(a1
, sizeof
(a1
), "%u", ntohs
(port
->port
[0]));
4325 snprintf
(a2
, sizeof
(a2
), "%u", ntohs
(port
->port
[1]));
4328 else if
(port
->op
== PF_OP_IRG
)
4329 snprintf
(op
, sizeof
(op
), "%s><%s", a1
, a2
);
4330 else if
(port
->op
== PF_OP_XRG
)
4331 snprintf
(op
, sizeof
(op
), "%s<>%s", a1
, a2
);
4332 else if
(port
->op
== PF_OP_EQ
)
4333 snprintf
(op
, sizeof
(op
), "%s", a1
);
4334 else if
(port
->op
== PF_OP_NE
)
4335 snprintf
(op
, sizeof
(op
), "!=%s", a1
);
4336 else if
(port
->op
== PF_OP_LT
)
4337 snprintf
(op
, sizeof
(op
), "<%s", a1
);
4338 else if
(port
->op
== PF_OP_LE
)
4339 snprintf
(op
, sizeof
(op
), "<=%s", a1
);
4340 else if
(port
->op
== PF_OP_GT
)
4341 snprintf
(op
, sizeof
(op
), ">%s", a1
);
4342 else if
(port
->op
== PF_OP_GE
)
4343 snprintf
(op
, sizeof
(op
), ">=%s", a1
);
4344 expand_label_str
(label
, len
, name
, op
);
4349 expand_label_proto
(const char *name
, char *label
, size_t len
, u_int8_t proto
)
4351 struct protoent
*pe
;
4354 if
(strstr
(label
, name
) != NULL
) {
4355 pe
= getprotobynumber
(proto
);
4357 expand_label_str
(label
, len
, name
, pe
->p_name
);
4359 snprintf
(n
, sizeof
(n
), "%u", proto
);
4360 expand_label_str
(label
, len
, name
, n
);
4366 expand_label_nr
(const char *name
, char *label
, size_t len
)
4370 if
(strstr
(label
, name
) != NULL
) {
4371 snprintf
(n
, sizeof
(n
), "%u", pf
->anchor
->match
);
4372 expand_label_str
(label
, len
, name
, n
);
4377 expand_label
(char *label
, size_t len
, const char *ifname
, sa_family_t af
,
4378 struct node_host
*src_host
, struct node_port
*src_port
,
4379 struct node_host
*dst_host
, struct node_port
*dst_port
,
4382 expand_label_if
("$if", label
, len
, ifname
);
4383 expand_label_addr
("$srcaddr", label
, len
, af
, src_host
);
4384 expand_label_addr
("$dstaddr", label
, len
, af
, dst_host
);
4385 expand_label_port
("$srcport", label
, len
, src_port
);
4386 expand_label_port
("$dstport", label
, len
, dst_port
);
4387 expand_label_proto
("$proto", label
, len
, proto
);
4388 expand_label_nr
("$nr", label
, len
);
4392 expand_altq
(struct pf_altq
*a
, struct node_if
*interfaces
,
4393 struct node_queue
*nqueues
, struct node_queue_bw bwspec
,
4394 struct node_queue_opt
*opts
)
4396 struct pf_altq pa
, pb
;
4397 char qname
[PF_QNAME_SIZE
];
4398 struct node_queue
*n
;
4399 struct node_queue_bw bw
;
4402 if
((pf
->loadopt
& PFCTL_FLAG_ALTQ
) == 0) {
4403 FREE_LIST
(struct node_if
, interfaces
);
4404 FREE_LIST
(struct node_queue
, nqueues
);
4408 LOOP_THROUGH
(struct node_if
, interface
, interfaces
,
4409 memcpy
(&pa
, a
, sizeof
(struct pf_altq
));
4410 if
(strlcpy
(pa.ifname
, interface
->ifname
,
4411 sizeof
(pa.ifname
)) >= sizeof
(pa.ifname
))
4412 errx
(1, "expand_altq: strlcpy");
4414 if
(interface
->not
) {
4415 yyerror("altq on ! <interface> is not supported");
4418 if
(eval_pfaltq
(pf
, &pa
, &bwspec
, opts
))
4421 if
(pfctl_add_altq
(pf
, &pa
))
4424 if
(pf
->opts
& PF_OPT_VERBOSE
) {
4425 print_altq
(&pf
->paltq
->altq
, 0,
4427 if
(nqueues
&& nqueues
->tail
) {
4429 LOOP_THROUGH
(struct node_queue
, queue
,
4439 if
(pa.scheduler
== ALTQT_CBQ ||
4440 pa.scheduler
== ALTQT_HFSC
) {
4441 /* now create a root queue */
4442 memset
(&pb
, 0, sizeof
(struct pf_altq
));
4443 if
(strlcpy
(qname
, "root_", sizeof
(qname
)) >=
4445 errx
(1, "expand_altq: strlcpy");
4446 if
(strlcat
(qname
, interface
->ifname
,
4447 sizeof
(qname
)) >= sizeof
(qname
))
4448 errx
(1, "expand_altq: strlcat");
4449 if
(strlcpy
(pb.qname
, qname
,
4450 sizeof
(pb.qname
)) >= sizeof
(pb.qname
))
4451 errx
(1, "expand_altq: strlcpy");
4452 if
(strlcpy
(pb.ifname
, interface
->ifname
,
4453 sizeof
(pb.ifname
)) >= sizeof
(pb.ifname
))
4454 errx
(1, "expand_altq: strlcpy");
4455 pb.qlimit
= pa.qlimit
;
4456 pb.scheduler
= pa.scheduler
;
4457 bw.bw_absolute
= pa.ifbandwidth
;
4459 if
(eval_pfqueue
(pf
, &pb
, &bw
, opts
))
4462 if
(pfctl_add_altq
(pf
, &pb
))
4466 LOOP_THROUGH
(struct node_queue
, queue
, nqueues
,
4467 n
= calloc
(1, sizeof
(struct node_queue
));
4469 err
(1, "expand_altq: calloc");
4470 if
(pa.scheduler
== ALTQT_CBQ ||
4471 pa.scheduler
== ALTQT_HFSC
)
4472 if
(strlcpy
(n
->parent
, qname
,
4473 sizeof
(n
->parent
)) >=
4475 errx
(1, "expand_altq: strlcpy");
4476 if
(strlcpy
(n
->queue
, queue
->queue
,
4477 sizeof
(n
->queue
)) >= sizeof
(n
->queue
))
4478 errx
(1, "expand_altq: strlcpy");
4479 if
(strlcpy
(n
->ifname
, interface
->ifname
,
4480 sizeof
(n
->ifname
)) >= sizeof
(n
->ifname
))
4481 errx
(1, "expand_altq: strlcpy");
4482 n
->scheduler
= pa.scheduler
;
4488 queues
->tail
->next
= n
;
4494 FREE_LIST
(struct node_if
, interfaces
);
4495 FREE_LIST
(struct node_queue
, nqueues
);
4501 expand_queue
(struct pf_altq
*a
, struct node_if
*interfaces
,
4502 struct node_queue
*nqueues
, struct node_queue_bw bwspec
,
4503 struct node_queue_opt
*opts
)
4505 struct node_queue
*n
, *nq
;
4510 if
((pf
->loadopt
& PFCTL_FLAG_ALTQ
) == 0) {
4511 FREE_LIST
(struct node_queue
, nqueues
);
4515 if
(queues
== NULL
) {
4516 yyerror("queue %s has no parent", a
->qname
);
4517 FREE_LIST
(struct node_queue
, nqueues
);
4521 LOOP_THROUGH
(struct node_if
, interface
, interfaces
,
4522 LOOP_THROUGH
(struct node_queue
, tqueue
, queues
,
4523 if
(!strncmp
(a
->qname
, tqueue
->queue
, PF_QNAME_SIZE
) &&
4524 (interface
->ifname
[0] == 0 ||
4525 (!interface
->not
&& !strncmp
(interface
->ifname
,
4526 tqueue
->ifname
, IFNAMSIZ
)) ||
4527 (interface
->not
&& strncmp
(interface
->ifname
,
4528 tqueue
->ifname
, IFNAMSIZ
)))) {
4529 /* found ourself in queues */
4532 memcpy
(&pa
, a
, sizeof
(struct pf_altq
));
4534 if
(pa.scheduler
!= ALTQT_NONE
&&
4535 pa.scheduler
!= tqueue
->scheduler
) {
4536 yyerror("exactly one scheduler type "
4537 "per interface allowed");
4541 pa.scheduler
= tqueue
->scheduler
;
4543 /* scheduler dependent error checking */
4544 switch
(pa.scheduler
) {
4546 if
(nqueues
!= NULL
) {
4547 yyerror("priq queues cannot "
4548 "have child queues");
4552 if
(bwspec.bw_absolute
> 0 ||
4553 bwspec.bw_percent
< 100) {
4554 yyerror("priq doesn't take "
4564 if
(strlcpy
(pa.ifname
, tqueue
->ifname
,
4565 sizeof
(pa.ifname
)) >= sizeof
(pa.ifname
))
4566 errx
(1, "expand_queue: strlcpy");
4567 if
(strlcpy
(pa.parent
, tqueue
->parent
,
4568 sizeof
(pa.parent
)) >= sizeof
(pa.parent
))
4569 errx
(1, "expand_queue: strlcpy");
4571 if
(eval_pfqueue
(pf
, &pa
, &bwspec
, opts
))
4574 if
(pfctl_add_altq
(pf
, &pa
))
4577 for
(nq
= nqueues
; nq
!= NULL
; nq
= nq
->next
) {
4578 if
(!strcmp
(a
->qname
, nq
->queue
)) {
4579 yyerror("queue cannot have "
4585 sizeof
(struct node_queue
));
4587 err
(1, "expand_queue: calloc");
4588 if
(strlcpy
(n
->parent
, a
->qname
,
4589 sizeof
(n
->parent
)) >=
4591 errx
(1, "expand_queue strlcpy");
4592 if
(strlcpy
(n
->queue
, nq
->queue
,
4593 sizeof
(n
->queue
)) >=
4595 errx
(1, "expand_queue strlcpy");
4596 if
(strlcpy
(n
->ifname
, tqueue
->ifname
,
4597 sizeof
(n
->ifname
)) >=
4599 errx
(1, "expand_queue strlcpy");
4600 n
->scheduler
= tqueue
->scheduler
;
4606 queues
->tail
->next
= n
;
4610 if
((pf
->opts
& PF_OPT_VERBOSE
) && (
4611 (found
== 1 && interface
->ifname
[0] == 0) ||
4612 (found
> 0 && interface
->ifname
[0] != 0))) {
4613 print_queue
(&pf
->paltq
->altq
, 0,
4614 &bwspec
, interface
->ifname
[0] != 0,
4616 if
(nqueues
&& nqueues
->tail
) {
4618 LOOP_THROUGH
(struct node_queue
,
4632 FREE_LIST
(struct node_queue
, nqueues
);
4633 FREE_LIST
(struct node_if
, interfaces
);
4636 yyerror("queue %s has no parent", a
->qname
);
4647 expand_rule
(struct pf_rule
*r
,
4648 struct node_if
*interfaces
, struct node_host
*rpool_hosts
,
4649 struct node_proto
*protos
, struct node_os
*src_oses
,
4650 struct node_host
*src_hosts
, struct node_port
*src_ports
,
4651 struct node_host
*dst_hosts
, struct node_port
*dst_ports
,
4652 struct node_uid
*uids
, struct node_gid
*gids
, struct node_icmp
*icmp_types
,
4653 const char *anchor_call
)
4655 sa_family_t af
= r
->af
;
4656 int added
= 0, error = 0;
4657 char ifname
[IF_NAMESIZE
];
4658 char label
[PF_RULE_LABEL_SIZE
];
4659 char tagname
[PF_TAG_NAME_SIZE
];
4660 char match_tagname
[PF_TAG_NAME_SIZE
];
4661 struct pf_pooladdr
*pa
;
4662 struct node_host
*h
;
4663 u_int8_t flags
, flagset
, keep_state
;
4665 if
(strlcpy
(label
, r
->label
, sizeof
(label
)) >= sizeof
(label
))
4666 errx
(1, "expand_rule: strlcpy");
4667 if
(strlcpy
(tagname
, r
->tagname
, sizeof
(tagname
)) >= sizeof
(tagname
))
4668 errx
(1, "expand_rule: strlcpy");
4669 if
(strlcpy
(match_tagname
, r
->match_tagname
, sizeof
(match_tagname
)) >=
4670 sizeof
(match_tagname
))
4671 errx
(1, "expand_rule: strlcpy");
4673 flagset
= r
->flagset
;
4674 keep_state
= r
->keep_state
;
4676 LOOP_THROUGH
(struct node_if
, interface
, interfaces
,
4677 LOOP_THROUGH
(struct node_proto
, proto
, protos
,
4678 LOOP_THROUGH
(struct node_icmp
, icmp_type
, icmp_types
,
4679 LOOP_THROUGH
(struct node_host
, src_host
, src_hosts
,
4680 LOOP_THROUGH
(struct node_port
, src_port
, src_ports
,
4681 LOOP_THROUGH
(struct node_os
, src_os
, src_oses
,
4682 LOOP_THROUGH
(struct node_host
, dst_host
, dst_hosts
,
4683 LOOP_THROUGH
(struct node_port
, dst_port
, dst_ports
,
4684 LOOP_THROUGH
(struct node_uid
, uid
, uids
,
4685 LOOP_THROUGH
(struct node_gid
, gid
, gids
,
4688 /* for link-local IPv6 address, interface must match up */
4689 if
((r
->af
&& src_host
->af
&& r
->af
!= src_host
->af
) ||
4690 (r
->af
&& dst_host
->af
&& r
->af
!= dst_host
->af
) ||
4691 (src_host
->af
&& dst_host
->af
&&
4692 src_host
->af
!= dst_host
->af
) ||
4693 (src_host
->ifindex
&& dst_host
->ifindex
&&
4694 src_host
->ifindex
!= dst_host
->ifindex
) ||
4695 (src_host
->ifindex
&& *interface
->ifname
&&
4696 src_host
->ifindex
!= if_nametoindex
(interface
->ifname
)) ||
4697 (dst_host
->ifindex
&& *interface
->ifname
&&
4698 dst_host
->ifindex
!= if_nametoindex
(interface
->ifname
)))
4700 if
(!r
->af
&& src_host
->af
)
4701 r
->af
= src_host
->af
;
4702 else if
(!r
->af
&& dst_host
->af
)
4703 r
->af
= dst_host
->af
;
4705 if
(*interface
->ifname
)
4706 strlcpy
(r
->ifname
, interface
->ifname
,
4708 else if
(if_indextoname
(src_host
->ifindex
, ifname
))
4709 strlcpy
(r
->ifname
, ifname
, sizeof
(r
->ifname
));
4710 else if
(if_indextoname
(dst_host
->ifindex
, ifname
))
4711 strlcpy
(r
->ifname
, ifname
, sizeof
(r
->ifname
));
4713 memset
(r
->ifname
, '\0', sizeof
(r
->ifname
));
4715 if
(strlcpy
(r
->label
, label
, sizeof
(r
->label
)) >=
4717 errx
(1, "expand_rule: strlcpy");
4718 if
(strlcpy
(r
->tagname
, tagname
, sizeof
(r
->tagname
)) >=
4720 errx
(1, "expand_rule: strlcpy");
4721 if
(strlcpy
(r
->match_tagname
, match_tagname
,
4722 sizeof
(r
->match_tagname
)) >= sizeof
(r
->match_tagname
))
4723 errx
(1, "expand_rule: strlcpy");
4724 expand_label
(r
->label
, PF_RULE_LABEL_SIZE
, r
->ifname
, r
->af
,
4725 src_host
, src_port
, dst_host
, dst_port
, proto
->proto
);
4726 expand_label
(r
->tagname
, PF_TAG_NAME_SIZE
, r
->ifname
, r
->af
,
4727 src_host
, src_port
, dst_host
, dst_port
, proto
->proto
);
4728 expand_label
(r
->match_tagname
, PF_TAG_NAME_SIZE
, r
->ifname
,
4729 r
->af
, src_host
, src_port
, dst_host
, dst_port
,
4732 error += check_netmask
(src_host
, r
->af
);
4733 error += check_netmask
(dst_host
, r
->af
);
4735 r
->ifnot
= interface
->not
;
4736 r
->proto
= proto
->proto
;
4737 r
->src.addr
= src_host
->addr
;
4738 r
->src.neg
= src_host
->not
;
4739 r
->src.port
[0] = src_port
->port
[0];
4740 r
->src.port
[1] = src_port
->port
[1];
4741 r
->src.port_op
= src_port
->op
;
4742 r
->dst.addr
= dst_host
->addr
;
4743 r
->dst.neg
= dst_host
->not
;
4744 r
->dst.port
[0] = dst_port
->port
[0];
4745 r
->dst.port
[1] = dst_port
->port
[1];
4746 r
->dst.port_op
= dst_port
->op
;
4747 r
->uid.op
= uid
->op
;
4748 r
->uid.uid
[0] = uid
->uid
[0];
4749 r
->uid.uid
[1] = uid
->uid
[1];
4750 r
->gid.op
= gid
->op
;
4751 r
->gid.gid
[0] = gid
->gid
[0];
4752 r
->gid.gid
[1] = gid
->gid
[1];
4753 r
->type
= icmp_type
->type
;
4754 r
->code
= icmp_type
->code
;
4756 if
((keep_state
== PF_STATE_MODULATE ||
4757 keep_state
== PF_STATE_SYNPROXY
) &&
4758 r
->proto
&& r
->proto
!= IPPROTO_TCP
)
4759 r
->keep_state
= PF_STATE_NORMAL
;
4761 r
->keep_state
= keep_state
;
4763 if
(r
->proto
&& r
->proto
!= IPPROTO_TCP
) {
4768 r
->flagset
= flagset
;
4770 if
(icmp_type
->proto
&& r
->proto
!= icmp_type
->proto
) {
4771 yyerror("icmp-type mismatch");
4775 if
(src_os
&& src_os
->os
) {
4776 r
->os_fingerprint
= pfctl_get_fingerprint
(src_os
->os
);
4777 if
((pf
->opts
& PF_OPT_VERBOSE2
) &&
4778 r
->os_fingerprint
== PF_OSFP_NOMATCH
)
4780 "warning: unknown '%s' OS fingerprint\n",
4783 r
->os_fingerprint
= PF_OSFP_ANY
;
4786 TAILQ_INIT
(&r
->rpool.list
);
4787 for
(h
= rpool_hosts
; h
!= NULL
; h
= h
->next
) {
4788 pa
= calloc
(1, sizeof
(struct pf_pooladdr
));
4790 err
(1, "expand_rule: calloc");
4792 if
(h
->ifname
!= NULL
) {
4793 if
(strlcpy
(pa
->ifname
, h
->ifname
,
4794 sizeof
(pa
->ifname
)) >=
4796 errx
(1, "expand_rule: strlcpy");
4799 TAILQ_INSERT_TAIL
(&r
->rpool.list
, pa
, entries
);
4802 if
(rule_consistent
(r
, anchor_call
[0]) < 0 ||
error)
4803 yyerror("skipping rule due to errors");
4805 r
->nr
= pf
->astack
[pf
->asd
]->match
++;
4806 pfctl_add_rule
(pf
, r
, anchor_call
);
4812 FREE_LIST
(struct node_if
, interfaces
);
4813 FREE_LIST
(struct node_proto
, protos
);
4814 FREE_LIST
(struct node_host
, src_hosts
);
4815 FREE_LIST
(struct node_port
, src_ports
);
4816 FREE_LIST
(struct node_os
, src_oses
);
4817 FREE_LIST
(struct node_host
, dst_hosts
);
4818 FREE_LIST
(struct node_port
, dst_ports
);
4819 FREE_LIST
(struct node_uid
, uids
);
4820 FREE_LIST
(struct node_gid
, gids
);
4821 FREE_LIST
(struct node_icmp
, icmp_types
);
4822 FREE_LIST
(struct node_host
, rpool_hosts
);
4825 yyerror("rule expands to no valid combination");
4829 expand_skip_interface
(struct node_if
*interfaces
)
4833 if
(!interfaces ||
(!interfaces
->next
&& !interfaces
->not
&&
4834 !strcmp
(interfaces
->ifname
, "none"))) {
4835 if
(pf
->opts
& PF_OPT_VERBOSE
)
4836 printf
("set skip on none\n");
4837 errs
= pfctl_set_interface_flags
(pf
, "", PFI_IFLAG_SKIP
, 0);
4841 if
(pf
->opts
& PF_OPT_VERBOSE
)
4842 printf
("set skip on {");
4843 LOOP_THROUGH
(struct node_if
, interface
, interfaces
,
4844 if
(pf
->opts
& PF_OPT_VERBOSE
)
4845 printf
(" %s", interface
->ifname
);
4846 if
(interface
->not
) {
4847 yyerror("skip on ! <interface> is not supported");
4850 errs
+= pfctl_set_interface_flags
(pf
,
4851 interface
->ifname
, PFI_IFLAG_SKIP
, 1);
4853 if
(pf
->opts
& PF_OPT_VERBOSE
)
4856 FREE_LIST
(struct node_if
, interfaces
);
4868 check_rulestate
(int desired_state
)
4870 if
(require_order
&& (rulestate
> desired_state
)) {
4871 yyerror("Rules must be in order: options, normalization, "
4872 "queueing, translation, filtering");
4875 rulestate
= desired_state
;
4880 kw_cmp
(const void *k
, const void *e
)
4882 return
(strcmp
(k
, ((const struct keywords
*)e
)->k_name
));
4888 /* this has to be sorted always */
4889 static const struct keywords keywords
[] = {
4891 { "allow-opts", ALLOWOPTS
},
4893 { "anchor", ANCHOR
},
4894 { "antispoof", ANTISPOOF
},
4896 { "bandwidth", BANDWIDTH
},
4898 { "binat-anchor", BINATANCHOR
},
4899 { "bitmask", BITMASK
},
4901 { "block-policy", BLOCKPOLICY
},
4904 { "crop", FRAGCROP
},
4907 { "drop-ovl", FRAGDROP
},
4909 { "fastroute", FASTROUTE
},
4910 { "file", FILENAME
},
4911 { "fingerprints", FINGERPRINTS
},
4913 { "floating", FLOATING
},
4916 { "fragment", FRAGMENT
},
4918 { "global", GLOBAL
},
4921 { "hostid", HOSTID
},
4922 { "icmp-type", ICMPTYPE
},
4923 { "icmp6-type", ICMP6TYPE
},
4924 { "if-bound", IFBOUND
},
4931 { "linkshare", LINKSHARE
},
4934 { "loginterface", LOGINTERFACE
},
4936 { "max-mss", MAXMSS
},
4937 { "max-src-conn", MAXSRCCONN
},
4938 { "max-src-conn-rate", MAXSRCCONNRATE
},
4939 { "max-src-nodes", MAXSRCNODES
},
4940 { "max-src-states", MAXSRCSTATES
},
4941 { "min-ttl", MINTTL
},
4942 { "modulate", MODULATE
},
4944 { "nat-anchor", NATANCHOR
},
4947 { "no-route", NOROUTE
},
4948 { "no-sync", NOSYNC
},
4950 { "optimization", OPTIMIZATION
},
4953 { "overload", OVERLOAD
},
4956 { "priority", PRIORITY
},
4958 { "probability", PROBABILITY
},
4960 { "qlimit", QLIMIT
},
4963 { "random", RANDOM
},
4964 { "random-id", RANDOMID
},
4966 { "rdr-anchor", RDRANCHOR
},
4967 { "realtime", REALTIME
},
4968 { "reassemble", REASSEMBLE
},
4969 { "reply-to", REPLYTO
},
4970 { "require-order", REQUIREORDER
},
4971 { "return", RETURN
},
4972 { "return-icmp", RETURNICMP
},
4973 { "return-icmp6", RETURNICMP6
},
4974 { "return-rst", RETURNRST
},
4975 { "round-robin", ROUNDROBIN
},
4977 { "route-to", ROUTETO
},
4978 { "rtable", RTABLE
},
4980 { "ruleset-optimization", RULESET_OPTIMIZATION
},
4984 { "source-hash", SOURCEHASH
},
4985 { "source-track", SOURCETRACK
},
4987 { "state-policy", STATEPOLICY
},
4988 { "static-port", STATICPORT
},
4989 { "sticky-address", STICKYADDRESS
},
4990 { "synproxy", SYNPROXY
},
4993 { "tagged", TAGGED
},
4994 { "tbrsize", TBRSIZE
},
4995 { "timeout", TIMEOUT
},
4999 { "upperlimit", UPPERLIMIT
},
5000 { "urpf-failed", URPFFAILED
},
5003 const struct keywords
*p
;
5005 p
= bsearch
(s
, keywords
, sizeof
(keywords
)/sizeof
(keywords
[0]),
5006 sizeof
(keywords
[0]), kw_cmp
);
5010 fprintf
(stderr
, "%s: %d\n", s
, p
->k_val
);
5014 fprintf
(stderr
, "string: %s\n", s
);
5019 #define MAXPUSHBACK 128
5023 char pushback_buffer
[MAXPUSHBACK
];
5024 int pushback_index
= 0;
5032 /* Read character from the parsebuffer instead of input. */
5033 if
(parseindex
>= 0) {
5034 c
= parsebuf
[parseindex
++];
5043 return
(pushback_buffer
[--pushback_index
]);
5045 while
((c
= getc
(f
)) == '\\') {
5051 yylval.lineno
= lineno
;
5054 if
(c
== '\t' || c
== ' ') {
5055 /* Compress blanks to a single space. */
5058 } while
(c
== '\t' || c
== ' ');
5073 if
(parseindex
>= 0)
5076 if
(pushback_index
< MAXPUSHBACK
-1)
5077 return
(pushback_buffer
[pushback_index
++] = c
);
5090 /* skip to either EOF or the first real EOL */
5113 while
((c
= lgetc
(fin
)) == ' ')
5116 yylval.lineno
= lineno
;
5118 while
((c
= lgetc
(fin
)) != '\n' && c
!= EOF
)
5120 if
(c
== '$' && parsebuf
== NULL
) {
5122 if
((c
= lgetc
(fin
)) == EOF
)
5125 if
(p
+ 1 >= buf
+ sizeof
(buf
) - 1) {
5126 yyerror("string too long");
5129 if
(isalnum
(c
) || c
== '_') {
5139 yyerror("macro '%s' not defined", buf
);
5152 if
((c
= lgetc
(fin
)) == EOF
)
5162 if
(p
+ 1 >= buf
+ sizeof
(buf
) - 1) {
5163 yyerror("string too long");
5168 yylval.v.
string = strdup
(buf
);
5169 if
(yylval.v.
string == NULL
)
5170 err
(1, "yylex: strdup");
5175 yylval.v.i
= PF_OP_XRG
;
5176 return
(PORTBINARY
);
5183 yylval.v.i
= PF_OP_IRG
;
5184 return
(PORTBINARY
);
5196 #define allowed_in_string(x) \
5197 (isalnum
(x
) ||
(ispunct
(x
) && x
!= '(' && x
!= ')' && \
5198 x
!= '{' && x
!= '}' && x
!= '<' && x
!= '>' && \
5199 x
!= '!' && x
!= '=' && x
!= '/' && x
!= '#' && \
5202 if
(isalnum
(c
) || c
== ':' || c
== '_') {
5205 if
((unsigned)(p
-buf
) >= sizeof
(buf
)) {
5206 yyerror("string too long");
5209 } while
((c
= lgetc
(fin
)) != EOF
&& (allowed_in_string
(c
)));
5212 if
((token
= lookup
(buf
)) == STRING
)
5213 if
((yylval.v.
string = strdup
(buf
)) == NULL
)
5214 err
(1, "yylex: strdup");
5218 yylval.lineno
= lineno
;
5227 parse_rules
(FILE *input
, struct pfctl
*xpf
)
5229 struct sym
*sym
, *next
;
5235 rulestate
= PFCTL_STATE_NONE
;
5236 returnicmpdefault
= (ICMP_UNREACH
<< 8) | ICMP_UNREACH_PORT
;
5237 returnicmp6default
=
5238 (ICMP6_DST_UNREACH
<< 8) | ICMP6_DST_UNREACH_NOPORT
;
5239 blockpolicy
= PFRULE_DROP
;
5244 /* Free macros and check which have not been used. */
5245 for
(sym
= TAILQ_FIRST
(&symhead
); sym
!= NULL
; sym
= next
) {
5246 next
= TAILQ_NEXT
(sym
, entries
);
5247 if
((pf
->opts
& PF_OPT_VERBOSE2
) && !sym
->used
)
5248 fprintf
(stderr
, "warning: macro '%s' not "
5249 "used\n", sym
->nam
);
5252 TAILQ_REMOVE
(&symhead
, sym
, entries
);
5256 return
(errors ?
-1 : 0);
5260 * Over-designed efficiency is a French and German concept, so how about
5261 * we wait until they discover this ugliness and make it all fancy.
5264 symset
(const char *nam
, const char *val
, int persist
)
5268 for
(sym
= TAILQ_FIRST
(&symhead
); sym
&& strcmp
(nam
, sym
->nam
);
5269 sym
= TAILQ_NEXT
(sym
, entries
))
5273 if
(sym
->persist
== 1)
5278 TAILQ_REMOVE
(&symhead
, sym
, entries
);
5282 if
((sym
= calloc
(1, sizeof
(*sym
))) == NULL
)
5285 sym
->nam
= strdup
(nam
);
5286 if
(sym
->nam
== NULL
) {
5290 sym
->val
= strdup
(val
);
5291 if
(sym
->val
== NULL
) {
5297 sym
->persist
= persist
;
5298 TAILQ_INSERT_TAIL
(&symhead
, sym
, entries
);
5303 pfctl_cmdline_symset
(char *s
)
5308 if
((val
= strrchr
(s
, '=')) == NULL
)
5311 if
((sym
= malloc
(strlen
(s
) - strlen
(val
) + 1)) == NULL
)
5312 err
(1, "pfctl_cmdline_symset: malloc");
5314 strlcpy
(sym
, s
, strlen
(s
) - strlen
(val
) + 1);
5316 ret
= symset
(sym
, val
+ 1, 1);
5323 symget
(const char *nam
)
5327 TAILQ_FOREACH
(sym
, &symhead
, entries
)
5328 if
(strcmp
(nam
, sym
->nam
) == 0) {
5336 mv_rules
(struct pf_ruleset
*src
, struct pf_ruleset
*dst
)
5341 for
(i
= 0; i
< PF_RULESET_MAX
; ++i
) {
5342 while
((r
= TAILQ_FIRST
(src
->rules
[i
].active.ptr
))
5344 TAILQ_REMOVE
(src
->rules
[i
].active.ptr
, r
, entries
);
5345 TAILQ_INSERT_TAIL
(dst
->rules
[i
].active.ptr
, r
, entries
);
5346 dst
->anchor
->match
++;
5348 src
->anchor
->match
= 0;
5349 while
((r
= TAILQ_FIRST
(src
->rules
[i
].inactive.ptr
))
5351 TAILQ_REMOVE
(src
->rules
[i
].inactive.ptr
, r
, entries
);
5352 TAILQ_INSERT_TAIL
(dst
->rules
[i
].inactive.ptr
,
5359 decide_address_family
(struct node_host
*n
, sa_family_t
*af
)
5361 if
(*af
!= 0 || n
== NULL
)
5364 while
((n
= n
->next
) != NULL
) {
5373 remove_invalid_hosts
(struct node_host
**nh
, sa_family_t
*af
)
5375 struct node_host
*n
= *nh
, *prev
= NULL
;
5378 if
(*af
&& n
->af
&& n
->af
!= *af
) {
5379 /* unlink and free n */
5380 struct node_host
*next
= n
->next
;
5382 /* adjust tail pointer */
5383 if
(n
== (*nh
)->tail
)
5385 /* adjust previous node's next pointer */
5391 if
(n
->ifname
!= NULL
)
5405 invalid_redirect
(struct node_host
*nh
, sa_family_t af
)
5408 struct node_host
*n
;
5410 /* tables and dyniftl are ok without an address family */
5411 for
(n
= nh
; n
!= NULL
; n
= n
->next
) {
5412 if
(n
->addr.type
!= PF_ADDR_TABLE
&&
5413 n
->addr.type
!= PF_ADDR_DYNIFTL
) {
5414 yyerror("address family not given and "
5415 "translation address expands to multiple "
5416 "address families");
5422 yyerror("no translation address with matching address family "
5430 atoul
(char *s
, u_long
*ulvalp
)
5436 ulval
= strtoul
(s
, &ep
, 0);
5437 if
(s
[0] == '\0' ||
*ep
!= '\0')
5439 if
(errno
== ERANGE
&& ulval
== ULONG_MAX
)
5451 if
(atoul
(n
, &ulval
) == 0) {
5452 if
(ulval
> 65535) {
5453 yyerror("illegal port value %lu", ulval
);
5456 return
(htons
(ulval
));
5458 s
= getservbyname
(n
, "tcp");
5460 s
= getservbyname
(n
, "udp");
5462 yyerror("unknown port %s", n
);
5470 rule_label
(struct pf_rule
*r
, char *s
)
5473 if
(strlcpy
(r
->label
, s
, sizeof
(r
->label
)) >=
5475 yyerror("rule label too long (max %d chars)",
5476 sizeof
(r
->label
)-1);
5484 parseicmpspec
(char *w
, sa_family_t af
)
5486 const struct icmpcodeent
*p
;
5491 icmptype
= returnicmpdefault
>> 8;
5493 icmptype
= returnicmp6default
>> 8;
5495 if
(atoul
(w
, &ulval
) == -1) {
5496 if
((p
= geticmpcodebyname
(icmptype
, w
, af
)) == NULL
) {
5497 yyerror("unknown icmp code %s", w
);
5503 yyerror("invalid icmp code %lu", ulval
);
5506 return
(icmptype
<< 8 | ulval
);
5510 pfctl_load_anchors
(int dev
, struct pfctl
*pf
, struct pfr_buffer
*trans
)
5512 struct loadanchors
*la
;
5515 TAILQ_FOREACH
(la
, &loadanchorshead
, entries
) {
5516 if
(pf
->opts
& PF_OPT_VERBOSE
)
5517 fprintf
(stderr
, "\nLoading anchor %s from %s\n",
5518 la
->anchorname
, la
->filename
);
5519 if
((fin
= pfctl_fopen
(la
->filename
, "r")) == NULL
) {
5520 warn
("%s", la
->filename
);
5523 if
(pfctl_rules
(dev
, la
->filename
, fin
, pf
->opts
, pf
->optimize
,
5524 la
->anchorname
, trans
) == -1)