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