xref: /netbsd-src/external/bsd/ipf/dist/lib/printfr.c (revision 13885a665959c62f13a82b3caedf986eaa17aa31)
1*13885a66Sdarrenr /*	$NetBSD: printfr.c,v 1.2 2012/07/22 14:27:36 darrenr Exp $	*/
2bc4097aaSchristos 
3bc4097aaSchristos /*
4c9d5dc6cSdarrenr  * Copyright (C) 2012 by Darren Reed.
5bc4097aaSchristos  *
6bc4097aaSchristos  * See the IPFILTER.LICENCE file for details on licencing.
7bc4097aaSchristos  *
8*13885a66Sdarrenr  * Id: printfr.c,v 1.1.1.2 2012/07/22 13:44:40 darrenr Exp $
9bc4097aaSchristos  */
10bc4097aaSchristos 
11bc4097aaSchristos #include "ipf.h"
12bc4097aaSchristos 
13bc4097aaSchristos 
14bc4097aaSchristos /*
15bc4097aaSchristos  * print the filter structure in a useful way
16bc4097aaSchristos  */
17bc4097aaSchristos void
printfr(fp,iocfunc)18bc4097aaSchristos printfr(fp, iocfunc)
19bc4097aaSchristos 	struct	frentry	*fp;
20bc4097aaSchristos 	ioctlfunc_t	iocfunc;
21bc4097aaSchristos {
22bc4097aaSchristos 	struct protoent	*p;
23bc4097aaSchristos 	u_short	sec[2];
24bc4097aaSchristos 	u_32_t type;
25bc4097aaSchristos 	int pr, af;
26bc4097aaSchristos 	char *s;
27bc4097aaSchristos 	int hash;
28bc4097aaSchristos 
29bc4097aaSchristos 	pr = -2;
30bc4097aaSchristos 	type = fp->fr_type & ~FR_T_BUILTIN;
31bc4097aaSchristos 
32bc4097aaSchristos 	if ((fp->fr_type & FR_T_BUILTIN) != 0)
33bc4097aaSchristos 		PRINTF("# Builtin: ");
34bc4097aaSchristos 
35bc4097aaSchristos 	if (fp->fr_collect != 0)
36bc4097aaSchristos 		PRINTF("%u ", fp->fr_collect);
37bc4097aaSchristos 
38bc4097aaSchristos 	if (fp->fr_type == FR_T_CALLFUNC) {
39bc4097aaSchristos 		;
40bc4097aaSchristos 	} else if (fp->fr_func != NULL) {
41bc4097aaSchristos 		PRINTF("call");
42bc4097aaSchristos 		if ((fp->fr_flags & FR_CALLNOW) != 0)
43bc4097aaSchristos 			PRINTF(" now");
44bc4097aaSchristos 		s = kvatoname(fp->fr_func, iocfunc);
45bc4097aaSchristos 		PRINTF(" %s/%u", s ? s : "?", fp->fr_arg);
46bc4097aaSchristos 	} else if (FR_ISPASS(fp->fr_flags))
47bc4097aaSchristos 		PRINTF("pass");
48bc4097aaSchristos 	else if (FR_ISBLOCK(fp->fr_flags)) {
49bc4097aaSchristos 		PRINTF("block");
50bc4097aaSchristos 	} else if ((fp->fr_flags & FR_LOGMASK) == FR_LOG) {
51bc4097aaSchristos 		printlog(fp);
52bc4097aaSchristos 	} else if (FR_ISACCOUNT(fp->fr_flags))
53bc4097aaSchristos 		PRINTF("count");
54bc4097aaSchristos 	else if (FR_ISAUTH(fp->fr_flags))
55bc4097aaSchristos 		PRINTF("auth");
56bc4097aaSchristos 	else if (FR_ISPREAUTH(fp->fr_flags))
57bc4097aaSchristos 		PRINTF("preauth");
58bc4097aaSchristos 	else if (FR_ISNOMATCH(fp->fr_flags))
59bc4097aaSchristos 		PRINTF("nomatch");
60c9d5dc6cSdarrenr 	else if (FR_ISDECAPS(fp->fr_flags))
61c9d5dc6cSdarrenr 		PRINTF("decapsulate");
62bc4097aaSchristos 	else if (FR_ISSKIP(fp->fr_flags))
63bc4097aaSchristos 		PRINTF("skip %u", fp->fr_arg);
64bc4097aaSchristos 	else {
65bc4097aaSchristos 		PRINTF("%x", fp->fr_flags);
66bc4097aaSchristos 	}
67bc4097aaSchristos 	if (fp->fr_flags & FR_RETICMP) {
68bc4097aaSchristos 		if ((fp->fr_flags & FR_RETMASK) == FR_FAKEICMP)
69bc4097aaSchristos 			PRINTF(" return-icmp-as-dest");
70bc4097aaSchristos 		else if ((fp->fr_flags & FR_RETMASK) == FR_RETICMP)
71bc4097aaSchristos 			PRINTF(" return-icmp");
72bc4097aaSchristos 		if (fp->fr_icode) {
73bc4097aaSchristos 			if (fp->fr_icode <= MAX_ICMPCODE)
74bc4097aaSchristos 				PRINTF("(%s)",
75bc4097aaSchristos 					icmpcodes[(int)fp->fr_icode]);
76bc4097aaSchristos 			else
77bc4097aaSchristos 				PRINTF("(%d)", fp->fr_icode);
78bc4097aaSchristos 		}
79bc4097aaSchristos 	} else if ((fp->fr_flags & FR_RETMASK) == FR_RETRST)
80bc4097aaSchristos 		PRINTF(" return-rst");
81bc4097aaSchristos 
82bc4097aaSchristos 	if (fp->fr_flags & FR_OUTQUE)
83bc4097aaSchristos 		PRINTF(" out ");
84bc4097aaSchristos 	else if (fp->fr_flags & FR_INQUE)
85bc4097aaSchristos 		PRINTF(" in ");
86bc4097aaSchristos 
87bc4097aaSchristos 	if (((fp->fr_flags & FR_LOGB) == FR_LOGB) ||
88bc4097aaSchristos 	    ((fp->fr_flags & FR_LOGP) == FR_LOGP)) {
89bc4097aaSchristos 		printlog(fp);
90bc4097aaSchristos 		putchar(' ');
91bc4097aaSchristos 	}
92bc4097aaSchristos 
93bc4097aaSchristos 	if (fp->fr_flags & FR_QUICK)
94bc4097aaSchristos 		PRINTF("quick ");
95bc4097aaSchristos 
96bc4097aaSchristos 	if (fp->fr_ifnames[0] != -1) {
97bc4097aaSchristos 		printifname("on ", fp->fr_names + fp->fr_ifnames[0],
98bc4097aaSchristos 			    fp->fr_ifa);
99bc4097aaSchristos 		if (fp->fr_ifnames[1] != -1 &&
100bc4097aaSchristos 		    strcmp(fp->fr_names + fp->fr_ifnames[1], "*"))
101bc4097aaSchristos 			printifname(",", fp->fr_names + fp->fr_ifnames[1],
102bc4097aaSchristos 				    fp->fr_ifas[1]);
103bc4097aaSchristos 		putchar(' ');
104bc4097aaSchristos 	}
105bc4097aaSchristos 
106bc4097aaSchristos 	if (fp->fr_tif.fd_name != -1)
107c9d5dc6cSdarrenr 		print_toif(fp->fr_family, "to", fp->fr_names, &fp->fr_tif);
108c9d5dc6cSdarrenr 	if (fp->fr_dif.fd_name != -1)
109c9d5dc6cSdarrenr 		print_toif(fp->fr_family, "dup-to", fp->fr_names,
110c9d5dc6cSdarrenr 			   &fp->fr_dif);
111bc4097aaSchristos 	if (fp->fr_rif.fd_name != -1)
112c9d5dc6cSdarrenr 		print_toif(fp->fr_family, "reply-to", fp->fr_names,
113c9d5dc6cSdarrenr 			   &fp->fr_rif);
114bc4097aaSchristos 	if (fp->fr_flags & FR_FASTROUTE)
115bc4097aaSchristos 		PRINTF("fastroute ");
116bc4097aaSchristos 
117bc4097aaSchristos 	if ((fp->fr_ifnames[2] != -1 &&
118bc4097aaSchristos 	     strcmp(fp->fr_names + fp->fr_ifnames[2], "*")) ||
119bc4097aaSchristos 	    (fp->fr_ifnames[3] != -1 &&
120bc4097aaSchristos 		 strcmp(fp->fr_names + fp->fr_ifnames[3], "*"))) {
121bc4097aaSchristos 		if (fp->fr_flags & FR_OUTQUE)
122bc4097aaSchristos 			PRINTF("in-via ");
123bc4097aaSchristos 		else
124bc4097aaSchristos 			PRINTF("out-via ");
125bc4097aaSchristos 
126bc4097aaSchristos 		if (fp->fr_ifnames[2] != -1) {
127bc4097aaSchristos 			printifname("", fp->fr_names + fp->fr_ifnames[2],
128bc4097aaSchristos 				    fp->fr_ifas[2]);
129bc4097aaSchristos 			if (fp->fr_ifnames[3] != -1) {
130bc4097aaSchristos 				printifname(",",
131bc4097aaSchristos 					    fp->fr_names + fp->fr_ifnames[3],
132bc4097aaSchristos 					    fp->fr_ifas[3]);
133bc4097aaSchristos 			}
134bc4097aaSchristos 			putchar(' ');
135bc4097aaSchristos 		}
136bc4097aaSchristos 	}
137bc4097aaSchristos 
138bc4097aaSchristos 	if (fp->fr_family == AF_INET) {
139bc4097aaSchristos 		PRINTF("inet ");
140bc4097aaSchristos 		af = AF_INET;
141bc4097aaSchristos #ifdef USE_INET6
142bc4097aaSchristos 	} else if (fp->fr_family == AF_INET6) {
143bc4097aaSchristos 		PRINTF("inet6 ");
144bc4097aaSchristos 		af = AF_INET6;
145bc4097aaSchristos #endif
146bc4097aaSchristos 	} else {
147bc4097aaSchristos 		af = -1;
148bc4097aaSchristos 	}
149bc4097aaSchristos 
150bc4097aaSchristos 	if (type == FR_T_IPF) {
151bc4097aaSchristos 		if (fp->fr_mip.fi_tos)
152bc4097aaSchristos 			PRINTF("tos %#x ", fp->fr_tos);
153bc4097aaSchristos 		if (fp->fr_mip.fi_ttl)
154bc4097aaSchristos 			PRINTF("ttl %d ", fp->fr_ttl);
155bc4097aaSchristos 		if (fp->fr_flx & FI_TCPUDP) {
156bc4097aaSchristos 			PRINTF("proto tcp/udp ");
157bc4097aaSchristos 			pr = -1;
158bc4097aaSchristos 		} else if (fp->fr_mip.fi_p) {
159bc4097aaSchristos 			pr = fp->fr_ip.fi_p;
160bc4097aaSchristos 			p = getprotobynumber(pr);
161bc4097aaSchristos 			PRINTF("proto ");
162bc4097aaSchristos 			printproto(p, pr, NULL);
163bc4097aaSchristos 			putchar(' ');
164bc4097aaSchristos 		}
165bc4097aaSchristos 	}
166bc4097aaSchristos 
167bc4097aaSchristos 	switch (type)
168bc4097aaSchristos 	{
169bc4097aaSchristos 	case FR_T_NONE :
170bc4097aaSchristos 		PRINTF("all");
171bc4097aaSchristos 		break;
172bc4097aaSchristos 
173bc4097aaSchristos 	case FR_T_IPF :
174bc4097aaSchristos 		PRINTF("from %s", fp->fr_flags & FR_NOTSRCIP ? "!" : "");
175bc4097aaSchristos 		printaddr(af, fp->fr_satype, fp->fr_names, fp->fr_ifnames[0],
176bc4097aaSchristos 			  &fp->fr_src.s_addr, &fp->fr_smsk.s_addr);
177bc4097aaSchristos 		if (fp->fr_scmp)
178bc4097aaSchristos 			printportcmp(pr, &fp->fr_tuc.ftu_src);
179bc4097aaSchristos 
180bc4097aaSchristos 		PRINTF(" to %s", fp->fr_flags & FR_NOTDSTIP ? "!" : "");
181bc4097aaSchristos 		printaddr(af, fp->fr_datype, fp->fr_names, fp->fr_ifnames[0],
182bc4097aaSchristos 			  &fp->fr_dst.s_addr, &fp->fr_dmsk.s_addr);
183bc4097aaSchristos 		if (fp->fr_dcmp)
184bc4097aaSchristos 			printportcmp(pr, &fp->fr_tuc.ftu_dst);
185bc4097aaSchristos 
186bc4097aaSchristos 		if (((fp->fr_proto == IPPROTO_ICMP) ||
187bc4097aaSchristos 		     (fp->fr_proto == IPPROTO_ICMPV6)) && fp->fr_icmpm) {
188bc4097aaSchristos 			int	type = fp->fr_icmp, code;
189bc4097aaSchristos 			char	*name;
190bc4097aaSchristos 
191bc4097aaSchristos 			type = ntohs(fp->fr_icmp);
192bc4097aaSchristos 			code = type & 0xff;
193bc4097aaSchristos 			type /= 256;
194bc4097aaSchristos 			name = icmptypename(fp->fr_family, type);
195bc4097aaSchristos 			if (name == NULL)
196bc4097aaSchristos 				PRINTF(" icmp-type %d", type);
197bc4097aaSchristos 			else
198bc4097aaSchristos 				PRINTF(" icmp-type %s", name);
199bc4097aaSchristos 			if (ntohs(fp->fr_icmpm) & 0xff)
200bc4097aaSchristos 				PRINTF(" code %d", code);
201bc4097aaSchristos 		}
202bc4097aaSchristos 		if ((fp->fr_proto == IPPROTO_TCP) &&
203bc4097aaSchristos 		    (fp->fr_tcpf || fp->fr_tcpfm)) {
204bc4097aaSchristos 			PRINTF(" flags ");
205bc4097aaSchristos 			printtcpflags(fp->fr_tcpf, fp->fr_tcpfm);
206bc4097aaSchristos 		}
207bc4097aaSchristos 		break;
208bc4097aaSchristos 
209bc4097aaSchristos 	case FR_T_BPFOPC :
210bc4097aaSchristos 	    {
211bc4097aaSchristos 		fakebpf_t *fb;
212bc4097aaSchristos 		int i;
213bc4097aaSchristos 
214bc4097aaSchristos 		PRINTF("bpf-v%d { \"", fp->fr_family);
215bc4097aaSchristos 		i = fp->fr_dsize / sizeof(*fb);
216bc4097aaSchristos 
217bc4097aaSchristos 		for (fb = fp->fr_data, s = ""; i; i--, fb++, s = " ")
218bc4097aaSchristos 			PRINTF("%s%#x %#x %#x %#x", s, fb->fb_c, fb->fb_t,
219bc4097aaSchristos 			       fb->fb_f, fb->fb_k);
220bc4097aaSchristos 
221bc4097aaSchristos 		PRINTF("\" }");
222bc4097aaSchristos 		break;
223bc4097aaSchristos 	    }
224bc4097aaSchristos 
225bc4097aaSchristos 	case FR_T_COMPIPF :
226bc4097aaSchristos 		break;
227bc4097aaSchristos 
228bc4097aaSchristos 	case FR_T_CALLFUNC :
229bc4097aaSchristos 		PRINTF("call function at %p", fp->fr_data);
230bc4097aaSchristos 		break;
231bc4097aaSchristos 
232bc4097aaSchristos 	case FR_T_IPFEXPR :
233bc4097aaSchristos 		PRINTF("exp { \"");
234bc4097aaSchristos 		printipfexpr(fp->fr_data);
235bc4097aaSchristos 		PRINTF("\" } ");
236bc4097aaSchristos 		break;
237bc4097aaSchristos 
238bc4097aaSchristos 	default :
239bc4097aaSchristos 		PRINTF("[unknown filter type %#x]", fp->fr_type);
240bc4097aaSchristos 		break;
241bc4097aaSchristos 	}
242bc4097aaSchristos 
243bc4097aaSchristos 	if ((type == FR_T_IPF) &&
244bc4097aaSchristos 	    ((fp->fr_flx & FI_WITH) || (fp->fr_mflx & FI_WITH) ||
245bc4097aaSchristos 	     fp->fr_optbits || fp->fr_optmask ||
246bc4097aaSchristos 	     fp->fr_secbits || fp->fr_secmask)) {
247bc4097aaSchristos 		char *comma = " ";
248bc4097aaSchristos 
249bc4097aaSchristos 		PRINTF(" with");
250bc4097aaSchristos 		if (fp->fr_optbits || fp->fr_optmask ||
251bc4097aaSchristos 		    fp->fr_secbits || fp->fr_secmask) {
252bc4097aaSchristos 			sec[0] = fp->fr_secmask;
253bc4097aaSchristos 			sec[1] = fp->fr_secbits;
254bc4097aaSchristos 			if (fp->fr_family == AF_INET)
255bc4097aaSchristos 				optprint(sec, fp->fr_optmask, fp->fr_optbits);
256bc4097aaSchristos #ifdef	USE_INET6
257bc4097aaSchristos 			else
258bc4097aaSchristos 				optprintv6(sec, fp->fr_optmask,
259bc4097aaSchristos 					   fp->fr_optbits);
260bc4097aaSchristos #endif
261bc4097aaSchristos 		} else if (fp->fr_mflx & FI_OPTIONS) {
262bc4097aaSchristos 			fputs(comma, stdout);
263bc4097aaSchristos 			if (!(fp->fr_flx & FI_OPTIONS))
264bc4097aaSchristos 				PRINTF("not ");
265bc4097aaSchristos 			PRINTF("ipopts");
266bc4097aaSchristos 			comma = ",";
267bc4097aaSchristos 		}
268bc4097aaSchristos 		if (fp->fr_mflx & FI_SHORT) {
269bc4097aaSchristos 			fputs(comma, stdout);
270bc4097aaSchristos 			if (!(fp->fr_flx & FI_SHORT))
271bc4097aaSchristos 				PRINTF("not ");
272bc4097aaSchristos 			PRINTF("short");
273bc4097aaSchristos 			comma = ",";
274bc4097aaSchristos 		}
275bc4097aaSchristos 		if (fp->fr_mflx & FI_FRAG) {
276bc4097aaSchristos 			fputs(comma, stdout);
277bc4097aaSchristos 			if (!(fp->fr_flx & FI_FRAG))
278bc4097aaSchristos 				PRINTF("not ");
279bc4097aaSchristos 			PRINTF("frag");
280bc4097aaSchristos 			comma = ",";
281bc4097aaSchristos 		}
282bc4097aaSchristos 		if (fp->fr_mflx & FI_FRAGBODY) {
283bc4097aaSchristos 			fputs(comma, stdout);
284bc4097aaSchristos 			if (!(fp->fr_flx & FI_FRAGBODY))
285bc4097aaSchristos 				PRINTF("not ");
286bc4097aaSchristos 			PRINTF("frag-body");
287bc4097aaSchristos 			comma = ",";
288bc4097aaSchristos 		}
289bc4097aaSchristos 		if (fp->fr_mflx & FI_NATED) {
290bc4097aaSchristos 			fputs(comma, stdout);
291bc4097aaSchristos 			if (!(fp->fr_flx & FI_NATED))
292bc4097aaSchristos 				PRINTF("not ");
293bc4097aaSchristos 			PRINTF("nat");
294bc4097aaSchristos 			comma = ",";
295bc4097aaSchristos 		}
296bc4097aaSchristos 		if (fp->fr_mflx & FI_LOWTTL) {
297bc4097aaSchristos 			fputs(comma, stdout);
298bc4097aaSchristos 			if (!(fp->fr_flx & FI_LOWTTL))
299bc4097aaSchristos 				PRINTF("not ");
300bc4097aaSchristos 			PRINTF("lowttl");
301bc4097aaSchristos 			comma = ",";
302bc4097aaSchristos 		}
303bc4097aaSchristos 		if (fp->fr_mflx & FI_BAD) {
304bc4097aaSchristos 			fputs(comma, stdout);
305bc4097aaSchristos 			if (!(fp->fr_flx & FI_BAD))
306bc4097aaSchristos 				PRINTF("not ");
307bc4097aaSchristos 			PRINTF("bad");
308bc4097aaSchristos 			comma = ",";
309bc4097aaSchristos 		}
310bc4097aaSchristos 		if (fp->fr_mflx & FI_BADSRC) {
311bc4097aaSchristos 			fputs(comma, stdout);
312bc4097aaSchristos 			if (!(fp->fr_flx & FI_BADSRC))
313bc4097aaSchristos 				PRINTF("not ");
314bc4097aaSchristos 			PRINTF("bad-src");
315bc4097aaSchristos 			comma = ",";
316bc4097aaSchristos 		}
317bc4097aaSchristos 		if (fp->fr_mflx & FI_BADNAT) {
318bc4097aaSchristos 			fputs(comma, stdout);
319bc4097aaSchristos 			if (!(fp->fr_flx & FI_BADNAT))
320bc4097aaSchristos 				PRINTF("not ");
321bc4097aaSchristos 			PRINTF("bad-nat");
322bc4097aaSchristos 			comma = ",";
323bc4097aaSchristos 		}
324bc4097aaSchristos 		if (fp->fr_mflx & FI_OOW) {
325bc4097aaSchristos 			fputs(comma, stdout);
326bc4097aaSchristos 			if (!(fp->fr_flx & FI_OOW))
327bc4097aaSchristos 				PRINTF("not ");
328bc4097aaSchristos 			PRINTF("oow");
329bc4097aaSchristos 			comma = ",";
330bc4097aaSchristos 		}
331bc4097aaSchristos 		if (fp->fr_mflx & FI_MBCAST) {
332bc4097aaSchristos 			fputs(comma, stdout);
333bc4097aaSchristos 			if (!(fp->fr_flx & FI_MBCAST))
334bc4097aaSchristos 				PRINTF("not ");
335bc4097aaSchristos 			PRINTF("mbcast");
336bc4097aaSchristos 			comma = ",";
337bc4097aaSchristos 		}
338bc4097aaSchristos 		if (fp->fr_mflx & FI_BROADCAST) {
339bc4097aaSchristos 			fputs(comma, stdout);
340bc4097aaSchristos 			if (!(fp->fr_flx & FI_BROADCAST))
341bc4097aaSchristos 				PRINTF("not ");
342bc4097aaSchristos 			PRINTF("bcast");
343bc4097aaSchristos 			comma = ",";
344bc4097aaSchristos 		}
345bc4097aaSchristos 		if (fp->fr_mflx & FI_MULTICAST) {
346bc4097aaSchristos 			fputs(comma, stdout);
347bc4097aaSchristos 			if (!(fp->fr_flx & FI_MULTICAST))
348bc4097aaSchristos 				PRINTF("not ");
349bc4097aaSchristos 			PRINTF("mcast");
350bc4097aaSchristos 			comma = ",";
351bc4097aaSchristos 		}
352bc4097aaSchristos 		if (fp->fr_mflx & FI_STATE) {
353bc4097aaSchristos 			fputs(comma, stdout);
354bc4097aaSchristos 			if (!(fp->fr_flx & FI_STATE))
355bc4097aaSchristos 				PRINTF("not ");
356bc4097aaSchristos 			PRINTF("state");
357bc4097aaSchristos 			comma = ",";
358bc4097aaSchristos 		}
359c9d5dc6cSdarrenr 		if (fp->fr_mflx & FI_V6EXTHDR) {
360c9d5dc6cSdarrenr 			fputs(comma, stdout);
361c9d5dc6cSdarrenr 			if (!(fp->fr_flx & FI_V6EXTHDR))
362c9d5dc6cSdarrenr 				PRINTF("not ");
363c9d5dc6cSdarrenr 			PRINTF("v6hdrs");
364c9d5dc6cSdarrenr 			comma = ",";
365c9d5dc6cSdarrenr 		}
366bc4097aaSchristos 	}
367bc4097aaSchristos 
368bc4097aaSchristos 	if (fp->fr_flags & FR_KEEPSTATE) {
369bc4097aaSchristos 		host_track_t *src = &fp->fr_srctrack;
370bc4097aaSchristos 		PRINTF(" keep state");
371bc4097aaSchristos 		if ((fp->fr_flags & (FR_STSTRICT|FR_NEWISN|
372bc4097aaSchristos 				     FR_NOICMPERR|FR_STATESYNC)) ||
373bc4097aaSchristos 		    (fp->fr_statemax != 0) || (fp->fr_age[0] != 0) ||
374bc4097aaSchristos 		    (src->ht_max_nodes != 0)) {
375bc4097aaSchristos 			char *comma = "";
376bc4097aaSchristos 			PRINTF(" (");
377bc4097aaSchristos 			if (fp->fr_statemax != 0) {
378bc4097aaSchristos 				PRINTF("limit %u", fp->fr_statemax);
379bc4097aaSchristos 				comma = ",";
380bc4097aaSchristos 			}
381bc4097aaSchristos 			if (src->ht_max_nodes != 0) {
382bc4097aaSchristos 				PRINTF("%smax-nodes %d", comma,
383bc4097aaSchristos 				       src->ht_max_nodes);
384bc4097aaSchristos 				if (src->ht_max_per_node)
385bc4097aaSchristos 					PRINTF(", max-per-src %d/%d",
386bc4097aaSchristos 					       src->ht_max_per_node,
387bc4097aaSchristos 					       src->ht_netmask);
388bc4097aaSchristos 				comma = ",";
389bc4097aaSchristos 			}
390bc4097aaSchristos 			if (fp->fr_flags & FR_STSTRICT) {
391bc4097aaSchristos 				PRINTF("%sstrict", comma);
392bc4097aaSchristos 				comma = ",";
393bc4097aaSchristos 			}
394bc4097aaSchristos 			if (fp->fr_flags & FR_STLOOSE) {
395bc4097aaSchristos 				PRINTF("%sloose", comma);
396bc4097aaSchristos 				comma = ",";
397bc4097aaSchristos 			}
398bc4097aaSchristos 			if (fp->fr_flags & FR_NEWISN) {
399bc4097aaSchristos 				PRINTF("%snewisn", comma);
400bc4097aaSchristos 				comma = ",";
401bc4097aaSchristos 			}
402bc4097aaSchristos 			if (fp->fr_flags & FR_NOICMPERR) {
403bc4097aaSchristos 				PRINTF("%sno-icmp-err", comma);
404bc4097aaSchristos 				comma = ",";
405bc4097aaSchristos 			}
406bc4097aaSchristos 			if (fp->fr_flags & FR_STATESYNC) {
407bc4097aaSchristos 				PRINTF("%ssync", comma);
408bc4097aaSchristos 				comma = ",";
409bc4097aaSchristos 			}
410bc4097aaSchristos 			if (fp->fr_age[0] || fp->fr_age[1])
411bc4097aaSchristos 				PRINTF("%sage %d/%d", comma, fp->fr_age[0],
412bc4097aaSchristos 				       fp->fr_age[1]);
413bc4097aaSchristos 			PRINTF(")");
414bc4097aaSchristos 		}
415bc4097aaSchristos 	}
416bc4097aaSchristos 	if (fp->fr_flags & FR_KEEPFRAG) {
417bc4097aaSchristos 		PRINTF(" keep frags");
418bc4097aaSchristos 		if (fp->fr_flags & (FR_FRSTRICT)) {
419bc4097aaSchristos 			PRINTF(" (");
420bc4097aaSchristos 			if (fp->fr_flags & FR_FRSTRICT)
421bc4097aaSchristos 				PRINTF("strict");
422bc4097aaSchristos 			PRINTF(")");
423bc4097aaSchristos 
424bc4097aaSchristos 		}
425bc4097aaSchristos 	}
426bc4097aaSchristos 	if (fp->fr_isc != (struct ipscan *)-1) {
427bc4097aaSchristos 		if (fp->fr_isctag != -1)
428bc4097aaSchristos 			PRINTF(" scan %s", fp->fr_isctag + fp->fr_names);
429bc4097aaSchristos 		else
430bc4097aaSchristos 			PRINTF(" scan *");
431bc4097aaSchristos 	}
432bc4097aaSchristos 	if (fp->fr_grhead != -1)
433bc4097aaSchristos 		PRINTF(" head %s", fp->fr_names + fp->fr_grhead);
434bc4097aaSchristos 	if (fp->fr_group != -1)
435bc4097aaSchristos 		PRINTF(" group %s", fp->fr_names + fp->fr_group);
436bc4097aaSchristos 	if (fp->fr_logtag != FR_NOLOGTAG || *fp->fr_nattag.ipt_tag) {
437bc4097aaSchristos 		char *s = "";
438bc4097aaSchristos 
439bc4097aaSchristos 		PRINTF(" set-tag(");
440bc4097aaSchristos 		if (fp->fr_logtag != FR_NOLOGTAG) {
441bc4097aaSchristos 			PRINTF("log=%u", fp->fr_logtag);
442bc4097aaSchristos 			s = ", ";
443bc4097aaSchristos 		}
444bc4097aaSchristos 		if (*fp->fr_nattag.ipt_tag) {
445bc4097aaSchristos 			PRINTF("%snat=%-.*s", s, IPFTAG_LEN,
446bc4097aaSchristos 				fp->fr_nattag.ipt_tag);
447bc4097aaSchristos 		}
448bc4097aaSchristos 		PRINTF(")");
449bc4097aaSchristos 	}
450bc4097aaSchristos 
451bc4097aaSchristos 	if (fp->fr_pps)
452bc4097aaSchristos 		PRINTF(" pps %d", fp->fr_pps);
453bc4097aaSchristos 
454bc4097aaSchristos 	if (fp->fr_comment != -1)
455bc4097aaSchristos 		PRINTF(" comment \"%s\"", fp->fr_names + fp->fr_comment);
456bc4097aaSchristos 
457bc4097aaSchristos 	hash = 0;
458bc4097aaSchristos 	if ((fp->fr_flags & FR_KEEPSTATE) && (opts & OPT_VERBOSE)) {
459bc4097aaSchristos 		PRINTF(" # count %d", fp->fr_statecnt);
460bc4097aaSchristos 		if (fp->fr_die != 0)
461bc4097aaSchristos 			PRINTF(" rule-ttl %u", fp->fr_die);
462bc4097aaSchristos 		hash = 1;
463bc4097aaSchristos 	} else if (fp->fr_die != 0) {
464bc4097aaSchristos 		PRINTF(" # rule-ttl %u", fp->fr_die);
465bc4097aaSchristos 		hash = 1;
466bc4097aaSchristos 	}
467bc4097aaSchristos 	if (opts & OPT_DEBUG) {
468bc4097aaSchristos 		if (hash == 0)
469bc4097aaSchristos 			putchar('#');
470bc4097aaSchristos 		PRINTF(" ref %d", fp->fr_ref);
471bc4097aaSchristos 	}
472bc4097aaSchristos 	(void)putchar('\n');
473bc4097aaSchristos }
474