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