1145519Sdarrenr/*	$FreeBSD$	*/
2145510Sdarrenr
3145510Sdarrenr/*
4255332Scy * Copyright (C) 2012 by Darren Reed.
5145510Sdarrenr *
6145510Sdarrenr * See the IPFILTER.LICENCE file for details on licencing.
7145510Sdarrenr *
8255332Scy * $Id$
9145510Sdarrenr */
10145510Sdarrenr
11145510Sdarrenr#include "ipf.h"
12145510Sdarrenr
13145510Sdarrenr
14145510Sdarrenr/*
15145510Sdarrenr * print the filter structure in a useful way
16145510Sdarrenr */
17255332Scyvoid
18255332Scyprintfr(fp, iocfunc)
19255332Scy	struct	frentry	*fp;
20255332Scy	ioctlfunc_t	iocfunc;
21145510Sdarrenr{
22145510Sdarrenr	struct protoent	*p;
23145510Sdarrenr	u_short	sec[2];
24145510Sdarrenr	u_32_t type;
25255332Scy	int pr, af;
26145510Sdarrenr	char *s;
27255332Scy	int hash;
28145510Sdarrenr
29145510Sdarrenr	pr = -2;
30145510Sdarrenr	type = fp->fr_type & ~FR_T_BUILTIN;
31145510Sdarrenr
32145510Sdarrenr	if ((fp->fr_type & FR_T_BUILTIN) != 0)
33255332Scy		PRINTF("# Builtin: ");
34145510Sdarrenr
35153881Sguido	if (fp->fr_collect != 0)
36255332Scy		PRINTF("%u ", fp->fr_collect);
37153881Sguido
38145510Sdarrenr	if (fp->fr_type == FR_T_CALLFUNC) {
39145510Sdarrenr		;
40145510Sdarrenr	} else if (fp->fr_func != NULL) {
41255332Scy		PRINTF("call");
42145510Sdarrenr		if ((fp->fr_flags & FR_CALLNOW) != 0)
43255332Scy			PRINTF(" now");
44145510Sdarrenr		s = kvatoname(fp->fr_func, iocfunc);
45255332Scy		PRINTF(" %s/%u", s ? s : "?", fp->fr_arg);
46145510Sdarrenr	} else if (FR_ISPASS(fp->fr_flags))
47255332Scy		PRINTF("pass");
48145510Sdarrenr	else if (FR_ISBLOCK(fp->fr_flags)) {
49255332Scy		PRINTF("block");
50145510Sdarrenr	} else if ((fp->fr_flags & FR_LOGMASK) == FR_LOG) {
51145510Sdarrenr		printlog(fp);
52145510Sdarrenr	} else if (FR_ISACCOUNT(fp->fr_flags))
53255332Scy		PRINTF("count");
54145510Sdarrenr	else if (FR_ISAUTH(fp->fr_flags))
55255332Scy		PRINTF("auth");
56145510Sdarrenr	else if (FR_ISPREAUTH(fp->fr_flags))
57255332Scy		PRINTF("preauth");
58145510Sdarrenr	else if (FR_ISNOMATCH(fp->fr_flags))
59255332Scy		PRINTF("nomatch");
60255332Scy	else if (FR_ISDECAPS(fp->fr_flags))
61255332Scy		PRINTF("decapsulate");
62145510Sdarrenr	else if (FR_ISSKIP(fp->fr_flags))
63255332Scy		PRINTF("skip %u", fp->fr_arg);
64145510Sdarrenr	else {
65255332Scy		PRINTF("%x", fp->fr_flags);
66145510Sdarrenr	}
67161357Sguido	if (fp->fr_flags & FR_RETICMP) {
68161357Sguido		if ((fp->fr_flags & FR_RETMASK) == FR_FAKEICMP)
69255332Scy			PRINTF(" return-icmp-as-dest");
70161357Sguido		else if ((fp->fr_flags & FR_RETMASK) == FR_RETICMP)
71255332Scy			PRINTF(" return-icmp");
72161357Sguido		if (fp->fr_icode) {
73161357Sguido			if (fp->fr_icode <= MAX_ICMPCODE)
74255332Scy				PRINTF("(%s)",
75161357Sguido					icmpcodes[(int)fp->fr_icode]);
76161357Sguido			else
77255332Scy				PRINTF("(%d)", fp->fr_icode);
78161357Sguido		}
79161357Sguido	} else if ((fp->fr_flags & FR_RETMASK) == FR_RETRST)
80255332Scy		PRINTF(" return-rst");
81145510Sdarrenr
82145510Sdarrenr	if (fp->fr_flags & FR_OUTQUE)
83255332Scy		PRINTF(" out ");
84255332Scy	else if (fp->fr_flags & FR_INQUE)
85255332Scy		PRINTF(" in ");
86145510Sdarrenr
87145510Sdarrenr	if (((fp->fr_flags & FR_LOGB) == FR_LOGB) ||
88145510Sdarrenr	    ((fp->fr_flags & FR_LOGP) == FR_LOGP)) {
89145510Sdarrenr		printlog(fp);
90145510Sdarrenr		putchar(' ');
91145510Sdarrenr	}
92145510Sdarrenr
93145510Sdarrenr	if (fp->fr_flags & FR_QUICK)
94255332Scy		PRINTF("quick ");
95145510Sdarrenr
96255332Scy	if (fp->fr_ifnames[0] != -1) {
97255332Scy		printifname("on ", fp->fr_names + fp->fr_ifnames[0],
98255332Scy			    fp->fr_ifa);
99255332Scy		if (fp->fr_ifnames[1] != -1 &&
100255332Scy		    strcmp(fp->fr_names + fp->fr_ifnames[1], "*"))
101255332Scy			printifname(",", fp->fr_names + fp->fr_ifnames[1],
102255332Scy				    fp->fr_ifas[1]);
103145510Sdarrenr		putchar(' ');
104145510Sdarrenr	}
105145510Sdarrenr
106255332Scy	if (fp->fr_tif.fd_name != -1)
107255332Scy		print_toif(fp->fr_family, "to", fp->fr_names, &fp->fr_tif);
108255332Scy	if (fp->fr_dif.fd_name != -1)
109255332Scy		print_toif(fp->fr_family, "dup-to", fp->fr_names,
110255332Scy			   &fp->fr_dif);
111255332Scy	if (fp->fr_rif.fd_name != -1)
112255332Scy		print_toif(fp->fr_family, "reply-to", fp->fr_names,
113255332Scy			   &fp->fr_rif);
114145510Sdarrenr	if (fp->fr_flags & FR_FASTROUTE)
115255332Scy		PRINTF("fastroute ");
116145510Sdarrenr
117255332Scy	if ((fp->fr_ifnames[2] != -1 &&
118255332Scy	     strcmp(fp->fr_names + fp->fr_ifnames[2], "*")) ||
119255332Scy	    (fp->fr_ifnames[3] != -1 &&
120255332Scy		 strcmp(fp->fr_names + fp->fr_ifnames[3], "*"))) {
121145510Sdarrenr		if (fp->fr_flags & FR_OUTQUE)
122255332Scy			PRINTF("in-via ");
123145510Sdarrenr		else
124255332Scy			PRINTF("out-via ");
125145510Sdarrenr
126255332Scy		if (fp->fr_ifnames[2] != -1) {
127255332Scy			printifname("", fp->fr_names + fp->fr_ifnames[2],
128145510Sdarrenr				    fp->fr_ifas[2]);
129255332Scy			if (fp->fr_ifnames[3] != -1) {
130255332Scy				printifname(",",
131255332Scy					    fp->fr_names + fp->fr_ifnames[3],
132145510Sdarrenr					    fp->fr_ifas[3]);
133145510Sdarrenr			}
134153881Sguido			putchar(' ');
135145510Sdarrenr		}
136145510Sdarrenr	}
137145510Sdarrenr
138255332Scy	if (fp->fr_family == AF_INET) {
139255332Scy		PRINTF("inet ");
140255332Scy		af = AF_INET;
141255332Scy#ifdef USE_INET6
142255332Scy	} else if (fp->fr_family == AF_INET6) {
143255332Scy		PRINTF("inet6 ");
144255332Scy		af = AF_INET6;
145255332Scy#endif
146255332Scy	} else {
147255332Scy		af = -1;
148255332Scy	}
149255332Scy
150145510Sdarrenr	if (type == FR_T_IPF) {
151145510Sdarrenr		if (fp->fr_mip.fi_tos)
152255332Scy			PRINTF("tos %#x ", fp->fr_tos);
153145510Sdarrenr		if (fp->fr_mip.fi_ttl)
154255332Scy			PRINTF("ttl %d ", fp->fr_ttl);
155145510Sdarrenr		if (fp->fr_flx & FI_TCPUDP) {
156255332Scy			PRINTF("proto tcp/udp ");
157145510Sdarrenr			pr = -1;
158145510Sdarrenr		} else if (fp->fr_mip.fi_p) {
159145510Sdarrenr			pr = fp->fr_ip.fi_p;
160153881Sguido			p = getprotobynumber(pr);
161255332Scy			PRINTF("proto ");
162153881Sguido			printproto(p, pr, NULL);
163153881Sguido			putchar(' ');
164145510Sdarrenr		}
165145510Sdarrenr	}
166145510Sdarrenr
167255332Scy	switch (type)
168255332Scy	{
169255332Scy	case FR_T_NONE :
170255332Scy		PRINTF("all");
171255332Scy		break;
172255332Scy
173255332Scy	case FR_T_IPF :
174255332Scy		PRINTF("from %s", fp->fr_flags & FR_NOTSRCIP ? "!" : "");
175255332Scy		printaddr(af, fp->fr_satype, fp->fr_names, fp->fr_ifnames[0],
176145510Sdarrenr			  &fp->fr_src.s_addr, &fp->fr_smsk.s_addr);
177145510Sdarrenr		if (fp->fr_scmp)
178145510Sdarrenr			printportcmp(pr, &fp->fr_tuc.ftu_src);
179145510Sdarrenr
180255332Scy		PRINTF(" to %s", fp->fr_flags & FR_NOTDSTIP ? "!" : "");
181255332Scy		printaddr(af, fp->fr_datype, fp->fr_names, fp->fr_ifnames[0],
182145510Sdarrenr			  &fp->fr_dst.s_addr, &fp->fr_dmsk.s_addr);
183145510Sdarrenr		if (fp->fr_dcmp)
184145510Sdarrenr			printportcmp(pr, &fp->fr_tuc.ftu_dst);
185145510Sdarrenr
186255332Scy		if (((fp->fr_proto == IPPROTO_ICMP) ||
187255332Scy		     (fp->fr_proto == IPPROTO_ICMPV6)) && fp->fr_icmpm) {
188145510Sdarrenr			int	type = fp->fr_icmp, code;
189255332Scy			char	*name;
190145510Sdarrenr
191145510Sdarrenr			type = ntohs(fp->fr_icmp);
192145510Sdarrenr			code = type & 0xff;
193145510Sdarrenr			type /= 256;
194255332Scy			name = icmptypename(fp->fr_family, type);
195255332Scy			if (name == NULL)
196255332Scy				PRINTF(" icmp-type %d", type);
197145510Sdarrenr			else
198255332Scy				PRINTF(" icmp-type %s", name);
199145510Sdarrenr			if (ntohs(fp->fr_icmpm) & 0xff)
200255332Scy				PRINTF(" code %d", code);
201145510Sdarrenr		}
202145510Sdarrenr		if ((fp->fr_proto == IPPROTO_TCP) &&
203145510Sdarrenr		    (fp->fr_tcpf || fp->fr_tcpfm)) {
204255332Scy			PRINTF(" flags ");
205255332Scy			printtcpflags(fp->fr_tcpf, fp->fr_tcpfm);
206145510Sdarrenr		}
207255332Scy		break;
208255332Scy
209255332Scy	case FR_T_BPFOPC :
210255332Scy	    {
211145510Sdarrenr		fakebpf_t *fb;
212145510Sdarrenr		int i;
213145510Sdarrenr
214255332Scy		PRINTF("bpf-v%d { \"", fp->fr_family);
215145510Sdarrenr		i = fp->fr_dsize / sizeof(*fb);
216145510Sdarrenr
217145510Sdarrenr		for (fb = fp->fr_data, s = ""; i; i--, fb++, s = " ")
218255332Scy			PRINTF("%s%#x %#x %#x %#x", s, fb->fb_c, fb->fb_t,
219145510Sdarrenr			       fb->fb_f, fb->fb_k);
220145510Sdarrenr
221255332Scy		PRINTF("\" }");
222255332Scy		break;
223255332Scy	    }
224255332Scy
225255332Scy	case FR_T_COMPIPF :
226255332Scy		break;
227255332Scy
228255332Scy	case FR_T_CALLFUNC :
229255332Scy		PRINTF("call function at %p", fp->fr_data);
230255332Scy		break;
231255332Scy
232255332Scy	case FR_T_IPFEXPR :
233255332Scy		PRINTF("exp { \"");
234255332Scy		printipfexpr(fp->fr_data);
235255332Scy		PRINTF("\" } ");
236255332Scy		break;
237255332Scy
238255332Scy	default :
239255332Scy		PRINTF("[unknown filter type %#x]", fp->fr_type);
240255332Scy		break;
241145510Sdarrenr	}
242145510Sdarrenr
243145510Sdarrenr	if ((type == FR_T_IPF) &&
244145510Sdarrenr	    ((fp->fr_flx & FI_WITH) || (fp->fr_mflx & FI_WITH) ||
245145510Sdarrenr	     fp->fr_optbits || fp->fr_optmask ||
246145510Sdarrenr	     fp->fr_secbits || fp->fr_secmask)) {
247145510Sdarrenr		char *comma = " ";
248145510Sdarrenr
249255332Scy		PRINTF(" with");
250145510Sdarrenr		if (fp->fr_optbits || fp->fr_optmask ||
251145510Sdarrenr		    fp->fr_secbits || fp->fr_secmask) {
252145510Sdarrenr			sec[0] = fp->fr_secmask;
253145510Sdarrenr			sec[1] = fp->fr_secbits;
254255332Scy			if (fp->fr_family == AF_INET)
255145510Sdarrenr				optprint(sec, fp->fr_optmask, fp->fr_optbits);
256145510Sdarrenr#ifdef	USE_INET6
257145510Sdarrenr			else
258145510Sdarrenr				optprintv6(sec, fp->fr_optmask,
259145510Sdarrenr					   fp->fr_optbits);
260145510Sdarrenr#endif
261145510Sdarrenr		} else if (fp->fr_mflx & FI_OPTIONS) {
262145510Sdarrenr			fputs(comma, stdout);
263145510Sdarrenr			if (!(fp->fr_flx & FI_OPTIONS))
264255332Scy				PRINTF("not ");
265255332Scy			PRINTF("ipopts");
266145510Sdarrenr			comma = ",";
267145510Sdarrenr		}
268145510Sdarrenr		if (fp->fr_mflx & FI_SHORT) {
269145510Sdarrenr			fputs(comma, stdout);
270145510Sdarrenr			if (!(fp->fr_flx & FI_SHORT))
271255332Scy				PRINTF("not ");
272255332Scy			PRINTF("short");
273145510Sdarrenr			comma = ",";
274145510Sdarrenr		}
275145510Sdarrenr		if (fp->fr_mflx & FI_FRAG) {
276145510Sdarrenr			fputs(comma, stdout);
277145510Sdarrenr			if (!(fp->fr_flx & FI_FRAG))
278255332Scy				PRINTF("not ");
279255332Scy			PRINTF("frag");
280145510Sdarrenr			comma = ",";
281145510Sdarrenr		}
282145510Sdarrenr		if (fp->fr_mflx & FI_FRAGBODY) {
283145510Sdarrenr			fputs(comma, stdout);
284145510Sdarrenr			if (!(fp->fr_flx & FI_FRAGBODY))
285255332Scy				PRINTF("not ");
286255332Scy			PRINTF("frag-body");
287145510Sdarrenr			comma = ",";
288145510Sdarrenr		}
289145510Sdarrenr		if (fp->fr_mflx & FI_NATED) {
290145510Sdarrenr			fputs(comma, stdout);
291145510Sdarrenr			if (!(fp->fr_flx & FI_NATED))
292255332Scy				PRINTF("not ");
293255332Scy			PRINTF("nat");
294145510Sdarrenr			comma = ",";
295145510Sdarrenr		}
296145510Sdarrenr		if (fp->fr_mflx & FI_LOWTTL) {
297145510Sdarrenr			fputs(comma, stdout);
298145510Sdarrenr			if (!(fp->fr_flx & FI_LOWTTL))
299255332Scy				PRINTF("not ");
300255332Scy			PRINTF("lowttl");
301145510Sdarrenr			comma = ",";
302145510Sdarrenr		}
303145510Sdarrenr		if (fp->fr_mflx & FI_BAD) {
304145510Sdarrenr			fputs(comma, stdout);
305145510Sdarrenr			if (!(fp->fr_flx & FI_BAD))
306255332Scy				PRINTF("not ");
307255332Scy			PRINTF("bad");
308145510Sdarrenr			comma = ",";
309145510Sdarrenr		}
310145510Sdarrenr		if (fp->fr_mflx & FI_BADSRC) {
311145510Sdarrenr			fputs(comma, stdout);
312145510Sdarrenr			if (!(fp->fr_flx & FI_BADSRC))
313255332Scy				PRINTF("not ");
314255332Scy			PRINTF("bad-src");
315145510Sdarrenr			comma = ",";
316145510Sdarrenr		}
317145510Sdarrenr		if (fp->fr_mflx & FI_BADNAT) {
318145510Sdarrenr			fputs(comma, stdout);
319145510Sdarrenr			if (!(fp->fr_flx & FI_BADNAT))
320255332Scy				PRINTF("not ");
321255332Scy			PRINTF("bad-nat");
322145510Sdarrenr			comma = ",";
323145510Sdarrenr		}
324145510Sdarrenr		if (fp->fr_mflx & FI_OOW) {
325145510Sdarrenr			fputs(comma, stdout);
326145510Sdarrenr			if (!(fp->fr_flx & FI_OOW))
327255332Scy				PRINTF("not ");
328255332Scy			PRINTF("oow");
329153881Sguido			comma = ",";
330145510Sdarrenr		}
331153881Sguido		if (fp->fr_mflx & FI_MBCAST) {
332153881Sguido			fputs(comma, stdout);
333153881Sguido			if (!(fp->fr_flx & FI_MBCAST))
334255332Scy				PRINTF("not ");
335255332Scy			PRINTF("mbcast");
336153881Sguido			comma = ",";
337153881Sguido		}
338153881Sguido		if (fp->fr_mflx & FI_BROADCAST) {
339153881Sguido			fputs(comma, stdout);
340153881Sguido			if (!(fp->fr_flx & FI_BROADCAST))
341255332Scy				PRINTF("not ");
342255332Scy			PRINTF("bcast");
343153881Sguido			comma = ",";
344153881Sguido		}
345153881Sguido		if (fp->fr_mflx & FI_MULTICAST) {
346153881Sguido			fputs(comma, stdout);
347153881Sguido			if (!(fp->fr_flx & FI_MULTICAST))
348255332Scy				PRINTF("not ");
349255332Scy			PRINTF("mcast");
350153881Sguido			comma = ",";
351153881Sguido		}
352153881Sguido		if (fp->fr_mflx & FI_STATE) {
353153881Sguido			fputs(comma, stdout);
354153881Sguido			if (!(fp->fr_flx & FI_STATE))
355255332Scy				PRINTF("not ");
356255332Scy			PRINTF("state");
357153881Sguido			comma = ",";
358153881Sguido		}
359255332Scy		if (fp->fr_mflx & FI_V6EXTHDR) {
360255332Scy			fputs(comma, stdout);
361255332Scy			if (!(fp->fr_flx & FI_V6EXTHDR))
362255332Scy				PRINTF("not ");
363255332Scy			PRINTF("v6hdrs");
364255332Scy			comma = ",";
365255332Scy		}
366145510Sdarrenr	}
367145510Sdarrenr
368145510Sdarrenr	if (fp->fr_flags & FR_KEEPSTATE) {
369255332Scy		host_track_t *src = &fp->fr_srctrack;
370255332Scy		PRINTF(" keep state");
371255332Scy		if ((fp->fr_flags & (FR_STSTRICT|FR_NEWISN|
372255332Scy				     FR_NOICMPERR|FR_STATESYNC)) ||
373255332Scy		    (fp->fr_statemax != 0) || (fp->fr_age[0] != 0) ||
374255332Scy		    (src->ht_max_nodes != 0)) {
375145510Sdarrenr			char *comma = "";
376255332Scy			PRINTF(" (");
377145510Sdarrenr			if (fp->fr_statemax != 0) {
378255332Scy				PRINTF("limit %u", fp->fr_statemax);
379145510Sdarrenr				comma = ",";
380145510Sdarrenr			}
381255332Scy			if (src->ht_max_nodes != 0) {
382255332Scy				PRINTF("%smax-nodes %d", comma,
383255332Scy				       src->ht_max_nodes);
384255332Scy				if (src->ht_max_per_node)
385255332Scy					PRINTF(", max-per-src %d/%d",
386255332Scy					       src->ht_max_per_node,
387255332Scy					       src->ht_netmask);
388255332Scy				comma = ",";
389255332Scy			}
390145510Sdarrenr			if (fp->fr_flags & FR_STSTRICT) {
391255332Scy				PRINTF("%sstrict", comma);
392145510Sdarrenr				comma = ",";
393145510Sdarrenr			}
394255332Scy			if (fp->fr_flags & FR_STLOOSE) {
395255332Scy				PRINTF("%sloose", comma);
396255332Scy				comma = ",";
397255332Scy			}
398145510Sdarrenr			if (fp->fr_flags & FR_NEWISN) {
399255332Scy				PRINTF("%snewisn", comma);
400145510Sdarrenr				comma = ",";
401145510Sdarrenr			}
402145510Sdarrenr			if (fp->fr_flags & FR_NOICMPERR) {
403255332Scy				PRINTF("%sno-icmp-err", comma);
404145510Sdarrenr				comma = ",";
405145510Sdarrenr			}
406145510Sdarrenr			if (fp->fr_flags & FR_STATESYNC) {
407255332Scy				PRINTF("%ssync", comma);
408145510Sdarrenr				comma = ",";
409145510Sdarrenr			}
410145510Sdarrenr			if (fp->fr_age[0] || fp->fr_age[1])
411255332Scy				PRINTF("%sage %d/%d", comma, fp->fr_age[0],
412145510Sdarrenr				       fp->fr_age[1]);
413255332Scy			PRINTF(")");
414145510Sdarrenr		}
415145510Sdarrenr	}
416145510Sdarrenr	if (fp->fr_flags & FR_KEEPFRAG) {
417255332Scy		PRINTF(" keep frags");
418145510Sdarrenr		if (fp->fr_flags & (FR_FRSTRICT)) {
419255332Scy			PRINTF(" (");
420145510Sdarrenr			if (fp->fr_flags & FR_FRSTRICT)
421255332Scy				PRINTF("strict");
422255332Scy			PRINTF(")");
423255332Scy
424145510Sdarrenr		}
425145510Sdarrenr	}
426145510Sdarrenr	if (fp->fr_isc != (struct ipscan *)-1) {
427255332Scy		if (fp->fr_isctag != -1)
428255332Scy			PRINTF(" scan %s", fp->fr_isctag + fp->fr_names);
429145510Sdarrenr		else
430255332Scy			PRINTF(" scan *");
431145510Sdarrenr	}
432255332Scy	if (fp->fr_grhead != -1)
433255332Scy		PRINTF(" head %s", fp->fr_names + fp->fr_grhead);
434255332Scy	if (fp->fr_group != -1)
435255332Scy		PRINTF(" group %s", fp->fr_names + fp->fr_group);
436145510Sdarrenr	if (fp->fr_logtag != FR_NOLOGTAG || *fp->fr_nattag.ipt_tag) {
437145510Sdarrenr		char *s = "";
438145510Sdarrenr
439255332Scy		PRINTF(" set-tag(");
440145510Sdarrenr		if (fp->fr_logtag != FR_NOLOGTAG) {
441255332Scy			PRINTF("log=%u", fp->fr_logtag);
442145510Sdarrenr			s = ", ";
443145510Sdarrenr		}
444145510Sdarrenr		if (*fp->fr_nattag.ipt_tag) {
445255332Scy			PRINTF("%snat=%-.*s", s, IPFTAG_LEN,
446145510Sdarrenr				fp->fr_nattag.ipt_tag);
447145510Sdarrenr		}
448255332Scy		PRINTF(")");
449145510Sdarrenr	}
450170268Sdarrenr
451145510Sdarrenr	if (fp->fr_pps)
452255332Scy		PRINTF(" pps %d", fp->fr_pps);
453170268Sdarrenr
454255332Scy	if (fp->fr_comment != -1)
455255332Scy		PRINTF(" comment \"%s\"", fp->fr_names + fp->fr_comment);
456255332Scy
457255332Scy	hash = 0;
458170268Sdarrenr	if ((fp->fr_flags & FR_KEEPSTATE) && (opts & OPT_VERBOSE)) {
459255332Scy		PRINTF(" # count %d", fp->fr_statecnt);
460255332Scy		if (fp->fr_die != 0)
461255332Scy			PRINTF(" rule-ttl %u", fp->fr_die);
462255332Scy		hash = 1;
463255332Scy	} else if (fp->fr_die != 0) {
464255332Scy		PRINTF(" # rule-ttl %u", fp->fr_die);
465255332Scy		hash = 1;
466170268Sdarrenr	}
467255332Scy	if (opts & OPT_DEBUG) {
468255332Scy		if (hash == 0)
469255332Scy			putchar('#');
470255332Scy		PRINTF(" ref %d", fp->fr_ref);
471255332Scy	}
472145510Sdarrenr	(void)putchar('\n');
473145510Sdarrenr}
474