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