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