parse.y 148 KB
Newer Older
1
/*	$OpenBSD: parse.y,v 1.554 2008/10/17 12:59:53 henning Exp $	*/
2

3
4
5
/*-
 * SPDX-License-Identifier: BSD-2-Clause
 *
6
7
 * Copyright (c) 2001 Markus Friedl.  All rights reserved.
 * Copyright (c) 2001 Daniel Hartmeier.  All rights reserved.
8
9
 * Copyright (c) 2001 Theo de Raadt.  All rights reserved.
 * Copyright (c) 2002,2003 Henning Brauer. All rights reserved.
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
%{
David E. O'Brien's avatar
David E. O'Brien committed
32
33
34
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");

35
36
#define PFIOC_USE_LATEST

37
38
#include <sys/types.h>
#include <sys/socket.h>
Max Laier's avatar
Max Laier committed
39
#include <sys/stat.h>
40
41
42
#ifdef __FreeBSD__
#include <sys/sysctl.h>
#endif
43
44
45
46
47
48
49
50
#include <net/if.h>
#include <netinet/in.h>
#include <netinet/in_systm.h>
#include <netinet/ip.h>
#include <netinet/ip_icmp.h>
#include <netinet/icmp6.h>
#include <net/pfvar.h>
#include <arpa/inet.h>
51
52
#include <net/altq/altq.h>
#include <net/altq/altq_cbq.h>
53
#include <net/altq/altq_codel.h>
54
55
#include <net/altq/altq_priq.h>
#include <net/altq/altq_hfsc.h>
56
#include <net/altq/altq_fairq.h>
57

58
#include <assert.h>
59
#include <stdio.h>
Max Laier's avatar
Max Laier committed
60
#include <unistd.h>
61
62
63
64
65
66
#include <stdlib.h>
#include <netdb.h>
#include <stdarg.h>
#include <errno.h>
#include <string.h>
#include <ctype.h>
67
#include <math.h>
68
#include <err.h>
69
#include <limits.h>
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
#include <pwd.h>
#include <grp.h>
#include <md5.h>

#include "pfctl_parser.h"
#include "pfctl.h"

static struct pfctl	*pf = NULL;
static int		 debug = 0;
static int		 rulestate = 0;
static u_int16_t	 returnicmpdefault =
			    (ICMP_UNREACH << 8) | ICMP_UNREACH_PORT;
static u_int16_t	 returnicmp6default =
			    (ICMP6_DST_UNREACH << 8) | ICMP6_DST_UNREACH_NOPORT;
static int		 blockpolicy = PFRULE_DROP;
85
static int		 failpolicy = PFRULE_DROP;
86
static int		 require_order = 1;
87
static int		 default_statelock;
88

89
static TAILQ_HEAD(files, file)	 files = TAILQ_HEAD_INITIALIZER(files);
Max Laier's avatar
Max Laier committed
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
static struct file {
	TAILQ_ENTRY(file)	 entry;
	FILE			*stream;
	char			*name;
	int			 lineno;
	int			 errors;
} *file;
struct file	*pushfile(const char *, int);
int		 popfile(void);
int		 check_file_secrecy(int, const char *);
int		 yyparse(void);
int		 yylex(void);
int		 yyerror(const char *, ...);
int		 kw_cmp(const void *, const void *);
int		 lookup(char *);
int		 lgetc(int);
int		 lungetc(int);
int		 findeol(void);

109
static TAILQ_HEAD(symhead, sym)	 symhead = TAILQ_HEAD_INITIALIZER(symhead);
Max Laier's avatar
Max Laier committed
110
111
112
113
114
115
116
117
118
119
120
121
struct sym {
	TAILQ_ENTRY(sym)	 entry;
	int			 used;
	int			 persist;
	char			*nam;
	char			*val;
};
int		 symset(const char *, const char *, int);
char		*symget(const char *);

int		 atoul(char *, u_long *);

122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
enum {
	PFCTL_STATE_NONE,
	PFCTL_STATE_OPTION,
	PFCTL_STATE_SCRUB,
	PFCTL_STATE_QUEUE,
	PFCTL_STATE_NAT,
	PFCTL_STATE_FILTER
};

struct node_proto {
	u_int8_t		 proto;
	struct node_proto	*next;
	struct node_proto	*tail;
};

struct node_port {
	u_int16_t		 port[2];
	u_int8_t		 op;
	struct node_port	*next;
	struct node_port	*tail;
};

struct node_uid {
	uid_t			 uid[2];
	u_int8_t		 op;
	struct node_uid		*next;
	struct node_uid		*tail;
};

struct node_gid {
	gid_t			 gid[2];
	u_int8_t		 op;
	struct node_gid		*next;
	struct node_gid		*tail;
};

struct node_icmp {
	u_int8_t		 code;
	u_int8_t		 type;
	u_int8_t		 proto;
	struct node_icmp	*next;
	struct node_icmp	*tail;
};

166
enum	{ PF_STATE_OPT_MAX, PF_STATE_OPT_NOSYNC, PF_STATE_OPT_SRCTRACK,
167
168
169
	    PF_STATE_OPT_MAX_SRC_STATES, PF_STATE_OPT_MAX_SRC_CONN,
	    PF_STATE_OPT_MAX_SRC_CONN_RATE, PF_STATE_OPT_MAX_SRC_NODES,
	    PF_STATE_OPT_OVERLOAD, PF_STATE_OPT_STATELOCK,
170
	    PF_STATE_OPT_TIMEOUT, PF_STATE_OPT_SLOPPY, };
171
172
173

enum	{ PF_SRCTRACK_NONE, PF_SRCTRACK, PF_SRCTRACK_GLOBAL, PF_SRCTRACK_RULE };

174
175
176
177
struct node_state_opt {
	int			 type;
	union {
		u_int32_t	 max_states;
178
		u_int32_t	 max_src_states;
179
180
181
182
183
184
185
186
187
		u_int32_t	 max_src_conn;
		struct {
			u_int32_t	limit;
			u_int32_t	seconds;
		}		 max_src_conn_rate;
		struct {
			u_int8_t	flush;
			char		tblname[PF_TABLE_NAME_SIZE];
		}		 overload;
188
189
190
		u_int32_t	 max_src_nodes;
		u_int8_t	 src_track;
		u_int32_t	 statelock;
191
192
193
194
195
196
197
198
199
200
201
202
203
204
		struct {
			int		number;
			u_int32_t	seconds;
		}		 timeout;
	}			 data;
	struct node_state_opt	*next;
	struct node_state_opt	*tail;
};

struct peer {
	struct node_host	*host;
	struct node_port	*port;
};

205
static struct node_queue {
206
207
208
209
210
211
212
213
214
215
216
217
218
	char			 queue[PF_QNAME_SIZE];
	char			 parent[PF_QNAME_SIZE];
	char			 ifname[IFNAMSIZ];
	int			 scheduler;
	struct node_queue	*next;
	struct node_queue	*tail;
}	*queues = NULL;

struct node_qassign {
	char		*qname;
	char		*pqname;
};

219
static struct filter_opts {
220
221
222
223
224
	int			 marker;
#define FOM_FLAGS	0x01
#define FOM_ICMP	0x02
#define FOM_TOS		0x04
#define FOM_KEEP	0x08
225
#define FOM_SRCTRACK	0x10
226
227
#define FOM_SETPRIO	0x0400
#define FOM_PRIO	0x2000
228
229
230
231
232
233
234
235
236
237
	struct node_uid		*uid;
	struct node_gid		*gid;
	struct {
		u_int8_t	 b1;
		u_int8_t	 b2;
		u_int16_t	 w;
		u_int16_t	 w2;
	} flags;
	struct node_icmp	*icmpspec;
	u_int32_t		 tos;
238
	u_int32_t		 prob;
239
240
241
242
243
244
	struct {
		int			 action;
		struct node_state_opt	*options;
	} keep;
	int			 fragment;
	int			 allowopts;
245
246
	char			*label[PF_RULE_MAX_LABEL_COUNT];
	int			 labelcount;
247
248
249
250
	struct node_qassign	 queues;
	char			*tag;
	char			*match_tag;
	u_int8_t		 match_tag_not;
Kristof Provost's avatar
Kristof Provost committed
251
252
253
	u_int16_t		 dnpipe;
	u_int16_t		 dnrpipe;
	u_int32_t		 free_flags;
Max Laier's avatar
Max Laier committed
254
	u_int			 rtableid;
255
256
	u_int8_t		 prio;
	u_int8_t		 set_prio[2];
257
258
259
260
	struct {
		struct node_host	*addr;
		u_int16_t		port;
	}			 divert;
261
262
} filter_opts;

263
static struct antispoof_opts {
264
265
	char			*label[PF_RULE_MAX_LABEL_COUNT];
	int			 labelcount;
Max Laier's avatar
Max Laier committed
266
	u_int			 rtableid;
267
268
} antispoof_opts;

269
static struct scrub_opts {
270
	int			 marker;
271
272
273
#define SOM_MINTTL	0x01
#define SOM_MAXMSS	0x02
#define SOM_FRAGCACHE	0x04
274
#define SOM_SETTOS	0x08
275
276
277
278
279
280
281
282
283
284
	int			 nodf;
	int			 minttl;
	int			 maxmss;
	int			 settos;
	int			 fragcache;
	int			 randomid;
	int			 reassemble_tcp;
	char			*match_tag;
	u_int8_t		 match_tag_not;
	u_int			 rtableid;
285
286
} scrub_opts;

287
static struct queue_opts {
288
289
290
291
292
293
294
295
296
	int			marker;
#define QOM_BWSPEC	0x01
#define QOM_SCHEDULER	0x02
#define QOM_PRIORITY	0x04
#define QOM_TBRSIZE	0x08
#define QOM_QLIMIT	0x10
	struct node_queue_bw	queue_bwspec;
	struct node_queue_opt	scheduler;
	int			priority;
297
	unsigned int		tbrsize;
298
299
300
	int			qlimit;
} queue_opts;

301
static struct table_opts {
302
303
304
305
306
	int			flags;
	int			init_addr;
	struct node_tinithead	init_nodes;
} table_opts;

307
static struct pool_opts {
308
309
310
311
312
313
314
	int			 marker;
#define POM_TYPE		0x01
#define POM_STICKYADDRESS	0x02
	u_int8_t		 opts;
	int			 type;
	int			 staticport;
	struct pf_poolhashkey	*key;
315
	struct pf_mape_portset	 mape;
316
317
318

} pool_opts;

319
320
321
322
static struct codel_opts	 codel_opts;
static struct node_hfsc_opts	 hfsc_opts;
static struct node_fairq_opts	 fairq_opts;
static struct node_state_opt	*keep_state_defaults = NULL;
323

Max Laier's avatar
Max Laier committed
324
325
326
int		 disallow_table(struct node_host *, const char *);
int		 disallow_urpf_failed(struct node_host *, const char *);
int		 disallow_alias(struct node_host *, const char *);
327
328
329
330
int		 rule_consistent(struct pfctl_rule *, int);
int		 filter_consistent(struct pfctl_rule *, int);
int		 nat_consistent(struct pfctl_rule *);
int		 rdr_consistent(struct pfctl_rule *);
Max Laier's avatar
Max Laier committed
331
332
333
334
335
336
337
338
339
340
341
342
int		 process_tabledef(char *, struct table_opts *);
void		 expand_label_str(char *, size_t, const char *, const char *);
void		 expand_label_if(const char *, char *, size_t, const char *);
void		 expand_label_addr(const char *, char *, size_t, u_int8_t,
		    struct node_host *);
void		 expand_label_port(const char *, char *, size_t,
		    struct node_port *);
void		 expand_label_proto(const char *, char *, size_t, u_int8_t);
void		 expand_label_nr(const char *, char *, size_t);
void		 expand_label(char *, size_t, const char *, u_int8_t,
		    struct node_host *, struct node_port *, struct node_host *,
		    struct node_port *, u_int8_t);
343
void		 expand_rule(struct pfctl_rule *, struct node_if *,
Max Laier's avatar
Max Laier committed
344
345
346
347
348
349
350
351
352
353
354
		    struct node_host *, struct node_proto *, struct node_os *,
		    struct node_host *, struct node_port *, struct node_host *,
		    struct node_port *, struct node_uid *, struct node_gid *,
		    struct node_icmp *, const char *);
int		 expand_altq(struct pf_altq *, struct node_if *,
		    struct node_queue *, struct node_queue_bw bwspec,
		    struct node_queue_opt *);
int		 expand_queue(struct pf_altq *, struct node_if *,
		    struct node_queue *, struct node_queue_bw,
		    struct node_queue_opt *);
int		 expand_skip_interface(struct node_if *);
355
356
357

int	 check_rulestate(int);
int	 getservice(char *);
358
int	 rule_label(struct pfctl_rule *, char *s[PF_RULE_MAX_LABEL_COUNT]);
359
int	 rt_tableid_max(void);
360

361
void	 mv_rules(struct pfctl_ruleset *, struct pfctl_ruleset *);
362
363
364
365
void	 decide_address_family(struct node_host *, sa_family_t *);
void	 remove_invalid_hosts(struct node_host **, sa_family_t *);
int	 invalid_redirect(struct node_host *, sa_family_t);
u_int16_t parseicmpspec(char *, sa_family_t);
366
367
int	 kw_casecmp(const void *, const void *);
int	 map_tos(char *string, int *);
368

369
static TAILQ_HEAD(loadanchorshead, loadanchors)
370
371
    loadanchorshead = TAILQ_HEAD_INITIALIZER(loadanchorshead);

372
373
374
375
376
377
378
379
struct loadanchors {
	TAILQ_ENTRY(loadanchors)	 entries;
	char				*anchorname;
	char				*filename;
};

typedef struct {
	union {
Max Laier's avatar
Max Laier committed
380
381
		int64_t			 number;
		double			 probability;
382
383
		int			 i;
		char			*string;
Max Laier's avatar
Max Laier committed
384
		u_int			 rtableid;
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
		struct {
			u_int8_t	 b1;
			u_int8_t	 b2;
			u_int16_t	 w;
			u_int16_t	 w2;
		}			 b;
		struct range {
			int		 a;
			int		 b;
			int		 t;
		}			 range;
		struct node_if		*interface;
		struct node_proto	*proto;
		struct node_icmp	*icmp;
		struct node_host	*host;
		struct node_os		*os;
		struct node_port	*port;
		struct node_uid		*uid;
		struct node_gid		*gid;
		struct node_state_opt	*state_opt;
		struct peer		 peer;
		struct {
			struct peer	 src, dst;
			struct node_os	*src_os;
		}			 fromto;
		struct {
			struct node_host	*host;
			u_int8_t		 rt;
			u_int8_t		 pool_opts;
			sa_family_t		 af;
			struct pf_poolhashkey	*key;
		}			 route;
		struct redirection {
			struct node_host	*host;
			struct range		 rport;
		}			*redirection;
		struct {
			int			 action;
			struct node_state_opt	*options;
		}			 keep_state;
		struct {
			u_int8_t	 log;
427
			u_int8_t	 logif;
428
429
			u_int8_t	 quick;
		}			 logquick;
430
431
432
433
		struct {
			int		 neg;
			char		*name;
		}			 tagged;
434
		struct pf_poolhashkey	*hashkey;
435
436
437
438
439
440
441
442
443
		struct node_queue	*queue;
		struct node_queue_opt	 queue_options;
		struct node_queue_bw	 queue_bwspec;
		struct node_qassign	 qassign;
		struct filter_opts	 filter_opts;
		struct antispoof_opts	 antispoof_opts;
		struct queue_opts	 queue_opts;
		struct scrub_opts	 scrub_opts;
		struct table_opts	 table_opts;
444
		struct pool_opts	 pool_opts;
445
		struct node_hfsc_opts	 hfsc_opts;
446
		struct node_fairq_opts	 fairq_opts;
447
		struct codel_opts	 codel_opts;
448
449
450
451
	} v;
	int lineno;
} YYSTYPE;

452
453
454
455
#define PPORT_RANGE	1
#define PPORT_STAR	2
int	parseport(char *, struct range *r, int);

456
457
458
459
#define DYNIF_MULTIADDR(addr) ((addr).type == PF_ADDR_DYNIFTL && \
	(!((addr).iflags & PFI_AFLAG_NOALIAS) ||		 \
	!isdigit((addr).v.ifname[strlen((addr).v.ifname)-1])))

460
461
%}

Kristof Provost's avatar
Kristof Provost committed
462
%token	PASS BLOCK MATCH SCRUB RETURN IN OS OUT LOG QUICK ON FROM TO FLAGS
463
464
465
%token	RETURNRST RETURNICMP RETURNICMP6 PROTO INET INET6 ALL ANY ICMPTYPE
%token	ICMP6TYPE CODE KEEP MODULATE STATE PORT RDR NAT BINAT ARROW NODF
%token	MINTTL ERROR ALLOWOPTS FASTROUTE FILENAME ROUTETO DUPTO REPLYTO NO LABEL
466
%token	NOROUTE URPFFAILED FRAGMENT USER GROUP MAXMSS MAXIMUM TTL TOS DROP TABLE
467
%token	REASSEMBLE FRAGDROP FRAGCROP ANCHOR NATANCHOR RDRANCHOR BINATANCHOR
468
469
%token	SET OPTIMIZATION TIMEOUT LIMIT LOGINTERFACE BLOCKPOLICY FAILPOLICY
%token	RANDOMID REQUIREORDER SYNPROXY FINGERPRINTS NOSYNC DEBUG SKIP HOSTID
470
%token	ANTISPOOF FOR INCLUDE KEEPCOUNTERS SYNCOOKIES
471
%token	BITMASK RANDOM SOURCEHASH ROUNDROBIN STATICPORT PROBABILITY MAPEPORTSET
472
473
%token	ALTQ CBQ CODEL PRIQ HFSC FAIRQ BANDWIDTH TBRSIZE LINKSHARE REALTIME
%token	UPPERLIMIT QUEUE PRIORITY QLIMIT HOGS BUCKETS RTABLE TARGET INTERVAL
Kristof Provost's avatar
Kristof Provost committed
474
%token	DNPIPE DNQUEUE
475
%token	LOAD RULESET_OPTIMIZATION PRIO
476
%token	STICKYADDRESS MAXSRCSTATES MAXSRCNODES SOURCETRACK GLOBAL RULE
477
%token	MAXSRCCONN MAXSRCCONNRATE OVERLOAD FLUSH SLOPPY
478
%token	TAGGED TAG IFBOUND FLOATING STATEPOLICY STATEDEFAULTS ROUTE SETTOS
479
%token	DIVERTTO DIVERTREPLY
480
%token	<v.string>		STRING
Max Laier's avatar
Max Laier committed
481
%token	<v.number>		NUMBER
482
483
484
%token	<v.i>			PORTBINARY
%type	<v.interface>		interface if_list if_item_not if_item
%type	<v.number>		number icmptype icmp6type uid gid
485
%type	<v.number>		tos not yesno
Max Laier's avatar
Max Laier committed
486
%type	<v.probability>		probability
487
%type	<v.i>			no dir af fragcache optimizer syncookie_val
488
%type	<v.i>			sourcetrack flush unaryop statelock
Max Laier's avatar
Max Laier committed
489
%type	<v.b>			action nataction natpasslog scrubaction
490
%type	<v.b>			flags flag blockspec prio
491
%type	<v.range>		portplain portstar portrange
492
493
%type	<v.hashkey>		hashkey
%type	<v.proto>		proto proto_list proto_item
Max Laier's avatar
Max Laier committed
494
%type	<v.number>		protoval
495
496
497
%type	<v.icmp>		icmpspec
%type	<v.icmp>		icmp_list icmp_item
%type	<v.icmp>		icmp6_list icmp6_item
Max Laier's avatar
Max Laier committed
498
%type	<v.number>		reticmpspec reticmp6spec
499
500
%type	<v.fromto>		fromto
%type	<v.peer>		ipportspec from to
501
%type	<v.host>		ipspec toipspec xhost host dynaddr host_list
502
503
504
505
506
507
508
509
%type	<v.host>		redir_host_list redirspec
%type	<v.host>		route_host route_host_list routespec
%type	<v.os>			os xos os_list
%type	<v.port>		portspec port_list port_item
%type	<v.uid>			uids uid_list uid_item
%type	<v.gid>			gids gid_list gid_item
%type	<v.route>		route
%type	<v.redirection>		redirection redirpool
510
511
%type	<v.string>		label stringall tag anchorname
%type	<v.string>		string varstring numberstring
512
513
%type	<v.keep_state>		keep
%type	<v.state_opt>		state_opt_spec state_opt_list state_opt_item
514
%type	<v.logquick>		logquick quick log logopts logopt
515
%type	<v.interface>		antispoof_ifspc antispoof_iflst antispoof_if
516
517
518
519
520
521
%type	<v.qassign>		qname
%type	<v.queue>		qassign qassign_list qassign_item
%type	<v.queue_options>	scheduler
%type	<v.number>		cbqflags_list cbqflags_item
%type	<v.number>		priqflags_list priqflags_item
%type	<v.hfsc_opts>		hfscopts_list hfscopts_item hfsc_opts
522
%type	<v.fairq_opts>		fairqopts_list fairqopts_item fairq_opts
523
%type	<v.codel_opts>		codelopts_list codelopts_item codel_opts
524
525
%type	<v.queue_bwspec>	bandwidth
%type	<v.filter_opts>		filter_opts filter_opt filter_opts_l
526
%type	<v.filter_opts>		filter_sets filter_set filter_sets_l
527
528
529
530
%type	<v.antispoof_opts>	antispoof_opts antispoof_opt antispoof_opts_l
%type	<v.queue_opts>		queue_opts queue_opt queue_opts_l
%type	<v.scrub_opts>		scrub_opts scrub_opt scrub_opts_l
%type	<v.table_opts>		table_opts table_opt table_opts_l
531
%type	<v.pool_opts>		pool_opts pool_opt pool_opts_l
532
%type	<v.tagged>		tagged
533
%type	<v.rtableid>		rtable
534
535
536
%%

ruleset		: /* empty */
Max Laier's avatar
Max Laier committed
537
		| ruleset include '\n'
