ipf_y.y revision 170268
1199969Savg/*	$FreeBSD: head/contrib/ipfilter/tools/ipf_y.y 170268 2007-06-04 02:54:36Z darrenr $	*/
2199969Savg
3199969Savg/*
4199969Savg * Copyright (C) 2001-2006 by Darren Reed.
5199969Savg *
6199969Savg * See the IPFILTER.LICENCE file for details on licencing.
7199969Savg */
8199969Savg%{
9199969Savg#include "ipf.h"
10199969Savg#include <sys/ioctl.h>
11199969Savg#include <syslog.h>
12199969Savg#ifdef IPFILTER_BPF
13199969Savg# include "pcap-bpf.h"
14199969Savg# define _NET_BPF_H_
15199969Savg# include <pcap.h>
16199969Savg#endif
17199969Savg#include "netinet/ip_pool.h"
18199969Savg#include "netinet/ip_htable.h"
19199969Savg#include "netinet/ipl.h"
20199969Savg#include "ipf_l.h"
21199969Savg
22199969Savg#define	YYDEBUG	1
23199969Savg#define	DOALL(x)	for (fr = frc; fr != NULL; fr = fr->fr_next) { x }
24199969Savg#define	DOREM(x)	for (; fr != NULL; fr = fr->fr_next) { x }
25199969Savg
26199969Savgextern	void	yyerror __P((char *));
27199969Savgextern	int	yyparse __P((void));
28222805Savgextern	int	yylex __P((void));
29199969Savgextern	int	yydebug;
30199969Savgextern	FILE	*yyin;
31199969Savgextern	int	yylineNum;
32199969Savg
33222805Savgstatic	void	newrule __P((void));
34199969Savgstatic	void	setipftype __P((void));
35199969Savgstatic	u_32_t	lookuphost __P((char *));
36199969Savgstatic	void	dobpf __P((int, char *));
37199969Savgstatic	void	resetaddr __P((void));
38199969Savgstatic	struct	alist_s	*newalist __P((struct alist_s *));
39199969Savgstatic	u_int	makehash __P((struct alist_s *));
40199969Savgstatic	int	makepool __P((struct alist_s *));
41199969Savgstatic	frentry_t *addrule __P((void));
42199969Savgstatic	void	setsyslog __P((void));
43199969Savgstatic	void	unsetsyslog __P((void));
44199969Savgstatic	void	fillgroup __P((frentry_t *));
45199969Savg
46199969Savgfrentry_t	*fr = NULL, *frc = NULL, *frtop = NULL, *frold = NULL;
47199969Savg
48199969Savgstatic	int		ifpflag = 0;
49199969Savgstatic	int		nowith = 0;
50199969Savgstatic	int		dynamic = -1;
51199969Savgstatic	int		pooled = 0;
52199969Savgstatic	int		hashed = 0;
53199969Savgstatic	int		nrules = 0;
54222805Savgstatic	int		newlist = 0;
55199969Savgstatic	int		added = 0;
56199969Savgstatic	int		ipffd = -1;
57199969Savgstatic	int		*yycont = 0;
58199969Savgstatic	ioctlfunc_t	ipfioctl[IPL_LOGSIZE];
59199969Savgstatic	addfunc_t	ipfaddfunc = NULL;
60199969Savgstatic	struct	wordtab ipfwords[95];
61199969Savgstatic	struct	wordtab	addrwords[4];
62199969Savgstatic	struct	wordtab	maskwords[5];
63199969Savgstatic	struct	wordtab icmpcodewords[17];
64222721Savgstatic	struct	wordtab icmptypewords[16];
65222721Savgstatic	struct	wordtab ipv4optwords[25];
66222721Savgstatic	struct	wordtab ipv4secwords[9];
67199969Savgstatic	struct	wordtab ipv6optwords[9];
68199969Savgstatic	struct	wordtab logwords[33];
69199969Savg
70199969Savg%}
71199969Savg%union	{
72222720Savg	char	*str;
73199969Savg	u_32_t	num;
74222720Savg	struct	in_addr	ipa;
75	frentry_t	fr;
76	frtuc_t	*frt;
77	struct	alist_s	*alist;
78	u_short	port;
79	struct	{
80		u_short	p1;
81		u_short	p2;
82		int	pc;
83	} pc;
84	struct	{
85		union	i6addr	a;
86		union	i6addr	m;
87	} ipp;
88	union	i6addr	ip6;
89	struct	{
90		char	*if1;
91		char	*if2;
92	} ifs;
93};
94
95%type	<port>	portnum
96%type	<num>	facility priority icmpcode seclevel secname icmptype
97%type	<num>	opt compare range opttype flagset optlist ipv6hdrlist ipv6hdr
98%type	<num>	portc porteq
99%type	<ipa>	hostname ipv4 ipv4mask ipv4_16 ipv4_24
100%type	<ip6>	ipv6mask
101%type	<ipp>	addr ipaddr
102%type	<str>	servicename name interfacename
103%type	<pc>	portrange portcomp
104%type	<alist>	addrlist poollist
105%type	<ifs>	onname
106
107%token	<num>	YY_NUMBER YY_HEX
108%token	<str>	YY_STR
109%token		YY_COMMENT
110%token		YY_CMP_EQ YY_CMP_NE YY_CMP_LE YY_CMP_GE YY_CMP_LT YY_CMP_GT
111%token		YY_RANGE_OUT YY_RANGE_IN
112%token	<ip6>	YY_IPV6
113
114%token	IPFY_PASS IPFY_BLOCK IPFY_COUNT IPFY_CALL IPFY_NOMATCH
115%token	IPFY_RETICMP IPFY_RETRST IPFY_RETICMPASDST
116%token	IPFY_IN IPFY_OUT
117%token	IPFY_QUICK IPFY_ON IPFY_OUTVIA IPFY_INVIA
118%token	IPFY_DUPTO IPFY_TO IPFY_FROUTE IPFY_REPLY_TO IPFY_ROUTETO
119%token	IPFY_TOS IPFY_TTL IPFY_PROTO
120%token	IPFY_HEAD IPFY_GROUP
121%token	IPFY_AUTH IPFY_PREAUTH
122%token	IPFY_LOG IPFY_BODY IPFY_FIRST IPFY_LEVEL IPFY_ORBLOCK
123%token	IPFY_LOGTAG IPFY_MATCHTAG IPFY_SETTAG IPFY_SKIP
124%token	IPFY_FROM IPFY_ALL IPFY_ANY IPFY_BPFV4 IPFY_BPFV6 IPFY_POOL IPFY_HASH
125%token	IPFY_PPS
126%token	IPFY_ESP IPFY_AH
127%token	IPFY_WITH IPFY_AND IPFY_NOT IPFY_NO IPFY_OPT
128%token	IPFY_TCPUDP IPFY_TCP IPFY_UDP
129%token	IPFY_FLAGS IPFY_MULTICAST
130%token	IPFY_MASK IPFY_BROADCAST IPFY_NETWORK IPFY_NETMASKED IPFY_PEER
131%token	IPFY_PORT
132%token	IPFY_NOW
133%token	IPFY_ICMP IPFY_ICMPTYPE IPFY_ICMPCODE
134%token	IPFY_IPOPTS IPFY_SHORT IPFY_NAT IPFY_BADSRC IPFY_LOWTTL IPFY_FRAG
135%token	IPFY_MBCAST IPFY_BAD IPFY_BADNAT IPFY_OOW IPFY_NEWISN IPFY_NOICMPERR
136%token	IPFY_KEEP IPFY_STATE IPFY_FRAGS IPFY_LIMIT IPFY_STRICT IPFY_AGE
137%token	IPFY_SYNC IPFY_FRAGBODY
138%token	IPFY_IPOPT_NOP IPFY_IPOPT_RR IPFY_IPOPT_ZSU IPFY_IPOPT_MTUP
139%token	IPFY_IPOPT_MTUR IPFY_IPOPT_ENCODE IPFY_IPOPT_TS IPFY_IPOPT_TR
140%token	IPFY_IPOPT_SEC IPFY_IPOPT_LSRR IPFY_IPOPT_ESEC IPFY_IPOPT_CIPSO
141%token	IPFY_IPOPT_SATID IPFY_IPOPT_SSRR IPFY_IPOPT_ADDEXT IPFY_IPOPT_VISA
142%token	IPFY_IPOPT_IMITD IPFY_IPOPT_EIP IPFY_IPOPT_FINN IPFY_IPOPT_DPS
143%token	IPFY_IPOPT_SDB IPFY_IPOPT_NSAPA IPFY_IPOPT_RTRALRT IPFY_IPOPT_UMP
144%token	IPFY_SECCLASS IPFY_SEC_UNC IPFY_SEC_CONF IPFY_SEC_RSV1 IPFY_SEC_RSV2
145%token	IPFY_SEC_RSV4 IPFY_SEC_SEC IPFY_SEC_TS IPFY_SEC_RSV3
146
147%token	IPF6_V6HDRS IPFY_IPV6OPT IPFY_IPV6OPT_DSTOPTS IPFY_IPV6OPT_HOPOPTS
148%token	IPFY_IPV6OPT_IPV6 IPFY_IPV6OPT_NONE IPFY_IPV6OPT_ROUTING
149%token	IPFY_IPV6OPT_MOBILITY IPFY_IPV6OPT_ESP IPFY_IPV6OPT_FRAG
150
151%token	IPFY_ICMPT_UNR IPFY_ICMPT_ECHO IPFY_ICMPT_ECHOR IPFY_ICMPT_SQUENCH
152%token	IPFY_ICMPT_REDIR IPFY_ICMPT_TIMEX IPFY_ICMPT_PARAMP IPFY_ICMPT_TIMEST
153%token	IPFY_ICMPT_TIMESTREP IPFY_ICMPT_INFOREQ IPFY_ICMPT_INFOREP
154%token	IPFY_ICMPT_MASKREQ IPFY_ICMPT_MASKREP IPFY_ICMPT_ROUTERAD
155%token	IPFY_ICMPT_ROUTERSOL
156
157%token	IPFY_ICMPC_NETUNR IPFY_ICMPC_HSTUNR IPFY_ICMPC_PROUNR IPFY_ICMPC_PORUNR
158%token	IPFY_ICMPC_NEEDF IPFY_ICMPC_SRCFAIL IPFY_ICMPC_NETUNK IPFY_ICMPC_HSTUNK
159%token	IPFY_ICMPC_ISOLATE IPFY_ICMPC_NETPRO IPFY_ICMPC_HSTPRO
160%token	IPFY_ICMPC_NETTOS IPFY_ICMPC_HSTTOS IPFY_ICMPC_FLTPRO IPFY_ICMPC_HSTPRE
161%token	IPFY_ICMPC_CUTPRE
162
163%token	IPFY_FAC_KERN IPFY_FAC_USER IPFY_FAC_MAIL IPFY_FAC_DAEMON IPFY_FAC_AUTH
164%token	IPFY_FAC_SYSLOG IPFY_FAC_LPR IPFY_FAC_NEWS IPFY_FAC_UUCP IPFY_FAC_CRON
165%token	IPFY_FAC_LOCAL0 IPFY_FAC_LOCAL1 IPFY_FAC_LOCAL2 IPFY_FAC_LOCAL3
166%token	IPFY_FAC_LOCAL4 IPFY_FAC_LOCAL5 IPFY_FAC_LOCAL6 IPFY_FAC_LOCAL7
167%token	IPFY_FAC_SECURITY IPFY_FAC_FTP IPFY_FAC_AUTHPRIV IPFY_FAC_AUDIT
168%token	IPFY_FAC_LFMT IPFY_FAC_CONSOLE
169
170%token	IPFY_PRI_EMERG IPFY_PRI_ALERT IPFY_PRI_CRIT IPFY_PRI_ERR IPFY_PRI_WARN
171%token	IPFY_PRI_NOTICE IPFY_PRI_INFO IPFY_PRI_DEBUG
172%%
173file:	line
174	| assign
175	| file line
176	| file assign
177	;
178
179line:	rule		{ while ((fr = frtop) != NULL) {
180				frtop = fr->fr_next;
181				fr->fr_next = NULL;
182				(*ipfaddfunc)(ipffd, ipfioctl[IPL_LOGIPF], fr);
183				fr->fr_next = frold;
184				frold = fr;
185			  }
186			  resetlexer();
187			}
188	| YY_COMMENT
189	;
190
191xx:					{ newrule(); }
192	;
193
194assign:	YY_STR assigning YY_STR ';'	{ set_variable($1, $3);
195					  resetlexer();
196					  free($1);
197					  free($3);
198					  yyvarnext = 0;
199					}
200	;
201
202assigning:
203	'='				{ yyvarnext = 1; }
204	;
205
206rule:	inrule eol
207	| outrule eol
208	;
209
210eol:	| ';'
211	;
212
213inrule:
214	rulehead markin inopts rulemain ruletail intag ruletail2
215	;
216
217outrule:
218	rulehead markout outopts rulemain ruletail outtag ruletail2
219	;
220
221rulehead:
222	xx collection action
223	| xx insert collection action
224	;
225
226markin:	IPFY_IN				{ fr->fr_flags |= FR_INQUE; }
227	;
228
229markout:
230	IPFY_OUT			{ fr->fr_flags |= FR_OUTQUE; }
231	;
232
233rulemain:
234	ipfrule
235	| bpfrule
236	;
237
238ipfrule:
239	tos ttl proto ip
240	;
241
242bpfrule:
243	IPFY_BPFV4 '{' YY_STR '}' 	{ dobpf(4, $3); free($3); }
244	| IPFY_BPFV6 '{' YY_STR '}' 	{ dobpf(6, $3); free($3); }
245	;
246
247ruletail:
248	with keep head group
249	;
250
251ruletail2:
252	pps age new
253	;
254
255intag:	settagin matchtagin
256	;
257
258outtag:	settagout matchtagout
259	;
260
261insert:
262	'@' YY_NUMBER			{ fr->fr_hits = (U_QUAD_T)$2 + 1; }
263	;
264
265collection:
266	| YY_NUMBER			{ fr->fr_collect = $1; }
267	;
268
269action:	block
270	| IPFY_PASS			{ fr->fr_flags |= FR_PASS; }
271	| IPFY_NOMATCH			{ fr->fr_flags |= FR_NOMATCH; }
272	| log
273	| IPFY_COUNT			{ fr->fr_flags |= FR_ACCOUNT; }
274	| auth
275	| IPFY_SKIP YY_NUMBER		{ fr->fr_flags |= FR_SKIP;
276					  fr->fr_arg = $2; }
277	| IPFY_CALL func
278	| IPFY_CALL IPFY_NOW func	{ fr->fr_flags |= FR_CALLNOW; }
279	;
280
281block:	blocked
282	| blocked blockreturn
283	;
284
285blocked:
286	IPFY_BLOCK			{ fr->fr_flags = FR_BLOCK; }
287	;
288blockreturn:
289	IPFY_RETICMP			{ fr->fr_flags |= FR_RETICMP; }
290	| IPFY_RETICMP returncode	{ fr->fr_flags |= FR_RETICMP; }
291	| IPFY_RETICMPASDST		{ fr->fr_flags |= FR_FAKEICMP; }
292	| IPFY_RETICMPASDST returncode	{ fr->fr_flags |= FR_FAKEICMP; }
293	| IPFY_RETRST			{ fr->fr_flags |= FR_RETRST; }
294	;
295
296log:	IPFY_LOG			{ fr->fr_flags |= FR_LOG; }
297	| IPFY_LOG logoptions		{ fr->fr_flags |= FR_LOG; }
298	;
299
300auth:	IPFY_AUTH			{ fr->fr_flags |= FR_AUTH; }
301	| IPFY_AUTH blockreturn		{ fr->fr_flags |= FR_AUTH;}
302	| IPFY_PREAUTH			{ fr->fr_flags |= FR_PREAUTH; }
303	;
304
305func:	YY_STR '/' YY_NUMBER	{ fr->fr_func = nametokva($1,
306							  ipfioctl[IPL_LOGIPF]);
307				  fr->fr_arg = $3;
308				  free($1); }
309	;
310
311inopts:
312	| inopts inopt
313	;
314
315inopt:
316	logopt
317	| quick
318	| on
319	| dup
320	| froute
321	| proute
322	| replyto
323	;
324
325outopts:
326	| outopts outopt
327	;
328
329outopt:
330	logopt
331	| quick
332	| on
333	| dup
334	| proute
335	| replyto
336	;
337
338tos:	| settos YY_NUMBER	{ DOALL(fr->fr_tos = $2; fr->fr_mtos = 0xff;) }
339	| settos YY_HEX	{ DOALL(fr->fr_tos = $2; fr->fr_mtos = 0xff;) }
340	| settos lstart toslist lend
341	;
342
343settos:	IPFY_TOS			{ setipftype(); }
344	;
345
346toslist:
347	YY_NUMBER	{ DOALL(fr->fr_tos = $1; fr->fr_mtos = 0xff;) }
348	| YY_HEX	{ DOREM(fr->fr_tos = $1; fr->fr_mtos = 0xff;) }
349	| toslist lmore YY_NUMBER
350			{ DOREM(fr->fr_tos = $3; fr->fr_mtos = 0xff;) }
351	| toslist lmore YY_HEX
352			{ DOREM(fr->fr_tos = $3; fr->fr_mtos = 0xff;) }
353	;
354
355ttl:	| setttl YY_NUMBER
356			{ DOALL(fr->fr_ttl = $2; fr->fr_mttl = 0xff;) }
357	| setttl lstart ttllist lend
358	;
359
360lstart:	'('				{ newlist = 1; fr = frc; added = 0; }
361	;
362
363lend:	')'				{ nrules += added; }
364	;
365
366lmore:	lanother			{ if (newlist == 1) {
367						newlist = 0;
368					  }
369					  fr = addrule();
370					  if (yycont != NULL)
371						*yycont = 1;
372					}
373	;
374
375lanother:
376	| ','
377	;
378
379setttl:	IPFY_TTL			{ setipftype(); }
380	;
381
382ttllist:
383	YY_NUMBER	{ DOREM(fr->fr_ttl = $1; fr->fr_mttl = 0xff;) }
384	| ttllist lmore YY_NUMBER
385			{ DOREM(fr->fr_ttl = $3; fr->fr_mttl = 0xff;) }
386	;
387
388proto:	| protox protocol		{ yyresetdict(); }
389	;
390
391protox:	IPFY_PROTO			{ setipftype();
392					  fr = frc;
393					  yysetdict(NULL); }
394	;
395
396ip:	srcdst flags icmp
397	;
398
399group:	| IPFY_GROUP YY_STR		{ DOALL(strncpy(fr->fr_group, $2, \
400							FR_GROUPLEN); \
401							fillgroup(fr););
402					  free($2); }
403	| IPFY_GROUP YY_NUMBER		{ DOALL(sprintf(fr->fr_group, "%d", \
404							$2); \
405							fillgroup(fr);) }
406	;
407
408head:	| IPFY_HEAD YY_STR		{ DOALL(strncpy(fr->fr_grhead, $2, \
409							FR_GROUPLEN););
410					  free($2); }
411	| IPFY_HEAD YY_NUMBER		{ DOALL(sprintf(fr->fr_grhead, "%d", \
412							$2);) }
413	;
414
415settagin:
416	| IPFY_SETTAG '(' taginlist ')'
417	;
418
419taginlist:
420	taginspec
421	| taginlist ',' taginspec
422	;
423
424taginspec:
425	logtag
426	;
427
428nattag:	IPFY_NAT '=' YY_STR		{ DOALL(strncpy(fr->fr_nattag.ipt_tag,\
429						$3, IPFTAG_LEN););
430					  free($3); }
431	| IPFY_NAT '=' YY_NUMBER	{ DOALL(sprintf(fr->fr_nattag.ipt_tag,\
432						"%d", $3 & 0xffffffff);) }
433	;
434
435logtag:	IPFY_LOG '=' YY_NUMBER		{ DOALL(fr->fr_logtag = $3;) }
436	;
437
438settagout:
439	| IPFY_SETTAG '(' tagoutlist ')'
440	;
441
442tagoutlist:
443	tagoutspec
444	| tagoutlist ',' tagoutspec
445	;
446
447tagoutspec:
448	logtag
449	| nattag
450	;
451
452matchtagin:
453	| IPFY_MATCHTAG '(' tagoutlist ')'
454	;
455
456matchtagout:
457	| IPFY_MATCHTAG '(' taginlist ')'
458	;
459
460pps:	| IPFY_PPS YY_NUMBER		{ DOALL(fr->fr_pps = $2;) }
461	;
462
463new:	| savegroup file restoregroup
464	;
465
466savegroup:
467	'{'
468	;
469
470restoregroup:
471	'}'
472	;
473
474logopt:	log
475	;
476
477quick:
478	IPFY_QUICK			{ fr->fr_flags |= FR_QUICK; }
479	;
480
481on:	IPFY_ON onname
482	| IPFY_ON lstart onlist lend
483	| IPFY_ON onname IPFY_INVIA vianame
484	| IPFY_ON onname IPFY_OUTVIA vianame
485	;
486
487onlist:	onname			{ DOREM(strncpy(fr->fr_ifnames[0], $1.if1, \
488					sizeof(fr->fr_ifnames[0])); 	   \
489					if ($1.if2 != NULL) {		   \
490						strncpy(fr->fr_ifnames[1], \
491							$1.if2,		   \
492						sizeof(fr->fr_ifnames[1]));\
493					}				   \
494					) }
495	| onlist lmore onname	{ DOREM(strncpy(fr->fr_ifnames[0], $3.if1, \
496					sizeof(fr->fr_ifnames[0])); 	   \
497					if ($3.if2 != NULL) {		   \
498						strncpy(fr->fr_ifnames[1], \
499							$3.if2,		   \
500						sizeof(fr->fr_ifnames[1]));\
501					}				   \
502					) }
503	;
504
505onname:	interfacename
506		{ strncpy(fr->fr_ifnames[0], $1, sizeof(fr->fr_ifnames[0]));
507		  $$.if1 = fr->fr_ifnames[0];
508		  $$.if2 = NULL;
509		  free($1);
510		}
511	| interfacename ',' interfacename
512		{ strncpy(fr->fr_ifnames[0], $1, sizeof(fr->fr_ifnames[0]));
513		  $$.if1 = fr->fr_ifnames[0];
514		  free($1);
515		  strncpy(fr->fr_ifnames[1], $3, sizeof(fr->fr_ifnames[1]));
516		  $$.if1 = fr->fr_ifnames[1];
517		  free($3);
518		}
519	;
520
521vianame:
522	name
523		{ strncpy(fr->fr_ifnames[2], $1, sizeof(fr->fr_ifnames[2]));
524		  free($1);
525		}
526	| name ',' name
527		{ strncpy(fr->fr_ifnames[2], $1, sizeof(fr->fr_ifnames[2]));
528		  free($1);
529		  strncpy(fr->fr_ifnames[3], $3, sizeof(fr->fr_ifnames[3]));
530		  free($3);
531		}
532	;
533
534dup:	IPFY_DUPTO name
535	{ strncpy(fr->fr_dif.fd_ifname, $2, sizeof(fr->fr_dif.fd_ifname));
536	  free($2);
537	}
538	| IPFY_DUPTO name duptoseparator hostname
539	{ strncpy(fr->fr_dif.fd_ifname, $2, sizeof(fr->fr_dif.fd_ifname));
540	  fr->fr_dif.fd_ip = $4;
541	  yyexpectaddr = 0;
542	  free($2);
543	}
544	| IPFY_DUPTO name duptoseparator YY_IPV6
545	{ strncpy(fr->fr_dif.fd_ifname, $2, sizeof(fr->fr_dif.fd_ifname));
546	  bcopy(&$4, &fr->fr_dif.fd_ip6, sizeof(fr->fr_dif.fd_ip6));
547	  yyexpectaddr = 0;
548	  free($2);
549	}
550	;
551
552duptoseparator:
553	':'	{ yyexpectaddr = 1; yycont = &yyexpectaddr; resetaddr(); }
554	;
555
556froute:	IPFY_FROUTE			{ fr->fr_flags |= FR_FASTROUTE; }
557	;
558
559proute:	routeto name
560	{ strncpy(fr->fr_tif.fd_ifname, $2, sizeof(fr->fr_tif.fd_ifname));
561	  free($2);
562	}
563	| routeto name duptoseparator hostname
564	{ strncpy(fr->fr_tif.fd_ifname, $2, sizeof(fr->fr_tif.fd_ifname));
565	  fr->fr_tif.fd_ip = $4;
566	  yyexpectaddr = 0;
567	  free($2);
568	}
569	| routeto name duptoseparator YY_IPV6
570	{ strncpy(fr->fr_tif.fd_ifname, $2, sizeof(fr->fr_tif.fd_ifname));
571	  bcopy(&$4, &fr->fr_tif.fd_ip6, sizeof(fr->fr_tif.fd_ip6));
572	  yyexpectaddr = 0;
573	  free($2);
574	}
575	;
576
577routeto:
578	IPFY_TO
579	| IPFY_ROUTETO
580	;
581
582replyto:
583	IPFY_REPLY_TO name
584	{ strncpy(fr->fr_rif.fd_ifname, $2, sizeof(fr->fr_rif.fd_ifname));
585	  free($2);
586	}
587	| IPFY_REPLY_TO name duptoseparator hostname
588	{ strncpy(fr->fr_rif.fd_ifname, $2, sizeof(fr->fr_rif.fd_ifname));
589	  fr->fr_rif.fd_ip = $4;
590	  free($2);
591	}
592	;
593
594logoptions:
595	logoption
596	| logoptions logoption
597	;
598
599logoption:
600	IPFY_BODY			{ fr->fr_flags |= FR_LOGBODY; }
601	| IPFY_FIRST			{ fr->fr_flags |= FR_LOGFIRST; }
602	| IPFY_ORBLOCK			{ fr->fr_flags |= FR_LOGORBLOCK; }
603	| level loglevel		{ unsetsyslog(); }
604	;
605
606returncode:
607	starticmpcode icmpcode ')'	{ fr->fr_icode = $2; yyresetdict(); }
608	;
609
610starticmpcode:
611	'('				{ yysetdict(icmpcodewords); }
612	;
613
614srcdst:	| IPFY_ALL
615	| fromto
616	;
617
618protocol:
619	YY_NUMBER		{ DOREM(fr->fr_proto = $1; \
620					fr->fr_mproto = 0xff;) }
621	| YY_STR		{ if (!strcmp($1, "tcp-udp")) {
622					DOREM(fr->fr_flx |= FI_TCPUDP; \
623					      fr->fr_mflx |= FI_TCPUDP;)
624				  } else {
625					int p = getproto($1);
626					if (p == -1)
627						yyerror("protocol unknown");
628					DOREM(fr->fr_proto = p; \
629						fr->fr_mproto = 0xff;)
630				  }
631				  free($1);
632					}
633	| YY_STR nextstring YY_STR
634				{ if (!strcmp($1, "tcp") &&
635				      !strcmp($3, "udp")) {
636					DOREM(fr->fr_flx |= FI_TCPUDP; \
637					      fr->fr_mflx |= FI_TCPUDP;)
638				  } else
639					YYERROR;
640				  free($1);
641				  free($3);
642				}
643	;
644
645nextstring:
646	'/'			{ yysetdict(NULL); }
647	;
648
649fromto:	from srcobject to dstobject	{ yyexpectaddr = 0; yycont = NULL; }
650	| to dstobject			{ yyexpectaddr = 0; yycont = NULL; }
651	| from srcobject		{ yyexpectaddr = 0; yycont = NULL; }
652	;
653
654from:	IPFY_FROM			{ setipftype();
655					  if (fr == NULL)
656						fr = frc;
657					  yyexpectaddr = 1;
658					  if (yydebug)
659						printf("set yyexpectaddr\n");
660					  yycont = &yyexpectaddr;
661					  yysetdict(addrwords);
662					  resetaddr(); }
663	;
664
665to:	IPFY_TO				{ if (fr == NULL)
666						fr = frc;
667					  yyexpectaddr = 1;
668					  if (yydebug)
669						printf("set yyexpectaddr\n");
670					  yycont = &yyexpectaddr;
671					  yysetdict(addrwords);
672					  resetaddr(); }
673	;
674
675with:	| andwith withlist
676	;
677
678andwith:
679	IPFY_WITH			{ nowith = 0; setipftype(); }
680	| IPFY_AND			{ nowith = 0; setipftype(); }
681	;
682
683flags:	| startflags flagset
684		{ DOALL(fr->fr_tcpf = $2; fr->fr_tcpfm = FR_TCPFMAX;) }
685	| startflags flagset '/' flagset
686		{ DOALL(fr->fr_tcpf = $2; fr->fr_tcpfm = $4;) }
687	| startflags '/' flagset
688		{ DOALL(fr->fr_tcpf = 0; fr->fr_tcpfm = $3;) }
689	| startflags YY_NUMBER
690		{ DOALL(fr->fr_tcpf = $2; fr->fr_tcpfm = FR_TCPFMAX;) }
691	| startflags '/' YY_NUMBER
692		{ DOALL(fr->fr_tcpf = 0; fr->fr_tcpfm = $3;) }
693	| startflags YY_NUMBER '/' YY_NUMBER
694		{ DOALL(fr->fr_tcpf = $2; fr->fr_tcpfm = $4;) }
695	| startflags flagset '/' YY_NUMBER
696		{ DOALL(fr->fr_tcpf = $2; fr->fr_tcpfm = $4;) }
697	| startflags YY_NUMBER '/' flagset
698		{ DOALL(fr->fr_tcpf = $2; fr->fr_tcpfm = $4;) }
699	;
700
701startflags:
702	IPFY_FLAGS	{ if (frc->fr_type != FR_T_IPF)
703				yyerror("flags with non-ipf type rule");
704			  if (frc->fr_proto != IPPROTO_TCP)
705				yyerror("flags with non-TCP rule");
706			}
707	;
708
709flagset:
710	YY_STR				{ $$ = tcpflags($1); free($1); }
711	| YY_HEX			{ $$ = $1; }
712	;
713
714srcobject:
715	{ yyresetdict(); } fromport
716	| srcaddr srcport
717	| '!' srcaddr srcport
718		{ DOALL(fr->fr_flags |= FR_NOTSRCIP;) }
719	;
720
721srcaddr:
722	addr	{ DOREM(bcopy(&($1.a), &fr->fr_ip.fi_src, sizeof($1.a)); \
723			bcopy(&($1.m), &fr->fr_mip.fi_src, sizeof($1.m)); \
724			if (dynamic != -1) { \
725				fr->fr_satype = ifpflag; \
726				fr->fr_ipf->fri_sifpidx = dynamic; \
727			} else if (pooled || hashed) \
728				fr->fr_satype = FRI_LOOKUP;)
729		}
730	| lstart srcaddrlist lend
731	;
732
733srcaddrlist:
734	addr	{ DOREM(bcopy(&($1.a), &fr->fr_ip.fi_src, sizeof($1.a)); \
735			bcopy(&($1.m), &fr->fr_mip.fi_src, sizeof($1.m)); \
736			if (dynamic != -1) { \
737				fr->fr_satype = ifpflag; \
738				fr->fr_ipf->fri_sifpidx = dynamic; \
739			} else if (pooled || hashed) \
740				fr->fr_satype = FRI_LOOKUP;)
741		}
742	| srcaddrlist lmore addr
743		{ DOREM(bcopy(&($3.a), &fr->fr_ip.fi_src, sizeof($3.a)); \
744			bcopy(&($3.m), &fr->fr_mip.fi_src, sizeof($3.m)); \
745			if (dynamic != -1) { \
746				fr->fr_satype = ifpflag; \
747				fr->fr_ipf->fri_sifpidx = dynamic; \
748			} else if (pooled || hashed) \
749				fr->fr_satype = FRI_LOOKUP;)
750		}
751	;
752
753srcport:
754	| portcomp
755		{ DOALL(fr->fr_scmp = $1.pc; fr->fr_sport = $1.p1;) }
756	| portrange
757		{ DOALL(fr->fr_scmp = $1.pc; fr->fr_sport = $1.p1; \
758			fr->fr_stop = $1.p2;) }
759	| porteq lstart srcportlist lend
760		{ yyresetdict(); }
761	;
762
763fromport:
764	portcomp
765		{ DOALL(fr->fr_scmp = $1.pc; fr->fr_sport = $1.p1;) }
766	| portrange
767		{ DOALL(fr->fr_scmp = $1.pc; fr->fr_sport = $1.p1; \
768			fr->fr_stop = $1.p2;) }
769	| porteq lstart srcportlist lend
770		{ yyresetdict(); }
771	;
772
773srcportlist:
774	portnum		{ DOREM(fr->fr_scmp = FR_EQUAL; fr->fr_sport = $1;) }
775	| srcportlist lmore portnum
776			{ DOREM(fr->fr_scmp = FR_EQUAL; fr->fr_sport = $3;) }
777	;
778
779dstobject:
780	{ yyresetdict(); } toport
781	| dstaddr dstport
782	| '!' dstaddr dstport
783			{ DOALL(fr->fr_flags |= FR_NOTDSTIP;) }
784	;
785
786dstaddr:
787	addr	{ DOREM(bcopy(&($1.a), &fr->fr_ip.fi_dst, sizeof($1.a)); \
788			bcopy(&($1.m), &fr->fr_mip.fi_dst, sizeof($1.m)); \
789			if (dynamic != -1) { \
790				fr->fr_datype = ifpflag; \
791				fr->fr_ipf->fri_difpidx = dynamic; \
792			  } else if (pooled || hashed) \
793				fr->fr_datype = FRI_LOOKUP;)
794		}
795	| lstart dstaddrlist lend
796	;
797
798dstaddrlist:
799	addr	{ DOREM(bcopy(&($1.a), &fr->fr_ip.fi_dst, sizeof($1.a)); \
800			bcopy(&($1.m), &fr->fr_mip.fi_dst, sizeof($1.m)); \
801			if (dynamic != -1) { \
802				fr->fr_datype = ifpflag; \
803				fr->fr_ipf->fri_difpidx = dynamic; \
804			} else if (pooled || hashed) \
805				fr->fr_datype = FRI_LOOKUP;)
806		}
807	| dstaddrlist lmore addr
808		{ DOREM(bcopy(&($3.a), &fr->fr_ip.fi_dst, sizeof($3.a)); \
809			bcopy(&($3.m), &fr->fr_mip.fi_dst, sizeof($3.m)); \
810			if (dynamic != -1) { \
811				fr->fr_datype = ifpflag; \
812				fr->fr_ipf->fri_difpidx = dynamic; \
813			} else if (pooled || hashed) \
814				fr->fr_datype = FRI_LOOKUP;)
815		}
816	;
817
818
819dstport:
820	| portcomp
821		{ DOALL(fr->fr_dcmp = $1.pc; fr->fr_dport = $1.p1;) }
822	| portrange
823		{ DOALL(fr->fr_dcmp = $1.pc; fr->fr_dport = $1.p1; \
824			fr->fr_dtop = $1.p2;) }
825	| porteq lstart dstportlist lend
826		{ yyresetdict(); }
827	;
828
829toport:
830	portcomp
831		{ DOALL(fr->fr_dcmp = $1.pc; fr->fr_dport = $1.p1;) }
832	| portrange
833		{ DOALL(fr->fr_dcmp = $1.pc; fr->fr_dport = $1.p1; \
834			fr->fr_dtop = $1.p2;) }
835	| porteq lstart dstportlist lend
836		{ yyresetdict(); }
837	;
838
839dstportlist:
840	portnum		{ DOREM(fr->fr_dcmp = FR_EQUAL; fr->fr_dport = $1;) }
841	| dstportlist lmore portnum
842			{ DOREM(fr->fr_dcmp = FR_EQUAL; fr->fr_dport = $3;) }
843	;
844
845addr:	pool '/' YY_NUMBER		{ pooled = 1;
846					  $$.a.iplookuptype = IPLT_POOL;
847					  $$.a.iplookupsubtype = 0;
848					  $$.a.iplookupnum = $3; }
849	| pool '/' YY_STR		{ pooled = 1;
850					  $$.a.iplookuptype = IPLT_POOL;
851					  $$.a.iplookupsubtype = 1;
852					  strncpy($$.a.iplookupname, $3,
853						  sizeof($$.a.iplookupname));
854					}
855	| pool '=' '(' poollist ')'	{ pooled = 1;
856					  $$.a.iplookuptype = IPLT_POOL;
857					  $$.a.iplookupsubtype = 0;
858					  $$.a.iplookupnum = makepool($4); }
859	| hash '/' YY_NUMBER		{ hashed = 1;
860					  $$.a.iplookuptype = IPLT_HASH;
861					  $$.a.iplookupsubtype = 0;
862					  $$.a.iplookupnum = $3; }
863	| hash '/' YY_STR		{ pooled = 1;
864					  $$.a.iplookuptype = IPLT_HASH;
865					  $$.a.iplookupsubtype = 1;
866					  strncpy($$.a.iplookupname, $3,
867						  sizeof($$.a.iplookupname));
868					}
869	| hash '=' '(' addrlist ')'	{ hashed = 1;
870					  $$.a.iplookuptype = IPLT_HASH;
871					  $$.a.iplookupsubtype = 0;
872					  $$.a.iplookupnum = makehash($4); }
873	| ipaddr			{ bcopy(&$1, &$$, sizeof($$));
874					  yyexpectaddr = 0; }
875	;
876
877ipaddr:	IPFY_ANY			{ bzero(&($$), sizeof($$));
878					  yyresetdict();
879					  yyexpectaddr = 0; }
880	| hostname			{ $$.a.in4 = $1;
881					  $$.m.in4_addr = 0xffffffff;
882					  yyexpectaddr = 0; }
883	| hostname			{ yyresetdict();
884					  $$.a.in4_addr = $1.s_addr; }
885		maskspace		{ yysetdict(maskwords); }
886		ipv4mask		{ $$.m.in4_addr = $5.s_addr;
887					  $$.a.in4_addr &= $5.s_addr;
888					  yyresetdict();
889					  yyexpectaddr = 0; }
890	| YY_IPV6			{ bcopy(&$1, &$$.a, sizeof($$.a));
891					  fill6bits(128, (u_32_t *)&$$.m);
892					  yyresetdict();
893					  yyexpectaddr = 0; }
894	| YY_IPV6			{ yyresetdict();
895					  bcopy(&$1, &$$.a, sizeof($$.a)); }
896		maskspace		{ yysetdict(maskwords); }
897		ipv6mask		{ bcopy(&$5, &$$.m, sizeof($$.m));
898					  yyresetdict();
899					  yyexpectaddr = 0; }
900	;
901maskspace:
902	'/'
903	| IPFY_MASK
904	;
905
906ipv4mask:
907	ipv4				{ $$ = $1; }
908	| YY_HEX			{ $$.s_addr = htonl($1); }
909	| YY_NUMBER			{ ntomask(4, $1, (u_32_t *)&$$); }
910	| IPFY_BROADCAST		{ if (ifpflag == FRI_DYNAMIC) {
911						$$.s_addr = 0;
912						ifpflag = FRI_BROADCAST;
913					  } else
914						YYERROR;
915					}
916	| IPFY_NETWORK			{ if (ifpflag == FRI_DYNAMIC) {
917						$$.s_addr = 0;
918						ifpflag = FRI_NETWORK;
919					  } else
920						YYERROR;
921					}
922	| IPFY_NETMASKED		{ if (ifpflag == FRI_DYNAMIC) {
923						$$.s_addr = 0;
924						ifpflag = FRI_NETMASKED;
925					  } else
926						YYERROR;
927					}
928	| IPFY_PEER			{ if (ifpflag == FRI_DYNAMIC) {
929						$$.s_addr = 0;
930						ifpflag = FRI_PEERADDR;
931					  } else
932						YYERROR;
933					}
934	;
935
936ipv6mask:
937	YY_NUMBER			{ ntomask(6, $1, $$.i6); }
938	| IPFY_BROADCAST		{ if (ifpflag == FRI_DYNAMIC) {
939						bzero(&$$, sizeof($$));
940						ifpflag = FRI_BROADCAST;
941					  } else
942						YYERROR;
943					}
944	| IPFY_NETWORK			{ if (ifpflag == FRI_DYNAMIC) {
945						bzero(&$$, sizeof($$));
946						ifpflag = FRI_BROADCAST;
947					  } else
948						YYERROR;
949					}
950	| IPFY_NETMASKED		{ if (ifpflag == FRI_DYNAMIC) {
951						bzero(&$$, sizeof($$));
952						ifpflag = FRI_BROADCAST;
953					  } else
954						YYERROR;
955					}
956	| IPFY_PEER			{ if (ifpflag == FRI_DYNAMIC) {
957						bzero(&$$, sizeof($$));
958						ifpflag = FRI_BROADCAST;
959					  } else
960						YYERROR;
961					}
962	;
963
964hostname:
965	ipv4				{ $$ = $1; }
966	| YY_NUMBER			{ $$.s_addr = $1; }
967	| YY_HEX			{ $$.s_addr = $1; }
968	| YY_STR			{ $$.s_addr = lookuphost($1);
969					  free($1);
970					}
971	;
972
973addrlist:
974	ipaddr		{ $$ = newalist(NULL);
975			  bcopy(&($1.a), &($$->al_i6addr), sizeof($1.a));
976			  bcopy(&($1.m), &($$->al_i6mask), sizeof($1.m)); }
977	| addrlist ',' ipaddr
978			{ $$ = newalist($1);
979			  bcopy(&($3.a), &($$->al_i6addr), sizeof($3.a));
980			  bcopy(&($3.m), &($$->al_i6mask), sizeof($3.m)); }
981	;
982
983pool:	IPFY_POOL	{ yyexpectaddr = 0; yycont = NULL; yyresetdict(); }
984	;
985
986hash:	IPFY_HASH	{ yyexpectaddr = 0; yycont = NULL; yyresetdict(); }
987	;
988
989poollist:
990	ipaddr		{ $$ = newalist(NULL);
991			  bcopy(&($1.a), &($$->al_i6addr), sizeof($1.a));
992			  bcopy(&($1.m), &($$->al_i6mask), sizeof($1.m)); }
993	| '!' ipaddr	{ $$ = newalist(NULL);
994			  $$->al_not = 1;
995			  bcopy(&($2.a), &($$->al_i6addr), sizeof($2.a));
996			  bcopy(&($2.m), &($$->al_i6mask), sizeof($2.m)); }
997	| poollist ',' ipaddr
998			{ $$ = newalist($1);
999			  bcopy(&($3.a), &($$->al_i6addr), sizeof($3.a));
1000			  bcopy(&($3.m), &($$->al_i6mask), sizeof($3.m)); }
1001	| poollist ',' '!' ipaddr
1002			{ $$ = newalist($1);
1003			  $$->al_not = 1;
1004			  bcopy(&($4.a), &($$->al_i6addr), sizeof($4.a));
1005			  bcopy(&($4.m), &($$->al_i6mask), sizeof($4.m)); }
1006	;
1007
1008port:	IPFY_PORT			{ yyexpectaddr = 0;
1009					  yycont = NULL;
1010					}
1011	;
1012
1013portc:	port compare			{ $$ = $2;
1014					  yysetdict(NULL); }
1015	| porteq			{ $$ = $1; }
1016	;
1017
1018porteq:	port '='			{ $$ = FR_EQUAL;
1019					  yysetdict(NULL); }
1020	;
1021
1022portr:	IPFY_PORT			{ yyexpectaddr = 0;
1023					  yycont = NULL;
1024					  yysetdict(NULL); }
1025	;
1026
1027portcomp:
1028	portc portnum			{ $$.pc = $1;
1029					  $$.p1 = $2;
1030					  yyresetdict(); }
1031	;
1032
1033portrange:
1034	portr portnum range portnum	{ $$.p1 = $2;
1035					  $$.pc = $3;
1036					  $$.p2 = $4;
1037					  yyresetdict(); }
1038	;
1039
1040icmp:	| itype icode
1041	;
1042
1043itype:	seticmptype icmptype
1044	{ DOALL(fr->fr_icmp = htons($2 << 8); fr->fr_icmpm = htons(0xff00););
1045	  yyresetdict();
1046	}
1047	| seticmptype lstart typelist lend	{ yyresetdict(); }
1048	;
1049
1050seticmptype:
1051	IPFY_ICMPTYPE				{ setipftype();
1052						  yysetdict(icmptypewords); }
1053	;
1054
1055icode:	| seticmpcode icmpcode
1056	{ DOALL(fr->fr_icmp |= htons($2); fr->fr_icmpm |= htons(0xff););
1057	  yyresetdict();
1058	}
1059	| seticmpcode lstart codelist lend	{ yyresetdict(); }
1060	;
1061
1062seticmpcode:
1063	IPFY_ICMPCODE				{ yysetdict(icmpcodewords); }
1064	;
1065
1066typelist:
1067	icmptype
1068	{ DOREM(fr->fr_icmp = htons($1 << 8); fr->fr_icmpm = htons(0xff00);) }
1069	| typelist lmore icmptype
1070	{ DOREM(fr->fr_icmp = htons($3 << 8); fr->fr_icmpm = htons(0xff00);) }
1071	;
1072
1073codelist:
1074	icmpcode
1075	{ DOREM(fr->fr_icmp |= htons($1); fr->fr_icmpm |= htons(0xff);) }
1076	| codelist lmore icmpcode
1077	{ DOREM(fr->fr_icmp &= htons(0xff00); fr->fr_icmp |= htons($3); \
1078		fr->fr_icmpm |= htons(0xff);) }
1079	;
1080
1081age:	| IPFY_AGE YY_NUMBER		{ DOALL(fr->fr_age[0] = $2; \
1082						fr->fr_age[1] = $2;) }
1083	| IPFY_AGE YY_NUMBER '/' YY_NUMBER
1084					{ DOALL(fr->fr_age[0] = $2; \
1085						fr->fr_age[1] = $4;) }
1086	;
1087
1088keep:	| IPFY_KEEP keepstate keep
1089	| IPFY_KEEP keepfrag keep
1090	;
1091
1092keepstate:
1093	IPFY_STATE stateoptlist		{ DOALL(fr->fr_flags |= FR_KEEPSTATE;)}
1094	;
1095
1096keepfrag:
1097	IPFY_FRAGS fragoptlist		{ DOALL(fr->fr_flags |= FR_KEEPFRAG;) }
1098	| IPFY_FRAG fragoptlist		{ DOALL(fr->fr_flags |= FR_KEEPFRAG;) }
1099	;
1100
1101fragoptlist:
1102	| '(' fragopts ')'
1103	;
1104
1105fragopts:
1106	fragopt lanother fragopts
1107	| fragopt
1108	;
1109
1110fragopt:
1111	IPFY_STRICT			{ DOALL(fr->fr_flags |= FR_FRSTRICT;) }
1112	;
1113
1114stateoptlist:
1115	| '(' stateopts ')'
1116	;
1117
1118stateopts:
1119	stateopt lanother stateopts
1120	| stateopt
1121	;
1122
1123stateopt:
1124	IPFY_LIMIT YY_NUMBER	{ DOALL(fr->fr_statemax = $2;) }
1125	| IPFY_STRICT		{ DOALL(if (fr->fr_proto != IPPROTO_TCP) { \
1126						YYERROR; \
1127					  } else \
1128						fr->fr_flags |= FR_STSTRICT;)
1129				}
1130	| IPFY_NEWISN		{ DOALL(if (fr->fr_proto != IPPROTO_TCP) { \
1131						YYERROR; \
1132					  } else \
1133						fr->fr_flags |= FR_NEWISN;)
1134				}
1135	| IPFY_NOICMPERR	{ DOALL(fr->fr_flags |= FR_NOICMPERR;) }
1136
1137	| IPFY_SYNC		{ DOALL(fr->fr_flags |= FR_STATESYNC;) }
1138	| IPFY_AGE YY_NUMBER		{ DOALL(fr->fr_age[0] = $2; \
1139						fr->fr_age[1] = $2;) }
1140	| IPFY_AGE YY_NUMBER '/' YY_NUMBER
1141					{ DOALL(fr->fr_age[0] = $2; \
1142						fr->fr_age[1] = $4;) }
1143	;
1144
1145portnum:
1146	servicename			{ if (getport(frc, $1, &($$)) == -1)
1147						yyerror("service unknown");
1148					  $$ = ntohs($$);
1149					  free($1);
1150					}
1151	| YY_NUMBER			{ if ($1 > 65535)	/* Unsigned */
1152						yyerror("invalid port number");
1153					  else
1154						$$ = $1;
1155					}
1156	;
1157
1158withlist:
1159	withopt				{ nowith = 0; }
1160	| withlist withopt		{ nowith = 0; }
1161	| withlist ',' withopt		{ nowith = 0; }
1162	;
1163
1164withopt:
1165	opttype		{ DOALL(fr->fr_flx |= $1; fr->fr_mflx |= $1;) }
1166	| notwith opttype		{ DOALL(fr->fr_mflx |= $2;) }
1167	| ipopt ipopts			{ yyresetdict(); }
1168	| notwith ipopt ipopts		{ yyresetdict(); }
1169	| startv6hdrs ipv6hdrs		{ yyresetdict(); }
1170	;
1171
1172ipopt:	IPFY_OPT			{ yysetdict(ipv4optwords); }
1173	;
1174
1175startv6hdrs:
1176	IPF6_V6HDRS	{ if (use_inet6 == 0)
1177				yyerror("only available with IPv6");
1178			  yysetdict(ipv6optwords);
1179			}
1180	;
1181
1182notwith:
1183	IPFY_NOT			{ nowith = 1; }
1184	| IPFY_NO			{ nowith = 1; }
1185	;
1186
1187opttype:
1188	IPFY_IPOPTS			{ $$ = FI_OPTIONS; }
1189	| IPFY_SHORT			{ $$ = FI_SHORT; }
1190	| IPFY_NAT			{ $$ = FI_NATED; }
1191	| IPFY_BAD			{ $$ = FI_BAD; }
1192	| IPFY_BADNAT			{ $$ = FI_BADNAT; }
1193	| IPFY_BADSRC			{ $$ = FI_BADSRC; }
1194	| IPFY_LOWTTL			{ $$ = FI_LOWTTL; }
1195	| IPFY_FRAG			{ $$ = FI_FRAG; }
1196	| IPFY_FRAGBODY			{ $$ = FI_FRAGBODY; }
1197	| IPFY_FRAGS			{ $$ = FI_FRAG; }
1198	| IPFY_MBCAST			{ $$ = FI_MBCAST; }
1199	| IPFY_MULTICAST		{ $$ = FI_MULTICAST; }
1200	| IPFY_BROADCAST		{ $$ = FI_BROADCAST; }
1201	| IPFY_STATE			{ $$ = FI_STATE; }
1202	| IPFY_OOW			{ $$ = FI_OOW; }
1203	;
1204
1205ipopts:	optlist		{ DOALL(fr->fr_mip.fi_optmsk |= $1;
1206				if (!nowith)
1207					fr->fr_ip.fi_optmsk |= $1;)
1208			}
1209	;
1210
1211optlist:
1212	opt				{ $$ |= $1; }
1213	| optlist ',' opt		{ $$ |= $1 | $3; }
1214	;
1215
1216ipv6hdrs:
1217	ipv6hdrlist	{ DOALL(fr->fr_mip.fi_optmsk |= $1;
1218				if (!nowith)
1219					fr->fr_ip.fi_optmsk |= $1;)
1220			}
1221	;
1222
1223ipv6hdrlist:
1224	ipv6hdr				{ $$ |= $1; }
1225	| ipv6hdrlist ',' ipv6hdr	{ $$ |= $1 | $3; }
1226	;
1227
1228secname:
1229	seclevel			{ $$ |= $1; }
1230	| secname ',' seclevel		{ $$ |= $1 | $3; }
1231	;
1232
1233seclevel:
1234	IPFY_SEC_UNC			{ $$ = secbit(IPSO_CLASS_UNCL); }
1235	| IPFY_SEC_CONF			{ $$ = secbit(IPSO_CLASS_CONF); }
1236	| IPFY_SEC_RSV1			{ $$ = secbit(IPSO_CLASS_RES1); }
1237	| IPFY_SEC_RSV2			{ $$ = secbit(IPSO_CLASS_RES2); }
1238	| IPFY_SEC_RSV3			{ $$ = secbit(IPSO_CLASS_RES3); }
1239	| IPFY_SEC_RSV4			{ $$ = secbit(IPSO_CLASS_RES4); }
1240	| IPFY_SEC_SEC			{ $$ = secbit(IPSO_CLASS_SECR); }
1241	| IPFY_SEC_TS			{ $$ = secbit(IPSO_CLASS_TOPS); }
1242	;
1243
1244icmptype:
1245	YY_NUMBER			{ $$ = $1; }
1246	| IPFY_ICMPT_UNR		{ $$ = ICMP_UNREACH; }
1247	| IPFY_ICMPT_ECHO		{ $$ = ICMP_ECHO; }
1248	| IPFY_ICMPT_ECHOR		{ $$ = ICMP_ECHOREPLY; }
1249	| IPFY_ICMPT_SQUENCH		{ $$ = ICMP_SOURCEQUENCH; }
1250	| IPFY_ICMPT_REDIR		{ $$ = ICMP_REDIRECT; }
1251	| IPFY_ICMPT_TIMEX		{ $$ = ICMP_TIMXCEED; }
1252	| IPFY_ICMPT_PARAMP		{ $$ = ICMP_PARAMPROB; }
1253	| IPFY_ICMPT_TIMEST		{ $$ = ICMP_TSTAMP; }
1254	| IPFY_ICMPT_TIMESTREP		{ $$ = ICMP_TSTAMPREPLY; }
1255	| IPFY_ICMPT_INFOREQ		{ $$ = ICMP_IREQ; }
1256	| IPFY_ICMPT_INFOREP		{ $$ = ICMP_IREQREPLY; }
1257	| IPFY_ICMPT_MASKREQ		{ $$ = ICMP_MASKREQ; }
1258	| IPFY_ICMPT_MASKREP		{ $$ = ICMP_MASKREPLY; }
1259	| IPFY_ICMPT_ROUTERAD		{ $$ = ICMP_ROUTERADVERT; }
1260	| IPFY_ICMPT_ROUTERSOL		{ $$ = ICMP_ROUTERSOLICIT; }
1261	;
1262
1263icmpcode:
1264	YY_NUMBER			{ $$ = $1; }
1265	| IPFY_ICMPC_NETUNR		{ $$ = ICMP_UNREACH_NET; }
1266	| IPFY_ICMPC_HSTUNR		{ $$ = ICMP_UNREACH_HOST; }
1267	| IPFY_ICMPC_PROUNR		{ $$ = ICMP_UNREACH_PROTOCOL; }
1268	| IPFY_ICMPC_PORUNR		{ $$ = ICMP_UNREACH_PORT; }
1269	| IPFY_ICMPC_NEEDF		{ $$ = ICMP_UNREACH_NEEDFRAG; }
1270	| IPFY_ICMPC_SRCFAIL		{ $$ = ICMP_UNREACH_SRCFAIL; }
1271	| IPFY_ICMPC_NETUNK		{ $$ = ICMP_UNREACH_NET_UNKNOWN; }
1272	| IPFY_ICMPC_HSTUNK		{ $$ = ICMP_UNREACH_HOST_UNKNOWN; }
1273	| IPFY_ICMPC_ISOLATE		{ $$ = ICMP_UNREACH_ISOLATED; }
1274	| IPFY_ICMPC_NETPRO		{ $$ = ICMP_UNREACH_NET_PROHIB; }
1275	| IPFY_ICMPC_HSTPRO		{ $$ = ICMP_UNREACH_HOST_PROHIB; }
1276	| IPFY_ICMPC_NETTOS		{ $$ = ICMP_UNREACH_TOSNET; }
1277	| IPFY_ICMPC_HSTTOS		{ $$ = ICMP_UNREACH_TOSHOST; }
1278	| IPFY_ICMPC_FLTPRO		{ $$ = ICMP_UNREACH_ADMIN_PROHIBIT; }
1279	| IPFY_ICMPC_HSTPRE		{ $$ = 14; }
1280	| IPFY_ICMPC_CUTPRE		{ $$ = 15; }
1281	;
1282
1283opt:
1284	IPFY_IPOPT_NOP			{ $$ = getoptbyvalue(IPOPT_NOP); }
1285	| IPFY_IPOPT_RR			{ $$ = getoptbyvalue(IPOPT_RR); }
1286	| IPFY_IPOPT_ZSU		{ $$ = getoptbyvalue(IPOPT_ZSU); }
1287	| IPFY_IPOPT_MTUP		{ $$ = getoptbyvalue(IPOPT_MTUP); }
1288	| IPFY_IPOPT_MTUR		{ $$ = getoptbyvalue(IPOPT_MTUR); }
1289	| IPFY_IPOPT_ENCODE		{ $$ = getoptbyvalue(IPOPT_ENCODE); }
1290	| IPFY_IPOPT_TS			{ $$ = getoptbyvalue(IPOPT_TS); }
1291	| IPFY_IPOPT_TR			{ $$ = getoptbyvalue(IPOPT_TR); }
1292	| IPFY_IPOPT_SEC		{ $$ = getoptbyvalue(IPOPT_SECURITY); }
1293	| IPFY_IPOPT_LSRR		{ $$ = getoptbyvalue(IPOPT_LSRR); }
1294	| IPFY_IPOPT_ESEC		{ $$ = getoptbyvalue(IPOPT_E_SEC); }
1295	| IPFY_IPOPT_CIPSO		{ $$ = getoptbyvalue(IPOPT_CIPSO); }
1296	| IPFY_IPOPT_SATID		{ $$ = getoptbyvalue(IPOPT_SATID); }
1297	| IPFY_IPOPT_SSRR		{ $$ = getoptbyvalue(IPOPT_SSRR); }
1298	| IPFY_IPOPT_ADDEXT		{ $$ = getoptbyvalue(IPOPT_ADDEXT); }
1299	| IPFY_IPOPT_VISA		{ $$ = getoptbyvalue(IPOPT_VISA); }
1300	| IPFY_IPOPT_IMITD		{ $$ = getoptbyvalue(IPOPT_IMITD); }
1301	| IPFY_IPOPT_EIP		{ $$ = getoptbyvalue(IPOPT_EIP); }
1302	| IPFY_IPOPT_FINN		{ $$ = getoptbyvalue(IPOPT_FINN); }
1303	| IPFY_IPOPT_DPS		{ $$ = getoptbyvalue(IPOPT_DPS); }
1304	| IPFY_IPOPT_SDB		{ $$ = getoptbyvalue(IPOPT_SDB); }
1305	| IPFY_IPOPT_NSAPA		{ $$ = getoptbyvalue(IPOPT_NSAPA); }
1306	| IPFY_IPOPT_RTRALRT		{ $$ = getoptbyvalue(IPOPT_RTRALRT); }
1307	| IPFY_IPOPT_UMP		{ $$ = getoptbyvalue(IPOPT_UMP); }
1308	| setsecclass secname
1309			{ DOALL(fr->fr_mip.fi_secmsk |= $2;
1310				if (!nowith)
1311					fr->fr_ip.fi_secmsk |= $2;)
1312			  $$ = 0;
1313			  yyresetdict();
1314			}
1315	;
1316
1317setsecclass:
1318	IPFY_SECCLASS	{ yysetdict(ipv4secwords); }
1319	;
1320
1321ipv6hdr:
1322	IPFY_AH			{ $$ = getv6optbyvalue(IPPROTO_AH); }
1323	| IPFY_IPV6OPT_DSTOPTS	{ $$ = getv6optbyvalue(IPPROTO_DSTOPTS); }
1324	| IPFY_IPV6OPT_ESP	{ $$ = getv6optbyvalue(IPPROTO_ESP); }
1325	| IPFY_IPV6OPT_HOPOPTS	{ $$ = getv6optbyvalue(IPPROTO_HOPOPTS); }
1326	| IPFY_IPV6OPT_IPV6	{ $$ = getv6optbyvalue(IPPROTO_IPV6); }
1327	| IPFY_IPV6OPT_NONE	{ $$ = getv6optbyvalue(IPPROTO_NONE); }
1328	| IPFY_IPV6OPT_ROUTING	{ $$ = getv6optbyvalue(IPPROTO_ROUTING); }
1329	| IPFY_IPV6OPT_FRAG	{ $$ = getv6optbyvalue(IPPROTO_FRAGMENT); }
1330	| IPFY_IPV6OPT_MOBILITY	{ $$ = getv6optbyvalue(IPPROTO_MOBILITY); }
1331	;
1332
1333level:	IPFY_LEVEL			{ setsyslog(); }
1334	;
1335
1336loglevel:
1337	priority			{ fr->fr_loglevel = LOG_LOCAL0|$1; }
1338	| facility '.' priority		{ fr->fr_loglevel = $1 | $3; }
1339	;
1340
1341facility:
1342	IPFY_FAC_KERN			{ $$ = LOG_KERN; }
1343	| IPFY_FAC_USER			{ $$ = LOG_USER; }
1344	| IPFY_FAC_MAIL			{ $$ = LOG_MAIL; }
1345	| IPFY_FAC_DAEMON		{ $$ = LOG_DAEMON; }
1346	| IPFY_FAC_AUTH			{ $$ = LOG_AUTH; }
1347	| IPFY_FAC_SYSLOG		{ $$ = LOG_SYSLOG; }
1348	| IPFY_FAC_LPR			{ $$ = LOG_LPR; }
1349	| IPFY_FAC_NEWS			{ $$ = LOG_NEWS; }
1350	| IPFY_FAC_UUCP			{ $$ = LOG_UUCP; }
1351	| IPFY_FAC_CRON			{ $$ = LOG_CRON; }
1352	| IPFY_FAC_FTP			{ $$ = LOG_FTP; }
1353	| IPFY_FAC_AUTHPRIV		{ $$ = LOG_AUTHPRIV; }
1354	| IPFY_FAC_AUDIT		{ $$ = LOG_AUDIT; }
1355	| IPFY_FAC_LFMT			{ $$ = LOG_LFMT; }
1356	| IPFY_FAC_LOCAL0		{ $$ = LOG_LOCAL0; }
1357	| IPFY_FAC_LOCAL1		{ $$ = LOG_LOCAL1; }
1358	| IPFY_FAC_LOCAL2		{ $$ = LOG_LOCAL2; }
1359	| IPFY_FAC_LOCAL3		{ $$ = LOG_LOCAL3; }
1360	| IPFY_FAC_LOCAL4		{ $$ = LOG_LOCAL4; }
1361	| IPFY_FAC_LOCAL5		{ $$ = LOG_LOCAL5; }
1362	| IPFY_FAC_LOCAL6		{ $$ = LOG_LOCAL6; }
1363	| IPFY_FAC_LOCAL7		{ $$ = LOG_LOCAL7; }
1364	| IPFY_FAC_SECURITY		{ $$ = LOG_SECURITY; }
1365	;
1366
1367priority:
1368	IPFY_PRI_EMERG			{ $$ = LOG_EMERG; }
1369	| IPFY_PRI_ALERT		{ $$ = LOG_ALERT; }
1370	| IPFY_PRI_CRIT			{ $$ = LOG_CRIT; }
1371	| IPFY_PRI_ERR			{ $$ = LOG_ERR; }
1372	| IPFY_PRI_WARN			{ $$ = LOG_WARNING; }
1373	| IPFY_PRI_NOTICE		{ $$ = LOG_NOTICE; }
1374	| IPFY_PRI_INFO			{ $$ = LOG_INFO; }
1375	| IPFY_PRI_DEBUG		{ $$ = LOG_DEBUG; }
1376	;
1377
1378compare:
1379	YY_CMP_EQ			{ $$ = FR_EQUAL; }
1380	| YY_CMP_NE			{ $$ = FR_NEQUAL; }
1381	| YY_CMP_LT			{ $$ = FR_LESST; }
1382	| YY_CMP_LE			{ $$ = FR_LESSTE; }
1383	| YY_CMP_GT			{ $$ = FR_GREATERT; }
1384	| YY_CMP_GE			{ $$ = FR_GREATERTE; }
1385	;
1386
1387range:	YY_RANGE_IN			{ $$ = FR_INRANGE; }
1388	| YY_RANGE_OUT			{ $$ = FR_OUTRANGE; }
1389	| ':'				{ $$ = FR_INCRANGE; }
1390	;
1391
1392servicename:
1393	YY_STR				{ $$ = $1; }
1394	;
1395
1396interfacename:	name				{ $$ = $1; }
1397	| name ':' YY_NUMBER
1398		{ $$ = $1;
1399		  fprintf(stderr, "%d: Logical interface %s:%d unsupported, "
1400			  "use the physical interface %s instead.\n",
1401			  yylineNum, $1, $3, $1);
1402		}
1403	;
1404
1405name:	YY_STR				{ $$ = $1; }
1406	| '-'				{ $$ = strdup("-"); }
1407	;
1408
1409ipv4_16:
1410	YY_NUMBER '.' YY_NUMBER
1411		{ if ($1 > 255 || $3 > 255) {
1412			yyerror("Invalid octet string for IP address");
1413			return 0;
1414		  }
1415		  $$.s_addr = ($1 << 24) | ($3 << 16);
1416		  $$.s_addr = htonl($$.s_addr);
1417		}
1418	;
1419
1420ipv4_24:
1421	ipv4_16 '.' YY_NUMBER
1422		{ if ($3 > 255) {
1423			yyerror("Invalid octet string for IP address");
1424			return 0;
1425		  }
1426		  $$.s_addr |= htonl($3 << 8);
1427		}
1428	;
1429
1430ipv4:	ipv4_24 '.' YY_NUMBER
1431		{ if ($3 > 255) {
1432			yyerror("Invalid octet string for IP address");
1433			return 0;
1434		  }
1435		  $$.s_addr |= htonl($3);
1436		}
1437	| ipv4_24
1438	| ipv4_16
1439	;
1440
1441%%
1442
1443
1444static	struct	wordtab ipfwords[95] = {
1445	{ "age",			IPFY_AGE },
1446	{ "ah",				IPFY_AH },
1447	{ "all",			IPFY_ALL },
1448	{ "and",			IPFY_AND },
1449	{ "auth",			IPFY_AUTH },
1450	{ "bad",			IPFY_BAD },
1451	{ "bad-nat",			IPFY_BADNAT },
1452	{ "bad-src",			IPFY_BADSRC },
1453	{ "bcast",			IPFY_BROADCAST },
1454	{ "block",			IPFY_BLOCK },
1455	{ "body",			IPFY_BODY },
1456	{ "bpf-v4",			IPFY_BPFV4 },
1457#ifdef USE_INET6
1458	{ "bpf-v6",			IPFY_BPFV6 },
1459#endif
1460	{ "call",			IPFY_CALL },
1461	{ "code",			IPFY_ICMPCODE },
1462	{ "count",			IPFY_COUNT },
1463	{ "dup-to",			IPFY_DUPTO },
1464	{ "eq",				YY_CMP_EQ },
1465	{ "esp",			IPFY_ESP },
1466	{ "fastroute",			IPFY_FROUTE },
1467	{ "first",			IPFY_FIRST },
1468	{ "flags",			IPFY_FLAGS },
1469	{ "frag",			IPFY_FRAG },
1470	{ "frag-body",			IPFY_FRAGBODY },
1471	{ "frags",			IPFY_FRAGS },
1472	{ "from",			IPFY_FROM },
1473	{ "ge",				YY_CMP_GE },
1474	{ "group",			IPFY_GROUP },
1475	{ "gt",				YY_CMP_GT },
1476	{ "head",			IPFY_HEAD },
1477	{ "icmp",			IPFY_ICMP },
1478	{ "icmp-type",			IPFY_ICMPTYPE },
1479	{ "in",				IPFY_IN },
1480	{ "in-via",			IPFY_INVIA },
1481	{ "ipopt",			IPFY_IPOPTS },
1482	{ "ipopts",			IPFY_IPOPTS },
1483	{ "keep",			IPFY_KEEP },
1484	{ "le",				YY_CMP_LE },
1485	{ "level",			IPFY_LEVEL },
1486	{ "limit",			IPFY_LIMIT },
1487	{ "log",			IPFY_LOG },
1488	{ "lowttl",			IPFY_LOWTTL },
1489	{ "lt",				YY_CMP_LT },
1490	{ "mask",			IPFY_MASK },
1491	{ "match-tag",			IPFY_MATCHTAG },
1492	{ "mbcast",			IPFY_MBCAST },
1493	{ "mcast",			IPFY_MULTICAST },
1494	{ "multicast",			IPFY_MULTICAST },
1495	{ "nat",			IPFY_NAT },
1496	{ "ne",				YY_CMP_NE },
1497	{ "net",			IPFY_NETWORK },
1498	{ "newisn",			IPFY_NEWISN },
1499	{ "no",				IPFY_NO },
1500	{ "no-icmp-err",		IPFY_NOICMPERR },
1501	{ "nomatch",			IPFY_NOMATCH },
1502	{ "now",			IPFY_NOW },
1503	{ "not",			IPFY_NOT },
1504	{ "oow",			IPFY_OOW },
1505	{ "on",				IPFY_ON },
1506	{ "opt",			IPFY_OPT },
1507	{ "or-block",			IPFY_ORBLOCK },
1508	{ "out",			IPFY_OUT },
1509	{ "out-via",			IPFY_OUTVIA },
1510	{ "pass",			IPFY_PASS },
1511	{ "port",			IPFY_PORT },
1512	{ "pps",			IPFY_PPS },
1513	{ "preauth",			IPFY_PREAUTH },
1514	{ "proto",			IPFY_PROTO },
1515	{ "quick",			IPFY_QUICK },
1516	{ "reply-to",			IPFY_REPLY_TO },
1517	{ "return-icmp",		IPFY_RETICMP },
1518	{ "return-icmp-as-dest",	IPFY_RETICMPASDST },
1519	{ "return-rst",			IPFY_RETRST },
1520	{ "route-to",			IPFY_ROUTETO },
1521	{ "sec-class",			IPFY_SECCLASS },
1522	{ "set-tag",			IPFY_SETTAG },
1523	{ "skip",			IPFY_SKIP },
1524	{ "short",			IPFY_SHORT },
1525	{ "state",			IPFY_STATE },
1526	{ "state-age",			IPFY_AGE },
1527	{ "strict",			IPFY_STRICT },
1528	{ "sync",			IPFY_SYNC },
1529	{ "tcp",			IPFY_TCP },
1530	{ "tcp-udp",			IPFY_TCPUDP },
1531	{ "tos",			IPFY_TOS },
1532	{ "to",				IPFY_TO },
1533	{ "ttl",			IPFY_TTL },
1534	{ "udp",			IPFY_UDP },
1535	{ "v6hdrs",			IPF6_V6HDRS },
1536	{ "with",			IPFY_WITH },
1537	{ NULL,				0 }
1538};
1539
1540static	struct	wordtab	addrwords[4] = {
1541	{ "any",			IPFY_ANY },
1542	{ "hash",			IPFY_HASH },
1543	{ "pool",			IPFY_POOL },
1544	{ NULL,				0 }
1545};
1546
1547static	struct	wordtab	maskwords[5] = {
1548	{ "broadcast",			IPFY_BROADCAST },
1549	{ "netmasked",			IPFY_NETMASKED },
1550	{ "network",			IPFY_NETWORK },
1551	{ "peer",			IPFY_PEER },
1552	{ NULL,				0 }
1553};
1554
1555static	struct	wordtab icmptypewords[16] = {
1556	{ "echo",			IPFY_ICMPT_ECHO },
1557	{ "echorep",			IPFY_ICMPT_ECHOR },
1558	{ "inforeq",			IPFY_ICMPT_INFOREQ },
1559	{ "inforep",			IPFY_ICMPT_INFOREP },
1560	{ "maskrep",			IPFY_ICMPT_MASKREP },
1561	{ "maskreq",			IPFY_ICMPT_MASKREQ },
1562	{ "paramprob",			IPFY_ICMPT_PARAMP },
1563	{ "redir",			IPFY_ICMPT_REDIR },
1564	{ "unreach",			IPFY_ICMPT_UNR },
1565	{ "routerad",			IPFY_ICMPT_ROUTERAD },
1566	{ "routersol",			IPFY_ICMPT_ROUTERSOL },
1567	{ "squench",			IPFY_ICMPT_SQUENCH },
1568	{ "timest",			IPFY_ICMPT_TIMEST },
1569	{ "timestrep",			IPFY_ICMPT_TIMESTREP },
1570	{ "timex",			IPFY_ICMPT_TIMEX },
1571	{ NULL,				0 },
1572};
1573
1574static	struct	wordtab icmpcodewords[17] = {
1575	{ "cutoff-preced",		IPFY_ICMPC_CUTPRE },
1576	{ "filter-prohib",		IPFY_ICMPC_FLTPRO },
1577	{ "isolate",			IPFY_ICMPC_ISOLATE },
1578	{ "needfrag",			IPFY_ICMPC_NEEDF },
1579	{ "net-prohib",			IPFY_ICMPC_NETPRO },
1580	{ "net-tos",			IPFY_ICMPC_NETTOS },
1581	{ "host-preced",		IPFY_ICMPC_HSTPRE },
1582	{ "host-prohib",		IPFY_ICMPC_HSTPRO },
1583	{ "host-tos",			IPFY_ICMPC_HSTTOS },
1584	{ "host-unk",			IPFY_ICMPC_HSTUNK },
1585	{ "host-unr",			IPFY_ICMPC_HSTUNR },
1586	{ "net-unk",			IPFY_ICMPC_NETUNK },
1587	{ "net-unr",			IPFY_ICMPC_NETUNR },
1588	{ "port-unr",			IPFY_ICMPC_PORUNR },
1589	{ "proto-unr",			IPFY_ICMPC_PROUNR },
1590	{ "srcfail",			IPFY_ICMPC_SRCFAIL },
1591	{ NULL,				0 },
1592};
1593
1594static	struct	wordtab ipv4optwords[25] = {
1595	{ "addext",			IPFY_IPOPT_ADDEXT },
1596	{ "cipso",			IPFY_IPOPT_CIPSO },
1597	{ "dps",			IPFY_IPOPT_DPS },
1598	{ "e-sec",			IPFY_IPOPT_ESEC },
1599	{ "eip",			IPFY_IPOPT_EIP },
1600	{ "encode",			IPFY_IPOPT_ENCODE },
1601	{ "finn",			IPFY_IPOPT_FINN },
1602	{ "imitd",			IPFY_IPOPT_IMITD },
1603	{ "lsrr",			IPFY_IPOPT_LSRR },
1604	{ "mtup",			IPFY_IPOPT_MTUP },
1605	{ "mtur",			IPFY_IPOPT_MTUR },
1606	{ "nop",			IPFY_IPOPT_NOP },
1607	{ "nsapa",			IPFY_IPOPT_NSAPA },
1608	{ "rr",				IPFY_IPOPT_RR },
1609	{ "rtralrt",			IPFY_IPOPT_RTRALRT },
1610	{ "satid",			IPFY_IPOPT_SATID },
1611	{ "sdb",			IPFY_IPOPT_SDB },
1612	{ "sec",			IPFY_IPOPT_SEC },
1613	{ "ssrr",			IPFY_IPOPT_SSRR },
1614	{ "tr",				IPFY_IPOPT_TR },
1615	{ "ts",				IPFY_IPOPT_TS },
1616	{ "ump",			IPFY_IPOPT_UMP },
1617	{ "visa",			IPFY_IPOPT_VISA },
1618	{ "zsu",			IPFY_IPOPT_ZSU },
1619	{ NULL,				0 },
1620};
1621
1622static	struct	wordtab ipv4secwords[9] = {
1623	{ "confid",			IPFY_SEC_CONF },
1624	{ "reserv-1",			IPFY_SEC_RSV1 },
1625	{ "reserv-2",			IPFY_SEC_RSV2 },
1626	{ "reserv-3",			IPFY_SEC_RSV3 },
1627	{ "reserv-4",			IPFY_SEC_RSV4 },
1628	{ "secret",			IPFY_SEC_SEC },
1629	{ "topsecret",			IPFY_SEC_TS },
1630	{ "unclass",			IPFY_SEC_UNC },
1631	{ NULL,				0 },
1632};
1633
1634static	struct	wordtab ipv6optwords[9] = {
1635	{ "dstopts",			IPFY_IPV6OPT_DSTOPTS },
1636	{ "esp",			IPFY_IPV6OPT_ESP },
1637	{ "frag",			IPFY_IPV6OPT_FRAG },
1638	{ "hopopts",			IPFY_IPV6OPT_HOPOPTS },
1639	{ "ipv6",			IPFY_IPV6OPT_IPV6 },
1640	{ "mobility",			IPFY_IPV6OPT_MOBILITY },
1641	{ "none",			IPFY_IPV6OPT_NONE },
1642	{ "routing",			IPFY_IPV6OPT_ROUTING },
1643	{ NULL,				0 },
1644};
1645
1646static	struct	wordtab logwords[33] = {
1647	{ "kern",			IPFY_FAC_KERN },
1648	{ "user",			IPFY_FAC_USER },
1649	{ "mail",			IPFY_FAC_MAIL },
1650	{ "daemon",			IPFY_FAC_DAEMON },
1651	{ "auth",			IPFY_FAC_AUTH },
1652	{ "syslog",			IPFY_FAC_SYSLOG },
1653	{ "lpr",			IPFY_FAC_LPR },
1654	{ "news",			IPFY_FAC_NEWS },
1655	{ "uucp",			IPFY_FAC_UUCP },
1656	{ "cron",			IPFY_FAC_CRON },
1657	{ "ftp",			IPFY_FAC_FTP },
1658	{ "authpriv",			IPFY_FAC_AUTHPRIV },
1659	{ "audit",			IPFY_FAC_AUDIT },
1660	{ "logalert",			IPFY_FAC_LFMT },
1661	{ "console",			IPFY_FAC_CONSOLE },
1662	{ "security",			IPFY_FAC_SECURITY },
1663	{ "local0",			IPFY_FAC_LOCAL0 },
1664	{ "local1",			IPFY_FAC_LOCAL1 },
1665	{ "local2",			IPFY_FAC_LOCAL2 },
1666	{ "local3",			IPFY_FAC_LOCAL3 },
1667	{ "local4",			IPFY_FAC_LOCAL4 },
1668	{ "local5",			IPFY_FAC_LOCAL5 },
1669	{ "local6",			IPFY_FAC_LOCAL6 },
1670	{ "local7",			IPFY_FAC_LOCAL7 },
1671	{ "emerg",			IPFY_PRI_EMERG },
1672	{ "alert",			IPFY_PRI_ALERT },
1673	{ "crit",			IPFY_PRI_CRIT },
1674	{ "err",			IPFY_PRI_ERR },
1675	{ "warn",			IPFY_PRI_WARN },
1676	{ "notice",			IPFY_PRI_NOTICE },
1677	{ "info",			IPFY_PRI_INFO },
1678	{ "debug",			IPFY_PRI_DEBUG },
1679	{ NULL,				0 },
1680};
1681
1682
1683
1684
1685int ipf_parsefile(fd, addfunc, iocfuncs, filename)
1686int fd;
1687addfunc_t addfunc;
1688ioctlfunc_t *iocfuncs;
1689char *filename;
1690{
1691	FILE *fp = NULL;
1692	char *s;
1693
1694	yylineNum = 1;
1695	yysettab(ipfwords);
1696
1697	s = getenv("YYDEBUG");
1698	if (s != NULL)
1699		yydebug = atoi(s);
1700	else
1701		yydebug = 0;
1702
1703	if (strcmp(filename, "-")) {
1704		fp = fopen(filename, "r");
1705		if (fp == NULL) {
1706			fprintf(stderr, "fopen(%s) failed: %s\n", filename,
1707				STRERROR(errno));
1708			return -1;
1709		}
1710	} else
1711		fp = stdin;
1712
1713	while (ipf_parsesome(fd, addfunc, iocfuncs, fp) == 1)
1714		;
1715	if (fp != NULL)
1716		fclose(fp);
1717	return 0;
1718}
1719
1720
1721int ipf_parsesome(fd, addfunc, iocfuncs, fp)
1722int fd;
1723addfunc_t addfunc;
1724ioctlfunc_t *iocfuncs;
1725FILE *fp;
1726{
1727	char *s;
1728	int i;
1729
1730	ipffd = fd;
1731	for (i = 0; i <= IPL_LOGMAX; i++)
1732		ipfioctl[i] = iocfuncs[i];
1733	ipfaddfunc = addfunc;
1734
1735	if (feof(fp))
1736		return 0;
1737	i = fgetc(fp);
1738	if (i == EOF)
1739		return 0;
1740	if (ungetc(i, fp) == 0)
1741		return 0;
1742	if (feof(fp))
1743		return 0;
1744	s = getenv("YYDEBUG");
1745	if (s != NULL)
1746		yydebug = atoi(s);
1747	else
1748		yydebug = 0;
1749
1750	yyin = fp;
1751	yyparse();
1752	return 1;
1753}
1754
1755
1756static void newrule()
1757{
1758	frentry_t *frn;
1759
1760	frn = (frentry_t *)calloc(1, sizeof(frentry_t));
1761	for (fr = frtop; fr != NULL && fr->fr_next != NULL; fr = fr->fr_next)
1762		;
1763	if (fr != NULL)
1764		fr->fr_next = frn;
1765	if (frtop == NULL)
1766		frtop = frn;
1767	fr = frn;
1768	frc = frn;
1769	fr->fr_loglevel = 0xffff;
1770	fr->fr_isc = (void *)-1;
1771	fr->fr_logtag = FR_NOLOGTAG;
1772	fr->fr_type = FR_T_NONE;
1773	if (use_inet6 != 0)
1774		fr->fr_v = 6;
1775	else
1776		fr->fr_v = 4;
1777
1778	nrules = 1;
1779}
1780
1781
1782static void setipftype()
1783{
1784	for (fr = frc; fr != NULL; fr = fr->fr_next) {
1785		if (fr->fr_type == FR_T_NONE) {
1786			fr->fr_type = FR_T_IPF;
1787			fr->fr_data = (void *)calloc(sizeof(fripf_t), 1);
1788			fr->fr_dsize = sizeof(fripf_t);
1789			fr->fr_ip.fi_v = frc->fr_v;
1790			fr->fr_mip.fi_v = 0xf;
1791			fr->fr_ipf->fri_sifpidx = -1;
1792			fr->fr_ipf->fri_difpidx = -1;
1793		}
1794		if (fr->fr_type != FR_T_IPF) {
1795			fprintf(stderr, "IPF Type not set\n");
1796		}
1797	}
1798}
1799
1800
1801static frentry_t *addrule()
1802{
1803	frentry_t *f, *f1, *f2;
1804	int count;
1805
1806	for (f2 = frc; f2->fr_next != NULL; f2 = f2->fr_next)
1807		;
1808
1809	count = nrules;
1810	f = f2;
1811	for (f1 = frc; count > 0; count--, f1 = f1->fr_next) {
1812		f->fr_next = (frentry_t *)calloc(sizeof(*f), 1);
1813		added++;
1814		f = f->fr_next;
1815		bcopy(f1, f, sizeof(*f));
1816		f->fr_next = NULL;
1817		if (f->fr_caddr != NULL) {
1818			f->fr_caddr = malloc(f->fr_dsize);
1819			bcopy(f1->fr_caddr, f->fr_caddr, f->fr_dsize);
1820		}
1821	}
1822
1823	return f2->fr_next;
1824}
1825
1826
1827static u_32_t lookuphost(name)
1828char *name;
1829{
1830	u_32_t addr;
1831	int i;
1832
1833	hashed = 0;
1834	pooled = 0;
1835	dynamic = -1;
1836
1837	for (i = 0; i < 4; i++) {
1838		if (strncmp(name, frc->fr_ifnames[i],
1839			    sizeof(frc->fr_ifnames[i])) == 0) {
1840			ifpflag = FRI_DYNAMIC;
1841			dynamic = i;
1842			return 0;
1843		}
1844	}
1845
1846	if (gethost(name, &addr) == -1) {
1847		fprintf(stderr, "unknown name \"%s\"\n", name);
1848		return 0;
1849	}
1850	return addr;
1851}
1852
1853
1854static void dobpf(v, phrase)
1855int v;
1856char *phrase;
1857{
1858#ifdef IPFILTER_BPF
1859	struct bpf_program bpf;
1860	struct pcap *p;
1861#endif
1862	fakebpf_t *fb;
1863	u_32_t l;
1864	char *s;
1865	int i;
1866
1867	for (fr = frc; fr != NULL; fr = fr->fr_next) {
1868		if (fr->fr_type != FR_T_NONE) {
1869			fprintf(stderr, "cannot mix IPF and BPF matching\n");
1870			return;
1871		}
1872		fr->fr_v = v;
1873		fr->fr_type = FR_T_BPFOPC;
1874
1875		if (!strncmp(phrase, "0x", 2)) {
1876			fb = malloc(sizeof(fakebpf_t));
1877
1878			for (i = 0, s = strtok(phrase, " \r\n\t"); s != NULL;
1879			     s = strtok(NULL, " \r\n\t"), i++) {
1880				fb = realloc(fb, (i / 4 + 1) * sizeof(*fb));
1881				l = (u_32_t)strtol(s, NULL, 0);
1882				switch (i & 3)
1883				{
1884				case 0 :
1885					fb[i / 4].fb_c = l & 0xffff;
1886					break;
1887				case 1 :
1888					fb[i / 4].fb_t = l & 0xff;
1889					break;
1890				case 2 :
1891					fb[i / 4].fb_f = l & 0xff;
1892					break;
1893				case 3 :
1894					fb[i / 4].fb_k = l;
1895					break;
1896				}
1897			}
1898			if ((i & 3) != 0) {
1899				fprintf(stderr,
1900					"Odd number of bytes in BPF code\n");
1901				exit(1);
1902			}
1903			i--;
1904			fr->fr_dsize = (i / 4 + 1) * sizeof(*fb);
1905			fr->fr_data = fb;
1906			return;
1907		}
1908
1909#ifdef IPFILTER_BPF
1910		bzero((char *)&bpf, sizeof(bpf));
1911		p = pcap_open_dead(DLT_RAW, 1);
1912		if (!p) {
1913			fprintf(stderr, "pcap_open_dead failed\n");
1914			return;
1915		}
1916
1917		if (pcap_compile(p, &bpf, phrase, 1, 0xffffffff)) {
1918			pcap_perror(p, "ipf");
1919			pcap_close(p);
1920			fprintf(stderr, "pcap parsing failed (%s)\n", phrase);
1921			return;
1922		}
1923		pcap_close(p);
1924
1925		fr->fr_dsize = bpf.bf_len * sizeof(struct bpf_insn);
1926		fr->fr_data = malloc(fr->fr_dsize);
1927		bcopy((char *)bpf.bf_insns, fr->fr_data, fr->fr_dsize);
1928		if (!bpf_validate(fr->fr_data, bpf.bf_len)) {
1929			fprintf(stderr, "BPF validation failed\n");
1930			return;
1931		}
1932#endif
1933	}
1934
1935#ifdef IPFILTER_BPF
1936	if (opts & OPT_DEBUG)
1937		bpf_dump(&bpf, 0);
1938#else
1939	fprintf(stderr, "BPF filter expressions not supported\n");
1940	exit(1);
1941#endif
1942}
1943
1944
1945static void resetaddr()
1946{
1947	hashed = 0;
1948	pooled = 0;
1949	dynamic = -1;
1950}
1951
1952
1953static alist_t *newalist(ptr)
1954alist_t *ptr;
1955{
1956	alist_t *al;
1957
1958	al = malloc(sizeof(*al));
1959	if (al == NULL)
1960		return NULL;
1961	al->al_not = 0;
1962	al->al_next = ptr;
1963	return al;
1964}
1965
1966
1967static int makepool(list)
1968alist_t *list;
1969{
1970	ip_pool_node_t *n, *top;
1971	ip_pool_t pool;
1972	alist_t *a;
1973	int num;
1974
1975	if (list == NULL)
1976		return 0;
1977	top = calloc(1, sizeof(*top));
1978	if (top == NULL)
1979		return 0;
1980
1981	for (n = top, a = list; (n != NULL) && (a != NULL); a = a->al_next) {
1982		n->ipn_addr.adf_addr.in4.s_addr = a->al_1;
1983		n->ipn_mask.adf_addr.in4.s_addr = a->al_2;
1984		n->ipn_info = a->al_not;
1985		if (a->al_next != NULL) {
1986			n->ipn_next = calloc(1, sizeof(*n));
1987			n = n->ipn_next;
1988		}
1989	}
1990
1991	bzero((char *)&pool, sizeof(pool));
1992	pool.ipo_unit = IPL_LOGIPF;
1993	pool.ipo_list = top;
1994	num = load_pool(&pool, ipfioctl[IPL_LOGLOOKUP]);
1995
1996	while ((n = top) != NULL) {
1997		top = n->ipn_next;
1998		free(n);
1999	}
2000	return num;
2001}
2002
2003
2004static u_int makehash(list)
2005alist_t *list;
2006{
2007	iphtent_t *n, *top;
2008	iphtable_t iph;
2009	alist_t *a;
2010	int num;
2011
2012	if (list == NULL)
2013		return 0;
2014	top = calloc(1, sizeof(*top));
2015	if (top == NULL)
2016		return 0;
2017
2018	for (n = top, a = list; (n != NULL) && (a != NULL); a = a->al_next) {
2019		n->ipe_addr.in4_addr = a->al_1;
2020		n->ipe_mask.in4_addr = a->al_2;
2021		n->ipe_value = 0;
2022		if (a->al_next != NULL) {
2023			n->ipe_next = calloc(1, sizeof(*n));
2024			n = n->ipe_next;
2025		}
2026	}
2027
2028	bzero((char *)&iph, sizeof(iph));
2029	iph.iph_unit = IPL_LOGIPF;
2030	iph.iph_type = IPHASH_LOOKUP;
2031	*iph.iph_name = '\0';
2032
2033	if (load_hash(&iph, top, ipfioctl[IPL_LOGLOOKUP]) == 0)
2034		sscanf(iph.iph_name, "%u", &num);
2035	else
2036		num = 0;
2037
2038	while ((n = top) != NULL) {
2039		top = n->ipe_next;
2040		free(n);
2041	}
2042	return num;
2043}
2044
2045
2046void ipf_addrule(fd, ioctlfunc, ptr)
2047int fd;
2048ioctlfunc_t ioctlfunc;
2049void *ptr;
2050{
2051	ioctlcmd_t add, del;
2052	frentry_t *fr;
2053	ipfobj_t obj;
2054
2055	if (ptr == NULL)
2056		return;
2057
2058	fr = ptr;
2059	add = 0;
2060	del = 0;
2061
2062	bzero((char *)&obj, sizeof(obj));
2063	obj.ipfo_rev = IPFILTER_VERSION;
2064	obj.ipfo_size = sizeof(*fr);
2065	obj.ipfo_type = IPFOBJ_FRENTRY;
2066	obj.ipfo_ptr = ptr;
2067
2068	if ((opts & OPT_DONOTHING) != 0)
2069		fd = -1;
2070
2071	if (opts & OPT_ZERORULEST) {
2072		add = SIOCZRLST;
2073	} else if (opts & OPT_INACTIVE) {
2074		add = (u_int)fr->fr_hits ? SIOCINIFR :
2075					   SIOCADIFR;
2076		del = SIOCRMIFR;
2077	} else {
2078		add = (u_int)fr->fr_hits ? SIOCINAFR :
2079					   SIOCADAFR;
2080		del = SIOCRMAFR;
2081	}
2082
2083	if ((opts & OPT_OUTQUE) != 0)
2084		fr->fr_flags |= FR_OUTQUE;
2085	if (fr->fr_hits)
2086		fr->fr_hits--;
2087	if ((opts & OPT_VERBOSE) != 0)
2088		printfr(fr, ioctlfunc);
2089
2090	if ((opts & OPT_DEBUG) != 0) {
2091		binprint(fr, sizeof(*fr));
2092		if (fr->fr_data != NULL)
2093			binprint(fr->fr_data, fr->fr_dsize);
2094	}
2095
2096	if ((opts & OPT_ZERORULEST) != 0) {
2097		if ((*ioctlfunc)(fd, add, (void *)&obj) == -1) {
2098			if ((opts & OPT_DONOTHING) == 0) {
2099				fprintf(stderr, "%d:", yylineNum);
2100				perror("ioctl(SIOCZRLST)");
2101			}
2102		} else {
2103#ifdef	USE_QUAD_T
2104			printf("hits %qd bytes %qd ",
2105				(long long)fr->fr_hits,
2106				(long long)fr->fr_bytes);
2107#else
2108			printf("hits %ld bytes %ld ",
2109				fr->fr_hits, fr->fr_bytes);
2110#endif
2111			printfr(fr, ioctlfunc);
2112		}
2113	} else if ((opts & OPT_REMOVE) != 0) {
2114		if ((*ioctlfunc)(fd, del, (void *)&obj) == -1) {
2115			if ((opts & OPT_DONOTHING) != 0) {
2116				fprintf(stderr, "%d:", yylineNum);
2117				perror("ioctl(delete rule)");
2118			}
2119		}
2120	} else {
2121		if ((*ioctlfunc)(fd, add, (void *)&obj) == -1) {
2122			if (!(opts & OPT_DONOTHING)) {
2123				fprintf(stderr, "%d:", yylineNum);
2124				perror("ioctl(add/insert rule)");
2125			}
2126		}
2127	}
2128}
2129
2130static void setsyslog()
2131{
2132	yysetdict(logwords);
2133	yybreakondot = 1;
2134}
2135
2136
2137static void unsetsyslog()
2138{
2139	yyresetdict();
2140	yybreakondot = 0;
2141}
2142
2143
2144static void fillgroup(fr)
2145frentry_t *fr;
2146{
2147	frentry_t *f;
2148
2149	for (f = frold; f != NULL; f = f->fr_next)
2150		if (strncmp(f->fr_grhead, fr->fr_group, FR_GROUPLEN) == 0)
2151			break;
2152	if (f == NULL)
2153		return;
2154
2155	/*
2156	 * Only copy down matching fields if the rules are of the same type
2157	 * and are of ipf type.   The only fields that are copied are those
2158	 * that impact the rule parsing itself, eg. need for knowing what the
2159	 * protocol should be for rules with port comparisons in them.
2160	 */
2161	if (f->fr_type != fr->fr_type || f->fr_type != FR_T_IPF)
2162		return;
2163
2164	if (fr->fr_v == 0 && f->fr_v != 0)
2165		fr->fr_v = f->fr_v;
2166
2167	if (fr->fr_mproto == 0 && f->fr_mproto != 0)
2168		fr->fr_mproto = f->fr_mproto;
2169	if (fr->fr_proto == 0 && f->fr_proto != 0)
2170		fr->fr_proto = f->fr_proto;
2171
2172	if ((fr->fr_mproto == 0) && ((fr->fr_flx & FI_TCPUDP) == 0) &&
2173	    ((f->fr_flx & FI_TCPUDP) != 0))
2174		fr->fr_flx |= FI_TCPUDP;
2175}
2176