1 0 stevel /* 2 6295 an207044 * Copyright (C) 1995-2004 by Darren Reed. 3 0 stevel * 4 0 stevel * See the IPFILTER.LICENCE file for details on licencing. 5 0 stevel * 6 8624 Darren * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 7 0 stevel * Use is subject to license terms. 8 0 stevel */ 9 0 stevel 10 0 stevel #if defined(KERNEL) || defined(_KERNEL) 11 0 stevel # undef KERNEL 12 0 stevel # undef _KERNEL 13 0 stevel # define KERNEL 1 14 0 stevel # define _KERNEL 1 15 0 stevel #endif 16 0 stevel #include <sys/errno.h> 17 0 stevel #include <sys/types.h> 18 0 stevel #include <sys/param.h> 19 0 stevel #include <sys/time.h> 20 0 stevel #include <sys/file.h> 21 0 stevel #if defined(__NetBSD__) && (NetBSD >= 199905) && !defined(IPFILTER_LKM) && \ 22 0 stevel defined(_KERNEL) 23 0 stevel # include "opt_ipfilter_log.h" 24 0 stevel #endif 25 0 stevel #if !defined(_KERNEL) 26 0 stevel # include <stdio.h> 27 0 stevel # include <string.h> 28 0 stevel # include <stdlib.h> 29 0 stevel # define _KERNEL 30 0 stevel # ifdef __OpenBSD__ 31 0 stevel struct file; 32 0 stevel # endif 33 0 stevel # include <sys/uio.h> 34 0 stevel # undef _KERNEL 35 0 stevel #endif 36 0 stevel #if defined(_KERNEL) && (__FreeBSD_version >= 220000) 37 0 stevel # include <sys/filio.h> 38 0 stevel # include <sys/fcntl.h> 39 0 stevel #else 40 0 stevel # include <sys/ioctl.h> 41 0 stevel #endif 42 2393 yz155240 #if !defined(AIX) 43 2393 yz155240 # include <sys/fcntl.h> 44 2393 yz155240 #endif 45 2393 yz155240 #if !defined(linux) 46 2393 yz155240 # include <sys/protosw.h> 47 2393 yz155240 #endif 48 0 stevel #include <sys/socket.h> 49 0 stevel #if defined(_KERNEL) 50 0 stevel # include <sys/systm.h> 51 0 stevel # if !defined(__SVR4) && !defined(__svr4__) 52 0 stevel # include <sys/mbuf.h> 53 0 stevel # endif 54 0 stevel #endif 55 0 stevel #if defined(__SVR4) || defined(__svr4__) 56 0 stevel # include <sys/filio.h> 57 0 stevel # include <sys/byteorder.h> 58 0 stevel # ifdef _KERNEL 59 0 stevel # include <sys/dditypes.h> 60 0 stevel # endif 61 0 stevel # include <sys/stream.h> 62 0 stevel # include <sys/kmem.h> 63 0 stevel #endif 64 0 stevel #if __FreeBSD_version >= 300000 65 0 stevel # include <sys/queue.h> 66 0 stevel #endif 67 0 stevel #include <net/if.h> 68 0 stevel #if __FreeBSD_version >= 300000 69 0 stevel # include <net/if_var.h> 70 0 stevel # if defined(_KERNEL) && !defined(IPFILTER_LKM) 71 0 stevel # include "opt_ipfilter.h" 72 0 stevel # endif 73 0 stevel #endif 74 0 stevel #ifdef sun 75 0 stevel # include <net/af.h> 76 0 stevel #endif 77 0 stevel #include <net/route.h> 78 0 stevel #include <netinet/in.h> 79 0 stevel #include <netinet/in_systm.h> 80 0 stevel #include <netinet/ip.h> 81 0 stevel 82 0 stevel #ifdef RFC1825 83 0 stevel # include <vpn/md5.h> 84 0 stevel # include <vpn/ipsec.h> 85 0 stevel extern struct ifnet vpnif; 86 0 stevel #endif 87 0 stevel 88 2393 yz155240 #if !defined(linux) 89 2393 yz155240 # include <netinet/ip_var.h> 90 2393 yz155240 #endif 91 0 stevel #include <netinet/tcp.h> 92 0 stevel #include <netinet/udp.h> 93 0 stevel #include <netinet/ip_icmp.h> 94 2393 yz155240 #include "netinet/ip_compat.h" 95 0 stevel #include <netinet/tcpip.h> 96 0 stevel #include "netinet/ip_fil.h" 97 0 stevel #include "netinet/ip_nat.h" 98 0 stevel #include "netinet/ip_frag.h" 99 0 stevel #include "netinet/ip_state.h" 100 0 stevel #include "netinet/ip_proxy.h" 101 3448 dh155122 #include "netinet/ipf_stack.h" 102 0 stevel #ifdef IPFILTER_SYNC 103 0 stevel #include "netinet/ip_sync.h" 104 0 stevel #endif 105 0 stevel #if (__FreeBSD_version >= 300000) 106 0 stevel # include <sys/malloc.h> 107 0 stevel #endif 108 2393 yz155240 /* END OF INCLUDES */ 109 2393 yz155240 110 0 stevel #undef SOCKADDR_IN 111 0 stevel #define SOCKADDR_IN struct sockaddr_in 112 0 stevel 113 0 stevel #if !defined(lint) 114 0 stevel static const char sccsid[] = "@(#)ip_nat.c 1.11 6/5/96 (C) 1995 Darren Reed"; 115 2393 yz155240 static const char rcsid[] = "@(#)$Id: ip_nat.c,v 2.195.2.42 2005/08/11 19:51:36 darrenr Exp $"; 116 0 stevel #endif 117 0 stevel 118 0 stevel 119 0 stevel /* ======================================================================== */ 120 0 stevel /* How the NAT is organised and works. */ 121 0 stevel /* */ 122 0 stevel /* Inside (interface y) NAT Outside (interface x) */ 123 0 stevel /* -------------------- -+- ------------------------------------- */ 124 0 stevel /* Packet going | out, processsed by fr_checknatout() for x */ 125 0 stevel /* ------------> | ------------> */ 126 0 stevel /* src=10.1.1.1 | src=192.1.1.1 */ 127 0 stevel /* | */ 128 0 stevel /* | in, processed by fr_checknatin() for x */ 129 0 stevel /* <------------ | <------------ */ 130 0 stevel /* dst=10.1.1.1 | dst=192.1.1.1 */ 131 0 stevel /* -------------------- -+- ------------------------------------- */ 132 0 stevel /* fr_checknatout() - changes ip_src and if required, sport */ 133 0 stevel /* - creates a new mapping, if required. */ 134 0 stevel /* fr_checknatin() - changes ip_dst and if required, dport */ 135 0 stevel /* */ 136 0 stevel /* In the NAT table, internal source is recorded as "in" and externally */ 137 0 stevel /* seen as "out". */ 138 0 stevel /* ======================================================================== */ 139 0 stevel 140 3448 dh155122 141 3448 dh155122 static int nat_clearlist __P((ipf_stack_t *)); 142 3448 dh155122 static void nat_addnat __P((struct ipnat *, ipf_stack_t *)); 143 3448 dh155122 static void nat_addrdr __P((struct ipnat *, ipf_stack_t *)); 144 3448 dh155122 static int fr_natgetent __P((caddr_t, ipf_stack_t *)); 145 3448 dh155122 static int fr_natgetsz __P((caddr_t, ipf_stack_t *)); 146 3448 dh155122 static int fr_natputent __P((caddr_t, int, ipf_stack_t *)); 147 3448 dh155122 static void nat_tabmove __P((nat_t *, ipf_stack_t *)); 148 0 stevel static int nat_match __P((fr_info_t *, ipnat_t *)); 149 0 stevel static INLINE int nat_newmap __P((fr_info_t *, nat_t *, natinfo_t *)); 150 0 stevel static INLINE int nat_newrdr __P((fr_info_t *, nat_t *, natinfo_t *)); 151 0 stevel static hostmap_t *nat_hostmap __P((ipnat_t *, struct in_addr, 152 3448 dh155122 struct in_addr, struct in_addr, u_32_t, 153 3448 dh155122 ipf_stack_t *)); 154 0 stevel static INLINE int nat_icmpquerytype4 __P((int)); 155 7176 yx160601 static int nat_ruleaddrinit __P((ipnat_t *)); 156 7176 yx160601 static int nat_siocaddnat __P((ipnat_t *, ipnat_t **, int, ipf_stack_t *)); 157 7176 yx160601 static void nat_siocdelnat __P((ipnat_t *, ipnat_t **, int, ipf_stack_t *)); 158 3448 dh155122 static INLINE int nat_icmperrortype4 __P((int)); 159 0 stevel static INLINE int nat_finalise __P((fr_info_t *, nat_t *, natinfo_t *, 160 0 stevel tcphdr_t *, nat_t **, int)); 161 4380 jojemann static INLINE int nat_resolverule __P((ipnat_t *, ipf_stack_t *)); 162 2958 dr146992 static void nat_mssclamp __P((tcphdr_t *, u_32_t, u_short *)); 163 3448 dh155122 static int nat_getnext __P((ipftoken_t *, ipfgeniter_t *, ipf_stack_t *)); 164 3448 dh155122 static int nat_iterator __P((ipftoken_t *, ipfgeniter_t *, ipf_stack_t *)); 165 8170 John static int nat_flushtable __P((int, ipf_stack_t *)); 166 0 stevel 167 6253 an207044 #define NAT_HAS_L4_CHANGED(n) \ 168 6295 an207044 (((n)->nat_flags & (IPN_TCPUDPICMP)) && \ 169 6295 an207044 (n)->nat_inport != (n)->nat_outport) 170 8170 John 171 0 stevel 172 0 stevel /* ------------------------------------------------------------------------ */ 173 0 stevel /* Function: fr_natinit */ 174 0 stevel /* Returns: int - 0 == success, -1 == failure */ 175 0 stevel /* Parameters: Nil */ 176 0 stevel /* */ 177 0 stevel /* Initialise all of the NAT locks, tables and other structures. */ 178 0 stevel /* ------------------------------------------------------------------------ */ 179 3448 dh155122 int fr_natinit(ifs) 180 3448 dh155122 ipf_stack_t *ifs; 181 0 stevel { 182 0 stevel int i; 183 0 stevel 184 3448 dh155122 KMALLOCS(ifs->ifs_nat_table[0], nat_t **, 185 3448 dh155122 sizeof(nat_t *) * ifs->ifs_ipf_nattable_sz); 186 3448 dh155122 if (ifs->ifs_nat_table[0] != NULL) 187 3448 dh155122 bzero((char *)ifs->ifs_nat_table[0], 188 3448 dh155122 ifs->ifs_ipf_nattable_sz * sizeof(nat_t *)); 189 0 stevel else 190 0 stevel return -1; 191 0 stevel 192 3448 dh155122 KMALLOCS(ifs->ifs_nat_table[1], nat_t **, 193 3448 dh155122 sizeof(nat_t *) * ifs->ifs_ipf_nattable_sz); 194 3448 dh155122 if (ifs->ifs_nat_table[1] != NULL) 195 3448 dh155122 bzero((char *)ifs->ifs_nat_table[1], 196 3448 dh155122 ifs->ifs_ipf_nattable_sz * sizeof(nat_t *)); 197 0 stevel else 198 2393 yz155240 return -2; 199 0 stevel 200 3448 dh155122 KMALLOCS(ifs->ifs_nat_rules, ipnat_t **, 201 3448 dh155122 sizeof(ipnat_t *) * ifs->ifs_ipf_natrules_sz); 202 3448 dh155122 if (ifs->ifs_nat_rules != NULL) 203 3448 dh155122 bzero((char *)ifs->ifs_nat_rules, 204 3448 dh155122 ifs->ifs_ipf_natrules_sz * sizeof(ipnat_t *)); 205 0 stevel else 206 2393 yz155240 return -3; 207 0 stevel 208 3448 dh155122 KMALLOCS(ifs->ifs_rdr_rules, ipnat_t **, 209 3448 dh155122 sizeof(ipnat_t *) * ifs->ifs_ipf_rdrrules_sz); 210 3448 dh155122 if (ifs->ifs_rdr_rules != NULL) 211 3448 dh155122 bzero((char *)ifs->ifs_rdr_rules, 212 3448 dh155122 ifs->ifs_ipf_rdrrules_sz * sizeof(ipnat_t *)); 213 0 stevel else 214 2393 yz155240 return -4; 215 0 stevel 216 3448 dh155122 KMALLOCS(ifs->ifs_maptable, hostmap_t **, 217 3448 dh155122 sizeof(hostmap_t *) * ifs->ifs_ipf_hostmap_sz); 218 3448 dh155122 if (ifs->ifs_maptable != NULL) 219 3448 dh155122 bzero((char *)ifs->ifs_maptable, 220 3448 dh155122 sizeof(hostmap_t *) * ifs->ifs_ipf_hostmap_sz); 221 0 stevel else 222 2393 yz155240 return -5; 223 0 stevel 224 3448 dh155122 ifs->ifs_ipf_hm_maplist = NULL; 225 3448 dh155122 226 3448 dh155122 KMALLOCS(ifs->ifs_nat_stats.ns_bucketlen[0], u_long *, 227 3448 dh155122 ifs->ifs_ipf_nattable_sz * sizeof(u_long)); 228 3448 dh155122 if (ifs->ifs_nat_stats.ns_bucketlen[0] == NULL) 229 3448 dh155122 return -1; 230 3448 dh155122 bzero((char *)ifs->ifs_nat_stats.ns_bucketlen[0], 231 3448 dh155122 ifs->ifs_ipf_nattable_sz * sizeof(u_long)); 232 3448 dh155122 233 3448 dh155122 KMALLOCS(ifs->ifs_nat_stats.ns_bucketlen[1], u_long *, 234 3448 dh155122 ifs->ifs_ipf_nattable_sz * sizeof(u_long)); 235 3448 dh155122 if (ifs->ifs_nat_stats.ns_bucketlen[1] == NULL) 236 3448 dh155122 return -1; 237 3448 dh155122 bzero((char *)ifs->ifs_nat_stats.ns_bucketlen[1], 238 3448 dh155122 ifs->ifs_ipf_nattable_sz * sizeof(u_long)); 239 3448 dh155122 240 3448 dh155122 if (ifs->ifs_fr_nat_maxbucket == 0) { 241 3448 dh155122 for (i = ifs->ifs_ipf_nattable_sz; i > 0; i >>= 1) 242 3448 dh155122 ifs->ifs_fr_nat_maxbucket++; 243 3448 dh155122 ifs->ifs_fr_nat_maxbucket *= 2; 244 3448 dh155122 } 245 3448 dh155122 246 3448 dh155122 fr_sttab_init(ifs->ifs_nat_tqb, ifs); 247 0 stevel /* 248 0 stevel * Increase this because we may have "keep state" following this too 249 0 stevel * and packet storms can occur if this is removed too quickly. 250 0 stevel */ 251 3448 dh155122 ifs->ifs_nat_tqb[IPF_TCPS_CLOSED].ifq_ttl = ifs->ifs_fr_tcplastack; 252 3448 dh155122 ifs->ifs_nat_tqb[IPF_TCP_NSTATES - 1].ifq_next = &ifs->ifs_nat_udptq; 253 3448 dh155122 ifs->ifs_nat_udptq.ifq_ttl = ifs->ifs_fr_defnatage; 254 3448 dh155122 ifs->ifs_nat_udptq.ifq_ref = 1; 255 3448 dh155122 ifs->ifs_nat_udptq.ifq_head = NULL; 256 3448 dh155122 ifs->ifs_nat_udptq.ifq_tail = &ifs->ifs_nat_udptq.ifq_head; 257 3448 dh155122 MUTEX_INIT(&ifs->ifs_nat_udptq.ifq_lock, "nat ipftq udp tab"); 258 3448 dh155122 ifs->ifs_nat_udptq.ifq_next = &ifs->ifs_nat_icmptq; 259 3448 dh155122 ifs->ifs_nat_icmptq.ifq_ttl = ifs->ifs_fr_defnaticmpage; 260 3448 dh155122 ifs->ifs_nat_icmptq.ifq_ref = 1; 261 3448 dh155122 ifs->ifs_nat_icmptq.ifq_head = NULL; 262 3448 dh155122 ifs->ifs_nat_icmptq.ifq_tail = &ifs->ifs_nat_icmptq.ifq_head; 263 3448 dh155122 MUTEX_INIT(&ifs->ifs_nat_icmptq.ifq_lock, "nat icmp ipftq tab"); 264 3448 dh155122 ifs->ifs_nat_icmptq.ifq_next = &ifs->ifs_nat_iptq; 265 3448 dh155122 ifs->ifs_nat_iptq.ifq_ttl = ifs->ifs_fr_defnatipage; 266 3448 dh155122 ifs->ifs_nat_iptq.ifq_ref = 1; 267 3448 dh155122 ifs->ifs_nat_iptq.ifq_head = NULL; 268 3448 dh155122 ifs->ifs_nat_iptq.ifq_tail = &ifs->ifs_nat_iptq.ifq_head; 269 3448 dh155122 MUTEX_INIT(&ifs->ifs_nat_iptq.ifq_lock, "nat ip ipftq tab"); 270 3448 dh155122 ifs->ifs_nat_iptq.ifq_next = NULL; 271 0 stevel 272 0 stevel for (i = 0; i < IPF_TCP_NSTATES; i++) { 273 3448 dh155122 if (ifs->ifs_nat_tqb[i].ifq_ttl < ifs->ifs_fr_defnaticmpage) 274 3448 dh155122 ifs->ifs_nat_tqb[i].ifq_ttl = ifs->ifs_fr_defnaticmpage; 275 0 stevel #ifdef LARGE_NAT 276 3448 dh155122 else if (ifs->ifs_nat_tqb[i].ifq_ttl > ifs->ifs_fr_defnatage) 277 3448 dh155122 ifs->ifs_nat_tqb[i].ifq_ttl = ifs->ifs_fr_defnatage; 278 0 stevel #endif 279 0 stevel } 280 0 stevel 281 0 stevel /* 282 0 stevel * Increase this because we may have "keep state" following 283 0 stevel * this too and packet storms can occur if this is removed 284 0 stevel * too quickly. 285 0 stevel */ 286 3448 dh155122 ifs->ifs_nat_tqb[IPF_TCPS_CLOSED].ifq_ttl = 287 3448 dh155122 ifs->ifs_nat_tqb[IPF_TCPS_LAST_ACK].ifq_ttl; 288 3448 dh155122 289 3448 dh155122 RWLOCK_INIT(&ifs->ifs_ipf_nat, "ipf IP NAT rwlock"); 290 3448 dh155122 RWLOCK_INIT(&ifs->ifs_ipf_natfrag, "ipf IP NAT-Frag rwlock"); 291 3448 dh155122 MUTEX_INIT(&ifs->ifs_ipf_nat_new, "ipf nat new mutex"); 292 3448 dh155122 MUTEX_INIT(&ifs->ifs_ipf_natio, "ipf nat io mutex"); 293 3448 dh155122 294 3448 dh155122 ifs->ifs_fr_nat_init = 1; 295 8170 John ifs->ifs_nat_last_force_flush = ifs->ifs_fr_ticks; 296 0 stevel return 0; 297 0 stevel } 298 0 stevel 299 0 stevel 300 0 stevel /* ------------------------------------------------------------------------ */ 301 0 stevel /* Function: nat_addrdr */ 302 0 stevel /* Returns: Nil */ 303 0 stevel /* Parameters: n(I) - pointer to NAT rule to add */ 304 0 stevel /* */ 305 0 stevel /* Adds a redirect rule to the hash table of redirect rules and the list of */ 306 0 stevel /* loaded NAT rules. Updates the bitmask indicating which netmasks are in */ 307 0 stevel /* use by redirect rules. */ 308 0 stevel /* ------------------------------------------------------------------------ */ 309 3448 dh155122 static void nat_addrdr(n, ifs) 310 0 stevel ipnat_t *n; 311 3448 dh155122 ipf_stack_t *ifs; 312 0 stevel { 313 0 stevel ipnat_t **np; 314 0 stevel u_32_t j; 315 0 stevel u_int hv; 316 0 stevel int k; 317 0 stevel 318 0 stevel k = count4bits(n->in_outmsk); 319 0 stevel if ((k >= 0) && (k != 32)) 320 3448 dh155122 ifs->ifs_rdr_masks |= 1 << k; 321 0 stevel j = (n->in_outip & n->in_outmsk); 322 3448 dh155122 hv = NAT_HASH_FN(j, 0, ifs->ifs_ipf_rdrrules_sz); 323 3448 dh155122 np = ifs->ifs_rdr_rules + hv; 324 0 stevel while (*np != NULL) 325 0 stevel np = &(*np)->in_rnext; 326 0 stevel n->in_rnext = NULL; 327 0 stevel n->in_prnext = np; 328 2393 yz155240 n->in_hv = hv; 329 0 stevel *np = n; 330 0 stevel } 331 0 stevel 332 0 stevel 333 0 stevel /* ------------------------------------------------------------------------ */ 334 0 stevel /* Function: nat_addnat */ 335 0 stevel /* Returns: Nil */ 336 0 stevel /* Parameters: n(I) - pointer to NAT rule to add */ 337 0 stevel /* */ 338 0 stevel /* Adds a NAT map rule to the hash table of rules and the list of loaded */ 339 0 stevel /* NAT rules. Updates the bitmask indicating which netmasks are in use by */ 340 0 stevel /* redirect rules. */ 341 0 stevel /* ------------------------------------------------------------------------ */ 342 3448 dh155122 static void nat_addnat(n, ifs) 343 0 stevel ipnat_t *n; 344 3448 dh155122 ipf_stack_t *ifs; 345 0 stevel { 346 0 stevel ipnat_t **np; 347 0 stevel u_32_t j; 348 0 stevel u_int hv; 349 0 stevel int k; 350 0 stevel 351 0 stevel k = count4bits(n->in_inmsk); 352 0 stevel if ((k >= 0) && (k != 32)) 353 3448 dh155122 ifs->ifs_nat_masks |= 1 << k; 354 0 stevel j = (n->in_inip & n->in_inmsk); 355 3448 dh155122 hv = NAT_HASH_FN(j, 0, ifs->ifs_ipf_natrules_sz); 356 3448 dh155122 np = ifs->ifs_nat_rules + hv; 357 0 stevel while (*np != NULL) 358 0 stevel np = &(*np)->in_mnext; 359 0 stevel n->in_mnext = NULL; 360 0 stevel n->in_pmnext = np; 361 2393 yz155240 n->in_hv = hv; 362 0 stevel *np = n; 363 0 stevel } 364 0 stevel 365 0 stevel 366 0 stevel /* ------------------------------------------------------------------------ */ 367 0 stevel /* Function: nat_delrdr */ 368 0 stevel /* Returns: Nil */ 369 0 stevel /* Parameters: n(I) - pointer to NAT rule to delete */ 370 0 stevel /* */ 371 0 stevel /* Removes a redirect rule from the hash table of redirect rules. */ 372 0 stevel /* ------------------------------------------------------------------------ */ 373 7176 yx160601 void nat_delrdr(n) 374 0 stevel ipnat_t *n; 375 0 stevel { 376 0 stevel if (n->in_rnext) 377 0 stevel n->in_rnext->in_prnext = n->in_prnext; 378 0 stevel *n->in_prnext = n->in_rnext; 379 0 stevel } 380 0 stevel 381 0 stevel 382 0 stevel /* ------------------------------------------------------------------------ */ 383 0 stevel /* Function: nat_delnat */ 384 0 stevel /* Returns: Nil */ 385 0 stevel /* Parameters: n(I) - pointer to NAT rule to delete */ 386 0 stevel /* */ 387 0 stevel /* Removes a NAT map rule from the hash table of NAT map rules. */ 388 0 stevel /* ------------------------------------------------------------------------ */ 389 7176 yx160601 void nat_delnat(n) 390 0 stevel ipnat_t *n; 391 0 stevel { 392 0 stevel if (n->in_mnext != NULL) 393 0 stevel n->in_mnext->in_pmnext = n->in_pmnext; 394 0 stevel *n->in_pmnext = n->in_mnext; 395 0 stevel } 396 0 stevel 397 0 stevel 398 0 stevel /* ------------------------------------------------------------------------ */ 399 0 stevel /* Function: nat_hostmap */ 400 0 stevel /* Returns: struct hostmap* - NULL if no hostmap could be created, */ 401 0 stevel /* else a pointer to the hostmapping to use */ 402 0 stevel /* Parameters: np(I) - pointer to NAT rule */ 403 0 stevel /* real(I) - real IP address */ 404 0 stevel /* map(I) - mapped IP address */ 405 0 stevel /* port(I) - destination port number */ 406 0 stevel /* Write Locks: ipf_nat */ 407 0 stevel /* */ 408 0 stevel /* Check if an ip address has already been allocated for a given mapping */ 409 0 stevel /* that is not doing port based translation. If is not yet allocated, then */ 410 2393 yz155240 /* create a new entry if a non-NULL NAT rule pointer has been supplied. */ 411 0 stevel /* ------------------------------------------------------------------------ */ 412 3448 dh155122 static struct hostmap *nat_hostmap(np, src, dst, map, port, ifs) 413 0 stevel ipnat_t *np; 414 0 stevel struct in_addr src; 415 0 stevel struct in_addr dst; 416 0 stevel struct in_addr map; 417 0 stevel u_32_t port; 418 3448 dh155122 ipf_stack_t *ifs; 419 0 stevel { 420 0 stevel hostmap_t *hm; 421 0 stevel u_int hv; 422 0 stevel 423 0 stevel hv = (src.s_addr ^ dst.s_addr); 424 0 stevel hv += src.s_addr; 425 0 stevel hv += dst.s_addr; 426 0 stevel hv %= HOSTMAP_SIZE; 427 3448 dh155122 for (hm = ifs->ifs_maptable[hv]; hm; hm = hm->hm_next) 428 0 stevel if ((hm->hm_srcip.s_addr == src.s_addr) && 429 0 stevel (hm->hm_dstip.s_addr == dst.s_addr) && 430 0 stevel ((np == NULL) || (np == hm->hm_ipnat)) && 431 0 stevel ((port == 0) || (port == hm->hm_port))) { 432 0 stevel hm->hm_ref++; 433 0 stevel return hm; 434 0 stevel } 435 0 stevel 436 0 stevel if (np == NULL) 437 0 stevel return NULL; 438 0 stevel 439 0 stevel KMALLOC(hm, hostmap_t *); 440 0 stevel if (hm) { 441 3448 dh155122 hm->hm_hnext = ifs->ifs_ipf_hm_maplist; 442 3448 dh155122 hm->hm_phnext = &ifs->ifs_ipf_hm_maplist; 443 3448 dh155122 if (ifs->ifs_ipf_hm_maplist != NULL) 444 3448 dh155122 ifs->ifs_ipf_hm_maplist->hm_phnext = &hm->hm_hnext; 445 3448 dh155122 ifs->ifs_ipf_hm_maplist = hm; 446 3448 dh155122 447 3448 dh155122 hm->hm_next = ifs->ifs_maptable[hv]; 448 3448 dh155122 hm->hm_pnext = ifs->ifs_maptable + hv; 449 3448 dh155122 if (ifs->ifs_maptable[hv] != NULL) 450 3448 dh155122 ifs->ifs_maptable[hv]->hm_pnext = &hm->hm_next; 451 3448 dh155122 ifs->ifs_maptable[hv] = hm; 452 0 stevel hm->hm_ipnat = np; 453 0 stevel hm->hm_srcip = src; 454 0 stevel hm->hm_dstip = dst; 455 0 stevel hm->hm_mapip = map; 456 0 stevel hm->hm_ref = 1; 457 0 stevel hm->hm_port = port; 458 7176 yx160601 hm->hm_v = 4; 459 0 stevel } 460 0 stevel return hm; 461 0 stevel } 462 0 stevel 463 0 stevel 464 0 stevel /* ------------------------------------------------------------------------ */ 465 5417 jojemann /* Function: fr_hostmapdel */ 466 5417 jojemann /* Returns: Nil */ 467 5417 jojemann /* Parameters: hmp(I) - pointer to pointer to hostmap structure */ 468 0 stevel /* Write Locks: ipf_nat */ 469 0 stevel /* */ 470 0 stevel /* Decrement the references to this hostmap structure by one. If this */ 471 0 stevel /* reaches zero then remove it and free it. */ 472 0 stevel /* ------------------------------------------------------------------------ */ 473 5417 jojemann void fr_hostmapdel(hmp) 474 5417 jojemann struct hostmap **hmp; 475 5417 jojemann { 476 5417 jojemann struct hostmap *hm; 477 5417 jojemann 478 5417 jojemann hm = *hmp; 479 5417 jojemann *hmp = NULL; 480 5417 jojemann 481 0 stevel hm->hm_ref--; 482 0 stevel if (hm->hm_ref == 0) { 483 0 stevel if (hm->hm_next) 484 0 stevel hm->hm_next->hm_pnext = hm->hm_pnext; 485 0 stevel *hm->hm_pnext = hm->hm_next; 486 3448 dh155122 if (hm->hm_hnext) 487 3448 dh155122 hm->hm_hnext->hm_phnext = hm->hm_phnext; 488 3448 dh155122 *hm->hm_phnext = hm->hm_hnext; 489 0 stevel KFREE(hm); 490 0 stevel } 491 0 stevel } 492 0 stevel 493 0 stevel 494 0 stevel /* ------------------------------------------------------------------------ */ 495 0 stevel /* Function: fix_outcksum */ 496 0 stevel /* Returns: Nil */ 497 2958 dr146992 /* Parameters: sp(I) - location of 16bit checksum to update */ 498 0 stevel /* n((I) - amount to adjust checksum by */ 499 0 stevel /* */ 500 0 stevel /* Adjusts the 16bit checksum by "n" for packets going out. */ 501 0 stevel /* ------------------------------------------------------------------------ */ 502 2958 dr146992 void fix_outcksum(sp, n) 503 0 stevel u_short *sp; 504 0 stevel u_32_t n; 505 0 stevel { 506 0 stevel u_short sumshort; 507 0 stevel u_32_t sum1; 508 0 stevel 509 0 stevel if (n == 0) 510 0 stevel return; 511 0 stevel 512 0 stevel sum1 = (~ntohs(*sp)) & 0xffff; 513 0 stevel sum1 += (n); 514 0 stevel sum1 = (sum1 >> 16) + (sum1 & 0xffff); 515 0 stevel /* Again */ 516 0 stevel sum1 = (sum1 >> 16) + (sum1 & 0xffff); 517 0 stevel sumshort = ~(u_short)sum1; 518 0 stevel *(sp) = htons(sumshort); 519 0 stevel } 520 0 stevel 521 0 stevel 522 0 stevel /* ------------------------------------------------------------------------ */ 523 0 stevel /* Function: fix_incksum */ 524 0 stevel /* Returns: Nil */ 525 2958 dr146992 /* Parameters: sp(I) - location of 16bit checksum to update */ 526 0 stevel /* n((I) - amount to adjust checksum by */ 527 0 stevel /* */ 528 0 stevel /* Adjusts the 16bit checksum by "n" for packets going in. */ 529 0 stevel /* ------------------------------------------------------------------------ */ 530 2958 dr146992 void fix_incksum(sp, n) 531 0 stevel u_short *sp; 532 0 stevel u_32_t n; 533 0 stevel { 534 0 stevel u_short sumshort; 535 0 stevel u_32_t sum1; 536 0 stevel 537 0 stevel if (n == 0) 538 0 stevel return; 539 0 stevel 540 0 stevel sum1 = (~ntohs(*sp)) & 0xffff; 541 0 stevel sum1 += ~(n) & 0xffff; 542 0 stevel sum1 = (sum1 >> 16) + (sum1 & 0xffff); 543 0 stevel /* Again */ 544 0 stevel sum1 = (sum1 >> 16) + (sum1 & 0xffff); 545 0 stevel sumshort = ~(u_short)sum1; 546 0 stevel *(sp) = htons(sumshort); 547 0 stevel } 548 0 stevel 549 0 stevel 550 0 stevel /* ------------------------------------------------------------------------ */ 551 0 stevel /* Function: fix_datacksum */ 552 0 stevel /* Returns: Nil */ 553 0 stevel /* Parameters: sp(I) - location of 16bit checksum to update */ 554 0 stevel /* n((I) - amount to adjust checksum by */ 555 0 stevel /* */ 556 0 stevel /* Fix_datacksum is used *only* for the adjustments of checksums in the */ 557 0 stevel /* data section of an IP packet. */ 558 0 stevel /* */ 559 0 stevel /* The only situation in which you need to do this is when NAT'ing an */ 560 0 stevel /* ICMP error message. Such a message, contains in its body the IP header */ 561 0 stevel /* of the original IP packet, that causes the error. */ 562 0 stevel /* */ 563 0 stevel /* You can't use fix_incksum or fix_outcksum in that case, because for the */ 564 0 stevel /* kernel the data section of the ICMP error is just data, and no special */ 565 0 stevel /* processing like hardware cksum or ntohs processing have been done by the */ 566 0 stevel /* kernel on the data section. */ 567 0 stevel /* ------------------------------------------------------------------------ */ 568 0 stevel void fix_datacksum(sp, n) 569 0 stevel u_short *sp; 570 0 stevel u_32_t n; 571 0 stevel { 572 0 stevel u_short sumshort; 573 0 stevel u_32_t sum1; 574 0 stevel 575 0 stevel if (n == 0) 576 0 stevel return; 577 0 stevel 578 0 stevel sum1 = (~ntohs(*sp)) & 0xffff; 579 0 stevel sum1 += (n); 580 0 stevel sum1 = (sum1 >> 16) + (sum1 & 0xffff); 581 0 stevel /* Again */ 582 0 stevel sum1 = (sum1 >> 16) + (sum1 & 0xffff); 583 0 stevel sumshort = ~(u_short)sum1; 584 0 stevel *(sp) = htons(sumshort); 585 0 stevel } 586 0 stevel 587 0 stevel 588 0 stevel /* ------------------------------------------------------------------------ */ 589 0 stevel /* Function: fr_nat_ioctl */ 590 0 stevel /* Returns: int - 0 == success, != 0 == failure */ 591 0 stevel /* Parameters: data(I) - pointer to ioctl data */ 592 0 stevel /* cmd(I) - ioctl command integer */ 593 0 stevel /* mode(I) - file mode bits used with open */ 594 8170 John /* uid(I) - uid of caller */ 595 8170 John /* ctx(I) - pointer to give the uid context */ 596 8170 John /* ifs - ipf stack instance */ 597 0 stevel /* */ 598 0 stevel /* Processes an ioctl call made to operate on the IP Filter NAT device. */ 599 0 stevel /* ------------------------------------------------------------------------ */ 600 3448 dh155122 int fr_nat_ioctl(data, cmd, mode, uid, ctx, ifs) 601 2393 yz155240 ioctlcmd_t cmd; 602 0 stevel caddr_t data; 603 3448 dh155122 int mode, uid; 604 3448 dh155122 void *ctx; 605 3448 dh155122 ipf_stack_t *ifs; 606 0 stevel { 607 0 stevel ipnat_t *nat, *nt, *n = NULL, **np = NULL; 608 0 stevel int error = 0, ret, arg, getlock; 609 0 stevel ipnat_t natd; 610 0 stevel 611 0 stevel #if (BSD >= 199306) && defined(_KERNEL) 612 0 stevel if ((securelevel >= 2) && (mode & FWRITE)) 613 0 stevel return EPERM; 614 0 stevel #endif 615 0 stevel 616 0 stevel #if defined(__osf__) && defined(_KERNEL) 617 0 stevel getlock = 0; 618 0 stevel #else 619 0 stevel getlock = (mode & NAT_LOCKHELD) ? 0 : 1; 620 0 stevel #endif 621 0 stevel 622 0 stevel nat = NULL; /* XXX gcc -Wuninitialized */ 623 2393 yz155240 if (cmd == (ioctlcmd_t)SIOCADNAT) { 624 0 stevel KMALLOC(nt, ipnat_t *); 625 0 stevel } else { 626 0 stevel nt = NULL; 627 0 stevel } 628 0 stevel 629 2393 yz155240 if ((cmd == (ioctlcmd_t)SIOCADNAT) || (cmd == (ioctlcmd_t)SIOCRMNAT)) { 630 0 stevel if (mode & NAT_SYSSPACE) { 631 0 stevel bcopy(data, (char *)&natd, sizeof(natd)); 632 0 stevel error = 0; 633 0 stevel } else { 634 0 stevel error = fr_inobj(data, &natd, IPFOBJ_IPNAT); 635 0 stevel } 636 0 stevel 637 0 stevel } 638 0 stevel 639 0 stevel if (error != 0) 640 0 stevel goto done; 641 0 stevel 642 0 stevel /* 643 0 stevel * For add/delete, look to see if the NAT entry is already present 644 0 stevel */ 645 2393 yz155240 if ((cmd == (ioctlcmd_t)SIOCADNAT) || (cmd == (ioctlcmd_t)SIOCRMNAT)) { 646 0 stevel nat = &natd; 647 2393 yz155240 if (nat->in_v == 0) /* For backward compat. */ 648 2393 yz155240 nat->in_v = 4; 649 0 stevel nat->in_flags &= IPN_USERFLAGS; 650 0 stevel if ((nat->in_redir & NAT_MAPBLK) == 0) { 651 0 stevel if ((nat->in_flags & IPN_SPLIT) == 0) 652 0 stevel nat->in_inip &= nat->in_inmsk; 653 0 stevel if ((nat->in_flags & IPN_IPRANGE) == 0) 654 0 stevel nat->in_outip &= nat->in_outmsk; 655 0 stevel } 656 3448 dh155122 MUTEX_ENTER(&ifs->ifs_ipf_natio); 657 3448 dh155122 for (np = &ifs->ifs_nat_list; ((n = *np) != NULL); 658 3448 dh155122 np = &n->in_next) 659 5828 jojemann if (bcmp((char *)&nat->in_flags, (char *)&n->in_flags, 660 5828 jojemann IPN_CMPSIZ) == 0) { 661 5828 jojemann if (nat->in_redir == NAT_REDIRECT && 662 5828 jojemann nat->in_pnext != n->in_pnext) 663 5828 jojemann continue; 664 5828 jojemann break; 665 5828 jojemann } 666 0 stevel } 667 0 stevel 668 0 stevel switch (cmd) 669 0 stevel { 670 3448 dh155122 case SIOCGENITER : 671 3448 dh155122 { 672 3448 dh155122 ipfgeniter_t iter; 673 3448 dh155122 ipftoken_t *token; 674 3448 dh155122 675 3448 dh155122 error = fr_inobj(data, &iter, IPFOBJ_GENITER); 676 3448 dh155122 if (error != 0) 677 3448 dh155122 break; 678 3448 dh155122 679 3448 dh155122 token = ipf_findtoken(iter.igi_type, uid, ctx, ifs); 680 3448 dh155122 if (token != NULL) 681 3448 dh155122 error = nat_iterator(token, &iter, ifs); 682 3448 dh155122 else 683 3448 dh155122 error = ESRCH; 684 3448 dh155122 RWLOCK_EXIT(&ifs->ifs_ipf_tokens); 685 3448 dh155122 break; 686 3448 dh155122 } 687 0 stevel #ifdef IPFILTER_LOG 688 0 stevel case SIOCIPFFB : 689 0 stevel { 690 0 stevel int tmp; 691 0 stevel 692 0 stevel if (!(mode & FWRITE)) 693 0 stevel error = EPERM; 694 0 stevel else { 695 3448 dh155122 tmp = ipflog_clear(IPL_LOGNAT, ifs); 696 7433 John error = BCOPYOUT((char *)&tmp, (char *)data, 697 7433 John sizeof(tmp)); 698 7433 John if (error != 0) 699 7433 John error = EFAULT; 700 0 stevel } 701 0 stevel break; 702 0 stevel } 703 0 stevel case SIOCSETLG : 704 7433 John if (!(mode & FWRITE)) { 705 7433 John error = EPERM; 706 7433 John } else { 707 7433 John error = BCOPYIN((char *)data, 708 7433 John (char *)&ifs->ifs_nat_logging, 709 7433 John sizeof(ifs->ifs_nat_logging)); 710 7433 John if (error != 0) 711 7433 John error = EFAULT; 712 7433 John } 713 7433 John break; 714 7433 John case SIOCGETLG : 715 7433 John error = BCOPYOUT((char *)&ifs->ifs_nat_logging, (char *)data, 716 3448 dh155122 sizeof(ifs->ifs_nat_logging)); 717 7433 John if (error != 0) 718 7433 John error = EFAULT; 719 0 stevel break; 720 0 stevel case FIONREAD : 721 3448 dh155122 arg = ifs->ifs_iplused[IPL_LOGNAT]; 722 7433 John error = BCOPYOUT(&arg, data, sizeof(arg)); 723 7433 John if (error != 0) 724 7433 John error = EFAULT; 725 0 stevel break; 726 0 stevel #endif 727 0 stevel case SIOCADNAT : 728 0 stevel if (!(mode & FWRITE)) { 729 0 stevel error = EPERM; 730 0 stevel } else if (n != NULL) { 731 0 stevel error = EEXIST; 732 0 stevel } else if (nt == NULL) { 733 0 stevel error = ENOMEM; 734 0 stevel } 735 0 stevel if (error != 0) { 736 3448 dh155122 MUTEX_EXIT(&ifs->ifs_ipf_natio); 737 0 stevel break; 738 0 stevel } 739 0 stevel bcopy((char *)nat, (char *)nt, sizeof(*n)); 740 3448 dh155122 error = nat_siocaddnat(nt, np, getlock, ifs); 741 3448 dh155122 MUTEX_EXIT(&ifs->ifs_ipf_natio); 742 0 stevel if (error == 0) 743 0 stevel nt = NULL; 744 0 stevel break; 745 0 stevel case SIOCRMNAT : 746 0 stevel if (!(mode & FWRITE)) { 747 0 stevel error = EPERM; 748 0 stevel n = NULL; 749 0 stevel } else if (n == NULL) { 750 0 stevel error = ESRCH; 751 0 stevel } 752 0 stevel 753 0 stevel if (error != 0) { 754 3448 dh155122 MUTEX_EXIT(&ifs->ifs_ipf_natio); 755 3448 dh155122 break; 756 3448 dh155122 } 757 3448 dh155122 nat_siocdelnat(n, np, getlock, ifs); 758 3448 dh155122 759 3448 dh155122 MUTEX_EXIT(&ifs->ifs_ipf_natio); 760 0 stevel n = NULL; 761 0 stevel break; 762 0 stevel case SIOCGNATS : 763 3448 dh155122 ifs->ifs_nat_stats.ns_table[0] = ifs->ifs_nat_table[0]; 764 3448 dh155122 ifs->ifs_nat_stats.ns_table[1] = ifs->ifs_nat_table[1]; 765 3448 dh155122 ifs->ifs_nat_stats.ns_list = ifs->ifs_nat_list; 766 3448 dh155122 ifs->ifs_nat_stats.ns_maptable = ifs->ifs_maptable; 767 3448 dh155122 ifs->ifs_nat_stats.ns_maplist = ifs->ifs_ipf_hm_maplist; 768 3448 dh155122 ifs->ifs_nat_stats.ns_nattab_max = ifs->ifs_ipf_nattable_max; 769 3448 dh155122 ifs->ifs_nat_stats.ns_nattab_sz = ifs->ifs_ipf_nattable_sz; 770 3448 dh155122 ifs->ifs_nat_stats.ns_rultab_sz = ifs->ifs_ipf_natrules_sz; 771 3448 dh155122 ifs->ifs_nat_stats.ns_rdrtab_sz = ifs->ifs_ipf_rdrrules_sz; 772 3448 dh155122 ifs->ifs_nat_stats.ns_hostmap_sz = ifs->ifs_ipf_hostmap_sz; 773 3448 dh155122 ifs->ifs_nat_stats.ns_instances = ifs->ifs_nat_instances; 774 3448 dh155122 ifs->ifs_nat_stats.ns_apslist = ifs->ifs_ap_sess_list; 775 3448 dh155122 error = fr_outobj(data, &ifs->ifs_nat_stats, IPFOBJ_NATSTAT); 776 0 stevel break; 777 0 stevel case SIOCGNATL : 778 0 stevel { 779 0 stevel natlookup_t nl; 780 0 stevel 781 0 stevel if (getlock) { 782 3448 dh155122 READ_ENTER(&ifs->ifs_ipf_nat); 783 0 stevel } 784 0 stevel error = fr_inobj(data, &nl, IPFOBJ_NATLOOKUP); 785 7176 yx160601 if (nl.nl_v != 6) 786 7176 yx160601 nl.nl_v = 4; 787 680 dr146992 if (error == 0) { 788 7176 yx160601 void *ptr; 789 7176 yx160601 790 7176 yx160601 switch (nl.nl_v) 791 7176 yx160601 { 792 7176 yx160601 case 4: 793 7176 yx160601 ptr = nat_lookupredir(&nl, ifs); 794 7176 yx160601 break; 795 7176 yx160601 #ifdef USE_INET6 796 7176 yx160601 case 6: 797 7176 yx160601 ptr = nat6_lookupredir(&nl, ifs); 798 7176 yx160601 break; 799 7176 yx160601 #endif 800 7176 yx160601 default: 801 7176 yx160601 ptr = NULL; 802 7176 yx160601 break; 803 7176 yx160601 } 804 7176 yx160601 805 7176 yx160601 if (ptr != NULL) { 806 680 dr146992 error = fr_outobj(data, &nl, IPFOBJ_NATLOOKUP); 807 2393 yz155240 } else { 808 680 dr146992 error = ESRCH; 809 2393 yz155240 } 810 680 dr146992 } 811 0 stevel if (getlock) { 812 3448 dh155122 RWLOCK_EXIT(&ifs->ifs_ipf_nat); 813 0 stevel } 814 0 stevel break; 815 0 stevel } 816 0 stevel case SIOCIPFFL : /* old SIOCFLNAT & SIOCCNATL */ 817 0 stevel if (!(mode & FWRITE)) { 818 0 stevel error = EPERM; 819 0 stevel break; 820 0 stevel } 821 0 stevel if (getlock) { 822 3448 dh155122 WRITE_ENTER(&ifs->ifs_ipf_nat); 823 0 stevel } 824 7433 John error = BCOPYIN(data, &arg, sizeof(arg)); 825 7433 John if (error != 0) { 826 7433 John error = EFAULT; 827 7433 John } else { 828 8170 John if (arg == FLUSH_LIST) 829 7433 John ret = nat_clearlist(ifs); 830 8170 John else if (VALID_TABLE_FLUSH_OPT(arg)) 831 8170 John ret = nat_flushtable(arg, ifs); 832 7433 John else 833 7433 John error = EINVAL; 834 7433 John } 835 0 stevel if (getlock) { 836 3448 dh155122 RWLOCK_EXIT(&ifs->ifs_ipf_nat); 837 0 stevel } 838 0 stevel if (error == 0) { 839 7433 John error = BCOPYOUT(&ret, data, sizeof(ret)); 840 7433 John if (error != 0) 841 7433 John error = EFAULT; 842 0 stevel } 843 0 stevel break; 844 0 stevel case SIOCPROXY : 845 3448 dh155122 error = appr_ioctl(data, cmd, mode, ifs); 846 0 stevel break; 847 0 stevel case SIOCSTLCK : 848 2393 yz155240 if (!(mode & FWRITE)) { 849 2393 yz155240 error = EPERM; 850 2393 yz155240 } else { 851 7433 John error = fr_lock(data, &ifs->ifs_fr_nat_lock); 852 2393 yz155240 } 853 0 stevel break; 854 0 stevel case SIOCSTPUT : 855 2761 jojemann if ((mode & FWRITE) != 0) { 856 3448 dh155122 error = fr_natputent(data, getlock, ifs); 857 1143 jojemann } else { 858 0 stevel error = EACCES; 859 1143 jojemann } 860 0 stevel break; 861 0 stevel case SIOCSTGSZ : 862 3448 dh155122 if (ifs->ifs_fr_nat_lock) { 863 0 stevel if (getlock) { 864 3448 dh155122 READ_ENTER(&ifs->ifs_ipf_nat); 865 3448 dh155122 } 866 3448 dh155122 error = fr_natgetsz(data, ifs); 867 0 stevel if (getlock) { 868 3448 dh155122 RWLOCK_EXIT(&ifs->ifs_ipf_nat); 869 0 stevel } 870 0 stevel } else 871 0 stevel error = EACCES; 872 0 stevel break; 873 0 stevel case SIOCSTGET : 874 3448 dh155122 if (ifs->ifs_fr_nat_lock) { 875 0 stevel if (getlock) { 876 3448 dh155122 READ_ENTER(&ifs->ifs_ipf_nat); 877 3448 dh155122 } 878 3448 dh155122 error = fr_natgetent(data, ifs); 879 0 stevel if (getlock) { 880 3448 dh155122 RWLOCK_EXIT(&ifs->ifs_ipf_nat); 881 0 stevel } 882 0 stevel } else 883 0 stevel error = EACCES; 884 3448 dh155122 break; 885 3448 dh155122 case SIOCIPFDELTOK : 886 7433 John error = BCOPYIN((caddr_t)data, (caddr_t)&arg, sizeof(arg)); 887 7433 John if (error != 0) { 888 7433 John error = EFAULT; 889 7433 John } else { 890 7433 John error = ipf_deltoken(arg, uid, ctx, ifs); 891 7433 John } 892 0 stevel break; 893 0 stevel default : 894 0 stevel error = EINVAL; 895 0 stevel break; 896 0 stevel } 897 0 stevel done: 898 0 stevel if (nt) 899 0 stevel KFREE(nt); 900 0 stevel return error; 901 0 stevel } 902 0 stevel 903 0 stevel 904 0 stevel /* ------------------------------------------------------------------------ */ 905 0 stevel /* Function: nat_siocaddnat */ 906 0 stevel /* Returns: int - 0 == success, != 0 == failure */ 907 0 stevel /* Parameters: n(I) - pointer to new NAT rule */ 908 0 stevel /* np(I) - pointer to where to insert new NAT rule */ 909 0 stevel /* getlock(I) - flag indicating if lock on ipf_nat is held */ 910 0 stevel /* Mutex Locks: ipf_natio */ 911 0 stevel /* */ 912 0 stevel /* Handle SIOCADNAT. Resolve and calculate details inside the NAT rule */ 913 0 stevel /* from information passed to the kernel, then add it to the appropriate */ 914 0 stevel /* NAT rule table(s). */ 915 0 stevel /* ------------------------------------------------------------------------ */ 916 3448 dh155122 static int nat_siocaddnat(n, np, getlock, ifs) 917 0 stevel ipnat_t *n, **np; 918 0 stevel int getlock; 919 3448 dh155122 ipf_stack_t *ifs; 920 0 stevel { 921 0 stevel int error = 0, i, j; 922 0 stevel 923 4380 jojemann if (nat_resolverule(n, ifs) != 0) 924 4380 jojemann return ENOENT; 925 2393 yz155240 926 2393 yz155240 if ((n->in_age[0] == 0) && (n->in_age[1] != 0)) 927 2393 yz155240 return EINVAL; 928 0 stevel 929 0 stevel n->in_use = 0; 930 0 stevel if (n->in_redir & NAT_MAPBLK) 931 0 stevel n->in_space = USABLE_PORTS * ~ntohl(n->in_outmsk); 932 0 stevel else if (n->in_flags & IPN_AUTOPORTMAP) 933 0 stevel n->in_space = USABLE_PORTS * ~ntohl(n->in_inmsk); 934 0 stevel else if (n->in_flags & IPN_IPRANGE) 935 0 stevel n->in_space = ntohl(n->in_outmsk) - ntohl(n->in_outip); 936 0 stevel else if (n->in_flags & IPN_SPLIT) 937 0 stevel n->in_space = 2; 938 2393 yz155240 else if (n->in_outmsk != 0) 939 0 stevel n->in_space = ~ntohl(n->in_outmsk); 940 2393 yz155240 else 941 2393 yz155240 n->in_space = 1; 942 8624 Darren if (n->in_flags & NAT_TCPUDPICMPQ) { 943 8624 Darren if (ntohs(n->in_pmax) < ntohs(n->in_pmin)) 944 8624 Darren return EINVAL; 945 8624 Darren } 946 2393 yz155240 947 0 stevel /* 948 0 stevel * Calculate the number of valid IP addresses in the output 949 0 stevel * mapping range. In all cases, the range is inclusive of 950 0 stevel * the start and ending IP addresses. 951 0 stevel * If to a CIDR address, lose 2: broadcast + network address 952 0 stevel * (so subtract 1) 953 0 stevel * If to a range, add one. 954 0 stevel * If to a single IP address, set to 1. 955 0 stevel */ 956 0 stevel if (n->in_space) { 957 0 stevel if ((n->in_flags & IPN_IPRANGE) != 0) 958 0 stevel n->in_space += 1; 959 0 stevel else 960 0 stevel n->in_space -= 1; 961 0 stevel } else 962 0 stevel n->in_space = 1; 963 2393 yz155240 964 7176 yx160601 #ifdef USE_INET6 965 7176 yx160601 if (n->in_v == 6 && (n->in_flags & (IPN_IPRANGE|IPN_SPLIT)) == 0 && 966 7176 yx160601 !IP6_ISONES(&n->in_out[1]) && !IP6_ISZERO(&n->in_out[1])) 967 7176 yx160601 IP6_ADD(&n->in_out[0], 1, &n->in_next6) 968 7176 yx160601 else if (n->in_v == 6 && 969 7176 yx160601 (n->in_flags & IPN_SPLIT) && (n->in_redir & NAT_REDIRECT)) 970 7176 yx160601 n->in_next6 = n->in_in[0]; 971 7176 yx160601 else if (n->in_v == 6) 972 7176 yx160601 n->in_next6 = n->in_out[0]; 973 7176 yx160601 else 974 7176 yx160601 #endif 975 0 stevel if ((n->in_outmsk != 0xffffffff) && (n->in_outmsk != 0) && 976 0 stevel ((n->in_flags & (IPN_IPRANGE|IPN_SPLIT)) == 0)) 977 0 stevel n->in_nip = ntohl(n->in_outip) + 1; 978 0 stevel else if ((n->in_flags & IPN_SPLIT) && 979 0 stevel (n->in_redir & NAT_REDIRECT)) 980 0 stevel n->in_nip = ntohl(n->in_inip); 981 0 stevel else 982 0 stevel n->in_nip = ntohl(n->in_outip); 983 7176 yx160601 984 0 stevel if (n->in_redir & NAT_MAP) { 985 0 stevel n->in_pnext = ntohs(n->in_pmin); 986 0 stevel /* 987 0 stevel * Multiply by the number of ports made available. 988 0 stevel */ 989 0 stevel if (ntohs(n->in_pmax) >= ntohs(n->in_pmin)) { 990 0 stevel n->in_space *= (ntohs(n->in_pmax) - 991 0 stevel ntohs(n->in_pmin) + 1); 992 0 stevel /* 993 0 stevel * Because two different sources can map to 994 0 stevel * different destinations but use the same 995 0 stevel * local IP#/port #. 996 0 stevel * If the result is smaller than in_space, then 997 0 stevel * we may have wrapped around 32bits. 998 0 stevel */ 999 0 stevel i = n->in_inmsk; 1000 0 stevel if ((i != 0) && (i != 0xffffffff)) { 1001 0 stevel j = n->in_space * (~ntohl(i) + 1); 1002 0 stevel if (j >= n->in_space) 1003 0 stevel n->in_space = j; 1004 0 stevel else 1005 0 stevel n->in_space = 0xffffffff; 1006 0 stevel } 1007 0 stevel } 1008 0 stevel /* 1009 0 stevel * If no protocol is specified, multiple by 256 to allow for 1010 0 stevel * at least one IP:IP mapping per protocol. 1011 0 stevel */ 1012 0 stevel if ((n->in_flags & IPN_TCPUDPICMP) == 0) { 1013 0 stevel j = n->in_space * 256; 1014 0 stevel if (j >= n->in_space) 1015 0 stevel n->in_space = j; 1016 0 stevel else 1017 0 stevel n->in_space = 0xffffffff; 1018 0 stevel } 1019 0 stevel } 1020 2393 yz155240 1021 0 stevel /* Otherwise, these fields are preset */ 1022 0 stevel 1023 0 stevel if (getlock) { 1024 3448 dh155122 WRITE_ENTER(&ifs->ifs_ipf_nat); 1025 0 stevel } 1026 0 stevel n->in_next = NULL; 1027 0 stevel *np = n; 1028 0 stevel 1029 0 stevel if (n->in_age[0] != 0) 1030 3448 dh155122 n->in_tqehead[0] = fr_addtimeoutqueue(&ifs->ifs_nat_utqe, 1031 3448 dh155122 n->in_age[0], ifs); 1032 0 stevel 1033 0 stevel if (n->in_age[1] != 0) 1034 3448 dh155122 n->in_tqehead[1] = fr_addtimeoutqueue(&ifs->ifs_nat_utqe, 1035 3448 dh155122 n->in_age[1], ifs); 1036 0 stevel 1037 0 stevel if (n->in_redir & NAT_REDIRECT) { 1038 0 stevel n->in_flags &= ~IPN_NOTDST; 1039 7176 yx160601 switch (n->in_v) 1040 7176 yx160601 { 1041 7176 yx160601 case 4 : 1042 7176 yx160601 nat_addrdr(n, ifs); 1043 7176 yx160601 break; 1044 7176 yx160601 #ifdef USE_INET6 1045 7176 yx160601 case 6 : 1046 7176 yx160601 nat6_addrdr(n, ifs); 1047 7176 yx160601 break; 1048 7176 yx160601 #endif 1049 7176 yx160601 default : 1050 7176 yx160601 break; 1051 7176 yx160601 } 1052 0 stevel } 1053 0 stevel if (n->in_redir & (NAT_MAP|NAT_MAPBLK)) { 1054 0 stevel n->in_flags &= ~IPN_NOTSRC; 1055 7176 yx160601 switch (n->in_v) 1056 7176 yx160601 { 1057 7176 yx160601 case 4 : 1058 7176 yx160601 nat_addnat(n, ifs); 1059 7176 yx160601 break; 1060 7176 yx160601 #ifdef USE_INET6 1061 7176 yx160601 case 6 : 1062 7176 yx160601 nat6_addnat(n, ifs); 1063 7176 yx160601 break; 1064 7176 yx160601 #endif 1065 7176 yx160601 default : 1066 7176 yx160601 break; 1067 7176 yx160601 } 1068 0 stevel } 1069 0 stevel n = NULL; 1070 3448 dh155122 ifs->ifs_nat_stats.ns_rules++; 1071 3448 dh155122 if (getlock) { 1072 3448 dh155122 RWLOCK_EXIT(&ifs->ifs_ipf_nat); /* WRITE */ 1073 0 stevel } 1074 0 stevel 1075 0 stevel return error; 1076 0 stevel } 1077 0 stevel 1078 0 stevel 1079 0 stevel /* ------------------------------------------------------------------------ */ 1080 0 stevel /* Function: nat_resolvrule */ 1081 4380 jojemann /* Returns: int - 0 == success, -1 == failure */ 1082 0 stevel /* Parameters: n(I) - pointer to NAT rule */ 1083 0 stevel /* */ 1084 4380 jojemann /* Resolve some of the details inside the NAT rule. Includes resolving */ 1085 4380 jojemann /* any specified interfaces and proxy labels, and determines whether or not */ 1086 4380 jojemann /* all proxy labels are correctly specified. */ 1087 4380 jojemann /* */ 1088 4380 jojemann /* Called by nat_siocaddnat() (SIOCADNAT) and fr_natputent (SIOCSTPUT). */ 1089 4380 jojemann /* ------------------------------------------------------------------------ */ 1090 4380 jojemann static int nat_resolverule(n, ifs) 1091 2393 yz155240 ipnat_t *n; 1092 3448 dh155122 ipf_stack_t *ifs; 1093 2393 yz155240 { 1094 2393 yz155240 n->in_ifnames[0][LIFNAMSIZ - 1] = '\0'; 1095 7176 yx160601 n->in_ifps[0] = fr_resolvenic(n->in_ifnames[0], n->in_v, ifs); 1096 2393 yz155240 1097 2393 yz155240 n->in_ifnames[1][LIFNAMSIZ - 1] = '\0'; 1098 0 stevel if (n->in_ifnames[1][0] == '\0') { 1099 0 stevel (void) strncpy(n->in_ifnames[1], n->in_ifnames[0], LIFNAMSIZ); 1100 0 stevel n->in_ifps[1] = n->in_ifps[0]; 1101 0 stevel } else { 1102 7176 yx160601 n->in_ifps[1] = fr_resolvenic(n->in_ifnames[1], n->in_v, ifs); 1103 0 stevel } 1104 0 stevel 1105 0 stevel if (n->in_plabel[0] != '\0') { 1106 3448 dh155122 n->in_apr = appr_lookup(n->in_p, n->in_plabel, ifs); 1107 4380 jojemann if (n->in_apr == NULL) 1108 4380 jojemann return -1; 1109 4380 jojemann } 1110 4380 jojemann return 0; 1111 0 stevel } 1112 0 stevel 1113 0 stevel 1114 0 stevel /* ------------------------------------------------------------------------ */ 1115 0 stevel /* Function: nat_siocdelnat */ 1116 0 stevel /* Returns: int - 0 == success, != 0 == failure */ 1117 0 stevel /* Parameters: n(I) - pointer to new NAT rule */ 1118 0 stevel /* np(I) - pointer to where to insert new NAT rule */ 1119 0 stevel /* getlock(I) - flag indicating if lock on ipf_nat is held */ 1120 0 stevel /* Mutex Locks: ipf_natio */ 1121 0 stevel /* */ 1122 0 stevel /* Handle SIOCADNAT. Resolve and calculate details inside the NAT rule */ 1123 0 stevel /* from information passed to the kernel, then add it to the appropriate */ 1124 0 stevel /* NAT rule table(s). */ 1125 0 stevel /* ------------------------------------------------------------------------ */ 1126 3448 dh155122 static void nat_siocdelnat(n, np, getlock, ifs) 1127 0 stevel ipnat_t *n, **np; 1128 0 stevel int getlock; 1129 3448 dh155122 ipf_stack_t *ifs; 1130 3448 dh155122 { 1131 7176 yx160601 int i; 1132 7176 yx160601 1133 3448 dh155122 if (getlock) { 1134 3448 dh155122 WRITE_ENTER(&ifs->ifs_ipf_nat); 1135 0 stevel } 1136 0 stevel if (n->in_redir & NAT_REDIRECT) 1137 0 stevel nat_delrdr(n); 1138 0 stevel if (n->in_redir & (NAT_MAPBLK|NAT_MAP)) 1139 0 stevel nat_delnat(n); 1140 3448 dh155122 if (ifs->ifs_nat_list == NULL) { 1141 3448 dh155122 ifs->ifs_nat_masks = 0; 1142 3448 dh155122 ifs->ifs_rdr_masks = 0; 1143 7176 yx160601 for (i = 0; i < 4; i++) { 1144 7176 yx160601 ifs->ifs_nat6_masks[i] = 0; 1145 7176 yx160601 ifs->ifs_rdr6_masks[i] = 0; 1146 7176 yx160601 } 1147 0 stevel } 1148 0 stevel 1149 2393 yz155240 if (n->in_tqehead[0] != NULL) { 1150 2393 yz155240 if (fr_deletetimeoutqueue(n->in_tqehead[0]) == 0) { 1151 4817 an207044 fr_freetimeoutqueue(n->in_tqehead[0], ifs); 1152 2393 yz155240 } 1153 2393 yz155240 } 1154 2393 yz155240 1155 2393 yz155240 if (n->in_tqehead[1] != NULL) { 1156 2393 yz155240 if (fr_deletetimeoutqueue(n->in_tqehead[1]) == 0) { 1157 3448 dh155122 fr_freetimeoutqueue(n->in_tqehead[1], ifs); 1158 2393 yz155240 } 1159 2393 yz155240 } 1160 0 stevel 1161 0 stevel *np = n->in_next; 1162 0 stevel 1163 0 stevel if (n->in_use == 0) { 1164 0 stevel if (n->in_apr) 1165 0 stevel appr_free(n->in_apr); 1166 0 stevel KFREE(n); 1167 3448 dh155122 ifs->ifs_nat_stats.ns_rules--; 1168 0 stevel } else { 1169 0 stevel n->in_flags |= IPN_DELETE; 1170 0 stevel n->in_next = NULL; 1171 0 stevel } 1172 0 stevel if (getlock) { 1173 3448 dh155122 RWLOCK_EXIT(&ifs->ifs_ipf_nat); /* READ/WRITE */ 1174 0 stevel } 1175 0 stevel } 1176 0 stevel 1177 0 stevel 1178 0 stevel /* ------------------------------------------------------------------------ */ 1179 0 stevel /* Function: fr_natgetsz */ 1180 0 stevel /* Returns: int - 0 == success, != 0 is the error value. */ 1181 0 stevel /* Parameters: data(I) - pointer to natget structure with kernel pointer */ 1182 0 stevel /* get the size of. */ 1183 0 stevel /* */ 1184 0 stevel /* Handle SIOCSTGSZ. */ 1185 0 stevel /* Return the size of the nat list entry to be copied back to user space. */ 1186 0 stevel /* The size of the entry is stored in the ng_sz field and the enture natget */ 1187 0 stevel /* structure is copied back to the user. */ 1188 0 stevel /* ------------------------------------------------------------------------ */ 1189 3448 dh155122 static int fr_natgetsz(data, ifs) 1190 0 stevel caddr_t data; 1191 3448 dh155122 ipf_stack_t *ifs; 1192 0 stevel { 1193 0 stevel ap_session_t *aps; 1194 0 stevel nat_t *nat, *n; 1195 0 stevel natget_t ng; 1196 7433 John int err; 1197 7433 John 1198 7433 John err = BCOPYIN(data, &ng, sizeof(ng)); 1199 7433 John if (err != 0) 1200 7433 John return EFAULT; 1201 0 stevel 1202 0 stevel nat = ng.ng_ptr; 1203 0 stevel if (!nat) { 1204 3448 dh155122 nat = ifs->ifs_nat_instances; 1205 0 stevel ng.ng_sz = 0; 1206 0 stevel /* 1207 0 stevel * Empty list so the size returned is 0. Simple. 1208 0 stevel */ 1209 0 stevel if (nat == NULL) { 1210 7433 John err = BCOPYOUT(&ng, data, sizeof(ng)); 1211 7433 John if (err != 0) { 1212 7433 John return EFAULT; 1213 7433 John } else { 1214 7433 John return 0; 1215 7433 John } 1216 0 stevel } 1217 0 stevel } else { 1218 0 stevel /* 1219 0 stevel * Make sure the pointer we're copying from exists in the 1220 0 stevel * current list of entries. Security precaution to prevent 1221 0 stevel * copying of random kernel data. 1222 0 stevel */ 1223 3448 dh155122 for (n = ifs->ifs_nat_instances; n; n = n->nat_next) 1224 0 stevel if (n == nat) 1225 0 stevel break; 1226 0 stevel if (!n) 1227 0 stevel return ESRCH; 1228 0 stevel } 1229 0 stevel 1230 0 stevel /* 1231 0 stevel * Incluse any space required for proxy data structures. 1232 0 stevel */ 1233 0 stevel ng.ng_sz = sizeof(nat_save_t); 1234 0 stevel aps = nat->nat_aps; 1235 2393 yz155240 if (aps != NULL) { 1236 2393 yz155240 ng.ng_sz += sizeof(ap_session_t) - 4; 1237 2393 yz155240 if (aps->aps_data != 0) 1238 2393 yz155240 ng.ng_sz += aps->aps_psiz; 1239 2393 yz155240 } 1240 2393 yz155240 1241 7433 John err = BCOPYOUT(&ng, data, sizeof(ng)); 1242 7433 John if (err != 0) 1243 7433 John return EFAULT; 1244 0 stevel return 0; 1245 0 stevel } 1246 0 stevel 1247 0 stevel 1248 0 stevel /* ------------------------------------------------------------------------ */ 1249 0 stevel /* Function: fr_natgetent */ 1250 0 stevel /* Returns: int - 0 == success, != 0 is the error value. */ 1251 0 stevel /* Parameters: data(I) - pointer to natget structure with kernel pointer */ 1252 0 stevel /* to NAT structure to copy out. */ 1253 0 stevel /* */ 1254 0 stevel /* Handle SIOCSTGET. */ 1255 0 stevel /* Copies out NAT entry to user space. Any additional data held for a */ 1256 0 stevel /* proxy is also copied, as to is the NAT rule which was responsible for it */ 1257 0 stevel /* ------------------------------------------------------------------------ */ 1258 3448 dh155122 static int fr_natgetent(data, ifs) 1259 0 stevel caddr_t data; 1260 3448 dh155122 ipf_stack_t *ifs; 1261 0 stevel { 1262 2393 yz155240 int error, outsize; 1263 0 stevel ap_session_t *aps; 1264 2393 yz155240 nat_save_t *ipn, ipns; 1265 0 stevel nat_t *n, *nat; 1266 2393 yz155240 1267 2393 yz155240 error = fr_inobj(data, &ipns, IPFOBJ_NATSAVE); 1268 0 stevel if (error != 0) 1269 0 stevel return error; 1270 0 stevel 1271 2393 yz155240 if ((ipns.ipn_dsize < sizeof(ipns)) || (ipns.ipn_dsize > 81920)) 1272 2393 yz155240 return EINVAL; 1273 2393 yz155240 1274 2393 yz155240 KMALLOCS(ipn, nat_save_t *, ipns.ipn_dsize); 1275 2393 yz155240 if (ipn == NULL) 1276 2393 yz155240 return ENOMEM; 1277 2393 yz155240 1278 2393 yz155240 ipn->ipn_dsize = ipns.ipn_dsize; 1279 2393 yz155240 nat = ipns.ipn_next; 1280 0 stevel if (nat == NULL) { 1281 3448 dh155122 nat = ifs->ifs_nat_instances; 1282 0 stevel if (nat == NULL) { 1283 3448 dh155122 if (ifs->ifs_nat_instances == NULL) 1284 2393 yz155240 error = ENOENT; 1285 2393 yz155240 goto finished; 1286 0 stevel } 1287 0 stevel } else { 1288 0 stevel /* 1289 0 stevel * Make sure the pointer we're copying from exists in the 1290 0 stevel * current list of entries. Security precaution to prevent 1291 0 stevel * copying of random kernel data. 1292 0 stevel */ 1293 3448 dh155122 for (n = ifs->ifs_nat_instances; n; n = n->nat_next) 1294 0 stevel if (n == nat) 1295 0 stevel break; 1296 2393 yz155240 if (n == NULL) { 1297 2393 yz155240 error = ESRCH; 1298 2393 yz155240 goto finished; 1299 2393 yz155240 } 1300 2393 yz155240 } 1301 2393 yz155240 ipn->ipn_next = nat->nat_next; 1302 2393 yz155240 1303 2393 yz155240 /* 1304 2393 yz155240 * Copy the NAT structure. 1305 2393 yz155240 */ 1306 2393 yz155240 bcopy((char *)nat, &ipn->ipn_nat, sizeof(*nat)); 1307 0 stevel 1308 0 stevel /* 1309 0 stevel * If we have a pointer to the NAT rule it belongs to, save that too. 1310 0 stevel */ 1311 2393 yz155240 if (nat->nat_ptr != NULL) 1312 2393 yz155240 bcopy((char *)nat->nat_ptr, (char *)&ipn->ipn_ipnat, 1313 2393 yz155240 sizeof(ipn->ipn_ipnat)); 1314 0 stevel 1315 0 stevel /* 1316 0 stevel * If we also know the NAT entry has an associated filter rule, 1317 0 stevel * save that too. 1318 0 stevel */ 1319 2393 yz155240 if (nat->nat_fr != NULL) 1320 2393 yz155240 bcopy((char *)nat->nat_fr, (char *)&ipn->ipn_fr, 1321 2393 yz155240 sizeof(ipn->ipn_fr)); 1322 0 stevel 1323 0 stevel /* 1324 0 stevel * Last but not least, if there is an application proxy session set 1325 0 stevel * up for this NAT entry, then copy that out too, including any 1326 0 stevel * private data saved along side it by the proxy. 1327 0 stevel */ 1328 0 stevel aps = nat->nat_aps; 1329 2393 yz155240 outsize = ipn->ipn_dsize - sizeof(*ipn) + sizeof(ipn->ipn_data); 1330 0 stevel if (aps != NULL) { 1331 2393 yz155240 char *s; 1332 2393 yz155240 1333 2393 yz155240 if (outsize < sizeof(*aps)) { 1334 2393 yz155240 error = ENOBUFS; 1335 2393 yz155240 goto finished; 1336 2393 yz155240 } 1337 2393 yz155240 1338 2393 yz155240 s = ipn->ipn_data; 1339 2393 yz155240 bcopy((char *)aps, s, sizeof(*aps)); 1340 2393 yz155240 s += sizeof(*aps); 1341 2393 yz155240 outsize -= sizeof(*aps); 1342 2393 yz155240 if ((aps->aps_data != NULL) && (outsize >= aps->aps_psiz)) 1343 2393 yz155240 bcopy(aps->aps_data, s, aps->aps_psiz); 1344 2393 yz155240 else 1345 2393 yz155240 error = ENOBUFS; 1346 2393 yz155240 } 1347 2393 yz155240 if (error == 0) { 1348 2393 yz155240 error = fr_outobjsz(data, ipn, IPFOBJ_NATSAVE, ipns.ipn_dsize); 1349 2393 yz155240 } 1350 2393 yz155240 1351 2393 yz155240 finished: 1352 2393 yz155240 if (ipn != NULL) { 1353 2393 yz155240 KFREES(ipn, ipns.ipn_dsize); 1354 0 stevel } 1355 0 stevel return error; 1356 0 stevel } 1357 0 stevel 1358 6253 an207044 /* ------------------------------------------------------------------------ */ 1359 6253 an207044 /* Function: nat_calc_chksum_diffs */ 1360 6253 an207044 /* Returns: void */ 1361 6253 an207044 /* Parameters: nat - pointer to NAT table entry */ 1362 6253 an207044 /* */ 1363 6253 an207044 /* Function calculates chksum deltas for IP header (nat_ipsumd) and TCP/UDP */ 1364 6253 an207044 /* headers (nat_sumd). The things for L4 (UDP/TCP) get complicated when */ 1365 6253 an207044 /* we are dealing with partial chksum offload. For these cases we need to */ 1366 6253 an207044 /* compute a 'partial chksum delta'. The 'partial chksum delta'is stored */ 1367 6253 an207044 /* into nat_sumd[1], while ordinary chksum delta for TCP/UDP is in */ 1368 6253 an207044 /* nat_sumd[0]. */ 1369 6253 an207044 /* */ 1370 6253 an207044 /* The function accepts initialized NAT table entry and computes the deltas */ 1371 6253 an207044 /* from nat_inip/nat_outip members. The function is called right before */ 1372 6253 an207044 /* the new entry is inserted into the table. */ 1373 6253 an207044 /* */ 1374 6253 an207044 /* The ipsumd (IP hedaer chksum delta adjustment) is computed as a chksum */ 1375 6253 an207044 /* of delta between original and new IP addresses. */ 1376 6253 an207044 /* */ 1377 6253 an207044 /* the nat_sumd[0] (TCP/UDP header chksum delta adjustment) is computed as */ 1378 6253 an207044 /* a chkusm of delta between original an new IP addrress:port tupples. */ 1379 6253 an207044 /* */ 1380 6253 an207044 /* Some facts about chksum, we should remember: */ 1381 6253 an207044 /* IP header chksum covers IP header only */ 1382 6253 an207044 /* */ 1383 6253 an207044 /* TCP/UDP chksum covers data payload and so called pseudo header */ 1384 6253 an207044 /* SRC, DST IP address */ 1385 6253 an207044 /* SRC, DST Port */ 1386 6253 an207044 /* length of payload */ 1387 6253 an207044 /* */ 1388 6253 an207044 /* The partial chksum delta (nat_sumd[1] is used to adjust db_ckusm16 */ 1389 6253 an207044 /* member of dblk_t structure. The db_ckusm16 member is not part of */ 1390 6253 an207044 /* IP/UDP/TCP header it is 16 bit value computed by NIC driver with partial */ 1391 6253 an207044 /* chksum offload capacbility for every inbound packet. The db_cksum16 is */ 1392 6253 an207044 /* stored along with other IP packet data in dblk_t structure and used in */ 1393 6253 an207044 /* for IP/UDP/TCP chksum validation later in ip.c. */ 1394 6253 an207044 /* */ 1395 6253 an207044 /* The partial chksum delta (adjustment, nat_sumd[1]) is computed as chksum */ 1396 6253 an207044 /* of delta between new and orig address. NOTE: the order of operands for */ 1397 6253 an207044 /* partial delta operation is swapped compared to computing the IP/TCP/UDP */ 1398 6253 an207044 /* header adjustment. It is by design see (IP_CKSUM_RECV() macro in ip.c). */ 1399 6253 an207044 /* */ 1400 6253 an207044 /* ------------------------------------------------------------------------ */ 1401 7176 yx160601 void nat_calc_chksum_diffs(nat) 1402 6253 an207044 nat_t *nat; 1403 6253 an207044 { 1404 6253 an207044 u_32_t sum_orig = 0; 1405 6253 an207044 u_32_t sum_changed = 0; 1406 6253 an207044 u_32_t sumd; 1407 6253 an207044 u_32_t ipsum_orig = 0; 1408 6253 an207044 u_32_t ipsum_changed = 0; 1409 6253 an207044 1410 7176 yx160601 if (nat->nat_v != 4 && nat->nat_v != 6) 1411 7176 yx160601 return; 1412 7176 yx160601 1413 6253 an207044 /* 1414 6253 an207044 * the switch calculates operands for CALC_SUMD(), 1415 6253 an207044 * which will compute the partial chksum delta. 1416 6253 an207044 */ 1417 6253 an207044 switch (nat->nat_dir) 1418 6253 an207044 { 1419 6253 an207044 case NAT_INBOUND: 1420 6253 an207044 /* 1421 6253 an207044 * we are dealing with RDR rule (DST address gets 1422 6253 an207044 * modified on packet from client) 1423 6253 an207044 */ 1424 7176 yx160601 if (nat->nat_v == 4) { 1425 7176 yx160601 sum_changed = LONG_SUM(ntohl(nat->nat_inip.s_addr)); 1426 7176 yx160601 sum_orig = LONG_SUM(ntohl(nat->nat_outip.s_addr)); 1427 7176 yx160601 } else { 1428 7176 yx160601 sum_changed = LONG_SUM6(&nat->nat_inip6); 1429 7176 yx160601 sum_orig = LONG_SUM6(&nat->nat_outip6); 1430 7176 yx160601 } 1431 6253 an207044 break; 1432 6253 an207044 case NAT_OUTBOUND: 1433 6253 an207044 /* 1434 6253 an207044 * we are dealing with MAP rule (SRC address gets 1435 6253 an207044 * modified on packet from client) 1436 6253 an207044 */ 1437 7176 yx160601 if (nat->nat_v == 4) { 1438 7176 yx160601 sum_changed = LONG_SUM(ntohl(nat->nat_outip.s_addr)); 1439 7176 yx160601 sum_orig = LONG_SUM(ntohl(nat->nat_inip.s_addr)); 1440 7176 yx160601 } else { 1441 7176 yx160601 sum_changed = LONG_SUM6(&nat->nat_outip6); 1442 7176 yx160601 sum_orig = LONG_SUM6(&nat->nat_inip6); 1443 7176 yx160601 } 1444 6253 an207044 break; 1445 6253 an207044 default: ; 1446 6253 an207044 break; 1447 6253 an207044 } 1448 6253 an207044 1449 6253 an207044 /* 1450 6253 an207044 * we also preserve CALC_SUMD() operands here, for IP chksum delta 1451 6253 an207044 * calculation, which happens at the end of function. 1452 6253 an207044 */ 1453 6253 an207044 ipsum_changed = sum_changed; 1454 6253 an207044 ipsum_orig = sum_orig; 1455 6253 an207044 /* 1456 6253 an207044 * NOTE: the order of operands for partial chksum adjustment 1457 6253 an207044 * computation has to be swapped! 1458 6253 an207044 */ 1459 6253 an207044 CALC_SUMD(sum_changed, sum_orig, sumd); 1460 6253 an207044 nat->nat_sumd[1] = (sumd & 0xffff) + (sumd >> 16); 1461 6253 an207044 1462 6295 an207044 if (nat->nat_flags & (IPN_TCPUDP | IPN_ICMPQUERY)) { 1463 6253 an207044 1464 6253 an207044 /* 1465 6253 an207044 * switch calculates operands for CALC_SUMD(), which will 1466 6253 an207044 * compute the full chksum delta. 1467 6253 an207044 */ 1468 6253 an207044 switch (nat->nat_dir) 1469 6253 an207044 { 1470 6253 an207044 case NAT_INBOUND: 1471 7176 yx160601 if (nat->nat_v == 4) { 1472 7176 yx160601 sum_changed = LONG_SUM( 1473 7176 yx160601 ntohl(nat->nat_inip.s_addr) + 1474 7176 yx160601 ntohs(nat->nat_inport)); 1475 7176 yx160601 sum_orig = LONG_SUM( 1476 7176 yx160601 ntohl(nat->nat_outip.s_addr) + 1477 7176 yx160601 ntohs(nat->nat_outport)); 1478 7176 yx160601 } else { 1479 7176 yx160601 sum_changed = LONG_SUM6(&nat->nat_inip6) + 1480 7176 yx160601 ntohs(nat->nat_inport); 1481 7176 yx160601 sum_orig = LONG_SUM6(&nat->nat_outip6) + 1482 7176 yx160601 ntohs(nat->nat_outport); 1483 7176 yx160601 } 1484 6253 an207044 break; 1485 6253 an207044 case NAT_OUTBOUND: 1486 7176 yx160601 if (nat->nat_v == 4) { 1487 7176 yx160601 sum_changed = LONG_SUM( 1488 7176 yx160601 ntohl(nat->nat_outip.s_addr) + 1489 7176 yx160601 ntohs(nat->nat_outport)); 1490 7176 yx160601 sum_orig = LONG_SUM( 1491 7176 yx160601 ntohl(nat->nat_inip.s_addr) + 1492 7176 yx160601 ntohs(nat->nat_inport)); 1493 7176 yx160601 } else { 1494 7176 yx160601 sum_changed = LONG_SUM6(&nat->nat_outip6) + 1495 7176 yx160601 ntohs(nat->nat_outport); 1496 7176 yx160601 sum_orig = LONG_SUM6(&nat->nat_inip6) + 1497 7176 yx160601 ntohs(nat->nat_inport); 1498 7176 yx160601 } 1499 6253 an207044 break; 1500 6253 an207044 default: ; 1501 6253 an207044 break; 1502 6253 an207044 } 1503 6253 an207044 1504 6253 an207044 CALC_SUMD(sum_orig, sum_changed, sumd); 1505 6253 an207044 nat->nat_sumd[0] = (sumd & 0xffff) + (sumd >> 16); 1506 6295 an207044 1507 6295 an207044 if (!(nat->nat_flags & IPN_TCPUDP)) { 1508 6295 an207044 /* 1509 6295 an207044 * partial HW chksum offload works for TCP/UDP headers only, 1510 6295 an207044 * so we need to enforce full chksum adjustment for ICMP 1511 6295 an207044 */ 1512 6295 an207044 nat->nat_sumd[1] = nat->nat_sumd[0]; 1513 6295 an207044 } 1514 6253 an207044 } 1515 6253 an207044 else 1516 6253 an207044 nat->nat_sumd[0] = nat->nat_sumd[1]; 1517 6253 an207044 1518 6253 an207044 /* 1519 6253 an207044 * we may reuse the already computed nat_sumd[0] for IP header chksum 1520 6253 an207044 * adjustment in case the L4 (TCP/UDP header) is not changed by NAT. 1521 6253 an207044 */ 1522 7176 yx160601 if (nat->nat_v == 4) { 1523 7176 yx160601 if (NAT_HAS_L4_CHANGED(nat)) { 1524 7176 yx160601 /* 1525 7176 yx160601 * bad luck, NAT changes also the L4 header, use IP 1526 7176 yx160601 * addresses to compute chksum adjustment for IP header. 1527 7176 yx160601 */ 1528 7176 yx160601 CALC_SUMD(ipsum_orig, ipsum_changed, sumd); 1529 7176 yx160601 nat->nat_ipsumd = (sumd & 0xffff) + (sumd >> 16); 1530 7176 yx160601 } else { 1531 7176 yx160601 /* 1532 7176 yx160601 * the NAT does not change L4 hdr -> reuse chksum 1533 7176 yx160601 * adjustment for IP hdr. 1534 7176 yx160601 */ 1535 7176 yx160601 nat->nat_ipsumd = nat->nat_sumd[0]; 1536 7176 yx160601 1537 7176 yx160601 /* 1538 7176 yx160601 * if L4 header does not use chksum - zero out deltas 1539 7176 yx160601 */ 1540 7176 yx160601 if (!(nat->nat_flags & IPN_TCPUDP)) { 1541 7176 yx160601 nat->nat_sumd[0] = 0; 1542 7176 yx160601 nat->nat_sumd[1] = 0; 1543 7176 yx160601 } 1544 6295 an207044 } 1545 6253 an207044 } 1546 6253 an207044 1547 6253 an207044 return; 1548 6253 an207044 } 1549 0 stevel 1550 0 stevel /* ------------------------------------------------------------------------ */ 1551 0 stevel /* Function: fr_natputent */ 1552 0 stevel /* Returns: int - 0 == success, != 0 is the error value. */ 1553 8170 John /* Parameters: data(I) - pointer to natget structure with NAT */ 1554 8170 John /* structure information to load into the kernel */ 1555 2393 yz155240 /* getlock(I) - flag indicating whether or not a write lock */ 1556 2393 yz155240 /* on ipf_nat is already held. */ 1557 8170 John /* ifs - ipf stack instance */ 1558 0 stevel /* */ 1559 0 stevel /* Handle SIOCSTPUT. */ 1560 0 stevel /* Loads a NAT table entry from user space, including a NAT rule, proxy and */ 1561 0 stevel /* firewall rule data structures, if pointers to them indicate so. */ 1562 0 stevel /* ------------------------------------------------------------------------ */ 1563 3448 dh155122 static int fr_natputent(data, getlock, ifs) 1564 0 stevel caddr_t data; 1565 1143 jojemann int getlock; 1566 3448 dh155122 ipf_stack_t *ifs; 1567 0 stevel { 1568 0 stevel nat_save_t ipn, *ipnn; 1569 0 stevel ap_session_t *aps; 1570 0 stevel nat_t *n, *nat; 1571 0 stevel frentry_t *fr; 1572 429 dr146992 fr_info_t fin; 1573 0 stevel ipnat_t *in; 1574 0 stevel int error; 1575 0 stevel 1576 0 stevel error = fr_inobj(data, &ipn, IPFOBJ_NATSAVE); 1577 0 stevel if (error != 0) 1578 0 stevel return error; 1579 4817 an207044 1580 4817 an207044 /* 1581 8170 John * Trigger automatic call to nat_flushtable() if the 1582 4817 an207044 * table has reached capcity specified by hi watermark. 1583 4817 an207044 */ 1584 8170 John if (NAT_TAB_WATER_LEVEL(ifs) > ifs->ifs_nat_flush_level_hi) 1585 4817 an207044 ifs->ifs_nat_doflush = 1; 1586 0 stevel 1587 2393 yz155240 /* 1588 7432 John * If automatic flushing did not do its job, and the table 1589 7432 John * has filled up, don't try to create a new entry. 1590 7432 John */ 1591 7432 John if (ifs->ifs_nat_stats.ns_inuse >= ifs->ifs_ipf_nattable_max) { 1592 7432 John ifs->ifs_nat_stats.ns_memfail++; 1593 7432 John return ENOMEM; 1594 7432 John } 1595 7432 John 1596 7432 John /* 1597 2393 yz155240 * Initialise early because of code at junkput label. 1598 2393 yz155240 */ 1599 2393 yz155240 in = NULL; 1600 2393 yz155240 aps = NULL; 1601 0 stevel nat = NULL; 1602 2393 yz155240 ipnn = NULL; 1603 2393 yz155240 1604 2393 yz155240 /* 1605 2393 yz155240 * New entry, copy in the rest of the NAT entry if it's size is more 1606 2393 yz155240 * than just the nat_t structure. 1607 2393 yz155240 */ 1608 2393 yz155240 fr = NULL; 1609 2393 yz155240 if (ipn.ipn_dsize > sizeof(ipn)) { 1610 2393 yz155240 if (ipn.ipn_dsize > 81920) { 1611 2393 yz155240 error = ENOMEM; 1612 2393 yz155240 goto junkput; 1613 2393 yz155240 } 1614 2393 yz155240 1615 2393 yz155240 KMALLOCS(ipnn, nat_save_t *, ipn.ipn_dsize); 1616 0 stevel if (ipnn == NULL) 1617 0 stevel return ENOMEM; 1618 0 stevel 1619 2393 yz155240 error = fr_inobjsz(data, ipnn, IPFOBJ_NATSAVE, ipn.ipn_dsize); 1620 0 stevel if (error != 0) { 1621 0 stevel error = EFAULT; 1622 0 stevel goto junkput; 1623 0 stevel } 1624 0 stevel } else 1625 2393 yz155240 ipnn = &ipn; 1626 0 stevel 1627 0 stevel KMALLOC(nat, nat_t *); 1628 0 stevel if (nat == NULL) { 1629 0 stevel error = ENOMEM; 1630 0 stevel goto junkput; 1631 0 stevel } 1632 0 stevel 1633 2393 yz155240 bcopy((char *)&ipnn->ipn_nat, (char *)nat, sizeof(*nat)); 1634 0 stevel /* 1635 0 stevel * Initialize all these so that nat_delete() doesn't cause a crash. 1636 0 stevel */ 1637 2393 yz155240 bzero((char *)nat, offsetof(struct nat, nat_tqe)); 1638 2393 yz155240 nat->nat_tqe.tqe_pnext = NULL; 1639 2393 yz155240 nat->nat_tqe.tqe_next = NULL; 1640 2393 yz155240 nat->nat_tqe.tqe_ifq = NULL; 1641 2393 yz155240 nat->nat_tqe.tqe_parent = nat; 1642 0 stevel 1643 0 stevel /* 1644 0 stevel * Restore the rule associated with this nat session 1645 0 stevel */ 1646 2393 yz155240 in = ipnn->ipn_nat.nat_ptr; 1647 0 stevel if (in != NULL) { 1648 0 stevel KMALLOC(in, ipnat_t *); 1649 2393 yz155240 nat->nat_ptr = in; 1650 0 stevel if (in == NULL) { 1651 0 stevel error = ENOMEM; 1652 0 stevel goto junkput; 1653 0 stevel } 1654 2393 yz155240 bzero((char *)in, offsetof(struct ipnat, in_next6)); 1655 2393 yz155240 bcopy((char *)&ipnn->ipn_ipnat, (char *)in, sizeof(*in)); 1656 0 stevel in->in_use = 1; 1657 0 stevel in->in_flags |= IPN_DELETE; 1658 2393 yz155240 1659 3448 dh155122 ATOMIC_INC(ifs->ifs_nat_stats.ns_rules); 1660 3448 dh155122 1661 4380 jojemann if (nat_resolverule(in, ifs) != 0) { 1662 4380 jojemann error = ESRCH; 1663 4380 jojemann goto junkput; 1664 4380 jojemann } 1665 429 dr146992 } 1666 429 dr146992 1667 429 dr146992 /* 1668 429 dr146992 * Check that the NAT entry doesn't already exist in the kernel. 1669 429 dr146992 */ 1670 7176 yx160601 if (nat->nat_v != 6) 1671 7176 yx160601 nat->nat_v = 4; 1672 429 dr146992 bzero((char *)&fin, sizeof(fin)); 1673 429 dr146992 fin.fin_p = nat->nat_p; 1674 4414 jojemann fin.fin_ifs = ifs; 1675 429 dr146992 if (nat->nat_dir == NAT_OUTBOUND) { 1676 429 dr146992 fin.fin_data[0] = ntohs(nat->nat_oport); 1677 429 dr146992 fin.fin_data[1] = ntohs(nat->nat_outport); 1678 2508 yz155240 fin.fin_ifp = nat->nat_ifps[0]; 1679 1143 jojemann if (getlock) { 1680 3448 dh155122 READ_ENTER(&ifs->ifs_ipf_nat); 1681 1143 jojemann } 1682 7176 yx160601 1683 7176 yx160601 switch (nat->nat_v) 1684 7176 yx160601 { 1685 7176 yx160601 case 4: 1686 7176 yx160601 fin.fin_v = nat->nat_v; 1687 7176 yx160601 n = nat_inlookup(&fin, nat->nat_flags, fin.fin_p, 1688 7176 yx160601 nat->nat_oip, nat->nat_outip); 1689 7176 yx160601 break; 1690 7176 yx160601 #ifdef USE_INET6 1691 7176 yx160601 case 6: 1692 7176 yx160601 n = nat6_inlookup(&fin, nat->nat_flags, fin.fin_p, 1693 7176 yx160601 &nat->nat_oip6.in6, &nat->nat_outip6.in6); 1694 7176 yx160601 break; 1695 7176 yx160601 #endif 1696 7176 yx160601 default: 1697 7176 yx160601 n = NULL; 1698 7176 yx160601 break; 1699 7176 yx160601 } 1700 7176 yx160601 1701 1143 jojemann if (getlock) { 1702 3448 dh155122 RWLOCK_EXIT(&ifs->ifs_ipf_nat); 1703 1143 jojemann } 1704 1143 jojemann if (n != NULL) { 1705 429 dr146992 error = EEXIST; 1706 429 dr146992 goto junkput; 1707 429 dr146992 } 1708 429 dr146992 } else if (nat->nat_dir == NAT_INBOUND) { 1709 1364 jojemann fin.fin_data[0] = ntohs(nat->nat_inport); 1710 429 dr146992 fin.fin_data[1] = ntohs(nat->nat_oport); 1711 2508 yz155240 fin.fin_ifp = nat->nat_ifps[1]; 1712 1143 jojemann if (getlock) { 1713 3448 dh155122 READ_ENTER(&ifs->ifs_ipf_nat); 1714 1143 jojemann } 1715 7176 yx160601 1716 7176 yx160601 switch (nat->nat_v) 1717 7176 yx160601 { 1718 7176 yx160601 case 4: 1719 7176 yx160601 n = nat_outlookup(&fin, nat->nat_flags, fin.fin_p, 1720 7176 yx160601 nat->nat_inip, nat->nat_oip); 1721 7176 yx160601 break; 1722 7176 yx160601 #ifdef USE_INET6 1723 7176 yx160601 case 6: 1724 7176 yx160601 n = nat6_outlookup(&fin, nat->nat_flags, fin.fin_p, 1725 7176 yx160601 &nat->nat_inip6.in6, &nat->nat_oip6.in6); 1726 7176 yx160601 break; 1727 7176 yx160601 #endif 1728 7176 yx160601 default: 1729 7176 yx160601 n = NULL; 1730 7176 yx160601 break; 1731 7176 yx160601 } 1732 7176 yx160601 1733 1143 jojemann if (getlock) { 1734 3448 dh155122 RWLOCK_EXIT(&ifs->ifs_ipf_nat); 1735 1143 jojemann } 1736 1143 jojemann if (n != NULL) { 1737 429 dr146992 error = EEXIST; 1738 429 dr146992 goto junkput; 1739 429 dr146992 } 1740 429 dr146992 } else { 1741 429 dr146992 error = EINVAL; 1742 429 dr146992 goto junkput; 1743 0 stevel } 1744 0 stevel 1745 0 stevel /* 1746 0 stevel * Restore ap_session_t structure. Include the private data allocated 1747 0 stevel * if it was there. 1748 0 stevel */ 1749 2393 yz155240 aps = nat->nat_aps; 1750 0 stevel if (aps != NULL) { 1751 0 stevel KMALLOC(aps, ap_session_t *); 1752 2393 yz155240 nat->nat_aps = aps; 1753 0 stevel if (aps == NULL) { 1754 0 stevel error = ENOMEM; 1755 0 stevel goto junkput; 1756 0 stevel } 1757 0 stevel bcopy(ipnn->ipn_data, (char *)aps, sizeof(*aps)); 1758 2393 yz155240 if (in != NULL) 1759 0 stevel aps->aps_apr = in->in_apr; 1760 2393 yz155240 else 1761 2393 yz155240 aps->aps_apr = NULL; 1762 0 stevel if (aps->aps_psiz != 0) { 1763 2393 yz155240 if (aps->aps_psiz > 81920) { 1764 2393 yz155240 error = ENOMEM; 1765 2393 yz155240 goto junkput; 1766 2393 yz155240 } 1767 0 stevel KMALLOCS(aps->aps_data, void *, aps->aps_psiz); 1768 0 stevel if (aps->aps_data == NULL) { 1769 0 stevel error = ENOMEM; 1770 0 stevel goto junkput; 1771 0 stevel } 1772 0 stevel bcopy(ipnn->ipn_data + sizeof(*aps), aps->aps_data, 1773 0 stevel aps->aps_psiz); 1774 0 stevel } else { 1775 0 stevel aps->aps_psiz = 0; 1776 0 stevel aps->aps_data = NULL; 1777 0 stevel } 1778 0 stevel } 1779 0 stevel 1780 0 stevel /* 1781 0 stevel * If there was a filtering rule associated with this entry then 1782 0 stevel * build up a new one. 1783 0 stevel */ 1784 2393 yz155240 fr = nat->nat_fr; 1785 0 stevel if (fr != NULL) { 1786 2393 yz155240 if ((nat->nat_flags & SI_NEWFR) != 0) { 1787 0 stevel KMALLOC(fr, frentry_t *); 1788 0 stevel nat->nat_fr = fr; 1789 0 stevel if (fr == NULL) { 1790 0 stevel error = ENOMEM; 1791 0 stevel goto junkput; 1792 0 stevel } 1793 2393 yz155240 ipnn->ipn_nat.nat_fr = fr; 1794 2393 yz155240 (void) fr_outobj(data, ipnn, IPFOBJ_NATSAVE); 1795 2393 yz155240 bcopy((char *)&ipnn->ipn_fr, (char *)fr, sizeof(*fr)); 1796 4380 jojemann 1797 4380 jojemann fr->fr_ref = 1; 1798 4380 jojemann fr->fr_dsize = 0; 1799 4380 jojemann fr->fr_data = NULL; 1800 4380 jojemann fr->fr_type = FR_T_NONE; 1801 4380 jojemann 1802 0 stevel MUTEX_NUKE(&fr->fr_lock); 1803 0 stevel MUTEX_INIT(&fr->fr_lock, "nat-filter rule lock"); 1804 2393 yz155240 } else { 1805 4380 jojemann if (getlock) { 1806 4380 jojemann READ_ENTER(&ifs->ifs_ipf_nat); 1807 4380 jojemann } 1808 3448 dh155122 for (n = ifs->ifs_nat_instances; n; n = n->nat_next) 1809 0 stevel if (n->nat_fr == fr) 1810 0 stevel break; 1811 2393 yz155240 1812 1143 jojemann if (n != NULL) { 1813 1143 jojemann MUTEX_ENTER(&fr->fr_lock); 1814 1143 jojemann fr->fr_ref++; 1815 1143 jojemann MUTEX_EXIT(&fr->fr_lock); 1816 1143 jojemann } 1817 4380 jojemann if (getlock) { 1818 4380 jojemann RWLOCK_EXIT(&ifs->ifs_ipf_nat); 1819 4380 jojemann } 1820 0 stevel if (!n) { 1821 0 stevel error = ESRCH; 1822 0 stevel goto junkput; 1823 0 stevel } 1824 0 stevel } 1825 0 stevel } 1826 0 stevel 1827 2393 yz155240 if (ipnn != &ipn) { 1828 2393 yz155240 KFREES(ipnn, ipn.ipn_dsize); 1829 2393 yz155240 ipnn = NULL; 1830 2393 yz155240 } 1831 6253 an207044 1832 6253 an207044 nat_calc_chksum_diffs(nat); 1833 2393 yz155240 1834 2393 yz155240 if (getlock) { 1835 3448 dh155122 WRITE_ENTER(&ifs->ifs_ipf_nat); 1836 3448 dh155122 } 1837 7176 yx160601 1838 7176 yx160601 nat_calc_chksum_diffs(nat); 1839 7176 yx160601 1840 7176 yx160601 switch (nat->nat_v) 1841 7176 yx160601 { 1842 7176 yx160601 case 4 : 1843 7176 yx160601 error = nat_insert(nat, nat->nat_rev, ifs); 1844 7176 yx160601 break; 1845 7176 yx160601 #ifdef USE_INET6 1846 7176 yx160601 case 6 : 1847 7176 yx160601 error = nat6_insert(nat, nat->nat_rev, ifs); 1848 7176 yx160601 break; 1849 7176 yx160601 #endif 1850 7176 yx160601 default : 1851 7176 yx160601 break; 1852 7176 yx160601 } 1853 7176 yx160601 1854 2393 yz155240 if ((error == 0) && (aps != NULL)) { 1855 3448 dh155122 aps->aps_next = ifs->ifs_ap_sess_list; 1856 3448 dh155122 ifs->ifs_ap_sess_list = aps; 1857 3448 dh155122 } 1858 3448 dh155122 if (getlock) { 1859 3448 dh155122 RWLOCK_EXIT(&ifs->ifs_ipf_nat); 1860 1143 jojemann } 1861 2393 yz155240 1862 2393 yz155240 if (error == 0) 1863 2393 yz155240 return 0; 1864 2393 yz155240 1865 263 jojemann error = ENOMEM; 1866 263 jojemann 1867 0 stevel junkput: 1868 2393 yz155240 if (fr != NULL) 1869 3448 dh155122 (void) fr_derefrule(&fr, ifs); 1870 2393 yz155240 1871 2393 yz155240 if ((ipnn != NULL) && (ipnn != &ipn)) { 1872 2393 yz155240 KFREES(ipnn, ipn.ipn_dsize); 1873 263 jojemann } 1874 263 jojemann if (nat != NULL) { 1875 263 jojemann if (aps != NULL) { 1876 263 jojemann if (aps->aps_data != NULL) { 1877 263 jojemann KFREES(aps->aps_data, aps->aps_psiz); 1878 263 jojemann } 1879 263 jojemann KFREE(aps); 1880 263 jojemann } 1881 263 jojemann if (in != NULL) { 1882 263 jojemann if (in->in_apr) 1883 263 jojemann appr_free(in->in_apr); 1884 263 jojemann KFREE(in); 1885 263 jojemann } 1886 263 jojemann KFREE(nat); 1887 263 jojemann } 1888 2393 yz155240 return error; 1889 0 stevel } 1890 0 stevel 1891 0 stevel 1892 0 stevel /* ------------------------------------------------------------------------ */ 1893 0 stevel /* Function: nat_delete */ 1894 8170 John /* Returns: int - 0 if entry deleted. Otherwise, ref count on entry */ 1895 8170 John /* Parameters: nat - pointer to the NAT entry to delete */ 1896 8170 John /* logtype - type of LOG record to create before deleting */ 1897 8170 John /* ifs - ipf stack instance */ 1898 0 stevel /* Write Lock: ipf_nat */ 1899 0 stevel /* */ 1900 0 stevel /* Delete a nat entry from the various lists and table. If NAT logging is */ 1901 0 stevel /* enabled then generate a NAT log record for this event. */ 1902 0 stevel /* ------------------------------------------------------------------------ */ 1903 8170 John int nat_delete(nat, logtype, ifs) 1904 0 stevel struct nat *nat; 1905 0 stevel int logtype; 1906 3448 dh155122 ipf_stack_t *ifs; 1907 0 stevel { 1908 0 stevel struct ipnat *ipn; 1909 7432 John int removed = 0; 1910 0 stevel 1911 3448 dh155122 if (logtype != 0 && ifs->ifs_nat_logging != 0) 1912 3448 dh155122 nat_log(nat, logtype, ifs); 1913 3448 dh155122 1914 0 stevel /* 1915 7432 John * Start by removing the entry from the hash table of nat entries 1916 7432 John * so it will not be "used" again. 1917 7432 John * 1918 7432 John * It will remain in the "list" of nat entries until all references 1919 7432 John * have been accounted for. 1920 7432 John */ 1921 7432 John if ((nat->nat_phnext[0] != NULL) && (nat->nat_phnext[1] != NULL)) { 1922 7432 John removed = 1; 1923 7432 John 1924 3448 dh155122 ifs->ifs_nat_stats.ns_bucketlen[0][nat->nat_hv[0]]--; 1925 3448 dh155122 ifs->ifs_nat_stats.ns_bucketlen[1][nat->nat_hv[1]]--; 1926 0 stevel 1927 7432 John *nat->nat_phnext[0] = nat->nat_hnext[0]; 1928 7432 John if (nat->nat_hnext[0] != NULL) { 1929 7432 John nat->nat_hnext[0]->nat_phnext[0] = nat->nat_phnext[0]; 1930 7432 John nat->nat_hnext[0] = NULL; 1931 7432 John } 1932 7432 John nat->nat_phnext[0] = NULL; 1933 7432 John 1934 7432 John *nat->nat_phnext[1] = nat->nat_hnext[1]; 1935 7432 John if (nat->nat_hnext[1] != NULL) { 1936 7432 John nat->nat_hnext[1]->nat_phnext[1] = nat->nat_phnext[1]; 1937 7432 John nat->nat_hnext[1] = NULL; 1938 7432 John } 1939 7432 John nat->nat_phnext[1] = NULL; 1940 7432 John 1941 7432 John if ((nat->nat_flags & SI_WILDP) != 0) 1942 7432 John ifs->ifs_nat_stats.ns_wilds--; 1943 7432 John } 1944 7432 John 1945 7432 John /* 1946 7432 John * Next, remove it from the timeout queue it is in. 1947 7432 John */ 1948 7432 John fr_deletequeueentry(&nat->nat_tqe); 1949 7432 John 1950 7432 John if (nat->nat_me != NULL) { 1951 7432 John *nat->nat_me = NULL; 1952 7432 John nat->nat_me = NULL; 1953 7432 John } 1954 7432 John 1955 7432 John MUTEX_ENTER(&nat->nat_lock); 1956 8624 Darren if (nat->nat_ref > 1) { 1957 7432 John nat->nat_ref--; 1958 7432 John MUTEX_EXIT(&nat->nat_lock); 1959 7432 John if (removed) 1960 7432 John ifs->ifs_nat_stats.ns_orphans++; 1961 8170 John return (nat->nat_ref); 1962 7432 John } 1963 7432 John MUTEX_EXIT(&nat->nat_lock); 1964 7432 John 1965 7432 John nat->nat_ref = 0; 1966 7432 John 1967 7432 John /* 1968 7432 John * If entry had already been removed, 1969 7432 John * it means we're cleaning up an orphan. 1970 7432 John */ 1971 7432 John if (!removed) 1972 7432 John ifs->ifs_nat_stats.ns_orphans--; 1973 7432 John 1974 7432 John #ifdef IPFILTER_SYNC 1975 7432 John if (nat->nat_sync) 1976 7432 John ipfsync_del(nat->nat_sync); 1977 7432 John #endif 1978 7432 John 1979 7432 John /* 1980 7432 John * Now remove it from master list of nat table entries 1981 7432 John */ 1982 7432 John if (nat->nat_pnext != NULL) { 1983 0 stevel *nat->nat_pnext = nat->nat_next; 1984 0 stevel if (nat->nat_next != NULL) { 1985 0 stevel nat->nat_next->nat_pnext = nat->nat_pnext; 1986 0 stevel nat->nat_next = NULL; 1987 0 stevel } 1988 0 stevel nat->nat_pnext = NULL; 1989 7432 John } 1990 8170 John 1991 0 stevel if (nat->nat_fr != NULL) 1992 3448 dh155122 (void)fr_derefrule(&nat->nat_fr, ifs); 1993 0 stevel 1994 0 stevel if (nat->nat_hm != NULL) 1995 5417 jojemann fr_hostmapdel(&nat->nat_hm); 1996 0 stevel 1997 0 stevel /* 1998 0 stevel * If there is an active reference from the nat entry to its parent 1999 0 stevel * rule, decrement the rule's reference count and free it too if no 2000 0 stevel * longer being used. 2001 0 stevel */ 2002 0 stevel ipn = nat->nat_ptr; 2003 0 stevel if (ipn != NULL) { 2004 0 stevel ipn->in_space++; 2005 0 stevel ipn->in_use--; 2006 0 stevel if (ipn->in_use == 0 && (ipn->in_flags & IPN_DELETE)) { 2007 0 stevel if (ipn->in_apr) 2008 0 stevel appr_free(ipn->in_apr); 2009 0 stevel KFREE(ipn); 2010 3448 dh155122 ifs->ifs_nat_stats.ns_rules--; 2011 0 stevel } 2012 0 stevel } 2013 0 stevel 2014 0 stevel MUTEX_DESTROY(&nat->nat_lock); 2015 0 stevel 2016 3448 dh155122 aps_free(nat->nat_aps, ifs); 2017 3448 dh155122 ifs->ifs_nat_stats.ns_inuse--; 2018 0 stevel 2019 0 stevel /* 2020 0 stevel * If there's a fragment table entry too for this nat entry, then 2021 0 stevel * dereference that as well. This is after nat_lock is released 2022 0 stevel * because of Tru64. 2023 0 stevel */ 2024 3448 dh155122 fr_forgetnat((void *)nat, ifs); 2025 0 stevel 2026 0 stevel KFREE(nat); 2027 8170 John 2028 8170 John return (0); 2029 0 stevel } 2030 0 stevel 2031 0 stevel 2032 0 stevel /* ------------------------------------------------------------------------ */ 2033 0 stevel /* Function: nat_clearlist */ 2034 0 stevel /* Returns: int - number of NAT/RDR rules deleted */ 2035 0 stevel /* Parameters: Nil */ 2036 0 stevel /* */ 2037 0 stevel /* Delete all rules in the current list of rules. There is nothing elegant */ 2038 0 stevel /* about this cleanup: simply free all entries on the list of rules and */ 2039 0 stevel /* clear out the tables used for hashed NAT rule lookups. */ 2040 0 stevel /* ------------------------------------------------------------------------ */ 2041 3448 dh155122 static int nat_clearlist(ifs) 2042 3448 dh155122 ipf_stack_t *ifs; 2043 3448 dh155122 { 2044 3448 dh155122 ipnat_t *n, **np = &ifs->ifs_nat_list; 2045 0 stevel int i = 0; 2046 0 stevel 2047 3448 dh155122 if (ifs->ifs_nat_rules != NULL) 2048 3448 dh155122 bzero((char *)ifs->ifs_nat_rules, 2049 3448 dh155122 sizeof(*ifs->ifs_nat_rules) * ifs->ifs_ipf_natrules_sz); 2050 3448 dh155122 if (ifs->ifs_rdr_rules != NULL) 2051 3448 dh155122 bzero((char *)ifs->ifs_rdr_rules, 2052 3448 dh155122 sizeof(*ifs->ifs_rdr_rules) * ifs->ifs_ipf_rdrrules_sz); 2053 0 stevel 2054 0 stevel while ((n = *np) != NULL) { 2055 0 stevel *np = n->in_next; 2056 0 stevel if (n->in_use == 0) { 2057 0 stevel if (n->in_apr != NULL) 2058 0 stevel appr_free(n->in_apr); 2059 0 stevel KFREE(n); 2060 3448 dh155122 ifs->ifs_nat_stats.ns_rules--; 2061 0 stevel } else { 2062 0 stevel n->in_flags |= IPN_DELETE; 2063 0 stevel n->in_next = NULL; 2064 0 stevel } 2065 0 stevel i++; 2066 0 stevel } 2067 3448 dh155122 ifs->ifs_nat_masks = 0; 2068 3448 dh155122 ifs->ifs_rdr_masks = 0; 2069 7176 yx160601 for (i = 0; i < 4; i++) { 2070 7176 yx160601 ifs->ifs_nat6_masks[i] = 0; 2071 7176 yx160601 ifs->ifs_rdr6_masks[i] = 0; 2072 7176 yx160601 } 2073 0 stevel return i; 2074 0 stevel } 2075 0 stevel 2076 0 stevel 2077 0 stevel /* ------------------------------------------------------------------------ */ 2078 0 stevel /* Function: nat_newmap */ 2079 0 stevel /* Returns: int - -1 == error, 0 == success */ 2080 0 stevel /* Parameters: fin(I) - pointer to packet information */ 2081 0 stevel /* nat(I) - pointer to NAT entry */ 2082 0 stevel /* ni(I) - pointer to structure with misc. information needed */ 2083 0 stevel /* to create new NAT entry. */ 2084 0 stevel /* */ 2085 0 stevel /* Given an empty NAT structure, populate it with new information about a */ 2086 0 stevel /* new NAT session, as defined by the matching NAT rule. */ 2087 2393 yz155240 /* ni.nai_ip is passed in uninitialised and must be set, in host byte order,*/ 2088 2393 yz155240 /* to the new IP address for the translation. */ 2089 0 stevel /* ------------------------------------------------------------------------ */ 2090 0 stevel static INLINE int nat_newmap(fin, nat, ni) 2091 0 stevel fr_info_t *fin; 2092 0 stevel nat_t *nat; 2093 0 stevel natinfo_t *ni; 2094 0 stevel { 2095 0 stevel u_short st_port, dport, sport, port, sp, dp; 2096 0 stevel struct in_addr in, inb; 2097 0 stevel hostmap_t *hm; 2098 0 stevel u_32_t flags; 2099 0 stevel u_32_t st_ip; 2100 0 stevel ipnat_t *np; 2101 0 stevel nat_t *natl; 2102 0 stevel int l; 2103 3448 dh155122 ipf_stack_t *ifs = fin->fin_ifs; 2104 0 stevel 2105 0 stevel /* 2106 0 stevel * If it's an outbound packet which doesn't match any existing 2107 0 stevel * record, then create a new port 2108 0 stevel */ 2109 0 stevel l = 0; 2110 0 stevel hm = NULL; 2111 0 stevel np = ni->nai_np; 2112 0 stevel st_ip = np->in_nip; 2113 0 stevel st_port = np->in_pnext; 2114 0 stevel flags = ni->nai_flags; 2115 0 stevel sport = ni->nai_sport; 2116 0 stevel dport = ni->nai_dport; 2117 0 stevel 2118 0 stevel /* 2119 0 stevel * Do a loop until we either run out of entries to try or we find 2120 0 stevel * a NAT mapping that isn't currently being used. This is done 2121 0 stevel * because the change to the source is not (usually) being fixed. 2122 0 stevel */ 2123 0 stevel do { 2124 0 stevel port = 0; 2125 0 stevel in.s_addr = htonl(np->in_nip); 2126 0 stevel if (l == 0) { 2127 0 stevel /* 2128 0 stevel * Check to see if there is an existing NAT 2129 0 stevel * setup for this IP address pair. 2130 0 stevel */ 2131 0 stevel hm = nat_hostmap(np, fin->fin_src, fin->fin_dst, 2132 3448 dh155122 in, 0, ifs); 2133 0 stevel if (hm != NULL) 2134 0 stevel in.s_addr = hm->hm_mapip.s_addr; 2135 0 stevel } else if ((l == 1) && (hm != NULL)) { 2136 5417 jojemann fr_hostmapdel(&hm); 2137 0 stevel } 2138 0 stevel in.s_addr = ntohl(in.s_addr); 2139 0 stevel 2140 0 stevel nat->nat_hm = hm; 2141 0 stevel 2142 0 stevel if ((np->in_outmsk == 0xffffffff) && (np->in_pnext == 0)) { 2143 0 stevel if (l > 0) 2144 0 stevel return -1; 2145 0 stevel } 2146 0 stevel 2147 0 stevel if (np->in_redir == NAT_BIMAP && 2148 0 stevel np->in_inmsk == np->in_outmsk) { 2149 0 stevel /* 2150 0 stevel * map the address block in a 1:1 fashion 2151 0 stevel */ 2152 0 stevel in.s_addr = np->in_outip; 2153 0 stevel in.s_addr |= fin->fin_saddr & ~np->in_inmsk; 2154 0 stevel in.s_addr = ntohl(in.s_addr); 2155 0 stevel 2156 0 stevel } else if (np->in_redir & NAT_MAPBLK) { 2157 0 stevel if ((l >= np->in_ppip) || ((l > 0) && 2158 0 stevel !(flags & IPN_TCPUDP))) 2159 0 stevel return -1; 2160 0 stevel /* 2161 0 stevel * map-block - Calculate destination address. 2162 0 stevel */ 2163 0 stevel in.s_addr = ntohl(fin->fin_saddr); 2164 0 stevel in.s_addr &= ntohl(~np->in_inmsk); 2165 0 stevel inb.s_addr = in.s_addr; 2166 0 stevel in.s_addr /= np->in_ippip; 2167 0 stevel in.s_addr &= ntohl(~np->in_outmsk); 2168 0 stevel in.s_addr += ntohl(np->in_outip); 2169 0 stevel /* 2170 0 stevel * Calculate destination port. 2171 0 stevel */ 2172 0 stevel if ((flags & IPN_TCPUDP) && 2173 0 stevel (np->in_ppip != 0)) { 2174 0 stevel port = ntohs(sport) + l; 2175 0 stevel port %= np->in_ppip; 2176 0 stevel port += np->in_ppip * 2177 0 stevel (inb.s_addr % np->in_ippip); 2178 0 stevel port += MAPBLK_MINPORT; 2179 0 stevel port = htons(port); 2180 0 stevel } 2181 0 stevel 2182 0 stevel } else if ((np->in_outip == 0) && 2183 0 stevel (np->in_outmsk == 0xffffffff)) { 2184 0 stevel /* 2185 0 stevel * 0/32 - use the interface's IP address. 2186 0 stevel */ 2187 0 stevel if ((l > 0) || 2188 0 stevel fr_ifpaddr(4, FRI_NORMAL, fin->fin_ifp, 2189 3448 dh155122 &in, NULL, fin->fin_ifs) == -1) 2190 0 stevel return -1; 2191 0 stevel in.s_addr = ntohl(in.s_addr); 2192 0 stevel 2193 0 stevel } else if ((np->in_outip == 0) && (np->in_outmsk == 0)) { 2194 0 stevel /* 2195 0 stevel * 0/0 - use the original source address/port. 2196 0 stevel */ 2197 0 stevel if (l > 0) 2198 0 stevel return -1; 2199 0 stevel in.s_addr = ntohl(fin->fin_saddr); 2200 0 stevel 2201 0 stevel } else if ((np->in_outmsk != 0xffffffff) && 2202 0 stevel (np->in_pnext == 0) && ((l > 0) || (hm == NULL))) 2203 0 stevel np->in_nip++; 2204 0 stevel 2205 0 stevel natl = NULL; 2206 0 stevel 2207 0 stevel if ((flags & IPN_TCPUDP) && 2208 0 stevel ((np->in_redir & NAT_MAPBLK) == 0) && 2209 0 stevel (np->in_flags & IPN_AUTOPORTMAP)) { 2210 0 stevel /* 2211 0 stevel * "ports auto" (without map-block) 2212 0 stevel */ 2213 0 stevel if ((l > 0) && (l % np->in_ppip == 0)) { 2214 0 stevel if (l > np->in_space) { 2215 0 stevel return -1; 2216 0 stevel } else if ((l > np->in_ppip) && 2217 0 stevel np->in_outmsk != 0xffffffff) 2218 0 stevel np->in_nip++; 2219 0 stevel } 2220 0 stevel if (np->in_ppip != 0) { 2221 0 stevel port = ntohs(sport); 2222 0 stevel port += (l % np->in_ppip); 2223 0 stevel port %= np->in_ppip; 2224 0 stevel port += np->in_ppip * 2225 0 stevel (ntohl(fin->fin_saddr) % 2226 0 stevel np->in_ippip); 2227 0 stevel port += MAPBLK_MINPORT; 2228 0 stevel port = htons(port); 2229 0 stevel } 2230 0 stevel 2231 0 stevel } else if (((np->in_redir & NAT_MAPBLK) == 0) && 2232 0 stevel (flags & IPN_TCPUDPICMP) && (np->in_pnext != 0)) { 2233 0 stevel /* 2234 0 stevel * Standard port translation. Select next port. 2235 0 stevel */ 2236 7259 dr146992 if (np->in_flags & IPN_SEQUENTIAL) { 2237 7259 dr146992 port = np->in_pnext; 2238 7259 dr146992 } else { 2239 7259 dr146992 port = ipf_random() % (ntohs(np->in_pmax) - 2240 8624 Darren ntohs(np->in_pmin) + 1); 2241 7259 dr146992 port += ntohs(np->in_pmin); 2242 7259 dr146992 } 2243 7259 dr146992 port = htons(port); 2244 7259 dr146992 np->in_pnext++; 2245 0 stevel 2246 0 stevel if (np->in_pnext > ntohs(np->in_pmax)) { 2247 0 stevel np->in_pnext = ntohs(np->in_pmin); 2248 0 stevel if (np->in_outmsk != 0xffffffff) 2249 0 stevel np->in_nip++; 2250 0 stevel } 2251 0 stevel } 2252 0 stevel 2253 0 stevel if (np->in_flags & IPN_IPRANGE) { 2254 0 stevel if (np->in_nip > ntohl(np->in_outmsk)) 2255 0 stevel np->in_nip = ntohl(np->in_outip); 2256 0 stevel } else { 2257 0 stevel if ((np->in_outmsk != 0xffffffff) && 2258 0 stevel ((np->in_nip + 1) & ntohl(np->in_outmsk)) > 2259 0 stevel ntohl(np->in_outip)) 2260 0 stevel np->in_nip = ntohl(np->in_outip) + 1; 2261 0 stevel } 2262 0 stevel 2263 0 stevel if ((port == 0) && (flags & (IPN_TCPUDPICMP|IPN_ICMPQUERY))) 2264 0 stevel port = sport; 2265 0 stevel 2266 0 stevel /* 2267 0 stevel * Here we do a lookup of the connection as seen from 2268 0 stevel * the outside. If an IP# pair already exists, try 2269 0 stevel * again. So if you have A->B becomes C->B, you can 2270 0 stevel * also have D->E become C->E but not D->B causing 2271 0 stevel * another C->B. Also take protocol and ports into 2272 0 stevel * account when determining whether a pre-existing 2273 0 stevel * NAT setup will cause an external conflict where 2274 0 stevel * this is appropriate. 2275 0 stevel */ 2276 0 stevel inb.s_addr = htonl(in.s_addr); 2277 0 stevel sp = fin->fin_data[0]; 2278 0 stevel dp = fin->fin_data[1]; 2279 0 stevel fin->fin_data[0] = fin->fin_data[1]; 2280 0 stevel fin->fin_data[1] = htons(port); 2281 0 stevel natl = nat_inlookup(fin, flags & ~(SI_WILDP|NAT_SEARCH), 2282 0 stevel (u_int)fin->fin_p, fin->fin_dst, inb); 2283 0 stevel fin->fin_data[0] = sp; 2284 0 stevel fin->fin_data[1] = dp; 2285 0 stevel 2286 0 stevel /* 2287 0 stevel * Has the search wrapped around and come back to the 2288 0 stevel * start ? 2289 0 stevel */ 2290 0 stevel if ((natl != NULL) && 2291 0 stevel (np->in_pnext != 0) && (st_port == np->in_pnext) && 2292 0 stevel (np->in_nip != 0) && (st_ip == np->in_nip)) 2293 0 stevel return -1; 2294 0 stevel l++; 2295 0 stevel } while (natl != NULL); 2296 0 stevel 2297 0 stevel if (np->in_space > 0) 2298 0 stevel np->in_space--; 2299 0 stevel 2300 0 stevel /* Setup the NAT table */ 2301 0 stevel nat->nat_inip = fin->fin_src; 2302 0 stevel nat->nat_outip.s_addr = htonl(in.s_addr); 2303 0 stevel nat->nat_oip = fin->fin_dst; 2304 0 stevel if (nat->nat_hm == NULL) 2305 0 stevel nat->nat_hm = nat_hostmap(np, fin->fin_src, fin->fin_dst, 2306 3448 dh155122 nat->nat_outip, 0, ifs); 2307 0 stevel 2308 2393 yz155240 if (flags & IPN_TCPUDP) { 2309 0 stevel nat->nat_inport = sport; 2310 0 stevel nat->nat_outport = port; /* sport */ 2311 0 stevel nat->nat_oport = dport; 2312 0 stevel ((tcphdr_t *)fin->fin_dp)->th_sport = port; 2313 2393 yz155240 } else if (flags & IPN_ICMPQUERY) { 2314 0 stevel ((icmphdr_t *)fin->fin_dp)->icmp_id = port; 2315 2393 yz155240 nat->nat_inport = port; 2316 2393 yz155240 nat->nat_outport = port; 2317 2393 yz155240 } 2318 2393 yz155240 2319 2393 yz155240 ni->nai_ip.s_addr = in.s_addr; 2320 0 stevel ni->nai_port = port; 2321 0 stevel ni->nai_nport = dport; 2322 0 stevel return 0; 2323 0 stevel } 2324 0 stevel 2325 0 stevel 2326 0 stevel /* ------------------------------------------------------------------------ */ 2327 0 stevel /* Function: nat_newrdr */ 2328 0 stevel /* Returns: int - -1 == error, 0 == success (no move), 1 == success and */ 2329 0 stevel /* allow rule to be moved if IPN_ROUNDR is set. */ 2330 0 stevel /* Parameters: fin(I) - pointer to packet information */ 2331 0 stevel /* nat(I) - pointer to NAT entry */ 2332 0 stevel /* ni(I) - pointer to structure with misc. information needed */ 2333 0 stevel /* to create new NAT entry. */ 2334 0 stevel /* */ 2335 2393 yz155240 /* ni.nai_ip is passed in uninitialised and must be set, in host byte order,*/ 2336 2393 yz155240 /* to the new IP address for the translation. */ 2337 0 stevel /* ------------------------------------------------------------------------ */ 2338 0 stevel static INLINE int nat_newrdr(fin, nat, ni) 2339 0 stevel fr_info_t *fin; 2340 0 stevel nat_t *nat; 2341 0 stevel natinfo_t *ni; 2342 0 stevel { 2343 0 stevel u_short nport, dport, sport; 2344 5828 jojemann struct in_addr in, inb; 2345 5828 jojemann u_short sp, dp; 2346 0 stevel hostmap_t *hm; 2347 0 stevel u_32_t flags; 2348 0 stevel ipnat_t *np; 2349 5828 jojemann nat_t *natl; 2350 0 stevel int move; 2351 3448 dh155122 ipf_stack_t *ifs = fin->fin_ifs; 2352 0 stevel 2353 0 stevel move = 1; 2354 0 stevel hm = NULL; 2355 2393 yz155240 in.s_addr = 0; 2356 0 stevel np = ni->nai_np; 2357 0 stevel flags = ni->nai_flags; 2358 0 stevel sport = ni->nai_sport; 2359 0 stevel dport = ni->nai_dport; 2360 0 stevel 2361 0 stevel /* 2362 0 stevel * If the matching rule has IPN_STICKY set, then we want to have the 2363 0 stevel * same rule kick in as before. Why would this happen? If you have 2364 0 stevel * a collection of rdr rules with "round-robin sticky", the current 2365 0 stevel * packet might match a different one to the previous connection but 2366 0 stevel * we want the same destination to be used. 2367 0 stevel */ 2368 0 stevel if ((np->in_flags & (IPN_ROUNDR|IPN_STICKY)) == 2369 0 stevel (IPN_ROUNDR|IPN_STICKY)) { 2370 0 stevel hm = nat_hostmap(NULL, fin->fin_src, fin->fin_dst, in, 2371 3448 dh155122 (u_32_t)dport, ifs); 2372 0 stevel if (hm != NULL) { 2373 2393 yz155240 in.s_addr = ntohl(hm->hm_mapip.s_addr); 2374 0 stevel np = hm->hm_ipnat; 2375 0 stevel ni->nai_np = np; 2376 0 stevel move = 0; 2377 0 stevel } 2378 0 stevel } 2379 0 stevel 2380 0 stevel /* 2381 0 stevel * Otherwise, it's an inbound packet. Most likely, we don't 2382 0 stevel * want to rewrite source ports and source addresses. Instead, 2383 0 stevel * we want to rewrite to a fixed internal address and fixed 2384 0 stevel * internal port. 2385 0 stevel */ 2386 0 stevel if (np->in_flags & IPN_SPLIT) { 2387 0 stevel in.s_addr = np->in_nip; 2388 0 stevel 2389 0 stevel if ((np->in_flags & (IPN_ROUNDR|IPN_STICKY)) == IPN_STICKY) { 2390 0 stevel hm = nat_hostmap(np, fin->fin_src, fin->fin_dst, 2391 3448 dh155122 in, (u_32_t)dport, ifs); 2392 0 stevel if (hm != NULL) { 2393 0 stevel in.s_addr = hm->hm_mapip.s_addr; 2394 0 stevel move = 0; 2395 0 stevel } 2396 0 stevel } 2397 0 stevel 2398 0 stevel if (hm == NULL || hm->hm_ref == 1) { 2399 0 stevel if (np->in_inip == htonl(in.s_addr)) { 2400 0 stevel np->in_nip = ntohl(np->in_inmsk); 2401 0 stevel move = 0; 2402 0 stevel } else { 2403 0 stevel np->in_nip = ntohl(np->in_inip); 2404 0 stevel } 2405 0 stevel } 2406 0 stevel 2407 0 stevel } else if ((np->in_inip == 0) && (np->in_inmsk == 0xffffffff)) { 2408 0 stevel /* 2409 0 stevel * 0/32 - use the interface's IP address. 2410 0 stevel */ 2411 3448 dh155122 if (fr_ifpaddr(4, FRI_NORMAL, fin->fin_ifp, &in, NULL, 2412 3448 dh155122 fin->fin_ifs) == -1) 2413 0 stevel return -1; 2414 0 stevel in.s_addr = ntohl(in.s_addr); 2415 0 stevel 2416 0 stevel } else if ((np->in_inip == 0) && (np->in_inmsk== 0)) { 2417 0 stevel /* 2418 0 stevel * 0/0 - use the original destination address/port. 2419 0 stevel */ 2420 0 stevel in.s_addr = ntohl(fin->fin_daddr); 2421 0 stevel 2422 0 stevel } else if (np->in_redir == NAT_BIMAP && 2423 0 stevel np->in_inmsk == np->in_outmsk) { 2424 0 stevel /* 2425 0 stevel * map the address block in a 1:1 fashion 2426 0 stevel */ 2427 2393 yz155240 in.s_addr = np->in_inip; 2428 2393 yz155240 in.s_addr |= fin->fin_daddr & ~np->in_inmsk; 2429 2393 yz155240 in.s_addr = ntohl(in.s_addr); 2430 0 stevel } else { 2431 0 stevel in.s_addr = ntohl(np->in_inip); 2432 0 stevel } 2433 0 stevel 2434 0 stevel if ((np->in_pnext == 0) || ((flags & NAT_NOTRULEPORT) != 0)) 2435 0 stevel nport = dport; 2436 0 stevel else { 2437 0 stevel /* 2438 0 stevel * Whilst not optimized for the case where 2439 0 stevel * pmin == pmax, the gain is not significant. 2440 0 stevel */ 2441 2393 yz155240 if (((np->in_flags & IPN_FIXEDDPORT) == 0) && 2442 2393 yz155240 (np->in_pmin != np->in_pmax)) { 2443 0 stevel nport = ntohs(dport) - ntohs(np->in_pmin) + 2444 0 stevel ntohs(np->in_pnext); 2445 0 stevel nport = htons(nport); 2446 0 stevel } else 2447 0 stevel nport = np->in_pnext; 2448 0 stevel } 2449 0 stevel 2450 0 stevel /* 2451 0 stevel * When the redirect-to address is set to 0.0.0.0, just 2452 0 stevel * assume a blank `forwarding' of the packet. We don't 2453 0 stevel * setup any translation for this either. 2454 0 stevel */ 2455 0 stevel if (in.s_addr == 0) { 2456 0 stevel if (nport == dport) 2457 0 stevel return -1; 2458 0 stevel in.s_addr = ntohl(fin->fin_daddr); 2459 0 stevel } 2460 5828 jojemann 2461 5828 jojemann /* 2462 5828 jojemann * Check to see if this redirect mapping already exists and if 2463 5828 jojemann * it does, return "failure" (allowing it to be created will just 2464 5828 jojemann * cause one or both of these "connections" to stop working.) 2465 5828 jojemann */ 2466 5828 jojemann inb.s_addr = htonl(in.s_addr); 2467 5828 jojemann sp = fin->fin_data[0]; 2468 5828 jojemann dp = fin->fin_data[1]; 2469 5828 jojemann fin->fin_data[1] = fin->fin_data[0]; 2470 5828 jojemann fin->fin_data[0] = ntohs(nport); 2471 5828 jojemann natl = nat_outlookup(fin, flags & ~(SI_WILDP|NAT_SEARCH), 2472 5828 jojemann (u_int)fin->fin_p, inb, fin->fin_src); 2473 5828 jojemann fin->fin_data[0] = sp; 2474 5828 jojemann fin->fin_data[1] = dp; 2475 5828 jojemann if (natl != NULL) 2476 5828 jojemann return (-1); 2477 0 stevel 2478 0 stevel nat->nat_inip.s_addr = htonl(in.s_addr); 2479 0 stevel nat->nat_outip = fin->fin_dst; 2480 0 stevel nat->nat_oip = fin->fin_src; 2481 0 stevel 2482 2393 yz155240 ni->nai_ip.s_addr = in.s_addr; 2483 0 stevel ni->nai_nport = nport; 2484 0 stevel ni->nai_port = sport; 2485 0 stevel 2486 0 stevel if (flags & IPN_TCPUDP) { 2487 0 stevel nat->nat_inport = nport; 2488 0 stevel nat->nat_outport = dport; 2489 0 stevel nat->nat_oport = sport; 2490 0 stevel ((tcphdr_t *)fin->fin_dp)->th_dport = nport; 2491 0 stevel } else if (flags & IPN_ICMPQUERY) { 2492 0 stevel ((icmphdr_t *)fin->fin_dp)->icmp_id = nport; 2493 2393 yz155240 nat->nat_inport = nport; 2494 2393 yz155240 nat->nat_outport = nport; 2495 0 stevel } 2496 0 stevel 2497 0 stevel return move; 2498 0 stevel } 2499 0 stevel 2500 0 stevel /* ------------------------------------------------------------------------ */ 2501 0 stevel /* Function: nat_new */ 2502 0 stevel /* Returns: nat_t* - NULL == failure to create new NAT structure, */ 2503 0 stevel /* else pointer to new NAT structure */ 2504 0 stevel /* Parameters: fin(I) - pointer to packet information */ 2505 0 stevel /* np(I) - pointer to NAT rule */ 2506 0 stevel /* natsave(I) - pointer to where to store NAT struct pointer */ 2507 0 stevel /* flags(I) - flags describing the current packet */ 2508 0 stevel /* direction(I) - direction of packet (in/out) */ 2509 0 stevel /* Write Lock: ipf_nat */ 2510 0 stevel /* */ 2511 0 stevel /* Attempts to create a new NAT entry. Does not actually change the packet */ 2512 0 stevel /* in any way. */ 2513 0 stevel /* */ 2514 0 stevel /* This fucntion is in three main parts: (1) deal with creating a new NAT */ 2515 0 stevel /* structure for a "MAP" rule (outgoing NAT translation); (2) deal with */ 2516 0 stevel /* creating a new NAT structure for a "RDR" rule (incoming NAT translation) */ 2517 0 stevel /* and (3) building that structure and putting it into the NAT table(s). */ 2518 0 stevel /* ------------------------------------------------------------------------ */ 2519 0 stevel nat_t *nat_new(fin, np, natsave, flags, direction) 2520 0 stevel fr_info_t *fin; 2521 0 stevel ipnat_t *np; 2522 0 stevel nat_t **natsave; 2523 0 stevel u_int flags; 2524 0 stevel int direction; 2525 0 stevel { 2526 0 stevel tcphdr_t *tcp = NULL; 2527 0 stevel hostmap_t *hm = NULL; 2528 0 stevel nat_t *nat, *natl; 2529 0 stevel u_int nflags; 2530 0 stevel natinfo_t ni; 2531 0 stevel int move; 2532 3448 dh155122 ipf_stack_t *ifs = fin->fin_ifs; 2533 4817 an207044 2534 4817 an207044 /* 2535 8170 John * Trigger automatic call to nat_flushtable() if the 2536 4817 an207044 * table has reached capcity specified by hi watermark. 2537 4817 an207044 */ 2538 8170 John if (NAT_TAB_WATER_LEVEL(ifs) > ifs->ifs_nat_flush_level_hi) 2539 4817 an207044 ifs->ifs_nat_doflush = 1; 2540 3448 dh155122 2541 7432 John /* 2542 7432 John * If automatic flushing did not do its job, and the table 2543 7432 John * has filled up, don't try to create a new entry. 2544 7432 John */ 2545 3448 dh155122 if (ifs->ifs_nat_stats.ns_inuse >= ifs->ifs_ipf_nattable_max) { 2546 3448 dh155122 ifs->ifs_nat_stats.ns_memfail++; 2547 2393 yz155240 return NULL; 2548 2393 yz155240 } 2549 0 stevel 2550 0 stevel move = 1; 2551 0 stevel nflags = np->in_flags & flags; 2552 0 stevel nflags &= NAT_FROMRULE; 2553 0 stevel 2554 0 stevel ni.nai_np = np; 2555 0 stevel ni.nai_nflags = nflags; 2556 0 stevel ni.nai_flags = flags; 2557 0 stevel 2558 0 stevel /* Give me a new nat */ 2559 0 stevel KMALLOC(nat, nat_t *); 2560 0 stevel if (nat == NULL) { 2561 3448 dh155122 ifs->ifs_nat_stats.ns_memfail++; 2562 2393 yz155240 /* 2563 2393 yz155240 * Try to automatically tune the max # of entries in the 2564 2393 yz155240 * table allowed to be less than what will cause kmem_alloc() 2565 2393 yz155240 * to fail and try to eliminate panics due to out of memory 2566 2393 yz155240 * conditions arising. 2567 2393 yz155240 */ 2568 3448 dh155122 if (ifs->ifs_ipf_nattable_max > ifs->ifs_ipf_nattable_sz) { 2569 3448 dh155122 ifs->ifs_ipf_nattable_max = ifs->ifs_nat_stats.ns_inuse - 100; 2570 2393 yz155240 printf("ipf_nattable_max reduced to %d\n", 2571 3448 dh155122 ifs->ifs_ipf_nattable_max); 2572 2393 yz155240 } 2573 0 stevel return NULL; 2574 0 stevel } 2575 0 stevel 2576 0 stevel if (flags & IPN_TCPUDP) { 2577 0 stevel tcp = fin->fin_dp; 2578 0 stevel ni.nai_sport = htons(fin->fin_sport); 2579 0 stevel ni.nai_dport = htons(fin->fin_dport); 2580 0 stevel } else if (flags & IPN_ICMPQUERY) { 2581 0 stevel /* 2582 0 stevel * In the ICMP query NAT code, we translate the ICMP id fields 2583 2393 yz155240 * to make them unique. This is indepedent of the ICMP type 2584 2393 yz155240 * (e.g. in the unlikely event that a host sends an echo and 2585 2393 yz155240 * an tstamp request with the same id, both packets will have 2586 0 stevel * their ip address/id field changed in the same way). 2587 0 stevel */ 2588 0 stevel /* The icmp_id field is used by the sender to identify the 2589 2393 yz155240 * process making the icmp request. (the receiver justs 2590 2393 yz155240 * copies it back in its response). So, it closely matches 2591 2393 yz155240 * the concept of source port. We overlay sport, so we can 2592 0 stevel * maximally reuse the existing code. 2593 0 stevel */ 2594 0 stevel ni.nai_sport = ((icmphdr_t *)fin->fin_dp)->icmp_id; 2595 0 stevel ni.nai_dport = ni.nai_sport; 2596 0 stevel } 2597 0 stevel 2598 0 stevel bzero((char *)nat, sizeof(*nat)); 2599 0 stevel nat->nat_flags = flags; 2600 3448 dh155122 nat->nat_redir = np->in_redir; 2601 0 stevel 2602 2393 yz155240 if ((flags & NAT_SLAVE) == 0) { 2603 3448 dh155122 MUTEX_ENTER(&ifs->ifs_ipf_nat_new); 2604 2393 yz155240 } 2605 0 stevel 2606 0 stevel /* 2607 0 stevel * Search the current table for a match. 2608 0 stevel */ 2609 0 stevel if (direction == NAT_OUTBOUND) { 2610 0 stevel /* 2611 0 stevel * We can now arrange to call this for the same connection 2612 0 stevel * because ipf_nat_new doesn't protect the code path into 2613 0 stevel * this function. 2614 0 stevel */ 2615 0 stevel natl = nat_outlookup(fin, nflags, (u_int)fin->fin_p, 2616 0 stevel fin->fin_src, fin->fin_dst); 2617 0 stevel if (natl != NULL) { 2618 4380 jojemann KFREE(nat); 2619 2393 yz155240 nat = natl; 2620 2393 yz155240 goto done; 2621 0 stevel } 2622 0 stevel 2623 0 stevel move = nat_newmap(fin, nat, &ni); 2624 2393 yz155240 if (move == -1) 2625 0 stevel goto badnat; 2626 0 stevel 2627 0 stevel np = ni.nai_np; 2628 0 stevel } else { 2629 2393 yz155240 /* 2630 0 stevel * NAT_INBOUND is used only for redirects rules 2631 0 stevel */ 2632 0 stevel natl = nat_inlookup(fin, nflags, (u_int)fin->fin_p, 2633 0 stevel fin->fin_src, fin->fin_dst); 2634 0 stevel if (natl != NULL) { 2635 4380 jojemann KFREE(nat); 2636 2393 yz155240 nat = natl; 2637 2393 yz155240 goto done; 2638 0 stevel } 2639 0 stevel 2640 0 stevel move = nat_newrdr(fin, nat, &ni); 2641 2393 yz155240 if (move == -1) 2642 0 stevel goto badnat; 2643 0 stevel 2644 0 stevel np = ni.nai_np; 2645 6256 an207044 } 2646 0 stevel 2647 0 stevel if ((move == 1) && (np->in_flags & IPN_ROUNDR)) { 2648 0 stevel if (np->in_redir == NAT_REDIRECT) { 2649 0 stevel nat_delrdr(np); 2650 3448 dh155122 nat_addrdr(np, ifs); 2651 0 stevel } else if (np->in_redir == NAT_MAP) { 2652 0 stevel nat_delnat(np); 2653 3448 dh155122 nat_addnat(np, ifs); 2654 0 stevel } 2655 0 stevel } 2656 0 stevel 2657 0 stevel if (nat_finalise(fin, nat, &ni, tcp, natsave, direction) == -1) { 2658 2393 yz155240 goto badnat; 2659 0 stevel } 2660 6253 an207044 2661 6253 an207044 nat_calc_chksum_diffs(nat); 2662 6253 an207044 2663 0 stevel if (flags & SI_WILDP) 2664 3448 dh155122 ifs->ifs_nat_stats.ns_wilds++; 2665 7432 John fin->fin_flx |= FI_NEWNAT; 2666 2393 yz155240 goto done; 2667 0 stevel badnat: 2668 3448 dh155122 ifs->ifs_nat_stats.ns_badnat++; 2669 0 stevel if ((hm = nat->nat_hm) != NULL) 2670 5417 jojemann fr_hostmapdel(&hm); 2671 0 stevel KFREE(nat); 2672 2393 yz155240 nat = NULL; 2673 2393 yz155240 done: 2674 2393 yz155240 if ((flags & NAT_SLAVE) == 0) { 2675 3448 dh155122 MUTEX_EXIT(&ifs->ifs_ipf_nat_new); 2676 2393 yz155240 } 2677 2393 yz155240 return nat; 2678 0 stevel } 2679 0 stevel 2680 0 stevel 2681 0 stevel /* ------------------------------------------------------------------------ */ 2682 0 stevel /* Function: nat_finalise */ 2683 0 stevel /* Returns: int - 0 == sucess, -1 == failure */ 2684 0 stevel /* Parameters: fin(I) - pointer to packet information */ 2685 0 stevel /* nat(I) - pointer to NAT entry */ 2686 0 stevel /* ni(I) - pointer to structure with misc. information needed */ 2687 0 stevel /* to create new NAT entry. */ 2688 0 stevel /* Write Lock: ipf_nat */ 2689 0 stevel /* */ 2690 0 stevel /* This is the tail end of constructing a new NAT entry and is the same */ 2691 0 stevel /* for both IPv4 and IPv6. */ 2692 0 stevel /* ------------------------------------------------------------------------ */ 2693 0 stevel /*ARGSUSED*/ 2694 0 stevel static INLINE int nat_finalise(fin, nat, ni, tcp, natsave, direction) 2695 0 stevel fr_info_t *fin; 2696 0 stevel nat_t *nat; 2697 0 stevel natinfo_t *ni; 2698 0 stevel tcphdr_t *tcp; 2699 0 stevel nat_t **natsave; 2700 0 stevel int direction; 2701 0 stevel { 2702 0 stevel frentry_t *fr; 2703 0 stevel ipnat_t *np; 2704 3448 dh155122 ipf_stack_t *ifs = fin->fin_ifs; 2705 0 stevel 2706 0 stevel np = ni->nai_np; 2707 0 stevel 2708 2958 dr146992 COPYIFNAME(fin->fin_ifp, nat->nat_ifnames[0], fin->fin_v); 2709 2958 dr146992 2710 2146 jojemann #ifdef IPFILTER_SYNC 2711 2146 jojemann if ((nat->nat_flags & SI_CLONE) == 0) 2712 2146 jojemann nat->nat_sync = ipfsync_new(SMC_NAT, fin, nat); 2713 0 stevel #endif 2714 0 stevel 2715 0 stevel nat->nat_me = natsave; 2716 0 stevel nat->nat_dir = direction; 2717 2508 yz155240 nat->nat_ifps[0] = np->in_ifps[0]; 2718 2508 yz155240 nat->nat_ifps[1] = np->in_ifps[1]; 2719 0 stevel nat->nat_ptr = np; 2720 0 stevel nat->nat_p = fin->fin_p; 2721 7176 yx160601 nat->nat_v = fin->fin_v; 2722 0 stevel nat->nat_mssclamp = np->in_mssclamp; 2723 0 stevel fr = fin->fin_fr; 2724 0 stevel nat->nat_fr = fr; 2725 0 stevel 2726 0 stevel if ((np->in_apr != NULL) && ((ni->nai_flags & NAT_SLAVE) == 0)) 2727 0 stevel if (appr_new(fin, nat) == -1) 2728 0 stevel return -1; 2729 0 stevel 2730 3448 dh155122 if (nat_insert(nat, fin->fin_rev, ifs) == 0) { 2731 3448 dh155122 if (ifs->ifs_nat_logging) 2732 3448 dh155122 nat_log(nat, (u_int)np->in_redir, ifs); 2733 0 stevel np->in_use++; 2734 0 stevel if (fr != NULL) { 2735 0 stevel MUTEX_ENTER(&fr->fr_lock); 2736 0 stevel fr->fr_ref++; 2737 0 stevel MUTEX_EXIT(&fr->fr_lock); 2738 0 stevel } 2739 0 stevel return 0; 2740 0 stevel } 2741 0 stevel 2742 0 stevel /* 2743 0 stevel * nat_insert failed, so cleanup time... 2744 0 stevel */ 2745 0 stevel return -1; 2746 0 stevel } 2747 0 stevel 2748 0 stevel 2749 0 stevel /* ------------------------------------------------------------------------ */ 2750 2393 yz155240 /* Function: nat_insert */ 2751 2393 yz155240 /* Returns: int - 0 == sucess, -1 == failure */ 2752 2393 yz155240 /* Parameters: nat(I) - pointer to NAT structure */ 2753 2393 yz155240 /* rev(I) - flag indicating forward/reverse direction of packet */ 2754 2393 yz155240 /* Write Lock: ipf_nat */ 2755 0 stevel /* */ 2756 0 stevel /* Insert a NAT entry into the hash tables for searching and add it to the */ 2757 0 stevel /* list of active NAT entries. Adjust global counters when complete. */ 2758 0 stevel /* ------------------------------------------------------------------------ */ 2759 3448 dh155122 int nat_insert(nat, rev, ifs) 2760 0 stevel nat_t *nat; 2761 2393 yz155240 int rev; 2762 3448 dh155122 ipf_stack_t *ifs; 2763 2393 yz155240 { 2764 0 stevel u_int hv1, hv2; 2765 0 stevel nat_t **natp; 2766 0 stevel 2767 0 stevel /* 2768 0 stevel * Try and return an error as early as possible, so calculate the hash 2769 0 stevel * entry numbers first and then proceed. 2770 0 stevel */ 2771 0 stevel if ((nat->nat_flags & (SI_W_SPORT|SI_W_DPORT)) == 0) { 2772 0 stevel hv1 = NAT_HASH_FN(nat->nat_inip.s_addr, nat->nat_inport, 2773 0 stevel 0xffffffff); 2774 0 stevel hv1 = NAT_HASH_FN(nat->nat_oip.s_addr, hv1 + nat->nat_oport, 2775 3448 dh155122 ifs->ifs_ipf_nattable_sz); 2776 0 stevel hv2 = NAT_HASH_FN(nat->nat_outip.s_addr, nat->nat_outport, 2777 0 stevel 0xffffffff); 2778 0 stevel hv2 = NAT_HASH_FN(nat->nat_oip.s_addr, hv2 + nat->nat_oport, 2779 3448 dh155122 ifs->ifs_ipf_nattable_sz); 2780 0 stevel } else { 2781 0 stevel hv1 = NAT_HASH_FN(nat->nat_inip.s_addr, 0, 0xffffffff); 2782 3448 dh155122 hv1 = NAT_HASH_FN(nat->nat_oip.s_addr, hv1, 2783 3448 dh155122 ifs->ifs_ipf_nattable_sz); 2784 0 stevel hv2 = NAT_HASH_FN(nat->nat_outip.s_addr, 0, 0xffffffff); 2785 3448 dh155122 hv2 = NAT_HASH_FN(nat->nat_oip.s_addr, hv2, 2786 3448 dh155122 ifs->ifs_ipf_nattable_sz); 2787 3448 dh155122 } 2788 3448 dh155122 2789 3448 dh155122 if (ifs->ifs_nat_stats.ns_bucketlen[0][hv1] >= ifs->ifs_fr_nat_maxbucket || 2790 3448 dh155122 ifs->ifs_nat_stats.ns_bucketlen[1][hv2] >= ifs->ifs_fr_nat_maxbucket) { 2791 0 stevel return -1; 2792 2393 yz155240 } 2793 0 stevel 2794 0 stevel nat->nat_hv[0] = hv1; 2795 0 stevel nat->nat_hv[1] = hv2; 2796 0 stevel 2797 0 stevel MUTEX_INIT(&nat->nat_lock, "nat entry lock"); 2798 0 stevel 2799 2393 yz155240 nat->nat_rev = rev; 2800 0 stevel nat->nat_ref = 1; 2801 0 stevel nat->nat_bytes[0] = 0; 2802 0 stevel nat->nat_pkts[0] = 0; 2803 0 stevel nat->nat_bytes[1] = 0; 2804 0 stevel nat->nat_pkts[1] = 0; 2805 2393 yz155240 2806 2393 yz155240 nat->nat_ifnames[0][LIFNAMSIZ - 1] = '\0'; 2807 3448 dh155122 nat->nat_ifps[0] = fr_resolvenic(nat->nat_ifnames[0], 4, ifs); 2808 2393 yz155240 2809 2393 yz155240 if (nat->nat_ifnames[1][0] !='\0') { 2810 2393 yz155240 nat->nat_ifnames[1][LIFNAMSIZ - 1] = '\0'; 2811 3448 dh155122 nat->nat_ifps[1] = fr_resolvenic(nat->nat_ifnames[1], 4, ifs); 2812 0 stevel } else { 2813 2146 jojemann (void) strncpy(nat->nat_ifnames[1], nat->nat_ifnames[0], 2814 2393 yz155240 LIFNAMSIZ); 2815 2393 yz155240 nat->nat_ifnames[1][LIFNAMSIZ - 1] = '\0'; 2816 0 stevel nat->nat_ifps[1] = nat->nat_ifps[0]; 2817 0 stevel } 2818 0 stevel 2819 3448 dh155122 nat->nat_next = ifs->ifs_nat_instances; 2820 3448 dh155122 nat->nat_pnext = &ifs->ifs_nat_instances; 2821 3448 dh155122 if (ifs->ifs_nat_instances) 2822 3448 dh155122 ifs->ifs_nat_instances->nat_pnext = &nat->nat_next; 2823 3448 dh155122 ifs->ifs_nat_instances = nat; 2824 3448 dh155122 2825 3448 dh155122 natp = &ifs->ifs_nat_table[0][hv1]; 2826 0 stevel if (*natp) 2827 0 stevel (*natp)->nat_phnext[0] = &nat->nat_hnext[0]; 2828 0 stevel nat->nat_phnext[0] = natp; 2829 0 stevel nat->nat_hnext[0] = *natp; 2830 0 stevel *natp = nat; 2831 3448 dh155122 ifs->ifs_nat_stats.ns_bucketlen[0][hv1]++; 2832 3448 dh155122 2833 3448 dh155122 natp = &ifs->ifs_nat_table[1][hv2]; 2834 0 stevel if (*natp) 2835 0 stevel (*natp)->nat_phnext[1] = &nat->nat_hnext[1]; 2836 0 stevel nat->nat_phnext[1] = natp; 2837 0 stevel nat->nat_hnext[1] = *natp; 2838 0 stevel *natp = nat; 2839 3448 dh155122 ifs->ifs_nat_stats.ns_bucketlen[1][hv2]++; 2840 3448 dh155122 2841 3448 dh155122 fr_setnatqueue(nat, rev, ifs); 2842 3448 dh155122 2843 3448 dh155122 ifs->ifs_nat_stats.ns_added++; 2844 3448 dh155122 ifs->ifs_nat_stats.ns_inuse++; 2845 0 stevel return 0; 2846 0 stevel } 2847 0 stevel 2848 0 stevel 2849 0 stevel /* ------------------------------------------------------------------------ */ 2850 0 stevel /* Function: nat_icmperrorlookup */ 2851 0 stevel /* Returns: nat_t* - point to matching NAT structure */ 2852 0 stevel /* Parameters: fin(I) - pointer to packet information */ 2853 0 stevel /* dir(I) - direction of packet (in/out) */ 2854 0 stevel /* */ 2855 0 stevel /* Check if the ICMP error message is related to an existing TCP, UDP or */ 2856 2393 yz155240 /* ICMP query nat entry. It is assumed that the packet is already of the */ 2857 2393 yz155240 /* the required length. */ 2858 0 stevel /* ------------------------------------------------------------------------ */ 2859 0 stevel nat_t *nat_icmperrorlookup(fin, dir) 2860 0 stevel fr_info_t *fin; 2861 0 stevel int dir; 2862 0 stevel { 2863 2393 yz155240 int flags = 0, minlen; 2864 2393 yz155240 icmphdr_t *orgicmp; 2865 0 stevel tcphdr_t *tcp = NULL; 2866 2393 yz155240 u_short data[2]; 2867 2393 yz155240 nat_t *nat; 2868 0 stevel ip_t *oip; 2869 0 stevel u_int p; 2870 0 stevel 2871 0 stevel /* 2872 0 stevel * Does it at least have the return (basic) IP header ? 2873 0 stevel * Only a basic IP header (no options) should be with an ICMP error 2874 2393 yz155240 * header. Also, if it's not an error type, then return. 2875 2393 yz155240 */ 2876 2393 yz155240 if ((fin->fin_hlen != sizeof(ip_t)) || !(fin->fin_flx & FI_ICMPERR)) 2877 2393 yz155240 return NULL; 2878 2393 yz155240 2879 2393 yz155240 /* 2880 2393 yz155240 * Check packet size 2881 0 stevel */ 2882 0 stevel oip = (ip_t *)((char *)fin->fin_dp + 8); 2883 0 stevel minlen = IP_HL(oip) << 2; 2884 2393 yz155240 if ((minlen < sizeof(ip_t)) || 2885 2393 yz155240 (fin->fin_plen < ICMPERR_IPICMPHLEN + minlen)) 2886 0 stevel return NULL; 2887 0 stevel /* 2888 0 stevel * Is the buffer big enough for all of it ? It's the size of the IP 2889 0 stevel * header claimed in the encapsulated part which is of concern. It 2890 0 stevel * may be too big to be in this buffer but not so big that it's 2891 0 stevel * outside the ICMP packet, leading to TCP deref's causing problems. 2892 0 stevel * This is possible because we don't know how big oip_hl is when we 2893 0 stevel * do the pullup early in fr_check() and thus can't gaurantee it is 2894 0 stevel * all here now. 2895 0 stevel */ 2896 0 stevel #ifdef _KERNEL 2897 0 stevel { 2898 0 stevel mb_t *m; 2899 0 stevel 2900 0 stevel m = fin->fin_m; 2901 0 stevel # if defined(MENTAT) 2902 0 stevel if ((char *)oip + fin->fin_dlen - ICMPERR_ICMPHLEN > (char *)m->b_wptr) 2903 0 stevel return NULL; 2904 2393 yz155240 # else 2905 0 stevel if ((char *)oip + fin->fin_dlen - ICMPERR_ICMPHLEN > 2906 0 stevel (char *)fin->fin_ip + M_LEN(m)) 2907 2393 yz155240 return NULL; 2908 2393 yz155240 # endif 2909 2393 yz155240 } 2910 2393 yz155240 #endif 2911 2393 yz155240 2912 2393 yz155240 if (fin->fin_daddr != oip->ip_src.s_addr) 2913 2393 yz155240 return NULL; 2914 2393 yz155240 2915 0 stevel p = oip->ip_p; 2916 0 stevel if (p == IPPROTO_TCP) 2917 0 stevel flags = IPN_TCP; 2918 0 stevel else if (p == IPPROTO_UDP) 2919 0 stevel flags = IPN_UDP; 2920 0 stevel else if (p == IPPROTO_ICMP) { 2921 0 stevel orgicmp = (icmphdr_t *)((char *)oip + (IP_HL(oip) << 2)); 2922 0 stevel 2923 0 stevel /* see if this is related to an ICMP query */ 2924 0 stevel if (nat_icmpquerytype4(orgicmp->icmp_type)) { 2925 2393 yz155240 data[0] = fin->fin_data[0]; 2926 2393 yz155240 data[1] = fin->fin_data[1]; 2927 2393 yz155240 fin->fin_data[0] = 0; 2928 2393 yz155240 fin->fin_data[1] = orgicmp->icmp_id; 2929 2393 yz155240 2930 2393 yz155240 flags = IPN_ICMPERR|IPN_ICMPQUERY; 2931 0 stevel /* 2932 0 stevel * NOTE : dir refers to the direction of the original 2933 0 stevel * ip packet. By definition the icmp error 2934 0 stevel * message flows in the opposite direction. 2935 0 stevel */ 2936 0 stevel if (dir == NAT_INBOUND) 2937 2393 yz155240 nat = nat_inlookup(fin, flags, p, oip->ip_dst, 2938 2393 yz155240 oip->ip_src); 2939 2393 yz155240 else 2940 2393 yz155240 nat = nat_outlookup(fin, flags, p, oip->ip_dst, 2941 0 stevel oip->ip_src); 2942 2393 yz155240 fin->fin_data[0] = data[0]; 2943 2393 yz155240 fin->fin_data[1] = data[1]; 2944 2393 yz155240 return nat; 2945 0 stevel } 2946 0 stevel } 2947 0 stevel 2948 0 stevel if (flags & IPN_TCPUDP) { 2949 0 stevel minlen += 8; /* + 64bits of data to get ports */ 2950 0 stevel if (fin->fin_plen < ICMPERR_IPICMPHLEN + minlen) 2951 0 stevel return NULL; 2952 0 stevel 2953 0 stevel data[0] = fin->fin_data[0]; 2954 0 stevel data[1] = fin->fin_data[1]; 2955 0 stevel tcp = (tcphdr_t *)((char *)oip + (IP_HL(oip) << 2)); 2956 0 stevel fin->fin_data[0] = ntohs(tcp->th_dport); 2957 0 stevel fin->fin_data[1] = ntohs(tcp->th_sport); 2958 0 stevel 2959 0 stevel if (dir == NAT_INBOUND) { 2960 0 stevel nat = nat_inlookup(fin, flags, p, oip->ip_dst, 2961 0 stevel oip->ip_src); 2962 0 stevel } else { 2963 0 stevel nat = nat_outlookup(fin, flags, p, oip->ip_dst, 2964 0 stevel oip->ip_src); 2965 0 stevel } 2966 0 stevel fin->fin_data[0] = data[0]; 2967 0 stevel fin->fin_data[1] = data[1]; 2968 0 stevel return nat; 2969 0 stevel } 2970 0 stevel if (dir == NAT_INBOUND) 2971 0 stevel return nat_inlookup(fin, 0, p, oip->ip_dst, oip->ip_src); 2972 0 stevel else 2973 0 stevel return nat_outlookup(fin, 0, p, oip->ip_dst, oip->ip_src); 2974 0 stevel } 2975 0 stevel 2976 0 stevel 2977 0 stevel /* ------------------------------------------------------------------------ */ 2978 0 stevel /* Function: nat_icmperror */ 2979 0 stevel /* Returns: nat_t* - point to matching NAT structure */ 2980 0 stevel /* Parameters: fin(I) - pointer to packet information */ 2981 0