538
539
540
541
542
543
544
545
546
547
548
549
550
		| ruleset '\n'
		| ruleset option '\n'
		| ruleset scrubrule '\n'
		| ruleset natrule '\n'
		| ruleset binatrule '\n'
		| ruleset pfrule '\n'
		| ruleset anchorrule '\n'
		| ruleset loadrule '\n'
		| ruleset altqif '\n'
		| ruleset queuespec '\n'
		| ruleset varset '\n'
		| ruleset antispoof '\n'
		| ruleset tabledef '\n'
551
		| '{' fakeanchor '}' '\n';
Max Laier's avatar
Max Laier committed
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
		| ruleset error '\n'		{ file->errors++; }
		;

include		: INCLUDE STRING		{
			struct file	*nfile;

			if ((nfile = pushfile($2, 0)) == NULL) {
				yyerror("failed to include file %s", $2);
				free($2);
				YYERROR;
			}
			free($2);

			file = nfile;
			lungetc('\n');
		}
568
569
		;

570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
/*
 * apply to previouslys specified rule: must be careful to note
 * what that is: pf or nat or binat or rdr
 */
fakeanchor	: fakeanchor '\n'
		| fakeanchor anchorrule '\n'
		| fakeanchor binatrule '\n'
		| fakeanchor natrule '\n'
		| fakeanchor pfrule '\n'
		| fakeanchor error '\n'
		;

