1 /* $OpenBSD: parse.y,v 1.554 2008/10/17 12:59:53 henning 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/cdefs.h>
31 __FBSDID("$FreeBSD$");
33 #include <sys/types.h>
34 #include <sys/socket.h>
37 #include <sys/sysctl.h>
40 #include <netinet/in.h>
41 #include <netinet/in_systm.h>
42 #include <netinet/ip.h>
43 #include <netinet/ip_icmp.h>
44 #include <netinet/icmp6.h>
45 #include <net/pfvar.h>
46 #include <arpa/inet.h>
47 #include <altq/altq.h>
48 #include <altq/altq_cbq.h>
49 #include <altq/altq_priq.h>
50 #include <altq/altq_hfsc.h>
51 #include <net/altq/altq_fairq.h>
68 #include "pfctl_parser.h"
71 static struct pfctl *pf = NULL;
73 static int rulestate = 0;
74 static u_int16_t returnicmpdefault =
75 (ICMP_UNREACH << 8) | ICMP_UNREACH_PORT;
76 static u_int16_t returnicmp6default =
77 (ICMP6_DST_UNREACH << 8) | ICMP6_DST_UNREACH_NOPORT;
78 static int blockpolicy = PFRULE_DROP;
79 static int require_order = 1;
80 static int default_statelock;
82 TAILQ_HEAD(files, file) files = TAILQ_HEAD_INITIALIZER(files);
84 TAILQ_ENTRY(file) entry;
90 struct file *pushfile(const char *, int);
92 int check_file_secrecy(int, const char *);
95 int yyerror(const char *, ...);
96 int kw_cmp(const void *, const void *);
102 TAILQ_HEAD(symhead, sym) symhead = TAILQ_HEAD_INITIALIZER(symhead);
104 TAILQ_ENTRY(sym) entry;
110 int symset(const char *, const char *, int);
111 char *symget(const char *);
113 int atoul(char *, u_long *);
126 struct node_proto *next;
127 struct node_proto *tail;
133 struct node_port *next;
134 struct node_port *tail;
140 struct node_uid *next;
141 struct node_uid *tail;
147 struct node_gid *next;
148 struct node_gid *tail;
155 struct node_icmp *next;
156 struct node_icmp *tail;
159 enum { PF_STATE_OPT_MAX, PF_STATE_OPT_NOSYNC, PF_STATE_OPT_SRCTRACK,
160 PF_STATE_OPT_MAX_SRC_STATES, PF_STATE_OPT_MAX_SRC_CONN,
161 PF_STATE_OPT_MAX_SRC_CONN_RATE, PF_STATE_OPT_MAX_SRC_NODES,
162 PF_STATE_OPT_OVERLOAD, PF_STATE_OPT_STATELOCK,
163 PF_STATE_OPT_TIMEOUT, PF_STATE_OPT_SLOPPY, };
165 enum { PF_SRCTRACK_NONE, PF_SRCTRACK, PF_SRCTRACK_GLOBAL, PF_SRCTRACK_RULE };
167 struct node_state_opt {
170 u_int32_t max_states;
171 u_int32_t max_src_states;
172 u_int32_t max_src_conn;
179 char tblname[PF_TABLE_NAME_SIZE];
181 u_int32_t max_src_nodes;
189 struct node_state_opt *next;
190 struct node_state_opt *tail;
194 struct node_host *host;
195 struct node_port *port;
199 char queue[PF_QNAME_SIZE];
200 char parent[PF_QNAME_SIZE];
201 char ifname[IFNAMSIZ];
203 struct node_queue *next;
204 struct node_queue *tail;
207 struct node_qassign {
214 #define FOM_FLAGS 0x01
215 #define FOM_ICMP 0x02
217 #define FOM_KEEP 0x08
218 #define FOM_SRCTRACK 0x10
219 struct node_uid *uid;
220 struct node_gid *gid;
227 struct node_icmp *icmpspec;
232 struct node_state_opt *options;
237 struct node_qassign queues;
240 u_int8_t match_tag_not;
243 struct node_host *addr;
248 struct antispoof_opts {
255 #define SOM_MINTTL 0x01
256 #define SOM_MAXMSS 0x02
257 #define SOM_FRAGCACHE 0x04
258 #define SOM_SETTOS 0x08
267 u_int8_t match_tag_not;
273 #define QOM_BWSPEC 0x01
274 #define QOM_SCHEDULER 0x02
275 #define QOM_PRIORITY 0x04
276 #define QOM_TBRSIZE 0x08
277 #define QOM_QLIMIT 0x10
278 struct node_queue_bw queue_bwspec;
279 struct node_queue_opt scheduler;
288 struct node_tinithead init_nodes;
293 #define POM_TYPE 0x01
294 #define POM_STICKYADDRESS 0x02
298 struct pf_poolhashkey *key;
303 struct node_hfsc_opts hfsc_opts;
304 struct node_fairq_opts fairq_opts;
305 struct node_state_opt *keep_state_defaults = NULL;
307 int disallow_table(struct node_host *, const char *);
308 int disallow_urpf_failed(struct node_host *, const char *);
309 int disallow_alias(struct node_host *, const char *);
310 int rule_consistent(struct pf_rule *, int);
311 int filter_consistent(struct pf_rule *, int);
312 int nat_consistent(struct pf_rule *);
313 int rdr_consistent(struct pf_rule *);
314 int process_tabledef(char *, struct table_opts *);
315 void expand_label_str(char *, size_t, const char *, const char *);
316 void expand_label_if(const char *, char *, size_t, const char *);
317 void expand_label_addr(const char *, char *, size_t, u_int8_t,
319 void expand_label_port(const char *, char *, size_t,
321 void expand_label_proto(const char *, char *, size_t, u_int8_t);
322 void expand_label_nr(const char *, char *, size_t);
323 void expand_label(char *, size_t, const char *, u_int8_t,
324 struct node_host *, struct node_port *, struct node_host *,
325 struct node_port *, u_int8_t);
326 void expand_rule(struct pf_rule *, struct node_if *,
327 struct node_host *, struct node_proto *, struct node_os *,
328 struct node_host *, struct node_port *, struct node_host *,
329 struct node_port *, struct node_uid *, struct node_gid *,
330 struct node_icmp *, const char *);
331 int expand_altq(struct pf_altq *, struct node_if *,
332 struct node_queue *, struct node_queue_bw bwspec,
333 struct node_queue_opt *);
334 int expand_queue(struct pf_altq *, struct node_if *,
335 struct node_queue *, struct node_queue_bw,
336 struct node_queue_opt *);
337 int expand_skip_interface(struct node_if *);
339 int check_rulestate(int);
340 int getservice(char *);
341 int rule_label(struct pf_rule *, char *);
342 int rt_tableid_max(void);
344 void mv_rules(struct pf_ruleset *, struct pf_ruleset *);
345 void decide_address_family(struct node_host *, sa_family_t *);
346 void remove_invalid_hosts(struct node_host **, sa_family_t *);
347 int invalid_redirect(struct node_host *, sa_family_t);
348 u_int16_t parseicmpspec(char *, sa_family_t);
350 TAILQ_HEAD(loadanchorshead, loadanchors)
351 loadanchorshead = TAILQ_HEAD_INITIALIZER(loadanchorshead);
354 TAILQ_ENTRY(loadanchors) entries;
377 struct node_if *interface;
378 struct node_proto *proto;
379 struct node_icmp *icmp;
380 struct node_host *host;
382 struct node_port *port;
383 struct node_uid *uid;
384 struct node_gid *gid;
385 struct node_state_opt *state_opt;
388 struct peer src, dst;
389 struct node_os *src_os;
392 struct node_host *host;
396 struct pf_poolhashkey *key;
399 struct node_host *host;
404 struct node_state_opt *options;
415 struct pf_poolhashkey *hashkey;
416 struct node_queue *queue;
417 struct node_queue_opt queue_options;
418 struct node_queue_bw queue_bwspec;
419 struct node_qassign qassign;
420 struct filter_opts filter_opts;
421 struct antispoof_opts antispoof_opts;
422 struct queue_opts queue_opts;
423 struct scrub_opts scrub_opts;
424 struct table_opts table_opts;
425 struct pool_opts pool_opts;
426 struct node_hfsc_opts hfsc_opts;
427 struct node_fairq_opts fairq_opts;
432 #define PPORT_RANGE 1
434 int parseport(char *, struct range *r, int);
436 #define DYNIF_MULTIADDR(addr) ((addr).type == PF_ADDR_DYNIFTL && \
437 (!((addr).iflags & PFI_AFLAG_NOALIAS) || \
438 !isdigit((addr).v.ifname[strlen((addr).v.ifname)-1])))
442 %token PASS BLOCK SCRUB RETURN IN OS OUT LOG QUICK ON FROM TO FLAGS
443 %token RETURNRST RETURNICMP RETURNICMP6 PROTO INET INET6 ALL ANY ICMPTYPE
444 %token ICMP6TYPE CODE KEEP MODULATE STATE PORT RDR NAT BINAT ARROW NODF
445 %token MINTTL ERROR ALLOWOPTS FASTROUTE FILENAME ROUTETO DUPTO REPLYTO NO LABEL
446 %token NOROUTE URPFFAILED FRAGMENT USER GROUP MAXMSS MAXIMUM TTL TOS DROP TABLE
447 %token REASSEMBLE FRAGDROP FRAGCROP ANCHOR NATANCHOR RDRANCHOR BINATANCHOR
448 %token SET OPTIMIZATION TIMEOUT LIMIT LOGINTERFACE BLOCKPOLICY RANDOMID
449 %token REQUIREORDER SYNPROXY FINGERPRINTS NOSYNC DEBUG SKIP HOSTID
450 %token ANTISPOOF FOR INCLUDE
451 %token BITMASK RANDOM SOURCEHASH ROUNDROBIN STATICPORT PROBABILITY
452 %token ALTQ CBQ PRIQ HFSC FAIRQ BANDWIDTH TBRSIZE LINKSHARE REALTIME UPPERLIMIT
453 %token QUEUE PRIORITY QLIMIT HOGS BUCKETS RTABLE
454 %token LOAD RULESET_OPTIMIZATION
455 %token STICKYADDRESS MAXSRCSTATES MAXSRCNODES SOURCETRACK GLOBAL RULE
456 %token MAXSRCCONN MAXSRCCONNRATE OVERLOAD FLUSH SLOPPY
457 %token TAGGED TAG IFBOUND FLOATING STATEPOLICY STATEDEFAULTS ROUTE SETTOS
458 %token DIVERTTO DIVERTREPLY
459 %token <v.string> STRING
460 %token <v.number> NUMBER
461 %token <v.i> PORTBINARY
462 %type <v.interface> interface if_list if_item_not if_item
463 %type <v.number> number icmptype icmp6type uid gid
464 %type <v.number> tos not yesno
465 %type <v.probability> probability
466 %type <v.i> no dir af fragcache optimizer
467 %type <v.i> sourcetrack flush unaryop statelock
468 %type <v.b> action nataction natpasslog scrubaction
469 %type <v.b> flags flag blockspec
470 %type <v.range> portplain portstar portrange
471 %type <v.hashkey> hashkey
472 %type <v.proto> proto proto_list proto_item
473 %type <v.number> protoval
474 %type <v.icmp> icmpspec
475 %type <v.icmp> icmp_list icmp_item
476 %type <v.icmp> icmp6_list icmp6_item
477 %type <v.number> reticmpspec reticmp6spec
478 %type <v.fromto> fromto
479 %type <v.peer> ipportspec from to
480 %type <v.host> ipspec toipspec xhost host dynaddr host_list
481 %type <v.host> redir_host_list redirspec
482 %type <v.host> route_host route_host_list routespec
483 %type <v.os> os xos os_list
484 %type <v.port> portspec port_list port_item
485 %type <v.uid> uids uid_list uid_item
486 %type <v.gid> gids gid_list gid_item
487 %type <v.route> route
488 %type <v.redirection> redirection redirpool
489 %type <v.string> label stringall tag anchorname
490 %type <v.string> string varstring numberstring
491 %type <v.keep_state> keep
492 %type <v.state_opt> state_opt_spec state_opt_list state_opt_item
493 %type <v.logquick> logquick quick log logopts logopt
494 %type <v.interface> antispoof_ifspc antispoof_iflst antispoof_if
495 %type <v.qassign> qname
496 %type <v.queue> qassign qassign_list qassign_item
497 %type <v.queue_options> scheduler
498 %type <v.number> cbqflags_list cbqflags_item
499 %type <v.number> priqflags_list priqflags_item
500 %type <v.hfsc_opts> hfscopts_list hfscopts_item hfsc_opts
501 %type <v.fairq_opts> fairqopts_list fairqopts_item fairq_opts
502 %type <v.queue_bwspec> bandwidth
503 %type <v.filter_opts> filter_opts filter_opt filter_opts_l
504 %type <v.antispoof_opts> antispoof_opts antispoof_opt antispoof_opts_l
505 %type <v.queue_opts> queue_opts queue_opt queue_opts_l
506 %type <v.scrub_opts> scrub_opts scrub_opt scrub_opts_l
507 %type <v.table_opts> table_opts table_opt table_opts_l
508 %type <v.pool_opts> pool_opts pool_opt pool_opts_l
509 %type <v.tagged> tagged
510 %type <v.rtableid> rtable
513 ruleset : /* empty */
514 | ruleset include '\n'
516 | ruleset option '\n'
517 | ruleset scrubrule '\n'
518 | ruleset natrule '\n'
519 | ruleset binatrule '\n'
520 | ruleset pfrule '\n'
521 | ruleset anchorrule '\n'
522 | ruleset loadrule '\n'
523 | ruleset altqif '\n'
524 | ruleset queuespec '\n'
525 | ruleset varset '\n'
526 | ruleset antispoof '\n'
527 | ruleset tabledef '\n'
528 | '{' fakeanchor '}' '\n';
529 | ruleset error '\n' { file->errors++; }
532 include : INCLUDE STRING {
535 if ((nfile = pushfile($2, 0)) == NULL) {
536 yyerror("failed to include file %s", $2);
548 * apply to previouslys specified rule: must be careful to note
549 * what that is: pf or nat or binat or rdr
551 fakeanchor : fakeanchor '\n'
552 | fakeanchor anchorrule '\n'
553 | fakeanchor binatrule '\n'
554 | fakeanchor natrule '\n'
555 | fakeanchor pfrule '\n'
556 | fakeanchor error '\n'
560 if (!strcmp($1, "none"))
562 else if (!strcmp($1, "basic"))
563 $$ = PF_OPTIMIZE_BASIC;
564 else if (!strcmp($1, "profile"))
565 $$ = PF_OPTIMIZE_BASIC | PF_OPTIMIZE_PROFILE;
567 yyerror("unknown ruleset-optimization %s", $1);
573 option : SET OPTIMIZATION STRING {
574 if (check_rulestate(PFCTL_STATE_OPTION)) {
578 if (pfctl_set_optimization(pf, $3) != 0) {
579 yyerror("unknown optimization %s", $3);
585 | SET RULESET_OPTIMIZATION optimizer {
586 if (!(pf->opts & PF_OPT_OPTIMIZE)) {
587 pf->opts |= PF_OPT_OPTIMIZE;
591 | SET TIMEOUT timeout_spec
592 | SET TIMEOUT '{' optnl timeout_list '}'
593 | SET LIMIT limit_spec
594 | SET LIMIT '{' optnl limit_list '}'
595 | SET LOGINTERFACE stringall {
596 if (check_rulestate(PFCTL_STATE_OPTION)) {
600 if (pfctl_set_logif(pf, $3) != 0) {
601 yyerror("error setting loginterface %s", $3);
607 | SET HOSTID number {
608 if ($3 == 0 || $3 > UINT_MAX) {
609 yyerror("hostid must be non-zero");
612 if (pfctl_set_hostid(pf, $3) != 0) {
613 yyerror("error setting hostid %08x", $3);
617 | SET BLOCKPOLICY DROP {
618 if (pf->opts & PF_OPT_VERBOSE)
619 printf("set block-policy drop\n");
620 if (check_rulestate(PFCTL_STATE_OPTION))
622 blockpolicy = PFRULE_DROP;
624 | SET BLOCKPOLICY RETURN {
625 if (pf->opts & PF_OPT_VERBOSE)
626 printf("set block-policy return\n");
627 if (check_rulestate(PFCTL_STATE_OPTION))
629 blockpolicy = PFRULE_RETURN;
631 | SET REQUIREORDER yesno {
632 if (pf->opts & PF_OPT_VERBOSE)
633 printf("set require-order %s\n",
634 $3 == 1 ? "yes" : "no");
637 | SET FINGERPRINTS STRING {
638 if (pf->opts & PF_OPT_VERBOSE)
639 printf("set fingerprints \"%s\"\n", $3);
640 if (check_rulestate(PFCTL_STATE_OPTION)) {
644 if (!pf->anchor->name[0]) {
645 if (pfctl_file_fingerprints(pf->dev,
647 yyerror("error loading "
648 "fingerprints %s", $3);
655 | SET STATEPOLICY statelock {
656 if (pf->opts & PF_OPT_VERBOSE)
659 printf("set state-policy floating\n");
662 printf("set state-policy if-bound\n");
665 default_statelock = $3;
668 if (check_rulestate(PFCTL_STATE_OPTION)) {
672 if (pfctl_set_debug(pf, $3) != 0) {
673 yyerror("error setting debuglevel %s", $3);
679 | SET SKIP interface {
680 if (expand_skip_interface($3) != 0) {
681 yyerror("error setting skip interface(s)");
685 | SET STATEDEFAULTS state_opt_list {
686 if (keep_state_defaults != NULL) {
687 yyerror("cannot redefine state-defaults");
690 keep_state_defaults = $3;
694 stringall : STRING { $$ = $1; }
696 if (($$ = strdup("all")) == NULL) {
697 err(1, "stringall: strdup");
702 string : STRING string {
703 if (asprintf(&$$, "%s %s", $1, $2) == -1)
704 err(1, "string: asprintf");
711 varstring : numberstring varstring {
712 if (asprintf(&$$, "%s %s", $1, $2) == -1)
713 err(1, "string: asprintf");
720 numberstring : NUMBER {
722 if (asprintf(&s, "%lld", (long long)$1) == -1) {
723 yyerror("string: asprintf");
731 varset : STRING '=' varstring {
732 if (pf->opts & PF_OPT_VERBOSE)
733 printf("%s = \"%s\"\n", $1, $3);
734 if (symset($1, $3, 0) == -1)
735 err(1, "cannot store variable %s", $1);
741 anchorname : STRING { $$ = $1; }
742 | /* empty */ { $$ = NULL; }
745 pfa_anchorlist : /* empty */
746 | pfa_anchorlist '\n'
747 | pfa_anchorlist pfrule '\n'
748 | pfa_anchorlist anchorrule '\n'
753 char ta[PF_ANCHOR_NAME_SIZE];
754 struct pf_ruleset *rs;
756 /* steping into a brace anchor */
761 /* create a holding ruleset in the root */
762 snprintf(ta, PF_ANCHOR_NAME_SIZE, "_%d", pf->bn);
763 rs = pf_find_or_create_ruleset(ta);
765 err(1, "pfa_anchor: pf_find_or_create_ruleset");
766 pf->astack[pf->asd] = rs->anchor;
767 pf->anchor = rs->anchor;
768 } '\n' pfa_anchorlist '}'
770 pf->alast = pf->anchor;
772 pf->anchor = pf->astack[pf->asd];
777 anchorrule : ANCHOR anchorname dir quick interface af proto fromto
778 filter_opts pfa_anchor
781 struct node_proto *proto;
783 if (check_rulestate(PFCTL_STATE_FILTER)) {
789 if ($2 && ($2[0] == '_' || strstr($2, "/_") != NULL)) {
791 yyerror("anchor names beginning with '_' "
792 "are reserved for internal use");
796 memset(&r, 0, sizeof(r));
797 if (pf->astack[pf->asd + 1]) {
798 /* move inline rules into relative location */
800 &pf->astack[pf->asd]->ruleset,
801 $2 ? $2 : pf->alast->name);
803 if (r.anchor == NULL)
804 err(1, "anchorrule: unable to "
807 if (pf->alast != r.anchor) {
808 if (r.anchor->match) {
809 yyerror("inline anchor '%s' "
814 mv_rules(&pf->alast->ruleset,
817 pf_remove_if_empty_ruleset(&pf->alast->ruleset);
818 pf->alast = r.anchor;
821 yyerror("anchors without explicit "
822 "rules must specify a name");
830 r.rtableid = $9.rtableid;
833 if (strlcpy(r.tagname, $9.tag,
834 PF_TAG_NAME_SIZE) >= PF_TAG_NAME_SIZE) {
835 yyerror("tag too long, max %u chars",
836 PF_TAG_NAME_SIZE - 1);
840 if (strlcpy(r.match_tagname, $9.match_tag,
841 PF_TAG_NAME_SIZE) >= PF_TAG_NAME_SIZE) {
842 yyerror("tag too long, max %u chars",
843 PF_TAG_NAME_SIZE - 1);
846 r.match_tag_not = $9.match_tag_not;
847 if (rule_label(&r, $9.label))
850 r.flags = $9.flags.b1;
851 r.flagset = $9.flags.b2;
852 if (($9.flags.b1 & $9.flags.b2) != $9.flags.b1) {
853 yyerror("flags always false");
856 if ($9.flags.b1 || $9.flags.b2 || $8.src_os) {
857 for (proto = $7; proto != NULL &&
858 proto->proto != IPPROTO_TCP;
861 if (proto == NULL && $7 != NULL) {
862 if ($9.flags.b1 || $9.flags.b2)
864 "flags only apply to tcp");
867 "OS fingerprinting only "
875 if ($9.keep.action) {
876 yyerror("cannot specify state handling "
882 if (strlcpy(r.match_tagname, $9.match_tag,
883 PF_TAG_NAME_SIZE) >= PF_TAG_NAME_SIZE) {
884 yyerror("tag too long, max %u chars",
885 PF_TAG_NAME_SIZE - 1);
888 r.match_tag_not = $9.match_tag_not;
890 decide_address_family($8.src.host, &r.af);
891 decide_address_family($8.dst.host, &r.af);
893 expand_rule(&r, $5, NULL, $7, $8.src_os,
894 $8.src.host, $8.src.port, $8.dst.host, $8.dst.port,
895 $9.uid, $9.gid, $9.icmpspec,
896 pf->astack[pf->asd + 1] ? pf->alast->name : $2);
898 pf->astack[pf->asd + 1] = NULL;
900 | NATANCHOR string interface af proto fromto rtable {
903 if (check_rulestate(PFCTL_STATE_NAT)) {
908 memset(&r, 0, sizeof(r));
913 decide_address_family($6.src.host, &r.af);
914 decide_address_family($6.dst.host, &r.af);
916 expand_rule(&r, $3, NULL, $5, $6.src_os,
917 $6.src.host, $6.src.port, $6.dst.host, $6.dst.port,
921 | RDRANCHOR string interface af proto fromto rtable {
924 if (check_rulestate(PFCTL_STATE_NAT)) {
929 memset(&r, 0, sizeof(r));
934 decide_address_family($6.src.host, &r.af);
935 decide_address_family($6.dst.host, &r.af);
937 if ($6.src.port != NULL) {
938 yyerror("source port parameter not supported"
942 if ($6.dst.port != NULL) {
943 if ($6.dst.port->next != NULL) {
944 yyerror("destination port list "
945 "expansion not supported in "
948 } else if ($6.dst.port->op != PF_OP_EQ) {
949 yyerror("destination port operators"
950 " not supported in rdr-anchor");
953 r.dst.port[0] = $6.dst.port->port[0];
954 r.dst.port[1] = $6.dst.port->port[1];
955 r.dst.port_op = $6.dst.port->op;
958 expand_rule(&r, $3, NULL, $5, $6.src_os,
959 $6.src.host, $6.src.port, $6.dst.host, $6.dst.port,
963 | BINATANCHOR string interface af proto fromto rtable {
966 if (check_rulestate(PFCTL_STATE_NAT)) {
971 memset(&r, 0, sizeof(r));
976 if ($5->next != NULL) {
977 yyerror("proto list expansion"
978 " not supported in binat-anchor");
985 if ($6.src.host != NULL || $6.src.port != NULL ||
986 $6.dst.host != NULL || $6.dst.port != NULL) {
987 yyerror("fromto parameter not supported"
992 decide_address_family($6.src.host, &r.af);
993 decide_address_family($6.dst.host, &r.af);
995 pfctl_add_rule(pf, &r, $2);
1000 loadrule : LOAD ANCHOR string FROM string {
1001 struct loadanchors *loadanchor;
1003 if (strlen(pf->anchor->name) + 1 +
1004 strlen($3) >= MAXPATHLEN) {
1005 yyerror("anchorname %s too long, max %u\n",
1006 $3, MAXPATHLEN - 1);
1010 loadanchor = calloc(1, sizeof(struct loadanchors));
1011 if (loadanchor == NULL)
1012 err(1, "loadrule: calloc");
1013 if ((loadanchor->anchorname = malloc(MAXPATHLEN)) ==
1015 err(1, "loadrule: malloc");
1016 if (pf->anchor->name[0])
1017 snprintf(loadanchor->anchorname, MAXPATHLEN,
1018 "%s/%s", pf->anchor->name, $3);
1020 strlcpy(loadanchor->anchorname, $3, MAXPATHLEN);
1021 if ((loadanchor->filename = strdup($5)) == NULL)
1022 err(1, "loadrule: strdup");
1024 TAILQ_INSERT_TAIL(&loadanchorshead, loadanchor,
1031 scrubaction : no SCRUB {
1040 scrubrule : scrubaction dir logquick interface af proto fromto scrub_opts
1044 if (check_rulestate(PFCTL_STATE_SCRUB))
1047 memset(&r, 0, sizeof(r));
1055 yyerror("scrub rules do not support 'quick'");
1061 r.rule_flag |= PFRULE_NODF;
1063 r.rule_flag |= PFRULE_RANDOMID;
1064 if ($8.reassemble_tcp) {
1065 if (r.direction != PF_INOUT) {
1066 yyerror("reassemble tcp rules can not "
1067 "specify direction");
1070 r.rule_flag |= PFRULE_REASSEMBLE_TCP;
1073 r.min_ttl = $8.minttl;
1075 r.max_mss = $8.maxmss;
1076 if ($8.marker & SOM_SETTOS) {
1077 r.rule_flag |= PFRULE_SET_TOS;
1078 r.set_tos = $8.settos;
1081 r.rule_flag |= $8.fragcache;
1083 if (strlcpy(r.match_tagname, $8.match_tag,
1084 PF_TAG_NAME_SIZE) >= PF_TAG_NAME_SIZE) {
1085 yyerror("tag too long, max %u chars",
1086 PF_TAG_NAME_SIZE - 1);
1089 r.match_tag_not = $8.match_tag_not;
1090 r.rtableid = $8.rtableid;
1092 expand_rule(&r, $4, NULL, $6, $7.src_os,
1093 $7.src.host, $7.src.port, $7.dst.host, $7.dst.port,
1094 NULL, NULL, NULL, "");
1099 bzero(&scrub_opts, sizeof scrub_opts);
1100 scrub_opts.rtableid = -1;
1103 { $$ = scrub_opts; }
1105 bzero(&scrub_opts, sizeof scrub_opts);
1106 scrub_opts.rtableid = -1;
1111 scrub_opts_l : scrub_opts_l scrub_opt
1116 if (scrub_opts.nodf) {
1117 yyerror("no-df cannot be respecified");
1120 scrub_opts.nodf = 1;
1123 if (scrub_opts.marker & SOM_MINTTL) {
1124 yyerror("min-ttl cannot be respecified");
1127 if ($2 < 0 || $2 > 255) {
1128 yyerror("illegal min-ttl value %d", $2);
1131 scrub_opts.marker |= SOM_MINTTL;
1132 scrub_opts.minttl = $2;
1135 if (scrub_opts.marker & SOM_MAXMSS) {
1136 yyerror("max-mss cannot be respecified");
1139 if ($2 < 0 || $2 > 65535) {
1140 yyerror("illegal max-mss value %d", $2);
1143 scrub_opts.marker |= SOM_MAXMSS;
1144 scrub_opts.maxmss = $2;
1147 if (scrub_opts.marker & SOM_SETTOS) {
1148 yyerror("set-tos cannot be respecified");
1151 scrub_opts.marker |= SOM_SETTOS;
1152 scrub_opts.settos = $2;
1155 if (scrub_opts.marker & SOM_FRAGCACHE) {
1156 yyerror("fragcache cannot be respecified");
1159 scrub_opts.marker |= SOM_FRAGCACHE;
1160 scrub_opts.fragcache = $1;
1162 | REASSEMBLE STRING {
1163 if (strcasecmp($2, "tcp") != 0) {
1164 yyerror("scrub reassemble supports only tcp, "
1170 if (scrub_opts.reassemble_tcp) {
1171 yyerror("reassemble tcp cannot be respecified");
1174 scrub_opts.reassemble_tcp = 1;
1177 if (scrub_opts.randomid) {
1178 yyerror("random-id cannot be respecified");
1181 scrub_opts.randomid = 1;
1184 if ($2 < 0 || $2 > rt_tableid_max()) {
1185 yyerror("invalid rtable id");
1188 scrub_opts.rtableid = $2;
1190 | not TAGGED string {
1191 scrub_opts.match_tag = $3;
1192 scrub_opts.match_tag_not = $1;
1196 fragcache : FRAGMENT REASSEMBLE { $$ = 0; /* default */ }
1197 | FRAGMENT FRAGCROP { $$ = PFRULE_FRAGCROP; }
1198 | FRAGMENT FRAGDROP { $$ = PFRULE_FRAGDROP; }
1201 antispoof : ANTISPOOF logquick antispoof_ifspc af antispoof_opts {
1203 struct node_host *h = NULL, *hh;
1204 struct node_if *i, *j;
1206 if (check_rulestate(PFCTL_STATE_FILTER))
1209 for (i = $3; i; i = i->next) {
1210 bzero(&r, sizeof(r));
1213 r.direction = PF_IN;
1218 if (rule_label(&r, $5.label))
1220 r.rtableid = $5.rtableid;
1221 j = calloc(1, sizeof(struct node_if));
1223 err(1, "antispoof: calloc");
1224 if (strlcpy(j->ifname, i->ifname,
1225 sizeof(j->ifname)) >= sizeof(j->ifname)) {
1227 yyerror("interface name too long");
1232 h = calloc(1, sizeof(*h));
1234 err(1, "address: calloc");
1235 h->addr.type = PF_ADDR_DYNIFTL;
1237 if (strlcpy(h->addr.v.ifname, i->ifname,
1238 sizeof(h->addr.v.ifname)) >=
1239 sizeof(h->addr.v.ifname)) {
1242 "interface name too long");
1245 hh = malloc(sizeof(*hh));
1247 err(1, "address: malloc");
1248 bcopy(h, hh, sizeof(*hh));
1249 h->addr.iflags = PFI_AFLAG_NETWORK;
1251 h = ifa_lookup(j->ifname,
1257 expand_rule(&r, j, NULL, NULL, NULL, h,
1258 NULL, NULL, NULL, NULL, NULL,
1261 if ((i->ifa_flags & IFF_LOOPBACK) == 0) {
1262 bzero(&r, sizeof(r));
1265 r.direction = PF_IN;
1270 if (rule_label(&r, $5.label))
1272 r.rtableid = $5.rtableid;
1276 h = ifa_lookup(i->ifname, 0);
1278 expand_rule(&r, NULL, NULL,
1279 NULL, NULL, h, NULL, NULL,
1280 NULL, NULL, NULL, NULL, "");
1288 antispoof_ifspc : FOR antispoof_if { $$ = $2; }
1289 | FOR '{' optnl antispoof_iflst '}' { $$ = $4; }
1292 antispoof_iflst : antispoof_if optnl { $$ = $1; }
1293 | antispoof_iflst comma antispoof_if optnl {
1294 $1->tail->next = $3;
1300 antispoof_if : if_item { $$ = $1; }
1308 bzero(&antispoof_opts, sizeof antispoof_opts);
1309 antispoof_opts.rtableid = -1;
1312 { $$ = antispoof_opts; }
1314 bzero(&antispoof_opts, sizeof antispoof_opts);
1315 antispoof_opts.rtableid = -1;
1316 $$ = antispoof_opts;
1320 antispoof_opts_l : antispoof_opts_l antispoof_opt
1324 antispoof_opt : label {
1325 if (antispoof_opts.label) {
1326 yyerror("label cannot be redefined");
1329 antispoof_opts.label = $1;
1332 if ($2 < 0 || $2 > rt_tableid_max()) {
1333 yyerror("invalid rtable id");
1336 antispoof_opts.rtableid = $2;
1340 not : '!' { $$ = 1; }
1341 | /* empty */ { $$ = 0; }
1344 tabledef : TABLE '<' STRING '>' table_opts {
1345 struct node_host *h, *nh;
1346 struct node_tinit *ti, *nti;
1348 if (strlen($3) >= PF_TABLE_NAME_SIZE) {
1349 yyerror("table name too long, max %d chars",
1350 PF_TABLE_NAME_SIZE - 1);
1354 if (pf->loadopt & PFCTL_FLAG_TABLE)
1355 if (process_tabledef($3, &$5)) {
1360 for (ti = SIMPLEQ_FIRST(&$5.init_nodes);
1361 ti != SIMPLEQ_END(&$5.init_nodes); ti = nti) {
1364 for (h = ti->host; h != NULL; h = nh) {
1368 nti = SIMPLEQ_NEXT(ti, entries);
1375 bzero(&table_opts, sizeof table_opts);
1376 SIMPLEQ_INIT(&table_opts.init_nodes);
1379 { $$ = table_opts; }
1382 bzero(&table_opts, sizeof table_opts);
1383 SIMPLEQ_INIT(&table_opts.init_nodes);
1388 table_opts_l : table_opts_l table_opt
1392 table_opt : STRING {
1393 if (!strcmp($1, "const"))
1394 table_opts.flags |= PFR_TFLAG_CONST;
1395 else if (!strcmp($1, "persist"))
1396 table_opts.flags |= PFR_TFLAG_PERSIST;
1397 else if (!strcmp($1, "counters"))
1398 table_opts.flags |= PFR_TFLAG_COUNTERS;
1400 yyerror("invalid table option '%s'", $1);
1406 | '{' optnl '}' { table_opts.init_addr = 1; }
1407 | '{' optnl host_list '}' {
1408 struct node_host *n;
1409 struct node_tinit *ti;
1411 for (n = $3; n != NULL; n = n->next) {
1412 switch (n->addr.type) {
1413 case PF_ADDR_ADDRMASK:
1416 yyerror("address ranges are not "
1417 "permitted inside tables");
1419 case PF_ADDR_DYNIFTL:
1420 yyerror("dynamic addresses are not "
1421 "permitted inside tables");
1424 yyerror("tables cannot contain tables");
1426 case PF_ADDR_NOROUTE:
1427 yyerror("\"no-route\" is not permitted "
1430 case PF_ADDR_URPFFAILED:
1431 yyerror("\"urpf-failed\" is not "
1432 "permitted inside tables");
1435 yyerror("unknown address type %d",
1440 if (!(ti = calloc(1, sizeof(*ti))))
1441 err(1, "table_opt: calloc");
1443 SIMPLEQ_INSERT_TAIL(&table_opts.init_nodes, ti,
1445 table_opts.init_addr = 1;
1448 struct node_tinit *ti;
1450 if (!(ti = calloc(1, sizeof(*ti))))
1451 err(1, "table_opt: calloc");
1453 SIMPLEQ_INSERT_TAIL(&table_opts.init_nodes, ti,
1455 table_opts.init_addr = 1;
1459 altqif : ALTQ interface queue_opts QUEUE qassign {
1462 if (check_rulestate(PFCTL_STATE_QUEUE))
1465 memset(&a, 0, sizeof(a));
1466 if ($3.scheduler.qtype == ALTQT_NONE) {
1467 yyerror("no scheduler specified!");
1470 a.scheduler = $3.scheduler.qtype;
1471 a.qlimit = $3.qlimit;
1472 a.tbrsize = $3.tbrsize;
1474 yyerror("no child queues specified");
1477 if (expand_altq(&a, $2, $5, $3.queue_bwspec,
1483 queuespec : QUEUE STRING interface queue_opts qassign {
1486 if (check_rulestate(PFCTL_STATE_QUEUE)) {
1491 memset(&a, 0, sizeof(a));
1493 if (strlcpy(a.qname, $2, sizeof(a.qname)) >=
1495 yyerror("queue name too long (max "
1496 "%d chars)", PF_QNAME_SIZE-1);
1502 yyerror("cannot specify tbrsize for queue");
1505 if ($4.priority > 255) {
1506 yyerror("priority out of range: max 255");
1509 a.priority = $4.priority;
1510 a.qlimit = $4.qlimit;
1511 a.scheduler = $4.scheduler.qtype;
1512 if (expand_queue(&a, $3, $5, $4.queue_bwspec,
1514 yyerror("errors in queue definition");
1521 bzero(&queue_opts, sizeof queue_opts);
1522 queue_opts.priority = DEFAULT_PRIORITY;
1523 queue_opts.qlimit = DEFAULT_QLIMIT;
1524 queue_opts.scheduler.qtype = ALTQT_NONE;
1525 queue_opts.queue_bwspec.bw_percent = 100;
1528 { $$ = queue_opts; }
1530 bzero(&queue_opts, sizeof queue_opts);
1531 queue_opts.priority = DEFAULT_PRIORITY;
1532 queue_opts.qlimit = DEFAULT_QLIMIT;
1533 queue_opts.scheduler.qtype = ALTQT_NONE;
1534 queue_opts.queue_bwspec.bw_percent = 100;
1539 queue_opts_l : queue_opts_l queue_opt
1543 queue_opt : BANDWIDTH bandwidth {
1544 if (queue_opts.marker & QOM_BWSPEC) {
1545 yyerror("bandwidth cannot be respecified");
1548 queue_opts.marker |= QOM_BWSPEC;
1549 queue_opts.queue_bwspec = $2;
1552 if (queue_opts.marker & QOM_PRIORITY) {
1553 yyerror("priority cannot be respecified");
1556 if ($2 < 0 || $2 > 255) {
1557 yyerror("priority out of range: max 255");
1560 queue_opts.marker |= QOM_PRIORITY;
1561 queue_opts.priority = $2;
1564 if (queue_opts.marker & QOM_QLIMIT) {
1565 yyerror("qlimit cannot be respecified");
1568 if ($2 < 0 || $2 > 65535) {
1569 yyerror("qlimit out of range: max 65535");
1572 queue_opts.marker |= QOM_QLIMIT;
1573 queue_opts.qlimit = $2;
1576 if (queue_opts.marker & QOM_SCHEDULER) {
1577 yyerror("scheduler cannot be respecified");
1580 queue_opts.marker |= QOM_SCHEDULER;
1581 queue_opts.scheduler = $1;
1584 if (queue_opts.marker & QOM_TBRSIZE) {
1585 yyerror("tbrsize cannot be respecified");
1588 if ($2 < 0 || $2 > 65535) {
1589 yyerror("tbrsize too big: max 65535");
1592 queue_opts.marker |= QOM_TBRSIZE;
1593 queue_opts.tbrsize = $2;
1597 bandwidth : STRING {
1603 bps = strtod($1, &cp);
1605 if (!strcmp(cp, "b"))
1607 else if (!strcmp(cp, "Kb"))
1609 else if (!strcmp(cp, "Mb"))
1611 else if (!strcmp(cp, "Gb"))
1612 bps *= 1000 * 1000 * 1000;
1613 else if (!strcmp(cp, "%")) {
1614 if (bps < 0 || bps > 100) {
1615 yyerror("bandwidth spec "
1620 $$.bw_percent = bps;
1623 yyerror("unknown unit %s", cp);
1629 $$.bw_absolute = (u_int32_t)bps;
1632 if ($1 < 0 || $1 > UINT_MAX) {
1633 yyerror("bandwidth number too big");
1637 $$.bw_absolute = $1;
1642 $$.qtype = ALTQT_CBQ;
1643 $$.data.cbq_opts.flags = 0;
1645 | CBQ '(' cbqflags_list ')' {
1646 $$.qtype = ALTQT_CBQ;
1647 $$.data.cbq_opts.flags = $3;
1650 $$.qtype = ALTQT_PRIQ;
1651 $$.data.priq_opts.flags = 0;
1653 | PRIQ '(' priqflags_list ')' {
1654 $$.qtype = ALTQT_PRIQ;
1655 $$.data.priq_opts.flags = $3;
1658 $$.qtype = ALTQT_HFSC;
1659 bzero(&$$.data.hfsc_opts,
1660 sizeof(struct node_hfsc_opts));
1662 | HFSC '(' hfsc_opts ')' {
1663 $$.qtype = ALTQT_HFSC;
1664 $$.data.hfsc_opts = $3;
1667 $$.qtype = ALTQT_FAIRQ;
1668 bzero(&$$.data.fairq_opts,
1669 sizeof(struct node_fairq_opts));
1671 | FAIRQ '(' fairq_opts ')' {
1672 $$.qtype = ALTQT_FAIRQ;
1673 $$.data.fairq_opts = $3;
1677 cbqflags_list : cbqflags_item { $$ |= $1; }
1678 | cbqflags_list comma cbqflags_item { $$ |= $3; }
1681 cbqflags_item : STRING {
1682 if (!strcmp($1, "default"))
1683 $$ = CBQCLF_DEFCLASS;
1684 else if (!strcmp($1, "borrow"))
1686 else if (!strcmp($1, "red"))
1688 else if (!strcmp($1, "ecn"))
1689 $$ = CBQCLF_RED|CBQCLF_ECN;
1690 else if (!strcmp($1, "rio"))
1693 yyerror("unknown cbq flag \"%s\"", $1);
1701 priqflags_list : priqflags_item { $$ |= $1; }
1702 | priqflags_list comma priqflags_item { $$ |= $3; }
1705 priqflags_item : STRING {
1706 if (!strcmp($1, "default"))
1707 $$ = PRCF_DEFAULTCLASS;
1708 else if (!strcmp($1, "red"))
1710 else if (!strcmp($1, "ecn"))
1711 $$ = PRCF_RED|PRCF_ECN;
1712 else if (!strcmp($1, "rio"))
1715 yyerror("unknown priq flag \"%s\"", $1);
1725 sizeof(struct node_hfsc_opts));
1732 hfscopts_list : hfscopts_item
1733 | hfscopts_list comma hfscopts_item
1736 hfscopts_item : LINKSHARE bandwidth {
1737 if (hfsc_opts.linkshare.used) {
1738 yyerror("linkshare already specified");
1741 hfsc_opts.linkshare.m2 = $2;
1742 hfsc_opts.linkshare.used = 1;
1744 | LINKSHARE '(' bandwidth comma NUMBER comma bandwidth ')'
1746 if ($5 < 0 || $5 > INT_MAX) {
1747 yyerror("timing in curve out of range");
1750 if (hfsc_opts.linkshare.used) {
1751 yyerror("linkshare already specified");
1754 hfsc_opts.linkshare.m1 = $3;
1755 hfsc_opts.linkshare.d = $5;
1756 hfsc_opts.linkshare.m2 = $7;
1757 hfsc_opts.linkshare.used = 1;
1759 | REALTIME bandwidth {
1760 if (hfsc_opts.realtime.used) {
1761 yyerror("realtime already specified");
1764 hfsc_opts.realtime.m2 = $2;
1765 hfsc_opts.realtime.used = 1;
1767 | REALTIME '(' bandwidth comma NUMBER comma bandwidth ')'
1769 if ($5 < 0 || $5 > INT_MAX) {
1770 yyerror("timing in curve out of range");
1773 if (hfsc_opts.realtime.used) {
1774 yyerror("realtime already specified");
1777 hfsc_opts.realtime.m1 = $3;
1778 hfsc_opts.realtime.d = $5;
1779 hfsc_opts.realtime.m2 = $7;
1780 hfsc_opts.realtime.used = 1;
1782 | UPPERLIMIT bandwidth {
1783 if (hfsc_opts.upperlimit.used) {
1784 yyerror("upperlimit already specified");
1787 hfsc_opts.upperlimit.m2 = $2;
1788 hfsc_opts.upperlimit.used = 1;
1790 | UPPERLIMIT '(' bandwidth comma NUMBER comma bandwidth ')'
1792 if ($5 < 0 || $5 > INT_MAX) {
1793 yyerror("timing in curve out of range");
1796 if (hfsc_opts.upperlimit.used) {
1797 yyerror("upperlimit already specified");
1800 hfsc_opts.upperlimit.m1 = $3;
1801 hfsc_opts.upperlimit.d = $5;
1802 hfsc_opts.upperlimit.m2 = $7;
1803 hfsc_opts.upperlimit.used = 1;
1806 if (!strcmp($1, "default"))
1807 hfsc_opts.flags |= HFCF_DEFAULTCLASS;
1808 else if (!strcmp($1, "red"))
1809 hfsc_opts.flags |= HFCF_RED;
1810 else if (!strcmp($1, "ecn"))
1811 hfsc_opts.flags |= HFCF_RED|HFCF_ECN;
1812 else if (!strcmp($1, "rio"))
1813 hfsc_opts.flags |= HFCF_RIO;
1815 yyerror("unknown hfsc flag \"%s\"", $1);
1825 sizeof(struct node_fairq_opts));
1832 fairqopts_list : fairqopts_item
1833 | fairqopts_list comma fairqopts_item
1836 fairqopts_item : LINKSHARE bandwidth {
1837 if (fairq_opts.linkshare.used) {
1838 yyerror("linkshare already specified");
1841 fairq_opts.linkshare.m2 = $2;
1842 fairq_opts.linkshare.used = 1;
1844 | LINKSHARE '(' bandwidth number bandwidth ')' {
1845 if (fairq_opts.linkshare.used) {
1846 yyerror("linkshare already specified");
1849 fairq_opts.linkshare.m1 = $3;
1850 fairq_opts.linkshare.d = $4;
1851 fairq_opts.linkshare.m2 = $5;
1852 fairq_opts.linkshare.used = 1;
1855 fairq_opts.hogs_bw = $2;
1858 fairq_opts.nbuckets = $2;
1861 if (!strcmp($1, "default"))
1862 fairq_opts.flags |= FARF_DEFAULTCLASS;
1863 else if (!strcmp($1, "red"))
1864 fairq_opts.flags |= FARF_RED;
1865 else if (!strcmp($1, "ecn"))
1866 fairq_opts.flags |= FARF_RED|FARF_ECN;
1867 else if (!strcmp($1, "rio"))
1868 fairq_opts.flags |= FARF_RIO;
1870 yyerror("unknown fairq flag \"%s\"", $1);
1878 qassign : /* empty */ { $$ = NULL; }
1879 | qassign_item { $$ = $1; }
1880 | '{' optnl qassign_list '}' { $$ = $3; }
1883 qassign_list : qassign_item optnl { $$ = $1; }
1884 | qassign_list comma qassign_item optnl {
1885 $1->tail->next = $3;
1891 qassign_item : STRING {
1892 $$ = calloc(1, sizeof(struct node_queue));
1894 err(1, "qassign_item: calloc");
1895 if (strlcpy($$->queue, $1, sizeof($$->queue)) >=
1896 sizeof($$->queue)) {
1897 yyerror("queue name '%s' too long (max "
1898 "%d chars)", $1, sizeof($$->queue)-1);
1909 pfrule : action dir logquick interface route af proto fromto
1913 struct node_state_opt *o;
1914 struct node_proto *proto;
1920 if (check_rulestate(PFCTL_STATE_FILTER))
1923 memset(&r, 0, sizeof(r));
1927 case PFRULE_RETURNRST:
1928 r.rule_flag |= PFRULE_RETURNRST;
1929 r.return_ttl = $1.w;
1931 case PFRULE_RETURNICMP:
1932 r.rule_flag |= PFRULE_RETURNICMP;
1933 r.return_icmp = $1.w;
1934 r.return_icmp6 = $1.w2;
1937 r.rule_flag |= PFRULE_RETURN;
1938 r.return_icmp = $1.w;
1939 r.return_icmp6 = $1.w2;
1947 r.rtableid = $9.rtableid;
1951 if (strlcpy(r.tagname, $9.tag,
1952 PF_TAG_NAME_SIZE) >= PF_TAG_NAME_SIZE) {
1953 yyerror("tag too long, max %u chars",
1954 PF_TAG_NAME_SIZE - 1);
1958 if (strlcpy(r.match_tagname, $9.match_tag,
1959 PF_TAG_NAME_SIZE) >= PF_TAG_NAME_SIZE) {
1960 yyerror("tag too long, max %u chars",
1961 PF_TAG_NAME_SIZE - 1);
1964 r.match_tag_not = $9.match_tag_not;
1965 if (rule_label(&r, $9.label))
1968 r.flags = $9.flags.b1;
1969 r.flagset = $9.flags.b2;
1970 if (($9.flags.b1 & $9.flags.b2) != $9.flags.b1) {
1971 yyerror("flags always false");
1974 if ($9.flags.b1 || $9.flags.b2 || $8.src_os) {
1975 for (proto = $7; proto != NULL &&
1976 proto->proto != IPPROTO_TCP;
1977 proto = proto->next)
1979 if (proto == NULL && $7 != NULL) {
1980 if ($9.flags.b1 || $9.flags.b2)
1982 "flags only apply to tcp");
1985 "OS fingerprinting only "
1990 if (($9.flags.b1 & parse_flags("S")) == 0 &&
1992 yyerror("OS fingerprinting requires "
1993 "the SYN TCP flag (flags S/SA)");
2000 r.keep_state = $9.keep.action;
2001 o = $9.keep.options;
2003 /* 'keep state' by default on pass rules. */
2004 if (!r.keep_state && !r.action &&
2005 !($9.marker & FOM_KEEP)) {
2006 r.keep_state = PF_STATE_NORMAL;
2007 o = keep_state_defaults;
2012 struct node_state_opt *p = o;
2015 case PF_STATE_OPT_MAX:
2017 yyerror("state option 'max' "
2018 "multiple definitions");
2021 r.max_states = o->data.max_states;
2023 case PF_STATE_OPT_NOSYNC:
2024 if (r.rule_flag & PFRULE_NOSYNC) {
2025 yyerror("state option 'sync' "
2026 "multiple definitions");
2029 r.rule_flag |= PFRULE_NOSYNC;
2031 case PF_STATE_OPT_SRCTRACK:
2033 yyerror("state option "
2035 "multiple definitions");
2038 srctrack = o->data.src_track;
2039 r.rule_flag |= PFRULE_SRCTRACK;
2041 case PF_STATE_OPT_MAX_SRC_STATES:
2042 if (r.max_src_states) {
2043 yyerror("state option "
2045 "multiple definitions");
2048 if (o->data.max_src_states == 0) {
2049 yyerror("'max-src-states' must "
2054 o->data.max_src_states;
2055 r.rule_flag |= PFRULE_SRCTRACK;
2057 case PF_STATE_OPT_OVERLOAD:
2058 if (r.overload_tblname[0]) {
2059 yyerror("multiple 'overload' "
2060 "table definitions");
2063 if (strlcpy(r.overload_tblname,
2064 o->data.overload.tblname,
2065 PF_TABLE_NAME_SIZE) >=
2066 PF_TABLE_NAME_SIZE) {
2067 yyerror("state option: "
2071 r.flush = o->data.overload.flush;
2073 case PF_STATE_OPT_MAX_SRC_CONN:
2074 if (r.max_src_conn) {
2075 yyerror("state option "
2077 "multiple definitions");
2080 if (o->data.max_src_conn == 0) {
2081 yyerror("'max-src-conn' "
2086 o->data.max_src_conn;
2087 r.rule_flag |= PFRULE_SRCTRACK |
2088 PFRULE_RULESRCTRACK;
2090 case PF_STATE_OPT_MAX_SRC_CONN_RATE:
2091 if (r.max_src_conn_rate.limit) {
2092 yyerror("state option "
2093 "'max-src-conn-rate' "
2094 "multiple definitions");
2097 if (!o->data.max_src_conn_rate.limit ||
2098 !o->data.max_src_conn_rate.seconds) {
2099 yyerror("'max-src-conn-rate' "
2100 "values must be > 0");
2103 if (o->data.max_src_conn_rate.limit >
2105 yyerror("'max-src-conn-rate' "
2106 "maximum rate must be < %u",
2110 r.max_src_conn_rate.limit =
2111 o->data.max_src_conn_rate.limit;
2112 r.max_src_conn_rate.seconds =
2113 o->data.max_src_conn_rate.seconds;
2114 r.rule_flag |= PFRULE_SRCTRACK |
2115 PFRULE_RULESRCTRACK;
2117 case PF_STATE_OPT_MAX_SRC_NODES:
2118 if (r.max_src_nodes) {
2119 yyerror("state option "
2121 "multiple definitions");
2124 if (o->data.max_src_nodes == 0) {
2125 yyerror("'max-src-nodes' must "
2130 o->data.max_src_nodes;
2131 r.rule_flag |= PFRULE_SRCTRACK |
2132 PFRULE_RULESRCTRACK;
2134 case PF_STATE_OPT_STATELOCK:
2136 yyerror("state locking option: "
2137 "multiple definitions");
2141 r.rule_flag |= o->data.statelock;
2143 case PF_STATE_OPT_SLOPPY:
2144 if (r.rule_flag & PFRULE_STATESLOPPY) {
2145 yyerror("state sloppy option: "
2146 "multiple definitions");
2149 r.rule_flag |= PFRULE_STATESLOPPY;
2151 case PF_STATE_OPT_TIMEOUT:
2152 if (o->data.timeout.number ==
2153 PFTM_ADAPTIVE_START ||
2154 o->data.timeout.number ==
2157 if (r.timeout[o->data.timeout.number]) {
2158 yyerror("state timeout %s "
2159 "multiple definitions",
2160 pf_timeouts[o->data.
2161 timeout.number].name);
2164 r.timeout[o->data.timeout.number] =
2165 o->data.timeout.seconds;
2172 /* 'flags S/SA' by default on stateful rules */
2173 if (!r.action && !r.flags && !r.flagset &&
2174 !$9.fragment && !($9.marker & FOM_FLAGS) &&
2176 r.flags = parse_flags("S");
2177 r.flagset = parse_flags("SA");
2179 if (!adaptive && r.max_states) {
2180 r.timeout[PFTM_ADAPTIVE_START] =
2181 (r.max_states / 10) * 6;
2182 r.timeout[PFTM_ADAPTIVE_END] =
2183 (r.max_states / 10) * 12;
2185 if (r.rule_flag & PFRULE_SRCTRACK) {
2186 if (srctrack == PF_SRCTRACK_GLOBAL &&
2188 yyerror("'max-src-nodes' is "
2189 "incompatible with "
2190 "'source-track global'");
2193 if (srctrack == PF_SRCTRACK_GLOBAL &&
2195 yyerror("'max-src-conn' is "
2196 "incompatible with "
2197 "'source-track global'");
2200 if (srctrack == PF_SRCTRACK_GLOBAL &&
2201 r.max_src_conn_rate.seconds) {
2202 yyerror("'max-src-conn-rate' is "
2203 "incompatible with "
2204 "'source-track global'");
2207 if (r.timeout[PFTM_SRC_NODE] <
2208 r.max_src_conn_rate.seconds)
2209 r.timeout[PFTM_SRC_NODE] =
2210 r.max_src_conn_rate.seconds;
2211 r.rule_flag |= PFRULE_SRCTRACK;
2212 if (srctrack == PF_SRCTRACK_RULE)
2213 r.rule_flag |= PFRULE_RULESRCTRACK;
2215 if (r.keep_state && !statelock)
2216 r.rule_flag |= default_statelock;
2219 r.rule_flag |= PFRULE_FRAGMENT;
2220 r.allow_opts = $9.allowopts;
2222 decide_address_family($8.src.host, &r.af);
2223 decide_address_family($8.dst.host, &r.af);
2227 yyerror("direction must be explicit "
2228 "with rules that specify routing");
2232 r.rpool.opts = $5.pool_opts;
2234 memcpy(&r.rpool.key, $5.key,
2235 sizeof(struct pf_poolhashkey));
2237 if (r.rt && r.rt != PF_FASTROUTE) {
2238 decide_address_family($5.host, &r.af);
2239 remove_invalid_hosts(&$5.host, &r.af);
2240 if ($5.host == NULL) {
2241 yyerror("no routing address with "
2242 "matching address family found.");
2245 if ((r.rpool.opts & PF_POOL_TYPEMASK) ==
2246 PF_POOL_NONE && ($5.host->next != NULL ||
2247 $5.host->addr.type == PF_ADDR_TABLE ||
2248 DYNIF_MULTIADDR($5.host->addr)))
2249 r.rpool.opts |= PF_POOL_ROUNDROBIN;
2250 if ((r.rpool.opts & PF_POOL_TYPEMASK) !=
2251 PF_POOL_ROUNDROBIN &&
2252 disallow_table($5.host, "tables are only "
2253 "supported in round-robin routing pools"))
2255 if ((r.rpool.opts & PF_POOL_TYPEMASK) !=
2256 PF_POOL_ROUNDROBIN &&
2257 disallow_alias($5.host, "interface (%s) "
2258 "is only supported in round-robin "
2261 if ($5.host->next != NULL) {
2262 if ((r.rpool.opts & PF_POOL_TYPEMASK) !=
2263 PF_POOL_ROUNDROBIN) {
2264 yyerror("r.rpool.opts must "
2265 "be PF_POOL_ROUNDROBIN");
2270 if ($9.queues.qname != NULL) {
2271 if (strlcpy(r.qname, $9.queues.qname,
2272 sizeof(r.qname)) >= sizeof(r.qname)) {
2273 yyerror("rule qname too long (max "
2274 "%d chars)", sizeof(r.qname)-1);
2277 free($9.queues.qname);
2279 if ($9.queues.pqname != NULL) {
2280 if (strlcpy(r.pqname, $9.queues.pqname,
2281 sizeof(r.pqname)) >= sizeof(r.pqname)) {
2282 yyerror("rule pqname too long (max "
2283 "%d chars)", sizeof(r.pqname)-1);
2286 free($9.queues.pqname);
2289 r.divert.port = $9.divert.port;
2291 if ((r.divert.port = $9.divert.port)) {
2292 if (r.direction == PF_OUT) {
2293 if ($9.divert.addr) {
2294 yyerror("address specified "
2295 "for outgoing divert");
2298 bzero(&r.divert.addr,
2299 sizeof(r.divert.addr));
2301 if (!$9.divert.addr) {
2302 yyerror("no address specified "
2303 "for incoming divert");
2306 if ($9.divert.addr->af != r.af) {
2307 yyerror("address family "
2308 "mismatch for divert");
2312 $9.divert.addr->addr.v.a.addr;
2317 expand_rule(&r, $4, $5.host, $7, $8.src_os,
2318 $8.src.host, $8.src.port, $8.dst.host, $8.dst.port,
2319 $9.uid, $9.gid, $9.icmpspec, "");
2324 bzero(&filter_opts, sizeof filter_opts);
2325 filter_opts.rtableid = -1;
2328 { $$ = filter_opts; }
2330 bzero(&filter_opts, sizeof filter_opts);
2331 filter_opts.rtableid = -1;
2336 filter_opts_l : filter_opts_l filter_opt
2340 filter_opt : USER uids {
2341 if (filter_opts.uid)
2342 $2->tail->next = filter_opts.uid;
2343 filter_opts.uid = $2;
2346 if (filter_opts.gid)
2347 $2->tail->next = filter_opts.gid;
2348 filter_opts.gid = $2;
2351 if (filter_opts.marker & FOM_FLAGS) {
2352 yyerror("flags cannot be redefined");
2355 filter_opts.marker |= FOM_FLAGS;
2356 filter_opts.flags.b1 |= $1.b1;
2357 filter_opts.flags.b2 |= $1.b2;
2358 filter_opts.flags.w |= $1.w;
2359 filter_opts.flags.w2 |= $1.w2;
2362 if (filter_opts.marker & FOM_ICMP) {
2363 yyerror("icmp-type cannot be redefined");
2366 filter_opts.marker |= FOM_ICMP;
2367 filter_opts.icmpspec = $1;
2370 if (filter_opts.marker & FOM_TOS) {
2371 yyerror("tos cannot be redefined");
2374 filter_opts.marker |= FOM_TOS;
2375 filter_opts.tos = $2;
2378 if (filter_opts.marker & FOM_KEEP) {
2379 yyerror("modulate or keep cannot be redefined");
2382 filter_opts.marker |= FOM_KEEP;
2383 filter_opts.keep.action = $1.action;
2384 filter_opts.keep.options = $1.options;
2387 filter_opts.fragment = 1;
2390 filter_opts.allowopts = 1;
2393 if (filter_opts.label) {
2394 yyerror("label cannot be redefined");
2397 filter_opts.label = $1;
2400 if (filter_opts.queues.qname) {
2401 yyerror("queue cannot be redefined");
2404 filter_opts.queues = $1;
2407 filter_opts.tag = $2;
2409 | not TAGGED string {
2410 filter_opts.match_tag = $3;
2411 filter_opts.match_tag_not = $1;
2413 | PROBABILITY probability {
2416 p = floor($2 * UINT_MAX + 0.5);
2417 if (p < 0.0 || p > UINT_MAX) {
2418 yyerror("invalid probability: %lf", p);
2421 filter_opts.prob = (u_int32_t)p;
2422 if (filter_opts.prob == 0)
2423 filter_opts.prob = 1;
2426 if ($2 < 0 || $2 > rt_tableid_max()) {
2427 yyerror("invalid rtable id");
2430 filter_opts.rtableid = $2;
2432 | DIVERTTO portplain {
2434 filter_opts.divert.port = $2.a;
2435 if (!filter_opts.divert.port) {
2436 yyerror("invalid divert port: %u", ntohs($2.a));
2441 | DIVERTTO STRING PORT portplain {
2443 if ((filter_opts.divert.addr = host($2)) == NULL) {
2444 yyerror("could not parse divert address: %s",
2453 filter_opts.divert.port = $4.a;
2454 if (!filter_opts.divert.port) {
2455 yyerror("invalid divert port: %u", ntohs($4.a));
2461 yyerror("divert-reply has no meaning in FreeBSD pf(4)");
2464 filter_opts.divert.port = 1; /* some random value */
2469 probability : STRING {
2471 double p = strtod($1, &e);
2478 yyerror("invalid probability: %s", $1);
2491 action : PASS { $$.b1 = PF_PASS; $$.b2 = $$.w = 0; }
2492 | BLOCK blockspec { $$ = $2; $$.b1 = PF_DROP; }
2495 blockspec : /* empty */ {
2496 $$.b2 = blockpolicy;
2497 $$.w = returnicmpdefault;
2498 $$.w2 = returnicmp6default;
2501 $$.b2 = PFRULE_DROP;
2506 $$.b2 = PFRULE_RETURNRST;
2510 | RETURNRST '(' TTL NUMBER ')' {
2511 if ($4 < 0 || $4 > 255) {
2512 yyerror("illegal ttl value %d", $4);
2515 $$.b2 = PFRULE_RETURNRST;
2520 $$.b2 = PFRULE_RETURNICMP;
2521 $$.w = returnicmpdefault;
2522 $$.w2 = returnicmp6default;
2525 $$.b2 = PFRULE_RETURNICMP;
2526 $$.w = returnicmpdefault;
2527 $$.w2 = returnicmp6default;
2529 | RETURNICMP '(' reticmpspec ')' {
2530 $$.b2 = PFRULE_RETURNICMP;
2532 $$.w2 = returnicmpdefault;
2534 | RETURNICMP6 '(' reticmp6spec ')' {
2535 $$.b2 = PFRULE_RETURNICMP;
2536 $$.w = returnicmpdefault;
2539 | RETURNICMP '(' reticmpspec comma reticmp6spec ')' {
2540 $$.b2 = PFRULE_RETURNICMP;
2545 $$.b2 = PFRULE_RETURN;
2546 $$.w = returnicmpdefault;
2547 $$.w2 = returnicmp6default;
2551 reticmpspec : STRING {
2552 if (!($$ = parseicmpspec($1, AF_INET))) {
2561 if ($1 < 0 || $1 > 255) {
2562 yyerror("invalid icmp code %lu", $1);
2565 icmptype = returnicmpdefault >> 8;
2566 $$ = (icmptype << 8 | $1);
2570 reticmp6spec : STRING {
2571 if (!($$ = parseicmpspec($1, AF_INET6))) {
2580 if ($1 < 0 || $1 > 255) {
2581 yyerror("invalid icmp code %lu", $1);
2584 icmptype = returnicmp6default >> 8;
2585 $$ = (icmptype << 8 | $1);
2589 dir : /* empty */ { $$ = PF_INOUT; }
2590 | IN { $$ = PF_IN; }
2591 | OUT { $$ = PF_OUT; }
2594 quick : /* empty */ { $$.quick = 0; }
2595 | QUICK { $$.quick = 1; }
2598 logquick : /* empty */ { $$.log = 0; $$.quick = 0; $$.logif = 0; }
2599 | log { $$ = $1; $$.quick = 0; }
2600 | QUICK { $$.quick = 1; $$.log = 0; $$.logif = 0; }
2601 | log QUICK { $$ = $1; $$.quick = 1; }
2602 | QUICK log { $$ = $2; $$.quick = 1; }
2605 log : LOG { $$.log = PF_LOG; $$.logif = 0; }
2606 | LOG '(' logopts ')' {
2607 $$.log = PF_LOG | $3.log;
2608 $$.logif = $3.logif;
2612 logopts : logopt { $$ = $1; }
2613 | logopts comma logopt {
2614 $$.log = $1.log | $3.log;
2615 $$.logif = $3.logif;
2617 $$.logif = $1.logif;
2621 logopt : ALL { $$.log = PF_LOG_ALL; $$.logif = 0; }
2622 | USER { $$.log = PF_LOG_SOCKET_LOOKUP; $$.logif = 0; }
2623 | GROUP { $$.log = PF_LOG_SOCKET_LOOKUP; $$.logif = 0; }
2629 if (strncmp($2, "pflog", 5)) {
2630 yyerror("%s: should be a pflog interface", $2);
2634 i = strtonum($2 + 5, 0, 255, &errstr);
2636 yyerror("%s: %s", $2, errstr);
2645 interface : /* empty */ { $$ = NULL; }
2646 | ON if_item_not { $$ = $2; }
2647 | ON '{' optnl if_list '}' { $$ = $4; }
2650 if_list : if_item_not optnl { $$ = $1; }
2651 | if_list comma if_item_not optnl {
2652 $1->tail->next = $3;
2658 if_item_not : not if_item { $$ = $2; $$->not = $1; }
2662 struct node_host *n;
2664 $$ = calloc(1, sizeof(struct node_if));
2666 err(1, "if_item: calloc");
2667 if (strlcpy($$->ifname, $1, sizeof($$->ifname)) >=
2668 sizeof($$->ifname)) {
2671 yyerror("interface name too long");
2675 if ((n = ifa_exists($1)) != NULL)
2676 $$->ifa_flags = n->ifa_flags;
2685 af : /* empty */ { $$ = 0; }
2686 | INET { $$ = AF_INET; }
2687 | INET6 { $$ = AF_INET6; }
2690 proto : /* empty */ { $$ = NULL; }
2691 | PROTO proto_item { $$ = $2; }
2692 | PROTO '{' optnl proto_list '}' { $$ = $4; }
2695 proto_list : proto_item optnl { $$ = $1; }
2696 | proto_list comma proto_item optnl {
2697 $1->tail->next = $3;
2703 proto_item : protoval {
2708 yyerror("proto 0 cannot be used");
2711 $$ = calloc(1, sizeof(struct node_proto));
2713 err(1, "proto_item: calloc");
2723 p = getprotobyname($1);
2725 yyerror("unknown protocol %s", $1);
2733 if ($1 < 0 || $1 > 255) {
2734 yyerror("protocol outside range");
2754 os : /* empty */ { $$ = NULL; }
2755 | OS xos { $$ = $2; }
2756 | OS '{' optnl os_list '}' { $$ = $4; }
2760 $$ = calloc(1, sizeof(struct node_os));
2762 err(1, "os: calloc");
2768 os_list : xos optnl { $$ = $1; }
2769 | os_list comma xos optnl {
2770 $1->tail->next = $3;
2776 from : /* empty */ {
2790 if (disallow_urpf_failed($2.host, "\"urpf-failed\" is "
2791 "not permitted in a destination address"))
2797 ipportspec : ipspec {
2801 | ipspec PORT portspec {
2815 ipspec : ANY { $$ = NULL; }
2816 | xhost { $$ = $1; }
2817 | '{' optnl host_list '}' { $$ = $3; }
2820 toipspec : TO ipspec { $$ = $2; }
2821 | /* empty */ { $$ = NULL; }
2824 host_list : ipspec optnl { $$ = $1; }
2825 | host_list comma ipspec optnl {
2828 else if ($1 == NULL)
2831 $1->tail->next = $3;
2832 $1->tail = $3->tail;
2839 struct node_host *n;
2841 for (n = $2; n != NULL; n = n->next)
2846 $$ = calloc(1, sizeof(struct node_host));
2848 err(1, "xhost: calloc");
2849 $$->addr.type = PF_ADDR_NOROUTE;
2855 $$ = calloc(1, sizeof(struct node_host));
2857 err(1, "xhost: calloc");
2858 $$->addr.type = PF_ADDR_URPFFAILED;
2866 if (($$ = host($1)) == NULL) {
2867 /* error. "any" is handled elsewhere */
2869 yyerror("could not parse host specification");
2875 | STRING '-' STRING {
2876 struct node_host *b, *e;
2878 if ((b = host($1)) == NULL || (e = host($3)) == NULL) {
2881 yyerror("could not parse host specification");
2884 if (b->af != e->af ||
2885 b->addr.type != PF_ADDR_ADDRMASK ||
2886 e->addr.type != PF_ADDR_ADDRMASK ||
2887 unmask(&b->addr.v.a.mask, b->af) !=
2888 (b->af == AF_INET ? 32 : 128) ||
2889 unmask(&e->addr.v.a.mask, e->af) !=
2890 (e->af == AF_INET ? 32 : 128) ||
2891 b->next != NULL || b->not ||
2892 e->next != NULL || e->not) {
2897 yyerror("invalid address range");
2900 memcpy(&b->addr.v.a.mask, &e->addr.v.a.addr,
2901 sizeof(b->addr.v.a.mask));
2902 b->addr.type = PF_ADDR_RANGE;
2908 | STRING '/' NUMBER {
2911 if (asprintf(&buf, "%s/%lld", $1, (long long)$3) == -1)
2912 err(1, "host: asprintf");
2914 if (($$ = host(buf)) == NULL) {
2915 /* error. "any" is handled elsewhere */
2917 yyerror("could not parse host specification");
2922 | NUMBER '/' NUMBER {
2925 /* ie. for 10/8 parsing */
2927 if (asprintf(&buf, "%lld/%lld", (long long)$1, (long long)$3) == -1)
2929 if (asprintf(&buf, "%lld/%lld", $1, $3) == -1)
2931 err(1, "host: asprintf");
2932 if (($$ = host(buf)) == NULL) {
2933 /* error. "any" is handled elsewhere */
2935 yyerror("could not parse host specification");
2941 | dynaddr '/' NUMBER {
2942 struct node_host *n;
2944 if ($3 < 0 || $3 > 128) {
2945 yyerror("bit number too big");
2949 for (n = $1; n != NULL; n = n->next)
2953 if (strlen($2) >= PF_TABLE_NAME_SIZE) {
2954 yyerror("table name '%s' too long", $2);
2958 $$ = calloc(1, sizeof(struct node_host));
2960 err(1, "host: calloc");
2961 $$->addr.type = PF_ADDR_TABLE;
2962 if (strlcpy($$->addr.v.tblname, $2,
2963 sizeof($$->addr.v.tblname)) >=
2964 sizeof($$->addr.v.tblname))
2965 errx(1, "host: strlcpy");
2976 if (atoul($1, &ulval) == -1) {
2977 yyerror("%s is not a number", $1);
2986 dynaddr : '(' STRING ')' {
2991 if (!isalpha(op[0])) {
2992 yyerror("invalid interface name '%s'", op);
2996 while ((p = strrchr($2, ':')) != NULL) {
2997 if (!strcmp(p+1, "network"))
2998 flags |= PFI_AFLAG_NETWORK;
2999 else if (!strcmp(p+1, "broadcast"))
3000 flags |= PFI_AFLAG_BROADCAST;
3001 else if (!strcmp(p+1, "peer"))
3002 flags |= PFI_AFLAG_PEER;
3003 else if (!strcmp(p+1, "0"))
3004 flags |= PFI_AFLAG_NOALIAS;
3006 yyerror("interface %s has bad modifier",
3013 if (flags & (flags - 1) & PFI_AFLAG_MODEMASK) {
3015 yyerror("illegal combination of "
3016 "interface modifiers");
3019 $$ = calloc(1, sizeof(struct node_host));
3021 err(1, "address: calloc");
3023 set_ipmask($$, 128);
3024 $$->addr.type = PF_ADDR_DYNIFTL;
3025 $$->addr.iflags = flags;
3026 if (strlcpy($$->addr.v.ifname, $2,
3027 sizeof($$->addr.v.ifname)) >=
3028 sizeof($$->addr.v.ifname)) {
3031 yyerror("interface name too long");
3040 portspec : port_item { $$ = $1; }
3041 | '{' optnl port_list '}' { $$ = $3; }
3044 port_list : port_item optnl { $$ = $1; }
3045 | port_list comma port_item optnl {
3046 $1->tail->next = $3;
3052 port_item : portrange {
3053 $$ = calloc(1, sizeof(struct node_port));
3055 err(1, "port_item: calloc");
3065 | unaryop portrange {
3067 yyerror("':' cannot be used with an other "
3071 $$ = calloc(1, sizeof(struct node_port));
3073 err(1, "port_item: calloc");
3080 | portrange PORTBINARY portrange {
3082 yyerror("':' cannot be used with an other "
3086 $$ = calloc(1, sizeof(struct node_port));
3088 err(1, "port_item: calloc");
3097 portplain : numberstring {
3098 if (parseport($1, &$$, 0) == -1) {
3106 portrange : numberstring {
3107 if (parseport($1, &$$, PPORT_RANGE) == -1) {
3115 uids : uid_item { $$ = $1; }
3116 | '{' optnl uid_list '}' { $$ = $3; }
3119 uid_list : uid_item optnl { $$ = $1; }
3120 | uid_list comma uid_item optnl {
3121 $1->tail->next = $3;
3128 $$ = calloc(1, sizeof(struct node_uid));
3130 err(1, "uid_item: calloc");
3138 if ($2 == UID_MAX && $1 != PF_OP_EQ && $1 != PF_OP_NE) {
3139 yyerror("user unknown requires operator = or "
3143 $$ = calloc(1, sizeof(struct node_uid));
3145 err(1, "uid_item: calloc");
3152 | uid PORTBINARY uid {
3153 if ($1 == UID_MAX || $3 == UID_MAX) {
3154 yyerror("user unknown requires operator = or "
3158 $$ = calloc(1, sizeof(struct node_uid));
3160 err(1, "uid_item: calloc");
3170 if (!strcmp($1, "unknown"))
3175 if ((pw = getpwnam($1)) == NULL) {
3176 yyerror("unknown user %s", $1);
3185 if ($1 < 0 || $1 >= UID_MAX) {
3186 yyerror("illegal uid value %lu", $1);
3193 gids : gid_item { $$ = $1; }
3194 | '{' optnl gid_list '}' { $$ = $3; }
3197 gid_list : gid_item optnl { $$ = $1; }
3198 | gid_list comma gid_item optnl {
3199 $1->tail->next = $3;
3206 $$ = calloc(1, sizeof(struct node_gid));
3208 err(1, "gid_item: calloc");
3216 if ($2 == GID_MAX && $1 != PF_OP_EQ && $1 != PF_OP_NE) {
3217 yyerror("group unknown requires operator = or "
3221 $$ = calloc(1, sizeof(struct node_gid));
3223 err(1, "gid_item: calloc");
3230 | gid PORTBINARY gid {
3231 if ($1 == GID_MAX || $3 == GID_MAX) {
3232 yyerror("group unknown requires operator = or "
3236 $$ = calloc(1, sizeof(struct node_gid));
3238 err(1, "gid_item: calloc");
3248 if (!strcmp($1, "unknown"))
3253 if ((grp = getgrnam($1)) == NULL) {
3254 yyerror("unknown group %s", $1);
3263 if ($1 < 0 || $1 >= GID_MAX) {
3264 yyerror("illegal gid value %lu", $1);
3274 if ((f = parse_flags($1)) < 0) {
3275 yyerror("bad flags %s", $1);
3284 flags : FLAGS flag '/' flag { $$.b1 = $2.b1; $$.b2 = $4.b1; }
3285 | FLAGS '/' flag { $$.b1 = 0; $$.b2 = $3.b1; }
3286 | FLAGS ANY { $$.b1 = 0; $$.b2 = 0; }
3289 icmpspec : ICMPTYPE icmp_item { $$ = $2; }
3290 | ICMPTYPE '{' optnl icmp_list '}' { $$ = $4; }
3291 | ICMP6TYPE icmp6_item { $$ = $2; }
3292 | ICMP6TYPE '{' optnl icmp6_list '}' { $$ = $4; }
3295 icmp_list : icmp_item optnl { $$ = $1; }
3296 | icmp_list comma icmp_item optnl {
3297 $1->tail->next = $3;
3303 icmp6_list : icmp6_item optnl { $$ = $1; }
3304 | icmp6_list comma icmp6_item optnl {
3305 $1->tail->next = $3;
3311 icmp_item : icmptype {
3312 $$ = calloc(1, sizeof(struct node_icmp));
3314 err(1, "icmp_item: calloc");
3317 $$->proto = IPPROTO_ICMP;
3321 | icmptype CODE STRING {
3322 const struct icmpcodeent *p;
3324 if ((p = geticmpcodebyname($1-1, $3, AF_INET)) == NULL) {
3325 yyerror("unknown icmp-code %s", $3);
3331 $$ = calloc(1, sizeof(struct node_icmp));
3333 err(1, "icmp_item: calloc");
3335 $$->code = p->code + 1;
3336 $$->proto = IPPROTO_ICMP;
3340 | icmptype CODE NUMBER {
3341 if ($3 < 0 || $3 > 255) {
3342 yyerror("illegal icmp-code %lu", $3);
3345 $$ = calloc(1, sizeof(struct node_icmp));
3347 err(1, "icmp_item: calloc");
3350 $$->proto = IPPROTO_ICMP;
3356 icmp6_item : icmp6type {
3357 $$ = calloc(1, sizeof(struct node_icmp));
3359 err(1, "icmp_item: calloc");
3362 $$->proto = IPPROTO_ICMPV6;
3366 | icmp6type CODE STRING {
3367 const struct icmpcodeent *p;
3369 if ((p = geticmpcodebyname($1-1, $3, AF_INET6)) == NULL) {
3370 yyerror("unknown icmp6-code %s", $3);
3376 $$ = calloc(1, sizeof(struct node_icmp));
3378 err(1, "icmp_item: calloc");
3380 $$->code = p->code + 1;
3381 $$->proto = IPPROTO_ICMPV6;
3385 | icmp6type CODE NUMBER {
3386 if ($3 < 0 || $3 > 255) {
3387 yyerror("illegal icmp-code %lu", $3);
3390 $$ = calloc(1, sizeof(struct node_icmp));
3392 err(1, "icmp_item: calloc");
3395 $$->proto = IPPROTO_ICMPV6;
3402 const struct icmptypeent *p;
3404 if ((p = geticmptypebyname($1, AF_INET)) == NULL) {
3405 yyerror("unknown icmp-type %s", $1);
3413 if ($1 < 0 || $1 > 255) {
3414 yyerror("illegal icmp-type %lu", $1);
3421 icmp6type : STRING {
3422 const struct icmptypeent *p;
3424 if ((p = geticmptypebyname($1, AF_INET6)) ==
3426 yyerror("unknown icmp6-type %s", $1);
3434 if ($1 < 0 || $1 > 255) {
3435 yyerror("illegal icmp6-type %lu", $1);
3443 if (!strcmp($1, "lowdelay"))
3444 $$ = IPTOS_LOWDELAY;
3445 else if (!strcmp($1, "throughput"))
3446 $$ = IPTOS_THROUGHPUT;
3447 else if (!strcmp($1, "reliability"))
3448 $$ = IPTOS_RELIABILITY;
3449 else if ($1[0] == '0' && $1[1] == 'x')
3450 $$ = strtoul($1, NULL, 16);
3452 $$ = 0; /* flag bad argument */
3453 if (!$$ || $$ > 255) {
3454 yyerror("illegal tos value %s", $1);
3462 if (!$$ || $$ > 255) {
3463 yyerror("illegal tos value %s", $1);
3469 sourcetrack : SOURCETRACK { $$ = PF_SRCTRACK; }
3470 | SOURCETRACK GLOBAL { $$ = PF_SRCTRACK_GLOBAL; }
3471 | SOURCETRACK RULE { $$ = PF_SRCTRACK_RULE; }
3474 statelock : IFBOUND {
3475 $$ = PFRULE_IFBOUND;
3486 | KEEP STATE state_opt_spec {
3487 $$.action = PF_STATE_NORMAL;
3490 | MODULATE STATE state_opt_spec {
3491 $$.action = PF_STATE_MODULATE;
3494 | SYNPROXY STATE state_opt_spec {
3495 $$.action = PF_STATE_SYNPROXY;
3500 flush : /* empty */ { $$ = 0; }
3501 | FLUSH { $$ = PF_FLUSH; }
3503 $$ = PF_FLUSH | PF_FLUSH_GLOBAL;
3507 state_opt_spec : '(' state_opt_list ')' { $$ = $2; }
3508 | /* empty */ { $$ = NULL; }
3511 state_opt_list : state_opt_item { $$ = $1; }
3512 | state_opt_list comma state_opt_item {
3513 $1->tail->next = $3;
3519 state_opt_item : MAXIMUM NUMBER {
3520 if ($2 < 0 || $2 > UINT_MAX) {
3521 yyerror("only positive values permitted");
3524 $$ = calloc(1, sizeof(struct node_state_opt));
3526 err(1, "state_opt_item: calloc");
3527 $$->type = PF_STATE_OPT_MAX;
3528 $$->data.max_states = $2;
3533 $$ = calloc(1, sizeof(struct node_state_opt));
3535 err(1, "state_opt_item: calloc");
3536 $$->type = PF_STATE_OPT_NOSYNC;
3540 | MAXSRCSTATES NUMBER {
3541 if ($2 < 0 || $2 > UINT_MAX) {
3542 yyerror("only positive values permitted");
3545 $$ = calloc(1, sizeof(struct node_state_opt));
3547 err(1, "state_opt_item: calloc");
3548 $$->type = PF_STATE_OPT_MAX_SRC_STATES;
3549 $$->data.max_src_states = $2;
3553 | MAXSRCCONN NUMBER {
3554 if ($2 < 0 || $2 > 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;
3562 $$->data.max_src_conn = $2;
3566 | MAXSRCCONNRATE NUMBER '/' NUMBER {
3567 if ($2 < 0 || $2 > UINT_MAX ||
3568 $4 < 0 || $4 > UINT_MAX) {
3569 yyerror("only positive values permitted");
3572 $$ = calloc(1, sizeof(struct node_state_opt));
3574 err(1, "state_opt_item: calloc");
3575 $$->type = PF_STATE_OPT_MAX_SRC_CONN_RATE;
3576 $$->data.max_src_conn_rate.limit = $2;
3577 $$->data.max_src_conn_rate.seconds = $4;
3581 | OVERLOAD '<' STRING '>' flush {
3582 if (strlen($3) >= PF_TABLE_NAME_SIZE) {
3583 yyerror("table name '%s' too long", $3);
3587 $$ = calloc(1, sizeof(struct node_state_opt));
3589 err(1, "state_opt_item: calloc");
3590 if (strlcpy($$->data.overload.tblname, $3,
3591 PF_TABLE_NAME_SIZE) >= PF_TABLE_NAME_SIZE)
3592 errx(1, "state_opt_item: strlcpy");
3594 $$->type = PF_STATE_OPT_OVERLOAD;
3595 $$->data.overload.flush = $5;
3599 | MAXSRCNODES NUMBER {
3600 if ($2 < 0 || $2 > UINT_MAX) {
3601 yyerror("only positive values permitted");
3604 $$ = calloc(1, sizeof(struct node_state_opt));
3606 err(1, "state_opt_item: calloc");
3607 $$->type = PF_STATE_OPT_MAX_SRC_NODES;
3608 $$->data.max_src_nodes = $2;
3613 $$ = calloc(1, sizeof(struct node_state_opt));
3615 err(1, "state_opt_item: calloc");
3616 $$->type = PF_STATE_OPT_SRCTRACK;
3617 $$->data.src_track = $1;
3622 $$ = calloc(1, sizeof(struct node_state_opt));
3624 err(1, "state_opt_item: calloc");
3625 $$->type = PF_STATE_OPT_STATELOCK;
3626 $$->data.statelock = $1;
3631 $$ = calloc(1, sizeof(struct node_state_opt));
3633 err(1, "state_opt_item: calloc");
3634 $$->type = PF_STATE_OPT_SLOPPY;
3641 if ($2 < 0 || $2 > UINT_MAX) {
3642 yyerror("only positive values permitted");
3645 for (i = 0; pf_timeouts[i].name &&
3646 strcmp(pf_timeouts[i].name, $1); ++i)
3648 if (!pf_timeouts[i].name) {
3649 yyerror("illegal timeout name %s", $1);
3653 if (strchr(pf_timeouts[i].name, '.') == NULL) {
3654 yyerror("illegal state timeout %s", $1);
3659 $$ = calloc(1, sizeof(struct node_state_opt));
3661 err(1, "state_opt_item: calloc");
3662 $$->type = PF_STATE_OPT_TIMEOUT;
3663 $$->data.timeout.number = pf_timeouts[i].timeout;
3664 $$->data.timeout.seconds = $2;
3670 label : LABEL STRING {
3675 qname : QUEUE STRING {
3679 | QUEUE '(' STRING ')' {
3683 | QUEUE '(' STRING comma STRING ')' {
3689 no : /* empty */ { $$ = 0; }
3693 portstar : numberstring {
3694 if (parseport($1, &$$, PPORT_RANGE|PPORT_STAR) == -1) {
3702 redirspec : host { $$ = $1; }
3703 | '{' optnl redir_host_list '}' { $$ = $3; }
3706 redir_host_list : host optnl { $$ = $1; }
3707 | redir_host_list comma host optnl {
3708 $1->tail->next = $3;
3709 $1->tail = $3->tail;
3714 redirpool : /* empty */ { $$ = NULL; }
3716 $$ = calloc(1, sizeof(struct redirection));
3718 err(1, "redirection: calloc");
3720 $$->rport.a = $$->rport.b = $$->rport.t = 0;
3722 | ARROW redirspec PORT portstar {
3723 $$ = calloc(1, sizeof(struct redirection));
3725 err(1, "redirection: calloc");
3731 hashkey : /* empty */
3733 $$ = calloc(1, sizeof(struct pf_poolhashkey));
3735 err(1, "hashkey: calloc");
3736 $$->key32[0] = arc4random();
3737 $$->key32[1] = arc4random();
3738 $$->key32[2] = arc4random();
3739 $$->key32[3] = arc4random();
3743 if (!strncmp($1, "0x", 2)) {
3744 if (strlen($1) != 34) {
3746 yyerror("hex key must be 128 bits "
3747 "(32 hex digits) long");
3750 $$ = calloc(1, sizeof(struct pf_poolhashkey));
3752 err(1, "hashkey: calloc");
3754 if (sscanf($1, "0x%8x%8x%8x%8x",
3755 &$$->key32[0], &$$->key32[1],
3756 &$$->key32[2], &$$->key32[3]) != 4) {
3759 yyerror("invalid hex key");
3765 $$ = calloc(1, sizeof(struct pf_poolhashkey));
3767 err(1, "hashkey: calloc");
3769 MD5Update(&context, (unsigned char *)$1,
3771 MD5Final((unsigned char *)$$, &context);
3772 HTONL($$->key32[0]);
3773 HTONL($$->key32[1]);
3774 HTONL($$->key32[2]);
3775 HTONL($$->key32[3]);
3781 pool_opts : { bzero(&pool_opts, sizeof pool_opts); }
3785 bzero(&pool_opts, sizeof pool_opts);
3790 pool_opts_l : pool_opts_l pool_opt
3794 pool_opt : BITMASK {
3795 if (pool_opts.type) {
3796 yyerror("pool type cannot be redefined");
3799 pool_opts.type = PF_POOL_BITMASK;
3802 if (pool_opts.type) {
3803 yyerror("pool type cannot be redefined");
3806 pool_opts.type = PF_POOL_RANDOM;
3808 | SOURCEHASH hashkey {
3809 if (pool_opts.type) {
3810 yyerror("pool type cannot be redefined");
3813 pool_opts.type = PF_POOL_SRCHASH;
3817 if (pool_opts.type) {
3818 yyerror("pool type cannot be redefined");
3821 pool_opts.type = PF_POOL_ROUNDROBIN;
3824 if (pool_opts.staticport) {
3825 yyerror("static-port cannot be redefined");
3828 pool_opts.staticport = 1;
3831 if (filter_opts.marker & POM_STICKYADDRESS) {
3832 yyerror("sticky-address cannot be redefined");
3835 pool_opts.marker |= POM_STICKYADDRESS;
3836 pool_opts.opts |= PF_POOL_STICKYADDR;
3840 redirection : /* empty */ { $$ = NULL; }
3842 $$ = calloc(1, sizeof(struct redirection));
3844 err(1, "redirection: calloc");
3846 $$->rport.a = $$->rport.b = $$->rport.t = 0;
3848 | ARROW host PORT portstar {
3849 $$ = calloc(1, sizeof(struct redirection));
3851 err(1, "redirection: calloc");
3857 natpasslog : /* empty */ { $$.b1 = $$.b2 = 0; $$.w2 = 0; }
3858 | PASS { $$.b1 = 1; $$.b2 = 0; $$.w2 = 0; }
3859 | PASS log { $$.b1 = 1; $$.b2 = $2.log; $$.w2 = $2.logif; }
3860 | log { $$.b1 = 0; $$.b2 = $1.log; $$.w2 = $1.logif; }
3863 nataction : no NAT natpasslog {
3865 yyerror("\"pass\" not valid with \"no\"");
3876 | no RDR natpasslog {
3878 yyerror("\"pass\" not valid with \"no\"");
3891 natrule : nataction interface af proto fromto tag tagged rtable
3896 if (check_rulestate(PFCTL_STATE_NAT))
3899 memset(&r, 0, sizeof(r));
3908 if ($5.src.host && $5.src.host->af &&
3909 !$5.src.host->ifindex)
3910 r.af = $5.src.host->af;
3911 else if ($5.dst.host && $5.dst.host->af &&
3912 !$5.dst.host->ifindex)
3913 r.af = $5.dst.host->af;
3917 if (strlcpy(r.tagname, $6, PF_TAG_NAME_SIZE) >=
3919 yyerror("tag too long, max %u chars",
3920 PF_TAG_NAME_SIZE - 1);
3925 if (strlcpy(r.match_tagname, $7.name,
3926 PF_TAG_NAME_SIZE) >= PF_TAG_NAME_SIZE) {
3927 yyerror("tag too long, max %u chars",
3928 PF_TAG_NAME_SIZE - 1);
3931 r.match_tag_not = $7.neg;
3934 if (r.action == PF_NONAT || r.action == PF_NORDR) {
3936 yyerror("translation rule with 'no' "
3937 "does not need '->'");
3941 if ($9 == NULL || $9->host == NULL) {
3942 yyerror("translation rule requires '-> "
3946 if (!r.af && ! $9->host->ifindex)
3947 r.af = $9->host->af;
3949 remove_invalid_hosts(&$9->host, &r.af);
3950 if (invalid_redirect($9->host, r.af))
3952 if (check_netmask($9->host, r.af))
3955 r.rpool.proxy_port[0] = ntohs($9->rport.a);
3959 if (!$9->rport.b && $9->rport.t &&
3960 $5.dst.port != NULL) {
3961 r.rpool.proxy_port[1] =
3962 ntohs($9->rport.a) +
3964 $5.dst.port->port[1]) -
3966 $5.dst.port->port[0]));
3968 r.rpool.proxy_port[1] =
3972 r.rpool.proxy_port[1] =
3974 if (!r.rpool.proxy_port[0] &&
3975 !r.rpool.proxy_port[1]) {
3976 r.rpool.proxy_port[0] =
3977 PF_NAT_PROXY_PORT_LOW;
3978 r.rpool.proxy_port[1] =
3979 PF_NAT_PROXY_PORT_HIGH;
3980 } else if (!r.rpool.proxy_port[1])
3981 r.rpool.proxy_port[1] =
3982 r.rpool.proxy_port[0];
3988 r.rpool.opts = $10.type;
3989 if ((r.rpool.opts & PF_POOL_TYPEMASK) ==
3990 PF_POOL_NONE && ($9->host->next != NULL ||
3991 $9->host->addr.type == PF_ADDR_TABLE ||
3992 DYNIF_MULTIADDR($9->host->addr)))
3993 r.rpool.opts = PF_POOL_ROUNDROBIN;
3994 if ((r.rpool.opts & PF_POOL_TYPEMASK) !=
3995 PF_POOL_ROUNDROBIN &&
3996 disallow_table($9->host, "tables are only "
3997 "supported in round-robin redirection "
4000 if ((r.rpool.opts & PF_POOL_TYPEMASK) !=
4001 PF_POOL_ROUNDROBIN &&
4002 disallow_alias($9->host, "interface (%s) "
4003 "is only supported in round-robin "
4004 "redirection pools"))
4006 if ($9->host->next != NULL) {
4007 if ((r.rpool.opts & PF_POOL_TYPEMASK) !=
4008 PF_POOL_ROUNDROBIN) {
4009 yyerror("only round-robin "
4010 "valid for multiple "
4011 "redirection addresses");
4017 if ($10.key != NULL)
4018 memcpy(&r.rpool.key, $10.key,
4019 sizeof(struct pf_poolhashkey));
4022 r.rpool.opts |= $10.opts;
4024 if ($10.staticport) {
4025 if (r.action != PF_NAT) {
4026 yyerror("the 'static-port' option is "
4027 "only valid with nat rules");
4030 if (r.rpool.proxy_port[0] !=
4031 PF_NAT_PROXY_PORT_LOW &&
4032 r.rpool.proxy_port[1] !=
4033 PF_NAT_PROXY_PORT_HIGH) {
4034 yyerror("the 'static-port' option can't"
4035 " be used when specifying a port"
4039 r.rpool.proxy_port[0] = 0;
4040 r.rpool.proxy_port[1] = 0;
4043 expand_rule(&r, $2, $9 == NULL ? NULL : $9->host, $4,
4044 $5.src_os, $5.src.host, $5.src.port, $5.dst.host,
4045 $5.dst.port, 0, 0, 0, "");
4050 binatrule : no BINAT natpasslog interface af proto FROM host toipspec tag
4051 tagged rtable redirection
4053 struct pf_rule binat;
4054 struct pf_pooladdr *pa;
4056 if (check_rulestate(PFCTL_STATE_NAT))
4058 if (disallow_urpf_failed($9, "\"urpf-failed\" is not "
4059 "permitted as a binat destination"))
4062 memset(&binat, 0, sizeof(binat));
4065 yyerror("\"pass\" not valid with \"no\"");
4069 binat.action = PF_NOBINAT;
4071 binat.action = PF_BINAT;
4072 binat.natpass = $3.b1;
4074 binat.logif = $3.w2;
4076 if (!binat.af && $8 != NULL && $8->af)
4078 if (!binat.af && $9 != NULL && $9->af)
4081 if (!binat.af && $13 != NULL && $13->host)
4082 binat.af = $13->host->af;
4084 yyerror("address family (inet/inet6) "
4090 memcpy(binat.ifname, $4->ifname,
4091 sizeof(binat.ifname));
4092 binat.ifnot = $4->not;
4097 if (strlcpy(binat.tagname, $10,
4098 PF_TAG_NAME_SIZE) >= PF_TAG_NAME_SIZE) {
4099 yyerror("tag too long, max %u chars",
4100 PF_TAG_NAME_SIZE - 1);
4104 if (strlcpy(binat.match_tagname, $11.name,
4105 PF_TAG_NAME_SIZE) >= PF_TAG_NAME_SIZE) {
4106 yyerror("tag too long, max %u chars",
4107 PF_TAG_NAME_SIZE - 1);
4110 binat.match_tag_not = $11.neg;
4111 binat.rtableid = $12;
4114 binat.proto = $6->proto;
4118 if ($8 != NULL && disallow_table($8, "invalid use of "
4119 "table <%s> as the source address of a binat rule"))
4121 if ($8 != NULL && disallow_alias($8, "invalid use of "
4122 "interface (%s) as the source address of a binat "
4125 if ($13 != NULL && $13->host != NULL && disallow_table(
4126 $13->host, "invalid use of table <%s> as the "
4127 "redirect address of a binat rule"))
4129 if ($13 != NULL && $13->host != NULL && disallow_alias(
4130 $13->host, "invalid use of interface (%s) as the "
4131 "redirect address of a binat rule"))
4136 yyerror("multiple binat ip addresses");
4139 if ($8->addr.type == PF_ADDR_DYNIFTL)
4141 if ($8->af != binat.af) {
4142 yyerror("binat ip versions must match");
4145 if (check_netmask($8, binat.af))
4147 memcpy(&binat.src.addr, &$8->addr,
4148 sizeof(binat.src.addr));
4153 yyerror("multiple binat ip addresses");
4156 if ($9->af != binat.af && $9->af) {
4157 yyerror("binat ip versions must match");
4160 if (check_netmask($9, binat.af))
4162 memcpy(&binat.dst.addr, &$9->addr,
4163 sizeof(binat.dst.addr));
4164 binat.dst.neg = $9->not;
4168 if (binat.action == PF_NOBINAT) {
4170 yyerror("'no binat' rule does not need"
4175 if ($13 == NULL || $13->host == NULL) {
4176 yyerror("'binat' rule requires"
4181 remove_invalid_hosts(&$13->host, &binat.af);
4182 if (invalid_redirect($13->host, binat.af))
4184 if ($13->host->next != NULL) {
4185 yyerror("binat rule must redirect to "
4186 "a single address");
4189 if (check_netmask($13->host, binat.af))
4192 if (!PF_AZERO(&binat.src.addr.v.a.mask,
4194 !PF_AEQ(&binat.src.addr.v.a.mask,
4195 &$13->host->addr.v.a.mask, binat.af)) {
4196 yyerror("'binat' source mask and "
4197 "redirect mask must be the same");
4201 TAILQ_INIT(&binat.rpool.list);
4202 pa = calloc(1, sizeof(struct pf_pooladdr));
4204 err(1, "binat: calloc");
4205 pa->addr = $13->host->addr;
4207 TAILQ_INSERT_TAIL(&binat.rpool.list,
4213 pfctl_add_rule(pf, &binat, "");
4217 tag : /* empty */ { $$ = NULL; }
4218 | TAG STRING { $$ = $2; }
4221 tagged : /* empty */ { $$.neg = 0; $$.name = NULL; }
4222 | not TAGGED string { $$.neg = $1; $$.name = $3; }
4225 rtable : /* empty */ { $$ = -1; }
4227 if ($2 < 0 || $2 > rt_tableid_max()) {
4228 yyerror("invalid rtable id");
4235 route_host : STRING {
4236 $$ = calloc(1, sizeof(struct node_host));
4238 err(1, "route_host: calloc");
4240 set_ipmask($$, 128);
4244 | '(' STRING host ')' {
4250 route_host_list : route_host optnl { $$ = $1; }
4251 | route_host_list comma route_host optnl {
4254 if ($1->af != $3->af) {
4255 yyerror("all pool addresses must be in the "
4256 "same address family");
4259 $1->tail->next = $3;
4260 $1->tail = $3->tail;
4265 routespec : route_host { $$ = $1; }
4266 | '{' optnl route_host_list '}' { $$ = $3; }
4269 route : /* empty */ {
4276 $$.rt = PF_FASTROUTE;
4279 | ROUTETO routespec pool_opts {
4282 $$.pool_opts = $3.type | $3.opts;
4286 | REPLYTO routespec pool_opts {
4289 $$.pool_opts = $3.type | $3.opts;
4293 | DUPTO routespec pool_opts {
4296 $$.pool_opts = $3.type | $3.opts;
4302 timeout_spec : STRING NUMBER
4304 if (check_rulestate(PFCTL_STATE_OPTION)) {
4308 if ($2 < 0 || $2 > UINT_MAX) {
4309 yyerror("only positive values permitted");
4312 if (pfctl_set_timeout(pf, $1, $2, 0) != 0) {
4313 yyerror("unknown timeout %s", $1);
4321 timeout_list : timeout_list comma timeout_spec optnl
4322 | timeout_spec optnl
4325 limit_spec : STRING NUMBER
4327 if (check_rulestate(PFCTL_STATE_OPTION)) {
4331 if ($2 < 0 || $2 > UINT_MAX) {
4332 yyerror("only positive values permitted");
4335 if (pfctl_set_limit(pf, $1, $2) != 0) {
4336 yyerror("unable to set limit %s %u", $1, $2);
4344 limit_list : limit_list comma limit_spec optnl
4352 yesno : NO { $$ = 0; }
4354 if (!strcmp($1, "yes"))
4357 yyerror("invalid value '%s', expected 'yes' "
4366 unaryop : '=' { $$ = PF_OP_EQ; }
4367 | '!' '=' { $$ = PF_OP_NE; }
4368 | '<' '=' { $$ = PF_OP_LE; }
4369 | '<' { $$ = PF_OP_LT; }
4370 | '>' '=' { $$ = PF_OP_GE; }
4371 | '>' { $$ = PF_OP_GT; }
4377 yyerror(const char *fmt, ...)
4383 fprintf(stderr, "%s:%d: ", file->name, yylval.lineno);
4384 vfprintf(stderr, fmt, ap);
4385 fprintf(stderr, "\n");
4391 disallow_table(struct node_host *h, const char *fmt)
4393 for (; h != NULL; h = h->next)
4394 if (h->addr.type == PF_ADDR_TABLE) {
4395 yyerror(fmt, h->addr.v.tblname);
4402 disallow_urpf_failed(struct node_host *h, const char *fmt)
4404 for (; h != NULL; h = h->next)
4405 if (h->addr.type == PF_ADDR_URPFFAILED) {
4413 disallow_alias(struct node_host *h, const char *fmt)
4415 for (; h != NULL; h = h->next)
4416 if (DYNIF_MULTIADDR(h->addr)) {
4417 yyerror(fmt, h->addr.v.tblname);
4424 rule_consistent(struct pf_rule *r, int anchor_call)
4428 switch (r->action) {
4433 problems = filter_consistent(r, anchor_call);
4437 problems = nat_consistent(r);
4441 problems = rdr_consistent(r);
4452 filter_consistent(struct pf_rule *r, int anchor_call)
4456 if (r->proto != IPPROTO_TCP && r->proto != IPPROTO_UDP &&
4457 (r->src.port_op || r->dst.port_op)) {
4458 yyerror("port only applies to tcp/udp");
4461 if (r->proto != IPPROTO_ICMP && r->proto != IPPROTO_ICMPV6 &&
4462 (r->type || r->code)) {
4463 yyerror("icmp-type/code only applies to icmp");
4466 if (!r->af && (r->type || r->code)) {
4467 yyerror("must indicate address family with icmp-type/code");
4470 if (r->overload_tblname[0] &&
4471 r->max_src_conn == 0 && r->max_src_conn_rate.seconds == 0) {
4472 yyerror("'overload' requires 'max-src-conn' "
4473 "or 'max-src-conn-rate'");
4476 if ((r->proto == IPPROTO_ICMP && r->af == AF_INET6) ||
4477 (r->proto == IPPROTO_ICMPV6 && r->af == AF_INET)) {
4478 yyerror("proto %s doesn't match address family %s",
4479 r->proto == IPPROTO_ICMP ? "icmp" : "icmp6",
4480 r->af == AF_INET ? "inet" : "inet6");
4483 if (r->allow_opts && r->action != PF_PASS) {
4484 yyerror("allow-opts can only be specified for pass rules");
4487 if (r->rule_flag & PFRULE_FRAGMENT && (r->src.port_op ||
4488 r->dst.port_op || r->flagset || r->type || r->code)) {
4489 yyerror("fragments can be filtered only on IP header fields");
4492 if (r->rule_flag & PFRULE_RETURNRST && r->proto != IPPROTO_TCP) {
4493 yyerror("return-rst can only be applied to TCP rules");
4496 if (r->max_src_nodes && !(r->rule_flag & PFRULE_RULESRCTRACK)) {
4497 yyerror("max-src-nodes requires 'source-track rule'");
4500 if (r->action == PF_DROP && r->keep_state) {
4501 yyerror("keep state on block rules doesn't make sense");
4504 if (r->rule_flag & PFRULE_STATESLOPPY &&
4505 (r->keep_state == PF_STATE_MODULATE ||
4506 r->keep_state == PF_STATE_SYNPROXY)) {
4507 yyerror("sloppy state matching cannot be used with "
4508 "synproxy state or modulate state");
4515 nat_consistent(struct pf_rule *r)
4517 return (0); /* yeah! */
4521 rdr_consistent(struct pf_rule *r)
4525 if (r->proto != IPPROTO_TCP && r->proto != IPPROTO_UDP) {
4526 if (r->src.port_op) {
4527 yyerror("src port only applies to tcp/udp");
4530 if (r->dst.port_op) {
4531 yyerror("dst port only applies to tcp/udp");
4534 if (r->rpool.proxy_port[0]) {
4535 yyerror("rpool port only applies to tcp/udp");
4539 if (r->dst.port_op &&
4540 r->dst.port_op != PF_OP_EQ && r->dst.port_op != PF_OP_RRG) {
4541 yyerror("invalid port operator for rdr destination port");
4548 process_tabledef(char *name, struct table_opts *opts)
4550 struct pfr_buffer ab;
4551 struct node_tinit *ti;
4553 bzero(&ab, sizeof(ab));
4554 ab.pfrb_type = PFRB_ADDRS;
4555 SIMPLEQ_FOREACH(ti, &opts->init_nodes, entries) {
4557 if (pfr_buf_load(&ab, ti->file, 0, append_addr)) {
4559 yyerror("cannot load \"%s\": %s",
4560 ti->file, strerror(errno));
4562 yyerror("file \"%s\" contains bad data",
4567 if (append_addr_host(&ab, ti->host, 0, 0)) {
4568 yyerror("cannot create address buffer: %s",
4573 if (pf->opts & PF_OPT_VERBOSE)
4574 print_tabledef(name, opts->flags, opts->init_addr,
4576 if (!(pf->opts & PF_OPT_NOACTION) &&
4577 pfctl_define_table(name, opts->flags, opts->init_addr,
4578 pf->anchor->name, &ab, pf->anchor->ruleset.tticket)) {
4579 yyerror("cannot define table %s: %s", name,
4580 pfr_strerror(errno));
4596 /* macro gore, but you should've seen the prior indentation nightmare... */
4598 #define FREE_LIST(T,r) \
4601 while (node != NULL) { \
4603 node = node->next; \
4608 #define LOOP_THROUGH(T,n,r,C) \
4612 r = calloc(1, sizeof(T)); \
4614 err(1, "LOOP: calloc"); \
4618 while (n != NULL) { \
4627 expand_label_str(char *label, size_t len, const char *srch, const char *repl)
4632 if ((tmp = calloc(1, len)) == NULL)
4633 err(1, "expand_label_str: calloc");
4635 while ((q = strstr(p, srch)) != NULL) {
4637 if ((strlcat(tmp, p, len) >= len) ||
4638 (strlcat(tmp, repl, len) >= len))
4639 errx(1, "expand_label: label too long");
4643 if (strlcat(tmp, p, len) >= len)
4644 errx(1, "expand_label: label too long");
4645 strlcpy(label, tmp, len); /* always fits */
4650 expand_label_if(const char *name, char *label, size_t len, const char *ifname)
4652 if (strstr(label, name) != NULL) {
4654 expand_label_str(label, len, name, "any");
4656 expand_label_str(label, len, name, ifname);
4661 expand_label_addr(const char *name, char *label, size_t len, sa_family_t af,
4662 struct node_host *h)
4664 char tmp[64], tmp_not[66];
4666 if (strstr(label, name) != NULL) {
4667 switch (h->addr.type) {
4668 case PF_ADDR_DYNIFTL:
4669 snprintf(tmp, sizeof(tmp), "(%s)", h->addr.v.ifname);
4672 snprintf(tmp, sizeof(tmp), "<%s>", h->addr.v.tblname);
4674 case PF_ADDR_NOROUTE:
4675 snprintf(tmp, sizeof(tmp), "no-route");
4677 case PF_ADDR_URPFFAILED:
4678 snprintf(tmp, sizeof(tmp), "urpf-failed");
4680 case PF_ADDR_ADDRMASK:
4681 if (!af || (PF_AZERO(&h->addr.v.a.addr, af) &&
4682 PF_AZERO(&h->addr.v.a.mask, af)))
4683 snprintf(tmp, sizeof(tmp), "any");
4688 if (inet_ntop(af, &h->addr.v.a.addr, a,
4690 snprintf(tmp, sizeof(tmp), "?");
4692 bits = unmask(&h->addr.v.a.mask, af);
4693 if ((af == AF_INET && bits < 32) ||
4694 (af == AF_INET6 && bits < 128))
4695 snprintf(tmp, sizeof(tmp),
4698 snprintf(tmp, sizeof(tmp),
4704 snprintf(tmp, sizeof(tmp), "?");
4709 snprintf(tmp_not, sizeof(tmp_not), "! %s", tmp);
4710 expand_label_str(label, len, name, tmp_not);
4712 expand_label_str(label, len, name, tmp);
4717 expand_label_port(const char *name, char *label, size_t len,
4718 struct node_port *port)
4720 char a1[6], a2[6], op[13] = "";
4722 if (strstr(label, name) != NULL) {
4723 snprintf(a1, sizeof(a1), "%u", ntohs(port->port[0]));
4724 snprintf(a2, sizeof(a2), "%u", ntohs(port->port[1]));
4727 else if (port->op == PF_OP_IRG)
4728 snprintf(op, sizeof(op), "%s><%s", a1, a2);
4729 else if (port->op == PF_OP_XRG)
4730 snprintf(op, sizeof(op), "%s<>%s", a1, a2);
4731 else if (port->op == PF_OP_EQ)
4732 snprintf(op, sizeof(op), "%s", a1);
4733 else if (port->op == PF_OP_NE)
4734 snprintf(op, sizeof(op), "!=%s", a1);
4735 else if (port->op == PF_OP_LT)
4736 snprintf(op, sizeof(op), "<%s", a1);
4737 else if (port->op == PF_OP_LE)
4738 snprintf(op, sizeof(op), "<=%s", a1);
4739 else if (port->op == PF_OP_GT)
4740 snprintf(op, sizeof(op), ">%s", a1);
4741 else if (port->op == PF_OP_GE)
4742 snprintf(op, sizeof(op), ">=%s", a1);
4743 expand_label_str(label, len, name, op);
4748 expand_label_proto(const char *name, char *label, size_t len, u_int8_t proto)
4750 struct protoent *pe;
4753 if (strstr(label, name) != NULL) {
4754 pe = getprotobynumber(proto);
4756 expand_label_str(label, len, name, pe->p_name);
4758 snprintf(n, sizeof(n), "%u", proto);
4759 expand_label_str(label, len, name, n);
4765 expand_label_nr(const char *name, char *label, size_t len)
4769 if (strstr(label, name) != NULL) {
4770 snprintf(n, sizeof(n), "%u", pf->anchor->match);
4771 expand_label_str(label, len, name, n);
4776 expand_label(char *label, size_t len, const char *ifname, sa_family_t af,
4777 struct node_host *src_host, struct node_port *src_port,
4778 struct node_host *dst_host, struct node_port *dst_port,
4781 expand_label_if("$if", label, len, ifname);
4782 expand_label_addr("$srcaddr", label, len, af, src_host);
4783 expand_label_addr("$dstaddr", label, len, af, dst_host);
4784 expand_label_port("$srcport", label, len, src_port);
4785 expand_label_port("$dstport", label, len, dst_port);
4786 expand_label_proto("$proto", label, len, proto);
4787 expand_label_nr("$nr", label, len);
4791 expand_altq(struct pf_altq *a, struct node_if *interfaces,
4792 struct node_queue *nqueues, struct node_queue_bw bwspec,
4793 struct node_queue_opt *opts)
4795 struct pf_altq pa, pb;
4796 char qname[PF_QNAME_SIZE];
4797 struct node_queue *n;
4798 struct node_queue_bw bw;
4801 if ((pf->loadopt & PFCTL_FLAG_ALTQ) == 0) {
4802 FREE_LIST(struct node_if, interfaces);
4803 FREE_LIST(struct node_queue, nqueues);
4807 LOOP_THROUGH(struct node_if, interface, interfaces,
4808 memcpy(&pa, a, sizeof(struct pf_altq));
4809 if (strlcpy(pa.ifname, interface->ifname,
4810 sizeof(pa.ifname)) >= sizeof(pa.ifname))
4811 errx(1, "expand_altq: strlcpy");
4813 if (interface->not) {
4814 yyerror("altq on ! <interface> is not supported");
4817 if (eval_pfaltq(pf, &pa, &bwspec, opts))
4820 if (pfctl_add_altq(pf, &pa))
4823 if (pf->opts & PF_OPT_VERBOSE) {
4824 print_altq(&pf->paltq->altq, 0,
4826 if (nqueues && nqueues->tail) {
4828 LOOP_THROUGH(struct node_queue, queue,
4838 if (pa.scheduler == ALTQT_CBQ ||
4839 pa.scheduler == ALTQT_HFSC) {
4840 /* now create a root queue */
4841 memset(&pb, 0, sizeof(struct pf_altq));
4842 if (strlcpy(qname, "root_", sizeof(qname)) >=
4844 errx(1, "expand_altq: strlcpy");
4845 if (strlcat(qname, interface->ifname,
4846 sizeof(qname)) >= sizeof(qname))
4847 errx(1, "expand_altq: strlcat");
4848 if (strlcpy(pb.qname, qname,
4849 sizeof(pb.qname)) >= sizeof(pb.qname))
4850 errx(1, "expand_altq: strlcpy");
4851 if (strlcpy(pb.ifname, interface->ifname,
4852 sizeof(pb.ifname)) >= sizeof(pb.ifname))
4853 errx(1, "expand_altq: strlcpy");
4854 pb.qlimit = pa.qlimit;
4855 pb.scheduler = pa.scheduler;
4856 bw.bw_absolute = pa.ifbandwidth;
4858 if (eval_pfqueue(pf, &pb, &bw, opts))
4861 if (pfctl_add_altq(pf, &pb))
4865 LOOP_THROUGH(struct node_queue, queue, nqueues,
4866 n = calloc(1, sizeof(struct node_queue));
4868 err(1, "expand_altq: calloc");
4869 if (pa.scheduler == ALTQT_CBQ ||
4870 pa.scheduler == ALTQT_HFSC)
4871 if (strlcpy(n->parent, qname,
4872 sizeof(n->parent)) >=
4874 errx(1, "expand_altq: strlcpy");
4875 if (strlcpy(n->queue, queue->queue,
4876 sizeof(n->queue)) >= sizeof(n->queue))
4877 errx(1, "expand_altq: strlcpy");
4878 if (strlcpy(n->ifname, interface->ifname,
4879 sizeof(n->ifname)) >= sizeof(n->ifname))
4880 errx(1, "expand_altq: strlcpy");
4881 n->scheduler = pa.scheduler;
4887 queues->tail->next = n;
4893 FREE_LIST(struct node_if, interfaces);
4894 FREE_LIST(struct node_queue, nqueues);
4900 expand_queue(struct pf_altq *a, struct node_if *interfaces,
4901 struct node_queue *nqueues, struct node_queue_bw bwspec,
4902 struct node_queue_opt *opts)
4904 struct node_queue *n, *nq;
4909 if ((pf->loadopt & PFCTL_FLAG_ALTQ) == 0) {
4910 FREE_LIST(struct node_queue, nqueues);
4914 if (queues == NULL) {
4915 yyerror("queue %s has no parent", a->qname);
4916 FREE_LIST(struct node_queue, nqueues);
4920 LOOP_THROUGH(struct node_if, interface, interfaces,
4921 LOOP_THROUGH(struct node_queue, tqueue, queues,
4922 if (!strncmp(a->qname, tqueue->queue, PF_QNAME_SIZE) &&
4923 (interface->ifname[0] == 0 ||
4924 (!interface->not && !strncmp(interface->ifname,
4925 tqueue->ifname, IFNAMSIZ)) ||
4926 (interface->not && strncmp(interface->ifname,
4927 tqueue->ifname, IFNAMSIZ)))) {
4928 /* found ourself in queues */
4931 memcpy(&pa, a, sizeof(struct pf_altq));
4933 if (pa.scheduler != ALTQT_NONE &&
4934 pa.scheduler != tqueue->scheduler) {
4935 yyerror("exactly one scheduler type "
4936 "per interface allowed");
4939 pa.scheduler = tqueue->scheduler;
4941 /* scheduler dependent error checking */
4942 switch (pa.scheduler) {
4944 if (nqueues != NULL) {
4945 yyerror("priq queues cannot "
4946 "have child queues");
4949 if (bwspec.bw_absolute > 0 ||
4950 bwspec.bw_percent < 100) {
4951 yyerror("priq doesn't take "
4960 if (strlcpy(pa.ifname, tqueue->ifname,
4961 sizeof(pa.ifname)) >= sizeof(pa.ifname))
4962 errx(1, "expand_queue: strlcpy");
4963 if (strlcpy(pa.parent, tqueue->parent,
4964 sizeof(pa.parent)) >= sizeof(pa.parent))
4965 errx(1, "expand_queue: strlcpy");
4967 if (eval_pfqueue(pf, &pa, &bwspec, opts))
4970 if (pfctl_add_altq(pf, &pa))
4973 for (nq = nqueues; nq != NULL; nq = nq->next) {
4974 if (!strcmp(a->qname, nq->queue)) {
4975 yyerror("queue cannot have "
4981 sizeof(struct node_queue));
4983 err(1, "expand_queue: calloc");
4984 if (strlcpy(n->parent, a->qname,
4985 sizeof(n->parent)) >=
4987 errx(1, "expand_queue strlcpy");
4988 if (strlcpy(n->queue, nq->queue,
4989 sizeof(n->queue)) >=
4991 errx(1, "expand_queue strlcpy");
4992 if (strlcpy(n->ifname, tqueue->ifname,
4993 sizeof(n->ifname)) >=
4995 errx(1, "expand_queue strlcpy");
4996 n->scheduler = tqueue->scheduler;
5002 queues->tail->next = n;
5006 if ((pf->opts & PF_OPT_VERBOSE) && (
5007 (found == 1 && interface->ifname[0] == 0) ||
5008 (found > 0 && interface->ifname[0] != 0))) {
5009 print_queue(&pf->paltq->altq, 0,
5010 &bwspec, interface->ifname[0] != 0,
5012 if (nqueues && nqueues->tail) {
5014 LOOP_THROUGH(struct node_queue,
5027 FREE_LIST(struct node_queue, nqueues);
5028 FREE_LIST(struct node_if, interfaces);
5031 yyerror("queue %s has no parent", a->qname);
5042 expand_rule(struct pf_rule *r,
5043 struct node_if *interfaces, struct node_host *rpool_hosts,
5044 struct node_proto *protos, struct node_os *src_oses,
5045 struct node_host *src_hosts, struct node_port *src_ports,
5046 struct node_host *dst_hosts, struct node_port *dst_ports,
5047 struct node_uid *uids, struct node_gid *gids, struct node_icmp *icmp_types,
5048 const char *anchor_call)
5050 sa_family_t af = r->af;
5051 int added = 0, error = 0;
5052 char ifname[IF_NAMESIZE];
5053 char label[PF_RULE_LABEL_SIZE];
5054 char tagname[PF_TAG_NAME_SIZE];
5055 char match_tagname[PF_TAG_NAME_SIZE];
5056 struct pf_pooladdr *pa;
5057 struct node_host *h;
5058 u_int8_t flags, flagset, keep_state;
5060 if (strlcpy(label, r->label, sizeof(label)) >= sizeof(label))
5061 errx(1, "expand_rule: strlcpy");
5062 if (strlcpy(tagname, r->tagname, sizeof(tagname)) >= sizeof(tagname))
5063 errx(1, "expand_rule: strlcpy");
5064 if (strlcpy(match_tagname, r->match_tagname, sizeof(match_tagname)) >=
5065 sizeof(match_tagname))
5066 errx(1, "expand_rule: strlcpy");
5068 flagset = r->flagset;
5069 keep_state = r->keep_state;
5071 LOOP_THROUGH(struct node_if, interface, interfaces,
5072 LOOP_THROUGH(struct node_proto, proto, protos,
5073 LOOP_THROUGH(struct node_icmp, icmp_type, icmp_types,
5074 LOOP_THROUGH(struct node_host, src_host, src_hosts,
5075 LOOP_THROUGH(struct node_port, src_port, src_ports,
5076 LOOP_THROUGH(struct node_os, src_os, src_oses,
5077 LOOP_THROUGH(struct node_host, dst_host, dst_hosts,
5078 LOOP_THROUGH(struct node_port, dst_port, dst_ports,
5079 LOOP_THROUGH(struct node_uid, uid, uids,
5080 LOOP_THROUGH(struct node_gid, gid, gids,
5083 /* for link-local IPv6 address, interface must match up */
5084 if ((r->af && src_host->af && r->af != src_host->af) ||
5085 (r->af && dst_host->af && r->af != dst_host->af) ||
5086 (src_host->af && dst_host->af &&
5087 src_host->af != dst_host->af) ||
5088 (src_host->ifindex && dst_host->ifindex &&
5089 src_host->ifindex != dst_host->ifindex) ||
5090 (src_host->ifindex && *interface->ifname &&
5091 src_host->ifindex != if_nametoindex(interface->ifname)) ||
5092 (dst_host->ifindex && *interface->ifname &&
5093 dst_host->ifindex != if_nametoindex(interface->ifname)))
5095 if (!r->af && src_host->af)
5096 r->af = src_host->af;
5097 else if (!r->af && dst_host->af)
5098 r->af = dst_host->af;
5100 if (*interface->ifname)
5101 strlcpy(r->ifname, interface->ifname,
5103 else if (if_indextoname(src_host->ifindex, ifname))
5104 strlcpy(r->ifname, ifname, sizeof(r->ifname));
5105 else if (if_indextoname(dst_host->ifindex, ifname))
5106 strlcpy(r->ifname, ifname, sizeof(r->ifname));
5108 memset(r->ifname, '\0', sizeof(r->ifname));
5110 if (strlcpy(r->label, label, sizeof(r->label)) >=
5112 errx(1, "expand_rule: strlcpy");
5113 if (strlcpy(r->tagname, tagname, sizeof(r->tagname)) >=
5115 errx(1, "expand_rule: strlcpy");
5116 if (strlcpy(r->match_tagname, match_tagname,
5117 sizeof(r->match_tagname)) >= sizeof(r->match_tagname))
5118 errx(1, "expand_rule: strlcpy");
5119 expand_label(r->label, PF_RULE_LABEL_SIZE, r->ifname, r->af,
5120 src_host, src_port, dst_host, dst_port, proto->proto);
5121 expand_label(r->tagname, PF_TAG_NAME_SIZE, r->ifname, r->af,
5122 src_host, src_port, dst_host, dst_port, proto->proto);
5123 expand_label(r->match_tagname, PF_TAG_NAME_SIZE, r->ifname,
5124 r->af, src_host, src_port, dst_host, dst_port,
5127 error += check_netmask(src_host, r->af);
5128 error += check_netmask(dst_host, r->af);
5130 r->ifnot = interface->not;
5131 r->proto = proto->proto;
5132 r->src.addr = src_host->addr;
5133 r->src.neg = src_host->not;
5134 r->src.port[0] = src_port->port[0];
5135 r->src.port[1] = src_port->port[1];
5136 r->src.port_op = src_port->op;
5137 r->dst.addr = dst_host->addr;
5138 r->dst.neg = dst_host->not;
5139 r->dst.port[0] = dst_port->port[0];
5140 r->dst.port[1] = dst_port->port[1];
5141 r->dst.port_op = dst_port->op;
5142 r->uid.op = uid->op;
5143 r->uid.uid[0] = uid->uid[0];
5144 r->uid.uid[1] = uid->uid[1];
5145 r->gid.op = gid->op;
5146 r->gid.gid[0] = gid->gid[0];
5147 r->gid.gid[1] = gid->gid[1];
5148 r->type = icmp_type->type;
5149 r->code = icmp_type->code;
5151 if ((keep_state == PF_STATE_MODULATE ||
5152 keep_state == PF_STATE_SYNPROXY) &&
5153 r->proto && r->proto != IPPROTO_TCP)
5154 r->keep_state = PF_STATE_NORMAL;
5156 r->keep_state = keep_state;
5158 if (r->proto && r->proto != IPPROTO_TCP) {
5163 r->flagset = flagset;
5165 if (icmp_type->proto && r->proto != icmp_type->proto) {
5166 yyerror("icmp-type mismatch");
5170 if (src_os && src_os->os) {
5171 r->os_fingerprint = pfctl_get_fingerprint(src_os->os);
5172 if ((pf->opts & PF_OPT_VERBOSE2) &&
5173 r->os_fingerprint == PF_OSFP_NOMATCH)
5175 "warning: unknown '%s' OS fingerprint\n",
5178 r->os_fingerprint = PF_OSFP_ANY;
5181 TAILQ_INIT(&r->rpool.list);
5182 for (h = rpool_hosts; h != NULL; h = h->next) {
5183 pa = calloc(1, sizeof(struct pf_pooladdr));
5185 err(1, "expand_rule: calloc");
5187 if (h->ifname != NULL) {
5188 if (strlcpy(pa->ifname, h->ifname,
5189 sizeof(pa->ifname)) >=
5191 errx(1, "expand_rule: strlcpy");
5194 TAILQ_INSERT_TAIL(&r->rpool.list, pa, entries);
5197 if (rule_consistent(r, anchor_call[0]) < 0 || error)
5198 yyerror("skipping rule due to errors");
5200 r->nr = pf->astack[pf->asd]->match++;
5201 pfctl_add_rule(pf, r, anchor_call);
5207 FREE_LIST(struct node_if, interfaces);
5208 FREE_LIST(struct node_proto, protos);
5209 FREE_LIST(struct node_host, src_hosts);
5210 FREE_LIST(struct node_port, src_ports);
5211 FREE_LIST(struct node_os, src_oses);
5212 FREE_LIST(struct node_host, dst_hosts);
5213 FREE_LIST(struct node_port, dst_ports);
5214 FREE_LIST(struct node_uid, uids);
5215 FREE_LIST(struct node_gid, gids);
5216 FREE_LIST(struct node_icmp, icmp_types);
5217 FREE_LIST(struct node_host, rpool_hosts);
5220 yyerror("rule expands to no valid combination");
5224 expand_skip_interface(struct node_if *interfaces)
5228 if (!interfaces || (!interfaces->next && !interfaces->not &&
5229 !strcmp(interfaces->ifname, "none"))) {
5230 if (pf->opts & PF_OPT_VERBOSE)
5231 printf("set skip on none\n");
5232 errs = pfctl_set_interface_flags(pf, "", PFI_IFLAG_SKIP, 0);
5236 if (pf->opts & PF_OPT_VERBOSE)
5237 printf("set skip on {");
5238 LOOP_THROUGH(struct node_if, interface, interfaces,
5239 if (pf->opts & PF_OPT_VERBOSE)
5240 printf(" %s", interface->ifname);
5241 if (interface->not) {
5242 yyerror("skip on ! <interface> is not supported");
5245 errs += pfctl_set_interface_flags(pf,
5246 interface->ifname, PFI_IFLAG_SKIP, 1);
5248 if (pf->opts & PF_OPT_VERBOSE)
5251 FREE_LIST(struct node_if, interfaces);
5263 check_rulestate(int desired_state)
5265 if (require_order && (rulestate > desired_state)) {
5266 yyerror("Rules must be in order: options, normalization, "
5267 "queueing, translation, filtering");
5270 rulestate = desired_state;
5275 kw_cmp(const void *k, const void *e)
5277 return (strcmp(k, ((const struct keywords *)e)->k_name));
5283 /* this has to be sorted always */
5284 static const struct keywords keywords[] = {
5286 { "allow-opts", ALLOWOPTS},
5288 { "anchor", ANCHOR},
5289 { "antispoof", ANTISPOOF},
5291 { "bandwidth", BANDWIDTH},
5293 { "binat-anchor", BINATANCHOR},
5294 { "bitmask", BITMASK},
5296 { "block-policy", BLOCKPOLICY},
5297 { "buckets", BUCKETS},
5300 { "crop", FRAGCROP},
5302 { "divert-reply", DIVERTREPLY},
5303 { "divert-to", DIVERTTO},
5305 { "drop-ovl", FRAGDROP},
5308 { "fastroute", FASTROUTE},
5309 { "file", FILENAME},
5310 { "fingerprints", FINGERPRINTS},
5312 { "floating", FLOATING},
5315 { "fragment", FRAGMENT},
5317 { "global", GLOBAL},
5321 { "hostid", HOSTID},
5322 { "icmp-type", ICMPTYPE},
5323 { "icmp6-type", ICMP6TYPE},
5324 { "if-bound", IFBOUND},
5326 { "include", INCLUDE},
5332 { "linkshare", LINKSHARE},
5335 { "loginterface", LOGINTERFACE},
5337 { "max-mss", MAXMSS},
5338 { "max-src-conn", MAXSRCCONN},
5339 { "max-src-conn-rate", MAXSRCCONNRATE},
5340 { "max-src-nodes", MAXSRCNODES},
5341 { "max-src-states", MAXSRCSTATES},
5342 { "min-ttl", MINTTL},
5343 { "modulate", MODULATE},
5345 { "nat-anchor", NATANCHOR},
5348 { "no-route", NOROUTE},
5349 { "no-sync", NOSYNC},
5351 { "optimization", OPTIMIZATION},
5354 { "overload", OVERLOAD},
5357 { "priority", PRIORITY},
5359 { "probability", PROBABILITY},
5361 { "qlimit", QLIMIT},
5364 { "random", RANDOM},
5365 { "random-id", RANDOMID},
5367 { "rdr-anchor", RDRANCHOR},
5368 { "realtime", REALTIME},
5369 { "reassemble", REASSEMBLE},
5370 { "reply-to", REPLYTO},
5371 { "require-order", REQUIREORDER},
5372 { "return", RETURN},
5373 { "return-icmp", RETURNICMP},
5374 { "return-icmp6", RETURNICMP6},
5375 { "return-rst", RETURNRST},
5376 { "round-robin", ROUNDROBIN},
5378 { "route-to", ROUTETO},
5379 { "rtable", RTABLE},
5381 { "ruleset-optimization", RULESET_OPTIMIZATION},
5384 { "set-tos", SETTOS},
5386 { "sloppy", SLOPPY},
5387 { "source-hash", SOURCEHASH},
5388 { "source-track", SOURCETRACK},
5390 { "state-defaults", STATEDEFAULTS},
5391 { "state-policy", STATEPOLICY},
5392 { "static-port", STATICPORT},
5393 { "sticky-address", STICKYADDRESS},
5394 { "synproxy", SYNPROXY},
5397 { "tagged", TAGGED},
5398 { "tbrsize", TBRSIZE},
5399 { "timeout", TIMEOUT},
5403 { "upperlimit", UPPERLIMIT},
5404 { "urpf-failed", URPFFAILED},
5407 const struct keywords *p;
5409 p = bsearch(s, keywords, sizeof(keywords)/sizeof(keywords[0]),
5410 sizeof(keywords[0]), kw_cmp);
5414 fprintf(stderr, "%s: %d\n", s, p->k_val);
5418 fprintf(stderr, "string: %s\n", s);
5423 #define MAXPUSHBACK 128
5427 char pushback_buffer[MAXPUSHBACK];
5428 int pushback_index = 0;
5436 /* Read character from the parsebuffer instead of input. */
5437 if (parseindex >= 0) {
5438 c = parsebuf[parseindex++];
5447 return (pushback_buffer[--pushback_index]);
5450 if ((c = getc(file->stream)) == EOF) {
5451 yyerror("reached end of file while parsing quoted string");
5452 if (popfile() == EOF)
5459 while ((c = getc(file->stream)) == '\\') {
5460 next = getc(file->stream);
5465 yylval.lineno = file->lineno;
5470 if (popfile() == EOF)
5472 c = getc(file->stream);
5484 if (parseindex >= 0)
5487 if (pushback_index < MAXPUSHBACK-1)
5488 return (pushback_buffer[pushback_index++] = c);
5500 /* skip to either EOF or the first real EOL */
5503 c = pushback_buffer[--pushback_index];
5521 int quotec, next, c;
5526 while ((c = lgetc(0)) == ' ' || c == '\t')
5529 yylval.lineno = file->lineno;
5531 while ((c = lgetc(0)) != '\n' && c != EOF)
5533 if (c == '$' && parsebuf == NULL) {
5535 if ((c = lgetc(0)) == EOF)
5538 if (p + 1 >= buf + sizeof(buf) - 1) {
5539 yyerror("string too long");
5542 if (isalnum(c) || c == '_') {
5552 yyerror("macro '%s' not defined", buf);
5565 if ((c = lgetc(quotec)) == EOF)
5570 } else if (c == '\\') {
5571 if ((next = lgetc(quotec)) == EOF)
5573 if (next == quotec || c == ' ' || c == '\t')
5575 else if (next == '\n')
5579 } else if (c == quotec) {
5583 if (p + 1 >= buf + sizeof(buf) - 1) {
5584 yyerror("string too long");
5589 yylval.v.string = strdup(buf);
5590 if (yylval.v.string == NULL)
5591 err(1, "yylex: strdup");
5596 yylval.v.i = PF_OP_XRG;
5597 return (PORTBINARY);
5604 yylval.v.i = PF_OP_IRG;
5605 return (PORTBINARY);
5617 #define allowed_to_end_number(x) \
5618 (isspace(x) || x == ')' || x ==',' || x == '/' || x == '}' || x == '=')
5620 if (c == '-' || isdigit(c)) {
5623 if ((unsigned)(p-buf) >= sizeof(buf)) {
5624 yyerror("string too long");
5627 } while ((c = lgetc(0)) != EOF && isdigit(c));
5629 if (p == buf + 1 && buf[0] == '-')
5631 if (c == EOF || allowed_to_end_number(c)) {
5632 const char *errstr = NULL;
5635 yylval.v.number = strtonum(buf, LLONG_MIN,
5636 LLONG_MAX, &errstr);
5638 yyerror("\"%s\" invalid number: %s",
5653 #define allowed_in_string(x) \
5654 (isalnum(x) || (ispunct(x) && x != '(' && x != ')' && \
5655 x != '{' && x != '}' && x != '<' && x != '>' && \
5656 x != '!' && x != '=' && x != '/' && x != '#' && \
5659 if (isalnum(c) || c == ':' || c == '_') {
5662 if ((unsigned)(p-buf) >= sizeof(buf)) {
5663 yyerror("string too long");
5666 } while ((c = lgetc(0)) != EOF && (allowed_in_string(c)));
5669 if ((token = lookup(buf)) == STRING)
5670 if ((yylval.v.string = strdup(buf)) == NULL)
5671 err(1, "yylex: strdup");
5675 yylval.lineno = file->lineno;
5684 check_file_secrecy(int fd, const char *fname)
5688 if (fstat(fd, &st)) {
5689 warn("cannot stat %s", fname);
5692 if (st.st_uid != 0 && st.st_uid != getuid()) {
5693 warnx("%s: owner not root or current user", fname);
5696 if (st.st_mode & (S_IRWXG | S_IRWXO)) {
5697 warnx("%s: group/world readable/writeable", fname);
5704 pushfile(const char *name, int secret)
5708 if ((nfile = calloc(1, sizeof(struct file))) == NULL ||
5709 (nfile->name = strdup(name)) == NULL) {
5713 if (TAILQ_FIRST(&files) == NULL && strcmp(nfile->name, "-") == 0) {
5714 nfile->stream = stdin;
5716 if ((nfile->name = strdup("stdin")) == NULL) {
5721 } else if ((nfile->stream = fopen(nfile->name, "r")) == NULL) {
5722 warn("%s", nfile->name);
5726 } else if (secret &&
5727 check_file_secrecy(fileno(nfile->stream), nfile->name)) {
5728 fclose(nfile->stream);
5734 TAILQ_INSERT_TAIL(&files, nfile, entry);
5743 if ((prev = TAILQ_PREV(file, files, entry)) != NULL) {
5744 prev->errors += file->errors;
5745 TAILQ_REMOVE(&files, file, entry);
5746 fclose(file->stream);
5756 parse_config(char *filename, struct pfctl *xpf)
5763 rulestate = PFCTL_STATE_NONE;
5764 returnicmpdefault = (ICMP_UNREACH << 8) | ICMP_UNREACH_PORT;
5765 returnicmp6default =
5766 (ICMP6_DST_UNREACH << 8) | ICMP6_DST_UNREACH_NOPORT;
5767 blockpolicy = PFRULE_DROP;
5770 if ((file = pushfile(filename, 0)) == NULL) {
5771 warn("cannot open the main config file!");
5776 errors = file->errors;
5779 /* Free macros and check which have not been used. */
5780 while ((sym = TAILQ_FIRST(&symhead))) {
5781 if ((pf->opts & PF_OPT_VERBOSE2) && !sym->used)
5782 fprintf(stderr, "warning: macro '%s' not "
5783 "used\n", sym->nam);
5786 TAILQ_REMOVE(&symhead, sym, entry);
5790 return (errors ? -1 : 0);
5794 symset(const char *nam, const char *val, int persist)
5798 for (sym = TAILQ_FIRST(&symhead); sym && strcmp(nam, sym->nam);
5799 sym = TAILQ_NEXT(sym, entry))
5803 if (sym->persist == 1)
5808 TAILQ_REMOVE(&symhead, sym, entry);
5812 if ((sym = calloc(1, sizeof(*sym))) == NULL)
5815 sym->nam = strdup(nam);
5816 if (sym->nam == NULL) {
5820 sym->val = strdup(val);
5821 if (sym->val == NULL) {
5827 sym->persist = persist;
5828 TAILQ_INSERT_TAIL(&symhead, sym, entry);
5833 pfctl_cmdline_symset(char *s)
5838 if ((val = strrchr(s, '=')) == NULL)
5841 if ((sym = malloc(strlen(s) - strlen(val) + 1)) == NULL)
5842 err(1, "pfctl_cmdline_symset: malloc");
5844 strlcpy(sym, s, strlen(s) - strlen(val) + 1);
5846 ret = symset(sym, val + 1, 1);
5853 symget(const char *nam)
5857 TAILQ_FOREACH(sym, &symhead, entry)
5858 if (strcmp(nam, sym->nam) == 0) {
5866 mv_rules(struct pf_ruleset *src, struct pf_ruleset *dst)
5871 for (i = 0; i < PF_RULESET_MAX; ++i) {
5872 while ((r = TAILQ_FIRST(src->rules[i].active.ptr))
5874 TAILQ_REMOVE(src->rules[i].active.ptr, r, entries);
5875 TAILQ_INSERT_TAIL(dst->rules[i].active.ptr, r, entries);
5876 dst->anchor->match++;
5878 src->anchor->match = 0;
5879 while ((r = TAILQ_FIRST(src->rules[i].inactive.ptr))
5881 TAILQ_REMOVE(src->rules[i].inactive.ptr, r, entries);
5882 TAILQ_INSERT_TAIL(dst->rules[i].inactive.ptr,
5889 decide_address_family(struct node_host *n, sa_family_t *af)
5891 if (*af != 0 || n == NULL)
5894 while ((n = n->next) != NULL) {
5903 remove_invalid_hosts(struct node_host **nh, sa_family_t *af)
5905 struct node_host *n = *nh, *prev = NULL;
5908 if (*af && n->af && n->af != *af) {
5909 /* unlink and free n */
5910 struct node_host *next = n->next;
5912 /* adjust tail pointer */
5913 if (n == (*nh)->tail)
5915 /* adjust previous node's next pointer */
5921 if (n->ifname != NULL)
5935 invalid_redirect(struct node_host *nh, sa_family_t af)
5938 struct node_host *n;
5940 /* tables and dyniftl are ok without an address family */
5941 for (n = nh; n != NULL; n = n->next) {
5942 if (n->addr.type != PF_ADDR_TABLE &&
5943 n->addr.type != PF_ADDR_DYNIFTL) {
5944 yyerror("address family not given and "
5945 "translation address expands to multiple "
5946 "address families");
5952 yyerror("no translation address with matching address family "
5960 atoul(char *s, u_long *ulvalp)
5966 ulval = strtoul(s, &ep, 0);
5967 if (s[0] == '\0' || *ep != '\0')
5969 if (errno == ERANGE && ulval == ULONG_MAX)
5981 if (atoul(n, &ulval) == 0) {
5982 if (ulval > 65535) {
5983 yyerror("illegal port value %lu", ulval);
5986 return (htons(ulval));
5988 s = getservbyname(n, "tcp");
5990 s = getservbyname(n, "udp");
5992 yyerror("unknown port %s", n);
6000 rule_label(struct pf_rule *r, char *s)
6003 if (strlcpy(r->label, s, sizeof(r->label)) >=
6005 yyerror("rule label too long (max %d chars)",
6006 sizeof(r->label)-1);
6014 parseicmpspec(char *w, sa_family_t af)
6016 const struct icmpcodeent *p;
6021 icmptype = returnicmpdefault >> 8;
6023 icmptype = returnicmp6default >> 8;
6025 if (atoul(w, &ulval) == -1) {
6026 if ((p = geticmpcodebyname(icmptype, w, af)) == NULL) {
6027 yyerror("unknown icmp code %s", w);
6033 yyerror("invalid icmp code %lu", ulval);
6036 return (icmptype << 8 | ulval);
6040 parseport(char *port, struct range *r, int extensions)
6042 char *p = strchr(port, ':');
6045 if ((r->a = getservice(port)) == -1)
6051 if ((extensions & PPORT_STAR) && !strcmp(p+1, "*")) {
6053 if ((r->a = getservice(port)) == -1)
6059 if ((extensions & PPORT_RANGE)) {
6061 if ((r->a = getservice(port)) == -1 ||
6062 (r->b = getservice(p)) == -1)
6075 pfctl_load_anchors(int dev, struct pfctl *pf, struct pfr_buffer *trans)
6077 struct loadanchors *la;
6079 TAILQ_FOREACH(la, &loadanchorshead, entries) {
6080 if (pf->opts & PF_OPT_VERBOSE)
6081 fprintf(stderr, "\nLoading anchor %s from %s\n",
6082 la->anchorname, la->filename);
6083 if (pfctl_rules(dev, la->filename, pf->opts, pf->optimize,
6084 la->anchorname, trans) == -1)
6092 rt_tableid_max(void)
6096 size_t l = sizeof(fibs);
6098 if (sysctlbyname("net.fibs", &fibs, &l, NULL, 0) == -1)
6099 fibs = 16; /* XXX RT_MAXFIBS, at least limit it some. */
6101 * As the OpenBSD code only compares > and not >= we need to adjust
6102 * here given we only accept values of 0..n and want to avoid #ifdefs
6107 return (RT_TABLEID_MAX);