ipnat.c revision 145554
11541Srgrimes/* $FreeBSD: head/contrib/ipfilter/tools/ipnat.c 145554 2005-04-26 15:18:45Z darrenr $ */ 21541Srgrimes 31541Srgrimes/* 41541Srgrimes * Copyright (C) 1993-2001 by Darren Reed. 51541Srgrimes * 61541Srgrimes * See the IPFILTER.LICENCE file for details on licencing. 71541Srgrimes * 81541Srgrimes * Added redirect stuff and a variety of bug fixes. (mcn@EnGarde.com) 91541Srgrimes */ 101541Srgrimes#include <stdio.h> 111541Srgrimes#include <string.h> 121541Srgrimes#include <fcntl.h> 131541Srgrimes#include <errno.h> 141541Srgrimes#include <sys/types.h> 151541Srgrimes#if !defined(__SVR4) && !defined(__svr4__) 161541Srgrimes#include <strings.h> 171541Srgrimes#else 181541Srgrimes#include <sys/byteorder.h> 191541Srgrimes#endif 201541Srgrimes#include <sys/time.h> 211541Srgrimes#include <sys/param.h> 221541Srgrimes#include <stdlib.h> 231541Srgrimes#include <unistd.h> 241541Srgrimes#include <stddef.h> 251541Srgrimes#include <sys/file.h> 261541Srgrimes#define _KERNEL 271541Srgrimes#include <sys/uio.h> 281541Srgrimes#undef _KERNEL 291541Srgrimes#include <sys/socket.h> 301541Srgrimes#include <sys/ioctl.h> 311541Srgrimes#if defined(sun) && (defined(__svr4__) || defined(__SVR4)) 321541Srgrimes# include <sys/ioccom.h> 331541Srgrimes# include <sys/sysmacros.h> 3412478Sbde#endif 351541Srgrimes#include <netinet/in.h> 361541Srgrimes#include <netinet/in_systm.h> 372165Spaul#include <netinet/ip.h> 385052Sbde#include <netinet/tcp.h> 392165Spaul#include <net/if.h> 401541Srgrimes#if __FreeBSD_version >= 300000 411541Srgrimes# include <net/if_var.h> 421541Srgrimes#endif 431541Srgrimes#include <netdb.h> 441541Srgrimes#include <arpa/nameser.h> 451541Srgrimes#include <arpa/inet.h> 461541Srgrimes#include <resolv.h> 471541Srgrimes#include <ctype.h> 481541Srgrimes#if defined(linux) 491541Srgrimes# include <linux/a.out.h> 501541Srgrimes#else 511541Srgrimes# include <nlist.h> 521541Srgrimes#endif 531541Srgrimes#include "ipf.h" 544027Sphk#include "netinet/ipl.h" 551541Srgrimes#include "kmem.h" 561541Srgrimes 571541Srgrimes#ifdef __hpux 581541Srgrimes# define nlist nlist64 591541Srgrimes#endif 601541Srgrimes 611541Srgrimes#if defined(sun) && !SOLARIS2 621541Srgrimes# define STRERROR(x) sys_errlist[x] 631541Srgrimesextern char *sys_errlist[]; 641541Srgrimes#else 651541Srgrimes# define STRERROR(x) strerror(x) 661541Srgrimes#endif 671541Srgrimes 681541Srgrimes#if !defined(lint) 691541Srgrimesstatic const char sccsid[] ="@(#)ipnat.c 1.9 6/5/96 (C) 1993 Darren Reed"; 701541Srgrimesstatic const char rcsid[] = "@(#)Id: ipnat.c,v 1.24.2.1 2004/04/28 17:56:22 darrenr Exp"; 711541Srgrimes#endif 725052Sbde 735052Sbde 745052Sbde#if SOLARIS 751541Srgrimes#define bzero(a,b) memset(a,0,b) 761541Srgrimes#endif 771541Srgrimesint use_inet6 = 0; 781541Srgrimeschar thishost[MAXHOSTNAMELEN]; 791541Srgrimes 801541Srgrimesextern char *optarg; 811541Srgrimes 828876Srgrimesvoid dostats __P((natstat_t *, int)), flushtable __P((int, int)); 831541Srgrimesvoid usage __P((char *)); 841541Srgrimesint main __P((int, char*[])); 851541Srgrimesvoid showhostmap __P((natstat_t *nsp)); 861541Srgrimesvoid natstat_dead __P((natstat_t *, char *)); 871541Srgrimes 881541Srgrimesint opts; 891541Srgrimes 901541Srgrimesvoid usage(name) 918876Srgrimeschar *name; 921541Srgrimes{ 931541Srgrimes fprintf(stderr, "Usage: %s [-CFhlnrRsv] [-f filename]\n", name); 948876Srgrimes exit(1); 951541Srgrimes} 961541Srgrimes 971541Srgrimes 988876Srgrimesint main(argc, argv) 998876Srgrimesint argc; 1001541Srgrimeschar *argv[]; 1011541Srgrimes{ 1021541Srgrimes char *file, *core, *kernel; 1031541Srgrimes natstat_t ns, *nsp; 1041541Srgrimes int fd, c, mode; 1051541Srgrimes ipfobj_t obj; 1061541Srgrimes 1071541Srgrimes fd = -1; 1081541Srgrimes opts = 0; 1091541Srgrimes nsp = &ns; 1101541Srgrimes file = NULL; 1111541Srgrimes core = NULL; 1121541Srgrimes kernel = NULL; 1131541Srgrimes mode = O_RDWR; 1141541Srgrimes 1151541Srgrimes while ((c = getopt(argc, argv, "CdFf:hlM:N:nrRsv")) != -1) 1161541Srgrimes switch (c) 1171541Srgrimes { 1181541Srgrimes case 'C' : 1191541Srgrimes opts |= OPT_CLEAR; 1201541Srgrimes break; 1211541Srgrimes case 'd' : 1221541Srgrimes opts |= OPT_DEBUG; 1231541Srgrimes break; 1241541Srgrimes case 'f' : 1251541Srgrimes file = optarg; 1261541Srgrimes break; 1271541Srgrimes case 'F' : 1281541Srgrimes opts |= OPT_FLUSH; 1291541Srgrimes break; 1301541Srgrimes case 'h' : 1311541Srgrimes opts |=OPT_HITS; 1321541Srgrimes break; 1331541Srgrimes case 'l' : 1341541Srgrimes opts |= OPT_LIST; 1351541Srgrimes mode = O_RDONLY; 1361541Srgrimes break; 1371541Srgrimes case 'M' : 1381541Srgrimes core = optarg; 1391541Srgrimes break; 1401541Srgrimes case 'N' : 1411541Srgrimes kernel = optarg; 1421541Srgrimes break; 1431541Srgrimes case 'n' : 1441541Srgrimes opts |= OPT_DONOTHING; 1451541Srgrimes mode = O_RDONLY; 1461541Srgrimes break; 1471541Srgrimes case 'R' : 1481541Srgrimes opts |= OPT_NORESOLVE; 1491541Srgrimes break; 1501541Srgrimes case 'r' : 1511541Srgrimes opts |= OPT_REMOVE; 1521541Srgrimes break; 1531541Srgrimes case 's' : 1541541Srgrimes opts |= OPT_STAT; 1551541Srgrimes mode = O_RDONLY; 1561541Srgrimes break; 1571541Srgrimes case 'v' : 1581541Srgrimes opts |= OPT_VERBOSE; 1591541Srgrimes break; 1601541Srgrimes default : 1611541Srgrimes usage(argv[0]); 1621541Srgrimes } 1631541Srgrimes 1641541Srgrimes initparse(); 1651541Srgrimes 1661541Srgrimes if ((kernel != NULL) || (core != NULL)) { 1671541Srgrimes (void) setgid(getgid()); 1681541Srgrimes (void) setuid(getuid()); 1691541Srgrimes } 1701541Srgrimes 1711541Srgrimes bzero((char *)&ns, sizeof(ns)); 1721541Srgrimes 1731541Srgrimes if ((opts & OPT_DONOTHING) == 0) { 1741541Srgrimes if (checkrev(IPL_NAME) == -1) { 1751541Srgrimes fprintf(stderr, "User/kernel version check failed\n"); 1761541Srgrimes exit(1); 1771541Srgrimes } 1781541Srgrimes } 1791541Srgrimes 1801541Srgrimes 1811541Srgrimes if (!(opts & OPT_DONOTHING) && (kernel == NULL) && (core == NULL)) { 1821541Srgrimes if (openkmem(kernel, core) == -1) 1831541Srgrimes exit(1); 1841541Srgrimes 1851541Srgrimes if (((fd = open(IPNAT_NAME, mode)) == -1) && 1861541Srgrimes ((fd = open(IPNAT_NAME, O_RDONLY)) == -1)) { 1871541Srgrimes (void) fprintf(stderr, "%s: open: %s\n", IPNAT_NAME, 1881541Srgrimes STRERROR(errno)); 1891541Srgrimes exit(1); 1901541Srgrimes } 1911541Srgrimes 1921541Srgrimes bzero((char *)&obj, sizeof(obj)); 1931541Srgrimes obj.ipfo_rev = IPFILTER_VERSION; 1941541Srgrimes obj.ipfo_size = sizeof(*nsp); 1951541Srgrimes obj.ipfo_type = IPFOBJ_NATSTAT; 1961541Srgrimes obj.ipfo_ptr = (void *)nsp; 1971541Srgrimes if (ioctl(fd, SIOCGNATS, &obj) == -1) { 1981541Srgrimes perror("ioctl(SIOCGNATS)"); 1991541Srgrimes exit(1); 2001541Srgrimes } 2011541Srgrimes (void) setgid(getgid()); 2021541Srgrimes (void) setuid(getuid()); 2031541Srgrimes } else if ((kernel != NULL) || (core != NULL)) { 2041541Srgrimes if (openkmem(kernel, core) == -1) 2051541Srgrimes exit(1); 2061541Srgrimes 2071541Srgrimes natstat_dead(nsp, kernel); 2081541Srgrimes if (opts & (OPT_LIST|OPT_STAT)) 2091541Srgrimes dostats(nsp, opts); 2101541Srgrimes exit(0); 2111541Srgrimes } 2121541Srgrimes 2131541Srgrimes if (opts & (OPT_FLUSH|OPT_CLEAR)) 2141541Srgrimes flushtable(fd, opts); 2151541Srgrimes if (file) { 2161541Srgrimes ipnat_parsefile(fd, ipnat_addrule, ioctl, file); 2171541Srgrimes } 2181541Srgrimes if (opts & (OPT_LIST|OPT_STAT)) 2191541Srgrimes dostats(nsp, opts); 2201541Srgrimes return 0; 2211541Srgrimes} 2221541Srgrimes 2231541Srgrimes 2241541Srgrimes/* 2251541Srgrimes * Read NAT statistic information in using a symbol table and memory file 2261541Srgrimes * rather than doing ioctl's. 2271541Srgrimes */ 2281541Srgrimesvoid natstat_dead(nsp, kernel) 2291541Srgrimesnatstat_t *nsp; 2301541Srgrimeschar *kernel; 2311541Srgrimes{ 2321541Srgrimes struct nlist nat_nlist[10] = { 2331541Srgrimes { "nat_table" }, /* 0 */ 2341541Srgrimes { "nat_list" }, 2351541Srgrimes { "maptable" }, 2361541Srgrimes { "ipf_nattable_sz" }, 2371541Srgrimes { "ipf_natrules_sz" }, 2381541Srgrimes { "ipf_rdrrules_sz" }, /* 5 */ 2391541Srgrimes { "ipf_hostmap_sz" }, 2401541Srgrimes { "nat_instances" }, 2411541Srgrimes { "ap_sess_list" }, 2421541Srgrimes { NULL } 2431541Srgrimes }; 2441541Srgrimes void *tables[2]; 2451541Srgrimes 2461541Srgrimes if (nlist(kernel, nat_nlist) == -1) { 2471541Srgrimes fprintf(stderr, "nlist error\n"); 2481541Srgrimes return; 2491541Srgrimes } 2501541Srgrimes 2511541Srgrimes /* 2521541Srgrimes * Normally the ioctl copies all of these values into the structure 2531541Srgrimes * for us, before returning it to userland, so here we must copy each 2541541Srgrimes * one in individually. 2551541Srgrimes */ 2561541Srgrimes kmemcpy((char *)&tables, nat_nlist[0].n_value, sizeof(tables)); 2571541Srgrimes nsp->ns_table[0] = tables[0]; 2581541Srgrimes nsp->ns_table[1] = tables[1]; 2591541Srgrimes 2601541Srgrimes kmemcpy((char *)&nsp->ns_list, nat_nlist[1].n_value, 2611541Srgrimes sizeof(nsp->ns_list)); 2621541Srgrimes kmemcpy((char *)&nsp->ns_maptable, nat_nlist[2].n_value, 2631541Srgrimes sizeof(nsp->ns_maptable)); 2641541Srgrimes kmemcpy((char *)&nsp->ns_nattab_sz, nat_nlist[3].n_value, 2651541Srgrimes sizeof(nsp->ns_nattab_sz)); 2661541Srgrimes kmemcpy((char *)&nsp->ns_rultab_sz, nat_nlist[4].n_value, 2671541Srgrimes sizeof(nsp->ns_rultab_sz)); 2681541Srgrimes kmemcpy((char *)&nsp->ns_rdrtab_sz, nat_nlist[5].n_value, 2691541Srgrimes sizeof(nsp->ns_rdrtab_sz)); 2701541Srgrimes kmemcpy((char *)&nsp->ns_hostmap_sz, nat_nlist[6].n_value, 2711541Srgrimes sizeof(nsp->ns_hostmap_sz)); 2721541Srgrimes kmemcpy((char *)&nsp->ns_instances, nat_nlist[7].n_value, 2731541Srgrimes sizeof(nsp->ns_instances)); 2741541Srgrimes kmemcpy((char *)&nsp->ns_apslist, nat_nlist[8].n_value, 2751541Srgrimes sizeof(nsp->ns_apslist)); 2761541Srgrimes} 2771541Srgrimes 2781541Srgrimes 2791541Srgrimes/* 2801541Srgrimes * Display NAT statistics. 2811541Srgrimes */ 2821541Srgrimesvoid dostats(nsp, opts) 2831541Srgrimesnatstat_t *nsp; 2841541Srgrimesint opts; 2851541Srgrimes{ 2861541Srgrimes nat_t *np, nat; 2871541Srgrimes ipnat_t ipn; 2881541Srgrimes 2891541Srgrimes /* 2901541Srgrimes * Show statistics ? 2911541Srgrimes */ 2921541Srgrimes if (opts & OPT_STAT) { 2931541Srgrimes printf("mapped\tin\t%lu\tout\t%lu\n", 2941541Srgrimes nsp->ns_mapped[0], nsp->ns_mapped[1]); 2951541Srgrimes printf("added\t%lu\texpired\t%lu\n", 2961541Srgrimes nsp->ns_added, nsp->ns_expire); 2971541Srgrimes printf("no memory\t%lu\tbad nat\t%lu\n", 2981541Srgrimes nsp->ns_memfail, nsp->ns_badnat); 2991541Srgrimes printf("inuse\t%lu\nrules\t%lu\n", 3001541Srgrimes nsp->ns_inuse, nsp->ns_rules); 3011541Srgrimes printf("wilds\t%u\n", nsp->ns_wilds); 3021541Srgrimes if (opts & OPT_VERBOSE) 3031541Srgrimes printf("table %p list %p\n", 3041541Srgrimes nsp->ns_table, nsp->ns_list); 3051541Srgrimes } 3061541Srgrimes 3071541Srgrimes /* 3081541Srgrimes * Show list of NAT rules and NAT sessions ? 3091541Srgrimes */ 3101549Srgrimes if (opts & OPT_LIST) { 3111549Srgrimes printf("List of active MAP/Redirect filters:\n"); 3121549Srgrimes while (nsp->ns_list) { 3131549Srgrimes if (kmemcpy((char *)&ipn, (long)nsp->ns_list, 3141549Srgrimes sizeof(ipn))) { 3153742Spaul perror("kmemcpy"); 3161549Srgrimes break; 3171549Srgrimes } 3181549Srgrimes if (opts & OPT_HITS) 3191549Srgrimes printf("%lu ", ipn.in_hits); 3201549Srgrimes printnat(&ipn, opts & (OPT_DEBUG|OPT_VERBOSE)); 3211549Srgrimes nsp->ns_list = ipn.in_next; 3221549Srgrimes } 3231549Srgrimes 3241549Srgrimes printf("\nList of active sessions:\n"); 3251549Srgrimes 3261549Srgrimes for (np = nsp->ns_instances; np; np = nat.nat_next) { 3271549Srgrimes if (kmemcpy((char *)&nat, (long)np, sizeof(nat))) 3281549Srgrimes break; 3291549Srgrimes printactivenat(&nat, opts); 3301549Srgrimes if (nat.nat_aps) 3311549Srgrimes printaps(nat.nat_aps, opts); 3321549Srgrimes } 3331541Srgrimes 3341541Srgrimes if (opts & OPT_VERBOSE) 3351541Srgrimes showhostmap(nsp); 3361541Srgrimes } 3371541Srgrimes} 3381541Srgrimes 3391541Srgrimes 3401541Srgrimes/* 3411541Srgrimes * Display the active host mapping table. 3421541Srgrimes */ 3431541Srgrimesvoid showhostmap(nsp) 3441541Srgrimesnatstat_t *nsp; 3451541Srgrimes{ 3461541Srgrimes hostmap_t hm, *hmp, **maptable; 3471541Srgrimes u_int hv; 3481541Srgrimes 3491541Srgrimes printf("\nList of active host mappings:\n"); 3501541Srgrimes 3518552Sdg maptable = (hostmap_t **)malloc(sizeof(hostmap_t *) * 3521541Srgrimes nsp->ns_hostmap_sz); 3535052Sbde if (kmemcpy((char *)maptable, (u_long)nsp->ns_maptable, 3545052Sbde sizeof(hostmap_t *) * nsp->ns_hostmap_sz)) { 3555052Sbde perror("kmemcpy (maptable)"); 3565052Sbde return; 3575052Sbde } 3585052Sbde 3598876Srgrimes for (hv = 0; hv < nsp->ns_hostmap_sz; hv++) { 3605052Sbde hmp = maptable[hv]; 3615052Sbde 3625052Sbde while (hmp) { 3638193Sjulian if (kmemcpy((char *)&hm, (u_long)hmp, sizeof(hm))) { 3648193Sjulian perror("kmemcpy (hostmap)"); 3658193Sjulian return; 3668193Sjulian } 3678193Sjulian 3688193Sjulian printhostmap(&hm, hv); 3698193Sjulian hmp = hm.hm_next; 3708193Sjulian } 3718193Sjulian } 3728193Sjulian free(maptable); 3738193Sjulian} 3748193Sjulian 3758193Sjulian 3768193Sjulian/* 3775052Sbde * Issue an ioctl to flush either the NAT rules table or the active mapping 3785052Sbde * table or both. 3795052Sbde */ 3805052Sbdevoid flushtable(fd, opts) 3815052Sbdeint fd, opts; 3825052Sbde{ 3835052Sbde int n = 0; 3845052Sbde 3851541Srgrimes if (opts & OPT_FLUSH) { 3863940Sjkh n = 0; 3875052Sbde if (!(opts & OPT_DONOTHING) && ioctl(fd, SIOCIPFFL, &n) == -1) 3885052Sbde perror("ioctl(SIOCFLNAT)"); 3895052Sbde else 3905052Sbde printf("%d entries flushed from NAT table\n", n); 3914462Sbde } 39212478Sbde 39312478Sbde if (opts & OPT_CLEAR) { 3947090Sbde n = 1; 3957090Sbde if (!(opts & OPT_DONOTHING) && ioctl(fd, SIOCIPFFL, &n) == -1) 3965052Sbde perror("ioctl(SIOCCNATL)"); 3975052Sbde else 3983940Sjkh printf("%d entries flushed from NAT list\n", n); 3995052Sbde } 4005052Sbde} 40110823Sbde