1 /*        $NetBSD: parse.y,v 1.12 2009/06/16 05:16:52 minskim Exp $   */
2 /*        $OpenBSD: parse.y,v 1.519 2007/06/21 19:30:03 henning Exp $ */
3 
4 /*
5  * Copyright (c) 2001 Markus Friedl.  All rights reserved.
6  * Copyright (c) 2001 Daniel Hartmeier.  All rights reserved.
7  * Copyright (c) 2001 Theo de Raadt.  All rights reserved.
8  * Copyright (c) 2002,2003 Henning Brauer. All rights reserved.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
20  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
23  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
24  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29  */
30 %{
31 #include <sys/types.h>
32 #include <sys/socket.h>
33 #include <net/if.h>
34 #include <netinet/in.h>
35 #include <netinet/in_systm.h>
36 #include <netinet/ip.h>
37 #include <netinet/ip_icmp.h>
38 #include <netinet/icmp6.h>
39 #include <net/pfvar.h>
40 #include <arpa/inet.h>
41 #include <altq/altq.h>
42 #include <altq/altq_cbq.h>
43 #include <altq/altq_priq.h>
44 #include <altq/altq_hfsc.h>
45 
46 #include <stdio.h>
47 #include <stdlib.h>
48 #include <netdb.h>
49 #include <stdarg.h>
50 #include <errno.h>
51 #include <string.h>
52 #include <ctype.h>
53 #include <math.h>
54 #include <err.h>
55 #include <limits.h>
56 #include <pwd.h>
57 #include <grp.h>
58 #include <md5.h>
59 
60 #include "pfctl_parser.h"
61 #include "pfctl.h"
62 
63 #ifndef RT_TABLEID_MAX
64 #define RT_TABLEID_MAX        255
65 #endif /* !RT_TABLEID_MAX */
66 
67 static struct pfctl *pf = NULL;
68 static FILE                   *fin = NULL;
69 static int                     debug = 0;
70 static int                     lineno = 1;
71 static int                     errors = 0;
72 static int                     rulestate = 0;
73 static u_int16_t     returnicmpdefault =
74                                   (ICMP_UNREACH << 8) | ICMP_UNREACH_PORT;
75 static u_int16_t     returnicmp6default =
76                                   (ICMP6_DST_UNREACH << 8) | ICMP6_DST_UNREACH_NOPORT;
77 static int                     blockpolicy = PFRULE_DROP;
78 static int                     require_order = 1;
79 static int                     default_statelock;
80 
81 enum {
82           PFCTL_STATE_NONE,
83           PFCTL_STATE_OPTION,
84           PFCTL_STATE_SCRUB,
85           PFCTL_STATE_QUEUE,
86           PFCTL_STATE_NAT,
87           PFCTL_STATE_FILTER
88 };
89 
90 struct node_proto {
91           u_int8_t             proto;
92           struct node_proto   *next;
93           struct node_proto   *tail;
94 };
95 
96 struct node_port {
97           u_int16_t            port[2];
98           u_int8_t             op;
99           struct node_port    *next;
100           struct node_port    *tail;
101 };
102 
103 struct node_uid {
104           uid_t                          uid[2];
105           u_int8_t             op;
106           struct node_uid               *next;
107           struct node_uid               *tail;
108 };
109 
110 struct node_gid {
111           gid_t                          gid[2];
112           u_int8_t             op;
113           struct node_gid               *next;
114           struct node_gid               *tail;
115 };
116 
117 struct node_icmp {
118           u_int8_t             code;
119           u_int8_t             type;
120           u_int8_t             proto;
121           struct node_icmp    *next;
122           struct node_icmp    *tail;
123 };
124 
125 enum      { PF_STATE_OPT_MAX, PF_STATE_OPT_NOSYNC, PF_STATE_OPT_SRCTRACK,
126               PF_STATE_OPT_MAX_SRC_STATES, PF_STATE_OPT_MAX_SRC_CONN,
127               PF_STATE_OPT_MAX_SRC_CONN_RATE, PF_STATE_OPT_MAX_SRC_NODES,
128               PF_STATE_OPT_OVERLOAD, PF_STATE_OPT_STATELOCK,
129               PF_STATE_OPT_TIMEOUT };
130 
131 enum      { PF_SRCTRACK_NONE, PF_SRCTRACK, PF_SRCTRACK_GLOBAL, PF_SRCTRACK_RULE };
132 
133 struct node_state_opt {
134           int                            type;
135           union {
136                     u_int32_t  max_states;
137                     u_int32_t  max_src_states;
138                     u_int32_t  max_src_conn;
139                     struct {
140                               u_int32_t limit;
141                               u_int32_t seconds;
142                     }                    max_src_conn_rate;
143                     struct {
144                               u_int8_t  flush;
145                               char                tblname[PF_TABLE_NAME_SIZE];
146                     }                    overload;
147                     u_int32_t  max_src_nodes;
148                     u_int8_t   src_track;
149                     u_int32_t  statelock;
150                     struct {
151                               int                 number;
152                               u_int32_t seconds;
153                     }                    timeout;
154           }                              data;
155           struct node_state_opt         *next;
156           struct node_state_opt         *tail;
157 };
158 
159 struct peer {
160           struct node_host    *host;
161           struct node_port    *port;
162 };
163 
164 struct node_queue {
165           char                           queue[PF_QNAME_SIZE];
166           char                           parent[PF_QNAME_SIZE];
167           char                           ifname[IFNAMSIZ];
168           int                            scheduler;
169           struct node_queue   *next;
170           struct node_queue   *tail;
171 }         *queues = NULL;
172 
173 struct node_qassign {
174           char                *qname;
175           char                *pqname;
176 };
177 
178 struct filter_opts {
179           int                            marker;
180 #define FOM_FLAGS   0x01
181 #define FOM_ICMP    0x02
182 #define FOM_TOS               0x04
183 #define FOM_KEEP    0x08
184 #define FOM_SRCTRACK          0x10
185           struct node_uid               *uid;
186           struct node_gid               *gid;
187           struct {
188                     u_int8_t   b1;
189                     u_int8_t   b2;
190                     u_int16_t  w;
191                     u_int16_t  w2;
192           } flags;
193           struct node_icmp    *icmpspec;
194           u_int32_t            tos;
195           u_int32_t            prob;
196           struct {
197                     int                            action;
198                     struct node_state_opt         *options;
199           } keep;
200           int                            fragment;
201           int                            allowopts;
202           char                          *label;
203           struct node_qassign  queues;
204           char                          *tag;
205           char                          *match_tag;
206           u_int8_t             match_tag_not;
207           int                            rtableid;
208 } filter_opts;
209 
210 struct antispoof_opts {
211           char                          *label;
212           int                            rtableid;
213 } antispoof_opts;
214 
215 struct scrub_opts {
216           int                           marker;
217 #define SOM_MINTTL  0x01
218 #define SOM_MAXMSS  0x02
219 #define SOM_FRAGCACHE         0x04
220           int                           nodf;
221           int                           minttl;
222           int                           maxmss;
223           int                           fragcache;
224           int                           randomid;
225           int                           reassemble_tcp;
226           int                           rtableid;
227 } scrub_opts;
228 
229 struct queue_opts {
230           int                           marker;
231 #define QOM_BWSPEC  0x01
232 #define QOM_SCHEDULER         0x02
233 #define QOM_PRIORITY          0x04
234 #define QOM_TBRSIZE 0x08
235 #define QOM_QLIMIT  0x10
236           struct node_queue_bw          queue_bwspec;
237           struct node_queue_opt         scheduler;
238           int                           priority;
239           int                           tbrsize;
240           int                           qlimit;
241 } queue_opts;
242 
243 struct table_opts {
244           int                           flags;
245           int                           init_addr;
246           struct node_tinithead         init_nodes;
247 } table_opts;
248 
249 struct pool_opts {
250           int                            marker;
251 #define POM_TYPE              0x01
252 #define POM_STICKYADDRESS     0x02
253           u_int8_t             opts;
254           int                            type;
255           int                            staticport;
256           struct pf_poolhashkey         *key;
257 
258 } pool_opts;
259 
260 
261 struct node_hfsc_opts         hfsc_opts;
262 
263 int       yyerror(const char *, ...);
264 int       disallow_table(struct node_host *, const char *);
265 int       disallow_urpf_failed(struct node_host *, const char *);
266 int       disallow_alias(struct node_host *, const char *);
267 int       rule_consistent(struct pf_rule *, int);
268 int       filter_consistent(struct pf_rule *, int);
269 int       nat_consistent(struct pf_rule *);
270 int       rdr_consistent(struct pf_rule *);
271 int       process_tabledef(char *, struct table_opts *);
272 int       yyparse(void);
273 void      expand_label_str(char *, size_t, const char *, const char *);
274 void      expand_label_if(const char *, char *, size_t, const char *);
275 void      expand_label_addr(const char *, char *, size_t, u_int8_t,
276               struct node_host *);
277 void      expand_label_port(const char *, char *, size_t, struct node_port *);
278 void      expand_label_proto(const char *, char *, size_t, u_int8_t);
279 void      expand_label_nr(const char *, char *, size_t);
280 void      expand_label(char *, size_t, const char *, u_int8_t, struct node_host *,
281               struct node_port *, struct node_host *, struct node_port *,
282               u_int8_t);
283 void      expand_rule(struct pf_rule *, struct node_if *, struct node_host *,
284               struct node_proto *, struct node_os*, struct node_host *,
285               struct node_port *, struct node_host *, struct node_port *,
286               struct node_uid *, struct node_gid *, struct node_icmp *,
287               const char *);
288 int       expand_altq(struct pf_altq *, struct node_if *, struct node_queue *,
289               struct node_queue_bw bwspec, struct node_queue_opt *);
290 int       expand_queue(struct pf_altq *, struct node_if *, struct node_queue *,
291               struct node_queue_bw, struct node_queue_opt *);
292 int       expand_skip_interface(struct node_if *);
293 
294 int        check_rulestate(int);
295 int        kw_cmp(const void *, const void *);
296 int        lookup(char *);
297 int        lgetc(FILE *);
298 int        lungetc(int);
299 int        findeol(void);
300 int        yylex(void);
301 int        atoul(char *, u_long *);
302 int        getservice(char *);
303 int        rule_label(struct pf_rule *, char *);
304 
305 TAILQ_HEAD(symhead, sym)       symhead = TAILQ_HEAD_INITIALIZER(symhead);
306 struct sym {
307           TAILQ_ENTRY(sym)     entries;
308           int                            used;
309           int                            persist;
310           char                          *nam;
311           char                          *val;
312 };
313 
314 
315 int        symset(const char *, const char *, int);
316 char      *symget(const char *);
317 
318 void       mv_rules(struct pf_ruleset *, struct pf_ruleset *);
319 void       decide_address_family(struct node_host *, sa_family_t *);
320 void       remove_invalid_hosts(struct node_host **, sa_family_t *);
321 int        invalid_redirect(struct node_host *, sa_family_t);
322 u_int16_t parseicmpspec(char *, sa_family_t);
323 
324 TAILQ_HEAD(loadanchorshead, loadanchors)
325     loadanchorshead = TAILQ_HEAD_INITIALIZER(loadanchorshead);
326 
327 struct loadanchors {
328           TAILQ_ENTRY(loadanchors)       entries;
329           char                                    *anchorname;
330           char                                    *filename;
331 };
332 
333 typedef struct {
334           union {
335                     u_int32_t            number;
336                     int                            i;
337                     char                          *string;
338                     int                            rtableid;
339                     struct {
340                               u_int8_t   b1;
341                               u_int8_t   b2;
342                               u_int16_t  w;
343                               u_int16_t  w2;
344                     }                              b;
345                     struct range {
346                               int                  a;
347                               int                  b;
348                               int                  t;
349                     }                              range;
350                     struct node_if                *interface;
351                     struct node_proto   *proto;
352                     struct node_icmp    *icmp;
353                     struct node_host    *host;
354                     struct node_os                *os;
355                     struct node_port    *port;
356                     struct node_uid               *uid;
357                     struct node_gid               *gid;
358                     struct node_state_opt         *state_opt;
359                     struct peer                    peer;
360                     struct {
361                               struct peer          src, dst;
362                               struct node_os      *src_os;
363                     }                              fromto;
364                     struct {
365                               struct node_host    *host;
366                               u_int8_t             rt;
367                               u_int8_t             pool_opts;
368                               sa_family_t                    af;
369                               struct pf_poolhashkey         *key;
370                     }                              route;
371                     struct redirection {
372                               struct node_host    *host;
373                               struct range                   rport;
374                     }                             *redirection;
375                     struct {
376                               int                            action;
377                               struct node_state_opt         *options;
378                     }                              keep_state;
379                     struct {
380                               u_int8_t   log;
381                               u_int8_t   logif;
382                               u_int8_t   quick;
383                     }                              logquick;
384                     struct {
385                               int                  neg;
386                               char                *name;
387                     }                              tagged;
388                     struct pf_poolhashkey         *hashkey;
389                     struct node_queue   *queue;
390                     struct node_queue_opt          queue_options;
391                     struct node_queue_bw           queue_bwspec;
392                     struct node_qassign  qassign;
393                     struct filter_opts   filter_opts;
394                     struct antispoof_opts          antispoof_opts;
395                     struct queue_opts    queue_opts;
396                     struct scrub_opts    scrub_opts;
397                     struct table_opts    table_opts;
398                     struct pool_opts     pool_opts;
399                     struct node_hfsc_opts          hfsc_opts;
400           } v;
401           int lineno;
402 } YYSTYPE;
403 
404 #define DYNIF_MULTIADDR(addr) ((addr).type == PF_ADDR_DYNIFTL && \
405           (!((addr).iflags & PFI_AFLAG_NOALIAS) ||                     \
406           !isdigit((unsigned char)(addr).v.ifname[strlen((addr).v.ifname)-1])))
407 
408 %}
409 
410 %token    PASS BLOCK SCRUB RETURN IN OS OUT LOG QUICK ON FROM TO FLAGS
411 %token    RETURNRST RETURNICMP RETURNICMP6 PROTO INET INET6 ALL ANY ICMPTYPE
412 %token    ICMP6TYPE CODE KEEP MODULATE STATE PORT RDR NAT BINAT ARROW NODF
413 %token    MINTTL ERROR ALLOWOPTS FASTROUTE FILENAME ROUTETO DUPTO REPLYTO NO LABEL
414 %token    NOROUTE URPFFAILED FRAGMENT USER GROUP MAXMSS MAXIMUM TTL TOS DROP TABLE
415 %token    REASSEMBLE FRAGDROP FRAGCROP ANCHOR NATANCHOR RDRANCHOR BINATANCHOR
416 %token    SET OPTIMIZATION TIMEOUT LIMIT LOGINTERFACE BLOCKPOLICY RANDOMID
417 %token    REQUIREORDER SYNPROXY FINGERPRINTS NOSYNC DEBUG SKIP HOSTID
418 %token    ANTISPOOF FOR
419 %token    BITMASK RANDOM SOURCEHASH ROUNDROBIN STATICPORT PROBABILITY
420 %token    ALTQ CBQ PRIQ HFSC BANDWIDTH TBRSIZE LINKSHARE REALTIME UPPERLIMIT
421 %token    QUEUE PRIORITY QLIMIT RTABLE
422 %token    LOAD RULESET_OPTIMIZATION
423 %token    STICKYADDRESS MAXSRCSTATES MAXSRCNODES SOURCETRACK GLOBAL RULE
424 %token    MAXSRCCONN MAXSRCCONNRATE OVERLOAD FLUSH
425 %token    TAGGED TAG IFBOUND FLOATING STATEPOLICY ROUTE
426 %token    <v.string>                    STRING
427 %token    <v.i>                         PORTBINARY
428 %type     <v.interface>                 interface if_list if_item_not if_item
429 %type     <v.number>                    number icmptype icmp6type uid gid
430 %type     <v.number>                    tos not yesno
431 %type     <v.i>                         no dir af fragcache optimizer
432 %type     <v.i>                         sourcetrack flush unaryop statelock
433 %type     <v.b>                         action nataction natpasslog scrubaction
434 %type     <v.b>                         flags flag blockspec
435 %type     <v.range>           port rport
436 %type     <v.hashkey>                   hashkey
437 %type     <v.proto>           proto proto_list proto_item
438 %type     <v.icmp>            icmpspec
439 %type     <v.icmp>            icmp_list icmp_item
440 %type     <v.icmp>            icmp6_list icmp6_item
441 %type     <v.fromto>                    fromto
442 %type     <v.peer>            ipportspec from to
443 %type     <v.host>            ipspec xhost host dynaddr host_list
444 %type     <v.host>            redir_host_list redirspec
445 %type     <v.host>            route_host route_host_list routespec
446 %type     <v.os>                        os xos os_list
447 %type     <v.port>            portspec port_list port_item
448 %type     <v.uid>                       uids uid_list uid_item
449 %type     <v.gid>                       gids gid_list gid_item
450 %type     <v.route>           route
451 %type     <v.redirection>               redirection redirpool
452 %type     <v.string>                    label string tag anchorname
453 %type     <v.keep_state>                keep
454 %type     <v.state_opt>                 state_opt_spec state_opt_list state_opt_item
455 %type     <v.state_opt>                 opt_statelock
456 %type     <v.logquick>                  logquick quick log logopts logopt
457 %type     <v.interface>                 antispoof_ifspc antispoof_iflst antispoof_if
458 %type     <v.qassign>                   qname
459 %type     <v.queue>           qassign qassign_list qassign_item
460 %type     <v.queue_options>   scheduler
461 %type     <v.number>                    cbqflags_list cbqflags_item
462 %type     <v.number>                    priqflags_list priqflags_item
463 %type     <v.hfsc_opts>                 hfscopts_list hfscopts_item hfsc_opts
464 %type     <v.queue_bwspec>    bandwidth
465 %type     <v.filter_opts>               filter_opts filter_opt filter_opts_l
466 %type     <v.antispoof_opts>  antispoof_opts antispoof_opt antispoof_opts_l
467 %type     <v.queue_opts>                queue_opts queue_opt queue_opts_l
468 %type     <v.scrub_opts>                scrub_opts scrub_opt scrub_opts_l
469 %type     <v.table_opts>                table_opts table_opt table_opts_l
470 %type     <v.pool_opts>                 pool_opts pool_opt pool_opts_l
471 %type     <v.tagged>                    tagged
472 %type     <v.rtableid>                  rtable
473 %%
474 
475 ruleset             : /* empty */
476                     | ruleset '\n'
477                     | ruleset option '\n'
478                     | ruleset scrubrule '\n'
479                     | ruleset natrule '\n'
480                     | ruleset binatrule '\n'
481                     | ruleset pfrule '\n'
482                     | ruleset anchorrule '\n'
483                     | ruleset loadrule '\n'
484                     | ruleset altqif '\n'
485                     | ruleset queuespec '\n'
486                     | ruleset varset '\n'
487                     | ruleset antispoof '\n'
488                     | ruleset tabledef '\n'
489                     | '{' fakeanchor '}' '\n';
490                     | ruleset error '\n'                    { errors++; }
491                     ;
492 
493 /*
494  * apply to previouslys specified rule: must be careful to note
495  * what that is: pf or nat or binat or rdr
496  */
497 fakeanchor          : fakeanchor '\n'
498                     | fakeanchor anchorrule '\n'
499                     | fakeanchor binatrule '\n'
500                     | fakeanchor natrule '\n'
501                     | fakeanchor pfrule '\n'
502                     | fakeanchor error '\n'
503                     ;
504 
505 optimizer : string  {
506                               if (!strcmp($1, "none"))
507                                         $$ = 0;
508                               else if (!strcmp($1, "basic"))
509                                         $$ = PF_OPTIMIZE_BASIC;
510                               else if (!strcmp($1, "profile"))
511                                         $$ = PF_OPTIMIZE_BASIC | PF_OPTIMIZE_PROFILE;
512                               else {
513                                         yyerror("unknown ruleset-optimization %s", $$);
514                                         YYERROR;
515                               }
516                     }
517                     ;
518 
519 option              : SET OPTIMIZATION STRING               {
520                               if (check_rulestate(PFCTL_STATE_OPTION)) {
521                                         free($3);
522                                         YYERROR;
523                               }
524                               if (pfctl_set_optimization(pf, $3) != 0) {
525                                         yyerror("unknown optimization %s", $3);
526                                         free($3);
527                                         YYERROR;
528                               }
529                               free($3);
530                     }
531                     | SET RULESET_OPTIMIZATION optimizer {
532                               if (!(pf->opts & PF_OPT_OPTIMIZE)) {
533                                         pf->opts |= PF_OPT_OPTIMIZE;
534                                         pf->optimize = $3;
535                               }
536                     }
537                     | SET TIMEOUT timeout_spec
538                     | SET TIMEOUT '{' timeout_list '}'
539                     | SET LIMIT limit_spec
540                     | SET LIMIT '{' limit_list '}'
541                     | SET LOGINTERFACE STRING               {
542                               if (check_rulestate(PFCTL_STATE_OPTION)) {
543                                         free($3);
544                                         YYERROR;
545                               }
546                               if (pfctl_set_logif(pf, $3) != 0) {
547                                         yyerror("error setting loginterface %s", $3);
548                                         free($3);
549                                         YYERROR;
550                               }
551                               free($3);
552                     }
553                     | SET HOSTID number {
554                               if ($3 == 0) {
555                                         yyerror("hostid must be non-zero");
556                                         YYERROR;
557                               }
558                               if (pfctl_set_hostid(pf, $3) != 0) {
559                                         yyerror("error setting hostid %08x", $3);
560                                         YYERROR;
561                               }
562                     }
563                     | SET BLOCKPOLICY DROP        {
564                               if (pf->opts & PF_OPT_VERBOSE)
565                                         printf("set block-policy drop\n");
566                               if (check_rulestate(PFCTL_STATE_OPTION))
567                                         YYERROR;
568                               blockpolicy = PFRULE_DROP;
569                     }
570                     | SET BLOCKPOLICY RETURN {
571                               if (pf->opts & PF_OPT_VERBOSE)
572                                         printf("set block-policy return\n");
573                               if (check_rulestate(PFCTL_STATE_OPTION))
574                                         YYERROR;
575                               blockpolicy = PFRULE_RETURN;
576                     }
577                     | SET REQUIREORDER yesno {
578                               if (pf->opts & PF_OPT_VERBOSE)
579                                         printf("set require-order %s\n",
580                                             $3 == 1 ? "yes" : "no");
581                               require_order = $3;
582                     }
583                     | SET FINGERPRINTS STRING {
584                               if (pf->opts & PF_OPT_VERBOSE)
585                                         printf("set fingerprints \"%s\"\n", $3);
586                               if (check_rulestate(PFCTL_STATE_OPTION)) {
587                                         free($3);
588                                         YYERROR;
589                               }
590                               if (!pf->anchor->name[0]) {
591                                         if (pfctl_file_fingerprints(pf->dev,
592                                             pf->opts, $3)) {
593                                                   yyerror("error loading "
594                                                       "fingerprints %s", $3);
595                                                   free($3);
596                                                   YYERROR;
597                                         }
598                               }
599                               free($3);
600                     }
601                     | SET STATEPOLICY statelock {
602                               if (pf->opts & PF_OPT_VERBOSE)
603                                         switch ($3) {
604                                         case 0:
605                                                   printf("set state-policy floating\n");
606                                                   break;
607                                         case PFRULE_IFBOUND:
608                                                   printf("set state-policy if-bound\n");
609                                                   break;
610                                         }
611                               default_statelock = $3;
612                     }
613                     | SET DEBUG STRING {
614                               if (check_rulestate(PFCTL_STATE_OPTION)) {
615                                         free($3);
616                                         YYERROR;
617                               }
618                               if (pfctl_set_debug(pf, $3) != 0) {
619                                         yyerror("error setting debuglevel %s", $3);
620                                         free($3);
621                                         YYERROR;
622                               }
623                               free($3);
624                     }
625                     | SET SKIP interface {
626                               if (expand_skip_interface($3) != 0) {
627                                         yyerror("error setting skip interface(s)");
628                                         YYERROR;
629                               }
630                     }
631                     ;
632 
633 string              : string STRING                                   {
634                               if (asprintf(&$$, "%s %s", $1, $2) == -1)
635                                         err(1, "string: asprintf");
636                               free($1);
637                               free($2);
638                     }
639                     | STRING
640                     ;
641 
642 varset              : STRING '=' string           {
643                               if (pf->opts & PF_OPT_VERBOSE)
644                                         printf("%s = \"%s\"\n", $1, $3);
645                               if (symset($1, $3, 0) == -1)
646                                         err(1, "cannot store variable %s", $1);
647                               free($1);
648                               free($3);
649                     }
650                     ;
651 
652 anchorname          : STRING                      { $$ = $1; }
653                     | /* empty */                           { $$ = NULL; }
654                     ;
655 
656 optnl               : optnl '\n'
657                     |
658                     ;
659 
660 pfa_anchorlist      : pfrule optnl
661                     | anchorrule optnl
662                     | pfa_anchorlist pfrule optnl
663                     | pfa_anchorlist anchorrule optnl
664                     ;
665 
666 pfa_anchor          : '{'
667                     {
668                               char ta[PF_ANCHOR_NAME_SIZE];
669                               struct pf_ruleset *rs;
670 
671                               /* steping into a brace anchor */
672                               pf->asd++;
673                               pf->bn++;
674                               pf->brace = 1;
675 
676                               /* create a holding ruleset in the root */
677                               snprintf(ta, PF_ANCHOR_NAME_SIZE, "_%d", pf->bn);
678                               rs = pf_find_or_create_ruleset(ta);
679                               if (rs == NULL)
680                                         err(1, "pfa_anchor: pf_find_or_create_ruleset");
681                               pf->astack[pf->asd] = rs->anchor;
682                               pf->anchor = rs->anchor;
683                     } '\n' pfa_anchorlist '}'
684                     {
685                               pf->alast = pf->anchor;
686                               pf->asd--;
687                               pf->anchor = pf->astack[pf->asd];
688                     }
689                     | /* empty */
690                     ;
691 
692 anchorrule          : ANCHOR anchorname dir quick interface af proto fromto
693                         filter_opts pfa_anchor
694                     {
695                               struct pf_rule      r;
696 
697                               if (check_rulestate(PFCTL_STATE_FILTER)) {
698                                         if ($2)
699                                                   free($2);
700                                         YYERROR;
701                               }
702 
703                               if ($2 && ($2[0] == '_' || strstr($2, "/_") != NULL)) {
704                                         free($2);
705                                         yyerror("anchor names beginning with '_' "
706                                             "are reserved for internal use");
707                                         YYERROR;
708                               }
709 
710                               memset(&r, 0, sizeof(r));
711                               if (pf->astack[pf->asd + 1]) {
712                                         /* move inline rules into relative location */
713                                         pf_anchor_setup(&r,
714                                             &pf->astack[pf->asd]->ruleset,
715                                             $2 ? $2 : pf->alast->name);
716 
717                                         if (r.anchor == NULL)
718                                                   err(1, "anchorrule: unable to "
719                                                       "create ruleset");
720 
721                                         if (pf->alast != r.anchor) {
722                                                   if (r.anchor->match) {
723                                                             yyerror("inline anchor '%s' "
724                                                                 "already exists",
725                                                                 r.anchor->name);
726                                                             YYERROR;
727                                                   }
728                                                   mv_rules(&pf->alast->ruleset,
729                                                       &r.anchor->ruleset);
730                                         }
731                                         pf_remove_if_empty_ruleset(&pf->alast->ruleset);
732                                         pf->alast = r.anchor;
733                               } else {
734                                         if (!$2) {
735                                                   yyerror("anchors without explicit "
736                                                       "rules must specify a name");
737                                                   YYERROR;
738                                         }
739                               }
740                               r.direction = $3;
741                               r.quick = $4.quick;
742                               r.af = $6;
743                               r.prob = $9.prob;
744                               r.rtableid = $9.rtableid;
745 
746                               if ($9.match_tag)
747                                         if (strlcpy(r.match_tagname, $9.match_tag,
748                                             PF_TAG_NAME_SIZE) >= PF_TAG_NAME_SIZE) {
749                                                   yyerror("tag too long, max %u chars",
750                                                       PF_TAG_NAME_SIZE - 1);
751                                                   YYERROR;
752                                         }
753                               r.match_tag_not = $9.match_tag_not;
754 
755                               decide_address_family($8.src.host, &r.af);
756                               decide_address_family($8.dst.host, &r.af);
757 
758                               expand_rule(&r, $5, NULL, $7, $8.src_os,
759                                   $8.src.host, $8.src.port, $8.dst.host, $8.dst.port,
760                                   0, 0, 0, pf->astack[pf->asd + 1] ?
761                                   pf->alast->name : $2);
762                               free($2);
763                               pf->astack[pf->asd + 1] = NULL;
764                     }
765                     | NATANCHOR string interface af proto fromto rtable {
766                               struct pf_rule      r;
767 
768                               if (check_rulestate(PFCTL_STATE_NAT)) {
769                                         free($2);
770                                         YYERROR;
771                               }
772 
773                               memset(&r, 0, sizeof(r));
774                               r.action = PF_NAT;
775                               r.af = $4;
776                               r.rtableid = $7;
777 
778                               decide_address_family($6.src.host, &r.af);
779                               decide_address_family($6.dst.host, &r.af);
780 
781                               expand_rule(&r, $3, NULL, $5, $6.src_os,
782                                   $6.src.host, $6.src.port, $6.dst.host, $6.dst.port,
783                                   0, 0, 0, $2);
784                               free($2);
785                     }
786                     | RDRANCHOR string interface af proto fromto rtable {
787                               struct pf_rule      r;
788 
789                               if (check_rulestate(PFCTL_STATE_NAT)) {
790                                         free($2);
791                                         YYERROR;
792                               }
793 
794                               memset(&r, 0, sizeof(r));
795                               r.action = PF_RDR;
796                               r.af = $4;
797                               r.rtableid = $7;
798 
799                               decide_address_family($6.src.host, &r.af);
800                               decide_address_family($6.dst.host, &r.af);
801 
802                               if ($6.src.port != NULL) {
803                                         yyerror("source port parameter not supported"
804                                             " in rdr-anchor");
805                                         YYERROR;
806                               }
807                               if ($6.dst.port != NULL) {
808                                         if ($6.dst.port->next != NULL) {
809                                                   yyerror("destination port list "
810                                                       "expansion not supported in "
811                                                       "rdr-anchor");
812                                                   YYERROR;
813                                         } else if ($6.dst.port->op != PF_OP_EQ) {
814                                                   yyerror("destination port operators"
815                                                       " not supported in rdr-anchor");
816                                                   YYERROR;
817                                         }
818                                         r.dst.port[0] = $6.dst.port->port[0];
819                                         r.dst.port[1] = $6.dst.port->port[1];
820                                         r.dst.port_op = $6.dst.port->op;
821                               }
822 
823                               expand_rule(&r, $3, NULL, $5, $6.src_os,
824                                   $6.src.host, $6.src.port, $6.dst.host, $6.dst.port,
825                                   0, 0, 0, $2);
826                               free($2);
827                     }
828                     | BINATANCHOR string interface af proto fromto rtable {
829                               struct pf_rule      r;
830 
831                               if (check_rulestate(PFCTL_STATE_NAT)) {
832                                         free($2);
833                                         YYERROR;
834                               }
835 
836                               memset(&r, 0, sizeof(r));
837                               r.action = PF_BINAT;
838                               r.af = $4;
839                               r.rtableid = $7;
840                               if ($5 != NULL) {
841                                         if ($5->next != NULL) {
842                                                   yyerror("proto list expansion"
843                                                       " not supported in binat-anchor");
844                                                   YYERROR;
845                                         }
846                                         r.proto = $5->proto;
847                                         free($5);
848                               }
849 
850                               if ($6.src.host != NULL || $6.src.port != NULL ||
851                                   $6.dst.host != NULL || $6.dst.port != NULL) {
852                                         yyerror("fromto parameter not supported"
853                                             " in binat-anchor");
854                                         YYERROR;
855                               }
856 
857                               decide_address_family($6.src.host, &r.af);
858                               decide_address_family($6.dst.host, &r.af);
859 
860                               pfctl_add_rule(pf, &r, $2);
861                               free($2);
862                     }
863                     ;
864 
865 loadrule  : LOAD ANCHOR string FROM string        {
866                               struct loadanchors  *loadanchor;
867 
868                               if (strlen(pf->anchor->name) + 1 +
869                                   strlen($3) >= MAXPATHLEN) {
870                                         yyerror("anchorname %s too long, max %u\n",
871                                             $3, MAXPATHLEN - 1);
872                                         free($3);
873                                         YYERROR;
874                               }
875                               loadanchor = calloc(1, sizeof(struct loadanchors));
876                               if (loadanchor == NULL)
877                                         err(1, "loadrule: calloc");
878                               if ((loadanchor->anchorname = malloc(MAXPATHLEN)) ==
879                                   NULL)
880                                         err(1, "loadrule: malloc");
881                               if (pf->anchor->name[0])
882                                         snprintf(loadanchor->anchorname, MAXPATHLEN,
883                                             "%s/%s", pf->anchor->name, $3);
884                               else
885                                         strlcpy(loadanchor->anchorname, $3, MAXPATHLEN);
886                               if ((loadanchor->filename = strdup($5)) == NULL)
887                                         err(1, "loadrule: strdup");
888 
889                               TAILQ_INSERT_TAIL(&loadanchorshead, loadanchor,
890                                   entries);
891 
892                               free($3);
893                               free($5);
894                     };
895 
896 scrubaction         : no SCRUB {
897                               $$.b2 = $$.w = 0;
898                               if ($1)
899                                         $$.b1 = PF_NOSCRUB;
900                               else
901                                         $$.b1 = PF_SCRUB;
902                     }
903                     ;
904 
905 scrubrule : scrubaction dir logquick interface af proto fromto scrub_opts
906                     {
907                               struct pf_rule      r;
908 
909                               if (check_rulestate(PFCTL_STATE_SCRUB))
910                                         YYERROR;
911 
912                               memset(&r, 0, sizeof(r));
913 
914                               r.action = $1.b1;
915                               r.direction = $2;
916 
917                               r.log = $3.log;
918                               r.logif = $3.logif;
919                               if ($3.quick) {
920                                         yyerror("scrub rules do not support 'quick'");
921                                         YYERROR;
922                               }
923 
924                               r.af = $5;
925                               if ($8.nodf)
926                                         r.rule_flag |= PFRULE_NODF;
927                               if ($8.randomid)
928                                         r.rule_flag |= PFRULE_RANDOMID;
929                               if ($8.reassemble_tcp) {
930                                         if (r.direction != PF_INOUT) {
931                                                   yyerror("reassemble tcp rules can not "
932                                                       "specify direction");
933                                                   YYERROR;
934                                         }
935                                         r.rule_flag |= PFRULE_REASSEMBLE_TCP;
936                               }
937                               if ($8.minttl)
938                                         r.min_ttl = $8.minttl;
939                               if ($8.maxmss)
940                                         r.max_mss = $8.maxmss;
941                               if ($8.fragcache)
942                                         r.rule_flag |= $8.fragcache;
943                               r.rtableid = $8.rtableid;
944 
945                               expand_rule(&r, $4, NULL, $6, $7.src_os,
946                                   $7.src.host, $7.src.port, $7.dst.host, $7.dst.port,
947                                   NULL, NULL, NULL, "");
948                     }
949                     ;
950 
951 scrub_opts          :         {
952                                         bzero(&scrub_opts, sizeof scrub_opts);
953                                         scrub_opts.rtableid = -1;
954                               }
955                         scrub_opts_l
956                               { $$ = scrub_opts; }
957                     | /* empty */ {
958                               bzero(&scrub_opts, sizeof scrub_opts);
959                               scrub_opts.rtableid = -1;
960                               $$ = scrub_opts;
961                     }
962                     ;
963 
964 scrub_opts_l        : scrub_opts_l scrub_opt
965                     | scrub_opt
966                     ;
967 
968 scrub_opt : NODF    {
969                               if (scrub_opts.nodf) {
970                                         yyerror("no-df cannot be respecified");
971                                         YYERROR;
972                               }
973                               scrub_opts.nodf = 1;
974                     }
975                     | MINTTL number {
976                               if (scrub_opts.marker & SOM_MINTTL) {
977                                         yyerror("min-ttl cannot be respecified");
978                                         YYERROR;
979                               }
980                               if ($2 > 255) {
981                                         yyerror("illegal min-ttl value %d", $2);
982                                         YYERROR;
983                               }
984                               scrub_opts.marker |= SOM_MINTTL;
985                               scrub_opts.minttl = $2;
986                     }
987                     | MAXMSS number {
988                               if (scrub_opts.marker & SOM_MAXMSS) {
989                                         yyerror("max-mss cannot be respecified");
990                                         YYERROR;
991                               }
992                               if ($2 > 65535) {
993                                         yyerror("illegal max-mss value %d", $2);
994                                         YYERROR;
995                               }
996                               scrub_opts.marker |= SOM_MAXMSS;
997                               scrub_opts.maxmss = $2;
998                     }
999                     | fragcache {
1000                               if (scrub_opts.marker & SOM_FRAGCACHE) {
1001                                         yyerror("fragcache cannot be respecified");
1002                                         YYERROR;
1003                               }
1004                               scrub_opts.marker |= SOM_FRAGCACHE;
1005                               scrub_opts.fragcache = $1;
1006                     }
1007                     | REASSEMBLE STRING {
1008                               if (strcasecmp($2, "tcp") != 0) {
1009                                         yyerror("scrub reassemble supports only tcp, "
1010                                             "not '%s'", $2);
1011                                         free($2);
1012                                         YYERROR;
1013                               }
1014                               free($2);
1015                               if (scrub_opts.reassemble_tcp) {
1016                                         yyerror("reassemble tcp cannot be respecified");
1017                                         YYERROR;
1018                               }
1019                               scrub_opts.reassemble_tcp = 1;
1020                     }
1021                     | RANDOMID {
1022                               if (scrub_opts.randomid) {
1023                                         yyerror("random-id cannot be respecified");
1024                                         YYERROR;
1025                               }
1026                               scrub_opts.randomid = 1;
1027                     }
1028                     | RTABLE number                                   {
1029                               if ($2 > RT_TABLEID_MAX || $2 < 0) {
1030                                         yyerror("invalid rtable id");
1031                                         YYERROR;
1032                               }
1033                               scrub_opts.rtableid = $2;
1034                     }
1035                     ;
1036 
1037 fragcache : FRAGMENT REASSEMBLE         { $$ = 0; /* default */ }
1038                     | FRAGMENT FRAGCROP { $$ = PFRULE_FRAGCROP; }
1039                     | FRAGMENT FRAGDROP { $$ = PFRULE_FRAGDROP; }
1040                     ;
1041 
1042 antispoof : ANTISPOOF logquick antispoof_ifspc af antispoof_opts {
1043                               struct pf_rule                 r;
1044                               struct node_host    *h = NULL, *hh;
1045                               struct node_if                *i, *j;
1046 
1047                               if (check_rulestate(PFCTL_STATE_FILTER))
1048                                         YYERROR;
1049 
1050                               for (i = $3; i; i = i->next) {
1051                                         bzero(&r, sizeof(r));
1052 
1053                                         r.action = PF_DROP;
1054                                         r.direction = PF_IN;
1055                                         r.log = $2.log;
1056                                         r.logif = $2.logif;
1057                                         r.quick = $2.quick;
1058                                         r.af = $4;
1059                                         if (rule_label(&r, $5.label))
1060                                                   YYERROR;
1061                                         r.rtableid = $5.rtableid;
1062                                         j = calloc(1, sizeof(struct node_if));
1063                                         if (j == NULL)
1064                                                   err(1, "antispoof: calloc");
1065                                         if (strlcpy(j->ifname, i->ifname,
1066                                             sizeof(j->ifname)) >= sizeof(j->ifname)) {
1067                                                   free(j);
1068                                                   yyerror("interface name too long");
1069                                                   YYERROR;
1070                                         }
1071                                         j->not = 1;
1072                                         if (i->dynamic) {
1073                                                   h = calloc(1, sizeof(*h));
1074                                                   if (h == NULL)
1075                                                             err(1, "address: calloc");
1076                                                   h->addr.type = PF_ADDR_DYNIFTL;
1077                                                   set_ipmask(h, 128);
1078                                                   if (strlcpy(h->addr.v.ifname, i->ifname,
1079                                                       sizeof(h->addr.v.ifname)) >=
1080                                                       sizeof(h->addr.v.ifname)) {
1081                                                             free(h);
1082                                                             yyerror(
1083                                                                 "interface name too long");
1084                                                             YYERROR;
1085                                                   }
1086                                                   hh = malloc(sizeof(*hh));
1087                                                   if (hh == NULL)
1088                                                              err(1, "address: malloc");
1089                                                   bcopy(h, hh, sizeof(*hh));
1090                                                   h->addr.iflags = PFI_AFLAG_NETWORK;
1091                                         } else {
1092                                                   h = ifa_lookup(j->ifname,
1093                                                       PFI_AFLAG_NETWORK);
1094                                                   hh = NULL;
1095                                         }
1096 
1097                                         if (h != NULL)
1098                                                   expand_rule(&r, j, NULL, NULL, NULL, h,
1099                                                       NULL, NULL, NULL, NULL, NULL,
1100                                                       NULL, "");
1101 
1102                                         if ((i->ifa_flags & IFF_LOOPBACK) == 0) {
1103                                                   bzero(&r, sizeof(r));
1104 
1105                                                   r.action = PF_DROP;
1106                                                   r.direction = PF_IN;
1107                                                   r.log = $2.log;
1108                                                   r.quick = $2.quick;
1109                                                   r.af = $4;
1110                                                   if (rule_label(&r, $5.label))
1111                                                             YYERROR;
1112                                                   r.rtableid = $5.rtableid;
1113                                                   if (hh != NULL)
1114                                                             h = hh;
1115                                                   else
1116                                                             h = ifa_lookup(i->ifname, 0);
1117                                                   if (h != NULL)
1118                                                             expand_rule(&r, NULL, NULL,
1119                                                                 NULL, NULL, h, NULL, NULL,
1120                                                                 NULL, NULL, NULL, NULL, "");
1121                                         } else
1122                                                   free(hh);
1123                               }
1124                               free($5.label);
1125                     }
1126                     ;
1127 
1128 antispoof_ifspc     : FOR antispoof_if            { $$ = $2; }
1129                     | FOR '{' antispoof_iflst '}' { $$ = $3; }
1130                     ;
1131 
1132 antispoof_iflst     : antispoof_if                                    { $$ = $1; }
1133                     | antispoof_iflst comma antispoof_if    {
1134                               $1->tail->next = $3;
1135                               $1->tail = $3;
1136                               $$ = $1;
1137                     }
1138                     ;
1139 
1140 antispoof_if  : if_item                                     { $$ = $1; }
1141                     | '(' if_item ')'             {
1142                               $2->dynamic = 1;
1143                               $$ = $2;
1144                     }
1145                     ;
1146 
1147 antispoof_opts      :         {
1148                                         bzero(&antispoof_opts, sizeof antispoof_opts);
1149                                         antispoof_opts.rtableid = -1;
1150                               }
1151                         antispoof_opts_l
1152                               { $$ = antispoof_opts; }
1153                     | /* empty */       {
1154                               bzero(&antispoof_opts, sizeof antispoof_opts);
1155                               antispoof_opts.rtableid = -1;
1156                               $$ = antispoof_opts;
1157                     }
1158                     ;
1159 
1160 antispoof_opts_l    : antispoof_opts_l antispoof_opt
1161                               | antispoof_opt
1162                               ;
1163 
1164 antispoof_opt       : label   {
1165                               if (antispoof_opts.label) {
1166                                         yyerror("label cannot be redefined");
1167                                         YYERROR;
1168                               }
1169                               antispoof_opts.label = $1;
1170                     }
1171                     | RTABLE number                                   {
1172                               if ($2 > RT_TABLEID_MAX || $2 < 0) {
1173                                         yyerror("invalid rtable id");
1174                                         YYERROR;
1175                               }
1176                               antispoof_opts.rtableid = $2;
1177                     }
1178                     ;
1179 
1180 not                 : '!'               { $$ = 1; }
1181                     | /* empty */       { $$ = 0; }
1182                     ;
1183 
1184 tabledef  : TABLE '<' STRING '>' table_opts {
1185                               struct node_host     *h, *nh;
1186                               struct node_tinit    *ti, *nti;
1187 
1188                               if (strlen($3) >= PF_TABLE_NAME_SIZE) {
1189                                         yyerror("table name too long, max %d chars",
1190                                             PF_TABLE_NAME_SIZE - 1);
1191                                         free($3);
1192                                         YYERROR;
1193                               }
1194                               if (pf->loadopt & PFCTL_FLAG_TABLE)
1195                                         if (process_tabledef($3, &$5)) {
1196                                                   free($3);
1197                                                   YYERROR;
1198                                         }
1199                               free($3);
1200                               for (ti = SIMPLEQ_FIRST(&$5.init_nodes);
1201                                   ti != NULL; ti = nti) {
1202                                         if (ti->file)
1203                                                   free(ti->file);
1204                                         for (h = ti->host; h != NULL; h = nh) {
1205                                                   nh = h->next;
1206                                                   free(h);
1207                                         }
1208                                         nti = SIMPLEQ_NEXT(ti, entries);
1209                                         free(ti);
1210                               }
1211                     }
1212                     ;
1213 
1214 table_opts          :         {
1215                               bzero(&table_opts, sizeof table_opts);
1216                               SIMPLEQ_INIT(&table_opts.init_nodes);
1217                     }
1218                         table_opts_l
1219                               { $$ = table_opts; }
1220                     | /* empty */
1221                               {
1222                               bzero(&table_opts, sizeof table_opts);
1223                               SIMPLEQ_INIT(&table_opts.init_nodes);
1224                               $$ = table_opts;
1225                     }
1226                     ;
1227 
1228 table_opts_l        : table_opts_l table_opt
1229                     | table_opt
1230                     ;
1231 
1232 table_opt : STRING            {
1233                               if (!strcmp($1, "const"))
1234                                         table_opts.flags |= PFR_TFLAG_CONST;
1235                               else if (!strcmp($1, "persist"))
1236                                         table_opts.flags |= PFR_TFLAG_PERSIST;
1237                               else {
1238                                         yyerror("invalid table option '%s'", $1);
1239                                         free($1);
1240                                         YYERROR;
1241                               }
1242                               free($1);
1243                     }
1244                     | '{' '}'           { table_opts.init_addr = 1; }
1245                     | '{' host_list '}' {
1246                               struct node_host    *n;
1247                               struct node_tinit   *ti;
1248 
1249                               for (n = $2; n != NULL; n = n->next) {
1250                                         switch (n->addr.type) {
1251                                         case PF_ADDR_ADDRMASK:
1252                                                   continue; /* ok */
1253                                         case PF_ADDR_DYNIFTL:
1254                                                   yyerror("dynamic addresses are not "
1255                                                       "permitted inside tables");
1256                                                   break;
1257                                         case PF_ADDR_TABLE:
1258                                                   yyerror("tables cannot contain tables");
1259                                                   break;
1260                                         case PF_ADDR_NOROUTE:
1261                                                   yyerror("\"no-route\" is not permitted "
1262                                                       "inside tables");
1263                                                   break;
1264                                         case PF_ADDR_URPFFAILED:
1265                                                   yyerror("\"urpf-failed\" is not "
1266                                                       "permitted inside tables");
1267                                                   break;
1268                                         default:
1269                                                   yyerror("unknown address type %d",
1270                                                       n->addr.type);
1271                                         }
1272                                         YYERROR;
1273                               }
1274                               if (!(ti = calloc(1, sizeof(*ti))))
1275                                         err(1, "table_opt: calloc");
1276                               ti->host = $2;
1277                               SIMPLEQ_INSERT_TAIL(&table_opts.init_nodes, ti,
1278                                   entries);
1279                               table_opts.init_addr = 1;
1280                     }
1281                     | FILENAME STRING   {
1282                               struct node_tinit   *ti;
1283 
1284                               if (!(ti = calloc(1, sizeof(*ti))))
1285                                         err(1, "table_opt: calloc");
1286                               ti->file = $2;
1287                               SIMPLEQ_INSERT_TAIL(&table_opts.init_nodes, ti,
1288                                   entries);
1289                               table_opts.init_addr = 1;
1290                     }
1291                     ;
1292 
1293 altqif              : ALTQ interface queue_opts QUEUE qassign {
1294                               struct pf_altq      a;
1295 
1296                               if (check_rulestate(PFCTL_STATE_QUEUE))
1297                                         YYERROR;
1298 
1299                               memset(&a, 0, sizeof(a));
1300                               if ($3.scheduler.qtype == ALTQT_NONE) {
1301                                         yyerror("no scheduler specified!");
1302                                         YYERROR;
1303                               }
1304                               a.scheduler = $3.scheduler.qtype;
1305                               a.qlimit = $3.qlimit;
1306                               a.tbrsize = $3.tbrsize;
1307                               if ($5 == NULL) {
1308                                         yyerror("no child queues specified");
1309                                         YYERROR;
1310                               }
1311                               if (expand_altq(&a, $2, $5, $3.queue_bwspec,
1312                                   &$3.scheduler))
1313                                         YYERROR;
1314                     }
1315                     ;
1316 
1317 queuespec : QUEUE STRING interface queue_opts qassign {
1318                               struct pf_altq      a;
1319 
1320                               if (check_rulestate(PFCTL_STATE_QUEUE)) {
1321                                         free($2);
1322                                         YYERROR;
1323                               }
1324 
1325                               memset(&a, 0, sizeof(a));
1326 
1327                               if (strlcpy(a.qname, $2, sizeof(a.qname)) >=
1328                                   sizeof(a.qname)) {
1329                                         yyerror("queue name too long (max "
1330                                             "%d chars)", PF_QNAME_SIZE-1);
1331                                         free($2);
1332                                         YYERROR;
1333                               }
1334                               free($2);
1335                               if ($4.tbrsize) {
1336                                         yyerror("cannot specify tbrsize for queue");
1337                                         YYERROR;
1338                               }
1339                               if ($4.priority > 255) {
1340                                         yyerror("priority out of range: max 255");
1341                                         YYERROR;
1342                               }
1343                               a.priority = $4.priority;
1344                               a.qlimit = $4.qlimit;
1345                               a.scheduler = $4.scheduler.qtype;
1346                               if (expand_queue(&a, $3, $5, $4.queue_bwspec,
1347                                   &$4.scheduler)) {
1348                                         yyerror("errors in queue definition");
1349                                         YYERROR;
1350                               }
1351                     }
1352                     ;
1353 
1354 queue_opts          :         {
1355                               bzero(&queue_opts, sizeof queue_opts);
1356                               queue_opts.priority = DEFAULT_PRIORITY;
1357                               queue_opts.qlimit = DEFAULT_QLIMIT;
1358                               queue_opts.scheduler.qtype = ALTQT_NONE;
1359                               queue_opts.queue_bwspec.bw_percent = 100;
1360                     }
1361                         queue_opts_l
1362                               { $$ = queue_opts; }
1363                     | /* empty */ {
1364                               bzero(&queue_opts, sizeof queue_opts);
1365                               queue_opts.priority = DEFAULT_PRIORITY;
1366                               queue_opts.qlimit = DEFAULT_QLIMIT;
1367                               queue_opts.scheduler.qtype = ALTQT_NONE;
1368                               queue_opts.queue_bwspec.bw_percent = 100;
1369                               $$ = queue_opts;
1370                     }
1371                     ;
1372 
1373 queue_opts_l        : queue_opts_l queue_opt
1374                     | queue_opt
1375                     ;
1376 
1377 queue_opt : BANDWIDTH bandwidth         {
1378                               if (queue_opts.marker & QOM_BWSPEC) {
1379                                         yyerror("bandwidth cannot be respecified");
1380                                         YYERROR;
1381                               }
1382                               queue_opts.marker |= QOM_BWSPEC;
1383                               queue_opts.queue_bwspec = $2;
1384                     }
1385                     | PRIORITY number   {
1386                               if (queue_opts.marker & QOM_PRIORITY) {
1387                                         yyerror("priority cannot be respecified");
1388                                         YYERROR;
1389                               }
1390                               if ($2 > 255) {
1391                                         yyerror("priority out of range: max 255");
1392                                         YYERROR;
1393                               }
1394                               queue_opts.marker |= QOM_PRIORITY;
1395                               queue_opts.priority = $2;
1396                     }
1397                     | QLIMIT number     {
1398                               if (queue_opts.marker & QOM_QLIMIT) {
1399                                         yyerror("qlimit cannot be respecified");
1400                                         YYERROR;
1401                               }
1402                               if ($2 > 65535) {
1403                                         yyerror("qlimit out of range: max 65535");
1404                                         YYERROR;
1405                               }
1406                               queue_opts.marker |= QOM_QLIMIT;
1407                               queue_opts.qlimit = $2;
1408                     }
1409                     | scheduler         {
1410                               if (queue_opts.marker & QOM_SCHEDULER) {
1411                                         yyerror("scheduler cannot be respecified");
1412                                         YYERROR;
1413                               }
1414                               queue_opts.marker |= QOM_SCHEDULER;
1415                               queue_opts.scheduler = $1;
1416                     }
1417                     | TBRSIZE number    {
1418                               if (queue_opts.marker & QOM_TBRSIZE) {
1419                                         yyerror("tbrsize cannot be respecified");
1420                                         YYERROR;
1421                               }
1422                               if ($2 > 65535) {
1423                                         yyerror("tbrsize too big: max 65535");
1424                                         YYERROR;
1425                               }
1426                               queue_opts.marker |= QOM_TBRSIZE;
1427                               queue_opts.tbrsize = $2;
1428                     }
1429                     ;
1430 
1431 bandwidth : STRING {
1432                               double     bps;
1433                               char      *cp;
1434 
1435                               $$.bw_percent = 0;
1436 
1437                               bps = strtod($1, &cp);
1438                               if (cp != NULL) {
1439                                         if (!strcmp(cp, "b"))
1440                                                   ; /* nothing */
1441                                         else if (!strcmp(cp, "Kb"))
1442                                                   bps *= 1000;
1443                                         else if (!strcmp(cp, "Mb"))
1444                                                   bps *= 1000 * 1000;
1445                                         else if (!strcmp(cp, "Gb"))
1446                                                   bps *= 1000 * 1000 * 1000;
1447                                         else if (!strcmp(cp, "%")) {
1448                                                   if (bps < 0 || bps > 100) {
1449                                                             yyerror("bandwidth spec "
1450                                                                 "out of range");
1451                                                             free($1);
1452                                                             YYERROR;
1453                                                   }
1454                                                   $$.bw_percent = bps;
1455                                                   bps = 0;
1456                                         } else {
1457                                                   yyerror("unknown unit %s", cp);
1458                                                   free($1);
1459                                                   YYERROR;
1460                                         }
1461                               }
1462                               free($1);
1463                               $$.bw_absolute = (u_int32_t)bps;
1464                     }
1465                     ;
1466 
1467 scheduler : CBQ                                   {
1468                               $$.qtype = ALTQT_CBQ;
1469                               $$.data.cbq_opts.flags = 0;
1470                     }
1471                     | CBQ '(' cbqflags_list ')'   {
1472                               $$.qtype = ALTQT_CBQ;
1473                               $$.data.cbq_opts.flags = $3;
1474                     }
1475                     | PRIQ                                  {
1476                               $$.qtype = ALTQT_PRIQ;
1477                               $$.data.priq_opts.flags = 0;
1478                     }
1479                     | PRIQ '(' priqflags_list ')' {
1480                               $$.qtype = ALTQT_PRIQ;
1481                               $$.data.priq_opts.flags = $3;
1482                     }
1483                     | HFSC                                  {
1484                               $$.qtype = ALTQT_HFSC;
1485                               bzero(&$$.data.hfsc_opts,
1486                                   sizeof(struct node_hfsc_opts));
1487                     }
1488                     | HFSC '(' hfsc_opts ')'      {
1489                               $$.qtype = ALTQT_HFSC;
1490                               $$.data.hfsc_opts = $3;
1491                     }
1492                     ;
1493 
1494 cbqflags_list       : cbqflags_item                                   { $$ |= $1; }
1495                     | cbqflags_list comma cbqflags_item     { $$ |= $3; }
1496                     ;
1497 
1498 cbqflags_item       : STRING  {
1499                               if (!strcmp($1, "default"))
1500                                         $$ = CBQCLF_DEFCLASS;
1501 #ifdef CBQCLF_BORROW
1502                               else if (!strcmp($1, "borrow"))
1503                                         $$ = CBQCLF_BORROW;
1504 #endif
1505                               else if (!strcmp($1, "red"))
1506                                         $$ = CBQCLF_RED;
1507                               else if (!strcmp($1, "ecn"))
1508                                         $$ = CBQCLF_RED|CBQCLF_ECN;
1509                               else if (!strcmp($1, "rio"))
1510                                         $$ = CBQCLF_RIO;
1511                               else {
1512                                         yyerror("unknown cbq flag \"%s\"", $1);
1513                                         free($1);
1514                                         YYERROR;
1515                               }
1516                               free($1);
1517                     }
1518                     ;
1519 
1520 priqflags_list      : priqflags_item                        { $$ |= $1; }
1521                     | priqflags_list comma priqflags_item   { $$ |= $3; }
1522                     ;
1523 
1524 priqflags_item      : STRING  {
1525                               if (!strcmp($1, "default"))
1526                                         $$ = PRCF_DEFAULTCLASS;
1527                               else if (!strcmp($1, "red"))
1528                                         $$ = PRCF_RED;
1529                               else if (!strcmp($1, "ecn"))
1530                                         $$ = PRCF_RED|PRCF_ECN;
1531                               else if (!strcmp($1, "rio"))
1532                                         $$ = PRCF_RIO;
1533                               else {
1534                                         yyerror("unknown priq flag \"%s\"", $1);
1535                                         free($1);
1536                                         YYERROR;
1537                               }
1538                               free($1);
1539                     }
1540                     ;
1541 
1542 hfsc_opts :         {
1543                                         bzero(&hfsc_opts,
1544                                             sizeof(struct node_hfsc_opts));
1545                               }
1546                         hfscopts_list                                 {
1547                               $$ = hfsc_opts;
1548                     }
1549                     ;
1550 
1551 hfscopts_list       : hfscopts_item
1552                     | hfscopts_list comma hfscopts_item
1553                     ;
1554 
1555 hfscopts_item       : LINKSHARE bandwidth                                       {
1556                               if (hfsc_opts.linkshare.used) {
1557                                         yyerror("linkshare already specified");
1558                                         YYERROR;
1559                               }
1560                               hfsc_opts.linkshare.m2 = $2;
1561                               hfsc_opts.linkshare.used = 1;
1562                     }
1563                     | LINKSHARE '(' bandwidth comma number comma bandwidth ')'
1564                         {
1565                               if (hfsc_opts.linkshare.used) {
1566                                         yyerror("linkshare already specified");
1567                                         YYERROR;
1568                               }
1569                               hfsc_opts.linkshare.m1 = $3;
1570                               hfsc_opts.linkshare.d = $5;
1571                               hfsc_opts.linkshare.m2 = $7;
1572                               hfsc_opts.linkshare.used = 1;
1573                     }
1574                     | REALTIME bandwidth                                        {
1575                               if (hfsc_opts.realtime.used) {
1576                                         yyerror("realtime already specified");
1577                                         YYERROR;
1578                               }
1579                               hfsc_opts.realtime.m2 = $2;
1580                               hfsc_opts.realtime.used = 1;
1581                     }
1582                     | REALTIME '(' bandwidth comma number comma bandwidth ')'
1583                         {
1584                               if (hfsc_opts.realtime.used) {
1585                                         yyerror("realtime already specified");
1586                                         YYERROR;
1587                               }
1588                               hfsc_opts.realtime.m1 = $3;
1589                               hfsc_opts.realtime.d = $5;
1590                               hfsc_opts.realtime.m2 = $7;
1591                               hfsc_opts.realtime.used = 1;
1592                     }
1593                     | UPPERLIMIT bandwidth                                      {
1594                               if (hfsc_opts.upperlimit.used) {
1595                                         yyerror("upperlimit already specified");
1596                                         YYERROR;
1597                               }
1598                               hfsc_opts.upperlimit.m2 = $2;
1599                               hfsc_opts.upperlimit.used = 1;
1600                     }
1601                     | UPPERLIMIT '(' bandwidth comma number comma bandwidth ')'
1602                         {
1603                               if (hfsc_opts.upperlimit.used) {
1604                                         yyerror("upperlimit already specified");
1605                                         YYERROR;
1606                               }
1607                               hfsc_opts.upperlimit.m1 = $3;
1608                               hfsc_opts.upperlimit.d = $5;
1609                               hfsc_opts.upperlimit.m2 = $7;
1610                               hfsc_opts.upperlimit.used = 1;
1611                     }
1612                     | STRING  {
1613                               if (!strcmp($1, "default"))
1614                                         hfsc_opts.flags |= HFCF_DEFAULTCLASS;
1615                               else if (!strcmp($1, "red"))
1616                                         hfsc_opts.flags |= HFCF_RED;
1617                               else if (!strcmp($1, "ecn"))
1618                                         hfsc_opts.flags |= HFCF_RED|HFCF_ECN;
1619                               else if (!strcmp($1, "rio"))
1620                                         hfsc_opts.flags |= HFCF_RIO;
1621                               else {
1622                                         yyerror("unknown hfsc flag \"%s\"", $1);
1623                                         free($1);
1624                                         YYERROR;
1625                               }
1626                               free($1);
1627                     }
1628                     ;
1629 
1630 qassign             : /* empty */                 { $$ = NULL; }
1631                     | qassign_item                { $$ = $1; }
1632                     | '{' qassign_list '}'        { $$ = $2; }
1633                     ;
1634 
1635 qassign_list        : qassign_item                          { $$ = $1; }
1636                     | qassign_list comma qassign_item       {
1637                               $1->tail->next = $3;
1638                               $1->tail = $3;
1639                               $$ = $1;
1640                     }
1641                     ;
1642 
1643 qassign_item        : STRING                      {
1644                               $$ = calloc(1, sizeof(struct node_queue));
1645                               if ($$ == NULL)
1646                                         err(1, "qassign_item: calloc");
1647                               if (strlcpy($$->queue, $1, sizeof($$->queue)) >=
1648                                   sizeof($$->queue)) {
1649                                         yyerror("queue name '%s' too long (max "
1650                                             "%d chars)", $1, sizeof($$->queue)-1);
1651                                         free($1);
1652                                         free($$);
1653                                         YYERROR;
1654                               }
1655                               free($1);
1656                               $$->next = NULL;
1657                               $$->tail = $$;
1658                     }
1659                     ;
1660 
1661 pfrule              : action dir logquick interface route af proto fromto
1662                         filter_opts
1663                     {
1664                               struct pf_rule                 r;
1665                               struct node_state_opt         *o;
1666                               struct node_proto   *proto;
1667                               int                            srctrack = 0;
1668                               int                            statelock = 0;
1669                               int                            adaptive = 0;
1670 
1671                               if (check_rulestate(PFCTL_STATE_FILTER))
1672                                         YYERROR;
1673 
1674                               memset(&r, 0, sizeof(r));
1675 
1676                               r.action = $1.b1;
1677                               switch ($1.b2) {
1678                               case PFRULE_RETURNRST:
1679                                         r.rule_flag |= PFRULE_RETURNRST;
1680                                         r.return_ttl = $1.w;
1681                                         break;
1682                               case PFRULE_RETURNICMP:
1683                                         r.rule_flag |= PFRULE_RETURNICMP;
1684                                         r.return_icmp = $1.w;
1685                                         r.return_icmp6 = $1.w2;
1686                                         break;
1687                               case PFRULE_RETURN:
1688                                         r.rule_flag |= PFRULE_RETURN;
1689                                         r.return_icmp = $1.w;
1690                                         r.return_icmp6 = $1.w2;
1691                                         break;
1692                               }
1693                               r.direction = $2;
1694                               r.log = $3.log;
1695                               r.logif = $3.logif;
1696                               r.quick = $3.quick;
1697                               r.prob = $9.prob;
1698                               r.rtableid = $9.rtableid;
1699 
1700                               r.af = $6;
1701                               if ($9.tag)
1702                                         if (strlcpy(r.tagname, $9.tag,
1703                                             PF_TAG_NAME_SIZE) >= PF_TAG_NAME_SIZE) {
1704                                                   yyerror("tag too long, max %u chars",
1705                                                       PF_TAG_NAME_SIZE - 1);
1706                                                   YYERROR;
1707                                         }
1708                               if ($9.match_tag)
1709                                         if (strlcpy(r.match_tagname, $9.match_tag,
1710                                             PF_TAG_NAME_SIZE) >= PF_TAG_NAME_SIZE) {
1711                                                   yyerror("tag too long, max %u chars",
1712                                                       PF_TAG_NAME_SIZE - 1);
1713                                                   YYERROR;
1714                                         }
1715                               r.match_tag_not = $9.match_tag_not;
1716                               if (rule_label(&r, $9.label))
1717                                         YYERROR;
1718                               free($9.label);
1719                               r.flags = $9.flags.b1;
1720                               r.flagset = $9.flags.b2;
1721                               if (($9.flags.b1 & $9.flags.b2) != $9.flags.b1) {
1722                                         yyerror("flags always false");
1723                                         YYERROR;
1724                               }
1725                               if ($9.flags.b1 || $9.flags.b2 || $8.src_os) {
1726                                         for (proto = $7; proto != NULL &&
1727                                             proto->proto != IPPROTO_TCP;
1728                                             proto = proto->next)
1729                                                   ;         /* nothing */
1730                                         if (proto == NULL && $7 != NULL) {
1731                                                   if ($9.flags.b1 || $9.flags.b2)
1732                                                             yyerror(
1733                                                                 "flags only apply to tcp");
1734                                                   if ($8.src_os)
1735                                                             yyerror(
1736                                                                 "OS fingerprinting only "
1737                                                                 "apply to tcp");
1738                                                   YYERROR;
1739                                         }
1740 #if 0
1741                                         if (($9.flags.b1 & parse_flags("S")) == 0 &&
1742                                             $8.src_os) {
1743                                                   yyerror("OS fingerprinting requires "
1744                                                       "the SYN TCP flag (flags S/SA)");
1745                                                   YYERROR;
1746                                         }
1747 #endif
1748                               }
1749 
1750                               r.tos = $9.tos;
1751                               r.keep_state = $9.keep.action;
1752 
1753                               /* 'keep state' by default on pass rules. */
1754                               if (!r.keep_state && !r.action &&
1755                                   !($9.marker & FOM_KEEP))
1756                                         r.keep_state = PF_STATE_NORMAL;
1757 
1758                               o = $9.keep.options;
1759                               while (o) {
1760                                         struct node_state_opt         *p = o;
1761 
1762                                         switch (o->type) {
1763                                         case PF_STATE_OPT_MAX:
1764                                                   if (r.max_states) {
1765                                                             yyerror("state option 'max' "
1766                                                                 "multiple definitions");
1767                                                             YYERROR;
1768                                                   }
1769                                                   r.max_states = o->data.max_states;
1770                                                   break;
1771                                         case PF_STATE_OPT_NOSYNC:
1772                                                   if (r.rule_flag & PFRULE_NOSYNC) {
1773                                                             yyerror("state option 'sync' "
1774                                                                 "multiple definitions");
1775                                                             YYERROR;
1776                                                   }
1777                                                   r.rule_flag |= PFRULE_NOSYNC;
1778                                                   break;
1779                                         case PF_STATE_OPT_SRCTRACK:
1780                                                   if (srctrack) {
1781                                                             yyerror("state option "
1782                                                                 "'source-track' "
1783                                                                 "multiple definitions");
1784                                                             YYERROR;
1785                                                   }
1786                                                   srctrack =  o->data.src_track;
1787                                                   r.rule_flag |= PFRULE_SRCTRACK;
1788                                                   break;
1789                                         case PF_STATE_OPT_MAX_SRC_STATES:
1790                                                   if (r.max_src_states) {
1791                                                             yyerror("state option "
1792                                                                 "'max-src-states' "
1793                                                                 "multiple definitions");
1794                                                             YYERROR;
1795                                                   }
1796                                                   if (o->data.max_src_states == 0) {
1797                                                             yyerror("'max-src-states' must "
1798                                                                 "be > 0");
1799                                                             YYERROR;
1800                                                   }
1801                                                   r.max_src_states =
1802                                                       o->data.max_src_states;
1803                                                   r.rule_flag |= PFRULE_SRCTRACK;
1804                                                   break;
1805                                         case PF_STATE_OPT_OVERLOAD:
1806                                                   if (r.overload_tblname[0]) {
1807                                                             yyerror("multiple 'overload' "
1808                                                                 "table definitions");
1809                                                             YYERROR;
1810                                                   }
1811                                                   if (strlcpy(r.overload_tblname,
1812                                                       o->data.overload.tblname,
1813                                                       PF_TABLE_NAME_SIZE) >=
1814                                                       PF_TABLE_NAME_SIZE) {
1815                                                             yyerror("state option: "
1816                                                                 "strlcpy");
1817                                                             YYERROR;
1818                                                   }
1819                                                   r.flush = o->data.overload.flush;
1820                                                   break;
1821                                         case PF_STATE_OPT_MAX_SRC_CONN:
1822                                                   if (r.max_src_conn) {
1823                                                             yyerror("state option "
1824                                                                 "'max-src-conn' "
1825                                                                 "multiple definitions");
1826                                                             YYERROR;
1827                                                   }
1828                                                   if (o->data.max_src_conn == 0) {
1829                                                             yyerror("'max-src-conn' "
1830                                                                 "must be > 0");
1831                                                             YYERROR;
1832                                                   }
1833                                                   r.max_src_conn =
1834                                                       o->data.max_src_conn;
1835                                                   r.rule_flag |= PFRULE_SRCTRACK |
1836                                                       PFRULE_RULESRCTRACK;
1837                                                   break;
1838                                         case PF_STATE_OPT_MAX_SRC_CONN_RATE:
1839                                                   if (r.max_src_conn_rate.limit) {
1840                                                             yyerror("state option "
1841                                                                 "'max-src-conn-rate' "
1842                                                                 "multiple definitions");
1843                                                             YYERROR;
1844                                                   }
1845                                                   if (!o->data.max_src_conn_rate.limit ||
1846                                                       !o->data.max_src_conn_rate.seconds) {
1847                                                             yyerror("'max-src-conn-rate' "
1848                                                                 "values must be > 0");
1849                                                             YYERROR;
1850                                                   }
1851                                                   if (o->data.max_src_conn_rate.limit >
1852                                                       PF_THRESHOLD_MAX) {
1853                                                             yyerror("'max-src-conn-rate' "
1854                                                                 "maximum rate must be < %u",
1855                                                                 PF_THRESHOLD_MAX);
1856                                                             YYERROR;
1857                                                   }
1858                                                   r.max_src_conn_rate.limit =
1859                                                       o->data.max_src_conn_rate.limit;
1860                                                   r.max_src_conn_rate.seconds =
1861                                                       o->data.max_src_conn_rate.seconds;
1862                                                   r.rule_flag |= PFRULE_SRCTRACK |
1863                                                       PFRULE_RULESRCTRACK;
1864                                                   break;
1865                                         case PF_STATE_OPT_MAX_SRC_NODES:
1866                                                   if (r.max_src_nodes) {
1867                                                             yyerror("state option "
1868                                                                 "'max-src-nodes' "
1869                                                                 "multiple definitions");
1870                                                             YYERROR;
1871                                                   }
1872                                                   if (o->data.max_src_nodes == 0) {
1873                                                             yyerror("'max-src-nodes' must "
1874                                                                 "be > 0");
1875                                                             YYERROR;
1876                                                   }
1877                                                   r.max_src_nodes =
1878                                                       o->data.max_src_nodes;
1879                                                   r.rule_flag |= PFRULE_SRCTRACK |
1880                                                       PFRULE_RULESRCTRACK;
1881                                                   break;
1882                                         case PF_STATE_OPT_STATELOCK:
1883                                                   if (statelock) {
1884                                                             yyerror("state locking option: "
1885                                                                 "multiple definitions");
1886                                                             YYERROR;
1887                                                   }
1888                                                   statelock = 1;
1889                                                   r.rule_flag |= o->data.statelock;
1890                                                   break;
1891                                         case PF_STATE_OPT_TIMEOUT:
1892                                                   if (o->data.timeout.number ==
1893                                                       PFTM_ADAPTIVE_START ||
1894                                                       o->data.timeout.number ==
1895                                                       PFTM_ADAPTIVE_END)
1896                                                             adaptive = 1;
1897                                                   if (r.timeout[o->data.timeout.number]) {
1898                                                             yyerror("state timeout %s "
1899                                                                 "multiple definitions",
1900                                                                 pf_timeouts[o->data.
1901                                                                 timeout.number].name);
1902                                                             YYERROR;
1903                                                   }
1904                                                   r.timeout[o->data.timeout.number] =
1905                                                       o->data.timeout.seconds;
1906                                         }
1907                                         o = o->next;
1908                                         free(p);
1909                               }
1910 
1911                               /* 'flags S/SA' by default on stateful rules */
1912                               if (!r.action && !r.flags && !r.flagset &&
1913                                   !$9.fragment && !($9.marker & FOM_FLAGS) &&
1914                                   r.keep_state) {
1915                                         r.flags = parse_flags("S");
1916                                         r.flagset =  parse_flags("SA");
1917                               }
1918                               if (!adaptive && r.max_states) {
1919                                         r.timeout[PFTM_ADAPTIVE_START] =
1920                                             (r.max_states / 10) * 6;
1921                                         r.timeout[PFTM_ADAPTIVE_END] =
1922                                             (r.max_states / 10) * 12;
1923                               }
1924                               if (r.rule_flag & PFRULE_SRCTRACK) {
1925                                         if (srctrack == PF_SRCTRACK_GLOBAL &&
1926                                             r.max_src_nodes) {
1927                                                   yyerror("'max-src-nodes' is "
1928                                                       "incompatible with "
1929                                                       "'source-track global'");
1930                                                   YYERROR;
1931                                         }
1932                                         if (srctrack == PF_SRCTRACK_GLOBAL &&
1933                                             r.max_src_conn) {
1934                                                   yyerror("'max-src-conn' is "
1935                                                       "incompatible with "
1936                                                       "'source-track global'");
1937                                                   YYERROR;
1938                                         }
1939                                         if (srctrack == PF_SRCTRACK_GLOBAL &&
1940                                             r.max_src_conn_rate.seconds) {
1941                                                   yyerror("'max-src-conn-rate' is "
1942                                                       "incompatible with "
1943                                                       "'source-track global'");
1944                                                   YYERROR;
1945                                         }
1946                                         if (r.timeout[PFTM_SRC_NODE] <
1947                                             r.max_src_conn_rate.seconds)
1948                                                   r.timeout[PFTM_SRC_NODE] =
1949                                                       r.max_src_conn_rate.seconds;
1950                                         r.rule_flag |= PFRULE_SRCTRACK;
1951                                         if (srctrack == PF_SRCTRACK_RULE)
1952                                                   r.rule_flag |= PFRULE_RULESRCTRACK;
1953                               }
1954                               if (r.keep_state && !statelock)
1955                                         r.rule_flag |= default_statelock;
1956 
1957                               if ($9.fragment)
1958                                         r.rule_flag |= PFRULE_FRAGMENT;
1959                               r.allow_opts = $9.allowopts;
1960 
1961                               decide_address_family($8.src.host, &r.af);
1962                               decide_address_family($8.dst.host, &r.af);
1963 
1964                               if ($5.rt) {
1965                                         if (!r.direction) {
1966                                                   yyerror("direction must be explicit "
1967                                                       "with rules that specify routing");
1968                                                   YYERROR;
1969                                         }
1970                                         r.rt = $5.rt;
1971                                         r.rpool.opts = $5.pool_opts;
1972                                         if ($5.key != NULL)
1973                                                   memcpy(&r.rpool.key, $5.key,
1974                                                       sizeof(struct pf_poolhashkey));
1975                               }
1976                               if (r.rt && r.rt != PF_FASTROUTE) {
1977                                         decide_address_family($5.host, &r.af);
1978                                         remove_invalid_hosts(&$5.host, &r.af);
1979                                         if ($5.host == NULL) {
1980                                                   yyerror("no routing address with "
1981                                                       "matching address family found.");
1982                                                   YYERROR;
1983                                         }
1984                                         if ((r.rpool.opts & PF_POOL_TYPEMASK) ==
1985                                             PF_POOL_NONE && ($5.host->next != NULL ||
1986                                             $5.host->addr.type == PF_ADDR_TABLE ||
1987                                             DYNIF_MULTIADDR($5.host->addr)))
1988                                                   r.rpool.opts |= PF_POOL_ROUNDROBIN;
1989                                         if ((r.rpool.opts & PF_POOL_TYPEMASK) !=
1990                                             PF_POOL_ROUNDROBIN &&
1991                                             disallow_table($5.host, "tables are only "
1992                                             "supported in round-robin routing pools"))
1993                                                   YYERROR;
1994                                         if ((r.rpool.opts & PF_POOL_TYPEMASK) !=
1995                                             PF_POOL_ROUNDROBIN &&
1996                                             disallow_alias($5.host, "interface (%s) "
1997                                             "is only supported in round-robin "
1998                                             "routing pools"))
1999                                                   YYERROR;
2000                                         if ($5.host->next != NULL) {
2001                                                   if ((r.rpool.opts & PF_POOL_TYPEMASK) !=
2002                                                       PF_POOL_ROUNDROBIN) {
2003                                                             yyerror("r.rpool.opts must "
2004                                                                 "be PF_POOL_ROUNDROBIN");
2005                                                             YYERROR;
2006                                                   }
2007                                         }
2008                               }
2009                               if ($9.queues.qname != NULL) {
2010                                         if (strlcpy(r.qname, $9.queues.qname,
2011                                             sizeof(r.qname)) >= sizeof(r.qname)) {
2012                                                   yyerror("rule qname too long (max "
2013                                                       "%d chars)", sizeof(r.qname)-1);
2014                                                   YYERROR;
2015                                         }
2016                                         free($9.queues.qname);
2017                               }
2018                               if ($9.queues.pqname != NULL) {
2019                                         if (strlcpy(r.pqname, $9.queues.pqname,
2020                                             sizeof(r.pqname)) >= sizeof(r.pqname)) {
2021                                                   yyerror("rule pqname too long (max "
2022                                                       "%d chars)", sizeof(r.pqname)-1);
2023                                                   YYERROR;
2024                                         }
2025                                         free($9.queues.pqname);
2026                               }
2027 
2028                               expand_rule(&r, $4, $5.host, $7, $8.src_os,
2029                                   $8.src.host, $8.src.port, $8.dst.host, $8.dst.port,
2030                                   $9.uid, $9.gid, $9.icmpspec, "");
2031                     }
2032                     ;
2033 
2034 opt_statelock       : statelock
2035                     {
2036                               $$ = calloc(1, sizeof(struct node_state_opt));
2037                               if ($$ == NULL)
2038                                         err(EXIT_FAILURE, "opt_statelock: calloc");
2039                               $$->type = PF_STATE_OPT_STATELOCK;
2040                               $$->data.statelock = $1;
2041                               $$->next = NULL;
2042                               $$->tail = $$;
2043                     }
2044                     | /* empty */       {
2045                               $$ = NULL;
2046                     }
2047                     ;
2048 
2049 filter_opts         :         {
2050                                         bzero(&filter_opts, sizeof filter_opts);
2051                                         filter_opts.rtableid = -1;
2052                               }
2053                         filter_opts_l
2054                               { $$ = filter_opts; }
2055                     | /* empty */       {
2056                               bzero(&filter_opts, sizeof filter_opts);
2057                               filter_opts.rtableid = -1;
2058                               $$ = filter_opts;
2059                     }
2060                     ;
2061 
2062 filter_opts_l       : filter_opts_l filter_opt
2063                     | filter_opt
2064                     ;
2065 
2066 filter_opt          : USER uids {
2067                               if (filter_opts.uid)
2068                                         $2->tail->next = filter_opts.uid;
2069                               filter_opts.uid = $2;
2070                     }
2071                     | GROUP gids {
2072                               if (filter_opts.gid)
2073                                         $2->tail->next = filter_opts.gid;
2074                               filter_opts.gid = $2;
2075                     }
2076                     | flags {
2077                               if (filter_opts.marker & FOM_FLAGS) {
2078                                         yyerror("flags cannot be redefined");
2079                                         YYERROR;
2080                               }
2081                               filter_opts.marker |= FOM_FLAGS;
2082                               filter_opts.flags.b1 |= $1.b1;
2083                               filter_opts.flags.b2 |= $1.b2;
2084                               filter_opts.flags.w |= $1.w;
2085                               filter_opts.flags.w2 |= $1.w2;
2086                     }
2087                     | icmpspec {
2088                               if (filter_opts.marker & FOM_ICMP) {
2089                                         yyerror("icmp-type cannot be redefined");
2090                                         YYERROR;
2091                               }
2092                               filter_opts.marker |= FOM_ICMP;
2093                               filter_opts.icmpspec = $1;
2094                     }
2095                     | tos {
2096                               if (filter_opts.marker & FOM_TOS) {
2097                                         yyerror("tos cannot be redefined");
2098                                         YYERROR;
2099                               }
2100                               filter_opts.marker |= FOM_TOS;
2101                               filter_opts.tos = $1;
2102                     }
2103                     | keep {
2104                               if (filter_opts.marker & FOM_KEEP) {
2105                                         yyerror("modulate or keep cannot be redefined");
2106                                         YYERROR;
2107                               }
2108                               filter_opts.marker |= FOM_KEEP;
2109                               filter_opts.keep.action = $1.action;
2110                               filter_opts.keep.options = $1.options;
2111                     }
2112                     | FRAGMENT {
2113                               filter_opts.fragment = 1;
2114                     }
2115                     | ALLOWOPTS {
2116                               filter_opts.allowopts = 1;
2117                     }
2118                     | label   {
2119                               if (filter_opts.label) {
2120                                         yyerror("label cannot be redefined");
2121                                         YYERROR;
2122                               }
2123                               filter_opts.label = $1;
2124                     }
2125                     | qname   {
2126                               if (filter_opts.queues.qname) {
2127                                         yyerror("queue cannot be redefined");
2128                                         YYERROR;
2129                               }
2130                               filter_opts.queues = $1;
2131                     }
2132                     | TAG string                                      {
2133                               filter_opts.tag = $2;
2134                     }
2135                     | not TAGGED string                     {
2136                               filter_opts.match_tag = $3;
2137                               filter_opts.match_tag_not = $1;
2138                     }
2139                     | PROBABILITY STRING                              {
2140                               char      *e;
2141                               double     p = strtod($2, &e);
2142 
2143                               if (*e == '%') {
2144                                         p *= 0.01;
2145                                         e++;
2146                               }
2147                               if (*e) {
2148                                         yyerror("invalid probability: %s", $2);
2149                                         free($2);
2150                                         YYERROR;
2151                               }
2152                               p = floor(p * (UINT_MAX+1.0) + 0.5);
2153                               if (p < 1.0 || p >= (UINT_MAX+1.0)) {
2154                                         yyerror("invalid probability: %s", $2);
2155                                         free($2);
2156                                         YYERROR;
2157                               }
2158                               filter_opts.prob = (u_int32_t)p;
2159                               free($2);
2160                     }
2161                     | RTABLE number                                   {
2162                               if ($2 > RT_TABLEID_MAX || $2 < 0) {
2163                                         yyerror("invalid rtable id");
2164                                         YYERROR;
2165                               }
2166                               filter_opts.rtableid = $2;
2167                     }
2168                     ;
2169 
2170 action              : PASS                        { $$.b1 = PF_PASS; $$.b2 = $$.w = 0; }
2171                     | BLOCK blockspec   { $$ = $2; $$.b1 = PF_DROP; }
2172                     ;
2173 
2174 blockspec : /* empty */                 {
2175                               $$.b2 = blockpolicy;
2176                               $$.w = returnicmpdefault;
2177                               $$.w2 = returnicmp6default;
2178                     }
2179                     | DROP                        {
2180                               $$.b2 = PFRULE_DROP;
2181                               $$.w = 0;
2182                               $$.w2 = 0;
2183                     }
2184                     | RETURNRST                   {
2185                               $$.b2 = PFRULE_RETURNRST;
2186                               $$.w = 0;
2187                               $$.w2 = 0;
2188                     }
2189                     | RETURNRST '(' TTL number ')'          {
2190                               if ($4 > 255) {
2191                                         yyerror("illegal ttl value %d", $4);
2192                                         YYERROR;
2193                               }
2194                               $$.b2 = PFRULE_RETURNRST;
2195                               $$.w = $4;
2196                               $$.w2 = 0;
2197                     }
2198                     | RETURNICMP                  {
2199                               $$.b2 = PFRULE_RETURNICMP;
2200                               $$.w = returnicmpdefault;
2201                               $$.w2 = returnicmp6default;
2202                     }
2203                     | RETURNICMP6                 {
2204                               $$.b2 = PFRULE_RETURNICMP;
2205                               $$.w = returnicmpdefault;
2206                               $$.w2 = returnicmp6default;
2207                     }
2208                     | RETURNICMP '(' STRING ')'   {
2209                               $$.b2 = PFRULE_RETURNICMP;
2210                               if (!($$.w = parseicmpspec($3, AF_INET))) {
2211                                         free($3);
2212                                         YYERROR;
2213                               }
2214                               free($3);
2215                               $$.w2 = returnicmp6default;
2216                     }
2217                     | RETURNICMP6 '(' STRING ')'  {
2218                               $$.b2 = PFRULE_RETURNICMP;
2219                               $$.w = returnicmpdefault;
2220                               if (!($$.w2 = parseicmpspec($3, AF_INET6))) {
2221                                         free($3);
2222                                         YYERROR;
2223                               }
2224                               free($3);
2225                     }
2226                     | RETURNICMP '(' STRING comma STRING ')' {
2227                               $$.b2 = PFRULE_RETURNICMP;
2228                               if (!($$.w = parseicmpspec($3, AF_INET)) ||
2229                                   !($$.w2 = parseicmpspec($5, AF_INET6))) {
2230                                         free($3);
2231                                         free($5);
2232                                         YYERROR;
2233                               }
2234                               free($3);
2235                               free($5);
2236                     }
2237                     | RETURN {
2238                               $$.b2 = PFRULE_RETURN;
2239                               $$.w = returnicmpdefault;
2240                               $$.w2 = returnicmp6default;
2241                     }
2242                     ;
2243 
2244 dir                 : /* empty */                           { $$ = 0; }
2245                     | IN                                    { $$ = PF_IN; }
2246                     | OUT                                   { $$ = PF_OUT; }
2247                     ;
2248 
2249 quick               : /* empty */                           { $$.quick = 0; }
2250                     | QUICK                                 { $$.quick = 1; }
2251                     ;
2252 
2253 logquick  : /* empty */       { $$.log = 0; $$.quick = 0; $$.logif = 0; }
2254                     | log               { $$ = $1; $$.quick = 0; }
2255                     | QUICK             { $$.quick = 1; $$.log = 0; $$.logif = 0; }
2256                     | log QUICK         { $$ = $1; $$.quick = 1; }
2257                     | QUICK log         { $$ = $2; $$.quick = 1; }
2258                     ;
2259 
2260 log                 : LOG                         { $$.log = PF_LOG; $$.logif = 0; }
2261                     | LOG '(' logopts ')'         {
2262                               $$.log = PF_LOG | $3.log;
2263                               $$.logif = $3.logif;
2264                     }
2265                     ;
2266 
2267 logopts             : logopt                      { $$ = $1; }
2268                     | logopts comma logopt                  {
2269                               $$.log = $1.log | $3.log;
2270                               $$.logif = $3.logif;
2271                               if ($$.logif == 0)
2272                                         $$.logif = $1.logif;
2273                     }
2274                     ;
2275 
2276 logopt              : ALL               { $$.log = PF_LOG_ALL; $$.logif = 0; }
2277                     | USER              { $$.log = PF_LOG_SOCKET_LOOKUP; $$.logif = 0; }
2278                     | GROUP             { $$.log = PF_LOG_SOCKET_LOOKUP; $$.logif = 0; }
2279                     | TO string         {
2280                               const char          *errstr = NULL; /* XXX gcc */
2281                               u_int                i;
2282 
2283                               $$.log = 0;
2284                               if (strncmp($2, "pflog", 5)) {
2285                                         yyerror("%s: should be a pflog interface", $2);
2286                                         free($2);
2287                                         YYERROR;
2288                               }
2289                               i = strtonum($2 + 5, 0, 255, &errstr);
2290                               if (errstr) {
2291                                         yyerror("%s: %s", $2, errstr);
2292                                         free($2);
2293                                         YYERROR;
2294                               }
2295                               free($2);
2296                               $$.logif = i;
2297                     }
2298                     ;
2299 
2300 interface : /* empty */                           { $$ = NULL; }
2301                     | ON if_item_not              { $$ = $2; }
2302                     | ON '{' if_list '}'                    { $$ = $3; }
2303                     ;
2304 
2305 if_list             : if_item_not                           { $$ = $1; }
2306                     | if_list comma if_item_not   {
2307                               $1->tail->next = $3;
2308                               $1->tail = $3;
2309                               $$ = $1;
2310                     }
2311                     ;
2312 
2313 if_item_not         : not if_item                           { $$ = $2; $$->not = $1; }
2314                     ;
2315 
2316 if_item             : STRING                      {
2317                               struct node_host    *n;
2318 
2319                               $$ = calloc(1, sizeof(struct node_if));
2320                               if ($$ == NULL)
2321                                         err(1, "if_item: calloc");
2322                               if (strlcpy($$->ifname, $1, sizeof($$->ifname)) >=
2323                                   sizeof($$->ifname)) {
2324                                         free($1);
2325                                         free($$);
2326                                         yyerror("interface name too long");
2327                                         YYERROR;
2328                               }
2329 
2330                               if ((n = ifa_exists($1)) != NULL)
2331                                         $$->ifa_flags = n->ifa_flags;
2332 
2333                               free($1);
2334                               $$->not = 0;
2335                               $$->next = NULL;
2336                               $$->tail = $$;
2337                     }
2338                     ;
2339 
2340 af                  : /* empty */                           { $$ = 0; }
2341                     | INET                                  { $$ = AF_INET; }
2342                     | INET6                                 { $$ = AF_INET6; }
2343                     ;
2344 
2345 proto               : /* empty */                           { $$ = NULL; }
2346                     | PROTO proto_item            { $$ = $2; }
2347                     | PROTO '{' proto_list '}'    { $$ = $3; }
2348                     ;
2349 
2350 proto_list          : proto_item                            { $$ = $1; }
2351                     | proto_list comma proto_item {
2352                               $1->tail->next = $3;
2353                               $1->tail = $3;
2354                               $$ = $1;
2355                     }
2356                     ;
2357 
2358 proto_item          : STRING                      {
2359                               u_int8_t  pr;
2360                               u_long              ulval;
2361 
2362                               if (atoul($1, &ulval) == 0) {
2363                                         if (ulval > 255) {
2364                                                   yyerror("protocol outside range");
2365                                                   free($1);
2366                                                   YYERROR;
2367                                         }
2368                                         pr = (u_int8_t)ulval;
2369                               } else {
2370                                         struct protoent     *p;
2371 
2372                                         p = getprotobyname($1);
2373                                         if (p == NULL) {
2374                                                   yyerror("unknown protocol %s", $1);
2375                                                   free($1);
2376                                                   YYERROR;
2377                                         }
2378                                         pr = p->p_proto;
2379                               }
2380                               free($1);
2381                               if (pr == 0) {
2382                                         yyerror("proto 0 cannot be used");
2383                                         YYERROR;
2384                               }
2385                               $$ = calloc(1, sizeof(struct node_proto));
2386                               if ($$ == NULL)
2387                                         err(1, "proto_item: calloc");
2388                               $$->proto = pr;
2389                               $$->next = NULL;
2390                               $$->tail = $$;
2391                     }
2392                     ;
2393 
2394 fromto              : ALL                                   {
2395                               $$.src.host = NULL;
2396                               $$.src.port = NULL;
2397                               $$.dst.host = NULL;
2398                               $$.dst.port = NULL;
2399                               $$.src_os = NULL;
2400                     }
2401                     | from os to                            {
2402                               $$.src = $1;
2403                               $$.src_os = $2;
2404                               $$.dst = $3;
2405                     }
2406                     ;
2407 
2408 os                  : /* empty */                           { $$ = NULL; }
2409                     | OS xos                      { $$ = $2; }
2410                     | OS '{' os_list '}'                    { $$ = $3; }
2411                     ;
2412 
2413 xos                 : STRING {
2414                               $$ = calloc(1, sizeof(struct node_os));
2415                               if ($$ == NULL)
2416                                         err(1, "os: calloc");
2417                               $$->os = $1;
2418                               $$->tail = $$;
2419                     }
2420                     ;
2421 
2422 os_list             : xos                                   { $$ = $1; }
2423                     | os_list comma xos           {
2424                               $1->tail->next = $3;
2425                               $1->tail = $3;
2426                               $$ = $1;
2427                     }
2428                     ;
2429 
2430 from                : /* empty */                           {
2431                               $$.host = NULL;
2432                               $$.port = NULL;
2433                     }
2434                     | FROM ipportspec             {
2435                               $$ = $2;
2436                     }
2437                     ;
2438 
2439 to                  : /* empty */                           {
2440                               $$.host = NULL;
2441                               $$.port = NULL;
2442                     }
2443                     | TO ipportspec               {
2444                               if (disallow_urpf_failed($2.host, "\"urpf-failed\" is "
2445                                   "not permitted in a destination address"))
2446                                         YYERROR;
2447                               $$ = $2;
2448                     }
2449                     ;
2450 
2451 ipportspec          : ipspec                      {
2452                               $$.host = $1;
2453                               $$.port = NULL;
2454                     }
2455                     | ipspec PORT portspec                  {
2456                               $$.host = $1;
2457                               $$.port = $3;
2458                     }
2459                     | PORT portspec                         {
2460                               $$.host = NULL;
2461                               $$.port = $2;
2462                     }
2463                     ;
2464 
2465 ipspec              : ANY                                   { $$ = NULL; }
2466                     | xhost                                 { $$ = $1; }
2467                     | '{' host_list '}'           { $$ = $2; }
2468                     ;
2469 
2470 host_list : ipspec                      { $$ = $1; }
2471                     | host_list comma ipspec      {
2472                               if ($3 == NULL)
2473                                         $$ = $1;
2474                               else if ($1 == NULL)
2475                                         $$ = $3;
2476                               else {
2477                                         $1->tail->next = $3;
2478                                         $1->tail = $3->tail;
2479                                         $$ = $1;
2480                               }
2481                     }
2482                     ;
2483 
2484 xhost               : not host                              {
2485                               struct node_host    *n;
2486 
2487                               for (n = $2; n != NULL; n = n->next)
2488                                         n->not = $1;
2489                               $$ = $2;
2490                     }
2491                     | not NOROUTE                           {
2492                               $$ = calloc(1, sizeof(struct node_host));
2493                               if ($$ == NULL)
2494                                         err(1, "xhost: calloc");
2495                               $$->addr.type = PF_ADDR_NOROUTE;
2496                               $$->next = NULL;
2497                               $$->not = $1;
2498                               $$->tail = $$;
2499                     }
2500                     | not URPFFAILED              {
2501                               $$ = calloc(1, sizeof(struct node_host));
2502                               if ($$ == NULL)
2503                                         err(1, "xhost: calloc");
2504                               $$->addr.type = PF_ADDR_URPFFAILED;
2505                               $$->next = NULL;
2506                               $$->not = $1;
2507                               $$->tail = $$;
2508                     }
2509                     ;
2510 
2511 host                : STRING                      {
2512                               if (($$ = host($1)) == NULL)  {
2513                                         /* error. "any" is handled elsewhere */
2514                                         free($1);
2515                                         yyerror("could not parse host specification");
2516                                         YYERROR;
2517                               }
2518                               free($1);
2519 
2520                     }
2521                     | STRING '/' number           {
2522                               char      *buf;
2523 
2524                               if (asprintf(&buf, "%s/%u", $1, $3) == -1)
2525                                         err(1, "host: asprintf");
2526                               free($1);
2527                               if (($$ = host(buf)) == NULL) {
2528                                         /* error. "any" is handled elsewhere */
2529                                         free(buf);
2530                                         yyerror("could not parse host specification");
2531                                         YYERROR;
2532                               }
2533                               free(buf);
2534                     }
2535                     | dynaddr
2536                     | dynaddr '/' number                    {
2537                               struct node_host    *n;
2538 
2539                               $$ = $1;
2540                               for (n = $1; n != NULL; n = n->next)
2541                                         set_ipmask(n, $3);
2542                     }
2543                     | '<' STRING '>'    {
2544                               if (strlen($2) >= PF_TABLE_NAME_SIZE) {
2545                                         yyerror("table name '%s' too long", $2);
2546                                         free($2);
2547                                         YYERROR;
2548                               }
2549                               $$ = calloc(1, sizeof(struct node_host));
2550                               if ($$ == NULL)
2551                                         err(1, "host: calloc");
2552                               $$->addr.type = PF_ADDR_TABLE;
2553                               if (strlcpy($$->addr.v.tblname, $2,
2554                                   sizeof($$->addr.v.tblname)) >=
2555                                   sizeof($$->addr.v.tblname))
2556                                         errx(1, "host: strlcpy");
2557                               free($2);
2558                               $$->next = NULL;
2559                               $$->tail = $$;
2560                     }
2561                     | ROUTE   STRING              {
2562                               $$ = calloc(1, sizeof(struct node_host));
2563                               if ($$ == NULL) {
2564                                         free($2);
2565                                         err(1, "host: calloc");
2566                               }
2567                               $$->addr.type = PF_ADDR_RTLABEL;
2568                               if (strlcpy($$->addr.v.rtlabelname, $2,
2569                                   sizeof($$->addr.v.rtlabelname)) >=
2570                                   sizeof($$->addr.v.rtlabelname)) {
2571                                         yyerror("route label too long, max %u chars",
2572                                             sizeof($$->addr.v.rtlabelname) - 1);
2573                                         free($2);
2574                                         free($$);
2575                                         YYERROR;
2576                               }
2577                               $$->next = NULL;
2578                               $$->tail = $$;
2579                               free($2);
2580                     }
2581                     ;
2582 
2583 number              : STRING                      {
2584                               u_long    ulval;
2585 
2586                               if (atoul($1, &ulval) == -1) {
2587                                         yyerror("%s is not a number", $1);
2588                                         free($1);
2589                                         YYERROR;
2590                               } else
2591                                         $$ = ulval;
2592                               free($1);
2593                     }
2594                     ;
2595 
2596 dynaddr             : '(' STRING ')'              {
2597                               int        flags = 0;
2598                               char      *p, *op;
2599 
2600                               op = $2;
2601                               if (!isalpha((unsigned char)op[0])) {
2602                                         yyerror("invalid interface name '%s'", op);
2603                                         free(op);
2604                                         YYERROR;
2605                               }
2606                               while ((p = strrchr($2, ':')) != NULL) {
2607                                         if (!strcmp(p+1, "network"))
2608                                                   flags |= PFI_AFLAG_NETWORK;
2609                                         else if (!strcmp(p+1, "broadcast"))
2610                                                   flags |= PFI_AFLAG_BROADCAST;
2611                                         else if (!strcmp(p+1, "peer"))
2612                                                   flags |= PFI_AFLAG_PEER;
2613                                         else if (!strcmp(p+1, "0"))
2614                                                   flags |= PFI_AFLAG_NOALIAS;
2615                                         else {
2616                                                   yyerror("interface %s has bad modifier",
2617                                                       $2);
2618                                                   free(op);
2619                                                   YYERROR;
2620                                         }
2621                                         *p = '\0';
2622                               }
2623                               if (flags & (flags - 1) & PFI_AFLAG_MODEMASK) {
2624                                         free(op);
2625                                         yyerror("illegal combination of "
2626                                             "interface modifiers");
2627                                         YYERROR;
2628                               }
2629                               $$ = calloc(1, sizeof(struct node_host));
2630                               if ($$ == NULL)
2631                                         err(1, "address: calloc");
2632                               $$->af = 0;
2633                               set_ipmask($$, 128);
2634                               $$->addr.type = PF_ADDR_DYNIFTL;
2635                               $$->addr.iflags = flags;
2636                               if (strlcpy($$->addr.v.ifname, $2,
2637                                   sizeof($$->addr.v.ifname)) >=
2638                                   sizeof($$->addr.v.ifname)) {
2639                                         free(op);
2640                                         free($$);
2641                                         yyerror("interface name too long");
2642                                         YYERROR;
2643                               }
2644                               free(op);
2645                               $$->next = NULL;
2646                               $$->tail = $$;
2647                     }
2648                     ;
2649 
2650 portspec  : port_item                             { $$ = $1; }
2651                     | '{' port_list '}'           { $$ = $2; }
2652                     ;
2653 
2654 port_list : port_item                             { $$ = $1; }
2655                     | port_list comma port_item   {
2656                               $1->tail->next = $3;
2657                               $1->tail = $3;
2658                               $$ = $1;
2659                     }
2660                     ;
2661 
2662 port_item : port                                  {
2663                               $$ = calloc(1, sizeof(struct node_port));
2664                               if ($$ == NULL)
2665                                         err(1, "port_item: calloc");
2666                               $$->port[0] = $1.a;
2667                               $$->port[1] = $1.b;
2668                               if ($1.t)
2669                                         $$->op = PF_OP_RRG;
2670                               else
2671                                         $$->op = PF_OP_EQ;
2672                               $$->next = NULL;
2673                               $$->tail = $$;
2674                     }
2675                     | unaryop port                {
2676                               if ($2.t) {
2677                                         yyerror("':' cannot be used with an other "
2678                                             "port operator");
2679                                         YYERROR;
2680                               }
2681                               $$ = calloc(1, sizeof(struct node_port));
2682                               if ($$ == NULL)
2683                                         err(1, "port_item: calloc");
2684                               $$->port[0] = $2.a;
2685                               $$->port[1] = $2.b;
2686                               $$->op = $1;
2687                               $$->next = NULL;
2688                               $$->tail = $$;
2689                     }
2690                     | port PORTBINARY port                  {
2691                               if ($1.t || $3.t) {
2692                                         yyerror("':' cannot be used with an other "
2693                                             "port operator");
2694                                         YYERROR;
2695                               }
2696                               $$ = calloc(1, sizeof(struct node_port));
2697                               if ($$ == NULL)
2698                                         err(1, "port_item: calloc");
2699                               $$->port[0] = $1.a;
2700                               $$->port[1] = $3.a;
2701                               $$->op = $2;
2702                               $$->next = NULL;
2703                               $$->tail = $$;
2704                     }
2705                     ;
2706 
2707 port                : STRING                      {
2708                               char      *p = strchr($1, ':');
2709 
2710                               if (p == NULL) {
2711                                         if (($$.a = getservice($1)) == -1) {
2712                                                   free($1);
2713                                                   YYERROR;
2714                                         }
2715                                         $$.b = $$.t = 0;
2716                               } else {
2717                                         int port[2];
2718 
2719                                         *p++ = 0;
2720                                         if ((port[0] = getservice($1)) == -1 ||
2721                                             (port[1] = getservice(p)) == -1) {
2722                                                   free($1);
2723                                                   YYERROR;
2724                                         }
2725                                         $$.a = port[0];
2726                                         $$.b = port[1];
2727                                         $$.t = PF_OP_RRG;
2728                               }
2729                               free($1);
2730                     }
2731                     ;
2732 
2733 uids                : uid_item                              { $$ = $1; }
2734                     | '{' uid_list '}'            { $$ = $2; }
2735                     ;
2736 
2737 uid_list  : uid_item                              { $$ = $1; }
2738                     | uid_list comma uid_item     {
2739                               $1->tail->next = $3;
2740                               $1->tail = $3;
2741                               $$ = $1;
2742                     }
2743                     ;
2744 
2745 uid_item  : uid                                   {
2746                               $$ = calloc(1, sizeof(struct node_uid));
2747                               if ($$ == NULL)
2748                                         err(1, "uid_item: calloc");
2749                               $$->uid[0] = $1;
2750                               $$->uid[1] = $1;
2751                               $$->op = PF_OP_EQ;
2752                               $$->next = NULL;
2753                               $$->tail = $$;
2754                     }
2755                     | unaryop uid                           {
2756                               if ($2 == UID_MAX && $1 != PF_OP_EQ && $1 != PF_OP_NE) {
2757                                         yyerror("user unknown requires operator = or "
2758                                             "!=");
2759                                         YYERROR;
2760                               }
2761                               $$ = calloc(1, sizeof(struct node_uid));
2762                               if ($$ == NULL)
2763                                         err(1, "uid_item: calloc");
2764                               $$->uid[0] = $2;
2765                               $$->uid[1] = $2;
2766                               $$->op = $1;
2767                               $$->next = NULL;
2768                               $$->tail = $$;
2769                     }
2770                     | uid PORTBINARY uid                    {
2771                               if ($1 == UID_MAX || $3 == UID_MAX) {
2772                                         yyerror("user unknown requires operator = or "
2773                                             "!=");
2774                                         YYERROR;
2775                               }
2776                               $$ = calloc(1, sizeof(struct node_uid));
2777                               if ($$ == NULL)
2778                                         err(1, "uid_item: calloc");
2779                               $$->uid[0] = $1;
2780                               $$->uid[1] = $3;
2781                               $$->op = $2;
2782                               $$->next = NULL;
2783                               $$->tail = $$;
2784                     }
2785                     ;
2786 
2787 uid                 : STRING                      {
2788                               u_long    ulval;
2789 
2790                               if (atoul($1, &ulval) == -1) {
2791                                         if (!strcmp($1, "unknown"))
2792                                                   $$ = UID_MAX;
2793                                         else {
2794                                                   struct passwd       *pw;
2795 
2796                                                   if ((pw = getpwnam($1)) == NULL) {
2797                                                             yyerror("unknown user %s", $1);
2798                                                             free($1);
2799                                                             YYERROR;
2800                                                   }
2801                                                   $$ = pw->pw_uid;
2802                                         }
2803                               } else {
2804                                         if (ulval >= UID_MAX) {
2805                                                   free($1);
2806                                                   yyerror("illegal uid value %lu", ulval);
2807                                                   YYERROR;
2808                                         }
2809                                         $$ = ulval;
2810                               }
2811                               free($1);
2812                     }
2813                     ;
2814 
2815 gids                : gid_item                              { $$ = $1; }
2816                     | '{' gid_list '}'            { $$ = $2; }
2817                     ;
2818 
2819 gid_list  : gid_item                              { $$ = $1; }
2820                     | gid_list comma gid_item     {
2821                               $1->tail->next = $3;
2822                               $1->tail = $3;
2823                               $$ = $1;
2824                     }
2825                     ;
2826 
2827 gid_item  : gid                                   {
2828                               $$ = calloc(1, sizeof(struct node_gid));
2829                               if ($$ == NULL)
2830                                         err(1, "gid_item: calloc");
2831                               $$->gid[0] = $1;
2832                               $$->gid[1] = $1;
2833                               $$->op = PF_OP_EQ;
2834                               $$->next = NULL;
2835                               $$->tail = $$;
2836                     }
2837                     | unaryop gid                           {
2838                               if ($2 == GID_MAX && $1 != PF_OP_EQ && $1 != PF_OP_NE) {
2839                                         yyerror("group unknown requires operator = or "
2840                                             "!=");
2841                                         YYERROR;
2842                               }
2843                               $$ = calloc(1, sizeof(struct node_gid));
2844                               if ($$ == NULL)
2845                                         err(1, "gid_item: calloc");
2846                               $$->gid[0] = $2;
2847                               $$->gid[1] = $2;
2848                               $$->op = $1;
2849                               $$->next = NULL;
2850                               $$->tail = $$;
2851                     }
2852                     | gid PORTBINARY gid                    {
2853                               if ($1 == GID_MAX || $3 == GID_MAX) {
2854                                         yyerror("group unknown requires operator = or "
2855                                             "!=");
2856                                         YYERROR;
2857                               }
2858                               $$ = calloc(1, sizeof(struct node_gid));
2859                               if ($$ == NULL)
2860                                         err(1, "gid_item: calloc");
2861                               $$->gid[0] = $1;
2862                               $$->gid[1] = $3;
2863                               $$->op = $2;
2864                               $$->next = NULL;
2865                               $$->tail = $$;
2866                     }
2867                     ;
2868 
2869 gid                 : STRING                      {
2870                               u_long    ulval;
2871 
2872                               if (atoul($1, &ulval) == -1) {
2873                                         if (!strcmp($1, "unknown"))
2874                                                   $$ = GID_MAX;
2875                                         else {
2876                                                   struct group        *grp;
2877 
2878                                                   if ((grp = getgrnam($1)) == NULL) {
2879                                                             yyerror("unknown group %s", $1);
2880                                                             free($1);
2881                                                             YYERROR;
2882                                                   }
2883                                                   $$ = grp->gr_gid;
2884                                         }
2885                               } else {
2886                                         if (ulval >= GID_MAX) {
2887                                                   yyerror("illegal gid value %lu", ulval);
2888                                                   free($1);
2889                                                   YYERROR;
2890                                         }
2891                                         $$ = ulval;
2892                               }
2893                               free($1);
2894                     }
2895                     ;
2896 
2897 flag                : STRING                      {
2898                               int       f;
2899 
2900                               if ((f = parse_flags($1)) < 0) {
2901                                         yyerror("bad flags %s", $1);
2902                                         free($1);
2903                                         YYERROR;
2904                               }
2905                               free($1);
2906                               $$.b1 = f;
2907                     }
2908                     ;
2909 
2910 flags               : FLAGS flag '/' flag         { $$.b1 = $2.b1; $$.b2 = $4.b1; }
2911                     | FLAGS '/' flag    { $$.b1 = 0; $$.b2 = $3.b1; }
2912                     | FLAGS ANY                   { $$.b1 = 0; $$.b2 = 0; }
2913                     ;
2914 
2915 icmpspec  : ICMPTYPE icmp_item                    { $$ = $2; }
2916                     | ICMPTYPE '{' icmp_list '}'  { $$ = $3; }
2917                     | ICMP6TYPE icmp6_item                  { $$ = $2; }
2918                     | ICMP6TYPE '{' icmp6_list '}'          { $$ = $3; }
2919                     ;
2920 
2921 icmp_list : icmp_item                             { $$ = $1; }
2922                     | icmp_list comma icmp_item   {
2923                               $1->tail->next = $3;
2924                               $1->tail = $3;
2925                               $$ = $1;
2926                     }
2927                     ;
2928 
2929 icmp6_list          : icmp6_item                            { $$ = $1; }
2930                     | icmp6_list comma icmp6_item {
2931                               $1->tail->next = $3;
2932                               $1->tail = $3;
2933                               $$ = $1;
2934                     }
2935                     ;
2936 
2937 icmp_item : icmptype                    {
2938                               $$ = calloc(1, sizeof(struct node_icmp));
2939                               if ($$ == NULL)
2940                                         err(1, "icmp_item: calloc");
2941                               $$->type = $1;
2942                               $$->code = 0;
2943                               $$->proto = IPPROTO_ICMP;
2944                               $$->next = NULL;
2945                               $$->tail = $$;
2946                     }
2947                     | icmptype CODE STRING        {
2948                               const struct icmpcodeent      *p;
2949                               u_long                                   ulval;
2950 
2951                               if (atoul($3, &ulval) == 0) {
2952                                         if (ulval > 255) {
2953                                                   free($3);
2954                                                   yyerror("illegal icmp-code %lu", ulval);
2955                                                   YYERROR;
2956                                         }
2957                               } else {
2958                                         if ((p = geticmpcodebyname($1-1, $3,
2959                                             AF_INET)) == NULL) {
2960                                                   yyerror("unknown icmp-code %s", $3);
2961                                                   free($3);
2962                                                   YYERROR;
2963                                         }
2964                                         ulval = p->code;
2965                               }
2966                               free($3);
2967                               $$ = calloc(1, sizeof(struct node_icmp));
2968                               if ($$ == NULL)
2969                                         err(1, "icmp_item: calloc");
2970                               $$->type = $1;
2971                               $$->code = ulval + 1;
2972                               $$->proto = IPPROTO_ICMP;
2973                               $$->next = NULL;
2974                               $$->tail = $$;
2975                     }
2976                     ;
2977 
2978 icmp6_item          : icmp6type                   {
2979                               $$ = calloc(1, sizeof(struct node_icmp));
2980                               if ($$ == NULL)
2981                                         err(1, "icmp_item: calloc");
2982                               $$->type = $1;
2983                               $$->code = 0;
2984                               $$->proto = IPPROTO_ICMPV6;
2985                               $$->next = NULL;
2986                               $$->tail = $$;
2987                     }
2988                     | icmp6type CODE STRING       {
2989                               const struct icmpcodeent      *p;
2990                               u_long                                   ulval;
2991 
2992                               if (atoul($3, &ulval) == 0) {
2993                                         if (ulval > 255) {
2994                                                   yyerror("illegal icmp6-code %lu",
2995                                                       ulval);
2996                                                   free($3);
2997                                                   YYERROR;
2998                                         }
2999                               } else {
3000                                         if ((p = geticmpcodebyname($1-1, $3,
3001                                             AF_INET6)) == NULL) {
3002                                                   yyerror("unknown icmp6-code %s", $3);
3003                                                   free($3);
3004                                                   YYERROR;
3005                                         }
3006                                         ulval = p->code;
3007                               }
3008                               free($3);
3009                               $$ = calloc(1, sizeof(struct node_icmp));
3010                               if ($$ == NULL)
3011                                         err(1, "icmp_item: calloc");
3012                               $$->type = $1;
3013                               $$->code = ulval + 1;
3014                               $$->proto = IPPROTO_ICMPV6;
3015                               $$->next = NULL;
3016                               $$->tail = $$;
3017                     }
3018                     ;
3019 
3020 icmptype  : STRING                      {
3021                               const struct icmptypeent      *p;
3022                               u_long                                   ulval;
3023 
3024                               if (atoul($1, &ulval) == 0) {
3025                                         if (ulval > 255) {
3026                                                   yyerror("illegal icmp-type %lu", ulval);
3027                                                   free($1);
3028                                                   YYERROR;
3029                                         }
3030                                         $$ = ulval + 1;
3031                               } else {
3032                                         if ((p = geticmptypebyname($1, AF_INET)) ==
3033                                             NULL) {
3034                                                   yyerror("unknown icmp-type %s", $1);
3035                                                   free($1);
3036                                                   YYERROR;
3037                                         }
3038                                         $$ = p->type + 1;
3039                               }
3040                               free($1);
3041                     }
3042                     ;
3043 
3044 icmp6type : STRING                      {
3045                               const struct icmptypeent      *p;
3046                               u_long                                   ulval;
3047 
3048                               if (atoul($1, &ulval) == 0) {
3049                                         if (ulval > 255) {
3050                                                   yyerror("illegal icmp6-type %lu",
3051                                                       ulval);
3052                                                   free($1);
3053                                                   YYERROR;
3054                                         }
3055                                         $$ = ulval + 1;
3056                               } else {
3057                                         if ((p = geticmptypebyname($1, AF_INET6)) ==
3058                                             NULL) {
3059                                                   yyerror("unknown icmp6-type %s", $1);
3060                                                   free($1);
3061                                                   YYERROR;
3062                                         }
3063                                         $$ = p->type + 1;
3064                               }
3065                               free($1);
3066                     }
3067                     ;
3068 
3069 tos                 : TOS STRING                            {
3070                               if (!strcmp($2, "lowdelay"))
3071                                         $$ = IPTOS_LOWDELAY;
3072                               else if (!strcmp($2, "throughput"))
3073                                         $$ = IPTOS_THROUGHPUT;
3074                               else if (!strcmp($2, "reliability"))
3075                                         $$ = IPTOS_RELIABILITY;
3076                               else if ($2[0] == '0' && $2[1] == 'x')
3077                                         $$ = strtoul($2, NULL, 16);
3078                               else
3079                                         $$ = strtoul($2, NULL, 10);
3080                               if (!$$ || $$ > 255) {
3081                                         yyerror("illegal tos value %s", $2);
3082                                         free($2);
3083                                         YYERROR;
3084                               }
3085                               free($2);
3086                     }
3087                     ;
3088 
3089 sourcetrack         : SOURCETRACK                 { $$ = PF_SRCTRACK; }
3090                     | SOURCETRACK GLOBAL          { $$ = PF_SRCTRACK_GLOBAL; }
3091                     | SOURCETRACK RULE  { $$ = PF_SRCTRACK_RULE; }
3092                     ;
3093 
3094 statelock : IFBOUND {
3095                               $$ = PFRULE_IFBOUND;
3096                     }
3097                     | FLOATING {
3098                               $$ = 0;
3099                     }
3100                     ;
3101 
3102 keep                : NO STATE                              {
3103                               $$.action = 0;
3104                               $$.options = NULL;
3105                     }
3106                     | KEEP STATE state_opt_spec   {
3107                               $$.action = PF_STATE_NORMAL;
3108                               $$.options = $3;
3109                     }
3110                     | MODULATE STATE state_opt_spec {
3111                               $$.action = PF_STATE_MODULATE;
3112                               $$.options = $3;
3113                     }
3114                     | SYNPROXY STATE state_opt_spec {
3115                               $$.action = PF_STATE_SYNPROXY;
3116                               $$.options = $3;
3117                     }
3118                     ;
3119 
3120 flush               : /* empty */                           { $$ = 0; }
3121                     | FLUSH                                 { $$ = PF_FLUSH; }
3122                     | FLUSH GLOBAL                          {
3123                               $$ = PF_FLUSH | PF_FLUSH_GLOBAL;
3124                     }
3125                     ;
3126 
3127 state_opt_spec      : '(' state_opt_list ')'      { $$ = $2; }
3128                     | /* empty */                           { $$ = NULL; }
3129                     ;
3130 
3131 state_opt_list      : state_opt_item              { $$ = $1; }
3132                     | state_opt_list comma state_opt_item {
3133                               $1->tail->next = $3;
3134                               $1->tail = $3;
3135                               $$ = $1;
3136                     }
3137                     ;
3138 
3139 state_opt_item      : MAXIMUM number              {
3140                               $$ = calloc(1, sizeof(struct node_state_opt));
3141                               if ($$ == NULL)
3142                                         err(1, "state_opt_item: calloc");
3143                               $$->type = PF_STATE_OPT_MAX;
3144                               $$->data.max_states = $2;
3145                               $$->next = NULL;
3146                               $$->tail = $$;
3147                     }
3148                     | NOSYNC                                {
3149                               $$ = calloc(1, sizeof(struct node_state_opt));
3150                               if ($$ == NULL)
3151                                         err(1, "state_opt_item: calloc");
3152                               $$->type = PF_STATE_OPT_NOSYNC;
3153                               $$->next = NULL;
3154                               $$->tail = $$;
3155                     }
3156                     | MAXSRCSTATES number                             {
3157                               $$ = calloc(1, sizeof(struct node_state_opt));
3158                               if ($$ == NULL)
3159                                         err(1, "state_opt_item: calloc");
3160                               $$->type = PF_STATE_OPT_MAX_SRC_STATES;
3161                               $$->data.max_src_states = $2;
3162                               $$->next = NULL;
3163                               $$->tail = $$;
3164                     }
3165                     | MAXSRCCONN number                     {
3166                               $$ = calloc(1, sizeof(struct node_state_opt));
3167                               if ($$ == NULL)
3168                                         err(1, "state_opt_item: calloc");
3169                               $$->type = PF_STATE_OPT_MAX_SRC_CONN;
3170                               $$->data.max_src_conn = $2;
3171                               $$->next = NULL;
3172                               $$->tail = $$;
3173                     }
3174                     | MAXSRCCONNRATE number '/' number      {
3175                               $$ = calloc(1, sizeof(struct node_state_opt));
3176                               if ($$ == NULL)
3177                                         err(1, "state_opt_item: calloc");
3178                               $$->type = PF_STATE_OPT_MAX_SRC_CONN_RATE;
3179                               $$->data.max_src_conn_rate.limit = $2;
3180                               $$->data.max_src_conn_rate.seconds = $4;
3181                               $$->next = NULL;
3182                               $$->tail = $$;
3183                     }
3184                     | OVERLOAD '<' STRING '>' flush                   {
3185                               if (strlen($3) >= PF_TABLE_NAME_SIZE) {
3186                                         yyerror("table name '%s' too long", $3);
3187                                         free($3);
3188                                         YYERROR;
3189                               }
3190                               $$ = calloc(1, sizeof(struct node_state_opt));
3191                               if ($$ == NULL)
3192                                         err(1, "state_opt_item: calloc");
3193                               if (strlcpy($$->data.overload.tblname, $3,
3194                                   PF_TABLE_NAME_SIZE) >= PF_TABLE_NAME_SIZE)
3195                                         errx(1, "state_opt_item: strlcpy");
3196                               free($3);
3197                               $$->type = PF_STATE_OPT_OVERLOAD;
3198                               $$->data.overload.flush = $5;
3199                               $$->next = NULL;
3200                               $$->tail = $$;
3201                     }
3202                     | MAXSRCNODES number                              {
3203                               $$ = calloc(1, sizeof(struct node_state_opt));
3204                               if ($$ == NULL)
3205                                         err(1, "state_opt_item: calloc");
3206                               $$->type = PF_STATE_OPT_MAX_SRC_NODES;
3207                               $$->data.max_src_nodes = $2;
3208                               $$->next = NULL;
3209                               $$->tail = $$;
3210                     }
3211                     | sourcetrack {
3212                               $$ = calloc(1, sizeof(struct node_state_opt));
3213                               if ($$ == NULL)
3214                                         err(1, "state_opt_item: calloc");
3215                               $$->type = PF_STATE_OPT_SRCTRACK;
3216                               $$->data.src_track = $1;
3217                               $$->next = NULL;
3218                               $$->tail = $$;
3219                     }
3220                     | statelock {
3221                               $$ = calloc(1, sizeof(struct node_state_opt));
3222                               if ($$ == NULL)
3223                                         err(1, "state_opt_item: calloc");
3224                               $$->type = PF_STATE_OPT_STATELOCK;
3225                               $$->data.statelock = $1;
3226                               $$->next = NULL;
3227                               $$->tail = $$;
3228                     }
3229                     | STRING number                         {
3230                               int       i;
3231 
3232                               for (i = 0; pf_timeouts[i].name &&
3233                                   strcmp(pf_timeouts[i].name, $1); ++i)
3234                                         ;         /* nothing */
3235                               if (!pf_timeouts[i].name) {
3236                                         yyerror("illegal timeout name %s", $1);
3237                                         free($1);
3238                                         YYERROR;
3239                               }
3240                               if (strchr(pf_timeouts[i].name, '.') == NULL) {
3241                                         yyerror("illegal state timeout %s", $1);
3242                                         free($1);
3243                                         YYERROR;
3244                               }
3245                               free($1);
3246                               $$ = calloc(1, sizeof(struct node_state_opt));
3247                               if ($$ == NULL)
3248                                         err(1, "state_opt_item: calloc");
3249                               $$->type = PF_STATE_OPT_TIMEOUT;
3250                               $$->data.timeout.number = pf_timeouts[i].timeout;
3251                               $$->data.timeout.seconds = $2;
3252                               $$->next = NULL;
3253                               $$->tail = $$;
3254                     }
3255                     ;
3256 
3257 label               : LABEL STRING                          {
3258                               $$ = $2;
3259                     }
3260                     ;
3261 
3262 qname               : QUEUE STRING                                    {
3263                               $$.qname = $2;
3264                     }
3265                     | QUEUE '(' STRING ')'                            {
3266                               $$.qname = $3;
3267                     }
3268                     | QUEUE '(' STRING comma STRING ')'     {
3269                               $$.qname = $3;
3270                               $$.pqname = $5;
3271                     }
3272                     ;
3273 
3274 no                  : /* empty */                           { $$ = 0; }
3275                     | NO                                    { $$ = 1; }
3276                     ;
3277 
3278 rport               : STRING                      {
3279                               char      *p = strchr($1, ':');
3280 
3281                               if (p == NULL) {
3282                                         if (($$.a = getservice($1)) == -1) {
3283                                                   free($1);
3284                                                   YYERROR;
3285                                         }
3286                                         $$.b = $$.t = 0;
3287                               } else if (!strcmp(p+1, "*")) {
3288                                         *p = 0;
3289                                         if (($$.a = getservice($1)) == -1) {
3290                                                   free($1);
3291                                                   YYERROR;
3292                                         }
3293                                         $$.b = 0;
3294                                         $$.t = 1;
3295                               } else {
3296                                         *p++ = 0;
3297                                         if (($$.a = getservice($1)) == -1 ||
3298                                             ($$.b = getservice(p)) == -1) {
3299                                                   free($1);
3300                                                   YYERROR;
3301                                         }
3302                                         if ($$.a == $$.b)
3303                                                   $$.b = 0;
3304                                         $$.t = 0;
3305                               }
3306                               free($1);
3307                     }
3308                     ;
3309 
3310 redirspec : host                                  { $$ = $1; }
3311                     | '{' redir_host_list '}'     { $$ = $2; }
3312                     ;
3313 
3314 redir_host_list     : host                                  { $$ = $1; }
3315                     | redir_host_list comma host  {
3316                               $1->tail->next = $3;
3317                               $1->tail = $3->tail;
3318                               $$ = $1;
3319                     }
3320                     ;
3321 
3322 redirpool : /* empty */                           { $$ = NULL; }
3323                     | ARROW redirspec             {
3324                               $$ = calloc(1, sizeof(struct redirection));
3325                               if ($$ == NULL)
3326                                         err(1, "redirection: calloc");
3327                               $$->host = $2;
3328                               $$->rport.a = $$->rport.b = $$->rport.t = 0;
3329                     }
3330                     | ARROW redirspec PORT rport  {
3331                               $$ = calloc(1, sizeof(struct redirection));
3332                               if ($$ == NULL)
3333                                         err(1, "redirection: calloc");
3334                               $$->host = $2;
3335                               $$->rport = $4;
3336                     }
3337                     ;
3338 
3339 hashkey             : /* empty */
3340                     {
3341                               $$ = calloc(1, sizeof(struct pf_poolhashkey));
3342                               if ($$ == NULL)
3343                                         err(1, "hashkey: calloc");
3344                               $$->key32[0] = arc4random();
3345                               $$->key32[1] = arc4random();
3346                               $$->key32[2] = arc4random();
3347                               $$->key32[3] = arc4random();
3348                     }
3349                     | string
3350                     {
3351                               if (!strncmp($1, "0x", 2)) {
3352                                         if (strlen($1) != 34) {
3353                                                   free($1);
3354                                                   yyerror("hex key must be 128 bits "
3355                                                             "(32 hex digits) long");
3356                                                   YYERROR;
3357                                         }
3358                                         $$ = calloc(1, sizeof(struct pf_poolhashkey));
3359                                         if ($$ == NULL)
3360                                                   err(1, "hashkey: calloc");
3361 
3362                                         if (sscanf($1, "0x%8x%8x%8x%8x",
3363                                             &$$->key32[0], &$$->key32[1],
3364                                             &$$->key32[2], &$$->key32[3]) != 4) {
3365                                                   free($$);
3366                                                   free($1);
3367                                                   yyerror("invalid hex key");
3368                                                   YYERROR;
3369                                         }
3370                               } else {
3371                                         MD5_CTX   context;
3372 
3373                                         $$ = calloc(1, sizeof(struct pf_poolhashkey));
3374                                         if ($$ == NULL)
3375                                                   err(1, "hashkey: calloc");
3376                                         MD5Init(&context);
3377                                         MD5Update(&context, (unsigned char *)$1,
3378                                             strlen($1));
3379                                         MD5Final((unsigned char *)$$, &context);
3380                                         HTONL($$->key32[0]);
3381                                         HTONL($$->key32[1]);
3382                                         HTONL($$->key32[2]);
3383                                         HTONL($$->key32[3]);
3384                               }
3385                               free($1);
3386                     }
3387                     ;
3388 
3389 pool_opts :         { bzero(&pool_opts, sizeof pool_opts); }
3390                         pool_opts_l
3391                               { $$ = pool_opts; }
3392                     | /* empty */       {
3393                               bzero(&pool_opts, sizeof pool_opts);
3394                               $$ = pool_opts;
3395                     }
3396                     ;
3397 
3398 pool_opts_l         : pool_opts_l pool_opt
3399                     | pool_opt
3400                     ;
3401 
3402 pool_opt  : BITMASK {
3403                               if (pool_opts.type) {
3404                                         yyerror("pool type cannot be redefined");
3405                                         YYERROR;
3406                               }
3407                               pool_opts.type =  PF_POOL_BITMASK;
3408                     }
3409                     | RANDOM  {
3410                               if (pool_opts.type) {
3411                                         yyerror("pool type cannot be redefined");
3412                                         YYERROR;
3413                               }
3414                               pool_opts.type = PF_POOL_RANDOM;
3415                     }
3416                     | SOURCEHASH hashkey {
3417                               if (pool_opts.type) {
3418                                         yyerror("pool type cannot be redefined");
3419                                         YYERROR;
3420                               }
3421                               pool_opts.type = PF_POOL_SRCHASH;
3422                               pool_opts.key = $2;
3423                     }
3424                     | ROUNDROBIN        {
3425                               if (pool_opts.type) {
3426                                         yyerror("pool type cannot be redefined");
3427                                         YYERROR;
3428                               }
3429                               pool_opts.type = PF_POOL_ROUNDROBIN;
3430                     }
3431                     | STATICPORT        {
3432                               if (pool_opts.staticport) {
3433                                         yyerror("static-port cannot be redefined");
3434                                         YYERROR;
3435                               }
3436                               pool_opts.staticport = 1;
3437                     }
3438                     | STICKYADDRESS     {
3439                               if (filter_opts.marker & POM_STICKYADDRESS) {
3440                                         yyerror("sticky-address cannot be redefined");
3441                                         YYERROR;
3442                               }
3443                               pool_opts.marker |= POM_STICKYADDRESS;
3444                               pool_opts.opts |= PF_POOL_STICKYADDR;
3445                     }
3446                     ;
3447 
3448 redirection         : /* empty */                           { $$ = NULL; }
3449                     | ARROW host                            {
3450                               $$ = calloc(1, sizeof(struct redirection));
3451                               if ($$ == NULL)
3452                                         err(1, "redirection: calloc");
3453                               $$->host = $2;
3454                               $$->rport.a = $$->rport.b = $$->rport.t = 0;
3455                     }
3456                     | ARROW host PORT rport       {
3457                               $$ = calloc(1, sizeof(struct redirection));
3458                               if ($$ == NULL)
3459                                         err(1, "redirection: calloc");
3460                               $$->host = $2;
3461                               $$->rport = $4;
3462                     }
3463                     ;
3464 
3465 natpasslog          : /* empty */       { $$.b1 = $$.b2 = 0; $$.w2 = 0; }
3466                     | PASS              { $$.b1 = 1; $$.b2 = 0; $$.w2 = 0; }
3467                     | PASS log          { $$.b1 = 1; $$.b2 = $2.log; $$.w2 = $2.logif; }
3468                     | log               { $$.b1 = 0; $$.b2 = $1.log; $$.w2 = $1.logif; }
3469                     ;
3470 
3471 nataction : no NAT natpasslog {
3472                               if ($1 && $3.b1) {
3473                                         yyerror("\"pass\" not valid with \"no\"");
3474                                         YYERROR;
3475                               }
3476                               if ($1)
3477                                         $$.b1 = PF_NONAT;
3478                               else
3479                                         $$.b1 = PF_NAT;
3480                               $$.b2 = $3.b1;
3481                               $$.w = $3.b2;
3482                               $$.w2 = $3.w2;
3483                     }
3484                     | no RDR natpasslog {
3485                               if ($1 && $3.b1) {
3486                                         yyerror("\"pass\" not valid with \"no\"");
3487                                         YYERROR;
3488                               }
3489                               if ($1)
3490                                         $$.b1 = PF_NORDR;
3491                               else
3492                                         $$.b1 = PF_RDR;
3493                               $$.b2 = $3.b1;
3494                               $$.w = $3.b2;
3495                               $$.w2 = $3.w2;
3496                     }
3497                     ;
3498 
3499 natrule             : nataction interface af proto fromto tag tagged rtable
3500                         redirpool pool_opts opt_statelock
3501                     {
3502                               struct pf_rule      r;
3503 
3504                               if (check_rulestate(PFCTL_STATE_NAT))
3505                                         YYERROR;
3506 
3507                               memset(&r, 0, sizeof(r));
3508 
3509                               r.action = $1.b1;
3510                               r.natpass = $1.b2;
3511                               r.log = $1.w;
3512                               r.logif = $1.w2;
3513                               r.af = $3;
3514 
3515                               if (!r.af) {
3516                                         if ($5.src.host && $5.src.host->af &&
3517                                             !$5.src.host->ifindex)
3518                                                   r.af = $5.src.host->af;
3519                                         else if ($5.dst.host && $5.dst.host->af &&
3520                                             !$5.dst.host->ifindex)
3521                                                   r.af = $5.dst.host->af;
3522                               }
3523 
3524                               if ($6 != NULL)
3525                                         if (strlcpy(r.tagname, $6, PF_TAG_NAME_SIZE) >=
3526                                             PF_TAG_NAME_SIZE) {
3527                                                   yyerror("tag too long, max %u chars",
3528                                                       PF_TAG_NAME_SIZE - 1);
3529                                                   YYERROR;
3530                                         }
3531 
3532                               if ($7.name)
3533                                         if (strlcpy(r.match_tagname, $7.name,
3534                                             PF_TAG_NAME_SIZE) >= PF_TAG_NAME_SIZE) {
3535                                                   yyerror("tag too long, max %u chars",
3536                                                       PF_TAG_NAME_SIZE - 1);
3537                                                   YYERROR;
3538                                         }
3539                               r.match_tag_not = $7.neg;
3540                               r.rtableid = $8;
3541 
3542                               if (r.action == PF_NONAT || r.action == PF_NORDR) {
3543                                         if ($9 != NULL) {
3544                                                   yyerror("translation rule with 'no' "
3545                                                       "does not need '->'");
3546                                                   YYERROR;
3547                                         }
3548                               } else {
3549                                         if ($9 == NULL || $9->host == NULL) {
3550                                                   yyerror("translation rule requires '-> "
3551                                                       "address'");
3552                                                   YYERROR;
3553                                         }
3554                                         if (!r.af && ! $9->host->ifindex)
3555                                                   r.af = $9->host->af;
3556 
3557                                         remove_invalid_hosts(&$9->host, &r.af);
3558                                         if (invalid_redirect($9->host, r.af))
3559                                                   YYERROR;
3560                                         if (check_netmask($9->host, r.af))
3561                                                   YYERROR;
3562 
3563                                         r.rpool.proxy_port[0] = ntohs($9->rport.a);
3564 
3565                                         switch (r.action) {
3566                                         case PF_RDR:
3567                                                   if (!$9->rport.b && $9->rport.t &&
3568                                                       $5.dst.port != NULL) {
3569                                                             r.rpool.proxy_port[1] =
3570                                                                 ntohs($9->rport.a) +
3571                                                                 (ntohs(
3572                                                                 $5.dst.port->port[1]) -
3573                                                                 ntohs(
3574                                                                 $5.dst.port->port[0]));
3575                                                   } else
3576                                                             r.rpool.proxy_port[1] =
3577                                                                 ntohs($9->rport.b);
3578                                                   break;
3579                                         case PF_NAT:
3580                                                   r.rpool.proxy_port[1] =
3581                                                       ntohs($9->rport.b);
3582                                                   if (!r.rpool.proxy_port[0] &&
3583                                                       !r.rpool.proxy_port[1]) {
3584                                                             r.rpool.proxy_port[0] =
3585                                                                 PF_NAT_PROXY_PORT_LOW;
3586                                                             r.rpool.proxy_port[1] =
3587                                                                 PF_NAT_PROXY_PORT_HIGH;
3588                                                   } else if (!r.rpool.proxy_port[1])
3589                                                             r.rpool.proxy_port[1] =
3590                                                                 r.rpool.proxy_port[0];
3591                                                   break;
3592                                         default:
3593                                                   break;
3594                                         }
3595 
3596                                         r.rpool.opts = $10.type;
3597                                         if ((r.rpool.opts & PF_POOL_TYPEMASK) ==
3598                                             PF_POOL_NONE && ($9->host->next != NULL ||
3599                                             $9->host->addr.type == PF_ADDR_TABLE ||
3600                                             DYNIF_MULTIADDR($9->host->addr)))
3601                                                   r.rpool.opts = PF_POOL_ROUNDROBIN;
3602                                         if ((r.rpool.opts & PF_POOL_TYPEMASK) !=
3603                                             PF_POOL_ROUNDROBIN &&
3604                                             disallow_table($9->host, "tables are only "
3605                                             "supported in round-robin redirection "
3606                                             "pools"))
3607                                                   YYERROR;
3608                                         if ((r.rpool.opts & PF_POOL_TYPEMASK) !=
3609                                             PF_POOL_ROUNDROBIN &&
3610                                             disallow_alias($9->host, "interface (%s) "
3611                                             "is only supported in round-robin "
3612                                             "redirection pools"))
3613                                                   YYERROR;
3614                                         if ($9->host->next != NULL) {
3615                                                   if ((r.rpool.opts & PF_POOL_TYPEMASK) !=
3616                                                       PF_POOL_ROUNDROBIN) {
3617                                                             yyerror("only round-robin "
3618                                                                 "valid for multiple "
3619                                                                 "redirection addresses");
3620                                                             YYERROR;
3621                                                   }
3622                                         }
3623                               }
3624 
3625                               if ($10.key != NULL)
3626                                         memcpy(&r.rpool.key, $10.key,
3627                                             sizeof(struct pf_poolhashkey));
3628 
3629                                if ($10.opts)
3630                                         r.rpool.opts |= $10.opts;
3631 
3632                               if ($10.staticport) {
3633                                         if (r.action != PF_NAT) {
3634                                                   yyerror("the 'static-port' option is "
3635                                                       "only valid with nat rules");
3636                                                   YYERROR;
3637                                         }
3638                                         if (r.rpool.proxy_port[0] !=
3639                                             PF_NAT_PROXY_PORT_LOW &&
3640                                             r.rpool.proxy_port[1] !=
3641                                             PF_NAT_PROXY_PORT_HIGH) {
3642                                                   yyerror("the 'static-port' option can't"
3643                                                       " be used when specifying a port"
3644                                                       " range");
3645                                                   YYERROR;
3646                                         }
3647                                         r.rpool.proxy_port[0] = 0;
3648                                         r.rpool.proxy_port[1] = 0;
3649                               }
3650 
3651                               if ($11 == NULL)
3652                                         r.rule_flag |= default_statelock;
3653                               else {
3654                                         r.rule_flag |= $11->data.statelock;
3655                                         free($11);
3656                               }
3657 
3658                               expand_rule(&r, $2, $9 == NULL ? NULL : $9->host, $4,
3659                                   $5.src_os, $5.src.host, $5.src.port, $5.dst.host,
3660                                   $5.dst.port, 0, 0, 0, "");
3661                               free($9);
3662                     }
3663                     ;
3664 
3665 binatrule : no BINAT natpasslog interface af proto FROM host TO ipspec tag
3666                         tagged rtable redirection
3667                     {
3668                               struct pf_rule                binat;
3669                               struct pf_pooladdr  *pa;
3670 
3671                               if (check_rulestate(PFCTL_STATE_NAT))
3672                                         YYERROR;
3673                               if (disallow_urpf_failed($10, "\"urpf-failed\" is not "
3674                                   "permitted as a binat destination"))
3675                                         YYERROR;
3676 
3677                               memset(&binat, 0, sizeof(binat));
3678 
3679                               if ($1 && $3.b1) {
3680                                         yyerror("\"pass\" not valid with \"no\"");
3681                                         YYERROR;
3682                               }
3683                               if ($1)
3684                                         binat.action = PF_NOBINAT;
3685                               else
3686                                         binat.action = PF_BINAT;
3687                               binat.natpass = $3.b1;
3688                               binat.log = $3.b2;
3689                               binat.logif = $3.w2;
3690                               binat.af = $5;
3691                               if (!binat.af && $8 != NULL && $8->af)
3692                                         binat.af = $8->af;
3693                               if (!binat.af && $10 != NULL && $10->af)
3694                                         binat.af = $10->af;
3695 
3696                               if (!binat.af && $14 != NULL && $14->host)
3697                                         binat.af = $14->host->af;
3698                               if (!binat.af) {
3699                                         yyerror("address family (inet/inet6) "
3700                                             "undefined");
3701                                         YYERROR;
3702                               }
3703 
3704                               if ($4 != NULL) {
3705                                         memcpy(binat.ifname, $4->ifname,
3706                                             sizeof(binat.ifname));
3707                                         binat.ifnot = $4->not;
3708                                         free($4);
3709                               }
3710 
3711                               if ($11 != NULL)
3712                                         if (strlcpy(binat.tagname, $11,
3713                                             PF_TAG_NAME_SIZE) >= PF_TAG_NAME_SIZE) {
3714                                                   yyerror("tag too long, max %u chars",
3715                                                       PF_TAG_NAME_SIZE - 1);
3716                                                   YYERROR;
3717                                         }
3718                               if ($12.name)
3719                                         if (strlcpy(binat.match_tagname, $12.name,
3720                                             PF_TAG_NAME_SIZE) >= PF_TAG_NAME_SIZE) {
3721                                                   yyerror("tag too long, max %u chars",
3722                                                       PF_TAG_NAME_SIZE - 1);
3723                                                   YYERROR;
3724                                         }
3725                               binat.match_tag_not = $12.neg;
3726                               binat.rtableid = $13;
3727 
3728                               if ($6 != NULL) {
3729                                         binat.proto = $6->proto;
3730                                         free($6);
3731                               }
3732 
3733                               if ($8 != NULL && disallow_table($8, "invalid use of "
3734                                   "table <%s> as the source address of a binat rule"))
3735                                         YYERROR;
3736                               if ($8 != NULL && disallow_alias($8, "invalid use of "
3737                                   "interface (%s) as the source address of a binat "
3738                                   "rule"))
3739                                         YYERROR;
3740                               if ($14 != NULL && $14->host != NULL && disallow_table(
3741                                   $14->host, "invalid use of table <%s> as the "
3742                                   "redirect address of a binat rule"))
3743                                         YYERROR;
3744                               if ($14 != NULL && $14->host != NULL && disallow_alias(
3745                                   $14->host, "invalid use of interface (%s) as the "
3746                                   "redirect address of a binat rule"))
3747                                         YYERROR;
3748 
3749                               if ($8 != NULL) {
3750                                         if ($8->next) {
3751                                                   yyerror("multiple binat ip addresses");
3752                                                   YYERROR;
3753                                         }
3754                                         if ($8->addr.type == PF_ADDR_DYNIFTL)
3755                                                   $8->af = binat.af;
3756                                         if ($8->af != binat.af) {
3757                                                   yyerror("binat ip versions must match");
3758                                                   YYERROR;
3759                                         }
3760                                         if (check_netmask($8, binat.af))
3761                                                   YYERROR;
3762                                         memcpy(&binat.src.addr, &$8->addr,
3763                                             sizeof(binat.src.addr));
3764                                         free($8);
3765                               }
3766                               if ($10 != NULL) {
3767                                         if ($10->next) {
3768                                                   yyerror("multiple binat ip addresses");
3769                                                   YYERROR;
3770                                         }
3771                                         if ($10->af != binat.af && $10->af) {
3772                                                   yyerror("binat ip versions must match");
3773                                                   YYERROR;
3774                                         }
3775                                         if (check_netmask($10, binat.af))
3776                                                   YYERROR;
3777                                         memcpy(&binat.dst.addr, &$10->addr,
3778                                             sizeof(binat.dst.addr));
3779                                         binat.dst.neg = $10->not;
3780                                         free($10);
3781                               }
3782 
3783                               if (binat.action == PF_NOBINAT) {
3784                                         if ($14 != NULL) {
3785                                                   yyerror("'no binat' rule does not need"
3786                                                       " '->'");
3787                                                   YYERROR;
3788                                         }
3789                               } else {
3790                                         if ($14 == NULL || $14->host == NULL) {
3791                                                   yyerror("'binat' rule requires"
3792                                                       " '-> address'");
3793                                                   YYERROR;
3794                                         }
3795 
3796                                         remove_invalid_hosts(&$14->host, &binat.af);
3797                                         if (invalid_redirect($14->host, binat.af))
3798                                                   YYERROR;
3799                                         if ($14->host->next != NULL) {
3800                                                   yyerror("binat rule must redirect to "
3801                                                       "a single address");
3802                                                   YYERROR;
3803                                         }
3804                                         if (check_netmask($14->host, binat.af))
3805                                                   YYERROR;
3806 
3807                                         if (!PF_AZERO(&binat.src.addr.v.a.mask,
3808                                             binat.af) &&
3809                                             !PF_AEQ(&binat.src.addr.v.a.mask,
3810                                             &$14->host->addr.v.a.mask, binat.af)) {
3811                                                   yyerror("'binat' source mask and "
3812                                                       "redirect mask must be the same");
3813                                                   YYERROR;
3814                                         }
3815 
3816                                         TAILQ_INIT(&binat.rpool.list);
3817                                         pa = calloc(1, sizeof(struct pf_pooladdr));
3818                                         if (pa == NULL)
3819                                                   err(1, "binat: calloc");
3820                                         pa->addr = $14->host->addr;
3821                                         pa->ifname[0] = 0;
3822                                         TAILQ_INSERT_TAIL(&binat.rpool.list,
3823                                             pa, entries);
3824 
3825                                         free($14);
3826                               }
3827 
3828                               pfctl_add_rule(pf, &binat, "");
3829                     }
3830                     ;
3831 
3832 tag                 : /* empty */                 { $$ = NULL; }
3833                     | TAG STRING                  { $$ = $2; }
3834                     ;
3835 
3836 tagged              : /* empty */                 { $$.neg = 0; $$.name = NULL; }
3837                     | not TAGGED string { $$.neg = $1; $$.name = $3; }
3838                     ;
3839 
3840 rtable              : /* empty */                 { $$ = -1; }
3841                     | RTABLE number               {
3842                               if ($2 > RT_TABLEID_MAX || $2 < 0) {
3843                                         yyerror("invalid rtable id");
3844                                         YYERROR;
3845                               }
3846                               $$ = $2;
3847                     }
3848                     ;
3849 
3850 route_host          : STRING                      {
3851                               $$ = calloc(1, sizeof(struct node_host));
3852                               if ($$ == NULL)
3853                                         err(1, "route_host: calloc");
3854                               $$->ifname = $1;
3855                               set_ipmask($$, 128);
3856                               $$->next = NULL;
3857                               $$->tail = $$;
3858                     }
3859                     | '(' STRING host ')'                   {
3860                               $$ = $3;
3861                               $$->ifname = $2;
3862                     }
3863                     ;
3864 
3865 route_host_list     : route_host                                      { $$ = $1; }
3866                     | route_host_list comma route_host      {
3867                               if ($1->af == 0)
3868                                         $1->af = $3->af;
3869                               if ($1->af != $3->af) {
3870                                         yyerror("all pool addresses must be in the "
3871                                             "same address family");
3872                                         YYERROR;
3873                               }
3874                               $1->tail->next = $3;
3875                               $1->tail = $3->tail;
3876                               $$ = $1;
3877                     }
3878                     ;
3879 
3880 routespec : route_host                            { $$ = $1; }
3881                     | '{' route_host_list '}'     { $$ = $2; }
3882                     ;
3883 
3884 route               : /* empty */                           {
3885                               $$.host = NULL;
3886                               $$.rt = 0;
3887                               $$.pool_opts = 0;
3888                     }
3889                     | FASTROUTE {
3890                               $$.host = NULL;
3891                               $$.rt = PF_FASTROUTE;
3892                               $$.pool_opts = 0;
3893                     }
3894                     | ROUTETO routespec pool_opts {
3895                               $$.host = $2;
3896                               $$.rt = PF_ROUTETO;
3897                               $$.pool_opts = $3.type | $3.opts;
3898                               if ($3.key != NULL)
3899                                         $$.key = $3.key;
3900                     }
3901                     | REPLYTO routespec pool_opts {
3902                               $$.host = $2;
3903                               $$.rt = PF_REPLYTO;
3904                               $$.pool_opts = $3.type | $3.opts;
3905                               if ($3.key != NULL)
3906                                         $$.key = $3.key;
3907                     }
3908                     | DUPTO routespec pool_opts {
3909                               $$.host = $2;
3910                               $$.rt = PF_DUPTO;
3911                               $$.pool_opts = $3.type | $3.opts;
3912                               if ($3.key != NULL)
3913                                         $$.key = $3.key;
3914                     }
3915                     ;
3916 
3917 timeout_spec        : STRING number
3918                     {
3919                               if (check_rulestate(PFCTL_STATE_OPTION)) {
3920                                         free($1);
3921                                         YYERROR;
3922                               }
3923                               if (pfctl_set_timeout(pf, $1, $2, 0) != 0) {
3924                                         yyerror("unknown timeout %s", $1);
3925                                         free($1);
3926                                         YYERROR;
3927                               }
3928                               free($1);
3929                     }
3930                     ;
3931 
3932 timeout_list        : timeout_list comma timeout_spec
3933                     | timeout_spec
3934                     ;
3935 
3936 limit_spec          : STRING number
3937                     {
3938                               if (check_rulestate(PFCTL_STATE_OPTION)) {
3939                                         free($1);
3940                                         YYERROR;
3941                               }
3942                               if (pfctl_set_limit(pf, $1, $2) != 0) {
3943                                         yyerror("unable to set limit %s %u", $1, $2);
3944                                         free($1);
3945                                         YYERROR;
3946                               }
3947                               free($1);
3948                     }
3949                     ;
3950 
3951 limit_list          : limit_list comma limit_spec
3952                     | limit_spec
3953                     ;
3954 
3955 comma               : ','
3956                     | /* empty */
3957                     ;
3958 
3959 yesno               : NO                          { $$ = 0; }
3960                     | STRING            {
3961                               if (!strcmp($1, "yes"))
3962                                         $$ = 1;
3963                               else {
3964                                         yyerror("invalid value '%s', expected 'yes' "
3965                                             "or 'no'", $1);
3966                                         free($1);
3967                                         YYERROR;
3968                               }
3969                               free($1);
3970                     }
3971                     ;
3972 
3973 unaryop             : '='               { $$ = PF_OP_EQ; }
3974                     | '!' '=' { $$ = PF_OP_NE; }
3975                     | '<' '=' { $$ = PF_OP_LE; }
3976                     | '<'               { $$ = PF_OP_LT; }
3977                     | '>' '=' { $$ = PF_OP_GE; }
3978                     | '>'               { $$ = PF_OP_GT; }
3979                     ;
3980 
3981 %%
3982 
3983 int
3984 yyerror(const char *fmt, ...)
3985 {
3986           va_list              ap;
3987           extern const char *infile;
3988 
3989           errors = 1;
3990           va_start(ap, fmt);
3991           fprintf(stderr, "%s:%d: ", infile, yylval.lineno);
3992           vfprintf(stderr, fmt, ap);
3993           fprintf(stderr, "\n");
3994           va_end(ap);
3995           return (0);
3996 }
3997 
3998 int
disallow_table(struct node_host * h,const char * fmt)3999 disallow_table(struct node_host *h, const char *fmt)
4000 {
4001           for (; h != NULL; h = h->next)
4002                     if (h->addr.type == PF_ADDR_TABLE) {
4003                               yyerror(fmt, h->addr.v.tblname);
4004                               return (1);
4005                     }
4006           return (0);
4007 }
4008 
4009 int
disallow_urpf_failed(struct node_host * h,const char * fmt)4010 disallow_urpf_failed(struct node_host *h, const char *fmt)
4011 {
4012           for (; h != NULL; h = h->next)
4013                     if (h->addr.type == PF_ADDR_URPFFAILED) {
4014                               yyerror(fmt);
4015                               return (1);
4016                     }
4017           return (0);
4018 }
4019 
4020 int
disallow_alias(struct node_host * h,const char * fmt)4021 disallow_alias(struct node_host *h, const char *fmt)
4022 {
4023           for (; h != NULL; h = h->next)
4024                     if (DYNIF_MULTIADDR(h->addr)) {
4025                               yyerror(fmt, h->addr.v.tblname);
4026                               return (1);
4027                     }
4028           return (0);
4029 }
4030 
4031 int
rule_consistent(struct pf_rule * r,int anchor_call)4032 rule_consistent(struct pf_rule *r, int anchor_call)
4033 {
4034           int       problems = 0;
4035 
4036           switch (r->action) {
4037           case PF_PASS:
4038           case PF_DROP:
4039           case PF_SCRUB:
4040           case PF_NOSCRUB:
4041                     problems = filter_consistent(r, anchor_call);
4042                     break;
4043           case PF_NAT:
4044           case PF_NONAT:
4045                     problems = nat_consistent(r);
4046                     break;
4047           case PF_RDR:
4048           case PF_NORDR:
4049                     problems = rdr_consistent(r);
4050                     break;
4051           case PF_BINAT:
4052           case PF_NOBINAT:
4053           default:
4054                     break;
4055           }
4056           return (problems);
4057 }
4058 
4059 int
filter_consistent(struct pf_rule * r,int anchor_call)4060 filter_consistent(struct pf_rule *r, int anchor_call)
4061 {
4062           int       problems = 0;
4063 
4064           if (r->proto != IPPROTO_TCP && r->proto != IPPROTO_UDP &&
4065               (r->src.port_op || r->dst.port_op)) {
4066                     yyerror("port only applies to tcp/udp");
4067                     problems++;
4068           }
4069           if (r->proto != IPPROTO_ICMP && r->proto != IPPROTO_ICMPV6 &&
4070               (r->type || r->code)) {
4071                     yyerror("icmp-type/code only applies to icmp");
4072                     problems++;
4073           }
4074           if (!r->af && (r->type || r->code)) {
4075                     yyerror("must indicate address family with icmp-type/code");
4076                     problems++;
4077           }
4078           if (r->overload_tblname[0] &&
4079               r->max_src_conn == 0 && r->max_src_conn_rate.seconds == 0) {
4080                     yyerror("'overload' requires 'max-src-conn' "
4081                         "or 'max-src-conn-rate'");
4082                     problems++;
4083           }
4084           if ((r->proto == IPPROTO_ICMP && r->af == AF_INET6) ||
4085               (r->proto == IPPROTO_ICMPV6 && r->af == AF_INET)) {
4086                     yyerror("proto %s doesn't match address family %s",
4087                         r->proto == IPPROTO_ICMP ? "icmp" : "icmp6",
4088                         r->af == AF_INET ? "inet" : "inet6");
4089                     problems++;
4090           }
4091           if (r->allow_opts && r->action != PF_PASS) {
4092                     yyerror("allow-opts can only be specified for pass rules");
4093                     problems++;
4094           }
4095           if (r->rule_flag & PFRULE_FRAGMENT && (r->src.port_op ||
4096               r->dst.port_op || r->flagset || r->type || r->code)) {
4097                     yyerror("fragments can be filtered only on IP header fields");
4098                     problems++;
4099           }
4100           if (r->rule_flag & PFRULE_RETURNRST && r->proto != IPPROTO_TCP) {
4101                     yyerror("return-rst can only be applied to TCP rules");
4102                     problems++;
4103           }
4104           if (r->max_src_nodes && !(r->rule_flag & PFRULE_RULESRCTRACK)) {
4105                     yyerror("max-src-nodes requires 'source-track rule'");
4106                     problems++;
4107           }
4108           if (r->action == PF_DROP && r->keep_state) {
4109                     yyerror("keep state on block rules doesn't make sense");
4110                     problems++;
4111           }
4112           return (-problems);
4113 }
4114 
4115 int
nat_consistent(struct pf_rule * r)4116 nat_consistent(struct pf_rule *r)
4117 {
4118           return (0);         /* yeah! */
4119 }
4120 
4121 int
rdr_consistent(struct pf_rule * r)4122 rdr_consistent(struct pf_rule *r)
4123 {
4124           int                            problems = 0;
4125 
4126           if (r->proto != IPPROTO_TCP && r->proto != IPPROTO_UDP) {
4127                     if (r->src.port_op) {
4128                               yyerror("src port only applies to tcp/udp");
4129                               problems++;
4130                     }
4131                     if (r->dst.port_op) {
4132                               yyerror("dst port only applies to tcp/udp");
4133                               problems++;
4134                     }
4135                     if (r->rpool.proxy_port[0]) {
4136                               yyerror("rpool port only applies to tcp/udp");
4137                               problems++;
4138                     }
4139           }
4140           if (r->dst.port_op &&
4141               r->dst.port_op != PF_OP_EQ && r->dst.port_op != PF_OP_RRG) {
4142                     yyerror("invalid port operator for rdr destination port");
4143                     problems++;
4144           }
4145           return (-problems);
4146 }
4147 
4148 int
process_tabledef(char * name,struct table_opts * opts)4149 process_tabledef(char *name, struct table_opts *opts)
4150 {
4151           struct pfr_buffer    ab;
4152           struct node_tinit   *ti;
4153 
4154           bzero(&ab, sizeof(ab));
4155           ab.pfrb_type = PFRB_ADDRS;
4156           SIMPLEQ_FOREACH(ti, &opts->init_nodes, entries) {
4157                     if (ti->file)
4158                               if (pfr_buf_load(&ab, ti->file, 0, append_addr)) {
4159                                         if (errno)
4160                                                   yyerror("cannot load \"%s\": %s",
4161                                                       ti->file, strerror(errno));
4162                                         else
4163                                                   yyerror("file \"%s\" contains bad data",
4164                                                       ti->file);
4165                                         goto _error;
4166                               }
4167                     if (ti->host)
4168                               if (append_addr_host(&ab, ti->host, 0, 0)) {
4169                                         yyerror("cannot create address buffer: %s",
4170                                             strerror(errno));
4171                                         goto _error;
4172                               }
4173           }
4174           if (pf->opts & PF_OPT_VERBOSE)
4175                     print_tabledef(name, opts->flags, opts->init_addr,
4176                         &opts->init_nodes);
4177           if (!(pf->opts & PF_OPT_NOACTION) &&
4178               pfctl_define_table(name, opts->flags, opts->init_addr,
4179               pf->anchor->name, &ab, pf->anchor->ruleset.tticket)) {
4180                     yyerror("cannot define table %s: %s", name,
4181                         pfr_strerror(errno));
4182                     goto _error;
4183           }
4184           pf->tdirty = 1;
4185           pfr_buf_clear(&ab);
4186           return (0);
4187 _error:
4188           pfr_buf_clear(&ab);
4189           return (-1);
4190 }
4191 
4192 struct keywords {
4193           const char          *k_name;
4194           int                  k_val;
4195 };
4196 
4197 /* macro gore, but you should've seen the prior indentation nightmare... */
4198 
4199 #define FREE_LIST(T,r) \
4200           do { \
4201                     T *p, *node = r; \
4202                     while (node != NULL) { \
4203                               p = node; \
4204                               node = node->next; \
4205                               free(p); \
4206                     } \
4207           } while (0)
4208 
4209 #define LOOP_THROUGH(T,n,r,C) \
4210           do { \
4211                     T *n; \
4212                     if (r == NULL) { \
4213                               r = calloc(1, sizeof(T)); \
4214                               if (r == NULL) \
4215                                         err(1, "LOOP: calloc"); \
4216                               r->next = NULL; \
4217                     } \
4218                     n = r; \
4219                     while (n != NULL) { \
4220                               do { \
4221                                         C; \
4222                               } while (0); \
4223                               n = n->next; \
4224                     } \
4225           } while (0)
4226 
4227 void
expand_label_str(char * label,size_t len,const char * srch,const char * repl)4228 expand_label_str(char *label, size_t len, const char *srch, const char *repl)
4229 {
4230           char *tmp;
4231           char *p, *q;
4232 
4233           if ((tmp = calloc(1, len)) == NULL)
4234                     err(1, "expand_label_str: calloc");
4235           p = q = label;
4236           while ((q = strstr(p, srch)) != NULL) {
4237                     *q = '\0';
4238                     if ((strlcat(tmp, p, len) >= len) ||
4239                         (strlcat(tmp, repl, len) >= len))
4240                               errx(1, "expand_label: label too long");
4241                     q += strlen(srch);
4242                     p = q;
4243           }
4244           if (strlcat(tmp, p, len) >= len)
4245                     errx(1, "expand_label: label too long");
4246           strlcpy(label, tmp, len);     /* always fits */
4247           free(tmp);
4248 }
4249 
4250 void
expand_label_if(const char * name,char * label,size_t len,const char * ifname)4251 expand_label_if(const char *name, char *label, size_t len, const char *ifname)
4252 {
4253           if (strstr(label, name) != NULL) {
4254                     if (!*ifname)
4255                               expand_label_str(label, len, name, "any");
4256                     else
4257                               expand_label_str(label, len, name, ifname);
4258           }
4259 }
4260 
4261 void
expand_label_addr(const char * name,char * label,size_t len,sa_family_t af,struct node_host * h)4262 expand_label_addr(const char *name, char *label, size_t len, sa_family_t af,
4263     struct node_host *h)
4264 {
4265           char tmp[64], tmp_not[66];
4266 
4267           if (strstr(label, name) != NULL) {
4268                     switch (h->addr.type) {
4269                     case PF_ADDR_DYNIFTL:
4270                               snprintf(tmp, sizeof(tmp), "(%s)", h->addr.v.ifname);
4271                               break;
4272                     case PF_ADDR_TABLE:
4273                               snprintf(tmp, sizeof(tmp), "<%s>", h->addr.v.tblname);
4274                               break;
4275                     case PF_ADDR_NOROUTE:
4276                               snprintf(tmp, sizeof(tmp), "no-route");
4277                               break;
4278                     case PF_ADDR_URPFFAILED:
4279                               snprintf(tmp, sizeof(tmp), "urpf-failed");
4280                               break;
4281                     case PF_ADDR_ADDRMASK:
4282                               if (!af || (PF_AZERO(&h->addr.v.a.addr, af) &&
4283                                   PF_AZERO(&h->addr.v.a.mask, af)))
4284                                         snprintf(tmp, sizeof(tmp), "any");
4285                               else {
4286                                         char      a[48];
4287                                         int       bits;
4288 
4289                                         if (inet_ntop(af, &h->addr.v.a.addr, a,
4290                                             sizeof(a)) == NULL)
4291                                                   snprintf(tmp, sizeof(tmp), "?");
4292                                         else {
4293                                                   bits = unmask(&h->addr.v.a.mask, af);
4294                                                   if ((af == AF_INET && bits < 32) ||
4295                                                       (af == AF_INET6 && bits < 128))
4296                                                             snprintf(tmp, sizeof(tmp),
4297                                                                 "%s/%d", a, bits);
4298                                                   else
4299                                                             snprintf(tmp, sizeof(tmp),
4300                                                                 "%s", a);
4301                                         }
4302                               }
4303                               break;
4304                     default:
4305                               snprintf(tmp, sizeof(tmp), "?");
4306                               break;
4307                     }
4308 
4309                     if (h->not) {
4310                               snprintf(tmp_not, sizeof(tmp_not), "! %s", tmp);
4311                               expand_label_str(label, len, name, tmp_not);
4312                     } else
4313                               expand_label_str(label, len, name, tmp);
4314           }
4315 }
4316 
4317 void
expand_label_port(const char * name,char * label,size_t len,struct node_port * port)4318 expand_label_port(const char *name, char *label, size_t len,
4319     struct node_port *port)
4320 {
4321           char       a1[6], a2[6], op[13] = "";
4322 
4323           if (strstr(label, name) != NULL) {
4324                     snprintf(a1, sizeof(a1), "%u", ntohs(port->port[0]));
4325                     snprintf(a2, sizeof(a2), "%u", ntohs(port->port[1]));
4326                     if (!port->op)
4327                               ;
4328                     else if (port->op == PF_OP_IRG)
4329                               snprintf(op, sizeof(op), "%s><%s", a1, a2);
4330                     else if (port->op == PF_OP_XRG)
4331                               snprintf(op, sizeof(op), "%s<>%s", a1, a2);
4332                     else if (port->op == PF_OP_EQ)
4333                               snprintf(op, sizeof(op), "%s", a1);
4334                     else if (port->op == PF_OP_NE)
4335                               snprintf(op, sizeof(op), "!=%s", a1);
4336                     else if (port->op == PF_OP_LT)
4337                               snprintf(op, sizeof(op), "<%s", a1);
4338                     else if (port->op == PF_OP_LE)
4339                               snprintf(op, sizeof(op), "<=%s", a1);
4340                     else if (port->op == PF_OP_GT)
4341                               snprintf(op, sizeof(op), ">%s", a1);
4342                     else if (port->op == PF_OP_GE)
4343                               snprintf(op, sizeof(op), ">=%s", a1);
4344                     expand_label_str(label, len, name, op);
4345           }
4346 }
4347 
4348 void
expand_label_proto(const char * name,char * label,size_t len,u_int8_t proto)4349 expand_label_proto(const char *name, char *label, size_t len, u_int8_t proto)
4350 {
4351           struct protoent *pe;
4352           char n[4];
4353 
4354           if (strstr(label, name) != NULL) {
4355                     pe = getprotobynumber(proto);
4356                     if (pe != NULL)
4357                               expand_label_str(label, len, name, pe->p_name);
4358                     else {
4359                               snprintf(n, sizeof(n), "%u", proto);
4360                               expand_label_str(label, len, name, n);
4361                     }
4362           }
4363 }
4364 
4365 void
expand_label_nr(const char * name,char * label,size_t len)4366 expand_label_nr(const char *name, char *label, size_t len)
4367 {
4368           char n[11];
4369 
4370           if (strstr(label, name) != NULL) {
4371                     snprintf(n, sizeof(n), "%u", pf->anchor->match);
4372                     expand_label_str(label, len, name, n);
4373           }
4374 }
4375 
4376 void
expand_label(char * label,size_t len,const char * ifname,sa_family_t af,struct node_host * src_host,struct node_port * src_port,struct node_host * dst_host,struct node_port * dst_port,u_int8_t proto)4377 expand_label(char *label, size_t len, const char *ifname, sa_family_t af,
4378     struct node_host *src_host, struct node_port *src_port,
4379     struct node_host *dst_host, struct node_port *dst_port,
4380     u_int8_t proto)
4381 {
4382           expand_label_if("$if", label, len, ifname);
4383           expand_label_addr("$srcaddr", label, len, af, src_host);
4384           expand_label_addr("$dstaddr", label, len, af, dst_host);
4385           expand_label_port("$srcport", label, len, src_port);
4386           expand_label_port("$dstport", label, len, dst_port);
4387           expand_label_proto("$proto", label, len, proto);
4388           expand_label_nr("$nr", label, len);
4389 }
4390 
4391 int
expand_altq(struct pf_altq * a,struct node_if * interfaces,struct node_queue * nqueues,struct node_queue_bw bwspec,struct node_queue_opt * opts)4392 expand_altq(struct pf_altq *a, struct node_if *interfaces,
4393     struct node_queue *nqueues, struct node_queue_bw bwspec,
4394     struct node_queue_opt *opts)
4395 {
4396           struct pf_altq                 pa, pb;
4397           char                           qname[PF_QNAME_SIZE];
4398           struct node_queue   *n;
4399           struct node_queue_bw           bw;
4400           int                            errs = 0;
4401 
4402           if ((pf->loadopt & PFCTL_FLAG_ALTQ) == 0) {
4403                     FREE_LIST(struct node_if, interfaces);
4404                     FREE_LIST(struct node_queue, nqueues);
4405                     return (0);
4406           }
4407 
4408           LOOP_THROUGH(struct node_if, interface, interfaces,
4409                     memcpy(&pa, a, sizeof(struct pf_altq));
4410                     if (strlcpy(pa.ifname, interface->ifname,
4411                         sizeof(pa.ifname)) >= sizeof(pa.ifname))
4412                               errx(1, "expand_altq: strlcpy");
4413 
4414                     if (interface->not) {
4415                               yyerror("altq on ! <interface> is not supported");
4416                               errs++;
4417                     } else {
4418                               if (eval_pfaltq(pf, &pa, &bwspec, opts))
4419                                         errs++;
4420                               else
4421                                         if (pfctl_add_altq(pf, &pa))
4422                                                   errs++;
4423 
4424                               if (pf->opts & PF_OPT_VERBOSE) {
4425                                         print_altq(&pf->paltq->altq, 0,
4426                                             &bwspec, opts);
4427                                         if (nqueues && nqueues->tail) {
4428                                                   printf("queue { ");
4429                                                   LOOP_THROUGH(struct node_queue, queue,
4430                                                       nqueues,
4431                                                             printf("%s ",
4432                                                                 queue->queue);
4433                                                   );
4434                                                   printf("}");
4435                                         }
4436                                         printf("\n");
4437                               }
4438 
4439                               if (pa.scheduler == ALTQT_CBQ ||
4440                                   pa.scheduler == ALTQT_HFSC) {
4441                                         /* now create a root queue */
4442                                         memset(&pb, 0, sizeof(struct pf_altq));
4443                                         if (strlcpy(qname, "root_", sizeof(qname)) >=
4444                                             sizeof(qname))
4445                                                   errx(1, "expand_altq: strlcpy");
4446                                         if (strlcat(qname, interface->ifname,
4447                                             sizeof(qname)) >= sizeof(qname))
4448                                                   errx(1, "expand_altq: strlcat");
4449                                         if (strlcpy(pb.qname, qname,
4450                                             sizeof(pb.qname)) >= sizeof(pb.qname))
4451                                                   errx(1, "expand_altq: strlcpy");
4452                                         if (strlcpy(pb.ifname, interface->ifname,
4453                                             sizeof(pb.ifname)) >= sizeof(pb.ifname))
4454                                                   errx(1, "expand_altq: strlcpy");
4455                                         pb.qlimit = pa.qlimit;
4456                                         pb.scheduler = pa.scheduler;
4457                                         bw.bw_absolute = pa.ifbandwidth;
4458                                         bw.bw_percent = 0;
4459                                         if (eval_pfqueue(pf, &pb, &bw, opts))
4460                                                   errs++;
4461                                         else
4462                                                   if (pfctl_add_altq(pf, &pb))
4463                                                             errs++;
4464                               }
4465 
4466                               LOOP_THROUGH(struct node_queue, queue, nqueues,
4467                                         n = calloc(1, sizeof(struct node_queue));
4468                                         if (n == NULL)
4469                                                   err(1, "expand_altq: calloc");
4470                                         if (pa.scheduler == ALTQT_CBQ ||
4471                                             pa.scheduler == ALTQT_HFSC)
4472                                                   if (strlcpy(n->parent, qname,
4473                                                       sizeof(n->parent)) >=
4474                                                       sizeof(n->parent))
4475                                                             errx(1, "expand_altq: strlcpy");
4476                                         if (strlcpy(n->queue, queue->queue,
4477                                             sizeof(n->queue)) >= sizeof(n->queue))
4478                                                   errx(1, "expand_altq: strlcpy");
4479                                         if (strlcpy(n->ifname, interface->ifname,
4480                                             sizeof(n->ifname)) >= sizeof(n->ifname))
4481                                                   errx(1, "expand_altq: strlcpy");
4482                                         n->scheduler = pa.scheduler;
4483                                         n->next = NULL;
4484                                         n->tail = n;
4485                                         if (queues == NULL)
4486                                                   queues = n;
4487                                         else {
4488                                                   queues->tail->next = n;
4489                                                   queues->tail = n;
4490                                         }
4491                               );
4492                     }
4493           );
4494           FREE_LIST(struct node_if, interfaces);
4495           FREE_LIST(struct node_queue, nqueues);
4496 
4497           return (errs);
4498 }
4499 
4500 int
expand_queue(struct pf_altq * a,struct node_if * interfaces,struct node_queue * nqueues,struct node_queue_bw bwspec,struct node_queue_opt * opts)4501 expand_queue(struct pf_altq *a, struct node_if *interfaces,
4502     struct node_queue *nqueues, struct node_queue_bw bwspec,
4503     struct node_queue_opt *opts)
4504 {
4505           struct node_queue   *n, *nq;
4506           struct pf_altq                 pa;
4507           u_int8_t             found = 0;
4508           u_int8_t             errs = 0;
4509 
4510           if ((pf->loadopt & PFCTL_FLAG_ALTQ) == 0) {
4511                     FREE_LIST(struct node_queue, nqueues);
4512                     return (0);
4513           }
4514 
4515           if (queues == NULL) {
4516                     yyerror("queue %s has no parent", a->qname);
4517                     FREE_LIST(struct node_queue, nqueues);
4518                     return (1);
4519           }
4520 
4521           LOOP_THROUGH(struct node_if, interface, interfaces,
4522                     LOOP_THROUGH(struct node_queue, tqueue, queues,
4523                               if (!strncmp(a->qname, tqueue->queue, PF_QNAME_SIZE) &&
4524                                   (interface->ifname[0] == 0 ||
4525                                   (!interface->not && !strncmp(interface->ifname,
4526                                   tqueue->ifname, IFNAMSIZ)) ||
4527                                   (interface->not && strncmp(interface->ifname,
4528                                   tqueue->ifname, IFNAMSIZ)))) {
4529                                         /* found ourself in queues */
4530                                         found++;
4531 
4532                                         memcpy(&pa, a, sizeof(struct pf_altq));
4533 
4534                                         if (pa.scheduler != ALTQT_NONE &&
4535                                             pa.scheduler != tqueue->scheduler) {
4536                                                   yyerror("exactly one scheduler type "
4537                                                       "per interface allowed");
4538                                                   errs++;
4539                                                   goto out;
4540                                         }
4541                                         pa.scheduler = tqueue->scheduler;
4542 
4543                                         /* scheduler dependent error checking */
4544                                         switch (pa.scheduler) {
4545                                         case ALTQT_PRIQ:
4546                                                   if (nqueues != NULL) {
4547                                                             yyerror("priq queues cannot "
4548                                                                 "have child queues");
4549                                                             errs++;
4550                                                             goto out;
4551                                                   }
4552                                                   if (bwspec.bw_absolute > 0 ||
4553                                                       bwspec.bw_percent < 100) {
4554                                                             yyerror("priq doesn't take "
4555                                                                 "bandwidth");
4556                                                             errs++;
4557                                                             goto out;
4558                                                   }
4559                                                   break;
4560                                         default:
4561                                                   break;
4562                                         }
4563 
4564                                         if (strlcpy(pa.ifname, tqueue->ifname,
4565                                             sizeof(pa.ifname)) >= sizeof(pa.ifname))
4566                                                   errx(1, "expand_queue: strlcpy");
4567                                         if (strlcpy(pa.parent, tqueue->parent,
4568                                             sizeof(pa.parent)) >= sizeof(pa.parent))
4569                                                   errx(1, "expand_queue: strlcpy");
4570 
4571                                         if (eval_pfqueue(pf, &pa, &bwspec, opts))
4572                                                   errs++;
4573                                         else
4574                                                   if (pfctl_add_altq(pf, &pa))
4575                                                             errs++;
4576 
4577                                         for (nq = nqueues; nq != NULL; nq = nq->next) {
4578                                                   if (!strcmp(a->qname, nq->queue)) {
4579                                                             yyerror("queue cannot have "
4580                                                                 "itself as child");
4581                                                             errs++;
4582                                                             continue;
4583                                                   }
4584                                                   n = calloc(1,
4585                                                       sizeof(struct node_queue));
4586                                                   if (n == NULL)
4587                                                             err(1, "expand_queue: calloc");
4588                                                   if (strlcpy(n->parent, a->qname,
4589                                                       sizeof(n->parent)) >=
4590                                                       sizeof(n->parent))
4591                                                             errx(1, "expand_queue strlcpy");
4592                                                   if (strlcpy(n->queue, nq->queue,
4593                                                       sizeof(n->queue)) >=
4594                                                       sizeof(n->queue))
4595                                                             errx(1, "expand_queue strlcpy");
4596                                                   if (strlcpy(n->ifname, tqueue->ifname,
4597                                                       sizeof(n->ifname)) >=
4598                                                       sizeof(n->ifname))
4599                                                             errx(1, "expand_queue strlcpy");
4600                                                   n->scheduler = tqueue->scheduler;
4601                                                   n->next = NULL;
4602                                                   n->tail = n;
4603                                                   if (queues == NULL)
4604                                                             queues = n;
4605                                                   else {
4606                                                             queues->tail->next = n;
4607                                                             queues->tail = n;
4608                                                   }
4609                                         }
4610                                         if ((pf->opts & PF_OPT_VERBOSE) && (
4611                                             (found == 1 && interface->ifname[0] == 0) ||
4612                                             (found > 0 && interface->ifname[0] != 0))) {
4613                                                   print_queue(&pf->paltq->altq, 0,
4614                                                       &bwspec, interface->ifname[0] != 0,
4615                                                       opts);
4616                                                   if (nqueues && nqueues->tail) {
4617                                                             printf("{ ");
4618                                                             LOOP_THROUGH(struct node_queue,
4619                                                                 queue, nqueues,
4620                                                                       printf("%s ",
4621                                                                           queue->queue);
4622                                                             );
4623                                                             printf("}");
4624                                                   }
4625                                                   printf("\n");
4626                                         }
4627                               }
4628                     );
4629           );
4630 
4631 out:
4632           FREE_LIST(struct node_queue, nqueues);
4633           FREE_LIST(struct node_if, interfaces);
4634 
4635           if (!found) {
4636                     yyerror("queue %s has no parent", a->qname);
4637                     errs++;
4638           }
4639 
4640           if (errs)
4641                     return (1);
4642           else
4643                     return (0);
4644 }
4645 
4646 void
expand_rule(struct pf_rule * r,struct node_if * interfaces,struct node_host * rpool_hosts,struct node_proto * protos,struct node_os * src_oses,struct node_host * src_hosts,struct node_port * src_ports,struct node_host * dst_hosts,struct node_port * dst_ports,struct node_uid * uids,struct node_gid * gids,struct node_icmp * icmp_types,const char * anchor_call)4647 expand_rule(struct pf_rule *r,
4648     struct node_if *interfaces, struct node_host *rpool_hosts,
4649     struct node_proto *protos, struct node_os *src_oses,
4650     struct node_host *src_hosts, struct node_port *src_ports,
4651     struct node_host *dst_hosts, struct node_port *dst_ports,
4652     struct node_uid *uids, struct node_gid *gids, struct node_icmp *icmp_types,
4653     const char *anchor_call)
4654 {
4655           sa_family_t                    af = r->af;
4656           int                            added = 0, error = 0;
4657           char                           ifname[IF_NAMESIZE];
4658           char                           label[PF_RULE_LABEL_SIZE];
4659           char                           tagname[PF_TAG_NAME_SIZE];
4660           char                           match_tagname[PF_TAG_NAME_SIZE];
4661           struct pf_pooladdr  *pa;
4662           struct node_host    *h;
4663           u_int8_t             flags, flagset, keep_state;
4664 
4665           if (strlcpy(label, r->label, sizeof(label)) >= sizeof(label))
4666                     errx(1, "expand_rule: strlcpy");
4667           if (strlcpy(tagname, r->tagname, sizeof(tagname)) >= sizeof(tagname))
4668                     errx(1, "expand_rule: strlcpy");
4669           if (strlcpy(match_tagname, r->match_tagname, sizeof(match_tagname)) >=
4670               sizeof(match_tagname))
4671                     errx(1, "expand_rule: strlcpy");
4672           flags = r->flags;
4673           flagset = r->flagset;
4674           keep_state = r->keep_state;
4675 
4676           LOOP_THROUGH(struct node_if, interface, interfaces,
4677           LOOP_THROUGH(struct node_proto, proto, protos,
4678           LOOP_THROUGH(struct node_icmp, icmp_type, icmp_types,
4679           LOOP_THROUGH(struct node_host, src_host, src_hosts,
4680           LOOP_THROUGH(struct node_port, src_port, src_ports,
4681           LOOP_THROUGH(struct node_os, src_os, src_oses,
4682           LOOP_THROUGH(struct node_host, dst_host, dst_hosts,
4683           LOOP_THROUGH(struct node_port, dst_port, dst_ports,
4684           LOOP_THROUGH(struct node_uid, uid, uids,
4685           LOOP_THROUGH(struct node_gid, gid, gids,
4686 
4687                     r->af = af;
4688                     /* for link-local IPv6 address, interface must match up */
4689                     if ((r->af && src_host->af && r->af != src_host->af) ||
4690                         (r->af && dst_host->af && r->af != dst_host->af) ||
4691                         (src_host->af && dst_host->af &&
4692                         src_host->af != dst_host->af) ||
4693                         (src_host->ifindex && dst_host->ifindex &&
4694                         src_host->ifindex != dst_host->ifindex) ||
4695                         (src_host->ifindex && *interface->ifname &&
4696                         src_host->ifindex != if_nametoindex(interface->ifname)) ||
4697                         (dst_host->ifindex && *interface->ifname &&
4698                         dst_host->ifindex != if_nametoindex(interface->ifname)))
4699                               continue;
4700                     if (!r->af && src_host->af)
4701                               r->af = src_host->af;
4702                     else if (!r->af && dst_host->af)
4703                               r->af = dst_host->af;
4704 
4705                     if (*interface->ifname)
4706                               strlcpy(r->ifname, interface->ifname,
4707                                   sizeof(r->ifname));
4708                     else if (if_indextoname(src_host->ifindex, ifname))
4709                               strlcpy(r->ifname, ifname, sizeof(r->ifname));
4710                     else if (if_indextoname(dst_host->ifindex, ifname))
4711                               strlcpy(r->ifname, ifname, sizeof(r->ifname));
4712                     else
4713                               memset(r->ifname, '\0', sizeof(r->ifname));
4714 
4715                     if (strlcpy(r->label, label, sizeof(r->label)) >=
4716                         sizeof(r->label))
4717                               errx(1, "expand_rule: strlcpy");
4718                     if (strlcpy(r->tagname, tagname, sizeof(r->tagname)) >=
4719                         sizeof(r->tagname))
4720                               errx(1, "expand_rule: strlcpy");
4721                     if (strlcpy(r->match_tagname, match_tagname,
4722                         sizeof(r->match_tagname)) >= sizeof(r->match_tagname))
4723                               errx(1, "expand_rule: strlcpy");
4724                     expand_label(r->label, PF_RULE_LABEL_SIZE, r->ifname, r->af,
4725                         src_host, src_port, dst_host, dst_port, proto->proto);
4726                     expand_label(r->tagname, PF_TAG_NAME_SIZE, r->ifname, r->af,
4727                         src_host, src_port, dst_host, dst_port, proto->proto);
4728                     expand_label(r->match_tagname, PF_TAG_NAME_SIZE, r->ifname,
4729                         r->af, src_host, src_port, dst_host, dst_port,
4730                         proto->proto);
4731 
4732                     error += check_netmask(src_host, r->af);
4733                     error += check_netmask(dst_host, r->af);
4734 
4735                     r->ifnot = interface->not;
4736                     r->proto = proto->proto;
4737                     r->src.addr = src_host->addr;
4738                     r->src.neg = src_host->not;
4739                     r->src.port[0] = src_port->port[0];
4740                     r->src.port[1] = src_port->port[1];
4741                     r->src.port_op = src_port->op;
4742                     r->dst.addr = dst_host->addr;
4743                     r->dst.neg = dst_host->not;
4744                     r->dst.port[0] = dst_port->port[0];
4745                     r->dst.port[1] = dst_port->port[1];
4746                     r->dst.port_op = dst_port->op;
4747                     r->uid.op = uid->op;
4748                     r->uid.uid[0] = uid->uid[0];
4749                     r->uid.uid[1] = uid->uid[1];
4750                     r->gid.op = gid->op;
4751                     r->gid.gid[0] = gid->gid[0];
4752                     r->gid.gid[1] = gid->gid[1];
4753                     r->type = icmp_type->type;
4754                     r->code = icmp_type->code;
4755 
4756                     if ((keep_state == PF_STATE_MODULATE ||
4757                         keep_state == PF_STATE_SYNPROXY) &&
4758                         r->proto && r->proto != IPPROTO_TCP)
4759                               r->keep_state = PF_STATE_NORMAL;
4760                     else
4761                               r->keep_state = keep_state;
4762 
4763                     if (r->proto && r->proto != IPPROTO_TCP) {
4764                               r->flags = 0;
4765                               r->flagset = 0;
4766                     } else {
4767                               r->flags = flags;
4768                               r->flagset = flagset;
4769                     }
4770                     if (icmp_type->proto && r->proto != icmp_type->proto) {
4771                               yyerror("icmp-type mismatch");
4772                               error++;
4773                     }
4774 
4775                     if (src_os && src_os->os) {
4776                               r->os_fingerprint = pfctl_get_fingerprint(src_os->os);
4777                               if ((pf->opts & PF_OPT_VERBOSE2) &&
4778                                   r->os_fingerprint == PF_OSFP_NOMATCH)
4779                                         fprintf(stderr,
4780                                             "warning: unknown '%s' OS fingerprint\n",
4781                                             src_os->os);
4782                     } else {
4783                               r->os_fingerprint = PF_OSFP_ANY;
4784                     }
4785 
4786                     TAILQ_INIT(&r->rpool.list);
4787                     for (h = rpool_hosts; h != NULL; h = h->next) {
4788                               pa = calloc(1, sizeof(struct pf_pooladdr));
4789                               if (pa == NULL)
4790                                         err(1, "expand_rule: calloc");
4791                               pa->addr = h->addr;
4792                               if (h->ifname != NULL) {
4793                                         if (strlcpy(pa->ifname, h->ifname,
4794                                             sizeof(pa->ifname)) >=
4795                                             sizeof(pa->ifname))
4796                                                   errx(1, "expand_rule: strlcpy");
4797                               } else
4798                                         pa->ifname[0] = 0;
4799                               TAILQ_INSERT_TAIL(&r->rpool.list, pa, entries);
4800                     }
4801 
4802                     if (rule_consistent(r, anchor_call[0]) < 0 || error)
4803                               yyerror("skipping rule due to errors");
4804                     else {
4805                               r->nr = pf->astack[pf->asd]->match++;
4806                               pfctl_add_rule(pf, r, anchor_call);
4807                               added++;
4808                     }
4809 
4810           ))))))))));
4811 
4812           FREE_LIST(struct node_if, interfaces);
4813           FREE_LIST(struct node_proto, protos);
4814           FREE_LIST(struct node_host, src_hosts);
4815           FREE_LIST(struct node_port, src_ports);
4816           FREE_LIST(struct node_os, src_oses);
4817           FREE_LIST(struct node_host, dst_hosts);
4818           FREE_LIST(struct node_port, dst_ports);
4819           FREE_LIST(struct node_uid, uids);
4820           FREE_LIST(struct node_gid, gids);
4821           FREE_LIST(struct node_icmp, icmp_types);
4822           FREE_LIST(struct node_host, rpool_hosts);
4823 
4824           if (!added)
4825                     yyerror("rule expands to no valid combination");
4826 }
4827 
4828 int
expand_skip_interface(struct node_if * interfaces)4829 expand_skip_interface(struct node_if *interfaces)
4830 {
4831           int       errs = 0;
4832 
4833           if (!interfaces || (!interfaces->next && !interfaces->not &&
4834               !strcmp(interfaces->ifname, "none"))) {
4835                     if (pf->opts & PF_OPT_VERBOSE)
4836                               printf("set skip on none\n");
4837                     errs = pfctl_set_interface_flags(pf, "", PFI_IFLAG_SKIP, 0);
4838                     return (errs);
4839           }
4840 
4841           if (pf->opts & PF_OPT_VERBOSE)
4842                     printf("set skip on {");
4843           LOOP_THROUGH(struct node_if, interface, interfaces,
4844                     if (pf->opts & PF_OPT_VERBOSE)
4845                               printf(" %s", interface->ifname);
4846                     if (interface->not) {
4847                               yyerror("skip on ! <interface> is not supported");
4848                               errs++;
4849                     } else
4850                               errs += pfctl_set_interface_flags(pf,
4851                                   interface->ifname, PFI_IFLAG_SKIP, 1);
4852           );
4853           if (pf->opts & PF_OPT_VERBOSE)
4854                     printf(" }\n");
4855 
4856           FREE_LIST(struct node_if, interfaces);
4857 
4858           if (errs)
4859                     return (1);
4860           else
4861                     return (0);
4862 }
4863 
4864 #undef FREE_LIST
4865 #undef LOOP_THROUGH
4866 
4867 int
check_rulestate(int desired_state)4868 check_rulestate(int desired_state)
4869 {
4870           if (require_order && (rulestate > desired_state)) {
4871                     yyerror("Rules must be in order: options, normalization, "
4872                         "queueing, translation, filtering");
4873                     return (1);
4874           }
4875           rulestate = desired_state;
4876           return (0);
4877 }
4878 
4879 int
kw_cmp(const void * k,const void * e)4880 kw_cmp(const void *k, const void *e)
4881 {
4882           return (strcmp(k, ((const struct keywords *)e)->k_name));
4883 }
4884 
4885 int
lookup(char * s)4886 lookup(char *s)
4887 {
4888           /* this has to be sorted always */
4889           static const struct keywords keywords[] = {
4890                     { "all",            ALL},
4891                     { "allow-opts",               ALLOWOPTS},
4892                     { "altq",           ALTQ},
4893                     { "anchor",                   ANCHOR},
4894                     { "antispoof",                ANTISPOOF},
4895                     { "any",            ANY},
4896                     { "bandwidth",                BANDWIDTH},
4897                     { "binat",                    BINAT},
4898                     { "binat-anchor",   BINATANCHOR},
4899                     { "bitmask",                  BITMASK},
4900                     { "block",                    BLOCK},
4901                     { "block-policy",   BLOCKPOLICY},
4902                     { "cbq",            CBQ},
4903                     { "code",           CODE},
4904                     { "crop",           FRAGCROP},
4905                     { "debug",                    DEBUG},
4906                     { "drop",           DROP},
4907                     { "drop-ovl",                 FRAGDROP},
4908                     { "dup-to",                   DUPTO},
4909                     { "fastroute",                FASTROUTE},
4910                     { "file",           FILENAME},
4911                     { "fingerprints",   FINGERPRINTS},
4912                     { "flags",                    FLAGS},
4913                     { "floating",                 FLOATING},
4914                     { "flush",                    FLUSH},
4915                     { "for",            FOR},
4916                     { "fragment",                 FRAGMENT},
4917                     { "from",           FROM},
4918                     { "global",                   GLOBAL},
4919                     { "group",                    GROUP},
4920                     { "hfsc",           HFSC},
4921                     { "hostid",                   HOSTID},
4922                     { "icmp-type",                ICMPTYPE},
4923                     { "icmp6-type",               ICMP6TYPE},
4924                     { "if-bound",                 IFBOUND},
4925                     { "in",                       IN},
4926                     { "inet",           INET},
4927                     { "inet6",                    INET6},
4928                     { "keep",           KEEP},
4929                     { "label",                    LABEL},
4930                     { "limit",                    LIMIT},
4931                     { "linkshare",                LINKSHARE},
4932                     { "load",           LOAD},
4933                     { "log",            LOG},
4934                     { "loginterface",   LOGINTERFACE},
4935                     { "max",            MAXIMUM},
4936                     { "max-mss",                  MAXMSS},
4937                     { "max-src-conn",   MAXSRCCONN},
4938                     { "max-src-conn-rate",        MAXSRCCONNRATE},
4939                     { "max-src-nodes",  MAXSRCNODES},
4940                     { "max-src-states", MAXSRCSTATES},
4941                     { "min-ttl",                  MINTTL},
4942                     { "modulate",                 MODULATE},
4943                     { "nat",            NAT},
4944                     { "nat-anchor",               NATANCHOR},
4945                     { "no",                       NO},
4946                     { "no-df",                    NODF},
4947                     { "no-route",                 NOROUTE},
4948                     { "no-sync",                  NOSYNC},
4949                     { "on",                       ON},
4950                     { "optimization",   OPTIMIZATION},
4951                     { "os",                       OS},
4952                     { "out",            OUT},
4953                     { "overload",                 OVERLOAD},
4954                     { "pass",           PASS},
4955                     { "port",           PORT},
4956                     { "priority",                 PRIORITY},
4957                     { "priq",           PRIQ},
4958                     { "probability",    PROBABILITY},
4959                     { "proto",                    PROTO},
4960                     { "qlimit",                   QLIMIT},
4961                     { "queue",                    QUEUE},
4962                     { "quick",                    QUICK},
4963                     { "random",                   RANDOM},
4964                     { "random-id",                RANDOMID},
4965                     { "rdr",            RDR},
4966                     { "rdr-anchor",               RDRANCHOR},
4967                     { "realtime",                 REALTIME},
4968                     { "reassemble",               REASSEMBLE},
4969                     { "reply-to",                 REPLYTO},
4970                     { "require-order",  REQUIREORDER},
4971                     { "return",                   RETURN},
4972                     { "return-icmp",    RETURNICMP},
4973                     { "return-icmp6",   RETURNICMP6},
4974                     { "return-rst",               RETURNRST},
4975                     { "round-robin",    ROUNDROBIN},
4976                     { "route",                    ROUTE},
4977                     { "route-to",                 ROUTETO},
4978                     { "rtable",                   RTABLE},
4979                     { "rule",           RULE},
4980                     { "ruleset-optimization",     RULESET_OPTIMIZATION},
4981                     { "scrub",                    SCRUB},
4982                     { "set",            SET},
4983                     { "skip",           SKIP},
4984                     { "source-hash",    SOURCEHASH},
4985                     { "source-track",   SOURCETRACK},
4986                     { "state",                    STATE},
4987                     { "state-policy",   STATEPOLICY},
4988                     { "static-port",    STATICPORT},
4989                     { "sticky-address", STICKYADDRESS},
4990                     { "synproxy",                 SYNPROXY},
4991                     { "table",                    TABLE},
4992                     { "tag",            TAG},
4993                     { "tagged",                   TAGGED},
4994                     { "tbrsize",                  TBRSIZE},
4995                     { "timeout",                  TIMEOUT},
4996                     { "to",                       TO},
4997                     { "tos",            TOS},
4998                     { "ttl",            TTL},
4999                     { "upperlimit",               UPPERLIMIT},
5000                     { "urpf-failed",    URPFFAILED},
5001                     { "user",           USER},
5002           };
5003           const struct keywords         *p;
5004 
5005           p = bsearch(s, keywords, sizeof(keywords)/sizeof(keywords[0]),
5006               sizeof(keywords[0]), kw_cmp);
5007 
5008           if (p) {
5009                     if (debug > 1)
5010                               fprintf(stderr, "%s: %d\n", s, p->k_val);
5011                     return (p->k_val);
5012           } else {
5013                     if (debug > 1)
5014                               fprintf(stderr, "string: %s\n", s);
5015                     return (STRING);
5016           }
5017 }
5018 
5019 #define MAXPUSHBACK 128
5020 
5021 char      *parsebuf;
5022 int        parseindex;
5023 char       pushback_buffer[MAXPUSHBACK];
5024 int        pushback_index = 0;
5025 
5026 int
lgetc(FILE * f)5027 lgetc(FILE *f)
5028 {
5029           int       c, next;
5030 
5031           if (parsebuf) {
5032                     /* Read character from the parsebuffer instead of input. */
5033                     if (parseindex >= 0) {
5034                               c = parsebuf[parseindex++];
5035                               if (c != '\0')
5036                                         return (c);
5037                               parsebuf = NULL;
5038                     } else
5039                               parseindex++;
5040           }
5041 
5042           if (pushback_index)
5043                     return (pushback_buffer[--pushback_index]);
5044 
5045           while ((c = getc(f)) == '\\') {
5046                     next = getc(f);
5047                     if (next != '\n') {
5048                               c = next;
5049                               break;
5050                     }
5051                     yylval.lineno = lineno;
5052                     lineno++;
5053           }
5054           if (c == '\t' || c == ' ') {
5055                     /* Compress blanks to a single space. */
5056                     do {
5057                               c = getc(f);
5058                     } while (c == '\t' || c == ' ');
5059                     ungetc(c, f);
5060                     c = ' ';
5061           }
5062 
5063           return (c);
5064 }
5065 
5066 int
lungetc(int c)5067 lungetc(int c)
5068 {
5069           if (c == EOF)
5070                     return (EOF);
5071           if (parsebuf) {
5072                     parseindex--;
5073                     if (parseindex >= 0)
5074                               return (c);
5075           }
5076           if (pushback_index < MAXPUSHBACK-1)
5077                     return (pushback_buffer[pushback_index++] = c);
5078           else
5079                     return (EOF);
5080 }
5081 
5082 int
findeol(void)5083 findeol(void)
5084 {
5085           int       c;
5086 
5087           parsebuf = NULL;
5088           pushback_index = 0;
5089 
5090           /* skip to either EOF or the first real EOL */
5091           while (1) {
5092                     c = lgetc(fin);
5093                     if (c == '\n') {
5094                               lineno++;
5095                               break;
5096                     }
5097                     if (c == EOF)
5098                               break;
5099           }
5100           return (ERROR);
5101 }
5102 
5103 int
yylex(void)5104 yylex(void)
5105 {
5106           char       buf[8096];
5107           char      *p, *val;
5108           int        endc, c, next;
5109           int        token;
5110 
5111 top:
5112           p = buf;
5113           while ((c = lgetc(fin)) == ' ')
5114                     ; /* nothing */
5115 
5116           yylval.lineno = lineno;
5117           if (c == '#')
5118                     while ((c = lgetc(fin)) != '\n' && c != EOF)
5119                               ; /* nothing */
5120           if (c == '$' && parsebuf == NULL) {
5121                     while (1) {
5122                               if ((c = lgetc(fin)) == EOF)
5123                                         return (0);
5124 
5125                               if (p + 1 >= buf + sizeof(buf) - 1) {
5126                                         yyerror("string too long");
5127                                         return (findeol());
5128                               }
5129                               if (isalnum(c) || c == '_') {
5130                                         *p++ = (char)c;
5131                                         continue;
5132                               }
5133                               *p = '\0';
5134                               lungetc(c);
5135                               break;
5136                     }
5137                     val = symget(buf);
5138                     if (val == NULL) {
5139                               yyerror("macro '%s' not defined", buf);
5140                               return (findeol());
5141                     }
5142                     parsebuf = val;
5143                     parseindex = 0;
5144                     goto top;
5145           }
5146 
5147           switch (c) {
5148           case '\'':
5149           case '"':
5150                     endc = c;
5151                     while (1) {
5152                               if ((c = lgetc(fin)) == EOF)
5153                                         return (0);
5154                               if (c == endc) {
5155                                         *p = '\0';
5156                                         break;
5157                               }
5158                               if (c == '\n') {
5159                                         lineno++;
5160                                         continue;
5161                               }
5162                               if (p + 1 >= buf + sizeof(buf) - 1) {
5163                                         yyerror("string too long");
5164                                         return (findeol());
5165                               }
5166                               *p++ = (char)c;
5167                     }
5168                     yylval.v.string = strdup(buf);
5169                     if (yylval.v.string == NULL)
5170                               err(1, "yylex: strdup");
5171                     return (STRING);
5172           case '<':
5173                     next = lgetc(fin);
5174                     if (next == '>') {
5175                               yylval.v.i = PF_OP_XRG;
5176                               return (PORTBINARY);
5177                     }
5178                     lungetc(next);
5179                     break;
5180           case '>':
5181                     next = lgetc(fin);
5182                     if (next == '<') {
5183                               yylval.v.i = PF_OP_IRG;
5184                               return (PORTBINARY);
5185                     }
5186                     lungetc(next);
5187                     break;
5188           case '-':
5189                     next = lgetc(fin);
5190                     if (next == '>')
5191                               return (ARROW);
5192                     lungetc(next);
5193                     break;
5194           }
5195 
5196 #define allowed_in_string(x) \
5197           (isalnum(x) || (ispunct(x) && x != '(' && x != ')' && \
5198           x != '{' && x != '}' && x != '<' && x != '>' && \
5199           x != '!' && x != '=' && x != '/' && x != '#' && \
5200           x != ','))
5201 
5202           if (isalnum(c) || c == ':' || c == '_') {
5203                     do {
5204                               *p++ = c;
5205                               if ((unsigned)(p-buf) >= sizeof(buf)) {
5206                                         yyerror("string too long");
5207                                         return (findeol());
5208                               }
5209                     } while ((c = lgetc(fin)) != EOF && (allowed_in_string(c)));
5210                     lungetc(c);
5211                     *p = '\0';
5212                     if ((token = lookup(buf)) == STRING)
5213                               if ((yylval.v.string = strdup(buf)) == NULL)
5214                                         err(1, "yylex: strdup");
5215                     return (token);
5216           }
5217           if (c == '\n') {
5218                     yylval.lineno = lineno;
5219                     lineno++;
5220           }
5221           if (c == EOF)
5222                     return (0);
5223           return (c);
5224 }
5225 
5226 int
parse_rules(FILE * input,struct pfctl * xpf)5227 parse_rules(FILE *input, struct pfctl *xpf)
5228 {
5229           struct sym          *sym, *next;
5230 
5231           fin = input;
5232           pf = xpf;
5233           lineno = 1;
5234           errors = 0;
5235           rulestate = PFCTL_STATE_NONE;
5236           returnicmpdefault = (ICMP_UNREACH << 8) | ICMP_UNREACH_PORT;
5237           returnicmp6default =
5238               (ICMP6_DST_UNREACH << 8) | ICMP6_DST_UNREACH_NOPORT;
5239           blockpolicy = PFRULE_DROP;
5240           require_order = 1;
5241 
5242           yyparse();
5243 
5244           /* Free macros and check which have not been used. */
5245           for (sym = TAILQ_FIRST(&symhead); sym != NULL; sym = next) {
5246                     next = TAILQ_NEXT(sym, entries);
5247                     if ((pf->opts & PF_OPT_VERBOSE2) && !sym->used)
5248                               fprintf(stderr, "warning: macro '%s' not "
5249                                   "used\n", sym->nam);
5250                     free(sym->nam);
5251                     free(sym->val);
5252                     TAILQ_REMOVE(&symhead, sym, entries);
5253                     free(sym);
5254           }
5255 
5256           return (errors ? -1 : 0);
5257 }
5258 
5259 /*
5260  * Over-designed efficiency is a French and German concept, so how about
5261  * we wait until they discover this ugliness and make it all fancy.
5262  */
5263 int
symset(const char * nam,const char * val,int persist)5264 symset(const char *nam, const char *val, int persist)
5265 {
5266           struct sym          *sym;
5267 
5268           for (sym = TAILQ_FIRST(&symhead); sym && strcmp(nam, sym->nam);
5269               sym = TAILQ_NEXT(sym, entries))
5270                     ;         /* nothing */
5271 
5272           if (sym != NULL) {
5273                     if (sym->persist == 1)
5274                               return (0);
5275                     else {
5276                               free(sym->nam);
5277                               free(sym->val);
5278                               TAILQ_REMOVE(&symhead, sym, entries);
5279                               free(sym);
5280                     }
5281           }
5282           if ((sym = calloc(1, sizeof(*sym))) == NULL)
5283                     return (-1);
5284 
5285           sym->nam = strdup(nam);
5286           if (sym->nam == NULL) {
5287                     free(sym);
5288                     return (-1);
5289           }
5290           sym->val = strdup(val);
5291           if (sym->val == NULL) {
5292                     free(sym->nam);
5293                     free(sym);
5294                     return (-1);
5295           }
5296           sym->used = 0;
5297           sym->persist = persist;
5298           TAILQ_INSERT_TAIL(&symhead, sym, entries);
5299           return (0);
5300 }
5301 
5302 int
pfctl_cmdline_symset(char * s)5303 pfctl_cmdline_symset(char *s)
5304 {
5305           char      *sym, *val;
5306           int        ret;
5307 
5308           if ((val = strrchr(s, '=')) == NULL)
5309                     return (-1);
5310 
5311           if ((sym = malloc(strlen(s) - strlen(val) + 1)) == NULL)
5312                     err(1, "pfctl_cmdline_symset: malloc");
5313 
5314           strlcpy(sym, s, strlen(s) - strlen(val) + 1);
5315 
5316           ret = symset(sym, val + 1, 1);
5317           free(sym);
5318 
5319           return (ret);
5320 }
5321 
5322 char *
symget(const char * nam)5323 symget(const char *nam)
5324 {
5325           struct sym          *sym;
5326 
5327           TAILQ_FOREACH(sym, &symhead, entries)
5328                     if (strcmp(nam, sym->nam) == 0) {
5329                               sym->used = 1;
5330                               return (sym->val);
5331                     }
5332           return (NULL);
5333 }
5334 
5335 void
mv_rules(struct pf_ruleset * src,struct pf_ruleset * dst)5336 mv_rules(struct pf_ruleset *src, struct pf_ruleset *dst)
5337 {
5338           int i;
5339           struct pf_rule *r;
5340 
5341           for (i = 0; i < PF_RULESET_MAX; ++i) {
5342                     while ((r = TAILQ_FIRST(src->rules[i].active.ptr))
5343                         != NULL) {
5344                               TAILQ_REMOVE(src->rules[i].active.ptr, r, entries);
5345                               TAILQ_INSERT_TAIL(dst->rules[i].active.ptr, r, entries);
5346                               dst->anchor->match++;
5347                     }
5348                     src->anchor->match = 0;
5349                     while ((r = TAILQ_FIRST(src->rules[i].inactive.ptr))
5350                         != NULL) {
5351                               TAILQ_REMOVE(src->rules[i].inactive.ptr, r, entries);
5352                               TAILQ_INSERT_TAIL(dst->rules[i].inactive.ptr,
5353                                         r, entries);
5354                     }
5355           }
5356 }
5357 
5358 void
decide_address_family(struct node_host * n,sa_family_t * af)5359 decide_address_family(struct node_host *n, sa_family_t *af)
5360 {
5361           if (*af != 0 || n == NULL)
5362                     return;
5363           *af = n->af;
5364           while ((n = n->next) != NULL) {
5365                     if (n->af != *af) {
5366                               *af = 0;
5367                               return;
5368                     }
5369           }
5370 }
5371 
5372 void
remove_invalid_hosts(struct node_host ** nh,sa_family_t * af)5373 remove_invalid_hosts(struct node_host **nh, sa_family_t *af)
5374 {
5375           struct node_host    *n = *nh, *prev = NULL;
5376 
5377           while (n != NULL) {
5378                     if (*af && n->af && n->af != *af) {
5379                               /* unlink and free n */
5380                               struct node_host *next = n->next;
5381 
5382                               /* adjust tail pointer */
5383                               if (n == (*nh)->tail)
5384                                         (*nh)->tail = prev;
5385                               /* adjust previous node's next pointer */
5386                               if (prev == NULL)
5387                                         *nh = next;
5388                               else
5389                                         prev->next = next;
5390                               /* free node */
5391                               if (n->ifname != NULL)
5392                                         free(n->ifname);
5393                               free(n);
5394                               n = next;
5395                     } else {
5396                               if (n->af && !*af)
5397                                         *af = n->af;
5398                               prev = n;
5399                               n = n->next;
5400                     }
5401           }
5402 }
5403 
5404 int
invalid_redirect(struct node_host * nh,sa_family_t af)5405 invalid_redirect(struct node_host *nh, sa_family_t af)
5406 {
5407           if (!af) {
5408                     struct node_host *n;
5409 
5410                     /* tables and dyniftl are ok without an address family */
5411                     for (n = nh; n != NULL; n = n->next) {
5412                               if (n->addr.type != PF_ADDR_TABLE &&
5413                                   n->addr.type != PF_ADDR_DYNIFTL) {
5414                                         yyerror("address family not given and "
5415                                             "translation address expands to multiple "
5416                                             "address families");
5417                                         return (1);
5418                               }
5419                     }
5420           }
5421           if (nh == NULL) {
5422                     yyerror("no translation address with matching address family "
5423                         "found.");
5424                     return (1);
5425           }
5426           return (0);
5427 }
5428 
5429 int
atoul(char * s,u_long * ulvalp)5430 atoul(char *s, u_long *ulvalp)
5431 {
5432           u_long     ulval;
5433           char      *ep;
5434 
5435           errno = 0;
5436           ulval = strtoul(s, &ep, 0);
5437           if (s[0] == '\0' || *ep != '\0')
5438                     return (-1);
5439           if (errno == ERANGE && ulval == ULONG_MAX)
5440                     return (-1);
5441           *ulvalp = ulval;
5442           return (0);
5443 }
5444 
5445 int
getservice(char * n)5446 getservice(char *n)
5447 {
5448           struct servent      *s;
5449           u_long               ulval;
5450 
5451           if (atoul(n, &ulval) == 0) {
5452                     if (ulval > 65535) {
5453                               yyerror("illegal port value %lu", ulval);
5454                               return (-1);
5455                     }
5456                     return (htons(ulval));
5457           } else {
5458                     s = getservbyname(n, "tcp");
5459                     if (s == NULL)
5460                               s = getservbyname(n, "udp");
5461                     if (s == NULL) {
5462                               yyerror("unknown port %s", n);
5463                               return (-1);
5464                     }
5465                     return (s->s_port);
5466           }
5467 }
5468 
5469 int
rule_label(struct pf_rule * r,char * s)5470 rule_label(struct pf_rule *r, char *s)
5471 {
5472           if (s) {
5473                     if (strlcpy(r->label, s, sizeof(r->label)) >=
5474                         sizeof(r->label)) {
5475                               yyerror("rule label too long (max %d chars)",
5476                                   sizeof(r->label)-1);
5477                               return (-1);
5478                     }
5479           }
5480           return (0);
5481 }
5482 
5483 u_int16_t
parseicmpspec(char * w,sa_family_t af)5484 parseicmpspec(char *w, sa_family_t af)
5485 {
5486           const struct icmpcodeent      *p;
5487           u_long                                   ulval;
5488           u_int8_t                       icmptype;
5489 
5490           if (af == AF_INET)
5491                     icmptype = returnicmpdefault >> 8;
5492           else
5493                     icmptype = returnicmp6default >> 8;
5494 
5495           if (atoul(w, &ulval) == -1) {
5496                     if ((p = geticmpcodebyname(icmptype, w, af)) == NULL) {
5497                               yyerror("unknown icmp code %s", w);
5498                               return (0);
5499                     }
5500                     ulval = p->code;
5501           }
5502           if (ulval > 255) {
5503                     yyerror("invalid icmp code %lu", ulval);
5504                     return (0);
5505           }
5506           return (icmptype << 8 | ulval);
5507 }
5508 
5509 int
pfctl_load_anchors(int dev,struct pfctl * pf,struct pfr_buffer * trans)5510 pfctl_load_anchors(int dev, struct pfctl *pf, struct pfr_buffer *trans)
5511 {
5512           struct loadanchors  *la;
5513           FILE                          *fin;
5514 
5515           TAILQ_FOREACH(la, &loadanchorshead, entries) {
5516                     if (pf->opts & PF_OPT_VERBOSE)
5517                               fprintf(stderr, "\nLoading anchor %s from %s\n",
5518                                   la->anchorname, la->filename);
5519                     if ((fin = pfctl_fopen(la->filename, "r")) == NULL) {
5520                               warn("%s", la->filename);
5521                               continue;
5522                     }
5523                     if (pfctl_rules(dev, la->filename, fin, pf->opts, pf->optimize,
5524                         la->anchorname, trans) == -1)
5525                               return (-1);
5526           }
5527 
5528           return (0);
5529 }
5530