1 /* $OpenBSD: parse.y,v 1.549 2008/07/03 16:09:34 deraadt Exp $ */
4 * Copyright (c) 2001 Markus Friedl. All rights reserved.
5 * Copyright (c) 2001 Daniel Hartmeier. All rights reserved.
6 * Copyright (c) 2001 Theo de Raadt. All rights reserved.
7 * Copyright (c) 2002,2003 Henning Brauer. All rights reserved.
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 #include <sys/types.h>
31 #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/pf/pfvar.h>
40 #include <arpa/inet.h>
41 #include <net/altq/altq.h>
42 #include <net/altq/altq_cbq.h>
43 #include <net/altq/altq_priq.h>
44 #include <net/altq/altq_hfsc.h>
45 #include <net/altq/altq_fairq.h>
63 #include "pfctl_parser.h"
66 static struct pfctl
*pf
= NULL
;
68 static int rulestate
= 0;
69 static u_int16_t returnicmpdefault
=
70 (ICMP_UNREACH
<< 8) | ICMP_UNREACH_PORT
;
71 static u_int16_t returnicmp6default
=
72 (ICMP6_DST_UNREACH
<< 8) | ICMP6_DST_UNREACH_NOPORT
;
73 static int blockpolicy
= PFRULE_DROP
;
74 static int require_order
= 1;
75 static int default_statelock
;
76 static int default_keeppolicy_action
;
77 static struct node_state_opt
*default_keeppolicy_options
;
79 TAILQ_HEAD
(files
, file
) files
= TAILQ_HEAD_INITIALIZER
(files
);
81 TAILQ_ENTRY
(file
) entry
;
87 struct file
*pushfile
(const char *, int);
89 int check_file_secrecy
(int, const char *);
91 int yyerror(const char *, ...
) __printflike
(1, 2);
92 int kw_cmp
(const void *, const void *);
98 TAILQ_HEAD
(symhead
, sym
) symhead
= TAILQ_HEAD_INITIALIZER
(symhead
);
100 TAILQ_ENTRY
(sym
) entry
;
106 int symset
(const char *, const char *, int);
107 char *symget
(const char *);
109 int atoul
(char *, u_long
*);
122 struct node_proto
*next
;
123 struct node_proto
*tail
;
129 struct node_port
*next
;
130 struct node_port
*tail
;
136 struct node_uid
*next
;
137 struct node_uid
*tail
;
143 struct node_gid
*next
;
144 struct node_gid
*tail
;
151 struct node_icmp
*next
;
152 struct node_icmp
*tail
;
155 enum { PF_STATE_OPT_MAX
, PF_STATE_OPT_NOSYNC
, PF_STATE_OPT_SRCTRACK
,
156 PF_STATE_OPT_MAX_SRC_STATES
, PF_STATE_OPT_MAX_SRC_CONN
,
157 PF_STATE_OPT_MAX_SRC_CONN_RATE
, PF_STATE_OPT_MAX_SRC_NODES
,
158 PF_STATE_OPT_OVERLOAD
, PF_STATE_OPT_STATELOCK
,
159 PF_STATE_OPT_TIMEOUT
, PF_STATE_OPT_SLOPPY
, PF_STATE_OPT_PICKUPS
};
161 enum { PF_SRCTRACK_NONE
, PF_SRCTRACK
, PF_SRCTRACK_GLOBAL
, PF_SRCTRACK_RULE
};
163 struct node_state_opt
{
166 u_int32_t max_states
;
167 u_int32_t max_src_states
;
168 u_int32_t max_src_conn
;
175 char tblname
[PF_TABLE_NAME_SIZE
];
177 u_int32_t max_src_nodes
;
179 u_int8_t pickup_mode
;
186 struct node_state_opt
*next
;
187 struct node_state_opt
*tail
;
191 struct node_host
*host
;
192 struct node_port
*port
;
196 char queue
[PF_QNAME_SIZE
];
197 char parent
[PF_QNAME_SIZE
];
198 char ifname
[IFNAMSIZ
];
200 struct node_queue
*next
;
201 struct node_queue
*tail
;
204 struct node_qassign
{
211 #define FOM_FLAGS 0x01
212 #define FOM_ICMP 0x02
214 #define FOM_KEEP 0x08
215 #define FOM_SRCTRACK 0x10
216 struct node_uid
*uid
;
217 struct node_gid
*gid
;
224 struct node_icmp
*icmpspec
;
229 struct node_state_opt
*options
;
234 struct node_qassign queues
;
237 u_int8_t match_tag_not
;
240 struct node_host
*addr
;
245 struct antispoof_opts
{
252 #define SOM_MINTTL 0x01
253 #define SOM_MAXMSS 0x02
254 #define SOM_FRAGCACHE 0x04
255 #define SOM_SETTOS 0x08
264 u_int8_t match_tag_not
;
270 #define QOM_BWSPEC 0x01
271 #define QOM_SCHEDULER 0x02
272 #define QOM_PRIORITY 0x04
273 #define QOM_TBRSIZE 0x08
274 #define QOM_QLIMIT 0x10
275 struct node_queue_bw queue_bwspec
;
276 struct node_queue_opt scheduler
;
285 struct node_tinithead init_nodes
;
290 #define POM_TYPE 0x01
291 #define POM_STICKYADDRESS 0x02
295 struct pf_poolhashkey
*key
;
300 struct node_hfsc_opts hfsc_opts
;
301 struct node_fairq_opts fairq_opts
;
303 int disallow_table
(struct node_host
*, const char *);
304 int disallow_urpf_failed
(struct node_host
*, const char *);
305 int disallow_alias
(struct node_host
*, const char *);
306 int rule_consistent
(struct pf_rule
*, int);
307 int filter_consistent
(struct pf_rule
*, int);
308 int nat_consistent
(struct pf_rule
*);
309 int rdr_consistent
(struct pf_rule
*);
310 int process_tabledef
(char *, struct table_opts
*);
311 void expand_label_str
(char *, size_t, const char *, const char *);
312 void expand_label_if
(const char *, char *, size_t, const char *);
313 void expand_label_addr
(const char *, char *, size_t, u_int8_t
,
315 void expand_label_port
(const char *, char *, size_t,
317 void expand_label_proto
(const char *, char *, size_t, u_int8_t
);
318 void expand_label_nr
(const char *, char *, size_t);
319 void expand_label
(char *, size_t, const char *, u_int8_t
,
320 struct node_host
*, struct node_port
*, struct node_host
*,
321 struct node_port
*, u_int8_t
);
322 void expand_rule
(struct pf_rule
*, struct node_if
*,
323 struct node_host
*, struct node_proto
*, struct node_os
*,
324 struct node_host
*, struct node_port
*, struct node_host
*,
325 struct node_port
*, struct node_uid
*, struct node_gid
*,
326 struct node_icmp
*, const char *);
327 int expand_altq
(struct pf_altq
*, struct node_if
*,
328 struct node_queue
*, struct node_queue_bw bwspec
,
329 struct node_queue_opt
*);
330 int expand_queue
(struct pf_altq
*, struct node_if
*,
331 struct node_queue
*, struct node_queue_bw
,
332 struct node_queue_opt
*);
333 int expand_skip_interface
(struct node_if
*);
335 int check_rulestate
(int);
336 int getservice
(char *);
337 int rule_label
(struct pf_rule
*, char *);
339 void mv_rules
(struct pf_ruleset
*, struct pf_ruleset
*);
340 void decide_address_family
(struct node_host
*, sa_family_t
*);
341 void remove_invalid_hosts
(struct node_host
**, sa_family_t
*);
342 int invalid_redirect
(struct node_host
*, sa_family_t
);
343 u_int16_t parseicmpspec
(char *, sa_family_t
);
345 TAILQ_HEAD
(loadanchorshead
, loadanchors
)
346 loadanchorshead
= TAILQ_HEAD_INITIALIZER
(loadanchorshead
);
349 TAILQ_ENTRY
(loadanchors
) entries
;
372 struct node_if
*interface
;
373 struct node_proto
*proto
;
374 struct node_icmp
*icmp
;
375 struct node_host
*host
;
377 struct node_port
*port
;
378 struct node_uid
*uid
;
379 struct node_gid
*gid
;
380 struct node_state_opt
*state_opt
;
383 struct peer src
, dst
;
384 struct node_os
*src_os
;
387 struct node_host
*host
;
391 struct pf_poolhashkey
*key
;
394 struct node_host
*host
;
399 struct node_state_opt
*options
;
410 struct pf_poolhashkey
*hashkey
;
411 struct node_queue
*queue
;
412 struct node_queue_opt queue_options
;
413 struct node_queue_bw queue_bwspec
;
414 struct node_qassign qassign
;
415 struct filter_opts filter_opts
;
416 struct antispoof_opts antispoof_opts
;
417 struct queue_opts queue_opts
;
418 struct scrub_opts scrub_opts
;
419 struct table_opts table_opts
;
420 struct pool_opts pool_opts
;
421 struct node_hfsc_opts hfsc_opts
;
422 struct node_fairq_opts fairq_opts
;
427 #define PPORT_RANGE 1
429 int parseport
(char *, struct range
*r
, int);
431 #define DYNIF_MULTIADDR(addr) ((addr).type == PF_ADDR_DYNIFTL && \
432 (!((addr
).iflags
& PFI_AFLAG_NOALIAS
) || \
433 !isdigit
((addr
).v.ifname
[strlen
((addr
).v.ifname
)-1])))
439 %token PASS BLOCK SCRUB RETURN IN OS OUT LOG QUICK ON FROM TO FLAGS
440 %token RETURNRST RETURNICMP RETURNICMP6 PROTO INET INET6 ALL ANY ICMPTYPE
441 %token ICMP6TYPE CODE KEEP MODULATE STATE PORT RDR NAT BINAT ARROW NODF
442 %token MINTTL ERROR ALLOWOPTS FASTROUTE FILENAME ROUTETO DUPTO REPLYTO NO LABEL
443 %token NOROUTE URPFFAILED FRAGMENT USER GROUP MAXMSS MAXIMUM TTL TOS DROP TABLE
444 %token REASSEMBLE FRAGDROP FRAGCROP ANCHOR NATANCHOR RDRANCHOR BINATANCHOR
445 %token SET OPTIMIZATION TIMEOUT LIMIT LOGINTERFACE BLOCKPOLICY RANDOMID
446 %token REQUIREORDER SYNPROXY FINGERPRINTS NOSYNC DEBUG SKIP HOSTID
447 %token ANTISPOOF FOR INCLUDE
448 %token BITMASK RANDOM SOURCEHASH ROUNDROBIN STATICPORT PROBABILITY
449 %token ALTQ CBQ PRIQ HFSC FAIRQ BANDWIDTH TBRSIZE LINKSHARE REALTIME UPPERLIMIT
450 %token QUEUE PRIORITY QLIMIT RTABLE HOGS BUCKETS
451 %token LOAD RULESET_OPTIMIZATION
452 %token PICKUPS NOPICKUPS HASHONLY
453 %token STICKYADDRESS MAXSRCSTATES MAXSRCNODES SOURCETRACK GLOBAL RULE
454 %token MAXSRCCONN MAXSRCCONNRATE OVERLOAD FLUSH SLOPPY
455 %token TAGGED TAG IFBOUND FLOATING STATEPOLICY ROUTE SETTOS KEEPPOLICY
456 %token DIVERTTO DIVERTREPLY
457 %token
<v.
string> STRING
458 %token
<v.number
> NUMBER
459 %token
<v.i
> PORTBINARY
460 %type
<v.interface
> interface if_list if_item_not if_item
461 %type
<v.number
> number icmptype icmp6type uid gid
462 %type
<v.number
> tos not yesno
463 %type
<v.probability
> probability
464 %type
<v.i
> no dir af fragcache optimizer
465 %type
<v.i
> sourcetrack flush unaryop statelock
466 %type
<v.b
> action nataction natpasslog scrubaction
467 %type
<v.b
> flags flag blockspec
468 %type
<v.range
> portplain portstar portrange
469 %type
<v.hashkey
> hashkey
470 %type
<v.proto
> proto proto_list proto_item
471 %type
<v.number
> protoval
472 %type
<v.icmp
> icmpspec
473 %type
<v.icmp
> icmp_list icmp_item
474 %type
<v.icmp
> icmp6_list icmp6_item
475 %type
<v.number
> reticmpspec reticmp6spec
476 %type
<v.fromto
> fromto
477 %type
<v.peer
> ipportspec from to
478 %type
<v.host
> ipspec toipspec xhost host dynaddr host_list
479 %type
<v.host
> redir_host_list redirspec
480 %type
<v.host
> route_host route_host_list routespec
481 %type
<v.os
> os xos os_list
482 %type
<v.port
> portspec port_list port_item
483 %type
<v.uid
> uids uid_list uid_item
484 %type
<v.gid
> gids gid_list gid_item
485 %type
<v.route
> route
486 %type
<v.redirection
> redirection redirpool
487 %type
<v.
string> label stringall tag anchorname
488 %type
<v.
string> string varstring numberstring
489 %type
<v.keep_state
> keep
490 %type
<v.state_opt
> state_opt_spec state_opt_list state_opt_item
491 %type
<v.logquick
> logquick quick log logopts logopt
492 %type
<v.interface
> antispoof_ifspc antispoof_iflst antispoof_if
493 %type
<v.qassign
> qname
494 %type
<v.queue
> qassign qassign_list qassign_item
495 %type
<v.queue_options
> scheduler
496 %type
<v.number
> cbqflags_list cbqflags_item
497 %type
<v.number
> priqflags_list priqflags_item
498 %type
<v.hfsc_opts
> hfscopts_list hfscopts_item hfsc_opts
499 %type
<v.fairq_opts
> fairqopts_list fairqopts_item fairq_opts
500 %type
<v.queue_bwspec
> bandwidth
501 %type
<v.filter_opts
> filter_opts filter_opt filter_opts_l
502 %type
<v.antispoof_opts
> antispoof_opts antispoof_opt antispoof_opts_l
503 %type
<v.queue_opts
> queue_opts queue_opt queue_opts_l
504 %type
<v.scrub_opts
> scrub_opts scrub_opt scrub_opts_l
505 %type
<v.table_opts
> table_opts table_opt table_opts_l
506 %type
<v.pool_opts
> pool_opts pool_opt pool_opts_l
507 %type
<v.tagged
> tagged
508 %type
<v.rtableid
> rtable
511 ruleset
: /* empty */
512 | ruleset include
'\n'
514 | ruleset option
'\n'
515 | ruleset scrubrule
'\n'
516 | ruleset natrule
'\n'
517 | ruleset binatrule
'\n'
518 | ruleset pfrule
'\n'
519 | ruleset anchorrule
'\n'
520 | ruleset loadrule
'\n'
521 | ruleset altqif
'\n'
522 | ruleset queuespec
'\n'
523 | ruleset varset
'\n'
524 | ruleset antispoof
'\n'
525 | ruleset tabledef
'\n'
526 |
'{' fakeanchor
'}' '\n';
527 | ruleset
error '\n' { file
->errors
++; }
530 include
: INCLUDE STRING
{
533 if
((nfile
= pushfile
($2, 0)) == NULL
) {
534 yyerror("failed to include file %s", $2);
546 * apply to previouslys specified rule: must be careful to note
547 * what that is: pf or nat or binat or rdr
549 fakeanchor
: fakeanchor
'\n'
550 | fakeanchor anchorrule
'\n'
551 | fakeanchor binatrule
'\n'
552 | fakeanchor natrule
'\n'
553 | fakeanchor pfrule
'\n'
554 | fakeanchor
error '\n'
558 if
(!strcmp
($1, "none"))
560 else if
(!strcmp
($1, "basic"))
561 $$
= PF_OPTIMIZE_BASIC
;
562 else if
(!strcmp
($1, "profile"))
563 $$
= PF_OPTIMIZE_BASIC | PF_OPTIMIZE_PROFILE
;
565 yyerror("unknown ruleset-optimization %s", $1);
571 option
: SET OPTIMIZATION STRING
{
572 if
(check_rulestate
(PFCTL_STATE_OPTION
)) {
576 if
(pfctl_set_optimization
(pf
, $3) != 0) {
577 yyerror("unknown optimization %s", $3);
583 | SET RULESET_OPTIMIZATION optimizer
{
584 if
(!(pf
->opts
& PF_OPT_OPTIMIZE
)) {
585 pf
->opts |
= PF_OPT_OPTIMIZE
;
589 | SET TIMEOUT timeout_spec
590 | SET TIMEOUT
'{' optnl timeout_list
'}'
591 | SET LIMIT limit_spec
592 | SET LIMIT
'{' optnl limit_list
'}'
593 | SET LOGINTERFACE stringall
{
594 if
(check_rulestate
(PFCTL_STATE_OPTION
)) {
598 if
(pfctl_set_logif
(pf
, $3) != 0) {
599 yyerror("error setting loginterface %s", $3);
605 | SET HOSTID number
{
606 if
($3 == 0 ||
$3 > UINT_MAX
) {
607 yyerror("hostid must be non-zero");
610 if
(pfctl_set_hostid
(pf
, $3) != 0) {
611 yyerror("error setting hostid %08" PRId64
, $3);
615 | SET BLOCKPOLICY DROP
{
616 if
(pf
->opts
& PF_OPT_VERBOSE
)
617 printf
("set block-policy drop\n");
618 if
(check_rulestate
(PFCTL_STATE_OPTION
))
620 blockpolicy
= PFRULE_DROP
;
622 | SET BLOCKPOLICY RETURN
{
623 if
(pf
->opts
& PF_OPT_VERBOSE
)
624 printf
("set block-policy return\n");
625 if
(check_rulestate
(PFCTL_STATE_OPTION
))
627 blockpolicy
= PFRULE_RETURN
;
629 | SET REQUIREORDER yesno
{
630 if
(pf
->opts
& PF_OPT_VERBOSE
)
631 printf
("set require-order %s\n",
632 $3 == 1 ?
"yes" : "no");
635 | SET FINGERPRINTS STRING
{
636 if
(pf
->opts
& PF_OPT_VERBOSE
)
637 printf
("set fingerprints \"%s\"\n", $3);
638 if
(check_rulestate
(PFCTL_STATE_OPTION
)) {
642 if
(!pf
->anchor
->name
[0]) {
643 if
(pfctl_file_fingerprints
(pf
->dev
,
645 yyerror("error loading "
646 "fingerprints %s", $3);
653 | SET STATEPOLICY statelock
{
654 if
(pf
->opts
& PF_OPT_VERBOSE
)
657 printf
("set state-policy floating\n");
660 printf
("set state-policy if-bound\n");
663 default_statelock
= $3;
665 | SET KEEPPOLICY keep
{
666 if
(pf
->opts
& PF_OPT_VERBOSE
)
667 printf
("A default keeppolicy was set\n");
668 default_keeppolicy_action
= $3.action
;
669 default_keeppolicy_options
= $3.options
;
672 if
(check_rulestate
(PFCTL_STATE_OPTION
)) {
676 if
(pfctl_set_debug
(pf
, $3) != 0) {
677 yyerror("error setting debuglevel %s", $3);
683 | SET SKIP interface
{
684 if
(expand_skip_interface
($3) != 0) {
685 yyerror("error setting skip interface(s)");
691 stringall
: STRING
{ $$
= $1; }
693 if
(($$
= strdup
("all")) == NULL
) {
694 err
(1, "stringall: strdup");
699 string : STRING
string {
700 if
(asprintf
(&$$
, "%s %s", $1, $2) == -1)
701 err
(1, "string: asprintf");
708 varstring
: numberstring varstring
{
709 if
(asprintf
(&$$
, "%s %s", $1, $2) == -1)
710 err
(1, "string: asprintf");
717 numberstring
: NUMBER
{
719 if
(asprintf
(&s
, "%" PRId64
, $1) == -1) {
720 yyerror("string: asprintf");
728 varset
: STRING
'=' varstring
{
729 if
(pf
->opts
& PF_OPT_VERBOSE
)
730 printf
("%s = \"%s\"\n", $1, $3);
731 if
(symset
($1, $3, 0) == -1)
732 err
(1, "cannot store variable %s", $1);
738 anchorname
: STRING
{ $$
= $1; }
739 |
/* empty */ { $$
= NULL
; }
742 pfa_anchorlist
: /* empty */
743 | pfa_anchorlist
'\n'
744 | pfa_anchorlist pfrule
'\n'
745 | pfa_anchorlist anchorrule
'\n'
750 char ta
[PF_ANCHOR_NAME_SIZE
];
751 struct pf_ruleset
*rs
;
753 /* steping into a brace anchor */
758 /* create a holding ruleset in the root */
759 snprintf
(ta
, PF_ANCHOR_NAME_SIZE
, "_%d", pf
->bn
);
760 rs
= pf_find_or_create_ruleset
(ta
);
762 err
(1, "pfa_anchor: pf_find_or_create_ruleset");
763 pf
->astack
[pf
->asd
] = rs
->anchor
;
764 pf
->anchor
= rs
->anchor
;
765 } '\n' pfa_anchorlist
'}'
767 pf
->alast
= pf
->anchor
;
769 pf
->anchor
= pf
->astack
[pf
->asd
];
774 anchorrule
: ANCHOR anchorname dir quick interface af proto fromto
775 filter_opts pfa_anchor
778 struct node_proto
*proto
;
780 if
(check_rulestate
(PFCTL_STATE_FILTER
)) {
786 if
($2 && ($2[0] == '_' || strstr
($2, "/_") != NULL
)) {
788 yyerror("anchor names beginning with '_' "
789 "are reserved for internal use");
793 memset
(&r
, 0, sizeof
(r
));
794 if
(pf
->astack
[pf
->asd
+ 1]) {
795 /* move inline rules into relative location */
797 &pf
->astack
[pf
->asd
]->ruleset
,
798 $2 ?
$2 : pf
->alast
->name
);
800 if
(r.anchor
== NULL
)
801 err
(1, "anchorrule: unable to "
804 if
(pf
->alast
!= r.anchor
) {
805 if
(r.anchor
->match
) {
806 yyerror("inline anchor '%s' "
811 mv_rules
(&pf
->alast
->ruleset
,
814 pf_remove_if_empty_ruleset
(&pf
->alast
->ruleset
);
815 pf
->alast
= r.anchor
;
818 yyerror("anchors without explicit "
819 "rules must specify a name");
827 r.rtableid
= $9.rtableid
;
830 if
(strlcpy
(r.tagname
, $9.tag
,
831 PF_TAG_NAME_SIZE
) >= PF_TAG_NAME_SIZE
) {
832 yyerror("tag too long, max %u chars",
833 PF_TAG_NAME_SIZE
- 1);
837 if
(strlcpy
(r.match_tagname
, $9.match_tag
,
838 PF_TAG_NAME_SIZE
) >= PF_TAG_NAME_SIZE
) {
839 yyerror("tag too long, max %u chars",
840 PF_TAG_NAME_SIZE
- 1);
843 r.match_tag_not
= $9.match_tag_not
;
844 if
(rule_label
(&r
, $9.label
))
847 r.flags
= $9.flags.b1
;
848 r.flagset
= $9.flags.b2
;
849 if
(($9.flags.b1
& $9.flags.b2
) != $9.flags.b1
) {
850 yyerror("flags always false");
853 if
($9.flags.b1 ||
$9.flags.b2 ||
$8.src_os
) {
854 for
(proto
= $7; proto
!= NULL
&&
855 proto
->proto
!= IPPROTO_TCP
;
858 if
(proto
== NULL
&& $7 != NULL
) {
859 if
($9.flags.b1 ||
$9.flags.b2
)
861 "flags only apply to tcp");
864 "OS fingerprinting only "
872 if
($9.keep.action
) {
873 yyerror("cannot specify state handling "
879 if
(strlcpy
(r.match_tagname
, $9.match_tag
,
880 PF_TAG_NAME_SIZE
) >= PF_TAG_NAME_SIZE
) {
881 yyerror("tag too long, max %u chars",
882 PF_TAG_NAME_SIZE
- 1);
885 r.match_tag_not
= $9.match_tag_not
;
887 decide_address_family
($8.src.host
, &r.af
);
888 decide_address_family
($8.dst.host
, &r.af
);
890 expand_rule
(&r
, $5, NULL
, $7, $8.src_os
,
891 $8.src.host
, $8.src.port
, $8.dst.host
, $8.dst.port
,
892 $9.uid
, $9.gid
, $9.icmpspec
,
893 pf
->astack
[pf
->asd
+ 1] ? pf
->alast
->name
: $2);
895 pf
->astack
[pf
->asd
+ 1] = NULL
;
897 | NATANCHOR
string interface af proto fromto rtable
{
900 if
(check_rulestate
(PFCTL_STATE_NAT
)) {
905 memset
(&r
, 0, sizeof
(r
));
910 decide_address_family
($6.src.host
, &r.af
);
911 decide_address_family
($6.dst.host
, &r.af
);
913 expand_rule
(&r
, $3, NULL
, $5, $6.src_os
,
914 $6.src.host
, $6.src.port
, $6.dst.host
, $6.dst.port
,
918 | RDRANCHOR
string interface af proto fromto rtable
{
921 if
(check_rulestate
(PFCTL_STATE_NAT
)) {
926 memset
(&r
, 0, sizeof
(r
));
931 decide_address_family
($6.src.host
, &r.af
);
932 decide_address_family
($6.dst.host
, &r.af
);
934 if
($6.src.port
!= NULL
) {
935 yyerror("source port parameter not supported"
939 if
($6.dst.port
!= NULL
) {
940 if
($6.dst.port
->next
!= NULL
) {
941 yyerror("destination port list "
942 "expansion not supported in "
945 } else if
($6.dst.port
->op
!= PF_OP_EQ
) {
946 yyerror("destination port operators"
947 " not supported in rdr-anchor");
950 r.dst.port
[0] = $6.dst.port
->port
[0];
951 r.dst.port
[1] = $6.dst.port
->port
[1];
952 r.dst.port_op
= $6.dst.port
->op
;
955 expand_rule
(&r
, $3, NULL
, $5, $6.src_os
,
956 $6.src.host
, $6.src.port
, $6.dst.host
, $6.dst.port
,
960 | BINATANCHOR
string interface af proto fromto rtable
{
963 if
(check_rulestate
(PFCTL_STATE_NAT
)) {
968 memset
(&r
, 0, sizeof
(r
));
973 if
($5->next
!= NULL
) {
974 yyerror("proto list expansion"
975 " not supported in binat-anchor");
982 if
($6.src.host
!= NULL ||
$6.src.port
!= NULL ||
983 $6.dst.host
!= NULL ||
$6.dst.port
!= NULL
) {
984 yyerror("fromto parameter not supported"
989 decide_address_family
($6.src.host
, &r.af
);
990 decide_address_family
($6.dst.host
, &r.af
);
992 pfctl_add_rule
(pf
, &r
, $2);
997 loadrule
: LOAD ANCHOR
string FROM
string {
998 struct loadanchors
*loadanchor
;
1000 if
(strlen
(pf
->anchor
->name
) + 1 +
1001 strlen
($3) >= MAXPATHLEN
) {
1002 yyerror("anchorname %s too long, max %u\n",
1003 $3, MAXPATHLEN
- 1);
1007 loadanchor
= calloc
(1, sizeof
(struct loadanchors
));
1008 if
(loadanchor
== NULL
)
1009 err
(1, "loadrule: calloc");
1010 if
((loadanchor
->anchorname
= malloc
(MAXPATHLEN
)) ==
1012 err
(1, "loadrule: malloc");
1013 if
(pf
->anchor
->name
[0])
1014 snprintf
(loadanchor
->anchorname
, MAXPATHLEN
,
1015 "%s/%s", pf
->anchor
->name
, $3);
1017 strlcpy
(loadanchor
->anchorname
, $3, MAXPATHLEN
);
1018 if
((loadanchor
->filename
= strdup
($5)) == NULL
)
1019 err
(1, "loadrule: strdup");
1021 TAILQ_INSERT_TAIL
(&loadanchorshead
, loadanchor
,
1028 scrubaction
: no SCRUB
{
1037 scrubrule
: scrubaction dir logquick interface af proto fromto scrub_opts
1041 if
(check_rulestate
(PFCTL_STATE_SCRUB
))
1044 memset
(&r
, 0, sizeof
(r
));
1052 yyerror("scrub rules do not support 'quick'");
1058 r.rule_flag |
= PFRULE_NODF
;
1060 r.rule_flag |
= PFRULE_RANDOMID
;
1061 if
($8.reassemble_tcp
) {
1062 if
(r.direction
!= PF_INOUT
) {
1063 yyerror("reassemble tcp rules can not "
1064 "specify direction");
1067 r.rule_flag |
= PFRULE_REASSEMBLE_TCP
;
1070 r.min_ttl
= $8.minttl
;
1072 r.max_mss
= $8.maxmss
;
1073 if
($8.marker
& SOM_SETTOS
) {
1074 r.rule_flag |
= PFRULE_SET_TOS
;
1075 r.set_tos
= $8.settos
;
1078 r.rule_flag |
= $8.fragcache
;
1080 if
(strlcpy
(r.match_tagname
, $8.match_tag
,
1081 PF_TAG_NAME_SIZE
) >= PF_TAG_NAME_SIZE
) {
1082 yyerror("tag too long, max %u chars",
1083 PF_TAG_NAME_SIZE
- 1);
1086 r.match_tag_not
= $8.match_tag_not
;
1087 r.rtableid
= $8.rtableid
;
1089 expand_rule
(&r
, $4, NULL
, $6, $7.src_os
,
1090 $7.src.host
, $7.src.port
, $7.dst.host
, $7.dst.port
,
1091 NULL
, NULL
, NULL
, "");
1096 bzero
(&scrub_opts
, sizeof scrub_opts
);
1097 scrub_opts.rtableid
= -1;
1100 { $$
= scrub_opts
; }
1102 bzero
(&scrub_opts
, sizeof scrub_opts
);
1103 scrub_opts.rtableid
= -1;
1108 scrub_opts_l
: scrub_opts_l scrub_opt
1113 if
(scrub_opts.nodf
) {
1114 yyerror("no-df cannot be respecified");
1117 scrub_opts.nodf
= 1;
1120 if
(scrub_opts.marker
& SOM_MINTTL
) {
1121 yyerror("min-ttl cannot be respecified");
1124 if
($2 < 0 ||
$2 > 255) {
1125 yyerror("illegal min-ttl value %" PRId64
, $2);
1128 scrub_opts.marker |
= SOM_MINTTL
;
1129 scrub_opts.minttl
= $2;
1132 if
(scrub_opts.marker
& SOM_MAXMSS
) {
1133 yyerror("max-mss cannot be respecified");
1136 if
($2 < 0 ||
$2 > 65535) {
1137 yyerror("illegal max-mss value %" PRId64
, $2);
1140 scrub_opts.marker |
= SOM_MAXMSS
;
1141 scrub_opts.maxmss
= $2;
1144 if
(scrub_opts.marker
& SOM_SETTOS
) {
1145 yyerror("set-tos cannot be respecified");
1148 scrub_opts.marker |
= SOM_SETTOS
;
1149 scrub_opts.settos
= $2;
1152 if
(scrub_opts.marker
& SOM_FRAGCACHE
) {
1153 yyerror("fragcache cannot be respecified");
1156 scrub_opts.marker |
= SOM_FRAGCACHE
;
1157 scrub_opts.fragcache
= $1;
1159 | REASSEMBLE STRING
{
1160 if
(strcasecmp
($2, "tcp") != 0) {
1161 yyerror("scrub reassemble supports only tcp, "
1167 if
(scrub_opts.reassemble_tcp
) {
1168 yyerror("reassemble tcp cannot be respecified");
1171 scrub_opts.reassemble_tcp
= 1;
1174 if
(scrub_opts.randomid
) {
1175 yyerror("random-id cannot be respecified");
1178 scrub_opts.randomid
= 1;
1181 scrub_opts.rtableid
= $2;
1183 | not TAGGED
string {
1184 scrub_opts.match_tag
= $3;
1185 scrub_opts.match_tag_not
= $1;
1189 fragcache
: FRAGMENT REASSEMBLE
{ $$
= 0; /* default */ }
1190 | FRAGMENT FRAGCROP
{ $$
= PFRULE_FRAGCROP
; }
1191 | FRAGMENT FRAGDROP
{ $$
= PFRULE_FRAGDROP
; }
1194 antispoof
: ANTISPOOF logquick antispoof_ifspc af antispoof_opts
{
1196 struct node_host
*h
= NULL
, *hh
;
1197 struct node_if
*i
, *j
;
1199 if
(check_rulestate
(PFCTL_STATE_FILTER
))
1202 for
(i
= $3; i
; i
= i
->next
) {
1203 bzero
(&r
, sizeof
(r
));
1206 r.direction
= PF_IN
;
1211 if
(rule_label
(&r
, $5.label
))
1213 r.rtableid
= $5.rtableid
;
1214 j
= calloc
(1, sizeof
(struct node_if
));
1216 err
(1, "antispoof: calloc");
1217 if
(strlcpy
(j
->ifname
, i
->ifname
,
1218 sizeof
(j
->ifname
)) >= sizeof
(j
->ifname
)) {
1220 yyerror("interface name too long");
1225 h
= calloc
(1, sizeof
(*h
));
1227 err
(1, "address: calloc");
1228 h
->addr.type
= PF_ADDR_DYNIFTL
;
1230 if
(strlcpy
(h
->addr.v.ifname
, i
->ifname
,
1231 sizeof
(h
->addr.v.ifname
)) >=
1232 sizeof
(h
->addr.v.ifname
)) {
1235 "interface name too long");
1238 hh
= malloc
(sizeof
(*hh
));
1240 err
(1, "address: malloc");
1241 bcopy
(h
, hh
, sizeof
(*hh
));
1242 h
->addr.iflags
= PFI_AFLAG_NETWORK
;
1244 h
= ifa_lookup
(j
->ifname
,
1250 expand_rule
(&r
, j
, NULL
, NULL
, NULL
, h
,
1251 NULL
, NULL
, NULL
, NULL
, NULL
,
1254 if
((i
->ifa_flags
& IFF_LOOPBACK
) == 0) {
1255 bzero
(&r
, sizeof
(r
));
1258 r.direction
= PF_IN
;
1262 if
(rule_label
(&r
, $5.label
))
1264 r.rtableid
= $5.rtableid
;
1268 h
= ifa_lookup
(i
->ifname
, 0);
1270 expand_rule
(&r
, NULL
, NULL
,
1271 NULL
, NULL
, h
, NULL
, NULL
,
1272 NULL
, NULL
, NULL
, NULL
, "");
1280 antispoof_ifspc
: FOR antispoof_if
{ $$
= $2; }
1281 | FOR
'{' optnl antispoof_iflst
'}' { $$
= $4; }
1284 antispoof_iflst
: antispoof_if optnl
{ $$
= $1; }
1285 | antispoof_iflst comma antispoof_if optnl
{
1286 $1->tail
->next
= $3;
1292 antispoof_if
: if_item
{ $$
= $1; }
1300 bzero
(&antispoof_opts
, sizeof antispoof_opts
);
1301 antispoof_opts.rtableid
= -1;
1304 { $$
= antispoof_opts
; }
1306 bzero
(&antispoof_opts
, sizeof antispoof_opts
);
1307 antispoof_opts.rtableid
= -1;
1308 $$
= antispoof_opts
;
1312 antispoof_opts_l
: antispoof_opts_l antispoof_opt
1316 antispoof_opt
: label
{
1317 if
(antispoof_opts.label
) {
1318 yyerror("label cannot be redefined");
1321 antispoof_opts.label
= $1;
1324 antispoof_opts.rtableid
= $2;
1328 not
: '!' { $$
= 1; }
1329 |
/* empty */ { $$
= 0; }
1332 tabledef
: TABLE
'<' STRING
'>' table_opts
{
1333 struct node_host
*h
, *nh
;
1334 struct node_tinit
*ti
, *nti
;
1336 if
(strlen
($3) >= PF_TABLE_NAME_SIZE
) {
1337 yyerror("table name too long, max %d chars",
1338 PF_TABLE_NAME_SIZE
- 1);
1342 if
(pf
->loadopt
& PFCTL_FLAG_TABLE
)
1343 if
(process_tabledef
($3, &$5)) {
1348 for
(ti
= SIMPLEQ_FIRST
(&$5.init_nodes
);
1349 ti
!= SIMPLEQ_END
(&$5.init_nodes
); ti
= nti
) {
1352 for
(h
= ti
->host
; h
!= NULL
; h
= nh
) {
1356 nti
= SIMPLEQ_NEXT
(ti
, entries
);
1363 bzero
(&table_opts
, sizeof table_opts
);
1364 SIMPLEQ_INIT
(&table_opts.init_nodes
);
1367 { $$
= table_opts
; }
1370 bzero
(&table_opts
, sizeof table_opts
);
1371 SIMPLEQ_INIT
(&table_opts.init_nodes
);
1376 table_opts_l
: table_opts_l table_opt
1380 table_opt
: STRING
{
1381 if
(!strcmp
($1, "const"))
1382 table_opts.flags |
= PFR_TFLAG_CONST
;
1383 else if
(!strcmp
($1, "persist"))
1384 table_opts.flags |
= PFR_TFLAG_PERSIST
;
1385 else if
(!strcmp
($1, "counters"))
1386 table_opts.flags |
= PFR_TFLAG_COUNTERS
;
1388 yyerror("invalid table option '%s'", $1);
1394 |
'{' optnl
'}' { table_opts.init_addr
= 1; }
1395 |
'{' optnl host_list
'}' {
1396 struct node_host
*n
;
1397 struct node_tinit
*ti
;
1399 for
(n
= $3; n
!= NULL
; n
= n
->next
) {
1400 switch
(n
->addr.type
) {
1401 case PF_ADDR_ADDRMASK
:
1404 yyerror("address ranges are not "
1405 "permitted inside tables");
1407 case PF_ADDR_DYNIFTL
:
1408 yyerror("dynamic addresses are not "
1409 "permitted inside tables");
1412 yyerror("tables cannot contain tables");
1414 case PF_ADDR_NOROUTE
:
1415 yyerror("\"no-route\" is not permitted "
1418 case PF_ADDR_URPFFAILED
:
1419 yyerror("\"urpf-failed\" is not "
1420 "permitted inside tables");
1423 yyerror("unknown address type %d",
1428 if
(!(ti
= calloc
(1, sizeof
(*ti
))))
1429 err
(1, "table_opt: calloc");
1431 SIMPLEQ_INSERT_TAIL
(&table_opts.init_nodes
, ti
,
1433 table_opts.init_addr
= 1;
1436 struct node_tinit
*ti
;
1438 if
(!(ti
= calloc
(1, sizeof
(*ti
))))
1439 err
(1, "table_opt: calloc");
1441 SIMPLEQ_INSERT_TAIL
(&table_opts.init_nodes
, ti
,
1443 table_opts.init_addr
= 1;
1447 altqif
: ALTQ interface queue_opts QUEUE qassign
{
1450 if
(check_rulestate
(PFCTL_STATE_QUEUE
))
1453 memset
(&a
, 0, sizeof
(a
));
1454 if
($3.scheduler.qtype
== ALTQT_NONE
) {
1455 yyerror("no scheduler specified!");
1458 a.scheduler
= $3.scheduler.qtype
;
1459 a.qlimit
= $3.qlimit
;
1460 a.tbrsize
= $3.tbrsize
;
1462 yyerror("no child queues specified");
1465 if
(expand_altq
(&a
, $2, $5, $3.queue_bwspec
,
1471 queuespec
: QUEUE STRING interface queue_opts qassign
{
1474 if
(check_rulestate
(PFCTL_STATE_QUEUE
)) {
1479 memset
(&a
, 0, sizeof
(a
));
1481 if
(strlcpy
(a.qname
, $2, sizeof
(a.qname
)) >=
1483 yyerror("queue name too long (max "
1484 "%d chars)", PF_QNAME_SIZE
-1);
1490 yyerror("cannot specify tbrsize for queue");
1493 if
($4.priority
> 255) {
1494 yyerror("priority out of range: max 255");
1497 a.priority
= $4.priority
;
1498 a.qlimit
= $4.qlimit
;
1499 a.scheduler
= $4.scheduler.qtype
;
1500 if
(expand_queue
(&a
, $3, $5, $4.queue_bwspec
,
1502 yyerror("errors in queue definition");
1509 bzero
(&queue_opts
, sizeof queue_opts
);
1510 queue_opts.priority
= DEFAULT_PRIORITY
;
1511 queue_opts.qlimit
= DEFAULT_QLIMIT
;
1512 queue_opts.scheduler.qtype
= ALTQT_NONE
;
1513 queue_opts.queue_bwspec.bw_percent
= 100;
1516 { $$
= queue_opts
; }
1518 bzero
(&queue_opts
, sizeof queue_opts
);
1519 queue_opts.priority
= DEFAULT_PRIORITY
;
1520 queue_opts.qlimit
= DEFAULT_QLIMIT
;
1521 queue_opts.scheduler.qtype
= ALTQT_NONE
;
1522 queue_opts.queue_bwspec.bw_percent
= 100;
1527 queue_opts_l
: queue_opts_l queue_opt
1531 queue_opt
: BANDWIDTH bandwidth
{
1532 if
(queue_opts.marker
& QOM_BWSPEC
) {
1533 yyerror("bandwidth cannot be respecified");
1536 queue_opts.marker |
= QOM_BWSPEC
;
1537 queue_opts.queue_bwspec
= $2;
1540 if
(queue_opts.marker
& QOM_PRIORITY
) {
1541 yyerror("priority cannot be respecified");
1544 if
($2 < 0 ||
$2 > 255) {
1545 yyerror("priority out of range: max 255");
1548 queue_opts.marker |
= QOM_PRIORITY
;
1549 queue_opts.priority
= $2;
1552 if
(queue_opts.marker
& QOM_QLIMIT
) {
1553 yyerror("qlimit cannot be respecified");
1556 if
($2 < 0 ||
$2 > 65535) {
1557 yyerror("qlimit out of range: max 65535");
1560 queue_opts.marker |
= QOM_QLIMIT
;
1561 queue_opts.qlimit
= $2;
1564 if
(queue_opts.marker
& QOM_SCHEDULER
) {
1565 yyerror("scheduler cannot be respecified");
1568 queue_opts.marker |
= QOM_SCHEDULER
;
1569 queue_opts.scheduler
= $1;
1572 if
(queue_opts.marker
& QOM_TBRSIZE
) {
1573 yyerror("tbrsize cannot be respecified");
1576 if
($2 < 0 ||
$2 > 65535) {
1577 yyerror("tbrsize too big: max 65535");
1580 queue_opts.marker |
= QOM_TBRSIZE
;
1581 queue_opts.tbrsize
= $2;
1585 bandwidth
: STRING
{
1591 bps
= strtod
($1, &cp
);
1593 if
(!strcmp
(cp
, "b"))
1595 else if
(!strcmp
(cp
, "Kb"))
1597 else if
(!strcmp
(cp
, "Mb"))
1599 else if
(!strcmp
(cp
, "Gb"))
1600 bps
*= 1000 * 1000 * 1000;
1601 else if
(!strcmp
(cp
, "%")) {
1602 if
(bps
< 0 || bps
> 100) {
1603 yyerror("bandwidth spec "
1608 $$.bw_percent
= bps
;
1611 yyerror("unknown unit %s", cp
);
1617 $$.bw_absolute
= (u_int32_t
)bps
;
1620 if
($1 < 0 ||
$1 > UINT_MAX
) {
1621 yyerror("bandwidth number too big");
1625 $$.bw_absolute
= $1;
1630 $$.qtype
= ALTQT_CBQ
;
1631 $$.data.cbq_opts.flags
= 0;
1633 | CBQ
'(' cbqflags_list
')' {
1634 $$.qtype
= ALTQT_CBQ
;
1635 $$.data.cbq_opts.flags
= $3;
1638 $$.qtype
= ALTQT_PRIQ
;
1639 $$.data.priq_opts.flags
= 0;
1641 | PRIQ
'(' priqflags_list
')' {
1642 $$.qtype
= ALTQT_PRIQ
;
1643 $$.data.priq_opts.flags
= $3;
1646 $$.qtype
= ALTQT_HFSC
;
1647 bzero
(&$$.data.hfsc_opts
,
1648 sizeof
(struct node_hfsc_opts
));
1650 | HFSC
'(' hfsc_opts
')' {
1651 $$.qtype
= ALTQT_HFSC
;
1652 $$.data.hfsc_opts
= $3;
1655 $$.qtype
= ALTQT_FAIRQ
;
1656 bzero
(&$$.data.fairq_opts
,
1657 sizeof
(struct node_fairq_opts
));
1659 | FAIRQ
'(' fairq_opts
')' {
1660 $$.qtype
= ALTQT_FAIRQ
;
1661 $$.data.fairq_opts
= $3;
1665 cbqflags_list
: cbqflags_item
{ $$ |
= $1; }
1666 | cbqflags_list comma cbqflags_item
{ $$ |
= $3; }
1669 cbqflags_item
: STRING
{
1670 if
(!strcmp
($1, "default"))
1671 $$
= CBQCLF_DEFCLASS
;
1672 else if
(!strcmp
($1, "borrow"))
1674 else if
(!strcmp
($1, "red"))
1676 else if
(!strcmp
($1, "ecn"))
1677 $$
= CBQCLF_RED|CBQCLF_ECN
;
1678 else if
(!strcmp
($1, "rio"))
1681 yyerror("unknown cbq flag \"%s\"", $1);
1689 priqflags_list
: priqflags_item
{ $$ |
= $1; }
1690 | priqflags_list comma priqflags_item
{ $$ |
= $3; }
1693 priqflags_item
: STRING
{
1694 if
(!strcmp
($1, "default"))
1695 $$
= PRCF_DEFAULTCLASS
;
1696 else if
(!strcmp
($1, "red"))
1698 else if
(!strcmp
($1, "ecn"))
1699 $$
= PRCF_RED|PRCF_ECN
;
1700 else if
(!strcmp
($1, "rio"))
1703 yyerror("unknown priq flag \"%s\"", $1);
1713 sizeof
(struct node_hfsc_opts
));
1720 hfscopts_list
: hfscopts_item
1721 | hfscopts_list comma hfscopts_item
1724 hfscopts_item
: LINKSHARE bandwidth
{
1725 if
(hfsc_opts.linkshare.used
) {
1726 yyerror("linkshare already specified");
1729 hfsc_opts.linkshare.m2
= $2;
1730 hfsc_opts.linkshare.used
= 1;
1732 | LINKSHARE
'(' bandwidth comma NUMBER comma bandwidth
')'
1734 if
($5 < 0 ||
$5 > INT_MAX
) {
1735 yyerror("timing in curve out of range");
1738 if
(hfsc_opts.linkshare.used
) {
1739 yyerror("linkshare already specified");
1742 hfsc_opts.linkshare.m1
= $3;
1743 hfsc_opts.linkshare.d
= $5;
1744 hfsc_opts.linkshare.m2
= $7;
1745 hfsc_opts.linkshare.used
= 1;
1747 | REALTIME bandwidth
{
1748 if
(hfsc_opts.realtime.used
) {
1749 yyerror("realtime already specified");
1752 hfsc_opts.realtime.m2
= $2;
1753 hfsc_opts.realtime.used
= 1;
1755 | REALTIME
'(' bandwidth comma NUMBER comma bandwidth
')'
1757 if
($5 < 0 ||
$5 > INT_MAX
) {
1758 yyerror("timing in curve out of range");
1761 if
(hfsc_opts.realtime.used
) {
1762 yyerror("realtime already specified");
1765 hfsc_opts.realtime.m1
= $3;
1766 hfsc_opts.realtime.d
= $5;
1767 hfsc_opts.realtime.m2
= $7;
1768 hfsc_opts.realtime.used
= 1;
1770 | UPPERLIMIT bandwidth
{
1771 if
(hfsc_opts.upperlimit.used
) {
1772 yyerror("upperlimit already specified");
1775 hfsc_opts.upperlimit.m2
= $2;
1776 hfsc_opts.upperlimit.used
= 1;
1778 | UPPERLIMIT
'(' bandwidth comma NUMBER comma bandwidth
')'
1780 if
($5 < 0 ||
$5 > INT_MAX
) {
1781 yyerror("timing in curve out of range");
1784 if
(hfsc_opts.upperlimit.used
) {
1785 yyerror("upperlimit already specified");
1788 hfsc_opts.upperlimit.m1
= $3;
1789 hfsc_opts.upperlimit.d
= $5;
1790 hfsc_opts.upperlimit.m2
= $7;
1791 hfsc_opts.upperlimit.used
= 1;
1794 if
(!strcmp
($1, "default"))
1795 hfsc_opts.flags |
= HFCF_DEFAULTCLASS
;
1796 else if
(!strcmp
($1, "red"))
1797 hfsc_opts.flags |
= HFCF_RED
;
1798 else if
(!strcmp
($1, "ecn"))
1799 hfsc_opts.flags |
= HFCF_RED|HFCF_ECN
;
1800 else if
(!strcmp
($1, "rio"))
1801 hfsc_opts.flags |
= HFCF_RIO
;
1803 yyerror("unknown hfsc flag \"%s\"", $1);
1813 sizeof
(struct node_fairq_opts
));
1820 fairqopts_list
: fairqopts_item
1821 | fairqopts_list comma fairqopts_item
1824 fairqopts_item
: LINKSHARE bandwidth
{
1825 if
(fairq_opts.linkshare.used
) {
1826 yyerror("linkshare already specified");
1829 fairq_opts.linkshare.m2
= $2;
1830 fairq_opts.linkshare.used
= 1;
1832 | LINKSHARE
'(' bandwidth number bandwidth
')' {
1833 if
(fairq_opts.linkshare.used
) {
1834 yyerror("linkshare already specified");
1837 fairq_opts.linkshare.m1
= $3;
1838 fairq_opts.linkshare.d
= $4;
1839 fairq_opts.linkshare.m2
= $5;
1840 fairq_opts.linkshare.used
= 1;
1843 fairq_opts.hogs_bw
= $2;
1846 fairq_opts.nbuckets
= $2;
1849 if
(!strcmp
($1, "default"))
1850 fairq_opts.flags |
= FARF_DEFAULTCLASS
;
1851 else if
(!strcmp
($1, "red"))
1852 fairq_opts.flags |
= FARF_RED
;
1853 else if
(!strcmp
($1, "ecn"))
1854 fairq_opts.flags |
= FARF_RED|FARF_ECN
;
1855 else if
(!strcmp
($1, "rio"))
1856 fairq_opts.flags |
= FARF_RIO
;
1858 yyerror("unknown fairq flag \"%s\"", $1);
1866 qassign
: /* empty */ { $$
= NULL
; }
1867 | qassign_item
{ $$
= $1; }
1868 |
'{' optnl qassign_list
'}' { $$
= $3; }
1871 qassign_list
: qassign_item optnl
{ $$
= $1; }
1872 | qassign_list comma qassign_item optnl
{
1873 $1->tail
->next
= $3;
1879 qassign_item
: STRING
{
1880 $$
= calloc
(1, sizeof
(struct node_queue
));
1882 err
(1, "qassign_item: calloc");
1883 if
(strlcpy
($$
->queue
, $1, sizeof
($$
->queue
)) >=
1884 sizeof
($$
->queue
)) {
1885 yyerror("queue name '%s' too long (max "
1886 "%zd chars)", $1, sizeof
($$
->queue
)-1);
1897 pfrule
: action dir logquick interface route af proto fromto
1901 struct node_state_opt
*o
;
1902 struct node_proto
*proto
;
1908 if
(check_rulestate
(PFCTL_STATE_FILTER
))
1911 memset
(&r
, 0, sizeof
(r
));
1915 case PFRULE_RETURNRST
:
1916 r.rule_flag |
= PFRULE_RETURNRST
;
1917 r.return_ttl
= $1.w
;
1919 case PFRULE_RETURNICMP
:
1920 r.rule_flag |
= PFRULE_RETURNICMP
;
1921 r.return_icmp
= $1.w
;
1922 r.return_icmp6
= $1.w2
;
1925 r.rule_flag |
= PFRULE_RETURN
;
1926 r.return_icmp
= $1.w
;
1927 r.return_icmp6
= $1.w2
;
1935 r.rtableid
= $9.rtableid
;
1939 if
(strlcpy
(r.tagname
, $9.tag
,
1940 PF_TAG_NAME_SIZE
) >= PF_TAG_NAME_SIZE
) {
1941 yyerror("tag too long, max %u chars",
1942 PF_TAG_NAME_SIZE
- 1);
1946 if
(strlcpy
(r.match_tagname
, $9.match_tag
,
1947 PF_TAG_NAME_SIZE
) >= PF_TAG_NAME_SIZE
) {
1948 yyerror("tag too long, max %u chars",
1949 PF_TAG_NAME_SIZE
- 1);
1952 r.match_tag_not
= $9.match_tag_not
;
1953 if
(rule_label
(&r
, $9.label
))
1956 r.flags
= $9.flags.b1
;
1957 r.flagset
= $9.flags.b2
;
1958 if
(($9.flags.b1
& $9.flags.b2
) != $9.flags.b1
) {
1959 yyerror("flags always false");
1962 if
($9.flags.b1 ||
$9.flags.b2 ||
$8.src_os
) {
1963 for
(proto
= $7; proto
!= NULL
&&
1964 proto
->proto
!= IPPROTO_TCP
;
1965 proto
= proto
->next
)
1967 if
(proto
== NULL
&& $7 != NULL
) {
1968 if
($9.flags.b1 ||
$9.flags.b2
)
1970 "flags only apply to tcp");
1973 "OS fingerprinting only "
1978 if
(($9.flags.b1
& parse_flags
("S")) == 0 &&
1980 yyerror("OS fingerprinting requires "
1981 "the SYN TCP flag (flags S/SA)");
1989 if
(filter_opts.marker
& FOM_KEEP
) {
1990 r.keep_state
= $9.keep.action
;
1991 o
= $9.keep.options
;
1993 } else if
(r.action
== PF_PASS
) {
1994 r.keep_state
= default_keeppolicy_action
;
1995 o
= default_keeppolicy_options
;
2002 struct node_state_opt
*p
= o
;
2005 case PF_STATE_OPT_MAX
:
2007 yyerror("state option 'max' "
2008 "multiple definitions");
2011 r.max_states
= o
->data.max_states
;
2013 case PF_STATE_OPT_NOSYNC
:
2014 if
(r.rule_flag
& PFRULE_NOSYNC
) {
2015 yyerror("state option 'sync' "
2016 "multiple definitions");
2019 r.rule_flag |
= PFRULE_NOSYNC
;
2021 case PF_STATE_OPT_SRCTRACK
:
2023 yyerror("state option "
2025 "multiple definitions");
2028 srctrack
= o
->data.src_track
;
2029 r.rule_flag |
= PFRULE_SRCTRACK
;
2031 case PF_STATE_OPT_MAX_SRC_STATES
:
2032 if
(r.max_src_states
) {
2033 yyerror("state option "
2035 "multiple definitions");
2038 if
(o
->data.max_src_states
== 0) {
2039 yyerror("'max-src-states' must "
2044 o
->data.max_src_states
;
2045 r.rule_flag |
= PFRULE_SRCTRACK
;
2047 case PF_STATE_OPT_OVERLOAD
:
2048 if
(r.overload_tblname
[0]) {
2049 yyerror("multiple 'overload' "
2050 "table definitions");
2053 if
(strlcpy
(r.overload_tblname
,
2054 o
->data.overload.tblname
,
2055 PF_TABLE_NAME_SIZE
) >=
2056 PF_TABLE_NAME_SIZE
) {
2057 yyerror("state option: "
2061 r.flush
= o
->data.overload.flush
;
2063 case PF_STATE_OPT_MAX_SRC_CONN
:
2064 if
(r.max_src_conn
) {
2065 yyerror("state option "
2067 "multiple definitions");
2070 if
(o
->data.max_src_conn
== 0) {
2071 yyerror("'max-src-conn' "
2076 o
->data.max_src_conn
;
2077 r.rule_flag |
= PFRULE_SRCTRACK |
2078 PFRULE_RULESRCTRACK
;
2080 case PF_STATE_OPT_MAX_SRC_CONN_RATE
:
2081 if
(r.max_src_conn_rate.limit
) {
2082 yyerror("state option "
2083 "'max-src-conn-rate' "
2084 "multiple definitions");
2087 if
(!o
->data.max_src_conn_rate.limit ||
2088 !o
->data.max_src_conn_rate.seconds
) {
2089 yyerror("'max-src-conn-rate' "
2090 "values must be > 0");
2093 if
(o
->data.max_src_conn_rate.limit
>
2095 yyerror("'max-src-conn-rate' "
2096 "maximum rate must be < %u",
2100 r.max_src_conn_rate.limit
=
2101 o
->data.max_src_conn_rate.limit
;
2102 r.max_src_conn_rate.seconds
=
2103 o
->data.max_src_conn_rate.seconds
;
2104 r.rule_flag |
= PFRULE_SRCTRACK |
2105 PFRULE_RULESRCTRACK
;
2107 case PF_STATE_OPT_MAX_SRC_NODES
:
2108 if
(r.max_src_nodes
) {
2109 yyerror("state option "
2111 "multiple definitions");
2114 if
(o
->data.max_src_nodes
== 0) {
2115 yyerror("'max-src-nodes' must "
2120 o
->data.max_src_nodes
;
2121 r.rule_flag |
= PFRULE_SRCTRACK |
2122 PFRULE_RULESRCTRACK
;
2124 case PF_STATE_OPT_STATELOCK
:
2126 yyerror("state locking option: "
2127 "multiple definitions");
2131 r.rule_flag |
= o
->data.statelock
;
2133 case PF_STATE_OPT_SLOPPY
:
2134 if
(r.rule_flag
& PFRULE_STATESLOPPY
) {
2135 yyerror("state sloppy option: "
2136 "multiple definitions");
2139 r.rule_flag |
= PFRULE_STATESLOPPY
;
2141 case PF_STATE_OPT_TIMEOUT
:
2142 if
(o
->data.timeout.number
==
2143 PFTM_ADAPTIVE_START ||
2144 o
->data.timeout.number
==
2147 if
(r.timeout
[o
->data.timeout.number
]) {
2148 yyerror("state timeout %s "
2149 "multiple definitions",
2150 pf_timeouts
[o
->data.
2151 timeout.number
].name
);
2154 r.timeout
[o
->data.timeout.number
] =
2155 o
->data.timeout.seconds
;
2157 case PF_STATE_OPT_PICKUPS
:
2158 r.pickup_mode
= o
->data.pickup_mode
;
2167 /* 'flags S/SA' by default on stateful rules */
2168 if
(!r.action
&& !r.flags
&& !r.flagset
&&
2169 !$9.fragment
&& !($9.marker
& FOM_FLAGS
) &&
2171 r.flags
= parse_flags
("S");
2172 r.flagset
= parse_flags
("SA");
2175 if
(!adaptive
&& r.max_states
) {
2176 r.timeout
[PFTM_ADAPTIVE_START
] =
2177 (r.max_states
/ 10) * 6;
2178 r.timeout
[PFTM_ADAPTIVE_END
] =
2179 (r.max_states
/ 10) * 12;
2181 if
(r.rule_flag
& PFRULE_SRCTRACK
) {
2182 if
(srctrack
== PF_SRCTRACK_GLOBAL
&&
2184 yyerror("'max-src-nodes' is "
2185 "incompatible with "
2186 "'source-track global'");
2189 if
(srctrack
== PF_SRCTRACK_GLOBAL
&&
2191 yyerror("'max-src-conn' is "
2192 "incompatible with "
2193 "'source-track global'");
2196 if
(srctrack
== PF_SRCTRACK_GLOBAL
&&
2197 r.max_src_conn_rate.seconds
) {
2198 yyerror("'max-src-conn-rate' is "
2199 "incompatible with "
2200 "'source-track global'");
2203 if
(r.timeout
[PFTM_SRC_NODE
] <
2204 r.max_src_conn_rate.seconds
)
2205 r.timeout
[PFTM_SRC_NODE
] =
2206 r.max_src_conn_rate.seconds
;
2207 r.rule_flag |
= PFRULE_SRCTRACK
;
2208 if
(srctrack
== PF_SRCTRACK_RULE
)
2209 r.rule_flag |
= PFRULE_RULESRCTRACK
;
2211 if
(r.keep_state
&& !statelock
)
2212 r.rule_flag |
= default_statelock
;
2215 r.rule_flag |
= PFRULE_FRAGMENT
;
2216 r.allow_opts
= $9.allowopts
;
2218 decide_address_family
($8.src.host
, &r.af
);
2219 decide_address_family
($8.dst.host
, &r.af
);
2223 yyerror("direction must be explicit "
2224 "with rules that specify routing");
2228 r.rpool.opts
= $5.pool_opts
;
2230 memcpy
(&r.rpool.key
, $5.key
,
2231 sizeof
(struct pf_poolhashkey
));
2233 if
(r.rt
&& r.rt
!= PF_FASTROUTE
) {
2234 decide_address_family
($5.host
, &r.af
);
2235 remove_invalid_hosts
(&$5.host
, &r.af
);
2236 if
($5.host
== NULL
) {
2237 yyerror("no routing address with "
2238 "matching address family found.");
2241 if
((r.rpool.opts
& PF_POOL_TYPEMASK
) ==
2242 PF_POOL_NONE
&& ($5.host
->next
!= NULL ||
2243 $5.host
->addr.type
== PF_ADDR_TABLE ||
2244 DYNIF_MULTIADDR
($5.host
->addr
)))
2245 r.rpool.opts |
= PF_POOL_ROUNDROBIN
;
2246 if
((r.rpool.opts
& PF_POOL_TYPEMASK
) !=
2247 PF_POOL_ROUNDROBIN
&&
2248 disallow_table
($5.host
, "tables are only "
2249 "supported in round-robin routing pools"))
2251 if
((r.rpool.opts
& PF_POOL_TYPEMASK
) !=
2252 PF_POOL_ROUNDROBIN
&&
2253 disallow_alias
($5.host
, "interface (%s) "
2254 "is only supported in round-robin "
2257 if
($5.host
->next
!= NULL
) {
2258 if
((r.rpool.opts
& PF_POOL_TYPEMASK
) !=
2259 PF_POOL_ROUNDROBIN
) {
2260 yyerror("r.rpool.opts must "
2261 "be PF_POOL_ROUNDROBIN");
2266 if
($9.queues.qname
!= NULL
) {
2267 if
(strlcpy
(r.qname
, $9.queues.qname
,
2268 sizeof
(r.qname
)) >= sizeof
(r.qname
)) {
2269 yyerror("rule qname too long (max "
2270 "%zd chars)", sizeof
(r.qname
)-1);
2273 free
($9.queues.qname
);
2275 if
($9.queues.pqname
!= NULL
) {
2276 if
(strlcpy
(r.pqname
, $9.queues.pqname
,
2277 sizeof
(r.pqname
)) >= sizeof
(r.pqname
)) {
2278 yyerror("rule pqname too long (max "
2279 "%zd chars)", sizeof
(r.pqname
)-1);
2282 free
($9.queues.pqname
);
2284 if
((r.divert.port
= $9.divert.port
)) {
2285 if
(r.direction
== PF_OUT
) {
2286 if
($9.divert.addr
) {
2287 yyerror("address specified "
2288 "for outgoing divert");
2291 bzero
(&r.divert.addr
,
2292 sizeof
(r.divert.addr
));
2294 if
(!$9.divert.addr
) {
2295 yyerror("no address specified "
2296 "for incoming divert");
2299 if
($9.divert.addr
->af
!= r.af
) {
2300 yyerror("address family "
2301 "mismatch for divert");
2305 $9.divert.addr
->addr.v.a.addr
;
2309 expand_rule
(&r
, $4, $5.host
, $7, $8.src_os
,
2310 $8.src.host
, $8.src.port
, $8.dst.host
, $8.dst.port
,
2311 $9.uid
, $9.gid
, $9.icmpspec
, "");
2316 bzero
(&filter_opts
, sizeof filter_opts
);
2317 filter_opts.rtableid
= -1;
2320 { $$
= filter_opts
; }
2322 bzero
(&filter_opts
, sizeof filter_opts
);
2323 filter_opts.rtableid
= -1;
2328 filter_opts_l
: filter_opts_l filter_opt
2332 filter_opt
: USER uids
{
2333 if
(filter_opts.uid
)
2334 $2->tail
->next
= filter_opts.uid
;
2335 filter_opts.uid
= $2;
2338 if
(filter_opts.gid
)
2339 $2->tail
->next
= filter_opts.gid
;
2340 filter_opts.gid
= $2;
2343 if
(filter_opts.marker
& FOM_FLAGS
) {
2344 yyerror("flags cannot be redefined");
2347 filter_opts.marker |
= FOM_FLAGS
;
2348 filter_opts.flags.b1 |
= $1.b1
;
2349 filter_opts.flags.b2 |
= $1.b2
;
2350 filter_opts.flags.w |
= $1.w
;
2351 filter_opts.flags.w2 |
= $1.w2
;
2354 if
(filter_opts.marker
& FOM_ICMP
) {
2355 yyerror("icmp-type cannot be redefined");
2358 filter_opts.marker |
= FOM_ICMP
;
2359 filter_opts.icmpspec
= $1;
2362 if
(filter_opts.marker
& FOM_TOS
) {
2363 yyerror("tos cannot be redefined");
2366 filter_opts.marker |
= FOM_TOS
;
2367 filter_opts.tos
= $2;
2370 if
(filter_opts.marker
& FOM_KEEP
) {
2371 yyerror("modulate or keep cannot be redefined");
2374 filter_opts.marker |
= FOM_KEEP
;
2375 filter_opts.keep.action
= $1.action
;
2376 filter_opts.keep.options
= $1.options
;
2379 filter_opts.fragment
= 1;
2382 filter_opts.allowopts
= 1;
2385 if
(filter_opts.label
) {
2386 yyerror("label cannot be redefined");
2389 filter_opts.label
= $1;
2392 if
(filter_opts.queues.qname
) {
2393 yyerror("queue cannot be redefined");
2396 filter_opts.queues
= $1;
2399 filter_opts.tag
= $2;
2401 | not TAGGED
string {
2402 filter_opts.match_tag
= $3;
2403 filter_opts.match_tag_not
= $1;
2405 | PROBABILITY probability
{
2408 p
= floor
($2 * UINT_MAX
+ 0.5);
2409 if
(p
< 0.0 || p
> UINT_MAX
) {
2410 yyerror("invalid probability: %lf", p
);
2413 filter_opts.prob
= (u_int32_t
)p
;
2414 if
(filter_opts.prob
== 0)
2415 filter_opts.prob
= 1;
2418 filter_opts.rtableid
= $2;
2420 | DIVERTTO STRING PORT portplain
{
2421 if
((filter_opts.divert.addr
= host
($2)) == NULL
) {
2422 yyerror("could not parse divert address: %s",
2428 filter_opts.divert.port
= $4.a
;
2429 if
(!filter_opts.divert.port
) {
2430 yyerror("invalid divert port: %u", ntohs
($4.a
));
2435 filter_opts.divert.port
= 1; /* some random value */
2439 probability
: STRING
{
2441 double p
= strtod
($1, &e
);
2448 yyerror("invalid probability: %s", $1);
2461 action
: PASS
{ $$.b1
= PF_PASS
; $$.b2
= $$.w
= 0; }
2462 | BLOCK blockspec
{ $$
= $2; $$.b1
= PF_DROP
; }
2465 blockspec
: /* empty */ {
2466 $$.b2
= blockpolicy
;
2467 $$.w
= returnicmpdefault
;
2468 $$.w2
= returnicmp6default
;
2471 $$.b2
= PFRULE_DROP
;
2476 $$.b2
= PFRULE_RETURNRST
;
2480 | RETURNRST
'(' TTL NUMBER
')' {
2481 if
($4 < 0 ||
$4 > 255) {
2482 yyerror("illegal ttl value %" PRId64
, $4);
2485 $$.b2
= PFRULE_RETURNRST
;
2490 $$.b2
= PFRULE_RETURNICMP
;
2491 $$.w
= returnicmpdefault
;
2492 $$.w2
= returnicmp6default
;
2495 $$.b2
= PFRULE_RETURNICMP
;
2496 $$.w
= returnicmpdefault
;
2497 $$.w2
= returnicmp6default
;
2499 | RETURNICMP
'(' reticmpspec
')' {
2500 $$.b2
= PFRULE_RETURNICMP
;
2502 $$.w2
= returnicmpdefault
;
2504 | RETURNICMP6
'(' reticmp6spec
')' {
2505 $$.b2
= PFRULE_RETURNICMP
;
2506 $$.w
= returnicmpdefault
;
2509 | RETURNICMP
'(' reticmpspec comma reticmp6spec
')' {
2510 $$.b2
= PFRULE_RETURNICMP
;
2515 $$.b2
= PFRULE_RETURN
;
2516 $$.w
= returnicmpdefault
;
2517 $$.w2
= returnicmp6default
;
2521 reticmpspec
: STRING
{
2522 if
(!($$
= parseicmpspec
($1, AF_INET
))) {
2531 if
($1 < 0 ||
$1 > 255) {
2532 yyerror("invalid icmp code %" PRId64
, $1);
2535 icmptype
= returnicmpdefault
>> 8;
2536 $$
= (icmptype
<< 8 |
$1);
2540 reticmp6spec
: STRING
{
2541 if
(!($$
= parseicmpspec
($1, AF_INET6
))) {
2550 if
($1 < 0 ||
$1 > 255) {
2551 yyerror("invalid icmp code %" PRId64
, $1);
2554 icmptype
= returnicmp6default
>> 8;
2555 $$
= (icmptype
<< 8 |
$1);
2559 dir
: /* empty */ { $$
= PF_INOUT
; }
2560 | IN
{ $$
= PF_IN
; }
2561 | OUT
{ $$
= PF_OUT
; }
2564 quick
: /* empty */ { $$.quick
= 0; }
2565 | QUICK
{ $$.quick
= 1; }
2568 logquick
: /* empty */ { $$.log
= 0; $$.quick
= 0; $$.logif
= 0; }
2569 | log
{ $$
= $1; $$.quick
= 0; }
2570 | QUICK
{ $$.quick
= 1; $$.log
= 0; $$.logif
= 0; }
2571 | log QUICK
{ $$
= $1; $$.quick
= 1; }
2572 | QUICK log
{ $$
= $2; $$.quick
= 1; }
2575 log
: LOG
{ $$.log
= PF_LOG
; $$.logif
= 0; }
2576 | LOG
'(' logopts
')' {
2577 $$.log
= PF_LOG |
$3.log
;
2578 $$.logif
= $3.logif
;
2582 logopts
: logopt
{ $$
= $1; }
2583 | logopts comma logopt
{
2584 $$.log
= $1.log |
$3.log
;
2585 $$.logif
= $3.logif
;
2587 $$.logif
= $1.logif
;
2591 logopt
: ALL
{ $$.log
= PF_LOG_ALL
; $$.logif
= 0; }
2592 | USER
{ $$.log
= PF_LOG_SOCKET_LOOKUP
; $$.logif
= 0; }
2593 | GROUP
{ $$.log
= PF_LOG_SOCKET_LOOKUP
; $$.logif
= 0; }
2599 if
(strncmp
($2, "pflog", 5)) {
2600 yyerror("%s: should be a pflog interface", $2);
2604 i
= strtonum
($2 + 5, 0, 255, &errstr
);
2606 yyerror("%s: %s", $2, errstr
);
2615 interface
: /* empty */ { $$
= NULL
; }
2616 | ON if_item_not
{ $$
= $2; }
2617 | ON
'{' optnl if_list
'}' { $$
= $4; }
2620 if_list
: if_item_not optnl
{ $$
= $1; }
2621 | if_list comma if_item_not optnl
{
2622 $1->tail
->next
= $3;
2628 if_item_not
: not if_item
{ $$
= $2; $$
->not
= $1; }
2632 struct node_host
*n
;
2634 $$
= calloc
(1, sizeof
(struct node_if
));
2636 err
(1, "if_item: calloc");
2637 if
(strlcpy
($$
->ifname
, $1, sizeof
($$
->ifname
)) >=
2638 sizeof
($$
->ifname
)) {
2641 yyerror("interface name too long");
2645 if
((n
= ifa_exists
($1)) != NULL
)
2646 $$
->ifa_flags
= n
->ifa_flags
;
2655 af
: /* empty */ { $$
= 0; }
2656 | INET
{ $$
= AF_INET
; }
2657 | INET6
{ $$
= AF_INET6
; }
2660 proto
: /* empty */ { $$
= NULL
; }
2661 | PROTO proto_item
{ $$
= $2; }
2662 | PROTO
'{' optnl proto_list
'}' { $$
= $4; }
2665 proto_list
: proto_item optnl
{ $$
= $1; }
2666 | proto_list comma proto_item optnl
{
2667 $1->tail
->next
= $3;
2673 proto_item
: protoval
{
2678 yyerror("proto 0 cannot be used");
2681 $$
= calloc
(1, sizeof
(struct node_proto
));
2683 err
(1, "proto_item: calloc");
2693 p
= getprotobyname
($1);
2695 yyerror("unknown protocol %s", $1);
2703 if
($1 < 0 ||
$1 > 255) {
2704 yyerror("protocol outside range");
2724 os
: /* empty */ { $$
= NULL
; }
2725 | OS xos
{ $$
= $2; }
2726 | OS
'{' optnl os_list
'}' { $$
= $4; }
2730 $$
= calloc
(1, sizeof
(struct node_os
));
2732 err
(1, "os: calloc");
2738 os_list
: xos optnl
{ $$
= $1; }
2739 | os_list comma xos optnl
{
2740 $1->tail
->next
= $3;
2746 from
: /* empty */ {
2760 if
(disallow_urpf_failed
($2.host
, "\"urpf-failed\" is "
2761 "not permitted in a destination address"))
2767 ipportspec
: ipspec
{
2771 | ipspec PORT portspec
{
2785 ipspec
: ANY
{ $$
= NULL
; }
2786 | xhost
{ $$
= $1; }
2787 |
'{' optnl host_list
'}' { $$
= $3; }
2790 toipspec
: TO ipspec
{ $$
= $2; }
2791 |
/* empty */ { $$
= NULL
; }
2794 host_list
: ipspec optnl
{ $$
= $1; }
2795 | host_list comma ipspec optnl
{
2798 else if
($1 == NULL
)
2801 $1->tail
->next
= $3;
2802 $1->tail
= $3->tail
;
2809 struct node_host
*n
;
2811 for
(n
= $2; n
!= NULL
; n
= n
->next
)
2816 $$
= calloc
(1, sizeof
(struct node_host
));
2818 err
(1, "xhost: calloc");
2819 $$
->addr.type
= PF_ADDR_NOROUTE
;
2825 $$
= calloc
(1, sizeof
(struct node_host
));
2827 err
(1, "xhost: calloc");
2828 $$
->addr.type
= PF_ADDR_URPFFAILED
;
2836 if
(($$
= host
($1)) == NULL
) {
2837 /* error. "any" is handled elsewhere */
2839 yyerror("could not parse host specification");
2845 | STRING
'-' STRING
{
2846 struct node_host
*b
, *e
;
2848 if
((b
= host
($1)) == NULL ||
(e
= host
($3)) == NULL
) {
2851 yyerror("could not parse host specification");
2854 if
(b
->af
!= e
->af ||
2855 b
->addr.type
!= PF_ADDR_ADDRMASK ||
2856 e
->addr.type
!= PF_ADDR_ADDRMASK ||
2857 unmask
(&b
->addr.v.a.mask
, b
->af
) !=
2858 (b
->af
== AF_INET ?
32 : 128) ||
2859 unmask
(&e
->addr.v.a.mask
, e
->af
) !=
2860 (e
->af
== AF_INET ?
32 : 128) ||
2861 b
->next
!= NULL || b
->not ||
2862 e
->next
!= NULL || e
->not
) {
2867 yyerror("invalid address range");
2870 memcpy
(&b
->addr.v.a.mask
, &e
->addr.v.a.addr
,
2871 sizeof
(b
->addr.v.a.mask
));
2872 b
->addr.type
= PF_ADDR_RANGE
;
2878 | STRING
'/' NUMBER
{
2881 if
(asprintf
(&buf
, "%s/%" PRId64
, $1, $3) == -1)
2882 err
(1, "host: asprintf");
2884 if
(($$
= host
(buf
)) == NULL
) {
2885 /* error. "any" is handled elsewhere */
2887 yyerror("could not parse host specification");
2892 | NUMBER
'/' NUMBER
{
2895 /* ie. for 10/8 parsing */
2896 if
(asprintf
(&buf
, "%" PRId64
"/%" PRId64
, $1, $3) == -1)
2897 err
(1, "host: asprintf");
2898 if
(($$
= host
(buf
)) == NULL
) {
2899 /* error. "any" is handled elsewhere */
2901 yyerror("could not parse host specification");
2907 | dynaddr
'/' NUMBER
{
2908 struct node_host
*n
;
2910 if
($3 < 0 ||
$3 > 128) {
2911 yyerror("bit number too big");
2915 for
(n
= $1; n
!= NULL
; n
= n
->next
)
2919 if
(strlen
($2) >= PF_TABLE_NAME_SIZE
) {
2920 yyerror("table name '%s' too long", $2);
2924 $$
= calloc
(1, sizeof
(struct node_host
));
2926 err
(1, "host: calloc");
2927 $$
->addr.type
= PF_ADDR_TABLE
;
2928 if
(strlcpy
($$
->addr.v.tblname
, $2,
2929 sizeof
($$
->addr.v.tblname
)) >=
2930 sizeof
($$
->addr.v.tblname
))
2931 errx
(1, "host: strlcpy");
2937 $$
= calloc
(1, sizeof
(struct node_host
));
2940 err
(1, "host: calloc");
2942 $$
->addr.type
= PF_ADDR_RTLABEL
;
2943 if
(strlcpy
($$
->addr.v.rtlabelname
, $2,
2944 sizeof
($$
->addr.v.rtlabelname
)) >=
2945 sizeof
($$
->addr.v.rtlabelname
)) {
2946 yyerror("route label too long, max %zd chars",
2947 sizeof
($$
->addr.v.rtlabelname
) - 1);
2962 if
(atoul
($1, &ulval
) == -1) {
2963 yyerror("%s is not a number", $1);
2972 dynaddr
: '(' STRING
')' {
2977 if
(!isalpha
(op
[0])) {
2978 yyerror("invalid interface name '%s'", op
);
2982 while
((p
= strrchr
($2, ':')) != NULL
) {
2983 if
(!strcmp
(p
+1, "network"))
2984 flags |
= PFI_AFLAG_NETWORK
;
2985 else if
(!strcmp
(p
+1, "broadcast"))
2986 flags |
= PFI_AFLAG_BROADCAST
;
2987 else if
(!strcmp
(p
+1, "peer"))
2988 flags |
= PFI_AFLAG_PEER
;
2989 else if
(!strcmp
(p
+1, "0"))
2990 flags |
= PFI_AFLAG_NOALIAS
;
2992 yyerror("interface %s has bad modifier",
2999 if
(flags
& (flags
- 1) & PFI_AFLAG_MODEMASK
) {
3001 yyerror("illegal combination of "
3002 "interface modifiers");
3005 $$
= calloc
(1, sizeof
(struct node_host
));
3007 err
(1, "address: calloc");
3009 set_ipmask
($$
, 128);
3010 $$
->addr.type
= PF_ADDR_DYNIFTL
;
3011 $$
->addr.iflags
= flags
;
3012 if
(strlcpy
($$
->addr.v.ifname
, $2,
3013 sizeof
($$
->addr.v.ifname
)) >=
3014 sizeof
($$
->addr.v.ifname
)) {
3017 yyerror("interface name too long");
3026 portspec
: port_item
{ $$
= $1; }
3027 |
'{' optnl port_list
'}' { $$
= $3; }
3030 port_list
: port_item optnl
{ $$
= $1; }
3031 | port_list comma port_item optnl
{
3032 $1->tail
->next
= $3;
3038 port_item
: portrange
{
3039 $$
= calloc
(1, sizeof
(struct node_port
));
3041 err
(1, "port_item: calloc");
3051 | unaryop portrange
{
3053 yyerror("':' cannot be used with an other "
3057 $$
= calloc
(1, sizeof
(struct node_port
));
3059 err
(1, "port_item: calloc");
3066 | portrange PORTBINARY portrange
{
3068 yyerror("':' cannot be used with an other "
3072 $$
= calloc
(1, sizeof
(struct node_port
));
3074 err
(1, "port_item: calloc");
3083 portplain
: numberstring
{
3084 if
(parseport
($1, &$$
, 0) == -1) {
3092 portrange
: numberstring
{
3093 if
(parseport
($1, &$$
, PPORT_RANGE
) == -1) {
3101 uids
: uid_item
{ $$
= $1; }
3102 |
'{' optnl uid_list
'}' { $$
= $3; }
3105 uid_list
: uid_item optnl
{ $$
= $1; }
3106 | uid_list comma uid_item optnl
{
3107 $1->tail
->next
= $3;
3114 $$
= calloc
(1, sizeof
(struct node_uid
));
3116 err
(1, "uid_item: calloc");
3124 if
($2 == UID_MAX
&& $1 != PF_OP_EQ
&& $1 != PF_OP_NE
) {
3125 yyerror("user unknown requires operator = or "
3129 $$
= calloc
(1, sizeof
(struct node_uid
));
3131 err
(1, "uid_item: calloc");
3138 | uid PORTBINARY uid
{
3139 if
($1 == UID_MAX ||
$3 == UID_MAX
) {
3140 yyerror("user unknown requires operator = or "
3144 $$
= calloc
(1, sizeof
(struct node_uid
));
3146 err
(1, "uid_item: calloc");
3156 if
(!strcmp
($1, "unknown"))
3161 if
((pw
= getpwnam
($1)) == NULL
) {
3162 yyerror("unknown user %s", $1);
3171 if
($1 < 0 ||
$1 >= UID_MAX
) {
3172 yyerror("illegal uid value %" PRId64
, $1);
3179 gids
: gid_item
{ $$
= $1; }
3180 |
'{' optnl gid_list
'}' { $$
= $3; }
3183 gid_list
: gid_item optnl
{ $$
= $1; }
3184 | gid_list comma gid_item optnl
{
3185 $1->tail
->next
= $3;
3192 $$
= calloc
(1, sizeof
(struct node_gid
));
3194 err
(1, "gid_item: calloc");
3202 if
($2 == GID_MAX
&& $1 != PF_OP_EQ
&& $1 != PF_OP_NE
) {
3203 yyerror("group unknown requires operator = or "
3207 $$
= calloc
(1, sizeof
(struct node_gid
));
3209 err
(1, "gid_item: calloc");
3216 | gid PORTBINARY gid
{
3217 if
($1 == GID_MAX ||
$3 == GID_MAX
) {
3218 yyerror("group unknown requires operator = or "
3222 $$
= calloc
(1, sizeof
(struct node_gid
));
3224 err
(1, "gid_item: calloc");
3234 if
(!strcmp
($1, "unknown"))
3239 if
((grp
= getgrnam
($1)) == NULL
) {
3240 yyerror("unknown group %s", $1);
3249 if
($1 < 0 ||
$1 >= GID_MAX
) {
3250 yyerror("illegal gid value %" PRId64
, $1);
3260 if
((f
= parse_flags
($1)) < 0) {
3261 yyerror("bad flags %s", $1);
3270 flags
: FLAGS flag
'/' flag
{ $$.b1
= $2.b1
; $$.b2
= $4.b1
; }
3271 | FLAGS
'/' flag
{ $$.b1
= 0; $$.b2
= $3.b1
; }
3272 | FLAGS ANY
{ $$.b1
= 0; $$.b2
= 0; }
3275 icmpspec
: ICMPTYPE icmp_item
{ $$
= $2; }
3276 | ICMPTYPE
'{' optnl icmp_list
'}' { $$
= $4; }
3277 | ICMP6TYPE icmp6_item
{ $$
= $2; }
3278 | ICMP6TYPE
'{' optnl icmp6_list
'}' { $$
= $4; }
3281 icmp_list
: icmp_item optnl
{ $$
= $1; }
3282 | icmp_list comma icmp_item optnl
{
3283 $1->tail
->next
= $3;
3289 icmp6_list
: icmp6_item optnl
{ $$
= $1; }
3290 | icmp6_list comma icmp6_item optnl
{
3291 $1->tail
->next
= $3;
3297 icmp_item
: icmptype
{
3298 $$
= calloc
(1, sizeof
(struct node_icmp
));
3300 err
(1, "icmp_item: calloc");
3303 $$
->proto
= IPPROTO_ICMP
;
3307 | icmptype CODE STRING
{
3308 const struct icmpcodeent
*p
;
3310 if
((p
= geticmpcodebyname
($1-1, $3, AF_INET
)) == NULL
) {
3311 yyerror("unknown icmp-code %s", $3);
3317 $$
= calloc
(1, sizeof
(struct node_icmp
));
3319 err
(1, "icmp_item: calloc");
3321 $$
->code
= p
->code
+ 1;
3322 $$
->proto
= IPPROTO_ICMP
;
3326 | icmptype CODE NUMBER
{
3327 if
($3 < 0 ||
$3 > 255) {
3328 yyerror("illegal icmp-code %" PRId64
, $3);
3331 $$
= calloc
(1, sizeof
(struct node_icmp
));
3333 err
(1, "icmp_item: calloc");
3336 $$
->proto
= IPPROTO_ICMP
;
3342 icmp6_item
: icmp6type
{
3343 $$
= calloc
(1, sizeof
(struct node_icmp
));
3345 err
(1, "icmp_item: calloc");
3348 $$
->proto
= IPPROTO_ICMPV6
;
3352 | icmp6type CODE STRING
{
3353 const struct icmpcodeent
*p
;
3355 if
((p
= geticmpcodebyname
($1-1, $3, AF_INET6
)) == NULL
) {
3356 yyerror("unknown icmp6-code %s", $3);
3362 $$
= calloc
(1, sizeof
(struct node_icmp
));
3364 err
(1, "icmp_item: calloc");
3366 $$
->code
= p
->code
+ 1;
3367 $$
->proto
= IPPROTO_ICMPV6
;
3371 | icmp6type CODE NUMBER
{
3372 if
($3 < 0 ||
$3 > 255) {
3373 yyerror("illegal icmp-code %" PRId64
, $3);
3376 $$
= calloc
(1, sizeof
(struct node_icmp
));
3378 err
(1, "icmp_item: calloc");
3381 $$
->proto
= IPPROTO_ICMPV6
;
3388 const struct icmptypeent
*p
;
3390 if
((p
= geticmptypebyname
($1, AF_INET
)) == NULL
) {
3391 yyerror("unknown icmp-type %s", $1);
3399 if
($1 < 0 ||
$1 > 255) {
3400 yyerror("illegal icmp-type %" PRId64
, $1);
3407 icmp6type
: STRING
{
3408 const struct icmptypeent
*p
;
3410 if
((p
= geticmptypebyname
($1, AF_INET6
)) ==
3412 yyerror("unknown icmp6-type %s", $1);
3420 if
($1 < 0 ||
$1 > 255) {
3421 yyerror("illegal icmp6-type %" PRId64
, $1);
3429 if
(!strcmp
($1, "lowdelay"))
3430 $$
= IPTOS_LOWDELAY
;
3431 else if
(!strcmp
($1, "throughput"))
3432 $$
= IPTOS_THROUGHPUT
;
3433 else if
(!strcmp
($1, "reliability"))
3434 $$
= IPTOS_RELIABILITY
;
3435 else if
($1[0] == '0' && $1[1] == 'x')
3436 $$
= strtoul
($1, NULL
, 16);
3438 $$
= 0; /* flag bad argument */
3439 if
(!$$ || $$
> 255) {
3440 yyerror("illegal tos value %s", $1);
3448 if
(!$$ || $$
> 255) {
3449 yyerror("illegal tos value %" PRId64
, $1);
3455 sourcetrack
: SOURCETRACK
{ $$
= PF_SRCTRACK
; }
3456 | SOURCETRACK GLOBAL
{ $$
= PF_SRCTRACK_GLOBAL
; }
3457 | SOURCETRACK RULE
{ $$
= PF_SRCTRACK_RULE
; }
3460 statelock
: IFBOUND
{
3461 $$
= PFRULE_IFBOUND
;
3472 | KEEP STATE state_opt_spec
{
3473 $$.action
= PF_STATE_NORMAL
;
3476 | MODULATE STATE state_opt_spec
{
3477 $$.action
= PF_STATE_MODULATE
;
3480 | SYNPROXY STATE state_opt_spec
{
3481 $$.action
= PF_STATE_SYNPROXY
;
3486 flush
: /* empty */ { $$
= 0; }
3487 | FLUSH
{ $$
= PF_FLUSH
; }
3489 $$
= PF_FLUSH | PF_FLUSH_GLOBAL
;
3493 state_opt_spec
: '(' state_opt_list
')' { $$
= $2; }
3494 |
/* empty */ { $$
= NULL
; }
3497 state_opt_list
: state_opt_item
{ $$
= $1; }
3498 | state_opt_list comma state_opt_item
{
3499 $1->tail
->next
= $3;
3505 state_opt_item
: MAXIMUM NUMBER
{
3506 if
($2 < 0 ||
$2 > UINT_MAX
) {
3507 yyerror("only positive values permitted");
3510 $$
= calloc
(1, sizeof
(struct node_state_opt
));
3512 err
(1, "state_opt_item: calloc");
3513 $$
->type
= PF_STATE_OPT_MAX
;
3514 $$
->data.max_states
= $2;
3519 $$
= calloc
(1, sizeof
(struct node_state_opt
));
3521 err
(1, "state_opt_item: calloc");
3522 $$
->type
= PF_STATE_OPT_NOSYNC
;
3526 | MAXSRCSTATES NUMBER
{
3527 if
($2 < 0 ||
$2 > UINT_MAX
) {
3528 yyerror("only positive values permitted");
3531 $$
= calloc
(1, sizeof
(struct node_state_opt
));
3533 err
(1, "state_opt_item: calloc");
3534 $$
->type
= PF_STATE_OPT_MAX_SRC_STATES
;
3535 $$
->data.max_src_states
= $2;
3539 | MAXSRCCONN NUMBER
{
3540 if
($2 < 0 ||
$2 > UINT_MAX
) {
3541 yyerror("only positive values permitted");
3544 $$
= calloc
(1, sizeof
(struct node_state_opt
));
3546 err
(1, "state_opt_item: calloc");
3547 $$
->type
= PF_STATE_OPT_MAX_SRC_CONN
;
3548 $$
->data.max_src_conn
= $2;
3552 | MAXSRCCONNRATE NUMBER
'/' NUMBER
{
3553 if
($2 < 0 ||
$2 > UINT_MAX ||
3554 $4 < 0 ||
$4 > UINT_MAX
) {
3555 yyerror("only positive values permitted");
3558 $$
= calloc
(1, sizeof
(struct node_state_opt
));
3560 err
(1, "state_opt_item: calloc");
3561 $$
->type
= PF_STATE_OPT_MAX_SRC_CONN_RATE
;
3562 $$
->data.max_src_conn_rate.limit
= $2;
3563 $$
->data.max_src_conn_rate.seconds
= $4;
3567 | OVERLOAD
'<' STRING
'>' flush
{
3568 if
(strlen
($3) >= PF_TABLE_NAME_SIZE
) {
3569 yyerror("table name '%s' too long", $3);
3573 $$
= calloc
(1, sizeof
(struct node_state_opt
));
3575 err
(1, "state_opt_item: calloc");
3576 if
(strlcpy
($$
->data.overload.tblname
, $3,
3577 PF_TABLE_NAME_SIZE
) >= PF_TABLE_NAME_SIZE
)
3578 errx
(1, "state_opt_item: strlcpy");
3580 $$
->type
= PF_STATE_OPT_OVERLOAD
;
3581 $$
->data.overload.flush
= $5;
3585 | MAXSRCNODES NUMBER
{
3586 if
($2 < 0 ||
$2 > UINT_MAX
) {
3587 yyerror("only positive values permitted");
3590 $$
= calloc
(1, sizeof
(struct node_state_opt
));
3592 err
(1, "state_opt_item: calloc");
3593 $$
->type
= PF_STATE_OPT_MAX_SRC_NODES
;
3594 $$
->data.max_src_nodes
= $2;
3599 $$
= calloc
(1, sizeof
(struct node_state_opt
));
3601 err
(1, "state_opt_item: calloc");
3602 $$
->type
= PF_STATE_OPT_PICKUPS
;
3603 $$
->data.pickup_mode
= PF_PICKUPS_ENABLED
;
3608 $$
= calloc
(1, sizeof
(struct node_state_opt
));
3610 err
(1, "state_opt_item: calloc");
3611 $$
->type
= PF_STATE_OPT_PICKUPS
;
3612 $$
->data.pickup_mode
= PF_PICKUPS_DISABLED
;
3617 $$
= calloc
(1, sizeof
(struct node_state_opt
));
3619 err
(1, "state_opt_item: calloc");
3620 $$
->type
= PF_STATE_OPT_PICKUPS
;
3621 $$
->data.pickup_mode
= PF_PICKUPS_HASHONLY
;
3626 $$
= calloc
(1, sizeof
(struct node_state_opt
));
3628 err
(1, "state_opt_item: calloc");
3629 $$
->type
= PF_STATE_OPT_SRCTRACK
;
3630 $$
->data.src_track
= $1;
3635 $$
= calloc
(1, sizeof
(struct node_state_opt
));
3637 err
(1, "state_opt_item: calloc");
3638 $$
->type
= PF_STATE_OPT_STATELOCK
;
3639 $$
->data.statelock
= $1;
3644 $$
= calloc
(1, sizeof
(struct node_state_opt
));
3646 err
(1, "state_opt_item: calloc");
3647 $$
->type
= PF_STATE_OPT_SLOPPY
;
3654 if
($2 < 0 ||
$2 > UINT_MAX
) {
3655 yyerror("only positive values permitted");
3658 for
(i
= 0; pf_timeouts
[i
].name
&&
3659 strcmp
(pf_timeouts
[i
].name
, $1); ++i
)
3661 if
(!pf_timeouts
[i
].name
) {
3662 yyerror("illegal timeout name %s", $1);
3666 if
(strchr
(pf_timeouts
[i
].name
, '.') == NULL
) {
3667 yyerror("illegal state timeout %s", $1);
3672 $$
= calloc
(1, sizeof
(struct node_state_opt
));
3674 err
(1, "state_opt_item: calloc");
3675 $$
->type
= PF_STATE_OPT_TIMEOUT
;
3676 $$
->data.timeout.number
= pf_timeouts
[i
].timeout
;
3677 $$
->data.timeout.seconds
= $2;
3683 label
: LABEL STRING
{
3688 qname
: QUEUE STRING
{
3692 | QUEUE
'(' STRING
')' {
3696 | QUEUE
'(' STRING comma STRING
')' {
3702 no
: /* empty */ { $$
= 0; }
3706 portstar
: numberstring
{
3707 if
(parseport
($1, &$$
, PPORT_RANGE|PPORT_STAR
) == -1) {
3715 redirspec
: host
{ $$
= $1; }
3716 |
'{' optnl redir_host_list
'}' { $$
= $3; }
3719 redir_host_list
: host optnl
{ $$
= $1; }
3720 | redir_host_list comma host optnl
{
3721 $1->tail
->next
= $3;
3722 $1->tail
= $3->tail
;
3727 redirpool
: /* empty */ { $$
= NULL
; }
3729 $$
= calloc
(1, sizeof
(struct redirection
));
3731 err
(1, "redirection: calloc");
3733 $$
->rport.a
= $$
->rport.b
= $$
->rport.t
= 0;
3735 | ARROW redirspec PORT portstar
{
3736 $$
= calloc
(1, sizeof
(struct redirection
));
3738 err
(1, "redirection: calloc");
3744 hashkey
: /* empty */
3746 $$
= calloc
(1, sizeof
(struct pf_poolhashkey
));
3748 err
(1, "hashkey: calloc");
3749 $$
->key32
[0] = arc4random
();
3750 $$
->key32
[1] = arc4random
();
3751 $$
->key32
[2] = arc4random
();
3752 $$
->key32
[3] = arc4random
();
3756 if
(!strncmp
($1, "0x", 2)) {
3757 if
(strlen
($1) != 34) {
3759 yyerror("hex key must be 128 bits "
3760 "(32 hex digits) long");
3763 $$
= calloc
(1, sizeof
(struct pf_poolhashkey
));
3765 err
(1, "hashkey: calloc");
3767 if
(sscanf
($1, "0x%8x%8x%8x%8x",
3768 &$$
->key32
[0], &$$
->key32
[1],
3769 &$$
->key32
[2], &$$
->key32
[3]) != 4) {
3772 yyerror("invalid hex key");
3778 $$
= calloc
(1, sizeof
(struct pf_poolhashkey
));
3780 err
(1, "hashkey: calloc");
3782 MD5Update
(&context
, (unsigned char *)$1,
3784 MD5Final
((unsigned char *)$$
, &context
);
3785 $$
->key32
[0] = htonl
($$
->key32
[0]);
3786 $$
->key32
[1] = htonl
($$
->key32
[1]);
3787 $$
->key32
[2] = htonl
($$
->key32
[2]);
3788 $$
->key32
[3] = htonl
($$
->key32
[3]);
3794 pool_opts
: { bzero
(&pool_opts
, sizeof pool_opts
); }
3798 bzero
(&pool_opts
, sizeof pool_opts
);
3803 pool_opts_l
: pool_opts_l pool_opt
3807 pool_opt
: BITMASK
{
3808 if
(pool_opts.type
) {
3809 yyerror("pool type cannot be redefined");
3812 pool_opts.type
= PF_POOL_BITMASK
;
3815 if
(pool_opts.type
) {
3816 yyerror("pool type cannot be redefined");
3819 pool_opts.type
= PF_POOL_RANDOM
;
3821 | SOURCEHASH hashkey
{
3822 if
(pool_opts.type
) {
3823 yyerror("pool type cannot be redefined");
3826 pool_opts.type
= PF_POOL_SRCHASH
;
3830 if
(pool_opts.type
) {
3831 yyerror("pool type cannot be redefined");
3834 pool_opts.type
= PF_POOL_ROUNDROBIN
;
3837 if
(pool_opts.staticport
) {
3838 yyerror("static-port cannot be redefined");
3841 pool_opts.staticport
= 1;
3844 if
(filter_opts.marker
& POM_STICKYADDRESS
) {
3845 yyerror("sticky-address cannot be redefined");
3848 pool_opts.marker |
= POM_STICKYADDRESS
;
3849 pool_opts.opts |
= PF_POOL_STICKYADDR
;
3853 redirection
: /* empty */ { $$
= NULL
; }
3855 $$
= calloc
(1, sizeof
(struct redirection
));
3857 err
(1, "redirection: calloc");
3859 $$
->rport.a
= $$
->rport.b
= $$
->rport.t
= 0;
3861 | ARROW host PORT portstar
{
3862 $$
= calloc
(1, sizeof
(struct redirection
));
3864 err
(1, "redirection: calloc");
3870 natpasslog
: /* empty */ { $$.b1
= $$.b2
= 0; $$.w2
= 0; }
3871 | PASS
{ $$.b1
= 1; $$.b2
= 0; $$.w2
= 0; }
3872 | PASS log
{ $$.b1
= 1; $$.b2
= $2.log
; $$.w2
= $2.logif
; }
3873 | log
{ $$.b1
= 0; $$.b2
= $1.log
; $$.w2
= $1.logif
; }
3876 nataction
: no NAT natpasslog
{
3878 yyerror("\"pass\" not valid with \"no\"");
3889 | no RDR natpasslog
{
3891 yyerror("\"pass\" not valid with \"no\"");
3904 natrule
: nataction interface af proto fromto tag tagged rtable
3909 if
(check_rulestate
(PFCTL_STATE_NAT
))
3912 memset
(&r
, 0, sizeof
(r
));
3921 if
($5.src.host
&& $5.src.host
->af
&&
3922 !$5.src.host
->ifindex
)
3923 r.af
= $5.src.host
->af
;
3924 else if
($5.dst.host
&& $5.dst.host
->af
&&
3925 !$5.dst.host
->ifindex
)
3926 r.af
= $5.dst.host
->af
;
3930 if
(strlcpy
(r.tagname
, $6, PF_TAG_NAME_SIZE
) >=
3932 yyerror("tag too long, max %u chars",
3933 PF_TAG_NAME_SIZE
- 1);
3938 if
(strlcpy
(r.match_tagname
, $7.name
,
3939 PF_TAG_NAME_SIZE
) >= PF_TAG_NAME_SIZE
) {
3940 yyerror("tag too long, max %u chars",
3941 PF_TAG_NAME_SIZE
- 1);
3944 r.match_tag_not
= $7.neg
;
3947 if
(r.action
== PF_NONAT || r.action
== PF_NORDR
) {
3949 yyerror("translation rule with 'no' "
3950 "does not need '->'");
3954 if
($9 == NULL ||
$9->host
== NULL
) {
3955 yyerror("translation rule requires '-> "
3959 if
(!r.af
&& ! $9->host
->ifindex
)
3960 r.af
= $9->host
->af
;
3962 remove_invalid_hosts
(&$9->host
, &r.af
);
3963 if
(invalid_redirect
($9->host
, r.af
))
3965 if
(check_netmask
($9->host
, r.af
))
3968 r.rpool.proxy_port
[0] = ntohs
($9->rport.a
);
3972 if
(!$9->rport.b
&& $9->rport.t
&&
3973 $5.dst.port
!= NULL
) {
3974 r.rpool.proxy_port
[1] =
3975 ntohs
($9->rport.a
) +
3977 $5.dst.port
->port
[1]) -
3979 $5.dst.port
->port
[0]));
3981 r.rpool.proxy_port
[1] =
3985 r.rpool.proxy_port
[1] =
3987 if
(!r.rpool.proxy_port
[0] &&
3988 !r.rpool.proxy_port
[1]) {
3989 r.rpool.proxy_port
[0] =
3990 PF_NAT_PROXY_PORT_LOW
;
3991 r.rpool.proxy_port
[1] =
3992 PF_NAT_PROXY_PORT_HIGH
;
3993 } else if
(!r.rpool.proxy_port
[1])
3994 r.rpool.proxy_port
[1] =
3995 r.rpool.proxy_port
[0];
4001 r.rpool.opts
= $10.type
;
4002 if
((r.rpool.opts
& PF_POOL_TYPEMASK
) ==
4003 PF_POOL_NONE
&& ($9->host
->next
!= NULL ||
4004 $9->host
->addr.type
== PF_ADDR_TABLE ||
4005 DYNIF_MULTIADDR
($9->host
->addr
)))
4006 r.rpool.opts
= PF_POOL_ROUNDROBIN
;
4007 if
((r.rpool.opts
& PF_POOL_TYPEMASK
) !=
4008 PF_POOL_ROUNDROBIN
&&
4009 disallow_table
($9->host
, "tables are only "
4010 "supported in round-robin redirection "
4013 if
((r.rpool.opts
& PF_POOL_TYPEMASK
) !=
4014 PF_POOL_ROUNDROBIN
&&
4015 disallow_alias
($9->host
, "interface (%s) "
4016 "is only supported in round-robin "
4017 "redirection pools"))
4019 if
($9->host
->next
!= NULL
) {
4020 if
((r.rpool.opts
& PF_POOL_TYPEMASK
) !=
4021 PF_POOL_ROUNDROBIN
) {
4022 yyerror("only round-robin "
4023 "valid for multiple "
4024 "redirection addresses");
4030 if
($10.key
!= NULL
)
4031 memcpy
(&r.rpool.key
, $10.key
,
4032 sizeof
(struct pf_poolhashkey
));
4035 r.rpool.opts |
= $10.opts
;
4037 if
($10.staticport
) {
4038 if
(r.action
!= PF_NAT
) {
4039 yyerror("the 'static-port' option is "
4040 "only valid with nat rules");
4043 if
(r.rpool.proxy_port
[0] !=
4044 PF_NAT_PROXY_PORT_LOW
&&
4045 r.rpool.proxy_port
[1] !=
4046 PF_NAT_PROXY_PORT_HIGH
) {
4047 yyerror("the 'static-port' option can't"
4048 " be used when specifying a port"
4052 r.rpool.proxy_port
[0] = 0;
4053 r.rpool.proxy_port
[1] = 0;
4056 expand_rule
(&r
, $2, $9 == NULL ? NULL
: $9->host
, $4,
4057 $5.src_os
, $5.src.host
, $5.src.port
, $5.dst.host
,
4058 $5.dst.port
, 0, 0, 0, "");
4063 binatrule
: no BINAT natpasslog interface af proto FROM host toipspec tag
4064 tagged rtable redirection
4066 struct pf_rule binat
;
4067 struct pf_pooladdr
*pa
;
4069 if
(check_rulestate
(PFCTL_STATE_NAT
))
4071 if
(disallow_urpf_failed
($9, "\"urpf-failed\" is not "
4072 "permitted as a binat destination"))
4075 memset
(&binat
, 0, sizeof
(binat
));
4078 yyerror("\"pass\" not valid with \"no\"");
4082 binat.action
= PF_NOBINAT
;
4084 binat.action
= PF_BINAT
;
4085 binat.natpass
= $3.b1
;
4087 binat.logif
= $3.w2
;
4089 if
(!binat.af
&& $8 != NULL
&& $8->af
)
4091 if
(!binat.af
&& $9 != NULL
&& $9->af
)
4094 if
(!binat.af
&& $13 != NULL
&& $13->host
)
4095 binat.af
= $13->host
->af
;
4097 yyerror("address family (inet/inet6) "
4103 memcpy
(binat.ifname
, $4->ifname
,
4104 sizeof
(binat.ifname
));
4105 binat.ifnot
= $4->not
;
4110 if
(strlcpy
(binat.tagname
, $10,
4111 PF_TAG_NAME_SIZE
) >= PF_TAG_NAME_SIZE
) {
4112 yyerror("tag too long, max %u chars",
4113 PF_TAG_NAME_SIZE
- 1);
4117 if
(strlcpy
(binat.match_tagname
, $11.name
,
4118 PF_TAG_NAME_SIZE
) >= PF_TAG_NAME_SIZE
) {
4119 yyerror("tag too long, max %u chars",
4120 PF_TAG_NAME_SIZE
- 1);
4123 binat.match_tag_not
= $11.neg
;
4124 binat.rtableid
= $12;
4127 binat.proto
= $6->proto
;
4131 if
($8 != NULL
&& disallow_table
($8, "invalid use of "
4132 "table <%s> as the source address of a binat rule"))
4134 if
($8 != NULL
&& disallow_alias
($8, "invalid use of "
4135 "interface (%s) as the source address of a binat "
4138 if
($13 != NULL
&& $13->host
!= NULL
&& disallow_table
(
4139 $13->host
, "invalid use of table <%s> as the "
4140 "redirect address of a binat rule"))
4142 if
($13 != NULL
&& $13->host
!= NULL
&& disallow_alias
(
4143 $13->host
, "invalid use of interface (%s) as the "
4144 "redirect address of a binat rule"))
4149 yyerror("multiple binat ip addresses");
4152 if
($8->addr.type
== PF_ADDR_DYNIFTL
)
4154 if
($8->af
!= binat.af
) {
4155 yyerror("binat ip versions must match");
4158 if
(check_netmask
($8, binat.af
))
4160 memcpy
(&binat.src.addr
, &$8->addr
,
4161 sizeof
(binat.src.addr
));
4166 yyerror("multiple binat ip addresses");
4169 if
($9->af
!= binat.af
&& $9->af
) {
4170 yyerror("binat ip versions must match");
4173 if
(check_netmask
($9, binat.af
))
4175 memcpy
(&binat.dst.addr
, &$9->addr
,
4176 sizeof
(binat.dst.addr
));
4177 binat.dst.neg
= $9->not
;
4181 if
(binat.action
== PF_NOBINAT
) {
4183 yyerror("'no binat' rule does not need"
4188 if
($13 == NULL ||
$13->host
== NULL
) {
4189 yyerror("'binat' rule requires"
4194 remove_invalid_hosts
(&$13->host
, &binat.af
);
4195 if
(invalid_redirect
($13->host
, binat.af
))
4197 if
($13->host
->next
!= NULL
) {
4198 yyerror("binat rule must redirect to "
4199 "a single address");
4202 if
(check_netmask
($13->host
, binat.af
))
4205 if
(!PF_AZERO
(&binat.src.addr.v.a.mask
,
4207 !PF_AEQ
(&binat.src.addr.v.a.mask
,
4208 &$13->host
->addr.v.a.mask
, binat.af
)) {
4209 yyerror("'binat' source mask and "
4210 "redirect mask must be the same");
4214 TAILQ_INIT
(&binat.rpool.list
);
4215 pa
= calloc
(1, sizeof
(struct pf_pooladdr
));
4217 err
(1, "binat: calloc");
4218 pa
->addr
= $13->host
->addr
;
4220 TAILQ_INSERT_TAIL
(&binat.rpool.list
,
4226 pfctl_add_rule
(pf
, &binat
, "");
4230 tag
: /* empty */ { $$
= NULL
; }
4231 | TAG STRING
{ $$
= $2; }
4234 tagged
: /* empty */ { $$.neg
= 0; $$.name
= NULL
; }
4235 | not TAGGED
string { $$.neg
= $1; $$.name
= $3; }
4238 rtable
: /* empty */ { $$
= -1; }
4244 route_host
: STRING
{
4245 $$
= calloc
(1, sizeof
(struct node_host
));
4247 err
(1, "route_host: calloc");
4249 set_ipmask
($$
, 128);
4253 |
'(' STRING host
')' {
4259 route_host_list
: route_host optnl
{ $$
= $1; }
4260 | route_host_list comma route_host optnl
{
4263 if
($1->af
!= $3->af
) {
4264 yyerror("all pool addresses must be in the "
4265 "same address family");
4268 $1->tail
->next
= $3;
4269 $1->tail
= $3->tail
;
4274 routespec
: route_host
{ $$
= $1; }
4275 |
'{' optnl route_host_list
'}' { $$
= $3; }
4278 route
: /* empty */ {
4285 $$.rt
= PF_FASTROUTE
;
4288 | ROUTETO routespec pool_opts
{
4291 $$.pool_opts
= $3.type |
$3.opts
;
4295 | REPLYTO routespec pool_opts
{
4298 $$.pool_opts
= $3.type |
$3.opts
;
4302 | DUPTO routespec pool_opts
{
4305 $$.pool_opts
= $3.type |
$3.opts
;
4311 timeout_spec
: STRING NUMBER
4313 if
(check_rulestate
(PFCTL_STATE_OPTION
)) {
4317 if
($2 < 0 ||
$2 > UINT_MAX
) {
4318 yyerror("only positive values permitted");
4321 if
(pfctl_set_timeout
(pf
, $1, $2, 0) != 0) {
4322 yyerror("unknown timeout %s", $1);
4330 timeout_list
: timeout_list comma timeout_spec optnl
4331 | timeout_spec optnl
4334 limit_spec
: STRING NUMBER
4336 if
(check_rulestate
(PFCTL_STATE_OPTION
)) {
4340 if
($2 < 0 ||
$2 > UINT_MAX
) {
4341 yyerror("only positive values permitted");
4344 if
(pfctl_set_limit
(pf
, $1, $2) != 0) {
4345 yyerror("unable to set limit %s %" PRId64
, $1, $2);
4353 limit_list
: limit_list comma limit_spec optnl
4361 yesno
: NO
{ $$
= 0; }
4363 if
(!strcmp
($1, "yes"))
4366 yyerror("invalid value '%s', expected 'yes' "
4375 unaryop
: '=' { $$
= PF_OP_EQ
; }
4376 |
'!' '=' { $$
= PF_OP_NE
; }
4377 |
'<' '=' { $$
= PF_OP_LE
; }
4378 |
'<' { $$
= PF_OP_LT
; }
4379 |
'>' '=' { $$
= PF_OP_GE
; }
4380 |
'>' { $$
= PF_OP_GT
; }
4386 yyerror(const char *fmt
, ...
)
4392 fprintf
(stderr
, "%s:%d: ", file
->name
, yylval.lineno
);
4393 vfprintf
(stderr
, fmt
, ap
);
4394 fprintf
(stderr
, "\n");
4400 disallow_table
(struct node_host
*h
, const char *fmt
)
4402 for
(; h
!= NULL
; h
= h
->next
)
4403 if
(h
->addr.type
== PF_ADDR_TABLE
) {
4404 yyerror(fmt
, h
->addr.v.tblname
);
4411 disallow_urpf_failed
(struct node_host
*h
, const char *fmt
)
4413 for
(; h
!= NULL
; h
= h
->next
)
4414 if
(h
->addr.type
== PF_ADDR_URPFFAILED
) {
4422 disallow_alias
(struct node_host
*h
, const char *fmt
)
4424 for
(; h
!= NULL
; h
= h
->next
)
4425 if
(DYNIF_MULTIADDR
(h
->addr
)) {
4426 yyerror(fmt
, h
->addr.v.tblname
);
4433 rule_consistent
(struct pf_rule
*r
, int anchor_call __unused
)
4437 switch
(r
->action
) {
4442 problems
= filter_consistent
(r
, anchor_call
);
4446 problems
= nat_consistent
(r
);
4450 problems
= rdr_consistent
(r
);
4461 filter_consistent
(struct pf_rule
*r
, int anchor_call __unused
)
4465 if
(r
->proto
!= IPPROTO_TCP
&& r
->proto
!= IPPROTO_UDP
&&
4466 (r
->src.port_op || r
->dst.port_op
)) {
4467 yyerror("port only applies to tcp/udp");
4470 if
(r
->proto
!= IPPROTO_ICMP
&& r
->proto
!= IPPROTO_ICMPV6
&&
4471 (r
->type || r
->code
)) {
4472 yyerror("icmp-type/code only applies to icmp");
4475 if
(!r
->af
&& (r
->type || r
->code
)) {
4476 yyerror("must indicate address family with icmp-type/code");
4479 if
(r
->overload_tblname
[0] &&
4480 r
->max_src_conn
== 0 && r
->max_src_conn_rate.seconds
== 0) {
4481 yyerror("'overload' requires 'max-src-conn' "
4482 "or 'max-src-conn-rate'");
4485 if
((r
->proto
== IPPROTO_ICMP
&& r
->af
== AF_INET6
) ||
4486 (r
->proto
== IPPROTO_ICMPV6
&& r
->af
== AF_INET
)) {
4487 yyerror("proto %s doesn't match address family %s",
4488 r
->proto
== IPPROTO_ICMP ?
"icmp" : "icmp6",
4489 r
->af
== AF_INET ?
"inet" : "inet6");
4492 if
(r
->allow_opts
&& r
->action
!= PF_PASS
) {
4493 yyerror("allow-opts can only be specified for pass rules");
4496 if
(r
->rule_flag
& PFRULE_FRAGMENT
&& (r
->src.port_op ||
4497 r
->dst.port_op || r
->flagset || r
->type || r
->code
)) {
4498 yyerror("fragments can be filtered only on IP header fields");
4501 if
(r
->rule_flag
& PFRULE_RETURNRST
&& r
->proto
!= IPPROTO_TCP
) {
4502 yyerror("return-rst can only be applied to TCP rules");
4505 if
(r
->max_src_nodes
&& !(r
->rule_flag
& PFRULE_RULESRCTRACK
)) {
4506 yyerror("max-src-nodes requires 'source-track rule'");
4509 if
(r
->action
== PF_DROP
&& r
->keep_state
) {
4510 yyerror("keep state on block rules doesn't make sense");
4513 if
(r
->rule_flag
& PFRULE_STATESLOPPY
&&
4514 (r
->keep_state
== PF_STATE_MODULATE ||
4515 r
->keep_state
== PF_STATE_SYNPROXY
)) {
4516 yyerror("sloppy state matching cannot be used with "
4517 "synproxy state or modulate state");
4524 nat_consistent
(struct pf_rule
*r __unused
)
4526 return
(0); /* yeah! */
4530 rdr_consistent
(struct pf_rule
*r
)
4534 if
(r
->proto
!= IPPROTO_TCP
&& r
->proto
!= IPPROTO_UDP
) {
4535 if
(r
->src.port_op
) {
4536 yyerror("src port only applies to tcp/udp");
4539 if
(r
->dst.port_op
) {
4540 yyerror("dst port only applies to tcp/udp");
4543 if
(r
->rpool.proxy_port
[0]) {
4544 yyerror("rpool port only applies to tcp/udp");
4548 if
(r
->dst.port_op
&&
4549 r
->dst.port_op
!= PF_OP_EQ
&& r
->dst.port_op
!= PF_OP_RRG
) {
4550 yyerror("invalid port operator for rdr destination port");
4557 process_tabledef
(char *name
, struct table_opts
*opts
)
4559 struct pfr_buffer ab
;
4560 struct node_tinit
*ti
;
4562 bzero
(&ab
, sizeof
(ab
));
4563 ab.pfrb_type
= PFRB_ADDRS
;
4564 SIMPLEQ_FOREACH
(ti
, &opts
->init_nodes
, entries
) {
4566 if
(pfr_buf_load
(&ab
, ti
->file
, 0, append_addr
)) {
4568 yyerror("cannot load \"%s\": %s",
4569 ti
->file
, strerror
(errno
));
4571 yyerror("file \"%s\" contains bad data",
4576 if
(append_addr_host
(&ab
, ti
->host
, 0, 0)) {
4577 yyerror("cannot create address buffer: %s",
4582 if
(pf
->opts
& PF_OPT_VERBOSE
)
4583 print_tabledef
(name
, opts
->flags
, opts
->init_addr
,
4585 if
(!(pf
->opts
& PF_OPT_NOACTION
) &&
4586 pfctl_define_table
(name
, opts
->flags
, opts
->init_addr
,
4587 pf
->anchor
->name
, &ab
, pf
->anchor
->ruleset.tticket
)) {
4588 yyerror("cannot define table %s: %s", name
,
4589 pfr_strerror
(errno
));
4605 /* macro gore, but you should've seen the prior indentation nightmare... */
4607 #define FREE_LIST(T,r) \
4610 while
(node
!= NULL
) { \
4612 node
= node
->next
; \
4617 #define LOOP_THROUGH(T,n,r,C) \
4621 r
= calloc
(1, sizeof
(T
)); \
4623 err
(1, "LOOP: calloc"); \
4627 while
(n
!= NULL
) { \
4636 expand_label_str
(char *label
, size_t len
, const char *srch
, const char *repl
)
4641 if
((tmp
= calloc
(1, len
)) == NULL
)
4642 err
(1, "expand_label_str: calloc");
4644 while
((q
= strstr
(p
, srch
)) != NULL
) {
4646 if
((strlcat
(tmp
, p
, len
) >= len
) ||
4647 (strlcat
(tmp
, repl
, len
) >= len
))
4648 errx
(1, "expand_label: label too long");
4652 if
(strlcat
(tmp
, p
, len
) >= len
)
4653 errx
(1, "expand_label: label too long");
4654 strlcpy
(label
, tmp
, len
); /* always fits */
4659 expand_label_if
(const char *name
, char *label
, size_t len
, const char *ifname
)
4661 if
(strstr
(label
, name
) != NULL
) {
4663 expand_label_str
(label
, len
, name
, "any");
4665 expand_label_str
(label
, len
, name
, ifname
);
4670 expand_label_addr
(const char *name
, char *label
, size_t len
, sa_family_t af
,
4671 struct node_host
*h
)
4673 char tmp
[64], tmp_not
[66];
4675 if
(strstr
(label
, name
) != NULL
) {
4676 switch
(h
->addr.type
) {
4677 case PF_ADDR_DYNIFTL
:
4678 snprintf
(tmp
, sizeof
(tmp
), "(%s)", h
->addr.v.ifname
);
4681 snprintf
(tmp
, sizeof
(tmp
), "<%s>", h
->addr.v.tblname
);
4683 case PF_ADDR_NOROUTE
:
4684 snprintf
(tmp
, sizeof
(tmp
), "no-route");
4686 case PF_ADDR_URPFFAILED
:
4687 snprintf
(tmp
, sizeof
(tmp
), "urpf-failed");
4689 case PF_ADDR_ADDRMASK
:
4690 if
(!af ||
(PF_AZERO
(&h
->addr.v.a.addr
, af
) &&
4691 PF_AZERO
(&h
->addr.v.a.mask
, af
)))
4692 snprintf
(tmp
, sizeof
(tmp
), "any");
4697 if
(inet_ntop
(af
, &h
->addr.v.a.addr
, a
,
4699 snprintf
(tmp
, sizeof
(tmp
), "?");
4701 bits
= unmask
(&h
->addr.v.a.mask
, af
);
4702 if
((af
== AF_INET
&& bits
< 32) ||
4703 (af
== AF_INET6
&& bits
< 128))
4704 snprintf
(tmp
, sizeof
(tmp
),
4707 snprintf
(tmp
, sizeof
(tmp
),
4713 snprintf
(tmp
, sizeof
(tmp
), "?");
4718 snprintf
(tmp_not
, sizeof
(tmp_not
), "! %s", tmp
);
4719 expand_label_str
(label
, len
, name
, tmp_not
);
4721 expand_label_str
(label
, len
, name
, tmp
);
4726 expand_label_port
(const char *name
, char *label
, size_t len
,
4727 struct node_port
*port
)
4729 char a1
[6], a2
[6], op
[13] = "";
4731 if
(strstr
(label
, name
) != NULL
) {
4732 snprintf
(a1
, sizeof
(a1
), "%u", ntohs
(port
->port
[0]));
4733 snprintf
(a2
, sizeof
(a2
), "%u", ntohs
(port
->port
[1]));
4736 else if
(port
->op
== PF_OP_IRG
)
4737 snprintf
(op
, sizeof
(op
), "%s><%s", a1
, a2
);
4738 else if
(port
->op
== PF_OP_XRG
)
4739 snprintf
(op
, sizeof
(op
), "%s<>%s", a1
, a2
);
4740 else if
(port
->op
== PF_OP_EQ
)
4741 snprintf
(op
, sizeof
(op
), "%s", a1
);
4742 else if
(port
->op
== PF_OP_NE
)
4743 snprintf
(op
, sizeof
(op
), "!=%s", a1
);
4744 else if
(port
->op
== PF_OP_LT
)
4745 snprintf
(op
, sizeof
(op
), "<%s", a1
);
4746 else if
(port
->op
== PF_OP_LE
)
4747 snprintf
(op
, sizeof
(op
), "<=%s", a1
);
4748 else if
(port
->op
== PF_OP_GT
)
4749 snprintf
(op
, sizeof
(op
), ">%s", a1
);
4750 else if
(port
->op
== PF_OP_GE
)
4751 snprintf
(op
, sizeof
(op
), ">=%s", a1
);
4752 expand_label_str
(label
, len
, name
, op
);
4757 expand_label_proto
(const char *name
, char *label
, size_t len
, u_int8_t proto
)
4759 struct protoent
*pe
;
4762 if
(strstr
(label
, name
) != NULL
) {
4763 pe
= getprotobynumber
(proto
);
4765 expand_label_str
(label
, len
, name
, pe
->p_name
);
4767 snprintf
(n
, sizeof
(n
), "%u", proto
);
4768 expand_label_str
(label
, len
, name
, n
);
4774 expand_label_nr
(const char *name
, char *label
, size_t len
)
4778 if
(strstr
(label
, name
) != NULL
) {
4779 snprintf
(n
, sizeof
(n
), "%u", pf
->anchor
->match
);
4780 expand_label_str
(label
, len
, name
, n
);
4785 expand_label
(char *label
, size_t len
, const char *ifname
, sa_family_t af
,
4786 struct node_host
*src_host
, struct node_port
*src_port
,
4787 struct node_host
*dst_host
, struct node_port
*dst_port
,
4790 expand_label_if
("$if", label
, len
, ifname
);
4791 expand_label_addr
("$srcaddr", label
, len
, af
, src_host
);
4792 expand_label_addr
("$dstaddr", label
, len
, af
, dst_host
);
4793 expand_label_port
("$srcport", label
, len
, src_port
);
4794 expand_label_port
("$dstport", label
, len
, dst_port
);
4795 expand_label_proto
("$proto", label
, len
, proto
);
4796 expand_label_nr
("$nr", label
, len
);
4800 expand_altq
(struct pf_altq
*a
, struct node_if
*interfaces
,
4801 struct node_queue
*nqueues
, struct node_queue_bw bwspec
,
4802 struct node_queue_opt
*opts
)
4804 struct pf_altq pa
, pb
;
4805 char qname
[PF_QNAME_SIZE
];
4806 struct node_queue
*n
;
4807 struct node_queue_bw bw
;
4810 if
((pf
->loadopt
& PFCTL_FLAG_ALTQ
) == 0) {
4811 FREE_LIST
(struct node_if
, interfaces
);
4812 FREE_LIST
(struct node_queue
, nqueues
);
4816 LOOP_THROUGH
(struct node_if
, interface
, interfaces
,
4817 memcpy
(&pa
, a
, sizeof
(struct pf_altq
));
4818 if
(strlcpy
(pa.ifname
, interface
->ifname
,
4819 sizeof
(pa.ifname
)) >= sizeof
(pa.ifname
))
4820 errx
(1, "expand_altq: strlcpy");
4822 if
(interface
->not
) {
4823 yyerror("altq on ! <interface> is not supported");
4826 if
(eval_pfaltq
(pf
, &pa
, &bwspec
, opts
))
4829 if
(pfctl_add_altq
(pf
, &pa
))
4832 if
(pf
->opts
& PF_OPT_VERBOSE
) {
4833 print_altq
(&pf
->paltq
->altq
, 0,
4835 if
(nqueues
&& nqueues
->tail
) {
4837 LOOP_THROUGH
(struct node_queue
, queue
,
4847 if
(pa.scheduler
== ALTQT_CBQ ||
4848 pa.scheduler
== ALTQT_HFSC
) {
4849 /* now create a root queue */
4850 memset
(&pb
, 0, sizeof
(struct pf_altq
));
4851 if
(strlcpy
(qname
, "root_", sizeof
(qname
)) >=
4853 errx
(1, "expand_altq: strlcpy");
4854 if
(strlcat
(qname
, interface
->ifname
,
4855 sizeof
(qname
)) >= sizeof
(qname
))
4856 errx
(1, "expand_altq: strlcat");
4857 if
(strlcpy
(pb.qname
, qname
,
4858 sizeof
(pb.qname
)) >= sizeof
(pb.qname
))
4859 errx
(1, "expand_altq: strlcpy");
4860 if
(strlcpy
(pb.ifname
, interface
->ifname
,
4861 sizeof
(pb.ifname
)) >= sizeof
(pb.ifname
))
4862 errx
(1, "expand_altq: strlcpy");
4863 pb.qlimit
= pa.qlimit
;
4864 pb.scheduler
= pa.scheduler
;
4865 bw.bw_absolute
= pa.ifbandwidth
;
4867 if
(eval_pfqueue
(pf
, &pb
, &bw
, opts
))
4870 if
(pfctl_add_altq
(pf
, &pb
))
4874 LOOP_THROUGH
(struct node_queue
, queue
, nqueues
,
4875 n
= calloc
(1, sizeof
(struct node_queue
));
4877 err
(1, "expand_altq: calloc");
4878 if
(pa.scheduler
== ALTQT_CBQ ||
4879 pa.scheduler
== ALTQT_HFSC
/*||
4880 pa.scheduler == ALTQT_FAIRQ*/)
4881 if
(strlcpy
(n
->parent
, qname
,
4882 sizeof
(n
->parent
)) >=
4884 errx
(1, "expand_altq: strlcpy");
4885 if
(strlcpy
(n
->queue
, queue
->queue
,
4886 sizeof
(n
->queue
)) >= sizeof
(n
->queue
))
4887 errx
(1, "expand_altq: strlcpy");
4888 if
(strlcpy
(n
->ifname
, interface
->ifname
,
4889 sizeof
(n
->ifname
)) >= sizeof
(n
->ifname
))
4890 errx
(1, "expand_altq: strlcpy");
4891 n
->scheduler
= pa.scheduler
;
4897 queues
->tail
->next
= n
;
4903 FREE_LIST
(struct node_if
, interfaces
);
4904 FREE_LIST
(struct node_queue
, nqueues
);
4910 expand_queue
(struct pf_altq
*a
, struct node_if
*interfaces
,
4911 struct node_queue
*nqueues
, struct node_queue_bw bwspec
,
4912 struct node_queue_opt
*opts
)
4914 struct node_queue
*n
, *nq
;
4919 if
((pf
->loadopt
& PFCTL_FLAG_ALTQ
) == 0) {
4920 FREE_LIST
(struct node_queue
, nqueues
);
4924 if
(queues
== NULL
) {
4925 yyerror("queue %s has no parent", a
->qname
);
4926 FREE_LIST
(struct node_queue
, nqueues
);
4930 LOOP_THROUGH
(struct node_if
, interface
, interfaces
,
4931 LOOP_THROUGH
(struct node_queue
, tqueue
, queues
,
4932 if
(!strncmp
(a
->qname
, tqueue
->queue
, PF_QNAME_SIZE
) &&
4933 (interface
->ifname
[0] == 0 ||
4934 (!interface
->not
&& !strncmp
(interface
->ifname
,
4935 tqueue
->ifname
, IFNAMSIZ
)) ||
4936 (interface
->not
&& strncmp
(interface
->ifname
,
4937 tqueue
->ifname
, IFNAMSIZ
)))) {
4938 /* found ourself in queues */
4941 memcpy
(&pa
, a
, sizeof
(struct pf_altq
));
4943 if
(pa.scheduler
!= ALTQT_NONE
&&
4944 pa.scheduler
!= tqueue
->scheduler
) {
4945 yyerror("exactly one scheduler type "
4946 "per interface allowed");
4949 pa.scheduler
= tqueue
->scheduler
;
4951 /* scheduler dependent error checking */
4952 switch
(pa.scheduler
) {
4954 if
(nqueues
!= NULL
) {
4955 yyerror("priq queues cannot "
4956 "have child queues");
4959 if
(bwspec.bw_absolute
> 0 ||
4960 bwspec.bw_percent
< 100) {
4961 yyerror("priq doesn't take "
4970 if
(strlcpy
(pa.ifname
, tqueue
->ifname
,
4971 sizeof
(pa.ifname
)) >= sizeof
(pa.ifname
))
4972 errx
(1, "expand_queue: strlcpy");
4973 if
(strlcpy
(pa.parent
, tqueue
->parent
,
4974 sizeof
(pa.parent
)) >= sizeof
(pa.parent
))
4975 errx
(1, "expand_queue: strlcpy");
4977 if
(eval_pfqueue
(pf
, &pa
, &bwspec
, opts
))
4980 if
(pfctl_add_altq
(pf
, &pa
))
4983 for
(nq
= nqueues
; nq
!= NULL
; nq
= nq
->next
) {
4984 if
(!strcmp
(a
->qname
, nq
->queue
)) {
4985 yyerror("queue cannot have "
4991 sizeof
(struct node_queue
));
4993 err
(1, "expand_queue: calloc");
4994 if
(strlcpy
(n
->parent
, a
->qname
,
4995 sizeof
(n
->parent
)) >=
4997 errx
(1, "expand_queue strlcpy");
4998 if
(strlcpy
(n
->queue
, nq
->queue
,
4999 sizeof
(n
->queue
)) >=
5001 errx
(1, "expand_queue strlcpy");
5002 if
(strlcpy
(n
->ifname
, tqueue
->ifname
,
5003 sizeof
(n
->ifname
)) >=
5005 errx
(1, "expand_queue strlcpy");
5006 n
->scheduler
= tqueue
->scheduler
;
5012 queues
->tail
->next
= n
;
5016 if
((pf
->opts
& PF_OPT_VERBOSE
) && (
5017 (found
== 1 && interface
->ifname
[0] == 0) ||
5018 (found
> 0 && interface
->ifname
[0] != 0))) {
5019 print_queue
(&pf
->paltq
->altq
, 0,
5020 &bwspec
, interface
->ifname
[0] != 0,
5022 if
(nqueues
&& nqueues
->tail
) {
5024 LOOP_THROUGH
(struct node_queue
,
5037 FREE_LIST
(struct node_queue
, nqueues
);
5038 FREE_LIST
(struct node_if
, interfaces
);
5041 yyerror("queue %s has no parent", a
->qname
);
5052 expand_rule
(struct pf_rule
*r
,
5053 struct node_if
*interfaces
, struct node_host
*rpool_hosts
,
5054 struct node_proto
*protos
, struct node_os
*src_oses
,
5055 struct node_host
*src_hosts
, struct node_port
*src_ports
,
5056 struct node_host
*dst_hosts
, struct node_port
*dst_ports
,
5057 struct node_uid
*uids
, struct node_gid
*gids
, struct node_icmp
*icmp_types
,
5058 const char *anchor_call
)
5060 sa_family_t af
= r
->af
;
5061 int added
= 0, error = 0;
5062 char ifname
[IF_NAMESIZE
];
5063 char label
[PF_RULE_LABEL_SIZE
];
5064 char tagname
[PF_TAG_NAME_SIZE
];
5065 char match_tagname
[PF_TAG_NAME_SIZE
];
5066 struct pf_pooladdr
*pa
;
5067 struct node_host
*h
;
5068 u_int8_t flags
, flagset
, keep_state
;
5070 if
(strlcpy
(label
, r
->label
, sizeof
(label
)) >= sizeof
(label
))
5071 errx
(1, "expand_rule: strlcpy");
5072 if
(strlcpy
(tagname
, r
->tagname
, sizeof
(tagname
)) >= sizeof
(tagname
))
5073 errx
(1, "expand_rule: strlcpy");
5074 if
(strlcpy
(match_tagname
, r
->match_tagname
, sizeof
(match_tagname
)) >=
5075 sizeof
(match_tagname
))
5076 errx
(1, "expand_rule: strlcpy");
5078 flagset
= r
->flagset
;
5079 keep_state
= r
->keep_state
;
5081 LOOP_THROUGH
(struct node_if
, interface
, interfaces
,
5082 LOOP_THROUGH
(struct node_proto
, proto
, protos
,
5083 LOOP_THROUGH
(struct node_icmp
, icmp_type
, icmp_types
,
5084 LOOP_THROUGH
(struct node_host
, src_host
, src_hosts
,
5085 LOOP_THROUGH
(struct node_port
, src_port
, src_ports
,
5086 LOOP_THROUGH
(struct node_os
, src_os
, src_oses
,
5087 LOOP_THROUGH
(struct node_host
, dst_host
, dst_hosts
,
5088 LOOP_THROUGH
(struct node_port
, dst_port
, dst_ports
,
5089 LOOP_THROUGH
(struct node_uid
, uid
, uids
,
5090 LOOP_THROUGH
(struct node_gid
, gid
, gids
,
5093 /* for link-local IPv6 address, interface must match up */
5094 if
((r
->af
&& src_host
->af
&& r
->af
!= src_host
->af
) ||
5095 (r
->af
&& dst_host
->af
&& r
->af
!= dst_host
->af
) ||
5096 (src_host
->af
&& dst_host
->af
&&
5097 src_host
->af
!= dst_host
->af
) ||
5098 (src_host
->ifindex
&& dst_host
->ifindex
&&
5099 src_host
->ifindex
!= dst_host
->ifindex
) ||
5100 (src_host
->ifindex
&& *interface
->ifname
&&
5101 src_host
->ifindex
!= if_nametoindex
(interface
->ifname
)) ||
5102 (dst_host
->ifindex
&& *interface
->ifname
&&
5103 dst_host
->ifindex
!= if_nametoindex
(interface
->ifname
)))
5105 if
(!r
->af
&& src_host
->af
)
5106 r
->af
= src_host
->af
;
5107 else if
(!r
->af
&& dst_host
->af
)
5108 r
->af
= dst_host
->af
;
5110 if
(*interface
->ifname
)
5111 strlcpy
(r
->ifname
, interface
->ifname
,
5113 else if
(if_indextoname
(src_host
->ifindex
, ifname
))
5114 strlcpy
(r
->ifname
, ifname
, sizeof
(r
->ifname
));
5115 else if
(if_indextoname
(dst_host
->ifindex
, ifname
))
5116 strlcpy
(r
->ifname
, ifname
, sizeof
(r
->ifname
));
5118 memset
(r
->ifname
, '\0', sizeof
(r
->ifname
));
5120 if
(strlcpy
(r
->label
, label
, sizeof
(r
->label
)) >=
5122 errx
(1, "expand_rule: strlcpy");
5123 if
(strlcpy
(r
->tagname
, tagname
, sizeof
(r
->tagname
)) >=
5125 errx
(1, "expand_rule: strlcpy");
5126 if
(strlcpy
(r
->match_tagname
, match_tagname
,
5127 sizeof
(r
->match_tagname
)) >= sizeof
(r
->match_tagname
))
5128 errx
(1, "expand_rule: strlcpy");
5129 expand_label
(r
->label
, PF_RULE_LABEL_SIZE
, r
->ifname
, r
->af
,
5130 src_host
, src_port
, dst_host
, dst_port
, proto
->proto
);
5131 expand_label
(r
->tagname
, PF_TAG_NAME_SIZE
, r
->ifname
, r
->af
,
5132 src_host
, src_port
, dst_host
, dst_port
, proto
->proto
);
5133 expand_label
(r
->match_tagname
, PF_TAG_NAME_SIZE
, r
->ifname
,
5134 r
->af
, src_host
, src_port
, dst_host
, dst_port
,
5137 error += check_netmask
(src_host
, r
->af
);
5138 error += check_netmask
(dst_host
, r
->af
);
5140 r
->ifnot
= interface
->not
;
5141 r
->proto
= proto
->proto
;
5142 r
->src.addr
= src_host
->addr
;
5143 r
->src.neg
= src_host
->not
;
5144 r
->src.port
[0] = src_port
->port
[0];
5145 r
->src.port
[1] = src_port
->port
[1];
5146 r
->src.port_op
= src_port
->op
;
5147 r
->dst.addr
= dst_host
->addr
;
5148 r
->dst.neg
= dst_host
->not
;
5149 r
->dst.port
[0] = dst_port
->port
[0];
5150 r
->dst.port
[1] = dst_port
->port
[1];
5151 r
->dst.port_op
= dst_port
->op
;
5152 r
->uid.op
= uid
->op
;
5153 r
->uid.uid
[0] = uid
->uid
[0];
5154 r
->uid.uid
[1] = uid
->uid
[1];
5155 r
->gid.op
= gid
->op
;
5156 r
->gid.gid
[0] = gid
->gid
[0];
5157 r
->gid.gid
[1] = gid
->gid
[1];
5158 r
->type
= icmp_type
->type
;
5159 r
->code
= icmp_type
->code
;
5161 if
((keep_state
== PF_STATE_MODULATE ||
5162 keep_state
== PF_STATE_SYNPROXY
) &&
5163 r
->proto
&& r
->proto
!= IPPROTO_TCP
)
5164 r
->keep_state
= PF_STATE_NORMAL
;
5166 r
->keep_state
= keep_state
;
5168 if
(r
->proto
&& r
->proto
!= IPPROTO_TCP
) {
5173 r
->flagset
= flagset
;
5175 if
(icmp_type
->proto
&& r
->proto
!= icmp_type
->proto
) {
5176 yyerror("icmp-type mismatch");
5180 if
(src_os
&& src_os
->os
) {
5181 r
->os_fingerprint
= pfctl_get_fingerprint
(src_os
->os
);
5182 if
((pf
->opts
& PF_OPT_VERBOSE2
) &&
5183 r
->os_fingerprint
== PF_OSFP_NOMATCH
)
5185 "warning: unknown '%s' OS fingerprint\n",
5188 r
->os_fingerprint
= PF_OSFP_ANY
;
5191 TAILQ_INIT
(&r
->rpool.list
);
5192 for
(h
= rpool_hosts
; h
!= NULL
; h
= h
->next
) {
5193 pa
= calloc
(1, sizeof
(struct pf_pooladdr
));
5195 err
(1, "expand_rule: calloc");
5197 if
(h
->ifname
!= NULL
) {
5198 if
(strlcpy
(pa
->ifname
, h
->ifname
,
5199 sizeof
(pa
->ifname
)) >=
5201 errx
(1, "expand_rule: strlcpy");
5204 TAILQ_INSERT_TAIL
(&r
->rpool.list
, pa
, entries
);
5207 if
(rule_consistent
(r
, anchor_call
[0]) < 0 ||
error)
5208 yyerror("skipping rule due to errors");
5210 r
->nr
= pf
->astack
[pf
->asd
]->match
++;
5211 pfctl_add_rule
(pf
, r
, anchor_call
);
5217 FREE_LIST
(struct node_if
, interfaces
);
5218 FREE_LIST
(struct node_proto
, protos
);
5219 FREE_LIST
(struct node_host
, src_hosts
);
5220 FREE_LIST
(struct node_port
, src_ports
);
5221 FREE_LIST
(struct node_os
, src_oses
);
5222 FREE_LIST
(struct node_host
, dst_hosts
);
5223 FREE_LIST
(struct node_port
, dst_ports
);
5224 FREE_LIST
(struct node_uid
, uids
);
5225 FREE_LIST
(struct node_gid
, gids
);
5226 FREE_LIST
(struct node_icmp
, icmp_types
);
5227 FREE_LIST
(struct node_host
, rpool_hosts
);
5230 yyerror("rule expands to no valid combination");
5234 expand_skip_interface
(struct node_if
*interfaces
)
5238 if
(!interfaces ||
(!interfaces
->next
&& !interfaces
->not
&&
5239 !strcmp
(interfaces
->ifname
, "none"))) {
5240 if
(pf
->opts
& PF_OPT_VERBOSE
)
5241 printf
("set skip on none\n");
5242 errs
= pfctl_set_interface_flags
(pf
, __DECONST
(char *, ""), PFI_IFLAG_SKIP
, 0);
5246 if
(pf
->opts
& PF_OPT_VERBOSE
)
5247 printf
("set skip on {");
5248 LOOP_THROUGH
(struct node_if
, interface
, interfaces
,
5249 if
(pf
->opts
& PF_OPT_VERBOSE
)
5250 printf
(" %s", interface
->ifname
);
5251 if
(interface
->not
) {
5252 yyerror("skip on ! <interface> is not supported");
5255 errs
+= pfctl_set_interface_flags
(pf
,
5256 interface
->ifname
, PFI_IFLAG_SKIP
, 1);
5258 if
(pf
->opts
& PF_OPT_VERBOSE
)
5261 FREE_LIST
(struct node_if
, interfaces
);
5273 check_rulestate
(int desired_state
)
5275 if
(require_order
&& (rulestate
> desired_state
)) {
5276 yyerror("Rules must be in order: options, normalization, "
5277 "queueing, translation, filtering");
5280 rulestate
= desired_state
;
5285 kw_cmp
(const void *k
, const void *e
)
5287 return
(strcmp
(k
, ((const struct keywords
*)e
)->k_name
));
5293 /* this has to be sorted always */
5294 static const struct keywords keywords
[] = {
5296 { "allow-opts", ALLOWOPTS
},
5298 { "anchor", ANCHOR
},
5299 { "antispoof", ANTISPOOF
},
5301 { "bandwidth", BANDWIDTH
},
5303 { "binat-anchor", BINATANCHOR
},
5304 { "bitmask", BITMASK
},
5306 { "block-policy", BLOCKPOLICY
},
5307 { "buckets", BUCKETS
},
5310 { "crop", FRAGCROP
},
5312 { "divert-reply", DIVERTREPLY
},
5313 { "divert-to", DIVERTTO
},
5315 { "drop-ovl", FRAGDROP
},
5318 { "fastroute", FASTROUTE
},
5319 { "file", FILENAME
},
5320 { "fingerprints", FINGERPRINTS
},
5322 { "floating", FLOATING
},
5325 { "fragment", FRAGMENT
},
5327 { "global", GLOBAL
},
5329 { "hash-only", HASHONLY
},
5332 { "hostid", HOSTID
},
5333 { "icmp-type", ICMPTYPE
},
5334 { "icmp6-type", ICMP6TYPE
},
5335 { "if-bound", IFBOUND
},
5337 { "include", INCLUDE
},
5341 { "keep-policy", KEEPPOLICY
},
5344 { "linkshare", LINKSHARE
},
5347 { "loginterface", LOGINTERFACE
},
5349 { "max-mss", MAXMSS
},
5350 { "max-src-conn", MAXSRCCONN
},
5351 { "max-src-conn-rate", MAXSRCCONNRATE
},
5352 { "max-src-nodes", MAXSRCNODES
},
5353 { "max-src-states", MAXSRCSTATES
},
5354 { "min-ttl", MINTTL
},
5355 { "modulate", MODULATE
},
5357 { "nat-anchor", NATANCHOR
},
5360 { "no-pickups", NOPICKUPS
},
5361 { "no-route", NOROUTE
},
5362 { "no-sync", NOSYNC
},
5364 { "optimization", OPTIMIZATION
},
5367 { "overload", OVERLOAD
},
5369 { "pickups", PICKUPS
},
5371 { "priority", PRIORITY
},
5373 { "probability", PROBABILITY
},
5375 { "qlimit", QLIMIT
},
5378 { "random", RANDOM
},
5379 { "random-id", RANDOMID
},
5381 { "rdr-anchor", RDRANCHOR
},
5382 { "realtime", REALTIME
},
5383 { "reassemble", REASSEMBLE
},
5384 { "reply-to", REPLYTO
},
5385 { "require-order", REQUIREORDER
},
5386 { "return", RETURN
},
5387 { "return-icmp", RETURNICMP
},
5388 { "return-icmp6", RETURNICMP6
},
5389 { "return-rst", RETURNRST
},
5390 { "round-robin", ROUNDROBIN
},
5392 { "route-to", ROUTETO
},
5393 { "rtable", RTABLE
},
5395 { "ruleset-optimization", RULESET_OPTIMIZATION
},
5398 { "set-tos", SETTOS
},
5400 { "sloppy", SLOPPY
},
5401 { "source-hash", SOURCEHASH
},
5402 { "source-track", SOURCETRACK
},
5404 { "state-policy", STATEPOLICY
},
5405 { "static-port", STATICPORT
},
5406 { "sticky-address", STICKYADDRESS
},
5407 { "synproxy", SYNPROXY
},
5410 { "tagged", TAGGED
},
5411 { "tbrsize", TBRSIZE
},
5412 { "timeout", TIMEOUT
},
5416 { "upperlimit", UPPERLIMIT
},
5417 { "urpf-failed", URPFFAILED
},
5420 const struct keywords
*p
;
5422 p
= bsearch
(s
, keywords
, sizeof
(keywords
)/sizeof
(keywords
[0]),
5423 sizeof
(keywords
[0]), kw_cmp
);
5427 fprintf
(stderr
, "%s: %d\n", s
, p
->k_val
);
5431 fprintf
(stderr
, "string: %s\n", s
);
5436 #define MAXPUSHBACK 128
5440 char pushback_buffer
[MAXPUSHBACK
];
5441 int pushback_index
= 0;
5449 /* Read character from the parsebuffer instead of input. */
5450 if
(parseindex
>= 0) {
5451 c
= parsebuf
[parseindex
++];
5460 return
(pushback_buffer
[--pushback_index
]);
5463 if
((c
= getc
(file
->stream
)) == EOF
) {
5464 yyerror("reached end of file while parsing quoted string");
5465 if
(popfile
() == EOF
)
5472 while
((c
= getc
(file
->stream
)) == '\\') {
5473 next
= getc
(file
->stream
);
5478 yylval.lineno
= file
->lineno
;
5483 if
(popfile
() == EOF
)
5485 c
= getc
(file
->stream
);
5497 if
(parseindex
>= 0)
5500 if
(pushback_index
< MAXPUSHBACK
-1)
5501 return
(pushback_buffer
[pushback_index
++] = c
);
5514 /* skip to either EOF or the first real EOL */
5532 int quotec
, next
, c
;
5537 while
((c
= lgetc
(0)) == ' ' || c
== '\t')
5540 yylval.lineno
= file
->lineno
;
5542 while
((c
= lgetc
(0)) != '\n' && c
!= EOF
)
5544 if
(c
== '$' && parsebuf
== NULL
) {
5546 if
((c
= lgetc
(0)) == EOF
)
5549 if
(p
+ 1 >= buf
+ sizeof
(buf
) - 1) {
5550 yyerror("string too long");
5553 if
(isalnum
(c
) || c
== '_') {
5563 yyerror("macro '%s' not defined", buf
);
5576 if
((c
= lgetc
(quotec
)) == EOF
)
5581 } else if
(c
== '\\') {
5582 if
((next
= lgetc
(quotec
)) == EOF
)
5584 if
(next
== quotec || c
== ' ' || c
== '\t')
5586 else if
(next
== '\n')
5590 } else if
(c
== quotec
) {
5594 if
(p
+ 1 >= buf
+ sizeof
(buf
) - 1) {
5595 yyerror("string too long");
5600 yylval.v.
string = strdup
(buf
);
5601 if
(yylval.v.
string == NULL
)
5602 err
(1, "yylex: strdup");
5607 yylval.v.i
= PF_OP_XRG
;
5608 return
(PORTBINARY
);
5615 yylval.v.i
= PF_OP_IRG
;
5616 return
(PORTBINARY
);
5628 #define allowed_to_end_number(x) \
5629 (isspace
(x
) || x
== ')' || x
==',' || x
== '/' || x
== '}' || x
== '=')
5631 if
(c
== '-' || isdigit
(c
)) {
5634 if
((unsigned)(p
-buf
) >= sizeof
(buf
)) {
5635 yyerror("string too long");
5638 } while
((c
= lgetc
(0)) != EOF
&& isdigit
(c
));
5640 if
(p
== buf
+ 1 && buf
[0] == '-')
5642 if
(c
== EOF || allowed_to_end_number
(c
)) {
5643 const char *errstr
= NULL
;
5646 yylval.v.number
= strtonum
(buf
, LLONG_MIN
,
5647 LLONG_MAX
, &errstr
);
5649 yyerror("\"%s\" invalid number: %s",
5664 #define allowed_in_string(x) \
5665 (isalnum
(x
) ||
(ispunct
(x
) && x
!= '(' && x
!= ')' && \
5666 x
!= '{' && x
!= '}' && x
!= '<' && x
!= '>' && \
5667 x
!= '!' && x
!= '=' && x
!= '/' && x
!= '#' && \
5670 if
(isalnum
(c
) || c
== ':' || c
== '_') {
5673 if
((unsigned)(p
-buf
) >= sizeof
(buf
)) {
5674 yyerror("string too long");
5677 } while
((c
= lgetc
(0)) != EOF
&& (allowed_in_string
(c
)));
5680 if
((token
= lookup
(buf
)) == STRING
)
5681 if
((yylval.v.
string = strdup
(buf
)) == NULL
)
5682 err
(1, "yylex: strdup");
5686 yylval.lineno
= file
->lineno
;
5695 check_file_secrecy
(int fd
, const char *fname
)
5699 if
(fstat
(fd
, &st
)) {
5700 warn
("cannot stat %s", fname
);
5703 if
(st.st_uid
!= 0 && st.st_uid
!= getuid
()) {
5704 warnx
("%s: owner not root or current user", fname
);
5707 if
(st.st_mode
& (S_IRWXG | S_IRWXO
)) {
5708 warnx
("%s: group/world readable/writeable", fname
);
5715 pushfile
(const char *name
, int secret
)
5719 if
((nfile
= calloc
(1, sizeof
(struct file
))) == NULL ||
5720 (nfile
->name
= strdup
(name
)) == NULL
) {
5724 if
(TAILQ_FIRST
(&files
) == NULL
&& strcmp
(nfile
->name
, "-") == 0) {
5725 nfile
->stream
= stdin
;
5727 if
((nfile
->name
= strdup
("stdin")) == NULL
) {
5732 } else if
((nfile
->stream
= fopen
(nfile
->name
, "r")) == NULL
) {
5733 warn
("%s", nfile
->name
);
5737 } else if
(secret
&&
5738 check_file_secrecy
(fileno
(nfile
->stream
), nfile
->name
)) {
5739 fclose
(nfile
->stream
);
5745 TAILQ_INSERT_TAIL
(&files
, nfile
, entry
);
5754 if
((prev
= TAILQ_PREV
(file
, files
, entry
)) != NULL
) {
5755 prev
->errors
+= file
->errors
;
5756 TAILQ_REMOVE
(&files
, file
, entry
);
5757 fclose
(file
->stream
);
5767 parse_config
(char *filename
, struct pfctl
*xpf
)
5774 rulestate
= PFCTL_STATE_NONE
;
5775 returnicmpdefault
= (ICMP_UNREACH
<< 8) | ICMP_UNREACH_PORT
;
5776 returnicmp6default
=
5777 (ICMP6_DST_UNREACH
<< 8) | ICMP6_DST_UNREACH_NOPORT
;
5778 blockpolicy
= PFRULE_DROP
;
5782 * Default keep-polifcy is:
5784 * set keep-policy keep state (pickups, sloppy)
5786 * pickups - Allows TCP connections to be picked up mid-stream,
5787 * meaning that router restarts and changes in packet
5788 * routing will not destroy TCP connections already in
5791 * sloppy - Window scale options are only sent with SYN and SYN+ACK,
5792 * when picking up a connection in the middle, such as when
5793 * the router has been restarted or when multi-pathing
5794 * occurs, PF will not understand the window scale. This
5795 * tells PF to ignore the sequence space tests for this case.
5797 * While it is true that ICMP attack vectors are easier with these
5798 * options, the problem is that PF just has no business defaulting
5799 * to strict enforcement because it completely destroys the system
5800 * operator's ability to multi-path packets, to change packet routing,
5801 * or to restart the router (or PF) without kicking *ALL* active TCP
5802 * connections that were flowing through the router at the time. It
5803 * unacceptable to kick active connections by default.
5806 struct node_state_opt
*opt1
= calloc
(1, sizeof
(*opt1
));
5807 struct node_state_opt
*opt2
= calloc
(1, sizeof
(*opt2
));
5809 opt1
->type
= PF_STATE_OPT_PICKUPS
;
5810 opt1
->data.pickup_mode
= PF_PICKUPS_ENABLED
;
5814 opt2
->type
= PF_STATE_OPT_SLOPPY
;
5818 default_keeppolicy_action
= PF_STATE_NORMAL
;
5819 default_keeppolicy_options
= opt1
;
5824 if
((file
= pushfile
(filename
, 0)) == NULL
) {
5825 warn
("cannot open the main config file!");
5830 errors
= file
->errors
;
5833 /* Free macros and check which have not been used. */
5834 while
((sym
= TAILQ_FIRST
(&symhead
))) {
5835 if
((pf
->opts
& PF_OPT_VERBOSE2
) && !sym
->used
)
5836 fprintf
(stderr
, "warning: macro '%s' not "
5837 "used\n", sym
->nam
);
5840 TAILQ_REMOVE
(&symhead
, sym
, entry
);
5844 return
(errors ?
-1 : 0);
5848 symset
(const char *nam
, const char *val
, int persist
)
5852 for
(sym
= TAILQ_FIRST
(&symhead
); sym
&& strcmp
(nam
, sym
->nam
);
5853 sym
= TAILQ_NEXT
(sym
, entry
))
5857 if
(sym
->persist
== 1)
5862 TAILQ_REMOVE
(&symhead
, sym
, entry
);
5866 if
((sym
= calloc
(1, sizeof
(*sym
))) == NULL
)
5869 sym
->nam
= strdup
(nam
);
5870 if
(sym
->nam
== NULL
) {
5874 sym
->val
= strdup
(val
);
5875 if
(sym
->val
== NULL
) {
5881 sym
->persist
= persist
;
5882 TAILQ_INSERT_TAIL
(&symhead
, sym
, entry
);
5887 pfctl_cmdline_symset
(char *s
)
5892 if
((val
= strrchr
(s
, '=')) == NULL
)
5895 if
((sym
= malloc
(strlen
(s
) - strlen
(val
) + 1)) == NULL
)
5896 err
(1, "pfctl_cmdline_symset: malloc");
5898 strlcpy
(sym
, s
, strlen
(s
) - strlen
(val
) + 1);
5900 ret
= symset
(sym
, val
+ 1, 1);
5907 symget
(const char *nam
)
5911 TAILQ_FOREACH
(sym
, &symhead
, entry
)
5912 if
(strcmp
(nam
, sym
->nam
) == 0) {
5920 mv_rules
(struct pf_ruleset
*src
, struct pf_ruleset
*dst
)
5925 for
(i
= 0; i
< PF_RULESET_MAX
; ++i
) {
5926 while
((r
= TAILQ_FIRST
(src
->rules
[i
].active.ptr
))
5928 TAILQ_REMOVE
(src
->rules
[i
].active.ptr
, r
, entries
);
5929 TAILQ_INSERT_TAIL
(dst
->rules
[i
].active.ptr
, r
, entries
);
5930 dst
->anchor
->match
++;
5932 src
->anchor
->match
= 0;
5933 while
((r
= TAILQ_FIRST
(src
->rules
[i
].inactive.ptr
))
5935 TAILQ_REMOVE
(src
->rules
[i
].inactive.ptr
, r
, entries
);
5936 TAILQ_INSERT_TAIL
(dst
->rules
[i
].inactive.ptr
,
5943 decide_address_family
(struct node_host
*n
, sa_family_t
*af
)
5945 if
(*af
!= 0 || n
== NULL
)
5948 while
((n
= n
->next
) != NULL
) {
5957 remove_invalid_hosts
(struct node_host
**nh
, sa_family_t
*af
)
5959 struct node_host
*n
= *nh
, *prev
= NULL
;
5962 if
(*af
&& n
->af
&& n
->af
!= *af
) {
5963 /* unlink and free n */
5964 struct node_host
*next
= n
->next
;
5966 /* adjust tail pointer */
5967 if
(n
== (*nh
)->tail
)
5969 /* adjust previous node's next pointer */
5975 if
(n
->ifname
!= NULL
)
5989 invalid_redirect
(struct node_host
*nh
, sa_family_t af
)
5992 struct node_host
*n
;
5994 /* tables and dyniftl are ok without an address family */
5995 for
(n
= nh
; n
!= NULL
; n
= n
->next
) {
5996 if
(n
->addr.type
!= PF_ADDR_TABLE
&&
5997 n
->addr.type
!= PF_ADDR_DYNIFTL
) {
5998 yyerror("address family not given and "
5999 "translation address expands to multiple "
6000 "address families");
6006 yyerror("no translation address with matching address family "
6014 atoul
(char *s
, u_long
*ulvalp
)
6020 ulval
= strtoul
(s
, &ep
, 0);
6021 if
(s
[0] == '\0' ||
*ep
!= '\0')
6023 if
(errno
== ERANGE
&& ulval
== ULONG_MAX
)
6035 if
(atoul
(n
, &ulval
) == 0) {
6036 if
(ulval
> 65535) {
6037 yyerror("illegal port value %lu", ulval
);
6040 return
(htons
(ulval
));
6042 s
= getservbyname
(n
, "tcp");
6044 s
= getservbyname
(n
, "udp");
6046 yyerror("unknown port %s", n
);
6054 rule_label
(struct pf_rule
*r
, char *s
)
6057 if
(strlcpy
(r
->label
, s
, sizeof
(r
->label
)) >=
6059 yyerror("rule label too long (max %zd chars)",
6060 sizeof
(r
->label
)-1);
6068 parseicmpspec
(char *w
, sa_family_t af
)
6070 const struct icmpcodeent
*p
;
6075 icmptype
= returnicmpdefault
>> 8;
6077 icmptype
= returnicmp6default
>> 8;
6079 if
(atoul
(w
, &ulval
) == -1) {
6080 if
((p
= geticmpcodebyname
(icmptype
, w
, af
)) == NULL
) {
6081 yyerror("unknown icmp code %s", w
);
6087 yyerror("invalid icmp code %lu", ulval
);
6090 return
(icmptype
<< 8 | ulval
);
6094 parseport
(char *port
, struct range
*r
, int extensions
)
6096 char *p
= strchr
(port
, ':');
6099 if
((r
->a
= getservice
(port
)) == -1)
6105 if
((extensions
& PPORT_STAR
) && !strcmp
(p
+1, "*")) {
6107 if
((r
->a
= getservice
(port
)) == -1)
6113 if
((extensions
& PPORT_RANGE
)) {
6115 if
((r
->a
= getservice
(port
)) == -1 ||
6116 (r
->b
= getservice
(p
)) == -1)
6129 pfctl_load_anchors
(int dev
, struct pfctl
*his_pf
, struct pfr_buffer
*trans
)
6131 struct loadanchors
*la
;
6133 TAILQ_FOREACH
(la
, &loadanchorshead
, entries
) {
6134 if
(his_pf
->opts
& PF_OPT_VERBOSE
)
6135 fprintf
(stderr
, "\nLoading anchor %s from %s\n",
6136 la
->anchorname
, la
->filename
);
6137 if
(pfctl_rules
(dev
, la
->filename
, his_pf
->opts
, his_pf
->optimize
,
6138 la
->anchorname
, trans
) == -1)