optimizer	: string	{
			if (!strcmp($1, "none"))
				$$ = 0;
			else if (!strcmp($1, "basic"))
				$$ = PF_OPTIMIZE_BASIC;
			else if (!strcmp($1, "profile"))
				$$ = PF_OPTIMIZE_BASIC | PF_OPTIMIZE_PROFILE;
			else {
590
				yyerror("unknown ruleset-optimization %s", $1);
591
592
593
594
595
				YYERROR;
			}
		}
		;

596
option		: SET OPTIMIZATION STRING		{
597
598
			if (check_rulestate(PFCTL_STATE_OPTION)) {
				free($3);
599
				YYERROR;
600
			}
601
602
			if (pfctl_set_optimization(pf, $3) != 0) {
				yyerror("unknown optimization %s", $3);
603
				free($3);
604
605
				YYERROR;
			}
606
607
608
609
610
611
612
			free($3);
		}
		| SET RULESET_OPTIMIZATION optimizer {
			if (!(pf->opts & PF_OPT_OPTIMIZE)) {
				pf->opts |= PF_OPT_OPTIMIZE;
				pf->optimize = $3;
			}
613
614
		}
		| SET TIMEOUT timeout_spec
615
		| SET TIMEOUT '{' optnl timeout_list '}'
616
		| SET LIMIT limit_spec
