xref: /netbsd-src/external/bsd/ipf/dist/tools/ipf_y.y (revision 19d3d51e867fb4d7cd1988a3603e969aa5dbf19a)
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 
26 extern	void	yyerror __P((char *));
27 extern	int	yyparse __P((void));
28 extern	int	yylex __P((void));
29 extern	int	yydebug;
30 extern	FILE	*yyin;
31 extern	int	yylineNum;
32 
33 static	int	addname __P((frentry_t **, char *));
34 static	frentry_t *addrule __P((void));
35 static frentry_t *allocfr __P((void));
36 static	void	build_dstaddr_af __P((frentry_t *, void *));
37 static	void	build_srcaddr_af __P((frentry_t *, void *));
38 static	void	dobpf __P((int, char *));
39 static	void	doipfexpr __P((char *));
40 static	void	do_tuneint __P((char *, int));
41 static	void	do_tunestr __P((char *, char *));
42 static	void	fillgroup __P((frentry_t *));
43 static	int	lookuphost __P((char *, i6addr_t *));
44 static	u_int	makehash __P((struct alist_s *));
45 static	int	makepool __P((struct alist_s *));
46 static	struct	alist_s	*newalist __P((struct alist_s *));
47 static	void	newrule __P((void));
48 static	void	resetaddr __P((void));
49 static	void	setgroup __P((frentry_t **, char *));
50 static	void	setgrhead __P((frentry_t **, char *));
51 static	void	seticmphead __P((frentry_t **, char *));
52 static	void	setifname __P((frentry_t **, int, char *));
53 static	void	setipftype __P((void));
54 static	void	setsyslog __P((void));
55 static	void	unsetsyslog __P((void));
56 
57 frentry_t	*fr = NULL, *frc = NULL, *frtop = NULL, *frold = NULL;
58 
59 static	int		ifpflag = 0;
60 static	int		nowith = 0;
61 static	int		dynamic = -1;
62 static	int		pooled = 0;
63 static	int		hashed = 0;
64 static	int		nrules = 0;
65 static	int		newlist = 0;
66 static	int		added = 0;
67 static	int		ipffd = -1;
68 static	int		*yycont = NULL;
69 static	ioctlfunc_t	ipfioctls[IPL_LOGSIZE];
70 static	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 %%
188 file:	settings rules
189 	| rules
190 	;
191 
192 settings:
193 	YY_COMMENT
194 	| setting
195 	| settings setting
196 	;
197 
198 rules:	line
199 	| assign
200 	| rules line
201 	| rules assign
202 	;
203 
204 setting:
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 
210 line:	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 
226 xx:					{ newrule(); }
227 	;
228 
229 assign:	YY_STR assigning YY_STR ';'	{ set_variable($1, $3);
230 					  resetlexer();
231 					  free($1);
232 					  free($3);
233 					  yyvarnext = 0;
234 					}
235 	;
236 
237 assigning:
238 	'='				{ yyvarnext = 1; }
239 	;
240 
241 rule:	inrule eol
242 	| outrule eol
243 	;
244 
245 eol:	| ';'
246 	;
247 
248 inrule:
249 	rulehead markin inopts rulemain ruletail intag ruletail2
250 	;
251 
252 outrule:
253 	rulehead markout outopts rulemain ruletail outtag ruletail2
254 	;
255 
256 rulehead:
257 	xx collection action
258 	| xx insert collection action
259 	;
260 
261 markin:	IPFY_IN				{ fr->fr_flags |= FR_INQUE; }
262 	;
263 
264 markout:
265 	IPFY_OUT			{ fr->fr_flags |= FR_OUTQUE; }
266 	;
267 
268 rulemain:
269 	ipfrule
270 	| bpfrule
271 	| exprrule
272 	;
273 
274 ipfrule:
275 	family tos ttl proto ip
276 	;
277 
278 family:	| 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 
304 bpfrule:
305 	IPFY_BPFV4 '{' YY_STR '}' 	{ dobpf(4, $3); free($3); }
306 	| IPFY_BPFV6 '{' YY_STR '}' 	{ dobpf(6, $3); free($3); }
307 	;
308 
309 exprrule:
310 	IPFY_IPFEXPR '{' YY_STR '}'	{ doipfexpr($3); }
311 	;
312 
313 ruletail:
314 	with keep head group
315 	;
316 
317 ruletail2:
318 	pps age new rulettl comment
319 	;
320 
321 intag:	settagin matchtagin
322 	;
323 
324 outtag:	settagout matchtagout
325 	;
326 
327 insert:
328 	'@' YY_NUMBER			{ fr->fr_hits = (U_QUAD_T)$2 + 1; }
329 	;
330 
331 collection:
332 	| YY_NUMBER			{ fr->fr_collect = $1; }
333 	;
334 
335 action:	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 
348 block:	blocked
349 	| blocked blockreturn
350 	;
351 
352 blocked:
353 	IPFY_BLOCK			{ fr->fr_flags = FR_BLOCK; }
354 	;
355 blockreturn:
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 
363 decaps:	IPFY_DECAPS
364 	| IPFY_DECAPS IPFY_L5AS '(' YY_STR ')'
365 					{ fr->fr_icode = atoi($4); }
366 	;
367 
368 log:	IPFY_LOG			{ fr->fr_flags |= FR_LOG; }
369 	| IPFY_LOG logoptions		{ fr->fr_flags |= FR_LOG; }
370 	;
371 
372 auth:	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 
377 func:	YY_STR '/' YY_NUMBER
378 			{ fr->fr_func = nametokva($1, ipfioctls[IPL_LOGIPF]);
379 			  fr->fr_arg = $3;
380 			  free($1);
381 			}
382 	;
383 
384 inopts:
385 	| inopts inopt
386 	;
387 
388 inopt:
389 	logopt
390 	| quick
391 	| on
392 	| dup
393 	| froute
394 	| proute
395 	| replyto
396 	;
397 
398 outopts:
399 	| outopts outopt
400 	;
401 
402 outopt:
403 	logopt
404 	| quick
405 	| on
406 	| dup
407 	| proute
408 	| froute
409 	| replyto
410 	;
411 
412 tos:	| 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 
417 settos:	IPFY_TOS			{ setipftype(); }
418 	;
419 
420 toslist:
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 
429 ttl:	| setttl YY_NUMBER
430 			{ DOALL(fr->fr_ttl = $2; fr->fr_mttl = 0xff;) }
431 	| setttl lstart ttllist lend
432 	;
433 
434 lstart:	'{'				{ newlist = 1; fr = frc; added = 0; }
435 	;
436 
437 lend:	'}'				{ nrules += added; }
438 	;
439 
440 lmore:	lanother			{ if (newlist == 1) {
441 						newlist = 0;
442 					  }
443 					  fr = addrule();
444 					  if (yycont != NULL)
445 						*yycont = 1;
446 					}
447 	;
448 
449 lanother:
450 	| ','
451 	;
452 
453 setttl:	IPFY_TTL			{ setipftype(); }
454 	;
455 
456 ttllist:
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 
462 proto:	| protox protocol		{ yyresetdict(); }
463 	;
464 
465 protox:	IPFY_PROTO			{ setipftype();
466 					  fr = frc;
467 					  yysetdict(NULL); }
468 	;
469 
470 ip:	srcdst flags icmp
471 	;
472 
473 group:	| IPFY_GROUP groupname		{ DOALL(setgroup(&fr, $2); \
474 						fillgroup(fr););
475 					  free($2);
476 					}
477 	;
478 
479 head:	| IPFY_HEAD groupname		{ DOALL(setgrhead(&fr, $2););
480 					  free($2);
481 					}
482 	;
483 
484 groupname:
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 
494 settagin:
495 	| IPFY_SETTAG '(' taginlist ')'
496 	;
497 
498 taginlist:
499 	taginspec
500 	| taginlist ',' taginspec
501 	;
502 
503 taginspec:
504 	logtag
505 	;
506 
507 nattag:	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 
514 logtag:	IPFY_LOG '=' YY_NUMBER		{ DOALL(fr->fr_logtag = $3;) }
515 	;
516 
517 settagout:
518 	| IPFY_SETTAG '(' tagoutlist ')'
519 	;
520 
521 tagoutlist:
522 	tagoutspec
523 	| tagoutlist ',' tagoutspec
524 	;
525 
526 tagoutspec:
527 	logtag
528 	| nattag
529 	;
530 
531 matchtagin:
532 	| IPFY_MATCHTAG '(' tagoutlist ')'
533 	;
534 
535 matchtagout:
536 	| IPFY_MATCHTAG '(' taginlist ')'
537 	;
538 
539 pps:	| IPFY_PPS YY_NUMBER		{ DOALL(fr->fr_pps = $2;) }
540 	;
541 
542 new:	| savegroup file restoregroup
543 	;
544 
545 rulettl:
546 	| IPFY_RULETTL YY_NUMBER	{ DOALL(fr->fr_die = $2;) }
547 	;
548 
549 comment:
550 	| IPFY_COMMENT YY_STR		{ DOALL(fr->fr_comment = addname(&fr, \
551 						$2);) }
552 	;
553 
554 savegroup:
555 	'{'
556 	;
557 
558 restoregroup:
559 	'}'
560 	;
561 
562 logopt:	log
563 	;
564 
565 quick:	IPFY_QUICK				{ fr->fr_flags |= FR_QUICK; }
566 	;
567 
568 on:	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 
595 onlist:	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 
613 onname:	interfacename		{ $$.if1 = $1;
614 				  $$.if2 = NULL;
615 				}
616 	| interfacename ',' interfacename
617 				{ $$.if1 = $1;
618 				  $$.if2 = $3;
619 				}
620 	;
621 
622 vianame:
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 
633 dup:	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 
656 duptoseparator:
657 	':'	{ yyexpectaddr = 1; yycont = &yyexpectaddr; resetaddr(); }
658 	;
659 
660 froute:	IPFY_FROUTE			{ fr->fr_flags |= FR_FASTROUTE; }
661 	;
662 
663 proute:	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 
686 routeto:
687 	IPFY_TO
688 	| IPFY_ROUTETO
689 	;
690 
691 replyto:
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 
713 logoptions:
714 	logoption
715 	| logoptions logoption
716 	;
717 
718 logoption:
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 
725 returncode:
726 	starticmpcode icmpcode ')'	{ fr->fr_icode = $2; yyresetdict(); }
727 	;
728 
729 starticmpcode:
730 	'('				{ yysetdict(icmpcodewords); }
731 	;
732 
733 srcdst:	| IPFY_ALL
734 	| fromto
735 	;
736 
737 protocol:
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 
766 nextstring:
767 	'/'			{ yysetdict(NULL); }
768 	;
769 
770 fromto:	from srcobject to dstobject	{ yyexpectaddr = 0; yycont = NULL; }
771 	| to dstobject			{ yyexpectaddr = 0; yycont = NULL; }
772 	| from srcobject		{ yyexpectaddr = 0; yycont = NULL; }
773 	;
774 
775 from:	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 
786 to:	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 
797 with:	| andwith withlist
798 	;
799 
800 andwith:
801 	IPFY_WITH			{ nowith = 0; setipftype(); }
802 	| IPFY_AND			{ nowith = 0; setipftype(); }
803 	;
804 
805 flags:	| 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 
823 startflags:
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 
831 flagset:
832 	YY_STR				{ $$ = tcpflags($1); free($1); }
833 	| YY_HEX			{ $$ = $1; }
834 	;
835 
836 srcobject:
837 	{ yyresetdict(); } fromport
838 	| srcaddr srcport
839 	| '!' srcaddr srcport
840 		{ DOALL(fr->fr_flags |= FR_NOTSRCIP;) }
841 	;
842 
843 srcaddr:
844 	addr	{ build_srcaddr_af(fr, &$1); }
845 	| lstart srcaddrlist lend
846 	;
847 
848 srcaddrlist:
849 	addr	{ build_srcaddr_af(fr, &$1); }
850 	| srcaddrlist lmore addr
851 		{ build_srcaddr_af(fr, &$3); }
852 	;
853 
854 srcport:
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 
864 fromport:
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 
874 srcportlist:
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 
892 dstobject:
893 	{ yyresetdict(); } toport
894 	| dstaddr dstport
895 	| '!' dstaddr dstport
896 			{ DOALL(fr->fr_flags |= FR_NOTDSTIP;) }
897 	;
898 
899 dstaddr:
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 
908 dstaddrlist:
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 
923 dstport:
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 
933 toport:
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 
943 dstportlist:
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 
961 addr:	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 
1025 ipaddr:	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 
1107 maskspace:
1108 	'/'
1109 	| IPFY_MASK
1110 	;
1111 
1112 ipmask:	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 
1119 maskopts:
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 
1151 hostname:
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 
1188 addrlist:
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 
1202 pool:	IPFY_POOL	{ yyexpectaddr = 0; yycont = NULL; yyresetdict(); }
1203 	;
1204 
1205 hash:	IPFY_HASH	{ yyexpectaddr = 0; yycont = NULL; yyresetdict(); }
1206 	;
1207 
1208 poollist:
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 
1235 port:	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 
1244 portc:	port compare			{ $$ = $2;
1245 					  yysetdict(NULL);
1246 					}
1247 	| porteq			{ $$ = $1; }
1248 	;
1249 
1250 porteq:	port '='			{ $$ = FR_EQUAL;
1251 					  yysetdict(NULL);
1252 					}
1253 	;
1254 
1255 portr:	IPFY_PORT			{ yyexpectaddr = 0;
1256 					  yycont = NULL;
1257 					  yysetdict(NULL);
1258 					}
1259 	;
1260 
1261 portcomp:
1262 	portc portnum			{ $$.pc = $1;
1263 					  $$.p1 = $2;
1264 					  yyresetdict();
1265 					}
1266 	;
1267 
1268 portrange:
1269 	portr portnum range portnum	{ $$.p1 = $2;
1270 					  $$.pc = $3;
1271 					  $$.p2 = $4;
1272 					  yyresetdict();
1273 					}
1274 	;
1275 
1276 icmp:	| itype icode
1277 	;
1278 
1279 itype:	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 
1286 seticmptype:
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 
1313 icode:	| 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 
1320 seticmpcode:
1321 	IPFY_ICMPCODE				{ yysetdict(icmpcodewords); }
1322 	;
1323 
1324 typelist:
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 
1331 codelist:
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 
1339 age:	| 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 
1346 keep:	| IPFY_KEEP keepstate keep
1347 	| IPFY_KEEP keepfrag keep
1348 	;
1349 
1350 keepstate:
1351 	IPFY_STATE stateoptlist		{ DOALL(fr->fr_flags |= FR_KEEPSTATE;)}
1352 	;
1353 
1354 keepfrag:
1355 	IPFY_FRAGS fragoptlist		{ DOALL(fr->fr_flags |= FR_KEEPFRAG;) }
1356 	| IPFY_FRAG fragoptlist		{ DOALL(fr->fr_flags |= FR_KEEPFRAG;) }
1357 	;
1358 
1359 fragoptlist:
1360 	| '(' fragopts ')'
1361 	;
1362 
1363 fragopts:
1364 	fragopt lanother fragopts
1365 	| fragopt
1366 	;
1367 
1368 fragopt:
1369 	IPFY_STRICT			{ DOALL(fr->fr_flags |= FR_FRSTRICT;) }
1370 	;
1371 
1372 stateoptlist:
1373 	| '(' stateopts ')'
1374 	;
1375 
1376 stateopts:
1377 	stateopt lanother stateopts
1378 	| stateopt
1379 	;
1380 
1381 stateopt:
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 
1433 portnum:
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 
1447 withlist:
1448 	withopt				{ nowith = 0; }
1449 	| withlist withopt		{ nowith = 0; }
1450 	| withlist ',' withopt		{ nowith = 0; }
1451 	;
1452 
1453 withopt:
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 
1461 ipopt:	IPFY_OPT			{ yysetdict(ipv4optwords); }
1462 	;
1463 
1464 startv6hdr:
1465 	IPFY_V6HDR	{ if (frc->fr_family != AF_INET6)
1466 				yyerror("only available with IPv6");
1467 			  yysetdict(ipv6optwords);
1468 			}
1469 	;
1470 
1471 notwith:
1472 	IPFY_NOT			{ nowith = 1; }
1473 	| IPFY_NO			{ nowith = 1; }
1474 	;
1475 
1476 opttype:
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 
1496 ipopts:	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 
1509 optlist:
1510 	opt				{ $$ |= $1; }
1511 	| optlist ',' opt		{ $$ |= $1 | $3; }
1512 	;
1513 
1514 ipv6hdrs:
1515 	ipv6hdrlist	{ DOALL(fr->fr_mip.fi_optmsk |= $1;
1516 				if (!nowith)
1517 					fr->fr_ip.fi_optmsk |= $1;)
1518 			}
1519 	;
1520 
1521 ipv6hdrlist:
1522 	ipv6hdr				{ $$ |= $1; }
1523 	| ipv6hdrlist ',' ipv6hdr	{ $$ |= $1 | $3; }
1524 	;
1525 
1526 secname:
1527 	seclevel			{ $$ |= $1; }
1528 	| secname ',' seclevel		{ $$ |= $1 | $3; }
1529 	;
1530 
1531 seclevel:
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 
1542 icmptype:
1543 	YY_NUMBER		{ $$ = $1; }
1544 	| YY_STR		{ $$ = geticmptype(frc->fr_family, $1);
1545 				  if ($$ == -1)
1546 					yyerror("unrecognised icmp type");
1547 				}
1548 	;
1549 
1550 icmpcode:
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 
1570 opt:
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 
1612 setsecclass:
1613 	IPFY_SECCLASS			{ yysetdict(ipv4secwords); }
1614 	;
1615 
1616 doi:	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 
1624 ipv6hdr:
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 
1636 level:	IPFY_LEVEL			{ setsyslog(); }
1637 	;
1638 
1639 loglevel:
1640 	priority			{ fr->fr_loglevel = LOG_LOCAL0|$1; }
1641 	| facility '.' priority		{ fr->fr_loglevel = $1 | $3; }
1642 	;
1643 
1644 facility:
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 
1670 priority:
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 
1681 compare:
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 
1690 range:	YY_RANGE_IN			{ $$ = FR_INRANGE; }
1691 	| YY_RANGE_OUT			{ $$ = FR_OUTRANGE; }
1692 	| ':'				{ $$ = FR_INCRANGE; }
1693 	;
1694 
1695 servicename:
1696 	YY_STR				{ $$ = $1; }
1697 	;
1698 
1699 interfacename:	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 
1708 name:	YY_STR				{ $$ = $1; }
1709 	| '-'				{ $$ = strdup("-"); }
1710 	;
1711 
1712 ipv4_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 
1723 ipv4_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 
1733 ipv4:	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 
1747 static	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 
1861 static	struct	wordtab	addrwords[] = {
1862 	{ "any",			IPFY_ANY },
1863 	{ "hash",			IPFY_HASH },
1864 	{ "pool",			IPFY_POOL },
1865 	{ NULL,				0 }
1866 };
1867 
1868 static	struct	wordtab	maskwords[] = {
1869 	{ "broadcast",			IPFY_BROADCAST },
1870 	{ "netmasked",			IPFY_NETMASKED },
1871 	{ "network",			IPFY_NETWORK },
1872 	{ "peer",			IPFY_PEER },
1873 	{ NULL,				0 }
1874 };
1875 
1876 static	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 
1896 static	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 
1924 static	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 
1936 static	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 
1948 static	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 
ipf_parsefile(fd,addfunc,iocfuncs,filename)1987 int ipf_parsefile(fd, addfunc, iocfuncs, filename)
1988 int fd;
1989 addfunc_t addfunc;
1990 ioctlfunc_t *iocfuncs;
1991 char *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 
ipf_parsesome(fd,addfunc,iocfuncs,fp)2023 int ipf_parsesome(fd, addfunc, iocfuncs, fp)
2024 int fd;
2025 addfunc_t addfunc;
2026 ioctlfunc_t *iocfuncs;
2027 FILE *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 
newrule()2058 static 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 
setipftype()2090 static 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 
addrule()2115 static 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 
2144 static int
lookuphost(name,addrp)2145 lookuphost(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 
dobpf(v,phrase)2173 static void dobpf(v, phrase)
2174 int v;
2175 char *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 
resetaddr()2264 static void resetaddr()
2265 {
2266 	hashed = 0;
2267 	pooled = 0;
2268 	dynamic = -1;
2269 }
2270 
2271 
newalist(ptr)2272 static alist_t *newalist(ptr)
2273 alist_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 
2286 static int
makepool(list)2287 makepool(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 
makehash(list)2344 static u_int makehash(list)
2345 alist_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 
ipf_addrule(fd,ioctlfunc,ptr)2393 int ipf_addrule(fd, ioctlfunc, ptr)
2394 int fd;
2395 ioctlfunc_t ioctlfunc;
2396 void *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 
setsyslog()2487 static void setsyslog()
2488 {
2489 	yysetdict(logwords);
2490 	yybreakondot = 1;
2491 }
2492 
2493 
unsetsyslog()2494 static void unsetsyslog()
2495 {
2496 	yyresetdict();
2497 	yybreakondot = 0;
2498 }
2499 
2500 
fillgroup(fr)2501 static void fillgroup(fr)
2502 frentry_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 
doipfexpr(line)2544 static void doipfexpr(line)
2545 char *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 
do_tuneint(varname,value)2563 static void do_tuneint(varname, value)
2564 char *varname;
2565 int 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 
do_tunestr(varname,value)2577 static void do_tunestr(varname, value)
2578 char *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 
setifname(frp,idx,name)2591 static void setifname(frp, idx, name)
2592 frentry_t **frp;
2593 int idx;
2594 char *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 
addname(frp,name)2605 static int addname(frp, name)
2606 frentry_t **frp;
2607 char *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 
allocfr()2637 static 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 
setgroup(frp,name)2660 static void setgroup(frp, name)
2661 frentry_t **frp;
2662 char *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 
setgrhead(frp,name)2673 static void setgrhead(frp, name)
2674 frentry_t **frp;
2675 char *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 
seticmphead(frp,name)2686 static void seticmphead(frp, name)
2687 frentry_t **frp;
2688 char *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 
2699 static void
build_dstaddr_af(fp,ptr)2700 build_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 
2730 static void
build_srcaddr_af(fp,ptr)2731 build_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