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 int use_inet6 = 0;
74 extern char thishost[MAXHOSTNAMELEN];
75
76 extern char *optarg;
77
78 void dostats __P((int, natstat_t *, int, int));
79 void flushtable __P((int, int));
80 void usage __P((char *));
81 int main __P((int, char *[]));
82 void showhostmap __P((natstat_t *nsp));
83 void natstat_dead __P((natstat_t *, char *));
84 void dostats_live __P((int, natstat_t *, int));
85 void showhostmap_live __P((int, natstat_t *));
86
87 int opts;
88
89 void
usage(char * name)90 usage(char *name)
91 {
92 fprintf(stderr, "Usage: %s [-CdFhlnrRsv] [-f filename]", name);
93 fprintf(stderr, " [-G|-z zonename]\n");
94 exit(1);
95 }
96
97
98 int
main(int argc,char * argv[])99 main(int argc, char *argv[])
100 {
101 char *file, *core, *kernel;
102 natstat_t ns, *nsp;
103 int fd, c, mode;
104 ipfobj_t obj;
105
106 fd = -1;
107 opts = 0;
108 nsp = &ns;
109 file = NULL;
110 core = NULL;
111 kernel = NULL;
112 mode = O_RDWR;
113
114 while ((c = getopt(argc, argv, "CdFf:G:hlM:N:nrRsvz:")) != -1)
115 switch (c) {
116 case 'C' :
117 opts |= OPT_CLEAR;
118 break;
119 case 'd' :
120 opts |= OPT_DEBUG;
121 break;
122 case 'f' :
123 file = optarg;
124 break;
125 case 'F' :
126 opts |= OPT_FLUSH;
127 break;
128 case 'G' :
129 setzonename_global(optarg);
130 break;
131 case 'h' :
132 opts |= OPT_HITS;
133 break;
134 case 'l' :
135 opts |= OPT_LIST;
136 mode = O_RDONLY;
137 break;
138 case 'M' :
139 core = optarg;
140 break;
141 case 'N' :
142 kernel = optarg;
143 break;
144 case 'n' :
145 opts |= OPT_DONOTHING;
146 mode = O_RDONLY;
147 break;
148 case 'R' :
149 opts |= OPT_NORESOLVE;
150 break;
151 case 'r' :
152 opts |= OPT_REMOVE;
153 break;
154 case 's' :
155 opts |= OPT_STAT;
156 mode = O_RDONLY;
157 break;
158 case 'v' :
159 opts |= OPT_VERBOSE;
160 break;
161 case 'z' :
162 setzonename(optarg);
163 break;
164 default :
165 usage(argv[0]);
166 }
167
168 initparse();
169
170 if ((kernel != NULL) || (core != NULL)) {
171 (void) setgid(getgid());
172 (void) setreuid(getuid(), getuid());
173 }
174
175 bzero((char *)&ns, sizeof (ns));
176
177 if ((opts & OPT_DONOTHING) == 0) {
178 if (checkrev(IPL_NAME) == -1) {
179 fprintf(stderr, "User/kernel version check failed\n");
180 exit(1);
181 }
182 }
183
184
185 if (!(opts & OPT_DONOTHING) && (kernel == NULL) && (core == NULL)) {
186 #ifdef notdef
187 if (openkmem(kernel, core) == -1)
188 exit(1);
189 #endif
190 if (((fd = open(IPNAT_NAME, mode)) == -1) &&
191 ((fd = open(IPNAT_NAME, O_RDONLY)) == -1)) {
192 (void) fprintf(stderr, "%s: open: %s\n", IPNAT_NAME,
193 STRERROR(errno));
194 exit(1);
195 }
196
197 if (setzone(fd) != 0) {
198 close(fd);
199 exit(1);
200 }
201
202 bzero((char *)&obj, sizeof (obj));
203 obj.ipfo_rev = IPFILTER_VERSION;
204 obj.ipfo_size = sizeof (*nsp);
205 obj.ipfo_type = IPFOBJ_NATSTAT;
206 obj.ipfo_ptr = (void *)nsp;
207 if (ioctl(fd, SIOCGNATS, &obj) == -1) {
208 perror("ioctl(SIOCGNATS)");
209 exit(1);
210 }
211 (void) setgid(getgid());
212 (void) setreuid(getuid(), getuid());
213 } else if ((kernel != NULL) || (core != NULL)) {
214 if (openkmem(kernel, core) == -1)
215 exit(1);
216
217 natstat_dead(nsp, kernel);
218 if (opts & (OPT_LIST|OPT_STAT))
219 dostats(fd, nsp, opts, 0);
220 exit(0);
221 }
222
223 if (opts & (OPT_FLUSH|OPT_CLEAR))
224 flushtable(fd, opts);
225 if (file) {
226 ipnat_parsefile(fd, ipnat_addrule, ioctl, file);
227 }
228 if (opts & (OPT_LIST|OPT_STAT))
229 dostats(fd, nsp, opts, 1);
230 return (0);
231 }
232
233
234 /*
235 * Read NAT statistic information in using a symbol table and memory file
236 * rather than doing ioctl's.
237 */
238 void
natstat_dead(natstat_t * nsp,char * kernel)239 natstat_dead(natstat_t *nsp, char *kernel)
240 {
241 struct nlist nat_nlist[10] = {
242 { "nat_table" }, /* 0 */
243 { "nat_list" },
244 { "maptable" },
245 { "ipf_nattable_sz" },
246 { "ipf_natrules_sz" },
247 { "ipf_rdrrules_sz" }, /* 5 */
248 { "ipf_hostmap_sz" },
249 { "nat_instances" },
250 { "ap_sess_list" },
251 { NULL }
252 };
253 void *tables[2];
254
255 if (nlist(kernel, nat_nlist) == -1) {
256 fprintf(stderr, "nlist error\n");
257 return;
258 }
259
260 /*
261 * Normally the ioctl copies all of these values into the structure
262 * for us, before returning it to userland, so here we must copy each
263 * one in individually.
264 */
265 kmemcpy((char *)&tables, nat_nlist[0].n_value, sizeof (tables));
266 nsp->ns_table[0] = tables[0];
267 nsp->ns_table[1] = tables[1];
268
269 kmemcpy((char *)&nsp->ns_list, nat_nlist[1].n_value,
270 sizeof (nsp->ns_list));
271 kmemcpy((char *)&nsp->ns_maptable, nat_nlist[2].n_value,
272 sizeof (nsp->ns_maptable));
273 kmemcpy((char *)&nsp->ns_nattab_sz, nat_nlist[3].n_value,
274 sizeof (nsp->ns_nattab_sz));
275 kmemcpy((char *)&nsp->ns_rultab_sz, nat_nlist[4].n_value,
276 sizeof (nsp->ns_rultab_sz));
277 kmemcpy((char *)&nsp->ns_rdrtab_sz, nat_nlist[5].n_value,
278 sizeof (nsp->ns_rdrtab_sz));
279 kmemcpy((char *)&nsp->ns_hostmap_sz, nat_nlist[6].n_value,
280 sizeof (nsp->ns_hostmap_sz));
281 kmemcpy((char *)&nsp->ns_instances, nat_nlist[7].n_value,
282 sizeof (nsp->ns_instances));
283 kmemcpy((char *)&nsp->ns_apslist, nat_nlist[8].n_value,
284 sizeof (nsp->ns_apslist));
285 }
286
287
288 /*
289 * Display NAT statistics.
290 */
291 void
dostats(int fd,natstat_t * nsp,int opts,int alive)292 dostats(int fd, natstat_t *nsp, int opts, int alive)
293 {
294 nat_t *np, nat;
295 ipnat_t ipn;
296
297 /*
298 * Show statistics ?
299 */
300 if (opts & OPT_STAT) {
301 printf("mapped\tin\t%lu\tout\t%lu\n",
302 nsp->ns_mapped[0], nsp->ns_mapped[1]);
303 printf("added\t%lu\texpired\t%lu\n",
304 nsp->ns_added, nsp->ns_expire);
305 printf("no memory\t%lu\tbad nat\t%lu\n",
306 nsp->ns_memfail, nsp->ns_badnat);
307 printf("inuse\t%lu\norphans\t%u\nrules\t%lu\n",
308 nsp->ns_inuse, nsp->ns_orphans, nsp->ns_rules);
309 printf("wilds\t%u\n", nsp->ns_wilds);
310 if (opts & OPT_VERBOSE)
311 printf("table %p list %p\n",
312 nsp->ns_table, nsp->ns_list);
313 }
314
315 /*
316 * Show list of NAT rules and NAT sessions ?
317 */
318 if (opts & OPT_LIST) {
319 if (alive) {
320 dostats_live(fd, nsp, opts);
321 return;
322 }
323 printf("List of active MAP/Redirect filters:\n");
324 while (nsp->ns_list) {
325 if (kmemcpy((char *)&ipn, (long)nsp->ns_list,
326 sizeof (ipn))) {
327 perror("kmemcpy");
328 break;
329 }
330 if (opts & OPT_HITS)
331 printf("%lu ", ipn.in_hits);
332 printnat(&ipn, opts & (OPT_DEBUG|OPT_VERBOSE));
333 nsp->ns_list = ipn.in_next;
334 }
335
336 printf("\nList of active sessions:\n");
337
338 for (np = nsp->ns_instances; np; np = nat.nat_next) {
339 if (kmemcpy((char *)&nat, (long)np, sizeof (nat)))
340 break;
341 printactivenat(&nat, opts, 0);
342 if (nat.nat_aps)
343 printaps(nat.nat_aps, opts);
344 }
345
346 if (opts & OPT_VERBOSE)
347 showhostmap(nsp);
348 }
349 }
350
351
352 /*
353 * Display the active host mapping table.
354 */
355 void
showhostmap(natstat_t * nsp)356 showhostmap(natstat_t *nsp)
357 {
358 hostmap_t hm, *hmp, **maptable;
359 uint_t hv;
360
361 printf("\nList of active host mappings:\n");
362
363 maptable = (hostmap_t **)malloc(sizeof (hostmap_t *) *
364 nsp->ns_hostmap_sz);
365 if (maptable == NULL) {
366 perror("malloc");
367 exit(1);
368 }
369 if (kmemcpy((char *)maptable, (ulong_t)nsp->ns_maptable,
370 sizeof (hostmap_t *) * nsp->ns_hostmap_sz)) {
371 perror("kmemcpy (maptable)");
372 return;
373 }
374
375 for (hv = 0; hv < nsp->ns_hostmap_sz; hv++) {
376 hmp = maptable[hv];
377
378 while (hmp) {
379 if (kmemcpy((char *)&hm, (ulong_t)hmp, sizeof (hm))) {
380 perror("kmemcpy (hostmap)");
381 return;
382 }
383
384 printhostmap(&hm, hv);
385 hmp = hm.hm_next;
386 }
387 }
388 free(maptable);
389 }
390
391
392 /*
393 * Issue an ioctl to flush either the NAT rules table or the active mapping
394 * table or both.
395 */
396 void
flushtable(int fd,int opts)397 flushtable(int fd, int opts)
398 {
399 int n = 0;
400
401 if (opts & OPT_FLUSH) {
402 n = FLUSH_TABLE_ALL;
403 if (!(opts & OPT_DONOTHING) && ioctl(fd, SIOCIPFFL, &n) == -1)
404 perror("ioctl(SIOCFLNAT)");
405 else
406 printf("%d entries flushed from NAT table\n", n);
407 }
408
409 if (opts & OPT_CLEAR) {
410 n = FLUSH_LIST;
411 if (!(opts & OPT_DONOTHING) && ioctl(fd, SIOCIPFFL, &n) == -1)
412 perror("ioctl(SIOCCNATL)");
413 else
414 printf("%d entries flushed from NAT list\n", n);
415 }
416 }
417
418 /*
419 * Display NAT statistics.
420 */
421 void
dostats_live(int fd,natstat_t * nsp,int opts)422 dostats_live(int fd, natstat_t *nsp, int opts)
423 {
424 ipfgeniter_t iter;
425 ipfobj_t obj;
426 ipnat_t ipn;
427 nat_t nat;
428
429 bzero((char *)&obj, sizeof (obj));
430 obj.ipfo_rev = IPFILTER_VERSION;
431 obj.ipfo_type = IPFOBJ_GENITER;
432 obj.ipfo_size = sizeof (iter);
433 obj.ipfo_ptr = &iter;
434
435 iter.igi_type = IPFGENITER_IPNAT;
436 iter.igi_nitems = 1;
437 iter.igi_data = &ipn;
438
439 /*
440 * Show list of NAT rules and NAT sessions ?
441 */
442 printf("List of active MAP/Redirect filters:\n");
443 while (nsp->ns_list) {
444 if (ioctl(fd, SIOCGENITER, &obj) == -1)
445 break;
446 if (opts & OPT_HITS)
447 printf("%lu ", ipn.in_hits);
448 printnat(&ipn, opts & (OPT_DEBUG|OPT_VERBOSE));
449 nsp->ns_list = ipn.in_next;
450 }
451
452 printf("\nList of active sessions:\n");
453
454 iter.igi_type = IPFGENITER_NAT;
455 iter.igi_nitems = 1;
456 iter.igi_data = &nat;
457
458 while (nsp->ns_instances != NULL) {
459 if (ioctl(fd, SIOCGENITER, &obj) == -1)
460 break;
461 printactivenat(&nat, opts, 1);
462 if (nat.nat_aps)
463 printaps(nat.nat_aps, opts);
464 nsp->ns_instances = nat.nat_next;
465 }
466
467 if (opts & OPT_VERBOSE)
468 showhostmap_live(fd, nsp);
469 }
470
471 /*
472 * Display the active host mapping table.
473 */
474 void
showhostmap_live(int fd,natstat_t * nsp)475 showhostmap_live(int fd, natstat_t *nsp)
476 {
477 hostmap_t hm, *hmp;
478 ipfgeniter_t iter;
479 ipfobj_t obj;
480
481 bzero((char *)&obj, sizeof (obj));
482 obj.ipfo_rev = IPFILTER_VERSION;
483 obj.ipfo_type = IPFOBJ_GENITER;
484 obj.ipfo_size = sizeof (iter);
485 obj.ipfo_ptr = &iter;
486
487 iter.igi_type = IPFGENITER_HOSTMAP;
488 iter.igi_nitems = 1;
489 iter.igi_data = &hm;
490
491 printf("\nList of active host mappings:\n");
492
493 while (nsp->ns_maplist != NULL) {
494 if (ioctl(fd, SIOCGENITER, &obj) == -1)
495 break;
496 printhostmap(&hm, 0);
497 nsp->ns_maplist = hm.hm_next;
498 }
499 }
500