13b9b51feSCy Schubert /* $FreeBSD$ */ 23b9b51feSCy Schubert 33b9b51feSCy Schubert /* 43b9b51feSCy Schubert * Copyright (C) 2012 by Darren Reed. 53b9b51feSCy Schubert * 63b9b51feSCy Schubert * See the IPFILTER.LICENCE file for details on licencing. 73b9b51feSCy Schubert */ 83b9b51feSCy Schubert #if defined(KERNEL) || defined(_KERNEL) 93b9b51feSCy Schubert # undef KERNEL 103b9b51feSCy Schubert # undef _KERNEL 113b9b51feSCy Schubert # define KERNEL 1 123b9b51feSCy Schubert # define _KERNEL 1 133b9b51feSCy Schubert #endif 143b9b51feSCy Schubert #include <sys/errno.h> 153b9b51feSCy Schubert #include <sys/types.h> 163b9b51feSCy Schubert #include <sys/param.h> 173b9b51feSCy Schubert #include <sys/time.h> 183b9b51feSCy Schubert #include <sys/file.h> 193b9b51feSCy Schubert #if defined(_KERNEL) && \ 203b9b51feSCy Schubert (defined(__NetBSD_Version) && (__NetBSD_Version >= 399002000)) 213b9b51feSCy Schubert # include <sys/kauth.h> 223b9b51feSCy Schubert #endif 233b9b51feSCy Schubert #if !defined(_KERNEL) 243b9b51feSCy Schubert # include <stdio.h> 253b9b51feSCy Schubert # include <string.h> 263b9b51feSCy Schubert # include <stdlib.h> 273b9b51feSCy Schubert # define KERNEL 283b9b51feSCy Schubert # ifdef _OpenBSD__ 293b9b51feSCy Schubert struct file; 303b9b51feSCy Schubert # endif 313b9b51feSCy Schubert # include <sys/uio.h> 323b9b51feSCy Schubert # undef KERNEL 333b9b51feSCy Schubert #endif 343b9b51feSCy Schubert #if defined(_KERNEL) && defined(__FreeBSD__) 353b9b51feSCy Schubert # include <sys/filio.h> 363b9b51feSCy Schubert # include <sys/fcntl.h> 373b9b51feSCy Schubert #else 383b9b51feSCy Schubert # include <sys/ioctl.h> 393b9b51feSCy Schubert #endif 403b9b51feSCy Schubert # include <sys/fcntl.h> 413b9b51feSCy Schubert # include <sys/protosw.h> 423b9b51feSCy Schubert #include <sys/socket.h> 433b9b51feSCy Schubert #if defined(_KERNEL) 443b9b51feSCy Schubert # include <sys/systm.h> 453b9b51feSCy Schubert # if !defined(__SVR4) 463b9b51feSCy Schubert # include <sys/mbuf.h> 473b9b51feSCy Schubert # endif 483b9b51feSCy Schubert #endif 493b9b51feSCy Schubert #if defined(__SVR4) 503b9b51feSCy Schubert # include <sys/filio.h> 513b9b51feSCy Schubert # include <sys/byteorder.h> 523b9b51feSCy Schubert # ifdef KERNEL 533b9b51feSCy Schubert # include <sys/dditypes.h> 543b9b51feSCy Schubert # endif 553b9b51feSCy Schubert # include <sys/stream.h> 563b9b51feSCy Schubert # include <sys/kmem.h> 573b9b51feSCy Schubert #endif 583b9b51feSCy Schubert #if defined(__FreeBSD__) 593b9b51feSCy Schubert # include <sys/queue.h> 603b9b51feSCy Schubert #endif 613b9b51feSCy Schubert #include <net/if.h> 623b9b51feSCy Schubert #if defined(__FreeBSD__) 633b9b51feSCy Schubert # include <net/if_var.h> 643b9b51feSCy Schubert #endif 653b9b51feSCy Schubert #ifdef sun 663b9b51feSCy Schubert # include <net/af.h> 673b9b51feSCy Schubert #endif 683b9b51feSCy Schubert #include <netinet/in.h> 693b9b51feSCy Schubert #include <netinet/in_systm.h> 703b9b51feSCy Schubert #include <netinet/ip.h> 713b9b51feSCy Schubert 723b9b51feSCy Schubert #ifdef RFC1825 733b9b51feSCy Schubert # include <vpn/md5.h> 743b9b51feSCy Schubert # include <vpn/ipsec.h> 753b9b51feSCy Schubert extern struct ifnet vpnif; 763b9b51feSCy Schubert #endif 773b9b51feSCy Schubert 783b9b51feSCy Schubert # include <netinet/ip_var.h> 793b9b51feSCy Schubert #include <netinet/tcp.h> 803b9b51feSCy Schubert #include <netinet/udp.h> 813b9b51feSCy Schubert #include <netinet/ip_icmp.h> 823b9b51feSCy Schubert #include "netinet/ip_compat.h" 833b9b51feSCy Schubert #include <netinet/tcpip.h> 843b9b51feSCy Schubert #include "netinet/ipl.h" 853b9b51feSCy Schubert #include "netinet/ip_fil.h" 863b9b51feSCy Schubert #include "netinet/ip_nat.h" 873b9b51feSCy Schubert #include "netinet/ip_frag.h" 883b9b51feSCy Schubert #include "netinet/ip_state.h" 893b9b51feSCy Schubert #include "netinet/ip_proxy.h" 903b9b51feSCy Schubert #include "netinet/ip_lookup.h" 913b9b51feSCy Schubert #include "netinet/ip_dstlist.h" 923b9b51feSCy Schubert #include "netinet/ip_sync.h" 933b9b51feSCy Schubert #if defined(__FreeBSD__) 943b9b51feSCy Schubert # include <sys/malloc.h> 953b9b51feSCy Schubert #endif 963b9b51feSCy Schubert #ifdef HAS_SYS_MD5_H 973b9b51feSCy Schubert # include <sys/md5.h> 983b9b51feSCy Schubert #else 993b9b51feSCy Schubert # include "md5.h" 1003b9b51feSCy Schubert #endif 1013b9b51feSCy Schubert /* END OF INCLUDES */ 1023b9b51feSCy Schubert 1033b9b51feSCy Schubert #undef SOCKADDR_IN 1043b9b51feSCy Schubert #define SOCKADDR_IN struct sockaddr_in 1053b9b51feSCy Schubert 1063b9b51feSCy Schubert #if !defined(lint) 1073b9b51feSCy Schubert static const char sccsid[] = "@(#)ip_nat.c 1.11 6/5/96 (C) 1995 Darren Reed"; 1083b9b51feSCy Schubert static const char rcsid[] = "@(#)$FreeBSD$"; 1093b9b51feSCy Schubert /* static const char rcsid[] = "@(#)$Id: ip_nat.c,v 2.195.2.102 2007/10/16 10:08:10 darrenr Exp $"; */ 1103b9b51feSCy Schubert #endif 1113b9b51feSCy Schubert 1123b9b51feSCy Schubert 1133b9b51feSCy Schubert #define NATFSUM(n,v,f) ((v) == 4 ? (n)->f.in4.s_addr : (n)->f.i6[0] + \ 1143b9b51feSCy Schubert (n)->f.i6[1] + (n)->f.i6[2] + (n)->f.i6[3]) 1153b9b51feSCy Schubert #define NBUMP(x) softn->(x)++ 1163b9b51feSCy Schubert #define NBUMPD(x, y) do { \ 1173b9b51feSCy Schubert softn->x.y++; \ 1183b9b51feSCy Schubert DT(y); \ 1193b9b51feSCy Schubert } while (0) 1203b9b51feSCy Schubert #define NBUMPSIDE(y,x) softn->ipf_nat_stats.ns_side[y].x++ 1213b9b51feSCy Schubert #define NBUMPSIDED(y,x) do { softn->ipf_nat_stats.ns_side[y].x++; \ 1223b9b51feSCy Schubert DT(x); } while (0) 1233b9b51feSCy Schubert #define NBUMPSIDEX(y,x,z) \ 1243b9b51feSCy Schubert do { softn->ipf_nat_stats.ns_side[y].x++; \ 1253b9b51feSCy Schubert DT(z); } while (0) 1263b9b51feSCy Schubert #define NBUMPSIDEDF(y,x)do { softn->ipf_nat_stats.ns_side[y].x++; \ 1273b9b51feSCy Schubert DT1(x, fr_info_t *, fin); } while (0) 1283b9b51feSCy Schubert 1293b9b51feSCy Schubert static ipftuneable_t ipf_nat_tuneables[] = { 1303b9b51feSCy Schubert /* nat */ 1313b9b51feSCy Schubert { { (void *)offsetof(ipf_nat_softc_t, ipf_nat_lock) }, 1323b9b51feSCy Schubert "nat_lock", 0, 1, 1333b9b51feSCy Schubert stsizeof(ipf_nat_softc_t, ipf_nat_lock), 1343b9b51feSCy Schubert IPFT_RDONLY, NULL, NULL }, 1353b9b51feSCy Schubert { { (void *)offsetof(ipf_nat_softc_t, ipf_nat_table_sz) }, 1363b9b51feSCy Schubert "nat_table_size", 1, 0x7fffffff, 1373b9b51feSCy Schubert stsizeof(ipf_nat_softc_t, ipf_nat_table_sz), 1383b9b51feSCy Schubert 0, NULL, ipf_nat_rehash }, 1393b9b51feSCy Schubert { { (void *)offsetof(ipf_nat_softc_t, ipf_nat_table_max) }, 1403b9b51feSCy Schubert "nat_table_max", 1, 0x7fffffff, 1413b9b51feSCy Schubert stsizeof(ipf_nat_softc_t, ipf_nat_table_max), 1423b9b51feSCy Schubert 0, NULL, NULL }, 1433b9b51feSCy Schubert { { (void *)offsetof(ipf_nat_softc_t, ipf_nat_maprules_sz) }, 1443b9b51feSCy Schubert "nat_rules_size", 1, 0x7fffffff, 1453b9b51feSCy Schubert stsizeof(ipf_nat_softc_t, ipf_nat_maprules_sz), 1463b9b51feSCy Schubert 0, NULL, ipf_nat_rehash_rules }, 1473b9b51feSCy Schubert { { (void *)offsetof(ipf_nat_softc_t, ipf_nat_rdrrules_sz) }, 1483b9b51feSCy Schubert "rdr_rules_size", 1, 0x7fffffff, 1493b9b51feSCy Schubert stsizeof(ipf_nat_softc_t, ipf_nat_rdrrules_sz), 1503b9b51feSCy Schubert 0, NULL, ipf_nat_rehash_rules }, 1513b9b51feSCy Schubert { { (void *)offsetof(ipf_nat_softc_t, ipf_nat_hostmap_sz) }, 1523b9b51feSCy Schubert "hostmap_size", 1, 0x7fffffff, 1533b9b51feSCy Schubert stsizeof(ipf_nat_softc_t, ipf_nat_hostmap_sz), 1543b9b51feSCy Schubert 0, NULL, ipf_nat_hostmap_rehash }, 1553b9b51feSCy Schubert { { (void *)offsetof(ipf_nat_softc_t, ipf_nat_maxbucket) }, 1563b9b51feSCy Schubert "nat_maxbucket",1, 0x7fffffff, 1573b9b51feSCy Schubert stsizeof(ipf_nat_softc_t, ipf_nat_maxbucket), 1583b9b51feSCy Schubert 0, NULL, NULL }, 1593b9b51feSCy Schubert { { (void *)offsetof(ipf_nat_softc_t, ipf_nat_logging) }, 1603b9b51feSCy Schubert "nat_logging", 0, 1, 1613b9b51feSCy Schubert stsizeof(ipf_nat_softc_t, ipf_nat_logging), 1623b9b51feSCy Schubert 0, NULL, NULL }, 1633b9b51feSCy Schubert { { (void *)offsetof(ipf_nat_softc_t, ipf_nat_doflush) }, 1643b9b51feSCy Schubert "nat_doflush", 0, 1, 1653b9b51feSCy Schubert stsizeof(ipf_nat_softc_t, ipf_nat_doflush), 1663b9b51feSCy Schubert 0, NULL, NULL }, 1673b9b51feSCy Schubert { { (void *)offsetof(ipf_nat_softc_t, ipf_nat_table_wm_low) }, 1683b9b51feSCy Schubert "nat_table_wm_low", 1, 99, 1693b9b51feSCy Schubert stsizeof(ipf_nat_softc_t, ipf_nat_table_wm_low), 1703b9b51feSCy Schubert 0, NULL, NULL }, 1713b9b51feSCy Schubert { { (void *)offsetof(ipf_nat_softc_t, ipf_nat_table_wm_high) }, 1723b9b51feSCy Schubert "nat_table_wm_high", 2, 100, 1733b9b51feSCy Schubert stsizeof(ipf_nat_softc_t, ipf_nat_table_wm_high), 1743b9b51feSCy Schubert 0, NULL, NULL }, 1753b9b51feSCy Schubert { { 0 }, 1763b9b51feSCy Schubert NULL, 0, 0, 1773b9b51feSCy Schubert 0, 1783b9b51feSCy Schubert 0, NULL, NULL } 1793b9b51feSCy Schubert }; 1803b9b51feSCy Schubert 1813b9b51feSCy Schubert /* ======================================================================== */ 1823b9b51feSCy Schubert /* How the NAT is organised and works. */ 1833b9b51feSCy Schubert /* */ 1843b9b51feSCy Schubert /* Inside (interface y) NAT Outside (interface x) */ 1853b9b51feSCy Schubert /* -------------------- -+- ------------------------------------- */ 1863b9b51feSCy Schubert /* Packet going | out, processsed by ipf_nat_checkout() for x */ 1873b9b51feSCy Schubert /* ------------> | ------------> */ 1883b9b51feSCy Schubert /* src=10.1.1.1 | src=192.1.1.1 */ 1893b9b51feSCy Schubert /* | */ 1903b9b51feSCy Schubert /* | in, processed by ipf_nat_checkin() for x */ 1913b9b51feSCy Schubert /* <------------ | <------------ */ 1923b9b51feSCy Schubert /* dst=10.1.1.1 | dst=192.1.1.1 */ 1933b9b51feSCy Schubert /* -------------------- -+- ------------------------------------- */ 1943b9b51feSCy Schubert /* ipf_nat_checkout() - changes ip_src and if required, sport */ 1953b9b51feSCy Schubert /* - creates a new mapping, if required. */ 1963b9b51feSCy Schubert /* ipf_nat_checkin() - changes ip_dst and if required, dport */ 1973b9b51feSCy Schubert /* */ 1983b9b51feSCy Schubert /* In the NAT table, internal source is recorded as "in" and externally */ 1993b9b51feSCy Schubert /* seen as "out". */ 2003b9b51feSCy Schubert /* ======================================================================== */ 2013b9b51feSCy Schubert 2023b9b51feSCy Schubert 2033b9b51feSCy Schubert #if SOLARIS && !defined(INSTANCES) 2043b9b51feSCy Schubert extern int pfil_delayed_copy; 2053b9b51feSCy Schubert #endif 2063b9b51feSCy Schubert 2073b9b51feSCy Schubert static int ipf_nat_flush_entry(ipf_main_softc_t *, void *); 2083b9b51feSCy Schubert static int ipf_nat_getent(ipf_main_softc_t *, caddr_t, int); 2093b9b51feSCy Schubert static int ipf_nat_getsz(ipf_main_softc_t *, caddr_t, int); 2103b9b51feSCy Schubert static int ipf_nat_putent(ipf_main_softc_t *, caddr_t, int); 2113b9b51feSCy Schubert static void ipf_nat_addmap(ipf_nat_softc_t *, ipnat_t *); 2123b9b51feSCy Schubert static void ipf_nat_addrdr(ipf_nat_softc_t *, ipnat_t *); 2133b9b51feSCy Schubert static int ipf_nat_builddivertmp(ipf_nat_softc_t *, ipnat_t *); 2143b9b51feSCy Schubert static int ipf_nat_clearlist(ipf_main_softc_t *, ipf_nat_softc_t *); 2153b9b51feSCy Schubert static int ipf_nat_cmp_rules(ipnat_t *, ipnat_t *); 2163b9b51feSCy Schubert static int ipf_nat_decap(fr_info_t *, nat_t *); 2173b9b51feSCy Schubert static void ipf_nat_delrule(ipf_main_softc_t *, ipf_nat_softc_t *, 2183b9b51feSCy Schubert ipnat_t *, int); 2193b9b51feSCy Schubert static int ipf_nat_extraflush(ipf_main_softc_t *, ipf_nat_softc_t *, int); 2203b9b51feSCy Schubert static int ipf_nat_finalise(fr_info_t *, nat_t *); 2213b9b51feSCy Schubert static int ipf_nat_flushtable(ipf_main_softc_t *, ipf_nat_softc_t *); 2223b9b51feSCy Schubert static int ipf_nat_getnext(ipf_main_softc_t *, ipftoken_t *, 2233b9b51feSCy Schubert ipfgeniter_t *, ipfobj_t *); 2243b9b51feSCy Schubert static int ipf_nat_gettable(ipf_main_softc_t *, ipf_nat_softc_t *, 2253b9b51feSCy Schubert char *); 2263b9b51feSCy Schubert static hostmap_t *ipf_nat_hostmap(ipf_nat_softc_t *, ipnat_t *, 2273b9b51feSCy Schubert struct in_addr, struct in_addr, 2283b9b51feSCy Schubert struct in_addr, u_32_t); 2293b9b51feSCy Schubert static int ipf_nat_icmpquerytype(int); 2303b9b51feSCy Schubert static int ipf_nat_iterator(ipf_main_softc_t *, ipftoken_t *, 2313b9b51feSCy Schubert ipfgeniter_t *, ipfobj_t *); 2323b9b51feSCy Schubert static int ipf_nat_match(fr_info_t *, ipnat_t *); 2333b9b51feSCy Schubert static int ipf_nat_matcharray(nat_t *, int *, u_long); 2343b9b51feSCy Schubert static int ipf_nat_matchflush(ipf_main_softc_t *, ipf_nat_softc_t *, 2353b9b51feSCy Schubert caddr_t); 2363b9b51feSCy Schubert static void ipf_nat_mssclamp(tcphdr_t *, u_32_t, fr_info_t *, 2373b9b51feSCy Schubert u_short *); 2383b9b51feSCy Schubert static int ipf_nat_newmap(fr_info_t *, nat_t *, natinfo_t *); 2393b9b51feSCy Schubert static int ipf_nat_newdivert(fr_info_t *, nat_t *, natinfo_t *); 2403b9b51feSCy Schubert static int ipf_nat_newrdr(fr_info_t *, nat_t *, natinfo_t *); 2413b9b51feSCy Schubert static int ipf_nat_newrewrite(fr_info_t *, nat_t *, natinfo_t *); 2423b9b51feSCy Schubert static int ipf_nat_nextaddr(fr_info_t *, nat_addr_t *, u_32_t *, 2433b9b51feSCy Schubert u_32_t *); 2443b9b51feSCy Schubert static int ipf_nat_nextaddrinit(ipf_main_softc_t *, char *, 2453b9b51feSCy Schubert nat_addr_t *, int, void *); 2463b9b51feSCy Schubert static int ipf_nat_resolverule(ipf_main_softc_t *, ipnat_t *); 2473b9b51feSCy Schubert static int ipf_nat_ruleaddrinit(ipf_main_softc_t *, 2483b9b51feSCy Schubert ipf_nat_softc_t *, ipnat_t *); 2493b9b51feSCy Schubert static void ipf_nat_rule_fini(ipf_main_softc_t *, ipnat_t *); 2503b9b51feSCy Schubert static int ipf_nat_rule_init(ipf_main_softc_t *, ipf_nat_softc_t *, 2513b9b51feSCy Schubert ipnat_t *); 2523b9b51feSCy Schubert static int ipf_nat_siocaddnat(ipf_main_softc_t *, ipf_nat_softc_t *, 2533b9b51feSCy Schubert ipnat_t *, int); 2543b9b51feSCy Schubert static void ipf_nat_siocdelnat(ipf_main_softc_t *, ipf_nat_softc_t *, 2553b9b51feSCy Schubert ipnat_t *, int); 2563b9b51feSCy Schubert static void ipf_nat_tabmove(ipf_nat_softc_t *, nat_t *); 2573b9b51feSCy Schubert 2583b9b51feSCy Schubert /* ------------------------------------------------------------------------ */ 2593b9b51feSCy Schubert /* Function: ipf_nat_main_load */ 2603b9b51feSCy Schubert /* Returns: int - 0 == success, -1 == failure */ 2613b9b51feSCy Schubert /* Parameters: Nil */ 2623b9b51feSCy Schubert /* */ 2633b9b51feSCy Schubert /* The only global NAT structure that needs to be initialised is the filter */ 2643b9b51feSCy Schubert /* rule that is used with blocking packets. */ 2653b9b51feSCy Schubert /* ------------------------------------------------------------------------ */ 2663b9b51feSCy Schubert int 2673b9b51feSCy Schubert ipf_nat_main_load() 2683b9b51feSCy Schubert { 2693b9b51feSCy Schubert 2703b9b51feSCy Schubert return 0; 2713b9b51feSCy Schubert } 2723b9b51feSCy Schubert 2733b9b51feSCy Schubert 2743b9b51feSCy Schubert /* ------------------------------------------------------------------------ */ 2753b9b51feSCy Schubert /* Function: ipf_nat_main_unload */ 2763b9b51feSCy Schubert /* Returns: int - 0 == success, -1 == failure */ 2773b9b51feSCy Schubert /* Parameters: Nil */ 2783b9b51feSCy Schubert /* */ 2793b9b51feSCy Schubert /* A null-op function that exists as a placeholder so that the flow in */ 2803b9b51feSCy Schubert /* other functions is obvious. */ 2813b9b51feSCy Schubert /* ------------------------------------------------------------------------ */ 2823b9b51feSCy Schubert int 2833b9b51feSCy Schubert ipf_nat_main_unload() 2843b9b51feSCy Schubert { 2853b9b51feSCy Schubert return 0; 2863b9b51feSCy Schubert } 2873b9b51feSCy Schubert 2883b9b51feSCy Schubert 2893b9b51feSCy Schubert /* ------------------------------------------------------------------------ */ 2903b9b51feSCy Schubert /* Function: ipf_nat_soft_create */ 2913b9b51feSCy Schubert /* Returns: void * - NULL = failure, else pointer to NAT context */ 2923b9b51feSCy Schubert /* Parameters: softc(I) - pointer to soft context main structure */ 2933b9b51feSCy Schubert /* */ 2943b9b51feSCy Schubert /* Allocate the initial soft context structure for NAT and populate it with */ 2953b9b51feSCy Schubert /* some default values. Creating the tables is left until we call _init so */ 2963b9b51feSCy Schubert /* that sizes can be changed before we get under way. */ 2973b9b51feSCy Schubert /* ------------------------------------------------------------------------ */ 2983b9b51feSCy Schubert void * 2993b9b51feSCy Schubert ipf_nat_soft_create(softc) 3003b9b51feSCy Schubert ipf_main_softc_t *softc; 3013b9b51feSCy Schubert { 3023b9b51feSCy Schubert ipf_nat_softc_t *softn; 3033b9b51feSCy Schubert 3043b9b51feSCy Schubert KMALLOC(softn, ipf_nat_softc_t *); 3053b9b51feSCy Schubert if (softn == NULL) 3063b9b51feSCy Schubert return NULL; 3073b9b51feSCy Schubert 3083b9b51feSCy Schubert bzero((char *)softn, sizeof(*softn)); 3093b9b51feSCy Schubert 3103b9b51feSCy Schubert softn->ipf_nat_tune = ipf_tune_array_copy(softn, 3113b9b51feSCy Schubert sizeof(ipf_nat_tuneables), 3123b9b51feSCy Schubert ipf_nat_tuneables); 3133b9b51feSCy Schubert if (softn->ipf_nat_tune == NULL) { 3143b9b51feSCy Schubert ipf_nat_soft_destroy(softc, softn); 3153b9b51feSCy Schubert return NULL; 3163b9b51feSCy Schubert } 3173b9b51feSCy Schubert if (ipf_tune_array_link(softc, softn->ipf_nat_tune) == -1) { 3183b9b51feSCy Schubert ipf_nat_soft_destroy(softc, softn); 3193b9b51feSCy Schubert return NULL; 3203b9b51feSCy Schubert } 3213b9b51feSCy Schubert 3223b9b51feSCy Schubert softn->ipf_nat_list_tail = &softn->ipf_nat_list; 3233b9b51feSCy Schubert 3243b9b51feSCy Schubert if (softc->ipf_large_nat) { 3253b9b51feSCy Schubert softn->ipf_nat_table_max = NAT_TABLE_MAX_LARGE; 3263b9b51feSCy Schubert softn->ipf_nat_table_sz = NAT_TABLE_SZ_LARGE; 3273b9b51feSCy Schubert softn->ipf_nat_maprules_sz = NAT_SIZE_LARGE; 3283b9b51feSCy Schubert softn->ipf_nat_rdrrules_sz = RDR_SIZE_LARGE; 3293b9b51feSCy Schubert softn->ipf_nat_hostmap_sz = HOSTMAP_SIZE_LARGE; 3303b9b51feSCy Schubert } else { 3313b9b51feSCy Schubert softn->ipf_nat_table_max = NAT_TABLE_MAX_NORMAL; 3323b9b51feSCy Schubert softn->ipf_nat_table_sz = NAT_TABLE_SZ_NORMAL; 3333b9b51feSCy Schubert softn->ipf_nat_maprules_sz = NAT_SIZE_NORMAL; 3343b9b51feSCy Schubert softn->ipf_nat_rdrrules_sz = RDR_SIZE_NORMAL; 3353b9b51feSCy Schubert softn->ipf_nat_hostmap_sz = HOSTMAP_SIZE_NORMAL; 3363b9b51feSCy Schubert } 3373b9b51feSCy Schubert softn->ipf_nat_doflush = 0; 3383b9b51feSCy Schubert #ifdef IPFILTER_LOG 3393b9b51feSCy Schubert softn->ipf_nat_logging = 1; 3403b9b51feSCy Schubert #else 3413b9b51feSCy Schubert softn->ipf_nat_logging = 0; 3423b9b51feSCy Schubert #endif 3433b9b51feSCy Schubert 3443b9b51feSCy Schubert softn->ipf_nat_defage = DEF_NAT_AGE; 3453b9b51feSCy Schubert softn->ipf_nat_defipage = IPF_TTLVAL(60); 3463b9b51feSCy Schubert softn->ipf_nat_deficmpage = IPF_TTLVAL(3); 3473b9b51feSCy Schubert softn->ipf_nat_table_wm_high = 99; 3483b9b51feSCy Schubert softn->ipf_nat_table_wm_low = 90; 3493b9b51feSCy Schubert 3503b9b51feSCy Schubert return softn; 3513b9b51feSCy Schubert } 3523b9b51feSCy Schubert 3533b9b51feSCy Schubert /* ------------------------------------------------------------------------ */ 3543b9b51feSCy Schubert /* Function: ipf_nat_soft_destroy */ 3553b9b51feSCy Schubert /* Returns: Nil */ 3563b9b51feSCy Schubert /* Parameters: softc(I) - pointer to soft context main structure */ 3573b9b51feSCy Schubert /* */ 3583b9b51feSCy Schubert /* ------------------------------------------------------------------------ */ 3593b9b51feSCy Schubert void 3603b9b51feSCy Schubert ipf_nat_soft_destroy(softc, arg) 3613b9b51feSCy Schubert ipf_main_softc_t *softc; 3623b9b51feSCy Schubert void *arg; 3633b9b51feSCy Schubert { 3643b9b51feSCy Schubert ipf_nat_softc_t *softn = arg; 3653b9b51feSCy Schubert 3663b9b51feSCy Schubert if (softn->ipf_nat_tune != NULL) { 3673b9b51feSCy Schubert ipf_tune_array_unlink(softc, softn->ipf_nat_tune); 3683b9b51feSCy Schubert KFREES(softn->ipf_nat_tune, sizeof(ipf_nat_tuneables)); 3693b9b51feSCy Schubert softn->ipf_nat_tune = NULL; 3703b9b51feSCy Schubert } 3713b9b51feSCy Schubert 3723b9b51feSCy Schubert KFREE(softn); 3733b9b51feSCy Schubert } 3743b9b51feSCy Schubert 3753b9b51feSCy Schubert 3763b9b51feSCy Schubert /* ------------------------------------------------------------------------ */ 3773b9b51feSCy Schubert /* Function: ipf_nat_init */ 3783b9b51feSCy Schubert /* Returns: int - 0 == success, -1 == failure */ 3793b9b51feSCy Schubert /* Parameters: softc(I) - pointer to soft context main structure */ 3803b9b51feSCy Schubert /* */ 3813b9b51feSCy Schubert /* Initialise all of the NAT locks, tables and other structures. */ 3823b9b51feSCy Schubert /* ------------------------------------------------------------------------ */ 3833b9b51feSCy Schubert int 3843b9b51feSCy Schubert ipf_nat_soft_init(softc, arg) 3853b9b51feSCy Schubert ipf_main_softc_t *softc; 3863b9b51feSCy Schubert void *arg; 3873b9b51feSCy Schubert { 3883b9b51feSCy Schubert ipf_nat_softc_t *softn = arg; 3893b9b51feSCy Schubert ipftq_t *tq; 3903b9b51feSCy Schubert int i; 3913b9b51feSCy Schubert 3923b9b51feSCy Schubert KMALLOCS(softn->ipf_nat_table[0], nat_t **, \ 3933b9b51feSCy Schubert sizeof(nat_t *) * softn->ipf_nat_table_sz); 3943b9b51feSCy Schubert 3953b9b51feSCy Schubert if (softn->ipf_nat_table[0] != NULL) { 3963b9b51feSCy Schubert bzero((char *)softn->ipf_nat_table[0], 3973b9b51feSCy Schubert softn->ipf_nat_table_sz * sizeof(nat_t *)); 3983b9b51feSCy Schubert } else { 3993b9b51feSCy Schubert return -1; 4003b9b51feSCy Schubert } 4013b9b51feSCy Schubert 4023b9b51feSCy Schubert KMALLOCS(softn->ipf_nat_table[1], nat_t **, \ 4033b9b51feSCy Schubert sizeof(nat_t *) * softn->ipf_nat_table_sz); 4043b9b51feSCy Schubert 4053b9b51feSCy Schubert if (softn->ipf_nat_table[1] != NULL) { 4063b9b51feSCy Schubert bzero((char *)softn->ipf_nat_table[1], 4073b9b51feSCy Schubert softn->ipf_nat_table_sz * sizeof(nat_t *)); 4083b9b51feSCy Schubert } else { 4093b9b51feSCy Schubert return -2; 4103b9b51feSCy Schubert } 4113b9b51feSCy Schubert 4123b9b51feSCy Schubert KMALLOCS(softn->ipf_nat_map_rules, ipnat_t **, \ 4133b9b51feSCy Schubert sizeof(ipnat_t *) * softn->ipf_nat_maprules_sz); 4143b9b51feSCy Schubert 4153b9b51feSCy Schubert if (softn->ipf_nat_map_rules != NULL) { 4163b9b51feSCy Schubert bzero((char *)softn->ipf_nat_map_rules, 4173b9b51feSCy Schubert softn->ipf_nat_maprules_sz * sizeof(ipnat_t *)); 4183b9b51feSCy Schubert } else { 4193b9b51feSCy Schubert return -3; 4203b9b51feSCy Schubert } 4213b9b51feSCy Schubert 4223b9b51feSCy Schubert KMALLOCS(softn->ipf_nat_rdr_rules, ipnat_t **, \ 4233b9b51feSCy Schubert sizeof(ipnat_t *) * softn->ipf_nat_rdrrules_sz); 4243b9b51feSCy Schubert 4253b9b51feSCy Schubert if (softn->ipf_nat_rdr_rules != NULL) { 4263b9b51feSCy Schubert bzero((char *)softn->ipf_nat_rdr_rules, 4273b9b51feSCy Schubert softn->ipf_nat_rdrrules_sz * sizeof(ipnat_t *)); 4283b9b51feSCy Schubert } else { 4293b9b51feSCy Schubert return -4; 4303b9b51feSCy Schubert } 4313b9b51feSCy Schubert 4323b9b51feSCy Schubert KMALLOCS(softn->ipf_hm_maptable, hostmap_t **, \ 4333b9b51feSCy Schubert sizeof(hostmap_t *) * softn->ipf_nat_hostmap_sz); 4343b9b51feSCy Schubert 4353b9b51feSCy Schubert if (softn->ipf_hm_maptable != NULL) { 4363b9b51feSCy Schubert bzero((char *)softn->ipf_hm_maptable, 4373b9b51feSCy Schubert sizeof(hostmap_t *) * softn->ipf_nat_hostmap_sz); 4383b9b51feSCy Schubert } else { 4393b9b51feSCy Schubert return -5; 4403b9b51feSCy Schubert } 4413b9b51feSCy Schubert softn->ipf_hm_maplist = NULL; 4423b9b51feSCy Schubert 4433b9b51feSCy Schubert KMALLOCS(softn->ipf_nat_stats.ns_side[0].ns_bucketlen, u_int *, 4443b9b51feSCy Schubert softn->ipf_nat_table_sz * sizeof(u_int)); 4453b9b51feSCy Schubert 4463b9b51feSCy Schubert if (softn->ipf_nat_stats.ns_side[0].ns_bucketlen == NULL) { 4473b9b51feSCy Schubert return -6; 4483b9b51feSCy Schubert } 4493b9b51feSCy Schubert bzero((char *)softn->ipf_nat_stats.ns_side[0].ns_bucketlen, 4503b9b51feSCy Schubert softn->ipf_nat_table_sz * sizeof(u_int)); 4513b9b51feSCy Schubert 4523b9b51feSCy Schubert KMALLOCS(softn->ipf_nat_stats.ns_side[1].ns_bucketlen, u_int *, 4533b9b51feSCy Schubert softn->ipf_nat_table_sz * sizeof(u_int)); 4543b9b51feSCy Schubert 4553b9b51feSCy Schubert if (softn->ipf_nat_stats.ns_side[1].ns_bucketlen == NULL) { 4563b9b51feSCy Schubert return -7; 4573b9b51feSCy Schubert } 4583b9b51feSCy Schubert 4593b9b51feSCy Schubert bzero((char *)softn->ipf_nat_stats.ns_side[1].ns_bucketlen, 4603b9b51feSCy Schubert softn->ipf_nat_table_sz * sizeof(u_int)); 4613b9b51feSCy Schubert 4623b9b51feSCy Schubert if (softn->ipf_nat_maxbucket == 0) { 4633b9b51feSCy Schubert for (i = softn->ipf_nat_table_sz; i > 0; i >>= 1) 4643b9b51feSCy Schubert softn->ipf_nat_maxbucket++; 4653b9b51feSCy Schubert softn->ipf_nat_maxbucket *= 2; 4663b9b51feSCy Schubert } 4673b9b51feSCy Schubert 4683b9b51feSCy Schubert ipf_sttab_init(softc, softn->ipf_nat_tcptq); 4693b9b51feSCy Schubert /* 4703b9b51feSCy Schubert * Increase this because we may have "keep state" following this too 4713b9b51feSCy Schubert * and packet storms can occur if this is removed too quickly. 4723b9b51feSCy Schubert */ 4733b9b51feSCy Schubert softn->ipf_nat_tcptq[IPF_TCPS_CLOSED].ifq_ttl = softc->ipf_tcplastack; 4743b9b51feSCy Schubert softn->ipf_nat_tcptq[IPF_TCP_NSTATES - 1].ifq_next = 4753b9b51feSCy Schubert &softn->ipf_nat_udptq; 4763b9b51feSCy Schubert 4773b9b51feSCy Schubert IPFTQ_INIT(&softn->ipf_nat_udptq, softn->ipf_nat_defage, 4783b9b51feSCy Schubert "nat ipftq udp tab"); 4793b9b51feSCy Schubert softn->ipf_nat_udptq.ifq_next = &softn->ipf_nat_udpacktq; 4803b9b51feSCy Schubert 4813b9b51feSCy Schubert IPFTQ_INIT(&softn->ipf_nat_udpacktq, softn->ipf_nat_defage, 4823b9b51feSCy Schubert "nat ipftq udpack tab"); 4833b9b51feSCy Schubert softn->ipf_nat_udpacktq.ifq_next = &softn->ipf_nat_icmptq; 4843b9b51feSCy Schubert 4853b9b51feSCy Schubert IPFTQ_INIT(&softn->ipf_nat_icmptq, softn->ipf_nat_deficmpage, 4863b9b51feSCy Schubert "nat icmp ipftq tab"); 4873b9b51feSCy Schubert softn->ipf_nat_icmptq.ifq_next = &softn->ipf_nat_icmpacktq; 4883b9b51feSCy Schubert 4893b9b51feSCy Schubert IPFTQ_INIT(&softn->ipf_nat_icmpacktq, softn->ipf_nat_defage, 4903b9b51feSCy Schubert "nat icmpack ipftq tab"); 4913b9b51feSCy Schubert softn->ipf_nat_icmpacktq.ifq_next = &softn->ipf_nat_iptq; 4923b9b51feSCy Schubert 4933b9b51feSCy Schubert IPFTQ_INIT(&softn->ipf_nat_iptq, softn->ipf_nat_defipage, 4943b9b51feSCy Schubert "nat ip ipftq tab"); 4953b9b51feSCy Schubert softn->ipf_nat_iptq.ifq_next = &softn->ipf_nat_pending; 4963b9b51feSCy Schubert 4973b9b51feSCy Schubert IPFTQ_INIT(&softn->ipf_nat_pending, 1, "nat pending ipftq tab"); 4983b9b51feSCy Schubert softn->ipf_nat_pending.ifq_next = NULL; 4993b9b51feSCy Schubert 5003b9b51feSCy Schubert for (i = 0, tq = softn->ipf_nat_tcptq; i < IPF_TCP_NSTATES; i++, tq++) { 5013b9b51feSCy Schubert if (tq->ifq_ttl < softn->ipf_nat_deficmpage) 5023b9b51feSCy Schubert tq->ifq_ttl = softn->ipf_nat_deficmpage; 5033b9b51feSCy Schubert else if (tq->ifq_ttl > softn->ipf_nat_defage && softc->ipf_large_nat) 5043b9b51feSCy Schubert tq->ifq_ttl = softn->ipf_nat_defage; 5053b9b51feSCy Schubert } 5063b9b51feSCy Schubert 5073b9b51feSCy Schubert /* 5083b9b51feSCy Schubert * Increase this because we may have "keep state" following 5093b9b51feSCy Schubert * this too and packet storms can occur if this is removed 5103b9b51feSCy Schubert * too quickly. 5113b9b51feSCy Schubert */ 5123b9b51feSCy Schubert softn->ipf_nat_tcptq[IPF_TCPS_CLOSED].ifq_ttl = softc->ipf_tcplastack; 5133b9b51feSCy Schubert 5143b9b51feSCy Schubert MUTEX_INIT(&softn->ipf_nat_new, "ipf nat new mutex"); 5153b9b51feSCy Schubert MUTEX_INIT(&softn->ipf_nat_io, "ipf nat io mutex"); 5163b9b51feSCy Schubert 5173b9b51feSCy Schubert softn->ipf_nat_inited = 1; 5183b9b51feSCy Schubert 5193b9b51feSCy Schubert return 0; 5203b9b51feSCy Schubert } 5213b9b51feSCy Schubert 5223b9b51feSCy Schubert 5233b9b51feSCy Schubert /* ------------------------------------------------------------------------ */ 5243b9b51feSCy Schubert /* Function: ipf_nat_soft_fini */ 5253b9b51feSCy Schubert /* Returns: Nil */ 5263b9b51feSCy Schubert /* Parameters: softc(I) - pointer to soft context main structure */ 5273b9b51feSCy Schubert /* */ 5283b9b51feSCy Schubert /* Free all memory used by NAT structures allocated at runtime. */ 5293b9b51feSCy Schubert /* ------------------------------------------------------------------------ */ 5303b9b51feSCy Schubert int 5313b9b51feSCy Schubert ipf_nat_soft_fini(softc, arg) 5323b9b51feSCy Schubert ipf_main_softc_t *softc; 5333b9b51feSCy Schubert void *arg; 5343b9b51feSCy Schubert { 5353b9b51feSCy Schubert ipf_nat_softc_t *softn = arg; 5363b9b51feSCy Schubert ipftq_t *ifq, *ifqnext; 5373b9b51feSCy Schubert 5383b9b51feSCy Schubert (void) ipf_nat_clearlist(softc, softn); 5393b9b51feSCy Schubert (void) ipf_nat_flushtable(softc, softn); 5403b9b51feSCy Schubert 5413b9b51feSCy Schubert /* 5423b9b51feSCy Schubert * Proxy timeout queues are not cleaned here because although they 5433b9b51feSCy Schubert * exist on the NAT list, ipf_proxy_unload is called after unload 5443b9b51feSCy Schubert * and the proxies actually are responsible for them being created. 5453b9b51feSCy Schubert * Should the proxy timeouts have their own list? There's no real 5463b9b51feSCy Schubert * justification as this is the only complication. 5473b9b51feSCy Schubert */ 5483b9b51feSCy Schubert for (ifq = softn->ipf_nat_utqe; ifq != NULL; ifq = ifqnext) { 5493b9b51feSCy Schubert ifqnext = ifq->ifq_next; 5503b9b51feSCy Schubert if (ipf_deletetimeoutqueue(ifq) == 0) 5513b9b51feSCy Schubert ipf_freetimeoutqueue(softc, ifq); 5523b9b51feSCy Schubert } 5533b9b51feSCy Schubert 5543b9b51feSCy Schubert if (softn->ipf_nat_table[0] != NULL) { 5553b9b51feSCy Schubert KFREES(softn->ipf_nat_table[0], 5563b9b51feSCy Schubert sizeof(nat_t *) * softn->ipf_nat_table_sz); 5573b9b51feSCy Schubert softn->ipf_nat_table[0] = NULL; 5583b9b51feSCy Schubert } 5593b9b51feSCy Schubert if (softn->ipf_nat_table[1] != NULL) { 5603b9b51feSCy Schubert KFREES(softn->ipf_nat_table[1], 5613b9b51feSCy Schubert sizeof(nat_t *) * softn->ipf_nat_table_sz); 5623b9b51feSCy Schubert softn->ipf_nat_table[1] = NULL; 5633b9b51feSCy Schubert } 5643b9b51feSCy Schubert if (softn->ipf_nat_map_rules != NULL) { 5653b9b51feSCy Schubert KFREES(softn->ipf_nat_map_rules, 5663b9b51feSCy Schubert sizeof(ipnat_t *) * softn->ipf_nat_maprules_sz); 5673b9b51feSCy Schubert softn->ipf_nat_map_rules = NULL; 5683b9b51feSCy Schubert } 5693b9b51feSCy Schubert if (softn->ipf_nat_rdr_rules != NULL) { 5703b9b51feSCy Schubert KFREES(softn->ipf_nat_rdr_rules, 5713b9b51feSCy Schubert sizeof(ipnat_t *) * softn->ipf_nat_rdrrules_sz); 5723b9b51feSCy Schubert softn->ipf_nat_rdr_rules = NULL; 5733b9b51feSCy Schubert } 5743b9b51feSCy Schubert if (softn->ipf_hm_maptable != NULL) { 5753b9b51feSCy Schubert KFREES(softn->ipf_hm_maptable, 5763b9b51feSCy Schubert sizeof(hostmap_t *) * softn->ipf_nat_hostmap_sz); 5773b9b51feSCy Schubert softn->ipf_hm_maptable = NULL; 5783b9b51feSCy Schubert } 5793b9b51feSCy Schubert if (softn->ipf_nat_stats.ns_side[0].ns_bucketlen != NULL) { 5803b9b51feSCy Schubert KFREES(softn->ipf_nat_stats.ns_side[0].ns_bucketlen, 5813b9b51feSCy Schubert sizeof(u_int) * softn->ipf_nat_table_sz); 5823b9b51feSCy Schubert softn->ipf_nat_stats.ns_side[0].ns_bucketlen = NULL; 5833b9b51feSCy Schubert } 5843b9b51feSCy Schubert if (softn->ipf_nat_stats.ns_side[1].ns_bucketlen != NULL) { 5853b9b51feSCy Schubert KFREES(softn->ipf_nat_stats.ns_side[1].ns_bucketlen, 5863b9b51feSCy Schubert sizeof(u_int) * softn->ipf_nat_table_sz); 5873b9b51feSCy Schubert softn->ipf_nat_stats.ns_side[1].ns_bucketlen = NULL; 5883b9b51feSCy Schubert } 5893b9b51feSCy Schubert 5903b9b51feSCy Schubert if (softn->ipf_nat_inited == 1) { 5913b9b51feSCy Schubert softn->ipf_nat_inited = 0; 5923b9b51feSCy Schubert ipf_sttab_destroy(softn->ipf_nat_tcptq); 5933b9b51feSCy Schubert 5943b9b51feSCy Schubert MUTEX_DESTROY(&softn->ipf_nat_new); 5953b9b51feSCy Schubert MUTEX_DESTROY(&softn->ipf_nat_io); 5963b9b51feSCy Schubert 5973b9b51feSCy Schubert MUTEX_DESTROY(&softn->ipf_nat_udptq.ifq_lock); 5983b9b51feSCy Schubert MUTEX_DESTROY(&softn->ipf_nat_udpacktq.ifq_lock); 5993b9b51feSCy Schubert MUTEX_DESTROY(&softn->ipf_nat_icmptq.ifq_lock); 6003b9b51feSCy Schubert MUTEX_DESTROY(&softn->ipf_nat_icmpacktq.ifq_lock); 6013b9b51feSCy Schubert MUTEX_DESTROY(&softn->ipf_nat_iptq.ifq_lock); 6023b9b51feSCy Schubert MUTEX_DESTROY(&softn->ipf_nat_pending.ifq_lock); 6033b9b51feSCy Schubert } 6043b9b51feSCy Schubert 6053b9b51feSCy Schubert return 0; 6063b9b51feSCy Schubert } 6073b9b51feSCy Schubert 6083b9b51feSCy Schubert 6093b9b51feSCy Schubert /* ------------------------------------------------------------------------ */ 6103b9b51feSCy Schubert /* Function: ipf_nat_setlock */ 6113b9b51feSCy Schubert /* Returns: Nil */ 6123b9b51feSCy Schubert /* Parameters: arg(I) - pointer to soft state information */ 6133b9b51feSCy Schubert /* tmp(I) - new lock value */ 6143b9b51feSCy Schubert /* */ 6153b9b51feSCy Schubert /* Set the "lock status" of NAT to the value in tmp. */ 6163b9b51feSCy Schubert /* ------------------------------------------------------------------------ */ 6173b9b51feSCy Schubert void 6183b9b51feSCy Schubert ipf_nat_setlock(arg, tmp) 6193b9b51feSCy Schubert void *arg; 6203b9b51feSCy Schubert int tmp; 6213b9b51feSCy Schubert { 6223b9b51feSCy Schubert ipf_nat_softc_t *softn = arg; 6233b9b51feSCy Schubert 6243b9b51feSCy Schubert softn->ipf_nat_lock = tmp; 6253b9b51feSCy Schubert } 6263b9b51feSCy Schubert 6273b9b51feSCy Schubert 6283b9b51feSCy Schubert /* ------------------------------------------------------------------------ */ 6293b9b51feSCy Schubert /* Function: ipf_nat_addrdr */ 6303b9b51feSCy Schubert /* Returns: Nil */ 6313b9b51feSCy Schubert /* Parameters: n(I) - pointer to NAT rule to add */ 6323b9b51feSCy Schubert /* */ 6333b9b51feSCy Schubert /* Adds a redirect rule to the hash table of redirect rules and the list of */ 6343b9b51feSCy Schubert /* loaded NAT rules. Updates the bitmask indicating which netmasks are in */ 6353b9b51feSCy Schubert /* use by redirect rules. */ 6363b9b51feSCy Schubert /* ------------------------------------------------------------------------ */ 6373b9b51feSCy Schubert static void 6383b9b51feSCy Schubert ipf_nat_addrdr(softn, n) 6393b9b51feSCy Schubert ipf_nat_softc_t *softn; 6403b9b51feSCy Schubert ipnat_t *n; 6413b9b51feSCy Schubert { 6423b9b51feSCy Schubert ipnat_t **np; 6433b9b51feSCy Schubert u_32_t j; 6443b9b51feSCy Schubert u_int hv; 6453b9b51feSCy Schubert u_int rhv; 6463b9b51feSCy Schubert int k; 6473b9b51feSCy Schubert 6483b9b51feSCy Schubert if (n->in_odstatype == FRI_NORMAL) { 6493b9b51feSCy Schubert k = count4bits(n->in_odstmsk); 6503b9b51feSCy Schubert ipf_inet_mask_add(k, &softn->ipf_nat_rdr_mask); 6513b9b51feSCy Schubert j = (n->in_odstaddr & n->in_odstmsk); 6523b9b51feSCy Schubert rhv = NAT_HASH_FN(j, 0, 0xffffffff); 6533b9b51feSCy Schubert } else { 6543b9b51feSCy Schubert ipf_inet_mask_add(0, &softn->ipf_nat_rdr_mask); 6553b9b51feSCy Schubert j = 0; 6563b9b51feSCy Schubert rhv = 0; 6573b9b51feSCy Schubert } 6583b9b51feSCy Schubert hv = rhv % softn->ipf_nat_rdrrules_sz; 6593b9b51feSCy Schubert np = softn->ipf_nat_rdr_rules + hv; 6603b9b51feSCy Schubert while (*np != NULL) 6613b9b51feSCy Schubert np = &(*np)->in_rnext; 6623b9b51feSCy Schubert n->in_rnext = NULL; 6633b9b51feSCy Schubert n->in_prnext = np; 6643b9b51feSCy Schubert n->in_hv[0] = hv; 6653b9b51feSCy Schubert n->in_use++; 6663b9b51feSCy Schubert *np = n; 6673b9b51feSCy Schubert } 6683b9b51feSCy Schubert 6693b9b51feSCy Schubert 6703b9b51feSCy Schubert /* ------------------------------------------------------------------------ */ 6713b9b51feSCy Schubert /* Function: ipf_nat_addmap */ 6723b9b51feSCy Schubert /* Returns: Nil */ 6733b9b51feSCy Schubert /* Parameters: n(I) - pointer to NAT rule to add */ 6743b9b51feSCy Schubert /* */ 6753b9b51feSCy Schubert /* Adds a NAT map rule to the hash table of rules and the list of loaded */ 6763b9b51feSCy Schubert /* NAT rules. Updates the bitmask indicating which netmasks are in use by */ 6773b9b51feSCy Schubert /* redirect rules. */ 6783b9b51feSCy Schubert /* ------------------------------------------------------------------------ */ 6793b9b51feSCy Schubert static void 6803b9b51feSCy Schubert ipf_nat_addmap(softn, n) 6813b9b51feSCy Schubert ipf_nat_softc_t *softn; 6823b9b51feSCy Schubert ipnat_t *n; 6833b9b51feSCy Schubert { 6843b9b51feSCy Schubert ipnat_t **np; 6853b9b51feSCy Schubert u_32_t j; 6863b9b51feSCy Schubert u_int hv; 6873b9b51feSCy Schubert u_int rhv; 6883b9b51feSCy Schubert int k; 6893b9b51feSCy Schubert 6903b9b51feSCy Schubert if (n->in_osrcatype == FRI_NORMAL) { 6913b9b51feSCy Schubert k = count4bits(n->in_osrcmsk); 6923b9b51feSCy Schubert ipf_inet_mask_add(k, &softn->ipf_nat_map_mask); 6933b9b51feSCy Schubert j = (n->in_osrcaddr & n->in_osrcmsk); 6943b9b51feSCy Schubert rhv = NAT_HASH_FN(j, 0, 0xffffffff); 6953b9b51feSCy Schubert } else { 6963b9b51feSCy Schubert ipf_inet_mask_add(0, &softn->ipf_nat_map_mask); 6973b9b51feSCy Schubert j = 0; 6983b9b51feSCy Schubert rhv = 0; 6993b9b51feSCy Schubert } 7003b9b51feSCy Schubert hv = rhv % softn->ipf_nat_maprules_sz; 7013b9b51feSCy Schubert np = softn->ipf_nat_map_rules + hv; 7023b9b51feSCy Schubert while (*np != NULL) 7033b9b51feSCy Schubert np = &(*np)->in_mnext; 7043b9b51feSCy Schubert n->in_mnext = NULL; 7053b9b51feSCy Schubert n->in_pmnext = np; 7063b9b51feSCy Schubert n->in_hv[1] = rhv; 7073b9b51feSCy Schubert n->in_use++; 7083b9b51feSCy Schubert *np = n; 7093b9b51feSCy Schubert } 7103b9b51feSCy Schubert 7113b9b51feSCy Schubert 7123b9b51feSCy Schubert /* ------------------------------------------------------------------------ */ 7133b9b51feSCy Schubert /* Function: ipf_nat_delrdr */ 7143b9b51feSCy Schubert /* Returns: Nil */ 7153b9b51feSCy Schubert /* Parameters: n(I) - pointer to NAT rule to delete */ 7163b9b51feSCy Schubert /* */ 7173b9b51feSCy Schubert /* Removes a redirect rule from the hash table of redirect rules. */ 7183b9b51feSCy Schubert /* ------------------------------------------------------------------------ */ 7193b9b51feSCy Schubert void 7203b9b51feSCy Schubert ipf_nat_delrdr(softn, n) 7213b9b51feSCy Schubert ipf_nat_softc_t *softn; 7223b9b51feSCy Schubert ipnat_t *n; 7233b9b51feSCy Schubert { 7243b9b51feSCy Schubert if (n->in_odstatype == FRI_NORMAL) { 7253b9b51feSCy Schubert int k = count4bits(n->in_odstmsk); 7263b9b51feSCy Schubert ipf_inet_mask_del(k, &softn->ipf_nat_rdr_mask); 7273b9b51feSCy Schubert } else { 7283b9b51feSCy Schubert ipf_inet_mask_del(0, &softn->ipf_nat_rdr_mask); 7293b9b51feSCy Schubert } 7303b9b51feSCy Schubert if (n->in_rnext) 7313b9b51feSCy Schubert n->in_rnext->in_prnext = n->in_prnext; 7323b9b51feSCy Schubert *n->in_prnext = n->in_rnext; 7333b9b51feSCy Schubert n->in_use--; 7343b9b51feSCy Schubert } 7353b9b51feSCy Schubert 7363b9b51feSCy Schubert 7373b9b51feSCy Schubert /* ------------------------------------------------------------------------ */ 7383b9b51feSCy Schubert /* Function: ipf_nat_delmap */ 7393b9b51feSCy Schubert /* Returns: Nil */ 7403b9b51feSCy Schubert /* Parameters: n(I) - pointer to NAT rule to delete */ 7413b9b51feSCy Schubert /* */ 7423b9b51feSCy Schubert /* Removes a NAT map rule from the hash table of NAT map rules. */ 7433b9b51feSCy Schubert /* ------------------------------------------------------------------------ */ 7443b9b51feSCy Schubert void 7453b9b51feSCy Schubert ipf_nat_delmap(softn, n) 7463b9b51feSCy Schubert ipf_nat_softc_t *softn; 7473b9b51feSCy Schubert ipnat_t *n; 7483b9b51feSCy Schubert { 7493b9b51feSCy Schubert if (n->in_osrcatype == FRI_NORMAL) { 7503b9b51feSCy Schubert int k = count4bits(n->in_osrcmsk); 7513b9b51feSCy Schubert ipf_inet_mask_del(k, &softn->ipf_nat_map_mask); 7523b9b51feSCy Schubert } else { 7533b9b51feSCy Schubert ipf_inet_mask_del(0, &softn->ipf_nat_map_mask); 7543b9b51feSCy Schubert } 7553b9b51feSCy Schubert if (n->in_mnext != NULL) 7563b9b51feSCy Schubert n->in_mnext->in_pmnext = n->in_pmnext; 7573b9b51feSCy Schubert *n->in_pmnext = n->in_mnext; 7583b9b51feSCy Schubert n->in_use--; 7593b9b51feSCy Schubert } 7603b9b51feSCy Schubert 7613b9b51feSCy Schubert 7623b9b51feSCy Schubert /* ------------------------------------------------------------------------ */ 7633b9b51feSCy Schubert /* Function: ipf_nat_hostmap */ 7643b9b51feSCy Schubert /* Returns: struct hostmap* - NULL if no hostmap could be created, */ 7653b9b51feSCy Schubert /* else a pointer to the hostmapping to use */ 7663b9b51feSCy Schubert /* Parameters: np(I) - pointer to NAT rule */ 7673b9b51feSCy Schubert /* real(I) - real IP address */ 7683b9b51feSCy Schubert /* map(I) - mapped IP address */ 7693b9b51feSCy Schubert /* port(I) - destination port number */ 7703b9b51feSCy Schubert /* Write Locks: ipf_nat */ 7713b9b51feSCy Schubert /* */ 7723b9b51feSCy Schubert /* Check if an ip address has already been allocated for a given mapping */ 7733b9b51feSCy Schubert /* that is not doing port based translation. If is not yet allocated, then */ 7743b9b51feSCy Schubert /* create a new entry if a non-NULL NAT rule pointer has been supplied. */ 7753b9b51feSCy Schubert /* ------------------------------------------------------------------------ */ 7763b9b51feSCy Schubert static struct hostmap * 7773b9b51feSCy Schubert ipf_nat_hostmap(softn, np, src, dst, map, port) 7783b9b51feSCy Schubert ipf_nat_softc_t *softn; 7793b9b51feSCy Schubert ipnat_t *np; 7803b9b51feSCy Schubert struct in_addr src; 7813b9b51feSCy Schubert struct in_addr dst; 7823b9b51feSCy Schubert struct in_addr map; 7833b9b51feSCy Schubert u_32_t port; 7843b9b51feSCy Schubert { 7853b9b51feSCy Schubert hostmap_t *hm; 7863b9b51feSCy Schubert u_int hv, rhv; 7873b9b51feSCy Schubert 7883b9b51feSCy Schubert hv = (src.s_addr ^ dst.s_addr); 7893b9b51feSCy Schubert hv += src.s_addr; 7903b9b51feSCy Schubert hv += dst.s_addr; 7913b9b51feSCy Schubert rhv = hv; 7923b9b51feSCy Schubert hv %= softn->ipf_nat_hostmap_sz; 7933b9b51feSCy Schubert for (hm = softn->ipf_hm_maptable[hv]; hm; hm = hm->hm_hnext) 7943b9b51feSCy Schubert if ((hm->hm_osrcip.s_addr == src.s_addr) && 7953b9b51feSCy Schubert (hm->hm_odstip.s_addr == dst.s_addr) && 7963b9b51feSCy Schubert ((np == NULL) || (np == hm->hm_ipnat)) && 7973b9b51feSCy Schubert ((port == 0) || (port == hm->hm_port))) { 7983b9b51feSCy Schubert softn->ipf_nat_stats.ns_hm_addref++; 7993b9b51feSCy Schubert hm->hm_ref++; 8003b9b51feSCy Schubert return hm; 8013b9b51feSCy Schubert } 8023b9b51feSCy Schubert 8033b9b51feSCy Schubert if (np == NULL) { 8043b9b51feSCy Schubert softn->ipf_nat_stats.ns_hm_nullnp++; 8053b9b51feSCy Schubert return NULL; 8063b9b51feSCy Schubert } 8073b9b51feSCy Schubert 8083b9b51feSCy Schubert KMALLOC(hm, hostmap_t *); 8093b9b51feSCy Schubert if (hm) { 8103b9b51feSCy Schubert hm->hm_next = softn->ipf_hm_maplist; 8113b9b51feSCy Schubert hm->hm_pnext = &softn->ipf_hm_maplist; 8123b9b51feSCy Schubert if (softn->ipf_hm_maplist != NULL) 8133b9b51feSCy Schubert softn->ipf_hm_maplist->hm_pnext = &hm->hm_next; 8143b9b51feSCy Schubert softn->ipf_hm_maplist = hm; 8153b9b51feSCy Schubert hm->hm_hnext = softn->ipf_hm_maptable[hv]; 8163b9b51feSCy Schubert hm->hm_phnext = softn->ipf_hm_maptable + hv; 8173b9b51feSCy Schubert if (softn->ipf_hm_maptable[hv] != NULL) 8183b9b51feSCy Schubert softn->ipf_hm_maptable[hv]->hm_phnext = &hm->hm_hnext; 8193b9b51feSCy Schubert softn->ipf_hm_maptable[hv] = hm; 8203b9b51feSCy Schubert hm->hm_ipnat = np; 8213b9b51feSCy Schubert np->in_use++; 8223b9b51feSCy Schubert hm->hm_osrcip = src; 8233b9b51feSCy Schubert hm->hm_odstip = dst; 8243b9b51feSCy Schubert hm->hm_nsrcip = map; 8253b9b51feSCy Schubert hm->hm_ndstip.s_addr = 0; 8263b9b51feSCy Schubert hm->hm_ref = 1; 8273b9b51feSCy Schubert hm->hm_port = port; 8283b9b51feSCy Schubert hm->hm_hv = rhv; 8293b9b51feSCy Schubert hm->hm_v = 4; 8303b9b51feSCy Schubert softn->ipf_nat_stats.ns_hm_new++; 8313b9b51feSCy Schubert } else { 8323b9b51feSCy Schubert softn->ipf_nat_stats.ns_hm_newfail++; 8333b9b51feSCy Schubert } 8343b9b51feSCy Schubert return hm; 8353b9b51feSCy Schubert } 8363b9b51feSCy Schubert 8373b9b51feSCy Schubert 8383b9b51feSCy Schubert /* ------------------------------------------------------------------------ */ 8393b9b51feSCy Schubert /* Function: ipf_nat_hostmapdel */ 8403b9b51feSCy Schubert /* Returns: Nil */ 8413b9b51feSCy Schubert /* Parameters: hmp(I) - pointer to hostmap structure pointer */ 8423b9b51feSCy Schubert /* Write Locks: ipf_nat */ 8433b9b51feSCy Schubert /* */ 8443b9b51feSCy Schubert /* Decrement the references to this hostmap structure by one. If this */ 8453b9b51feSCy Schubert /* reaches zero then remove it and free it. */ 8463b9b51feSCy Schubert /* ------------------------------------------------------------------------ */ 8473b9b51feSCy Schubert void 8483b9b51feSCy Schubert ipf_nat_hostmapdel(softc, hmp) 8493b9b51feSCy Schubert ipf_main_softc_t *softc; 8503b9b51feSCy Schubert struct hostmap **hmp; 8513b9b51feSCy Schubert { 8523b9b51feSCy Schubert struct hostmap *hm; 8533b9b51feSCy Schubert 8543b9b51feSCy Schubert hm = *hmp; 8553b9b51feSCy Schubert *hmp = NULL; 8563b9b51feSCy Schubert 8573b9b51feSCy Schubert hm->hm_ref--; 8583b9b51feSCy Schubert if (hm->hm_ref == 0) { 8593b9b51feSCy Schubert ipf_nat_rule_deref(softc, &hm->hm_ipnat); 8603b9b51feSCy Schubert if (hm->hm_hnext) 8613b9b51feSCy Schubert hm->hm_hnext->hm_phnext = hm->hm_phnext; 8623b9b51feSCy Schubert *hm->hm_phnext = hm->hm_hnext; 8633b9b51feSCy Schubert if (hm->hm_next) 8643b9b51feSCy Schubert hm->hm_next->hm_pnext = hm->hm_pnext; 8653b9b51feSCy Schubert *hm->hm_pnext = hm->hm_next; 8663b9b51feSCy Schubert KFREE(hm); 8673b9b51feSCy Schubert } 8683b9b51feSCy Schubert } 8693b9b51feSCy Schubert 8703b9b51feSCy Schubert 8713b9b51feSCy Schubert /* ------------------------------------------------------------------------ */ 8723b9b51feSCy Schubert /* Function: ipf_fix_outcksum */ 8733b9b51feSCy Schubert /* Returns: Nil */ 8743b9b51feSCy Schubert /* Parameters: fin(I) - pointer to packet information */ 8753b9b51feSCy Schubert /* sp(I) - location of 16bit checksum to update */ 8763b9b51feSCy Schubert /* n((I) - amount to adjust checksum by */ 8773b9b51feSCy Schubert /* */ 8783b9b51feSCy Schubert /* Adjusts the 16bit checksum by "n" for packets going out. */ 8793b9b51feSCy Schubert /* ------------------------------------------------------------------------ */ 8803b9b51feSCy Schubert void 8813b9b51feSCy Schubert ipf_fix_outcksum(cksum, sp, n, partial) 8823b9b51feSCy Schubert int cksum; 8833b9b51feSCy Schubert u_short *sp; 8843b9b51feSCy Schubert u_32_t n, partial; 8853b9b51feSCy Schubert { 8863b9b51feSCy Schubert u_short sumshort; 8873b9b51feSCy Schubert u_32_t sum1; 8883b9b51feSCy Schubert 8893b9b51feSCy Schubert if (n == 0) 8903b9b51feSCy Schubert return; 8913b9b51feSCy Schubert 8923b9b51feSCy Schubert if (cksum == 4) { 8933b9b51feSCy Schubert *sp = 0; 8943b9b51feSCy Schubert return; 8953b9b51feSCy Schubert } 8963b9b51feSCy Schubert if (cksum == 2) { 8973b9b51feSCy Schubert sum1 = partial; 8983b9b51feSCy Schubert sum1 = (sum1 & 0xffff) + (sum1 >> 16); 8993b9b51feSCy Schubert *sp = htons(sum1); 9003b9b51feSCy Schubert return; 9013b9b51feSCy Schubert } 9023b9b51feSCy Schubert sum1 = (~ntohs(*sp)) & 0xffff; 9033b9b51feSCy Schubert sum1 += (n); 9043b9b51feSCy Schubert sum1 = (sum1 >> 16) + (sum1 & 0xffff); 9053b9b51feSCy Schubert /* Again */ 9063b9b51feSCy Schubert sum1 = (sum1 >> 16) + (sum1 & 0xffff); 9073b9b51feSCy Schubert sumshort = ~(u_short)sum1; 9083b9b51feSCy Schubert *(sp) = htons(sumshort); 9093b9b51feSCy Schubert } 9103b9b51feSCy Schubert 9113b9b51feSCy Schubert 9123b9b51feSCy Schubert /* ------------------------------------------------------------------------ */ 9133b9b51feSCy Schubert /* Function: ipf_fix_incksum */ 9143b9b51feSCy Schubert /* Returns: Nil */ 9153b9b51feSCy Schubert /* Parameters: fin(I) - pointer to packet information */ 9163b9b51feSCy Schubert /* sp(I) - location of 16bit checksum to update */ 9173b9b51feSCy Schubert /* n((I) - amount to adjust checksum by */ 9183b9b51feSCy Schubert /* */ 9193b9b51feSCy Schubert /* Adjusts the 16bit checksum by "n" for packets going in. */ 9203b9b51feSCy Schubert /* ------------------------------------------------------------------------ */ 9213b9b51feSCy Schubert void 9223b9b51feSCy Schubert ipf_fix_incksum(cksum, sp, n, partial) 9233b9b51feSCy Schubert int cksum; 9243b9b51feSCy Schubert u_short *sp; 9253b9b51feSCy Schubert u_32_t n, partial; 9263b9b51feSCy Schubert { 9273b9b51feSCy Schubert u_short sumshort; 9283b9b51feSCy Schubert u_32_t sum1; 9293b9b51feSCy Schubert 9303b9b51feSCy Schubert if (n == 0) 9313b9b51feSCy Schubert return; 9323b9b51feSCy Schubert 9333b9b51feSCy Schubert if (cksum == 4) { 9343b9b51feSCy Schubert *sp = 0; 9353b9b51feSCy Schubert return; 9363b9b51feSCy Schubert } 9373b9b51feSCy Schubert if (cksum == 2) { 9383b9b51feSCy Schubert sum1 = partial; 9393b9b51feSCy Schubert sum1 = (sum1 & 0xffff) + (sum1 >> 16); 9403b9b51feSCy Schubert *sp = htons(sum1); 9413b9b51feSCy Schubert return; 9423b9b51feSCy Schubert } 9433b9b51feSCy Schubert 9443b9b51feSCy Schubert sum1 = (~ntohs(*sp)) & 0xffff; 9453b9b51feSCy Schubert sum1 += ~(n) & 0xffff; 9463b9b51feSCy Schubert sum1 = (sum1 >> 16) + (sum1 & 0xffff); 9473b9b51feSCy Schubert /* Again */ 9483b9b51feSCy Schubert sum1 = (sum1 >> 16) + (sum1 & 0xffff); 9493b9b51feSCy Schubert sumshort = ~(u_short)sum1; 9503b9b51feSCy Schubert *(sp) = htons(sumshort); 9513b9b51feSCy Schubert } 9523b9b51feSCy Schubert 9533b9b51feSCy Schubert 9543b9b51feSCy Schubert /* ------------------------------------------------------------------------ */ 9553b9b51feSCy Schubert /* Function: ipf_fix_datacksum */ 9563b9b51feSCy Schubert /* Returns: Nil */ 9573b9b51feSCy Schubert /* Parameters: sp(I) - location of 16bit checksum to update */ 9583b9b51feSCy Schubert /* n((I) - amount to adjust checksum by */ 9593b9b51feSCy Schubert /* */ 9603b9b51feSCy Schubert /* Fix_datacksum is used *only* for the adjustments of checksums in the */ 9613b9b51feSCy Schubert /* data section of an IP packet. */ 9623b9b51feSCy Schubert /* */ 9633b9b51feSCy Schubert /* The only situation in which you need to do this is when NAT'ing an */ 9643b9b51feSCy Schubert /* ICMP error message. Such a message, contains in its body the IP header */ 9653b9b51feSCy Schubert /* of the original IP packet, that causes the error. */ 9663b9b51feSCy Schubert /* */ 9673b9b51feSCy Schubert /* You can't use fix_incksum or fix_outcksum in that case, because for the */ 9683b9b51feSCy Schubert /* kernel the data section of the ICMP error is just data, and no special */ 9693b9b51feSCy Schubert /* processing like hardware cksum or ntohs processing have been done by the */ 9703b9b51feSCy Schubert /* kernel on the data section. */ 9713b9b51feSCy Schubert /* ------------------------------------------------------------------------ */ 9723b9b51feSCy Schubert void 9733b9b51feSCy Schubert ipf_fix_datacksum(sp, n) 9743b9b51feSCy Schubert u_short *sp; 9753b9b51feSCy Schubert u_32_t n; 9763b9b51feSCy Schubert { 9773b9b51feSCy Schubert u_short sumshort; 9783b9b51feSCy Schubert u_32_t sum1; 9793b9b51feSCy Schubert 9803b9b51feSCy Schubert if (n == 0) 9813b9b51feSCy Schubert return; 9823b9b51feSCy Schubert 9833b9b51feSCy Schubert sum1 = (~ntohs(*sp)) & 0xffff; 9843b9b51feSCy Schubert sum1 += (n); 9853b9b51feSCy Schubert sum1 = (sum1 >> 16) + (sum1 & 0xffff); 9863b9b51feSCy Schubert /* Again */ 9873b9b51feSCy Schubert sum1 = (sum1 >> 16) + (sum1 & 0xffff); 9883b9b51feSCy Schubert sumshort = ~(u_short)sum1; 9893b9b51feSCy Schubert *(sp) = htons(sumshort); 9903b9b51feSCy Schubert } 9913b9b51feSCy Schubert 9923b9b51feSCy Schubert 9933b9b51feSCy Schubert /* ------------------------------------------------------------------------ */ 9943b9b51feSCy Schubert /* Function: ipf_nat_ioctl */ 9953b9b51feSCy Schubert /* Returns: int - 0 == success, != 0 == failure */ 9963b9b51feSCy Schubert /* Parameters: softc(I) - pointer to soft context main structure */ 9973b9b51feSCy Schubert /* data(I) - pointer to ioctl data */ 9983b9b51feSCy Schubert /* cmd(I) - ioctl command integer */ 9993b9b51feSCy Schubert /* mode(I) - file mode bits used with open */ 10003b9b51feSCy Schubert /* uid(I) - uid of calling process */ 10013b9b51feSCy Schubert /* ctx(I) - pointer used as key for finding context */ 10023b9b51feSCy Schubert /* */ 10033b9b51feSCy Schubert /* Processes an ioctl call made to operate on the IP Filter NAT device. */ 10043b9b51feSCy Schubert /* ------------------------------------------------------------------------ */ 10053b9b51feSCy Schubert int 10063b9b51feSCy Schubert ipf_nat_ioctl(softc, data, cmd, mode, uid, ctx) 10073b9b51feSCy Schubert ipf_main_softc_t *softc; 10083b9b51feSCy Schubert ioctlcmd_t cmd; 10093b9b51feSCy Schubert caddr_t data; 10103b9b51feSCy Schubert int mode, uid; 10113b9b51feSCy Schubert void *ctx; 10123b9b51feSCy Schubert { 10133b9b51feSCy Schubert ipf_nat_softc_t *softn = softc->ipf_nat_soft; 10143b9b51feSCy Schubert int error = 0, ret, arg, getlock; 10153b9b51feSCy Schubert ipnat_t *nat, *nt, *n; 10163b9b51feSCy Schubert ipnat_t natd; 10173b9b51feSCy Schubert SPL_INT(s); 10183b9b51feSCy Schubert 10193b9b51feSCy Schubert #if !SOLARIS && defined(_KERNEL) 10203b9b51feSCy Schubert # if NETBSD_GE_REV(399002000) 10213b9b51feSCy Schubert if ((mode & FWRITE) && 10223b9b51feSCy Schubert kauth_authorize_network(curlwp->l_cred, KAUTH_NETWORK_FIREWALL, 10233b9b51feSCy Schubert KAUTH_REQ_NETWORK_FIREWALL_FW, 10243b9b51feSCy Schubert NULL, NULL, NULL)) 10253b9b51feSCy Schubert # else 10263b9b51feSCy Schubert # if defined(__FreeBSD__) 10273b9b51feSCy Schubert if (securelevel_ge(curthread->td_ucred, 3) && (mode & FWRITE)) 10283b9b51feSCy Schubert # else 10293b9b51feSCy Schubert if ((securelevel >= 3) && (mode & FWRITE)) 10303b9b51feSCy Schubert # endif 10313b9b51feSCy Schubert # endif 10323b9b51feSCy Schubert { 10333b9b51feSCy Schubert IPFERROR(60001); 10343b9b51feSCy Schubert return EPERM; 10353b9b51feSCy Schubert } 10363b9b51feSCy Schubert #endif 10373b9b51feSCy Schubert 10383b9b51feSCy Schubert getlock = (mode & NAT_LOCKHELD) ? 0 : 1; 10393b9b51feSCy Schubert 10403b9b51feSCy Schubert n = NULL; 10413b9b51feSCy Schubert nt = NULL; 10423b9b51feSCy Schubert nat = NULL; 10433b9b51feSCy Schubert 10443b9b51feSCy Schubert if ((cmd == (ioctlcmd_t)SIOCADNAT) || (cmd == (ioctlcmd_t)SIOCRMNAT) || 10453b9b51feSCy Schubert (cmd == (ioctlcmd_t)SIOCPURGENAT)) { 10463b9b51feSCy Schubert if (mode & NAT_SYSSPACE) { 10473b9b51feSCy Schubert bcopy(data, (char *)&natd, sizeof(natd)); 10483b9b51feSCy Schubert nat = &natd; 10493b9b51feSCy Schubert error = 0; 10503b9b51feSCy Schubert } else { 10513b9b51feSCy Schubert bzero(&natd, sizeof(natd)); 10523b9b51feSCy Schubert error = ipf_inobj(softc, data, NULL, &natd, 10533b9b51feSCy Schubert IPFOBJ_IPNAT); 10543b9b51feSCy Schubert if (error != 0) 10553b9b51feSCy Schubert goto done; 10563b9b51feSCy Schubert 10573b9b51feSCy Schubert if (natd.in_size < sizeof(ipnat_t)) { 10583b9b51feSCy Schubert error = EINVAL; 10593b9b51feSCy Schubert goto done; 10603b9b51feSCy Schubert } 10613b9b51feSCy Schubert KMALLOCS(nt, ipnat_t *, natd.in_size); 10623b9b51feSCy Schubert if (nt == NULL) { 10633b9b51feSCy Schubert IPFERROR(60070); 10643b9b51feSCy Schubert error = ENOMEM; 10653b9b51feSCy Schubert goto done; 10663b9b51feSCy Schubert } 10673b9b51feSCy Schubert bzero(nt, natd.in_size); 10683b9b51feSCy Schubert error = ipf_inobjsz(softc, data, nt, IPFOBJ_IPNAT, 10693b9b51feSCy Schubert natd.in_size); 10703b9b51feSCy Schubert if (error) 10713b9b51feSCy Schubert goto done; 10723b9b51feSCy Schubert nat = nt; 10733b9b51feSCy Schubert } 10743b9b51feSCy Schubert 10753b9b51feSCy Schubert /* 10763b9b51feSCy Schubert * For add/delete, look to see if the NAT entry is 10773b9b51feSCy Schubert * already present 10783b9b51feSCy Schubert */ 10793b9b51feSCy Schubert nat->in_flags &= IPN_USERFLAGS; 10803b9b51feSCy Schubert if ((nat->in_redir & NAT_MAPBLK) == 0) { 10813b9b51feSCy Schubert if (nat->in_osrcatype == FRI_NORMAL || 10823b9b51feSCy Schubert nat->in_osrcatype == FRI_NONE) 10833b9b51feSCy Schubert nat->in_osrcaddr &= nat->in_osrcmsk; 10843b9b51feSCy Schubert if (nat->in_odstatype == FRI_NORMAL || 10853b9b51feSCy Schubert nat->in_odstatype == FRI_NONE) 10863b9b51feSCy Schubert nat->in_odstaddr &= nat->in_odstmsk; 10873b9b51feSCy Schubert if ((nat->in_flags & (IPN_SPLIT|IPN_SIPRANGE)) == 0) { 10883b9b51feSCy Schubert if (nat->in_nsrcatype == FRI_NORMAL) 10893b9b51feSCy Schubert nat->in_nsrcaddr &= nat->in_nsrcmsk; 10903b9b51feSCy Schubert if (nat->in_ndstatype == FRI_NORMAL) 10913b9b51feSCy Schubert nat->in_ndstaddr &= nat->in_ndstmsk; 10923b9b51feSCy Schubert } 10933b9b51feSCy Schubert } 10943b9b51feSCy Schubert 10953b9b51feSCy Schubert error = ipf_nat_rule_init(softc, softn, nat); 10963b9b51feSCy Schubert if (error != 0) 10973b9b51feSCy Schubert goto done; 10983b9b51feSCy Schubert 10993b9b51feSCy Schubert MUTEX_ENTER(&softn->ipf_nat_io); 11003b9b51feSCy Schubert for (n = softn->ipf_nat_list; n != NULL; n = n->in_next) 11013b9b51feSCy Schubert if (ipf_nat_cmp_rules(nat, n) == 0) 11023b9b51feSCy Schubert break; 11033b9b51feSCy Schubert } 11043b9b51feSCy Schubert 11053b9b51feSCy Schubert switch (cmd) 11063b9b51feSCy Schubert { 11073b9b51feSCy Schubert #ifdef IPFILTER_LOG 11083b9b51feSCy Schubert case SIOCIPFFB : 11093b9b51feSCy Schubert { 11103b9b51feSCy Schubert int tmp; 11113b9b51feSCy Schubert 11123b9b51feSCy Schubert if (!(mode & FWRITE)) { 11133b9b51feSCy Schubert IPFERROR(60002); 11143b9b51feSCy Schubert error = EPERM; 11153b9b51feSCy Schubert } else { 11163b9b51feSCy Schubert tmp = ipf_log_clear(softc, IPL_LOGNAT); 11173b9b51feSCy Schubert error = BCOPYOUT(&tmp, data, sizeof(tmp)); 11183b9b51feSCy Schubert if (error != 0) { 11193b9b51feSCy Schubert IPFERROR(60057); 11203b9b51feSCy Schubert error = EFAULT; 11213b9b51feSCy Schubert } 11223b9b51feSCy Schubert } 11233b9b51feSCy Schubert break; 11243b9b51feSCy Schubert } 11253b9b51feSCy Schubert 11263b9b51feSCy Schubert case SIOCSETLG : 11273b9b51feSCy Schubert if (!(mode & FWRITE)) { 11283b9b51feSCy Schubert IPFERROR(60003); 11293b9b51feSCy Schubert error = EPERM; 11303b9b51feSCy Schubert } else { 11313b9b51feSCy Schubert error = BCOPYIN(data, &softn->ipf_nat_logging, 11323b9b51feSCy Schubert sizeof(softn->ipf_nat_logging)); 11333b9b51feSCy Schubert if (error != 0) 11343b9b51feSCy Schubert error = EFAULT; 11353b9b51feSCy Schubert } 11363b9b51feSCy Schubert break; 11373b9b51feSCy Schubert 11383b9b51feSCy Schubert case SIOCGETLG : 11393b9b51feSCy Schubert error = BCOPYOUT(&softn->ipf_nat_logging, data, 11403b9b51feSCy Schubert sizeof(softn->ipf_nat_logging)); 11413b9b51feSCy Schubert if (error != 0) { 11423b9b51feSCy Schubert IPFERROR(60004); 11433b9b51feSCy Schubert error = EFAULT; 11443b9b51feSCy Schubert } 11453b9b51feSCy Schubert break; 11463b9b51feSCy Schubert 11473b9b51feSCy Schubert case FIONREAD : 11483b9b51feSCy Schubert arg = ipf_log_bytesused(softc, IPL_LOGNAT); 11493b9b51feSCy Schubert error = BCOPYOUT(&arg, data, sizeof(arg)); 11503b9b51feSCy Schubert if (error != 0) { 11513b9b51feSCy Schubert IPFERROR(60005); 11523b9b51feSCy Schubert error = EFAULT; 11533b9b51feSCy Schubert } 11543b9b51feSCy Schubert break; 11553b9b51feSCy Schubert #endif 11563b9b51feSCy Schubert case SIOCADNAT : 11573b9b51feSCy Schubert if (!(mode & FWRITE)) { 11583b9b51feSCy Schubert IPFERROR(60006); 11593b9b51feSCy Schubert error = EPERM; 11603b9b51feSCy Schubert } else if (n != NULL) { 11613b9b51feSCy Schubert natd.in_flineno = n->in_flineno; 11623b9b51feSCy Schubert (void) ipf_outobj(softc, data, &natd, IPFOBJ_IPNAT); 11633b9b51feSCy Schubert IPFERROR(60007); 11643b9b51feSCy Schubert error = EEXIST; 11653b9b51feSCy Schubert } else if (nt == NULL) { 11663b9b51feSCy Schubert IPFERROR(60008); 11673b9b51feSCy Schubert error = ENOMEM; 11683b9b51feSCy Schubert } 11693b9b51feSCy Schubert if (error != 0) { 11703b9b51feSCy Schubert MUTEX_EXIT(&softn->ipf_nat_io); 11713b9b51feSCy Schubert break; 11723b9b51feSCy Schubert } 11733b9b51feSCy Schubert if (nat != nt) 11743b9b51feSCy Schubert bcopy((char *)nat, (char *)nt, sizeof(*n)); 11753b9b51feSCy Schubert error = ipf_nat_siocaddnat(softc, softn, nt, getlock); 11763b9b51feSCy Schubert MUTEX_EXIT(&softn->ipf_nat_io); 11773b9b51feSCy Schubert if (error == 0) { 11783b9b51feSCy Schubert nat = NULL; 11793b9b51feSCy Schubert nt = NULL; 11803b9b51feSCy Schubert } 11813b9b51feSCy Schubert break; 11823b9b51feSCy Schubert 11833b9b51feSCy Schubert case SIOCRMNAT : 11843b9b51feSCy Schubert case SIOCPURGENAT : 11853b9b51feSCy Schubert if (!(mode & FWRITE)) { 11863b9b51feSCy Schubert IPFERROR(60009); 11873b9b51feSCy Schubert error = EPERM; 11883b9b51feSCy Schubert n = NULL; 11893b9b51feSCy Schubert } else if (n == NULL) { 11903b9b51feSCy Schubert IPFERROR(60010); 11913b9b51feSCy Schubert error = ESRCH; 11923b9b51feSCy Schubert } 11933b9b51feSCy Schubert 11943b9b51feSCy Schubert if (error != 0) { 11953b9b51feSCy Schubert MUTEX_EXIT(&softn->ipf_nat_io); 11963b9b51feSCy Schubert break; 11973b9b51feSCy Schubert } 11983b9b51feSCy Schubert if (cmd == (ioctlcmd_t)SIOCPURGENAT) { 11993b9b51feSCy Schubert error = ipf_outobjsz(softc, data, n, IPFOBJ_IPNAT, 12003b9b51feSCy Schubert n->in_size); 12013b9b51feSCy Schubert if (error) { 12023b9b51feSCy Schubert MUTEX_EXIT(&softn->ipf_nat_io); 12033b9b51feSCy Schubert goto done; 12043b9b51feSCy Schubert } 12053b9b51feSCy Schubert n->in_flags |= IPN_PURGE; 12063b9b51feSCy Schubert } 12073b9b51feSCy Schubert ipf_nat_siocdelnat(softc, softn, n, getlock); 12083b9b51feSCy Schubert 12093b9b51feSCy Schubert MUTEX_EXIT(&softn->ipf_nat_io); 12103b9b51feSCy Schubert n = NULL; 12113b9b51feSCy Schubert break; 12123b9b51feSCy Schubert 12133b9b51feSCy Schubert case SIOCGNATS : 12143b9b51feSCy Schubert { 12153b9b51feSCy Schubert natstat_t *nsp = &softn->ipf_nat_stats; 12163b9b51feSCy Schubert 12173b9b51feSCy Schubert nsp->ns_side[0].ns_table = softn->ipf_nat_table[0]; 12183b9b51feSCy Schubert nsp->ns_side[1].ns_table = softn->ipf_nat_table[1]; 12193b9b51feSCy Schubert nsp->ns_list = softn->ipf_nat_list; 12203b9b51feSCy Schubert nsp->ns_maptable = softn->ipf_hm_maptable; 12213b9b51feSCy Schubert nsp->ns_maplist = softn->ipf_hm_maplist; 12223b9b51feSCy Schubert nsp->ns_nattab_sz = softn->ipf_nat_table_sz; 12233b9b51feSCy Schubert nsp->ns_nattab_max = softn->ipf_nat_table_max; 12243b9b51feSCy Schubert nsp->ns_rultab_sz = softn->ipf_nat_maprules_sz; 12253b9b51feSCy Schubert nsp->ns_rdrtab_sz = softn->ipf_nat_rdrrules_sz; 12263b9b51feSCy Schubert nsp->ns_hostmap_sz = softn->ipf_nat_hostmap_sz; 12273b9b51feSCy Schubert nsp->ns_instances = softn->ipf_nat_instances; 12283b9b51feSCy Schubert nsp->ns_ticks = softc->ipf_ticks; 12293b9b51feSCy Schubert #ifdef IPFILTER_LOGGING 12303b9b51feSCy Schubert nsp->ns_log_ok = ipf_log_logok(softc, IPF_LOGNAT); 12313b9b51feSCy Schubert nsp->ns_log_fail = ipf_log_failures(softc, IPF_LOGNAT); 12323b9b51feSCy Schubert #else 12333b9b51feSCy Schubert nsp->ns_log_ok = 0; 12343b9b51feSCy Schubert nsp->ns_log_fail = 0; 12353b9b51feSCy Schubert #endif 12363b9b51feSCy Schubert error = ipf_outobj(softc, data, nsp, IPFOBJ_NATSTAT); 12373b9b51feSCy Schubert break; 12383b9b51feSCy Schubert } 12393b9b51feSCy Schubert 12403b9b51feSCy Schubert case SIOCGNATL : 12413b9b51feSCy Schubert { 12423b9b51feSCy Schubert natlookup_t nl; 12433b9b51feSCy Schubert 12443b9b51feSCy Schubert error = ipf_inobj(softc, data, NULL, &nl, IPFOBJ_NATLOOKUP); 12453b9b51feSCy Schubert if (error == 0) { 12463b9b51feSCy Schubert void *ptr; 12473b9b51feSCy Schubert 12483b9b51feSCy Schubert if (getlock) { 12493b9b51feSCy Schubert READ_ENTER(&softc->ipf_nat); 12503b9b51feSCy Schubert } 12513b9b51feSCy Schubert 12523b9b51feSCy Schubert switch (nl.nl_v) 12533b9b51feSCy Schubert { 12543b9b51feSCy Schubert case 4 : 12553b9b51feSCy Schubert ptr = ipf_nat_lookupredir(&nl); 12563b9b51feSCy Schubert break; 12573b9b51feSCy Schubert #ifdef USE_INET6 12583b9b51feSCy Schubert case 6 : 12593b9b51feSCy Schubert ptr = ipf_nat6_lookupredir(&nl); 12603b9b51feSCy Schubert break; 12613b9b51feSCy Schubert #endif 12623b9b51feSCy Schubert default: 12633b9b51feSCy Schubert ptr = NULL; 12643b9b51feSCy Schubert break; 12653b9b51feSCy Schubert } 12663b9b51feSCy Schubert 12673b9b51feSCy Schubert if (getlock) { 12683b9b51feSCy Schubert RWLOCK_EXIT(&softc->ipf_nat); 12693b9b51feSCy Schubert } 12703b9b51feSCy Schubert if (ptr != NULL) { 12713b9b51feSCy Schubert error = ipf_outobj(softc, data, &nl, 12723b9b51feSCy Schubert IPFOBJ_NATLOOKUP); 12733b9b51feSCy Schubert } else { 12743b9b51feSCy Schubert IPFERROR(60011); 12753b9b51feSCy Schubert error = ESRCH; 12763b9b51feSCy Schubert } 12773b9b51feSCy Schubert } 12783b9b51feSCy Schubert break; 12793b9b51feSCy Schubert } 12803b9b51feSCy Schubert 12813b9b51feSCy Schubert case SIOCIPFFL : /* old SIOCFLNAT & SIOCCNATL */ 12823b9b51feSCy Schubert if (!(mode & FWRITE)) { 12833b9b51feSCy Schubert IPFERROR(60012); 12843b9b51feSCy Schubert error = EPERM; 12853b9b51feSCy Schubert break; 12863b9b51feSCy Schubert } 12873b9b51feSCy Schubert if (getlock) { 12883b9b51feSCy Schubert WRITE_ENTER(&softc->ipf_nat); 12893b9b51feSCy Schubert } 12903b9b51feSCy Schubert 12913b9b51feSCy Schubert error = BCOPYIN(data, &arg, sizeof(arg)); 12923b9b51feSCy Schubert if (error != 0) { 12933b9b51feSCy Schubert IPFERROR(60013); 12943b9b51feSCy Schubert error = EFAULT; 12953b9b51feSCy Schubert } else { 12963b9b51feSCy Schubert if (arg == 0) 12973b9b51feSCy Schubert ret = ipf_nat_flushtable(softc, softn); 12983b9b51feSCy Schubert else if (arg == 1) 12993b9b51feSCy Schubert ret = ipf_nat_clearlist(softc, softn); 13003b9b51feSCy Schubert else 13013b9b51feSCy Schubert ret = ipf_nat_extraflush(softc, softn, arg); 13023b9b51feSCy Schubert ipf_proxy_flush(softc->ipf_proxy_soft, arg); 13033b9b51feSCy Schubert } 13043b9b51feSCy Schubert 13053b9b51feSCy Schubert if (getlock) { 13063b9b51feSCy Schubert RWLOCK_EXIT(&softc->ipf_nat); 13073b9b51feSCy Schubert } 13083b9b51feSCy Schubert if (error == 0) { 13093b9b51feSCy Schubert error = BCOPYOUT(&ret, data, sizeof(ret)); 13103b9b51feSCy Schubert } 13113b9b51feSCy Schubert break; 13123b9b51feSCy Schubert 13133b9b51feSCy Schubert case SIOCMATCHFLUSH : 13143b9b51feSCy Schubert if (!(mode & FWRITE)) { 13153b9b51feSCy Schubert IPFERROR(60014); 13163b9b51feSCy Schubert error = EPERM; 13173b9b51feSCy Schubert break; 13183b9b51feSCy Schubert } 13193b9b51feSCy Schubert if (getlock) { 13203b9b51feSCy Schubert WRITE_ENTER(&softc->ipf_nat); 13213b9b51feSCy Schubert } 13223b9b51feSCy Schubert 13233b9b51feSCy Schubert error = ipf_nat_matchflush(softc, softn, data); 13243b9b51feSCy Schubert 13253b9b51feSCy Schubert if (getlock) { 13263b9b51feSCy Schubert RWLOCK_EXIT(&softc->ipf_nat); 13273b9b51feSCy Schubert } 13283b9b51feSCy Schubert break; 13293b9b51feSCy Schubert 13303b9b51feSCy Schubert case SIOCPROXY : 13313b9b51feSCy Schubert error = ipf_proxy_ioctl(softc, data, cmd, mode, ctx); 13323b9b51feSCy Schubert break; 13333b9b51feSCy Schubert 13343b9b51feSCy Schubert case SIOCSTLCK : 13353b9b51feSCy Schubert if (!(mode & FWRITE)) { 13363b9b51feSCy Schubert IPFERROR(60015); 13373b9b51feSCy Schubert error = EPERM; 13383b9b51feSCy Schubert } else { 13393b9b51feSCy Schubert error = ipf_lock(data, &softn->ipf_nat_lock); 13403b9b51feSCy Schubert } 13413b9b51feSCy Schubert break; 13423b9b51feSCy Schubert 13433b9b51feSCy Schubert case SIOCSTPUT : 13443b9b51feSCy Schubert if ((mode & FWRITE) != 0) { 13453b9b51feSCy Schubert error = ipf_nat_putent(softc, data, getlock); 13463b9b51feSCy Schubert } else { 13473b9b51feSCy Schubert IPFERROR(60016); 13483b9b51feSCy Schubert error = EACCES; 13493b9b51feSCy Schubert } 13503b9b51feSCy Schubert break; 13513b9b51feSCy Schubert 13523b9b51feSCy Schubert case SIOCSTGSZ : 13533b9b51feSCy Schubert if (softn->ipf_nat_lock) { 13543b9b51feSCy Schubert error = ipf_nat_getsz(softc, data, getlock); 13553b9b51feSCy Schubert } else { 13563b9b51feSCy Schubert IPFERROR(60017); 13573b9b51feSCy Schubert error = EACCES; 13583b9b51feSCy Schubert } 13593b9b51feSCy Schubert break; 13603b9b51feSCy Schubert 13613b9b51feSCy Schubert case SIOCSTGET : 13623b9b51feSCy Schubert if (softn->ipf_nat_lock) { 13633b9b51feSCy Schubert error = ipf_nat_getent(softc, data, getlock); 13643b9b51feSCy Schubert } else { 13653b9b51feSCy Schubert IPFERROR(60018); 13663b9b51feSCy Schubert error = EACCES; 13673b9b51feSCy Schubert } 13683b9b51feSCy Schubert break; 13693b9b51feSCy Schubert 13703b9b51feSCy Schubert case SIOCGENITER : 13713b9b51feSCy Schubert { 13723b9b51feSCy Schubert ipfgeniter_t iter; 13733b9b51feSCy Schubert ipftoken_t *token; 13743b9b51feSCy Schubert ipfobj_t obj; 13753b9b51feSCy Schubert 13763b9b51feSCy Schubert error = ipf_inobj(softc, data, &obj, &iter, IPFOBJ_GENITER); 13773b9b51feSCy Schubert if (error != 0) 13783b9b51feSCy Schubert break; 13793b9b51feSCy Schubert 13803b9b51feSCy Schubert SPL_SCHED(s); 13813b9b51feSCy Schubert token = ipf_token_find(softc, iter.igi_type, uid, ctx); 13823b9b51feSCy Schubert if (token != NULL) { 13833b9b51feSCy Schubert error = ipf_nat_iterator(softc, token, &iter, &obj); 13843b9b51feSCy Schubert WRITE_ENTER(&softc->ipf_tokens); 13853b9b51feSCy Schubert ipf_token_deref(softc, token); 13863b9b51feSCy Schubert RWLOCK_EXIT(&softc->ipf_tokens); 13873b9b51feSCy Schubert } 13883b9b51feSCy Schubert SPL_X(s); 13893b9b51feSCy Schubert break; 13903b9b51feSCy Schubert } 13913b9b51feSCy Schubert 13923b9b51feSCy Schubert case SIOCIPFDELTOK : 13933b9b51feSCy Schubert error = BCOPYIN(data, &arg, sizeof(arg)); 13943b9b51feSCy Schubert if (error == 0) { 13953b9b51feSCy Schubert SPL_SCHED(s); 13963b9b51feSCy Schubert error = ipf_token_del(softc, arg, uid, ctx); 13973b9b51feSCy Schubert SPL_X(s); 13983b9b51feSCy Schubert } else { 13993b9b51feSCy Schubert IPFERROR(60019); 14003b9b51feSCy Schubert error = EFAULT; 14013b9b51feSCy Schubert } 14023b9b51feSCy Schubert break; 14033b9b51feSCy Schubert 14043b9b51feSCy Schubert case SIOCGTQTAB : 14053b9b51feSCy Schubert error = ipf_outobj(softc, data, softn->ipf_nat_tcptq, 14063b9b51feSCy Schubert IPFOBJ_STATETQTAB); 14073b9b51feSCy Schubert break; 14083b9b51feSCy Schubert 14093b9b51feSCy Schubert case SIOCGTABL : 14103b9b51feSCy Schubert error = ipf_nat_gettable(softc, softn, data); 14113b9b51feSCy Schubert break; 14123b9b51feSCy Schubert 14133b9b51feSCy Schubert default : 14143b9b51feSCy Schubert IPFERROR(60020); 14153b9b51feSCy Schubert error = EINVAL; 14163b9b51feSCy Schubert break; 14173b9b51feSCy Schubert } 14183b9b51feSCy Schubert done: 14193b9b51feSCy Schubert if (nat != NULL) 14203b9b51feSCy Schubert ipf_nat_rule_fini(softc, nat); 14213b9b51feSCy Schubert if (nt != NULL) 14223b9b51feSCy Schubert KFREES(nt, nt->in_size); 14233b9b51feSCy Schubert return error; 14243b9b51feSCy Schubert } 14253b9b51feSCy Schubert 14263b9b51feSCy Schubert 14273b9b51feSCy Schubert /* ------------------------------------------------------------------------ */ 14283b9b51feSCy Schubert /* Function: ipf_nat_siocaddnat */ 14293b9b51feSCy Schubert /* Returns: int - 0 == success, != 0 == failure */ 14303b9b51feSCy Schubert /* Parameters: softc(I) - pointer to soft context main structure */ 14313b9b51feSCy Schubert /* softn(I) - pointer to NAT context structure */ 14323b9b51feSCy Schubert /* n(I) - pointer to new NAT rule */ 14333b9b51feSCy Schubert /* np(I) - pointer to where to insert new NAT rule */ 14343b9b51feSCy Schubert /* getlock(I) - flag indicating if lock on is held */ 14353b9b51feSCy Schubert /* Mutex Locks: ipf_nat_io */ 14363b9b51feSCy Schubert /* */ 14373b9b51feSCy Schubert /* Handle SIOCADNAT. Resolve and calculate details inside the NAT rule */ 14383b9b51feSCy Schubert /* from information passed to the kernel, then add it to the appropriate */ 14393b9b51feSCy Schubert /* NAT rule table(s). */ 14403b9b51feSCy Schubert /* ------------------------------------------------------------------------ */ 14413b9b51feSCy Schubert static int 14423b9b51feSCy Schubert ipf_nat_siocaddnat(softc, softn, n, getlock) 14433b9b51feSCy Schubert ipf_main_softc_t *softc; 14443b9b51feSCy Schubert ipf_nat_softc_t *softn; 14453b9b51feSCy Schubert ipnat_t *n; 14463b9b51feSCy Schubert int getlock; 14473b9b51feSCy Schubert { 14483b9b51feSCy Schubert int error = 0; 14493b9b51feSCy Schubert 14503b9b51feSCy Schubert if (ipf_nat_resolverule(softc, n) != 0) { 14513b9b51feSCy Schubert IPFERROR(60022); 14523b9b51feSCy Schubert return ENOENT; 14533b9b51feSCy Schubert } 14543b9b51feSCy Schubert 14553b9b51feSCy Schubert if ((n->in_age[0] == 0) && (n->in_age[1] != 0)) { 14563b9b51feSCy Schubert IPFERROR(60023); 14573b9b51feSCy Schubert return EINVAL; 14583b9b51feSCy Schubert } 14593b9b51feSCy Schubert 14603b9b51feSCy Schubert if (n->in_redir == (NAT_DIVERTUDP|NAT_MAP)) { 14613b9b51feSCy Schubert /* 14623b9b51feSCy Schubert * Prerecord whether or not the destination of the divert 14633b9b51feSCy Schubert * is local or not to the interface the packet is going 14643b9b51feSCy Schubert * to be sent out. 14653b9b51feSCy Schubert */ 14663b9b51feSCy Schubert n->in_dlocal = ipf_deliverlocal(softc, n->in_v[1], 14673b9b51feSCy Schubert n->in_ifps[1], &n->in_ndstip6); 14683b9b51feSCy Schubert } 14693b9b51feSCy Schubert 14703b9b51feSCy Schubert if (getlock) { 14713b9b51feSCy Schubert WRITE_ENTER(&softc->ipf_nat); 14723b9b51feSCy Schubert } 14733b9b51feSCy Schubert n->in_next = NULL; 14743b9b51feSCy Schubert n->in_pnext = softn->ipf_nat_list_tail; 14753b9b51feSCy Schubert *n->in_pnext = n; 14763b9b51feSCy Schubert softn->ipf_nat_list_tail = &n->in_next; 14773b9b51feSCy Schubert n->in_use++; 14783b9b51feSCy Schubert 14793b9b51feSCy Schubert if (n->in_redir & NAT_REDIRECT) { 14803b9b51feSCy Schubert n->in_flags &= ~IPN_NOTDST; 14813b9b51feSCy Schubert switch (n->in_v[0]) 14823b9b51feSCy Schubert { 14833b9b51feSCy Schubert case 4 : 14843b9b51feSCy Schubert ipf_nat_addrdr(softn, n); 14853b9b51feSCy Schubert break; 14863b9b51feSCy Schubert #ifdef USE_INET6 14873b9b51feSCy Schubert case 6 : 14883b9b51feSCy Schubert ipf_nat6_addrdr(softn, n); 14893b9b51feSCy Schubert break; 14903b9b51feSCy Schubert #endif 14913b9b51feSCy Schubert default : 14923b9b51feSCy Schubert break; 14933b9b51feSCy Schubert } 14943b9b51feSCy Schubert ATOMIC_INC32(softn->ipf_nat_stats.ns_rules_rdr); 14953b9b51feSCy Schubert } 14963b9b51feSCy Schubert 14973b9b51feSCy Schubert if (n->in_redir & (NAT_MAP|NAT_MAPBLK)) { 14983b9b51feSCy Schubert n->in_flags &= ~IPN_NOTSRC; 14993b9b51feSCy Schubert switch (n->in_v[0]) 15003b9b51feSCy Schubert { 15013b9b51feSCy Schubert case 4 : 15023b9b51feSCy Schubert ipf_nat_addmap(softn, n); 15033b9b51feSCy Schubert break; 15043b9b51feSCy Schubert #ifdef USE_INET6 15053b9b51feSCy Schubert case 6 : 15063b9b51feSCy Schubert ipf_nat6_addmap(softn, n); 15073b9b51feSCy Schubert break; 15083b9b51feSCy Schubert #endif 15093b9b51feSCy Schubert default : 15103b9b51feSCy Schubert break; 15113b9b51feSCy Schubert } 15123b9b51feSCy Schubert ATOMIC_INC32(softn->ipf_nat_stats.ns_rules_map); 15133b9b51feSCy Schubert } 15143b9b51feSCy Schubert 15153b9b51feSCy Schubert if (n->in_age[0] != 0) 15163b9b51feSCy Schubert n->in_tqehead[0] = ipf_addtimeoutqueue(softc, 15173b9b51feSCy Schubert &softn->ipf_nat_utqe, 15183b9b51feSCy Schubert n->in_age[0]); 15193b9b51feSCy Schubert 15203b9b51feSCy Schubert if (n->in_age[1] != 0) 15213b9b51feSCy Schubert n->in_tqehead[1] = ipf_addtimeoutqueue(softc, 15223b9b51feSCy Schubert &softn->ipf_nat_utqe, 15233b9b51feSCy Schubert n->in_age[1]); 15243b9b51feSCy Schubert 15253b9b51feSCy Schubert MUTEX_INIT(&n->in_lock, "ipnat rule lock"); 15263b9b51feSCy Schubert 15273b9b51feSCy Schubert n = NULL; 15283b9b51feSCy Schubert ATOMIC_INC32(softn->ipf_nat_stats.ns_rules); 15293b9b51feSCy Schubert #if SOLARIS && !defined(INSTANCES) 15303b9b51feSCy Schubert pfil_delayed_copy = 0; 15313b9b51feSCy Schubert #endif 15323b9b51feSCy Schubert if (getlock) { 15333b9b51feSCy Schubert RWLOCK_EXIT(&softc->ipf_nat); /* WRITE */ 15343b9b51feSCy Schubert } 15353b9b51feSCy Schubert 15363b9b51feSCy Schubert return error; 15373b9b51feSCy Schubert } 15383b9b51feSCy Schubert 15393b9b51feSCy Schubert 15403b9b51feSCy Schubert /* ------------------------------------------------------------------------ */ 15413b9b51feSCy Schubert /* Function: ipf_nat_ruleaddrinit */ 15423b9b51feSCy Schubert /* Parameters: softc(I) - pointer to soft context main structure */ 15433b9b51feSCy Schubert /* softn(I) - pointer to NAT context structure */ 15443b9b51feSCy Schubert /* n(I) - pointer to NAT rule */ 15453b9b51feSCy Schubert /* */ 15463b9b51feSCy Schubert /* Initialise all of the NAT address structures in a NAT rule. */ 15473b9b51feSCy Schubert /* ------------------------------------------------------------------------ */ 15483b9b51feSCy Schubert static int 15493b9b51feSCy Schubert ipf_nat_ruleaddrinit(softc, softn, n) 15503b9b51feSCy Schubert ipf_main_softc_t *softc; 15513b9b51feSCy Schubert ipf_nat_softc_t *softn; 15523b9b51feSCy Schubert ipnat_t *n; 15533b9b51feSCy Schubert { 15543b9b51feSCy Schubert int idx, error; 15553b9b51feSCy Schubert 15563b9b51feSCy Schubert if ((n->in_ndst.na_atype == FRI_LOOKUP) && 15573b9b51feSCy Schubert (n->in_ndst.na_type != IPLT_DSTLIST)) { 15583b9b51feSCy Schubert IPFERROR(60071); 15593b9b51feSCy Schubert return EINVAL; 15603b9b51feSCy Schubert } 15613b9b51feSCy Schubert if ((n->in_nsrc.na_atype == FRI_LOOKUP) && 15623b9b51feSCy Schubert (n->in_nsrc.na_type != IPLT_DSTLIST)) { 15633b9b51feSCy Schubert IPFERROR(60069); 15643b9b51feSCy Schubert return EINVAL; 15653b9b51feSCy Schubert } 15663b9b51feSCy Schubert 15673b9b51feSCy Schubert if (n->in_redir == NAT_BIMAP) { 15683b9b51feSCy Schubert n->in_ndstaddr = n->in_osrcaddr; 15693b9b51feSCy Schubert n->in_ndstmsk = n->in_osrcmsk; 15703b9b51feSCy Schubert n->in_odstaddr = n->in_nsrcaddr; 15713b9b51feSCy Schubert n->in_odstmsk = n->in_nsrcmsk; 15723b9b51feSCy Schubert 15733b9b51feSCy Schubert } 15743b9b51feSCy Schubert 15753b9b51feSCy Schubert if (n->in_redir & NAT_REDIRECT) 15763b9b51feSCy Schubert idx = 1; 15773b9b51feSCy Schubert else 15783b9b51feSCy Schubert idx = 0; 15793b9b51feSCy Schubert /* 15803b9b51feSCy Schubert * Initialise all of the address fields. 15813b9b51feSCy Schubert */ 15823b9b51feSCy Schubert error = ipf_nat_nextaddrinit(softc, n->in_names, &n->in_osrc, 1, 15833b9b51feSCy Schubert n->in_ifps[idx]); 15843b9b51feSCy Schubert if (error != 0) 15853b9b51feSCy Schubert return error; 15863b9b51feSCy Schubert 15873b9b51feSCy Schubert error = ipf_nat_nextaddrinit(softc, n->in_names, &n->in_odst, 1, 15883b9b51feSCy Schubert n->in_ifps[idx]); 15893b9b51feSCy Schubert if (error != 0) 15903b9b51feSCy Schubert return error; 15913b9b51feSCy Schubert 15923b9b51feSCy Schubert error = ipf_nat_nextaddrinit(softc, n->in_names, &n->in_nsrc, 1, 15933b9b51feSCy Schubert n->in_ifps[idx]); 15943b9b51feSCy Schubert if (error != 0) 15953b9b51feSCy Schubert return error; 15963b9b51feSCy Schubert 15973b9b51feSCy Schubert error = ipf_nat_nextaddrinit(softc, n->in_names, &n->in_ndst, 1, 15983b9b51feSCy Schubert n->in_ifps[idx]); 15993b9b51feSCy Schubert if (error != 0) 16003b9b51feSCy Schubert return error; 16013b9b51feSCy Schubert 16023b9b51feSCy Schubert if (n->in_redir & NAT_DIVERTUDP) 16033b9b51feSCy Schubert ipf_nat_builddivertmp(softn, n); 16043b9b51feSCy Schubert 16053b9b51feSCy Schubert return 0; 16063b9b51feSCy Schubert } 16073b9b51feSCy Schubert 16083b9b51feSCy Schubert 16093b9b51feSCy Schubert /* ------------------------------------------------------------------------ */ 16103b9b51feSCy Schubert /* Function: ipf_nat_resolvrule */ 16113b9b51feSCy Schubert /* Returns: Nil */ 16123b9b51feSCy Schubert /* Parameters: softc(I) - pointer to soft context main structure */ 16133b9b51feSCy Schubert /* n(I) - pointer to NAT rule */ 16143b9b51feSCy Schubert /* */ 16153b9b51feSCy Schubert /* Handle SIOCADNAT. Resolve and calculate details inside the NAT rule */ 16163b9b51feSCy Schubert /* from information passed to the kernel, then add it to the appropriate */ 16173b9b51feSCy Schubert /* NAT rule table(s). */ 16183b9b51feSCy Schubert /* ------------------------------------------------------------------------ */ 16193b9b51feSCy Schubert static int 16203b9b51feSCy Schubert ipf_nat_resolverule(softc, n) 16213b9b51feSCy Schubert ipf_main_softc_t *softc; 16223b9b51feSCy Schubert ipnat_t *n; 16233b9b51feSCy Schubert { 16243b9b51feSCy Schubert char *base; 16253b9b51feSCy Schubert 16263b9b51feSCy Schubert base = n->in_names; 16273b9b51feSCy Schubert 16283b9b51feSCy Schubert n->in_ifps[0] = ipf_resolvenic(softc, base + n->in_ifnames[0], 16293b9b51feSCy Schubert n->in_v[0]); 16303b9b51feSCy Schubert 16313b9b51feSCy Schubert if (n->in_ifnames[1] == -1) { 16323b9b51feSCy Schubert n->in_ifnames[1] = n->in_ifnames[0]; 16333b9b51feSCy Schubert n->in_ifps[1] = n->in_ifps[0]; 16343b9b51feSCy Schubert } else { 16353b9b51feSCy Schubert n->in_ifps[1] = ipf_resolvenic(softc, base + n->in_ifnames[1], 16363b9b51feSCy Schubert n->in_v[1]); 16373b9b51feSCy Schubert } 16383b9b51feSCy Schubert 16393b9b51feSCy Schubert if (n->in_plabel != -1) { 16403b9b51feSCy Schubert if (n->in_redir & NAT_REDIRECT) 16413b9b51feSCy Schubert n->in_apr = ipf_proxy_lookup(softc->ipf_proxy_soft, 16423b9b51feSCy Schubert n->in_pr[0], 16433b9b51feSCy Schubert base + n->in_plabel); 16443b9b51feSCy Schubert else 16453b9b51feSCy Schubert n->in_apr = ipf_proxy_lookup(softc->ipf_proxy_soft, 16463b9b51feSCy Schubert n->in_pr[1], 16473b9b51feSCy Schubert base + n->in_plabel); 16483b9b51feSCy Schubert if (n->in_apr == NULL) 16493b9b51feSCy Schubert return -1; 16503b9b51feSCy Schubert } 16513b9b51feSCy Schubert return 0; 16523b9b51feSCy Schubert } 16533b9b51feSCy Schubert 16543b9b51feSCy Schubert 16553b9b51feSCy Schubert /* ------------------------------------------------------------------------ */ 16563b9b51feSCy Schubert /* Function: ipf_nat_siocdelnat */ 16573b9b51feSCy Schubert /* Returns: int - 0 == success, != 0 == failure */ 16583b9b51feSCy Schubert /* Parameters: softc(I) - pointer to soft context main structure */ 16593b9b51feSCy Schubert /* softn(I) - pointer to NAT context structure */ 16603b9b51feSCy Schubert /* n(I) - pointer to new NAT rule */ 16613b9b51feSCy Schubert /* getlock(I) - flag indicating if lock on is held */ 16623b9b51feSCy Schubert /* Mutex Locks: ipf_nat_io */ 16633b9b51feSCy Schubert /* */ 16643b9b51feSCy Schubert /* Handle SIOCADNAT. Resolve and calculate details inside the NAT rule */ 16653b9b51feSCy Schubert /* from information passed to the kernel, then add it to the appropriate */ 16663b9b51feSCy Schubert /* NAT rule table(s). */ 16673b9b51feSCy Schubert /* ------------------------------------------------------------------------ */ 16683b9b51feSCy Schubert static void 16693b9b51feSCy Schubert ipf_nat_siocdelnat(softc, softn, n, getlock) 16703b9b51feSCy Schubert ipf_main_softc_t *softc; 16713b9b51feSCy Schubert ipf_nat_softc_t *softn; 16723b9b51feSCy Schubert ipnat_t *n; 16733b9b51feSCy Schubert int getlock; 16743b9b51feSCy Schubert { 16753b9b51feSCy Schubert if (getlock) { 16763b9b51feSCy Schubert WRITE_ENTER(&softc->ipf_nat); 16773b9b51feSCy Schubert } 16783b9b51feSCy Schubert 16793b9b51feSCy Schubert ipf_nat_delrule(softc, softn, n, 1); 16803b9b51feSCy Schubert 16813b9b51feSCy Schubert if (getlock) { 16823b9b51feSCy Schubert RWLOCK_EXIT(&softc->ipf_nat); /* READ/WRITE */ 16833b9b51feSCy Schubert } 16843b9b51feSCy Schubert } 16853b9b51feSCy Schubert 16863b9b51feSCy Schubert 16873b9b51feSCy Schubert /* ------------------------------------------------------------------------ */ 16883b9b51feSCy Schubert /* Function: ipf_nat_getsz */ 16893b9b51feSCy Schubert /* Returns: int - 0 == success, != 0 is the error value. */ 16903b9b51feSCy Schubert /* Parameters: softc(I) - pointer to soft context main structure */ 16913b9b51feSCy Schubert /* data(I) - pointer to natget structure with kernel */ 16923b9b51feSCy Schubert /* pointer get the size of. */ 16933b9b51feSCy Schubert /* getlock(I) - flag indicating whether or not the caller */ 16943b9b51feSCy Schubert /* holds a lock on ipf_nat */ 16953b9b51feSCy Schubert /* */ 16963b9b51feSCy Schubert /* Handle SIOCSTGSZ. */ 16973b9b51feSCy Schubert /* Return the size of the nat list entry to be copied back to user space. */ 16983b9b51feSCy Schubert /* The size of the entry is stored in the ng_sz field and the enture natget */ 16993b9b51feSCy Schubert /* structure is copied back to the user. */ 17003b9b51feSCy Schubert /* ------------------------------------------------------------------------ */ 17013b9b51feSCy Schubert static int 17023b9b51feSCy Schubert ipf_nat_getsz(softc, data, getlock) 17033b9b51feSCy Schubert ipf_main_softc_t *softc; 17043b9b51feSCy Schubert caddr_t data; 17053b9b51feSCy Schubert int getlock; 17063b9b51feSCy Schubert { 17073b9b51feSCy Schubert ipf_nat_softc_t *softn = softc->ipf_nat_soft; 17083b9b51feSCy Schubert ap_session_t *aps; 17093b9b51feSCy Schubert nat_t *nat, *n; 17103b9b51feSCy Schubert natget_t ng; 17113b9b51feSCy Schubert int error; 17123b9b51feSCy Schubert 17133b9b51feSCy Schubert error = BCOPYIN(data, &ng, sizeof(ng)); 17143b9b51feSCy Schubert if (error != 0) { 17153b9b51feSCy Schubert IPFERROR(60024); 17163b9b51feSCy Schubert return EFAULT; 17173b9b51feSCy Schubert } 17183b9b51feSCy Schubert 17193b9b51feSCy Schubert if (getlock) { 17203b9b51feSCy Schubert READ_ENTER(&softc->ipf_nat); 17213b9b51feSCy Schubert } 17223b9b51feSCy Schubert 17233b9b51feSCy Schubert nat = ng.ng_ptr; 17243b9b51feSCy Schubert if (!nat) { 17253b9b51feSCy Schubert nat = softn->ipf_nat_instances; 17263b9b51feSCy Schubert ng.ng_sz = 0; 17273b9b51feSCy Schubert /* 17283b9b51feSCy Schubert * Empty list so the size returned is 0. Simple. 17293b9b51feSCy Schubert */ 17303b9b51feSCy Schubert if (nat == NULL) { 17313b9b51feSCy Schubert if (getlock) { 17323b9b51feSCy Schubert RWLOCK_EXIT(&softc->ipf_nat); 17333b9b51feSCy Schubert } 17343b9b51feSCy Schubert error = BCOPYOUT(&ng, data, sizeof(ng)); 17353b9b51feSCy Schubert if (error != 0) { 17363b9b51feSCy Schubert IPFERROR(60025); 17373b9b51feSCy Schubert return EFAULT; 17383b9b51feSCy Schubert } 17393b9b51feSCy Schubert return 0; 17403b9b51feSCy Schubert } 17413b9b51feSCy Schubert } else { 17423b9b51feSCy Schubert /* 17433b9b51feSCy Schubert * Make sure the pointer we're copying from exists in the 17443b9b51feSCy Schubert * current list of entries. Security precaution to prevent 17453b9b51feSCy Schubert * copying of random kernel data. 17463b9b51feSCy Schubert */ 17473b9b51feSCy Schubert for (n = softn->ipf_nat_instances; n; n = n->nat_next) 17483b9b51feSCy Schubert if (n == nat) 17493b9b51feSCy Schubert break; 17503b9b51feSCy Schubert if (n == NULL) { 17513b9b51feSCy Schubert if (getlock) { 17523b9b51feSCy Schubert RWLOCK_EXIT(&softc->ipf_nat); 17533b9b51feSCy Schubert } 17543b9b51feSCy Schubert IPFERROR(60026); 17553b9b51feSCy Schubert return ESRCH; 17563b9b51feSCy Schubert } 17573b9b51feSCy Schubert } 17583b9b51feSCy Schubert 17593b9b51feSCy Schubert /* 17603b9b51feSCy Schubert * Incluse any space required for proxy data structures. 17613b9b51feSCy Schubert */ 17623b9b51feSCy Schubert ng.ng_sz = sizeof(nat_save_t); 17633b9b51feSCy Schubert aps = nat->nat_aps; 17643b9b51feSCy Schubert if (aps != NULL) { 17653b9b51feSCy Schubert ng.ng_sz += sizeof(ap_session_t) - 4; 17663b9b51feSCy Schubert if (aps->aps_data != 0) 17673b9b51feSCy Schubert ng.ng_sz += aps->aps_psiz; 17683b9b51feSCy Schubert } 17693b9b51feSCy Schubert if (getlock) { 17703b9b51feSCy Schubert RWLOCK_EXIT(&softc->ipf_nat); 17713b9b51feSCy Schubert } 17723b9b51feSCy Schubert 17733b9b51feSCy Schubert error = BCOPYOUT(&ng, data, sizeof(ng)); 17743b9b51feSCy Schubert if (error != 0) { 17753b9b51feSCy Schubert IPFERROR(60027); 17763b9b51feSCy Schubert return EFAULT; 17773b9b51feSCy Schubert } 17783b9b51feSCy Schubert return 0; 17793b9b51feSCy Schubert } 17803b9b51feSCy Schubert 17813b9b51feSCy Schubert 17823b9b51feSCy Schubert /* ------------------------------------------------------------------------ */ 17833b9b51feSCy Schubert /* Function: ipf_nat_getent */ 17843b9b51feSCy Schubert /* Returns: int - 0 == success, != 0 is the error value. */ 17853b9b51feSCy Schubert /* Parameters: softc(I) - pointer to soft context main structure */ 17863b9b51feSCy Schubert /* data(I) - pointer to natget structure with kernel pointer*/ 17873b9b51feSCy Schubert /* to NAT structure to copy out. */ 17883b9b51feSCy Schubert /* getlock(I) - flag indicating whether or not the caller */ 17893b9b51feSCy Schubert /* holds a lock on ipf_nat */ 17903b9b51feSCy Schubert /* */ 17913b9b51feSCy Schubert /* Handle SIOCSTGET. */ 17923b9b51feSCy Schubert /* Copies out NAT entry to user space. Any additional data held for a */ 17933b9b51feSCy Schubert /* proxy is also copied, as to is the NAT rule which was responsible for it */ 17943b9b51feSCy Schubert /* ------------------------------------------------------------------------ */ 17953b9b51feSCy Schubert static int 17963b9b51feSCy Schubert ipf_nat_getent(softc, data, getlock) 17973b9b51feSCy Schubert ipf_main_softc_t *softc; 17983b9b51feSCy Schubert caddr_t data; 17993b9b51feSCy Schubert int getlock; 18003b9b51feSCy Schubert { 18013b9b51feSCy Schubert ipf_nat_softc_t *softn = softc->ipf_nat_soft; 18023b9b51feSCy Schubert int error, outsize; 18033b9b51feSCy Schubert ap_session_t *aps; 18043b9b51feSCy Schubert nat_save_t *ipn, ipns; 18053b9b51feSCy Schubert nat_t *n, *nat; 18063b9b51feSCy Schubert 18073b9b51feSCy Schubert error = ipf_inobj(softc, data, NULL, &ipns, IPFOBJ_NATSAVE); 18083b9b51feSCy Schubert if (error != 0) 18093b9b51feSCy Schubert return error; 18103b9b51feSCy Schubert 18113b9b51feSCy Schubert if ((ipns.ipn_dsize < sizeof(ipns)) || (ipns.ipn_dsize > 81920)) { 18123b9b51feSCy Schubert IPFERROR(60028); 18133b9b51feSCy Schubert return EINVAL; 18143b9b51feSCy Schubert } 18153b9b51feSCy Schubert 18163b9b51feSCy Schubert KMALLOCS(ipn, nat_save_t *, ipns.ipn_dsize); 18173b9b51feSCy Schubert if (ipn == NULL) { 18183b9b51feSCy Schubert IPFERROR(60029); 18193b9b51feSCy Schubert return ENOMEM; 18203b9b51feSCy Schubert } 18213b9b51feSCy Schubert 18223b9b51feSCy Schubert if (getlock) { 18233b9b51feSCy Schubert READ_ENTER(&softc->ipf_nat); 18243b9b51feSCy Schubert } 18253b9b51feSCy Schubert 18263b9b51feSCy Schubert ipn->ipn_dsize = ipns.ipn_dsize; 18273b9b51feSCy Schubert nat = ipns.ipn_next; 18283b9b51feSCy Schubert if (nat == NULL) { 18293b9b51feSCy Schubert nat = softn->ipf_nat_instances; 18303b9b51feSCy Schubert if (nat == NULL) { 18313b9b51feSCy Schubert if (softn->ipf_nat_instances == NULL) { 18323b9b51feSCy Schubert IPFERROR(60030); 18333b9b51feSCy Schubert error = ENOENT; 18343b9b51feSCy Schubert } 18353b9b51feSCy Schubert goto finished; 18363b9b51feSCy Schubert } 18373b9b51feSCy Schubert } else { 18383b9b51feSCy Schubert /* 18393b9b51feSCy Schubert * Make sure the pointer we're copying from exists in the 18403b9b51feSCy Schubert * current list of entries. Security precaution to prevent 18413b9b51feSCy Schubert * copying of random kernel data. 18423b9b51feSCy Schubert */ 18433b9b51feSCy Schubert for (n = softn->ipf_nat_instances; n; n = n->nat_next) 18443b9b51feSCy Schubert if (n == nat) 18453b9b51feSCy Schubert break; 18463b9b51feSCy Schubert if (n == NULL) { 18473b9b51feSCy Schubert IPFERROR(60031); 18483b9b51feSCy Schubert error = ESRCH; 18493b9b51feSCy Schubert goto finished; 18503b9b51feSCy Schubert } 18513b9b51feSCy Schubert } 18523b9b51feSCy Schubert ipn->ipn_next = nat->nat_next; 18533b9b51feSCy Schubert 18543b9b51feSCy Schubert /* 18553b9b51feSCy Schubert * Copy the NAT structure. 18563b9b51feSCy Schubert */ 18573b9b51feSCy Schubert bcopy((char *)nat, &ipn->ipn_nat, sizeof(*nat)); 18583b9b51feSCy Schubert 18593b9b51feSCy Schubert /* 18603b9b51feSCy Schubert * If we have a pointer to the NAT rule it belongs to, save that too. 18613b9b51feSCy Schubert */ 18623b9b51feSCy Schubert if (nat->nat_ptr != NULL) 18633b9b51feSCy Schubert bcopy((char *)nat->nat_ptr, (char *)&ipn->ipn_ipnat, 18643b9b51feSCy Schubert sizeof(nat->nat_ptr)); 18653b9b51feSCy Schubert 18663b9b51feSCy Schubert /* 18673b9b51feSCy Schubert * If we also know the NAT entry has an associated filter rule, 18683b9b51feSCy Schubert * save that too. 18693b9b51feSCy Schubert */ 18703b9b51feSCy Schubert if (nat->nat_fr != NULL) 18713b9b51feSCy Schubert bcopy((char *)nat->nat_fr, (char *)&ipn->ipn_fr, 18723b9b51feSCy Schubert sizeof(ipn->ipn_fr)); 18733b9b51feSCy Schubert 18743b9b51feSCy Schubert /* 18753b9b51feSCy Schubert * Last but not least, if there is an application proxy session set 18763b9b51feSCy Schubert * up for this NAT entry, then copy that out too, including any 18773b9b51feSCy Schubert * private data saved along side it by the proxy. 18783b9b51feSCy Schubert */ 18793b9b51feSCy Schubert aps = nat->nat_aps; 18803b9b51feSCy Schubert outsize = ipn->ipn_dsize - sizeof(*ipn) + sizeof(ipn->ipn_data); 18813b9b51feSCy Schubert if (aps != NULL) { 18823b9b51feSCy Schubert char *s; 18833b9b51feSCy Schubert 18843b9b51feSCy Schubert if (outsize < sizeof(*aps)) { 18853b9b51feSCy Schubert IPFERROR(60032); 18863b9b51feSCy Schubert error = ENOBUFS; 18873b9b51feSCy Schubert goto finished; 18883b9b51feSCy Schubert } 18893b9b51feSCy Schubert 18903b9b51feSCy Schubert s = ipn->ipn_data; 18913b9b51feSCy Schubert bcopy((char *)aps, s, sizeof(*aps)); 18923b9b51feSCy Schubert s += sizeof(*aps); 18933b9b51feSCy Schubert outsize -= sizeof(*aps); 18943b9b51feSCy Schubert if ((aps->aps_data != NULL) && (outsize >= aps->aps_psiz)) 18953b9b51feSCy Schubert bcopy(aps->aps_data, s, aps->aps_psiz); 18963b9b51feSCy Schubert else { 18973b9b51feSCy Schubert IPFERROR(60033); 18983b9b51feSCy Schubert error = ENOBUFS; 18993b9b51feSCy Schubert } 19003b9b51feSCy Schubert } 19013b9b51feSCy Schubert if (error == 0) { 19023b9b51feSCy Schubert error = ipf_outobjsz(softc, data, ipn, IPFOBJ_NATSAVE, 19033b9b51feSCy Schubert ipns.ipn_dsize); 19043b9b51feSCy Schubert } 19053b9b51feSCy Schubert 19063b9b51feSCy Schubert finished: 19073b9b51feSCy Schubert if (ipn != NULL) { 19083b9b51feSCy Schubert KFREES(ipn, ipns.ipn_dsize); 19093b9b51feSCy Schubert } 19103b9b51feSCy Schubert if (getlock) { 19113b9b51feSCy Schubert RWLOCK_EXIT(&softc->ipf_nat); 19123b9b51feSCy Schubert } 19133b9b51feSCy Schubert return error; 19143b9b51feSCy Schubert } 19153b9b51feSCy Schubert 19163b9b51feSCy Schubert 19173b9b51feSCy Schubert /* ------------------------------------------------------------------------ */ 19183b9b51feSCy Schubert /* Function: ipf_nat_putent */ 19193b9b51feSCy Schubert /* Returns: int - 0 == success, != 0 is the error value. */ 19203b9b51feSCy Schubert /* Parameters: softc(I) - pointer to soft context main structure */ 19213b9b51feSCy Schubert /* data(I) - pointer to natget structure with NAT */ 19223b9b51feSCy Schubert /* structure information to load into the kernel */ 19233b9b51feSCy Schubert /* getlock(I) - flag indicating whether or not a write lock */ 19243b9b51feSCy Schubert /* on is already held. */ 19253b9b51feSCy Schubert /* */ 19263b9b51feSCy Schubert /* Handle SIOCSTPUT. */ 19273b9b51feSCy Schubert /* Loads a NAT table entry from user space, including a NAT rule, proxy and */ 19283b9b51feSCy Schubert /* firewall rule data structures, if pointers to them indicate so. */ 19293b9b51feSCy Schubert /* ------------------------------------------------------------------------ */ 19303b9b51feSCy Schubert static int 19313b9b51feSCy Schubert ipf_nat_putent(softc, data, getlock) 19323b9b51feSCy Schubert ipf_main_softc_t *softc; 19333b9b51feSCy Schubert caddr_t data; 19343b9b51feSCy Schubert int getlock; 19353b9b51feSCy Schubert { 19363b9b51feSCy Schubert ipf_nat_softc_t *softn = softc->ipf_nat_soft; 19373b9b51feSCy Schubert nat_save_t ipn, *ipnn; 19383b9b51feSCy Schubert ap_session_t *aps; 19393b9b51feSCy Schubert nat_t *n, *nat; 19403b9b51feSCy Schubert frentry_t *fr; 19413b9b51feSCy Schubert fr_info_t fin; 19423b9b51feSCy Schubert ipnat_t *in; 19433b9b51feSCy Schubert int error; 19443b9b51feSCy Schubert 19453b9b51feSCy Schubert error = ipf_inobj(softc, data, NULL, &ipn, IPFOBJ_NATSAVE); 19463b9b51feSCy Schubert if (error != 0) 19473b9b51feSCy Schubert return error; 19483b9b51feSCy Schubert 19493b9b51feSCy Schubert /* 19503b9b51feSCy Schubert * Initialise early because of code at junkput label. 19513b9b51feSCy Schubert */ 19523b9b51feSCy Schubert n = NULL; 19533b9b51feSCy Schubert in = NULL; 19543b9b51feSCy Schubert aps = NULL; 19553b9b51feSCy Schubert nat = NULL; 19563b9b51feSCy Schubert ipnn = NULL; 19573b9b51feSCy Schubert fr = NULL; 19583b9b51feSCy Schubert 19593b9b51feSCy Schubert /* 19603b9b51feSCy Schubert * New entry, copy in the rest of the NAT entry if it's size is more 19613b9b51feSCy Schubert * than just the nat_t structure. 19623b9b51feSCy Schubert */ 19633b9b51feSCy Schubert if (ipn.ipn_dsize > sizeof(ipn)) { 19643b9b51feSCy Schubert if (ipn.ipn_dsize > 81920) { 19653b9b51feSCy Schubert IPFERROR(60034); 19663b9b51feSCy Schubert error = ENOMEM; 19673b9b51feSCy Schubert goto junkput; 19683b9b51feSCy Schubert } 19693b9b51feSCy Schubert 19703b9b51feSCy Schubert KMALLOCS(ipnn, nat_save_t *, ipn.ipn_dsize); 19713b9b51feSCy Schubert if (ipnn == NULL) { 19723b9b51feSCy Schubert IPFERROR(60035); 19733b9b51feSCy Schubert return ENOMEM; 19743b9b51feSCy Schubert } 19753b9b51feSCy Schubert 19763b9b51feSCy Schubert bzero(ipnn, ipn.ipn_dsize); 19773b9b51feSCy Schubert error = ipf_inobjsz(softc, data, ipnn, IPFOBJ_NATSAVE, 19783b9b51feSCy Schubert ipn.ipn_dsize); 19793b9b51feSCy Schubert if (error != 0) { 19803b9b51feSCy Schubert goto junkput; 19813b9b51feSCy Schubert } 19823b9b51feSCy Schubert } else 19833b9b51feSCy Schubert ipnn = &ipn; 19843b9b51feSCy Schubert 19853b9b51feSCy Schubert KMALLOC(nat, nat_t *); 19863b9b51feSCy Schubert if (nat == NULL) { 19873b9b51feSCy Schubert IPFERROR(60037); 19883b9b51feSCy Schubert error = ENOMEM; 19893b9b51feSCy Schubert goto junkput; 19903b9b51feSCy Schubert } 19913b9b51feSCy Schubert 19923b9b51feSCy Schubert bcopy((char *)&ipnn->ipn_nat, (char *)nat, sizeof(*nat)); 19933b9b51feSCy Schubert 19943b9b51feSCy Schubert switch (nat->nat_v[0]) 19953b9b51feSCy Schubert { 19963b9b51feSCy Schubert case 4: 19973b9b51feSCy Schubert #ifdef USE_INET6 19983b9b51feSCy Schubert case 6 : 19993b9b51feSCy Schubert #endif 20003b9b51feSCy Schubert break; 20013b9b51feSCy Schubert default : 20023b9b51feSCy Schubert IPFERROR(60061); 20033b9b51feSCy Schubert error = EPROTONOSUPPORT; 20043b9b51feSCy Schubert goto junkput; 20053b9b51feSCy Schubert /*NOTREACHED*/ 20063b9b51feSCy Schubert } 20073b9b51feSCy Schubert 20083b9b51feSCy Schubert /* 20093b9b51feSCy Schubert * Initialize all these so that ipf_nat_delete() doesn't cause a crash. 20103b9b51feSCy Schubert */ 20113b9b51feSCy Schubert bzero((char *)nat, offsetof(struct nat, nat_tqe)); 20123b9b51feSCy Schubert nat->nat_tqe.tqe_pnext = NULL; 20133b9b51feSCy Schubert nat->nat_tqe.tqe_next = NULL; 20143b9b51feSCy Schubert nat->nat_tqe.tqe_ifq = NULL; 20153b9b51feSCy Schubert nat->nat_tqe.tqe_parent = nat; 20163b9b51feSCy Schubert 20173b9b51feSCy Schubert /* 20183b9b51feSCy Schubert * Restore the rule associated with this nat session 20193b9b51feSCy Schubert */ 20203b9b51feSCy Schubert in = ipnn->ipn_nat.nat_ptr; 20213b9b51feSCy Schubert if (in != NULL) { 20223b9b51feSCy Schubert KMALLOCS(in, ipnat_t *, ipnn->ipn_ipnat.in_size); 20233b9b51feSCy Schubert nat->nat_ptr = in; 20243b9b51feSCy Schubert if (in == NULL) { 20253b9b51feSCy Schubert IPFERROR(60038); 20263b9b51feSCy Schubert error = ENOMEM; 20273b9b51feSCy Schubert goto junkput; 20283b9b51feSCy Schubert } 20293b9b51feSCy Schubert bcopy((char *)&ipnn->ipn_ipnat, (char *)in, 20303b9b51feSCy Schubert ipnn->ipn_ipnat.in_size); 20313b9b51feSCy Schubert in->in_use = 1; 20323b9b51feSCy Schubert in->in_flags |= IPN_DELETE; 20333b9b51feSCy Schubert 20343b9b51feSCy Schubert ATOMIC_INC32(softn->ipf_nat_stats.ns_rules); 20353b9b51feSCy Schubert 20363b9b51feSCy Schubert if (ipf_nat_resolverule(softc, in) != 0) { 20373b9b51feSCy Schubert IPFERROR(60039); 20383b9b51feSCy Schubert error = ESRCH; 20393b9b51feSCy Schubert goto junkput; 20403b9b51feSCy Schubert } 20413b9b51feSCy Schubert } 20423b9b51feSCy Schubert 20433b9b51feSCy Schubert /* 20443b9b51feSCy Schubert * Check that the NAT entry doesn't already exist in the kernel. 20453b9b51feSCy Schubert * 20463b9b51feSCy Schubert * For NAT_OUTBOUND, we're lookup for a duplicate MAP entry. To do 20473b9b51feSCy Schubert * this, we check to see if the inbound combination of addresses and 20483b9b51feSCy Schubert * ports is already known. Similar logic is applied for NAT_INBOUND. 20493b9b51feSCy Schubert * 20503b9b51feSCy Schubert */ 20513b9b51feSCy Schubert bzero((char *)&fin, sizeof(fin)); 20523b9b51feSCy Schubert fin.fin_v = nat->nat_v[0]; 20533b9b51feSCy Schubert fin.fin_p = nat->nat_pr[0]; 20543b9b51feSCy Schubert fin.fin_rev = nat->nat_rev; 20553b9b51feSCy Schubert fin.fin_ifp = nat->nat_ifps[0]; 20563b9b51feSCy Schubert fin.fin_data[0] = ntohs(nat->nat_ndport); 20573b9b51feSCy Schubert fin.fin_data[1] = ntohs(nat->nat_nsport); 20583b9b51feSCy Schubert 20593b9b51feSCy Schubert switch (nat->nat_dir) 20603b9b51feSCy Schubert { 20613b9b51feSCy Schubert case NAT_OUTBOUND : 20623b9b51feSCy Schubert case NAT_DIVERTOUT : 20633b9b51feSCy Schubert if (getlock) { 20643b9b51feSCy Schubert READ_ENTER(&softc->ipf_nat); 20653b9b51feSCy Schubert } 20663b9b51feSCy Schubert 20673b9b51feSCy Schubert fin.fin_v = nat->nat_v[1]; 20683b9b51feSCy Schubert if (nat->nat_v[1] == 4) { 20693b9b51feSCy Schubert n = ipf_nat_inlookup(&fin, nat->nat_flags, fin.fin_p, 20703b9b51feSCy Schubert nat->nat_ndstip, nat->nat_nsrcip); 20713b9b51feSCy Schubert #ifdef USE_INET6 20723b9b51feSCy Schubert } else if (nat->nat_v[1] == 6) { 20733b9b51feSCy Schubert n = ipf_nat6_inlookup(&fin, nat->nat_flags, fin.fin_p, 20743b9b51feSCy Schubert &nat->nat_ndst6.in6, 20753b9b51feSCy Schubert &nat->nat_nsrc6.in6); 20763b9b51feSCy Schubert #endif 20773b9b51feSCy Schubert } 20783b9b51feSCy Schubert 20793b9b51feSCy Schubert if (getlock) { 20803b9b51feSCy Schubert RWLOCK_EXIT(&softc->ipf_nat); 20813b9b51feSCy Schubert } 20823b9b51feSCy Schubert if (n != NULL) { 20833b9b51feSCy Schubert IPFERROR(60040); 20843b9b51feSCy Schubert error = EEXIST; 20853b9b51feSCy Schubert goto junkput; 20863b9b51feSCy Schubert } 20873b9b51feSCy Schubert break; 20883b9b51feSCy Schubert 20893b9b51feSCy Schubert case NAT_INBOUND : 20903b9b51feSCy Schubert case NAT_DIVERTIN : 20913b9b51feSCy Schubert if (getlock) { 20923b9b51feSCy Schubert READ_ENTER(&softc->ipf_nat); 20933b9b51feSCy Schubert } 20943b9b51feSCy Schubert 20953b9b51feSCy Schubert if (fin.fin_v == 4) { 20963b9b51feSCy Schubert n = ipf_nat_outlookup(&fin, nat->nat_flags, fin.fin_p, 20973b9b51feSCy Schubert nat->nat_ndstip, 20983b9b51feSCy Schubert nat->nat_nsrcip); 20993b9b51feSCy Schubert #ifdef USE_INET6 21003b9b51feSCy Schubert } else if (fin.fin_v == 6) { 21013b9b51feSCy Schubert n = ipf_nat6_outlookup(&fin, nat->nat_flags, fin.fin_p, 21023b9b51feSCy Schubert &nat->nat_ndst6.in6, 21033b9b51feSCy Schubert &nat->nat_nsrc6.in6); 21043b9b51feSCy Schubert #endif 21053b9b51feSCy Schubert } 21063b9b51feSCy Schubert 21073b9b51feSCy Schubert if (getlock) { 21083b9b51feSCy Schubert RWLOCK_EXIT(&softc->ipf_nat); 21093b9b51feSCy Schubert } 21103b9b51feSCy Schubert if (n != NULL) { 21113b9b51feSCy Schubert IPFERROR(60041); 21123b9b51feSCy Schubert error = EEXIST; 21133b9b51feSCy Schubert goto junkput; 21143b9b51feSCy Schubert } 21153b9b51feSCy Schubert break; 21163b9b51feSCy Schubert 21173b9b51feSCy Schubert default : 21183b9b51feSCy Schubert IPFERROR(60042); 21193b9b51feSCy Schubert error = EINVAL; 21203b9b51feSCy Schubert goto junkput; 21213b9b51feSCy Schubert } 21223b9b51feSCy Schubert 21233b9b51feSCy Schubert /* 21243b9b51feSCy Schubert * Restore ap_session_t structure. Include the private data allocated 21253b9b51feSCy Schubert * if it was there. 21263b9b51feSCy Schubert */ 21273b9b51feSCy Schubert aps = nat->nat_aps; 21283b9b51feSCy Schubert if (aps != NULL) { 21293b9b51feSCy Schubert KMALLOC(aps, ap_session_t *); 21303b9b51feSCy Schubert nat->nat_aps = aps; 21313b9b51feSCy Schubert if (aps == NULL) { 21323b9b51feSCy Schubert IPFERROR(60043); 21333b9b51feSCy Schubert error = ENOMEM; 21343b9b51feSCy Schubert goto junkput; 21353b9b51feSCy Schubert } 21363b9b51feSCy Schubert bcopy(ipnn->ipn_data, (char *)aps, sizeof(*aps)); 21373b9b51feSCy Schubert if (in != NULL) 21383b9b51feSCy Schubert aps->aps_apr = in->in_apr; 21393b9b51feSCy Schubert else 21403b9b51feSCy Schubert aps->aps_apr = NULL; 21413b9b51feSCy Schubert if (aps->aps_psiz != 0) { 21423b9b51feSCy Schubert if (aps->aps_psiz > 81920) { 21433b9b51feSCy Schubert IPFERROR(60044); 21443b9b51feSCy Schubert error = ENOMEM; 21453b9b51feSCy Schubert goto junkput; 21463b9b51feSCy Schubert } 21473b9b51feSCy Schubert KMALLOCS(aps->aps_data, void *, aps->aps_psiz); 21483b9b51feSCy Schubert if (aps->aps_data == NULL) { 21493b9b51feSCy Schubert IPFERROR(60045); 21503b9b51feSCy Schubert error = ENOMEM; 21513b9b51feSCy Schubert goto junkput; 21523b9b51feSCy Schubert } 21533b9b51feSCy Schubert bcopy(ipnn->ipn_data + sizeof(*aps), aps->aps_data, 21543b9b51feSCy Schubert aps->aps_psiz); 21553b9b51feSCy Schubert } else { 21563b9b51feSCy Schubert aps->aps_psiz = 0; 21573b9b51feSCy Schubert aps->aps_data = NULL; 21583b9b51feSCy Schubert } 21593b9b51feSCy Schubert } 21603b9b51feSCy Schubert 21613b9b51feSCy Schubert /* 21623b9b51feSCy Schubert * If there was a filtering rule associated with this entry then 21633b9b51feSCy Schubert * build up a new one. 21643b9b51feSCy Schubert */ 21653b9b51feSCy Schubert fr = nat->nat_fr; 21663b9b51feSCy Schubert if (fr != NULL) { 21673b9b51feSCy Schubert if ((nat->nat_flags & SI_NEWFR) != 0) { 21683b9b51feSCy Schubert KMALLOC(fr, frentry_t *); 21693b9b51feSCy Schubert nat->nat_fr = fr; 21703b9b51feSCy Schubert if (fr == NULL) { 21713b9b51feSCy Schubert IPFERROR(60046); 21723b9b51feSCy Schubert error = ENOMEM; 21733b9b51feSCy Schubert goto junkput; 21743b9b51feSCy Schubert } 21753b9b51feSCy Schubert ipnn->ipn_nat.nat_fr = fr; 21763b9b51feSCy Schubert fr->fr_ref = 1; 21773b9b51feSCy Schubert (void) ipf_outobj(softc, data, ipnn, IPFOBJ_NATSAVE); 21783b9b51feSCy Schubert bcopy((char *)&ipnn->ipn_fr, (char *)fr, sizeof(*fr)); 21793b9b51feSCy Schubert 21803b9b51feSCy Schubert fr->fr_ref = 1; 21813b9b51feSCy Schubert fr->fr_dsize = 0; 21823b9b51feSCy Schubert fr->fr_data = NULL; 21833b9b51feSCy Schubert fr->fr_type = FR_T_NONE; 21843b9b51feSCy Schubert 21853b9b51feSCy Schubert MUTEX_NUKE(&fr->fr_lock); 21863b9b51feSCy Schubert MUTEX_INIT(&fr->fr_lock, "nat-filter rule lock"); 21873b9b51feSCy Schubert } else { 21883b9b51feSCy Schubert if (getlock) { 21893b9b51feSCy Schubert READ_ENTER(&softc->ipf_nat); 21903b9b51feSCy Schubert } 21913b9b51feSCy Schubert for (n = softn->ipf_nat_instances; n; n = n->nat_next) 21923b9b51feSCy Schubert if (n->nat_fr == fr) 21933b9b51feSCy Schubert break; 21943b9b51feSCy Schubert 21953b9b51feSCy Schubert if (n != NULL) { 21963b9b51feSCy Schubert MUTEX_ENTER(&fr->fr_lock); 21973b9b51feSCy Schubert fr->fr_ref++; 21983b9b51feSCy Schubert MUTEX_EXIT(&fr->fr_lock); 21993b9b51feSCy Schubert } 22003b9b51feSCy Schubert if (getlock) { 22013b9b51feSCy Schubert RWLOCK_EXIT(&softc->ipf_nat); 22023b9b51feSCy Schubert } 22033b9b51feSCy Schubert 22043b9b51feSCy Schubert if (n == NULL) { 22053b9b51feSCy Schubert IPFERROR(60047); 22063b9b51feSCy Schubert error = ESRCH; 22073b9b51feSCy Schubert goto junkput; 22083b9b51feSCy Schubert } 22093b9b51feSCy Schubert } 22103b9b51feSCy Schubert } 22113b9b51feSCy Schubert 22123b9b51feSCy Schubert if (ipnn != &ipn) { 22133b9b51feSCy Schubert KFREES(ipnn, ipn.ipn_dsize); 22143b9b51feSCy Schubert ipnn = NULL; 22153b9b51feSCy Schubert } 22163b9b51feSCy Schubert 22173b9b51feSCy Schubert if (getlock) { 22183b9b51feSCy Schubert WRITE_ENTER(&softc->ipf_nat); 22193b9b51feSCy Schubert } 22203b9b51feSCy Schubert 22213b9b51feSCy Schubert if (fin.fin_v == 4) 22223b9b51feSCy Schubert error = ipf_nat_finalise(&fin, nat); 22233b9b51feSCy Schubert #ifdef USE_INET6 22243b9b51feSCy Schubert else 22253b9b51feSCy Schubert error = ipf_nat6_finalise(&fin, nat); 22263b9b51feSCy Schubert #endif 22273b9b51feSCy Schubert 22283b9b51feSCy Schubert if (getlock) { 22293b9b51feSCy Schubert RWLOCK_EXIT(&softc->ipf_nat); 22303b9b51feSCy Schubert } 22313b9b51feSCy Schubert 22323b9b51feSCy Schubert if (error == 0) 22333b9b51feSCy Schubert return 0; 22343b9b51feSCy Schubert 22353b9b51feSCy Schubert IPFERROR(60048); 22363b9b51feSCy Schubert error = ENOMEM; 22373b9b51feSCy Schubert 22383b9b51feSCy Schubert junkput: 22393b9b51feSCy Schubert if (fr != NULL) { 22403b9b51feSCy Schubert (void) ipf_derefrule(softc, &fr); 22413b9b51feSCy Schubert } 22423b9b51feSCy Schubert 22433b9b51feSCy Schubert if ((ipnn != NULL) && (ipnn != &ipn)) { 22443b9b51feSCy Schubert KFREES(ipnn, ipn.ipn_dsize); 22453b9b51feSCy Schubert } 22463b9b51feSCy Schubert if (nat != NULL) { 22473b9b51feSCy Schubert if (aps != NULL) { 22483b9b51feSCy Schubert if (aps->aps_data != NULL) { 22493b9b51feSCy Schubert KFREES(aps->aps_data, aps->aps_psiz); 22503b9b51feSCy Schubert } 22513b9b51feSCy Schubert KFREE(aps); 22523b9b51feSCy Schubert } 22533b9b51feSCy Schubert if (in != NULL) { 22543b9b51feSCy Schubert if (in->in_apr) 22553b9b51feSCy Schubert ipf_proxy_deref(in->in_apr); 22563b9b51feSCy Schubert KFREES(in, in->in_size); 22573b9b51feSCy Schubert } 22583b9b51feSCy Schubert KFREE(nat); 22593b9b51feSCy Schubert } 22603b9b51feSCy Schubert return error; 22613b9b51feSCy Schubert } 22623b9b51feSCy Schubert 22633b9b51feSCy Schubert 22643b9b51feSCy Schubert /* ------------------------------------------------------------------------ */ 22653b9b51feSCy Schubert /* Function: ipf_nat_delete */ 22663b9b51feSCy Schubert /* Returns: Nil */ 22673b9b51feSCy Schubert /* Parameters: softc(I) - pointer to soft context main structure */ 22683b9b51feSCy Schubert /* nat(I) - pointer to NAT structure to delete */ 22693b9b51feSCy Schubert /* logtype(I) - type of LOG record to create before deleting */ 22703b9b51feSCy Schubert /* Write Lock: ipf_nat */ 22713b9b51feSCy Schubert /* */ 22723b9b51feSCy Schubert /* Delete a nat entry from the various lists and table. If NAT logging is */ 22733b9b51feSCy Schubert /* enabled then generate a NAT log record for this event. */ 22743b9b51feSCy Schubert /* ------------------------------------------------------------------------ */ 22753b9b51feSCy Schubert void 22763b9b51feSCy Schubert ipf_nat_delete(softc, nat, logtype) 22773b9b51feSCy Schubert ipf_main_softc_t *softc; 22783b9b51feSCy Schubert struct nat *nat; 22793b9b51feSCy Schubert int logtype; 22803b9b51feSCy Schubert { 22813b9b51feSCy Schubert ipf_nat_softc_t *softn = softc->ipf_nat_soft; 22823b9b51feSCy Schubert int madeorphan = 0, bkt, removed = 0; 22833b9b51feSCy Schubert nat_stat_side_t *nss; 22843b9b51feSCy Schubert struct ipnat *ipn; 22853b9b51feSCy Schubert 22863b9b51feSCy Schubert if (logtype != 0 && softn->ipf_nat_logging != 0) 22873b9b51feSCy Schubert ipf_nat_log(softc, softn, nat, logtype); 22883b9b51feSCy Schubert 22893b9b51feSCy Schubert /* 22903b9b51feSCy Schubert * Take it as a general indication that all the pointers are set if 22913b9b51feSCy Schubert * nat_pnext is set. 22923b9b51feSCy Schubert */ 22933b9b51feSCy Schubert if (nat->nat_pnext != NULL) { 22943b9b51feSCy Schubert removed = 1; 22953b9b51feSCy Schubert 22963b9b51feSCy Schubert bkt = nat->nat_hv[0] % softn->ipf_nat_table_sz; 22973b9b51feSCy Schubert nss = &softn->ipf_nat_stats.ns_side[0]; 22983b9b51feSCy Schubert if (nss->ns_bucketlen[bkt] > 0) 22993b9b51feSCy Schubert nss->ns_bucketlen[bkt]--; 23003b9b51feSCy Schubert if (nss->ns_bucketlen[bkt] == 0) { 23013b9b51feSCy Schubert nss->ns_inuse--; 23023b9b51feSCy Schubert } 23033b9b51feSCy Schubert 23043b9b51feSCy Schubert bkt = nat->nat_hv[1] % softn->ipf_nat_table_sz; 23053b9b51feSCy Schubert nss = &softn->ipf_nat_stats.ns_side[1]; 23063b9b51feSCy Schubert if (nss->ns_bucketlen[bkt] > 0) 23073b9b51feSCy Schubert nss->ns_bucketlen[bkt]--; 23083b9b51feSCy Schubert if (nss->ns_bucketlen[bkt] == 0) { 23093b9b51feSCy Schubert nss->ns_inuse--; 23103b9b51feSCy Schubert } 23113b9b51feSCy Schubert 23123b9b51feSCy Schubert *nat->nat_pnext = nat->nat_next; 23133b9b51feSCy Schubert if (nat->nat_next != NULL) { 23143b9b51feSCy Schubert nat->nat_next->nat_pnext = nat->nat_pnext; 23153b9b51feSCy Schubert nat->nat_next = NULL; 23163b9b51feSCy Schubert } 23173b9b51feSCy Schubert nat->nat_pnext = NULL; 23183b9b51feSCy Schubert 23193b9b51feSCy Schubert *nat->nat_phnext[0] = nat->nat_hnext[0]; 23203b9b51feSCy Schubert if (nat->nat_hnext[0] != NULL) { 23213b9b51feSCy Schubert nat->nat_hnext[0]->nat_phnext[0] = nat->nat_phnext[0]; 23223b9b51feSCy Schubert nat->nat_hnext[0] = NULL; 23233b9b51feSCy Schubert } 23243b9b51feSCy Schubert nat->nat_phnext[0] = NULL; 23253b9b51feSCy Schubert 23263b9b51feSCy Schubert *nat->nat_phnext[1] = nat->nat_hnext[1]; 23273b9b51feSCy Schubert if (nat->nat_hnext[1] != NULL) { 23283b9b51feSCy Schubert nat->nat_hnext[1]->nat_phnext[1] = nat->nat_phnext[1]; 23293b9b51feSCy Schubert nat->nat_hnext[1] = NULL; 23303b9b51feSCy Schubert } 23313b9b51feSCy Schubert nat->nat_phnext[1] = NULL; 23323b9b51feSCy Schubert 23333b9b51feSCy Schubert if ((nat->nat_flags & SI_WILDP) != 0) { 23343b9b51feSCy Schubert ATOMIC_DEC32(softn->ipf_nat_stats.ns_wilds); 23353b9b51feSCy Schubert } 23363b9b51feSCy Schubert madeorphan = 1; 23373b9b51feSCy Schubert } 23383b9b51feSCy Schubert 23393b9b51feSCy Schubert if (nat->nat_me != NULL) { 23403b9b51feSCy Schubert *nat->nat_me = NULL; 23413b9b51feSCy Schubert nat->nat_me = NULL; 23423b9b51feSCy Schubert nat->nat_ref--; 23433b9b51feSCy Schubert ASSERT(nat->nat_ref >= 0); 23443b9b51feSCy Schubert } 23453b9b51feSCy Schubert 23463b9b51feSCy Schubert if (nat->nat_tqe.tqe_ifq != NULL) { 23473b9b51feSCy Schubert /* 23483b9b51feSCy Schubert * No call to ipf_freetimeoutqueue() is made here, they are 23493b9b51feSCy Schubert * garbage collected in ipf_nat_expire(). 23503b9b51feSCy Schubert */ 23513b9b51feSCy Schubert (void) ipf_deletequeueentry(&nat->nat_tqe); 23523b9b51feSCy Schubert } 23533b9b51feSCy Schubert 23543b9b51feSCy Schubert if (nat->nat_sync) { 23553b9b51feSCy Schubert ipf_sync_del_nat(softc->ipf_sync_soft, nat->nat_sync); 23563b9b51feSCy Schubert nat->nat_sync = NULL; 23573b9b51feSCy Schubert } 23583b9b51feSCy Schubert 23593b9b51feSCy Schubert if (logtype == NL_EXPIRE) 23603b9b51feSCy Schubert softn->ipf_nat_stats.ns_expire++; 23613b9b51feSCy Schubert 23623b9b51feSCy Schubert MUTEX_ENTER(&nat->nat_lock); 23633b9b51feSCy Schubert /* 23643b9b51feSCy Schubert * NL_DESTROY should only be passed in when we've got nat_ref >= 2. 23653b9b51feSCy Schubert * This happens when a nat'd packet is blocked and we want to throw 23663b9b51feSCy Schubert * away the NAT session. 23673b9b51feSCy Schubert */ 23683b9b51feSCy Schubert if (logtype == NL_DESTROY) { 23693b9b51feSCy Schubert if (nat->nat_ref > 2) { 23703b9b51feSCy Schubert nat->nat_ref -= 2; 23713b9b51feSCy Schubert MUTEX_EXIT(&nat->nat_lock); 23723b9b51feSCy Schubert if (removed) 23733b9b51feSCy Schubert softn->ipf_nat_stats.ns_orphans++; 23743b9b51feSCy Schubert return; 23753b9b51feSCy Schubert } 23763b9b51feSCy Schubert } else if (nat->nat_ref > 1) { 23773b9b51feSCy Schubert nat->nat_ref--; 23783b9b51feSCy Schubert MUTEX_EXIT(&nat->nat_lock); 23793b9b51feSCy Schubert if (madeorphan == 1) 23803b9b51feSCy Schubert softn->ipf_nat_stats.ns_orphans++; 23813b9b51feSCy Schubert return; 23823b9b51feSCy Schubert } 23833b9b51feSCy Schubert ASSERT(nat->nat_ref >= 0); 23843b9b51feSCy Schubert MUTEX_EXIT(&nat->nat_lock); 23853b9b51feSCy Schubert 23863b9b51feSCy Schubert nat->nat_ref = 0; 23873b9b51feSCy Schubert 23883b9b51feSCy Schubert if (madeorphan == 0) 23893b9b51feSCy Schubert softn->ipf_nat_stats.ns_orphans--; 23903b9b51feSCy Schubert 23913b9b51feSCy Schubert /* 23923b9b51feSCy Schubert * At this point, nat_ref can be either 0 or -1 23933b9b51feSCy Schubert */ 23943b9b51feSCy Schubert softn->ipf_nat_stats.ns_proto[nat->nat_pr[0]]--; 23953b9b51feSCy Schubert 23963b9b51feSCy Schubert if (nat->nat_fr != NULL) { 23973b9b51feSCy Schubert (void) ipf_derefrule(softc, &nat->nat_fr); 23983b9b51feSCy Schubert } 23993b9b51feSCy Schubert 24003b9b51feSCy Schubert if (nat->nat_hm != NULL) { 24013b9b51feSCy Schubert ipf_nat_hostmapdel(softc, &nat->nat_hm); 24023b9b51feSCy Schubert } 24033b9b51feSCy Schubert 24043b9b51feSCy Schubert /* 24053b9b51feSCy Schubert * If there is an active reference from the nat entry to its parent 24063b9b51feSCy Schubert * rule, decrement the rule's reference count and free it too if no 24073b9b51feSCy Schubert * longer being used. 24083b9b51feSCy Schubert */ 24093b9b51feSCy Schubert ipn = nat->nat_ptr; 24103b9b51feSCy Schubert nat->nat_ptr = NULL; 24113b9b51feSCy Schubert 24123b9b51feSCy Schubert if (ipn != NULL) { 24133b9b51feSCy Schubert ipn->in_space++; 24143b9b51feSCy Schubert ipf_nat_rule_deref(softc, &ipn); 24153b9b51feSCy Schubert } 24163b9b51feSCy Schubert 24173b9b51feSCy Schubert if (nat->nat_aps != NULL) { 24183b9b51feSCy Schubert ipf_proxy_free(softc, nat->nat_aps); 24193b9b51feSCy Schubert nat->nat_aps = NULL; 24203b9b51feSCy Schubert } 24213b9b51feSCy Schubert 24223b9b51feSCy Schubert MUTEX_DESTROY(&nat->nat_lock); 24233b9b51feSCy Schubert 24243b9b51feSCy Schubert softn->ipf_nat_stats.ns_active--; 24253b9b51feSCy Schubert 24263b9b51feSCy Schubert /* 24273b9b51feSCy Schubert * If there's a fragment table entry too for this nat entry, then 24283b9b51feSCy Schubert * dereference that as well. This is after nat_lock is released 24293b9b51feSCy Schubert * because of Tru64. 24303b9b51feSCy Schubert */ 24313b9b51feSCy Schubert ipf_frag_natforget(softc, (void *)nat); 24323b9b51feSCy Schubert 24333b9b51feSCy Schubert KFREE(nat); 24343b9b51feSCy Schubert } 24353b9b51feSCy Schubert 24363b9b51feSCy Schubert 24373b9b51feSCy Schubert /* ------------------------------------------------------------------------ */ 24383b9b51feSCy Schubert /* Function: ipf_nat_flushtable */ 24393b9b51feSCy Schubert /* Returns: int - number of NAT rules deleted */ 24403b9b51feSCy Schubert /* Parameters: softc(I) - pointer to soft context main structure */ 24413b9b51feSCy Schubert /* softn(I) - pointer to NAT context structure */ 24423b9b51feSCy Schubert /* Write Lock: ipf_nat */ 24433b9b51feSCy Schubert /* */ 24443b9b51feSCy Schubert /* Deletes all currently active NAT sessions. In deleting each NAT entry a */ 24453b9b51feSCy Schubert /* log record should be emitted in ipf_nat_delete() if NAT logging is */ 24463b9b51feSCy Schubert /* enabled. */ 24473b9b51feSCy Schubert /* ------------------------------------------------------------------------ */ 24483b9b51feSCy Schubert /* 24493b9b51feSCy Schubert * nat_flushtable - clear the NAT table of all mapping entries. 24503b9b51feSCy Schubert */ 24513b9b51feSCy Schubert static int 24523b9b51feSCy Schubert ipf_nat_flushtable(softc, softn) 24533b9b51feSCy Schubert ipf_main_softc_t *softc; 24543b9b51feSCy Schubert ipf_nat_softc_t *softn; 24553b9b51feSCy Schubert { 24563b9b51feSCy Schubert nat_t *nat; 24573b9b51feSCy Schubert int j = 0; 24583b9b51feSCy Schubert 24593b9b51feSCy Schubert /* 24603b9b51feSCy Schubert * ALL NAT mappings deleted, so lets just make the deletions 24613b9b51feSCy Schubert * quicker. 24623b9b51feSCy Schubert */ 24633b9b51feSCy Schubert if (softn->ipf_nat_table[0] != NULL) 24643b9b51feSCy Schubert bzero((char *)softn->ipf_nat_table[0], 24653b9b51feSCy Schubert sizeof(softn->ipf_nat_table[0]) * 24663b9b51feSCy Schubert softn->ipf_nat_table_sz); 24673b9b51feSCy Schubert if (softn->ipf_nat_table[1] != NULL) 24683b9b51feSCy Schubert bzero((char *)softn->ipf_nat_table[1], 24693b9b51feSCy Schubert sizeof(softn->ipf_nat_table[1]) * 24703b9b51feSCy Schubert softn->ipf_nat_table_sz); 24713b9b51feSCy Schubert 24723b9b51feSCy Schubert while ((nat = softn->ipf_nat_instances) != NULL) { 24733b9b51feSCy Schubert ipf_nat_delete(softc, nat, NL_FLUSH); 24743b9b51feSCy Schubert j++; 24753b9b51feSCy Schubert } 24763b9b51feSCy Schubert 24773b9b51feSCy Schubert return j; 24783b9b51feSCy Schubert } 24793b9b51feSCy Schubert 24803b9b51feSCy Schubert 24813b9b51feSCy Schubert /* ------------------------------------------------------------------------ */ 24823b9b51feSCy Schubert /* Function: ipf_nat_clearlist */ 24833b9b51feSCy Schubert /* Returns: int - number of NAT/RDR rules deleted */ 24843b9b51feSCy Schubert /* Parameters: softc(I) - pointer to soft context main structure */ 24853b9b51feSCy Schubert /* softn(I) - pointer to NAT context structure */ 24863b9b51feSCy Schubert /* */ 24873b9b51feSCy Schubert /* Delete all rules in the current list of rules. There is nothing elegant */ 24883b9b51feSCy Schubert /* about this cleanup: simply free all entries on the list of rules and */ 24893b9b51feSCy Schubert /* clear out the tables used for hashed NAT rule lookups. */ 24903b9b51feSCy Schubert /* ------------------------------------------------------------------------ */ 24913b9b51feSCy Schubert static int 24923b9b51feSCy Schubert ipf_nat_clearlist(softc, softn) 24933b9b51feSCy Schubert ipf_main_softc_t *softc; 24943b9b51feSCy Schubert ipf_nat_softc_t *softn; 24953b9b51feSCy Schubert { 24963b9b51feSCy Schubert ipnat_t *n; 24973b9b51feSCy Schubert int i = 0; 24983b9b51feSCy Schubert 24993b9b51feSCy Schubert if (softn->ipf_nat_map_rules != NULL) { 25003b9b51feSCy Schubert bzero((char *)softn->ipf_nat_map_rules, 25013b9b51feSCy Schubert sizeof(*softn->ipf_nat_map_rules) * 25023b9b51feSCy Schubert softn->ipf_nat_maprules_sz); 25033b9b51feSCy Schubert } 25043b9b51feSCy Schubert if (softn->ipf_nat_rdr_rules != NULL) { 25053b9b51feSCy Schubert bzero((char *)softn->ipf_nat_rdr_rules, 25063b9b51feSCy Schubert sizeof(*softn->ipf_nat_rdr_rules) * 25073b9b51feSCy Schubert softn->ipf_nat_rdrrules_sz); 25083b9b51feSCy Schubert } 25093b9b51feSCy Schubert 25103b9b51feSCy Schubert while ((n = softn->ipf_nat_list) != NULL) { 25113b9b51feSCy Schubert ipf_nat_delrule(softc, softn, n, 0); 25123b9b51feSCy Schubert i++; 25133b9b51feSCy Schubert } 25143b9b51feSCy Schubert #if SOLARIS && !defined(INSTANCES) 25153b9b51feSCy Schubert pfil_delayed_copy = 1; 25163b9b51feSCy Schubert #endif 25173b9b51feSCy Schubert return i; 25183b9b51feSCy Schubert } 25193b9b51feSCy Schubert 25203b9b51feSCy Schubert 25213b9b51feSCy Schubert /* ------------------------------------------------------------------------ */ 25223b9b51feSCy Schubert /* Function: ipf_nat_delrule */ 25233b9b51feSCy Schubert /* Returns: Nil */ 25243b9b51feSCy Schubert /* Parameters: softc(I) - pointer to soft context main structure */ 25253b9b51feSCy Schubert /* softn(I) - pointer to NAT context structure */ 25263b9b51feSCy Schubert /* np(I) - pointer to NAT rule to delete */ 25273b9b51feSCy Schubert /* purge(I) - 1 == allow purge, 0 == prevent purge */ 25283b9b51feSCy Schubert /* Locks: WRITE(ipf_nat) */ 25293b9b51feSCy Schubert /* */ 25303b9b51feSCy Schubert /* Preventing "purge" from occuring is allowed because when all of the NAT */ 25313b9b51feSCy Schubert /* rules are being removed, allowing the "purge" to walk through the list */ 25323b9b51feSCy Schubert /* of NAT sessions, possibly multiple times, would be a large performance */ 25333b9b51feSCy Schubert /* hit, on the order of O(N^2). */ 25343b9b51feSCy Schubert /* ------------------------------------------------------------------------ */ 25353b9b51feSCy Schubert static void 25363b9b51feSCy Schubert ipf_nat_delrule(softc, softn, np, purge) 25373b9b51feSCy Schubert ipf_main_softc_t *softc; 25383b9b51feSCy Schubert ipf_nat_softc_t *softn; 25393b9b51feSCy Schubert ipnat_t *np; 25403b9b51feSCy Schubert int purge; 25413b9b51feSCy Schubert { 25423b9b51feSCy Schubert 25433b9b51feSCy Schubert if (np->in_pnext != NULL) { 25443b9b51feSCy Schubert *np->in_pnext = np->in_next; 25453b9b51feSCy Schubert if (np->in_next != NULL) 25463b9b51feSCy Schubert np->in_next->in_pnext = np->in_pnext; 25473b9b51feSCy Schubert if (softn->ipf_nat_list_tail == &np->in_next) 25483b9b51feSCy Schubert softn->ipf_nat_list_tail = np->in_pnext; 25493b9b51feSCy Schubert } 25503b9b51feSCy Schubert 25513b9b51feSCy Schubert if ((purge == 1) && ((np->in_flags & IPN_PURGE) != 0)) { 25523b9b51feSCy Schubert nat_t *next; 25533b9b51feSCy Schubert nat_t *nat; 25543b9b51feSCy Schubert 25553b9b51feSCy Schubert for (next = softn->ipf_nat_instances; (nat = next) != NULL;) { 25563b9b51feSCy Schubert next = nat->nat_next; 25573b9b51feSCy Schubert if (nat->nat_ptr == np) 25583b9b51feSCy Schubert ipf_nat_delete(softc, nat, NL_PURGE); 25593b9b51feSCy Schubert } 25603b9b51feSCy Schubert } 25613b9b51feSCy Schubert 25623b9b51feSCy Schubert if ((np->in_flags & IPN_DELETE) == 0) { 25633b9b51feSCy Schubert if (np->in_redir & NAT_REDIRECT) { 25643b9b51feSCy Schubert switch (np->in_v[0]) 25653b9b51feSCy Schubert { 25663b9b51feSCy Schubert case 4 : 25673b9b51feSCy Schubert ipf_nat_delrdr(softn, np); 25683b9b51feSCy Schubert break; 25693b9b51feSCy Schubert #ifdef USE_INET6 25703b9b51feSCy Schubert case 6 : 25713b9b51feSCy Schubert ipf_nat6_delrdr(softn, np); 25723b9b51feSCy Schubert break; 25733b9b51feSCy Schubert #endif 25743b9b51feSCy Schubert } 25753b9b51feSCy Schubert } 25763b9b51feSCy Schubert if (np->in_redir & (NAT_MAPBLK|NAT_MAP)) { 25773b9b51feSCy Schubert switch (np->in_v[0]) 25783b9b51feSCy Schubert { 25793b9b51feSCy Schubert case 4 : 25803b9b51feSCy Schubert ipf_nat_delmap(softn, np); 25813b9b51feSCy Schubert break; 25823b9b51feSCy Schubert #ifdef USE_INET6 25833b9b51feSCy Schubert case 6 : 25843b9b51feSCy Schubert ipf_nat6_delmap(softn, np); 25853b9b51feSCy Schubert break; 25863b9b51feSCy Schubert #endif 25873b9b51feSCy Schubert } 25883b9b51feSCy Schubert } 25893b9b51feSCy Schubert } 25903b9b51feSCy Schubert 25913b9b51feSCy Schubert np->in_flags |= IPN_DELETE; 25923b9b51feSCy Schubert ipf_nat_rule_deref(softc, &np); 25933b9b51feSCy Schubert } 25943b9b51feSCy Schubert 25953b9b51feSCy Schubert 25963b9b51feSCy Schubert /* ------------------------------------------------------------------------ */ 25973b9b51feSCy Schubert /* Function: ipf_nat_newmap */ 25983b9b51feSCy Schubert /* Returns: int - -1 == error, 0 == success */ 25993b9b51feSCy Schubert /* Parameters: fin(I) - pointer to packet information */ 26003b9b51feSCy Schubert /* nat(I) - pointer to NAT entry */ 26013b9b51feSCy Schubert /* ni(I) - pointer to structure with misc. information needed */ 26023b9b51feSCy Schubert /* to create new NAT entry. */ 26033b9b51feSCy Schubert /* */ 26043b9b51feSCy Schubert /* Given an empty NAT structure, populate it with new information about a */ 26053b9b51feSCy Schubert /* new NAT session, as defined by the matching NAT rule. */ 26063b9b51feSCy Schubert /* ni.nai_ip is passed in uninitialised and must be set, in host byte order,*/ 26073b9b51feSCy Schubert /* to the new IP address for the translation. */ 26083b9b51feSCy Schubert /* ------------------------------------------------------------------------ */ 26093b9b51feSCy Schubert static int 26103b9b51feSCy Schubert ipf_nat_newmap(fin, nat, ni) 26113b9b51feSCy Schubert fr_info_t *fin; 26123b9b51feSCy Schubert nat_t *nat; 26133b9b51feSCy Schubert natinfo_t *ni; 26143b9b51feSCy Schubert { 26153b9b51feSCy Schubert ipf_main_softc_t *softc = fin->fin_main_soft; 26163b9b51feSCy Schubert ipf_nat_softc_t *softn = softc->ipf_nat_soft; 26173b9b51feSCy Schubert u_short st_port, dport, sport, port, sp, dp; 26183b9b51feSCy Schubert struct in_addr in, inb; 26193b9b51feSCy Schubert hostmap_t *hm; 26203b9b51feSCy Schubert u_32_t flags; 26213b9b51feSCy Schubert u_32_t st_ip; 26223b9b51feSCy Schubert ipnat_t *np; 26233b9b51feSCy Schubert nat_t *natl; 26243b9b51feSCy Schubert int l; 26253b9b51feSCy Schubert 26263b9b51feSCy Schubert /* 26273b9b51feSCy Schubert * If it's an outbound packet which doesn't match any existing 26283b9b51feSCy Schubert * record, then create a new port 26293b9b51feSCy Schubert */ 26303b9b51feSCy Schubert l = 0; 26313b9b51feSCy Schubert hm = NULL; 26323b9b51feSCy Schubert np = ni->nai_np; 26333b9b51feSCy Schubert st_ip = np->in_snip; 26343b9b51feSCy Schubert st_port = np->in_spnext; 26353b9b51feSCy Schubert flags = nat->nat_flags; 26363b9b51feSCy Schubert 26373b9b51feSCy Schubert if (flags & IPN_ICMPQUERY) { 26383b9b51feSCy Schubert sport = fin->fin_data[1]; 26393b9b51feSCy Schubert dport = 0; 26403b9b51feSCy Schubert } else { 26413b9b51feSCy Schubert sport = htons(fin->fin_data[0]); 26423b9b51feSCy Schubert dport = htons(fin->fin_data[1]); 26433b9b51feSCy Schubert } 26443b9b51feSCy Schubert 26453b9b51feSCy Schubert /* 26463b9b51feSCy Schubert * Do a loop until we either run out of entries to try or we find 26473b9b51feSCy Schubert * a NAT mapping that isn't currently being used. This is done 26483b9b51feSCy Schubert * because the change to the source is not (usually) being fixed. 26493b9b51feSCy Schubert */ 26503b9b51feSCy Schubert do { 26513b9b51feSCy Schubert port = 0; 26523b9b51feSCy Schubert in.s_addr = htonl(np->in_snip); 26533b9b51feSCy Schubert if (l == 0) { 26543b9b51feSCy Schubert /* 26553b9b51feSCy Schubert * Check to see if there is an existing NAT 26563b9b51feSCy Schubert * setup for this IP address pair. 26573b9b51feSCy Schubert */ 26583b9b51feSCy Schubert hm = ipf_nat_hostmap(softn, np, fin->fin_src, 26593b9b51feSCy Schubert fin->fin_dst, in, 0); 26603b9b51feSCy Schubert if (hm != NULL) 26613b9b51feSCy Schubert in.s_addr = hm->hm_nsrcip.s_addr; 26623b9b51feSCy Schubert } else if ((l == 1) && (hm != NULL)) { 26633b9b51feSCy Schubert ipf_nat_hostmapdel(softc, &hm); 26643b9b51feSCy Schubert } 26653b9b51feSCy Schubert in.s_addr = ntohl(in.s_addr); 26663b9b51feSCy Schubert 26673b9b51feSCy Schubert nat->nat_hm = hm; 26683b9b51feSCy Schubert 26693b9b51feSCy Schubert if ((np->in_nsrcmsk == 0xffffffff) && (np->in_spnext == 0)) { 26703b9b51feSCy Schubert if (l > 0) { 26713b9b51feSCy Schubert NBUMPSIDEX(1, ns_exhausted, ns_exhausted_1); 26723b9b51feSCy Schubert DT4(ns_exhausted_1, fr_info_t *, fin, nat_t *, nat, natinfo_t *, ni, ipnat_t *, np); 26733b9b51feSCy Schubert return -1; 26743b9b51feSCy Schubert } 26753b9b51feSCy Schubert } 26763b9b51feSCy Schubert 26773b9b51feSCy Schubert if (np->in_redir == NAT_BIMAP && 26783b9b51feSCy Schubert np->in_osrcmsk == np->in_nsrcmsk) { 26793b9b51feSCy Schubert /* 26803b9b51feSCy Schubert * map the address block in a 1:1 fashion 26813b9b51feSCy Schubert */ 26823b9b51feSCy Schubert in.s_addr = np->in_nsrcaddr; 26833b9b51feSCy Schubert in.s_addr |= fin->fin_saddr & ~np->in_osrcmsk; 26843b9b51feSCy Schubert in.s_addr = ntohl(in.s_addr); 26853b9b51feSCy Schubert 26863b9b51feSCy Schubert } else if (np->in_redir & NAT_MAPBLK) { 26873b9b51feSCy Schubert if ((l >= np->in_ppip) || ((l > 0) && 26883b9b51feSCy Schubert !(flags & IPN_TCPUDP))) { 26893b9b51feSCy Schubert NBUMPSIDEX(1, ns_exhausted, ns_exhausted_2); 26903b9b51feSCy Schubert DT4(ns_exhausted_2, fr_info_t *, fin, nat_t *, nat, natinfo_t *, ni, ipnat_t *, np); 26913b9b51feSCy Schubert return -1; 26923b9b51feSCy Schubert } 26933b9b51feSCy Schubert /* 26943b9b51feSCy Schubert * map-block - Calculate destination address. 26953b9b51feSCy Schubert */ 26963b9b51feSCy Schubert in.s_addr = ntohl(fin->fin_saddr); 26973b9b51feSCy Schubert in.s_addr &= ntohl(~np->in_osrcmsk); 26983b9b51feSCy Schubert inb.s_addr = in.s_addr; 26993b9b51feSCy Schubert in.s_addr /= np->in_ippip; 27003b9b51feSCy Schubert in.s_addr &= ntohl(~np->in_nsrcmsk); 27013b9b51feSCy Schubert in.s_addr += ntohl(np->in_nsrcaddr); 27023b9b51feSCy Schubert /* 27033b9b51feSCy Schubert * Calculate destination port. 27043b9b51feSCy Schubert */ 27053b9b51feSCy Schubert if ((flags & IPN_TCPUDP) && 27063b9b51feSCy Schubert (np->in_ppip != 0)) { 27073b9b51feSCy Schubert port = ntohs(sport) + l; 27083b9b51feSCy Schubert port %= np->in_ppip; 27093b9b51feSCy Schubert port += np->in_ppip * 27103b9b51feSCy Schubert (inb.s_addr % np->in_ippip); 27113b9b51feSCy Schubert port += MAPBLK_MINPORT; 27123b9b51feSCy Schubert port = htons(port); 27133b9b51feSCy Schubert } 27143b9b51feSCy Schubert 27153b9b51feSCy Schubert } else if ((np->in_nsrcaddr == 0) && 27163b9b51feSCy Schubert (np->in_nsrcmsk == 0xffffffff)) { 27173b9b51feSCy Schubert i6addr_t in6; 27183b9b51feSCy Schubert 27193b9b51feSCy Schubert /* 27203b9b51feSCy Schubert * 0/32 - use the interface's IP address. 27213b9b51feSCy Schubert */ 27223b9b51feSCy Schubert if ((l > 0) || 27233b9b51feSCy Schubert ipf_ifpaddr(softc, 4, FRI_NORMAL, fin->fin_ifp, 27243b9b51feSCy Schubert &in6, NULL) == -1) { 27253b9b51feSCy Schubert NBUMPSIDEX(1, ns_new_ifpaddr, ns_new_ifpaddr_1); 27263b9b51feSCy Schubert DT4(ns_new_ifpaddr_1, fr_info_t *, fin, nat_t *, nat, natinfo_t *, ni, ipnat_t *, np); 27273b9b51feSCy Schubert return -1; 27283b9b51feSCy Schubert } 27293b9b51feSCy Schubert in.s_addr = ntohl(in6.in4.s_addr); 27303b9b51feSCy Schubert 27313b9b51feSCy Schubert } else if ((np->in_nsrcaddr == 0) && (np->in_nsrcmsk == 0)) { 27323b9b51feSCy Schubert /* 27333b9b51feSCy Schubert * 0/0 - use the original source address/port. 27343b9b51feSCy Schubert */ 27353b9b51feSCy Schubert if (l > 0) { 27363b9b51feSCy Schubert NBUMPSIDEX(1, ns_exhausted, ns_exhausted_3); 27373b9b51feSCy Schubert DT4(ns_exhausted_3, fr_info_t *, fin, nat_t *, nat, natinfo_t *, ni, ipnat_t *, np); 27383b9b51feSCy Schubert return -1; 27393b9b51feSCy Schubert } 27403b9b51feSCy Schubert in.s_addr = ntohl(fin->fin_saddr); 27413b9b51feSCy Schubert 27423b9b51feSCy Schubert } else if ((np->in_nsrcmsk != 0xffffffff) && 27433b9b51feSCy Schubert (np->in_spnext == 0) && ((l > 0) || (hm == NULL))) 27443b9b51feSCy Schubert np->in_snip++; 27453b9b51feSCy Schubert 27463b9b51feSCy Schubert natl = NULL; 27473b9b51feSCy Schubert 27483b9b51feSCy Schubert if ((flags & IPN_TCPUDP) && 27493b9b51feSCy Schubert ((np->in_redir & NAT_MAPBLK) == 0) && 27503b9b51feSCy Schubert (np->in_flags & IPN_AUTOPORTMAP)) { 27513b9b51feSCy Schubert /* 27523b9b51feSCy Schubert * "ports auto" (without map-block) 27533b9b51feSCy Schubert */ 27543b9b51feSCy Schubert if ((l > 0) && (l % np->in_ppip == 0)) { 27553b9b51feSCy Schubert if ((l > np->in_ppip) && 27563b9b51feSCy Schubert np->in_nsrcmsk != 0xffffffff) 27573b9b51feSCy Schubert np->in_snip++; 27583b9b51feSCy Schubert } 27593b9b51feSCy Schubert if (np->in_ppip != 0) { 27603b9b51feSCy Schubert port = ntohs(sport); 27613b9b51feSCy Schubert port += (l % np->in_ppip); 27623b9b51feSCy Schubert port %= np->in_ppip; 27633b9b51feSCy Schubert port += np->in_ppip * 27643b9b51feSCy Schubert (ntohl(fin->fin_saddr) % 27653b9b51feSCy Schubert np->in_ippip); 27663b9b51feSCy Schubert port += MAPBLK_MINPORT; 27673b9b51feSCy Schubert port = htons(port); 27683b9b51feSCy Schubert } 27693b9b51feSCy Schubert 27703b9b51feSCy Schubert } else if (((np->in_redir & NAT_MAPBLK) == 0) && 27713b9b51feSCy Schubert (flags & IPN_TCPUDPICMP) && (np->in_spnext != 0)) { 27723b9b51feSCy Schubert /* 27733b9b51feSCy Schubert * Standard port translation. Select next port. 27743b9b51feSCy Schubert */ 27753b9b51feSCy Schubert if (np->in_flags & IPN_SEQUENTIAL) { 27763b9b51feSCy Schubert port = np->in_spnext; 27773b9b51feSCy Schubert } else { 27783b9b51feSCy Schubert port = ipf_random() % (np->in_spmax - 27793b9b51feSCy Schubert np->in_spmin + 1); 27803b9b51feSCy Schubert port += np->in_spmin; 27813b9b51feSCy Schubert } 27823b9b51feSCy Schubert port = htons(port); 27833b9b51feSCy Schubert np->in_spnext++; 27843b9b51feSCy Schubert 27853b9b51feSCy Schubert if (np->in_spnext > np->in_spmax) { 27863b9b51feSCy Schubert np->in_spnext = np->in_spmin; 27873b9b51feSCy Schubert if (np->in_nsrcmsk != 0xffffffff) 27883b9b51feSCy Schubert np->in_snip++; 27893b9b51feSCy Schubert } 27903b9b51feSCy Schubert } 27913b9b51feSCy Schubert 27923b9b51feSCy Schubert if (np->in_flags & IPN_SIPRANGE) { 27933b9b51feSCy Schubert if (np->in_snip > ntohl(np->in_nsrcmsk)) 27943b9b51feSCy Schubert np->in_snip = ntohl(np->in_nsrcaddr); 27953b9b51feSCy Schubert } else { 27963b9b51feSCy Schubert if ((np->in_nsrcmsk != 0xffffffff) && 27973b9b51feSCy Schubert ((np->in_snip + 1) & ntohl(np->in_nsrcmsk)) > 27983b9b51feSCy Schubert ntohl(np->in_nsrcaddr)) 27993b9b51feSCy Schubert np->in_snip = ntohl(np->in_nsrcaddr) + 1; 28003b9b51feSCy Schubert } 28013b9b51feSCy Schubert 28023b9b51feSCy Schubert if ((port == 0) && (flags & (IPN_TCPUDPICMP|IPN_ICMPQUERY))) 28033b9b51feSCy Schubert port = sport; 28043b9b51feSCy Schubert 28053b9b51feSCy Schubert /* 28063b9b51feSCy Schubert * Here we do a lookup of the connection as seen from 28073b9b51feSCy Schubert * the outside. If an IP# pair already exists, try 28083b9b51feSCy Schubert * again. So if you have A->B becomes C->B, you can 28093b9b51feSCy Schubert * also have D->E become C->E but not D->B causing 28103b9b51feSCy Schubert * another C->B. Also take protocol and ports into 28113b9b51feSCy Schubert * account when determining whether a pre-existing 28123b9b51feSCy Schubert * NAT setup will cause an external conflict where 28133b9b51feSCy Schubert * this is appropriate. 28143b9b51feSCy Schubert */ 28153b9b51feSCy Schubert inb.s_addr = htonl(in.s_addr); 28163b9b51feSCy Schubert sp = fin->fin_data[0]; 28173b9b51feSCy Schubert dp = fin->fin_data[1]; 28183b9b51feSCy Schubert fin->fin_data[0] = fin->fin_data[1]; 28193b9b51feSCy Schubert fin->fin_data[1] = ntohs(port); 28203b9b51feSCy Schubert natl = ipf_nat_inlookup(fin, flags & ~(SI_WILDP|NAT_SEARCH), 28213b9b51feSCy Schubert (u_int)fin->fin_p, fin->fin_dst, inb); 28223b9b51feSCy Schubert fin->fin_data[0] = sp; 28233b9b51feSCy Schubert fin->fin_data[1] = dp; 28243b9b51feSCy Schubert 28253b9b51feSCy Schubert /* 28263b9b51feSCy Schubert * Has the search wrapped around and come back to the 28273b9b51feSCy Schubert * start ? 28283b9b51feSCy Schubert */ 28293b9b51feSCy Schubert if ((natl != NULL) && 28303b9b51feSCy Schubert (np->in_spnext != 0) && (st_port == np->in_spnext) && 28313b9b51feSCy Schubert (np->in_snip != 0) && (st_ip == np->in_snip)) { 28323b9b51feSCy Schubert NBUMPSIDED(1, ns_wrap); 28333b9b51feSCy Schubert DT4(ns_wrap, fr_info_t *, fin, nat_t *, nat, natinfo_t *, ni, ipnat_t *, np); 28343b9b51feSCy Schubert return -1; 28353b9b51feSCy Schubert } 28363b9b51feSCy Schubert l++; 28373b9b51feSCy Schubert } while (natl != NULL); 28383b9b51feSCy Schubert 28393b9b51feSCy Schubert /* Setup the NAT table */ 28403b9b51feSCy Schubert nat->nat_osrcip = fin->fin_src; 28413b9b51feSCy Schubert nat->nat_nsrcaddr = htonl(in.s_addr); 28423b9b51feSCy Schubert nat->nat_odstip = fin->fin_dst; 28433b9b51feSCy Schubert nat->nat_ndstip = fin->fin_dst; 28443b9b51feSCy Schubert if (nat->nat_hm == NULL) 28453b9b51feSCy Schubert nat->nat_hm = ipf_nat_hostmap(softn, np, fin->fin_src, 28463b9b51feSCy Schubert fin->fin_dst, nat->nat_nsrcip, 28473b9b51feSCy Schubert 0); 28483b9b51feSCy Schubert 28493b9b51feSCy Schubert if (flags & IPN_TCPUDP) { 28503b9b51feSCy Schubert nat->nat_osport = sport; 28513b9b51feSCy Schubert nat->nat_nsport = port; /* sport */ 28523b9b51feSCy Schubert nat->nat_odport = dport; 28533b9b51feSCy Schubert nat->nat_ndport = dport; 28543b9b51feSCy Schubert ((tcphdr_t *)fin->fin_dp)->th_sport = port; 28553b9b51feSCy Schubert } else if (flags & IPN_ICMPQUERY) { 28563b9b51feSCy Schubert nat->nat_oicmpid = fin->fin_data[1]; 28573b9b51feSCy Schubert ((icmphdr_t *)fin->fin_dp)->icmp_id = port; 28583b9b51feSCy Schubert nat->nat_nicmpid = port; 28593b9b51feSCy Schubert } 28603b9b51feSCy Schubert return 0; 28613b9b51feSCy Schubert } 28623b9b51feSCy Schubert 28633b9b51feSCy Schubert 28643b9b51feSCy Schubert /* ------------------------------------------------------------------------ */ 28653b9b51feSCy Schubert /* Function: ipf_nat_newrdr */ 28663b9b51feSCy Schubert /* Returns: int - -1 == error, 0 == success (no move), 1 == success and */ 28673b9b51feSCy Schubert /* allow rule to be moved if IPN_ROUNDR is set. */ 28683b9b51feSCy Schubert /* Parameters: fin(I) - pointer to packet information */ 28693b9b51feSCy Schubert /* nat(I) - pointer to NAT entry */ 28703b9b51feSCy Schubert /* ni(I) - pointer to structure with misc. information needed */ 28713b9b51feSCy Schubert /* to create new NAT entry. */ 28723b9b51feSCy Schubert /* */ 28733b9b51feSCy Schubert /* ni.nai_ip is passed in uninitialised and must be set, in host byte order,*/ 28743b9b51feSCy Schubert /* to the new IP address for the translation. */ 28753b9b51feSCy Schubert /* ------------------------------------------------------------------------ */ 28763b9b51feSCy Schubert static int 28773b9b51feSCy Schubert ipf_nat_newrdr(fin, nat, ni) 28783b9b51feSCy Schubert fr_info_t *fin; 28793b9b51feSCy Schubert nat_t *nat; 28803b9b51feSCy Schubert natinfo_t *ni; 28813b9b51feSCy Schubert { 28823b9b51feSCy Schubert ipf_main_softc_t *softc = fin->fin_main_soft; 28833b9b51feSCy Schubert ipf_nat_softc_t *softn = softc->ipf_nat_soft; 28843b9b51feSCy Schubert u_short nport, dport, sport; 28853b9b51feSCy Schubert struct in_addr in, inb; 28863b9b51feSCy Schubert u_short sp, dp; 28873b9b51feSCy Schubert hostmap_t *hm; 28883b9b51feSCy Schubert u_32_t flags; 28893b9b51feSCy Schubert ipnat_t *np; 28903b9b51feSCy Schubert nat_t *natl; 28913b9b51feSCy Schubert int move; 28923b9b51feSCy Schubert 28933b9b51feSCy Schubert move = 1; 28943b9b51feSCy Schubert hm = NULL; 28953b9b51feSCy Schubert in.s_addr = 0; 28963b9b51feSCy Schubert np = ni->nai_np; 28973b9b51feSCy Schubert flags = nat->nat_flags; 28983b9b51feSCy Schubert 28993b9b51feSCy Schubert if (flags & IPN_ICMPQUERY) { 29003b9b51feSCy Schubert dport = fin->fin_data[1]; 29013b9b51feSCy Schubert sport = 0; 29023b9b51feSCy Schubert } else { 29033b9b51feSCy Schubert sport = htons(fin->fin_data[0]); 29043b9b51feSCy Schubert dport = htons(fin->fin_data[1]); 29053b9b51feSCy Schubert } 29063b9b51feSCy Schubert 29073b9b51feSCy Schubert /* TRACE sport, dport */ 29083b9b51feSCy Schubert 29093b9b51feSCy Schubert 29103b9b51feSCy Schubert /* 29113b9b51feSCy Schubert * If the matching rule has IPN_STICKY set, then we want to have the 29123b9b51feSCy Schubert * same rule kick in as before. Why would this happen? If you have 29133b9b51feSCy Schubert * a collection of rdr rules with "round-robin sticky", the current 29143b9b51feSCy Schubert * packet might match a different one to the previous connection but 29153b9b51feSCy Schubert * we want the same destination to be used. 29163b9b51feSCy Schubert */ 29173b9b51feSCy Schubert if (((np->in_flags & (IPN_ROUNDR|IPN_SPLIT)) != 0) && 29183b9b51feSCy Schubert ((np->in_flags & IPN_STICKY) != 0)) { 29193b9b51feSCy Schubert hm = ipf_nat_hostmap(softn, NULL, fin->fin_src, fin->fin_dst, 29203b9b51feSCy Schubert in, (u_32_t)dport); 29213b9b51feSCy Schubert if (hm != NULL) { 29223b9b51feSCy Schubert in.s_addr = ntohl(hm->hm_ndstip.s_addr); 29233b9b51feSCy Schubert np = hm->hm_ipnat; 29243b9b51feSCy Schubert ni->nai_np = np; 29253b9b51feSCy Schubert move = 0; 29263b9b51feSCy Schubert ipf_nat_hostmapdel(softc, &hm); 29273b9b51feSCy Schubert } 29283b9b51feSCy Schubert } 29293b9b51feSCy Schubert 29303b9b51feSCy Schubert /* 29313b9b51feSCy Schubert * Otherwise, it's an inbound packet. Most likely, we don't 29323b9b51feSCy Schubert * want to rewrite source ports and source addresses. Instead, 29333b9b51feSCy Schubert * we want to rewrite to a fixed internal address and fixed 29343b9b51feSCy Schubert * internal port. 29353b9b51feSCy Schubert */ 29363b9b51feSCy Schubert if (np->in_flags & IPN_SPLIT) { 29373b9b51feSCy Schubert in.s_addr = np->in_dnip; 29383b9b51feSCy Schubert inb.s_addr = htonl(in.s_addr); 29393b9b51feSCy Schubert 29403b9b51feSCy Schubert if ((np->in_flags & (IPN_ROUNDR|IPN_STICKY)) == IPN_STICKY) { 29413b9b51feSCy Schubert hm = ipf_nat_hostmap(softn, NULL, fin->fin_src, 29423b9b51feSCy Schubert fin->fin_dst, inb, (u_32_t)dport); 29433b9b51feSCy Schubert if (hm != NULL) { 29443b9b51feSCy Schubert in.s_addr = hm->hm_ndstip.s_addr; 29453b9b51feSCy Schubert move = 0; 29463b9b51feSCy Schubert } 29473b9b51feSCy Schubert } 29483b9b51feSCy Schubert 29493b9b51feSCy Schubert if (hm == NULL || hm->hm_ref == 1) { 29503b9b51feSCy Schubert if (np->in_ndstaddr == htonl(in.s_addr)) { 29513b9b51feSCy Schubert np->in_dnip = ntohl(np->in_ndstmsk); 29523b9b51feSCy Schubert move = 0; 29533b9b51feSCy Schubert } else { 29543b9b51feSCy Schubert np->in_dnip = ntohl(np->in_ndstaddr); 29553b9b51feSCy Schubert } 29563b9b51feSCy Schubert } 29573b9b51feSCy Schubert if (hm != NULL) 29583b9b51feSCy Schubert ipf_nat_hostmapdel(softc, &hm); 29593b9b51feSCy Schubert 29603b9b51feSCy Schubert } else if ((np->in_ndstaddr == 0) && (np->in_ndstmsk == 0xffffffff)) { 29613b9b51feSCy Schubert i6addr_t in6; 29623b9b51feSCy Schubert 29633b9b51feSCy Schubert /* 29643b9b51feSCy Schubert * 0/32 - use the interface's IP address. 29653b9b51feSCy Schubert */ 29663b9b51feSCy Schubert if (ipf_ifpaddr(softc, 4, FRI_NORMAL, fin->fin_ifp, 29673b9b51feSCy Schubert &in6, NULL) == -1) { 29683b9b51feSCy Schubert NBUMPSIDEX(0, ns_new_ifpaddr, ns_new_ifpaddr_2); 29693b9b51feSCy Schubert DT3(ns_new_ifpaddr_2, fr_info_t *, fin, nat_t *, nat, natinfo_t, ni); 29703b9b51feSCy Schubert return -1; 29713b9b51feSCy Schubert } 29723b9b51feSCy Schubert in.s_addr = ntohl(in6.in4.s_addr); 29733b9b51feSCy Schubert 29743b9b51feSCy Schubert } else if ((np->in_ndstaddr == 0) && (np->in_ndstmsk== 0)) { 29753b9b51feSCy Schubert /* 29763b9b51feSCy Schubert * 0/0 - use the original destination address/port. 29773b9b51feSCy Schubert */ 29783b9b51feSCy Schubert in.s_addr = ntohl(fin->fin_daddr); 29793b9b51feSCy Schubert 29803b9b51feSCy Schubert } else if (np->in_redir == NAT_BIMAP && 29813b9b51feSCy Schubert np->in_ndstmsk == np->in_odstmsk) { 29823b9b51feSCy Schubert /* 29833b9b51feSCy Schubert * map the address block in a 1:1 fashion 29843b9b51feSCy Schubert */ 29853b9b51feSCy Schubert in.s_addr = np->in_ndstaddr; 29863b9b51feSCy Schubert in.s_addr |= fin->fin_daddr & ~np->in_ndstmsk; 29873b9b51feSCy Schubert in.s_addr = ntohl(in.s_addr); 29883b9b51feSCy Schubert } else { 29893b9b51feSCy Schubert in.s_addr = ntohl(np->in_ndstaddr); 29903b9b51feSCy Schubert } 29913b9b51feSCy Schubert 29923b9b51feSCy Schubert if ((np->in_dpnext == 0) || ((flags & NAT_NOTRULEPORT) != 0)) 29933b9b51feSCy Schubert nport = dport; 29943b9b51feSCy Schubert else { 29953b9b51feSCy Schubert /* 29963b9b51feSCy Schubert * Whilst not optimized for the case where 29973b9b51feSCy Schubert * pmin == pmax, the gain is not significant. 29983b9b51feSCy Schubert */ 29993b9b51feSCy Schubert if (((np->in_flags & IPN_FIXEDDPORT) == 0) && 30003b9b51feSCy Schubert (np->in_odport != np->in_dtop)) { 30013b9b51feSCy Schubert nport = ntohs(dport) - np->in_odport + np->in_dpmax; 30023b9b51feSCy Schubert nport = htons(nport); 30033b9b51feSCy Schubert } else { 30043b9b51feSCy Schubert nport = htons(np->in_dpnext); 30053b9b51feSCy Schubert np->in_dpnext++; 30063b9b51feSCy Schubert if (np->in_dpnext > np->in_dpmax) 30073b9b51feSCy Schubert np->in_dpnext = np->in_dpmin; 30083b9b51feSCy Schubert } 30093b9b51feSCy Schubert } 30103b9b51feSCy Schubert 30113b9b51feSCy Schubert /* 30123b9b51feSCy Schubert * When the redirect-to address is set to 0.0.0.0, just 30133b9b51feSCy Schubert * assume a blank `forwarding' of the packet. We don't 30143b9b51feSCy Schubert * setup any translation for this either. 30153b9b51feSCy Schubert */ 30163b9b51feSCy Schubert if (in.s_addr == 0) { 30173b9b51feSCy Schubert if (nport == dport) { 30183b9b51feSCy Schubert NBUMPSIDED(0, ns_xlate_null); 30193b9b51feSCy Schubert return -1; 30203b9b51feSCy Schubert } 30213b9b51feSCy Schubert in.s_addr = ntohl(fin->fin_daddr); 30223b9b51feSCy Schubert } 30233b9b51feSCy Schubert 30243b9b51feSCy Schubert /* 30253b9b51feSCy Schubert * Check to see if this redirect mapping already exists and if 30263b9b51feSCy Schubert * it does, return "failure" (allowing it to be created will just 30273b9b51feSCy Schubert * cause one or both of these "connections" to stop working.) 30283b9b51feSCy Schubert */ 30293b9b51feSCy Schubert inb.s_addr = htonl(in.s_addr); 30303b9b51feSCy Schubert sp = fin->fin_data[0]; 30313b9b51feSCy Schubert dp = fin->fin_data[1]; 30323b9b51feSCy Schubert fin->fin_data[1] = fin->fin_data[0]; 30333b9b51feSCy Schubert fin->fin_data[0] = ntohs(nport); 30343b9b51feSCy Schubert natl = ipf_nat_outlookup(fin, flags & ~(SI_WILDP|NAT_SEARCH), 30353b9b51feSCy Schubert (u_int)fin->fin_p, inb, fin->fin_src); 30363b9b51feSCy Schubert fin->fin_data[0] = sp; 30373b9b51feSCy Schubert fin->fin_data[1] = dp; 30383b9b51feSCy Schubert if (natl != NULL) { 30393b9b51feSCy Schubert DT2(ns_new_xlate_exists, fr_info_t *, fin, nat_t *, natl); 30403b9b51feSCy Schubert NBUMPSIDE(0, ns_xlate_exists); 30413b9b51feSCy Schubert return -1; 30423b9b51feSCy Schubert } 30433b9b51feSCy Schubert 30443b9b51feSCy Schubert inb.s_addr = htonl(in.s_addr); 30453b9b51feSCy Schubert nat->nat_ndstaddr = htonl(in.s_addr); 30463b9b51feSCy Schubert nat->nat_odstip = fin->fin_dst; 30473b9b51feSCy Schubert nat->nat_nsrcip = fin->fin_src; 30483b9b51feSCy Schubert nat->nat_osrcip = fin->fin_src; 30493b9b51feSCy Schubert if ((nat->nat_hm == NULL) && ((np->in_flags & IPN_STICKY) != 0)) 30503b9b51feSCy Schubert nat->nat_hm = ipf_nat_hostmap(softn, np, fin->fin_src, 30513b9b51feSCy Schubert fin->fin_dst, inb, (u_32_t)dport); 30523b9b51feSCy Schubert 30533b9b51feSCy Schubert if (flags & IPN_TCPUDP) { 30543b9b51feSCy Schubert nat->nat_odport = dport; 30553b9b51feSCy Schubert nat->nat_ndport = nport; 30563b9b51feSCy Schubert nat->nat_osport = sport; 30573b9b51feSCy Schubert nat->nat_nsport = sport; 30583b9b51feSCy Schubert ((tcphdr_t *)fin->fin_dp)->th_dport = nport; 30593b9b51feSCy Schubert } else if (flags & IPN_ICMPQUERY) { 30603b9b51feSCy Schubert nat->nat_oicmpid = fin->fin_data[1]; 30613b9b51feSCy Schubert ((icmphdr_t *)fin->fin_dp)->icmp_id = nport; 30623b9b51feSCy Schubert nat->nat_nicmpid = nport; 30633b9b51feSCy Schubert } 30643b9b51feSCy Schubert 30653b9b51feSCy Schubert return move; 30663b9b51feSCy Schubert } 30673b9b51feSCy Schubert 30683b9b51feSCy Schubert /* ------------------------------------------------------------------------ */ 30693b9b51feSCy Schubert /* Function: ipf_nat_add */ 30703b9b51feSCy Schubert /* Returns: nat_t* - NULL == failure to create new NAT structure, */ 30713b9b51feSCy Schubert /* else pointer to new NAT structure */ 30723b9b51feSCy Schubert /* Parameters: fin(I) - pointer to packet information */ 30733b9b51feSCy Schubert /* np(I) - pointer to NAT rule */ 30743b9b51feSCy Schubert /* natsave(I) - pointer to where to store NAT struct pointer */ 30753b9b51feSCy Schubert /* flags(I) - flags describing the current packet */ 30763b9b51feSCy Schubert /* direction(I) - direction of packet (in/out) */ 30773b9b51feSCy Schubert /* Write Lock: ipf_nat */ 30783b9b51feSCy Schubert /* */ 30793b9b51feSCy Schubert /* Attempts to create a new NAT entry. Does not actually change the packet */ 30803b9b51feSCy Schubert /* in any way. */ 30813b9b51feSCy Schubert /* */ 30823b9b51feSCy Schubert /* This function is in three main parts: (1) deal with creating a new NAT */ 30833b9b51feSCy Schubert /* structure for a "MAP" rule (outgoing NAT translation); (2) deal with */ 30843b9b51feSCy Schubert /* creating a new NAT structure for a "RDR" rule (incoming NAT translation) */ 30853b9b51feSCy Schubert /* and (3) building that structure and putting it into the NAT table(s). */ 30863b9b51feSCy Schubert /* */ 30873b9b51feSCy Schubert /* NOTE: natsave should NOT be used to point back to an ipstate_t struct */ 30883b9b51feSCy Schubert /* as it can result in memory being corrupted. */ 30893b9b51feSCy Schubert /* ------------------------------------------------------------------------ */ 30903b9b51feSCy Schubert nat_t * 30913b9b51feSCy Schubert ipf_nat_add(fin, np, natsave, flags, direction) 30923b9b51feSCy Schubert fr_info_t *fin; 30933b9b51feSCy Schubert ipnat_t *np; 30943b9b51feSCy Schubert nat_t **natsave; 30953b9b51feSCy Schubert u_int flags; 30963b9b51feSCy Schubert int direction; 30973b9b51feSCy Schubert { 30983b9b51feSCy Schubert ipf_main_softc_t *softc = fin->fin_main_soft; 30993b9b51feSCy Schubert ipf_nat_softc_t *softn = softc->ipf_nat_soft; 31003b9b51feSCy Schubert hostmap_t *hm = NULL; 31013b9b51feSCy Schubert nat_t *nat, *natl; 31023b9b51feSCy Schubert natstat_t *nsp; 31033b9b51feSCy Schubert u_int nflags; 31043b9b51feSCy Schubert natinfo_t ni; 31053b9b51feSCy Schubert int move; 31063b9b51feSCy Schubert 31073b9b51feSCy Schubert nsp = &softn->ipf_nat_stats; 31083b9b51feSCy Schubert 31093b9b51feSCy Schubert if ((nsp->ns_active * 100 / softn->ipf_nat_table_max) > 31103b9b51feSCy Schubert softn->ipf_nat_table_wm_high) { 31113b9b51feSCy Schubert softn->ipf_nat_doflush = 1; 31123b9b51feSCy Schubert } 31133b9b51feSCy Schubert 31143b9b51feSCy Schubert if (nsp->ns_active >= softn->ipf_nat_table_max) { 31153b9b51feSCy Schubert NBUMPSIDED(fin->fin_out, ns_table_max); 31163b9b51feSCy Schubert DT2(ns_table_max, nat_stat_t *, nsp, ipf_nat_softc_t *, softn); 31173b9b51feSCy Schubert return NULL; 31183b9b51feSCy Schubert } 31193b9b51feSCy Schubert 31203b9b51feSCy Schubert move = 1; 31213b9b51feSCy Schubert nflags = np->in_flags & flags; 31223b9b51feSCy Schubert nflags &= NAT_FROMRULE; 31233b9b51feSCy Schubert 31243b9b51feSCy Schubert ni.nai_np = np; 31253b9b51feSCy Schubert ni.nai_dport = 0; 31263b9b51feSCy Schubert ni.nai_sport = 0; 31273b9b51feSCy Schubert 31283b9b51feSCy Schubert /* Give me a new nat */ 31293b9b51feSCy Schubert KMALLOC(nat, nat_t *); 31303b9b51feSCy Schubert if (nat == NULL) { 31313b9b51feSCy Schubert DT(ns_memfail); 31323b9b51feSCy Schubert NBUMPSIDED(fin->fin_out, ns_memfail); 31333b9b51feSCy Schubert /* 31343b9b51feSCy Schubert * Try to automatically tune the max # of entries in the 31353b9b51feSCy Schubert * table allowed to be less than what will cause kmem_alloc() 31363b9b51feSCy Schubert * to fail and try to eliminate panics due to out of memory 31373b9b51feSCy Schubert * conditions arising. 31383b9b51feSCy Schubert */ 31393b9b51feSCy Schubert if ((softn->ipf_nat_table_max > softn->ipf_nat_table_sz) && 31403b9b51feSCy Schubert (nsp->ns_active > 100)) { 31413b9b51feSCy Schubert softn->ipf_nat_table_max = nsp->ns_active - 100; 31423b9b51feSCy Schubert printf("table_max reduced to %d\n", 31433b9b51feSCy Schubert softn->ipf_nat_table_max); 31443b9b51feSCy Schubert } 31453b9b51feSCy Schubert return NULL; 31463b9b51feSCy Schubert } 31473b9b51feSCy Schubert 31483b9b51feSCy Schubert if (flags & IPN_ICMPQUERY) { 31493b9b51feSCy Schubert /* 31503b9b51feSCy Schubert * In the ICMP query NAT code, we translate the ICMP id fields 31513b9b51feSCy Schubert * to make them unique. This is indepedent of the ICMP type 31523b9b51feSCy Schubert * (e.g. in the unlikely event that a host sends an echo and 31533b9b51feSCy Schubert * an tstamp request with the same id, both packets will have 31543b9b51feSCy Schubert * their ip address/id field changed in the same way). 31553b9b51feSCy Schubert */ 31563b9b51feSCy Schubert /* The icmp_id field is used by the sender to identify the 31573b9b51feSCy Schubert * process making the icmp request. (the receiver justs 31583b9b51feSCy Schubert * copies it back in its response). So, it closely matches 31593b9b51feSCy Schubert * the concept of source port. We overlay sport, so we can 31603b9b51feSCy Schubert * maximally reuse the existing code. 31613b9b51feSCy Schubert */ 31623b9b51feSCy Schubert ni.nai_sport = fin->fin_data[1]; 31633b9b51feSCy Schubert ni.nai_dport = 0; 31643b9b51feSCy Schubert } 31653b9b51feSCy Schubert 31663b9b51feSCy Schubert bzero((char *)nat, sizeof(*nat)); 31673b9b51feSCy Schubert nat->nat_flags = flags; 31683b9b51feSCy Schubert nat->nat_redir = np->in_redir; 31693b9b51feSCy Schubert nat->nat_dir = direction; 31703b9b51feSCy Schubert nat->nat_pr[0] = fin->fin_p; 31713b9b51feSCy Schubert nat->nat_pr[1] = fin->fin_p; 31723b9b51feSCy Schubert 31733b9b51feSCy Schubert /* 31743b9b51feSCy Schubert * Search the current table for a match and create a new mapping 31753b9b51feSCy Schubert * if there is none found. 31763b9b51feSCy Schubert */ 31773b9b51feSCy Schubert if (np->in_redir & NAT_DIVERTUDP) { 31783b9b51feSCy Schubert move = ipf_nat_newdivert(fin, nat, &ni); 31793b9b51feSCy Schubert 31803b9b51feSCy Schubert } else if (np->in_redir & NAT_REWRITE) { 31813b9b51feSCy Schubert move = ipf_nat_newrewrite(fin, nat, &ni); 31823b9b51feSCy Schubert 31833b9b51feSCy Schubert } else if (direction == NAT_OUTBOUND) { 31843b9b51feSCy Schubert /* 31853b9b51feSCy Schubert * We can now arrange to call this for the same connection 31863b9b51feSCy Schubert * because ipf_nat_new doesn't protect the code path into 31873b9b51feSCy Schubert * this function. 31883b9b51feSCy Schubert */ 31893b9b51feSCy Schubert natl = ipf_nat_outlookup(fin, nflags, (u_int)fin->fin_p, 31903b9b51feSCy Schubert fin->fin_src, fin->fin_dst); 31913b9b51feSCy Schubert if (natl != NULL) { 31923b9b51feSCy Schubert KFREE(nat); 31933b9b51feSCy Schubert nat = natl; 31943b9b51feSCy Schubert goto done; 31953b9b51feSCy Schubert } 31963b9b51feSCy Schubert 31973b9b51feSCy Schubert move = ipf_nat_newmap(fin, nat, &ni); 31983b9b51feSCy Schubert } else { 31993b9b51feSCy Schubert /* 32003b9b51feSCy Schubert * NAT_INBOUND is used for redirects rules 32013b9b51feSCy Schubert */ 32023b9b51feSCy Schubert natl = ipf_nat_inlookup(fin, nflags, (u_int)fin->fin_p, 32033b9b51feSCy Schubert fin->fin_src, fin->fin_dst); 32043b9b51feSCy Schubert if (natl != NULL) { 32053b9b51feSCy Schubert KFREE(nat); 32063b9b51feSCy Schubert nat = natl; 32073b9b51feSCy Schubert goto done; 32083b9b51feSCy Schubert } 32093b9b51feSCy Schubert 32103b9b51feSCy Schubert move = ipf_nat_newrdr(fin, nat, &ni); 32113b9b51feSCy Schubert } 32123b9b51feSCy Schubert if (move == -1) 32133b9b51feSCy Schubert goto badnat; 32143b9b51feSCy Schubert 32153b9b51feSCy Schubert np = ni.nai_np; 32163b9b51feSCy Schubert 32173b9b51feSCy Schubert nat->nat_mssclamp = np->in_mssclamp; 32183b9b51feSCy Schubert nat->nat_me = natsave; 32193b9b51feSCy Schubert nat->nat_fr = fin->fin_fr; 32203b9b51feSCy Schubert nat->nat_rev = fin->fin_rev; 32213b9b51feSCy Schubert nat->nat_ptr = np; 32223b9b51feSCy Schubert nat->nat_dlocal = np->in_dlocal; 32233b9b51feSCy Schubert 32243b9b51feSCy Schubert if ((np->in_apr != NULL) && ((nat->nat_flags & NAT_SLAVE) == 0)) { 32253b9b51feSCy Schubert if (ipf_proxy_new(fin, nat) == -1) { 32263b9b51feSCy Schubert NBUMPSIDED(fin->fin_out, ns_appr_fail); 32273b9b51feSCy Schubert DT3(ns_appr_fail, fr_info_t *, fin, nat_t *, nat, ipnat_t *, np); 32283b9b51feSCy Schubert goto badnat; 32293b9b51feSCy Schubert } 32303b9b51feSCy Schubert } 32313b9b51feSCy Schubert 32323b9b51feSCy Schubert nat->nat_ifps[0] = np->in_ifps[0]; 32333b9b51feSCy Schubert if (np->in_ifps[0] != NULL) { 32343b9b51feSCy Schubert COPYIFNAME(np->in_v[0], np->in_ifps[0], nat->nat_ifnames[0]); 32353b9b51feSCy Schubert } 32363b9b51feSCy Schubert 32373b9b51feSCy Schubert nat->nat_ifps[1] = np->in_ifps[1]; 32383b9b51feSCy Schubert if (np->in_ifps[1] != NULL) { 32393b9b51feSCy Schubert COPYIFNAME(np->in_v[1], np->in_ifps[1], nat->nat_ifnames[1]); 32403b9b51feSCy Schubert } 32413b9b51feSCy Schubert 32423b9b51feSCy Schubert if (ipf_nat_finalise(fin, nat) == -1) { 32433b9b51feSCy Schubert goto badnat; 32443b9b51feSCy Schubert } 32453b9b51feSCy Schubert 32463b9b51feSCy Schubert np->in_use++; 32473b9b51feSCy Schubert 32483b9b51feSCy Schubert if ((move == 1) && (np->in_flags & IPN_ROUNDR)) { 32493b9b51feSCy Schubert if ((np->in_redir & (NAT_REDIRECT|NAT_MAP)) == NAT_REDIRECT) { 32503b9b51feSCy Schubert ipf_nat_delrdr(softn, np); 32513b9b51feSCy Schubert ipf_nat_addrdr(softn, np); 32523b9b51feSCy Schubert } else if ((np->in_redir & (NAT_REDIRECT|NAT_MAP)) == NAT_MAP) { 32533b9b51feSCy Schubert ipf_nat_delmap(softn, np); 32543b9b51feSCy Schubert ipf_nat_addmap(softn, np); 32553b9b51feSCy Schubert } 32563b9b51feSCy Schubert } 32573b9b51feSCy Schubert 32583b9b51feSCy Schubert if (flags & SI_WILDP) 32593b9b51feSCy Schubert nsp->ns_wilds++; 32603b9b51feSCy Schubert nsp->ns_proto[nat->nat_pr[0]]++; 32613b9b51feSCy Schubert 32623b9b51feSCy Schubert goto done; 32633b9b51feSCy Schubert badnat: 32643b9b51feSCy Schubert DT3(ns_badnatnew, fr_info_t *, fin, nat_t *, nat, ipnat_t *, np); 32653b9b51feSCy Schubert NBUMPSIDE(fin->fin_out, ns_badnatnew); 32663b9b51feSCy Schubert if ((hm = nat->nat_hm) != NULL) 32673b9b51feSCy Schubert ipf_nat_hostmapdel(softc, &hm); 32683b9b51feSCy Schubert KFREE(nat); 32693b9b51feSCy Schubert nat = NULL; 32703b9b51feSCy Schubert done: 32713b9b51feSCy Schubert if (nat != NULL && np != NULL) 32723b9b51feSCy Schubert np->in_hits++; 32733b9b51feSCy Schubert if (natsave != NULL) 32743b9b51feSCy Schubert *natsave = nat; 32753b9b51feSCy Schubert return nat; 32763b9b51feSCy Schubert } 32773b9b51feSCy Schubert 32783b9b51feSCy Schubert 32793b9b51feSCy Schubert /* ------------------------------------------------------------------------ */ 32803b9b51feSCy Schubert /* Function: ipf_nat_finalise */ 32813b9b51feSCy Schubert /* Returns: int - 0 == sucess, -1 == failure */ 32823b9b51feSCy Schubert /* Parameters: fin(I) - pointer to packet information */ 32833b9b51feSCy Schubert /* nat(I) - pointer to NAT entry */ 32843b9b51feSCy Schubert /* Write Lock: ipf_nat */ 32853b9b51feSCy Schubert /* */ 32863b9b51feSCy Schubert /* This is the tail end of constructing a new NAT entry and is the same */ 32873b9b51feSCy Schubert /* for both IPv4 and IPv6. */ 32883b9b51feSCy Schubert /* ------------------------------------------------------------------------ */ 32893b9b51feSCy Schubert /*ARGSUSED*/ 32903b9b51feSCy Schubert static int 32913b9b51feSCy Schubert ipf_nat_finalise(fin, nat) 32923b9b51feSCy Schubert fr_info_t *fin; 32933b9b51feSCy Schubert nat_t *nat; 32943b9b51feSCy Schubert { 32953b9b51feSCy Schubert ipf_main_softc_t *softc = fin->fin_main_soft; 32963b9b51feSCy Schubert ipf_nat_softc_t *softn = softc->ipf_nat_soft; 32973b9b51feSCy Schubert u_32_t sum1, sum2, sumd; 32983b9b51feSCy Schubert frentry_t *fr; 32993b9b51feSCy Schubert u_32_t flags; 33003b9b51feSCy Schubert #if SOLARIS && defined(_KERNEL) && defined(ICK_M_CTL_MAGIC) 33013b9b51feSCy Schubert qpktinfo_t *qpi = fin->fin_qpi; 33023b9b51feSCy Schubert #endif 33033b9b51feSCy Schubert 33043b9b51feSCy Schubert flags = nat->nat_flags; 33053b9b51feSCy Schubert 33063b9b51feSCy Schubert switch (nat->nat_pr[0]) 33073b9b51feSCy Schubert { 33083b9b51feSCy Schubert case IPPROTO_ICMP : 33093b9b51feSCy Schubert sum1 = LONG_SUM(ntohs(nat->nat_oicmpid)); 33103b9b51feSCy Schubert sum2 = LONG_SUM(ntohs(nat->nat_nicmpid)); 33113b9b51feSCy Schubert CALC_SUMD(sum1, sum2, sumd); 33123b9b51feSCy Schubert nat->nat_sumd[0] = (sumd & 0xffff) + (sumd >> 16); 33133b9b51feSCy Schubert 33143b9b51feSCy Schubert break; 33153b9b51feSCy Schubert 33163b9b51feSCy Schubert default : 33173b9b51feSCy Schubert sum1 = LONG_SUM(ntohl(nat->nat_osrcaddr) + \ 33183b9b51feSCy Schubert ntohs(nat->nat_osport)); 33193b9b51feSCy Schubert sum2 = LONG_SUM(ntohl(nat->nat_nsrcaddr) + \ 33203b9b51feSCy Schubert ntohs(nat->nat_nsport)); 33213b9b51feSCy Schubert CALC_SUMD(sum1, sum2, sumd); 33223b9b51feSCy Schubert nat->nat_sumd[0] = (sumd & 0xffff) + (sumd >> 16); 33233b9b51feSCy Schubert 33243b9b51feSCy Schubert sum1 = LONG_SUM(ntohl(nat->nat_odstaddr) + \ 33253b9b51feSCy Schubert ntohs(nat->nat_odport)); 33263b9b51feSCy Schubert sum2 = LONG_SUM(ntohl(nat->nat_ndstaddr) + \ 33273b9b51feSCy Schubert ntohs(nat->nat_ndport)); 33283b9b51feSCy Schubert CALC_SUMD(sum1, sum2, sumd); 33293b9b51feSCy Schubert nat->nat_sumd[0] += (sumd & 0xffff) + (sumd >> 16); 33303b9b51feSCy Schubert break; 33313b9b51feSCy Schubert } 33323b9b51feSCy Schubert 33333b9b51feSCy Schubert /* 33343b9b51feSCy Schubert * Compute the partial checksum, just in case. 33353b9b51feSCy Schubert * This is only ever placed into outbound packets so care needs 33363b9b51feSCy Schubert * to be taken over which pair of addresses are used. 33373b9b51feSCy Schubert */ 33383b9b51feSCy Schubert if (nat->nat_dir == NAT_OUTBOUND) { 33393b9b51feSCy Schubert sum1 = LONG_SUM(ntohl(nat->nat_nsrcaddr)); 33403b9b51feSCy Schubert sum1 += LONG_SUM(ntohl(nat->nat_ndstaddr)); 33413b9b51feSCy Schubert } else { 33423b9b51feSCy Schubert sum1 = LONG_SUM(ntohl(nat->nat_osrcaddr)); 33433b9b51feSCy Schubert sum1 += LONG_SUM(ntohl(nat->nat_odstaddr)); 33443b9b51feSCy Schubert } 33453b9b51feSCy Schubert sum1 += nat->nat_pr[1]; 33463b9b51feSCy Schubert nat->nat_sumd[1] = (sum1 & 0xffff) + (sum1 >> 16); 33473b9b51feSCy Schubert 33483b9b51feSCy Schubert sum1 = LONG_SUM(ntohl(nat->nat_osrcaddr)); 33493b9b51feSCy Schubert sum2 = LONG_SUM(ntohl(nat->nat_nsrcaddr)); 33503b9b51feSCy Schubert CALC_SUMD(sum1, sum2, sumd); 33513b9b51feSCy Schubert nat->nat_ipsumd = (sumd & 0xffff) + (sumd >> 16); 33523b9b51feSCy Schubert 33533b9b51feSCy Schubert sum1 = LONG_SUM(ntohl(nat->nat_odstaddr)); 33543b9b51feSCy Schubert sum2 = LONG_SUM(ntohl(nat->nat_ndstaddr)); 33553b9b51feSCy Schubert CALC_SUMD(sum1, sum2, sumd); 33563b9b51feSCy Schubert nat->nat_ipsumd += (sumd & 0xffff) + (sumd >> 16); 33573b9b51feSCy Schubert 33583b9b51feSCy Schubert nat->nat_v[0] = 4; 33593b9b51feSCy Schubert nat->nat_v[1] = 4; 33603b9b51feSCy Schubert 33613b9b51feSCy Schubert if ((nat->nat_ifps[0] != NULL) && (nat->nat_ifps[0] != (void *)-1)) { 33623b9b51feSCy Schubert nat->nat_mtu[0] = GETIFMTU_4(nat->nat_ifps[0]); 33633b9b51feSCy Schubert } 33643b9b51feSCy Schubert 33653b9b51feSCy Schubert if ((nat->nat_ifps[1] != NULL) && (nat->nat_ifps[1] != (void *)-1)) { 33663b9b51feSCy Schubert nat->nat_mtu[1] = GETIFMTU_4(nat->nat_ifps[1]); 33673b9b51feSCy Schubert } 33683b9b51feSCy Schubert 33693b9b51feSCy Schubert if ((nat->nat_flags & SI_CLONE) == 0) 33703b9b51feSCy Schubert nat->nat_sync = ipf_sync_new(softc, SMC_NAT, fin, nat); 33713b9b51feSCy Schubert 33723b9b51feSCy Schubert if (ipf_nat_insert(softc, softn, nat) == 0) { 33733b9b51feSCy Schubert if (softn->ipf_nat_logging) 33743b9b51feSCy Schubert ipf_nat_log(softc, softn, nat, NL_NEW); 33753b9b51feSCy Schubert fr = nat->nat_fr; 33763b9b51feSCy Schubert if (fr != NULL) { 33773b9b51feSCy Schubert MUTEX_ENTER(&fr->fr_lock); 33783b9b51feSCy Schubert fr->fr_ref++; 33793b9b51feSCy Schubert MUTEX_EXIT(&fr->fr_lock); 33803b9b51feSCy Schubert } 33813b9b51feSCy Schubert return 0; 33823b9b51feSCy Schubert } 33833b9b51feSCy Schubert 33843b9b51feSCy Schubert NBUMPSIDED(fin->fin_out, ns_unfinalised); 33853b9b51feSCy Schubert DT2(ns_unfinalised, fr_info_t *, fin, nat_t *, nat); 33863b9b51feSCy Schubert /* 33873b9b51feSCy Schubert * nat_insert failed, so cleanup time... 33883b9b51feSCy Schubert */ 33893b9b51feSCy Schubert if (nat->nat_sync != NULL) 33903b9b51feSCy Schubert ipf_sync_del_nat(softc->ipf_sync_soft, nat->nat_sync); 33913b9b51feSCy Schubert return -1; 33923b9b51feSCy Schubert } 33933b9b51feSCy Schubert 33943b9b51feSCy Schubert 33953b9b51feSCy Schubert /* ------------------------------------------------------------------------ */ 33963b9b51feSCy Schubert /* Function: ipf_nat_insert */ 33973b9b51feSCy Schubert /* Returns: int - 0 == sucess, -1 == failure */ 33983b9b51feSCy Schubert /* Parameters: softc(I) - pointer to soft context main structure */ 33993b9b51feSCy Schubert /* softn(I) - pointer to NAT context structure */ 34003b9b51feSCy Schubert /* nat(I) - pointer to NAT structure */ 34013b9b51feSCy Schubert /* Write Lock: ipf_nat */ 34023b9b51feSCy Schubert /* */ 34033b9b51feSCy Schubert /* Insert a NAT entry into the hash tables for searching and add it to the */ 34043b9b51feSCy Schubert /* list of active NAT entries. Adjust global counters when complete. */ 34053b9b51feSCy Schubert /* ------------------------------------------------------------------------ */ 34063b9b51feSCy Schubert int 34073b9b51feSCy Schubert ipf_nat_insert(softc, softn, nat) 34083b9b51feSCy Schubert ipf_main_softc_t *softc; 34093b9b51feSCy Schubert ipf_nat_softc_t *softn; 34103b9b51feSCy Schubert nat_t *nat; 34113b9b51feSCy Schubert { 34123b9b51feSCy Schubert u_int hv0, hv1; 34133b9b51feSCy Schubert u_int sp, dp; 34143b9b51feSCy Schubert ipnat_t *in; 34153b9b51feSCy Schubert int ret; 34163b9b51feSCy Schubert 34173b9b51feSCy Schubert /* 34183b9b51feSCy Schubert * Try and return an error as early as possible, so calculate the hash 34193b9b51feSCy Schubert * entry numbers first and then proceed. 34203b9b51feSCy Schubert */ 34213b9b51feSCy Schubert if ((nat->nat_flags & (SI_W_SPORT|SI_W_DPORT)) == 0) { 34223b9b51feSCy Schubert if ((nat->nat_flags & IPN_TCPUDP) != 0) { 34233b9b51feSCy Schubert sp = nat->nat_osport; 34243b9b51feSCy Schubert dp = nat->nat_odport; 34253b9b51feSCy Schubert } else if ((nat->nat_flags & IPN_ICMPQUERY) != 0) { 34263b9b51feSCy Schubert sp = 0; 34273b9b51feSCy Schubert dp = nat->nat_oicmpid; 34283b9b51feSCy Schubert } else { 34293b9b51feSCy Schubert sp = 0; 34303b9b51feSCy Schubert dp = 0; 34313b9b51feSCy Schubert } 34323b9b51feSCy Schubert hv0 = NAT_HASH_FN(nat->nat_osrcaddr, sp, 0xffffffff); 34333b9b51feSCy Schubert hv0 = NAT_HASH_FN(nat->nat_odstaddr, hv0 + dp, 0xffffffff); 34343b9b51feSCy Schubert /* 34353b9b51feSCy Schubert * TRACE nat_osrcaddr, nat_osport, nat_odstaddr, 34363b9b51feSCy Schubert * nat_odport, hv0 34373b9b51feSCy Schubert */ 34383b9b51feSCy Schubert 34393b9b51feSCy Schubert if ((nat->nat_flags & IPN_TCPUDP) != 0) { 34403b9b51feSCy Schubert sp = nat->nat_nsport; 34413b9b51feSCy Schubert dp = nat->nat_ndport; 34423b9b51feSCy Schubert } else if ((nat->nat_flags & IPN_ICMPQUERY) != 0) { 34433b9b51feSCy Schubert sp = 0; 34443b9b51feSCy Schubert dp = nat->nat_nicmpid; 34453b9b51feSCy Schubert } else { 34463b9b51feSCy Schubert sp = 0; 34473b9b51feSCy Schubert dp = 0; 34483b9b51feSCy Schubert } 34493b9b51feSCy Schubert hv1 = NAT_HASH_FN(nat->nat_nsrcaddr, sp, 0xffffffff); 34503b9b51feSCy Schubert hv1 = NAT_HASH_FN(nat->nat_ndstaddr, hv1 + dp, 0xffffffff); 34513b9b51feSCy Schubert /* 34523b9b51feSCy Schubert * TRACE nat_nsrcaddr, nat_nsport, nat_ndstaddr, 34533b9b51feSCy Schubert * nat_ndport, hv1 34543b9b51feSCy Schubert */ 34553b9b51feSCy Schubert } else { 34563b9b51feSCy Schubert hv0 = NAT_HASH_FN(nat->nat_osrcaddr, 0, 0xffffffff); 34573b9b51feSCy Schubert hv0 = NAT_HASH_FN(nat->nat_odstaddr, hv0, 0xffffffff); 34583b9b51feSCy Schubert /* TRACE nat_osrcaddr, nat_odstaddr, hv0 */ 34593b9b51feSCy Schubert 34603b9b51feSCy Schubert hv1 = NAT_HASH_FN(nat->nat_nsrcaddr, 0, 0xffffffff); 34613b9b51feSCy Schubert hv1 = NAT_HASH_FN(nat->nat_ndstaddr, hv1, 0xffffffff); 34623b9b51feSCy Schubert /* TRACE nat_nsrcaddr, nat_ndstaddr, hv1 */ 34633b9b51feSCy Schubert } 34643b9b51feSCy Schubert 34653b9b51feSCy Schubert nat->nat_hv[0] = hv0; 34663b9b51feSCy Schubert nat->nat_hv[1] = hv1; 34673b9b51feSCy Schubert 34683b9b51feSCy Schubert MUTEX_INIT(&nat->nat_lock, "nat entry lock"); 34693b9b51feSCy Schubert 34703b9b51feSCy Schubert in = nat->nat_ptr; 34713b9b51feSCy Schubert nat->nat_ref = nat->nat_me ? 2 : 1; 34723b9b51feSCy Schubert 34733b9b51feSCy Schubert nat->nat_ifnames[0][LIFNAMSIZ - 1] = '\0'; 34743b9b51feSCy Schubert nat->nat_ifps[0] = ipf_resolvenic(softc, nat->nat_ifnames[0], 4); 34753b9b51feSCy Schubert 34763b9b51feSCy Schubert if (nat->nat_ifnames[1][0] != '\0') { 34773b9b51feSCy Schubert nat->nat_ifnames[1][LIFNAMSIZ - 1] = '\0'; 34783b9b51feSCy Schubert nat->nat_ifps[1] = ipf_resolvenic(softc, 34793b9b51feSCy Schubert nat->nat_ifnames[1], 4); 34803b9b51feSCy Schubert } else if (in->in_ifnames[1] != -1) { 34813b9b51feSCy Schubert char *name; 34823b9b51feSCy Schubert 34833b9b51feSCy Schubert name = in->in_names + in->in_ifnames[1]; 34843b9b51feSCy Schubert if (name[1] != '\0' && name[0] != '-' && name[0] != '*') { 34853b9b51feSCy Schubert (void) strncpy(nat->nat_ifnames[1], 34863b9b51feSCy Schubert nat->nat_ifnames[0], LIFNAMSIZ); 34873b9b51feSCy Schubert nat->nat_ifnames[1][LIFNAMSIZ - 1] = '\0'; 34883b9b51feSCy Schubert nat->nat_ifps[1] = nat->nat_ifps[0]; 34893b9b51feSCy Schubert } 34903b9b51feSCy Schubert } 34913b9b51feSCy Schubert if ((nat->nat_ifps[0] != NULL) && (nat->nat_ifps[0] != (void *)-1)) { 34923b9b51feSCy Schubert nat->nat_mtu[0] = GETIFMTU_4(nat->nat_ifps[0]); 34933b9b51feSCy Schubert } 34943b9b51feSCy Schubert if ((nat->nat_ifps[1] != NULL) && (nat->nat_ifps[1] != (void *)-1)) { 34953b9b51feSCy Schubert nat->nat_mtu[1] = GETIFMTU_4(nat->nat_ifps[1]); 34963b9b51feSCy Schubert } 34973b9b51feSCy Schubert 34983b9b51feSCy Schubert ret = ipf_nat_hashtab_add(softc, softn, nat); 34993b9b51feSCy Schubert if (ret == -1) 35003b9b51feSCy Schubert MUTEX_DESTROY(&nat->nat_lock); 35013b9b51feSCy Schubert return ret; 35023b9b51feSCy Schubert } 35033b9b51feSCy Schubert 35043b9b51feSCy Schubert 35053b9b51feSCy Schubert /* ------------------------------------------------------------------------ */ 35063b9b51feSCy Schubert /* Function: ipf_nat_hashtab_add */ 35073b9b51feSCy Schubert /* Returns: int - 0 == sucess, -1 == failure */ 35083b9b51feSCy Schubert /* Parameters: softc(I) - pointer to soft context main structure */ 35093b9b51feSCy Schubert /* softn(I) - pointer to NAT context structure */ 35103b9b51feSCy Schubert /* nat(I) - pointer to NAT structure */ 35113b9b51feSCy Schubert /* */ 35123b9b51feSCy Schubert /* Handle the insertion of a NAT entry into the table/list. */ 35133b9b51feSCy Schubert /* ------------------------------------------------------------------------ */ 35143b9b51feSCy Schubert int 35153b9b51feSCy Schubert ipf_nat_hashtab_add(softc, softn, nat) 35163b9b51feSCy Schubert ipf_main_softc_t *softc; 35173b9b51feSCy Schubert ipf_nat_softc_t *softn; 35183b9b51feSCy Schubert nat_t *nat; 35193b9b51feSCy Schubert { 35203b9b51feSCy Schubert nat_t **natp; 35213b9b51feSCy Schubert u_int hv0; 35223b9b51feSCy Schubert u_int hv1; 35233b9b51feSCy Schubert 35243b9b51feSCy Schubert if (nat->nat_dir == NAT_INBOUND || nat->nat_dir == NAT_DIVERTIN) { 35253b9b51feSCy Schubert hv1 = nat->nat_hv[0] % softn->ipf_nat_table_sz; 35263b9b51feSCy Schubert hv0 = nat->nat_hv[1] % softn->ipf_nat_table_sz; 35273b9b51feSCy Schubert } else { 35283b9b51feSCy Schubert hv0 = nat->nat_hv[0] % softn->ipf_nat_table_sz; 35293b9b51feSCy Schubert hv1 = nat->nat_hv[1] % softn->ipf_nat_table_sz; 35303b9b51feSCy Schubert } 35313b9b51feSCy Schubert 35323b9b51feSCy Schubert if (softn->ipf_nat_stats.ns_side[0].ns_bucketlen[hv0] >= 35333b9b51feSCy Schubert softn->ipf_nat_maxbucket) { 35343b9b51feSCy Schubert DT1(ns_bucket_max_0, int, 35353b9b51feSCy Schubert softn->ipf_nat_stats.ns_side[0].ns_bucketlen[hv0]); 35363b9b51feSCy Schubert NBUMPSIDE(0, ns_bucket_max); 35373b9b51feSCy Schubert return -1; 35383b9b51feSCy Schubert } 35393b9b51feSCy Schubert 35403b9b51feSCy Schubert if (softn->ipf_nat_stats.ns_side[1].ns_bucketlen[hv1] >= 35413b9b51feSCy Schubert softn->ipf_nat_maxbucket) { 35423b9b51feSCy Schubert DT1(ns_bucket_max_1, int, 35433b9b51feSCy Schubert softn->ipf_nat_stats.ns_side[1].ns_bucketlen[hv1]); 35443b9b51feSCy Schubert NBUMPSIDE(1, ns_bucket_max); 35453b9b51feSCy Schubert return -1; 35463b9b51feSCy Schubert } 35473b9b51feSCy Schubert 35483b9b51feSCy Schubert /* 35493b9b51feSCy Schubert * The ordering of operations in the list and hash table insertion 35503b9b51feSCy Schubert * is very important. The last operation for each task should be 35513b9b51feSCy Schubert * to update the top of the list, after all the "nexts" have been 35523b9b51feSCy Schubert * done so that walking the list while it is being done does not 35533b9b51feSCy Schubert * find strange pointers. 35543b9b51feSCy Schubert * 35553b9b51feSCy Schubert * Global list of NAT instances 35563b9b51feSCy Schubert */ 35573b9b51feSCy Schubert nat->nat_next = softn->ipf_nat_instances; 35583b9b51feSCy Schubert nat->nat_pnext = &softn->ipf_nat_instances; 35593b9b51feSCy Schubert if (softn->ipf_nat_instances) 35603b9b51feSCy Schubert softn->ipf_nat_instances->nat_pnext = &nat->nat_next; 35613b9b51feSCy Schubert softn->ipf_nat_instances = nat; 35623b9b51feSCy Schubert 35633b9b51feSCy Schubert /* 35643b9b51feSCy Schubert * Inbound hash table. 35653b9b51feSCy Schubert */ 35663b9b51feSCy Schubert natp = &softn->ipf_nat_table[0][hv0]; 35673b9b51feSCy Schubert nat->nat_phnext[0] = natp; 35683b9b51feSCy Schubert nat->nat_hnext[0] = *natp; 35693b9b51feSCy Schubert if (*natp) { 35703b9b51feSCy Schubert (*natp)->nat_phnext[0] = &nat->nat_hnext[0]; 35713b9b51feSCy Schubert } else { 35723b9b51feSCy Schubert NBUMPSIDE(0, ns_inuse); 35733b9b51feSCy Schubert } 35743b9b51feSCy Schubert *natp = nat; 35753b9b51feSCy Schubert NBUMPSIDE(0, ns_bucketlen[hv0]); 35763b9b51feSCy Schubert 35773b9b51feSCy Schubert /* 35783b9b51feSCy Schubert * Outbound hash table. 35793b9b51feSCy Schubert */ 35803b9b51feSCy Schubert natp = &softn->ipf_nat_table[1][hv1]; 35813b9b51feSCy Schubert nat->nat_phnext[1] = natp; 35823b9b51feSCy Schubert nat->nat_hnext[1] = *natp; 35833b9b51feSCy Schubert if (*natp) 35843b9b51feSCy Schubert (*natp)->nat_phnext[1] = &nat->nat_hnext[1]; 35853b9b51feSCy Schubert else { 35863b9b51feSCy Schubert NBUMPSIDE(1, ns_inuse); 35873b9b51feSCy Schubert } 35883b9b51feSCy Schubert *natp = nat; 35893b9b51feSCy Schubert NBUMPSIDE(1, ns_bucketlen[hv1]); 35903b9b51feSCy Schubert 35913b9b51feSCy Schubert ipf_nat_setqueue(softc, softn, nat); 35923b9b51feSCy Schubert 35933b9b51feSCy Schubert if (nat->nat_dir & NAT_OUTBOUND) { 35943b9b51feSCy Schubert NBUMPSIDE(1, ns_added); 35953b9b51feSCy Schubert } else { 35963b9b51feSCy Schubert NBUMPSIDE(0, ns_added); 35973b9b51feSCy Schubert } 35983b9b51feSCy Schubert softn->ipf_nat_stats.ns_active++; 35993b9b51feSCy Schubert return 0; 36003b9b51feSCy Schubert } 36013b9b51feSCy Schubert 36023b9b51feSCy Schubert 36033b9b51feSCy Schubert /* ------------------------------------------------------------------------ */ 36043b9b51feSCy Schubert /* Function: ipf_nat_icmperrorlookup */ 36053b9b51feSCy Schubert /* Returns: nat_t* - point to matching NAT structure */ 36063b9b51feSCy Schubert /* Parameters: fin(I) - pointer to packet information */ 36073b9b51feSCy Schubert /* dir(I) - direction of packet (in/out) */ 36083b9b51feSCy Schubert /* */ 36093b9b51feSCy Schubert /* Check if the ICMP error message is related to an existing TCP, UDP or */ 36103b9b51feSCy Schubert /* ICMP query nat entry. It is assumed that the packet is already of the */ 36113b9b51feSCy Schubert /* the required length. */ 36123b9b51feSCy Schubert /* ------------------------------------------------------------------------ */ 36133b9b51feSCy Schubert nat_t * 36143b9b51feSCy Schubert ipf_nat_icmperrorlookup(fin, dir) 36153b9b51feSCy Schubert fr_info_t *fin; 36163b9b51feSCy Schubert int dir; 36173b9b51feSCy Schubert { 36183b9b51feSCy Schubert ipf_main_softc_t *softc = fin->fin_main_soft; 36193b9b51feSCy Schubert ipf_nat_softc_t *softn = softc->ipf_nat_soft; 36203b9b51feSCy Schubert int flags = 0, type, minlen; 36213b9b51feSCy Schubert icmphdr_t *icmp, *orgicmp; 36223b9b51feSCy Schubert nat_stat_side_t *nside; 36233b9b51feSCy Schubert tcphdr_t *tcp = NULL; 36243b9b51feSCy Schubert u_short data[2]; 36253b9b51feSCy Schubert nat_t *nat; 36263b9b51feSCy Schubert ip_t *oip; 36273b9b51feSCy Schubert u_int p; 36283b9b51feSCy Schubert 36293b9b51feSCy Schubert icmp = fin->fin_dp; 36303b9b51feSCy Schubert type = icmp->icmp_type; 36313b9b51feSCy Schubert nside = &softn->ipf_nat_stats.ns_side[fin->fin_out]; 36323b9b51feSCy Schubert /* 36333b9b51feSCy Schubert * Does it at least have the return (basic) IP header ? 36343b9b51feSCy Schubert * Only a basic IP header (no options) should be with an ICMP error 36353b9b51feSCy Schubert * header. Also, if it's not an error type, then return. 36363b9b51feSCy Schubert */ 36373b9b51feSCy Schubert if ((fin->fin_hlen != sizeof(ip_t)) || !(fin->fin_flx & FI_ICMPERR)) { 36383b9b51feSCy Schubert ATOMIC_INCL(nside->ns_icmp_basic); 36393b9b51feSCy Schubert return NULL; 36403b9b51feSCy Schubert } 36413b9b51feSCy Schubert 36423b9b51feSCy Schubert /* 36433b9b51feSCy Schubert * Check packet size 36443b9b51feSCy Schubert */ 36453b9b51feSCy Schubert oip = (ip_t *)((char *)fin->fin_dp + 8); 36463b9b51feSCy Schubert minlen = IP_HL(oip) << 2; 36473b9b51feSCy Schubert if ((minlen < sizeof(ip_t)) || 36483b9b51feSCy Schubert (fin->fin_plen < ICMPERR_IPICMPHLEN + minlen)) { 36493b9b51feSCy Schubert ATOMIC_INCL(nside->ns_icmp_size); 36503b9b51feSCy Schubert return NULL; 36513b9b51feSCy Schubert } 36523b9b51feSCy Schubert 36533b9b51feSCy Schubert /* 36543b9b51feSCy Schubert * Is the buffer big enough for all of it ? It's the size of the IP 36553b9b51feSCy Schubert * header claimed in the encapsulated part which is of concern. It 36563b9b51feSCy Schubert * may be too big to be in this buffer but not so big that it's 36573b9b51feSCy Schubert * outside the ICMP packet, leading to TCP deref's causing problems. 36583b9b51feSCy Schubert * This is possible because we don't know how big oip_hl is when we 36593b9b51feSCy Schubert * do the pullup early in ipf_check() and thus can't gaurantee it is 36603b9b51feSCy Schubert * all here now. 36613b9b51feSCy Schubert */ 36623b9b51feSCy Schubert #ifdef ipf_nat_KERNEL 36633b9b51feSCy Schubert { 36643b9b51feSCy Schubert mb_t *m; 36653b9b51feSCy Schubert 36663b9b51feSCy Schubert m = fin->fin_m; 36673b9b51feSCy Schubert # if SOLARIS 36683b9b51feSCy Schubert if ((char *)oip + fin->fin_dlen - ICMPERR_ICMPHLEN > 36693b9b51feSCy Schubert (char *)m->b_wptr) { 36703b9b51feSCy Schubert ATOMIC_INCL(nside->ns_icmp_mbuf); 36713b9b51feSCy Schubert return NULL; 36723b9b51feSCy Schubert } 36733b9b51feSCy Schubert # else 36743b9b51feSCy Schubert if ((char *)oip + fin->fin_dlen - ICMPERR_ICMPHLEN > 36753b9b51feSCy Schubert (char *)fin->fin_ip + M_LEN(m)) { 36763b9b51feSCy Schubert ATOMIC_INCL(nside->ns_icmp_mbuf); 36773b9b51feSCy Schubert return NULL; 36783b9b51feSCy Schubert } 36793b9b51feSCy Schubert # endif 36803b9b51feSCy Schubert } 36813b9b51feSCy Schubert #endif 36823b9b51feSCy Schubert 36833b9b51feSCy Schubert if (fin->fin_daddr != oip->ip_src.s_addr) { 36843b9b51feSCy Schubert ATOMIC_INCL(nside->ns_icmp_address); 36853b9b51feSCy Schubert return NULL; 36863b9b51feSCy Schubert } 36873b9b51feSCy Schubert 36883b9b51feSCy Schubert p = oip->ip_p; 36893b9b51feSCy Schubert if (p == IPPROTO_TCP) 36903b9b51feSCy Schubert flags = IPN_TCP; 36913b9b51feSCy Schubert else if (p == IPPROTO_UDP) 36923b9b51feSCy Schubert flags = IPN_UDP; 36933b9b51feSCy Schubert else if (p == IPPROTO_ICMP) { 36943b9b51feSCy Schubert orgicmp = (icmphdr_t *)((char *)oip + (IP_HL(oip) << 2)); 36953b9b51feSCy Schubert 36963b9b51feSCy Schubert /* see if this is related to an ICMP query */ 36973b9b51feSCy Schubert if (ipf_nat_icmpquerytype(orgicmp->icmp_type)) { 36983b9b51feSCy Schubert data[0] = fin->fin_data[0]; 36993b9b51feSCy Schubert data[1] = fin->fin_data[1]; 37003b9b51feSCy Schubert fin->fin_data[0] = 0; 37013b9b51feSCy Schubert fin->fin_data[1] = orgicmp->icmp_id; 37023b9b51feSCy Schubert 37033b9b51feSCy Schubert flags = IPN_ICMPERR|IPN_ICMPQUERY; 37043b9b51feSCy Schubert /* 37053b9b51feSCy Schubert * NOTE : dir refers to the direction of the original 37063b9b51feSCy Schubert * ip packet. By definition the icmp error 37073b9b51feSCy Schubert * message flows in the opposite direction. 37083b9b51feSCy Schubert */ 37093b9b51feSCy Schubert if (dir == NAT_INBOUND) 37103b9b51feSCy Schubert nat = ipf_nat_inlookup(fin, flags, p, 37113b9b51feSCy Schubert oip->ip_dst, 37123b9b51feSCy Schubert oip->ip_src); 37133b9b51feSCy Schubert else 37143b9b51feSCy Schubert nat = ipf_nat_outlookup(fin, flags, p, 37153b9b51feSCy Schubert oip->ip_dst, 37163b9b51feSCy Schubert oip->ip_src); 37173b9b51feSCy Schubert fin->fin_data[0] = data[0]; 37183b9b51feSCy Schubert fin->fin_data[1] = data[1]; 37193b9b51feSCy Schubert return nat; 37203b9b51feSCy Schubert } 37213b9b51feSCy Schubert } 37223b9b51feSCy Schubert 37233b9b51feSCy Schubert if (flags & IPN_TCPUDP) { 37243b9b51feSCy Schubert minlen += 8; /* + 64bits of data to get ports */ 37253b9b51feSCy Schubert /* TRACE (fin,minlen) */ 37263b9b51feSCy Schubert if (fin->fin_plen < ICMPERR_IPICMPHLEN + minlen) { 37273b9b51feSCy Schubert ATOMIC_INCL(nside->ns_icmp_short); 37283b9b51feSCy Schubert return NULL; 37293b9b51feSCy Schubert } 37303b9b51feSCy Schubert 37313b9b51feSCy Schubert data[0] = fin->fin_data[0]; 37323b9b51feSCy Schubert data[1] = fin->fin_data[1]; 37333b9b51feSCy Schubert tcp = (tcphdr_t *)((char *)oip + (IP_HL(oip) << 2)); 37343b9b51feSCy Schubert fin->fin_data[0] = ntohs(tcp->th_dport); 37353b9b51feSCy Schubert fin->fin_data[1] = ntohs(tcp->th_sport); 37363b9b51feSCy Schubert 37373b9b51feSCy Schubert if (dir == NAT_INBOUND) { 37383b9b51feSCy Schubert nat = ipf_nat_inlookup(fin, flags, p, oip->ip_dst, 37393b9b51feSCy Schubert oip->ip_src); 37403b9b51feSCy Schubert } else { 37413b9b51feSCy Schubert nat = ipf_nat_outlookup(fin, flags, p, oip->ip_dst, 37423b9b51feSCy Schubert oip->ip_src); 37433b9b51feSCy Schubert } 37443b9b51feSCy Schubert fin->fin_data[0] = data[0]; 37453b9b51feSCy Schubert fin->fin_data[1] = data[1]; 37463b9b51feSCy Schubert return nat; 37473b9b51feSCy Schubert } 37483b9b51feSCy Schubert if (dir == NAT_INBOUND) 37493b9b51feSCy Schubert nat = ipf_nat_inlookup(fin, 0, p, oip->ip_dst, oip->ip_src); 37503b9b51feSCy Schubert else 37513b9b51feSCy Schubert nat = ipf_nat_outlookup(fin, 0, p, oip->ip_dst, oip->ip_src); 37523b9b51feSCy Schubert 37533b9b51feSCy Schubert return nat; 37543b9b51feSCy Schubert } 37553b9b51feSCy Schubert 37563b9b51feSCy Schubert 37573b9b51feSCy Schubert /* ------------------------------------------------------------------------ */ 37583b9b51feSCy Schubert /* Function: ipf_nat_icmperror */ 37593b9b51feSCy Schubert /* Returns: nat_t* - point to matching NAT structure */ 37603b9b51feSCy Schubert /* Parameters: fin(I) - pointer to packet information */ 37613b9b51feSCy Schubert /* nflags(I) - NAT flags for this packet */ 37623b9b51feSCy Schubert /* dir(I) - direction of packet (in/out) */ 37633b9b51feSCy Schubert /* */ 37643b9b51feSCy Schubert /* Fix up an ICMP packet which is an error message for an existing NAT */ 37653b9b51feSCy Schubert /* session. This will correct both packet header data and checksums. */ 37663b9b51feSCy Schubert /* */ 37673b9b51feSCy Schubert /* This should *ONLY* be used for incoming ICMP error packets to make sure */ 37683b9b51feSCy Schubert /* a NAT'd ICMP packet gets correctly recognised. */ 37693b9b51feSCy Schubert /* ------------------------------------------------------------------------ */ 37703b9b51feSCy Schubert nat_t * 37713b9b51feSCy Schubert ipf_nat_icmperror(fin, nflags, dir) 37723b9b51feSCy Schubert fr_info_t *fin; 37733b9b51feSCy Schubert u_int *nflags; 37743b9b51feSCy Schubert int dir; 37753b9b51feSCy Schubert { 37763b9b51feSCy Schubert ipf_main_softc_t *softc = fin->fin_main_soft; 37773b9b51feSCy Schubert ipf_nat_softc_t *softn = softc->ipf_nat_soft; 37783b9b51feSCy Schubert u_32_t sum1, sum2, sumd, sumd2; 37793b9b51feSCy Schubert struct in_addr a1, a2, a3, a4; 37803b9b51feSCy Schubert int flags, dlen, odst; 37813b9b51feSCy Schubert icmphdr_t *icmp; 37823b9b51feSCy Schubert u_short *csump; 37833b9b51feSCy Schubert tcphdr_t *tcp; 37843b9b51feSCy Schubert nat_t *nat; 37853b9b51feSCy Schubert ip_t *oip; 37863b9b51feSCy Schubert void *dp; 37873b9b51feSCy Schubert 37883b9b51feSCy Schubert if ((fin->fin_flx & (FI_SHORT|FI_FRAGBODY))) { 37893b9b51feSCy Schubert NBUMPSIDED(fin->fin_out, ns_icmp_short); 37903b9b51feSCy Schubert return NULL; 37913b9b51feSCy Schubert } 37923b9b51feSCy Schubert 37933b9b51feSCy Schubert /* 37943b9b51feSCy Schubert * ipf_nat_icmperrorlookup() will return NULL for `defective' packets. 37953b9b51feSCy Schubert */ 37963b9b51feSCy Schubert if ((fin->fin_v != 4) || !(nat = ipf_nat_icmperrorlookup(fin, dir))) { 37973b9b51feSCy Schubert NBUMPSIDED(fin->fin_out, ns_icmp_notfound); 37983b9b51feSCy Schubert return NULL; 37993b9b51feSCy Schubert } 38003b9b51feSCy Schubert 38013b9b51feSCy Schubert tcp = NULL; 38023b9b51feSCy Schubert csump = NULL; 38033b9b51feSCy Schubert flags = 0; 38043b9b51feSCy Schubert sumd2 = 0; 38053b9b51feSCy Schubert *nflags = IPN_ICMPERR; 38063b9b51feSCy Schubert icmp = fin->fin_dp; 38073b9b51feSCy Schubert oip = (ip_t *)&icmp->icmp_ip; 38083b9b51feSCy Schubert dp = (((char *)oip) + (IP_HL(oip) << 2)); 38093b9b51feSCy Schubert if (oip->ip_p == IPPROTO_TCP) { 38103b9b51feSCy Schubert tcp = (tcphdr_t *)dp; 38113b9b51feSCy Schubert csump = (u_short *)&tcp->th_sum; 38123b9b51feSCy Schubert flags = IPN_TCP; 38133b9b51feSCy Schubert } else if (oip->ip_p == IPPROTO_UDP) { 38143b9b51feSCy Schubert udphdr_t *udp; 38153b9b51feSCy Schubert 38163b9b51feSCy Schubert udp = (udphdr_t *)dp; 38173b9b51feSCy Schubert tcp = (tcphdr_t *)dp; 38183b9b51feSCy Schubert csump = (u_short *)&udp->uh_sum; 38193b9b51feSCy Schubert flags = IPN_UDP; 38203b9b51feSCy Schubert } else if (oip->ip_p == IPPROTO_ICMP) 38213b9b51feSCy Schubert flags = IPN_ICMPQUERY; 38223b9b51feSCy Schubert dlen = fin->fin_plen - ((char *)dp - (char *)fin->fin_ip); 38233b9b51feSCy Schubert 38243b9b51feSCy Schubert /* 38253b9b51feSCy Schubert * Need to adjust ICMP header to include the real IP#'s and 38263b9b51feSCy Schubert * port #'s. Only apply a checksum change relative to the 38273b9b51feSCy Schubert * IP address change as it will be modified again in ipf_nat_checkout 38283b9b51feSCy Schubert * for both address and port. Two checksum changes are 38293b9b51feSCy Schubert * necessary for the two header address changes. Be careful 38303b9b51feSCy Schubert * to only modify the checksum once for the port # and twice 38313b9b51feSCy Schubert * for the IP#. 38323b9b51feSCy Schubert */ 38333b9b51feSCy Schubert 38343b9b51feSCy Schubert /* 38353b9b51feSCy Schubert * Step 1 38363b9b51feSCy Schubert * Fix the IP addresses in the offending IP packet. You also need 38373b9b51feSCy Schubert * to adjust the IP header checksum of that offending IP packet. 38383b9b51feSCy Schubert * 38393b9b51feSCy Schubert * Normally, you would expect that the ICMP checksum of the 38403b9b51feSCy Schubert * ICMP error message needs to be adjusted as well for the 38413b9b51feSCy Schubert * IP address change in oip. 38423b9b51feSCy Schubert * However, this is a NOP, because the ICMP checksum is 38433b9b51feSCy Schubert * calculated over the complete ICMP packet, which includes the 38443b9b51feSCy Schubert * changed oip IP addresses and oip->ip_sum. However, these 38453b9b51feSCy Schubert * two changes cancel each other out (if the delta for 38463b9b51feSCy Schubert * the IP address is x, then the delta for ip_sum is minus x), 38473b9b51feSCy Schubert * so no change in the icmp_cksum is necessary. 38483b9b51feSCy Schubert * 38493b9b51feSCy Schubert * Inbound ICMP 38503b9b51feSCy Schubert * ------------ 38513b9b51feSCy Schubert * MAP rule, SRC=a,DST=b -> SRC=c,DST=b 38523b9b51feSCy Schubert * - response to outgoing packet (a,b)=>(c,b) (OIP_SRC=c,OIP_DST=b) 38533b9b51feSCy Schubert * - OIP_SRC(c)=nat_newsrcip, OIP_DST(b)=nat_newdstip 38543b9b51feSCy Schubert *=> OIP_SRC(c)=nat_oldsrcip, OIP_DST(b)=nat_olddstip 38553b9b51feSCy Schubert * 38563b9b51feSCy Schubert * RDR rule, SRC=a,DST=b -> SRC=a,DST=c 38573b9b51feSCy Schubert * - response to outgoing packet (c,a)=>(b,a) (OIP_SRC=b,OIP_DST=a) 38583b9b51feSCy Schubert * - OIP_SRC(b)=nat_olddstip, OIP_DST(a)=nat_oldsrcip 38593b9b51feSCy Schubert *=> OIP_SRC(b)=nat_newdstip, OIP_DST(a)=nat_newsrcip 38603b9b51feSCy Schubert * 38613b9b51feSCy Schubert * REWRITE out rule, SRC=a,DST=b -> SRC=c,DST=d 38623b9b51feSCy Schubert * - response to outgoing packet (a,b)=>(c,d) (OIP_SRC=c,OIP_DST=d) 38633b9b51feSCy Schubert * - OIP_SRC(c)=nat_newsrcip, OIP_DST(d)=nat_newdstip 38643b9b51feSCy Schubert *=> OIP_SRC(c)=nat_oldsrcip, OIP_DST(d)=nat_olddstip 38653b9b51feSCy Schubert * 38663b9b51feSCy Schubert * REWRITE in rule, SRC=a,DST=b -> SRC=c,DST=d 38673b9b51feSCy Schubert * - response to outgoing packet (d,c)=>(b,a) (OIP_SRC=b,OIP_DST=a) 38683b9b51feSCy Schubert * - OIP_SRC(b)=nat_olddstip, OIP_DST(a)=nat_oldsrcip 38693b9b51feSCy Schubert *=> OIP_SRC(b)=nat_newdstip, OIP_DST(a)=nat_newsrcip 38703b9b51feSCy Schubert * 38713b9b51feSCy Schubert * Outbound ICMP 38723b9b51feSCy Schubert * ------------- 38733b9b51feSCy Schubert * MAP rule, SRC=a,DST=b -> SRC=c,DST=b 38743b9b51feSCy Schubert * - response to incoming packet (b,c)=>(b,a) (OIP_SRC=b,OIP_DST=a) 38753b9b51feSCy Schubert * - OIP_SRC(b)=nat_olddstip, OIP_DST(a)=nat_oldsrcip 38763b9b51feSCy Schubert *=> OIP_SRC(b)=nat_newdstip, OIP_DST(a)=nat_newsrcip 38773b9b51feSCy Schubert * 38783b9b51feSCy Schubert * RDR rule, SRC=a,DST=b -> SRC=a,DST=c 38793b9b51feSCy Schubert * - response to incoming packet (a,b)=>(a,c) (OIP_SRC=a,OIP_DST=c) 38803b9b51feSCy Schubert * - OIP_SRC(a)=nat_newsrcip, OIP_DST(c)=nat_newdstip 38813b9b51feSCy Schubert *=> OIP_SRC(a)=nat_oldsrcip, OIP_DST(c)=nat_olddstip 38823b9b51feSCy Schubert * 38833b9b51feSCy Schubert * REWRITE out rule, SRC=a,DST=b -> SRC=c,DST=d 38843b9b51feSCy Schubert * - response to incoming packet (d,c)=>(b,a) (OIP_SRC=c,OIP_DST=d) 38853b9b51feSCy Schubert * - OIP_SRC(c)=nat_olddstip, OIP_DST(d)=nat_oldsrcip 38863b9b51feSCy Schubert *=> OIP_SRC(b)=nat_newdstip, OIP_DST(a)=nat_newsrcip 38873b9b51feSCy Schubert * 38883b9b51feSCy Schubert * REWRITE in rule, SRC=a,DST=b -> SRC=c,DST=d 38893b9b51feSCy Schubert * - response to incoming packet (a,b)=>(c,d) (OIP_SRC=b,OIP_DST=a) 38903b9b51feSCy Schubert * - OIP_SRC(b)=nat_newsrcip, OIP_DST(a)=nat_newdstip 38913b9b51feSCy Schubert *=> OIP_SRC(a)=nat_oldsrcip, OIP_DST(c)=nat_olddstip 38923b9b51feSCy Schubert */ 38933b9b51feSCy Schubert 38943b9b51feSCy Schubert if (((fin->fin_out == 0) && ((nat->nat_redir & NAT_MAP) != 0)) || 38953b9b51feSCy Schubert ((fin->fin_out == 1) && ((nat->nat_redir & NAT_REDIRECT) != 0))) { 38963b9b51feSCy Schubert a1.s_addr = ntohl(nat->nat_osrcaddr); 38973b9b51feSCy Schubert a4.s_addr = ntohl(oip->ip_src.s_addr); 38983b9b51feSCy Schubert a3.s_addr = ntohl(nat->nat_odstaddr); 38993b9b51feSCy Schubert a2.s_addr = ntohl(oip->ip_dst.s_addr); 39003b9b51feSCy Schubert oip->ip_src.s_addr = htonl(a1.s_addr); 39013b9b51feSCy Schubert oip->ip_dst.s_addr = htonl(a3.s_addr); 39023b9b51feSCy Schubert odst = 1; 39033b9b51feSCy Schubert } else { 39043b9b51feSCy Schubert a1.s_addr = ntohl(nat->nat_ndstaddr); 39053b9b51feSCy Schubert a2.s_addr = ntohl(oip->ip_dst.s_addr); 39063b9b51feSCy Schubert a3.s_addr = ntohl(nat->nat_nsrcaddr); 39073b9b51feSCy Schubert a4.s_addr = ntohl(oip->ip_src.s_addr); 39083b9b51feSCy Schubert oip->ip_dst.s_addr = htonl(a3.s_addr); 39093b9b51feSCy Schubert oip->ip_src.s_addr = htonl(a1.s_addr); 39103b9b51feSCy Schubert odst = 0; 39113b9b51feSCy Schubert } 39123b9b51feSCy Schubert sum1 = 0; 39133b9b51feSCy Schubert sum2 = 0; 39143b9b51feSCy Schubert sumd = 0; 39153b9b51feSCy Schubert CALC_SUMD(a2.s_addr, a3.s_addr, sum1); 39163b9b51feSCy Schubert CALC_SUMD(a4.s_addr, a1.s_addr, sum2); 39173b9b51feSCy Schubert sumd = sum2 + sum1; 39183b9b51feSCy Schubert if (sumd != 0) 39193b9b51feSCy Schubert ipf_fix_datacksum(&oip->ip_sum, sumd); 39203b9b51feSCy Schubert 39213b9b51feSCy Schubert sumd2 = sumd; 39223b9b51feSCy Schubert sum1 = 0; 39233b9b51feSCy Schubert sum2 = 0; 39243b9b51feSCy Schubert 39253b9b51feSCy Schubert /* 39263b9b51feSCy Schubert * Fix UDP pseudo header checksum to compensate for the 39273b9b51feSCy Schubert * IP address change. 39283b9b51feSCy Schubert */ 39293b9b51feSCy Schubert if (((flags & IPN_TCPUDP) != 0) && (dlen >= 4)) { 39303b9b51feSCy Schubert u_32_t sum3, sum4, sumt; 39313b9b51feSCy Schubert 39323b9b51feSCy Schubert /* 39333b9b51feSCy Schubert * Step 2 : 39343b9b51feSCy Schubert * For offending TCP/UDP IP packets, translate the ports as 39353b9b51feSCy Schubert * well, based on the NAT specification. Of course such 39363b9b51feSCy Schubert * a change may be reflected in the ICMP checksum as well. 39373b9b51feSCy Schubert * 39383b9b51feSCy Schubert * Since the port fields are part of the TCP/UDP checksum 39393b9b51feSCy Schubert * of the offending IP packet, you need to adjust that checksum 39403b9b51feSCy Schubert * as well... except that the change in the port numbers should 39413b9b51feSCy Schubert * be offset by the checksum change. However, the TCP/UDP 39423b9b51feSCy Schubert * checksum will also need to change if there has been an 39433b9b51feSCy Schubert * IP address change. 39443b9b51feSCy Schubert */ 39453b9b51feSCy Schubert if (odst == 1) { 39463b9b51feSCy Schubert sum1 = ntohs(nat->nat_osport); 39473b9b51feSCy Schubert sum4 = ntohs(tcp->th_sport); 39483b9b51feSCy Schubert sum3 = ntohs(nat->nat_odport); 39493b9b51feSCy Schubert sum2 = ntohs(tcp->th_dport); 39503b9b51feSCy Schubert 39513b9b51feSCy Schubert tcp->th_sport = htons(sum1); 39523b9b51feSCy Schubert tcp->th_dport = htons(sum3); 39533b9b51feSCy Schubert } else { 39543b9b51feSCy Schubert sum1 = ntohs(nat->nat_ndport); 39553b9b51feSCy Schubert sum2 = ntohs(tcp->th_dport); 39563b9b51feSCy Schubert sum3 = ntohs(nat->nat_nsport); 39573b9b51feSCy Schubert sum4 = ntohs(tcp->th_sport); 39583b9b51feSCy Schubert 39593b9b51feSCy Schubert tcp->th_dport = htons(sum3); 39603b9b51feSCy Schubert tcp->th_sport = htons(sum1); 39613b9b51feSCy Schubert } 39623b9b51feSCy Schubert CALC_SUMD(sum4, sum1, sumt); 39633b9b51feSCy Schubert sumd += sumt; 39643b9b51feSCy Schubert CALC_SUMD(sum2, sum3, sumt); 39653b9b51feSCy Schubert sumd += sumt; 39663b9b51feSCy Schubert 39673b9b51feSCy Schubert if (sumd != 0 || sumd2 != 0) { 39683b9b51feSCy Schubert /* 39693b9b51feSCy Schubert * At this point, sumd is the delta to apply to the 39703b9b51feSCy Schubert * TCP/UDP header, given the changes in both the IP 39713b9b51feSCy Schubert * address and the ports and sumd2 is the delta to 39723b9b51feSCy Schubert * apply to the ICMP header, given the IP address 39733b9b51feSCy Schubert * change delta that may need to be applied to the 39743b9b51feSCy Schubert * TCP/UDP checksum instead. 39753b9b51feSCy Schubert * 39763b9b51feSCy Schubert * If we will both the IP and TCP/UDP checksums 39773b9b51feSCy Schubert * then the ICMP checksum changes by the address 39783b9b51feSCy Schubert * delta applied to the TCP/UDP checksum. If we 39793b9b51feSCy Schubert * do not change the TCP/UDP checksum them we 39803b9b51feSCy Schubert * apply the delta in ports to the ICMP checksum. 39813b9b51feSCy Schubert */ 39823b9b51feSCy Schubert if (oip->ip_p == IPPROTO_UDP) { 39833b9b51feSCy Schubert if ((dlen >= 8) && (*csump != 0)) { 39843b9b51feSCy Schubert ipf_fix_datacksum(csump, sumd); 39853b9b51feSCy Schubert } else { 39863b9b51feSCy Schubert CALC_SUMD(sum1, sum4, sumd2); 39873b9b51feSCy Schubert CALC_SUMD(sum3, sum2, sumt); 39883b9b51feSCy Schubert sumd2 += sumt; 39893b9b51feSCy Schubert } 39903b9b51feSCy Schubert } else if (oip->ip_p == IPPROTO_TCP) { 39913b9b51feSCy Schubert if (dlen >= 18) { 39923b9b51feSCy Schubert ipf_fix_datacksum(csump, sumd); 39933b9b51feSCy Schubert } else { 39943b9b51feSCy Schubert CALC_SUMD(sum1, sum4, sumd2); 39953b9b51feSCy Schubert CALC_SUMD(sum3, sum2, sumt); 39963b9b51feSCy Schubert sumd2 += sumt; 39973b9b51feSCy Schubert } 39983b9b51feSCy Schubert } 39993b9b51feSCy Schubert if (sumd2 != 0) { 40003b9b51feSCy Schubert sumd2 = (sumd2 & 0xffff) + (sumd2 >> 16); 40013b9b51feSCy Schubert sumd2 = (sumd2 & 0xffff) + (sumd2 >> 16); 40023b9b51feSCy Schubert sumd2 = (sumd2 & 0xffff) + (sumd2 >> 16); 40033b9b51feSCy Schubert ipf_fix_incksum(0, &icmp->icmp_cksum, sumd2, 0); 40043b9b51feSCy Schubert } 40053b9b51feSCy Schubert } 40063b9b51feSCy Schubert } else if (((flags & IPN_ICMPQUERY) != 0) && (dlen >= 8)) { 40073b9b51feSCy Schubert icmphdr_t *orgicmp; 40083b9b51feSCy Schubert 40093b9b51feSCy Schubert /* 40103b9b51feSCy Schubert * XXX - what if this is bogus hl and we go off the end ? 40113b9b51feSCy Schubert * In this case, ipf_nat_icmperrorlookup() will have 40123b9b51feSCy Schubert * returned NULL. 40133b9b51feSCy Schubert */ 40143b9b51feSCy Schubert orgicmp = (icmphdr_t *)dp; 40153b9b51feSCy Schubert 40163b9b51feSCy Schubert if (odst == 1) { 40173b9b51feSCy Schubert if (orgicmp->icmp_id != nat->nat_osport) { 40183b9b51feSCy Schubert 40193b9b51feSCy Schubert /* 40203b9b51feSCy Schubert * Fix ICMP checksum (of the offening ICMP 40213b9b51feSCy Schubert * query packet) to compensate the change 40223b9b51feSCy Schubert * in the ICMP id of the offending ICMP 40233b9b51feSCy Schubert * packet. 40243b9b51feSCy Schubert * 40253b9b51feSCy Schubert * Since you modify orgicmp->icmp_id with 40263b9b51feSCy Schubert * a delta (say x) and you compensate that 40273b9b51feSCy Schubert * in origicmp->icmp_cksum with a delta 40283b9b51feSCy Schubert * minus x, you don't have to adjust the 40293b9b51feSCy Schubert * overall icmp->icmp_cksum 40303b9b51feSCy Schubert */ 40313b9b51feSCy Schubert sum1 = ntohs(orgicmp->icmp_id); 40323b9b51feSCy Schubert sum2 = ntohs(nat->nat_oicmpid); 40333b9b51feSCy Schubert CALC_SUMD(sum1, sum2, sumd); 40343b9b51feSCy Schubert orgicmp->icmp_id = nat->nat_oicmpid; 40353b9b51feSCy Schubert ipf_fix_datacksum(&orgicmp->icmp_cksum, sumd); 40363b9b51feSCy Schubert } 40373b9b51feSCy Schubert } /* nat_dir == NAT_INBOUND is impossible for icmp queries */ 40383b9b51feSCy Schubert } 40393b9b51feSCy Schubert return nat; 40403b9b51feSCy Schubert } 40413b9b51feSCy Schubert 40423b9b51feSCy Schubert 40433b9b51feSCy Schubert /* 40443b9b51feSCy Schubert * MAP-IN MAP-OUT RDR-IN RDR-OUT 40453b9b51feSCy Schubert * osrc X == src == src X 40463b9b51feSCy Schubert * odst X == dst == dst X 40473b9b51feSCy Schubert * nsrc == dst X X == dst 40483b9b51feSCy Schubert * ndst == src X X == src 40493b9b51feSCy Schubert * MAP = NAT_OUTBOUND, RDR = NAT_INBOUND 40503b9b51feSCy Schubert */ 40513b9b51feSCy Schubert /* 40523b9b51feSCy Schubert * NB: these lookups don't lock access to the list, it assumed that it has 40533b9b51feSCy Schubert * already been done! 40543b9b51feSCy Schubert */ 40553b9b51feSCy Schubert /* ------------------------------------------------------------------------ */ 40563b9b51feSCy Schubert /* Function: ipf_nat_inlookup */ 40573b9b51feSCy Schubert /* Returns: nat_t* - NULL == no match, */ 40583b9b51feSCy Schubert /* else pointer to matching NAT entry */ 40593b9b51feSCy Schubert /* Parameters: fin(I) - pointer to packet information */ 40603b9b51feSCy Schubert /* flags(I) - NAT flags for this packet */ 40613b9b51feSCy Schubert /* p(I) - protocol for this packet */ 40623b9b51feSCy Schubert /* src(I) - source IP address */ 40633b9b51feSCy Schubert /* mapdst(I) - destination IP address */ 40643b9b51feSCy Schubert /* */ 40653b9b51feSCy Schubert /* Lookup a nat entry based on the mapped destination ip address/port and */ 40663b9b51feSCy Schubert /* real source address/port. We use this lookup when receiving a packet, */ 40673b9b51feSCy Schubert /* we're looking for a table entry, based on the destination address. */ 40683b9b51feSCy Schubert /* */ 40693b9b51feSCy Schubert /* NOTE: THE PACKET BEING CHECKED (IF FOUND) HAS A MAPPING ALREADY. */ 40703b9b51feSCy Schubert /* */ 40713b9b51feSCy Schubert /* NOTE: IT IS ASSUMED THAT IS ONLY HELD WITH A READ LOCK WHEN */ 40723b9b51feSCy Schubert /* THIS FUNCTION IS CALLED WITH NAT_SEARCH SET IN nflags. */ 40733b9b51feSCy Schubert /* */ 40743b9b51feSCy Schubert /* flags -> relevant are IPN_UDP/IPN_TCP/IPN_ICMPQUERY that indicate if */ 40753b9b51feSCy Schubert /* the packet is of said protocol */ 40763b9b51feSCy Schubert /* ------------------------------------------------------------------------ */ 40773b9b51feSCy Schubert nat_t * 40783b9b51feSCy Schubert ipf_nat_inlookup(fin, flags, p, src, mapdst) 40793b9b51feSCy Schubert fr_info_t *fin; 40803b9b51feSCy Schubert u_int flags, p; 40813b9b51feSCy Schubert struct in_addr src , mapdst; 40823b9b51feSCy Schubert { 40833b9b51feSCy Schubert ipf_main_softc_t *softc = fin->fin_main_soft; 40843b9b51feSCy Schubert ipf_nat_softc_t *softn = softc->ipf_nat_soft; 40853b9b51feSCy Schubert u_short sport, dport; 40863b9b51feSCy Schubert grehdr_t *gre; 40873b9b51feSCy Schubert ipnat_t *ipn; 40883b9b51feSCy Schubert u_int sflags; 40893b9b51feSCy Schubert nat_t *nat; 40903b9b51feSCy Schubert int nflags; 40913b9b51feSCy Schubert u_32_t dst; 40923b9b51feSCy Schubert void *ifp; 40933b9b51feSCy Schubert u_int hv, rhv; 40943b9b51feSCy Schubert 40953b9b51feSCy Schubert ifp = fin->fin_ifp; 40963b9b51feSCy Schubert gre = NULL; 40973b9b51feSCy Schubert dst = mapdst.s_addr; 40983b9b51feSCy Schubert sflags = flags & NAT_TCPUDPICMP; 40993b9b51feSCy Schubert 41003b9b51feSCy Schubert switch (p) 41013b9b51feSCy Schubert { 41023b9b51feSCy Schubert case IPPROTO_TCP : 41033b9b51feSCy Schubert case IPPROTO_UDP : 41043b9b51feSCy Schubert sport = htons(fin->fin_data[0]); 41053b9b51feSCy Schubert dport = htons(fin->fin_data[1]); 41063b9b51feSCy Schubert break; 41073b9b51feSCy Schubert case IPPROTO_ICMP : 41083b9b51feSCy Schubert sport = 0; 41093b9b51feSCy Schubert dport = fin->fin_data[1]; 41103b9b51feSCy Schubert break; 41113b9b51feSCy Schubert default : 41123b9b51feSCy Schubert sport = 0; 41133b9b51feSCy Schubert dport = 0; 41143b9b51feSCy Schubert break; 41153b9b51feSCy Schubert } 41163b9b51feSCy Schubert 41173b9b51feSCy Schubert 41183b9b51feSCy Schubert if ((flags & SI_WILDP) != 0) 41193b9b51feSCy Schubert goto find_in_wild_ports; 41203b9b51feSCy Schubert 41213b9b51feSCy Schubert rhv = NAT_HASH_FN(dst, dport, 0xffffffff); 41223b9b51feSCy Schubert rhv = NAT_HASH_FN(src.s_addr, rhv + sport, 0xffffffff); 41233b9b51feSCy Schubert hv = rhv % softn->ipf_nat_table_sz; 41243b9b51feSCy Schubert nat = softn->ipf_nat_table[1][hv]; 41253b9b51feSCy Schubert /* TRACE dst, dport, src, sport, hv, nat */ 41263b9b51feSCy Schubert 41273b9b51feSCy Schubert for (; nat; nat = nat->nat_hnext[1]) { 41283b9b51feSCy Schubert if (nat->nat_ifps[0] != NULL) { 41293b9b51feSCy Schubert if ((ifp != NULL) && (ifp != nat->nat_ifps[0])) 41303b9b51feSCy Schubert continue; 41313b9b51feSCy Schubert } 41323b9b51feSCy Schubert 41333b9b51feSCy Schubert if (nat->nat_pr[0] != p) 41343b9b51feSCy Schubert continue; 41353b9b51feSCy Schubert 41363b9b51feSCy Schubert switch (nat->nat_dir) 41373b9b51feSCy Schubert { 41383b9b51feSCy Schubert case NAT_INBOUND : 41393b9b51feSCy Schubert case NAT_DIVERTIN : 41403b9b51feSCy Schubert if (nat->nat_v[0] != 4) 41413b9b51feSCy Schubert continue; 41423b9b51feSCy Schubert if (nat->nat_osrcaddr != src.s_addr || 41433b9b51feSCy Schubert nat->nat_odstaddr != dst) 41443b9b51feSCy Schubert continue; 41453b9b51feSCy Schubert if ((nat->nat_flags & IPN_TCPUDP) != 0) { 41463b9b51feSCy Schubert if (nat->nat_osport != sport) 41473b9b51feSCy Schubert continue; 41483b9b51feSCy Schubert if (nat->nat_odport != dport) 41493b9b51feSCy Schubert continue; 41503b9b51feSCy Schubert 41513b9b51feSCy Schubert } else if (p == IPPROTO_ICMP) { 41523b9b51feSCy Schubert if (nat->nat_osport != dport) { 41533b9b51feSCy Schubert continue; 41543b9b51feSCy Schubert } 41553b9b51feSCy Schubert } 41563b9b51feSCy Schubert break; 41573b9b51feSCy Schubert case NAT_DIVERTOUT : 41583b9b51feSCy Schubert if (nat->nat_dlocal) 41593b9b51feSCy Schubert continue; 41603b9b51feSCy Schubert case NAT_OUTBOUND : 41613b9b51feSCy Schubert if (nat->nat_v[1] != 4) 41623b9b51feSCy Schubert continue; 41633b9b51feSCy Schubert if (nat->nat_dlocal) 41643b9b51feSCy Schubert continue; 41653b9b51feSCy Schubert if (nat->nat_dlocal) 41663b9b51feSCy Schubert continue; 41673b9b51feSCy Schubert if (nat->nat_ndstaddr != src.s_addr || 41683b9b51feSCy Schubert nat->nat_nsrcaddr != dst) 41693b9b51feSCy Schubert continue; 41703b9b51feSCy Schubert if ((nat->nat_flags & IPN_TCPUDP) != 0) { 41713b9b51feSCy Schubert if (nat->nat_ndport != sport) 41723b9b51feSCy Schubert continue; 41733b9b51feSCy Schubert if (nat->nat_nsport != dport) 41743b9b51feSCy Schubert continue; 41753b9b51feSCy Schubert 41763b9b51feSCy Schubert } else if (p == IPPROTO_ICMP) { 41773b9b51feSCy Schubert if (nat->nat_osport != dport) { 41783b9b51feSCy Schubert continue; 41793b9b51feSCy Schubert } 41803b9b51feSCy Schubert } 41813b9b51feSCy Schubert break; 41823b9b51feSCy Schubert } 41833b9b51feSCy Schubert 41843b9b51feSCy Schubert 41853b9b51feSCy Schubert if ((nat->nat_flags & IPN_TCPUDP) != 0) { 41863b9b51feSCy Schubert ipn = nat->nat_ptr; 41873b9b51feSCy Schubert if ((ipn != NULL) && (nat->nat_aps != NULL)) 41883b9b51feSCy Schubert if (ipf_proxy_match(fin, nat) != 0) 41893b9b51feSCy Schubert continue; 41903b9b51feSCy Schubert } 41913b9b51feSCy Schubert if ((nat->nat_ifps[0] == NULL) && (ifp != NULL)) { 41923b9b51feSCy Schubert nat->nat_ifps[0] = ifp; 41933b9b51feSCy Schubert nat->nat_mtu[0] = GETIFMTU_4(ifp); 41943b9b51feSCy Schubert } 41953b9b51feSCy Schubert return nat; 41963b9b51feSCy Schubert } 41973b9b51feSCy Schubert 41983b9b51feSCy Schubert /* 41993b9b51feSCy Schubert * So if we didn't find it but there are wildcard members in the hash 42003b9b51feSCy Schubert * table, go back and look for them. We do this search and update here 42013b9b51feSCy Schubert * because it is modifying the NAT table and we want to do this only 42023b9b51feSCy Schubert * for the first packet that matches. The exception, of course, is 42033b9b51feSCy Schubert * for "dummy" (FI_IGNORE) lookups. 42043b9b51feSCy Schubert */ 42053b9b51feSCy Schubert find_in_wild_ports: 42063b9b51feSCy Schubert if (!(flags & NAT_TCPUDP) || !(flags & NAT_SEARCH)) { 42073b9b51feSCy Schubert NBUMPSIDEX(0, ns_lookup_miss, ns_lookup_miss_0); 42083b9b51feSCy Schubert return NULL; 42093b9b51feSCy Schubert } 42103b9b51feSCy Schubert if (softn->ipf_nat_stats.ns_wilds == 0 || (fin->fin_flx & FI_NOWILD)) { 42113b9b51feSCy Schubert NBUMPSIDEX(0, ns_lookup_nowild, ns_lookup_nowild_0); 42123b9b51feSCy Schubert return NULL; 42133b9b51feSCy Schubert } 42143b9b51feSCy Schubert 42153b9b51feSCy Schubert RWLOCK_EXIT(&softc->ipf_nat); 42163b9b51feSCy Schubert 42173b9b51feSCy Schubert hv = NAT_HASH_FN(dst, 0, 0xffffffff); 42183b9b51feSCy Schubert hv = NAT_HASH_FN(src.s_addr, hv, softn->ipf_nat_table_sz); 42193b9b51feSCy Schubert WRITE_ENTER(&softc->ipf_nat); 42203b9b51feSCy Schubert 42213b9b51feSCy Schubert nat = softn->ipf_nat_table[1][hv]; 42223b9b51feSCy Schubert /* TRACE dst, src, hv, nat */ 42233b9b51feSCy Schubert for (; nat; nat = nat->nat_hnext[1]) { 42243b9b51feSCy Schubert if (nat->nat_ifps[0] != NULL) { 42253b9b51feSCy Schubert if ((ifp != NULL) && (ifp != nat->nat_ifps[0])) 42263b9b51feSCy Schubert continue; 42273b9b51feSCy Schubert } 42283b9b51feSCy Schubert 42293b9b51feSCy Schubert if (nat->nat_pr[0] != fin->fin_p) 42303b9b51feSCy Schubert continue; 42313b9b51feSCy Schubert 42323b9b51feSCy Schubert switch (nat->nat_dir & (NAT_INBOUND|NAT_OUTBOUND)) 42333b9b51feSCy Schubert { 42343b9b51feSCy Schubert case NAT_INBOUND : 42353b9b51feSCy Schubert if (nat->nat_v[0] != 4) 42363b9b51feSCy Schubert continue; 42373b9b51feSCy Schubert if (nat->nat_osrcaddr != src.s_addr || 42383b9b51feSCy Schubert nat->nat_odstaddr != dst) 42393b9b51feSCy Schubert continue; 42403b9b51feSCy Schubert break; 42413b9b51feSCy Schubert case NAT_OUTBOUND : 42423b9b51feSCy Schubert if (nat->nat_v[1] != 4) 42433b9b51feSCy Schubert continue; 42443b9b51feSCy Schubert if (nat->nat_ndstaddr != src.s_addr || 42453b9b51feSCy Schubert nat->nat_nsrcaddr != dst) 42463b9b51feSCy Schubert continue; 42473b9b51feSCy Schubert break; 42483b9b51feSCy Schubert } 42493b9b51feSCy Schubert 42503b9b51feSCy Schubert nflags = nat->nat_flags; 42513b9b51feSCy Schubert if (!(nflags & (NAT_TCPUDP|SI_WILDP))) 42523b9b51feSCy Schubert continue; 42533b9b51feSCy Schubert 42543b9b51feSCy Schubert if (ipf_nat_wildok(nat, (int)sport, (int)dport, nflags, 42553b9b51feSCy Schubert NAT_INBOUND) == 1) { 42563b9b51feSCy Schubert if ((fin->fin_flx & FI_IGNORE) != 0) 42573b9b51feSCy Schubert break; 42583b9b51feSCy Schubert if ((nflags & SI_CLONE) != 0) { 42593b9b51feSCy Schubert nat = ipf_nat_clone(fin, nat); 42603b9b51feSCy Schubert if (nat == NULL) 42613b9b51feSCy Schubert break; 42623b9b51feSCy Schubert } else { 42633b9b51feSCy Schubert MUTEX_ENTER(&softn->ipf_nat_new); 42643b9b51feSCy Schubert softn->ipf_nat_stats.ns_wilds--; 42653b9b51feSCy Schubert MUTEX_EXIT(&softn->ipf_nat_new); 42663b9b51feSCy Schubert } 42673b9b51feSCy Schubert 42683b9b51feSCy Schubert if (nat->nat_dir == NAT_INBOUND) { 42693b9b51feSCy Schubert if (nat->nat_osport == 0) { 42703b9b51feSCy Schubert nat->nat_osport = sport; 42713b9b51feSCy Schubert nat->nat_nsport = sport; 42723b9b51feSCy Schubert } 42733b9b51feSCy Schubert if (nat->nat_odport == 0) { 42743b9b51feSCy Schubert nat->nat_odport = dport; 42753b9b51feSCy Schubert nat->nat_ndport = dport; 42763b9b51feSCy Schubert } 42773b9b51feSCy Schubert } else if (nat->nat_dir == NAT_OUTBOUND) { 42783b9b51feSCy Schubert if (nat->nat_osport == 0) { 42793b9b51feSCy Schubert nat->nat_osport = dport; 42803b9b51feSCy Schubert nat->nat_nsport = dport; 42813b9b51feSCy Schubert } 42823b9b51feSCy Schubert if (nat->nat_odport == 0) { 42833b9b51feSCy Schubert nat->nat_odport = sport; 42843b9b51feSCy Schubert nat->nat_ndport = sport; 42853b9b51feSCy Schubert } 42863b9b51feSCy Schubert } 42873b9b51feSCy Schubert if ((nat->nat_ifps[0] == NULL) && (ifp != NULL)) { 42883b9b51feSCy Schubert nat->nat_ifps[0] = ifp; 42893b9b51feSCy Schubert nat->nat_mtu[0] = GETIFMTU_4(ifp); 42903b9b51feSCy Schubert } 42913b9b51feSCy Schubert nat->nat_flags &= ~(SI_W_DPORT|SI_W_SPORT); 42923b9b51feSCy Schubert ipf_nat_tabmove(softn, nat); 42933b9b51feSCy Schubert break; 42943b9b51feSCy Schubert } 42953b9b51feSCy Schubert } 42963b9b51feSCy Schubert 42973b9b51feSCy Schubert MUTEX_DOWNGRADE(&softc->ipf_nat); 42983b9b51feSCy Schubert 42993b9b51feSCy Schubert if (nat == NULL) { 43003b9b51feSCy Schubert NBUMPSIDE(0, ns_lookup_miss); 43013b9b51feSCy Schubert } 43023b9b51feSCy Schubert return nat; 43033b9b51feSCy Schubert } 43043b9b51feSCy Schubert 43053b9b51feSCy Schubert 43063b9b51feSCy Schubert /* ------------------------------------------------------------------------ */ 43073b9b51feSCy Schubert /* Function: ipf_nat_tabmove */ 43083b9b51feSCy Schubert /* Returns: Nil */ 43093b9b51feSCy Schubert /* Parameters: softn(I) - pointer to NAT context structure */ 43103b9b51feSCy Schubert /* nat(I) - pointer to NAT structure */ 43113b9b51feSCy Schubert /* Write Lock: ipf_nat */ 43123b9b51feSCy Schubert /* */ 43133b9b51feSCy Schubert /* This function is only called for TCP/UDP NAT table entries where the */ 43143b9b51feSCy Schubert /* original was placed in the table without hashing on the ports and we now */ 43153b9b51feSCy Schubert /* want to include hashing on port numbers. */ 43163b9b51feSCy Schubert /* ------------------------------------------------------------------------ */ 43173b9b51feSCy Schubert static void 43183b9b51feSCy Schubert ipf_nat_tabmove(softn, nat) 43193b9b51feSCy Schubert ipf_nat_softc_t *softn; 43203b9b51feSCy Schubert nat_t *nat; 43213b9b51feSCy Schubert { 43223b9b51feSCy Schubert u_int hv0, hv1, rhv0, rhv1; 43233b9b51feSCy Schubert natstat_t *nsp; 43243b9b51feSCy Schubert nat_t **natp; 43253b9b51feSCy Schubert 43263b9b51feSCy Schubert if (nat->nat_flags & SI_CLONE) 43273b9b51feSCy Schubert return; 43283b9b51feSCy Schubert 43293b9b51feSCy Schubert nsp = &softn->ipf_nat_stats; 43303b9b51feSCy Schubert /* 43313b9b51feSCy Schubert * Remove the NAT entry from the old location 43323b9b51feSCy Schubert */ 43333b9b51feSCy Schubert if (nat->nat_hnext[0]) 43343b9b51feSCy Schubert nat->nat_hnext[0]->nat_phnext[0] = nat->nat_phnext[0]; 43353b9b51feSCy Schubert *nat->nat_phnext[0] = nat->nat_hnext[0]; 43363b9b51feSCy Schubert nsp->ns_side[0].ns_bucketlen[nat->nat_hv[0] % 43373b9b51feSCy Schubert softn->ipf_nat_table_sz]--; 43383b9b51feSCy Schubert 43393b9b51feSCy Schubert if (nat->nat_hnext[1]) 43403b9b51feSCy Schubert nat->nat_hnext[1]->nat_phnext[1] = nat->nat_phnext[1]; 43413b9b51feSCy Schubert *nat->nat_phnext[1] = nat->nat_hnext[1]; 43423b9b51feSCy Schubert nsp->ns_side[1].ns_bucketlen[nat->nat_hv[1] % 43433b9b51feSCy Schubert softn->ipf_nat_table_sz]--; 43443b9b51feSCy Schubert 43453b9b51feSCy Schubert /* 43463b9b51feSCy Schubert * Add into the NAT table in the new position 43473b9b51feSCy Schubert */ 43483b9b51feSCy Schubert rhv0 = NAT_HASH_FN(nat->nat_osrcaddr, nat->nat_osport, 0xffffffff); 43493b9b51feSCy Schubert rhv0 = NAT_HASH_FN(nat->nat_odstaddr, rhv0 + nat->nat_odport, 43503b9b51feSCy Schubert 0xffffffff); 43513b9b51feSCy Schubert rhv1 = NAT_HASH_FN(nat->nat_nsrcaddr, nat->nat_nsport, 0xffffffff); 43523b9b51feSCy Schubert rhv1 = NAT_HASH_FN(nat->nat_ndstaddr, rhv1 + nat->nat_ndport, 43533b9b51feSCy Schubert 0xffffffff); 43543b9b51feSCy Schubert 43553b9b51feSCy Schubert hv0 = rhv0 % softn->ipf_nat_table_sz; 43563b9b51feSCy Schubert hv1 = rhv1 % softn->ipf_nat_table_sz; 43573b9b51feSCy Schubert 43583b9b51feSCy Schubert if (nat->nat_dir == NAT_INBOUND || nat->nat_dir == NAT_DIVERTIN) { 43593b9b51feSCy Schubert u_int swap; 43603b9b51feSCy Schubert 43613b9b51feSCy Schubert swap = hv0; 43623b9b51feSCy Schubert hv0 = hv1; 43633b9b51feSCy Schubert hv1 = swap; 43643b9b51feSCy Schubert } 43653b9b51feSCy Schubert 43663b9b51feSCy Schubert /* TRACE nat_osrcaddr, nat_osport, nat_odstaddr, nat_odport, hv0 */ 43673b9b51feSCy Schubert /* TRACE nat_nsrcaddr, nat_nsport, nat_ndstaddr, nat_ndport, hv1 */ 43683b9b51feSCy Schubert 43693b9b51feSCy Schubert nat->nat_hv[0] = rhv0; 43703b9b51feSCy Schubert natp = &softn->ipf_nat_table[0][hv0]; 43713b9b51feSCy Schubert if (*natp) 43723b9b51feSCy Schubert (*natp)->nat_phnext[0] = &nat->nat_hnext[0]; 43733b9b51feSCy Schubert nat->nat_phnext[0] = natp; 43743b9b51feSCy Schubert nat->nat_hnext[0] = *natp; 43753b9b51feSCy Schubert *natp = nat; 43763b9b51feSCy Schubert nsp->ns_side[0].ns_bucketlen[hv0]++; 43773b9b51feSCy Schubert 43783b9b51feSCy Schubert nat->nat_hv[1] = rhv1; 43793b9b51feSCy Schubert natp = &softn->ipf_nat_table[1][hv1]; 43803b9b51feSCy Schubert if (*natp) 43813b9b51feSCy Schubert (*natp)->nat_phnext[1] = &nat->nat_hnext[1]; 43823b9b51feSCy Schubert nat->nat_phnext[1] = natp; 43833b9b51feSCy Schubert nat->nat_hnext[1] = *natp; 43843b9b51feSCy Schubert *natp = nat; 43853b9b51feSCy Schubert nsp->ns_side[1].ns_bucketlen[hv1]++; 43863b9b51feSCy Schubert } 43873b9b51feSCy Schubert 43883b9b51feSCy Schubert 43893b9b51feSCy Schubert /* ------------------------------------------------------------------------ */ 43903b9b51feSCy Schubert /* Function: ipf_nat_outlookup */ 43913b9b51feSCy Schubert /* Returns: nat_t* - NULL == no match, */ 43923b9b51feSCy Schubert /* else pointer to matching NAT entry */ 43933b9b51feSCy Schubert /* Parameters: fin(I) - pointer to packet information */ 43943b9b51feSCy Schubert /* flags(I) - NAT flags for this packet */ 43953b9b51feSCy Schubert /* p(I) - protocol for this packet */ 43963b9b51feSCy Schubert /* src(I) - source IP address */ 43973b9b51feSCy Schubert /* dst(I) - destination IP address */ 43983b9b51feSCy Schubert /* rw(I) - 1 == write lock on held, 0 == read lock. */ 43993b9b51feSCy Schubert /* */ 44003b9b51feSCy Schubert /* Lookup a nat entry based on the source 'real' ip address/port and */ 44013b9b51feSCy Schubert /* destination address/port. We use this lookup when sending a packet out, */ 44023b9b51feSCy Schubert /* we're looking for a table entry, based on the source address. */ 44033b9b51feSCy Schubert /* */ 44043b9b51feSCy Schubert /* NOTE: THE PACKET BEING CHECKED (IF FOUND) HAS A MAPPING ALREADY. */ 44053b9b51feSCy Schubert /* */ 44063b9b51feSCy Schubert /* NOTE: IT IS ASSUMED THAT IS ONLY HELD WITH A READ LOCK WHEN */ 44073b9b51feSCy Schubert /* THIS FUNCTION IS CALLED WITH NAT_SEARCH SET IN nflags. */ 44083b9b51feSCy Schubert /* */ 44093b9b51feSCy Schubert /* flags -> relevant are IPN_UDP/IPN_TCP/IPN_ICMPQUERY that indicate if */ 44103b9b51feSCy Schubert /* the packet is of said protocol */ 44113b9b51feSCy Schubert /* ------------------------------------------------------------------------ */ 44123b9b51feSCy Schubert nat_t * 44133b9b51feSCy Schubert ipf_nat_outlookup(fin, flags, p, src, dst) 44143b9b51feSCy Schubert fr_info_t *fin; 44153b9b51feSCy Schubert u_int flags, p; 44163b9b51feSCy Schubert struct in_addr src , dst; 44173b9b51feSCy Schubert { 44183b9b51feSCy Schubert ipf_main_softc_t *softc = fin->fin_main_soft; 44193b9b51feSCy Schubert ipf_nat_softc_t *softn = softc->ipf_nat_soft; 44203b9b51feSCy Schubert u_short sport, dport; 44213b9b51feSCy Schubert u_int sflags; 44223b9b51feSCy Schubert ipnat_t *ipn; 44233b9b51feSCy Schubert nat_t *nat; 44243b9b51feSCy Schubert void *ifp; 44253b9b51feSCy Schubert u_int hv; 44263b9b51feSCy Schubert 44273b9b51feSCy Schubert ifp = fin->fin_ifp; 44283b9b51feSCy Schubert sflags = flags & IPN_TCPUDPICMP; 44293b9b51feSCy Schubert 44303b9b51feSCy Schubert switch (p) 44313b9b51feSCy Schubert { 44323b9b51feSCy Schubert case IPPROTO_TCP : 44333b9b51feSCy Schubert case IPPROTO_UDP : 44343b9b51feSCy Schubert sport = htons(fin->fin_data[0]); 44353b9b51feSCy Schubert dport = htons(fin->fin_data[1]); 44363b9b51feSCy Schubert break; 44373b9b51feSCy Schubert case IPPROTO_ICMP : 44383b9b51feSCy Schubert sport = 0; 44393b9b51feSCy Schubert dport = fin->fin_data[1]; 44403b9b51feSCy Schubert break; 44413b9b51feSCy Schubert default : 44423b9b51feSCy Schubert sport = 0; 44433b9b51feSCy Schubert dport = 0; 44443b9b51feSCy Schubert break; 44453b9b51feSCy Schubert } 44463b9b51feSCy Schubert 44473b9b51feSCy Schubert if ((flags & SI_WILDP) != 0) 44483b9b51feSCy Schubert goto find_out_wild_ports; 44493b9b51feSCy Schubert 44503b9b51feSCy Schubert hv = NAT_HASH_FN(src.s_addr, sport, 0xffffffff); 44513b9b51feSCy Schubert hv = NAT_HASH_FN(dst.s_addr, hv + dport, softn->ipf_nat_table_sz); 44523b9b51feSCy Schubert nat = softn->ipf_nat_table[0][hv]; 44533b9b51feSCy Schubert 44543b9b51feSCy Schubert /* TRACE src, sport, dst, dport, hv, nat */ 44553b9b51feSCy Schubert 44563b9b51feSCy Schubert for (; nat; nat = nat->nat_hnext[0]) { 44573b9b51feSCy Schubert if (nat->nat_ifps[1] != NULL) { 44583b9b51feSCy Schubert if ((ifp != NULL) && (ifp != nat->nat_ifps[1])) 44593b9b51feSCy Schubert continue; 44603b9b51feSCy Schubert } 44613b9b51feSCy Schubert 44623b9b51feSCy Schubert if (nat->nat_pr[1] != p) 44633b9b51feSCy Schubert continue; 44643b9b51feSCy Schubert 44653b9b51feSCy Schubert switch (nat->nat_dir) 44663b9b51feSCy Schubert { 44673b9b51feSCy Schubert case NAT_INBOUND : 44683b9b51feSCy Schubert case NAT_DIVERTIN : 44693b9b51feSCy Schubert if (nat->nat_v[1] != 4) 44703b9b51feSCy Schubert continue; 44713b9b51feSCy Schubert if (nat->nat_ndstaddr != src.s_addr || 44723b9b51feSCy Schubert nat->nat_nsrcaddr != dst.s_addr) 44733b9b51feSCy Schubert continue; 44743b9b51feSCy Schubert 44753b9b51feSCy Schubert if ((nat->nat_flags & IPN_TCPUDP) != 0) { 44763b9b51feSCy Schubert if (nat->nat_ndport != sport) 44773b9b51feSCy Schubert continue; 44783b9b51feSCy Schubert if (nat->nat_nsport != dport) 44793b9b51feSCy Schubert continue; 44803b9b51feSCy Schubert 44813b9b51feSCy Schubert } else if (p == IPPROTO_ICMP) { 44823b9b51feSCy Schubert if (nat->nat_osport != dport) { 44833b9b51feSCy Schubert continue; 44843b9b51feSCy Schubert } 44853b9b51feSCy Schubert } 44863b9b51feSCy Schubert break; 44873b9b51feSCy Schubert case NAT_OUTBOUND : 44883b9b51feSCy Schubert case NAT_DIVERTOUT : 44893b9b51feSCy Schubert if (nat->nat_v[0] != 4) 44903b9b51feSCy Schubert continue; 44913b9b51feSCy Schubert if (nat->nat_osrcaddr != src.s_addr || 44923b9b51feSCy Schubert nat->nat_odstaddr != dst.s_addr) 44933b9b51feSCy Schubert continue; 44943b9b51feSCy Schubert 44953b9b51feSCy Schubert if ((nat->nat_flags & IPN_TCPUDP) != 0) { 44963b9b51feSCy Schubert if (nat->nat_odport != dport) 44973b9b51feSCy Schubert continue; 44983b9b51feSCy Schubert if (nat->nat_osport != sport) 44993b9b51feSCy Schubert continue; 45003b9b51feSCy Schubert 45013b9b51feSCy Schubert } else if (p == IPPROTO_ICMP) { 45023b9b51feSCy Schubert if (nat->nat_osport != dport) { 45033b9b51feSCy Schubert continue; 45043b9b51feSCy Schubert } 45053b9b51feSCy Schubert } 45063b9b51feSCy Schubert break; 45073b9b51feSCy Schubert } 45083b9b51feSCy Schubert 45093b9b51feSCy Schubert ipn = nat->nat_ptr; 45103b9b51feSCy Schubert if ((ipn != NULL) && (nat->nat_aps != NULL)) 45113b9b51feSCy Schubert if (ipf_proxy_match(fin, nat) != 0) 45123b9b51feSCy Schubert continue; 45133b9b51feSCy Schubert 45143b9b51feSCy Schubert if ((nat->nat_ifps[1] == NULL) && (ifp != NULL)) { 45153b9b51feSCy Schubert nat->nat_ifps[1] = ifp; 45163b9b51feSCy Schubert nat->nat_mtu[1] = GETIFMTU_4(ifp); 45173b9b51feSCy Schubert } 45183b9b51feSCy Schubert return nat; 45193b9b51feSCy Schubert } 45203b9b51feSCy Schubert 45213b9b51feSCy Schubert /* 45223b9b51feSCy Schubert * So if we didn't find it but there are wildcard members in the hash 45233b9b51feSCy Schubert * table, go back and look for them. We do this search and update here 45243b9b51feSCy Schubert * because it is modifying the NAT table and we want to do this only 45253b9b51feSCy Schubert * for the first packet that matches. The exception, of course, is 45263b9b51feSCy Schubert * for "dummy" (FI_IGNORE) lookups. 45273b9b51feSCy Schubert */ 45283b9b51feSCy Schubert find_out_wild_ports: 45293b9b51feSCy Schubert if (!(flags & NAT_TCPUDP) || !(flags & NAT_SEARCH)) { 45303b9b51feSCy Schubert NBUMPSIDEX(1, ns_lookup_miss, ns_lookup_miss_1); 45313b9b51feSCy Schubert return NULL; 45323b9b51feSCy Schubert } 45333b9b51feSCy Schubert if (softn->ipf_nat_stats.ns_wilds == 0 || (fin->fin_flx & FI_NOWILD)) { 45343b9b51feSCy Schubert NBUMPSIDEX(1, ns_lookup_nowild, ns_lookup_nowild_1); 45353b9b51feSCy Schubert return NULL; 45363b9b51feSCy Schubert } 45373b9b51feSCy Schubert 45383b9b51feSCy Schubert RWLOCK_EXIT(&softc->ipf_nat); 45393b9b51feSCy Schubert 45403b9b51feSCy Schubert hv = NAT_HASH_FN(src.s_addr, 0, 0xffffffff); 45413b9b51feSCy Schubert hv = NAT_HASH_FN(dst.s_addr, hv, softn->ipf_nat_table_sz); 45423b9b51feSCy Schubert 45433b9b51feSCy Schubert WRITE_ENTER(&softc->ipf_nat); 45443b9b51feSCy Schubert 45453b9b51feSCy Schubert nat = softn->ipf_nat_table[0][hv]; 45463b9b51feSCy Schubert for (; nat; nat = nat->nat_hnext[0]) { 45473b9b51feSCy Schubert if (nat->nat_ifps[1] != NULL) { 45483b9b51feSCy Schubert if ((ifp != NULL) && (ifp != nat->nat_ifps[1])) 45493b9b51feSCy Schubert continue; 45503b9b51feSCy Schubert } 45513b9b51feSCy Schubert 45523b9b51feSCy Schubert if (nat->nat_pr[1] != fin->fin_p) 45533b9b51feSCy Schubert continue; 45543b9b51feSCy Schubert 45553b9b51feSCy Schubert switch (nat->nat_dir & (NAT_INBOUND|NAT_OUTBOUND)) 45563b9b51feSCy Schubert { 45573b9b51feSCy Schubert case NAT_INBOUND : 45583b9b51feSCy Schubert if (nat->nat_v[1] != 4) 45593b9b51feSCy Schubert continue; 45603b9b51feSCy Schubert if (nat->nat_ndstaddr != src.s_addr || 45613b9b51feSCy Schubert nat->nat_nsrcaddr != dst.s_addr) 45623b9b51feSCy Schubert continue; 45633b9b51feSCy Schubert break; 45643b9b51feSCy Schubert case NAT_OUTBOUND : 45653b9b51feSCy Schubert if (nat->nat_v[0] != 4) 45663b9b51feSCy Schubert continue; 45673b9b51feSCy Schubert if (nat->nat_osrcaddr != src.s_addr || 45683b9b51feSCy Schubert nat->nat_odstaddr != dst.s_addr) 45693b9b51feSCy Schubert continue; 45703b9b51feSCy Schubert break; 45713b9b51feSCy Schubert } 45723b9b51feSCy Schubert 45733b9b51feSCy Schubert if (!(nat->nat_flags & (NAT_TCPUDP|SI_WILDP))) 45743b9b51feSCy Schubert continue; 45753b9b51feSCy Schubert 45763b9b51feSCy Schubert if (ipf_nat_wildok(nat, (int)sport, (int)dport, nat->nat_flags, 45773b9b51feSCy Schubert NAT_OUTBOUND) == 1) { 45783b9b51feSCy Schubert if ((fin->fin_flx & FI_IGNORE) != 0) 45793b9b51feSCy Schubert break; 45803b9b51feSCy Schubert if ((nat->nat_flags & SI_CLONE) != 0) { 45813b9b51feSCy Schubert nat = ipf_nat_clone(fin, nat); 45823b9b51feSCy Schubert if (nat == NULL) 45833b9b51feSCy Schubert break; 45843b9b51feSCy Schubert } else { 45853b9b51feSCy Schubert MUTEX_ENTER(&softn->ipf_nat_new); 45863b9b51feSCy Schubert softn->ipf_nat_stats.ns_wilds--; 45873b9b51feSCy Schubert MUTEX_EXIT(&softn->ipf_nat_new); 45883b9b51feSCy Schubert } 45893b9b51feSCy Schubert 45903b9b51feSCy Schubert if (nat->nat_dir == NAT_OUTBOUND) { 45913b9b51feSCy Schubert if (nat->nat_osport == 0) { 45923b9b51feSCy Schubert nat->nat_osport = sport; 45933b9b51feSCy Schubert nat->nat_nsport = sport; 45943b9b51feSCy Schubert } 45953b9b51feSCy Schubert if (nat->nat_odport == 0) { 45963b9b51feSCy Schubert nat->nat_odport = dport; 45973b9b51feSCy Schubert nat->nat_ndport = dport; 45983b9b51feSCy Schubert } 45993b9b51feSCy Schubert } else if (nat->nat_dir == NAT_INBOUND) { 46003b9b51feSCy Schubert if (nat->nat_osport == 0) { 46013b9b51feSCy Schubert nat->nat_osport = dport; 46023b9b51feSCy Schubert nat->nat_nsport = dport; 46033b9b51feSCy Schubert } 46043b9b51feSCy Schubert if (nat->nat_odport == 0) { 46053b9b51feSCy Schubert nat->nat_odport = sport; 46063b9b51feSCy Schubert nat->nat_ndport = sport; 46073b9b51feSCy Schubert } 46083b9b51feSCy Schubert } 46093b9b51feSCy Schubert if ((nat->nat_ifps[1] == NULL) && (ifp != NULL)) { 46103b9b51feSCy Schubert nat->nat_ifps[1] = ifp; 46113b9b51feSCy Schubert nat->nat_mtu[1] = GETIFMTU_4(ifp); 46123b9b51feSCy Schubert } 46133b9b51feSCy Schubert nat->nat_flags &= ~(SI_W_DPORT|SI_W_SPORT); 46143b9b51feSCy Schubert ipf_nat_tabmove(softn, nat); 46153b9b51feSCy Schubert break; 46163b9b51feSCy Schubert } 46173b9b51feSCy Schubert } 46183b9b51feSCy Schubert 46193b9b51feSCy Schubert MUTEX_DOWNGRADE(&softc->ipf_nat); 46203b9b51feSCy Schubert 46213b9b51feSCy Schubert if (nat == NULL) { 46223b9b51feSCy Schubert NBUMPSIDE(1, ns_lookup_miss); 46233b9b51feSCy Schubert } 46243b9b51feSCy Schubert return nat; 46253b9b51feSCy Schubert } 46263b9b51feSCy Schubert 46273b9b51feSCy Schubert 46283b9b51feSCy Schubert /* ------------------------------------------------------------------------ */ 46293b9b51feSCy Schubert /* Function: ipf_nat_lookupredir */ 46303b9b51feSCy Schubert /* Returns: nat_t* - NULL == no match, */ 46313b9b51feSCy Schubert /* else pointer to matching NAT entry */ 46323b9b51feSCy Schubert /* Parameters: np(I) - pointer to description of packet to find NAT table */ 46333b9b51feSCy Schubert /* entry for. */ 46343b9b51feSCy Schubert /* */ 46353b9b51feSCy Schubert /* Lookup the NAT tables to search for a matching redirect */ 46363b9b51feSCy Schubert /* The contents of natlookup_t should imitate those found in a packet that */ 46373b9b51feSCy Schubert /* would be translated - ie a packet coming in for RDR or going out for MAP.*/ 46383b9b51feSCy Schubert /* We can do the lookup in one of two ways, imitating an inbound or */ 46393b9b51feSCy Schubert /* outbound packet. By default we assume outbound, unless IPN_IN is set. */ 46403b9b51feSCy Schubert /* For IN, the fields are set as follows: */ 46413b9b51feSCy Schubert /* nl_real* = source information */ 46423b9b51feSCy Schubert /* nl_out* = destination information (translated) */ 46433b9b51feSCy Schubert /* For an out packet, the fields are set like this: */ 46443b9b51feSCy Schubert /* nl_in* = source information (untranslated) */ 46453b9b51feSCy Schubert /* nl_out* = destination information (translated) */ 46463b9b51feSCy Schubert /* ------------------------------------------------------------------------ */ 46473b9b51feSCy Schubert nat_t * 46483b9b51feSCy Schubert ipf_nat_lookupredir(np) 46493b9b51feSCy Schubert natlookup_t *np; 46503b9b51feSCy Schubert { 46513b9b51feSCy Schubert fr_info_t fi; 46523b9b51feSCy Schubert nat_t *nat; 46533b9b51feSCy Schubert 46543b9b51feSCy Schubert bzero((char *)&fi, sizeof(fi)); 46553b9b51feSCy Schubert if (np->nl_flags & IPN_IN) { 46563b9b51feSCy Schubert fi.fin_data[0] = ntohs(np->nl_realport); 46573b9b51feSCy Schubert fi.fin_data[1] = ntohs(np->nl_outport); 46583b9b51feSCy Schubert } else { 46593b9b51feSCy Schubert fi.fin_data[0] = ntohs(np->nl_inport); 46603b9b51feSCy Schubert fi.fin_data[1] = ntohs(np->nl_outport); 46613b9b51feSCy Schubert } 46623b9b51feSCy Schubert if (np->nl_flags & IPN_TCP) 46633b9b51feSCy Schubert fi.fin_p = IPPROTO_TCP; 46643b9b51feSCy Schubert else if (np->nl_flags & IPN_UDP) 46653b9b51feSCy Schubert fi.fin_p = IPPROTO_UDP; 46663b9b51feSCy Schubert else if (np->nl_flags & (IPN_ICMPERR|IPN_ICMPQUERY)) 46673b9b51feSCy Schubert fi.fin_p = IPPROTO_ICMP; 46683b9b51feSCy Schubert 46693b9b51feSCy Schubert /* 46703b9b51feSCy Schubert * We can do two sorts of lookups: 46713b9b51feSCy Schubert * - IPN_IN: we have the `real' and `out' address, look for `in'. 46723b9b51feSCy Schubert * - default: we have the `in' and `out' address, look for `real'. 46733b9b51feSCy Schubert */ 46743b9b51feSCy Schubert if (np->nl_flags & IPN_IN) { 46753b9b51feSCy Schubert if ((nat = ipf_nat_inlookup(&fi, np->nl_flags, fi.fin_p, 46763b9b51feSCy Schubert np->nl_realip, np->nl_outip))) { 46773b9b51feSCy Schubert np->nl_inip = nat->nat_odstip; 46783b9b51feSCy Schubert np->nl_inport = nat->nat_odport; 46793b9b51feSCy Schubert } 46803b9b51feSCy Schubert } else { 46813b9b51feSCy Schubert /* 46823b9b51feSCy Schubert * If nl_inip is non null, this is a lookup based on the real 46833b9b51feSCy Schubert * ip address. Else, we use the fake. 46843b9b51feSCy Schubert */ 46853b9b51feSCy Schubert if ((nat = ipf_nat_outlookup(&fi, np->nl_flags, fi.fin_p, 46863b9b51feSCy Schubert np->nl_inip, np->nl_outip))) { 46873b9b51feSCy Schubert 46883b9b51feSCy Schubert if ((np->nl_flags & IPN_FINDFORWARD) != 0) { 46893b9b51feSCy Schubert fr_info_t fin; 46903b9b51feSCy Schubert bzero((char *)&fin, sizeof(fin)); 46913b9b51feSCy Schubert fin.fin_p = nat->nat_pr[0]; 46923b9b51feSCy Schubert fin.fin_data[0] = ntohs(nat->nat_ndport); 46933b9b51feSCy Schubert fin.fin_data[1] = ntohs(nat->nat_nsport); 46943b9b51feSCy Schubert if (ipf_nat_inlookup(&fin, np->nl_flags, 46953b9b51feSCy Schubert fin.fin_p, nat->nat_ndstip, 46963b9b51feSCy Schubert nat->nat_nsrcip) != NULL) { 46973b9b51feSCy Schubert np->nl_flags &= ~IPN_FINDFORWARD; 46983b9b51feSCy Schubert } 46993b9b51feSCy Schubert } 47003b9b51feSCy Schubert 47013b9b51feSCy Schubert np->nl_realip = nat->nat_odstip; 47023b9b51feSCy Schubert np->nl_realport = nat->nat_odport; 47033b9b51feSCy Schubert } 47043b9b51feSCy Schubert } 47053b9b51feSCy Schubert 47063b9b51feSCy Schubert return nat; 47073b9b51feSCy Schubert } 47083b9b51feSCy Schubert 47093b9b51feSCy Schubert 47103b9b51feSCy Schubert /* ------------------------------------------------------------------------ */ 47113b9b51feSCy Schubert /* Function: ipf_nat_match */ 47123b9b51feSCy Schubert /* Returns: int - 0 == no match, 1 == match */ 47133b9b51feSCy Schubert /* Parameters: fin(I) - pointer to packet information */ 47143b9b51feSCy Schubert /* np(I) - pointer to NAT rule */ 47153b9b51feSCy Schubert /* */ 47163b9b51feSCy Schubert /* Pull the matching of a packet against a NAT rule out of that complex */ 47173b9b51feSCy Schubert /* loop inside ipf_nat_checkin() and lay it out properly in its own function. */ 47183b9b51feSCy Schubert /* ------------------------------------------------------------------------ */ 47193b9b51feSCy Schubert static int 47203b9b51feSCy Schubert ipf_nat_match(fin, np) 47213b9b51feSCy Schubert fr_info_t *fin; 47223b9b51feSCy Schubert ipnat_t *np; 47233b9b51feSCy Schubert { 47243b9b51feSCy Schubert ipf_main_softc_t *softc = fin->fin_main_soft; 47253b9b51feSCy Schubert frtuc_t *ft; 47263b9b51feSCy Schubert int match; 47273b9b51feSCy Schubert 47283b9b51feSCy Schubert match = 0; 47293b9b51feSCy Schubert switch (np->in_osrcatype) 47303b9b51feSCy Schubert { 47313b9b51feSCy Schubert case FRI_NORMAL : 47323b9b51feSCy Schubert match = ((fin->fin_saddr & np->in_osrcmsk) != np->in_osrcaddr); 47333b9b51feSCy Schubert break; 47343b9b51feSCy Schubert case FRI_LOOKUP : 47353b9b51feSCy Schubert match = (*np->in_osrcfunc)(softc, np->in_osrcptr, 47363b9b51feSCy Schubert 4, &fin->fin_saddr, fin->fin_plen); 47373b9b51feSCy Schubert break; 47383b9b51feSCy Schubert } 47393b9b51feSCy Schubert match ^= ((np->in_flags & IPN_NOTSRC) != 0); 47403b9b51feSCy Schubert if (match) 47413b9b51feSCy Schubert return 0; 47423b9b51feSCy Schubert 47433b9b51feSCy Schubert match = 0; 47443b9b51feSCy Schubert switch (np->in_odstatype) 47453b9b51feSCy Schubert { 47463b9b51feSCy Schubert case FRI_NORMAL : 47473b9b51feSCy Schubert match = ((fin->fin_daddr & np->in_odstmsk) != np->in_odstaddr); 47483b9b51feSCy Schubert break; 47493b9b51feSCy Schubert case FRI_LOOKUP : 47503b9b51feSCy Schubert match = (*np->in_odstfunc)(softc, np->in_odstptr, 47513b9b51feSCy Schubert 4, &fin->fin_daddr, fin->fin_plen); 47523b9b51feSCy Schubert break; 47533b9b51feSCy Schubert } 47543b9b51feSCy Schubert 47553b9b51feSCy Schubert match ^= ((np->in_flags & IPN_NOTDST) != 0); 47563b9b51feSCy Schubert if (match) 47573b9b51feSCy Schubert return 0; 47583b9b51feSCy Schubert 47593b9b51feSCy Schubert ft = &np->in_tuc; 47603b9b51feSCy Schubert if (!(fin->fin_flx & FI_TCPUDP) || 47613b9b51feSCy Schubert (fin->fin_flx & (FI_SHORT|FI_FRAGBODY))) { 47623b9b51feSCy Schubert if (ft->ftu_scmp || ft->ftu_dcmp) 47633b9b51feSCy Schubert return 0; 47643b9b51feSCy Schubert return 1; 47653b9b51feSCy Schubert } 47663b9b51feSCy Schubert 47673b9b51feSCy Schubert return ipf_tcpudpchk(&fin->fin_fi, ft); 47683b9b51feSCy Schubert } 47693b9b51feSCy Schubert 47703b9b51feSCy Schubert 47713b9b51feSCy Schubert /* ------------------------------------------------------------------------ */ 47723b9b51feSCy Schubert /* Function: ipf_nat_update */ 47733b9b51feSCy Schubert /* Returns: Nil */ 47743b9b51feSCy Schubert /* Parameters: fin(I) - pointer to packet information */ 47753b9b51feSCy Schubert /* nat(I) - pointer to NAT structure */ 47763b9b51feSCy Schubert /* */ 47773b9b51feSCy Schubert /* Updates the lifetime of a NAT table entry for non-TCP packets. Must be */ 47783b9b51feSCy Schubert /* called with fin_rev updated - i.e. after calling ipf_nat_proto(). */ 47793b9b51feSCy Schubert /* */ 47803b9b51feSCy Schubert /* This *MUST* be called after ipf_nat_proto() as it expects fin_rev to */ 47813b9b51feSCy Schubert /* already be set. */ 47823b9b51feSCy Schubert /* ------------------------------------------------------------------------ */ 47833b9b51feSCy Schubert void 47843b9b51feSCy Schubert ipf_nat_update(fin, nat) 47853b9b51feSCy Schubert fr_info_t *fin; 47863b9b51feSCy Schubert nat_t *nat; 47873b9b51feSCy Schubert { 47883b9b51feSCy Schubert ipf_main_softc_t *softc = fin->fin_main_soft; 47893b9b51feSCy Schubert ipf_nat_softc_t *softn = softc->ipf_nat_soft; 47903b9b51feSCy Schubert ipftq_t *ifq, *ifq2; 47913b9b51feSCy Schubert ipftqent_t *tqe; 47923b9b51feSCy Schubert ipnat_t *np = nat->nat_ptr; 47933b9b51feSCy Schubert 47943b9b51feSCy Schubert tqe = &nat->nat_tqe; 47953b9b51feSCy Schubert ifq = tqe->tqe_ifq; 47963b9b51feSCy Schubert 47973b9b51feSCy Schubert /* 47983b9b51feSCy Schubert * We allow over-riding of NAT timeouts from NAT rules, even for 47993b9b51feSCy Schubert * TCP, however, if it is TCP and there is no rule timeout set, 48003b9b51feSCy Schubert * then do not update the timeout here. 48013b9b51feSCy Schubert */ 48023b9b51feSCy Schubert if (np != NULL) { 48033b9b51feSCy Schubert np->in_bytes[fin->fin_rev] += fin->fin_plen; 48043b9b51feSCy Schubert ifq2 = np->in_tqehead[fin->fin_rev]; 48053b9b51feSCy Schubert } else { 48063b9b51feSCy Schubert ifq2 = NULL; 48073b9b51feSCy Schubert } 48083b9b51feSCy Schubert 48093b9b51feSCy Schubert if (nat->nat_pr[0] == IPPROTO_TCP && ifq2 == NULL) { 48103b9b51feSCy Schubert (void) ipf_tcp_age(&nat->nat_tqe, fin, softn->ipf_nat_tcptq, 48113b9b51feSCy Schubert 0, 2); 48123b9b51feSCy Schubert } else { 48133b9b51feSCy Schubert if (ifq2 == NULL) { 48143b9b51feSCy Schubert if (nat->nat_pr[0] == IPPROTO_UDP) 48153b9b51feSCy Schubert ifq2 = fin->fin_rev ? &softn->ipf_nat_udpacktq : 48163b9b51feSCy Schubert &softn->ipf_nat_udptq; 48173b9b51feSCy Schubert else if (nat->nat_pr[0] == IPPROTO_ICMP || 48183b9b51feSCy Schubert nat->nat_pr[0] == IPPROTO_ICMPV6) 48193b9b51feSCy Schubert ifq2 = fin->fin_rev ? &softn->ipf_nat_icmpacktq: 48203b9b51feSCy Schubert &softn->ipf_nat_icmptq; 48213b9b51feSCy Schubert else 48223b9b51feSCy Schubert ifq2 = &softn->ipf_nat_iptq; 48233b9b51feSCy Schubert } 48243b9b51feSCy Schubert 48253b9b51feSCy Schubert ipf_movequeue(softc->ipf_ticks, tqe, ifq, ifq2); 48263b9b51feSCy Schubert } 48273b9b51feSCy Schubert } 48283b9b51feSCy Schubert 48293b9b51feSCy Schubert 48303b9b51feSCy Schubert /* ------------------------------------------------------------------------ */ 48313b9b51feSCy Schubert /* Function: ipf_nat_checkout */ 48323b9b51feSCy Schubert /* Returns: int - -1 == packet failed NAT checks so block it, */ 48333b9b51feSCy Schubert /* 0 == no packet translation occurred, */ 48343b9b51feSCy Schubert /* 1 == packet was successfully translated. */ 48353b9b51feSCy Schubert /* Parameters: fin(I) - pointer to packet information */ 48363b9b51feSCy Schubert /* passp(I) - pointer to filtering result flags */ 48373b9b51feSCy Schubert /* */ 48383b9b51feSCy Schubert /* Check to see if an outcoming packet should be changed. ICMP packets are */ 48393b9b51feSCy Schubert /* first checked to see if they match an existing entry (if an error), */ 48403b9b51feSCy Schubert /* otherwise a search of the current NAT table is made. If neither results */ 48413b9b51feSCy Schubert /* in a match then a search for a matching NAT rule is made. Create a new */ 48423b9b51feSCy Schubert /* NAT entry if a we matched a NAT rule. Lastly, actually change the */ 48433b9b51feSCy Schubert /* packet header(s) as required. */ 48443b9b51feSCy Schubert /* ------------------------------------------------------------------------ */ 48453b9b51feSCy Schubert int 48463b9b51feSCy Schubert ipf_nat_checkout(fin, passp) 48473b9b51feSCy Schubert fr_info_t *fin; 48483b9b51feSCy Schubert u_32_t *passp; 48493b9b51feSCy Schubert { 48503b9b51feSCy Schubert ipnat_t *np = NULL, *npnext; 48513b9b51feSCy Schubert struct ifnet *ifp, *sifp; 48523b9b51feSCy Schubert ipf_main_softc_t *softc; 48533b9b51feSCy Schubert ipf_nat_softc_t *softn; 48543b9b51feSCy Schubert icmphdr_t *icmp = NULL; 48553b9b51feSCy Schubert tcphdr_t *tcp = NULL; 48563b9b51feSCy Schubert int rval, natfailed; 48573b9b51feSCy Schubert u_int nflags = 0; 48583b9b51feSCy Schubert u_32_t ipa, iph; 48593b9b51feSCy Schubert int natadd = 1; 48603b9b51feSCy Schubert frentry_t *fr; 48613b9b51feSCy Schubert nat_t *nat; 48623b9b51feSCy Schubert 48633b9b51feSCy Schubert if (fin->fin_v == 6) { 48643b9b51feSCy Schubert #ifdef USE_INET6 48653b9b51feSCy Schubert return ipf_nat6_checkout(fin, passp); 48663b9b51feSCy Schubert #else 48673b9b51feSCy Schubert return 0; 48683b9b51feSCy Schubert #endif 48693b9b51feSCy Schubert } 48703b9b51feSCy Schubert 48713b9b51feSCy Schubert softc = fin->fin_main_soft; 48723b9b51feSCy Schubert softn = softc->ipf_nat_soft; 48733b9b51feSCy Schubert 48743b9b51feSCy Schubert if (softn->ipf_nat_lock != 0) 48753b9b51feSCy Schubert return 0; 48763b9b51feSCy Schubert if (softn->ipf_nat_stats.ns_rules == 0 && 48773b9b51feSCy Schubert softn->ipf_nat_instances == NULL) 48783b9b51feSCy Schubert return 0; 48793b9b51feSCy Schubert 48803b9b51feSCy Schubert natfailed = 0; 48813b9b51feSCy Schubert fr = fin->fin_fr; 48823b9b51feSCy Schubert sifp = fin->fin_ifp; 48833b9b51feSCy Schubert if (fr != NULL) { 48843b9b51feSCy Schubert ifp = fr->fr_tifs[fin->fin_rev].fd_ptr; 48853b9b51feSCy Schubert if ((ifp != NULL) && (ifp != (void *)-1)) 48863b9b51feSCy Schubert fin->fin_ifp = ifp; 48873b9b51feSCy Schubert } 48883b9b51feSCy Schubert ifp = fin->fin_ifp; 48893b9b51feSCy Schubert 48903b9b51feSCy Schubert if (!(fin->fin_flx & FI_SHORT) && (fin->fin_off == 0)) { 48913b9b51feSCy Schubert switch (fin->fin_p) 48923b9b51feSCy Schubert { 48933b9b51feSCy Schubert case IPPROTO_TCP : 48943b9b51feSCy Schubert nflags = IPN_TCP; 48953b9b51feSCy Schubert break; 48963b9b51feSCy Schubert case IPPROTO_UDP : 48973b9b51feSCy Schubert nflags = IPN_UDP; 48983b9b51feSCy Schubert break; 48993b9b51feSCy Schubert case IPPROTO_ICMP : 49003b9b51feSCy Schubert icmp = fin->fin_dp; 49013b9b51feSCy Schubert 49023b9b51feSCy Schubert /* 49033b9b51feSCy Schubert * This is an incoming packet, so the destination is 49043b9b51feSCy Schubert * the icmp_id and the source port equals 0 49053b9b51feSCy Schubert */ 49063b9b51feSCy Schubert if ((fin->fin_flx & FI_ICMPQUERY) != 0) 49073b9b51feSCy Schubert nflags = IPN_ICMPQUERY; 49083b9b51feSCy Schubert break; 49093b9b51feSCy Schubert default : 49103b9b51feSCy Schubert break; 49113b9b51feSCy Schubert } 49123b9b51feSCy Schubert 49133b9b51feSCy Schubert if ((nflags & IPN_TCPUDP)) 49143b9b51feSCy Schubert tcp = fin->fin_dp; 49153b9b51feSCy Schubert } 49163b9b51feSCy Schubert 49173b9b51feSCy Schubert ipa = fin->fin_saddr; 49183b9b51feSCy Schubert 49193b9b51feSCy Schubert READ_ENTER(&softc->ipf_nat); 49203b9b51feSCy Schubert 49213b9b51feSCy Schubert if ((fin->fin_p == IPPROTO_ICMP) && !(nflags & IPN_ICMPQUERY) && 49223b9b51feSCy Schubert (nat = ipf_nat_icmperror(fin, &nflags, NAT_OUTBOUND))) 49233b9b51feSCy Schubert /*EMPTY*/; 49243b9b51feSCy Schubert else if ((fin->fin_flx & FI_FRAG) && (nat = ipf_frag_natknown(fin))) 49253b9b51feSCy Schubert natadd = 0; 49263b9b51feSCy Schubert else if ((nat = ipf_nat_outlookup(fin, nflags|NAT_SEARCH, 49273b9b51feSCy Schubert (u_int)fin->fin_p, fin->fin_src, 49283b9b51feSCy Schubert fin->fin_dst))) { 49293b9b51feSCy Schubert nflags = nat->nat_flags; 49303b9b51feSCy Schubert } else if (fin->fin_off == 0) { 49313b9b51feSCy Schubert u_32_t hv, msk, nmsk = 0; 49323b9b51feSCy Schubert 49333b9b51feSCy Schubert /* 49343b9b51feSCy Schubert * If there is no current entry in the nat table for this IP#, 49353b9b51feSCy Schubert * create one for it (if there is a matching rule). 49363b9b51feSCy Schubert */ 49373b9b51feSCy Schubert maskloop: 49383b9b51feSCy Schubert msk = softn->ipf_nat_map_active_masks[nmsk]; 49393b9b51feSCy Schubert iph = ipa & msk; 49403b9b51feSCy Schubert hv = NAT_HASH_FN(iph, 0, softn->ipf_nat_maprules_sz); 49413b9b51feSCy Schubert retry_roundrobin: 49423b9b51feSCy Schubert for (np = softn->ipf_nat_map_rules[hv]; np; np = npnext) { 49433b9b51feSCy Schubert npnext = np->in_mnext; 49443b9b51feSCy Schubert if ((np->in_ifps[1] && (np->in_ifps[1] != ifp))) 49453b9b51feSCy Schubert continue; 49463b9b51feSCy Schubert if (np->in_v[0] != 4) 49473b9b51feSCy Schubert continue; 49483b9b51feSCy Schubert if (np->in_pr[1] && (np->in_pr[1] != fin->fin_p)) 49493b9b51feSCy Schubert continue; 49503b9b51feSCy Schubert if ((np->in_flags & IPN_RF) && 49513b9b51feSCy Schubert !(np->in_flags & nflags)) 49523b9b51feSCy Schubert continue; 49533b9b51feSCy Schubert if (np->in_flags & IPN_FILTER) { 49543b9b51feSCy Schubert switch (ipf_nat_match(fin, np)) 49553b9b51feSCy Schubert { 49563b9b51feSCy Schubert case 0 : 49573b9b51feSCy Schubert continue; 49583b9b51feSCy Schubert case -1 : 49593b9b51feSCy Schubert rval = -3; 49603b9b51feSCy Schubert goto outmatchfail; 49613b9b51feSCy Schubert case 1 : 49623b9b51feSCy Schubert default : 49633b9b51feSCy Schubert break; 49643b9b51feSCy Schubert } 49653b9b51feSCy Schubert } else if ((ipa & np->in_osrcmsk) != np->in_osrcaddr) 49663b9b51feSCy Schubert continue; 49673b9b51feSCy Schubert 49683b9b51feSCy Schubert if ((fr != NULL) && 49693b9b51feSCy Schubert !ipf_matchtag(&np->in_tag, &fr->fr_nattag)) 49703b9b51feSCy Schubert continue; 49713b9b51feSCy Schubert 49723b9b51feSCy Schubert if (np->in_plabel != -1) { 49733b9b51feSCy Schubert if (((np->in_flags & IPN_FILTER) == 0) && 49743b9b51feSCy Schubert (np->in_odport != fin->fin_data[1])) 49753b9b51feSCy Schubert continue; 49763b9b51feSCy Schubert if (ipf_proxy_ok(fin, tcp, np) == 0) 49773b9b51feSCy Schubert continue; 49783b9b51feSCy Schubert } 49793b9b51feSCy Schubert 49803b9b51feSCy Schubert if (np->in_flags & IPN_NO) { 49813b9b51feSCy Schubert np->in_hits++; 49823b9b51feSCy Schubert break; 49833b9b51feSCy Schubert } 49843b9b51feSCy Schubert MUTEX_ENTER(&softn->ipf_nat_new); 49853b9b51feSCy Schubert /* 49863b9b51feSCy Schubert * If we've matched a round-robin rule but it has 49873b9b51feSCy Schubert * moved in the list since we got it, start over as 49883b9b51feSCy Schubert * this is now no longer correct. 49893b9b51feSCy Schubert */ 49903b9b51feSCy Schubert if (npnext != np->in_mnext) { 49913b9b51feSCy Schubert if ((np->in_flags & IPN_ROUNDR) != 0) { 49923b9b51feSCy Schubert MUTEX_EXIT(&softn->ipf_nat_new); 49933b9b51feSCy Schubert goto retry_roundrobin; 49943b9b51feSCy Schubert } 49953b9b51feSCy Schubert npnext = np->in_mnext; 49963b9b51feSCy Schubert } 49973b9b51feSCy Schubert 49983b9b51feSCy Schubert nat = ipf_nat_add(fin, np, NULL, nflags, NAT_OUTBOUND); 49993b9b51feSCy Schubert MUTEX_EXIT(&softn->ipf_nat_new); 50003b9b51feSCy Schubert if (nat != NULL) { 50013b9b51feSCy Schubert natfailed = 0; 50023b9b51feSCy Schubert break; 50033b9b51feSCy Schubert } 50043b9b51feSCy Schubert natfailed = -2; 50053b9b51feSCy Schubert } 50063b9b51feSCy Schubert if ((np == NULL) && (nmsk < softn->ipf_nat_map_max)) { 50073b9b51feSCy Schubert nmsk++; 50083b9b51feSCy Schubert goto maskloop; 50093b9b51feSCy Schubert } 50103b9b51feSCy Schubert } 50113b9b51feSCy Schubert 50123b9b51feSCy Schubert if (nat != NULL) { 50133b9b51feSCy Schubert rval = ipf_nat_out(fin, nat, natadd, nflags); 50143b9b51feSCy Schubert if (rval == 1) { 50153b9b51feSCy Schubert MUTEX_ENTER(&nat->nat_lock); 50163b9b51feSCy Schubert ipf_nat_update(fin, nat); 50173b9b51feSCy Schubert nat->nat_bytes[1] += fin->fin_plen; 50183b9b51feSCy Schubert nat->nat_pkts[1]++; 50193b9b51feSCy Schubert fin->fin_pktnum = nat->nat_pkts[1]; 50203b9b51feSCy Schubert MUTEX_EXIT(&nat->nat_lock); 50213b9b51feSCy Schubert } 50223b9b51feSCy Schubert } else 50233b9b51feSCy Schubert rval = natfailed; 50243b9b51feSCy Schubert outmatchfail: 50253b9b51feSCy Schubert RWLOCK_EXIT(&softc->ipf_nat); 50263b9b51feSCy Schubert 50273b9b51feSCy Schubert switch (rval) 50283b9b51feSCy Schubert { 50293b9b51feSCy Schubert case -3 : 50303b9b51feSCy Schubert /* ipf_nat_match() failure */ 50313b9b51feSCy Schubert /* FALLTHROUGH */ 50323b9b51feSCy Schubert case -2 : 50333b9b51feSCy Schubert /* retry_roundrobin loop failure */ 50343b9b51feSCy Schubert /* FALLTHROUGH */ 50353b9b51feSCy Schubert case -1 : 50363b9b51feSCy Schubert /* proxy failure detected by ipf_nat_out() */ 50373b9b51feSCy Schubert if (passp != NULL) { 50383b9b51feSCy Schubert DT2(frb_natv4out, fr_info_t *, fin, int, rval); 50393b9b51feSCy Schubert NBUMPSIDED(1, ns_drop); 50403b9b51feSCy Schubert *passp = FR_BLOCK; 50413b9b51feSCy Schubert fin->fin_reason = FRB_NATV4; 50423b9b51feSCy Schubert } 50433b9b51feSCy Schubert fin->fin_flx |= FI_BADNAT; 50443b9b51feSCy Schubert NBUMPSIDED(1, ns_badnat); 50453b9b51feSCy Schubert rval = -1; /* We only return -1 on error. */ 50463b9b51feSCy Schubert break; 50473b9b51feSCy Schubert case 0 : 50483b9b51feSCy Schubert NBUMPSIDE(1, ns_ignored); 50493b9b51feSCy Schubert break; 50503b9b51feSCy Schubert case 1 : 50513b9b51feSCy Schubert NBUMPSIDE(1, ns_translated); 50523b9b51feSCy Schubert break; 50533b9b51feSCy Schubert } 50543b9b51feSCy Schubert fin->fin_ifp = sifp; 50553b9b51feSCy Schubert return rval; 50563b9b51feSCy Schubert } 50573b9b51feSCy Schubert 50583b9b51feSCy Schubert /* ------------------------------------------------------------------------ */ 50593b9b51feSCy Schubert /* Function: ipf_nat_out */ 50603b9b51feSCy Schubert /* Returns: int - -1 == packet failed NAT checks so block it, */ 50613b9b51feSCy Schubert /* 1 == packet was successfully translated. */ 50623b9b51feSCy Schubert /* Parameters: fin(I) - pointer to packet information */ 50633b9b51feSCy Schubert /* nat(I) - pointer to NAT structure */ 50643b9b51feSCy Schubert /* natadd(I) - flag indicating if it is safe to add frag cache */ 50653b9b51feSCy Schubert /* nflags(I) - NAT flags set for this packet */ 50663b9b51feSCy Schubert /* */ 50673b9b51feSCy Schubert /* Translate a packet coming "out" on an interface. */ 50683b9b51feSCy Schubert /* ------------------------------------------------------------------------ */ 50693b9b51feSCy Schubert int 50703b9b51feSCy Schubert ipf_nat_out(fin, nat, natadd, nflags) 50713b9b51feSCy Schubert fr_info_t *fin; 50723b9b51feSCy Schubert nat_t *nat; 50733b9b51feSCy Schubert int natadd; 50743b9b51feSCy Schubert u_32_t nflags; 50753b9b51feSCy Schubert { 50763b9b51feSCy Schubert ipf_main_softc_t *softc = fin->fin_main_soft; 50773b9b51feSCy Schubert ipf_nat_softc_t *softn = softc->ipf_nat_soft; 50783b9b51feSCy Schubert icmphdr_t *icmp; 50793b9b51feSCy Schubert tcphdr_t *tcp; 50803b9b51feSCy Schubert ipnat_t *np; 50813b9b51feSCy Schubert int skip; 50823b9b51feSCy Schubert int i; 50833b9b51feSCy Schubert 50843b9b51feSCy Schubert tcp = NULL; 50853b9b51feSCy Schubert icmp = NULL; 50863b9b51feSCy Schubert np = nat->nat_ptr; 50873b9b51feSCy Schubert 50883b9b51feSCy Schubert if ((natadd != 0) && (fin->fin_flx & FI_FRAG) && (np != NULL)) 50893b9b51feSCy Schubert (void) ipf_frag_natnew(softc, fin, 0, nat); 50903b9b51feSCy Schubert 50913b9b51feSCy Schubert /* 50923b9b51feSCy Schubert * Fix up checksums, not by recalculating them, but 50933b9b51feSCy Schubert * simply computing adjustments. 50943b9b51feSCy Schubert * This is only done for STREAMS based IP implementations where the 50953b9b51feSCy Schubert * checksum has already been calculated by IP. In all other cases, 50963b9b51feSCy Schubert * IPFilter is called before the checksum needs calculating so there 50973b9b51feSCy Schubert * is no call to modify whatever is in the header now. 50983b9b51feSCy Schubert */ 50993b9b51feSCy Schubert if (nflags == IPN_ICMPERR) { 51003b9b51feSCy Schubert u_32_t s1, s2, sumd, msumd; 51013b9b51feSCy Schubert 51023b9b51feSCy Schubert s1 = LONG_SUM(ntohl(fin->fin_saddr)); 51033b9b51feSCy Schubert if (nat->nat_dir == NAT_OUTBOUND) { 51043b9b51feSCy Schubert s2 = LONG_SUM(ntohl(nat->nat_nsrcaddr)); 51053b9b51feSCy Schubert } else { 51063b9b51feSCy Schubert s2 = LONG_SUM(ntohl(nat->nat_odstaddr)); 51073b9b51feSCy Schubert } 51083b9b51feSCy Schubert CALC_SUMD(s1, s2, sumd); 51093b9b51feSCy Schubert msumd = sumd; 51103b9b51feSCy Schubert 51113b9b51feSCy Schubert s1 = LONG_SUM(ntohl(fin->fin_daddr)); 51123b9b51feSCy Schubert if (nat->nat_dir == NAT_OUTBOUND) { 51133b9b51feSCy Schubert s2 = LONG_SUM(ntohl(nat->nat_ndstaddr)); 51143b9b51feSCy Schubert } else { 51153b9b51feSCy Schubert s2 = LONG_SUM(ntohl(nat->nat_osrcaddr)); 51163b9b51feSCy Schubert } 51173b9b51feSCy Schubert CALC_SUMD(s1, s2, sumd); 51183b9b51feSCy Schubert msumd += sumd; 51193b9b51feSCy Schubert 51203b9b51feSCy Schubert ipf_fix_outcksum(0, &fin->fin_ip->ip_sum, msumd, 0); 51213b9b51feSCy Schubert } 51223b9b51feSCy Schubert #if !defined(_KERNEL) || SOLARIS || \ 51233b9b51feSCy Schubert defined(BRIDGE_IPF) || defined(__FreeBSD__) 51243b9b51feSCy Schubert else { 51253b9b51feSCy Schubert /* 51263b9b51feSCy Schubert * Strictly speaking, this isn't necessary on BSD 51273b9b51feSCy Schubert * kernels because they do checksum calculation after 51283b9b51feSCy Schubert * this code has run BUT if ipfilter is being used 51293b9b51feSCy Schubert * to do NAT as a bridge, that code doesn't exist. 51303b9b51feSCy Schubert */ 51313b9b51feSCy Schubert switch (nat->nat_dir) 51323b9b51feSCy Schubert { 51333b9b51feSCy Schubert case NAT_OUTBOUND : 51343b9b51feSCy Schubert ipf_fix_outcksum(fin->fin_cksum & FI_CK_L4PART, 51353b9b51feSCy Schubert &fin->fin_ip->ip_sum, 51363b9b51feSCy Schubert nat->nat_ipsumd, 0); 51373b9b51feSCy Schubert break; 51383b9b51feSCy Schubert 51393b9b51feSCy Schubert case NAT_INBOUND : 51403b9b51feSCy Schubert ipf_fix_incksum(fin->fin_cksum & FI_CK_L4PART, 51413b9b51feSCy Schubert &fin->fin_ip->ip_sum, 51423b9b51feSCy Schubert nat->nat_ipsumd, 0); 51433b9b51feSCy Schubert break; 51443b9b51feSCy Schubert 51453b9b51feSCy Schubert default : 51463b9b51feSCy Schubert break; 51473b9b51feSCy Schubert } 51483b9b51feSCy Schubert } 51493b9b51feSCy Schubert #endif 51503b9b51feSCy Schubert 51513b9b51feSCy Schubert /* 51523b9b51feSCy Schubert * Address assignment is after the checksum modification because 51533b9b51feSCy Schubert * we are using the address in the packet for determining the 51543b9b51feSCy Schubert * correct checksum offset (the ICMP error could be coming from 51553b9b51feSCy Schubert * anyone...) 51563b9b51feSCy Schubert */ 51573b9b51feSCy Schubert switch (nat->nat_dir) 51583b9b51feSCy Schubert { 51593b9b51feSCy Schubert case NAT_OUTBOUND : 51603b9b51feSCy Schubert fin->fin_ip->ip_src = nat->nat_nsrcip; 51613b9b51feSCy Schubert fin->fin_saddr = nat->nat_nsrcaddr; 51623b9b51feSCy Schubert fin->fin_ip->ip_dst = nat->nat_ndstip; 51633b9b51feSCy Schubert fin->fin_daddr = nat->nat_ndstaddr; 51643b9b51feSCy Schubert break; 51653b9b51feSCy Schubert 51663b9b51feSCy Schubert case NAT_INBOUND : 51673b9b51feSCy Schubert fin->fin_ip->ip_src = nat->nat_odstip; 51683b9b51feSCy Schubert fin->fin_saddr = nat->nat_ndstaddr; 51693b9b51feSCy Schubert fin->fin_ip->ip_dst = nat->nat_osrcip; 51703b9b51feSCy Schubert fin->fin_daddr = nat->nat_nsrcaddr; 51713b9b51feSCy Schubert break; 51723b9b51feSCy Schubert 51733b9b51feSCy Schubert case NAT_DIVERTIN : 51743b9b51feSCy Schubert { 51753b9b51feSCy Schubert mb_t *m; 51763b9b51feSCy Schubert 51773b9b51feSCy Schubert skip = ipf_nat_decap(fin, nat); 51783b9b51feSCy Schubert if (skip <= 0) { 51793b9b51feSCy Schubert NBUMPSIDED(1, ns_decap_fail); 51803b9b51feSCy Schubert return -1; 51813b9b51feSCy Schubert } 51823b9b51feSCy Schubert 51833b9b51feSCy Schubert m = fin->fin_m; 51843b9b51feSCy Schubert 51853b9b51feSCy Schubert #if SOLARIS && defined(_KERNEL) 51863b9b51feSCy Schubert m->b_rptr += skip; 51873b9b51feSCy Schubert #else 51883b9b51feSCy Schubert m->m_data += skip; 51893b9b51feSCy Schubert m->m_len -= skip; 51903b9b51feSCy Schubert 51913b9b51feSCy Schubert # ifdef M_PKTHDR 51923b9b51feSCy Schubert if (m->m_flags & M_PKTHDR) 51933b9b51feSCy Schubert m->m_pkthdr.len -= skip; 51943b9b51feSCy Schubert # endif 51953b9b51feSCy Schubert #endif 51963b9b51feSCy Schubert 51973b9b51feSCy Schubert MUTEX_ENTER(&nat->nat_lock); 51983b9b51feSCy Schubert ipf_nat_update(fin, nat); 51993b9b51feSCy Schubert MUTEX_EXIT(&nat->nat_lock); 52003b9b51feSCy Schubert fin->fin_flx |= FI_NATED; 52013b9b51feSCy Schubert if (np != NULL && np->in_tag.ipt_num[0] != 0) 52023b9b51feSCy Schubert fin->fin_nattag = &np->in_tag; 52033b9b51feSCy Schubert return 1; 52043b9b51feSCy Schubert /* NOTREACHED */ 52053b9b51feSCy Schubert } 52063b9b51feSCy Schubert 52073b9b51feSCy Schubert case NAT_DIVERTOUT : 52083b9b51feSCy Schubert { 52093b9b51feSCy Schubert u_32_t s1, s2, sumd; 52103b9b51feSCy Schubert udphdr_t *uh; 52113b9b51feSCy Schubert ip_t *ip; 52123b9b51feSCy Schubert mb_t *m; 52133b9b51feSCy Schubert 52143b9b51feSCy Schubert m = M_DUP(np->in_divmp); 52153b9b51feSCy Schubert if (m == NULL) { 52163b9b51feSCy Schubert NBUMPSIDED(1, ns_divert_dup); 52173b9b51feSCy Schubert return -1; 52183b9b51feSCy Schubert } 52193b9b51feSCy Schubert 52203b9b51feSCy Schubert ip = MTOD(m, ip_t *); 52213b9b51feSCy Schubert ip_fillid(ip); 52223b9b51feSCy Schubert s2 = ntohs(ip->ip_id); 52233b9b51feSCy Schubert 52243b9b51feSCy Schubert s1 = ip->ip_len; 52253b9b51feSCy Schubert ip->ip_len = ntohs(ip->ip_len); 52263b9b51feSCy Schubert ip->ip_len += fin->fin_plen; 52273b9b51feSCy Schubert ip->ip_len = htons(ip->ip_len); 52283b9b51feSCy Schubert s2 += ntohs(ip->ip_len); 52293b9b51feSCy Schubert CALC_SUMD(s1, s2, sumd); 52303b9b51feSCy Schubert 52313b9b51feSCy Schubert uh = (udphdr_t *)(ip + 1); 52323b9b51feSCy Schubert uh->uh_ulen += fin->fin_plen; 52333b9b51feSCy Schubert uh->uh_ulen = htons(uh->uh_ulen); 52343b9b51feSCy Schubert #if !defined(_KERNEL) || SOLARIS || \ 52353b9b51feSCy Schubert defined(BRIDGE_IPF) || defined(__FreeBSD__) 52363b9b51feSCy Schubert ipf_fix_outcksum(0, &ip->ip_sum, sumd, 0); 52373b9b51feSCy Schubert #endif 52383b9b51feSCy Schubert 52393b9b51feSCy Schubert PREP_MB_T(fin, m); 52403b9b51feSCy Schubert 52413b9b51feSCy Schubert fin->fin_src = ip->ip_src; 52423b9b51feSCy Schubert fin->fin_dst = ip->ip_dst; 52433b9b51feSCy Schubert fin->fin_ip = ip; 52443b9b51feSCy Schubert fin->fin_plen += sizeof(ip_t) + 8; /* UDP + IPv4 hdr */ 52453b9b51feSCy Schubert fin->fin_dlen += sizeof(ip_t) + 8; /* UDP + IPv4 hdr */ 52463b9b51feSCy Schubert 52473b9b51feSCy Schubert nflags &= ~IPN_TCPUDPICMP; 52483b9b51feSCy Schubert 52493b9b51feSCy Schubert break; 52503b9b51feSCy Schubert } 52513b9b51feSCy Schubert 52523b9b51feSCy Schubert default : 52533b9b51feSCy Schubert break; 52543b9b51feSCy Schubert } 52553b9b51feSCy Schubert 52563b9b51feSCy Schubert if (!(fin->fin_flx & FI_SHORT) && (fin->fin_off == 0)) { 52573b9b51feSCy Schubert u_short *csump; 52583b9b51feSCy Schubert 52593b9b51feSCy Schubert if ((nat->nat_nsport != 0) && (nflags & IPN_TCPUDP)) { 52603b9b51feSCy Schubert tcp = fin->fin_dp; 52613b9b51feSCy Schubert 52623b9b51feSCy Schubert switch (nat->nat_dir) 52633b9b51feSCy Schubert { 52643b9b51feSCy Schubert case NAT_OUTBOUND : 52653b9b51feSCy Schubert tcp->th_sport = nat->nat_nsport; 52663b9b51feSCy Schubert fin->fin_data[0] = ntohs(nat->nat_nsport); 52673b9b51feSCy Schubert tcp->th_dport = nat->nat_ndport; 52683b9b51feSCy Schubert fin->fin_data[1] = ntohs(nat->nat_ndport); 52693b9b51feSCy Schubert break; 52703b9b51feSCy Schubert 52713b9b51feSCy Schubert case NAT_INBOUND : 52723b9b51feSCy Schubert tcp->th_sport = nat->nat_odport; 52733b9b51feSCy Schubert fin->fin_data[0] = ntohs(nat->nat_odport); 52743b9b51feSCy Schubert tcp->th_dport = nat->nat_osport; 52753b9b51feSCy Schubert fin->fin_data[1] = ntohs(nat->nat_osport); 52763b9b51feSCy Schubert break; 52773b9b51feSCy Schubert } 52783b9b51feSCy Schubert } 52793b9b51feSCy Schubert 52803b9b51feSCy Schubert if ((nat->nat_nsport != 0) && (nflags & IPN_ICMPQUERY)) { 52813b9b51feSCy Schubert icmp = fin->fin_dp; 52823b9b51feSCy Schubert icmp->icmp_id = nat->nat_nicmpid; 52833b9b51feSCy Schubert } 52843b9b51feSCy Schubert 52853b9b51feSCy Schubert csump = ipf_nat_proto(fin, nat, nflags); 52863b9b51feSCy Schubert 52873b9b51feSCy Schubert /* 52883b9b51feSCy Schubert * The above comments do not hold for layer 4 (or higher) 52893b9b51feSCy Schubert * checksums... 52903b9b51feSCy Schubert */ 52913b9b51feSCy Schubert if (csump != NULL) { 52923b9b51feSCy Schubert if (nat->nat_dir == NAT_OUTBOUND) 52933b9b51feSCy Schubert ipf_fix_outcksum(fin->fin_cksum, csump, 52943b9b51feSCy Schubert nat->nat_sumd[0], 52953b9b51feSCy Schubert nat->nat_sumd[1] + 52963b9b51feSCy Schubert fin->fin_dlen); 52973b9b51feSCy Schubert else 52983b9b51feSCy Schubert ipf_fix_incksum(fin->fin_cksum, csump, 52993b9b51feSCy Schubert nat->nat_sumd[0], 53003b9b51feSCy Schubert nat->nat_sumd[1] + 53013b9b51feSCy Schubert fin->fin_dlen); 53023b9b51feSCy Schubert } 53033b9b51feSCy Schubert } 53043b9b51feSCy Schubert 53053b9b51feSCy Schubert ipf_sync_update(softc, SMC_NAT, fin, nat->nat_sync); 53063b9b51feSCy Schubert /* ------------------------------------------------------------- */ 53073b9b51feSCy Schubert /* A few quick notes: */ 53083b9b51feSCy Schubert /* Following are test conditions prior to calling the */ 53093b9b51feSCy Schubert /* ipf_proxy_check routine. */ 53103b9b51feSCy Schubert /* */ 53113b9b51feSCy Schubert /* A NULL tcp indicates a non TCP/UDP packet. When dealing */ 53123b9b51feSCy Schubert /* with a redirect rule, we attempt to match the packet's */ 53133b9b51feSCy Schubert /* source port against in_dport, otherwise we'd compare the */ 53143b9b51feSCy Schubert /* packet's destination. */ 53153b9b51feSCy Schubert /* ------------------------------------------------------------- */ 53163b9b51feSCy Schubert if ((np != NULL) && (np->in_apr != NULL)) { 53173b9b51feSCy Schubert i = ipf_proxy_check(fin, nat); 53183b9b51feSCy Schubert if (i == -1) { 53193b9b51feSCy Schubert NBUMPSIDED(1, ns_ipf_proxy_fail); 53203b9b51feSCy Schubert } 53213b9b51feSCy Schubert } else { 53223b9b51feSCy Schubert i = 1; 53233b9b51feSCy Schubert } 53243b9b51feSCy Schubert fin->fin_flx |= FI_NATED; 53253b9b51feSCy Schubert return i; 53263b9b51feSCy Schubert } 53273b9b51feSCy Schubert 53283b9b51feSCy Schubert 53293b9b51feSCy Schubert /* ------------------------------------------------------------------------ */ 53303b9b51feSCy Schubert /* Function: ipf_nat_checkin */ 53313b9b51feSCy Schubert /* Returns: int - -1 == packet failed NAT checks so block it, */ 53323b9b51feSCy Schubert /* 0 == no packet translation occurred, */ 53333b9b51feSCy Schubert /* 1 == packet was successfully translated. */ 53343b9b51feSCy Schubert /* Parameters: fin(I) - pointer to packet information */ 53353b9b51feSCy Schubert /* passp(I) - pointer to filtering result flags */ 53363b9b51feSCy Schubert /* */ 53373b9b51feSCy Schubert /* Check to see if an incoming packet should be changed. ICMP packets are */ 53383b9b51feSCy Schubert /* first checked to see if they match an existing entry (if an error), */ 53393b9b51feSCy Schubert /* otherwise a search of the current NAT table is made. If neither results */ 53403b9b51feSCy Schubert /* in a match then a search for a matching NAT rule is made. Create a new */ 53413b9b51feSCy Schubert /* NAT entry if a we matched a NAT rule. Lastly, actually change the */ 53423b9b51feSCy Schubert /* packet header(s) as required. */ 53433b9b51feSCy Schubert /* ------------------------------------------------------------------------ */ 53443b9b51feSCy Schubert int 53453b9b51feSCy Schubert ipf_nat_checkin(fin, passp) 53463b9b51feSCy Schubert fr_info_t *fin; 53473b9b51feSCy Schubert u_32_t *passp; 53483b9b51feSCy Schubert { 53493b9b51feSCy Schubert ipf_main_softc_t *softc; 53503b9b51feSCy Schubert ipf_nat_softc_t *softn; 53513b9b51feSCy Schubert u_int nflags, natadd; 53523b9b51feSCy Schubert ipnat_t *np, *npnext; 53533b9b51feSCy Schubert int rval, natfailed; 53543b9b51feSCy Schubert struct ifnet *ifp; 53553b9b51feSCy Schubert struct in_addr in; 53563b9b51feSCy Schubert icmphdr_t *icmp; 53573b9b51feSCy Schubert tcphdr_t *tcp; 53583b9b51feSCy Schubert u_short dport; 53593b9b51feSCy Schubert nat_t *nat; 53603b9b51feSCy Schubert u_32_t iph; 53613b9b51feSCy Schubert 53623b9b51feSCy Schubert softc = fin->fin_main_soft; 53633b9b51feSCy Schubert softn = softc->ipf_nat_soft; 53643b9b51feSCy Schubert 53653b9b51feSCy Schubert if (softn->ipf_nat_lock != 0) 53663b9b51feSCy Schubert return 0; 53673b9b51feSCy Schubert if (softn->ipf_nat_stats.ns_rules == 0 && 53683b9b51feSCy Schubert softn->ipf_nat_instances == NULL) 53693b9b51feSCy Schubert return 0; 53703b9b51feSCy Schubert 53713b9b51feSCy Schubert tcp = NULL; 53723b9b51feSCy Schubert icmp = NULL; 53733b9b51feSCy Schubert dport = 0; 53743b9b51feSCy Schubert natadd = 1; 53753b9b51feSCy Schubert nflags = 0; 53763b9b51feSCy Schubert natfailed = 0; 53773b9b51feSCy Schubert ifp = fin->fin_ifp; 53783b9b51feSCy Schubert 53793b9b51feSCy Schubert if (!(fin->fin_flx & FI_SHORT) && (fin->fin_off == 0)) { 53803b9b51feSCy Schubert switch (fin->fin_p) 53813b9b51feSCy Schubert { 53823b9b51feSCy Schubert case IPPROTO_TCP : 53833b9b51feSCy Schubert nflags = IPN_TCP; 53843b9b51feSCy Schubert break; 53853b9b51feSCy Schubert case IPPROTO_UDP : 53863b9b51feSCy Schubert nflags = IPN_UDP; 53873b9b51feSCy Schubert break; 53883b9b51feSCy Schubert case IPPROTO_ICMP : 53893b9b51feSCy Schubert icmp = fin->fin_dp; 53903b9b51feSCy Schubert 53913b9b51feSCy Schubert /* 53923b9b51feSCy Schubert * This is an incoming packet, so the destination is 53933b9b51feSCy Schubert * the icmp_id and the source port equals 0 53943b9b51feSCy Schubert */ 53953b9b51feSCy Schubert if ((fin->fin_flx & FI_ICMPQUERY) != 0) { 53963b9b51feSCy Schubert nflags = IPN_ICMPQUERY; 53973b9b51feSCy Schubert dport = icmp->icmp_id; 53983b9b51feSCy Schubert } break; 53993b9b51feSCy Schubert default : 54003b9b51feSCy Schubert break; 54013b9b51feSCy Schubert } 54023b9b51feSCy Schubert 54033b9b51feSCy Schubert if ((nflags & IPN_TCPUDP)) { 54043b9b51feSCy Schubert tcp = fin->fin_dp; 54053b9b51feSCy Schubert dport = fin->fin_data[1]; 54063b9b51feSCy Schubert } 54073b9b51feSCy Schubert } 54083b9b51feSCy Schubert 54093b9b51feSCy Schubert in = fin->fin_dst; 54103b9b51feSCy Schubert 54113b9b51feSCy Schubert READ_ENTER(&softc->ipf_nat); 54123b9b51feSCy Schubert 54133b9b51feSCy Schubert if ((fin->fin_p == IPPROTO_ICMP) && !(nflags & IPN_ICMPQUERY) && 54143b9b51feSCy Schubert (nat = ipf_nat_icmperror(fin, &nflags, NAT_INBOUND))) 54153b9b51feSCy Schubert /*EMPTY*/; 54163b9b51feSCy Schubert else if ((fin->fin_flx & FI_FRAG) && (nat = ipf_frag_natknown(fin))) 54173b9b51feSCy Schubert natadd = 0; 54183b9b51feSCy Schubert else if ((nat = ipf_nat_inlookup(fin, nflags|NAT_SEARCH, 54193b9b51feSCy Schubert (u_int)fin->fin_p, 54203b9b51feSCy Schubert fin->fin_src, in))) { 54213b9b51feSCy Schubert nflags = nat->nat_flags; 54223b9b51feSCy Schubert } else if (fin->fin_off == 0) { 54233b9b51feSCy Schubert u_32_t hv, msk, rmsk = 0; 54243b9b51feSCy Schubert 54253b9b51feSCy Schubert /* 54263b9b51feSCy Schubert * If there is no current entry in the nat table for this IP#, 54273b9b51feSCy Schubert * create one for it (if there is a matching rule). 54283b9b51feSCy Schubert */ 54293b9b51feSCy Schubert maskloop: 54303b9b51feSCy Schubert msk = softn->ipf_nat_rdr_active_masks[rmsk]; 54313b9b51feSCy Schubert iph = in.s_addr & msk; 54323b9b51feSCy Schubert hv = NAT_HASH_FN(iph, 0, softn->ipf_nat_rdrrules_sz); 54333b9b51feSCy Schubert retry_roundrobin: 54343b9b51feSCy Schubert /* TRACE (iph,msk,rmsk,hv,softn->ipf_nat_rdrrules_sz) */ 54353b9b51feSCy Schubert for (np = softn->ipf_nat_rdr_rules[hv]; np; np = npnext) { 54363b9b51feSCy Schubert npnext = np->in_rnext; 54373b9b51feSCy Schubert if (np->in_ifps[0] && (np->in_ifps[0] != ifp)) 54383b9b51feSCy Schubert continue; 54393b9b51feSCy Schubert if (np->in_v[0] != 4) 54403b9b51feSCy Schubert continue; 54413b9b51feSCy Schubert if (np->in_pr[0] && (np->in_pr[0] != fin->fin_p)) 54423b9b51feSCy Schubert continue; 54433b9b51feSCy Schubert if ((np->in_flags & IPN_RF) && !(np->in_flags & nflags)) 54443b9b51feSCy Schubert continue; 54453b9b51feSCy Schubert if (np->in_flags & IPN_FILTER) { 54463b9b51feSCy Schubert switch (ipf_nat_match(fin, np)) 54473b9b51feSCy Schubert { 54483b9b51feSCy Schubert case 0 : 54493b9b51feSCy Schubert continue; 54503b9b51feSCy Schubert case -1 : 54513b9b51feSCy Schubert rval = -3; 54523b9b51feSCy Schubert goto inmatchfail; 54533b9b51feSCy Schubert case 1 : 54543b9b51feSCy Schubert default : 54553b9b51feSCy Schubert break; 54563b9b51feSCy Schubert } 54573b9b51feSCy Schubert } else { 54583b9b51feSCy Schubert if ((in.s_addr & np->in_odstmsk) != 54593b9b51feSCy Schubert np->in_odstaddr) 54603b9b51feSCy Schubert continue; 54613b9b51feSCy Schubert if (np->in_odport && 54623b9b51feSCy Schubert ((np->in_dtop < dport) || 54633b9b51feSCy Schubert (dport < np->in_odport))) 54643b9b51feSCy Schubert continue; 54653b9b51feSCy Schubert } 54663b9b51feSCy Schubert 54673b9b51feSCy Schubert if (np->in_plabel != -1) { 54683b9b51feSCy Schubert if (!ipf_proxy_ok(fin, tcp, np)) { 54693b9b51feSCy Schubert continue; 54703b9b51feSCy Schubert } 54713b9b51feSCy Schubert } 54723b9b51feSCy Schubert 54733b9b51feSCy Schubert if (np->in_flags & IPN_NO) { 54743b9b51feSCy Schubert np->in_hits++; 54753b9b51feSCy Schubert break; 54763b9b51feSCy Schubert } 54773b9b51feSCy Schubert 54783b9b51feSCy Schubert MUTEX_ENTER(&softn->ipf_nat_new); 54793b9b51feSCy Schubert /* 54803b9b51feSCy Schubert * If we've matched a round-robin rule but it has 54813b9b51feSCy Schubert * moved in the list since we got it, start over as 54823b9b51feSCy Schubert * this is now no longer correct. 54833b9b51feSCy Schubert */ 54843b9b51feSCy Schubert if (npnext != np->in_rnext) { 54853b9b51feSCy Schubert if ((np->in_flags & IPN_ROUNDR) != 0) { 54863b9b51feSCy Schubert MUTEX_EXIT(&softn->ipf_nat_new); 54873b9b51feSCy Schubert goto retry_roundrobin; 54883b9b51feSCy Schubert } 54893b9b51feSCy Schubert npnext = np->in_rnext; 54903b9b51feSCy Schubert } 54913b9b51feSCy Schubert 54923b9b51feSCy Schubert nat = ipf_nat_add(fin, np, NULL, nflags, NAT_INBOUND); 54933b9b51feSCy Schubert MUTEX_EXIT(&softn->ipf_nat_new); 54943b9b51feSCy Schubert if (nat != NULL) { 54953b9b51feSCy Schubert natfailed = 0; 54963b9b51feSCy Schubert break; 54973b9b51feSCy Schubert } 54983b9b51feSCy Schubert natfailed = -2; 54993b9b51feSCy Schubert } 55003b9b51feSCy Schubert if ((np == NULL) && (rmsk < softn->ipf_nat_rdr_max)) { 55013b9b51feSCy Schubert rmsk++; 55023b9b51feSCy Schubert goto maskloop; 55033b9b51feSCy Schubert } 55043b9b51feSCy Schubert } 55053b9b51feSCy Schubert 55063b9b51feSCy Schubert if (nat != NULL) { 55073b9b51feSCy Schubert rval = ipf_nat_in(fin, nat, natadd, nflags); 55083b9b51feSCy Schubert if (rval == 1) { 55093b9b51feSCy Schubert MUTEX_ENTER(&nat->nat_lock); 55103b9b51feSCy Schubert ipf_nat_update(fin, nat); 55113b9b51feSCy Schubert nat->nat_bytes[0] += fin->fin_plen; 55123b9b51feSCy Schubert nat->nat_pkts[0]++; 55133b9b51feSCy Schubert fin->fin_pktnum = nat->nat_pkts[0]; 55143b9b51feSCy Schubert MUTEX_EXIT(&nat->nat_lock); 55153b9b51feSCy Schubert } 55163b9b51feSCy Schubert } else 55173b9b51feSCy Schubert rval = natfailed; 55183b9b51feSCy Schubert inmatchfail: 55193b9b51feSCy Schubert RWLOCK_EXIT(&softc->ipf_nat); 55203b9b51feSCy Schubert 55213b9b51feSCy Schubert switch (rval) 55223b9b51feSCy Schubert { 55233b9b51feSCy Schubert case -3 : 55243b9b51feSCy Schubert /* ipf_nat_match() failure */ 55253b9b51feSCy Schubert /* FALLTHROUGH */ 55263b9b51feSCy Schubert case -2 : 55273b9b51feSCy Schubert /* retry_roundrobin loop failure */ 55283b9b51feSCy Schubert /* FALLTHROUGH */ 55293b9b51feSCy Schubert case -1 : 55303b9b51feSCy Schubert /* proxy failure detected by ipf_nat_in() */ 55313b9b51feSCy Schubert if (passp != NULL) { 55323b9b51feSCy Schubert DT2(frb_natv4in, fr_info_t *, fin, int, rval); 55333b9b51feSCy Schubert NBUMPSIDED(0, ns_drop); 55343b9b51feSCy Schubert *passp = FR_BLOCK; 55353b9b51feSCy Schubert fin->fin_reason = FRB_NATV4; 55363b9b51feSCy Schubert } 55373b9b51feSCy Schubert fin->fin_flx |= FI_BADNAT; 55383b9b51feSCy Schubert NBUMPSIDED(0, ns_badnat); 55393b9b51feSCy Schubert rval = -1; /* We only return -1 on error. */ 55403b9b51feSCy Schubert break; 55413b9b51feSCy Schubert case 0 : 55423b9b51feSCy Schubert NBUMPSIDE(0, ns_ignored); 55433b9b51feSCy Schubert break; 55443b9b51feSCy Schubert case 1 : 55453b9b51feSCy Schubert NBUMPSIDE(0, ns_translated); 55463b9b51feSCy Schubert break; 55473b9b51feSCy Schubert } 55483b9b51feSCy Schubert return rval; 55493b9b51feSCy Schubert } 55503b9b51feSCy Schubert 55513b9b51feSCy Schubert 55523b9b51feSCy Schubert /* ------------------------------------------------------------------------ */ 55533b9b51feSCy Schubert /* Function: ipf_nat_in */ 55543b9b51feSCy Schubert /* Returns: int - -1 == packet failed NAT checks so block it, */ 55553b9b51feSCy Schubert /* 1 == packet was successfully translated. */ 55563b9b51feSCy Schubert /* Parameters: fin(I) - pointer to packet information */ 55573b9b51feSCy Schubert /* nat(I) - pointer to NAT structure */ 55583b9b51feSCy Schubert /* natadd(I) - flag indicating if it is safe to add frag cache */ 55593b9b51feSCy Schubert /* nflags(I) - NAT flags set for this packet */ 55603b9b51feSCy Schubert /* Locks Held: ipf_nat(READ) */ 55613b9b51feSCy Schubert /* */ 55623b9b51feSCy Schubert /* Translate a packet coming "in" on an interface. */ 55633b9b51feSCy Schubert /* ------------------------------------------------------------------------ */ 55643b9b51feSCy Schubert int 55653b9b51feSCy Schubert ipf_nat_in(fin, nat, natadd, nflags) 55663b9b51feSCy Schubert fr_info_t *fin; 55673b9b51feSCy Schubert nat_t *nat; 55683b9b51feSCy Schubert int natadd; 55693b9b51feSCy Schubert u_32_t nflags; 55703b9b51feSCy Schubert { 55713b9b51feSCy Schubert ipf_main_softc_t *softc = fin->fin_main_soft; 55723b9b51feSCy Schubert ipf_nat_softc_t *softn = softc->ipf_nat_soft; 55733b9b51feSCy Schubert u_32_t sumd, ipsumd, sum1, sum2; 55743b9b51feSCy Schubert icmphdr_t *icmp; 55753b9b51feSCy Schubert tcphdr_t *tcp; 55763b9b51feSCy Schubert ipnat_t *np; 55773b9b51feSCy Schubert int skip; 55783b9b51feSCy Schubert int i; 55793b9b51feSCy Schubert 55803b9b51feSCy Schubert tcp = NULL; 55813b9b51feSCy Schubert np = nat->nat_ptr; 55823b9b51feSCy Schubert fin->fin_fr = nat->nat_fr; 55833b9b51feSCy Schubert 55843b9b51feSCy Schubert if (np != NULL) { 55853b9b51feSCy Schubert if ((natadd != 0) && (fin->fin_flx & FI_FRAG)) 55863b9b51feSCy Schubert (void) ipf_frag_natnew(softc, fin, 0, nat); 55873b9b51feSCy Schubert 55883b9b51feSCy Schubert /* ------------------------------------------------------------- */ 55893b9b51feSCy Schubert /* A few quick notes: */ 55903b9b51feSCy Schubert /* Following are test conditions prior to calling the */ 55913b9b51feSCy Schubert /* ipf_proxy_check routine. */ 55923b9b51feSCy Schubert /* */ 55933b9b51feSCy Schubert /* A NULL tcp indicates a non TCP/UDP packet. When dealing */ 55943b9b51feSCy Schubert /* with a map rule, we attempt to match the packet's */ 55953b9b51feSCy Schubert /* source port against in_dport, otherwise we'd compare the */ 55963b9b51feSCy Schubert /* packet's destination. */ 55973b9b51feSCy Schubert /* ------------------------------------------------------------- */ 55983b9b51feSCy Schubert if (np->in_apr != NULL) { 55993b9b51feSCy Schubert i = ipf_proxy_check(fin, nat); 56003b9b51feSCy Schubert if (i == -1) { 56013b9b51feSCy Schubert NBUMPSIDED(0, ns_ipf_proxy_fail); 56023b9b51feSCy Schubert return -1; 56033b9b51feSCy Schubert } 56043b9b51feSCy Schubert } 56053b9b51feSCy Schubert } 56063b9b51feSCy Schubert 56073b9b51feSCy Schubert ipf_sync_update(softc, SMC_NAT, fin, nat->nat_sync); 56083b9b51feSCy Schubert 56093b9b51feSCy Schubert ipsumd = nat->nat_ipsumd; 56103b9b51feSCy Schubert /* 56113b9b51feSCy Schubert * Fix up checksums, not by recalculating them, but 56123b9b51feSCy Schubert * simply computing adjustments. 56133b9b51feSCy Schubert * Why only do this for some platforms on inbound packets ? 56143b9b51feSCy Schubert * Because for those that it is done, IP processing is yet to happen 56153b9b51feSCy Schubert * and so the IPv4 header checksum has not yet been evaluated. 56163b9b51feSCy Schubert * Perhaps it should always be done for the benefit of things like 56173b9b51feSCy Schubert * fast forwarding (so that it doesn't need to be recomputed) but with 56183b9b51feSCy Schubert * header checksum offloading, perhaps it is a moot point. 56193b9b51feSCy Schubert */ 56203b9b51feSCy Schubert 56213b9b51feSCy Schubert switch (nat->nat_dir) 56223b9b51feSCy Schubert { 56233b9b51feSCy Schubert case NAT_INBOUND : 56243b9b51feSCy Schubert if ((fin->fin_flx & FI_ICMPERR) == 0) { 56253b9b51feSCy Schubert fin->fin_ip->ip_src = nat->nat_nsrcip; 56263b9b51feSCy Schubert fin->fin_saddr = nat->nat_nsrcaddr; 56273b9b51feSCy Schubert } else { 56283b9b51feSCy Schubert sum1 = nat->nat_osrcaddr; 56293b9b51feSCy Schubert sum2 = nat->nat_nsrcaddr; 56303b9b51feSCy Schubert CALC_SUMD(sum1, sum2, sumd); 56313b9b51feSCy Schubert ipsumd -= sumd; 56323b9b51feSCy Schubert } 56333b9b51feSCy Schubert fin->fin_ip->ip_dst = nat->nat_ndstip; 56343b9b51feSCy Schubert fin->fin_daddr = nat->nat_ndstaddr; 56353b9b51feSCy Schubert #if !defined(_KERNEL) || SOLARIS 56363b9b51feSCy Schubert ipf_fix_outcksum(0, &fin->fin_ip->ip_sum, ipsumd, 0); 56373b9b51feSCy Schubert #endif 56383b9b51feSCy Schubert break; 56393b9b51feSCy Schubert 56403b9b51feSCy Schubert case NAT_OUTBOUND : 56413b9b51feSCy Schubert if ((fin->fin_flx & FI_ICMPERR) == 0) { 56423b9b51feSCy Schubert fin->fin_ip->ip_src = nat->nat_odstip; 56433b9b51feSCy Schubert fin->fin_saddr = nat->nat_odstaddr; 56443b9b51feSCy Schubert } else { 56453b9b51feSCy Schubert sum1 = nat->nat_odstaddr; 56463b9b51feSCy Schubert sum2 = nat->nat_ndstaddr; 56473b9b51feSCy Schubert CALC_SUMD(sum1, sum2, sumd); 56483b9b51feSCy Schubert ipsumd -= sumd; 56493b9b51feSCy Schubert } 56503b9b51feSCy Schubert fin->fin_ip->ip_dst = nat->nat_osrcip; 56513b9b51feSCy Schubert fin->fin_daddr = nat->nat_osrcaddr; 56523b9b51feSCy Schubert #if !defined(_KERNEL) || SOLARIS 56533b9b51feSCy Schubert ipf_fix_incksum(0, &fin->fin_ip->ip_sum, ipsumd, 0); 56543b9b51feSCy Schubert #endif 56553b9b51feSCy Schubert break; 56563b9b51feSCy Schubert 56573b9b51feSCy Schubert case NAT_DIVERTIN : 56583b9b51feSCy Schubert { 56593b9b51feSCy Schubert udphdr_t *uh; 56603b9b51feSCy Schubert ip_t *ip; 56613b9b51feSCy Schubert mb_t *m; 56623b9b51feSCy Schubert 56633b9b51feSCy Schubert m = M_DUP(np->in_divmp); 56643b9b51feSCy Schubert if (m == NULL) { 56653b9b51feSCy Schubert NBUMPSIDED(0, ns_divert_dup); 56663b9b51feSCy Schubert return -1; 56673b9b51feSCy Schubert } 56683b9b51feSCy Schubert 56693b9b51feSCy Schubert ip = MTOD(m, ip_t *); 56703b9b51feSCy Schubert ip_fillid(ip); 56713b9b51feSCy Schubert sum1 = ntohs(ip->ip_len); 56723b9b51feSCy Schubert ip->ip_len = ntohs(ip->ip_len); 56733b9b51feSCy Schubert ip->ip_len += fin->fin_plen; 56743b9b51feSCy Schubert ip->ip_len = htons(ip->ip_len); 56753b9b51feSCy Schubert 56763b9b51feSCy Schubert uh = (udphdr_t *)(ip + 1); 56773b9b51feSCy Schubert uh->uh_ulen += fin->fin_plen; 56783b9b51feSCy Schubert uh->uh_ulen = htons(uh->uh_ulen); 56793b9b51feSCy Schubert 56803b9b51feSCy Schubert sum2 = ntohs(ip->ip_id) + ntohs(ip->ip_len); 56813b9b51feSCy Schubert sum2 += ntohs(ip->ip_off) & IP_DF; 56823b9b51feSCy Schubert CALC_SUMD(sum1, sum2, sumd); 56833b9b51feSCy Schubert 56843b9b51feSCy Schubert #if !defined(_KERNEL) || SOLARIS 56853b9b51feSCy Schubert ipf_fix_outcksum(0, &ip->ip_sum, sumd, 0); 56863b9b51feSCy Schubert #endif 56873b9b51feSCy Schubert PREP_MB_T(fin, m); 56883b9b51feSCy Schubert 56893b9b51feSCy Schubert fin->fin_ip = ip; 56903b9b51feSCy Schubert fin->fin_plen += sizeof(ip_t) + 8; /* UDP + new IPv4 hdr */ 56913b9b51feSCy Schubert fin->fin_dlen += sizeof(ip_t) + 8; /* UDP + old IPv4 hdr */ 56923b9b51feSCy Schubert 56933b9b51feSCy Schubert nflags &= ~IPN_TCPUDPICMP; 56943b9b51feSCy Schubert 56953b9b51feSCy Schubert break; 56963b9b51feSCy Schubert } 56973b9b51feSCy Schubert 56983b9b51feSCy Schubert case NAT_DIVERTOUT : 56993b9b51feSCy Schubert { 57003b9b51feSCy Schubert mb_t *m; 57013b9b51feSCy Schubert 57023b9b51feSCy Schubert skip = ipf_nat_decap(fin, nat); 57033b9b51feSCy Schubert if (skip <= 0) { 57043b9b51feSCy Schubert NBUMPSIDED(0, ns_decap_fail); 57053b9b51feSCy Schubert return -1; 57063b9b51feSCy Schubert } 57073b9b51feSCy Schubert 57083b9b51feSCy Schubert m = fin->fin_m; 57093b9b51feSCy Schubert 57103b9b51feSCy Schubert #if SOLARIS && defined(_KERNEL) 57113b9b51feSCy Schubert m->b_rptr += skip; 57123b9b51feSCy Schubert #else 57133b9b51feSCy Schubert m->m_data += skip; 57143b9b51feSCy Schubert m->m_len -= skip; 57153b9b51feSCy Schubert 57163b9b51feSCy Schubert # ifdef M_PKTHDR 57173b9b51feSCy Schubert if (m->m_flags & M_PKTHDR) 57183b9b51feSCy Schubert m->m_pkthdr.len -= skip; 57193b9b51feSCy Schubert # endif 57203b9b51feSCy Schubert #endif 57213b9b51feSCy Schubert 57223b9b51feSCy Schubert ipf_nat_update(fin, nat); 57233b9b51feSCy Schubert nflags &= ~IPN_TCPUDPICMP; 57243b9b51feSCy Schubert fin->fin_flx |= FI_NATED; 57253b9b51feSCy Schubert if (np != NULL && np->in_tag.ipt_num[0] != 0) 57263b9b51feSCy Schubert fin->fin_nattag = &np->in_tag; 57273b9b51feSCy Schubert return 1; 57283b9b51feSCy Schubert /* NOTREACHED */ 57293b9b51feSCy Schubert } 57303b9b51feSCy Schubert } 57313b9b51feSCy Schubert if (nflags & IPN_TCPUDP) 57323b9b51feSCy Schubert tcp = fin->fin_dp; 57333b9b51feSCy Schubert 57343b9b51feSCy Schubert if (!(fin->fin_flx & FI_SHORT) && (fin->fin_off == 0)) { 57353b9b51feSCy Schubert u_short *csump; 57363b9b51feSCy Schubert 57373b9b51feSCy Schubert if ((nat->nat_odport != 0) && (nflags & IPN_TCPUDP)) { 57383b9b51feSCy Schubert switch (nat->nat_dir) 57393b9b51feSCy Schubert { 57403b9b51feSCy Schubert case NAT_INBOUND : 57413b9b51feSCy Schubert tcp->th_sport = nat->nat_nsport; 57423b9b51feSCy Schubert fin->fin_data[0] = ntohs(nat->nat_nsport); 57433b9b51feSCy Schubert tcp->th_dport = nat->nat_ndport; 57443b9b51feSCy Schubert fin->fin_data[1] = ntohs(nat->nat_ndport); 57453b9b51feSCy Schubert break; 57463b9b51feSCy Schubert 57473b9b51feSCy Schubert case NAT_OUTBOUND : 57483b9b51feSCy Schubert tcp->th_sport = nat->nat_odport; 57493b9b51feSCy Schubert fin->fin_data[0] = ntohs(nat->nat_odport); 57503b9b51feSCy Schubert tcp->th_dport = nat->nat_osport; 57513b9b51feSCy Schubert fin->fin_data[1] = ntohs(nat->nat_osport); 57523b9b51feSCy Schubert break; 57533b9b51feSCy Schubert } 57543b9b51feSCy Schubert } 57553b9b51feSCy Schubert 57563b9b51feSCy Schubert 57573b9b51feSCy Schubert if ((nat->nat_odport != 0) && (nflags & IPN_ICMPQUERY)) { 57583b9b51feSCy Schubert icmp = fin->fin_dp; 57593b9b51feSCy Schubert 57603b9b51feSCy Schubert icmp->icmp_id = nat->nat_nicmpid; 57613b9b51feSCy Schubert } 57623b9b51feSCy Schubert 57633b9b51feSCy Schubert csump = ipf_nat_proto(fin, nat, nflags); 57643b9b51feSCy Schubert 57653b9b51feSCy Schubert /* 57663b9b51feSCy Schubert * The above comments do not hold for layer 4 (or higher) 57673b9b51feSCy Schubert * checksums... 57683b9b51feSCy Schubert */ 57693b9b51feSCy Schubert if (csump != NULL) { 57703b9b51feSCy Schubert if (nat->nat_dir == NAT_OUTBOUND) 57713b9b51feSCy Schubert ipf_fix_incksum(0, csump, nat->nat_sumd[0], 0); 57723b9b51feSCy Schubert else 57733b9b51feSCy Schubert ipf_fix_outcksum(0, csump, nat->nat_sumd[0], 0); 57743b9b51feSCy Schubert } 57753b9b51feSCy Schubert } 57763b9b51feSCy Schubert 57773b9b51feSCy Schubert fin->fin_flx |= FI_NATED; 57783b9b51feSCy Schubert if (np != NULL && np->in_tag.ipt_num[0] != 0) 57793b9b51feSCy Schubert fin->fin_nattag = &np->in_tag; 57803b9b51feSCy Schubert return 1; 57813b9b51feSCy Schubert } 57823b9b51feSCy Schubert 57833b9b51feSCy Schubert 57843b9b51feSCy Schubert /* ------------------------------------------------------------------------ */ 57853b9b51feSCy Schubert /* Function: ipf_nat_proto */ 57863b9b51feSCy Schubert /* Returns: u_short* - pointer to transport header checksum to update, */ 57873b9b51feSCy Schubert /* NULL if the transport protocol is not recognised */ 57883b9b51feSCy Schubert /* as needing a checksum update. */ 57893b9b51feSCy Schubert /* Parameters: fin(I) - pointer to packet information */ 57903b9b51feSCy Schubert /* nat(I) - pointer to NAT structure */ 57913b9b51feSCy Schubert /* nflags(I) - NAT flags set for this packet */ 57923b9b51feSCy Schubert /* */ 57933b9b51feSCy Schubert /* Return the pointer to the checksum field for each protocol so understood.*/ 57943b9b51feSCy Schubert /* If support for making other changes to a protocol header is required, */ 57953b9b51feSCy Schubert /* that is not strictly 'address' translation, such as clamping the MSS in */ 57963b9b51feSCy Schubert /* TCP down to a specific value, then do it from here. */ 57973b9b51feSCy Schubert /* ------------------------------------------------------------------------ */ 57983b9b51feSCy Schubert u_short * 57993b9b51feSCy Schubert ipf_nat_proto(fin, nat, nflags) 58003b9b51feSCy Schubert fr_info_t *fin; 58013b9b51feSCy Schubert nat_t *nat; 58023b9b51feSCy Schubert u_int nflags; 58033b9b51feSCy Schubert { 58043b9b51feSCy Schubert icmphdr_t *icmp; 58053b9b51feSCy Schubert u_short *csump; 58063b9b51feSCy Schubert tcphdr_t *tcp; 58073b9b51feSCy Schubert udphdr_t *udp; 58083b9b51feSCy Schubert 58093b9b51feSCy Schubert csump = NULL; 58103b9b51feSCy Schubert if (fin->fin_out == 0) { 58113b9b51feSCy Schubert fin->fin_rev = (nat->nat_dir & NAT_OUTBOUND); 58123b9b51feSCy Schubert } else { 58133b9b51feSCy Schubert fin->fin_rev = ((nat->nat_dir & NAT_OUTBOUND) == 0); 58143b9b51feSCy Schubert } 58153b9b51feSCy Schubert 58163b9b51feSCy Schubert switch (fin->fin_p) 58173b9b51feSCy Schubert { 58183b9b51feSCy Schubert case IPPROTO_TCP : 58193b9b51feSCy Schubert tcp = fin->fin_dp; 58203b9b51feSCy Schubert 58213b9b51feSCy Schubert if ((nflags & IPN_TCP) != 0) 58223b9b51feSCy Schubert csump = &tcp->th_sum; 58233b9b51feSCy Schubert 58243b9b51feSCy Schubert /* 58253b9b51feSCy Schubert * Do a MSS CLAMPING on a SYN packet, 58263b9b51feSCy Schubert * only deal IPv4 for now. 58273b9b51feSCy Schubert */ 58283b9b51feSCy Schubert if ((nat->nat_mssclamp != 0) && (tcp->th_flags & TH_SYN) != 0) 58293b9b51feSCy Schubert ipf_nat_mssclamp(tcp, nat->nat_mssclamp, fin, csump); 58303b9b51feSCy Schubert 58313b9b51feSCy Schubert break; 58323b9b51feSCy Schubert 58333b9b51feSCy Schubert case IPPROTO_UDP : 58343b9b51feSCy Schubert udp = fin->fin_dp; 58353b9b51feSCy Schubert 58363b9b51feSCy Schubert if ((nflags & IPN_UDP) != 0) { 58373b9b51feSCy Schubert if (udp->uh_sum != 0) 58383b9b51feSCy Schubert csump = &udp->uh_sum; 58393b9b51feSCy Schubert } 58403b9b51feSCy Schubert break; 58413b9b51feSCy Schubert 58423b9b51feSCy Schubert case IPPROTO_ICMP : 58433b9b51feSCy Schubert icmp = fin->fin_dp; 58443b9b51feSCy Schubert 58453b9b51feSCy Schubert if ((nflags & IPN_ICMPQUERY) != 0) { 58463b9b51feSCy Schubert if (icmp->icmp_cksum != 0) 58473b9b51feSCy Schubert csump = &icmp->icmp_cksum; 58483b9b51feSCy Schubert } 58493b9b51feSCy Schubert break; 58503b9b51feSCy Schubert 58513b9b51feSCy Schubert #ifdef USE_INET6 58523b9b51feSCy Schubert case IPPROTO_ICMPV6 : 58533b9b51feSCy Schubert { 58543b9b51feSCy Schubert struct icmp6_hdr *icmp6 = (struct icmp6_hdr *)fin->fin_dp; 58553b9b51feSCy Schubert 58563b9b51feSCy Schubert icmp6 = fin->fin_dp; 58573b9b51feSCy Schubert 58583b9b51feSCy Schubert if ((nflags & IPN_ICMPQUERY) != 0) { 58593b9b51feSCy Schubert if (icmp6->icmp6_cksum != 0) 58603b9b51feSCy Schubert csump = &icmp6->icmp6_cksum; 58613b9b51feSCy Schubert } 58623b9b51feSCy Schubert break; 58633b9b51feSCy Schubert } 58643b9b51feSCy Schubert #endif 58653b9b51feSCy Schubert } 58663b9b51feSCy Schubert return csump; 58673b9b51feSCy Schubert } 58683b9b51feSCy Schubert 58693b9b51feSCy Schubert 58703b9b51feSCy Schubert /* ------------------------------------------------------------------------ */ 58713b9b51feSCy Schubert /* Function: ipf_nat_expire */ 58723b9b51feSCy Schubert /* Returns: Nil */ 58733b9b51feSCy Schubert /* Parameters: softc(I) - pointer to soft context main structure */ 58743b9b51feSCy Schubert /* */ 58753b9b51feSCy Schubert /* Check all of the timeout queues for entries at the top which need to be */ 58763b9b51feSCy Schubert /* expired. */ 58773b9b51feSCy Schubert /* ------------------------------------------------------------------------ */ 58783b9b51feSCy Schubert void 58793b9b51feSCy Schubert ipf_nat_expire(softc) 58803b9b51feSCy Schubert ipf_main_softc_t *softc; 58813b9b51feSCy Schubert { 58823b9b51feSCy Schubert ipf_nat_softc_t *softn = softc->ipf_nat_soft; 58833b9b51feSCy Schubert ipftq_t *ifq, *ifqnext; 58843b9b51feSCy Schubert ipftqent_t *tqe, *tqn; 58853b9b51feSCy Schubert int i; 58863b9b51feSCy Schubert SPL_INT(s); 58873b9b51feSCy Schubert 58883b9b51feSCy Schubert SPL_NET(s); 58893b9b51feSCy Schubert WRITE_ENTER(&softc->ipf_nat); 58903b9b51feSCy Schubert for (ifq = softn->ipf_nat_tcptq, i = 0; ifq != NULL; 58913b9b51feSCy Schubert ifq = ifq->ifq_next) { 58923b9b51feSCy Schubert for (tqn = ifq->ifq_head; ((tqe = tqn) != NULL); i++) { 58933b9b51feSCy Schubert if (tqe->tqe_die > softc->ipf_ticks) 58943b9b51feSCy Schubert break; 58953b9b51feSCy Schubert tqn = tqe->tqe_next; 58963b9b51feSCy Schubert ipf_nat_delete(softc, tqe->tqe_parent, NL_EXPIRE); 58973b9b51feSCy Schubert } 58983b9b51feSCy Schubert } 58993b9b51feSCy Schubert 59003b9b51feSCy Schubert for (ifq = softn->ipf_nat_utqe; ifq != NULL; ifq = ifq->ifq_next) { 59013b9b51feSCy Schubert for (tqn = ifq->ifq_head; ((tqe = tqn) != NULL); i++) { 59023b9b51feSCy Schubert if (tqe->tqe_die > softc->ipf_ticks) 59033b9b51feSCy Schubert break; 59043b9b51feSCy Schubert tqn = tqe->tqe_next; 59053b9b51feSCy Schubert ipf_nat_delete(softc, tqe->tqe_parent, NL_EXPIRE); 59063b9b51feSCy Schubert } 59073b9b51feSCy Schubert } 59083b9b51feSCy Schubert 59093b9b51feSCy Schubert for (ifq = softn->ipf_nat_utqe; ifq != NULL; ifq = ifqnext) { 59103b9b51feSCy Schubert ifqnext = ifq->ifq_next; 59113b9b51feSCy Schubert 59123b9b51feSCy Schubert if (((ifq->ifq_flags & IFQF_DELETE) != 0) && 59133b9b51feSCy Schubert (ifq->ifq_ref == 0)) { 59143b9b51feSCy Schubert ipf_freetimeoutqueue(softc, ifq); 59153b9b51feSCy Schubert } 59163b9b51feSCy Schubert } 59173b9b51feSCy Schubert 59183b9b51feSCy Schubert if (softn->ipf_nat_doflush != 0) { 59193b9b51feSCy Schubert ipf_nat_extraflush(softc, softn, 2); 59203b9b51feSCy Schubert softn->ipf_nat_doflush = 0; 59213b9b51feSCy Schubert } 59223b9b51feSCy Schubert 59233b9b51feSCy Schubert RWLOCK_EXIT(&softc->ipf_nat); 59243b9b51feSCy Schubert SPL_X(s); 59253b9b51feSCy Schubert } 59263b9b51feSCy Schubert 59273b9b51feSCy Schubert 59283b9b51feSCy Schubert /* ------------------------------------------------------------------------ */ 59293b9b51feSCy Schubert /* Function: ipf_nat_sync */ 59303b9b51feSCy Schubert /* Returns: Nil */ 59313b9b51feSCy Schubert /* Parameters: softc(I) - pointer to soft context main structure */ 59323b9b51feSCy Schubert /* ifp(I) - pointer to network interface */ 59333b9b51feSCy Schubert /* */ 59343b9b51feSCy Schubert /* Walk through all of the currently active NAT sessions, looking for those */ 59353b9b51feSCy Schubert /* which need to have their translated address updated. */ 59363b9b51feSCy Schubert /* ------------------------------------------------------------------------ */ 59373b9b51feSCy Schubert void 59383b9b51feSCy Schubert ipf_nat_sync(softc, ifp) 59393b9b51feSCy Schubert ipf_main_softc_t *softc; 59403b9b51feSCy Schubert void *ifp; 59413b9b51feSCy Schubert { 59423b9b51feSCy Schubert ipf_nat_softc_t *softn = softc->ipf_nat_soft; 59433b9b51feSCy Schubert u_32_t sum1, sum2, sumd; 59443b9b51feSCy Schubert i6addr_t in; 59453b9b51feSCy Schubert ipnat_t *n; 59463b9b51feSCy Schubert nat_t *nat; 59473b9b51feSCy Schubert void *ifp2; 59483b9b51feSCy Schubert int idx; 59493b9b51feSCy Schubert SPL_INT(s); 59503b9b51feSCy Schubert 59513b9b51feSCy Schubert if (softc->ipf_running <= 0) 59523b9b51feSCy Schubert return; 59533b9b51feSCy Schubert 59543b9b51feSCy Schubert /* 59553b9b51feSCy Schubert * Change IP addresses for NAT sessions for any protocol except TCP 59563b9b51feSCy Schubert * since it will break the TCP connection anyway. The only rules 59573b9b51feSCy Schubert * which will get changed are those which are "map ... -> 0/32", 59583b9b51feSCy Schubert * where the rule specifies the address is taken from the interface. 59593b9b51feSCy Schubert */ 59603b9b51feSCy Schubert SPL_NET(s); 59613b9b51feSCy Schubert WRITE_ENTER(&softc->ipf_nat); 59623b9b51feSCy Schubert 59633b9b51feSCy Schubert if (softc->ipf_running <= 0) { 59643b9b51feSCy Schubert RWLOCK_EXIT(&softc->ipf_nat); 59653b9b51feSCy Schubert return; 59663b9b51feSCy Schubert } 59673b9b51feSCy Schubert 59683b9b51feSCy Schubert for (nat = softn->ipf_nat_instances; nat; nat = nat->nat_next) { 59693b9b51feSCy Schubert if ((nat->nat_flags & IPN_TCP) != 0) 59703b9b51feSCy Schubert continue; 59713b9b51feSCy Schubert 59723b9b51feSCy Schubert n = nat->nat_ptr; 59733b9b51feSCy Schubert if (n != NULL) { 59743b9b51feSCy Schubert if (n->in_v[1] == 4) { 59753b9b51feSCy Schubert if (n->in_redir & NAT_MAP) { 59763b9b51feSCy Schubert if ((n->in_nsrcaddr != 0) || 59773b9b51feSCy Schubert (n->in_nsrcmsk != 0xffffffff)) 59783b9b51feSCy Schubert continue; 59793b9b51feSCy Schubert } else if (n->in_redir & NAT_REDIRECT) { 59803b9b51feSCy Schubert if ((n->in_ndstaddr != 0) || 59813b9b51feSCy Schubert (n->in_ndstmsk != 0xffffffff)) 59823b9b51feSCy Schubert continue; 59833b9b51feSCy Schubert } 59843b9b51feSCy Schubert } 59853b9b51feSCy Schubert #ifdef USE_INET6 59863b9b51feSCy Schubert if (n->in_v[1] == 4) { 59873b9b51feSCy Schubert if (n->in_redir & NAT_MAP) { 59883b9b51feSCy Schubert if (!IP6_ISZERO(&n->in_nsrcaddr) || 59893b9b51feSCy Schubert !IP6_ISONES(&n->in_nsrcmsk)) 59903b9b51feSCy Schubert continue; 59913b9b51feSCy Schubert } else if (n->in_redir & NAT_REDIRECT) { 59923b9b51feSCy Schubert if (!IP6_ISZERO(&n->in_ndstaddr) || 59933b9b51feSCy Schubert !IP6_ISONES(&n->in_ndstmsk)) 59943b9b51feSCy Schubert continue; 59953b9b51feSCy Schubert } 59963b9b51feSCy Schubert } 59973b9b51feSCy Schubert #endif 59983b9b51feSCy Schubert } 59993b9b51feSCy Schubert 60003b9b51feSCy Schubert if (((ifp == NULL) || (ifp == nat->nat_ifps[0]) || 60013b9b51feSCy Schubert (ifp == nat->nat_ifps[1]))) { 60023b9b51feSCy Schubert nat->nat_ifps[0] = GETIFP(nat->nat_ifnames[0], 60033b9b51feSCy Schubert nat->nat_v[0]); 60043b9b51feSCy Schubert if ((nat->nat_ifps[0] != NULL) && 60053b9b51feSCy Schubert (nat->nat_ifps[0] != (void *)-1)) { 60063b9b51feSCy Schubert nat->nat_mtu[0] = GETIFMTU_4(nat->nat_ifps[0]); 60073b9b51feSCy Schubert } 60083b9b51feSCy Schubert if (nat->nat_ifnames[1][0] != '\0') { 60093b9b51feSCy Schubert nat->nat_ifps[1] = GETIFP(nat->nat_ifnames[1], 60103b9b51feSCy Schubert nat->nat_v[1]); 60113b9b51feSCy Schubert } else { 60123b9b51feSCy Schubert nat->nat_ifps[1] = nat->nat_ifps[0]; 60133b9b51feSCy Schubert } 60143b9b51feSCy Schubert if ((nat->nat_ifps[1] != NULL) && 60153b9b51feSCy Schubert (nat->nat_ifps[1] != (void *)-1)) { 60163b9b51feSCy Schubert nat->nat_mtu[1] = GETIFMTU_4(nat->nat_ifps[1]); 60173b9b51feSCy Schubert } 60183b9b51feSCy Schubert ifp2 = nat->nat_ifps[0]; 60193b9b51feSCy Schubert if (ifp2 == NULL) 60203b9b51feSCy Schubert continue; 60213b9b51feSCy Schubert 60223b9b51feSCy Schubert /* 60233b9b51feSCy Schubert * Change the map-to address to be the same as the 60243b9b51feSCy Schubert * new one. 60253b9b51feSCy Schubert */ 60263b9b51feSCy Schubert sum1 = NATFSUM(nat, nat->nat_v[1], nat_nsrc6); 60273b9b51feSCy Schubert if (ipf_ifpaddr(softc, nat->nat_v[0], FRI_NORMAL, ifp2, 60283b9b51feSCy Schubert &in, NULL) != -1) { 60293b9b51feSCy Schubert if (nat->nat_v[0] == 4) 60303b9b51feSCy Schubert nat->nat_nsrcip = in.in4; 60313b9b51feSCy Schubert } 60323b9b51feSCy Schubert sum2 = NATFSUM(nat, nat->nat_v[1], nat_nsrc6); 60333b9b51feSCy Schubert 60343b9b51feSCy Schubert if (sum1 == sum2) 60353b9b51feSCy Schubert continue; 60363b9b51feSCy Schubert /* 60373b9b51feSCy Schubert * Readjust the checksum adjustment to take into 60383b9b51feSCy Schubert * account the new IP#. 60393b9b51feSCy Schubert */ 60403b9b51feSCy Schubert CALC_SUMD(sum1, sum2, sumd); 60413b9b51feSCy Schubert /* XXX - dont change for TCP when solaris does 60423b9b51feSCy Schubert * hardware checksumming. 60433b9b51feSCy Schubert */ 60443b9b51feSCy Schubert sumd += nat->nat_sumd[0]; 60453b9b51feSCy Schubert nat->nat_sumd[0] = (sumd & 0xffff) + (sumd >> 16); 60463b9b51feSCy Schubert nat->nat_sumd[1] = nat->nat_sumd[0]; 60473b9b51feSCy Schubert } 60483b9b51feSCy Schubert } 60493b9b51feSCy Schubert 60503b9b51feSCy Schubert for (n = softn->ipf_nat_list; (n != NULL); n = n->in_next) { 60513b9b51feSCy Schubert char *base = n->in_names; 60523b9b51feSCy Schubert 60533b9b51feSCy Schubert if ((ifp == NULL) || (n->in_ifps[0] == ifp)) 60543b9b51feSCy Schubert n->in_ifps[0] = ipf_resolvenic(softc, 60553b9b51feSCy Schubert base + n->in_ifnames[0], 60563b9b51feSCy Schubert n->in_v[0]); 60573b9b51feSCy Schubert if ((ifp == NULL) || (n->in_ifps[1] == ifp)) 60583b9b51feSCy Schubert n->in_ifps[1] = ipf_resolvenic(softc, 60593b9b51feSCy Schubert base + n->in_ifnames[1], 60603b9b51feSCy Schubert n->in_v[1]); 60613b9b51feSCy Schubert 60623b9b51feSCy Schubert if (n->in_redir & NAT_REDIRECT) 60633b9b51feSCy Schubert idx = 1; 60643b9b51feSCy Schubert else 60653b9b51feSCy Schubert idx = 0; 60663b9b51feSCy Schubert 60673b9b51feSCy Schubert if (((ifp == NULL) || (n->in_ifps[idx] == ifp)) && 60683b9b51feSCy Schubert (n->in_ifps[idx] != NULL && 60693b9b51feSCy Schubert n->in_ifps[idx] != (void *)-1)) { 60703b9b51feSCy Schubert 60713b9b51feSCy Schubert ipf_nat_nextaddrinit(softc, n->in_names, &n->in_osrc, 60723b9b51feSCy Schubert 0, n->in_ifps[idx]); 60733b9b51feSCy Schubert ipf_nat_nextaddrinit(softc, n->in_names, &n->in_odst, 60743b9b51feSCy Schubert 0, n->in_ifps[idx]); 60753b9b51feSCy Schubert ipf_nat_nextaddrinit(softc, n->in_names, &n->in_nsrc, 60763b9b51feSCy Schubert 0, n->in_ifps[idx]); 60773b9b51feSCy Schubert ipf_nat_nextaddrinit(softc, n->in_names, &n->in_ndst, 60783b9b51feSCy Schubert 0, n->in_ifps[idx]); 60793b9b51feSCy Schubert } 60803b9b51feSCy Schubert } 60813b9b51feSCy Schubert RWLOCK_EXIT(&softc->ipf_nat); 60823b9b51feSCy Schubert SPL_X(s); 60833b9b51feSCy Schubert } 60843b9b51feSCy Schubert 60853b9b51feSCy Schubert 60863b9b51feSCy Schubert /* ------------------------------------------------------------------------ */ 60873b9b51feSCy Schubert /* Function: ipf_nat_icmpquerytype */ 60883b9b51feSCy Schubert /* Returns: int - 1 == success, 0 == failure */ 60893b9b51feSCy Schubert /* Parameters: icmptype(I) - ICMP type number */ 60903b9b51feSCy Schubert /* */ 60913b9b51feSCy Schubert /* Tests to see if the ICMP type number passed is a query/response type or */ 60923b9b51feSCy Schubert /* not. */ 60933b9b51feSCy Schubert /* ------------------------------------------------------------------------ */ 60943b9b51feSCy Schubert static int 60953b9b51feSCy Schubert ipf_nat_icmpquerytype(icmptype) 60963b9b51feSCy Schubert int icmptype; 60973b9b51feSCy Schubert { 60983b9b51feSCy Schubert 60993b9b51feSCy Schubert /* 61003b9b51feSCy Schubert * For the ICMP query NAT code, it is essential that both the query 61013b9b51feSCy Schubert * and the reply match on the NAT rule. Because the NAT structure 61023b9b51feSCy Schubert * does not keep track of the icmptype, and a single NAT structure 61033b9b51feSCy Schubert * is used for all icmp types with the same src, dest and id, we 61043b9b51feSCy Schubert * simply define the replies as queries as well. The funny thing is, 61053b9b51feSCy Schubert * altough it seems silly to call a reply a query, this is exactly 61063b9b51feSCy Schubert * as it is defined in the IPv4 specification 61073b9b51feSCy Schubert */ 61083b9b51feSCy Schubert switch (icmptype) 61093b9b51feSCy Schubert { 61103b9b51feSCy Schubert case ICMP_ECHOREPLY: 61113b9b51feSCy Schubert case ICMP_ECHO: 61123b9b51feSCy Schubert /* route advertisement/solicitation is currently unsupported: */ 61133b9b51feSCy Schubert /* it would require rewriting the ICMP data section */ 61143b9b51feSCy Schubert case ICMP_TSTAMP: 61153b9b51feSCy Schubert case ICMP_TSTAMPREPLY: 61163b9b51feSCy Schubert case ICMP_IREQ: 61173b9b51feSCy Schubert case ICMP_IREQREPLY: 61183b9b51feSCy Schubert case ICMP_MASKREQ: 61193b9b51feSCy Schubert case ICMP_MASKREPLY: 61203b9b51feSCy Schubert return 1; 61213b9b51feSCy Schubert default: 61223b9b51feSCy Schubert return 0; 61233b9b51feSCy Schubert } 61243b9b51feSCy Schubert } 61253b9b51feSCy Schubert 61263b9b51feSCy Schubert 61273b9b51feSCy Schubert /* ------------------------------------------------------------------------ */ 61283b9b51feSCy Schubert /* Function: nat_log */ 61293b9b51feSCy Schubert /* Returns: Nil */ 61303b9b51feSCy Schubert /* Parameters: softc(I) - pointer to soft context main structure */ 61313b9b51feSCy Schubert /* softn(I) - pointer to NAT context structure */ 61323b9b51feSCy Schubert /* nat(I) - pointer to NAT structure */ 61333b9b51feSCy Schubert /* action(I) - action related to NAT structure being performed */ 61343b9b51feSCy Schubert /* */ 61353b9b51feSCy Schubert /* Creates a NAT log entry. */ 61363b9b51feSCy Schubert /* ------------------------------------------------------------------------ */ 61373b9b51feSCy Schubert void 61383b9b51feSCy Schubert ipf_nat_log(softc, softn, nat, action) 61393b9b51feSCy Schubert ipf_main_softc_t *softc; 61403b9b51feSCy Schubert ipf_nat_softc_t *softn; 61413b9b51feSCy Schubert struct nat *nat; 61423b9b51feSCy Schubert u_int action; 61433b9b51feSCy Schubert { 61443b9b51feSCy Schubert #ifdef IPFILTER_LOG 61453b9b51feSCy Schubert struct ipnat *np; 61463b9b51feSCy Schubert int rulen; 61473b9b51feSCy Schubert struct natlog natl; 61483b9b51feSCy Schubert void *items[1]; 61493b9b51feSCy Schubert size_t sizes[1]; 61503b9b51feSCy Schubert int types[1]; 61513b9b51feSCy Schubert 61523b9b51feSCy Schubert bcopy((char *)&nat->nat_osrc6, (char *)&natl.nl_osrcip, 61533b9b51feSCy Schubert sizeof(natl.nl_osrcip)); 61543b9b51feSCy Schubert bcopy((char *)&nat->nat_nsrc6, (char *)&natl.nl_nsrcip, 61553b9b51feSCy Schubert sizeof(natl.nl_nsrcip)); 61563b9b51feSCy Schubert bcopy((char *)&nat->nat_odst6, (char *)&natl.nl_odstip, 61573b9b51feSCy Schubert sizeof(natl.nl_odstip)); 61583b9b51feSCy Schubert bcopy((char *)&nat->nat_ndst6, (char *)&natl.nl_ndstip, 61593b9b51feSCy Schubert sizeof(natl.nl_ndstip)); 61603b9b51feSCy Schubert 61613b9b51feSCy Schubert natl.nl_bytes[0] = nat->nat_bytes[0]; 61623b9b51feSCy Schubert natl.nl_bytes[1] = nat->nat_bytes[1]; 61633b9b51feSCy Schubert natl.nl_pkts[0] = nat->nat_pkts[0]; 61643b9b51feSCy Schubert natl.nl_pkts[1] = nat->nat_pkts[1]; 61653b9b51feSCy Schubert natl.nl_odstport = nat->nat_odport; 61663b9b51feSCy Schubert natl.nl_osrcport = nat->nat_osport; 61673b9b51feSCy Schubert natl.nl_nsrcport = nat->nat_nsport; 61683b9b51feSCy Schubert natl.nl_ndstport = nat->nat_ndport; 61693b9b51feSCy Schubert natl.nl_p[0] = nat->nat_pr[0]; 61703b9b51feSCy Schubert natl.nl_p[1] = nat->nat_pr[1]; 61713b9b51feSCy Schubert natl.nl_v[0] = nat->nat_v[0]; 61723b9b51feSCy Schubert natl.nl_v[1] = nat->nat_v[1]; 61733b9b51feSCy Schubert natl.nl_type = nat->nat_redir; 61743b9b51feSCy Schubert natl.nl_action = action; 61753b9b51feSCy Schubert natl.nl_rule = -1; 61763b9b51feSCy Schubert 61773b9b51feSCy Schubert bcopy(nat->nat_ifnames[0], natl.nl_ifnames[0], 61783b9b51feSCy Schubert sizeof(nat->nat_ifnames[0])); 61793b9b51feSCy Schubert bcopy(nat->nat_ifnames[1], natl.nl_ifnames[1], 61803b9b51feSCy Schubert sizeof(nat->nat_ifnames[1])); 61813b9b51feSCy Schubert 61823b9b51feSCy Schubert if (softc->ipf_large_nat && nat->nat_ptr != NULL) { 61833b9b51feSCy Schubert for (rulen = 0, np = softn->ipf_nat_list; np != NULL; 61843b9b51feSCy Schubert np = np->in_next, rulen++) 61853b9b51feSCy Schubert if (np == nat->nat_ptr) { 61863b9b51feSCy Schubert natl.nl_rule = rulen; 61873b9b51feSCy Schubert break; 61883b9b51feSCy Schubert } 61893b9b51feSCy Schubert } 61903b9b51feSCy Schubert items[0] = &natl; 61913b9b51feSCy Schubert sizes[0] = sizeof(natl); 61923b9b51feSCy Schubert types[0] = 0; 61933b9b51feSCy Schubert 61943b9b51feSCy Schubert (void) ipf_log_items(softc, IPL_LOGNAT, NULL, items, sizes, types, 1); 61953b9b51feSCy Schubert #endif 61963b9b51feSCy Schubert } 61973b9b51feSCy Schubert 61983b9b51feSCy Schubert 61993b9b51feSCy Schubert 62003b9b51feSCy Schubert 62013b9b51feSCy Schubert /* ------------------------------------------------------------------------ */ 62023b9b51feSCy Schubert /* Function: ipf_nat_rule_deref */ 62033b9b51feSCy Schubert /* Returns: Nil */ 62043b9b51feSCy Schubert /* Parameters: softc(I) - pointer to soft context main structure */ 62053b9b51feSCy Schubert /* inp(I) - pointer to pointer to NAT rule */ 62063b9b51feSCy Schubert /* Write Locks: ipf_nat */ 62073b9b51feSCy Schubert /* */ 62083b9b51feSCy Schubert /* Dropping the refernce count for a rule means that whatever held the */ 62093b9b51feSCy Schubert /* pointer to this rule (*inp) is no longer interested in it and when the */ 62103b9b51feSCy Schubert /* reference count drops to zero, any resources allocated for the rule can */ 62113b9b51feSCy Schubert /* be released and the rule itself free'd. */ 62123b9b51feSCy Schubert /* ------------------------------------------------------------------------ */ 62133b9b51feSCy Schubert void 62143b9b51feSCy Schubert ipf_nat_rule_deref(softc, inp) 62153b9b51feSCy Schubert ipf_main_softc_t *softc; 62163b9b51feSCy Schubert ipnat_t **inp; 62173b9b51feSCy Schubert { 62183b9b51feSCy Schubert ipf_nat_softc_t *softn = softc->ipf_nat_soft; 62193b9b51feSCy Schubert ipnat_t *n; 62203b9b51feSCy Schubert 62213b9b51feSCy Schubert n = *inp; 62223b9b51feSCy Schubert *inp = NULL; 62233b9b51feSCy Schubert n->in_use--; 62243b9b51feSCy Schubert if (n->in_use > 0) 62253b9b51feSCy Schubert return; 62263b9b51feSCy Schubert 62273b9b51feSCy Schubert if (n->in_apr != NULL) 62283b9b51feSCy Schubert ipf_proxy_deref(n->in_apr); 62293b9b51feSCy Schubert 62303b9b51feSCy Schubert ipf_nat_rule_fini(softc, n); 62313b9b51feSCy Schubert 62323b9b51feSCy Schubert if (n->in_redir & NAT_REDIRECT) { 62333b9b51feSCy Schubert if ((n->in_flags & IPN_PROXYRULE) == 0) { 62343b9b51feSCy Schubert ATOMIC_DEC32(softn->ipf_nat_stats.ns_rules_rdr); 62353b9b51feSCy Schubert } 62363b9b51feSCy Schubert } 62373b9b51feSCy Schubert if (n->in_redir & (NAT_MAP|NAT_MAPBLK)) { 62383b9b51feSCy Schubert if ((n->in_flags & IPN_PROXYRULE) == 0) { 62393b9b51feSCy Schubert ATOMIC_DEC32(softn->ipf_nat_stats.ns_rules_map); 62403b9b51feSCy Schubert } 62413b9b51feSCy Schubert } 62423b9b51feSCy Schubert 62433b9b51feSCy Schubert if (n->in_tqehead[0] != NULL) { 62443b9b51feSCy Schubert if (ipf_deletetimeoutqueue(n->in_tqehead[0]) == 0) { 62453b9b51feSCy Schubert ipf_freetimeoutqueue(softc, n->in_tqehead[0]); 62463b9b51feSCy Schubert } 62473b9b51feSCy Schubert } 62483b9b51feSCy Schubert 62493b9b51feSCy Schubert if (n->in_tqehead[1] != NULL) { 62503b9b51feSCy Schubert if (ipf_deletetimeoutqueue(n->in_tqehead[1]) == 0) { 62513b9b51feSCy Schubert ipf_freetimeoutqueue(softc, n->in_tqehead[1]); 62523b9b51feSCy Schubert } 62533b9b51feSCy Schubert } 62543b9b51feSCy Schubert 62553b9b51feSCy Schubert if ((n->in_flags & IPN_PROXYRULE) == 0) { 62563b9b51feSCy Schubert ATOMIC_DEC32(softn->ipf_nat_stats.ns_rules); 62573b9b51feSCy Schubert } 62583b9b51feSCy Schubert 62593b9b51feSCy Schubert MUTEX_DESTROY(&n->in_lock); 62603b9b51feSCy Schubert 62613b9b51feSCy Schubert KFREES(n, n->in_size); 62623b9b51feSCy Schubert 62633b9b51feSCy Schubert #if SOLARIS && !defined(INSTANCES) 62643b9b51feSCy Schubert if (softn->ipf_nat_stats.ns_rules == 0) 62653b9b51feSCy Schubert pfil_delayed_copy = 1; 62663b9b51feSCy Schubert #endif 62673b9b51feSCy Schubert } 62683b9b51feSCy Schubert 62693b9b51feSCy Schubert 62703b9b51feSCy Schubert /* ------------------------------------------------------------------------ */ 62713b9b51feSCy Schubert /* Function: ipf_nat_deref */ 62723b9b51feSCy Schubert /* Returns: Nil */ 62733b9b51feSCy Schubert /* Parameters: softc(I) - pointer to soft context main structure */ 62743b9b51feSCy Schubert /* natp(I) - pointer to pointer to NAT table entry */ 62753b9b51feSCy Schubert /* */ 62763b9b51feSCy Schubert /* Decrement the reference counter for this NAT table entry and free it if */ 62773b9b51feSCy Schubert /* there are no more things using it. */ 62783b9b51feSCy Schubert /* */ 62793b9b51feSCy Schubert /* IF nat_ref == 1 when this function is called, then we have an orphan nat */ 62803b9b51feSCy Schubert /* structure *because* it only gets called on paths _after_ nat_ref has been*/ 62813b9b51feSCy Schubert /* incremented. If nat_ref == 1 then we shouldn't decrement it here */ 62823b9b51feSCy Schubert /* because nat_delete() will do that and send nat_ref to -1. */ 62833b9b51feSCy Schubert /* */ 62843b9b51feSCy Schubert /* Holding the lock on nat_lock is required to serialise nat_delete() being */ 62853b9b51feSCy Schubert /* called from a NAT flush ioctl with a deref happening because of a packet.*/ 62863b9b51feSCy Schubert /* ------------------------------------------------------------------------ */ 62873b9b51feSCy Schubert void 62883b9b51feSCy Schubert ipf_nat_deref(softc, natp) 62893b9b51feSCy Schubert ipf_main_softc_t *softc; 62903b9b51feSCy Schubert nat_t **natp; 62913b9b51feSCy Schubert { 62923b9b51feSCy Schubert nat_t *nat; 62933b9b51feSCy Schubert 62943b9b51feSCy Schubert nat = *natp; 62953b9b51feSCy Schubert *natp = NULL; 62963b9b51feSCy Schubert 62973b9b51feSCy Schubert MUTEX_ENTER(&nat->nat_lock); 62983b9b51feSCy Schubert if (nat->nat_ref > 1) { 62993b9b51feSCy Schubert nat->nat_ref--; 63003b9b51feSCy Schubert ASSERT(nat->nat_ref >= 0); 63013b9b51feSCy Schubert MUTEX_EXIT(&nat->nat_lock); 63023b9b51feSCy Schubert return; 63033b9b51feSCy Schubert } 63043b9b51feSCy Schubert MUTEX_EXIT(&nat->nat_lock); 63053b9b51feSCy Schubert 63063b9b51feSCy Schubert WRITE_ENTER(&softc->ipf_nat); 63073b9b51feSCy Schubert ipf_nat_delete(softc, nat, NL_EXPIRE); 63083b9b51feSCy Schubert RWLOCK_EXIT(&softc->ipf_nat); 63093b9b51feSCy Schubert } 63103b9b51feSCy Schubert 63113b9b51feSCy Schubert 63123b9b51feSCy Schubert /* ------------------------------------------------------------------------ */ 63133b9b51feSCy Schubert /* Function: ipf_nat_clone */ 63143b9b51feSCy Schubert /* Returns: ipstate_t* - NULL == cloning failed, */ 63153b9b51feSCy Schubert /* else pointer to new state structure */ 63163b9b51feSCy Schubert /* Parameters: fin(I) - pointer to packet information */ 63173b9b51feSCy Schubert /* is(I) - pointer to master state structure */ 63183b9b51feSCy Schubert /* Write Lock: ipf_nat */ 63193b9b51feSCy Schubert /* */ 63203b9b51feSCy Schubert /* Create a "duplcate" state table entry from the master. */ 63213b9b51feSCy Schubert /* ------------------------------------------------------------------------ */ 63223b9b51feSCy Schubert nat_t * 63233b9b51feSCy Schubert ipf_nat_clone(fin, nat) 63243b9b51feSCy Schubert fr_info_t *fin; 63253b9b51feSCy Schubert nat_t *nat; 63263b9b51feSCy Schubert { 63273b9b51feSCy Schubert ipf_main_softc_t *softc = fin->fin_main_soft; 63283b9b51feSCy Schubert ipf_nat_softc_t *softn = softc->ipf_nat_soft; 63293b9b51feSCy Schubert frentry_t *fr; 63303b9b51feSCy Schubert nat_t *clone; 63313b9b51feSCy Schubert ipnat_t *np; 63323b9b51feSCy Schubert 63333b9b51feSCy Schubert KMALLOC(clone, nat_t *); 63343b9b51feSCy Schubert if (clone == NULL) { 63353b9b51feSCy Schubert NBUMPSIDED(fin->fin_out, ns_clone_nomem); 63363b9b51feSCy Schubert return NULL; 63373b9b51feSCy Schubert } 63383b9b51feSCy Schubert bcopy((char *)nat, (char *)clone, sizeof(*clone)); 63393b9b51feSCy Schubert 63403b9b51feSCy Schubert MUTEX_NUKE(&clone->nat_lock); 63413b9b51feSCy Schubert 63423b9b51feSCy Schubert clone->nat_rev = fin->fin_rev; 63433b9b51feSCy Schubert clone->nat_aps = NULL; 63443b9b51feSCy Schubert /* 63453b9b51feSCy Schubert * Initialize all these so that ipf_nat_delete() doesn't cause a crash. 63463b9b51feSCy Schubert */ 63473b9b51feSCy Schubert clone->nat_tqe.tqe_pnext = NULL; 63483b9b51feSCy Schubert clone->nat_tqe.tqe_next = NULL; 63493b9b51feSCy Schubert clone->nat_tqe.tqe_ifq = NULL; 63503b9b51feSCy Schubert clone->nat_tqe.tqe_parent = clone; 63513b9b51feSCy Schubert 63523b9b51feSCy Schubert clone->nat_flags &= ~SI_CLONE; 63533b9b51feSCy Schubert clone->nat_flags |= SI_CLONED; 63543b9b51feSCy Schubert 63553b9b51feSCy Schubert if (clone->nat_hm) 63563b9b51feSCy Schubert clone->nat_hm->hm_ref++; 63573b9b51feSCy Schubert 63583b9b51feSCy Schubert if (ipf_nat_insert(softc, softn, clone) == -1) { 63593b9b51feSCy Schubert KFREE(clone); 63603b9b51feSCy Schubert NBUMPSIDED(fin->fin_out, ns_insert_fail); 63613b9b51feSCy Schubert return NULL; 63623b9b51feSCy Schubert } 63633b9b51feSCy Schubert 63643b9b51feSCy Schubert np = clone->nat_ptr; 63653b9b51feSCy Schubert if (np != NULL) { 63663b9b51feSCy Schubert if (softn->ipf_nat_logging) 63673b9b51feSCy Schubert ipf_nat_log(softc, softn, clone, NL_CLONE); 63683b9b51feSCy Schubert np->in_use++; 63693b9b51feSCy Schubert } 63703b9b51feSCy Schubert fr = clone->nat_fr; 63713b9b51feSCy Schubert if (fr != NULL) { 63723b9b51feSCy Schubert MUTEX_ENTER(&fr->fr_lock); 63733b9b51feSCy Schubert fr->fr_ref++; 63743b9b51feSCy Schubert MUTEX_EXIT(&fr->fr_lock); 63753b9b51feSCy Schubert } 63763b9b51feSCy Schubert 63773b9b51feSCy Schubert 63783b9b51feSCy Schubert /* 63793b9b51feSCy Schubert * Because the clone is created outside the normal loop of things and 63803b9b51feSCy Schubert * TCP has special needs in terms of state, initialise the timeout 63813b9b51feSCy Schubert * state of the new NAT from here. 63823b9b51feSCy Schubert */ 63833b9b51feSCy Schubert if (clone->nat_pr[0] == IPPROTO_TCP) { 63843b9b51feSCy Schubert (void) ipf_tcp_age(&clone->nat_tqe, fin, softn->ipf_nat_tcptq, 63853b9b51feSCy Schubert clone->nat_flags, 2); 63863b9b51feSCy Schubert } 63873b9b51feSCy Schubert clone->nat_sync = ipf_sync_new(softc, SMC_NAT, fin, clone); 63883b9b51feSCy Schubert if (softn->ipf_nat_logging) 63893b9b51feSCy Schubert ipf_nat_log(softc, softn, clone, NL_CLONE); 63903b9b51feSCy Schubert return clone; 63913b9b51feSCy Schubert } 63923b9b51feSCy Schubert 63933b9b51feSCy Schubert 63943b9b51feSCy Schubert /* ------------------------------------------------------------------------ */ 63953b9b51feSCy Schubert /* Function: ipf_nat_wildok */ 63963b9b51feSCy Schubert /* Returns: int - 1 == packet's ports match wildcards */ 63973b9b51feSCy Schubert /* 0 == packet's ports don't match wildcards */ 63983b9b51feSCy Schubert /* Parameters: nat(I) - NAT entry */ 63993b9b51feSCy Schubert /* sport(I) - source port */ 64003b9b51feSCy Schubert /* dport(I) - destination port */ 64013b9b51feSCy Schubert /* flags(I) - wildcard flags */ 64023b9b51feSCy Schubert /* dir(I) - packet direction */ 64033b9b51feSCy Schubert /* */ 64043b9b51feSCy Schubert /* Use NAT entry and packet direction to determine which combination of */ 64053b9b51feSCy Schubert /* wildcard flags should be used. */ 64063b9b51feSCy Schubert /* ------------------------------------------------------------------------ */ 64073b9b51feSCy Schubert int 64083b9b51feSCy Schubert ipf_nat_wildok(nat, sport, dport, flags, dir) 64093b9b51feSCy Schubert nat_t *nat; 64103b9b51feSCy Schubert int sport, dport, flags, dir; 64113b9b51feSCy Schubert { 64123b9b51feSCy Schubert /* 64133b9b51feSCy Schubert * When called by dir is set to 64143b9b51feSCy Schubert * nat_inlookup NAT_INBOUND (0) 64153b9b51feSCy Schubert * nat_outlookup NAT_OUTBOUND (1) 64163b9b51feSCy Schubert * 64173b9b51feSCy Schubert * We simply combine the packet's direction in dir with the original 64183b9b51feSCy Schubert * "intended" direction of that NAT entry in nat->nat_dir to decide 64193b9b51feSCy Schubert * which combination of wildcard flags to allow. 64203b9b51feSCy Schubert */ 64213b9b51feSCy Schubert switch ((dir << 1) | (nat->nat_dir & (NAT_INBOUND|NAT_OUTBOUND))) 64223b9b51feSCy Schubert { 64233b9b51feSCy Schubert case 3: /* outbound packet / outbound entry */ 64243b9b51feSCy Schubert if (((nat->nat_osport == sport) || 64253b9b51feSCy Schubert (flags & SI_W_SPORT)) && 64263b9b51feSCy Schubert ((nat->nat_odport == dport) || 64273b9b51feSCy Schubert (flags & SI_W_DPORT))) 64283b9b51feSCy Schubert return 1; 64293b9b51feSCy Schubert break; 64303b9b51feSCy Schubert case 2: /* outbound packet / inbound entry */ 64313b9b51feSCy Schubert if (((nat->nat_osport == dport) || 64323b9b51feSCy Schubert (flags & SI_W_SPORT)) && 64333b9b51feSCy Schubert ((nat->nat_odport == sport) || 64343b9b51feSCy Schubert (flags & SI_W_DPORT))) 64353b9b51feSCy Schubert return 1; 64363b9b51feSCy Schubert break; 64373b9b51feSCy Schubert case 1: /* inbound packet / outbound entry */ 64383b9b51feSCy Schubert if (((nat->nat_osport == dport) || 64393b9b51feSCy Schubert (flags & SI_W_SPORT)) && 64403b9b51feSCy Schubert ((nat->nat_odport == sport) || 64413b9b51feSCy Schubert (flags & SI_W_DPORT))) 64423b9b51feSCy Schubert return 1; 64433b9b51feSCy Schubert break; 64443b9b51feSCy Schubert case 0: /* inbound packet / inbound entry */ 64453b9b51feSCy Schubert if (((nat->nat_osport == sport) || 64463b9b51feSCy Schubert (flags & SI_W_SPORT)) && 64473b9b51feSCy Schubert ((nat->nat_odport == dport) || 64483b9b51feSCy Schubert (flags & SI_W_DPORT))) 64493b9b51feSCy Schubert return 1; 64503b9b51feSCy Schubert break; 64513b9b51feSCy Schubert default: 64523b9b51feSCy Schubert break; 64533b9b51feSCy Schubert } 64543b9b51feSCy Schubert 64553b9b51feSCy Schubert return(0); 64563b9b51feSCy Schubert } 64573b9b51feSCy Schubert 64583b9b51feSCy Schubert 64593b9b51feSCy Schubert /* ------------------------------------------------------------------------ */ 64603b9b51feSCy Schubert /* Function: nat_mssclamp */ 64613b9b51feSCy Schubert /* Returns: Nil */ 64623b9b51feSCy Schubert /* Parameters: tcp(I) - pointer to TCP header */ 64633b9b51feSCy Schubert /* maxmss(I) - value to clamp the TCP MSS to */ 64643b9b51feSCy Schubert /* fin(I) - pointer to packet information */ 64653b9b51feSCy Schubert /* csump(I) - pointer to TCP checksum */ 64663b9b51feSCy Schubert /* */ 64673b9b51feSCy Schubert /* Check for MSS option and clamp it if necessary. If found and changed, */ 64683b9b51feSCy Schubert /* then the TCP header checksum will be updated to reflect the change in */ 64693b9b51feSCy Schubert /* the MSS. */ 64703b9b51feSCy Schubert /* ------------------------------------------------------------------------ */ 64713b9b51feSCy Schubert static void 64723b9b51feSCy Schubert ipf_nat_mssclamp(tcp, maxmss, fin, csump) 64733b9b51feSCy Schubert tcphdr_t *tcp; 64743b9b51feSCy Schubert u_32_t maxmss; 64753b9b51feSCy Schubert fr_info_t *fin; 64763b9b51feSCy Schubert u_short *csump; 64773b9b51feSCy Schubert { 64783b9b51feSCy Schubert u_char *cp, *ep, opt; 64793b9b51feSCy Schubert int hlen, advance; 64803b9b51feSCy Schubert u_32_t mss, sumd; 64813b9b51feSCy Schubert 64823b9b51feSCy Schubert hlen = TCP_OFF(tcp) << 2; 64833b9b51feSCy Schubert if (hlen > sizeof(*tcp)) { 64843b9b51feSCy Schubert cp = (u_char *)tcp + sizeof(*tcp); 64853b9b51feSCy Schubert ep = (u_char *)tcp + hlen; 64863b9b51feSCy Schubert 64873b9b51feSCy Schubert while (cp < ep) { 64883b9b51feSCy Schubert opt = cp[0]; 64893b9b51feSCy Schubert if (opt == TCPOPT_EOL) 64903b9b51feSCy Schubert break; 64913b9b51feSCy Schubert else if (opt == TCPOPT_NOP) { 64923b9b51feSCy Schubert cp++; 64933b9b51feSCy Schubert continue; 64943b9b51feSCy Schubert } 64953b9b51feSCy Schubert 64963b9b51feSCy Schubert if (cp + 1 >= ep) 64973b9b51feSCy Schubert break; 64983b9b51feSCy Schubert advance = cp[1]; 64993b9b51feSCy Schubert if ((cp + advance > ep) || (advance <= 0)) 65003b9b51feSCy Schubert break; 65013b9b51feSCy Schubert switch (opt) 65023b9b51feSCy Schubert { 65033b9b51feSCy Schubert case TCPOPT_MAXSEG: 65043b9b51feSCy Schubert if (advance != 4) 65053b9b51feSCy Schubert break; 65063b9b51feSCy Schubert mss = cp[2] * 256 + cp[3]; 65073b9b51feSCy Schubert if (mss > maxmss) { 65083b9b51feSCy Schubert cp[2] = maxmss / 256; 65093b9b51feSCy Schubert cp[3] = maxmss & 0xff; 65103b9b51feSCy Schubert CALC_SUMD(mss, maxmss, sumd); 65113b9b51feSCy Schubert ipf_fix_outcksum(0, csump, sumd, 0); 65123b9b51feSCy Schubert } 65133b9b51feSCy Schubert break; 65143b9b51feSCy Schubert default: 65153b9b51feSCy Schubert /* ignore unknown options */ 65163b9b51feSCy Schubert break; 65173b9b51feSCy Schubert } 65183b9b51feSCy Schubert 65193b9b51feSCy Schubert cp += advance; 65203b9b51feSCy Schubert } 65213b9b51feSCy Schubert } 65223b9b51feSCy Schubert } 65233b9b51feSCy Schubert 65243b9b51feSCy Schubert 65253b9b51feSCy Schubert /* ------------------------------------------------------------------------ */ 65263b9b51feSCy Schubert /* Function: ipf_nat_setqueue */ 65273b9b51feSCy Schubert /* Returns: Nil */ 65283b9b51feSCy Schubert /* Parameters: softc(I) - pointer to soft context main structure */ 65293b9b51feSCy Schubert /* softn(I) - pointer to NAT context structure */ 65303b9b51feSCy Schubert /* nat(I)- pointer to NAT structure */ 65313b9b51feSCy Schubert /* Locks: ipf_nat (read or write) */ 65323b9b51feSCy Schubert /* */ 65333b9b51feSCy Schubert /* Put the NAT entry on its default queue entry, using rev as a helped in */ 65343b9b51feSCy Schubert /* determining which queue it should be placed on. */ 65353b9b51feSCy Schubert /* ------------------------------------------------------------------------ */ 65363b9b51feSCy Schubert void 65373b9b51feSCy Schubert ipf_nat_setqueue(softc, softn, nat) 65383b9b51feSCy Schubert ipf_main_softc_t *softc; 65393b9b51feSCy Schubert ipf_nat_softc_t *softn; 65403b9b51feSCy Schubert nat_t *nat; 65413b9b51feSCy Schubert { 65423b9b51feSCy Schubert ipftq_t *oifq, *nifq; 65433b9b51feSCy Schubert int rev = nat->nat_rev; 65443b9b51feSCy Schubert 65453b9b51feSCy Schubert if (nat->nat_ptr != NULL) 65463b9b51feSCy Schubert nifq = nat->nat_ptr->in_tqehead[rev]; 65473b9b51feSCy Schubert else 65483b9b51feSCy Schubert nifq = NULL; 65493b9b51feSCy Schubert 65503b9b51feSCy Schubert if (nifq == NULL) { 65513b9b51feSCy Schubert switch (nat->nat_pr[0]) 65523b9b51feSCy Schubert { 65533b9b51feSCy Schubert case IPPROTO_UDP : 65543b9b51feSCy Schubert nifq = &softn->ipf_nat_udptq; 65553b9b51feSCy Schubert break; 65563b9b51feSCy Schubert case IPPROTO_ICMP : 65573b9b51feSCy Schubert nifq = &softn->ipf_nat_icmptq; 65583b9b51feSCy Schubert break; 65593b9b51feSCy Schubert case IPPROTO_TCP : 65603b9b51feSCy Schubert nifq = softn->ipf_nat_tcptq + 65613b9b51feSCy Schubert nat->nat_tqe.tqe_state[rev]; 65623b9b51feSCy Schubert break; 65633b9b51feSCy Schubert default : 65643b9b51feSCy Schubert nifq = &softn->ipf_nat_iptq; 65653b9b51feSCy Schubert break; 65663b9b51feSCy Schubert } 65673b9b51feSCy Schubert } 65683b9b51feSCy Schubert 65693b9b51feSCy Schubert oifq = nat->nat_tqe.tqe_ifq; 65703b9b51feSCy Schubert /* 65713b9b51feSCy Schubert * If it's currently on a timeout queue, move it from one queue to 65723b9b51feSCy Schubert * another, else put it on the end of the newly determined queue. 65733b9b51feSCy Schubert */ 65743b9b51feSCy Schubert if (oifq != NULL) 65753b9b51feSCy Schubert ipf_movequeue(softc->ipf_ticks, &nat->nat_tqe, oifq, nifq); 65763b9b51feSCy Schubert else 65773b9b51feSCy Schubert ipf_queueappend(softc->ipf_ticks, &nat->nat_tqe, nifq, nat); 65783b9b51feSCy Schubert return; 65793b9b51feSCy Schubert } 65803b9b51feSCy Schubert 65813b9b51feSCy Schubert 65823b9b51feSCy Schubert /* ------------------------------------------------------------------------ */ 65833b9b51feSCy Schubert /* Function: nat_getnext */ 65843b9b51feSCy Schubert /* Returns: int - 0 == ok, else error */ 65853b9b51feSCy Schubert /* Parameters: softc(I) - pointer to soft context main structure */ 65863b9b51feSCy Schubert /* t(I) - pointer to ipftoken structure */ 65873b9b51feSCy Schubert /* itp(I) - pointer to ipfgeniter_t structure */ 65883b9b51feSCy Schubert /* */ 65893b9b51feSCy Schubert /* Fetch the next nat/ipnat structure pointer from the linked list and */ 65903b9b51feSCy Schubert /* copy it out to the storage space pointed to by itp_data. The next item */ 65913b9b51feSCy Schubert /* in the list to look at is put back in the ipftoken struture. */ 65923b9b51feSCy Schubert /* ------------------------------------------------------------------------ */ 65933b9b51feSCy Schubert static int 65943b9b51feSCy Schubert ipf_nat_getnext(softc, t, itp, objp) 65953b9b51feSCy Schubert ipf_main_softc_t *softc; 65963b9b51feSCy Schubert ipftoken_t *t; 65973b9b51feSCy Schubert ipfgeniter_t *itp; 65983b9b51feSCy Schubert ipfobj_t *objp; 65993b9b51feSCy Schubert { 66003b9b51feSCy Schubert ipf_nat_softc_t *softn = softc->ipf_nat_soft; 66013b9b51feSCy Schubert hostmap_t *hm, *nexthm = NULL, zerohm; 66023b9b51feSCy Schubert ipnat_t *ipn, *nextipnat = NULL, zeroipn; 66033b9b51feSCy Schubert nat_t *nat, *nextnat = NULL, zeronat; 66043b9b51feSCy Schubert int error = 0; 66053b9b51feSCy Schubert void *nnext; 66063b9b51feSCy Schubert 66073b9b51feSCy Schubert if (itp->igi_nitems != 1) { 66083b9b51feSCy Schubert IPFERROR(60075); 66093b9b51feSCy Schubert return ENOSPC; 66103b9b51feSCy Schubert } 66113b9b51feSCy Schubert 66123b9b51feSCy Schubert READ_ENTER(&softc->ipf_nat); 66133b9b51feSCy Schubert 66143b9b51feSCy Schubert switch (itp->igi_type) 66153b9b51feSCy Schubert { 66163b9b51feSCy Schubert case IPFGENITER_HOSTMAP : 66173b9b51feSCy Schubert hm = t->ipt_data; 66183b9b51feSCy Schubert if (hm == NULL) { 66193b9b51feSCy Schubert nexthm = softn->ipf_hm_maplist; 66203b9b51feSCy Schubert } else { 66213b9b51feSCy Schubert nexthm = hm->hm_next; 66223b9b51feSCy Schubert } 66233b9b51feSCy Schubert if (nexthm != NULL) { 66243b9b51feSCy Schubert ATOMIC_INC32(nexthm->hm_ref); 66253b9b51feSCy Schubert t->ipt_data = nexthm; 66263b9b51feSCy Schubert } else { 66273b9b51feSCy Schubert bzero(&zerohm, sizeof(zerohm)); 66283b9b51feSCy Schubert nexthm = &zerohm; 66293b9b51feSCy Schubert t->ipt_data = NULL; 66303b9b51feSCy Schubert } 66313b9b51feSCy Schubert nnext = nexthm->hm_next; 66323b9b51feSCy Schubert break; 66333b9b51feSCy Schubert 66343b9b51feSCy Schubert case IPFGENITER_IPNAT : 66353b9b51feSCy Schubert ipn = t->ipt_data; 66363b9b51feSCy Schubert if (ipn == NULL) { 66373b9b51feSCy Schubert nextipnat = softn->ipf_nat_list; 66383b9b51feSCy Schubert } else { 66393b9b51feSCy Schubert nextipnat = ipn->in_next; 66403b9b51feSCy Schubert } 66413b9b51feSCy Schubert if (nextipnat != NULL) { 66423b9b51feSCy Schubert ATOMIC_INC32(nextipnat->in_use); 66433b9b51feSCy Schubert t->ipt_data = nextipnat; 66443b9b51feSCy Schubert } else { 66453b9b51feSCy Schubert bzero(&zeroipn, sizeof(zeroipn)); 66463b9b51feSCy Schubert nextipnat = &zeroipn; 66473b9b51feSCy Schubert t->ipt_data = NULL; 66483b9b51feSCy Schubert } 66493b9b51feSCy Schubert nnext = nextipnat->in_next; 66503b9b51feSCy Schubert break; 66513b9b51feSCy Schubert 66523b9b51feSCy Schubert case IPFGENITER_NAT : 66533b9b51feSCy Schubert nat = t->ipt_data; 66543b9b51feSCy Schubert if (nat == NULL) { 66553b9b51feSCy Schubert nextnat = softn->ipf_nat_instances; 66563b9b51feSCy Schubert } else { 66573b9b51feSCy Schubert nextnat = nat->nat_next; 66583b9b51feSCy Schubert } 66593b9b51feSCy Schubert if (nextnat != NULL) { 66603b9b51feSCy Schubert MUTEX_ENTER(&nextnat->nat_lock); 66613b9b51feSCy Schubert nextnat->nat_ref++; 66623b9b51feSCy Schubert MUTEX_EXIT(&nextnat->nat_lock); 66633b9b51feSCy Schubert t->ipt_data = nextnat; 66643b9b51feSCy Schubert } else { 66653b9b51feSCy Schubert bzero(&zeronat, sizeof(zeronat)); 66663b9b51feSCy Schubert nextnat = &zeronat; 66673b9b51feSCy Schubert t->ipt_data = NULL; 66683b9b51feSCy Schubert } 66693b9b51feSCy Schubert nnext = nextnat->nat_next; 66703b9b51feSCy Schubert break; 66713b9b51feSCy Schubert 66723b9b51feSCy Schubert default : 66733b9b51feSCy Schubert RWLOCK_EXIT(&softc->ipf_nat); 66743b9b51feSCy Schubert IPFERROR(60055); 66753b9b51feSCy Schubert return EINVAL; 66763b9b51feSCy Schubert } 66773b9b51feSCy Schubert 66783b9b51feSCy Schubert RWLOCK_EXIT(&softc->ipf_nat); 66793b9b51feSCy Schubert 66803b9b51feSCy Schubert objp->ipfo_ptr = itp->igi_data; 66813b9b51feSCy Schubert 66823b9b51feSCy Schubert switch (itp->igi_type) 66833b9b51feSCy Schubert { 66843b9b51feSCy Schubert case IPFGENITER_HOSTMAP : 66853b9b51feSCy Schubert error = COPYOUT(nexthm, objp->ipfo_ptr, sizeof(*nexthm)); 66863b9b51feSCy Schubert if (error != 0) { 66873b9b51feSCy Schubert IPFERROR(60049); 66883b9b51feSCy Schubert error = EFAULT; 66893b9b51feSCy Schubert } 66903b9b51feSCy Schubert if (hm != NULL) { 66913b9b51feSCy Schubert WRITE_ENTER(&softc->ipf_nat); 66923b9b51feSCy Schubert ipf_nat_hostmapdel(softc, &hm); 66933b9b51feSCy Schubert RWLOCK_EXIT(&softc->ipf_nat); 66943b9b51feSCy Schubert } 66953b9b51feSCy Schubert break; 66963b9b51feSCy Schubert 66973b9b51feSCy Schubert case IPFGENITER_IPNAT : 66983b9b51feSCy Schubert objp->ipfo_size = nextipnat->in_size; 66993b9b51feSCy Schubert objp->ipfo_type = IPFOBJ_IPNAT; 67003b9b51feSCy Schubert error = ipf_outobjk(softc, objp, nextipnat); 67013b9b51feSCy Schubert if (ipn != NULL) { 67023b9b51feSCy Schubert WRITE_ENTER(&softc->ipf_nat); 67033b9b51feSCy Schubert ipf_nat_rule_deref(softc, &ipn); 67043b9b51feSCy Schubert RWLOCK_EXIT(&softc->ipf_nat); 67053b9b51feSCy Schubert } 67063b9b51feSCy Schubert break; 67073b9b51feSCy Schubert 67083b9b51feSCy Schubert case IPFGENITER_NAT : 67093b9b51feSCy Schubert objp->ipfo_size = sizeof(nat_t); 67103b9b51feSCy Schubert objp->ipfo_type = IPFOBJ_NAT; 67113b9b51feSCy Schubert error = ipf_outobjk(softc, objp, nextnat); 67123b9b51feSCy Schubert if (nat != NULL) 67133b9b51feSCy Schubert ipf_nat_deref(softc, &nat); 67143b9b51feSCy Schubert 67153b9b51feSCy Schubert break; 67163b9b51feSCy Schubert } 67173b9b51feSCy Schubert 67183b9b51feSCy Schubert if (nnext == NULL) 67193b9b51feSCy Schubert ipf_token_mark_complete(t); 67203b9b51feSCy Schubert 67213b9b51feSCy Schubert return error; 67223b9b51feSCy Schubert } 67233b9b51feSCy Schubert 67243b9b51feSCy Schubert 67253b9b51feSCy Schubert /* ------------------------------------------------------------------------ */ 67263b9b51feSCy Schubert /* Function: nat_extraflush */ 67273b9b51feSCy Schubert /* Returns: int - 0 == success, -1 == failure */ 67283b9b51feSCy Schubert /* Parameters: softc(I) - pointer to soft context main structure */ 67293b9b51feSCy Schubert /* softn(I) - pointer to NAT context structure */ 67303b9b51feSCy Schubert /* which(I) - how to flush the active NAT table */ 67313b9b51feSCy Schubert /* Write Locks: ipf_nat */ 67323b9b51feSCy Schubert /* */ 67333b9b51feSCy Schubert /* Flush nat tables. Three actions currently defined: */ 67343b9b51feSCy Schubert /* which == 0 : flush all nat table entries */ 67353b9b51feSCy Schubert /* which == 1 : flush TCP connections which have started to close but are */ 67363b9b51feSCy Schubert /* stuck for some reason. */ 67373b9b51feSCy Schubert /* which == 2 : flush TCP connections which have been idle for a long time, */ 67383b9b51feSCy Schubert /* starting at > 4 days idle and working back in successive half-*/ 67393b9b51feSCy Schubert /* days to at most 12 hours old. If this fails to free enough */ 67403b9b51feSCy Schubert /* slots then work backwards in half hour slots to 30 minutes. */ 67413b9b51feSCy Schubert /* If that too fails, then work backwards in 30 second intervals */ 67423b9b51feSCy Schubert /* for the last 30 minutes to at worst 30 seconds idle. */ 67433b9b51feSCy Schubert /* ------------------------------------------------------------------------ */ 67443b9b51feSCy Schubert static int 67453b9b51feSCy Schubert ipf_nat_extraflush(softc, softn, which) 67463b9b51feSCy Schubert ipf_main_softc_t *softc; 67473b9b51feSCy Schubert ipf_nat_softc_t *softn; 67483b9b51feSCy Schubert int which; 67493b9b51feSCy Schubert { 67503b9b51feSCy Schubert nat_t *nat, **natp; 67513b9b51feSCy Schubert ipftqent_t *tqn; 67523b9b51feSCy Schubert ipftq_t *ifq; 67533b9b51feSCy Schubert int removed; 67543b9b51feSCy Schubert SPL_INT(s); 67553b9b51feSCy Schubert 67563b9b51feSCy Schubert removed = 0; 67573b9b51feSCy Schubert 67583b9b51feSCy Schubert SPL_NET(s); 67593b9b51feSCy Schubert switch (which) 67603b9b51feSCy Schubert { 67613b9b51feSCy Schubert case 0 : 67623b9b51feSCy Schubert softn->ipf_nat_stats.ns_flush_all++; 67633b9b51feSCy Schubert /* 67643b9b51feSCy Schubert * Style 0 flush removes everything... 67653b9b51feSCy Schubert */ 67663b9b51feSCy Schubert for (natp = &softn->ipf_nat_instances; 67673b9b51feSCy Schubert ((nat = *natp) != NULL); ) { 67683b9b51feSCy Schubert ipf_nat_delete(softc, nat, NL_FLUSH); 67693b9b51feSCy Schubert removed++; 67703b9b51feSCy Schubert } 67713b9b51feSCy Schubert break; 67723b9b51feSCy Schubert 67733b9b51feSCy Schubert case 1 : 67743b9b51feSCy Schubert softn->ipf_nat_stats.ns_flush_closing++; 67753b9b51feSCy Schubert /* 67763b9b51feSCy Schubert * Since we're only interested in things that are closing, 67773b9b51feSCy Schubert * we can start with the appropriate timeout queue. 67783b9b51feSCy Schubert */ 67793b9b51feSCy Schubert for (ifq = softn->ipf_nat_tcptq + IPF_TCPS_CLOSE_WAIT; 67803b9b51feSCy Schubert ifq != NULL; ifq = ifq->ifq_next) { 67813b9b51feSCy Schubert 67823b9b51feSCy Schubert for (tqn = ifq->ifq_head; tqn != NULL; ) { 67833b9b51feSCy Schubert nat = tqn->tqe_parent; 67843b9b51feSCy Schubert tqn = tqn->tqe_next; 67853b9b51feSCy Schubert if (nat->nat_pr[0] != IPPROTO_TCP || 67863b9b51feSCy Schubert nat->nat_pr[1] != IPPROTO_TCP) 67873b9b51feSCy Schubert break; 67883b9b51feSCy Schubert ipf_nat_delete(softc, nat, NL_EXPIRE); 67893b9b51feSCy Schubert removed++; 67903b9b51feSCy Schubert } 67913b9b51feSCy Schubert } 67923b9b51feSCy Schubert 67933b9b51feSCy Schubert /* 67943b9b51feSCy Schubert * Also need to look through the user defined queues. 67953b9b51feSCy Schubert */ 67963b9b51feSCy Schubert for (ifq = softn->ipf_nat_utqe; ifq != NULL; 67973b9b51feSCy Schubert ifq = ifq->ifq_next) { 67983b9b51feSCy Schubert for (tqn = ifq->ifq_head; tqn != NULL; ) { 67993b9b51feSCy Schubert nat = tqn->tqe_parent; 68003b9b51feSCy Schubert tqn = tqn->tqe_next; 68013b9b51feSCy Schubert if (nat->nat_pr[0] != IPPROTO_TCP || 68023b9b51feSCy Schubert nat->nat_pr[1] != IPPROTO_TCP) 68033b9b51feSCy Schubert continue; 68043b9b51feSCy Schubert 68053b9b51feSCy Schubert if ((nat->nat_tcpstate[0] > 68063b9b51feSCy Schubert IPF_TCPS_ESTABLISHED) && 68073b9b51feSCy Schubert (nat->nat_tcpstate[1] > 68083b9b51feSCy Schubert IPF_TCPS_ESTABLISHED)) { 68093b9b51feSCy Schubert ipf_nat_delete(softc, nat, NL_EXPIRE); 68103b9b51feSCy Schubert removed++; 68113b9b51feSCy Schubert } 68123b9b51feSCy Schubert } 68133b9b51feSCy Schubert } 68143b9b51feSCy Schubert break; 68153b9b51feSCy Schubert 68163b9b51feSCy Schubert /* 68173b9b51feSCy Schubert * Args 5-11 correspond to flushing those particular states 68183b9b51feSCy Schubert * for TCP connections. 68193b9b51feSCy Schubert */ 68203b9b51feSCy Schubert case IPF_TCPS_CLOSE_WAIT : 68213b9b51feSCy Schubert case IPF_TCPS_FIN_WAIT_1 : 68223b9b51feSCy Schubert case IPF_TCPS_CLOSING : 68233b9b51feSCy Schubert case IPF_TCPS_LAST_ACK : 68243b9b51feSCy Schubert case IPF_TCPS_FIN_WAIT_2 : 68253b9b51feSCy Schubert case IPF_TCPS_TIME_WAIT : 68263b9b51feSCy Schubert case IPF_TCPS_CLOSED : 68273b9b51feSCy Schubert softn->ipf_nat_stats.ns_flush_state++; 68283b9b51feSCy Schubert tqn = softn->ipf_nat_tcptq[which].ifq_head; 68293b9b51feSCy Schubert while (tqn != NULL) { 68303b9b51feSCy Schubert nat = tqn->tqe_parent; 68313b9b51feSCy Schubert tqn = tqn->tqe_next; 68323b9b51feSCy Schubert ipf_nat_delete(softc, nat, NL_FLUSH); 68333b9b51feSCy Schubert removed++; 68343b9b51feSCy Schubert } 68353b9b51feSCy Schubert break; 68363b9b51feSCy Schubert 68373b9b51feSCy Schubert default : 68383b9b51feSCy Schubert if (which < 30) 68393b9b51feSCy Schubert break; 68403b9b51feSCy Schubert 68413b9b51feSCy Schubert softn->ipf_nat_stats.ns_flush_timeout++; 68423b9b51feSCy Schubert /* 68433b9b51feSCy Schubert * Take a large arbitrary number to mean the number of seconds 68443b9b51feSCy Schubert * for which which consider to be the maximum value we'll allow 68453b9b51feSCy Schubert * the expiration to be. 68463b9b51feSCy Schubert */ 68473b9b51feSCy Schubert which = IPF_TTLVAL(which); 68483b9b51feSCy Schubert for (natp = &softn->ipf_nat_instances; 68493b9b51feSCy Schubert ((nat = *natp) != NULL); ) { 68503b9b51feSCy Schubert if (softc->ipf_ticks - nat->nat_touched > which) { 68513b9b51feSCy Schubert ipf_nat_delete(softc, nat, NL_FLUSH); 68523b9b51feSCy Schubert removed++; 68533b9b51feSCy Schubert } else 68543b9b51feSCy Schubert natp = &nat->nat_next; 68553b9b51feSCy Schubert } 68563b9b51feSCy Schubert break; 68573b9b51feSCy Schubert } 68583b9b51feSCy Schubert 68593b9b51feSCy Schubert if (which != 2) { 68603b9b51feSCy Schubert SPL_X(s); 68613b9b51feSCy Schubert return removed; 68623b9b51feSCy Schubert } 68633b9b51feSCy Schubert 68643b9b51feSCy Schubert softn->ipf_nat_stats.ns_flush_queue++; 68653b9b51feSCy Schubert 68663b9b51feSCy Schubert /* 68673b9b51feSCy Schubert * Asked to remove inactive entries because the table is full, try 68683b9b51feSCy Schubert * again, 3 times, if first attempt failed with a different criteria 68693b9b51feSCy Schubert * each time. The order tried in must be in decreasing age. 68703b9b51feSCy Schubert * Another alternative is to implement random drop and drop N entries 68713b9b51feSCy Schubert * at random until N have been freed up. 68723b9b51feSCy Schubert */ 68733b9b51feSCy Schubert if (softc->ipf_ticks - softn->ipf_nat_last_force_flush > 68743b9b51feSCy Schubert IPF_TTLVAL(5)) { 68753b9b51feSCy Schubert softn->ipf_nat_last_force_flush = softc->ipf_ticks; 68763b9b51feSCy Schubert 68773b9b51feSCy Schubert removed = ipf_queueflush(softc, ipf_nat_flush_entry, 68783b9b51feSCy Schubert softn->ipf_nat_tcptq, 68793b9b51feSCy Schubert softn->ipf_nat_utqe, 68803b9b51feSCy Schubert &softn->ipf_nat_stats.ns_active, 68813b9b51feSCy Schubert softn->ipf_nat_table_sz, 68823b9b51feSCy Schubert softn->ipf_nat_table_wm_low); 68833b9b51feSCy Schubert } 68843b9b51feSCy Schubert 68853b9b51feSCy Schubert SPL_X(s); 68863b9b51feSCy Schubert return removed; 68873b9b51feSCy Schubert } 68883b9b51feSCy Schubert 68893b9b51feSCy Schubert 68903b9b51feSCy Schubert /* ------------------------------------------------------------------------ */ 68913b9b51feSCy Schubert /* Function: ipf_nat_flush_entry */ 68923b9b51feSCy Schubert /* Returns: 0 - always succeeds */ 68933b9b51feSCy Schubert /* Parameters: softc(I) - pointer to soft context main structure */ 68943b9b51feSCy Schubert /* entry(I) - pointer to NAT entry */ 68953b9b51feSCy Schubert /* Write Locks: ipf_nat */ 68963b9b51feSCy Schubert /* */ 68973b9b51feSCy Schubert /* This function is a stepping stone between ipf_queueflush() and */ 68983b9b51feSCy Schubert /* nat_dlete(). It is used so we can provide a uniform interface via the */ 68993b9b51feSCy Schubert /* ipf_queueflush() function. Since the nat_delete() function returns void */ 69003b9b51feSCy Schubert /* we translate that to mean it always succeeds in deleting something. */ 69013b9b51feSCy Schubert /* ------------------------------------------------------------------------ */ 69023b9b51feSCy Schubert static int 69033b9b51feSCy Schubert ipf_nat_flush_entry(softc, entry) 69043b9b51feSCy Schubert ipf_main_softc_t *softc; 69053b9b51feSCy Schubert void *entry; 69063b9b51feSCy Schubert { 69073b9b51feSCy Schubert ipf_nat_delete(softc, entry, NL_FLUSH); 69083b9b51feSCy Schubert return 0; 69093b9b51feSCy Schubert } 69103b9b51feSCy Schubert 69113b9b51feSCy Schubert 69123b9b51feSCy Schubert /* ------------------------------------------------------------------------ */ 69133b9b51feSCy Schubert /* Function: ipf_nat_iterator */ 69143b9b51feSCy Schubert /* Returns: int - 0 == ok, else error */ 69153b9b51feSCy Schubert /* Parameters: softc(I) - pointer to soft context main structure */ 69163b9b51feSCy Schubert /* token(I) - pointer to ipftoken structure */ 69173b9b51feSCy Schubert /* itp(I) - pointer to ipfgeniter_t structure */ 69183b9b51feSCy Schubert /* obj(I) - pointer to data description structure */ 69193b9b51feSCy Schubert /* */ 69203b9b51feSCy Schubert /* This function acts as a handler for the SIOCGENITER ioctls that use a */ 69213b9b51feSCy Schubert /* generic structure to iterate through a list. There are three different */ 69223b9b51feSCy Schubert /* linked lists of NAT related information to go through: NAT rules, active */ 69233b9b51feSCy Schubert /* NAT mappings and the NAT fragment cache. */ 69243b9b51feSCy Schubert /* ------------------------------------------------------------------------ */ 69253b9b51feSCy Schubert static int 69263b9b51feSCy Schubert ipf_nat_iterator(softc, token, itp, obj) 69273b9b51feSCy Schubert ipf_main_softc_t *softc; 69283b9b51feSCy Schubert ipftoken_t *token; 69293b9b51feSCy Schubert ipfgeniter_t *itp; 69303b9b51feSCy Schubert ipfobj_t *obj; 69313b9b51feSCy Schubert { 69323b9b51feSCy Schubert int error; 69333b9b51feSCy Schubert 69343b9b51feSCy Schubert if (itp->igi_data == NULL) { 69353b9b51feSCy Schubert IPFERROR(60052); 69363b9b51feSCy Schubert return EFAULT; 69373b9b51feSCy Schubert } 69383b9b51feSCy Schubert 69393b9b51feSCy Schubert switch (itp->igi_type) 69403b9b51feSCy Schubert { 69413b9b51feSCy Schubert case IPFGENITER_HOSTMAP : 69423b9b51feSCy Schubert case IPFGENITER_IPNAT : 69433b9b51feSCy Schubert case IPFGENITER_NAT : 69443b9b51feSCy Schubert error = ipf_nat_getnext(softc, token, itp, obj); 69453b9b51feSCy Schubert break; 69463b9b51feSCy Schubert 69473b9b51feSCy Schubert case IPFGENITER_NATFRAG : 69483b9b51feSCy Schubert error = ipf_frag_nat_next(softc, token, itp); 69493b9b51feSCy Schubert break; 69503b9b51feSCy Schubert default : 69513b9b51feSCy Schubert IPFERROR(60053); 69523b9b51feSCy Schubert error = EINVAL; 69533b9b51feSCy Schubert break; 69543b9b51feSCy Schubert } 69553b9b51feSCy Schubert 69563b9b51feSCy Schubert return error; 69573b9b51feSCy Schubert } 69583b9b51feSCy Schubert 69593b9b51feSCy Schubert 69603b9b51feSCy Schubert /* ------------------------------------------------------------------------ */ 69613b9b51feSCy Schubert /* Function: ipf_nat_setpending */ 69623b9b51feSCy Schubert /* Returns: Nil */ 69633b9b51feSCy Schubert /* Parameters: softc(I) - pointer to soft context main structure */ 69643b9b51feSCy Schubert /* nat(I) - pointer to NAT structure */ 69653b9b51feSCy Schubert /* Locks: ipf_nat (read or write) */ 69663b9b51feSCy Schubert /* */ 69673b9b51feSCy Schubert /* Put the NAT entry on to the pending queue - this queue has a very short */ 69683b9b51feSCy Schubert /* lifetime where items are put that can't be deleted straight away because */ 69693b9b51feSCy Schubert /* of locking issues but we want to delete them ASAP, anyway. In calling */ 69703b9b51feSCy Schubert /* this function, it is assumed that the owner (if there is one, as shown */ 69713b9b51feSCy Schubert /* by nat_me) is no longer interested in it. */ 69723b9b51feSCy Schubert /* ------------------------------------------------------------------------ */ 69733b9b51feSCy Schubert void 69743b9b51feSCy Schubert ipf_nat_setpending(softc, nat) 69753b9b51feSCy Schubert ipf_main_softc_t *softc; 69763b9b51feSCy Schubert nat_t *nat; 69773b9b51feSCy Schubert { 69783b9b51feSCy Schubert ipf_nat_softc_t *softn = softc->ipf_nat_soft; 69793b9b51feSCy Schubert ipftq_t *oifq; 69803b9b51feSCy Schubert 69813b9b51feSCy Schubert oifq = nat->nat_tqe.tqe_ifq; 69823b9b51feSCy Schubert if (oifq != NULL) 69833b9b51feSCy Schubert ipf_movequeue(softc->ipf_ticks, &nat->nat_tqe, oifq, 69843b9b51feSCy Schubert &softn->ipf_nat_pending); 69853b9b51feSCy Schubert else 69863b9b51feSCy Schubert ipf_queueappend(softc->ipf_ticks, &nat->nat_tqe, 69873b9b51feSCy Schubert &softn->ipf_nat_pending, nat); 69883b9b51feSCy Schubert 69893b9b51feSCy Schubert if (nat->nat_me != NULL) { 69903b9b51feSCy Schubert *nat->nat_me = NULL; 69913b9b51feSCy Schubert nat->nat_me = NULL; 69923b9b51feSCy Schubert nat->nat_ref--; 69933b9b51feSCy Schubert ASSERT(nat->nat_ref >= 0); 69943b9b51feSCy Schubert } 69953b9b51feSCy Schubert } 69963b9b51feSCy Schubert 69973b9b51feSCy Schubert 69983b9b51feSCy Schubert /* ------------------------------------------------------------------------ */ 69993b9b51feSCy Schubert /* Function: nat_newrewrite */ 70003b9b51feSCy Schubert /* Returns: int - -1 == error, 0 == success (no move), 1 == success and */ 70013b9b51feSCy Schubert /* allow rule to be moved if IPN_ROUNDR is set. */ 70023b9b51feSCy Schubert /* Parameters: fin(I) - pointer to packet information */ 70033b9b51feSCy Schubert /* nat(I) - pointer to NAT entry */ 70043b9b51feSCy Schubert /* ni(I) - pointer to structure with misc. information needed */ 70053b9b51feSCy Schubert /* to create new NAT entry. */ 70063b9b51feSCy Schubert /* Write Lock: ipf_nat */ 70073b9b51feSCy Schubert /* */ 70083b9b51feSCy Schubert /* This function is responsible for setting up an active NAT session where */ 70093b9b51feSCy Schubert /* we are changing both the source and destination parameters at the same */ 70103b9b51feSCy Schubert /* time. The loop in here works differently to elsewhere - each iteration */ 70113b9b51feSCy Schubert /* is responsible for changing a single parameter that can be incremented. */ 70123b9b51feSCy Schubert /* So one pass may increase the source IP#, next source port, next dest. IP#*/ 70133b9b51feSCy Schubert /* and the last destination port for a total of 4 iterations to try each. */ 70143b9b51feSCy Schubert /* This is done to try and exhaustively use the translation space available.*/ 70153b9b51feSCy Schubert /* ------------------------------------------------------------------------ */ 70163b9b51feSCy Schubert static int 70173b9b51feSCy Schubert ipf_nat_newrewrite(fin, nat, nai) 70183b9b51feSCy Schubert fr_info_t *fin; 70193b9b51feSCy Schubert nat_t *nat; 70203b9b51feSCy Schubert natinfo_t *nai; 70213b9b51feSCy Schubert { 70223b9b51feSCy Schubert int src_search = 1; 70233b9b51feSCy Schubert int dst_search = 1; 70243b9b51feSCy Schubert fr_info_t frnat; 70253b9b51feSCy Schubert u_32_t flags; 70263b9b51feSCy Schubert u_short swap; 70273b9b51feSCy Schubert ipnat_t *np; 70283b9b51feSCy Schubert nat_t *natl; 70293b9b51feSCy Schubert int l = 0; 70303b9b51feSCy Schubert int changed; 70313b9b51feSCy Schubert 70323b9b51feSCy Schubert natl = NULL; 70333b9b51feSCy Schubert changed = -1; 70343b9b51feSCy Schubert np = nai->nai_np; 70353b9b51feSCy Schubert flags = nat->nat_flags; 70363b9b51feSCy Schubert bcopy((char *)fin, (char *)&frnat, sizeof(*fin)); 70373b9b51feSCy Schubert 70383b9b51feSCy Schubert nat->nat_hm = NULL; 70393b9b51feSCy Schubert 70403b9b51feSCy Schubert do { 70413b9b51feSCy Schubert changed = -1; 70423b9b51feSCy Schubert /* TRACE (l, src_search, dst_search, np) */ 70433b9b51feSCy Schubert DT4(ipf_nat_rewrite_1, int, l, int, src_search, int, dst_search, ipnat_t *, np); 70443b9b51feSCy Schubert 70453b9b51feSCy Schubert if ((src_search == 0) && (np->in_spnext == 0) && 70463b9b51feSCy Schubert (dst_search == 0) && (np->in_dpnext == 0)) { 70473b9b51feSCy Schubert if (l > 0) 70483b9b51feSCy Schubert return -1; 70493b9b51feSCy Schubert } 70503b9b51feSCy Schubert 70513b9b51feSCy Schubert /* 70523b9b51feSCy Schubert * Find a new source address 70533b9b51feSCy Schubert */ 70543b9b51feSCy Schubert if (ipf_nat_nextaddr(fin, &np->in_nsrc, &frnat.fin_saddr, 70553b9b51feSCy Schubert &frnat.fin_saddr) == -1) { 70563b9b51feSCy Schubert return -1; 70573b9b51feSCy Schubert } 70583b9b51feSCy Schubert 70593b9b51feSCy Schubert if ((np->in_nsrcaddr == 0) && (np->in_nsrcmsk == 0xffffffff)) { 70603b9b51feSCy Schubert src_search = 0; 70613b9b51feSCy Schubert if (np->in_stepnext == 0) 70623b9b51feSCy Schubert np->in_stepnext = 1; 70633b9b51feSCy Schubert 70643b9b51feSCy Schubert } else if ((np->in_nsrcaddr == 0) && (np->in_nsrcmsk == 0)) { 70653b9b51feSCy Schubert src_search = 0; 70663b9b51feSCy Schubert if (np->in_stepnext == 0) 70673b9b51feSCy Schubert np->in_stepnext = 1; 70683b9b51feSCy Schubert 70693b9b51feSCy Schubert } else if (np->in_nsrcmsk == 0xffffffff) { 70703b9b51feSCy Schubert src_search = 0; 70713b9b51feSCy Schubert if (np->in_stepnext == 0) 70723b9b51feSCy Schubert np->in_stepnext = 1; 70733b9b51feSCy Schubert 70743b9b51feSCy Schubert } else if (np->in_nsrcmsk != 0xffffffff) { 70753b9b51feSCy Schubert if (np->in_stepnext == 0 && changed == -1) { 70763b9b51feSCy Schubert np->in_snip++; 70773b9b51feSCy Schubert np->in_stepnext++; 70783b9b51feSCy Schubert changed = 0; 70793b9b51feSCy Schubert } 70803b9b51feSCy Schubert } 70813b9b51feSCy Schubert 70823b9b51feSCy Schubert if ((flags & IPN_TCPUDPICMP) != 0) { 70833b9b51feSCy Schubert if (np->in_spnext != 0) 70843b9b51feSCy Schubert frnat.fin_data[0] = np->in_spnext; 70853b9b51feSCy Schubert 70863b9b51feSCy Schubert /* 70873b9b51feSCy Schubert * Standard port translation. Select next port. 70883b9b51feSCy Schubert */ 70893b9b51feSCy Schubert if ((flags & IPN_FIXEDSPORT) != 0) { 70903b9b51feSCy Schubert np->in_stepnext = 2; 70913b9b51feSCy Schubert } else if ((np->in_stepnext == 1) && 70923b9b51feSCy Schubert (changed == -1) && (natl != NULL)) { 70933b9b51feSCy Schubert np->in_spnext++; 70943b9b51feSCy Schubert np->in_stepnext++; 70953b9b51feSCy Schubert changed = 1; 70963b9b51feSCy Schubert if (np->in_spnext > np->in_spmax) 70973b9b51feSCy Schubert np->in_spnext = np->in_spmin; 70983b9b51feSCy Schubert } 70993b9b51feSCy Schubert } else { 71003b9b51feSCy Schubert np->in_stepnext = 2; 71013b9b51feSCy Schubert } 71023b9b51feSCy Schubert np->in_stepnext &= 0x3; 71033b9b51feSCy Schubert 71043b9b51feSCy Schubert /* 71053b9b51feSCy Schubert * Find a new destination address 71063b9b51feSCy Schubert */ 71073b9b51feSCy Schubert /* TRACE (fin, np, l, frnat) */ 71083b9b51feSCy Schubert DT4(ipf_nat_rewrite_2, frinfo_t *, fin, ipnat_t *, np, int, l, frinfo_t *, &frnat); 71093b9b51feSCy Schubert 71103b9b51feSCy Schubert if (ipf_nat_nextaddr(fin, &np->in_ndst, &frnat.fin_daddr, 71113b9b51feSCy Schubert &frnat.fin_daddr) == -1) 71123b9b51feSCy Schubert return -1; 71133b9b51feSCy Schubert if ((np->in_ndstaddr == 0) && (np->in_ndstmsk == 0xffffffff)) { 71143b9b51feSCy Schubert dst_search = 0; 71153b9b51feSCy Schubert if (np->in_stepnext == 2) 71163b9b51feSCy Schubert np->in_stepnext = 3; 71173b9b51feSCy Schubert 71183b9b51feSCy Schubert } else if ((np->in_ndstaddr == 0) && (np->in_ndstmsk == 0)) { 71193b9b51feSCy Schubert dst_search = 0; 71203b9b51feSCy Schubert if (np->in_stepnext == 2) 71213b9b51feSCy Schubert np->in_stepnext = 3; 71223b9b51feSCy Schubert 71233b9b51feSCy Schubert } else if (np->in_ndstmsk == 0xffffffff) { 71243b9b51feSCy Schubert dst_search = 0; 71253b9b51feSCy Schubert if (np->in_stepnext == 2) 71263b9b51feSCy Schubert np->in_stepnext = 3; 71273b9b51feSCy Schubert 71283b9b51feSCy Schubert } else if (np->in_ndstmsk != 0xffffffff) { 71293b9b51feSCy Schubert if ((np->in_stepnext == 2) && (changed == -1) && 71303b9b51feSCy Schubert (natl != NULL)) { 71313b9b51feSCy Schubert changed = 2; 71323b9b51feSCy Schubert np->in_stepnext++; 71333b9b51feSCy Schubert np->in_dnip++; 71343b9b51feSCy Schubert } 71353b9b51feSCy Schubert } 71363b9b51feSCy Schubert 71373b9b51feSCy Schubert if ((flags & IPN_TCPUDPICMP) != 0) { 71383b9b51feSCy Schubert if (np->in_dpnext != 0) 71393b9b51feSCy Schubert frnat.fin_data[1] = np->in_dpnext; 71403b9b51feSCy Schubert 71413b9b51feSCy Schubert /* 71423b9b51feSCy Schubert * Standard port translation. Select next port. 71433b9b51feSCy Schubert */ 71443b9b51feSCy Schubert if ((flags & IPN_FIXEDDPORT) != 0) { 71453b9b51feSCy Schubert np->in_stepnext = 0; 71463b9b51feSCy Schubert } else if (np->in_stepnext == 3 && changed == -1) { 71473b9b51feSCy Schubert np->in_dpnext++; 71483b9b51feSCy Schubert np->in_stepnext++; 71493b9b51feSCy Schubert changed = 3; 71503b9b51feSCy Schubert if (np->in_dpnext > np->in_dpmax) 71513b9b51feSCy Schubert np->in_dpnext = np->in_dpmin; 71523b9b51feSCy Schubert } 71533b9b51feSCy Schubert } else { 71543b9b51feSCy Schubert if (np->in_stepnext == 3) 71553b9b51feSCy Schubert np->in_stepnext = 0; 71563b9b51feSCy Schubert } 71573b9b51feSCy Schubert 71583b9b51feSCy Schubert /* TRACE (frnat) */ 71593b9b51feSCy Schubert DT1(ipf_nat_rewrite_3, frinfo_t *, &frnat); 71603b9b51feSCy Schubert 71613b9b51feSCy Schubert /* 71623b9b51feSCy Schubert * Here we do a lookup of the connection as seen from 71633b9b51feSCy Schubert * the outside. If an IP# pair already exists, try 71643b9b51feSCy Schubert * again. So if you have A->B becomes C->B, you can 71653b9b51feSCy Schubert * also have D->E become C->E but not D->B causing 71663b9b51feSCy Schubert * another C->B. Also take protocol and ports into 71673b9b51feSCy Schubert * account when determining whether a pre-existing 71683b9b51feSCy Schubert * NAT setup will cause an external conflict where 71693b9b51feSCy Schubert * this is appropriate. 71703b9b51feSCy Schubert * 71713b9b51feSCy Schubert * fin_data[] is swapped around because we are doing a 71723b9b51feSCy Schubert * lookup of the packet is if it were moving in the opposite 71733b9b51feSCy Schubert * direction of the one we are working with now. 71743b9b51feSCy Schubert */ 71753b9b51feSCy Schubert if (flags & IPN_TCPUDP) { 71763b9b51feSCy Schubert swap = frnat.fin_data[0]; 71773b9b51feSCy Schubert frnat.fin_data[0] = frnat.fin_data[1]; 71783b9b51feSCy Schubert frnat.fin_data[1] = swap; 71793b9b51feSCy Schubert } 71803b9b51feSCy Schubert if (fin->fin_out == 1) { 71813b9b51feSCy Schubert natl = ipf_nat_inlookup(&frnat, 71823b9b51feSCy Schubert flags & ~(SI_WILDP|NAT_SEARCH), 71833b9b51feSCy Schubert (u_int)frnat.fin_p, 71843b9b51feSCy Schubert frnat.fin_dst, frnat.fin_src); 71853b9b51feSCy Schubert 71863b9b51feSCy Schubert } else { 71873b9b51feSCy Schubert natl = ipf_nat_outlookup(&frnat, 71883b9b51feSCy Schubert flags & ~(SI_WILDP|NAT_SEARCH), 71893b9b51feSCy Schubert (u_int)frnat.fin_p, 71903b9b51feSCy Schubert frnat.fin_dst, frnat.fin_src); 71913b9b51feSCy Schubert } 71923b9b51feSCy Schubert if (flags & IPN_TCPUDP) { 71933b9b51feSCy Schubert swap = frnat.fin_data[0]; 71943b9b51feSCy Schubert frnat.fin_data[0] = frnat.fin_data[1]; 71953b9b51feSCy Schubert frnat.fin_data[1] = swap; 71963b9b51feSCy Schubert } 71973b9b51feSCy Schubert 71983b9b51feSCy Schubert /* TRACE natl, in_stepnext, l */ 71993b9b51feSCy Schubert DT3(ipf_nat_rewrite_2, nat_t *, natl, ipnat_t *, np , int, l); 72003b9b51feSCy Schubert 72013b9b51feSCy Schubert if ((natl != NULL) && (l > 8)) /* XXX 8 is arbitrary */ 72023b9b51feSCy Schubert return -1; 72033b9b51feSCy Schubert 72043b9b51feSCy Schubert np->in_stepnext &= 0x3; 72053b9b51feSCy Schubert 72063b9b51feSCy Schubert l++; 72073b9b51feSCy Schubert changed = -1; 72083b9b51feSCy Schubert } while (natl != NULL); 72093b9b51feSCy Schubert 72103b9b51feSCy Schubert nat->nat_osrcip = fin->fin_src; 72113b9b51feSCy Schubert nat->nat_odstip = fin->fin_dst; 72123b9b51feSCy Schubert nat->nat_nsrcip = frnat.fin_src; 72133b9b51feSCy Schubert nat->nat_ndstip = frnat.fin_dst; 72143b9b51feSCy Schubert 72153b9b51feSCy Schubert if ((flags & IPN_TCPUDP) != 0) { 72163b9b51feSCy Schubert nat->nat_osport = htons(fin->fin_data[0]); 72173b9b51feSCy Schubert nat->nat_odport = htons(fin->fin_data[1]); 72183b9b51feSCy Schubert nat->nat_nsport = htons(frnat.fin_data[0]); 72193b9b51feSCy Schubert nat->nat_ndport = htons(frnat.fin_data[1]); 72203b9b51feSCy Schubert } else if ((flags & IPN_ICMPQUERY) != 0) { 72213b9b51feSCy Schubert nat->nat_oicmpid = fin->fin_data[1]; 72223b9b51feSCy Schubert nat->nat_nicmpid = frnat.fin_data[1]; 72233b9b51feSCy Schubert } 72243b9b51feSCy Schubert 72253b9b51feSCy Schubert return 0; 72263b9b51feSCy Schubert } 72273b9b51feSCy Schubert 72283b9b51feSCy Schubert 72293b9b51feSCy Schubert /* ------------------------------------------------------------------------ */ 72303b9b51feSCy Schubert /* Function: nat_newdivert */ 72313b9b51feSCy Schubert /* Returns: int - -1 == error, 0 == success */ 72323b9b51feSCy Schubert /* Parameters: fin(I) - pointer to packet information */ 72333b9b51feSCy Schubert /* nat(I) - pointer to NAT entry */ 72343b9b51feSCy Schubert /* ni(I) - pointer to structure with misc. information needed */ 72353b9b51feSCy Schubert /* to create new NAT entry. */ 72363b9b51feSCy Schubert /* Write Lock: ipf_nat */ 72373b9b51feSCy Schubert /* */ 72383b9b51feSCy Schubert /* Create a new NAT divert session as defined by the NAT rule. This is */ 72393b9b51feSCy Schubert /* somewhat different to other NAT session creation routines because we */ 72403b9b51feSCy Schubert /* do not iterate through either port numbers or IP addresses, searching */ 72413b9b51feSCy Schubert /* for a unique mapping, however, a complimentary duplicate check is made. */ 72423b9b51feSCy Schubert /* ------------------------------------------------------------------------ */ 72433b9b51feSCy Schubert static int 72443b9b51feSCy Schubert ipf_nat_newdivert(fin, nat, nai) 72453b9b51feSCy Schubert fr_info_t *fin; 72463b9b51feSCy Schubert nat_t *nat; 72473b9b51feSCy Schubert natinfo_t *nai; 72483b9b51feSCy Schubert { 72493b9b51feSCy Schubert ipf_main_softc_t *softc = fin->fin_main_soft; 72503b9b51feSCy Schubert ipf_nat_softc_t *softn = softc->ipf_nat_soft; 72513b9b51feSCy Schubert fr_info_t frnat; 72523b9b51feSCy Schubert ipnat_t *np; 72533b9b51feSCy Schubert nat_t *natl; 72543b9b51feSCy Schubert int p; 72553b9b51feSCy Schubert 72563b9b51feSCy Schubert np = nai->nai_np; 72573b9b51feSCy Schubert bcopy((char *)fin, (char *)&frnat, sizeof(*fin)); 72583b9b51feSCy Schubert 72593b9b51feSCy Schubert nat->nat_pr[0] = 0; 72603b9b51feSCy Schubert nat->nat_osrcaddr = fin->fin_saddr; 72613b9b51feSCy Schubert nat->nat_odstaddr = fin->fin_daddr; 72623b9b51feSCy Schubert frnat.fin_saddr = htonl(np->in_snip); 72633b9b51feSCy Schubert frnat.fin_daddr = htonl(np->in_dnip); 72643b9b51feSCy Schubert if ((nat->nat_flags & IPN_TCPUDP) != 0) { 72653b9b51feSCy Schubert nat->nat_osport = htons(fin->fin_data[0]); 72663b9b51feSCy Schubert nat->nat_odport = htons(fin->fin_data[1]); 72673b9b51feSCy Schubert } else if ((nat->nat_flags & IPN_ICMPQUERY) != 0) { 72683b9b51feSCy Schubert nat->nat_oicmpid = fin->fin_data[1]; 72693b9b51feSCy Schubert } 72703b9b51feSCy Schubert 72713b9b51feSCy Schubert if (np->in_redir & NAT_DIVERTUDP) { 72723b9b51feSCy Schubert frnat.fin_data[0] = np->in_spnext; 72733b9b51feSCy Schubert frnat.fin_data[1] = np->in_dpnext; 72743b9b51feSCy Schubert frnat.fin_flx |= FI_TCPUDP; 72753b9b51feSCy Schubert p = IPPROTO_UDP; 72763b9b51feSCy Schubert } else { 72773b9b51feSCy Schubert frnat.fin_flx &= ~FI_TCPUDP; 72783b9b51feSCy Schubert p = IPPROTO_IPIP; 72793b9b51feSCy Schubert } 72803b9b51feSCy Schubert 72813b9b51feSCy Schubert if (fin->fin_out == 1) { 72823b9b51feSCy Schubert natl = ipf_nat_inlookup(&frnat, 0, p, 72833b9b51feSCy Schubert frnat.fin_dst, frnat.fin_src); 72843b9b51feSCy Schubert 72853b9b51feSCy Schubert } else { 72863b9b51feSCy Schubert natl = ipf_nat_outlookup(&frnat, 0, p, 72873b9b51feSCy Schubert frnat.fin_dst, frnat.fin_src); 72883b9b51feSCy Schubert } 72893b9b51feSCy Schubert 72903b9b51feSCy Schubert if (natl != NULL) { 72913b9b51feSCy Schubert NBUMPSIDED(fin->fin_out, ns_divert_exist); 72923b9b51feSCy Schubert DT3(ns_divert_exist, fr_info_t *, fin, nat_t *, nat, natinfo_t, nai); 72933b9b51feSCy Schubert return -1; 72943b9b51feSCy Schubert } 72953b9b51feSCy Schubert 72963b9b51feSCy Schubert nat->nat_nsrcaddr = frnat.fin_saddr; 72973b9b51feSCy Schubert nat->nat_ndstaddr = frnat.fin_daddr; 72983b9b51feSCy Schubert if ((nat->nat_flags & IPN_TCPUDP) != 0) { 72993b9b51feSCy Schubert nat->nat_nsport = htons(frnat.fin_data[0]); 73003b9b51feSCy Schubert nat->nat_ndport = htons(frnat.fin_data[1]); 73013b9b51feSCy Schubert } else if ((nat->nat_flags & IPN_ICMPQUERY) != 0) { 73023b9b51feSCy Schubert nat->nat_nicmpid = frnat.fin_data[1]; 73033b9b51feSCy Schubert } 73043b9b51feSCy Schubert 73053b9b51feSCy Schubert nat->nat_pr[fin->fin_out] = fin->fin_p; 73063b9b51feSCy Schubert nat->nat_pr[1 - fin->fin_out] = p; 73073b9b51feSCy Schubert 73083b9b51feSCy Schubert if (np->in_redir & NAT_REDIRECT) 73093b9b51feSCy Schubert nat->nat_dir = NAT_DIVERTIN; 73103b9b51feSCy Schubert else 73113b9b51feSCy Schubert nat->nat_dir = NAT_DIVERTOUT; 73123b9b51feSCy Schubert 73133b9b51feSCy Schubert return 0; 73143b9b51feSCy Schubert } 73153b9b51feSCy Schubert 73163b9b51feSCy Schubert 73173b9b51feSCy Schubert /* ------------------------------------------------------------------------ */ 73183b9b51feSCy Schubert /* Function: nat_builddivertmp */ 73193b9b51feSCy Schubert /* Returns: int - -1 == error, 0 == success */ 73203b9b51feSCy Schubert /* Parameters: softn(I) - pointer to NAT context structure */ 73213b9b51feSCy Schubert /* np(I) - pointer to a NAT rule */ 73223b9b51feSCy Schubert /* */ 73233b9b51feSCy Schubert /* For divert rules, a skeleton packet representing what will be prepended */ 73243b9b51feSCy Schubert /* to the real packet is created. Even though we don't have the full */ 73253b9b51feSCy Schubert /* packet here, a checksum is calculated that we update later when we */ 73263b9b51feSCy Schubert /* fill in the final details. At present a 0 checksum for UDP is being set */ 73273b9b51feSCy Schubert /* here because it is expected that divert will be used for localhost. */ 73283b9b51feSCy Schubert /* ------------------------------------------------------------------------ */ 73293b9b51feSCy Schubert static int 73303b9b51feSCy Schubert ipf_nat_builddivertmp(softn, np) 73313b9b51feSCy Schubert ipf_nat_softc_t *softn; 73323b9b51feSCy Schubert ipnat_t *np; 73333b9b51feSCy Schubert { 73343b9b51feSCy Schubert udphdr_t *uh; 73353b9b51feSCy Schubert size_t len; 73363b9b51feSCy Schubert ip_t *ip; 73373b9b51feSCy Schubert 73383b9b51feSCy Schubert if ((np->in_redir & NAT_DIVERTUDP) != 0) 73393b9b51feSCy Schubert len = sizeof(ip_t) + sizeof(udphdr_t); 73403b9b51feSCy Schubert else 73413b9b51feSCy Schubert len = sizeof(ip_t); 73423b9b51feSCy Schubert 73433b9b51feSCy Schubert ALLOC_MB_T(np->in_divmp, len); 73443b9b51feSCy Schubert if (np->in_divmp == NULL) { 73453b9b51feSCy Schubert NBUMPD(ipf_nat_stats, ns_divert_build); 73463b9b51feSCy Schubert return -1; 73473b9b51feSCy Schubert } 73483b9b51feSCy Schubert 73493b9b51feSCy Schubert /* 73503b9b51feSCy Schubert * First, the header to get the packet diverted to the new destination 73513b9b51feSCy Schubert */ 73523b9b51feSCy Schubert ip = MTOD(np->in_divmp, ip_t *); 73533b9b51feSCy Schubert IP_V_A(ip, 4); 73543b9b51feSCy Schubert IP_HL_A(ip, 5); 73553b9b51feSCy Schubert ip->ip_tos = 0; 73563b9b51feSCy Schubert if ((np->in_redir & NAT_DIVERTUDP) != 0) 73573b9b51feSCy Schubert ip->ip_p = IPPROTO_UDP; 73583b9b51feSCy Schubert else 73593b9b51feSCy Schubert ip->ip_p = IPPROTO_IPIP; 73603b9b51feSCy Schubert ip->ip_ttl = 255; 73613b9b51feSCy Schubert ip->ip_off = 0; 73623b9b51feSCy Schubert ip->ip_sum = 0; 73633b9b51feSCy Schubert ip->ip_len = htons(len); 73643b9b51feSCy Schubert ip->ip_id = 0; 73653b9b51feSCy Schubert ip->ip_src.s_addr = htonl(np->in_snip); 73663b9b51feSCy Schubert ip->ip_dst.s_addr = htonl(np->in_dnip); 73673b9b51feSCy Schubert ip->ip_sum = ipf_cksum((u_short *)ip, sizeof(*ip)); 73683b9b51feSCy Schubert 73693b9b51feSCy Schubert if (np->in_redir & NAT_DIVERTUDP) { 73703b9b51feSCy Schubert uh = (udphdr_t *)(ip + 1); 73713b9b51feSCy Schubert uh->uh_sum = 0; 73723b9b51feSCy Schubert uh->uh_ulen = 8; 73733b9b51feSCy Schubert uh->uh_sport = htons(np->in_spnext); 73743b9b51feSCy Schubert uh->uh_dport = htons(np->in_dpnext); 73753b9b51feSCy Schubert } 73763b9b51feSCy Schubert 73773b9b51feSCy Schubert return 0; 73783b9b51feSCy Schubert } 73793b9b51feSCy Schubert 73803b9b51feSCy Schubert 73813b9b51feSCy Schubert #define MINDECAP (sizeof(ip_t) + sizeof(udphdr_t) + sizeof(ip_t)) 73823b9b51feSCy Schubert 73833b9b51feSCy Schubert /* ------------------------------------------------------------------------ */ 73843b9b51feSCy Schubert /* Function: nat_decap */ 73853b9b51feSCy Schubert /* Returns: int - -1 == error, 0 == success */ 73863b9b51feSCy Schubert /* Parameters: fin(I) - pointer to packet information */ 73873b9b51feSCy Schubert /* nat(I) - pointer to current NAT session */ 73883b9b51feSCy Schubert /* */ 73893b9b51feSCy Schubert /* This function is responsible for undoing a packet's encapsulation in the */ 73903b9b51feSCy Schubert /* reverse of an encap/divert rule. After removing the outer encapsulation */ 73913b9b51feSCy Schubert /* it is necessary to call ipf_makefrip() again so that the contents of 'fin'*/ 73923b9b51feSCy Schubert /* match the "new" packet as it may still be used by IPFilter elsewhere. */ 73933b9b51feSCy Schubert /* We use "dir" here as the basis for some of the expectations about the */ 73943b9b51feSCy Schubert /* outer header. If we return an error, the goal is to leave the original */ 73953b9b51feSCy Schubert /* packet information undisturbed - this falls short at the end where we'd */ 73963b9b51feSCy Schubert /* need to back a backup copy of "fin" - expensive. */ 73973b9b51feSCy Schubert /* ------------------------------------------------------------------------ */ 73983b9b51feSCy Schubert static int 73993b9b51feSCy Schubert ipf_nat_decap(fin, nat) 74003b9b51feSCy Schubert fr_info_t *fin; 74013b9b51feSCy Schubert nat_t *nat; 74023b9b51feSCy Schubert { 74033b9b51feSCy Schubert ipf_main_softc_t *softc = fin->fin_main_soft; 74043b9b51feSCy Schubert ipf_nat_softc_t *softn = softc->ipf_nat_soft; 74053b9b51feSCy Schubert char *hdr; 74063b9b51feSCy Schubert int hlen; 74073b9b51feSCy Schubert int skip; 74083b9b51feSCy Schubert mb_t *m; 74093b9b51feSCy Schubert 74103b9b51feSCy Schubert if ((fin->fin_flx & FI_ICMPERR) != 0) { 74113b9b51feSCy Schubert /* 74123b9b51feSCy Schubert * ICMP packets don't get decapsulated, instead what we need 74133b9b51feSCy Schubert * to do is change the ICMP reply from including (in the data 74143b9b51feSCy Schubert * portion for errors) the encapsulated packet that we sent 74153b9b51feSCy Schubert * out to something that resembles the original packet prior 74163b9b51feSCy Schubert * to encapsulation. This isn't done here - all we're doing 74173b9b51feSCy Schubert * here is changing the outer address to ensure that it gets 74183b9b51feSCy Schubert * targetted back to the correct system. 74193b9b51feSCy Schubert */ 74203b9b51feSCy Schubert 74213b9b51feSCy Schubert if (nat->nat_dir & NAT_OUTBOUND) { 74223b9b51feSCy Schubert u_32_t sum1, sum2, sumd; 74233b9b51feSCy Schubert 74243b9b51feSCy Schubert sum1 = ntohl(fin->fin_daddr); 74253b9b51feSCy Schubert sum2 = ntohl(nat->nat_osrcaddr); 74263b9b51feSCy Schubert CALC_SUMD(sum1, sum2, sumd); 74273b9b51feSCy Schubert fin->fin_ip->ip_dst = nat->nat_osrcip; 74283b9b51feSCy Schubert fin->fin_daddr = nat->nat_osrcaddr; 74293b9b51feSCy Schubert #if !defined(_KERNEL) || SOLARIS 74303b9b51feSCy Schubert ipf_fix_outcksum(0, &fin->fin_ip->ip_sum, sumd, 0); 74313b9b51feSCy Schubert #endif 74323b9b51feSCy Schubert } 74333b9b51feSCy Schubert return 0; 74343b9b51feSCy Schubert } 74353b9b51feSCy Schubert 74363b9b51feSCy Schubert m = fin->fin_m; 74373b9b51feSCy Schubert skip = fin->fin_hlen; 74383b9b51feSCy Schubert 74393b9b51feSCy Schubert switch (nat->nat_dir) 74403b9b51feSCy Schubert { 74413b9b51feSCy Schubert case NAT_DIVERTIN : 74423b9b51feSCy Schubert case NAT_DIVERTOUT : 74433b9b51feSCy Schubert if (fin->fin_plen < MINDECAP) 74443b9b51feSCy Schubert return -1; 74453b9b51feSCy Schubert skip += sizeof(udphdr_t); 74463b9b51feSCy Schubert break; 74473b9b51feSCy Schubert 74483b9b51feSCy Schubert case NAT_ENCAPIN : 74493b9b51feSCy Schubert case NAT_ENCAPOUT : 74503b9b51feSCy Schubert if (fin->fin_plen < (skip + sizeof(ip_t))) 74513b9b51feSCy Schubert return -1; 74523b9b51feSCy Schubert break; 74533b9b51feSCy Schubert default : 74543b9b51feSCy Schubert return -1; 74553b9b51feSCy Schubert /* NOTREACHED */ 74563b9b51feSCy Schubert } 74573b9b51feSCy Schubert 74583b9b51feSCy Schubert /* 74593b9b51feSCy Schubert * The aim here is to keep the original packet details in "fin" for 74603b9b51feSCy Schubert * as long as possible so that returning with an error is for the 74613b9b51feSCy Schubert * original packet and there is little undoing work to do. 74623b9b51feSCy Schubert */ 74633b9b51feSCy Schubert if (M_LEN(m) < skip + sizeof(ip_t)) { 74643b9b51feSCy Schubert if (ipf_pr_pullup(fin, skip + sizeof(ip_t)) == -1) 74653b9b51feSCy Schubert return -1; 74663b9b51feSCy Schubert } 74673b9b51feSCy Schubert 74683b9b51feSCy Schubert hdr = MTOD(fin->fin_m, char *); 74693b9b51feSCy Schubert fin->fin_ip = (ip_t *)(hdr + skip); 74703b9b51feSCy Schubert hlen = IP_HL(fin->fin_ip) << 2; 74713b9b51feSCy Schubert 74723b9b51feSCy Schubert if (ipf_pr_pullup(fin, skip + hlen) == -1) { 74733b9b51feSCy Schubert NBUMPSIDED(fin->fin_out, ns_decap_pullup); 74743b9b51feSCy Schubert return -1; 74753b9b51feSCy Schubert } 74763b9b51feSCy Schubert 74773b9b51feSCy Schubert fin->fin_hlen = hlen; 74783b9b51feSCy Schubert fin->fin_dlen -= skip; 74793b9b51feSCy Schubert fin->fin_plen -= skip; 74803b9b51feSCy Schubert fin->fin_ipoff += skip; 74813b9b51feSCy Schubert 74823b9b51feSCy Schubert if (ipf_makefrip(hlen, (ip_t *)hdr, fin) == -1) { 74833b9b51feSCy Schubert NBUMPSIDED(fin->fin_out, ns_decap_bad); 74843b9b51feSCy Schubert return -1; 74853b9b51feSCy Schubert } 74863b9b51feSCy Schubert 74873b9b51feSCy Schubert return skip; 74883b9b51feSCy Schubert } 74893b9b51feSCy Schubert 74903b9b51feSCy Schubert 74913b9b51feSCy Schubert /* ------------------------------------------------------------------------ */ 74923b9b51feSCy Schubert /* Function: nat_nextaddr */ 74933b9b51feSCy Schubert /* Returns: int - -1 == bad input (no new address), */ 74943b9b51feSCy Schubert /* 0 == success and dst has new address */ 74953b9b51feSCy Schubert /* Parameters: fin(I) - pointer to packet information */ 74963b9b51feSCy Schubert /* na(I) - how to generate new address */ 74973b9b51feSCy Schubert /* old(I) - original address being replaced */ 74983b9b51feSCy Schubert /* dst(O) - where to put the new address */ 74993b9b51feSCy Schubert /* Write Lock: ipf_nat */ 75003b9b51feSCy Schubert /* */ 75013b9b51feSCy Schubert /* This function uses the contents of the "na" structure, in combination */ 75023b9b51feSCy Schubert /* with "old" to produce a new address to store in "dst". Not all of the */ 75033b9b51feSCy Schubert /* possible uses of "na" will result in a new address. */ 75043b9b51feSCy Schubert /* ------------------------------------------------------------------------ */ 75053b9b51feSCy Schubert static int 75063b9b51feSCy Schubert ipf_nat_nextaddr(fin, na, old, dst) 75073b9b51feSCy Schubert fr_info_t *fin; 75083b9b51feSCy Schubert nat_addr_t *na; 75093b9b51feSCy Schubert u_32_t *old, *dst; 75103b9b51feSCy Schubert { 75113b9b51feSCy Schubert ipf_main_softc_t *softc = fin->fin_main_soft; 75123b9b51feSCy Schubert ipf_nat_softc_t *softn = softc->ipf_nat_soft; 75133b9b51feSCy Schubert u_32_t amin, amax, new; 75143b9b51feSCy Schubert i6addr_t newip; 75153b9b51feSCy Schubert int error; 75163b9b51feSCy Schubert 75173b9b51feSCy Schubert new = 0; 75183b9b51feSCy Schubert amin = na->na_addr[0].in4.s_addr; 75193b9b51feSCy Schubert 75203b9b51feSCy Schubert switch (na->na_atype) 75213b9b51feSCy Schubert { 75223b9b51feSCy Schubert case FRI_RANGE : 75233b9b51feSCy Schubert amax = na->na_addr[1].in4.s_addr; 75243b9b51feSCy Schubert break; 75253b9b51feSCy Schubert 75263b9b51feSCy Schubert case FRI_NETMASKED : 75273b9b51feSCy Schubert case FRI_DYNAMIC : 75283b9b51feSCy Schubert case FRI_NORMAL : 75293b9b51feSCy Schubert /* 75303b9b51feSCy Schubert * Compute the maximum address by adding the inverse of the 75313b9b51feSCy Schubert * netmask to the minimum address. 75323b9b51feSCy Schubert */ 75333b9b51feSCy Schubert amax = ~na->na_addr[1].in4.s_addr; 75343b9b51feSCy Schubert amax |= amin; 75353b9b51feSCy Schubert break; 75363b9b51feSCy Schubert 75373b9b51feSCy Schubert case FRI_LOOKUP : 75383b9b51feSCy Schubert break; 75393b9b51feSCy Schubert 75403b9b51feSCy Schubert case FRI_BROADCAST : 75413b9b51feSCy Schubert case FRI_PEERADDR : 75423b9b51feSCy Schubert case FRI_NETWORK : 75433b9b51feSCy Schubert default : 75443b9b51feSCy Schubert DT4(ns_na_atype, fr_info_t *, fin, nat_addr_t *, na, u_32_t *, old, u_32_t *, new); 75453b9b51feSCy Schubert return -1; 75463b9b51feSCy Schubert } 75473b9b51feSCy Schubert 75483b9b51feSCy Schubert error = -1; 75493b9b51feSCy Schubert 75503b9b51feSCy Schubert if (na->na_atype == FRI_LOOKUP) { 75513b9b51feSCy Schubert if (na->na_type == IPLT_DSTLIST) { 75523b9b51feSCy Schubert error = ipf_dstlist_select_node(fin, na->na_ptr, dst, 75533b9b51feSCy Schubert NULL); 75543b9b51feSCy Schubert } else { 75553b9b51feSCy Schubert NBUMPSIDE(fin->fin_out, ns_badnextaddr); 75563b9b51feSCy Schubert DT4(ns_badnextaddr_1, fr_info_t *, fin, nat_addr_t *, na, u_32_t *, old, u_32_t *, new); 75573b9b51feSCy Schubert } 75583b9b51feSCy Schubert 75593b9b51feSCy Schubert } else if (na->na_atype == IPLT_NONE) { 75603b9b51feSCy Schubert /* 75613b9b51feSCy Schubert * 0/0 as the new address means leave it alone. 75623b9b51feSCy Schubert */ 75633b9b51feSCy Schubert if (na->na_addr[0].in4.s_addr == 0 && 75643b9b51feSCy Schubert na->na_addr[1].in4.s_addr == 0) { 75653b9b51feSCy Schubert new = *old; 75663b9b51feSCy Schubert 75673b9b51feSCy Schubert /* 75683b9b51feSCy Schubert * 0/32 means get the interface's address 75693b9b51feSCy Schubert */ 75703b9b51feSCy Schubert } else if (na->na_addr[0].in4.s_addr == 0 && 75713b9b51feSCy Schubert na->na_addr[1].in4.s_addr == 0xffffffff) { 75723b9b51feSCy Schubert if (ipf_ifpaddr(softc, 4, na->na_atype, 75733b9b51feSCy Schubert fin->fin_ifp, &newip, NULL) == -1) { 75743b9b51feSCy Schubert NBUMPSIDED(fin->fin_out, ns_ifpaddrfail); 75753b9b51feSCy Schubert DT4(ns_ifpaddrfail, fr_info_t *, fin, nat_addr_t *, na, u_32_t *, old, u_32_t *, new); 75763b9b51feSCy Schubert return -1; 75773b9b51feSCy Schubert } 75783b9b51feSCy Schubert new = newip.in4.s_addr; 75793b9b51feSCy Schubert } else { 75803b9b51feSCy Schubert new = htonl(na->na_nextip); 75813b9b51feSCy Schubert } 75823b9b51feSCy Schubert *dst = new; 75833b9b51feSCy Schubert error = 0; 75843b9b51feSCy Schubert 75853b9b51feSCy Schubert } else { 75863b9b51feSCy Schubert NBUMPSIDE(fin->fin_out, ns_badnextaddr); 75873b9b51feSCy Schubert DT4(ns_badnextaddr_2, fr_info_t *, fin, nat_addr_t *, na, u_32_t *, old, u_32_t *, new); 75883b9b51feSCy Schubert } 75893b9b51feSCy Schubert 75903b9b51feSCy Schubert return error; 75913b9b51feSCy Schubert } 75923b9b51feSCy Schubert 75933b9b51feSCy Schubert 75943b9b51feSCy Schubert /* ------------------------------------------------------------------------ */ 75953b9b51feSCy Schubert /* Function: nat_nextaddrinit */ 75963b9b51feSCy Schubert /* Returns: int - 0 == success, else error number */ 75973b9b51feSCy Schubert /* Parameters: softc(I) - pointer to soft context main structure */ 75983b9b51feSCy Schubert /* na(I) - NAT address information for generating new addr*/ 75993b9b51feSCy Schubert /* initial(I) - flag indicating if it is the first call for */ 76003b9b51feSCy Schubert /* this "na" structure. */ 76013b9b51feSCy Schubert /* ifp(I) - network interface to derive address */ 76023b9b51feSCy Schubert /* information from. */ 76033b9b51feSCy Schubert /* */ 76043b9b51feSCy Schubert /* This function is expected to be called in two scenarious: when a new NAT */ 76053b9b51feSCy Schubert /* rule is loaded into the kernel and when the list of NAT rules is sync'd */ 76063b9b51feSCy Schubert /* up with the valid network interfaces (possibly due to them changing.) */ 76073b9b51feSCy Schubert /* To distinguish between these, the "initial" parameter is used. If it is */ 76083b9b51feSCy Schubert /* 1 then this indicates the rule has just been reloaded and 0 for when we */ 76093b9b51feSCy Schubert /* are updating information. This difference is important because in */ 76103b9b51feSCy Schubert /* instances where we are not updating address information associated with */ 76113b9b51feSCy Schubert /* a network interface, we don't want to disturb what the "next" address to */ 76123b9b51feSCy Schubert /* come out of ipf_nat_nextaddr() will be. */ 76133b9b51feSCy Schubert /* ------------------------------------------------------------------------ */ 76143b9b51feSCy Schubert static int 76153b9b51feSCy Schubert ipf_nat_nextaddrinit(softc, base, na, initial, ifp) 76163b9b51feSCy Schubert ipf_main_softc_t *softc; 76173b9b51feSCy Schubert char *base; 76183b9b51feSCy Schubert nat_addr_t *na; 76193b9b51feSCy Schubert int initial; 76203b9b51feSCy Schubert void *ifp; 76213b9b51feSCy Schubert { 76223b9b51feSCy Schubert 76233b9b51feSCy Schubert switch (na->na_atype) 76243b9b51feSCy Schubert { 76253b9b51feSCy Schubert case FRI_LOOKUP : 76263b9b51feSCy Schubert if (na->na_subtype == 0) { 76273b9b51feSCy Schubert na->na_ptr = ipf_lookup_res_num(softc, IPL_LOGNAT, 76283b9b51feSCy Schubert na->na_type, 76293b9b51feSCy Schubert na->na_num, 76303b9b51feSCy Schubert &na->na_func); 76313b9b51feSCy Schubert } else if (na->na_subtype == 1) { 76323b9b51feSCy Schubert na->na_ptr = ipf_lookup_res_name(softc, IPL_LOGNAT, 76333b9b51feSCy Schubert na->na_type, 76343b9b51feSCy Schubert base + na->na_num, 76353b9b51feSCy Schubert &na->na_func); 76363b9b51feSCy Schubert } 76373b9b51feSCy Schubert if (na->na_func == NULL) { 76383b9b51feSCy Schubert IPFERROR(60060); 76393b9b51feSCy Schubert return ESRCH; 76403b9b51feSCy Schubert } 76413b9b51feSCy Schubert if (na->na_ptr == NULL) { 76423b9b51feSCy Schubert IPFERROR(60056); 76433b9b51feSCy Schubert return ESRCH; 76443b9b51feSCy Schubert } 76453b9b51feSCy Schubert break; 76463b9b51feSCy Schubert 76473b9b51feSCy Schubert case FRI_DYNAMIC : 76483b9b51feSCy Schubert case FRI_BROADCAST : 76493b9b51feSCy Schubert case FRI_NETWORK : 76503b9b51feSCy Schubert case FRI_NETMASKED : 76513b9b51feSCy Schubert case FRI_PEERADDR : 76523b9b51feSCy Schubert if (ifp != NULL) 76533b9b51feSCy Schubert (void )ipf_ifpaddr(softc, 4, na->na_atype, ifp, 76543b9b51feSCy Schubert &na->na_addr[0], &na->na_addr[1]); 76553b9b51feSCy Schubert break; 76563b9b51feSCy Schubert 76573b9b51feSCy Schubert case FRI_SPLIT : 76583b9b51feSCy Schubert case FRI_RANGE : 76593b9b51feSCy Schubert if (initial) 76603b9b51feSCy Schubert na->na_nextip = ntohl(na->na_addr[0].in4.s_addr); 76613b9b51feSCy Schubert break; 76623b9b51feSCy Schubert 76633b9b51feSCy Schubert case FRI_NONE : 76643b9b51feSCy Schubert na->na_addr[0].in4.s_addr &= na->na_addr[1].in4.s_addr; 76653b9b51feSCy Schubert return 0; 76663b9b51feSCy Schubert 76673b9b51feSCy Schubert case FRI_NORMAL : 76683b9b51feSCy Schubert na->na_addr[0].in4.s_addr &= na->na_addr[1].in4.s_addr; 76693b9b51feSCy Schubert break; 76703b9b51feSCy Schubert 76713b9b51feSCy Schubert default : 76723b9b51feSCy Schubert IPFERROR(60054); 76733b9b51feSCy Schubert return EINVAL; 76743b9b51feSCy Schubert } 76753b9b51feSCy Schubert 76763b9b51feSCy Schubert if (initial && (na->na_atype == FRI_NORMAL)) { 76773b9b51feSCy Schubert if (na->na_addr[0].in4.s_addr == 0) { 76783b9b51feSCy Schubert if ((na->na_addr[1].in4.s_addr == 0xffffffff) || 76793b9b51feSCy Schubert (na->na_addr[1].in4.s_addr == 0)) { 76803b9b51feSCy Schubert return 0; 76813b9b51feSCy Schubert } 76823b9b51feSCy Schubert } 76833b9b51feSCy Schubert 76843b9b51feSCy Schubert if (na->na_addr[1].in4.s_addr == 0xffffffff) { 76853b9b51feSCy Schubert na->na_nextip = ntohl(na->na_addr[0].in4.s_addr); 76863b9b51feSCy Schubert } else { 76873b9b51feSCy Schubert na->na_nextip = ntohl(na->na_addr[0].in4.s_addr) + 1; 76883b9b51feSCy Schubert } 76893b9b51feSCy Schubert } 76903b9b51feSCy Schubert 76913b9b51feSCy Schubert return 0; 76923b9b51feSCy Schubert } 76933b9b51feSCy Schubert 76943b9b51feSCy Schubert 76953b9b51feSCy Schubert /* ------------------------------------------------------------------------ */ 76963b9b51feSCy Schubert /* Function: ipf_nat_matchflush */ 76973b9b51feSCy Schubert /* Returns: int - -1 == error, 0 == success */ 76983b9b51feSCy Schubert /* Parameters: softc(I) - pointer to soft context main structure */ 76993b9b51feSCy Schubert /* softn(I) - pointer to NAT context structure */ 77003b9b51feSCy Schubert /* nat(I) - pointer to current NAT session */ 77013b9b51feSCy Schubert /* */ 77023b9b51feSCy Schubert /* ------------------------------------------------------------------------ */ 77033b9b51feSCy Schubert static int 77043b9b51feSCy Schubert ipf_nat_matchflush(softc, softn, data) 77053b9b51feSCy Schubert ipf_main_softc_t *softc; 77063b9b51feSCy Schubert ipf_nat_softc_t *softn; 77073b9b51feSCy Schubert caddr_t data; 77083b9b51feSCy Schubert { 77093b9b51feSCy Schubert int *array, flushed, error; 77103b9b51feSCy Schubert nat_t *nat, *natnext; 77113b9b51feSCy Schubert ipfobj_t obj; 77123b9b51feSCy Schubert 77133b9b51feSCy Schubert error = ipf_matcharray_load(softc, data, &obj, &array); 77143b9b51feSCy Schubert if (error != 0) 77153b9b51feSCy Schubert return error; 77163b9b51feSCy Schubert 77173b9b51feSCy Schubert flushed = 0; 77183b9b51feSCy Schubert 77193b9b51feSCy Schubert for (nat = softn->ipf_nat_instances; nat != NULL; nat = natnext) { 77203b9b51feSCy Schubert natnext = nat->nat_next; 77213b9b51feSCy Schubert if (ipf_nat_matcharray(nat, array, softc->ipf_ticks) == 0) { 77223b9b51feSCy Schubert ipf_nat_delete(softc, nat, NL_FLUSH); 77233b9b51feSCy Schubert flushed++; 77243b9b51feSCy Schubert } 77253b9b51feSCy Schubert } 77263b9b51feSCy Schubert 77273b9b51feSCy Schubert obj.ipfo_retval = flushed; 77283b9b51feSCy Schubert error = BCOPYOUT(&obj, data, sizeof(obj)); 77293b9b51feSCy Schubert 77303b9b51feSCy Schubert KFREES(array, array[0] * sizeof(*array)); 77313b9b51feSCy Schubert 77323b9b51feSCy Schubert return error; 77333b9b51feSCy Schubert } 77343b9b51feSCy Schubert 77353b9b51feSCy Schubert 77363b9b51feSCy Schubert /* ------------------------------------------------------------------------ */ 77373b9b51feSCy Schubert /* Function: ipf_nat_matcharray */ 77383b9b51feSCy Schubert /* Returns: int - -1 == error, 0 == success */ 77393b9b51feSCy Schubert /* Parameters: fin(I) - pointer to packet information */ 77403b9b51feSCy Schubert /* nat(I) - pointer to current NAT session */ 77413b9b51feSCy Schubert /* */ 77423b9b51feSCy Schubert /* ------------------------------------------------------------------------ */ 77433b9b51feSCy Schubert static int 77443b9b51feSCy Schubert ipf_nat_matcharray(nat, array, ticks) 77453b9b51feSCy Schubert nat_t *nat; 77463b9b51feSCy Schubert int *array; 77473b9b51feSCy Schubert u_long ticks; 77483b9b51feSCy Schubert { 77493b9b51feSCy Schubert int i, n, *x, e, p; 77503b9b51feSCy Schubert 77513b9b51feSCy Schubert e = 0; 77523b9b51feSCy Schubert n = array[0]; 77533b9b51feSCy Schubert x = array + 1; 77543b9b51feSCy Schubert 77553b9b51feSCy Schubert for (; n > 0; x += 3 + x[2]) { 77563b9b51feSCy Schubert if (x[0] == IPF_EXP_END) 77573b9b51feSCy Schubert break; 77583b9b51feSCy Schubert e = 0; 77593b9b51feSCy Schubert 77603b9b51feSCy Schubert n -= x[2] + 3; 77613b9b51feSCy Schubert if (n < 0) 77623b9b51feSCy Schubert break; 77633b9b51feSCy Schubert 77643b9b51feSCy Schubert p = x[0] >> 16; 77653b9b51feSCy Schubert if (p != 0 && p != nat->nat_pr[1]) 77663b9b51feSCy Schubert break; 77673b9b51feSCy Schubert 77683b9b51feSCy Schubert switch (x[0]) 77693b9b51feSCy Schubert { 77703b9b51feSCy Schubert case IPF_EXP_IP_PR : 77713b9b51feSCy Schubert for (i = 0; !e && i < x[2]; i++) { 77723b9b51feSCy Schubert e |= (nat->nat_pr[1] == x[i + 3]); 77733b9b51feSCy Schubert } 77743b9b51feSCy Schubert break; 77753b9b51feSCy Schubert 77763b9b51feSCy Schubert case IPF_EXP_IP_SRCADDR : 77773b9b51feSCy Schubert if (nat->nat_v[0] == 4) { 77783b9b51feSCy Schubert for (i = 0; !e && i < x[2]; i++) { 77793b9b51feSCy Schubert e |= ((nat->nat_osrcaddr & x[i + 4]) == 77803b9b51feSCy Schubert x[i + 3]); 77813b9b51feSCy Schubert } 77823b9b51feSCy Schubert } 77833b9b51feSCy Schubert if (nat->nat_v[1] == 4) { 77843b9b51feSCy Schubert for (i = 0; !e && i < x[2]; i++) { 77853b9b51feSCy Schubert e |= ((nat->nat_nsrcaddr & x[i + 4]) == 77863b9b51feSCy Schubert x[i + 3]); 77873b9b51feSCy Schubert } 77883b9b51feSCy Schubert } 77893b9b51feSCy Schubert break; 77903b9b51feSCy Schubert 77913b9b51feSCy Schubert case IPF_EXP_IP_DSTADDR : 77923b9b51feSCy Schubert if (nat->nat_v[0] == 4) { 77933b9b51feSCy Schubert for (i = 0; !e && i < x[2]; i++) { 77943b9b51feSCy Schubert e |= ((nat->nat_odstaddr & x[i + 4]) == 77953b9b51feSCy Schubert x[i + 3]); 77963b9b51feSCy Schubert } 77973b9b51feSCy Schubert } 77983b9b51feSCy Schubert if (nat->nat_v[1] == 4) { 77993b9b51feSCy Schubert for (i = 0; !e && i < x[2]; i++) { 78003b9b51feSCy Schubert e |= ((nat->nat_ndstaddr & x[i + 4]) == 78013b9b51feSCy Schubert x[i + 3]); 78023b9b51feSCy Schubert } 78033b9b51feSCy Schubert } 78043b9b51feSCy Schubert break; 78053b9b51feSCy Schubert 78063b9b51feSCy Schubert case IPF_EXP_IP_ADDR : 78073b9b51feSCy Schubert for (i = 0; !e && i < x[2]; i++) { 78083b9b51feSCy Schubert if (nat->nat_v[0] == 4) { 78093b9b51feSCy Schubert e |= ((nat->nat_osrcaddr & x[i + 4]) == 78103b9b51feSCy Schubert x[i + 3]); 78113b9b51feSCy Schubert } 78123b9b51feSCy Schubert if (nat->nat_v[1] == 4) { 78133b9b51feSCy Schubert e |= ((nat->nat_nsrcaddr & x[i + 4]) == 78143b9b51feSCy Schubert x[i + 3]); 78153b9b51feSCy Schubert } 78163b9b51feSCy Schubert if (nat->nat_v[0] == 4) { 78173b9b51feSCy Schubert e |= ((nat->nat_odstaddr & x[i + 4]) == 78183b9b51feSCy Schubert x[i + 3]); 78193b9b51feSCy Schubert } 78203b9b51feSCy Schubert if (nat->nat_v[1] == 4) { 78213b9b51feSCy Schubert e |= ((nat->nat_ndstaddr & x[i + 4]) == 78223b9b51feSCy Schubert x[i + 3]); 78233b9b51feSCy Schubert } 78243b9b51feSCy Schubert } 78253b9b51feSCy Schubert break; 78263b9b51feSCy Schubert 78273b9b51feSCy Schubert #ifdef USE_INET6 78283b9b51feSCy Schubert case IPF_EXP_IP6_SRCADDR : 78293b9b51feSCy Schubert if (nat->nat_v[0] == 6) { 78303b9b51feSCy Schubert for (i = 0; !e && i < x[3]; i++) { 78313b9b51feSCy Schubert e |= IP6_MASKEQ(&nat->nat_osrc6, 78323b9b51feSCy Schubert x + i + 7, x + i + 3); 78333b9b51feSCy Schubert } 78343b9b51feSCy Schubert } 78353b9b51feSCy Schubert if (nat->nat_v[1] == 6) { 78363b9b51feSCy Schubert for (i = 0; !e && i < x[3]; i++) { 78373b9b51feSCy Schubert e |= IP6_MASKEQ(&nat->nat_nsrc6, 78383b9b51feSCy Schubert x + i + 7, x + i + 3); 78393b9b51feSCy Schubert } 78403b9b51feSCy Schubert } 78413b9b51feSCy Schubert break; 78423b9b51feSCy Schubert 78433b9b51feSCy Schubert case IPF_EXP_IP6_DSTADDR : 78443b9b51feSCy Schubert if (nat->nat_v[0] == 6) { 78453b9b51feSCy Schubert for (i = 0; !e && i < x[3]; i++) { 78463b9b51feSCy Schubert e |= IP6_MASKEQ(&nat->nat_odst6, 78473b9b51feSCy Schubert x + i + 7, 78483b9b51feSCy Schubert x + i + 3); 78493b9b51feSCy Schubert } 78503b9b51feSCy Schubert } 78513b9b51feSCy Schubert if (nat->nat_v[1] == 6) { 78523b9b51feSCy Schubert for (i = 0; !e && i < x[3]; i++) { 78533b9b51feSCy Schubert e |= IP6_MASKEQ(&nat->nat_ndst6, 78543b9b51feSCy Schubert x + i + 7, 78553b9b51feSCy Schubert x + i + 3); 78563b9b51feSCy Schubert } 78573b9b51feSCy Schubert } 78583b9b51feSCy Schubert break; 78593b9b51feSCy Schubert 78603b9b51feSCy Schubert case IPF_EXP_IP6_ADDR : 78613b9b51feSCy Schubert for (i = 0; !e && i < x[3]; i++) { 78623b9b51feSCy Schubert if (nat->nat_v[0] == 6) { 78633b9b51feSCy Schubert e |= IP6_MASKEQ(&nat->nat_osrc6, 78643b9b51feSCy Schubert x + i + 7, 78653b9b51feSCy Schubert x + i + 3); 78663b9b51feSCy Schubert } 78673b9b51feSCy Schubert if (nat->nat_v[0] == 6) { 78683b9b51feSCy Schubert e |= IP6_MASKEQ(&nat->nat_odst6, 78693b9b51feSCy Schubert x + i + 7, 78703b9b51feSCy Schubert x + i + 3); 78713b9b51feSCy Schubert } 78723b9b51feSCy Schubert if (nat->nat_v[1] == 6) { 78733b9b51feSCy Schubert e |= IP6_MASKEQ(&nat->nat_nsrc6, 78743b9b51feSCy Schubert x + i + 7, 78753b9b51feSCy Schubert x + i + 3); 78763b9b51feSCy Schubert } 78773b9b51feSCy Schubert if (nat->nat_v[1] == 6) { 78783b9b51feSCy Schubert e |= IP6_MASKEQ(&nat->nat_ndst6, 78793b9b51feSCy Schubert x + i + 7, 78803b9b51feSCy Schubert x + i + 3); 78813b9b51feSCy Schubert } 78823b9b51feSCy Schubert } 78833b9b51feSCy Schubert break; 78843b9b51feSCy Schubert #endif 78853b9b51feSCy Schubert 78863b9b51feSCy Schubert case IPF_EXP_UDP_PORT : 78873b9b51feSCy Schubert case IPF_EXP_TCP_PORT : 78883b9b51feSCy Schubert for (i = 0; !e && i < x[2]; i++) { 78893b9b51feSCy Schubert e |= (nat->nat_nsport == x[i + 3]) || 78903b9b51feSCy Schubert (nat->nat_ndport == x[i + 3]); 78913b9b51feSCy Schubert } 78923b9b51feSCy Schubert break; 78933b9b51feSCy Schubert 78943b9b51feSCy Schubert case IPF_EXP_UDP_SPORT : 78953b9b51feSCy Schubert case IPF_EXP_TCP_SPORT : 78963b9b51feSCy Schubert for (i = 0; !e && i < x[2]; i++) { 78973b9b51feSCy Schubert e |= (nat->nat_nsport == x[i + 3]); 78983b9b51feSCy Schubert } 78993b9b51feSCy Schubert break; 79003b9b51feSCy Schubert 79013b9b51feSCy Schubert case IPF_EXP_UDP_DPORT : 79023b9b51feSCy Schubert case IPF_EXP_TCP_DPORT : 79033b9b51feSCy Schubert for (i = 0; !e && i < x[2]; i++) { 79043b9b51feSCy Schubert e |= (nat->nat_ndport == x[i + 3]); 79053b9b51feSCy Schubert } 79063b9b51feSCy Schubert break; 79073b9b51feSCy Schubert 79083b9b51feSCy Schubert case IPF_EXP_TCP_STATE : 79093b9b51feSCy Schubert for (i = 0; !e && i < x[2]; i++) { 79103b9b51feSCy Schubert e |= (nat->nat_tcpstate[0] == x[i + 3]) || 79113b9b51feSCy Schubert (nat->nat_tcpstate[1] == x[i + 3]); 79123b9b51feSCy Schubert } 79133b9b51feSCy Schubert break; 79143b9b51feSCy Schubert 79153b9b51feSCy Schubert case IPF_EXP_IDLE_GT : 79163b9b51feSCy Schubert e |= (ticks - nat->nat_touched > x[3]); 79173b9b51feSCy Schubert break; 79183b9b51feSCy Schubert } 79193b9b51feSCy Schubert e ^= x[1]; 79203b9b51feSCy Schubert 79213b9b51feSCy Schubert if (!e) 79223b9b51feSCy Schubert break; 79233b9b51feSCy Schubert } 79243b9b51feSCy Schubert 79253b9b51feSCy Schubert return e; 79263b9b51feSCy Schubert } 79273b9b51feSCy Schubert 79283b9b51feSCy Schubert 79293b9b51feSCy Schubert /* ------------------------------------------------------------------------ */ 79303b9b51feSCy Schubert /* Function: ipf_nat_gettable */ 79313b9b51feSCy Schubert /* Returns: int - 0 = success, else error */ 79323b9b51feSCy Schubert /* Parameters: softc(I) - pointer to soft context main structure */ 79333b9b51feSCy Schubert /* softn(I) - pointer to NAT context structure */ 79343b9b51feSCy Schubert /* data(I) - pointer to ioctl data */ 79353b9b51feSCy Schubert /* */ 79363b9b51feSCy Schubert /* This function handles ioctl requests for tables of nat information. */ 79373b9b51feSCy Schubert /* At present the only table it deals with is the hash bucket statistics. */ 79383b9b51feSCy Schubert /* ------------------------------------------------------------------------ */ 79393b9b51feSCy Schubert static int 79403b9b51feSCy Schubert ipf_nat_gettable(softc, softn, data) 79413b9b51feSCy Schubert ipf_main_softc_t *softc; 79423b9b51feSCy Schubert ipf_nat_softc_t *softn; 79433b9b51feSCy Schubert char *data; 79443b9b51feSCy Schubert { 79453b9b51feSCy Schubert ipftable_t table; 79463b9b51feSCy Schubert int error; 79473b9b51feSCy Schubert 79483b9b51feSCy Schubert error = ipf_inobj(softc, data, NULL, &table, IPFOBJ_GTABLE); 79493b9b51feSCy Schubert if (error != 0) 79503b9b51feSCy Schubert return error; 79513b9b51feSCy Schubert 79523b9b51feSCy Schubert switch (table.ita_type) 79533b9b51feSCy Schubert { 79543b9b51feSCy Schubert case IPFTABLE_BUCKETS_NATIN : 79553b9b51feSCy Schubert error = COPYOUT(softn->ipf_nat_stats.ns_side[0].ns_bucketlen, 79563b9b51feSCy Schubert table.ita_table, 79573b9b51feSCy Schubert softn->ipf_nat_table_sz * sizeof(u_int)); 79583b9b51feSCy Schubert break; 79593b9b51feSCy Schubert 79603b9b51feSCy Schubert case IPFTABLE_BUCKETS_NATOUT : 79613b9b51feSCy Schubert error = COPYOUT(softn->ipf_nat_stats.ns_side[1].ns_bucketlen, 79623b9b51feSCy Schubert table.ita_table, 79633b9b51feSCy Schubert softn->ipf_nat_table_sz * sizeof(u_int)); 79643b9b51feSCy Schubert break; 79653b9b51feSCy Schubert 79663b9b51feSCy Schubert default : 79673b9b51feSCy Schubert IPFERROR(60058); 79683b9b51feSCy Schubert return EINVAL; 79693b9b51feSCy Schubert } 79703b9b51feSCy Schubert 79713b9b51feSCy Schubert if (error != 0) { 79723b9b51feSCy Schubert IPFERROR(60059); 79733b9b51feSCy Schubert error = EFAULT; 79743b9b51feSCy Schubert } 79753b9b51feSCy Schubert return error; 79763b9b51feSCy Schubert } 79773b9b51feSCy Schubert 79783b9b51feSCy Schubert 79793b9b51feSCy Schubert /* ------------------------------------------------------------------------ */ 79803b9b51feSCy Schubert /* Function: ipf_nat_settimeout */ 79813b9b51feSCy Schubert /* Returns: int - 0 = success, else failure */ 79823b9b51feSCy Schubert /* Parameters: softc(I) - pointer to soft context main structure */ 79833b9b51feSCy Schubert /* t(I) - pointer to tunable */ 79843b9b51feSCy Schubert /* p(I) - pointer to new tuning data */ 79853b9b51feSCy Schubert /* */ 79863b9b51feSCy Schubert /* Apply the timeout change to the NAT timeout queues. */ 79873b9b51feSCy Schubert /* ------------------------------------------------------------------------ */ 79883b9b51feSCy Schubert int 79893b9b51feSCy Schubert ipf_nat_settimeout(softc, t, p) 79903b9b51feSCy Schubert struct ipf_main_softc_s *softc; 79913b9b51feSCy Schubert ipftuneable_t *t; 79923b9b51feSCy Schubert ipftuneval_t *p; 79933b9b51feSCy Schubert { 79943b9b51feSCy Schubert ipf_nat_softc_t *softn = softc->ipf_nat_soft; 79953b9b51feSCy Schubert 79963b9b51feSCy Schubert if (!strncmp(t->ipft_name, "tcp_", 4)) 79973b9b51feSCy Schubert return ipf_settimeout_tcp(t, p, softn->ipf_nat_tcptq); 79983b9b51feSCy Schubert 79993b9b51feSCy Schubert if (!strcmp(t->ipft_name, "udp_timeout")) { 80003b9b51feSCy Schubert ipf_apply_timeout(&softn->ipf_nat_udptq, p->ipftu_int); 80013b9b51feSCy Schubert } else if (!strcmp(t->ipft_name, "udp_ack_timeout")) { 80023b9b51feSCy Schubert ipf_apply_timeout(&softn->ipf_nat_udpacktq, p->ipftu_int); 80033b9b51feSCy Schubert } else if (!strcmp(t->ipft_name, "icmp_timeout")) { 80043b9b51feSCy Schubert ipf_apply_timeout(&softn->ipf_nat_icmptq, p->ipftu_int); 80053b9b51feSCy Schubert } else if (!strcmp(t->ipft_name, "icmp_ack_timeout")) { 80063b9b51feSCy Schubert ipf_apply_timeout(&softn->ipf_nat_icmpacktq, p->ipftu_int); 80073b9b51feSCy Schubert } else if (!strcmp(t->ipft_name, "ip_timeout")) { 80083b9b51feSCy Schubert ipf_apply_timeout(&softn->ipf_nat_iptq, p->ipftu_int); 80093b9b51feSCy Schubert } else { 80103b9b51feSCy Schubert IPFERROR(60062); 80113b9b51feSCy Schubert return ESRCH; 80123b9b51feSCy Schubert } 80133b9b51feSCy Schubert return 0; 80143b9b51feSCy Schubert } 80153b9b51feSCy Schubert 80163b9b51feSCy Schubert 80173b9b51feSCy Schubert /* ------------------------------------------------------------------------ */ 80183b9b51feSCy Schubert /* Function: ipf_nat_rehash */ 80193b9b51feSCy Schubert /* Returns: int - 0 = success, else failure */ 80203b9b51feSCy Schubert /* Parameters: softc(I) - pointer to soft context main structure */ 80213b9b51feSCy Schubert /* t(I) - pointer to tunable */ 80223b9b51feSCy Schubert /* p(I) - pointer to new tuning data */ 80233b9b51feSCy Schubert /* */ 80243b9b51feSCy Schubert /* To change the size of the basic NAT table, we need to first allocate the */ 80253b9b51feSCy Schubert /* new tables (lest it fails and we've got nowhere to store all of the NAT */ 80263b9b51feSCy Schubert /* sessions currently active) and then walk through the entire list and */ 80273b9b51feSCy Schubert /* insert them into the table. There are two tables here: an inbound one */ 80283b9b51feSCy Schubert /* and an outbound one. Each NAT entry goes into each table once. */ 80293b9b51feSCy Schubert /* ------------------------------------------------------------------------ */ 80303b9b51feSCy Schubert int 80313b9b51feSCy Schubert ipf_nat_rehash(softc, t, p) 80323b9b51feSCy Schubert ipf_main_softc_t *softc; 80333b9b51feSCy Schubert ipftuneable_t *t; 80343b9b51feSCy Schubert ipftuneval_t *p; 80353b9b51feSCy Schubert { 80363b9b51feSCy Schubert ipf_nat_softc_t *softn = softc->ipf_nat_soft; 80373b9b51feSCy Schubert nat_t **newtab[2], *nat, **natp; 80383b9b51feSCy Schubert u_int *bucketlens[2]; 80393b9b51feSCy Schubert u_int maxbucket; 80403b9b51feSCy Schubert u_int newsize; 80413b9b51feSCy Schubert int error; 80423b9b51feSCy Schubert u_int hv; 80433b9b51feSCy Schubert int i; 80443b9b51feSCy Schubert 80453b9b51feSCy Schubert newsize = p->ipftu_int; 80463b9b51feSCy Schubert /* 80473b9b51feSCy Schubert * In case there is nothing to do... 80483b9b51feSCy Schubert */ 80493b9b51feSCy Schubert if (newsize == softn->ipf_nat_table_sz) 80503b9b51feSCy Schubert return 0; 80513b9b51feSCy Schubert 80523b9b51feSCy Schubert newtab[0] = NULL; 80533b9b51feSCy Schubert newtab[1] = NULL; 80543b9b51feSCy Schubert bucketlens[0] = NULL; 80553b9b51feSCy Schubert bucketlens[1] = NULL; 80563b9b51feSCy Schubert /* 80573b9b51feSCy Schubert * 4 tables depend on the NAT table size: the inbound looking table, 80583b9b51feSCy Schubert * the outbound lookup table and the hash chain length for each. 80593b9b51feSCy Schubert */ 80603b9b51feSCy Schubert KMALLOCS(newtab[0], nat_t **, newsize * sizeof(nat_t *)); 80613b9b51feSCy Schubert if (newtab[0] == NULL) { 80623b9b51feSCy Schubert error = 60063; 80633b9b51feSCy Schubert goto badrehash; 80643b9b51feSCy Schubert } 80653b9b51feSCy Schubert 80663b9b51feSCy Schubert KMALLOCS(newtab[1], nat_t **, newsize * sizeof(nat_t *)); 80673b9b51feSCy Schubert if (newtab[1] == NULL) { 80683b9b51feSCy Schubert error = 60064; 80693b9b51feSCy Schubert goto badrehash; 80703b9b51feSCy Schubert } 80713b9b51feSCy Schubert 80723b9b51feSCy Schubert KMALLOCS(bucketlens[0], u_int *, newsize * sizeof(u_int)); 80733b9b51feSCy Schubert if (bucketlens[0] == NULL) { 80743b9b51feSCy Schubert error = 60065; 80753b9b51feSCy Schubert goto badrehash; 80763b9b51feSCy Schubert } 80773b9b51feSCy Schubert 80783b9b51feSCy Schubert KMALLOCS(bucketlens[1], u_int *, newsize * sizeof(u_int)); 80793b9b51feSCy Schubert if (bucketlens[1] == NULL) { 80803b9b51feSCy Schubert error = 60066; 80813b9b51feSCy Schubert goto badrehash; 80823b9b51feSCy Schubert } 80833b9b51feSCy Schubert 80843b9b51feSCy Schubert /* 80853b9b51feSCy Schubert * Recalculate the maximum length based on the new size. 80863b9b51feSCy Schubert */ 80873b9b51feSCy Schubert for (maxbucket = 0, i = newsize; i > 0; i >>= 1) 80883b9b51feSCy Schubert maxbucket++; 80893b9b51feSCy Schubert maxbucket *= 2; 80903b9b51feSCy Schubert 80913b9b51feSCy Schubert bzero((char *)newtab[0], newsize * sizeof(nat_t *)); 80923b9b51feSCy Schubert bzero((char *)newtab[1], newsize * sizeof(nat_t *)); 80933b9b51feSCy Schubert bzero((char *)bucketlens[0], newsize * sizeof(u_int)); 80943b9b51feSCy Schubert bzero((char *)bucketlens[1], newsize * sizeof(u_int)); 80953b9b51feSCy Schubert 80963b9b51feSCy Schubert WRITE_ENTER(&softc->ipf_nat); 80973b9b51feSCy Schubert 80983b9b51feSCy Schubert if (softn->ipf_nat_table[0] != NULL) { 80993b9b51feSCy Schubert KFREES(softn->ipf_nat_table[0], 81003b9b51feSCy Schubert softn->ipf_nat_table_sz * 81013b9b51feSCy Schubert sizeof(*softn->ipf_nat_table[0])); 81023b9b51feSCy Schubert } 81033b9b51feSCy Schubert softn->ipf_nat_table[0] = newtab[0]; 81043b9b51feSCy Schubert 81053b9b51feSCy Schubert if (softn->ipf_nat_table[1] != NULL) { 81063b9b51feSCy Schubert KFREES(softn->ipf_nat_table[1], 81073b9b51feSCy Schubert softn->ipf_nat_table_sz * 81083b9b51feSCy Schubert sizeof(*softn->ipf_nat_table[1])); 81093b9b51feSCy Schubert } 81103b9b51feSCy Schubert softn->ipf_nat_table[1] = newtab[1]; 81113b9b51feSCy Schubert 81123b9b51feSCy Schubert if (softn->ipf_nat_stats.ns_side[0].ns_bucketlen != NULL) { 81133b9b51feSCy Schubert KFREES(softn->ipf_nat_stats.ns_side[0].ns_bucketlen, 81143b9b51feSCy Schubert softn->ipf_nat_table_sz * sizeof(u_int)); 81153b9b51feSCy Schubert } 81163b9b51feSCy Schubert softn->ipf_nat_stats.ns_side[0].ns_bucketlen = bucketlens[0]; 81173b9b51feSCy Schubert 81183b9b51feSCy Schubert if (softn->ipf_nat_stats.ns_side[1].ns_bucketlen != NULL) { 81193b9b51feSCy Schubert KFREES(softn->ipf_nat_stats.ns_side[1].ns_bucketlen, 81203b9b51feSCy Schubert softn->ipf_nat_table_sz * sizeof(u_int)); 81213b9b51feSCy Schubert } 81223b9b51feSCy Schubert softn->ipf_nat_stats.ns_side[1].ns_bucketlen = bucketlens[1]; 81233b9b51feSCy Schubert 81243b9b51feSCy Schubert #ifdef USE_INET6 81253b9b51feSCy Schubert if (softn->ipf_nat_stats.ns_side6[0].ns_bucketlen != NULL) { 81263b9b51feSCy Schubert KFREES(softn->ipf_nat_stats.ns_side6[0].ns_bucketlen, 81273b9b51feSCy Schubert softn->ipf_nat_table_sz * sizeof(u_int)); 81283b9b51feSCy Schubert } 81293b9b51feSCy Schubert softn->ipf_nat_stats.ns_side6[0].ns_bucketlen = bucketlens[0]; 81303b9b51feSCy Schubert 81313b9b51feSCy Schubert if (softn->ipf_nat_stats.ns_side6[1].ns_bucketlen != NULL) { 81323b9b51feSCy Schubert KFREES(softn->ipf_nat_stats.ns_side6[1].ns_bucketlen, 81333b9b51feSCy Schubert softn->ipf_nat_table_sz * sizeof(u_int)); 81343b9b51feSCy Schubert } 81353b9b51feSCy Schubert softn->ipf_nat_stats.ns_side6[1].ns_bucketlen = bucketlens[1]; 81363b9b51feSCy Schubert #endif 81373b9b51feSCy Schubert 81383b9b51feSCy Schubert softn->ipf_nat_maxbucket = maxbucket; 81393b9b51feSCy Schubert softn->ipf_nat_table_sz = newsize; 81403b9b51feSCy Schubert /* 81413b9b51feSCy Schubert * Walk through the entire list of NAT table entries and put them 81423b9b51feSCy Schubert * in the new NAT table, somewhere. Because we have a new table, 81433b9b51feSCy Schubert * we need to restart the counter of how many chains are in use. 81443b9b51feSCy Schubert */ 81453b9b51feSCy Schubert softn->ipf_nat_stats.ns_side[0].ns_inuse = 0; 81463b9b51feSCy Schubert softn->ipf_nat_stats.ns_side[1].ns_inuse = 0; 81473b9b51feSCy Schubert #ifdef USE_INET6 81483b9b51feSCy Schubert softn->ipf_nat_stats.ns_side6[0].ns_inuse = 0; 81493b9b51feSCy Schubert softn->ipf_nat_stats.ns_side6[1].ns_inuse = 0; 81503b9b51feSCy Schubert #endif 81513b9b51feSCy Schubert 81523b9b51feSCy Schubert for (nat = softn->ipf_nat_instances; nat != NULL; nat = nat->nat_next) { 81533b9b51feSCy Schubert nat->nat_hnext[0] = NULL; 81543b9b51feSCy Schubert nat->nat_phnext[0] = NULL; 81553b9b51feSCy Schubert hv = nat->nat_hv[0] % softn->ipf_nat_table_sz; 81563b9b51feSCy Schubert 81573b9b51feSCy Schubert natp = &softn->ipf_nat_table[0][hv]; 81583b9b51feSCy Schubert if (*natp) { 81593b9b51feSCy Schubert (*natp)->nat_phnext[0] = &nat->nat_hnext[0]; 81603b9b51feSCy Schubert } else { 81613b9b51feSCy Schubert NBUMPSIDE(0, ns_inuse); 81623b9b51feSCy Schubert } 81633b9b51feSCy Schubert nat->nat_phnext[0] = natp; 81643b9b51feSCy Schubert nat->nat_hnext[0] = *natp; 81653b9b51feSCy Schubert *natp = nat; 81663b9b51feSCy Schubert NBUMPSIDE(0, ns_bucketlen[hv]); 81673b9b51feSCy Schubert 81683b9b51feSCy Schubert nat->nat_hnext[1] = NULL; 81693b9b51feSCy Schubert nat->nat_phnext[1] = NULL; 81703b9b51feSCy Schubert hv = nat->nat_hv[1] % softn->ipf_nat_table_sz; 81713b9b51feSCy Schubert 81723b9b51feSCy Schubert natp = &softn->ipf_nat_table[1][hv]; 81733b9b51feSCy Schubert if (*natp) { 81743b9b51feSCy Schubert (*natp)->nat_phnext[1] = &nat->nat_hnext[1]; 81753b9b51feSCy Schubert } else { 81763b9b51feSCy Schubert NBUMPSIDE(1, ns_inuse); 81773b9b51feSCy Schubert } 81783b9b51feSCy Schubert nat->nat_phnext[1] = natp; 81793b9b51feSCy Schubert nat->nat_hnext[1] = *natp; 81803b9b51feSCy Schubert *natp = nat; 81813b9b51feSCy Schubert NBUMPSIDE(1, ns_bucketlen[hv]); 81823b9b51feSCy Schubert } 81833b9b51feSCy Schubert RWLOCK_EXIT(&softc->ipf_nat); 81843b9b51feSCy Schubert 81853b9b51feSCy Schubert return 0; 81863b9b51feSCy Schubert 81873b9b51feSCy Schubert badrehash: 81883b9b51feSCy Schubert if (bucketlens[1] != NULL) { 81893b9b51feSCy Schubert KFREES(bucketlens[0], newsize * sizeof(u_int)); 81903b9b51feSCy Schubert } 81913b9b51feSCy Schubert if (bucketlens[0] != NULL) { 81923b9b51feSCy Schubert KFREES(bucketlens[0], newsize * sizeof(u_int)); 81933b9b51feSCy Schubert } 81943b9b51feSCy Schubert if (newtab[0] != NULL) { 81953b9b51feSCy Schubert KFREES(newtab[0], newsize * sizeof(nat_t *)); 81963b9b51feSCy Schubert } 81973b9b51feSCy Schubert if (newtab[1] != NULL) { 81983b9b51feSCy Schubert KFREES(newtab[1], newsize * sizeof(nat_t *)); 81993b9b51feSCy Schubert } 82003b9b51feSCy Schubert IPFERROR(error); 82013b9b51feSCy Schubert return ENOMEM; 82023b9b51feSCy Schubert } 82033b9b51feSCy Schubert 82043b9b51feSCy Schubert 82053b9b51feSCy Schubert /* ------------------------------------------------------------------------ */ 82063b9b51feSCy Schubert /* Function: ipf_nat_rehash_rules */ 82073b9b51feSCy Schubert /* Returns: int - 0 = success, else failure */ 82083b9b51feSCy Schubert /* Parameters: softc(I) - pointer to soft context main structure */ 82093b9b51feSCy Schubert /* t(I) - pointer to tunable */ 82103b9b51feSCy Schubert /* p(I) - pointer to new tuning data */ 82113b9b51feSCy Schubert /* */ 82123b9b51feSCy Schubert /* All of the NAT rules hang off of a hash table that is searched with a */ 82133b9b51feSCy Schubert /* hash on address after the netmask is applied. There is a different table*/ 82143b9b51feSCy Schubert /* for both inbound rules (rdr) and outbound (map.) The resizing will only */ 82153b9b51feSCy Schubert /* affect one of these two tables. */ 82163b9b51feSCy Schubert /* ------------------------------------------------------------------------ */ 82173b9b51feSCy Schubert int 82183b9b51feSCy Schubert ipf_nat_rehash_rules(softc, t, p) 82193b9b51feSCy Schubert ipf_main_softc_t *softc; 82203b9b51feSCy Schubert ipftuneable_t *t; 82213b9b51feSCy Schubert ipftuneval_t *p; 82223b9b51feSCy Schubert { 82233b9b51feSCy Schubert ipf_nat_softc_t *softn = softc->ipf_nat_soft; 82243b9b51feSCy Schubert ipnat_t **newtab, *np, ***old, **npp; 82253b9b51feSCy Schubert u_int newsize; 82263b9b51feSCy Schubert u_int mask; 82273b9b51feSCy Schubert u_int hv; 82283b9b51feSCy Schubert 82293b9b51feSCy Schubert newsize = p->ipftu_int; 82303b9b51feSCy Schubert /* 82313b9b51feSCy Schubert * In case there is nothing to do... 82323b9b51feSCy Schubert */ 82333b9b51feSCy Schubert if (newsize == *t->ipft_pint) 82343b9b51feSCy Schubert return 0; 82353b9b51feSCy Schubert 82363b9b51feSCy Schubert /* 82373b9b51feSCy Schubert * All inbound rules have the NAT_REDIRECT bit set in in_redir and 82383b9b51feSCy Schubert * all outbound rules have either NAT_MAP or MAT_MAPBLK set. 82393b9b51feSCy Schubert * This if statement allows for some more generic code to be below, 82403b9b51feSCy Schubert * rather than two huge gobs of code that almost do the same thing. 82413b9b51feSCy Schubert */ 82423b9b51feSCy Schubert if (t->ipft_pint == &softn->ipf_nat_rdrrules_sz) { 82433b9b51feSCy Schubert old = &softn->ipf_nat_rdr_rules; 82443b9b51feSCy Schubert mask = NAT_REDIRECT; 82453b9b51feSCy Schubert } else { 82463b9b51feSCy Schubert old = &softn->ipf_nat_map_rules; 82473b9b51feSCy Schubert mask = NAT_MAP|NAT_MAPBLK; 82483b9b51feSCy Schubert } 82493b9b51feSCy Schubert 82503b9b51feSCy Schubert KMALLOCS(newtab, ipnat_t **, newsize * sizeof(ipnat_t *)); 82513b9b51feSCy Schubert if (newtab == NULL) { 82523b9b51feSCy Schubert IPFERROR(60067); 82533b9b51feSCy Schubert return ENOMEM; 82543b9b51feSCy Schubert } 82553b9b51feSCy Schubert 82563b9b51feSCy Schubert bzero((char *)newtab, newsize * sizeof(ipnat_t *)); 82573b9b51feSCy Schubert 82583b9b51feSCy Schubert WRITE_ENTER(&softc->ipf_nat); 82593b9b51feSCy Schubert 82603b9b51feSCy Schubert if (*old != NULL) { 82613b9b51feSCy Schubert KFREES(*old, *t->ipft_pint * sizeof(ipnat_t **)); 82623b9b51feSCy Schubert } 82633b9b51feSCy Schubert *old = newtab; 82643b9b51feSCy Schubert *t->ipft_pint = newsize; 82653b9b51feSCy Schubert 82663b9b51feSCy Schubert for (np = softn->ipf_nat_list; np != NULL; np = np->in_next) { 82673b9b51feSCy Schubert if ((np->in_redir & mask) == 0) 82683b9b51feSCy Schubert continue; 82693b9b51feSCy Schubert 82703b9b51feSCy Schubert if (np->in_redir & NAT_REDIRECT) { 82713b9b51feSCy Schubert np->in_rnext = NULL; 82723b9b51feSCy Schubert hv = np->in_hv[0] % newsize; 82733b9b51feSCy Schubert for (npp = newtab + hv; *npp != NULL; ) 82743b9b51feSCy Schubert npp = &(*npp)->in_rnext; 82753b9b51feSCy Schubert np->in_prnext = npp; 82763b9b51feSCy Schubert *npp = np; 82773b9b51feSCy Schubert } 82783b9b51feSCy Schubert if (np->in_redir & NAT_MAP) { 82793b9b51feSCy Schubert np->in_mnext = NULL; 82803b9b51feSCy Schubert hv = np->in_hv[1] % newsize; 82813b9b51feSCy Schubert for (npp = newtab + hv; *npp != NULL; ) 82823b9b51feSCy Schubert npp = &(*npp)->in_mnext; 82833b9b51feSCy Schubert np->in_pmnext = npp; 82843b9b51feSCy Schubert *npp = np; 82853b9b51feSCy Schubert } 82863b9b51feSCy Schubert 82873b9b51feSCy Schubert } 82883b9b51feSCy Schubert RWLOCK_EXIT(&softc->ipf_nat); 82893b9b51feSCy Schubert 82903b9b51feSCy Schubert return 0; 82913b9b51feSCy Schubert } 82923b9b51feSCy Schubert 82933b9b51feSCy Schubert 82943b9b51feSCy Schubert /* ------------------------------------------------------------------------ */ 82953b9b51feSCy Schubert /* Function: ipf_nat_hostmap_rehash */ 82963b9b51feSCy Schubert /* Returns: int - 0 = success, else failure */ 82973b9b51feSCy Schubert /* Parameters: softc(I) - pointer to soft context main structure */ 82983b9b51feSCy Schubert /* t(I) - pointer to tunable */ 82993b9b51feSCy Schubert /* p(I) - pointer to new tuning data */ 83003b9b51feSCy Schubert /* */ 83013b9b51feSCy Schubert /* Allocate and populate a new hash table that will contain a reference to */ 83023b9b51feSCy Schubert /* all of the active IP# translations currently in place. */ 83033b9b51feSCy Schubert /* ------------------------------------------------------------------------ */ 83043b9b51feSCy Schubert int 83053b9b51feSCy Schubert ipf_nat_hostmap_rehash(softc, t, p) 83063b9b51feSCy Schubert ipf_main_softc_t *softc; 83073b9b51feSCy Schubert ipftuneable_t *t; 83083b9b51feSCy Schubert ipftuneval_t *p; 83093b9b51feSCy Schubert { 83103b9b51feSCy Schubert ipf_nat_softc_t *softn = softc->ipf_nat_soft; 83113b9b51feSCy Schubert hostmap_t *hm, **newtab; 83123b9b51feSCy Schubert u_int newsize; 83133b9b51feSCy Schubert u_int hv; 83143b9b51feSCy Schubert 83153b9b51feSCy Schubert newsize = p->ipftu_int; 83163b9b51feSCy Schubert /* 83173b9b51feSCy Schubert * In case there is nothing to do... 83183b9b51feSCy Schubert */ 83193b9b51feSCy Schubert if (newsize == *t->ipft_pint) 83203b9b51feSCy Schubert return 0; 83213b9b51feSCy Schubert 83223b9b51feSCy Schubert KMALLOCS(newtab, hostmap_t **, newsize * sizeof(hostmap_t *)); 83233b9b51feSCy Schubert if (newtab == NULL) { 83243b9b51feSCy Schubert IPFERROR(60068); 83253b9b51feSCy Schubert return ENOMEM; 83263b9b51feSCy Schubert } 83273b9b51feSCy Schubert 83283b9b51feSCy Schubert bzero((char *)newtab, newsize * sizeof(hostmap_t *)); 83293b9b51feSCy Schubert 83303b9b51feSCy Schubert WRITE_ENTER(&softc->ipf_nat); 83313b9b51feSCy Schubert if (softn->ipf_hm_maptable != NULL) { 83323b9b51feSCy Schubert KFREES(softn->ipf_hm_maptable, 83333b9b51feSCy Schubert softn->ipf_nat_hostmap_sz * sizeof(hostmap_t *)); 83343b9b51feSCy Schubert } 83353b9b51feSCy Schubert softn->ipf_hm_maptable = newtab; 83363b9b51feSCy Schubert softn->ipf_nat_hostmap_sz = newsize; 83373b9b51feSCy Schubert 83383b9b51feSCy Schubert for (hm = softn->ipf_hm_maplist; hm != NULL; hm = hm->hm_next) { 83393b9b51feSCy Schubert hv = hm->hm_hv % softn->ipf_nat_hostmap_sz; 83403b9b51feSCy Schubert hm->hm_hnext = softn->ipf_hm_maptable[hv]; 83413b9b51feSCy Schubert hm->hm_phnext = softn->ipf_hm_maptable + hv; 83423b9b51feSCy Schubert if (softn->ipf_hm_maptable[hv] != NULL) 83433b9b51feSCy Schubert softn->ipf_hm_maptable[hv]->hm_phnext = &hm->hm_hnext; 83443b9b51feSCy Schubert softn->ipf_hm_maptable[hv] = hm; 83453b9b51feSCy Schubert } 83463b9b51feSCy Schubert RWLOCK_EXIT(&softc->ipf_nat); 83473b9b51feSCy Schubert 83483b9b51feSCy Schubert return 0; 83493b9b51feSCy Schubert } 83503b9b51feSCy Schubert 83513b9b51feSCy Schubert 83523b9b51feSCy Schubert /* ------------------------------------------------------------------------ */ 83533b9b51feSCy Schubert /* Function: ipf_nat_add_tq */ 83543b9b51feSCy Schubert /* Parameters: softc(I) - pointer to soft context main structure */ 83553b9b51feSCy Schubert /* */ 83563b9b51feSCy Schubert /* ------------------------------------------------------------------------ */ 83573b9b51feSCy Schubert ipftq_t * 83583b9b51feSCy Schubert ipf_nat_add_tq(softc, ttl) 83593b9b51feSCy Schubert ipf_main_softc_t *softc; 83603b9b51feSCy Schubert int ttl; 83613b9b51feSCy Schubert { 83623b9b51feSCy Schubert ipf_nat_softc_t *softs = softc->ipf_nat_soft; 83633b9b51feSCy Schubert 83643b9b51feSCy Schubert return ipf_addtimeoutqueue(softc, &softs->ipf_nat_utqe, ttl); 83653b9b51feSCy Schubert } 83663b9b51feSCy Schubert 83673b9b51feSCy Schubert /* ------------------------------------------------------------------------ */ 83683b9b51feSCy Schubert /* Function: ipf_nat_uncreate */ 83693b9b51feSCy Schubert /* Returns: Nil */ 83703b9b51feSCy Schubert /* Parameters: fin(I) - pointer to packet information */ 83713b9b51feSCy Schubert /* */ 83723b9b51feSCy Schubert /* This function is used to remove a NAT entry from the NAT table when we */ 83733b9b51feSCy Schubert /* decide that the create was actually in error. It is thus assumed that */ 83743b9b51feSCy Schubert /* fin_flx will have both FI_NATED and FI_NATNEW set. Because we're dealing */ 83753b9b51feSCy Schubert /* with the translated packet (not the original), we have to reverse the */ 83763b9b51feSCy Schubert /* lookup. Although doing the lookup is expensive (relatively speaking), it */ 83773b9b51feSCy Schubert /* is not anticipated that this will be a frequent occurance for normal */ 83783b9b51feSCy Schubert /* traffic patterns. */ 83793b9b51feSCy Schubert /* ------------------------------------------------------------------------ */ 83803b9b51feSCy Schubert void 83813b9b51feSCy Schubert ipf_nat_uncreate(fin) 83823b9b51feSCy Schubert fr_info_t *fin; 83833b9b51feSCy Schubert { 83843b9b51feSCy Schubert ipf_main_softc_t *softc = fin->fin_main_soft; 83853b9b51feSCy Schubert ipf_nat_softc_t *softn = softc->ipf_nat_soft; 83863b9b51feSCy Schubert int nflags; 83873b9b51feSCy Schubert nat_t *nat; 83883b9b51feSCy Schubert 83893b9b51feSCy Schubert switch (fin->fin_p) 83903b9b51feSCy Schubert { 83913b9b51feSCy Schubert case IPPROTO_TCP : 83923b9b51feSCy Schubert nflags = IPN_TCP; 83933b9b51feSCy Schubert break; 83943b9b51feSCy Schubert case IPPROTO_UDP : 83953b9b51feSCy Schubert nflags = IPN_UDP; 83963b9b51feSCy Schubert break; 83973b9b51feSCy Schubert default : 83983b9b51feSCy Schubert nflags = 0; 83993b9b51feSCy Schubert break; 84003b9b51feSCy Schubert } 84013b9b51feSCy Schubert 84023b9b51feSCy Schubert WRITE_ENTER(&softc->ipf_nat); 84033b9b51feSCy Schubert 84043b9b51feSCy Schubert if (fin->fin_out == 0) { 84053b9b51feSCy Schubert nat = ipf_nat_outlookup(fin, nflags, (u_int)fin->fin_p, 84063b9b51feSCy Schubert fin->fin_dst, fin->fin_src); 84073b9b51feSCy Schubert } else { 84083b9b51feSCy Schubert nat = ipf_nat_inlookup(fin, nflags, (u_int)fin->fin_p, 84093b9b51feSCy Schubert fin->fin_src, fin->fin_dst); 84103b9b51feSCy Schubert } 84113b9b51feSCy Schubert 84123b9b51feSCy Schubert if (nat != NULL) { 84133b9b51feSCy Schubert NBUMPSIDE(fin->fin_out, ns_uncreate[0]); 84143b9b51feSCy Schubert ipf_nat_delete(softc, nat, NL_DESTROY); 84153b9b51feSCy Schubert } else { 84163b9b51feSCy Schubert NBUMPSIDE(fin->fin_out, ns_uncreate[1]); 84173b9b51feSCy Schubert } 84183b9b51feSCy Schubert 84193b9b51feSCy Schubert RWLOCK_EXIT(&softc->ipf_nat); 84203b9b51feSCy Schubert } 84213b9b51feSCy Schubert 84223b9b51feSCy Schubert 84233b9b51feSCy Schubert /* ------------------------------------------------------------------------ */ 84243b9b51feSCy Schubert /* Function: ipf_nat_cmp_rules */ 84253b9b51feSCy Schubert /* Returns: int - 0 == success, else rules do not match. */ 84263b9b51feSCy Schubert /* Parameters: n1(I) - first rule to compare */ 84273b9b51feSCy Schubert /* n2(I) - first rule to compare */ 84283b9b51feSCy Schubert /* */ 84293b9b51feSCy Schubert /* Compare two rules using pointers to each rule. A straight bcmp will not */ 84303b9b51feSCy Schubert /* work as some fields (such as in_dst, in_pkts) actually do change once */ 84313b9b51feSCy Schubert /* the rule has been loaded into the kernel. Whilst this function returns */ 84323b9b51feSCy Schubert /* various non-zero returns, they're strictly to aid in debugging. Use of */ 84333b9b51feSCy Schubert /* this function should simply care if the result is zero or not. */ 84343b9b51feSCy Schubert /* ------------------------------------------------------------------------ */ 84353b9b51feSCy Schubert static int 84363b9b51feSCy Schubert ipf_nat_cmp_rules(n1, n2) 84373b9b51feSCy Schubert ipnat_t *n1, *n2; 84383b9b51feSCy Schubert { 84393b9b51feSCy Schubert if (n1->in_size != n2->in_size) 84403b9b51feSCy Schubert return 1; 84413b9b51feSCy Schubert 84423b9b51feSCy Schubert if (bcmp((char *)&n1->in_v, (char *)&n2->in_v, 84433b9b51feSCy Schubert offsetof(ipnat_t, in_ndst) - offsetof(ipnat_t, in_v)) != 0) 84443b9b51feSCy Schubert return 2; 84453b9b51feSCy Schubert 84463b9b51feSCy Schubert if (bcmp((char *)&n1->in_tuc, (char *)&n2->in_tuc, 84473b9b51feSCy Schubert n1->in_size - offsetof(ipnat_t, in_tuc)) != 0) 84483b9b51feSCy Schubert return 3; 84493b9b51feSCy Schubert if (n1->in_ndst.na_atype != n2->in_ndst.na_atype) 84503b9b51feSCy Schubert return 5; 84513b9b51feSCy Schubert if (n1->in_ndst.na_function != n2->in_ndst.na_function) 84523b9b51feSCy Schubert return 6; 84533b9b51feSCy Schubert if (bcmp((char *)&n1->in_ndst.na_addr, (char *)&n2->in_ndst.na_addr, 84543b9b51feSCy Schubert sizeof(n1->in_ndst.na_addr))) 84553b9b51feSCy Schubert return 7; 84563b9b51feSCy Schubert if (n1->in_nsrc.na_atype != n2->in_nsrc.na_atype) 84573b9b51feSCy Schubert return 8; 84583b9b51feSCy Schubert if (n1->in_nsrc.na_function != n2->in_nsrc.na_function) 84593b9b51feSCy Schubert return 9; 84603b9b51feSCy Schubert if (bcmp((char *)&n1->in_nsrc.na_addr, (char *)&n2->in_nsrc.na_addr, 84613b9b51feSCy Schubert sizeof(n1->in_nsrc.na_addr))) 84623b9b51feSCy Schubert return 10; 84633b9b51feSCy Schubert if (n1->in_odst.na_atype != n2->in_odst.na_atype) 84643b9b51feSCy Schubert return 11; 84653b9b51feSCy Schubert if (n1->in_odst.na_function != n2->in_odst.na_function) 84663b9b51feSCy Schubert return 12; 84673b9b51feSCy Schubert if (bcmp((char *)&n1->in_odst.na_addr, (char *)&n2->in_odst.na_addr, 84683b9b51feSCy Schubert sizeof(n1->in_odst.na_addr))) 84693b9b51feSCy Schubert return 13; 84703b9b51feSCy Schubert if (n1->in_osrc.na_atype != n2->in_osrc.na_atype) 84713b9b51feSCy Schubert return 14; 84723b9b51feSCy Schubert if (n1->in_osrc.na_function != n2->in_osrc.na_function) 84733b9b51feSCy Schubert return 15; 84743b9b51feSCy Schubert if (bcmp((char *)&n1->in_osrc.na_addr, (char *)&n2->in_osrc.na_addr, 84753b9b51feSCy Schubert sizeof(n1->in_osrc.na_addr))) 84763b9b51feSCy Schubert return 16; 84773b9b51feSCy Schubert return 0; 84783b9b51feSCy Schubert } 84793b9b51feSCy Schubert 84803b9b51feSCy Schubert 84813b9b51feSCy Schubert /* ------------------------------------------------------------------------ */ 84823b9b51feSCy Schubert /* Function: ipf_nat_rule_init */ 84833b9b51feSCy Schubert /* Returns: int - 0 == success, else rules do not match. */ 84843b9b51feSCy Schubert /* Parameters: softc(I) - pointer to soft context main structure */ 84853b9b51feSCy Schubert /* softn(I) - pointer to NAT context structure */ 84863b9b51feSCy Schubert /* n(I) - first rule to compare */ 84873b9b51feSCy Schubert /* */ 84883b9b51feSCy Schubert /* ------------------------------------------------------------------------ */ 84893b9b51feSCy Schubert static int 84903b9b51feSCy Schubert ipf_nat_rule_init(softc, softn, n) 84913b9b51feSCy Schubert ipf_main_softc_t *softc; 84923b9b51feSCy Schubert ipf_nat_softc_t *softn; 84933b9b51feSCy Schubert ipnat_t *n; 84943b9b51feSCy Schubert { 84953b9b51feSCy Schubert int error = 0; 84963b9b51feSCy Schubert 84973b9b51feSCy Schubert if ((n->in_flags & IPN_SIPRANGE) != 0) 84983b9b51feSCy Schubert n->in_nsrcatype = FRI_RANGE; 84993b9b51feSCy Schubert 85003b9b51feSCy Schubert if ((n->in_flags & IPN_DIPRANGE) != 0) 85013b9b51feSCy Schubert n->in_ndstatype = FRI_RANGE; 85023b9b51feSCy Schubert 85033b9b51feSCy Schubert if ((n->in_flags & IPN_SPLIT) != 0) 85043b9b51feSCy Schubert n->in_ndstatype = FRI_SPLIT; 85053b9b51feSCy Schubert 85063b9b51feSCy Schubert if ((n->in_redir & (NAT_MAP|NAT_REWRITE|NAT_DIVERTUDP)) != 0) 85073b9b51feSCy Schubert n->in_spnext = n->in_spmin; 85083b9b51feSCy Schubert 85093b9b51feSCy Schubert if ((n->in_redir & (NAT_REWRITE|NAT_DIVERTUDP)) != 0) { 85103b9b51feSCy Schubert n->in_dpnext = n->in_dpmin; 85113b9b51feSCy Schubert } else if (n->in_redir == NAT_REDIRECT) { 85123b9b51feSCy Schubert n->in_dpnext = n->in_dpmin; 85133b9b51feSCy Schubert } 85143b9b51feSCy Schubert 85153b9b51feSCy Schubert n->in_stepnext = 0; 85163b9b51feSCy Schubert 85173b9b51feSCy Schubert switch (n->in_v[0]) 85183b9b51feSCy Schubert { 85193b9b51feSCy Schubert case 4 : 85203b9b51feSCy Schubert error = ipf_nat_ruleaddrinit(softc, softn, n); 85213b9b51feSCy Schubert if (error != 0) 85223b9b51feSCy Schubert return error; 85233b9b51feSCy Schubert break; 85243b9b51feSCy Schubert #ifdef USE_INET6 85253b9b51feSCy Schubert case 6 : 85263b9b51feSCy Schubert error = ipf_nat6_ruleaddrinit(softc, softn, n); 85273b9b51feSCy Schubert if (error != 0) 85283b9b51feSCy Schubert return error; 85293b9b51feSCy Schubert break; 85303b9b51feSCy Schubert #endif 85313b9b51feSCy Schubert default : 85323b9b51feSCy Schubert break; 85333b9b51feSCy Schubert } 85343b9b51feSCy Schubert 85353b9b51feSCy Schubert if (n->in_redir == (NAT_DIVERTUDP|NAT_MAP)) { 85363b9b51feSCy Schubert /* 85373b9b51feSCy Schubert * Prerecord whether or not the destination of the divert 85383b9b51feSCy Schubert * is local or not to the interface the packet is going 85393b9b51feSCy Schubert * to be sent out. 85403b9b51feSCy Schubert */ 85413b9b51feSCy Schubert n->in_dlocal = ipf_deliverlocal(softc, n->in_v[1], 85423b9b51feSCy Schubert n->in_ifps[1], &n->in_ndstip6); 85433b9b51feSCy Schubert } 85443b9b51feSCy Schubert 85453b9b51feSCy Schubert return error; 85463b9b51feSCy Schubert } 85473b9b51feSCy Schubert 85483b9b51feSCy Schubert 85493b9b51feSCy Schubert /* ------------------------------------------------------------------------ */ 85503b9b51feSCy Schubert /* Function: ipf_nat_rule_fini */ 85513b9b51feSCy Schubert /* Returns: int - 0 == success, else rules do not match. */ 85523b9b51feSCy Schubert /* Parameters: softc(I) - pointer to soft context main structure */ 85533b9b51feSCy Schubert /* n(I) - rule to work on */ 85543b9b51feSCy Schubert /* */ 85553b9b51feSCy Schubert /* This function is used to release any objects that were referenced during */ 85563b9b51feSCy Schubert /* the rule initialisation. This is useful both when free'ing the rule and */ 85573b9b51feSCy Schubert /* when handling ioctls that need to initialise these fields but not */ 85583b9b51feSCy Schubert /* actually use them after the ioctl processing has finished. */ 85593b9b51feSCy Schubert /* ------------------------------------------------------------------------ */ 85603b9b51feSCy Schubert static void 85613b9b51feSCy Schubert ipf_nat_rule_fini(softc, n) 85623b9b51feSCy Schubert ipf_main_softc_t *softc; 85633b9b51feSCy Schubert ipnat_t *n; 85643b9b51feSCy Schubert { 85653b9b51feSCy Schubert if (n->in_odst.na_atype == FRI_LOOKUP && n->in_odst.na_ptr != NULL) 85663b9b51feSCy Schubert ipf_lookup_deref(softc, n->in_odst.na_type, n->in_odst.na_ptr); 85673b9b51feSCy Schubert 85683b9b51feSCy Schubert if (n->in_osrc.na_atype == FRI_LOOKUP && n->in_osrc.na_ptr != NULL) 85693b9b51feSCy Schubert ipf_lookup_deref(softc, n->in_osrc.na_type, n->in_osrc.na_ptr); 85703b9b51feSCy Schubert 85713b9b51feSCy Schubert if (n->in_ndst.na_atype == FRI_LOOKUP && n->in_ndst.na_ptr != NULL) 85723b9b51feSCy Schubert ipf_lookup_deref(softc, n->in_ndst.na_type, n->in_ndst.na_ptr); 85733b9b51feSCy Schubert 85743b9b51feSCy Schubert if (n->in_nsrc.na_atype == FRI_LOOKUP && n->in_nsrc.na_ptr != NULL) 85753b9b51feSCy Schubert ipf_lookup_deref(softc, n->in_nsrc.na_type, n->in_nsrc.na_ptr); 85763b9b51feSCy Schubert 85773b9b51feSCy Schubert if (n->in_divmp != NULL) 85783b9b51feSCy Schubert FREE_MB_T(n->in_divmp); 85793b9b51feSCy Schubert } 8580