xref: /freebsd/sbin/ipf/libipf/printnat.c (revision 1db64f89363c97858961c4df0b7d02f3223723cf)
1 
2 /*
3  * Copyright (C) 2012 by Darren Reed.
4  *
5  * See the IPFILTER.LICENCE file for details on licencing.
6  *
7  * Added redirect stuff and a variety of bug fixes. (mcn@EnGarde.com)
8  */
9 
10 #include "ipf.h"
11 #include "kmem.h"
12 
13 
14 
15 
16 /*
17  * Print out a NAT rule
18  */
19 void
20 printnat(ipnat_t *np, int opts)
21 {
22 	struct protoent *pr;
23 	char *base;
24 	int family;
25 	int proto;
26 
27 	if (np->in_v[0] == 4)
28 		family = AF_INET;
29 #ifdef USE_INET6
30 	else if (np->in_v[0] == 6)
31 		family = AF_INET6;
32 #endif
33 	else
34 		family = AF_UNSPEC;
35 
36 	if (np->in_flags & IPN_NO)
37 		PRINTF("no ");
38 
39 	switch (np->in_redir)
40 	{
41 	case NAT_REDIRECT|NAT_ENCAP :
42 		PRINTF("encap in on");
43 		proto = np->in_pr[0];
44 		break;
45 	case NAT_MAP|NAT_ENCAP :
46 		PRINTF("encap out on");
47 		proto = np->in_pr[1];
48 		break;
49 	case NAT_REDIRECT|NAT_DIVERTUDP :
50 		PRINTF("divert in on");
51 		proto = np->in_pr[0];
52 		break;
53 	case NAT_MAP|NAT_DIVERTUDP :
54 		PRINTF("divert out on");
55 		proto = np->in_pr[1];
56 		break;
57 	case NAT_REDIRECT|NAT_REWRITE :
58 		PRINTF("rewrite in on");
59 		proto = np->in_pr[0];
60 		break;
61 	case NAT_MAP|NAT_REWRITE :
62 		PRINTF("rewrite out on");
63 		proto = np->in_pr[1];
64 		break;
65 	case NAT_REDIRECT :
66 		PRINTF("rdr");
67 		proto = np->in_pr[0];
68 		break;
69 	case NAT_MAP :
70 		PRINTF("map");
71 		proto = np->in_pr[1];
72 		break;
73 	case NAT_MAPBLK :
74 		PRINTF("map-block");
75 		proto = np->in_pr[1];
76 		break;
77 	case NAT_BIMAP :
78 		PRINTF("bimap");
79 		proto = np->in_pr[0];
80 		break;
81 	default :
82 		FPRINTF(stderr, "unknown value for in_redir: %#x\n",
83 			np->in_redir);
84 		proto = np->in_pr[0];
85 		break;
86 	}
87 
88 	pr = getprotobynumber(proto);
89 
90 	base = np->in_names;
91 	if (!strcmp(base + np->in_ifnames[0], "-"))
92 		PRINTF(" \"%s\"", base + np->in_ifnames[0]);
93 	else
94 		PRINTF(" %s", base + np->in_ifnames[0]);
95 	if ((np->in_ifnames[1] != -1) &&
96 	    (strcmp(base + np->in_ifnames[0], base + np->in_ifnames[1]) != 0)) {
97 		if (!strcmp(base + np->in_ifnames[1], "-"))
98 			PRINTF(",\"%s\"", base + np->in_ifnames[1]);
99 		else
100 			PRINTF(",%s", base + np->in_ifnames[1]);
101 	}
102 	putchar(' ');
103 
104 	if (family == AF_INET6)
105 		PRINTF("inet6 ");
106 
107 	if (np->in_redir & (NAT_REWRITE|NAT_ENCAP|NAT_DIVERTUDP)) {
108 		if ((proto != 0) || (np->in_flags & IPN_TCPUDP)) {
109 			PRINTF("proto ");
110 			printproto(pr, proto, np);
111 			putchar(' ');
112 		}
113 	}
114 
115 	if (np->in_flags & IPN_FILTER) {
116 		if (np->in_flags & IPN_NOTSRC)
117 			PRINTF("! ");
118 		PRINTF("from ");
119 		printnataddr(np->in_v[0], np->in_names, &np->in_osrc,
120 			     np->in_ifnames[0]);
121 		if (np->in_scmp)
122 			printportcmp(proto, &np->in_tuc.ftu_src);
123 
124 		if (np->in_flags & IPN_NOTDST)
125 			PRINTF(" !");
126 		PRINTF(" to ");
127 		printnataddr(np->in_v[0], np->in_names, &np->in_odst,
128 			     np->in_ifnames[0]);
129 		if (np->in_dcmp)
130 			printportcmp(proto, &np->in_tuc.ftu_dst);
131 	}
132 
133 	if (np->in_redir & (NAT_ENCAP|NAT_DIVERTUDP)) {
134 		PRINTF(" -> src ");
135 		printnataddr(np->in_v[1], np->in_names, &np->in_nsrc,
136 			     np->in_ifnames[0]);
137 		if ((np->in_redir & NAT_DIVERTUDP) != 0)
138 			PRINTF(",%u", np->in_spmin);
139 		PRINTF(" dst ");
140 		printnataddr(np->in_v[1], np->in_names, &np->in_ndst,
141 			     np->in_ifnames[0]);
142 		if ((np->in_redir & NAT_DIVERTUDP) != 0)
143 			PRINTF(",%u udp", np->in_dpmin);
144 		if ((np->in_flags & IPN_PURGE) != 0)
145 			PRINTF(" purge");
146 		PRINTF(";\n");
147 
148 	} else if (np->in_redir & NAT_REWRITE) {
149 		PRINTF(" -> src ");
150 		if (np->in_nsrc.na_atype == FRI_LOOKUP &&
151 		    np->in_nsrc.na_type == IPLT_DSTLIST) {
152 			PRINTF("dstlist/");
153 			if (np->in_nsrc.na_subtype == 0)
154 				PRINTF("%d", np->in_nsrc.na_num);
155 			else
156 				PRINTF("%s", base + np->in_nsrc.na_num);
157 		} else {
158 			printnataddr(np->in_v[1], np->in_names, &np->in_nsrc,
159 				     np->in_ifnames[0]);
160 		}
161 		if ((((np->in_flags & IPN_TCPUDP) != 0)) &&
162 		    (np->in_spmin != 0)) {
163 			if ((np->in_flags & IPN_FIXEDSPORT) != 0) {
164 				PRINTF(",port = %u", np->in_spmin);
165 			} else {
166 				PRINTF(",%u", np->in_spmin);
167 				if (np->in_spmax != np->in_spmin)
168 					PRINTF("-%u", np->in_spmax);
169 			}
170 		}
171 		PRINTF(" dst ");
172 		if (np->in_ndst.na_atype == FRI_LOOKUP &&
173 		    np->in_ndst.na_type == IPLT_DSTLIST) {
174 			PRINTF("dstlist/");
175 			if (np->in_ndst.na_subtype == 0)
176 				PRINTF("%d", np->in_nsrc.na_num);
177 			else
178 				PRINTF("%s", base + np->in_ndst.na_num);
179 		} else {
180 			printnataddr(np->in_v[1], np->in_names, &np->in_ndst,
181 				     np->in_ifnames[0]);
182 		}
183 		if ((((np->in_flags & IPN_TCPUDP) != 0)) &&
184 		    (np->in_dpmin != 0)) {
185 			if ((np->in_flags & IPN_FIXEDDPORT) != 0) {
186 				PRINTF(",port = %u", np->in_dpmin);
187 			} else {
188 				PRINTF(",%u", np->in_dpmin);
189 				if (np->in_dpmax != np->in_dpmin)
190 					PRINTF("-%u", np->in_dpmax);
191 			}
192 		}
193 		if ((np->in_flags & IPN_PURGE) != 0)
194 			PRINTF(" purge");
195 		PRINTF(";\n");
196 
197 	} else if (np->in_redir == NAT_REDIRECT) {
198 		if (!(np->in_flags & IPN_FILTER)) {
199 			printnataddr(np->in_v[0], np->in_names, &np->in_odst,
200 				     np->in_ifnames[0]);
201 			if (np->in_flags & IPN_TCPUDP) {
202 				PRINTF(" port %d", np->in_odport);
203 				if (np->in_odport != np->in_dtop)
204 					PRINTF("-%d", np->in_dtop);
205 			}
206 		}
207 		if (np->in_flags & IPN_NO) {
208 			putchar(' ');
209 			printproto(pr, proto, np);
210 			PRINTF(";\n");
211 			return;
212 		}
213 		PRINTF(" -> ");
214 		printnataddr(np->in_v[1], np->in_names, &np->in_ndst,
215 			     np->in_ifnames[0]);
216 		if (np->in_flags & IPN_TCPUDP) {
217 			if ((np->in_flags & IPN_FIXEDDPORT) != 0)
218 				PRINTF(" port = %d", np->in_dpmin);
219 			else {
220 				PRINTF(" port %d", np->in_dpmin);
221 				if (np->in_dpmin != np->in_dpmax)
222 					PRINTF("-%d", np->in_dpmax);
223 			}
224 		}
225 		putchar(' ');
226 		printproto(pr, proto, np);
227 		if (np->in_flags & IPN_ROUNDR)
228 			PRINTF(" round-robin");
229 		if (np->in_flags & IPN_FRAG)
230 			PRINTF(" frag");
231 		if (np->in_age[0] != 0 || np->in_age[1] != 0) {
232 			PRINTF(" age %d/%d", np->in_age[0], np->in_age[1]);
233 		}
234 		if (np->in_flags & IPN_STICKY)
235 			PRINTF(" sticky");
236 		if (np->in_mssclamp != 0)
237 			PRINTF(" mssclamp %d", np->in_mssclamp);
238 		if (np->in_plabel != -1)
239 			PRINTF(" proxy %s", np->in_names + np->in_plabel);
240 		if (np->in_tag.ipt_tag[0] != '\0')
241 			PRINTF(" tag %-.*s", IPFTAG_LEN, np->in_tag.ipt_tag);
242 		if ((np->in_flags & IPN_PURGE) != 0)
243 			PRINTF(" purge");
244 		PRINTF("\n");
245 		if (opts & OPT_DEBUG)
246 			PRINTF("\tpmax %u\n", np->in_dpmax);
247 
248 	} else {
249 		int protoprinted = 0;
250 
251 		if (!(np->in_flags & IPN_FILTER)) {
252 			printnataddr(np->in_v[0], np->in_names, &np->in_osrc,
253 				     np->in_ifnames[0]);
254 		}
255 		if (np->in_flags & IPN_NO) {
256 			putchar(' ');
257 			printproto(pr, proto, np);
258 			PRINTF(";\n");
259 			return;
260 		}
261 		PRINTF(" -> ");
262 		if (np->in_flags & IPN_SIPRANGE) {
263 			PRINTF("range ");
264 			printnataddr(np->in_v[1], np->in_names, &np->in_nsrc,
265 				     np->in_ifnames[0]);
266 		} else {
267 			printnataddr(np->in_v[1], np->in_names, &np->in_nsrc,
268 				     np->in_ifnames[0]);
269 		}
270 		if (np->in_plabel != -1) {
271 			PRINTF(" proxy port ");
272 			if (np->in_odport != 0) {
273 				char *s;
274 
275 				s = portname(proto, np->in_odport);
276 				if (s != NULL)
277 					fputs(s, stdout);
278 				else
279 					fputs("???", stdout);
280 			}
281 			PRINTF(" %s/", np->in_names + np->in_plabel);
282 			printproto(pr, proto, NULL);
283 			protoprinted = 1;
284 		} else if (np->in_redir == NAT_MAPBLK) {
285 			if ((np->in_spmin == 0) &&
286 			    (np->in_flags & IPN_AUTOPORTMAP))
287 				PRINTF(" ports auto");
288 			else
289 				PRINTF(" ports %d", np->in_spmin);
290 			if (opts & OPT_DEBUG)
291 				PRINTF("\n\tip modulous %d", np->in_spmax);
292 
293 		} else if (np->in_spmin || np->in_spmax) {
294 			if (np->in_flags & IPN_ICMPQUERY) {
295 				PRINTF(" icmpidmap ");
296 			} else {
297 				PRINTF(" portmap ");
298 			}
299 			printproto(pr, proto, np);
300 			protoprinted = 1;
301 			if (np->in_flags & IPN_AUTOPORTMAP) {
302 				PRINTF(" auto");
303 				if (opts & OPT_DEBUG)
304 					PRINTF(" [%d:%d %d %d]",
305 					       np->in_spmin, np->in_spmax,
306 					       np->in_ippip, np->in_ppip);
307 			} else {
308 				PRINTF(" %d:%d", np->in_spmin, np->in_spmax);
309 			}
310 			if (np->in_flags & IPN_SEQUENTIAL)
311 				PRINTF(" sequential");
312 		}
313 
314 		if (np->in_flags & IPN_FRAG)
315 			PRINTF(" frag");
316 		if (np->in_age[0] != 0 || np->in_age[1] != 0) {
317 			PRINTF(" age %d/%d", np->in_age[0], np->in_age[1]);
318 		}
319 		if (np->in_mssclamp != 0)
320 			PRINTF(" mssclamp %d", np->in_mssclamp);
321 		if (np->in_tag.ipt_tag[0] != '\0')
322 			PRINTF(" tag %s", np->in_tag.ipt_tag);
323 		if (!protoprinted && (np->in_flags & IPN_TCPUDP || proto)) {
324 			putchar(' ');
325 			printproto(pr, proto, np);
326 		}
327 		if ((np->in_flags & IPN_PURGE) != 0)
328 			PRINTF(" purge");
329 		PRINTF("\n");
330 		if (opts & OPT_DEBUG) {
331 			PRINTF("\tnextip ");
332 			printip(family, &np->in_snip);
333 			PRINTF(" pnext %d\n", np->in_spnext);
334 		}
335 	}
336 
337 	if (opts & OPT_DEBUG) {
338 		PRINTF("\tspace %lu use %u hits %lu flags %#x proto %d/%d",
339 			np->in_space, np->in_use, np->in_hits,
340 			np->in_flags, np->in_pr[0], np->in_pr[1]);
341 		PRINTF(" hv %u/%u\n", np->in_hv[0], np->in_hv[1]);
342 		PRINTF("\tifp[0] %p ifp[1] %p apr %p\n",
343 			np->in_ifps[0], np->in_ifps[1], np->in_apr);
344 		PRINTF("\ttqehead %p/%p comment %p\n",
345 			np->in_tqehead[0], np->in_tqehead[1], np->in_comment);
346 	}
347 }
348