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