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