617
		| SET LIMIT '{' optnl limit_list '}'
Max Laier's avatar
Max Laier committed
618
		| SET LOGINTERFACE stringall		{
619
620
			if (check_rulestate(PFCTL_STATE_OPTION)) {
				free($3);
621
				YYERROR;
622
			}
623
624
			if (pfctl_set_logif(pf, $3) != 0) {
				yyerror("error setting loginterface %s", $3);
625
626
627
628
629
630
				free($3);
				YYERROR;
			}
			free($3);
		}
		| SET HOSTID number {
Max Laier's avatar
Max Laier committed
631
			if ($3 == 0 || $3 > UINT_MAX) {
632
633
634
635
				yyerror("hostid must be non-zero");
				YYERROR;
			}
			if (pfctl_set_hostid(pf, $3) != 0) {
636
				yyerror("error setting hostid %08x", $3);
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
				YYERROR;
			}
		}
		| SET BLOCKPOLICY DROP	{
			if (pf->opts & PF_OPT_VERBOSE)
				printf("set block-policy drop\n");
			if (check_rulestate(PFCTL_STATE_OPTION))
				YYERROR;
			blockpolicy = PFRULE_DROP;
		}
		| SET BLOCKPOLICY RETURN {
			if (pf->opts & PF_OPT_VERBOSE)
				printf("set block-policy return\n");
			if (check_rulestate(PFCTL_STATE_OPTION))
				YYERROR;
			blockpolicy = PFRULE_RETURN;
		}
