1ab25eeb5Syz155240 /* 227dbc409San207044 * Copyright (C) 1995-2004 by Darren Reed. 3ab25eeb5Syz155240 * 4ab25eeb5Syz155240 * See the IPFILTER.LICENCE file for details on licencing. 5ab25eeb5Syz155240 * 68899fcfaSjojemann * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 7ab25eeb5Syz155240 * Use is subject to license terms. 8ab25eeb5Syz155240 */ 9ab25eeb5Syz155240 10dcf3e898Sjojemann #pragma ident "%Z%%M% %I% %E% SMI"$ 11ab25eeb5Syz155240 12ab25eeb5Syz155240 #if defined(KERNEL) || defined(_KERNEL) 13ab25eeb5Syz155240 # undef KERNEL 14ab25eeb5Syz155240 # undef _KERNEL 15ab25eeb5Syz155240 # define KERNEL 1 16ab25eeb5Syz155240 # define _KERNEL 1 17ab25eeb5Syz155240 #endif 18ab25eeb5Syz155240 #include <sys/errno.h> 19ab25eeb5Syz155240 #include <sys/types.h> 20ab25eeb5Syz155240 #include <sys/param.h> 21ab25eeb5Syz155240 #include <sys/time.h> 22ab25eeb5Syz155240 #include <sys/file.h> 23ab25eeb5Syz155240 #if defined(__NetBSD__) && (NetBSD >= 199905) && !defined(IPFILTER_LKM) && \ 24ab25eeb5Syz155240 defined(_KERNEL) 25ab25eeb5Syz155240 # include "opt_ipfilter_log.h" 26ab25eeb5Syz155240 #endif 27ab25eeb5Syz155240 #if !defined(_KERNEL) 28ab25eeb5Syz155240 # include <stdio.h> 29ab25eeb5Syz155240 # include <string.h> 30ab25eeb5Syz155240 # include <stdlib.h> 31ab25eeb5Syz155240 # define _KERNEL 32ab25eeb5Syz155240 # ifdef __OpenBSD__ 33ab25eeb5Syz155240 struct file; 34ab25eeb5Syz155240 # endif 35ab25eeb5Syz155240 # include <sys/uio.h> 36ab25eeb5Syz155240 # undef _KERNEL 37ab25eeb5Syz155240 #endif 38ab25eeb5Syz155240 #if defined(_KERNEL) && (__FreeBSD_version >= 220000) 39ab25eeb5Syz155240 # include <sys/filio.h> 40ab25eeb5Syz155240 # include <sys/fcntl.h> 41ab25eeb5Syz155240 #else 42ab25eeb5Syz155240 # include <sys/ioctl.h> 43ab25eeb5Syz155240 #endif 44ab25eeb5Syz155240 #if !defined(AIX) 45ab25eeb5Syz155240 # include <sys/fcntl.h> 46ab25eeb5Syz155240 #endif 47ab25eeb5Syz155240 #if !defined(linux) 48ab25eeb5Syz155240 # include <sys/protosw.h> 49ab25eeb5Syz155240 #endif 50ab25eeb5Syz155240 #include <sys/socket.h> 51ab25eeb5Syz155240 #if defined(_KERNEL) 52ab25eeb5Syz155240 # include <sys/systm.h> 53ab25eeb5Syz155240 # if !defined(__SVR4) && !defined(__svr4__) 54ab25eeb5Syz155240 # include <sys/mbuf.h> 55ab25eeb5Syz155240 # endif 56ab25eeb5Syz155240 #endif 57ab25eeb5Syz155240 #if defined(__SVR4) || defined(__svr4__) 58ab25eeb5Syz155240 # include <sys/filio.h> 59ab25eeb5Syz155240 # include <sys/byteorder.h> 60ab25eeb5Syz155240 # ifdef _KERNEL 61ab25eeb5Syz155240 # include <sys/dditypes.h> 62ab25eeb5Syz155240 # endif 63ab25eeb5Syz155240 # include <sys/stream.h> 64ab25eeb5Syz155240 # include <sys/kmem.h> 65ab25eeb5Syz155240 #endif 66ab25eeb5Syz155240 #if __FreeBSD_version >= 300000 67ab25eeb5Syz155240 # include <sys/queue.h> 68ab25eeb5Syz155240 #endif 69ab25eeb5Syz155240 #include <net/if.h> 70ab25eeb5Syz155240 #if __FreeBSD_version >= 300000 71ab25eeb5Syz155240 # include <net/if_var.h> 72ab25eeb5Syz155240 # if defined(_KERNEL) && !defined(IPFILTER_LKM) 73ab25eeb5Syz155240 # include "opt_ipfilter.h" 74ab25eeb5Syz155240 # endif 75ab25eeb5Syz155240 #endif 76ab25eeb5Syz155240 #ifdef sun 77ab25eeb5Syz155240 # include <net/af.h> 78ab25eeb5Syz155240 #endif 79ab25eeb5Syz155240 #include <net/route.h> 80ab25eeb5Syz155240 #include <netinet/in.h> 81ab25eeb5Syz155240 #include <netinet/in_systm.h> 82ab25eeb5Syz155240 #include <netinet/ip.h> 83ab25eeb5Syz155240 84ab25eeb5Syz155240 #ifdef RFC1825 85ab25eeb5Syz155240 # include <vpn/md5.h> 86ab25eeb5Syz155240 # include <vpn/ipsec.h> 87ab25eeb5Syz155240 extern struct ifnet vpnif; 88ab25eeb5Syz155240 #endif 89ab25eeb5Syz155240 90ab25eeb5Syz155240 #if !defined(linux) 91ab25eeb5Syz155240 # include <netinet/ip_var.h> 92ab25eeb5Syz155240 #endif 93ab25eeb5Syz155240 #include <netinet/tcp.h> 94ab25eeb5Syz155240 #include <netinet/udp.h> 95ab25eeb5Syz155240 #include <netinet/ip_icmp.h> 96ab25eeb5Syz155240 #include "netinet/ip_compat.h" 97ab25eeb5Syz155240 #include <netinet/tcpip.h> 98ab25eeb5Syz155240 #include "netinet/ip_fil.h" 99ab25eeb5Syz155240 #include "netinet/ip_nat.h" 100ab25eeb5Syz155240 #include "netinet/ip_frag.h" 101ab25eeb5Syz155240 #include "netinet/ip_state.h" 102ab25eeb5Syz155240 #include "netinet/ip_proxy.h" 103f4b3ec61Sdh155122 #include "netinet/ipf_stack.h" 104ab25eeb5Syz155240 #ifdef IPFILTER_SYNC 105ab25eeb5Syz155240 #include "netinet/ip_sync.h" 106ab25eeb5Syz155240 #endif 107ab25eeb5Syz155240 #if (__FreeBSD_version >= 300000) 108ab25eeb5Syz155240 # include <sys/malloc.h> 109ab25eeb5Syz155240 #endif 110ab25eeb5Syz155240 /* END OF INCLUDES */ 111ab25eeb5Syz155240 112ab25eeb5Syz155240 #undef SOCKADDR_IN 113ab25eeb5Syz155240 #define SOCKADDR_IN struct sockaddr_in 114ab25eeb5Syz155240 115ab25eeb5Syz155240 #if !defined(lint) 116ab25eeb5Syz155240 static const char sccsid[] = "@(#)ip_nat.c 1.11 6/5/96 (C) 1995 Darren Reed"; 117ab25eeb5Syz155240 static const char rcsid[] = "@(#)$Id: ip_nat.c,v 2.195.2.42 2005/08/11 19:51:36 darrenr Exp $"; 118ab25eeb5Syz155240 #endif 119ab25eeb5Syz155240 120ab25eeb5Syz155240 121ab25eeb5Syz155240 /* ======================================================================== */ 122ab25eeb5Syz155240 /* How the NAT is organised and works. */ 123ab25eeb5Syz155240 /* */ 124ab25eeb5Syz155240 /* Inside (interface y) NAT Outside (interface x) */ 125ab25eeb5Syz155240 /* -------------------- -+- ------------------------------------- */ 126ab25eeb5Syz155240 /* Packet going | out, processsed by fr_checknatout() for x */ 127ab25eeb5Syz155240 /* ------------> | ------------> */ 128ab25eeb5Syz155240 /* src=10.1.1.1 | src=192.1.1.1 */ 129ab25eeb5Syz155240 /* | */ 130ab25eeb5Syz155240 /* | in, processed by fr_checknatin() for x */ 131ab25eeb5Syz155240 /* <------------ | <------------ */ 132ab25eeb5Syz155240 /* dst=10.1.1.1 | dst=192.1.1.1 */ 133ab25eeb5Syz155240 /* -------------------- -+- ------------------------------------- */ 134ab25eeb5Syz155240 /* fr_checknatout() - changes ip_src and if required, sport */ 135ab25eeb5Syz155240 /* - creates a new mapping, if required. */ 136ab25eeb5Syz155240 /* fr_checknatin() - changes ip_dst and if required, dport */ 137ab25eeb5Syz155240 /* */ 138ab25eeb5Syz155240 /* In the NAT table, internal source is recorded as "in" and externally */ 139ab25eeb5Syz155240 /* seen as "out". */ 140ab25eeb5Syz155240 /* ======================================================================== */ 141ab25eeb5Syz155240 142ab25eeb5Syz155240 143f4b3ec61Sdh155122 static int nat_flushtable __P((ipf_stack_t *)); 144f4b3ec61Sdh155122 static int nat_clearlist __P((ipf_stack_t *)); 145f4b3ec61Sdh155122 static void nat_addnat __P((struct ipnat *, ipf_stack_t *)); 146f4b3ec61Sdh155122 static void nat_addrdr __P((struct ipnat *, ipf_stack_t *)); 147f4b3ec61Sdh155122 static void nat_delete __P((struct nat *, int, ipf_stack_t *)); 148f4b3ec61Sdh155122 static int fr_natgetent __P((caddr_t, ipf_stack_t *)); 149f4b3ec61Sdh155122 static int fr_natgetsz __P((caddr_t, ipf_stack_t *)); 150f4b3ec61Sdh155122 static int fr_natputent __P((caddr_t, int, ipf_stack_t *)); 151f4b3ec61Sdh155122 static void nat_tabmove __P((nat_t *, ipf_stack_t *)); 152ab25eeb5Syz155240 static int nat_match __P((fr_info_t *, ipnat_t *)); 153ab25eeb5Syz155240 static INLINE int nat_newmap __P((fr_info_t *, nat_t *, natinfo_t *)); 154ab25eeb5Syz155240 static INLINE int nat_newrdr __P((fr_info_t *, nat_t *, natinfo_t *)); 155ab25eeb5Syz155240 static hostmap_t *nat_hostmap __P((ipnat_t *, struct in_addr, 156f4b3ec61Sdh155122 struct in_addr, struct in_addr, u_32_t, 157f4b3ec61Sdh155122 ipf_stack_t *)); 158ab25eeb5Syz155240 static INLINE int nat_icmpquerytype4 __P((int)); 159*d6c23f6fSyx160601 static int nat_ruleaddrinit __P((ipnat_t *)); 160*d6c23f6fSyx160601 static int nat_siocaddnat __P((ipnat_t *, ipnat_t **, int, ipf_stack_t *)); 161*d6c23f6fSyx160601 static void nat_siocdelnat __P((ipnat_t *, ipnat_t **, int, ipf_stack_t *)); 162f4b3ec61Sdh155122 static INLINE int nat_icmperrortype4 __P((int)); 163ab25eeb5Syz155240 static INLINE int nat_finalise __P((fr_info_t *, nat_t *, natinfo_t *, 164ab25eeb5Syz155240 tcphdr_t *, nat_t **, int)); 165dcf3e898Sjojemann static INLINE int nat_resolverule __P((ipnat_t *, ipf_stack_t *)); 166381a2a9aSdr146992 static void nat_mssclamp __P((tcphdr_t *, u_32_t, u_short *)); 167f4b3ec61Sdh155122 static int nat_getnext __P((ipftoken_t *, ipfgeniter_t *, ipf_stack_t *)); 168f4b3ec61Sdh155122 static int nat_iterator __P((ipftoken_t *, ipfgeniter_t *, ipf_stack_t *)); 1693805c50fSan207044 static int nat_extraflush __P((int, ipf_stack_t *)); 1703805c50fSan207044 static int nat_earlydrop __P((ipftq_t *, int, ipf_stack_t *)); 1713805c50fSan207044 static int nat_flushclosing __P((int, ipf_stack_t *)); 1723805c50fSan207044 1733805c50fSan207044 1743805c50fSan207044 /* 1753805c50fSan207044 * Below we declare a list of constants used only in the nat_extraflush() 1763805c50fSan207044 * routine. We are placing it here, instead of in nat_extraflush() itself, 1773805c50fSan207044 * because we want to make it visible to tools such as mdb, nm etc., so the 1783805c50fSan207044 * values can easily be altered during debugging. 1793805c50fSan207044 */ 1803805c50fSan207044 static const int idletime_tab[] = { 1813805c50fSan207044 IPF_TTLVAL(30), /* 30 seconds */ 1823805c50fSan207044 IPF_TTLVAL(1800), /* 30 minutes */ 1833805c50fSan207044 IPF_TTLVAL(43200), /* 12 hours */ 1843805c50fSan207044 IPF_TTLVAL(345600), /* 4 days */ 1853805c50fSan207044 }; 186ab25eeb5Syz155240 1873c50f6d6San207044 #define NAT_HAS_L4_CHANGED(n) \ 18827dbc409San207044 (((n)->nat_flags & (IPN_TCPUDPICMP)) && \ 1893c50f6d6San207044 (n)->nat_inport != (n)->nat_outport) 1903c50f6d6San207044 191ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */ 192ab25eeb5Syz155240 /* Function: fr_natinit */ 193ab25eeb5Syz155240 /* Returns: int - 0 == success, -1 == failure */ 194ab25eeb5Syz155240 /* Parameters: Nil */ 195ab25eeb5Syz155240 /* */ 196ab25eeb5Syz155240 /* Initialise all of the NAT locks, tables and other structures. */ 197ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */ 198f4b3ec61Sdh155122 int fr_natinit(ifs) 199f4b3ec61Sdh155122 ipf_stack_t *ifs; 200ab25eeb5Syz155240 { 201ab25eeb5Syz155240 int i; 202ab25eeb5Syz155240 203f4b3ec61Sdh155122 KMALLOCS(ifs->ifs_nat_table[0], nat_t **, 204f4b3ec61Sdh155122 sizeof(nat_t *) * ifs->ifs_ipf_nattable_sz); 205f4b3ec61Sdh155122 if (ifs->ifs_nat_table[0] != NULL) 206f4b3ec61Sdh155122 bzero((char *)ifs->ifs_nat_table[0], 207f4b3ec61Sdh155122 ifs->ifs_ipf_nattable_sz * sizeof(nat_t *)); 208ab25eeb5Syz155240 else 209ab25eeb5Syz155240 return -1; 210ab25eeb5Syz155240 211f4b3ec61Sdh155122 KMALLOCS(ifs->ifs_nat_table[1], nat_t **, 212f4b3ec61Sdh155122 sizeof(nat_t *) * ifs->ifs_ipf_nattable_sz); 213f4b3ec61Sdh155122 if (ifs->ifs_nat_table[1] != NULL) 214f4b3ec61Sdh155122 bzero((char *)ifs->ifs_nat_table[1], 215f4b3ec61Sdh155122 ifs->ifs_ipf_nattable_sz * sizeof(nat_t *)); 216ab25eeb5Syz155240 else 217ab25eeb5Syz155240 return -2; 218ab25eeb5Syz155240 219f4b3ec61Sdh155122 KMALLOCS(ifs->ifs_nat_rules, ipnat_t **, 220f4b3ec61Sdh155122 sizeof(ipnat_t *) * ifs->ifs_ipf_natrules_sz); 221f4b3ec61Sdh155122 if (ifs->ifs_nat_rules != NULL) 222f4b3ec61Sdh155122 bzero((char *)ifs->ifs_nat_rules, 223f4b3ec61Sdh155122 ifs->ifs_ipf_natrules_sz * sizeof(ipnat_t *)); 224ab25eeb5Syz155240 else 225ab25eeb5Syz155240 return -3; 226ab25eeb5Syz155240 227f4b3ec61Sdh155122 KMALLOCS(ifs->ifs_rdr_rules, ipnat_t **, 228f4b3ec61Sdh155122 sizeof(ipnat_t *) * ifs->ifs_ipf_rdrrules_sz); 229f4b3ec61Sdh155122 if (ifs->ifs_rdr_rules != NULL) 230f4b3ec61Sdh155122 bzero((char *)ifs->ifs_rdr_rules, 231f4b3ec61Sdh155122 ifs->ifs_ipf_rdrrules_sz * sizeof(ipnat_t *)); 232ab25eeb5Syz155240 else 233ab25eeb5Syz155240 return -4; 234ab25eeb5Syz155240 235f4b3ec61Sdh155122 KMALLOCS(ifs->ifs_maptable, hostmap_t **, 236f4b3ec61Sdh155122 sizeof(hostmap_t *) * ifs->ifs_ipf_hostmap_sz); 237f4b3ec61Sdh155122 if (ifs->ifs_maptable != NULL) 238f4b3ec61Sdh155122 bzero((char *)ifs->ifs_maptable, 239f4b3ec61Sdh155122 sizeof(hostmap_t *) * ifs->ifs_ipf_hostmap_sz); 240ab25eeb5Syz155240 else 241ab25eeb5Syz155240 return -5; 242ab25eeb5Syz155240 243f4b3ec61Sdh155122 ifs->ifs_ipf_hm_maplist = NULL; 244ab25eeb5Syz155240 245f4b3ec61Sdh155122 KMALLOCS(ifs->ifs_nat_stats.ns_bucketlen[0], u_long *, 246f4b3ec61Sdh155122 ifs->ifs_ipf_nattable_sz * sizeof(u_long)); 247f4b3ec61Sdh155122 if (ifs->ifs_nat_stats.ns_bucketlen[0] == NULL) 248f4b3ec61Sdh155122 return -1; 249f4b3ec61Sdh155122 bzero((char *)ifs->ifs_nat_stats.ns_bucketlen[0], 250f4b3ec61Sdh155122 ifs->ifs_ipf_nattable_sz * sizeof(u_long)); 251ab25eeb5Syz155240 252f4b3ec61Sdh155122 KMALLOCS(ifs->ifs_nat_stats.ns_bucketlen[1], u_long *, 253f4b3ec61Sdh155122 ifs->ifs_ipf_nattable_sz * sizeof(u_long)); 254f4b3ec61Sdh155122 if (ifs->ifs_nat_stats.ns_bucketlen[1] == NULL) 255f4b3ec61Sdh155122 return -1; 256f4b3ec61Sdh155122 bzero((char *)ifs->ifs_nat_stats.ns_bucketlen[1], 257f4b3ec61Sdh155122 ifs->ifs_ipf_nattable_sz * sizeof(u_long)); 258ab25eeb5Syz155240 259f4b3ec61Sdh155122 if (ifs->ifs_fr_nat_maxbucket == 0) { 260f4b3ec61Sdh155122 for (i = ifs->ifs_ipf_nattable_sz; i > 0; i >>= 1) 261f4b3ec61Sdh155122 ifs->ifs_fr_nat_maxbucket++; 262f4b3ec61Sdh155122 ifs->ifs_fr_nat_maxbucket *= 2; 263ab25eeb5Syz155240 } 264ab25eeb5Syz155240 265f4b3ec61Sdh155122 fr_sttab_init(ifs->ifs_nat_tqb, ifs); 266ab25eeb5Syz155240 /* 267ab25eeb5Syz155240 * Increase this because we may have "keep state" following this too 268ab25eeb5Syz155240 * and packet storms can occur if this is removed too quickly. 269ab25eeb5Syz155240 */ 270f4b3ec61Sdh155122 ifs->ifs_nat_tqb[IPF_TCPS_CLOSED].ifq_ttl = ifs->ifs_fr_tcplastack; 271f4b3ec61Sdh155122 ifs->ifs_nat_tqb[IPF_TCP_NSTATES - 1].ifq_next = &ifs->ifs_nat_udptq; 272f4b3ec61Sdh155122 ifs->ifs_nat_udptq.ifq_ttl = ifs->ifs_fr_defnatage; 273f4b3ec61Sdh155122 ifs->ifs_nat_udptq.ifq_ref = 1; 274f4b3ec61Sdh155122 ifs->ifs_nat_udptq.ifq_head = NULL; 275f4b3ec61Sdh155122 ifs->ifs_nat_udptq.ifq_tail = &ifs->ifs_nat_udptq.ifq_head; 276f4b3ec61Sdh155122 MUTEX_INIT(&ifs->ifs_nat_udptq.ifq_lock, "nat ipftq udp tab"); 277f4b3ec61Sdh155122 ifs->ifs_nat_udptq.ifq_next = &ifs->ifs_nat_icmptq; 278f4b3ec61Sdh155122 ifs->ifs_nat_icmptq.ifq_ttl = ifs->ifs_fr_defnaticmpage; 279f4b3ec61Sdh155122 ifs->ifs_nat_icmptq.ifq_ref = 1; 280f4b3ec61Sdh155122 ifs->ifs_nat_icmptq.ifq_head = NULL; 281f4b3ec61Sdh155122 ifs->ifs_nat_icmptq.ifq_tail = &ifs->ifs_nat_icmptq.ifq_head; 282f4b3ec61Sdh155122 MUTEX_INIT(&ifs->ifs_nat_icmptq.ifq_lock, "nat icmp ipftq tab"); 283f4b3ec61Sdh155122 ifs->ifs_nat_icmptq.ifq_next = &ifs->ifs_nat_iptq; 284f4b3ec61Sdh155122 ifs->ifs_nat_iptq.ifq_ttl = ifs->ifs_fr_defnatipage; 285f4b3ec61Sdh155122 ifs->ifs_nat_iptq.ifq_ref = 1; 286f4b3ec61Sdh155122 ifs->ifs_nat_iptq.ifq_head = NULL; 287f4b3ec61Sdh155122 ifs->ifs_nat_iptq.ifq_tail = &ifs->ifs_nat_iptq.ifq_head; 288f4b3ec61Sdh155122 MUTEX_INIT(&ifs->ifs_nat_iptq.ifq_lock, "nat ip ipftq tab"); 289f4b3ec61Sdh155122 ifs->ifs_nat_iptq.ifq_next = NULL; 290ab25eeb5Syz155240 291ab25eeb5Syz155240 for (i = 0; i < IPF_TCP_NSTATES; i++) { 292f4b3ec61Sdh155122 if (ifs->ifs_nat_tqb[i].ifq_ttl < ifs->ifs_fr_defnaticmpage) 293f4b3ec61Sdh155122 ifs->ifs_nat_tqb[i].ifq_ttl = ifs->ifs_fr_defnaticmpage; 294ab25eeb5Syz155240 #ifdef LARGE_NAT 295f4b3ec61Sdh155122 else if (ifs->ifs_nat_tqb[i].ifq_ttl > ifs->ifs_fr_defnatage) 296f4b3ec61Sdh155122 ifs->ifs_nat_tqb[i].ifq_ttl = ifs->ifs_fr_defnatage; 297ab25eeb5Syz155240 #endif 298ab25eeb5Syz155240 } 299ab25eeb5Syz155240 300ab25eeb5Syz155240 /* 301ab25eeb5Syz155240 * Increase this because we may have "keep state" following 302ab25eeb5Syz155240 * this too and packet storms can occur if this is removed 303ab25eeb5Syz155240 * too quickly. 304ab25eeb5Syz155240 */ 305f4b3ec61Sdh155122 ifs->ifs_nat_tqb[IPF_TCPS_CLOSED].ifq_ttl = 306f4b3ec61Sdh155122 ifs->ifs_nat_tqb[IPF_TCPS_LAST_ACK].ifq_ttl; 307ab25eeb5Syz155240 308f4b3ec61Sdh155122 RWLOCK_INIT(&ifs->ifs_ipf_nat, "ipf IP NAT rwlock"); 309f4b3ec61Sdh155122 RWLOCK_INIT(&ifs->ifs_ipf_natfrag, "ipf IP NAT-Frag rwlock"); 310f4b3ec61Sdh155122 MUTEX_INIT(&ifs->ifs_ipf_nat_new, "ipf nat new mutex"); 311f4b3ec61Sdh155122 MUTEX_INIT(&ifs->ifs_ipf_natio, "ipf nat io mutex"); 312ab25eeb5Syz155240 313f4b3ec61Sdh155122 ifs->ifs_fr_nat_init = 1; 314ab25eeb5Syz155240 315ab25eeb5Syz155240 return 0; 316ab25eeb5Syz155240 } 317ab25eeb5Syz155240 318ab25eeb5Syz155240 319ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */ 320ab25eeb5Syz155240 /* Function: nat_addrdr */ 321ab25eeb5Syz155240 /* Returns: Nil */ 322ab25eeb5Syz155240 /* Parameters: n(I) - pointer to NAT rule to add */ 323ab25eeb5Syz155240 /* */ 324ab25eeb5Syz155240 /* Adds a redirect rule to the hash table of redirect rules and the list of */ 325ab25eeb5Syz155240 /* loaded NAT rules. Updates the bitmask indicating which netmasks are in */ 326ab25eeb5Syz155240 /* use by redirect rules. */ 327ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */ 328f4b3ec61Sdh155122 static void nat_addrdr(n, ifs) 329ab25eeb5Syz155240 ipnat_t *n; 330f4b3ec61Sdh155122 ipf_stack_t *ifs; 331ab25eeb5Syz155240 { 332ab25eeb5Syz155240 ipnat_t **np; 333ab25eeb5Syz155240 u_32_t j; 334ab25eeb5Syz155240 u_int hv; 335ab25eeb5Syz155240 int k; 336ab25eeb5Syz155240 337ab25eeb5Syz155240 k = count4bits(n->in_outmsk); 338ab25eeb5Syz155240 if ((k >= 0) && (k != 32)) 339f4b3ec61Sdh155122 ifs->ifs_rdr_masks |= 1 << k; 340ab25eeb5Syz155240 j = (n->in_outip & n->in_outmsk); 341f4b3ec61Sdh155122 hv = NAT_HASH_FN(j, 0, ifs->ifs_ipf_rdrrules_sz); 342f4b3ec61Sdh155122 np = ifs->ifs_rdr_rules + hv; 343ab25eeb5Syz155240 while (*np != NULL) 344ab25eeb5Syz155240 np = &(*np)->in_rnext; 345ab25eeb5Syz155240 n->in_rnext = NULL; 346ab25eeb5Syz155240 n->in_prnext = np; 347ab25eeb5Syz155240 n->in_hv = hv; 348ab25eeb5Syz155240 *np = n; 349ab25eeb5Syz155240 } 350ab25eeb5Syz155240 351ab25eeb5Syz155240 352ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */ 353ab25eeb5Syz155240 /* Function: nat_addnat */ 354ab25eeb5Syz155240 /* Returns: Nil */ 355ab25eeb5Syz155240 /* Parameters: n(I) - pointer to NAT rule to add */ 356ab25eeb5Syz155240 /* */ 357ab25eeb5Syz155240 /* Adds a NAT map rule to the hash table of rules and the list of loaded */ 358ab25eeb5Syz155240 /* NAT rules. Updates the bitmask indicating which netmasks are in use by */ 359ab25eeb5Syz155240 /* redirect rules. */ 360ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */ 361f4b3ec61Sdh155122 static void nat_addnat(n, ifs) 362ab25eeb5Syz155240 ipnat_t *n; 363f4b3ec61Sdh155122 ipf_stack_t *ifs; 364ab25eeb5Syz155240 { 365ab25eeb5Syz155240 ipnat_t **np; 366ab25eeb5Syz155240 u_32_t j; 367ab25eeb5Syz155240 u_int hv; 368ab25eeb5Syz155240 int k; 369ab25eeb5Syz155240 370ab25eeb5Syz155240 k = count4bits(n->in_inmsk); 371ab25eeb5Syz155240 if ((k >= 0) && (k != 32)) 372f4b3ec61Sdh155122 ifs->ifs_nat_masks |= 1 << k; 373ab25eeb5Syz155240 j = (n->in_inip & n->in_inmsk); 374f4b3ec61Sdh155122 hv = NAT_HASH_FN(j, 0, ifs->ifs_ipf_natrules_sz); 375f4b3ec61Sdh155122 np = ifs->ifs_nat_rules + hv; 376ab25eeb5Syz155240 while (*np != NULL) 377ab25eeb5Syz155240 np = &(*np)->in_mnext; 378ab25eeb5Syz155240 n->in_mnext = NULL; 379ab25eeb5Syz155240 n->in_pmnext = np; 380ab25eeb5Syz155240 n->in_hv = hv; 381ab25eeb5Syz155240 *np = n; 382ab25eeb5Syz155240 } 383ab25eeb5Syz155240 384ab25eeb5Syz155240 385ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */ 386ab25eeb5Syz155240 /* Function: nat_delrdr */ 387ab25eeb5Syz155240 /* Returns: Nil */ 388ab25eeb5Syz155240 /* Parameters: n(I) - pointer to NAT rule to delete */ 389ab25eeb5Syz155240 /* */ 390ab25eeb5Syz155240 /* Removes a redirect rule from the hash table of redirect rules. */ 391ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */ 392*d6c23f6fSyx160601 void nat_delrdr(n) 393ab25eeb5Syz155240 ipnat_t *n; 394ab25eeb5Syz155240 { 395ab25eeb5Syz155240 if (n->in_rnext) 396ab25eeb5Syz155240 n->in_rnext->in_prnext = n->in_prnext; 397ab25eeb5Syz155240 *n->in_prnext = n->in_rnext; 398ab25eeb5Syz155240 } 399ab25eeb5Syz155240 400ab25eeb5Syz155240 401ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */ 402ab25eeb5Syz155240 /* Function: nat_delnat */ 403ab25eeb5Syz155240 /* Returns: Nil */ 404ab25eeb5Syz155240 /* Parameters: n(I) - pointer to NAT rule to delete */ 405ab25eeb5Syz155240 /* */ 406ab25eeb5Syz155240 /* Removes a NAT map rule from the hash table of NAT map rules. */ 407ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */ 408*d6c23f6fSyx160601 void nat_delnat(n) 409ab25eeb5Syz155240 ipnat_t *n; 410ab25eeb5Syz155240 { 411ab25eeb5Syz155240 if (n->in_mnext != NULL) 412ab25eeb5Syz155240 n->in_mnext->in_pmnext = n->in_pmnext; 413ab25eeb5Syz155240 *n->in_pmnext = n->in_mnext; 414ab25eeb5Syz155240 } 415ab25eeb5Syz155240 416ab25eeb5Syz155240 417ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */ 418ab25eeb5Syz155240 /* Function: nat_hostmap */ 419ab25eeb5Syz155240 /* Returns: struct hostmap* - NULL if no hostmap could be created, */ 420ab25eeb5Syz155240 /* else a pointer to the hostmapping to use */ 421ab25eeb5Syz155240 /* Parameters: np(I) - pointer to NAT rule */ 422ab25eeb5Syz155240 /* real(I) - real IP address */ 423ab25eeb5Syz155240 /* map(I) - mapped IP address */ 424ab25eeb5Syz155240 /* port(I) - destination port number */ 425ab25eeb5Syz155240 /* Write Locks: ipf_nat */ 426ab25eeb5Syz155240 /* */ 427ab25eeb5Syz155240 /* Check if an ip address has already been allocated for a given mapping */ 428ab25eeb5Syz155240 /* that is not doing port based translation. If is not yet allocated, then */ 429ab25eeb5Syz155240 /* create a new entry if a non-NULL NAT rule pointer has been supplied. */ 430ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */ 431f4b3ec61Sdh155122 static struct hostmap *nat_hostmap(np, src, dst, map, port, ifs) 432ab25eeb5Syz155240 ipnat_t *np; 433ab25eeb5Syz155240 struct in_addr src; 434ab25eeb5Syz155240 struct in_addr dst; 435ab25eeb5Syz155240 struct in_addr map; 436ab25eeb5Syz155240 u_32_t port; 437f4b3ec61Sdh155122 ipf_stack_t *ifs; 438ab25eeb5Syz155240 { 439ab25eeb5Syz155240 hostmap_t *hm; 440ab25eeb5Syz155240 u_int hv; 441ab25eeb5Syz155240 442ab25eeb5Syz155240 hv = (src.s_addr ^ dst.s_addr); 443ab25eeb5Syz155240 hv += src.s_addr; 444ab25eeb5Syz155240 hv += dst.s_addr; 445ab25eeb5Syz155240 hv %= HOSTMAP_SIZE; 446f4b3ec61Sdh155122 for (hm = ifs->ifs_maptable[hv]; hm; hm = hm->hm_next) 447ab25eeb5Syz155240 if ((hm->hm_srcip.s_addr == src.s_addr) && 448ab25eeb5Syz155240 (hm->hm_dstip.s_addr == dst.s_addr) && 449ab25eeb5Syz155240 ((np == NULL) || (np == hm->hm_ipnat)) && 450ab25eeb5Syz155240 ((port == 0) || (port == hm->hm_port))) { 451ab25eeb5Syz155240 hm->hm_ref++; 452ab25eeb5Syz155240 return hm; 453ab25eeb5Syz155240 } 454ab25eeb5Syz155240 455ab25eeb5Syz155240 if (np == NULL) 456ab25eeb5Syz155240 return NULL; 457ab25eeb5Syz155240 458ab25eeb5Syz155240 KMALLOC(hm, hostmap_t *); 459ab25eeb5Syz155240 if (hm) { 460f4b3ec61Sdh155122 hm->hm_hnext = ifs->ifs_ipf_hm_maplist; 461f4b3ec61Sdh155122 hm->hm_phnext = &ifs->ifs_ipf_hm_maplist; 462f4b3ec61Sdh155122 if (ifs->ifs_ipf_hm_maplist != NULL) 463f4b3ec61Sdh155122 ifs->ifs_ipf_hm_maplist->hm_phnext = &hm->hm_hnext; 464f4b3ec61Sdh155122 ifs->ifs_ipf_hm_maplist = hm; 465f4b3ec61Sdh155122 466f4b3ec61Sdh155122 hm->hm_next = ifs->ifs_maptable[hv]; 467f4b3ec61Sdh155122 hm->hm_pnext = ifs->ifs_maptable + hv; 468f4b3ec61Sdh155122 if (ifs->ifs_maptable[hv] != NULL) 469f4b3ec61Sdh155122 ifs->ifs_maptable[hv]->hm_pnext = &hm->hm_next; 470f4b3ec61Sdh155122 ifs->ifs_maptable[hv] = hm; 471ab25eeb5Syz155240 hm->hm_ipnat = np; 472ab25eeb5Syz155240 hm->hm_srcip = src; 473ab25eeb5Syz155240 hm->hm_dstip = dst; 474ab25eeb5Syz155240 hm->hm_mapip = map; 475ab25eeb5Syz155240 hm->hm_ref = 1; 476ab25eeb5Syz155240 hm->hm_port = port; 477*d6c23f6fSyx160601 hm->hm_v = 4; 478ab25eeb5Syz155240 } 479ab25eeb5Syz155240 return hm; 480ab25eeb5Syz155240 } 481ab25eeb5Syz155240 482ab25eeb5Syz155240 483ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */ 48490b0a856Sjojemann /* Function: fr_hostmapdel */ 485ab25eeb5Syz155240 /* Returns: Nil */ 48690b0a856Sjojemann /* Parameters: hmp(I) - pointer to pointer to hostmap structure */ 487ab25eeb5Syz155240 /* Write Locks: ipf_nat */ 488ab25eeb5Syz155240 /* */ 489ab25eeb5Syz155240 /* Decrement the references to this hostmap structure by one. If this */ 490ab25eeb5Syz155240 /* reaches zero then remove it and free it. */ 491ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */ 49290b0a856Sjojemann void fr_hostmapdel(hmp) 49390b0a856Sjojemann struct hostmap **hmp; 494ab25eeb5Syz155240 { 49590b0a856Sjojemann struct hostmap *hm; 49690b0a856Sjojemann 49790b0a856Sjojemann hm = *hmp; 49890b0a856Sjojemann *hmp = NULL; 49990b0a856Sjojemann 500ab25eeb5Syz155240 hm->hm_ref--; 501ab25eeb5Syz155240 if (hm->hm_ref == 0) { 502ab25eeb5Syz155240 if (hm->hm_next) 503ab25eeb5Syz155240 hm->hm_next->hm_pnext = hm->hm_pnext; 504ab25eeb5Syz155240 *hm->hm_pnext = hm->hm_next; 505f4b3ec61Sdh155122 if (hm->hm_hnext) 506f4b3ec61Sdh155122 hm->hm_hnext->hm_phnext = hm->hm_phnext; 507f4b3ec61Sdh155122 *hm->hm_phnext = hm->hm_hnext; 508ab25eeb5Syz155240 KFREE(hm); 509ab25eeb5Syz155240 } 510ab25eeb5Syz155240 } 511ab25eeb5Syz155240 512ab25eeb5Syz155240 513ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */ 514ab25eeb5Syz155240 /* Function: fix_outcksum */ 515ab25eeb5Syz155240 /* Returns: Nil */ 516381a2a9aSdr146992 /* Parameters: sp(I) - location of 16bit checksum to update */ 517ab25eeb5Syz155240 /* n((I) - amount to adjust checksum by */ 518ab25eeb5Syz155240 /* */ 519ab25eeb5Syz155240 /* Adjusts the 16bit checksum by "n" for packets going out. */ 520ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */ 521381a2a9aSdr146992 void fix_outcksum(sp, n) 522ab25eeb5Syz155240 u_short *sp; 523ab25eeb5Syz155240 u_32_t n; 524ab25eeb5Syz155240 { 525ab25eeb5Syz155240 u_short sumshort; 526ab25eeb5Syz155240 u_32_t sum1; 527ab25eeb5Syz155240 528ab25eeb5Syz155240 if (n == 0) 529ab25eeb5Syz155240 return; 530ab25eeb5Syz155240 531ab25eeb5Syz155240 sum1 = (~ntohs(*sp)) & 0xffff; 532ab25eeb5Syz155240 sum1 += (n); 533ab25eeb5Syz155240 sum1 = (sum1 >> 16) + (sum1 & 0xffff); 534ab25eeb5Syz155240 /* Again */ 535ab25eeb5Syz155240 sum1 = (sum1 >> 16) + (sum1 & 0xffff); 536ab25eeb5Syz155240 sumshort = ~(u_short)sum1; 537ab25eeb5Syz155240 *(sp) = htons(sumshort); 538ab25eeb5Syz155240 } 539ab25eeb5Syz155240 540ab25eeb5Syz155240 541ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */ 542ab25eeb5Syz155240 /* Function: fix_incksum */ 543ab25eeb5Syz155240 /* Returns: Nil */ 544381a2a9aSdr146992 /* Parameters: sp(I) - location of 16bit checksum to update */ 545ab25eeb5Syz155240 /* n((I) - amount to adjust checksum by */ 546ab25eeb5Syz155240 /* */ 547ab25eeb5Syz155240 /* Adjusts the 16bit checksum by "n" for packets going in. */ 548ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */ 549381a2a9aSdr146992 void fix_incksum(sp, n) 550ab25eeb5Syz155240 u_short *sp; 551ab25eeb5Syz155240 u_32_t n; 552ab25eeb5Syz155240 { 553ab25eeb5Syz155240 u_short sumshort; 554ab25eeb5Syz155240 u_32_t sum1; 555ab25eeb5Syz155240 556ab25eeb5Syz155240 if (n == 0) 557ab25eeb5Syz155240 return; 558ab25eeb5Syz155240 559ab25eeb5Syz155240 sum1 = (~ntohs(*sp)) & 0xffff; 560ab25eeb5Syz155240 sum1 += ~(n) & 0xffff; 561ab25eeb5Syz155240 sum1 = (sum1 >> 16) + (sum1 & 0xffff); 562ab25eeb5Syz155240 /* Again */ 563ab25eeb5Syz155240 sum1 = (sum1 >> 16) + (sum1 & 0xffff); 564ab25eeb5Syz155240 sumshort = ~(u_short)sum1; 565ab25eeb5Syz155240 *(sp) = htons(sumshort); 566ab25eeb5Syz155240 } 567ab25eeb5Syz155240 568ab25eeb5Syz155240 569ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */ 570ab25eeb5Syz155240 /* Function: fix_datacksum */ 571ab25eeb5Syz155240 /* Returns: Nil */ 572ab25eeb5Syz155240 /* Parameters: sp(I) - location of 16bit checksum to update */ 573ab25eeb5Syz155240 /* n((I) - amount to adjust checksum by */ 574ab25eeb5Syz155240 /* */ 575ab25eeb5Syz155240 /* Fix_datacksum is used *only* for the adjustments of checksums in the */ 576ab25eeb5Syz155240 /* data section of an IP packet. */ 577ab25eeb5Syz155240 /* */ 578ab25eeb5Syz155240 /* The only situation in which you need to do this is when NAT'ing an */ 579ab25eeb5Syz155240 /* ICMP error message. Such a message, contains in its body the IP header */ 580ab25eeb5Syz155240 /* of the original IP packet, that causes the error. */ 581ab25eeb5Syz155240 /* */ 582ab25eeb5Syz155240 /* You can't use fix_incksum or fix_outcksum in that case, because for the */ 583ab25eeb5Syz155240 /* kernel the data section of the ICMP error is just data, and no special */ 584ab25eeb5Syz155240 /* processing like hardware cksum or ntohs processing have been done by the */ 585ab25eeb5Syz155240 /* kernel on the data section. */ 586ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */ 587ab25eeb5Syz155240 void fix_datacksum(sp, n) 588ab25eeb5Syz155240 u_short *sp; 589ab25eeb5Syz155240 u_32_t n; 590ab25eeb5Syz155240 { 591ab25eeb5Syz155240 u_short sumshort; 592ab25eeb5Syz155240 u_32_t sum1; 593ab25eeb5Syz155240 594ab25eeb5Syz155240 if (n == 0) 595ab25eeb5Syz155240 return; 596ab25eeb5Syz155240 597ab25eeb5Syz155240 sum1 = (~ntohs(*sp)) & 0xffff; 598ab25eeb5Syz155240 sum1 += (n); 599ab25eeb5Syz155240 sum1 = (sum1 >> 16) + (sum1 & 0xffff); 600ab25eeb5Syz155240 /* Again */ 601ab25eeb5Syz155240 sum1 = (sum1 >> 16) + (sum1 & 0xffff); 602ab25eeb5Syz155240 sumshort = ~(u_short)sum1; 603ab25eeb5Syz155240 *(sp) = htons(sumshort); 604ab25eeb5Syz155240 } 605ab25eeb5Syz155240 606ab25eeb5Syz155240 607ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */ 608ab25eeb5Syz155240 /* Function: fr_nat_ioctl */ 609ab25eeb5Syz155240 /* Returns: int - 0 == success, != 0 == failure */ 610ab25eeb5Syz155240 /* Parameters: data(I) - pointer to ioctl data */ 611ab25eeb5Syz155240 /* cmd(I) - ioctl command integer */ 612ab25eeb5Syz155240 /* mode(I) - file mode bits used with open */ 613ab25eeb5Syz155240 /* */ 614ab25eeb5Syz155240 /* Processes an ioctl call made to operate on the IP Filter NAT device. */ 615ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */ 616f4b3ec61Sdh155122 int fr_nat_ioctl(data, cmd, mode, uid, ctx, ifs) 617ab25eeb5Syz155240 ioctlcmd_t cmd; 618ab25eeb5Syz155240 caddr_t data; 619f4b3ec61Sdh155122 int mode, uid; 620f4b3ec61Sdh155122 void *ctx; 621f4b3ec61Sdh155122 ipf_stack_t *ifs; 622ab25eeb5Syz155240 { 623ab25eeb5Syz155240 ipnat_t *nat, *nt, *n = NULL, **np = NULL; 624ab25eeb5Syz155240 int error = 0, ret, arg, getlock; 625ab25eeb5Syz155240 ipnat_t natd; 626ab25eeb5Syz155240 627ab25eeb5Syz155240 #if (BSD >= 199306) && defined(_KERNEL) 628ab25eeb5Syz155240 if ((securelevel >= 2) && (mode & FWRITE)) 629ab25eeb5Syz155240 return EPERM; 630ab25eeb5Syz155240 #endif 631ab25eeb5Syz155240 632ab25eeb5Syz155240 #if defined(__osf__) && defined(_KERNEL) 633ab25eeb5Syz155240 getlock = 0; 634ab25eeb5Syz155240 #else 635ab25eeb5Syz155240 getlock = (mode & NAT_LOCKHELD) ? 0 : 1; 636ab25eeb5Syz155240 #endif 637ab25eeb5Syz155240 638ab25eeb5Syz155240 nat = NULL; /* XXX gcc -Wuninitialized */ 639ab25eeb5Syz155240 if (cmd == (ioctlcmd_t)SIOCADNAT) { 640ab25eeb5Syz155240 KMALLOC(nt, ipnat_t *); 641ab25eeb5Syz155240 } else { 642ab25eeb5Syz155240 nt = NULL; 643ab25eeb5Syz155240 } 644ab25eeb5Syz155240 645ab25eeb5Syz155240 if ((cmd == (ioctlcmd_t)SIOCADNAT) || (cmd == (ioctlcmd_t)SIOCRMNAT)) { 646ab25eeb5Syz155240 if (mode & NAT_SYSSPACE) { 647ab25eeb5Syz155240 bcopy(data, (char *)&natd, sizeof(natd)); 648ab25eeb5Syz155240 error = 0; 649ab25eeb5Syz155240 } else { 650ab25eeb5Syz155240 error = fr_inobj(data, &natd, IPFOBJ_IPNAT); 651ab25eeb5Syz155240 } 652ab25eeb5Syz155240 653ab25eeb5Syz155240 } else if (cmd == (ioctlcmd_t)SIOCIPFFL) { /* SIOCFLNAT & SIOCCNATL */ 654ab25eeb5Syz155240 BCOPYIN(data, &arg, sizeof(arg)); 655ab25eeb5Syz155240 } 656ab25eeb5Syz155240 657ab25eeb5Syz155240 if (error != 0) 658ab25eeb5Syz155240 goto done; 659ab25eeb5Syz155240 660ab25eeb5Syz155240 /* 661ab25eeb5Syz155240 * For add/delete, look to see if the NAT entry is already present 662ab25eeb5Syz155240 */ 663ab25eeb5Syz155240 if ((cmd == (ioctlcmd_t)SIOCADNAT) || (cmd == (ioctlcmd_t)SIOCRMNAT)) { 664ab25eeb5Syz155240 nat = &natd; 665ab25eeb5Syz155240 if (nat->in_v == 0) /* For backward compat. */ 666ab25eeb5Syz155240 nat->in_v = 4; 667ab25eeb5Syz155240 nat->in_flags &= IPN_USERFLAGS; 668ab25eeb5Syz155240 if ((nat->in_redir & NAT_MAPBLK) == 0) { 669ab25eeb5Syz155240 if ((nat->in_flags & IPN_SPLIT) == 0) 670ab25eeb5Syz155240 nat->in_inip &= nat->in_inmsk; 671ab25eeb5Syz155240 if ((nat->in_flags & IPN_IPRANGE) == 0) 672ab25eeb5Syz155240 nat->in_outip &= nat->in_outmsk; 673ab25eeb5Syz155240 } 674f4b3ec61Sdh155122 MUTEX_ENTER(&ifs->ifs_ipf_natio); 675f4b3ec61Sdh155122 for (np = &ifs->ifs_nat_list; ((n = *np) != NULL); 676f4b3ec61Sdh155122 np = &n->in_next) 6778899fcfaSjojemann if (bcmp((char *)&nat->in_flags, (char *)&n->in_flags, 6788899fcfaSjojemann IPN_CMPSIZ) == 0) { 6798899fcfaSjojemann if (nat->in_redir == NAT_REDIRECT && 6808899fcfaSjojemann nat->in_pnext != n->in_pnext) 6818899fcfaSjojemann continue; 682ab25eeb5Syz155240 break; 683ab25eeb5Syz155240 } 6848899fcfaSjojemann } 685ab25eeb5Syz155240 686ab25eeb5Syz155240 switch (cmd) 687ab25eeb5Syz155240 { 688f4b3ec61Sdh155122 case SIOCGENITER : 689f4b3ec61Sdh155122 { 690f4b3ec61Sdh155122 ipfgeniter_t iter; 691f4b3ec61Sdh155122 ipftoken_t *token; 692f4b3ec61Sdh155122 693f4b3ec61Sdh155122 error = fr_inobj(data, &iter, IPFOBJ_GENITER); 694f4b3ec61Sdh155122 if (error != 0) 695f4b3ec61Sdh155122 break; 696f4b3ec61Sdh155122 697f4b3ec61Sdh155122 token = ipf_findtoken(iter.igi_type, uid, ctx, ifs); 698f4b3ec61Sdh155122 if (token != NULL) 699f4b3ec61Sdh155122 error = nat_iterator(token, &iter, ifs); 700f4b3ec61Sdh155122 else 701f4b3ec61Sdh155122 error = ESRCH; 702f4b3ec61Sdh155122 RWLOCK_EXIT(&ifs->ifs_ipf_tokens); 703f4b3ec61Sdh155122 break; 704f4b3ec61Sdh155122 } 705ab25eeb5Syz155240 #ifdef IPFILTER_LOG 706ab25eeb5Syz155240 case SIOCIPFFB : 707ab25eeb5Syz155240 { 708ab25eeb5Syz155240 int tmp; 709ab25eeb5Syz155240 710ab25eeb5Syz155240 if (!(mode & FWRITE)) 711ab25eeb5Syz155240 error = EPERM; 712ab25eeb5Syz155240 else { 713f4b3ec61Sdh155122 tmp = ipflog_clear(IPL_LOGNAT, ifs); 714ab25eeb5Syz155240 BCOPYOUT((char *)&tmp, (char *)data, sizeof(tmp)); 715ab25eeb5Syz155240 } 716ab25eeb5Syz155240 break; 717ab25eeb5Syz155240 } 718ab25eeb5Syz155240 case SIOCSETLG : 719ab25eeb5Syz155240 if (!(mode & FWRITE)) 720ab25eeb5Syz155240 error = EPERM; 721ab25eeb5Syz155240 else { 722f4b3ec61Sdh155122 BCOPYIN((char *)data, 723f4b3ec61Sdh155122 (char *)&ifs->ifs_nat_logging, 724f4b3ec61Sdh155122 sizeof(ifs->ifs_nat_logging)); 725ab25eeb5Syz155240 } 726ab25eeb5Syz155240 break; 727ab25eeb5Syz155240 case SIOCGETLG : 728f4b3ec61Sdh155122 BCOPYOUT((char *)&ifs->ifs_nat_logging, (char *)data, 729f4b3ec61Sdh155122 sizeof(ifs->ifs_nat_logging)); 730ab25eeb5Syz155240 break; 731ab25eeb5Syz155240 case FIONREAD : 732f4b3ec61Sdh155122 arg = ifs->ifs_iplused[IPL_LOGNAT]; 733ab25eeb5Syz155240 BCOPYOUT(&arg, data, sizeof(arg)); 734ab25eeb5Syz155240 break; 735ab25eeb5Syz155240 #endif 736ab25eeb5Syz155240 case SIOCADNAT : 737ab25eeb5Syz155240 if (!(mode & FWRITE)) { 738ab25eeb5Syz155240 error = EPERM; 739ab25eeb5Syz155240 } else if (n != NULL) { 740ab25eeb5Syz155240 error = EEXIST; 741ab25eeb5Syz155240 } else if (nt == NULL) { 742ab25eeb5Syz155240 error = ENOMEM; 743ab25eeb5Syz155240 } 744ab25eeb5Syz155240 if (error != 0) { 745f4b3ec61Sdh155122 MUTEX_EXIT(&ifs->ifs_ipf_natio); 746ab25eeb5Syz155240 break; 747ab25eeb5Syz155240 } 748ab25eeb5Syz155240 bcopy((char *)nat, (char *)nt, sizeof(*n)); 749f4b3ec61Sdh155122 error = nat_siocaddnat(nt, np, getlock, ifs); 750f4b3ec61Sdh155122 MUTEX_EXIT(&ifs->ifs_ipf_natio); 751ab25eeb5Syz155240 if (error == 0) 752ab25eeb5Syz155240 nt = NULL; 753ab25eeb5Syz155240 break; 754ab25eeb5Syz155240 case SIOCRMNAT : 755ab25eeb5Syz155240 if (!(mode & FWRITE)) { 756ab25eeb5Syz155240 error = EPERM; 757ab25eeb5Syz155240 n = NULL; 758ab25eeb5Syz155240 } else if (n == NULL) { 759ab25eeb5Syz155240 error = ESRCH; 760ab25eeb5Syz155240 } 761ab25eeb5Syz155240 762ab25eeb5Syz155240 if (error != 0) { 763f4b3ec61Sdh155122 MUTEX_EXIT(&ifs->ifs_ipf_natio); 764ab25eeb5Syz155240 break; 765ab25eeb5Syz155240 } 766f4b3ec61Sdh155122 nat_siocdelnat(n, np, getlock, ifs); 767ab25eeb5Syz155240 768f4b3ec61Sdh155122 MUTEX_EXIT(&ifs->ifs_ipf_natio); 769ab25eeb5Syz155240 n = NULL; 770ab25eeb5Syz155240 break; 771ab25eeb5Syz155240 case SIOCGNATS : 772f4b3ec61Sdh155122 ifs->ifs_nat_stats.ns_table[0] = ifs->ifs_nat_table[0]; 773f4b3ec61Sdh155122 ifs->ifs_nat_stats.ns_table[1] = ifs->ifs_nat_table[1]; 774f4b3ec61Sdh155122 ifs->ifs_nat_stats.ns_list = ifs->ifs_nat_list; 775f4b3ec61Sdh155122 ifs->ifs_nat_stats.ns_maptable = ifs->ifs_maptable; 776f4b3ec61Sdh155122 ifs->ifs_nat_stats.ns_maplist = ifs->ifs_ipf_hm_maplist; 777f4b3ec61Sdh155122 ifs->ifs_nat_stats.ns_nattab_max = ifs->ifs_ipf_nattable_max; 778f4b3ec61Sdh155122 ifs->ifs_nat_stats.ns_nattab_sz = ifs->ifs_ipf_nattable_sz; 779f4b3ec61Sdh155122 ifs->ifs_nat_stats.ns_rultab_sz = ifs->ifs_ipf_natrules_sz; 780f4b3ec61Sdh155122 ifs->ifs_nat_stats.ns_rdrtab_sz = ifs->ifs_ipf_rdrrules_sz; 781f4b3ec61Sdh155122 ifs->ifs_nat_stats.ns_hostmap_sz = ifs->ifs_ipf_hostmap_sz; 782f4b3ec61Sdh155122 ifs->ifs_nat_stats.ns_instances = ifs->ifs_nat_instances; 783f4b3ec61Sdh155122 ifs->ifs_nat_stats.ns_apslist = ifs->ifs_ap_sess_list; 784f4b3ec61Sdh155122 error = fr_outobj(data, &ifs->ifs_nat_stats, IPFOBJ_NATSTAT); 785ab25eeb5Syz155240 break; 786ab25eeb5Syz155240 case SIOCGNATL : 787ab25eeb5Syz155240 { 788ab25eeb5Syz155240 natlookup_t nl; 789ab25eeb5Syz155240 790ab25eeb5Syz155240 if (getlock) { 791f4b3ec61Sdh155122 READ_ENTER(&ifs->ifs_ipf_nat); 792ab25eeb5Syz155240 } 793ab25eeb5Syz155240 error = fr_inobj(data, &nl, IPFOBJ_NATLOOKUP); 794*d6c23f6fSyx160601 if (nl.nl_v != 6) 795*d6c23f6fSyx160601 nl.nl_v = 4; 796ab25eeb5Syz155240 if (error == 0) { 797*d6c23f6fSyx160601 void *ptr; 798*d6c23f6fSyx160601 799*d6c23f6fSyx160601 switch (nl.nl_v) 800*d6c23f6fSyx160601 { 801*d6c23f6fSyx160601 case 4: 802*d6c23f6fSyx160601 ptr = nat_lookupredir(&nl, ifs); 803*d6c23f6fSyx160601 break; 804*d6c23f6fSyx160601 #ifdef USE_INET6 805*d6c23f6fSyx160601 case 6: 806*d6c23f6fSyx160601 ptr = nat6_lookupredir(&nl, ifs); 807*d6c23f6fSyx160601 break; 808*d6c23f6fSyx160601 #endif 809*d6c23f6fSyx160601 default: 810*d6c23f6fSyx160601 ptr = NULL; 811*d6c23f6fSyx160601 break; 812*d6c23f6fSyx160601 } 813*d6c23f6fSyx160601 814*d6c23f6fSyx160601 if (ptr != NULL) { 815ab25eeb5Syz155240 error = fr_outobj(data, &nl, IPFOBJ_NATLOOKUP); 816ab25eeb5Syz155240 } else { 817ab25eeb5Syz155240 error = ESRCH; 818ab25eeb5Syz155240 } 819ab25eeb5Syz155240 } 820ab25eeb5Syz155240 if (getlock) { 821f4b3ec61Sdh155122 RWLOCK_EXIT(&ifs->ifs_ipf_nat); 822ab25eeb5Syz155240 } 823ab25eeb5Syz155240 break; 824ab25eeb5Syz155240 } 825ab25eeb5Syz155240 case SIOCIPFFL : /* old SIOCFLNAT & SIOCCNATL */ 826ab25eeb5Syz155240 if (!(mode & FWRITE)) { 827ab25eeb5Syz155240 error = EPERM; 828ab25eeb5Syz155240 break; 829ab25eeb5Syz155240 } 830ab25eeb5Syz155240 if (getlock) { 831f4b3ec61Sdh155122 WRITE_ENTER(&ifs->ifs_ipf_nat); 832ab25eeb5Syz155240 } 833ab25eeb5Syz155240 error = 0; 834ab25eeb5Syz155240 if (arg == 0) 835f4b3ec61Sdh155122 ret = nat_flushtable(ifs); 836ab25eeb5Syz155240 else if (arg == 1) 837f4b3ec61Sdh155122 ret = nat_clearlist(ifs); 8383805c50fSan207044 else if (arg >= 2 && arg <= 4) 8393805c50fSan207044 ret = nat_extraflush(arg - 2, ifs); 840ab25eeb5Syz155240 else 841ab25eeb5Syz155240 error = EINVAL; 842ab25eeb5Syz155240 if (getlock) { 843f4b3ec61Sdh155122 RWLOCK_EXIT(&ifs->ifs_ipf_nat); 844ab25eeb5Syz155240 } 845ab25eeb5Syz155240 if (error == 0) { 846ab25eeb5Syz155240 BCOPYOUT(&ret, data, sizeof(ret)); 847ab25eeb5Syz155240 } 848ab25eeb5Syz155240 break; 849ab25eeb5Syz155240 case SIOCPROXY : 850f4b3ec61Sdh155122 error = appr_ioctl(data, cmd, mode, ifs); 851ab25eeb5Syz155240 break; 852ab25eeb5Syz155240 case SIOCSTLCK : 853ab25eeb5Syz155240 if (!(mode & FWRITE)) { 854ab25eeb5Syz155240 error = EPERM; 855ab25eeb5Syz155240 } else { 856f4b3ec61Sdh155122 fr_lock(data, &ifs->ifs_fr_nat_lock); 857ab25eeb5Syz155240 } 858ab25eeb5Syz155240 break; 859ab25eeb5Syz155240 case SIOCSTPUT : 8603c3c3491Sjojemann if ((mode & FWRITE) != 0) { 861f4b3ec61Sdh155122 error = fr_natputent(data, getlock, ifs); 862ab25eeb5Syz155240 } else { 863ab25eeb5Syz155240 error = EACCES; 864ab25eeb5Syz155240 } 865ab25eeb5Syz155240 break; 866ab25eeb5Syz155240 case SIOCSTGSZ : 867f4b3ec61Sdh155122 if (ifs->ifs_fr_nat_lock) { 868ab25eeb5Syz155240 if (getlock) { 869f4b3ec61Sdh155122 READ_ENTER(&ifs->ifs_ipf_nat); 870ab25eeb5Syz155240 } 871f4b3ec61Sdh155122 error = fr_natgetsz(data, ifs); 872ab25eeb5Syz155240 if (getlock) { 873f4b3ec61Sdh155122 RWLOCK_EXIT(&ifs->ifs_ipf_nat); 874ab25eeb5Syz155240 } 875ab25eeb5Syz155240 } else 876ab25eeb5Syz155240 error = EACCES; 877ab25eeb5Syz155240 break; 878ab25eeb5Syz155240 case SIOCSTGET : 879f4b3ec61Sdh155122 if (ifs->ifs_fr_nat_lock) { 880ab25eeb5Syz155240 if (getlock) { 881f4b3ec61Sdh155122 READ_ENTER(&ifs->ifs_ipf_nat); 882ab25eeb5Syz155240 } 883f4b3ec61Sdh155122 error = fr_natgetent(data, ifs); 884ab25eeb5Syz155240 if (getlock) { 885f4b3ec61Sdh155122 RWLOCK_EXIT(&ifs->ifs_ipf_nat); 886ab25eeb5Syz155240 } 887ab25eeb5Syz155240 } else 888ab25eeb5Syz155240 error = EACCES; 889ab25eeb5Syz155240 break; 890f4b3ec61Sdh155122 case SIOCIPFDELTOK : 891f4b3ec61Sdh155122 (void) BCOPYIN((caddr_t)data, (caddr_t)&arg, sizeof(arg)); 892f4b3ec61Sdh155122 error = ipf_deltoken(arg, uid, ctx, ifs); 893f4b3ec61Sdh155122 break; 894ab25eeb5Syz155240 default : 895ab25eeb5Syz155240 error = EINVAL; 896ab25eeb5Syz155240 break; 897ab25eeb5Syz155240 } 898ab25eeb5Syz155240 done: 899ab25eeb5Syz155240 if (nt) 900ab25eeb5Syz155240 KFREE(nt); 901ab25eeb5Syz155240 return error; 902ab25eeb5Syz155240 } 903ab25eeb5Syz155240 904ab25eeb5Syz155240 905ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */ 906ab25eeb5Syz155240 /* Function: nat_siocaddnat */ 907ab25eeb5Syz155240 /* Returns: int - 0 == success, != 0 == failure */ 908ab25eeb5Syz155240 /* Parameters: n(I) - pointer to new NAT rule */ 909ab25eeb5Syz155240 /* np(I) - pointer to where to insert new NAT rule */ 910ab25eeb5Syz155240 /* getlock(I) - flag indicating if lock on ipf_nat is held */ 911ab25eeb5Syz155240 /* Mutex Locks: ipf_natio */ 912ab25eeb5Syz155240 /* */ 913ab25eeb5Syz155240 /* Handle SIOCADNAT. Resolve and calculate details inside the NAT rule */ 914ab25eeb5Syz155240 /* from information passed to the kernel, then add it to the appropriate */ 915ab25eeb5Syz155240 /* NAT rule table(s). */ 916ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */ 917f4b3ec61Sdh155122 static int nat_siocaddnat(n, np, getlock, ifs) 918ab25eeb5Syz155240 ipnat_t *n, **np; 919ab25eeb5Syz155240 int getlock; 920f4b3ec61Sdh155122 ipf_stack_t *ifs; 921ab25eeb5Syz155240 { 922ab25eeb5Syz155240 int error = 0, i, j; 923ab25eeb5Syz155240 924dcf3e898Sjojemann if (nat_resolverule(n, ifs) != 0) 925ab25eeb5Syz155240 return ENOENT; 926ab25eeb5Syz155240 927ab25eeb5Syz155240 if ((n->in_age[0] == 0) && (n->in_age[1] != 0)) 928ab25eeb5Syz155240 return EINVAL; 929ab25eeb5Syz155240 930ab25eeb5Syz155240 n->in_use = 0; 931ab25eeb5Syz155240 if (n->in_redir & NAT_MAPBLK) 932ab25eeb5Syz155240 n->in_space = USABLE_PORTS * ~ntohl(n->in_outmsk); 933ab25eeb5Syz155240 else if (n->in_flags & IPN_AUTOPORTMAP) 934ab25eeb5Syz155240 n->in_space = USABLE_PORTS * ~ntohl(n->in_inmsk); 935ab25eeb5Syz155240 else if (n->in_flags & IPN_IPRANGE) 936ab25eeb5Syz155240 n->in_space = ntohl(n->in_outmsk) - ntohl(n->in_outip); 937ab25eeb5Syz155240 else if (n->in_flags & IPN_SPLIT) 938ab25eeb5Syz155240 n->in_space = 2; 939ab25eeb5Syz155240 else if (n->in_outmsk != 0) 940ab25eeb5Syz155240 n->in_space = ~ntohl(n->in_outmsk); 941ab25eeb5Syz155240 else 942ab25eeb5Syz155240 n->in_space = 1; 943ab25eeb5Syz155240 944ab25eeb5Syz155240 /* 945ab25eeb5Syz155240 * Calculate the number of valid IP addresses in the output 946ab25eeb5Syz155240 * mapping range. In all cases, the range is inclusive of 947ab25eeb5Syz155240 * the start and ending IP addresses. 948ab25eeb5Syz155240 * If to a CIDR address, lose 2: broadcast + network address 949ab25eeb5Syz155240 * (so subtract 1) 950ab25eeb5Syz155240 * If to a range, add one. 951ab25eeb5Syz155240 * If to a single IP address, set to 1. 952ab25eeb5Syz155240 */ 953ab25eeb5Syz155240 if (n->in_space) { 954ab25eeb5Syz155240 if ((n->in_flags & IPN_IPRANGE) != 0) 955ab25eeb5Syz155240 n->in_space += 1; 956ab25eeb5Syz155240 else 957ab25eeb5Syz155240 n->in_space -= 1; 958ab25eeb5Syz155240 } else 959ab25eeb5Syz155240 n->in_space = 1; 960ab25eeb5Syz155240 961*d6c23f6fSyx160601 #ifdef USE_INET6 962*d6c23f6fSyx160601 if (n->in_v == 6 && (n->in_flags & (IPN_IPRANGE|IPN_SPLIT)) == 0 && 963*d6c23f6fSyx160601 !IP6_ISONES(&n->in_out[1]) && !IP6_ISZERO(&n->in_out[1])) 964*d6c23f6fSyx160601 IP6_ADD(&n->in_out[0], 1, &n->in_next6) 965*d6c23f6fSyx160601 else if (n->in_v == 6 && 966*d6c23f6fSyx160601 (n->in_flags & IPN_SPLIT) && (n->in_redir & NAT_REDIRECT)) 967*d6c23f6fSyx160601 n->in_next6 = n->in_in[0]; 968*d6c23f6fSyx160601 else if (n->in_v == 6) 969*d6c23f6fSyx160601 n->in_next6 = n->in_out[0]; 970*d6c23f6fSyx160601 else 971*d6c23f6fSyx160601 #endif 972ab25eeb5Syz155240 if ((n->in_outmsk != 0xffffffff) && (n->in_outmsk != 0) && 973ab25eeb5Syz155240 ((n->in_flags & (IPN_IPRANGE|IPN_SPLIT)) == 0)) 974ab25eeb5Syz155240 n->in_nip = ntohl(n->in_outip) + 1; 975ab25eeb5Syz155240 else if ((n->in_flags & IPN_SPLIT) && 976ab25eeb5Syz155240 (n->in_redir & NAT_REDIRECT)) 977ab25eeb5Syz155240 n->in_nip = ntohl(n->in_inip); 978ab25eeb5Syz155240 else 979ab25eeb5Syz155240 n->in_nip = ntohl(n->in_outip); 980*d6c23f6fSyx160601 981ab25eeb5Syz155240 if (n->in_redir & NAT_MAP) { 982ab25eeb5Syz155240 n->in_pnext = ntohs(n->in_pmin); 983ab25eeb5Syz155240 /* 984ab25eeb5Syz155240 * Multiply by the number of ports made available. 985ab25eeb5Syz155240 */ 986ab25eeb5Syz155240 if (ntohs(n->in_pmax) >= ntohs(n->in_pmin)) { 987ab25eeb5Syz155240 n->in_space *= (ntohs(n->in_pmax) - 988ab25eeb5Syz155240 ntohs(n->in_pmin) + 1); 989ab25eeb5Syz155240 /* 990ab25eeb5Syz155240 * Because two different sources can map to 991ab25eeb5Syz155240 * different destinations but use the same 992ab25eeb5Syz155240 * local IP#/port #. 993ab25eeb5Syz155240 * If the result is smaller than in_space, then 994ab25eeb5Syz155240 * we may have wrapped around 32bits. 995ab25eeb5Syz155240 */ 996ab25eeb5Syz155240 i = n->in_inmsk; 997ab25eeb5Syz155240 if ((i != 0) && (i != 0xffffffff)) { 998ab25eeb5Syz155240 j = n->in_space * (~ntohl(i) + 1); 999ab25eeb5Syz155240 if (j >= n->in_space) 1000ab25eeb5Syz155240 n->in_space = j; 1001ab25eeb5Syz155240 else 1002ab25eeb5Syz155240 n->in_space = 0xffffffff; 1003ab25eeb5Syz155240 } 1004ab25eeb5Syz155240 } 1005ab25eeb5Syz155240 /* 1006ab25eeb5Syz155240 * If no protocol is specified, multiple by 256 to allow for 1007ab25eeb5Syz155240 * at least one IP:IP mapping per protocol. 1008ab25eeb5Syz155240 */ 1009ab25eeb5Syz155240 if ((n->in_flags & IPN_TCPUDPICMP) == 0) { 1010ab25eeb5Syz155240 j = n->in_space * 256; 1011ab25eeb5Syz155240 if (j >= n->in_space) 1012ab25eeb5Syz155240 n->in_space = j; 1013ab25eeb5Syz155240 else 1014ab25eeb5Syz155240 n->in_space = 0xffffffff; 1015ab25eeb5Syz155240 } 1016ab25eeb5Syz155240 } 1017ab25eeb5Syz155240 1018ab25eeb5Syz155240 /* Otherwise, these fields are preset */ 1019ab25eeb5Syz155240 1020ab25eeb5Syz155240 if (getlock) { 1021f4b3ec61Sdh155122 WRITE_ENTER(&ifs->ifs_ipf_nat); 1022ab25eeb5Syz155240 } 1023ab25eeb5Syz155240 n->in_next = NULL; 1024ab25eeb5Syz155240 *np = n; 1025ab25eeb5Syz155240 1026ab25eeb5Syz155240 if (n->in_age[0] != 0) 1027f4b3ec61Sdh155122 n->in_tqehead[0] = fr_addtimeoutqueue(&ifs->ifs_nat_utqe, 1028f4b3ec61Sdh155122 n->in_age[0], ifs); 1029ab25eeb5Syz155240 1030ab25eeb5Syz155240 if (n->in_age[1] != 0) 1031f4b3ec61Sdh155122 n->in_tqehead[1] = fr_addtimeoutqueue(&ifs->ifs_nat_utqe, 1032f4b3ec61Sdh155122 n->in_age[1], ifs); 1033ab25eeb5Syz155240 1034ab25eeb5Syz155240 if (n->in_redir & NAT_REDIRECT) { 1035ab25eeb5Syz155240 n->in_flags &= ~IPN_NOTDST; 1036*d6c23f6fSyx160601 switch (n->in_v) 1037*d6c23f6fSyx160601 { 1038*d6c23f6fSyx160601 case 4 : 1039f4b3ec61Sdh155122 nat_addrdr(n, ifs); 1040*d6c23f6fSyx160601 break; 1041*d6c23f6fSyx160601 #ifdef USE_INET6 1042*d6c23f6fSyx160601 case 6 : 1043*d6c23f6fSyx160601 nat6_addrdr(n, ifs); 1044*d6c23f6fSyx160601 break; 1045*d6c23f6fSyx160601 #endif 1046*d6c23f6fSyx160601 default : 1047*d6c23f6fSyx160601 break; 1048*d6c23f6fSyx160601 } 1049ab25eeb5Syz155240 } 1050ab25eeb5Syz155240 if (n->in_redir & (NAT_MAP|NAT_MAPBLK)) { 1051ab25eeb5Syz155240 n->in_flags &= ~IPN_NOTSRC; 1052*d6c23f6fSyx160601 switch (n->in_v) 1053*d6c23f6fSyx160601 { 1054*d6c23f6fSyx160601 case 4 : 1055f4b3ec61Sdh155122 nat_addnat(n, ifs); 1056*d6c23f6fSyx160601 break; 1057*d6c23f6fSyx160601 #ifdef USE_INET6 1058*d6c23f6fSyx160601 case 6 : 1059*d6c23f6fSyx160601 nat6_addnat(n, ifs); 1060*d6c23f6fSyx160601 break; 1061*d6c23f6fSyx160601 #endif 1062*d6c23f6fSyx160601 default : 1063*d6c23f6fSyx160601 break; 1064*d6c23f6fSyx160601 } 1065ab25eeb5Syz155240 } 1066ab25eeb5Syz155240 n = NULL; 1067f4b3ec61Sdh155122 ifs->ifs_nat_stats.ns_rules++; 1068ab25eeb5Syz155240 if (getlock) { 1069f4b3ec61Sdh155122 RWLOCK_EXIT(&ifs->ifs_ipf_nat); /* WRITE */ 1070ab25eeb5Syz155240 } 1071ab25eeb5Syz155240 1072ab25eeb5Syz155240 return error; 1073ab25eeb5Syz155240 } 1074ab25eeb5Syz155240 1075ab25eeb5Syz155240 1076ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */ 1077ab25eeb5Syz155240 /* Function: nat_resolvrule */ 1078dcf3e898Sjojemann /* Returns: int - 0 == success, -1 == failure */ 1079ab25eeb5Syz155240 /* Parameters: n(I) - pointer to NAT rule */ 1080ab25eeb5Syz155240 /* */ 1081dcf3e898Sjojemann /* Resolve some of the details inside the NAT rule. Includes resolving */ 1082dcf3e898Sjojemann /* any specified interfaces and proxy labels, and determines whether or not */ 1083dcf3e898Sjojemann /* all proxy labels are correctly specified. */ 1084dcf3e898Sjojemann /* */ 1085dcf3e898Sjojemann /* Called by nat_siocaddnat() (SIOCADNAT) and fr_natputent (SIOCSTPUT). */ 1086ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */ 1087dcf3e898Sjojemann static int nat_resolverule(n, ifs) 1088ab25eeb5Syz155240 ipnat_t *n; 1089f4b3ec61Sdh155122 ipf_stack_t *ifs; 1090ab25eeb5Syz155240 { 1091ab25eeb5Syz155240 n->in_ifnames[0][LIFNAMSIZ - 1] = '\0'; 1092*d6c23f6fSyx160601 n->in_ifps[0] = fr_resolvenic(n->in_ifnames[0], n->in_v, ifs); 1093ab25eeb5Syz155240 1094ab25eeb5Syz155240 n->in_ifnames[1][LIFNAMSIZ - 1] = '\0'; 1095ab25eeb5Syz155240 if (n->in_ifnames[1][0] == '\0') { 1096ab25eeb5Syz155240 (void) strncpy(n->in_ifnames[1], n->in_ifnames[0], LIFNAMSIZ); 1097ab25eeb5Syz155240 n->in_ifps[1] = n->in_ifps[0]; 1098ab25eeb5Syz155240 } else { 1099*d6c23f6fSyx160601 n->in_ifps[1] = fr_resolvenic(n->in_ifnames[1], n->in_v, ifs); 1100ab25eeb5Syz155240 } 1101ab25eeb5Syz155240 1102ab25eeb5Syz155240 if (n->in_plabel[0] != '\0') { 1103f4b3ec61Sdh155122 n->in_apr = appr_lookup(n->in_p, n->in_plabel, ifs); 1104dcf3e898Sjojemann if (n->in_apr == NULL) 1105dcf3e898Sjojemann return -1; 1106ab25eeb5Syz155240 } 1107dcf3e898Sjojemann return 0; 1108ab25eeb5Syz155240 } 1109ab25eeb5Syz155240 1110ab25eeb5Syz155240 1111ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */ 1112ab25eeb5Syz155240 /* Function: nat_siocdelnat */ 1113ab25eeb5Syz155240 /* Returns: int - 0 == success, != 0 == failure */ 1114ab25eeb5Syz155240 /* Parameters: n(I) - pointer to new NAT rule */ 1115ab25eeb5Syz155240 /* np(I) - pointer to where to insert new NAT rule */ 1116ab25eeb5Syz155240 /* getlock(I) - flag indicating if lock on ipf_nat is held */ 1117ab25eeb5Syz155240 /* Mutex Locks: ipf_natio */ 1118ab25eeb5Syz155240 /* */ 1119ab25eeb5Syz155240 /* Handle SIOCADNAT. Resolve and calculate details inside the NAT rule */ 1120ab25eeb5Syz155240 /* from information passed to the kernel, then add it to the appropriate */ 1121ab25eeb5Syz155240 /* NAT rule table(s). */ 1122ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */ 1123f4b3ec61Sdh155122 static void nat_siocdelnat(n, np, getlock, ifs) 1124ab25eeb5Syz155240 ipnat_t *n, **np; 1125ab25eeb5Syz155240 int getlock; 1126f4b3ec61Sdh155122 ipf_stack_t *ifs; 1127ab25eeb5Syz155240 { 1128*d6c23f6fSyx160601 int i; 1129*d6c23f6fSyx160601 1130ab25eeb5Syz155240 if (getlock) { 1131f4b3ec61Sdh155122 WRITE_ENTER(&ifs->ifs_ipf_nat); 1132ab25eeb5Syz155240 } 1133ab25eeb5Syz155240 if (n->in_redir & NAT_REDIRECT) 1134ab25eeb5Syz155240 nat_delrdr(n); 1135ab25eeb5Syz155240 if (n->in_redir & (NAT_MAPBLK|NAT_MAP)) 1136ab25eeb5Syz155240 nat_delnat(n); 1137f4b3ec61Sdh155122 if (ifs->ifs_nat_list == NULL) { 1138f4b3ec61Sdh155122 ifs->ifs_nat_masks = 0; 1139f4b3ec61Sdh155122 ifs->ifs_rdr_masks = 0; 1140*d6c23f6fSyx160601 for (i = 0; i < 4; i++) { 1141*d6c23f6fSyx160601 ifs->ifs_nat6_masks[i] = 0; 1142*d6c23f6fSyx160601 ifs->ifs_rdr6_masks[i] = 0; 1143*d6c23f6fSyx160601 } 1144ab25eeb5Syz155240 } 1145ab25eeb5Syz155240 1146ab25eeb5Syz155240 if (n->in_tqehead[0] != NULL) { 1147ab25eeb5Syz155240 if (fr_deletetimeoutqueue(n->in_tqehead[0]) == 0) { 11483805c50fSan207044 fr_freetimeoutqueue(n->in_tqehead[0], ifs); 1149ab25eeb5Syz155240 } 1150ab25eeb5Syz155240 } 1151ab25eeb5Syz155240 1152ab25eeb5Syz155240 if (n->in_tqehead[1] != NULL) { 1153ab25eeb5Syz155240 if (fr_deletetimeoutqueue(n->in_tqehead[1]) == 0) { 1154f4b3ec61Sdh155122 fr_freetimeoutqueue(n->in_tqehead[1], ifs); 1155ab25eeb5Syz155240 } 1156ab25eeb5Syz155240 } 1157ab25eeb5Syz155240 1158ab25eeb5Syz155240 *np = n->in_next; 1159ab25eeb5Syz155240 1160ab25eeb5Syz155240 if (n->in_use == 0) { 1161ab25eeb5Syz155240 if (n->in_apr) 1162ab25eeb5Syz155240 appr_free(n->in_apr); 1163ab25eeb5Syz155240 KFREE(n); 1164f4b3ec61Sdh155122 ifs->ifs_nat_stats.ns_rules--; 1165ab25eeb5Syz155240 } else { 1166ab25eeb5Syz155240 n->in_flags |= IPN_DELETE; 1167ab25eeb5Syz155240 n->in_next = NULL; 1168ab25eeb5Syz155240 } 1169ab25eeb5Syz155240 if (getlock) { 1170f4b3ec61Sdh155122 RWLOCK_EXIT(&ifs->ifs_ipf_nat); /* READ/WRITE */ 1171ab25eeb5Syz155240 } 1172ab25eeb5Syz155240 } 1173ab25eeb5Syz155240 1174ab25eeb5Syz155240 1175ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */ 1176ab25eeb5Syz155240 /* Function: fr_natgetsz */ 1177ab25eeb5Syz155240 /* Returns: int - 0 == success, != 0 is the error value. */ 1178ab25eeb5Syz155240 /* Parameters: data(I) - pointer to natget structure with kernel pointer */ 1179ab25eeb5Syz155240 /* get the size of. */ 1180ab25eeb5Syz155240 /* */ 1181ab25eeb5Syz155240 /* Handle SIOCSTGSZ. */ 1182ab25eeb5Syz155240 /* Return the size of the nat list entry to be copied back to user space. */ 1183ab25eeb5Syz155240 /* The size of the entry is stored in the ng_sz field and the enture natget */ 1184ab25eeb5Syz155240 /* structure is copied back to the user. */ 1185ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */ 1186f4b3ec61Sdh155122 static int fr_natgetsz(data, ifs) 1187ab25eeb5Syz155240 caddr_t data; 1188f4b3ec61Sdh155122 ipf_stack_t *ifs; 1189ab25eeb5Syz155240 { 1190ab25eeb5Syz155240 ap_session_t *aps; 1191ab25eeb5Syz155240 nat_t *nat, *n; 1192ab25eeb5Syz155240 natget_t ng; 1193ab25eeb5Syz155240 1194ab25eeb5Syz155240 BCOPYIN(data, &ng, sizeof(ng)); 1195ab25eeb5Syz155240 1196ab25eeb5Syz155240 nat = ng.ng_ptr; 1197ab25eeb5Syz155240 if (!nat) { 1198f4b3ec61Sdh155122 nat = ifs->ifs_nat_instances; 1199ab25eeb5Syz155240 ng.ng_sz = 0; 1200ab25eeb5Syz155240 /* 1201ab25eeb5Syz155240 * Empty list so the size returned is 0. Simple. 1202ab25eeb5Syz155240 */ 1203ab25eeb5Syz155240 if (nat == NULL) { 1204ab25eeb5Syz155240 BCOPYOUT(&ng, data, sizeof(ng)); 1205ab25eeb5Syz155240 return 0; 1206ab25eeb5Syz155240 } 1207ab25eeb5Syz155240 } else { 1208ab25eeb5Syz155240 /* 1209ab25eeb5Syz155240 * Make sure the pointer we're copying from exists in the 1210ab25eeb5Syz155240 * current list of entries. Security precaution to prevent 1211ab25eeb5Syz155240 * copying of random kernel data. 1212ab25eeb5Syz155240 */ 1213f4b3ec61Sdh155122 for (n = ifs->ifs_nat_instances; n; n = n->nat_next) 1214ab25eeb5Syz155240 if (n == nat) 1215ab25eeb5Syz155240 break; 1216ab25eeb5Syz155240 if (!n) 1217ab25eeb5Syz155240 return ESRCH; 1218ab25eeb5Syz155240 } 1219ab25eeb5Syz155240 1220ab25eeb5Syz155240 /* 1221ab25eeb5Syz155240 * Incluse any space required for proxy data structures. 1222ab25eeb5Syz155240 */ 1223ab25eeb5Syz155240 ng.ng_sz = sizeof(nat_save_t); 1224ab25eeb5Syz155240 aps = nat->nat_aps; 1225ab25eeb5Syz155240 if (aps != NULL) { 1226ab25eeb5Syz155240 ng.ng_sz += sizeof(ap_session_t) - 4; 1227ab25eeb5Syz155240 if (aps->aps_data != 0) 1228ab25eeb5Syz155240 ng.ng_sz += aps->aps_psiz; 1229ab25eeb5Syz155240 } 1230ab25eeb5Syz155240 1231ab25eeb5Syz155240 BCOPYOUT(&ng, data, sizeof(ng)); 1232ab25eeb5Syz155240 return 0; 1233ab25eeb5Syz155240 } 1234ab25eeb5Syz155240 1235ab25eeb5Syz155240 1236ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */ 1237ab25eeb5Syz155240 /* Function: fr_natgetent */ 1238ab25eeb5Syz155240 /* Returns: int - 0 == success, != 0 is the error value. */ 1239ab25eeb5Syz155240 /* Parameters: data(I) - pointer to natget structure with kernel pointer */ 1240ab25eeb5Syz155240 /* to NAT structure to copy out. */ 1241ab25eeb5Syz155240 /* */ 1242ab25eeb5Syz155240 /* Handle SIOCSTGET. */ 1243ab25eeb5Syz155240 /* Copies out NAT entry to user space. Any additional data held for a */ 1244ab25eeb5Syz155240 /* proxy is also copied, as to is the NAT rule which was responsible for it */ 1245ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */ 1246f4b3ec61Sdh155122 static int fr_natgetent(data, ifs) 1247ab25eeb5Syz155240 caddr_t data; 1248f4b3ec61Sdh155122 ipf_stack_t *ifs; 1249ab25eeb5Syz155240 { 1250ab25eeb5Syz155240 int error, outsize; 1251ab25eeb5Syz155240 ap_session_t *aps; 1252ab25eeb5Syz155240 nat_save_t *ipn, ipns; 1253ab25eeb5Syz155240 nat_t *n, *nat; 1254ab25eeb5Syz155240 1255ab25eeb5Syz155240 error = fr_inobj(data, &ipns, IPFOBJ_NATSAVE); 1256ab25eeb5Syz155240 if (error != 0) 1257ab25eeb5Syz155240 return error; 1258ab25eeb5Syz155240 1259ab25eeb5Syz155240 if ((ipns.ipn_dsize < sizeof(ipns)) || (ipns.ipn_dsize > 81920)) 1260ab25eeb5Syz155240 return EINVAL; 1261ab25eeb5Syz155240 1262ab25eeb5Syz155240 KMALLOCS(ipn, nat_save_t *, ipns.ipn_dsize); 1263ab25eeb5Syz155240 if (ipn == NULL) 1264ab25eeb5Syz155240 return ENOMEM; 1265ab25eeb5Syz155240 1266ab25eeb5Syz155240 ipn->ipn_dsize = ipns.ipn_dsize; 1267ab25eeb5Syz155240 nat = ipns.ipn_next; 1268ab25eeb5Syz155240 if (nat == NULL) { 1269f4b3ec61Sdh155122 nat = ifs->ifs_nat_instances; 1270ab25eeb5Syz155240 if (nat == NULL) { 1271f4b3ec61Sdh155122 if (ifs->ifs_nat_instances == NULL) 1272ab25eeb5Syz155240 error = ENOENT; 1273ab25eeb5Syz155240 goto finished; 1274ab25eeb5Syz155240 } 1275ab25eeb5Syz155240 } else { 1276ab25eeb5Syz155240 /* 1277ab25eeb5Syz155240 * Make sure the pointer we're copying from exists in the 1278ab25eeb5Syz155240 * current list of entries. Security precaution to prevent 1279ab25eeb5Syz155240 * copying of random kernel data. 1280ab25eeb5Syz155240 */ 1281f4b3ec61Sdh155122 for (n = ifs->ifs_nat_instances; n; n = n->nat_next) 1282ab25eeb5Syz155240 if (n == nat) 1283ab25eeb5Syz155240 break; 1284ab25eeb5Syz155240 if (n == NULL) { 1285ab25eeb5Syz155240 error = ESRCH; 1286ab25eeb5Syz155240 goto finished; 1287ab25eeb5Syz155240 } 1288ab25eeb5Syz155240 } 1289ab25eeb5Syz155240 ipn->ipn_next = nat->nat_next; 1290ab25eeb5Syz155240 1291ab25eeb5Syz155240 /* 1292ab25eeb5Syz155240 * Copy the NAT structure. 1293ab25eeb5Syz155240 */ 1294ab25eeb5Syz155240 bcopy((char *)nat, &ipn->ipn_nat, sizeof(*nat)); 1295ab25eeb5Syz155240 1296ab25eeb5Syz155240 /* 1297ab25eeb5Syz155240 * If we have a pointer to the NAT rule it belongs to, save that too. 1298ab25eeb5Syz155240 */ 1299ab25eeb5Syz155240 if (nat->nat_ptr != NULL) 1300ab25eeb5Syz155240 bcopy((char *)nat->nat_ptr, (char *)&ipn->ipn_ipnat, 1301ab25eeb5Syz155240 sizeof(ipn->ipn_ipnat)); 1302ab25eeb5Syz155240 1303ab25eeb5Syz155240 /* 1304ab25eeb5Syz155240 * If we also know the NAT entry has an associated filter rule, 1305ab25eeb5Syz155240 * save that too. 1306ab25eeb5Syz155240 */ 1307ab25eeb5Syz155240 if (nat->nat_fr != NULL) 1308ab25eeb5Syz155240 bcopy((char *)nat->nat_fr, (char *)&ipn->ipn_fr, 1309ab25eeb5Syz155240 sizeof(ipn->ipn_fr)); 1310ab25eeb5Syz155240 1311ab25eeb5Syz155240 /* 1312ab25eeb5Syz155240 * Last but not least, if there is an application proxy session set 1313ab25eeb5Syz155240 * up for this NAT entry, then copy that out too, including any 1314ab25eeb5Syz155240 * private data saved along side it by the proxy. 1315ab25eeb5Syz155240 */ 1316ab25eeb5Syz155240 aps = nat->nat_aps; 1317ab25eeb5Syz155240 outsize = ipn->ipn_dsize - sizeof(*ipn) + sizeof(ipn->ipn_data); 1318ab25eeb5Syz155240 if (aps != NULL) { 1319ab25eeb5Syz155240 char *s; 1320ab25eeb5Syz155240 1321ab25eeb5Syz155240 if (outsize < sizeof(*aps)) { 1322ab25eeb5Syz155240 error = ENOBUFS; 1323ab25eeb5Syz155240 goto finished; 1324ab25eeb5Syz155240 } 1325ab25eeb5Syz155240 1326ab25eeb5Syz155240 s = ipn->ipn_data; 1327ab25eeb5Syz155240 bcopy((char *)aps, s, sizeof(*aps)); 1328ab25eeb5Syz155240 s += sizeof(*aps); 1329ab25eeb5Syz155240 outsize -= sizeof(*aps); 1330ab25eeb5Syz155240 if ((aps->aps_data != NULL) && (outsize >= aps->aps_psiz)) 1331ab25eeb5Syz155240 bcopy(aps->aps_data, s, aps->aps_psiz); 1332ab25eeb5Syz155240 else 1333ab25eeb5Syz155240 error = ENOBUFS; 1334ab25eeb5Syz155240 } 1335ab25eeb5Syz155240 if (error == 0) { 1336ab25eeb5Syz155240 error = fr_outobjsz(data, ipn, IPFOBJ_NATSAVE, ipns.ipn_dsize); 1337ab25eeb5Syz155240 } 1338ab25eeb5Syz155240 1339ab25eeb5Syz155240 finished: 1340ab25eeb5Syz155240 if (ipn != NULL) { 1341ab25eeb5Syz155240 KFREES(ipn, ipns.ipn_dsize); 1342ab25eeb5Syz155240 } 1343ab25eeb5Syz155240 return error; 1344ab25eeb5Syz155240 } 1345ab25eeb5Syz155240 13463c50f6d6San207044 /* ------------------------------------------------------------------------ */ 13473c50f6d6San207044 /* Function: nat_calc_chksum_diffs */ 13483c50f6d6San207044 /* Returns: void */ 13493c50f6d6San207044 /* Parameters: nat - pointer to NAT table entry */ 13503c50f6d6San207044 /* */ 13513c50f6d6San207044 /* Function calculates chksum deltas for IP header (nat_ipsumd) and TCP/UDP */ 13523c50f6d6San207044 /* headers (nat_sumd). The things for L4 (UDP/TCP) get complicated when */ 13533c50f6d6San207044 /* we are dealing with partial chksum offload. For these cases we need to */ 13543c50f6d6San207044 /* compute a 'partial chksum delta'. The 'partial chksum delta'is stored */ 13553c50f6d6San207044 /* into nat_sumd[1], while ordinary chksum delta for TCP/UDP is in */ 13563c50f6d6San207044 /* nat_sumd[0]. */ 13573c50f6d6San207044 /* */ 13583c50f6d6San207044 /* The function accepts initialized NAT table entry and computes the deltas */ 13593c50f6d6San207044 /* from nat_inip/nat_outip members. The function is called right before */ 13603c50f6d6San207044 /* the new entry is inserted into the table. */ 13613c50f6d6San207044 /* */ 13623c50f6d6San207044 /* The ipsumd (IP hedaer chksum delta adjustment) is computed as a chksum */ 13633c50f6d6San207044 /* of delta between original and new IP addresses. */ 13643c50f6d6San207044 /* */ 13653c50f6d6San207044 /* the nat_sumd[0] (TCP/UDP header chksum delta adjustment) is computed as */ 13663c50f6d6San207044 /* a chkusm of delta between original an new IP addrress:port tupples. */ 13673c50f6d6San207044 /* */ 13683c50f6d6San207044 /* Some facts about chksum, we should remember: */ 13693c50f6d6San207044 /* IP header chksum covers IP header only */ 13703c50f6d6San207044 /* */ 13713c50f6d6San207044 /* TCP/UDP chksum covers data payload and so called pseudo header */ 13723c50f6d6San207044 /* SRC, DST IP address */ 13733c50f6d6San207044 /* SRC, DST Port */ 13743c50f6d6San207044 /* length of payload */ 13753c50f6d6San207044 /* */ 13763c50f6d6San207044 /* The partial chksum delta (nat_sumd[1] is used to adjust db_ckusm16 */ 13773c50f6d6San207044 /* member of dblk_t structure. The db_ckusm16 member is not part of */ 13783c50f6d6San207044 /* IP/UDP/TCP header it is 16 bit value computed by NIC driver with partial */ 13793c50f6d6San207044 /* chksum offload capacbility for every inbound packet. The db_cksum16 is */ 13803c50f6d6San207044 /* stored along with other IP packet data in dblk_t structure and used in */ 13813c50f6d6San207044 /* for IP/UDP/TCP chksum validation later in ip.c. */ 13823c50f6d6San207044 /* */ 13833c50f6d6San207044 /* The partial chksum delta (adjustment, nat_sumd[1]) is computed as chksum */ 13843c50f6d6San207044 /* of delta between new and orig address. NOTE: the order of operands for */ 13853c50f6d6San207044 /* partial delta operation is swapped compared to computing the IP/TCP/UDP */ 13863c50f6d6San207044 /* header adjustment. It is by design see (IP_CKSUM_RECV() macro in ip.c). */ 13873c50f6d6San207044 /* */ 13883c50f6d6San207044 /* ------------------------------------------------------------------------ */ 1389*d6c23f6fSyx160601 void nat_calc_chksum_diffs(nat) 13903c50f6d6San207044 nat_t *nat; 13913c50f6d6San207044 { 13923c50f6d6San207044 u_32_t sum_orig = 0; 13933c50f6d6San207044 u_32_t sum_changed = 0; 13943c50f6d6San207044 u_32_t sumd; 13953c50f6d6San207044 u_32_t ipsum_orig = 0; 13963c50f6d6San207044 u_32_t ipsum_changed = 0; 13973c50f6d6San207044 1398*d6c23f6fSyx160601 if (nat->nat_v != 4 && nat->nat_v != 6) 1399*d6c23f6fSyx160601 return; 1400*d6c23f6fSyx160601 14013c50f6d6San207044 /* 14023c50f6d6San207044 * the switch calculates operands for CALC_SUMD(), 14033c50f6d6San207044 * which will compute the partial chksum delta. 14043c50f6d6San207044 */ 14053c50f6d6San207044 switch (nat->nat_dir) 14063c50f6d6San207044 { 14073c50f6d6San207044 case NAT_INBOUND: 14083c50f6d6San207044 /* 14093c50f6d6San207044 * we are dealing with RDR rule (DST address gets 14103c50f6d6San207044 * modified on packet from client) 14113c50f6d6San207044 */ 1412*d6c23f6fSyx160601 if (nat->nat_v == 4) { 14133c50f6d6San207044 sum_changed = LONG_SUM(ntohl(nat->nat_inip.s_addr)); 14143c50f6d6San207044 sum_orig = LONG_SUM(ntohl(nat->nat_outip.s_addr)); 1415*d6c23f6fSyx160601 } else { 1416*d6c23f6fSyx160601 sum_changed = LONG_SUM6(&nat->nat_inip6); 1417*d6c23f6fSyx160601 sum_orig = LONG_SUM6(&nat->nat_outip6); 1418*d6c23f6fSyx160601 } 14193c50f6d6San207044 break; 14203c50f6d6San207044 case NAT_OUTBOUND: 14213c50f6d6San207044 /* 14223c50f6d6San207044 * we are dealing with MAP rule (SRC address gets 14233c50f6d6San207044 * modified on packet from client) 14243c50f6d6San207044 */ 1425*d6c23f6fSyx160601 if (nat->nat_v == 4) { 14263c50f6d6San207044 sum_changed = LONG_SUM(ntohl(nat->nat_outip.s_addr)); 14273c50f6d6San207044 sum_orig = LONG_SUM(ntohl(nat->nat_inip.s_addr)); 1428*d6c23f6fSyx160601 } else { 1429*d6c23f6fSyx160601 sum_changed = LONG_SUM6(&nat->nat_outip6); 1430*d6c23f6fSyx160601 sum_orig = LONG_SUM6(&nat->nat_inip6); 1431*d6c23f6fSyx160601 } 14323c50f6d6San207044 break; 14333c50f6d6San207044 default: ; 14343c50f6d6San207044 break; 14353c50f6d6San207044 } 14363c50f6d6San207044 14373c50f6d6San207044 /* 14383c50f6d6San207044 * we also preserve CALC_SUMD() operands here, for IP chksum delta 14393c50f6d6San207044 * calculation, which happens at the end of function. 14403c50f6d6San207044 */ 14413c50f6d6San207044 ipsum_changed = sum_changed; 14423c50f6d6San207044 ipsum_orig = sum_orig; 14433c50f6d6San207044 /* 14443c50f6d6San207044 * NOTE: the order of operands for partial chksum adjustment 14453c50f6d6San207044 * computation has to be swapped! 14463c50f6d6San207044 */ 14473c50f6d6San207044 CALC_SUMD(sum_changed, sum_orig, sumd); 14483c50f6d6San207044 nat->nat_sumd[1] = (sumd & 0xffff) + (sumd >> 16); 14493c50f6d6San207044 145027dbc409San207044 if (nat->nat_flags & (IPN_TCPUDP | IPN_ICMPQUERY)) { 14513c50f6d6San207044 14523c50f6d6San207044 /* 14533c50f6d6San207044 * switch calculates operands for CALC_SUMD(), which will 14543c50f6d6San207044 * compute the full chksum delta. 14553c50f6d6San207044 */ 14563c50f6d6San207044 switch (nat->nat_dir) 14573c50f6d6San207044 { 14583c50f6d6San207044 case NAT_INBOUND: 1459*d6c23f6fSyx160601 if (nat->nat_v == 4) { 14603c50f6d6San207044 sum_changed = LONG_SUM( 14613c50f6d6San207044 ntohl(nat->nat_inip.s_addr) + 1462*d6c23f6fSyx160601 ntohs(nat->nat_inport)); 14633c50f6d6San207044 sum_orig = LONG_SUM( 14643c50f6d6San207044 ntohl(nat->nat_outip.s_addr) + 1465*d6c23f6fSyx160601 ntohs(nat->nat_outport)); 1466*d6c23f6fSyx160601 } else { 1467*d6c23f6fSyx160601 sum_changed = LONG_SUM6(&nat->nat_inip6) + 1468*d6c23f6fSyx160601 ntohs(nat->nat_inport); 1469*d6c23f6fSyx160601 sum_orig = LONG_SUM6(&nat->nat_outip6) + 1470*d6c23f6fSyx160601 ntohs(nat->nat_outport); 1471*d6c23f6fSyx160601 } 14723c50f6d6San207044 break; 14733c50f6d6San207044 case NAT_OUTBOUND: 1474*d6c23f6fSyx160601 if (nat->nat_v == 4) { 14753c50f6d6San207044 sum_changed = LONG_SUM( 14763c50f6d6San207044 ntohl(nat->nat_outip.s_addr) + 1477*d6c23f6fSyx160601 ntohs(nat->nat_outport)); 14783c50f6d6San207044 sum_orig = LONG_SUM( 14793c50f6d6San207044 ntohl(nat->nat_inip.s_addr) + 1480*d6c23f6fSyx160601 ntohs(nat->nat_inport)); 1481*d6c23f6fSyx160601 } else { 1482*d6c23f6fSyx160601 sum_changed = LONG_SUM6(&nat->nat_outip6) + 1483*d6c23f6fSyx160601 ntohs(nat->nat_outport); 1484*d6c23f6fSyx160601 sum_orig = LONG_SUM6(&nat->nat_inip6) + 1485*d6c23f6fSyx160601 ntohs(nat->nat_inport); 1486*d6c23f6fSyx160601 } 14873c50f6d6San207044 break; 14883c50f6d6San207044 default: ; 14893c50f6d6San207044 break; 14903c50f6d6San207044 } 14913c50f6d6San207044 14923c50f6d6San207044 CALC_SUMD(sum_orig, sum_changed, sumd); 14933c50f6d6San207044 nat->nat_sumd[0] = (sumd & 0xffff) + (sumd >> 16); 149427dbc409San207044 149527dbc409San207044 if (!(nat->nat_flags & IPN_TCPUDP)) { 149627dbc409San207044 /* 149727dbc409San207044 * partial HW chksum offload works for TCP/UDP headers only, 149827dbc409San207044 * so we need to enforce full chksum adjustment for ICMP 149927dbc409San207044 */ 150027dbc409San207044 nat->nat_sumd[1] = nat->nat_sumd[0]; 150127dbc409San207044 } 15023c50f6d6San207044 } 15033c50f6d6San207044 else 15043c50f6d6San207044 nat->nat_sumd[0] = nat->nat_sumd[1]; 15053c50f6d6San207044 15063c50f6d6San207044 /* 15073c50f6d6San207044 * we may reuse the already computed nat_sumd[0] for IP header chksum 15083c50f6d6San207044 * adjustment in case the L4 (TCP/UDP header) is not changed by NAT. 15093c50f6d6San207044 */ 1510*d6c23f6fSyx160601 if (nat->nat_v == 4) { 15113c50f6d6San207044 if (NAT_HAS_L4_CHANGED(nat)) { 15123c50f6d6San207044 /* 1513*d6c23f6fSyx160601 * bad luck, NAT changes also the L4 header, use IP 1514*d6c23f6fSyx160601 * addresses to compute chksum adjustment for IP header. 15153c50f6d6San207044 */ 15163c50f6d6San207044 CALC_SUMD(ipsum_orig, ipsum_changed, sumd); 15173c50f6d6San207044 nat->nat_ipsumd = (sumd & 0xffff) + (sumd >> 16); 1518*d6c23f6fSyx160601 } else { 15193c50f6d6San207044 /* 1520*d6c23f6fSyx160601 * the NAT does not change L4 hdr -> reuse chksum 1521*d6c23f6fSyx160601 * adjustment for IP hdr. 15223c50f6d6San207044 */ 15233c50f6d6San207044 nat->nat_ipsumd = nat->nat_sumd[0]; 152427dbc409San207044 152527dbc409San207044 /* 1526*d6c23f6fSyx160601 * if L4 header does not use chksum - zero out deltas 152727dbc409San207044 */ 1528*d6c23f6fSyx160601 if (!(nat->nat_flags & IPN_TCPUDP)) { 152927dbc409San207044 nat->nat_sumd[0] = 0; 153027dbc409San207044 nat->nat_sumd[1] = 0; 153127dbc409San207044 } 15323c50f6d6San207044 } 1533*d6c23f6fSyx160601 } 15343c50f6d6San207044 15353c50f6d6San207044 return; 15363c50f6d6San207044 } 1537ab25eeb5Syz155240 1538ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */ 1539ab25eeb5Syz155240 /* Function: fr_natputent */ 1540ab25eeb5Syz155240 /* Returns: int - 0 == success, != 0 is the error value. */ 1541ab25eeb5Syz155240 /* Parameters: data(I) - pointer to natget structure with NAT */ 1542ab25eeb5Syz155240 /* structure information to load into the kernel */ 1543ab25eeb5Syz155240 /* getlock(I) - flag indicating whether or not a write lock */ 1544ab25eeb5Syz155240 /* on ipf_nat is already held. */ 1545ab25eeb5Syz155240 /* */ 1546ab25eeb5Syz155240 /* Handle SIOCSTPUT. */ 1547ab25eeb5Syz155240 /* Loads a NAT table entry from user space, including a NAT rule, proxy and */ 1548ab25eeb5Syz155240 /* firewall rule data structures, if pointers to them indicate so. */ 1549ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */ 1550f4b3ec61Sdh155122 static int fr_natputent(data, getlock, ifs) 1551ab25eeb5Syz155240 caddr_t data; 1552ab25eeb5Syz155240 int getlock; 1553f4b3ec61Sdh155122 ipf_stack_t *ifs; 1554ab25eeb5Syz155240 { 1555ab25eeb5Syz155240 nat_save_t ipn, *ipnn; 1556ab25eeb5Syz155240 ap_session_t *aps; 1557ab25eeb5Syz155240 nat_t *n, *nat; 1558ab25eeb5Syz155240 frentry_t *fr; 1559ab25eeb5Syz155240 fr_info_t fin; 1560ab25eeb5Syz155240 ipnat_t *in; 1561ab25eeb5Syz155240 int error; 1562ab25eeb5Syz155240 1563ab25eeb5Syz155240 error = fr_inobj(data, &ipn, IPFOBJ_NATSAVE); 1564ab25eeb5Syz155240 if (error != 0) 1565ab25eeb5Syz155240 return error; 1566ab25eeb5Syz155240 1567ab25eeb5Syz155240 /* 15683805c50fSan207044 * Trigger automatic call to nat_extraflush() if the 15693805c50fSan207044 * table has reached capcity specified by hi watermark. 15703805c50fSan207044 */ 15713805c50fSan207044 if (NAT_TAB_WATER_LEVEL(ifs) > ifs->ifs_nat_flush_lvl_hi) 15723805c50fSan207044 ifs->ifs_nat_doflush = 1; 15733805c50fSan207044 15743805c50fSan207044 /* 1575ab25eeb5Syz155240 * Initialise early because of code at junkput label. 1576ab25eeb5Syz155240 */ 1577ab25eeb5Syz155240 in = NULL; 1578ab25eeb5Syz155240 aps = NULL; 1579ab25eeb5Syz155240 nat = NULL; 1580ab25eeb5Syz155240 ipnn = NULL; 1581ab25eeb5Syz155240 1582ab25eeb5Syz155240 /* 1583ab25eeb5Syz155240 * New entry, copy in the rest of the NAT entry if it's size is more 1584ab25eeb5Syz155240 * than just the nat_t structure. 1585ab25eeb5Syz155240 */ 1586ab25eeb5Syz155240 fr = NULL; 1587ab25eeb5Syz155240 if (ipn.ipn_dsize > sizeof(ipn)) { 1588ab25eeb5Syz155240 if (ipn.ipn_dsize > 81920) { 1589ab25eeb5Syz155240 error = ENOMEM; 1590ab25eeb5Syz155240 goto junkput; 1591ab25eeb5Syz155240 } 1592ab25eeb5Syz155240 1593ab25eeb5Syz155240 KMALLOCS(ipnn, nat_save_t *, ipn.ipn_dsize); 1594ab25eeb5Syz155240 if (ipnn == NULL) 1595ab25eeb5Syz155240 return ENOMEM; 1596ab25eeb5Syz155240 1597ab25eeb5Syz155240 error = fr_inobjsz(data, ipnn, IPFOBJ_NATSAVE, ipn.ipn_dsize); 1598ab25eeb5Syz155240 if (error != 0) { 1599ab25eeb5Syz155240 error = EFAULT; 1600ab25eeb5Syz155240 goto junkput; 1601ab25eeb5Syz155240 } 1602ab25eeb5Syz155240 } else 1603ab25eeb5Syz155240 ipnn = &ipn; 1604ab25eeb5Syz155240 1605ab25eeb5Syz155240 KMALLOC(nat, nat_t *); 1606ab25eeb5Syz155240 if (nat == NULL) { 1607ab25eeb5Syz155240 error = ENOMEM; 1608ab25eeb5Syz155240 goto junkput; 1609ab25eeb5Syz155240 } 1610ab25eeb5Syz155240 1611ab25eeb5Syz155240 bcopy((char *)&ipnn->ipn_nat, (char *)nat, sizeof(*nat)); 1612ab25eeb5Syz155240 /* 1613ab25eeb5Syz155240 * Initialize all these so that nat_delete() doesn't cause a crash. 1614ab25eeb5Syz155240 */ 1615ab25eeb5Syz155240 bzero((char *)nat, offsetof(struct nat, nat_tqe)); 1616ab25eeb5Syz155240 nat->nat_tqe.tqe_pnext = NULL; 1617ab25eeb5Syz155240 nat->nat_tqe.tqe_next = NULL; 1618ab25eeb5Syz155240 nat->nat_tqe.tqe_ifq = NULL; 1619ab25eeb5Syz155240 nat->nat_tqe.tqe_parent = nat; 1620ab25eeb5Syz155240 1621ab25eeb5Syz155240 /* 1622ab25eeb5Syz155240 * Restore the rule associated with this nat session 1623ab25eeb5Syz155240 */ 1624ab25eeb5Syz155240 in = ipnn->ipn_nat.nat_ptr; 1625ab25eeb5Syz155240 if (in != NULL) { 1626ab25eeb5Syz155240 KMALLOC(in, ipnat_t *); 1627ab25eeb5Syz155240 nat->nat_ptr = in; 1628ab25eeb5Syz155240 if (in == NULL) { 1629ab25eeb5Syz155240 error = ENOMEM; 1630ab25eeb5Syz155240 goto junkput; 1631ab25eeb5Syz155240 } 1632ab25eeb5Syz155240 bzero((char *)in, offsetof(struct ipnat, in_next6)); 1633ab25eeb5Syz155240 bcopy((char *)&ipnn->ipn_ipnat, (char *)in, sizeof(*in)); 1634ab25eeb5Syz155240 in->in_use = 1; 1635ab25eeb5Syz155240 in->in_flags |= IPN_DELETE; 1636ab25eeb5Syz155240 1637f4b3ec61Sdh155122 ATOMIC_INC(ifs->ifs_nat_stats.ns_rules); 1638ab25eeb5Syz155240 1639dcf3e898Sjojemann if (nat_resolverule(in, ifs) != 0) { 1640dcf3e898Sjojemann error = ESRCH; 1641dcf3e898Sjojemann goto junkput; 1642dcf3e898Sjojemann } 1643ab25eeb5Syz155240 } 1644ab25eeb5Syz155240 1645ab25eeb5Syz155240 /* 1646ab25eeb5Syz155240 * Check that the NAT entry doesn't already exist in the kernel. 1647ab25eeb5Syz155240 */ 1648*d6c23f6fSyx160601 if (nat->nat_v != 6) 1649*d6c23f6fSyx160601 nat->nat_v = 4; 1650ab25eeb5Syz155240 bzero((char *)&fin, sizeof(fin)); 1651ab25eeb5Syz155240 fin.fin_p = nat->nat_p; 165275c9105fSjojemann fin.fin_ifs = ifs; 1653ab25eeb5Syz155240 if (nat->nat_dir == NAT_OUTBOUND) { 1654ab25eeb5Syz155240 fin.fin_data[0] = ntohs(nat->nat_oport); 1655ab25eeb5Syz155240 fin.fin_data[1] = ntohs(nat->nat_outport); 1656e6c6c1faSyz155240 fin.fin_ifp = nat->nat_ifps[0]; 1657ab25eeb5Syz155240 if (getlock) { 1658f4b3ec61Sdh155122 READ_ENTER(&ifs->ifs_ipf_nat); 1659ab25eeb5Syz155240 } 1660*d6c23f6fSyx160601 1661*d6c23f6fSyx160601 switch (nat->nat_v) 1662*d6c23f6fSyx160601 { 1663*d6c23f6fSyx160601 case 4: 1664*d6c23f6fSyx160601 fin.fin_v = nat->nat_v; 1665ab25eeb5Syz155240 n = nat_inlookup(&fin, nat->nat_flags, fin.fin_p, 1666ab25eeb5Syz155240 nat->nat_oip, nat->nat_outip); 1667*d6c23f6fSyx160601 break; 1668*d6c23f6fSyx160601 #ifdef USE_INET6 1669*d6c23f6fSyx160601 case 6: 1670*d6c23f6fSyx160601 n = nat6_inlookup(&fin, nat->nat_flags, fin.fin_p, 1671*d6c23f6fSyx160601 &nat->nat_oip6.in6, &nat->nat_outip6.in6); 1672*d6c23f6fSyx160601 break; 1673*d6c23f6fSyx160601 #endif 1674*d6c23f6fSyx160601 default: 1675*d6c23f6fSyx160601 n = NULL; 1676*d6c23f6fSyx160601 break; 1677*d6c23f6fSyx160601 } 1678*d6c23f6fSyx160601 1679ab25eeb5Syz155240 if (getlock) { 1680f4b3ec61Sdh155122 RWLOCK_EXIT(&ifs->ifs_ipf_nat); 1681ab25eeb5Syz155240 } 1682ab25eeb5Syz155240 if (n != NULL) { 1683ab25eeb5Syz155240 error = EEXIST; 1684ab25eeb5Syz155240 goto junkput; 1685ab25eeb5Syz155240 } 1686ab25eeb5Syz155240 } else if (nat->nat_dir == NAT_INBOUND) { 1687ab25eeb5Syz155240 fin.fin_data[0] = ntohs(nat->nat_inport); 1688ab25eeb5Syz155240 fin.fin_data[1] = ntohs(nat->nat_oport); 1689e6c6c1faSyz155240 fin.fin_ifp = nat->nat_ifps[1]; 1690ab25eeb5Syz155240 if (getlock) { 1691f4b3ec61Sdh155122 READ_ENTER(&ifs->ifs_ipf_nat); 1692ab25eeb5Syz155240 } 1693*d6c23f6fSyx160601 1694*d6c23f6fSyx160601 switch (nat->nat_v) 1695*d6c23f6fSyx160601 { 1696*d6c23f6fSyx160601 case 4: 1697ab25eeb5Syz155240 n = nat_outlookup(&fin, nat->nat_flags, fin.fin_p, 1698e6c6c1faSyz155240 nat->nat_inip, nat->nat_oip); 1699*d6c23f6fSyx160601 break; 1700*d6c23f6fSyx160601 #ifdef USE_INET6 1701*d6c23f6fSyx160601 case 6: 1702*d6c23f6fSyx160601 n = nat6_outlookup(&fin, nat->nat_flags, fin.fin_p, 1703*d6c23f6fSyx160601 &nat->nat_inip6.in6, &nat->nat_oip6.in6); 1704*d6c23f6fSyx160601 break; 1705*d6c23f6fSyx160601 #endif 1706*d6c23f6fSyx160601 default: 1707*d6c23f6fSyx160601 n = NULL; 1708*d6c23f6fSyx160601 break; 1709*d6c23f6fSyx160601 } 1710*d6c23f6fSyx160601 1711ab25eeb5Syz155240 if (getlock) { 1712f4b3ec61Sdh155122 RWLOCK_EXIT(&ifs->ifs_ipf_nat); 1713ab25eeb5Syz155240 } 1714ab25eeb5Syz155240 if (n != NULL) { 1715ab25eeb5Syz155240 error = EEXIST; 1716ab25eeb5Syz155240 goto junkput; 1717ab25eeb5Syz155240 } 1718ab25eeb5Syz155240 } else { 1719ab25eeb5Syz155240 error = EINVAL; 1720ab25eeb5Syz155240 goto junkput; 1721ab25eeb5Syz155240 } 1722ab25eeb5Syz155240 1723ab25eeb5Syz155240 /* 1724ab25eeb5Syz155240 * Restore ap_session_t structure. Include the private data allocated 1725ab25eeb5Syz155240 * if it was there. 1726ab25eeb5Syz155240 */ 1727ab25eeb5Syz155240 aps = nat->nat_aps; 1728ab25eeb5Syz155240 if (aps != NULL) { 1729ab25eeb5Syz155240 KMALLOC(aps, ap_session_t *); 1730ab25eeb5Syz155240 nat->nat_aps = aps; 1731ab25eeb5Syz155240 if (aps == NULL) { 1732ab25eeb5Syz155240 error = ENOMEM; 1733ab25eeb5Syz155240 goto junkput; 1734ab25eeb5Syz155240 } 1735ab25eeb5Syz155240 bcopy(ipnn->ipn_data, (char *)aps, sizeof(*aps)); 1736ab25eeb5Syz155240 if (in != NULL) 1737ab25eeb5Syz155240 aps->aps_apr = in->in_apr; 1738ab25eeb5Syz155240 else 1739ab25eeb5Syz155240 aps->aps_apr = NULL; 1740ab25eeb5Syz155240 if (aps->aps_psiz != 0) { 1741ab25eeb5Syz155240 if (aps->aps_psiz > 81920) { 1742ab25eeb5Syz155240 error = ENOMEM; 1743ab25eeb5Syz155240 goto junkput; 1744ab25eeb5Syz155240 } 1745ab25eeb5Syz155240 KMALLOCS(aps->aps_data, void *, aps->aps_psiz); 1746ab25eeb5Syz155240 if (aps->aps_data == NULL) { 1747ab25eeb5Syz155240 error = ENOMEM; 1748ab25eeb5Syz155240 goto junkput; 1749ab25eeb5Syz155240 } 1750ab25eeb5Syz155240 bcopy(ipnn->ipn_data + sizeof(*aps), aps->aps_data, 1751ab25eeb5Syz155240 aps->aps_psiz); 1752ab25eeb5Syz155240 } else { 1753ab25eeb5Syz155240 aps->aps_psiz = 0; 1754ab25eeb5Syz155240 aps->aps_data = NULL; 1755ab25eeb5Syz155240 } 1756ab25eeb5Syz155240 } 1757ab25eeb5Syz155240 1758ab25eeb5Syz155240 /* 1759ab25eeb5Syz155240 * If there was a filtering rule associated with this entry then 1760ab25eeb5Syz155240 * build up a new one. 1761ab25eeb5Syz155240 */ 1762ab25eeb5Syz155240 fr = nat->nat_fr; 1763ab25eeb5Syz155240 if (fr != NULL) { 1764ab25eeb5Syz155240 if ((nat->nat_flags & SI_NEWFR) != 0) { 1765ab25eeb5Syz155240 KMALLOC(fr, frentry_t *); 1766ab25eeb5Syz155240 nat->nat_fr = fr; 1767ab25eeb5Syz155240 if (fr == NULL) { 1768ab25eeb5Syz155240 error = ENOMEM; 1769ab25eeb5Syz155240 goto junkput; 1770ab25eeb5Syz155240 } 1771ab25eeb5Syz155240 ipnn->ipn_nat.nat_fr = fr; 1772ab25eeb5Syz155240 (void) fr_outobj(data, ipnn, IPFOBJ_NATSAVE); 1773ab25eeb5Syz155240 bcopy((char *)&ipnn->ipn_fr, (char *)fr, sizeof(*fr)); 1774dcf3e898Sjojemann 1775dcf3e898Sjojemann fr->fr_ref = 1; 1776dcf3e898Sjojemann fr->fr_dsize = 0; 1777dcf3e898Sjojemann fr->fr_data = NULL; 1778dcf3e898Sjojemann fr->fr_type = FR_T_NONE; 1779dcf3e898Sjojemann 1780ab25eeb5Syz155240 MUTEX_NUKE(&fr->fr_lock); 1781ab25eeb5Syz155240 MUTEX_INIT(&fr->fr_lock, "nat-filter rule lock"); 1782ab25eeb5Syz155240 } else { 1783dcf3e898Sjojemann if (getlock) { 1784f4b3ec61Sdh155122 READ_ENTER(&ifs->ifs_ipf_nat); 1785dcf3e898Sjojemann } 1786f4b3ec61Sdh155122 for (n = ifs->ifs_nat_instances; n; n = n->nat_next) 1787ab25eeb5Syz155240 if (n->nat_fr == fr) 1788ab25eeb5Syz155240 break; 1789ab25eeb5Syz155240 1790ab25eeb5Syz155240 if (n != NULL) { 1791ab25eeb5Syz155240 MUTEX_ENTER(&fr->fr_lock); 1792ab25eeb5Syz155240 fr->fr_ref++; 1793ab25eeb5Syz155240 MUTEX_EXIT(&fr->fr_lock); 1794ab25eeb5Syz155240 } 1795dcf3e898Sjojemann if (getlock) { 1796f4b3ec61Sdh155122 RWLOCK_EXIT(&ifs->ifs_ipf_nat); 1797dcf3e898Sjojemann } 1798ab25eeb5Syz155240 if (!n) { 1799ab25eeb5Syz155240 error = ESRCH; 1800ab25eeb5Syz155240 goto junkput; 1801ab25eeb5Syz155240 } 1802ab25eeb5Syz155240 } 1803ab25eeb5Syz155240 } 1804ab25eeb5Syz155240 1805ab25eeb5Syz155240 if (ipnn != &ipn) { 1806ab25eeb5Syz155240 KFREES(ipnn, ipn.ipn_dsize); 1807ab25eeb5Syz155240 ipnn = NULL; 1808ab25eeb5Syz155240 } 1809ab25eeb5Syz155240 18103c50f6d6San207044 nat_calc_chksum_diffs(nat); 18113c50f6d6San207044 1812ab25eeb5Syz155240 if (getlock) { 1813f4b3ec61Sdh155122 WRITE_ENTER(&ifs->ifs_ipf_nat); 1814ab25eeb5Syz155240 } 1815*d6c23f6fSyx160601 1816*d6c23f6fSyx160601 nat_calc_chksum_diffs(nat); 1817*d6c23f6fSyx160601 1818*d6c23f6fSyx160601 switch (nat->nat_v) 1819*d6c23f6fSyx160601 { 1820*d6c23f6fSyx160601 case 4 : 1821f4b3ec61Sdh155122 error = nat_insert(nat, nat->nat_rev, ifs); 1822*d6c23f6fSyx160601 break; 1823*d6c23f6fSyx160601 #ifdef USE_INET6 1824*d6c23f6fSyx160601 case 6 : 1825*d6c23f6fSyx160601 error = nat6_insert(nat, nat->nat_rev, ifs); 1826*d6c23f6fSyx160601 break; 1827*d6c23f6fSyx160601 #endif 1828*d6c23f6fSyx160601 default : 1829*d6c23f6fSyx160601 break; 1830*d6c23f6fSyx160601 } 1831*d6c23f6fSyx160601 1832ab25eeb5Syz155240 if ((error == 0) && (aps != NULL)) { 1833f4b3ec61Sdh155122 aps->aps_next = ifs->ifs_ap_sess_list; 1834f4b3ec61Sdh155122 ifs->ifs_ap_sess_list = aps; 1835ab25eeb5Syz155240 } 1836ab25eeb5Syz155240 if (getlock) { 1837f4b3ec61Sdh155122 RWLOCK_EXIT(&ifs->ifs_ipf_nat); 1838ab25eeb5Syz155240 } 1839ab25eeb5Syz155240 1840ab25eeb5Syz155240 if (error == 0) 1841ab25eeb5Syz155240 return 0; 1842ab25eeb5Syz155240 1843ab25eeb5Syz155240 error = ENOMEM; 1844ab25eeb5Syz155240 1845ab25eeb5Syz155240 junkput: 1846ab25eeb5Syz155240 if (fr != NULL) 1847f4b3ec61Sdh155122 (void) fr_derefrule(&fr, ifs); 1848ab25eeb5Syz155240 1849ab25eeb5Syz155240 if ((ipnn != NULL) && (ipnn != &ipn)) { 1850ab25eeb5Syz155240 KFREES(ipnn, ipn.ipn_dsize); 1851ab25eeb5Syz155240 } 1852ab25eeb5Syz155240 if (nat != NULL) { 1853ab25eeb5Syz155240 if (aps != NULL) { 1854ab25eeb5Syz155240 if (aps->aps_data != NULL) { 1855ab25eeb5Syz155240 KFREES(aps->aps_data, aps->aps_psiz); 1856ab25eeb5Syz155240 } 1857ab25eeb5Syz155240 KFREE(aps); 1858ab25eeb5Syz155240 } 1859ab25eeb5Syz155240 if (in != NULL) { 1860ab25eeb5Syz155240 if (in->in_apr) 1861ab25eeb5Syz155240 appr_free(in->in_apr); 1862ab25eeb5Syz155240 KFREE(in); 1863ab25eeb5Syz155240 } 1864ab25eeb5Syz155240 KFREE(nat); 1865ab25eeb5Syz155240 } 1866ab25eeb5Syz155240 return error; 1867ab25eeb5Syz155240 } 1868ab25eeb5Syz155240 1869ab25eeb5Syz155240 1870ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */ 1871ab25eeb5Syz155240 /* Function: nat_delete */ 1872ab25eeb5Syz155240 /* Returns: Nil */ 1873ab25eeb5Syz155240 /* Parameters: natd(I) - pointer to NAT structure to delete */ 1874ab25eeb5Syz155240 /* logtype(I) - type of LOG record to create before deleting */ 1875ab25eeb5Syz155240 /* Write Lock: ipf_nat */ 1876ab25eeb5Syz155240 /* */ 1877ab25eeb5Syz155240 /* Delete a nat entry from the various lists and table. If NAT logging is */ 1878ab25eeb5Syz155240 /* enabled then generate a NAT log record for this event. */ 1879ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */ 1880f4b3ec61Sdh155122 static void nat_delete(nat, logtype, ifs) 1881ab25eeb5Syz155240 struct nat *nat; 1882ab25eeb5Syz155240 int logtype; 1883f4b3ec61Sdh155122 ipf_stack_t *ifs; 1884ab25eeb5Syz155240 { 1885ab25eeb5Syz155240 struct ipnat *ipn; 1886ab25eeb5Syz155240 1887f4b3ec61Sdh155122 if (logtype != 0 && ifs->ifs_nat_logging != 0) 1888f4b3ec61Sdh155122 nat_log(nat, logtype, ifs); 1889ab25eeb5Syz155240 1890ab25eeb5Syz155240 /* 1891ab25eeb5Syz155240 * Take it as a general indication that all the pointers are set if 1892ab25eeb5Syz155240 * nat_pnext is set. 1893ab25eeb5Syz155240 */ 1894ab25eeb5Syz155240 if (nat->nat_pnext != NULL) { 1895f4b3ec61Sdh155122 ifs->ifs_nat_stats.ns_bucketlen[0][nat->nat_hv[0]]--; 1896f4b3ec61Sdh155122 ifs->ifs_nat_stats.ns_bucketlen[1][nat->nat_hv[1]]--; 1897ab25eeb5Syz155240 1898ab25eeb5Syz155240 *nat->nat_pnext = nat->nat_next; 1899ab25eeb5Syz155240 if (nat->nat_next != NULL) { 1900ab25eeb5Syz155240 nat->nat_next->nat_pnext = nat->nat_pnext; 1901ab25eeb5Syz155240 nat->nat_next = NULL; 1902ab25eeb5Syz155240 } 1903ab25eeb5Syz155240 nat->nat_pnext = NULL; 1904ab25eeb5Syz155240 1905ab25eeb5Syz155240 *nat->nat_phnext[0] = nat->nat_hnext[0]; 1906ab25eeb5Syz155240 if (nat->nat_hnext[0] != NULL) { 1907ab25eeb5Syz155240 nat->nat_hnext[0]->nat_phnext[0] = nat->nat_phnext[0]; 1908ab25eeb5Syz155240 nat->nat_hnext[0] = NULL; 1909ab25eeb5Syz155240 } 1910ab25eeb5Syz155240 nat->nat_phnext[0] = NULL; 1911ab25eeb5Syz155240 1912ab25eeb5Syz155240 *nat->nat_phnext[1] = nat->nat_hnext[1]; 1913ab25eeb5Syz155240 if (nat->nat_hnext[1] != NULL) { 1914ab25eeb5Syz155240 nat->nat_hnext[1]->nat_phnext[1] = nat->nat_phnext[1]; 1915ab25eeb5Syz155240 nat->nat_hnext[1] = NULL; 1916ab25eeb5Syz155240 } 1917ab25eeb5Syz155240 nat->nat_phnext[1] = NULL; 1918ab25eeb5Syz155240 1919ab25eeb5Syz155240 if ((nat->nat_flags & SI_WILDP) != 0) 1920f4b3ec61Sdh155122 ifs->ifs_nat_stats.ns_wilds--; 1921ab25eeb5Syz155240 } 1922ab25eeb5Syz155240 1923ab25eeb5Syz155240 if (nat->nat_me != NULL) { 1924ab25eeb5Syz155240 *nat->nat_me = NULL; 1925ab25eeb5Syz155240 nat->nat_me = NULL; 1926ab25eeb5Syz155240 } 1927ab25eeb5Syz155240 1928ab25eeb5Syz155240 fr_deletequeueentry(&nat->nat_tqe); 1929ab25eeb5Syz155240 19300e01ff8bSdr146992 MUTEX_ENTER(&nat->nat_lock); 19310e01ff8bSdr146992 if (nat->nat_ref > 1) { 1932ab25eeb5Syz155240 nat->nat_ref--; 19330e01ff8bSdr146992 MUTEX_EXIT(&nat->nat_lock); 1934ab25eeb5Syz155240 return; 1935ab25eeb5Syz155240 } 19360e01ff8bSdr146992 MUTEX_EXIT(&nat->nat_lock); 19370e01ff8bSdr146992 19380e01ff8bSdr146992 /* 19390e01ff8bSdr146992 * At this point, nat_ref is 1, doing "--" would make it 0.. 19400e01ff8bSdr146992 */ 19410e01ff8bSdr146992 nat->nat_ref = 0; 1942ab25eeb5Syz155240 1943ab25eeb5Syz155240 #ifdef IPFILTER_SYNC 1944ab25eeb5Syz155240 if (nat->nat_sync) 1945ab25eeb5Syz155240 ipfsync_del(nat->nat_sync); 1946ab25eeb5Syz155240 #endif 1947ab25eeb5Syz155240 1948ab25eeb5Syz155240 if (nat->nat_fr != NULL) 1949f4b3ec61Sdh155122 (void)fr_derefrule(&nat->nat_fr, ifs); 1950ab25eeb5Syz155240 1951ab25eeb5Syz155240 if (nat->nat_hm != NULL) 195290b0a856Sjojemann fr_hostmapdel(&nat->nat_hm); 1953ab25eeb5Syz155240 1954ab25eeb5Syz155240 /* 1955ab25eeb5Syz155240 * If there is an active reference from the nat entry to its parent 1956ab25eeb5Syz155240 * rule, decrement the rule's reference count and free it too if no 1957ab25eeb5Syz155240 * longer being used. 1958ab25eeb5Syz155240 */ 1959ab25eeb5Syz155240 ipn = nat->nat_ptr; 1960ab25eeb5Syz155240 if (ipn != NULL) { 1961ab25eeb5Syz155240 ipn->in_space++; 1962ab25eeb5Syz155240 ipn->in_use--; 1963ab25eeb5Syz155240 if (ipn->in_use == 0 && (ipn->in_flags & IPN_DELETE)) { 1964ab25eeb5Syz155240 if (ipn->in_apr) 1965ab25eeb5Syz155240 appr_free(ipn->in_apr); 1966ab25eeb5Syz155240 KFREE(ipn); 1967f4b3ec61Sdh155122 ifs->ifs_nat_stats.ns_rules--; 1968ab25eeb5Syz155240 } 1969ab25eeb5Syz155240 } 1970ab25eeb5Syz155240 1971ab25eeb5Syz155240 MUTEX_DESTROY(&nat->nat_lock); 1972ab25eeb5Syz155240 1973f4b3ec61Sdh155122 aps_free(nat->nat_aps, ifs); 1974f4b3ec61Sdh155122 ifs->ifs_nat_stats.ns_inuse--; 1975ab25eeb5Syz155240 1976ab25eeb5Syz155240 /* 1977ab25eeb5Syz155240 * If there's a fragment table entry too for this nat entry, then 1978ab25eeb5Syz155240 * dereference that as well. This is after nat_lock is released 1979ab25eeb5Syz155240 * because of Tru64. 1980ab25eeb5Syz155240 */ 1981f4b3ec61Sdh155122 fr_forgetnat((void *)nat, ifs); 1982ab25eeb5Syz155240 1983ab25eeb5Syz155240 KFREE(nat); 1984ab25eeb5Syz155240 } 1985ab25eeb5Syz155240 1986ab25eeb5Syz155240 1987ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */ 1988ab25eeb5Syz155240 /* Function: nat_flushtable */ 1989ab25eeb5Syz155240 /* Returns: int - number of NAT rules deleted */ 1990ab25eeb5Syz155240 /* Parameters: Nil */ 1991ab25eeb5Syz155240 /* */ 1992ab25eeb5Syz155240 /* Deletes all currently active NAT sessions. In deleting each NAT entry a */ 1993ab25eeb5Syz155240 /* log record should be emitted in nat_delete() if NAT logging is enabled. */ 1994ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */ 1995ab25eeb5Syz155240 /* 1996ab25eeb5Syz155240 * nat_flushtable - clear the NAT table of all mapping entries. 1997ab25eeb5Syz155240 */ 1998f4b3ec61Sdh155122 static int nat_flushtable(ifs) 1999f4b3ec61Sdh155122 ipf_stack_t *ifs; 2000ab25eeb5Syz155240 { 2001ab25eeb5Syz155240 nat_t *nat; 2002ab25eeb5Syz155240 int j = 0; 2003ab25eeb5Syz155240 2004ab25eeb5Syz155240 /* 2005ab25eeb5Syz155240 * ALL NAT mappings deleted, so lets just make the deletions 2006ab25eeb5Syz155240 * quicker. 2007ab25eeb5Syz155240 */ 2008f4b3ec61Sdh155122 if (ifs->ifs_nat_table[0] != NULL) 2009f4b3ec61Sdh155122 bzero((char *)ifs->ifs_nat_table[0], 2010f4b3ec61Sdh155122 sizeof(ifs->ifs_nat_table[0]) * ifs->ifs_ipf_nattable_sz); 2011f4b3ec61Sdh155122 if (ifs->ifs_nat_table[1] != NULL) 2012f4b3ec61Sdh155122 bzero((char *)ifs->ifs_nat_table[1], 2013f4b3ec61Sdh155122 sizeof(ifs->ifs_nat_table[1]) * ifs->ifs_ipf_nattable_sz); 2014ab25eeb5Syz155240 2015f4b3ec61Sdh155122 while ((nat = ifs->ifs_nat_instances) != NULL) { 2016f4b3ec61Sdh155122 nat_delete(nat, NL_FLUSH, ifs); 2017ab25eeb5Syz155240 j++; 2018ab25eeb5Syz155240 } 2019ab25eeb5Syz155240 2020ab25eeb5Syz155240 return j; 2021ab25eeb5Syz155240 } 2022ab25eeb5Syz155240 2023ab25eeb5Syz155240 2024ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */ 2025ab25eeb5Syz155240 /* Function: nat_clearlist */ 2026ab25eeb5Syz155240 /* Returns: int - number of NAT/RDR rules deleted */ 2027ab25eeb5Syz155240 /* Parameters: Nil */ 2028ab25eeb5Syz155240 /* */ 2029ab25eeb5Syz155240 /* Delete all rules in the current list of rules. There is nothing elegant */ 2030ab25eeb5Syz155240 /* about this cleanup: simply free all entries on the list of rules and */ 2031ab25eeb5Syz155240 /* clear out the tables used for hashed NAT rule lookups. */ 2032ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */ 2033f4b3ec61Sdh155122 static int nat_clearlist(ifs) 2034f4b3ec61Sdh155122 ipf_stack_t *ifs; 2035ab25eeb5Syz155240 { 2036f4b3ec61Sdh155122 ipnat_t *n, **np = &ifs->ifs_nat_list; 2037ab25eeb5Syz155240 int i = 0; 2038ab25eeb5Syz155240 2039f4b3ec61Sdh155122 if (ifs->ifs_nat_rules != NULL) 2040f4b3ec61Sdh155122 bzero((char *)ifs->ifs_nat_rules, 2041f4b3ec61Sdh155122 sizeof(*ifs->ifs_nat_rules) * ifs->ifs_ipf_natrules_sz); 2042f4b3ec61Sdh155122 if (ifs->ifs_rdr_rules != NULL) 2043f4b3ec61Sdh155122 bzero((char *)ifs->ifs_rdr_rules, 2044f4b3ec61Sdh155122 sizeof(*ifs->ifs_rdr_rules) * ifs->ifs_ipf_rdrrules_sz); 2045ab25eeb5Syz155240 2046ab25eeb5Syz155240 while ((n = *np) != NULL) { 2047ab25eeb5Syz155240 *np = n->in_next; 2048ab25eeb5Syz155240 if (n->in_use == 0) { 2049ab25eeb5Syz155240 if (n->in_apr != NULL) 2050ab25eeb5Syz155240 appr_free(n->in_apr); 2051ab25eeb5Syz155240 KFREE(n); 2052f4b3ec61Sdh155122 ifs->ifs_nat_stats.ns_rules--; 2053ab25eeb5Syz155240 } else { 2054ab25eeb5Syz155240 n->in_flags |= IPN_DELETE; 2055ab25eeb5Syz155240 n->in_next = NULL; 2056ab25eeb5Syz155240 } 2057ab25eeb5Syz155240 i++; 2058ab25eeb5Syz155240 } 2059f4b3ec61Sdh155122 ifs->ifs_nat_masks = 0; 2060f4b3ec61Sdh155122 ifs->ifs_rdr_masks = 0; 2061*d6c23f6fSyx160601 for (i = 0; i < 4; i++) { 2062*d6c23f6fSyx160601 ifs->ifs_nat6_masks[i] = 0; 2063*d6c23f6fSyx160601 ifs->ifs_rdr6_masks[i] = 0; 2064*d6c23f6fSyx160601 } 2065ab25eeb5Syz155240 return i; 2066ab25eeb5Syz155240 } 2067ab25eeb5Syz155240 2068ab25eeb5Syz155240 2069ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */ 2070ab25eeb5Syz155240 /* Function: nat_newmap */ 2071ab25eeb5Syz155240 /* Returns: int - -1 == error, 0 == success */ 2072ab25eeb5Syz155240 /* Parameters: fin(I) - pointer to packet information */ 2073ab25eeb5Syz155240 /* nat(I) - pointer to NAT entry */ 2074ab25eeb5Syz155240 /* ni(I) - pointer to structure with misc. information needed */ 2075ab25eeb5Syz155240 /* to create new NAT entry. */ 2076ab25eeb5Syz155240 /* */ 2077ab25eeb5Syz155240 /* Given an empty NAT structure, populate it with new information about a */ 2078ab25eeb5Syz155240 /* new NAT session, as defined by the matching NAT rule. */ 2079ab25eeb5Syz155240 /* ni.nai_ip is passed in uninitialised and must be set, in host byte order,*/ 2080ab25eeb5Syz155240 /* to the new IP address for the translation. */ 2081ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */ 2082ab25eeb5Syz155240 static INLINE int nat_newmap(fin, nat, ni) 2083ab25eeb5Syz155240 fr_info_t *fin; 2084ab25eeb5Syz155240 nat_t *nat; 2085ab25eeb5Syz155240 natinfo_t *ni; 2086ab25eeb5Syz155240 { 2087ab25eeb5Syz155240 u_short st_port, dport, sport, port, sp, dp; 2088ab25eeb5Syz155240 struct in_addr in, inb; 2089ab25eeb5Syz155240 hostmap_t *hm; 2090ab25eeb5Syz155240 u_32_t flags; 2091ab25eeb5Syz155240 u_32_t st_ip; 2092ab25eeb5Syz155240 ipnat_t *np; 2093ab25eeb5Syz155240 nat_t *natl; 2094ab25eeb5Syz155240 int l; 2095f4b3ec61Sdh155122 ipf_stack_t *ifs = fin->fin_ifs; 2096ab25eeb5Syz155240 2097ab25eeb5Syz155240 /* 2098ab25eeb5Syz155240 * If it's an outbound packet which doesn't match any existing 2099ab25eeb5Syz155240 * record, then create a new port 2100ab25eeb5Syz155240 */ 2101ab25eeb5Syz155240 l = 0; 2102ab25eeb5Syz155240 hm = NULL; 2103ab25eeb5Syz155240 np = ni->nai_np; 2104ab25eeb5Syz155240 st_ip = np->in_nip; 2105ab25eeb5Syz155240 st_port = np->in_pnext; 2106ab25eeb5Syz155240 flags = ni->nai_flags; 2107ab25eeb5Syz155240 sport = ni->nai_sport; 2108ab25eeb5Syz155240 dport = ni->nai_dport; 2109ab25eeb5Syz155240 2110ab25eeb5Syz155240 /* 2111ab25eeb5Syz155240 * Do a loop until we either run out of entries to try or we find 2112ab25eeb5Syz155240 * a NAT mapping that isn't currently being used. This is done 2113ab25eeb5Syz155240 * because the change to the source is not (usually) being fixed. 2114ab25eeb5Syz155240 */ 2115ab25eeb5Syz155240 do { 2116ab25eeb5Syz155240 port = 0; 2117ab25eeb5Syz155240 in.s_addr = htonl(np->in_nip); 2118ab25eeb5Syz155240 if (l == 0) { 2119ab25eeb5Syz155240 /* 2120ab25eeb5Syz155240 * Check to see if there is an existing NAT 2121ab25eeb5Syz155240 * setup for this IP address pair. 2122ab25eeb5Syz155240 */ 2123ab25eeb5Syz155240 hm = nat_hostmap(np, fin->fin_src, fin->fin_dst, 2124f4b3ec61Sdh155122 in, 0, ifs); 2125ab25eeb5Syz155240 if (hm != NULL) 2126ab25eeb5Syz155240 in.s_addr = hm->hm_mapip.s_addr; 2127ab25eeb5Syz155240 } else if ((l == 1) && (hm != NULL)) { 212890b0a856Sjojemann fr_hostmapdel(&hm); 2129ab25eeb5Syz155240 } 2130ab25eeb5Syz155240 in.s_addr = ntohl(in.s_addr); 2131ab25eeb5Syz155240 2132ab25eeb5Syz155240 nat->nat_hm = hm; 2133ab25eeb5Syz155240 2134ab25eeb5Syz155240 if ((np->in_outmsk == 0xffffffff) && (np->in_pnext == 0)) { 2135ab25eeb5Syz155240 if (l > 0) 2136ab25eeb5Syz155240 return -1; 2137ab25eeb5Syz155240 } 2138ab25eeb5Syz155240 2139ab25eeb5Syz155240 if (np->in_redir == NAT_BIMAP && 2140ab25eeb5Syz155240 np->in_inmsk == np->in_outmsk) { 2141ab25eeb5Syz155240 /* 2142ab25eeb5Syz155240 * map the address block in a 1:1 fashion 2143ab25eeb5Syz155240 */ 2144ab25eeb5Syz155240 in.s_addr = np->in_outip; 2145ab25eeb5Syz155240 in.s_addr |= fin->fin_saddr & ~np->in_inmsk; 2146ab25eeb5Syz155240 in.s_addr = ntohl(in.s_addr); 2147ab25eeb5Syz155240 2148ab25eeb5Syz155240 } else if (np->in_redir & NAT_MAPBLK) { 2149ab25eeb5Syz155240 if ((l >= np->in_ppip) || ((l > 0) && 2150ab25eeb5Syz155240 !(flags & IPN_TCPUDP))) 2151ab25eeb5Syz155240 return -1; 2152ab25eeb5Syz155240 /* 2153ab25eeb5Syz155240 * map-block - Calculate destination address. 2154ab25eeb5Syz155240 */ 2155ab25eeb5Syz155240 in.s_addr = ntohl(fin->fin_saddr); 2156ab25eeb5Syz155240 in.s_addr &= ntohl(~np->in_inmsk); 2157ab25eeb5Syz155240 inb.s_addr = in.s_addr; 2158ab25eeb5Syz155240 in.s_addr /= np->in_ippip; 2159ab25eeb5Syz155240 in.s_addr &= ntohl(~np->in_outmsk); 2160ab25eeb5Syz155240 in.s_addr += ntohl(np->in_outip); 2161ab25eeb5Syz155240 /* 2162ab25eeb5Syz155240 * Calculate destination port. 2163ab25eeb5Syz155240 */ 2164ab25eeb5Syz155240 if ((flags & IPN_TCPUDP) && 2165ab25eeb5Syz155240 (np->in_ppip != 0)) { 2166ab25eeb5Syz155240 port = ntohs(sport) + l; 2167ab25eeb5Syz155240 port %= np->in_ppip; 2168ab25eeb5Syz155240 port += np->in_ppip * 2169ab25eeb5Syz155240 (inb.s_addr % np->in_ippip); 2170ab25eeb5Syz155240 port += MAPBLK_MINPORT; 2171ab25eeb5Syz155240 port = htons(port); 2172ab25eeb5Syz155240 } 2173ab25eeb5Syz155240 2174ab25eeb5Syz155240 } else if ((np->in_outip == 0) && 2175ab25eeb5Syz155240 (np->in_outmsk == 0xffffffff)) { 2176ab25eeb5Syz155240 /* 2177ab25eeb5Syz155240 * 0/32 - use the interface's IP address. 2178ab25eeb5Syz155240 */ 2179ab25eeb5Syz155240 if ((l > 0) || 2180ab25eeb5Syz155240 fr_ifpaddr(4, FRI_NORMAL, fin->fin_ifp, 2181f4b3ec61Sdh155122 &in, NULL, fin->fin_ifs) == -1) 2182ab25eeb5Syz155240 return -1; 2183ab25eeb5Syz155240 in.s_addr = ntohl(in.s_addr); 2184ab25eeb5Syz155240 2185ab25eeb5Syz155240 } else if ((np->in_outip == 0) && (np->in_outmsk == 0)) { 2186ab25eeb5Syz155240 /* 2187ab25eeb5Syz155240 * 0/0 - use the original source address/port. 2188ab25eeb5Syz155240 */ 2189ab25eeb5Syz155240 if (l > 0) 2190ab25eeb5Syz155240 return -1; 2191ab25eeb5Syz155240 in.s_addr = ntohl(fin->fin_saddr); 2192ab25eeb5Syz155240 2193ab25eeb5Syz155240 } else if ((np->in_outmsk != 0xffffffff) && 2194ab25eeb5Syz155240 (np->in_pnext == 0) && ((l > 0) || (hm == NULL))) 2195ab25eeb5Syz155240 np->in_nip++; 2196ab25eeb5Syz155240 2197ab25eeb5Syz155240 natl = NULL; 2198ab25eeb5Syz155240 2199ab25eeb5Syz155240 if ((flags & IPN_TCPUDP) && 2200ab25eeb5Syz155240 ((np->in_redir & NAT_MAPBLK) == 0) && 2201ab25eeb5Syz155240 (np->in_flags & IPN_AUTOPORTMAP)) { 2202ab25eeb5Syz155240 /* 2203ab25eeb5Syz155240 * "ports auto" (without map-block) 2204ab25eeb5Syz155240 */ 2205ab25eeb5Syz155240 if ((l > 0) && (l % np->in_ppip == 0)) { 2206ab25eeb5Syz155240 if (l > np->in_space) { 2207ab25eeb5Syz155240 return -1; 2208ab25eeb5Syz155240 } else if ((l > np->in_ppip) && 2209ab25eeb5Syz155240 np->in_outmsk != 0xffffffff) 2210ab25eeb5Syz155240 np->in_nip++; 2211ab25eeb5Syz155240 } 2212ab25eeb5Syz155240 if (np->in_ppip != 0) { 2213ab25eeb5Syz155240 port = ntohs(sport); 2214ab25eeb5Syz155240 port += (l % np->in_ppip); 2215ab25eeb5Syz155240 port %= np->in_ppip; 2216ab25eeb5Syz155240 port += np->in_ppip * 2217ab25eeb5Syz155240 (ntohl(fin->fin_saddr) % 2218ab25eeb5Syz155240 np->in_ippip); 2219ab25eeb5Syz155240 port += MAPBLK_MINPORT; 2220ab25eeb5Syz155240 port = htons(port); 2221ab25eeb5Syz155240 } 2222ab25eeb5Syz155240 2223ab25eeb5Syz155240 } else if (((np->in_redir & NAT_MAPBLK) == 0) && 2224ab25eeb5Syz155240 (flags & IPN_TCPUDPICMP) && (np->in_pnext != 0)) { 2225ab25eeb5Syz155240 /* 2226ab25eeb5Syz155240 * Standard port translation. Select next port. 2227ab25eeb5Syz155240 */ 2228ab25eeb5Syz155240 port = htons(np->in_pnext++); 2229ab25eeb5Syz155240 2230ab25eeb5Syz155240 if (np->in_pnext > ntohs(np->in_pmax)) { 2231ab25eeb5Syz155240 np->in_pnext = ntohs(np->in_pmin); 2232ab25eeb5Syz155240 if (np->in_outmsk != 0xffffffff) 2233ab25eeb5Syz155240 np->in_nip++; 2234ab25eeb5Syz155240 } 2235ab25eeb5Syz155240 } 2236ab25eeb5Syz155240 2237ab25eeb5Syz155240 if (np->in_flags & IPN_IPRANGE) { 2238ab25eeb5Syz155240 if (np->in_nip > ntohl(np->in_outmsk)) 2239ab25eeb5Syz155240 np->in_nip = ntohl(np->in_outip); 2240ab25eeb5Syz155240 } else { 2241ab25eeb5Syz155240 if ((np->in_outmsk != 0xffffffff) && 2242ab25eeb5Syz155240 ((np->in_nip + 1) & ntohl(np->in_outmsk)) > 2243ab25eeb5Syz155240 ntohl(np->in_outip)) 2244ab25eeb5Syz155240 np->in_nip = ntohl(np->in_outip) + 1; 2245ab25eeb5Syz155240 } 2246ab25eeb5Syz155240 2247ab25eeb5Syz155240 if ((port == 0) && (flags & (IPN_TCPUDPICMP|IPN_ICMPQUERY))) 2248ab25eeb5Syz155240 port = sport; 2249ab25eeb5Syz155240 2250ab25eeb5Syz155240 /* 2251ab25eeb5Syz155240 * Here we do a lookup of the connection as seen from 2252ab25eeb5Syz155240 * the outside. If an IP# pair already exists, try 2253ab25eeb5Syz155240 * again. So if you have A->B becomes C->B, you can 2254ab25eeb5Syz155240 * also have D->E become C->E but not D->B causing 2255ab25eeb5Syz155240 * another C->B. Also take protocol and ports into 2256ab25eeb5Syz155240 * account when determining whether a pre-existing 2257ab25eeb5Syz155240 * NAT setup will cause an external conflict where 2258ab25eeb5Syz155240 * this is appropriate. 2259ab25eeb5Syz155240 */ 2260ab25eeb5Syz155240 inb.s_addr = htonl(in.s_addr); 2261ab25eeb5Syz155240 sp = fin->fin_data[0]; 2262ab25eeb5Syz155240 dp = fin->fin_data[1]; 2263ab25eeb5Syz155240 fin->fin_data[0] = fin->fin_data[1]; 2264ab25eeb5Syz155240 fin->fin_data[1] = htons(port); 2265ab25eeb5Syz155240 natl = nat_inlookup(fin, flags & ~(SI_WILDP|NAT_SEARCH), 2266ab25eeb5Syz155240 (u_int)fin->fin_p, fin->fin_dst, inb); 2267ab25eeb5Syz155240 fin->fin_data[0] = sp; 2268ab25eeb5Syz155240 fin->fin_data[1] = dp; 2269ab25eeb5Syz155240 2270ab25eeb5Syz155240 /* 2271ab25eeb5Syz155240 * Has the search wrapped around and come back to the 2272ab25eeb5Syz155240 * start ? 2273ab25eeb5Syz155240 */ 2274ab25eeb5Syz155240 if ((natl != NULL) && 2275ab25eeb5Syz155240 (np->in_pnext != 0) && (st_port == np->in_pnext) && 2276ab25eeb5Syz155240 (np->in_nip != 0) && (st_ip == np->in_nip)) 2277ab25eeb5Syz155240 return -1; 2278ab25eeb5Syz155240 l++; 2279ab25eeb5Syz155240 } while (natl != NULL); 2280ab25eeb5Syz155240 2281ab25eeb5Syz155240 if (np->in_space > 0) 2282ab25eeb5Syz155240 np->in_space--; 2283ab25eeb5Syz155240 2284ab25eeb5Syz155240 /* Setup the NAT table */ 2285ab25eeb5Syz155240 nat->nat_inip = fin->fin_src; 2286ab25eeb5Syz155240 nat->nat_outip.s_addr = htonl(in.s_addr); 2287ab25eeb5Syz155240 nat->nat_oip = fin->fin_dst; 2288ab25eeb5Syz155240 if (nat->nat_hm == NULL) 2289ab25eeb5Syz155240 nat->nat_hm = nat_hostmap(np, fin->fin_src, fin->fin_dst, 2290f4b3ec61Sdh155122 nat->nat_outip, 0, ifs); 2291ab25eeb5Syz155240 2292ab25eeb5Syz155240 if (flags & IPN_TCPUDP) { 2293ab25eeb5Syz155240 nat->nat_inport = sport; 2294ab25eeb5Syz155240 nat->nat_outport = port; /* sport */ 2295ab25eeb5Syz155240 nat->nat_oport = dport; 2296ab25eeb5Syz155240 ((tcphdr_t *)fin->fin_dp)->th_sport = port; 2297ab25eeb5Syz155240 } else if (flags & IPN_ICMPQUERY) { 2298ab25eeb5Syz155240 ((icmphdr_t *)fin->fin_dp)->icmp_id = port; 2299ab25eeb5Syz155240 nat->nat_inport = port; 2300ab25eeb5Syz155240 nat->nat_outport = port; 2301ab25eeb5Syz155240 } 2302ab25eeb5Syz155240 2303ab25eeb5Syz155240 ni->nai_ip.s_addr = in.s_addr; 2304ab25eeb5Syz155240 ni->nai_port = port; 2305ab25eeb5Syz155240 ni->nai_nport = dport; 2306ab25eeb5Syz155240 return 0; 2307ab25eeb5Syz155240 } 2308ab25eeb5Syz155240 2309ab25eeb5Syz155240 2310ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */ 2311ab25eeb5Syz155240 /* Function: nat_newrdr */ 2312ab25eeb5Syz155240 /* Returns: int - -1 == error, 0 == success (no move), 1 == success and */ 2313ab25eeb5Syz155240 /* allow rule to be moved if IPN_ROUNDR is set. */ 2314ab25eeb5Syz155240 /* Parameters: fin(I) - pointer to packet information */ 2315ab25eeb5Syz155240 /* nat(I) - pointer to NAT entry */ 2316ab25eeb5Syz155240 /* ni(I) - pointer to structure with misc. information needed */ 2317ab25eeb5Syz155240 /* to create new NAT entry. */ 2318ab25eeb5Syz155240 /* */ 2319ab25eeb5Syz155240 /* ni.nai_ip is passed in uninitialised and must be set, in host byte order,*/ 2320ab25eeb5Syz155240 /* to the new IP address for the translation. */ 2321ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */ 2322ab25eeb5Syz155240 static INLINE int nat_newrdr(fin, nat, ni) 2323ab25eeb5Syz155240 fr_info_t *fin; 2324ab25eeb5Syz155240 nat_t *nat; 2325ab25eeb5Syz155240 natinfo_t *ni; 2326ab25eeb5Syz155240 { 2327ab25eeb5Syz155240 u_short nport, dport, sport; 23288899fcfaSjojemann struct in_addr in, inb; 23298899fcfaSjojemann u_short sp, dp; 2330ab25eeb5Syz155240 hostmap_t *hm; 2331ab25eeb5Syz155240 u_32_t flags; 2332ab25eeb5Syz155240 ipnat_t *np; 23338899fcfaSjojemann nat_t *natl; 2334ab25eeb5Syz155240 int move; 2335f4b3ec61Sdh155122 ipf_stack_t *ifs = fin->fin_ifs; 2336ab25eeb5Syz155240 2337ab25eeb5Syz155240 move = 1; 2338ab25eeb5Syz155240 hm = NULL; 2339ab25eeb5Syz155240 in.s_addr = 0; 2340ab25eeb5Syz155240 np = ni->nai_np; 2341ab25eeb5Syz155240 flags = ni->nai_flags; 2342ab25eeb5Syz155240 sport = ni->nai_sport; 2343ab25eeb5Syz155240 dport = ni->nai_dport; 2344ab25eeb5Syz155240 2345ab25eeb5Syz155240 /* 2346ab25eeb5Syz155240 * If the matching rule has IPN_STICKY set, then we want to have the 2347ab25eeb5Syz155240 * same rule kick in as before. Why would this happen? If you have 2348ab25eeb5Syz155240 * a collection of rdr rules with "round-robin sticky", the current 2349ab25eeb5Syz155240 * packet might match a different one to the previous connection but 2350ab25eeb5Syz155240 * we want the same destination to be used. 2351ab25eeb5Syz155240 */ 2352ab25eeb5Syz155240 if ((np->in_flags & (IPN_ROUNDR|IPN_STICKY)) == 2353ab25eeb5Syz155240 (IPN_ROUNDR|IPN_STICKY)) { 2354ab25eeb5Syz155240 hm = nat_hostmap(NULL, fin->fin_src, fin->fin_dst, in, 2355f4b3ec61Sdh155122 (u_32_t)dport, ifs); 2356ab25eeb5Syz155240 if (hm != NULL) { 2357ab25eeb5Syz155240 in.s_addr = ntohl(hm->hm_mapip.s_addr); 2358ab25eeb5Syz155240 np = hm->hm_ipnat; 2359ab25eeb5Syz155240 ni->nai_np = np; 2360ab25eeb5Syz155240 move = 0; 2361ab25eeb5Syz155240 } 2362ab25eeb5Syz155240 } 2363ab25eeb5Syz155240 2364ab25eeb5Syz155240 /* 2365ab25eeb5Syz155240 * Otherwise, it's an inbound packet. Most likely, we don't 2366ab25eeb5Syz155240 * want to rewrite source ports and source addresses. Instead, 2367ab25eeb5Syz155240 * we want to rewrite to a fixed internal address and fixed 2368ab25eeb5Syz155240 * internal port. 2369ab25eeb5Syz155240 */ 2370ab25eeb5Syz155240 if (np->in_flags & IPN_SPLIT) { 2371ab25eeb5Syz155240 in.s_addr = np->in_nip; 2372ab25eeb5Syz155240 2373ab25eeb5Syz155240 if ((np->in_flags & (IPN_ROUNDR|IPN_STICKY)) == IPN_STICKY) { 2374ab25eeb5Syz155240 hm = nat_hostmap(np, fin->fin_src, fin->fin_dst, 2375f4b3ec61Sdh155122 in, (u_32_t)dport, ifs); 2376ab25eeb5Syz155240 if (hm != NULL) { 2377ab25eeb5Syz155240 in.s_addr = hm->hm_mapip.s_addr; 2378ab25eeb5Syz155240 move = 0; 2379ab25eeb5Syz155240 } 2380ab25eeb5Syz155240 } 2381ab25eeb5Syz155240 2382ab25eeb5Syz155240 if (hm == NULL || hm->hm_ref == 1) { 2383ab25eeb5Syz155240 if (np->in_inip == htonl(in.s_addr)) { 2384ab25eeb5Syz155240 np->in_nip = ntohl(np->in_inmsk); 2385ab25eeb5Syz155240 move = 0; 2386ab25eeb5Syz155240 } else { 2387ab25eeb5Syz155240 np->in_nip = ntohl(np->in_inip); 2388ab25eeb5Syz155240 } 2389ab25eeb5Syz155240 } 2390ab25eeb5Syz155240 2391ab25eeb5Syz155240 } else if ((np->in_inip == 0) && (np->in_inmsk == 0xffffffff)) { 2392ab25eeb5Syz155240 /* 2393ab25eeb5Syz155240 * 0/32 - use the interface's IP address. 2394ab25eeb5Syz155240 */ 2395f4b3ec61Sdh155122 if (fr_ifpaddr(4, FRI_NORMAL, fin->fin_ifp, &in, NULL, 2396f4b3ec61Sdh155122 fin->fin_ifs) == -1) 2397ab25eeb5Syz155240 return -1; 2398ab25eeb5Syz155240 in.s_addr = ntohl(in.s_addr); 2399ab25eeb5Syz155240 2400ab25eeb5Syz155240 } else if ((np->in_inip == 0) && (np->in_inmsk== 0)) { 2401ab25eeb5Syz155240 /* 2402ab25eeb5Syz155240 * 0/0 - use the original destination address/port. 2403ab25eeb5Syz155240 */ 2404ab25eeb5Syz155240 in.s_addr = ntohl(fin->fin_daddr); 2405ab25eeb5Syz155240 2406ab25eeb5Syz155240 } else if (np->in_redir == NAT_BIMAP && 2407ab25eeb5Syz155240 np->in_inmsk == np->in_outmsk) { 2408ab25eeb5Syz155240 /* 2409ab25eeb5Syz155240 * map the address block in a 1:1 fashion 2410ab25eeb5Syz155240 */ 2411ab25eeb5Syz155240 in.s_addr = np->in_inip; 2412ab25eeb5Syz155240 in.s_addr |= fin->fin_daddr & ~np->in_inmsk; 2413ab25eeb5Syz155240 in.s_addr = ntohl(in.s_addr); 2414ab25eeb5Syz155240 } else { 2415ab25eeb5Syz155240 in.s_addr = ntohl(np->in_inip); 2416ab25eeb5Syz155240 } 2417ab25eeb5Syz155240 2418ab25eeb5Syz155240 if ((np->in_pnext == 0) || ((flags & NAT_NOTRULEPORT) != 0)) 2419ab25eeb5Syz155240 nport = dport; 2420ab25eeb5Syz155240 else { 2421ab25eeb5Syz155240 /* 2422ab25eeb5Syz155240 * Whilst not optimized for the case where 2423ab25eeb5Syz155240 * pmin == pmax, the gain is not significant. 2424ab25eeb5Syz155240 */ 2425ab25eeb5Syz155240 if (((np->in_flags & IPN_FIXEDDPORT) == 0) && 2426ab25eeb5Syz155240 (np->in_pmin != np->in_pmax)) { 2427ab25eeb5Syz155240 nport = ntohs(dport) - ntohs(np->in_pmin) + 2428ab25eeb5Syz155240 ntohs(np->in_pnext); 2429ab25eeb5Syz155240 nport = htons(nport); 2430ab25eeb5Syz155240 } else 2431ab25eeb5Syz155240 nport = np->in_pnext; 2432ab25eeb5Syz155240 } 2433ab25eeb5Syz155240 2434ab25eeb5Syz155240 /* 2435ab25eeb5Syz155240 * When the redirect-to address is set to 0.0.0.0, just 2436ab25eeb5Syz155240 * assume a blank `forwarding' of the packet. We don't 2437ab25eeb5Syz155240 * setup any translation for this either. 2438ab25eeb5Syz155240 */ 2439ab25eeb5Syz155240 if (in.s_addr == 0) { 2440ab25eeb5Syz155240 if (nport == dport) 2441ab25eeb5Syz155240 return -1; 2442ab25eeb5Syz155240 in.s_addr = ntohl(fin->fin_daddr); 2443ab25eeb5Syz155240 } 2444ab25eeb5Syz155240 24458899fcfaSjojemann /* 24468899fcfaSjojemann * Check to see if this redirect mapping already exists and if 24478899fcfaSjojemann * it does, return "failure" (allowing it to be created will just 24488899fcfaSjojemann * cause one or both of these "connections" to stop working.) 24498899fcfaSjojemann */ 24508899fcfaSjojemann inb.s_addr = htonl(in.s_addr); 24518899fcfaSjojemann sp = fin->fin_data[0]; 24528899fcfaSjojemann dp = fin->fin_data[1]; 24538899fcfaSjojemann fin->fin_data[1] = fin->fin_data[0]; 24548899fcfaSjojemann fin->fin_data[0] = ntohs(nport); 24558899fcfaSjojemann natl = nat_outlookup(fin, flags & ~(SI_WILDP|NAT_SEARCH), 24568899fcfaSjojemann (u_int)fin->fin_p, inb, fin->fin_src); 24578899fcfaSjojemann fin->fin_data[0] = sp; 24588899fcfaSjojemann fin->fin_data[1] = dp; 24598899fcfaSjojemann if (natl != NULL) 24608899fcfaSjojemann return (-1); 24618899fcfaSjojemann 2462ab25eeb5Syz155240 nat->nat_inip.s_addr = htonl(in.s_addr); 2463ab25eeb5Syz155240 nat->nat_outip = fin->fin_dst; 2464ab25eeb5Syz155240 nat->nat_oip = fin->fin_src; 2465ab25eeb5Syz155240 2466ab25eeb5Syz155240 ni->nai_ip.s_addr = in.s_addr; 2467ab25eeb5Syz155240 ni->nai_nport = nport; 2468ab25eeb5Syz155240 ni->nai_port = sport; 2469ab25eeb5Syz155240 2470ab25eeb5Syz155240 if (flags & IPN_TCPUDP) { 2471ab25eeb5Syz155240 nat->nat_inport = nport; 2472ab25eeb5Syz155240 nat->nat_outport = dport; 2473ab25eeb5Syz155240 nat->nat_oport = sport; 2474ab25eeb5Syz155240 ((tcphdr_t *)fin->fin_dp)->th_dport = nport; 2475ab25eeb5Syz155240 } else if (flags & IPN_ICMPQUERY) { 2476ab25eeb5Syz155240 ((icmphdr_t *)fin->fin_dp)->icmp_id = nport; 2477ab25eeb5Syz155240 nat->nat_inport = nport; 2478ab25eeb5Syz155240 nat->nat_outport = nport; 2479ab25eeb5Syz155240 } 2480ab25eeb5Syz155240 2481ab25eeb5Syz155240 return move; 2482ab25eeb5Syz155240 } 2483ab25eeb5Syz155240 2484ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */ 2485ab25eeb5Syz155240 /* Function: nat_new */ 2486ab25eeb5Syz155240 /* Returns: nat_t* - NULL == failure to create new NAT structure, */ 2487ab25eeb5Syz155240 /* else pointer to new NAT structure */ 2488ab25eeb5Syz155240 /* Parameters: fin(I) - pointer to packet information */ 2489ab25eeb5Syz155240 /* np(I) - pointer to NAT rule */ 2490ab25eeb5Syz155240 /* natsave(I) - pointer to where to store NAT struct pointer */ 2491ab25eeb5Syz155240 /* flags(I) - flags describing the current packet */ 2492ab25eeb5Syz155240 /* direction(I) - direction of packet (in/out) */ 2493ab25eeb5Syz155240 /* Write Lock: ipf_nat */ 2494ab25eeb5Syz155240 /* */ 2495ab25eeb5Syz155240 /* Attempts to create a new NAT entry. Does not actually change the packet */ 2496ab25eeb5Syz155240 /* in any way. */ 2497ab25eeb5Syz155240 /* */ 2498ab25eeb5Syz155240 /* This fucntion is in three main parts: (1) deal with creating a new NAT */ 2499ab25eeb5Syz155240 /* structure for a "MAP" rule (outgoing NAT translation); (2) deal with */ 2500ab25eeb5Syz155240 /* creating a new NAT structure for a "RDR" rule (incoming NAT translation) */ 2501ab25eeb5Syz155240 /* and (3) building that structure and putting it into the NAT table(s). */ 2502ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */ 2503ab25eeb5Syz155240 nat_t *nat_new(fin, np, natsave, flags, direction) 2504ab25eeb5Syz155240 fr_info_t *fin; 2505ab25eeb5Syz155240 ipnat_t *np; 2506ab25eeb5Syz155240 nat_t **natsave; 2507ab25eeb5Syz155240 u_int flags; 2508ab25eeb5Syz155240 int direction; 2509ab25eeb5Syz155240 { 2510ab25eeb5Syz155240 tcphdr_t *tcp = NULL; 2511ab25eeb5Syz155240 hostmap_t *hm = NULL; 2512ab25eeb5Syz155240 nat_t *nat, *natl; 2513ab25eeb5Syz155240 u_int nflags; 2514ab25eeb5Syz155240 natinfo_t ni; 2515ab25eeb5Syz155240 int move; 2516f4b3ec61Sdh155122 ipf_stack_t *ifs = fin->fin_ifs; 2517ab25eeb5Syz155240 25183805c50fSan207044 /* 25193805c50fSan207044 * Trigger automatic call to nat_extraflush() if the 25203805c50fSan207044 * table has reached capcity specified by hi watermark. 25213805c50fSan207044 */ 25223805c50fSan207044 if (NAT_TAB_WATER_LEVEL(ifs) > ifs->ifs_nat_flush_lvl_hi) 25233805c50fSan207044 ifs->ifs_nat_doflush = 1; 25243805c50fSan207044 2525f4b3ec61Sdh155122 if (ifs->ifs_nat_stats.ns_inuse >= ifs->ifs_ipf_nattable_max) { 2526f4b3ec61Sdh155122 ifs->ifs_nat_stats.ns_memfail++; 2527ab25eeb5Syz155240 return NULL; 2528ab25eeb5Syz155240 } 2529ab25eeb5Syz155240 2530ab25eeb5Syz155240 move = 1; 2531ab25eeb5Syz155240 nflags = np->in_flags & flags; 2532ab25eeb5Syz155240 nflags &= NAT_FROMRULE; 2533ab25eeb5Syz155240 2534ab25eeb5Syz155240 ni.nai_np = np; 2535ab25eeb5Syz155240 ni.nai_nflags = nflags; 2536ab25eeb5Syz155240 ni.nai_flags = flags; 2537ab25eeb5Syz155240 2538ab25eeb5Syz155240 /* Give me a new nat */ 2539ab25eeb5Syz155240 KMALLOC(nat, nat_t *); 2540ab25eeb5Syz155240 if (nat == NULL) { 2541f4b3ec61Sdh155122 ifs->ifs_nat_stats.ns_memfail++; 2542ab25eeb5Syz155240 /* 2543ab25eeb5Syz155240 * Try to automatically tune the max # of entries in the 2544ab25eeb5Syz155240 * table allowed to be less than what will cause kmem_alloc() 2545ab25eeb5Syz155240 * to fail and try to eliminate panics due to out of memory 2546ab25eeb5Syz155240 * conditions arising. 2547ab25eeb5Syz155240 */ 2548f4b3ec61Sdh155122 if (ifs->ifs_ipf_nattable_max > ifs->ifs_ipf_nattable_sz) { 2549f4b3ec61Sdh155122 ifs->ifs_ipf_nattable_max = ifs->ifs_nat_stats.ns_inuse - 100; 2550ab25eeb5Syz155240 printf("ipf_nattable_max reduced to %d\n", 2551f4b3ec61Sdh155122 ifs->ifs_ipf_nattable_max); 2552ab25eeb5Syz155240 } 2553ab25eeb5Syz155240 return NULL; 2554ab25eeb5Syz155240 } 2555ab25eeb5Syz155240 2556ab25eeb5Syz155240 if (flags & IPN_TCPUDP) { 2557ab25eeb5Syz155240 tcp = fin->fin_dp; 2558ab25eeb5Syz155240 ni.nai_sport = htons(fin->fin_sport); 2559ab25eeb5Syz155240 ni.nai_dport = htons(fin->fin_dport); 2560ab25eeb5Syz155240 } else if (flags & IPN_ICMPQUERY) { 2561ab25eeb5Syz155240 /* 2562ab25eeb5Syz155240 * In the ICMP query NAT code, we translate the ICMP id fields 2563ab25eeb5Syz155240 * to make them unique. This is indepedent of the ICMP type 2564ab25eeb5Syz155240 * (e.g. in the unlikely event that a host sends an echo and 2565ab25eeb5Syz155240 * an tstamp request with the same id, both packets will have 2566ab25eeb5Syz155240 * their ip address/id field changed in the same way). 2567ab25eeb5Syz155240 */ 2568ab25eeb5Syz155240 /* The icmp_id field is used by the sender to identify the 2569ab25eeb5Syz155240 * process making the icmp request. (the receiver justs 2570ab25eeb5Syz155240 * copies it back in its response). So, it closely matches 2571ab25eeb5Syz155240 * the concept of source port. We overlay sport, so we can 2572ab25eeb5Syz155240 * maximally reuse the existing code. 2573ab25eeb5Syz155240 */ 2574ab25eeb5Syz155240 ni.nai_sport = ((icmphdr_t *)fin->fin_dp)->icmp_id; 2575ab25eeb5Syz155240 ni.nai_dport = ni.nai_sport; 2576ab25eeb5Syz155240 } 2577ab25eeb5Syz155240 2578ab25eeb5Syz155240 bzero((char *)nat, sizeof(*nat)); 2579ab25eeb5Syz155240 nat->nat_flags = flags; 2580f4b3ec61Sdh155122 nat->nat_redir = np->in_redir; 2581ab25eeb5Syz155240 2582ab25eeb5Syz155240 if ((flags & NAT_SLAVE) == 0) { 2583f4b3ec61Sdh155122 MUTEX_ENTER(&ifs->ifs_ipf_nat_new); 2584ab25eeb5Syz155240 } 2585ab25eeb5Syz155240 2586ab25eeb5Syz155240 /* 2587ab25eeb5Syz155240 * Search the current table for a match. 2588ab25eeb5Syz155240 */ 2589ab25eeb5Syz155240 if (direction == NAT_OUTBOUND) { 2590ab25eeb5Syz155240 /* 2591ab25eeb5Syz155240 * We can now arrange to call this for the same connection 2592ab25eeb5Syz155240 * because ipf_nat_new doesn't protect the code path into 2593ab25eeb5Syz155240 * this function. 2594ab25eeb5Syz155240 */ 2595ab25eeb5Syz155240 natl = nat_outlookup(fin, nflags, (u_int)fin->fin_p, 2596ab25eeb5Syz155240 fin->fin_src, fin->fin_dst); 2597ab25eeb5Syz155240 if (natl != NULL) { 2598dcf3e898Sjojemann KFREE(nat); 2599ab25eeb5Syz155240 nat = natl; 2600ab25eeb5Syz155240 goto done; 2601ab25eeb5Syz155240 } 2602ab25eeb5Syz155240 2603ab25eeb5Syz155240 move = nat_newmap(fin, nat, &ni); 2604ab25eeb5Syz155240 if (move == -1) 2605ab25eeb5Syz155240 goto badnat; 2606ab25eeb5Syz155240 2607ab25eeb5Syz155240 np = ni.nai_np; 2608ab25eeb5Syz155240 } else { 2609ab25eeb5Syz155240 /* 2610ab25eeb5Syz155240 * NAT_INBOUND is used only for redirects rules 2611ab25eeb5Syz155240 */ 2612ab25eeb5Syz155240 natl = nat_inlookup(fin, nflags, (u_int)fin->fin_p, 2613ab25eeb5Syz155240 fin->fin_src, fin->fin_dst); 2614ab25eeb5Syz155240 if (natl != NULL) { 2615dcf3e898Sjojemann KFREE(nat); 2616ab25eeb5Syz155240 nat = natl; 2617ab25eeb5Syz155240 goto done; 2618ab25eeb5Syz155240 } 2619ab25eeb5Syz155240 2620ab25eeb5Syz155240 move = nat_newrdr(fin, nat, &ni); 2621ab25eeb5Syz155240 if (move == -1) 2622ab25eeb5Syz155240 goto badnat; 2623ab25eeb5Syz155240 2624ab25eeb5Syz155240 np = ni.nai_np; 2625ab25eeb5Syz155240 } 2626ab25eeb5Syz155240 2627ab25eeb5Syz155240 if ((move == 1) && (np->in_flags & IPN_ROUNDR)) { 2628ab25eeb5Syz155240 if (np->in_redir == NAT_REDIRECT) { 2629ab25eeb5Syz155240 nat_delrdr(np); 2630f4b3ec61Sdh155122 nat_addrdr(np, ifs); 2631ab25eeb5Syz155240 } else if (np->in_redir == NAT_MAP) { 2632ab25eeb5Syz155240 nat_delnat(np); 2633f4b3ec61Sdh155122 nat_addnat(np, ifs); 2634ab25eeb5Syz155240 } 2635ab25eeb5Syz155240 } 2636ab25eeb5Syz155240 2637ab25eeb5Syz155240 if (nat_finalise(fin, nat, &ni, tcp, natsave, direction) == -1) { 2638ab25eeb5Syz155240 goto badnat; 2639ab25eeb5Syz155240 } 26403c50f6d6San207044 26413c50f6d6San207044 nat_calc_chksum_diffs(nat); 26423c50f6d6San207044 2643ab25eeb5Syz155240 if (flags & SI_WILDP) 2644f4b3ec61Sdh155122 ifs->ifs_nat_stats.ns_wilds++; 2645ab25eeb5Syz155240 goto done; 2646ab25eeb5Syz155240 badnat: 2647f4b3ec61Sdh155122 ifs->ifs_nat_stats.ns_badnat++; 2648ab25eeb5Syz155240 if ((hm = nat->nat_hm) != NULL) 264990b0a856Sjojemann fr_hostmapdel(&hm); 2650ab25eeb5Syz155240 KFREE(nat); 2651ab25eeb5Syz155240 nat = NULL; 2652ab25eeb5Syz155240 done: 2653ab25eeb5Syz155240 if ((flags & NAT_SLAVE) == 0) { 2654f4b3ec61Sdh155122 MUTEX_EXIT(&ifs->ifs_ipf_nat_new); 2655ab25eeb5Syz155240 } 2656ab25eeb5Syz155240 return nat; 2657ab25eeb5Syz155240 } 2658ab25eeb5Syz155240 2659ab25eeb5Syz155240 2660ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */ 2661ab25eeb5Syz155240 /* Function: nat_finalise */ 2662ab25eeb5Syz155240 /* Returns: int - 0 == sucess, -1 == failure */ 2663ab25eeb5Syz155240 /* Parameters: fin(I) - pointer to packet information */ 2664ab25eeb5Syz155240 /* nat(I) - pointer to NAT entry */ 2665ab25eeb5Syz155240 /* ni(I) - pointer to structure with misc. information needed */ 2666ab25eeb5Syz155240 /* to create new NAT entry. */ 2667ab25eeb5Syz155240 /* Write Lock: ipf_nat */ 2668ab25eeb5Syz155240 /* */ 2669ab25eeb5Syz155240 /* This is the tail end of constructing a new NAT entry and is the same */ 2670ab25eeb5Syz155240 /* for both IPv4 and IPv6. */ 2671ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */ 2672ab25eeb5Syz155240 /*ARGSUSED*/ 2673ab25eeb5Syz155240 static INLINE int nat_finalise(fin, nat, ni, tcp, natsave, direction) 2674ab25eeb5Syz155240 fr_info_t *fin; 2675ab25eeb5Syz155240 nat_t *nat; 2676ab25eeb5Syz155240 natinfo_t *ni; 2677ab25eeb5Syz155240 tcphdr_t *tcp; 2678ab25eeb5Syz155240 nat_t **natsave; 2679ab25eeb5Syz155240 int direction; 2680ab25eeb5Syz155240 { 2681ab25eeb5Syz155240 frentry_t *fr; 2682ab25eeb5Syz155240 ipnat_t *np; 2683f4b3ec61Sdh155122 ipf_stack_t *ifs = fin->fin_ifs; 2684ab25eeb5Syz155240 2685ab25eeb5Syz155240 np = ni->nai_np; 2686ab25eeb5Syz155240 2687381a2a9aSdr146992 COPYIFNAME(fin->fin_ifp, nat->nat_ifnames[0], fin->fin_v); 2688381a2a9aSdr146992 2689ab25eeb5Syz155240 #ifdef IPFILTER_SYNC 2690ab25eeb5Syz155240 if ((nat->nat_flags & SI_CLONE) == 0) 2691ab25eeb5Syz155240 nat->nat_sync = ipfsync_new(SMC_NAT, fin, nat); 2692ab25eeb5Syz155240 #endif 2693ab25eeb5Syz155240 2694ab25eeb5Syz155240 nat->nat_me = natsave; 2695ab25eeb5Syz155240 nat->nat_dir = direction; 2696e6c6c1faSyz155240 nat->nat_ifps[0] = np->in_ifps[0]; 2697e6c6c1faSyz155240 nat->nat_ifps[1] = np->in_ifps[1]; 2698ab25eeb5Syz155240 nat->nat_ptr = np; 2699ab25eeb5Syz155240 nat->nat_p = fin->fin_p; 2700*d6c23f6fSyx160601 nat->nat_v = fin->fin_v; 2701ab25eeb5Syz155240 nat->nat_mssclamp = np->in_mssclamp; 2702ab25eeb5Syz155240 fr = fin->fin_fr; 2703ab25eeb5Syz155240 nat->nat_fr = fr; 2704ab25eeb5Syz155240 2705ab25eeb5Syz155240 if ((np->in_apr != NULL) && ((ni->nai_flags & NAT_SLAVE) == 0)) 2706ab25eeb5Syz155240 if (appr_new(fin, nat) == -1) 2707ab25eeb5Syz155240 return -1; 2708ab25eeb5Syz155240 2709f4b3ec61Sdh155122 if (nat_insert(nat, fin->fin_rev, ifs) == 0) { 2710f4b3ec61Sdh155122 if (ifs->ifs_nat_logging) 2711f4b3ec61Sdh155122 nat_log(nat, (u_int)np->in_redir, ifs); 2712ab25eeb5Syz155240 np->in_use++; 2713ab25eeb5Syz155240 if (fr != NULL) { 2714ab25eeb5Syz155240 MUTEX_ENTER(&fr->fr_lock); 2715ab25eeb5Syz155240 fr->fr_ref++; 2716ab25eeb5Syz155240 MUTEX_EXIT(&fr->fr_lock); 2717ab25eeb5Syz155240 } 2718ab25eeb5Syz155240 return 0; 2719ab25eeb5Syz155240 } 2720ab25eeb5Syz155240 2721ab25eeb5Syz155240 /* 2722ab25eeb5Syz155240 * nat_insert failed, so cleanup time... 2723ab25eeb5Syz155240 */ 2724ab25eeb5Syz155240 return -1; 2725ab25eeb5Syz155240 } 2726ab25eeb5Syz155240 2727ab25eeb5Syz155240 2728ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */ 2729ab25eeb5Syz155240 /* Function: nat_insert */ 2730ab25eeb5Syz155240 /* Returns: int - 0 == sucess, -1 == failure */ 2731ab25eeb5Syz155240 /* Parameters: nat(I) - pointer to NAT structure */ 2732ab25eeb5Syz155240 /* rev(I) - flag indicating forward/reverse direction of packet */ 2733ab25eeb5Syz155240 /* Write Lock: ipf_nat */ 2734ab25eeb5Syz155240 /* */ 2735ab25eeb5Syz155240 /* Insert a NAT entry into the hash tables for searching and add it to the */ 2736ab25eeb5Syz155240 /* list of active NAT entries. Adjust global counters when complete. */ 2737ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */ 2738f4b3ec61Sdh155122 int nat_insert(nat, rev, ifs) 2739ab25eeb5Syz155240 nat_t *nat; 2740ab25eeb5Syz155240 int rev; 2741f4b3ec61Sdh155122 ipf_stack_t *ifs; 2742ab25eeb5Syz155240 { 2743ab25eeb5Syz155240 u_int hv1, hv2; 2744ab25eeb5Syz155240 nat_t **natp; 2745ab25eeb5Syz155240 2746ab25eeb5Syz155240 /* 2747ab25eeb5Syz155240 * Try and return an error as early as possible, so calculate the hash 2748ab25eeb5Syz155240 * entry numbers first and then proceed. 2749ab25eeb5Syz155240 */ 2750ab25eeb5Syz155240 if ((nat->nat_flags & (SI_W_SPORT|SI_W_DPORT)) == 0) { 2751ab25eeb5Syz155240 hv1 = NAT_HASH_FN(nat->nat_inip.s_addr, nat->nat_inport, 2752ab25eeb5Syz155240 0xffffffff); 2753ab25eeb5Syz155240 hv1 = NAT_HASH_FN(nat->nat_oip.s_addr, hv1 + nat->nat_oport, 2754f4b3ec61Sdh155122 ifs->ifs_ipf_nattable_sz); 2755ab25eeb5Syz155240 hv2 = NAT_HASH_FN(nat->nat_outip.s_addr, nat->nat_outport, 2756ab25eeb5Syz155240 0xffffffff); 2757ab25eeb5Syz155240 hv2 = NAT_HASH_FN(nat->nat_oip.s_addr, hv2 + nat->nat_oport, 2758f4b3ec61Sdh155122 ifs->ifs_ipf_nattable_sz); 2759ab25eeb5Syz155240 } else { 2760ab25eeb5Syz155240 hv1 = NAT_HASH_FN(nat->nat_inip.s_addr, 0, 0xffffffff); 2761f4b3ec61Sdh155122 hv1 = NAT_HASH_FN(nat->nat_oip.s_addr, hv1, 2762f4b3ec61Sdh155122 ifs->ifs_ipf_nattable_sz); 2763ab25eeb5Syz155240 hv2 = NAT_HASH_FN(nat->nat_outip.s_addr, 0, 0xffffffff); 2764f4b3ec61Sdh155122 hv2 = NAT_HASH_FN(nat->nat_oip.s_addr, hv2, 2765f4b3ec61Sdh155122 ifs->ifs_ipf_nattable_sz); 2766ab25eeb5Syz155240 } 2767ab25eeb5Syz155240 2768f4b3ec61Sdh155122 if (ifs->ifs_nat_stats.ns_bucketlen[0][hv1] >= ifs->ifs_fr_nat_maxbucket || 2769f4b3ec61Sdh155122 ifs->ifs_nat_stats.ns_bucketlen[1][hv2] >= ifs->ifs_fr_nat_maxbucket) { 2770ab25eeb5Syz155240 return -1; 2771ab25eeb5Syz155240 } 2772ab25eeb5Syz155240 2773ab25eeb5Syz155240 nat->nat_hv[0] = hv1; 2774ab25eeb5Syz155240 nat->nat_hv[1] = hv2; 2775ab25eeb5Syz155240 2776ab25eeb5Syz155240 MUTEX_INIT(&nat->nat_lock, "nat entry lock"); 2777ab25eeb5Syz155240 2778ab25eeb5Syz155240 nat->nat_rev = rev; 2779ab25eeb5Syz155240 nat->nat_ref = 1; 2780ab25eeb5Syz155240 nat->nat_bytes[0] = 0; 2781ab25eeb5Syz155240 nat->nat_pkts[0] = 0; 2782ab25eeb5Syz155240 nat->nat_bytes[1] = 0; 2783ab25eeb5Syz155240 nat->nat_pkts[1] = 0; 2784ab25eeb5Syz155240 2785ab25eeb5Syz155240 nat->nat_ifnames[0][LIFNAMSIZ - 1] = '\0'; 2786f4b3ec61Sdh155122 nat->nat_ifps[0] = fr_resolvenic(nat->nat_ifnames[0], 4, ifs); 2787ab25eeb5Syz155240 2788ab25eeb5Syz155240 if (nat->nat_ifnames[1][0] !='\0') { 2789ab25eeb5Syz155240 nat->nat_ifnames[1][LIFNAMSIZ - 1] = '\0'; 2790f4b3ec61Sdh155122 nat->nat_ifps[1] = fr_resolvenic(nat->nat_ifnames[1], 4, ifs); 2791ab25eeb5Syz155240 } else { 2792ab25eeb5Syz155240 (void) strncpy(nat->nat_ifnames[1], nat->nat_ifnames[0], 2793ab25eeb5Syz155240 LIFNAMSIZ); 2794ab25eeb5Syz155240 nat->nat_ifnames[1][LIFNAMSIZ - 1] = '\0'; 2795ab25eeb5Syz155240 nat->nat_ifps[1] = nat->nat_ifps[0]; 2796ab25eeb5Syz155240 } 2797ab25eeb5Syz155240 2798f4b3ec61Sdh155122 nat->nat_next = ifs->ifs_nat_instances; 2799f4b3ec61Sdh155122 nat->nat_pnext = &ifs->ifs_nat_instances; 2800f4b3ec61Sdh155122 if (ifs->ifs_nat_instances) 2801f4b3ec61Sdh155122 ifs->ifs_nat_instances->nat_pnext = &nat->nat_next; 2802f4b3ec61Sdh155122 ifs->ifs_nat_instances = nat; 2803ab25eeb5Syz155240 2804f4b3ec61Sdh155122 natp = &ifs->ifs_nat_table[0][hv1]; 2805ab25eeb5Syz155240 if (*natp) 2806ab25eeb5Syz155240 (*natp)->nat_phnext[0] = &nat->nat_hnext[0]; 2807ab25eeb5Syz155240 nat->nat_phnext[0] = natp; 2808ab25eeb5Syz155240 nat->nat_hnext[0] = *natp; 2809ab25eeb5Syz155240 *natp = nat; 2810f4b3ec61Sdh155122 ifs->ifs_nat_stats.ns_bucketlen[0][hv1]++; 2811ab25eeb5Syz155240 2812f4b3ec61Sdh155122 natp = &ifs->ifs_nat_table[1][hv2]; 2813ab25eeb5Syz155240 if (*natp) 2814ab25eeb5Syz155240 (*natp)->nat_phnext[1] = &nat->nat_hnext[1]; 2815ab25eeb5Syz155240 nat->nat_phnext[1] = natp; 2816ab25eeb5Syz155240 nat->nat_hnext[1] = *natp; 2817ab25eeb5Syz155240 *natp = nat; 2818f4b3ec61Sdh155122 ifs->ifs_nat_stats.ns_bucketlen[1][hv2]++; 2819ab25eeb5Syz155240 2820f4b3ec61Sdh155122 fr_setnatqueue(nat, rev, ifs); 2821ab25eeb5Syz155240 2822f4b3ec61Sdh155122 ifs->ifs_nat_stats.ns_added++; 2823f4b3ec61Sdh155122 ifs->ifs_nat_stats.ns_inuse++; 2824ab25eeb5Syz155240 return 0; 2825ab25eeb5Syz155240 } 2826ab25eeb5Syz155240 2827ab25eeb5Syz155240 2828ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */ 2829ab25eeb5Syz155240 /* Function: nat_icmperrorlookup */ 2830ab25eeb5Syz155240 /* Returns: nat_t* - point to matching NAT structure */ 2831ab25eeb5Syz155240 /* Parameters: fin(I) - pointer to packet information */ 2832ab25eeb5Syz155240 /* dir(I) - direction of packet (in/out) */ 2833ab25eeb5Syz155240 /* */ 2834ab25eeb5Syz155240 /* Check if the ICMP error message is related to an existing TCP, UDP or */ 2835ab25eeb5Syz155240 /* ICMP query nat entry. It is assumed that the packet is already of the */ 2836ab25eeb5Syz155240 /* the required length. */ 2837ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */ 2838ab25eeb5Syz155240 nat_t *nat_icmperrorlookup(fin, dir) 2839ab25eeb5Syz155240 fr_info_t *fin; 2840ab25eeb5Syz155240 int dir; 2841ab25eeb5Syz155240 { 2842ab25eeb5Syz155240 int flags = 0, minlen; 2843ab25eeb5Syz155240 icmphdr_t *orgicmp; 2844ab25eeb5Syz155240 tcphdr_t *tcp = NULL; 2845ab25eeb5Syz155240 u_short data[2]; 2846ab25eeb5Syz155240 nat_t *nat; 2847ab25eeb5Syz155240 ip_t *oip; 2848ab25eeb5Syz155240 u_int p; 2849ab25eeb5Syz155240 2850ab25eeb5Syz155240 /* 2851ab25eeb5Syz155240 * Does it at least have the return (basic) IP header ? 2852ab25eeb5Syz155240 * Only a basic IP header (no options) should be with an ICMP error 2853ab25eeb5Syz155240 * header. Also, if it's not an error type, then return. 2854ab25eeb5Syz155240 */ 2855ab25eeb5Syz155240 if ((fin->fin_hlen != sizeof(ip_t)) || !(fin->fin_flx & FI_ICMPERR)) 2856ab25eeb5Syz155240 return NULL; 2857ab25eeb5Syz155240 2858ab25eeb5Syz155240 /* 2859ab25eeb5Syz155240 * Check packet size 2860ab25eeb5Syz155240 */ 2861ab25eeb5Syz155240 oip = (ip_t *)((char *)fin->fin_dp + 8); 2862ab25eeb5Syz155240 minlen = IP_HL(oip) << 2; 2863ab25eeb5Syz155240 if ((minlen < sizeof(ip_t)) || 2864ab25eeb5Syz155240 (fin->fin_plen < ICMPERR_IPICMPHLEN + minlen)) 2865ab25eeb5Syz155240 return NULL; 2866ab25eeb5Syz155240 /* 2867ab25eeb5Syz155240 * Is the buffer big enough for all of it ? It's the size of the IP 2868ab25eeb5Syz155240 * header claimed in the encapsulated part which is of concern. It 2869ab25eeb5Syz155240 * may be too big to be in this buffer but not so big that it's 2870ab25eeb5Syz155240 * outside the ICMP packet, leading to TCP deref's causing problems. 2871ab25eeb5Syz155240 * This is possible because we don't know how big oip_hl is when we 2872ab25eeb5Syz155240 * do the pullup early in fr_check() and thus can't gaurantee it is 2873ab25eeb5Syz155240 * all here now. 2874ab25eeb5Syz155240 */ 2875ab25eeb5Syz155240 #ifdef _KERNEL 2876ab25eeb5Syz155240 { 2877ab25eeb5Syz155240 mb_t *m; 2878ab25eeb5Syz155240 2879ab25eeb5Syz155240 m = fin->fin_m; 2880ab25eeb5Syz155240 # if defined(MENTAT) 2881ab25eeb5Syz155240 if ((char *)oip + fin->fin_dlen - ICMPERR_ICMPHLEN > (char *)m->b_wptr) 2882ab25eeb5Syz155240 return NULL; 2883ab25eeb5Syz155240 # else 2884ab25eeb5Syz155240 if ((char *)oip + fin->fin_dlen - ICMPERR_ICMPHLEN > 2885ab25eeb5Syz155240 (char *)fin->fin_ip + M_LEN(m)) 2886ab25eeb5Syz155240 return NULL; 2887ab25eeb5Syz155240 # endif 2888ab25eeb5Syz155240 } 2889ab25eeb5Syz155240 #endif 2890ab25eeb5Syz155240 2891ab25eeb5Syz155240 if (fin->fin_daddr != oip->ip_src.s_addr) 2892ab25eeb5Syz155240 return NULL; 2893ab25eeb5Syz155240 2894ab25eeb5Syz155240 p = oip->ip_p; 2895ab25eeb5Syz155240 if (p == IPPROTO_TCP) 2896ab25eeb5Syz155240 flags = IPN_TCP; 2897ab25eeb5Syz155240 else if (p == IPPROTO_UDP) 2898ab25eeb5Syz155240 flags = IPN_UDP; 2899ab25eeb5Syz155240 else if (p == IPPROTO_ICMP) { 2900ab25eeb5Syz155240 orgicmp = (icmphdr_t *)((char *)oip + (IP_HL(oip) << 2)); 2901ab25eeb5Syz155240 2902ab25eeb5Syz155240 /* see if this is related to an ICMP query */ 2903ab25eeb5Syz155240 if (nat_icmpquerytype4(orgicmp->icmp_type)) { 2904ab25eeb5Syz155240 data[0] = fin->fin_data[0]; 2905ab25eeb5Syz155240 data[1] = fin->fin_data[1]; 2906ab25eeb5Syz155240 fin->fin_data[0] = 0; 2907ab25eeb5Syz155240 fin->fin_data[1] = orgicmp->icmp_id; 2908ab25eeb5Syz155240 2909ab25eeb5Syz155240 flags = IPN_ICMPERR|IPN_ICMPQUERY; 2910ab25eeb5Syz155240 /* 2911ab25eeb5Syz155240 * NOTE : dir refers to the direction of the original 2912ab25eeb5Syz155240 * ip packet. By definition the icmp error 2913ab25eeb5Syz155240 * message flows in the opposite direction. 2914ab25eeb5Syz155240 */ 2915ab25eeb5Syz155240 if (dir == NAT_INBOUND) 2916ab25eeb5Syz155240 nat = nat_inlookup(fin, flags, p, oip->ip_dst, 2917ab25eeb5Syz155240 oip->ip_src); 2918ab25eeb5Syz155240 else 2919ab25eeb5Syz155240 nat = nat_outlookup(fin, flags, p, oip->ip_dst, 2920ab25eeb5Syz155240 oip->ip_src); 2921ab25eeb5Syz155240 fin->fin_data[0] = data[0]; 2922ab25eeb5Syz155240 fin->fin_data[1] = data[1]; 2923ab25eeb5Syz155240 return nat; 2924ab25eeb5Syz155240 } 2925ab25eeb5Syz155240 } 2926ab25eeb5Syz155240 2927ab25eeb5Syz155240 if (flags & IPN_TCPUDP) { 2928ab25eeb5Syz155240 minlen += 8; /* + 64bits of data to get ports */ 2929ab25eeb5Syz155240 if (fin->fin_plen < ICMPERR_IPICMPHLEN + minlen) 2930ab25eeb5Syz155240 return NULL; 2931ab25eeb5Syz155240 2932ab25eeb5Syz155240 data[0] = fin->fin_data[0]; 2933ab25eeb5Syz155240 data[1] = fin->fin_data[1]; 2934ab25eeb5Syz155240 tcp = (tcphdr_t *)((char *)oip + (IP_HL(oip) << 2)); 2935ab25eeb5Syz155240 fin->fin_data[0] = ntohs(tcp->th_dport); 2936ab25eeb5Syz155240 fin->fin_data[1] = ntohs(tcp->th_sport); 2937ab25eeb5Syz155240 2938ab25eeb5Syz155240 if (dir == NAT_INBOUND) { 2939ab25eeb5Syz155240 nat = nat_inlookup(fin, flags, p, oip->ip_dst, 2940ab25eeb5Syz155240 oip->ip_src); 2941ab25eeb5Syz155240 } else { 2942ab25eeb5Syz155240 nat = nat_outlookup(fin, flags, p, oip->ip_dst, 2943ab25eeb5Syz155240 oip->ip_src); 2944ab25eeb5Syz155240 } 2945ab25eeb5Syz155240 fin->fin_data[0] = data[0]; 2946ab25eeb5Syz155240 fin->fin_data[1] = data[1]; 2947ab25eeb5Syz155240 return nat; 2948ab25eeb5Syz155240 } 2949ab25eeb5Syz155240 if (dir == NAT_INBOUND) 2950ab25eeb5Syz155240 return nat_inlookup(fin, 0, p, oip->ip_dst, oip->ip_src); 2951ab25eeb5Syz155240 else 2952ab25eeb5Syz155240 return nat_outlookup(fin, 0, p, oip->ip_dst, oip->ip_src); 2953ab25eeb5Syz155240 } 2954ab25eeb5Syz155240 2955ab25eeb5Syz155240 2956ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */ 2957ab25eeb5Syz155240 /* Function: nat_icmperror */ 2958ab25eeb5Syz155240 /* Returns: nat_t* - point to matching NAT structure */ 2959ab25eeb5Syz155240 /* Parameters: fin(I) - pointer to packet information */ 2960ab25eeb5Syz155240 /* nflags(I) - NAT flags for this packet */ 2961ab25eeb5Syz155240 /* dir(I) - direction of packet (in/out) */ 2962ab25eeb5Syz155240 /* */ 2963ab25eeb5Syz155240 /* Fix up an ICMP packet which is an error message for an existing NAT */ 2964ab25eeb5Syz155240 /* session. This will correct both packet header data and checksums. */ 2965ab25eeb5Syz155240 /* */ 2966ab25eeb5Syz155240 /* This should *ONLY* be used for incoming ICMP error packets to make sure */ 2967ab25eeb5Syz155240 /* a NAT'd ICMP packet gets correctly recognised. */ 2968ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */ 2969ab25eeb5Syz155240 nat_t *nat_icmperror(fin, nflags, dir) 2970ab25eeb5Syz155240 fr_info_t *fin; 2971ab25eeb5Syz155240 u_int *nflags; 2972ab25eeb5Syz155240 int dir; 2973ab25eeb5Syz155240 { 29745142ed1fSjojemann u_32_t sum1, sum2, sumd, psum1, psum2, psumd, sumd2; 2975ab25eeb5Syz155240 struct in_addr in; 29765142ed1fSjojemann icmphdr_t *icmp, *orgicmp; 29775142ed1fSjojemann int dlen; 29785142ed1fSjojemann udphdr_t *udp; 2979ab25eeb5Syz155240 tcphdr_t *tcp; 2980ab25eeb5Syz155240 nat_t *nat; 2981ab25eeb5Syz155240 ip_t *oip; 2982ab25eeb5Syz155240 if ((fin->fin_flx & (FI_SHORT|FI_FRAGBODY))) 2983ab25eeb5Syz155240 return NULL; 29845142ed1fSjojemann 2985ab25eeb5Syz155240 /* 29865142ed1fSjojemann * nat_icmperrorlookup() looks up nat entry associated with the 29875142ed1fSjojemann * offending IP packet and returns pointer to the entry, or NULL 29885142ed1fSjojemann * if packet wasn't natted or for `defective' packets. 2989ab25eeb5Syz155240 */ 29905142ed1fSjojemann 2991ab25eeb5Syz155240 if ((fin->fin_v != 4) || !(nat = nat_icmperrorlookup(fin, dir))) 2992ab25eeb5Syz155240 return NULL; 2993ab25eeb5Syz155240 2994ab25eeb5Syz155240 sumd2 = 0; 2995ab25eeb5Syz155240 *nflags = IPN_ICMPERR; 2996ab25eeb5Syz155240 icmp = fin->fin_dp; 2997ab25eeb5Syz155240 oip = (ip_t *)&icmp->icmp_ip; 29985142ed1fSjojemann udp = (udphdr_t *)((((char *)oip) + (IP_HL(oip) << 2))); 29995142ed1fSjojemann tcp = (tcphdr_t *)udp; 30005142ed1fSjojemann dlen = fin->fin_plen - ((char *)udp - (char *)fin->fin_ip); 3001ab25eeb5Syz155240 3002ab25eeb5Syz155240 /* 3003ab25eeb5Syz155240 * Need to adjust ICMP header to include the real IP#'s and 30045142ed1fSjojemann * port #'s. There are three steps required. 3005ab25eeb5Syz155240 * 30065142ed1fSjojemann * Step 1 30075142ed1fSjojemann * Fix the IP addresses in the offending IP packet and update 30085142ed1fSjojemann * ip header checksum to compensate for the change. 30095142ed1fSjojemann * 30105142ed1fSjojemann * No update needed here for icmp_cksum because the ICMP checksum 30115142ed1fSjojemann * is calculated over the complete ICMP packet, which includes the 30125142ed1fSjojemann * changed oip IP addresses and oip->ip_sum. These two changes 30135142ed1fSjojemann * cancel each other out (if the delta for the IP address is x, 30145142ed1fSjojemann * then the delta for ip_sum is minus x). 3015ab25eeb5Syz155240 */ 3016ab25eeb5Syz155240 3017ab25eeb5Syz155240 if (oip->ip_dst.s_addr == nat->nat_oip.s_addr) { 3018ab25eeb5Syz155240 sum1 = LONG_SUM(ntohl(oip->ip_src.s_addr)); 3019ab25eeb5Syz155240 in = nat->nat_inip; 3020ab25eeb5Syz155240 oip->ip_src = in; 3021ab25eeb5Syz155240 } else { 3022ab25eeb5Syz155240 sum1 = LONG_SUM(ntohl(oip->ip_dst.s_addr)); 3023ab25eeb5Syz155240 in = nat->nat_outip; 3024ab25eeb5Syz155240 oip->ip_dst = in; 3025ab25eeb5Syz155240 } 3026ab25eeb5Syz155240 3027ab25eeb5Syz155240 sum2 = LONG_SUM(ntohl(in.s_addr)); 3028ab25eeb5Syz155240 CALC_SUMD(sum1, sum2, sumd); 3029ab25eeb5Syz155240 fix_datacksum(&oip->ip_sum, sumd); 3030ab25eeb5Syz155240 3031ab25eeb5Syz155240 /* 30325142ed1fSjojemann * Step 2 30335142ed1fSjojemann * Perform other adjustments based on protocol of offending packet. 3034ab25eeb5Syz155240 */ 30355142ed1fSjojemann 30365142ed1fSjojemann switch (oip->ip_p) { 30375142ed1fSjojemann case IPPROTO_TCP : 30385142ed1fSjojemann case IPPROTO_UDP : 3039ab25eeb5Syz155240 3040ab25eeb5Syz155240 /* 30415142ed1fSjojemann * For offending TCP/UDP IP packets, translate the ports 30425142ed1fSjojemann * based on the NAT specification. 3043ab25eeb5Syz155240 * 3044ab25eeb5Syz155240 * Advance notice : Now it becomes complicated :-) 3045ab25eeb5Syz155240 * 30465142ed1fSjojemann * Since the port and IP addresse fields are both part 30475142ed1fSjojemann * of the TCP/UDP checksum of the offending IP packet, 30485142ed1fSjojemann * we need to adjust that checksum as well. 3049ab25eeb5Syz155240 * 30505142ed1fSjojemann * To further complicate things, the TCP/UDP checksum 30515142ed1fSjojemann * may not be present. We must check to see if the 30525142ed1fSjojemann * length of the data portion is big enough to hold 30535142ed1fSjojemann * the checksum. In the UDP case, a test to determine 30545142ed1fSjojemann * if the checksum is even set is also required. 30555142ed1fSjojemann * 30565142ed1fSjojemann * Any changes to an IP address, port or checksum within 30575142ed1fSjojemann * the ICMP packet requires a change to icmp_cksum. 30585142ed1fSjojemann * 30595142ed1fSjojemann * Be extremely careful here ... The change is dependent 30605142ed1fSjojemann * upon whether or not the TCP/UPD checksum is present. 30615142ed1fSjojemann * 30625142ed1fSjojemann * If TCP/UPD checksum is present, the icmp_cksum must 30635142ed1fSjojemann * compensate for checksum modification resulting from 30645142ed1fSjojemann * IP address change only. Port change and resulting 30655142ed1fSjojemann * data checksum adjustments cancel each other out. 30665142ed1fSjojemann * 30675142ed1fSjojemann * If TCP/UDP checksum is not present, icmp_cksum must 30685142ed1fSjojemann * compensate for port change only. The IP address 30695142ed1fSjojemann * change does not modify anything else in this case. 3070ab25eeb5Syz155240 */ 3071ab25eeb5Syz155240 30725142ed1fSjojemann psum1 = 0; 30735142ed1fSjojemann psum2 = 0; 30745142ed1fSjojemann psumd = 0; 30755142ed1fSjojemann 30765142ed1fSjojemann if ((tcp->th_dport == nat->nat_oport) && 30775142ed1fSjojemann (tcp->th_sport != nat->nat_inport)) { 30785142ed1fSjojemann 30795142ed1fSjojemann /* 30805142ed1fSjojemann * Translate the source port. 30815142ed1fSjojemann */ 30825142ed1fSjojemann 30835142ed1fSjojemann psum1 = ntohs(tcp->th_sport); 30845142ed1fSjojemann psum2 = ntohs(nat->nat_inport); 30855142ed1fSjojemann tcp->th_sport = nat->nat_inport; 30865142ed1fSjojemann 30875142ed1fSjojemann } else if ((tcp->th_sport == nat->nat_oport) && 30885142ed1fSjojemann (tcp->th_dport != nat->nat_outport)) { 30895142ed1fSjojemann 30905142ed1fSjojemann /* 30915142ed1fSjojemann * Translate the destination port. 30925142ed1fSjojemann */ 30935142ed1fSjojemann 30945142ed1fSjojemann psum1 = ntohs(tcp->th_dport); 30955142ed1fSjojemann psum2 = ntohs(nat->nat_outport); 30965142ed1fSjojemann tcp->th_dport = nat->nat_outport; 3097ab25eeb5Syz155240 } 3098ab25eeb5Syz155240 30995142ed1fSjojemann if ((oip->ip_p == IPPROTO_TCP) && (dlen >= 18)) { 3100ab25eeb5Syz155240 3101ab25eeb5Syz155240 /* 31025142ed1fSjojemann * TCP checksum present. 3103ab25eeb5Syz155240 * 31045142ed1fSjojemann * Adjust data checksum and icmp checksum to 31055142ed1fSjojemann * compensate for any IP address change. 3106ab25eeb5Syz155240 */ 3107ab25eeb5Syz155240 31085142ed1fSjojemann sum1 = ntohs(tcp->th_sum); 31095142ed1fSjojemann fix_datacksum(&tcp->th_sum, sumd); 31105142ed1fSjojemann sum2 = ntohs(tcp->th_sum); 31115142ed1fSjojemann sumd2 = sumd << 1; 3112ab25eeb5Syz155240 CALC_SUMD(sum1, sum2, sumd); 3113ab25eeb5Syz155240 sumd2 += sumd; 31145142ed1fSjojemann 31155142ed1fSjojemann /* 31165142ed1fSjojemann * Also make data checksum adjustment to 31175142ed1fSjojemann * compensate for any port change. 31185142ed1fSjojemann */ 31195142ed1fSjojemann 31205142ed1fSjojemann if (psum1 != psum2) { 31215142ed1fSjojemann CALC_SUMD(psum1, psum2, psumd); 31225142ed1fSjojemann fix_datacksum(&tcp->th_sum, psumd); 3123ab25eeb5Syz155240 } 3124ab25eeb5Syz155240 31255142ed1fSjojemann } else if ((oip->ip_p == IPPROTO_UDP) && 31265142ed1fSjojemann (dlen >= 8) && (udp->uh_sum != 0)) { 3127ab25eeb5Syz155240 3128ab25eeb5Syz155240 /* 31295142ed1fSjojemann * The UDP checksum is present and set. 31305142ed1fSjojemann * 31315142ed1fSjojemann * Adjust data checksum and icmp checksum to 31325142ed1fSjojemann * compensate for any IP address change. 3133ab25eeb5Syz155240 */ 31345142ed1fSjojemann 31355142ed1fSjojemann sum1 = ntohs(udp->uh_sum); 31365142ed1fSjojemann fix_datacksum(&udp->uh_sum, sumd); 31375142ed1fSjojemann sum2 = ntohs(udp->uh_sum); 31385142ed1fSjojemann sumd2 = sumd << 1; 3139ab25eeb5Syz155240 CALC_SUMD(sum1, sum2, sumd); 3140ab25eeb5Syz155240 sumd2 += sumd; 31415142ed1fSjojemann 31425142ed1fSjojemann /* 31435142ed1fSjojemann * Also make data checksum adjustment to 31445142ed1fSjojemann * compensate for any port change. 31455142ed1fSjojemann */ 31465142ed1fSjojemann 31475142ed1fSjojemann if (psum1 != psum2) { 31485142ed1fSjojemann CALC_SUMD(psum1, psum2, psumd); 31495142ed1fSjojemann fix_datacksum(&udp->uh_sum, psumd); 31505142ed1fSjojemann } 31515142ed1fSjojemann 3152ab25eeb5Syz155240 } else { 3153ab25eeb5Syz155240 3154ab25eeb5Syz155240 /* 31555142ed1fSjojemann * Data checksum was not present. 3156ab25eeb5Syz155240 * 31575142ed1fSjojemann * Compensate for any port change. 3158ab25eeb5Syz155240 */ 3159ab25eeb5Syz155240 31605142ed1fSjojemann CALC_SUMD(psum2, psum1, psumd); 31615142ed1fSjojemann sumd2 += psumd; 3162ab25eeb5Syz155240 } 31635142ed1fSjojemann break; 3164ab25eeb5Syz155240 31655142ed1fSjojemann case IPPROTO_ICMP : 3166ab25eeb5Syz155240 31675142ed1fSjojemann orgicmp = (icmphdr_t *)udp; 3168ab25eeb5Syz155240 31695142ed1fSjojemann if ((nat->nat_dir == NAT_OUTBOUND) && 31705142ed1fSjojemann (orgicmp->icmp_id != nat->nat_inport) && 31715142ed1fSjojemann (dlen >= 8)) { 3172ab25eeb5Syz155240 3173ab25eeb5Syz155240 /* 3174ab25eeb5Syz155240 * Fix ICMP checksum (of the offening ICMP 3175ab25eeb5Syz155240 * query packet) to compensate the change 3176ab25eeb5Syz155240 * in the ICMP id of the offending ICMP 3177ab25eeb5Syz155240 * packet. 3178ab25eeb5Syz155240 * 3179ab25eeb5Syz155240 * Since you modify orgicmp->icmp_id with 3180ab25eeb5Syz155240 * a delta (say x) and you compensate that 3181ab25eeb5Syz155240 * in origicmp->icmp_cksum with a delta 3182ab25eeb5Syz155240 * minus x, you don't have to adjust the 3183ab25eeb5Syz155240 * overall icmp->icmp_cksum 3184ab25eeb5Syz155240 */ 31855142ed1fSjojemann 3186ab25eeb5Syz155240 sum1 = ntohs(orgicmp->icmp_id); 3187ab25eeb5Syz155240 sum2 = ntohs(nat->nat_inport); 3188ab25eeb5Syz155240 CALC_SUMD(sum1, sum2, sumd); 3189ab25eeb5Syz155240 orgicmp->icmp_id = nat->nat_inport; 3190ab25eeb5Syz155240 fix_datacksum(&orgicmp->icmp_cksum, sumd); 31915142ed1fSjojemann 31925142ed1fSjojemann } /* nat_dir can't be NAT_INBOUND for icmp queries */ 31935142ed1fSjojemann 31945142ed1fSjojemann break; 31955142ed1fSjojemann 31965142ed1fSjojemann default : 31975142ed1fSjojemann 31985142ed1fSjojemann break; 31995142ed1fSjojemann 32005142ed1fSjojemann } /* switch (oip->ip_p) */ 32015142ed1fSjojemann 32025142ed1fSjojemann /* 32035142ed1fSjojemann * Step 3 32045142ed1fSjojemann * Make the adjustments to icmp checksum. 32055142ed1fSjojemann */ 32065142ed1fSjojemann 32075142ed1fSjojemann if (sumd2 != 0) { 32085142ed1fSjojemann sumd2 = (sumd2 & 0xffff) + (sumd2 >> 16); 32095142ed1fSjojemann sumd2 = (sumd2 & 0xffff) + (sumd2 >> 16); 3210381a2a9aSdr146992 fix_incksum(&icmp->icmp_cksum, sumd2); 3211ab25eeb5Syz155240 } 3212ab25eeb5Syz155240 return nat; 3213ab25eeb5Syz155240 } 3214ab25eeb5Syz155240 3215ab25eeb5Syz155240 3216ab25eeb5Syz155240 /* 3217ab25eeb5Syz155240 * NB: these lookups don't lock access to the list, it assumed that it has 3218ab25eeb5Syz155240 * already been done! 3219ab25eeb5Syz155240 */ 3220ab25eeb5Syz155240 3221ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */ 3222ab25eeb5Syz155240 /* Function: nat_inlookup */ 3223ab25eeb5Syz155240 /* Returns: nat_t* - NULL == no match, */ 3224ab25eeb5Syz155240 /* else pointer to matching NAT entry */ 3225ab25eeb5Syz155240 /* Parameters: fin(I) - pointer to packet information */ 3226ab25eeb5Syz155240 /* flags(I) - NAT flags for this packet */ 3227ab25eeb5Syz155240 /* p(I) - protocol for this packet */ 3228ab25eeb5Syz155240 /* src(I) - source IP address */ 3229ab25eeb5Syz155240 /* mapdst(I) - destination IP address */ 3230ab25eeb5Syz155240 /* */ 3231ab25eeb5Syz155240 /* Lookup a nat entry based on the mapped destination ip address/port and */ 3232ab25eeb5Syz155240 /* real source address/port. We use this lookup when receiving a packet, */ 3233ab25eeb5Syz155240 /* we're looking for a table entry, based on the destination address. */ 3234ab25eeb5Syz155240 /* */ 3235ab25eeb5Syz155240 /* NOTE: THE PACKET BEING CHECKED (IF FOUND) HAS A MAPPING ALREADY. */ 3236ab25eeb5Syz155240 /* */ 3237ab25eeb5Syz155240 /* NOTE: IT IS ASSUMED THAT ipf_nat IS ONLY HELD WITH A READ LOCK WHEN */ 3238ab25eeb5Syz155240 /* THIS FUNCTION IS CALLED WITH NAT_SEARCH SET IN nflags. */ 3239ab25eeb5Syz155240 /* */ 3240ab25eeb5Syz155240 /* flags -> relevant are IPN_UDP/IPN_TCP/IPN_ICMPQUERY that indicate if */ 3241ab25eeb5Syz155240 /* the packet is of said protocol */ 3242ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */ 3243ab25eeb5Syz155240 nat_t *nat_inlookup(fin, flags, p, src, mapdst) 3244ab25eeb5Syz155240 fr_info_t *fin; 3245ab25eeb5Syz155240 u_int flags, p; 3246ab25eeb5Syz155240 struct in_addr src , mapdst; 3247ab25eeb5Syz155240 { 3248ab25eeb5Syz155240 u_short sport, dport; 3249ab25eeb5Syz155240 ipnat_t *ipn; 3250ab25eeb5Syz155240 u_int sflags; 3251ab25eeb5Syz155240 nat_t *nat; 3252ab25eeb5Syz155240 int nflags; 3253ab25eeb5Syz155240 u_32_t dst; 3254ab25eeb5Syz155240 void *ifp; 3255ab25eeb5Syz155240 u_int hv; 3256f4b3ec61Sdh155122 ipf_stack_t *ifs = fin->fin_ifs; 3257ab25eeb5Syz155240 3258ab25eeb5Syz155240 if (fin != NULL) 3259ab25eeb5Syz155240 ifp = fin->fin_ifp; 3260ab25eeb5Syz155240 else 3261ab25eeb5Syz155240 ifp = NULL; 3262ab25eeb5Syz155240 sport = 0; 3263ab25eeb5Syz155240 dport = 0; 3264ab25eeb5Syz155240 dst = mapdst.s_addr; 3265ab25eeb5Syz155240 sflags = flags & NAT_TCPUDPICMP; 3266ab25eeb5Syz155240 3267ab25eeb5Syz155240 switch (p) 3268ab25eeb5Syz155240 { 3269ab25eeb5Syz155240 case IPPROTO_TCP : 3270ab25eeb5Syz155240 case IPPROTO_UDP : 3271ab25eeb5Syz155240 sport = htons(fin->fin_data[0]); 3272ab25eeb5Syz155240 dport = htons(fin->fin_data[1]); 3273ab25eeb5Syz155240 break; 3274ab25eeb5Syz155240 case IPPROTO_ICMP : 3275ab25eeb5Syz155240 if (flags & IPN_ICMPERR) 3276ab25eeb5Syz155240 sport = fin->fin_data[1]; 3277ab25eeb5Syz155240 else 3278ab25eeb5Syz155240 dport = fin->fin_data[1]; 3279ab25eeb5Syz155240 break; 3280ab25eeb5Syz155240 default : 3281ab25eeb5Syz155240 break; 3282ab25eeb5Syz155240 } 3283ab25eeb5Syz155240 3284ab25eeb5Syz155240 3285ab25eeb5Syz155240 if ((flags & SI_WILDP) != 0) 3286ab25eeb5Syz155240 goto find_in_wild_ports; 3287ab25eeb5Syz155240 3288ab25eeb5Syz155240 hv = NAT_HASH_FN(dst, dport, 0xffffffff); 3289f4b3ec61Sdh155122 hv = NAT_HASH_FN(src.s_addr, hv + sport, ifs->ifs_ipf_nattable_sz); 3290f4b3ec61Sdh155122 nat = ifs->ifs_nat_table[1][hv]; 3291ab25eeb5Syz155240 for (; nat; nat = nat->nat_hnext[1]) { 3292*d6c23f6fSyx160601 if (nat->nat_v != 4) 3293*d6c23f6fSyx160601 continue; 3294*d6c23f6fSyx160601 3295e6c6c1faSyz155240 if (nat->nat_ifps[0] != NULL) { 3296e6c6c1faSyz155240 if ((ifp != NULL) && (ifp != nat->nat_ifps[0])) 3297e6c6c1faSyz155240 continue; 3298e6c6c1faSyz155240 } else if (ifp != NULL) 3299e6c6c1faSyz155240 nat->nat_ifps[0] = ifp; 3300ab25eeb5Syz155240 3301e6c6c1faSyz155240 nflags = nat->nat_flags; 3302ab25eeb5Syz155240 3303ab25eeb5Syz155240 if (nat->nat_oip.s_addr == src.s_addr && 3304ab25eeb5Syz155240 nat->nat_outip.s_addr == dst && 3305ab25eeb5Syz155240 (((p == 0) && 3306ab25eeb5Syz155240 (sflags == (nat->nat_flags & IPN_TCPUDPICMP))) 3307ab25eeb5Syz155240 || (p == nat->nat_p))) { 3308ab25eeb5Syz155240 switch (p) 3309ab25eeb5Syz155240 { 3310ab25eeb5Syz155240 #if 0 3311ab25eeb5Syz155240 case IPPROTO_GRE : 3312ab25eeb5Syz155240 if (nat->nat_call[1] != fin->fin_data[0]) 3313ab25eeb5Syz155240 continue; 3314ab25eeb5Syz155240 break; 3315ab25eeb5Syz155240 #endif 3316ab25eeb5Syz155240 case IPPROTO_ICMP : 3317ab25eeb5Syz155240 if ((flags & IPN_ICMPERR) != 0) { 3318ab25eeb5Syz155240 if (nat->nat_outport != sport) 3319ab25eeb5Syz155240 continue; 3320ab25eeb5Syz155240 } else { 3321ab25eeb5Syz155240 if (nat->nat_outport != dport) 3322ab25eeb5Syz155240 continue; 3323ab25eeb5Syz155240 } 3324ab25eeb5Syz155240 break; 3325ab25eeb5Syz155240 case IPPROTO_TCP : 3326ab25eeb5Syz155240 case IPPROTO_UDP : 3327ab25eeb5Syz155240 if (nat->nat_oport != sport) 3328ab25eeb5Syz155240 continue; 3329ab25eeb5Syz155240 if (nat->nat_outport != dport) 3330ab25eeb5Syz155240 continue; 3331ab25eeb5Syz155240 break; 3332ab25eeb5Syz155240 default : 3333ab25eeb5Syz155240 break; 3334ab25eeb5Syz155240 } 3335ab25eeb5Syz155240 3336ab25eeb5Syz155240 ipn = nat->nat_ptr; 3337ab25eeb5Syz155240 if ((ipn != NULL) && (nat->nat_aps != NULL)) 3338ab25eeb5Syz155240 if (appr_match(fin, nat) != 0) 3339ab25eeb5Syz155240 continue; 3340ab25eeb5Syz155240 return nat; 3341ab25eeb5Syz155240 } 3342ab25eeb5Syz155240 } 3343ab25eeb5Syz155240 3344ab25eeb5Syz155240 /* 3345ab25eeb5Syz155240 * So if we didn't find it but there are wildcard members in the hash 3346ab25eeb5Syz155240 * table, go back and look for them. We do this search and update here 3347ab25eeb5Syz155240 * because it is modifying the NAT table and we want to do this only 3348ab25eeb5Syz155240 * for the first packet that matches. The exception, of course, is 3349ab25eeb5Syz155240 * for "dummy" (FI_IGNORE) lookups. 3350ab25eeb5Syz155240 */ 3351ab25eeb5Syz155240 find_in_wild_ports: 3352ab25eeb5Syz155240 if (!(flags & NAT_TCPUDP) || !(flags & NAT_SEARCH)) 3353ab25eeb5Syz155240 return NULL; 3354f4b3ec61Sdh155122 if (ifs->ifs_nat_stats.ns_wilds == 0) 3355ab25eeb5Syz155240 return NULL; 3356ab25eeb5Syz155240 3357f4b3ec61Sdh155122 RWLOCK_EXIT(&ifs->ifs_ipf_nat); 3358ab25eeb5Syz155240 3359ab25eeb5Syz155240 hv = NAT_HASH_FN(dst, 0, 0xffffffff); 3360f4b3ec61Sdh155122 hv = NAT_HASH_FN(src.s_addr, hv, ifs->ifs_ipf_nattable_sz); 3361ab25eeb5Syz155240 3362f4b3ec61Sdh155122 WRITE_ENTER(&ifs->ifs_ipf_nat); 3363ab25eeb5Syz155240 3364f4b3ec61Sdh155122 nat = ifs->ifs_nat_table[1][hv]; 3365ab25eeb5Syz155240 for (; nat; nat = nat->nat_hnext[1]) { 3366*d6c23f6fSyx160601 if (nat->nat_v != 4) 3367*d6c23f6fSyx160601 continue; 3368*d6c23f6fSyx160601 3369e6c6c1faSyz155240 if (nat->nat_ifps[0] != NULL) { 3370e6c6c1faSyz155240 if ((ifp != NULL) && (ifp != nat->nat_ifps[0])) 3371ab25eeb5Syz155240 continue; 3372e6c6c1faSyz155240 } else if (ifp != NULL) 3373e6c6c1faSyz155240 nat->nat_ifps[0] = ifp; 3374ab25eeb5Syz155240 3375ab25eeb5Syz155240 if (nat->nat_p != fin->fin_p) 3376ab25eeb5Syz155240 continue; 3377ab25eeb5Syz155240 if (nat->nat_oip.s_addr != src.s_addr || 3378ab25eeb5Syz155240 nat->nat_outip.s_addr != dst) 3379ab25eeb5Syz155240 continue; 3380ab25eeb5Syz155240 3381ab25eeb5Syz155240 nflags = nat->nat_flags; 3382ab25eeb5Syz155240 if (!(nflags & (NAT_TCPUDP|SI_WILDP))) 3383ab25eeb5Syz155240 continue; 3384ab25eeb5Syz155240 3385ab25eeb5Syz155240 if (nat_wildok(nat, (int)sport, (int)dport, nflags, 3386ab25eeb5Syz155240 NAT_INBOUND) == 1) { 3387ab25eeb5Syz155240 if ((fin->fin_flx & FI_IGNORE) != 0) 3388ab25eeb5Syz155240 break; 3389ab25eeb5Syz155240 if ((nflags & SI_CLONE) != 0) { 3390ab25eeb5Syz155240 nat = fr_natclone(fin, nat); 3391ab25eeb5Syz155240 if (nat == NULL) 3392ab25eeb5Syz155240 break; 3393ab25eeb5Syz155240 } else { 3394f4b3ec61Sdh155122 MUTEX_ENTER(&ifs->ifs_ipf_nat_new); 3395f4b3ec61Sdh155122 ifs->ifs_nat_stats.ns_wilds--; 3396f4b3ec61Sdh155122 MUTEX_EXIT(&ifs->ifs_ipf_nat_new); 3397ab25eeb5Syz155240 } 3398ab25eeb5Syz155240 nat->nat_oport = sport; 3399ab25eeb5Syz155240 nat->nat_outport = dport; 3400ab25eeb5Syz155240 nat->nat_flags &= ~(SI_W_DPORT|SI_W_SPORT); 3401f4b3ec61Sdh155122 nat_tabmove(nat, ifs); 3402ab25eeb5Syz155240 break; 3403ab25eeb5Syz155240 } 3404ab25eeb5Syz155240 } 3405ab25eeb5Syz155240 3406f4b3ec61Sdh155122 MUTEX_DOWNGRADE(&ifs->ifs_ipf_nat); 3407ab25eeb5Syz155240 3408ab25eeb5Syz155240 return nat; 3409ab25eeb5Syz155240 } 3410ab25eeb5Syz155240 3411ab25eeb5Syz155240 3412ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */ 3413ab25eeb5Syz155240 /* Function: nat_tabmove */ 3414ab25eeb5Syz155240 /* Returns: Nil */ 3415ab25eeb5Syz155240 /* Parameters: nat(I) - pointer to NAT structure */ 3416ab25eeb5Syz155240 /* Write Lock: ipf_nat */ 3417ab25eeb5Syz155240 /* */ 3418ab25eeb5Syz155240 /* This function is only called for TCP/UDP NAT table entries where the */ 3419ab25eeb5Syz155240 /* original was placed in the table without hashing on the ports and we now */ 3420ab25eeb5Syz155240 /* want to include hashing on port numbers. */ 3421ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */ 3422f4b3ec61Sdh155122 static void nat_tabmove(nat, ifs) 3423ab25eeb5Syz155240 nat_t *nat; 3424f4b3ec61Sdh155122 ipf_stack_t *ifs; 3425ab25eeb5Syz155240 { 3426ab25eeb5Syz155240 nat_t **natp; 3427ab25eeb5Syz155240 u_int hv; 3428ab25eeb5Syz155240 3429ab25eeb5Syz155240 if (nat->nat_flags & SI_CLONE) 3430ab25eeb5Syz155240 return; 3431ab25eeb5Syz155240 3432ab25eeb5Syz155240 /* 3433ab25eeb5Syz155240 * Remove the NAT entry from the old location 3434ab25eeb5Syz155240 */ 3435ab25eeb5Syz155240 if (nat->nat_hnext[0]) 3436ab25eeb5Syz155240 nat->nat_hnext[0]->nat_phnext[0] = nat->nat_phnext[0]; 3437ab25eeb5Syz155240 *nat->nat_phnext[0] = nat->nat_hnext[0]; 3438f4b3ec61Sdh155122 ifs->ifs_nat_stats.ns_bucketlen[0][nat->nat_hv[0]]--; 3439ab25eeb5Syz155240 3440ab25eeb5Syz155240 if (nat->nat_hnext[1]) 3441ab25eeb5Syz155240 nat->nat_hnext[1]->nat_phnext[1] = nat->nat_phnext[1]; 3442ab25eeb5Syz155240 *nat->nat_phnext[1] = nat->nat_hnext[1]; 3443f4b3ec61Sdh155122 ifs->ifs_nat_stats.ns_bucketlen[1][nat->nat_hv[1]]--; 3444ab25eeb5Syz155240 3445ab25eeb5Syz155240 /* 3446ab25eeb5Syz155240 * Add into the NAT table in the new position 3447ab25eeb5Syz155240 */ 3448ab25eeb5Syz155240 hv = NAT_HASH_FN(nat->nat_inip.s_addr, nat->nat_inport, 0xffffffff); 3449ab25eeb5Syz155240 hv = NAT_HASH_FN(nat->nat_oip.s_addr, hv + nat->nat_oport, 3450f4b3ec61Sdh155122 ifs->ifs_ipf_nattable_sz); 3451ab25eeb5Syz155240 nat->nat_hv[0] = hv; 3452f4b3ec61Sdh155122 natp = &ifs->ifs_nat_table[0][hv]; 3453ab25eeb5Syz155240 if (*natp) 3454ab25eeb5Syz155240 (*natp)->nat_phnext[0] = &nat->nat_hnext[0]; 3455ab25eeb5Syz155240 nat->nat_phnext[0] = natp; 3456ab25eeb5Syz155240 nat->nat_hnext[0] = *natp; 3457ab25eeb5Syz155240 *natp = nat; 3458f4b3ec61Sdh155122 ifs->ifs_nat_stats.ns_bucketlen[0][hv]++; 3459ab25eeb5Syz155240 3460ab25eeb5Syz155240 hv = NAT_HASH_FN(nat->nat_outip.s_addr, nat->nat_outport, 0xffffffff); 3461ab25eeb5Syz155240 hv = NAT_HASH_FN(nat->nat_oip.s_addr, hv + nat->nat_oport, 3462f4b3ec61Sdh155122 ifs->ifs_ipf_nattable_sz); 3463ab25eeb5Syz155240 nat->nat_hv[1] = hv; 3464f4b3ec61Sdh155122 natp = &ifs->ifs_nat_table[1][hv]; 3465ab25eeb5Syz155240 if (*natp) 3466ab25eeb5Syz155240 (*natp)->nat_phnext[1] = &nat->nat_hnext[1]; 3467ab25eeb5Syz155240 nat->nat_phnext[1] = natp; 3468ab25eeb5Syz155240 nat->nat_hnext[1] = *natp; 3469ab25eeb5Syz155240 *natp = nat; 3470f4b3ec61Sdh155122 ifs->ifs_nat_stats.ns_bucketlen[1][hv]++; 3471ab25eeb5Syz155240 } 3472ab25eeb5Syz155240 3473ab25eeb5Syz155240 3474ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */ 3475ab25eeb5Syz155240 /* Function: nat_outlookup */ 3476ab25eeb5Syz155240 /* Returns: nat_t* - NULL == no match, */ 3477ab25eeb5Syz155240 /* else pointer to matching NAT entry */ 3478ab25eeb5Syz155240 /* Parameters: fin(I) - pointer to packet information */ 3479ab25eeb5Syz155240 /* flags(I) - NAT flags for this packet */ 3480ab25eeb5Syz155240 /* p(I) - protocol for this packet */ 3481ab25eeb5Syz155240 /* src(I) - source IP address */ 3482ab25eeb5Syz155240 /* dst(I) - destination IP address */ 3483ab25eeb5Syz155240 /* rw(I) - 1 == write lock on ipf_nat held, 0 == read lock. */ 3484ab25eeb5Syz155240 /* */ 3485ab25eeb5Syz155240 /* Lookup a nat entry based on the source 'real' ip address/port and */ 3486ab25eeb5Syz155240 /* destination address/port. We use this lookup when sending a packet out, */ 3487ab25eeb5Syz155240 /* we're looking for a table entry, based on the source address. */ 3488ab25eeb5Syz155240 /* */ 3489ab25eeb5Syz155240 /* NOTE: THE PACKET BEING CHECKED (IF FOUND) HAS A MAPPING ALREADY. */ 3490ab25eeb5Syz155240 /* */ 3491ab25eeb5Syz155240 /* NOTE: IT IS ASSUMED THAT ipf_nat IS ONLY HELD WITH A READ LOCK WHEN */ 3492ab25eeb5Syz155240 /* THIS FUNCTION IS CALLED WITH NAT_SEARCH SET IN nflags. */ 3493ab25eeb5Syz155240 /* */ 3494ab25eeb5Syz155240 /* flags -> relevant are IPN_UDP/IPN_TCP/IPN_ICMPQUERY that indicate if */ 3495ab25eeb5Syz155240 /* the packet is of said protocol */ 3496ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */ 3497ab25eeb5Syz155240 nat_t *nat_outlookup(fin, flags, p, src, dst) 3498ab25eeb5Syz155240 fr_info_t *fin; 3499ab25eeb5Syz155240 u_int flags, p; 3500ab25eeb5Syz155240 struct in_addr src , dst; 3501ab25eeb5Syz155240 { 3502ab25eeb5Syz155240 u_short sport, dport; 3503ab25eeb5Syz155240 u_int sflags; 3504ab25eeb5Syz155240 ipnat_t *ipn; 3505ab25eeb5Syz155240 u_32_t srcip; 3506ab25eeb5Syz155240 nat_t *nat; 3507ab25eeb5Syz155240 int nflags; 3508ab25eeb5Syz155240 void *ifp; 3509ab25eeb5Syz155240 u_int hv; 3510f4b3ec61Sdh155122 ipf_stack_t *ifs = fin->fin_ifs; 3511ab25eeb5Syz155240 3512ab25eeb5Syz155240 ifp = fin->fin_ifp; 3513e6c6c1faSyz155240 3514ab25eeb5Syz155240 srcip = src.s_addr; 3515ab25eeb5Syz155240 sflags = flags & IPN_TCPUDPICMP; 3516ab25eeb5Syz155240 sport = 0; 3517ab25eeb5Syz155240 dport = 0; 3518ab25eeb5Syz155240 3519ab25eeb5Syz155240 switch (p) 3520ab25eeb5Syz155240 { 3521ab25eeb5Syz155240 case IPPROTO_TCP : 3522ab25eeb5Syz155240 case IPPROTO_UDP : 3523ab25eeb5Syz155240 sport = htons(fin->fin_data[0]); 3524ab25eeb5Syz155240 dport = htons(fin->fin_data[1]); 3525ab25eeb5Syz155240 break; 3526ab25eeb5Syz155240 case IPPROTO_ICMP : 3527ab25eeb5Syz155240 if (flags & IPN_ICMPERR) 3528ab25eeb5Syz155240 sport = fin->fin_data[1]; 3529ab25eeb5Syz155240 else 3530ab25eeb5Syz155240 dport = fin->fin_data[1]; 3531ab25eeb5Syz155240 break; 3532ab25eeb5Syz155240 default : 3533ab25eeb5Syz155240 break; 3534ab25eeb5Syz155240 } 3535ab25eeb5Syz155240 3536ab25eeb5Syz155240 if ((flags & SI_WILDP) != 0) 3537ab25eeb5Syz155240 goto find_out_wild_ports; 3538ab25eeb5Syz155240 3539ab25eeb5Syz155240 hv = NAT_HASH_FN(srcip, sport, 0xffffffff); 3540f4b3ec61Sdh155122 hv = NAT_HASH_FN(dst.s_addr, hv + dport, ifs->ifs_ipf_nattable_sz); 3541f4b3ec61Sdh155122 nat = ifs->ifs_nat_table[0][hv]; 3542ab25eeb5Syz155240 for (; nat; nat = nat->nat_hnext[0]) { 3543*d6c23f6fSyx160601 if (nat->nat_v != 4) 3544*d6c23f6fSyx160601 continue; 3545*d6c23f6fSyx160601 3546e6c6c1faSyz155240 if (nat->nat_ifps[1] != NULL) { 3547e6c6c1faSyz155240 if ((ifp != NULL) && (ifp != nat->nat_ifps[1])) 3548e6c6c1faSyz155240 continue; 3549e6c6c1faSyz155240 } else if (ifp != NULL) 3550e6c6c1faSyz155240 nat->nat_ifps[1] = ifp; 3551ab25eeb5Syz155240 3552e6c6c1faSyz155240 nflags = nat->nat_flags; 3553ab25eeb5Syz155240 3554ab25eeb5Syz155240 if (nat->nat_inip.s_addr == srcip && 3555ab25eeb5Syz155240 nat->nat_oip.s_addr == dst.s_addr && 3556ab25eeb5Syz155240 (((p == 0) && (sflags == (nflags & NAT_TCPUDPICMP))) 3557ab25eeb5Syz155240 || (p == nat->nat_p))) { 3558ab25eeb5Syz155240 switch (p) 3559ab25eeb5Syz155240 { 3560ab25eeb5Syz155240 #if 0 3561ab25eeb5Syz155240 case IPPROTO_GRE : 3562ab25eeb5Syz155240 if (nat->nat_call[1] != fin->fin_data[0]) 3563ab25eeb5Syz155240 continue; 3564ab25eeb5Syz155240 break; 3565ab25eeb5Syz155240 #endif 3566ab25eeb5Syz155240 case IPPROTO_TCP : 3567ab25eeb5Syz155240 case IPPROTO_UDP : 3568ab25eeb5Syz155240 if (nat->nat_oport != dport) 3569ab25eeb5Syz155240 continue; 3570ab25eeb5Syz155240 if (nat->nat_inport != sport) 3571ab25eeb5Syz155240 continue; 3572ab25eeb5Syz155240 break; 3573ab25eeb5Syz155240 default : 3574ab25eeb5Syz155240 break; 3575ab25eeb5Syz155240 } 3576ab25eeb5Syz155240 3577ab25eeb5Syz155240 ipn = nat->nat_ptr; 3578ab25eeb5Syz155240 if ((ipn != NULL) && (nat->nat_aps != NULL)) 3579ab25eeb5Syz155240 if (appr_match(fin, nat) != 0) 3580ab25eeb5Syz155240 continue; 3581ab25eeb5Syz155240 return nat; 3582ab25eeb5Syz155240 } 3583ab25eeb5Syz155240 } 3584ab25eeb5Syz155240 3585ab25eeb5Syz155240 /* 3586ab25eeb5Syz155240 * So if we didn't find it but there are wildcard members in the hash 3587ab25eeb5Syz155240 * table, go back and look for them. We do this search and update here 3588ab25eeb5Syz155240 * because it is modifying the NAT table and we want to do this only 3589ab25eeb5Syz155240 * for the first packet that matches. The exception, of course, is 3590ab25eeb5Syz155240 * for "dummy" (FI_IGNORE) lookups. 3591ab25eeb5Syz155240 */ 3592ab25eeb5Syz155240 find_out_wild_ports: 3593ab25eeb5Syz155240 if (!(flags & NAT_TCPUDP) || !(flags & NAT_SEARCH)) 3594ab25eeb5Syz155240 return NULL; 3595f4b3ec61Sdh155122 if (ifs->ifs_nat_stats.ns_wilds == 0) 3596ab25eeb5Syz155240 return NULL; 3597ab25eeb5Syz155240 3598f4b3ec61Sdh155122 RWLOCK_EXIT(&ifs->ifs_ipf_nat); 3599ab25eeb5Syz155240 3600ab25eeb5Syz155240 hv = NAT_HASH_FN(srcip, 0, 0xffffffff); 3601f4b3ec61Sdh155122 hv = NAT_HASH_FN(dst.s_addr, hv, ifs->ifs_ipf_nattable_sz); 3602ab25eeb5Syz155240 3603f4b3ec61Sdh155122 WRITE_ENTER(&ifs->ifs_ipf_nat); 3604ab25eeb5Syz155240 3605f4b3ec61Sdh155122 nat = ifs->ifs_nat_table[0][hv]; 3606ab25eeb5Syz155240 for (; nat; nat = nat->nat_hnext[0]) { 3607*d6c23f6fSyx160601 if (nat->nat_v != 4) 3608*d6c23f6fSyx160601 continue; 3609*d6c23f6fSyx160601 3610e6c6c1faSyz155240 if (nat->nat_ifps[1] != NULL) { 3611e6c6c1faSyz155240 if ((ifp != NULL) && (ifp != nat->nat_ifps[1])) 3612ab25eeb5Syz155240 continue; 3613e6c6c1faSyz155240 } else if (ifp != NULL) 3614e6c6c1faSyz155240 nat->nat_ifps[1] = ifp; 3615ab25eeb5Syz155240 3616ab25eeb5Syz155240 if (nat->nat_p != fin->fin_p) 3617ab25eeb5Syz155240 continue; 3618ab25eeb5Syz155240 if ((nat->nat_inip.s_addr != srcip) || 3619ab25eeb5Syz155240 (nat->nat_oip.s_addr != dst.s_addr)) 3620ab25eeb5Syz155240 continue; 3621ab25eeb5Syz155240 3622ab25eeb5Syz155240 nflags = nat->nat_flags; 3623ab25eeb5Syz155240 if (!(nflags & (NAT_TCPUDP|SI_WILDP))) 3624ab25eeb5Syz155240 continue; 3625ab25eeb5Syz155240 3626ab25eeb5Syz155240 if (nat_wildok(nat, (int)sport, (int)dport, nflags, 3627ab25eeb5Syz155240 NAT_OUTBOUND) == 1) { 3628ab25eeb5Syz155240 if ((fin->fin_flx & FI_IGNORE) != 0) 3629ab25eeb5Syz155240 break; 3630ab25eeb5Syz155240 if ((nflags & SI_CLONE) != 0) { 3631ab25eeb5Syz155240 nat = fr_natclone(fin, nat); 3632ab25eeb5Syz155240 if (nat == NULL) 3633ab25eeb5Syz155240 break; 3634ab25eeb5Syz155240 } else { 3635f4b3ec61Sdh155122 MUTEX_ENTER(&ifs->ifs_ipf_nat_new); 3636f4b3ec61Sdh155122 ifs->ifs_nat_stats.ns_wilds--; 3637f4b3ec61Sdh155122 MUTEX_EXIT(&ifs->ifs_ipf_nat_new); 3638ab25eeb5Syz155240 } 3639ab25eeb5Syz155240 nat->nat_inport = sport; 3640ab25eeb5Syz155240 nat->nat_oport = dport; 3641ab25eeb5Syz155240 if (nat->nat_outport == 0) 3642ab25eeb5Syz155240 nat->nat_outport = sport; 3643ab25eeb5Syz155240 nat->nat_flags &= ~(SI_W_DPORT|SI_W_SPORT); 3644f4b3ec61Sdh155122 nat_tabmove(nat, ifs); 3645ab25eeb5Syz155240 break; 3646ab25eeb5Syz155240 } 3647ab25eeb5Syz155240 } 3648ab25eeb5Syz155240 3649f4b3ec61Sdh155122 MUTEX_DOWNGRADE(&ifs->ifs_ipf_nat); 3650ab25eeb5Syz155240 3651ab25eeb5Syz155240 return nat; 3652ab25eeb5Syz155240 } 3653ab25eeb5Syz155240 3654ab25eeb5Syz155240 3655ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */ 3656ab25eeb5Syz155240 /* Function: nat_lookupredir */ 3657ab25eeb5Syz155240 /* Returns: nat_t* - NULL == no match, */ 3658ab25eeb5Syz155240 /* else pointer to matching NAT entry */ 3659ab25eeb5Syz155240 /* Parameters: np(I) - pointer to description of packet to find NAT table */ 3660ab25eeb5Syz155240 /* entry for. */ 3661ab25eeb5Syz155240 /* */ 3662ab25eeb5Syz155240 /* Lookup the NAT tables to search for a matching redirect */ 3663ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */ 3664f4b3ec61Sdh155122 nat_t *nat_lookupredir(np, ifs) 3665ab25eeb5Syz155240 natlookup_t *np; 3666f4b3ec61Sdh155122 ipf_stack_t *ifs; 3667ab25eeb5Syz155240 { 3668ab25eeb5Syz155240 fr_info_t fi; 3669ab25eeb5Syz155240 nat_t *nat; 3670ab25eeb5Syz155240 3671ab25eeb5Syz155240 bzero((char *)&fi, sizeof(fi)); 3672ab25eeb5Syz155240 if (np->nl_flags & IPN_IN) { 3673ab25eeb5Syz155240 fi.fin_data[0] = ntohs(np->nl_realport); 3674ab25eeb5Syz155240 fi.fin_data[1] = ntohs(np->nl_outport); 3675ab25eeb5Syz155240 } else { 3676ab25eeb5Syz155240 fi.fin_data[0] = ntohs(np->nl_inport); 3677ab25eeb5Syz155240 fi.fin_data[1] = ntohs(np->nl_outport); 3678ab25eeb5Syz155240 } 3679ab25eeb5Syz155240 if (np->nl_flags & IPN_TCP) 3680ab25eeb5Syz155240 fi.fin_p = IPPROTO_TCP; 3681ab25eeb5Syz155240 else if (np->nl_flags & IPN_UDP) 3682ab25eeb5Syz155240 fi.fin_p = IPPROTO_UDP; 3683ab25eeb5Syz155240 else if (np->nl_flags & (IPN_ICMPERR|IPN_ICMPQUERY)) 3684ab25eeb5Syz155240 fi.fin_p = IPPROTO_ICMP; 3685ab25eeb5Syz155240 3686f4b3ec61Sdh155122 fi.fin_ifs = ifs; 3687ab25eeb5Syz155240 /* 3688ab25eeb5Syz155240 * We can do two sorts of lookups: 3689ab25eeb5Syz155240 * - IPN_IN: we have the `real' and `out' address, look for `in'. 3690ab25eeb5Syz155240 * - default: we have the `in' and `out' address, look for `real'. 3691ab25eeb5Syz155240 */ 3692ab25eeb5Syz155240 if (np->nl_flags & IPN_IN) { 3693ab25eeb5Syz155240 if ((nat = nat_inlookup(&fi, np->nl_flags, fi.fin_p, 3694ab25eeb5Syz155240 np->nl_realip, np->nl_outip))) { 3695ab25eeb5Syz155240 np->nl_inip = nat->nat_inip; 3696ab25eeb5Syz155240 np->nl_inport = nat->nat_inport; 3697ab25eeb5Syz155240 } 3698ab25eeb5Syz155240 } else { 3699ab25eeb5Syz155240 /* 3700ab25eeb5Syz155240 * If nl_inip is non null, this is a lookup based on the real 3701ab25eeb5Syz155240 * ip address. Else, we use the fake. 3702ab25eeb5Syz155240 */ 3703ab25eeb5Syz155240 if ((nat = nat_outlookup(&fi, np->nl_flags, fi.fin_p, 3704ab25eeb5Syz155240 np->nl_inip, np->nl_outip))) { 3705ab25eeb5Syz155240 3706ab25eeb5Syz155240 if ((np->nl_flags & IPN_FINDFORWARD) != 0) { 3707ab25eeb5Syz155240 fr_info_t fin; 3708ab25eeb5Syz155240 bzero((char *)&fin, sizeof(fin)); 3709ab25eeb5Syz155240 fin.fin_p = nat->nat_p; 3710ab25eeb5Syz155240 fin.fin_data[0] = ntohs(nat->nat_outport); 3711ab25eeb5Syz155240 fin.fin_data[1] = ntohs(nat->nat_oport); 3712f4b3ec61Sdh155122 fin.fin_ifs = ifs; 3713ab25eeb5Syz155240 if (nat_inlookup(&fin, np->nl_flags, fin.fin_p, 3714ab25eeb5Syz155240 nat->nat_outip, 3715ab25eeb5Syz155240 nat->nat_oip) != NULL) { 3716ab25eeb5Syz155240 np->nl_flags &= ~IPN_FINDFORWARD; 3717ab25eeb5Syz155240 } 3718ab25eeb5Syz155240 } 3719ab25eeb5Syz155240 3720ab25eeb5Syz155240 np->nl_realip = nat->nat_outip; 3721ab25eeb5Syz155240 np->nl_realport = nat->nat_outport; 3722ab25eeb5Syz155240 } 3723ab25eeb5Syz155240 } 3724ab25eeb5Syz155240 3725ab25eeb5Syz155240 return nat; 3726ab25eeb5Syz155240 } 3727ab25eeb5Syz155240 3728ab25eeb5Syz155240 3729ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */ 3730ab25eeb5Syz155240 /* Function: nat_match */ 3731ab25eeb5Syz155240 /* Returns: int - 0 == no match, 1 == match */ 3732ab25eeb5Syz155240 /* Parameters: fin(I) - pointer to packet information */ 3733ab25eeb5Syz155240 /* np(I) - pointer to NAT rule */ 3734ab25eeb5Syz155240 /* */ 3735ab25eeb5Syz155240 /* Pull the matching of a packet against a NAT rule out of that complex */ 3736ab25eeb5Syz155240 /* loop inside fr_checknatin() and lay it out properly in its own function. */ 3737ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */ 3738ab25eeb5Syz155240 static int nat_match(fin, np) 3739ab25eeb5Syz155240 fr_info_t *fin; 3740ab25eeb5Syz155240 ipnat_t *np; 3741ab25eeb5Syz155240 { 3742ab25eeb5Syz155240 frtuc_t *ft; 3743ab25eeb5Syz155240 3744ab25eeb5Syz155240 if (fin->fin_v != 4) 3745ab25eeb5Syz155240 return 0; 3746ab25eeb5Syz155240 3747ab25eeb5Syz155240 if (np->in_p && fin->fin_p != np->in_p) 3748ab25eeb5Syz155240 return 0; 3749ab25eeb5Syz155240 3750ab25eeb5Syz155240 if (fin->fin_out) { 3751ab25eeb5Syz155240 if (!(np->in_redir & (NAT_MAP|NAT_MAPBLK))) 3752ab25eeb5Syz155240 return 0; 3753ab25eeb5Syz155240 if (((fin->fin_fi.fi_saddr & np->in_inmsk) != np->in_inip) 3754ab25eeb5Syz155240 ^ ((np->in_flags & IPN_NOTSRC) != 0)) 3755ab25eeb5Syz155240 return 0; 3756ab25eeb5Syz155240 if (((fin->fin_fi.fi_daddr & np->in_srcmsk) != np->in_srcip) 3757ab25eeb5Syz155240 ^ ((np->in_flags & IPN_NOTDST) != 0)) 3758ab25eeb5Syz155240 return 0; 3759ab25eeb5Syz155240 } else { 3760ab25eeb5Syz155240 if (!(np->in_redir & NAT_REDIRECT)) 3761ab25eeb5Syz155240 return 0; 3762ab25eeb5Syz155240 if (((fin->fin_fi.fi_saddr & np->in_srcmsk) != np->in_srcip) 3763ab25eeb5Syz155240 ^ ((np->in_flags & IPN_NOTSRC) != 0)) 3764ab25eeb5Syz155240 return 0; 3765ab25eeb5Syz155240 if (((fin->fin_fi.fi_daddr & np->in_outmsk) != np->in_outip) 3766ab25eeb5Syz155240 ^ ((np->in_flags & IPN_NOTDST) != 0)) 3767ab25eeb5Syz155240 return 0; 3768ab25eeb5Syz155240 } 3769ab25eeb5Syz155240 3770ab25eeb5Syz155240 ft = &np->in_tuc; 3771ab25eeb5Syz155240 if (!(fin->fin_flx & FI_TCPUDP) || 3772ab25eeb5Syz155240 (fin->fin_flx & (FI_SHORT|FI_FRAGBODY))) { 3773ab25eeb5Syz155240 if (ft->ftu_scmp || ft->ftu_dcmp) 3774ab25eeb5Syz155240 return 0; 3775ab25eeb5Syz155240 return 1; 3776ab25eeb5Syz155240 } 3777ab25eeb5Syz155240 3778ab25eeb5Syz155240 return fr_tcpudpchk(fin, ft); 3779ab25eeb5Syz155240 } 3780ab25eeb5Syz155240 3781ab25eeb5Syz155240 3782ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */ 3783ab25eeb5Syz155240 /* Function: nat_update */ 3784ab25eeb5Syz155240 /* Returns: Nil */ 3785ab25eeb5Syz155240 /* Parameters: nat(I) - pointer to NAT structure */ 3786ab25eeb5Syz155240 /* np(I) - pointer to NAT rule */ 3787ab25eeb5Syz155240 /* */ 3788ab25eeb5Syz155240 /* Updates the lifetime of a NAT table entry for non-TCP packets. Must be */ 3789ab25eeb5Syz155240 /* called with fin_rev updated - i.e. after calling nat_proto(). */ 3790ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */ 3791ab25eeb5Syz155240 void nat_update(fin, nat, np) 3792ab25eeb5Syz155240 fr_info_t *fin; 3793ab25eeb5Syz155240 nat_t *nat; 3794ab25eeb5Syz155240 ipnat_t *np; 3795ab25eeb5Syz155240 { 3796ab25eeb5Syz155240 ipftq_t *ifq, *ifq2; 3797ab25eeb5Syz155240 ipftqent_t *tqe; 3798f4b3ec61Sdh155122 ipf_stack_t *ifs = fin->fin_ifs; 3799ab25eeb5Syz155240 3800ab25eeb5Syz155240 MUTEX_ENTER(&nat->nat_lock); 3801ab25eeb5Syz155240 tqe = &nat->nat_tqe; 3802ab25eeb5Syz155240 ifq = tqe->tqe_ifq; 3803ab25eeb5Syz155240 3804ab25eeb5Syz155240 /* 3805ab25eeb5Syz155240 * We allow over-riding of NAT timeouts from NAT rules, even for 3806ab25eeb5Syz155240 * TCP, however, if it is TCP and there is no rule timeout set, 3807ab25eeb5Syz155240 * then do not update the timeout here. 3808ab25eeb5Syz155240 */ 3809ab25eeb5Syz155240 if (np != NULL) 3810ab25eeb5Syz155240 ifq2 = np->in_tqehead[fin->fin_rev]; 3811ab25eeb5Syz155240 else 3812ab25eeb5Syz155240 ifq2 = NULL; 3813ab25eeb5Syz155240 3814ab25eeb5Syz155240 if (nat->nat_p == IPPROTO_TCP && ifq2 == NULL) { 3815f4b3ec61Sdh155122 (void) fr_tcp_age(&nat->nat_tqe, fin, ifs->ifs_nat_tqb, 0); 3816ab25eeb5Syz155240 } else { 3817ab25eeb5Syz155240 if (ifq2 == NULL) { 3818ab25eeb5Syz155240 if (nat->nat_p == IPPROTO_UDP) 3819f4b3ec61Sdh155122 ifq2 = &ifs->ifs_nat_udptq; 3820ab25eeb5Syz155240 else if (nat->nat_p == IPPROTO_ICMP) 3821f4b3ec61Sdh155122 ifq2 = &ifs->ifs_nat_icmptq; 3822ab25eeb5Syz155240 else 3823f4b3ec61Sdh155122 ifq2 = &ifs->ifs_nat_iptq; 3824ab25eeb5Syz155240 } 3825ab25eeb5Syz155240 3826f4b3ec61Sdh155122 fr_movequeue(tqe, ifq, ifq2, ifs); 3827ab25eeb5Syz155240 } 3828ab25eeb5Syz155240 MUTEX_EXIT(&nat->nat_lock); 3829ab25eeb5Syz155240 } 3830ab25eeb5Syz155240 3831ab25eeb5Syz155240 3832ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */ 3833ab25eeb5Syz155240 /* Function: fr_checknatout */ 3834ab25eeb5Syz155240 /* Returns: int - -1 == packet failed NAT checks so block it, */ 3835ab25eeb5Syz155240 /* 0 == no packet translation occurred, */ 3836ab25eeb5Syz155240 /* 1 == packet was successfully translated. */ 3837ab25eeb5Syz155240 /* Parameters: fin(I) - pointer to packet information */ 3838ab25eeb5Syz155240 /* passp(I) - pointer to filtering result flags */ 3839ab25eeb5Syz155240 /* */ 3840ab25eeb5Syz155240 /* Check to see if an outcoming packet should be changed. ICMP packets are */ 3841ab25eeb5Syz155240 /* first checked to see if they match an existing entry (if an error), */ 3842ab25eeb5Syz155240 /* otherwise a search of the current NAT table is made. If neither results */ 3843ab25eeb5Syz155240 /* in a match then a search for a matching NAT rule is made. Create a new */ 3844ab25eeb5Syz155240 /* NAT entry if a we matched a NAT rule. Lastly, actually change the */ 3845ab25eeb5Syz155240 /* packet header(s) as required. */ 3846ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */ 3847ab25eeb5Syz155240 int fr_checknatout(fin, passp) 3848ab25eeb5Syz155240 fr_info_t *fin; 3849ab25eeb5Syz155240 u_32_t *passp; 3850ab25eeb5Syz155240 { 3851cbded9aeSdr146992 ipnat_t *np = NULL, *npnext; 3852ab25eeb5Syz155240 struct ifnet *ifp, *sifp; 3853ab25eeb5Syz155240 icmphdr_t *icmp = NULL; 3854ab25eeb5Syz155240 tcphdr_t *tcp = NULL; 3855ab25eeb5Syz155240 int rval, natfailed; 3856ab25eeb5Syz155240 u_int nflags = 0; 3857ab25eeb5Syz155240 u_32_t ipa, iph; 3858ab25eeb5Syz155240 int natadd = 1; 3859ab25eeb5Syz155240 frentry_t *fr; 3860ab25eeb5Syz155240 nat_t *nat; 3861f4b3ec61Sdh155122 ipf_stack_t *ifs = fin->fin_ifs; 3862ab25eeb5Syz155240 3863f4b3ec61Sdh155122 if (ifs->ifs_nat_stats.ns_rules == 0 || ifs->ifs_fr_nat_lock != 0) 3864ab25eeb5Syz155240 return 0; 3865ab25eeb5Syz155240 3866ab25eeb5Syz155240 natfailed = 0; 3867ab25eeb5Syz155240 fr = fin->fin_fr; 3868ab25eeb5Syz155240 sifp = fin->fin_ifp; 3869ab25eeb5Syz155240 if ((fr != NULL) && !(fr->fr_flags & FR_DUP) && 3870d3675867Sjojemann fr->fr_tifs[fin->fin_rev].fd_ifp && 3871d3675867Sjojemann fr->fr_tifs[fin->fin_rev].fd_ifp != (void *)-1) 3872d3675867Sjojemann fin->fin_ifp = fr->fr_tifs[fin->fin_rev].fd_ifp; 3873ab25eeb5Syz155240 ifp = fin->fin_ifp; 3874ab25eeb5Syz155240 3875ab25eeb5Syz155240 if (!(fin->fin_flx & FI_SHORT) && (fin->fin_off == 0)) { 3876ab25eeb5Syz155240 switch (fin->fin_p) 3877ab25eeb5Syz155240 { 3878ab25eeb5Syz155240 case IPPROTO_TCP : 3879ab25eeb5Syz155240 nflags = IPN_TCP; 3880ab25eeb5Syz155240 break; 3881ab25eeb5Syz155240 case IPPROTO_UDP : 3882ab25eeb5Syz155240 nflags = IPN_UDP; 3883ab25eeb5Syz155240 break; 3884ab25eeb5Syz155240 case IPPROTO_ICMP : 3885ab25eeb5Syz155240 icmp = fin->fin_dp; 3886ab25eeb5Syz155240 3887ab25eeb5Syz155240 /* 3888ab25eeb5Syz155240 * This is an incoming packet, so the destination is 3889ab25eeb5Syz155240 * the icmp_id and the source port equals 0 3890ab25eeb5Syz155240 */ 3891ab25eeb5Syz155240 if (nat_icmpquerytype4(icmp->icmp_type)) 3892ab25eeb5Syz155240 nflags = IPN_ICMPQUERY; 3893ab25eeb5Syz155240 break; 3894ab25eeb5Syz155240 default : 3895ab25eeb5Syz155240 break; 3896ab25eeb5Syz155240 } 3897ab25eeb5Syz155240 3898ab25eeb5Syz155240 if ((nflags & IPN_TCPUDP)) 3899ab25eeb5Syz155240 tcp = fin->fin_dp; 3900ab25eeb5Syz155240 } 3901ab25eeb5Syz155240 3902ab25eeb5Syz155240 ipa = fin->fin_saddr; 3903ab25eeb5Syz155240 3904f4b3ec61Sdh155122 READ_ENTER(&ifs->ifs_ipf_nat); 3905ab25eeb5Syz155240 3906ab25eeb5Syz155240 if ((fin->fin_p == IPPROTO_ICMP) && !(nflags & IPN_ICMPQUERY) && 3907ab25eeb5Syz155240 (nat = nat_icmperror(fin, &nflags, NAT_OUTBOUND))) 3908ab25eeb5Syz155240 /*EMPTY*/; 3909ab25eeb5Syz155240 else if ((fin->fin_flx & FI_FRAG) && (nat = fr_nat_knownfrag(fin))) 3910ab25eeb5Syz155240 natadd = 0; 3911ab25eeb5Syz155240 else if ((nat = nat_outlookup(fin, nflags|NAT_SEARCH, (u_int)fin->fin_p, 3912ab25eeb5Syz155240 fin->fin_src, fin->fin_dst))) { 3913ab25eeb5Syz155240 nflags = nat->nat_flags; 3914ab25eeb5Syz155240 } else { 3915ab25eeb5Syz155240 u_32_t hv, msk, nmsk; 3916ab25eeb5Syz155240 3917ab25eeb5Syz155240 /* 3918ab25eeb5Syz155240 * If there is no current entry in the nat table for this IP#, 3919ab25eeb5Syz155240 * create one for it (if there is a matching rule). 3920ab25eeb5Syz155240 */ 3921ab25eeb5Syz155240 msk = 0xffffffff; 3922f4b3ec61Sdh155122 nmsk = ifs->ifs_nat_masks; 3923ab25eeb5Syz155240 maskloop: 3924ab25eeb5Syz155240 iph = ipa & htonl(msk); 3925f4b3ec61Sdh155122 hv = NAT_HASH_FN(iph, 0, ifs->ifs_ipf_natrules_sz); 3926cbded9aeSdr146992 for (np = ifs->ifs_nat_rules[hv]; np; np = npnext) { 3927cbded9aeSdr146992 npnext = np->in_mnext; 3928e6c6c1faSyz155240 if ((np->in_ifps[1] && (np->in_ifps[1] != ifp))) 3929ab25eeb5Syz155240 continue; 3930ab25eeb5Syz155240 if (np->in_v != fin->fin_v) 3931ab25eeb5Syz155240 continue; 3932ab25eeb5Syz155240 if (np->in_p && (np->in_p != fin->fin_p)) 3933ab25eeb5Syz155240 continue; 3934ab25eeb5Syz155240 if ((np->in_flags & IPN_RF) && !(np->in_flags & nflags)) 3935ab25eeb5Syz155240 continue; 3936ab25eeb5Syz155240 if (np->in_flags & IPN_FILTER) { 3937ab25eeb5Syz155240 if (!nat_match(fin, np)) 3938ab25eeb5Syz155240 continue; 3939ab25eeb5Syz155240 } else if ((ipa & np->in_inmsk) != np->in_inip) 3940ab25eeb5Syz155240 continue; 3941ab25eeb5Syz155240 3942ab25eeb5Syz155240 if ((fr != NULL) && 3943ab25eeb5Syz155240 !fr_matchtag(&np->in_tag, &fr->fr_nattag)) 3944ab25eeb5Syz155240 continue; 3945ab25eeb5Syz155240 3946ab25eeb5Syz155240 if (*np->in_plabel != '\0') { 3947ab25eeb5Syz155240 if (((np->in_flags & IPN_FILTER) == 0) && 3948ab25eeb5Syz155240 (np->in_dport != tcp->th_dport)) 3949ab25eeb5Syz155240 continue; 3950ab25eeb5Syz155240 if (appr_ok(fin, tcp, np) == 0) 3951ab25eeb5Syz155240 continue; 3952ab25eeb5Syz155240 } 3953ab25eeb5Syz155240 3954cbded9aeSdr146992 ATOMIC_INC32(np->in_use); 3955cbded9aeSdr146992 RWLOCK_EXIT(&ifs->ifs_ipf_nat); 3956cbded9aeSdr146992 WRITE_ENTER(&ifs->ifs_ipf_nat); 3957cbded9aeSdr146992 nat = nat_new(fin, np, NULL, nflags, NAT_OUTBOUND); 3958cbded9aeSdr146992 if (nat != NULL) { 3959cbded9aeSdr146992 np->in_use--; 3960ab25eeb5Syz155240 np->in_hits++; 3961cbded9aeSdr146992 MUTEX_DOWNGRADE(&ifs->ifs_ipf_nat); 3962ab25eeb5Syz155240 break; 3963cbded9aeSdr146992 } 3964ab25eeb5Syz155240 natfailed = -1; 3965cbded9aeSdr146992 npnext = np->in_mnext; 3966cbded9aeSdr146992 fr_ipnatderef(&np, ifs); 3967cbded9aeSdr146992 MUTEX_DOWNGRADE(&ifs->ifs_ipf_nat); 3968ab25eeb5Syz155240 } 3969ab25eeb5Syz155240 if ((np == NULL) && (nmsk != 0)) { 3970ab25eeb5Syz155240 while (nmsk) { 3971ab25eeb5Syz155240 msk <<= 1; 3972ab25eeb5Syz155240 if (nmsk & 0x80000000) 3973ab25eeb5Syz155240 break; 3974ab25eeb5Syz155240 nmsk <<= 1; 3975ab25eeb5Syz155240 } 3976ab25eeb5Syz155240 if (nmsk != 0) { 3977ab25eeb5Syz155240 nmsk <<= 1; 3978ab25eeb5Syz155240 goto maskloop; 3979ab25eeb5Syz155240 } 3980ab25eeb5Syz155240 } 3981ab25eeb5Syz155240 } 3982ab25eeb5Syz155240 3983ab25eeb5Syz155240 if (nat != NULL) { 3984ab25eeb5Syz155240 rval = fr_natout(fin, nat, natadd, nflags); 3985ab25eeb5Syz155240 if (rval == 1) { 3986ab25eeb5Syz155240 MUTEX_ENTER(&nat->nat_lock); 3987ab25eeb5Syz155240 nat->nat_ref++; 3988ab25eeb5Syz155240 MUTEX_EXIT(&nat->nat_lock); 39893805c50fSan207044 nat->nat_touched = ifs->ifs_fr_ticks; 3990ab25eeb5Syz155240 fin->fin_nat = nat; 3991ab25eeb5Syz155240 } 3992ab25eeb5Syz155240 } else 3993ab25eeb5Syz155240 rval = natfailed; 3994f4b3ec61Sdh155122 RWLOCK_EXIT(&ifs->ifs_ipf_nat); 3995ab25eeb5Syz155240 3996ab25eeb5Syz155240 if (rval == -1) { 3997ab25eeb5Syz155240 if (passp != NULL) 3998ab25eeb5Syz155240 *passp = FR_BLOCK; 3999ab25eeb5Syz155240 fin->fin_flx |= FI_BADNAT; 4000ab25eeb5Syz155240 } 4001ab25eeb5Syz155240 fin->fin_ifp = sifp; 4002ab25eeb5Syz155240 return rval; 4003ab25eeb5Syz155240 } 4004ab25eeb5Syz155240 4005ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */ 4006ab25eeb5Syz155240 /* Function: fr_natout */ 4007ab25eeb5Syz155240 /* Returns: int - -1 == packet failed NAT checks so block it, */ 4008ab25eeb5Syz155240 /* 1 == packet was successfully translated. */ 4009ab25eeb5Syz155240 /* Parameters: fin(I) - pointer to packet information */ 4010ab25eeb5Syz155240 /* nat(I) - pointer to NAT structure */ 4011ab25eeb5Syz155240 /* natadd(I) - flag indicating if it is safe to add frag cache */ 4012ab25eeb5Syz155240 /* nflags(I) - NAT flags set for this packet */ 4013ab25eeb5Syz155240 /* */ 4014ab25eeb5Syz155240 /* Translate a packet coming "out" on an interface. */ 4015ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */ 4016ab25eeb5Syz155240 int fr_natout(fin, nat, natadd, nflags) 4017ab25eeb5Syz155240 fr_info_t *fin; 4018ab25eeb5Syz155240 nat_t *nat; 4019ab25eeb5Syz155240 int natadd; 4020ab25eeb5Syz155240 u_32_t nflags; 4021ab25eeb5Syz155240 { 4022ab25eeb5Syz155240 icmphdr_t *icmp; 4023ab25eeb5Syz155240 u_short *csump; 4024381a2a9aSdr146992 u_32_t sumd; 4025ab25eeb5Syz155240 tcphdr_t *tcp; 4026ab25eeb5Syz155240 ipnat_t *np; 4027ab25eeb5Syz155240 int i; 4028f4b3ec61Sdh155122 ipf_stack_t *ifs = fin->fin_ifs; 4029ab25eeb5Syz155240 4030*d6c23f6fSyx160601 if (fin->fin_v == 6) { 4031*d6c23f6fSyx160601 #ifdef USE_INET6 4032*d6c23f6fSyx160601 return fr_nat6out(fin, nat, natadd, nflags); 4033*d6c23f6fSyx160601 #else 4034*d6c23f6fSyx160601 return NULL; 4035*d6c23f6fSyx160601 #endif 4036*d6c23f6fSyx160601 } 4037*d6c23f6fSyx160601 4038381a2a9aSdr146992 #if SOLARIS && defined(_KERNEL) 4039*d6c23f6fSyx160601 net_data_t net_data_p = ifs->ifs_ipf_ipv4; 4040381a2a9aSdr146992 #endif 4041381a2a9aSdr146992 4042ab25eeb5Syz155240 tcp = NULL; 4043ab25eeb5Syz155240 icmp = NULL; 4044ab25eeb5Syz155240 csump = NULL; 4045ab25eeb5Syz155240 np = nat->nat_ptr; 4046ab25eeb5Syz155240 404715013d88Szf203873 if ((natadd != 0) && (fin->fin_flx & FI_FRAG)) 4048ab25eeb5Syz155240 (void) fr_nat_newfrag(fin, 0, nat); 4049ab25eeb5Syz155240 4050ab25eeb5Syz155240 MUTEX_ENTER(&nat->nat_lock); 4051ab25eeb5Syz155240 nat->nat_bytes[1] += fin->fin_plen; 4052ab25eeb5Syz155240 nat->nat_pkts[1]++; 4053ab25eeb5Syz155240 MUTEX_EXIT(&nat->nat_lock); 4054ab25eeb5Syz155240 4055ab25eeb5Syz155240 /* 4056ab25eeb5Syz155240 * Fix up checksums, not by recalculating them, but 4057ab25eeb5Syz155240 * simply computing adjustments. 4058ab25eeb5Syz155240 * This is only done for STREAMS based IP implementations where the 4059ab25eeb5Syz155240 * checksum has already been calculated by IP. In all other cases, 4060ab25eeb5Syz155240 * IPFilter is called before the checksum needs calculating so there 4061ab25eeb5Syz155240 * is no call to modify whatever is in the header now. 4062ab25eeb5Syz155240 */ 4063381a2a9aSdr146992 ASSERT(fin->fin_m != NULL); 4064381a2a9aSdr146992 if (fin->fin_v == 4 && !NET_IS_HCK_L3_FULL(net_data_p, fin->fin_m)) { 4065ab25eeb5Syz155240 if (nflags == IPN_ICMPERR) { 4066381a2a9aSdr146992 u_32_t s1, s2; 4067ab25eeb5Syz155240 4068ab25eeb5Syz155240 s1 = LONG_SUM(ntohl(fin->fin_saddr)); 4069ab25eeb5Syz155240 s2 = LONG_SUM(ntohl(nat->nat_outip.s_addr)); 4070ab25eeb5Syz155240 CALC_SUMD(s1, s2, sumd); 4071381a2a9aSdr146992 4072381a2a9aSdr146992 fix_outcksum(&fin->fin_ip->ip_sum, sumd); 4073ab25eeb5Syz155240 } 4074ab25eeb5Syz155240 #if !defined(_KERNEL) || defined(MENTAT) || defined(__sgi) || \ 4075ab25eeb5Syz155240 defined(linux) || defined(BRIDGE_IPF) 4076ab25eeb5Syz155240 else { 4077ab25eeb5Syz155240 /* 4078ab25eeb5Syz155240 * Strictly speaking, this isn't necessary on BSD 4079ab25eeb5Syz155240 * kernels because they do checksum calculation after 4080ab25eeb5Syz155240 * this code has run BUT if ipfilter is being used 4081ab25eeb5Syz155240 * to do NAT as a bridge, that code doesn't exist. 4082ab25eeb5Syz155240 */ 4083ab25eeb5Syz155240 if (nat->nat_dir == NAT_OUTBOUND) 4084381a2a9aSdr146992 fix_outcksum(&fin->fin_ip->ip_sum, 4085ab25eeb5Syz155240 nat->nat_ipsumd); 4086ab25eeb5Syz155240 else 4087381a2a9aSdr146992 fix_incksum(&fin->fin_ip->ip_sum, 4088ab25eeb5Syz155240 nat->nat_ipsumd); 4089ab25eeb5Syz155240 } 4090ab25eeb5Syz155240 #endif 4091ab25eeb5Syz155240 } 4092ab25eeb5Syz155240 4093ab25eeb5Syz155240 if (!(fin->fin_flx & FI_SHORT) && (fin->fin_off == 0)) { 4094ab25eeb5Syz155240 if ((nat->nat_outport != 0) && (nflags & IPN_TCPUDP)) { 4095ab25eeb5Syz155240 tcp = fin->fin_dp; 4096ab25eeb5Syz155240 4097ab25eeb5Syz155240 tcp->th_sport = nat->nat_outport; 4098ab25eeb5Syz155240 fin->fin_data[0] = ntohs(nat->nat_outport); 4099ab25eeb5Syz155240 } 4100ab25eeb5Syz155240 4101ab25eeb5Syz155240 if ((nat->nat_outport != 0) && (nflags & IPN_ICMPQUERY)) { 4102ab25eeb5Syz155240 icmp = fin->fin_dp; 4103ab25eeb5Syz155240 icmp->icmp_id = nat->nat_outport; 4104ab25eeb5Syz155240 } 4105ab25eeb5Syz155240 4106ab25eeb5Syz155240 csump = nat_proto(fin, nat, nflags); 4107ab25eeb5Syz155240 } 4108ab25eeb5Syz155240 4109ab25eeb5Syz155240 fin->fin_ip->ip_src = nat->nat_outip; 4110ab25eeb5Syz155240 4111ab25eeb5Syz155240 nat_update(fin, nat, np); 4112ab25eeb5Syz155240 4113ab25eeb5Syz155240 /* 4114ab25eeb5Syz155240 * The above comments do not hold for layer 4 (or higher) checksums... 4115ab25eeb5Syz155240 */ 4116381a2a9aSdr146992 if (csump != NULL && !NET_IS_HCK_L4_FULL(net_data_p, fin->fin_m)) { 4117381a2a9aSdr146992 if (nflags & IPN_TCPUDP && 4118381a2a9aSdr146992 NET_IS_HCK_L4_PART(net_data_p, fin->fin_m)) 4119381a2a9aSdr146992 sumd = nat->nat_sumd[1]; 4120ab25eeb5Syz155240 else 4121381a2a9aSdr146992 sumd = nat->nat_sumd[0]; 4122381a2a9aSdr146992 4123381a2a9aSdr146992 if (nat->nat_dir == NAT_OUTBOUND) 4124381a2a9aSdr146992 fix_outcksum(csump, sumd); 4125381a2a9aSdr146992 else 4126381a2a9aSdr146992 fix_incksum(csump, sumd); 4127ab25eeb5Syz155240 } 4128ab25eeb5Syz155240 #ifdef IPFILTER_SYNC 4129ab25eeb5Syz155240 ipfsync_update(SMC_NAT, fin, nat->nat_sync); 4130ab25eeb5Syz155240 #endif 4131ab25eeb5Syz155240 /* ------------------------------------------------------------- */ 4132ab25eeb5Syz155240 /* A few quick notes: */ 4133ab25eeb5Syz155240 /* Following are test conditions prior to calling the */ 4134ab25eeb5Syz155240 /* appr_check routine. */ 4135ab25eeb5Syz155240 /* */ 4136ab25eeb5Syz155240 /* A NULL tcp indicates a non TCP/UDP packet. When dealing */ 4137ab25eeb5Syz155240 /* with a redirect rule, we attempt to match the packet's */ 4138ab25eeb5Syz155240 /* source port against in_dport, otherwise we'd compare the */ 4139ab25eeb5Syz155240 /* packet's destination. */ 4140ab25eeb5Syz155240 /* ------------------------------------------------------------- */ 4141ab25eeb5Syz155240 if ((np != NULL) && (np->in_apr != NULL)) { 4142ab25eeb5Syz155240 i = appr_check(fin, nat); 4143ab25eeb5Syz155240 if (i == 0) 4144ab25eeb5Syz155240 i = 1; 4145ab25eeb5Syz155240 } else 4146ab25eeb5Syz155240 i = 1; 4147cbded9aeSdr146992 ifs->ifs_nat_stats.ns_mapped[1]++; 4148ab25eeb5Syz155240 fin->fin_flx |= FI_NATED; 4149ab25eeb5Syz155240 return i; 4150ab25eeb5Syz155240 } 4151ab25eeb5Syz155240 4152ab25eeb5Syz155240 4153ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */ 4154ab25eeb5Syz155240 /* Function: fr_checknatin */ 4155ab25eeb5Syz155240 /* Returns: int - -1 == packet failed NAT checks so block it, */ 4156ab25eeb5Syz155240 /* 0 == no packet translation occurred, */ 4157ab25eeb5Syz155240 /* 1 == packet was successfully translated. */ 4158ab25eeb5Syz155240 /* Parameters: fin(I) - pointer to packet information */ 4159ab25eeb5Syz155240 /* passp(I) - pointer to filtering result flags */ 4160ab25eeb5Syz155240 /* */ 4161ab25eeb5Syz155240 /* Check to see if an incoming packet should be changed. ICMP packets are */ 4162ab25eeb5Syz155240 /* first checked to see if they match an existing entry (if an error), */ 4163ab25eeb5Syz155240 /* otherwise a search of the current NAT table is made. If neither results */ 4164ab25eeb5Syz155240 /* in a match then a search for a matching NAT rule is made. Create a new */ 4165ab25eeb5Syz155240 /* NAT entry if a we matched a NAT rule. Lastly, actually change the */ 4166ab25eeb5Syz155240 /* packet header(s) as required. */ 4167ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */ 4168ab25eeb5Syz155240 int fr_checknatin(fin, passp) 4169ab25eeb5Syz155240 fr_info_t *fin; 4170ab25eeb5Syz155240 u_32_t *passp; 4171ab25eeb5Syz155240 { 4172ab25eeb5Syz155240 u_int nflags, natadd; 4173cbded9aeSdr146992 ipnat_t *np, *npnext; 4174ab25eeb5Syz155240 int rval, natfailed; 4175ab25eeb5Syz155240 struct ifnet *ifp; 4176ab25eeb5Syz155240 struct in_addr in; 4177ab25eeb5Syz155240 icmphdr_t *icmp; 4178ab25eeb5Syz155240 tcphdr_t *tcp; 4179ab25eeb5Syz155240 u_short dport; 4180ab25eeb5Syz155240 nat_t *nat; 4181ab25eeb5Syz155240 u_32_t iph; 4182f4b3ec61Sdh155122 ipf_stack_t *ifs = fin->fin_ifs; 4183ab25eeb5Syz155240 4184f4b3ec61Sdh155122 if (ifs->ifs_nat_stats.ns_rules == 0 || ifs->ifs_fr_nat_lock != 0) 4185ab25eeb5Syz155240 return 0; 4186ab25eeb5Syz155240 4187ab25eeb5Syz155240 tcp = NULL; 4188ab25eeb5Syz155240 icmp = NULL; 4189ab25eeb5Syz155240 dport = 0; 4190ab25eeb5Syz155240 natadd = 1; 4191ab25eeb5Syz155240 nflags = 0; 4192ab25eeb5Syz155240 natfailed = 0; 4193ab25eeb5Syz155240 ifp = fin->fin_ifp; 4194ab25eeb5Syz155240 4195ab25eeb5Syz155240 if (!(fin->fin_flx & FI_SHORT) && (fin->fin_off == 0)) { 4196ab25eeb5Syz155240 switch (fin->fin_p) 4197ab25eeb5Syz155240 { 4198ab25eeb5Syz155240 case IPPROTO_TCP : 4199ab25eeb5Syz155240 nflags = IPN_TCP; 4200ab25eeb5Syz155240 break; 4201ab25eeb5Syz155240 case IPPROTO_UDP : 4202ab25eeb5Syz155240 nflags = IPN_UDP; 4203ab25eeb5Syz155240 break; 4204ab25eeb5Syz155240 case IPPROTO_ICMP : 4205ab25eeb5Syz155240 icmp = fin->fin_dp; 4206ab25eeb5Syz155240 4207ab25eeb5Syz155240 /* 4208ab25eeb5Syz155240 * This is an incoming packet, so the destination is 4209ab25eeb5Syz155240 * the icmp_id and the source port equals 0 4210ab25eeb5Syz155240 */ 4211ab25eeb5Syz155240 if (nat_icmpquerytype4(icmp->icmp_type)) { 4212ab25eeb5Syz155240 nflags = IPN_ICMPQUERY; 4213ab25eeb5Syz155240 dport = icmp->icmp_id; 4214ab25eeb5Syz155240 } break; 4215ab25eeb5Syz155240 default : 4216ab25eeb5Syz155240 break; 4217ab25eeb5Syz155240 } 4218ab25eeb5Syz155240 4219ab25eeb5Syz155240 if ((nflags & IPN_TCPUDP)) { 4220ab25eeb5Syz155240 tcp = fin->fin_dp; 4221ab25eeb5Syz155240 dport = tcp->th_dport; 4222ab25eeb5Syz155240 } 4223ab25eeb5Syz155240 } 4224ab25eeb5Syz155240 4225ab25eeb5Syz155240 in = fin->fin_dst; 4226ab25eeb5Syz155240 4227f4b3ec61Sdh155122 READ_ENTER(&ifs->ifs_ipf_nat); 4228ab25eeb5Syz155240 4229ab25eeb5Syz155240 if ((fin->fin_p == IPPROTO_ICMP) && !(nflags & IPN_ICMPQUERY) && 4230ab25eeb5Syz155240 (nat = nat_icmperror(fin, &nflags, NAT_INBOUND))) 4231ab25eeb5Syz155240 /*EMPTY*/; 4232ab25eeb5Syz155240 else if ((fin->fin_flx & FI_FRAG) && (nat = fr_nat_knownfrag(fin))) 4233ab25eeb5Syz155240 natadd = 0; 4234ab25eeb5Syz155240 else if ((nat = nat_inlookup(fin, nflags|NAT_SEARCH, (u_int)fin->fin_p, 4235ab25eeb5Syz155240 fin->fin_src, in))) { 4236ab25eeb5Syz155240 nflags = nat->nat_flags; 4237ab25eeb5Syz155240 } else { 4238ab25eeb5Syz155240 u_32_t hv, msk, rmsk; 4239ab25eeb5Syz155240 4240f4b3ec61Sdh155122 rmsk = ifs->ifs_rdr_masks; 4241ab25eeb5Syz155240 msk = 0xffffffff; 4242ab25eeb5Syz155240 /* 4243ab25eeb5Syz155240 * If there is no current entry in the nat table for this IP#, 4244ab25eeb5Syz155240 * create one for it (if there is a matching rule). 4245ab25eeb5Syz155240 */ 4246ab25eeb5Syz155240 maskloop: 4247ab25eeb5Syz155240 iph = in.s_addr & htonl(msk); 4248f4b3ec61Sdh155122 hv = NAT_HASH_FN(iph, 0, ifs->ifs_ipf_rdrrules_sz); 4249cbded9aeSdr146992 for (np = ifs->ifs_rdr_rules[hv]; np; np = npnext) { 4250cbded9aeSdr146992 npnext = np->in_rnext; 4251ab25eeb5Syz155240 if (np->in_ifps[0] && (np->in_ifps[0] != ifp)) 4252ab25eeb5Syz155240 continue; 4253ab25eeb5Syz155240 if (np->in_v != fin->fin_v) 4254ab25eeb5Syz155240 continue; 4255ab25eeb5Syz155240 if (np->in_p && (np->in_p != fin->fin_p)) 4256ab25eeb5Syz155240 continue; 4257ab25eeb5Syz155240 if ((np->in_flags & IPN_RF) && !(np->in_flags & nflags)) 4258ab25eeb5Syz155240 continue; 4259ab25eeb5Syz155240 if (np->in_flags & IPN_FILTER) { 4260ab25eeb5Syz155240 if (!nat_match(fin, np)) 4261ab25eeb5Syz155240 continue; 4262ab25eeb5Syz155240 } else { 4263ab25eeb5Syz155240 if ((in.s_addr & np->in_outmsk) != np->in_outip) 4264ab25eeb5Syz155240 continue; 4265ab25eeb5Syz155240 if (np->in_pmin && 4266ab25eeb5Syz155240 ((ntohs(np->in_pmax) < ntohs(dport)) || 4267ab25eeb5Syz155240 (ntohs(dport) < ntohs(np->in_pmin)))) 4268ab25eeb5Syz155240 continue; 4269ab25eeb5Syz155240 } 4270ab25eeb5Syz155240 4271ab25eeb5Syz155240 if (*np->in_plabel != '\0') { 4272ab25eeb5Syz155240 if (!appr_ok(fin, tcp, np)) { 4273ab25eeb5Syz155240 continue; 4274ab25eeb5Syz155240 } 4275ab25eeb5Syz155240 } 4276ab25eeb5Syz155240 4277cbded9aeSdr146992 ATOMIC_INC32(np->in_use); 4278cbded9aeSdr146992 RWLOCK_EXIT(&ifs->ifs_ipf_nat); 4279cbded9aeSdr146992 WRITE_ENTER(&ifs->ifs_ipf_nat); 4280ab25eeb5Syz155240 nat = nat_new(fin, np, NULL, nflags, NAT_INBOUND); 4281ab25eeb5Syz155240 if (nat != NULL) { 4282cbded9aeSdr146992 np->in_use--; 4283ab25eeb5Syz155240 np->in_hits++; 4284cbded9aeSdr146992 MUTEX_DOWNGRADE(&ifs->ifs_ipf_nat); 4285ab25eeb5Syz155240 break; 4286cbded9aeSdr146992 } 4287ab25eeb5Syz155240 natfailed = -1; 4288cbded9aeSdr146992 npnext = np->in_rnext; 4289cbded9aeSdr146992 fr_ipnatderef(&np, ifs); 4290cbded9aeSdr146992 MUTEX_DOWNGRADE(&ifs->ifs_ipf_nat); 4291ab25eeb5Syz155240 } 4292ab25eeb5Syz155240 4293ab25eeb5Syz155240 if ((np == NULL) && (rmsk != 0)) { 4294ab25eeb5Syz155240 while (rmsk) { 4295ab25eeb5Syz155240 msk <<= 1; 4296ab25eeb5Syz155240 if (rmsk & 0x80000000) 4297ab25eeb5Syz155240 break; 4298ab25eeb5Syz155240 rmsk <<= 1; 4299ab25eeb5Syz155240 } 4300ab25eeb5Syz155240 if (rmsk != 0) { 4301ab25eeb5Syz155240 rmsk <<= 1; 4302ab25eeb5Syz155240 goto maskloop; 4303ab25eeb5Syz155240 } 4304ab25eeb5Syz155240 } 4305ab25eeb5Syz155240 } 4306ab25eeb5Syz155240 if (nat != NULL) { 4307ab25eeb5Syz155240 rval = fr_natin(fin, nat, natadd, nflags); 4308ab25eeb5Syz155240 if (rval == 1) { 4309ab25eeb5Syz155240 MUTEX_ENTER(&nat->nat_lock); 4310ab25eeb5Syz155240 nat->nat_ref++; 4311ab25eeb5Syz155240 MUTEX_EXIT(&nat->nat_lock); 43123805c50fSan207044 nat->nat_touched = ifs->ifs_fr_ticks; 4313ab25eeb5Syz155240 fin->fin_nat = nat; 4314ab25eeb5Syz155240 fin->fin_state = nat->nat_state; 4315ab25eeb5Syz155240 } 4316ab25eeb5Syz155240 } else 4317ab25eeb5Syz155240 rval = natfailed; 4318f4b3ec61Sdh155122 RWLOCK_EXIT(&ifs->ifs_ipf_nat); 4319ab25eeb5Syz155240 4320ab25eeb5Syz155240 if (rval == -1) { 4321ab25eeb5Syz155240 if (passp != NULL) 4322ab25eeb5Syz155240 *passp = FR_BLOCK; 4323ab25eeb5Syz155240 fin->fin_flx |= FI_BADNAT; 4324ab25eeb5Syz155240 } 4325ab25eeb5Syz155240 return rval; 4326ab25eeb5Syz155240 } 4327ab25eeb5Syz155240 4328ab25eeb5Syz155240 4329ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */ 4330ab25eeb5Syz155240 /* Function: fr_natin */ 4331ab25eeb5Syz155240 /* Returns: int - -1 == packet failed NAT checks so block it, */ 4332ab25eeb5Syz155240 /* 1 == packet was successfully translated. */ 4333ab25eeb5Syz155240 /* Parameters: fin(I) - pointer to packet information */ 4334ab25eeb5Syz155240 /* nat(I) - pointer to NAT structure */ 4335ab25eeb5Syz155240 /* natadd(I) - flag indicating if it is safe to add frag cache */ 4336ab25eeb5Syz155240 /* nflags(I) - NAT flags set for this packet */ 4337ab25eeb5Syz155240 /* Locks Held: ipf_nat (READ) */ 4338ab25eeb5Syz155240 /* */ 4339ab25eeb5Syz155240 /* Translate a packet coming "in" on an interface. */ 4340ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */ 4341ab25eeb5Syz155240 int fr_natin(fin, nat, natadd, nflags) 4342ab25eeb5Syz155240 fr_info_t *fin; 4343ab25eeb5Syz155240 nat_t *nat; 4344ab25eeb5Syz155240 int natadd; 4345ab25eeb5Syz155240 u_32_t nflags; 4346ab25eeb5Syz155240 { 4347ab25eeb5Syz155240 icmphdr_t *icmp; 434824109627Syx160601 u_short *csump; 4349ab25eeb5Syz155240 tcphdr_t *tcp; 4350ab25eeb5Syz155240 ipnat_t *np; 4351ab25eeb5Syz155240 int i; 4352f4b3ec61Sdh155122 ipf_stack_t *ifs = fin->fin_ifs; 4353ab25eeb5Syz155240 4354*d6c23f6fSyx160601 if (fin->fin_v == 6) { 4355*d6c23f6fSyx160601 #ifdef USE_INET6 4356*d6c23f6fSyx160601 return fr_nat6in(fin, nat, natadd, nflags); 4357*d6c23f6fSyx160601 #else 4358*d6c23f6fSyx160601 return NULL; 4359*d6c23f6fSyx160601 #endif 4360*d6c23f6fSyx160601 } 4361*d6c23f6fSyx160601 4362381a2a9aSdr146992 #if SOLARIS && defined(_KERNEL) 4363*d6c23f6fSyx160601 net_data_t net_data_p = ifs->ifs_ipf_ipv4; 4364381a2a9aSdr146992 #endif 4365381a2a9aSdr146992 4366ab25eeb5Syz155240 tcp = NULL; 4367ab25eeb5Syz155240 csump = NULL; 4368ab25eeb5Syz155240 np = nat->nat_ptr; 4369ab25eeb5Syz155240 fin->fin_fr = nat->nat_fr; 4370ab25eeb5Syz155240 4371ab25eeb5Syz155240 if ((natadd != 0) && (fin->fin_flx & FI_FRAG)) 4372ab25eeb5Syz155240 (void) fr_nat_newfrag(fin, 0, nat); 4373ab25eeb5Syz155240 437415013d88Szf203873 if (np != NULL) { 437515013d88Szf203873 4376ab25eeb5Syz155240 /* ------------------------------------------------------------- */ 4377ab25eeb5Syz155240 /* A few quick notes: */ 4378ab25eeb5Syz155240 /* Following are test conditions prior to calling the */ 4379ab25eeb5Syz155240 /* appr_check routine. */ 4380ab25eeb5Syz155240 /* */ 4381ab25eeb5Syz155240 /* A NULL tcp indicates a non TCP/UDP packet. When dealing */ 4382ab25eeb5Syz155240 /* with a map rule, we attempt to match the packet's */ 4383ab25eeb5Syz155240 /* source port against in_dport, otherwise we'd compare the */ 4384ab25eeb5Syz155240 /* packet's destination. */ 4385ab25eeb5Syz155240 /* ------------------------------------------------------------- */ 4386ab25eeb5Syz155240 if (np->in_apr != NULL) { 4387ab25eeb5Syz155240 i = appr_check(fin, nat); 4388ab25eeb5Syz155240 if (i == -1) { 4389ab25eeb5Syz155240 return -1; 4390ab25eeb5Syz155240 } 4391ab25eeb5Syz155240 } 4392ab25eeb5Syz155240 } 4393ab25eeb5Syz155240 4394ab25eeb5Syz155240 #ifdef IPFILTER_SYNC 4395ab25eeb5Syz155240 ipfsync_update(SMC_NAT, fin, nat->nat_sync); 4396ab25eeb5Syz155240 #endif 4397ab25eeb5Syz155240 4398ab25eeb5Syz155240 MUTEX_ENTER(&nat->nat_lock); 4399ab25eeb5Syz155240 nat->nat_bytes[0] += fin->fin_plen; 4400ab25eeb5Syz155240 nat->nat_pkts[0]++; 4401ab25eeb5Syz155240 MUTEX_EXIT(&nat->nat_lock); 4402ab25eeb5Syz155240 4403ab25eeb5Syz155240 fin->fin_ip->ip_dst = nat->nat_inip; 4404ab25eeb5Syz155240 fin->fin_fi.fi_daddr = nat->nat_inip.s_addr; 4405ab25eeb5Syz155240 if (nflags & IPN_TCPUDP) 4406ab25eeb5Syz155240 tcp = fin->fin_dp; 4407ab25eeb5Syz155240 4408ab25eeb5Syz155240 /* 4409ab25eeb5Syz155240 * Fix up checksums, not by recalculating them, but 4410ab25eeb5Syz155240 * simply computing adjustments. 4411ab25eeb5Syz155240 * Why only do this for some platforms on inbound packets ? 4412ab25eeb5Syz155240 * Because for those that it is done, IP processing is yet to happen 4413ab25eeb5Syz155240 * and so the IPv4 header checksum has not yet been evaluated. 4414ab25eeb5Syz155240 * Perhaps it should always be done for the benefit of things like 4415ab25eeb5Syz155240 * fast forwarding (so that it doesn't need to be recomputed) but with 4416ab25eeb5Syz155240 * header checksum offloading, perhaps it is a moot point. 4417ab25eeb5Syz155240 */ 4418ab25eeb5Syz155240 #if !defined(_KERNEL) || defined(MENTAT) || defined(__sgi) || \ 4419ab25eeb5Syz155240 defined(__osf__) || defined(linux) 4420ab25eeb5Syz155240 if (nat->nat_dir == NAT_OUTBOUND) 4421381a2a9aSdr146992 fix_incksum(&fin->fin_ip->ip_sum, nat->nat_ipsumd); 4422ab25eeb5Syz155240 else 4423381a2a9aSdr146992 fix_outcksum(&fin->fin_ip->ip_sum, nat->nat_ipsumd); 4424ab25eeb5Syz155240 #endif 4425ab25eeb5Syz155240 4426ab25eeb5Syz155240 if (!(fin->fin_flx & FI_SHORT) && (fin->fin_off == 0)) { 4427ab25eeb5Syz155240 if ((nat->nat_inport != 0) && (nflags & IPN_TCPUDP)) { 4428ab25eeb5Syz155240 tcp->th_dport = nat->nat_inport; 4429ab25eeb5Syz155240 fin->fin_data[1] = ntohs(nat->nat_inport); 4430ab25eeb5Syz155240 } 4431ab25eeb5Syz155240 4432ab25eeb5Syz155240 4433ab25eeb5Syz155240 if ((nat->nat_inport != 0) && (nflags & IPN_ICMPQUERY)) { 4434ab25eeb5Syz155240 icmp = fin->fin_dp; 4435ab25eeb5Syz155240 4436ab25eeb5Syz155240 icmp->icmp_id = nat->nat_inport; 4437ab25eeb5Syz155240 } 4438ab25eeb5Syz155240 4439ab25eeb5Syz155240 csump = nat_proto(fin, nat, nflags); 4440ab25eeb5Syz155240 } 4441ab25eeb5Syz155240 4442ab25eeb5Syz155240 nat_update(fin, nat, np); 4443ab25eeb5Syz155240 4444ab25eeb5Syz155240 /* 444524109627Syx160601 * In case they are being forwarded, inbound packets always need to have 444624109627Syx160601 * their checksum adjusted even if hardware checksum validation said OK. 4447ab25eeb5Syz155240 */ 4448ab25eeb5Syz155240 if (csump != NULL) { 4449ab25eeb5Syz155240 if (nat->nat_dir == NAT_OUTBOUND) 445024109627Syx160601 fix_incksum(csump, nat->nat_sumd[0]); 4451ab25eeb5Syz155240 else 445224109627Syx160601 fix_outcksum(csump, nat->nat_sumd[0]); 4453ab25eeb5Syz155240 } 445424109627Syx160601 445524109627Syx160601 #if SOLARIS && defined(_KERNEL) 445624109627Syx160601 if (nflags & IPN_TCPUDP && 445724109627Syx160601 NET_IS_HCK_L4_PART(net_data_p, fin->fin_m)) { 445824109627Syx160601 /* 445924109627Syx160601 * Need to adjust the partial checksum result stored in 446024109627Syx160601 * db_cksum16, which will be used for validation in IP. 446124109627Syx160601 * See IP_CKSUM_RECV(). 446224109627Syx160601 * Adjustment data should be the inverse of the IP address 446324109627Syx160601 * changes, because db_cksum16 is supposed to be the complement 446424109627Syx160601 * of the pesudo header. 446524109627Syx160601 */ 446624109627Syx160601 csump = &fin->fin_m->b_datap->db_cksum16; 446724109627Syx160601 if (nat->nat_dir == NAT_OUTBOUND) 446824109627Syx160601 fix_outcksum(csump, nat->nat_sumd[1]); 446924109627Syx160601 else 447024109627Syx160601 fix_incksum(csump, nat->nat_sumd[1]); 447124109627Syx160601 } 447224109627Syx160601 #endif 447324109627Syx160601 4474cbded9aeSdr146992 ifs->ifs_nat_stats.ns_mapped[0]++; 4475ab25eeb5Syz155240 fin->fin_flx |= FI_NATED; 4476ab25eeb5Syz155240 if (np != NULL && np->in_tag.ipt_num[0] != 0) 4477ab25eeb5Syz155240 fin->fin_nattag = &np->in_tag; 4478ab25eeb5Syz155240 return 1; 4479ab25eeb5Syz155240 } 4480ab25eeb5Syz155240 4481ab25eeb5Syz155240 4482ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */ 4483ab25eeb5Syz155240 /* Function: nat_proto */ 4484ab25eeb5Syz155240 /* Returns: u_short* - pointer to transport header checksum to update, */ 4485ab25eeb5Syz155240 /* NULL if the transport protocol is not recognised */ 4486ab25eeb5Syz155240 /* as needing a checksum update. */ 4487ab25eeb5Syz155240 /* Parameters: fin(I) - pointer to packet information */ 4488ab25eeb5Syz155240 /* nat(I) - pointer to NAT structure */ 4489ab25eeb5Syz155240 /* nflags(I) - NAT flags set for this packet */ 4490ab25eeb5Syz155240 /* */ 4491ab25eeb5Syz155240 /* Return the pointer to the checksum field for each protocol so understood.*/ 4492ab25eeb5Syz155240 /* If support for making other changes to a protocol header is required, */ 4493ab25eeb5Syz155240 /* that is not strictly 'address' translation, such as clamping the MSS in */ 4494ab25eeb5Syz155240 /* TCP down to a specific value, then do it from here. */ 4495ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */ 4496ab25eeb5Syz155240 u_short *nat_proto(fin, nat, nflags) 4497ab25eeb5Syz155240 fr_info_t *fin; 4498ab25eeb5Syz155240 nat_t *nat; 4499ab25eeb5Syz155240 u_int nflags; 4500ab25eeb5Syz155240 { 4501ab25eeb5Syz155240 icmphdr_t *icmp; 4502*d6c23f6fSyx160601 struct icmp6_hdr *icmp6; 4503ab25eeb5Syz155240 u_short *csump; 4504ab25eeb5Syz155240 tcphdr_t *tcp; 4505ab25eeb5Syz155240 udphdr_t *udp; 4506ab25eeb5Syz155240 4507ab25eeb5Syz155240 csump = NULL; 4508ab25eeb5Syz155240 if (fin->fin_out == 0) { 4509ab25eeb5Syz155240 fin->fin_rev = (nat->nat_dir == NAT_OUTBOUND); 4510ab25eeb5Syz155240 } else { 4511ab25eeb5Syz155240 fin->fin_rev = (nat->nat_dir == NAT_INBOUND); 4512ab25eeb5Syz155240 } 4513ab25eeb5Syz155240 4514ab25eeb5Syz155240 switch (fin->fin_p) 4515ab25eeb5Syz155240 { 4516ab25eeb5Syz155240 case IPPROTO_TCP : 4517ab25eeb5Syz155240 tcp = fin->fin_dp; 4518ab25eeb5Syz155240 4519ab25eeb5Syz155240 csump = &tcp->th_sum; 4520ab25eeb5Syz155240 4521ab25eeb5Syz155240 /* 4522ab25eeb5Syz155240 * Do a MSS CLAMPING on a SYN packet, 4523ab25eeb5Syz155240 * only deal IPv4 for now. 4524ab25eeb5Syz155240 */ 4525ab25eeb5Syz155240 if ((nat->nat_mssclamp != 0) && (tcp->th_flags & TH_SYN) != 0) 4526381a2a9aSdr146992 nat_mssclamp(tcp, nat->nat_mssclamp, csump); 4527ab25eeb5Syz155240 4528ab25eeb5Syz155240 break; 4529ab25eeb5Syz155240 4530ab25eeb5Syz155240 case IPPROTO_UDP : 4531ab25eeb5Syz155240 udp = fin->fin_dp; 4532ab25eeb5Syz155240 4533ab25eeb5Syz155240 if (udp->uh_sum) 4534ab25eeb5Syz155240 csump = &udp->uh_sum; 4535ab25eeb5Syz155240 break; 4536ab25eeb5Syz155240 4537ab25eeb5Syz155240 case IPPROTO_ICMP : 4538ab25eeb5Syz155240 icmp = fin->fin_dp; 4539ab25eeb5Syz155240 4540ab25eeb5Syz155240 if ((nflags & IPN_ICMPQUERY) != 0) { 4541ab25eeb5Syz155240 if (icmp->icmp_cksum != 0) 4542ab25eeb5Syz155240 csump = &icmp->icmp_cksum; 4543ab25eeb5Syz155240 } 4544ab25eeb5Syz155240 break; 4545*d6c23f6fSyx160601 4546*d6c23f6fSyx160601 case IPPROTO_ICMPV6 : 4547*d6c23f6fSyx160601 icmp6 = fin->fin_dp; 4548*d6c23f6fSyx160601 4549*d6c23f6fSyx160601 if ((nflags & IPN_ICMPQUERY) != 0) { 4550*d6c23f6fSyx160601 if (icmp6->icmp6_cksum != 0) 4551*d6c23f6fSyx160601 csump = &icmp6->icmp6_cksum; 4552*d6c23f6fSyx160601 } 4553*d6c23f6fSyx160601 break; 4554ab25eeb5Syz155240 } 4555ab25eeb5Syz155240 return csump; 4556ab25eeb5Syz155240 } 4557ab25eeb5Syz155240 4558ab25eeb5Syz155240 4559ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */ 4560ab25eeb5Syz155240 /* Function: fr_natunload */ 4561ab25eeb5Syz155240 /* Returns: Nil */ 4562ab25eeb5Syz155240 /* Parameters: Nil */ 4563ab25eeb5Syz155240 /* */ 4564ab25eeb5Syz155240 /* Free all memory used by NAT structures allocated at runtime. */ 4565ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */ 4566f4b3ec61Sdh155122 void fr_natunload(ifs) 4567f4b3ec61Sdh155122 ipf_stack_t *ifs; 4568ab25eeb5Syz155240 { 4569ab25eeb5Syz155240 ipftq_t *ifq, *ifqnext; 4570ab25eeb5Syz155240 4571f4b3ec61Sdh155122 (void) nat_clearlist(ifs); 4572f4b3ec61Sdh155122 (void) nat_flushtable(ifs); 4573ab25eeb5Syz155240 4574ab25eeb5Syz155240 /* 4575ab25eeb5Syz155240 * Proxy timeout queues are not cleaned here because although they 4576ab25eeb5Syz155240 * exist on the NAT list, appr_unload is called after fr_natunload 4577ab25eeb5Syz155240 * and the proxies actually are responsible for them being created. 4578ab25eeb5Syz155240 * Should the proxy timeouts have their own list? There's no real 4579ab25eeb5Syz155240 * justification as this is the only complication. 4580ab25eeb5Syz155240 */ 4581f4b3ec61Sdh155122 for (ifq = ifs->ifs_nat_utqe; ifq != NULL; ifq = ifqnext) { 4582ab25eeb5Syz155240 ifqnext = ifq->ifq_next; 4583ab25eeb5Syz155240 if (((ifq->ifq_flags & IFQF_PROXY) == 0) && 4584ab25eeb5Syz155240 (fr_deletetimeoutqueue(ifq) == 0)) 4585f4b3ec61Sdh155122 fr_freetimeoutqueue(ifq, ifs); 4586ab25eeb5Syz155240 } 4587ab25eeb5Syz155240 4588f4b3ec61Sdh155122 if (ifs->ifs_nat_table[0] != NULL) { 4589f4b3ec61Sdh155122 KFREES(ifs->ifs_nat_table[0], 4590f4b3ec61Sdh155122 sizeof(nat_t *) * ifs->ifs_ipf_nattable_sz); 4591f4b3ec61Sdh155122 ifs->ifs_nat_table[0] = NULL; 4592ab25eeb5Syz155240 } 4593f4b3ec61Sdh155122 if (ifs->ifs_nat_table[1] != NULL) { 4594f4b3ec61Sdh155122 KFREES(ifs->ifs_nat_table[1], 4595f4b3ec61Sdh155122 sizeof(nat_t *) * ifs->ifs_ipf_nattable_sz); 4596f4b3ec61Sdh155122 ifs->ifs_nat_table[1] = NULL; 4597ab25eeb5Syz155240 } 4598f4b3ec61Sdh155122 if (ifs->ifs_nat_rules != NULL) { 4599f4b3ec61Sdh155122 KFREES(ifs->ifs_nat_rules, 4600f4b3ec61Sdh155122 sizeof(ipnat_t *) * ifs->ifs_ipf_natrules_sz); 4601f4b3ec61Sdh155122 ifs->ifs_nat_rules = NULL; 4602ab25eeb5Syz155240 } 4603f4b3ec61Sdh155122 if (ifs->ifs_rdr_rules != NULL) { 4604f4b3ec61Sdh155122 KFREES(ifs->ifs_rdr_rules, 4605f4b3ec61Sdh155122 sizeof(ipnat_t *) * ifs->ifs_ipf_rdrrules_sz); 4606f4b3ec61Sdh155122 ifs->ifs_rdr_rules = NULL; 4607ab25eeb5Syz155240 } 4608f4b3ec61Sdh155122 if (ifs->ifs_maptable != NULL) { 4609f4b3ec61Sdh155122 KFREES(ifs->ifs_maptable, 4610f4b3ec61Sdh155122 sizeof(hostmap_t *) * ifs->ifs_ipf_hostmap_sz); 4611f4b3ec61Sdh155122 ifs->ifs_maptable = NULL; 4612ab25eeb5Syz155240 } 4613f4b3ec61Sdh155122 if (ifs->ifs_nat_stats.ns_bucketlen[0] != NULL) { 4614f4b3ec61Sdh155122 KFREES(ifs->ifs_nat_stats.ns_bucketlen[0], 4615f4b3ec61Sdh155122 sizeof(u_long *) * ifs->ifs_ipf_nattable_sz); 4616f4b3ec61Sdh155122 ifs->ifs_nat_stats.ns_bucketlen[0] = NULL; 4617ab25eeb5Syz155240 } 4618f4b3ec61Sdh155122 if (ifs->ifs_nat_stats.ns_bucketlen[1] != NULL) { 4619f4b3ec61Sdh155122 KFREES(ifs->ifs_nat_stats.ns_bucketlen[1], 4620f4b3ec61Sdh155122 sizeof(u_long *) * ifs->ifs_ipf_nattable_sz); 4621f4b3ec61Sdh155122 ifs->ifs_nat_stats.ns_bucketlen[1] = NULL; 4622ab25eeb5Syz155240 } 4623ab25eeb5Syz155240 4624f4b3ec61Sdh155122 if (ifs->ifs_fr_nat_maxbucket_reset == 1) 4625f4b3ec61Sdh155122 ifs->ifs_fr_nat_maxbucket = 0; 4626ab25eeb5Syz155240 4627f4b3ec61Sdh155122 if (ifs->ifs_fr_nat_init == 1) { 4628f4b3ec61Sdh155122 ifs->ifs_fr_nat_init = 0; 4629f4b3ec61Sdh155122 fr_sttab_destroy(ifs->ifs_nat_tqb); 4630ab25eeb5Syz155240 4631f4b3ec61Sdh155122 RW_DESTROY(&ifs->ifs_ipf_natfrag); 4632f4b3ec61Sdh155122 RW_DESTROY(&ifs->ifs_ipf_nat); 4633ab25eeb5Syz155240 4634f4b3ec61Sdh155122 MUTEX_DESTROY(&ifs->ifs_ipf_nat_new); 4635f4b3ec61Sdh155122 MUTEX_DESTROY(&ifs->ifs_ipf_natio); 4636ab25eeb5Syz155240 4637f4b3ec61Sdh155122 MUTEX_DESTROY(&ifs->ifs_nat_udptq.ifq_lock); 4638f4b3ec61Sdh155122 MUTEX_DESTROY(&ifs->ifs_nat_icmptq.ifq_lock); 4639f4b3ec61Sdh155122 MUTEX_DESTROY(&ifs->ifs_nat_iptq.ifq_lock); 4640ab25eeb5Syz155240 } 4641ab25eeb5Syz155240 } 4642ab25eeb5Syz155240 4643ab25eeb5Syz155240 4644ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */ 4645ab25eeb5Syz155240 /* Function: fr_natexpire */ 4646ab25eeb5Syz155240 /* Returns: Nil */ 4647ab25eeb5Syz155240 /* Parameters: Nil */ 4648ab25eeb5Syz155240 /* */ 4649ab25eeb5Syz155240 /* Check all of the timeout queues for entries at the top which need to be */ 4650ab25eeb5Syz155240 /* expired. */ 4651ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */ 4652f4b3ec61Sdh155122 void fr_natexpire(ifs) 4653f4b3ec61Sdh155122 ipf_stack_t *ifs; 4654ab25eeb5Syz155240 { 4655ab25eeb5Syz155240 ipftq_t *ifq, *ifqnext; 4656ab25eeb5Syz155240 ipftqent_t *tqe, *tqn; 4657ab25eeb5Syz155240 int i; 4658ab25eeb5Syz155240 SPL_INT(s); 4659ab25eeb5Syz155240 4660ab25eeb5Syz155240 SPL_NET(s); 4661f4b3ec61Sdh155122 WRITE_ENTER(&ifs->ifs_ipf_nat); 4662f4b3ec61Sdh155122 for (ifq = ifs->ifs_nat_tqb, i = 0; ifq != NULL; ifq = ifq->ifq_next) { 4663ab25eeb5Syz155240 for (tqn = ifq->ifq_head; ((tqe = tqn) != NULL); i++) { 4664f4b3ec61Sdh155122 if (tqe->tqe_die > ifs->ifs_fr_ticks) 4665ab25eeb5Syz155240 break; 4666ab25eeb5Syz155240 tqn = tqe->tqe_next; 4667f4b3ec61Sdh155122 nat_delete(tqe->tqe_parent, NL_EXPIRE, ifs); 4668ab25eeb5Syz155240 } 4669ab25eeb5Syz155240 } 4670ab25eeb5Syz155240 4671f4b3ec61Sdh155122 for (ifq = ifs->ifs_nat_utqe; ifq != NULL; ifq = ifqnext) { 4672ab25eeb5Syz155240 ifqnext = ifq->ifq_next; 4673ab25eeb5Syz155240 4674ab25eeb5Syz155240 for (tqn = ifq->ifq_head; ((tqe = tqn) != NULL); i++) { 4675f4b3ec61Sdh155122 if (tqe->tqe_die > ifs->ifs_fr_ticks) 4676ab25eeb5Syz155240 break; 4677ab25eeb5Syz155240 tqn = tqe->tqe_next; 4678f4b3ec61Sdh155122 nat_delete(tqe->tqe_parent, NL_EXPIRE, ifs); 4679ab25eeb5Syz155240 } 4680ab25eeb5Syz155240 } 4681ab25eeb5Syz155240 4682f4b3ec61Sdh155122 for (ifq = ifs->ifs_nat_utqe; ifq != NULL; ifq = ifqnext) { 4683ab25eeb5Syz155240 ifqnext = ifq->ifq_next; 4684ab25eeb5Syz155240 4685ab25eeb5Syz155240 if (((ifq->ifq_flags & IFQF_DELETE) != 0) && 4686ab25eeb5Syz155240 (ifq->ifq_ref == 0)) { 4687f4b3ec61Sdh155122 fr_freetimeoutqueue(ifq, ifs); 4688ab25eeb5Syz155240 } 4689ab25eeb5Syz155240 } 4690ab25eeb5Syz155240 46913805c50fSan207044 if (ifs->ifs_nat_doflush != 0) { 46923805c50fSan207044 (void) nat_extraflush(2, ifs); 46933805c50fSan207044 ifs->ifs_nat_doflush = 0; 46943805c50fSan207044 } 46953805c50fSan207044 4696f4b3ec61Sdh155122 RWLOCK_EXIT(&ifs->ifs_ipf_nat); 4697ab25eeb5Syz155240 SPL_X(s); 4698ab25eeb5Syz155240 } 4699ab25eeb5Syz155240 4700ab25eeb5Syz155240 4701ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */ 4702381a2a9aSdr146992 /* Function: fr_nataddrsync */ 4703ab25eeb5Syz155240 /* Returns: Nil */ 4704ab25eeb5Syz155240 /* Parameters: ifp(I) - pointer to network interface */ 4705381a2a9aSdr146992 /* addr(I) - pointer to new network address */ 4706ab25eeb5Syz155240 /* */ 4707ab25eeb5Syz155240 /* Walk through all of the currently active NAT sessions, looking for those */ 4708381a2a9aSdr146992 /* which need to have their translated address updated (where the interface */ 4709381a2a9aSdr146992 /* matches the one passed in) and change it, recalculating the checksum sum */ 4710381a2a9aSdr146992 /* difference too. */ 4711ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */ 4712*d6c23f6fSyx160601 void fr_nataddrsync(v, ifp, addr, ifs) 4713*d6c23f6fSyx160601 int v; 4714ab25eeb5Syz155240 void *ifp; 4715*d6c23f6fSyx160601 void *addr; 4716f4b3ec61Sdh155122 ipf_stack_t *ifs; 4717ab25eeb5Syz155240 { 4718ab25eeb5Syz155240 u_32_t sum1, sum2, sumd; 4719ab25eeb5Syz155240 nat_t *nat; 4720381a2a9aSdr146992 ipnat_t *np; 4721ab25eeb5Syz155240 SPL_INT(s); 4722ab25eeb5Syz155240 4723f4b3ec61Sdh155122 if (ifs->ifs_fr_running <= 0) 4724ab25eeb5Syz155240 return; 4725ab25eeb5Syz155240 4726ab25eeb5Syz155240 SPL_NET(s); 4727f4b3ec61Sdh155122 WRITE_ENTER(&ifs->ifs_ipf_nat); 4728ab25eeb5Syz155240 4729f4b3ec61Sdh155122 if (ifs->ifs_fr_running <= 0) { 4730f4b3ec61Sdh155122 RWLOCK_EXIT(&ifs->ifs_ipf_nat); 4731ab25eeb5Syz155240 return; 4732ab25eeb5Syz155240 } 4733ab25eeb5Syz155240 4734381a2a9aSdr146992 /* 4735381a2a9aSdr146992 * Change IP addresses for NAT sessions for any protocol except TCP 4736381a2a9aSdr146992 * since it will break the TCP connection anyway. The only rules 4737381a2a9aSdr146992 * which will get changed are those which are "map ... -> 0/32", 4738381a2a9aSdr146992 * where the rule specifies the address is taken from the interface. 4739381a2a9aSdr146992 */ 4740f4b3ec61Sdh155122 for (nat = ifs->ifs_nat_instances; nat; nat = nat->nat_next) { 4741381a2a9aSdr146992 if (addr != NULL) { 4742381a2a9aSdr146992 if (((ifp != NULL) && ifp != (nat->nat_ifps[0])) || 4743381a2a9aSdr146992 ((nat->nat_flags & IPN_TCP) != 0)) 4744ab25eeb5Syz155240 continue; 4745*d6c23f6fSyx160601 if ((np = nat->nat_ptr) == NULL) 4746ab25eeb5Syz155240 continue; 4747*d6c23f6fSyx160601 if (v == 4 && np->in_v == 4) { 4748*d6c23f6fSyx160601 if (np->in_nip || np->in_outmsk != 0xffffffff) 4749*d6c23f6fSyx160601 continue; 4750ab25eeb5Syz155240 /* 4751*d6c23f6fSyx160601 * Change the map-to address to be the same as 4752*d6c23f6fSyx160601 * the new one. 4753ab25eeb5Syz155240 */ 4754ab25eeb5Syz155240 sum1 = nat->nat_outip.s_addr; 4755*d6c23f6fSyx160601 nat->nat_outip = *(struct in_addr *)addr; 4756381a2a9aSdr146992 sum2 = nat->nat_outip.s_addr; 4757*d6c23f6fSyx160601 } else if (v == 6 && np->in_v == 6) { 4758*d6c23f6fSyx160601 if (!IP6_ISZERO(&np->in_next6.in6) || 4759*d6c23f6fSyx160601 !IP6_ISONES(&np->in_out[1].in6)) 4760*d6c23f6fSyx160601 continue; 4761*d6c23f6fSyx160601 /* 4762*d6c23f6fSyx160601 * Change the map-to address to be the same as 4763*d6c23f6fSyx160601 * the new one. 4764*d6c23f6fSyx160601 */ 4765*d6c23f6fSyx160601 nat->nat_outip6.in6 = *(struct in6_addr *)addr; 4766*d6c23f6fSyx160601 } else 4767*d6c23f6fSyx160601 continue; 4768381a2a9aSdr146992 4769381a2a9aSdr146992 } else if (((ifp == NULL) || (ifp == nat->nat_ifps[0])) && 4770*d6c23f6fSyx160601 !(nat->nat_flags & IPN_TCP) && (np = nat->nat_ptr)) { 4771*d6c23f6fSyx160601 if (np->in_v == 4 && (v == 4 || v == 0)) { 4772381a2a9aSdr146992 struct in_addr in; 4773*d6c23f6fSyx160601 if (np->in_outmsk != 0xffffffff || np->in_nip) 4774*d6c23f6fSyx160601 continue; 4775381a2a9aSdr146992 /* 4776*d6c23f6fSyx160601 * Change the map-to address to be the same as 4777*d6c23f6fSyx160601 * the new one. 4778381a2a9aSdr146992 */ 4779381a2a9aSdr146992 sum1 = nat->nat_outip.s_addr; 4780381a2a9aSdr146992 if (fr_ifpaddr(4, FRI_NORMAL, nat->nat_ifps[0], 4781f4b3ec61Sdh155122 &in, NULL, ifs) != -1) 4782ab25eeb5Syz155240 nat->nat_outip = in; 4783ab25eeb5Syz155240 sum2 = nat->nat_outip.s_addr; 4784*d6c23f6fSyx160601 } else if (np->in_v == 6 && (v == 6 || v == 0)) { 4785*d6c23f6fSyx160601 struct in6_addr in6; 4786*d6c23f6fSyx160601 if (!IP6_ISZERO(&np->in_next6.in6) || 4787*d6c23f6fSyx160601 !IP6_ISONES(&np->in_out[1].in6)) 4788*d6c23f6fSyx160601 continue; 4789*d6c23f6fSyx160601 /* 4790*d6c23f6fSyx160601 * Change the map-to address to be the same as 4791*d6c23f6fSyx160601 * the new one. 4792*d6c23f6fSyx160601 */ 4793*d6c23f6fSyx160601 if (fr_ifpaddr(6, FRI_NORMAL, nat->nat_ifps[0], 4794*d6c23f6fSyx160601 (void *)&in6, NULL, ifs) != -1) 4795*d6c23f6fSyx160601 nat->nat_outip6.in6 = in6; 4796*d6c23f6fSyx160601 } else 4797*d6c23f6fSyx160601 continue; 4798381a2a9aSdr146992 } else { 4799381a2a9aSdr146992 continue; 4800381a2a9aSdr146992 } 4801ab25eeb5Syz155240 4802ab25eeb5Syz155240 if (sum1 == sum2) 4803ab25eeb5Syz155240 continue; 4804ab25eeb5Syz155240 /* 4805ab25eeb5Syz155240 * Readjust the checksum adjustment to take into 4806ab25eeb5Syz155240 * account the new IP#. 4807ab25eeb5Syz155240 */ 4808ab25eeb5Syz155240 CALC_SUMD(sum1, sum2, sumd); 4809ab25eeb5Syz155240 /* XXX - dont change for TCP when solaris does 4810ab25eeb5Syz155240 * hardware checksumming. 4811ab25eeb5Syz155240 */ 4812ab25eeb5Syz155240 sumd += nat->nat_sumd[0]; 4813ab25eeb5Syz155240 nat->nat_sumd[0] = (sumd & 0xffff) + (sumd >> 16); 4814ab25eeb5Syz155240 nat->nat_sumd[1] = nat->nat_sumd[0]; 4815ab25eeb5Syz155240 } 4816381a2a9aSdr146992 4817f4b3ec61Sdh155122 RWLOCK_EXIT(&ifs->ifs_ipf_nat); 4818381a2a9aSdr146992 SPL_X(s); 4819381a2a9aSdr146992 } 4820381a2a9aSdr146992 4821381a2a9aSdr146992 4822381a2a9aSdr146992 /* ------------------------------------------------------------------------ */ 4823381a2a9aSdr146992 /* Function: fr_natifpsync */ 4824381a2a9aSdr146992 /* Returns: Nil */ 4825381a2a9aSdr146992 /* Parameters: action(I) - how we are syncing */ 4826381a2a9aSdr146992 /* ifp(I) - pointer to network interface */ 4827381a2a9aSdr146992 /* name(I) - name of interface to sync to */ 4828381a2a9aSdr146992 /* */ 4829381a2a9aSdr146992 /* This function is used to resync the mapping of interface names and their */ 4830381a2a9aSdr146992 /* respective 'pointers'. For "action == IPFSYNC_RESYNC", resync all */ 4831381a2a9aSdr146992 /* interfaces by doing a new lookup of name to 'pointer'. For "action == */ 4832381a2a9aSdr146992 /* IPFSYNC_NEWIFP", treat ifp as the new pointer value associated with */ 4833381a2a9aSdr146992 /* "name" and for "action == IPFSYNC_OLDIFP", ifp is a pointer for which */ 4834381a2a9aSdr146992 /* there is no longer any interface associated with it. */ 4835381a2a9aSdr146992 /* ------------------------------------------------------------------------ */ 4836*d6c23f6fSyx160601 void fr_natifpsync(action, v, ifp, name, ifs) 4837*d6c23f6fSyx160601 int action, v; 4838381a2a9aSdr146992 void *ifp; 4839381a2a9aSdr146992 char *name; 4840f4b3ec61Sdh155122 ipf_stack_t *ifs; 4841381a2a9aSdr146992 { 4842381a2a9aSdr146992 #if defined(_KERNEL) && !defined(MENTAT) && defined(USE_SPL) 4843381a2a9aSdr146992 int s; 4844381a2a9aSdr146992 #endif 4845381a2a9aSdr146992 nat_t *nat; 4846381a2a9aSdr146992 ipnat_t *n; 4847*d6c23f6fSyx160601 int nv; 4848381a2a9aSdr146992 4849f4b3ec61Sdh155122 if (ifs->ifs_fr_running <= 0) 4850381a2a9aSdr146992 return; 4851381a2a9aSdr146992 4852381a2a9aSdr146992 SPL_NET(s); 4853f4b3ec61Sdh155122 WRITE_ENTER(&ifs->ifs_ipf_nat); 4854381a2a9aSdr146992 4855f4b3ec61Sdh155122 if (ifs->ifs_fr_running <= 0) { 4856f4b3ec61Sdh155122 RWLOCK_EXIT(&ifs->ifs_ipf_nat); 4857381a2a9aSdr146992 return; 4858381a2a9aSdr146992 } 4859381a2a9aSdr146992 4860381a2a9aSdr146992 switch (action) 4861381a2a9aSdr146992 { 4862381a2a9aSdr146992 case IPFSYNC_RESYNC : 4863f4b3ec61Sdh155122 for (nat = ifs->ifs_nat_instances; nat; nat = nat->nat_next) { 4864*d6c23f6fSyx160601 nv = (v == 0) ? nat->nat_v : v; 4865*d6c23f6fSyx160601 if (nat->nat_v != nv) 4866*d6c23f6fSyx160601 continue; 4867381a2a9aSdr146992 if ((ifp == nat->nat_ifps[0]) || 4868381a2a9aSdr146992 (nat->nat_ifps[0] == (void *)-1)) { 4869381a2a9aSdr146992 nat->nat_ifps[0] = 4870*d6c23f6fSyx160601 fr_resolvenic(nat->nat_ifnames[0], nv, ifs); 4871381a2a9aSdr146992 } 4872381a2a9aSdr146992 4873381a2a9aSdr146992 if ((ifp == nat->nat_ifps[1]) || 4874381a2a9aSdr146992 (nat->nat_ifps[1] == (void *)-1)) { 4875381a2a9aSdr146992 nat->nat_ifps[1] = 4876*d6c23f6fSyx160601 fr_resolvenic(nat->nat_ifnames[1], nv, ifs); 4877381a2a9aSdr146992 } 4878ab25eeb5Syz155240 } 4879ab25eeb5Syz155240 4880f4b3ec61Sdh155122 for (n = ifs->ifs_nat_list; (n != NULL); n = n->in_next) { 4881*d6c23f6fSyx160601 nv = (v == 0) ? (int)n->in_v : v; 4882*d6c23f6fSyx160601 if ((int)n->in_v != nv) 4883*d6c23f6fSyx160601 continue; 4884381a2a9aSdr146992 if (n->in_ifps[0] == ifp || 4885381a2a9aSdr146992 n->in_ifps[0] == (void *)-1) { 4886381a2a9aSdr146992 n->in_ifps[0] = 4887*d6c23f6fSyx160601 fr_resolvenic(n->in_ifnames[0], nv, ifs); 4888381a2a9aSdr146992 } 4889381a2a9aSdr146992 if (n->in_ifps[1] == ifp || 4890381a2a9aSdr146992 n->in_ifps[1] == (void *)-1) { 4891381a2a9aSdr146992 n->in_ifps[1] = 4892*d6c23f6fSyx160601 fr_resolvenic(n->in_ifnames[1], nv, ifs); 4893381a2a9aSdr146992 } 4894381a2a9aSdr146992 } 4895381a2a9aSdr146992 break; 4896381a2a9aSdr146992 case IPFSYNC_NEWIFP : 4897f4b3ec61Sdh155122 for (nat = ifs->ifs_nat_instances; nat; nat = nat->nat_next) { 4898*d6c23f6fSyx160601 if (nat->nat_v != v) 4899*d6c23f6fSyx160601 continue; 4900381a2a9aSdr146992 if (!strncmp(name, nat->nat_ifnames[0], 4901381a2a9aSdr146992 sizeof(nat->nat_ifnames[0]))) 4902381a2a9aSdr146992 nat->nat_ifps[0] = ifp; 4903381a2a9aSdr146992 if (!strncmp(name, nat->nat_ifnames[1], 4904381a2a9aSdr146992 sizeof(nat->nat_ifnames[1]))) 4905381a2a9aSdr146992 nat->nat_ifps[1] = ifp; 4906381a2a9aSdr146992 } 4907f4b3ec61Sdh155122 for (n = ifs->ifs_nat_list; (n != NULL); n = n->in_next) { 4908*d6c23f6fSyx160601 if ((int)n->in_v != v) 4909*d6c23f6fSyx160601 continue; 4910381a2a9aSdr146992 if (!strncmp(name, n->in_ifnames[0], 4911381a2a9aSdr146992 sizeof(n->in_ifnames[0]))) 4912381a2a9aSdr146992 n->in_ifps[0] = ifp; 4913381a2a9aSdr146992 if (!strncmp(name, n->in_ifnames[1], 4914381a2a9aSdr146992 sizeof(n->in_ifnames[1]))) 4915381a2a9aSdr146992 n->in_ifps[1] = ifp; 4916381a2a9aSdr146992 } 4917381a2a9aSdr146992 break; 4918381a2a9aSdr146992 case IPFSYNC_OLDIFP : 4919f4b3ec61Sdh155122 for (nat = ifs->ifs_nat_instances; nat; nat = nat->nat_next) { 4920*d6c23f6fSyx160601 if (nat->nat_v != v) 4921*d6c23f6fSyx160601 continue; 4922381a2a9aSdr146992 if (ifp == nat->nat_ifps[0]) 4923381a2a9aSdr146992 nat->nat_ifps[0] = (void *)-1; 4924381a2a9aSdr146992 if (ifp == nat->nat_ifps[1]) 4925381a2a9aSdr146992 nat->nat_ifps[1] = (void *)-1; 4926381a2a9aSdr146992 } 4927f4b3ec61Sdh155122 for (n = ifs->ifs_nat_list; (n != NULL); n = n->in_next) { 4928*d6c23f6fSyx160601 if ((int)n->in_v != v) 4929*d6c23f6fSyx160601 continue; 4930381a2a9aSdr146992 if (n->in_ifps[0] == ifp) 4931381a2a9aSdr146992 n->in_ifps[0] = (void *)-1; 4932381a2a9aSdr146992 if (n->in_ifps[1] == ifp) 4933381a2a9aSdr146992 n->in_ifps[1] = (void *)-1; 4934381a2a9aSdr146992 } 4935381a2a9aSdr146992 break; 4936ab25eeb5Syz155240 } 4937f4b3ec61Sdh155122 RWLOCK_EXIT(&ifs->ifs_ipf_nat); 4938ab25eeb5Syz155240 SPL_X(s); 4939ab25eeb5Syz155240 } 4940ab25eeb5Syz155240 4941ab25eeb5Syz155240 4942ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */ 4943ab25eeb5Syz155240 /* Function: nat_icmpquerytype4 */ 4944ab25eeb5Syz155240 /* Returns: int - 1 == success, 0 == failure */ 4945ab25eeb5Syz155240 /* Parameters: icmptype(I) - ICMP type number */ 4946ab25eeb5Syz155240 /* */ 4947ab25eeb5Syz155240 /* Tests to see if the ICMP type number passed is a query/response type or */ 4948ab25eeb5Syz155240 /* not. */ 4949ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */ 4950ab25eeb5Syz155240 static INLINE int nat_icmpquerytype4(icmptype) 4951ab25eeb5Syz155240 int icmptype; 4952ab25eeb5Syz155240 { 4953ab25eeb5Syz155240 4954ab25eeb5Syz155240 /* 4955ab25eeb5Syz155240 * For the ICMP query NAT code, it is essential that both the query 4956ab25eeb5Syz155240 * and the reply match on the NAT rule. Because the NAT structure 4957ab25eeb5Syz155240 * does not keep track of the icmptype, and a single NAT structure 4958ab25eeb5Syz155240 * is used for all icmp types with the same src, dest and id, we 4959ab25eeb5Syz155240 * simply define the replies as queries as well. The funny thing is, 4960ab25eeb5Syz155240 * altough it seems silly to call a reply a query, this is exactly 4961ab25eeb5Syz155240 * as it is defined in the IPv4 specification 4962ab25eeb5Syz155240 */ 4963ab25eeb5Syz155240 4964ab25eeb5Syz155240 switch (icmptype) 4965ab25eeb5Syz155240 { 4966ab25eeb5Syz155240 4967ab25eeb5Syz155240 case ICMP_ECHOREPLY: 4968ab25eeb5Syz155240 case ICMP_ECHO: 4969ab25eeb5Syz155240 /* route aedvertisement/solliciation is currently unsupported: */ 4970ab25eeb5Syz155240 /* it would require rewriting the ICMP data section */ 4971ab25eeb5Syz155240 case ICMP_TSTAMP: 4972ab25eeb5Syz155240 case ICMP_TSTAMPREPLY: 4973ab25eeb5Syz155240 case ICMP_IREQ: 4974ab25eeb5Syz155240 case ICMP_IREQREPLY: 4975ab25eeb5Syz155240 case ICMP_MASKREQ: 4976ab25eeb5Syz155240 case ICMP_MASKREPLY: 4977ab25eeb5Syz155240 return 1; 4978ab25eeb5Syz155240 default: 4979ab25eeb5Syz155240 return 0; 4980ab25eeb5Syz155240 } 4981ab25eeb5Syz155240 } 4982ab25eeb5Syz155240 4983ab25eeb5Syz155240 4984ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */ 4985ab25eeb5Syz155240 /* Function: nat_log */ 4986ab25eeb5Syz155240 /* Returns: Nil */ 4987ab25eeb5Syz155240 /* Parameters: nat(I) - pointer to NAT structure */ 4988ab25eeb5Syz155240 /* type(I) - type of log entry to create */ 4989ab25eeb5Syz155240 /* */ 4990ab25eeb5Syz155240 /* Creates a NAT log entry. */ 4991ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */ 4992f4b3ec61Sdh155122 void nat_log(nat, type, ifs) 4993ab25eeb5Syz155240 struct nat *nat; 4994ab25eeb5Syz155240 u_int type; 4995f4b3ec61Sdh155122 ipf_stack_t *ifs; 4996ab25eeb5Syz155240 { 4997ab25eeb5Syz155240 #ifdef IPFILTER_LOG 4998ab25eeb5Syz155240 # ifndef LARGE_NAT 4999ab25eeb5Syz155240 struct ipnat *np; 5000ab25eeb5Syz155240 int rulen; 5001ab25eeb5Syz155240 # endif 5002ab25eeb5Syz155240 struct natlog natl; 5003ab25eeb5Syz155240 void *items[1]; 5004ab25eeb5Syz155240 size_t sizes[1]; 5005ab25eeb5Syz155240 int types[1]; 5006ab25eeb5Syz155240 5007*d6c23f6fSyx160601 natl.nlg_inip = nat->nat_inip6; 5008*d6c23f6fSyx160601 natl.nlg_outip = nat->nat_outip6; 5009*d6c23f6fSyx160601 natl.nlg_origip = nat->nat_oip6; 5010*d6c23f6fSyx160601 natl.nlg_bytes[0] = nat->nat_bytes[0]; 5011*d6c23f6fSyx160601 natl.nlg_bytes[1] = nat->nat_bytes[1]; 5012*d6c23f6fSyx160601 natl.nlg_pkts[0] = nat->nat_pkts[0]; 5013*d6c23f6fSyx160601 natl.nlg_pkts[1] = nat->nat_pkts[1]; 5014*d6c23f6fSyx160601 natl.nlg_origport = nat->nat_oport; 5015*d6c23f6fSyx160601 natl.nlg_inport = nat->nat_inport; 5016*d6c23f6fSyx160601 natl.nlg_outport = nat->nat_outport; 5017*d6c23f6fSyx160601 natl.nlg_p = nat->nat_p; 5018*d6c23f6fSyx160601 natl.nlg_type = type; 5019*d6c23f6fSyx160601 natl.nlg_rule = -1; 5020*d6c23f6fSyx160601 natl.nlg_v = nat->nat_v; 5021ab25eeb5Syz155240 # ifndef LARGE_NAT 5022ab25eeb5Syz155240 if (nat->nat_ptr != NULL) { 5023f4b3ec61Sdh155122 for (rulen = 0, np = ifs->ifs_nat_list; np; 5024f4b3ec61Sdh155122 np = np->in_next, rulen++) 5025ab25eeb5Syz155240 if (np == nat->nat_ptr) { 5026*d6c23f6fSyx160601 natl.nlg_rule = rulen; 5027ab25eeb5Syz155240 break; 5028ab25eeb5Syz155240 } 5029ab25eeb5Syz155240 } 5030ab25eeb5Syz155240 # endif 5031ab25eeb5Syz155240 items[0] = &natl; 5032ab25eeb5Syz155240 sizes[0] = sizeof(natl); 5033ab25eeb5Syz155240 types[0] = 0; 5034ab25eeb5Syz155240 5035f4b3ec61Sdh155122 (void) ipllog(IPL_LOGNAT, NULL, items, sizes, types, 1, ifs); 5036ab25eeb5Syz155240 #endif 5037ab25eeb5Syz155240 } 5038ab25eeb5Syz155240 5039ab25eeb5Syz155240 5040ab25eeb5Syz155240 #if defined(__OpenBSD__) 5041ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */ 5042ab25eeb5Syz155240 /* Function: nat_ifdetach */ 5043ab25eeb5Syz155240 /* Returns: Nil */ 5044ab25eeb5Syz155240 /* Parameters: ifp(I) - pointer to network interface */ 5045ab25eeb5Syz155240 /* */ 5046ab25eeb5Syz155240 /* Compatibility interface for OpenBSD to trigger the correct updating of */ 5047ab25eeb5Syz155240 /* interface references within IPFilter. */ 5048ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */ 5049f4b3ec61Sdh155122 void nat_ifdetach(ifp, ifs) 5050ab25eeb5Syz155240 void *ifp; 5051f4b3ec61Sdh155122 ipf_stack_t *ifs; 5052ab25eeb5Syz155240 { 5053f4b3ec61Sdh155122 frsync(ifp, ifs); 5054ab25eeb5Syz155240 return; 5055ab25eeb5Syz155240 } 5056ab25eeb5Syz155240 #endif 5057ab25eeb5Syz155240 5058ab25eeb5Syz155240 5059ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */ 5060f4b3ec61Sdh155122 /* Function: fr_ipnatderef */ 5061f4b3ec61Sdh155122 /* Returns: Nil */ 5062cbded9aeSdr146992 /* Parameters: inp(I) - pointer to pointer to NAT rule */ 5063f4b3ec61Sdh155122 /* Write Locks: ipf_nat */ 5064f4b3ec61Sdh155122 /* */ 5065f4b3ec61Sdh155122 /* ------------------------------------------------------------------------ */ 5066f4b3ec61Sdh155122 void fr_ipnatderef(inp, ifs) 5067f4b3ec61Sdh155122 ipnat_t **inp; 5068f4b3ec61Sdh155122 ipf_stack_t *ifs; 5069f4b3ec61Sdh155122 { 5070f4b3ec61Sdh155122 ipnat_t *in; 5071f4b3ec61Sdh155122 5072f4b3ec61Sdh155122 in = *inp; 5073f4b3ec61Sdh155122 *inp = NULL; 5074f4b3ec61Sdh155122 in->in_use--; 5075f4b3ec61Sdh155122 if (in->in_use == 0 && (in->in_flags & IPN_DELETE)) { 5076f4b3ec61Sdh155122 if (in->in_apr) 5077f4b3ec61Sdh155122 appr_free(in->in_apr); 5078f4b3ec61Sdh155122 KFREE(in); 5079f4b3ec61Sdh155122 ifs->ifs_nat_stats.ns_rules--; 5080f4b3ec61Sdh155122 #ifdef notdef 5081f4b3ec61Sdh155122 #if SOLARIS 5082f4b3ec61Sdh155122 if (ifs->ifs_nat_stats.ns_rules == 0) 5083f4b3ec61Sdh155122 ifs->ifs_pfil_delayed_copy = 1; 5084f4b3ec61Sdh155122 #endif 5085f4b3ec61Sdh155122 #endif 5086f4b3ec61Sdh155122 } 5087f4b3ec61Sdh155122 } 5088f4b3ec61Sdh155122 5089f4b3ec61Sdh155122 5090f4b3ec61Sdh155122 /* ------------------------------------------------------------------------ */ 5091ab25eeb5Syz155240 /* Function: fr_natderef */ 5092ab25eeb5Syz155240 /* Returns: Nil */ 5093ab25eeb5Syz155240 /* Parameters: isp(I) - pointer to pointer to NAT table entry */ 5094ab25eeb5Syz155240 /* */ 5095ab25eeb5Syz155240 /* Decrement the reference counter for this NAT table entry and free it if */ 5096ab25eeb5Syz155240 /* there are no more things using it. */ 50970e01ff8bSdr146992 /* */ 50980e01ff8bSdr146992 /* IF nat_ref == 1 when this function is called, then we have an orphan nat */ 50990e01ff8bSdr146992 /* structure *because* it only gets called on paths _after_ nat_ref has been*/ 51000e01ff8bSdr146992 /* incremented. If nat_ref == 1 then we shouldn't decrement it here */ 51010e01ff8bSdr146992 /* because nat_delete() will do that and send nat_ref to -1. */ 51020e01ff8bSdr146992 /* */ 51030e01ff8bSdr146992 /* Holding the lock on nat_lock is required to serialise nat_delete() being */ 51040e01ff8bSdr146992 /* called from a NAT flush ioctl with a deref happening because of a packet.*/ 5105ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */ 5106f4b3ec61Sdh155122 void fr_natderef(natp, ifs) 5107ab25eeb5Syz155240 nat_t **natp; 5108f4b3ec61Sdh155122 ipf_stack_t *ifs; 5109ab25eeb5Syz155240 { 5110ab25eeb5Syz155240 nat_t *nat; 5111ab25eeb5Syz155240 5112ab25eeb5Syz155240 nat = *natp; 5113ab25eeb5Syz155240 *natp = NULL; 51140e01ff8bSdr146992 51150e01ff8bSdr146992 MUTEX_ENTER(&nat->nat_lock); 51160e01ff8bSdr146992 if (nat->nat_ref > 1) { 5117ab25eeb5Syz155240 nat->nat_ref--; 51180e01ff8bSdr146992 MUTEX_EXIT(&nat->nat_lock); 51190e01ff8bSdr146992 return; 51200e01ff8bSdr146992 } 51210e01ff8bSdr146992 MUTEX_EXIT(&nat->nat_lock); 51220e01ff8bSdr146992 51230e01ff8bSdr146992 WRITE_ENTER(&ifs->ifs_ipf_nat); 5124f4b3ec61Sdh155122 nat_delete(nat, NL_EXPIRE, ifs); 5125f4b3ec61Sdh155122 RWLOCK_EXIT(&ifs->ifs_ipf_nat); 5126ab25eeb5Syz155240 } 5127ab25eeb5Syz155240 5128ab25eeb5Syz155240 5129ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */ 5130ab25eeb5Syz155240 /* Function: fr_natclone */ 5131ab25eeb5Syz155240 /* Returns: ipstate_t* - NULL == cloning failed, */ 5132ab25eeb5Syz155240 /* else pointer to new state structure */ 5133ab25eeb5Syz155240 /* Parameters: fin(I) - pointer to packet information */ 5134ab25eeb5Syz155240 /* is(I) - pointer to master state structure */ 5135ab25eeb5Syz155240 /* Write Lock: ipf_nat */ 5136ab25eeb5Syz155240 /* */ 5137ab25eeb5Syz155240 /* Create a "duplcate" state table entry from the master. */ 5138ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */ 5139*d6c23f6fSyx160601 nat_t *fr_natclone(fin, nat) 5140ab25eeb5Syz155240 fr_info_t *fin; 5141ab25eeb5Syz155240 nat_t *nat; 5142ab25eeb5Syz155240 { 5143ab25eeb5Syz155240 frentry_t *fr; 5144ab25eeb5Syz155240 nat_t *clone; 5145ab25eeb5Syz155240 ipnat_t *np; 5146f4b3ec61Sdh155122 ipf_stack_t *ifs = fin->fin_ifs; 5147ab25eeb5Syz155240 5148ab25eeb5Syz155240 KMALLOC(clone, nat_t *); 5149ab25eeb5Syz155240 if (clone == NULL) 5150ab25eeb5Syz155240 return NULL; 5151ab25eeb5Syz155240 bcopy((char *)nat, (char *)clone, sizeof(*clone)); 5152ab25eeb5Syz155240 5153ab25eeb5Syz155240 MUTEX_NUKE(&clone->nat_lock); 5154ab25eeb5Syz155240 5155ab25eeb5Syz155240 clone->nat_aps = NULL; 5156ab25eeb5Syz155240 /* 5157ab25eeb5Syz155240 * Initialize all these so that nat_delete() doesn't cause a crash. 5158ab25eeb5Syz155240 */ 5159ab25eeb5Syz155240 clone->nat_tqe.tqe_pnext = NULL; 5160ab25eeb5Syz155240 clone->nat_tqe.tqe_next = NULL; 5161ab25eeb5Syz155240 clone->nat_tqe.tqe_ifq = NULL; 5162ab25eeb5Syz155240 clone->nat_tqe.tqe_parent = clone; 5163ab25eeb5Syz155240 5164ab25eeb5Syz155240 clone->nat_flags &= ~SI_CLONE; 5165ab25eeb5Syz155240 clone->nat_flags |= SI_CLONED; 5166ab25eeb5Syz155240 5167ab25eeb5Syz155240 if (clone->nat_hm) 5168ab25eeb5Syz155240 clone->nat_hm->hm_ref++; 5169ab25eeb5Syz155240 5170f4b3ec61Sdh155122 if (nat_insert(clone, fin->fin_rev, ifs) == -1) { 5171ab25eeb5Syz155240 KFREE(clone); 5172ab25eeb5Syz155240 return NULL; 5173ab25eeb5Syz155240 } 5174ab25eeb5Syz155240 np = clone->nat_ptr; 5175ab25eeb5Syz155240 if (np != NULL) { 5176f4b3ec61Sdh155122 if (ifs->ifs_nat_logging) 5177f4b3ec61Sdh155122 nat_log(clone, (u_int)np->in_redir, ifs); 5178ab25eeb5Syz155240 np->in_use++; 5179ab25eeb5Syz155240 } 5180ab25eeb5Syz155240 fr = clone->nat_fr; 5181ab25eeb5Syz155240 if (fr != NULL) { 5182ab25eeb5Syz155240 MUTEX_ENTER(&fr->fr_lock); 5183ab25eeb5Syz155240 fr->fr_ref++; 5184ab25eeb5Syz155240 MUTEX_EXIT(&fr->fr_lock); 5185ab25eeb5Syz155240 } 5186ab25eeb5Syz155240 5187ab25eeb5Syz155240 /* 5188ab25eeb5Syz155240 * Because the clone is created outside the normal loop of things and 5189ab25eeb5Syz155240 * TCP has special needs in terms of state, initialise the timeout 5190ab25eeb5Syz155240 * state of the new NAT from here. 5191ab25eeb5Syz155240 */ 5192ab25eeb5Syz155240 if (clone->nat_p == IPPROTO_TCP) { 5193f4b3ec61Sdh155122 (void) fr_tcp_age(&clone->nat_tqe, fin, ifs->ifs_nat_tqb, 5194ab25eeb5Syz155240 clone->nat_flags); 5195ab25eeb5Syz155240 } 5196ab25eeb5Syz155240 #ifdef IPFILTER_SYNC 5197ab25eeb5Syz155240 clone->nat_sync = ipfsync_new(SMC_NAT, fin, clone); 5198ab25eeb5Syz155240 #endif 5199f4b3ec61Sdh155122 if (ifs->ifs_nat_logging) 5200f4b3ec61Sdh155122 nat_log(clone, NL_CLONE, ifs); 5201ab25eeb5Syz155240 return clone; 5202ab25eeb5Syz155240 } 5203ab25eeb5Syz155240 5204ab25eeb5Syz155240 5205ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */ 5206ab25eeb5Syz155240 /* Function: nat_wildok */ 5207ab25eeb5Syz155240 /* Returns: int - 1 == packet's ports match wildcards */ 5208ab25eeb5Syz155240 /* 0 == packet's ports don't match wildcards */ 5209ab25eeb5Syz155240 /* Parameters: nat(I) - NAT entry */ 5210ab25eeb5Syz155240 /* sport(I) - source port */ 5211ab25eeb5Syz155240 /* dport(I) - destination port */ 5212ab25eeb5Syz155240 /* flags(I) - wildcard flags */ 5213ab25eeb5Syz155240 /* dir(I) - packet direction */ 5214ab25eeb5Syz155240 /* */ 5215ab25eeb5Syz155240 /* Use NAT entry and packet direction to determine which combination of */ 5216ab25eeb5Syz155240 /* wildcard flags should be used. */ 5217ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */ 5218*d6c23f6fSyx160601 int nat_wildok(nat, sport, dport, flags, dir) 5219ab25eeb5Syz155240 nat_t *nat; 5220ab25eeb5Syz155240 int sport; 5221ab25eeb5Syz155240 int dport; 5222ab25eeb5Syz155240 int flags; 5223ab25eeb5Syz155240 int dir; 5224ab25eeb5Syz155240 { 5225ab25eeb5Syz155240 /* 5226ab25eeb5Syz155240 * When called by dir is set to 5227ab25eeb5Syz155240 * nat_inlookup NAT_INBOUND (0) 5228ab25eeb5Syz155240 * nat_outlookup NAT_OUTBOUND (1) 5229ab25eeb5Syz155240 * 5230ab25eeb5Syz155240 * We simply combine the packet's direction in dir with the original 5231ab25eeb5Syz155240 * "intended" direction of that NAT entry in nat->nat_dir to decide 5232ab25eeb5Syz155240 * which combination of wildcard flags to allow. 5233ab25eeb5Syz155240 */ 5234ab25eeb5Syz155240 5235ab25eeb5Syz155240 switch ((dir << 1) | nat->nat_dir) 5236ab25eeb5Syz155240 { 5237ab25eeb5Syz155240 case 3: /* outbound packet / outbound entry */ 5238ab25eeb5Syz155240 if (((nat->nat_inport == sport) || 5239ab25eeb5Syz155240 (flags & SI_W_SPORT)) && 5240ab25eeb5Syz155240 ((nat->nat_oport == dport) || 5241ab25eeb5Syz155240 (flags & SI_W_DPORT))) 5242ab25eeb5Syz155240 return 1; 5243ab25eeb5Syz155240 break; 5244ab25eeb5Syz155240 case 2: /* outbound packet / inbound entry */ 5245ab25eeb5Syz155240 if (((nat->nat_outport == sport) || 5246ab25eeb5Syz155240 (flags & SI_W_DPORT)) && 5247ab25eeb5Syz155240 ((nat->nat_oport == dport) || 5248ab25eeb5Syz155240 (flags & SI_W_SPORT))) 5249ab25eeb5Syz155240 return 1; 5250ab25eeb5Syz155240 break; 5251ab25eeb5Syz155240 case 1: /* inbound packet / outbound entry */ 5252ab25eeb5Syz155240 if (((nat->nat_oport == sport) || 5253ab25eeb5Syz155240 (flags & SI_W_DPORT)) && 5254ab25eeb5Syz155240 ((nat->nat_outport == dport) || 5255ab25eeb5Syz155240 (flags & SI_W_SPORT))) 5256ab25eeb5Syz155240 return 1; 5257ab25eeb5Syz155240 break; 5258ab25eeb5Syz155240 case 0: /* inbound packet / inbound entry */ 5259ab25eeb5Syz155240 if (((nat->nat_oport == sport) || 5260ab25eeb5Syz155240 (flags & SI_W_SPORT)) && 5261ab25eeb5Syz155240 ((nat->nat_outport == dport) || 5262ab25eeb5Syz155240 (flags & SI_W_DPORT))) 5263ab25eeb5Syz155240 return 1; 5264ab25eeb5Syz155240 break; 5265ab25eeb5Syz155240 default: 5266ab25eeb5Syz155240 break; 5267ab25eeb5Syz155240 } 5268ab25eeb5Syz155240 5269ab25eeb5Syz155240 return(0); 5270ab25eeb5Syz155240 } 5271ab25eeb5Syz155240 5272ab25eeb5Syz155240 5273ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */ 5274ab25eeb5Syz155240 /* Function: nat_mssclamp */ 5275ab25eeb5Syz155240 /* Returns: Nil */ 5276ab25eeb5Syz155240 /* Parameters: tcp(I) - pointer to TCP header */ 5277ab25eeb5Syz155240 /* maxmss(I) - value to clamp the TCP MSS to */ 5278ab25eeb5Syz155240 /* csump(I) - pointer to TCP checksum */ 5279ab25eeb5Syz155240 /* */ 5280ab25eeb5Syz155240 /* Check for MSS option and clamp it if necessary. If found and changed, */ 5281ab25eeb5Syz155240 /* then the TCP header checksum will be updated to reflect the change in */ 5282ab25eeb5Syz155240 /* the MSS. */ 5283ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */ 5284381a2a9aSdr146992 static void nat_mssclamp(tcp, maxmss, csump) 5285ab25eeb5Syz155240 tcphdr_t *tcp; 5286ab25eeb5Syz155240 u_32_t maxmss; 5287ab25eeb5Syz155240 u_short *csump; 5288ab25eeb5Syz155240 { 5289ab25eeb5Syz155240 u_char *cp, *ep, opt; 5290ab25eeb5Syz155240 int hlen, advance; 5291ab25eeb5Syz155240 u_32_t mss, sumd; 5292ab25eeb5Syz155240 5293ab25eeb5Syz155240 hlen = TCP_OFF(tcp) << 2; 5294ab25eeb5Syz155240 if (hlen > sizeof(*tcp)) { 5295ab25eeb5Syz155240 cp = (u_char *)tcp + sizeof(*tcp); 5296ab25eeb5Syz155240 ep = (u_char *)tcp + hlen; 5297ab25eeb5Syz155240 5298ab25eeb5Syz155240 while (cp < ep) { 5299ab25eeb5Syz155240 opt = cp[0]; 5300ab25eeb5Syz155240 if (opt == TCPOPT_EOL) 5301ab25eeb5Syz155240 break; 5302ab25eeb5Syz155240 else if (opt == TCPOPT_NOP) { 5303ab25eeb5Syz155240 cp++; 5304ab25eeb5Syz155240 continue; 5305ab25eeb5Syz155240 } 5306ab25eeb5Syz155240 5307ab25eeb5Syz155240 if (cp + 1 >= ep) 5308ab25eeb5Syz155240 break; 5309ab25eeb5Syz155240 advance = cp[1]; 5310ab25eeb5Syz155240 if ((cp + advance > ep) || (advance <= 0)) 5311ab25eeb5Syz155240 break; 5312ab25eeb5Syz155240 switch (opt) 5313ab25eeb5Syz155240 { 5314ab25eeb5Syz155240 case TCPOPT_MAXSEG: 5315ab25eeb5Syz155240 if (advance != 4) 5316ab25eeb5Syz155240 break; 5317ab25eeb5Syz155240 mss = cp[2] * 256 + cp[3]; 5318ab25eeb5Syz155240 if (mss > maxmss) { 5319ab25eeb5Syz155240 cp[2] = maxmss / 256; 5320ab25eeb5Syz155240 cp[3] = maxmss & 0xff; 5321ab25eeb5Syz155240 CALC_SUMD(mss, maxmss, sumd); 5322381a2a9aSdr146992 fix_outcksum(csump, sumd); 5323ab25eeb5Syz155240 } 5324ab25eeb5Syz155240 break; 5325ab25eeb5Syz155240 default: 5326ab25eeb5Syz155240 /* ignore unknown options */ 5327ab25eeb5Syz155240 break; 5328ab25eeb5Syz155240 } 5329ab25eeb5Syz155240 5330ab25eeb5Syz155240 cp += advance; 5331ab25eeb5Syz155240 } 5332ab25eeb5Syz155240 } 5333ab25eeb5Syz155240 } 5334ab25eeb5Syz155240 5335ab25eeb5Syz155240 5336ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */ 5337ab25eeb5Syz155240 /* Function: fr_setnatqueue */ 5338ab25eeb5Syz155240 /* Returns: Nil */ 5339ab25eeb5Syz155240 /* Parameters: nat(I)- pointer to NAT structure */ 5340ab25eeb5Syz155240 /* rev(I) - forward(0) or reverse(1) direction */ 5341ab25eeb5Syz155240 /* Locks: ipf_nat (read or write) */ 5342ab25eeb5Syz155240 /* */ 5343ab25eeb5Syz155240 /* Put the NAT entry on its default queue entry, using rev as a helped in */ 5344ab25eeb5Syz155240 /* determining which queue it should be placed on. */ 5345ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */ 5346f4b3ec61Sdh155122 void fr_setnatqueue(nat, rev, ifs) 5347ab25eeb5Syz155240 nat_t *nat; 5348ab25eeb5Syz155240 int rev; 5349f4b3ec61Sdh155122 ipf_stack_t *ifs; 5350ab25eeb5Syz155240 { 5351ab25eeb5Syz155240 ipftq_t *oifq, *nifq; 5352ab25eeb5Syz155240 5353ab25eeb5Syz155240 if (nat->nat_ptr != NULL) 5354ab25eeb5Syz155240 nifq = nat->nat_ptr->in_tqehead[rev]; 5355ab25eeb5Syz155240 else 5356ab25eeb5Syz155240 nifq = NULL; 5357ab25eeb5Syz155240 5358ab25eeb5Syz155240 if (nifq == NULL) { 5359ab25eeb5Syz155240 switch (nat->nat_p) 5360ab25eeb5Syz155240 { 5361ab25eeb5Syz155240 case IPPROTO_UDP : 5362f4b3ec61Sdh155122 nifq = &ifs->ifs_nat_udptq; 5363ab25eeb5Syz155240 break; 5364ab25eeb5Syz155240 case IPPROTO_ICMP : 5365f4b3ec61Sdh155122 nifq = &ifs->ifs_nat_icmptq; 5366ab25eeb5Syz155240 break; 5367ab25eeb5Syz155240 case IPPROTO_TCP : 5368f4b3ec61Sdh155122 nifq = ifs->ifs_nat_tqb + nat->nat_tqe.tqe_state[rev]; 5369ab25eeb5Syz155240 break; 5370ab25eeb5Syz155240 default : 5371f4b3ec61Sdh155122 nifq = &ifs->ifs_nat_iptq; 5372ab25eeb5Syz155240 break; 5373ab25eeb5Syz155240 } 5374ab25eeb5Syz155240 } 5375ab25eeb5Syz155240 5376ab25eeb5Syz155240 oifq = nat->nat_tqe.tqe_ifq; 5377ab25eeb5Syz155240 /* 5378ab25eeb5Syz155240 * If it's currently on a timeout queue, move it from one queue to 5379ab25eeb5Syz155240 * another, else put it on the end of the newly determined queue. 5380ab25eeb5Syz155240 */ 5381ab25eeb5Syz155240 if (oifq != NULL) 5382f4b3ec61Sdh155122 fr_movequeue(&nat->nat_tqe, oifq, nifq, ifs); 5383ab25eeb5Syz155240 else 5384f4b3ec61Sdh155122 fr_queueappend(&nat->nat_tqe, nifq, nat, ifs); 5385ab25eeb5Syz155240 return; 5386ab25eeb5Syz155240 } 5387f4b3ec61Sdh155122 538890b0a856Sjojemann /* ------------------------------------------------------------------------ */ 5389f4b3ec61Sdh155122 /* Function: nat_getnext */ 5390f4b3ec61Sdh155122 /* Returns: int - 0 == ok, else error */ 5391f4b3ec61Sdh155122 /* Parameters: t(I) - pointer to ipftoken structure */ 5392f4b3ec61Sdh155122 /* itp(I) - pointer to ipfgeniter_t structure */ 539390b0a856Sjojemann /* ifs - ipf stack instance */ 5394f4b3ec61Sdh155122 /* */ 539590b0a856Sjojemann /* Fetch the next nat/ipnat/hostmap structure pointer from the linked list */ 539690b0a856Sjojemann /* and copy it out to the storage space pointed to by itp. The next item */ 5397f4b3ec61Sdh155122 /* in the list to look at is put back in the ipftoken struture. */ 5398f4b3ec61Sdh155122 /* ------------------------------------------------------------------------ */ 5399f4b3ec61Sdh155122 static int nat_getnext(t, itp, ifs) 5400f4b3ec61Sdh155122 ipftoken_t *t; 5401f4b3ec61Sdh155122 ipfgeniter_t *itp; 5402f4b3ec61Sdh155122 ipf_stack_t *ifs; 5403f4b3ec61Sdh155122 { 5404f4b3ec61Sdh155122 hostmap_t *hm, *nexthm = NULL, zerohm; 5405f4b3ec61Sdh155122 ipnat_t *ipn, *nextipnat = NULL, zeroipn; 5406f4b3ec61Sdh155122 nat_t *nat, *nextnat = NULL, zeronat; 540790b0a856Sjojemann int error = 0, count; 540890b0a856Sjojemann char *dst; 540990b0a856Sjojemann 541090b0a856Sjojemann if (itp->igi_nitems == 0) 541190b0a856Sjojemann return EINVAL; 5412f4b3ec61Sdh155122 5413f4b3ec61Sdh155122 READ_ENTER(&ifs->ifs_ipf_nat); 541490b0a856Sjojemann 5415786c7074Sjojemann /* 5416786c7074Sjojemann * Get "previous" entry from the token and find the next entry. 5417786c7074Sjojemann */ 5418f4b3ec61Sdh155122 switch (itp->igi_type) 5419f4b3ec61Sdh155122 { 5420f4b3ec61Sdh155122 case IPFGENITER_HOSTMAP : 5421f4b3ec61Sdh155122 hm = t->ipt_data; 5422f4b3ec61Sdh155122 if (hm == NULL) { 5423f4b3ec61Sdh155122 nexthm = ifs->ifs_ipf_hm_maplist; 5424f4b3ec61Sdh155122 } else { 542590b0a856Sjojemann nexthm = hm->hm_next; 5426f4b3ec61Sdh155122 } 5427f4b3ec61Sdh155122 break; 5428f4b3ec61Sdh155122 5429f4b3ec61Sdh155122 case IPFGENITER_IPNAT : 5430f4b3ec61Sdh155122 ipn = t->ipt_data; 5431f4b3ec61Sdh155122 if (ipn == NULL) { 5432f4b3ec61Sdh155122 nextipnat = ifs->ifs_nat_list; 5433f4b3ec61Sdh155122 } else { 5434f4b3ec61Sdh155122 nextipnat = ipn->in_next; 5435f4b3ec61Sdh155122 } 5436f4b3ec61Sdh155122 break; 5437f4b3ec61Sdh155122 5438f4b3ec61Sdh155122 case IPFGENITER_NAT : 5439f4b3ec61Sdh155122 nat = t->ipt_data; 5440f4b3ec61Sdh155122 if (nat == NULL) { 5441f4b3ec61Sdh155122 nextnat = ifs->ifs_nat_instances; 5442f4b3ec61Sdh155122 } else { 5443f4b3ec61Sdh155122 nextnat = nat->nat_next; 5444f4b3ec61Sdh155122 } 544590b0a856Sjojemann break; 544690b0a856Sjojemann default : 544790b0a856Sjojemann RWLOCK_EXIT(&ifs->ifs_ipf_nat); 544890b0a856Sjojemann return EINVAL; 544990b0a856Sjojemann } 545090b0a856Sjojemann 545190b0a856Sjojemann dst = itp->igi_data; 545290b0a856Sjojemann for (count = itp->igi_nitems; count > 0; count--) { 5453786c7074Sjojemann /* 5454786c7074Sjojemann * If we found an entry, add a reference to it and update the token. 5455786c7074Sjojemann * Otherwise, zero out data to be returned and NULL out token. 5456786c7074Sjojemann */ 545790b0a856Sjojemann switch (itp->igi_type) 545890b0a856Sjojemann { 545990b0a856Sjojemann case IPFGENITER_HOSTMAP : 546090b0a856Sjojemann if (nexthm != NULL) { 546190b0a856Sjojemann ATOMIC_INC32(nexthm->hm_ref); 546290b0a856Sjojemann t->ipt_data = nexthm; 5463f4b3ec61Sdh155122 } else { 546490b0a856Sjojemann bzero(&zerohm, sizeof(zerohm)); 546590b0a856Sjojemann nexthm = &zerohm; 546690b0a856Sjojemann t->ipt_data = NULL; 546790b0a856Sjojemann } 546890b0a856Sjojemann break; 546990b0a856Sjojemann case IPFGENITER_IPNAT : 547090b0a856Sjojemann if (nextipnat != NULL) { 547190b0a856Sjojemann ATOMIC_INC32(nextipnat->in_use); 547290b0a856Sjojemann t->ipt_data = nextipnat; 547390b0a856Sjojemann } else { 547490b0a856Sjojemann bzero(&zeroipn, sizeof(zeroipn)); 547590b0a856Sjojemann nextipnat = &zeroipn; 547690b0a856Sjojemann t->ipt_data = NULL; 547790b0a856Sjojemann } 547890b0a856Sjojemann break; 547990b0a856Sjojemann case IPFGENITER_NAT : 548090b0a856Sjojemann if (nextnat != NULL) { 5481f4b3ec61Sdh155122 MUTEX_ENTER(&nextnat->nat_lock); 5482f4b3ec61Sdh155122 nextnat->nat_ref++; 5483f4b3ec61Sdh155122 MUTEX_EXIT(&nextnat->nat_lock); 548490b0a856Sjojemann t->ipt_data = nextnat; 5485f4b3ec61Sdh155122 } else { 5486f4b3ec61Sdh155122 bzero(&zeronat, sizeof(zeronat)); 5487f4b3ec61Sdh155122 nextnat = &zeronat; 548890b0a856Sjojemann t->ipt_data = NULL; 5489f4b3ec61Sdh155122 } 5490f4b3ec61Sdh155122 break; 549190b0a856Sjojemann default : 549290b0a856Sjojemann break; 5493f4b3ec61Sdh155122 } 5494f4b3ec61Sdh155122 549590b0a856Sjojemann /* 5496786c7074Sjojemann * Now that we have ref, it's save to give up lock. 549790b0a856Sjojemann */ 5498f4b3ec61Sdh155122 RWLOCK_EXIT(&ifs->ifs_ipf_nat); 5499f4b3ec61Sdh155122 5500786c7074Sjojemann /* 5501786c7074Sjojemann * Copy out data and clean up references and token as needed. 5502786c7074Sjojemann */ 5503f4b3ec61Sdh155122 switch (itp->igi_type) 5504f4b3ec61Sdh155122 { 5505f4b3ec61Sdh155122 case IPFGENITER_HOSTMAP : 5506786c7074Sjojemann error = COPYOUT(nexthm, dst, sizeof(*nexthm)); 5507786c7074Sjojemann if (error != 0) 5508786c7074Sjojemann error = EFAULT; 5509786c7074Sjojemann if (t->ipt_data == NULL) { 5510786c7074Sjojemann ipf_freetoken(t, ifs); 5511786c7074Sjojemann break; 5512786c7074Sjojemann } else { 5513f4b3ec61Sdh155122 if (hm != NULL) { 5514f4b3ec61Sdh155122 WRITE_ENTER(&ifs->ifs_ipf_nat); 551590b0a856Sjojemann fr_hostmapdel(&hm); 5516f4b3ec61Sdh155122 RWLOCK_EXIT(&ifs->ifs_ipf_nat); 5517f4b3ec61Sdh155122 } 5518786c7074Sjojemann if (nexthm->hm_next == NULL) { 5519786c7074Sjojemann ipf_freetoken(t, ifs); 5520786c7074Sjojemann break; 5521786c7074Sjojemann } 552290b0a856Sjojemann dst += sizeof(*nexthm); 552390b0a856Sjojemann hm = nexthm; 552490b0a856Sjojemann nexthm = nexthm->hm_next; 552590b0a856Sjojemann } 5526f4b3ec61Sdh155122 break; 5527786c7074Sjojemann 5528f4b3ec61Sdh155122 case IPFGENITER_IPNAT : 5529786c7074Sjojemann error = COPYOUT(nextipnat, dst, sizeof(*nextipnat)); 5530786c7074Sjojemann if (error != 0) 5531786c7074Sjojemann error = EFAULT; 5532786c7074Sjojemann if (t->ipt_data == NULL) { 5533786c7074Sjojemann ipf_freetoken(t, ifs); 5534786c7074Sjojemann break; 5535786c7074Sjojemann } else { 553690b0a856Sjojemann if (ipn != NULL) { 553790b0a856Sjojemann WRITE_ENTER(&ifs->ifs_ipf_nat); 5538f4b3ec61Sdh155122 fr_ipnatderef(&ipn, ifs); 553990b0a856Sjojemann RWLOCK_EXIT(&ifs->ifs_ipf_nat); 554090b0a856Sjojemann } 5541786c7074Sjojemann if (nextipnat->in_next == NULL) { 5542786c7074Sjojemann ipf_freetoken(t, ifs); 5543786c7074Sjojemann break; 5544786c7074Sjojemann } 554590b0a856Sjojemann dst += sizeof(*nextipnat); 554690b0a856Sjojemann ipn = nextipnat; 554790b0a856Sjojemann nextipnat = nextipnat->in_next; 554890b0a856Sjojemann } 554990b0a856Sjojemann break; 5550786c7074Sjojemann 555190b0a856Sjojemann case IPFGENITER_NAT : 555290b0a856Sjojemann error = COPYOUT(nextnat, dst, sizeof(*nextnat)); 5553786c7074Sjojemann if (error != 0) 555490b0a856Sjojemann error = EFAULT; 5555786c7074Sjojemann if (t->ipt_data == NULL) { 5556786c7074Sjojemann ipf_freetoken(t, ifs); 5557786c7074Sjojemann break; 555890b0a856Sjojemann } else { 5559786c7074Sjojemann if (nat != NULL) 5560786c7074Sjojemann fr_natderef(&nat, ifs); 5561786c7074Sjojemann if (nextnat->nat_next == NULL) { 5562786c7074Sjojemann ipf_freetoken(t, ifs); 5563786c7074Sjojemann break; 5564786c7074Sjojemann } 556590b0a856Sjojemann dst += sizeof(*nextnat); 556690b0a856Sjojemann nat = nextnat; 556790b0a856Sjojemann nextnat = nextnat->nat_next; 556890b0a856Sjojemann } 556990b0a856Sjojemann break; 557090b0a856Sjojemann default : 557190b0a856Sjojemann break; 557290b0a856Sjojemann } 557390b0a856Sjojemann 557490b0a856Sjojemann if ((count == 1) || (error != 0)) 5575f4b3ec61Sdh155122 break; 5576f4b3ec61Sdh155122 557790b0a856Sjojemann READ_ENTER(&ifs->ifs_ipf_nat); 5578f4b3ec61Sdh155122 } 5579f4b3ec61Sdh155122 5580f4b3ec61Sdh155122 return error; 5581f4b3ec61Sdh155122 } 5582f4b3ec61Sdh155122 5583f4b3ec61Sdh155122 5584f4b3ec61Sdh155122 /* ------------------------------------------------------------------------ */ 5585f4b3ec61Sdh155122 /* Function: nat_iterator */ 5586f4b3ec61Sdh155122 /* Returns: int - 0 == ok, else error */ 5587f4b3ec61Sdh155122 /* Parameters: token(I) - pointer to ipftoken structure */ 5588f4b3ec61Sdh155122 /* itp(I) - pointer to ipfgeniter_t structure */ 5589f4b3ec61Sdh155122 /* */ 5590f4b3ec61Sdh155122 /* This function acts as a handler for the SIOCGENITER ioctls that use a */ 5591f4b3ec61Sdh155122 /* generic structure to iterate through a list. There are three different */ 5592f4b3ec61Sdh155122 /* linked lists of NAT related information to go through: NAT rules, active */ 5593f4b3ec61Sdh155122 /* NAT mappings and the NAT fragment cache. */ 5594f4b3ec61Sdh155122 /* ------------------------------------------------------------------------ */ 5595f4b3ec61Sdh155122 static int nat_iterator(token, itp, ifs) 5596f4b3ec61Sdh155122 ipftoken_t *token; 5597f4b3ec61Sdh155122 ipfgeniter_t *itp; 5598f4b3ec61Sdh155122 ipf_stack_t *ifs; 5599f4b3ec61Sdh155122 { 5600f4b3ec61Sdh155122 int error; 5601f4b3ec61Sdh155122 5602f4b3ec61Sdh155122 if (itp->igi_data == NULL) 5603f4b3ec61Sdh155122 return EFAULT; 5604f4b3ec61Sdh155122 5605f4b3ec61Sdh155122 token->ipt_subtype = itp->igi_type; 5606f4b3ec61Sdh155122 5607f4b3ec61Sdh155122 switch (itp->igi_type) 5608f4b3ec61Sdh155122 { 5609f4b3ec61Sdh155122 case IPFGENITER_HOSTMAP : 5610f4b3ec61Sdh155122 case IPFGENITER_IPNAT : 5611f4b3ec61Sdh155122 case IPFGENITER_NAT : 5612f4b3ec61Sdh155122 error = nat_getnext(token, itp, ifs); 5613f4b3ec61Sdh155122 break; 5614f4b3ec61Sdh155122 case IPFGENITER_NATFRAG : 5615f4b3ec61Sdh155122 error = fr_nextfrag(token, itp, &ifs->ifs_ipfr_natlist, 5616f4b3ec61Sdh155122 &ifs->ifs_ipfr_nattail, 5617f4b3ec61Sdh155122 &ifs->ifs_ipf_natfrag, ifs); 5618f4b3ec61Sdh155122 break; 5619f4b3ec61Sdh155122 default : 5620f4b3ec61Sdh155122 error = EINVAL; 5621f4b3ec61Sdh155122 break; 5622f4b3ec61Sdh155122 } 5623f4b3ec61Sdh155122 5624f4b3ec61Sdh155122 return error; 5625f4b3ec61Sdh155122 } 56263805c50fSan207044 56273805c50fSan207044 56283805c50fSan207044 /* -------------------------------------------------------------------- */ 56293805c50fSan207044 /* Function: nat_earlydrop */ 56303805c50fSan207044 /* Returns: number of dropped/removed entries from the queue */ 56313805c50fSan207044 /* Parameters: ifq - pointer to queue with entries to be processed */ 56323805c50fSan207044 /* maxidle - entry must be idle this long to be dropped */ 56333805c50fSan207044 /* ifs - ipf stack instance */ 56343805c50fSan207044 /* */ 56353805c50fSan207044 /* Function is invoked from nat_extraflush() only. Removes entries */ 56363805c50fSan207044 /* form specified timeout queue, based on how long they've sat idle, */ 56373805c50fSan207044 /* without waiting for it to happen on its own. */ 56383805c50fSan207044 /* -------------------------------------------------------------------- */ 56393805c50fSan207044 static int nat_earlydrop(ifq, maxidle, ifs) 56403805c50fSan207044 ipftq_t *ifq; 56413805c50fSan207044 int maxidle; 56423805c50fSan207044 ipf_stack_t *ifs; 56433805c50fSan207044 { 56443805c50fSan207044 ipftqent_t *tqe, *tqn; 56453805c50fSan207044 nat_t *nat; 56463805c50fSan207044 unsigned int dropped; 56473805c50fSan207044 int droptick; 56483805c50fSan207044 56493805c50fSan207044 if (ifq == NULL) 56503805c50fSan207044 return (0); 56513805c50fSan207044 56523805c50fSan207044 dropped = 0; 56533805c50fSan207044 56543805c50fSan207044 /* 56553805c50fSan207044 * Determine the tick representing the idle time we're interested 56563805c50fSan207044 * in. If an entry exists in the queue, and it was touched before 56573805c50fSan207044 * that tick, then it's been idle longer than maxidle ... remove it. 56583805c50fSan207044 */ 56593805c50fSan207044 droptick = ifs->ifs_fr_ticks - maxidle; 56603805c50fSan207044 tqn = ifq->ifq_head; 56613805c50fSan207044 while ((tqe = tqn) != NULL && tqe->tqe_touched < droptick) { 56623805c50fSan207044 tqn = tqe->tqe_next; 56633805c50fSan207044 nat = tqe->tqe_parent; 56643805c50fSan207044 nat_delete(nat, ISL_EXPIRE, ifs); 56653805c50fSan207044 dropped++; 56663805c50fSan207044 } 56673805c50fSan207044 return (dropped); 56683805c50fSan207044 } 56693805c50fSan207044 56703805c50fSan207044 56713805c50fSan207044 /* --------------------------------------------------------------------- */ 56723805c50fSan207044 /* Function: nat_flushclosing */ 56733805c50fSan207044 /* Returns: int - number of NAT entries deleted */ 56743805c50fSan207044 /* Parameters: stateval(I) - State at which to start removing entries */ 56753805c50fSan207044 /* ifs - ipf stack instance */ 56763805c50fSan207044 /* */ 56773805c50fSan207044 /* Remove nat table entries for TCP connections which are in the process */ 56783805c50fSan207044 /* of closing, and are in (or "beyond") state specified by 'stateval'. */ 56793805c50fSan207044 /* --------------------------------------------------------------------- */ 56803805c50fSan207044 static int nat_flushclosing(stateval, ifs) 56813805c50fSan207044 int stateval; 56823805c50fSan207044 ipf_stack_t *ifs; 56833805c50fSan207044 { 56843805c50fSan207044 ipftq_t *ifq, *ifqn; 56853805c50fSan207044 ipftqent_t *tqe, *tqn; 56863805c50fSan207044 nat_t *nat; 56873805c50fSan207044 int dropped; 56883805c50fSan207044 56893805c50fSan207044 dropped = 0; 56903805c50fSan207044 56913805c50fSan207044 /* 56923805c50fSan207044 * Start by deleting any entries in specific timeout queues. 56933805c50fSan207044 */ 56943805c50fSan207044 ifqn = &ifs->ifs_nat_tqb[stateval]; 56953805c50fSan207044 while ((ifq = ifqn) != NULL) { 56963805c50fSan207044 ifqn = ifq->ifq_next; 56973805c50fSan207044 dropped += nat_earlydrop(ifq, (int)0, ifs); 56983805c50fSan207044 } 56993805c50fSan207044 57003805c50fSan207044 /* 57013805c50fSan207044 * Next, look through user defined queues for closing entries. 57023805c50fSan207044 */ 57033805c50fSan207044 ifqn = ifs->ifs_nat_utqe; 57043805c50fSan207044 while ((ifq = ifqn) != NULL) { 57053805c50fSan207044 ifqn = ifq->ifq_next; 57063805c50fSan207044 tqn = ifq->ifq_head; 57073805c50fSan207044 while ((tqe = tqn) != NULL) { 57083805c50fSan207044 tqn = tqe->tqe_next; 57093805c50fSan207044 nat = tqe->tqe_parent; 57103805c50fSan207044 if (nat->nat_p != IPPROTO_TCP) 57113805c50fSan207044 continue; 57123805c50fSan207044 if ((nat->nat_tcpstate[0] >= stateval) && 57133805c50fSan207044 (nat->nat_tcpstate[1] >= stateval)) { 57143805c50fSan207044 nat_delete(nat, NL_EXPIRE, ifs); 57153805c50fSan207044 dropped++; 57163805c50fSan207044 } 57173805c50fSan207044 } 57183805c50fSan207044 } 57193805c50fSan207044 return (dropped); 57203805c50fSan207044 } 57213805c50fSan207044 57223805c50fSan207044 57233805c50fSan207044 /* --------------------------------------------------------------------- */ 57243805c50fSan207044 /* Function: nat_extraflush */ 57253805c50fSan207044 /* Returns: int - number of NAT entries deleted */ 57263805c50fSan207044 /* Parameters: which(I) - how to flush the active NAT table */ 57273805c50fSan207044 /* ifs - ipf stack instance */ 57283805c50fSan207044 /* Write Locks: ipf_nat */ 57293805c50fSan207044 /* */ 57303805c50fSan207044 /* Flush nat tables. Three actions currently defined: */ 57313805c50fSan207044 /* */ 57323805c50fSan207044 /* which == 0 : Flush all nat table entries. */ 57333805c50fSan207044 /* */ 57343805c50fSan207044 /* which == 1 : Flush entries with TCP connections which have started */ 57353805c50fSan207044 /* to close on both ends. */ 57363805c50fSan207044 /* */ 57373805c50fSan207044 /* which == 2 : First, flush entries which are "almost" closed. If that */ 57383805c50fSan207044 /* does not take us below specified threshold in the table, */ 57393805c50fSan207044 /* we want to flush entries with TCP connections which have */ 57403805c50fSan207044 /* been idle for a long time. Start with connections idle */ 57413805c50fSan207044 /* over 12 hours, and then work backwards in half hour */ 57423805c50fSan207044 /* increments to at most 30 minutes idle, and finally work */ 57433805c50fSan207044 /* back in 30 second increments to at most 30 seconds. */ 57443805c50fSan207044 /* --------------------------------------------------------------------- */ 57453805c50fSan207044 static int nat_extraflush(which, ifs) 57463805c50fSan207044 int which; 57473805c50fSan207044 ipf_stack_t *ifs; 57483805c50fSan207044 { 57493805c50fSan207044 ipftq_t *ifq, *ifqn; 57503805c50fSan207044 nat_t *nat, **natp; 57513805c50fSan207044 int idletime, removed, idle_idx; 57523805c50fSan207044 SPL_INT(s); 57533805c50fSan207044 57543805c50fSan207044 removed = 0; 57553805c50fSan207044 57563805c50fSan207044 SPL_NET(s); 57573805c50fSan207044 switch (which) 57583805c50fSan207044 { 57593805c50fSan207044 case 0: 57603805c50fSan207044 natp = &ifs->ifs_nat_instances; 57613805c50fSan207044 while ((nat = *natp) != NULL) { 57623805c50fSan207044 natp = &nat->nat_next; 57633805c50fSan207044 nat_delete(nat, ISL_FLUSH, ifs); 57643805c50fSan207044 removed++; 57653805c50fSan207044 } 57663805c50fSan207044 break; 57673805c50fSan207044 57683805c50fSan207044 case 1: 57693805c50fSan207044 removed = nat_flushclosing(IPF_TCPS_CLOSE_WAIT, ifs); 57703805c50fSan207044 break; 57713805c50fSan207044 57723805c50fSan207044 case 2: 57733805c50fSan207044 removed = nat_flushclosing(IPF_TCPS_FIN_WAIT_2, ifs); 57743805c50fSan207044 57753805c50fSan207044 /* 57763805c50fSan207044 * Be sure we haven't done this in the last 10 seconds. 57773805c50fSan207044 */ 57783805c50fSan207044 if (ifs->ifs_fr_ticks - ifs->ifs_nat_last_force_flush < 57793805c50fSan207044 IPF_TTLVAL(10)) 57803805c50fSan207044 break; 57813805c50fSan207044 ifs->ifs_nat_last_force_flush = ifs->ifs_fr_ticks; 57823805c50fSan207044 57833805c50fSan207044 /* 57843805c50fSan207044 * Determine initial threshold for minimum idle time based on 57853805c50fSan207044 * how long ipfilter has been running. Ipfilter needs to have 57863805c50fSan207044 * been up as long as the smallest interval to continue on. 57873805c50fSan207044 * 57883805c50fSan207044 * Minimum idle times stored in idletime_tab and indexed by 57893805c50fSan207044 * idle_idx. Start at upper end of array and work backwards. 57903805c50fSan207044 * 57913805c50fSan207044 * Once the index is found, set the initial idle time to the 57923805c50fSan207044 * first interval before the current ipfilter run time. 57933805c50fSan207044 */ 57943805c50fSan207044 if (ifs->ifs_fr_ticks < idletime_tab[0]) 57953805c50fSan207044 break; /* switch */ 57963805c50fSan207044 idle_idx = (sizeof (idletime_tab) / sizeof (int)) - 1; 57973805c50fSan207044 if (ifs->ifs_fr_ticks > idletime_tab[idle_idx]) { 57983805c50fSan207044 idletime = idletime_tab[idle_idx]; 57993805c50fSan207044 } else { 58003805c50fSan207044 while ((idle_idx > 0) && 58013805c50fSan207044 (ifs->ifs_fr_ticks < idletime_tab[idle_idx])) 58023805c50fSan207044 idle_idx--; 58033805c50fSan207044 idletime = (ifs->ifs_fr_ticks / 58043805c50fSan207044 idletime_tab[idle_idx]) * 58053805c50fSan207044 idletime_tab[idle_idx]; 58063805c50fSan207044 } 58073805c50fSan207044 58083805c50fSan207044 while ((idle_idx >= 0) && 58093805c50fSan207044 (NAT_TAB_WATER_LEVEL(ifs) > ifs->ifs_nat_flush_lvl_lo)) { 58103805c50fSan207044 /* 58113805c50fSan207044 * Start with appropriate timeout queue. 58123805c50fSan207044 */ 58133805c50fSan207044 removed += nat_earlydrop( 58143805c50fSan207044 &ifs->ifs_nat_tqb[IPF_TCPS_ESTABLISHED], 58153805c50fSan207044 idletime, ifs); 58163805c50fSan207044 58173805c50fSan207044 /* 58183805c50fSan207044 * Make sure we haven't already deleted enough 58193805c50fSan207044 * entries before checking the user defined queues. 58203805c50fSan207044 */ 58213805c50fSan207044 if (NAT_TAB_WATER_LEVEL(ifs) <= 58223805c50fSan207044 ifs->ifs_nat_flush_lvl_lo) 58233805c50fSan207044 break; 58243805c50fSan207044 58253805c50fSan207044 /* 58263805c50fSan207044 * Next, look through the user defined queues. 58273805c50fSan207044 */ 58283805c50fSan207044 ifqn = ifs->ifs_nat_utqe; 58293805c50fSan207044 while ((ifq = ifqn) != NULL) { 58303805c50fSan207044 ifqn = ifq->ifq_next; 58313805c50fSan207044 removed += nat_earlydrop(ifq, idletime, ifs); 58323805c50fSan207044 } 58333805c50fSan207044 58343805c50fSan207044 /* 58353805c50fSan207044 * Adjust the granularity of idle time. 58363805c50fSan207044 * 58373805c50fSan207044 * If we reach an interval boundary, we need to 58383805c50fSan207044 * either adjust the idle time accordingly or exit 58393805c50fSan207044 * the loop altogether (if this is very last check). 58403805c50fSan207044 */ 58413805c50fSan207044 idletime -= idletime_tab[idle_idx]; 58423805c50fSan207044 if (idletime < idletime_tab[idle_idx]) { 58433805c50fSan207044 if (idle_idx != 0) { 58443805c50fSan207044 idletime = idletime_tab[idle_idx] - 58453805c50fSan207044 idletime_tab[idle_idx - 1]; 58463805c50fSan207044 idle_idx--; 58473805c50fSan207044 } else { 58483805c50fSan207044 break; /* while */ 58493805c50fSan207044 } 58503805c50fSan207044 } 58513805c50fSan207044 } 58523805c50fSan207044 break; 58533805c50fSan207044 default: 58543805c50fSan207044 break; 58553805c50fSan207044 } 58563805c50fSan207044 58573805c50fSan207044 SPL_X(s); 58583805c50fSan207044 return (removed); 58593805c50fSan207044 } 5860