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