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