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