654
655
656
657
658
659
660
661
662
663
664
665
666
667
		| SET FAILPOLICY DROP	{
			if (pf->opts & PF_OPT_VERBOSE)
				printf("set fail-policy drop\n");
			if (check_rulestate(PFCTL_STATE_OPTION))
				YYERROR;
			failpolicy = PFRULE_DROP;
		}
		| SET FAILPOLICY RETURN {
			if (pf->opts & PF_OPT_VERBOSE)
				printf("set fail-policy return\n");
			if (check_rulestate(PFCTL_STATE_OPTION))
				YYERROR;
			failpolicy = PFRULE_RETURN;
		}
668
669
670
671
672
673
674
675
		| SET REQUIREORDER yesno {
			if (pf->opts & PF_OPT_VERBOSE)
				printf("set require-order %s\n",
				    $3 == 1 ? "yes" : "no");
			require_order = $3;
		}
		| SET FINGERPRINTS STRING {
			if (pf->opts & PF_OPT_VERBOSE)
676
				printf("set fingerprints \"%s\"\n", $3);
677
678
			if (check_rulestate(PFCTL_STATE_OPTION)) {
				free($3);
679
				YYERROR;
680
			}
681
			if (!pf->anchor->name[0]) {
682
683
684
685
686
687
688
				if (pfctl_file_fingerprints(pf->dev,
				    pf->opts, $3)) {
					yyerror("error loading "
					    "fingerprints %s", $3);
					free($3);
					YYERROR;
				}
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
			}
			free($3);
		}
		| SET STATEPOLICY statelock {
			if (pf->opts & PF_OPT_VERBOSE)
				switch ($3) {
				case 0:
					printf("set state-policy floating\n");
					break;
				case PFRULE_IFBOUND:
					printf("set state-policy if-bound\n");
					break;
				}
			default_statelock = $3;
		}
		| SET DEBUG STRING {
			if (check_rulestate(PFCTL_STATE_OPTION)) {
				free($3);
				YYERROR;
			}
			if (pfctl_set_debug(pf, $3) != 0) {
				yyerror("error setting debuglevel %s", $3);
				free($3);
712
713
				YYERROR;
			}
714
			free($3);
715
		}
