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