xref: /freebsd/sbin/ipf/common/ipf_y.y (revision 9768746b)
1 /*	$FreeBSD$	*/
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 
25 extern	void	yyerror(char *);
26 extern	int	yyparse(void);
27 extern	int	yylex(void);
28 extern	int	yydebug;
29 extern	FILE	*yyin;
30 extern	int	yylineNum;
31 
32 static	int	addname(frentry_t **, char *);
33 static	frentry_t *addrule(void);
34 static frentry_t *allocfr(void);
35 static	void	build_dstaddr_af(frentry_t *, void *);
36 static	void	build_srcaddr_af(frentry_t *, void *);
37 static	void	dobpf(int, char *);
38 static	void	doipfexpr(char *);
39 static	void	do_tuneint(char *, int);
40 static	void	do_tunestr(char *, char *);
41 static	void	fillgroup(frentry_t *);
42 static	int	lookuphost(char *, i6addr_t *);
43 static	u_int	makehash(struct alist_s *);
44 static	int	makepool(struct alist_s *);
45 static	struct	alist_s	*newalist(struct alist_s *);
46 static	void	newrule(void);
47 static	void	resetaddr(void);
48 static	void	setgroup(frentry_t **, char *);
49 static	void	setgrhead(frentry_t **, char *);
50 static	void	seticmphead(frentry_t **, char *);
51 static	void	setifname(frentry_t **, int, char *);
52 static	void	setipftype(void);
53 static	void	setsyslog(void);
54 static	void	unsetsyslog(void);
55 
56 frentry_t	*fr = NULL, *frc = NULL, *frtop = NULL, *frold = NULL;
57 
58 static	int		ifpflag = 0;
59 static	int		nowith = 0;
60 static	int		dynamic = -1;
61 static	int		pooled = 0;
62 static	int		hashed = 0;
63 static	int		nrules = 0;
64 static	int		newlist = 0;
65 static	int		added = 0;
66 static	int		ipffd = -1;
67 static	int		*yycont = NULL;
68 static	ioctlfunc_t	ipfioctls[IPL_LOGSIZE];
69 static	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 %%
187 file:	settings rules
188 	| rules
189 	;
190 
191 settings:
192 	YY_COMMENT
193 	| setting
194 	| settings setting
195 	;
196 
197 rules:	line
198 	| assign
199 	| rules line
200 	| rules assign
201 	;
202 
203 setting:
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 
209 line:	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 
225 xx:					{ newrule(); }
226 	;
227 
228 assign:	YY_STR assigning YY_STR ';'	{ set_variable($1, $3);
229 					  resetlexer();
230 					  free($1);
231 					  free($3);
232 					  yyvarnext = 0;
233 					}
234 	;
235 
236 assigning:
237 	'='				{ yyvarnext = 1; }
238 	;
239 
240 rule:	inrule eol
241 	| outrule eol
242 	;
243 
244 eol:	| ';'
245 	;
246 
247 inrule:
248 	rulehead markin inopts rulemain ruletail intag ruletail2
249 	;
250 
251 outrule:
252 	rulehead markout outopts rulemain ruletail outtag ruletail2
253 	;
254 
255 rulehead:
256 	xx collection action
257 	| xx insert collection action
258 	;
259 
260 markin:	IPFY_IN				{ fr->fr_flags |= FR_INQUE; }
261 	;
262 
263 markout:
264 	IPFY_OUT			{ fr->fr_flags |= FR_OUTQUE; }
265 	;
266 
267 rulemain:
268 	ipfrule
269 	| bpfrule
270 	| exprrule
271 	;
272 
273 ipfrule:
274 	family tos ttl proto ip
275 	;
276 
277 family:	| 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 
303 bpfrule:
304 	IPFY_BPFV4 '{' YY_STR '}' 	{ dobpf(4, $3); free($3); }
305 	| IPFY_BPFV6 '{' YY_STR '}' 	{ dobpf(6, $3); free($3); }
306 	;
307 
308 exprrule:
309 	IPFY_IPFEXPR '{' YY_STR '}'	{ doipfexpr($3); }
310 	;
311 
312 ruletail:
313 	with keep head group
314 	;
315 
316 ruletail2:
317 	pps age new rulettl comment
318 	;
319 
320 intag:	settagin matchtagin
321 	;
322 
323 outtag:	settagout matchtagout
324 	;
325 
326 insert:
327 	'@' YY_NUMBER			{ fr->fr_hits = (U_QUAD_T)$2 + 1; }
328 	;
329 
330 collection:
331 	| YY_NUMBER			{ fr->fr_collect = $1; }
332 	;
333 
334 action:	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 
347 block:	blocked
348 	| blocked blockreturn
349 	;
350 
351 blocked:
352 	IPFY_BLOCK			{ fr->fr_flags = FR_BLOCK; }
353 	;
354 blockreturn:
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 
362 decaps:	IPFY_DECAPS
363 	| IPFY_DECAPS IPFY_L5AS '(' YY_STR ')'
364 					{ fr->fr_icode = atoi($4); }
365 	;
366 
367 log:	IPFY_LOG			{ fr->fr_flags |= FR_LOG; }
368 	| IPFY_LOG logoptions		{ fr->fr_flags |= FR_LOG; }
369 	;
370 
371 auth:	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 
376 func:	YY_STR '/' YY_NUMBER
377 			{ fr->fr_func = nametokva($1, ipfioctls[IPL_LOGIPF]);
378 			  fr->fr_arg = $3;
379 			  free($1);
380 			}
381 	;
382 
383 inopts:
384 	| inopts inopt
385 	;
386 
387 inopt:
388 	logopt
389 	| quick
390 	| on
391 	| dup
392 	| froute
393 	| proute
394 	| replyto
395 	;
396 
397 outopts:
398 	| outopts outopt
399 	;
400 
401 outopt:
402 	logopt
403 	| quick
404 	| on
405 	| dup
406 	| proute
407 	| froute
408 	| replyto
409 	;
410 
411 tos:	| 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 
416 settos:	IPFY_TOS			{ setipftype(); }
417 	;
418 
419 toslist:
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 
428 ttl:	| setttl YY_NUMBER
429 			{ DOALL(fr->fr_ttl = $2; fr->fr_mttl = 0xff;) }
430 	| setttl lstart ttllist lend
431 	;
432 
433 lstart:	'{'				{ newlist = 1; fr = frc; added = 0; }
434 	;
435 
436 lend:	'}'				{ nrules += added; }
437 	;
438 
439 lmore:	lanother			{ if (newlist == 1) {
440 						newlist = 0;
441 					  }
442 					  fr = addrule();
443 					  if (yycont != NULL)
444 						*yycont = 1;
445 					}
446 	;
447 
448 lanother:
449 	| ','
450 	;
451 
452 setttl:	IPFY_TTL			{ setipftype(); }
453 	;
454 
455 ttllist:
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 
461 proto:	| protox protocol		{ yyresetdict(); }
462 	;
463 
464 protox:	IPFY_PROTO			{ setipftype();
465 					  fr = frc;
466 					  yysetdict(NULL); }
467 	;
468 
469 ip:	srcdst flags icmp
470 	;
471 
472 group:	| IPFY_GROUP groupname		{ DOALL(setgroup(&fr, $2); \
473 						fillgroup(fr););
474 					  free($2);
475 					}
476 	;
477 
478 head:	| IPFY_HEAD groupname		{ DOALL(setgrhead(&fr, $2););
479 					  free($2);
480 					}
481 	;
482 
483 groupname:
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 
493 settagin:
494 	| IPFY_SETTAG '(' taginlist ')'
495 	;
496 
497 taginlist:
498 	taginspec
499 	| taginlist ',' taginspec
500 	;
501 
502 taginspec:
503 	logtag
504 	;
505 
506 nattag:	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 
513 logtag:	IPFY_LOG '=' YY_NUMBER		{ DOALL(fr->fr_logtag = $3;) }
514 	;
515 
516 settagout:
517 	| IPFY_SETTAG '(' tagoutlist ')'
518 	;
519 
520 tagoutlist:
521 	tagoutspec
522 	| tagoutlist ',' tagoutspec
523 	;
524 
525 tagoutspec:
526 	logtag
527 	| nattag
528 	;
529 
530 matchtagin:
531 	| IPFY_MATCHTAG '(' tagoutlist ')'
532 	;
533 
534 matchtagout:
535 	| IPFY_MATCHTAG '(' taginlist ')'
536 	;
537 
538 pps:	| IPFY_PPS YY_NUMBER		{ DOALL(fr->fr_pps = $2;) }
539 	;
540 
541 new:	| savegroup file restoregroup
542 	;
543 
544 rulettl:
545 	| IPFY_RULETTL YY_NUMBER	{ DOALL(fr->fr_die = $2;) }
546 	;
547 
548 comment:
549 	| IPFY_COMMENT YY_STR		{ DOALL(fr->fr_comment = addname(&fr, \
550 						$2);) }
551 	;
552 
553 savegroup:
554 	'{'
555 	;
556 
557 restoregroup:
558 	'}'
559 	;
560 
561 logopt:	log
562 	;
563 
564 quick:	IPFY_QUICK				{ fr->fr_flags |= FR_QUICK; }
565 	;
566 
567 on:	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 
594 onlist:	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 
612 onname:	interfacename		{ $$.if1 = $1;
613 				  $$.if2 = NULL;
614 				}
615 	| interfacename ',' interfacename
616 				{ $$.if1 = $1;
617 				  $$.if2 = $3;
618 				}
619 	;
620 
621 vianame:
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 
632 dup:	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 
655 duptoseparator:
656 	':'	{ yyexpectaddr = 1; yycont = &yyexpectaddr; resetaddr(); }
657 	;
658 
659 froute:	IPFY_FROUTE			{ fr->fr_flags |= FR_FASTROUTE; }
660 	;
661 
662 proute:	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 
685 routeto:
686 	IPFY_TO
687 	| IPFY_ROUTETO
688 	;
689 
690 replyto:
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 
712 logoptions:
713 	logoption
714 	| logoptions logoption
715 	;
716 
717 logoption:
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 
724 returncode:
725 	starticmpcode icmpcode ')'	{ fr->fr_icode = $2; yyresetdict(); }
726 	;
727 
728 starticmpcode:
729 	'('				{ yysetdict(icmpcodewords); }
730 	;
731 
732 srcdst:	| IPFY_ALL
733 	| fromto
734 	;
735 
736 protocol:
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 
765 nextstring:
766 	'/'			{ yysetdict(NULL); }
767 	;
768 
769 fromto:	from srcobject to dstobject	{ yyexpectaddr = 0; yycont = NULL; }
770 	| to dstobject			{ yyexpectaddr = 0; yycont = NULL; }
771 	| from srcobject		{ yyexpectaddr = 0; yycont = NULL; }
772 	;
773 
774 from:	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 
785 to:	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 
796 with:	| andwith withlist
797 	;
798 
799 andwith:
800 	IPFY_WITH			{ nowith = 0; setipftype(); }
801 	| IPFY_AND			{ nowith = 0; setipftype(); }
802 	;
803 
804 flags:	| 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 
822 startflags:
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 
830 flagset:
831 	YY_STR				{ $$ = tcpflags($1); free($1); }
832 	| YY_HEX			{ $$ = $1; }
833 	;
834 
835 srcobject:
836 	{ yyresetdict(); } fromport
837 	| srcaddr srcport
838 	| '!' srcaddr srcport
839 		{ DOALL(fr->fr_flags |= FR_NOTSRCIP;) }
840 	;
841 
842 srcaddr:
843 	addr	{ build_srcaddr_af(fr, &$1); }
844 	| lstart srcaddrlist lend
845 	;
846 
847 srcaddrlist:
848 	addr	{ build_srcaddr_af(fr, &$1); }
849 	| srcaddrlist lmore addr
850 		{ build_srcaddr_af(fr, &$3); }
851 	;
852 
853 srcport:
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 
863 fromport:
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 
873 srcportlist:
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 
891 dstobject:
892 	{ yyresetdict(); } toport
893 	| dstaddr dstport
894 	| '!' dstaddr dstport
895 			{ DOALL(fr->fr_flags |= FR_NOTDSTIP;) }
896 	;
897 
898 dstaddr:
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 
907 dstaddrlist:
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 
922 dstport:
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 
932 toport:
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 
942 dstportlist:
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 
960 addr:	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 
1024 ipaddr:	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 
1106 maskspace:
1107 	'/'
1108 	| IPFY_MASK
1109 	;
1110 
1111 ipmask:	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 
1118 maskopts:
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 
1150 hostname:
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 
1187 addrlist:
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 
1201 pool:	IPFY_POOL	{ yyexpectaddr = 0; yycont = NULL; yyresetdict(); }
1202 	;
1203 
1204 hash:	IPFY_HASH	{ yyexpectaddr = 0; yycont = NULL; yyresetdict(); }
1205 	;
1206 
1207 poollist:
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 
1234 port:	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 
1243 portc:	port compare			{ $$ = $2;
1244 					  yysetdict(NULL);
1245 					}
1246 	| porteq			{ $$ = $1; }
1247 	;
1248 
1249 porteq:	port '='			{ $$ = FR_EQUAL;
1250 					  yysetdict(NULL);
1251 					}
1252 	;
1253 
1254 portr:	IPFY_PORT			{ yyexpectaddr = 0;
1255 					  yycont = NULL;
1256 					  yysetdict(NULL);
1257 					}
1258 	;
1259 
1260 portcomp:
1261 	portc portnum			{ $$.pc = $1;
1262 					  $$.p1 = $2;
1263 					  yyresetdict();
1264 					}
1265 	;
1266 
1267 portrange:
1268 	portr portnum range portnum	{ $$.p1 = $2;
1269 					  $$.pc = $3;
1270 					  $$.p2 = $4;
1271 					  yyresetdict();
1272 					}
1273 	;
1274 
1275 icmp:	| itype icode
1276 	;
1277 
1278 itype:	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 
1285 seticmptype:
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 
1312 icode:	| 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 
1319 seticmpcode:
1320 	IPFY_ICMPCODE				{ yysetdict(icmpcodewords); }
1321 	;
1322 
1323 typelist:
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 
1330 codelist:
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 
1338 age:	| 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 
1345 keep:	| IPFY_KEEP keepstate keep
1346 	| IPFY_KEEP keepfrag keep
1347 	;
1348 
1349 keepstate:
1350 	IPFY_STATE stateoptlist		{ DOALL(fr->fr_flags |= FR_KEEPSTATE;)}
1351 	;
1352 
1353 keepfrag:
1354 	IPFY_FRAGS fragoptlist		{ DOALL(fr->fr_flags |= FR_KEEPFRAG;) }
1355 	| IPFY_FRAG fragoptlist		{ DOALL(fr->fr_flags |= FR_KEEPFRAG;) }
1356 	;
1357 
1358 fragoptlist:
1359 	| '(' fragopts ')'
1360 	;
1361 
1362 fragopts:
1363 	fragopt lanother fragopts
1364 	| fragopt
1365 	;
1366 
1367 fragopt:
1368 	IPFY_STRICT			{ DOALL(fr->fr_flags |= FR_FRSTRICT;) }
1369 	;
1370 
1371 stateoptlist:
1372 	| '(' stateopts ')'
1373 	;
1374 
1375 stateopts:
1376 	stateopt lanother stateopts
1377 	| stateopt
1378 	;
1379 
1380 stateopt:
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 
1432 portnum:
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 
1446 withlist:
1447 	withopt				{ nowith = 0; }
1448 	| withlist withopt		{ nowith = 0; }
1449 	| withlist ',' withopt		{ nowith = 0; }
1450 	;
1451 
1452 withopt:
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 
1460 ipopt:	IPFY_OPT			{ yysetdict(ipv4optwords); }
1461 	;
1462 
1463 startv6hdr:
1464 	IPFY_V6HDR	{ if (frc->fr_family != AF_INET6)
1465 				yyerror("only available with IPv6");
1466 			  yysetdict(ipv6optwords);
1467 			}
1468 	;
1469 
1470 notwith:
1471 	IPFY_NOT			{ nowith = 1; }
1472 	| IPFY_NO			{ nowith = 1; }
1473 	;
1474 
1475 opttype:
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 
1495 ipopts:	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 
1508 optlist:
1509 	opt				{ $$ |= $1; }
1510 	| optlist ',' opt		{ $$ |= $1 | $3; }
1511 	;
1512 
1513 ipv6hdrs:
1514 	ipv6hdrlist	{ DOALL(fr->fr_mip.fi_optmsk |= $1;
1515 				if (!nowith)
1516 					fr->fr_ip.fi_optmsk |= $1;)
1517 			}
1518 	;
1519 
1520 ipv6hdrlist:
1521 	ipv6hdr				{ $$ |= $1; }
1522 	| ipv6hdrlist ',' ipv6hdr	{ $$ |= $1 | $3; }
1523 	;
1524 
1525 secname:
1526 	seclevel			{ $$ |= $1; }
1527 	| secname ',' seclevel		{ $$ |= $1 | $3; }
1528 	;
1529 
1530 seclevel:
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 
1541 icmptype:
1542 	YY_NUMBER		{ $$ = $1; }
1543 	| YY_STR		{ $$ = geticmptype(frc->fr_family, $1);
1544 				  if ($$ == -1)
1545 					yyerror("unrecognised icmp type");
1546 				}
1547 	;
1548 
1549 icmpcode:
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 
1569 opt:
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 
1611 setsecclass:
1612 	IPFY_SECCLASS			{ yysetdict(ipv4secwords); }
1613 	;
1614 
1615 doi:	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 
1623 ipv6hdr:
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 
1635 level:	IPFY_LEVEL			{ setsyslog(); }
1636 	;
1637 
1638 loglevel:
1639 	priority			{ fr->fr_loglevel = LOG_LOCAL0|$1; }
1640 	| facility '.' priority		{ fr->fr_loglevel = $1 | $3; }
1641 	;
1642 
1643 facility:
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 
1669 priority:
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 
1680 compare:
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 
1689 range:	YY_RANGE_IN			{ $$ = FR_INRANGE; }
1690 	| YY_RANGE_OUT			{ $$ = FR_OUTRANGE; }
1691 	| ':'				{ $$ = FR_INCRANGE; }
1692 	;
1693 
1694 servicename:
1695 	YY_STR				{ $$ = $1; }
1696 	;
1697 
1698 interfacename:	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 
1707 name:	YY_STR				{ $$ = $1; }
1708 	| '-'				{ $$ = strdup("-"); }
1709 	;
1710 
1711 ipv4_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 
1722 ipv4_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 
1732 ipv4:	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 
1746 static	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 
1860 static	struct	wordtab	addrwords[] = {
1861 	{ "any",			IPFY_ANY },
1862 	{ "hash",			IPFY_HASH },
1863 	{ "pool",			IPFY_POOL },
1864 	{ NULL,				0 }
1865 };
1866 
1867 static	struct	wordtab	maskwords[] = {
1868 	{ "broadcast",			IPFY_BROADCAST },
1869 	{ "netmasked",			IPFY_NETMASKED },
1870 	{ "network",			IPFY_NETWORK },
1871 	{ "peer",			IPFY_PEER },
1872 	{ NULL,				0 }
1873 };
1874 
1875 static	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 
1895 static	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 
1923 static	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 
1935 static	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 
1947 static	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 
1986 int
1987 ipf_parsefile(int fd, addfunc_t addfunc, ioctlfunc_t *iocfuncs, char *filename)
1988 {
1989 	FILE *fp = NULL;
1990 	char *s;
1991 
1992 	yylineNum = 1;
1993 	yysettab(ipfwords);
1994 
1995 	s = getenv("YYDEBUG");
1996 	if (s != NULL)
1997 		yydebug = atoi(s);
1998 	else
1999 		yydebug = 0;
2000 
2001 	if (strcmp(filename, "-")) {
2002 		fp = fopen(filename, "r");
2003 		if (fp == NULL) {
2004 			fprintf(stderr, "fopen(%s) failed: %s\n", filename,
2005 				STRERROR(errno));
2006 			return(-1);
2007 		}
2008 	} else
2009 		fp = stdin;
2010 
2011 	while (ipf_parsesome(fd, addfunc, iocfuncs, fp) == 1)
2012 		;
2013 	if (fp != NULL)
2014 		fclose(fp);
2015 	return(0);
2016 }
2017 
2018 
2019 int
2020 ipf_parsesome(int fd, addfunc_t addfunc, ioctlfunc_t *iocfuncs, FILE *fp)
2021 {
2022 	char *s;
2023 	int i;
2024 
2025 	ipffd = fd;
2026 	for (i = 0; i <= IPL_LOGMAX; i++)
2027 		ipfioctls[i] = iocfuncs[i];
2028 	ipfaddfunc = addfunc;
2029 
2030 	if (feof(fp))
2031 		return(0);
2032 	i = fgetc(fp);
2033 	if (i == EOF)
2034 		return(0);
2035 	if (ungetc(i, fp) == 0)
2036 		return(0);
2037 	if (feof(fp))
2038 		return(0);
2039 	s = getenv("YYDEBUG");
2040 	if (s != NULL)
2041 		yydebug = atoi(s);
2042 	else
2043 		yydebug = 0;
2044 
2045 	yyin = fp;
2046 	yyparse();
2047 	return(1);
2048 }
2049 
2050 
2051 static void
2052 newrule(void)
2053 {
2054 	frentry_t *frn;
2055 
2056 	frn = allocfr();
2057 	for (fr = frtop; fr != NULL && fr->fr_next != NULL; fr = fr->fr_next)
2058 		;
2059 	if (fr != NULL) {
2060 		fr->fr_next = frn;
2061 		frn->fr_pnext = &fr->fr_next;
2062 	}
2063 	if (frtop == NULL) {
2064 		frtop = frn;
2065 		frn->fr_pnext = &frtop;
2066 	}
2067 	fr = frn;
2068 	frc = frn;
2069 	fr->fr_loglevel = 0xffff;
2070 	fr->fr_isc = (void *)-1;
2071 	fr->fr_logtag = FR_NOLOGTAG;
2072 	fr->fr_type = FR_T_NONE;
2073 	fr->fr_flineno = yylineNum;
2074 
2075 	if (use_inet6 == 1)
2076 		fr->fr_family = AF_INET6;
2077 	else if (use_inet6 == -1)
2078 		fr->fr_family = AF_INET;
2079 
2080 	nrules = 1;
2081 }
2082 
2083 
2084 static void
2085 setipftype(void)
2086 {
2087 	for (fr = frc; fr != NULL; fr = fr->fr_next) {
2088 		if (fr->fr_type == FR_T_NONE) {
2089 			fr->fr_type = FR_T_IPF;
2090 			fr->fr_data = (void *)calloc(sizeof(fripf_t), 1);
2091 			fr->fr_dsize = sizeof(fripf_t);
2092 			fr->fr_family = frc->fr_family;
2093 			if (fr->fr_family == AF_INET) {
2094 				fr->fr_ip.fi_v = 4;
2095 			}
2096 			else if (fr->fr_family == AF_INET6) {
2097 				fr->fr_ip.fi_v = 6;
2098 			}
2099 			fr->fr_mip.fi_v = 0xf;
2100 			fr->fr_ipf->fri_sifpidx = -1;
2101 			fr->fr_ipf->fri_difpidx = -1;
2102 		}
2103 		if (fr->fr_type != FR_T_IPF) {
2104 			fprintf(stderr, "IPF Type not set\n");
2105 		}
2106 	}
2107 }
2108 
2109 
2110 static frentry_t *
2111 addrule(void)
2112 {
2113 	frentry_t *f, *f1, *f2;
2114 	int count;
2115 
2116 	for (f2 = frc; f2->fr_next != NULL; f2 = f2->fr_next)
2117 		;
2118 
2119 	count = nrules;
2120 	f = f2;
2121 	for (f1 = frc; count > 0; count--, f1 = f1->fr_next) {
2122 		f->fr_next = allocfr();
2123 		if (f->fr_next == NULL)
2124 			return(NULL);
2125 		f->fr_next->fr_pnext = &f->fr_next;
2126 		added++;
2127 		f = f->fr_next;
2128 		*f = *f1;
2129 		f->fr_next = NULL;
2130 		if (f->fr_caddr != NULL) {
2131 			f->fr_caddr = malloc(f->fr_dsize);
2132 			bcopy(f1->fr_caddr, f->fr_caddr, f->fr_dsize);
2133 		}
2134 	}
2135 
2136 	return(f2->fr_next);
2137 }
2138 
2139 
2140 static int
2141 lookuphost(char *name, i6addr_t *addrp)
2142 {
2143 	int i;
2144 
2145 	hashed = 0;
2146 	pooled = 0;
2147 	dynamic = -1;
2148 
2149 	for (i = 0; i < 4; i++) {
2150 		if (fr->fr_ifnames[i] == -1)
2151 			continue;
2152 		if (strcmp(name, fr->fr_names + fr->fr_ifnames[i]) == 0) {
2153 			ifpflag = FRI_DYNAMIC;
2154 			dynamic = addname(&fr, name);
2155 			return(1);
2156 		}
2157 	}
2158 
2159 	if (gethost(AF_INET, name, addrp) == -1) {
2160 		fprintf(stderr, "unknown name \"%s\"\n", name);
2161 		return(-1);
2162 	}
2163 	return(0);
2164 }
2165 
2166 
2167 static void
2168 dobpf(int v, char *phrase)
2169 {
2170 #ifdef IPFILTER_BPF
2171 	struct bpf_program bpf;
2172 	struct pcap *p;
2173 #endif
2174 	fakebpf_t *fb;
2175 	u_32_t l;
2176 	char *s;
2177 	int i;
2178 
2179 	for (fr = frc; fr != NULL; fr = fr->fr_next) {
2180 		if (fr->fr_type != FR_T_NONE) {
2181 			fprintf(stderr, "cannot mix IPF and BPF matching\n");
2182 			return;
2183 		}
2184 		fr->fr_family = vtof(v);
2185 		fr->fr_type = FR_T_BPFOPC;
2186 
2187 		if (!strncmp(phrase, "0x", 2)) {
2188 			fb = malloc(sizeof(fakebpf_t));
2189 
2190 			for (i = 0, s = strtok(phrase, " \r\n\t"); s != NULL;
2191 			     s = strtok(NULL, " \r\n\t"), i++) {
2192 				fb = reallocarray(fb, i / 4 + 1, sizeof(*fb));
2193 				if (fb == NULL) {
2194 					warnx("memory allocation error at %d in %s in %s", __LINE__, __FUNCTION__, __FILE__);
2195 					abort();
2196 				}
2197 				l = (u_32_t)strtol(s, NULL, 0);
2198 				switch (i & 3)
2199 				{
2200 				case 0 :
2201 					fb[i / 4].fb_c = l & 0xffff;
2202 					break;
2203 				case 1 :
2204 					fb[i / 4].fb_t = l & 0xff;
2205 					break;
2206 				case 2 :
2207 					fb[i / 4].fb_f = l & 0xff;
2208 					break;
2209 				case 3 :
2210 					fb[i / 4].fb_k = l;
2211 					break;
2212 				}
2213 			}
2214 			if ((i & 3) != 0) {
2215 				fprintf(stderr,
2216 					"Odd number of bytes in BPF code\n");
2217 				exit(1);
2218 			}
2219 			i--;
2220 			fr->fr_dsize = (i / 4 + 1) * sizeof(*fb);
2221 			fr->fr_data = fb;
2222 			return;
2223 		}
2224 
2225 #ifdef IPFILTER_BPF
2226 		bzero((char *)&bpf, sizeof(bpf));
2227 		p = pcap_open_dead(DLT_RAW, 1);
2228 		if (!p) {
2229 			fprintf(stderr, "pcap_open_dead failed\n");
2230 			return;
2231 		}
2232 
2233 		if (pcap_compile(p, &bpf, phrase, 1, 0xffffffff)) {
2234 			pcap_perror(p, "ipf");
2235 			pcap_close(p);
2236 			fprintf(stderr, "pcap parsing failed (%s)\n", phrase);
2237 			return;
2238 		}
2239 		pcap_close(p);
2240 
2241 		fr->fr_dsize = bpf.bf_len * sizeof(struct bpf_insn);
2242 		fr->fr_data = malloc(fr->fr_dsize);
2243 		bcopy((char *)bpf.bf_insns, fr->fr_data, fr->fr_dsize);
2244 		if (!bpf_validate(fr->fr_data, bpf.bf_len)) {
2245 			fprintf(stderr, "BPF validation failed\n");
2246 			return;
2247 		}
2248 #endif
2249 	}
2250 
2251 #ifdef IPFILTER_BPF
2252 	if (opts & OPT_DEBUG)
2253 		bpf_dump(&bpf, 0);
2254 #else
2255 	fprintf(stderr, "BPF filter expressions not supported\n");
2256 	exit(1);
2257 #endif
2258 }
2259 
2260 
2261 static void
2262 resetaddr(void)
2263 {
2264 	hashed = 0;
2265 	pooled = 0;
2266 	dynamic = -1;
2267 }
2268 
2269 
2270 static alist_t *
2271 newalist(alist_t *ptr)
2272 {
2273 	alist_t *al;
2274 
2275 	al = malloc(sizeof(*al));
2276 	if (al == NULL)
2277 		return(NULL);
2278 	al->al_not = 0;
2279 	al->al_next = ptr;
2280 	return(al);
2281 }
2282 
2283 
2284 static int
2285 makepool(alist_t *list)
2286 {
2287 	ip_pool_node_t *n, *top;
2288 	ip_pool_t pool;
2289 	alist_t *a;
2290 	int num;
2291 
2292 	if (list == NULL)
2293 		return(0);
2294 	top = calloc(1, sizeof(*top));
2295 	if (top == NULL)
2296 		return(0);
2297 
2298 	for (n = top, a = list; (n != NULL) && (a != NULL); a = a->al_next) {
2299 		if (use_inet6 == 1) {
2300 #ifdef USE_INET6
2301 			n->ipn_addr.adf_family = AF_INET6;
2302 			n->ipn_addr.adf_addr = a->al_i6addr;
2303 			n->ipn_addr.adf_len = offsetof(addrfamily_t,
2304 						       adf_addr) + 16;
2305 			n->ipn_mask.adf_family = AF_INET6;
2306 			n->ipn_mask.adf_addr = a->al_i6mask;
2307 			n->ipn_mask.adf_len = offsetof(addrfamily_t,
2308 						       adf_addr) + 16;
2309 
2310 #endif
2311 		} else {
2312 			n->ipn_addr.adf_family = AF_INET;
2313 			n->ipn_addr.adf_addr.in4.s_addr = a->al_1;
2314 			n->ipn_addr.adf_len = offsetof(addrfamily_t,
2315 						       adf_addr) + 4;
2316 			n->ipn_mask.adf_family = AF_INET;
2317 			n->ipn_mask.adf_addr.in4.s_addr = a->al_2;
2318 			n->ipn_mask.adf_len = offsetof(addrfamily_t,
2319 						       adf_addr) + 4;
2320 		}
2321 		n->ipn_info = a->al_not;
2322 		if (a->al_next != NULL) {
2323 			n->ipn_next = calloc(1, sizeof(*n));
2324 			n = n->ipn_next;
2325 		}
2326 	}
2327 
2328 	bzero((char *)&pool, sizeof(pool));
2329 	pool.ipo_unit = IPL_LOGIPF;
2330 	pool.ipo_list = top;
2331 	num = load_pool(&pool, ipfioctls[IPL_LOGLOOKUP]);
2332 
2333 	while ((n = top) != NULL) {
2334 		top = n->ipn_next;
2335 		free(n);
2336 	}
2337 	return(num);
2338 }
2339 
2340 
2341 static u_int
2342 makehash(alist_t *list)
2343 {
2344 	iphtent_t *n, *top;
2345 	iphtable_t iph;
2346 	alist_t *a;
2347 	int num;
2348 
2349 	if (list == NULL)
2350 		return(0);
2351 	top = calloc(1, sizeof(*top));
2352 	if (top == NULL)
2353 		return(0);
2354 
2355 	for (n = top, a = list; (n != NULL) && (a != NULL); a = a->al_next) {
2356 		if (a->al_family == AF_INET6) {
2357 			n->ipe_family = AF_INET6;
2358 			n->ipe_addr = a->al_i6addr;
2359 			n->ipe_mask = a->al_i6mask;
2360 		} else {
2361 			n->ipe_family = AF_INET;
2362 			n->ipe_addr.in4_addr = a->al_1;
2363 			n->ipe_mask.in4_addr = a->al_2;
2364 		}
2365 		n->ipe_value = 0;
2366 		if (a->al_next != NULL) {
2367 			n->ipe_next = calloc(1, sizeof(*n));
2368 			n = n->ipe_next;
2369 		}
2370 	}
2371 
2372 	bzero((char *)&iph, sizeof(iph));
2373 	iph.iph_unit = IPL_LOGIPF;
2374 	iph.iph_type = IPHASH_LOOKUP;
2375 	*iph.iph_name = '\0';
2376 
2377 	if (load_hash(&iph, top, ipfioctls[IPL_LOGLOOKUP]) == 0)
2378 		sscanf(iph.iph_name, "%u", &num);
2379 	else
2380 		num = 0;
2381 
2382 	while ((n = top) != NULL) {
2383 		top = n->ipe_next;
2384 		free(n);
2385 	}
2386 	return(num);
2387 }
2388 
2389 
2390 int
2391 ipf_addrule(int fd, ioctlfunc_t ioctlfunc, void *ptr)
2392 {
2393 	ioctlcmd_t add, del;
2394 	frentry_t *fr;
2395 	ipfobj_t obj;
2396 
2397 	if (ptr == NULL)
2398 		return(0);
2399 
2400 	fr = ptr;
2401 	add = 0;
2402 	del = 0;
2403 
2404 	bzero((char *)&obj, sizeof(obj));
2405 	obj.ipfo_rev = IPFILTER_VERSION;
2406 	obj.ipfo_size = fr->fr_size;
2407 	obj.ipfo_type = IPFOBJ_FRENTRY;
2408 	obj.ipfo_ptr = ptr;
2409 
2410 	if ((opts & OPT_DONOTHING) != 0)
2411 		fd = -1;
2412 
2413 	if (opts & OPT_ZERORULEST) {
2414 		add = SIOCZRLST;
2415 	} else if (opts & OPT_INACTIVE) {
2416 		add = (u_int)fr->fr_hits ? SIOCINIFR :
2417 					   SIOCADIFR;
2418 		del = SIOCRMIFR;
2419 	} else {
2420 		add = (u_int)fr->fr_hits ? SIOCINAFR :
2421 					   SIOCADAFR;
2422 		del = SIOCRMAFR;
2423 	}
2424 
2425 	if ((opts & OPT_OUTQUE) != 0)
2426 		fr->fr_flags |= FR_OUTQUE;
2427 	if (fr->fr_hits)
2428 		fr->fr_hits--;
2429 	if ((opts & OPT_VERBOSE) != 0)
2430 		printfr(fr, ioctlfunc);
2431 
2432 	if ((opts & OPT_DEBUG) != 0) {
2433 		binprint(fr, sizeof(*fr));
2434 		if (fr->fr_data != NULL)
2435 			binprint(fr->fr_data, fr->fr_dsize);
2436 	}
2437 
2438 	if ((opts & OPT_ZERORULEST) != 0) {
2439 		if ((*ioctlfunc)(fd, add, (void *)&obj) == -1) {
2440 			if ((opts & OPT_DONOTHING) == 0) {
2441 				char msg[80];
2442 
2443 				snprintf(msg, sizeof(msg), "%d:ioctl(zero rule)",
2444 					fr->fr_flineno);
2445 				return(ipf_perror_fd(fd, ioctlfunc, msg));
2446 			}
2447 		} else {
2448 #ifdef	USE_QUAD_T
2449 			printf("hits %qd bytes %qd ",
2450 				(long long)fr->fr_hits,
2451 				(long long)fr->fr_bytes);
2452 #else
2453 			printf("hits %ld bytes %ld ",
2454 				fr->fr_hits, fr->fr_bytes);
2455 #endif
2456 			printfr(fr, ioctlfunc);
2457 		}
2458 	} else if ((opts & OPT_REMOVE) != 0) {
2459 		if ((*ioctlfunc)(fd, del, (void *)&obj) == -1) {
2460 			if ((opts & OPT_DONOTHING) == 0) {
2461 				char msg[80];
2462 
2463 				snprintf(msg, sizeof(msg), "%d:ioctl(delete rule)",
2464 					fr->fr_flineno);
2465 				return(ipf_perror_fd(fd, ioctlfunc, msg));
2466 			}
2467 		}
2468 	} else {
2469 		if ((*ioctlfunc)(fd, add, (void *)&obj) == -1) {
2470 			if ((opts & OPT_DONOTHING) == 0) {
2471 				char msg[80];
2472 
2473 				snprintf(msg, sizeof(msg), "%d:ioctl(add/insert rule)",
2474 					fr->fr_flineno);
2475 				return(ipf_perror_fd(fd, ioctlfunc, msg));
2476 			}
2477 		}
2478 	}
2479 	return(0);
2480 }
2481 
2482 static void
2483 setsyslog(void)
2484 {
2485 	yysetdict(logwords);
2486 	yybreakondot = 1;
2487 }
2488 
2489 
2490 static void
2491 unsetsyslog(void)
2492 {
2493 	yyresetdict();
2494 	yybreakondot = 0;
2495 }
2496 
2497 
2498 static void
2499 fillgroup(frentry_t *fr)
2500 {
2501 	frentry_t *f;
2502 
2503 	for (f = frold; f != NULL; f = f->fr_next) {
2504 		if (f->fr_grhead == -1 && fr->fr_group == -1)
2505 			break;
2506 		if (f->fr_grhead == -1 || fr->fr_group == -1)
2507 			continue;
2508 		if (strcmp(f->fr_names + f->fr_grhead,
2509 			   fr->fr_names + fr->fr_group) == 0)
2510 			break;
2511 	}
2512 
2513 	if (f == NULL)
2514 		return;
2515 
2516 	/*
2517 	 * Only copy down matching fields if the rules are of the same type
2518 	 * and are of ipf type.   The only fields that are copied are those
2519 	 * that impact the rule parsing itself, eg. need for knowing what the
2520 	 * protocol should be for rules with port comparisons in them.
2521 	 */
2522 	if (f->fr_type != fr->fr_type || f->fr_type != FR_T_IPF)
2523 		return;
2524 
2525 	if (fr->fr_family == 0 && f->fr_family != 0)
2526 		fr->fr_family = f->fr_family;
2527 
2528 	if (fr->fr_mproto == 0 && f->fr_mproto != 0)
2529 		fr->fr_mproto = f->fr_mproto;
2530 	if (fr->fr_proto == 0 && f->fr_proto != 0)
2531 		fr->fr_proto = f->fr_proto;
2532 
2533 	if ((fr->fr_mproto == 0) && ((fr->fr_flx & FI_TCPUDP) == 0) &&
2534 	    ((f->fr_flx & FI_TCPUDP) != 0)) {
2535 		fr->fr_flx |= FI_TCPUDP;
2536 		fr->fr_mflx |= FI_TCPUDP;
2537 	}
2538 }
2539 
2540 
2541 static void
2542 doipfexpr(char *line)
2543 {
2544 	int *array;
2545 	char *error;
2546 
2547 	array = parseipfexpr(line, &error);
2548 	if (array == NULL) {
2549 		fprintf(stderr, "%s:", error);
2550 		yyerror("error parsing ipf matching expression");
2551 		return;
2552 	}
2553 
2554 	fr->fr_type = FR_T_IPFEXPR;
2555 	fr->fr_data = array;
2556 	fr->fr_dsize = array[0] * sizeof(*array);
2557 }
2558 
2559 
2560 static void
2561 do_tuneint(char *varname, int value)
2562 {
2563 	char buffer[80];
2564 
2565 	strncpy(buffer, varname, 60);
2566 	buffer[59] = '\0';
2567 	strcat(buffer, "=");
2568 	snprintf(buffer, sizeof(buffer), "%u", value);
2569 	ipf_dotuning(ipffd, buffer, ioctl);
2570 }
2571 
2572 
2573 static void
2574 do_tunestr(char *varname, char *value)
2575 {
2576 
2577 	if (!strcasecmp(value, "true")) {
2578 		do_tuneint(varname, 1);
2579 	} else if (!strcasecmp(value, "false")) {
2580 		do_tuneint(varname, 0);
2581 	} else {
2582 		yyerror("did not find true/false where expected");
2583 	}
2584 }
2585 
2586 
2587 static void
2588 setifname(frentry_t **frp, int idx, char *name)
2589 {
2590 	int pos;
2591 
2592 	pos = addname(frp, name);
2593 	if (pos == -1)
2594 		return;
2595 	(*frp)->fr_ifnames[idx] = pos;
2596 }
2597 
2598 
2599 static int
2600 addname(frentry_t **frp, char *name)
2601 {
2602 	frentry_t *f;
2603 	int nlen;
2604 	int pos;
2605 
2606 	nlen = strlen(name) + 1;
2607 	f = realloc(*frp, (*frp)->fr_size + nlen);
2608 	if (*frp == frc)
2609 		frc = f;
2610 	*frp = f;
2611 	if (f == NULL)
2612 		return(-1);
2613 	if (f->fr_pnext != NULL)
2614 		*f->fr_pnext = f;
2615 	f->fr_size += nlen;
2616 	pos = f->fr_namelen;
2617 	f->fr_namelen += nlen;
2618 	strcpy(f->fr_names + pos, name);
2619 	f->fr_names[f->fr_namelen] = '\0';
2620 	return(pos);
2621 }
2622 
2623 
2624 static frentry_t *
2625 allocfr(void)
2626 {
2627 	frentry_t *fr;
2628 
2629 	fr = calloc(1, sizeof(*fr));
2630 	if (fr != NULL) {
2631 		fr->fr_size = sizeof(*fr);
2632 		fr->fr_comment = -1;
2633 		fr->fr_group = -1;
2634 		fr->fr_grhead = -1;
2635 		fr->fr_icmphead = -1;
2636 		fr->fr_ifnames[0] = -1;
2637 		fr->fr_ifnames[1] = -1;
2638 		fr->fr_ifnames[2] = -1;
2639 		fr->fr_ifnames[3] = -1;
2640 		fr->fr_tif.fd_name = -1;
2641 		fr->fr_rif.fd_name = -1;
2642 		fr->fr_dif.fd_name = -1;
2643 	}
2644 	return(fr);
2645 }
2646 
2647 
2648 static void
2649 setgroup(frentry_t **frp, char *name)
2650 {
2651 	int pos;
2652 
2653 	pos = addname(frp, name);
2654 	if (pos == -1)
2655 		return;
2656 	(*frp)->fr_group = pos;
2657 }
2658 
2659 
2660 static void
2661 setgrhead(frentry_t **frp, char *name)
2662 {
2663 	int pos;
2664 
2665 	pos = addname(frp, name);
2666 	if (pos == -1)
2667 		return;
2668 	(*frp)->fr_grhead = pos;
2669 }
2670 
2671 
2672 static void
2673 seticmphead(frentry_t **frp, char *name)
2674 {
2675 	int pos;
2676 
2677 	pos = addname(frp, name);
2678 	if (pos == -1)
2679 		return;
2680 	(*frp)->fr_icmphead = pos;
2681 }
2682 
2683 
2684 static void
2685 build_dstaddr_af(frentry_t *fp, void *ptr)
2686 {
2687 	struct ipp_s *ipp = ptr;
2688 	frentry_t *f = fp;
2689 
2690 	if (f->fr_family != AF_UNSPEC && ipp->f == AF_UNSPEC) {
2691 		ipp->f = f->fr_family;
2692 		ipp->v = f->fr_ip.fi_v;
2693 	}
2694 	if (ipp->f == AF_INET)
2695 		ipp->v = 4;
2696 	else if (ipp->f == AF_INET6)
2697 		ipp->v = 6;
2698 
2699 	for (; f != NULL; f = f->fr_next) {
2700 		f->fr_ip.fi_dst = ipp->a;
2701 		f->fr_mip.fi_dst = ipp->m;
2702 		f->fr_family = ipp->f;
2703 		f->fr_ip.fi_v = ipp->v;
2704 		f->fr_mip.fi_v = 0xf;
2705 		f->fr_datype = ipp->type;
2706 		if (ipp->ifpos != -1)
2707 			f->fr_ipf->fri_difpidx = ipp->ifpos;
2708 	}
2709 	fr = NULL;
2710 }
2711 
2712 
2713 static void
2714 build_srcaddr_af(frentry_t *fp, void *ptr)
2715 {
2716 	struct ipp_s *ipp = ptr;
2717 	frentry_t *f = fp;
2718 
2719 	if (f->fr_family != AF_UNSPEC && ipp->f == AF_UNSPEC) {
2720 		ipp->f = f->fr_family;
2721 		ipp->v = f->fr_ip.fi_v;
2722 	}
2723 	if (ipp->f == AF_INET)
2724 		ipp->v = 4;
2725 	else if (ipp->f == AF_INET6)
2726 		ipp->v = 6;
2727 
2728 	for (; f != NULL; f = f->fr_next) {
2729 		f->fr_ip.fi_src = ipp->a;
2730 		f->fr_mip.fi_src = ipp->m;
2731 		f->fr_family = ipp->f;
2732 		f->fr_ip.fi_v = ipp->v;
2733 		f->fr_mip.fi_v = 0xf;
2734 		f->fr_satype = ipp->type;
2735 		f->fr_ipf->fri_sifpidx = ipp->ifpos;
2736 	}
2737 	fr = NULL;
2738 }
2739