1 /* $OpenBSD: parse.y,v 1.554 2008/10/17 12:59:53 henning Exp $ */
2
3 /*-
4 * SPDX-License-Identifier: BSD-2-Clause
5 *
6 * Copyright (c) 2001 Markus Friedl. All rights reserved.
7 * Copyright (c) 2001 Daniel Hartmeier. All rights reserved.
8 * Copyright (c) 2001 Theo de Raadt. All rights reserved.
9 * Copyright (c) 2002,2003 Henning Brauer. All rights reserved.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
21 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
22 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
23 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
24 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
25 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
29 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 */
31 %{
32 #include <sys/cdefs.h>
33 #define PFIOC_USE_LATEST
34
35 #include <sys/types.h>
36 #include <sys/socket.h>
37 #include <sys/stat.h>
38 #ifdef __FreeBSD__
39 #include <sys/sysctl.h>
40 #endif
41 #include <net/if.h>
42 #include <netinet/in.h>
43 #include <netinet/in_systm.h>
44 #include <netinet/ip.h>
45 #include <netinet/ip_icmp.h>
46 #include <netinet/icmp6.h>
47 #include <net/pfvar.h>
48 #include <arpa/inet.h>
49 #include <net/altq/altq.h>
50 #include <net/altq/altq_cbq.h>
51 #include <net/altq/altq_codel.h>
52 #include <net/altq/altq_priq.h>
53 #include <net/altq/altq_hfsc.h>
54 #include <net/altq/altq_fairq.h>
55
56 #include <assert.h>
57 #include <stdio.h>
58 #include <unistd.h>
59 #include <stdlib.h>
60 #include <netdb.h>
61 #include <stdarg.h>
62 #include <errno.h>
63 #include <string.h>
64 #include <ctype.h>
65 #include <math.h>
66 #include <err.h>
67 #include <limits.h>
68 #include <pwd.h>
69 #include <grp.h>
70 #include <md5.h>
71
72 #include "pfctl_parser.h"
73 #include "pfctl.h"
74
75 #define ISSET(_v, _m) ((_v) & (_m))
76
77 static struct pfctl *pf = NULL;
78 static int debug = 0;
79 static int rulestate = 0;
80 static u_int16_t returnicmpdefault =
81 (ICMP_UNREACH << 8) | ICMP_UNREACH_PORT;
82 static u_int16_t returnicmp6default =
83 (ICMP6_DST_UNREACH << 8) | ICMP6_DST_UNREACH_NOPORT;
84 static int blockpolicy = PFRULE_DROP;
85 static int failpolicy = PFRULE_DROP;
86 static int require_order = 1;
87 static int default_statelock;
88
89 static TAILQ_HEAD(files, file) files = TAILQ_HEAD_INITIALIZER(files);
90 static struct file {
91 TAILQ_ENTRY(file) entry;
92 FILE *stream;
93 char *name;
94 size_t ungetpos;
95 size_t ungetsize;
96 u_char *ungetbuf;
97 int eof_reached;
98 int lineno;
99 int errors;
100 } *file, *topfile;
101 struct file *pushfile(const char *, int);
102 int popfile(void);
103 int check_file_secrecy(int, const char *);
104 int yyparse(void);
105 int yylex(void);
106 int yyerror(const char *, ...);
107 int kw_cmp(const void *, const void *);
108 int lookup(char *);
109 int igetc(void);
110 int lgetc(int);
111 void lungetc(int);
112 int findeol(void);
113
114 static TAILQ_HEAD(symhead, sym) symhead = TAILQ_HEAD_INITIALIZER(symhead);
115 struct sym {
116 TAILQ_ENTRY(sym) entry;
117 int used;
118 int persist;
119 char *nam;
120 char *val;
121 };
122 int symset(const char *, const char *, int);
123 char *symget(const char *);
124
125 int atoul(char *, u_long *);
126
127 enum {
128 PFCTL_STATE_NONE,
129 PFCTL_STATE_OPTION,
130 PFCTL_STATE_ETHER,
131 PFCTL_STATE_SCRUB,
132 PFCTL_STATE_QUEUE,
133 PFCTL_STATE_NAT,
134 PFCTL_STATE_FILTER
135 };
136
137 struct node_etherproto {
138 u_int16_t proto;
139 struct node_etherproto *next;
140 struct node_etherproto *tail;
141 };
142
143 struct node_proto {
144 u_int8_t proto;
145 struct node_proto *next;
146 struct node_proto *tail;
147 };
148
149 struct node_port {
150 u_int16_t port[2];
151 u_int8_t op;
152 struct node_port *next;
153 struct node_port *tail;
154 };
155
156 struct node_uid {
157 uid_t uid[2];
158 u_int8_t op;
159 struct node_uid *next;
160 struct node_uid *tail;
161 };
162
163 struct node_gid {
164 gid_t gid[2];
165 u_int8_t op;
166 struct node_gid *next;
167 struct node_gid *tail;
168 };
169
170 struct node_icmp {
171 uint16_t code;
172 uint16_t type;
173 u_int8_t proto;
174 struct node_icmp *next;
175 struct node_icmp *tail;
176 };
177
178 enum { PF_STATE_OPT_MAX, PF_STATE_OPT_NOSYNC, PF_STATE_OPT_SRCTRACK,
179 PF_STATE_OPT_MAX_SRC_STATES, PF_STATE_OPT_MAX_SRC_CONN,
180 PF_STATE_OPT_MAX_SRC_CONN_RATE, PF_STATE_OPT_MAX_SRC_NODES,
181 PF_STATE_OPT_OVERLOAD, PF_STATE_OPT_STATELOCK,
182 PF_STATE_OPT_TIMEOUT, PF_STATE_OPT_SLOPPY,
183 PF_STATE_OPT_PFLOW, PF_STATE_OPT_ALLOW_RELATED,
184 PF_STATE_OPT_STATELIM, PF_STATE_OPT_SOURCELIM };
185
186 enum { PF_SRCTRACK_NONE, PF_SRCTRACK, PF_SRCTRACK_GLOBAL, PF_SRCTRACK_RULE };
187
188 struct node_state_opt {
189 int type;
190 union {
191 u_int32_t max_states;
192 u_int32_t max_src_states;
193 u_int32_t max_src_conn;
194 struct {
195 u_int32_t limit;
196 u_int32_t seconds;
197 } max_src_conn_rate;
198 struct {
199 u_int8_t flush;
200 char tblname[PF_TABLE_NAME_SIZE];
201 } overload;
202 u_int32_t max_src_nodes;
203 u_int8_t src_track;
204 u_int32_t statelock;
205 struct {
206 int number;
207 u_int32_t seconds;
208 } timeout;
209 } data;
210 struct node_state_opt *next;
211 struct node_state_opt *tail;
212 };
213
214 struct peer {
215 struct node_host *host;
216 struct node_port *port;
217 };
218
219 static struct node_queue {
220 char queue[PF_QNAME_SIZE];
221 char parent[PF_QNAME_SIZE];
222 char ifname[IFNAMSIZ];
223 int scheduler;
224 struct node_queue *next;
225 struct node_queue *tail;
226 } *queues = NULL;
227
228 struct node_qassign {
229 char *qname;
230 char *pqname;
231 };
232
233 struct range {
234 int a;
235 int b;
236 int t;
237 };
238
239 static struct pool_opts {
240 int marker;
241 #define POM_TYPE 0x01
242 #define POM_STICKYADDRESS 0x02
243 #define POM_ENDPI 0x04
244 #define POM_IPV6NH 0x08
245 u_int8_t opts;
246 int type;
247 int staticport;
248 struct pf_poolhashkey *key;
249 struct pf_mape_portset mape;
250 } pool_opts;
251
252 struct redirspec {
253 struct node_host *host;
254 struct range rport;
255 struct pool_opts pool_opts;
256 sa_family_t af;
257 bool binat;
258 };
259
260 struct limiterspec {
261 uint32_t id;
262 int limiter_action;
263 };
264
265 static struct filter_opts {
266 int marker;
267 #define FOM_FLAGS 0x0001
268 #define FOM_ICMP 0x0002
269 #define FOM_TOS 0x0004
270 #define FOM_KEEP 0x0008
271 #define FOM_SRCTRACK 0x0010
272 #define FOM_MINTTL 0x0020
273 #define FOM_MAXMSS 0x0040
274 #define FOM_AFTO 0x0080
275 #define FOM_SETTOS 0x0100
276 #define FOM_SCRUB_TCP 0x0200
277 #define FOM_SETPRIO 0x0400
278 #define FOM_ONCE 0x1000
279 #define FOM_PRIO 0x2000
280 #define FOM_SETDELAY 0x4000
281 #define FOM_FRAGCACHE 0x8000 /* does not exist in OpenBSD */
282 struct node_uid *uid;
283 struct node_gid *gid;
284 struct node_if *rcv;
285 struct {
286 u_int8_t b1;
287 u_int8_t b2;
288 u_int16_t w;
289 u_int16_t w2;
290 } flags;
291 struct node_icmp *icmpspec;
292 u_int32_t tos;
293 u_int32_t prob;
294 u_int32_t ridentifier;
295 struct limiterspec statelim;
296 struct limiterspec sourcelim;
297 struct {
298 int action;
299 struct node_state_opt *options;
300 } keep;
301 int fragment;
302 int allowopts;
303 char *label[PF_RULE_MAX_LABEL_COUNT];
304 int labelcount;
305 struct node_qassign queues;
306 char *tag;
307 char *match_tag;
308 u_int8_t match_tag_not;
309 u_int16_t dnpipe;
310 u_int16_t dnrpipe;
311 u_int32_t free_flags;
312 u_int rtableid;
313 u_int8_t prio;
314 u_int8_t set_prio[2];
315 struct {
316 struct node_host *addr;
317 u_int16_t port;
318 } divert;
319 struct redirspec *nat;
320 struct redirspec *rdr;
321 /* new-style scrub opts */
322 int nodf;
323 int minttl;
324 int settos;
325 int randomid;
326 int max_mss;
327 struct {
328 uint32_t limit;
329 uint32_t seconds;
330 } pktrate;
331 int max_pkt_size;
332 } filter_opts;
333
334 static struct antispoof_opts {
335 char *label[PF_RULE_MAX_LABEL_COUNT];
336 int labelcount;
337 u_int32_t ridentifier;
338 u_int rtableid;
339 } antispoof_opts;
340
341 static struct scrub_opts {
342 int marker;
343 int nodf;
344 int minttl;
345 int maxmss;
346 int settos;
347 int fragcache;
348 int randomid;
349 int reassemble_tcp;
350 char *match_tag;
351 u_int8_t match_tag_not;
352 u_int rtableid;
353 } scrub_opts;
354
355 static struct queue_opts {
356 int marker;
357 #define QOM_BWSPEC 0x01
358 #define QOM_SCHEDULER 0x02
359 #define QOM_PRIORITY 0x04
360 #define QOM_TBRSIZE 0x08
361 #define QOM_QLIMIT 0x10
362 struct node_queue_bw queue_bwspec;
363 struct node_queue_opt scheduler;
364 int priority;
365 unsigned int tbrsize;
366 int qlimit;
367 } queue_opts;
368
369 static struct table_opts {
370 int flags;
371 int init_addr;
372 struct node_tinithead init_nodes;
373 } table_opts;
374
375 struct statelim_opts {
376 unsigned int marker;
377 #define STATELIM_M_ID 0x01
378 #define STATELIM_M_LIMIT 0x02
379 #define STATELIM_M_RATE 0x04
380
381 uint32_t id;
382 char name[PF_STATELIM_NAME_LEN];
383 unsigned int limit;
384 struct {
385 unsigned int limit;
386 unsigned int seconds;
387 } rate;
388 };
389
390 static struct statelim_opts statelim_opts;
391
392 struct sourcelim_opts {
393 unsigned int marker;
394 #define SOURCELIM_M_ID 0x01
395 #define SOURCELIM_M_ENTRIES 0x02
396 #define SOURCELIM_M_LIMIT 0x04
397 #define SOURCELIM_M_RATE 0x08
398 #define SOURCELIM_M_TABLE 0x10
399 #define SOURCELIM_M_INET_MASK 0x20
400 #define SOURCELIM_M_INET6_MASK 0x40
401
402 uint32_t id;
403 unsigned int entries;
404 unsigned int limit;
405 struct {
406 unsigned int limit;
407 unsigned int seconds;
408 } rate;
409 struct {
410 char name[PF_TABLE_NAME_SIZE];
411 unsigned int above;
412 unsigned int below;
413 } table;
414 unsigned int inet_mask;
415 unsigned int inet6_mask;
416 };
417
418 static struct sourcelim_opts sourcelim_opts;
419
420 static struct codel_opts codel_opts;
421 static struct node_hfsc_opts hfsc_opts;
422 static struct node_fairq_opts fairq_opts;
423 static struct node_state_opt *keep_state_defaults = NULL;
424 static struct pfctl_watermarks syncookie_opts;
425
426 int validate_range(uint8_t, uint16_t, uint16_t);
427 int disallow_table(struct node_host *, const char *);
428 int disallow_urpf_failed(struct node_host *, const char *);
429 int disallow_alias(struct node_host *, const char *);
430 int rule_consistent(struct pfctl_rule *);
431 int filter_consistent(struct pfctl_rule *);
432 int nat_consistent(struct pfctl_rule *);
433 int rdr_consistent(struct pfctl_rule *);
434 int process_tabledef(char *, struct table_opts *, int);
435 void expand_label_str(char *, size_t, const char *, const char *);
436 void expand_label_if(const char *, char *, size_t, const char *);
437 void expand_label_addr(const char *, char *, size_t, sa_family_t,
438 struct pf_rule_addr *);
439 void expand_label_port(const char *, char *, size_t,
440 struct pf_rule_addr *);
441 void expand_label_proto(const char *, char *, size_t, u_int8_t);
442 void expand_label_nr(const char *, char *, size_t,
443 struct pfctl_rule *);
444 void expand_eth_rule(struct pfctl_eth_rule *,
445 struct node_if *, struct node_etherproto *,
446 struct node_mac *, struct node_mac *,
447 struct node_host *, struct node_host *, const char *,
448 const char *);
449 int apply_rdr_ports(struct pfctl_rule *r, struct pfctl_pool *, struct redirspec *);
450 int apply_nat_ports(struct pfctl_pool *, struct redirspec *);
451 int apply_redirspec(struct pfctl_pool *, struct redirspec *);
452 int check_binat_redirspec(struct node_host *, struct pfctl_rule *, sa_family_t);
453 void add_binat_rdr_rule(struct pfctl_rule *, struct redirspec *,
454 struct node_host *, struct pfctl_rule *, struct redirspec **,
455 struct node_host **);
456 void expand_rule(struct pfctl_rule *, bool, struct node_if *,
457 struct redirspec *, struct redirspec *, struct redirspec *,
458 struct node_proto *, struct node_os *, struct node_host *,
459 struct node_port *, struct node_host *, struct node_port *,
460 struct node_uid *, struct node_gid *, struct node_if *,
461 struct node_icmp *);
462 int expand_altq(struct pf_altq *, struct node_if *,
463 struct node_queue *, struct node_queue_bw bwspec,
464 struct node_queue_opt *);
465 int expand_queue(struct pf_altq *, struct node_if *,
466 struct node_queue *, struct node_queue_bw,
467 struct node_queue_opt *);
468 int expand_skip_interface(struct node_if *);
469
470 int check_rulestate(int);
471 int getservice(char *);
472 int rule_label(struct pfctl_rule *, char *s[PF_RULE_MAX_LABEL_COUNT]);
473 int eth_rule_label(struct pfctl_eth_rule *, char *s[PF_RULE_MAX_LABEL_COUNT]);
474 int rt_tableid_max(void);
475
476 void mv_rules(struct pfctl_ruleset *, struct pfctl_ruleset *);
477 void mv_eth_rules(struct pfctl_eth_ruleset *, struct pfctl_eth_ruleset *);
478 void mv_tables(struct pfctl *, struct pfr_ktablehead *,
479 struct pfctl_anchor *, struct pfctl_anchor *);
480 void decide_address_family(struct node_host *, sa_family_t *);
481 void remove_invalid_hosts(struct node_host **, sa_family_t *);
482 int invalid_redirect(struct node_host *, sa_family_t);
483 u_int16_t parseicmpspec(char *, sa_family_t);
484 int kw_casecmp(const void *, const void *);
485 int map_tos(char *string, int *);
486 int filteropts_to_rule(struct pfctl_rule *, struct filter_opts *);
487 struct node_mac* node_mac_from_string(const char *);
488 struct node_mac* node_mac_from_string_masklen(const char *, int);
489 struct node_mac* node_mac_from_string_mask(const char *, const char *);
490 static bool pfctl_setup_anchor(struct pfctl_rule *, struct pfctl *, char *);
491
492 static TAILQ_HEAD(loadanchorshead, loadanchors)
493 loadanchorshead = TAILQ_HEAD_INITIALIZER(loadanchorshead);
494
495 struct loadanchors {
496 TAILQ_ENTRY(loadanchors) entries;
497 char *anchorname;
498 char *filename;
499 };
500
501 typedef struct {
502 union {
503 int64_t number;
504 double probability;
505 int i;
506 char *string;
507 u_int rtableid;
508 struct {
509 u_int8_t b1;
510 u_int8_t b2;
511 u_int16_t w;
512 u_int16_t w2;
513 } b;
514 struct range range;
515 struct node_if *interface;
516 struct node_proto *proto;
517 struct node_etherproto *etherproto;
518 struct node_icmp *icmp;
519 struct node_host *host;
520 struct node_os *os;
521 struct node_port *port;
522 struct node_uid *uid;
523 struct node_gid *gid;
524 struct node_state_opt *state_opt;
525 struct peer peer;
526 struct {
527 struct peer src, dst;
528 struct node_os *src_os;
529 } fromto;
530 struct {
531 struct node_mac *src;
532 struct node_mac *dst;
533 } etherfromto;
534 struct node_mac *mac;
535 struct {
536 struct node_mac *mac;
537 } etheraddr;
538 char *bridge_to;
539 struct {
540 struct redirspec *redirspec;
541 u_int8_t rt;
542 } route;
543 struct redirspec *redirspec;
544 struct {
545 int action;
546 struct node_state_opt *options;
547 } keep_state;
548 struct {
549 u_int8_t log;
550 u_int8_t logif;
551 u_int8_t quick;
552 } logquick;
553 struct {
554 int neg;
555 char *name;
556 } tagged;
557 struct pf_poolhashkey *hashkey;
558 struct node_queue *queue;
559 struct node_queue_opt queue_options;
560 struct node_queue_bw queue_bwspec;
561 struct node_qassign qassign;
562 struct filter_opts filter_opts;
563 struct antispoof_opts antispoof_opts;
564 struct queue_opts queue_opts;
565 struct scrub_opts scrub_opts;
566 struct table_opts table_opts;
567 struct pool_opts pool_opts;
568 struct node_hfsc_opts hfsc_opts;
569 struct node_fairq_opts fairq_opts;
570 struct codel_opts codel_opts;
571 struct statelim_opts *statelim_opts;
572 struct sourcelim_opts *sourcelim_opts;
573 struct pfctl_watermarks *watermarks;
574 struct limiterspec limiterspec;
575 } v;
576 int lineno;
577 } YYSTYPE;
578
579 #define PPORT_RANGE 1
580 #define PPORT_STAR 2
581 int parseport(char *, struct range *r, int);
582
583 #define DYNIF_MULTIADDR(addr) ((addr).type == PF_ADDR_DYNIFTL && \
584 (!((addr).iflags & PFI_AFLAG_NOALIAS) || \
585 !isdigit((addr).v.ifname[strlen((addr).v.ifname)-1])))
586
587 %}
588
589 %token PASS BLOCK MATCH SCRUB RETURN IN OS OUT LOG QUICK ON FROM TO FLAGS
590 %token RETURNRST RETURNICMP RETURNICMP6 PROTO INET INET6 ALL ANY ICMPTYPE
591 %token ICMP6TYPE CODE KEEP MODULATE STATE PORT RDR NAT BINAT ARROW NODF
592 %token MINTTL ERROR ALLOWOPTS FASTROUTE FILENAME ROUTETO DUPTO REPLYTO NO LABEL
593 %token NOROUTE URPFFAILED FRAGMENT USER GROUP MAXMSS MAXIMUM TTL TOS DROP TABLE
594 %token REASSEMBLE ANCHOR NATANCHOR RDRANCHOR BINATANCHOR
595 %token SET OPTIMIZATION TIMEOUT LIMIT LOGINTERFACE BLOCKPOLICY FAILPOLICY
596 %token RANDOMID REQUIREORDER SYNPROXY FINGERPRINTS NOSYNC DEBUG SKIP HOSTID
597 %token ANTISPOOF FOR INCLUDE KEEPCOUNTERS SYNCOOKIES L3 MATCHES
598 %token ETHER
599 %token BITMASK RANDOM SOURCEHASH ROUNDROBIN STATICPORT PROBABILITY MAPEPORTSET
600 %token ALTQ CBQ CODEL PRIQ HFSC FAIRQ BANDWIDTH TBRSIZE LINKSHARE REALTIME
601 %token UPPERLIMIT QUEUE PRIORITY QLIMIT HOGS BUCKETS RTABLE TARGET INTERVAL
602 %token DNPIPE DNQUEUE RIDENTIFIER
603 %token LOAD RULESET_OPTIMIZATION PRIO ONCE
604 %token STICKYADDRESS ENDPI MAXSRCSTATES MAXSRCNODES SOURCETRACK GLOBAL RULE
605 %token MAXSRCCONN MAXSRCCONNRATE OVERLOAD FLUSH SLOPPY PFLOW ALLOW_RELATED
606 %token TAGGED TAG IFBOUND FLOATING STATEPOLICY STATEDEFAULTS ROUTE SETTOS
607 %token DIVERTTO DIVERTREPLY BRIDGE_TO RECEIVEDON NE LE GE AFTO NATTO RDRTO
608 %token BINATTO MAXPKTRATE MAXPKTSIZE IPV6NH
609 %token LIMITER ID RATE SOURCE ENTRIES ABOVE BELOW MASK NOMATCH
610 %token <v.string> STRING
611 %token <v.number> NUMBER
612 %token <v.i> PORTBINARY
613 %type <v.interface> interface if_list if_item_not if_item
614 %type <v.number> number icmptype icmp6type uid gid
615 %type <v.number> tos not yesno optnodf sourcelim_opt_below
616 %type <v.probability> probability
617 %type <v.i> no dir af fragcache optimizer syncookie_val
618 %type <v.i> sourcetrack flush unaryop statelock
619 %type <v.i> etherprotoval
620 %type <v.b> action nataction natpasslog scrubaction
621 %type <v.b> flags flag blockspec prio
622 %type <v.range> portplain portstar portrange
623 %type <v.hashkey> hashkey
624 %type <v.proto> proto proto_list proto_item
625 %type <v.number> protoval
626 %type <v.icmp> icmpspec
627 %type <v.icmp> icmp_list icmp_item
628 %type <v.icmp> icmp6_list icmp6_item
629 %type <v.number> reticmpspec reticmp6spec
630 %type <v.fromto> fromto l3fromto
631 %type <v.peer> ipportspec from to
632 %type <v.host> ipspec toipspec xhost host dynaddr host_list
633 %type <v.host> redir_host redir_host_list routespec
634 %type <v.host> route_host route_host_list
635 %type <v.os> os xos os_list
636 %type <v.port> portspec port_list port_item
637 %type <v.uid> uids uid_list uid_item
638 %type <v.gid> gids gid_list gid_item
639 %type <v.route> route
640 %type <v.redirspec> no_port_redirspec port_redirspec route_redirspec
641 %type <v.redirspec> binat_redirspec nat_redirspec
642 %type <v.string> label stringall tag anchorname
643 %type <v.string> string varstring numberstring
644 %type <v.keep_state> keep
645 %type <v.state_opt> state_opt_spec state_opt_list state_opt_item
646 %type <v.logquick> logquick quick log logopts logopt
647 %type <v.interface> antispoof_ifspc antispoof_iflst antispoof_if
648 %type <v.qassign> qname etherqname
649 %type <v.queue> qassign qassign_list qassign_item
650 %type <v.queue_options> scheduler
651 %type <v.number> cbqflags_list cbqflags_item
652 %type <v.number> priqflags_list priqflags_item
653 %type <v.hfsc_opts> hfscopts_list hfscopts_item hfsc_opts
654 %type <v.fairq_opts> fairqopts_list fairqopts_item fairq_opts
655 %type <v.codel_opts> codelopts_list codelopts_item codel_opts
656 %type <v.queue_bwspec> bandwidth
657 %type <v.filter_opts> filter_opts filter_opt filter_opts_l etherfilter_opts etherfilter_opt etherfilter_opts_l
658 %type <v.filter_opts> filter_sets filter_set filter_sets_l
659 %type <v.antispoof_opts> antispoof_opts antispoof_opt antispoof_opts_l
660 %type <v.queue_opts> queue_opts queue_opt queue_opts_l
661 %type <v.scrub_opts> scrub_opts scrub_opt scrub_opts_l
662 %type <v.table_opts> table_opts table_opt table_opts_l
663 %type <v.pool_opts> pool_opts pool_opt pool_opts_l
664 %type <v.tagged> tagged
665 %type <v.rtableid> rtable
666 %type <v.watermarks> syncookie_opts
667 %type <v.etherproto> etherproto etherproto_list etherproto_item
668 %type <v.etherfromto> etherfromto
669 %type <v.etheraddr> etherfrom etherto
670 %type <v.bridge_to> bridge
671 %type <v.mac> xmac mac mac_list macspec
672 %type <v.string> statelim_nm sourcelim_nm
673 %type <v.number> statelim_id sourcelim_id limiter_opt limiter_opt_spec
674 %type <v.limiterspec> statelim_filter_opt sourcelim_filter_opt
675 %type <v.statelim_opts> statelim_opts
676 %type <v.sourcelim_opts> sourcelim_opts
677 %%
678
679 ruleset : /* empty */
680 | ruleset include '\n'
681 | ruleset '\n'
682 | ruleset option '\n'
683 | ruleset statelim '\n'
684 | ruleset sourcelim '\n'
685 | ruleset etherrule '\n'
686 | ruleset etheranchorrule '\n'
687 | ruleset scrubrule '\n'
688 | ruleset natrule '\n'
689 | ruleset binatrule '\n'
690 | ruleset pfrule '\n'
691 | ruleset anchorrule '\n'
692 | ruleset loadrule '\n'
693 | ruleset altqif '\n'
694 | ruleset queuespec '\n'
695 | ruleset varset '\n'
696 | ruleset antispoof '\n'
697 | ruleset tabledef '\n'
698 | '{' fakeanchor '}' '\n';
699 | ruleset error '\n' { file->errors++; }
700 ;
701
702 include : INCLUDE STRING {
703 struct file *nfile;
704
705 if ((nfile = pushfile($2, 0)) == NULL) {
706 yyerror("failed to include file %s", $2);
707 free($2);
708 YYERROR;
709 }
710 free($2);
711
712 file = nfile;
713 lungetc('\n');
714 }
715 ;
716
717 /*
718 * apply to previouslys specified rule: must be careful to note
719 * what that is: pf or nat or binat or rdr
720 */
721 fakeanchor : fakeanchor '\n'
722 | fakeanchor anchorrule '\n'
723 | fakeanchor binatrule '\n'
724 | fakeanchor natrule '\n'
725 | fakeanchor pfrule '\n'
726 | fakeanchor error '\n'
727 ;
728
729 optimizer : string {
730 if (!strcmp($1, "none"))
731 $$ = 0;
732 else if (!strcmp($1, "basic"))
733 $$ = PF_OPTIMIZE_BASIC;
734 else if (!strcmp($1, "profile"))
735 $$ = PF_OPTIMIZE_BASIC | PF_OPTIMIZE_PROFILE;
736 else {
737 yyerror("unknown ruleset-optimization %s", $1);
738 YYERROR;
739 }
740 }
741 ;
742
743 optnodf : /* empty */ { $$ = 0; }
744 | NODF { $$ = 1; }
745 ;
746
747 option : SET REASSEMBLE yesno optnodf {
748 if (check_rulestate(PFCTL_STATE_OPTION))
749 YYERROR;
750 pfctl_set_reassembly(pf, $3, $4);
751 }
752 | SET OPTIMIZATION STRING {
753 if (check_rulestate(PFCTL_STATE_OPTION)) {
754 free($3);
755 YYERROR;
756 }
757 if (pfctl_set_optimization(pf, $3) != 0) {
758 yyerror("unknown optimization %s", $3);
759 free($3);
760 YYERROR;
761 }
762 free($3);
763 }
764 | SET RULESET_OPTIMIZATION optimizer {
765 if (!(pf->opts & PF_OPT_OPTIMIZE)) {
766 pf->opts |= PF_OPT_OPTIMIZE;
767 pf->optimize = $3;
768 }
769 }
770 | SET TIMEOUT timeout_spec
771 | SET TIMEOUT '{' optnl timeout_list '}'
772 | SET LIMIT limit_spec
773 | SET LIMIT '{' optnl limit_list '}'
774 | SET LOGINTERFACE stringall {
775 if (check_rulestate(PFCTL_STATE_OPTION)) {
776 free($3);
777 YYERROR;
778 }
779 if (pfctl_set_logif(pf, $3) != 0) {
780 yyerror("error setting loginterface %s", $3);
781 free($3);
782 YYERROR;
783 }
784 free($3);
785 }
786 | SET HOSTID number {
787 if ($3 == 0 || $3 > UINT_MAX) {
788 yyerror("hostid must be non-zero");
789 YYERROR;
790 }
791 pfctl_set_hostid(pf, $3);
792 }
793 | SET BLOCKPOLICY DROP {
794 if (pf->opts & PF_OPT_VERBOSE)
795 printf("set block-policy drop\n");
796 if (check_rulestate(PFCTL_STATE_OPTION))
797 YYERROR;
798 blockpolicy = PFRULE_DROP;
799 }
800 | SET BLOCKPOLICY RETURN {
801 if (pf->opts & PF_OPT_VERBOSE)
802 printf("set block-policy return\n");
803 if (check_rulestate(PFCTL_STATE_OPTION))
804 YYERROR;
805 blockpolicy = PFRULE_RETURN;
806 }
807 | SET FAILPOLICY DROP {
808 if (pf->opts & PF_OPT_VERBOSE)
809 printf("set fail-policy drop\n");
810 if (check_rulestate(PFCTL_STATE_OPTION))
811 YYERROR;
812 failpolicy = PFRULE_DROP;
813 }
814 | SET FAILPOLICY RETURN {
815 if (pf->opts & PF_OPT_VERBOSE)
816 printf("set fail-policy return\n");
817 if (check_rulestate(PFCTL_STATE_OPTION))
818 YYERROR;
819 failpolicy = PFRULE_RETURN;
820 }
821 | SET REQUIREORDER yesno {
822 if (pf->opts & PF_OPT_VERBOSE)
823 printf("set require-order %s\n",
824 $3 == 1 ? "yes" : "no");
825 require_order = $3;
826 }
827 | SET FINGERPRINTS STRING {
828 if (pf->opts & PF_OPT_VERBOSE)
829 printf("set fingerprints \"%s\"\n", $3);
830 if (check_rulestate(PFCTL_STATE_OPTION)) {
831 free($3);
832 YYERROR;
833 }
834 if (!pf->anchor->name[0]) {
835 if (pfctl_file_fingerprints(pf->dev,
836 pf->opts, $3)) {
837 yyerror("error loading "
838 "fingerprints %s", $3);
839 free($3);
840 YYERROR;
841 }
842 }
843 free($3);
844 }
845 | SET STATEPOLICY statelock {
846 if (pf->opts & PF_OPT_VERBOSE)
847 switch ($3) {
848 case 0:
849 printf("set state-policy floating\n");
850 break;
851 case PFRULE_IFBOUND:
852 printf("set state-policy if-bound\n");
853 break;
854 }
855 default_statelock = $3;
856 }
857 | SET DEBUG STRING {
858 if (check_rulestate(PFCTL_STATE_OPTION)) {
859 free($3);
860 YYERROR;
861 }
862 if (pfctl_do_set_debug(pf, $3) != 0) {
863 yyerror("error setting debuglevel %s", $3);
864 free($3);
865 YYERROR;
866 }
867 free($3);
868 }
869 | SET SKIP interface {
870 if (expand_skip_interface($3) != 0) {
871 yyerror("error setting skip interface(s)");
872 YYERROR;
873 }
874 }
875 | SET STATEDEFAULTS state_opt_list {
876 if (keep_state_defaults != NULL) {
877 yyerror("cannot redefine state-defaults");
878 YYERROR;
879 }
880 keep_state_defaults = $3;
881 }
882 | SET KEEPCOUNTERS {
883 pf->keep_counters = true;
884 }
885 | SET SYNCOOKIES syncookie_val syncookie_opts {
886 if (pfctl_cfg_syncookies(pf, $3, $4)) {
887 yyerror("error setting syncookies");
888 YYERROR;
889 }
890 }
891 ;
892
893 syncookie_val : STRING {
894 if (!strcmp($1, "never"))
895 $$ = PFCTL_SYNCOOKIES_NEVER;
896 else if (!strcmp($1, "adaptive"))
897 $$ = PFCTL_SYNCOOKIES_ADAPTIVE;
898 else if (!strcmp($1, "always"))
899 $$ = PFCTL_SYNCOOKIES_ALWAYS;
900 else {
901 yyerror("illegal value for syncookies");
902 YYERROR;
903 }
904 }
905 ;
906 syncookie_opts : /* empty */ { $$ = NULL; }
907 | {
908 memset(&syncookie_opts, 0, sizeof(syncookie_opts));
909 } '(' syncookie_opt_l ')' { $$ = &syncookie_opts; }
910 ;
911
912 syncookie_opt_l : syncookie_opt_l comma syncookie_opt
913 | syncookie_opt
914 ;
915
916 syncookie_opt : STRING STRING {
917 double val;
918 char *cp;
919
920 val = strtod($2, &cp);
921 if (cp == NULL || strcmp(cp, "%"))
922 YYERROR;
923 if (val <= 0 || val > 100) {
924 yyerror("illegal percentage value");
925 YYERROR;
926 }
927 if (!strcmp($1, "start")) {
928 syncookie_opts.hi = val;
929 } else if (!strcmp($1, "end")) {
930 syncookie_opts.lo = val;
931 } else {
932 yyerror("illegal syncookie option");
933 YYERROR;
934 }
935 }
936 ;
937
938 stringall : STRING { $$ = $1; }
939 | ALL {
940 if (($$ = strdup("all")) == NULL) {
941 err(1, "stringall: strdup");
942 }
943 }
944 ;
945
946 string : STRING string {
947 if (asprintf(&$$, "%s %s", $1, $2) == -1)
948 err(1, "string: asprintf");
949 free($1);
950 free($2);
951 }
952 | STRING
953 ;
954
955 varstring : numberstring varstring {
956 if (asprintf(&$$, "%s %s", $1, $2) == -1)
957 err(1, "string: asprintf");
958 free($1);
959 free($2);
960 }
961 | numberstring
962 ;
963
964 numberstring : NUMBER {
965 char *s;
966 if (asprintf(&s, "%lld", (long long)$1) == -1) {
967 yyerror("string: asprintf");
968 YYERROR;
969 }
970 $$ = s;
971 }
972 | STRING
973 ;
974
975 varset : STRING '=' varstring {
976 char *s = $1;
977 if (pf->opts & PF_OPT_VERBOSE)
978 printf("%s = \"%s\"\n", $1, $3);
979 while (*s++) {
980 if (isspace((unsigned char)*s)) {
981 yyerror("macro name cannot contain "
982 "whitespace");
983 free($1);
984 free($3);
985 YYERROR;
986 }
987 }
988 if (symset($1, $3, 0) == -1)
989 err(1, "cannot store variable %s", $1);
990 free($1);
991 free($3);
992 }
993 ;
994
995 anchorname : STRING {
996 if ($1[0] == '\0') {
997 free($1);
998 yyerror("anchor name must not be empty");
999 YYERROR;
1000 }
1001 if (strlen(pf->anchor->path) + 1 +
1002 strlen($1) >= PATH_MAX) {
1003 free($1);
1004 yyerror("anchor name is longer than %u",
1005 PATH_MAX - 1);
1006 YYERROR;
1007 }
1008 if ($1[0] == '_' || strstr($1, "/_") != NULL) {
1009 free($1);
1010 yyerror("anchor names beginning with '_' "
1011 "are reserved for internal use");
1012 YYERROR;
1013 }
1014 $$ = $1;
1015 }
1016 | /* empty */ { $$ = NULL; }
1017 ;
1018
1019 pfa_anchorlist : /* empty */
1020 | pfa_anchorlist '\n'
1021 | pfa_anchorlist tabledef '\n'
1022 | pfa_anchorlist pfrule '\n'
1023 | pfa_anchorlist anchorrule '\n'
1024 | pfa_anchorlist include '\n'
1025 ;
1026
1027 pfa_anchor : '{'
1028 {
1029 char ta[PF_ANCHOR_NAME_SIZE];
1030 struct pfctl_ruleset *rs;
1031
1032 /* stepping into a brace anchor */
1033 if (pf->asd >= PFCTL_ANCHOR_STACK_DEPTH)
1034 errx(1, "pfa_anchor: anchors too deep");
1035 pf->asd++;
1036 pf->bn++;
1037
1038 /*
1039 * Anchor contents are parsed before the anchor rule
1040 * production completes, so we don't know the real
1041 * location yet. Create a holding ruleset in the root;
1042 * contents will be moved afterwards.
1043 */
1044 snprintf(ta, PF_ANCHOR_NAME_SIZE, "_%d", pf->bn);
1045 rs = pf_find_or_create_ruleset(ta);
1046 if (rs == NULL)
1047 err(1, "pfa_anchor: pf_find_or_create_ruleset (%s)", ta);
1048 pf->astack[pf->asd] = rs->anchor;
1049 pf->anchor = rs->anchor;
1050 } '\n' pfa_anchorlist '}'
1051 {
1052 pf->alast = pf->anchor;
1053 pf->asd--;
1054 pf->anchor = pf->astack[pf->asd];
1055 }
1056 | /* empty */
1057 ;
1058
1059 anchorrule : ANCHOR anchorname dir quick interface af proto fromto
1060 filter_opts pfa_anchor
1061 {
1062 struct pfctl_rule r;
1063 struct node_proto *proto;
1064
1065 if (check_rulestate(PFCTL_STATE_FILTER)) {
1066 if ($2)
1067 free($2);
1068 YYERROR;
1069 }
1070
1071 pfctl_init_rule(&r);
1072 if (! pfctl_setup_anchor(&r, pf, $2))
1073 YYERROR;
1074
1075 r.direction = $3;
1076 r.quick = $4.quick;
1077 r.af = $6;
1078
1079 if ($9.flags.b1 || $9.flags.b2 || $8.src_os) {
1080 for (proto = $7; proto != NULL &&
1081 proto->proto != IPPROTO_TCP;
1082 proto = proto->next)
1083 ; /* nothing */
1084 if (proto == NULL && $7 != NULL) {
1085 if ($9.flags.b1 || $9.flags.b2)
1086 yyerror(
1087 "flags only apply to tcp");
1088 if ($8.src_os)
1089 yyerror(
1090 "OS fingerprinting only "
1091 "applies to tcp");
1092 YYERROR;
1093 }
1094 }
1095
1096 if (filteropts_to_rule(&r, &$9))
1097 YYERROR;
1098
1099 if ($9.keep.action) {
1100 yyerror("cannot specify state handling "
1101 "on anchors");
1102 YYERROR;
1103 }
1104
1105 decide_address_family($8.src.host, &r.af);
1106 decide_address_family($8.dst.host, &r.af);
1107
1108 expand_rule(&r, false, $5, NULL, NULL, NULL,
1109 $7, $8.src_os, $8.src.host, $8.src.port, $8.dst.host,
1110 $8.dst.port, $9.uid, $9.gid, $9.rcv, $9.icmpspec);
1111 free($2);
1112 pf->astack[pf->asd + 1] = NULL;
1113 }
1114 | NATANCHOR string interface af proto fromto rtable {
1115 struct pfctl_rule r;
1116
1117 if (check_rulestate(PFCTL_STATE_NAT)) {
1118 free($2);
1119 YYERROR;
1120 }
1121
1122 pfctl_init_rule(&r);
1123 if (! pfctl_setup_anchor(&r, pf, $2))
1124 YYERROR;
1125
1126 r.action = PF_NAT;
1127 r.af = $4;
1128 r.rtableid = $7;
1129
1130 decide_address_family($6.src.host, &r.af);
1131 decide_address_family($6.dst.host, &r.af);
1132
1133 expand_rule(&r, false, $3, NULL, NULL, NULL,
1134 $5, $6.src_os, $6.src.host, $6.src.port, $6.dst.host,
1135 $6.dst.port, 0, 0, 0, 0);
1136 free($2);
1137 }
1138 | RDRANCHOR string interface af proto fromto rtable {
1139 struct pfctl_rule r;
1140
1141 if (check_rulestate(PFCTL_STATE_NAT)) {
1142 free($2);
1143 YYERROR;
1144 }
1145
1146 pfctl_init_rule(&r);
1147 if (! pfctl_setup_anchor(&r, pf, $2))
1148 YYERROR;
1149
1150 r.action = PF_RDR;
1151 r.af = $4;
1152 r.rtableid = $7;
1153
1154 decide_address_family($6.src.host, &r.af);
1155 decide_address_family($6.dst.host, &r.af);
1156
1157 if ($6.src.port != NULL) {
1158 yyerror("source port parameter not supported"
1159 " in rdr-anchor");
1160 YYERROR;
1161 }
1162 if ($6.dst.port != NULL) {
1163 if ($6.dst.port->next != NULL) {
1164 yyerror("destination port list "
1165 "expansion not supported in "
1166 "rdr-anchor");
1167 YYERROR;
1168 } else if ($6.dst.port->op != PF_OP_EQ) {
1169 yyerror("destination port operators"
1170 " not supported in rdr-anchor");
1171 YYERROR;
1172 }
1173 r.dst.port[0] = $6.dst.port->port[0];
1174 r.dst.port[1] = $6.dst.port->port[1];
1175 r.dst.port_op = $6.dst.port->op;
1176 }
1177
1178 expand_rule(&r, false, $3, NULL, NULL, NULL,
1179 $5, $6.src_os, $6.src.host, $6.src.port, $6.dst.host,
1180 $6.dst.port, 0, 0, 0, 0);
1181 free($2);
1182 }
1183 | BINATANCHOR string interface af proto fromto rtable {
1184 struct pfctl_rule r;
1185
1186 if (check_rulestate(PFCTL_STATE_NAT)) {
1187 free($2);
1188 YYERROR;
1189 }
1190
1191 pfctl_init_rule(&r);
1192 if (! pfctl_setup_anchor(&r, pf, $2))
1193 YYERROR;
1194
1195 r.action = PF_BINAT;
1196 r.af = $4;
1197 r.rtableid = $7;
1198 if ($5 != NULL) {
1199 if ($5->next != NULL) {
1200 yyerror("proto list expansion"
1201 " not supported in binat-anchor");
1202 YYERROR;
1203 }
1204 r.proto = $5->proto;
1205 free($5);
1206 }
1207
1208 if ($6.src.host != NULL || $6.src.port != NULL ||
1209 $6.dst.host != NULL || $6.dst.port != NULL) {
1210 yyerror("fromto parameter not supported"
1211 " in binat-anchor");
1212 YYERROR;
1213 }
1214
1215 decide_address_family($6.src.host, &r.af);
1216 decide_address_family($6.dst.host, &r.af);
1217
1218 pfctl_append_rule(pf, &r);
1219 free($2);
1220 }
1221 ;
1222
1223 loadrule : LOAD ANCHOR anchorname FROM string {
1224 struct loadanchors *loadanchor;
1225
1226 if ($3 == NULL) {
1227 yyerror("anchor name is missing");
1228 YYERROR;
1229 }
1230 loadanchor = calloc(1, sizeof(struct loadanchors));
1231 if (loadanchor == NULL)
1232 err(1, "loadrule: calloc");
1233 if ((loadanchor->anchorname = malloc(MAXPATHLEN)) ==
1234 NULL)
1235 err(1, "loadrule: malloc");
1236 if (pf->anchor->name[0])
1237 snprintf(loadanchor->anchorname, MAXPATHLEN,
1238 "%s/%s", pf->anchor->path, $3);
1239 else
1240 strlcpy(loadanchor->anchorname, $3, MAXPATHLEN);
1241 if ((loadanchor->filename = strdup($5)) == NULL)
1242 err(1, "loadrule: strdup");
1243
1244 TAILQ_INSERT_TAIL(&loadanchorshead, loadanchor,
1245 entries);
1246
1247 free($3);
1248 free($5);
1249 };
1250
1251 scrubaction : no SCRUB {
1252 $$.b2 = $$.w = 0;
1253 if ($1)
1254 $$.b1 = PF_NOSCRUB;
1255 else
1256 $$.b1 = PF_SCRUB;
1257 }
1258 ;
1259
1260 etherrule : ETHER action dir quick interface bridge etherproto etherfromto l3fromto etherfilter_opts
1261 {
1262 struct pfctl_eth_rule r;
1263
1264 bzero(&r, sizeof(r));
1265
1266 if (check_rulestate(PFCTL_STATE_ETHER))
1267 YYERROR;
1268
1269 r.action = $2.b1;
1270 r.direction = $3;
1271 r.quick = $4.quick;
1272 if ($10.tag != NULL)
1273 strlcpy(r.tagname, $10.tag, sizeof(r.tagname));
1274 if ($10.match_tag)
1275 if (strlcpy(r.match_tagname, $10.match_tag,
1276 PF_TAG_NAME_SIZE) >= PF_TAG_NAME_SIZE) {
1277 yyerror("tag too long, max %u chars",
1278 PF_TAG_NAME_SIZE - 1);
1279 YYERROR;
1280 }
1281 r.match_tag_not = $10.match_tag_not;
1282 if ($10.queues.qname != NULL)
1283 strlcpy(r.qname, $10.queues.qname, sizeof(r.qname));
1284 r.dnpipe = $10.dnpipe;
1285 r.dnflags = $10.free_flags;
1286 if (eth_rule_label(&r, $10.label))
1287 YYERROR;
1288 for (int i = 0; i < PF_RULE_MAX_LABEL_COUNT; i++)
1289 free($10.label[i]);
1290 r.ridentifier = $10.ridentifier;
1291
1292 expand_eth_rule(&r, $5, $7, $8.src, $8.dst,
1293 $9.src.host, $9.dst.host, $6, "");
1294 }
1295 ;
1296
1297 etherpfa_anchorlist : /* empty */
1298 | etherpfa_anchorlist '\n'
1299 | etherpfa_anchorlist etherrule '\n'
1300 | etherpfa_anchorlist etheranchorrule '\n'
1301 ;
1302
1303 etherpfa_anchor : '{'
1304 {
1305 char ta[PF_ANCHOR_NAME_SIZE];
1306 struct pfctl_eth_ruleset *rs;
1307
1308 /* steping into a brace anchor */
1309 if (pf->asd >= PFCTL_ANCHOR_STACK_DEPTH)
1310 errx(1, "pfa_anchor: anchors too deep");
1311 pf->asd++;
1312 pf->bn++;
1313
1314 /* create a holding ruleset in the root */
1315 snprintf(ta, PF_ANCHOR_NAME_SIZE, "_%d", pf->bn);
1316 rs = pf_find_or_create_eth_ruleset(ta);
1317 if (rs == NULL)
1318 err(1, "etherpfa_anchor: pf_find_or_create_eth_ruleset");
1319 pf->eastack[pf->asd] = rs->anchor;
1320 pf->eanchor = rs->anchor;
1321 } '\n' etherpfa_anchorlist '}'
1322 {
1323 pf->ealast = pf->eanchor;
1324 pf->asd--;
1325 pf->eanchor = pf->eastack[pf->asd];
1326 }
1327 | /* empty */
1328 ;
1329
1330 etheranchorrule : ETHER ANCHOR anchorname dir quick interface etherproto etherfromto l3fromto etherpfa_anchor
1331 {
1332 struct pfctl_eth_rule r;
1333
1334 if (check_rulestate(PFCTL_STATE_ETHER)) {
1335 free($3);
1336 YYERROR;
1337 }
1338
1339 if ($3 && ($3[0] == '_' || strstr($3, "/_") != NULL)) {
1340 free($3);
1341 yyerror("anchor names beginning with '_' "
1342 "are reserved for internal use");
1343 YYERROR;
1344 }
1345
1346 memset(&r, 0, sizeof(r));
1347 if (pf->eastack[pf->asd + 1]) {
1348 if ($3 && strchr($3, '/') != NULL) {
1349 free($3);
1350 yyerror("anchor paths containing '/' "
1351 "cannot be used for inline anchors.");
1352 YYERROR;
1353 }
1354
1355 /* Move inline rules into relative location. */
1356 pfctl_eth_anchor_setup(pf, &r,
1357 &pf->eastack[pf->asd]->ruleset,
1358 $3 ? $3 : pf->ealast->name);
1359 if (r.anchor == NULL)
1360 err(1, "etheranchorrule: unable to "
1361 "create ruleset");
1362
1363 if (pf->ealast != r.anchor) {
1364 if (r.anchor->match) {
1365 yyerror("inline anchor '%s' "
1366 "already exists",
1367 r.anchor->name);
1368 YYERROR;
1369 }
1370 mv_eth_rules(&pf->ealast->ruleset,
1371 &r.anchor->ruleset);
1372 }
1373 pf_remove_if_empty_eth_ruleset(&pf->ealast->ruleset);
1374 pf->ealast = r.anchor;
1375 } else {
1376 if (!$3) {
1377 yyerror("anchors without explicit "
1378 "rules must specify a name");
1379 YYERROR;
1380 }
1381 }
1382
1383 r.direction = $4;
1384 r.quick = $5.quick;
1385
1386 expand_eth_rule(&r, $6, $7, $8.src, $8.dst,
1387 $9.src.host, $9.dst.host, NULL,
1388 pf->eastack[pf->asd + 1] ? pf->ealast->name : $3);
1389
1390 free($3);
1391 pf->eastack[pf->asd + 1] = NULL;
1392 }
1393 ;
1394
1395 etherfilter_opts : {
1396 bzero(&filter_opts, sizeof filter_opts);
1397 }
1398 etherfilter_opts_l
1399 { $$ = filter_opts; }
1400 | /* empty */ {
1401 bzero(&filter_opts, sizeof filter_opts);
1402 $$ = filter_opts;
1403 }
1404 ;
1405
1406 etherfilter_opts_l : etherfilter_opts_l etherfilter_opt
1407 | etherfilter_opt
1408
1409 etherfilter_opt : etherqname {
1410 if (filter_opts.queues.qname) {
1411 yyerror("queue cannot be redefined");
1412 YYERROR;
1413 }
1414 filter_opts.queues = $1;
1415 }
1416 | RIDENTIFIER number {
1417 filter_opts.ridentifier = $2;
1418 }
1419 | label {
1420 if (filter_opts.labelcount >= PF_RULE_MAX_LABEL_COUNT) {
1421 yyerror("label can only be used %d times", PF_RULE_MAX_LABEL_COUNT);
1422 YYERROR;
1423 }
1424 filter_opts.label[filter_opts.labelcount++] = $1;
1425 }
1426 | TAG string {
1427 filter_opts.tag = $2;
1428 }
1429 | not TAGGED string {
1430 filter_opts.match_tag = $3;
1431 filter_opts.match_tag_not = $1;
1432 }
1433 | DNPIPE number {
1434 filter_opts.dnpipe = $2;
1435 filter_opts.free_flags |= PFRULE_DN_IS_PIPE;
1436 }
1437 | DNQUEUE number {
1438 filter_opts.dnpipe = $2;
1439 filter_opts.free_flags |= PFRULE_DN_IS_QUEUE;
1440 }
1441 ;
1442
1443 bridge : /* empty */ {
1444 $$ = NULL;
1445 }
1446 | BRIDGE_TO STRING {
1447 $$ = strdup($2);
1448 }
1449 ;
1450
1451 scrubrule : scrubaction dir logquick interface af proto fromto scrub_opts
1452 {
1453 struct pfctl_rule r;
1454
1455 if (check_rulestate(PFCTL_STATE_SCRUB))
1456 YYERROR;
1457
1458 pfctl_init_rule(&r);
1459
1460 r.action = $1.b1;
1461 r.direction = $2;
1462
1463 r.log = $3.log;
1464 r.logif = $3.logif;
1465 if ($3.quick) {
1466 yyerror("scrub rules do not support 'quick'");
1467 YYERROR;
1468 }
1469
1470 r.af = $5;
1471 if ($8.nodf)
1472 r.rule_flag |= PFRULE_NODF;
1473 if ($8.randomid)
1474 r.rule_flag |= PFRULE_RANDOMID;
1475 if ($8.reassemble_tcp) {
1476 if (r.direction != PF_INOUT) {
1477 yyerror("reassemble tcp rules can not "
1478 "specify direction");
1479 YYERROR;
1480 }
1481 r.rule_flag |= PFRULE_REASSEMBLE_TCP;
1482 }
1483 if ($8.minttl)
1484 r.min_ttl = $8.minttl;
1485 if ($8.maxmss)
1486 r.max_mss = $8.maxmss;
1487 if ($8.marker & FOM_SETTOS) {
1488 r.rule_flag |= PFRULE_SET_TOS;
1489 r.set_tos = $8.settos;
1490 }
1491 if ($8.fragcache)
1492 r.rule_flag |= $8.fragcache;
1493 if ($8.match_tag)
1494 if (strlcpy(r.match_tagname, $8.match_tag,
1495 PF_TAG_NAME_SIZE) >= PF_TAG_NAME_SIZE) {
1496 yyerror("tag too long, max %u chars",
1497 PF_TAG_NAME_SIZE - 1);
1498 YYERROR;
1499 }
1500 r.match_tag_not = $8.match_tag_not;
1501 r.rtableid = $8.rtableid;
1502
1503 expand_rule(&r, false, $4, NULL, NULL, NULL,
1504 $6, $7.src_os, $7.src.host, $7.src.port, $7.dst.host,
1505 $7.dst.port, NULL, NULL, NULL, NULL);
1506 }
1507 ;
1508
1509 scrub_opts : {
1510 bzero(&scrub_opts, sizeof scrub_opts);
1511 scrub_opts.rtableid = -1;
1512 }
1513 scrub_opts_l
1514 { $$ = scrub_opts; }
1515 | /* empty */ {
1516 bzero(&scrub_opts, sizeof scrub_opts);
1517 scrub_opts.rtableid = -1;
1518 $$ = scrub_opts;
1519 }
1520 ;
1521
1522 scrub_opts_l : scrub_opts_l comma scrub_opt
1523 | scrub_opt
1524 ;
1525
1526 scrub_opt : NODF {
1527 if (scrub_opts.nodf) {
1528 yyerror("no-df cannot be respecified");
1529 YYERROR;
1530 }
1531 scrub_opts.nodf = 1;
1532 }
1533 | MINTTL NUMBER {
1534 if (scrub_opts.marker & FOM_MINTTL) {
1535 yyerror("min-ttl cannot be respecified");
1536 YYERROR;
1537 }
1538 if ($2 < 0 || $2 > 255) {
1539 yyerror("illegal min-ttl value %d", $2);
1540 YYERROR;
1541 }
1542 scrub_opts.marker |= FOM_MINTTL;
1543 scrub_opts.minttl = $2;
1544 }
1545 | MAXMSS NUMBER {
1546 if (scrub_opts.marker & FOM_MAXMSS) {
1547 yyerror("max-mss cannot be respecified");
1548 YYERROR;
1549 }
1550 if ($2 < 0 || $2 > 65535) {
1551 yyerror("illegal max-mss value %d", $2);
1552 YYERROR;
1553 }
1554 scrub_opts.marker |= FOM_MAXMSS;
1555 scrub_opts.maxmss = $2;
1556 }
1557 | SETTOS tos {
1558 if (scrub_opts.marker & FOM_SETTOS) {
1559 yyerror("set-tos cannot be respecified");
1560 YYERROR;
1561 }
1562 scrub_opts.marker |= FOM_SETTOS;
1563 scrub_opts.settos = $2;
1564 }
1565 | fragcache {
1566 if (scrub_opts.marker & FOM_FRAGCACHE) {
1567 yyerror("fragcache cannot be respecified");
1568 YYERROR;
1569 }
1570 scrub_opts.marker |= FOM_FRAGCACHE;
1571 scrub_opts.fragcache = $1;
1572 }
1573 | REASSEMBLE STRING {
1574 if (strcasecmp($2, "tcp") != 0) {
1575 yyerror("scrub reassemble supports only tcp, "
1576 "not '%s'", $2);
1577 free($2);
1578 YYERROR;
1579 }
1580 free($2);
1581 if (scrub_opts.reassemble_tcp) {
1582 yyerror("reassemble tcp cannot be respecified");
1583 YYERROR;
1584 }
1585 scrub_opts.reassemble_tcp = 1;
1586 }
1587 | RANDOMID {
1588 if (scrub_opts.randomid) {
1589 yyerror("random-id cannot be respecified");
1590 YYERROR;
1591 }
1592 scrub_opts.randomid = 1;
1593 }
1594 | RTABLE NUMBER {
1595 if ($2 < 0 || $2 > rt_tableid_max()) {
1596 yyerror("invalid rtable id");
1597 YYERROR;
1598 }
1599 scrub_opts.rtableid = $2;
1600 }
1601 | not TAGGED string {
1602 scrub_opts.match_tag = $3;
1603 scrub_opts.match_tag_not = $1;
1604 }
1605 ;
1606
1607 fragcache : FRAGMENT REASSEMBLE { $$ = 0; /* default */ }
1608 | FRAGMENT NO REASSEMBLE { $$ = PFRULE_FRAGMENT_NOREASS; }
1609 ;
1610
1611 antispoof : ANTISPOOF logquick antispoof_ifspc af antispoof_opts {
1612 struct pfctl_rule r;
1613 struct node_host *h = NULL, *hh;
1614 struct node_if *i, *j;
1615
1616 if (check_rulestate(PFCTL_STATE_FILTER))
1617 YYERROR;
1618
1619 for (i = $3; i; i = i->next) {
1620 pfctl_init_rule(&r);
1621
1622 r.action = PF_DROP;
1623 r.direction = PF_IN;
1624 r.log = $2.log;
1625 r.logif = $2.logif;
1626 r.quick = $2.quick;
1627 r.af = $4;
1628 r.ridentifier = $5.ridentifier;
1629 if (rule_label(&r, $5.label))
1630 YYERROR;
1631 r.rtableid = $5.rtableid;
1632 j = calloc(1, sizeof(struct node_if));
1633 if (j == NULL)
1634 err(1, "antispoof: calloc");
1635 if (strlcpy(j->ifname, i->ifname,
1636 sizeof(j->ifname)) >= sizeof(j->ifname)) {
1637 free(j);
1638 yyerror("interface name too long");
1639 YYERROR;
1640 }
1641 j->not = 1;
1642 if (i->dynamic) {
1643 h = calloc(1, sizeof(*h));
1644 if (h == NULL)
1645 err(1, "address: calloc");
1646 h->addr.type = PF_ADDR_DYNIFTL;
1647 set_ipmask(h, 128);
1648 if (strlcpy(h->addr.v.ifname, i->ifname,
1649 sizeof(h->addr.v.ifname)) >=
1650 sizeof(h->addr.v.ifname)) {
1651 free(h);
1652 yyerror(
1653 "interface name too long");
1654 YYERROR;
1655 }
1656 hh = malloc(sizeof(*hh));
1657 if (hh == NULL)
1658 err(1, "address: malloc");
1659 bcopy(h, hh, sizeof(*hh));
1660 h->addr.iflags = PFI_AFLAG_NETWORK;
1661 } else {
1662 h = ifa_lookup(j->ifname,
1663 PFI_AFLAG_NETWORK);
1664 hh = NULL;
1665 }
1666
1667 if (h != NULL)
1668 expand_rule(&r, false, j, NULL, NULL,
1669 NULL, NULL, NULL, h, NULL, NULL,
1670 NULL, NULL, NULL, NULL, NULL);
1671
1672 if ((i->ifa_flags & IFF_LOOPBACK) == 0) {
1673 bzero(&r, sizeof(r));
1674
1675 r.action = PF_DROP;
1676 r.direction = PF_IN;
1677 r.log = $2.log;
1678 r.logif = $2.logif;
1679 r.quick = $2.quick;
1680 r.af = $4;
1681 r.ridentifier = $5.ridentifier;
1682 if (rule_label(&r, $5.label))
1683 YYERROR;
1684 r.rtableid = $5.rtableid;
1685 if (hh != NULL)
1686 h = hh;
1687 else
1688 h = ifa_lookup(i->ifname, 0);
1689 if (h != NULL)
1690 expand_rule(&r, false, NULL,
1691 NULL, NULL, NULL, NULL,
1692 NULL, h, NULL, NULL, NULL,
1693 NULL, NULL, NULL, NULL);
1694 } else
1695 free(hh);
1696 }
1697 for (int i = 0; i < PF_RULE_MAX_LABEL_COUNT; i++)
1698 free($5.label[i]);
1699 }
1700 ;
1701
1702 antispoof_ifspc : FOR antispoof_if { $$ = $2; }
1703 | FOR '{' optnl antispoof_iflst '}' { $$ = $4; }
1704 ;
1705
1706 antispoof_iflst : antispoof_if optnl { $$ = $1; }
1707 | antispoof_iflst comma antispoof_if optnl {
1708 $1->tail->next = $3;
1709 $1->tail = $3;
1710 $$ = $1;
1711 }
1712 ;
1713
1714 antispoof_if : if_item { $$ = $1; }
1715 | '(' if_item ')' {
1716 $2->dynamic = 1;
1717 $$ = $2;
1718 }
1719 ;
1720
1721 antispoof_opts : {
1722 bzero(&antispoof_opts, sizeof antispoof_opts);
1723 antispoof_opts.rtableid = -1;
1724 }
1725 antispoof_opts_l
1726 { $$ = antispoof_opts; }
1727 | /* empty */ {
1728 bzero(&antispoof_opts, sizeof antispoof_opts);
1729 antispoof_opts.rtableid = -1;
1730 $$ = antispoof_opts;
1731 }
1732 ;
1733
1734 antispoof_opts_l : antispoof_opts_l antispoof_opt
1735 | antispoof_opt
1736 ;
1737
1738 antispoof_opt : label {
1739 if (antispoof_opts.labelcount >= PF_RULE_MAX_LABEL_COUNT) {
1740 yyerror("label can only be used %d times", PF_RULE_MAX_LABEL_COUNT);
1741 YYERROR;
1742 }
1743 antispoof_opts.label[antispoof_opts.labelcount++] = $1;
1744 }
1745 | RIDENTIFIER number {
1746 antispoof_opts.ridentifier = $2;
1747 }
1748 | RTABLE NUMBER {
1749 if ($2 < 0 || $2 > rt_tableid_max()) {
1750 yyerror("invalid rtable id");
1751 YYERROR;
1752 }
1753 antispoof_opts.rtableid = $2;
1754 }
1755 ;
1756
1757 not : '!' { $$ = 1; }
1758 | /* empty */ { $$ = 0; }
1759 ;
1760
1761 tabledef : TABLE '<' STRING '>' table_opts {
1762 struct node_host *h, *nh;
1763 struct node_tinit *ti, *nti;
1764
1765 if (strlen($3) >= PF_TABLE_NAME_SIZE) {
1766 yyerror("table name too long, max %d chars",
1767 PF_TABLE_NAME_SIZE - 1);
1768 free($3);
1769 YYERROR;
1770 }
1771 if (pf->loadopt & PFCTL_FLAG_TABLE)
1772 if (process_tabledef($3, &$5, pf->opts)) {
1773 free($3);
1774 YYERROR;
1775 }
1776 free($3);
1777 for (ti = SIMPLEQ_FIRST(&$5.init_nodes);
1778 ti != SIMPLEQ_END(&$5.init_nodes); ti = nti) {
1779 if (ti->file)
1780 free(ti->file);
1781 for (h = ti->host; h != NULL; h = nh) {
1782 nh = h->next;
1783 free(h);
1784 }
1785 nti = SIMPLEQ_NEXT(ti, entries);
1786 free(ti);
1787 }
1788 }
1789 ;
1790
1791 table_opts : {
1792 bzero(&table_opts, sizeof table_opts);
1793 SIMPLEQ_INIT(&table_opts.init_nodes);
1794 }
1795 table_opts_l
1796 { $$ = table_opts; }
1797 | /* empty */
1798 {
1799 bzero(&table_opts, sizeof table_opts);
1800 SIMPLEQ_INIT(&table_opts.init_nodes);
1801 $$ = table_opts;
1802 }
1803 ;
1804
1805 table_opts_l : table_opts_l table_opt
1806 | table_opt
1807 ;
1808
1809 table_opt : STRING {
1810 if (!strcmp($1, "const"))
1811 table_opts.flags |= PFR_TFLAG_CONST;
1812 else if (!strcmp($1, "persist"))
1813 table_opts.flags |= PFR_TFLAG_PERSIST;
1814 else if (!strcmp($1, "counters"))
1815 table_opts.flags |= PFR_TFLAG_COUNTERS;
1816 else {
1817 yyerror("invalid table option '%s'", $1);
1818 free($1);
1819 YYERROR;
1820 }
1821 free($1);
1822 }
1823 | '{' optnl '}' { table_opts.init_addr = 1; }
1824 | '{' optnl host_list '}' {
1825 struct node_host *n;
1826 struct node_tinit *ti;
1827
1828 for (n = $3; n != NULL; n = n->next) {
1829 switch (n->addr.type) {
1830 case PF_ADDR_ADDRMASK:
1831 continue; /* ok */
1832 case PF_ADDR_RANGE:
1833 yyerror("address ranges are not "
1834 "permitted inside tables");
1835 break;
1836 case PF_ADDR_DYNIFTL:
1837 yyerror("dynamic addresses are not "
1838 "permitted inside tables");
1839 break;
1840 case PF_ADDR_TABLE:
1841 yyerror("tables cannot contain tables");
1842 break;
1843 case PF_ADDR_NOROUTE:
1844 yyerror("\"no-route\" is not permitted "
1845 "inside tables");
1846 break;
1847 case PF_ADDR_URPFFAILED:
1848 yyerror("\"urpf-failed\" is not "
1849 "permitted inside tables");
1850 break;
1851 default:
1852 yyerror("unknown address type %d",
1853 n->addr.type);
1854 }
1855 YYERROR;
1856 }
1857 if (!(ti = calloc(1, sizeof(*ti))))
1858 err(1, "table_opt: calloc");
1859 ti->host = $3;
1860 SIMPLEQ_INSERT_TAIL(&table_opts.init_nodes, ti,
1861 entries);
1862 table_opts.init_addr = 1;
1863 }
1864 | FILENAME STRING {
1865 struct node_tinit *ti;
1866
1867 if (!(ti = calloc(1, sizeof(*ti))))
1868 err(1, "table_opt: calloc");
1869 ti->file = $2;
1870 SIMPLEQ_INSERT_TAIL(&table_opts.init_nodes, ti,
1871 entries);
1872 table_opts.init_addr = 1;
1873 }
1874 ;
1875
1876 altqif : ALTQ interface queue_opts QUEUE qassign {
1877 struct pf_altq a;
1878
1879 if (check_rulestate(PFCTL_STATE_QUEUE))
1880 YYERROR;
1881
1882 memset(&a, 0, sizeof(a));
1883 if ($3.scheduler.qtype == ALTQT_NONE) {
1884 yyerror("no scheduler specified!");
1885 YYERROR;
1886 }
1887 a.scheduler = $3.scheduler.qtype;
1888 a.qlimit = $3.qlimit;
1889 a.tbrsize = $3.tbrsize;
1890 if ($5 == NULL && $3.scheduler.qtype != ALTQT_CODEL) {
1891 yyerror("no child queues specified");
1892 YYERROR;
1893 }
1894 if (expand_altq(&a, $2, $5, $3.queue_bwspec,
1895 &$3.scheduler))
1896 YYERROR;
1897 }
1898 ;
1899
1900 queuespec : QUEUE STRING interface queue_opts qassign {
1901 struct pf_altq a;
1902
1903 if (check_rulestate(PFCTL_STATE_QUEUE)) {
1904 free($2);
1905 YYERROR;
1906 }
1907
1908 memset(&a, 0, sizeof(a));
1909
1910 if (strlcpy(a.qname, $2, sizeof(a.qname)) >=
1911 sizeof(a.qname)) {
1912 yyerror("queue name too long (max "
1913 "%d chars)", PF_QNAME_SIZE-1);
1914 free($2);
1915 YYERROR;
1916 }
1917 free($2);
1918 if ($4.tbrsize) {
1919 yyerror("cannot specify tbrsize for queue");
1920 YYERROR;
1921 }
1922 if ($4.priority > 255) {
1923 yyerror("priority out of range: max 255");
1924 YYERROR;
1925 }
1926 a.priority = $4.priority;
1927 a.qlimit = $4.qlimit;
1928 a.scheduler = $4.scheduler.qtype;
1929 if (expand_queue(&a, $3, $5, $4.queue_bwspec,
1930 &$4.scheduler)) {
1931 yyerror("errors in queue definition");
1932 YYERROR;
1933 }
1934 }
1935 ;
1936
1937 queue_opts : {
1938 bzero(&queue_opts, sizeof queue_opts);
1939 queue_opts.priority = DEFAULT_PRIORITY;
1940 queue_opts.qlimit = DEFAULT_QLIMIT;
1941 queue_opts.scheduler.qtype = ALTQT_NONE;
1942 queue_opts.queue_bwspec.bw_percent = 100;
1943 }
1944 queue_opts_l
1945 { $$ = queue_opts; }
1946 | /* empty */ {
1947 bzero(&queue_opts, sizeof queue_opts);
1948 queue_opts.priority = DEFAULT_PRIORITY;
1949 queue_opts.qlimit = DEFAULT_QLIMIT;
1950 queue_opts.scheduler.qtype = ALTQT_NONE;
1951 queue_opts.queue_bwspec.bw_percent = 100;
1952 $$ = queue_opts;
1953 }
1954 ;
1955
1956 queue_opts_l : queue_opts_l queue_opt
1957 | queue_opt
1958 ;
1959
1960 queue_opt : BANDWIDTH bandwidth {
1961 if (queue_opts.marker & QOM_BWSPEC) {
1962 yyerror("bandwidth cannot be respecified");
1963 YYERROR;
1964 }
1965 queue_opts.marker |= QOM_BWSPEC;
1966 queue_opts.queue_bwspec = $2;
1967 }
1968 | PRIORITY NUMBER {
1969 if (queue_opts.marker & QOM_PRIORITY) {
1970 yyerror("priority cannot be respecified");
1971 YYERROR;
1972 }
1973 if ($2 < 0 || $2 > 255) {
1974 yyerror("priority out of range: max 255");
1975 YYERROR;
1976 }
1977 queue_opts.marker |= QOM_PRIORITY;
1978 queue_opts.priority = $2;
1979 }
1980 | QLIMIT NUMBER {
1981 if (queue_opts.marker & QOM_QLIMIT) {
1982 yyerror("qlimit cannot be respecified");
1983 YYERROR;
1984 }
1985 if ($2 < 0 || $2 > 65535) {
1986 yyerror("qlimit out of range: max 65535");
1987 YYERROR;
1988 }
1989 queue_opts.marker |= QOM_QLIMIT;
1990 queue_opts.qlimit = $2;
1991 }
1992 | scheduler {
1993 if (queue_opts.marker & QOM_SCHEDULER) {
1994 yyerror("scheduler cannot be respecified");
1995 YYERROR;
1996 }
1997 queue_opts.marker |= QOM_SCHEDULER;
1998 queue_opts.scheduler = $1;
1999 }
2000 | TBRSIZE NUMBER {
2001 if (queue_opts.marker & QOM_TBRSIZE) {
2002 yyerror("tbrsize cannot be respecified");
2003 YYERROR;
2004 }
2005 if ($2 < 0 || $2 > UINT_MAX) {
2006 yyerror("tbrsize too big: max %u", UINT_MAX);
2007 YYERROR;
2008 }
2009 queue_opts.marker |= QOM_TBRSIZE;
2010 queue_opts.tbrsize = $2;
2011 }
2012 ;
2013
2014 bandwidth : STRING {
2015 double bps;
2016 char *cp;
2017
2018 $$.bw_percent = 0;
2019
2020 bps = strtod($1, &cp);
2021 if (cp != NULL) {
2022 if (strlen(cp) > 1) {
2023 char *cu = cp + 1;
2024 if (!strcmp(cu, "Bit") ||
2025 !strcmp(cu, "B") ||
2026 !strcmp(cu, "bit") ||
2027 !strcmp(cu, "b")) {
2028 *cu = 0;
2029 }
2030 }
2031 if (!strcmp(cp, "b"))
2032 ; /* nothing */
2033 else if (!strcmp(cp, "K"))
2034 bps *= 1000;
2035 else if (!strcmp(cp, "M"))
2036 bps *= 1000 * 1000;
2037 else if (!strcmp(cp, "G"))
2038 bps *= 1000 * 1000 * 1000;
2039 else if (!strcmp(cp, "%")) {
2040 if (bps < 0 || bps > 100) {
2041 yyerror("bandwidth spec "
2042 "out of range");
2043 free($1);
2044 YYERROR;
2045 }
2046 $$.bw_percent = bps;
2047 bps = 0;
2048 } else {
2049 yyerror("unknown unit %s", cp);
2050 free($1);
2051 YYERROR;
2052 }
2053 }
2054 free($1);
2055 $$.bw_absolute = (u_int64_t)bps;
2056 }
2057 | NUMBER {
2058 if ($1 < 0 || $1 >= LLONG_MAX) {
2059 yyerror("bandwidth number too big");
2060 YYERROR;
2061 }
2062 $$.bw_percent = 0;
2063 $$.bw_absolute = $1;
2064 }
2065 ;
2066
2067 scheduler : CBQ {
2068 $$.qtype = ALTQT_CBQ;
2069 $$.data.cbq_opts.flags = 0;
2070 }
2071 | CBQ '(' cbqflags_list ')' {
2072 $$.qtype = ALTQT_CBQ;
2073 $$.data.cbq_opts.flags = $3;
2074 }
2075 | PRIQ {
2076 $$.qtype = ALTQT_PRIQ;
2077 $$.data.priq_opts.flags = 0;
2078 }
2079 | PRIQ '(' priqflags_list ')' {
2080 $$.qtype = ALTQT_PRIQ;
2081 $$.data.priq_opts.flags = $3;
2082 }
2083 | HFSC {
2084 $$.qtype = ALTQT_HFSC;
2085 bzero(&$$.data.hfsc_opts,
2086 sizeof(struct node_hfsc_opts));
2087 }
2088 | HFSC '(' hfsc_opts ')' {
2089 $$.qtype = ALTQT_HFSC;
2090 $$.data.hfsc_opts = $3;
2091 }
2092 | FAIRQ {
2093 $$.qtype = ALTQT_FAIRQ;
2094 bzero(&$$.data.fairq_opts,
2095 sizeof(struct node_fairq_opts));
2096 }
2097 | FAIRQ '(' fairq_opts ')' {
2098 $$.qtype = ALTQT_FAIRQ;
2099 $$.data.fairq_opts = $3;
2100 }
2101 | CODEL {
2102 $$.qtype = ALTQT_CODEL;
2103 bzero(&$$.data.codel_opts,
2104 sizeof(struct codel_opts));
2105 }
2106 | CODEL '(' codel_opts ')' {
2107 $$.qtype = ALTQT_CODEL;
2108 $$.data.codel_opts = $3;
2109 }
2110 ;
2111
2112 cbqflags_list : cbqflags_item { $$ |= $1; }
2113 | cbqflags_list comma cbqflags_item { $$ |= $3; }
2114 ;
2115
2116 cbqflags_item : STRING {
2117 if (!strcmp($1, "default"))
2118 $$ = CBQCLF_DEFCLASS;
2119 else if (!strcmp($1, "borrow"))
2120 $$ = CBQCLF_BORROW;
2121 else if (!strcmp($1, "red"))
2122 $$ = CBQCLF_RED;
2123 else if (!strcmp($1, "ecn"))
2124 $$ = CBQCLF_RED|CBQCLF_ECN;
2125 else if (!strcmp($1, "rio"))
2126 $$ = CBQCLF_RIO;
2127 else if (!strcmp($1, "codel"))
2128 $$ = CBQCLF_CODEL;
2129 else {
2130 yyerror("unknown cbq flag \"%s\"", $1);
2131 free($1);
2132 YYERROR;
2133 }
2134 free($1);
2135 }
2136 ;
2137
2138 priqflags_list : priqflags_item { $$ |= $1; }
2139 | priqflags_list comma priqflags_item { $$ |= $3; }
2140 ;
2141
2142 priqflags_item : STRING {
2143 if (!strcmp($1, "default"))
2144 $$ = PRCF_DEFAULTCLASS;
2145 else if (!strcmp($1, "red"))
2146 $$ = PRCF_RED;
2147 else if (!strcmp($1, "ecn"))
2148 $$ = PRCF_RED|PRCF_ECN;
2149 else if (!strcmp($1, "rio"))
2150 $$ = PRCF_RIO;
2151 else if (!strcmp($1, "codel"))
2152 $$ = PRCF_CODEL;
2153 else {
2154 yyerror("unknown priq flag \"%s\"", $1);
2155 free($1);
2156 YYERROR;
2157 }
2158 free($1);
2159 }
2160 ;
2161
2162 hfsc_opts : {
2163 bzero(&hfsc_opts,
2164 sizeof(struct node_hfsc_opts));
2165 }
2166 hfscopts_list {
2167 $$ = hfsc_opts;
2168 }
2169 ;
2170
2171 hfscopts_list : hfscopts_item
2172 | hfscopts_list comma hfscopts_item
2173 ;
2174
2175 hfscopts_item : LINKSHARE bandwidth {
2176 if (hfsc_opts.linkshare.used) {
2177 yyerror("linkshare already specified");
2178 YYERROR;
2179 }
2180 hfsc_opts.linkshare.m2 = $2;
2181 hfsc_opts.linkshare.used = 1;
2182 }
2183 | LINKSHARE '(' bandwidth comma NUMBER comma bandwidth ')'
2184 {
2185 if ($5 < 0 || $5 > INT_MAX) {
2186 yyerror("timing in curve out of range");
2187 YYERROR;
2188 }
2189 if (hfsc_opts.linkshare.used) {
2190 yyerror("linkshare already specified");
2191 YYERROR;
2192 }
2193 hfsc_opts.linkshare.m1 = $3;
2194 hfsc_opts.linkshare.d = $5;
2195 hfsc_opts.linkshare.m2 = $7;
2196 hfsc_opts.linkshare.used = 1;
2197 }
2198 | REALTIME bandwidth {
2199 if (hfsc_opts.realtime.used) {
2200 yyerror("realtime already specified");
2201 YYERROR;
2202 }
2203 hfsc_opts.realtime.m2 = $2;
2204 hfsc_opts.realtime.used = 1;
2205 }
2206 | REALTIME '(' bandwidth comma NUMBER comma bandwidth ')'
2207 {
2208 if ($5 < 0 || $5 > INT_MAX) {
2209 yyerror("timing in curve out of range");
2210 YYERROR;
2211 }
2212 if (hfsc_opts.realtime.used) {
2213 yyerror("realtime already specified");
2214 YYERROR;
2215 }
2216 hfsc_opts.realtime.m1 = $3;
2217 hfsc_opts.realtime.d = $5;
2218 hfsc_opts.realtime.m2 = $7;
2219 hfsc_opts.realtime.used = 1;
2220 }
2221 | UPPERLIMIT bandwidth {
2222 if (hfsc_opts.upperlimit.used) {
2223 yyerror("upperlimit already specified");
2224 YYERROR;
2225 }
2226 hfsc_opts.upperlimit.m2 = $2;
2227 hfsc_opts.upperlimit.used = 1;
2228 }
2229 | UPPERLIMIT '(' bandwidth comma NUMBER comma bandwidth ')'
2230 {
2231 if ($5 < 0 || $5 > INT_MAX) {
2232 yyerror("timing in curve out of range");
2233 YYERROR;
2234 }
2235 if (hfsc_opts.upperlimit.used) {
2236 yyerror("upperlimit already specified");
2237 YYERROR;
2238 }
2239 hfsc_opts.upperlimit.m1 = $3;
2240 hfsc_opts.upperlimit.d = $5;
2241 hfsc_opts.upperlimit.m2 = $7;
2242 hfsc_opts.upperlimit.used = 1;
2243 }
2244 | STRING {
2245 if (!strcmp($1, "default"))
2246 hfsc_opts.flags |= HFCF_DEFAULTCLASS;
2247 else if (!strcmp($1, "red"))
2248 hfsc_opts.flags |= HFCF_RED;
2249 else if (!strcmp($1, "ecn"))
2250 hfsc_opts.flags |= HFCF_RED|HFCF_ECN;
2251 else if (!strcmp($1, "rio"))
2252 hfsc_opts.flags |= HFCF_RIO;
2253 else if (!strcmp($1, "codel"))
2254 hfsc_opts.flags |= HFCF_CODEL;
2255 else {
2256 yyerror("unknown hfsc flag \"%s\"", $1);
2257 free($1);
2258 YYERROR;
2259 }
2260 free($1);
2261 }
2262 ;
2263
2264 fairq_opts : {
2265 bzero(&fairq_opts,
2266 sizeof(struct node_fairq_opts));
2267 }
2268 fairqopts_list {
2269 $$ = fairq_opts;
2270 }
2271 ;
2272
2273 fairqopts_list : fairqopts_item
2274 | fairqopts_list comma fairqopts_item
2275 ;
2276
2277 fairqopts_item : LINKSHARE bandwidth {
2278 if (fairq_opts.linkshare.used) {
2279 yyerror("linkshare already specified");
2280 YYERROR;
2281 }
2282 fairq_opts.linkshare.m2 = $2;
2283 fairq_opts.linkshare.used = 1;
2284 }
2285 | LINKSHARE '(' bandwidth number bandwidth ')' {
2286 if (fairq_opts.linkshare.used) {
2287 yyerror("linkshare already specified");
2288 YYERROR;
2289 }
2290 fairq_opts.linkshare.m1 = $3;
2291 fairq_opts.linkshare.d = $4;
2292 fairq_opts.linkshare.m2 = $5;
2293 fairq_opts.linkshare.used = 1;
2294 }
2295 | HOGS bandwidth {
2296 fairq_opts.hogs_bw = $2;
2297 }
2298 | BUCKETS number {
2299 fairq_opts.nbuckets = $2;
2300 }
2301 | STRING {
2302 if (!strcmp($1, "default"))
2303 fairq_opts.flags |= FARF_DEFAULTCLASS;
2304 else if (!strcmp($1, "red"))
2305 fairq_opts.flags |= FARF_RED;
2306 else if (!strcmp($1, "ecn"))
2307 fairq_opts.flags |= FARF_RED|FARF_ECN;
2308 else if (!strcmp($1, "rio"))
2309 fairq_opts.flags |= FARF_RIO;
2310 else if (!strcmp($1, "codel"))
2311 fairq_opts.flags |= FARF_CODEL;
2312 else {
2313 yyerror("unknown fairq flag \"%s\"", $1);
2314 free($1);
2315 YYERROR;
2316 }
2317 free($1);
2318 }
2319 ;
2320
2321 codel_opts : {
2322 bzero(&codel_opts,
2323 sizeof(struct codel_opts));
2324 }
2325 codelopts_list {
2326 $$ = codel_opts;
2327 }
2328 ;
2329
2330 codelopts_list : codelopts_item
2331 | codelopts_list comma codelopts_item
2332 ;
2333
2334 codelopts_item : INTERVAL number {
2335 if (codel_opts.interval) {
2336 yyerror("interval already specified");
2337 YYERROR;
2338 }
2339 codel_opts.interval = $2;
2340 }
2341 | TARGET number {
2342 if (codel_opts.target) {
2343 yyerror("target already specified");
2344 YYERROR;
2345 }
2346 codel_opts.target = $2;
2347 }
2348 | STRING {
2349 if (!strcmp($1, "ecn"))
2350 codel_opts.ecn = 1;
2351 else {
2352 yyerror("unknown codel option \"%s\"", $1);
2353 free($1);
2354 YYERROR;
2355 }
2356 free($1);
2357 }
2358 ;
2359
2360 qassign : /* empty */ { $$ = NULL; }
2361 | qassign_item { $$ = $1; }
2362 | '{' optnl qassign_list '}' { $$ = $3; }
2363 ;
2364
2365 qassign_list : qassign_item optnl { $$ = $1; }
2366 | qassign_list comma qassign_item optnl {
2367 $1->tail->next = $3;
2368 $1->tail = $3;
2369 $$ = $1;
2370 }
2371 ;
2372
2373 qassign_item : STRING {
2374 $$ = calloc(1, sizeof(struct node_queue));
2375 if ($$ == NULL)
2376 err(1, "qassign_item: calloc");
2377 if (strlcpy($$->queue, $1, sizeof($$->queue)) >=
2378 sizeof($$->queue)) {
2379 yyerror("queue name '%s' too long (max "
2380 "%d chars)", $1, sizeof($$->queue)-1);
2381 free($1);
2382 free($$);
2383 YYERROR;
2384 }
2385 free($1);
2386 $$->next = NULL;
2387 $$->tail = $$;
2388 }
2389 ;
2390
2391 statelim : statelim_nm statelim_opts {
2392 struct pfctl_statelim *stlim;
2393 size_t len;
2394
2395 if (!ISSET($2->marker, STATELIM_M_ID)) {
2396 yyerror("id not specified");
2397 free($1);
2398 YYERROR;
2399 }
2400 if (!ISSET($2->marker, STATELIM_M_LIMIT)) {
2401 yyerror("limit not specified");
2402 free($1);
2403 YYERROR;
2404 }
2405
2406 stlim = calloc(1, sizeof(*stlim));
2407 if (stlim == NULL)
2408 err(1, "state limiter: malloc");
2409
2410 len = strlcpy(stlim->ioc.name, $1,
2411 sizeof(stlim->ioc.name));
2412 free($1);
2413 if (len >= sizeof(stlim->ioc.name)) {
2414 /* abort? */
2415 YYERROR;
2416 }
2417
2418 stlim->ioc.id = $2->id;
2419 stlim->ioc.limit = $2->limit;
2420 stlim->ioc.rate.limit = $2->rate.limit;
2421 stlim->ioc.rate.seconds = $2->rate.seconds;
2422
2423 if (pfctl_add_statelim(pf, stlim) != 0) {
2424 yyerror("state limiter %s id %u"
2425 " already exists",
2426 stlim->ioc.name, stlim->ioc.id);
2427 free(stlim);
2428 YYERROR;
2429 }
2430 }
2431 ;
2432
2433 statelim_nm : STATE LIMITER string {
2434 size_t len = strlen($3);
2435 if (len < 1) {
2436 yyerror("state limiter name is too short");
2437 free($3);
2438 YYERROR;
2439 }
2440 if (len >= PF_STATELIM_NAME_LEN) {
2441 yyerror("state limiter name is too long");
2442 free($3);
2443 YYERROR;
2444 }
2445 $$ = $3;
2446 }
2447 ;
2448
2449 statelim_id : ID NUMBER {
2450 if ($2 < PF_STATELIM_ID_MIN ||
2451 $2 > PF_STATELIM_ID_MAX) {
2452 yyerror("state limiter id %lld: "
2453 "invalid identifier", $2);
2454 YYERROR;
2455 }
2456
2457 $$ = $2;
2458 }
2459 ;
2460
2461 statelim_opts : /* empty */ {
2462 yyerror("state limiter missing options");
2463 YYERROR;
2464 }
2465 | {
2466 memset(&statelim_opts, 0, sizeof(statelim_opts));
2467 } statelim_opts_l {
2468 $$ = &statelim_opts;
2469 }
2470 ;
2471
2472 statelim_opts_l : statelim_opts_l statelim_opt
2473 | statelim_opt
2474 ;
2475
2476 statelim_opt : statelim_id {
2477 if (ISSET(statelim_opts.marker, STATELIM_M_ID)) {
2478 yyerror("id cannot be respecified");
2479 YYERROR;
2480 }
2481
2482 statelim_opts.id = $1;
2483
2484 statelim_opts.marker |= STATELIM_M_ID;
2485 }
2486 | LIMIT NUMBER {
2487 if (ISSET(statelim_opts.marker, STATELIM_M_LIMIT)) {
2488 yyerror("limit cannot be respecified");
2489 YYERROR;
2490 }
2491
2492 if ($2 < PF_STATELIM_LIMIT_MIN ||
2493 $2 > PF_STATELIM_LIMIT_MAX) {
2494 yyerror("invalid state limiter limit");
2495 YYERROR;
2496 }
2497
2498 statelim_opts.limit = $2;
2499
2500 statelim_opts.marker |= STATELIM_M_LIMIT;
2501 }
2502 | RATE NUMBER '/' NUMBER {
2503 if (ISSET(statelim_opts.marker, STATELIM_M_RATE)) {
2504 yyerror("rate cannot be respecified");
2505 YYERROR;
2506 }
2507 if ($2 < 1) {
2508 yyerror("invalid rate limit %lld", $2);
2509 YYERROR;
2510 }
2511 if ($4 < 1) {
2512 yyerror("invalid rate seconds %lld", $4);
2513 YYERROR;
2514 }
2515
2516 statelim_opts.rate.limit = $2;
2517 statelim_opts.rate.seconds = $4;
2518
2519 statelim_opts.marker |= STATELIM_M_RATE;
2520 }
2521 ;
2522
2523 statelim_filter_opt
2524 : STATE LIMITER STRING limiter_opt_spec {
2525 struct pfctl_statelim *stlim;
2526
2527 stlim = pfctl_get_statelim_nm(pf, $3);
2528 free($3);
2529 if (stlim == NULL) {
2530 yyerror("state limiter not found");
2531 YYERROR;
2532 }
2533
2534 $$.id = stlim->ioc.id;
2535 $$.limiter_action = $4;
2536 }
2537 | STATE LIMITER statelim_id limiter_opt_spec {
2538 $$.id = $3;
2539 $$.limiter_action = $4;
2540 }
2541 ;
2542
2543 sourcelim : sourcelim_nm sourcelim_opts {
2544 struct pfctl_sourcelim *srlim;
2545 size_t len;
2546
2547 if (!ISSET($2->marker, SOURCELIM_M_ID)) {
2548 yyerror("id not specified");
2549 free($1);
2550 YYERROR;
2551 }
2552 if (!ISSET($2->marker, SOURCELIM_M_ENTRIES)) {
2553 yyerror("entries not specified");
2554 free($1);
2555 YYERROR;
2556 }
2557 if (!ISSET($2->marker, SOURCELIM_M_LIMIT)) {
2558 yyerror("state limit not specified");
2559 free($1);
2560 YYERROR;
2561 }
2562
2563 srlim = calloc(1, sizeof(*srlim));
2564 if (srlim == NULL)
2565 err(1, "source limiter: malloc");
2566
2567 len = strlcpy(srlim->ioc.name, $1,
2568 sizeof(srlim->ioc.name));
2569 free($1);
2570 if (len >= sizeof(srlim->ioc.name)) {
2571 /* abort? */
2572 YYERROR;
2573 }
2574
2575 srlim->ioc.id = $2->id;
2576 srlim->ioc.entries = $2->entries;
2577 srlim->ioc.limit = $2->limit;
2578 srlim->ioc.rate.limit = $2->rate.limit;
2579 srlim->ioc.rate.seconds = $2->rate.seconds;
2580
2581 if (ISSET($2->marker, SOURCELIM_M_TABLE)) {
2582 if (strlcpy(srlim->ioc.overload_tblname,
2583 $2->table.name,
2584 sizeof(srlim->ioc.overload_tblname)) >=
2585 sizeof(srlim->ioc.overload_tblname)) {
2586 abort();
2587 }
2588 srlim->ioc.overload_hwm = $2->table.above;
2589 srlim->ioc.overload_lwm = $2->table.below;
2590 }
2591
2592 srlim->ioc.inet_prefix = $2->inet_mask;
2593 srlim->ioc.inet6_prefix = $2->inet6_mask;
2594
2595 if (pfctl_add_sourcelim(pf, srlim) != 0) {
2596 yyerror("source limiter %s id %u"
2597 " already exists",
2598 srlim->ioc.name, srlim->ioc.id);
2599 free(srlim);
2600 YYERROR;
2601 }
2602 }
2603 ;
2604
2605 sourcelim_nm : SOURCE LIMITER string {
2606 size_t len = strlen($3);
2607 if (len < 1) {
2608 yyerror("source limiter name is too short");
2609 free($3);
2610 YYERROR;
2611 }
2612 if (len >= PF_SOURCELIM_NAME_LEN) {
2613 yyerror("source limiter name is too long");
2614 free($3);
2615 YYERROR;
2616 }
2617 $$ = $3;
2618 }
2619 ;
2620
2621 sourcelim_id : ID NUMBER {
2622 if ($2 < PF_SOURCELIM_ID_MIN ||
2623 $2 > PF_SOURCELIM_ID_MAX) {
2624 yyerror("source limiter id %lld: "
2625 "invalid identifier", $2);
2626 YYERROR;
2627 }
2628
2629 $$ = $2;
2630 }
2631 ;
2632
2633 sourcelim_opts : /* empty */ {
2634 yyerror("source limiter missing options");
2635 YYERROR;
2636 }
2637 | {
2638 memset(&sourcelim_opts, 0, sizeof(sourcelim_opts));
2639 sourcelim_opts.inet_mask = 32;
2640 sourcelim_opts.inet6_mask = 128;
2641 } sourcelim_opts_l {
2642 $$ = &sourcelim_opts;
2643 }
2644 ;
2645
2646 sourcelim_opts_l : sourcelim_opts_l sourcelim_opt
2647 | sourcelim_opt
2648 ;
2649
2650 sourcelim_opt : sourcelim_id {
2651 if (ISSET(sourcelim_opts.marker, SOURCELIM_M_ID)) {
2652 yyerror("entries cannot be respecified");
2653 YYERROR;
2654 }
2655
2656 sourcelim_opts.id = $1;
2657
2658 sourcelim_opts.marker |= SOURCELIM_M_ID;
2659 }
2660 | ENTRIES NUMBER {
2661 if (ISSET(sourcelim_opts.marker, SOURCELIM_M_ENTRIES)) {
2662 yyerror("entries cannot be respecified");
2663 YYERROR;
2664 }
2665
2666 sourcelim_opts.entries = $2;
2667
2668 sourcelim_opts.marker |= SOURCELIM_M_ENTRIES;
2669 }
2670 | LIMIT NUMBER {
2671 if (ISSET(sourcelim_opts.marker, SOURCELIM_M_LIMIT)) {
2672 yyerror("state limit cannot be respecified");
2673 YYERROR;
2674 }
2675
2676 sourcelim_opts.limit = $2;
2677
2678 sourcelim_opts.marker |= SOURCELIM_M_LIMIT;
2679 }
2680 | RATE NUMBER '/' NUMBER {
2681 if (ISSET(sourcelim_opts.marker, SOURCELIM_M_RATE)) {
2682 yyerror("rate cannot be respecified");
2683 YYERROR;
2684 }
2685
2686 sourcelim_opts.rate.limit = $2;
2687 sourcelim_opts.rate.seconds = $4;
2688
2689 sourcelim_opts.marker |= SOURCELIM_M_RATE;
2690 }
2691 | TABLE '<' STRING '>' ABOVE NUMBER sourcelim_opt_below {
2692 size_t stringlen;
2693
2694 if (ISSET(sourcelim_opts.marker, SOURCELIM_M_TABLE)) {
2695 free($3);
2696 yyerror("rate cannot be respecified");
2697 YYERROR;
2698 }
2699
2700 stringlen = strlcpy(sourcelim_opts.table.name,
2701 $3, sizeof(sourcelim_opts.table.name));
2702 free($3);
2703 if (stringlen == 0 ||
2704 stringlen >= PF_TABLE_NAME_SIZE) {
2705 yyerror("invalid table name");
2706 YYERROR;
2707 }
2708
2709 if ($6 < 0) {
2710 yyerror("above limit is invalid");
2711 YYERROR;
2712 }
2713 if ($7 > $6) {
2714 yyerror("below limit higher than above limit");
2715 YYERROR;
2716 }
2717
2718 sourcelim_opts.table.above = $6;
2719 sourcelim_opts.table.below = $7;
2720
2721 sourcelim_opts.marker |= SOURCELIM_M_TABLE;
2722 }
2723 | INET MASK NUMBER {
2724 if (ISSET(sourcelim_opts.marker,
2725 SOURCELIM_M_INET_MASK)) {
2726 yyerror("inet mask cannot be respecified");
2727 YYERROR;
2728 }
2729
2730 if ($3 < 1 || $3 > 32) {
2731 yyerror("inet mask length out of range");
2732 YYERROR;
2733 }
2734
2735 sourcelim_opts.inet_mask = $3;
2736
2737 sourcelim_opts.marker |= SOURCELIM_M_INET_MASK;
2738 }
2739 | INET6 MASK NUMBER {
2740 if (ISSET(sourcelim_opts.marker,
2741 SOURCELIM_M_INET6_MASK)) {
2742 yyerror("inet6 mask cannot be respecified");
2743 YYERROR;
2744 }
2745
2746 if ($3 < 1 || $3 > 128) {
2747 yyerror("inet6 mask length out of range");
2748 YYERROR;
2749 }
2750
2751 sourcelim_opts.inet6_mask = $3;
2752
2753 sourcelim_opts.marker |= SOURCELIM_M_INET6_MASK;
2754 }
2755 ;
2756
2757 sourcelim_opt_below
2758 : /* empty */ {
2759 $$ = 0;
2760 }
2761 | BELOW NUMBER {
2762 if ($2 < 1) {
2763 yyerror("below limit is invalid");
2764 YYERROR;
2765 }
2766 $$ = $2;
2767 }
2768 ;
2769
2770 sourcelim_filter_opt
2771 : SOURCE LIMITER STRING limiter_opt_spec {
2772 struct pfctl_sourcelim *srlim;
2773
2774 srlim = pfctl_get_sourcelim_nm(pf, $3);
2775 free($3);
2776 if (srlim == NULL) {
2777 yyerror("source limiter not found");
2778 YYERROR;
2779 }
2780
2781 $$.id = srlim->ioc.id;
2782 $$.limiter_action = $4;
2783 }
2784 | SOURCE LIMITER sourcelim_id limiter_opt_spec {
2785 $$.id = $3;
2786 $$.limiter_action = $4;
2787 }
2788 ;
2789
2790 limiter_opt_spec: /* empty */ { $$ = PF_LIMITER_DEFAULT; }
2791 | '(' limiter_opt ')' { $$ = $2; }
2792 ;
2793
2794 limiter_opt: BLOCK {
2795 $$ = PF_LIMITER_BLOCK;
2796 }
2797 | NOMATCH {
2798 $$ = PF_LIMITER_NOMATCH;
2799 }
2800 ;
2801
2802 pfrule : action dir logquick interface route af proto fromto
2803 filter_opts
2804 {
2805 struct pfctl_rule r;
2806 struct node_state_opt *o;
2807 struct node_proto *proto;
2808 int srctrack = 0;
2809 int statelock = 0;
2810 int adaptive = 0;
2811 int defaults = 0;
2812
2813 if (check_rulestate(PFCTL_STATE_FILTER))
2814 YYERROR;
2815
2816 pfctl_init_rule(&r);
2817
2818 r.action = $1.b1;
2819 switch ($1.b2) {
2820 case PFRULE_RETURNRST:
2821 r.rule_flag |= PFRULE_RETURNRST;
2822 r.return_ttl = $1.w;
2823 break;
2824 case PFRULE_RETURNICMP:
2825 r.rule_flag |= PFRULE_RETURNICMP;
2826 r.return_icmp = $1.w;
2827 r.return_icmp6 = $1.w2;
2828 break;
2829 case PFRULE_RETURN:
2830 r.rule_flag |= PFRULE_RETURN;
2831 r.return_icmp = $1.w;
2832 r.return_icmp6 = $1.w2;
2833 break;
2834 }
2835 r.direction = $2;
2836 r.log = $3.log;
2837 r.logif = $3.logif;
2838 r.quick = $3.quick;
2839 r.af = $6;
2840
2841 if (filteropts_to_rule(&r, &$9))
2842 YYERROR;
2843
2844 if ($9.flags.b1 || $9.flags.b2 || $8.src_os) {
2845 for (proto = $7; proto != NULL &&
2846 proto->proto != IPPROTO_TCP;
2847 proto = proto->next)
2848 ; /* nothing */
2849 if (proto == NULL && $7 != NULL) {
2850 if ($9.flags.b1 || $9.flags.b2)
2851 yyerror(
2852 "flags only apply to tcp");
2853 if ($8.src_os)
2854 yyerror(
2855 "OS fingerprinting only "
2856 "apply to tcp");
2857 YYERROR;
2858 }
2859 }
2860
2861 o = $9.keep.options;
2862
2863 /* 'keep state' by default on pass rules. */
2864 if (!r.keep_state && !r.action &&
2865 !($9.marker & FOM_KEEP)) {
2866 r.keep_state = PF_STATE_NORMAL;
2867 o = keep_state_defaults;
2868 defaults = 1;
2869 }
2870
2871 while (o) {
2872 struct node_state_opt *p = o;
2873
2874 switch (o->type) {
2875 case PF_STATE_OPT_MAX:
2876 if (r.max_states) {
2877 yyerror("state option 'max' "
2878 "multiple definitions");
2879 YYERROR;
2880 }
2881 r.max_states = o->data.max_states;
2882 break;
2883 case PF_STATE_OPT_NOSYNC:
2884 if (r.rule_flag & PFRULE_NOSYNC) {
2885 yyerror("state option 'sync' "
2886 "multiple definitions");
2887 YYERROR;
2888 }
2889 r.rule_flag |= PFRULE_NOSYNC;
2890 break;
2891 case PF_STATE_OPT_SRCTRACK:
2892 if (srctrack) {
2893 yyerror("state option "
2894 "'source-track' "
2895 "multiple definitions");
2896 YYERROR;
2897 }
2898 srctrack = o->data.src_track;
2899 r.rule_flag |= PFRULE_SRCTRACK;
2900 break;
2901 case PF_STATE_OPT_MAX_SRC_STATES:
2902 if (r.max_src_states) {
2903 yyerror("state option "
2904 "'max-src-states' "
2905 "multiple definitions");
2906 YYERROR;
2907 }
2908 if (o->data.max_src_states == 0) {
2909 yyerror("'max-src-states' must "
2910 "be > 0");
2911 YYERROR;
2912 }
2913 r.max_src_states =
2914 o->data.max_src_states;
2915 r.rule_flag |= PFRULE_SRCTRACK;
2916 break;
2917 case PF_STATE_OPT_OVERLOAD:
2918 if (r.overload_tblname[0]) {
2919 yyerror("multiple 'overload' "
2920 "table definitions");
2921 YYERROR;
2922 }
2923 if (strlcpy(r.overload_tblname,
2924 o->data.overload.tblname,
2925 PF_TABLE_NAME_SIZE) >=
2926 PF_TABLE_NAME_SIZE) {
2927 yyerror("state option: "
2928 "strlcpy");
2929 YYERROR;
2930 }
2931 r.flush = o->data.overload.flush;
2932 break;
2933 case PF_STATE_OPT_MAX_SRC_CONN:
2934 if (r.max_src_conn) {
2935 yyerror("state option "
2936 "'max-src-conn' "
2937 "multiple definitions");
2938 YYERROR;
2939 }
2940 if (o->data.max_src_conn == 0) {
2941 yyerror("'max-src-conn' "
2942 "must be > 0");
2943 YYERROR;
2944 }
2945 r.max_src_conn =
2946 o->data.max_src_conn;
2947 r.rule_flag |= PFRULE_SRCTRACK |
2948 PFRULE_RULESRCTRACK;
2949 break;
2950 case PF_STATE_OPT_MAX_SRC_CONN_RATE:
2951 if (r.max_src_conn_rate.limit) {
2952 yyerror("state option "
2953 "'max-src-conn-rate' "
2954 "multiple definitions");
2955 YYERROR;
2956 }
2957 if (!o->data.max_src_conn_rate.limit ||
2958 !o->data.max_src_conn_rate.seconds) {
2959 yyerror("'max-src-conn-rate' "
2960 "values must be > 0");
2961 YYERROR;
2962 }
2963 if (o->data.max_src_conn_rate.limit >
2964 PF_THRESHOLD_MAX) {
2965 yyerror("'max-src-conn-rate' "
2966 "maximum rate must be < %u",
2967 PF_THRESHOLD_MAX);
2968 YYERROR;
2969 }
2970 r.max_src_conn_rate.limit =
2971 o->data.max_src_conn_rate.limit;
2972 r.max_src_conn_rate.seconds =
2973 o->data.max_src_conn_rate.seconds;
2974 r.rule_flag |= PFRULE_SRCTRACK |
2975 PFRULE_RULESRCTRACK;
2976 break;
2977 case PF_STATE_OPT_MAX_SRC_NODES:
2978 if (r.max_src_nodes) {
2979 yyerror("state option "
2980 "'max-src-nodes' "
2981 "multiple definitions");
2982 YYERROR;
2983 }
2984 if (o->data.max_src_nodes == 0) {
2985 yyerror("'max-src-nodes' must "
2986 "be > 0");
2987 YYERROR;
2988 }
2989 r.max_src_nodes =
2990 o->data.max_src_nodes;
2991 r.rule_flag |= PFRULE_SRCTRACK |
2992 PFRULE_RULESRCTRACK;
2993 break;
2994 case PF_STATE_OPT_STATELOCK:
2995 if (statelock) {
2996 yyerror("state locking option: "
2997 "multiple definitions");
2998 YYERROR;
2999 }
3000 statelock = 1;
3001 r.rule_flag |= o->data.statelock;
3002 break;
3003 case PF_STATE_OPT_SLOPPY:
3004 if (r.rule_flag & PFRULE_STATESLOPPY) {
3005 yyerror("state sloppy option: "
3006 "multiple definitions");
3007 YYERROR;
3008 }
3009 r.rule_flag |= PFRULE_STATESLOPPY;
3010 break;
3011 case PF_STATE_OPT_PFLOW:
3012 if (r.rule_flag & PFRULE_PFLOW) {
3013 yyerror("state pflow option: "
3014 "multiple definitions");
3015 YYERROR;
3016 }
3017 r.rule_flag |= PFRULE_PFLOW;
3018 break;
3019 case PF_STATE_OPT_ALLOW_RELATED:
3020 if (r.rule_flag & PFRULE_ALLOW_RELATED) {
3021 yyerror("state allow-related option: "
3022 "multiple definitions");
3023 YYERROR;
3024 }
3025 r.rule_flag |= PFRULE_ALLOW_RELATED;
3026 break;
3027 case PF_STATE_OPT_TIMEOUT:
3028 if (o->data.timeout.number ==
3029 PFTM_ADAPTIVE_START ||
3030 o->data.timeout.number ==
3031 PFTM_ADAPTIVE_END)
3032 adaptive = 1;
3033 if (r.timeout[o->data.timeout.number]) {
3034 yyerror("state timeout %s "
3035 "multiple definitions",
3036 pf_timeouts[o->data.
3037 timeout.number].name);
3038 YYERROR;
3039 }
3040 r.timeout[o->data.timeout.number] =
3041 o->data.timeout.seconds;
3042 break;
3043 }
3044 o = o->next;
3045 if (!defaults)
3046 free(p);
3047 }
3048
3049 /* 'flags S/SA' by default on stateful rules */
3050 if (!r.action && !r.flags && !r.flagset &&
3051 !$9.fragment && !($9.marker & FOM_FLAGS) &&
3052 r.keep_state) {
3053 r.flags = parse_flags("S");
3054 r.flagset = parse_flags("SA");
3055 }
3056 if (!adaptive && r.max_states) {
3057 r.timeout[PFTM_ADAPTIVE_START] =
3058 (r.max_states / 10) * 6;
3059 r.timeout[PFTM_ADAPTIVE_END] =
3060 (r.max_states / 10) * 12;
3061 }
3062 if (r.rule_flag & PFRULE_SRCTRACK) {
3063 if (srctrack == PF_SRCTRACK_GLOBAL &&
3064 r.max_src_nodes) {
3065 yyerror("'max-src-nodes' is "
3066 "incompatible with "
3067 "'source-track global'");
3068 YYERROR;
3069 }
3070 if (srctrack == PF_SRCTRACK_GLOBAL &&
3071 r.max_src_conn) {
3072 yyerror("'max-src-conn' is "
3073 "incompatible with "
3074 "'source-track global'");
3075 YYERROR;
3076 }
3077 if (srctrack == PF_SRCTRACK_GLOBAL &&
3078 r.max_src_conn_rate.seconds) {
3079 yyerror("'max-src-conn-rate' is "
3080 "incompatible with "
3081 "'source-track global'");
3082 YYERROR;
3083 }
3084 if (r.timeout[PFTM_SRC_NODE] <
3085 r.max_src_conn_rate.seconds)
3086 r.timeout[PFTM_SRC_NODE] =
3087 r.max_src_conn_rate.seconds;
3088 r.rule_flag |= PFRULE_SRCTRACK;
3089 if (srctrack == PF_SRCTRACK_RULE)
3090 r.rule_flag |= PFRULE_RULESRCTRACK;
3091 }
3092 if (r.keep_state && !statelock)
3093 r.rule_flag |= default_statelock;
3094
3095 decide_address_family($8.src.host, &r.af);
3096 decide_address_family($8.dst.host, &r.af);
3097
3098 if ($5.rt) {
3099 if (!r.direction) {
3100 yyerror("direction must be explicit "
3101 "with rules that specify routing");
3102 YYERROR;
3103 }
3104 r.rt = $5.rt;
3105
3106 if (!($5.redirspec->pool_opts.opts & PF_POOL_IPV6NH)) {
3107 decide_address_family($5.redirspec->host, &r.af);
3108 if (!(r.rule_flag & PFRULE_AFTO))
3109 remove_invalid_hosts(&($5.redirspec->host), &r.af);
3110 if ($5.redirspec->host == NULL) {
3111 yyerror("no routing address with "
3112 "matching address family found.");
3113 YYERROR;
3114 }
3115 }
3116 }
3117 #ifdef __FreeBSD__
3118 r.divert.port = $9.divert.port;
3119 #else
3120 if ((r.divert.port = $9.divert.port)) {
3121 if (r.direction == PF_OUT) {
3122 if ($9.divert.addr) {
3123 yyerror("address specified "
3124 "for outgoing divert");
3125 YYERROR;
3126 }
3127 bzero(&r.divert.addr,
3128 sizeof(r.divert.addr));
3129 } else {
3130 if (!$9.divert.addr) {
3131 yyerror("no address specified "
3132 "for incoming divert");
3133 YYERROR;
3134 }
3135 if ($9.divert.addr->af != r.af) {
3136 yyerror("address family "
3137 "mismatch for divert");
3138 YYERROR;
3139 }
3140 r.divert.addr =
3141 $9.divert.addr->addr.v.a.addr;
3142 }
3143 }
3144 #endif
3145
3146 if ($9.dnpipe || $9.dnrpipe) {
3147 r.dnpipe = $9.dnpipe;
3148 r.dnrpipe = $9.dnrpipe;
3149 if ($9.free_flags & PFRULE_DN_IS_PIPE)
3150 r.free_flags |= PFRULE_DN_IS_PIPE;
3151 else
3152 r.free_flags |= PFRULE_DN_IS_QUEUE;
3153 }
3154
3155 if ($9.marker & FOM_AFTO) {
3156 r.naf = $9.nat->af;
3157 } else {
3158 if ($9.nat) {
3159 if (!r.af && ! $9.nat->host->ifindex)
3160 r.af = $9.nat->host->af;
3161 remove_invalid_hosts(&($9.nat->host), &r.af);
3162 if (invalid_redirect($9.nat->host, r.af))
3163 YYERROR;
3164 if ($9.nat->host->addr.type == PF_ADDR_DYNIFTL) {
3165 if (($9.nat->host = gen_dynnode($9.nat->host, r.af)) == NULL)
3166 err(1, "calloc");
3167 }
3168 if (check_netmask($9.nat->host, r.af))
3169 YYERROR;
3170 }
3171 if ($9.rdr) {
3172 if (!r.af && ! $9.rdr->host->ifindex)
3173 r.af = $9.rdr->host->af;
3174 remove_invalid_hosts(&($9.rdr->host), &r.af);
3175 if (invalid_redirect($9.rdr->host, r.af))
3176 YYERROR;
3177 if ($9.rdr->host->addr.type == PF_ADDR_DYNIFTL) {
3178 if (($9.rdr->host = gen_dynnode($9.rdr->host, r.af)) == NULL)
3179 err(1, "calloc");
3180 }
3181 if (check_netmask($9.rdr->host, r.af))
3182 YYERROR;
3183 }
3184 }
3185
3186 expand_rule(&r, false, $4, $9.nat, $9.rdr, $5.redirspec,
3187 $7, $8.src_os, $8.src.host, $8.src.port, $8.dst.host,
3188 $8.dst.port, $9.uid, $9.gid, $9.rcv, $9.icmpspec);
3189 }
3190 ;
3191
3192 filter_opts : {
3193 bzero(&filter_opts, sizeof filter_opts);
3194 filter_opts.statelim.id = PF_STATELIM_ID_NONE;
3195 filter_opts.statelim.limiter_action = PF_LIMITER_NOMATCH;
3196 filter_opts.sourcelim.id = PF_SOURCELIM_ID_NONE;
3197 filter_opts.sourcelim.limiter_action = PF_LIMITER_NOMATCH;
3198 filter_opts.rtableid = -1;
3199 }
3200 filter_opts_l
3201 { $$ = filter_opts; }
3202 | /* empty */ {
3203 bzero(&filter_opts, sizeof filter_opts);
3204 filter_opts.statelim.id = PF_STATELIM_ID_NONE;
3205 filter_opts.statelim.limiter_action = PF_LIMITER_NOMATCH;
3206 filter_opts.sourcelim.id = PF_SOURCELIM_ID_NONE;
3207 filter_opts.sourcelim.limiter_action = PF_LIMITER_NOMATCH;
3208 filter_opts.rtableid = -1;
3209 $$ = filter_opts;
3210 }
3211 ;
3212
3213 filter_opts_l : filter_opts_l filter_opt
3214 | filter_opt
3215 ;
3216
3217 filter_opt : USER uids {
3218 if (filter_opts.uid)
3219 $2->tail->next = filter_opts.uid;
3220 filter_opts.uid = $2;
3221 }
3222 | GROUP gids {
3223 if (filter_opts.gid)
3224 $2->tail->next = filter_opts.gid;
3225 filter_opts.gid = $2;
3226 }
3227 | flags {
3228 if (filter_opts.marker & FOM_FLAGS) {
3229 yyerror("flags cannot be redefined");
3230 YYERROR;
3231 }
3232 filter_opts.marker |= FOM_FLAGS;
3233 filter_opts.flags.b1 |= $1.b1;
3234 filter_opts.flags.b2 |= $1.b2;
3235 filter_opts.flags.w |= $1.w;
3236 filter_opts.flags.w2 |= $1.w2;
3237 }
3238 | icmpspec {
3239 if (filter_opts.marker & FOM_ICMP) {
3240 yyerror("icmp-type cannot be redefined");
3241 YYERROR;
3242 }
3243 filter_opts.marker |= FOM_ICMP;
3244 filter_opts.icmpspec = $1;
3245 }
3246 | PRIO NUMBER {
3247 if (filter_opts.marker & FOM_PRIO) {
3248 yyerror("prio cannot be redefined");
3249 YYERROR;
3250 }
3251 if ($2 < 0 || $2 > PF_PRIO_MAX) {
3252 yyerror("prio must be 0 - %u", PF_PRIO_MAX);
3253 YYERROR;
3254 }
3255 filter_opts.marker |= FOM_PRIO;
3256 filter_opts.prio = $2;
3257 }
3258 | TOS tos {
3259 if (filter_opts.marker & FOM_TOS) {
3260 yyerror("tos cannot be redefined");
3261 YYERROR;
3262 }
3263 filter_opts.marker |= FOM_TOS;
3264 filter_opts.tos = $2;
3265 }
3266 | keep {
3267 if (filter_opts.marker & FOM_KEEP) {
3268 yyerror("modulate or keep cannot be redefined");
3269 YYERROR;
3270 }
3271 filter_opts.marker |= FOM_KEEP;
3272 filter_opts.keep.action = $1.action;
3273 filter_opts.keep.options = $1.options;
3274 }
3275 | RIDENTIFIER number {
3276 filter_opts.ridentifier = $2;
3277 }
3278 | FRAGMENT {
3279 filter_opts.fragment = 1;
3280 }
3281 | ALLOWOPTS {
3282 filter_opts.allowopts = 1;
3283 }
3284 | label {
3285 if (filter_opts.labelcount >= PF_RULE_MAX_LABEL_COUNT) {
3286 yyerror("label can only be used %d times", PF_RULE_MAX_LABEL_COUNT);
3287 YYERROR;
3288 }
3289 filter_opts.label[filter_opts.labelcount++] = $1;
3290 }
3291 | qname {
3292 if (filter_opts.queues.qname) {
3293 yyerror("queue cannot be redefined");
3294 YYERROR;
3295 }
3296 filter_opts.queues = $1;
3297 }
3298 | DNPIPE number {
3299 filter_opts.dnpipe = $2;
3300 filter_opts.free_flags |= PFRULE_DN_IS_PIPE;
3301 }
3302 | DNPIPE '(' number ')' {
3303 filter_opts.dnpipe = $3;
3304 filter_opts.free_flags |= PFRULE_DN_IS_PIPE;
3305 }
3306 | DNPIPE '(' number comma number ')' {
3307 filter_opts.dnrpipe = $5;
3308 filter_opts.dnpipe = $3;
3309 filter_opts.free_flags |= PFRULE_DN_IS_PIPE;
3310 }
3311 | DNQUEUE number {
3312 filter_opts.dnpipe = $2;
3313 filter_opts.free_flags |= PFRULE_DN_IS_QUEUE;
3314 }
3315 | DNQUEUE '(' number comma number ')' {
3316 filter_opts.dnrpipe = $5;
3317 filter_opts.dnpipe = $3;
3318 filter_opts.free_flags |= PFRULE_DN_IS_QUEUE;
3319 }
3320 | DNQUEUE '(' number ')' {
3321 filter_opts.dnpipe = $3;
3322 filter_opts.free_flags |= PFRULE_DN_IS_QUEUE;
3323 }
3324 | TAG string {
3325 filter_opts.tag = $2;
3326 }
3327 | not TAGGED string {
3328 filter_opts.match_tag = $3;
3329 filter_opts.match_tag_not = $1;
3330 }
3331 | not RECEIVEDON if_item {
3332 if (filter_opts.rcv) {
3333 yyerror("cannot respecify received-on");
3334 YYERROR;
3335 }
3336 filter_opts.rcv = $3;
3337 filter_opts.rcv->not = $1;
3338 }
3339 | PROBABILITY probability {
3340 double p;
3341
3342 p = floor($2 * UINT_MAX + 0.5);
3343 if (p < 0.0 || p > UINT_MAX) {
3344 yyerror("invalid probability: %lf", p);
3345 YYERROR;
3346 }
3347 filter_opts.prob = (u_int32_t)p;
3348 if (filter_opts.prob == 0)
3349 filter_opts.prob = 1;
3350 }
3351 | statelim_filter_opt {
3352 if (filter_opts.statelim.id != PF_STATELIM_ID_NONE) {
3353 yyerror("state limiter already specified");
3354 YYERROR;
3355 }
3356 filter_opts.statelim = $1;
3357 }
3358 | sourcelim_filter_opt {
3359 if (filter_opts.sourcelim.id != PF_SOURCELIM_ID_NONE) {
3360 yyerror("source limiter already specified");
3361 YYERROR;
3362 }
3363 filter_opts.sourcelim = $1;
3364 }
3365 | RTABLE NUMBER {
3366 if ($2 < 0 || $2 > rt_tableid_max()) {
3367 yyerror("invalid rtable id");
3368 YYERROR;
3369 }
3370 filter_opts.rtableid = $2;
3371 }
3372 | DIVERTTO portplain {
3373 #ifdef __FreeBSD__
3374 filter_opts.divert.port = $2.a;
3375 if (!filter_opts.divert.port) {
3376 yyerror("invalid divert port: %u", ntohs($2.a));
3377 YYERROR;
3378 }
3379 #endif
3380 }
3381 | DIVERTTO STRING PORT portplain {
3382 #ifndef __FreeBSD__
3383 if ((filter_opts.divert.addr = host($2, pf->opts)) == NULL) {
3384 yyerror("could not parse divert address: %s",
3385 $2);
3386 free($2);
3387 YYERROR;
3388 }
3389 #else
3390 if ($2)
3391 #endif
3392 free($2);
3393 filter_opts.divert.port = $4.a;
3394 if (!filter_opts.divert.port) {
3395 yyerror("invalid divert port: %u", ntohs($4.a));
3396 YYERROR;
3397 }
3398 }
3399 | DIVERTREPLY {
3400 #ifdef __FreeBSD__
3401 yyerror("divert-reply has no meaning in FreeBSD pf(4)");
3402 YYERROR;
3403 #else
3404 filter_opts.divert.port = 1; /* some random value */
3405 #endif
3406 }
3407 | SCRUB '(' scrub_opts ')' {
3408 filter_opts.nodf = $3.nodf;
3409 filter_opts.minttl = $3.minttl;
3410 if ($3.marker & FOM_SETTOS) {
3411 /* Old style rules are "scrub set-tos 0x42"
3412 * New style are "set tos 0x42 scrub (...)"
3413 * What is in "scrub(...)"" is unfortunately the
3414 * original scrub syntax so it would overwrite
3415 * "set tos" of a pass/match rule.
3416 */
3417 filter_opts.settos = $3.settos;
3418 }
3419 filter_opts.randomid = $3.randomid;
3420 filter_opts.max_mss = $3.maxmss;
3421 if ($3.reassemble_tcp)
3422 filter_opts.marker |= FOM_SCRUB_TCP;
3423 filter_opts.marker |= $3.marker;
3424 }
3425 | NATTO port_redirspec {
3426 if (filter_opts.nat) {
3427 yyerror("cannot respecify nat-to/binat-to");
3428 YYERROR;
3429 }
3430 filter_opts.nat = $2;
3431 }
3432 | RDRTO port_redirspec {
3433 if (filter_opts.rdr) {
3434 yyerror("cannot respecify rdr-to");
3435 YYERROR;
3436 }
3437 filter_opts.rdr = $2;
3438 }
3439 | BINATTO port_redirspec {
3440 if (filter_opts.nat) {
3441 yyerror("cannot respecify nat-to/binat-to");
3442 YYERROR;
3443 }
3444 filter_opts.nat = $2;
3445 filter_opts.nat->binat = 1;
3446 filter_opts.nat->pool_opts.staticport = 1;
3447 }
3448 | AFTO af FROM port_redirspec {
3449 if (filter_opts.nat) {
3450 yyerror("cannot respecify af-to");
3451 YYERROR;
3452 }
3453 if ($2 == 0) {
3454 yyerror("no address family specified");
3455 YYERROR;
3456 }
3457
3458 filter_opts.nat = $4;
3459 filter_opts.nat->af = $2;
3460 remove_invalid_hosts(&($4->host), &(filter_opts.nat->af));
3461 if ($4->host == NULL) {
3462 yyerror("af-to addresses must be in the "
3463 "target address family");
3464 YYERROR;
3465 }
3466 filter_opts.marker |= FOM_AFTO;
3467 }
3468 | AFTO af FROM port_redirspec TO port_redirspec {
3469 if (filter_opts.nat) {
3470 yyerror("cannot respecify af-to");
3471 YYERROR;
3472 }
3473 if ($2 == 0) {
3474 yyerror("no address family specified");
3475 YYERROR;
3476 }
3477 filter_opts.nat = $4;
3478 filter_opts.nat->af = $2;
3479 filter_opts.rdr = $6;
3480 filter_opts.rdr->af = $2;
3481 remove_invalid_hosts(&($4->host), &(filter_opts.nat->af));
3482 remove_invalid_hosts(&($6->host), &(filter_opts.rdr->af));
3483 if ($4->host == NULL || $6->host == NULL) {
3484 yyerror("af-to addresses must be in the "
3485 "target address family");
3486 YYERROR;
3487 }
3488 filter_opts.marker |= FOM_AFTO;
3489 }
3490 | MAXPKTRATE NUMBER '/' NUMBER {
3491 if ($2 < 0 || $2 > UINT_MAX ||
3492 $4 < 0 || $4 > UINT_MAX) {
3493 yyerror("only positive values permitted");
3494 YYERROR;
3495 }
3496 if (filter_opts.pktrate.limit) {
3497 yyerror("cannot respecify max-pkt-rate");
3498 YYERROR;
3499 }
3500 filter_opts.pktrate.limit = $2;
3501 filter_opts.pktrate.seconds = $4;
3502 }
3503 | MAXPKTSIZE NUMBER {
3504 if ($2 < 0 || $2 > UINT16_MAX) {
3505 yyerror("only positive values permitted");
3506 YYERROR;
3507 }
3508 filter_opts.max_pkt_size = $2;
3509 }
3510 | ONCE {
3511 filter_opts.marker |= FOM_ONCE;
3512 }
3513 | filter_sets
3514 ;
3515
3516 filter_sets : SET '(' filter_sets_l ')' { $$ = filter_opts; }
3517 | SET filter_set { $$ = filter_opts; }
3518 ;
3519
3520 filter_sets_l : filter_sets_l comma filter_set
3521 | filter_set
3522 ;
3523
3524 filter_set : prio {
3525 if (filter_opts.marker & FOM_SETPRIO) {
3526 yyerror("prio cannot be redefined");
3527 YYERROR;
3528 }
3529 filter_opts.marker |= FOM_SETPRIO;
3530 filter_opts.set_prio[0] = $1.b1;
3531 filter_opts.set_prio[1] = $1.b2;
3532 }
3533 | TOS tos {
3534 if (filter_opts.marker & FOM_SETTOS) {
3535 yyerror("tos cannot be respecified");
3536 YYERROR;
3537 }
3538 filter_opts.marker |= FOM_SETTOS;
3539 filter_opts.settos = $2;
3540 }
3541 prio : PRIO NUMBER {
3542 if ($2 < 0 || $2 > PF_PRIO_MAX) {
3543 yyerror("prio must be 0 - %u", PF_PRIO_MAX);
3544 YYERROR;
3545 }
3546 $$.b1 = $$.b2 = $2;
3547 }
3548 | PRIO '(' NUMBER comma NUMBER ')' {
3549 if ($3 < 0 || $3 > PF_PRIO_MAX ||
3550 $5 < 0 || $5 > PF_PRIO_MAX) {
3551 yyerror("prio must be 0 - %u", PF_PRIO_MAX);
3552 YYERROR;
3553 }
3554 $$.b1 = $3;
3555 $$.b2 = $5;
3556 }
3557 ;
3558
3559 probability : STRING {
3560 char *e;
3561 double p = strtod($1, &e);
3562
3563 if (*e == '%') {
3564 p *= 0.01;
3565 e++;
3566 }
3567 if (*e) {
3568 yyerror("invalid probability: %s", $1);
3569 free($1);
3570 YYERROR;
3571 }
3572 free($1);
3573 $$ = p;
3574 }
3575 | NUMBER {
3576 $$ = (double)$1;
3577 }
3578 ;
3579
3580
3581 action : PASS {
3582 $$.b1 = PF_PASS;
3583 $$.b2 = failpolicy;
3584 $$.w = returnicmpdefault;
3585 $$.w2 = returnicmp6default;
3586 }
3587 | MATCH { $$.b1 = PF_MATCH; $$.b2 = $$.w = 0; }
3588 | BLOCK blockspec { $$ = $2; $$.b1 = PF_DROP; }
3589 ;
3590
3591 blockspec : /* empty */ {
3592 $$.b2 = blockpolicy;
3593 $$.w = returnicmpdefault;
3594 $$.w2 = returnicmp6default;
3595 }
3596 | DROP {
3597 $$.b2 = PFRULE_DROP;
3598 $$.w = 0;
3599 $$.w2 = 0;
3600 }
3601 | RETURNRST {
3602 $$.b2 = PFRULE_RETURNRST;
3603 $$.w = 0;
3604 $$.w2 = 0;
3605 }
3606 | RETURNRST '(' TTL NUMBER ')' {
3607 if ($4 < 0 || $4 > 255) {
3608 yyerror("illegal ttl value %d", $4);
3609 YYERROR;
3610 }
3611 $$.b2 = PFRULE_RETURNRST;
3612 $$.w = $4;
3613 $$.w2 = 0;
3614 }
3615 | RETURNICMP {
3616 $$.b2 = PFRULE_RETURNICMP;
3617 $$.w = returnicmpdefault;
3618 $$.w2 = returnicmp6default;
3619 }
3620 | RETURNICMP6 {
3621 $$.b2 = PFRULE_RETURNICMP;
3622 $$.w = returnicmpdefault;
3623 $$.w2 = returnicmp6default;
3624 }
3625 | RETURNICMP '(' reticmpspec ')' {
3626 $$.b2 = PFRULE_RETURNICMP;
3627 $$.w = $3;
3628 $$.w2 = returnicmpdefault;
3629 }
3630 | RETURNICMP6 '(' reticmp6spec ')' {
3631 $$.b2 = PFRULE_RETURNICMP;
3632 $$.w = returnicmpdefault;
3633 $$.w2 = $3;
3634 }
3635 | RETURNICMP '(' reticmpspec comma reticmp6spec ')' {
3636 $$.b2 = PFRULE_RETURNICMP;
3637 $$.w = $3;
3638 $$.w2 = $5;
3639 }
3640 | RETURN {
3641 $$.b2 = PFRULE_RETURN;
3642 $$.w = returnicmpdefault;
3643 $$.w2 = returnicmp6default;
3644 }
3645 ;
3646
3647 reticmpspec : STRING {
3648 if (!($$ = parseicmpspec($1, AF_INET))) {
3649 free($1);
3650 YYERROR;
3651 }
3652 free($1);
3653 }
3654 | NUMBER {
3655 u_int8_t icmptype;
3656
3657 if ($1 < 0 || $1 > 255) {
3658 yyerror("invalid icmp code %lu", $1);
3659 YYERROR;
3660 }
3661 icmptype = returnicmpdefault >> 8;
3662 $$ = (icmptype << 8 | $1);
3663 }
3664 ;
3665
3666 reticmp6spec : STRING {
3667 if (!($$ = parseicmpspec($1, AF_INET6))) {
3668 free($1);
3669 YYERROR;
3670 }
3671 free($1);
3672 }
3673 | NUMBER {
3674 u_int8_t icmptype;
3675
3676 if ($1 < 0 || $1 > 255) {
3677 yyerror("invalid icmp code %lu", $1);
3678 YYERROR;
3679 }
3680 icmptype = returnicmp6default >> 8;
3681 $$ = (icmptype << 8 | $1);
3682 }
3683 ;
3684
3685 dir : /* empty */ { $$ = PF_INOUT; }
3686 | IN { $$ = PF_IN; }
3687 | OUT { $$ = PF_OUT; }
3688 ;
3689
3690 quick : /* empty */ { $$.quick = 0; }
3691 | QUICK { $$.quick = 1; }
3692 ;
3693
3694 logquick : /* empty */ { $$.log = 0; $$.quick = 0; $$.logif = 0; }
3695 | log { $$ = $1; $$.quick = 0; }
3696 | QUICK { $$.quick = 1; $$.log = 0; $$.logif = 0; }
3697 | log QUICK { $$ = $1; $$.quick = 1; }
3698 | QUICK log { $$ = $2; $$.quick = 1; }
3699 ;
3700
3701 log : LOG { $$.log = PF_LOG; $$.logif = 0; }
3702 | LOG '(' logopts ')' {
3703 $$.log = PF_LOG | $3.log;
3704 $$.logif = $3.logif;
3705 }
3706 ;
3707
3708 logopts : logopt { $$ = $1; }
3709 | logopts comma logopt {
3710 $$.log = $1.log | $3.log;
3711 $$.logif = $3.logif;
3712 if ($$.logif == 0)
3713 $$.logif = $1.logif;
3714 }
3715 ;
3716
3717 logopt : ALL { $$.log = PF_LOG_ALL; $$.logif = 0; }
3718 | MATCHES { $$.log = PF_LOG_MATCHES; $$.logif = 0; }
3719 | USER { $$.log = PF_LOG_USER; $$.logif = 0; }
3720 | TO string {
3721 const char *errstr;
3722 u_int i;
3723
3724 $$.log = 0;
3725 if (strncmp($2, "pflog", 5)) {
3726 yyerror("%s: should be a pflog interface", $2);
3727 free($2);
3728 YYERROR;
3729 }
3730 i = strtonum($2 + 5, 0, 255, &errstr);
3731 if (errstr) {
3732 yyerror("%s: %s", $2, errstr);
3733 free($2);
3734 YYERROR;
3735 }
3736 free($2);
3737 $$.logif = i;
3738 }
3739 ;
3740
3741 interface : /* empty */ { $$ = NULL; }
3742 | ON if_item_not { $$ = $2; }
3743 | ON '{' optnl if_list '}' { $$ = $4; }
3744 ;
3745
3746 if_list : if_item_not optnl { $$ = $1; }
3747 | if_list comma if_item_not optnl {
3748 $1->tail->next = $3;
3749 $1->tail = $3;
3750 $$ = $1;
3751 }
3752 ;
3753
3754 if_item_not : not if_item { $$ = $2; $$->not = $1; }
3755 ;
3756
3757 if_item : STRING {
3758 struct node_host *n;
3759
3760 $$ = calloc(1, sizeof(struct node_if));
3761 if ($$ == NULL)
3762 err(1, "if_item: calloc");
3763 if (strlcpy($$->ifname, $1, sizeof($$->ifname)) >=
3764 sizeof($$->ifname)) {
3765 free($1);
3766 free($$);
3767 yyerror("interface name too long");
3768 YYERROR;
3769 }
3770
3771 if ((n = ifa_exists($1)) != NULL)
3772 $$->ifa_flags = n->ifa_flags;
3773
3774 free($1);
3775 $$->not = 0;
3776 $$->next = NULL;
3777 $$->tail = $$;
3778 }
3779 | ANY {
3780 $$ = calloc(1, sizeof(struct node_if));
3781 if ($$ == NULL)
3782 err(1, "if_item: calloc");
3783 strlcpy($$->ifname, "any", sizeof($$->ifname));
3784 $$->not = 0;
3785 $$->next = NULL;
3786 $$->tail = $$;
3787 }
3788 ;
3789
3790 af : /* empty */ { $$ = 0; }
3791 | INET { $$ = AF_INET; }
3792 | INET6 { $$ = AF_INET6; }
3793 ;
3794
3795 etherproto : /* empty */ { $$ = NULL; }
3796 | PROTO etherproto_item { $$ = $2; }
3797 | PROTO '{' optnl etherproto_list '}' { $$ = $4; }
3798 ;
3799
3800 etherproto_list : etherproto_item optnl { $$ = $1; }
3801 | etherproto_list comma etherproto_item optnl {
3802 $1->tail->next = $3;
3803 $1->tail = $3;
3804 $$ = $1;
3805 }
3806 ;
3807
3808 etherproto_item : etherprotoval {
3809 u_int16_t pr;
3810
3811 pr = (u_int16_t)$1;
3812 if (pr == 0) {
3813 yyerror("proto 0 cannot be used");
3814 YYERROR;
3815 }
3816 $$ = calloc(1, sizeof(struct node_proto));
3817 if ($$ == NULL)
3818 err(1, "proto_item: calloc");
3819 $$->proto = pr;
3820 $$->next = NULL;
3821 $$->tail = $$;
3822 }
3823 ;
3824
3825 etherprotoval : NUMBER {
3826 if ($1 < 0 || $1 > 65565) {
3827 yyerror("protocol outside range");
3828 YYERROR;
3829 }
3830 }
3831 | STRING
3832 {
3833 if (!strncmp($1, "0x", 2)) {
3834 if (sscanf($1, "0x%4x", &$$) != 1) {
3835 free($1);
3836 yyerror("invalid EtherType hex");
3837 YYERROR;
3838 }
3839 } else {
3840 yyerror("Symbolic EtherType not yet supported");
3841 }
3842 }
3843 ;
3844
3845 proto : /* empty */ { $$ = NULL; }
3846 | PROTO proto_item { $$ = $2; }
3847 | PROTO '{' optnl proto_list '}' { $$ = $4; }
3848 ;
3849
3850 proto_list : proto_item optnl { $$ = $1; }
3851 | proto_list comma proto_item optnl {
3852 $1->tail->next = $3;
3853 $1->tail = $3;
3854 $$ = $1;
3855 }
3856 ;
3857
3858 proto_item : protoval {
3859 u_int8_t pr;
3860
3861 pr = (u_int8_t)$1;
3862 if (pr == 0) {
3863 yyerror("proto 0 cannot be used");
3864 YYERROR;
3865 }
3866 $$ = calloc(1, sizeof(struct node_proto));
3867 if ($$ == NULL)
3868 err(1, "proto_item: calloc");
3869 $$->proto = pr;
3870 $$->next = NULL;
3871 $$->tail = $$;
3872 }
3873 ;
3874
3875 protoval : STRING {
3876 struct protoent *p;
3877
3878 p = getprotobyname($1);
3879 if (p == NULL) {
3880 yyerror("unknown protocol %s", $1);
3881 free($1);
3882 YYERROR;
3883 }
3884 $$ = p->p_proto;
3885 free($1);
3886 }
3887 | NUMBER {
3888 if ($1 < 0 || $1 > 255) {
3889 yyerror("protocol outside range");
3890 YYERROR;
3891 }
3892 }
3893 ;
3894
3895 l3fromto : /* empty */ {
3896 bzero(&$$, sizeof($$));
3897 }
3898 | L3 fromto {
3899 if ($2.src.host != NULL &&
3900 $2.src.host->addr.type != PF_ADDR_ADDRMASK &&
3901 $2.src.host->addr.type != PF_ADDR_TABLE) {
3902 yyerror("from must be an address or table");
3903 YYERROR;
3904 }
3905 if ($2.dst.host != NULL &&
3906 $2.dst.host->addr.type != PF_ADDR_ADDRMASK &&
3907 $2.dst.host->addr.type != PF_ADDR_TABLE) {
3908 yyerror("to must be an address or table");
3909 YYERROR;
3910 }
3911 $$ = $2;
3912 }
3913 ;
3914 etherfromto : ALL {
3915 $$.src = NULL;
3916 $$.dst = NULL;
3917 }
3918 | etherfrom etherto {
3919 $$.src = $1.mac;
3920 $$.dst = $2.mac;
3921 }
3922 ;
3923
3924 etherfrom : /* emtpy */ {
3925 bzero(&$$, sizeof($$));
3926 }
3927 | FROM macspec {
3928 $$.mac = $2;
3929 }
3930 ;
3931
3932 etherto : /* empty */ {
3933 bzero(&$$, sizeof($$));
3934 }
3935 | TO macspec {
3936 $$.mac = $2;
3937 }
3938 ;
3939
3940 mac : string '/' NUMBER {
3941 $$ = node_mac_from_string_masklen($1, $3);
3942 free($1);
3943 if ($$ == NULL)
3944 YYERROR;
3945 }
3946 | string {
3947 if (strchr($1, '&')) {
3948 /* mac&mask */
3949 char *mac = strtok($1, "&");
3950 char *mask = strtok(NULL, "&");
3951 $$ = node_mac_from_string_mask(mac, mask);
3952 } else {
3953 $$ = node_mac_from_string($1);
3954 }
3955 free($1);
3956 if ($$ == NULL)
3957 YYERROR;
3958
3959 }
3960 xmac : not mac {
3961 struct node_mac *n;
3962
3963 for (n = $2; n != NULL; n = n->next)
3964 n->neg = $1;
3965 $$ = $2;
3966 }
3967 ;
3968 macspec : xmac {
3969 $$ = $1;
3970 }
3971 | '{' optnl mac_list '}'
3972 {
3973 $$ = $3;
3974 }
3975 ;
3976 mac_list : xmac optnl {
3977 $$ = $1;
3978 }
3979 | mac_list comma xmac {
3980 if ($3 == NULL)
3981 $$ = $1;
3982 else if ($1 == NULL)
3983 $$ = $3;
3984 else {
3985 $1->tail->next = $3;
3986 $1->tail = $3->tail;
3987 $$ = $1;
3988 }
3989 }
3990
3991 fromto : ALL {
3992 $$.src.host = NULL;
3993 $$.src.port = NULL;
3994 $$.dst.host = NULL;
3995 $$.dst.port = NULL;
3996 $$.src_os = NULL;
3997 }
3998 | from os to {
3999 $$.src = $1;
4000 $$.src_os = $2;
4001 $$.dst = $3;
4002 }
4003 ;
4004
4005 os : /* empty */ { $$ = NULL; }
4006 | OS xos { $$ = $2; }
4007 | OS '{' optnl os_list '}' { $$ = $4; }
4008 ;
4009
4010 xos : STRING {
4011 $$ = calloc(1, sizeof(struct node_os));
4012 if ($$ == NULL)
4013 err(1, "os: calloc");
4014 $$->os = $1;
4015 $$->tail = $$;
4016 }
4017 ;
4018
4019 os_list : xos optnl { $$ = $1; }
4020 | os_list comma xos optnl {
4021 $1->tail->next = $3;
4022 $1->tail = $3;
4023 $$ = $1;
4024 }
4025 ;
4026
4027 from : /* empty */ {
4028 $$.host = NULL;
4029 $$.port = NULL;
4030 }
4031 | FROM ipportspec {
4032 $$ = $2;
4033 }
4034 ;
4035
4036 to : /* empty */ {
4037 $$.host = NULL;
4038 $$.port = NULL;
4039 }
4040 | TO ipportspec {
4041 if (disallow_urpf_failed($2.host, "\"urpf-failed\" is "
4042 "not permitted in a destination address"))
4043 YYERROR;
4044 $$ = $2;
4045 }
4046 ;
4047
4048 ipportspec : ipspec {
4049 $$.host = $1;
4050 $$.port = NULL;
4051 }
4052 | ipspec PORT portspec {
4053 $$.host = $1;
4054 $$.port = $3;
4055 }
4056 | PORT portspec {
4057 $$.host = NULL;
4058 $$.port = $2;
4059 }
4060 ;
4061
4062 optnl : '\n' optnl
4063 |
4064 ;
4065
4066 ipspec : ANY { $$ = NULL; }
4067 | xhost { $$ = $1; }
4068 | '{' optnl host_list '}' { $$ = $3; }
4069 ;
4070
4071 toipspec : TO ipspec { $$ = $2; }
4072 | /* empty */ { $$ = NULL; }
4073 ;
4074
4075 host_list : ipspec optnl { $$ = $1; }
4076 | host_list comma ipspec optnl {
4077 if ($1 == NULL) {
4078 freehostlist($3);
4079 $$ = $1;
4080 } else if ($3 == NULL) {
4081 freehostlist($1);
4082 $$ = $3;
4083 } else {
4084 $1->tail->next = $3;
4085 $1->tail = $3->tail;
4086 $$ = $1;
4087 }
4088 }
4089 ;
4090
4091 xhost : not host {
4092 struct node_host *n;
4093
4094 for (n = $2; n != NULL; n = n->next)
4095 n->not = $1;
4096 $$ = $2;
4097 }
4098 | not NOROUTE {
4099 $$ = calloc(1, sizeof(struct node_host));
4100 if ($$ == NULL)
4101 err(1, "xhost: calloc");
4102 $$->addr.type = PF_ADDR_NOROUTE;
4103 $$->next = NULL;
4104 $$->not = $1;
4105 $$->tail = $$;
4106 }
4107 | not URPFFAILED {
4108 $$ = calloc(1, sizeof(struct node_host));
4109 if ($$ == NULL)
4110 err(1, "xhost: calloc");
4111 $$->addr.type = PF_ADDR_URPFFAILED;
4112 $$->next = NULL;
4113 $$->not = $1;
4114 $$->tail = $$;
4115 }
4116 ;
4117
4118 host : STRING {
4119 if (($$ = host($1, pf->opts)) == NULL) {
4120 /* error. "any" is handled elsewhere */
4121 free($1);
4122 yyerror("could not parse host specification");
4123 YYERROR;
4124 }
4125 free($1);
4126
4127 }
4128 | STRING '-' STRING {
4129 struct node_host *b, *e;
4130
4131 if ((b = host($1, pf->opts)) == NULL ||
4132 (e = host($3, pf->opts)) == NULL) {
4133 free($1);
4134 free($3);
4135 yyerror("could not parse host specification");
4136 YYERROR;
4137 }
4138 if (b->af != e->af ||
4139 b->addr.type != PF_ADDR_ADDRMASK ||
4140 e->addr.type != PF_ADDR_ADDRMASK ||
4141 unmask(&b->addr.v.a.mask) !=
4142 (b->af == AF_INET ? 32 : 128) ||
4143 unmask(&e->addr.v.a.mask) !=
4144 (e->af == AF_INET ? 32 : 128) ||
4145 b->next != NULL || b->not ||
4146 e->next != NULL || e->not) {
4147 free(b);
4148 free(e);
4149 free($1);
4150 free($3);
4151 yyerror("invalid address range");
4152 YYERROR;
4153 }
4154 memcpy(&b->addr.v.a.mask, &e->addr.v.a.addr,
4155 sizeof(b->addr.v.a.mask));
4156 b->addr.type = PF_ADDR_RANGE;
4157 $$ = b;
4158 free(e);
4159 free($1);
4160 free($3);
4161 }
4162 | STRING '/' NUMBER {
4163 char *buf;
4164
4165 if (asprintf(&buf, "%s/%lld", $1, (long long)$3) == -1)
4166 err(1, "host: asprintf");
4167 free($1);
4168 if (($$ = host(buf, pf->opts)) == NULL) {
4169 /* error. "any" is handled elsewhere */
4170 free(buf);
4171 yyerror("could not parse host specification");
4172 YYERROR;
4173 }
4174 free(buf);
4175 }
4176 | NUMBER '/' NUMBER {
4177 char *buf;
4178
4179 /* ie. for 10/8 parsing */
4180 #ifdef __FreeBSD__
4181 if (asprintf(&buf, "%lld/%lld", (long long)$1, (long long)$3) == -1)
4182 #else
4183 if (asprintf(&buf, "%lld/%lld", $1, $3) == -1)
4184 #endif
4185 err(1, "host: asprintf");
4186 if (($$ = host(buf, pf->opts)) == NULL) {
4187 /* error. "any" is handled elsewhere */
4188 free(buf);
4189 yyerror("could not parse host specification");
4190 YYERROR;
4191 }
4192 free(buf);
4193 }
4194 | dynaddr
4195 | dynaddr '/' NUMBER {
4196 struct node_host *n;
4197
4198 if ($3 < 0 || $3 > 128) {
4199 yyerror("bit number too big");
4200 YYERROR;
4201 }
4202 $$ = $1;
4203 for (n = $1; n != NULL; n = n->next)
4204 set_ipmask(n, $3);
4205 }
4206 | '<' STRING '>' {
4207 if (strlen($2) >= PF_TABLE_NAME_SIZE) {
4208 yyerror("table name '%s' too long", $2);
4209 free($2);
4210 YYERROR;
4211 }
4212 $$ = calloc(1, sizeof(struct node_host));
4213 if ($$ == NULL)
4214 err(1, "host: calloc");
4215 $$->addr.type = PF_ADDR_TABLE;
4216 if (strlcpy($$->addr.v.tblname, $2,
4217 sizeof($$->addr.v.tblname)) >=
4218 sizeof($$->addr.v.tblname))
4219 errx(1, "host: strlcpy");
4220 free($2);
4221 $$->next = NULL;
4222 $$->tail = $$;
4223 }
4224 ;
4225
4226 number : NUMBER
4227 | STRING {
4228 u_long ulval;
4229
4230 if (atoul($1, &ulval) == -1) {
4231 yyerror("%s is not a number", $1);
4232 free($1);
4233 YYERROR;
4234 } else
4235 $$ = ulval;
4236 free($1);
4237 }
4238 ;
4239
4240 dynaddr : '(' STRING ')' {
4241 int flags = 0;
4242 char *p, *op;
4243
4244 op = $2;
4245 if (!isalpha(op[0])) {
4246 yyerror("invalid interface name '%s'", op);
4247 free(op);
4248 YYERROR;
4249 }
4250 while ((p = strrchr($2, ':')) != NULL) {
4251 if (!strcmp(p+1, "network"))
4252 flags |= PFI_AFLAG_NETWORK;
4253 else if (!strcmp(p+1, "broadcast"))
4254 flags |= PFI_AFLAG_BROADCAST;
4255 else if (!strcmp(p+1, "peer"))
4256 flags |= PFI_AFLAG_PEER;
4257 else if (!strcmp(p+1, "0"))
4258 flags |= PFI_AFLAG_NOALIAS;
4259 else {
4260 yyerror("interface %s has bad modifier",
4261 $2);
4262 free(op);
4263 YYERROR;
4264 }
4265 *p = '\0';
4266 }
4267 if (flags & (flags - 1) & PFI_AFLAG_MODEMASK) {
4268 free(op);
4269 yyerror("illegal combination of "
4270 "interface modifiers");
4271 YYERROR;
4272 }
4273 $$ = calloc(1, sizeof(struct node_host));
4274 if ($$ == NULL)
4275 err(1, "address: calloc");
4276 $$->af = 0;
4277 set_ipmask($$, 128);
4278 $$->addr.type = PF_ADDR_DYNIFTL;
4279 $$->addr.iflags = flags;
4280 if (strlcpy($$->addr.v.ifname, $2,
4281 sizeof($$->addr.v.ifname)) >=
4282 sizeof($$->addr.v.ifname)) {
4283 free(op);
4284 free($$);
4285 yyerror("interface name too long");
4286 YYERROR;
4287 }
4288 free(op);
4289 $$->next = NULL;
4290 $$->tail = $$;
4291 }
4292 ;
4293
4294 portspec : port_item { $$ = $1; }
4295 | '{' optnl port_list '}' { $$ = $3; }
4296 ;
4297
4298 port_list : port_item optnl { $$ = $1; }
4299 | port_list comma port_item optnl {
4300 $1->tail->next = $3;
4301 $1->tail = $3;
4302 $$ = $1;
4303 }
4304 ;
4305
4306 port_item : portrange {
4307 $$ = calloc(1, sizeof(struct node_port));
4308 if ($$ == NULL)
4309 err(1, "port_item: calloc");
4310 $$->port[0] = $1.a;
4311 $$->port[1] = $1.b;
4312 if ($1.t) {
4313 $$->op = PF_OP_RRG;
4314 if (validate_range($$->op, $$->port[0],
4315 $$->port[1])) {
4316 yyerror("invalid port range");
4317 YYERROR;
4318 }
4319 } else
4320 $$->op = PF_OP_EQ;
4321 $$->next = NULL;
4322 $$->tail = $$;
4323 }
4324 | unaryop portrange {
4325 if ($2.t) {
4326 yyerror("':' cannot be used with an other "
4327 "port operator");
4328 YYERROR;
4329 }
4330 $$ = calloc(1, sizeof(struct node_port));
4331 if ($$ == NULL)
4332 err(1, "port_item: calloc");
4333 $$->port[0] = $2.a;
4334 $$->port[1] = $2.b;
4335 $$->op = $1;
4336 if (validate_range($$->op, $$->port[0], $$->port[1])) {
4337 yyerror("invalid port range");
4338 YYERROR;
4339 }
4340 $$->next = NULL;
4341 $$->tail = $$;
4342 }
4343 | portrange PORTBINARY portrange {
4344 if ($1.t || $3.t) {
4345 yyerror("':' cannot be used with an other "
4346 "port operator");
4347 YYERROR;
4348 }
4349 $$ = calloc(1, sizeof(struct node_port));
4350 if ($$ == NULL)
4351 err(1, "port_item: calloc");
4352 $$->port[0] = $1.a;
4353 $$->port[1] = $3.a;
4354 $$->op = $2;
4355 if (validate_range($$->op, $$->port[0], $$->port[1])) {
4356 yyerror("invalid port range");
4357 YYERROR;
4358 }
4359 $$->next = NULL;
4360 $$->tail = $$;
4361 }
4362 ;
4363
4364 portplain : numberstring {
4365 if (parseport($1, &$$, 0) == -1) {
4366 free($1);
4367 YYERROR;
4368 }
4369 free($1);
4370 }
4371 ;
4372
4373 portrange : numberstring {
4374 if (parseport($1, &$$, PPORT_RANGE) == -1) {
4375 free($1);
4376 YYERROR;
4377 }
4378 free($1);
4379 }
4380 ;
4381
4382 uids : uid_item { $$ = $1; }
4383 | '{' optnl uid_list '}' { $$ = $3; }
4384 ;
4385
4386 uid_list : uid_item optnl { $$ = $1; }
4387 | uid_list comma uid_item optnl {
4388 $1->tail->next = $3;
4389 $1->tail = $3;
4390 $$ = $1;
4391 }
4392 ;
4393
4394 uid_item : uid {
4395 $$ = calloc(1, sizeof(struct node_uid));
4396 if ($$ == NULL)
4397 err(1, "uid_item: calloc");
4398 $$->uid[0] = $1;
4399 $$->uid[1] = $1;
4400 $$->op = PF_OP_EQ;
4401 $$->next = NULL;
4402 $$->tail = $$;
4403 }
4404 | unaryop uid {
4405 if ($2 == -1 && $1 != PF_OP_EQ && $1 != PF_OP_NE) {
4406 yyerror("user unknown requires operator = or "
4407 "!=");
4408 YYERROR;
4409 }
4410 $$ = calloc(1, sizeof(struct node_uid));
4411 if ($$ == NULL)
4412 err(1, "uid_item: calloc");
4413 $$->uid[0] = $2;
4414 $$->uid[1] = $2;
4415 $$->op = $1;
4416 $$->next = NULL;
4417 $$->tail = $$;
4418 }
4419 | uid PORTBINARY uid {
4420 if ($1 == -1 || $3 == -1) {
4421 yyerror("user unknown requires operator = or "
4422 "!=");
4423 YYERROR;
4424 }
4425 $$ = calloc(1, sizeof(struct node_uid));
4426 if ($$ == NULL)
4427 err(1, "uid_item: calloc");
4428 $$->uid[0] = $1;
4429 $$->uid[1] = $3;
4430 $$->op = $2;
4431 $$->next = NULL;
4432 $$->tail = $$;
4433 }
4434 ;
4435
4436 uid : STRING {
4437 if (!strcmp($1, "unknown"))
4438 $$ = -1;
4439 else {
4440 uid_t uid;
4441
4442 if (uid_from_user($1, &uid) == -1) {
4443 yyerror("unknown user %s", $1);
4444 free($1);
4445 YYERROR;
4446 }
4447 $$ = uid;
4448 }
4449 free($1);
4450 }
4451 | NUMBER {
4452 if ($1 < 0 || $1 >= UID_MAX) {
4453 yyerror("illegal uid value %lu", $1);
4454 YYERROR;
4455 }
4456 $$ = $1;
4457 }
4458 ;
4459
4460 gids : gid_item { $$ = $1; }
4461 | '{' optnl gid_list '}' { $$ = $3; }
4462 ;
4463
4464 gid_list : gid_item optnl { $$ = $1; }
4465 | gid_list comma gid_item optnl {
4466 $1->tail->next = $3;
4467 $1->tail = $3;
4468 $$ = $1;
4469 }
4470 ;
4471
4472 gid_item : gid {
4473 $$ = calloc(1, sizeof(struct node_gid));
4474 if ($$ == NULL)
4475 err(1, "gid_item: calloc");
4476 $$->gid[0] = $1;
4477 $$->gid[1] = $1;
4478 $$->op = PF_OP_EQ;
4479 $$->next = NULL;
4480 $$->tail = $$;
4481 }
4482 | unaryop gid {
4483 if ($2 == -1 && $1 != PF_OP_EQ && $1 != PF_OP_NE) {
4484 yyerror("group unknown requires operator = or "
4485 "!=");
4486 YYERROR;
4487 }
4488 $$ = calloc(1, sizeof(struct node_gid));
4489 if ($$ == NULL)
4490 err(1, "gid_item: calloc");
4491 $$->gid[0] = $2;
4492 $$->gid[1] = $2;
4493 $$->op = $1;
4494 $$->next = NULL;
4495 $$->tail = $$;
4496 }
4497 | gid PORTBINARY gid {
4498 if ($1 == -1 || $3 == -1) {
4499 yyerror("group unknown requires operator = or "
4500 "!=");
4501 YYERROR;
4502 }
4503 $$ = calloc(1, sizeof(struct node_gid));
4504 if ($$ == NULL)
4505 err(1, "gid_item: calloc");
4506 $$->gid[0] = $1;
4507 $$->gid[1] = $3;
4508 $$->op = $2;
4509 $$->next = NULL;
4510 $$->tail = $$;
4511 }
4512 ;
4513
4514 gid : STRING {
4515 if (!strcmp($1, "unknown"))
4516 $$ = -1;
4517 else {
4518 gid_t gid;
4519
4520 if (gid_from_group($1, &gid) == -1) {
4521 yyerror("unknown group %s", $1);
4522 free($1);
4523 YYERROR;
4524 }
4525 $$ = gid;
4526 }
4527 free($1);
4528 }
4529 | NUMBER {
4530 if ($1 < 0 || $1 >= GID_MAX) {
4531 yyerror("illegal gid value %lu", $1);
4532 YYERROR;
4533 }
4534 $$ = $1;
4535 }
4536 ;
4537
4538 flag : STRING {
4539 int f;
4540
4541 if ((f = parse_flags($1)) < 0) {
4542 yyerror("bad flags %s", $1);
4543 free($1);
4544 YYERROR;
4545 }
4546 free($1);
4547 $$.b1 = f;
4548 }
4549 ;
4550
4551 flags : FLAGS flag '/' flag { $$.b1 = $2.b1; $$.b2 = $4.b1; }
4552 | FLAGS '/' flag { $$.b1 = 0; $$.b2 = $3.b1; }
4553 | FLAGS ANY { $$.b1 = 0; $$.b2 = 0; }
4554 ;
4555
4556 icmpspec : ICMPTYPE icmp_item { $$ = $2; }
4557 | ICMPTYPE '{' optnl icmp_list '}' { $$ = $4; }
4558 | ICMP6TYPE icmp6_item { $$ = $2; }
4559 | ICMP6TYPE '{' optnl icmp6_list '}' { $$ = $4; }
4560 ;
4561
4562 icmp_list : icmp_item optnl { $$ = $1; }
4563 | icmp_list comma icmp_item optnl {
4564 $1->tail->next = $3;
4565 $1->tail = $3;
4566 $$ = $1;
4567 }
4568 ;
4569
4570 icmp6_list : icmp6_item optnl { $$ = $1; }
4571 | icmp6_list comma icmp6_item optnl {
4572 $1->tail->next = $3;
4573 $1->tail = $3;
4574 $$ = $1;
4575 }
4576 ;
4577
4578 icmp_item : icmptype {
4579 $$ = calloc(1, sizeof(struct node_icmp));
4580 if ($$ == NULL)
4581 err(1, "icmp_item: calloc");
4582 $$->type = $1;
4583 $$->code = 0;
4584 $$->proto = IPPROTO_ICMP;
4585 $$->next = NULL;
4586 $$->tail = $$;
4587 }
4588 | icmptype CODE STRING {
4589 const struct icmpcodeent *p;
4590
4591 if ((p = geticmpcodebyname($1-1, $3, AF_INET)) == NULL) {
4592 yyerror("unknown icmp-code %s", $3);
4593 free($3);
4594 YYERROR;
4595 }
4596
4597 free($3);
4598 $$ = calloc(1, sizeof(struct node_icmp));
4599 if ($$ == NULL)
4600 err(1, "icmp_item: calloc");
4601 $$->type = $1;
4602 $$->code = p->code + 1;
4603 $$->proto = IPPROTO_ICMP;
4604 $$->next = NULL;
4605 $$->tail = $$;
4606 }
4607 | icmptype CODE NUMBER {
4608 if ($3 < 0 || $3 > 255) {
4609 yyerror("illegal icmp-code %lu", $3);
4610 YYERROR;
4611 }
4612 $$ = calloc(1, sizeof(struct node_icmp));
4613 if ($$ == NULL)
4614 err(1, "icmp_item: calloc");
4615 $$->type = $1;
4616 $$->code = $3 + 1;
4617 $$->proto = IPPROTO_ICMP;
4618 $$->next = NULL;
4619 $$->tail = $$;
4620 }
4621 ;
4622
4623 icmp6_item : icmp6type {
4624 $$ = calloc(1, sizeof(struct node_icmp));
4625 if ($$ == NULL)
4626 err(1, "icmp_item: calloc");
4627 $$->type = $1;
4628 $$->code = 0;
4629 $$->proto = IPPROTO_ICMPV6;
4630 $$->next = NULL;
4631 $$->tail = $$;
4632 }
4633 | icmp6type CODE STRING {
4634 const struct icmpcodeent *p;
4635
4636 if ((p = geticmpcodebyname($1-1, $3, AF_INET6)) == NULL) {
4637 yyerror("unknown icmp6-code %s", $3);
4638 free($3);
4639 YYERROR;
4640 }
4641 free($3);
4642
4643 $$ = calloc(1, sizeof(struct node_icmp));
4644 if ($$ == NULL)
4645 err(1, "icmp_item: calloc");
4646 $$->type = $1;
4647 $$->code = p->code + 1;
4648 $$->proto = IPPROTO_ICMPV6;
4649 $$->next = NULL;
4650 $$->tail = $$;
4651 }
4652 | icmp6type CODE NUMBER {
4653 if ($3 < 0 || $3 > 255) {
4654 yyerror("illegal icmp-code %lu", $3);
4655 YYERROR;
4656 }
4657 $$ = calloc(1, sizeof(struct node_icmp));
4658 if ($$ == NULL)
4659 err(1, "icmp_item: calloc");
4660 $$->type = $1;
4661 $$->code = $3 + 1;
4662 $$->proto = IPPROTO_ICMPV6;
4663 $$->next = NULL;
4664 $$->tail = $$;
4665 }
4666 ;
4667
4668 icmptype : STRING {
4669 const struct icmptypeent *p;
4670
4671 if ((p = geticmptypebyname($1, AF_INET)) == NULL) {
4672 yyerror("unknown icmp-type %s", $1);
4673 free($1);
4674 YYERROR;
4675 }
4676 $$ = p->type + 1;
4677 free($1);
4678 }
4679 | NUMBER {
4680 if ($1 < 0 || $1 > 255) {
4681 yyerror("illegal icmp-type %lu", $1);
4682 YYERROR;
4683 }
4684 $$ = $1 + 1;
4685 }
4686 ;
4687
4688 icmp6type : STRING {
4689 const struct icmptypeent *p;
4690
4691 if ((p = geticmptypebyname($1, AF_INET6)) ==
4692 NULL) {
4693 yyerror("unknown icmp6-type %s", $1);
4694 free($1);
4695 YYERROR;
4696 }
4697 $$ = p->type + 1;
4698 free($1);
4699 }
4700 | NUMBER {
4701 if ($1 < 0 || $1 > 255) {
4702 yyerror("illegal icmp6-type %lu", $1);
4703 YYERROR;
4704 }
4705 $$ = $1 + 1;
4706 }
4707 ;
4708
4709 tos : STRING {
4710 int val;
4711 char *end;
4712
4713 if (map_tos($1, &val))
4714 $$ = val;
4715 else if ($1[0] == '0' && $1[1] == 'x') {
4716 errno = 0;
4717 $$ = strtoul($1, &end, 16);
4718 if (errno || *end != '\0')
4719 $$ = 256;
4720 } else
4721 $$ = 256; /* flag bad argument */
4722 if ($$ < 0 || $$ > 255) {
4723 yyerror("illegal tos value %s", $1);
4724 free($1);
4725 YYERROR;
4726 }
4727 free($1);
4728 }
4729 | NUMBER {
4730 $$ = $1;
4731 if ($$ < 0 || $$ > 255) {
4732 yyerror("illegal tos value %lu", $1);
4733 YYERROR;
4734 }
4735 }
4736 ;
4737
4738 sourcetrack : SOURCETRACK { $$ = PF_SRCTRACK; }
4739 | SOURCETRACK GLOBAL { $$ = PF_SRCTRACK_GLOBAL; }
4740 | SOURCETRACK RULE { $$ = PF_SRCTRACK_RULE; }
4741 ;
4742
4743 statelock : IFBOUND {
4744 $$ = PFRULE_IFBOUND;
4745 }
4746 | FLOATING {
4747 $$ = 0;
4748 }
4749 ;
4750
4751 keep : NO STATE {
4752 $$.action = 0;
4753 $$.options = NULL;
4754 }
4755 | KEEP STATE state_opt_spec {
4756 $$.action = PF_STATE_NORMAL;
4757 $$.options = $3;
4758 }
4759 | MODULATE STATE state_opt_spec {
4760 $$.action = PF_STATE_MODULATE;
4761 $$.options = $3;
4762 }
4763 | SYNPROXY STATE state_opt_spec {
4764 $$.action = PF_STATE_SYNPROXY;
4765 $$.options = $3;
4766 }
4767 ;
4768
4769 flush : /* empty */ { $$ = 0; }
4770 | FLUSH { $$ = PF_FLUSH; }
4771 | FLUSH GLOBAL {
4772 $$ = PF_FLUSH | PF_FLUSH_GLOBAL;
4773 }
4774 ;
4775
4776 state_opt_spec : '(' state_opt_list ')' { $$ = $2; }
4777 | /* empty */ { $$ = NULL; }
4778 ;
4779
4780 state_opt_list : state_opt_item { $$ = $1; }
4781 | state_opt_list comma state_opt_item {
4782 $1->tail->next = $3;
4783 $1->tail = $3;
4784 $$ = $1;
4785 }
4786 ;
4787
4788 state_opt_item : MAXIMUM NUMBER {
4789 if ($2 < 0 || $2 > UINT_MAX) {
4790 yyerror("only positive values permitted");
4791 YYERROR;
4792 }
4793 $$ = calloc(1, sizeof(struct node_state_opt));
4794 if ($$ == NULL)
4795 err(1, "state_opt_item: calloc");
4796 $$->type = PF_STATE_OPT_MAX;
4797 $$->data.max_states = $2;
4798 $$->next = NULL;
4799 $$->tail = $$;
4800 }
4801 | NOSYNC {
4802 $$ = calloc(1, sizeof(struct node_state_opt));
4803 if ($$ == NULL)
4804 err(1, "state_opt_item: calloc");
4805 $$->type = PF_STATE_OPT_NOSYNC;
4806 $$->next = NULL;
4807 $$->tail = $$;
4808 }
4809 | MAXSRCSTATES NUMBER {
4810 if ($2 < 0 || $2 > UINT_MAX) {
4811 yyerror("only positive values permitted");
4812 YYERROR;
4813 }
4814 $$ = calloc(1, sizeof(struct node_state_opt));
4815 if ($$ == NULL)
4816 err(1, "state_opt_item: calloc");
4817 $$->type = PF_STATE_OPT_MAX_SRC_STATES;
4818 $$->data.max_src_states = $2;
4819 $$->next = NULL;
4820 $$->tail = $$;
4821 }
4822 | MAXSRCCONN NUMBER {
4823 if ($2 < 0 || $2 > UINT_MAX) {
4824 yyerror("only positive values permitted");
4825 YYERROR;
4826 }
4827 $$ = calloc(1, sizeof(struct node_state_opt));
4828 if ($$ == NULL)
4829 err(1, "state_opt_item: calloc");
4830 $$->type = PF_STATE_OPT_MAX_SRC_CONN;
4831 $$->data.max_src_conn = $2;
4832 $$->next = NULL;
4833 $$->tail = $$;
4834 }
4835 | MAXSRCCONNRATE NUMBER '/' NUMBER {
4836 if ($2 < 0 || $2 > UINT_MAX ||
4837 $4 < 0 || $4 > UINT_MAX) {
4838 yyerror("only positive values permitted");
4839 YYERROR;
4840 }
4841 $$ = calloc(1, sizeof(struct node_state_opt));
4842 if ($$ == NULL)
4843 err(1, "state_opt_item: calloc");
4844 $$->type = PF_STATE_OPT_MAX_SRC_CONN_RATE;
4845 $$->data.max_src_conn_rate.limit = $2;
4846 $$->data.max_src_conn_rate.seconds = $4;
4847 $$->next = NULL;
4848 $$->tail = $$;
4849 }
4850 | OVERLOAD '<' STRING '>' flush {
4851 if (strlen($3) >= PF_TABLE_NAME_SIZE) {
4852 yyerror("table name '%s' too long", $3);
4853 free($3);
4854 YYERROR;
4855 }
4856 $$ = calloc(1, sizeof(struct node_state_opt));
4857 if ($$ == NULL)
4858 err(1, "state_opt_item: calloc");
4859 if (strlcpy($$->data.overload.tblname, $3,
4860 PF_TABLE_NAME_SIZE) >= PF_TABLE_NAME_SIZE)
4861 errx(1, "state_opt_item: strlcpy");
4862 free($3);
4863 $$->type = PF_STATE_OPT_OVERLOAD;
4864 $$->data.overload.flush = $5;
4865 $$->next = NULL;
4866 $$->tail = $$;
4867 }
4868 | MAXSRCNODES NUMBER {
4869 if ($2 < 0 || $2 > UINT_MAX) {
4870 yyerror("only positive values permitted");
4871 YYERROR;
4872 }
4873 $$ = calloc(1, sizeof(struct node_state_opt));
4874 if ($$ == NULL)
4875 err(1, "state_opt_item: calloc");
4876 $$->type = PF_STATE_OPT_MAX_SRC_NODES;
4877 $$->data.max_src_nodes = $2;
4878 $$->next = NULL;
4879 $$->tail = $$;
4880 }
4881 | sourcetrack {
4882 $$ = calloc(1, sizeof(struct node_state_opt));
4883 if ($$ == NULL)
4884 err(1, "state_opt_item: calloc");
4885 $$->type = PF_STATE_OPT_SRCTRACK;
4886 $$->data.src_track = $1;
4887 $$->next = NULL;
4888 $$->tail = $$;
4889 }
4890 | statelock {
4891 $$ = calloc(1, sizeof(struct node_state_opt));
4892 if ($$ == NULL)
4893 err(1, "state_opt_item: calloc");
4894 $$->type = PF_STATE_OPT_STATELOCK;
4895 $$->data.statelock = $1;
4896 $$->next = NULL;
4897 $$->tail = $$;
4898 }
4899 | SLOPPY {
4900 $$ = calloc(1, sizeof(struct node_state_opt));
4901 if ($$ == NULL)
4902 err(1, "state_opt_item: calloc");
4903 $$->type = PF_STATE_OPT_SLOPPY;
4904 $$->next = NULL;
4905 $$->tail = $$;
4906 }
4907 | PFLOW {
4908 $$ = calloc(1, sizeof(struct node_state_opt));
4909 if ($$ == NULL)
4910 err(1, "state_opt_item: calloc");
4911 $$->type = PF_STATE_OPT_PFLOW;
4912 $$->next = NULL;
4913 $$->tail = $$;
4914 }
4915 | ALLOW_RELATED {
4916 $$ = calloc(1, sizeof(struct node_state_opt));
4917 if ($$ == NULL)
4918 err(1, "state_opt_item: calloc");
4919 $$->type = PF_STATE_OPT_ALLOW_RELATED;
4920 $$->next = NULL;
4921 $$->tail = $$;
4922 }
4923 | STRING NUMBER {
4924 int i;
4925
4926 if ($2 < 0 || $2 > UINT_MAX) {
4927 yyerror("only positive values permitted");
4928 YYERROR;
4929 }
4930 for (i = 0; pf_timeouts[i].name &&
4931 strcmp(pf_timeouts[i].name, $1); ++i)
4932 ; /* nothing */
4933 if (!pf_timeouts[i].name) {
4934 yyerror("illegal timeout name %s", $1);
4935 free($1);
4936 YYERROR;
4937 }
4938 if (strchr(pf_timeouts[i].name, '.') == NULL) {
4939 yyerror("illegal state timeout %s", $1);
4940 free($1);
4941 YYERROR;
4942 }
4943 free($1);
4944 $$ = calloc(1, sizeof(struct node_state_opt));
4945 if ($$ == NULL)
4946 err(1, "state_opt_item: calloc");
4947 $$->type = PF_STATE_OPT_TIMEOUT;
4948 $$->data.timeout.number = pf_timeouts[i].timeout;
4949 $$->data.timeout.seconds = $2;
4950 $$->next = NULL;
4951 $$->tail = $$;
4952 }
4953 ;
4954
4955 label : LABEL STRING {
4956 $$ = $2;
4957 }
4958 ;
4959
4960 etherqname : QUEUE STRING {
4961 $$.qname = $2;
4962 }
4963 | QUEUE '(' STRING ')' {
4964 $$.qname = $3;
4965 }
4966 ;
4967
4968 qname : QUEUE STRING {
4969 $$.qname = $2;
4970 $$.pqname = NULL;
4971 }
4972 | QUEUE '(' STRING ')' {
4973 $$.qname = $3;
4974 $$.pqname = NULL;
4975 }
4976 | QUEUE '(' STRING comma STRING ')' {
4977 $$.qname = $3;
4978 $$.pqname = $5;
4979 }
4980 ;
4981
4982 no : /* empty */ { $$ = 0; }
4983 | NO { $$ = 1; }
4984 ;
4985
4986 portstar : numberstring {
4987 if (parseport($1, &$$, PPORT_RANGE|PPORT_STAR) == -1) {
4988 free($1);
4989 YYERROR;
4990 }
4991 free($1);
4992 }
4993 ;
4994
4995 redir_host : host { $$ = $1; }
4996 | '{' optnl redir_host_list '}' { $$ = $3; }
4997 ;
4998
4999 redir_host_list : host optnl { $$ = $1; }
5000 | redir_host_list comma host optnl {
5001 $1->tail->next = $3;
5002 $1->tail = $3->tail;
5003 $$ = $1;
5004 }
5005 ;
5006
5007 /* Redirection without port */
5008 no_port_redirspec: redir_host pool_opts {
5009 $$ = calloc(1, sizeof(struct redirspec));
5010 if ($$ == NULL)
5011 err(1, "redirspec: calloc");
5012 $$->host = $1;
5013 $$->pool_opts = $2;
5014 $$->rport.a = $$->rport.b = $$->rport.t = 0;
5015 }
5016 ;
5017
5018 /* Redirection with optional port */
5019 port_redirspec : no_port_redirspec;
5020 | redir_host PORT portstar pool_opts {
5021 $$ = calloc(1, sizeof(struct redirspec));
5022 if ($$ == NULL)
5023 err(1, "redirspec: calloc");
5024 $$->host = $1;
5025 $$->rport = $3;
5026 $$->pool_opts = $4;
5027 }
5028
5029 /* Redirection with an arrow and an optional port: FreeBSD NAT rules */
5030 nat_redirspec : /* empty */ { $$ = NULL; }
5031 | ARROW port_redirspec {
5032 $$ = $2;
5033 }
5034 ;
5035
5036 /* Redirection with interfaces and without ports: route-to rules */
5037 route_redirspec : routespec pool_opts {
5038 $$ = calloc(1, sizeof(struct redirspec));
5039 if ($$ == NULL)
5040 err(1, "redirspec: calloc");
5041 $$->host = $1;
5042 $$->pool_opts = $2;
5043 }
5044 ;
5045
5046 hashkey : /* empty */
5047 {
5048 $$ = calloc(1, sizeof(struct pf_poolhashkey));
5049 if ($$ == NULL)
5050 err(1, "hashkey: calloc");
5051 $$->key32[0] = arc4random();
5052 $$->key32[1] = arc4random();
5053 $$->key32[2] = arc4random();
5054 $$->key32[3] = arc4random();
5055 }
5056 | string
5057 {
5058 if (!strncmp($1, "0x", 2)) {
5059 if (strlen($1) != 34) {
5060 free($1);
5061 yyerror("hex key must be 128 bits "
5062 "(32 hex digits) long");
5063 YYERROR;
5064 }
5065 $$ = calloc(1, sizeof(struct pf_poolhashkey));
5066 if ($$ == NULL)
5067 err(1, "hashkey: calloc");
5068
5069 if (sscanf($1, "0x%8x%8x%8x%8x",
5070 &$$->key32[0], &$$->key32[1],
5071 &$$->key32[2], &$$->key32[3]) != 4) {
5072 free($$);
5073 free($1);
5074 yyerror("invalid hex key");
5075 YYERROR;
5076 }
5077 } else {
5078 MD5_CTX context;
5079
5080 $$ = calloc(1, sizeof(struct pf_poolhashkey));
5081 if ($$ == NULL)
5082 err(1, "hashkey: calloc");
5083 MD5Init(&context);
5084 MD5Update(&context, (unsigned char *)$1,
5085 strlen($1));
5086 MD5Final((unsigned char *)$$, &context);
5087 HTONL($$->key32[0]);
5088 HTONL($$->key32[1]);
5089 HTONL($$->key32[2]);
5090 HTONL($$->key32[3]);
5091 }
5092 free($1);
5093 }
5094 ;
5095
5096 pool_opts : { bzero(&pool_opts, sizeof pool_opts); }
5097 pool_opts_l
5098 { $$ = pool_opts; }
5099 | /* empty */ {
5100 bzero(&pool_opts, sizeof pool_opts);
5101 $$ = pool_opts;
5102 }
5103 ;
5104
5105 pool_opts_l : pool_opts_l pool_opt
5106 | pool_opt
5107 ;
5108
5109 pool_opt : BITMASK {
5110 if (pool_opts.type) {
5111 yyerror("pool type cannot be redefined");
5112 YYERROR;
5113 }
5114 pool_opts.type = PF_POOL_BITMASK;
5115 }
5116 | RANDOM {
5117 if (pool_opts.type) {
5118 yyerror("pool type cannot be redefined");
5119 YYERROR;
5120 }
5121 pool_opts.type = PF_POOL_RANDOM;
5122 }
5123 | SOURCEHASH hashkey {
5124 if (pool_opts.type) {
5125 yyerror("pool type cannot be redefined");
5126 YYERROR;
5127 }
5128 pool_opts.type = PF_POOL_SRCHASH;
5129 pool_opts.key = $2;
5130 }
5131 | ROUNDROBIN {
5132 if (pool_opts.type) {
5133 yyerror("pool type cannot be redefined");
5134 YYERROR;
5135 }
5136 pool_opts.type = PF_POOL_ROUNDROBIN;
5137 }
5138 | STATICPORT {
5139 if (pool_opts.staticport) {
5140 yyerror("static-port cannot be redefined");
5141 YYERROR;
5142 }
5143 pool_opts.staticport = 1;
5144 }
5145 | STICKYADDRESS {
5146 if (pool_opts.marker & POM_STICKYADDRESS) {
5147 yyerror("sticky-address cannot be redefined");
5148 YYERROR;
5149 }
5150 pool_opts.marker |= POM_STICKYADDRESS;
5151 pool_opts.opts |= PF_POOL_STICKYADDR;
5152 }
5153 | ENDPI {
5154 if (pool_opts.marker & POM_ENDPI) {
5155 yyerror("endpoint-independent cannot be redefined");
5156 YYERROR;
5157 }
5158 pool_opts.marker |= POM_ENDPI;
5159 pool_opts.opts |= PF_POOL_ENDPI;
5160 }
5161 | IPV6NH {
5162 if (pool_opts.marker & POM_IPV6NH) {
5163 yyerror("prefer-ipv6-nexthop cannot be redefined");
5164 YYERROR;
5165 }
5166 pool_opts.marker |= POM_IPV6NH;
5167 pool_opts.opts |= PF_POOL_IPV6NH;
5168 }
5169 | MAPEPORTSET number '/' number '/' number {
5170 if (pool_opts.mape.offset) {
5171 yyerror("map-e-portset cannot be redefined");
5172 YYERROR;
5173 }
5174 if (pool_opts.type) {
5175 yyerror("map-e-portset cannot be used with "
5176 "address pools");
5177 YYERROR;
5178 }
5179 if ($2 <= 0 || $2 >= 16) {
5180 yyerror("MAP-E PSID offset must be 1-15");
5181 YYERROR;
5182 }
5183 if ($4 < 0 || $4 >= 16 || $2 + $4 > 16) {
5184 yyerror("Invalid MAP-E PSID length");
5185 YYERROR;
5186 } else if ($4 == 0) {
5187 yyerror("PSID Length = 0: this means"
5188 " you do not need MAP-E");
5189 YYERROR;
5190 }
5191 if ($6 < 0 || $6 > 65535) {
5192 yyerror("Invalid MAP-E PSID");
5193 YYERROR;
5194 }
5195 pool_opts.mape.offset = $2;
5196 pool_opts.mape.psidlen = $4;
5197 pool_opts.mape.psid = $6;
5198 }
5199 ;
5200
5201 binat_redirspec : /* empty */ { $$ = NULL; }
5202 | ARROW host {
5203 $$ = calloc(1, sizeof(struct redirspec));
5204 if ($$ == NULL)
5205 err(1, "redirspec: calloc");
5206 $$->host = $2;
5207 $$->rport.a = $$->rport.b = $$->rport.t = 0;
5208 }
5209 | ARROW host PORT portstar {
5210 $$ = calloc(1, sizeof(struct redirspec));
5211 if ($$ == NULL)
5212 err(1, "redirspec: calloc");
5213 $$->host = $2;
5214 $$->rport = $4;
5215 }
5216 ;
5217
5218 natpasslog : /* empty */ { $$.b1 = $$.b2 = 0; $$.w2 = 0; }
5219 | PASS { $$.b1 = 1; $$.b2 = 0; $$.w2 = 0; }
5220 | PASS log { $$.b1 = 1; $$.b2 = $2.log; $$.w2 = $2.logif; }
5221 | log { $$.b1 = 0; $$.b2 = $1.log; $$.w2 = $1.logif; }
5222 ;
5223
5224 nataction : no NAT natpasslog {
5225 if ($1 && $3.b1) {
5226 yyerror("\"pass\" not valid with \"no\"");
5227 YYERROR;
5228 }
5229 if ($1)
5230 $$.b1 = PF_NONAT;
5231 else
5232 $$.b1 = PF_NAT;
5233 $$.b2 = $3.b1;
5234 $$.w = $3.b2;
5235 $$.w2 = $3.w2;
5236 }
5237 | no RDR natpasslog {
5238 if ($1 && $3.b1) {
5239 yyerror("\"pass\" not valid with \"no\"");
5240 YYERROR;
5241 }
5242 if ($1)
5243 $$.b1 = PF_NORDR;
5244 else
5245 $$.b1 = PF_RDR;
5246 $$.b2 = $3.b1;
5247 $$.w = $3.b2;
5248 $$.w2 = $3.w2;
5249 }
5250 ;
5251
5252 natrule : nataction interface af proto fromto tag tagged rtable
5253 nat_redirspec
5254 {
5255 struct pfctl_rule r;
5256 struct node_state_opt *o;
5257
5258 if (check_rulestate(PFCTL_STATE_NAT))
5259 YYERROR;
5260
5261 pfctl_init_rule(&r);
5262
5263 r.action = $1.b1;
5264 r.natpass = $1.b2;
5265 r.log = $1.w;
5266 r.logif = $1.w2;
5267 r.af = $3;
5268
5269 if (!r.af) {
5270 if ($5.src.host && $5.src.host->af &&
5271 !$5.src.host->ifindex)
5272 r.af = $5.src.host->af;
5273 else if ($5.dst.host && $5.dst.host->af &&
5274 !$5.dst.host->ifindex)
5275 r.af = $5.dst.host->af;
5276 }
5277
5278 if ($6 != NULL)
5279 if (strlcpy(r.tagname, $6, PF_TAG_NAME_SIZE) >=
5280 PF_TAG_NAME_SIZE) {
5281 yyerror("tag too long, max %u chars",
5282 PF_TAG_NAME_SIZE - 1);
5283 YYERROR;
5284 }
5285
5286 if ($7.name)
5287 if (strlcpy(r.match_tagname, $7.name,
5288 PF_TAG_NAME_SIZE) >= PF_TAG_NAME_SIZE) {
5289 yyerror("tag too long, max %u chars",
5290 PF_TAG_NAME_SIZE - 1);
5291 YYERROR;
5292 }
5293 r.match_tag_not = $7.neg;
5294 r.rtableid = $8;
5295
5296 if (r.action == PF_NONAT || r.action == PF_NORDR) {
5297 if ($9 != NULL) {
5298 yyerror("translation rule with 'no' "
5299 "does not need '->'");
5300 YYERROR;
5301 }
5302 } else {
5303 if ($9 == NULL || $9->host == NULL) {
5304 yyerror("translation rule requires '-> "
5305 "address'");
5306 YYERROR;
5307 }
5308 if ($9->pool_opts.opts & PF_POOL_IPV6NH) {
5309 yyerror("The prefer-ipv6-nexthop option "
5310 "can't be used for nat/rdr/binat pools"
5311 );
5312 YYERROR;
5313 }
5314 if (!r.af && ! $9->host->ifindex)
5315 r.af = $9->host->af;
5316
5317 remove_invalid_hosts(&$9->host, &r.af);
5318 if (invalid_redirect($9->host, r.af))
5319 YYERROR;
5320 if ($9->host->addr.type == PF_ADDR_DYNIFTL) {
5321 if (($9->host = gen_dynnode($9->host, r.af)) == NULL)
5322 err(1, "calloc");
5323 }
5324 if (check_netmask($9->host, r.af))
5325 YYERROR;
5326 }
5327
5328 o = keep_state_defaults;
5329 while (o) {
5330 switch (o->type) {
5331 case PF_STATE_OPT_PFLOW:
5332 if (r.rule_flag & PFRULE_PFLOW) {
5333 yyerror("state pflow option: "
5334 "multiple definitions");
5335 YYERROR;
5336 }
5337 r.rule_flag |= PFRULE_PFLOW;
5338 break;
5339 }
5340 o = o->next;
5341 }
5342
5343 expand_rule(&r, false, $2, NULL, $9, NULL, $4,
5344 $5.src_os, $5.src.host, $5.src.port, $5.dst.host,
5345 $5.dst.port, 0, 0, 0, 0);
5346 }
5347 ;
5348
5349 binatrule : no BINAT natpasslog interface af proto FROM ipspec toipspec tag
5350 tagged rtable binat_redirspec
5351 {
5352 struct pfctl_rule binat;
5353 struct pfctl_pooladdr *pa;
5354
5355 if (check_rulestate(PFCTL_STATE_NAT))
5356 YYERROR;
5357 if (disallow_urpf_failed($9, "\"urpf-failed\" is not "
5358 "permitted as a binat destination"))
5359 YYERROR;
5360
5361 pfctl_init_rule(&binat);
5362
5363 if ($1 && $3.b1) {
5364 yyerror("\"pass\" not valid with \"no\"");
5365 YYERROR;
5366 }
5367 if ($1)
5368 binat.action = PF_NOBINAT;
5369 else
5370 binat.action = PF_BINAT;
5371 binat.natpass = $3.b1;
5372 binat.log = $3.b2;
5373 binat.logif = $3.w2;
5374 binat.af = $5;
5375 if (!binat.af && $8 != NULL && $8->af)
5376 binat.af = $8->af;
5377 if (!binat.af && $9 != NULL && $9->af)
5378 binat.af = $9->af;
5379
5380 if (!binat.af && $13 != NULL && $13->host)
5381 binat.af = $13->host->af;
5382 if (!binat.af) {
5383 yyerror("address family (inet/inet6) "
5384 "undefined");
5385 YYERROR;
5386 }
5387
5388 if ($4 != NULL) {
5389 memcpy(binat.ifname, $4->ifname,
5390 sizeof(binat.ifname));
5391 binat.ifnot = $4->not;
5392 free($4);
5393 }
5394
5395 if ($10 != NULL)
5396 if (strlcpy(binat.tagname, $10,
5397 PF_TAG_NAME_SIZE) >= PF_TAG_NAME_SIZE) {
5398 yyerror("tag too long, max %u chars",
5399 PF_TAG_NAME_SIZE - 1);
5400 YYERROR;
5401 }
5402 if ($11.name)
5403 if (strlcpy(binat.match_tagname, $11.name,
5404 PF_TAG_NAME_SIZE) >= PF_TAG_NAME_SIZE) {
5405 yyerror("tag too long, max %u chars",
5406 PF_TAG_NAME_SIZE - 1);
5407 YYERROR;
5408 }
5409 binat.match_tag_not = $11.neg;
5410 binat.rtableid = $12;
5411
5412 if ($6 != NULL) {
5413 binat.proto = $6->proto;
5414 free($6);
5415 }
5416
5417 if ($8 != NULL && disallow_table($8, "invalid use of "
5418 "table <%s> as the source address of a binat rule"))
5419 YYERROR;
5420 if ($8 != NULL && disallow_alias($8, "invalid use of "
5421 "interface (%s) as the source address of a binat "
5422 "rule"))
5423 YYERROR;
5424 if ($13 != NULL && $13->host != NULL && disallow_table(
5425 $13->host, "invalid use of table <%s> as the "
5426 "redirect address of a binat rule"))
5427 YYERROR;
5428 if ($13 != NULL && $13->host != NULL && disallow_alias(
5429 $13->host, "invalid use of interface (%s) as the "
5430 "redirect address of a binat rule"))
5431 YYERROR;
5432
5433 if ($8 != NULL) {
5434 if ($8->next) {
5435 yyerror("multiple binat ip addresses");
5436 YYERROR;
5437 }
5438 if ($8->addr.type == PF_ADDR_DYNIFTL)
5439 $8->af = binat.af;
5440 if ($8->af != binat.af) {
5441 yyerror("binat ip versions must match");
5442 YYERROR;
5443 }
5444 if ($8->addr.type == PF_ADDR_DYNIFTL) {
5445 if (($8 = gen_dynnode($8, binat.af)) == NULL)
5446 err(1, "calloc");
5447 }
5448 if (check_netmask($8, binat.af))
5449 YYERROR;
5450 memcpy(&binat.src.addr, &$8->addr,
5451 sizeof(binat.src.addr));
5452 free($8);
5453 }
5454 if ($9 != NULL) {
5455 if ($9->next) {
5456 yyerror("multiple binat ip addresses");
5457 YYERROR;
5458 }
5459 if ($9->af != binat.af && $9->af) {
5460 yyerror("binat ip versions must match");
5461 YYERROR;
5462 }
5463 if ($9->addr.type == PF_ADDR_DYNIFTL) {
5464 if (($9 = gen_dynnode($9, binat.af)) == NULL)
5465 err(1, "calloc");
5466 }
5467 if (check_netmask($9, binat.af))
5468 YYERROR;
5469 memcpy(&binat.dst.addr, &$9->addr,
5470 sizeof(binat.dst.addr));
5471 binat.dst.neg = $9->not;
5472 free($9);
5473 }
5474
5475 if (binat.action == PF_NOBINAT) {
5476 if ($13 != NULL) {
5477 yyerror("'no binat' rule does not need"
5478 " '->'");
5479 YYERROR;
5480 }
5481 } else {
5482 if ($13 == NULL || $13->host == NULL) {
5483 yyerror("'binat' rule requires"
5484 " '-> address'");
5485 YYERROR;
5486 }
5487
5488 remove_invalid_hosts(&$13->host, &binat.af);
5489 if (invalid_redirect($13->host, binat.af))
5490 YYERROR;
5491 if ($13->host->next != NULL) {
5492 yyerror("binat rule must redirect to "
5493 "a single address");
5494 YYERROR;
5495 }
5496 if ($13->host->addr.type == PF_ADDR_DYNIFTL) {
5497 if (($13->host = gen_dynnode($13->host, binat.af)) == NULL)
5498 err(1, "calloc");
5499 }
5500 if (check_netmask($13->host, binat.af))
5501 YYERROR;
5502
5503 if (!PF_AZERO(&binat.src.addr.v.a.mask,
5504 binat.af) &&
5505 !PF_AEQ(&binat.src.addr.v.a.mask,
5506 &$13->host->addr.v.a.mask, binat.af)) {
5507 yyerror("'binat' source mask and "
5508 "redirect mask must be the same");
5509 YYERROR;
5510 }
5511
5512 pa = calloc(1, sizeof(struct pfctl_pooladdr));
5513 if (pa == NULL)
5514 err(1, "binat: calloc");
5515 pa->addr = $13->host->addr;
5516 pa->ifname[0] = 0;
5517 pa->af = $13->host->af;
5518 TAILQ_INSERT_TAIL(&binat.rdr.list,
5519 pa, entries);
5520
5521 free($13);
5522 }
5523
5524 pfctl_append_rule(pf, &binat);
5525 }
5526 ;
5527
5528 tag : /* empty */ { $$ = NULL; }
5529 | TAG STRING { $$ = $2; }
5530 ;
5531
5532 tagged : /* empty */ { $$.neg = 0; $$.name = NULL; }
5533 | not TAGGED string { $$.neg = $1; $$.name = $3; }
5534 ;
5535
5536 rtable : /* empty */ { $$ = -1; }
5537 | RTABLE NUMBER {
5538 if ($2 < 0 || $2 > rt_tableid_max()) {
5539 yyerror("invalid rtable id");
5540 YYERROR;
5541 }
5542 $$ = $2;
5543 }
5544 ;
5545
5546 route_host : STRING {
5547 $$ = calloc(1, sizeof(struct node_host));
5548 if ($$ == NULL)
5549 err(1, "route_host: calloc");
5550 if (strlen($1) >= IFNAMSIZ) {
5551 yyerror("interface name too long");
5552 YYERROR;
5553 }
5554 $$->ifname = strdup($1);
5555 set_ipmask($$, 128);
5556 $$->next = NULL;
5557 $$->tail = $$;
5558 }
5559 | '(' STRING host ')' {
5560 struct node_host *n;
5561
5562 $$ = $3;
5563 for (n = $3; n != NULL; n = n->next) {
5564 if (strlen($2) >= IFNAMSIZ) {
5565 yyerror("interface name too long");
5566 YYERROR;
5567 }
5568 n->ifname = strdup($2);
5569 }
5570 }
5571 ;
5572
5573 route_host_list : route_host optnl { $$ = $1; }
5574 | route_host_list comma route_host optnl {
5575 $1->tail->next = $3;
5576 $1->tail = $3->tail;
5577 $$ = $1;
5578 }
5579 ;
5580
5581 routespec : route_host { $$ = $1; }
5582 | '{' optnl route_host_list '}' { $$ = $3; }
5583 ;
5584
5585 route : /* empty */ {
5586 $$.rt = PF_NOPFROUTE;
5587 }
5588 | FASTROUTE {
5589 /* backwards-compat */
5590 $$.rt = PF_NOPFROUTE;
5591 }
5592 | ROUTETO route_redirspec {
5593 $$.rt = PF_ROUTETO;
5594 $$.redirspec = $2;
5595 }
5596 | REPLYTO route_redirspec {
5597 $$.rt = PF_REPLYTO;
5598 $$.redirspec = $2;
5599 }
5600 | DUPTO route_redirspec {
5601 $$.rt = PF_DUPTO;
5602 $$.redirspec = $2;
5603 }
5604 ;
5605
5606 timeout_spec : STRING NUMBER
5607 {
5608 if (check_rulestate(PFCTL_STATE_OPTION)) {
5609 free($1);
5610 YYERROR;
5611 }
5612 if ($2 < 0 || $2 > UINT_MAX) {
5613 yyerror("only positive values permitted");
5614 YYERROR;
5615 }
5616 if (pfctl_apply_timeout(pf, $1, $2, 0) != 0) {
5617 yyerror("unknown timeout %s", $1);
5618 free($1);
5619 YYERROR;
5620 }
5621 free($1);
5622 }
5623 | INTERVAL NUMBER {
5624 if (check_rulestate(PFCTL_STATE_OPTION))
5625 YYERROR;
5626 if ($2 < 0 || $2 > UINT_MAX) {
5627 yyerror("only positive values permitted");
5628 YYERROR;
5629 }
5630 if (pfctl_apply_timeout(pf, "interval", $2, 0) != 0)
5631 YYERROR;
5632 }
5633 ;
5634
5635 timeout_list : timeout_list comma timeout_spec optnl
5636 | timeout_spec optnl
5637 ;
5638
5639 limit_spec : STRING NUMBER
5640 {
5641 if (check_rulestate(PFCTL_STATE_OPTION)) {
5642 free($1);
5643 YYERROR;
5644 }
5645 if ($2 < 0 || $2 > UINT_MAX) {
5646 yyerror("only positive values permitted");
5647 YYERROR;
5648 }
5649 if (pfctl_apply_limit(pf, $1, $2) != 0) {
5650 yyerror("unable to set limit %s %u", $1, $2);
5651 free($1);
5652 YYERROR;
5653 }
5654 free($1);
5655 }
5656 ;
5657
5658 limit_list : limit_list comma limit_spec optnl
5659 | limit_spec optnl
5660 ;
5661
5662 comma : ','
5663 | /* empty */
5664 ;
5665
5666 yesno : NO { $$ = 0; }
5667 | STRING {
5668 if (!strcmp($1, "yes"))
5669 $$ = 1;
5670 else {
5671 yyerror("invalid value '%s', expected 'yes' "
5672 "or 'no'", $1);
5673 free($1);
5674 YYERROR;
5675 }
5676 free($1);
5677 }
5678 ;
5679
5680 unaryop : '=' { $$ = PF_OP_EQ; }
5681 | NE { $$ = PF_OP_NE; }
5682 | LE { $$ = PF_OP_LE; }
5683 | '<' { $$ = PF_OP_LT; }
5684 | GE { $$ = PF_OP_GE; }
5685 | '>' { $$ = PF_OP_GT; }
5686 ;
5687
5688 %%
5689
5690 int
5691 yyerror(const char *fmt, ...)
5692 {
5693 va_list ap;
5694
5695 file->errors++;
5696 va_start(ap, fmt);
5697 fprintf(stderr, "%s:%d: ", file->name, yylval.lineno);
5698 vfprintf(stderr, fmt, ap);
5699 fprintf(stderr, "\n");
5700 va_end(ap);
5701 return (0);
5702 }
5703
5704 int
validate_range(uint8_t op,uint16_t p1,uint16_t p2)5705 validate_range(uint8_t op, uint16_t p1, uint16_t p2)
5706 {
5707 uint16_t a = ntohs(p1);
5708 uint16_t b = ntohs(p2);
5709
5710 if ((op == PF_OP_RRG && a > b) || /* 34:12, i.e. none */
5711 (op == PF_OP_IRG && a >= b) || /* 34><12, i.e. none */
5712 (op == PF_OP_XRG && a > b)) /* 34<>22, i.e. all */
5713 return 1;
5714 return 0;
5715 }
5716
5717 int
disallow_table(struct node_host * h,const char * fmt)5718 disallow_table(struct node_host *h, const char *fmt)
5719 {
5720 for (; h != NULL; h = h->next)
5721 if (h->addr.type == PF_ADDR_TABLE) {
5722 yyerror(fmt, h->addr.v.tblname);
5723 return (1);
5724 }
5725 return (0);
5726 }
5727
5728 int
disallow_urpf_failed(struct node_host * h,const char * fmt)5729 disallow_urpf_failed(struct node_host *h, const char *fmt)
5730 {
5731 for (; h != NULL; h = h->next)
5732 if (h->addr.type == PF_ADDR_URPFFAILED) {
5733 yyerror(fmt);
5734 return (1);
5735 }
5736 return (0);
5737 }
5738
5739 int
disallow_alias(struct node_host * h,const char * fmt)5740 disallow_alias(struct node_host *h, const char *fmt)
5741 {
5742 for (; h != NULL; h = h->next)
5743 if (DYNIF_MULTIADDR(h->addr)) {
5744 yyerror(fmt, h->addr.v.tblname);
5745 return (1);
5746 }
5747 return (0);
5748 }
5749
5750 int
rule_consistent(struct pfctl_rule * r)5751 rule_consistent(struct pfctl_rule *r)
5752 {
5753 int problems = 0;
5754
5755 switch (r->action) {
5756 case PF_PASS:
5757 case PF_MATCH:
5758 case PF_DROP:
5759 case PF_SCRUB:
5760 case PF_NOSCRUB:
5761 problems = filter_consistent(r);
5762 break;
5763 case PF_NAT:
5764 case PF_NONAT:
5765 problems = nat_consistent(r);
5766 break;
5767 case PF_RDR:
5768 case PF_NORDR:
5769 problems = rdr_consistent(r);
5770 break;
5771 case PF_BINAT:
5772 case PF_NOBINAT:
5773 default:
5774 break;
5775 }
5776 return (problems);
5777 }
5778
5779 int
filter_consistent(struct pfctl_rule * r)5780 filter_consistent(struct pfctl_rule *r)
5781 {
5782 int problems = 0;
5783
5784 if (r->proto != IPPROTO_TCP && r->proto != IPPROTO_UDP &&
5785 r->proto != IPPROTO_SCTP &&
5786 (r->src.port_op || r->dst.port_op)) {
5787 yyerror("port only applies to tcp/udp/sctp");
5788 problems++;
5789 }
5790 if (r->proto != IPPROTO_ICMP && r->proto != IPPROTO_ICMPV6 &&
5791 (r->type || r->code)) {
5792 yyerror("icmp-type/code only applies to icmp");
5793 problems++;
5794 }
5795 if (!r->af && (r->type || r->code)) {
5796 yyerror("must indicate address family with icmp-type/code");
5797 problems++;
5798 }
5799 if (r->rule_flag & PFRULE_AFTO && r->af == r->naf) {
5800 yyerror("must indicate different address family with af-to");
5801 problems++;
5802 }
5803 if (r->overload_tblname[0] &&
5804 r->max_src_conn == 0 && r->max_src_conn_rate.seconds == 0) {
5805 yyerror("'overload' requires 'max-src-conn' "
5806 "or 'max-src-conn-rate'");
5807 problems++;
5808 }
5809 if ((r->proto == IPPROTO_ICMP && r->af == AF_INET6) ||
5810 (r->proto == IPPROTO_ICMPV6 && r->af == AF_INET)) {
5811 yyerror("proto %s doesn't match address family %s",
5812 r->proto == IPPROTO_ICMP ? "icmp" : "icmp6",
5813 r->af == AF_INET ? "inet" : "inet6");
5814 problems++;
5815 }
5816 if (r->allow_opts && r->action != PF_PASS && r->action != PF_MATCH) {
5817 yyerror("allow-opts can only be specified for pass or "
5818 "match rules");
5819 problems++;
5820 }
5821 if (r->rule_flag & PFRULE_FRAGMENT && (r->src.port_op ||
5822 r->dst.port_op || r->flagset || r->type || r->code)) {
5823 yyerror("fragments can be filtered only on IP header fields");
5824 problems++;
5825 }
5826 if (r->rule_flag & PFRULE_RETURNRST && r->proto != IPPROTO_TCP) {
5827 yyerror("return-rst can only be applied to TCP rules");
5828 problems++;
5829 }
5830 if (r->max_src_nodes && !(r->rule_flag & PFRULE_RULESRCTRACK)) {
5831 yyerror("max-src-nodes requires 'source-track rule'");
5832 problems++;
5833 }
5834 if (r->action != PF_PASS && r->keep_state) {
5835 yyerror("keep state is great, but only for pass rules");
5836 problems++;
5837 }
5838 if (r->rule_flag & PFRULE_STATESLOPPY &&
5839 (r->keep_state == PF_STATE_MODULATE ||
5840 r->keep_state == PF_STATE_SYNPROXY)) {
5841 yyerror("sloppy state matching cannot be used with "
5842 "synproxy state or modulate state");
5843 problems++;
5844 }
5845 if ((r->keep_state == PF_STATE_SYNPROXY) && (r->direction != PF_IN))
5846 fprintf(stderr, "%s:%d: warning: "
5847 "synproxy used for inbound rules only, "
5848 "ignored for outbound\n", file->name, yylval.lineno);
5849 if (r->rule_flag & PFRULE_AFTO && r->rt) {
5850 if (r->rt != PF_ROUTETO && r->rt != PF_REPLYTO) {
5851 yyerror("dup-to "
5852 "must not be used on af-to rules");
5853 problems++;
5854 }
5855 }
5856 /* Basic rule sanity check. */
5857 switch (r->action) {
5858 case PF_MATCH:
5859 if (r->divert.port) {
5860 yyerror("divert is not supported on match rules");
5861 problems++;
5862 }
5863 if (r->rt) {
5864 yyerror("route-to, reply-to, dup-to and fastroute "
5865 "must not be used on match rules");
5866 problems++;
5867 }
5868 if (r->rule_flag & PFRULE_AFTO) {
5869 yyerror("af-to is not supported on match rules");
5870 problems++;
5871 }
5872 break;
5873 case PF_DROP:
5874 if (r->rt) {
5875 yyerror("route-to, reply-to and dup-to "
5876 "are not supported on block rules");
5877 problems++;
5878 }
5879 break;
5880 default:;
5881 }
5882 if (!TAILQ_EMPTY(&(r->nat.list)) || !TAILQ_EMPTY(&(r->rdr.list))) {
5883 if (r->action != PF_MATCH && !r->keep_state) {
5884 yyerror("nat-to and rdr-to require keep state");
5885 problems++;
5886 }
5887 if (r->direction == PF_INOUT) {
5888 yyerror("nat-to and rdr-to require a direction");
5889 problems++;
5890 }
5891 }
5892 if (r->route.opts & PF_POOL_STICKYADDR && !r->keep_state) {
5893 yyerror("'sticky-address' requires 'keep state'");
5894 }
5895 return (-problems);
5896 }
5897
5898 int
nat_consistent(struct pfctl_rule * r)5899 nat_consistent(struct pfctl_rule *r)
5900 {
5901 return (0); /* yeah! */
5902 }
5903
5904 int
rdr_consistent(struct pfctl_rule * r)5905 rdr_consistent(struct pfctl_rule *r)
5906 {
5907 int problems = 0;
5908
5909 if (r->proto != IPPROTO_TCP && r->proto != IPPROTO_UDP &&
5910 r->proto != IPPROTO_SCTP) {
5911 if (r->src.port_op) {
5912 yyerror("src port only applies to tcp/udp/sctp");
5913 problems++;
5914 }
5915 if (r->dst.port_op) {
5916 yyerror("dst port only applies to tcp/udp/sctp");
5917 problems++;
5918 }
5919 if (r->rdr.proxy_port[0]) {
5920 yyerror("rdr port only applies to tcp/udp/sctp");
5921 problems++;
5922 }
5923 }
5924 if (r->dst.port_op &&
5925 r->dst.port_op != PF_OP_EQ && r->dst.port_op != PF_OP_RRG) {
5926 yyerror("invalid port operator for rdr destination port");
5927 problems++;
5928 }
5929 return (-problems);
5930 }
5931
5932 int
process_tabledef(char * name,struct table_opts * opts,int popts)5933 process_tabledef(char *name, struct table_opts *opts, int popts)
5934 {
5935 struct pfr_buffer ab;
5936 struct node_tinit *ti;
5937 struct pfr_uktable *ukt;
5938 unsigned long maxcount;
5939 size_t s = sizeof(maxcount);
5940
5941 bzero(&ab, sizeof(ab));
5942 ab.pfrb_type = PFRB_ADDRS;
5943 SIMPLEQ_FOREACH(ti, &opts->init_nodes, entries) {
5944 if (ti->file)
5945 if (pfr_buf_load(&ab, ti->file, 0, append_addr, popts)) {
5946 if (errno)
5947 yyerror("cannot load \"%s\": %s",
5948 ti->file, strerror(errno));
5949 else
5950 yyerror("file \"%s\" contains bad data",
5951 ti->file);
5952 goto _error;
5953 }
5954 if (ti->host)
5955 if (append_addr_host(&ab, ti->host, 0, 0)) {
5956 yyerror("cannot create address buffer: %s",
5957 strerror(errno));
5958 goto _error;
5959 }
5960 }
5961 if (pf->opts & PF_OPT_VERBOSE)
5962 print_tabledef(name, opts->flags, opts->init_addr,
5963 &opts->init_nodes);
5964 if (!(pf->opts & PF_OPT_NOACTION) ||
5965 (pf->opts & PF_OPT_DUMMYACTION))
5966 warn_duplicate_tables(name, pf->anchor->path);
5967 else if (pf->opts & PF_OPT_VERBOSE)
5968 fprintf(stderr, "%s:%d: skipping duplicate table checks"
5969 " for <%s>\n", file->name, yylval.lineno, name);
5970 /*
5971 * postpone definition of non-root tables to moment
5972 * when path is fully resolved.
5973 */
5974 if (pf->asd > 0) {
5975 ukt = calloc(1, sizeof(struct pfr_uktable));
5976 if (ukt == NULL) {
5977 DBGPRINT(
5978 "%s:%d: not enough memory for <%s>\n", file->name,
5979 yylval.lineno, name);
5980 goto _error;
5981 }
5982 } else
5983 ukt = NULL;
5984 if (!(pf->opts & PF_OPT_NOACTION) &&
5985 pfctl_define_table(name, opts->flags, opts->init_addr,
5986 pf->anchor->path, &ab, pf->anchor->ruleset.tticket, ukt)) {
5987
5988 if (sysctlbyname("net.pf.request_maxcount", &maxcount, &s,
5989 NULL, 0) == -1)
5990 maxcount = 65535;
5991
5992 if (ab.pfrb_size > maxcount)
5993 yyerror("cannot define table %s: too many elements.\n"
5994 "Consider increasing net.pf.request_maxcount.",
5995 name);
5996 else
5997 yyerror("cannot define table %s: %s", name,
5998 pf_strerror(errno));
5999
6000 goto _error;
6001 }
6002
6003 if (ukt != NULL) {
6004 ukt->pfrukt_init_addr = opts->init_addr;
6005 if (RB_INSERT(pfr_ktablehead, &pfr_ktables,
6006 &ukt->pfrukt_kt) != NULL) {
6007 /*
6008 * I think this should not happen, because
6009 * pfctl_define_table() above does the same check
6010 * effectively.
6011 */
6012 DBGPRINT(
6013 "%s:%d table %s already exists in %s\n",
6014 file->name, yylval.lineno,
6015 ukt->pfrukt_name, pf->anchor->path);
6016 free(ukt);
6017 goto _error;
6018 }
6019 DBGPRINT("%s %s@%s inserted to tree\n",
6020 __func__, ukt->pfrukt_name, pf->anchor->path);
6021 } else
6022 DBGPRINT("%s ukt is null\n", __func__);
6023
6024 pf->tdirty = 1;
6025 pfr_buf_clear(&ab);
6026 return (0);
6027 _error:
6028 pfr_buf_clear(&ab);
6029 return (-1);
6030 }
6031
6032 struct keywords {
6033 const char *k_name;
6034 int k_val;
6035 };
6036
6037 /* macro gore, but you should've seen the prior indentation nightmare... */
6038
6039 #define FREE_LIST(T,r) \
6040 do { \
6041 T *p, *node = r; \
6042 while (node != NULL) { \
6043 p = node; \
6044 node = node->next; \
6045 free(p); \
6046 } \
6047 } while (0)
6048
6049 #define LOOP_THROUGH(T,n,r,C) \
6050 do { \
6051 T *n; \
6052 if (r == NULL) { \
6053 r = calloc(1, sizeof(T)); \
6054 if (r == NULL) \
6055 err(1, "LOOP: calloc"); \
6056 r->next = NULL; \
6057 } \
6058 n = r; \
6059 while (n != NULL) { \
6060 do { \
6061 C; \
6062 } while (0); \
6063 n = n->next; \
6064 } \
6065 } while (0)
6066
6067 void
expand_label_str(char * label,size_t len,const char * srch,const char * repl)6068 expand_label_str(char *label, size_t len, const char *srch, const char *repl)
6069 {
6070 char *tmp;
6071 char *p, *q;
6072
6073 if ((tmp = calloc(1, len)) == NULL)
6074 err(1, "%s: calloc", __func__);
6075 p = q = label;
6076 while ((q = strstr(p, srch)) != NULL) {
6077 *q = '\0';
6078 if ((strlcat(tmp, p, len) >= len) ||
6079 (strlcat(tmp, repl, len) >= len))
6080 errx(1, "%s: label too long", __func__);
6081 q += strlen(srch);
6082 p = q;
6083 }
6084 if (strlcat(tmp, p, len) >= len)
6085 errx(1, "%s: label too long", __func__);
6086 strlcpy(label, tmp, len); /* always fits */
6087 free(tmp);
6088 }
6089
6090 void
expand_label_if(const char * name,char * label,size_t len,const char * ifname)6091 expand_label_if(const char *name, char *label, size_t len, const char *ifname)
6092 {
6093 if (strstr(label, name) != NULL) {
6094 if (!*ifname)
6095 expand_label_str(label, len, name, "any");
6096 else
6097 expand_label_str(label, len, name, ifname);
6098 }
6099 }
6100
6101 void
expand_label_addr(const char * name,char * label,size_t len,sa_family_t af,struct pf_rule_addr * addr)6102 expand_label_addr(const char *name, char *label, size_t len, sa_family_t af,
6103 struct pf_rule_addr *addr)
6104 {
6105 char tmp[64], tmp_not[66];
6106
6107 if (strstr(label, name) != NULL) {
6108 switch (addr->addr.type) {
6109 case PF_ADDR_DYNIFTL:
6110 snprintf(tmp, sizeof(tmp), "(%s)", addr->addr.v.ifname);
6111 break;
6112 case PF_ADDR_TABLE:
6113 snprintf(tmp, sizeof(tmp), "<%s>", addr->addr.v.tblname);
6114 break;
6115 case PF_ADDR_NOROUTE:
6116 snprintf(tmp, sizeof(tmp), "no-route");
6117 break;
6118 case PF_ADDR_URPFFAILED:
6119 snprintf(tmp, sizeof(tmp), "urpf-failed");
6120 break;
6121 case PF_ADDR_ADDRMASK:
6122 if (!af || (PF_AZERO(&addr->addr.v.a.addr, af) &&
6123 PF_AZERO(&addr->addr.v.a.mask, af)))
6124 snprintf(tmp, sizeof(tmp), "any");
6125 else {
6126 char a[48];
6127 int bits;
6128
6129 if (inet_ntop(af, &addr->addr.v.a.addr, a,
6130 sizeof(a)) == NULL)
6131 snprintf(tmp, sizeof(tmp), "?");
6132 else {
6133 bits = unmask(&addr->addr.v.a.mask);
6134 if ((af == AF_INET && bits < 32) ||
6135 (af == AF_INET6 && bits < 128))
6136 snprintf(tmp, sizeof(tmp),
6137 "%s/%d", a, bits);
6138 else
6139 snprintf(tmp, sizeof(tmp),
6140 "%s", a);
6141 }
6142 }
6143 break;
6144 default:
6145 snprintf(tmp, sizeof(tmp), "?");
6146 break;
6147 }
6148
6149 if (addr->neg) {
6150 snprintf(tmp_not, sizeof(tmp_not), "! %s", tmp);
6151 expand_label_str(label, len, name, tmp_not);
6152 } else
6153 expand_label_str(label, len, name, tmp);
6154 }
6155 }
6156
6157 void
expand_label_port(const char * name,char * label,size_t len,struct pf_rule_addr * addr)6158 expand_label_port(const char *name, char *label, size_t len,
6159 struct pf_rule_addr *addr)
6160 {
6161 char a1[6], a2[6], op[13] = "";
6162
6163 if (strstr(label, name) != NULL) {
6164 snprintf(a1, sizeof(a1), "%u", ntohs(addr->port[0]));
6165 snprintf(a2, sizeof(a2), "%u", ntohs(addr->port[1]));
6166 if (!addr->port_op)
6167 ;
6168 else if (addr->port_op == PF_OP_IRG)
6169 snprintf(op, sizeof(op), "%s><%s", a1, a2);
6170 else if (addr->port_op == PF_OP_XRG)
6171 snprintf(op, sizeof(op), "%s<>%s", a1, a2);
6172 else if (addr->port_op == PF_OP_EQ)
6173 snprintf(op, sizeof(op), "%s", a1);
6174 else if (addr->port_op == PF_OP_NE)
6175 snprintf(op, sizeof(op), "!=%s", a1);
6176 else if (addr->port_op == PF_OP_LT)
6177 snprintf(op, sizeof(op), "<%s", a1);
6178 else if (addr->port_op == PF_OP_LE)
6179 snprintf(op, sizeof(op), "<=%s", a1);
6180 else if (addr->port_op == PF_OP_GT)
6181 snprintf(op, sizeof(op), ">%s", a1);
6182 else if (addr->port_op == PF_OP_GE)
6183 snprintf(op, sizeof(op), ">=%s", a1);
6184 expand_label_str(label, len, name, op);
6185 }
6186 }
6187
6188 void
expand_label_proto(const char * name,char * label,size_t len,u_int8_t proto)6189 expand_label_proto(const char *name, char *label, size_t len, u_int8_t proto)
6190 {
6191 const char *protoname;
6192 char n[4];
6193
6194 if (strstr(label, name) != NULL) {
6195 protoname = pfctl_proto2name(proto);
6196 if (protoname != NULL)
6197 expand_label_str(label, len, name, protoname);
6198 else {
6199 snprintf(n, sizeof(n), "%u", proto);
6200 expand_label_str(label, len, name, n);
6201 }
6202 }
6203 }
6204
6205 void
expand_label_nr(const char * name,char * label,size_t len,struct pfctl_rule * r)6206 expand_label_nr(const char *name, char *label, size_t len,
6207 struct pfctl_rule *r)
6208 {
6209 char n[11];
6210
6211 if (strstr(label, name) != NULL) {
6212 snprintf(n, sizeof(n), "%u", r->nr);
6213 expand_label_str(label, len, name, n);
6214 }
6215 }
6216
6217 void
expand_label(char * label,size_t len,struct pfctl_rule * r)6218 expand_label(char *label, size_t len, struct pfctl_rule *r)
6219 {
6220 expand_label_if("$if", label, len, r->ifname);
6221 expand_label_addr("$srcaddr", label, len, r->af, &r->src);
6222 expand_label_addr("$dstaddr", label, len, r->af, &r->dst);
6223 expand_label_port("$srcport", label, len, &r->src);
6224 expand_label_port("$dstport", label, len, &r->dst);
6225 expand_label_proto("$proto", label, len, r->proto);
6226 expand_label_nr("$nr", label, len, r);
6227 }
6228
6229 int
expand_altq(struct pf_altq * a,struct node_if * interfaces,struct node_queue * nqueues,struct node_queue_bw bwspec,struct node_queue_opt * opts)6230 expand_altq(struct pf_altq *a, struct node_if *interfaces,
6231 struct node_queue *nqueues, struct node_queue_bw bwspec,
6232 struct node_queue_opt *opts)
6233 {
6234 struct pf_altq pa, pb;
6235 char qname[PF_QNAME_SIZE];
6236 struct node_queue *n;
6237 struct node_queue_bw bw;
6238 int errs = 0;
6239
6240 if ((pf->loadopt & PFCTL_FLAG_ALTQ) == 0) {
6241 FREE_LIST(struct node_if, interfaces);
6242 if (nqueues)
6243 FREE_LIST(struct node_queue, nqueues);
6244 return (0);
6245 }
6246
6247 LOOP_THROUGH(struct node_if, interface, interfaces,
6248 memcpy(&pa, a, sizeof(struct pf_altq));
6249 if (strlcpy(pa.ifname, interface->ifname,
6250 sizeof(pa.ifname)) >= sizeof(pa.ifname))
6251 errx(1, "%s: strlcpy", __func__);
6252
6253 if (interface->not) {
6254 yyerror("altq on ! <interface> is not supported");
6255 errs++;
6256 } else {
6257 if (eval_pfaltq(pf, &pa, &bwspec, opts))
6258 errs++;
6259 else
6260 if (pfctl_add_altq(pf, &pa))
6261 errs++;
6262
6263 if (pf->opts & PF_OPT_VERBOSE) {
6264 print_altq(&pf->paltq->altq, 0,
6265 &bwspec, opts);
6266 if (nqueues && nqueues->tail) {
6267 printf("queue { ");
6268 LOOP_THROUGH(struct node_queue, queue,
6269 nqueues,
6270 printf("%s ",
6271 queue->queue);
6272 );
6273 printf("}");
6274 }
6275 printf("\n");
6276 }
6277
6278 if (pa.scheduler == ALTQT_CBQ ||
6279 pa.scheduler == ALTQT_HFSC ||
6280 pa.scheduler == ALTQT_FAIRQ) {
6281 /* now create a root queue */
6282 memset(&pb, 0, sizeof(struct pf_altq));
6283 if (strlcpy(qname, "root_", sizeof(qname)) >=
6284 sizeof(qname))
6285 errx(1, "%s: strlcpy", __func__);
6286 if (strlcat(qname, interface->ifname,
6287 sizeof(qname)) >= sizeof(qname))
6288 errx(1, "%s: strlcat", __func__);
6289 if (strlcpy(pb.qname, qname,
6290 sizeof(pb.qname)) >= sizeof(pb.qname))
6291 errx(1, "%s: strlcpy", __func__);
6292 if (strlcpy(pb.ifname, interface->ifname,
6293 sizeof(pb.ifname)) >= sizeof(pb.ifname))
6294 errx(1, "%s: strlcpy", __func__);
6295 pb.qlimit = pa.qlimit;
6296 pb.scheduler = pa.scheduler;
6297 bw.bw_absolute = pa.ifbandwidth;
6298 bw.bw_percent = 0;
6299 if (eval_pfqueue(pf, &pb, &bw, opts))
6300 errs++;
6301 else
6302 if (pfctl_add_altq(pf, &pb))
6303 errs++;
6304 }
6305
6306 LOOP_THROUGH(struct node_queue, queue, nqueues,
6307 n = calloc(1, sizeof(struct node_queue));
6308 if (n == NULL)
6309 err(1, "%s: calloc", __func__);
6310 if (pa.scheduler == ALTQT_CBQ ||
6311 pa.scheduler == ALTQT_HFSC ||
6312 pa.scheduler == ALTQT_FAIRQ)
6313 if (strlcpy(n->parent, qname,
6314 sizeof(n->parent)) >=
6315 sizeof(n->parent))
6316 errx(1, "%s: strlcpy", __func__);
6317 if (strlcpy(n->queue, queue->queue,
6318 sizeof(n->queue)) >= sizeof(n->queue))
6319 errx(1, "%s: strlcpy", __func__);
6320 if (strlcpy(n->ifname, interface->ifname,
6321 sizeof(n->ifname)) >= sizeof(n->ifname))
6322 errx(1, "%s: strlcpy", __func__);
6323 n->scheduler = pa.scheduler;
6324 n->next = NULL;
6325 n->tail = n;
6326 if (queues == NULL)
6327 queues = n;
6328 else {
6329 queues->tail->next = n;
6330 queues->tail = n;
6331 }
6332 );
6333 }
6334 );
6335 FREE_LIST(struct node_if, interfaces);
6336 if (nqueues)
6337 FREE_LIST(struct node_queue, nqueues);
6338
6339 return (errs);
6340 }
6341
6342 int
expand_queue(struct pf_altq * a,struct node_if * interfaces,struct node_queue * nqueues,struct node_queue_bw bwspec,struct node_queue_opt * opts)6343 expand_queue(struct pf_altq *a, struct node_if *interfaces,
6344 struct node_queue *nqueues, struct node_queue_bw bwspec,
6345 struct node_queue_opt *opts)
6346 {
6347 struct node_queue *n, *nq;
6348 struct pf_altq pa;
6349 u_int8_t found = 0;
6350 u_int8_t errs = 0;
6351
6352 if ((pf->loadopt & PFCTL_FLAG_ALTQ) == 0) {
6353 FREE_LIST(struct node_queue, nqueues);
6354 return (0);
6355 }
6356
6357 if (queues == NULL) {
6358 yyerror("queue %s has no parent", a->qname);
6359 FREE_LIST(struct node_queue, nqueues);
6360 return (1);
6361 }
6362
6363 LOOP_THROUGH(struct node_if, interface, interfaces,
6364 LOOP_THROUGH(struct node_queue, tqueue, queues,
6365 if (!strncmp(a->qname, tqueue->queue, PF_QNAME_SIZE) &&
6366 (interface->ifname[0] == 0 ||
6367 (!interface->not && !strncmp(interface->ifname,
6368 tqueue->ifname, IFNAMSIZ)) ||
6369 (interface->not && strncmp(interface->ifname,
6370 tqueue->ifname, IFNAMSIZ)))) {
6371 /* found ourself in queues */
6372 found++;
6373
6374 memcpy(&pa, a, sizeof(struct pf_altq));
6375
6376 if (pa.scheduler != ALTQT_NONE &&
6377 pa.scheduler != tqueue->scheduler) {
6378 yyerror("exactly one scheduler type "
6379 "per interface allowed");
6380 return (1);
6381 }
6382 pa.scheduler = tqueue->scheduler;
6383
6384 /* scheduler dependent error checking */
6385 switch (pa.scheduler) {
6386 case ALTQT_PRIQ:
6387 if (nqueues != NULL) {
6388 yyerror("priq queues cannot "
6389 "have child queues");
6390 return (1);
6391 }
6392 if (bwspec.bw_absolute > 0 ||
6393 bwspec.bw_percent < 100) {
6394 yyerror("priq doesn't take "
6395 "bandwidth");
6396 return (1);
6397 }
6398 break;
6399 default:
6400 break;
6401 }
6402
6403 if (strlcpy(pa.ifname, tqueue->ifname,
6404 sizeof(pa.ifname)) >= sizeof(pa.ifname))
6405 errx(1, "%s: strlcpy", __func__);
6406 if (strlcpy(pa.parent, tqueue->parent,
6407 sizeof(pa.parent)) >= sizeof(pa.parent))
6408 errx(1, "%s: strlcpy", __func__);
6409
6410 if (eval_pfqueue(pf, &pa, &bwspec, opts))
6411 errs++;
6412 else
6413 if (pfctl_add_altq(pf, &pa))
6414 errs++;
6415
6416 for (nq = nqueues; nq != NULL; nq = nq->next) {
6417 if (!strcmp(a->qname, nq->queue)) {
6418 yyerror("queue cannot have "
6419 "itself as child");
6420 errs++;
6421 continue;
6422 }
6423 n = calloc(1,
6424 sizeof(struct node_queue));
6425 if (n == NULL)
6426 err(1, "%s: calloc", __func__);
6427 if (strlcpy(n->parent, a->qname,
6428 sizeof(n->parent)) >=
6429 sizeof(n->parent))
6430 errx(1, "%s strlcpy", __func__);
6431 if (strlcpy(n->queue, nq->queue,
6432 sizeof(n->queue)) >=
6433 sizeof(n->queue))
6434 errx(1, "%s strlcpy", __func__);
6435 if (strlcpy(n->ifname, tqueue->ifname,
6436 sizeof(n->ifname)) >=
6437 sizeof(n->ifname))
6438 errx(1, "%s strlcpy", __func__);
6439 n->scheduler = tqueue->scheduler;
6440 n->next = NULL;
6441 n->tail = n;
6442 if (queues == NULL)
6443 queues = n;
6444 else {
6445 queues->tail->next = n;
6446 queues->tail = n;
6447 }
6448 }
6449 if ((pf->opts & PF_OPT_VERBOSE) && (
6450 (found == 1 && interface->ifname[0] == 0) ||
6451 (found > 0 && interface->ifname[0] != 0))) {
6452 print_queue(&pf->paltq->altq, 0,
6453 &bwspec, interface->ifname[0] != 0,
6454 opts);
6455 if (nqueues && nqueues->tail) {
6456 printf("{ ");
6457 LOOP_THROUGH(struct node_queue,
6458 queue, nqueues,
6459 printf("%s ",
6460 queue->queue);
6461 );
6462 printf("}");
6463 }
6464 printf("\n");
6465 }
6466 }
6467 );
6468 );
6469
6470 FREE_LIST(struct node_queue, nqueues);
6471 FREE_LIST(struct node_if, interfaces);
6472
6473 if (!found) {
6474 yyerror("queue %s has no parent", a->qname);
6475 errs++;
6476 }
6477
6478 if (errs)
6479 return (1);
6480 else
6481 return (0);
6482 }
6483
6484 static int
pf_af_to_proto(sa_family_t af)6485 pf_af_to_proto(sa_family_t af)
6486 {
6487 if (af == AF_INET)
6488 return (ETHERTYPE_IP);
6489 if (af == AF_INET6)
6490 return (ETHERTYPE_IPV6);
6491
6492 return (0);
6493 }
6494
6495 void
expand_eth_rule(struct pfctl_eth_rule * r,struct node_if * interfaces,struct node_etherproto * protos,struct node_mac * srcs,struct node_mac * dsts,struct node_host * ipsrcs,struct node_host * ipdsts,const char * bridge_to,const char * anchor_call)6496 expand_eth_rule(struct pfctl_eth_rule *r,
6497 struct node_if *interfaces, struct node_etherproto *protos,
6498 struct node_mac *srcs, struct node_mac *dsts,
6499 struct node_host *ipsrcs, struct node_host *ipdsts,
6500 const char *bridge_to, const char *anchor_call)
6501 {
6502 char tagname[PF_TAG_NAME_SIZE];
6503 char match_tagname[PF_TAG_NAME_SIZE];
6504 char qname[PF_QNAME_SIZE];
6505
6506 if (strlcpy(tagname, r->tagname, sizeof(tagname)) >= sizeof(tagname))
6507 errx(1, "%s: tagname", __func__);
6508 if (strlcpy(match_tagname, r->match_tagname, sizeof(match_tagname)) >=
6509 sizeof(match_tagname))
6510 errx(1, "%s: match_tagname", __func__);
6511 if (strlcpy(qname, r->qname, sizeof(qname)) >= sizeof(qname))
6512 errx(1, "%s: qname", __func__);
6513
6514 LOOP_THROUGH(struct node_if, interface, interfaces,
6515 LOOP_THROUGH(struct node_etherproto, proto, protos,
6516 LOOP_THROUGH(struct node_mac, src, srcs,
6517 LOOP_THROUGH(struct node_mac, dst, dsts,
6518 LOOP_THROUGH(struct node_host, ipsrc, ipsrcs,
6519 LOOP_THROUGH(struct node_host, ipdst, ipdsts,
6520 strlcpy(r->ifname, interface->ifname,
6521 sizeof(r->ifname));
6522 r->ifnot = interface->not;
6523 r->proto = proto->proto;
6524 if (!r->proto && ipsrc->af)
6525 r->proto = pf_af_to_proto(ipsrc->af);
6526 else if (!r->proto && ipdst->af)
6527 r->proto = pf_af_to_proto(ipdst->af);
6528 bcopy(src->mac, r->src.addr, ETHER_ADDR_LEN);
6529 bcopy(src->mask, r->src.mask, ETHER_ADDR_LEN);
6530 r->src.neg = src->neg;
6531 r->src.isset = src->isset;
6532 r->ipsrc.addr = ipsrc->addr;
6533 r->ipsrc.neg = ipsrc->not;
6534 r->ipdst.addr = ipdst->addr;
6535 r->ipdst.neg = ipdst->not;
6536 bcopy(dst->mac, r->dst.addr, ETHER_ADDR_LEN);
6537 bcopy(dst->mask, r->dst.mask, ETHER_ADDR_LEN);
6538 r->dst.neg = dst->neg;
6539 r->dst.isset = dst->isset;
6540 r->nr = pf->eastack[pf->asd]->match++;
6541
6542 if (strlcpy(r->tagname, tagname, sizeof(r->tagname)) >=
6543 sizeof(r->tagname))
6544 errx(1, "%s: r->tagname", __func__);
6545 if (strlcpy(r->match_tagname, match_tagname,
6546 sizeof(r->match_tagname)) >= sizeof(r->match_tagname))
6547 errx(1, "%s: r->match_tagname", __func__);
6548 if (strlcpy(r->qname, qname, sizeof(r->qname)) >= sizeof(r->qname))
6549 errx(1, "%s: r->qname", __func__);
6550
6551 if (bridge_to)
6552 strlcpy(r->bridge_to, bridge_to, sizeof(r->bridge_to));
6553
6554 pfctl_append_eth_rule(pf, r, anchor_call);
6555 ))))));
6556
6557 FREE_LIST(struct node_if, interfaces);
6558 FREE_LIST(struct node_etherproto, protos);
6559 FREE_LIST(struct node_mac, srcs);
6560 FREE_LIST(struct node_mac, dsts);
6561 FREE_LIST(struct node_host, ipsrcs);
6562 FREE_LIST(struct node_host, ipdsts);
6563 }
6564
6565 int
apply_rdr_ports(struct pfctl_rule * r,struct pfctl_pool * rpool,struct redirspec * rs)6566 apply_rdr_ports(struct pfctl_rule *r, struct pfctl_pool *rpool, struct redirspec *rs)
6567 {
6568 if (rs == NULL)
6569 return 0;
6570
6571 rpool->proxy_port[0] = ntohs(rs->rport.a);
6572
6573 if (!rs->rport.b && rs->rport.t) {
6574 rpool->proxy_port[1] = ntohs(rs->rport.a) +
6575 (ntohs(r->dst.port[1]) - ntohs(r->dst.port[0]));
6576 } else {
6577 if (validate_range(rs->rport.t, rs->rport.a,
6578 rs->rport.b)) {
6579 yyerror("invalid rdr-to port range");
6580 return (1);
6581 }
6582 r->rdr.proxy_port[1] = ntohs(rs->rport.b);
6583 }
6584
6585 if (rs->pool_opts.staticport) {
6586 yyerror("the 'static-port' option is only valid with nat rules");
6587 return 1;
6588 }
6589
6590 if (rs->pool_opts.mape.offset) {
6591 yyerror("the 'map-e-portset' option is only valid with nat rules");
6592 return 1;
6593 }
6594
6595 return 0;
6596 }
6597
6598 int
apply_nat_ports(struct pfctl_pool * rpool,struct redirspec * rs)6599 apply_nat_ports(struct pfctl_pool *rpool, struct redirspec *rs)
6600 {
6601 if (rs == NULL)
6602 return 0;
6603
6604 rpool->proxy_port[0] = ntohs(rs->rport.a);
6605 rpool->proxy_port[1] = ntohs(rs->rport.b);
6606 if (!rpool->proxy_port[0] && !rpool->proxy_port[1]) {
6607 rpool->proxy_port[0] = PF_NAT_PROXY_PORT_LOW;
6608 rpool->proxy_port[1] = PF_NAT_PROXY_PORT_HIGH;
6609 } else if (!rpool->proxy_port[1])
6610 rpool->proxy_port[1] = rpool->proxy_port[0];
6611
6612 if (rs->pool_opts.staticport) {
6613 if (rpool->proxy_port[0] != PF_NAT_PROXY_PORT_LOW &&
6614 rpool->proxy_port[1] != PF_NAT_PROXY_PORT_HIGH) {
6615 yyerror("the 'static-port' option can't"
6616 " be used when specifying a port"
6617 " range");
6618 return 1;
6619 }
6620 rpool->proxy_port[0] = 0;
6621 rpool->proxy_port[1] = 0;
6622 }
6623
6624 if (rs->pool_opts.mape.offset) {
6625 if (rs->pool_opts.staticport) {
6626 yyerror("the 'map-e-portset' option"
6627 " can't be used 'static-port'");
6628 return 1;
6629 }
6630 if (rpool->proxy_port[0] != PF_NAT_PROXY_PORT_LOW &&
6631 rpool->proxy_port[1] != PF_NAT_PROXY_PORT_HIGH) {
6632 yyerror("the 'map-e-portset' option"
6633 " can't be used when specifying"
6634 " a port range");
6635 return 1;
6636 }
6637 rpool->mape = rs->pool_opts.mape;
6638 }
6639
6640 return 0;
6641 }
6642
6643 int
apply_redirspec(struct pfctl_pool * rpool,struct redirspec * rs)6644 apply_redirspec(struct pfctl_pool *rpool, struct redirspec *rs)
6645 {
6646 struct node_host *h;
6647 struct pfctl_pooladdr *pa;
6648
6649 if (rs == NULL)
6650 return 0;
6651
6652 rpool->opts = rs->pool_opts.type;
6653
6654 if ((rpool->opts & PF_POOL_TYPEMASK) == PF_POOL_NONE &&
6655 (rs->host->next != NULL ||
6656 rs->host->addr.type == PF_ADDR_TABLE ||
6657 DYNIF_MULTIADDR(rs->host->addr)))
6658 rpool->opts = PF_POOL_ROUNDROBIN;
6659
6660 if (!PF_POOL_DYNTYPE(rpool->opts) &&
6661 (disallow_table(rs->host, "tables are not supported by pool type") ||
6662 disallow_alias(rs->host, "interface (%s) is not supported by pool type")))
6663 return 1;
6664
6665 if (rs->host->next != NULL &&
6666 ((rpool->opts & PF_POOL_TYPEMASK) != PF_POOL_ROUNDROBIN)) {
6667 yyerror("r.route.opts must be PF_POOL_ROUNDROBIN");
6668 return 1;
6669 }
6670
6671 if (rs->host->next != NULL) {
6672 if ((rpool->opts & PF_POOL_TYPEMASK) !=
6673 PF_POOL_ROUNDROBIN) {
6674 yyerror("only round-robin valid for multiple "
6675 "redirection addresses");
6676 return 1;
6677 }
6678 }
6679
6680 rpool->opts |= rs->pool_opts.opts;
6681
6682 if (rs->pool_opts.key != NULL)
6683 memcpy(&(rpool->key), rs->pool_opts.key,
6684 sizeof(struct pf_poolhashkey));
6685
6686 for (h = rs->host; h != NULL; h = h->next) {
6687 pa = calloc(1, sizeof(struct pfctl_pooladdr));
6688 if (pa == NULL)
6689 err(1, "%s: calloc", __func__);
6690 pa->addr = h->addr;
6691 pa->af = h->af;
6692 if (h->ifname != NULL) {
6693 if (strlcpy(pa->ifname, h->ifname,
6694 sizeof(pa->ifname)) >= sizeof(pa->ifname))
6695 errx(1, "%s: strlcpy", __func__);
6696 } else
6697 pa->ifname[0] = 0;
6698 TAILQ_INSERT_TAIL(&(rpool->list), pa, entries);
6699 }
6700
6701 return 0;
6702 }
6703
6704 int
check_binat_redirspec(struct node_host * src_host,struct pfctl_rule * r,sa_family_t af)6705 check_binat_redirspec(struct node_host *src_host, struct pfctl_rule *r,
6706 sa_family_t af)
6707 {
6708 struct pfctl_pooladdr *nat_pool = TAILQ_FIRST(&(r->nat.list));
6709 int error = 0;
6710
6711 /* XXX: FreeBSD allows syntax like "{ host1 host2 }" for redirection
6712 * pools but does not covert them to tables automatically, because
6713 * syntax "{ (iface1 host1), (iface2 iface2) }" is allowed for route-to
6714 * redirection. Add a FreeBSD-specific guard against using multiple
6715 * hosts for source and redirection.
6716 */
6717 if (src_host->next) {
6718 yyerror("invalid use of table as the source address "
6719 "of a binat-to rule");
6720 error++;
6721 }
6722 if (TAILQ_NEXT(nat_pool, entries)) {
6723 yyerror ("tables cannot be used as the redirect "
6724 "address of a binat-to rule");
6725 error++;
6726 }
6727
6728 if (disallow_table(src_host, "invalid use of table "
6729 "<%s> as the source address of a binat-to rule") ||
6730 disallow_alias(src_host, "invalid use of interface "
6731 "(%s) as the source address of a binat-to rule")) {
6732 error++;
6733 } else if ((r->src.addr.type != PF_ADDR_ADDRMASK &&
6734 r->src.addr.type != PF_ADDR_DYNIFTL) ||
6735 (nat_pool->addr.type != PF_ADDR_ADDRMASK &&
6736 nat_pool->addr.type != PF_ADDR_DYNIFTL)) {
6737 yyerror("binat-to requires a specified "
6738 "source and redirect address");
6739 error++;
6740 }
6741 if (DYNIF_MULTIADDR(r->src.addr) ||
6742 DYNIF_MULTIADDR(nat_pool->addr)) {
6743 yyerror ("dynamic interfaces must be "
6744 "used with:0 in a binat-to rule");
6745 error++;
6746 }
6747 if (PF_AZERO(&r->src.addr.v.a.mask, af) ||
6748 PF_AZERO(&(nat_pool->addr.v.a.mask), af)) {
6749 yyerror ("source and redir addresses must have "
6750 "a matching network mask in binat-rule");
6751 error++;
6752 }
6753 if (nat_pool->addr.type == PF_ADDR_TABLE) {
6754 yyerror ("tables cannot be used as the redirect "
6755 "address of a binat-to rule");
6756 error++;
6757 }
6758 if (r->direction != PF_INOUT) {
6759 yyerror("binat-to cannot be specified "
6760 "with a direction");
6761 error++;
6762 }
6763
6764 /* first specify outbound NAT rule */
6765 r->direction = PF_OUT;
6766
6767 return (error);
6768 }
6769
6770 void
add_binat_rdr_rule(struct pfctl_rule * binat_rule,struct redirspec * binat_nat_redirspec,struct node_host * binat_src_host,struct pfctl_rule * rdr_rule,struct redirspec ** rdr_redirspec,struct node_host ** rdr_dst_host)6771 add_binat_rdr_rule(
6772 struct pfctl_rule *binat_rule,
6773 struct redirspec *binat_nat_redirspec, struct node_host *binat_src_host,
6774 struct pfctl_rule *rdr_rule, struct redirspec **rdr_redirspec,
6775 struct node_host **rdr_dst_host)
6776 {
6777 struct node_host *rdr_src_host;
6778
6779 /*
6780 * We're copying the whole rule, but we must re-init redir pools.
6781 * FreeBSD uses lists of pfctl_pooladdr, we can't just overwrite them.
6782 */
6783 bcopy(binat_rule, rdr_rule, sizeof(struct pfctl_rule));
6784 TAILQ_INIT(&(rdr_rule->rdr.list));
6785 TAILQ_INIT(&(rdr_rule->nat.list));
6786
6787 /* now specify inbound rdr rule */
6788 rdr_rule->direction = PF_IN;
6789
6790 if ((rdr_src_host = calloc(1, sizeof(*rdr_src_host))) == NULL)
6791 err(1, "%s", __func__);
6792 bcopy(binat_src_host, rdr_src_host, sizeof(*rdr_src_host));
6793 rdr_src_host->ifname = NULL;
6794 rdr_src_host->next = NULL;
6795 rdr_src_host->tail = NULL;
6796
6797 if (((*rdr_dst_host) = calloc(1, sizeof(**rdr_dst_host))) == NULL)
6798 err(1, "%s", __func__);
6799 bcopy(&(binat_nat_redirspec->host->addr), &((*rdr_dst_host)->addr),
6800 sizeof((*rdr_dst_host)->addr));
6801 (*rdr_dst_host)->ifname = NULL;
6802 (*rdr_dst_host)->next = NULL;
6803 (*rdr_dst_host)->tail = NULL;
6804
6805 if (((*rdr_redirspec) = calloc(1, sizeof(**rdr_redirspec))) == NULL)
6806 err(1, "%s", __func__);
6807 bcopy(binat_nat_redirspec, (*rdr_redirspec), sizeof(**rdr_redirspec));
6808 (*rdr_redirspec)->pool_opts.staticport = 0;
6809 (*rdr_redirspec)->host = rdr_src_host;
6810 }
6811
6812 void
expand_rule(struct pfctl_rule * r,bool keeprule,struct node_if * interfaces,struct redirspec * nat,struct redirspec * rdr,struct redirspec * route,struct node_proto * protos,struct node_os * src_oses,struct node_host * src_hosts,struct node_port * src_ports,struct node_host * dst_hosts,struct node_port * dst_ports,struct node_uid * uids,struct node_gid * gids,struct node_if * rcv,struct node_icmp * icmp_types)6813 expand_rule(struct pfctl_rule *r, bool keeprule,
6814 struct node_if *interfaces, struct redirspec *nat,
6815 struct redirspec *rdr, struct redirspec *route,
6816 struct node_proto *protos,
6817 struct node_os *src_oses, struct node_host *src_hosts,
6818 struct node_port *src_ports, struct node_host *dst_hosts,
6819 struct node_port *dst_ports, struct node_uid *uids, struct node_gid *gids,
6820 struct node_if *rcv, struct node_icmp *icmp_types)
6821 {
6822 sa_family_t af = r->af;
6823 int added = 0, error = 0;
6824 char ifname[IF_NAMESIZE];
6825 char label[PF_RULE_MAX_LABEL_COUNT][PF_RULE_LABEL_SIZE];
6826 char tagname[PF_TAG_NAME_SIZE];
6827 char match_tagname[PF_TAG_NAME_SIZE];
6828 struct node_host *osrch, *odsth;
6829 u_int8_t flags, flagset, keep_state;
6830
6831 memcpy(label, r->label, sizeof(r->label));
6832 assert(sizeof(r->label) == sizeof(label));
6833 if (strlcpy(tagname, r->tagname, sizeof(tagname)) >= sizeof(tagname))
6834 errx(1, "%s: strlcpy", __func__);
6835 if (strlcpy(match_tagname, r->match_tagname, sizeof(match_tagname)) >=
6836 sizeof(match_tagname))
6837 errx(1, "%s: strlcpy", __func__);
6838 flags = r->flags;
6839 flagset = r->flagset;
6840 keep_state = r->keep_state;
6841
6842 LOOP_THROUGH(struct node_if, interface, interfaces,
6843 LOOP_THROUGH(struct node_proto, proto, protos,
6844 LOOP_THROUGH(struct node_icmp, icmp_type, icmp_types,
6845 LOOP_THROUGH(struct node_host, src_host, src_hosts,
6846 LOOP_THROUGH(struct node_host, dst_host, dst_hosts,
6847 LOOP_THROUGH(struct node_port, src_port, src_ports,
6848 LOOP_THROUGH(struct node_port, dst_port, dst_ports,
6849 LOOP_THROUGH(struct node_os, src_os, src_oses,
6850 LOOP_THROUGH(struct node_uid, uid, uids,
6851 LOOP_THROUGH(struct node_gid, gid, gids,
6852
6853 r->af = af;
6854
6855 if (r->rule_flag & PFRULE_AFTO) {
6856 assert(nat != NULL);
6857 r->naf = nat->af;
6858 }
6859
6860 /* for link-local IPv6 address, interface must match up */
6861 if ((r->af && src_host->af && r->af != src_host->af) ||
6862 (r->af && dst_host->af && r->af != dst_host->af) ||
6863 (src_host->af && dst_host->af &&
6864 src_host->af != dst_host->af) ||
6865 (src_host->ifindex && dst_host->ifindex &&
6866 src_host->ifindex != dst_host->ifindex) ||
6867 (src_host->ifindex && *interface->ifname &&
6868 src_host->ifindex != ifa_nametoindex(interface->ifname)) ||
6869 (dst_host->ifindex && *interface->ifname &&
6870 dst_host->ifindex != ifa_nametoindex(interface->ifname)))
6871 continue;
6872 if (!r->af && src_host->af)
6873 r->af = src_host->af;
6874 else if (!r->af && dst_host->af)
6875 r->af = dst_host->af;
6876
6877 if (*interface->ifname)
6878 strlcpy(r->ifname, interface->ifname,
6879 sizeof(r->ifname));
6880 else if (ifa_indextoname(src_host->ifindex, ifname))
6881 strlcpy(r->ifname, ifname, sizeof(r->ifname));
6882 else if (ifa_indextoname(dst_host->ifindex, ifname))
6883 strlcpy(r->ifname, ifname, sizeof(r->ifname));
6884 else
6885 memset(r->ifname, '\0', sizeof(r->ifname));
6886
6887 memcpy(r->label, label, sizeof(r->label));
6888 if (strlcpy(r->tagname, tagname, sizeof(r->tagname)) >=
6889 sizeof(r->tagname))
6890 errx(1, "%s: strlcpy", __func__);
6891 if (strlcpy(r->match_tagname, match_tagname,
6892 sizeof(r->match_tagname)) >= sizeof(r->match_tagname))
6893 errx(1, "%s: strlcpy", __func__);
6894
6895 osrch = odsth = NULL;
6896 if (src_host->addr.type == PF_ADDR_DYNIFTL) {
6897 osrch = src_host;
6898 if ((src_host = gen_dynnode(src_host, r->af)) == NULL)
6899 err(1, "%s: calloc", __func__);
6900 }
6901 if (dst_host->addr.type == PF_ADDR_DYNIFTL) {
6902 odsth = dst_host;
6903 if ((dst_host = gen_dynnode(dst_host, r->af)) == NULL)
6904 err(1, "%s: calloc", __func__);
6905 }
6906
6907 error += check_netmask(src_host, r->af);
6908 error += check_netmask(dst_host, r->af);
6909
6910 r->ifnot = interface->not;
6911 r->proto = proto->proto;
6912 r->src.addr = src_host->addr;
6913 r->src.neg = src_host->not;
6914 r->src.port[0] = src_port->port[0];
6915 r->src.port[1] = src_port->port[1];
6916 r->src.port_op = src_port->op;
6917 r->dst.addr = dst_host->addr;
6918 r->dst.neg = dst_host->not;
6919 r->dst.port[0] = dst_port->port[0];
6920 r->dst.port[1] = dst_port->port[1];
6921 r->dst.port_op = dst_port->op;
6922 r->uid.op = uid->op;
6923 r->uid.uid[0] = uid->uid[0];
6924 r->uid.uid[1] = uid->uid[1];
6925 r->gid.op = gid->op;
6926 r->gid.gid[0] = gid->gid[0];
6927 r->gid.gid[1] = gid->gid[1];
6928 if (rcv) {
6929 strlcpy(r->rcv_ifname, rcv->ifname,
6930 sizeof(r->rcv_ifname));
6931 r->rcvifnot = rcv->not;
6932 }
6933 r->type = icmp_type->type;
6934 r->code = icmp_type->code;
6935
6936 if ((keep_state == PF_STATE_MODULATE ||
6937 keep_state == PF_STATE_SYNPROXY) &&
6938 r->proto && r->proto != IPPROTO_TCP)
6939 r->keep_state = PF_STATE_NORMAL;
6940 else
6941 r->keep_state = keep_state;
6942
6943 if (r->proto && r->proto != IPPROTO_TCP) {
6944 r->flags = 0;
6945 r->flagset = 0;
6946 } else {
6947 r->flags = flags;
6948 r->flagset = flagset;
6949 }
6950 if (icmp_type->proto && r->proto != icmp_type->proto) {
6951 yyerror("icmp-type mismatch");
6952 error++;
6953 }
6954
6955 if (src_os && src_os->os) {
6956 r->os_fingerprint = pfctl_get_fingerprint(src_os->os);
6957 if ((pf->opts & PF_OPT_VERBOSE2) &&
6958 r->os_fingerprint == PF_OSFP_NOMATCH)
6959 fprintf(stderr,
6960 "warning: unknown '%s' OS fingerprint\n",
6961 src_os->os);
6962 } else {
6963 r->os_fingerprint = PF_OSFP_ANY;
6964 }
6965
6966 if (r->action == PF_RDR) {
6967 /* Pre-FreeBSD 15 "rdr" rule */
6968 error += apply_rdr_ports(r, &(r->rdr), rdr);
6969 error += apply_redirspec(&(r->rdr), rdr);
6970 } else if (r->action == PF_NAT) {
6971 /* Pre-FreeBSD 15 "nat" rule */
6972 error += apply_nat_ports(&(r->rdr), rdr);
6973 error += apply_redirspec(&(r->rdr), rdr);
6974 } else {
6975 /* Modern rule with optional NAT, BINAT, RDR or ROUTE*/
6976 error += apply_redirspec(&(r->route), route);
6977
6978 error += apply_nat_ports(&(r->nat), nat);
6979 error += apply_redirspec(&(r->nat), nat);
6980 error += apply_rdr_ports(r, &(r->rdr), rdr);
6981 error += apply_redirspec(&(r->rdr), rdr);
6982
6983 if (nat && nat->binat)
6984 error += check_binat_redirspec(src_host, r, af);
6985 }
6986
6987 if (rule_consistent(r) < 0 || error)
6988 yyerror("skipping rule due to errors");
6989 else {
6990 r->nr = pf->astack[pf->asd]->match++;
6991 pfctl_append_rule(pf, r);
6992 added++;
6993 }
6994
6995 /* Generate binat's matching inbound rule */
6996 if (!error && nat && nat->binat) {
6997 struct pfctl_rule rdr_rule;
6998 struct redirspec *rdr_redirspec;
6999 struct node_host *rdr_dst_host;
7000
7001 add_binat_rdr_rule(
7002 r, nat, src_hosts,
7003 &rdr_rule, &rdr_redirspec, &rdr_dst_host);
7004
7005 expand_rule(&rdr_rule, true, interface, NULL, rdr_redirspec,
7006 NULL, proto, src_os, dst_host, dst_port,
7007 rdr_dst_host, src_port, uid, gid, rcv, icmp_type);
7008 }
7009
7010 if (osrch && src_host->addr.type == PF_ADDR_DYNIFTL) {
7011 free(src_host);
7012 src_host = osrch;
7013 }
7014 if (odsth && dst_host->addr.type == PF_ADDR_DYNIFTL) {
7015 free(dst_host);
7016 dst_host = odsth;
7017 }
7018
7019 ))))))))));
7020
7021 if (!keeprule) {
7022 FREE_LIST(struct node_if, interfaces);
7023 FREE_LIST(struct node_proto, protos);
7024 FREE_LIST(struct node_host, src_hosts);
7025 FREE_LIST(struct node_port, src_ports);
7026 FREE_LIST(struct node_os, src_oses);
7027 FREE_LIST(struct node_host, dst_hosts);
7028 FREE_LIST(struct node_port, dst_ports);
7029 FREE_LIST(struct node_uid, uids);
7030 FREE_LIST(struct node_gid, gids);
7031 FREE_LIST(struct node_icmp, icmp_types);
7032 if (nat) {
7033 FREE_LIST(struct node_host, nat->host);
7034 free(nat);
7035 }
7036 if (rdr) {
7037 FREE_LIST(struct node_host, rdr->host);
7038 free(rdr);
7039 }
7040 if (route) {
7041 FREE_LIST(struct node_host, route->host);
7042 free(route);
7043 }
7044 }
7045
7046 if (!added)
7047 yyerror("rule expands to no valid combination");
7048 }
7049
7050 int
expand_skip_interface(struct node_if * interfaces)7051 expand_skip_interface(struct node_if *interfaces)
7052 {
7053 int errs = 0;
7054
7055 if (!interfaces || (!interfaces->next && !interfaces->not &&
7056 !strcmp(interfaces->ifname, "none"))) {
7057 if (pf->opts & PF_OPT_VERBOSE)
7058 printf("set skip on none\n");
7059 errs = pfctl_set_interface_flags(pf, "", PFI_IFLAG_SKIP, 0);
7060 return (errs);
7061 }
7062
7063 if (pf->opts & PF_OPT_VERBOSE)
7064 printf("set skip on {");
7065 LOOP_THROUGH(struct node_if, interface, interfaces,
7066 if (pf->opts & PF_OPT_VERBOSE)
7067 printf(" %s", interface->ifname);
7068 if (interface->not) {
7069 yyerror("skip on ! <interface> is not supported");
7070 errs++;
7071 } else
7072 errs += pfctl_set_interface_flags(pf,
7073 interface->ifname, PFI_IFLAG_SKIP, 1);
7074 );
7075 if (pf->opts & PF_OPT_VERBOSE)
7076 printf(" }\n");
7077
7078 FREE_LIST(struct node_if, interfaces);
7079
7080 if (errs)
7081 return (1);
7082 else
7083 return (0);
7084 }
7085
7086 void
freehostlist(struct node_host * h)7087 freehostlist(struct node_host *h)
7088 {
7089 FREE_LIST(struct node_host, h);
7090 }
7091
7092 #undef FREE_LIST
7093 #undef LOOP_THROUGH
7094
7095 int
check_rulestate(int desired_state)7096 check_rulestate(int desired_state)
7097 {
7098 if (require_order && (rulestate > desired_state)) {
7099 yyerror("Rules must be in order: options, ethernet, "
7100 "normalization, queueing, translation, filtering");
7101 return (1);
7102 }
7103 rulestate = desired_state;
7104 return (0);
7105 }
7106
7107 int
kw_cmp(const void * k,const void * e)7108 kw_cmp(const void *k, const void *e)
7109 {
7110 return (strcmp(k, ((const struct keywords *)e)->k_name));
7111 }
7112
7113 int
lookup(char * s)7114 lookup(char *s)
7115 {
7116 /* this has to be sorted always */
7117 static const struct keywords keywords[] = {
7118 { "above", ABOVE},
7119 { "af-to", AFTO},
7120 { "all", ALL},
7121 { "allow-opts", ALLOWOPTS},
7122 { "allow-related", ALLOW_RELATED},
7123 { "altq", ALTQ},
7124 { "anchor", ANCHOR},
7125 { "antispoof", ANTISPOOF},
7126 { "any", ANY},
7127 { "bandwidth", BANDWIDTH},
7128 { "below", BELOW},
7129 { "binat", BINAT},
7130 { "binat-anchor", BINATANCHOR},
7131 { "binat-to", BINATTO},
7132 { "bitmask", BITMASK},
7133 { "block", BLOCK},
7134 { "block-policy", BLOCKPOLICY},
7135 { "bridge-to", BRIDGE_TO},
7136 { "buckets", BUCKETS},
7137 { "cbq", CBQ},
7138 { "code", CODE},
7139 { "codelq", CODEL},
7140 { "debug", DEBUG},
7141 { "divert-reply", DIVERTREPLY},
7142 { "divert-to", DIVERTTO},
7143 { "dnpipe", DNPIPE},
7144 { "dnqueue", DNQUEUE},
7145 { "drop", DROP},
7146 { "dup-to", DUPTO},
7147 { "endpoint-independent", ENDPI},
7148 { "entries", ENTRIES},
7149 { "ether", ETHER},
7150 { "fail-policy", FAILPOLICY},
7151 { "fairq", FAIRQ},
7152 { "fastroute", FASTROUTE},
7153 { "file", FILENAME},
7154 { "fingerprints", FINGERPRINTS},
7155 { "flags", FLAGS},
7156 { "floating", FLOATING},
7157 { "flush", FLUSH},
7158 { "for", FOR},
7159 { "fragment", FRAGMENT},
7160 { "from", FROM},
7161 { "global", GLOBAL},
7162 { "group", GROUP},
7163 { "hfsc", HFSC},
7164 { "hogs", HOGS},
7165 { "hostid", HOSTID},
7166 { "icmp-type", ICMPTYPE},
7167 { "icmp6-type", ICMP6TYPE},
7168 { "id", ID},
7169 { "if-bound", IFBOUND},
7170 { "in", IN},
7171 { "include", INCLUDE},
7172 { "inet", INET},
7173 { "inet6", INET6},
7174 { "interval", INTERVAL},
7175 { "keep", KEEP},
7176 { "keepcounters", KEEPCOUNTERS},
7177 { "l3", L3},
7178 { "label", LABEL},
7179 { "limit", LIMIT},
7180 { "limiter", LIMITER},
7181 { "linkshare", LINKSHARE},
7182 { "load", LOAD},
7183 { "log", LOG},
7184 { "loginterface", LOGINTERFACE},
7185 { "map-e-portset", MAPEPORTSET},
7186 { "mask", MASK},
7187 { "match", MATCH},
7188 { "matches", MATCHES},
7189 { "max", MAXIMUM},
7190 { "max-mss", MAXMSS},
7191 { "max-pkt-rate", MAXPKTRATE},
7192 { "max-pkt-size", MAXPKTSIZE},
7193 { "max-src-conn", MAXSRCCONN},
7194 { "max-src-conn-rate", MAXSRCCONNRATE},
7195 { "max-src-nodes", MAXSRCNODES},
7196 { "max-src-states", MAXSRCSTATES},
7197 { "min-ttl", MINTTL},
7198 { "modulate", MODULATE},
7199 { "nat", NAT},
7200 { "nat-anchor", NATANCHOR},
7201 { "nat-to", NATTO},
7202 { "no", NO},
7203 { "no-df", NODF},
7204 { "no-match", NOMATCH},
7205 { "no-route", NOROUTE},
7206 { "no-sync", NOSYNC},
7207 { "on", ON},
7208 { "once", ONCE},
7209 { "optimization", OPTIMIZATION},
7210 { "os", OS},
7211 { "out", OUT},
7212 { "overload", OVERLOAD},
7213 { "pass", PASS},
7214 { "pflow", PFLOW},
7215 { "port", PORT},
7216 { "prefer-ipv6-nexthop", IPV6NH},
7217 { "prio", PRIO},
7218 { "priority", PRIORITY},
7219 { "priq", PRIQ},
7220 { "probability", PROBABILITY},
7221 { "proto", PROTO},
7222 { "qlimit", QLIMIT},
7223 { "queue", QUEUE},
7224 { "quick", QUICK},
7225 { "random", RANDOM},
7226 { "random-id", RANDOMID},
7227 { "rate", RATE},
7228 { "rdr", RDR},
7229 { "rdr-anchor", RDRANCHOR},
7230 { "rdr-to", RDRTO},
7231 { "realtime", REALTIME},
7232 { "reassemble", REASSEMBLE},
7233 { "received-on", RECEIVEDON},
7234 { "reply-to", REPLYTO},
7235 { "require-order", REQUIREORDER},
7236 { "return", RETURN},
7237 { "return-icmp", RETURNICMP},
7238 { "return-icmp6", RETURNICMP6},
7239 { "return-rst", RETURNRST},
7240 { "ridentifier", RIDENTIFIER},
7241 { "round-robin", ROUNDROBIN},
7242 { "route", ROUTE},
7243 { "route-to", ROUTETO},
7244 { "rtable", RTABLE},
7245 { "rule", RULE},
7246 { "ruleset-optimization", RULESET_OPTIMIZATION},
7247 { "scrub", SCRUB},
7248 { "set", SET},
7249 { "set-tos", SETTOS},
7250 { "skip", SKIP},
7251 { "sloppy", SLOPPY},
7252 { "source", SOURCE},
7253 { "source-hash", SOURCEHASH},
7254 { "source-track", SOURCETRACK},
7255 { "state", STATE},
7256 { "state-defaults", STATEDEFAULTS},
7257 { "state-policy", STATEPOLICY},
7258 { "static-port", STATICPORT},
7259 { "sticky-address", STICKYADDRESS},
7260 { "syncookies", SYNCOOKIES},
7261 { "synproxy", SYNPROXY},
7262 { "table", TABLE},
7263 { "tag", TAG},
7264 { "tagged", TAGGED},
7265 { "target", TARGET},
7266 { "tbrsize", TBRSIZE},
7267 { "timeout", TIMEOUT},
7268 { "to", TO},
7269 { "tos", TOS},
7270 { "ttl", TTL},
7271 { "upperlimit", UPPERLIMIT},
7272 { "urpf-failed", URPFFAILED},
7273 { "user", USER},
7274 };
7275 const struct keywords *p;
7276
7277 p = bsearch(s, keywords, sizeof(keywords)/sizeof(keywords[0]),
7278 sizeof(keywords[0]), kw_cmp);
7279
7280 if (p) {
7281 if (debug > 1)
7282 fprintf(stderr, "%s: %d\n", s, p->k_val);
7283 return (p->k_val);
7284 } else {
7285 if (debug > 1)
7286 fprintf(stderr, "string: %s\n", s);
7287 return (STRING);
7288 }
7289 }
7290
7291 #define START_EXPAND 1
7292 #define DONE_EXPAND 2
7293
7294 static int expanding;
7295
7296 int
igetc(void)7297 igetc(void)
7298 {
7299 int c;
7300 while (1) {
7301 if (file->ungetpos > 0)
7302 c = file->ungetbuf[--file->ungetpos];
7303 else
7304 c = getc(file->stream);
7305 if (c == START_EXPAND)
7306 expanding = 1;
7307 else if (c == DONE_EXPAND)
7308 expanding = 0;
7309 else
7310 break;
7311 }
7312 return (c);
7313 }
7314
7315 int
lgetc(int quotec)7316 lgetc(int quotec)
7317 {
7318 int c, next;
7319
7320 if (quotec) {
7321 if ((c = igetc()) == EOF) {
7322 yyerror("reached end of file while parsing quoted string");
7323 if (file == topfile || popfile() == EOF)
7324 return (EOF);
7325 return (quotec);
7326 }
7327 return (c);
7328 }
7329
7330 while ((c = igetc()) == '\\') {
7331 next = igetc();
7332 if (next != '\n') {
7333 c = next;
7334 break;
7335 }
7336 yylval.lineno = file->lineno;
7337 file->lineno++;
7338 }
7339
7340 if (c == EOF) {
7341 /*
7342 * Fake EOL when hit EOF for the first time. This gets line
7343 * count right if last line in included file is syntactically
7344 * invalid and has no newline.
7345 */
7346 if (file->eof_reached == 0) {
7347 file->eof_reached = 1;
7348 return ('\n');
7349 }
7350 while (c == EOF) {
7351 if (file == topfile || popfile() == EOF)
7352 return (EOF);
7353 c = igetc();
7354 }
7355 }
7356 return (c);
7357 }
7358
7359 void
lungetc(int c)7360 lungetc(int c)
7361 {
7362 if (c == EOF)
7363 return;
7364 if (file->ungetpos >= file->ungetsize) {
7365 void *p = reallocarray(file->ungetbuf, file->ungetsize, 2);
7366 if (p == NULL)
7367 err(1, "%s", __func__);
7368 file->ungetbuf = p;
7369 file->ungetsize *= 2;
7370 }
7371 file->ungetbuf[file->ungetpos++] = c;
7372 }
7373
7374 int
findeol(void)7375 findeol(void)
7376 {
7377 int c;
7378
7379 /* skip to either EOF or the first real EOL */
7380 while (1) {
7381 c = lgetc(0);
7382 if (c == '\n') {
7383 file->lineno++;
7384 break;
7385 }
7386 if (c == EOF)
7387 break;
7388 }
7389 return (ERROR);
7390 }
7391
7392 int
yylex(void)7393 yylex(void)
7394 {
7395 char buf[8096];
7396 char *p, *val;
7397 int quotec, next, c;
7398 int token;
7399
7400 top:
7401 p = buf;
7402 while ((c = lgetc(0)) == ' ' || c == '\t' || c == '\014')
7403 ; /* nothing */
7404
7405 yylval.lineno = file->lineno;
7406 if (c == '#')
7407 while ((c = lgetc(0)) != '\n' && c != EOF)
7408 ; /* nothing */
7409 if (c == '$' && !expanding) {
7410 while (1) {
7411 if ((c = lgetc(0)) == EOF)
7412 return (0);
7413
7414 if (p + 1 >= buf + sizeof(buf) - 1) {
7415 yyerror("string too long");
7416 return (findeol());
7417 }
7418 if (isalnum(c) || c == '_') {
7419 *p++ = (char)c;
7420 continue;
7421 }
7422 *p = '\0';
7423 lungetc(c);
7424 break;
7425 }
7426 val = symget(buf);
7427 if (val == NULL) {
7428 yyerror("macro '%s' not defined", buf);
7429 return (findeol());
7430 }
7431 p = val + strlen(val) - 1;
7432 lungetc(DONE_EXPAND);
7433 while (p >= val) {
7434 lungetc(*p);
7435 p--;
7436 }
7437 lungetc(START_EXPAND);
7438 goto top;
7439 }
7440
7441 switch (c) {
7442 case '\'':
7443 case '"':
7444 quotec = c;
7445 while (1) {
7446 if ((c = lgetc(quotec)) == EOF)
7447 return (0);
7448 if (c == '\n') {
7449 file->lineno++;
7450 continue;
7451 } else if (c == '\\') {
7452 if ((next = lgetc(quotec)) == EOF)
7453 return (0);
7454 if (next == quotec || next == ' ' ||
7455 next == '\t')
7456 c = next;
7457 else if (next == '\n') {
7458 file->lineno++;
7459 continue;
7460 }
7461 else
7462 lungetc(next);
7463 } else if (c == quotec) {
7464 *p = '\0';
7465 break;
7466 } else if (c == '\0') {
7467 yyerror("syntax error");
7468 return (findeol());
7469 }
7470 if (p + 1 >= buf + sizeof(buf) - 1) {
7471 yyerror("string too long");
7472 return (findeol());
7473 }
7474 *p++ = (char)c;
7475 }
7476 yylval.v.string = strdup(buf);
7477 if (yylval.v.string == NULL)
7478 err(1, "%s: strdup", __func__);
7479 return (STRING);
7480 case '!':
7481 next = lgetc(0);
7482 if (next == '=')
7483 return (NE);
7484 lungetc(next);
7485 break;
7486 case '<':
7487 next = lgetc(0);
7488 if (next == '>') {
7489 yylval.v.i = PF_OP_XRG;
7490 return (PORTBINARY);
7491 } else if (next == '=')
7492 return (LE);
7493 lungetc(next);
7494 break;
7495 case '>':
7496 next = lgetc(0);
7497 if (next == '<') {
7498 yylval.v.i = PF_OP_IRG;
7499 return (PORTBINARY);
7500 } else if (next == '=')
7501 return (GE);
7502 lungetc(next);
7503 break;
7504 case '-':
7505 next = lgetc(0);
7506 if (next == '>')
7507 return (ARROW);
7508 lungetc(next);
7509 break;
7510 }
7511
7512 #define allowed_to_end_number(x) \
7513 (isspace(x) || x == ')' || x ==',' || x == '/' || x == '}' || x == '=')
7514
7515 if (c == '-' || isdigit(c)) {
7516 do {
7517 *p++ = c;
7518 if ((size_t)(p-buf) >= sizeof(buf)) {
7519 yyerror("string too long");
7520 return (findeol());
7521 }
7522 } while ((c = lgetc(0)) != EOF && isdigit(c));
7523 lungetc(c);
7524 if (p == buf + 1 && buf[0] == '-')
7525 goto nodigits;
7526 if (c == EOF || allowed_to_end_number(c)) {
7527 const char *errstr = NULL;
7528
7529 *p = '\0';
7530 yylval.v.number = strtonum(buf, LLONG_MIN,
7531 LLONG_MAX, &errstr);
7532 if (errstr) {
7533 yyerror("\"%s\" invalid number: %s",
7534 buf, errstr);
7535 return (findeol());
7536 }
7537 return (NUMBER);
7538 } else {
7539 nodigits:
7540 while (p > buf + 1)
7541 lungetc(*--p);
7542 c = *--p;
7543 if (c == '-')
7544 return (c);
7545 }
7546 }
7547
7548 #define allowed_in_string(x) \
7549 (isalnum(x) || (ispunct(x) && x != '(' && x != ')' && \
7550 x != '{' && x != '}' && x != '<' && x != '>' && \
7551 x != '!' && x != '=' && x != '/' && x != '#' && \
7552 x != ','))
7553
7554 if (isalnum(c) || c == ':' || c == '_') {
7555 do {
7556 *p++ = c;
7557 if ((size_t)(p-buf) >= sizeof(buf)) {
7558 yyerror("string too long");
7559 return (findeol());
7560 }
7561 } while ((c = lgetc(0)) != EOF && (allowed_in_string(c)));
7562 lungetc(c);
7563 *p = '\0';
7564 if ((token = lookup(buf)) == STRING)
7565 if ((yylval.v.string = strdup(buf)) == NULL)
7566 err(1, "%s: strdup", __func__);
7567 return (token);
7568 }
7569 if (c == '\n') {
7570 yylval.lineno = file->lineno;
7571 file->lineno++;
7572 }
7573 if (c == EOF)
7574 return (0);
7575 return (c);
7576 }
7577
7578 int
check_file_secrecy(int fd,const char * fname)7579 check_file_secrecy(int fd, const char *fname)
7580 {
7581 struct stat st;
7582
7583 if (fstat(fd, &st)) {
7584 warn("cannot stat %s", fname);
7585 return (-1);
7586 }
7587 if (st.st_uid != 0 && st.st_uid != getuid()) {
7588 warnx("%s: owner not root or current user", fname);
7589 return (-1);
7590 }
7591 if (st.st_mode & (S_IWGRP | S_IXGRP | S_IRWXO)) {
7592 warnx("%s: group writable or world read/writable", fname);
7593 return (-1);
7594 }
7595 return (0);
7596 }
7597
7598 struct file *
pushfile(const char * name,int secret)7599 pushfile(const char *name, int secret)
7600 {
7601 struct file *nfile;
7602
7603 if ((nfile = calloc(1, sizeof(struct file))) == NULL ||
7604 (nfile->name = strdup(name)) == NULL) {
7605 warn("%s", __func__);
7606 if (nfile)
7607 free(nfile);
7608 return (NULL);
7609 }
7610 if (TAILQ_FIRST(&files) == NULL && strcmp(nfile->name, "-") == 0) {
7611 nfile->stream = stdin;
7612 free(nfile->name);
7613 if ((nfile->name = strdup("stdin")) == NULL) {
7614 warn("%s", __func__);
7615 free(nfile);
7616 return (NULL);
7617 }
7618 } else if ((nfile->stream = pfctl_fopen(nfile->name, "r")) == NULL) {
7619 warn("%s: %s", __func__, nfile->name);
7620 free(nfile->name);
7621 free(nfile);
7622 return (NULL);
7623 } else if (secret &&
7624 check_file_secrecy(fileno(nfile->stream), nfile->name)) {
7625 fclose(nfile->stream);
7626 free(nfile->name);
7627 free(nfile);
7628 return (NULL);
7629 }
7630 nfile->lineno = TAILQ_EMPTY(&files) ? 1 : 0;
7631 nfile->ungetsize = 16;
7632 nfile->ungetbuf = malloc(nfile->ungetsize);
7633 if (nfile->ungetbuf == NULL) {
7634 warn("%s", __func__);
7635 fclose(nfile->stream);
7636 free(nfile->name);
7637 free(nfile);
7638 return (NULL);
7639 }
7640 TAILQ_INSERT_TAIL(&files, nfile, entry);
7641 return (nfile);
7642 }
7643
7644 int
popfile(void)7645 popfile(void)
7646 {
7647 struct file *prev;
7648
7649 if ((prev = TAILQ_PREV(file, files, entry)) != NULL)
7650 prev->errors += file->errors;
7651
7652 TAILQ_REMOVE(&files, file, entry);
7653 fclose(file->stream);
7654 free(file->name);
7655 free(file->ungetbuf);
7656 free(file);
7657 file = prev;
7658
7659 return (file ? 0 : EOF);
7660 }
7661
7662 int
parse_config(char * filename,struct pfctl * xpf)7663 parse_config(char *filename, struct pfctl *xpf)
7664 {
7665 int errors = 0;
7666 struct sym *sym;
7667
7668 pf = xpf;
7669 errors = 0;
7670 rulestate = PFCTL_STATE_NONE;
7671 returnicmpdefault = (ICMP_UNREACH << 8) | ICMP_UNREACH_PORT;
7672 returnicmp6default =
7673 (ICMP6_DST_UNREACH << 8) | ICMP6_DST_UNREACH_NOPORT;
7674 blockpolicy = PFRULE_DROP;
7675 failpolicy = PFRULE_DROP;
7676 require_order = 1;
7677
7678 if ((file = pushfile(filename, 0)) == NULL) {
7679 warn("cannot open the main config file!");
7680 return (-1);
7681 }
7682 topfile = file;
7683
7684 yyparse();
7685 errors = file->errors;
7686 popfile();
7687
7688 /* Free macros and check which have not been used. */
7689 while ((sym = TAILQ_FIRST(&symhead))) {
7690 if ((pf->opts & PF_OPT_VERBOSE2) && !sym->used)
7691 fprintf(stderr, "warning: macro '%s' not "
7692 "used\n", sym->nam);
7693 free(sym->nam);
7694 free(sym->val);
7695 TAILQ_REMOVE(&symhead, sym, entry);
7696 free(sym);
7697 }
7698
7699 return (errors ? -1 : 0);
7700 }
7701
7702 int
symset(const char * nam,const char * val,int persist)7703 symset(const char *nam, const char *val, int persist)
7704 {
7705 struct sym *sym;
7706
7707 TAILQ_FOREACH(sym, &symhead, entry) {
7708 if (strcmp(nam, sym->nam) == 0)
7709 break;
7710 }
7711
7712 if (sym != NULL) {
7713 if (sym->persist == 1)
7714 return (0);
7715 else {
7716 free(sym->nam);
7717 free(sym->val);
7718 TAILQ_REMOVE(&symhead, sym, entry);
7719 free(sym);
7720 }
7721 }
7722 if ((sym = calloc(1, sizeof(*sym))) == NULL)
7723 return (-1);
7724
7725 sym->nam = strdup(nam);
7726 if (sym->nam == NULL) {
7727 free(sym);
7728 return (-1);
7729 }
7730 sym->val = strdup(val);
7731 if (sym->val == NULL) {
7732 free(sym->nam);
7733 free(sym);
7734 return (-1);
7735 }
7736 sym->used = 0;
7737 sym->persist = persist;
7738 TAILQ_INSERT_TAIL(&symhead, sym, entry);
7739 return (0);
7740 }
7741
7742 int
pfctl_cmdline_symset(char * s)7743 pfctl_cmdline_symset(char *s)
7744 {
7745 char *sym, *val;
7746 int ret;
7747
7748 if ((val = strrchr(s, '=')) == NULL)
7749 return (-1);
7750
7751 sym = strndup(s, val - s);
7752 if (sym == NULL)
7753 err(1, "%s: malloc", __func__);
7754
7755 ret = symset(sym, val + 1, 1);
7756 free(sym);
7757
7758 return (ret);
7759 }
7760
7761 char *
symget(const char * nam)7762 symget(const char *nam)
7763 {
7764 struct sym *sym;
7765
7766 TAILQ_FOREACH(sym, &symhead, entry) {
7767 if (strcmp(nam, sym->nam) == 0) {
7768 sym->used = 1;
7769 return (sym->val);
7770 }
7771 }
7772 return (NULL);
7773 }
7774
7775 void
mv_rules(struct pfctl_ruleset * src,struct pfctl_ruleset * dst)7776 mv_rules(struct pfctl_ruleset *src, struct pfctl_ruleset *dst)
7777 {
7778 int i;
7779 struct pfctl_rule *r;
7780
7781 for (i = 0; i < PF_RULESET_MAX; ++i) {
7782 TAILQ_FOREACH(r, src->rules[i].active.ptr, entries)
7783 dst->anchor->match++;
7784 TAILQ_CONCAT(dst->rules[i].active.ptr, src->rules[i].active.ptr, entries);
7785 src->anchor->match = 0;
7786 TAILQ_CONCAT(dst->rules[i].inactive.ptr, src->rules[i].inactive.ptr, entries);
7787 }
7788 }
7789
7790 void
mv_eth_rules(struct pfctl_eth_ruleset * src,struct pfctl_eth_ruleset * dst)7791 mv_eth_rules(struct pfctl_eth_ruleset *src, struct pfctl_eth_ruleset *dst)
7792 {
7793 struct pfctl_eth_rule *r;
7794
7795 while ((r = TAILQ_FIRST(&src->rules)) != NULL) {
7796 TAILQ_REMOVE(&src->rules, r, entries);
7797 TAILQ_INSERT_TAIL(&dst->rules, r, entries);
7798 dst->anchor->match++;
7799 }
7800 src->anchor->match = 0;
7801 }
7802
7803 void
mv_tables(struct pfctl * pf,struct pfr_ktablehead * ktables,struct pfctl_anchor * a,struct pfctl_anchor * alast)7804 mv_tables(struct pfctl *pf, struct pfr_ktablehead *ktables,
7805 struct pfctl_anchor *a, struct pfctl_anchor *alast)
7806 {
7807 struct pfr_ktable *kt, *kt_safe;
7808 char new_path[PF_ANCHOR_MAXPATH];
7809 char *path_cut;
7810 int sz;
7811 struct pfr_uktable *ukt;
7812 SLIST_HEAD(, pfr_uktable) ukt_list;
7813
7814 /*
7815 * Here we need to rename anchor path from temporal names such as
7816 * _1/_2/foo to _1/bar/foo etc.
7817 *
7818 * This also means we need to remove and insert table to ktables
7819 * tree as anchor path is being updated.
7820 */
7821 SLIST_INIT(&ukt_list);
7822 DBGPRINT("%s [ %s ] (%s)\n", __func__, a->path, alast->path);
7823 RB_FOREACH_SAFE(kt, pfr_ktablehead, ktables, kt_safe) {
7824 path_cut = strstr(kt->pfrkt_anchor, alast->path);
7825 if (path_cut != NULL) {
7826 path_cut += strlen(alast->path);
7827 if (*path_cut)
7828 sz = snprintf(new_path, sizeof (new_path),
7829 "%s%s", a->path, path_cut);
7830 else
7831 sz = snprintf(new_path, sizeof (new_path),
7832 "%s", a->path);
7833 if (sz >= sizeof (new_path))
7834 errx(1, "new path is too long for %s@%s\n",
7835 kt->pfrkt_name, kt->pfrkt_anchor);
7836
7837 DBGPRINT("%s %s@%s -> %s@%s\n", __func__,
7838 kt->pfrkt_name, kt->pfrkt_anchor,
7839 kt->pfrkt_name, new_path);
7840 RB_REMOVE(pfr_ktablehead, ktables, kt);
7841 strlcpy(kt->pfrkt_anchor, new_path,
7842 sizeof(kt->pfrkt_anchor));
7843 SLIST_INSERT_HEAD(&ukt_list, (struct pfr_uktable *)kt,
7844 pfrukt_entry);
7845 }
7846 }
7847
7848 while ((ukt = SLIST_FIRST(&ukt_list)) != NULL) {
7849 SLIST_REMOVE_HEAD(&ukt_list, pfrukt_entry);
7850 if (RB_INSERT(pfr_ktablehead, ktables,
7851 (struct pfr_ktable *)ukt) != NULL)
7852 errx(1, "%s@%s exists already\n",
7853 ukt->pfrukt_name,
7854 ukt->pfrukt_anchor);
7855 }
7856 }
7857
7858 void
decide_address_family(struct node_host * n,sa_family_t * af)7859 decide_address_family(struct node_host *n, sa_family_t *af)
7860 {
7861 if (*af != 0 || n == NULL)
7862 return;
7863 *af = n->af;
7864 while ((n = n->next) != NULL) {
7865 if (n->af != *af) {
7866 *af = 0;
7867 return;
7868 }
7869 }
7870 }
7871
7872 void
remove_invalid_hosts(struct node_host ** nh,sa_family_t * af)7873 remove_invalid_hosts(struct node_host **nh, sa_family_t *af)
7874 {
7875 struct node_host *n = *nh, *prev = NULL;
7876
7877 while (n != NULL) {
7878 if (*af && n->af && n->af != *af) {
7879 /* unlink and free n */
7880 struct node_host *next = n->next;
7881
7882 /* adjust tail pointer */
7883 if (n == (*nh)->tail)
7884 (*nh)->tail = prev;
7885 /* adjust previous node's next pointer */
7886 if (prev == NULL)
7887 *nh = next;
7888 else
7889 prev->next = next;
7890 /* free node */
7891 if (n->ifname != NULL)
7892 free(n->ifname);
7893 free(n);
7894 n = next;
7895 } else {
7896 if (n->af && !*af)
7897 *af = n->af;
7898 prev = n;
7899 n = n->next;
7900 }
7901 }
7902 }
7903
7904 int
invalid_redirect(struct node_host * nh,sa_family_t af)7905 invalid_redirect(struct node_host *nh, sa_family_t af)
7906 {
7907 if (!af) {
7908 struct node_host *n;
7909
7910 /* tables and dyniftl are ok without an address family */
7911 for (n = nh; n != NULL; n = n->next) {
7912 if (n->addr.type != PF_ADDR_TABLE &&
7913 n->addr.type != PF_ADDR_DYNIFTL) {
7914 yyerror("address family not given and "
7915 "translation address expands to multiple "
7916 "address families");
7917 return (1);
7918 }
7919 }
7920 }
7921 if (nh == NULL) {
7922 yyerror("no translation address with matching address family "
7923 "found.");
7924 return (1);
7925 }
7926 return (0);
7927 }
7928
7929 int
atoul(char * s,u_long * ulvalp)7930 atoul(char *s, u_long *ulvalp)
7931 {
7932 u_long ulval;
7933 char *ep;
7934
7935 errno = 0;
7936 ulval = strtoul(s, &ep, 0);
7937 if (s[0] == '\0' || *ep != '\0')
7938 return (-1);
7939 if (errno == ERANGE && ulval == ULONG_MAX)
7940 return (-1);
7941 *ulvalp = ulval;
7942 return (0);
7943 }
7944
7945 int
getservice(char * n)7946 getservice(char *n)
7947 {
7948 struct servent *s;
7949 u_long ulval;
7950
7951 if (atoul(n, &ulval) == 0) {
7952 if (ulval > 65535) {
7953 yyerror("illegal port value %lu", ulval);
7954 return (-1);
7955 }
7956 return (htons(ulval));
7957 } else {
7958 s = getservbyname(n, "tcp");
7959 if (s == NULL)
7960 s = getservbyname(n, "udp");
7961 if (s == NULL)
7962 s = getservbyname(n, "sctp");
7963 if (s == NULL) {
7964 yyerror("unknown port %s", n);
7965 return (-1);
7966 }
7967 return (s->s_port);
7968 }
7969 }
7970
7971 int
rule_label(struct pfctl_rule * r,char * s[PF_RULE_MAX_LABEL_COUNT])7972 rule_label(struct pfctl_rule *r, char *s[PF_RULE_MAX_LABEL_COUNT])
7973 {
7974 for (int i = 0; i < PF_RULE_MAX_LABEL_COUNT; i++) {
7975 if (s[i] == NULL)
7976 return (0);
7977
7978 if (strlcpy(r->label[i], s[i], sizeof(r->label[0])) >=
7979 sizeof(r->label[0])) {
7980 yyerror("rule label too long (max %d chars)",
7981 sizeof(r->label[0])-1);
7982 return (-1);
7983 }
7984 }
7985 return (0);
7986 }
7987
7988 int
eth_rule_label(struct pfctl_eth_rule * r,char * s[PF_RULE_MAX_LABEL_COUNT])7989 eth_rule_label(struct pfctl_eth_rule *r, char *s[PF_RULE_MAX_LABEL_COUNT])
7990 {
7991 for (int i = 0; i < PF_RULE_MAX_LABEL_COUNT; i++) {
7992 if (s[i] == NULL)
7993 return (0);
7994
7995 if (strlcpy(r->label[i], s[i], sizeof(r->label[0])) >=
7996 sizeof(r->label[0])) {
7997 yyerror("rule label too long (max %d chars)",
7998 sizeof(r->label[0])-1);
7999 return (-1);
8000 }
8001 }
8002 return (0);
8003 }
8004
8005 u_int16_t
parseicmpspec(char * w,sa_family_t af)8006 parseicmpspec(char *w, sa_family_t af)
8007 {
8008 const struct icmpcodeent *p;
8009 u_long ulval;
8010 u_int8_t icmptype;
8011
8012 if (af == AF_INET)
8013 icmptype = returnicmpdefault >> 8;
8014 else
8015 icmptype = returnicmp6default >> 8;
8016
8017 if (atoul(w, &ulval) == -1) {
8018 if ((p = geticmpcodebyname(icmptype, w, af)) == NULL) {
8019 yyerror("unknown icmp code %s", w);
8020 return (0);
8021 }
8022 ulval = p->code;
8023 }
8024 if (ulval > 255) {
8025 yyerror("invalid icmp code %lu", ulval);
8026 return (0);
8027 }
8028 return (icmptype << 8 | ulval);
8029 }
8030
8031 int
parseport(char * port,struct range * r,int extensions)8032 parseport(char *port, struct range *r, int extensions)
8033 {
8034 char *p = strchr(port, ':');
8035
8036 if (p == NULL) {
8037 if ((r->a = getservice(port)) == -1)
8038 return (-1);
8039 r->b = 0;
8040 r->t = PF_OP_NONE;
8041 return (0);
8042 }
8043 if ((extensions & PPORT_STAR) && !strcmp(p+1, "*")) {
8044 *p = 0;
8045 if ((r->a = getservice(port)) == -1)
8046 return (-1);
8047 r->b = 0;
8048 r->t = PF_OP_IRG;
8049 return (0);
8050 }
8051 if ((extensions & PPORT_RANGE)) {
8052 *p++ = 0;
8053 if ((r->a = getservice(port)) == -1 ||
8054 (r->b = getservice(p)) == -1)
8055 return (-1);
8056 if (r->a == r->b) {
8057 r->b = 0;
8058 r->t = PF_OP_NONE;
8059 } else
8060 r->t = PF_OP_RRG;
8061 return (0);
8062 }
8063 return (-1);
8064 }
8065
8066 int
pfctl_load_anchors(int dev,struct pfctl * pf)8067 pfctl_load_anchors(int dev, struct pfctl *pf)
8068 {
8069 struct loadanchors *la;
8070
8071 TAILQ_FOREACH(la, &loadanchorshead, entries) {
8072 if (pf->opts & PF_OPT_VERBOSE)
8073 fprintf(stderr, "\nLoading anchor %s from %s\n",
8074 la->anchorname, la->filename);
8075 if (pfctl_rules(dev, la->filename, pf->opts, pf->optimize,
8076 la->anchorname, pf->trans) == -1)
8077 return (-1);
8078 }
8079
8080 return (0);
8081 }
8082
8083 int
kw_casecmp(const void * k,const void * e)8084 kw_casecmp(const void *k, const void *e)
8085 {
8086 return (strcasecmp(k, ((const struct keywords *)e)->k_name));
8087 }
8088
8089 int
map_tos(char * s,int * val)8090 map_tos(char *s, int *val)
8091 {
8092 /* DiffServ Codepoints and other TOS mappings */
8093 const struct keywords toswords[] = {
8094 { "af11", IPTOS_DSCP_AF11 },
8095 { "af12", IPTOS_DSCP_AF12 },
8096 { "af13", IPTOS_DSCP_AF13 },
8097 { "af21", IPTOS_DSCP_AF21 },
8098 { "af22", IPTOS_DSCP_AF22 },
8099 { "af23", IPTOS_DSCP_AF23 },
8100 { "af31", IPTOS_DSCP_AF31 },
8101 { "af32", IPTOS_DSCP_AF32 },
8102 { "af33", IPTOS_DSCP_AF33 },
8103 { "af41", IPTOS_DSCP_AF41 },
8104 { "af42", IPTOS_DSCP_AF42 },
8105 { "af43", IPTOS_DSCP_AF43 },
8106 { "critical", IPTOS_PREC_CRITIC_ECP },
8107 { "cs0", IPTOS_DSCP_CS0 },
8108 { "cs1", IPTOS_DSCP_CS1 },
8109 { "cs2", IPTOS_DSCP_CS2 },
8110 { "cs3", IPTOS_DSCP_CS3 },
8111 { "cs4", IPTOS_DSCP_CS4 },
8112 { "cs5", IPTOS_DSCP_CS5 },
8113 { "cs6", IPTOS_DSCP_CS6 },
8114 { "cs7", IPTOS_DSCP_CS7 },
8115 { "ef", IPTOS_DSCP_EF },
8116 { "inetcontrol", IPTOS_PREC_INTERNETCONTROL },
8117 { "lowdelay", IPTOS_LOWDELAY },
8118 { "netcontrol", IPTOS_PREC_NETCONTROL },
8119 { "reliability", IPTOS_RELIABILITY },
8120 { "throughput", IPTOS_THROUGHPUT },
8121 { "va", IPTOS_DSCP_VA }
8122 };
8123 const struct keywords *p;
8124
8125 p = bsearch(s, toswords, sizeof(toswords)/sizeof(toswords[0]),
8126 sizeof(toswords[0]), kw_casecmp);
8127
8128 if (p) {
8129 *val = p->k_val;
8130 return (1);
8131 }
8132 return (0);
8133 }
8134
8135 int
rt_tableid_max(void)8136 rt_tableid_max(void)
8137 {
8138 #ifdef __FreeBSD__
8139 int fibs;
8140 size_t l = sizeof(fibs);
8141
8142 if (sysctlbyname("net.fibs", &fibs, &l, NULL, 0) == -1)
8143 fibs = 16; /* XXX RT_MAXFIBS, at least limit it some. */
8144 /*
8145 * As the OpenBSD code only compares > and not >= we need to adjust
8146 * here given we only accept values of 0..n and want to avoid #ifdefs
8147 * in the grammar.
8148 */
8149 return (fibs - 1);
8150 #else
8151 return (RT_TABLEID_MAX);
8152 #endif
8153 }
8154
8155 struct node_mac*
node_mac_from_string(const char * str)8156 node_mac_from_string(const char *str)
8157 {
8158 struct node_mac *m;
8159
8160 m = calloc(1, sizeof(struct node_mac));
8161 if (m == NULL)
8162 err(1, "%s: calloc", __func__);
8163
8164 if (sscanf(str, "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx",
8165 &m->mac[0], &m->mac[1], &m->mac[2], &m->mac[3], &m->mac[4],
8166 &m->mac[5]) != 6) {
8167 free(m);
8168 yyerror("invalid MAC address");
8169 return (NULL);
8170 }
8171
8172 memset(m->mask, 0xff, ETHER_ADDR_LEN);
8173 m->isset = true;
8174 m->next = NULL;
8175 m->tail = m;
8176
8177 return (m);
8178 }
8179
8180 struct node_mac*
node_mac_from_string_masklen(const char * str,int masklen)8181 node_mac_from_string_masklen(const char *str, int masklen)
8182 {
8183 struct node_mac *m;
8184
8185 if (masklen < 0 || masklen > (ETHER_ADDR_LEN * 8)) {
8186 yyerror("invalid MAC mask length");
8187 return (NULL);
8188 }
8189
8190 m = node_mac_from_string(str);
8191 if (m == NULL)
8192 return (NULL);
8193
8194 memset(m->mask, 0, ETHER_ADDR_LEN);
8195 for (int i = 0; i < masklen; i++)
8196 m->mask[i / 8] |= 1 << (i % 8);
8197
8198 return (m);
8199 }
8200
8201 struct node_mac*
node_mac_from_string_mask(const char * str,const char * mask)8202 node_mac_from_string_mask(const char *str, const char *mask)
8203 {
8204 struct node_mac *m;
8205
8206 m = node_mac_from_string(str);
8207 if (m == NULL)
8208 return (NULL);
8209
8210 if (sscanf(mask, "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx",
8211 &m->mask[0], &m->mask[1], &m->mask[2], &m->mask[3], &m->mask[4],
8212 &m->mask[5]) != 6) {
8213 free(m);
8214 yyerror("invalid MAC mask");
8215 return (NULL);
8216 }
8217
8218 return (m);
8219 }
8220
8221 int
filteropts_to_rule(struct pfctl_rule * r,struct filter_opts * opts)8222 filteropts_to_rule(struct pfctl_rule *r, struct filter_opts *opts)
8223 {
8224 if (opts->marker & FOM_ONCE) {
8225 if ((r->action != PF_PASS && r->action != PF_DROP) || r->anchor) {
8226 yyerror("'once' only applies to pass/block rules");
8227 return (1);
8228 }
8229 r->rule_flag |= PFRULE_ONCE;
8230 }
8231
8232 if (opts->statelim.id != PF_STATELIM_ID_NONE && r->action != PF_PASS) {
8233 yyerror("state limiter only applies to pass rules");
8234 return (1);
8235 }
8236 if (opts->sourcelim.id != PF_SOURCELIM_ID_NONE && r->action != PF_PASS) {
8237 yyerror("source limiter only applies to pass rules");
8238 return (1);
8239 }
8240
8241 r->keep_state = opts->keep.action;
8242 r->pktrate.limit = opts->pktrate.limit;
8243 r->pktrate.seconds = opts->pktrate.seconds;
8244 r->prob = opts->prob;
8245 r->statelim.id = opts->statelim.id;
8246 r->statelim.limiter_action = opts->statelim.limiter_action;
8247 r->sourcelim.id = opts->sourcelim.id;
8248 r->sourcelim.limiter_action = opts->sourcelim.limiter_action;
8249 r->rtableid = opts->rtableid;
8250 r->ridentifier = opts->ridentifier;
8251 r->max_pkt_size = opts->max_pkt_size;
8252 r->tos = opts->tos;
8253
8254 if (opts->nodf)
8255 r->scrub_flags |= PFSTATE_NODF;
8256 if (opts->randomid)
8257 r->scrub_flags |= PFSTATE_RANDOMID;
8258 if (opts->minttl)
8259 r->min_ttl = opts->minttl;
8260 if (opts->max_mss)
8261 r->max_mss = opts->max_mss;
8262
8263 if (opts->tag)
8264 if (strlcpy(r->tagname, opts->tag,
8265 PF_TAG_NAME_SIZE) >= PF_TAG_NAME_SIZE) {
8266 yyerror("tag too long, max %u chars",
8267 PF_TAG_NAME_SIZE - 1);
8268 return (1);
8269 }
8270 if (opts->match_tag)
8271 if (strlcpy(r->match_tagname, opts->match_tag,
8272 PF_TAG_NAME_SIZE) >= PF_TAG_NAME_SIZE) {
8273 yyerror("tag too long, max %u chars",
8274 PF_TAG_NAME_SIZE - 1);
8275 return (1);
8276 }
8277 r->match_tag_not = opts->match_tag_not;
8278
8279 if (rule_label(r, opts->label))
8280 return (1);
8281 for (int i = 0; i < PF_RULE_MAX_LABEL_COUNT; i++)
8282 free(opts->label[i]);
8283
8284 if (opts->marker & FOM_AFTO)
8285 r->rule_flag |= PFRULE_AFTO;
8286 if (opts->marker & FOM_SCRUB_TCP)
8287 r->scrub_flags |= PFSTATE_SCRUB_TCP;
8288 if (opts->marker & FOM_PRIO)
8289 r->prio = opts->prio ? opts->prio : PF_PRIO_ZERO;
8290 if (opts->marker & FOM_SETPRIO) {
8291 r->set_prio[0] = opts->set_prio[0];
8292 r->set_prio[1] = opts->set_prio[1];
8293 r->scrub_flags |= PFSTATE_SETPRIO;
8294 }
8295 if (opts->marker & FOM_SETTOS) {
8296 r->scrub_flags |= PFSTATE_SETTOS;
8297 r->set_tos = opts->settos;
8298 }
8299
8300 r->flags = opts->flags.b1;
8301 r->flagset = opts->flags.b2;
8302 if ((opts->flags.b1 & opts->flags.b2) != opts->flags.b1) {
8303 yyerror("flags always false");
8304 return (1);
8305 }
8306
8307 if (opts->queues.qname != NULL) {
8308 if (strlcpy(r->qname, opts->queues.qname,
8309 sizeof(r->qname)) >= sizeof(r->qname)) {
8310 yyerror("rule qname too long (max "
8311 "%d chars)", sizeof(r->qname)-1);
8312 return (1);
8313 }
8314 free(opts->queues.qname);
8315 }
8316 if (opts->queues.pqname != NULL) {
8317 if (strlcpy(r->pqname, opts->queues.pqname,
8318 sizeof(r->pqname)) >= sizeof(r->pqname)) {
8319 yyerror("rule pqname too long (max "
8320 "%d chars)", sizeof(r->pqname)-1);
8321 return (1);
8322 }
8323 free(opts->queues.pqname);
8324 }
8325
8326 if (opts->fragment)
8327 r->rule_flag |= PFRULE_FRAGMENT;
8328 r->allow_opts = opts->allowopts;
8329
8330 return (0);
8331 }
8332
8333 static bool
pfctl_setup_anchor(struct pfctl_rule * r,struct pfctl * pf,char * anchorname)8334 pfctl_setup_anchor(struct pfctl_rule *r, struct pfctl *pf, char *anchorname)
8335 {
8336 char *p;
8337
8338 if (pf->astack[pf->asd + 1]) {
8339 if (anchorname && strchr(anchorname, '/') != NULL) {
8340 free(anchorname);
8341 yyerror("anchor paths containing '/' "
8342 "cannot be used for inline anchors.");
8343 return (false);
8344 }
8345
8346 /* Move inline rules into relative location. */
8347 pfctl_anchor_setup(r,
8348 &pf->astack[pf->asd]->ruleset,
8349 anchorname ? anchorname : pf->alast->name);
8350
8351 if (r->anchor == NULL)
8352 err(1, "anchorrule: unable to "
8353 "create ruleset");
8354
8355 if (pf->alast != r->anchor) {
8356 if (r->anchor->match) {
8357 yyerror("inline anchor '%s' "
8358 "already exists",
8359 r->anchor->name);
8360 return (false);
8361 }
8362 mv_rules(&pf->alast->ruleset,
8363 &r->anchor->ruleset);
8364 mv_tables(pf, &pfr_ktables, r->anchor, pf->alast);
8365 }
8366 pf_remove_if_empty_ruleset(&pf->alast->ruleset);
8367 pf->alast = r->anchor;
8368 } else {
8369 if (! anchorname) {
8370 yyerror("anchors without explicit "
8371 "rules must specify a name");
8372 return (false);
8373 }
8374 /*
8375 * Don't make non-brace anchors part of the main anchor pool.
8376 */
8377 if ((r->anchor = calloc(1, sizeof(*r->anchor))) == NULL) {
8378 err(1, "anchorrule: calloc");
8379 }
8380 pf_init_ruleset(&r->anchor->ruleset);
8381 r->anchor->ruleset.anchor = r->anchor;
8382 if (strlcpy(r->anchor->path, anchorname,
8383 sizeof(r->anchor->path)) >= sizeof(r->anchor->path)) {
8384 errx(1, "anchorrule: strlcpy");
8385 }
8386 if ((p = strrchr(anchorname, '/')) != NULL) {
8387 if (strlen(p) == 1) {
8388 yyerror("anchorrule: bad anchor name %s",
8389 anchorname);
8390 return (false);
8391 }
8392 } else
8393 p = anchorname;
8394 if (strlcpy(r->anchor->name, p,
8395 sizeof(r->anchor->name)) >= sizeof(r->anchor->name)) {
8396 errx(1, "anchorrule: strlcpy");
8397 }
8398 }
8399
8400 return (true);
8401 }
8402