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