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