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