716
717
718
719
720
721
		| SET SKIP interface {
			if (expand_skip_interface($3) != 0) {
				yyerror("error setting skip interface(s)");
				YYERROR;
			}
		}
722
723
724
725
726
727
728
		| SET STATEDEFAULTS state_opt_list {
			if (keep_state_defaults != NULL) {
				yyerror("cannot redefine state-defaults");
				YYERROR;
			}
			keep_state_defaults = $3;
		}
729
730
731
		| SET KEEPCOUNTERS {
			pf->keep_counters = true;
		}
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
		| SET SYNCOOKIES syncookie_val {
			pf->syncookies = $3;
		}
		;

syncookie_val  : STRING        {
			if (!strcmp($1, "never"))
				$$ = PFCTL_SYNCOOKIES_NEVER;
			else if (!strcmp($1, "always"))
				$$ = PFCTL_SYNCOOKIES_ALWAYS;
			else {
				yyerror("illegal value for syncookies");
				YYERROR;
			}
		}
747
748
		;

Max Laier's avatar
Max Laier committed
749
750
751
752
753
754
stringall	: STRING	{ $$ = $1; }
		| ALL		{
			if (($$ = strdup("all")) == NULL) {
				err(1, "stringall: strdup");
			}
		}
755
756
		;

757
string		: STRING string				{
758
759
760
761
762
763
764
765
			if (asprintf(&$$, "%s %s", $1, $2) == -1)
				err(1, "string: asprintf");
			free($1);
			free($2);
		}
		| STRING
		;

