1ab25eeb5Syz155240 /* 227dbc409San207044 * Copyright (C) 1995-2004 by Darren Reed. 3ab25eeb5Syz155240 * 4ab25eeb5Syz155240 * See the IPFILTER.LICENCE file for details on licencing. 5ab25eeb5Syz155240 * 633f2fefdSDarren Reed * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 7ab25eeb5Syz155240 * Use is subject to license terms. 8ab25eeb5Syz155240 */ 9ab25eeb5Syz155240 10ab25eeb5Syz155240 #if defined(KERNEL) || defined(_KERNEL) 11ab25eeb5Syz155240 # undef KERNEL 12ab25eeb5Syz155240 # undef _KERNEL 13ab25eeb5Syz155240 # define KERNEL 1 14ab25eeb5Syz155240 # define _KERNEL 1 15ab25eeb5Syz155240 #endif 16ab25eeb5Syz155240 #include <sys/errno.h> 17ab25eeb5Syz155240 #include <sys/types.h> 18ab25eeb5Syz155240 #include <sys/param.h> 19ab25eeb5Syz155240 #include <sys/time.h> 20ab25eeb5Syz155240 #include <sys/file.h> 21ab25eeb5Syz155240 #if defined(__NetBSD__) && (NetBSD >= 199905) && !defined(IPFILTER_LKM) && \ 22ab25eeb5Syz155240 defined(_KERNEL) 23ab25eeb5Syz155240 # include "opt_ipfilter_log.h" 24ab25eeb5Syz155240 #endif 25ab25eeb5Syz155240 #if !defined(_KERNEL) 26ab25eeb5Syz155240 # include <stdio.h> 27ab25eeb5Syz155240 # include <string.h> 28ab25eeb5Syz155240 # include <stdlib.h> 29ab25eeb5Syz155240 # define _KERNEL 30ab25eeb5Syz155240 # ifdef __OpenBSD__ 31ab25eeb5Syz155240 struct file; 32ab25eeb5Syz155240 # endif 33ab25eeb5Syz155240 # include <sys/uio.h> 34ab25eeb5Syz155240 # undef _KERNEL 35ab25eeb5Syz155240 #endif 36ab25eeb5Syz155240 #if defined(_KERNEL) && (__FreeBSD_version >= 220000) 37ab25eeb5Syz155240 # include <sys/filio.h> 38ab25eeb5Syz155240 # include <sys/fcntl.h> 39ab25eeb5Syz155240 #else 40ab25eeb5Syz155240 # include <sys/ioctl.h> 41ab25eeb5Syz155240 #endif 42ab25eeb5Syz155240 #if !defined(AIX) 43ab25eeb5Syz155240 # include <sys/fcntl.h> 44ab25eeb5Syz155240 #endif 45ab25eeb5Syz155240 #if !defined(linux) 46ab25eeb5Syz155240 # include <sys/protosw.h> 47ab25eeb5Syz155240 #endif 48ab25eeb5Syz155240 #include <sys/socket.h> 49ab25eeb5Syz155240 #if defined(_KERNEL) 50ab25eeb5Syz155240 # include <sys/systm.h> 51ab25eeb5Syz155240 # if !defined(__SVR4) && !defined(__svr4__) 52ab25eeb5Syz155240 # include <sys/mbuf.h> 53ab25eeb5Syz155240 # endif 54ab25eeb5Syz155240 #endif 55ab25eeb5Syz155240 #if defined(__SVR4) || defined(__svr4__) 56ab25eeb5Syz155240 # include <sys/filio.h> 57ab25eeb5Syz155240 # include <sys/byteorder.h> 58ab25eeb5Syz155240 # ifdef _KERNEL 59ab25eeb5Syz155240 # include <sys/dditypes.h> 60ab25eeb5Syz155240 # endif 61ab25eeb5Syz155240 # include <sys/stream.h> 62ab25eeb5Syz155240 # include <sys/kmem.h> 63ab25eeb5Syz155240 #endif 64ab25eeb5Syz155240 #if __FreeBSD_version >= 300000 65ab25eeb5Syz155240 # include <sys/queue.h> 66ab25eeb5Syz155240 #endif 67ab25eeb5Syz155240 #include <net/if.h> 68ab25eeb5Syz155240 #if __FreeBSD_version >= 300000 69ab25eeb5Syz155240 # include <net/if_var.h> 70ab25eeb5Syz155240 # if defined(_KERNEL) && !defined(IPFILTER_LKM) 71ab25eeb5Syz155240 # include "opt_ipfilter.h" 72ab25eeb5Syz155240 # endif 73ab25eeb5Syz155240 #endif 74ab25eeb5Syz155240 #ifdef sun 75ab25eeb5Syz155240 # include <net/af.h> 76ab25eeb5Syz155240 #endif 77ab25eeb5Syz155240 #include <net/route.h> 78ab25eeb5Syz155240 #include <netinet/in.h> 79ab25eeb5Syz155240 #include <netinet/in_systm.h> 80ab25eeb5Syz155240 #include <netinet/ip.h> 81ab25eeb5Syz155240 82ab25eeb5Syz155240 #ifdef RFC1825 83ab25eeb5Syz155240 # include <vpn/md5.h> 84ab25eeb5Syz155240 # include <vpn/ipsec.h> 85ab25eeb5Syz155240 extern struct ifnet vpnif; 86ab25eeb5Syz155240 #endif 87ab25eeb5Syz155240 88ab25eeb5Syz155240 #if !defined(linux) 89ab25eeb5Syz155240 # include <netinet/ip_var.h> 90ab25eeb5Syz155240 #endif 91ab25eeb5Syz155240 #include <netinet/tcp.h> 92ab25eeb5Syz155240 #include <netinet/udp.h> 93ab25eeb5Syz155240 #include <netinet/ip_icmp.h> 94ab25eeb5Syz155240 #include "netinet/ip_compat.h" 95ab25eeb5Syz155240 #include <netinet/tcpip.h> 96ab25eeb5Syz155240 #include "netinet/ip_fil.h" 97ab25eeb5Syz155240 #include "netinet/ip_nat.h" 98ab25eeb5Syz155240 #include "netinet/ip_frag.h" 99ab25eeb5Syz155240 #include "netinet/ip_state.h" 100ab25eeb5Syz155240 #include "netinet/ip_proxy.h" 101f4b3ec61Sdh155122 #include "netinet/ipf_stack.h" 102ab25eeb5Syz155240 #ifdef IPFILTER_SYNC 103ab25eeb5Syz155240 #include "netinet/ip_sync.h" 104ab25eeb5Syz155240 #endif 105ab25eeb5Syz155240 #if (__FreeBSD_version >= 300000) 106ab25eeb5Syz155240 # include <sys/malloc.h> 107ab25eeb5Syz155240 #endif 108ab25eeb5Syz155240 /* END OF INCLUDES */ 109ab25eeb5Syz155240 110ab25eeb5Syz155240 #undef SOCKADDR_IN 111ab25eeb5Syz155240 #define SOCKADDR_IN struct sockaddr_in 112ab25eeb5Syz155240 113ab25eeb5Syz155240 #if !defined(lint) 114ab25eeb5Syz155240 static const char sccsid[] = "@(#)ip_nat.c 1.11 6/5/96 (C) 1995 Darren Reed"; 115ab25eeb5Syz155240 static const char rcsid[] = "@(#)$Id: ip_nat.c,v 2.195.2.42 2005/08/11 19:51:36 darrenr Exp $"; 116ab25eeb5Syz155240 #endif 117ab25eeb5Syz155240 118ab25eeb5Syz155240 119ab25eeb5Syz155240 /* ======================================================================== */ 120ab25eeb5Syz155240 /* How the NAT is organised and works. */ 121ab25eeb5Syz155240 /* */ 122ab25eeb5Syz155240 /* Inside (interface y) NAT Outside (interface x) */ 123ab25eeb5Syz155240 /* -------------------- -+- ------------------------------------- */ 124ab25eeb5Syz155240 /* Packet going | out, processsed by fr_checknatout() for x */ 125ab25eeb5Syz155240 /* ------------> | ------------> */ 126ab25eeb5Syz155240 /* src=10.1.1.1 | src=192.1.1.1 */ 127ab25eeb5Syz155240 /* | */ 128ab25eeb5Syz155240 /* | in, processed by fr_checknatin() for x */ 129ab25eeb5Syz155240 /* <------------ | <------------ */ 130ab25eeb5Syz155240 /* dst=10.1.1.1 | dst=192.1.1.1 */ 131ab25eeb5Syz155240 /* -------------------- -+- ------------------------------------- */ 132ab25eeb5Syz155240 /* fr_checknatout() - changes ip_src and if required, sport */ 133ab25eeb5Syz155240 /* - creates a new mapping, if required. */ 134ab25eeb5Syz155240 /* fr_checknatin() - changes ip_dst and if required, dport */ 135ab25eeb5Syz155240 /* */ 136ab25eeb5Syz155240 /* In the NAT table, internal source is recorded as "in" and externally */ 137ab25eeb5Syz155240 /* seen as "out". */ 138ab25eeb5Syz155240 /* ======================================================================== */ 139ab25eeb5Syz155240 140ab25eeb5Syz155240 141f4b3ec61Sdh155122 static int nat_clearlist __P((ipf_stack_t *)); 142f4b3ec61Sdh155122 static void nat_addnat __P((struct ipnat *, ipf_stack_t *)); 143f4b3ec61Sdh155122 static void nat_addrdr __P((struct ipnat *, ipf_stack_t *)); 144f4b3ec61Sdh155122 static int fr_natgetent __P((caddr_t, ipf_stack_t *)); 145f4b3ec61Sdh155122 static int fr_natgetsz __P((caddr_t, ipf_stack_t *)); 146f4b3ec61Sdh155122 static int fr_natputent __P((caddr_t, int, ipf_stack_t *)); 147f4b3ec61Sdh155122 static void nat_tabmove __P((nat_t *, ipf_stack_t *)); 148ab25eeb5Syz155240 static int nat_match __P((fr_info_t *, ipnat_t *)); 149ab25eeb5Syz155240 static INLINE int nat_newmap __P((fr_info_t *, nat_t *, natinfo_t *)); 150ab25eeb5Syz155240 static INLINE int nat_newrdr __P((fr_info_t *, nat_t *, natinfo_t *)); 151ab25eeb5Syz155240 static hostmap_t *nat_hostmap __P((ipnat_t *, struct in_addr, 152f4b3ec61Sdh155122 struct in_addr, struct in_addr, u_32_t, 153f4b3ec61Sdh155122 ipf_stack_t *)); 154ab25eeb5Syz155240 static INLINE int nat_icmpquerytype4 __P((int)); 155d6c23f6fSyx160601 static int nat_ruleaddrinit __P((ipnat_t *)); 156d6c23f6fSyx160601 static int nat_siocaddnat __P((ipnat_t *, ipnat_t **, int, ipf_stack_t *)); 157d6c23f6fSyx160601 static void nat_siocdelnat __P((ipnat_t *, ipnat_t **, int, ipf_stack_t *)); 158f4b3ec61Sdh155122 static INLINE int nat_icmperrortype4 __P((int)); 159ab25eeb5Syz155240 static INLINE int nat_finalise __P((fr_info_t *, nat_t *, natinfo_t *, 160ab25eeb5Syz155240 tcphdr_t *, nat_t **, int)); 161dcf3e898Sjojemann static INLINE int nat_resolverule __P((ipnat_t *, ipf_stack_t *)); 162381a2a9aSdr146992 static void nat_mssclamp __P((tcphdr_t *, u_32_t, u_short *)); 163f4b3ec61Sdh155122 static int nat_getnext __P((ipftoken_t *, ipfgeniter_t *, ipf_stack_t *)); 164f4b3ec61Sdh155122 static int nat_iterator __P((ipftoken_t *, ipfgeniter_t *, ipf_stack_t *)); 165ea8244dcSJohn Ojemann static int nat_flushtable __P((int, ipf_stack_t *)); 166ab25eeb5Syz155240 1673c50f6d6San207044 #define NAT_HAS_L4_CHANGED(n) \ 16827dbc409San207044 (((n)->nat_flags & (IPN_TCPUDPICMP)) && \ 1693c50f6d6San207044 (n)->nat_inport != (n)->nat_outport) 1703c50f6d6San207044 171ea8244dcSJohn Ojemann 172ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */ 173ab25eeb5Syz155240 /* Function: fr_natinit */ 174ab25eeb5Syz155240 /* Returns: int - 0 == success, -1 == failure */ 175ab25eeb5Syz155240 /* Parameters: Nil */ 176ab25eeb5Syz155240 /* */ 177ab25eeb5Syz155240 /* Initialise all of the NAT locks, tables and other structures. */ 178ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */ 179f4b3ec61Sdh155122 int fr_natinit(ifs) 180f4b3ec61Sdh155122 ipf_stack_t *ifs; 181ab25eeb5Syz155240 { 182ab25eeb5Syz155240 int i; 183ab25eeb5Syz155240 184f4b3ec61Sdh155122 KMALLOCS(ifs->ifs_nat_table[0], nat_t **, 185f4b3ec61Sdh155122 sizeof(nat_t *) * ifs->ifs_ipf_nattable_sz); 186f4b3ec61Sdh155122 if (ifs->ifs_nat_table[0] != NULL) 187f4b3ec61Sdh155122 bzero((char *)ifs->ifs_nat_table[0], 188f4b3ec61Sdh155122 ifs->ifs_ipf_nattable_sz * sizeof(nat_t *)); 189ab25eeb5Syz155240 else 190ab25eeb5Syz155240 return -1; 191ab25eeb5Syz155240 192f4b3ec61Sdh155122 KMALLOCS(ifs->ifs_nat_table[1], nat_t **, 193f4b3ec61Sdh155122 sizeof(nat_t *) * ifs->ifs_ipf_nattable_sz); 194f4b3ec61Sdh155122 if (ifs->ifs_nat_table[1] != NULL) 195f4b3ec61Sdh155122 bzero((char *)ifs->ifs_nat_table[1], 196f4b3ec61Sdh155122 ifs->ifs_ipf_nattable_sz * sizeof(nat_t *)); 197ab25eeb5Syz155240 else 198ab25eeb5Syz155240 return -2; 199ab25eeb5Syz155240 200f4b3ec61Sdh155122 KMALLOCS(ifs->ifs_nat_rules, ipnat_t **, 201f4b3ec61Sdh155122 sizeof(ipnat_t *) * ifs->ifs_ipf_natrules_sz); 202f4b3ec61Sdh155122 if (ifs->ifs_nat_rules != NULL) 203f4b3ec61Sdh155122 bzero((char *)ifs->ifs_nat_rules, 204f4b3ec61Sdh155122 ifs->ifs_ipf_natrules_sz * sizeof(ipnat_t *)); 205ab25eeb5Syz155240 else 206ab25eeb5Syz155240 return -3; 207ab25eeb5Syz155240 208f4b3ec61Sdh155122 KMALLOCS(ifs->ifs_rdr_rules, ipnat_t **, 209f4b3ec61Sdh155122 sizeof(ipnat_t *) * ifs->ifs_ipf_rdrrules_sz); 210f4b3ec61Sdh155122 if (ifs->ifs_rdr_rules != NULL) 211f4b3ec61Sdh155122 bzero((char *)ifs->ifs_rdr_rules, 212f4b3ec61Sdh155122 ifs->ifs_ipf_rdrrules_sz * sizeof(ipnat_t *)); 213ab25eeb5Syz155240 else 214ab25eeb5Syz155240 return -4; 215ab25eeb5Syz155240 216f4b3ec61Sdh155122 KMALLOCS(ifs->ifs_maptable, hostmap_t **, 217f4b3ec61Sdh155122 sizeof(hostmap_t *) * ifs->ifs_ipf_hostmap_sz); 218f4b3ec61Sdh155122 if (ifs->ifs_maptable != NULL) 219f4b3ec61Sdh155122 bzero((char *)ifs->ifs_maptable, 220f4b3ec61Sdh155122 sizeof(hostmap_t *) * ifs->ifs_ipf_hostmap_sz); 221ab25eeb5Syz155240 else 222ab25eeb5Syz155240 return -5; 223ab25eeb5Syz155240 224f4b3ec61Sdh155122 ifs->ifs_ipf_hm_maplist = NULL; 225ab25eeb5Syz155240 226f4b3ec61Sdh155122 KMALLOCS(ifs->ifs_nat_stats.ns_bucketlen[0], u_long *, 227f4b3ec61Sdh155122 ifs->ifs_ipf_nattable_sz * sizeof(u_long)); 228f4b3ec61Sdh155122 if (ifs->ifs_nat_stats.ns_bucketlen[0] == NULL) 229f4b3ec61Sdh155122 return -1; 230f4b3ec61Sdh155122 bzero((char *)ifs->ifs_nat_stats.ns_bucketlen[0], 231f4b3ec61Sdh155122 ifs->ifs_ipf_nattable_sz * sizeof(u_long)); 232ab25eeb5Syz155240 233f4b3ec61Sdh155122 KMALLOCS(ifs->ifs_nat_stats.ns_bucketlen[1], u_long *, 234f4b3ec61Sdh155122 ifs->ifs_ipf_nattable_sz * sizeof(u_long)); 235f4b3ec61Sdh155122 if (ifs->ifs_nat_stats.ns_bucketlen[1] == NULL) 236f4b3ec61Sdh155122 return -1; 237f4b3ec61Sdh155122 bzero((char *)ifs->ifs_nat_stats.ns_bucketlen[1], 238f4b3ec61Sdh155122 ifs->ifs_ipf_nattable_sz * sizeof(u_long)); 239ab25eeb5Syz155240 240f4b3ec61Sdh155122 if (ifs->ifs_fr_nat_maxbucket == 0) { 241f4b3ec61Sdh155122 for (i = ifs->ifs_ipf_nattable_sz; i > 0; i >>= 1) 242f4b3ec61Sdh155122 ifs->ifs_fr_nat_maxbucket++; 243f4b3ec61Sdh155122 ifs->ifs_fr_nat_maxbucket *= 2; 244ab25eeb5Syz155240 } 245ab25eeb5Syz155240 246f4b3ec61Sdh155122 fr_sttab_init(ifs->ifs_nat_tqb, ifs); 247ab25eeb5Syz155240 /* 248ab25eeb5Syz155240 * Increase this because we may have "keep state" following this too 249ab25eeb5Syz155240 * and packet storms can occur if this is removed too quickly. 250ab25eeb5Syz155240 */ 251f4b3ec61Sdh155122 ifs->ifs_nat_tqb[IPF_TCPS_CLOSED].ifq_ttl = ifs->ifs_fr_tcplastack; 252f4b3ec61Sdh155122 ifs->ifs_nat_tqb[IPF_TCP_NSTATES - 1].ifq_next = &ifs->ifs_nat_udptq; 253f4b3ec61Sdh155122 ifs->ifs_nat_udptq.ifq_ttl = ifs->ifs_fr_defnatage; 254f4b3ec61Sdh155122 ifs->ifs_nat_udptq.ifq_ref = 1; 255f4b3ec61Sdh155122 ifs->ifs_nat_udptq.ifq_head = NULL; 256f4b3ec61Sdh155122 ifs->ifs_nat_udptq.ifq_tail = &ifs->ifs_nat_udptq.ifq_head; 257f4b3ec61Sdh155122 MUTEX_INIT(&ifs->ifs_nat_udptq.ifq_lock, "nat ipftq udp tab"); 258f4b3ec61Sdh155122 ifs->ifs_nat_udptq.ifq_next = &ifs->ifs_nat_icmptq; 259f4b3ec61Sdh155122 ifs->ifs_nat_icmptq.ifq_ttl = ifs->ifs_fr_defnaticmpage; 260f4b3ec61Sdh155122 ifs->ifs_nat_icmptq.ifq_ref = 1; 261f4b3ec61Sdh155122 ifs->ifs_nat_icmptq.ifq_head = NULL; 262f4b3ec61Sdh155122 ifs->ifs_nat_icmptq.ifq_tail = &ifs->ifs_nat_icmptq.ifq_head; 263f4b3ec61Sdh155122 MUTEX_INIT(&ifs->ifs_nat_icmptq.ifq_lock, "nat icmp ipftq tab"); 264f4b3ec61Sdh155122 ifs->ifs_nat_icmptq.ifq_next = &ifs->ifs_nat_iptq; 265f4b3ec61Sdh155122 ifs->ifs_nat_iptq.ifq_ttl = ifs->ifs_fr_defnatipage; 266f4b3ec61Sdh155122 ifs->ifs_nat_iptq.ifq_ref = 1; 267f4b3ec61Sdh155122 ifs->ifs_nat_iptq.ifq_head = NULL; 268f4b3ec61Sdh155122 ifs->ifs_nat_iptq.ifq_tail = &ifs->ifs_nat_iptq.ifq_head; 269f4b3ec61Sdh155122 MUTEX_INIT(&ifs->ifs_nat_iptq.ifq_lock, "nat ip ipftq tab"); 270f4b3ec61Sdh155122 ifs->ifs_nat_iptq.ifq_next = NULL; 271ab25eeb5Syz155240 272ab25eeb5Syz155240 for (i = 0; i < IPF_TCP_NSTATES; i++) { 273f4b3ec61Sdh155122 if (ifs->ifs_nat_tqb[i].ifq_ttl < ifs->ifs_fr_defnaticmpage) 274f4b3ec61Sdh155122 ifs->ifs_nat_tqb[i].ifq_ttl = ifs->ifs_fr_defnaticmpage; 275ab25eeb5Syz155240 #ifdef LARGE_NAT 276f4b3ec61Sdh155122 else if (ifs->ifs_nat_tqb[i].ifq_ttl > ifs->ifs_fr_defnatage) 277f4b3ec61Sdh155122 ifs->ifs_nat_tqb[i].ifq_ttl = ifs->ifs_fr_defnatage; 278ab25eeb5Syz155240 #endif 279ab25eeb5Syz155240 } 280ab25eeb5Syz155240 281ab25eeb5Syz155240 /* 282ab25eeb5Syz155240 * Increase this because we may have "keep state" following 283ab25eeb5Syz155240 * this too and packet storms can occur if this is removed 284ab25eeb5Syz155240 * too quickly. 285ab25eeb5Syz155240 */ 286f4b3ec61Sdh155122 ifs->ifs_nat_tqb[IPF_TCPS_CLOSED].ifq_ttl = 287f4b3ec61Sdh155122 ifs->ifs_nat_tqb[IPF_TCPS_LAST_ACK].ifq_ttl; 288ab25eeb5Syz155240 289f4b3ec61Sdh155122 RWLOCK_INIT(&ifs->ifs_ipf_nat, "ipf IP NAT rwlock"); 290f4b3ec61Sdh155122 RWLOCK_INIT(&ifs->ifs_ipf_natfrag, "ipf IP NAT-Frag rwlock"); 291f4b3ec61Sdh155122 MUTEX_INIT(&ifs->ifs_ipf_nat_new, "ipf nat new mutex"); 292f4b3ec61Sdh155122 MUTEX_INIT(&ifs->ifs_ipf_natio, "ipf nat io mutex"); 293ab25eeb5Syz155240 294f4b3ec61Sdh155122 ifs->ifs_fr_nat_init = 1; 295ea8244dcSJohn Ojemann ifs->ifs_nat_last_force_flush = ifs->ifs_fr_ticks; 296ab25eeb5Syz155240 return 0; 297ab25eeb5Syz155240 } 298ab25eeb5Syz155240 299ab25eeb5Syz155240 300ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */ 301ab25eeb5Syz155240 /* Function: nat_addrdr */ 302ab25eeb5Syz155240 /* Returns: Nil */ 303ab25eeb5Syz155240 /* Parameters: n(I) - pointer to NAT rule to add */ 304ab25eeb5Syz155240 /* */ 305ab25eeb5Syz155240 /* Adds a redirect rule to the hash table of redirect rules and the list of */ 306ab25eeb5Syz155240 /* loaded NAT rules. Updates the bitmask indicating which netmasks are in */ 307ab25eeb5Syz155240 /* use by redirect rules. */ 308ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */ 309f4b3ec61Sdh155122 static void nat_addrdr(n, ifs) 310ab25eeb5Syz155240 ipnat_t *n; 311f4b3ec61Sdh155122 ipf_stack_t *ifs; 312ab25eeb5Syz155240 { 313ab25eeb5Syz155240 ipnat_t **np; 314ab25eeb5Syz155240 u_32_t j; 315ab25eeb5Syz155240 u_int hv; 316ab25eeb5Syz155240 int k; 317ab25eeb5Syz155240 318ab25eeb5Syz155240 k = count4bits(n->in_outmsk); 319ab25eeb5Syz155240 if ((k >= 0) && (k != 32)) 320f4b3ec61Sdh155122 ifs->ifs_rdr_masks |= 1 << k; 321ab25eeb5Syz155240 j = (n->in_outip & n->in_outmsk); 322f4b3ec61Sdh155122 hv = NAT_HASH_FN(j, 0, ifs->ifs_ipf_rdrrules_sz); 323f4b3ec61Sdh155122 np = ifs->ifs_rdr_rules + hv; 324ab25eeb5Syz155240 while (*np != NULL) 325ab25eeb5Syz155240 np = &(*np)->in_rnext; 326ab25eeb5Syz155240 n->in_rnext = NULL; 327ab25eeb5Syz155240 n->in_prnext = np; 328ab25eeb5Syz155240 n->in_hv = hv; 329ab25eeb5Syz155240 *np = n; 330ab25eeb5Syz155240 } 331ab25eeb5Syz155240 332ab25eeb5Syz155240 333ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */ 334ab25eeb5Syz155240 /* Function: nat_addnat */ 335ab25eeb5Syz155240 /* Returns: Nil */ 336ab25eeb5Syz155240 /* Parameters: n(I) - pointer to NAT rule to add */ 337ab25eeb5Syz155240 /* */ 338ab25eeb5Syz155240 /* Adds a NAT map rule to the hash table of rules and the list of loaded */ 339ab25eeb5Syz155240 /* NAT rules. Updates the bitmask indicating which netmasks are in use by */ 340ab25eeb5Syz155240 /* redirect rules. */ 341ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */ 342f4b3ec61Sdh155122 static void nat_addnat(n, ifs) 343ab25eeb5Syz155240 ipnat_t *n; 344f4b3ec61Sdh155122 ipf_stack_t *ifs; 345ab25eeb5Syz155240 { 346ab25eeb5Syz155240 ipnat_t **np; 347ab25eeb5Syz155240 u_32_t j; 348ab25eeb5Syz155240 u_int hv; 349ab25eeb5Syz155240 int k; 350ab25eeb5Syz155240 351ab25eeb5Syz155240 k = count4bits(n->in_inmsk); 352ab25eeb5Syz155240 if ((k >= 0) && (k != 32)) 353f4b3ec61Sdh155122 ifs->ifs_nat_masks |= 1 << k; 354ab25eeb5Syz155240 j = (n->in_inip & n->in_inmsk); 355f4b3ec61Sdh155122 hv = NAT_HASH_FN(j, 0, ifs->ifs_ipf_natrules_sz); 356f4b3ec61Sdh155122 np = ifs->ifs_nat_rules + hv; 357ab25eeb5Syz155240 while (*np != NULL) 358ab25eeb5Syz155240 np = &(*np)->in_mnext; 359ab25eeb5Syz155240 n->in_mnext = NULL; 360ab25eeb5Syz155240 n->in_pmnext = np; 361ab25eeb5Syz155240 n->in_hv = hv; 362ab25eeb5Syz155240 *np = n; 363ab25eeb5Syz155240 } 364ab25eeb5Syz155240 365ab25eeb5Syz155240 366ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */ 367ab25eeb5Syz155240 /* Function: nat_delrdr */ 368ab25eeb5Syz155240 /* Returns: Nil */ 369ab25eeb5Syz155240 /* Parameters: n(I) - pointer to NAT rule to delete */ 370ab25eeb5Syz155240 /* */ 371ab25eeb5Syz155240 /* Removes a redirect rule from the hash table of redirect rules. */ 372ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */ 373d6c23f6fSyx160601 void nat_delrdr(n) 374ab25eeb5Syz155240 ipnat_t *n; 375ab25eeb5Syz155240 { 376ab25eeb5Syz155240 if (n->in_rnext) 377ab25eeb5Syz155240 n->in_rnext->in_prnext = n->in_prnext; 378ab25eeb5Syz155240 *n->in_prnext = n->in_rnext; 379ab25eeb5Syz155240 } 380ab25eeb5Syz155240 381ab25eeb5Syz155240 382ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */ 383ab25eeb5Syz155240 /* Function: nat_delnat */ 384ab25eeb5Syz155240 /* Returns: Nil */ 385ab25eeb5Syz155240 /* Parameters: n(I) - pointer to NAT rule to delete */ 386ab25eeb5Syz155240 /* */ 387ab25eeb5Syz155240 /* Removes a NAT map rule from the hash table of NAT map rules. */ 388ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */ 389d6c23f6fSyx160601 void nat_delnat(n) 390ab25eeb5Syz155240 ipnat_t *n; 391ab25eeb5Syz155240 { 392ab25eeb5Syz155240 if (n->in_mnext != NULL) 393ab25eeb5Syz155240 n->in_mnext->in_pmnext = n->in_pmnext; 394ab25eeb5Syz155240 *n->in_pmnext = n->in_mnext; 395ab25eeb5Syz155240 } 396ab25eeb5Syz155240 397ab25eeb5Syz155240 398ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */ 399ab25eeb5Syz155240 /* Function: nat_hostmap */ 400ab25eeb5Syz155240 /* Returns: struct hostmap* - NULL if no hostmap could be created, */ 401ab25eeb5Syz155240 /* else a pointer to the hostmapping to use */ 402ab25eeb5Syz155240 /* Parameters: np(I) - pointer to NAT rule */ 403ab25eeb5Syz155240 /* real(I) - real IP address */ 404ab25eeb5Syz155240 /* map(I) - mapped IP address */ 405ab25eeb5Syz155240 /* port(I) - destination port number */ 406ab25eeb5Syz155240 /* Write Locks: ipf_nat */ 407ab25eeb5Syz155240 /* */ 408ab25eeb5Syz155240 /* Check if an ip address has already been allocated for a given mapping */ 409ab25eeb5Syz155240 /* that is not doing port based translation. If is not yet allocated, then */ 410ab25eeb5Syz155240 /* create a new entry if a non-NULL NAT rule pointer has been supplied. */ 411ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */ 412f4b3ec61Sdh155122 static struct hostmap *nat_hostmap(np, src, dst, map, port, ifs) 413ab25eeb5Syz155240 ipnat_t *np; 414ab25eeb5Syz155240 struct in_addr src; 415ab25eeb5Syz155240 struct in_addr dst; 416ab25eeb5Syz155240 struct in_addr map; 417ab25eeb5Syz155240 u_32_t port; 418f4b3ec61Sdh155122 ipf_stack_t *ifs; 419ab25eeb5Syz155240 { 420ab25eeb5Syz155240 hostmap_t *hm; 421ab25eeb5Syz155240 u_int hv; 422ab25eeb5Syz155240 423ab25eeb5Syz155240 hv = (src.s_addr ^ dst.s_addr); 424ab25eeb5Syz155240 hv += src.s_addr; 425ab25eeb5Syz155240 hv += dst.s_addr; 426ab25eeb5Syz155240 hv %= HOSTMAP_SIZE; 427f4b3ec61Sdh155122 for (hm = ifs->ifs_maptable[hv]; hm; hm = hm->hm_next) 428ab25eeb5Syz155240 if ((hm->hm_srcip.s_addr == src.s_addr) && 429ab25eeb5Syz155240 (hm->hm_dstip.s_addr == dst.s_addr) && 430ab25eeb5Syz155240 ((np == NULL) || (np == hm->hm_ipnat)) && 431ab25eeb5Syz155240 ((port == 0) || (port == hm->hm_port))) { 432ab25eeb5Syz155240 hm->hm_ref++; 433ab25eeb5Syz155240 return hm; 434ab25eeb5Syz155240 } 435ab25eeb5Syz155240 436ab25eeb5Syz155240 if (np == NULL) 437ab25eeb5Syz155240 return NULL; 438ab25eeb5Syz155240 439ab25eeb5Syz155240 KMALLOC(hm, hostmap_t *); 440ab25eeb5Syz155240 if (hm) { 441f4b3ec61Sdh155122 hm->hm_hnext = ifs->ifs_ipf_hm_maplist; 442f4b3ec61Sdh155122 hm->hm_phnext = &ifs->ifs_ipf_hm_maplist; 443f4b3ec61Sdh155122 if (ifs->ifs_ipf_hm_maplist != NULL) 444f4b3ec61Sdh155122 ifs->ifs_ipf_hm_maplist->hm_phnext = &hm->hm_hnext; 445f4b3ec61Sdh155122 ifs->ifs_ipf_hm_maplist = hm; 446f4b3ec61Sdh155122 447f4b3ec61Sdh155122 hm->hm_next = ifs->ifs_maptable[hv]; 448f4b3ec61Sdh155122 hm->hm_pnext = ifs->ifs_maptable + hv; 449f4b3ec61Sdh155122 if (ifs->ifs_maptable[hv] != NULL) 450f4b3ec61Sdh155122 ifs->ifs_maptable[hv]->hm_pnext = &hm->hm_next; 451f4b3ec61Sdh155122 ifs->ifs_maptable[hv] = hm; 452ab25eeb5Syz155240 hm->hm_ipnat = np; 453ab25eeb5Syz155240 hm->hm_srcip = src; 454ab25eeb5Syz155240 hm->hm_dstip = dst; 455ab25eeb5Syz155240 hm->hm_mapip = map; 456ab25eeb5Syz155240 hm->hm_ref = 1; 457ab25eeb5Syz155240 hm->hm_port = port; 458d6c23f6fSyx160601 hm->hm_v = 4; 459ab25eeb5Syz155240 } 460ab25eeb5Syz155240 return hm; 461ab25eeb5Syz155240 } 462ab25eeb5Syz155240 463ab25eeb5Syz155240 464ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */ 46590b0a856Sjojemann /* Function: fr_hostmapdel */ 466ab25eeb5Syz155240 /* Returns: Nil */ 46790b0a856Sjojemann /* Parameters: hmp(I) - pointer to pointer to hostmap structure */ 468ab25eeb5Syz155240 /* Write Locks: ipf_nat */ 469ab25eeb5Syz155240 /* */ 470ab25eeb5Syz155240 /* Decrement the references to this hostmap structure by one. If this */ 471ab25eeb5Syz155240 /* reaches zero then remove it and free it. */ 472ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */ 47390b0a856Sjojemann void fr_hostmapdel(hmp) 47490b0a856Sjojemann struct hostmap **hmp; 475ab25eeb5Syz155240 { 47690b0a856Sjojemann struct hostmap *hm; 47790b0a856Sjojemann 47890b0a856Sjojemann hm = *hmp; 47990b0a856Sjojemann *hmp = NULL; 48090b0a856Sjojemann 481ab25eeb5Syz155240 hm->hm_ref--; 482ab25eeb5Syz155240 if (hm->hm_ref == 0) { 483ab25eeb5Syz155240 if (hm->hm_next) 484ab25eeb5Syz155240 hm->hm_next->hm_pnext = hm->hm_pnext; 485ab25eeb5Syz155240 *hm->hm_pnext = hm->hm_next; 486f4b3ec61Sdh155122 if (hm->hm_hnext) 487f4b3ec61Sdh155122 hm->hm_hnext->hm_phnext = hm->hm_phnext; 488f4b3ec61Sdh155122 *hm->hm_phnext = hm->hm_hnext; 489ab25eeb5Syz155240 KFREE(hm); 490ab25eeb5Syz155240 } 491ab25eeb5Syz155240 } 492ab25eeb5Syz155240 493ab25eeb5Syz155240 494ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */ 495ab25eeb5Syz155240 /* Function: fix_outcksum */ 496ab25eeb5Syz155240 /* Returns: Nil */ 497381a2a9aSdr146992 /* Parameters: sp(I) - location of 16bit checksum to update */ 498ab25eeb5Syz155240 /* n((I) - amount to adjust checksum by */ 499ab25eeb5Syz155240 /* */ 500ab25eeb5Syz155240 /* Adjusts the 16bit checksum by "n" for packets going out. */ 501ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */ 502381a2a9aSdr146992 void fix_outcksum(sp, n) 503ab25eeb5Syz155240 u_short *sp; 504ab25eeb5Syz155240 u_32_t n; 505ab25eeb5Syz155240 { 506ab25eeb5Syz155240 u_short sumshort; 507ab25eeb5Syz155240 u_32_t sum1; 508ab25eeb5Syz155240 509ab25eeb5Syz155240 if (n == 0) 510ab25eeb5Syz155240 return; 511ab25eeb5Syz155240 512ab25eeb5Syz155240 sum1 = (~ntohs(*sp)) & 0xffff; 513ab25eeb5Syz155240 sum1 += (n); 514ab25eeb5Syz155240 sum1 = (sum1 >> 16) + (sum1 & 0xffff); 515ab25eeb5Syz155240 /* Again */ 516ab25eeb5Syz155240 sum1 = (sum1 >> 16) + (sum1 & 0xffff); 517ab25eeb5Syz155240 sumshort = ~(u_short)sum1; 518ab25eeb5Syz155240 *(sp) = htons(sumshort); 519ab25eeb5Syz155240 } 520ab25eeb5Syz155240 521ab25eeb5Syz155240 522ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */ 523ab25eeb5Syz155240 /* Function: fix_incksum */ 524ab25eeb5Syz155240 /* Returns: Nil */ 525381a2a9aSdr146992 /* Parameters: sp(I) - location of 16bit checksum to update */ 526ab25eeb5Syz155240 /* n((I) - amount to adjust checksum by */ 527ab25eeb5Syz155240 /* */ 528ab25eeb5Syz155240 /* Adjusts the 16bit checksum by "n" for packets going in. */ 529ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */ 530381a2a9aSdr146992 void fix_incksum(sp, n) 531ab25eeb5Syz155240 u_short *sp; 532ab25eeb5Syz155240 u_32_t n; 533ab25eeb5Syz155240 { 534ab25eeb5Syz155240 u_short sumshort; 535ab25eeb5Syz155240 u_32_t sum1; 536ab25eeb5Syz155240 537ab25eeb5Syz155240 if (n == 0) 538ab25eeb5Syz155240 return; 539ab25eeb5Syz155240 540ab25eeb5Syz155240 sum1 = (~ntohs(*sp)) & 0xffff; 541ab25eeb5Syz155240 sum1 += ~(n) & 0xffff; 542ab25eeb5Syz155240 sum1 = (sum1 >> 16) + (sum1 & 0xffff); 543ab25eeb5Syz155240 /* Again */ 544ab25eeb5Syz155240 sum1 = (sum1 >> 16) + (sum1 & 0xffff); 545ab25eeb5Syz155240 sumshort = ~(u_short)sum1; 546ab25eeb5Syz155240 *(sp) = htons(sumshort); 547ab25eeb5Syz155240 } 548ab25eeb5Syz155240 549ab25eeb5Syz155240 550ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */ 551ab25eeb5Syz155240 /* Function: fix_datacksum */ 552ab25eeb5Syz155240 /* Returns: Nil */ 553ab25eeb5Syz155240 /* Parameters: sp(I) - location of 16bit checksum to update */ 554ab25eeb5Syz155240 /* n((I) - amount to adjust checksum by */ 555ab25eeb5Syz155240 /* */ 556ab25eeb5Syz155240 /* Fix_datacksum is used *only* for the adjustments of checksums in the */ 557ab25eeb5Syz155240 /* data section of an IP packet. */ 558ab25eeb5Syz155240 /* */ 559ab25eeb5Syz155240 /* The only situation in which you need to do this is when NAT'ing an */ 560ab25eeb5Syz155240 /* ICMP error message. Such a message, contains in its body the IP header */ 561ab25eeb5Syz155240 /* of the original IP packet, that causes the error. */ 562ab25eeb5Syz155240 /* */ 563ab25eeb5Syz155240 /* You can't use fix_incksum or fix_outcksum in that case, because for the */ 564ab25eeb5Syz155240 /* kernel the data section of the ICMP error is just data, and no special */ 565ab25eeb5Syz155240 /* processing like hardware cksum or ntohs processing have been done by the */ 566ab25eeb5Syz155240 /* kernel on the data section. */ 567ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */ 568ab25eeb5Syz155240 void fix_datacksum(sp, n) 569ab25eeb5Syz155240 u_short *sp; 570ab25eeb5Syz155240 u_32_t n; 571ab25eeb5Syz155240 { 572ab25eeb5Syz155240 u_short sumshort; 573ab25eeb5Syz155240 u_32_t sum1; 574ab25eeb5Syz155240 575ab25eeb5Syz155240 if (n == 0) 576ab25eeb5Syz155240 return; 577ab25eeb5Syz155240 578ab25eeb5Syz155240 sum1 = (~ntohs(*sp)) & 0xffff; 579ab25eeb5Syz155240 sum1 += (n); 580ab25eeb5Syz155240 sum1 = (sum1 >> 16) + (sum1 & 0xffff); 581ab25eeb5Syz155240 /* Again */ 582ab25eeb5Syz155240 sum1 = (sum1 >> 16) + (sum1 & 0xffff); 583ab25eeb5Syz155240 sumshort = ~(u_short)sum1; 584ab25eeb5Syz155240 *(sp) = htons(sumshort); 585ab25eeb5Syz155240 } 586ab25eeb5Syz155240 587ab25eeb5Syz155240 588ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */ 589ab25eeb5Syz155240 /* Function: fr_nat_ioctl */ 590ab25eeb5Syz155240 /* Returns: int - 0 == success, != 0 == failure */ 591ab25eeb5Syz155240 /* Parameters: data(I) - pointer to ioctl data */ 592ab25eeb5Syz155240 /* cmd(I) - ioctl command integer */ 593ab25eeb5Syz155240 /* mode(I) - file mode bits used with open */ 594ea8244dcSJohn Ojemann /* uid(I) - uid of caller */ 595ea8244dcSJohn Ojemann /* ctx(I) - pointer to give the uid context */ 596ea8244dcSJohn Ojemann /* ifs - ipf stack instance */ 597ab25eeb5Syz155240 /* */ 598ab25eeb5Syz155240 /* Processes an ioctl call made to operate on the IP Filter NAT device. */ 599ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */ 600f4b3ec61Sdh155122 int fr_nat_ioctl(data, cmd, mode, uid, ctx, ifs) 601ab25eeb5Syz155240 ioctlcmd_t cmd; 602ab25eeb5Syz155240 caddr_t data; 603f4b3ec61Sdh155122 int mode, uid; 604f4b3ec61Sdh155122 void *ctx; 605f4b3ec61Sdh155122 ipf_stack_t *ifs; 606ab25eeb5Syz155240 { 607ab25eeb5Syz155240 ipnat_t *nat, *nt, *n = NULL, **np = NULL; 608ab25eeb5Syz155240 int error = 0, ret, arg, getlock; 609ab25eeb5Syz155240 ipnat_t natd; 610ab25eeb5Syz155240 611ab25eeb5Syz155240 #if (BSD >= 199306) && defined(_KERNEL) 612ab25eeb5Syz155240 if ((securelevel >= 2) && (mode & FWRITE)) 613ab25eeb5Syz155240 return EPERM; 614ab25eeb5Syz155240 #endif 615ab25eeb5Syz155240 616ab25eeb5Syz155240 #if defined(__osf__) && defined(_KERNEL) 617ab25eeb5Syz155240 getlock = 0; 618ab25eeb5Syz155240 #else 619ab25eeb5Syz155240 getlock = (mode & NAT_LOCKHELD) ? 0 : 1; 620ab25eeb5Syz155240 #endif 621ab25eeb5Syz155240 622ab25eeb5Syz155240 nat = NULL; /* XXX gcc -Wuninitialized */ 623ab25eeb5Syz155240 if (cmd == (ioctlcmd_t)SIOCADNAT) { 624ab25eeb5Syz155240 KMALLOC(nt, ipnat_t *); 625ab25eeb5Syz155240 } else { 626ab25eeb5Syz155240 nt = NULL; 627ab25eeb5Syz155240 } 628ab25eeb5Syz155240 629ab25eeb5Syz155240 if ((cmd == (ioctlcmd_t)SIOCADNAT) || (cmd == (ioctlcmd_t)SIOCRMNAT)) { 630ab25eeb5Syz155240 if (mode & NAT_SYSSPACE) { 631ab25eeb5Syz155240 bcopy(data, (char *)&natd, sizeof(natd)); 632ab25eeb5Syz155240 error = 0; 633ab25eeb5Syz155240 } else { 634ab25eeb5Syz155240 error = fr_inobj(data, &natd, IPFOBJ_IPNAT); 635ab25eeb5Syz155240 } 636ab25eeb5Syz155240 637ab25eeb5Syz155240 } 638ab25eeb5Syz155240 639ab25eeb5Syz155240 if (error != 0) 640ab25eeb5Syz155240 goto done; 641ab25eeb5Syz155240 642ab25eeb5Syz155240 /* 643ab25eeb5Syz155240 * For add/delete, look to see if the NAT entry is already present 644ab25eeb5Syz155240 */ 645ab25eeb5Syz155240 if ((cmd == (ioctlcmd_t)SIOCADNAT) || (cmd == (ioctlcmd_t)SIOCRMNAT)) { 646ab25eeb5Syz155240 nat = &natd; 647ab25eeb5Syz155240 if (nat->in_v == 0) /* For backward compat. */ 648ab25eeb5Syz155240 nat->in_v = 4; 649ab25eeb5Syz155240 nat->in_flags &= IPN_USERFLAGS; 650ab25eeb5Syz155240 if ((nat->in_redir & NAT_MAPBLK) == 0) { 651ab25eeb5Syz155240 if ((nat->in_flags & IPN_SPLIT) == 0) 652ab25eeb5Syz155240 nat->in_inip &= nat->in_inmsk; 653ab25eeb5Syz155240 if ((nat->in_flags & IPN_IPRANGE) == 0) 654ab25eeb5Syz155240 nat->in_outip &= nat->in_outmsk; 655ab25eeb5Syz155240 } 656f4b3ec61Sdh155122 MUTEX_ENTER(&ifs->ifs_ipf_natio); 657f4b3ec61Sdh155122 for (np = &ifs->ifs_nat_list; ((n = *np) != NULL); 658f4b3ec61Sdh155122 np = &n->in_next) 6598899fcfaSjojemann if (bcmp((char *)&nat->in_flags, (char *)&n->in_flags, 6608899fcfaSjojemann IPN_CMPSIZ) == 0) { 6618899fcfaSjojemann if (nat->in_redir == NAT_REDIRECT && 6628899fcfaSjojemann nat->in_pnext != n->in_pnext) 6638899fcfaSjojemann continue; 664ab25eeb5Syz155240 break; 665ab25eeb5Syz155240 } 6668899fcfaSjojemann } 667ab25eeb5Syz155240 668ab25eeb5Syz155240 switch (cmd) 669ab25eeb5Syz155240 { 670f4b3ec61Sdh155122 case SIOCGENITER : 671f4b3ec61Sdh155122 { 672f4b3ec61Sdh155122 ipfgeniter_t iter; 673f4b3ec61Sdh155122 ipftoken_t *token; 674f4b3ec61Sdh155122 675f4b3ec61Sdh155122 error = fr_inobj(data, &iter, IPFOBJ_GENITER); 676f4b3ec61Sdh155122 if (error != 0) 677f4b3ec61Sdh155122 break; 678f4b3ec61Sdh155122 679f4b3ec61Sdh155122 token = ipf_findtoken(iter.igi_type, uid, ctx, ifs); 680f4b3ec61Sdh155122 if (token != NULL) 681f4b3ec61Sdh155122 error = nat_iterator(token, &iter, ifs); 682f4b3ec61Sdh155122 else 683f4b3ec61Sdh155122 error = ESRCH; 684f4b3ec61Sdh155122 RWLOCK_EXIT(&ifs->ifs_ipf_tokens); 685f4b3ec61Sdh155122 break; 686f4b3ec61Sdh155122 } 687ab25eeb5Syz155240 #ifdef IPFILTER_LOG 688ab25eeb5Syz155240 case SIOCIPFFB : 689ab25eeb5Syz155240 { 690ab25eeb5Syz155240 int tmp; 691ab25eeb5Syz155240 692ab25eeb5Syz155240 if (!(mode & FWRITE)) 693ab25eeb5Syz155240 error = EPERM; 694ab25eeb5Syz155240 else { 695f4b3ec61Sdh155122 tmp = ipflog_clear(IPL_LOGNAT, ifs); 696bb1d9de5SJohn Ojemann error = BCOPYOUT((char *)&tmp, (char *)data, 697bb1d9de5SJohn Ojemann sizeof(tmp)); 698bb1d9de5SJohn Ojemann if (error != 0) 699bb1d9de5SJohn Ojemann error = EFAULT; 700ab25eeb5Syz155240 } 701ab25eeb5Syz155240 break; 702ab25eeb5Syz155240 } 703ab25eeb5Syz155240 case SIOCSETLG : 704bb1d9de5SJohn Ojemann if (!(mode & FWRITE)) { 705ab25eeb5Syz155240 error = EPERM; 706bb1d9de5SJohn Ojemann } else { 707bb1d9de5SJohn Ojemann error = BCOPYIN((char *)data, 708f4b3ec61Sdh155122 (char *)&ifs->ifs_nat_logging, 709f4b3ec61Sdh155122 sizeof(ifs->ifs_nat_logging)); 710bb1d9de5SJohn Ojemann if (error != 0) 711bb1d9de5SJohn Ojemann error = EFAULT; 712ab25eeb5Syz155240 } 713ab25eeb5Syz155240 break; 714ab25eeb5Syz155240 case SIOCGETLG : 715bb1d9de5SJohn Ojemann error = BCOPYOUT((char *)&ifs->ifs_nat_logging, (char *)data, 716f4b3ec61Sdh155122 sizeof(ifs->ifs_nat_logging)); 717bb1d9de5SJohn Ojemann if (error != 0) 718bb1d9de5SJohn Ojemann error = EFAULT; 719ab25eeb5Syz155240 break; 720ab25eeb5Syz155240 case FIONREAD : 721f4b3ec61Sdh155122 arg = ifs->ifs_iplused[IPL_LOGNAT]; 722bb1d9de5SJohn Ojemann error = BCOPYOUT(&arg, data, sizeof(arg)); 723bb1d9de5SJohn Ojemann if (error != 0) 724bb1d9de5SJohn Ojemann error = EFAULT; 725ab25eeb5Syz155240 break; 726ab25eeb5Syz155240 #endif 727ab25eeb5Syz155240 case SIOCADNAT : 728ab25eeb5Syz155240 if (!(mode & FWRITE)) { 729ab25eeb5Syz155240 error = EPERM; 730ab25eeb5Syz155240 } else if (n != NULL) { 731ab25eeb5Syz155240 error = EEXIST; 732ab25eeb5Syz155240 } else if (nt == NULL) { 733ab25eeb5Syz155240 error = ENOMEM; 734ab25eeb5Syz155240 } 735ab25eeb5Syz155240 if (error != 0) { 736f4b3ec61Sdh155122 MUTEX_EXIT(&ifs->ifs_ipf_natio); 737ab25eeb5Syz155240 break; 738ab25eeb5Syz155240 } 739ab25eeb5Syz155240 bcopy((char *)nat, (char *)nt, sizeof(*n)); 740f4b3ec61Sdh155122 error = nat_siocaddnat(nt, np, getlock, ifs); 741f4b3ec61Sdh155122 MUTEX_EXIT(&ifs->ifs_ipf_natio); 742ab25eeb5Syz155240 if (error == 0) 743ab25eeb5Syz155240 nt = NULL; 744ab25eeb5Syz155240 break; 745ab25eeb5Syz155240 case SIOCRMNAT : 746ab25eeb5Syz155240 if (!(mode & FWRITE)) { 747ab25eeb5Syz155240 error = EPERM; 748ab25eeb5Syz155240 n = NULL; 749ab25eeb5Syz155240 } else if (n == NULL) { 750ab25eeb5Syz155240 error = ESRCH; 751ab25eeb5Syz155240 } 752ab25eeb5Syz155240 753ab25eeb5Syz155240 if (error != 0) { 754f4b3ec61Sdh155122 MUTEX_EXIT(&ifs->ifs_ipf_natio); 755ab25eeb5Syz155240 break; 756ab25eeb5Syz155240 } 757f4b3ec61Sdh155122 nat_siocdelnat(n, np, getlock, ifs); 758ab25eeb5Syz155240 759f4b3ec61Sdh155122 MUTEX_EXIT(&ifs->ifs_ipf_natio); 760ab25eeb5Syz155240 n = NULL; 761ab25eeb5Syz155240 break; 762ab25eeb5Syz155240 case SIOCGNATS : 763f4b3ec61Sdh155122 ifs->ifs_nat_stats.ns_table[0] = ifs->ifs_nat_table[0]; 764f4b3ec61Sdh155122 ifs->ifs_nat_stats.ns_table[1] = ifs->ifs_nat_table[1]; 765f4b3ec61Sdh155122 ifs->ifs_nat_stats.ns_list = ifs->ifs_nat_list; 766f4b3ec61Sdh155122 ifs->ifs_nat_stats.ns_maptable = ifs->ifs_maptable; 767f4b3ec61Sdh155122 ifs->ifs_nat_stats.ns_maplist = ifs->ifs_ipf_hm_maplist; 768f4b3ec61Sdh155122 ifs->ifs_nat_stats.ns_nattab_max = ifs->ifs_ipf_nattable_max; 769f4b3ec61Sdh155122 ifs->ifs_nat_stats.ns_nattab_sz = ifs->ifs_ipf_nattable_sz; 770f4b3ec61Sdh155122 ifs->ifs_nat_stats.ns_rultab_sz = ifs->ifs_ipf_natrules_sz; 771f4b3ec61Sdh155122 ifs->ifs_nat_stats.ns_rdrtab_sz = ifs->ifs_ipf_rdrrules_sz; 772f4b3ec61Sdh155122 ifs->ifs_nat_stats.ns_hostmap_sz = ifs->ifs_ipf_hostmap_sz; 773f4b3ec61Sdh155122 ifs->ifs_nat_stats.ns_instances = ifs->ifs_nat_instances; 774f4b3ec61Sdh155122 ifs->ifs_nat_stats.ns_apslist = ifs->ifs_ap_sess_list; 775f4b3ec61Sdh155122 error = fr_outobj(data, &ifs->ifs_nat_stats, IPFOBJ_NATSTAT); 776ab25eeb5Syz155240 break; 777ab25eeb5Syz155240 case SIOCGNATL : 778ab25eeb5Syz155240 { 779ab25eeb5Syz155240 natlookup_t nl; 780ab25eeb5Syz155240 781ab25eeb5Syz155240 if (getlock) { 782f4b3ec61Sdh155122 READ_ENTER(&ifs->ifs_ipf_nat); 783ab25eeb5Syz155240 } 784ab25eeb5Syz155240 error = fr_inobj(data, &nl, IPFOBJ_NATLOOKUP); 785d6c23f6fSyx160601 if (nl.nl_v != 6) 786d6c23f6fSyx160601 nl.nl_v = 4; 787ab25eeb5Syz155240 if (error == 0) { 788d6c23f6fSyx160601 void *ptr; 789d6c23f6fSyx160601 790d6c23f6fSyx160601 switch (nl.nl_v) 791d6c23f6fSyx160601 { 792d6c23f6fSyx160601 case 4: 793d6c23f6fSyx160601 ptr = nat_lookupredir(&nl, ifs); 794d6c23f6fSyx160601 break; 795d6c23f6fSyx160601 #ifdef USE_INET6 796d6c23f6fSyx160601 case 6: 797d6c23f6fSyx160601 ptr = nat6_lookupredir(&nl, ifs); 798d6c23f6fSyx160601 break; 799d6c23f6fSyx160601 #endif 800d6c23f6fSyx160601 default: 801d6c23f6fSyx160601 ptr = NULL; 802d6c23f6fSyx160601 break; 803d6c23f6fSyx160601 } 804d6c23f6fSyx160601 805d6c23f6fSyx160601 if (ptr != NULL) { 806ab25eeb5Syz155240 error = fr_outobj(data, &nl, IPFOBJ_NATLOOKUP); 807ab25eeb5Syz155240 } else { 808ab25eeb5Syz155240 error = ESRCH; 809ab25eeb5Syz155240 } 810ab25eeb5Syz155240 } 811ab25eeb5Syz155240 if (getlock) { 812f4b3ec61Sdh155122 RWLOCK_EXIT(&ifs->ifs_ipf_nat); 813ab25eeb5Syz155240 } 814ab25eeb5Syz155240 break; 815ab25eeb5Syz155240 } 816ab25eeb5Syz155240 case SIOCIPFFL : /* old SIOCFLNAT & SIOCCNATL */ 817ab25eeb5Syz155240 if (!(mode & FWRITE)) { 818ab25eeb5Syz155240 error = EPERM; 819ab25eeb5Syz155240 break; 820ab25eeb5Syz155240 } 821ab25eeb5Syz155240 if (getlock) { 822f4b3ec61Sdh155122 WRITE_ENTER(&ifs->ifs_ipf_nat); 823ab25eeb5Syz155240 } 824bb1d9de5SJohn Ojemann error = BCOPYIN(data, &arg, sizeof(arg)); 825bb1d9de5SJohn Ojemann if (error != 0) { 826bb1d9de5SJohn Ojemann error = EFAULT; 827bb1d9de5SJohn Ojemann } else { 828ea8244dcSJohn Ojemann if (arg == FLUSH_LIST) 829f4b3ec61Sdh155122 ret = nat_clearlist(ifs); 830ea8244dcSJohn Ojemann else if (VALID_TABLE_FLUSH_OPT(arg)) 831ea8244dcSJohn Ojemann ret = nat_flushtable(arg, ifs); 832ab25eeb5Syz155240 else 833ab25eeb5Syz155240 error = EINVAL; 834bb1d9de5SJohn Ojemann } 835ab25eeb5Syz155240 if (getlock) { 836f4b3ec61Sdh155122 RWLOCK_EXIT(&ifs->ifs_ipf_nat); 837ab25eeb5Syz155240 } 838ab25eeb5Syz155240 if (error == 0) { 839bb1d9de5SJohn Ojemann error = BCOPYOUT(&ret, data, sizeof(ret)); 840bb1d9de5SJohn Ojemann if (error != 0) 841bb1d9de5SJohn Ojemann error = EFAULT; 842ab25eeb5Syz155240 } 843ab25eeb5Syz155240 break; 844ab25eeb5Syz155240 case SIOCPROXY : 845f4b3ec61Sdh155122 error = appr_ioctl(data, cmd, mode, ifs); 846ab25eeb5Syz155240 break; 847ab25eeb5Syz155240 case SIOCSTLCK : 848ab25eeb5Syz155240 if (!(mode & FWRITE)) { 849ab25eeb5Syz155240 error = EPERM; 850ab25eeb5Syz155240 } else { 851bb1d9de5SJohn Ojemann error = fr_lock(data, &ifs->ifs_fr_nat_lock); 852ab25eeb5Syz155240 } 853ab25eeb5Syz155240 break; 854ab25eeb5Syz155240 case SIOCSTPUT : 8553c3c3491Sjojemann if ((mode & FWRITE) != 0) { 856f4b3ec61Sdh155122 error = fr_natputent(data, getlock, ifs); 857ab25eeb5Syz155240 } else { 858ab25eeb5Syz155240 error = EACCES; 859ab25eeb5Syz155240 } 860ab25eeb5Syz155240 break; 861ab25eeb5Syz155240 case SIOCSTGSZ : 862f4b3ec61Sdh155122 if (ifs->ifs_fr_nat_lock) { 863ab25eeb5Syz155240 if (getlock) { 864f4b3ec61Sdh155122 READ_ENTER(&ifs->ifs_ipf_nat); 865ab25eeb5Syz155240 } 866f4b3ec61Sdh155122 error = fr_natgetsz(data, ifs); 867ab25eeb5Syz155240 if (getlock) { 868f4b3ec61Sdh155122 RWLOCK_EXIT(&ifs->ifs_ipf_nat); 869ab25eeb5Syz155240 } 870ab25eeb5Syz155240 } else 871ab25eeb5Syz155240 error = EACCES; 872ab25eeb5Syz155240 break; 873ab25eeb5Syz155240 case SIOCSTGET : 874f4b3ec61Sdh155122 if (ifs->ifs_fr_nat_lock) { 875ab25eeb5Syz155240 if (getlock) { 876f4b3ec61Sdh155122 READ_ENTER(&ifs->ifs_ipf_nat); 877ab25eeb5Syz155240 } 878f4b3ec61Sdh155122 error = fr_natgetent(data, ifs); 879ab25eeb5Syz155240 if (getlock) { 880f4b3ec61Sdh155122 RWLOCK_EXIT(&ifs->ifs_ipf_nat); 881ab25eeb5Syz155240 } 882ab25eeb5Syz155240 } else 883ab25eeb5Syz155240 error = EACCES; 884ab25eeb5Syz155240 break; 885f4b3ec61Sdh155122 case SIOCIPFDELTOK : 886bb1d9de5SJohn Ojemann error = BCOPYIN((caddr_t)data, (caddr_t)&arg, sizeof(arg)); 887bb1d9de5SJohn Ojemann if (error != 0) { 888bb1d9de5SJohn Ojemann error = EFAULT; 889bb1d9de5SJohn Ojemann } else { 890f4b3ec61Sdh155122 error = ipf_deltoken(arg, uid, ctx, ifs); 891bb1d9de5SJohn Ojemann } 892f4b3ec61Sdh155122 break; 893ab25eeb5Syz155240 default : 894ab25eeb5Syz155240 error = EINVAL; 895ab25eeb5Syz155240 break; 896ab25eeb5Syz155240 } 897ab25eeb5Syz155240 done: 898ab25eeb5Syz155240 if (nt) 899ab25eeb5Syz155240 KFREE(nt); 900ab25eeb5Syz155240 return error; 901ab25eeb5Syz155240 } 902ab25eeb5Syz155240 903ab25eeb5Syz155240 904ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */ 905ab25eeb5Syz155240 /* Function: nat_siocaddnat */ 906ab25eeb5Syz155240 /* Returns: int - 0 == success, != 0 == failure */ 907ab25eeb5Syz155240 /* Parameters: n(I) - pointer to new NAT rule */ 908ab25eeb5Syz155240 /* np(I) - pointer to where to insert new NAT rule */ 909ab25eeb5Syz155240 /* getlock(I) - flag indicating if lock on ipf_nat is held */ 910ab25eeb5Syz155240 /* Mutex Locks: ipf_natio */ 911ab25eeb5Syz155240 /* */ 912ab25eeb5Syz155240 /* Handle SIOCADNAT. Resolve and calculate details inside the NAT rule */ 913ab25eeb5Syz155240 /* from information passed to the kernel, then add it to the appropriate */ 914ab25eeb5Syz155240 /* NAT rule table(s). */ 915ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */ 916f4b3ec61Sdh155122 static int nat_siocaddnat(n, np, getlock, ifs) 917ab25eeb5Syz155240 ipnat_t *n, **np; 918ab25eeb5Syz155240 int getlock; 919f4b3ec61Sdh155122 ipf_stack_t *ifs; 920ab25eeb5Syz155240 { 921ab25eeb5Syz155240 int error = 0, i, j; 922ab25eeb5Syz155240 923dcf3e898Sjojemann if (nat_resolverule(n, ifs) != 0) 924ab25eeb5Syz155240 return ENOENT; 925ab25eeb5Syz155240 926ab25eeb5Syz155240 if ((n->in_age[0] == 0) && (n->in_age[1] != 0)) 927ab25eeb5Syz155240 return EINVAL; 928ab25eeb5Syz155240 929ab25eeb5Syz155240 n->in_use = 0; 930ab25eeb5Syz155240 if (n->in_redir & NAT_MAPBLK) 931ab25eeb5Syz155240 n->in_space = USABLE_PORTS * ~ntohl(n->in_outmsk); 932ab25eeb5Syz155240 else if (n->in_flags & IPN_AUTOPORTMAP) 933ab25eeb5Syz155240 n->in_space = USABLE_PORTS * ~ntohl(n->in_inmsk); 934ab25eeb5Syz155240 else if (n->in_flags & IPN_IPRANGE) 935ab25eeb5Syz155240 n->in_space = ntohl(n->in_outmsk) - ntohl(n->in_outip); 936ab25eeb5Syz155240 else if (n->in_flags & IPN_SPLIT) 937ab25eeb5Syz155240 n->in_space = 2; 938ab25eeb5Syz155240 else if (n->in_outmsk != 0) 939ab25eeb5Syz155240 n->in_space = ~ntohl(n->in_outmsk); 940ab25eeb5Syz155240 else 941ab25eeb5Syz155240 n->in_space = 1; 942f507f892SPaul Wernau if ((n->in_flags & NAT_TCPUDPICMPQ) && (n->in_redir != NAT_REDIRECT)) { 94333f2fefdSDarren Reed if (ntohs(n->in_pmax) < ntohs(n->in_pmin)) 94433f2fefdSDarren Reed return EINVAL; 94533f2fefdSDarren Reed } 946ab25eeb5Syz155240 947ab25eeb5Syz155240 /* 948ab25eeb5Syz155240 * Calculate the number of valid IP addresses in the output 949ab25eeb5Syz155240 * mapping range. In all cases, the range is inclusive of 950ab25eeb5Syz155240 * the start and ending IP addresses. 951ab25eeb5Syz155240 * If to a CIDR address, lose 2: broadcast + network address 952ab25eeb5Syz155240 * (so subtract 1) 953ab25eeb5Syz155240 * If to a range, add one. 954ab25eeb5Syz155240 * If to a single IP address, set to 1. 955ab25eeb5Syz155240 */ 956ab25eeb5Syz155240 if (n->in_space) { 957ab25eeb5Syz155240 if ((n->in_flags & IPN_IPRANGE) != 0) 958ab25eeb5Syz155240 n->in_space += 1; 959ab25eeb5Syz155240 else 960ab25eeb5Syz155240 n->in_space -= 1; 961ab25eeb5Syz155240 } else 962ab25eeb5Syz155240 n->in_space = 1; 963ab25eeb5Syz155240 964d6c23f6fSyx160601 #ifdef USE_INET6 965d6c23f6fSyx160601 if (n->in_v == 6 && (n->in_flags & (IPN_IPRANGE|IPN_SPLIT)) == 0 && 966d6c23f6fSyx160601 !IP6_ISONES(&n->in_out[1]) && !IP6_ISZERO(&n->in_out[1])) 967d6c23f6fSyx160601 IP6_ADD(&n->in_out[0], 1, &n->in_next6) 968d6c23f6fSyx160601 else if (n->in_v == 6 && 969d6c23f6fSyx160601 (n->in_flags & IPN_SPLIT) && (n->in_redir & NAT_REDIRECT)) 970d6c23f6fSyx160601 n->in_next6 = n->in_in[0]; 971d6c23f6fSyx160601 else if (n->in_v == 6) 972d6c23f6fSyx160601 n->in_next6 = n->in_out[0]; 973d6c23f6fSyx160601 else 974d6c23f6fSyx160601 #endif 975ab25eeb5Syz155240 if ((n->in_outmsk != 0xffffffff) && (n->in_outmsk != 0) && 976ab25eeb5Syz155240 ((n->in_flags & (IPN_IPRANGE|IPN_SPLIT)) == 0)) 977ab25eeb5Syz155240 n->in_nip = ntohl(n->in_outip) + 1; 978ab25eeb5Syz155240 else if ((n->in_flags & IPN_SPLIT) && 979ab25eeb5Syz155240 (n->in_redir & NAT_REDIRECT)) 980ab25eeb5Syz155240 n->in_nip = ntohl(n->in_inip); 981ab25eeb5Syz155240 else 982ab25eeb5Syz155240 n->in_nip = ntohl(n->in_outip); 983d6c23f6fSyx160601 984ab25eeb5Syz155240 if (n->in_redir & NAT_MAP) { 985ab25eeb5Syz155240 n->in_pnext = ntohs(n->in_pmin); 986ab25eeb5Syz155240 /* 987ab25eeb5Syz155240 * Multiply by the number of ports made available. 988ab25eeb5Syz155240 */ 989ab25eeb5Syz155240 if (ntohs(n->in_pmax) >= ntohs(n->in_pmin)) { 990ab25eeb5Syz155240 n->in_space *= (ntohs(n->in_pmax) - 991ab25eeb5Syz155240 ntohs(n->in_pmin) + 1); 992ab25eeb5Syz155240 /* 993ab25eeb5Syz155240 * Because two different sources can map to 994ab25eeb5Syz155240 * different destinations but use the same 995ab25eeb5Syz155240 * local IP#/port #. 996ab25eeb5Syz155240 * If the result is smaller than in_space, then 997ab25eeb5Syz155240 * we may have wrapped around 32bits. 998ab25eeb5Syz155240 */ 999ab25eeb5Syz155240 i = n->in_inmsk; 1000ab25eeb5Syz155240 if ((i != 0) && (i != 0xffffffff)) { 1001ab25eeb5Syz155240 j = n->in_space * (~ntohl(i) + 1); 1002ab25eeb5Syz155240 if (j >= n->in_space) 1003ab25eeb5Syz155240 n->in_space = j; 1004ab25eeb5Syz155240 else 1005ab25eeb5Syz155240 n->in_space = 0xffffffff; 1006ab25eeb5Syz155240 } 1007ab25eeb5Syz155240 } 1008ab25eeb5Syz155240 /* 1009ab25eeb5Syz155240 * If no protocol is specified, multiple by 256 to allow for 1010ab25eeb5Syz155240 * at least one IP:IP mapping per protocol. 1011ab25eeb5Syz155240 */ 1012ab25eeb5Syz155240 if ((n->in_flags & IPN_TCPUDPICMP) == 0) { 1013ab25eeb5Syz155240 j = n->in_space * 256; 1014ab25eeb5Syz155240 if (j >= n->in_space) 1015ab25eeb5Syz155240 n->in_space = j; 1016ab25eeb5Syz155240 else 1017ab25eeb5Syz155240 n->in_space = 0xffffffff; 1018ab25eeb5Syz155240 } 1019ab25eeb5Syz155240 } 1020ab25eeb5Syz155240 1021ab25eeb5Syz155240 /* Otherwise, these fields are preset */ 1022ab25eeb5Syz155240 1023ab25eeb5Syz155240 if (getlock) { 1024f4b3ec61Sdh155122 WRITE_ENTER(&ifs->ifs_ipf_nat); 1025ab25eeb5Syz155240 } 1026ab25eeb5Syz155240 n->in_next = NULL; 1027ab25eeb5Syz155240 *np = n; 1028ab25eeb5Syz155240 1029ab25eeb5Syz155240 if (n->in_age[0] != 0) 1030f4b3ec61Sdh155122 n->in_tqehead[0] = fr_addtimeoutqueue(&ifs->ifs_nat_utqe, 1031f4b3ec61Sdh155122 n->in_age[0], ifs); 1032ab25eeb5Syz155240 1033ab25eeb5Syz155240 if (n->in_age[1] != 0) 1034f4b3ec61Sdh155122 n->in_tqehead[1] = fr_addtimeoutqueue(&ifs->ifs_nat_utqe, 1035f4b3ec61Sdh155122 n->in_age[1], ifs); 1036ab25eeb5Syz155240 1037ab25eeb5Syz155240 if (n->in_redir & NAT_REDIRECT) { 1038ab25eeb5Syz155240 n->in_flags &= ~IPN_NOTDST; 1039d6c23f6fSyx160601 switch (n->in_v) 1040d6c23f6fSyx160601 { 1041d6c23f6fSyx160601 case 4 : 1042f4b3ec61Sdh155122 nat_addrdr(n, ifs); 1043d6c23f6fSyx160601 break; 1044d6c23f6fSyx160601 #ifdef USE_INET6 1045d6c23f6fSyx160601 case 6 : 1046d6c23f6fSyx160601 nat6_addrdr(n, ifs); 1047d6c23f6fSyx160601 break; 1048d6c23f6fSyx160601 #endif 1049d6c23f6fSyx160601 default : 1050d6c23f6fSyx160601 break; 1051d6c23f6fSyx160601 } 1052ab25eeb5Syz155240 } 1053ab25eeb5Syz155240 if (n->in_redir & (NAT_MAP|NAT_MAPBLK)) { 1054ab25eeb5Syz155240 n->in_flags &= ~IPN_NOTSRC; 1055d6c23f6fSyx160601 switch (n->in_v) 1056d6c23f6fSyx160601 { 1057d6c23f6fSyx160601 case 4 : 1058f4b3ec61Sdh155122 nat_addnat(n, ifs); 1059d6c23f6fSyx160601 break; 1060d6c23f6fSyx160601 #ifdef USE_INET6 1061d6c23f6fSyx160601 case 6 : 1062d6c23f6fSyx160601 nat6_addnat(n, ifs); 1063d6c23f6fSyx160601 break; 1064d6c23f6fSyx160601 #endif 1065d6c23f6fSyx160601 default : 1066d6c23f6fSyx160601 break; 1067d6c23f6fSyx160601 } 1068ab25eeb5Syz155240 } 1069ab25eeb5Syz155240 n = NULL; 1070f4b3ec61Sdh155122 ifs->ifs_nat_stats.ns_rules++; 1071ab25eeb5Syz155240 if (getlock) { 1072f4b3ec61Sdh155122 RWLOCK_EXIT(&ifs->ifs_ipf_nat); /* WRITE */ 1073ab25eeb5Syz155240 } 1074ab25eeb5Syz155240 1075ab25eeb5Syz155240 return error; 1076ab25eeb5Syz155240 } 1077ab25eeb5Syz155240 1078ab25eeb5Syz155240 1079ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */ 1080ab25eeb5Syz155240 /* Function: nat_resolvrule */ 1081dcf3e898Sjojemann /* Returns: int - 0 == success, -1 == failure */ 1082ab25eeb5Syz155240 /* Parameters: n(I) - pointer to NAT rule */ 1083ab25eeb5Syz155240 /* */ 1084dcf3e898Sjojemann /* Resolve some of the details inside the NAT rule. Includes resolving */ 1085dcf3e898Sjojemann /* any specified interfaces and proxy labels, and determines whether or not */ 1086dcf3e898Sjojemann /* all proxy labels are correctly specified. */ 1087dcf3e898Sjojemann /* */ 1088dcf3e898Sjojemann /* Called by nat_siocaddnat() (SIOCADNAT) and fr_natputent (SIOCSTPUT). */ 1089ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */ 1090dcf3e898Sjojemann static int nat_resolverule(n, ifs) 1091ab25eeb5Syz155240 ipnat_t *n; 1092f4b3ec61Sdh155122 ipf_stack_t *ifs; 1093ab25eeb5Syz155240 { 1094ab25eeb5Syz155240 n->in_ifnames[0][LIFNAMSIZ - 1] = '\0'; 1095d6c23f6fSyx160601 n->in_ifps[0] = fr_resolvenic(n->in_ifnames[0], n->in_v, ifs); 1096ab25eeb5Syz155240 1097ab25eeb5Syz155240 n->in_ifnames[1][LIFNAMSIZ - 1] = '\0'; 1098ab25eeb5Syz155240 if (n->in_ifnames[1][0] == '\0') { 1099ab25eeb5Syz155240 (void) strncpy(n->in_ifnames[1], n->in_ifnames[0], LIFNAMSIZ); 1100ab25eeb5Syz155240 n->in_ifps[1] = n->in_ifps[0]; 1101ab25eeb5Syz155240 } else { 1102d6c23f6fSyx160601 n->in_ifps[1] = fr_resolvenic(n->in_ifnames[1], n->in_v, ifs); 1103ab25eeb5Syz155240 } 1104ab25eeb5Syz155240 1105ab25eeb5Syz155240 if (n->in_plabel[0] != '\0') { 1106f4b3ec61Sdh155122 n->in_apr = appr_lookup(n->in_p, n->in_plabel, ifs); 1107dcf3e898Sjojemann if (n->in_apr == NULL) 1108dcf3e898Sjojemann return -1; 1109ab25eeb5Syz155240 } 1110dcf3e898Sjojemann return 0; 1111ab25eeb5Syz155240 } 1112ab25eeb5Syz155240 1113ab25eeb5Syz155240 1114ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */ 1115ab25eeb5Syz155240 /* Function: nat_siocdelnat */ 1116ab25eeb5Syz155240 /* Returns: int - 0 == success, != 0 == failure */ 1117ab25eeb5Syz155240 /* Parameters: n(I) - pointer to new NAT rule */ 1118ab25eeb5Syz155240 /* np(I) - pointer to where to insert new NAT rule */ 1119ab25eeb5Syz155240 /* getlock(I) - flag indicating if lock on ipf_nat is held */ 1120ab25eeb5Syz155240 /* Mutex Locks: ipf_natio */ 1121ab25eeb5Syz155240 /* */ 1122ab25eeb5Syz155240 /* Handle SIOCADNAT. Resolve and calculate details inside the NAT rule */ 1123ab25eeb5Syz155240 /* from information passed to the kernel, then add it to the appropriate */ 1124ab25eeb5Syz155240 /* NAT rule table(s). */ 1125ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */ 1126f4b3ec61Sdh155122 static void nat_siocdelnat(n, np, getlock, ifs) 1127ab25eeb5Syz155240 ipnat_t *n, **np; 1128ab25eeb5Syz155240 int getlock; 1129f4b3ec61Sdh155122 ipf_stack_t *ifs; 1130ab25eeb5Syz155240 { 1131d6c23f6fSyx160601 int i; 1132d6c23f6fSyx160601 1133ab25eeb5Syz155240 if (getlock) { 1134f4b3ec61Sdh155122 WRITE_ENTER(&ifs->ifs_ipf_nat); 1135ab25eeb5Syz155240 } 1136ab25eeb5Syz155240 if (n->in_redir & NAT_REDIRECT) 1137ab25eeb5Syz155240 nat_delrdr(n); 1138ab25eeb5Syz155240 if (n->in_redir & (NAT_MAPBLK|NAT_MAP)) 1139ab25eeb5Syz155240 nat_delnat(n); 1140f4b3ec61Sdh155122 if (ifs->ifs_nat_list == NULL) { 1141f4b3ec61Sdh155122 ifs->ifs_nat_masks = 0; 1142f4b3ec61Sdh155122 ifs->ifs_rdr_masks = 0; 1143d6c23f6fSyx160601 for (i = 0; i < 4; i++) { 1144d6c23f6fSyx160601 ifs->ifs_nat6_masks[i] = 0; 1145d6c23f6fSyx160601 ifs->ifs_rdr6_masks[i] = 0; 1146d6c23f6fSyx160601 } 1147ab25eeb5Syz155240 } 1148ab25eeb5Syz155240 1149ab25eeb5Syz155240 if (n->in_tqehead[0] != NULL) { 1150ab25eeb5Syz155240 if (fr_deletetimeoutqueue(n->in_tqehead[0]) == 0) { 11513805c50fSan207044 fr_freetimeoutqueue(n->in_tqehead[0], ifs); 1152ab25eeb5Syz155240 } 1153ab25eeb5Syz155240 } 1154ab25eeb5Syz155240 1155ab25eeb5Syz155240 if (n->in_tqehead[1] != NULL) { 1156ab25eeb5Syz155240 if (fr_deletetimeoutqueue(n->in_tqehead[1]) == 0) { 1157f4b3ec61Sdh155122 fr_freetimeoutqueue(n->in_tqehead[1], ifs); 1158ab25eeb5Syz155240 } 1159ab25eeb5Syz155240 } 1160ab25eeb5Syz155240 1161ab25eeb5Syz155240 *np = n->in_next; 1162ab25eeb5Syz155240 1163ab25eeb5Syz155240 if (n->in_use == 0) { 1164ab25eeb5Syz155240 if (n->in_apr) 1165ab25eeb5Syz155240 appr_free(n->in_apr); 1166ab25eeb5Syz155240 KFREE(n); 1167f4b3ec61Sdh155122 ifs->ifs_nat_stats.ns_rules--; 1168ab25eeb5Syz155240 } else { 1169ab25eeb5Syz155240 n->in_flags |= IPN_DELETE; 1170ab25eeb5Syz155240 n->in_next = NULL; 1171ab25eeb5Syz155240 } 1172ab25eeb5Syz155240 if (getlock) { 1173f4b3ec61Sdh155122 RWLOCK_EXIT(&ifs->ifs_ipf_nat); /* READ/WRITE */ 1174ab25eeb5Syz155240 } 1175ab25eeb5Syz155240 } 1176ab25eeb5Syz155240 1177ab25eeb5Syz155240 1178ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */ 1179ab25eeb5Syz155240 /* Function: fr_natgetsz */ 1180ab25eeb5Syz155240 /* Returns: int - 0 == success, != 0 is the error value. */ 1181ab25eeb5Syz155240 /* Parameters: data(I) - pointer to natget structure with kernel pointer */ 1182ab25eeb5Syz155240 /* get the size of. */ 1183ab25eeb5Syz155240 /* */ 1184ab25eeb5Syz155240 /* Handle SIOCSTGSZ. */ 1185ab25eeb5Syz155240 /* Return the size of the nat list entry to be copied back to user space. */ 1186ab25eeb5Syz155240 /* The size of the entry is stored in the ng_sz field and the enture natget */ 1187ab25eeb5Syz155240 /* structure is copied back to the user. */ 1188ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */ 1189f4b3ec61Sdh155122 static int fr_natgetsz(data, ifs) 1190ab25eeb5Syz155240 caddr_t data; 1191f4b3ec61Sdh155122 ipf_stack_t *ifs; 1192ab25eeb5Syz155240 { 1193ab25eeb5Syz155240 ap_session_t *aps; 1194ab25eeb5Syz155240 nat_t *nat, *n; 1195ab25eeb5Syz155240 natget_t ng; 1196bb1d9de5SJohn Ojemann int err; 1197ab25eeb5Syz155240 1198bb1d9de5SJohn Ojemann err = BCOPYIN(data, &ng, sizeof(ng)); 1199bb1d9de5SJohn Ojemann if (err != 0) 1200bb1d9de5SJohn Ojemann return EFAULT; 1201ab25eeb5Syz155240 1202ab25eeb5Syz155240 nat = ng.ng_ptr; 1203ab25eeb5Syz155240 if (!nat) { 1204f4b3ec61Sdh155122 nat = ifs->ifs_nat_instances; 1205ab25eeb5Syz155240 ng.ng_sz = 0; 1206ab25eeb5Syz155240 /* 1207ab25eeb5Syz155240 * Empty list so the size returned is 0. Simple. 1208ab25eeb5Syz155240 */ 1209ab25eeb5Syz155240 if (nat == NULL) { 1210bb1d9de5SJohn Ojemann err = BCOPYOUT(&ng, data, sizeof(ng)); 1211bb1d9de5SJohn Ojemann if (err != 0) { 1212bb1d9de5SJohn Ojemann return EFAULT; 1213bb1d9de5SJohn Ojemann } else { 1214ab25eeb5Syz155240 return 0; 1215ab25eeb5Syz155240 } 1216bb1d9de5SJohn Ojemann } 1217ab25eeb5Syz155240 } else { 1218ab25eeb5Syz155240 /* 1219ab25eeb5Syz155240 * Make sure the pointer we're copying from exists in the 1220ab25eeb5Syz155240 * current list of entries. Security precaution to prevent 1221ab25eeb5Syz155240 * copying of random kernel data. 1222ab25eeb5Syz155240 */ 1223f4b3ec61Sdh155122 for (n = ifs->ifs_nat_instances; n; n = n->nat_next) 1224ab25eeb5Syz155240 if (n == nat) 1225ab25eeb5Syz155240 break; 1226ab25eeb5Syz155240 if (!n) 1227ab25eeb5Syz155240 return ESRCH; 1228ab25eeb5Syz155240 } 1229ab25eeb5Syz155240 1230ab25eeb5Syz155240 /* 1231ab25eeb5Syz155240 * Incluse any space required for proxy data structures. 1232ab25eeb5Syz155240 */ 1233ab25eeb5Syz155240 ng.ng_sz = sizeof(nat_save_t); 1234ab25eeb5Syz155240 aps = nat->nat_aps; 1235ab25eeb5Syz155240 if (aps != NULL) { 1236ab25eeb5Syz155240 ng.ng_sz += sizeof(ap_session_t) - 4; 1237ab25eeb5Syz155240 if (aps->aps_data != 0) 1238ab25eeb5Syz155240 ng.ng_sz += aps->aps_psiz; 1239ab25eeb5Syz155240 } 1240ab25eeb5Syz155240 1241bb1d9de5SJohn Ojemann err = BCOPYOUT(&ng, data, sizeof(ng)); 1242bb1d9de5SJohn Ojemann if (err != 0) 1243bb1d9de5SJohn Ojemann return EFAULT; 1244ab25eeb5Syz155240 return 0; 1245ab25eeb5Syz155240 } 1246ab25eeb5Syz155240 1247ab25eeb5Syz155240 1248ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */ 1249ab25eeb5Syz155240 /* Function: fr_natgetent */ 1250ab25eeb5Syz155240 /* Returns: int - 0 == success, != 0 is the error value. */ 1251ab25eeb5Syz155240 /* Parameters: data(I) - pointer to natget structure with kernel pointer */ 1252ab25eeb5Syz155240 /* to NAT structure to copy out. */ 1253ab25eeb5Syz155240 /* */ 1254ab25eeb5Syz155240 /* Handle SIOCSTGET. */ 1255ab25eeb5Syz155240 /* Copies out NAT entry to user space. Any additional data held for a */ 1256ab25eeb5Syz155240 /* proxy is also copied, as to is the NAT rule which was responsible for it */ 1257ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */ 1258f4b3ec61Sdh155122 static int fr_natgetent(data, ifs) 1259ab25eeb5Syz155240 caddr_t data; 1260f4b3ec61Sdh155122 ipf_stack_t *ifs; 1261ab25eeb5Syz155240 { 1262ab25eeb5Syz155240 int error, outsize; 1263ab25eeb5Syz155240 ap_session_t *aps; 1264ab25eeb5Syz155240 nat_save_t *ipn, ipns; 1265ab25eeb5Syz155240 nat_t *n, *nat; 1266ab25eeb5Syz155240 1267ab25eeb5Syz155240 error = fr_inobj(data, &ipns, IPFOBJ_NATSAVE); 1268ab25eeb5Syz155240 if (error != 0) 1269ab25eeb5Syz155240 return error; 1270ab25eeb5Syz155240 1271ab25eeb5Syz155240 if ((ipns.ipn_dsize < sizeof(ipns)) || (ipns.ipn_dsize > 81920)) 1272ab25eeb5Syz155240 return EINVAL; 1273ab25eeb5Syz155240 1274ab25eeb5Syz155240 KMALLOCS(ipn, nat_save_t *, ipns.ipn_dsize); 1275ab25eeb5Syz155240 if (ipn == NULL) 1276ab25eeb5Syz155240 return ENOMEM; 1277ab25eeb5Syz155240 1278ab25eeb5Syz155240 ipn->ipn_dsize = ipns.ipn_dsize; 1279ab25eeb5Syz155240 nat = ipns.ipn_next; 1280ab25eeb5Syz155240 if (nat == NULL) { 1281f4b3ec61Sdh155122 nat = ifs->ifs_nat_instances; 1282ab25eeb5Syz155240 if (nat == NULL) { 1283f4b3ec61Sdh155122 if (ifs->ifs_nat_instances == NULL) 1284ab25eeb5Syz155240 error = ENOENT; 1285ab25eeb5Syz155240 goto finished; 1286ab25eeb5Syz155240 } 1287ab25eeb5Syz155240 } else { 1288ab25eeb5Syz155240 /* 1289ab25eeb5Syz155240 * Make sure the pointer we're copying from exists in the 1290ab25eeb5Syz155240 * current list of entries. Security precaution to prevent 1291ab25eeb5Syz155240 * copying of random kernel data. 1292ab25eeb5Syz155240 */ 1293f4b3ec61Sdh155122 for (n = ifs->ifs_nat_instances; n; n = n->nat_next) 1294ab25eeb5Syz155240 if (n == nat) 1295ab25eeb5Syz155240 break; 1296ab25eeb5Syz155240 if (n == NULL) { 1297ab25eeb5Syz155240 error = ESRCH; 1298ab25eeb5Syz155240 goto finished; 1299ab25eeb5Syz155240 } 1300ab25eeb5Syz155240 } 1301ab25eeb5Syz155240 ipn->ipn_next = nat->nat_next; 1302ab25eeb5Syz155240 1303ab25eeb5Syz155240 /* 1304ab25eeb5Syz155240 * Copy the NAT structure. 1305ab25eeb5Syz155240 */ 1306ab25eeb5Syz155240 bcopy((char *)nat, &ipn->ipn_nat, sizeof(*nat)); 1307ab25eeb5Syz155240 1308ab25eeb5Syz155240 /* 1309ab25eeb5Syz155240 * If we have a pointer to the NAT rule it belongs to, save that too. 1310ab25eeb5Syz155240 */ 1311ab25eeb5Syz155240 if (nat->nat_ptr != NULL) 1312ab25eeb5Syz155240 bcopy((char *)nat->nat_ptr, (char *)&ipn->ipn_ipnat, 1313ab25eeb5Syz155240 sizeof(ipn->ipn_ipnat)); 1314ab25eeb5Syz155240 1315ab25eeb5Syz155240 /* 1316ab25eeb5Syz155240 * If we also know the NAT entry has an associated filter rule, 1317ab25eeb5Syz155240 * save that too. 1318ab25eeb5Syz155240 */ 1319ab25eeb5Syz155240 if (nat->nat_fr != NULL) 1320ab25eeb5Syz155240 bcopy((char *)nat->nat_fr, (char *)&ipn->ipn_fr, 1321ab25eeb5Syz155240 sizeof(ipn->ipn_fr)); 1322ab25eeb5Syz155240 1323ab25eeb5Syz155240 /* 1324ab25eeb5Syz155240 * Last but not least, if there is an application proxy session set 1325ab25eeb5Syz155240 * up for this NAT entry, then copy that out too, including any 1326ab25eeb5Syz155240 * private data saved along side it by the proxy. 1327ab25eeb5Syz155240 */ 1328ab25eeb5Syz155240 aps = nat->nat_aps; 1329ab25eeb5Syz155240 outsize = ipn->ipn_dsize - sizeof(*ipn) + sizeof(ipn->ipn_data); 1330ab25eeb5Syz155240 if (aps != NULL) { 1331ab25eeb5Syz155240 char *s; 1332ab25eeb5Syz155240 1333ab25eeb5Syz155240 if (outsize < sizeof(*aps)) { 1334ab25eeb5Syz155240 error = ENOBUFS; 1335ab25eeb5Syz155240 goto finished; 1336ab25eeb5Syz155240 } 1337ab25eeb5Syz155240 1338ab25eeb5Syz155240 s = ipn->ipn_data; 1339ab25eeb5Syz155240 bcopy((char *)aps, s, sizeof(*aps)); 1340ab25eeb5Syz155240 s += sizeof(*aps); 1341ab25eeb5Syz155240 outsize -= sizeof(*aps); 1342ab25eeb5Syz155240 if ((aps->aps_data != NULL) && (outsize >= aps->aps_psiz)) 1343ab25eeb5Syz155240 bcopy(aps->aps_data, s, aps->aps_psiz); 1344ab25eeb5Syz155240 else 1345ab25eeb5Syz155240 error = ENOBUFS; 1346ab25eeb5Syz155240 } 1347ab25eeb5Syz155240 if (error == 0) { 1348ab25eeb5Syz155240 error = fr_outobjsz(data, ipn, IPFOBJ_NATSAVE, ipns.ipn_dsize); 1349ab25eeb5Syz155240 } 1350ab25eeb5Syz155240 1351ab25eeb5Syz155240 finished: 1352ab25eeb5Syz155240 if (ipn != NULL) { 1353ab25eeb5Syz155240 KFREES(ipn, ipns.ipn_dsize); 1354ab25eeb5Syz155240 } 1355ab25eeb5Syz155240 return error; 1356ab25eeb5Syz155240 } 1357ab25eeb5Syz155240 13583c50f6d6San207044 /* ------------------------------------------------------------------------ */ 13593c50f6d6San207044 /* Function: nat_calc_chksum_diffs */ 13603c50f6d6San207044 /* Returns: void */ 13613c50f6d6San207044 /* Parameters: nat - pointer to NAT table entry */ 13623c50f6d6San207044 /* */ 13633c50f6d6San207044 /* Function calculates chksum deltas for IP header (nat_ipsumd) and TCP/UDP */ 13643c50f6d6San207044 /* headers (nat_sumd). The things for L4 (UDP/TCP) get complicated when */ 13653c50f6d6San207044 /* we are dealing with partial chksum offload. For these cases we need to */ 13663c50f6d6San207044 /* compute a 'partial chksum delta'. The 'partial chksum delta'is stored */ 13673c50f6d6San207044 /* into nat_sumd[1], while ordinary chksum delta for TCP/UDP is in */ 13683c50f6d6San207044 /* nat_sumd[0]. */ 13693c50f6d6San207044 /* */ 13703c50f6d6San207044 /* The function accepts initialized NAT table entry and computes the deltas */ 13713c50f6d6San207044 /* from nat_inip/nat_outip members. The function is called right before */ 13723c50f6d6San207044 /* the new entry is inserted into the table. */ 13733c50f6d6San207044 /* */ 13743c50f6d6San207044 /* The ipsumd (IP hedaer chksum delta adjustment) is computed as a chksum */ 13753c50f6d6San207044 /* of delta between original and new IP addresses. */ 13763c50f6d6San207044 /* */ 13773c50f6d6San207044 /* the nat_sumd[0] (TCP/UDP header chksum delta adjustment) is computed as */ 13783c50f6d6San207044 /* a chkusm of delta between original an new IP addrress:port tupples. */ 13793c50f6d6San207044 /* */ 13803c50f6d6San207044 /* Some facts about chksum, we should remember: */ 13813c50f6d6San207044 /* IP header chksum covers IP header only */ 13823c50f6d6San207044 /* */ 13833c50f6d6San207044 /* TCP/UDP chksum covers data payload and so called pseudo header */ 13843c50f6d6San207044 /* SRC, DST IP address */ 13853c50f6d6San207044 /* SRC, DST Port */ 13863c50f6d6San207044 /* length of payload */ 13873c50f6d6San207044 /* */ 13883c50f6d6San207044 /* The partial chksum delta (nat_sumd[1] is used to adjust db_ckusm16 */ 13893c50f6d6San207044 /* member of dblk_t structure. The db_ckusm16 member is not part of */ 13903c50f6d6San207044 /* IP/UDP/TCP header it is 16 bit value computed by NIC driver with partial */ 13913c50f6d6San207044 /* chksum offload capacbility for every inbound packet. The db_cksum16 is */ 13923c50f6d6San207044 /* stored along with other IP packet data in dblk_t structure and used in */ 13933c50f6d6San207044 /* for IP/UDP/TCP chksum validation later in ip.c. */ 13943c50f6d6San207044 /* */ 13953c50f6d6San207044 /* The partial chksum delta (adjustment, nat_sumd[1]) is computed as chksum */ 13963c50f6d6San207044 /* of delta between new and orig address. NOTE: the order of operands for */ 13973c50f6d6San207044 /* partial delta operation is swapped compared to computing the IP/TCP/UDP */ 13983c50f6d6San207044 /* header adjustment. It is by design see (IP_CKSUM_RECV() macro in ip.c). */ 13993c50f6d6San207044 /* */ 14003c50f6d6San207044 /* ------------------------------------------------------------------------ */ 1401d6c23f6fSyx160601 void nat_calc_chksum_diffs(nat) 14023c50f6d6San207044 nat_t *nat; 14033c50f6d6San207044 { 14043c50f6d6San207044 u_32_t sum_orig = 0; 14053c50f6d6San207044 u_32_t sum_changed = 0; 14063c50f6d6San207044 u_32_t sumd; 14073c50f6d6San207044 u_32_t ipsum_orig = 0; 14083c50f6d6San207044 u_32_t ipsum_changed = 0; 14093c50f6d6San207044 1410d6c23f6fSyx160601 if (nat->nat_v != 4 && nat->nat_v != 6) 1411d6c23f6fSyx160601 return; 1412d6c23f6fSyx160601 14133c50f6d6San207044 /* 14143c50f6d6San207044 * the switch calculates operands for CALC_SUMD(), 14153c50f6d6San207044 * which will compute the partial chksum delta. 14163c50f6d6San207044 */ 14173c50f6d6San207044 switch (nat->nat_dir) 14183c50f6d6San207044 { 14193c50f6d6San207044 case NAT_INBOUND: 14203c50f6d6San207044 /* 14213c50f6d6San207044 * we are dealing with RDR rule (DST address gets 14223c50f6d6San207044 * modified on packet from client) 14233c50f6d6San207044 */ 1424d6c23f6fSyx160601 if (nat->nat_v == 4) { 14253c50f6d6San207044 sum_changed = LONG_SUM(ntohl(nat->nat_inip.s_addr)); 14263c50f6d6San207044 sum_orig = LONG_SUM(ntohl(nat->nat_outip.s_addr)); 1427d6c23f6fSyx160601 } else { 1428d6c23f6fSyx160601 sum_changed = LONG_SUM6(&nat->nat_inip6); 1429d6c23f6fSyx160601 sum_orig = LONG_SUM6(&nat->nat_outip6); 1430d6c23f6fSyx160601 } 14313c50f6d6San207044 break; 14323c50f6d6San207044 case NAT_OUTBOUND: 14333c50f6d6San207044 /* 14343c50f6d6San207044 * we are dealing with MAP rule (SRC address gets 14353c50f6d6San207044 * modified on packet from client) 14363c50f6d6San207044 */ 1437d6c23f6fSyx160601 if (nat->nat_v == 4) { 14383c50f6d6San207044 sum_changed = LONG_SUM(ntohl(nat->nat_outip.s_addr)); 14393c50f6d6San207044 sum_orig = LONG_SUM(ntohl(nat->nat_inip.s_addr)); 1440d6c23f6fSyx160601 } else { 1441d6c23f6fSyx160601 sum_changed = LONG_SUM6(&nat->nat_outip6); 1442d6c23f6fSyx160601 sum_orig = LONG_SUM6(&nat->nat_inip6); 1443d6c23f6fSyx160601 } 14443c50f6d6San207044 break; 14453c50f6d6San207044 default: ; 14463c50f6d6San207044 break; 14473c50f6d6San207044 } 14483c50f6d6San207044 14493c50f6d6San207044 /* 14503c50f6d6San207044 * we also preserve CALC_SUMD() operands here, for IP chksum delta 14513c50f6d6San207044 * calculation, which happens at the end of function. 14523c50f6d6San207044 */ 14533c50f6d6San207044 ipsum_changed = sum_changed; 14543c50f6d6San207044 ipsum_orig = sum_orig; 14553c50f6d6San207044 /* 14563c50f6d6San207044 * NOTE: the order of operands for partial chksum adjustment 14573c50f6d6San207044 * computation has to be swapped! 14583c50f6d6San207044 */ 14593c50f6d6San207044 CALC_SUMD(sum_changed, sum_orig, sumd); 14603c50f6d6San207044 nat->nat_sumd[1] = (sumd & 0xffff) + (sumd >> 16); 14613c50f6d6San207044 146227dbc409San207044 if (nat->nat_flags & (IPN_TCPUDP | IPN_ICMPQUERY)) { 14633c50f6d6San207044 14643c50f6d6San207044 /* 14653c50f6d6San207044 * switch calculates operands for CALC_SUMD(), which will 14663c50f6d6San207044 * compute the full chksum delta. 14673c50f6d6San207044 */ 14683c50f6d6San207044 switch (nat->nat_dir) 14693c50f6d6San207044 { 14703c50f6d6San207044 case NAT_INBOUND: 1471d6c23f6fSyx160601 if (nat->nat_v == 4) { 14723c50f6d6San207044 sum_changed = LONG_SUM( 14733c50f6d6San207044 ntohl(nat->nat_inip.s_addr) + 1474d6c23f6fSyx160601 ntohs(nat->nat_inport)); 14753c50f6d6San207044 sum_orig = LONG_SUM( 14763c50f6d6San207044 ntohl(nat->nat_outip.s_addr) + 1477d6c23f6fSyx160601 ntohs(nat->nat_outport)); 1478d6c23f6fSyx160601 } else { 1479d6c23f6fSyx160601 sum_changed = LONG_SUM6(&nat->nat_inip6) + 1480d6c23f6fSyx160601 ntohs(nat->nat_inport); 1481d6c23f6fSyx160601 sum_orig = LONG_SUM6(&nat->nat_outip6) + 1482d6c23f6fSyx160601 ntohs(nat->nat_outport); 1483d6c23f6fSyx160601 } 14843c50f6d6San207044 break; 14853c50f6d6San207044 case NAT_OUTBOUND: 1486d6c23f6fSyx160601 if (nat->nat_v == 4) { 14873c50f6d6San207044 sum_changed = LONG_SUM( 14883c50f6d6San207044 ntohl(nat->nat_outip.s_addr) + 1489d6c23f6fSyx160601 ntohs(nat->nat_outport)); 14903c50f6d6San207044 sum_orig = LONG_SUM( 14913c50f6d6San207044 ntohl(nat->nat_inip.s_addr) + 1492d6c23f6fSyx160601 ntohs(nat->nat_inport)); 1493d6c23f6fSyx160601 } else { 1494d6c23f6fSyx160601 sum_changed = LONG_SUM6(&nat->nat_outip6) + 1495d6c23f6fSyx160601 ntohs(nat->nat_outport); 1496d6c23f6fSyx160601 sum_orig = LONG_SUM6(&nat->nat_inip6) + 1497d6c23f6fSyx160601 ntohs(nat->nat_inport); 1498d6c23f6fSyx160601 } 14993c50f6d6San207044 break; 15003c50f6d6San207044 default: ; 15013c50f6d6San207044 break; 15023c50f6d6San207044 } 15033c50f6d6San207044 15043c50f6d6San207044 CALC_SUMD(sum_orig, sum_changed, sumd); 15053c50f6d6San207044 nat->nat_sumd[0] = (sumd & 0xffff) + (sumd >> 16); 150627dbc409San207044 150727dbc409San207044 if (!(nat->nat_flags & IPN_TCPUDP)) { 150827dbc409San207044 /* 150927dbc409San207044 * partial HW chksum offload works for TCP/UDP headers only, 151027dbc409San207044 * so we need to enforce full chksum adjustment for ICMP 151127dbc409San207044 */ 151227dbc409San207044 nat->nat_sumd[1] = nat->nat_sumd[0]; 151327dbc409San207044 } 15143c50f6d6San207044 } 15153c50f6d6San207044 else 15163c50f6d6San207044 nat->nat_sumd[0] = nat->nat_sumd[1]; 15173c50f6d6San207044 15183c50f6d6San207044 /* 15193c50f6d6San207044 * we may reuse the already computed nat_sumd[0] for IP header chksum 15203c50f6d6San207044 * adjustment in case the L4 (TCP/UDP header) is not changed by NAT. 15213c50f6d6San207044 */ 1522d6c23f6fSyx160601 if (nat->nat_v == 4) { 15233c50f6d6San207044 if (NAT_HAS_L4_CHANGED(nat)) { 15243c50f6d6San207044 /* 1525d6c23f6fSyx160601 * bad luck, NAT changes also the L4 header, use IP 1526d6c23f6fSyx160601 * addresses to compute chksum adjustment for IP header. 15273c50f6d6San207044 */ 15283c50f6d6San207044 CALC_SUMD(ipsum_orig, ipsum_changed, sumd); 15293c50f6d6San207044 nat->nat_ipsumd = (sumd & 0xffff) + (sumd >> 16); 1530d6c23f6fSyx160601 } else { 15313c50f6d6San207044 /* 1532d6c23f6fSyx160601 * the NAT does not change L4 hdr -> reuse chksum 1533d6c23f6fSyx160601 * adjustment for IP hdr. 15343c50f6d6San207044 */ 15353c50f6d6San207044 nat->nat_ipsumd = nat->nat_sumd[0]; 153627dbc409San207044 153727dbc409San207044 /* 1538d6c23f6fSyx160601 * if L4 header does not use chksum - zero out deltas 153927dbc409San207044 */ 1540d6c23f6fSyx160601 if (!(nat->nat_flags & IPN_TCPUDP)) { 154127dbc409San207044 nat->nat_sumd[0] = 0; 154227dbc409San207044 nat->nat_sumd[1] = 0; 154327dbc409San207044 } 15443c50f6d6San207044 } 1545d6c23f6fSyx160601 } 15463c50f6d6San207044 15473c50f6d6San207044 return; 15483c50f6d6San207044 } 1549ab25eeb5Syz155240 1550ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */ 1551ab25eeb5Syz155240 /* Function: fr_natputent */ 1552ab25eeb5Syz155240 /* Returns: int - 0 == success, != 0 is the error value. */ 1553ab25eeb5Syz155240 /* Parameters: data(I) - pointer to natget structure with NAT */ 1554ab25eeb5Syz155240 /* structure information to load into the kernel */ 1555ab25eeb5Syz155240 /* getlock(I) - flag indicating whether or not a write lock */ 1556ab25eeb5Syz155240 /* on ipf_nat is already held. */ 1557ea8244dcSJohn Ojemann /* ifs - ipf stack instance */ 1558ab25eeb5Syz155240 /* */ 1559ab25eeb5Syz155240 /* Handle SIOCSTPUT. */ 1560ab25eeb5Syz155240 /* Loads a NAT table entry from user space, including a NAT rule, proxy and */ 1561ab25eeb5Syz155240 /* firewall rule data structures, if pointers to them indicate so. */ 1562ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */ 1563f4b3ec61Sdh155122 static int fr_natputent(data, getlock, ifs) 1564ab25eeb5Syz155240 caddr_t data; 1565ab25eeb5Syz155240 int getlock; 1566f4b3ec61Sdh155122 ipf_stack_t *ifs; 1567ab25eeb5Syz155240 { 1568ab25eeb5Syz155240 nat_save_t ipn, *ipnn; 1569ab25eeb5Syz155240 ap_session_t *aps; 1570ab25eeb5Syz155240 nat_t *n, *nat; 1571ab25eeb5Syz155240 frentry_t *fr; 1572ab25eeb5Syz155240 fr_info_t fin; 1573ab25eeb5Syz155240 ipnat_t *in; 1574ab25eeb5Syz155240 int error; 1575ab25eeb5Syz155240 1576ab25eeb5Syz155240 error = fr_inobj(data, &ipn, IPFOBJ_NATSAVE); 1577ab25eeb5Syz155240 if (error != 0) 1578ab25eeb5Syz155240 return error; 1579ab25eeb5Syz155240 1580ab25eeb5Syz155240 /* 1581ea8244dcSJohn Ojemann * Trigger automatic call to nat_flushtable() if the 15823805c50fSan207044 * table has reached capcity specified by hi watermark. 15833805c50fSan207044 */ 1584ea8244dcSJohn Ojemann if (NAT_TAB_WATER_LEVEL(ifs) > ifs->ifs_nat_flush_level_hi) 15853805c50fSan207044 ifs->ifs_nat_doflush = 1; 15863805c50fSan207044 15873805c50fSan207044 /* 15885b48165cSJohn Ojemann * If automatic flushing did not do its job, and the table 15895b48165cSJohn Ojemann * has filled up, don't try to create a new entry. 15905b48165cSJohn Ojemann */ 15915b48165cSJohn Ojemann if (ifs->ifs_nat_stats.ns_inuse >= ifs->ifs_ipf_nattable_max) { 15925b48165cSJohn Ojemann ifs->ifs_nat_stats.ns_memfail++; 15935b48165cSJohn Ojemann return ENOMEM; 15945b48165cSJohn Ojemann } 15955b48165cSJohn Ojemann 15965b48165cSJohn Ojemann /* 1597ab25eeb5Syz155240 * Initialise early because of code at junkput label. 1598ab25eeb5Syz155240 */ 1599ab25eeb5Syz155240 in = NULL; 1600ab25eeb5Syz155240 aps = NULL; 1601ab25eeb5Syz155240 nat = NULL; 1602ab25eeb5Syz155240 ipnn = NULL; 1603ab25eeb5Syz155240 1604ab25eeb5Syz155240 /* 1605ab25eeb5Syz155240 * New entry, copy in the rest of the NAT entry if it's size is more 1606ab25eeb5Syz155240 * than just the nat_t structure. 1607ab25eeb5Syz155240 */ 1608ab25eeb5Syz155240 fr = NULL; 1609ab25eeb5Syz155240 if (ipn.ipn_dsize > sizeof(ipn)) { 1610ab25eeb5Syz155240 if (ipn.ipn_dsize > 81920) { 1611ab25eeb5Syz155240 error = ENOMEM; 1612ab25eeb5Syz155240 goto junkput; 1613ab25eeb5Syz155240 } 1614ab25eeb5Syz155240 1615ab25eeb5Syz155240 KMALLOCS(ipnn, nat_save_t *, ipn.ipn_dsize); 1616ab25eeb5Syz155240 if (ipnn == NULL) 1617ab25eeb5Syz155240 return ENOMEM; 1618ab25eeb5Syz155240 1619ab25eeb5Syz155240 error = fr_inobjsz(data, ipnn, IPFOBJ_NATSAVE, ipn.ipn_dsize); 1620ab25eeb5Syz155240 if (error != 0) { 1621ab25eeb5Syz155240 error = EFAULT; 1622ab25eeb5Syz155240 goto junkput; 1623ab25eeb5Syz155240 } 1624ab25eeb5Syz155240 } else 1625ab25eeb5Syz155240 ipnn = &ipn; 1626ab25eeb5Syz155240 1627ab25eeb5Syz155240 KMALLOC(nat, nat_t *); 1628ab25eeb5Syz155240 if (nat == NULL) { 1629ab25eeb5Syz155240 error = ENOMEM; 1630ab25eeb5Syz155240 goto junkput; 1631ab25eeb5Syz155240 } 1632ab25eeb5Syz155240 1633ab25eeb5Syz155240 bcopy((char *)&ipnn->ipn_nat, (char *)nat, sizeof(*nat)); 1634ab25eeb5Syz155240 /* 1635ab25eeb5Syz155240 * Initialize all these so that nat_delete() doesn't cause a crash. 1636ab25eeb5Syz155240 */ 1637ab25eeb5Syz155240 bzero((char *)nat, offsetof(struct nat, nat_tqe)); 1638ab25eeb5Syz155240 nat->nat_tqe.tqe_pnext = NULL; 1639ab25eeb5Syz155240 nat->nat_tqe.tqe_next = NULL; 1640ab25eeb5Syz155240 nat->nat_tqe.tqe_ifq = NULL; 1641ab25eeb5Syz155240 nat->nat_tqe.tqe_parent = nat; 1642ab25eeb5Syz155240 1643ab25eeb5Syz155240 /* 1644ab25eeb5Syz155240 * Restore the rule associated with this nat session 1645ab25eeb5Syz155240 */ 1646ab25eeb5Syz155240 in = ipnn->ipn_nat.nat_ptr; 1647ab25eeb5Syz155240 if (in != NULL) { 1648ab25eeb5Syz155240 KMALLOC(in, ipnat_t *); 1649ab25eeb5Syz155240 nat->nat_ptr = in; 1650ab25eeb5Syz155240 if (in == NULL) { 1651ab25eeb5Syz155240 error = ENOMEM; 1652ab25eeb5Syz155240 goto junkput; 1653ab25eeb5Syz155240 } 1654ab25eeb5Syz155240 bzero((char *)in, offsetof(struct ipnat, in_next6)); 1655ab25eeb5Syz155240 bcopy((char *)&ipnn->ipn_ipnat, (char *)in, sizeof(*in)); 1656ab25eeb5Syz155240 in->in_use = 1; 1657ab25eeb5Syz155240 in->in_flags |= IPN_DELETE; 1658ab25eeb5Syz155240 1659f4b3ec61Sdh155122 ATOMIC_INC(ifs->ifs_nat_stats.ns_rules); 1660ab25eeb5Syz155240 1661dcf3e898Sjojemann if (nat_resolverule(in, ifs) != 0) { 1662dcf3e898Sjojemann error = ESRCH; 1663dcf3e898Sjojemann goto junkput; 1664dcf3e898Sjojemann } 1665ab25eeb5Syz155240 } 1666ab25eeb5Syz155240 1667ab25eeb5Syz155240 /* 1668ab25eeb5Syz155240 * Check that the NAT entry doesn't already exist in the kernel. 1669ab25eeb5Syz155240 */ 1670d6c23f6fSyx160601 if (nat->nat_v != 6) 1671d6c23f6fSyx160601 nat->nat_v = 4; 1672ab25eeb5Syz155240 bzero((char *)&fin, sizeof(fin)); 1673ab25eeb5Syz155240 fin.fin_p = nat->nat_p; 167475c9105fSjojemann fin.fin_ifs = ifs; 1675ab25eeb5Syz155240 if (nat->nat_dir == NAT_OUTBOUND) { 1676ab25eeb5Syz155240 fin.fin_data[0] = ntohs(nat->nat_oport); 1677ab25eeb5Syz155240 fin.fin_data[1] = ntohs(nat->nat_outport); 1678e6c6c1faSyz155240 fin.fin_ifp = nat->nat_ifps[0]; 1679ab25eeb5Syz155240 if (getlock) { 1680f4b3ec61Sdh155122 READ_ENTER(&ifs->ifs_ipf_nat); 1681ab25eeb5Syz155240 } 1682d6c23f6fSyx160601 1683d6c23f6fSyx160601 switch (nat->nat_v) 1684d6c23f6fSyx160601 { 1685d6c23f6fSyx160601 case 4: 1686d6c23f6fSyx160601 fin.fin_v = nat->nat_v; 1687ab25eeb5Syz155240 n = nat_inlookup(&fin, nat->nat_flags, fin.fin_p, 1688ab25eeb5Syz155240 nat->nat_oip, nat->nat_outip); 1689d6c23f6fSyx160601 break; 1690d6c23f6fSyx160601 #ifdef USE_INET6 1691d6c23f6fSyx160601 case 6: 1692d6c23f6fSyx160601 n = nat6_inlookup(&fin, nat->nat_flags, fin.fin_p, 1693d6c23f6fSyx160601 &nat->nat_oip6.in6, &nat->nat_outip6.in6); 1694d6c23f6fSyx160601 break; 1695d6c23f6fSyx160601 #endif 1696d6c23f6fSyx160601 default: 1697d6c23f6fSyx160601 n = NULL; 1698d6c23f6fSyx160601 break; 1699d6c23f6fSyx160601 } 1700d6c23f6fSyx160601 1701ab25eeb5Syz155240 if (getlock) { 1702f4b3ec61Sdh155122 RWLOCK_EXIT(&ifs->ifs_ipf_nat); 1703ab25eeb5Syz155240 } 1704ab25eeb5Syz155240 if (n != NULL) { 1705ab25eeb5Syz155240 error = EEXIST; 1706ab25eeb5Syz155240 goto junkput; 1707ab25eeb5Syz155240 } 1708ab25eeb5Syz155240 } else if (nat->nat_dir == NAT_INBOUND) { 1709ab25eeb5Syz155240 fin.fin_data[0] = ntohs(nat->nat_inport); 1710ab25eeb5Syz155240 fin.fin_data[1] = ntohs(nat->nat_oport); 1711e6c6c1faSyz155240 fin.fin_ifp = nat->nat_ifps[1]; 1712ab25eeb5Syz155240 if (getlock) { 1713f4b3ec61Sdh155122 READ_ENTER(&ifs->ifs_ipf_nat); 1714ab25eeb5Syz155240 } 1715d6c23f6fSyx160601 1716d6c23f6fSyx160601 switch (nat->nat_v) 1717d6c23f6fSyx160601 { 1718d6c23f6fSyx160601 case 4: 1719ab25eeb5Syz155240 n = nat_outlookup(&fin, nat->nat_flags, fin.fin_p, 1720e6c6c1faSyz155240 nat->nat_inip, nat->nat_oip); 1721d6c23f6fSyx160601 break; 1722d6c23f6fSyx160601 #ifdef USE_INET6 1723d6c23f6fSyx160601 case 6: 1724d6c23f6fSyx160601 n = nat6_outlookup(&fin, nat->nat_flags, fin.fin_p, 1725d6c23f6fSyx160601 &nat->nat_inip6.in6, &nat->nat_oip6.in6); 1726d6c23f6fSyx160601 break; 1727d6c23f6fSyx160601 #endif 1728d6c23f6fSyx160601 default: 1729d6c23f6fSyx160601 n = NULL; 1730d6c23f6fSyx160601 break; 1731d6c23f6fSyx160601 } 1732d6c23f6fSyx160601 1733ab25eeb5Syz155240 if (getlock) { 1734f4b3ec61Sdh155122 RWLOCK_EXIT(&ifs->ifs_ipf_nat); 1735ab25eeb5Syz155240 } 1736ab25eeb5Syz155240 if (n != NULL) { 1737ab25eeb5Syz155240 error = EEXIST; 1738ab25eeb5Syz155240 goto junkput; 1739ab25eeb5Syz155240 } 1740ab25eeb5Syz155240 } else { 1741ab25eeb5Syz155240 error = EINVAL; 1742ab25eeb5Syz155240 goto junkput; 1743ab25eeb5Syz155240 } 1744ab25eeb5Syz155240 1745ab25eeb5Syz155240 /* 1746ab25eeb5Syz155240 * Restore ap_session_t structure. Include the private data allocated 1747ab25eeb5Syz155240 * if it was there. 1748ab25eeb5Syz155240 */ 1749ab25eeb5Syz155240 aps = nat->nat_aps; 1750ab25eeb5Syz155240 if (aps != NULL) { 1751ab25eeb5Syz155240 KMALLOC(aps, ap_session_t *); 1752ab25eeb5Syz155240 nat->nat_aps = aps; 1753ab25eeb5Syz155240 if (aps == NULL) { 1754ab25eeb5Syz155240 error = ENOMEM; 1755ab25eeb5Syz155240 goto junkput; 1756ab25eeb5Syz155240 } 1757ab25eeb5Syz155240 bcopy(ipnn->ipn_data, (char *)aps, sizeof(*aps)); 1758ab25eeb5Syz155240 if (in != NULL) 1759ab25eeb5Syz155240 aps->aps_apr = in->in_apr; 1760ab25eeb5Syz155240 else 1761ab25eeb5Syz155240 aps->aps_apr = NULL; 1762ab25eeb5Syz155240 if (aps->aps_psiz != 0) { 1763ab25eeb5Syz155240 if (aps->aps_psiz > 81920) { 1764ab25eeb5Syz155240 error = ENOMEM; 1765ab25eeb5Syz155240 goto junkput; 1766ab25eeb5Syz155240 } 1767ab25eeb5Syz155240 KMALLOCS(aps->aps_data, void *, aps->aps_psiz); 1768ab25eeb5Syz155240 if (aps->aps_data == NULL) { 1769ab25eeb5Syz155240 error = ENOMEM; 1770ab25eeb5Syz155240 goto junkput; 1771ab25eeb5Syz155240 } 1772ab25eeb5Syz155240 bcopy(ipnn->ipn_data + sizeof(*aps), aps->aps_data, 1773ab25eeb5Syz155240 aps->aps_psiz); 1774ab25eeb5Syz155240 } else { 1775ab25eeb5Syz155240 aps->aps_psiz = 0; 1776ab25eeb5Syz155240 aps->aps_data = NULL; 1777ab25eeb5Syz155240 } 1778ab25eeb5Syz155240 } 1779ab25eeb5Syz155240 1780ab25eeb5Syz155240 /* 1781ab25eeb5Syz155240 * If there was a filtering rule associated with this entry then 1782ab25eeb5Syz155240 * build up a new one. 1783ab25eeb5Syz155240 */ 1784ab25eeb5Syz155240 fr = nat->nat_fr; 1785ab25eeb5Syz155240 if (fr != NULL) { 1786ab25eeb5Syz155240 if ((nat->nat_flags & SI_NEWFR) != 0) { 1787ab25eeb5Syz155240 KMALLOC(fr, frentry_t *); 1788ab25eeb5Syz155240 nat->nat_fr = fr; 1789ab25eeb5Syz155240 if (fr == NULL) { 1790ab25eeb5Syz155240 error = ENOMEM; 1791ab25eeb5Syz155240 goto junkput; 1792ab25eeb5Syz155240 } 1793ab25eeb5Syz155240 ipnn->ipn_nat.nat_fr = fr; 1794ab25eeb5Syz155240 (void) fr_outobj(data, ipnn, IPFOBJ_NATSAVE); 1795ab25eeb5Syz155240 bcopy((char *)&ipnn->ipn_fr, (char *)fr, sizeof(*fr)); 1796dcf3e898Sjojemann 1797dcf3e898Sjojemann fr->fr_ref = 1; 1798dcf3e898Sjojemann fr->fr_dsize = 0; 1799dcf3e898Sjojemann fr->fr_data = NULL; 1800dcf3e898Sjojemann fr->fr_type = FR_T_NONE; 1801dcf3e898Sjojemann 1802ab25eeb5Syz155240 MUTEX_NUKE(&fr->fr_lock); 1803ab25eeb5Syz155240 MUTEX_INIT(&fr->fr_lock, "nat-filter rule lock"); 1804ab25eeb5Syz155240 } else { 1805dcf3e898Sjojemann if (getlock) { 1806f4b3ec61Sdh155122 READ_ENTER(&ifs->ifs_ipf_nat); 1807dcf3e898Sjojemann } 1808f4b3ec61Sdh155122 for (n = ifs->ifs_nat_instances; n; n = n->nat_next) 1809ab25eeb5Syz155240 if (n->nat_fr == fr) 1810ab25eeb5Syz155240 break; 1811ab25eeb5Syz155240 1812ab25eeb5Syz155240 if (n != NULL) { 1813ab25eeb5Syz155240 MUTEX_ENTER(&fr->fr_lock); 1814ab25eeb5Syz155240 fr->fr_ref++; 1815ab25eeb5Syz155240 MUTEX_EXIT(&fr->fr_lock); 1816ab25eeb5Syz155240 } 1817dcf3e898Sjojemann if (getlock) { 1818f4b3ec61Sdh155122 RWLOCK_EXIT(&ifs->ifs_ipf_nat); 1819dcf3e898Sjojemann } 1820ab25eeb5Syz155240 if (!n) { 1821ab25eeb5Syz155240 error = ESRCH; 1822ab25eeb5Syz155240 goto junkput; 1823ab25eeb5Syz155240 } 1824ab25eeb5Syz155240 } 1825ab25eeb5Syz155240 } 1826ab25eeb5Syz155240 1827ab25eeb5Syz155240 if (ipnn != &ipn) { 1828ab25eeb5Syz155240 KFREES(ipnn, ipn.ipn_dsize); 1829ab25eeb5Syz155240 ipnn = NULL; 1830ab25eeb5Syz155240 } 1831ab25eeb5Syz155240 18323c50f6d6San207044 nat_calc_chksum_diffs(nat); 18333c50f6d6San207044 1834ab25eeb5Syz155240 if (getlock) { 1835f4b3ec61Sdh155122 WRITE_ENTER(&ifs->ifs_ipf_nat); 1836ab25eeb5Syz155240 } 1837d6c23f6fSyx160601 1838d6c23f6fSyx160601 nat_calc_chksum_diffs(nat); 1839d6c23f6fSyx160601 1840d6c23f6fSyx160601 switch (nat->nat_v) 1841d6c23f6fSyx160601 { 1842d6c23f6fSyx160601 case 4 : 1843f4b3ec61Sdh155122 error = nat_insert(nat, nat->nat_rev, ifs); 1844d6c23f6fSyx160601 break; 1845d6c23f6fSyx160601 #ifdef USE_INET6 1846d6c23f6fSyx160601 case 6 : 1847d6c23f6fSyx160601 error = nat6_insert(nat, nat->nat_rev, ifs); 1848d6c23f6fSyx160601 break; 1849d6c23f6fSyx160601 #endif 1850d6c23f6fSyx160601 default : 1851d6c23f6fSyx160601 break; 1852d6c23f6fSyx160601 } 1853d6c23f6fSyx160601 1854ab25eeb5Syz155240 if ((error == 0) && (aps != NULL)) { 1855f4b3ec61Sdh155122 aps->aps_next = ifs->ifs_ap_sess_list; 1856f4b3ec61Sdh155122 ifs->ifs_ap_sess_list = aps; 1857ab25eeb5Syz155240 } 1858ab25eeb5Syz155240 if (getlock) { 1859f4b3ec61Sdh155122 RWLOCK_EXIT(&ifs->ifs_ipf_nat); 1860ab25eeb5Syz155240 } 1861ab25eeb5Syz155240 1862ab25eeb5Syz155240 if (error == 0) 1863ab25eeb5Syz155240 return 0; 1864ab25eeb5Syz155240 1865ab25eeb5Syz155240 error = ENOMEM; 1866ab25eeb5Syz155240 1867ab25eeb5Syz155240 junkput: 1868ab25eeb5Syz155240 if (fr != NULL) 1869f4b3ec61Sdh155122 (void) fr_derefrule(&fr, ifs); 1870ab25eeb5Syz155240 1871ab25eeb5Syz155240 if ((ipnn != NULL) && (ipnn != &ipn)) { 1872ab25eeb5Syz155240 KFREES(ipnn, ipn.ipn_dsize); 1873ab25eeb5Syz155240 } 1874ab25eeb5Syz155240 if (nat != NULL) { 1875ab25eeb5Syz155240 if (aps != NULL) { 1876ab25eeb5Syz155240 if (aps->aps_data != NULL) { 1877ab25eeb5Syz155240 KFREES(aps->aps_data, aps->aps_psiz); 1878ab25eeb5Syz155240 } 1879ab25eeb5Syz155240 KFREE(aps); 1880ab25eeb5Syz155240 } 1881ab25eeb5Syz155240 if (in != NULL) { 1882ab25eeb5Syz155240 if (in->in_apr) 1883ab25eeb5Syz155240 appr_free(in->in_apr); 1884ab25eeb5Syz155240 KFREE(in); 1885ab25eeb5Syz155240 } 1886ab25eeb5Syz155240 KFREE(nat); 1887ab25eeb5Syz155240 } 1888ab25eeb5Syz155240 return error; 1889ab25eeb5Syz155240 } 1890ab25eeb5Syz155240 1891ab25eeb5Syz155240 1892ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */ 1893ab25eeb5Syz155240 /* Function: nat_delete */ 1894ea8244dcSJohn Ojemann /* Returns: int - 0 if entry deleted. Otherwise, ref count on entry */ 1895ea8244dcSJohn Ojemann /* Parameters: nat - pointer to the NAT entry to delete */ 1896ea8244dcSJohn Ojemann /* logtype - type of LOG record to create before deleting */ 18975b48165cSJohn Ojemann /* ifs - ipf stack instance */ 1898ab25eeb5Syz155240 /* Write Lock: ipf_nat */ 1899ab25eeb5Syz155240 /* */ 1900ab25eeb5Syz155240 /* Delete a nat entry from the various lists and table. If NAT logging is */ 1901ab25eeb5Syz155240 /* enabled then generate a NAT log record for this event. */ 1902ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */ 1903ea8244dcSJohn Ojemann int nat_delete(nat, logtype, ifs) 1904ab25eeb5Syz155240 struct nat *nat; 1905ab25eeb5Syz155240 int logtype; 1906f4b3ec61Sdh155122 ipf_stack_t *ifs; 1907ab25eeb5Syz155240 { 1908ab25eeb5Syz155240 struct ipnat *ipn; 19095b48165cSJohn Ojemann int removed = 0; 1910ab25eeb5Syz155240 1911f4b3ec61Sdh155122 if (logtype != 0 && ifs->ifs_nat_logging != 0) 1912f4b3ec61Sdh155122 nat_log(nat, logtype, ifs); 1913ab25eeb5Syz155240 1914ab25eeb5Syz155240 /* 19155b48165cSJohn Ojemann * Start by removing the entry from the hash table of nat entries 19165b48165cSJohn Ojemann * so it will not be "used" again. 19175b48165cSJohn Ojemann * 19185b48165cSJohn Ojemann * It will remain in the "list" of nat entries until all references 19195b48165cSJohn Ojemann * have been accounted for. 1920ab25eeb5Syz155240 */ 19215b48165cSJohn Ojemann if ((nat->nat_phnext[0] != NULL) && (nat->nat_phnext[1] != NULL)) { 19225b48165cSJohn Ojemann removed = 1; 19235b48165cSJohn Ojemann 1924f4b3ec61Sdh155122 ifs->ifs_nat_stats.ns_bucketlen[0][nat->nat_hv[0]]--; 1925f4b3ec61Sdh155122 ifs->ifs_nat_stats.ns_bucketlen[1][nat->nat_hv[1]]--; 1926ab25eeb5Syz155240 1927ab25eeb5Syz155240 *nat->nat_phnext[0] = nat->nat_hnext[0]; 1928ab25eeb5Syz155240 if (nat->nat_hnext[0] != NULL) { 1929ab25eeb5Syz155240 nat->nat_hnext[0]->nat_phnext[0] = nat->nat_phnext[0]; 1930ab25eeb5Syz155240 nat->nat_hnext[0] = NULL; 1931ab25eeb5Syz155240 } 1932ab25eeb5Syz155240 nat->nat_phnext[0] = NULL; 1933ab25eeb5Syz155240 1934ab25eeb5Syz155240 *nat->nat_phnext[1] = nat->nat_hnext[1]; 1935ab25eeb5Syz155240 if (nat->nat_hnext[1] != NULL) { 1936ab25eeb5Syz155240 nat->nat_hnext[1]->nat_phnext[1] = nat->nat_phnext[1]; 1937ab25eeb5Syz155240 nat->nat_hnext[1] = NULL; 1938ab25eeb5Syz155240 } 1939ab25eeb5Syz155240 nat->nat_phnext[1] = NULL; 1940ab25eeb5Syz155240 1941ab25eeb5Syz155240 if ((nat->nat_flags & SI_WILDP) != 0) 1942f4b3ec61Sdh155122 ifs->ifs_nat_stats.ns_wilds--; 1943ab25eeb5Syz155240 } 1944ab25eeb5Syz155240 19455b48165cSJohn Ojemann /* 19465b48165cSJohn Ojemann * Next, remove it from the timeout queue it is in. 19475b48165cSJohn Ojemann */ 19485b48165cSJohn Ojemann fr_deletequeueentry(&nat->nat_tqe); 19495b48165cSJohn Ojemann 1950ab25eeb5Syz155240 if (nat->nat_me != NULL) { 1951ab25eeb5Syz155240 *nat->nat_me = NULL; 1952ab25eeb5Syz155240 nat->nat_me = NULL; 1953ab25eeb5Syz155240 } 1954ab25eeb5Syz155240 19550e01ff8bSdr146992 MUTEX_ENTER(&nat->nat_lock); 195633f2fefdSDarren Reed if (nat->nat_ref > 1) { 1957ab25eeb5Syz155240 nat->nat_ref--; 19580e01ff8bSdr146992 MUTEX_EXIT(&nat->nat_lock); 19595b48165cSJohn Ojemann if (removed) 19605b48165cSJohn Ojemann ifs->ifs_nat_stats.ns_orphans++; 1961ea8244dcSJohn Ojemann return (nat->nat_ref); 1962ab25eeb5Syz155240 } 19630e01ff8bSdr146992 MUTEX_EXIT(&nat->nat_lock); 19640e01ff8bSdr146992 19650e01ff8bSdr146992 nat->nat_ref = 0; 1966ab25eeb5Syz155240 19675b48165cSJohn Ojemann /* 19685b48165cSJohn Ojemann * If entry had already been removed, 19695b48165cSJohn Ojemann * it means we're cleaning up an orphan. 19705b48165cSJohn Ojemann */ 19715b48165cSJohn Ojemann if (!removed) 19725b48165cSJohn Ojemann ifs->ifs_nat_stats.ns_orphans--; 19735b48165cSJohn Ojemann 1974ab25eeb5Syz155240 #ifdef IPFILTER_SYNC 1975ab25eeb5Syz155240 if (nat->nat_sync) 1976ab25eeb5Syz155240 ipfsync_del(nat->nat_sync); 1977ab25eeb5Syz155240 #endif 1978ab25eeb5Syz155240 19795b48165cSJohn Ojemann /* 19805b48165cSJohn Ojemann * Now remove it from master list of nat table entries 19815b48165cSJohn Ojemann */ 19825b48165cSJohn Ojemann if (nat->nat_pnext != NULL) { 19835b48165cSJohn Ojemann *nat->nat_pnext = nat->nat_next; 19845b48165cSJohn Ojemann if (nat->nat_next != NULL) { 19855b48165cSJohn Ojemann nat->nat_next->nat_pnext = nat->nat_pnext; 19865b48165cSJohn Ojemann nat->nat_next = NULL; 19875b48165cSJohn Ojemann } 19885b48165cSJohn Ojemann nat->nat_pnext = NULL; 19895b48165cSJohn Ojemann } 19905b48165cSJohn Ojemann 1991ab25eeb5Syz155240 if (nat->nat_fr != NULL) 1992f4b3ec61Sdh155122 (void)fr_derefrule(&nat->nat_fr, ifs); 1993ab25eeb5Syz155240 1994ab25eeb5Syz155240 if (nat->nat_hm != NULL) 199590b0a856Sjojemann fr_hostmapdel(&nat->nat_hm); 1996ab25eeb5Syz155240 1997ab25eeb5Syz155240 /* 1998ab25eeb5Syz155240 * If there is an active reference from the nat entry to its parent 1999ab25eeb5Syz155240 * rule, decrement the rule's reference count and free it too if no 2000ab25eeb5Syz155240 * longer being used. 2001ab25eeb5Syz155240 */ 2002ab25eeb5Syz155240 ipn = nat->nat_ptr; 2003ab25eeb5Syz155240 if (ipn != NULL) { 2004ab25eeb5Syz155240 ipn->in_space++; 2005ab25eeb5Syz155240 ipn->in_use--; 2006ab25eeb5Syz155240 if (ipn->in_use == 0 && (ipn->in_flags & IPN_DELETE)) { 2007ab25eeb5Syz155240 if (ipn->in_apr) 2008ab25eeb5Syz155240 appr_free(ipn->in_apr); 2009ab25eeb5Syz155240 KFREE(ipn); 2010f4b3ec61Sdh155122 ifs->ifs_nat_stats.ns_rules--; 2011ab25eeb5Syz155240 } 2012ab25eeb5Syz155240 } 2013ab25eeb5Syz155240 2014ab25eeb5Syz155240 MUTEX_DESTROY(&nat->nat_lock); 2015ab25eeb5Syz155240 2016f4b3ec61Sdh155122 aps_free(nat->nat_aps, ifs); 2017f4b3ec61Sdh155122 ifs->ifs_nat_stats.ns_inuse--; 2018ab25eeb5Syz155240 2019ab25eeb5Syz155240 /* 2020ab25eeb5Syz155240 * If there's a fragment table entry too for this nat entry, then 2021ab25eeb5Syz155240 * dereference that as well. This is after nat_lock is released 2022ab25eeb5Syz155240 * because of Tru64. 2023ab25eeb5Syz155240 */ 2024f4b3ec61Sdh155122 fr_forgetnat((void *)nat, ifs); 2025ab25eeb5Syz155240 2026ab25eeb5Syz155240 KFREE(nat); 2027ab25eeb5Syz155240 2028ea8244dcSJohn Ojemann return (0); 2029ab25eeb5Syz155240 } 2030ab25eeb5Syz155240 2031ab25eeb5Syz155240 2032ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */ 2033ab25eeb5Syz155240 /* Function: nat_clearlist */ 2034ab25eeb5Syz155240 /* Returns: int - number of NAT/RDR rules deleted */ 2035ab25eeb5Syz155240 /* Parameters: Nil */ 2036ab25eeb5Syz155240 /* */ 2037ab25eeb5Syz155240 /* Delete all rules in the current list of rules. There is nothing elegant */ 2038ab25eeb5Syz155240 /* about this cleanup: simply free all entries on the list of rules and */ 2039ab25eeb5Syz155240 /* clear out the tables used for hashed NAT rule lookups. */ 2040ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */ 2041f4b3ec61Sdh155122 static int nat_clearlist(ifs) 2042f4b3ec61Sdh155122 ipf_stack_t *ifs; 2043ab25eeb5Syz155240 { 2044f4b3ec61Sdh155122 ipnat_t *n, **np = &ifs->ifs_nat_list; 2045ab25eeb5Syz155240 int i = 0; 2046ab25eeb5Syz155240 2047f4b3ec61Sdh155122 if (ifs->ifs_nat_rules != NULL) 2048f4b3ec61Sdh155122 bzero((char *)ifs->ifs_nat_rules, 2049f4b3ec61Sdh155122 sizeof(*ifs->ifs_nat_rules) * ifs->ifs_ipf_natrules_sz); 2050f4b3ec61Sdh155122 if (ifs->ifs_rdr_rules != NULL) 2051f4b3ec61Sdh155122 bzero((char *)ifs->ifs_rdr_rules, 2052f4b3ec61Sdh155122 sizeof(*ifs->ifs_rdr_rules) * ifs->ifs_ipf_rdrrules_sz); 2053ab25eeb5Syz155240 2054ab25eeb5Syz155240 while ((n = *np) != NULL) { 2055ab25eeb5Syz155240 *np = n->in_next; 2056ab25eeb5Syz155240 if (n->in_use == 0) { 2057ab25eeb5Syz155240 if (n->in_apr != NULL) 2058ab25eeb5Syz155240 appr_free(n->in_apr); 2059ab25eeb5Syz155240 KFREE(n); 2060f4b3ec61Sdh155122 ifs->ifs_nat_stats.ns_rules--; 2061ab25eeb5Syz155240 } else { 2062ab25eeb5Syz155240 n->in_flags |= IPN_DELETE; 2063ab25eeb5Syz155240 n->in_next = NULL; 2064ab25eeb5Syz155240 } 2065ab25eeb5Syz155240 i++; 2066ab25eeb5Syz155240 } 2067f4b3ec61Sdh155122 ifs->ifs_nat_masks = 0; 2068f4b3ec61Sdh155122 ifs->ifs_rdr_masks = 0; 2069d6c23f6fSyx160601 for (i = 0; i < 4; i++) { 2070d6c23f6fSyx160601 ifs->ifs_nat6_masks[i] = 0; 2071d6c23f6fSyx160601 ifs->ifs_rdr6_masks[i] = 0; 2072d6c23f6fSyx160601 } 2073ab25eeb5Syz155240 return i; 2074ab25eeb5Syz155240 } 2075ab25eeb5Syz155240 2076ab25eeb5Syz155240 2077ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */ 2078ab25eeb5Syz155240 /* Function: nat_newmap */ 2079ab25eeb5Syz155240 /* Returns: int - -1 == error, 0 == success */ 2080ab25eeb5Syz155240 /* Parameters: fin(I) - pointer to packet information */ 2081ab25eeb5Syz155240 /* nat(I) - pointer to NAT entry */ 2082ab25eeb5Syz155240 /* ni(I) - pointer to structure with misc. information needed */ 2083ab25eeb5Syz155240 /* to create new NAT entry. */ 2084ab25eeb5Syz155240 /* */ 2085ab25eeb5Syz155240 /* Given an empty NAT structure, populate it with new information about a */ 2086ab25eeb5Syz155240 /* new NAT session, as defined by the matching NAT rule. */ 2087ab25eeb5Syz155240 /* ni.nai_ip is passed in uninitialised and must be set, in host byte order,*/ 2088ab25eeb5Syz155240 /* to the new IP address for the translation. */ 2089ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */ 2090ab25eeb5Syz155240 static INLINE int nat_newmap(fin, nat, ni) 2091ab25eeb5Syz155240 fr_info_t *fin; 2092ab25eeb5Syz155240 nat_t *nat; 2093ab25eeb5Syz155240 natinfo_t *ni; 2094ab25eeb5Syz155240 { 2095ab25eeb5Syz155240 u_short st_port, dport, sport, port, sp, dp; 2096ab25eeb5Syz155240 struct in_addr in, inb; 2097ab25eeb5Syz155240 hostmap_t *hm; 2098ab25eeb5Syz155240 u_32_t flags; 2099ab25eeb5Syz155240 u_32_t st_ip; 2100ab25eeb5Syz155240 ipnat_t *np; 2101ab25eeb5Syz155240 nat_t *natl; 2102ab25eeb5Syz155240 int l; 2103f4b3ec61Sdh155122 ipf_stack_t *ifs = fin->fin_ifs; 2104ab25eeb5Syz155240 2105ab25eeb5Syz155240 /* 2106ab25eeb5Syz155240 * If it's an outbound packet which doesn't match any existing 2107ab25eeb5Syz155240 * record, then create a new port 2108ab25eeb5Syz155240 */ 2109ab25eeb5Syz155240 l = 0; 2110ab25eeb5Syz155240 hm = NULL; 2111ab25eeb5Syz155240 np = ni->nai_np; 2112ab25eeb5Syz155240 st_ip = np->in_nip; 2113ab25eeb5Syz155240 st_port = np->in_pnext; 2114ab25eeb5Syz155240 flags = ni->nai_flags; 2115ab25eeb5Syz155240 sport = ni->nai_sport; 2116ab25eeb5Syz155240 dport = ni->nai_dport; 2117ab25eeb5Syz155240 2118ab25eeb5Syz155240 /* 2119ab25eeb5Syz155240 * Do a loop until we either run out of entries to try or we find 2120ab25eeb5Syz155240 * a NAT mapping that isn't currently being used. This is done 2121ab25eeb5Syz155240 * because the change to the source is not (usually) being fixed. 2122ab25eeb5Syz155240 */ 2123ab25eeb5Syz155240 do { 2124ab25eeb5Syz155240 port = 0; 2125ab25eeb5Syz155240 in.s_addr = htonl(np->in_nip); 2126ab25eeb5Syz155240 if (l == 0) { 2127ab25eeb5Syz155240 /* 2128ab25eeb5Syz155240 * Check to see if there is an existing NAT 2129ab25eeb5Syz155240 * setup for this IP address pair. 2130ab25eeb5Syz155240 */ 2131ab25eeb5Syz155240 hm = nat_hostmap(np, fin->fin_src, fin->fin_dst, 2132f4b3ec61Sdh155122 in, 0, ifs); 2133ab25eeb5Syz155240 if (hm != NULL) 2134ab25eeb5Syz155240 in.s_addr = hm->hm_mapip.s_addr; 2135ab25eeb5Syz155240 } else if ((l == 1) && (hm != NULL)) { 213690b0a856Sjojemann fr_hostmapdel(&hm); 2137ab25eeb5Syz155240 } 2138ab25eeb5Syz155240 in.s_addr = ntohl(in.s_addr); 2139ab25eeb5Syz155240 2140ab25eeb5Syz155240 nat->nat_hm = hm; 2141ab25eeb5Syz155240 2142ab25eeb5Syz155240 if ((np->in_outmsk == 0xffffffff) && (np->in_pnext == 0)) { 2143ab25eeb5Syz155240 if (l > 0) 2144ab25eeb5Syz155240 return -1; 2145ab25eeb5Syz155240 } 2146ab25eeb5Syz155240 2147ab25eeb5Syz155240 if (np->in_redir == NAT_BIMAP && 2148ab25eeb5Syz155240 np->in_inmsk == np->in_outmsk) { 2149ab25eeb5Syz155240 /* 2150ab25eeb5Syz155240 * map the address block in a 1:1 fashion 2151ab25eeb5Syz155240 */ 2152ab25eeb5Syz155240 in.s_addr = np->in_outip; 2153ab25eeb5Syz155240 in.s_addr |= fin->fin_saddr & ~np->in_inmsk; 2154ab25eeb5Syz155240 in.s_addr = ntohl(in.s_addr); 2155ab25eeb5Syz155240 2156ab25eeb5Syz155240 } else if (np->in_redir & NAT_MAPBLK) { 2157ab25eeb5Syz155240 if ((l >= np->in_ppip) || ((l > 0) && 2158ab25eeb5Syz155240 !(flags & IPN_TCPUDP))) 2159ab25eeb5Syz155240 return -1; 2160ab25eeb5Syz155240 /* 2161ab25eeb5Syz155240 * map-block - Calculate destination address. 2162ab25eeb5Syz155240 */ 2163ab25eeb5Syz155240 in.s_addr = ntohl(fin->fin_saddr); 2164ab25eeb5Syz155240 in.s_addr &= ntohl(~np->in_inmsk); 2165ab25eeb5Syz155240 inb.s_addr = in.s_addr; 2166ab25eeb5Syz155240 in.s_addr /= np->in_ippip; 2167ab25eeb5Syz155240 in.s_addr &= ntohl(~np->in_outmsk); 2168ab25eeb5Syz155240 in.s_addr += ntohl(np->in_outip); 2169ab25eeb5Syz155240 /* 2170ab25eeb5Syz155240 * Calculate destination port. 2171ab25eeb5Syz155240 */ 2172ab25eeb5Syz155240 if ((flags & IPN_TCPUDP) && 2173ab25eeb5Syz155240 (np->in_ppip != 0)) { 2174ab25eeb5Syz155240 port = ntohs(sport) + l; 2175ab25eeb5Syz155240 port %= np->in_ppip; 2176ab25eeb5Syz155240 port += np->in_ppip * 2177ab25eeb5Syz155240 (inb.s_addr % np->in_ippip); 2178ab25eeb5Syz155240 port += MAPBLK_MINPORT; 2179ab25eeb5Syz155240 port = htons(port); 2180ab25eeb5Syz155240 } 2181ab25eeb5Syz155240 2182ab25eeb5Syz155240 } else if ((np->in_outip == 0) && 2183ab25eeb5Syz155240 (np->in_outmsk == 0xffffffff)) { 2184ab25eeb5Syz155240 /* 2185ab25eeb5Syz155240 * 0/32 - use the interface's IP address. 2186ab25eeb5Syz155240 */ 2187ab25eeb5Syz155240 if ((l > 0) || 2188ab25eeb5Syz155240 fr_ifpaddr(4, FRI_NORMAL, fin->fin_ifp, 2189f4b3ec61Sdh155122 &in, NULL, fin->fin_ifs) == -1) 2190ab25eeb5Syz155240 return -1; 2191ab25eeb5Syz155240 in.s_addr = ntohl(in.s_addr); 2192ab25eeb5Syz155240 2193ab25eeb5Syz155240 } else if ((np->in_outip == 0) && (np->in_outmsk == 0)) { 2194ab25eeb5Syz155240 /* 2195ab25eeb5Syz155240 * 0/0 - use the original source address/port. 2196ab25eeb5Syz155240 */ 2197ab25eeb5Syz155240 if (l > 0) 2198ab25eeb5Syz155240 return -1; 2199ab25eeb5Syz155240 in.s_addr = ntohl(fin->fin_saddr); 2200ab25eeb5Syz155240 2201ab25eeb5Syz155240 } else if ((np->in_outmsk != 0xffffffff) && 2202ab25eeb5Syz155240 (np->in_pnext == 0) && ((l > 0) || (hm == NULL))) 2203ab25eeb5Syz155240 np->in_nip++; 2204ab25eeb5Syz155240 2205ab25eeb5Syz155240 natl = NULL; 2206ab25eeb5Syz155240 2207ab25eeb5Syz155240 if ((flags & IPN_TCPUDP) && 2208ab25eeb5Syz155240 ((np->in_redir & NAT_MAPBLK) == 0) && 2209ab25eeb5Syz155240 (np->in_flags & IPN_AUTOPORTMAP)) { 2210ab25eeb5Syz155240 /* 2211ab25eeb5Syz155240 * "ports auto" (without map-block) 2212ab25eeb5Syz155240 */ 2213ab25eeb5Syz155240 if ((l > 0) && (l % np->in_ppip == 0)) { 2214ab25eeb5Syz155240 if (l > np->in_space) { 2215ab25eeb5Syz155240 return -1; 2216ab25eeb5Syz155240 } else if ((l > np->in_ppip) && 2217ab25eeb5Syz155240 np->in_outmsk != 0xffffffff) 2218ab25eeb5Syz155240 np->in_nip++; 2219ab25eeb5Syz155240 } 2220ab25eeb5Syz155240 if (np->in_ppip != 0) { 2221ab25eeb5Syz155240 port = ntohs(sport); 2222ab25eeb5Syz155240 port += (l % np->in_ppip); 2223ab25eeb5Syz155240 port %= np->in_ppip; 2224ab25eeb5Syz155240 port += np->in_ppip * 2225ab25eeb5Syz155240 (ntohl(fin->fin_saddr) % 2226ab25eeb5Syz155240 np->in_ippip); 2227ab25eeb5Syz155240 port += MAPBLK_MINPORT; 2228ab25eeb5Syz155240 port = htons(port); 2229ab25eeb5Syz155240 } 2230ab25eeb5Syz155240 2231ab25eeb5Syz155240 } else if (((np->in_redir & NAT_MAPBLK) == 0) && 2232ab25eeb5Syz155240 (flags & IPN_TCPUDPICMP) && (np->in_pnext != 0)) { 2233ab25eeb5Syz155240 /* 2234ab25eeb5Syz155240 * Standard port translation. Select next port. 2235ab25eeb5Syz155240 */ 2236ab073b32Sdr146992 if (np->in_flags & IPN_SEQUENTIAL) { 2237ab073b32Sdr146992 port = np->in_pnext; 2238ab073b32Sdr146992 } else { 2239ab073b32Sdr146992 port = ipf_random() % (ntohs(np->in_pmax) - 224033f2fefdSDarren Reed ntohs(np->in_pmin) + 1); 2241ab073b32Sdr146992 port += ntohs(np->in_pmin); 2242ab073b32Sdr146992 } 2243ab073b32Sdr146992 port = htons(port); 2244ab073b32Sdr146992 np->in_pnext++; 2245ab25eeb5Syz155240 2246ab25eeb5Syz155240 if (np->in_pnext > ntohs(np->in_pmax)) { 2247ab25eeb5Syz155240 np->in_pnext = ntohs(np->in_pmin); 2248ab25eeb5Syz155240 if (np->in_outmsk != 0xffffffff) 2249ab25eeb5Syz155240 np->in_nip++; 2250ab25eeb5Syz155240 } 2251ab25eeb5Syz155240 } 2252ab25eeb5Syz155240 2253ab25eeb5Syz155240 if (np->in_flags & IPN_IPRANGE) { 2254ab25eeb5Syz155240 if (np->in_nip > ntohl(np->in_outmsk)) 2255ab25eeb5Syz155240 np->in_nip = ntohl(np->in_outip); 2256ab25eeb5Syz155240 } else { 2257ab25eeb5Syz155240 if ((np->in_outmsk != 0xffffffff) && 2258ab25eeb5Syz155240 ((np->in_nip + 1) & ntohl(np->in_outmsk)) > 2259ab25eeb5Syz155240 ntohl(np->in_outip)) 2260ab25eeb5Syz155240 np->in_nip = ntohl(np->in_outip) + 1; 2261ab25eeb5Syz155240 } 2262ab25eeb5Syz155240 2263ab25eeb5Syz155240 if ((port == 0) && (flags & (IPN_TCPUDPICMP|IPN_ICMPQUERY))) 2264ab25eeb5Syz155240 port = sport; 2265ab25eeb5Syz155240 2266ab25eeb5Syz155240 /* 2267ab25eeb5Syz155240 * Here we do a lookup of the connection as seen from 2268ab25eeb5Syz155240 * the outside. If an IP# pair already exists, try 2269ab25eeb5Syz155240 * again. So if you have A->B becomes C->B, you can 2270ab25eeb5Syz155240 * also have D->E become C->E but not D->B causing 2271ab25eeb5Syz155240 * another C->B. Also take protocol and ports into 2272ab25eeb5Syz155240 * account when determining whether a pre-existing 2273ab25eeb5Syz155240 * NAT setup will cause an external conflict where 2274ab25eeb5Syz155240 * this is appropriate. 2275ab25eeb5Syz155240 */ 2276ab25eeb5Syz155240 inb.s_addr = htonl(in.s_addr); 2277ab25eeb5Syz155240 sp = fin->fin_data[0]; 2278ab25eeb5Syz155240 dp = fin->fin_data[1]; 2279ab25eeb5Syz155240 fin->fin_data[0] = fin->fin_data[1]; 2280ab25eeb5Syz155240 fin->fin_data[1] = htons(port); 2281ab25eeb5Syz155240 natl = nat_inlookup(fin, flags & ~(SI_WILDP|NAT_SEARCH), 2282ab25eeb5Syz155240 (u_int)fin->fin_p, fin->fin_dst, inb); 2283ab25eeb5Syz155240 fin->fin_data[0] = sp; 2284ab25eeb5Syz155240 fin->fin_data[1] = dp; 2285ab25eeb5Syz155240 2286ab25eeb5Syz155240 /* 2287ab25eeb5Syz155240 * Has the search wrapped around and come back to the 2288ab25eeb5Syz155240 * start ? 2289ab25eeb5Syz155240 */ 2290ab25eeb5Syz155240 if ((natl != NULL) && 2291ab25eeb5Syz155240 (np->in_pnext != 0) && (st_port == np->in_pnext) && 2292ab25eeb5Syz155240 (np->in_nip != 0) && (st_ip == np->in_nip)) 2293ab25eeb5Syz155240 return -1; 2294ab25eeb5Syz155240 l++; 2295ab25eeb5Syz155240 } while (natl != NULL); 2296ab25eeb5Syz155240 2297ab25eeb5Syz155240 if (np->in_space > 0) 2298ab25eeb5Syz155240 np->in_space--; 2299ab25eeb5Syz155240 2300ab25eeb5Syz155240 /* Setup the NAT table */ 2301ab25eeb5Syz155240 nat->nat_inip = fin->fin_src; 2302ab25eeb5Syz155240 nat->nat_outip.s_addr = htonl(in.s_addr); 2303ab25eeb5Syz155240 nat->nat_oip = fin->fin_dst; 2304ab25eeb5Syz155240 if (nat->nat_hm == NULL) 2305ab25eeb5Syz155240 nat->nat_hm = nat_hostmap(np, fin->fin_src, fin->fin_dst, 2306f4b3ec61Sdh155122 nat->nat_outip, 0, ifs); 2307ab25eeb5Syz155240 2308ab25eeb5Syz155240 if (flags & IPN_TCPUDP) { 2309ab25eeb5Syz155240 nat->nat_inport = sport; 2310ab25eeb5Syz155240 nat->nat_outport = port; /* sport */ 2311ab25eeb5Syz155240 nat->nat_oport = dport; 2312ab25eeb5Syz155240 ((tcphdr_t *)fin->fin_dp)->th_sport = port; 2313ab25eeb5Syz155240 } else if (flags & IPN_ICMPQUERY) { 2314ab25eeb5Syz155240 ((icmphdr_t *)fin->fin_dp)->icmp_id = port; 2315ab25eeb5Syz155240 nat->nat_inport = port; 2316ab25eeb5Syz155240 nat->nat_outport = port; 2317ab25eeb5Syz155240 } 2318ab25eeb5Syz155240 2319ab25eeb5Syz155240 ni->nai_ip.s_addr = in.s_addr; 2320ab25eeb5Syz155240 ni->nai_port = port; 2321ab25eeb5Syz155240 ni->nai_nport = dport; 2322ab25eeb5Syz155240 return 0; 2323ab25eeb5Syz155240 } 2324ab25eeb5Syz155240 2325ab25eeb5Syz155240 2326ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */ 2327ab25eeb5Syz155240 /* Function: nat_newrdr */ 2328ab25eeb5Syz155240 /* Returns: int - -1 == error, 0 == success (no move), 1 == success and */ 2329ab25eeb5Syz155240 /* allow rule to be moved if IPN_ROUNDR is set. */ 2330ab25eeb5Syz155240 /* Parameters: fin(I) - pointer to packet information */ 2331ab25eeb5Syz155240 /* nat(I) - pointer to NAT entry */ 2332ab25eeb5Syz155240 /* ni(I) - pointer to structure with misc. information needed */ 2333ab25eeb5Syz155240 /* to create new NAT entry. */ 2334ab25eeb5Syz155240 /* */ 2335ab25eeb5Syz155240 /* ni.nai_ip is passed in uninitialised and must be set, in host byte order,*/ 2336ab25eeb5Syz155240 /* to the new IP address for the translation. */ 2337ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */ 2338ab25eeb5Syz155240 static INLINE int nat_newrdr(fin, nat, ni) 2339ab25eeb5Syz155240 fr_info_t *fin; 2340ab25eeb5Syz155240 nat_t *nat; 2341ab25eeb5Syz155240 natinfo_t *ni; 2342ab25eeb5Syz155240 { 2343ab25eeb5Syz155240 u_short nport, dport, sport; 23448899fcfaSjojemann struct in_addr in, inb; 23458899fcfaSjojemann u_short sp, dp; 2346ab25eeb5Syz155240 hostmap_t *hm; 2347ab25eeb5Syz155240 u_32_t flags; 2348ab25eeb5Syz155240 ipnat_t *np; 23498899fcfaSjojemann nat_t *natl; 2350ab25eeb5Syz155240 int move; 2351f4b3ec61Sdh155122 ipf_stack_t *ifs = fin->fin_ifs; 2352ab25eeb5Syz155240 2353ab25eeb5Syz155240 move = 1; 2354ab25eeb5Syz155240 hm = NULL; 2355ab25eeb5Syz155240 in.s_addr = 0; 2356ab25eeb5Syz155240 np = ni->nai_np; 2357ab25eeb5Syz155240 flags = ni->nai_flags; 2358ab25eeb5Syz155240 sport = ni->nai_sport; 2359ab25eeb5Syz155240 dport = ni->nai_dport; 2360ab25eeb5Syz155240 2361ab25eeb5Syz155240 /* 2362ab25eeb5Syz155240 * If the matching rule has IPN_STICKY set, then we want to have the 2363ab25eeb5Syz155240 * same rule kick in as before. Why would this happen? If you have 2364ab25eeb5Syz155240 * a collection of rdr rules with "round-robin sticky", the current 2365ab25eeb5Syz155240 * packet might match a different one to the previous connection but 2366ab25eeb5Syz155240 * we want the same destination to be used. 2367ab25eeb5Syz155240 */ 2368ab25eeb5Syz155240 if ((np->in_flags & (IPN_ROUNDR|IPN_STICKY)) == 2369ab25eeb5Syz155240 (IPN_ROUNDR|IPN_STICKY)) { 2370ab25eeb5Syz155240 hm = nat_hostmap(NULL, fin->fin_src, fin->fin_dst, in, 2371f4b3ec61Sdh155122 (u_32_t)dport, ifs); 2372ab25eeb5Syz155240 if (hm != NULL) { 2373ab25eeb5Syz155240 in.s_addr = ntohl(hm->hm_mapip.s_addr); 2374ab25eeb5Syz155240 np = hm->hm_ipnat; 2375ab25eeb5Syz155240 ni->nai_np = np; 2376ab25eeb5Syz155240 move = 0; 2377ab25eeb5Syz155240 } 2378ab25eeb5Syz155240 } 2379ab25eeb5Syz155240 2380ab25eeb5Syz155240 /* 2381ab25eeb5Syz155240 * Otherwise, it's an inbound packet. Most likely, we don't 2382ab25eeb5Syz155240 * want to rewrite source ports and source addresses. Instead, 2383ab25eeb5Syz155240 * we want to rewrite to a fixed internal address and fixed 2384ab25eeb5Syz155240 * internal port. 2385ab25eeb5Syz155240 */ 2386ab25eeb5Syz155240 if (np->in_flags & IPN_SPLIT) { 2387ab25eeb5Syz155240 in.s_addr = np->in_nip; 2388ab25eeb5Syz155240 2389ab25eeb5Syz155240 if ((np->in_flags & (IPN_ROUNDR|IPN_STICKY)) == IPN_STICKY) { 2390ab25eeb5Syz155240 hm = nat_hostmap(np, fin->fin_src, fin->fin_dst, 2391f4b3ec61Sdh155122 in, (u_32_t)dport, ifs); 2392ab25eeb5Syz155240 if (hm != NULL) { 2393ab25eeb5Syz155240 in.s_addr = hm->hm_mapip.s_addr; 2394ab25eeb5Syz155240 move = 0; 2395ab25eeb5Syz155240 } 2396ab25eeb5Syz155240 } 2397ab25eeb5Syz155240 2398ab25eeb5Syz155240 if (hm == NULL || hm->hm_ref == 1) { 2399ab25eeb5Syz155240 if (np->in_inip == htonl(in.s_addr)) { 2400ab25eeb5Syz155240 np->in_nip = ntohl(np->in_inmsk); 2401ab25eeb5Syz155240 move = 0; 2402ab25eeb5Syz155240 } else { 2403ab25eeb5Syz155240 np->in_nip = ntohl(np->in_inip); 2404ab25eeb5Syz155240 } 2405ab25eeb5Syz155240 } 2406ab25eeb5Syz155240 2407ab25eeb5Syz155240 } else if ((np->in_inip == 0) && (np->in_inmsk == 0xffffffff)) { 2408ab25eeb5Syz155240 /* 2409ab25eeb5Syz155240 * 0/32 - use the interface's IP address. 2410ab25eeb5Syz155240 */ 2411f4b3ec61Sdh155122 if (fr_ifpaddr(4, FRI_NORMAL, fin->fin_ifp, &in, NULL, 2412f4b3ec61Sdh155122 fin->fin_ifs) == -1) 2413ab25eeb5Syz155240 return -1; 2414ab25eeb5Syz155240 in.s_addr = ntohl(in.s_addr); 2415ab25eeb5Syz155240 2416ab25eeb5Syz155240 } else if ((np->in_inip == 0) && (np->in_inmsk== 0)) { 2417ab25eeb5Syz155240 /* 2418ab25eeb5Syz155240 * 0/0 - use the original destination address/port. 2419ab25eeb5Syz155240 */ 2420ab25eeb5Syz155240 in.s_addr = ntohl(fin->fin_daddr); 2421ab25eeb5Syz155240 2422ab25eeb5Syz155240 } else if (np->in_redir == NAT_BIMAP && 2423ab25eeb5Syz155240 np->in_inmsk == np->in_outmsk) { 2424ab25eeb5Syz155240 /* 2425ab25eeb5Syz155240 * map the address block in a 1:1 fashion 2426ab25eeb5Syz155240 */ 2427ab25eeb5Syz155240 in.s_addr = np->in_inip; 2428ab25eeb5Syz155240 in.s_addr |= fin->fin_daddr & ~np->in_inmsk; 2429ab25eeb5Syz155240 in.s_addr = ntohl(in.s_addr); 2430ab25eeb5Syz155240 } else { 2431ab25eeb5Syz155240 in.s_addr = ntohl(np->in_inip); 2432ab25eeb5Syz155240 } 2433ab25eeb5Syz155240 2434ab25eeb5Syz155240 if ((np->in_pnext == 0) || ((flags & NAT_NOTRULEPORT) != 0)) 2435ab25eeb5Syz155240 nport = dport; 2436ab25eeb5Syz155240 else { 2437ab25eeb5Syz155240 /* 2438ab25eeb5Syz155240 * Whilst not optimized for the case where 2439ab25eeb5Syz155240 * pmin == pmax, the gain is not significant. 2440ab25eeb5Syz155240 */ 2441ab25eeb5Syz155240 if (((np->in_flags & IPN_FIXEDDPORT) == 0) && 2442ab25eeb5Syz155240 (np->in_pmin != np->in_pmax)) { 2443ab25eeb5Syz155240 nport = ntohs(dport) - ntohs(np->in_pmin) + 2444ab25eeb5Syz155240 ntohs(np->in_pnext); 2445ab25eeb5Syz155240 nport = htons(nport); 2446ab25eeb5Syz155240 } else 2447ab25eeb5Syz155240 nport = np->in_pnext; 2448ab25eeb5Syz155240 } 2449ab25eeb5Syz155240 2450ab25eeb5Syz155240 /* 2451ab25eeb5Syz155240 * When the redirect-to address is set to 0.0.0.0, just 2452ab25eeb5Syz155240 * assume a blank `forwarding' of the packet. We don't 2453ab25eeb5Syz155240 * setup any translation for this either. 2454ab25eeb5Syz155240 */ 2455ab25eeb5Syz155240 if (in.s_addr == 0) { 2456ab25eeb5Syz155240 if (nport == dport) 2457ab25eeb5Syz155240 return -1; 2458ab25eeb5Syz155240 in.s_addr = ntohl(fin->fin_daddr); 2459ab25eeb5Syz155240 } 2460ab25eeb5Syz155240 24618899fcfaSjojemann /* 24628899fcfaSjojemann * Check to see if this redirect mapping already exists and if 24638899fcfaSjojemann * it does, return "failure" (allowing it to be created will just 24648899fcfaSjojemann * cause one or both of these "connections" to stop working.) 24658899fcfaSjojemann */ 24668899fcfaSjojemann inb.s_addr = htonl(in.s_addr); 24678899fcfaSjojemann sp = fin->fin_data[0]; 24688899fcfaSjojemann dp = fin->fin_data[1]; 24698899fcfaSjojemann fin->fin_data[1] = fin->fin_data[0]; 24708899fcfaSjojemann fin->fin_data[0] = ntohs(nport); 24718899fcfaSjojemann natl = nat_outlookup(fin, flags & ~(SI_WILDP|NAT_SEARCH), 24728899fcfaSjojemann (u_int)fin->fin_p, inb, fin->fin_src); 24738899fcfaSjojemann fin->fin_data[0] = sp; 24748899fcfaSjojemann fin->fin_data[1] = dp; 24758899fcfaSjojemann if (natl != NULL) 24768899fcfaSjojemann return (-1); 24778899fcfaSjojemann 2478ab25eeb5Syz155240 nat->nat_inip.s_addr = htonl(in.s_addr); 2479ab25eeb5Syz155240 nat->nat_outip = fin->fin_dst; 2480ab25eeb5Syz155240 nat->nat_oip = fin->fin_src; 2481ab25eeb5Syz155240 2482ab25eeb5Syz155240 ni->nai_ip.s_addr = in.s_addr; 2483ab25eeb5Syz155240 ni->nai_nport = nport; 2484ab25eeb5Syz155240 ni->nai_port = sport; 2485ab25eeb5Syz155240 2486ab25eeb5Syz155240 if (flags & IPN_TCPUDP) { 2487ab25eeb5Syz155240 nat->nat_inport = nport; 2488ab25eeb5Syz155240 nat->nat_outport = dport; 2489ab25eeb5Syz155240 nat->nat_oport = sport; 2490ab25eeb5Syz155240 ((tcphdr_t *)fin->fin_dp)->th_dport = nport; 2491ab25eeb5Syz155240 } else if (flags & IPN_ICMPQUERY) { 2492ab25eeb5Syz155240 ((icmphdr_t *)fin->fin_dp)->icmp_id = nport; 2493ab25eeb5Syz155240 nat->nat_inport = nport; 2494ab25eeb5Syz155240 nat->nat_outport = nport; 2495ab25eeb5Syz155240 } 2496ab25eeb5Syz155240 2497ab25eeb5Syz155240 return move; 2498ab25eeb5Syz155240 } 2499ab25eeb5Syz155240 2500ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */ 2501ab25eeb5Syz155240 /* Function: nat_new */ 2502ab25eeb5Syz155240 /* Returns: nat_t* - NULL == failure to create new NAT structure, */ 2503ab25eeb5Syz155240 /* else pointer to new NAT structure */ 2504ab25eeb5Syz155240 /* Parameters: fin(I) - pointer to packet information */ 2505ab25eeb5Syz155240 /* np(I) - pointer to NAT rule */ 2506ab25eeb5Syz155240 /* natsave(I) - pointer to where to store NAT struct pointer */ 2507ab25eeb5Syz155240 /* flags(I) - flags describing the current packet */ 2508ab25eeb5Syz155240 /* direction(I) - direction of packet (in/out) */ 2509ab25eeb5Syz155240 /* Write Lock: ipf_nat */ 2510ab25eeb5Syz155240 /* */ 2511ab25eeb5Syz155240 /* Attempts to create a new NAT entry. Does not actually change the packet */ 2512ab25eeb5Syz155240 /* in any way. */ 2513ab25eeb5Syz155240 /* */ 2514ab25eeb5Syz155240 /* This fucntion is in three main parts: (1) deal with creating a new NAT */ 2515ab25eeb5Syz155240 /* structure for a "MAP" rule (outgoing NAT translation); (2) deal with */ 2516ab25eeb5Syz155240 /* creating a new NAT structure for a "RDR" rule (incoming NAT translation) */ 2517ab25eeb5Syz155240 /* and (3) building that structure and putting it into the NAT table(s). */ 2518ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */ 2519ab25eeb5Syz155240 nat_t *nat_new(fin, np, natsave, flags, direction) 2520ab25eeb5Syz155240 fr_info_t *fin; 2521ab25eeb5Syz155240 ipnat_t *np; 2522ab25eeb5Syz155240 nat_t **natsave; 2523ab25eeb5Syz155240 u_int flags; 2524ab25eeb5Syz155240 int direction; 2525ab25eeb5Syz155240 { 2526ab25eeb5Syz155240 tcphdr_t *tcp = NULL; 2527ab25eeb5Syz155240 hostmap_t *hm = NULL; 2528ab25eeb5Syz155240 nat_t *nat, *natl; 2529ab25eeb5Syz155240 u_int nflags; 2530ab25eeb5Syz155240 natinfo_t ni; 2531ab25eeb5Syz155240 int move; 2532f4b3ec61Sdh155122 ipf_stack_t *ifs = fin->fin_ifs; 2533ab25eeb5Syz155240 25343805c50fSan207044 /* 2535ea8244dcSJohn Ojemann * Trigger automatic call to nat_flushtable() if the 25363805c50fSan207044 * table has reached capcity specified by hi watermark. 25373805c50fSan207044 */ 2538ea8244dcSJohn Ojemann if (NAT_TAB_WATER_LEVEL(ifs) > ifs->ifs_nat_flush_level_hi) 25393805c50fSan207044 ifs->ifs_nat_doflush = 1; 25403805c50fSan207044 25415b48165cSJohn Ojemann /* 25425b48165cSJohn Ojemann * If automatic flushing did not do its job, and the table 25435b48165cSJohn Ojemann * has filled up, don't try to create a new entry. 25445b48165cSJohn Ojemann */ 2545f4b3ec61Sdh155122 if (ifs->ifs_nat_stats.ns_inuse >= ifs->ifs_ipf_nattable_max) { 2546f4b3ec61Sdh155122 ifs->ifs_nat_stats.ns_memfail++; 2547ab25eeb5Syz155240 return NULL; 2548ab25eeb5Syz155240 } 2549ab25eeb5Syz155240 2550ab25eeb5Syz155240 move = 1; 2551ab25eeb5Syz155240 nflags = np->in_flags & flags; 2552ab25eeb5Syz155240 nflags &= NAT_FROMRULE; 2553ab25eeb5Syz155240 2554ab25eeb5Syz155240 ni.nai_np = np; 2555ab25eeb5Syz155240 ni.nai_nflags = nflags; 2556ab25eeb5Syz155240 ni.nai_flags = flags; 2557ab25eeb5Syz155240 2558ab25eeb5Syz155240 /* Give me a new nat */ 2559ab25eeb5Syz155240 KMALLOC(nat, nat_t *); 2560ab25eeb5Syz155240 if (nat == NULL) { 2561f4b3ec61Sdh155122 ifs->ifs_nat_stats.ns_memfail++; 2562ab25eeb5Syz155240 /* 2563ab25eeb5Syz155240 * Try to automatically tune the max # of entries in the 2564ab25eeb5Syz155240 * table allowed to be less than what will cause kmem_alloc() 2565ab25eeb5Syz155240 * to fail and try to eliminate panics due to out of memory 2566ab25eeb5Syz155240 * conditions arising. 2567ab25eeb5Syz155240 */ 2568f4b3ec61Sdh155122 if (ifs->ifs_ipf_nattable_max > ifs->ifs_ipf_nattable_sz) { 2569f4b3ec61Sdh155122 ifs->ifs_ipf_nattable_max = ifs->ifs_nat_stats.ns_inuse - 100; 2570ab25eeb5Syz155240 printf("ipf_nattable_max reduced to %d\n", 2571f4b3ec61Sdh155122 ifs->ifs_ipf_nattable_max); 2572ab25eeb5Syz155240 } 2573ab25eeb5Syz155240 return NULL; 2574ab25eeb5Syz155240 } 2575ab25eeb5Syz155240 2576ab25eeb5Syz155240 if (flags & IPN_TCPUDP) { 2577ab25eeb5Syz155240 tcp = fin->fin_dp; 2578ab25eeb5Syz155240 ni.nai_sport = htons(fin->fin_sport); 2579ab25eeb5Syz155240 ni.nai_dport = htons(fin->fin_dport); 2580ab25eeb5Syz155240 } else if (flags & IPN_ICMPQUERY) { 2581ab25eeb5Syz155240 /* 2582ab25eeb5Syz155240 * In the ICMP query NAT code, we translate the ICMP id fields 2583ab25eeb5Syz155240 * to make them unique. This is indepedent of the ICMP type 2584ab25eeb5Syz155240 * (e.g. in the unlikely event that a host sends an echo and 2585ab25eeb5Syz155240 * an tstamp request with the same id, both packets will have 2586ab25eeb5Syz155240 * their ip address/id field changed in the same way). 2587ab25eeb5Syz155240 */ 2588ab25eeb5Syz155240 /* The icmp_id field is used by the sender to identify the 2589ab25eeb5Syz155240 * process making the icmp request. (the receiver justs 2590ab25eeb5Syz155240 * copies it back in its response). So, it closely matches 2591ab25eeb5Syz155240 * the concept of source port. We overlay sport, so we can 2592ab25eeb5Syz155240 * maximally reuse the existing code. 2593ab25eeb5Syz155240 */ 2594ab25eeb5Syz155240 ni.nai_sport = ((icmphdr_t *)fin->fin_dp)->icmp_id; 2595ab25eeb5Syz155240 ni.nai_dport = ni.nai_sport; 2596ab25eeb5Syz155240 } 2597ab25eeb5Syz155240 2598ab25eeb5Syz155240 bzero((char *)nat, sizeof(*nat)); 2599ab25eeb5Syz155240 nat->nat_flags = flags; 2600f4b3ec61Sdh155122 nat->nat_redir = np->in_redir; 2601ab25eeb5Syz155240 2602ab25eeb5Syz155240 if ((flags & NAT_SLAVE) == 0) { 2603f4b3ec61Sdh155122 MUTEX_ENTER(&ifs->ifs_ipf_nat_new); 2604ab25eeb5Syz155240 } 2605ab25eeb5Syz155240 2606ab25eeb5Syz155240 /* 2607ab25eeb5Syz155240 * Search the current table for a match. 2608ab25eeb5Syz155240 */ 2609ab25eeb5Syz155240 if (direction == NAT_OUTBOUND) { 2610ab25eeb5Syz155240 /* 2611ab25eeb5Syz155240 * We can now arrange to call this for the same connection 2612ab25eeb5Syz155240 * because ipf_nat_new doesn't protect the code path into 2613ab25eeb5Syz155240 * this function. 2614ab25eeb5Syz155240 */ 2615ab25eeb5Syz155240 natl = nat_outlookup(fin, nflags, (u_int)fin->fin_p, 2616ab25eeb5Syz155240 fin->fin_src, fin->fin_dst); 2617ab25eeb5Syz155240 if (natl != NULL) { 2618dcf3e898Sjojemann KFREE(nat); 2619ab25eeb5Syz155240 nat = natl; 2620ab25eeb5Syz155240 goto done; 2621ab25eeb5Syz155240 } 2622ab25eeb5Syz155240 2623ab25eeb5Syz155240 move = nat_newmap(fin, nat, &ni); 2624ab25eeb5Syz155240 if (move == -1) 2625ab25eeb5Syz155240 goto badnat; 2626ab25eeb5Syz155240 2627ab25eeb5Syz155240 np = ni.nai_np; 2628ab25eeb5Syz155240 } else { 2629ab25eeb5Syz155240 /* 2630ab25eeb5Syz155240 * NAT_INBOUND is used only for redirects rules 2631ab25eeb5Syz155240 */ 2632ab25eeb5Syz155240 natl = nat_inlookup(fin, nflags, (u_int)fin->fin_p, 2633ab25eeb5Syz155240 fin->fin_src, fin->fin_dst); 2634ab25eeb5Syz155240 if (natl != NULL) { 2635dcf3e898Sjojemann KFREE(nat); 2636ab25eeb5Syz155240 nat = natl; 2637ab25eeb5Syz155240 goto done; 2638ab25eeb5Syz155240 } 2639ab25eeb5Syz155240 2640ab25eeb5Syz155240 move = nat_newrdr(fin, nat, &ni); 2641ab25eeb5Syz155240 if (move == -1) 2642ab25eeb5Syz155240 goto badnat; 2643ab25eeb5Syz155240 2644ab25eeb5Syz155240 np = ni.nai_np; 2645ab25eeb5Syz155240 } 2646ab25eeb5Syz155240 2647ab25eeb5Syz155240 if ((move == 1) && (np->in_flags & IPN_ROUNDR)) { 2648ab25eeb5Syz155240 if (np->in_redir == NAT_REDIRECT) { 2649ab25eeb5Syz155240 nat_delrdr(np); 2650f4b3ec61Sdh155122 nat_addrdr(np, ifs); 2651ab25eeb5Syz155240 } else if (np->in_redir == NAT_MAP) { 2652ab25eeb5Syz155240 nat_delnat(np); 2653f4b3ec61Sdh155122 nat_addnat(np, ifs); 2654ab25eeb5Syz155240 } 2655ab25eeb5Syz155240 } 2656ab25eeb5Syz155240 2657ab25eeb5Syz155240 if (nat_finalise(fin, nat, &ni, tcp, natsave, direction) == -1) { 2658ab25eeb5Syz155240 goto badnat; 2659ab25eeb5Syz155240 } 26603c50f6d6San207044 26613c50f6d6San207044 nat_calc_chksum_diffs(nat); 26623c50f6d6San207044 2663ab25eeb5Syz155240 if (flags & SI_WILDP) 2664f4b3ec61Sdh155122 ifs->ifs_nat_stats.ns_wilds++; 26655b48165cSJohn Ojemann fin->fin_flx |= FI_NEWNAT; 2666ab25eeb5Syz155240 goto done; 2667ab25eeb5Syz155240 badnat: 2668f4b3ec61Sdh155122 ifs->ifs_nat_stats.ns_badnat++; 2669ab25eeb5Syz155240 if ((hm = nat->nat_hm) != NULL) 267090b0a856Sjojemann fr_hostmapdel(&hm); 2671ab25eeb5Syz155240 KFREE(nat); 2672ab25eeb5Syz155240 nat = NULL; 2673ab25eeb5Syz155240 done: 2674ab25eeb5Syz155240 if ((flags & NAT_SLAVE) == 0) { 2675f4b3ec61Sdh155122 MUTEX_EXIT(&ifs->ifs_ipf_nat_new); 2676ab25eeb5Syz155240 } 2677ab25eeb5Syz155240 return nat; 2678ab25eeb5Syz155240 } 2679ab25eeb5Syz155240 2680ab25eeb5Syz155240 2681ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */ 2682ab25eeb5Syz155240 /* Function: nat_finalise */ 2683ab25eeb5Syz155240 /* Returns: int - 0 == sucess, -1 == failure */ 2684ab25eeb5Syz155240 /* Parameters: fin(I) - pointer to packet information */ 2685ab25eeb5Syz155240 /* nat(I) - pointer to NAT entry */ 2686ab25eeb5Syz155240 /* ni(I) - pointer to structure with misc. information needed */ 2687ab25eeb5Syz155240 /* to create new NAT entry. */ 2688ab25eeb5Syz155240 /* Write Lock: ipf_nat */ 2689ab25eeb5Syz155240 /* */ 2690ab25eeb5Syz155240 /* This is the tail end of constructing a new NAT entry and is the same */ 2691ab25eeb5Syz155240 /* for both IPv4 and IPv6. */ 2692ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */ 2693ab25eeb5Syz155240 /*ARGSUSED*/ 2694ab25eeb5Syz155240 static INLINE int nat_finalise(fin, nat, ni, tcp, natsave, direction) 2695ab25eeb5Syz155240 fr_info_t *fin; 2696ab25eeb5Syz155240 nat_t *nat; 2697ab25eeb5Syz155240 natinfo_t *ni; 2698ab25eeb5Syz155240 tcphdr_t *tcp; 2699ab25eeb5Syz155240 nat_t **natsave; 2700ab25eeb5Syz155240 int direction; 2701ab25eeb5Syz155240 { 2702ab25eeb5Syz155240 frentry_t *fr; 2703ab25eeb5Syz155240 ipnat_t *np; 2704f4b3ec61Sdh155122 ipf_stack_t *ifs = fin->fin_ifs; 2705ab25eeb5Syz155240 2706ab25eeb5Syz155240 np = ni->nai_np; 2707ab25eeb5Syz155240 2708381a2a9aSdr146992 COPYIFNAME(fin->fin_ifp, nat->nat_ifnames[0], fin->fin_v); 2709381a2a9aSdr146992 2710ab25eeb5Syz155240 #ifdef IPFILTER_SYNC 2711ab25eeb5Syz155240 if ((nat->nat_flags & SI_CLONE) == 0) 2712ab25eeb5Syz155240 nat->nat_sync = ipfsync_new(SMC_NAT, fin, nat); 2713ab25eeb5Syz155240 #endif 2714ab25eeb5Syz155240 2715ab25eeb5Syz155240 nat->nat_me = natsave; 2716ab25eeb5Syz155240 nat->nat_dir = direction; 2717e6c6c1faSyz155240 nat->nat_ifps[0] = np->in_ifps[0]; 2718e6c6c1faSyz155240 nat->nat_ifps[1] = np->in_ifps[1]; 2719ab25eeb5Syz155240 nat->nat_ptr = np; 2720ab25eeb5Syz155240 nat->nat_p = fin->fin_p; 2721d6c23f6fSyx160601 nat->nat_v = fin->fin_v; 2722ab25eeb5Syz155240 nat->nat_mssclamp = np->in_mssclamp; 2723ab25eeb5Syz155240 fr = fin->fin_fr; 2724ab25eeb5Syz155240 nat->nat_fr = fr; 2725ab25eeb5Syz155240 2726ab25eeb5Syz155240 if ((np->in_apr != NULL) && ((ni->nai_flags & NAT_SLAVE) == 0)) 2727ab25eeb5Syz155240 if (appr_new(fin, nat) == -1) 2728ab25eeb5Syz155240 return -1; 2729ab25eeb5Syz155240 2730f4b3ec61Sdh155122 if (nat_insert(nat, fin->fin_rev, ifs) == 0) { 2731f4b3ec61Sdh155122 if (ifs->ifs_nat_logging) 2732f4b3ec61Sdh155122 nat_log(nat, (u_int)np->in_redir, ifs); 2733ab25eeb5Syz155240 np->in_use++; 2734ab25eeb5Syz155240 if (fr != NULL) { 2735ab25eeb5Syz155240 MUTEX_ENTER(&fr->fr_lock); 2736ab25eeb5Syz155240 fr->fr_ref++; 2737ab25eeb5Syz155240 MUTEX_EXIT(&fr->fr_lock); 2738ab25eeb5Syz155240 } 2739ab25eeb5Syz155240 return 0; 2740ab25eeb5Syz155240 } 2741ab25eeb5Syz155240 2742ab25eeb5Syz155240 /* 2743ab25eeb5Syz155240 * nat_insert failed, so cleanup time... 2744ab25eeb5Syz155240 */ 2745ab25eeb5Syz155240 return -1; 2746ab25eeb5Syz155240 } 2747ab25eeb5Syz155240 2748ab25eeb5Syz155240 2749ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */ 2750ab25eeb5Syz155240 /* Function: nat_insert */ 2751ab25eeb5Syz155240 /* Returns: int - 0 == sucess, -1 == failure */ 2752ab25eeb5Syz155240 /* Parameters: nat(I) - pointer to NAT structure */ 2753ab25eeb5Syz155240 /* rev(I) - flag indicating forward/reverse direction of packet */ 2754ab25eeb5Syz155240 /* Write Lock: ipf_nat */ 2755ab25eeb5Syz155240 /* */ 2756ab25eeb5Syz155240 /* Insert a NAT entry into the hash tables for searching and add it to the */ 2757ab25eeb5Syz155240 /* list of active NAT entries. Adjust global counters when complete. */ 2758ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */ 2759f4b3ec61Sdh155122 int nat_insert(nat, rev, ifs) 2760ab25eeb5Syz155240 nat_t *nat; 2761ab25eeb5Syz155240 int rev; 2762f4b3ec61Sdh155122 ipf_stack_t *ifs; 2763ab25eeb5Syz155240 { 2764ab25eeb5Syz155240 u_int hv1, hv2; 2765ab25eeb5Syz155240 nat_t **natp; 2766ab25eeb5Syz155240 2767ab25eeb5Syz155240 /* 2768ab25eeb5Syz155240 * Try and return an error as early as possible, so calculate the hash 2769ab25eeb5Syz155240 * entry numbers first and then proceed. 2770ab25eeb5Syz155240 */ 2771ab25eeb5Syz155240 if ((nat->nat_flags & (SI_W_SPORT|SI_W_DPORT)) == 0) { 2772ab25eeb5Syz155240 hv1 = NAT_HASH_FN(nat->nat_inip.s_addr, nat->nat_inport, 2773ab25eeb5Syz155240 0xffffffff); 2774ab25eeb5Syz155240 hv1 = NAT_HASH_FN(nat->nat_oip.s_addr, hv1 + nat->nat_oport, 2775f4b3ec61Sdh155122 ifs->ifs_ipf_nattable_sz); 2776ab25eeb5Syz155240 hv2 = NAT_HASH_FN(nat->nat_outip.s_addr, nat->nat_outport, 2777ab25eeb5Syz155240 0xffffffff); 2778ab25eeb5Syz155240 hv2 = NAT_HASH_FN(nat->nat_oip.s_addr, hv2 + nat->nat_oport, 2779f4b3ec61Sdh155122 ifs->ifs_ipf_nattable_sz); 2780ab25eeb5Syz155240 } else { 2781ab25eeb5Syz155240 hv1 = NAT_HASH_FN(nat->nat_inip.s_addr, 0, 0xffffffff); 2782f4b3ec61Sdh155122 hv1 = NAT_HASH_FN(nat->nat_oip.s_addr, hv1, 2783f4b3ec61Sdh155122 ifs->ifs_ipf_nattable_sz); 2784ab25eeb5Syz155240 hv2 = NAT_HASH_FN(nat->nat_outip.s_addr, 0, 0xffffffff); 2785f4b3ec61Sdh155122 hv2 = NAT_HASH_FN(nat->nat_oip.s_addr, hv2, 2786f4b3ec61Sdh155122 ifs->ifs_ipf_nattable_sz); 2787ab25eeb5Syz155240 } 2788ab25eeb5Syz155240 2789f4b3ec61Sdh155122 if (ifs->ifs_nat_stats.ns_bucketlen[0][hv1] >= ifs->ifs_fr_nat_maxbucket || 2790f4b3ec61Sdh155122 ifs->ifs_nat_stats.ns_bucketlen[1][hv2] >= ifs->ifs_fr_nat_maxbucket) { 2791ab25eeb5Syz155240 return -1; 2792ab25eeb5Syz155240 } 2793ab25eeb5Syz155240 2794ab25eeb5Syz155240 nat->nat_hv[0] = hv1; 2795ab25eeb5Syz155240 nat->nat_hv[1] = hv2; 2796ab25eeb5Syz155240 2797ab25eeb5Syz155240 MUTEX_INIT(&nat->nat_lock, "nat entry lock"); 2798ab25eeb5Syz155240 2799ab25eeb5Syz155240 nat->nat_rev = rev; 2800ab25eeb5Syz155240 nat->nat_ref = 1; 2801ab25eeb5Syz155240 nat->nat_bytes[0] = 0; 2802ab25eeb5Syz155240 nat->nat_pkts[0] = 0; 2803ab25eeb5Syz155240 nat->nat_bytes[1] = 0; 2804ab25eeb5Syz155240 nat->nat_pkts[1] = 0; 2805ab25eeb5Syz155240 2806ab25eeb5Syz155240 nat->nat_ifnames[0][LIFNAMSIZ - 1] = '\0'; 2807f4b3ec61Sdh155122 nat->nat_ifps[0] = fr_resolvenic(nat->nat_ifnames[0], 4, ifs); 2808ab25eeb5Syz155240 2809ab25eeb5Syz155240 if (nat->nat_ifnames[1][0] !='\0') { 2810ab25eeb5Syz155240 nat->nat_ifnames[1][LIFNAMSIZ - 1] = '\0'; 2811f4b3ec61Sdh155122 nat->nat_ifps[1] = fr_resolvenic(nat->nat_ifnames[1], 4, ifs); 2812ab25eeb5Syz155240 } else { 2813ab25eeb5Syz155240 (void) strncpy(nat->nat_ifnames[1], nat->nat_ifnames[0], 2814ab25eeb5Syz155240 LIFNAMSIZ); 2815ab25eeb5Syz155240 nat->nat_ifnames[1][LIFNAMSIZ - 1] = '\0'; 2816ab25eeb5Syz155240 nat->nat_ifps[1] = nat->nat_ifps[0]; 2817ab25eeb5Syz155240 } 2818ab25eeb5Syz155240 2819f4b3ec61Sdh155122 nat->nat_next = ifs->ifs_nat_instances; 2820f4b3ec61Sdh155122 nat->nat_pnext = &ifs->ifs_nat_instances; 2821f4b3ec61Sdh155122 if (ifs->ifs_nat_instances) 2822f4b3ec61Sdh155122 ifs->ifs_nat_instances->nat_pnext = &nat->nat_next; 2823f4b3ec61Sdh155122 ifs->ifs_nat_instances = nat; 2824ab25eeb5Syz155240 2825f4b3ec61Sdh155122 natp = &ifs->ifs_nat_table[0][hv1]; 2826ab25eeb5Syz155240 if (*natp) 2827ab25eeb5Syz155240 (*natp)->nat_phnext[0] = &nat->nat_hnext[0]; 2828ab25eeb5Syz155240 nat->nat_phnext[0] = natp; 2829ab25eeb5Syz155240 nat->nat_hnext[0] = *natp; 2830ab25eeb5Syz155240 *natp = nat; 2831f4b3ec61Sdh155122 ifs->ifs_nat_stats.ns_bucketlen[0][hv1]++; 2832ab25eeb5Syz155240 2833f4b3ec61Sdh155122 natp = &ifs->ifs_nat_table[1][hv2]; 2834ab25eeb5Syz155240 if (*natp) 2835ab25eeb5Syz155240 (*natp)->nat_phnext[1] = &nat->nat_hnext[1]; 2836ab25eeb5Syz155240 nat->nat_phnext[1] = natp; 2837ab25eeb5Syz155240 nat->nat_hnext[1] = *natp; 2838ab25eeb5Syz155240 *natp = nat; 2839f4b3ec61Sdh155122 ifs->ifs_nat_stats.ns_bucketlen[1][hv2]++; 2840ab25eeb5Syz155240 2841f4b3ec61Sdh155122 fr_setnatqueue(nat, rev, ifs); 2842ab25eeb5Syz155240 2843f4b3ec61Sdh155122 ifs->ifs_nat_stats.ns_added++; 2844f4b3ec61Sdh155122 ifs->ifs_nat_stats.ns_inuse++; 2845ab25eeb5Syz155240 return 0; 2846ab25eeb5Syz155240 } 2847ab25eeb5Syz155240 2848ab25eeb5Syz155240 2849ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */ 2850ab25eeb5Syz155240 /* Function: nat_icmperrorlookup */ 2851ab25eeb5Syz155240 /* Returns: nat_t* - point to matching NAT structure */ 2852ab25eeb5Syz155240 /* Parameters: fin(I) - pointer to packet information */ 2853ab25eeb5Syz155240 /* dir(I) - direction of packet (in/out) */ 2854ab25eeb5Syz155240 /* */ 2855ab25eeb5Syz155240 /* Check if the ICMP error message is related to an existing TCP, UDP or */ 2856ab25eeb5Syz155240 /* ICMP query nat entry. It is assumed that the packet is already of the */ 2857ab25eeb5Syz155240 /* the required length. */ 2858ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */ 2859ab25eeb5Syz155240 nat_t *nat_icmperrorlookup(fin, dir) 2860ab25eeb5Syz155240 fr_info_t *fin; 2861ab25eeb5Syz155240 int dir; 2862ab25eeb5Syz155240 { 2863ab25eeb5Syz155240 int flags = 0, minlen; 2864ab25eeb5Syz155240 icmphdr_t *orgicmp; 2865ab25eeb5Syz155240 tcphdr_t *tcp = NULL; 2866ab25eeb5Syz155240 u_short data[2]; 2867ab25eeb5Syz155240 nat_t *nat; 2868ab25eeb5Syz155240 ip_t *oip; 2869ab25eeb5Syz155240 u_int p; 2870ab25eeb5Syz155240 2871ab25eeb5Syz155240 /* 2872ab25eeb5Syz155240 * Does it at least have the return (basic) IP header ? 2873ab25eeb5Syz155240 * Only a basic IP header (no options) should be with an ICMP error 2874ab25eeb5Syz155240 * header. Also, if it's not an error type, then return. 2875ab25eeb5Syz155240 */ 2876ab25eeb5Syz155240 if ((fin->fin_hlen != sizeof(ip_t)) || !(fin->fin_flx & FI_ICMPERR)) 2877ab25eeb5Syz155240 return NULL; 2878ab25eeb5Syz155240 2879ab25eeb5Syz155240 /* 2880ab25eeb5Syz155240 * Check packet size 2881ab25eeb5Syz155240 */ 2882ab25eeb5Syz155240 oip = (ip_t *)((char *)fin->fin_dp + 8); 2883ab25eeb5Syz155240 minlen = IP_HL(oip) << 2; 2884ab25eeb5Syz155240 if ((minlen < sizeof(ip_t)) || 2885ab25eeb5Syz155240 (fin->fin_plen < ICMPERR_IPICMPHLEN + minlen)) 2886ab25eeb5Syz155240 return NULL; 2887ab25eeb5Syz155240 /* 2888ab25eeb5Syz155240 * Is the buffer big enough for all of it ? It's the size of the IP 2889ab25eeb5Syz155240 * header claimed in the encapsulated part which is of concern. It 2890ab25eeb5Syz155240 * may be too big to be in this buffer but not so big that it's 2891ab25eeb5Syz155240 * outside the ICMP packet, leading to TCP deref's causing problems. 2892ab25eeb5Syz155240 * This is possible because we don't know how big oip_hl is when we 2893ab25eeb5Syz155240 * do the pullup early in fr_check() and thus can't gaurantee it is 2894ab25eeb5Syz155240 * all here now. 2895ab25eeb5Syz155240 */ 2896ab25eeb5Syz155240 #ifdef _KERNEL 2897ab25eeb5Syz155240 { 2898ab25eeb5Syz155240 mb_t *m; 2899ab25eeb5Syz155240 2900ab25eeb5Syz155240 m = fin->fin_m; 2901ab25eeb5Syz155240 # if defined(MENTAT) 2902ab25eeb5Syz155240 if ((char *)oip + fin->fin_dlen - ICMPERR_ICMPHLEN > (char *)m->b_wptr) 2903ab25eeb5Syz155240 return NULL; 2904ab25eeb5Syz155240 # else 2905ab25eeb5Syz155240 if ((char *)oip + fin->fin_dlen - ICMPERR_ICMPHLEN > 2906ab25eeb5Syz155240 (char *)fin->fin_ip + M_LEN(m)) 2907ab25eeb5Syz155240 return NULL; 2908ab25eeb5Syz155240 # endif 2909ab25eeb5Syz155240 } 2910ab25eeb5Syz155240 #endif 2911ab25eeb5Syz155240 2912ab25eeb5Syz155240 if (fin->fin_daddr != oip->ip_src.s_addr) 2913ab25eeb5Syz155240 return NULL; 2914ab25eeb5Syz155240 2915ab25eeb5Syz155240 p = oip->ip_p; 2916ab25eeb5Syz155240 if (p == IPPROTO_TCP) 2917ab25eeb5Syz155240 flags = IPN_TCP; 2918ab25eeb5Syz155240 else if (p == IPPROTO_UDP) 2919ab25eeb5Syz155240 flags = IPN_UDP; 2920ab25eeb5Syz155240 else if (p == IPPROTO_ICMP) { 2921ab25eeb5Syz155240 orgicmp = (icmphdr_t *)((char *)oip + (IP_HL(oip) << 2)); 2922ab25eeb5Syz155240 2923ab25eeb5Syz155240 /* see if this is related to an ICMP query */ 2924ab25eeb5Syz155240 if (nat_icmpquerytype4(orgicmp->icmp_type)) { 2925ab25eeb5Syz155240 data[0] = fin->fin_data[0]; 2926ab25eeb5Syz155240 data[1] = fin->fin_data[1]; 2927ab25eeb5Syz155240 fin->fin_data[0] = 0; 2928ab25eeb5Syz155240 fin->fin_data[1] = orgicmp->icmp_id; 2929ab25eeb5Syz155240 2930ab25eeb5Syz155240 flags = IPN_ICMPERR|IPN_ICMPQUERY; 2931ab25eeb5Syz155240 /* 2932ab25eeb5Syz155240 * NOTE : dir refers to the direction of the original 2933ab25eeb5Syz155240 * ip packet. By definition the icmp error 2934ab25eeb5Syz155240 * message flows in the opposite direction. 2935ab25eeb5Syz155240 */ 2936ab25eeb5Syz155240 if (dir == NAT_INBOUND) 2937ab25eeb5Syz155240 nat = nat_inlookup(fin, flags, p, oip->ip_dst, 2938ab25eeb5Syz155240 oip->ip_src); 2939ab25eeb5Syz155240 else 2940ab25eeb5Syz155240 nat = nat_outlookup(fin, flags, p, oip->ip_dst, 2941ab25eeb5Syz155240 oip->ip_src); 2942ab25eeb5Syz155240 fin->fin_data[0] = data[0]; 2943ab25eeb5Syz155240 fin->fin_data[1] = data[1]; 2944ab25eeb5Syz155240 return nat; 2945ab25eeb5Syz155240 } 2946ab25eeb5Syz155240 } 2947ab25eeb5Syz155240 2948ab25eeb5Syz155240 if (flags & IPN_TCPUDP) { 2949ab25eeb5Syz155240 minlen += 8; /* + 64bits of data to get ports */ 2950ab25eeb5Syz155240 if (fin->fin_plen < ICMPERR_IPICMPHLEN + minlen) 2951ab25eeb5Syz155240 return NULL; 2952ab25eeb5Syz155240 2953ab25eeb5Syz155240 data[0] = fin->fin_data[0]; 2954ab25eeb5Syz155240 data[1] = fin->fin_data[1]; 2955ab25eeb5Syz155240 tcp = (tcphdr_t *)((char *)oip + (IP_HL(oip) << 2)); 2956ab25eeb5Syz155240 fin->fin_data[0] = ntohs(tcp->th_dport); 2957ab25eeb5Syz155240 fin->fin_data[1] = ntohs(tcp->th_sport); 2958ab25eeb5Syz155240 2959ab25eeb5Syz155240 if (dir == NAT_INBOUND) { 2960ab25eeb5Syz155240 nat = nat_inlookup(fin, flags, p, oip->ip_dst, 2961ab25eeb5Syz155240 oip->ip_src); 2962ab25eeb5Syz155240 } else { 2963ab25eeb5Syz155240 nat = nat_outlookup(fin, flags, p, oip->ip_dst, 2964ab25eeb5Syz155240 oip->ip_src); 2965ab25eeb5Syz155240 } 2966ab25eeb5Syz155240 fin->fin_data[0] = data[0]; 2967ab25eeb5Syz155240 fin->fin_data[1] = data[1]; 2968ab25eeb5Syz155240 return nat; 2969ab25eeb5Syz155240 } 2970ab25eeb5Syz155240 if (dir == NAT_INBOUND) 2971ab25eeb5Syz155240 return nat_inlookup(fin, 0, p, oip->ip_dst, oip->ip_src); 2972ab25eeb5Syz155240 else 2973ab25eeb5Syz155240 return nat_outlookup(fin, 0, p, oip->ip_dst, oip->ip_src); 2974ab25eeb5Syz155240 } 2975ab25eeb5Syz155240 2976ab25eeb5Syz155240 2977ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */ 2978ab25eeb5Syz155240 /* Function: nat_icmperror */ 2979ab25eeb5Syz155240 /* Returns: nat_t* - point to matching NAT structure */ 2980ab25eeb5Syz155240 /* Parameters: fin(I) - pointer to packet information */ 2981ab25eeb5Syz155240 /* nflags(I) - NAT flags for this packet */ 2982ab25eeb5Syz155240 /* dir(I) - direction of packet (in/out) */ 2983ab25eeb5Syz155240 /* */ 2984ab25eeb5Syz155240 /* Fix up an ICMP packet which is an error message for an existing NAT */ 2985ab25eeb5Syz155240 /* session. This will correct both packet header data and checksums. */ 2986ab25eeb5Syz155240 /* */ 2987ab25eeb5Syz155240 /* This should *ONLY* be used for incoming ICMP error packets to make sure */ 2988ab25eeb5Syz155240 /* a NAT'd ICMP packet gets correctly recognised. */ 2989ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */ 2990ab25eeb5Syz155240 nat_t *nat_icmperror(fin, nflags, dir) 2991ab25eeb5Syz155240 fr_info_t *fin; 2992ab25eeb5Syz155240 u_int *nflags; 2993ab25eeb5Syz155240 int dir; 2994ab25eeb5Syz155240 { 29955142ed1fSjojemann u_32_t sum1, sum2, sumd, psum1, psum2, psumd, sumd2; 2996ab25eeb5Syz155240 struct in_addr in; 29975142ed1fSjojemann icmphdr_t *icmp, *orgicmp; 29985142ed1fSjojemann int dlen; 29995142ed1fSjojemann udphdr_t *udp; 3000ab25eeb5Syz155240 tcphdr_t *tcp; 3001ab25eeb5Syz155240 nat_t *nat; 3002ab25eeb5Syz155240 ip_t *oip; 3003ab25eeb5Syz155240 if ((fin->fin_flx & (FI_SHORT|FI_FRAGBODY))) 3004ab25eeb5Syz155240 return NULL; 30055142ed1fSjojemann 3006ab25eeb5Syz155240 /* 30075142ed1fSjojemann * nat_icmperrorlookup() looks up nat entry associated with the 30085142ed1fSjojemann * offending IP packet and returns pointer to the entry, or NULL 30095142ed1fSjojemann * if packet wasn't natted or for `defective' packets. 3010ab25eeb5Syz155240 */ 30115142ed1fSjojemann 3012ab25eeb5Syz155240 if ((fin->fin_v != 4) || !(nat = nat_icmperrorlookup(fin, dir))) 3013ab25eeb5Syz155240 return NULL; 3014ab25eeb5Syz155240 3015ab25eeb5Syz155240 sumd2 = 0; 3016ab25eeb5Syz155240 *nflags = IPN_ICMPERR; 3017ab25eeb5Syz155240 icmp = fin->fin_dp; 3018ab25eeb5Syz155240 oip = (ip_t *)&icmp->icmp_ip; 30195142ed1fSjojemann udp = (udphdr_t *)((((char *)oip) + (IP_HL(oip) << 2))); 30205142ed1fSjojemann tcp = (tcphdr_t *)udp; 30215142ed1fSjojemann dlen = fin->fin_plen - ((char *)udp - (char *)fin->fin_ip); 3022ab25eeb5Syz155240 3023ab25eeb5Syz155240 /* 3024ab25eeb5Syz155240 * Need to adjust ICMP header to include the real IP#'s and 30255142ed1fSjojemann * port #'s. There are three steps required. 3026ab25eeb5Syz155240 * 30275142ed1fSjojemann * Step 1 30285142ed1fSjojemann * Fix the IP addresses in the offending IP packet and update 30295142ed1fSjojemann * ip header checksum to compensate for the change. 30305142ed1fSjojemann * 30315142ed1fSjojemann * No update needed here for icmp_cksum because the ICMP checksum 30325142ed1fSjojemann * is calculated over the complete ICMP packet, which includes the 30335142ed1fSjojemann * changed oip IP addresses and oip->ip_sum. These two changes 30345142ed1fSjojemann * cancel each other out (if the delta for the IP address is x, 30355142ed1fSjojemann * then the delta for ip_sum is minus x). 3036ab25eeb5Syz155240 */ 3037ab25eeb5Syz155240 3038ab25eeb5Syz155240 if (oip->ip_dst.s_addr == nat->nat_oip.s_addr) { 3039ab25eeb5Syz155240 sum1 = LONG_SUM(ntohl(oip->ip_src.s_addr)); 3040ab25eeb5Syz155240 in = nat->nat_inip; 3041ab25eeb5Syz155240 oip->ip_src = in; 3042ab25eeb5Syz155240 } else { 3043ab25eeb5Syz155240 sum1 = LONG_SUM(ntohl(oip->ip_dst.s_addr)); 3044ab25eeb5Syz155240 in = nat->nat_outip; 3045ab25eeb5Syz155240 oip->ip_dst = in; 3046ab25eeb5Syz155240 } 3047ab25eeb5Syz155240 3048ab25eeb5Syz155240 sum2 = LONG_SUM(ntohl(in.s_addr)); 3049ab25eeb5Syz155240 CALC_SUMD(sum1, sum2, sumd); 3050ab25eeb5Syz155240 fix_datacksum(&oip->ip_sum, sumd); 3051ab25eeb5Syz155240 3052ab25eeb5Syz155240 /* 30535142ed1fSjojemann * Step 2 30545142ed1fSjojemann * Perform other adjustments based on protocol of offending packet. 3055ab25eeb5Syz155240 */ 30565142ed1fSjojemann 30575142ed1fSjojemann switch (oip->ip_p) { 30585142ed1fSjojemann case IPPROTO_TCP : 30595142ed1fSjojemann case IPPROTO_UDP : 3060ab25eeb5Syz155240 3061ab25eeb5Syz155240 /* 30625142ed1fSjojemann * For offending TCP/UDP IP packets, translate the ports 30635142ed1fSjojemann * based on the NAT specification. 3064ab25eeb5Syz155240 * 3065ab25eeb5Syz155240 * Advance notice : Now it becomes complicated :-) 3066ab25eeb5Syz155240 * 30675142ed1fSjojemann * Since the port and IP addresse fields are both part 30685142ed1fSjojemann * of the TCP/UDP checksum of the offending IP packet, 30695142ed1fSjojemann * we need to adjust that checksum as well. 3070ab25eeb5Syz155240 * 30715142ed1fSjojemann * To further complicate things, the TCP/UDP checksum 30725142ed1fSjojemann * may not be present. We must check to see if the 30735142ed1fSjojemann * length of the data portion is big enough to hold 30745142ed1fSjojemann * the checksum. In the UDP case, a test to determine 30755142ed1fSjojemann * if the checksum is even set is also required. 30765142ed1fSjojemann * 30775142ed1fSjojemann * Any changes to an IP address, port or checksum within 30785142ed1fSjojemann * the ICMP packet requires a change to icmp_cksum. 30795142ed1fSjojemann * 30805142ed1fSjojemann * Be extremely careful here ... The change is dependent 30815142ed1fSjojemann * upon whether or not the TCP/UPD checksum is present. 30825142ed1fSjojemann * 30835142ed1fSjojemann * If TCP/UPD checksum is present, the icmp_cksum must 30845142ed1fSjojemann * compensate for checksum modification resulting from 30855142ed1fSjojemann * IP address change only. Port change and resulting 30865142ed1fSjojemann * data checksum adjustments cancel each other out. 30875142ed1fSjojemann * 30885142ed1fSjojemann * If TCP/UDP checksum is not present, icmp_cksum must 30895142ed1fSjojemann * compensate for port change only. The IP address 30905142ed1fSjojemann * change does not modify anything else in this case. 3091ab25eeb5Syz155240 */ 3092ab25eeb5Syz155240 30935142ed1fSjojemann psum1 = 0; 30945142ed1fSjojemann psum2 = 0; 30955142ed1fSjojemann psumd = 0; 30965142ed1fSjojemann 30975142ed1fSjojemann if ((tcp->th_dport == nat->nat_oport) && 30985142ed1fSjojemann (tcp->th_sport != nat->nat_inport)) { 30995142ed1fSjojemann 31005142ed1fSjojemann /* 31015142ed1fSjojemann * Translate the source port. 31025142ed1fSjojemann */ 31035142ed1fSjojemann 31045142ed1fSjojemann psum1 = ntohs(tcp->th_sport); 31055142ed1fSjojemann psum2 = ntohs(nat->nat_inport); 31065142ed1fSjojemann tcp->th_sport = nat->nat_inport; 31075142ed1fSjojemann 31085142ed1fSjojemann } else if ((tcp->th_sport == nat->nat_oport) && 31095142ed1fSjojemann (tcp->th_dport != nat->nat_outport)) { 31105142ed1fSjojemann 31115142ed1fSjojemann /* 31125142ed1fSjojemann * Translate the destination port. 31135142ed1fSjojemann */ 31145142ed1fSjojemann 31155142ed1fSjojemann psum1 = ntohs(tcp->th_dport); 31165142ed1fSjojemann psum2 = ntohs(nat->nat_outport); 31175142ed1fSjojemann tcp->th_dport = nat->nat_outport; 3118ab25eeb5Syz155240 } 3119ab25eeb5Syz155240 31205142ed1fSjojemann if ((oip->ip_p == IPPROTO_TCP) && (dlen >= 18)) { 3121ab25eeb5Syz155240 3122ab25eeb5Syz155240 /* 31235142ed1fSjojemann * TCP checksum present. 3124ab25eeb5Syz155240 * 31255142ed1fSjojemann * Adjust data checksum and icmp checksum to 31265142ed1fSjojemann * compensate for any IP address change. 3127ab25eeb5Syz155240 */ 3128ab25eeb5Syz155240 31295142ed1fSjojemann sum1 = ntohs(tcp->th_sum); 31305142ed1fSjojemann fix_datacksum(&tcp->th_sum, sumd); 31315142ed1fSjojemann sum2 = ntohs(tcp->th_sum); 31325142ed1fSjojemann sumd2 = sumd << 1; 3133ab25eeb5Syz155240 CALC_SUMD(sum1, sum2, sumd); 3134ab25eeb5Syz155240 sumd2 += sumd; 31355142ed1fSjojemann 31365142ed1fSjojemann /* 31375142ed1fSjojemann * Also make data checksum adjustment to 31385142ed1fSjojemann * compensate for any port change. 31395142ed1fSjojemann */ 31405142ed1fSjojemann 31415142ed1fSjojemann if (psum1 != psum2) { 31425142ed1fSjojemann CALC_SUMD(psum1, psum2, psumd); 31435142ed1fSjojemann fix_datacksum(&tcp->th_sum, psumd); 3144ab25eeb5Syz155240 } 3145ab25eeb5Syz155240 31465142ed1fSjojemann } else if ((oip->ip_p == IPPROTO_UDP) && 31475142ed1fSjojemann (dlen >= 8) && (udp->uh_sum != 0)) { 3148ab25eeb5Syz155240 3149ab25eeb5Syz155240 /* 31505142ed1fSjojemann * The UDP checksum is present and set. 31515142ed1fSjojemann * 31525142ed1fSjojemann * Adjust data checksum and icmp checksum to 31535142ed1fSjojemann * compensate for any IP address change. 3154ab25eeb5Syz155240 */ 31555142ed1fSjojemann 31565142ed1fSjojemann sum1 = ntohs(udp->uh_sum); 31575142ed1fSjojemann fix_datacksum(&udp->uh_sum, sumd); 31585142ed1fSjojemann sum2 = ntohs(udp->uh_sum); 31595142ed1fSjojemann sumd2 = sumd << 1; 3160ab25eeb5Syz155240 CALC_SUMD(sum1, sum2, sumd); 3161ab25eeb5Syz155240 sumd2 += sumd; 31625142ed1fSjojemann 31635142ed1fSjojemann /* 31645142ed1fSjojemann * Also make data checksum adjustment to 31655142ed1fSjojemann * compensate for any port change. 31665142ed1fSjojemann */ 31675142ed1fSjojemann 31685142ed1fSjojemann if (psum1 != psum2) { 31695142ed1fSjojemann CALC_SUMD(psum1, psum2, psumd); 31705142ed1fSjojemann fix_datacksum(&udp->uh_sum, psumd); 31715142ed1fSjojemann } 31725142ed1fSjojemann 3173ab25eeb5Syz155240 } else { 3174ab25eeb5Syz155240 3175ab25eeb5Syz155240 /* 31765142ed1fSjojemann * Data checksum was not present. 3177ab25eeb5Syz155240 * 31785142ed1fSjojemann * Compensate for any port change. 3179ab25eeb5Syz155240 */ 3180ab25eeb5Syz155240 31815142ed1fSjojemann CALC_SUMD(psum2, psum1, psumd); 31825142ed1fSjojemann sumd2 += psumd; 3183ab25eeb5Syz155240 } 31845142ed1fSjojemann break; 3185ab25eeb5Syz155240 31865142ed1fSjojemann case IPPROTO_ICMP : 3187ab25eeb5Syz155240 31885142ed1fSjojemann orgicmp = (icmphdr_t *)udp; 3189ab25eeb5Syz155240 31905142ed1fSjojemann if ((nat->nat_dir == NAT_OUTBOUND) && 31915142ed1fSjojemann (orgicmp->icmp_id != nat->nat_inport) && 31925142ed1fSjojemann (dlen >= 8)) { 3193ab25eeb5Syz155240 3194ab25eeb5Syz155240 /* 3195ab25eeb5Syz155240 * Fix ICMP checksum (of the offening ICMP 3196ab25eeb5Syz155240 * query packet) to compensate the change 3197ab25eeb5Syz155240 * in the ICMP id of the offending ICMP 3198ab25eeb5Syz155240 * packet. 3199ab25eeb5Syz155240 * 3200ab25eeb5Syz155240 * Since you modify orgicmp->icmp_id with 3201ab25eeb5Syz155240 * a delta (say x) and you compensate that 3202ab25eeb5Syz155240 * in origicmp->icmp_cksum with a delta 3203ab25eeb5Syz155240 * minus x, you don't have to adjust the 3204ab25eeb5Syz155240 * overall icmp->icmp_cksum 3205ab25eeb5Syz155240 */ 32065142ed1fSjojemann 3207ab25eeb5Syz155240 sum1 = ntohs(orgicmp->icmp_id); 3208ab25eeb5Syz155240 sum2 = ntohs(nat->nat_inport); 3209ab25eeb5Syz155240 CALC_SUMD(sum1, sum2, sumd); 3210ab25eeb5Syz155240 orgicmp->icmp_id = nat->nat_inport; 3211ab25eeb5Syz155240 fix_datacksum(&orgicmp->icmp_cksum, sumd); 32125142ed1fSjojemann 32135142ed1fSjojemann } /* nat_dir can't be NAT_INBOUND for icmp queries */ 32145142ed1fSjojemann 32155142ed1fSjojemann break; 32165142ed1fSjojemann 32175142ed1fSjojemann default : 32185142ed1fSjojemann 32195142ed1fSjojemann break; 32205142ed1fSjojemann 32215142ed1fSjojemann } /* switch (oip->ip_p) */ 32225142ed1fSjojemann 32235142ed1fSjojemann /* 32245142ed1fSjojemann * Step 3 32255142ed1fSjojemann * Make the adjustments to icmp checksum. 32265142ed1fSjojemann */ 32275142ed1fSjojemann 32285142ed1fSjojemann if (sumd2 != 0) { 32295142ed1fSjojemann sumd2 = (sumd2 & 0xffff) + (sumd2 >> 16); 32305142ed1fSjojemann sumd2 = (sumd2 & 0xffff) + (sumd2 >> 16); 3231381a2a9aSdr146992 fix_incksum(&icmp->icmp_cksum, sumd2); 3232ab25eeb5Syz155240 } 3233ab25eeb5Syz155240 return nat; 3234ab25eeb5Syz155240 } 3235ab25eeb5Syz155240 3236ab25eeb5Syz155240 3237ab25eeb5Syz155240 /* 3238ab25eeb5Syz155240 * NB: these lookups don't lock access to the list, it assumed that it has 3239ab25eeb5Syz155240 * already been done! 3240ab25eeb5Syz155240 */ 3241ab25eeb5Syz155240 3242ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */ 3243ab25eeb5Syz155240 /* Function: nat_inlookup */ 3244ab25eeb5Syz155240 /* Returns: nat_t* - NULL == no match, */ 3245ab25eeb5Syz155240 /* else pointer to matching NAT entry */ 3246ab25eeb5Syz155240 /* Parameters: fin(I) - pointer to packet information */ 3247ab25eeb5Syz155240 /* flags(I) - NAT flags for this packet */ 3248ab25eeb5Syz155240 /* p(I) - protocol for this packet */ 3249ab25eeb5Syz155240 /* src(I) - source IP address */ 3250ab25eeb5Syz155240 /* mapdst(I) - destination IP address */ 3251ab25eeb5Syz155240 /* */ 3252ab25eeb5Syz155240 /* Lookup a nat entry based on the mapped destination ip address/port and */ 3253ab25eeb5Syz155240 /* real source address/port. We use this lookup when receiving a packet, */ 3254ab25eeb5Syz155240 /* we're looking for a table entry, based on the destination address. */ 3255ab25eeb5Syz155240 /* */ 3256ab25eeb5Syz155240 /* NOTE: THE PACKET BEING CHECKED (IF FOUND) HAS A MAPPING ALREADY. */ 3257ab25eeb5Syz155240 /* */ 3258ab25eeb5Syz155240 /* NOTE: IT IS ASSUMED THAT ipf_nat IS ONLY HELD WITH A READ LOCK WHEN */ 3259ab25eeb5Syz155240 /* THIS FUNCTION IS CALLED WITH NAT_SEARCH SET IN nflags. */ 3260ab25eeb5Syz155240 /* */ 3261ab25eeb5Syz155240 /* flags -> relevant are IPN_UDP/IPN_TCP/IPN_ICMPQUERY that indicate if */ 3262ab25eeb5Syz155240 /* the packet is of said protocol */ 3263ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */ 3264ab25eeb5Syz155240 nat_t *nat_inlookup(fin, flags, p, src, mapdst) 3265ab25eeb5Syz155240 fr_info_t *fin; 3266ab25eeb5Syz155240 u_int flags, p; 3267ab25eeb5Syz155240 struct in_addr src , mapdst; 3268ab25eeb5Syz155240 { 3269ab25eeb5Syz155240 u_short sport, dport; 3270ab25eeb5Syz155240 ipnat_t *ipn; 3271ab25eeb5Syz155240 u_int sflags; 3272ab25eeb5Syz155240 nat_t *nat; 3273ab25eeb5Syz155240 int nflags; 3274ab25eeb5Syz155240 u_32_t dst; 3275ab25eeb5Syz155240 void *ifp; 3276ab25eeb5Syz155240 u_int hv; 3277f4b3ec61Sdh155122 ipf_stack_t *ifs = fin->fin_ifs; 3278ab25eeb5Syz155240 3279ab25eeb5Syz155240 if (fin != NULL) 3280ab25eeb5Syz155240 ifp = fin->fin_ifp; 3281ab25eeb5Syz155240 else 3282ab25eeb5Syz155240 ifp = NULL; 3283ab25eeb5Syz155240 sport = 0; 3284ab25eeb5Syz155240 dport = 0; 3285ab25eeb5Syz155240 dst = mapdst.s_addr; 3286ab25eeb5Syz155240 sflags = flags & NAT_TCPUDPICMP; 3287ab25eeb5Syz155240 3288ab25eeb5Syz155240 switch (p) 3289ab25eeb5Syz155240 { 3290ab25eeb5Syz155240 case IPPROTO_TCP : 3291ab25eeb5Syz155240 case IPPROTO_UDP : 3292ab25eeb5Syz155240 sport = htons(fin->fin_data[0]); 3293ab25eeb5Syz155240 dport = htons(fin->fin_data[1]); 3294ab25eeb5Syz155240 break; 3295ab25eeb5Syz155240 case IPPROTO_ICMP : 3296ab25eeb5Syz155240 if (flags & IPN_ICMPERR) 3297ab25eeb5Syz155240 sport = fin->fin_data[1]; 3298ab25eeb5Syz155240 else 3299ab25eeb5Syz155240 dport = fin->fin_data[1]; 3300ab25eeb5Syz155240 break; 3301ab25eeb5Syz155240 default : 3302ab25eeb5Syz155240 break; 3303ab25eeb5Syz155240 } 3304ab25eeb5Syz155240 3305ab25eeb5Syz155240 3306ab25eeb5Syz155240 if ((flags & SI_WILDP) != 0) 3307ab25eeb5Syz155240 goto find_in_wild_ports; 3308ab25eeb5Syz155240 3309ab25eeb5Syz155240 hv = NAT_HASH_FN(dst, dport, 0xffffffff); 3310f4b3ec61Sdh155122 hv = NAT_HASH_FN(src.s_addr, hv + sport, ifs->ifs_ipf_nattable_sz); 3311f4b3ec61Sdh155122 nat = ifs->ifs_nat_table[1][hv]; 3312ab25eeb5Syz155240 for (; nat; nat = nat->nat_hnext[1]) { 3313d6c23f6fSyx160601 if (nat->nat_v != 4) 3314d6c23f6fSyx160601 continue; 3315d6c23f6fSyx160601 3316e6c6c1faSyz155240 if (nat->nat_ifps[0] != NULL) { 3317e6c6c1faSyz155240 if ((ifp != NULL) && (ifp != nat->nat_ifps[0])) 3318e6c6c1faSyz155240 continue; 3319e6c6c1faSyz155240 } else if (ifp != NULL) 3320e6c6c1faSyz155240 nat->nat_ifps[0] = ifp; 3321ab25eeb5Syz155240 3322e6c6c1faSyz155240 nflags = nat->nat_flags; 3323ab25eeb5Syz155240 3324ab25eeb5Syz155240 if (nat->nat_oip.s_addr == src.s_addr && 3325ab25eeb5Syz155240 nat->nat_outip.s_addr == dst && 3326ab25eeb5Syz155240 (((p == 0) && 3327ab25eeb5Syz155240 (sflags == (nat->nat_flags & IPN_TCPUDPICMP))) 3328ab25eeb5Syz155240 || (p == nat->nat_p))) { 3329ab25eeb5Syz155240 switch (p) 3330ab25eeb5Syz155240 { 3331ab25eeb5Syz155240 #if 0 3332ab25eeb5Syz155240 case IPPROTO_GRE : 3333ab25eeb5Syz155240 if (nat->nat_call[1] != fin->fin_data[0]) 3334ab25eeb5Syz155240 continue; 3335ab25eeb5Syz155240 break; 3336ab25eeb5Syz155240 #endif 3337ab25eeb5Syz155240 case IPPROTO_ICMP : 3338ab25eeb5Syz155240 if ((flags & IPN_ICMPERR) != 0) { 3339ab25eeb5Syz155240 if (nat->nat_outport != sport) 3340ab25eeb5Syz155240 continue; 3341ab25eeb5Syz155240 } else { 3342ab25eeb5Syz155240 if (nat->nat_outport != dport) 3343ab25eeb5Syz155240 continue; 3344ab25eeb5Syz155240 } 3345ab25eeb5Syz155240 break; 3346ab25eeb5Syz155240 case IPPROTO_TCP : 3347ab25eeb5Syz155240 case IPPROTO_UDP : 3348ab25eeb5Syz155240 if (nat->nat_oport != sport) 3349ab25eeb5Syz155240 continue; 3350ab25eeb5Syz155240 if (nat->nat_outport != dport) 3351ab25eeb5Syz155240 continue; 3352ab25eeb5Syz155240 break; 3353ab25eeb5Syz155240 default : 3354ab25eeb5Syz155240 break; 3355ab25eeb5Syz155240 } 3356ab25eeb5Syz155240 3357ab25eeb5Syz155240 ipn = nat->nat_ptr; 3358ab25eeb5Syz155240 if ((ipn != NULL) && (nat->nat_aps != NULL)) 3359ab25eeb5Syz155240 if (appr_match(fin, nat) != 0) 3360ab25eeb5Syz155240 continue; 3361ab25eeb5Syz155240 return nat; 3362ab25eeb5Syz155240 } 3363ab25eeb5Syz155240 } 3364ab25eeb5Syz155240 3365ab25eeb5Syz155240 /* 3366ab25eeb5Syz155240 * So if we didn't find it but there are wildcard members in the hash 3367ab25eeb5Syz155240 * table, go back and look for them. We do this search and update here 3368ab25eeb5Syz155240 * because it is modifying the NAT table and we want to do this only 3369ab25eeb5Syz155240 * for the first packet that matches. The exception, of course, is 3370ab25eeb5Syz155240 * for "dummy" (FI_IGNORE) lookups. 3371ab25eeb5Syz155240 */ 3372ab25eeb5Syz155240 find_in_wild_ports: 3373ab25eeb5Syz155240 if (!(flags & NAT_TCPUDP) || !(flags & NAT_SEARCH)) 3374ab25eeb5Syz155240 return NULL; 3375f4b3ec61Sdh155122 if (ifs->ifs_nat_stats.ns_wilds == 0) 3376ab25eeb5Syz155240 return NULL; 3377ab25eeb5Syz155240 3378f4b3ec61Sdh155122 RWLOCK_EXIT(&ifs->ifs_ipf_nat); 3379ab25eeb5Syz155240 3380ab25eeb5Syz155240 hv = NAT_HASH_FN(dst, 0, 0xffffffff); 3381f4b3ec61Sdh155122 hv = NAT_HASH_FN(src.s_addr, hv, ifs->ifs_ipf_nattable_sz); 3382ab25eeb5Syz155240 3383f4b3ec61Sdh155122 WRITE_ENTER(&ifs->ifs_ipf_nat); 3384ab25eeb5Syz155240 3385f4b3ec61Sdh155122 nat = ifs->ifs_nat_table[1][hv]; 3386ab25eeb5Syz155240 for (; nat; nat = nat->nat_hnext[1]) { 3387d6c23f6fSyx160601 if (nat->nat_v != 4) 3388d6c23f6fSyx160601 continue; 3389d6c23f6fSyx160601 3390e6c6c1faSyz155240 if (nat->nat_ifps[0] != NULL) { 3391e6c6c1faSyz155240 if ((ifp != NULL) && (ifp != nat->nat_ifps[0])) 3392ab25eeb5Syz155240 continue; 3393e6c6c1faSyz155240 } else if (ifp != NULL) 3394e6c6c1faSyz155240 nat->nat_ifps[0] = ifp; 3395ab25eeb5Syz155240 3396ab25eeb5Syz155240 if (nat->nat_p != fin->fin_p) 3397ab25eeb5Syz155240 continue; 3398ab25eeb5Syz155240 if (nat->nat_oip.s_addr != src.s_addr || 3399ab25eeb5Syz155240 nat->nat_outip.s_addr != dst) 3400ab25eeb5Syz155240 continue; 3401ab25eeb5Syz155240 3402ab25eeb5Syz155240 nflags = nat->nat_flags; 3403ab25eeb5Syz155240 if (!(nflags & (NAT_TCPUDP|SI_WILDP))) 3404ab25eeb5Syz155240 continue; 3405ab25eeb5Syz155240 3406ab25eeb5Syz155240 if (nat_wildok(nat, (int)sport, (int)dport, nflags, 3407ab25eeb5Syz155240 NAT_INBOUND) == 1) { 3408ab25eeb5Syz155240 if ((fin->fin_flx & FI_IGNORE) != 0) 3409ab25eeb5Syz155240 break; 3410ab25eeb5Syz155240 if ((nflags & SI_CLONE) != 0) { 3411ab25eeb5Syz155240 nat = fr_natclone(fin, nat); 3412ab25eeb5Syz155240 if (nat == NULL) 3413ab25eeb5Syz155240 break; 3414ab25eeb5Syz155240 } else { 3415f4b3ec61Sdh155122 MUTEX_ENTER(&ifs->ifs_ipf_nat_new); 3416f4b3ec61Sdh155122 ifs->ifs_nat_stats.ns_wilds--; 3417f4b3ec61Sdh155122 MUTEX_EXIT(&ifs->ifs_ipf_nat_new); 3418ab25eeb5Syz155240 } 3419ab25eeb5Syz155240 nat->nat_oport = sport; 3420ab25eeb5Syz155240 nat->nat_outport = dport; 3421ab25eeb5Syz155240 nat->nat_flags &= ~(SI_W_DPORT|SI_W_SPORT); 3422f4b3ec61Sdh155122 nat_tabmove(nat, ifs); 3423ab25eeb5Syz155240 break; 3424ab25eeb5Syz155240 } 3425ab25eeb5Syz155240 } 3426ab25eeb5Syz155240 3427f4b3ec61Sdh155122 MUTEX_DOWNGRADE(&ifs->ifs_ipf_nat); 3428ab25eeb5Syz155240 3429ab25eeb5Syz155240 return nat; 3430ab25eeb5Syz155240 } 3431ab25eeb5Syz155240 3432ab25eeb5Syz155240 3433ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */ 3434ab25eeb5Syz155240 /* Function: nat_tabmove */ 3435ab25eeb5Syz155240 /* Returns: Nil */ 3436ab25eeb5Syz155240 /* Parameters: nat(I) - pointer to NAT structure */ 3437ab25eeb5Syz155240 /* Write Lock: ipf_nat */ 3438ab25eeb5Syz155240 /* */ 3439ab25eeb5Syz155240 /* This function is only called for TCP/UDP NAT table entries where the */ 3440ab25eeb5Syz155240 /* original was placed in the table without hashing on the ports and we now */ 3441ab25eeb5Syz155240 /* want to include hashing on port numbers. */ 3442ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */ 3443f4b3ec61Sdh155122 static void nat_tabmove(nat, ifs) 3444ab25eeb5Syz155240 nat_t *nat; 3445f4b3ec61Sdh155122 ipf_stack_t *ifs; 3446ab25eeb5Syz155240 { 3447ab25eeb5Syz155240 nat_t **natp; 3448ab25eeb5Syz155240 u_int hv; 3449ab25eeb5Syz155240 3450ab25eeb5Syz155240 if (nat->nat_flags & SI_CLONE) 3451ab25eeb5Syz155240 return; 3452ab25eeb5Syz155240 3453ab25eeb5Syz155240 /* 3454ab25eeb5Syz155240 * Remove the NAT entry from the old location 3455ab25eeb5Syz155240 */ 3456ab25eeb5Syz155240 if (nat->nat_hnext[0]) 3457ab25eeb5Syz155240 nat->nat_hnext[0]->nat_phnext[0] = nat->nat_phnext[0]; 3458ab25eeb5Syz155240 *nat->nat_phnext[0] = nat->nat_hnext[0]; 3459f4b3ec61Sdh155122 ifs->ifs_nat_stats.ns_bucketlen[0][nat->nat_hv[0]]--; 3460ab25eeb5Syz155240 3461ab25eeb5Syz155240 if (nat->nat_hnext[1]) 3462ab25eeb5Syz155240 nat->nat_hnext[1]->nat_phnext[1] = nat->nat_phnext[1]; 3463ab25eeb5Syz155240 *nat->nat_phnext[1] = nat->nat_hnext[1]; 3464f4b3ec61Sdh155122 ifs->ifs_nat_stats.ns_bucketlen[1][nat->nat_hv[1]]--; 3465ab25eeb5Syz155240 3466ab25eeb5Syz155240 /* 3467ab25eeb5Syz155240 * Add into the NAT table in the new position 3468ab25eeb5Syz155240 */ 3469ab25eeb5Syz155240 hv = NAT_HASH_FN(nat->nat_inip.s_addr, nat->nat_inport, 0xffffffff); 3470ab25eeb5Syz155240 hv = NAT_HASH_FN(nat->nat_oip.s_addr, hv + nat->nat_oport, 3471f4b3ec61Sdh155122 ifs->ifs_ipf_nattable_sz); 3472ab25eeb5Syz155240 nat->nat_hv[0] = hv; 3473f4b3ec61Sdh155122 natp = &ifs->ifs_nat_table[0][hv]; 3474ab25eeb5Syz155240 if (*natp) 3475ab25eeb5Syz155240 (*natp)->nat_phnext[0] = &nat->nat_hnext[0]; 3476ab25eeb5Syz155240 nat->nat_phnext[0] = natp; 3477ab25eeb5Syz155240 nat->nat_hnext[0] = *natp; 3478ab25eeb5Syz155240 *natp = nat; 3479f4b3ec61Sdh155122 ifs->ifs_nat_stats.ns_bucketlen[0][hv]++; 3480ab25eeb5Syz155240 3481ab25eeb5Syz155240 hv = NAT_HASH_FN(nat->nat_outip.s_addr, nat->nat_outport, 0xffffffff); 3482ab25eeb5Syz155240 hv = NAT_HASH_FN(nat->nat_oip.s_addr, hv + nat->nat_oport, 3483f4b3ec61Sdh155122 ifs->ifs_ipf_nattable_sz); 3484ab25eeb5Syz155240 nat->nat_hv[1] = hv; 3485f4b3ec61Sdh155122 natp = &ifs->ifs_nat_table[1][hv]; 3486ab25eeb5Syz155240 if (*natp) 3487ab25eeb5Syz155240 (*natp)->nat_phnext[1] = &nat->nat_hnext[1]; 3488ab25eeb5Syz155240 nat->nat_phnext[1] = natp; 3489ab25eeb5Syz155240 nat->nat_hnext[1] = *natp; 3490ab25eeb5Syz155240 *natp = nat; 3491f4b3ec61Sdh155122 ifs->ifs_nat_stats.ns_bucketlen[1][hv]++; 3492ab25eeb5Syz155240 } 3493ab25eeb5Syz155240 3494ab25eeb5Syz155240 3495ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */ 3496ab25eeb5Syz155240 /* Function: nat_outlookup */ 3497ab25eeb5Syz155240 /* Returns: nat_t* - NULL == no match, */ 3498ab25eeb5Syz155240 /* else pointer to matching NAT entry */ 3499ab25eeb5Syz155240 /* Parameters: fin(I) - pointer to packet information */ 3500ab25eeb5Syz155240 /* flags(I) - NAT flags for this packet */ 3501ab25eeb5Syz155240 /* p(I) - protocol for this packet */ 3502ab25eeb5Syz155240 /* src(I) - source IP address */ 3503ab25eeb5Syz155240 /* dst(I) - destination IP address */ 3504ab25eeb5Syz155240 /* rw(I) - 1 == write lock on ipf_nat held, 0 == read lock. */ 3505ab25eeb5Syz155240 /* */ 3506ab25eeb5Syz155240 /* Lookup a nat entry based on the source 'real' ip address/port and */ 3507ab25eeb5Syz155240 /* destination address/port. We use this lookup when sending a packet out, */ 3508ab25eeb5Syz155240 /* we're looking for a table entry, based on the source address. */ 3509ab25eeb5Syz155240 /* */ 3510ab25eeb5Syz155240 /* NOTE: THE PACKET BEING CHECKED (IF FOUND) HAS A MAPPING ALREADY. */ 3511ab25eeb5Syz155240 /* */ 3512ab25eeb5Syz155240 /* NOTE: IT IS ASSUMED THAT ipf_nat IS ONLY HELD WITH A READ LOCK WHEN */ 3513ab25eeb5Syz155240 /* THIS FUNCTION IS CALLED WITH NAT_SEARCH SET IN nflags. */ 3514ab25eeb5Syz155240 /* */ 3515ab25eeb5Syz155240 /* flags -> relevant are IPN_UDP/IPN_TCP/IPN_ICMPQUERY that indicate if */ 3516ab25eeb5Syz155240 /* the packet is of said protocol */ 3517ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */ 3518ab25eeb5Syz155240 nat_t *nat_outlookup(fin, flags, p, src, dst) 3519ab25eeb5Syz155240 fr_info_t *fin; 3520ab25eeb5Syz155240 u_int flags, p; 3521ab25eeb5Syz155240 struct in_addr src , dst; 3522ab25eeb5Syz155240 { 3523ab25eeb5Syz155240 u_short sport, dport; 3524ab25eeb5Syz155240 u_int sflags; 3525ab25eeb5Syz155240 ipnat_t *ipn; 3526ab25eeb5Syz155240 u_32_t srcip; 3527ab25eeb5Syz155240 nat_t *nat; 3528ab25eeb5Syz155240 int nflags; 3529ab25eeb5Syz155240 void *ifp; 3530ab25eeb5Syz155240 u_int hv; 3531f4b3ec61Sdh155122 ipf_stack_t *ifs = fin->fin_ifs; 3532ab25eeb5Syz155240 3533ab25eeb5Syz155240 ifp = fin->fin_ifp; 3534e6c6c1faSyz155240 3535ab25eeb5Syz155240 srcip = src.s_addr; 3536ab25eeb5Syz155240 sflags = flags & IPN_TCPUDPICMP; 3537ab25eeb5Syz155240 sport = 0; 3538ab25eeb5Syz155240 dport = 0; 3539ab25eeb5Syz155240 3540ab25eeb5Syz155240 switch (p) 3541ab25eeb5Syz155240 { 3542ab25eeb5Syz155240 case IPPROTO_TCP : 3543ab25eeb5Syz155240 case IPPROTO_UDP : 3544ab25eeb5Syz155240 sport = htons(fin->fin_data[0]); 3545ab25eeb5Syz155240 dport = htons(fin->fin_data[1]); 3546ab25eeb5Syz155240 break; 3547ab25eeb5Syz155240 case IPPROTO_ICMP : 3548ab25eeb5Syz155240 if (flags & IPN_ICMPERR) 3549ab25eeb5Syz155240 sport = fin->fin_data[1]; 3550ab25eeb5Syz155240 else 3551ab25eeb5Syz155240 dport = fin->fin_data[1]; 3552ab25eeb5Syz155240 break; 3553ab25eeb5Syz155240 default : 3554ab25eeb5Syz155240 break; 3555ab25eeb5Syz155240 } 3556ab25eeb5Syz155240 3557ab25eeb5Syz155240 if ((flags & SI_WILDP) != 0) 3558ab25eeb5Syz155240 goto find_out_wild_ports; 3559ab25eeb5Syz155240 3560ab25eeb5Syz155240 hv = NAT_HASH_FN(srcip, sport, 0xffffffff); 3561f4b3ec61Sdh155122 hv = NAT_HASH_FN(dst.s_addr, hv + dport, ifs->ifs_ipf_nattable_sz); 3562f4b3ec61Sdh155122 nat = ifs->ifs_nat_table[0][hv]; 3563ab25eeb5Syz155240 for (; nat; nat = nat->nat_hnext[0]) { 3564d6c23f6fSyx160601 if (nat->nat_v != 4) 3565d6c23f6fSyx160601 continue; 3566d6c23f6fSyx160601 3567e6c6c1faSyz155240 if (nat->nat_ifps[1] != NULL) { 3568e6c6c1faSyz155240 if ((ifp != NULL) && (ifp != nat->nat_ifps[1])) 3569e6c6c1faSyz155240 continue; 3570e6c6c1faSyz155240 } else if (ifp != NULL) 3571e6c6c1faSyz155240 nat->nat_ifps[1] = ifp; 3572ab25eeb5Syz155240 3573e6c6c1faSyz155240 nflags = nat->nat_flags; 3574ab25eeb5Syz155240 3575ab25eeb5Syz155240 if (nat->nat_inip.s_addr == srcip && 3576ab25eeb5Syz155240 nat->nat_oip.s_addr == dst.s_addr && 3577ab25eeb5Syz155240 (((p == 0) && (sflags == (nflags & NAT_TCPUDPICMP))) 3578ab25eeb5Syz155240 || (p == nat->nat_p))) { 3579ab25eeb5Syz155240 switch (p) 3580ab25eeb5Syz155240 { 3581ab25eeb5Syz155240 #if 0 3582ab25eeb5Syz155240 case IPPROTO_GRE : 3583ab25eeb5Syz155240 if (nat->nat_call[1] != fin->fin_data[0]) 3584ab25eeb5Syz155240 continue; 3585ab25eeb5Syz155240 break; 3586ab25eeb5Syz155240 #endif 3587ab25eeb5Syz155240 case IPPROTO_TCP : 3588ab25eeb5Syz155240 case IPPROTO_UDP : 3589ab25eeb5Syz155240 if (nat->nat_oport != dport) 3590ab25eeb5Syz155240 continue; 3591ab25eeb5Syz155240 if (nat->nat_inport != sport) 3592ab25eeb5Syz155240 continue; 3593ab25eeb5Syz155240 break; 3594ab25eeb5Syz155240 default : 3595ab25eeb5Syz155240 break; 3596ab25eeb5Syz155240 } 3597ab25eeb5Syz155240 3598ab25eeb5Syz155240 ipn = nat->nat_ptr; 3599ab25eeb5Syz155240 if ((ipn != NULL) && (nat->nat_aps != NULL)) 3600ab25eeb5Syz155240 if (appr_match(fin, nat) != 0) 3601ab25eeb5Syz155240 continue; 3602ab25eeb5Syz155240 return nat; 3603ab25eeb5Syz155240 } 3604ab25eeb5Syz155240 } 3605ab25eeb5Syz155240 3606ab25eeb5Syz155240 /* 3607ab25eeb5Syz155240 * So if we didn't find it but there are wildcard members in the hash 3608ab25eeb5Syz155240 * table, go back and look for them. We do this search and update here 3609ab25eeb5Syz155240 * because it is modifying the NAT table and we want to do this only 3610ab25eeb5Syz155240 * for the first packet that matches. The exception, of course, is 3611ab25eeb5Syz155240 * for "dummy" (FI_IGNORE) lookups. 3612ab25eeb5Syz155240 */ 3613ab25eeb5Syz155240 find_out_wild_ports: 3614ab25eeb5Syz155240 if (!(flags & NAT_TCPUDP) || !(flags & NAT_SEARCH)) 3615ab25eeb5Syz155240 return NULL; 3616f4b3ec61Sdh155122 if (ifs->ifs_nat_stats.ns_wilds == 0) 3617ab25eeb5Syz155240 return NULL; 3618ab25eeb5Syz155240 3619f4b3ec61Sdh155122 RWLOCK_EXIT(&ifs->ifs_ipf_nat); 3620ab25eeb5Syz155240 3621ab25eeb5Syz155240 hv = NAT_HASH_FN(srcip, 0, 0xffffffff); 3622f4b3ec61Sdh155122 hv = NAT_HASH_FN(dst.s_addr, hv, ifs->ifs_ipf_nattable_sz); 3623ab25eeb5Syz155240 3624f4b3ec61Sdh155122 WRITE_ENTER(&ifs->ifs_ipf_nat); 3625ab25eeb5Syz155240 3626f4b3ec61Sdh155122 nat = ifs->ifs_nat_table[0][hv]; 3627ab25eeb5Syz155240 for (; nat; nat = nat->nat_hnext[0]) { 3628d6c23f6fSyx160601 if (nat->nat_v != 4) 3629d6c23f6fSyx160601 continue; 3630d6c23f6fSyx160601 3631e6c6c1faSyz155240 if (nat->nat_ifps[1] != NULL) { 3632e6c6c1faSyz155240 if ((ifp != NULL) && (ifp != nat->nat_ifps[1])) 3633ab25eeb5Syz155240 continue; 3634e6c6c1faSyz155240 } else if (ifp != NULL) 3635e6c6c1faSyz155240 nat->nat_ifps[1] = ifp; 3636ab25eeb5Syz155240 3637ab25eeb5Syz155240 if (nat->nat_p != fin->fin_p) 3638ab25eeb5Syz155240 continue; 3639ab25eeb5Syz155240 if ((nat->nat_inip.s_addr != srcip) || 3640ab25eeb5Syz155240 (nat->nat_oip.s_addr != dst.s_addr)) 3641ab25eeb5Syz155240 continue; 3642ab25eeb5Syz155240 3643ab25eeb5Syz155240 nflags = nat->nat_flags; 3644ab25eeb5Syz155240 if (!(nflags & (NAT_TCPUDP|SI_WILDP))) 3645ab25eeb5Syz155240 continue; 3646ab25eeb5Syz155240 3647ab25eeb5Syz155240 if (nat_wildok(nat, (int)sport, (int)dport, nflags, 3648ab25eeb5Syz155240 NAT_OUTBOUND) == 1) { 3649ab25eeb5Syz155240 if ((fin->fin_flx & FI_IGNORE) != 0) 3650ab25eeb5Syz155240 break; 3651ab25eeb5Syz155240 if ((nflags & SI_CLONE) != 0) { 3652ab25eeb5Syz155240 nat = fr_natclone(fin, nat); 3653ab25eeb5Syz155240 if (nat == NULL) 3654ab25eeb5Syz155240 break; 3655ab25eeb5Syz155240 } else { 3656f4b3ec61Sdh155122 MUTEX_ENTER(&ifs->ifs_ipf_nat_new); 3657f4b3ec61Sdh155122 ifs->ifs_nat_stats.ns_wilds--; 3658f4b3ec61Sdh155122 MUTEX_EXIT(&ifs->ifs_ipf_nat_new); 3659ab25eeb5Syz155240 } 3660ab25eeb5Syz155240 nat->nat_inport = sport; 3661ab25eeb5Syz155240 nat->nat_oport = dport; 3662ab25eeb5Syz155240 if (nat->nat_outport == 0) 3663ab25eeb5Syz155240 nat->nat_outport = sport; 3664ab25eeb5Syz155240 nat->nat_flags &= ~(SI_W_DPORT|SI_W_SPORT); 3665f4b3ec61Sdh155122 nat_tabmove(nat, ifs); 3666ab25eeb5Syz155240 break; 3667ab25eeb5Syz155240 } 3668ab25eeb5Syz155240 } 3669ab25eeb5Syz155240 3670f4b3ec61Sdh155122 MUTEX_DOWNGRADE(&ifs->ifs_ipf_nat); 3671ab25eeb5Syz155240 3672ab25eeb5Syz155240 return nat; 3673ab25eeb5Syz155240 } 3674ab25eeb5Syz155240 3675ab25eeb5Syz155240 3676ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */ 3677ab25eeb5Syz155240 /* Function: nat_lookupredir */ 3678ab25eeb5Syz155240 /* Returns: nat_t* - NULL == no match, */ 3679ab25eeb5Syz155240 /* else pointer to matching NAT entry */ 3680ab25eeb5Syz155240 /* Parameters: np(I) - pointer to description of packet to find NAT table */ 3681ab25eeb5Syz155240 /* entry for. */ 3682ab25eeb5Syz155240 /* */ 3683ab25eeb5Syz155240 /* Lookup the NAT tables to search for a matching redirect */ 3684ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */ 3685f4b3ec61Sdh155122 nat_t *nat_lookupredir(np, ifs) 3686ab25eeb5Syz155240 natlookup_t *np; 3687f4b3ec61Sdh155122 ipf_stack_t *ifs; 3688ab25eeb5Syz155240 { 3689ab25eeb5Syz155240 fr_info_t fi; 3690ab25eeb5Syz155240 nat_t *nat; 3691ab25eeb5Syz155240 3692ab25eeb5Syz155240 bzero((char *)&fi, sizeof(fi)); 3693ab25eeb5Syz155240 if (np->nl_flags & IPN_IN) { 3694ab25eeb5Syz155240 fi.fin_data[0] = ntohs(np->nl_realport); 3695ab25eeb5Syz155240 fi.fin_data[1] = ntohs(np->nl_outport); 3696ab25eeb5Syz155240 } else { 3697ab25eeb5Syz155240 fi.fin_data[0] = ntohs(np->nl_inport); 3698ab25eeb5Syz155240 fi.fin_data[1] = ntohs(np->nl_outport); 3699ab25eeb5Syz155240 } 3700ab25eeb5Syz155240 if (np->nl_flags & IPN_TCP) 3701ab25eeb5Syz155240 fi.fin_p = IPPROTO_TCP; 3702ab25eeb5Syz155240 else if (np->nl_flags & IPN_UDP) 3703ab25eeb5Syz155240 fi.fin_p = IPPROTO_UDP; 3704ab25eeb5Syz155240 else if (np->nl_flags & (IPN_ICMPERR|IPN_ICMPQUERY)) 3705ab25eeb5Syz155240 fi.fin_p = IPPROTO_ICMP; 3706ab25eeb5Syz155240 3707f4b3ec61Sdh155122 fi.fin_ifs = ifs; 3708ab25eeb5Syz155240 /* 3709ab25eeb5Syz155240 * We can do two sorts of lookups: 3710ab25eeb5Syz155240 * - IPN_IN: we have the `real' and `out' address, look for `in'. 3711ab25eeb5Syz155240 * - default: we have the `in' and `out' address, look for `real'. 3712ab25eeb5Syz155240 */ 3713ab25eeb5Syz155240 if (np->nl_flags & IPN_IN) { 3714ab25eeb5Syz155240 if ((nat = nat_inlookup(&fi, np->nl_flags, fi.fin_p, 3715ab25eeb5Syz155240 np->nl_realip, np->nl_outip))) { 3716ab25eeb5Syz155240 np->nl_inip = nat->nat_inip; 3717ab25eeb5Syz155240 np->nl_inport = nat->nat_inport; 3718ab25eeb5Syz155240 } 3719ab25eeb5Syz155240 } else { 3720ab25eeb5Syz155240 /* 3721ab25eeb5Syz155240 * If nl_inip is non null, this is a lookup based on the real 3722ab25eeb5Syz155240 * ip address. Else, we use the fake. 3723ab25eeb5Syz155240 */ 3724ab25eeb5Syz155240 if ((nat = nat_outlookup(&fi, np->nl_flags, fi.fin_p, 3725ab25eeb5Syz155240 np->nl_inip, np->nl_outip))) { 3726ab25eeb5Syz155240 3727ab25eeb5Syz155240 if ((np->nl_flags & IPN_FINDFORWARD) != 0) { 3728ab25eeb5Syz155240 fr_info_t fin; 3729ab25eeb5Syz155240 bzero((char *)&fin, sizeof(fin)); 3730ab25eeb5Syz155240 fin.fin_p = nat->nat_p; 3731ab25eeb5Syz155240 fin.fin_data[0] = ntohs(nat->nat_outport); 3732ab25eeb5Syz155240 fin.fin_data[1] = ntohs(nat->nat_oport); 3733f4b3ec61Sdh155122 fin.fin_ifs = ifs; 3734ab25eeb5Syz155240 if (nat_inlookup(&fin, np->nl_flags, fin.fin_p, 3735ab25eeb5Syz155240 nat->nat_outip, 3736ab25eeb5Syz155240 nat->nat_oip) != NULL) { 3737ab25eeb5Syz155240 np->nl_flags &= ~IPN_FINDFORWARD; 3738ab25eeb5Syz155240 } 3739ab25eeb5Syz155240 } 3740ab25eeb5Syz155240 3741ab25eeb5Syz155240 np->nl_realip = nat->nat_outip; 3742ab25eeb5Syz155240 np->nl_realport = nat->nat_outport; 3743ab25eeb5Syz155240 } 3744ab25eeb5Syz155240 } 3745ab25eeb5Syz155240 3746ab25eeb5Syz155240 return nat; 3747ab25eeb5Syz155240 } 3748ab25eeb5Syz155240 3749ab25eeb5Syz155240 3750ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */ 3751ab25eeb5Syz155240 /* Function: nat_match */ 3752ab25eeb5Syz155240 /* Returns: int - 0 == no match, 1 == match */ 3753ab25eeb5Syz155240 /* Parameters: fin(I) - pointer to packet information */ 3754ab25eeb5Syz155240 /* np(I) - pointer to NAT rule */ 3755ab25eeb5Syz155240 /* */ 3756ab25eeb5Syz155240 /* Pull the matching of a packet against a NAT rule out of that complex */ 3757ab25eeb5Syz155240 /* loop inside fr_checknatin() and lay it out properly in its own function. */ 3758ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */ 3759ab25eeb5Syz155240 static int nat_match(fin, np) 3760ab25eeb5Syz155240 fr_info_t *fin; 3761ab25eeb5Syz155240 ipnat_t *np; 3762ab25eeb5Syz155240 { 3763ab25eeb5Syz155240 frtuc_t *ft; 3764ab25eeb5Syz155240 3765ab25eeb5Syz155240 if (fin->fin_v != 4) 3766ab25eeb5Syz155240 return 0; 3767ab25eeb5Syz155240 3768ab25eeb5Syz155240 if (np->in_p && fin->fin_p != np->in_p) 3769ab25eeb5Syz155240 return 0; 3770ab25eeb5Syz155240 3771ab25eeb5Syz155240 if (fin->fin_out) { 3772ab25eeb5Syz155240 if (!(np->in_redir & (NAT_MAP|NAT_MAPBLK))) 3773ab25eeb5Syz155240 return 0; 3774ab25eeb5Syz155240 if (((fin->fin_fi.fi_saddr & np->in_inmsk) != np->in_inip) 3775ab25eeb5Syz155240 ^ ((np->in_flags & IPN_NOTSRC) != 0)) 3776ab25eeb5Syz155240 return 0; 3777ab25eeb5Syz155240 if (((fin->fin_fi.fi_daddr & np->in_srcmsk) != np->in_srcip) 3778ab25eeb5Syz155240 ^ ((np->in_flags & IPN_NOTDST) != 0)) 3779ab25eeb5Syz155240 return 0; 3780ab25eeb5Syz155240 } else { 3781ab25eeb5Syz155240 if (!(np->in_redir & NAT_REDIRECT)) 3782ab25eeb5Syz155240 return 0; 3783ab25eeb5Syz155240 if (((fin->fin_fi.fi_saddr & np->in_srcmsk) != np->in_srcip) 3784ab25eeb5Syz155240 ^ ((np->in_flags & IPN_NOTSRC) != 0)) 3785ab25eeb5Syz155240 return 0; 3786ab25eeb5Syz155240 if (((fin->fin_fi.fi_daddr & np->in_outmsk) != np->in_outip) 3787ab25eeb5Syz155240 ^ ((np->in_flags & IPN_NOTDST) != 0)) 3788ab25eeb5Syz155240 return 0; 3789ab25eeb5Syz155240 } 3790ab25eeb5Syz155240 3791ab25eeb5Syz155240 ft = &np->in_tuc; 3792ab25eeb5Syz155240 if (!(fin->fin_flx & FI_TCPUDP) || 3793ab25eeb5Syz155240 (fin->fin_flx & (FI_SHORT|FI_FRAGBODY))) { 3794ab25eeb5Syz155240 if (ft->ftu_scmp || ft->ftu_dcmp) 3795ab25eeb5Syz155240 return 0; 3796ab25eeb5Syz155240 return 1; 3797ab25eeb5Syz155240 } 3798ab25eeb5Syz155240 3799ab25eeb5Syz155240 return fr_tcpudpchk(fin, ft); 3800ab25eeb5Syz155240 } 3801ab25eeb5Syz155240 3802ab25eeb5Syz155240 3803ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */ 3804ab25eeb5Syz155240 /* Function: nat_update */ 3805ab25eeb5Syz155240 /* Returns: Nil */ 380690907f62SJohn Ojemann /* Parameters: fin(I) - pointer to packet information */ 380790907f62SJohn Ojemann /* nat(I) - pointer to NAT structure */ 3808ab25eeb5Syz155240 /* np(I) - pointer to NAT rule */ 380990907f62SJohn Ojemann /* Locks: nat_lock */ 3810ab25eeb5Syz155240 /* */ 3811ab25eeb5Syz155240 /* Updates the lifetime of a NAT table entry for non-TCP packets. Must be */ 3812ab25eeb5Syz155240 /* called with fin_rev updated - i.e. after calling nat_proto(). */ 3813ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */ 3814ab25eeb5Syz155240 void nat_update(fin, nat, np) 3815ab25eeb5Syz155240 fr_info_t *fin; 3816ab25eeb5Syz155240 nat_t *nat; 3817ab25eeb5Syz155240 ipnat_t *np; 3818ab25eeb5Syz155240 { 3819ab25eeb5Syz155240 ipftq_t *ifq, *ifq2; 3820ab25eeb5Syz155240 ipftqent_t *tqe; 3821f4b3ec61Sdh155122 ipf_stack_t *ifs = fin->fin_ifs; 3822ab25eeb5Syz155240 3823ab25eeb5Syz155240 tqe = &nat->nat_tqe; 3824ab25eeb5Syz155240 ifq = tqe->tqe_ifq; 3825ab25eeb5Syz155240 3826ab25eeb5Syz155240 /* 3827ab25eeb5Syz155240 * We allow over-riding of NAT timeouts from NAT rules, even for 3828ab25eeb5Syz155240 * TCP, however, if it is TCP and there is no rule timeout set, 3829ab25eeb5Syz155240 * then do not update the timeout here. 3830ab25eeb5Syz155240 */ 3831ab25eeb5Syz155240 if (np != NULL) 3832ab25eeb5Syz155240 ifq2 = np->in_tqehead[fin->fin_rev]; 3833ab25eeb5Syz155240 else 3834ab25eeb5Syz155240 ifq2 = NULL; 3835ab25eeb5Syz155240 3836ab25eeb5Syz155240 if (nat->nat_p == IPPROTO_TCP && ifq2 == NULL) { 3837f4b3ec61Sdh155122 (void) fr_tcp_age(&nat->nat_tqe, fin, ifs->ifs_nat_tqb, 0); 3838ab25eeb5Syz155240 } else { 3839ab25eeb5Syz155240 if (ifq2 == NULL) { 3840ab25eeb5Syz155240 if (nat->nat_p == IPPROTO_UDP) 3841f4b3ec61Sdh155122 ifq2 = &ifs->ifs_nat_udptq; 3842ab25eeb5Syz155240 else if (nat->nat_p == IPPROTO_ICMP) 3843f4b3ec61Sdh155122 ifq2 = &ifs->ifs_nat_icmptq; 3844ab25eeb5Syz155240 else 3845f4b3ec61Sdh155122 ifq2 = &ifs->ifs_nat_iptq; 3846ab25eeb5Syz155240 } 3847ab25eeb5Syz155240 3848f4b3ec61Sdh155122 fr_movequeue(tqe, ifq, ifq2, ifs); 3849ab25eeb5Syz155240 } 3850ab25eeb5Syz155240 } 3851ab25eeb5Syz155240 3852ab25eeb5Syz155240 3853ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */ 3854ab25eeb5Syz155240 /* Function: fr_checknatout */ 3855ab25eeb5Syz155240 /* Returns: int - -1 == packet failed NAT checks so block it, */ 3856ab25eeb5Syz155240 /* 0 == no packet translation occurred, */ 3857ab25eeb5Syz155240 /* 1 == packet was successfully translated. */ 3858ab25eeb5Syz155240 /* Parameters: fin(I) - pointer to packet information */ 3859ab25eeb5Syz155240 /* passp(I) - pointer to filtering result flags */ 3860ab25eeb5Syz155240 /* */ 3861ab25eeb5Syz155240 /* Check to see if an outcoming packet should be changed. ICMP packets are */ 3862ab25eeb5Syz155240 /* first checked to see if they match an existing entry (if an error), */ 3863ab25eeb5Syz155240 /* otherwise a search of the current NAT table is made. If neither results */ 3864ab25eeb5Syz155240 /* in a match then a search for a matching NAT rule is made. Create a new */ 3865ab25eeb5Syz155240 /* NAT entry if a we matched a NAT rule. Lastly, actually change the */ 3866ab25eeb5Syz155240 /* packet header(s) as required. */ 3867ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */ 3868ab25eeb5Syz155240 int fr_checknatout(fin, passp) 3869ab25eeb5Syz155240 fr_info_t *fin; 3870ab25eeb5Syz155240 u_32_t *passp; 3871ab25eeb5Syz155240 { 3872cbded9aeSdr146992 ipnat_t *np = NULL, *npnext; 3873ab25eeb5Syz155240 struct ifnet *ifp, *sifp; 3874ab25eeb5Syz155240 icmphdr_t *icmp = NULL; 3875ab25eeb5Syz155240 tcphdr_t *tcp = NULL; 3876ab25eeb5Syz155240 int rval, natfailed; 3877ab25eeb5Syz155240 u_int nflags = 0; 3878ab25eeb5Syz155240 u_32_t ipa, iph; 3879ab25eeb5Syz155240 int natadd = 1; 3880ab25eeb5Syz155240 frentry_t *fr; 3881ab25eeb5Syz155240 nat_t *nat; 3882f4b3ec61Sdh155122 ipf_stack_t *ifs = fin->fin_ifs; 3883ab25eeb5Syz155240 38845b48165cSJohn Ojemann if (ifs->ifs_fr_nat_lock != 0) 38855b48165cSJohn Ojemann return 0; 38865b48165cSJohn Ojemann if (ifs->ifs_nat_stats.ns_rules == 0 && ifs->ifs_nat_instances == NULL) 3887ab25eeb5Syz155240 return 0; 3888ab25eeb5Syz155240 3889ab25eeb5Syz155240 natfailed = 0; 3890ab25eeb5Syz155240 fr = fin->fin_fr; 3891ab25eeb5Syz155240 sifp = fin->fin_ifp; 3892ab25eeb5Syz155240 if ((fr != NULL) && !(fr->fr_flags & FR_DUP) && 3893d3675867Sjojemann fr->fr_tifs[fin->fin_rev].fd_ifp && 3894d3675867Sjojemann fr->fr_tifs[fin->fin_rev].fd_ifp != (void *)-1) 3895d3675867Sjojemann fin->fin_ifp = fr->fr_tifs[fin->fin_rev].fd_ifp; 3896ab25eeb5Syz155240 ifp = fin->fin_ifp; 3897ab25eeb5Syz155240 3898ab25eeb5Syz155240 if (!(fin->fin_flx & FI_SHORT) && (fin->fin_off == 0)) { 3899ab25eeb5Syz155240 switch (fin->fin_p) 3900ab25eeb5Syz155240 { 3901ab25eeb5Syz155240 case IPPROTO_TCP : 3902ab25eeb5Syz155240 nflags = IPN_TCP; 3903ab25eeb5Syz155240 break; 3904ab25eeb5Syz155240 case IPPROTO_UDP : 3905ab25eeb5Syz155240 nflags = IPN_UDP; 3906ab25eeb5Syz155240 break; 3907ab25eeb5Syz155240 case IPPROTO_ICMP : 3908ab25eeb5Syz155240 icmp = fin->fin_dp; 3909ab25eeb5Syz155240 3910ab25eeb5Syz155240 /* 3911ab25eeb5Syz155240 * This is an incoming packet, so the destination is 3912ab25eeb5Syz155240 * the icmp_id and the source port equals 0 3913ab25eeb5Syz155240 */ 3914ab25eeb5Syz155240 if (nat_icmpquerytype4(icmp->icmp_type)) 3915ab25eeb5Syz155240 nflags = IPN_ICMPQUERY; 3916ab25eeb5Syz155240 break; 3917ab25eeb5Syz155240 default : 3918ab25eeb5Syz155240 break; 3919ab25eeb5Syz155240 } 3920ab25eeb5Syz155240 3921ab25eeb5Syz155240 if ((nflags & IPN_TCPUDP)) 3922ab25eeb5Syz155240 tcp = fin->fin_dp; 3923ab25eeb5Syz155240 } 3924ab25eeb5Syz155240 3925ab25eeb5Syz155240 ipa = fin->fin_saddr; 3926ab25eeb5Syz155240 3927f4b3ec61Sdh155122 READ_ENTER(&ifs->ifs_ipf_nat); 3928ab25eeb5Syz155240 3929ab25eeb5Syz155240 if ((fin->fin_p == IPPROTO_ICMP) && !(nflags & IPN_ICMPQUERY) && 3930ab25eeb5Syz155240 (nat = nat_icmperror(fin, &nflags, NAT_OUTBOUND))) 3931ab25eeb5Syz155240 /*EMPTY*/; 3932ab25eeb5Syz155240 else if ((fin->fin_flx & FI_FRAG) && (nat = fr_nat_knownfrag(fin))) 3933ab25eeb5Syz155240 natadd = 0; 3934ab25eeb5Syz155240 else if ((nat = nat_outlookup(fin, nflags|NAT_SEARCH, (u_int)fin->fin_p, 3935ab25eeb5Syz155240 fin->fin_src, fin->fin_dst))) { 3936ab25eeb5Syz155240 nflags = nat->nat_flags; 3937ab25eeb5Syz155240 } else { 3938ab25eeb5Syz155240 u_32_t hv, msk, nmsk; 3939ab25eeb5Syz155240 3940ab25eeb5Syz155240 /* 3941bb1d9de5SJohn Ojemann * There is no current entry in the nat table for this packet. 3942bb1d9de5SJohn Ojemann * 3943bb1d9de5SJohn Ojemann * If the packet is a fragment, but not the first fragment, 3944bb1d9de5SJohn Ojemann * then don't do anything. Otherwise, if there is a matching 3945bb1d9de5SJohn Ojemann * nat rule, try to create a new nat entry. 3946ab25eeb5Syz155240 */ 3947bb1d9de5SJohn Ojemann if ((fin->fin_off != 0) && (fin->fin_flx & FI_TCPUDP)) 3948bb1d9de5SJohn Ojemann goto nonatfrag; 3949bb1d9de5SJohn Ojemann 3950ab25eeb5Syz155240 msk = 0xffffffff; 3951f4b3ec61Sdh155122 nmsk = ifs->ifs_nat_masks; 3952ab25eeb5Syz155240 maskloop: 3953ab25eeb5Syz155240 iph = ipa & htonl(msk); 3954f4b3ec61Sdh155122 hv = NAT_HASH_FN(iph, 0, ifs->ifs_ipf_natrules_sz); 3955cbded9aeSdr146992 for (np = ifs->ifs_nat_rules[hv]; np; np = npnext) { 3956cbded9aeSdr146992 npnext = np->in_mnext; 3957e6c6c1faSyz155240 if ((np->in_ifps[1] && (np->in_ifps[1] != ifp))) 3958ab25eeb5Syz155240 continue; 3959ab25eeb5Syz155240 if (np->in_v != fin->fin_v) 3960ab25eeb5Syz155240 continue; 3961ab25eeb5Syz155240 if (np->in_p && (np->in_p != fin->fin_p)) 3962ab25eeb5Syz155240 continue; 3963ab25eeb5Syz155240 if ((np->in_flags & IPN_RF) && !(np->in_flags & nflags)) 3964ab25eeb5Syz155240 continue; 3965ab25eeb5Syz155240 if (np->in_flags & IPN_FILTER) { 3966ab25eeb5Syz155240 if (!nat_match(fin, np)) 3967ab25eeb5Syz155240 continue; 3968ab25eeb5Syz155240 } else if ((ipa & np->in_inmsk) != np->in_inip) 3969ab25eeb5Syz155240 continue; 3970ab25eeb5Syz155240 3971ab25eeb5Syz155240 if ((fr != NULL) && 3972ab25eeb5Syz155240 !fr_matchtag(&np->in_tag, &fr->fr_nattag)) 3973ab25eeb5Syz155240 continue; 3974ab25eeb5Syz155240 3975ab25eeb5Syz155240 if (*np->in_plabel != '\0') { 3976ab25eeb5Syz155240 if (((np->in_flags & IPN_FILTER) == 0) && 3977ab25eeb5Syz155240 (np->in_dport != tcp->th_dport)) 3978ab25eeb5Syz155240 continue; 3979ab25eeb5Syz155240 if (appr_ok(fin, tcp, np) == 0) 3980ab25eeb5Syz155240 continue; 3981ab25eeb5Syz155240 } 3982ab25eeb5Syz155240 3983cbded9aeSdr146992 ATOMIC_INC32(np->in_use); 3984cbded9aeSdr146992 RWLOCK_EXIT(&ifs->ifs_ipf_nat); 3985cbded9aeSdr146992 WRITE_ENTER(&ifs->ifs_ipf_nat); 3986cbded9aeSdr146992 nat = nat_new(fin, np, NULL, nflags, NAT_OUTBOUND); 3987cbded9aeSdr146992 if (nat != NULL) { 3988cbded9aeSdr146992 np->in_use--; 3989ab25eeb5Syz155240 np->in_hits++; 3990cbded9aeSdr146992 MUTEX_DOWNGRADE(&ifs->ifs_ipf_nat); 3991ab25eeb5Syz155240 break; 3992cbded9aeSdr146992 } 3993ab25eeb5Syz155240 natfailed = -1; 3994cbded9aeSdr146992 npnext = np->in_mnext; 3995cbded9aeSdr146992 fr_ipnatderef(&np, ifs); 3996cbded9aeSdr146992 MUTEX_DOWNGRADE(&ifs->ifs_ipf_nat); 3997ab25eeb5Syz155240 } 3998ab25eeb5Syz155240 if ((np == NULL) && (nmsk != 0)) { 3999ab25eeb5Syz155240 while (nmsk) { 4000ab25eeb5Syz155240 msk <<= 1; 4001ab25eeb5Syz155240 if (nmsk & 0x80000000) 4002ab25eeb5Syz155240 break; 4003ab25eeb5Syz155240 nmsk <<= 1; 4004ab25eeb5Syz155240 } 4005ab25eeb5Syz155240 if (nmsk != 0) { 4006ab25eeb5Syz155240 nmsk <<= 1; 4007ab25eeb5Syz155240 goto maskloop; 4008ab25eeb5Syz155240 } 4009ab25eeb5Syz155240 } 4010ab25eeb5Syz155240 } 4011ab25eeb5Syz155240 4012bb1d9de5SJohn Ojemann nonatfrag: 4013ab25eeb5Syz155240 if (nat != NULL) { 4014ab25eeb5Syz155240 rval = fr_natout(fin, nat, natadd, nflags); 4015ab25eeb5Syz155240 if (rval == 1) { 4016ab25eeb5Syz155240 MUTEX_ENTER(&nat->nat_lock); 401790907f62SJohn Ojemann nat_update(fin, nat, nat->nat_ptr); 401890907f62SJohn Ojemann nat->nat_bytes[1] += fin->fin_plen; 401990907f62SJohn Ojemann nat->nat_pkts[1]++; 402033f2fefdSDarren Reed fin->fin_pktnum = nat->nat_pkts[1]; 4021ab25eeb5Syz155240 MUTEX_EXIT(&nat->nat_lock); 4022ab25eeb5Syz155240 } 4023ab25eeb5Syz155240 } else 4024ab25eeb5Syz155240 rval = natfailed; 4025f4b3ec61Sdh155122 RWLOCK_EXIT(&ifs->ifs_ipf_nat); 4026ab25eeb5Syz155240 4027ab25eeb5Syz155240 if (rval == -1) { 4028ab25eeb5Syz155240 if (passp != NULL) 4029ab25eeb5Syz155240 *passp = FR_BLOCK; 4030ab25eeb5Syz155240 fin->fin_flx |= FI_BADNAT; 4031ab25eeb5Syz155240 } 4032ab25eeb5Syz155240 fin->fin_ifp = sifp; 4033ab25eeb5Syz155240 return rval; 4034ab25eeb5Syz155240 } 4035ab25eeb5Syz155240 4036ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */ 4037ab25eeb5Syz155240 /* Function: fr_natout */ 4038ab25eeb5Syz155240 /* Returns: int - -1 == packet failed NAT checks so block it, */ 4039ab25eeb5Syz155240 /* 1 == packet was successfully translated. */ 4040ab25eeb5Syz155240 /* Parameters: fin(I) - pointer to packet information */ 4041ab25eeb5Syz155240 /* nat(I) - pointer to NAT structure */ 4042ab25eeb5Syz155240 /* natadd(I) - flag indicating if it is safe to add frag cache */ 4043ab25eeb5Syz155240 /* nflags(I) - NAT flags set for this packet */ 4044ab25eeb5Syz155240 /* */ 4045ab25eeb5Syz155240 /* Translate a packet coming "out" on an interface. */ 4046ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */ 4047ab25eeb5Syz155240 int fr_natout(fin, nat, natadd, nflags) 4048ab25eeb5Syz155240 fr_info_t *fin; 4049ab25eeb5Syz155240 nat_t *nat; 4050ab25eeb5Syz155240 int natadd; 4051ab25eeb5Syz155240 u_32_t nflags; 4052ab25eeb5Syz155240 { 4053ab25eeb5Syz155240 icmphdr_t *icmp; 4054ab25eeb5Syz155240 u_short *csump; 4055381a2a9aSdr146992 u_32_t sumd; 4056ab25eeb5Syz155240 tcphdr_t *tcp; 4057ab25eeb5Syz155240 ipnat_t *np; 4058ab25eeb5Syz155240 int i; 4059f4b3ec61Sdh155122 ipf_stack_t *ifs = fin->fin_ifs; 4060ab25eeb5Syz155240 4061d6c23f6fSyx160601 if (fin->fin_v == 6) { 4062d6c23f6fSyx160601 #ifdef USE_INET6 4063d6c23f6fSyx160601 return fr_nat6out(fin, nat, natadd, nflags); 4064d6c23f6fSyx160601 #else 4065d6c23f6fSyx160601 return NULL; 4066d6c23f6fSyx160601 #endif 4067d6c23f6fSyx160601 } 4068d6c23f6fSyx160601 4069*f56257d8SToomas Soome #if defined(SOLARIS) && defined(_KERNEL) 40707ddc9b1aSDarren Reed net_handle_t net_data_p = ifs->ifs_ipf_ipv4; 4071381a2a9aSdr146992 #endif 4072381a2a9aSdr146992 4073ab25eeb5Syz155240 tcp = NULL; 4074ab25eeb5Syz155240 icmp = NULL; 4075ab25eeb5Syz155240 csump = NULL; 4076ab25eeb5Syz155240 np = nat->nat_ptr; 4077ab25eeb5Syz155240 407815013d88Szf203873 if ((natadd != 0) && (fin->fin_flx & FI_FRAG)) 4079ab25eeb5Syz155240 (void) fr_nat_newfrag(fin, 0, nat); 4080ab25eeb5Syz155240 4081ab25eeb5Syz155240 /* 4082ab25eeb5Syz155240 * Fix up checksums, not by recalculating them, but 4083ab25eeb5Syz155240 * simply computing adjustments. 4084ab25eeb5Syz155240 * This is only done for STREAMS based IP implementations where the 4085ab25eeb5Syz155240 * checksum has already been calculated by IP. In all other cases, 4086ab25eeb5Syz155240 * IPFilter is called before the checksum needs calculating so there 4087ab25eeb5Syz155240 * is no call to modify whatever is in the header now. 4088ab25eeb5Syz155240 */ 4089381a2a9aSdr146992 ASSERT(fin->fin_m != NULL); 4090381a2a9aSdr146992 if (fin->fin_v == 4 && !NET_IS_HCK_L3_FULL(net_data_p, fin->fin_m)) { 4091ab25eeb5Syz155240 if (nflags == IPN_ICMPERR) { 4092381a2a9aSdr146992 u_32_t s1, s2; 4093ab25eeb5Syz155240 4094ab25eeb5Syz155240 s1 = LONG_SUM(ntohl(fin->fin_saddr)); 4095ab25eeb5Syz155240 s2 = LONG_SUM(ntohl(nat->nat_outip.s_addr)); 4096ab25eeb5Syz155240 CALC_SUMD(s1, s2, sumd); 4097381a2a9aSdr146992 4098381a2a9aSdr146992 fix_outcksum(&fin->fin_ip->ip_sum, sumd); 4099ab25eeb5Syz155240 } 4100ab25eeb5Syz155240 #if !defined(_KERNEL) || defined(MENTAT) || defined(__sgi) || \ 4101ab25eeb5Syz155240 defined(linux) || defined(BRIDGE_IPF) 4102ab25eeb5Syz155240 else { 4103ab25eeb5Syz155240 /* 4104ab25eeb5Syz155240 * Strictly speaking, this isn't necessary on BSD 4105ab25eeb5Syz155240 * kernels because they do checksum calculation after 4106ab25eeb5Syz155240 * this code has run BUT if ipfilter is being used 4107ab25eeb5Syz155240 * to do NAT as a bridge, that code doesn't exist. 4108ab25eeb5Syz155240 */ 4109ab25eeb5Syz155240 if (nat->nat_dir == NAT_OUTBOUND) 4110381a2a9aSdr146992 fix_outcksum(&fin->fin_ip->ip_sum, 4111ab25eeb5Syz155240 nat->nat_ipsumd); 4112ab25eeb5Syz155240 else 4113381a2a9aSdr146992 fix_incksum(&fin->fin_ip->ip_sum, 4114ab25eeb5Syz155240 nat->nat_ipsumd); 4115ab25eeb5Syz155240 } 4116ab25eeb5Syz155240 #endif 4117ab25eeb5Syz155240 } 4118ab25eeb5Syz155240 4119ab25eeb5Syz155240 if (!(fin->fin_flx & FI_SHORT) && (fin->fin_off == 0)) { 4120ab25eeb5Syz155240 if ((nat->nat_outport != 0) && (nflags & IPN_TCPUDP)) { 4121ab25eeb5Syz155240 tcp = fin->fin_dp; 4122ab25eeb5Syz155240 4123ab25eeb5Syz155240 tcp->th_sport = nat->nat_outport; 4124ab25eeb5Syz155240 fin->fin_data[0] = ntohs(nat->nat_outport); 4125ab25eeb5Syz155240 } 4126ab25eeb5Syz155240 4127ab25eeb5Syz155240 if ((nat->nat_outport != 0) && (nflags & IPN_ICMPQUERY)) { 4128ab25eeb5Syz155240 icmp = fin->fin_dp; 4129ab25eeb5Syz155240 icmp->icmp_id = nat->nat_outport; 4130ab25eeb5Syz155240 } 4131ab25eeb5Syz155240 4132ab25eeb5Syz155240 csump = nat_proto(fin, nat, nflags); 4133ab25eeb5Syz155240 } 4134ab25eeb5Syz155240 4135ab25eeb5Syz155240 fin->fin_ip->ip_src = nat->nat_outip; 4136ab25eeb5Syz155240 4137ab25eeb5Syz155240 /* 4138ab25eeb5Syz155240 * The above comments do not hold for layer 4 (or higher) checksums... 4139ab25eeb5Syz155240 */ 4140381a2a9aSdr146992 if (csump != NULL && !NET_IS_HCK_L4_FULL(net_data_p, fin->fin_m)) { 4141381a2a9aSdr146992 if (nflags & IPN_TCPUDP && 4142381a2a9aSdr146992 NET_IS_HCK_L4_PART(net_data_p, fin->fin_m)) 4143381a2a9aSdr146992 sumd = nat->nat_sumd[1]; 4144ab25eeb5Syz155240 else 4145381a2a9aSdr146992 sumd = nat->nat_sumd[0]; 4146381a2a9aSdr146992 4147381a2a9aSdr146992 if (nat->nat_dir == NAT_OUTBOUND) 4148381a2a9aSdr146992 fix_outcksum(csump, sumd); 4149381a2a9aSdr146992 else 4150381a2a9aSdr146992 fix_incksum(csump, sumd); 4151ab25eeb5Syz155240 } 4152ab25eeb5Syz155240 #ifdef IPFILTER_SYNC 4153ab25eeb5Syz155240 ipfsync_update(SMC_NAT, fin, nat->nat_sync); 4154ab25eeb5Syz155240 #endif 4155ab25eeb5Syz155240 /* ------------------------------------------------------------- */ 4156ab25eeb5Syz155240 /* A few quick notes: */ 4157ab25eeb5Syz155240 /* Following are test conditions prior to calling the */ 4158ab25eeb5Syz155240 /* appr_check routine. */ 4159ab25eeb5Syz155240 /* */ 4160ab25eeb5Syz155240 /* A NULL tcp indicates a non TCP/UDP packet. When dealing */ 4161ab25eeb5Syz155240 /* with a redirect rule, we attempt to match the packet's */ 4162ab25eeb5Syz155240 /* source port against in_dport, otherwise we'd compare the */ 4163ab25eeb5Syz155240 /* packet's destination. */ 4164ab25eeb5Syz155240 /* ------------------------------------------------------------- */ 4165ab25eeb5Syz155240 if ((np != NULL) && (np->in_apr != NULL)) { 4166ab25eeb5Syz155240 i = appr_check(fin, nat); 4167ab25eeb5Syz155240 if (i == 0) 4168ab25eeb5Syz155240 i = 1; 4169ab25eeb5Syz155240 } else 4170ab25eeb5Syz155240 i = 1; 4171cbded9aeSdr146992 ifs->ifs_nat_stats.ns_mapped[1]++; 4172ab25eeb5Syz155240 fin->fin_flx |= FI_NATED; 4173ab25eeb5Syz155240 return i; 4174ab25eeb5Syz155240 } 4175ab25eeb5Syz155240 4176ab25eeb5Syz155240 4177ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */ 4178ab25eeb5Syz155240 /* Function: fr_checknatin */ 4179ab25eeb5Syz155240 /* Returns: int - -1 == packet failed NAT checks so block it, */ 4180ab25eeb5Syz155240 /* 0 == no packet translation occurred, */ 4181ab25eeb5Syz155240 /* 1 == packet was successfully translated. */ 4182ab25eeb5Syz155240 /* Parameters: fin(I) - pointer to packet information */ 4183ab25eeb5Syz155240 /* passp(I) - pointer to filtering result flags */ 4184ab25eeb5Syz155240 /* */ 4185ab25eeb5Syz155240 /* Check to see if an incoming packet should be changed. ICMP packets are */ 4186ab25eeb5Syz155240 /* first checked to see if they match an existing entry (if an error), */ 4187ab25eeb5Syz155240 /* otherwise a search of the current NAT table is made. If neither results */ 4188ab25eeb5Syz155240 /* in a match then a search for a matching NAT rule is made. Create a new */ 4189ab25eeb5Syz155240 /* NAT entry if a we matched a NAT rule. Lastly, actually change the */ 4190ab25eeb5Syz155240 /* packet header(s) as required. */ 4191ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */ 4192ab25eeb5Syz155240 int fr_checknatin(fin, passp) 4193ab25eeb5Syz155240 fr_info_t *fin; 4194ab25eeb5Syz155240 u_32_t *passp; 4195ab25eeb5Syz155240 { 4196ab25eeb5Syz155240 u_int nflags, natadd; 4197cbded9aeSdr146992 ipnat_t *np, *npnext; 4198ab25eeb5Syz155240 int rval, natfailed; 4199ab25eeb5Syz155240 struct ifnet *ifp; 4200ab25eeb5Syz155240 struct in_addr in; 4201ab25eeb5Syz155240 icmphdr_t *icmp; 4202ab25eeb5Syz155240 tcphdr_t *tcp; 4203ab25eeb5Syz155240 u_short dport; 4204ab25eeb5Syz155240 nat_t *nat; 4205ab25eeb5Syz155240 u_32_t iph; 4206f4b3ec61Sdh155122 ipf_stack_t *ifs = fin->fin_ifs; 4207ab25eeb5Syz155240 42085b48165cSJohn Ojemann if (ifs->ifs_fr_nat_lock != 0) 42095b48165cSJohn Ojemann return 0; 42105b48165cSJohn Ojemann if (ifs->ifs_nat_stats.ns_rules == 0 && ifs->ifs_nat_instances == NULL) 4211ab25eeb5Syz155240 return 0; 4212ab25eeb5Syz155240 4213ab25eeb5Syz155240 tcp = NULL; 4214ab25eeb5Syz155240 icmp = NULL; 4215ab25eeb5Syz155240 dport = 0; 4216ab25eeb5Syz155240 natadd = 1; 4217ab25eeb5Syz155240 nflags = 0; 4218ab25eeb5Syz155240 natfailed = 0; 4219ab25eeb5Syz155240 ifp = fin->fin_ifp; 4220ab25eeb5Syz155240 4221ab25eeb5Syz155240 if (!(fin->fin_flx & FI_SHORT) && (fin->fin_off == 0)) { 4222ab25eeb5Syz155240 switch (fin->fin_p) 4223ab25eeb5Syz155240 { 4224ab25eeb5Syz155240 case IPPROTO_TCP : 4225ab25eeb5Syz155240 nflags = IPN_TCP; 4226ab25eeb5Syz155240 break; 4227ab25eeb5Syz155240 case IPPROTO_UDP : 4228ab25eeb5Syz155240 nflags = IPN_UDP; 4229ab25eeb5Syz155240 break; 4230ab25eeb5Syz155240 case IPPROTO_ICMP : 4231ab25eeb5Syz155240 icmp = fin->fin_dp; 4232ab25eeb5Syz155240 4233ab25eeb5Syz155240 /* 4234ab25eeb5Syz155240 * This is an incoming packet, so the destination is 4235ab25eeb5Syz155240 * the icmp_id and the source port equals 0 4236ab25eeb5Syz155240 */ 4237ab25eeb5Syz155240 if (nat_icmpquerytype4(icmp->icmp_type)) { 4238ab25eeb5Syz155240 nflags = IPN_ICMPQUERY; 4239ab25eeb5Syz155240 dport = icmp->icmp_id; 4240ab25eeb5Syz155240 } break; 4241ab25eeb5Syz155240 default : 4242ab25eeb5Syz155240 break; 4243ab25eeb5Syz155240 } 4244ab25eeb5Syz155240 4245ab25eeb5Syz155240 if ((nflags & IPN_TCPUDP)) { 4246ab25eeb5Syz155240 tcp = fin->fin_dp; 4247ab25eeb5Syz155240 dport = tcp->th_dport; 4248ab25eeb5Syz155240 } 4249ab25eeb5Syz155240 } 4250ab25eeb5Syz155240 4251ab25eeb5Syz155240 in = fin->fin_dst; 4252ab25eeb5Syz155240 4253f4b3ec61Sdh155122 READ_ENTER(&ifs->ifs_ipf_nat); 4254ab25eeb5Syz155240 4255ab25eeb5Syz155240 if ((fin->fin_p == IPPROTO_ICMP) && !(nflags & IPN_ICMPQUERY) && 4256ab25eeb5Syz155240 (nat = nat_icmperror(fin, &nflags, NAT_INBOUND))) 4257ab25eeb5Syz155240 /*EMPTY*/; 4258ab25eeb5Syz155240 else if ((fin->fin_flx & FI_FRAG) && (nat = fr_nat_knownfrag(fin))) 4259ab25eeb5Syz155240 natadd = 0; 4260ab25eeb5Syz155240 else if ((nat = nat_inlookup(fin, nflags|NAT_SEARCH, (u_int)fin->fin_p, 4261ab25eeb5Syz155240 fin->fin_src, in))) { 4262ab25eeb5Syz155240 nflags = nat->nat_flags; 4263ab25eeb5Syz155240 } else { 4264ab25eeb5Syz155240 u_32_t hv, msk, rmsk; 4265ab25eeb5Syz155240 4266bb1d9de5SJohn Ojemann /* 4267bb1d9de5SJohn Ojemann * There is no current entry in the nat table for this packet. 4268bb1d9de5SJohn Ojemann * 4269bb1d9de5SJohn Ojemann * If the packet is a fragment, but not the first fragment, 4270bb1d9de5SJohn Ojemann * then don't do anything. Otherwise, if there is a matching 4271bb1d9de5SJohn Ojemann * nat rule, try to create a new nat entry. 4272bb1d9de5SJohn Ojemann */ 4273bb1d9de5SJohn Ojemann if ((fin->fin_off != 0) && (fin->fin_flx & FI_TCPUDP)) 4274bb1d9de5SJohn Ojemann goto nonatfrag; 4275bb1d9de5SJohn Ojemann 4276f4b3ec61Sdh155122 rmsk = ifs->ifs_rdr_masks; 4277ab25eeb5Syz155240 msk = 0xffffffff; 4278ab25eeb5Syz155240 maskloop: 4279ab25eeb5Syz155240 iph = in.s_addr & htonl(msk); 4280f4b3ec61Sdh155122 hv = NAT_HASH_FN(iph, 0, ifs->ifs_ipf_rdrrules_sz); 4281cbded9aeSdr146992 for (np = ifs->ifs_rdr_rules[hv]; np; np = npnext) { 4282cbded9aeSdr146992 npnext = np->in_rnext; 4283ab25eeb5Syz155240 if (np->in_ifps[0] && (np->in_ifps[0] != ifp)) 4284ab25eeb5Syz155240 continue; 4285ab25eeb5Syz155240 if (np->in_v != fin->fin_v) 4286ab25eeb5Syz155240 continue; 4287ab25eeb5Syz155240 if (np->in_p && (np->in_p != fin->fin_p)) 4288ab25eeb5Syz155240 continue; 4289ab25eeb5Syz155240 if ((np->in_flags & IPN_RF) && !(np->in_flags & nflags)) 4290ab25eeb5Syz155240 continue; 4291ab25eeb5Syz155240 if (np->in_flags & IPN_FILTER) { 4292ab25eeb5Syz155240 if (!nat_match(fin, np)) 4293ab25eeb5Syz155240 continue; 4294ab25eeb5Syz155240 } else { 4295ab25eeb5Syz155240 if ((in.s_addr & np->in_outmsk) != np->in_outip) 4296ab25eeb5Syz155240 continue; 4297ab25eeb5Syz155240 if (np->in_pmin && 4298ab25eeb5Syz155240 ((ntohs(np->in_pmax) < ntohs(dport)) || 4299ab25eeb5Syz155240 (ntohs(dport) < ntohs(np->in_pmin)))) 4300ab25eeb5Syz155240 continue; 4301ab25eeb5Syz155240 } 4302ab25eeb5Syz155240 4303ab25eeb5Syz155240 if (*np->in_plabel != '\0') { 4304ab25eeb5Syz155240 if (!appr_ok(fin, tcp, np)) { 4305ab25eeb5Syz155240 continue; 4306ab25eeb5Syz155240 } 4307ab25eeb5Syz155240 } 4308ab25eeb5Syz155240 4309cbded9aeSdr146992 ATOMIC_INC32(np->in_use); 4310cbded9aeSdr146992 RWLOCK_EXIT(&ifs->ifs_ipf_nat); 4311cbded9aeSdr146992 WRITE_ENTER(&ifs->ifs_ipf_nat); 4312ab25eeb5Syz155240 nat = nat_new(fin, np, NULL, nflags, NAT_INBOUND); 4313ab25eeb5Syz155240 if (nat != NULL) { 4314cbded9aeSdr146992 np->in_use--; 4315ab25eeb5Syz155240 np->in_hits++; 4316cbded9aeSdr146992 MUTEX_DOWNGRADE(&ifs->ifs_ipf_nat); 4317ab25eeb5Syz155240 break; 4318cbded9aeSdr146992 } 4319ab25eeb5Syz155240 natfailed = -1; 4320cbded9aeSdr146992 npnext = np->in_rnext; 4321cbded9aeSdr146992 fr_ipnatderef(&np, ifs); 4322cbded9aeSdr146992 MUTEX_DOWNGRADE(&ifs->ifs_ipf_nat); 4323ab25eeb5Syz155240 } 4324ab25eeb5Syz155240 4325ab25eeb5Syz155240 if ((np == NULL) && (rmsk != 0)) { 4326ab25eeb5Syz155240 while (rmsk) { 4327ab25eeb5Syz155240 msk <<= 1; 4328ab25eeb5Syz155240 if (rmsk & 0x80000000) 4329ab25eeb5Syz155240 break; 4330ab25eeb5Syz155240 rmsk <<= 1; 4331ab25eeb5Syz155240 } 4332ab25eeb5Syz155240 if (rmsk != 0) { 4333ab25eeb5Syz155240 rmsk <<= 1; 4334ab25eeb5Syz155240 goto maskloop; 4335ab25eeb5Syz155240 } 4336ab25eeb5Syz155240 } 4337ab25eeb5Syz155240 } 4338bb1d9de5SJohn Ojemann 4339bb1d9de5SJohn Ojemann nonatfrag: 4340ab25eeb5Syz155240 if (nat != NULL) { 4341ab25eeb5Syz155240 rval = fr_natin(fin, nat, natadd, nflags); 4342ab25eeb5Syz155240 if (rval == 1) { 4343ab25eeb5Syz155240 MUTEX_ENTER(&nat->nat_lock); 434490907f62SJohn Ojemann nat_update(fin, nat, nat->nat_ptr); 434590907f62SJohn Ojemann nat->nat_bytes[0] += fin->fin_plen; 434690907f62SJohn Ojemann nat->nat_pkts[0]++; 434733f2fefdSDarren Reed fin->fin_pktnum = nat->nat_pkts[0]; 4348ab25eeb5Syz155240 MUTEX_EXIT(&nat->nat_lock); 4349ab25eeb5Syz155240 } 4350ab25eeb5Syz155240 } else 4351ab25eeb5Syz155240 rval = natfailed; 4352f4b3ec61Sdh155122 RWLOCK_EXIT(&ifs->ifs_ipf_nat); 4353ab25eeb5Syz155240 4354ab25eeb5Syz155240 if (rval == -1) { 4355ab25eeb5Syz155240 if (passp != NULL) 4356ab25eeb5Syz155240 *passp = FR_BLOCK; 4357ab25eeb5Syz155240 fin->fin_flx |= FI_BADNAT; 4358ab25eeb5Syz155240 } 4359ab25eeb5Syz155240 return rval; 4360ab25eeb5Syz155240 } 4361ab25eeb5Syz155240 4362ab25eeb5Syz155240 4363ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */ 4364ab25eeb5Syz155240 /* Function: fr_natin */ 4365ab25eeb5Syz155240 /* Returns: int - -1 == packet failed NAT checks so block it, */ 4366ab25eeb5Syz155240 /* 1 == packet was successfully translated. */ 4367ab25eeb5Syz155240 /* Parameters: fin(I) - pointer to packet information */ 4368ab25eeb5Syz155240 /* nat(I) - pointer to NAT structure */ 4369ab25eeb5Syz155240 /* natadd(I) - flag indicating if it is safe to add frag cache */ 4370ab25eeb5Syz155240 /* nflags(I) - NAT flags set for this packet */ 4371ab25eeb5Syz155240 /* Locks Held: ipf_nat (READ) */ 4372ab25eeb5Syz155240 /* */ 4373ab25eeb5Syz155240 /* Translate a packet coming "in" on an interface. */ 4374ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */ 4375ab25eeb5Syz155240 int fr_natin(fin, nat, natadd, nflags) 4376ab25eeb5Syz155240 fr_info_t *fin; 4377ab25eeb5Syz155240 nat_t *nat; 4378ab25eeb5Syz155240 int natadd; 4379ab25eeb5Syz155240 u_32_t nflags; 4380ab25eeb5Syz155240 { 4381ab25eeb5Syz155240 icmphdr_t *icmp; 438224109627Syx160601 u_short *csump; 4383ab25eeb5Syz155240 tcphdr_t *tcp; 4384ab25eeb5Syz155240 ipnat_t *np; 4385ab25eeb5Syz155240 int i; 4386f4b3ec61Sdh155122 ipf_stack_t *ifs = fin->fin_ifs; 4387ab25eeb5Syz155240 4388d6c23f6fSyx160601 if (fin->fin_v == 6) { 4389d6c23f6fSyx160601 #ifdef USE_INET6 4390d6c23f6fSyx160601 return fr_nat6in(fin, nat, natadd, nflags); 4391d6c23f6fSyx160601 #else 4392d6c23f6fSyx160601 return NULL; 4393d6c23f6fSyx160601 #endif 4394d6c23f6fSyx160601 } 4395d6c23f6fSyx160601 4396*f56257d8SToomas Soome #if defined(SOLARIS) && defined(_KERNEL) 43977ddc9b1aSDarren Reed net_handle_t net_data_p = ifs->ifs_ipf_ipv4; 4398381a2a9aSdr146992 #endif 4399381a2a9aSdr146992 4400ab25eeb5Syz155240 tcp = NULL; 4401ab25eeb5Syz155240 csump = NULL; 4402ab25eeb5Syz155240 np = nat->nat_ptr; 4403ab25eeb5Syz155240 fin->fin_fr = nat->nat_fr; 4404ab25eeb5Syz155240 4405ab25eeb5Syz155240 if ((natadd != 0) && (fin->fin_flx & FI_FRAG)) 4406ab25eeb5Syz155240 (void) fr_nat_newfrag(fin, 0, nat); 4407ab25eeb5Syz155240 440815013d88Szf203873 if (np != NULL) { 440915013d88Szf203873 4410ab25eeb5Syz155240 /* ------------------------------------------------------------- */ 4411ab25eeb5Syz155240 /* A few quick notes: */ 4412ab25eeb5Syz155240 /* Following are test conditions prior to calling the */ 4413ab25eeb5Syz155240 /* appr_check routine. */ 4414ab25eeb5Syz155240 /* */ 4415ab25eeb5Syz155240 /* A NULL tcp indicates a non TCP/UDP packet. When dealing */ 4416ab25eeb5Syz155240 /* with a map rule, we attempt to match the packet's */ 4417ab25eeb5Syz155240 /* source port against in_dport, otherwise we'd compare the */ 4418ab25eeb5Syz155240 /* packet's destination. */ 4419ab25eeb5Syz155240 /* ------------------------------------------------------------- */ 4420ab25eeb5Syz155240 if (np->in_apr != NULL) { 4421ab25eeb5Syz155240 i = appr_check(fin, nat); 4422ab25eeb5Syz155240 if (i == -1) { 4423ab25eeb5Syz155240 return -1; 4424ab25eeb5Syz155240 } 4425ab25eeb5Syz155240 } 4426ab25eeb5Syz155240 } 4427ab25eeb5Syz155240 4428ab25eeb5Syz155240 #ifdef IPFILTER_SYNC 4429ab25eeb5Syz155240 ipfsync_update(SMC_NAT, fin, nat->nat_sync); 4430ab25eeb5Syz155240 #endif 4431ab25eeb5Syz155240 4432ab25eeb5Syz155240 fin->fin_ip->ip_dst = nat->nat_inip; 4433ab25eeb5Syz155240 fin->fin_fi.fi_daddr = nat->nat_inip.s_addr; 4434ab25eeb5Syz155240 if (nflags & IPN_TCPUDP) 4435ab25eeb5Syz155240 tcp = fin->fin_dp; 4436ab25eeb5Syz155240 4437ab25eeb5Syz155240 /* 4438ab25eeb5Syz155240 * Fix up checksums, not by recalculating them, but 4439ab25eeb5Syz155240 * simply computing adjustments. 4440ab25eeb5Syz155240 * Why only do this for some platforms on inbound packets ? 4441ab25eeb5Syz155240 * Because for those that it is done, IP processing is yet to happen 4442ab25eeb5Syz155240 * and so the IPv4 header checksum has not yet been evaluated. 4443ab25eeb5Syz155240 * Perhaps it should always be done for the benefit of things like 4444ab25eeb5Syz155240 * fast forwarding (so that it doesn't need to be recomputed) but with 4445ab25eeb5Syz155240 * header checksum offloading, perhaps it is a moot point. 4446ab25eeb5Syz155240 */ 4447ab25eeb5Syz155240 #if !defined(_KERNEL) || defined(MENTAT) || defined(__sgi) || \ 4448ab25eeb5Syz155240 defined(__osf__) || defined(linux) 4449ab25eeb5Syz155240 if (nat->nat_dir == NAT_OUTBOUND) 4450381a2a9aSdr146992 fix_incksum(&fin->fin_ip->ip_sum, nat->nat_ipsumd); 4451ab25eeb5Syz155240 else 4452381a2a9aSdr146992 fix_outcksum(&fin->fin_ip->ip_sum, nat->nat_ipsumd); 4453ab25eeb5Syz155240 #endif 4454ab25eeb5Syz155240 4455ab25eeb5Syz155240 if (!(fin->fin_flx & FI_SHORT) && (fin->fin_off == 0)) { 4456ab25eeb5Syz155240 if ((nat->nat_inport != 0) && (nflags & IPN_TCPUDP)) { 4457ab25eeb5Syz155240 tcp->th_dport = nat->nat_inport; 4458ab25eeb5Syz155240 fin->fin_data[1] = ntohs(nat->nat_inport); 4459ab25eeb5Syz155240 } 4460ab25eeb5Syz155240 4461ab25eeb5Syz155240 4462ab25eeb5Syz155240 if ((nat->nat_inport != 0) && (nflags & IPN_ICMPQUERY)) { 4463ab25eeb5Syz155240 icmp = fin->fin_dp; 4464ab25eeb5Syz155240 4465ab25eeb5Syz155240 icmp->icmp_id = nat->nat_inport; 4466ab25eeb5Syz155240 } 4467ab25eeb5Syz155240 4468ab25eeb5Syz155240 csump = nat_proto(fin, nat, nflags); 4469ab25eeb5Syz155240 } 4470ab25eeb5Syz155240 4471ab25eeb5Syz155240 /* 447224109627Syx160601 * In case they are being forwarded, inbound packets always need to have 447324109627Syx160601 * their checksum adjusted even if hardware checksum validation said OK. 4474ab25eeb5Syz155240 */ 4475ab25eeb5Syz155240 if (csump != NULL) { 4476ab25eeb5Syz155240 if (nat->nat_dir == NAT_OUTBOUND) 447724109627Syx160601 fix_incksum(csump, nat->nat_sumd[0]); 4478ab25eeb5Syz155240 else 447924109627Syx160601 fix_outcksum(csump, nat->nat_sumd[0]); 4480ab25eeb5Syz155240 } 448124109627Syx160601 4482*f56257d8SToomas Soome #if defined(SOLARIS) && defined(_KERNEL) 448324109627Syx160601 if (nflags & IPN_TCPUDP && 448424109627Syx160601 NET_IS_HCK_L4_PART(net_data_p, fin->fin_m)) { 448524109627Syx160601 /* 448624109627Syx160601 * Need to adjust the partial checksum result stored in 448724109627Syx160601 * db_cksum16, which will be used for validation in IP. 448824109627Syx160601 * See IP_CKSUM_RECV(). 448924109627Syx160601 * Adjustment data should be the inverse of the IP address 449024109627Syx160601 * changes, because db_cksum16 is supposed to be the complement 449124109627Syx160601 * of the pesudo header. 449224109627Syx160601 */ 449324109627Syx160601 csump = &fin->fin_m->b_datap->db_cksum16; 449424109627Syx160601 if (nat->nat_dir == NAT_OUTBOUND) 449524109627Syx160601 fix_outcksum(csump, nat->nat_sumd[1]); 449624109627Syx160601 else 449724109627Syx160601 fix_incksum(csump, nat->nat_sumd[1]); 449824109627Syx160601 } 449924109627Syx160601 #endif 450024109627Syx160601 4501cbded9aeSdr146992 ifs->ifs_nat_stats.ns_mapped[0]++; 4502ab25eeb5Syz155240 fin->fin_flx |= FI_NATED; 4503ab25eeb5Syz155240 if (np != NULL && np->in_tag.ipt_num[0] != 0) 4504ab25eeb5Syz155240 fin->fin_nattag = &np->in_tag; 4505ab25eeb5Syz155240 return 1; 4506ab25eeb5Syz155240 } 4507ab25eeb5Syz155240 4508ab25eeb5Syz155240 4509ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */ 4510ab25eeb5Syz155240 /* Function: nat_proto */ 4511ab25eeb5Syz155240 /* Returns: u_short* - pointer to transport header checksum to update, */ 4512ab25eeb5Syz155240 /* NULL if the transport protocol is not recognised */ 4513ab25eeb5Syz155240 /* as needing a checksum update. */ 4514ab25eeb5Syz155240 /* Parameters: fin(I) - pointer to packet information */ 4515ab25eeb5Syz155240 /* nat(I) - pointer to NAT structure */ 4516ab25eeb5Syz155240 /* nflags(I) - NAT flags set for this packet */ 4517ab25eeb5Syz155240 /* */ 4518ab25eeb5Syz155240 /* Return the pointer to the checksum field for each protocol so understood.*/ 4519ab25eeb5Syz155240 /* If support for making other changes to a protocol header is required, */ 4520ab25eeb5Syz155240 /* that is not strictly 'address' translation, such as clamping the MSS in */ 4521ab25eeb5Syz155240 /* TCP down to a specific value, then do it from here. */ 4522ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */ 4523ab25eeb5Syz155240 u_short *nat_proto(fin, nat, nflags) 4524ab25eeb5Syz155240 fr_info_t *fin; 4525ab25eeb5Syz155240 nat_t *nat; 4526ab25eeb5Syz155240 u_int nflags; 4527ab25eeb5Syz155240 { 4528ab25eeb5Syz155240 icmphdr_t *icmp; 4529d6c23f6fSyx160601 struct icmp6_hdr *icmp6; 4530ab25eeb5Syz155240 u_short *csump; 4531ab25eeb5Syz155240 tcphdr_t *tcp; 4532ab25eeb5Syz155240 udphdr_t *udp; 4533ab25eeb5Syz155240 4534ab25eeb5Syz155240 csump = NULL; 4535ab25eeb5Syz155240 if (fin->fin_out == 0) { 4536ab25eeb5Syz155240 fin->fin_rev = (nat->nat_dir == NAT_OUTBOUND); 4537ab25eeb5Syz155240 } else { 4538ab25eeb5Syz155240 fin->fin_rev = (nat->nat_dir == NAT_INBOUND); 4539ab25eeb5Syz155240 } 4540ab25eeb5Syz155240 4541ab25eeb5Syz155240 switch (fin->fin_p) 4542ab25eeb5Syz155240 { 4543ab25eeb5Syz155240 case IPPROTO_TCP : 4544ab25eeb5Syz155240 tcp = fin->fin_dp; 4545ab25eeb5Syz155240 4546ab25eeb5Syz155240 csump = &tcp->th_sum; 4547ab25eeb5Syz155240 4548ab25eeb5Syz155240 /* 4549ab25eeb5Syz155240 * Do a MSS CLAMPING on a SYN packet, 4550ab25eeb5Syz155240 * only deal IPv4 for now. 4551ab25eeb5Syz155240 */ 4552ab25eeb5Syz155240 if ((nat->nat_mssclamp != 0) && (tcp->th_flags & TH_SYN) != 0) 4553381a2a9aSdr146992 nat_mssclamp(tcp, nat->nat_mssclamp, csump); 4554ab25eeb5Syz155240 4555ab25eeb5Syz155240 break; 4556ab25eeb5Syz155240 4557ab25eeb5Syz155240 case IPPROTO_UDP : 4558ab25eeb5Syz155240 udp = fin->fin_dp; 4559ab25eeb5Syz155240 4560ab25eeb5Syz155240 if (udp->uh_sum) 4561ab25eeb5Syz155240 csump = &udp->uh_sum; 4562ab25eeb5Syz155240 break; 4563ab25eeb5Syz155240 4564ab25eeb5Syz155240 case IPPROTO_ICMP : 4565ab25eeb5Syz155240 icmp = fin->fin_dp; 4566ab25eeb5Syz155240 4567ab25eeb5Syz155240 if ((nflags & IPN_ICMPQUERY) != 0) { 4568ab25eeb5Syz155240 if (icmp->icmp_cksum != 0) 4569ab25eeb5Syz155240 csump = &icmp->icmp_cksum; 4570ab25eeb5Syz155240 } 4571ab25eeb5Syz155240 break; 4572d6c23f6fSyx160601 4573d6c23f6fSyx160601 case IPPROTO_ICMPV6 : 4574d6c23f6fSyx160601 icmp6 = fin->fin_dp; 4575d6c23f6fSyx160601 4576d6c23f6fSyx160601 if ((nflags & IPN_ICMPQUERY) != 0) { 4577d6c23f6fSyx160601 if (icmp6->icmp6_cksum != 0) 4578d6c23f6fSyx160601 csump = &icmp6->icmp6_cksum; 4579d6c23f6fSyx160601 } 4580d6c23f6fSyx160601 break; 4581ab25eeb5Syz155240 } 4582ab25eeb5Syz155240 return csump; 4583ab25eeb5Syz155240 } 4584ab25eeb5Syz155240 4585ab25eeb5Syz155240 4586ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */ 4587ab25eeb5Syz155240 /* Function: fr_natunload */ 4588ab25eeb5Syz155240 /* Returns: Nil */ 4589ea8244dcSJohn Ojemann /* Parameters: ifs - ipf stack instance */ 4590ab25eeb5Syz155240 /* */ 4591ab25eeb5Syz155240 /* Free all memory used by NAT structures allocated at runtime. */ 4592ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */ 4593f4b3ec61Sdh155122 void fr_natunload(ifs) 4594f4b3ec61Sdh155122 ipf_stack_t *ifs; 4595ab25eeb5Syz155240 { 4596ab25eeb5Syz155240 ipftq_t *ifq, *ifqnext; 4597ab25eeb5Syz155240 4598f4b3ec61Sdh155122 (void) nat_clearlist(ifs); 4599ea8244dcSJohn Ojemann (void) nat_flushtable(FLUSH_TABLE_ALL, ifs); 4600ab25eeb5Syz155240 4601ab25eeb5Syz155240 /* 4602ab25eeb5Syz155240 * Proxy timeout queues are not cleaned here because although they 4603ab25eeb5Syz155240 * exist on the NAT list, appr_unload is called after fr_natunload 4604ab25eeb5Syz155240 * and the proxies actually are responsible for them being created. 4605ab25eeb5Syz155240 * Should the proxy timeouts have their own list? There's no real 4606ab25eeb5Syz155240 * justification as this is the only complication. 4607ab25eeb5Syz155240 */ 4608f4b3ec61Sdh155122 for (ifq = ifs->ifs_nat_utqe; ifq != NULL; ifq = ifqnext) { 4609ab25eeb5Syz155240 ifqnext = ifq->ifq_next; 4610ab25eeb5Syz155240 if (((ifq->ifq_flags & IFQF_PROXY) == 0) && 4611ab25eeb5Syz155240 (fr_deletetimeoutqueue(ifq) == 0)) 4612f4b3ec61Sdh155122 fr_freetimeoutqueue(ifq, ifs); 4613ab25eeb5Syz155240 } 4614ab25eeb5Syz155240 4615f4b3ec61Sdh155122 if (ifs->ifs_nat_table[0] != NULL) { 4616f4b3ec61Sdh155122 KFREES(ifs->ifs_nat_table[0], 4617f4b3ec61Sdh155122 sizeof(nat_t *) * ifs->ifs_ipf_nattable_sz); 4618f4b3ec61Sdh155122 ifs->ifs_nat_table[0] = NULL; 4619ab25eeb5Syz155240 } 4620f4b3ec61Sdh155122 if (ifs->ifs_nat_table[1] != NULL) { 4621f4b3ec61Sdh155122 KFREES(ifs->ifs_nat_table[1], 4622f4b3ec61Sdh155122 sizeof(nat_t *) * ifs->ifs_ipf_nattable_sz); 4623f4b3ec61Sdh155122 ifs->ifs_nat_table[1] = NULL; 4624ab25eeb5Syz155240 } 4625f4b3ec61Sdh155122 if (ifs->ifs_nat_rules != NULL) { 4626f4b3ec61Sdh155122 KFREES(ifs->ifs_nat_rules, 4627f4b3ec61Sdh155122 sizeof(ipnat_t *) * ifs->ifs_ipf_natrules_sz); 4628f4b3ec61Sdh155122 ifs->ifs_nat_rules = NULL; 4629ab25eeb5Syz155240 } 4630f4b3ec61Sdh155122 if (ifs->ifs_rdr_rules != NULL) { 4631f4b3ec61Sdh155122 KFREES(ifs->ifs_rdr_rules, 4632f4b3ec61Sdh155122 sizeof(ipnat_t *) * ifs->ifs_ipf_rdrrules_sz); 4633f4b3ec61Sdh155122 ifs->ifs_rdr_rules = NULL; 4634ab25eeb5Syz155240 } 4635f4b3ec61Sdh155122 if (ifs->ifs_maptable != NULL) { 4636f4b3ec61Sdh155122 KFREES(ifs->ifs_maptable, 4637f4b3ec61Sdh155122 sizeof(hostmap_t *) * ifs->ifs_ipf_hostmap_sz); 4638f4b3ec61Sdh155122 ifs->ifs_maptable = NULL; 4639ab25eeb5Syz155240 } 4640f4b3ec61Sdh155122 if (ifs->ifs_nat_stats.ns_bucketlen[0] != NULL) { 4641f4b3ec61Sdh155122 KFREES(ifs->ifs_nat_stats.ns_bucketlen[0], 4642f4b3ec61Sdh155122 sizeof(u_long *) * ifs->ifs_ipf_nattable_sz); 4643f4b3ec61Sdh155122 ifs->ifs_nat_stats.ns_bucketlen[0] = NULL; 4644ab25eeb5Syz155240 } 4645f4b3ec61Sdh155122 if (ifs->ifs_nat_stats.ns_bucketlen[1] != NULL) { 4646f4b3ec61Sdh155122 KFREES(ifs->ifs_nat_stats.ns_bucketlen[1], 4647f4b3ec61Sdh155122 sizeof(u_long *) * ifs->ifs_ipf_nattable_sz); 4648f4b3ec61Sdh155122 ifs->ifs_nat_stats.ns_bucketlen[1] = NULL; 4649ab25eeb5Syz155240 } 4650ab25eeb5Syz155240 4651f4b3ec61Sdh155122 if (ifs->ifs_fr_nat_maxbucket_reset == 1) 4652f4b3ec61Sdh155122 ifs->ifs_fr_nat_maxbucket = 0; 4653ab25eeb5Syz155240 4654f4b3ec61Sdh155122 if (ifs->ifs_fr_nat_init == 1) { 4655f4b3ec61Sdh155122 ifs->ifs_fr_nat_init = 0; 4656f4b3ec61Sdh155122 fr_sttab_destroy(ifs->ifs_nat_tqb); 4657ab25eeb5Syz155240 4658f4b3ec61Sdh155122 RW_DESTROY(&ifs->ifs_ipf_natfrag); 4659f4b3ec61Sdh155122 RW_DESTROY(&ifs->ifs_ipf_nat); 4660ab25eeb5Syz155240 4661f4b3ec61Sdh155122 MUTEX_DESTROY(&ifs->ifs_ipf_nat_new); 4662f4b3ec61Sdh155122 MUTEX_DESTROY(&ifs->ifs_ipf_natio); 4663ab25eeb5Syz155240 4664f4b3ec61Sdh155122 MUTEX_DESTROY(&ifs->ifs_nat_udptq.ifq_lock); 4665f4b3ec61Sdh155122 MUTEX_DESTROY(&ifs->ifs_nat_icmptq.ifq_lock); 4666f4b3ec61Sdh155122 MUTEX_DESTROY(&ifs->ifs_nat_iptq.ifq_lock); 4667ab25eeb5Syz155240 } 4668ab25eeb5Syz155240 } 4669ab25eeb5Syz155240 4670ab25eeb5Syz155240 4671ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */ 4672ab25eeb5Syz155240 /* Function: fr_natexpire */ 4673ab25eeb5Syz155240 /* Returns: Nil */ 4674ea8244dcSJohn Ojemann /* Parameters: ifs - ipf stack instance */ 4675ab25eeb5Syz155240 /* */ 4676ab25eeb5Syz155240 /* Check all of the timeout queues for entries at the top which need to be */ 4677ab25eeb5Syz155240 /* expired. */ 4678ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */ 4679f4b3ec61Sdh155122 void fr_natexpire(ifs) 4680f4b3ec61Sdh155122 ipf_stack_t *ifs; 4681ab25eeb5Syz155240 { 4682ab25eeb5Syz155240 ipftq_t *ifq, *ifqnext; 4683ab25eeb5Syz155240 ipftqent_t *tqe, *tqn; 4684ab25eeb5Syz155240 int i; 4685ab25eeb5Syz155240 SPL_INT(s); 4686ab25eeb5Syz155240 4687ab25eeb5Syz155240 SPL_NET(s); 4688f4b3ec61Sdh155122 WRITE_ENTER(&ifs->ifs_ipf_nat); 4689f4b3ec61Sdh155122 for (ifq = ifs->ifs_nat_tqb, i = 0; ifq != NULL; ifq = ifq->ifq_next) { 4690ab25eeb5Syz155240 for (tqn = ifq->ifq_head; ((tqe = tqn) != NULL); i++) { 4691f4b3ec61Sdh155122 if (tqe->tqe_die > ifs->ifs_fr_ticks) 4692ab25eeb5Syz155240 break; 4693ab25eeb5Syz155240 tqn = tqe->tqe_next; 4694ea8244dcSJohn Ojemann (void) nat_delete(tqe->tqe_parent, NL_EXPIRE, ifs); 4695ab25eeb5Syz155240 } 4696ab25eeb5Syz155240 } 4697ab25eeb5Syz155240 4698f4b3ec61Sdh155122 for (ifq = ifs->ifs_nat_utqe; ifq != NULL; ifq = ifqnext) { 4699ab25eeb5Syz155240 ifqnext = ifq->ifq_next; 4700ab25eeb5Syz155240 4701ab25eeb5Syz155240 for (tqn = ifq->ifq_head; ((tqe = tqn) != NULL); i++) { 4702f4b3ec61Sdh155122 if (tqe->tqe_die > ifs->ifs_fr_ticks) 4703ab25eeb5Syz155240 break; 4704ab25eeb5Syz155240 tqn = tqe->tqe_next; 4705ea8244dcSJohn Ojemann (void) nat_delete(tqe->tqe_parent, NL_EXPIRE, ifs); 4706ab25eeb5Syz155240 } 4707ab25eeb5Syz155240 } 4708ab25eeb5Syz155240 4709f4b3ec61Sdh155122 for (ifq = ifs->ifs_nat_utqe; ifq != NULL; ifq = ifqnext) { 4710ab25eeb5Syz155240 ifqnext = ifq->ifq_next; 4711ab25eeb5Syz155240 4712ab25eeb5Syz155240 if (((ifq->ifq_flags & IFQF_DELETE) != 0) && 4713ab25eeb5Syz155240 (ifq->ifq_ref == 0)) { 4714f4b3ec61Sdh155122 fr_freetimeoutqueue(ifq, ifs); 4715ab25eeb5Syz155240 } 4716ab25eeb5Syz155240 } 4717ab25eeb5Syz155240 47183805c50fSan207044 if (ifs->ifs_nat_doflush != 0) { 4719ea8244dcSJohn Ojemann (void) nat_flushtable(FLUSH_TABLE_EXTRA, ifs); 47203805c50fSan207044 ifs->ifs_nat_doflush = 0; 47213805c50fSan207044 } 47223805c50fSan207044 4723f4b3ec61Sdh155122 RWLOCK_EXIT(&ifs->ifs_ipf_nat); 4724ab25eeb5Syz155240 SPL_X(s); 4725ab25eeb5Syz155240 } 4726ab25eeb5Syz155240 4727ab25eeb5Syz155240 4728ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */ 4729381a2a9aSdr146992 /* Function: fr_nataddrsync */ 4730ab25eeb5Syz155240 /* Returns: Nil */ 4731ab25eeb5Syz155240 /* Parameters: ifp(I) - pointer to network interface */ 4732381a2a9aSdr146992 /* addr(I) - pointer to new network address */ 4733ab25eeb5Syz155240 /* */ 4734ab25eeb5Syz155240 /* Walk through all of the currently active NAT sessions, looking for those */ 4735381a2a9aSdr146992 /* which need to have their translated address updated (where the interface */ 4736381a2a9aSdr146992 /* matches the one passed in) and change it, recalculating the checksum sum */ 4737381a2a9aSdr146992 /* difference too. */ 4738ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */ 4739d6c23f6fSyx160601 void fr_nataddrsync(v, ifp, addr, ifs) 4740d6c23f6fSyx160601 int v; 4741ab25eeb5Syz155240 void *ifp; 4742d6c23f6fSyx160601 void *addr; 4743f4b3ec61Sdh155122 ipf_stack_t *ifs; 4744ab25eeb5Syz155240 { 4745ab25eeb5Syz155240 u_32_t sum1, sum2, sumd; 4746ab25eeb5Syz155240 nat_t *nat; 4747381a2a9aSdr146992 ipnat_t *np; 4748ab25eeb5Syz155240 SPL_INT(s); 4749ab25eeb5Syz155240 4750f4b3ec61Sdh155122 if (ifs->ifs_fr_running <= 0) 4751ab25eeb5Syz155240 return; 4752ab25eeb5Syz155240 4753ab25eeb5Syz155240 SPL_NET(s); 4754f4b3ec61Sdh155122 WRITE_ENTER(&ifs->ifs_ipf_nat); 4755ab25eeb5Syz155240 4756f4b3ec61Sdh155122 if (ifs->ifs_fr_running <= 0) { 4757f4b3ec61Sdh155122 RWLOCK_EXIT(&ifs->ifs_ipf_nat); 4758ab25eeb5Syz155240 return; 4759ab25eeb5Syz155240 } 4760ab25eeb5Syz155240 4761381a2a9aSdr146992 /* 4762381a2a9aSdr146992 * Change IP addresses for NAT sessions for any protocol except TCP 4763381a2a9aSdr146992 * since it will break the TCP connection anyway. The only rules 4764381a2a9aSdr146992 * which will get changed are those which are "map ... -> 0/32", 4765381a2a9aSdr146992 * where the rule specifies the address is taken from the interface. 4766381a2a9aSdr146992 */ 4767f4b3ec61Sdh155122 for (nat = ifs->ifs_nat_instances; nat; nat = nat->nat_next) { 4768381a2a9aSdr146992 if (addr != NULL) { 4769381a2a9aSdr146992 if (((ifp != NULL) && ifp != (nat->nat_ifps[0])) || 4770381a2a9aSdr146992 ((nat->nat_flags & IPN_TCP) != 0)) 4771ab25eeb5Syz155240 continue; 4772d6c23f6fSyx160601 if ((np = nat->nat_ptr) == NULL) 4773ab25eeb5Syz155240 continue; 4774d6c23f6fSyx160601 if (v == 4 && np->in_v == 4) { 4775d6c23f6fSyx160601 if (np->in_nip || np->in_outmsk != 0xffffffff) 4776d6c23f6fSyx160601 continue; 4777ab25eeb5Syz155240 /* 4778d6c23f6fSyx160601 * Change the map-to address to be the same as 4779d6c23f6fSyx160601 * the new one. 4780ab25eeb5Syz155240 */ 4781ab25eeb5Syz155240 sum1 = nat->nat_outip.s_addr; 4782d6c23f6fSyx160601 nat->nat_outip = *(struct in_addr *)addr; 4783381a2a9aSdr146992 sum2 = nat->nat_outip.s_addr; 4784d6c23f6fSyx160601 } else if (v == 6 && np->in_v == 6) { 4785d6c23f6fSyx160601 if (!IP6_ISZERO(&np->in_next6.in6) || 4786d6c23f6fSyx160601 !IP6_ISONES(&np->in_out[1].in6)) 4787d6c23f6fSyx160601 continue; 4788d6c23f6fSyx160601 /* 4789d6c23f6fSyx160601 * Change the map-to address to be the same as 4790d6c23f6fSyx160601 * the new one. 4791d6c23f6fSyx160601 */ 4792d6c23f6fSyx160601 nat->nat_outip6.in6 = *(struct in6_addr *)addr; 4793d6c23f6fSyx160601 } else 4794d6c23f6fSyx160601 continue; 4795381a2a9aSdr146992 4796381a2a9aSdr146992 } else if (((ifp == NULL) || (ifp == nat->nat_ifps[0])) && 4797d6c23f6fSyx160601 !(nat->nat_flags & IPN_TCP) && (np = nat->nat_ptr)) { 4798d6c23f6fSyx160601 if (np->in_v == 4 && (v == 4 || v == 0)) { 4799381a2a9aSdr146992 struct in_addr in; 4800d6c23f6fSyx160601 if (np->in_outmsk != 0xffffffff || np->in_nip) 4801d6c23f6fSyx160601 continue; 4802381a2a9aSdr146992 /* 4803d6c23f6fSyx160601 * Change the map-to address to be the same as 4804d6c23f6fSyx160601 * the new one. 4805381a2a9aSdr146992 */ 4806381a2a9aSdr146992 sum1 = nat->nat_outip.s_addr; 4807381a2a9aSdr146992 if (fr_ifpaddr(4, FRI_NORMAL, nat->nat_ifps[0], 4808f4b3ec61Sdh155122 &in, NULL, ifs) != -1) 4809ab25eeb5Syz155240 nat->nat_outip = in; 4810ab25eeb5Syz155240 sum2 = nat->nat_outip.s_addr; 4811d6c23f6fSyx160601 } else if (np->in_v == 6 && (v == 6 || v == 0)) { 4812d6c23f6fSyx160601 struct in6_addr in6; 4813d6c23f6fSyx160601 if (!IP6_ISZERO(&np->in_next6.in6) || 4814d6c23f6fSyx160601 !IP6_ISONES(&np->in_out[1].in6)) 4815d6c23f6fSyx160601 continue; 4816d6c23f6fSyx160601 /* 4817d6c23f6fSyx160601 * Change the map-to address to be the same as 4818d6c23f6fSyx160601 * the new one. 4819d6c23f6fSyx160601 */ 4820d6c23f6fSyx160601 if (fr_ifpaddr(6, FRI_NORMAL, nat->nat_ifps[0], 4821d6c23f6fSyx160601 (void *)&in6, NULL, ifs) != -1) 4822d6c23f6fSyx160601 nat->nat_outip6.in6 = in6; 4823d6c23f6fSyx160601 } else 4824d6c23f6fSyx160601 continue; 4825381a2a9aSdr146992 } else { 4826381a2a9aSdr146992 continue; 4827381a2a9aSdr146992 } 4828ab25eeb5Syz155240 4829ab25eeb5Syz155240 if (sum1 == sum2) 4830ab25eeb5Syz155240 continue; 4831ab25eeb5Syz155240 /* 4832ab25eeb5Syz155240 * Readjust the checksum adjustment to take into 4833ab25eeb5Syz155240 * account the new IP#. 4834ab25eeb5Syz155240 */ 4835ab25eeb5Syz155240 CALC_SUMD(sum1, sum2, sumd); 4836ab25eeb5Syz155240 /* XXX - dont change for TCP when solaris does 4837ab25eeb5Syz155240 * hardware checksumming. 4838ab25eeb5Syz155240 */ 4839ab25eeb5Syz155240 sumd += nat->nat_sumd[0]; 4840ab25eeb5Syz155240 nat->nat_sumd[0] = (sumd & 0xffff) + (sumd >> 16); 4841ab25eeb5Syz155240 nat->nat_sumd[1] = nat->nat_sumd[0]; 4842ab25eeb5Syz155240 } 4843381a2a9aSdr146992 4844f4b3ec61Sdh155122 RWLOCK_EXIT(&ifs->ifs_ipf_nat); 4845381a2a9aSdr146992 SPL_X(s); 4846381a2a9aSdr146992 } 4847381a2a9aSdr146992 4848381a2a9aSdr146992 4849381a2a9aSdr146992 /* ------------------------------------------------------------------------ */ 4850381a2a9aSdr146992 /* Function: fr_natifpsync */ 4851381a2a9aSdr146992 /* Returns: Nil */ 4852381a2a9aSdr146992 /* Parameters: action(I) - how we are syncing */ 4853381a2a9aSdr146992 /* ifp(I) - pointer to network interface */ 4854381a2a9aSdr146992 /* name(I) - name of interface to sync to */ 4855381a2a9aSdr146992 /* */ 4856381a2a9aSdr146992 /* This function is used to resync the mapping of interface names and their */ 4857381a2a9aSdr146992 /* respective 'pointers'. For "action == IPFSYNC_RESYNC", resync all */ 4858381a2a9aSdr146992 /* interfaces by doing a new lookup of name to 'pointer'. For "action == */ 4859381a2a9aSdr146992 /* IPFSYNC_NEWIFP", treat ifp as the new pointer value associated with */ 4860381a2a9aSdr146992 /* "name" and for "action == IPFSYNC_OLDIFP", ifp is a pointer for which */ 4861381a2a9aSdr146992 /* there is no longer any interface associated with it. */ 4862381a2a9aSdr146992 /* ------------------------------------------------------------------------ */ 4863d6c23f6fSyx160601 void fr_natifpsync(action, v, ifp, name, ifs) 4864d6c23f6fSyx160601 int action, v; 4865381a2a9aSdr146992 void *ifp; 4866381a2a9aSdr146992 char *name; 4867f4b3ec61Sdh155122 ipf_stack_t *ifs; 4868381a2a9aSdr146992 { 4869381a2a9aSdr146992 #if defined(_KERNEL) && !defined(MENTAT) && defined(USE_SPL) 4870381a2a9aSdr146992 int s; 4871381a2a9aSdr146992 #endif 4872381a2a9aSdr146992 nat_t *nat; 4873381a2a9aSdr146992 ipnat_t *n; 4874d6c23f6fSyx160601 int nv; 4875381a2a9aSdr146992 4876f4b3ec61Sdh155122 if (ifs->ifs_fr_running <= 0) 4877381a2a9aSdr146992 return; 4878381a2a9aSdr146992 4879381a2a9aSdr146992 SPL_NET(s); 4880f4b3ec61Sdh155122 WRITE_ENTER(&ifs->ifs_ipf_nat); 4881381a2a9aSdr146992 4882f4b3ec61Sdh155122 if (ifs->ifs_fr_running <= 0) { 4883f4b3ec61Sdh155122 RWLOCK_EXIT(&ifs->ifs_ipf_nat); 4884381a2a9aSdr146992 return; 4885381a2a9aSdr146992 } 4886381a2a9aSdr146992 4887381a2a9aSdr146992 switch (action) 4888381a2a9aSdr146992 { 4889381a2a9aSdr146992 case IPFSYNC_RESYNC : 4890f4b3ec61Sdh155122 for (nat = ifs->ifs_nat_instances; nat; nat = nat->nat_next) { 4891d6c23f6fSyx160601 nv = (v == 0) ? nat->nat_v : v; 4892d6c23f6fSyx160601 if (nat->nat_v != nv) 4893d6c23f6fSyx160601 continue; 4894381a2a9aSdr146992 if ((ifp == nat->nat_ifps[0]) || 4895381a2a9aSdr146992 (nat->nat_ifps[0] == (void *)-1)) { 4896381a2a9aSdr146992 nat->nat_ifps[0] = 4897d6c23f6fSyx160601 fr_resolvenic(nat->nat_ifnames[0], nv, ifs); 4898381a2a9aSdr146992 } 4899381a2a9aSdr146992 4900381a2a9aSdr146992 if ((ifp == nat->nat_ifps[1]) || 4901381a2a9aSdr146992 (nat->nat_ifps[1] == (void *)-1)) { 4902381a2a9aSdr146992 nat->nat_ifps[1] = 4903d6c23f6fSyx160601 fr_resolvenic(nat->nat_ifnames[1], nv, ifs); 4904381a2a9aSdr146992 } 4905ab25eeb5Syz155240 } 4906ab25eeb5Syz155240 4907f4b3ec61Sdh155122 for (n = ifs->ifs_nat_list; (n != NULL); n = n->in_next) { 4908d6c23f6fSyx160601 nv = (v == 0) ? (int)n->in_v : v; 4909d6c23f6fSyx160601 if ((int)n->in_v != nv) 4910d6c23f6fSyx160601 continue; 4911381a2a9aSdr146992 if (n->in_ifps[0] == ifp || 4912381a2a9aSdr146992 n->in_ifps[0] == (void *)-1) { 4913381a2a9aSdr146992 n->in_ifps[0] = 4914d6c23f6fSyx160601 fr_resolvenic(n->in_ifnames[0], nv, ifs); 4915381a2a9aSdr146992 } 4916381a2a9aSdr146992 if (n->in_ifps[1] == ifp || 4917381a2a9aSdr146992 n->in_ifps[1] == (void *)-1) { 4918381a2a9aSdr146992 n->in_ifps[1] = 4919d6c23f6fSyx160601 fr_resolvenic(n->in_ifnames[1], nv, ifs); 4920381a2a9aSdr146992 } 4921381a2a9aSdr146992 } 4922381a2a9aSdr146992 break; 4923381a2a9aSdr146992 case IPFSYNC_NEWIFP : 4924f4b3ec61Sdh155122 for (nat = ifs->ifs_nat_instances; nat; nat = nat->nat_next) { 4925d6c23f6fSyx160601 if (nat->nat_v != v) 4926d6c23f6fSyx160601 continue; 4927381a2a9aSdr146992 if (!strncmp(name, nat->nat_ifnames[0], 4928381a2a9aSdr146992 sizeof(nat->nat_ifnames[0]))) 4929381a2a9aSdr146992 nat->nat_ifps[0] = ifp; 4930381a2a9aSdr146992 if (!strncmp(name, nat->nat_ifnames[1], 4931381a2a9aSdr146992 sizeof(nat->nat_ifnames[1]))) 4932381a2a9aSdr146992 nat->nat_ifps[1] = ifp; 4933381a2a9aSdr146992 } 4934f4b3ec61Sdh155122 for (n = ifs->ifs_nat_list; (n != NULL); n = n->in_next) { 4935d6c23f6fSyx160601 if ((int)n->in_v != v) 4936d6c23f6fSyx160601 continue; 4937381a2a9aSdr146992 if (!strncmp(name, n->in_ifnames[0], 4938381a2a9aSdr146992 sizeof(n->in_ifnames[0]))) 4939381a2a9aSdr146992 n->in_ifps[0] = ifp; 4940381a2a9aSdr146992 if (!strncmp(name, n->in_ifnames[1], 4941381a2a9aSdr146992 sizeof(n->in_ifnames[1]))) 4942381a2a9aSdr146992 n->in_ifps[1] = ifp; 4943381a2a9aSdr146992 } 4944381a2a9aSdr146992 break; 4945381a2a9aSdr146992 case IPFSYNC_OLDIFP : 4946f4b3ec61Sdh155122 for (nat = ifs->ifs_nat_instances; nat; nat = nat->nat_next) { 4947d6c23f6fSyx160601 if (nat->nat_v != v) 4948d6c23f6fSyx160601 continue; 4949381a2a9aSdr146992 if (ifp == nat->nat_ifps[0]) 4950381a2a9aSdr146992 nat->nat_ifps[0] = (void *)-1; 4951381a2a9aSdr146992 if (ifp == nat->nat_ifps[1]) 4952381a2a9aSdr146992 nat->nat_ifps[1] = (void *)-1; 4953381a2a9aSdr146992 } 4954f4b3ec61Sdh155122 for (n = ifs->ifs_nat_list; (n != NULL); n = n->in_next) { 4955d6c23f6fSyx160601 if ((int)n->in_v != v) 4956d6c23f6fSyx160601 continue; 4957381a2a9aSdr146992 if (n->in_ifps[0] == ifp) 4958381a2a9aSdr146992 n->in_ifps[0] = (void *)-1; 4959381a2a9aSdr146992 if (n->in_ifps[1] == ifp) 4960381a2a9aSdr146992 n->in_ifps[1] = (void *)-1; 4961381a2a9aSdr146992 } 4962381a2a9aSdr146992 break; 4963ab25eeb5Syz155240 } 4964f4b3ec61Sdh155122 RWLOCK_EXIT(&ifs->ifs_ipf_nat); 4965ab25eeb5Syz155240 SPL_X(s); 4966ab25eeb5Syz155240 } 4967ab25eeb5Syz155240 4968e8d569f4SAlexandr Nedvedicky #if SOLARIS2 >= 10 4969e8d569f4SAlexandr Nedvedicky /* ------------------------------------------------------------------------ */ 4970e8d569f4SAlexandr Nedvedicky /* Function: fr_natifindexsync */ 4971e8d569f4SAlexandr Nedvedicky /* Returns: void */ 4972e8d569f4SAlexandr Nedvedicky /* Parameters: ifp - interface, which is being sync'd */ 4973e8d569f4SAlexandr Nedvedicky /* newifp - new ifindex value for interface */ 4974e8d569f4SAlexandr Nedvedicky /* ifs - IPF's stack */ 4975e8d569f4SAlexandr Nedvedicky /* */ 4976e8d569f4SAlexandr Nedvedicky /* Write Locks: assumes ipf_mutex is locked */ 4977e8d569f4SAlexandr Nedvedicky /* */ 4978e8d569f4SAlexandr Nedvedicky /* Updates all interface index references in NAT rules and NAT entries. */ 4979e8d569f4SAlexandr Nedvedicky /* the index, which is about to be updated must match ifp value. */ 4980e8d569f4SAlexandr Nedvedicky /* ------------------------------------------------------------------------ */ 4981e8d569f4SAlexandr Nedvedicky void fr_natifindexsync(ifp, newifp, ifs) 4982e8d569f4SAlexandr Nedvedicky void *ifp; 4983e8d569f4SAlexandr Nedvedicky void *newifp; 4984e8d569f4SAlexandr Nedvedicky ipf_stack_t *ifs; 4985e8d569f4SAlexandr Nedvedicky { 4986e8d569f4SAlexandr Nedvedicky nat_t *nat; 4987e8d569f4SAlexandr Nedvedicky ipnat_t *n; 4988e8d569f4SAlexandr Nedvedicky 4989e8d569f4SAlexandr Nedvedicky WRITE_ENTER(&ifs->ifs_ipf_nat); 4990e8d569f4SAlexandr Nedvedicky 4991e8d569f4SAlexandr Nedvedicky for (nat = ifs->ifs_nat_instances; nat != NULL; nat = nat->nat_next) { 4992e8d569f4SAlexandr Nedvedicky if (ifp == nat->nat_ifps[0]) 4993e8d569f4SAlexandr Nedvedicky nat->nat_ifps[0] = newifp; 4994e8d569f4SAlexandr Nedvedicky 4995e8d569f4SAlexandr Nedvedicky if (ifp == nat->nat_ifps[1]) 4996e8d569f4SAlexandr Nedvedicky nat->nat_ifps[1] = newifp; 4997e8d569f4SAlexandr Nedvedicky } 4998e8d569f4SAlexandr Nedvedicky 4999e8d569f4SAlexandr Nedvedicky for (n = ifs->ifs_nat_list; n != NULL; n = n->in_next) { 5000e8d569f4SAlexandr Nedvedicky if (ifp == n->in_ifps[0]) 5001e8d569f4SAlexandr Nedvedicky n->in_ifps[0] = newifp; 5002e8d569f4SAlexandr Nedvedicky 5003e8d569f4SAlexandr Nedvedicky if (ifp == n->in_ifps[1]) 5004e8d569f4SAlexandr Nedvedicky n->in_ifps[1] = newifp; 5005e8d569f4SAlexandr Nedvedicky } 5006e8d569f4SAlexandr Nedvedicky 5007e8d569f4SAlexandr Nedvedicky RWLOCK_EXIT(&ifs->ifs_ipf_nat); 5008e8d569f4SAlexandr Nedvedicky } 5009e8d569f4SAlexandr Nedvedicky #endif 5010ab25eeb5Syz155240 5011ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */ 5012ab25eeb5Syz155240 /* Function: nat_icmpquerytype4 */ 5013ab25eeb5Syz155240 /* Returns: int - 1 == success, 0 == failure */ 5014ab25eeb5Syz155240 /* Parameters: icmptype(I) - ICMP type number */ 5015ab25eeb5Syz155240 /* */ 5016ab25eeb5Syz155240 /* Tests to see if the ICMP type number passed is a query/response type or */ 5017ab25eeb5Syz155240 /* not. */ 5018ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */ 5019ab25eeb5Syz155240 static INLINE int nat_icmpquerytype4(icmptype) 5020ab25eeb5Syz155240 int icmptype; 5021ab25eeb5Syz155240 { 5022ab25eeb5Syz155240 5023ab25eeb5Syz155240 /* 5024ab25eeb5Syz155240 * For the ICMP query NAT code, it is essential that both the query 5025ab25eeb5Syz155240 * and the reply match on the NAT rule. Because the NAT structure 5026ab25eeb5Syz155240 * does not keep track of the icmptype, and a single NAT structure 5027ab25eeb5Syz155240 * is used for all icmp types with the same src, dest and id, we 5028ab25eeb5Syz155240 * simply define the replies as queries as well. The funny thing is, 5029ab25eeb5Syz155240 * altough it seems silly to call a reply a query, this is exactly 5030ab25eeb5Syz155240 * as it is defined in the IPv4 specification 5031ab25eeb5Syz155240 */ 5032ab25eeb5Syz155240 5033ab25eeb5Syz155240 switch (icmptype) 5034ab25eeb5Syz155240 { 5035ab25eeb5Syz155240 5036ab25eeb5Syz155240 case ICMP_ECHOREPLY: 5037ab25eeb5Syz155240 case ICMP_ECHO: 5038ab25eeb5Syz155240 /* route aedvertisement/solliciation is currently unsupported: */ 5039ab25eeb5Syz155240 /* it would require rewriting the ICMP data section */ 5040ab25eeb5Syz155240 case ICMP_TSTAMP: 5041ab25eeb5Syz155240 case ICMP_TSTAMPREPLY: 5042ab25eeb5Syz155240 case ICMP_IREQ: 5043ab25eeb5Syz155240 case ICMP_IREQREPLY: 5044ab25eeb5Syz155240 case ICMP_MASKREQ: 5045ab25eeb5Syz155240 case ICMP_MASKREPLY: 5046ab25eeb5Syz155240 return 1; 5047ab25eeb5Syz155240 default: 5048ab25eeb5Syz155240 return 0; 5049ab25eeb5Syz155240 } 5050ab25eeb5Syz155240 } 5051ab25eeb5Syz155240 5052ab25eeb5Syz155240 5053ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */ 5054ab25eeb5Syz155240 /* Function: nat_log */ 5055ab25eeb5Syz155240 /* Returns: Nil */ 5056ab25eeb5Syz155240 /* Parameters: nat(I) - pointer to NAT structure */ 5057ab25eeb5Syz155240 /* type(I) - type of log entry to create */ 5058ab25eeb5Syz155240 /* */ 5059ab25eeb5Syz155240 /* Creates a NAT log entry. */ 5060ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */ 5061f4b3ec61Sdh155122 void nat_log(nat, type, ifs) 5062ab25eeb5Syz155240 struct nat *nat; 5063ab25eeb5Syz155240 u_int type; 5064f4b3ec61Sdh155122 ipf_stack_t *ifs; 5065ab25eeb5Syz155240 { 5066ab25eeb5Syz155240 #ifdef IPFILTER_LOG 5067ab25eeb5Syz155240 # ifndef LARGE_NAT 5068ab25eeb5Syz155240 struct ipnat *np; 5069ab25eeb5Syz155240 int rulen; 5070ab25eeb5Syz155240 # endif 5071ab25eeb5Syz155240 struct natlog natl; 5072ab25eeb5Syz155240 void *items[1]; 5073ab25eeb5Syz155240 size_t sizes[1]; 5074ab25eeb5Syz155240 int types[1]; 5075ab25eeb5Syz155240 5076d6c23f6fSyx160601 natl.nlg_inip = nat->nat_inip6; 5077d6c23f6fSyx160601 natl.nlg_outip = nat->nat_outip6; 5078d6c23f6fSyx160601 natl.nlg_origip = nat->nat_oip6; 5079d6c23f6fSyx160601 natl.nlg_bytes[0] = nat->nat_bytes[0]; 5080d6c23f6fSyx160601 natl.nlg_bytes[1] = nat->nat_bytes[1]; 5081d6c23f6fSyx160601 natl.nlg_pkts[0] = nat->nat_pkts[0]; 5082d6c23f6fSyx160601 natl.nlg_pkts[1] = nat->nat_pkts[1]; 5083d6c23f6fSyx160601 natl.nlg_origport = nat->nat_oport; 5084d6c23f6fSyx160601 natl.nlg_inport = nat->nat_inport; 5085d6c23f6fSyx160601 natl.nlg_outport = nat->nat_outport; 5086d6c23f6fSyx160601 natl.nlg_p = nat->nat_p; 5087d6c23f6fSyx160601 natl.nlg_type = type; 5088d6c23f6fSyx160601 natl.nlg_rule = -1; 5089d6c23f6fSyx160601 natl.nlg_v = nat->nat_v; 5090ab25eeb5Syz155240 # ifndef LARGE_NAT 5091ab25eeb5Syz155240 if (nat->nat_ptr != NULL) { 5092f4b3ec61Sdh155122 for (rulen = 0, np = ifs->ifs_nat_list; np; 5093f4b3ec61Sdh155122 np = np->in_next, rulen++) 5094ab25eeb5Syz155240 if (np == nat->nat_ptr) { 5095d6c23f6fSyx160601 natl.nlg_rule = rulen; 5096ab25eeb5Syz155240 break; 5097ab25eeb5Syz155240 } 5098ab25eeb5Syz155240 } 5099ab25eeb5Syz155240 # endif 5100ab25eeb5Syz155240 items[0] = &natl; 5101ab25eeb5Syz155240 sizes[0] = sizeof(natl); 5102ab25eeb5Syz155240 types[0] = 0; 5103ab25eeb5Syz155240 5104f4b3ec61Sdh155122 (void) ipllog(IPL_LOGNAT, NULL, items, sizes, types, 1, ifs); 5105ab25eeb5Syz155240 #endif 5106ab25eeb5Syz155240 } 5107ab25eeb5Syz155240 5108ab25eeb5Syz155240 5109ab25eeb5Syz155240 #if defined(__OpenBSD__) 5110ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */ 5111ab25eeb5Syz155240 /* Function: nat_ifdetach */ 5112ab25eeb5Syz155240 /* Returns: Nil */ 5113ab25eeb5Syz155240 /* Parameters: ifp(I) - pointer to network interface */ 5114ab25eeb5Syz155240 /* */ 5115ab25eeb5Syz155240 /* Compatibility interface for OpenBSD to trigger the correct updating of */ 5116ab25eeb5Syz155240 /* interface references within IPFilter. */ 5117ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */ 5118f4b3ec61Sdh155122 void nat_ifdetach(ifp, ifs) 5119ab25eeb5Syz155240 void *ifp; 5120f4b3ec61Sdh155122 ipf_stack_t *ifs; 5121ab25eeb5Syz155240 { 5122f4b3ec61Sdh155122 frsync(ifp, ifs); 5123ab25eeb5Syz155240 return; 5124ab25eeb5Syz155240 } 5125ab25eeb5Syz155240 #endif 5126ab25eeb5Syz155240 5127ab25eeb5Syz155240 5128ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */ 5129f4b3ec61Sdh155122 /* Function: fr_ipnatderef */ 5130f4b3ec61Sdh155122 /* Returns: Nil */ 5131cbded9aeSdr146992 /* Parameters: inp(I) - pointer to pointer to NAT rule */ 5132f4b3ec61Sdh155122 /* Write Locks: ipf_nat */ 5133f4b3ec61Sdh155122 /* */ 5134f4b3ec61Sdh155122 /* ------------------------------------------------------------------------ */ 5135f4b3ec61Sdh155122 void fr_ipnatderef(inp, ifs) 5136f4b3ec61Sdh155122 ipnat_t **inp; 5137f4b3ec61Sdh155122 ipf_stack_t *ifs; 5138f4b3ec61Sdh155122 { 5139f4b3ec61Sdh155122 ipnat_t *in; 5140f4b3ec61Sdh155122 5141f4b3ec61Sdh155122 in = *inp; 5142f4b3ec61Sdh155122 *inp = NULL; 5143f4b3ec61Sdh155122 in->in_use--; 5144f4b3ec61Sdh155122 if (in->in_use == 0 && (in->in_flags & IPN_DELETE)) { 5145f4b3ec61Sdh155122 if (in->in_apr) 5146f4b3ec61Sdh155122 appr_free(in->in_apr); 5147f4b3ec61Sdh155122 KFREE(in); 5148f4b3ec61Sdh155122 ifs->ifs_nat_stats.ns_rules--; 5149f4b3ec61Sdh155122 #ifdef notdef 5150f4b3ec61Sdh155122 #if SOLARIS 5151f4b3ec61Sdh155122 if (ifs->ifs_nat_stats.ns_rules == 0) 5152f4b3ec61Sdh155122 ifs->ifs_pfil_delayed_copy = 1; 5153f4b3ec61Sdh155122 #endif 5154f4b3ec61Sdh155122 #endif 5155f4b3ec61Sdh155122 } 5156f4b3ec61Sdh155122 } 5157f4b3ec61Sdh155122 5158f4b3ec61Sdh155122 5159f4b3ec61Sdh155122 /* ------------------------------------------------------------------------ */ 5160ab25eeb5Syz155240 /* Function: fr_natderef */ 5161ab25eeb5Syz155240 /* Returns: Nil */ 5162ea8244dcSJohn Ojemann /* Parameters: natp - pointer to pointer to NAT table entry */ 5163ea8244dcSJohn Ojemann /* ifs - ipf stack instance */ 5164ab25eeb5Syz155240 /* */ 5165ab25eeb5Syz155240 /* Decrement the reference counter for this NAT table entry and free it if */ 5166ab25eeb5Syz155240 /* there are no more things using it. */ 51670e01ff8bSdr146992 /* */ 51680e01ff8bSdr146992 /* IF nat_ref == 1 when this function is called, then we have an orphan nat */ 51690e01ff8bSdr146992 /* structure *because* it only gets called on paths _after_ nat_ref has been*/ 51700e01ff8bSdr146992 /* incremented. If nat_ref == 1 then we shouldn't decrement it here */ 51710e01ff8bSdr146992 /* because nat_delete() will do that and send nat_ref to -1. */ 51720e01ff8bSdr146992 /* */ 51730e01ff8bSdr146992 /* Holding the lock on nat_lock is required to serialise nat_delete() being */ 51740e01ff8bSdr146992 /* called from a NAT flush ioctl with a deref happening because of a packet.*/ 5175ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */ 5176f4b3ec61Sdh155122 void fr_natderef(natp, ifs) 5177ab25eeb5Syz155240 nat_t **natp; 5178f4b3ec61Sdh155122 ipf_stack_t *ifs; 5179ab25eeb5Syz155240 { 5180ab25eeb5Syz155240 nat_t *nat; 5181ab25eeb5Syz155240 5182ab25eeb5Syz155240 nat = *natp; 5183ab25eeb5Syz155240 *natp = NULL; 51840e01ff8bSdr146992 51850e01ff8bSdr146992 MUTEX_ENTER(&nat->nat_lock); 51860e01ff8bSdr146992 if (nat->nat_ref > 1) { 5187ab25eeb5Syz155240 nat->nat_ref--; 51880e01ff8bSdr146992 MUTEX_EXIT(&nat->nat_lock); 51890e01ff8bSdr146992 return; 51900e01ff8bSdr146992 } 51910e01ff8bSdr146992 MUTEX_EXIT(&nat->nat_lock); 51920e01ff8bSdr146992 51930e01ff8bSdr146992 WRITE_ENTER(&ifs->ifs_ipf_nat); 5194ea8244dcSJohn Ojemann (void) nat_delete(nat, NL_EXPIRE, ifs); 5195f4b3ec61Sdh155122 RWLOCK_EXIT(&ifs->ifs_ipf_nat); 5196ab25eeb5Syz155240 } 5197ab25eeb5Syz155240 5198ab25eeb5Syz155240 5199ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */ 5200ab25eeb5Syz155240 /* Function: fr_natclone */ 5201ab25eeb5Syz155240 /* Returns: ipstate_t* - NULL == cloning failed, */ 5202ea8244dcSJohn Ojemann /* else pointer to new NAT structure */ 5203ab25eeb5Syz155240 /* Parameters: fin(I) - pointer to packet information */ 5204ea8244dcSJohn Ojemann /* nat(I) - pointer to master NAT structure */ 5205ab25eeb5Syz155240 /* Write Lock: ipf_nat */ 5206ab25eeb5Syz155240 /* */ 5207ea8244dcSJohn Ojemann /* Create a "duplicate" NAT table entry from the master. */ 5208ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */ 5209d6c23f6fSyx160601 nat_t *fr_natclone(fin, nat) 5210ab25eeb5Syz155240 fr_info_t *fin; 5211ab25eeb5Syz155240 nat_t *nat; 5212ab25eeb5Syz155240 { 5213ab25eeb5Syz155240 frentry_t *fr; 5214ab25eeb5Syz155240 nat_t *clone; 5215ab25eeb5Syz155240 ipnat_t *np; 5216f4b3ec61Sdh155122 ipf_stack_t *ifs = fin->fin_ifs; 5217ab25eeb5Syz155240 5218ea8244dcSJohn Ojemann /* 5219ea8244dcSJohn Ojemann * Trigger automatic call to nat_flushtable() if the 5220ea8244dcSJohn Ojemann * table has reached capcity specified by hi watermark. 5221ea8244dcSJohn Ojemann */ 5222ea8244dcSJohn Ojemann if (NAT_TAB_WATER_LEVEL(ifs) > ifs->ifs_nat_flush_level_hi) 5223ea8244dcSJohn Ojemann ifs->ifs_nat_doflush = 1; 5224ea8244dcSJohn Ojemann 5225ea8244dcSJohn Ojemann /* 5226ea8244dcSJohn Ojemann * If automatic flushing did not do its job, and the table 5227ea8244dcSJohn Ojemann * has filled up, don't try to create a new entry. 5228ea8244dcSJohn Ojemann */ 5229ea8244dcSJohn Ojemann if (ifs->ifs_nat_stats.ns_inuse >= ifs->ifs_ipf_nattable_max) { 5230ea8244dcSJohn Ojemann ifs->ifs_nat_stats.ns_memfail++; 5231ea8244dcSJohn Ojemann return NULL; 5232ea8244dcSJohn Ojemann } 5233ea8244dcSJohn Ojemann 5234ab25eeb5Syz155240 KMALLOC(clone, nat_t *); 5235ab25eeb5Syz155240 if (clone == NULL) 5236ab25eeb5Syz155240 return NULL; 5237ab25eeb5Syz155240 bcopy((char *)nat, (char *)clone, sizeof(*clone)); 5238ab25eeb5Syz155240 5239ab25eeb5Syz155240 MUTEX_NUKE(&clone->nat_lock); 5240ab25eeb5Syz155240 5241ab25eeb5Syz155240 clone->nat_aps = NULL; 5242ab25eeb5Syz155240 /* 5243ab25eeb5Syz155240 * Initialize all these so that nat_delete() doesn't cause a crash. 5244ab25eeb5Syz155240 */ 5245ab25eeb5Syz155240 clone->nat_tqe.tqe_pnext = NULL; 5246ab25eeb5Syz155240 clone->nat_tqe.tqe_next = NULL; 5247ab25eeb5Syz155240 clone->nat_tqe.tqe_ifq = NULL; 5248ab25eeb5Syz155240 clone->nat_tqe.tqe_parent = clone; 5249ab25eeb5Syz155240 5250ab25eeb5Syz155240 clone->nat_flags &= ~SI_CLONE; 5251ab25eeb5Syz155240 clone->nat_flags |= SI_CLONED; 5252ab25eeb5Syz155240 5253ab25eeb5Syz155240 if (clone->nat_hm) 5254ab25eeb5Syz155240 clone->nat_hm->hm_ref++; 5255ab25eeb5Syz155240 5256f4b3ec61Sdh155122 if (nat_insert(clone, fin->fin_rev, ifs) == -1) { 5257ab25eeb5Syz155240 KFREE(clone); 5258ab25eeb5Syz155240 return NULL; 5259ab25eeb5Syz155240 } 5260ab25eeb5Syz155240 np = clone->nat_ptr; 5261ab25eeb5Syz155240 if (np != NULL) { 5262f4b3ec61Sdh155122 if (ifs->ifs_nat_logging) 5263f4b3ec61Sdh155122 nat_log(clone, (u_int)np->in_redir, ifs); 5264ab25eeb5Syz155240 np->in_use++; 5265ab25eeb5Syz155240 } 5266ab25eeb5Syz155240 fr = clone->nat_fr; 5267ab25eeb5Syz155240 if (fr != NULL) { 5268ab25eeb5Syz155240 MUTEX_ENTER(&fr->fr_lock); 5269ab25eeb5Syz155240 fr->fr_ref++; 5270ab25eeb5Syz155240 MUTEX_EXIT(&fr->fr_lock); 5271ab25eeb5Syz155240 } 5272ab25eeb5Syz155240 5273ab25eeb5Syz155240 /* 5274ab25eeb5Syz155240 * Because the clone is created outside the normal loop of things and 5275ab25eeb5Syz155240 * TCP has special needs in terms of state, initialise the timeout 5276ab25eeb5Syz155240 * state of the new NAT from here. 5277ab25eeb5Syz155240 */ 5278ab25eeb5Syz155240 if (clone->nat_p == IPPROTO_TCP) { 5279f4b3ec61Sdh155122 (void) fr_tcp_age(&clone->nat_tqe, fin, ifs->ifs_nat_tqb, 5280ab25eeb5Syz155240 clone->nat_flags); 5281ab25eeb5Syz155240 } 5282ab25eeb5Syz155240 #ifdef IPFILTER_SYNC 5283ab25eeb5Syz155240 clone->nat_sync = ipfsync_new(SMC_NAT, fin, clone); 5284ab25eeb5Syz155240 #endif 5285f4b3ec61Sdh155122 if (ifs->ifs_nat_logging) 5286f4b3ec61Sdh155122 nat_log(clone, NL_CLONE, ifs); 5287ab25eeb5Syz155240 return clone; 5288ab25eeb5Syz155240 } 5289ab25eeb5Syz155240 5290ab25eeb5Syz155240 5291ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */ 5292ab25eeb5Syz155240 /* Function: nat_wildok */ 5293ab25eeb5Syz155240 /* Returns: int - 1 == packet's ports match wildcards */ 5294ab25eeb5Syz155240 /* 0 == packet's ports don't match wildcards */ 5295ab25eeb5Syz155240 /* Parameters: nat(I) - NAT entry */ 5296ab25eeb5Syz155240 /* sport(I) - source port */ 5297ab25eeb5Syz155240 /* dport(I) - destination port */ 5298ab25eeb5Syz155240 /* flags(I) - wildcard flags */ 5299ab25eeb5Syz155240 /* dir(I) - packet direction */ 5300ab25eeb5Syz155240 /* */ 5301ab25eeb5Syz155240 /* Use NAT entry and packet direction to determine which combination of */ 5302ab25eeb5Syz155240 /* wildcard flags should be used. */ 5303ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */ 5304d6c23f6fSyx160601 int nat_wildok(nat, sport, dport, flags, dir) 5305ab25eeb5Syz155240 nat_t *nat; 5306ab25eeb5Syz155240 int sport; 5307ab25eeb5Syz155240 int dport; 5308ab25eeb5Syz155240 int flags; 5309ab25eeb5Syz155240 int dir; 5310ab25eeb5Syz155240 { 5311ab25eeb5Syz155240 /* 5312ab25eeb5Syz155240 * When called by dir is set to 5313ab25eeb5Syz155240 * nat_inlookup NAT_INBOUND (0) 5314ab25eeb5Syz155240 * nat_outlookup NAT_OUTBOUND (1) 5315ab25eeb5Syz155240 * 5316ab25eeb5Syz155240 * We simply combine the packet's direction in dir with the original 5317ab25eeb5Syz155240 * "intended" direction of that NAT entry in nat->nat_dir to decide 5318ab25eeb5Syz155240 * which combination of wildcard flags to allow. 5319ab25eeb5Syz155240 */ 5320ab25eeb5Syz155240 5321ab25eeb5Syz155240 switch ((dir << 1) | nat->nat_dir) 5322ab25eeb5Syz155240 { 5323ab25eeb5Syz155240 case 3: /* outbound packet / outbound entry */ 5324ab25eeb5Syz155240 if (((nat->nat_inport == sport) || 5325ab25eeb5Syz155240 (flags & SI_W_SPORT)) && 5326ab25eeb5Syz155240 ((nat->nat_oport == dport) || 5327ab25eeb5Syz155240 (flags & SI_W_DPORT))) 5328ab25eeb5Syz155240 return 1; 5329ab25eeb5Syz155240 break; 5330ab25eeb5Syz155240 case 2: /* outbound packet / inbound entry */ 5331ab25eeb5Syz155240 if (((nat->nat_outport == sport) || 5332ab25eeb5Syz155240 (flags & SI_W_DPORT)) && 5333ab25eeb5Syz155240 ((nat->nat_oport == dport) || 5334ab25eeb5Syz155240 (flags & SI_W_SPORT))) 5335ab25eeb5Syz155240 return 1; 5336ab25eeb5Syz155240 break; 5337ab25eeb5Syz155240 case 1: /* inbound packet / outbound entry */ 5338ab25eeb5Syz155240 if (((nat->nat_oport == sport) || 5339ab25eeb5Syz155240 (flags & SI_W_DPORT)) && 5340ab25eeb5Syz155240 ((nat->nat_outport == dport) || 5341ab25eeb5Syz155240 (flags & SI_W_SPORT))) 5342ab25eeb5Syz155240 return 1; 5343ab25eeb5Syz155240 break; 5344ab25eeb5Syz155240 case 0: /* inbound packet / inbound entry */ 5345ab25eeb5Syz155240 if (((nat->nat_oport == sport) || 5346ab25eeb5Syz155240 (flags & SI_W_SPORT)) && 5347ab25eeb5Syz155240 ((nat->nat_outport == dport) || 5348ab25eeb5Syz155240 (flags & SI_W_DPORT))) 5349ab25eeb5Syz155240 return 1; 5350ab25eeb5Syz155240 break; 5351ab25eeb5Syz155240 default: 5352ab25eeb5Syz155240 break; 5353ab25eeb5Syz155240 } 5354ab25eeb5Syz155240 5355ab25eeb5Syz155240 return(0); 5356ab25eeb5Syz155240 } 5357ab25eeb5Syz155240 5358ab25eeb5Syz155240 5359ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */ 5360ab25eeb5Syz155240 /* Function: nat_mssclamp */ 5361ab25eeb5Syz155240 /* Returns: Nil */ 5362ab25eeb5Syz155240 /* Parameters: tcp(I) - pointer to TCP header */ 5363ab25eeb5Syz155240 /* maxmss(I) - value to clamp the TCP MSS to */ 5364ab25eeb5Syz155240 /* csump(I) - pointer to TCP checksum */ 5365ab25eeb5Syz155240 /* */ 5366ab25eeb5Syz155240 /* Check for MSS option and clamp it if necessary. If found and changed, */ 5367ab25eeb5Syz155240 /* then the TCP header checksum will be updated to reflect the change in */ 5368ab25eeb5Syz155240 /* the MSS. */ 5369ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */ 5370381a2a9aSdr146992 static void nat_mssclamp(tcp, maxmss, csump) 5371ab25eeb5Syz155240 tcphdr_t *tcp; 5372ab25eeb5Syz155240 u_32_t maxmss; 5373ab25eeb5Syz155240 u_short *csump; 5374ab25eeb5Syz155240 { 5375ab25eeb5Syz155240 u_char *cp, *ep, opt; 5376ab25eeb5Syz155240 int hlen, advance; 5377ab25eeb5Syz155240 u_32_t mss, sumd; 5378ab25eeb5Syz155240 5379ab25eeb5Syz155240 hlen = TCP_OFF(tcp) << 2; 5380ab25eeb5Syz155240 if (hlen > sizeof(*tcp)) { 5381ab25eeb5Syz155240 cp = (u_char *)tcp + sizeof(*tcp); 5382ab25eeb5Syz155240 ep = (u_char *)tcp + hlen; 5383ab25eeb5Syz155240 5384ab25eeb5Syz155240 while (cp < ep) { 5385ab25eeb5Syz155240 opt = cp[0]; 5386ab25eeb5Syz155240 if (opt == TCPOPT_EOL) 5387ab25eeb5Syz155240 break; 5388ab25eeb5Syz155240 else if (opt == TCPOPT_NOP) { 5389ab25eeb5Syz155240 cp++; 5390ab25eeb5Syz155240 continue; 5391ab25eeb5Syz155240 } 5392ab25eeb5Syz155240 5393ab25eeb5Syz155240 if (cp + 1 >= ep) 5394ab25eeb5Syz155240 break; 5395ab25eeb5Syz155240 advance = cp[1]; 5396ab25eeb5Syz155240 if ((cp + advance > ep) || (advance <= 0)) 5397ab25eeb5Syz155240 break; 5398ab25eeb5Syz155240 switch (opt) 5399ab25eeb5Syz155240 { 5400ab25eeb5Syz155240 case TCPOPT_MAXSEG: 5401ab25eeb5Syz155240 if (advance != 4) 5402ab25eeb5Syz155240 break; 5403ab25eeb5Syz155240 mss = cp[2] * 256 + cp[3]; 5404ab25eeb5Syz155240 if (mss > maxmss) { 5405ab25eeb5Syz155240 cp[2] = maxmss / 256; 5406ab25eeb5Syz155240 cp[3] = maxmss & 0xff; 5407ab25eeb5Syz155240 CALC_SUMD(mss, maxmss, sumd); 5408381a2a9aSdr146992 fix_outcksum(csump, sumd); 5409ab25eeb5Syz155240 } 5410ab25eeb5Syz155240 break; 5411ab25eeb5Syz155240 default: 5412ab25eeb5Syz155240 /* ignore unknown options */ 5413ab25eeb5Syz155240 break; 5414ab25eeb5Syz155240 } 5415ab25eeb5Syz155240 5416ab25eeb5Syz155240 cp += advance; 5417ab25eeb5Syz155240 } 5418ab25eeb5Syz155240 } 5419ab25eeb5Syz155240 } 5420ab25eeb5Syz155240 5421ab25eeb5Syz155240 5422ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */ 5423ab25eeb5Syz155240 /* Function: fr_setnatqueue */ 5424ab25eeb5Syz155240 /* Returns: Nil */ 5425ab25eeb5Syz155240 /* Parameters: nat(I)- pointer to NAT structure */ 5426ab25eeb5Syz155240 /* rev(I) - forward(0) or reverse(1) direction */ 5427ab25eeb5Syz155240 /* Locks: ipf_nat (read or write) */ 5428ab25eeb5Syz155240 /* */ 5429ab25eeb5Syz155240 /* Put the NAT entry on its default queue entry, using rev as a helped in */ 5430ab25eeb5Syz155240 /* determining which queue it should be placed on. */ 5431ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */ 5432f4b3ec61Sdh155122 void fr_setnatqueue(nat, rev, ifs) 5433ab25eeb5Syz155240 nat_t *nat; 5434ab25eeb5Syz155240 int rev; 5435f4b3ec61Sdh155122 ipf_stack_t *ifs; 5436ab25eeb5Syz155240 { 5437ab25eeb5Syz155240 ipftq_t *oifq, *nifq; 5438ab25eeb5Syz155240 5439ab25eeb5Syz155240 if (nat->nat_ptr != NULL) 5440ab25eeb5Syz155240 nifq = nat->nat_ptr->in_tqehead[rev]; 5441ab25eeb5Syz155240 else 5442ab25eeb5Syz155240 nifq = NULL; 5443ab25eeb5Syz155240 5444ab25eeb5Syz155240 if (nifq == NULL) { 5445ab25eeb5Syz155240 switch (nat->nat_p) 5446ab25eeb5Syz155240 { 5447ab25eeb5Syz155240 case IPPROTO_UDP : 5448f4b3ec61Sdh155122 nifq = &ifs->ifs_nat_udptq; 5449ab25eeb5Syz155240 break; 5450ab25eeb5Syz155240 case IPPROTO_ICMP : 5451f4b3ec61Sdh155122 nifq = &ifs->ifs_nat_icmptq; 5452ab25eeb5Syz155240 break; 5453ab25eeb5Syz155240 case IPPROTO_TCP : 5454f4b3ec61Sdh155122 nifq = ifs->ifs_nat_tqb + nat->nat_tqe.tqe_state[rev]; 5455ab25eeb5Syz155240 break; 5456ab25eeb5Syz155240 default : 5457f4b3ec61Sdh155122 nifq = &ifs->ifs_nat_iptq; 5458ab25eeb5Syz155240 break; 5459ab25eeb5Syz155240 } 5460ab25eeb5Syz155240 } 5461ab25eeb5Syz155240 5462ab25eeb5Syz155240 oifq = nat->nat_tqe.tqe_ifq; 5463ab25eeb5Syz155240 /* 5464ab25eeb5Syz155240 * If it's currently on a timeout queue, move it from one queue to 5465ab25eeb5Syz155240 * another, else put it on the end of the newly determined queue. 5466ab25eeb5Syz155240 */ 5467ab25eeb5Syz155240 if (oifq != NULL) 5468f4b3ec61Sdh155122 fr_movequeue(&nat->nat_tqe, oifq, nifq, ifs); 5469ab25eeb5Syz155240 else 5470f4b3ec61Sdh155122 fr_queueappend(&nat->nat_tqe, nifq, nat, ifs); 5471ab25eeb5Syz155240 return; 5472ab25eeb5Syz155240 } 5473f4b3ec61Sdh155122 547490b0a856Sjojemann /* ------------------------------------------------------------------------ */ 5475f4b3ec61Sdh155122 /* Function: nat_getnext */ 5476f4b3ec61Sdh155122 /* Returns: int - 0 == ok, else error */ 5477f4b3ec61Sdh155122 /* Parameters: t(I) - pointer to ipftoken structure */ 5478f4b3ec61Sdh155122 /* itp(I) - pointer to ipfgeniter_t structure */ 547990b0a856Sjojemann /* ifs - ipf stack instance */ 5480f4b3ec61Sdh155122 /* */ 548190b0a856Sjojemann /* Fetch the next nat/ipnat/hostmap structure pointer from the linked list */ 548290b0a856Sjojemann /* and copy it out to the storage space pointed to by itp. The next item */ 5483f4b3ec61Sdh155122 /* in the list to look at is put back in the ipftoken struture. */ 5484f4b3ec61Sdh155122 /* ------------------------------------------------------------------------ */ 5485f4b3ec61Sdh155122 static int nat_getnext(t, itp, ifs) 5486f4b3ec61Sdh155122 ipftoken_t *t; 5487f4b3ec61Sdh155122 ipfgeniter_t *itp; 5488f4b3ec61Sdh155122 ipf_stack_t *ifs; 5489f4b3ec61Sdh155122 { 5490f4b3ec61Sdh155122 hostmap_t *hm, *nexthm = NULL, zerohm; 5491f4b3ec61Sdh155122 ipnat_t *ipn, *nextipnat = NULL, zeroipn; 5492f4b3ec61Sdh155122 nat_t *nat, *nextnat = NULL, zeronat; 549390b0a856Sjojemann int error = 0, count; 549490b0a856Sjojemann char *dst; 549590b0a856Sjojemann 549690b0a856Sjojemann if (itp->igi_nitems == 0) 549790b0a856Sjojemann return EINVAL; 5498f4b3ec61Sdh155122 5499f4b3ec61Sdh155122 READ_ENTER(&ifs->ifs_ipf_nat); 550090b0a856Sjojemann 5501786c7074Sjojemann /* 5502786c7074Sjojemann * Get "previous" entry from the token and find the next entry. 5503786c7074Sjojemann */ 5504f4b3ec61Sdh155122 switch (itp->igi_type) 5505f4b3ec61Sdh155122 { 5506f4b3ec61Sdh155122 case IPFGENITER_HOSTMAP : 5507f4b3ec61Sdh155122 hm = t->ipt_data; 5508f4b3ec61Sdh155122 if (hm == NULL) { 5509f4b3ec61Sdh155122 nexthm = ifs->ifs_ipf_hm_maplist; 5510f4b3ec61Sdh155122 } else { 551190b0a856Sjojemann nexthm = hm->hm_next; 5512f4b3ec61Sdh155122 } 5513f4b3ec61Sdh155122 break; 5514f4b3ec61Sdh155122 5515f4b3ec61Sdh155122 case IPFGENITER_IPNAT : 5516f4b3ec61Sdh155122 ipn = t->ipt_data; 5517f4b3ec61Sdh155122 if (ipn == NULL) { 5518f4b3ec61Sdh155122 nextipnat = ifs->ifs_nat_list; 5519f4b3ec61Sdh155122 } else { 5520f4b3ec61Sdh155122 nextipnat = ipn->in_next; 5521f4b3ec61Sdh155122 } 5522f4b3ec61Sdh155122 break; 5523f4b3ec61Sdh155122 5524f4b3ec61Sdh155122 case IPFGENITER_NAT : 5525f4b3ec61Sdh155122 nat = t->ipt_data; 5526f4b3ec61Sdh155122 if (nat == NULL) { 5527f4b3ec61Sdh155122 nextnat = ifs->ifs_nat_instances; 5528f4b3ec61Sdh155122 } else { 5529f4b3ec61Sdh155122 nextnat = nat->nat_next; 5530f4b3ec61Sdh155122 } 553190b0a856Sjojemann break; 553290b0a856Sjojemann default : 553390b0a856Sjojemann RWLOCK_EXIT(&ifs->ifs_ipf_nat); 553490b0a856Sjojemann return EINVAL; 553590b0a856Sjojemann } 553690b0a856Sjojemann 553758d7f9e6SRobert Mustacchi /* 553858d7f9e6SRobert Mustacchi * Note, this loop is based on the number of items that a user 553958d7f9e6SRobert Mustacchi * requested. The user can request any number, potentially far more than 554058d7f9e6SRobert Mustacchi * the number of items that actually exist. If a user does that, we'll 554158d7f9e6SRobert Mustacchi * break out of this by setting the value of count to 1 which terminates 554258d7f9e6SRobert Mustacchi * the loop. This should be fine from an ioctl perspective, because the 554358d7f9e6SRobert Mustacchi * last entry that we insert will be the zero entry which terminates the 554458d7f9e6SRobert Mustacchi * chain. 554558d7f9e6SRobert Mustacchi */ 554690b0a856Sjojemann dst = itp->igi_data; 554790b0a856Sjojemann for (count = itp->igi_nitems; count > 0; count--) { 5548786c7074Sjojemann /* 5549786c7074Sjojemann * If we found an entry, add a reference to it and update the token. 5550786c7074Sjojemann * Otherwise, zero out data to be returned and NULL out token. 5551786c7074Sjojemann */ 555290b0a856Sjojemann switch (itp->igi_type) 555390b0a856Sjojemann { 555490b0a856Sjojemann case IPFGENITER_HOSTMAP : 555590b0a856Sjojemann if (nexthm != NULL) { 555690b0a856Sjojemann ATOMIC_INC32(nexthm->hm_ref); 555790b0a856Sjojemann t->ipt_data = nexthm; 5558f4b3ec61Sdh155122 } else { 555990b0a856Sjojemann bzero(&zerohm, sizeof(zerohm)); 556090b0a856Sjojemann nexthm = &zerohm; 556190b0a856Sjojemann t->ipt_data = NULL; 556290b0a856Sjojemann } 556390b0a856Sjojemann break; 556490b0a856Sjojemann case IPFGENITER_IPNAT : 556590b0a856Sjojemann if (nextipnat != NULL) { 556690b0a856Sjojemann ATOMIC_INC32(nextipnat->in_use); 556790b0a856Sjojemann t->ipt_data = nextipnat; 556890b0a856Sjojemann } else { 556990b0a856Sjojemann bzero(&zeroipn, sizeof(zeroipn)); 557090b0a856Sjojemann nextipnat = &zeroipn; 557190b0a856Sjojemann t->ipt_data = NULL; 557290b0a856Sjojemann } 557390b0a856Sjojemann break; 557490b0a856Sjojemann case IPFGENITER_NAT : 557590b0a856Sjojemann if (nextnat != NULL) { 5576f4b3ec61Sdh155122 MUTEX_ENTER(&nextnat->nat_lock); 5577f4b3ec61Sdh155122 nextnat->nat_ref++; 5578f4b3ec61Sdh155122 MUTEX_EXIT(&nextnat->nat_lock); 557990b0a856Sjojemann t->ipt_data = nextnat; 5580f4b3ec61Sdh155122 } else { 5581f4b3ec61Sdh155122 bzero(&zeronat, sizeof(zeronat)); 5582f4b3ec61Sdh155122 nextnat = &zeronat; 558390b0a856Sjojemann t->ipt_data = NULL; 5584f4b3ec61Sdh155122 } 5585f4b3ec61Sdh155122 break; 558690b0a856Sjojemann default : 558790b0a856Sjojemann break; 5588f4b3ec61Sdh155122 } 5589f4b3ec61Sdh155122 559090b0a856Sjojemann /* 5591786c7074Sjojemann * Now that we have ref, it's save to give up lock. 559290b0a856Sjojemann */ 5593f4b3ec61Sdh155122 RWLOCK_EXIT(&ifs->ifs_ipf_nat); 5594f4b3ec61Sdh155122 5595786c7074Sjojemann /* 5596786c7074Sjojemann * Copy out data and clean up references and token as needed. 5597786c7074Sjojemann */ 5598f4b3ec61Sdh155122 switch (itp->igi_type) 5599f4b3ec61Sdh155122 { 5600f4b3ec61Sdh155122 case IPFGENITER_HOSTMAP : 5601786c7074Sjojemann error = COPYOUT(nexthm, dst, sizeof(*nexthm)); 5602786c7074Sjojemann if (error != 0) 5603786c7074Sjojemann error = EFAULT; 5604786c7074Sjojemann if (t->ipt_data == NULL) { 5605786c7074Sjojemann ipf_freetoken(t, ifs); 560658d7f9e6SRobert Mustacchi count = 1; 5607786c7074Sjojemann break; 5608786c7074Sjojemann } else { 5609f4b3ec61Sdh155122 if (hm != NULL) { 5610f4b3ec61Sdh155122 WRITE_ENTER(&ifs->ifs_ipf_nat); 561190b0a856Sjojemann fr_hostmapdel(&hm); 5612f4b3ec61Sdh155122 RWLOCK_EXIT(&ifs->ifs_ipf_nat); 5613f4b3ec61Sdh155122 } 5614786c7074Sjojemann if (nexthm->hm_next == NULL) { 5615786c7074Sjojemann ipf_freetoken(t, ifs); 561658d7f9e6SRobert Mustacchi count = 1; 5617786c7074Sjojemann break; 5618786c7074Sjojemann } 561990b0a856Sjojemann dst += sizeof(*nexthm); 562090b0a856Sjojemann hm = nexthm; 562190b0a856Sjojemann nexthm = nexthm->hm_next; 562290b0a856Sjojemann } 5623f4b3ec61Sdh155122 break; 5624786c7074Sjojemann 5625f4b3ec61Sdh155122 case IPFGENITER_IPNAT : 5626786c7074Sjojemann error = COPYOUT(nextipnat, dst, sizeof(*nextipnat)); 5627786c7074Sjojemann if (error != 0) 5628786c7074Sjojemann error = EFAULT; 5629786c7074Sjojemann if (t->ipt_data == NULL) { 5630786c7074Sjojemann ipf_freetoken(t, ifs); 563158d7f9e6SRobert Mustacchi count = 1; 5632786c7074Sjojemann break; 5633786c7074Sjojemann } else { 563490b0a856Sjojemann if (ipn != NULL) { 563590b0a856Sjojemann WRITE_ENTER(&ifs->ifs_ipf_nat); 5636f4b3ec61Sdh155122 fr_ipnatderef(&ipn, ifs); 563790b0a856Sjojemann RWLOCK_EXIT(&ifs->ifs_ipf_nat); 563890b0a856Sjojemann } 5639786c7074Sjojemann if (nextipnat->in_next == NULL) { 5640786c7074Sjojemann ipf_freetoken(t, ifs); 564158d7f9e6SRobert Mustacchi count = 1; 5642786c7074Sjojemann break; 5643786c7074Sjojemann } 564490b0a856Sjojemann dst += sizeof(*nextipnat); 564590b0a856Sjojemann ipn = nextipnat; 564690b0a856Sjojemann nextipnat = nextipnat->in_next; 564790b0a856Sjojemann } 564890b0a856Sjojemann break; 5649786c7074Sjojemann 565090b0a856Sjojemann case IPFGENITER_NAT : 565190b0a856Sjojemann error = COPYOUT(nextnat, dst, sizeof(*nextnat)); 5652786c7074Sjojemann if (error != 0) 565390b0a856Sjojemann error = EFAULT; 5654786c7074Sjojemann if (t->ipt_data == NULL) { 5655786c7074Sjojemann ipf_freetoken(t, ifs); 565658d7f9e6SRobert Mustacchi count = 1; 5657786c7074Sjojemann break; 565890b0a856Sjojemann } else { 5659786c7074Sjojemann if (nat != NULL) 5660786c7074Sjojemann fr_natderef(&nat, ifs); 5661786c7074Sjojemann if (nextnat->nat_next == NULL) { 5662786c7074Sjojemann ipf_freetoken(t, ifs); 566358d7f9e6SRobert Mustacchi count = 1; 5664786c7074Sjojemann break; 5665786c7074Sjojemann } 566690b0a856Sjojemann dst += sizeof(*nextnat); 566790b0a856Sjojemann nat = nextnat; 566890b0a856Sjojemann nextnat = nextnat->nat_next; 566990b0a856Sjojemann } 567090b0a856Sjojemann break; 567190b0a856Sjojemann default : 567290b0a856Sjojemann break; 567390b0a856Sjojemann } 567490b0a856Sjojemann 567590b0a856Sjojemann if ((count == 1) || (error != 0)) 5676f4b3ec61Sdh155122 break; 5677f4b3ec61Sdh155122 567890b0a856Sjojemann READ_ENTER(&ifs->ifs_ipf_nat); 5679f4b3ec61Sdh155122 } 5680f4b3ec61Sdh155122 5681f4b3ec61Sdh155122 return error; 5682f4b3ec61Sdh155122 } 5683f4b3ec61Sdh155122 5684f4b3ec61Sdh155122 5685f4b3ec61Sdh155122 /* ------------------------------------------------------------------------ */ 5686f4b3ec61Sdh155122 /* Function: nat_iterator */ 5687f4b3ec61Sdh155122 /* Returns: int - 0 == ok, else error */ 5688f4b3ec61Sdh155122 /* Parameters: token(I) - pointer to ipftoken structure */ 5689f4b3ec61Sdh155122 /* itp(I) - pointer to ipfgeniter_t structure */ 5690f4b3ec61Sdh155122 /* */ 5691f4b3ec61Sdh155122 /* This function acts as a handler for the SIOCGENITER ioctls that use a */ 5692f4b3ec61Sdh155122 /* generic structure to iterate through a list. There are three different */ 5693f4b3ec61Sdh155122 /* linked lists of NAT related information to go through: NAT rules, active */ 5694f4b3ec61Sdh155122 /* NAT mappings and the NAT fragment cache. */ 5695f4b3ec61Sdh155122 /* ------------------------------------------------------------------------ */ 5696f4b3ec61Sdh155122 static int nat_iterator(token, itp, ifs) 5697f4b3ec61Sdh155122 ipftoken_t *token; 5698f4b3ec61Sdh155122 ipfgeniter_t *itp; 5699f4b3ec61Sdh155122 ipf_stack_t *ifs; 5700f4b3ec61Sdh155122 { 5701f4b3ec61Sdh155122 int error; 5702f4b3ec61Sdh155122 5703f4b3ec61Sdh155122 if (itp->igi_data == NULL) 5704f4b3ec61Sdh155122 return EFAULT; 5705f4b3ec61Sdh155122 5706f4b3ec61Sdh155122 token->ipt_subtype = itp->igi_type; 5707f4b3ec61Sdh155122 5708f4b3ec61Sdh155122 switch (itp->igi_type) 5709f4b3ec61Sdh155122 { 5710f4b3ec61Sdh155122 case IPFGENITER_HOSTMAP : 5711f4b3ec61Sdh155122 case IPFGENITER_IPNAT : 5712f4b3ec61Sdh155122 case IPFGENITER_NAT : 5713f4b3ec61Sdh155122 error = nat_getnext(token, itp, ifs); 5714f4b3ec61Sdh155122 break; 5715f4b3ec61Sdh155122 case IPFGENITER_NATFRAG : 5716f4b3ec61Sdh155122 error = fr_nextfrag(token, itp, &ifs->ifs_ipfr_natlist, 5717f4b3ec61Sdh155122 &ifs->ifs_ipfr_nattail, 5718f4b3ec61Sdh155122 &ifs->ifs_ipf_natfrag, ifs); 5719f4b3ec61Sdh155122 break; 5720f4b3ec61Sdh155122 default : 5721f4b3ec61Sdh155122 error = EINVAL; 5722f4b3ec61Sdh155122 break; 5723f4b3ec61Sdh155122 } 5724f4b3ec61Sdh155122 5725f4b3ec61Sdh155122 return error; 5726f4b3ec61Sdh155122 } 57273805c50fSan207044 57283805c50fSan207044 5729ea8244dcSJohn Ojemann /* ---------------------------------------------------------------------- */ 5730ea8244dcSJohn Ojemann /* Function: nat_flushtable */ 5731ea8244dcSJohn Ojemann /* Returns: int - 0 == success, -1 == failure */ 5732ea8244dcSJohn Ojemann /* Parameters: flush_option - how to flush the active NAT table */ 57333805c50fSan207044 /* ifs - ipf stack instance */ 57343805c50fSan207044 /* Write Locks: ipf_nat */ 57353805c50fSan207044 /* */ 5736ea8244dcSJohn Ojemann /* Flush NAT tables. Three actions currently defined: */ 57373805c50fSan207044 /* */ 5738ea8244dcSJohn Ojemann /* FLUSH_TABLE_ALL : Flush all NAT table entries */ 57393805c50fSan207044 /* */ 5740ea8244dcSJohn Ojemann /* FLUSH_TABLE_CLOSING : Flush entries with TCP connections which */ 5741ea8244dcSJohn Ojemann /* have started to close on both ends using */ 5742ea8244dcSJohn Ojemann /* ipf_flushclosing(). */ 57433805c50fSan207044 /* */ 5744ea8244dcSJohn Ojemann /* FLUSH_TABLE_EXTRA : First, flush entries which are "almost" closed. */ 5745ea8244dcSJohn Ojemann /* Then, if needed, flush entries with TCP */ 5746ea8244dcSJohn Ojemann /* connections which have been idle for a long */ 5747ea8244dcSJohn Ojemann /* time with ipf_extraflush(). */ 5748ea8244dcSJohn Ojemann /* ---------------------------------------------------------------------- */ 5749ea8244dcSJohn Ojemann static int nat_flushtable(flush_option, ifs) 5750ea8244dcSJohn Ojemann int flush_option; 57513805c50fSan207044 ipf_stack_t *ifs; 57523805c50fSan207044 { 5753ea8244dcSJohn Ojemann nat_t *nat, *natn; 5754ea8244dcSJohn Ojemann int removed; 57553805c50fSan207044 SPL_INT(s); 57563805c50fSan207044 57573805c50fSan207044 removed = 0; 57583805c50fSan207044 57593805c50fSan207044 SPL_NET(s); 5760ea8244dcSJohn Ojemann switch (flush_option) 57613805c50fSan207044 { 5762ea8244dcSJohn Ojemann case FLUSH_TABLE_ALL: 5763ea8244dcSJohn Ojemann natn = ifs->ifs_nat_instances; 5764ea8244dcSJohn Ojemann while ((nat = natn) != NULL) { 5765ea8244dcSJohn Ojemann natn = nat->nat_next; 5766ea8244dcSJohn Ojemann if (nat_delete(nat, NL_FLUSH, ifs) == 0) 57673805c50fSan207044 removed++; 57683805c50fSan207044 } 57693805c50fSan207044 break; 57703805c50fSan207044 5771ea8244dcSJohn Ojemann case FLUSH_TABLE_CLOSING: 5772ea8244dcSJohn Ojemann removed = ipf_flushclosing(NAT_FLUSH, 5773ea8244dcSJohn Ojemann IPF_TCPS_CLOSE_WAIT, 5774ea8244dcSJohn Ojemann ifs->ifs_nat_tqb, 5775ea8244dcSJohn Ojemann ifs->ifs_nat_utqe, 5776ea8244dcSJohn Ojemann ifs); 57773805c50fSan207044 break; 57783805c50fSan207044 5779ea8244dcSJohn Ojemann case FLUSH_TABLE_EXTRA: 5780ea8244dcSJohn Ojemann removed = ipf_flushclosing(NAT_FLUSH, 5781ea8244dcSJohn Ojemann IPF_TCPS_FIN_WAIT_2, 5782ea8244dcSJohn Ojemann ifs->ifs_nat_tqb, 5783ea8244dcSJohn Ojemann ifs->ifs_nat_utqe, 5784ea8244dcSJohn Ojemann ifs); 57853805c50fSan207044 57863805c50fSan207044 /* 57873805c50fSan207044 * Be sure we haven't done this in the last 10 seconds. 57883805c50fSan207044 */ 57893805c50fSan207044 if (ifs->ifs_fr_ticks - ifs->ifs_nat_last_force_flush < 57903805c50fSan207044 IPF_TTLVAL(10)) 57913805c50fSan207044 break; 57923805c50fSan207044 ifs->ifs_nat_last_force_flush = ifs->ifs_fr_ticks; 5793ea8244dcSJohn Ojemann removed += ipf_extraflush(NAT_FLUSH, 57943805c50fSan207044 &ifs->ifs_nat_tqb[IPF_TCPS_ESTABLISHED], 5795ea8244dcSJohn Ojemann ifs->ifs_nat_utqe, 5796ea8244dcSJohn Ojemann ifs); 57973805c50fSan207044 break; 57983805c50fSan207044 5799ea8244dcSJohn Ojemann default: /* Flush Nothing */ 58003805c50fSan207044 break; 58013805c50fSan207044 } 58023805c50fSan207044 58033805c50fSan207044 SPL_X(s); 58043805c50fSan207044 return (removed); 58053805c50fSan207044 } 580633f2fefdSDarren Reed 580733f2fefdSDarren Reed 580833f2fefdSDarren Reed /* ------------------------------------------------------------------------ */ 580933f2fefdSDarren Reed /* Function: nat_uncreate */ 581033f2fefdSDarren Reed /* Returns: Nil */ 581133f2fefdSDarren Reed /* Parameters: fin(I) - pointer to packet information */ 581233f2fefdSDarren Reed /* */ 581333f2fefdSDarren Reed /* This function is used to remove a NAT entry from the NAT table when we */ 581433f2fefdSDarren Reed /* decide that the create was actually in error. It is thus assumed that */ 581533f2fefdSDarren Reed /* fin_flx will have both FI_NATED and FI_NATNEW set. Because we're dealing */ 581633f2fefdSDarren Reed /* with the translated packet (not the original), we have to reverse the */ 581733f2fefdSDarren Reed /* lookup. Although doing the lookup is expensive (relatively speaking), it */ 581833f2fefdSDarren Reed /* is not anticipated that this will be a frequent occurance for normal */ 581933f2fefdSDarren Reed /* traffic patterns. */ 582033f2fefdSDarren Reed /* ------------------------------------------------------------------------ */ 582133f2fefdSDarren Reed void nat_uncreate(fin) 582233f2fefdSDarren Reed fr_info_t *fin; 582333f2fefdSDarren Reed { 582433f2fefdSDarren Reed ipf_stack_t *ifs = fin->fin_ifs; 582533f2fefdSDarren Reed int nflags; 582633f2fefdSDarren Reed nat_t *nat; 582733f2fefdSDarren Reed 582833f2fefdSDarren Reed switch (fin->fin_p) 582933f2fefdSDarren Reed { 583033f2fefdSDarren Reed case IPPROTO_TCP : 583133f2fefdSDarren Reed nflags = IPN_TCP; 583233f2fefdSDarren Reed break; 583333f2fefdSDarren Reed case IPPROTO_UDP : 583433f2fefdSDarren Reed nflags = IPN_UDP; 583533f2fefdSDarren Reed break; 583633f2fefdSDarren Reed default : 583733f2fefdSDarren Reed nflags = 0; 583833f2fefdSDarren Reed break; 583933f2fefdSDarren Reed } 584033f2fefdSDarren Reed 584133f2fefdSDarren Reed WRITE_ENTER(&ifs->ifs_ipf_nat); 584233f2fefdSDarren Reed 584333f2fefdSDarren Reed if (fin->fin_out == 0) { 584433f2fefdSDarren Reed nat = nat_outlookup(fin, nflags, (u_int)fin->fin_p, 584533f2fefdSDarren Reed fin->fin_dst, fin->fin_src); 584633f2fefdSDarren Reed } else { 584733f2fefdSDarren Reed nat = nat_inlookup(fin, nflags, (u_int)fin->fin_p, 584833f2fefdSDarren Reed fin->fin_src, fin->fin_dst); 584933f2fefdSDarren Reed } 585033f2fefdSDarren Reed 585133f2fefdSDarren Reed if (nat != NULL) { 585233f2fefdSDarren Reed ifs->ifs_nat_stats.ns_uncreate[fin->fin_out][0]++; 5853150efaafSDarren Reed (void) nat_delete(nat, NL_DESTROY, ifs); 585433f2fefdSDarren Reed } else { 585533f2fefdSDarren Reed ifs->ifs_nat_stats.ns_uncreate[fin->fin_out][1]++; 585633f2fefdSDarren Reed } 585733f2fefdSDarren Reed 585833f2fefdSDarren Reed RWLOCK_EXIT(&ifs->ifs_ipf_nat); 585933f2fefdSDarren Reed } 5860