4 * Copyright (C) 2001-2006 by Darren Reed.
6 * See the IPFILTER.LICENCE file for details on licencing.
8 * Added redirect stuff and a variety of bug fixes. (mcn@EnGarde.com)
14 #include <sys/types.h>
15 #if !defined(__SVR4) && !defined(__svr4__)
18 #include <sys/byteorder.h>
21 #include <sys/param.h>
29 #include <sys/socket.h>
30 #include <sys/ioctl.h>
31 #if defined(sun) && (defined(__svr4__) || defined(__SVR4))
32 # include <sys/ioccom.h>
33 # include <sys/sysmacros.h>
35 #include <netinet/in.h>
36 #include <netinet/in_systm.h>
37 #include <netinet/ip.h>
38 #include <netinet/tcp.h>
40 #if __FreeBSD_version >= 300000
41 # include <net/if_var.h>
44 #include <arpa/nameser.h>
45 #include <arpa/inet.h>
49 # include <linux/a.out.h>
54 #include "netinet/ipl.h"
58 # define nlist nlist64
61 #if defined(sun) && !SOLARIS2
62 # define STRERROR(x) sys_errlist[x]
63 extern char *sys_errlist
[];
65 # define STRERROR(x) strerror(x)
69 static const char sccsid
[] ="@(#)ipnat.c 1.9 6/5/96 (C) 1993 Darren Reed";
70 static const char rcsid
[] = "@(#)Id: ipnat.c,v 1.24.2.12 2008/11/06 21:18:20 darrenr Exp";
75 #define bzero(a,b) memset(a,0,b)
78 char thishost
[MAXHOSTNAMELEN
];
82 void dostats
__P((int, natstat_t
*, int, int));
83 void dotable
__P((natstat_t
*, int, int));
84 void flushtable
__P((int, int));
85 void usage
__P((char *));
86 int main
__P((int, char*[]));
87 void showhostmap
__P((natstat_t
*nsp
));
88 void natstat_dead
__P((natstat_t
*, char *));
89 void dostats_live
__P((int, natstat_t
*, int));
90 void showhostmap_dead
__P((natstat_t
*));
91 void showhostmap_live
__P((int, natstat_t
*));
92 void dostats_dead
__P((natstat_t
*, int));
93 void showtqtable_live
__P((int));
100 fprintf(stderr
, "Usage: %s [-CFhlnrRsv] [-f filename]\n", name
);
109 char *file
, *core
, *kernel
;
122 while ((c
= getopt(argc
, argv
, "CdFf:hlM:N:nrRsv")) != -1)
151 opts
|= OPT_DONOTHING
;
155 opts
|= OPT_NORESOLVE
;
173 if ((kernel
!= NULL
) || (core
!= NULL
)) {
174 (void) setgid(getgid());
175 (void) setuid(getuid());
178 if (!(opts
& OPT_DONOTHING
)) {
179 if (((fd
= open(IPNAT_NAME
, mode
)) == -1) &&
180 ((fd
= open(IPNAT_NAME
, O_RDONLY
)) == -1)) {
181 (void) fprintf(stderr
, "%s: open: %s\n", IPNAT_NAME
,
187 bzero((char *)&ns
, sizeof(ns
));
189 if ((opts
& OPT_DONOTHING
) == 0) {
190 if (checkrev(IPL_NAME
) == -1) {
191 fprintf(stderr
, "User/kernel version check failed\n");
196 if (!(opts
& OPT_DONOTHING
) && (kernel
== NULL
) && (core
== NULL
)) {
197 bzero((char *)&obj
, sizeof(obj
));
198 obj
.ipfo_rev
= IPFILTER_VERSION
;
199 obj
.ipfo_type
= IPFOBJ_NATSTAT
;
200 obj
.ipfo_size
= sizeof(*nsp
);
201 obj
.ipfo_ptr
= (void *)nsp
;
202 if (ioctl(fd
, SIOCGNATS
, &obj
) == -1) {
203 perror("ioctl(SIOCGNATS)");
206 (void) setgid(getgid());
207 (void) setuid(getuid());
208 } else if ((kernel
!= NULL
) || (core
!= NULL
)) {
209 if (openkmem(kernel
, core
) == -1)
212 natstat_dead(nsp
, kernel
);
213 if (opts
& (OPT_LIST
|OPT_STAT
))
214 dostats(fd
, nsp
, opts
, 0);
218 if (opts
& (OPT_FLUSH
|OPT_CLEAR
))
219 flushtable(fd
, opts
);
221 ipnat_parsefile(fd
, ipnat_addrule
, ioctl
, file
);
223 if (opts
& (OPT_LIST
|OPT_STAT
))
224 dostats(fd
, nsp
, opts
, 1);
230 * Read NAT statistic information in using a symbol table and memory file
231 * rather than doing ioctl's.
233 void natstat_dead(nsp
, kernel
)
237 struct nlist nat_nlist
[10] = {
238 { "nat_table" }, /* 0 */
241 { "ipf_nattable_sz" },
242 { "ipf_natrules_sz" },
243 { "ipf_rdrrules_sz" }, /* 5 */
244 { "ipf_hostmap_sz" },
251 if (nlist(kernel
, nat_nlist
) == -1) {
252 fprintf(stderr
, "nlist error\n");
257 * Normally the ioctl copies all of these values into the structure
258 * for us, before returning it to userland, so here we must copy each
259 * one in individually.
261 kmemcpy((char *)&tables
, nat_nlist
[0].n_value
, sizeof(tables
));
262 nsp
->ns_table
[0] = tables
[0];
263 nsp
->ns_table
[1] = tables
[1];
265 kmemcpy((char *)&nsp
->ns_list
, nat_nlist
[1].n_value
,
266 sizeof(nsp
->ns_list
));
267 kmemcpy((char *)&nsp
->ns_maptable
, nat_nlist
[2].n_value
,
268 sizeof(nsp
->ns_maptable
));
269 kmemcpy((char *)&nsp
->ns_nattab_sz
, nat_nlist
[3].n_value
,
270 sizeof(nsp
->ns_nattab_sz
));
271 kmemcpy((char *)&nsp
->ns_rultab_sz
, nat_nlist
[4].n_value
,
272 sizeof(nsp
->ns_rultab_sz
));
273 kmemcpy((char *)&nsp
->ns_rdrtab_sz
, nat_nlist
[5].n_value
,
274 sizeof(nsp
->ns_rdrtab_sz
));
275 kmemcpy((char *)&nsp
->ns_hostmap_sz
, nat_nlist
[6].n_value
,
276 sizeof(nsp
->ns_hostmap_sz
));
277 kmemcpy((char *)&nsp
->ns_instances
, nat_nlist
[7].n_value
,
278 sizeof(nsp
->ns_instances
));
279 kmemcpy((char *)&nsp
->ns_apslist
, nat_nlist
[8].n_value
,
280 sizeof(nsp
->ns_apslist
));
285 * Issue an ioctl to flush either the NAT rules table or the active mapping
288 void flushtable(fd
, opts
)
293 if (opts
& OPT_FLUSH
) {
295 if (!(opts
& OPT_DONOTHING
) && ioctl(fd
, SIOCIPFFL
, &n
) == -1)
296 perror("ioctl(SIOCFLNAT)");
298 printf("%d entries flushed from NAT table\n", n
);
301 if (opts
& OPT_CLEAR
) {
303 if (!(opts
& OPT_DONOTHING
) && ioctl(fd
, SIOCIPFFL
, &n
) == -1)
304 perror("ioctl(SIOCCNATL)");
306 printf("%d entries flushed from NAT list\n", n
);
312 * Display NAT statistics.
314 void dostats_dead(nsp
, opts
)
321 printf("List of active MAP/Redirect filters:\n");
322 while (nsp
->ns_list
) {
323 if (kmemcpy((char *)&ipn
, (long)nsp
->ns_list
,
329 printf("%lu ", ipn
.in_hits
);
330 printnat(&ipn
, opts
& (OPT_DEBUG
|OPT_VERBOSE
));
331 nsp
->ns_list
= ipn
.in_next
;
334 printf("\nList of active sessions:\n");
336 for (np
= nsp
->ns_instances
; np
; np
= nat
.nat_next
) {
337 if (kmemcpy((char *)&nat
, (long)np
, sizeof(nat
)))
339 printactivenat(&nat
, opts
, 0, nsp
->ns_ticks
);
341 printaps(nat
.nat_aps
, opts
);
344 if (opts
& OPT_VERBOSE
)
345 showhostmap_dead(nsp
);
349 void dostats(fd
, nsp
, opts
, alive
)
356 if (opts
& OPT_STAT
) {
357 printf("mapped\tin\t%lu\tout\t%lu\n",
358 nsp
->ns_mapped
[0], nsp
->ns_mapped
[1]);
359 printf("added\t%lu\texpired\t%lu\n",
360 nsp
->ns_added
, nsp
->ns_expire
);
361 printf("no memory\t%lu\tbad nat\t%lu\n",
362 nsp
->ns_memfail
, nsp
->ns_badnat
);
363 printf("inuse\t%lu\norphans\t%u\nrules\t%lu\n",
364 nsp
->ns_inuse
, nsp
->ns_orphans
, nsp
->ns_rules
);
365 printf("in-uncreates succeed\t%lu\tfailed\t%lu\n",
366 nsp
->ns_uncreate
[0][0], nsp
->ns_uncreate
[0][1]);
367 printf("out-uncreates succeed\t%lu\tfailed\t%lu\n",
368 nsp
->ns_uncreate
[1][0], nsp
->ns_uncreate
[1][1]);
369 printf("wilds\t%u\n", nsp
->ns_wilds
);
370 dotable(nsp
, fd
, alive
);
371 if (opts
& OPT_VERBOSE
)
372 printf("table %p list %p\n",
373 nsp
->ns_table
, nsp
->ns_list
);
375 showtqtable_live(fd
);
378 if (opts
& OPT_LIST
) {
380 dostats_live(fd
, nsp
, opts
);
382 dostats_dead(nsp
, opts
);
387 void dotable(nsp
, fd
, alive
)
391 int sz
, i
, used
, totallen
, maxlen
, minlen
;
396 sz
= sizeof(*buckets
) * nsp
->ns_nattab_sz
;
397 buckets
= (u_long
*)malloc(sz
);
399 obj
.ipfo_rev
= IPFILTER_VERSION
;
400 obj
.ipfo_type
= IPFOBJ_GTABLE
;
401 obj
.ipfo_size
= sizeof(table
);
402 obj
.ipfo_ptr
= &table
;
404 table
.ita_type
= IPFTABLE_BUCKETS_NATIN
;
405 table
.ita_table
= buckets
;
408 if (ioctl(fd
, SIOCGTABL
, &obj
) != 0) {
413 if (kmemcpy((char *)buckets
, (u_long
)nsp
->ns_nattab_sz
, sz
)) {
421 minlen
= nsp
->ns_inuse
;
424 for (i
= 0; i
< nsp
->ns_nattab_sz
; i
++) {
425 if (buckets
[i
] > maxlen
)
427 if (buckets
[i
] < minlen
)
431 totallen
+= buckets
[i
];
434 printf("hash efficiency\t%2.2f%%\n",
435 totallen
? ((float)used
/ totallen
) * 100.0 : 0.0);
436 printf("bucket usage\t%2.2f%%\n",
437 ((float)used
/ nsp
->ns_nattab_sz
) * 100.0);
438 printf("minimal length\t%d\n", minlen
);
439 printf("maximal length\t%d\n", maxlen
);
440 printf("average length\t%.3f\n", used
? (float)totallen
/ used
: 0.0);
445 * Display NAT statistics.
447 void dostats_live(fd
, nsp
, opts
)
456 bzero((char *)&obj
, sizeof(obj
));
457 obj
.ipfo_rev
= IPFILTER_VERSION
;
458 obj
.ipfo_type
= IPFOBJ_GENITER
;
459 obj
.ipfo_size
= sizeof(iter
);
460 obj
.ipfo_ptr
= &iter
;
462 iter
.igi_type
= IPFGENITER_IPNAT
;
464 iter
.igi_data
= &ipn
;
467 * Show list of NAT rules and NAT sessions ?
469 printf("List of active MAP/Redirect filters:\n");
470 while (nsp
->ns_list
) {
471 if (ioctl(fd
, SIOCGENITER
, &obj
) == -1)
474 printf("%lu ", ipn
.in_hits
);
475 printnat(&ipn
, opts
& (OPT_DEBUG
|OPT_VERBOSE
));
476 nsp
->ns_list
= ipn
.in_next
;
479 printf("\nList of active sessions:\n");
481 iter
.igi_type
= IPFGENITER_NAT
;
483 iter
.igi_data
= &nat
;
485 while (nsp
->ns_instances
!= NULL
) {
486 if (ioctl(fd
, SIOCGENITER
, &obj
) == -1)
488 printactivenat(&nat
, opts
, 1, nsp
->ns_ticks
);
490 printaps(nat
.nat_aps
, opts
);
491 nsp
->ns_instances
= nat
.nat_next
;
494 if (opts
& OPT_VERBOSE
)
495 showhostmap_live(fd
, nsp
);
500 * Display the active host mapping table.
502 void showhostmap_dead(nsp
)
505 hostmap_t hm
, *hmp
, **maptable
;
508 printf("\nList of active host mappings:\n");
510 maptable
= (hostmap_t
**)malloc(sizeof(hostmap_t
*) *
512 if (kmemcpy((char *)maptable
, (u_long
)nsp
->ns_maptable
,
513 sizeof(hostmap_t
*) * nsp
->ns_hostmap_sz
)) {
514 perror("kmemcpy (maptable)");
518 for (hv
= 0; hv
< nsp
->ns_hostmap_sz
; hv
++) {
522 if (kmemcpy((char *)&hm
, (u_long
)hmp
, sizeof(hm
))) {
523 perror("kmemcpy (hostmap)");
527 printhostmap(&hm
, hv
);
536 * Display the active host mapping table.
538 void showhostmap_live(fd
, nsp
)
546 bzero((char *)&obj
, sizeof(obj
));
547 obj
.ipfo_rev
= IPFILTER_VERSION
;
548 obj
.ipfo_type
= IPFOBJ_GENITER
;
549 obj
.ipfo_size
= sizeof(iter
);
550 obj
.ipfo_ptr
= &iter
;
552 iter
.igi_type
= IPFGENITER_HOSTMAP
;
556 printf("\nList of active host mappings:\n");
558 while (nsp
->ns_maplist
!= NULL
) {
559 if (ioctl(fd
, SIOCGENITER
, &obj
) == -1)
561 printhostmap(&hm
, 0);
562 nsp
->ns_maplist
= hm
.hm_next
;
567 void showtqtable_live(fd
)
570 ipftq_t table
[IPF_TCP_NSTATES
];
573 bzero((char *)&obj
, sizeof(obj
));
574 obj
.ipfo_rev
= IPFILTER_VERSION
;
575 obj
.ipfo_size
= sizeof(table
);
576 obj
.ipfo_ptr
= (void *)table
;
577 obj
.ipfo_type
= IPFOBJ_STATETQTAB
;
579 if (ioctl(fd
, SIOCGTQTAB
, &obj
) == 0) {