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