xref: /freebsd/sbin/ipf/libipf/printfr.c (revision 2a63c3be158216222d89a073dcbd6a72ee4aab5a)
141edb306SCy Schubert 
241edb306SCy Schubert /*
341edb306SCy Schubert  * Copyright (C) 2012 by Darren Reed.
441edb306SCy Schubert  *
541edb306SCy Schubert  * See the IPFILTER.LICENCE file for details on licencing.
641edb306SCy Schubert  *
741edb306SCy Schubert  * $Id$
841edb306SCy Schubert  */
941edb306SCy Schubert 
1041edb306SCy Schubert #include "ipf.h"
1141edb306SCy Schubert 
1241edb306SCy Schubert 
1341edb306SCy Schubert /*
1441edb306SCy Schubert  * print the filter structure in a useful way
1541edb306SCy Schubert  */
1641edb306SCy Schubert void
printfr(struct frentry * fp,ioctlfunc_t iocfunc)17*efeb8bffSCy Schubert printfr( struct frentry *fp, ioctlfunc_t iocfunc)
1841edb306SCy Schubert {
1941edb306SCy Schubert 	struct protoent	*p;
2041edb306SCy Schubert 	u_short	sec[2];
2141edb306SCy Schubert 	u_32_t type;
2241edb306SCy Schubert 	int pr, af;
2341edb306SCy Schubert 	char *s;
2441edb306SCy Schubert 	int hash;
2541edb306SCy Schubert 
2641edb306SCy Schubert 	pr = -2;
2741edb306SCy Schubert 	type = fp->fr_type & ~FR_T_BUILTIN;
2841edb306SCy Schubert 
2941edb306SCy Schubert 	if ((fp->fr_type & FR_T_BUILTIN) != 0)
3041edb306SCy Schubert 		PRINTF("# Builtin: ");
3141edb306SCy Schubert 
3241edb306SCy Schubert 	if (fp->fr_collect != 0)
3341edb306SCy Schubert 		PRINTF("%u ", fp->fr_collect);
3441edb306SCy Schubert 
3541edb306SCy Schubert 	if (fp->fr_type == FR_T_CALLFUNC) {
3641edb306SCy Schubert 		;
3741edb306SCy Schubert 	} else if (fp->fr_func != NULL) {
3841edb306SCy Schubert 		PRINTF("call");
3941edb306SCy Schubert 		if ((fp->fr_flags & FR_CALLNOW) != 0)
4041edb306SCy Schubert 			PRINTF(" now");
4141edb306SCy Schubert 		s = kvatoname(fp->fr_func, iocfunc);
4241edb306SCy Schubert 		PRINTF(" %s/%u", s ? s : "?", fp->fr_arg);
4341edb306SCy Schubert 	} else if (FR_ISPASS(fp->fr_flags))
4441edb306SCy Schubert 		PRINTF("pass");
4541edb306SCy Schubert 	else if (FR_ISBLOCK(fp->fr_flags)) {
4641edb306SCy Schubert 		PRINTF("block");
4741edb306SCy Schubert 	} else if ((fp->fr_flags & FR_LOGMASK) == FR_LOG) {
4841edb306SCy Schubert 		printlog(fp);
4941edb306SCy Schubert 	} else if (FR_ISACCOUNT(fp->fr_flags))
5041edb306SCy Schubert 		PRINTF("count");
5141edb306SCy Schubert 	else if (FR_ISAUTH(fp->fr_flags))
5241edb306SCy Schubert 		PRINTF("auth");
5341edb306SCy Schubert 	else if (FR_ISPREAUTH(fp->fr_flags))
5441edb306SCy Schubert 		PRINTF("preauth");
5541edb306SCy Schubert 	else if (FR_ISNOMATCH(fp->fr_flags))
5641edb306SCy Schubert 		PRINTF("nomatch");
5741edb306SCy Schubert 	else if (FR_ISDECAPS(fp->fr_flags))
5841edb306SCy Schubert 		PRINTF("decapsulate");
5941edb306SCy Schubert 	else if (FR_ISSKIP(fp->fr_flags))
6041edb306SCy Schubert 		PRINTF("skip %u", fp->fr_arg);
6141edb306SCy Schubert 	else {
6241edb306SCy Schubert 		PRINTF("%x", fp->fr_flags);
6341edb306SCy Schubert 	}
6441edb306SCy Schubert 	if (fp->fr_flags & FR_RETICMP) {
6541edb306SCy Schubert 		if ((fp->fr_flags & FR_RETMASK) == FR_FAKEICMP)
6641edb306SCy Schubert 			PRINTF(" return-icmp-as-dest");
6741edb306SCy Schubert 		else if ((fp->fr_flags & FR_RETMASK) == FR_RETICMP)
6841edb306SCy Schubert 			PRINTF(" return-icmp");
6941edb306SCy Schubert 		if (fp->fr_icode) {
7041edb306SCy Schubert 			if (fp->fr_icode <= MAX_ICMPCODE)
7141edb306SCy Schubert 				PRINTF("(%s)",
7241edb306SCy Schubert 					icmpcodes[(int)fp->fr_icode]);
7341edb306SCy Schubert 			else
7441edb306SCy Schubert 				PRINTF("(%d)", fp->fr_icode);
7541edb306SCy Schubert 		}
7641edb306SCy Schubert 	} else if ((fp->fr_flags & FR_RETMASK) == FR_RETRST)
7741edb306SCy Schubert 		PRINTF(" return-rst");
7841edb306SCy Schubert 
7941edb306SCy Schubert 	if (fp->fr_flags & FR_OUTQUE)
8041edb306SCy Schubert 		PRINTF(" out ");
8141edb306SCy Schubert 	else if (fp->fr_flags & FR_INQUE)
8241edb306SCy Schubert 		PRINTF(" in ");
8341edb306SCy Schubert 
8441edb306SCy Schubert 	if (((fp->fr_flags & FR_LOGB) == FR_LOGB) ||
8541edb306SCy Schubert 	    ((fp->fr_flags & FR_LOGP) == FR_LOGP)) {
8641edb306SCy Schubert 		printlog(fp);
8741edb306SCy Schubert 		putchar(' ');
8841edb306SCy Schubert 	}
8941edb306SCy Schubert 
9041edb306SCy Schubert 	if (fp->fr_flags & FR_QUICK)
9141edb306SCy Schubert 		PRINTF("quick ");
9241edb306SCy Schubert 
9341edb306SCy Schubert 	if (fp->fr_ifnames[0] != -1) {
9441edb306SCy Schubert 		printifname("on ", fp->fr_names + fp->fr_ifnames[0],
9541edb306SCy Schubert 			    fp->fr_ifa);
9641edb306SCy Schubert 		if (fp->fr_ifnames[1] != -1 &&
9741edb306SCy Schubert 		    strcmp(fp->fr_names + fp->fr_ifnames[1], "*"))
9841edb306SCy Schubert 			printifname(",", fp->fr_names + fp->fr_ifnames[1],
9941edb306SCy Schubert 				    fp->fr_ifas[1]);
10041edb306SCy Schubert 		putchar(' ');
10141edb306SCy Schubert 	}
10241edb306SCy Schubert 
10341edb306SCy Schubert 	if (fp->fr_tif.fd_name != -1)
10441edb306SCy Schubert 		print_toif(fp->fr_family, "to", fp->fr_names, &fp->fr_tif);
10541edb306SCy Schubert 	if (fp->fr_dif.fd_name != -1)
10641edb306SCy Schubert 		print_toif(fp->fr_family, "dup-to", fp->fr_names,
10741edb306SCy Schubert 			   &fp->fr_dif);
10841edb306SCy Schubert 	if (fp->fr_rif.fd_name != -1)
10941edb306SCy Schubert 		print_toif(fp->fr_family, "reply-to", fp->fr_names,
11041edb306SCy Schubert 			   &fp->fr_rif);
11141edb306SCy Schubert 	if (fp->fr_flags & FR_FASTROUTE)
11241edb306SCy Schubert 		PRINTF("fastroute ");
11341edb306SCy Schubert 
11441edb306SCy Schubert 	if ((fp->fr_ifnames[2] != -1 &&
11541edb306SCy Schubert 	     strcmp(fp->fr_names + fp->fr_ifnames[2], "*")) ||
11641edb306SCy Schubert 	    (fp->fr_ifnames[3] != -1 &&
11741edb306SCy Schubert 		 strcmp(fp->fr_names + fp->fr_ifnames[3], "*"))) {
11841edb306SCy Schubert 		if (fp->fr_flags & FR_OUTQUE)
11941edb306SCy Schubert 			PRINTF("in-via ");
12041edb306SCy Schubert 		else
12141edb306SCy Schubert 			PRINTF("out-via ");
12241edb306SCy Schubert 
12341edb306SCy Schubert 		if (fp->fr_ifnames[2] != -1) {
12441edb306SCy Schubert 			printifname("", fp->fr_names + fp->fr_ifnames[2],
12541edb306SCy Schubert 				    fp->fr_ifas[2]);
12641edb306SCy Schubert 			if (fp->fr_ifnames[3] != -1) {
12741edb306SCy Schubert 				printifname(",",
12841edb306SCy Schubert 					    fp->fr_names + fp->fr_ifnames[3],
12941edb306SCy Schubert 					    fp->fr_ifas[3]);
13041edb306SCy Schubert 			}
13141edb306SCy Schubert 			putchar(' ');
13241edb306SCy Schubert 		}
13341edb306SCy Schubert 	}
13441edb306SCy Schubert 
13541edb306SCy Schubert 	if (fp->fr_family == AF_INET) {
13641edb306SCy Schubert 		PRINTF("inet ");
13741edb306SCy Schubert 		af = AF_INET;
13841edb306SCy Schubert #ifdef USE_INET6
13941edb306SCy Schubert 	} else if (fp->fr_family == AF_INET6) {
14041edb306SCy Schubert 		PRINTF("inet6 ");
14141edb306SCy Schubert 		af = AF_INET6;
14241edb306SCy Schubert #endif
14341edb306SCy Schubert 	} else {
14441edb306SCy Schubert 		af = -1;
14541edb306SCy Schubert 	}
14641edb306SCy Schubert 
14741edb306SCy Schubert 	if (type == FR_T_IPF) {
14841edb306SCy Schubert 		if (fp->fr_mip.fi_tos)
14941edb306SCy Schubert 			PRINTF("tos %#x ", fp->fr_tos);
15041edb306SCy Schubert 		if (fp->fr_mip.fi_ttl)
15141edb306SCy Schubert 			PRINTF("ttl %d ", fp->fr_ttl);
15241edb306SCy Schubert 		if (fp->fr_flx & FI_TCPUDP) {
15341edb306SCy Schubert 			PRINTF("proto tcp/udp ");
15441edb306SCy Schubert 			pr = -1;
15541edb306SCy Schubert 		} else if (fp->fr_mip.fi_p) {
15641edb306SCy Schubert 			pr = fp->fr_ip.fi_p;
15741edb306SCy Schubert 			p = getprotobynumber(pr);
15841edb306SCy Schubert 			PRINTF("proto ");
15941edb306SCy Schubert 			printproto(p, pr, NULL);
16041edb306SCy Schubert 			putchar(' ');
16141edb306SCy Schubert 		}
16241edb306SCy Schubert 	}
16341edb306SCy Schubert 
16441edb306SCy Schubert 	switch (type)
16541edb306SCy Schubert 	{
16641edb306SCy Schubert 	case FR_T_NONE :
16741edb306SCy Schubert 		PRINTF("all");
16841edb306SCy Schubert 		break;
16941edb306SCy Schubert 
17041edb306SCy Schubert 	case FR_T_IPF :
17141edb306SCy Schubert 		PRINTF("from %s", fp->fr_flags & FR_NOTSRCIP ? "!" : "");
17241edb306SCy Schubert 		printaddr(af, fp->fr_satype, fp->fr_names, fp->fr_ifnames[0],
17341edb306SCy Schubert 			  &fp->fr_src.s_addr, &fp->fr_smsk.s_addr);
17441edb306SCy Schubert 		if (fp->fr_scmp)
17541edb306SCy Schubert 			printportcmp(pr, &fp->fr_tuc.ftu_src);
17641edb306SCy Schubert 
17741edb306SCy Schubert 		PRINTF(" to %s", fp->fr_flags & FR_NOTDSTIP ? "!" : "");
17841edb306SCy Schubert 		printaddr(af, fp->fr_datype, fp->fr_names, fp->fr_ifnames[0],
17941edb306SCy Schubert 			  &fp->fr_dst.s_addr, &fp->fr_dmsk.s_addr);
18041edb306SCy Schubert 		if (fp->fr_dcmp)
18141edb306SCy Schubert 			printportcmp(pr, &fp->fr_tuc.ftu_dst);
18241edb306SCy Schubert 
18341edb306SCy Schubert 		if (((fp->fr_proto == IPPROTO_ICMP) ||
18441edb306SCy Schubert 		     (fp->fr_proto == IPPROTO_ICMPV6)) && fp->fr_icmpm) {
18541edb306SCy Schubert 			int	type = fp->fr_icmp, code;
18641edb306SCy Schubert 			char	*name;
18741edb306SCy Schubert 
18841edb306SCy Schubert 			type = ntohs(fp->fr_icmp);
18941edb306SCy Schubert 			code = type & 0xff;
19041edb306SCy Schubert 			type /= 256;
19141edb306SCy Schubert 			name = icmptypename(fp->fr_family, type);
19241edb306SCy Schubert 			if (name == NULL)
19341edb306SCy Schubert 				PRINTF(" icmp-type %d", type);
19441edb306SCy Schubert 			else
19541edb306SCy Schubert 				PRINTF(" icmp-type %s", name);
19641edb306SCy Schubert 			if (ntohs(fp->fr_icmpm) & 0xff)
19741edb306SCy Schubert 				PRINTF(" code %d", code);
19841edb306SCy Schubert 		}
19941edb306SCy Schubert 		if ((fp->fr_proto == IPPROTO_TCP) &&
20041edb306SCy Schubert 		    (fp->fr_tcpf || fp->fr_tcpfm)) {
20141edb306SCy Schubert 			PRINTF(" flags ");
20241edb306SCy Schubert 			printtcpflags(fp->fr_tcpf, fp->fr_tcpfm);
20341edb306SCy Schubert 		}
20441edb306SCy Schubert 		break;
20541edb306SCy Schubert 
20641edb306SCy Schubert 	case FR_T_BPFOPC :
20741edb306SCy Schubert 	    {
20841edb306SCy Schubert 		fakebpf_t *fb;
20941edb306SCy Schubert 		int i;
21041edb306SCy Schubert 
21141edb306SCy Schubert 		PRINTF("bpf-v%d { \"", fp->fr_family);
21241edb306SCy Schubert 		i = fp->fr_dsize / sizeof(*fb);
21341edb306SCy Schubert 
21441edb306SCy Schubert 		for (fb = fp->fr_data, s = ""; i; i--, fb++, s = " ")
21541edb306SCy Schubert 			PRINTF("%s%#x %#x %#x %#x", s, fb->fb_c, fb->fb_t,
21641edb306SCy Schubert 			       fb->fb_f, fb->fb_k);
21741edb306SCy Schubert 
21841edb306SCy Schubert 		PRINTF("\" }");
21941edb306SCy Schubert 		break;
22041edb306SCy Schubert 	    }
22141edb306SCy Schubert 
22241edb306SCy Schubert 	case FR_T_COMPIPF :
22341edb306SCy Schubert 		break;
22441edb306SCy Schubert 
22541edb306SCy Schubert 	case FR_T_CALLFUNC :
22641edb306SCy Schubert 		PRINTF("call function at %p", fp->fr_data);
22741edb306SCy Schubert 		break;
22841edb306SCy Schubert 
22941edb306SCy Schubert 	case FR_T_IPFEXPR :
23041edb306SCy Schubert 		PRINTF("exp { \"");
23141edb306SCy Schubert 		printipfexpr(fp->fr_data);
23241edb306SCy Schubert 		PRINTF("\" } ");
23341edb306SCy Schubert 		break;
23441edb306SCy Schubert 
23541edb306SCy Schubert 	default :
23641edb306SCy Schubert 		PRINTF("[unknown filter type %#x]", fp->fr_type);
23741edb306SCy Schubert 		break;
23841edb306SCy Schubert 	}
23941edb306SCy Schubert 
24041edb306SCy Schubert 	if ((type == FR_T_IPF) &&
24141edb306SCy Schubert 	    ((fp->fr_flx & FI_WITH) || (fp->fr_mflx & FI_WITH) ||
24241edb306SCy Schubert 	     fp->fr_optbits || fp->fr_optmask ||
24341edb306SCy Schubert 	     fp->fr_secbits || fp->fr_secmask)) {
24441edb306SCy Schubert 		char *comma = " ";
24541edb306SCy Schubert 
24641edb306SCy Schubert 		PRINTF(" with");
24741edb306SCy Schubert 		if (fp->fr_optbits || fp->fr_optmask ||
24841edb306SCy Schubert 		    fp->fr_secbits || fp->fr_secmask) {
24941edb306SCy Schubert 			sec[0] = fp->fr_secmask;
25041edb306SCy Schubert 			sec[1] = fp->fr_secbits;
25141edb306SCy Schubert 			if (fp->fr_family == AF_INET)
25241edb306SCy Schubert 				optprint(sec, fp->fr_optmask, fp->fr_optbits);
25341edb306SCy Schubert #ifdef	USE_INET6
25441edb306SCy Schubert 			else
25541edb306SCy Schubert 				optprintv6(sec, fp->fr_optmask,
25641edb306SCy Schubert 					   fp->fr_optbits);
25741edb306SCy Schubert #endif
25841edb306SCy Schubert 		} else if (fp->fr_mflx & FI_OPTIONS) {
25941edb306SCy Schubert 			fputs(comma, stdout);
26041edb306SCy Schubert 			if (!(fp->fr_flx & FI_OPTIONS))
26141edb306SCy Schubert 				PRINTF("not ");
26241edb306SCy Schubert 			PRINTF("ipopts");
26341edb306SCy Schubert 			comma = ",";
26441edb306SCy Schubert 		}
26541edb306SCy Schubert 		if (fp->fr_mflx & FI_SHORT) {
26641edb306SCy Schubert 			fputs(comma, stdout);
26741edb306SCy Schubert 			if (!(fp->fr_flx & FI_SHORT))
26841edb306SCy Schubert 				PRINTF("not ");
26941edb306SCy Schubert 			PRINTF("short");
27041edb306SCy Schubert 			comma = ",";
27141edb306SCy Schubert 		}
27241edb306SCy Schubert 		if (fp->fr_mflx & FI_FRAG) {
27341edb306SCy Schubert 			fputs(comma, stdout);
27441edb306SCy Schubert 			if (!(fp->fr_flx & FI_FRAG))
27541edb306SCy Schubert 				PRINTF("not ");
27641edb306SCy Schubert 			PRINTF("frag");
27741edb306SCy Schubert 			comma = ",";
27841edb306SCy Schubert 		}
27941edb306SCy Schubert 		if (fp->fr_mflx & FI_FRAGBODY) {
28041edb306SCy Schubert 			fputs(comma, stdout);
28141edb306SCy Schubert 			if (!(fp->fr_flx & FI_FRAGBODY))
28241edb306SCy Schubert 				PRINTF("not ");
28341edb306SCy Schubert 			PRINTF("frag-body");
28441edb306SCy Schubert 			comma = ",";
28541edb306SCy Schubert 		}
28641edb306SCy Schubert 		if (fp->fr_mflx & FI_NATED) {
28741edb306SCy Schubert 			fputs(comma, stdout);
28841edb306SCy Schubert 			if (!(fp->fr_flx & FI_NATED))
28941edb306SCy Schubert 				PRINTF("not ");
29041edb306SCy Schubert 			PRINTF("nat");
29141edb306SCy Schubert 			comma = ",";
29241edb306SCy Schubert 		}
29341edb306SCy Schubert 		if (fp->fr_mflx & FI_LOWTTL) {
29441edb306SCy Schubert 			fputs(comma, stdout);
29541edb306SCy Schubert 			if (!(fp->fr_flx & FI_LOWTTL))
29641edb306SCy Schubert 				PRINTF("not ");
29741edb306SCy Schubert 			PRINTF("lowttl");
29841edb306SCy Schubert 			comma = ",";
29941edb306SCy Schubert 		}
30041edb306SCy Schubert 		if (fp->fr_mflx & FI_BAD) {
30141edb306SCy Schubert 			fputs(comma, stdout);
30241edb306SCy Schubert 			if (!(fp->fr_flx & FI_BAD))
30341edb306SCy Schubert 				PRINTF("not ");
30441edb306SCy Schubert 			PRINTF("bad");
30541edb306SCy Schubert 			comma = ",";
30641edb306SCy Schubert 		}
30741edb306SCy Schubert 		if (fp->fr_mflx & FI_BADSRC) {
30841edb306SCy Schubert 			fputs(comma, stdout);
30941edb306SCy Schubert 			if (!(fp->fr_flx & FI_BADSRC))
31041edb306SCy Schubert 				PRINTF("not ");
31141edb306SCy Schubert 			PRINTF("bad-src");
31241edb306SCy Schubert 			comma = ",";
31341edb306SCy Schubert 		}
31441edb306SCy Schubert 		if (fp->fr_mflx & FI_BADNAT) {
31541edb306SCy Schubert 			fputs(comma, stdout);
31641edb306SCy Schubert 			if (!(fp->fr_flx & FI_BADNAT))
31741edb306SCy Schubert 				PRINTF("not ");
31841edb306SCy Schubert 			PRINTF("bad-nat");
31941edb306SCy Schubert 			comma = ",";
32041edb306SCy Schubert 		}
32141edb306SCy Schubert 		if (fp->fr_mflx & FI_OOW) {
32241edb306SCy Schubert 			fputs(comma, stdout);
32341edb306SCy Schubert 			if (!(fp->fr_flx & FI_OOW))
32441edb306SCy Schubert 				PRINTF("not ");
32541edb306SCy Schubert 			PRINTF("oow");
32641edb306SCy Schubert 			comma = ",";
32741edb306SCy Schubert 		}
32841edb306SCy Schubert 		if (fp->fr_mflx & FI_MBCAST) {
32941edb306SCy Schubert 			fputs(comma, stdout);
33041edb306SCy Schubert 			if (!(fp->fr_flx & FI_MBCAST))
33141edb306SCy Schubert 				PRINTF("not ");
33241edb306SCy Schubert 			PRINTF("mbcast");
33341edb306SCy Schubert 			comma = ",";
33441edb306SCy Schubert 		}
33541edb306SCy Schubert 		if (fp->fr_mflx & FI_BROADCAST) {
33641edb306SCy Schubert 			fputs(comma, stdout);
33741edb306SCy Schubert 			if (!(fp->fr_flx & FI_BROADCAST))
33841edb306SCy Schubert 				PRINTF("not ");
33941edb306SCy Schubert 			PRINTF("bcast");
34041edb306SCy Schubert 			comma = ",";
34141edb306SCy Schubert 		}
34241edb306SCy Schubert 		if (fp->fr_mflx & FI_MULTICAST) {
34341edb306SCy Schubert 			fputs(comma, stdout);
34441edb306SCy Schubert 			if (!(fp->fr_flx & FI_MULTICAST))
34541edb306SCy Schubert 				PRINTF("not ");
34641edb306SCy Schubert 			PRINTF("mcast");
34741edb306SCy Schubert 			comma = ",";
34841edb306SCy Schubert 		}
34941edb306SCy Schubert 		if (fp->fr_mflx & FI_STATE) {
35041edb306SCy Schubert 			fputs(comma, stdout);
35141edb306SCy Schubert 			if (!(fp->fr_flx & FI_STATE))
35241edb306SCy Schubert 				PRINTF("not ");
35341edb306SCy Schubert 			PRINTF("state");
35441edb306SCy Schubert 			comma = ",";
35541edb306SCy Schubert 		}
35641edb306SCy Schubert 		if (fp->fr_mflx & FI_V6EXTHDR) {
35741edb306SCy Schubert 			fputs(comma, stdout);
35841edb306SCy Schubert 			if (!(fp->fr_flx & FI_V6EXTHDR))
35941edb306SCy Schubert 				PRINTF("not ");
36041edb306SCy Schubert 			PRINTF("v6hdrs");
36141edb306SCy Schubert 			comma = ",";
36241edb306SCy Schubert 		}
36341edb306SCy Schubert 	}
36441edb306SCy Schubert 
36541edb306SCy Schubert 	if (fp->fr_flags & FR_KEEPSTATE) {
36641edb306SCy Schubert 		host_track_t *src = &fp->fr_srctrack;
36741edb306SCy Schubert 		PRINTF(" keep state");
36841edb306SCy Schubert 		if ((fp->fr_flags & (FR_STSTRICT|FR_NEWISN|
36941edb306SCy Schubert 				     FR_NOICMPERR|FR_STATESYNC)) ||
37041edb306SCy Schubert 		    (fp->fr_statemax != 0) || (fp->fr_age[0] != 0) ||
37141edb306SCy Schubert 		    (src->ht_max_nodes != 0)) {
37241edb306SCy Schubert 			char *comma = "";
37341edb306SCy Schubert 			PRINTF(" (");
37441edb306SCy Schubert 			if (fp->fr_statemax != 0) {
37541edb306SCy Schubert 				PRINTF("limit %u", fp->fr_statemax);
37641edb306SCy Schubert 				comma = ",";
37741edb306SCy Schubert 			}
37841edb306SCy Schubert 			if (src->ht_max_nodes != 0) {
37941edb306SCy Schubert 				PRINTF("%smax-nodes %d", comma,
38041edb306SCy Schubert 				       src->ht_max_nodes);
38141edb306SCy Schubert 				if (src->ht_max_per_node)
38241edb306SCy Schubert 					PRINTF(", max-per-src %d/%d",
38341edb306SCy Schubert 					       src->ht_max_per_node,
38441edb306SCy Schubert 					       src->ht_netmask);
38541edb306SCy Schubert 				comma = ",";
38641edb306SCy Schubert 			}
38741edb306SCy Schubert 			if (fp->fr_flags & FR_STSTRICT) {
38841edb306SCy Schubert 				PRINTF("%sstrict", comma);
38941edb306SCy Schubert 				comma = ",";
39041edb306SCy Schubert 			}
39141edb306SCy Schubert 			if (fp->fr_flags & FR_STLOOSE) {
39241edb306SCy Schubert 				PRINTF("%sloose", comma);
39341edb306SCy Schubert 				comma = ",";
39441edb306SCy Schubert 			}
39541edb306SCy Schubert 			if (fp->fr_flags & FR_NEWISN) {
39641edb306SCy Schubert 				PRINTF("%snewisn", comma);
39741edb306SCy Schubert 				comma = ",";
39841edb306SCy Schubert 			}
39941edb306SCy Schubert 			if (fp->fr_flags & FR_NOICMPERR) {
40041edb306SCy Schubert 				PRINTF("%sno-icmp-err", comma);
40141edb306SCy Schubert 				comma = ",";
40241edb306SCy Schubert 			}
40341edb306SCy Schubert 			if (fp->fr_flags & FR_STATESYNC) {
40441edb306SCy Schubert 				PRINTF("%ssync", comma);
40541edb306SCy Schubert 				comma = ",";
40641edb306SCy Schubert 			}
40741edb306SCy Schubert 			if (fp->fr_age[0] || fp->fr_age[1])
40841edb306SCy Schubert 				PRINTF("%sage %d/%d", comma, fp->fr_age[0],
40941edb306SCy Schubert 				       fp->fr_age[1]);
41041edb306SCy Schubert 			PRINTF(")");
41141edb306SCy Schubert 		}
41241edb306SCy Schubert 	}
41341edb306SCy Schubert 	if (fp->fr_flags & FR_KEEPFRAG) {
41441edb306SCy Schubert 		PRINTF(" keep frags");
41541edb306SCy Schubert 		if (fp->fr_flags & (FR_FRSTRICT)) {
41641edb306SCy Schubert 			PRINTF(" (");
41741edb306SCy Schubert 			if (fp->fr_flags & FR_FRSTRICT)
41841edb306SCy Schubert 				PRINTF("strict");
41941edb306SCy Schubert 			PRINTF(")");
42041edb306SCy Schubert 
42141edb306SCy Schubert 		}
42241edb306SCy Schubert 	}
42341edb306SCy Schubert 	if (fp->fr_isc != (struct ipscan *)-1) {
42441edb306SCy Schubert 		if (fp->fr_isctag != -1)
42541edb306SCy Schubert 			PRINTF(" scan %s", fp->fr_isctag + fp->fr_names);
42641edb306SCy Schubert 		else
42741edb306SCy Schubert 			PRINTF(" scan *");
42841edb306SCy Schubert 	}
42941edb306SCy Schubert 	if (fp->fr_grhead != -1)
43041edb306SCy Schubert 		PRINTF(" head %s", fp->fr_names + fp->fr_grhead);
43141edb306SCy Schubert 	if (fp->fr_group != -1)
43241edb306SCy Schubert 		PRINTF(" group %s", fp->fr_names + fp->fr_group);
43341edb306SCy Schubert 	if (fp->fr_logtag != FR_NOLOGTAG || *fp->fr_nattag.ipt_tag) {
43441edb306SCy Schubert 		char *s = "";
43541edb306SCy Schubert 
43641edb306SCy Schubert 		PRINTF(" set-tag(");
43741edb306SCy Schubert 		if (fp->fr_logtag != FR_NOLOGTAG) {
43841edb306SCy Schubert 			PRINTF("log=%u", fp->fr_logtag);
43941edb306SCy Schubert 			s = ", ";
44041edb306SCy Schubert 		}
44141edb306SCy Schubert 		if (*fp->fr_nattag.ipt_tag) {
44241edb306SCy Schubert 			PRINTF("%snat=%-.*s", s, IPFTAG_LEN,
44341edb306SCy Schubert 				fp->fr_nattag.ipt_tag);
44441edb306SCy Schubert 		}
44541edb306SCy Schubert 		PRINTF(")");
44641edb306SCy Schubert 	}
44741edb306SCy Schubert 
44841edb306SCy Schubert 	if (fp->fr_pps)
44941edb306SCy Schubert 		PRINTF(" pps %d", fp->fr_pps);
45041edb306SCy Schubert 
45141edb306SCy Schubert 	if (fp->fr_comment != -1)
45241edb306SCy Schubert 		PRINTF(" comment \"%s\"", fp->fr_names + fp->fr_comment);
45341edb306SCy Schubert 
45441edb306SCy Schubert 	hash = 0;
45541edb306SCy Schubert 	if ((fp->fr_flags & FR_KEEPSTATE) && (opts & OPT_VERBOSE)) {
45641edb306SCy Schubert 		PRINTF(" # count %d", fp->fr_statecnt);
45741edb306SCy Schubert 		if (fp->fr_die != 0)
45841edb306SCy Schubert 			PRINTF(" rule-ttl %u", fp->fr_die);
45941edb306SCy Schubert 		hash = 1;
46041edb306SCy Schubert 	} else if (fp->fr_die != 0) {
46141edb306SCy Schubert 		PRINTF(" # rule-ttl %u", fp->fr_die);
46241edb306SCy Schubert 		hash = 1;
46341edb306SCy Schubert 	}
46441edb306SCy Schubert 	if (opts & OPT_DEBUG) {
46541edb306SCy Schubert 		if (hash == 0)
46641edb306SCy Schubert 			putchar('#');
46741edb306SCy Schubert 		PRINTF(" ref %d", fp->fr_ref);
46841edb306SCy Schubert 	}
46941edb306SCy Schubert 	(void)putchar('\n');
47041edb306SCy Schubert }
471