766
767
768
varstring	: numberstring varstring 		{
			if (asprintf(&$$, "%s %s", $1, $2) == -1)
				err(1, "string: asprintf");
769
			free($1);
770
			free($2);
771
		}
772
773
774
775
		| numberstring
		;

numberstring	: NUMBER				{
Max Laier's avatar
Max Laier committed
776
			char	*s;
777
			if (asprintf(&s, "%lld", (long long)$1) == -1) {
Max Laier's avatar
Max Laier committed
778
779
780
				yyerror("string: asprintf");
				YYERROR;
			}
781
782
783
784
785
786
			$$ = s;
		}
		| STRING
		;

varset		: STRING '=' varstring	{
787
			char *s = $1;
788
789
			if (pf->opts & PF_OPT_VERBOSE)
				printf("%s = \"%s\"\n", $1, $3);
790
791
792
793
794
795
796
			while (*s++) {
				if (isspace((unsigned char)*s)) {
					yyerror("macro name cannot contain "
					   "whitespace");
					YYERROR;
				}
			}
797
798
			if (symset($1, $3, 0) == -1)
				err(1, "cannot store variable %s", $1);
799
800
			free($1);
			free($3);
801
802
803
		}
		;

804
805
806
807
anchorname	: STRING			{ $$ = $1; }
		| /* empty */			{ $$ = NULL; }
		;

808
809
810
811
pfa_anchorlist	: /* empty */
		| pfa_anchorlist '\n'
		| pfa_anchorlist pfrule '\n'
		| pfa_anchorlist anchorrule '\n'
812
813
814
815
816
		;

pfa_anchor	: '{'
		{
			char ta[PF_ANCHOR_NAME_SIZE];
817
			struct pfctl_ruleset *rs;
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842

			/* steping into a brace anchor */
			pf->asd++;
			pf->bn++;
			pf->brace = 1;

			/* create a holding ruleset in the root */
			snprintf(ta, PF_ANCHOR_NAME_SIZE, "_%d", pf->bn);
			rs = pf_find_or_create_ruleset(ta);
			if (rs == NULL)
				err(1, "pfa_anchor: pf_find_or_create_ruleset");
			pf->astack[pf->asd] = rs->anchor;
			pf->anchor = rs->anchor;
		} '\n' pfa_anchorlist '}'
		{
			pf->alast = pf->anchor;
			pf->asd--;
			pf->anchor = pf->astack[pf->asd];
		}
		| /* empty */
		;

