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