xref: /illumos-gate/usr/src/cmd/ipf/tools/ipnat.c (revision 2e10def1)
1 /*
2  * Copyright (C) 1993-2001 by Darren Reed.
3  *
4  * See the IPFILTER.LICENCE file for details on licencing.
5  *
6  * Added redirect stuff and a variety of bug fixes. (mcn@EnGarde.com)
7  *
8  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
9  * Use is subject to license terms.
10  *
11  * Copyright (c) 2014, Joyent, Inc.  All rights reserved.
12  */
13 
14 #include <stdio.h>
15 #include <string.h>
16 #include <fcntl.h>
17 #include <errno.h>
18 #include <sys/types.h>
19 #if !defined(__SVR4) && !defined(__svr4__)
20 #include <strings.h>
21 #else
22 #include <sys/byteorder.h>
23 #endif
24 #include <sys/time.h>
25 #include <sys/param.h>
26 #include <stdlib.h>
27 #include <unistd.h>
28 #include <stddef.h>
29 #include <sys/file.h>
30 #define _KERNEL
31 #include <sys/uio.h>
32 #undef _KERNEL
33 #include <sys/socket.h>
34 #include <sys/ioctl.h>
35 #if defined(sun) && (defined(__svr4__) || defined(__SVR4))
36 # include <sys/ioccom.h>
37 # include <sys/sysmacros.h>
38 #endif
39 #include <netinet/in.h>
40 #include <netinet/in_systm.h>
41 #include <netinet/ip.h>
42 #include <netinet/tcp.h>
43 #include <net/if.h>
44 #if __FreeBSD_version >= 300000
45 # include <net/if_var.h>
46 #endif
47 #include <netdb.h>
48 #include <arpa/nameser.h>
49 #include <arpa/inet.h>
50 #include <resolv.h>
51 #include <ctype.h>
52 #if defined(linux)
53 # include <linux/a.out.h>
54 #else
55 # include <nlist.h>
56 #endif
57 #include "ipf.h"
58 #include "netinet/ipl.h"
59 #include "kmem.h"
60 #include "ipfzone.h"
61 
62 #ifdef	__hpux
63 # define	nlist	nlist64
64 #endif
65 
66 #if	defined(sun) && !SOLARIS2
67 # define	STRERROR(x)	sys_errlist[x]
68 extern	char	*sys_errlist[];
69 #else
70 # define	STRERROR(x)	strerror(x)
71 #endif
72 
73 #if !defined(lint)
74 static const char sccsid[] ="@(#)ipnat.c	1.9 6/5/96 (C) 1993 Darren Reed";
75 static const char rcsid[] = "@(#)$Id: ipnat.c,v 1.24.2.2 2005/05/10 21:19:30 darrenr Exp $";
76 #endif
77 
78 
79 #ifdef	SOLARIS
80 #define	bzero(a,b)	memset(a,0,b)
81 #endif
82 int	use_inet6 = 0;
83 char	thishost[MAXHOSTNAMELEN];
84 
85 extern	char	*optarg;
86 
87 void	dostats __P((int, natstat_t *, int, int));
88 void	flushtable __P((int, int));
89 void	usage __P((char *));
90 int	main __P((int, char*[]));
91 void	showhostmap __P((natstat_t *nsp));
92 void	natstat_dead __P((natstat_t *, char *));
93 void	dostats_live __P((int, natstat_t *, int));
94 void	showhostmap_live __P((int, natstat_t *));
95 
96 int	opts;
97 
98 void usage(name)
99 char *name;
100 {
101 	fprintf(stderr, "Usage: %s [-CdFhlnrRsv] [-f filename]", name);
102 	fprintf(stderr, " [-G|-z zonename]\n");
103 	exit(1);
104 }
105 
106 
107 int main(argc, argv)
108 int argc;
109 char *argv[];
110 {
111 	char *file, *core, *kernel;
112 	natstat_t ns, *nsp;
113 	int fd, c, mode;
114 	ipfobj_t obj;
115 
116 	fd = -1;
117 	opts = 0;
118 	nsp = &ns;
119 	file = NULL;
120 	core = NULL;
121 	kernel = NULL;
122 	mode = O_RDWR;
123 
124 	while ((c = getopt(argc, argv, "CdFf:G:hlM:N:nrRsvz:")) != -1)
125 		switch (c)
126 		{
127 		case 'C' :
128 			opts |= OPT_CLEAR;
129 			break;
130 		case 'd' :
131 			opts |= OPT_DEBUG;
132 			break;
133 		case 'f' :
134 			file = optarg;
135 			break;
136 		case 'F' :
137 			opts |= OPT_FLUSH;
138 			break;
139 		case 'G' :
140 			setzonename_global(optarg);
141 			break;
142 		case 'h' :
143 			opts |=OPT_HITS;
144 			break;
145 		case 'l' :
146 			opts |= OPT_LIST;
147 			mode = O_RDONLY;
148 			break;
149 		case 'M' :
150 			core = optarg;
151 			break;
152 		case 'N' :
153 			kernel = optarg;
154 			break;
155 		case 'n' :
156 			opts |= OPT_DONOTHING;
157 			mode = O_RDONLY;
158 			break;
159 		case 'R' :
160 			opts |= OPT_NORESOLVE;
161 			break;
162 		case 'r' :
163 			opts |= OPT_REMOVE;
164 			break;
165 		case 's' :
166 			opts |= OPT_STAT;
167 			mode = O_RDONLY;
168 			break;
169 		case 'v' :
170 			opts |= OPT_VERBOSE;
171 			break;
172 		case 'z' :
173 			setzonename(optarg);
174 			break;
175 		default :
176 			usage(argv[0]);
177 		}
178 
179 	initparse();
180 
181 	if ((kernel != NULL) || (core != NULL)) {
182 		(void) setgid(getgid());
183 		(void) setreuid(getuid(), getuid());
184 	}
185 
186 	bzero((char *)&ns, sizeof(ns));
187 
188 	if ((opts & OPT_DONOTHING) == 0) {
189 		if (checkrev(IPL_NAME) == -1) {
190 			fprintf(stderr, "User/kernel version check failed\n");
191 			exit(1);
192 		}
193 	}
194 
195 
196 	if (!(opts & OPT_DONOTHING) && (kernel == NULL) && (core == NULL)) {
197 #ifdef notdef
198 		if (openkmem(kernel, core) == -1)
199 			exit(1);
200 #endif
201 		if (((fd = open(IPNAT_NAME, mode)) == -1) &&
202 		    ((fd = open(IPNAT_NAME, O_RDONLY)) == -1)) {
203 			(void) fprintf(stderr, "%s: open: %s\n", IPNAT_NAME,
204 				STRERROR(errno));
205 			exit(1);
206 		}
207 
208 		if (setzone(fd) != 0) {
209 			close(fd);
210 			exit(1);
211 		}
212 
213 		bzero((char *)&obj, sizeof(obj));
214 		obj.ipfo_rev = IPFILTER_VERSION;
215 		obj.ipfo_size = sizeof(*nsp);
216 		obj.ipfo_type = IPFOBJ_NATSTAT;
217 		obj.ipfo_ptr = (void *)nsp;
218 		if (ioctl(fd, SIOCGNATS, &obj) == -1) {
219 			perror("ioctl(SIOCGNATS)");
220 			exit(1);
221 		}
222 		(void) setgid(getgid());
223 		(void) setreuid(getuid(), getuid());
224 	} else if ((kernel != NULL) || (core != NULL)) {
225 		if (openkmem(kernel, core) == -1)
226 			exit(1);
227 
228 		natstat_dead(nsp, kernel);
229 		if (opts & (OPT_LIST|OPT_STAT))
230 			dostats(fd, nsp, opts, 0);
231 		exit(0);
232 	}
233 
234 	if (opts & (OPT_FLUSH|OPT_CLEAR))
235 		flushtable(fd, opts);
236 	if (file) {
237 		ipnat_parsefile(fd, ipnat_addrule, ioctl, file);
238 	}
239 	if (opts & (OPT_LIST|OPT_STAT))
240 		dostats(fd, nsp, opts, 1);
241 	return 0;
242 }
243 
244 
245 /*
246  * Read NAT statistic information in using a symbol table and memory file
247  * rather than doing ioctl's.
248  */
249 void natstat_dead(nsp, kernel)
250 natstat_t *nsp;
251 char *kernel;
252 {
253 	struct nlist nat_nlist[10] = {
254 		{ "nat_table" },		/* 0 */
255 		{ "nat_list" },
256 		{ "maptable" },
257 		{ "ipf_nattable_sz" },
258 		{ "ipf_natrules_sz" },
259 		{ "ipf_rdrrules_sz" },		/* 5 */
260 		{ "ipf_hostmap_sz" },
261 		{ "nat_instances" },
262 		{ "ap_sess_list" },
263 		{ NULL }
264 	};
265 	void *tables[2];
266 
267 	if (nlist(kernel, nat_nlist) == -1) {
268 		fprintf(stderr, "nlist error\n");
269 		return;
270 	}
271 
272 	/*
273 	 * Normally the ioctl copies all of these values into the structure
274 	 * for us, before returning it to userland, so here we must copy each
275 	 * one in individually.
276 	 */
277 	kmemcpy((char *)&tables, nat_nlist[0].n_value, sizeof(tables));
278 	nsp->ns_table[0] = tables[0];
279 	nsp->ns_table[1] = tables[1];
280 
281 	kmemcpy((char *)&nsp->ns_list, nat_nlist[1].n_value,
282 		sizeof(nsp->ns_list));
283 	kmemcpy((char *)&nsp->ns_maptable, nat_nlist[2].n_value,
284 		sizeof(nsp->ns_maptable));
285 	kmemcpy((char *)&nsp->ns_nattab_sz, nat_nlist[3].n_value,
286 		sizeof(nsp->ns_nattab_sz));
287 	kmemcpy((char *)&nsp->ns_rultab_sz, nat_nlist[4].n_value,
288 		sizeof(nsp->ns_rultab_sz));
289 	kmemcpy((char *)&nsp->ns_rdrtab_sz, nat_nlist[5].n_value,
290 		sizeof(nsp->ns_rdrtab_sz));
291 	kmemcpy((char *)&nsp->ns_hostmap_sz, nat_nlist[6].n_value,
292 		sizeof(nsp->ns_hostmap_sz));
293 	kmemcpy((char *)&nsp->ns_instances, nat_nlist[7].n_value,
294 		sizeof(nsp->ns_instances));
295 	kmemcpy((char *)&nsp->ns_apslist, nat_nlist[8].n_value,
296 		sizeof(nsp->ns_apslist));
297 }
298 
299 
300 /*
301  * Display NAT statistics.
302  */
303 void dostats(fd, nsp, opts, alive)
304 natstat_t *nsp;
305 int fd, opts, alive;
306 {
307 	nat_t *np, nat;
308 	ipnat_t	ipn;
309 
310 	/*
311 	 * Show statistics ?
312 	 */
313 	if (opts & OPT_STAT) {
314 		printf("mapped\tin\t%lu\tout\t%lu\n",
315 			nsp->ns_mapped[0], nsp->ns_mapped[1]);
316 		printf("added\t%lu\texpired\t%lu\n",
317 			nsp->ns_added, nsp->ns_expire);
318 		printf("no memory\t%lu\tbad nat\t%lu\n",
319 			nsp->ns_memfail, nsp->ns_badnat);
320 		printf("inuse\t%lu\norphans\t%u\nrules\t%lu\n",
321 			nsp->ns_inuse, nsp->ns_orphans, nsp->ns_rules);
322 		printf("wilds\t%u\n", nsp->ns_wilds);
323 		if (opts & OPT_VERBOSE)
324 			printf("table %p list %p\n",
325 				nsp->ns_table, nsp->ns_list);
326 	}
327 
328 	/*
329 	 * Show list of NAT rules and NAT sessions ?
330 	 */
331 	if (opts & OPT_LIST) {
332 		if (alive) {
333 			dostats_live(fd, nsp, opts);
334 			return;
335 		}
336 		printf("List of active MAP/Redirect filters:\n");
337 		while (nsp->ns_list) {
338 			if (kmemcpy((char *)&ipn, (long)nsp->ns_list,
339 				    sizeof(ipn))) {
340 				perror("kmemcpy");
341 				break;
342 			}
343 			if (opts & OPT_HITS)
344 				printf("%lu ", ipn.in_hits);
345 			printnat(&ipn, opts & (OPT_DEBUG|OPT_VERBOSE));
346 			nsp->ns_list = ipn.in_next;
347 		}
348 
349 		printf("\nList of active sessions:\n");
350 
351 		for (np = nsp->ns_instances; np; np = nat.nat_next) {
352 			if (kmemcpy((char *)&nat, (long)np, sizeof(nat)))
353 				break;
354 			printactivenat(&nat, opts, 0);
355 			if (nat.nat_aps)
356 				printaps(nat.nat_aps, opts);
357 		}
358 
359 		if (opts & OPT_VERBOSE)
360 			showhostmap(nsp);
361 	}
362 }
363 
364 
365 /*
366  * Display the active host mapping table.
367  */
368 void showhostmap(nsp)
369 natstat_t *nsp;
370 {
371 	hostmap_t hm, *hmp, **maptable;
372 	u_int hv;
373 
374 	printf("\nList of active host mappings:\n");
375 
376 	maptable = (hostmap_t **)malloc(sizeof(hostmap_t *) *
377 					nsp->ns_hostmap_sz);
378 	if (maptable == NULL) {
379 		perror("malloc");
380 		exit(1);
381 	}
382 	if (kmemcpy((char *)maptable, (u_long)nsp->ns_maptable,
383 		    sizeof(hostmap_t *) * nsp->ns_hostmap_sz)) {
384 		perror("kmemcpy (maptable)");
385 		return;
386 	}
387 
388 	for (hv = 0; hv < nsp->ns_hostmap_sz; hv++) {
389 		hmp = maptable[hv];
390 
391 		while (hmp) {
392 			if (kmemcpy((char *)&hm, (u_long)hmp, sizeof(hm))) {
393 				perror("kmemcpy (hostmap)");
394 				return;
395 			}
396 
397 			printhostmap(&hm, hv);
398 			hmp = hm.hm_next;
399 		}
400 	}
401 	free(maptable);
402 }
403 
404 
405 /*
406  * Issue an ioctl to flush either the NAT rules table or the active mapping
407  * table or both.
408  */
409 void flushtable(fd, opts)
410 int fd, opts;
411 {
412 	int n = 0;
413 
414 	if (opts & OPT_FLUSH) {
415 		n = FLUSH_TABLE_ALL;
416 		if (!(opts & OPT_DONOTHING) && ioctl(fd, SIOCIPFFL, &n) == -1)
417 			perror("ioctl(SIOCFLNAT)");
418 		else
419 			printf("%d entries flushed from NAT table\n", n);
420 	}
421 
422 	if (opts & OPT_CLEAR) {
423 		n = FLUSH_LIST;
424 		if (!(opts & OPT_DONOTHING) && ioctl(fd, SIOCIPFFL, &n) == -1)
425 			perror("ioctl(SIOCCNATL)");
426 		else
427 			printf("%d entries flushed from NAT list\n", n);
428 	}
429 }
430 
431 /*
432  * Display NAT statistics.
433  */
434 void dostats_live(fd, nsp, opts)
435 natstat_t *nsp;
436 int fd, opts;
437 {
438 	ipfgeniter_t iter;
439 	ipfobj_t obj;
440 	ipnat_t	ipn;
441 	nat_t nat;
442 
443 	bzero((char *)&obj, sizeof(obj));
444 	obj.ipfo_rev = IPFILTER_VERSION;
445 	obj.ipfo_type = IPFOBJ_GENITER;
446 	obj.ipfo_size = sizeof(iter);
447 	obj.ipfo_ptr = &iter;
448 
449 	iter.igi_type = IPFGENITER_IPNAT;
450 	iter.igi_nitems = 1;
451 	iter.igi_data = &ipn;
452 
453 	/*
454 	 * Show list of NAT rules and NAT sessions ?
455 	 */
456 	printf("List of active MAP/Redirect filters:\n");
457 	while (nsp->ns_list) {
458 		if (ioctl(fd, SIOCGENITER, &obj) == -1)
459 			break;
460 		if (opts & OPT_HITS)
461 			printf("%lu ", ipn.in_hits);
462 		printnat(&ipn, opts & (OPT_DEBUG|OPT_VERBOSE));
463 		nsp->ns_list = ipn.in_next;
464 	}
465 
466 	printf("\nList of active sessions:\n");
467 
468 	iter.igi_type = IPFGENITER_NAT;
469 	iter.igi_nitems = 1;
470 	iter.igi_data = &nat;
471 
472 	while (nsp->ns_instances != NULL) {
473 		if (ioctl(fd, SIOCGENITER, &obj) == -1)
474 			break;
475 		printactivenat(&nat, opts, 1);
476 		if (nat.nat_aps)
477 			printaps(nat.nat_aps, opts);
478 		nsp->ns_instances = nat.nat_next;
479 	}
480 
481 	if (opts & OPT_VERBOSE)
482 		showhostmap_live(fd, nsp);
483 }
484 
485 /*
486  * Display the active host mapping table.
487  */
488 void showhostmap_live(fd, nsp)
489 int fd;
490 natstat_t *nsp;
491 {
492 	hostmap_t hm, *hmp;
493 	ipfgeniter_t iter;
494 	ipfobj_t obj;
495 
496 	bzero((char *)&obj, sizeof(obj));
497 	obj.ipfo_rev = IPFILTER_VERSION;
498 	obj.ipfo_type = IPFOBJ_GENITER;
499 	obj.ipfo_size = sizeof(iter);
500 	obj.ipfo_ptr = &iter;
501 
502 	iter.igi_type = IPFGENITER_HOSTMAP;
503 	iter.igi_nitems = 1;
504 	iter.igi_data = &hm;
505 
506 	printf("\nList of active host mappings:\n");
507 
508 	while (nsp->ns_maplist != NULL) {
509 		if (ioctl(fd, SIOCGENITER, &obj) == -1)
510 			break;
511 		printhostmap(&hm, 0);
512 		nsp->ns_maplist = hm.hm_next;
513 	}
514 }
515