anchorrule	: ANCHOR anchorname dir quick interface af proto fromto
		    filter_opts pfa_anchor
		{
843
			struct pfctl_rule	r;
Max Laier's avatar
Max Laier committed
844
			struct node_proto	*proto;
845

846
			if (check_rulestate(PFCTL_STATE_FILTER)) {
847
848
849
850
851
852
				if ($2)
					free($2);
				YYERROR;
			}

			if ($2 && ($2[0] == '_' || strstr($2, "/_") != NULL)) {
853
				free($2);
854
855
				yyerror("anchor names beginning with '_' "
				    "are reserved for internal use");
856
				YYERROR;
857
			}
858

859
			memset(&r, 0, sizeof(r));
860
861
			if (pf->astack[pf->asd + 1]) {
				/* move inline rules into relative location */
862
				pfctl_anchor_setup(&r,
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
				    &pf->astack[pf->asd]->ruleset,
				    $2 ? $2 : pf->alast->name);
		
				if (r.anchor == NULL)
					err(1, "anchorrule: unable to "
					    "create ruleset");

				if (pf->alast != r.anchor) {
					if (r.anchor->match) {
						yyerror("inline anchor '%s' "
						    "already exists",
						    r.anchor->name);
						YYERROR;
					}
					mv_rules(&pf->alast->ruleset,
					    &r.anchor->ruleset);
				}
				pf_remove_if_empty_ruleset(&pf->alast->ruleset);
				pf->alast = r.anchor;
			} else {
				if (!$2) {
					yyerror("anchors without explicit "
					    "rules must specify a name");
					YYERROR;
				}
			}
889
			r.direction = $3;
890
891
892
893
			r.quick = $4.quick;
			r.af = $6;
			r.prob = $9.prob;
			r.rtableid = $9.rtableid;
894

Max Laier's avatar
Max Laier committed
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
			if ($9.tag)
				if (strlcpy(r.tagname, $9.tag,
				    PF_TAG_NAME_SIZE) >= PF_TAG_NAME_SIZE) {
					yyerror("tag too long, max %u chars",
					    PF_TAG_NAME_SIZE - 1);
					YYERROR;
				}
			if ($9.match_tag)
				if (strlcpy(r.match_tagname, $9.match_tag,
				    PF_TAG_NAME_SIZE) >= PF_TAG_NAME_SIZE) {
					yyerror("tag too long, max %u chars",
					    PF_TAG_NAME_SIZE - 1);
					YYERROR;
				}
			r.match_tag_not = $9.match_tag_not;
			if (rule_label(&r, $9.label))
				YYERROR;
912
913
			for (int i = 0; i < PF_RULE_MAX_LABEL_COUNT; i++)
				free($9.label[i]);
Max Laier's avatar
Max Laier committed
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
			r.flags = $9.flags.b1;
			r.flagset = $9.flags.b2;
			if (($9.flags.b1 & $9.flags.b2) != $9.flags.b1) {
				yyerror("flags always false");
				YYERROR;
			}
			if ($9.flags.b1 || $9.flags.b2 || $8.src_os) {
				for (proto = $7; proto != NULL &&
				    proto->proto != IPPROTO_TCP;
				    proto = proto->next)
					;	/* nothing */
				if (proto == NULL && $7 != NULL) {
					if ($9.flags.b1 || $9.flags.b2)
						yyerror(
						    "flags only apply to tcp");
					if ($8.src_os)
						yyerror(
						    "OS fingerprinting only "
						    "applies to tcp");
					YYERROR;
				}
			}

			r.tos = $9.tos;

			if ($9.keep.action) {
				yyerror("cannot specify state handling "
				    "on anchors");
				YYERROR;
			}

945
946
			if ($9.match_tag)
				if (strlcpy(r.match_tagname, $9.match_tag,
947
948
949
950
951
				    PF_TAG_NAME_SIZE) >= PF_TAG_NAME_SIZE) {
					yyerror("tag too long, max %u chars",
					    PF_TAG_NAME_SIZE - 1);
					YYERROR;
				}
952
			r.match_tag_not = $9.match_tag_not;
953
954
955
956
957
958
959
960
961
962
963
			if ($9.marker & FOM_PRIO) {
				if ($9.prio == 0)
					r.prio = PF_PRIO_ZERO;
				else
					r.prio = $9.prio;
			}
			if ($9.marker & FOM_SETPRIO) {
				r.set_prio[0] = $9.set_prio[0];
				r.set_prio[1] = $9.set_prio[1];
				r.scrub_flags |= PFSTATE_SETPRIO;
			}
964

965
966
			decide_address_family($8.src.host, &r.af);
			decide_address_family($8.dst.host, &r.af);
967

968
969
			expand_rule(&r, $5, NULL, $7, $8.src_os,
			    $8.src.host, $8.src.port, $8.dst.host, $8.dst.port,
Max Laier's avatar
Max Laier committed
970
971
			    $9.uid, $9.gid, $9.icmpspec,
			    pf->astack[pf->asd + 1] ? pf->alast->name : $2);
972
			free($2);
973
			pf->astack[pf->asd + 1] = NULL;
974
		}
975
		| NATANCHOR string interface af proto fromto rtable {
976
			struct pfctl_rule	r;
977

978
979
			if (check_rulestate(PFCTL_STATE_NAT)) {
				free($2);
980
				YYERROR;
981
			}
982

983
			memset(&r, 0, sizeof(r));
984
985
			r.action = PF_NAT;
			r.af = $4;
986
			r.rtableid = $7;
987
988
989
990
991
992

			decide_address_family($6.src.host, &r.af);
			decide_address_family($6.dst.host, &r.af);

			expand_rule(&r, $3, NULL, $5, $6.src_os,
			    $6.src.host, $6.src.port, $6.dst.host, $6.dst.port,
993
994
			    0, 0, 0, $2);
			free($2);
995
		}
996
		| RDRANCHOR string interface af proto fromto rtable {
997
			struct pfctl_rule	r;
998

999
1000
			if (check_rulestate(PFCTL_STATE_NAT)) {
				free($2);
For faster browsing, not all history is shown. View entire blame