1*f38cfa5bSmrg /* $NetBSD: ipnat.c,v 1.4 2021/04/12 04:09:26 mrg Exp $ */
226945a25Schristos
326945a25Schristos /*
4c50c2f6fSdarrenr * Copyright (C) 2012 by Darren Reed.
526945a25Schristos *
626945a25Schristos * See the IPFILTER.LICENCE file for details on licencing.
726945a25Schristos *
826945a25Schristos * Added redirect stuff and a variety of bug fixes. (mcn@EnGarde.com)
926945a25Schristos */
1026945a25Schristos #include <stdio.h>
1126945a25Schristos #include <string.h>
1226945a25Schristos #include <fcntl.h>
1326945a25Schristos #include <errno.h>
1426945a25Schristos #include <sys/types.h>
1526945a25Schristos #if !defined(__SVR4) && !defined(__svr4__)
1626945a25Schristos #include <strings.h>
1726945a25Schristos #else
1826945a25Schristos #include <sys/byteorder.h>
1926945a25Schristos #endif
2026945a25Schristos #include <sys/time.h>
2126945a25Schristos #include <sys/param.h>
2226945a25Schristos #include <stdlib.h>
2326945a25Schristos #include <unistd.h>
2426945a25Schristos #include <stddef.h>
2526945a25Schristos #include <sys/file.h>
2626945a25Schristos #define _KERNEL
2726945a25Schristos #include <sys/uio.h>
2826945a25Schristos #undef _KERNEL
2926945a25Schristos #include <sys/socket.h>
3026945a25Schristos #include <sys/ioctl.h>
3126945a25Schristos #if defined(sun) && (defined(__svr4__) || defined(__SVR4))
3226945a25Schristos # include <sys/ioccom.h>
3326945a25Schristos # include <sys/sysmacros.h>
3426945a25Schristos #endif
3526945a25Schristos #include <netinet/in.h>
3626945a25Schristos #include <netinet/in_systm.h>
3726945a25Schristos #include <netinet/ip.h>
3826945a25Schristos #include <netinet/tcp.h>
3926945a25Schristos #include <net/if.h>
4026945a25Schristos #if __FreeBSD_version >= 300000
4126945a25Schristos # include <net/if_var.h>
4226945a25Schristos #endif
4326945a25Schristos #include <netdb.h>
4426945a25Schristos #include <arpa/nameser.h>
4526945a25Schristos #include <arpa/inet.h>
4626945a25Schristos #include <resolv.h>
4726945a25Schristos #include <ctype.h>
4826945a25Schristos #if defined(linux)
4926945a25Schristos # include <linux/a.out.h>
5026945a25Schristos #else
5126945a25Schristos # include <nlist.h>
5226945a25Schristos #endif
5326945a25Schristos #include "ipf.h"
5426945a25Schristos #include "netinet/ipl.h"
5526945a25Schristos #include "kmem.h"
5626945a25Schristos
5726945a25Schristos #ifdef __hpux
5826945a25Schristos # define nlist nlist64
5926945a25Schristos #endif
6026945a25Schristos
6126945a25Schristos #if defined(sun) && !SOLARIS2
6226945a25Schristos # define STRERROR(x) sys_errlist[x]
6326945a25Schristos extern char *sys_errlist[];
6426945a25Schristos #else
6526945a25Schristos # define STRERROR(x) strerror(x)
6626945a25Schristos #endif
6726945a25Schristos
6826945a25Schristos #if !defined(lint)
698ff8d226Smrg static __attribute__((__used__)) const char sccsid[] ="@(#)ipnat.c 1.9 6/5/96 (C) 1993 Darren Reed";
708ff8d226Smrg static __attribute__((__used__)) const char rcsid[] = "@(#)Id: ipnat.c,v 1.1.1.2 2012/07/22 13:44:56 darrenr Exp $";
7126945a25Schristos #endif
7226945a25Schristos
7326945a25Schristos
7426945a25Schristos #if SOLARIS
7526945a25Schristos #define bzero(a,b) memset(a,0,b)
7626945a25Schristos #endif
7726945a25Schristos int use_inet6 = 0;
7826945a25Schristos
7926945a25Schristos extern char *optarg;
8026945a25Schristos
8126945a25Schristos void dostats __P((int, natstat_t *, int, int, int *));
8226945a25Schristos void dotable __P((natstat_t *, int, int, int, char *));
8326945a25Schristos void flushtable __P((int, int, int *));
8426945a25Schristos void usage __P((char *));
8526945a25Schristos int main __P((int, char*[]));
8626945a25Schristos void showhostmap __P((natstat_t *nsp));
8726945a25Schristos void natstat_dead __P((natstat_t *, char *));
8826945a25Schristos void dostats_live __P((int, natstat_t *, int, int *));
8926945a25Schristos void showhostmap_dead __P((natstat_t *));
9026945a25Schristos void showhostmap_live __P((int, natstat_t *));
9126945a25Schristos void dostats_dead __P((natstat_t *, int, int *));
9226945a25Schristos int nat_matcharray __P((nat_t *, int *));
9326945a25Schristos
9426945a25Schristos int opts;
9526945a25Schristos int nohdrfields = 0;
9626945a25Schristos wordtab_t *nat_fields = NULL;
9726945a25Schristos
usage(name)9826945a25Schristos void usage(name)
9926945a25Schristos char *name;
10026945a25Schristos {
10126945a25Schristos fprintf(stderr, "Usage: %s [-CFhlnrRsv] [-f filename]\n", name);
10226945a25Schristos exit(1);
10326945a25Schristos }
10426945a25Schristos
10526945a25Schristos
main(argc,argv)10626945a25Schristos int main(argc, argv)
10726945a25Schristos int argc;
10826945a25Schristos char *argv[];
10926945a25Schristos {
11026945a25Schristos int fd, c, mode, *natfilter;
11126945a25Schristos char *file, *core, *kernel;
11226945a25Schristos natstat_t ns, *nsp;
11326945a25Schristos ipfobj_t obj;
11426945a25Schristos
11526945a25Schristos fd = -1;
11626945a25Schristos opts = 0;
11726945a25Schristos nsp = &ns;
11826945a25Schristos file = NULL;
11926945a25Schristos core = NULL;
12026945a25Schristos kernel = NULL;
12126945a25Schristos mode = O_RDWR;
12226945a25Schristos natfilter = NULL;
12326945a25Schristos
12426945a25Schristos assigndefined(getenv("IPNAT_PREDEFINED"));
12526945a25Schristos
126c50c2f6fSdarrenr while ((c = getopt(argc, argv, "CdFf:hlm:M:N:nO:prRsv")) != -1)
12726945a25Schristos switch (c)
12826945a25Schristos {
12926945a25Schristos case 'C' :
13026945a25Schristos opts |= OPT_CLEAR;
13126945a25Schristos break;
13226945a25Schristos case 'd' :
13326945a25Schristos opts |= OPT_DEBUG;
13426945a25Schristos break;
13526945a25Schristos case 'f' :
13626945a25Schristos file = optarg;
13726945a25Schristos break;
13826945a25Schristos case 'F' :
13926945a25Schristos opts |= OPT_FLUSH;
14026945a25Schristos break;
14126945a25Schristos case 'h' :
14226945a25Schristos opts |=OPT_HITS;
14326945a25Schristos break;
14426945a25Schristos case 'l' :
14526945a25Schristos opts |= OPT_LIST;
14626945a25Schristos mode = O_RDONLY;
14726945a25Schristos break;
14826945a25Schristos case 'm' :
14926945a25Schristos natfilter = parseipfexpr(optarg, NULL);
15026945a25Schristos break;
15126945a25Schristos case 'M' :
15226945a25Schristos core = optarg;
15326945a25Schristos break;
15426945a25Schristos case 'N' :
15526945a25Schristos kernel = optarg;
15626945a25Schristos break;
15726945a25Schristos case 'n' :
15826945a25Schristos opts |= OPT_DONOTHING|OPT_DONTOPEN;
15926945a25Schristos mode = O_RDONLY;
16026945a25Schristos break;
16126945a25Schristos case 'O' :
16226945a25Schristos nat_fields = parsefields(natfields, optarg);
16326945a25Schristos break;
164c50c2f6fSdarrenr case 'p' :
165c50c2f6fSdarrenr opts |= OPT_PURGE;
166c50c2f6fSdarrenr break;
16726945a25Schristos case 'R' :
16826945a25Schristos opts |= OPT_NORESOLVE;
16926945a25Schristos break;
17026945a25Schristos case 'r' :
17126945a25Schristos opts |= OPT_REMOVE;
17226945a25Schristos break;
17326945a25Schristos case 's' :
17426945a25Schristos opts |= OPT_STAT;
17526945a25Schristos mode = O_RDONLY;
17626945a25Schristos break;
17726945a25Schristos case 'v' :
17826945a25Schristos opts |= OPT_VERBOSE;
17926945a25Schristos break;
18026945a25Schristos default :
18126945a25Schristos usage(argv[0]);
18226945a25Schristos }
18326945a25Schristos
184c50c2f6fSdarrenr if (((opts & OPT_PURGE) != 0) && ((opts & OPT_REMOVE) == 0)) {
185c50c2f6fSdarrenr (void) fprintf(stderr, "%s: -p must be used with -r\n",
186c50c2f6fSdarrenr argv[0]);
187c50c2f6fSdarrenr exit(1);
188c50c2f6fSdarrenr }
189c50c2f6fSdarrenr
19026945a25Schristos initparse();
19126945a25Schristos
19226945a25Schristos if ((kernel != NULL) || (core != NULL)) {
19326945a25Schristos (void) setgid(getgid());
19426945a25Schristos (void) setuid(getuid());
19526945a25Schristos }
19626945a25Schristos
19726945a25Schristos if (!(opts & OPT_DONOTHING)) {
19826945a25Schristos if (((fd = open(IPNAT_NAME, mode)) == -1) &&
19926945a25Schristos ((fd = open(IPNAT_NAME, O_RDONLY)) == -1)) {
20026945a25Schristos (void) fprintf(stderr, "%s: open: %s\n", IPNAT_NAME,
20126945a25Schristos STRERROR(errno));
20226945a25Schristos exit(1);
20326945a25Schristos }
20426945a25Schristos }
20526945a25Schristos
20626945a25Schristos bzero((char *)&ns, sizeof(ns));
20726945a25Schristos
20826945a25Schristos if ((opts & OPT_DONOTHING) == 0) {
20926945a25Schristos if (checkrev(IPL_NAME) == -1) {
21026945a25Schristos fprintf(stderr, "User/kernel version check failed\n");
21126945a25Schristos exit(1);
21226945a25Schristos }
21326945a25Schristos }
21426945a25Schristos
21526945a25Schristos if (!(opts & OPT_DONOTHING) && (kernel == NULL) && (core == NULL)) {
21626945a25Schristos bzero((char *)&obj, sizeof(obj));
21726945a25Schristos obj.ipfo_rev = IPFILTER_VERSION;
21826945a25Schristos obj.ipfo_type = IPFOBJ_NATSTAT;
21926945a25Schristos obj.ipfo_size = sizeof(*nsp);
22026945a25Schristos obj.ipfo_ptr = (void *)nsp;
22126945a25Schristos if (ioctl(fd, SIOCGNATS, &obj) == -1) {
22226945a25Schristos ipferror(fd, "ioctl(SIOCGNATS)");
22326945a25Schristos exit(1);
22426945a25Schristos }
22526945a25Schristos (void) setgid(getgid());
22626945a25Schristos (void) setuid(getuid());
22726945a25Schristos } else if ((kernel != NULL) || (core != NULL)) {
22826945a25Schristos if (openkmem(kernel, core) == -1)
22926945a25Schristos exit(1);
23026945a25Schristos
23126945a25Schristos natstat_dead(nsp, kernel);
23226945a25Schristos if (opts & (OPT_LIST|OPT_STAT))
23326945a25Schristos dostats(fd, nsp, opts, 0, natfilter);
23426945a25Schristos exit(0);
23526945a25Schristos }
23626945a25Schristos
23726945a25Schristos if (opts & (OPT_FLUSH|OPT_CLEAR))
23826945a25Schristos flushtable(fd, opts, natfilter);
23926945a25Schristos if (file) {
240c50c2f6fSdarrenr return ipnat_parsefile(fd, ipnat_addrule, ioctl, file);
24126945a25Schristos }
24226945a25Schristos if (opts & (OPT_LIST|OPT_STAT))
24326945a25Schristos dostats(fd, nsp, opts, 1, natfilter);
24426945a25Schristos return 0;
24526945a25Schristos }
24626945a25Schristos
24726945a25Schristos
24826945a25Schristos /*
24926945a25Schristos * Read NAT statistic information in using a symbol table and memory file
25026945a25Schristos * rather than doing ioctl's.
25126945a25Schristos */
natstat_dead(nsp,kernel)25226945a25Schristos void natstat_dead(nsp, kernel)
25326945a25Schristos natstat_t *nsp;
25426945a25Schristos char *kernel;
25526945a25Schristos {
25626945a25Schristos struct nlist nat_nlist[10] = {
25726945a25Schristos { "nat_table" }, /* 0 */
25826945a25Schristos { "nat_list" },
25926945a25Schristos { "maptable" },
26026945a25Schristos { "ipf_nattable_sz" },
26126945a25Schristos { "ipf_natrules_sz" },
26226945a25Schristos { "ipf_rdrrules_sz" }, /* 5 */
26326945a25Schristos { "ipf_hostmap_sz" },
26426945a25Schristos { "nat_instances" },
26526945a25Schristos { NULL }
26626945a25Schristos };
26726945a25Schristos void *tables[2];
26826945a25Schristos
26926945a25Schristos if (nlist(kernel, nat_nlist) == -1) {
27026945a25Schristos fprintf(stderr, "nlist error\n");
27126945a25Schristos return;
27226945a25Schristos }
27326945a25Schristos
27426945a25Schristos /*
27526945a25Schristos * Normally the ioctl copies all of these values into the structure
27626945a25Schristos * for us, before returning it to userland, so here we must copy each
27726945a25Schristos * one in individually.
27826945a25Schristos */
27926945a25Schristos kmemcpy((char *)&tables, nat_nlist[0].n_value, sizeof(tables));
28026945a25Schristos nsp->ns_side[0].ns_table = tables[0];
28126945a25Schristos nsp->ns_side[1].ns_table = tables[1];
28226945a25Schristos
28326945a25Schristos kmemcpy((char *)&nsp->ns_list, nat_nlist[1].n_value,
28426945a25Schristos sizeof(nsp->ns_list));
28526945a25Schristos kmemcpy((char *)&nsp->ns_maptable, nat_nlist[2].n_value,
28626945a25Schristos sizeof(nsp->ns_maptable));
28726945a25Schristos kmemcpy((char *)&nsp->ns_nattab_sz, nat_nlist[3].n_value,
28826945a25Schristos sizeof(nsp->ns_nattab_sz));
28926945a25Schristos kmemcpy((char *)&nsp->ns_rultab_sz, nat_nlist[4].n_value,
29026945a25Schristos sizeof(nsp->ns_rultab_sz));
29126945a25Schristos kmemcpy((char *)&nsp->ns_rdrtab_sz, nat_nlist[5].n_value,
29226945a25Schristos sizeof(nsp->ns_rdrtab_sz));
29326945a25Schristos kmemcpy((char *)&nsp->ns_hostmap_sz, nat_nlist[6].n_value,
29426945a25Schristos sizeof(nsp->ns_hostmap_sz));
29526945a25Schristos kmemcpy((char *)&nsp->ns_instances, nat_nlist[7].n_value,
29626945a25Schristos sizeof(nsp->ns_instances));
29726945a25Schristos }
29826945a25Schristos
29926945a25Schristos
30026945a25Schristos /*
30126945a25Schristos * Issue an ioctl to flush either the NAT rules table or the active mapping
30226945a25Schristos * table or both.
30326945a25Schristos */
flushtable(fd,opts,match)30426945a25Schristos void flushtable(fd, opts, match)
30526945a25Schristos int fd, opts, *match;
30626945a25Schristos {
30726945a25Schristos int n = 0;
30826945a25Schristos
30926945a25Schristos if (opts & OPT_FLUSH) {
31026945a25Schristos n = 0;
31126945a25Schristos if (!(opts & OPT_DONOTHING)) {
31226945a25Schristos if (match != NULL) {
31326945a25Schristos ipfobj_t obj;
31426945a25Schristos
31526945a25Schristos obj.ipfo_rev = IPFILTER_VERSION;
31626945a25Schristos obj.ipfo_size = match[0] * sizeof(int);
31726945a25Schristos obj.ipfo_type = IPFOBJ_IPFEXPR;
31826945a25Schristos obj.ipfo_ptr = match;
31926945a25Schristos if (ioctl(fd, SIOCMATCHFLUSH, &obj) == -1) {
32026945a25Schristos ipferror(fd, "ioctl(SIOCMATCHFLUSH)");
32126945a25Schristos n = -1;
32226945a25Schristos } else {
32326945a25Schristos n = obj.ipfo_retval;
32426945a25Schristos }
32526945a25Schristos } else if (ioctl(fd, SIOCIPFFL, &n) == -1) {
32626945a25Schristos ipferror(fd, "ioctl(SIOCIPFFL)");
32726945a25Schristos n = -1;
32826945a25Schristos }
32926945a25Schristos }
33026945a25Schristos if (n >= 0)
33126945a25Schristos printf("%d entries flushed from NAT table\n", n);
33226945a25Schristos }
33326945a25Schristos
33426945a25Schristos if (opts & OPT_CLEAR) {
33526945a25Schristos n = 1;
33626945a25Schristos if (!(opts & OPT_DONOTHING) && ioctl(fd, SIOCIPFFL, &n) == -1)
33726945a25Schristos ipferror(fd, "ioctl(SIOCCNATL)");
33826945a25Schristos else
33926945a25Schristos printf("%d entries flushed from NAT list\n", n);
34026945a25Schristos }
34126945a25Schristos }
34226945a25Schristos
34326945a25Schristos
34426945a25Schristos /*
34526945a25Schristos * Display NAT statistics.
34626945a25Schristos */
dostats_dead(nsp,opts,filter)34726945a25Schristos void dostats_dead(nsp, opts, filter)
34826945a25Schristos natstat_t *nsp;
34926945a25Schristos int opts, *filter;
35026945a25Schristos {
35126945a25Schristos nat_t *np, nat;
35226945a25Schristos ipnat_t ipn;
35326945a25Schristos int i;
35426945a25Schristos
35526945a25Schristos if (nat_fields == NULL) {
35626945a25Schristos printf("List of active MAP/Redirect filters:\n");
35726945a25Schristos while (nsp->ns_list) {
35826945a25Schristos if (kmemcpy((char *)&ipn, (long)nsp->ns_list,
35926945a25Schristos sizeof(ipn))) {
36026945a25Schristos perror("kmemcpy");
36126945a25Schristos break;
36226945a25Schristos }
36326945a25Schristos if (opts & OPT_HITS)
36426945a25Schristos printf("%lu ", ipn.in_hits);
36526945a25Schristos printnat(&ipn, opts & (OPT_DEBUG|OPT_VERBOSE));
36626945a25Schristos nsp->ns_list = ipn.in_next;
36726945a25Schristos }
36826945a25Schristos }
36926945a25Schristos
37026945a25Schristos if (nat_fields == NULL) {
37126945a25Schristos printf("\nList of active sessions:\n");
37226945a25Schristos
37326945a25Schristos } else if (nohdrfields == 0) {
37426945a25Schristos for (i = 0; nat_fields[i].w_value != 0; i++) {
37526945a25Schristos printfieldhdr(natfields, nat_fields + i);
37626945a25Schristos if (nat_fields[i + 1].w_value != 0)
37726945a25Schristos printf("\t");
37826945a25Schristos }
37926945a25Schristos printf("\n");
38026945a25Schristos }
38126945a25Schristos
38226945a25Schristos for (np = nsp->ns_instances; np; np = nat.nat_next) {
38326945a25Schristos if (kmemcpy((char *)&nat, (long)np, sizeof(nat)))
38426945a25Schristos break;
38526945a25Schristos if ((filter != NULL) && (nat_matcharray(&nat, filter) == 0))
38626945a25Schristos continue;
38726945a25Schristos if (nat_fields != NULL) {
38826945a25Schristos for (i = 0; nat_fields[i].w_value != 0; i++) {
38926945a25Schristos printnatfield(&nat, nat_fields[i].w_value);
39026945a25Schristos if (nat_fields[i + 1].w_value != 0)
39126945a25Schristos printf("\t");
39226945a25Schristos }
39326945a25Schristos printf("\n");
39426945a25Schristos } else {
39526945a25Schristos printactivenat(&nat, opts, nsp->ns_ticks);
39626945a25Schristos if (nat.nat_aps) {
39726945a25Schristos int proto;
39826945a25Schristos
39926945a25Schristos if (nat.nat_dir & NAT_OUTBOUND)
40026945a25Schristos proto = nat.nat_pr[1];
40126945a25Schristos else
40226945a25Schristos proto = nat.nat_pr[0];
40326945a25Schristos printaps(nat.nat_aps, opts, proto);
40426945a25Schristos }
40526945a25Schristos }
40626945a25Schristos }
40726945a25Schristos
40826945a25Schristos if (opts & OPT_VERBOSE)
40926945a25Schristos showhostmap_dead(nsp);
41026945a25Schristos }
41126945a25Schristos
41226945a25Schristos
dotable(nsp,fd,alive,which,side)41326945a25Schristos void dotable(nsp, fd, alive, which, side)
41426945a25Schristos natstat_t *nsp;
41526945a25Schristos int fd, alive, which;
41626945a25Schristos char *side;
41726945a25Schristos {
41826945a25Schristos int sz, i, used, maxlen, minlen, totallen;
41926945a25Schristos ipftable_t table;
42026945a25Schristos u_int *buckets;
42126945a25Schristos ipfobj_t obj;
42226945a25Schristos
42326945a25Schristos sz = sizeof(*buckets) * nsp->ns_nattab_sz;
42426945a25Schristos buckets = (u_int *)malloc(sz);
42526945a25Schristos if (buckets == NULL) {
42626945a25Schristos fprintf(stderr,
42726945a25Schristos "cannot allocate memory (%d) for buckets\n", sz);
42826945a25Schristos return;
42926945a25Schristos }
43026945a25Schristos
43126945a25Schristos obj.ipfo_rev = IPFILTER_VERSION;
43226945a25Schristos obj.ipfo_type = IPFOBJ_GTABLE;
43326945a25Schristos obj.ipfo_size = sizeof(table);
43426945a25Schristos obj.ipfo_ptr = &table;
43526945a25Schristos
43626945a25Schristos if (which == 0) {
43726945a25Schristos table.ita_type = IPFTABLE_BUCKETS_NATIN;
43826945a25Schristos } else if (which == 1) {
43926945a25Schristos table.ita_type = IPFTABLE_BUCKETS_NATOUT;
44026945a25Schristos }
44126945a25Schristos table.ita_table = buckets;
44226945a25Schristos
44326945a25Schristos if (alive) {
44426945a25Schristos if (ioctl(fd, SIOCGTABL, &obj) != 0) {
445c50c2f6fSdarrenr ipferror(fd, "SIOCFTABL");
44626945a25Schristos free(buckets);
44726945a25Schristos return;
44826945a25Schristos }
44926945a25Schristos } else {
45026945a25Schristos if (kmemcpy((char *)buckets, (u_long)nsp->ns_nattab_sz, sz)) {
45126945a25Schristos free(buckets);
45226945a25Schristos return;
45326945a25Schristos }
45426945a25Schristos }
45526945a25Schristos
45626945a25Schristos minlen = nsp->ns_side[which].ns_inuse;
45726945a25Schristos totallen = 0;
45826945a25Schristos maxlen = 0;
45926945a25Schristos used = 0;
46026945a25Schristos
46126945a25Schristos for (i = 0; i < nsp->ns_nattab_sz; i++) {
46226945a25Schristos if (buckets[i] > maxlen)
46326945a25Schristos maxlen = buckets[i];
46426945a25Schristos if (buckets[i] < minlen)
46526945a25Schristos minlen = buckets[i];
46626945a25Schristos if (buckets[i] != 0)
46726945a25Schristos used++;
46826945a25Schristos totallen += buckets[i];
46926945a25Schristos }
47026945a25Schristos
47126945a25Schristos printf("%d%%\thash efficiency %s\n",
47226945a25Schristos totallen ? used * 100 / totallen : 0, side);
47326945a25Schristos printf("%2.2f%%\tbucket usage %s\n",
47426945a25Schristos ((float)used / nsp->ns_nattab_sz) * 100.0, side);
47526945a25Schristos printf("%d\tminimal length %s\n", minlen, side);
47626945a25Schristos printf("%d\tmaximal length %s\n", maxlen, side);
47726945a25Schristos printf("%.3f\taverage length %s\n",
47826945a25Schristos used ? ((float)totallen / used) : 0.0, side);
47926945a25Schristos
48026945a25Schristos free(buckets);
48126945a25Schristos }
48226945a25Schristos
48326945a25Schristos
dostats(fd,nsp,opts,alive,filter)48426945a25Schristos void dostats(fd, nsp, opts, alive, filter)
48526945a25Schristos natstat_t *nsp;
48626945a25Schristos int fd, opts, alive, *filter;
48726945a25Schristos {
48826945a25Schristos /*
48926945a25Schristos * Show statistics ?
49026945a25Schristos */
49126945a25Schristos if (opts & OPT_STAT) {
492c50c2f6fSdarrenr printnatside("in", &nsp->ns_side[0]);
49326945a25Schristos dotable(nsp, fd, alive, 0, "in");
49426945a25Schristos
495c50c2f6fSdarrenr printnatside("out", &nsp->ns_side[1]);
49626945a25Schristos dotable(nsp, fd, alive, 1, "out");
49726945a25Schristos
49826945a25Schristos printf("%lu\tlog successes\n", nsp->ns_side[0].ns_log);
49926945a25Schristos printf("%lu\tlog failures\n", nsp->ns_side[1].ns_log);
50026945a25Schristos printf("%lu\tadded in\n%lu\tadded out\n",
50126945a25Schristos nsp->ns_side[0].ns_added,
50226945a25Schristos nsp->ns_side[1].ns_added);
503c50c2f6fSdarrenr printf("%u\tactive\n", nsp->ns_active);
504c50c2f6fSdarrenr printf("%lu\ttransparent adds\n", nsp->ns_addtrpnt);
505c50c2f6fSdarrenr printf("%lu\tdivert build\n", nsp->ns_divert_build);
50626945a25Schristos printf("%lu\texpired\n", nsp->ns_expire);
507c50c2f6fSdarrenr printf("%lu\tflush all\n", nsp->ns_flush_all);
508c50c2f6fSdarrenr printf("%lu\tflush closing\n", nsp->ns_flush_closing);
509c50c2f6fSdarrenr printf("%lu\tflush queue\n", nsp->ns_flush_queue);
510c50c2f6fSdarrenr printf("%lu\tflush state\n", nsp->ns_flush_state);
511c50c2f6fSdarrenr printf("%lu\tflush timeout\n", nsp->ns_flush_timeout);
512c50c2f6fSdarrenr printf("%lu\thostmap new\n", nsp->ns_hm_new);
513c50c2f6fSdarrenr printf("%lu\thostmap fails\n", nsp->ns_hm_newfail);
514c50c2f6fSdarrenr printf("%lu\thostmap add\n", nsp->ns_hm_addref);
515c50c2f6fSdarrenr printf("%lu\thostmap NULL rule\n", nsp->ns_hm_nullnp);
516c50c2f6fSdarrenr printf("%lu\tlog ok\n", nsp->ns_log_ok);
517c50c2f6fSdarrenr printf("%lu\tlog fail\n", nsp->ns_log_fail);
518c50c2f6fSdarrenr printf("%u\torphan count\n", nsp->ns_orphans);
519c50c2f6fSdarrenr printf("%u\trule count\n", nsp->ns_rules);
520c50c2f6fSdarrenr printf("%u\tmap rules\n", nsp->ns_rules_map);
521c50c2f6fSdarrenr printf("%u\trdr rules\n", nsp->ns_rules_rdr);
52226945a25Schristos printf("%u\twilds\n", nsp->ns_wilds);
52326945a25Schristos if (opts & OPT_VERBOSE)
52426945a25Schristos printf("list %p\n", nsp->ns_list);
52526945a25Schristos }
52626945a25Schristos
52726945a25Schristos if (opts & OPT_LIST) {
52826945a25Schristos if (alive)
52926945a25Schristos dostats_live(fd, nsp, opts, filter);
53026945a25Schristos else
53126945a25Schristos dostats_dead(nsp, opts, filter);
53226945a25Schristos }
53326945a25Schristos }
53426945a25Schristos
53526945a25Schristos
53626945a25Schristos /*
53726945a25Schristos * Display NAT statistics.
53826945a25Schristos */
dostats_live(fd,nsp,opts,filter)53926945a25Schristos void dostats_live(fd, nsp, opts, filter)
54026945a25Schristos natstat_t *nsp;
54126945a25Schristos int fd, opts, *filter;
54226945a25Schristos {
54326945a25Schristos ipfgeniter_t iter;
54426945a25Schristos char buffer[2000];
54526945a25Schristos ipfobj_t obj;
54626945a25Schristos ipnat_t *ipn;
54726945a25Schristos nat_t nat;
54826945a25Schristos int i;
54926945a25Schristos
55026945a25Schristos bzero((char *)&obj, sizeof(obj));
55126945a25Schristos obj.ipfo_rev = IPFILTER_VERSION;
55226945a25Schristos obj.ipfo_type = IPFOBJ_GENITER;
55326945a25Schristos obj.ipfo_size = sizeof(iter);
55426945a25Schristos obj.ipfo_ptr = &iter;
55526945a25Schristos
55626945a25Schristos iter.igi_type = IPFGENITER_IPNAT;
55726945a25Schristos iter.igi_nitems = 1;
55826945a25Schristos iter.igi_data = buffer;
55926945a25Schristos ipn = (ipnat_t *)buffer;
56026945a25Schristos
56126945a25Schristos /*
56226945a25Schristos * Show list of NAT rules and NAT sessions ?
56326945a25Schristos */
56426945a25Schristos if (nat_fields == NULL) {
56526945a25Schristos printf("List of active MAP/Redirect filters:\n");
56626945a25Schristos while (nsp->ns_list) {
56726945a25Schristos if (ioctl(fd, SIOCGENITER, &obj) == -1)
56826945a25Schristos break;
56926945a25Schristos if (opts & OPT_HITS)
57026945a25Schristos printf("%lu ", ipn->in_hits);
57126945a25Schristos printnat(ipn, opts & (OPT_DEBUG|OPT_VERBOSE));
57226945a25Schristos nsp->ns_list = ipn->in_next;
57326945a25Schristos }
57426945a25Schristos }
57526945a25Schristos
57626945a25Schristos if (nat_fields == NULL) {
57726945a25Schristos printf("\nList of active sessions:\n");
57826945a25Schristos
57926945a25Schristos } else if (nohdrfields == 0) {
58026945a25Schristos for (i = 0; nat_fields[i].w_value != 0; i++) {
58126945a25Schristos printfieldhdr(natfields, nat_fields + i);
58226945a25Schristos if (nat_fields[i + 1].w_value != 0)
58326945a25Schristos printf("\t");
58426945a25Schristos }
58526945a25Schristos printf("\n");
58626945a25Schristos }
58726945a25Schristos
58826945a25Schristos i = IPFGENITER_IPNAT;
58926945a25Schristos (void) ioctl(fd,SIOCIPFDELTOK, &i);
59026945a25Schristos
59126945a25Schristos
59226945a25Schristos iter.igi_type = IPFGENITER_NAT;
59326945a25Schristos iter.igi_nitems = 1;
59426945a25Schristos iter.igi_data = &nat;
59526945a25Schristos
59626945a25Schristos while (nsp->ns_instances != NULL) {
59726945a25Schristos if (ioctl(fd, SIOCGENITER, &obj) == -1)
59826945a25Schristos break;
59926945a25Schristos if ((filter != NULL) && (nat_matcharray(&nat, filter) == 0))
60026945a25Schristos continue;
60126945a25Schristos if (nat_fields != NULL) {
60226945a25Schristos for (i = 0; nat_fields[i].w_value != 0; i++) {
60326945a25Schristos printnatfield(&nat, nat_fields[i].w_value);
60426945a25Schristos if (nat_fields[i + 1].w_value != 0)
60526945a25Schristos printf("\t");
60626945a25Schristos }
60726945a25Schristos printf("\n");
60826945a25Schristos } else {
60926945a25Schristos printactivenat(&nat, opts, nsp->ns_ticks);
61026945a25Schristos if (nat.nat_aps) {
61126945a25Schristos int proto;
61226945a25Schristos
61326945a25Schristos if (nat.nat_dir & NAT_OUTBOUND)
61426945a25Schristos proto = nat.nat_pr[1];
61526945a25Schristos else
61626945a25Schristos proto = nat.nat_pr[0];
61726945a25Schristos printaps(nat.nat_aps, opts, proto);
61826945a25Schristos }
61926945a25Schristos }
62026945a25Schristos nsp->ns_instances = nat.nat_next;
62126945a25Schristos }
62226945a25Schristos
62326945a25Schristos if (opts & OPT_VERBOSE)
62426945a25Schristos showhostmap_live(fd, nsp);
62526945a25Schristos
62626945a25Schristos i = IPFGENITER_NAT;
62726945a25Schristos (void) ioctl(fd,SIOCIPFDELTOK, &i);
62826945a25Schristos }
62926945a25Schristos
63026945a25Schristos
63126945a25Schristos /*
63226945a25Schristos * Display the active host mapping table.
63326945a25Schristos */
showhostmap_dead(nsp)63426945a25Schristos void showhostmap_dead(nsp)
63526945a25Schristos natstat_t *nsp;
63626945a25Schristos {
63726945a25Schristos hostmap_t hm, *hmp, **maptable;
63826945a25Schristos u_int hv;
63926945a25Schristos
64026945a25Schristos printf("\nList of active host mappings:\n");
64126945a25Schristos
64226945a25Schristos maptable = (hostmap_t **)malloc(sizeof(hostmap_t *) *
64326945a25Schristos nsp->ns_hostmap_sz);
64426945a25Schristos if (kmemcpy((char *)maptable, (u_long)nsp->ns_maptable,
64526945a25Schristos sizeof(hostmap_t *) * nsp->ns_hostmap_sz)) {
64626945a25Schristos perror("kmemcpy (maptable)");
64726945a25Schristos return;
64826945a25Schristos }
64926945a25Schristos
65026945a25Schristos for (hv = 0; hv < nsp->ns_hostmap_sz; hv++) {
65126945a25Schristos hmp = maptable[hv];
65226945a25Schristos
65326945a25Schristos while (hmp) {
65426945a25Schristos if (kmemcpy((char *)&hm, (u_long)hmp, sizeof(hm))) {
65526945a25Schristos perror("kmemcpy (hostmap)");
65626945a25Schristos return;
65726945a25Schristos }
65826945a25Schristos
65926945a25Schristos printhostmap(&hm, hv);
66026945a25Schristos hmp = hm.hm_next;
66126945a25Schristos }
66226945a25Schristos }
66326945a25Schristos free(maptable);
66426945a25Schristos }
66526945a25Schristos
66626945a25Schristos
66726945a25Schristos /*
66826945a25Schristos * Display the active host mapping table.
66926945a25Schristos */
showhostmap_live(fd,nsp)67026945a25Schristos void showhostmap_live(fd, nsp)
67126945a25Schristos int fd;
67226945a25Schristos natstat_t *nsp;
67326945a25Schristos {
67426945a25Schristos ipfgeniter_t iter;
67526945a25Schristos hostmap_t hm;
67626945a25Schristos ipfobj_t obj;
67726945a25Schristos int i;
67826945a25Schristos
67926945a25Schristos bzero((char *)&obj, sizeof(obj));
68026945a25Schristos obj.ipfo_rev = IPFILTER_VERSION;
68126945a25Schristos obj.ipfo_type = IPFOBJ_GENITER;
68226945a25Schristos obj.ipfo_size = sizeof(iter);
68326945a25Schristos obj.ipfo_ptr = &iter;
68426945a25Schristos
68526945a25Schristos iter.igi_type = IPFGENITER_HOSTMAP;
68626945a25Schristos iter.igi_nitems = 1;
68726945a25Schristos iter.igi_data = &hm;
68826945a25Schristos
68926945a25Schristos printf("\nList of active host mappings:\n");
69026945a25Schristos
69126945a25Schristos while (nsp->ns_maplist != NULL) {
69226945a25Schristos if (ioctl(fd, SIOCGENITER, &obj) == -1)
69326945a25Schristos break;
69426945a25Schristos printhostmap(&hm, hm.hm_hv);
69526945a25Schristos nsp->ns_maplist = hm.hm_next;
69626945a25Schristos }
69726945a25Schristos
69826945a25Schristos i = IPFGENITER_HOSTMAP;
69926945a25Schristos (void) ioctl(fd,SIOCIPFDELTOK, &i);
70026945a25Schristos }
70126945a25Schristos
70226945a25Schristos
nat_matcharray(nat,array)70326945a25Schristos int nat_matcharray(nat, array)
70426945a25Schristos nat_t *nat;
70526945a25Schristos int *array;
70626945a25Schristos {
707c50c2f6fSdarrenr int i, n, *x, rv, p;
708c50c2f6fSdarrenr ipfexp_t *e;
70926945a25Schristos
710c50c2f6fSdarrenr rv = 0;
71126945a25Schristos n = array[0];
71226945a25Schristos x = array + 1;
71326945a25Schristos
714c50c2f6fSdarrenr for (; n > 0; x += 3 + x[3], rv = 0) {
715c50c2f6fSdarrenr e = (ipfexp_t *)x;
716c50c2f6fSdarrenr if (e->ipfe_cmd == IPF_EXP_END)
71726945a25Schristos break;
718c50c2f6fSdarrenr n -= e->ipfe_size;
71926945a25Schristos
720c50c2f6fSdarrenr p = e->ipfe_cmd >> 16;
721c50c2f6fSdarrenr if ((p != 0) && (p != nat->nat_pr[1]))
72226945a25Schristos break;
72326945a25Schristos
724c50c2f6fSdarrenr switch (e->ipfe_cmd)
72526945a25Schristos {
72626945a25Schristos case IPF_EXP_IP_PR :
727c50c2f6fSdarrenr for (i = 0; !rv && i < e->ipfe_narg; i++) {
728c50c2f6fSdarrenr rv |= (nat->nat_pr[1] == e->ipfe_arg0[i]);
72926945a25Schristos }
73026945a25Schristos break;
73126945a25Schristos
73226945a25Schristos case IPF_EXP_IP_SRCADDR :
733c50c2f6fSdarrenr if (nat->nat_v[0] != 4)
734c50c2f6fSdarrenr break;
735c50c2f6fSdarrenr for (i = 0; !rv && i < e->ipfe_narg; i++) {
736c50c2f6fSdarrenr rv |= ((nat->nat_osrcaddr &
737c50c2f6fSdarrenr e->ipfe_arg0[i * 2 + 1]) ==
738c50c2f6fSdarrenr e->ipfe_arg0[i * 2]) ||
739c50c2f6fSdarrenr ((nat->nat_nsrcaddr &
740c50c2f6fSdarrenr e->ipfe_arg0[i * 2 + 1]) ==
741c50c2f6fSdarrenr e->ipfe_arg0[i * 2]);
74226945a25Schristos }
74326945a25Schristos break;
74426945a25Schristos
74526945a25Schristos case IPF_EXP_IP_DSTADDR :
746c50c2f6fSdarrenr if (nat->nat_v[0] != 4)
747c50c2f6fSdarrenr break;
748c50c2f6fSdarrenr for (i = 0; !rv && i < e->ipfe_narg; i++) {
749c50c2f6fSdarrenr rv |= ((nat->nat_odstaddr &
750c50c2f6fSdarrenr e->ipfe_arg0[i * 2 + 1]) ==
751c50c2f6fSdarrenr e->ipfe_arg0[i * 2]) ||
752c50c2f6fSdarrenr ((nat->nat_ndstaddr &
753c50c2f6fSdarrenr e->ipfe_arg0[i * 2 + 1]) ==
754c50c2f6fSdarrenr e->ipfe_arg0[i * 2]);
75526945a25Schristos }
75626945a25Schristos break;
75726945a25Schristos
75826945a25Schristos case IPF_EXP_IP_ADDR :
759c50c2f6fSdarrenr if (nat->nat_v[0] != 4)
760c50c2f6fSdarrenr break;
761c50c2f6fSdarrenr for (i = 0; !rv && i < e->ipfe_narg; i++) {
762c50c2f6fSdarrenr rv |= ((nat->nat_osrcaddr &
763c50c2f6fSdarrenr e->ipfe_arg0[i * 2 + 1]) ==
764c50c2f6fSdarrenr e->ipfe_arg0[i * 2]) ||
765c50c2f6fSdarrenr ((nat->nat_nsrcaddr &
766c50c2f6fSdarrenr e->ipfe_arg0[i * 2 + 1]) ==
767c50c2f6fSdarrenr e->ipfe_arg0[i * 2]) ||
768c50c2f6fSdarrenr ((nat->nat_odstaddr &
769c50c2f6fSdarrenr e->ipfe_arg0[i * 2 + 1]) ==
770c50c2f6fSdarrenr e->ipfe_arg0[i * 2]) ||
771c50c2f6fSdarrenr ((nat->nat_ndstaddr &
772c50c2f6fSdarrenr e->ipfe_arg0[i * 2 + 1]) ==
773c50c2f6fSdarrenr e->ipfe_arg0[i * 2]);
77426945a25Schristos }
77526945a25Schristos break;
77626945a25Schristos
777c50c2f6fSdarrenr #ifdef USE_INET6
778c50c2f6fSdarrenr case IPF_EXP_IP6_SRCADDR :
779c50c2f6fSdarrenr if (nat->nat_v[0] != 6)
780c50c2f6fSdarrenr break;
781c50c2f6fSdarrenr for (i = 0; !rv && i < e->ipfe_narg; i++) {
782c50c2f6fSdarrenr rv |= IP6_MASKEQ(&nat->nat_osrc6,
783c50c2f6fSdarrenr &e->ipfe_arg0[i * 8 + 4],
784c50c2f6fSdarrenr &e->ipfe_arg0[i * 8]) ||
785c50c2f6fSdarrenr IP6_MASKEQ(&nat->nat_nsrc6,
786c50c2f6fSdarrenr &e->ipfe_arg0[i * 8 + 4],
787c50c2f6fSdarrenr &e->ipfe_arg0[i * 8]);
788c50c2f6fSdarrenr }
789c50c2f6fSdarrenr break;
790c50c2f6fSdarrenr
791c50c2f6fSdarrenr case IPF_EXP_IP6_DSTADDR :
792c50c2f6fSdarrenr if (nat->nat_v[0] != 6)
793c50c2f6fSdarrenr break;
794c50c2f6fSdarrenr for (i = 0; !rv && i < e->ipfe_narg; i++) {
795c50c2f6fSdarrenr rv |= IP6_MASKEQ(&nat->nat_odst6,
796c50c2f6fSdarrenr &e->ipfe_arg0[i * 8 + 4],
797c50c2f6fSdarrenr &e->ipfe_arg0[i * 8]) ||
798c50c2f6fSdarrenr IP6_MASKEQ(&nat->nat_ndst6,
799c50c2f6fSdarrenr &e->ipfe_arg0[i * 8 + 4],
800c50c2f6fSdarrenr &e->ipfe_arg0[i * 8]);
801c50c2f6fSdarrenr }
802c50c2f6fSdarrenr break;
803c50c2f6fSdarrenr
804c50c2f6fSdarrenr case IPF_EXP_IP6_ADDR :
805c50c2f6fSdarrenr if (nat->nat_v[0] != 6)
806c50c2f6fSdarrenr break;
807c50c2f6fSdarrenr for (i = 0; !rv && i < e->ipfe_narg; i++) {
808c50c2f6fSdarrenr rv |= IP6_MASKEQ(&nat->nat_osrc6,
809c50c2f6fSdarrenr &e->ipfe_arg0[i * 8 + 4],
810c50c2f6fSdarrenr &e->ipfe_arg0[i * 8]) ||
811c50c2f6fSdarrenr IP6_MASKEQ(&nat->nat_nsrc6,
812c50c2f6fSdarrenr &e->ipfe_arg0[i * 8 + 4],
813c50c2f6fSdarrenr &e->ipfe_arg0[i * 8]) ||
814c50c2f6fSdarrenr IP6_MASKEQ(&nat->nat_odst6,
815c50c2f6fSdarrenr &e->ipfe_arg0[i * 8 + 4],
816c50c2f6fSdarrenr &e->ipfe_arg0[i * 8]) ||
817c50c2f6fSdarrenr IP6_MASKEQ(&nat->nat_ndst6,
818c50c2f6fSdarrenr &e->ipfe_arg0[i * 8 + 4],
819c50c2f6fSdarrenr &e->ipfe_arg0[i * 8]);
820c50c2f6fSdarrenr }
821c50c2f6fSdarrenr break;
822c50c2f6fSdarrenr #endif
823c50c2f6fSdarrenr
82426945a25Schristos case IPF_EXP_UDP_PORT :
82526945a25Schristos case IPF_EXP_TCP_PORT :
826c50c2f6fSdarrenr for (i = 0; !rv && i < e->ipfe_narg; i++) {
827c50c2f6fSdarrenr rv |= (nat->nat_osport == e->ipfe_arg0[i]) ||
828c50c2f6fSdarrenr (nat->nat_nsport == e->ipfe_arg0[i]) ||
829c50c2f6fSdarrenr (nat->nat_odport == e->ipfe_arg0[i]) ||
830c50c2f6fSdarrenr (nat->nat_ndport == e->ipfe_arg0[i]);
83126945a25Schristos }
83226945a25Schristos break;
83326945a25Schristos
83426945a25Schristos case IPF_EXP_UDP_SPORT :
83526945a25Schristos case IPF_EXP_TCP_SPORT :
836c50c2f6fSdarrenr for (i = 0; !rv && i < e->ipfe_narg; i++) {
837c50c2f6fSdarrenr rv |= (nat->nat_osport == e->ipfe_arg0[i]) ||
838c50c2f6fSdarrenr (nat->nat_nsport == e->ipfe_arg0[i]);
83926945a25Schristos }
84026945a25Schristos break;
84126945a25Schristos
84226945a25Schristos case IPF_EXP_UDP_DPORT :
84326945a25Schristos case IPF_EXP_TCP_DPORT :
844c50c2f6fSdarrenr for (i = 0; !rv && i < e->ipfe_narg; i++) {
845c50c2f6fSdarrenr rv |= (nat->nat_odport == e->ipfe_arg0[i]) ||
846c50c2f6fSdarrenr (nat->nat_ndport == e->ipfe_arg0[i]);
84726945a25Schristos }
84826945a25Schristos break;
84926945a25Schristos }
850c50c2f6fSdarrenr rv ^= e->ipfe_not;
85126945a25Schristos
852c50c2f6fSdarrenr if (rv == 0)
85326945a25Schristos break;
85426945a25Schristos }
85526945a25Schristos
856c50c2f6fSdarrenr return rv;
85726945a25Schristos }
858