1 /* $NetBSD: ip_nat.c,v 1.27 2024/09/08 09:36:51 rillig Exp $ */ 2 3 /* 4 * Copyright (C) 2012 by Darren Reed. 5 * 6 * See the IPFILTER.LICENCE file for details on licencing. 7 */ 8 #if defined(KERNEL) || defined(_KERNEL) 9 # undef KERNEL 10 # undef KERNEL 11 # define KERNEL 1 12 # define KERNEL 1 13 #endif 14 #include <sys/errno.h> 15 #include <sys/types.h> 16 #include <sys/param.h> 17 #include <sys/time.h> 18 #include <sys/file.h> 19 #if defined(_KERNEL) && \ 20 (defined(__NetBSD_Version) && (__NetBSD_Version >= 399002000)) 21 # include <sys/kauth.h> 22 #endif 23 #if !defined(_KERNEL) 24 # include <stdio.h> 25 # include <string.h> 26 # include <stdlib.h> 27 # define KERNEL 28 # ifdef _OpenBSD__ 29 struct file; 30 # endif 31 # include <sys/uio.h> 32 # undef KERNEL 33 #endif 34 #if defined(_KERNEL) && \ 35 defined(__FreeBSD_version) && (__FreeBSD_version >= 220000) 36 # include <sys/filio.h> 37 # include <sys/fcntl.h> 38 #else 39 # include <sys/ioctl.h> 40 #endif 41 #if !defined(AIX) 42 # include <sys/fcntl.h> 43 #endif 44 #if !defined(linux) 45 # include <sys/protosw.h> 46 #endif 47 #include <sys/socket.h> 48 #if defined(_KERNEL) 49 # include <sys/systm.h> 50 # if !defined(__SVR4) && !defined(__svr4__) 51 # include <sys/mbuf.h> 52 # endif 53 #endif 54 #if defined(__SVR4) || defined(__svr4__) 55 # include <sys/filio.h> 56 # include <sys/byteorder.h> 57 # ifdef KERNEL 58 # include <sys/dditypes.h> 59 # endif 60 # include <sys/stream.h> 61 # include <sys/kmem.h> 62 #endif 63 #if _FreeBSD_version >= 300000 64 # include <sys/queue.h> 65 #endif 66 #include <net/if.h> 67 #if _FreeBSD_version >= 300000 68 # include <net/if_var.h> 69 #endif 70 #ifdef sun 71 # include <net/af.h> 72 #endif 73 #include <netinet/in.h> 74 #include <netinet/in_systm.h> 75 #include <netinet/ip.h> 76 77 #ifdef RFC1825 78 # include <vpn/md5.h> 79 # include <vpn/ipsec.h> 80 extern struct ifnet vpnif; 81 #endif 82 83 #if !defined(linux) 84 # include <netinet/ip_var.h> 85 #endif 86 #include <netinet/tcp.h> 87 #include <netinet/udp.h> 88 #include <netinet/ip_icmp.h> 89 #include "netinet/ip_compat.h" 90 #include "netinet/ipl.h" 91 #include "netinet/ip_fil.h" 92 #include "netinet/ip_nat.h" 93 #include "netinet/ip_frag.h" 94 #include "netinet/ip_state.h" 95 #include "netinet/ip_proxy.h" 96 #include "netinet/ip_lookup.h" 97 #include "netinet/ip_dstlist.h" 98 #include "netinet/ip_sync.h" 99 #if FREEBSD_GE_REV(300000) 100 # include <sys/malloc.h> 101 #endif 102 #ifdef HAS_SYS_MD5_H 103 # include <sys/md5.h> 104 #else 105 # include "md5.h" 106 #endif 107 /* END OF INCLUDES */ 108 109 #undef SOCKADDR_IN 110 #define SOCKADDR_IN struct sockaddr_in 111 112 #if !defined(lint) 113 #if defined(__NetBSD__) 114 #include <sys/cdefs.h> 115 __KERNEL_RCSID(0, "$NetBSD: ip_nat.c,v 1.27 2024/09/08 09:36:51 rillig Exp $"); 116 #else 117 static const char sccsid[] = "@(#)ip_nat.c 1.11 6/5/96 (C) 1995 Darren Reed"; 118 static const char rcsid[] = "@(#)Id: ip_nat.c,v 1.1.1.2 2012/07/22 13:45:27 darrenr Exp"; 119 #endif 120 #endif 121 122 123 #define NATFSUM(n,v,f) ((v) == 4 ? (n)->f.in4.s_addr : (n)->f.i6[0] + \ 124 (n)->f.i6[1] + (n)->f.i6[2] + (n)->f.i6[3]) 125 #define NBUMP(x) softn->(x)++ 126 #define NBUMPD(x, y) do { \ 127 softn->x.y++; \ 128 DT(y); \ 129 } while (0) 130 #define NBUMPSIDE(y,x) softn->ipf_nat_stats.ns_side[y].x++ 131 #define NBUMPSIDED(y,x) do { softn->ipf_nat_stats.ns_side[y].x++; \ 132 DT(x); } while (0) 133 #define NBUMPSIDEX(y,x,z) \ 134 do { softn->ipf_nat_stats.ns_side[y].x++; \ 135 DT(z); } while (0) 136 #define NBUMPSIDEDF(y,x)do { softn->ipf_nat_stats.ns_side[y].x++; \ 137 DT1(x, fr_info_t *, fin); } while (0) 138 139 frentry_t ipfnatblock; 140 141 static const ipftuneable_t ipf_nat_tuneables[] = { 142 /* nat */ 143 { { (void *)offsetof(ipf_nat_softc_t, ipf_nat_lock) }, 144 "nat_lock", 0, 1, 145 stsizeof(ipf_nat_softc_t, ipf_nat_lock), 146 IPFT_RDONLY, NULL, NULL }, 147 { { (void *)offsetof(ipf_nat_softc_t, ipf_nat_table_sz) }, 148 "nat_table_size", 1, 0x7fffffff, 149 stsizeof(ipf_nat_softc_t, ipf_nat_table_sz), 150 0, NULL, ipf_nat_rehash }, 151 { { (void *)offsetof(ipf_nat_softc_t, ipf_nat_table_max) }, 152 "nat_table_max", 1, 0x7fffffff, 153 stsizeof(ipf_nat_softc_t, ipf_nat_table_max), 154 0, NULL, NULL }, 155 { { (void *)offsetof(ipf_nat_softc_t, ipf_nat_maprules_sz) }, 156 "nat_rules_size", 1, 0x7fffffff, 157 stsizeof(ipf_nat_softc_t, ipf_nat_maprules_sz), 158 0, NULL, ipf_nat_rehash_rules }, 159 { { (void *)offsetof(ipf_nat_softc_t, ipf_nat_rdrrules_sz) }, 160 "rdr_rules_size", 1, 0x7fffffff, 161 stsizeof(ipf_nat_softc_t, ipf_nat_rdrrules_sz), 162 0, NULL, ipf_nat_rehash_rules }, 163 { { (void *)offsetof(ipf_nat_softc_t, ipf_nat_hostmap_sz) }, 164 "hostmap_size", 1, 0x7fffffff, 165 stsizeof(ipf_nat_softc_t, ipf_nat_hostmap_sz), 166 0, NULL, ipf_nat_hostmap_rehash }, 167 { { (void *)offsetof(ipf_nat_softc_t, ipf_nat_maxbucket) }, 168 "nat_maxbucket",1, 0x7fffffff, 169 stsizeof(ipf_nat_softc_t, ipf_nat_maxbucket), 170 0, NULL, NULL }, 171 { { (void *)offsetof(ipf_nat_softc_t, ipf_nat_logging) }, 172 "nat_logging", 0, 1, 173 stsizeof(ipf_nat_softc_t, ipf_nat_logging), 174 0, NULL, NULL }, 175 { { (void *)offsetof(ipf_nat_softc_t, ipf_nat_doflush) }, 176 "nat_doflush", 0, 1, 177 stsizeof(ipf_nat_softc_t, ipf_nat_doflush), 178 0, NULL, NULL }, 179 { { (void *)offsetof(ipf_nat_softc_t, ipf_nat_table_wm_low) }, 180 "nat_table_wm_low", 1, 99, 181 stsizeof(ipf_nat_softc_t, ipf_nat_table_wm_low), 182 0, NULL, NULL }, 183 { { (void *)offsetof(ipf_nat_softc_t, ipf_nat_table_wm_high) }, 184 "nat_table_wm_high", 2, 100, 185 stsizeof(ipf_nat_softc_t, ipf_nat_table_wm_high), 186 0, NULL, NULL }, 187 { { 0 }, 188 NULL, 0, 0, 189 0, 190 0, NULL, NULL } 191 }; 192 193 /* ======================================================================== */ 194 /* How the NAT is organised and works. */ 195 /* */ 196 /* Inside (interface y) NAT Outside (interface x) */ 197 /* -------------------- -+- ------------------------------------- */ 198 /* Packet going | out, processsed by ipf_nat_checkout() for x */ 199 /* ------------> | ------------> */ 200 /* src=10.1.1.1 | src=192.1.1.1 */ 201 /* | */ 202 /* | in, processed by ipf_nat_checkin() for x */ 203 /* <------------ | <------------ */ 204 /* dst=10.1.1.1 | dst=192.1.1.1 */ 205 /* -------------------- -+- ------------------------------------- */ 206 /* ipf_nat_checkout() - changes ip_src and if required, sport */ 207 /* - creates a new mapping, if required. */ 208 /* ipf_nat_checkin() - changes ip_dst and if required, dport */ 209 /* */ 210 /* In the NAT table, internal source is recorded as "in" and externally */ 211 /* seen as "out". */ 212 /* ======================================================================== */ 213 214 215 #if SOLARIS && !defined(INSTANCES) 216 extern int pfil_delayed_copy; 217 #endif 218 219 static int ipf_nat_flush_entry(ipf_main_softc_t *, void *); 220 static int ipf_nat_getent(ipf_main_softc_t *, void *, int); 221 static int ipf_nat_getsz(ipf_main_softc_t *, void *, int); 222 static int ipf_nat_putent(ipf_main_softc_t *, void *, int); 223 static void ipf_nat_addmap(ipf_nat_softc_t *, ipnat_t *); 224 static void ipf_nat_addrdr(ipf_nat_softc_t *, ipnat_t *); 225 static int ipf_nat_builddivertmp(ipf_nat_softc_t *, ipnat_t *); 226 static int ipf_nat_clearlist(ipf_main_softc_t *, ipf_nat_softc_t *); 227 static int ipf_nat_cmp_rules(ipnat_t *, ipnat_t *); 228 static int ipf_nat_decap(fr_info_t *, nat_t *); 229 static void ipf_nat_delrule(ipf_main_softc_t *, ipf_nat_softc_t *, 230 ipnat_t *, int); 231 static int ipf_nat_extraflush(ipf_main_softc_t *, ipf_nat_softc_t *, int); 232 static int ipf_nat_finalise(fr_info_t *, nat_t *); 233 static int ipf_nat_flushtable(ipf_main_softc_t *, ipf_nat_softc_t *); 234 static int ipf_nat_getnext(ipf_main_softc_t *, ipftoken_t *, 235 ipfgeniter_t *, ipfobj_t *); 236 static int ipf_nat_gettable(ipf_main_softc_t *, ipf_nat_softc_t *, char *); 237 static hostmap_t *ipf_nat_hostmap(ipf_nat_softc_t *, ipnat_t *, 238 struct in_addr, struct in_addr, 239 struct in_addr, u_32_t); 240 static int ipf_nat_icmpquerytype(int); 241 static int ipf_nat_iterator(ipf_main_softc_t *, ipftoken_t *, 242 ipfgeniter_t *, ipfobj_t *); 243 static int ipf_nat_match(fr_info_t *, ipnat_t *); 244 static int ipf_nat_matcharray(nat_t *, int *, u_long); 245 static int ipf_nat_matchflush(ipf_main_softc_t *, ipf_nat_softc_t *, 246 void *); 247 static void ipf_nat_mssclamp(tcphdr_t *, u_32_t, fr_info_t *, u_short *); 248 static int ipf_nat_newmap(fr_info_t *, nat_t *, natinfo_t *); 249 static int ipf_nat_newdivert(fr_info_t *, nat_t *, natinfo_t *); 250 static int ipf_nat_newrdr(fr_info_t *, nat_t *, natinfo_t *); 251 static int ipf_nat_newrewrite(fr_info_t *, nat_t *, natinfo_t *); 252 static int ipf_nat_nextaddr(fr_info_t *, nat_addr_t *, u_32_t *, u_32_t *); 253 static int ipf_nat_nextaddrinit(ipf_main_softc_t *, char *, 254 nat_addr_t *, int, void *); 255 static int ipf_nat_resolverule(ipf_main_softc_t *, ipnat_t *); 256 static int ipf_nat_ruleaddrinit(ipf_main_softc_t *, 257 ipf_nat_softc_t *, ipnat_t *); 258 static void ipf_nat_rule_fini(ipf_main_softc_t *, ipnat_t *); 259 static int ipf_nat_rule_init(ipf_main_softc_t *, ipf_nat_softc_t *, 260 ipnat_t *); 261 static int ipf_nat_siocaddnat(ipf_main_softc_t *, ipf_nat_softc_t *, 262 ipnat_t *, int); 263 static void ipf_nat_siocdelnat(ipf_main_softc_t *, ipf_nat_softc_t *, 264 ipnat_t *, int); 265 static void ipf_nat_tabmove(ipf_nat_softc_t *, nat_t *); 266 267 /* ------------------------------------------------------------------------ */ 268 /* Function: ipf_nat_main_load */ 269 /* Returns: int - 0 == success, -1 == failure */ 270 /* Parameters: Nil */ 271 /* */ 272 /* The only global NAT structure that needs to be initialised is the filter */ 273 /* rule that is used with blocking packets. */ 274 /* ------------------------------------------------------------------------ */ 275 int 276 ipf_nat_main_load(void) 277 { 278 bzero((char *)&ipfnatblock, sizeof(ipfnatblock)); 279 ipfnatblock.fr_flags = FR_BLOCK|FR_QUICK; 280 ipfnatblock.fr_ref = 1; 281 282 return 0; 283 } 284 285 286 /* ------------------------------------------------------------------------ */ 287 /* Function: ipf_nat_main_unload */ 288 /* Returns: int - 0 == success, -1 == failure */ 289 /* Parameters: Nil */ 290 /* */ 291 /* A null-op function that exists as a placeholder so that the flow in */ 292 /* other functions is obvious. */ 293 /* ------------------------------------------------------------------------ */ 294 int 295 ipf_nat_main_unload(void) 296 { 297 return 0; 298 } 299 300 301 /* ------------------------------------------------------------------------ */ 302 /* Function: ipf_nat_soft_create */ 303 /* Returns: void * - NULL = failure, else pointer to NAT context */ 304 /* Parameters: softc(I) - pointer to soft context main structure */ 305 /* */ 306 /* Allocate the initial soft context structure for NAT and populate it with */ 307 /* some default values. Creating the tables is left until we call _init so */ 308 /* that sizes can be changed before we get under way. */ 309 /* ------------------------------------------------------------------------ */ 310 void * 311 ipf_nat_soft_create(ipf_main_softc_t *softc) 312 { 313 ipf_nat_softc_t *softn; 314 315 KMALLOC(softn, ipf_nat_softc_t *); 316 if (softn == NULL) 317 return NULL; 318 319 bzero((char *)softn, sizeof(*softn)); 320 321 softn->ipf_nat_tune = ipf_tune_array_copy(softn, 322 sizeof(ipf_nat_tuneables), 323 ipf_nat_tuneables); 324 if (softn->ipf_nat_tune == NULL) { 325 ipf_nat_soft_destroy(softc, softn); 326 return NULL; 327 } 328 if (ipf_tune_array_link(softc, softn->ipf_nat_tune) == -1) { 329 ipf_nat_soft_destroy(softc, softn); 330 return NULL; 331 } 332 333 softn->ipf_nat_list_tail = &softn->ipf_nat_list; 334 335 softn->ipf_nat_table_max = NAT_TABLE_MAX; 336 softn->ipf_nat_table_sz = NAT_TABLE_SZ; 337 softn->ipf_nat_maprules_sz = NAT_SIZE; 338 softn->ipf_nat_rdrrules_sz = RDR_SIZE; 339 softn->ipf_nat_hostmap_sz = HOSTMAP_SIZE; 340 softn->ipf_nat_doflush = 0; 341 #ifdef IPFILTER_LOG 342 softn->ipf_nat_logging = 1; 343 #else 344 softn->ipf_nat_logging = 0; 345 #endif 346 347 softn->ipf_nat_defage = DEF_NAT_AGE; 348 softn->ipf_nat_defipage = IPF_TTLVAL(60); 349 softn->ipf_nat_deficmpage = IPF_TTLVAL(3); 350 softn->ipf_nat_table_wm_high = 99; 351 softn->ipf_nat_table_wm_low = 90; 352 353 return softn; 354 } 355 356 /* ------------------------------------------------------------------------ */ 357 /* Function: ipf_nat_soft_destroy */ 358 /* Returns: Nil */ 359 /* Parameters: softc(I) - pointer to soft context main structure */ 360 /* */ 361 /* ------------------------------------------------------------------------ */ 362 void 363 ipf_nat_soft_destroy(ipf_main_softc_t *softc, void *arg) 364 { 365 ipf_nat_softc_t *softn = arg; 366 367 if (softn->ipf_nat_tune != NULL) { 368 ipf_tune_array_unlink(softc, softn->ipf_nat_tune); 369 KFREES(softn->ipf_nat_tune, sizeof(ipf_nat_tuneables)); 370 softn->ipf_nat_tune = NULL; 371 } 372 373 KFREE(softn); 374 } 375 376 377 /* ------------------------------------------------------------------------ */ 378 /* Function: ipf_nat_init */ 379 /* Returns: int - 0 == success, -1 == failure */ 380 /* Parameters: softc(I) - pointer to soft context main structure */ 381 /* */ 382 /* Initialise all of the NAT locks, tables and other structures. */ 383 /* ------------------------------------------------------------------------ */ 384 int 385 ipf_nat_soft_init(ipf_main_softc_t *softc, void *arg) 386 { 387 ipf_nat_softc_t *softn = arg; 388 ipftq_t *tq; 389 int i; 390 391 KMALLOCS(softn->ipf_nat_table[0], nat_t **, \ 392 sizeof(nat_t *) * softn->ipf_nat_table_sz); 393 394 if (softn->ipf_nat_table[0] != NULL) { 395 bzero((char *)softn->ipf_nat_table[0], 396 softn->ipf_nat_table_sz * sizeof(nat_t *)); 397 } else { 398 return -1; 399 } 400 401 KMALLOCS(softn->ipf_nat_table[1], nat_t **, \ 402 sizeof(nat_t *) * softn->ipf_nat_table_sz); 403 404 if (softn->ipf_nat_table[1] != NULL) { 405 bzero((char *)softn->ipf_nat_table[1], 406 softn->ipf_nat_table_sz * sizeof(nat_t *)); 407 } else { 408 return -2; 409 } 410 411 KMALLOCS(softn->ipf_nat_map_rules, ipnat_t **, \ 412 sizeof(ipnat_t *) * softn->ipf_nat_maprules_sz); 413 414 if (softn->ipf_nat_map_rules != NULL) { 415 bzero((char *)softn->ipf_nat_map_rules, 416 softn->ipf_nat_maprules_sz * sizeof(ipnat_t *)); 417 } else { 418 return -3; 419 } 420 421 KMALLOCS(softn->ipf_nat_rdr_rules, ipnat_t **, \ 422 sizeof(ipnat_t *) * softn->ipf_nat_rdrrules_sz); 423 424 if (softn->ipf_nat_rdr_rules != NULL) { 425 bzero((char *)softn->ipf_nat_rdr_rules, 426 softn->ipf_nat_rdrrules_sz * sizeof(ipnat_t *)); 427 } else { 428 return -4; 429 } 430 431 KMALLOCS(softn->ipf_hm_maptable, hostmap_t **, \ 432 sizeof(hostmap_t *) * softn->ipf_nat_hostmap_sz); 433 434 if (softn->ipf_hm_maptable != NULL) { 435 bzero((char *)softn->ipf_hm_maptable, 436 sizeof(hostmap_t *) * softn->ipf_nat_hostmap_sz); 437 } else { 438 return -5; 439 } 440 softn->ipf_hm_maplist = NULL; 441 442 KMALLOCS(softn->ipf_nat_stats.ns_side[0].ns_bucketlen, u_int *, 443 softn->ipf_nat_table_sz * sizeof(u_int)); 444 445 if (softn->ipf_nat_stats.ns_side[0].ns_bucketlen == NULL) { 446 return -6; 447 } 448 bzero((char *)softn->ipf_nat_stats.ns_side[0].ns_bucketlen, 449 softn->ipf_nat_table_sz * sizeof(u_int)); 450 451 KMALLOCS(softn->ipf_nat_stats.ns_side[1].ns_bucketlen, u_int *, 452 softn->ipf_nat_table_sz * sizeof(u_int)); 453 454 if (softn->ipf_nat_stats.ns_side[1].ns_bucketlen == NULL) { 455 return -7; 456 } 457 458 bzero((char *)softn->ipf_nat_stats.ns_side[1].ns_bucketlen, 459 softn->ipf_nat_table_sz * sizeof(u_int)); 460 461 if (softn->ipf_nat_maxbucket == 0) { 462 for (i = softn->ipf_nat_table_sz; i > 0; i >>= 1) 463 softn->ipf_nat_maxbucket++; 464 softn->ipf_nat_maxbucket *= 2; 465 } 466 467 ipf_sttab_init(softc, softn->ipf_nat_tcptq); 468 /* 469 * Increase this because we may have "keep state" following this too 470 * and packet storms can occur if this is removed too quickly. 471 */ 472 softn->ipf_nat_tcptq[IPF_TCPS_CLOSED].ifq_ttl = softc->ipf_tcplastack; 473 softn->ipf_nat_tcptq[IPF_TCP_NSTATES - 1].ifq_next = 474 &softn->ipf_nat_udptq; 475 476 IPFTQ_INIT(&softn->ipf_nat_udptq, softn->ipf_nat_defage, 477 "nat ipftq udp tab"); 478 softn->ipf_nat_udptq.ifq_next = &softn->ipf_nat_udpacktq; 479 480 IPFTQ_INIT(&softn->ipf_nat_udpacktq, softn->ipf_nat_defage, 481 "nat ipftq udpack tab"); 482 softn->ipf_nat_udpacktq.ifq_next = &softn->ipf_nat_icmptq; 483 484 IPFTQ_INIT(&softn->ipf_nat_icmptq, softn->ipf_nat_deficmpage, 485 "nat icmp ipftq tab"); 486 softn->ipf_nat_icmptq.ifq_next = &softn->ipf_nat_icmpacktq; 487 488 IPFTQ_INIT(&softn->ipf_nat_icmpacktq, softn->ipf_nat_defage, 489 "nat icmpack ipftq tab"); 490 softn->ipf_nat_icmpacktq.ifq_next = &softn->ipf_nat_iptq; 491 492 IPFTQ_INIT(&softn->ipf_nat_iptq, softn->ipf_nat_defipage, 493 "nat ip ipftq tab"); 494 softn->ipf_nat_iptq.ifq_next = &softn->ipf_nat_pending; 495 496 IPFTQ_INIT(&softn->ipf_nat_pending, 1, "nat pending ipftq tab"); 497 softn->ipf_nat_pending.ifq_next = NULL; 498 499 for (i = 0, tq = softn->ipf_nat_tcptq; i < IPF_TCP_NSTATES; i++, tq++) { 500 if (tq->ifq_ttl < softn->ipf_nat_deficmpage) 501 tq->ifq_ttl = softn->ipf_nat_deficmpage; 502 #ifdef LARGE_NAT 503 else if (tq->ifq_ttl > softn->ipf_nat_defage) 504 tq->ifq_ttl = softn->ipf_nat_defage; 505 #endif 506 } 507 508 /* 509 * Increase this because we may have "keep state" following 510 * this too and packet storms can occur if this is removed 511 * too quickly. 512 */ 513 softn->ipf_nat_tcptq[IPF_TCPS_CLOSED].ifq_ttl = softc->ipf_tcplastack; 514 515 MUTEX_INIT(&softn->ipf_nat_new, "ipf nat new mutex"); 516 MUTEX_INIT(&softn->ipf_nat_io, "ipf nat io mutex"); 517 518 softn->ipf_nat_inited = 1; 519 520 return 0; 521 } 522 523 524 /* ------------------------------------------------------------------------ */ 525 /* Function: ipf_nat_soft_fini */ 526 /* Returns: Nil */ 527 /* Parameters: softc(I) - pointer to soft context main structure */ 528 /* */ 529 /* Free all memory used by NAT structures allocated at runtime. */ 530 /* ------------------------------------------------------------------------ */ 531 int 532 ipf_nat_soft_fini(ipf_main_softc_t *softc, void *arg) 533 { 534 ipf_nat_softc_t *softn = arg; 535 ipftq_t *ifq, *ifqnext; 536 537 (void) ipf_nat_clearlist(softc, softn); 538 (void) ipf_nat_flushtable(softc, softn); 539 540 /* 541 * Proxy timeout queues are not cleaned here because although they 542 * exist on the NAT list, ipf_proxy_unload is called after unload 543 * and the proxies actually are responsible for them being created. 544 * Should the proxy timeouts have their own list? There's no real 545 * justification as this is the only complication. 546 */ 547 for (ifq = softn->ipf_nat_utqe; ifq != NULL; ifq = ifqnext) { 548 ifqnext = ifq->ifq_next; 549 if (ipf_deletetimeoutqueue(ifq) == 0) 550 ipf_freetimeoutqueue(softc, ifq); 551 } 552 553 if (softn->ipf_nat_table[0] != NULL) { 554 KFREES(softn->ipf_nat_table[0], 555 sizeof(nat_t *) * softn->ipf_nat_table_sz); 556 softn->ipf_nat_table[0] = NULL; 557 } 558 if (softn->ipf_nat_table[1] != NULL) { 559 KFREES(softn->ipf_nat_table[1], 560 sizeof(nat_t *) * softn->ipf_nat_table_sz); 561 softn->ipf_nat_table[1] = NULL; 562 } 563 if (softn->ipf_nat_map_rules != NULL) { 564 KFREES(softn->ipf_nat_map_rules, 565 sizeof(ipnat_t *) * softn->ipf_nat_maprules_sz); 566 softn->ipf_nat_map_rules = NULL; 567 } 568 if (softn->ipf_nat_rdr_rules != NULL) { 569 KFREES(softn->ipf_nat_rdr_rules, 570 sizeof(ipnat_t *) * softn->ipf_nat_rdrrules_sz); 571 softn->ipf_nat_rdr_rules = NULL; 572 } 573 if (softn->ipf_hm_maptable != NULL) { 574 KFREES(softn->ipf_hm_maptable, 575 sizeof(hostmap_t *) * softn->ipf_nat_hostmap_sz); 576 softn->ipf_hm_maptable = NULL; 577 } 578 if (softn->ipf_nat_stats.ns_side[0].ns_bucketlen != NULL) { 579 KFREES(softn->ipf_nat_stats.ns_side[0].ns_bucketlen, 580 sizeof(u_int) * softn->ipf_nat_table_sz); 581 softn->ipf_nat_stats.ns_side[0].ns_bucketlen = NULL; 582 } 583 if (softn->ipf_nat_stats.ns_side[1].ns_bucketlen != NULL) { 584 KFREES(softn->ipf_nat_stats.ns_side[1].ns_bucketlen, 585 sizeof(u_int) * softn->ipf_nat_table_sz); 586 softn->ipf_nat_stats.ns_side[1].ns_bucketlen = NULL; 587 } 588 589 if (softn->ipf_nat_inited == 1) { 590 softn->ipf_nat_inited = 0; 591 ipf_sttab_destroy(softn->ipf_nat_tcptq); 592 593 MUTEX_DESTROY(&softn->ipf_nat_new); 594 MUTEX_DESTROY(&softn->ipf_nat_io); 595 596 MUTEX_DESTROY(&softn->ipf_nat_udptq.ifq_lock); 597 MUTEX_DESTROY(&softn->ipf_nat_udpacktq.ifq_lock); 598 MUTEX_DESTROY(&softn->ipf_nat_icmptq.ifq_lock); 599 MUTEX_DESTROY(&softn->ipf_nat_icmpacktq.ifq_lock); 600 MUTEX_DESTROY(&softn->ipf_nat_iptq.ifq_lock); 601 MUTEX_DESTROY(&softn->ipf_nat_pending.ifq_lock); 602 } 603 604 return 0; 605 } 606 607 608 /* ------------------------------------------------------------------------ */ 609 /* Function: ipf_nat_setlock */ 610 /* Returns: Nil */ 611 /* Parameters: arg(I) - pointer to soft state information */ 612 /* tmp(I) - new lock value */ 613 /* */ 614 /* Set the "lock status" of NAT to the value in tmp. */ 615 /* ------------------------------------------------------------------------ */ 616 void 617 ipf_nat_setlock(void *arg, int tmp) 618 { 619 ipf_nat_softc_t *softn = arg; 620 621 softn->ipf_nat_lock = tmp; 622 } 623 624 625 /* ------------------------------------------------------------------------ */ 626 /* Function: ipf_nat_addrdr */ 627 /* Returns: Nil */ 628 /* Parameters: n(I) - pointer to NAT rule to add */ 629 /* */ 630 /* Adds a redirect rule to the hash table of redirect rules and the list of */ 631 /* loaded NAT rules. Updates the bitmask indicating which netmasks are in */ 632 /* use by redirect rules. */ 633 /* ------------------------------------------------------------------------ */ 634 static void 635 ipf_nat_addrdr(ipf_nat_softc_t *softn, ipnat_t *n) 636 { 637 ipnat_t **np; 638 u_32_t j; 639 u_int hv; 640 u_int rhv; 641 int k; 642 643 if (n->in_odstatype == FRI_NORMAL) { 644 k = count4bits(n->in_odstmsk); 645 ipf_inet_mask_add(k, &softn->ipf_nat_rdr_mask); 646 j = (n->in_odstaddr & n->in_odstmsk); 647 rhv = NAT_HASH_FN(j, 0, 0xffffffff); 648 } else { 649 ipf_inet_mask_add(0, &softn->ipf_nat_rdr_mask); 650 j = 0; 651 rhv = 0; 652 } 653 hv = rhv % softn->ipf_nat_rdrrules_sz; 654 np = softn->ipf_nat_rdr_rules + hv; 655 while (*np != NULL) 656 np = &(*np)->in_rnext; 657 n->in_rnext = NULL; 658 n->in_prnext = np; 659 n->in_hv[0] = hv; 660 n->in_use++; 661 *np = n; 662 } 663 664 665 /* ------------------------------------------------------------------------ */ 666 /* Function: ipf_nat_addmap */ 667 /* Returns: Nil */ 668 /* Parameters: n(I) - pointer to NAT rule to add */ 669 /* */ 670 /* Adds a NAT map rule to the hash table of rules and the list of loaded */ 671 /* NAT rules. Updates the bitmask indicating which netmasks are in use by */ 672 /* redirect rules. */ 673 /* ------------------------------------------------------------------------ */ 674 static void 675 ipf_nat_addmap(ipf_nat_softc_t *softn, ipnat_t *n) 676 { 677 ipnat_t **np; 678 u_32_t j; 679 u_int hv; 680 u_int rhv; 681 int k; 682 683 if (n->in_osrcatype == FRI_NORMAL) { 684 k = count4bits(n->in_osrcmsk); 685 ipf_inet_mask_add(k, &softn->ipf_nat_map_mask); 686 j = (n->in_osrcaddr & n->in_osrcmsk); 687 rhv = NAT_HASH_FN(j, 0, 0xffffffff); 688 } else { 689 ipf_inet_mask_add(0, &softn->ipf_nat_map_mask); 690 j = 0; 691 rhv = 0; 692 } 693 hv = rhv % softn->ipf_nat_maprules_sz; 694 np = softn->ipf_nat_map_rules + hv; 695 while (*np != NULL) 696 np = &(*np)->in_mnext; 697 n->in_mnext = NULL; 698 n->in_pmnext = np; 699 n->in_hv[1] = rhv; 700 n->in_use++; 701 *np = n; 702 } 703 704 705 /* ------------------------------------------------------------------------ */ 706 /* Function: ipf_nat_delrdr */ 707 /* Returns: Nil */ 708 /* Parameters: n(I) - pointer to NAT rule to delete */ 709 /* */ 710 /* Removes a redirect rule from the hash table of redirect rules. */ 711 /* ------------------------------------------------------------------------ */ 712 void 713 ipf_nat_delrdr(ipf_nat_softc_t *softn, ipnat_t *n) 714 { 715 if (n->in_odstatype == FRI_NORMAL) { 716 int k = count4bits(n->in_odstmsk); 717 ipf_inet_mask_del(k, &softn->ipf_nat_rdr_mask); 718 } else { 719 ipf_inet_mask_del(0, &softn->ipf_nat_rdr_mask); 720 } 721 if (n->in_rnext) 722 n->in_rnext->in_prnext = n->in_prnext; 723 *n->in_prnext = n->in_rnext; 724 n->in_use--; 725 } 726 727 728 /* ------------------------------------------------------------------------ */ 729 /* Function: ipf_nat_delmap */ 730 /* Returns: Nil */ 731 /* Parameters: n(I) - pointer to NAT rule to delete */ 732 /* */ 733 /* Removes a NAT map rule from the hash table of NAT map rules. */ 734 /* ------------------------------------------------------------------------ */ 735 void 736 ipf_nat_delmap(ipf_nat_softc_t *softn, ipnat_t *n) 737 { 738 if (n->in_osrcatype == FRI_NORMAL) { 739 int k = count4bits(n->in_osrcmsk); 740 ipf_inet_mask_del(k, &softn->ipf_nat_map_mask); 741 } else { 742 ipf_inet_mask_del(0, &softn->ipf_nat_map_mask); 743 } 744 if (n->in_mnext != NULL) 745 n->in_mnext->in_pmnext = n->in_pmnext; 746 *n->in_pmnext = n->in_mnext; 747 n->in_use--; 748 } 749 750 751 /* ------------------------------------------------------------------------ */ 752 /* Function: ipf_nat_hostmap */ 753 /* Returns: struct hostmap* - NULL if no hostmap could be created, */ 754 /* else a pointer to the hostmapping to use */ 755 /* Parameters: np(I) - pointer to NAT rule */ 756 /* real(I) - real IP address */ 757 /* map(I) - mapped IP address */ 758 /* port(I) - destination port number */ 759 /* Write Locks: ipf_nat */ 760 /* */ 761 /* Check if an ip address has already been allocated for a given mapping */ 762 /* that is not doing port based translation. If is not yet allocated, then */ 763 /* create a new entry if a non-NULL NAT rule pointer has been supplied. */ 764 /* ------------------------------------------------------------------------ */ 765 static struct hostmap * 766 ipf_nat_hostmap(ipf_nat_softc_t *softn, ipnat_t *np, struct in_addr src, 767 struct in_addr dst, struct in_addr map, u_32_t port) 768 { 769 hostmap_t *hm; 770 u_int hv, rhv; 771 772 hv = (src.s_addr ^ dst.s_addr); 773 hv += src.s_addr; 774 hv += dst.s_addr; 775 rhv = hv; 776 hv %= softn->ipf_nat_hostmap_sz; 777 for (hm = softn->ipf_hm_maptable[hv]; hm; hm = hm->hm_hnext) 778 if ((hm->hm_osrcip.s_addr == src.s_addr) && 779 (hm->hm_odstip.s_addr == dst.s_addr) && 780 ((np == NULL) || (np == hm->hm_ipnat)) && 781 ((port == 0) || (port == hm->hm_port))) { 782 softn->ipf_nat_stats.ns_hm_addref++; 783 hm->hm_ref++; 784 return hm; 785 } 786 787 if (np == NULL) { 788 softn->ipf_nat_stats.ns_hm_nullnp++; 789 return NULL; 790 } 791 792 KMALLOC(hm, hostmap_t *); 793 if (hm) { 794 hm->hm_next = softn->ipf_hm_maplist; 795 hm->hm_pnext = &softn->ipf_hm_maplist; 796 if (softn->ipf_hm_maplist != NULL) 797 softn->ipf_hm_maplist->hm_pnext = &hm->hm_next; 798 softn->ipf_hm_maplist = hm; 799 hm->hm_hnext = softn->ipf_hm_maptable[hv]; 800 hm->hm_phnext = softn->ipf_hm_maptable + hv; 801 if (softn->ipf_hm_maptable[hv] != NULL) 802 softn->ipf_hm_maptable[hv]->hm_phnext = &hm->hm_hnext; 803 softn->ipf_hm_maptable[hv] = hm; 804 hm->hm_ipnat = np; 805 np->in_use++; 806 hm->hm_osrcip = src; 807 hm->hm_odstip = dst; 808 hm->hm_nsrcip = map; 809 hm->hm_ndstip.s_addr = 0; 810 hm->hm_ref = 1; 811 hm->hm_port = port; 812 hm->hm_hv = rhv; 813 hm->hm_v = 4; 814 softn->ipf_nat_stats.ns_hm_new++; 815 } else { 816 softn->ipf_nat_stats.ns_hm_newfail++; 817 } 818 return hm; 819 } 820 821 822 /* ------------------------------------------------------------------------ */ 823 /* Function: ipf_nat_hostmapdel */ 824 /* Returns: Nil */ 825 /* Parameters: hmp(I) - pointer to hostmap structure pointer */ 826 /* Write Locks: ipf_nat */ 827 /* */ 828 /* Decrement the references to this hostmap structure by one. If this */ 829 /* reaches zero then remove it and free it. */ 830 /* ------------------------------------------------------------------------ */ 831 void 832 ipf_nat_hostmapdel(ipf_main_softc_t *softc, struct hostmap **hmp) 833 { 834 struct hostmap *hm; 835 836 hm = *hmp; 837 *hmp = NULL; 838 839 hm->hm_ref--; 840 if (hm->hm_ref == 0) { 841 ipf_nat_rule_deref(softc, &hm->hm_ipnat); 842 if (hm->hm_hnext) 843 hm->hm_hnext->hm_phnext = hm->hm_phnext; 844 *hm->hm_phnext = hm->hm_hnext; 845 if (hm->hm_next) 846 hm->hm_next->hm_pnext = hm->hm_pnext; 847 *hm->hm_pnext = hm->hm_next; 848 KFREE(hm); 849 } 850 } 851 852 853 /* ------------------------------------------------------------------------ */ 854 /* Function: ipf_fix_outcksum */ 855 /* Returns: Nil */ 856 /* Parameters: fin(I) - pointer to packet information */ 857 /* sp(I) - location of 16bit checksum to update */ 858 /* n((I) - amount to adjust checksum by */ 859 /* */ 860 /* Adjusts the 16bit checksum by "n" for packets going out. */ 861 /* ------------------------------------------------------------------------ */ 862 void 863 ipf_fix_outcksum(int cksum, u_short *sp, u_32_t n, u_32_t partial) 864 { 865 u_short sumshort; 866 u_32_t sum1; 867 868 if (n == 0) 869 return; 870 871 if (cksum == 4) { 872 *sp = 0; 873 return; 874 } 875 if (cksum == 2) { 876 sum1 = partial; 877 sum1 = (sum1 & 0xffff) + (sum1 >> 16); 878 *sp = htons(sum1); 879 return; 880 } 881 sum1 = (~ntohs(*sp)) & 0xffff; 882 sum1 += (n); 883 sum1 = (sum1 >> 16) + (sum1 & 0xffff); 884 /* Again */ 885 sum1 = (sum1 >> 16) + (sum1 & 0xffff); 886 sumshort = ~(u_short)sum1; 887 *(sp) = htons(sumshort); 888 } 889 890 891 /* ------------------------------------------------------------------------ */ 892 /* Function: ipf_fix_incksum */ 893 /* Returns: Nil */ 894 /* Parameters: fin(I) - pointer to packet information */ 895 /* sp(I) - location of 16bit checksum to update */ 896 /* n((I) - amount to adjust checksum by */ 897 /* */ 898 /* Adjusts the 16bit checksum by "n" for packets going in. */ 899 /* ------------------------------------------------------------------------ */ 900 void 901 ipf_fix_incksum(int cksum, u_short *sp, u_32_t n, u_32_t partial) 902 { 903 u_short sumshort; 904 u_32_t sum1; 905 906 if (n == 0) 907 return; 908 909 if (cksum == 4) { 910 *sp = 0; 911 return; 912 } 913 if (cksum == 2) { 914 sum1 = partial; 915 sum1 = (sum1 & 0xffff) + (sum1 >> 16); 916 *sp = htons(sum1); 917 return; 918 } 919 920 sum1 = (~ntohs(*sp)) & 0xffff; 921 sum1 += ~(n) & 0xffff; 922 sum1 = (sum1 >> 16) + (sum1 & 0xffff); 923 /* Again */ 924 sum1 = (sum1 >> 16) + (sum1 & 0xffff); 925 sumshort = ~(u_short)sum1; 926 *(sp) = htons(sumshort); 927 } 928 929 930 /* ------------------------------------------------------------------------ */ 931 /* Function: ipf_fix_datacksum */ 932 /* Returns: Nil */ 933 /* Parameters: sp(I) - location of 16bit checksum to update */ 934 /* n((I) - amount to adjust checksum by */ 935 /* */ 936 /* Fix_datacksum is used *only* for the adjustments of checksums in the */ 937 /* data section of an IP packet. */ 938 /* */ 939 /* The only situation in which you need to do this is when NAT'ing an */ 940 /* ICMP error message. Such a message, contains in its body the IP header */ 941 /* of the original IP packet, that causes the error. */ 942 /* */ 943 /* You can't use fix_incksum or fix_outcksum in that case, because for the */ 944 /* kernel the data section of the ICMP error is just data, and no special */ 945 /* processing like hardware cksum or ntohs processing have been done by the */ 946 /* kernel on the data section. */ 947 /* ------------------------------------------------------------------------ */ 948 void 949 ipf_fix_datacksum(u_short *sp, u_32_t n) 950 { 951 u_short sumshort; 952 u_32_t sum1; 953 954 if (n == 0) 955 return; 956 957 sum1 = (~ntohs(*sp)) & 0xffff; 958 sum1 += (n); 959 sum1 = (sum1 >> 16) + (sum1 & 0xffff); 960 /* Again */ 961 sum1 = (sum1 >> 16) + (sum1 & 0xffff); 962 sumshort = ~(u_short)sum1; 963 *(sp) = htons(sumshort); 964 } 965 966 967 /* ------------------------------------------------------------------------ */ 968 /* Function: ipf_nat_ioctl */ 969 /* Returns: int - 0 == success, != 0 == failure */ 970 /* Parameters: softc(I) - pointer to soft context main structure */ 971 /* data(I) - pointer to ioctl data */ 972 /* cmd(I) - ioctl command integer */ 973 /* mode(I) - file mode bits used with open */ 974 /* uid(I) - uid of calling process */ 975 /* ctx(I) - pointer used as key for finding context */ 976 /* */ 977 /* Processes an ioctl call made to operate on the IP Filter NAT device. */ 978 /* ------------------------------------------------------------------------ */ 979 int 980 ipf_nat_ioctl(ipf_main_softc_t *softc, void *data, ioctlcmd_t cmd, int mode, 981 int uid, void *ctx) 982 { 983 ipf_nat_softc_t *softn = softc->ipf_nat_soft; 984 int error = 0, ret, arg, getlock; 985 ipnat_t *nat, *nt, *n; 986 ipnat_t *natd = NULL; 987 SPL_INT(s); 988 989 #if BSD_GE_YEAR(199306) && defined(_KERNEL) 990 # if NETBSD_GE_REV(399002000) 991 if ((mode & FWRITE) && kauth_authorize_network( 992 kauth_cred_get(), KAUTH_NETWORK_FIREWALL, 993 KAUTH_REQ_NETWORK_FIREWALL_FW, NULL, NULL, NULL)) 994 # else 995 # if defined(__FreeBSD_version) && (__FreeBSD_version >= 500034) 996 if (securelevel_ge(curthread->td_ucred, 3) && (mode & FWRITE)) 997 # else 998 if ((securelevel >= 3) && (mode & FWRITE)) 999 # endif 1000 # endif 1001 { 1002 IPFERROR(60001); 1003 return EPERM; 1004 } 1005 #endif 1006 1007 #if defined(__osf__) && defined(_KERNEL) 1008 getlock = 0; 1009 #else 1010 getlock = (mode & NAT_LOCKHELD) ? 0 : 1; 1011 #endif 1012 1013 n = NULL; 1014 nt = NULL; 1015 nat = NULL; 1016 1017 if ((cmd == (ioctlcmd_t)SIOCADNAT) || (cmd == (ioctlcmd_t)SIOCRMNAT) || 1018 (cmd == (ioctlcmd_t)SIOCPURGENAT)) { 1019 KMALLOC(natd, ipnat_t *); 1020 if (natd == NULL) { 1021 error = ENOMEM; 1022 goto done; 1023 } 1024 if (mode & NAT_SYSSPACE) { 1025 bcopy(data, natd, sizeof(*natd)); 1026 nat = natd; 1027 error = 0; 1028 } else { 1029 bzero(natd, sizeof(*natd)); 1030 error = ipf_inobj(softc, data, NULL, natd, 1031 IPFOBJ_IPNAT); 1032 if (error != 0) 1033 goto done; 1034 1035 if (natd->in_size < sizeof(ipnat_t)) { 1036 error = EINVAL; 1037 goto done; 1038 } 1039 KMALLOCS(nt, ipnat_t *, natd->in_size); 1040 if (nt == NULL) { 1041 IPFERROR(60070); 1042 error = ENOMEM; 1043 goto done; 1044 } 1045 bzero(nt, natd->in_size); 1046 error = ipf_inobjsz(softc, data, nt, IPFOBJ_IPNAT, 1047 natd->in_size); 1048 if (error) 1049 goto done; 1050 nat = nt; 1051 } 1052 1053 /* 1054 * For add/delete, look to see if the NAT entry is 1055 * already present 1056 */ 1057 nat->in_flags &= IPN_USERFLAGS; 1058 if ((nat->in_redir & NAT_MAPBLK) == 0) { 1059 if (nat->in_osrcatype == FRI_NORMAL || 1060 nat->in_osrcatype == FRI_NONE) 1061 nat->in_osrcaddr &= nat->in_osrcmsk; 1062 if (nat->in_odstatype == FRI_NORMAL || 1063 nat->in_odstatype == FRI_NONE) 1064 nat->in_odstaddr &= nat->in_odstmsk; 1065 if ((nat->in_flags & (IPN_SPLIT|IPN_SIPRANGE)) == 0) { 1066 if (nat->in_nsrcatype == FRI_NORMAL) 1067 nat->in_nsrcaddr &= nat->in_nsrcmsk; 1068 if (nat->in_ndstatype == FRI_NORMAL) 1069 nat->in_ndstaddr &= nat->in_ndstmsk; 1070 } 1071 } 1072 1073 error = ipf_nat_rule_init(softc, softn, nat); 1074 if (error != 0) 1075 goto done; 1076 1077 MUTEX_ENTER(&softn->ipf_nat_io); 1078 for (n = softn->ipf_nat_list; n != NULL; n = n->in_next) 1079 if (ipf_nat_cmp_rules(nat, n) == 0) 1080 break; 1081 } 1082 1083 switch (cmd) 1084 { 1085 #ifdef IPFILTER_LOG 1086 case SIOCIPFFB : 1087 { 1088 int tmp; 1089 1090 if (!(mode & FWRITE)) { 1091 IPFERROR(60002); 1092 error = EPERM; 1093 } else { 1094 tmp = ipf_log_clear(softc, IPL_LOGNAT); 1095 error = BCOPYOUT(&tmp, data, sizeof(tmp)); 1096 if (error != 0) { 1097 IPFERROR(60057); 1098 error = EFAULT; 1099 } 1100 } 1101 break; 1102 } 1103 1104 case SIOCSETLG : 1105 if (!(mode & FWRITE)) { 1106 IPFERROR(60003); 1107 error = EPERM; 1108 } else { 1109 error = BCOPYIN(data, &softn->ipf_nat_logging, 1110 sizeof(softn->ipf_nat_logging)); 1111 if (error != 0) 1112 error = EFAULT; 1113 } 1114 break; 1115 1116 case SIOCGETLG : 1117 error = BCOPYOUT(&softn->ipf_nat_logging, data, 1118 sizeof(softn->ipf_nat_logging)); 1119 if (error != 0) { 1120 IPFERROR(60004); 1121 error = EFAULT; 1122 } 1123 break; 1124 1125 case FIONREAD : 1126 arg = ipf_log_bytesused(softc, IPL_LOGNAT); 1127 error = BCOPYOUT(&arg, data, sizeof(arg)); 1128 if (error != 0) { 1129 IPFERROR(60005); 1130 error = EFAULT; 1131 } 1132 break; 1133 #endif 1134 case SIOCADNAT : 1135 if (!(mode & FWRITE)) { 1136 IPFERROR(60006); 1137 error = EPERM; 1138 } else if (n != NULL) { 1139 KMALLOC(natd, ipnat_t *); 1140 if (natd == NULL) { 1141 error = ENOMEM; 1142 goto done; 1143 } 1144 bzero(natd, sizeof(*natd)); 1145 natd->in_flineno = n->in_flineno; 1146 (void) ipf_outobj(softc, data, &natd, IPFOBJ_IPNAT); 1147 IPFERROR(60007); 1148 error = EEXIST; 1149 } else if (nt == NULL) { 1150 IPFERROR(60008); 1151 error = ENOMEM; 1152 } 1153 if (error != 0) { 1154 MUTEX_EXIT(&softn->ipf_nat_io); 1155 break; 1156 } 1157 if (nat != nt) 1158 bcopy((char *)nat, (char *)nt, sizeof(*n)); 1159 error = ipf_nat_siocaddnat(softc, softn, nt, getlock); 1160 MUTEX_EXIT(&softn->ipf_nat_io); 1161 if (error == 0) { 1162 nat = NULL; 1163 nt = NULL; 1164 } 1165 break; 1166 1167 case SIOCRMNAT : 1168 case SIOCPURGENAT : 1169 if (!(mode & FWRITE)) { 1170 IPFERROR(60009); 1171 error = EPERM; 1172 n = NULL; 1173 } else if (n == NULL) { 1174 IPFERROR(60010); 1175 error = ESRCH; 1176 } 1177 1178 if (error != 0) { 1179 MUTEX_EXIT(&softn->ipf_nat_io); 1180 break; 1181 } 1182 if (cmd == (ioctlcmd_t)SIOCPURGENAT) { 1183 error = ipf_outobjsz(softc, data, n, IPFOBJ_IPNAT, 1184 n->in_size); 1185 if (error) { 1186 MUTEX_EXIT(&softn->ipf_nat_io); 1187 goto done; 1188 } 1189 n->in_flags |= IPN_PURGE; 1190 } 1191 ipf_nat_siocdelnat(softc, softn, n, getlock); 1192 1193 MUTEX_EXIT(&softn->ipf_nat_io); 1194 n = NULL; 1195 break; 1196 1197 case SIOCGNATS : 1198 { 1199 natstat_t *nsp = &softn->ipf_nat_stats; 1200 1201 nsp->ns_side[0].ns_table = softn->ipf_nat_table[0]; 1202 nsp->ns_side[1].ns_table = softn->ipf_nat_table[1]; 1203 nsp->ns_list = softn->ipf_nat_list; 1204 nsp->ns_maptable = softn->ipf_hm_maptable; 1205 nsp->ns_maplist = softn->ipf_hm_maplist; 1206 nsp->ns_nattab_sz = softn->ipf_nat_table_sz; 1207 nsp->ns_nattab_max = softn->ipf_nat_table_max; 1208 nsp->ns_rultab_sz = softn->ipf_nat_maprules_sz; 1209 nsp->ns_rdrtab_sz = softn->ipf_nat_rdrrules_sz; 1210 nsp->ns_hostmap_sz = softn->ipf_nat_hostmap_sz; 1211 nsp->ns_instances = softn->ipf_nat_instances; 1212 nsp->ns_ticks = softc->ipf_ticks; 1213 #ifdef IPFILTER_LOGGING 1214 nsp->ns_log_ok = ipf_log_logok(softc, IPF_LOGNAT); 1215 nsp->ns_log_fail = ipf_log_failures(softc, IPF_LOGNAT); 1216 #else 1217 nsp->ns_log_ok = 0; 1218 nsp->ns_log_fail = 0; 1219 #endif 1220 error = ipf_outobj(softc, data, nsp, IPFOBJ_NATSTAT); 1221 break; 1222 } 1223 1224 case SIOCGNATL : 1225 { 1226 natlookup_t nl; 1227 1228 error = ipf_inobj(softc, data, NULL, &nl, IPFOBJ_NATLOOKUP); 1229 if (error == 0) { 1230 void *ptr; 1231 1232 if (getlock) { 1233 READ_ENTER(&softc->ipf_nat); 1234 } 1235 1236 switch (nl.nl_v) 1237 { 1238 case 4 : 1239 ptr = ipf_nat_lookupredir(softc, &nl); 1240 break; 1241 #ifdef USE_INET6 1242 case 6 : 1243 ptr = ipf_nat6_lookupredir(softc, &nl); 1244 break; 1245 #endif 1246 default: 1247 ptr = NULL; 1248 break; 1249 } 1250 1251 if (getlock) { 1252 RWLOCK_EXIT(&softc->ipf_nat); 1253 } 1254 if (ptr != NULL) { 1255 error = ipf_outobj(softc, data, &nl, 1256 IPFOBJ_NATLOOKUP); 1257 } else { 1258 IPFERROR(60011); 1259 error = ESRCH; 1260 } 1261 } 1262 break; 1263 } 1264 1265 case SIOCIPFFL : /* old SIOCFLNAT & SIOCCNATL */ 1266 if (!(mode & FWRITE)) { 1267 IPFERROR(60012); 1268 error = EPERM; 1269 break; 1270 } 1271 if (getlock) { 1272 WRITE_ENTER(&softc->ipf_nat); 1273 } 1274 1275 error = BCOPYIN(data, &arg, sizeof(arg)); 1276 if (error != 0) { 1277 IPFERROR(60013); 1278 error = EFAULT; 1279 } else { 1280 if (arg == 0) 1281 ret = ipf_nat_flushtable(softc, softn); 1282 else if (arg == 1) 1283 ret = ipf_nat_clearlist(softc, softn); 1284 else 1285 ret = ipf_nat_extraflush(softc, softn, arg); 1286 ipf_proxy_flush(softc->ipf_proxy_soft, arg); 1287 } 1288 1289 if (getlock) { 1290 RWLOCK_EXIT(&softc->ipf_nat); 1291 } 1292 if (error == 0) { 1293 error = BCOPYOUT(&ret, data, sizeof(ret)); 1294 } 1295 break; 1296 1297 case SIOCMATCHFLUSH : 1298 if (!(mode & FWRITE)) { 1299 IPFERROR(60014); 1300 error = EPERM; 1301 break; 1302 } 1303 if (getlock) { 1304 WRITE_ENTER(&softc->ipf_nat); 1305 } 1306 1307 error = ipf_nat_matchflush(softc, softn, data); 1308 1309 if (getlock) { 1310 RWLOCK_EXIT(&softc->ipf_nat); 1311 } 1312 break; 1313 1314 case SIOCPROXY : 1315 error = ipf_proxy_ioctl(softc, data, cmd, mode, ctx); 1316 break; 1317 1318 case SIOCSTLCK : 1319 if (!(mode & FWRITE)) { 1320 IPFERROR(60015); 1321 error = EPERM; 1322 } else { 1323 error = ipf_lock(data, &softn->ipf_nat_lock); 1324 } 1325 break; 1326 1327 case SIOCSTPUT : 1328 if ((mode & FWRITE) != 0) { 1329 error = ipf_nat_putent(softc, data, getlock); 1330 } else { 1331 IPFERROR(60016); 1332 error = EACCES; 1333 } 1334 break; 1335 1336 case SIOCSTGSZ : 1337 if (softn->ipf_nat_lock) { 1338 error = ipf_nat_getsz(softc, data, getlock); 1339 } else { 1340 IPFERROR(60017); 1341 error = EACCES; 1342 } 1343 break; 1344 1345 case SIOCSTGET : 1346 if (softn->ipf_nat_lock) { 1347 error = ipf_nat_getent(softc, data, getlock); 1348 } else { 1349 IPFERROR(60018); 1350 error = EACCES; 1351 } 1352 break; 1353 1354 case SIOCGENITER : 1355 { 1356 ipfgeniter_t iter; 1357 ipftoken_t *token; 1358 ipfobj_t obj; 1359 1360 error = ipf_inobj(softc, data, &obj, &iter, IPFOBJ_GENITER); 1361 if (error != 0) 1362 break; 1363 1364 SPL_SCHED(s); 1365 token = ipf_token_find(softc, iter.igi_type, uid, ctx); 1366 if (token != NULL) { 1367 error = ipf_nat_iterator(softc, token, &iter, &obj); 1368 WRITE_ENTER(&softc->ipf_tokens); 1369 ipf_token_deref(softc, token); 1370 RWLOCK_EXIT(&softc->ipf_tokens); 1371 } 1372 SPL_X(s); 1373 break; 1374 } 1375 1376 case SIOCIPFDELTOK : 1377 error = BCOPYIN(data, &arg, sizeof(arg)); 1378 if (error == 0) { 1379 SPL_SCHED(s); 1380 error = ipf_token_del(softc, arg, uid, ctx); 1381 SPL_X(s); 1382 } else { 1383 IPFERROR(60019); 1384 error = EFAULT; 1385 } 1386 break; 1387 1388 case SIOCGTQTAB : 1389 error = ipf_outobj(softc, data, softn->ipf_nat_tcptq, 1390 IPFOBJ_STATETQTAB); 1391 break; 1392 1393 case SIOCGTABL : 1394 error = ipf_nat_gettable(softc, softn, data); 1395 break; 1396 1397 default : 1398 IPFERROR(60020); 1399 error = EINVAL; 1400 break; 1401 } 1402 done: 1403 if (nat != NULL) 1404 ipf_nat_rule_fini(softc, nat); 1405 if (natd != NULL) 1406 KFREE(natd); 1407 if (nt != NULL) 1408 KFREES(nt, nt->in_size); 1409 return error; 1410 } 1411 1412 1413 /* ------------------------------------------------------------------------ */ 1414 /* Function: ipf_nat_siocaddnat */ 1415 /* Returns: int - 0 == success, != 0 == failure */ 1416 /* Parameters: softc(I) - pointer to soft context main structure */ 1417 /* softn(I) - pointer to NAT context structure */ 1418 /* n(I) - pointer to new NAT rule */ 1419 /* np(I) - pointer to where to insert new NAT rule */ 1420 /* getlock(I) - flag indicating if lock on is held */ 1421 /* Mutex Locks: ipf_nat_io */ 1422 /* */ 1423 /* Handle SIOCADNAT. Resolve and calculate details inside the NAT rule */ 1424 /* from information passed to the kernel, then add it to the appropriate */ 1425 /* NAT rule table(s). */ 1426 /* ------------------------------------------------------------------------ */ 1427 static int 1428 ipf_nat_siocaddnat(ipf_main_softc_t *softc, ipf_nat_softc_t *softn, ipnat_t *n, 1429 int getlock) 1430 { 1431 int error = 0; 1432 1433 if (ipf_nat_resolverule(softc, n) != 0) { 1434 IPFERROR(60022); 1435 return ENOENT; 1436 } 1437 1438 if ((n->in_age[0] == 0) && (n->in_age[1] != 0)) { 1439 IPFERROR(60023); 1440 return EINVAL; 1441 } 1442 1443 if (n->in_redir == (NAT_DIVERTUDP|NAT_MAP)) { 1444 /* 1445 * Prerecord whether or not the destination of the divert 1446 * is local or not to the interface the packet is going 1447 * to be sent out. 1448 */ 1449 n->in_dlocal = ipf_deliverlocal(softc, n->in_v[1], 1450 n->in_ifps[1], &n->in_ndstip6); 1451 } 1452 1453 if (getlock) { 1454 WRITE_ENTER(&softc->ipf_nat); 1455 } 1456 n->in_next = NULL; 1457 n->in_pnext = softn->ipf_nat_list_tail; 1458 *n->in_pnext = n; 1459 softn->ipf_nat_list_tail = &n->in_next; 1460 n->in_use++; 1461 1462 if (n->in_redir & NAT_REDIRECT) { 1463 n->in_flags &= ~IPN_NOTDST; 1464 switch (n->in_v[0]) 1465 { 1466 case 4 : 1467 ipf_nat_addrdr(softn, n); 1468 break; 1469 #ifdef USE_INET6 1470 case 6 : 1471 ipf_nat6_addrdr(softn, n); 1472 break; 1473 #endif 1474 default : 1475 break; 1476 } 1477 ATOMIC_INC32(softn->ipf_nat_stats.ns_rules_rdr); 1478 } 1479 1480 if (n->in_redir & (NAT_MAP|NAT_MAPBLK)) { 1481 n->in_flags &= ~IPN_NOTSRC; 1482 switch (n->in_v[0]) 1483 { 1484 case 4 : 1485 ipf_nat_addmap(softn, n); 1486 break; 1487 #ifdef USE_INET6 1488 case 6 : 1489 ipf_nat6_addmap(softn, n); 1490 break; 1491 #endif 1492 default : 1493 break; 1494 } 1495 ATOMIC_INC32(softn->ipf_nat_stats.ns_rules_map); 1496 } 1497 1498 if (n->in_age[0] != 0) 1499 n->in_tqehead[0] = ipf_addtimeoutqueue(softc, 1500 &softn->ipf_nat_utqe, 1501 n->in_age[0]); 1502 1503 if (n->in_age[1] != 0) 1504 n->in_tqehead[1] = ipf_addtimeoutqueue(softc, 1505 &softn->ipf_nat_utqe, 1506 n->in_age[1]); 1507 1508 MUTEX_INIT(&n->in_lock, "ipnat rule lock"); 1509 1510 n = NULL; 1511 ATOMIC_INC32(softn->ipf_nat_stats.ns_rules); 1512 #if SOLARIS && !defined(INSTANCES) 1513 pfil_delayed_copy = 0; 1514 #endif 1515 if (getlock) { 1516 RWLOCK_EXIT(&softc->ipf_nat); /* WRITE */ 1517 } 1518 1519 return error; 1520 } 1521 1522 1523 /* ------------------------------------------------------------------------ */ 1524 /* Function: ipf_nat_ruleaddrinit */ 1525 /* Parameters: softc(I) - pointer to soft context main structure */ 1526 /* softn(I) - pointer to NAT context structure */ 1527 /* n(I) - pointer to NAT rule */ 1528 /* */ 1529 /* Initialise all of the NAT address structures in a NAT rule. */ 1530 /* ------------------------------------------------------------------------ */ 1531 static int 1532 ipf_nat_ruleaddrinit(ipf_main_softc_t *softc, ipf_nat_softc_t *softn, 1533 ipnat_t *n) 1534 { 1535 int idx, error; 1536 1537 if ((n->in_ndst.na_atype == FRI_LOOKUP) && 1538 (n->in_ndst.na_type != IPLT_DSTLIST)) { 1539 IPFERROR(60071); 1540 return EINVAL; 1541 } 1542 if ((n->in_nsrc.na_atype == FRI_LOOKUP) && 1543 (n->in_nsrc.na_type != IPLT_DSTLIST)) { 1544 IPFERROR(60069); 1545 return EINVAL; 1546 } 1547 1548 if (n->in_redir == NAT_BIMAP) { 1549 n->in_ndstaddr = n->in_osrcaddr; 1550 n->in_ndstmsk = n->in_osrcmsk; 1551 n->in_odstaddr = n->in_nsrcaddr; 1552 n->in_odstmsk = n->in_nsrcmsk; 1553 1554 } 1555 1556 if (n->in_redir & NAT_REDIRECT) 1557 idx = 1; 1558 else 1559 idx = 0; 1560 /* 1561 * Initialise all of the address fields. 1562 */ 1563 error = ipf_nat_nextaddrinit(softc, n->in_names, &n->in_osrc, 1, 1564 n->in_ifps[idx]); 1565 if (error != 0) 1566 return error; 1567 1568 error = ipf_nat_nextaddrinit(softc, n->in_names, &n->in_odst, 1, 1569 n->in_ifps[idx]); 1570 if (error != 0) 1571 return error; 1572 1573 error = ipf_nat_nextaddrinit(softc, n->in_names, &n->in_nsrc, 1, 1574 n->in_ifps[idx]); 1575 if (error != 0) 1576 return error; 1577 1578 error = ipf_nat_nextaddrinit(softc, n->in_names, &n->in_ndst, 1, 1579 n->in_ifps[idx]); 1580 if (error != 0) 1581 return error; 1582 1583 if (n->in_redir & NAT_DIVERTUDP) 1584 ipf_nat_builddivertmp(softn, n); 1585 1586 return 0; 1587 } 1588 1589 1590 /* ------------------------------------------------------------------------ */ 1591 /* Function: ipf_nat_resolvrule */ 1592 /* Returns: Nil */ 1593 /* Parameters: softc(I) - pointer to soft context main structure */ 1594 /* n(I) - pointer to NAT rule */ 1595 /* */ 1596 /* Handle SIOCADNAT. Resolve and calculate details inside the NAT rule */ 1597 /* from information passed to the kernel, then add it to the appropriate */ 1598 /* NAT rule table(s). */ 1599 /* ------------------------------------------------------------------------ */ 1600 static int 1601 ipf_nat_resolverule(ipf_main_softc_t *softc, ipnat_t *n) 1602 { 1603 char *base; 1604 1605 base = n->in_names; 1606 1607 n->in_ifps[0] = ipf_resolvenic(softc, base + n->in_ifnames[0], 1608 n->in_v[0]); 1609 1610 if (n->in_ifnames[1] == -1) { 1611 n->in_ifnames[1] = n->in_ifnames[0]; 1612 n->in_ifps[1] = n->in_ifps[0]; 1613 } else { 1614 n->in_ifps[1] = ipf_resolvenic(softc, base + n->in_ifnames[1], 1615 n->in_v[1]); 1616 } 1617 1618 if (n->in_plabel != -1) { 1619 if (n->in_redir & NAT_REDIRECT) 1620 n->in_apr = ipf_proxy_lookup(softc->ipf_proxy_soft, 1621 n->in_pr[0], 1622 base + n->in_plabel); 1623 else 1624 n->in_apr = ipf_proxy_lookup(softc->ipf_proxy_soft, 1625 n->in_pr[1], 1626 base + n->in_plabel); 1627 if (n->in_apr == NULL) 1628 return -1; 1629 } 1630 return 0; 1631 } 1632 1633 1634 /* ------------------------------------------------------------------------ */ 1635 /* Function: ipf_nat_siocdelnat */ 1636 /* Returns: int - 0 == success, != 0 == failure */ 1637 /* Parameters: softc(I) - pointer to soft context main structure */ 1638 /* softn(I) - pointer to NAT context structure */ 1639 /* n(I) - pointer to new NAT rule */ 1640 /* getlock(I) - flag indicating if lock on is held */ 1641 /* Mutex Locks: ipf_nat_io */ 1642 /* */ 1643 /* Handle SIOCADNAT. Resolve and calculate details inside the NAT rule */ 1644 /* from information passed to the kernel, then add it to the appropriate */ 1645 /* NAT rule table(s). */ 1646 /* ------------------------------------------------------------------------ */ 1647 static void 1648 ipf_nat_siocdelnat(ipf_main_softc_t *softc, ipf_nat_softc_t *softn, ipnat_t *n, 1649 int getlock) 1650 { 1651 #ifdef IPF_NAT6 1652 int i; 1653 #endif 1654 1655 if (getlock) { 1656 WRITE_ENTER(&softc->ipf_nat); 1657 } 1658 1659 ipf_nat_delrule(softc, softn, n, 1); 1660 1661 if (getlock) { 1662 RWLOCK_EXIT(&softc->ipf_nat); /* READ/WRITE */ 1663 } 1664 } 1665 1666 1667 /* ------------------------------------------------------------------------ */ 1668 /* Function: ipf_nat_getsz */ 1669 /* Returns: int - 0 == success, != 0 is the error value. */ 1670 /* Parameters: softc(I) - pointer to soft context main structure */ 1671 /* data(I) - pointer to natget structure with kernel */ 1672 /* pointer get the size of. */ 1673 /* getlock(I) - flag indicating whether or not the caller */ 1674 /* holds a lock on ipf_nat */ 1675 /* */ 1676 /* Handle SIOCSTGSZ. */ 1677 /* Return the size of the nat list entry to be copied back to user space. */ 1678 /* The size of the entry is stored in the ng_sz field and the enture natget */ 1679 /* structure is copied back to the user. */ 1680 /* ------------------------------------------------------------------------ */ 1681 static int 1682 ipf_nat_getsz(ipf_main_softc_t *softc, void *data, int getlock) 1683 { 1684 ipf_nat_softc_t *softn = softc->ipf_nat_soft; 1685 ap_session_t *aps; 1686 nat_t *nat, *n; 1687 natget_t ng; 1688 int error; 1689 1690 error = BCOPYIN(data, &ng, sizeof(ng)); 1691 if (error != 0) { 1692 IPFERROR(60024); 1693 return EFAULT; 1694 } 1695 1696 if (getlock) { 1697 READ_ENTER(&softc->ipf_nat); 1698 } 1699 1700 nat = ng.ng_ptr; 1701 if (!nat) { 1702 nat = softn->ipf_nat_instances; 1703 ng.ng_sz = 0; 1704 /* 1705 * Empty list so the size returned is 0. Simple. 1706 */ 1707 if (nat == NULL) { 1708 if (getlock) { 1709 RWLOCK_EXIT(&softc->ipf_nat); 1710 } 1711 error = BCOPYOUT(&ng, data, sizeof(ng)); 1712 if (error != 0) { 1713 IPFERROR(60025); 1714 return EFAULT; 1715 } 1716 return 0; 1717 } 1718 } else { 1719 /* 1720 * Make sure the pointer we're copying from exists in the 1721 * current list of entries. Security precaution to prevent 1722 * copying of random kernel data. 1723 */ 1724 for (n = softn->ipf_nat_instances; n; n = n->nat_next) 1725 if (n == nat) 1726 break; 1727 if (n == NULL) { 1728 if (getlock) { 1729 RWLOCK_EXIT(&softc->ipf_nat); 1730 } 1731 IPFERROR(60026); 1732 return ESRCH; 1733 } 1734 } 1735 1736 /* 1737 * Include any space required for proxy data structures. 1738 */ 1739 ng.ng_sz = sizeof(nat_save_t); 1740 aps = nat->nat_aps; 1741 if (aps != NULL) { 1742 ng.ng_sz += sizeof(ap_session_t) - 4; 1743 if (aps->aps_data != 0) 1744 ng.ng_sz += aps->aps_psiz; 1745 } 1746 if (getlock) { 1747 RWLOCK_EXIT(&softc->ipf_nat); 1748 } 1749 1750 error = BCOPYOUT(&ng, data, sizeof(ng)); 1751 if (error != 0) { 1752 IPFERROR(60027); 1753 return EFAULT; 1754 } 1755 return 0; 1756 } 1757 1758 1759 /* ------------------------------------------------------------------------ */ 1760 /* Function: ipf_nat_getent */ 1761 /* Returns: int - 0 == success, != 0 is the error value. */ 1762 /* Parameters: softc(I) - pointer to soft context main structure */ 1763 /* data(I) - pointer to natget structure with kernel pointer*/ 1764 /* to NAT structure to copy out. */ 1765 /* getlock(I) - flag indicating whether or not the caller */ 1766 /* holds a lock on ipf_nat */ 1767 /* */ 1768 /* Handle SIOCSTGET. */ 1769 /* Copies out NAT entry to user space. Any additional data held for a */ 1770 /* proxy is also copied, as to is the NAT rule which was responsible for it */ 1771 /* ------------------------------------------------------------------------ */ 1772 static int 1773 ipf_nat_getent(ipf_main_softc_t *softc, void *data, int getlock) 1774 { 1775 ipf_nat_softc_t *softn = softc->ipf_nat_soft; 1776 int error, outsize; 1777 ap_session_t *aps; 1778 nat_save_t *ipn, ipns; 1779 nat_t *n, *nat; 1780 1781 error = ipf_inobj(softc, data, NULL, &ipns, IPFOBJ_NATSAVE); 1782 if (error != 0) 1783 return error; 1784 1785 if ((ipns.ipn_dsize < sizeof(ipns)) || (ipns.ipn_dsize > 81920)) { 1786 IPFERROR(60028); 1787 return EINVAL; 1788 } 1789 1790 KMALLOCS(ipn, nat_save_t *, ipns.ipn_dsize); 1791 if (ipn == NULL) { 1792 IPFERROR(60029); 1793 return ENOMEM; 1794 } 1795 1796 if (getlock) { 1797 READ_ENTER(&softc->ipf_nat); 1798 } 1799 1800 ipn->ipn_dsize = ipns.ipn_dsize; 1801 nat = ipns.ipn_next; 1802 if (nat == NULL) { 1803 nat = softn->ipf_nat_instances; 1804 if (nat == NULL) { 1805 if (softn->ipf_nat_instances == NULL) { 1806 IPFERROR(60030); 1807 error = ENOENT; 1808 } 1809 goto finished; 1810 } 1811 } else { 1812 /* 1813 * Make sure the pointer we're copying from exists in the 1814 * current list of entries. Security precaution to prevent 1815 * copying of random kernel data. 1816 */ 1817 for (n = softn->ipf_nat_instances; n; n = n->nat_next) 1818 if (n == nat) 1819 break; 1820 if (n == NULL) { 1821 IPFERROR(60031); 1822 error = ESRCH; 1823 goto finished; 1824 } 1825 } 1826 ipn->ipn_next = nat->nat_next; 1827 1828 /* 1829 * Copy the NAT structure. 1830 */ 1831 bcopy((char *)nat, &ipn->ipn_nat, sizeof(*nat)); 1832 1833 /* 1834 * If we have a pointer to the NAT rule it belongs to, save that too. 1835 */ 1836 if (nat->nat_ptr != NULL) 1837 bcopy((char *)nat->nat_ptr, (char *)&ipn->ipn_ipnat, 1838 ipn->ipn_ipnat.in_size); 1839 1840 /* 1841 * If we also know the NAT entry has an associated filter rule, 1842 * save that too. 1843 */ 1844 if (nat->nat_fr != NULL) 1845 bcopy((char *)nat->nat_fr, (char *)&ipn->ipn_fr, 1846 sizeof(ipn->ipn_fr)); 1847 1848 /* 1849 * Last but not least, if there is an application proxy session set 1850 * up for this NAT entry, then copy that out too, including any 1851 * private data saved along side it by the proxy. 1852 */ 1853 aps = nat->nat_aps; 1854 outsize = ipn->ipn_dsize - sizeof(*ipn) + sizeof(ipn->ipn_data); 1855 if (aps != NULL) { 1856 char *s; 1857 1858 if (outsize < sizeof(*aps)) { 1859 IPFERROR(60032); 1860 error = ENOBUFS; 1861 goto finished; 1862 } 1863 1864 s = ipn->ipn_data; 1865 bcopy((char *)aps, s, sizeof(*aps)); 1866 s += sizeof(*aps); 1867 outsize -= sizeof(*aps); 1868 if ((aps->aps_data != NULL) && (outsize >= aps->aps_psiz)) 1869 bcopy(aps->aps_data, s, aps->aps_psiz); 1870 else { 1871 IPFERROR(60033); 1872 error = ENOBUFS; 1873 } 1874 } 1875 if (error == 0) { 1876 if (getlock) { 1877 READ_ENTER(&softc->ipf_nat); 1878 getlock = 0; 1879 } 1880 error = ipf_outobjsz(softc, data, ipn, IPFOBJ_NATSAVE, 1881 ipns.ipn_dsize); 1882 } 1883 1884 finished: 1885 if (getlock) { 1886 READ_ENTER(&softc->ipf_nat); 1887 } 1888 if (ipn != NULL) { 1889 KFREES(ipn, ipns.ipn_dsize); 1890 } 1891 return error; 1892 } 1893 1894 1895 /* ------------------------------------------------------------------------ */ 1896 /* Function: ipf_nat_putent */ 1897 /* Returns: int - 0 == success, != 0 is the error value. */ 1898 /* Parameters: softc(I) - pointer to soft context main structure */ 1899 /* data(I) - pointer to natget structure with NAT */ 1900 /* structure information to load into the kernel */ 1901 /* getlock(I) - flag indicating whether or not a write lock */ 1902 /* on is already held. */ 1903 /* */ 1904 /* Handle SIOCSTPUT. */ 1905 /* Loads a NAT table entry from user space, including a NAT rule, proxy and */ 1906 /* firewall rule data structures, if pointers to them indicate so. */ 1907 /* ------------------------------------------------------------------------ */ 1908 static int 1909 ipf_nat_putent(ipf_main_softc_t *softc, void *data, int getlock) 1910 { 1911 ipf_nat_softc_t *softn = softc->ipf_nat_soft; 1912 nat_save_t *ipn, *ipnn; 1913 ap_session_t *aps; 1914 nat_t *n, *nat; 1915 frentry_t *fr; 1916 fr_info_t *fin; 1917 ipnat_t *in; 1918 int error; 1919 1920 KMALLOC(ipn, nat_save_t *); 1921 if (ipn == NULL) 1922 return ENOMEM; 1923 error = ipf_inobj(softc, data, NULL, ipn, IPFOBJ_NATSAVE); 1924 if (error != 0) 1925 return error; 1926 1927 /* 1928 * Initialise early because of code at junkput label. 1929 */ 1930 n = NULL; 1931 in = NULL; 1932 aps = NULL; 1933 nat = NULL; 1934 ipnn = NULL; 1935 fin = NULL; 1936 fr = NULL; 1937 1938 /* 1939 * New entry, copy in the rest of the NAT entry if it's size is more 1940 * than just the nat_t structure. 1941 */ 1942 if (ipn->ipn_dsize > sizeof(*ipn)) { 1943 if (ipn->ipn_dsize > 81920) { 1944 IPFERROR(60034); 1945 error = ENOMEM; 1946 goto junkput; 1947 } 1948 1949 KMALLOCS(ipnn, nat_save_t *, ipn->ipn_dsize); 1950 if (ipnn == NULL) { 1951 IPFERROR(60035); 1952 return ENOMEM; 1953 } 1954 1955 bzero(ipnn, ipn->ipn_dsize); 1956 error = ipf_inobjsz(softc, data, ipnn, IPFOBJ_NATSAVE, 1957 ipn->ipn_dsize); 1958 if (error != 0) { 1959 goto junkput; 1960 } 1961 } else 1962 ipnn = ipn; 1963 1964 KMALLOC(nat, nat_t *); 1965 if (nat == NULL) { 1966 IPFERROR(60037); 1967 error = ENOMEM; 1968 goto junkput; 1969 } 1970 1971 bcopy((char *)&ipnn->ipn_nat, (char *)nat, sizeof(*nat)); 1972 1973 switch (nat->nat_v[0]) 1974 { 1975 case 4: 1976 #ifdef USE_IENT6 1977 case 6 : 1978 #endif 1979 break; 1980 default : 1981 IPFERROR(60061); 1982 error = EPROTONOSUPPORT; 1983 goto junkput; 1984 /*NOTREACHED*/ 1985 } 1986 1987 /* 1988 * Initialize all these so that ipf_nat_delete() doesn't cause a crash. 1989 */ 1990 bzero((char *)nat, offsetof(struct nat, nat_tqe)); 1991 nat->nat_tqe.tqe_pnext = NULL; 1992 nat->nat_tqe.tqe_next = NULL; 1993 nat->nat_tqe.tqe_ifq = NULL; 1994 nat->nat_tqe.tqe_parent = nat; 1995 1996 /* 1997 * Restore the rule associated with this nat session 1998 */ 1999 in = ipnn->ipn_nat.nat_ptr; 2000 if (in != NULL) { 2001 KMALLOCS(in, ipnat_t *, ipnn->ipn_ipnat.in_size); 2002 nat->nat_ptr = in; 2003 if (in == NULL) { 2004 IPFERROR(60038); 2005 error = ENOMEM; 2006 goto junkput; 2007 } 2008 bcopy((char *)&ipnn->ipn_ipnat, (char *)in, 2009 ipnn->ipn_ipnat.in_size); 2010 in->in_use = 1; 2011 in->in_flags |= IPN_DELETE; 2012 2013 ATOMIC_INC32(softn->ipf_nat_stats.ns_rules); 2014 2015 if (ipf_nat_resolverule(softc, in) != 0) { 2016 IPFERROR(60039); 2017 error = ESRCH; 2018 goto junkput; 2019 } 2020 } 2021 2022 /* 2023 * Check that the NAT entry doesn't already exist in the kernel. 2024 * 2025 * For NAT_OUTBOUND, we're lookup for a duplicate MAP entry. To do 2026 * this, we check to see if the inbound combination of addresses and 2027 * ports is already known. Similar logic is applied for NAT_INBOUND. 2028 * 2029 */ 2030 KMALLOC(fin, fr_info_t *); 2031 if (fin == NULL) { 2032 error = ENOMEM; 2033 goto junkput; 2034 } 2035 bzero(fin, sizeof(*fin)); 2036 fin->fin_v = nat->nat_v[0]; 2037 fin->fin_p = nat->nat_pr[0]; 2038 fin->fin_rev = nat->nat_rev; 2039 fin->fin_ifp = nat->nat_ifps[0]; 2040 fin->fin_data[0] = ntohs(nat->nat_ndport); 2041 fin->fin_data[1] = ntohs(nat->nat_nsport); 2042 2043 switch (nat->nat_dir) 2044 { 2045 case NAT_OUTBOUND : 2046 case NAT_DIVERTOUT : 2047 if (getlock) { 2048 READ_ENTER(&softc->ipf_nat); 2049 } 2050 2051 fin->fin_v = nat->nat_v[1]; 2052 if (nat->nat_v[1] == 4) { 2053 n = ipf_nat_inlookup(fin, nat->nat_flags, fin->fin_p, 2054 nat->nat_ndstip, nat->nat_nsrcip); 2055 #ifdef USE_INET6 2056 } else if (nat->nat_v[1] == 6) { 2057 n = ipf_nat6_inlookup(fin, nat->nat_flags, fin->fin_p, 2058 &nat->nat_ndst6.in6, 2059 &nat->nat_nsrc6.in6); 2060 #endif 2061 } 2062 2063 if (getlock) { 2064 RWLOCK_EXIT(&softc->ipf_nat); 2065 } 2066 if (n != NULL) { 2067 IPFERROR(60040); 2068 error = EEXIST; 2069 goto junkput; 2070 } 2071 break; 2072 2073 case NAT_INBOUND : 2074 case NAT_DIVERTIN : 2075 if (getlock) { 2076 READ_ENTER(&softc->ipf_nat); 2077 } 2078 2079 if (fin->fin_v == 4) { 2080 n = ipf_nat_outlookup(fin, nat->nat_flags, fin->fin_p, 2081 nat->nat_ndstip, 2082 nat->nat_nsrcip); 2083 #ifdef USE_INET6 2084 } else if (fin->fin_v == 6) { 2085 n = ipf_nat6_outlookup(fin, nat->nat_flags, fin->fin_p, 2086 &nat->nat_ndst6.in6, 2087 &nat->nat_nsrc6.in6); 2088 #endif 2089 } 2090 2091 if (getlock) { 2092 RWLOCK_EXIT(&softc->ipf_nat); 2093 } 2094 if (n != NULL) { 2095 IPFERROR(60041); 2096 error = EEXIST; 2097 goto junkput; 2098 } 2099 break; 2100 2101 default : 2102 IPFERROR(60042); 2103 error = EINVAL; 2104 goto junkput; 2105 } 2106 2107 /* 2108 * Restore ap_session_t structure. Include the private data allocated 2109 * if it was there. 2110 */ 2111 aps = nat->nat_aps; 2112 if (aps != NULL) { 2113 KMALLOC(aps, ap_session_t *); 2114 nat->nat_aps = aps; 2115 if (aps == NULL) { 2116 IPFERROR(60043); 2117 error = ENOMEM; 2118 goto junkput; 2119 } 2120 bcopy(ipnn->ipn_data, (char *)aps, sizeof(*aps)); 2121 if (in != NULL) 2122 aps->aps_apr = in->in_apr; 2123 else 2124 aps->aps_apr = NULL; 2125 if (aps->aps_psiz != 0) { 2126 if (aps->aps_psiz > 81920) { 2127 IPFERROR(60044); 2128 error = ENOMEM; 2129 goto junkput; 2130 } 2131 KMALLOCS(aps->aps_data, void *, aps->aps_psiz); 2132 if (aps->aps_data == NULL) { 2133 IPFERROR(60045); 2134 error = ENOMEM; 2135 goto junkput; 2136 } 2137 bcopy(ipnn->ipn_data + sizeof(*aps), aps->aps_data, 2138 aps->aps_psiz); 2139 } else { 2140 aps->aps_psiz = 0; 2141 aps->aps_data = NULL; 2142 } 2143 } 2144 2145 /* 2146 * If there was a filtering rule associated with this entry then 2147 * build up a new one. 2148 */ 2149 fr = nat->nat_fr; 2150 if (fr != NULL) { 2151 if ((nat->nat_flags & SI_NEWFR) != 0) { 2152 KMALLOC(fr, frentry_t *); 2153 nat->nat_fr = fr; 2154 if (fr == NULL) { 2155 IPFERROR(60046); 2156 error = ENOMEM; 2157 goto junkput; 2158 } 2159 ipnn->ipn_nat.nat_fr = fr; 2160 fr->fr_ref = 1; 2161 (void) ipf_outobj(softc, data, ipnn, IPFOBJ_NATSAVE); 2162 bcopy((char *)&ipnn->ipn_fr, (char *)fr, sizeof(*fr)); 2163 2164 fr->fr_ref = 1; 2165 fr->fr_dsize = 0; 2166 fr->fr_data = NULL; 2167 fr->fr_type = FR_T_NONE; 2168 2169 MUTEX_NUKE(&fr->fr_lock); 2170 MUTEX_INIT(&fr->fr_lock, "nat-filter rule lock"); 2171 } else { 2172 if (getlock) { 2173 READ_ENTER(&softc->ipf_nat); 2174 } 2175 for (n = softn->ipf_nat_instances; n; n = n->nat_next) 2176 if (n->nat_fr == fr) 2177 break; 2178 2179 if (n != NULL) { 2180 MUTEX_ENTER(&fr->fr_lock); 2181 fr->fr_ref++; 2182 MUTEX_EXIT(&fr->fr_lock); 2183 } 2184 if (getlock) { 2185 RWLOCK_EXIT(&softc->ipf_nat); 2186 } 2187 2188 if (n == NULL) { 2189 IPFERROR(60047); 2190 error = ESRCH; 2191 goto junkput; 2192 } 2193 } 2194 } 2195 2196 if (ipnn != ipn) { 2197 KFREES(ipnn, ipn->ipn_dsize); 2198 ipnn = NULL; 2199 } 2200 2201 if (getlock) { 2202 WRITE_ENTER(&softc->ipf_nat); 2203 } 2204 2205 if (fin->fin_v == 4) 2206 error = ipf_nat_finalise(fin, nat); 2207 #ifdef USE_INET6 2208 else 2209 error = ipf_nat6_finalise(fin, nat); 2210 #endif 2211 2212 if (getlock) { 2213 RWLOCK_EXIT(&softc->ipf_nat); 2214 } 2215 2216 if (error == 0) 2217 return 0; 2218 2219 IPFERROR(60048); 2220 error = ENOMEM; 2221 2222 junkput: 2223 if (fin != NULL) 2224 KFREE(fin); 2225 if (fr != NULL) { 2226 (void) ipf_derefrule(softc, &fr); 2227 } 2228 2229 if ((ipnn != NULL) && (ipnn != ipn)) { 2230 KFREES(ipnn, ipn->ipn_dsize); 2231 } 2232 if (ipn != NULL) 2233 KFREE(ipn); 2234 if (nat != NULL) { 2235 if (aps != NULL) { 2236 if (aps->aps_data != NULL) { 2237 KFREES(aps->aps_data, aps->aps_psiz); 2238 } 2239 KFREE(aps); 2240 } 2241 if (in != NULL) { 2242 if (in->in_apr) 2243 ipf_proxy_deref(in->in_apr); 2244 KFREES(in, in->in_size); 2245 } 2246 KFREE(nat); 2247 } 2248 return error; 2249 } 2250 2251 2252 /* ------------------------------------------------------------------------ */ 2253 /* Function: ipf_nat_delete */ 2254 /* Returns: Nil */ 2255 /* Parameters: softc(I) - pointer to soft context main structure */ 2256 /* nat(I) - pointer to NAT structure to delete */ 2257 /* logtype(I) - type of LOG record to create before deleting */ 2258 /* Write Lock: ipf_nat */ 2259 /* */ 2260 /* Delete a nat entry from the various lists and table. If NAT logging is */ 2261 /* enabled then generate a NAT log record for this event. */ 2262 /* ------------------------------------------------------------------------ */ 2263 void 2264 ipf_nat_delete(ipf_main_softc_t *softc, struct nat *nat, int logtype) 2265 { 2266 ipf_nat_softc_t *softn = softc->ipf_nat_soft; 2267 int madeorphan = 0, removed = 0; 2268 u_int bkt; 2269 nat_stat_side_t *nss; 2270 struct ipnat *ipn; 2271 2272 if (logtype != 0 && softn->ipf_nat_logging != 0) 2273 ipf_nat_log(softc, softn, nat, logtype); 2274 2275 /* 2276 * Take it as a general indication that all the pointers are set if 2277 * nat_pnext is set. 2278 */ 2279 if (nat->nat_pnext != NULL) { 2280 removed = 1; 2281 2282 bkt = nat->nat_hv[0] % softn->ipf_nat_table_sz; 2283 nss = &softn->ipf_nat_stats.ns_side[0]; 2284 ASSERT(nss->ns_bucketlen[bkt] > 0); 2285 nss->ns_bucketlen[bkt]--; 2286 if (nss->ns_bucketlen[bkt] == 0) { 2287 nss->ns_inuse--; 2288 } 2289 2290 bkt = nat->nat_hv[1] % softn->ipf_nat_table_sz; 2291 nss = &softn->ipf_nat_stats.ns_side[1]; 2292 ASSERT(nss->ns_bucketlen[bkt] > 0); 2293 nss->ns_bucketlen[bkt]--; 2294 if (nss->ns_bucketlen[bkt] == 0) { 2295 nss->ns_inuse--; 2296 } 2297 2298 *nat->nat_pnext = nat->nat_next; 2299 if (nat->nat_next != NULL) { 2300 nat->nat_next->nat_pnext = nat->nat_pnext; 2301 nat->nat_next = NULL; 2302 } 2303 nat->nat_pnext = NULL; 2304 2305 *nat->nat_phnext[0] = nat->nat_hnext[0]; 2306 if (nat->nat_hnext[0] != NULL) { 2307 nat->nat_hnext[0]->nat_phnext[0] = nat->nat_phnext[0]; 2308 nat->nat_hnext[0] = NULL; 2309 } 2310 nat->nat_phnext[0] = NULL; 2311 2312 *nat->nat_phnext[1] = nat->nat_hnext[1]; 2313 if (nat->nat_hnext[1] != NULL) { 2314 nat->nat_hnext[1]->nat_phnext[1] = nat->nat_phnext[1]; 2315 nat->nat_hnext[1] = NULL; 2316 } 2317 nat->nat_phnext[1] = NULL; 2318 2319 if ((nat->nat_flags & SI_WILDP) != 0) { 2320 ATOMIC_DEC32(softn->ipf_nat_stats.ns_wilds); 2321 } 2322 madeorphan = 1; 2323 } 2324 2325 if (nat->nat_me != NULL) { 2326 *nat->nat_me = NULL; 2327 nat->nat_me = NULL; 2328 nat->nat_ref--; 2329 ASSERT(nat->nat_ref >= 0); 2330 } 2331 2332 if (nat->nat_tqe.tqe_ifq != NULL) { 2333 /* 2334 * No call to ipf_freetimeoutqueue() is made here, they are 2335 * garbage collected in ipf_nat_expire(). 2336 */ 2337 (void) ipf_deletequeueentry(&nat->nat_tqe); 2338 } 2339 2340 if (nat->nat_sync) { 2341 ipf_sync_del_nat(softc->ipf_sync_soft, nat->nat_sync); 2342 nat->nat_sync = NULL; 2343 } 2344 2345 if (logtype == NL_EXPIRE) 2346 softn->ipf_nat_stats.ns_expire++; 2347 2348 MUTEX_ENTER(&nat->nat_lock); 2349 /* 2350 * NL_DESTROY should only be passed in when we've got nat_ref >= 2. 2351 * This happens when a nat'd packet is blocked and we want to throw 2352 * away the NAT session. 2353 */ 2354 if (logtype == NL_DESTROY) { 2355 if (nat->nat_ref > 2) { 2356 nat->nat_ref -= 2; 2357 MUTEX_EXIT(&nat->nat_lock); 2358 if (removed) 2359 softn->ipf_nat_stats.ns_orphans++; 2360 return; 2361 } 2362 } else if (nat->nat_ref > 1) { 2363 nat->nat_ref--; 2364 MUTEX_EXIT(&nat->nat_lock); 2365 if (madeorphan == 1) 2366 softn->ipf_nat_stats.ns_orphans++; 2367 return; 2368 } 2369 ASSERT(nat->nat_ref >= 0); 2370 MUTEX_EXIT(&nat->nat_lock); 2371 2372 nat->nat_ref = 0; 2373 2374 if (madeorphan == 0) 2375 softn->ipf_nat_stats.ns_orphans--; 2376 2377 /* 2378 * At this point, nat_ref can be either 0 or -1 2379 */ 2380 softn->ipf_nat_stats.ns_proto[nat->nat_pr[0]]--; 2381 2382 if (nat->nat_fr != NULL) { 2383 (void) ipf_derefrule(softc, &nat->nat_fr); 2384 } 2385 2386 if (nat->nat_hm != NULL) { 2387 ipf_nat_hostmapdel(softc, &nat->nat_hm); 2388 } 2389 2390 /* 2391 * If there is an active reference from the nat entry to its parent 2392 * rule, decrement the rule's reference count and free it too if no 2393 * longer being used. 2394 */ 2395 ipn = nat->nat_ptr; 2396 nat->nat_ptr = NULL; 2397 2398 if (ipn != NULL) { 2399 ipn->in_space++; 2400 ipf_nat_rule_deref(softc, &ipn); 2401 } 2402 2403 if (nat->nat_aps != NULL) { 2404 ipf_proxy_free(softc, nat->nat_aps); 2405 nat->nat_aps = NULL; 2406 } 2407 2408 MUTEX_DESTROY(&nat->nat_lock); 2409 2410 softn->ipf_nat_stats.ns_active--; 2411 2412 /* 2413 * If there's a fragment table entry too for this nat entry, then 2414 * dereference that as well. This is after nat_lock is released 2415 * because of Tru64. 2416 */ 2417 ipf_frag_natforget(softc, (void *)nat); 2418 2419 KFREE(nat); 2420 } 2421 2422 2423 /* ------------------------------------------------------------------------ */ 2424 /* Function: ipf_nat_flushtable */ 2425 /* Returns: int - number of NAT rules deleted */ 2426 /* Parameters: softc(I) - pointer to soft context main structure */ 2427 /* softn(I) - pointer to NAT context structure */ 2428 /* Write Lock: ipf_nat */ 2429 /* */ 2430 /* Deletes all currently active NAT sessions. In deleting each NAT entry a */ 2431 /* log record should be emitted in ipf_nat_delete() if NAT logging is */ 2432 /* enabled. */ 2433 /* ------------------------------------------------------------------------ */ 2434 /* 2435 * nat_flushtable - clear the NAT table of all mapping entries. 2436 */ 2437 static int 2438 ipf_nat_flushtable(ipf_main_softc_t *softc, ipf_nat_softc_t *softn) 2439 { 2440 nat_t *nat; 2441 int j = 0; 2442 2443 /* 2444 * ALL NAT mappings deleted, so lets just make the deletions 2445 * quicker. 2446 */ 2447 if (softn->ipf_nat_table[0] != NULL) 2448 bzero((char *)softn->ipf_nat_table[0], 2449 sizeof(softn->ipf_nat_table[0]) * 2450 softn->ipf_nat_table_sz); 2451 if (softn->ipf_nat_table[1] != NULL) 2452 bzero((char *)softn->ipf_nat_table[1], 2453 sizeof(softn->ipf_nat_table[1]) * 2454 softn->ipf_nat_table_sz); 2455 2456 while ((nat = softn->ipf_nat_instances) != NULL) { 2457 ipf_nat_delete(softc, nat, NL_FLUSH); 2458 j++; 2459 } 2460 2461 return j; 2462 } 2463 2464 2465 /* ------------------------------------------------------------------------ */ 2466 /* Function: ipf_nat_clearlist */ 2467 /* Returns: int - number of NAT/RDR rules deleted */ 2468 /* Parameters: softc(I) - pointer to soft context main structure */ 2469 /* softn(I) - pointer to NAT context structure */ 2470 /* */ 2471 /* Delete all rules in the current list of rules. There is nothing elegant */ 2472 /* about this cleanup: simply free all entries on the list of rules and */ 2473 /* clear out the tables used for hashed NAT rule lookups. */ 2474 /* ------------------------------------------------------------------------ */ 2475 static int 2476 ipf_nat_clearlist(ipf_main_softc_t *softc, ipf_nat_softc_t *softn) 2477 { 2478 ipnat_t *n; 2479 int i = 0; 2480 2481 if (softn->ipf_nat_map_rules != NULL) { 2482 bzero((char *)softn->ipf_nat_map_rules, 2483 sizeof(*softn->ipf_nat_map_rules) * 2484 softn->ipf_nat_maprules_sz); 2485 } 2486 if (softn->ipf_nat_rdr_rules != NULL) { 2487 bzero((char *)softn->ipf_nat_rdr_rules, 2488 sizeof(*softn->ipf_nat_rdr_rules) * 2489 softn->ipf_nat_rdrrules_sz); 2490 } 2491 2492 while ((n = softn->ipf_nat_list) != NULL) { 2493 ipf_nat_delrule(softc, softn, n, 0); 2494 i++; 2495 } 2496 #if SOLARIS && !defined(INSTANCES) 2497 pfil_delayed_copy = 1; 2498 #endif 2499 return i; 2500 } 2501 2502 2503 /* ------------------------------------------------------------------------ */ 2504 /* Function: ipf_nat_delrule */ 2505 /* Returns: Nil */ 2506 /* Parameters: softc(I) - pointer to soft context main structure */ 2507 /* softn(I) - pointer to NAT context structure */ 2508 /* np(I) - pointer to NAT rule to delete */ 2509 /* purge(I) - 1 == allow purge, 0 == prevent purge */ 2510 /* Locks: WRITE(ipf_nat) */ 2511 /* */ 2512 /* Preventing "purge" from occuring is allowed because when all of the NAT */ 2513 /* rules are being removed, allowing the "purge" to walk through the list */ 2514 /* of NAT sessions, possibly multiple times, would be a large performance */ 2515 /* hit, on the order of O(N^2). */ 2516 /* ------------------------------------------------------------------------ */ 2517 static void 2518 ipf_nat_delrule(ipf_main_softc_t *softc, ipf_nat_softc_t *softn, ipnat_t *np, 2519 int purge) 2520 { 2521 2522 if (np->in_pnext != NULL) { 2523 *np->in_pnext = np->in_next; 2524 if (np->in_next != NULL) 2525 np->in_next->in_pnext = np->in_pnext; 2526 if (softn->ipf_nat_list_tail == &np->in_next) 2527 softn->ipf_nat_list_tail = np->in_pnext; 2528 } 2529 2530 if ((purge == 1) && ((np->in_flags & IPN_PURGE) != 0)) { 2531 nat_t *next; 2532 nat_t *nat; 2533 2534 for (next = softn->ipf_nat_instances; (nat = next) != NULL;) { 2535 next = nat->nat_next; 2536 if (nat->nat_ptr == np) 2537 ipf_nat_delete(softc, nat, NL_PURGE); 2538 } 2539 } 2540 2541 if ((np->in_flags & IPN_DELETE) == 0) { 2542 if (np->in_redir & NAT_REDIRECT) { 2543 switch (np->in_v[0]) 2544 { 2545 case 4 : 2546 ipf_nat_delrdr(softn, np); 2547 break; 2548 #ifdef USE_INET6 2549 case 6 : 2550 ipf_nat6_delrdr(softn, np); 2551 break; 2552 #endif 2553 } 2554 } 2555 if (np->in_redir & (NAT_MAPBLK|NAT_MAP)) { 2556 switch (np->in_v[0]) 2557 { 2558 case 4 : 2559 ipf_nat_delmap(softn, np); 2560 break; 2561 #ifdef USE_INET6 2562 case 6 : 2563 ipf_nat6_delmap(softn, np); 2564 break; 2565 #endif 2566 } 2567 } 2568 } 2569 2570 np->in_flags |= IPN_DELETE; 2571 ipf_nat_rule_deref(softc, &np); 2572 } 2573 2574 2575 /* ------------------------------------------------------------------------ */ 2576 /* Function: ipf_nat_newmap */ 2577 /* Returns: int - -1 == error, 0 == success */ 2578 /* Parameters: fin(I) - pointer to packet information */ 2579 /* nat(I) - pointer to NAT entry */ 2580 /* ni(I) - pointer to structure with misc. information needed */ 2581 /* to create new NAT entry. */ 2582 /* */ 2583 /* Given an empty NAT structure, populate it with new information about a */ 2584 /* new NAT session, as defined by the matching NAT rule. */ 2585 /* ni.nai_ip is passed in uninitialised and must be set, in host byte order,*/ 2586 /* to the new IP address for the translation. */ 2587 /* ------------------------------------------------------------------------ */ 2588 static int 2589 ipf_nat_newmap(fr_info_t *fin, nat_t *nat, natinfo_t *ni) 2590 { 2591 ipf_main_softc_t *softc = fin->fin_main_soft; 2592 ipf_nat_softc_t *softn = softc->ipf_nat_soft; 2593 u_short st_port, dport, sport, port, sp, dp; 2594 struct in_addr in, inb; 2595 hostmap_t *hm; 2596 u_32_t flags; 2597 u_32_t st_ip; 2598 ipnat_t *np; 2599 nat_t *natl; 2600 int l; 2601 2602 /* 2603 * If it's an outbound packet which doesn't match any existing 2604 * record, then create a new port 2605 */ 2606 l = 0; 2607 hm = NULL; 2608 np = ni->nai_np; 2609 st_ip = np->in_snip; 2610 st_port = np->in_spnext; 2611 flags = nat->nat_flags; 2612 2613 if (flags & IPN_ICMPQUERY) { 2614 sport = fin->fin_data[1]; 2615 dport = 0; 2616 } else { 2617 sport = htons(fin->fin_data[0]); 2618 dport = htons(fin->fin_data[1]); 2619 } 2620 2621 /* 2622 * Do a loop until we either run out of entries to try or we find 2623 * a NAT mapping that isn't currently being used. This is done 2624 * because the change to the source is not (usually) being fixed. 2625 */ 2626 do { 2627 port = 0; 2628 in.s_addr = htonl(np->in_snip); 2629 if (l == 0) { 2630 /* 2631 * Check to see if there is an existing NAT 2632 * setup for this IP address pair. 2633 */ 2634 hm = ipf_nat_hostmap(softn, np, fin->fin_src, 2635 fin->fin_dst, in, 0); 2636 if (hm != NULL) 2637 in.s_addr = hm->hm_nsrcip.s_addr; 2638 } else if ((l == 1) && (hm != NULL)) { 2639 ipf_nat_hostmapdel(softc, &hm); 2640 } 2641 in.s_addr = ntohl(in.s_addr); 2642 2643 nat->nat_hm = hm; 2644 2645 if ((np->in_nsrcmsk == 0xffffffff) && (np->in_spnext == 0)) { 2646 if (l > 0) { 2647 NBUMPSIDEX(1, ns_exhausted, ns_exhausted_1); 2648 return -1; 2649 } 2650 } 2651 2652 if (np->in_redir == NAT_BIMAP && 2653 np->in_osrcmsk == np->in_nsrcmsk) { 2654 /* 2655 * map the address block in a 1:1 fashion 2656 */ 2657 in.s_addr = np->in_nsrcaddr; 2658 in.s_addr |= fin->fin_saddr & ~np->in_osrcmsk; 2659 in.s_addr = ntohl(in.s_addr); 2660 2661 } else if (np->in_redir & NAT_MAPBLK) { 2662 if ((l >= np->in_ppip) || ((l > 0) && 2663 !(flags & IPN_TCPUDP))) { 2664 NBUMPSIDEX(1, ns_exhausted, ns_exhausted_2); 2665 return -1; 2666 } 2667 /* 2668 * map-block - Calculate destination address. 2669 */ 2670 in.s_addr = ntohl(fin->fin_saddr); 2671 in.s_addr &= ntohl(~np->in_osrcmsk); 2672 inb.s_addr = in.s_addr; 2673 in.s_addr /= np->in_ippip; 2674 in.s_addr &= ntohl(~np->in_nsrcmsk); 2675 in.s_addr += ntohl(np->in_nsrcaddr); 2676 /* 2677 * Calculate destination port. 2678 */ 2679 if ((flags & IPN_TCPUDP) && 2680 (np->in_ppip != 0)) { 2681 port = ntohs(sport) + l; 2682 port %= np->in_ppip; 2683 port += np->in_ppip * 2684 (inb.s_addr % np->in_ippip); 2685 port += MAPBLK_MINPORT; 2686 port = htons(port); 2687 } 2688 2689 } else if ((np->in_nsrcaddr == 0) && 2690 (np->in_nsrcmsk == 0xffffffff)) { 2691 i6addr_t in6; 2692 2693 /* 2694 * 0/32 - use the interface's IP address. 2695 */ 2696 if ((l > 0) || 2697 ipf_ifpaddr(softc, 4, FRI_NORMAL, fin->fin_ifp, 2698 &in6, NULL) == -1) { 2699 NBUMPSIDEX(1, ns_new_ifpaddr, ns_new_ifpaddr_1); 2700 return -1; 2701 } 2702 in.s_addr = ntohl(in6.in4.s_addr); 2703 2704 } else if ((np->in_nsrcaddr == 0) && (np->in_nsrcmsk == 0)) { 2705 /* 2706 * 0/0 - use the original source address/port. 2707 */ 2708 if (l > 0) { 2709 NBUMPSIDEX(1, ns_exhausted, ns_exhausted_3); 2710 return -1; 2711 } 2712 in.s_addr = ntohl(fin->fin_saddr); 2713 2714 } else if ((np->in_nsrcmsk != 0xffffffff) && 2715 (np->in_spnext == 0) && ((l > 0) || (hm == NULL))) 2716 np->in_snip++; 2717 2718 natl = NULL; 2719 2720 if ((flags & IPN_TCPUDP) && 2721 ((np->in_redir & NAT_MAPBLK) == 0) && 2722 (np->in_flags & IPN_AUTOPORTMAP)) { 2723 /* 2724 * "ports auto" (without map-block) 2725 */ 2726 if ((l > 0) && np->in_ppip && (l % np->in_ppip == 0)) { 2727 if (l > np->in_space) { 2728 return -1; 2729 } else if ((l > np->in_ppip) && 2730 np->in_nsrcmsk != 0xffffffff) 2731 np->in_snip++; 2732 } 2733 if (np->in_ppip != 0) { 2734 port = ntohs(sport); 2735 port += (l % np->in_ppip); 2736 port %= np->in_ppip; 2737 port += np->in_ppip * 2738 (ntohl(fin->fin_saddr) % 2739 np->in_ippip); 2740 port += MAPBLK_MINPORT; 2741 port = htons(port); 2742 } 2743 2744 } else if (((np->in_redir & NAT_MAPBLK) == 0) && 2745 (flags & IPN_TCPUDPICMP) && (np->in_spnext != 0)) { 2746 /* 2747 * Standard port translation. Select next port. 2748 */ 2749 if (np->in_flags & IPN_SEQUENTIAL) { 2750 port = np->in_spnext; 2751 } else { 2752 port = ipf_random() % (np->in_spmax - 2753 np->in_spmin + 1); 2754 port += np->in_spmin; 2755 } 2756 port = htons(port); 2757 np->in_spnext++; 2758 2759 if (np->in_spnext > np->in_spmax) { 2760 np->in_spnext = np->in_spmin; 2761 if (np->in_nsrcmsk != 0xffffffff) 2762 np->in_snip++; 2763 } 2764 } 2765 2766 if (np->in_flags & IPN_SIPRANGE) { 2767 if (np->in_snip > ntohl(np->in_nsrcmsk)) 2768 np->in_snip = ntohl(np->in_nsrcaddr); 2769 } else { 2770 if ((np->in_nsrcmsk != 0xffffffff) && 2771 ((np->in_snip + 1) & ntohl(np->in_nsrcmsk)) > 2772 ntohl(np->in_nsrcaddr)) 2773 np->in_snip = ntohl(np->in_nsrcaddr) + 1; 2774 } 2775 2776 if ((port == 0) && (flags & (IPN_TCPUDPICMP|IPN_ICMPQUERY))) 2777 port = sport; 2778 2779 /* 2780 * Here we do a lookup of the connection as seen from 2781 * the outside. If an IP# pair already exists, try 2782 * again. So if you have A->B becomes C->B, you can 2783 * also have D->E become C->E but not D->B causing 2784 * another C->B. Also take protocol and ports into 2785 * account when determining whether a pre-existing 2786 * NAT setup will cause an external conflict where 2787 * this is appropriate. 2788 */ 2789 inb.s_addr = htonl(in.s_addr); 2790 sp = fin->fin_data[0]; 2791 dp = fin->fin_data[1]; 2792 fin->fin_data[0] = fin->fin_data[1]; 2793 fin->fin_data[1] = ntohs(port); 2794 natl = ipf_nat_inlookup(fin, flags & ~(SI_WILDP|NAT_SEARCH), 2795 (u_int)fin->fin_p, fin->fin_dst, inb); 2796 fin->fin_data[0] = sp; 2797 fin->fin_data[1] = dp; 2798 2799 /* 2800 * Has the search wrapped around and come back to the 2801 * start ? 2802 */ 2803 if ((natl != NULL) && 2804 (np->in_spnext != 0) && (st_port == np->in_spnext) && 2805 (np->in_snip != 0) && (st_ip == np->in_snip)) { 2806 NBUMPSIDED(1, ns_wrap); 2807 return -1; 2808 } 2809 l++; 2810 } while (natl != NULL); 2811 2812 /* Setup the NAT table */ 2813 nat->nat_osrcip = fin->fin_src; 2814 nat->nat_nsrcaddr = htonl(in.s_addr); 2815 nat->nat_odstip = fin->fin_dst; 2816 nat->nat_ndstip = fin->fin_dst; 2817 if (nat->nat_hm == NULL) 2818 nat->nat_hm = ipf_nat_hostmap(softn, np, fin->fin_src, 2819 fin->fin_dst, nat->nat_nsrcip, 2820 0); 2821 2822 if (flags & IPN_TCPUDP) { 2823 nat->nat_osport = sport; 2824 nat->nat_nsport = port; /* sport */ 2825 nat->nat_odport = dport; 2826 nat->nat_ndport = dport; 2827 ((tcphdr_t *)fin->fin_dp)->th_sport = port; 2828 } else if (flags & IPN_ICMPQUERY) { 2829 nat->nat_oicmpid = fin->fin_data[1]; 2830 ((icmphdr_t *)fin->fin_dp)->icmp_id = port; 2831 nat->nat_nicmpid = port; 2832 } 2833 return 0; 2834 } 2835 2836 2837 /* ------------------------------------------------------------------------ */ 2838 /* Function: ipf_nat_newrdr */ 2839 /* Returns: int - -1 == error, 0 == success (no move), 1 == success and */ 2840 /* allow rule to be moved if IPN_ROUNDR is set. */ 2841 /* Parameters: fin(I) - pointer to packet information */ 2842 /* nat(I) - pointer to NAT entry */ 2843 /* ni(I) - pointer to structure with misc. information needed */ 2844 /* to create new NAT entry. */ 2845 /* */ 2846 /* ni.nai_ip is passed in uninitialised and must be set, in host byte order,*/ 2847 /* to the new IP address for the translation. */ 2848 /* ------------------------------------------------------------------------ */ 2849 static int 2850 ipf_nat_newrdr(fr_info_t *fin, nat_t *nat, natinfo_t *ni) 2851 { 2852 ipf_main_softc_t *softc = fin->fin_main_soft; 2853 ipf_nat_softc_t *softn = softc->ipf_nat_soft; 2854 u_short nport, dport, sport; 2855 struct in_addr in, inb; 2856 u_short sp, dp; 2857 hostmap_t *hm; 2858 u_32_t flags; 2859 ipnat_t *np; 2860 nat_t *natl; 2861 int move; 2862 2863 move = 1; 2864 hm = NULL; 2865 in.s_addr = 0; 2866 np = ni->nai_np; 2867 flags = nat->nat_flags; 2868 2869 if (flags & IPN_ICMPQUERY) { 2870 dport = fin->fin_data[1]; 2871 sport = 0; 2872 } else { 2873 sport = htons(fin->fin_data[0]); 2874 dport = htons(fin->fin_data[1]); 2875 } 2876 2877 /* TRACE sport, dport */ 2878 2879 2880 /* 2881 * If the matching rule has IPN_STICKY set, then we want to have the 2882 * same rule kick in as before. Why would this happen? If you have 2883 * a collection of rdr rules with "round-robin sticky", the current 2884 * packet might match a different one to the previous connection but 2885 * we want the same destination to be used. 2886 */ 2887 if (((np->in_flags & (IPN_ROUNDR|IPN_SPLIT)) != 0) && 2888 ((np->in_flags & IPN_STICKY) != 0)) { 2889 hm = ipf_nat_hostmap(softn, NULL, fin->fin_src, fin->fin_dst, 2890 in, (u_32_t)dport); 2891 if (hm != NULL) { 2892 in.s_addr = ntohl(hm->hm_ndstip.s_addr); 2893 np = hm->hm_ipnat; 2894 ni->nai_np = np; 2895 move = 0; 2896 ipf_nat_hostmapdel(softc, &hm); 2897 } 2898 } 2899 2900 /* 2901 * Otherwise, it's an inbound packet. Most likely, we don't 2902 * want to rewrite source ports and source addresses. Instead, 2903 * we want to rewrite to a fixed internal address and fixed 2904 * internal port. 2905 */ 2906 if (np->in_flags & IPN_SPLIT) { 2907 in.s_addr = np->in_dnip; 2908 inb.s_addr = htonl(in.s_addr); 2909 2910 if ((np->in_flags & (IPN_ROUNDR|IPN_STICKY)) == IPN_STICKY) { 2911 hm = ipf_nat_hostmap(softn, NULL, fin->fin_src, 2912 fin->fin_dst, inb, (u_32_t)dport); 2913 if (hm != NULL) { 2914 in.s_addr = hm->hm_ndstip.s_addr; 2915 move = 0; 2916 } 2917 } 2918 2919 if (hm == NULL || hm->hm_ref == 1) { 2920 if (np->in_ndstaddr == htonl(in.s_addr)) { 2921 np->in_dnip = ntohl(np->in_ndstmsk); 2922 move = 0; 2923 } else { 2924 np->in_dnip = ntohl(np->in_ndstaddr); 2925 } 2926 } 2927 if (hm != NULL) 2928 ipf_nat_hostmapdel(softc, &hm); 2929 2930 } else if ((np->in_ndstaddr == 0) && (np->in_ndstmsk == 0xffffffff)) { 2931 i6addr_t in6; 2932 2933 /* 2934 * 0/32 - use the interface's IP address. 2935 */ 2936 if (ipf_ifpaddr(softc, 4, FRI_NORMAL, fin->fin_ifp, 2937 &in6, NULL) == -1) { 2938 NBUMPSIDEX(0, ns_new_ifpaddr, ns_new_ifpaddr_2); 2939 return -1; 2940 } 2941 in.s_addr = ntohl(in6.in4.s_addr); 2942 2943 } else if ((np->in_ndstaddr == 0) && (np->in_ndstmsk== 0)) { 2944 /* 2945 * 0/0 - use the original destination address/port. 2946 */ 2947 in.s_addr = ntohl(fin->fin_daddr); 2948 2949 } else if (np->in_redir == NAT_BIMAP && 2950 np->in_ndstmsk == np->in_odstmsk) { 2951 /* 2952 * map the address block in a 1:1 fashion 2953 */ 2954 in.s_addr = np->in_ndstaddr; 2955 in.s_addr |= fin->fin_daddr & ~np->in_ndstmsk; 2956 in.s_addr = ntohl(in.s_addr); 2957 } else { 2958 in.s_addr = ntohl(np->in_ndstaddr); 2959 } 2960 2961 if ((np->in_dpnext == 0) || ((flags & NAT_NOTRULEPORT) != 0)) 2962 nport = dport; 2963 else { 2964 /* 2965 * Whilst not optimized for the case where 2966 * pmin == pmax, the gain is not significant. 2967 */ 2968 if (((np->in_flags & IPN_FIXEDDPORT) == 0) && 2969 (np->in_odport != np->in_dtop)) { 2970 nport = ntohs(dport) - np->in_odport + np->in_dpmax; 2971 nport = htons(nport); 2972 } else { 2973 nport = htons(np->in_dpnext); 2974 np->in_dpnext++; 2975 if (np->in_dpnext > np->in_dpmax) 2976 np->in_dpnext = np->in_dpmin; 2977 } 2978 } 2979 2980 /* 2981 * When the redirect-to address is set to 0.0.0.0, just 2982 * assume a blank `forwarding' of the packet. We don't 2983 * setup any translation for this either. 2984 */ 2985 if (in.s_addr == 0) { 2986 if (nport == dport) { 2987 NBUMPSIDED(0, ns_xlate_null); 2988 return -1; 2989 } 2990 in.s_addr = ntohl(fin->fin_daddr); 2991 } 2992 2993 /* 2994 * Check to see if this redirect mapping already exists and if 2995 * it does, return "failure" (allowing it to be created will just 2996 * cause one or both of these "connections" to stop working.) 2997 */ 2998 inb.s_addr = htonl(in.s_addr); 2999 sp = fin->fin_data[0]; 3000 dp = fin->fin_data[1]; 3001 fin->fin_data[1] = fin->fin_data[0]; 3002 fin->fin_data[0] = ntohs(nport); 3003 natl = ipf_nat_outlookup(fin, flags & ~(SI_WILDP|NAT_SEARCH), 3004 (u_int)fin->fin_p, inb, fin->fin_src); 3005 fin->fin_data[0] = sp; 3006 fin->fin_data[1] = dp; 3007 if (natl != NULL) { 3008 DT2(ns_new_xlate_exists, fr_info_t *, fin, nat_t *, natl); 3009 NBUMPSIDE(0, ns_xlate_exists); 3010 return -1; 3011 } 3012 3013 nat->nat_ndstaddr = htonl(in.s_addr); 3014 nat->nat_odstip = fin->fin_dst; 3015 nat->nat_nsrcip = fin->fin_src; 3016 nat->nat_osrcip = fin->fin_src; 3017 if ((nat->nat_hm == NULL) && ((np->in_flags & IPN_STICKY) != 0)) 3018 nat->nat_hm = ipf_nat_hostmap(softn, np, fin->fin_src, 3019 fin->fin_dst, inb, (u_32_t)dport); 3020 3021 if (flags & IPN_TCPUDP) { 3022 nat->nat_odport = dport; 3023 nat->nat_ndport = nport; 3024 nat->nat_osport = sport; 3025 nat->nat_nsport = sport; 3026 ((tcphdr_t *)fin->fin_dp)->th_dport = nport; 3027 } else if (flags & IPN_ICMPQUERY) { 3028 nat->nat_oicmpid = fin->fin_data[1]; 3029 ((icmphdr_t *)fin->fin_dp)->icmp_id = nport; 3030 nat->nat_nicmpid = nport; 3031 } 3032 3033 return move; 3034 } 3035 3036 /* ------------------------------------------------------------------------ */ 3037 /* Function: ipf_nat_add */ 3038 /* Returns: nat_t* - NULL == failure to create new NAT structure, */ 3039 /* else pointer to new NAT structure */ 3040 /* Parameters: fin(I) - pointer to packet information */ 3041 /* np(I) - pointer to NAT rule */ 3042 /* natsave(I) - pointer to where to store NAT struct pointer */ 3043 /* flags(I) - flags describing the current packet */ 3044 /* direction(I) - direction of packet (in/out) */ 3045 /* Write Lock: ipf_nat */ 3046 /* */ 3047 /* Attempts to create a new NAT entry. Does not actually change the packet */ 3048 /* in any way. */ 3049 /* */ 3050 /* This function is in three main parts: (1) deal with creating a new NAT */ 3051 /* structure for a "MAP" rule (outgoing NAT translation); (2) deal with */ 3052 /* creating a new NAT structure for a "RDR" rule (incoming NAT translation) */ 3053 /* and (3) building that structure and putting it into the NAT table(s). */ 3054 /* */ 3055 /* NOTE: natsave should NOT be used to point back to an ipstate_t struct */ 3056 /* as it can result in memory being corrupted. */ 3057 /* ------------------------------------------------------------------------ */ 3058 nat_t * 3059 ipf_nat_add(fr_info_t *fin, ipnat_t *np, nat_t **natsave, u_int flags, 3060 int direction) 3061 { 3062 ipf_main_softc_t *softc = fin->fin_main_soft; 3063 ipf_nat_softc_t *softn = softc->ipf_nat_soft; 3064 hostmap_t *hm = NULL; 3065 nat_t *nat, *natl; 3066 natstat_t *nsp; 3067 u_int nflags; 3068 natinfo_t ni; 3069 int move; 3070 3071 memset(&ni, 0, sizeof ni); /* XXX gcc */ 3072 nsp = &softn->ipf_nat_stats; 3073 3074 if ((nsp->ns_active * 100 / softn->ipf_nat_table_max) > 3075 softn->ipf_nat_table_wm_high) { 3076 softn->ipf_nat_doflush = 1; 3077 } 3078 3079 if (nsp->ns_active >= softn->ipf_nat_table_max) { 3080 NBUMPSIDED(fin->fin_out, ns_table_max); 3081 return NULL; 3082 } 3083 3084 move = 1; 3085 nflags = np->in_flags & flags; 3086 nflags &= NAT_FROMRULE; 3087 3088 ni.nai_np = np; 3089 ni.nai_dport = 0; 3090 ni.nai_sport = 0; 3091 3092 /* Give me a new nat */ 3093 KMALLOC(nat, nat_t *); 3094 if (nat == NULL) { 3095 NBUMPSIDED(fin->fin_out, ns_memfail); 3096 /* 3097 * Try to automatically tune the max # of entries in the 3098 * table allowed to be less than what will cause kmem_alloc() 3099 * to fail and try to eliminate panics due to out of memory 3100 * conditions arising. 3101 */ 3102 if ((softn->ipf_nat_table_max > softn->ipf_nat_table_sz) && 3103 (nsp->ns_active > 100)) { 3104 softn->ipf_nat_table_max = nsp->ns_active - 100; 3105 printf("table_max reduced to %d\n", 3106 softn->ipf_nat_table_max); 3107 } 3108 return NULL; 3109 } 3110 3111 if (flags & IPN_ICMPQUERY) { 3112 /* 3113 * In the ICMP query NAT code, we translate the ICMP id fields 3114 * to make them unique. This is indepedent of the ICMP type 3115 * (e.g. in the unlikely event that a host sends an echo and 3116 * a tstamp request with the same id, both packets will have 3117 * their ip address/id field changed in the same way). 3118 */ 3119 /* The icmp_id field is used by the sender to identify the 3120 * process making the icmp request. (the receiver justs 3121 * copies it back in its response). So, it closely matches 3122 * the concept of source port. We overlay sport, so we can 3123 * maximally reuse the existing code. 3124 */ 3125 ni.nai_sport = fin->fin_data[1]; 3126 ni.nai_dport = 0; 3127 } 3128 3129 bzero((char *)nat, sizeof(*nat)); 3130 nat->nat_flags = flags; 3131 nat->nat_redir = np->in_redir; 3132 nat->nat_dir = direction; 3133 nat->nat_pr[0] = fin->fin_p; 3134 nat->nat_pr[1] = fin->fin_p; 3135 3136 /* 3137 * Search the current table for a match and create a new mapping 3138 * if there is none found. 3139 */ 3140 if (np->in_redir & NAT_DIVERTUDP) { 3141 move = ipf_nat_newdivert(fin, nat, &ni); 3142 3143 } else if (np->in_redir & NAT_REWRITE) { 3144 move = ipf_nat_newrewrite(fin, nat, &ni); 3145 3146 } else if (direction == NAT_OUTBOUND) { 3147 /* 3148 * We can now arrange to call this for the same connection 3149 * because ipf_nat_new doesn't protect the code path into 3150 * this function. 3151 */ 3152 natl = ipf_nat_outlookup(fin, nflags, (u_int)fin->fin_p, 3153 fin->fin_src, fin->fin_dst); 3154 if (natl != NULL) { 3155 KFREE(nat); 3156 nat = natl; 3157 goto done; 3158 } 3159 3160 move = ipf_nat_newmap(fin, nat, &ni); 3161 } else { 3162 /* 3163 * NAT_INBOUND is used for redirects rules 3164 */ 3165 natl = ipf_nat_inlookup(fin, nflags, (u_int)fin->fin_p, 3166 fin->fin_src, fin->fin_dst); 3167 if (natl != NULL) { 3168 KFREE(nat); 3169 nat = natl; 3170 goto done; 3171 } 3172 3173 move = ipf_nat_newrdr(fin, nat, &ni); 3174 } 3175 if (move == -1) 3176 goto badnat; 3177 3178 np = ni.nai_np; 3179 3180 nat->nat_mssclamp = np->in_mssclamp; 3181 nat->nat_me = natsave; 3182 nat->nat_fr = fin->fin_fr; 3183 nat->nat_rev = fin->fin_rev; 3184 nat->nat_ptr = np; 3185 nat->nat_dlocal = np->in_dlocal; 3186 3187 if ((np->in_apr != NULL) && ((nat->nat_flags & NAT_SLAVE) == 0)) { 3188 if (ipf_proxy_new(fin, nat) == -1) { 3189 NBUMPSIDED(fin->fin_out, ns_appr_fail); 3190 goto badnat; 3191 } 3192 } 3193 3194 nat->nat_ifps[0] = np->in_ifps[0]; 3195 if (np->in_ifps[0] != NULL) { 3196 COPYIFNAME(np->in_v[0], np->in_ifps[0], nat->nat_ifnames[0]); 3197 } 3198 3199 nat->nat_ifps[1] = np->in_ifps[1]; 3200 if (np->in_ifps[1] != NULL) { 3201 COPYIFNAME(np->in_v[1], np->in_ifps[1], nat->nat_ifnames[1]); 3202 } 3203 3204 if (ipf_nat_finalise(fin, nat) == -1) { 3205 goto badnat; 3206 } 3207 3208 np->in_use++; 3209 3210 if ((move == 1) && (np->in_flags & IPN_ROUNDR)) { 3211 if ((np->in_redir & (NAT_REDIRECT|NAT_MAP)) == NAT_REDIRECT) { 3212 ipf_nat_delrdr(softn, np); 3213 ipf_nat_addrdr(softn, np); 3214 } else if ((np->in_redir & (NAT_REDIRECT|NAT_MAP)) == NAT_MAP) { 3215 ipf_nat_delmap(softn, np); 3216 ipf_nat_addmap(softn, np); 3217 } 3218 } 3219 3220 if (flags & SI_WILDP) 3221 nsp->ns_wilds++; 3222 nsp->ns_proto[nat->nat_pr[0]]++; 3223 3224 goto done; 3225 badnat: 3226 DT2(ns_badnatnew, fr_info_t *, fin, nat_t *, nat); 3227 NBUMPSIDE(fin->fin_out, ns_badnatnew); 3228 if ((hm = nat->nat_hm) != NULL) 3229 ipf_nat_hostmapdel(softc, &hm); 3230 KFREE(nat); 3231 nat = NULL; 3232 done: 3233 if (nat != NULL && np != NULL) 3234 np->in_hits++; 3235 if (natsave != NULL) 3236 *natsave = nat; 3237 return nat; 3238 } 3239 3240 3241 /* ------------------------------------------------------------------------ */ 3242 /* Function: ipf_nat_finalise */ 3243 /* Returns: int - 0 == sucess, -1 == failure */ 3244 /* Parameters: fin(I) - pointer to packet information */ 3245 /* nat(I) - pointer to NAT entry */ 3246 /* Write Lock: ipf_nat */ 3247 /* */ 3248 /* This is the tail end of constructing a new NAT entry and is the same */ 3249 /* for both IPv4 and IPv6. */ 3250 /* ------------------------------------------------------------------------ */ 3251 /*ARGSUSED*/ 3252 static int 3253 ipf_nat_finalise(fr_info_t *fin, nat_t *nat) 3254 { 3255 ipf_main_softc_t *softc = fin->fin_main_soft; 3256 ipf_nat_softc_t *softn = softc->ipf_nat_soft; 3257 u_32_t sum1, sum2, sumd; 3258 frentry_t *fr; 3259 #if SOLARIS && defined(_KERNEL) && (SOLARIS2 >= 6) && defined(ICK_M_CTL_MAGIC) 3260 qpktinfo_t *qpi = fin->fin_qpi; 3261 #endif 3262 3263 switch (nat->nat_pr[0]) 3264 { 3265 case IPPROTO_ICMP : 3266 sum1 = LONG_SUM(ntohs(nat->nat_oicmpid)); 3267 sum2 = LONG_SUM(ntohs(nat->nat_nicmpid)); 3268 CALC_SUMD(sum1, sum2, sumd); 3269 nat->nat_sumd[0] = (sumd & 0xffff) + (sumd >> 16); 3270 3271 break; 3272 3273 default : 3274 sum1 = LONG_SUM(ntohl(nat->nat_osrcaddr) + \ 3275 ntohs(nat->nat_osport)); 3276 sum2 = LONG_SUM(ntohl(nat->nat_nsrcaddr) + \ 3277 ntohs(nat->nat_nsport)); 3278 CALC_SUMD(sum1, sum2, sumd); 3279 nat->nat_sumd[0] = (sumd & 0xffff) + (sumd >> 16); 3280 3281 sum1 = LONG_SUM(ntohl(nat->nat_odstaddr) + \ 3282 ntohs(nat->nat_odport)); 3283 sum2 = LONG_SUM(ntohl(nat->nat_ndstaddr) + \ 3284 ntohs(nat->nat_ndport)); 3285 CALC_SUMD(sum1, sum2, sumd); 3286 nat->nat_sumd[0] += (sumd & 0xffff) + (sumd >> 16); 3287 break; 3288 } 3289 3290 /* 3291 * Compute the partial checksum, just in case. 3292 * This is only ever placed into outbound packets so care needs 3293 * to be taken over which pair of addresses are used. 3294 */ 3295 if (nat->nat_dir == NAT_OUTBOUND) { 3296 sum1 = LONG_SUM(ntohl(nat->nat_nsrcaddr)); 3297 sum1 += LONG_SUM(ntohl(nat->nat_ndstaddr)); 3298 } else { 3299 sum1 = LONG_SUM(ntohl(nat->nat_osrcaddr)); 3300 sum1 += LONG_SUM(ntohl(nat->nat_odstaddr)); 3301 } 3302 sum1 += nat->nat_pr[1]; 3303 nat->nat_sumd[1] = (sum1 & 0xffff) + (sum1 >> 16); 3304 3305 sum1 = LONG_SUM(ntohl(nat->nat_osrcaddr)); 3306 sum2 = LONG_SUM(ntohl(nat->nat_nsrcaddr)); 3307 CALC_SUMD(sum1, sum2, sumd); 3308 nat->nat_ipsumd = (sumd & 0xffff) + (sumd >> 16); 3309 3310 sum1 = LONG_SUM(ntohl(nat->nat_odstaddr)); 3311 sum2 = LONG_SUM(ntohl(nat->nat_ndstaddr)); 3312 CALC_SUMD(sum1, sum2, sumd); 3313 nat->nat_ipsumd += (sumd & 0xffff) + (sumd >> 16); 3314 3315 nat->nat_v[0] = 4; 3316 nat->nat_v[1] = 4; 3317 3318 if ((nat->nat_ifps[0] != NULL) && (nat->nat_ifps[0] != (void *)-1)) { 3319 nat->nat_mtu[0] = GETIFMTU_4(nat->nat_ifps[0]); 3320 } 3321 3322 if ((nat->nat_ifps[1] != NULL) && (nat->nat_ifps[1] != (void *)-1)) { 3323 nat->nat_mtu[1] = GETIFMTU_4(nat->nat_ifps[1]); 3324 } 3325 3326 if ((nat->nat_flags & SI_CLONE) == 0) 3327 nat->nat_sync = ipf_sync_new(softc, SMC_NAT, fin, nat); 3328 3329 if (ipf_nat_insert(softc, softn, nat) == 0) { 3330 if (softn->ipf_nat_logging) 3331 ipf_nat_log(softc, softn, nat, NL_NEW); 3332 fr = nat->nat_fr; 3333 if (fr != NULL) { 3334 MUTEX_ENTER(&fr->fr_lock); 3335 fr->fr_ref++; 3336 MUTEX_EXIT(&fr->fr_lock); 3337 } 3338 return 0; 3339 } 3340 3341 NBUMPSIDED(fin->fin_out, ns_unfinalised); 3342 /* 3343 * nat_insert failed, so cleanup time... 3344 */ 3345 if (nat->nat_sync != NULL) 3346 ipf_sync_del_nat(softc->ipf_sync_soft, nat->nat_sync); 3347 return -1; 3348 } 3349 3350 3351 /* ------------------------------------------------------------------------ */ 3352 /* Function: ipf_nat_insert */ 3353 /* Returns: int - 0 == sucess, -1 == failure */ 3354 /* Parameters: softc(I) - pointer to soft context main structure */ 3355 /* softn(I) - pointer to NAT context structure */ 3356 /* nat(I) - pointer to NAT structure */ 3357 /* Write Lock: ipf_nat */ 3358 /* */ 3359 /* Insert a NAT entry into the hash tables for searching and add it to the */ 3360 /* list of active NAT entries. Adjust global counters when complete. */ 3361 /* ------------------------------------------------------------------------ */ 3362 int 3363 ipf_nat_insert(ipf_main_softc_t *softc, ipf_nat_softc_t *softn, nat_t *nat) 3364 { 3365 u_int hv0, hv1; 3366 u_int sp, dp; 3367 ipnat_t *in; 3368 int ret; 3369 3370 /* 3371 * Try and return an error as early as possible, so calculate the hash 3372 * entry numbers first and then proceed. 3373 */ 3374 if ((nat->nat_flags & (SI_W_SPORT|SI_W_DPORT)) == 0) { 3375 if ((nat->nat_flags & IPN_TCPUDP) != 0) { 3376 sp = nat->nat_osport; 3377 dp = nat->nat_odport; 3378 } else if ((nat->nat_flags & IPN_ICMPQUERY) != 0) { 3379 sp = 0; 3380 dp = nat->nat_oicmpid; 3381 } else { 3382 sp = 0; 3383 dp = 0; 3384 } 3385 hv0 = NAT_HASH_FN(nat->nat_osrcaddr, sp, 0xffffffff); 3386 hv0 = NAT_HASH_FN(nat->nat_odstaddr, hv0 + dp, 0xffffffff); 3387 /* 3388 * TRACE nat_osrcaddr, nat_osport, nat_odstaddr, 3389 * nat_odport, hv0 3390 */ 3391 3392 if ((nat->nat_flags & IPN_TCPUDP) != 0) { 3393 sp = nat->nat_nsport; 3394 dp = nat->nat_ndport; 3395 } else if ((nat->nat_flags & IPN_ICMPQUERY) != 0) { 3396 sp = 0; 3397 dp = nat->nat_nicmpid; 3398 } else { 3399 sp = 0; 3400 dp = 0; 3401 } 3402 hv1 = NAT_HASH_FN(nat->nat_nsrcaddr, sp, 0xffffffff); 3403 hv1 = NAT_HASH_FN(nat->nat_ndstaddr, hv1 + dp, 0xffffffff); 3404 /* 3405 * TRACE nat_nsrcaddr, nat_nsport, nat_ndstaddr, 3406 * nat_ndport, hv1 3407 */ 3408 } else { 3409 hv0 = NAT_HASH_FN(nat->nat_osrcaddr, 0, 0xffffffff); 3410 hv0 = NAT_HASH_FN(nat->nat_odstaddr, hv0, 0xffffffff); 3411 /* TRACE nat_osrcaddr, nat_odstaddr, hv0 */ 3412 3413 hv1 = NAT_HASH_FN(nat->nat_nsrcaddr, 0, 0xffffffff); 3414 hv1 = NAT_HASH_FN(nat->nat_ndstaddr, hv1, 0xffffffff); 3415 /* TRACE nat_nsrcaddr, nat_ndstaddr, hv1 */ 3416 } 3417 3418 if ((nat->nat_dir & NAT_OUTBOUND) == NAT_OUTBOUND) { 3419 nat->nat_hv[0] = hv0; 3420 nat->nat_hv[1] = hv1; 3421 } else { 3422 nat->nat_hv[0] = hv1; 3423 nat->nat_hv[1] = hv0; 3424 } 3425 3426 MUTEX_INIT(&nat->nat_lock, "nat entry lock"); 3427 3428 in = nat->nat_ptr; 3429 nat->nat_ref = nat->nat_me ? 2 : 1; 3430 3431 nat->nat_ifnames[0][LIFNAMSIZ - 1] = '\0'; 3432 nat->nat_ifps[0] = ipf_resolvenic(softc, nat->nat_ifnames[0], 4); 3433 3434 if (nat->nat_ifnames[1][0] != '\0') { 3435 nat->nat_ifnames[1][LIFNAMSIZ - 1] = '\0'; 3436 nat->nat_ifps[1] = ipf_resolvenic(softc, 3437 nat->nat_ifnames[1], 4); 3438 } else if (in->in_ifnames[1] != -1) { 3439 char *name; 3440 3441 name = in->in_names + in->in_ifnames[1]; 3442 if (name[1] != '\0' && name[0] != '-' && name[0] != '*') { 3443 (void) strncpy(nat->nat_ifnames[1], 3444 nat->nat_ifnames[0], LIFNAMSIZ); 3445 nat->nat_ifnames[1][LIFNAMSIZ - 1] = '\0'; 3446 nat->nat_ifps[1] = nat->nat_ifps[0]; 3447 } 3448 } 3449 if ((nat->nat_ifps[0] != NULL) && (nat->nat_ifps[0] != (void *)-1)) { 3450 nat->nat_mtu[0] = GETIFMTU_4(nat->nat_ifps[0]); 3451 } 3452 if ((nat->nat_ifps[1] != NULL) && (nat->nat_ifps[1] != (void *)-1)) { 3453 nat->nat_mtu[1] = GETIFMTU_4(nat->nat_ifps[1]); 3454 } 3455 3456 ret = ipf_nat_hashtab_add(softc, softn, nat); 3457 if (ret != 0) 3458 MUTEX_DESTROY(&nat->nat_lock); 3459 return ret; 3460 } 3461 3462 3463 /* ------------------------------------------------------------------------ */ 3464 /* Function: ipf_nat_hashtab_add */ 3465 /* Returns: int - 0 == sucess, -1 == failure */ 3466 /* Parameters: softc(I) - pointer to soft context main structure */ 3467 /* softn(I) - pointer to NAT context structure */ 3468 /* nat(I) - pointer to NAT structure */ 3469 /* Write Lock: ipf_nat */ 3470 /* */ 3471 /* Handle the insertion of a NAT entry into the table/list. */ 3472 /* ------------------------------------------------------------------------ */ 3473 int 3474 ipf_nat_hashtab_add(ipf_main_softc_t *softc, ipf_nat_softc_t *softn, nat_t *nat) 3475 { 3476 nat_t **natp; 3477 u_int hv0; 3478 u_int hv1; 3479 3480 hv0 = nat->nat_hv[0] % softn->ipf_nat_table_sz; 3481 hv1 = nat->nat_hv[1] % softn->ipf_nat_table_sz; 3482 3483 if (softn->ipf_nat_stats.ns_side[0].ns_bucketlen[hv0] >= 3484 softn->ipf_nat_maxbucket) { 3485 DT1(ns_bucket_max_0, int, 3486 softn->ipf_nat_stats.ns_side[0].ns_bucketlen[hv0]); 3487 NBUMPSIDE(0, ns_bucket_max); 3488 return -1; 3489 } 3490 3491 if (softn->ipf_nat_stats.ns_side[1].ns_bucketlen[hv1] >= 3492 softn->ipf_nat_maxbucket) { 3493 DT1(ns_bucket_max_1, int, 3494 softn->ipf_nat_stats.ns_side[1].ns_bucketlen[hv1]); 3495 NBUMPSIDE(1, ns_bucket_max); 3496 return -1; 3497 } 3498 3499 /* 3500 * The ordering of operations in the list and hash table insertion 3501 * is very important. The last operation for each task should be 3502 * to update the top of the list, after all the "nexts" have been 3503 * done so that walking the list while it is being done does not 3504 * find strange pointers. 3505 * 3506 * Global list of NAT instances 3507 */ 3508 nat->nat_next = softn->ipf_nat_instances; 3509 nat->nat_pnext = &softn->ipf_nat_instances; 3510 if (softn->ipf_nat_instances) 3511 softn->ipf_nat_instances->nat_pnext = &nat->nat_next; 3512 softn->ipf_nat_instances = nat; 3513 3514 /* 3515 * Inbound hash table. 3516 */ 3517 natp = &softn->ipf_nat_table[0][hv0]; 3518 nat->nat_phnext[0] = natp; 3519 nat->nat_hnext[0] = *natp; 3520 if (*natp) { 3521 (*natp)->nat_phnext[0] = &nat->nat_hnext[0]; 3522 } else { 3523 NBUMPSIDE(0, ns_inuse); 3524 } 3525 *natp = nat; 3526 NBUMPSIDE(0, ns_bucketlen[hv0]); 3527 3528 /* 3529 * Outbound hash table. 3530 */ 3531 natp = &softn->ipf_nat_table[1][hv1]; 3532 nat->nat_phnext[1] = natp; 3533 nat->nat_hnext[1] = *natp; 3534 if (*natp) 3535 (*natp)->nat_phnext[1] = &nat->nat_hnext[1]; 3536 else { 3537 NBUMPSIDE(1, ns_inuse); 3538 } 3539 *natp = nat; 3540 NBUMPSIDE(1, ns_bucketlen[hv1]); 3541 3542 ipf_nat_setqueue(softc, softn, nat); 3543 3544 if (nat->nat_dir & NAT_OUTBOUND) { 3545 NBUMPSIDE(1, ns_added); 3546 } else { 3547 NBUMPSIDE(0, ns_added); 3548 } 3549 softn->ipf_nat_stats.ns_active++; 3550 return 0; 3551 } 3552 3553 3554 /* ------------------------------------------------------------------------ */ 3555 /* Function: ipf_nat_icmperrorlookup */ 3556 /* Returns: nat_t* - point to matching NAT structure */ 3557 /* Parameters: fin(I) - pointer to packet information */ 3558 /* dir(I) - direction of packet (in/out) */ 3559 /* */ 3560 /* Check if the ICMP error message is related to an existing TCP, UDP or */ 3561 /* ICMP query nat entry. It is assumed that the packet is already of the */ 3562 /* the required length. */ 3563 /* ------------------------------------------------------------------------ */ 3564 nat_t * 3565 ipf_nat_icmperrorlookup(fr_info_t *fin, int dir) 3566 { 3567 ipf_main_softc_t *softc = fin->fin_main_soft; 3568 ipf_nat_softc_t *softn = softc->ipf_nat_soft; 3569 int flags = 0, minlen; 3570 icmphdr_t *orgicmp; 3571 nat_stat_side_t *nside; 3572 tcphdr_t *tcp = NULL; 3573 u_short data[2]; 3574 nat_t *nat; 3575 ip_t *oip; 3576 u_int p; 3577 3578 nside = &softn->ipf_nat_stats.ns_side[fin->fin_out]; 3579 /* 3580 * Does it at least have the return (basic) IP header ? 3581 * Only a basic IP header (no options) should be with an ICMP error 3582 * header. Also, if it's not an error type, then return. 3583 */ 3584 if ((fin->fin_hlen != sizeof(ip_t)) || !(fin->fin_flx & FI_ICMPERR)) { 3585 ATOMIC_INCL(nside->ns_icmp_basic); 3586 return NULL; 3587 } 3588 3589 /* 3590 * Check packet size 3591 */ 3592 oip = (ip_t *)((char *)fin->fin_dp + 8); 3593 minlen = IP_HL(oip) << 2; 3594 if ((minlen < sizeof(ip_t)) || 3595 (fin->fin_plen < ICMPERR_IPICMPHLEN + minlen)) { 3596 ATOMIC_INCL(nside->ns_icmp_size); 3597 return NULL; 3598 } 3599 3600 /* 3601 * Is the buffer big enough for all of it ? It's the size of the IP 3602 * header claimed in the encapsulated part which is of concern. It 3603 * may be too big to be in this buffer but not so big that it's 3604 * outside the ICMP packet, leading to TCP deref's causing problems. 3605 * This is possible because we don't know how big oip_hl is when we 3606 * do the pullup early in ipf_check() and thus can't gaurantee it is 3607 * all here now. 3608 */ 3609 #ifdef ipf_nat_KERNEL 3610 { 3611 mb_t *m; 3612 3613 m = fin->fin_m; 3614 # if defined(MENTAT) 3615 if ((char *)oip + fin->fin_dlen - ICMPERR_ICMPHLEN > 3616 (char *)m->b_wptr) { 3617 ATOMIC_INCL(nside->ns_icmp_mbuf); 3618 return NULL; 3619 } 3620 # else 3621 if ((char *)oip + fin->fin_dlen - ICMPERR_ICMPHLEN > 3622 (char *)fin->fin_ip + M_LEN(m)) { 3623 ATOMIC_INCL(nside->ns_icmp_mbuf); 3624 return NULL; 3625 } 3626 # endif 3627 } 3628 #endif 3629 3630 if (fin->fin_daddr != oip->ip_src.s_addr) { 3631 ATOMIC_INCL(nside->ns_icmp_address); 3632 return NULL; 3633 } 3634 3635 p = oip->ip_p; 3636 if (p == IPPROTO_TCP) 3637 flags = IPN_TCP; 3638 else if (p == IPPROTO_UDP) 3639 flags = IPN_UDP; 3640 else if (p == IPPROTO_ICMP) { 3641 orgicmp = (icmphdr_t *)((char *)oip + (IP_HL(oip) << 2)); 3642 3643 /* see if this is related to an ICMP query */ 3644 if (ipf_nat_icmpquerytype(orgicmp->icmp_type)) { 3645 data[0] = fin->fin_data[0]; 3646 data[1] = fin->fin_data[1]; 3647 fin->fin_data[0] = 0; 3648 fin->fin_data[1] = orgicmp->icmp_id; 3649 3650 flags = IPN_ICMPERR|IPN_ICMPQUERY; 3651 /* 3652 * NOTE : dir refers to the direction of the original 3653 * ip packet. By definition the icmp error 3654 * message flows in the opposite direction. 3655 */ 3656 if (dir == NAT_INBOUND) 3657 nat = ipf_nat_inlookup(fin, flags, p, 3658 oip->ip_dst, 3659 oip->ip_src); 3660 else 3661 nat = ipf_nat_outlookup(fin, flags, p, 3662 oip->ip_dst, 3663 oip->ip_src); 3664 fin->fin_data[0] = data[0]; 3665 fin->fin_data[1] = data[1]; 3666 return nat; 3667 } 3668 } 3669 3670 if (flags & IPN_TCPUDP) { 3671 minlen += 8; /* + 64bits of data to get ports */ 3672 /* TRACE (fin,minlen) */ 3673 if (fin->fin_plen < ICMPERR_IPICMPHLEN + minlen) { 3674 ATOMIC_INCL(nside->ns_icmp_short); 3675 return NULL; 3676 } 3677 3678 data[0] = fin->fin_data[0]; 3679 data[1] = fin->fin_data[1]; 3680 tcp = (tcphdr_t *)((char *)oip + (IP_HL(oip) << 2)); 3681 fin->fin_data[0] = ntohs(tcp->th_dport); 3682 fin->fin_data[1] = ntohs(tcp->th_sport); 3683 3684 if (dir == NAT_INBOUND) { 3685 nat = ipf_nat_inlookup(fin, flags, p, oip->ip_dst, 3686 oip->ip_src); 3687 } else { 3688 nat = ipf_nat_outlookup(fin, flags, p, oip->ip_dst, 3689 oip->ip_src); 3690 } 3691 fin->fin_data[0] = data[0]; 3692 fin->fin_data[1] = data[1]; 3693 return nat; 3694 } 3695 if (dir == NAT_INBOUND) 3696 nat = ipf_nat_inlookup(fin, 0, p, oip->ip_dst, oip->ip_src); 3697 else 3698 nat = ipf_nat_outlookup(fin, 0, p, oip->ip_dst, oip->ip_src); 3699 3700 return nat; 3701 } 3702 3703 3704 /* ------------------------------------------------------------------------ */ 3705 /* Function: ipf_nat_icmperror */ 3706 /* Returns: nat_t* - point to matching NAT structure */ 3707 /* Parameters: fin(I) - pointer to packet information */ 3708 /* nflags(I) - NAT flags for this packet */ 3709 /* dir(I) - direction of packet (in/out) */ 3710 /* */ 3711 /* Fix up an ICMP packet which is an error message for an existing NAT */ 3712 /* session. This will correct both packet header data and checksums. */ 3713 /* */ 3714 /* This should *ONLY* be used for incoming ICMP error packets to make sure */ 3715 /* a NAT'd ICMP packet gets correctly recognised. */ 3716 /* ------------------------------------------------------------------------ */ 3717 nat_t * 3718 ipf_nat_icmperror(fr_info_t *fin, u_int *nflags, int dir) 3719 { 3720 ipf_main_softc_t *softc = fin->fin_main_soft; 3721 ipf_nat_softc_t *softn = softc->ipf_nat_soft; 3722 u_32_t sum1, sum2, sumd, sumd2; 3723 struct in_addr a1, a2, a3, a4; 3724 int flags, dlen, odst; 3725 icmphdr_t *icmp; 3726 u_short *csump; 3727 tcphdr_t *tcp; 3728 nat_t *nat; 3729 ip_t *oip; 3730 void *dp; 3731 3732 if ((fin->fin_flx & (FI_SHORT|FI_FRAGBODY))) { 3733 NBUMPSIDED(fin->fin_out, ns_icmp_short); 3734 return NULL; 3735 } 3736 3737 /* 3738 * ipf_nat_icmperrorlookup() will return NULL for `defective' packets. 3739 */ 3740 if ((fin->fin_v != 4) || !(nat = ipf_nat_icmperrorlookup(fin, dir))) { 3741 NBUMPSIDED(fin->fin_out, ns_icmp_notfound); 3742 return NULL; 3743 } 3744 3745 tcp = NULL; 3746 csump = NULL; 3747 flags = 0; 3748 sumd2 = 0; 3749 *nflags = IPN_ICMPERR; 3750 icmp = fin->fin_dp; 3751 oip = (ip_t *)&icmp->icmp_ip; 3752 dp = (((char *)oip) + (IP_HL(oip) << 2)); 3753 if (oip->ip_p == IPPROTO_TCP) { 3754 tcp = (tcphdr_t *)dp; 3755 csump = (u_short *)&tcp->th_sum; 3756 flags = IPN_TCP; 3757 } else if (oip->ip_p == IPPROTO_UDP) { 3758 udphdr_t *udp; 3759 3760 udp = (udphdr_t *)dp; 3761 tcp = (tcphdr_t *)dp; 3762 csump = (u_short *)&udp->uh_sum; 3763 flags = IPN_UDP; 3764 } else if (oip->ip_p == IPPROTO_ICMP) 3765 flags = IPN_ICMPQUERY; 3766 dlen = fin->fin_plen - ((char *)dp - (char *)fin->fin_ip); 3767 3768 /* 3769 * Need to adjust ICMP header to include the real IP#'s and 3770 * port #'s. Only apply a checksum change relative to the 3771 * IP address change as it will be modified again in ipf_nat_checkout 3772 * for both address and port. Two checksum changes are 3773 * necessary for the two header address changes. Be careful 3774 * to only modify the checksum once for the port # and twice 3775 * for the IP#. 3776 */ 3777 3778 /* 3779 * Step 1 3780 * Fix the IP addresses in the offending IP packet. You also need 3781 * to adjust the IP header checksum of that offending IP packet. 3782 * 3783 * Normally, you would expect that the ICMP checksum of the 3784 * ICMP error message needs to be adjusted as well for the 3785 * IP address change in oip. 3786 * However, this is a NOP, because the ICMP checksum is 3787 * calculated over the complete ICMP packet, which includes the 3788 * changed oip IP addresses and oip->ip_sum. However, these 3789 * two changes cancel each other out (if the delta for 3790 * the IP address is x, then the delta for ip_sum is minus x), 3791 * so no change in the icmp_cksum is necessary. 3792 * 3793 * Inbound ICMP 3794 * ------------ 3795 * MAP rule, SRC=a,DST=b -> SRC=c,DST=b 3796 * - response to outgoing packet (a,b)=>(c,b) (OIP_SRC=c,OIP_DST=b) 3797 * - OIP_SRC(c)=nat_newsrcip, OIP_DST(b)=nat_newdstip 3798 *=> OIP_SRC(c)=nat_oldsrcip, OIP_DST(b)=nat_olddstip 3799 * 3800 * RDR rule, SRC=a,DST=b -> SRC=a,DST=c 3801 * - response to outgoing packet (c,a)=>(b,a) (OIP_SRC=b,OIP_DST=a) 3802 * - OIP_SRC(b)=nat_olddstip, OIP_DST(a)=nat_oldsrcip 3803 *=> OIP_SRC(b)=nat_newdstip, OIP_DST(a)=nat_newsrcip 3804 * 3805 * REWRITE out rule, SRC=a,DST=b -> SRC=c,DST=d 3806 * - response to outgoing packet (a,b)=>(c,d) (OIP_SRC=c,OIP_DST=d) 3807 * - OIP_SRC(c)=nat_newsrcip, OIP_DST(d)=nat_newdstip 3808 *=> OIP_SRC(c)=nat_oldsrcip, OIP_DST(d)=nat_olddstip 3809 * 3810 * REWRITE in rule, SRC=a,DST=b -> SRC=c,DST=d 3811 * - response to outgoing packet (d,c)=>(b,a) (OIP_SRC=b,OIP_DST=a) 3812 * - OIP_SRC(b)=nat_olddstip, OIP_DST(a)=nat_oldsrcip 3813 *=> OIP_SRC(b)=nat_newdstip, OIP_DST(a)=nat_newsrcip 3814 * 3815 * Outbound ICMP 3816 * ------------- 3817 * MAP rule, SRC=a,DST=b -> SRC=c,DST=b 3818 * - response to incoming packet (b,c)=>(b,a) (OIP_SRC=b,OIP_DST=a) 3819 * - OIP_SRC(b)=nat_olddstip, OIP_DST(a)=nat_oldsrcip 3820 *=> OIP_SRC(b)=nat_newdstip, OIP_DST(a)=nat_newsrcip 3821 * 3822 * RDR rule, SRC=a,DST=b -> SRC=a,DST=c 3823 * - response to incoming packet (a,b)=>(a,c) (OIP_SRC=a,OIP_DST=c) 3824 * - OIP_SRC(a)=nat_newsrcip, OIP_DST(c)=nat_newdstip 3825 *=> OIP_SRC(a)=nat_oldsrcip, OIP_DST(c)=nat_olddstip 3826 * 3827 * REWRITE out rule, SRC=a,DST=b -> SRC=c,DST=d 3828 * - response to incoming packet (d,c)=>(b,a) (OIP_SRC=c,OIP_DST=d) 3829 * - OIP_SRC(c)=nat_olddstip, OIP_DST(d)=nat_oldsrcip 3830 *=> OIP_SRC(b)=nat_newdstip, OIP_DST(a)=nat_newsrcip 3831 * 3832 * REWRITE in rule, SRC=a,DST=b -> SRC=c,DST=d 3833 * - response to incoming packet (a,b)=>(c,d) (OIP_SRC=b,OIP_DST=a) 3834 * - OIP_SRC(b)=nat_newsrcip, OIP_DST(a)=nat_newdstip 3835 *=> OIP_SRC(a)=nat_oldsrcip, OIP_DST(c)=nat_olddstip 3836 */ 3837 3838 if (((fin->fin_out == 0) && ((nat->nat_redir & NAT_MAP) != 0)) || 3839 ((fin->fin_out == 1) && ((nat->nat_redir & NAT_REDIRECT) != 0))) { 3840 a1.s_addr = ntohl(nat->nat_osrcaddr); 3841 a4.s_addr = ntohl(oip->ip_src.s_addr); 3842 a3.s_addr = ntohl(nat->nat_odstaddr); 3843 a2.s_addr = ntohl(oip->ip_dst.s_addr); 3844 oip->ip_src.s_addr = htonl(a1.s_addr); 3845 oip->ip_dst.s_addr = htonl(a3.s_addr); 3846 odst = 1; 3847 } else { 3848 a1.s_addr = ntohl(nat->nat_ndstaddr); 3849 a2.s_addr = ntohl(oip->ip_dst.s_addr); 3850 a3.s_addr = ntohl(nat->nat_nsrcaddr); 3851 a4.s_addr = ntohl(oip->ip_src.s_addr); 3852 oip->ip_dst.s_addr = htonl(a3.s_addr); 3853 oip->ip_src.s_addr = htonl(a1.s_addr); 3854 odst = 0; 3855 } 3856 sum1 = 0; 3857 sum2 = 0; 3858 sumd = 0; 3859 CALC_SUMD(a2.s_addr, a3.s_addr, sum1); 3860 CALC_SUMD(a4.s_addr, a1.s_addr, sum2); 3861 sumd = sum2 + sum1; 3862 if (sumd != 0) 3863 ipf_fix_datacksum(&oip->ip_sum, sumd); 3864 3865 sumd2 = sumd; 3866 sum1 = 0; 3867 sum2 = 0; 3868 3869 /* 3870 * Fix UDP pseudo header checksum to compensate for the 3871 * IP address change. 3872 */ 3873 if (((flags & IPN_TCPUDP) != 0) && (dlen >= 4)) { 3874 u_32_t sum3, sum4, sumt; 3875 3876 /* 3877 * Step 2 : 3878 * For offending TCP/UDP IP packets, translate the ports as 3879 * well, based on the NAT specification. Of course such 3880 * a change may be reflected in the ICMP checksum as well. 3881 * 3882 * Since the port fields are part of the TCP/UDP checksum 3883 * of the offending IP packet, you need to adjust that checksum 3884 * as well... except that the change in the port numbers should 3885 * be offset by the checksum change. However, the TCP/UDP 3886 * checksum will also need to change if there has been an 3887 * IP address change. 3888 */ 3889 if (odst == 1) { 3890 sum1 = ntohs(nat->nat_osport); 3891 sum4 = ntohs(tcp->th_sport); 3892 sum3 = ntohs(nat->nat_odport); 3893 sum2 = ntohs(tcp->th_dport); 3894 3895 tcp->th_sport = htons(sum1); 3896 tcp->th_dport = htons(sum3); 3897 } else { 3898 sum1 = ntohs(nat->nat_ndport); 3899 sum2 = ntohs(tcp->th_dport); 3900 sum3 = ntohs(nat->nat_nsport); 3901 sum4 = ntohs(tcp->th_sport); 3902 3903 tcp->th_dport = htons(sum3); 3904 tcp->th_sport = htons(sum1); 3905 } 3906 CALC_SUMD(sum4, sum1, sumt); 3907 sumd += sumt; 3908 CALC_SUMD(sum2, sum3, sumt); 3909 sumd += sumt; 3910 3911 if (sumd != 0 || sumd2 != 0) { 3912 /* 3913 * At this point, sumd is the delta to apply to the 3914 * TCP/UDP header, given the changes in both the IP 3915 * address and the ports and sumd2 is the delta to 3916 * apply to the ICMP header, given the IP address 3917 * change delta that may need to be applied to the 3918 * TCP/UDP checksum instead. 3919 * 3920 * If we will both the IP and TCP/UDP checksums 3921 * then the ICMP checksum changes by the address 3922 * delta applied to the TCP/UDP checksum. If we 3923 * do not change the TCP/UDP checksum them we 3924 * apply the delta in ports to the ICMP checksum. 3925 */ 3926 if (oip->ip_p == IPPROTO_UDP) { 3927 if ((dlen >= 8) && (*csump != 0)) { 3928 ipf_fix_datacksum(csump, sumd); 3929 } else { 3930 CALC_SUMD(sum1, sum4, sumd2); 3931 CALC_SUMD(sum3, sum2, sumt); 3932 sumd2 += sumt; 3933 } 3934 } else if (oip->ip_p == IPPROTO_TCP) { 3935 if (dlen >= 18) { 3936 ipf_fix_datacksum(csump, sumd); 3937 } else { 3938 CALC_SUMD(sum1, sum4, sumd2); 3939 CALC_SUMD(sum3, sum2, sumt); 3940 sumd2 += sumt; 3941 } 3942 } 3943 if (sumd2 != 0) { 3944 sumd2 = (sumd2 & 0xffff) + (sumd2 >> 16); 3945 sumd2 = (sumd2 & 0xffff) + (sumd2 >> 16); 3946 sumd2 = (sumd2 & 0xffff) + (sumd2 >> 16); 3947 ipf_fix_incksum(0, &icmp->icmp_cksum, sumd2, 0); 3948 } 3949 } 3950 } else if (((flags & IPN_ICMPQUERY) != 0) && (dlen >= 8)) { 3951 icmphdr_t *orgicmp; 3952 3953 /* 3954 * XXX - what if this is bogus hl and we go off the end ? 3955 * In this case, ipf_nat_icmperrorlookup() will have 3956 * returned NULL. 3957 */ 3958 orgicmp = (icmphdr_t *)dp; 3959 3960 if (odst == 1) { 3961 if (orgicmp->icmp_id != nat->nat_osport) { 3962 3963 /* 3964 * Fix ICMP checksum (of the offening ICMP 3965 * query packet) to compensate the change 3966 * in the ICMP id of the offending ICMP 3967 * packet. 3968 * 3969 * Since you modify orgicmp->icmp_id with 3970 * a delta (say x) and you compensate that 3971 * in origicmp->icmp_cksum with a delta 3972 * minus x, you don't have to adjust the 3973 * overall icmp->icmp_cksum 3974 */ 3975 sum1 = ntohs(orgicmp->icmp_id); 3976 sum2 = ntohs(nat->nat_oicmpid); 3977 CALC_SUMD(sum1, sum2, sumd); 3978 orgicmp->icmp_id = nat->nat_oicmpid; 3979 ipf_fix_datacksum(&orgicmp->icmp_cksum, sumd); 3980 } 3981 } /* nat_dir == NAT_INBOUND is impossible for icmp queries */ 3982 } 3983 return nat; 3984 } 3985 3986 3987 /* 3988 * MAP-IN MAP-OUT RDR-IN RDR-OUT 3989 * osrc X == src == src X 3990 * odst X == dst == dst X 3991 * nsrc == dst X X == dst 3992 * ndst == src X X == src 3993 * MAP = NAT_OUTBOUND, RDR = NAT_INBOUND 3994 */ 3995 /* 3996 * NB: these lookups don't lock access to the list, it assumed that it has 3997 * already been done! 3998 */ 3999 /* ------------------------------------------------------------------------ */ 4000 /* Function: ipf_nat_inlookup */ 4001 /* Returns: nat_t* - NULL == no match, */ 4002 /* else pointer to matching NAT entry */ 4003 /* Parameters: fin(I) - pointer to packet information */ 4004 /* flags(I) - NAT flags for this packet */ 4005 /* p(I) - protocol for this packet */ 4006 /* src(I) - source IP address */ 4007 /* mapdst(I) - destination IP address */ 4008 /* */ 4009 /* Lookup a nat entry based on the mapped destination ip address/port and */ 4010 /* real source address/port. We use this lookup when receiving a packet, */ 4011 /* we're looking for a table entry, based on the destination address. */ 4012 /* */ 4013 /* NOTE: THE PACKET BEING CHECKED (IF FOUND) HAS A MAPPING ALREADY. */ 4014 /* */ 4015 /* NOTE: IT IS ASSUMED THAT IS ONLY HELD WITH A READ LOCK WHEN */ 4016 /* THIS FUNCTION IS CALLED WITH NAT_SEARCH SET IN nflags. */ 4017 /* */ 4018 /* flags -> relevant are IPN_UDP/IPN_TCP/IPN_ICMPQUERY that indicate if */ 4019 /* the packet is of said protocol */ 4020 /* ------------------------------------------------------------------------ */ 4021 nat_t * 4022 ipf_nat_inlookup(fr_info_t *fin, u_int flags, u_int p, struct in_addr src, 4023 struct in_addr mapdst) 4024 { 4025 ipf_main_softc_t *softc = fin->fin_main_soft; 4026 ipf_nat_softc_t *softn = softc->ipf_nat_soft; 4027 u_short sport, dport; 4028 ipnat_t *ipn; 4029 nat_t *nat; 4030 int nflags; 4031 u_32_t dst; 4032 void *ifp; 4033 u_int hv, rhv; 4034 4035 ifp = fin->fin_ifp; 4036 dst = mapdst.s_addr; 4037 4038 switch (p) 4039 { 4040 case IPPROTO_TCP : 4041 case IPPROTO_UDP : 4042 sport = htons(fin->fin_data[0]); 4043 dport = htons(fin->fin_data[1]); 4044 break; 4045 case IPPROTO_ICMP : 4046 sport = 0; 4047 dport = fin->fin_data[1]; 4048 break; 4049 default : 4050 sport = 0; 4051 dport = 0; 4052 break; 4053 } 4054 4055 4056 if ((flags & SI_WILDP) != 0) 4057 goto find_in_wild_ports; 4058 4059 rhv = NAT_HASH_FN(dst, dport, 0xffffffff); 4060 rhv = NAT_HASH_FN(src.s_addr, rhv + sport, 0xffffffff); 4061 hv = rhv % softn->ipf_nat_table_sz; 4062 nat = softn->ipf_nat_table[1][hv]; 4063 /* TRACE dst, dport, src, sport, hv, nat */ 4064 4065 for (; nat; nat = nat->nat_hnext[1]) { 4066 if (nat->nat_ifps[0] != NULL) { 4067 if ((ifp != NULL) && (ifp != nat->nat_ifps[0])) 4068 continue; 4069 } 4070 4071 if (nat->nat_pr[0] != p) 4072 continue; 4073 4074 switch (nat->nat_dir) 4075 { 4076 case NAT_INBOUND : 4077 case NAT_DIVERTIN : 4078 if (nat->nat_v[0] != 4) 4079 continue; 4080 if (nat->nat_osrcaddr != src.s_addr || 4081 nat->nat_odstaddr != dst) 4082 continue; 4083 if ((nat->nat_flags & IPN_TCPUDP) != 0) { 4084 if (nat->nat_osport != sport) 4085 continue; 4086 if (nat->nat_odport != dport) 4087 continue; 4088 4089 } else if (p == IPPROTO_ICMP) { 4090 if (nat->nat_oicmpid != dport) { 4091 continue; 4092 } 4093 } 4094 break; 4095 case NAT_DIVERTOUT : 4096 if (nat->nat_dlocal) 4097 continue; 4098 /* FALLTHROUGH */ 4099 case NAT_OUTBOUND : 4100 if (nat->nat_v[1] != 4) 4101 continue; 4102 if (nat->nat_dlocal) 4103 continue; 4104 if (nat->nat_dlocal) 4105 continue; 4106 if (nat->nat_ndstaddr != src.s_addr || 4107 nat->nat_nsrcaddr != dst) 4108 continue; 4109 if ((nat->nat_flags & IPN_TCPUDP) != 0) { 4110 if (nat->nat_ndport != sport) 4111 continue; 4112 if (nat->nat_nsport != dport) 4113 continue; 4114 4115 } else if (p == IPPROTO_ICMP) { 4116 if (nat->nat_nicmpid != dport) { 4117 continue; 4118 } 4119 } 4120 break; 4121 } 4122 4123 4124 if ((nat->nat_flags & IPN_TCPUDP) != 0) { 4125 ipn = nat->nat_ptr; 4126 if ((ipn != NULL) && (nat->nat_aps != NULL)) 4127 if (ipf_proxy_match(fin, nat) != 0) 4128 continue; 4129 } 4130 if ((nat->nat_ifps[0] == NULL) && (ifp != NULL)) { 4131 nat->nat_ifps[0] = ifp; 4132 nat->nat_mtu[0] = GETIFMTU_4(ifp); 4133 } 4134 return nat; 4135 } 4136 4137 /* 4138 * So if we didn't find it but there are wildcard members in the hash 4139 * table, go back and look for them. We do this search and update here 4140 * because it is modifying the NAT table and we want to do this only 4141 * for the first packet that matches. The exception, of course, is 4142 * for "dummy" (FI_IGNORE) lookups. 4143 */ 4144 find_in_wild_ports: 4145 if (!(flags & NAT_TCPUDP) || !(flags & NAT_SEARCH)) { 4146 NBUMPSIDEX(0, ns_lookup_miss, ns_lookup_miss_0); 4147 return NULL; 4148 } 4149 if (softn->ipf_nat_stats.ns_wilds == 0 || (fin->fin_flx & FI_NOWILD)) { 4150 NBUMPSIDEX(0, ns_lookup_nowild, ns_lookup_nowild_0); 4151 return NULL; 4152 } 4153 4154 RWLOCK_EXIT(&softc->ipf_nat); 4155 4156 hv = NAT_HASH_FN(dst, 0, 0xffffffff); 4157 hv = NAT_HASH_FN(src.s_addr, hv, softn->ipf_nat_table_sz); 4158 WRITE_ENTER(&softc->ipf_nat); 4159 4160 nat = softn->ipf_nat_table[1][hv]; 4161 /* TRACE dst, src, hv, nat */ 4162 for (; nat; nat = nat->nat_hnext[1]) { 4163 if (nat->nat_ifps[0] != NULL) { 4164 if ((ifp != NULL) && (ifp != nat->nat_ifps[0])) 4165 continue; 4166 } 4167 4168 if (nat->nat_pr[0] != fin->fin_p) 4169 continue; 4170 4171 switch (nat->nat_dir & (NAT_INBOUND|NAT_OUTBOUND)) 4172 { 4173 case NAT_INBOUND : 4174 if (nat->nat_v[0] != 4) 4175 continue; 4176 if (nat->nat_osrcaddr != src.s_addr || 4177 nat->nat_odstaddr != dst) 4178 continue; 4179 break; 4180 case NAT_OUTBOUND : 4181 if (nat->nat_v[1] != 4) 4182 continue; 4183 if (nat->nat_ndstaddr != src.s_addr || 4184 nat->nat_nsrcaddr != dst) 4185 continue; 4186 break; 4187 } 4188 4189 nflags = nat->nat_flags; 4190 if (!(nflags & (NAT_TCPUDP|SI_WILDP))) 4191 continue; 4192 4193 if (ipf_nat_wildok(nat, (int)sport, (int)dport, nflags, 4194 NAT_INBOUND) == 1) { 4195 if ((fin->fin_flx & FI_IGNORE) != 0) 4196 break; 4197 if ((nflags & SI_CLONE) != 0) { 4198 nat = ipf_nat_clone(fin, nat); 4199 if (nat == NULL) 4200 break; 4201 } else { 4202 MUTEX_ENTER(&softn->ipf_nat_new); 4203 softn->ipf_nat_stats.ns_wilds--; 4204 MUTEX_EXIT(&softn->ipf_nat_new); 4205 } 4206 4207 if (nat->nat_dir == NAT_INBOUND) { 4208 if (nat->nat_osport == 0) { 4209 nat->nat_osport = sport; 4210 nat->nat_nsport = sport; 4211 } 4212 if (nat->nat_odport == 0) { 4213 nat->nat_odport = dport; 4214 nat->nat_ndport = dport; 4215 } 4216 } else if (nat->nat_dir == NAT_OUTBOUND) { 4217 if (nat->nat_osport == 0) { 4218 nat->nat_osport = dport; 4219 nat->nat_nsport = dport; 4220 } 4221 if (nat->nat_odport == 0) { 4222 nat->nat_odport = sport; 4223 nat->nat_ndport = sport; 4224 } 4225 } 4226 if ((nat->nat_ifps[0] == NULL) && (ifp != NULL)) { 4227 nat->nat_ifps[0] = ifp; 4228 nat->nat_mtu[0] = GETIFMTU_4(ifp); 4229 } 4230 nat->nat_flags &= ~(SI_W_DPORT|SI_W_SPORT); 4231 ipf_nat_tabmove(softn, nat); 4232 break; 4233 } 4234 } 4235 4236 MUTEX_DOWNGRADE(&softc->ipf_nat); 4237 4238 if (nat == NULL) { 4239 NBUMPSIDE(0, ns_lookup_miss); 4240 } 4241 return nat; 4242 } 4243 4244 4245 /* ------------------------------------------------------------------------ */ 4246 /* Function: ipf_nat_tabmove */ 4247 /* Returns: Nil */ 4248 /* Parameters: softn(I) - pointer to NAT context structure */ 4249 /* nat(I) - pointer to NAT structure */ 4250 /* Write Lock: ipf_nat */ 4251 /* */ 4252 /* This function is only called for TCP/UDP NAT table entries where the */ 4253 /* original was placed in the table without hashing on the ports and we now */ 4254 /* want to include hashing on port numbers. */ 4255 /* ------------------------------------------------------------------------ */ 4256 static void 4257 ipf_nat_tabmove(ipf_nat_softc_t *softn, nat_t *nat) 4258 { 4259 u_int hv0, hv1, rhv0, rhv1; 4260 natstat_t *nsp; 4261 nat_t **natp; 4262 4263 if (nat->nat_flags & SI_CLONE) 4264 return; 4265 4266 nsp = &softn->ipf_nat_stats; 4267 /* 4268 * Remove the NAT entry from the old location 4269 */ 4270 if (nat->nat_hnext[0]) 4271 nat->nat_hnext[0]->nat_phnext[0] = nat->nat_phnext[0]; 4272 *nat->nat_phnext[0] = nat->nat_hnext[0]; 4273 hv0 = nat->nat_hv[0] % softn->ipf_nat_table_sz; 4274 hv1 = nat->nat_hv[1] % softn->ipf_nat_table_sz; 4275 4276 ASSERT(nsp->ns_side[0].ns_bucketlen[hv0] > 0); 4277 nsp->ns_side[0].ns_bucketlen[hv0]--; 4278 4279 if (nat->nat_hnext[1]) 4280 nat->nat_hnext[1]->nat_phnext[1] = nat->nat_phnext[1]; 4281 *nat->nat_phnext[1] = nat->nat_hnext[1]; 4282 ASSERT(nsp->ns_side[1].ns_bucketlen[hv1] > 0); 4283 nsp->ns_side[1].ns_bucketlen[hv1]--; 4284 4285 /* 4286 * Add into the NAT table in the new position 4287 */ 4288 rhv0 = NAT_HASH_FN(nat->nat_osrcaddr, nat->nat_osport, 0xffffffff); 4289 rhv0 = NAT_HASH_FN(nat->nat_odstaddr, rhv0 + nat->nat_odport, 4290 0xffffffff); 4291 rhv1 = NAT_HASH_FN(nat->nat_nsrcaddr, nat->nat_nsport, 0xffffffff); 4292 rhv1 = NAT_HASH_FN(nat->nat_ndstaddr, rhv1 + nat->nat_ndport, 4293 0xffffffff); 4294 4295 if ((nat->nat_dir & NAT_OUTBOUND) == NAT_OUTBOUND) { 4296 nat->nat_hv[0] = rhv0; 4297 nat->nat_hv[1] = rhv1; 4298 } else { 4299 nat->nat_hv[0] = rhv1; 4300 nat->nat_hv[1] = rhv0; 4301 } 4302 4303 hv0 = nat->nat_hv[0] % softn->ipf_nat_table_sz; 4304 hv1 = nat->nat_hv[1] % softn->ipf_nat_table_sz; 4305 4306 /* TRACE nat_osrcaddr, nat_osport, nat_odstaddr, nat_odport, hv0 */ 4307 /* TRACE nat_nsrcaddr, nat_nsport, nat_ndstaddr, nat_ndport, hv1 */ 4308 4309 natp = &softn->ipf_nat_table[0][hv0]; 4310 if (*natp) 4311 (*natp)->nat_phnext[0] = &nat->nat_hnext[0]; 4312 nat->nat_phnext[0] = natp; 4313 nat->nat_hnext[0] = *natp; 4314 *natp = nat; 4315 nsp->ns_side[0].ns_bucketlen[hv0]++; 4316 4317 natp = &softn->ipf_nat_table[1][hv1]; 4318 if (*natp) 4319 (*natp)->nat_phnext[1] = &nat->nat_hnext[1]; 4320 nat->nat_phnext[1] = natp; 4321 nat->nat_hnext[1] = *natp; 4322 *natp = nat; 4323 nsp->ns_side[1].ns_bucketlen[hv1]++; 4324 } 4325 4326 4327 /* ------------------------------------------------------------------------ */ 4328 /* Function: ipf_nat_outlookup */ 4329 /* Returns: nat_t* - NULL == no match, */ 4330 /* else pointer to matching NAT entry */ 4331 /* Parameters: fin(I) - pointer to packet information */ 4332 /* flags(I) - NAT flags for this packet */ 4333 /* p(I) - protocol for this packet */ 4334 /* src(I) - source IP address */ 4335 /* dst(I) - destination IP address */ 4336 /* rw(I) - 1 == write lock on held, 0 == read lock. */ 4337 /* */ 4338 /* Lookup a nat entry based on the source 'real' ip address/port and */ 4339 /* destination address/port. We use this lookup when sending a packet out, */ 4340 /* we're looking for a table entry, based on the source address. */ 4341 /* */ 4342 /* NOTE: THE PACKET BEING CHECKED (IF FOUND) HAS A MAPPING ALREADY. */ 4343 /* */ 4344 /* NOTE: IT IS ASSUMED THAT IS ONLY HELD WITH A READ LOCK WHEN */ 4345 /* THIS FUNCTION IS CALLED WITH NAT_SEARCH SET IN nflags. */ 4346 /* */ 4347 /* flags -> relevant are IPN_UDP/IPN_TCP/IPN_ICMPQUERY that indicate if */ 4348 /* the packet is of said protocol */ 4349 /* ------------------------------------------------------------------------ */ 4350 nat_t * 4351 ipf_nat_outlookup(fr_info_t *fin, u_int flags, u_int p, struct in_addr src, 4352 struct in_addr dst) 4353 { 4354 ipf_main_softc_t *softc = fin->fin_main_soft; 4355 ipf_nat_softc_t *softn = softc->ipf_nat_soft; 4356 u_short sport, dport; 4357 ipnat_t *ipn; 4358 nat_t *nat; 4359 void *ifp; 4360 u_int hv; 4361 4362 ifp = fin->fin_ifp; 4363 4364 switch (p) 4365 { 4366 case IPPROTO_TCP : 4367 case IPPROTO_UDP : 4368 sport = htons(fin->fin_data[0]); 4369 dport = htons(fin->fin_data[1]); 4370 break; 4371 case IPPROTO_ICMP : 4372 sport = 0; 4373 dport = fin->fin_data[1]; 4374 break; 4375 default : 4376 sport = 0; 4377 dport = 0; 4378 break; 4379 } 4380 4381 if ((flags & SI_WILDP) != 0) 4382 goto find_out_wild_ports; 4383 4384 hv = NAT_HASH_FN(src.s_addr, sport, 0xffffffff); 4385 hv = NAT_HASH_FN(dst.s_addr, hv + dport, softn->ipf_nat_table_sz); 4386 nat = softn->ipf_nat_table[0][hv]; 4387 4388 /* TRACE src, sport, dst, dport, hv, nat */ 4389 4390 for (; nat; nat = nat->nat_hnext[0]) { 4391 if (nat->nat_ifps[1] != NULL) { 4392 if ((ifp != NULL) && (ifp != nat->nat_ifps[1])) 4393 continue; 4394 } 4395 4396 if (nat->nat_pr[1] != p) 4397 continue; 4398 4399 switch (nat->nat_dir) 4400 { 4401 case NAT_INBOUND : 4402 case NAT_DIVERTIN : 4403 if (nat->nat_v[1] != 4) 4404 continue; 4405 if (nat->nat_ndstaddr != src.s_addr || 4406 nat->nat_nsrcaddr != dst.s_addr) 4407 continue; 4408 4409 if ((nat->nat_flags & IPN_TCPUDP) != 0) { 4410 if (nat->nat_ndport != sport) 4411 continue; 4412 if (nat->nat_nsport != dport) 4413 continue; 4414 4415 } else if (p == IPPROTO_ICMP) { 4416 if (nat->nat_nicmpid != dport) { 4417 continue; 4418 } 4419 } 4420 break; 4421 case NAT_OUTBOUND : 4422 case NAT_DIVERTOUT : 4423 if (nat->nat_v[0] != 4) 4424 continue; 4425 if (nat->nat_osrcaddr != src.s_addr || 4426 nat->nat_odstaddr != dst.s_addr) 4427 continue; 4428 4429 if ((nat->nat_flags & IPN_TCPUDP) != 0) { 4430 if (nat->nat_odport != dport) 4431 continue; 4432 if (nat->nat_osport != sport) 4433 continue; 4434 4435 } else if (p == IPPROTO_ICMP) { 4436 if (nat->nat_oicmpid != dport) { 4437 continue; 4438 } 4439 } 4440 break; 4441 } 4442 4443 ipn = nat->nat_ptr; 4444 if ((ipn != NULL) && (nat->nat_aps != NULL)) 4445 if (ipf_proxy_match(fin, nat) != 0) 4446 continue; 4447 4448 if ((nat->nat_ifps[1] == NULL) && (ifp != NULL)) { 4449 nat->nat_ifps[1] = ifp; 4450 nat->nat_mtu[1] = GETIFMTU_4(ifp); 4451 } 4452 return nat; 4453 } 4454 4455 /* 4456 * So if we didn't find it but there are wildcard members in the hash 4457 * table, go back and look for them. We do this search and update here 4458 * because it is modifying the NAT table and we want to do this only 4459 * for the first packet that matches. The exception, of course, is 4460 * for "dummy" (FI_IGNORE) lookups. 4461 */ 4462 find_out_wild_ports: 4463 if (!(flags & NAT_TCPUDP) || !(flags & NAT_SEARCH)) { 4464 NBUMPSIDEX(1, ns_lookup_miss, ns_lookup_miss_1); 4465 return NULL; 4466 } 4467 if (softn->ipf_nat_stats.ns_wilds == 0 || (fin->fin_flx & FI_NOWILD)) { 4468 NBUMPSIDEX(1, ns_lookup_nowild, ns_lookup_nowild_1); 4469 return NULL; 4470 } 4471 4472 RWLOCK_EXIT(&softc->ipf_nat); 4473 4474 hv = NAT_HASH_FN(src.s_addr, 0, 0xffffffff); 4475 hv = NAT_HASH_FN(dst.s_addr, hv, softn->ipf_nat_table_sz); 4476 4477 WRITE_ENTER(&softc->ipf_nat); 4478 4479 nat = softn->ipf_nat_table[0][hv]; 4480 for (; nat; nat = nat->nat_hnext[0]) { 4481 if (nat->nat_ifps[1] != NULL) { 4482 if ((ifp != NULL) && (ifp != nat->nat_ifps[1])) 4483 continue; 4484 } 4485 4486 if (nat->nat_pr[1] != fin->fin_p) 4487 continue; 4488 4489 switch (nat->nat_dir & (NAT_INBOUND|NAT_OUTBOUND)) 4490 { 4491 case NAT_INBOUND : 4492 if (nat->nat_v[1] != 4) 4493 continue; 4494 if (nat->nat_ndstaddr != src.s_addr || 4495 nat->nat_nsrcaddr != dst.s_addr) 4496 continue; 4497 break; 4498 case NAT_OUTBOUND : 4499 if (nat->nat_v[0] != 4) 4500 continue; 4501 if (nat->nat_osrcaddr != src.s_addr || 4502 nat->nat_odstaddr != dst.s_addr) 4503 continue; 4504 break; 4505 } 4506 4507 if (!(nat->nat_flags & (NAT_TCPUDP|SI_WILDP))) 4508 continue; 4509 4510 if (ipf_nat_wildok(nat, (int)sport, (int)dport, nat->nat_flags, 4511 NAT_OUTBOUND) == 1) { 4512 if ((fin->fin_flx & FI_IGNORE) != 0) 4513 break; 4514 if ((nat->nat_flags & SI_CLONE) != 0) { 4515 nat = ipf_nat_clone(fin, nat); 4516 if (nat == NULL) 4517 break; 4518 } else { 4519 MUTEX_ENTER(&softn->ipf_nat_new); 4520 softn->ipf_nat_stats.ns_wilds--; 4521 MUTEX_EXIT(&softn->ipf_nat_new); 4522 } 4523 4524 if (nat->nat_dir == NAT_OUTBOUND) { 4525 if (nat->nat_osport == 0) { 4526 nat->nat_osport = sport; 4527 nat->nat_nsport = sport; 4528 } 4529 if (nat->nat_odport == 0) { 4530 nat->nat_odport = dport; 4531 nat->nat_ndport = dport; 4532 } 4533 } else if (nat->nat_dir == NAT_INBOUND) { 4534 if (nat->nat_osport == 0) { 4535 nat->nat_osport = dport; 4536 nat->nat_nsport = dport; 4537 } 4538 if (nat->nat_odport == 0) { 4539 nat->nat_odport = sport; 4540 nat->nat_ndport = sport; 4541 } 4542 } 4543 if ((nat->nat_ifps[1] == NULL) && (ifp != NULL)) { 4544 nat->nat_ifps[1] = ifp; 4545 nat->nat_mtu[1] = GETIFMTU_4(ifp); 4546 } 4547 nat->nat_flags &= ~(SI_W_DPORT|SI_W_SPORT); 4548 ipf_nat_tabmove(softn, nat); 4549 break; 4550 } 4551 } 4552 4553 MUTEX_DOWNGRADE(&softc->ipf_nat); 4554 4555 if (nat == NULL) { 4556 NBUMPSIDE(1, ns_lookup_miss); 4557 } 4558 return nat; 4559 } 4560 4561 4562 /* ------------------------------------------------------------------------ */ 4563 /* Function: ipf_nat_lookupredir */ 4564 /* Returns: nat_t* - NULL == no match, */ 4565 /* else pointer to matching NAT entry */ 4566 /* Parameters: softc(I) - pointer to soft context main structure */ 4567 /* np(I) - pointer to description of packet to find NAT */ 4568 /* table entry for. */ 4569 /* */ 4570 /* Lookup the NAT tables to search for a matching redirect */ 4571 /* The contents of natlookup_t should imitate those found in a packet that */ 4572 /* would be translated - ie a packet coming in for RDR or going out for MAP.*/ 4573 /* We can do the lookup in one of two ways, imitating an inbound or */ 4574 /* outbound packet. By default we assume outbound, unless IPN_IN is set. */ 4575 /* For IN, the fields are set as follows: */ 4576 /* nl_real* = source information */ 4577 /* nl_out* = destination information (translated) */ 4578 /* For an out packet, the fields are set like this: */ 4579 /* nl_in* = source information (untranslated) */ 4580 /* nl_out* = destination information (translated) */ 4581 /* ------------------------------------------------------------------------ */ 4582 nat_t * 4583 ipf_nat_lookupredir(ipf_main_softc_t *softc, natlookup_t *np) 4584 { 4585 fr_info_t fi; 4586 nat_t *nat; 4587 4588 bzero((char *)&fi, sizeof(fi)); 4589 fi.fin_main_soft = softc; 4590 if (np->nl_flags & IPN_IN) { 4591 fi.fin_data[0] = ntohs(np->nl_realport); 4592 fi.fin_data[1] = ntohs(np->nl_outport); 4593 } else { 4594 fi.fin_data[0] = ntohs(np->nl_inport); 4595 fi.fin_data[1] = ntohs(np->nl_outport); 4596 } 4597 if (np->nl_flags & IPN_TCP) 4598 fi.fin_p = IPPROTO_TCP; 4599 else if (np->nl_flags & IPN_UDP) 4600 fi.fin_p = IPPROTO_UDP; 4601 else if (np->nl_flags & (IPN_ICMPERR|IPN_ICMPQUERY)) 4602 fi.fin_p = IPPROTO_ICMP; 4603 4604 /* 4605 * We can do two sorts of lookups: 4606 * - IPN_IN: we have the `real' and `out' address, look for `in'. 4607 * - default: we have the `in' and `out' address, look for `real'. 4608 */ 4609 if (np->nl_flags & IPN_IN) { 4610 if ((nat = ipf_nat_inlookup(&fi, np->nl_flags, fi.fin_p, 4611 np->nl_realip, np->nl_outip))) { 4612 np->nl_inip = nat->nat_odstip; 4613 np->nl_inport = nat->nat_odport; 4614 } 4615 } else { 4616 /* 4617 * If nl_inip is non null, this is a lookup based on the real 4618 * ip address. Else, we use the fake. 4619 */ 4620 if ((nat = ipf_nat_outlookup(&fi, np->nl_flags, fi.fin_p, 4621 np->nl_inip, np->nl_outip))) { 4622 4623 if ((np->nl_flags & IPN_FINDFORWARD) != 0) { 4624 fr_info_t fin; 4625 bzero((char *)&fin, sizeof(fin)); 4626 fin.fin_p = nat->nat_pr[0]; 4627 fin.fin_data[0] = ntohs(nat->nat_ndport); 4628 fin.fin_data[1] = ntohs(nat->nat_nsport); 4629 if (ipf_nat_inlookup(&fin, np->nl_flags, 4630 fin.fin_p, nat->nat_ndstip, 4631 nat->nat_nsrcip) != NULL) { 4632 np->nl_flags &= ~IPN_FINDFORWARD; 4633 } 4634 } 4635 4636 np->nl_realip = nat->nat_odstip; 4637 np->nl_realport = nat->nat_odport; 4638 } 4639 } 4640 4641 return nat; 4642 } 4643 4644 4645 /* ------------------------------------------------------------------------ */ 4646 /* Function: ipf_nat_match */ 4647 /* Returns: int - 0 == no match, 1 == match */ 4648 /* Parameters: fin(I) - pointer to packet information */ 4649 /* np(I) - pointer to NAT rule */ 4650 /* */ 4651 /* Pull the matching of a packet against a NAT rule out of that complex */ 4652 /* loop inside ipf_nat_checkin() and lay it out properly in its own function. */ 4653 /* ------------------------------------------------------------------------ */ 4654 static int 4655 ipf_nat_match(fr_info_t *fin, ipnat_t *np) 4656 { 4657 ipf_main_softc_t *softc = fin->fin_main_soft; 4658 frtuc_t *ft; 4659 int match; 4660 4661 match = 0; 4662 switch (np->in_osrcatype) 4663 { 4664 case FRI_NORMAL : 4665 match = ((fin->fin_saddr & np->in_osrcmsk) != np->in_osrcaddr); 4666 break; 4667 case FRI_LOOKUP : 4668 match = (*np->in_osrcfunc)(softc, np->in_osrcptr, 4669 4, &fin->fin_saddr, fin->fin_plen); 4670 break; 4671 } 4672 match ^= ((np->in_flags & IPN_NOTSRC) != 0); 4673 if (match) 4674 return 0; 4675 4676 match = 0; 4677 switch (np->in_odstatype) 4678 { 4679 case FRI_NORMAL : 4680 match = ((fin->fin_daddr & np->in_odstmsk) != np->in_odstaddr); 4681 break; 4682 case FRI_LOOKUP : 4683 match = (*np->in_odstfunc)(softc, np->in_odstptr, 4684 4, &fin->fin_daddr, fin->fin_plen); 4685 break; 4686 } 4687 4688 match ^= ((np->in_flags & IPN_NOTDST) != 0); 4689 if (match) 4690 return 0; 4691 4692 ft = &np->in_tuc; 4693 if (!(fin->fin_flx & FI_TCPUDP) || 4694 (fin->fin_flx & (FI_SHORT|FI_FRAGBODY))) { 4695 if (ft->ftu_scmp || ft->ftu_dcmp) 4696 return 0; 4697 return 1; 4698 } 4699 4700 return ipf_tcpudpchk(&fin->fin_fi, ft); 4701 } 4702 4703 4704 /* ------------------------------------------------------------------------ */ 4705 /* Function: ipf_nat_update */ 4706 /* Returns: Nil */ 4707 /* Parameters: fin(I) - pointer to packet information */ 4708 /* nat(I) - pointer to NAT structure */ 4709 /* */ 4710 /* Updates the lifetime of a NAT table entry for non-TCP packets. Must be */ 4711 /* called with fin_rev updated - i.e. after calling ipf_nat_proto(). */ 4712 /* */ 4713 /* This *MUST* be called after ipf_nat_proto() as it expects fin_rev to */ 4714 /* already be set. */ 4715 /* ------------------------------------------------------------------------ */ 4716 void 4717 ipf_nat_update(fr_info_t *fin, nat_t *nat) 4718 { 4719 ipf_main_softc_t *softc = fin->fin_main_soft; 4720 ipf_nat_softc_t *softn = softc->ipf_nat_soft; 4721 ipftq_t *ifq, *ifq2; 4722 ipftqent_t *tqe; 4723 ipnat_t *np = nat->nat_ptr; 4724 4725 tqe = &nat->nat_tqe; 4726 ifq = tqe->tqe_ifq; 4727 4728 /* 4729 * We allow over-riding of NAT timeouts from NAT rules, even for 4730 * TCP, however, if it is TCP and there is no rule timeout set, 4731 * then do not update the timeout here. 4732 */ 4733 if (np != NULL) { 4734 np->in_bytes[fin->fin_rev] += fin->fin_plen; 4735 ifq2 = np->in_tqehead[fin->fin_rev]; 4736 } else { 4737 ifq2 = NULL; 4738 } 4739 4740 if (nat->nat_pr[0] == IPPROTO_TCP && ifq2 == NULL) { 4741 (void) ipf_tcp_age(&nat->nat_tqe, fin, softn->ipf_nat_tcptq, 4742 0, 2); 4743 } else { 4744 if (ifq2 == NULL) { 4745 if (nat->nat_pr[0] == IPPROTO_UDP) 4746 ifq2 = fin->fin_rev ? &softn->ipf_nat_udpacktq : 4747 &softn->ipf_nat_udptq; 4748 else if (nat->nat_pr[0] == IPPROTO_ICMP || 4749 nat->nat_pr[0] == IPPROTO_ICMPV6) 4750 ifq2 = fin->fin_rev ? &softn->ipf_nat_icmpacktq: 4751 &softn->ipf_nat_icmptq; 4752 else 4753 ifq2 = &softn->ipf_nat_iptq; 4754 } 4755 4756 ipf_movequeue(softc->ipf_ticks, tqe, ifq, ifq2); 4757 } 4758 } 4759 4760 4761 /* ------------------------------------------------------------------------ */ 4762 /* Function: ipf_nat_checkout */ 4763 /* Returns: int - -1 == packet failed NAT checks so block it, */ 4764 /* 0 == no packet translation occurred, */ 4765 /* 1 == packet was successfully translated. */ 4766 /* Parameters: fin(I) - pointer to packet information */ 4767 /* passp(I) - pointer to filtering result flags */ 4768 /* */ 4769 /* Check to see if an outcoming packet should be changed. ICMP packets are */ 4770 /* first checked to see if they match an existing entry (if an error), */ 4771 /* otherwise a search of the current NAT table is made. If neither results */ 4772 /* in a match then a search for a matching NAT rule is made. Create a new */ 4773 /* NAT entry if a we matched a NAT rule. Lastly, actually change the */ 4774 /* packet header(s) as required. */ 4775 /* ------------------------------------------------------------------------ */ 4776 int 4777 ipf_nat_checkout(fr_info_t *fin, u_32_t *passp) 4778 { 4779 ipnat_t *np = NULL, *npnext; 4780 struct ifnet *ifp, *sifp; 4781 ipf_main_softc_t *softc; 4782 ipf_nat_softc_t *softn; 4783 tcphdr_t *tcp = NULL; 4784 int rval, natfailed; 4785 u_int nflags = 0; 4786 u_32_t ipa, iph; 4787 int natadd = 1; 4788 frentry_t *fr; 4789 nat_t *nat; 4790 4791 if (fin->fin_v == 6) { 4792 #ifdef USE_INET6 4793 return ipf_nat6_checkout(fin, passp); 4794 #else 4795 return 0; 4796 #endif 4797 } 4798 4799 softc = fin->fin_main_soft; 4800 softn = softc->ipf_nat_soft; 4801 4802 if (softn->ipf_nat_lock != 0) 4803 return 0; 4804 if (softn->ipf_nat_stats.ns_rules == 0 && 4805 softn->ipf_nat_instances == NULL) 4806 return 0; 4807 4808 natfailed = 0; 4809 fr = fin->fin_fr; 4810 sifp = fin->fin_ifp; 4811 if (fr != NULL) { 4812 ifp = fr->fr_tifs[fin->fin_rev].fd_ptr; 4813 if ((ifp != NULL) && (ifp != (void *)-1)) 4814 fin->fin_ifp = ifp; 4815 } 4816 ifp = fin->fin_ifp; 4817 4818 if (!(fin->fin_flx & FI_SHORT) && (fin->fin_off == 0)) { 4819 switch (fin->fin_p) 4820 { 4821 case IPPROTO_TCP : 4822 nflags = IPN_TCP; 4823 break; 4824 case IPPROTO_UDP : 4825 nflags = IPN_UDP; 4826 break; 4827 case IPPROTO_ICMP : 4828 /* 4829 * This is an incoming packet, so the destination is 4830 * the icmp_id and the source port equals 0 4831 */ 4832 if ((fin->fin_flx & FI_ICMPQUERY) != 0) 4833 nflags = IPN_ICMPQUERY; 4834 break; 4835 default : 4836 break; 4837 } 4838 4839 if ((nflags & IPN_TCPUDP)) 4840 tcp = fin->fin_dp; 4841 } 4842 4843 ipa = fin->fin_saddr; 4844 4845 READ_ENTER(&softc->ipf_nat); 4846 4847 if ((fin->fin_p == IPPROTO_ICMP) && !(nflags & IPN_ICMPQUERY) && 4848 (nat = ipf_nat_icmperror(fin, &nflags, NAT_OUTBOUND))) 4849 /*EMPTY*/; 4850 else if ((fin->fin_flx & FI_FRAG) && (nat = ipf_frag_natknown(fin))) 4851 natadd = 0; 4852 else if ((nat = ipf_nat_outlookup(fin, nflags|NAT_SEARCH, 4853 (u_int)fin->fin_p, fin->fin_src, 4854 fin->fin_dst))) { 4855 nflags = nat->nat_flags; 4856 } else if (fin->fin_off == 0) { 4857 u_32_t hv, msk, nmsk = 0; 4858 4859 /* 4860 * If there is no current entry in the nat table for this IP#, 4861 * create one for it (if there is a matching rule). 4862 */ 4863 maskloop: 4864 msk = softn->ipf_nat_map_active_masks[nmsk]; 4865 iph = ipa & msk; 4866 hv = NAT_HASH_FN(iph, 0, softn->ipf_nat_maprules_sz); 4867 retry_roundrobin: 4868 for (np = softn->ipf_nat_map_rules[hv]; np; np = npnext) { 4869 npnext = np->in_mnext; 4870 if ((np->in_ifps[1] && (np->in_ifps[1] != ifp))) 4871 continue; 4872 if (np->in_v[0] != 4) 4873 continue; 4874 if (np->in_pr[1] && (np->in_pr[1] != fin->fin_p)) 4875 continue; 4876 if ((np->in_flags & IPN_RF) && 4877 !(np->in_flags & nflags)) 4878 continue; 4879 if (np->in_flags & IPN_FILTER) { 4880 switch (ipf_nat_match(fin, np)) 4881 { 4882 case 0 : 4883 continue; 4884 case -1 : 4885 rval = -1; 4886 goto outmatchfail; 4887 case 1 : 4888 default : 4889 break; 4890 } 4891 } else if ((ipa & np->in_osrcmsk) != np->in_osrcaddr) 4892 continue; 4893 4894 if ((fr != NULL) && 4895 !ipf_matchtag(&np->in_tag, &fr->fr_nattag)) 4896 continue; 4897 4898 if (np->in_plabel != -1) { 4899 if (((np->in_flags & IPN_FILTER) == 0) && 4900 (np->in_odport != fin->fin_data[1])) 4901 continue; 4902 if (ipf_proxy_ok(fin, tcp, np) == 0) 4903 continue; 4904 } 4905 4906 if (np->in_flags & IPN_NO) { 4907 np->in_hits++; 4908 break; 4909 } 4910 MUTEX_ENTER(&softn->ipf_nat_new); 4911 /* 4912 * If we've matched a round-robin rule but it has 4913 * moved in the list since we got it, start over as 4914 * this is now no longer correct. 4915 */ 4916 if (npnext != np->in_mnext) { 4917 if ((np->in_flags & IPN_ROUNDR) != 0) { 4918 MUTEX_EXIT(&softn->ipf_nat_new); 4919 goto retry_roundrobin; 4920 } 4921 npnext = np->in_mnext; 4922 } 4923 4924 nat = ipf_nat_add(fin, np, NULL, nflags, NAT_OUTBOUND); 4925 MUTEX_EXIT(&softn->ipf_nat_new); 4926 if (nat != NULL) { 4927 natfailed = 0; 4928 break; 4929 } 4930 natfailed = -1; 4931 } 4932 if ((np == NULL) && (nmsk < softn->ipf_nat_map_max)) { 4933 nmsk++; 4934 goto maskloop; 4935 } 4936 } 4937 4938 if (nat != NULL) { 4939 rval = ipf_nat_out(fin, nat, natadd, nflags); 4940 if (rval == 1) { 4941 MUTEX_ENTER(&nat->nat_lock); 4942 ipf_nat_update(fin, nat); 4943 nat->nat_bytes[1] += fin->fin_plen; 4944 nat->nat_pkts[1]++; 4945 fin->fin_pktnum = nat->nat_pkts[1]; 4946 MUTEX_EXIT(&nat->nat_lock); 4947 } 4948 } else 4949 rval = natfailed; 4950 outmatchfail: 4951 RWLOCK_EXIT(&softc->ipf_nat); 4952 4953 switch (rval) 4954 { 4955 case -1 : 4956 if (passp != NULL) { 4957 DT1(frb_natv4out, fr_info_t *, fin); 4958 NBUMPSIDED(1, ns_drop); 4959 *passp = FR_BLOCK; 4960 fin->fin_reason = FRB_NATV4; 4961 } 4962 fin->fin_flx |= FI_BADNAT; 4963 NBUMPSIDED(1, ns_badnat); 4964 break; 4965 case 0 : 4966 NBUMPSIDE(1, ns_ignored); 4967 break; 4968 case 1 : 4969 NBUMPSIDE(1, ns_translated); 4970 break; 4971 } 4972 fin->fin_ifp = sifp; 4973 return rval; 4974 } 4975 4976 /* ------------------------------------------------------------------------ */ 4977 /* Function: ipf_nat_out */ 4978 /* Returns: int - -1 == packet failed NAT checks so block it, */ 4979 /* 1 == packet was successfully translated. */ 4980 /* Parameters: fin(I) - pointer to packet information */ 4981 /* nat(I) - pointer to NAT structure */ 4982 /* natadd(I) - flag indicating if it is safe to add frag cache */ 4983 /* nflags(I) - NAT flags set for this packet */ 4984 /* */ 4985 /* Translate a packet coming "out" on an interface. */ 4986 /* ------------------------------------------------------------------------ */ 4987 int 4988 ipf_nat_out(fr_info_t *fin, nat_t *nat, int natadd, u_32_t nflags) 4989 { 4990 ipf_main_softc_t *softc = fin->fin_main_soft; 4991 ipf_nat_softc_t *softn = softc->ipf_nat_soft; 4992 icmphdr_t *icmp; 4993 tcphdr_t *tcp; 4994 ipnat_t *np; 4995 int skip; 4996 int i; 4997 4998 tcp = NULL; 4999 icmp = NULL; 5000 np = nat->nat_ptr; 5001 5002 if ((natadd != 0) && (fin->fin_flx & FI_FRAG) && (np != NULL)) 5003 (void) ipf_frag_natnew(softc, fin, 0, nat); 5004 5005 /* 5006 * Fix up checksums, not by recalculating them, but 5007 * simply computing adjustments. 5008 * This is only done for STREAMS based IP implementations where the 5009 * checksum has already been calculated by IP. In all other cases, 5010 * IPFilter is called before the checksum needs calculating so there 5011 * is no call to modify whatever is in the header now. 5012 */ 5013 if (nflags == IPN_ICMPERR) { 5014 u_32_t s1, s2, sumd, msumd; 5015 5016 s1 = LONG_SUM(ntohl(fin->fin_saddr)); 5017 if (nat->nat_dir == NAT_OUTBOUND) { 5018 s2 = LONG_SUM(ntohl(nat->nat_nsrcaddr)); 5019 } else { 5020 s2 = LONG_SUM(ntohl(nat->nat_odstaddr)); 5021 } 5022 CALC_SUMD(s1, s2, sumd); 5023 msumd = sumd; 5024 5025 s1 = LONG_SUM(ntohl(fin->fin_daddr)); 5026 if (nat->nat_dir == NAT_OUTBOUND) { 5027 s2 = LONG_SUM(ntohl(nat->nat_ndstaddr)); 5028 } else { 5029 s2 = LONG_SUM(ntohl(nat->nat_osrcaddr)); 5030 } 5031 CALC_SUMD(s1, s2, sumd); 5032 msumd += sumd; 5033 5034 ipf_fix_outcksum(0, &fin->fin_ip->ip_sum, msumd, 0); 5035 } 5036 #if !defined(_KERNEL) || defined(MENTAT) || defined(__sgi) || \ 5037 defined(linux) 5038 else { 5039 /* 5040 * Strictly speaking, this isn't necessary on BSD 5041 * kernels because they do checksum calculation after 5042 * this code has run BUT if ipfilter is being used 5043 * to do NAT as a bridge, that code doesn't exist. 5044 */ 5045 switch (nat->nat_dir) 5046 { 5047 case NAT_OUTBOUND : 5048 ipf_fix_outcksum(fin->fin_cksum & FI_CK_L4PART, 5049 &fin->fin_ip->ip_sum, 5050 nat->nat_ipsumd, 0); 5051 break; 5052 5053 case NAT_INBOUND : 5054 ipf_fix_incksum(fin->fin_cksum & FI_CK_L4PART, 5055 &fin->fin_ip->ip_sum, 5056 nat->nat_ipsumd, 0); 5057 break; 5058 5059 default : 5060 break; 5061 } 5062 } 5063 #endif 5064 5065 /* 5066 * Address assignment is after the checksum modification because 5067 * we are using the address in the packet for determining the 5068 * correct checksum offset (the ICMP error could be coming from 5069 * anyone...) 5070 */ 5071 switch (nat->nat_dir) 5072 { 5073 case NAT_OUTBOUND : 5074 fin->fin_ip->ip_src = nat->nat_nsrcip; 5075 fin->fin_saddr = nat->nat_nsrcaddr; 5076 fin->fin_ip->ip_dst = nat->nat_ndstip; 5077 fin->fin_daddr = nat->nat_ndstaddr; 5078 break; 5079 5080 case NAT_INBOUND : 5081 fin->fin_ip->ip_src = nat->nat_odstip; 5082 fin->fin_saddr = nat->nat_ndstaddr; 5083 fin->fin_ip->ip_dst = nat->nat_osrcip; 5084 fin->fin_daddr = nat->nat_nsrcaddr; 5085 break; 5086 5087 case NAT_DIVERTIN : 5088 { 5089 mb_t *m; 5090 5091 skip = ipf_nat_decap(fin, nat); 5092 if (skip <= 0) { 5093 NBUMPSIDED(1, ns_decap_fail); 5094 return -1; 5095 } 5096 5097 m = fin->fin_m; 5098 5099 #if defined(MENTAT) && defined(_KERNEL) 5100 m->b_rptr += skip; 5101 #else 5102 m->m_data += skip; 5103 m->m_len -= skip; 5104 5105 # ifdef M_PKTHDR 5106 if (m->m_flags & M_PKTHDR) 5107 m->m_pkthdr.len -= skip; 5108 # endif 5109 #endif 5110 5111 MUTEX_ENTER(&nat->nat_lock); 5112 ipf_nat_update(fin, nat); 5113 MUTEX_EXIT(&nat->nat_lock); 5114 fin->fin_flx |= FI_NATED; 5115 if (np != NULL && np->in_tag.ipt_num[0] != 0) 5116 fin->fin_nattag = &np->in_tag; 5117 return 1; 5118 /* NOTREACHED */ 5119 } 5120 5121 case NAT_DIVERTOUT : 5122 { 5123 u_32_t s1, s2, sumd; 5124 udphdr_t *uh; 5125 ip_t *ip; 5126 mb_t *m; 5127 5128 m = M_DUP(np->in_divmp); 5129 if (m == NULL) { 5130 NBUMPSIDED(1, ns_divert_dup); 5131 return -1; 5132 } 5133 5134 ip = MTOD(m, ip_t *); 5135 ip->ip_id = htons(ipf_nextipid(fin)); 5136 s2 = ntohs(ip->ip_id); 5137 5138 s1 = ip->ip_len; 5139 ip->ip_len = ntohs(ip->ip_len); 5140 ip->ip_len += fin->fin_plen; 5141 ip->ip_len = htons(ip->ip_len); 5142 s2 += ntohs(ip->ip_len); 5143 CALC_SUMD(s1, s2, sumd); 5144 5145 uh = (udphdr_t *)(ip + 1); 5146 uh->uh_ulen += fin->fin_plen; 5147 uh->uh_ulen = htons(uh->uh_ulen); 5148 #if !defined(_KERNEL) || defined(MENTAT) || defined(__sgi) || \ 5149 defined(linux) 5150 ipf_fix_outcksum(0, &ip->ip_sum, sumd, 0); 5151 #endif 5152 5153 PREP_MB_T(fin, m); 5154 5155 fin->fin_src = ip->ip_src; 5156 fin->fin_dst = ip->ip_dst; 5157 fin->fin_ip = ip; 5158 fin->fin_plen += sizeof(ip_t) + 8; /* UDP + IPv4 hdr */ 5159 fin->fin_dlen += sizeof(ip_t) + 8; /* UDP + IPv4 hdr */ 5160 5161 nflags &= ~IPN_TCPUDPICMP; 5162 5163 break; 5164 } 5165 5166 default : 5167 break; 5168 } 5169 5170 if (!(fin->fin_flx & FI_SHORT) && (fin->fin_off == 0)) { 5171 u_short *csump; 5172 5173 if ((nat->nat_nsport != 0) && (nflags & IPN_TCPUDP)) { 5174 tcp = fin->fin_dp; 5175 5176 switch (nat->nat_dir) 5177 { 5178 case NAT_OUTBOUND : 5179 tcp->th_sport = nat->nat_nsport; 5180 fin->fin_data[0] = ntohs(nat->nat_nsport); 5181 tcp->th_dport = nat->nat_ndport; 5182 fin->fin_data[1] = ntohs(nat->nat_ndport); 5183 break; 5184 5185 case NAT_INBOUND : 5186 tcp->th_sport = nat->nat_odport; 5187 fin->fin_data[0] = ntohs(nat->nat_odport); 5188 tcp->th_dport = nat->nat_osport; 5189 fin->fin_data[1] = ntohs(nat->nat_osport); 5190 break; 5191 } 5192 } 5193 5194 if ((nat->nat_oicmpid != 0) && (nflags & IPN_ICMPQUERY)) { 5195 icmp = fin->fin_dp; 5196 5197 switch (nat->nat_dir) 5198 { 5199 case NAT_OUTBOUND : 5200 icmp->icmp_id = nat->nat_nicmpid; 5201 break; 5202 case NAT_INBOUND : 5203 icmp->icmp_id = nat->nat_oicmpid; 5204 break; 5205 } 5206 } 5207 5208 csump = ipf_nat_proto(fin, nat, nflags); 5209 5210 /* 5211 * The above comments do not hold for layer 4 (or higher) 5212 * checksums... 5213 */ 5214 if (csump != NULL) { 5215 if (nat->nat_dir == NAT_OUTBOUND) 5216 ipf_fix_outcksum(fin->fin_cksum, csump, 5217 nat->nat_sumd[0], 5218 nat->nat_sumd[1] + 5219 fin->fin_dlen); 5220 else 5221 ipf_fix_incksum(fin->fin_cksum, csump, 5222 nat->nat_sumd[0], 5223 nat->nat_sumd[1] + 5224 fin->fin_dlen); 5225 } 5226 } 5227 5228 ipf_sync_update(softc, SMC_NAT, fin, nat->nat_sync); 5229 /* ------------------------------------------------------------- */ 5230 /* A few quick notes: */ 5231 /* Following are test conditions prior to calling the */ 5232 /* ipf_proxy_check routine. */ 5233 /* */ 5234 /* A NULL tcp indicates a non TCP/UDP packet. When dealing */ 5235 /* with a redirect rule, we attempt to match the packet's */ 5236 /* source port against in_dport, otherwise we'd compare the */ 5237 /* packet's destination. */ 5238 /* ------------------------------------------------------------- */ 5239 if ((np != NULL) && (np->in_apr != NULL)) { 5240 i = ipf_proxy_check(fin, nat); 5241 if (i == 0) { 5242 i = 1; 5243 } else if (i == -1) { 5244 NBUMPSIDED(1, ns_ipf_proxy_fail); 5245 } 5246 } else { 5247 i = 1; 5248 } 5249 fin->fin_flx |= FI_NATED; 5250 return i; 5251 } 5252 5253 5254 /* ------------------------------------------------------------------------ */ 5255 /* Function: ipf_nat_checkin */ 5256 /* Returns: int - -1 == packet failed NAT checks so block it, */ 5257 /* 0 == no packet translation occurred, */ 5258 /* 1 == packet was successfully translated. */ 5259 /* Parameters: fin(I) - pointer to packet information */ 5260 /* passp(I) - pointer to filtering result flags */ 5261 /* */ 5262 /* Check to see if an incoming packet should be changed. ICMP packets are */ 5263 /* first checked to see if they match an existing entry (if an error), */ 5264 /* otherwise a search of the current NAT table is made. If neither results */ 5265 /* in a match then a search for a matching NAT rule is made. Create a new */ 5266 /* NAT entry if a we matched a NAT rule. Lastly, actually change the */ 5267 /* packet header(s) as required. */ 5268 /* ------------------------------------------------------------------------ */ 5269 int 5270 ipf_nat_checkin(fr_info_t *fin, u_32_t *passp) 5271 { 5272 ipf_main_softc_t *softc; 5273 ipf_nat_softc_t *softn; 5274 u_int nflags, natadd; 5275 ipnat_t *np, *npnext; 5276 int rval, natfailed; 5277 struct ifnet *ifp; 5278 struct in_addr in; 5279 icmphdr_t *icmp; 5280 tcphdr_t *tcp; 5281 u_short dport; 5282 nat_t *nat; 5283 u_32_t iph; 5284 5285 softc = fin->fin_main_soft; 5286 softn = softc->ipf_nat_soft; 5287 5288 if (softn->ipf_nat_lock != 0) 5289 return 0; 5290 if (softn->ipf_nat_stats.ns_rules == 0 && 5291 softn->ipf_nat_instances == NULL) 5292 return 0; 5293 5294 tcp = NULL; 5295 icmp = NULL; 5296 dport = 0; 5297 natadd = 1; 5298 nflags = 0; 5299 natfailed = 0; 5300 ifp = fin->fin_ifp; 5301 5302 if (!(fin->fin_flx & FI_SHORT) && (fin->fin_off == 0)) { 5303 switch (fin->fin_p) 5304 { 5305 case IPPROTO_TCP : 5306 nflags = IPN_TCP; 5307 break; 5308 case IPPROTO_UDP : 5309 nflags = IPN_UDP; 5310 break; 5311 case IPPROTO_ICMP : 5312 icmp = fin->fin_dp; 5313 5314 /* 5315 * This is an incoming packet, so the destination is 5316 * the icmp_id and the source port equals 0 5317 */ 5318 if ((fin->fin_flx & FI_ICMPQUERY) != 0) { 5319 nflags = IPN_ICMPQUERY; 5320 dport = icmp->icmp_id; 5321 } break; 5322 default : 5323 break; 5324 } 5325 5326 if ((nflags & IPN_TCPUDP)) { 5327 tcp = fin->fin_dp; 5328 dport = fin->fin_data[1]; 5329 } 5330 } 5331 5332 in = fin->fin_dst; 5333 5334 READ_ENTER(&softc->ipf_nat); 5335 5336 if ((fin->fin_p == IPPROTO_ICMP) && !(nflags & IPN_ICMPQUERY) && 5337 (nat = ipf_nat_icmperror(fin, &nflags, NAT_INBOUND))) 5338 /*EMPTY*/; 5339 else if ((fin->fin_flx & FI_FRAG) && (nat = ipf_frag_natknown(fin))) 5340 natadd = 0; 5341 else if ((nat = ipf_nat_inlookup(fin, nflags|NAT_SEARCH, 5342 (u_int)fin->fin_p, 5343 fin->fin_src, in))) { 5344 nflags = nat->nat_flags; 5345 } else if (fin->fin_off == 0) { 5346 u_32_t hv, msk, rmsk = 0; 5347 5348 /* 5349 * If there is no current entry in the nat table for this IP#, 5350 * create one for it (if there is a matching rule). 5351 */ 5352 maskloop: 5353 msk = softn->ipf_nat_rdr_active_masks[rmsk]; 5354 iph = in.s_addr & msk; 5355 hv = NAT_HASH_FN(iph, 0, softn->ipf_nat_rdrrules_sz); 5356 retry_roundrobin: 5357 /* TRACE (iph,msk,rmsk,hv,softn->ipf_nat_rdrrules_sz) */ 5358 for (np = softn->ipf_nat_rdr_rules[hv]; np; np = npnext) { 5359 npnext = np->in_rnext; 5360 if (np->in_ifps[0] && (np->in_ifps[0] != ifp)) 5361 continue; 5362 if (np->in_v[0] != 4) 5363 continue; 5364 if (np->in_pr[0] && (np->in_pr[0] != fin->fin_p)) 5365 continue; 5366 if ((np->in_flags & IPN_RF) && !(np->in_flags & nflags)) 5367 continue; 5368 if (np->in_flags & IPN_FILTER) { 5369 switch (ipf_nat_match(fin, np)) 5370 { 5371 case 0 : 5372 continue; 5373 case -1 : 5374 rval = -1; 5375 goto inmatchfail; 5376 case 1 : 5377 default : 5378 break; 5379 } 5380 } else { 5381 if ((in.s_addr & np->in_odstmsk) != 5382 np->in_odstaddr) 5383 continue; 5384 if (np->in_odport && 5385 ((np->in_dtop < dport) || 5386 (dport < np->in_odport))) 5387 continue; 5388 } 5389 5390 if (np->in_plabel != -1) { 5391 if (!ipf_proxy_ok(fin, tcp, np)) { 5392 continue; 5393 } 5394 } 5395 5396 if (np->in_flags & IPN_NO) { 5397 np->in_hits++; 5398 break; 5399 } 5400 5401 MUTEX_ENTER(&softn->ipf_nat_new); 5402 /* 5403 * If we've matched a round-robin rule but it has 5404 * moved in the list since we got it, start over as 5405 * this is now no longer correct. 5406 */ 5407 if (npnext != np->in_rnext) { 5408 if ((np->in_flags & IPN_ROUNDR) != 0) { 5409 MUTEX_EXIT(&softn->ipf_nat_new); 5410 goto retry_roundrobin; 5411 } 5412 npnext = np->in_rnext; 5413 } 5414 5415 nat = ipf_nat_add(fin, np, NULL, nflags, NAT_INBOUND); 5416 MUTEX_EXIT(&softn->ipf_nat_new); 5417 if (nat != NULL) { 5418 natfailed = 0; 5419 break; 5420 } 5421 natfailed = -1; 5422 } 5423 if ((np == NULL) && (rmsk < softn->ipf_nat_rdr_max)) { 5424 rmsk++; 5425 goto maskloop; 5426 } 5427 } 5428 5429 if (nat != NULL) { 5430 rval = ipf_nat_in(fin, nat, natadd, nflags); 5431 if (rval == 1) { 5432 MUTEX_ENTER(&nat->nat_lock); 5433 ipf_nat_update(fin, nat); 5434 nat->nat_bytes[0] += fin->fin_plen; 5435 nat->nat_pkts[0]++; 5436 fin->fin_pktnum = nat->nat_pkts[0]; 5437 MUTEX_EXIT(&nat->nat_lock); 5438 } 5439 } else 5440 rval = natfailed; 5441 inmatchfail: 5442 RWLOCK_EXIT(&softc->ipf_nat); 5443 5444 switch (rval) 5445 { 5446 case -1 : 5447 if (passp != NULL) { 5448 DT1(frb_natv4in, fr_info_t *, fin); 5449 NBUMPSIDED(0, ns_drop); 5450 *passp = FR_BLOCK; 5451 fin->fin_reason = FRB_NATV4; 5452 } 5453 fin->fin_flx |= FI_BADNAT; 5454 NBUMPSIDED(0, ns_badnat); 5455 break; 5456 case 0 : 5457 NBUMPSIDE(0, ns_ignored); 5458 break; 5459 case 1 : 5460 NBUMPSIDE(0, ns_translated); 5461 break; 5462 } 5463 return rval; 5464 } 5465 5466 5467 /* ------------------------------------------------------------------------ */ 5468 /* Function: ipf_nat_in */ 5469 /* Returns: int - -1 == packet failed NAT checks so block it, */ 5470 /* 1 == packet was successfully translated. */ 5471 /* Parameters: fin(I) - pointer to packet information */ 5472 /* nat(I) - pointer to NAT structure */ 5473 /* natadd(I) - flag indicating if it is safe to add frag cache */ 5474 /* nflags(I) - NAT flags set for this packet */ 5475 /* Locks Held: ipf_nat(READ) */ 5476 /* */ 5477 /* Translate a packet coming "in" on an interface. */ 5478 /* ------------------------------------------------------------------------ */ 5479 int 5480 ipf_nat_in(fr_info_t *fin, nat_t *nat, int natadd, u_32_t nflags) 5481 { 5482 ipf_main_softc_t *softc = fin->fin_main_soft; 5483 ipf_nat_softc_t *softn = softc->ipf_nat_soft; 5484 u_32_t sumd, ipsumd, sum1, sum2; 5485 icmphdr_t *icmp; 5486 tcphdr_t *tcp; 5487 ipnat_t *np; 5488 int skip; 5489 int i; 5490 5491 tcp = NULL; 5492 np = nat->nat_ptr; 5493 fin->fin_fr = nat->nat_fr; 5494 5495 if (np != NULL) { 5496 if ((natadd != 0) && (fin->fin_flx & FI_FRAG)) 5497 (void) ipf_frag_natnew(softc, fin, 0, nat); 5498 5499 /* ------------------------------------------------------------- */ 5500 /* A few quick notes: */ 5501 /* Following are test conditions prior to calling the */ 5502 /* ipf_proxy_check routine. */ 5503 /* */ 5504 /* A NULL tcp indicates a non TCP/UDP packet. When dealing */ 5505 /* with a map rule, we attempt to match the packet's */ 5506 /* source port against in_dport, otherwise we'd compare the */ 5507 /* packet's destination. */ 5508 /* ------------------------------------------------------------- */ 5509 if (np->in_apr != NULL) { 5510 i = ipf_proxy_check(fin, nat); 5511 if (i == -1) { 5512 NBUMPSIDED(0, ns_ipf_proxy_fail); 5513 return -1; 5514 } 5515 } 5516 } 5517 5518 ipf_sync_update(softc, SMC_NAT, fin, nat->nat_sync); 5519 5520 ipsumd = nat->nat_ipsumd; 5521 /* 5522 * Fix up checksums, not by recalculating them, but 5523 * simply computing adjustments. 5524 * Why only do this for some platforms on inbound packets ? 5525 * Because for those that it is done, IP processing is yet to happen 5526 * and so the IPv4 header checksum has not yet been evaluated. 5527 * Perhaps it should always be done for the benefit of things like 5528 * fast forwarding (so that it doesn't need to be recomputed) but with 5529 * header checksum offloading, perhaps it is a moot point. 5530 */ 5531 5532 switch (nat->nat_dir) 5533 { 5534 case NAT_INBOUND : 5535 if ((fin->fin_flx & FI_ICMPERR) == 0) { 5536 fin->fin_ip->ip_src = nat->nat_nsrcip; 5537 fin->fin_saddr = nat->nat_nsrcaddr; 5538 } else { 5539 sum1 = nat->nat_osrcaddr; 5540 sum2 = nat->nat_nsrcaddr; 5541 CALC_SUMD(sum1, sum2, sumd); 5542 ipsumd -= sumd; 5543 } 5544 fin->fin_ip->ip_dst = nat->nat_ndstip; 5545 fin->fin_daddr = nat->nat_ndstaddr; 5546 #if !defined(_KERNEL) || defined(MENTAT) || defined(__sgi) || \ 5547 defined(__osf__) || defined(linux) 5548 ipf_fix_outcksum(0, &fin->fin_ip->ip_sum, ipsumd, 0); 5549 #endif 5550 break; 5551 5552 case NAT_OUTBOUND : 5553 if ((fin->fin_flx & FI_ICMPERR) == 0) { 5554 fin->fin_ip->ip_src = nat->nat_odstip; 5555 fin->fin_saddr = nat->nat_odstaddr; 5556 } else { 5557 sum1 = nat->nat_odstaddr; 5558 sum2 = nat->nat_ndstaddr; 5559 CALC_SUMD(sum1, sum2, sumd); 5560 ipsumd -= sumd; 5561 } 5562 fin->fin_ip->ip_dst = nat->nat_osrcip; 5563 fin->fin_daddr = nat->nat_osrcaddr; 5564 #if !defined(_KERNEL) || defined(MENTAT) || defined(__sgi) || \ 5565 defined(__osf__) || defined(linux) 5566 ipf_fix_incksum(0, &fin->fin_ip->ip_sum, ipsumd, 0); 5567 #endif 5568 break; 5569 5570 case NAT_DIVERTIN : 5571 { 5572 udphdr_t *uh; 5573 ip_t *ip; 5574 mb_t *m; 5575 5576 m = M_DUP(np->in_divmp); 5577 if (m == NULL) { 5578 NBUMPSIDED(0, ns_divert_dup); 5579 return -1; 5580 } 5581 5582 ip = MTOD(m, ip_t *); 5583 ip->ip_id = htons(ipf_nextipid(fin)); 5584 sum1 = ntohs(ip->ip_len); 5585 ip->ip_len = ntohs(ip->ip_len); 5586 ip->ip_len += fin->fin_plen; 5587 ip->ip_len = htons(ip->ip_len); 5588 5589 uh = (udphdr_t *)(ip + 1); 5590 uh->uh_ulen += fin->fin_plen; 5591 uh->uh_ulen = htons(uh->uh_ulen); 5592 5593 sum2 = ntohs(ip->ip_id) + ntohs(ip->ip_len); 5594 sum2 += ntohs(ip->ip_off) & IP_DF; 5595 CALC_SUMD(sum1, sum2, sumd); 5596 5597 #if !defined(_KERNEL) || defined(MENTAT) || defined(__sgi) || \ 5598 defined(__osf__) || defined(linux) 5599 ipf_fix_outcksum(0, &ip->ip_sum, sumd, 0); 5600 #endif 5601 PREP_MB_T(fin, m); 5602 5603 fin->fin_ip = ip; 5604 fin->fin_plen += sizeof(ip_t) + 8; /* UDP + new IPv4 hdr */ 5605 fin->fin_dlen += sizeof(ip_t) + 8; /* UDP + old IPv4 hdr */ 5606 5607 nflags &= ~IPN_TCPUDPICMP; 5608 5609 break; 5610 } 5611 5612 case NAT_DIVERTOUT : 5613 { 5614 mb_t *m; 5615 5616 skip = ipf_nat_decap(fin, nat); 5617 if (skip <= 0) { 5618 NBUMPSIDED(0, ns_decap_fail); 5619 return -1; 5620 } 5621 5622 m = fin->fin_m; 5623 5624 #if defined(MENTAT) && defined(_KERNEL) 5625 m->b_rptr += skip; 5626 #else 5627 m->m_data += skip; 5628 m->m_len -= skip; 5629 5630 # ifdef M_PKTHDR 5631 if (m->m_flags & M_PKTHDR) 5632 m->m_pkthdr.len -= skip; 5633 # endif 5634 #endif 5635 5636 ipf_nat_update(fin, nat); 5637 nflags &= ~IPN_TCPUDPICMP; 5638 fin->fin_flx |= FI_NATED; 5639 if (np != NULL && np->in_tag.ipt_num[0] != 0) 5640 fin->fin_nattag = &np->in_tag; 5641 return 1; 5642 /* NOTREACHED */ 5643 } 5644 } 5645 if (nflags & IPN_TCPUDP) 5646 tcp = fin->fin_dp; 5647 5648 if (!(fin->fin_flx & FI_SHORT) && (fin->fin_off == 0)) { 5649 u_short *csump; 5650 5651 if ((nat->nat_odport != 0) && (nflags & IPN_TCPUDP)) { 5652 switch (nat->nat_dir) 5653 { 5654 case NAT_INBOUND : 5655 tcp->th_sport = nat->nat_nsport; 5656 fin->fin_data[0] = ntohs(nat->nat_nsport); 5657 tcp->th_dport = nat->nat_ndport; 5658 fin->fin_data[1] = ntohs(nat->nat_ndport); 5659 break; 5660 5661 case NAT_OUTBOUND : 5662 tcp->th_sport = nat->nat_odport; 5663 fin->fin_data[0] = ntohs(nat->nat_odport); 5664 tcp->th_dport = nat->nat_osport; 5665 fin->fin_data[1] = ntohs(nat->nat_osport); 5666 break; 5667 } 5668 } 5669 5670 5671 if ((nat->nat_oicmpid != 0) && (nflags & IPN_ICMPQUERY)) { 5672 icmp = fin->fin_dp; 5673 5674 switch (nat->nat_dir) 5675 { 5676 case NAT_INBOUND : 5677 icmp->icmp_id = nat->nat_nicmpid; 5678 break; 5679 case NAT_OUTBOUND : 5680 icmp->icmp_id = nat->nat_oicmpid; 5681 break; 5682 } 5683 } 5684 5685 csump = ipf_nat_proto(fin, nat, nflags); 5686 5687 /* 5688 * The above comments do not hold for layer 4 (or higher) 5689 * checksums... 5690 */ 5691 if (csump != NULL) { 5692 if (nat->nat_dir == NAT_OUTBOUND) 5693 ipf_fix_incksum(0, csump, nat->nat_sumd[0], 0); 5694 else 5695 ipf_fix_outcksum(0, csump, nat->nat_sumd[0], 0); 5696 } 5697 } 5698 5699 fin->fin_flx |= FI_NATED; 5700 if (np != NULL && np->in_tag.ipt_num[0] != 0) 5701 fin->fin_nattag = &np->in_tag; 5702 return 1; 5703 } 5704 5705 5706 /* ------------------------------------------------------------------------ */ 5707 /* Function: ipf_nat_proto */ 5708 /* Returns: u_short* - pointer to transport header checksum to update, */ 5709 /* NULL if the transport protocol is not recognised */ 5710 /* as needing a checksum update. */ 5711 /* Parameters: fin(I) - pointer to packet information */ 5712 /* nat(I) - pointer to NAT structure */ 5713 /* nflags(I) - NAT flags set for this packet */ 5714 /* */ 5715 /* Return the pointer to the checksum field for each protocol so understood.*/ 5716 /* If support for making other changes to a protocol header is required, */ 5717 /* that is not strictly 'address' translation, such as clamping the MSS in */ 5718 /* TCP down to a specific value, then do it from here. */ 5719 /* ------------------------------------------------------------------------ */ 5720 u_short * 5721 ipf_nat_proto(fr_info_t *fin, nat_t *nat, u_int nflags) 5722 { 5723 icmphdr_t *icmp; 5724 u_short *csump; 5725 tcphdr_t *tcp; 5726 udphdr_t *udp; 5727 5728 csump = NULL; 5729 if (fin->fin_out == 0) { 5730 fin->fin_rev = (nat->nat_dir & NAT_OUTBOUND); 5731 } else { 5732 fin->fin_rev = ((nat->nat_dir & NAT_OUTBOUND) == 0); 5733 } 5734 5735 switch (fin->fin_p) 5736 { 5737 case IPPROTO_TCP : 5738 tcp = fin->fin_dp; 5739 5740 if ((nflags & IPN_TCP) != 0) 5741 csump = &tcp->th_sum; 5742 5743 /* 5744 * Do a MSS CLAMPING on a SYN packet, 5745 * only deal IPv4 for now. 5746 */ 5747 if ((nat->nat_mssclamp != 0) && (tcp->th_flags & TH_SYN) != 0) 5748 ipf_nat_mssclamp(tcp, nat->nat_mssclamp, fin, csump); 5749 5750 break; 5751 5752 case IPPROTO_UDP : 5753 udp = fin->fin_dp; 5754 5755 if ((nflags & IPN_UDP) != 0) { 5756 if (udp->uh_sum != 0) 5757 csump = &udp->uh_sum; 5758 } 5759 break; 5760 5761 case IPPROTO_ICMP : 5762 icmp = fin->fin_dp; 5763 5764 if ((nflags & IPN_ICMPQUERY) != 0) { 5765 if (icmp->icmp_cksum != 0) 5766 csump = &icmp->icmp_cksum; 5767 } 5768 break; 5769 5770 #ifdef USE_INET6 5771 case IPPROTO_ICMPV6 : 5772 { 5773 struct icmp6_hdr *icmp6 = (struct icmp6_hdr *)fin->fin_dp; 5774 5775 icmp6 = fin->fin_dp; 5776 5777 if ((nflags & IPN_ICMPQUERY) != 0) { 5778 if (icmp6->icmp6_cksum != 0) 5779 csump = &icmp6->icmp6_cksum; 5780 } 5781 break; 5782 } 5783 #endif 5784 } 5785 return csump; 5786 } 5787 5788 5789 /* ------------------------------------------------------------------------ */ 5790 /* Function: ipf_nat_expire */ 5791 /* Returns: Nil */ 5792 /* Parameters: softc(I) - pointer to soft context main structure */ 5793 /* */ 5794 /* Check all of the timeout queues for entries at the top which need to be */ 5795 /* expired. */ 5796 /* ------------------------------------------------------------------------ */ 5797 void 5798 ipf_nat_expire(ipf_main_softc_t *softc) 5799 { 5800 ipf_nat_softc_t *softn = softc->ipf_nat_soft; 5801 ipftq_t *ifq, *ifqnext; 5802 ipftqent_t *tqe, *tqn; 5803 int i; 5804 SPL_INT(s); 5805 5806 SPL_NET(s); 5807 WRITE_ENTER(&softc->ipf_nat); 5808 for (ifq = softn->ipf_nat_tcptq, i = 0; ifq != NULL; 5809 ifq = ifq->ifq_next) { 5810 for (tqn = ifq->ifq_head; ((tqe = tqn) != NULL); i++) { 5811 if (tqe->tqe_die > softc->ipf_ticks) 5812 break; 5813 tqn = tqe->tqe_next; 5814 ipf_nat_delete(softc, tqe->tqe_parent, NL_EXPIRE); 5815 } 5816 } 5817 5818 for (ifq = softn->ipf_nat_utqe; ifq != NULL; ifq = ifq->ifq_next) { 5819 for (tqn = ifq->ifq_head; ((tqe = tqn) != NULL); i++) { 5820 if (tqe->tqe_die > softc->ipf_ticks) 5821 break; 5822 tqn = tqe->tqe_next; 5823 ipf_nat_delete(softc, tqe->tqe_parent, NL_EXPIRE); 5824 } 5825 } 5826 5827 for (ifq = softn->ipf_nat_utqe; ifq != NULL; ifq = ifqnext) { 5828 ifqnext = ifq->ifq_next; 5829 5830 if (((ifq->ifq_flags & IFQF_DELETE) != 0) && 5831 (ifq->ifq_ref == 0)) { 5832 ipf_freetimeoutqueue(softc, ifq); 5833 } 5834 } 5835 5836 if (softn->ipf_nat_doflush != 0) { 5837 ipf_nat_extraflush(softc, softn, 2); 5838 softn->ipf_nat_doflush = 0; 5839 } 5840 5841 RWLOCK_EXIT(&softc->ipf_nat); 5842 SPL_X(s); 5843 } 5844 5845 5846 /* ------------------------------------------------------------------------ */ 5847 /* Function: ipf_nat_sync */ 5848 /* Returns: Nil */ 5849 /* Parameters: softc(I) - pointer to soft context main structure */ 5850 /* ifp(I) - pointer to network interface */ 5851 /* */ 5852 /* Walk through all of the currently active NAT sessions, looking for those */ 5853 /* which need to have their translated address updated. */ 5854 /* ------------------------------------------------------------------------ */ 5855 void 5856 ipf_nat_sync(ipf_main_softc_t *softc, void *ifp) 5857 { 5858 ipf_nat_softc_t *softn = softc->ipf_nat_soft; 5859 u_32_t sum1, sum2, sumd; 5860 i6addr_t in; 5861 ipnat_t *n; 5862 nat_t *nat; 5863 void *ifp2; 5864 int idx; 5865 SPL_INT(s); 5866 5867 if (softc->ipf_running <= 0) 5868 return; 5869 5870 /* 5871 * Change IP addresses for NAT sessions for any protocol except TCP 5872 * since it will break the TCP connection anyway. The only rules 5873 * which will get changed are those which are "map ... -> 0/32", 5874 * where the rule specifies the address is taken from the interface. 5875 */ 5876 SPL_NET(s); 5877 WRITE_ENTER(&softc->ipf_nat); 5878 5879 if (softc->ipf_running <= 0) { 5880 RWLOCK_EXIT(&softc->ipf_nat); 5881 return; 5882 } 5883 5884 for (nat = softn->ipf_nat_instances; nat; nat = nat->nat_next) { 5885 if ((nat->nat_flags & IPN_TCP) != 0) 5886 continue; 5887 5888 n = nat->nat_ptr; 5889 if (n != NULL) { 5890 if (n->in_v[1] == 4) { 5891 if (n->in_redir & NAT_MAP) { 5892 if ((n->in_nsrcaddr != 0) || 5893 (n->in_nsrcmsk != 0xffffffff)) 5894 continue; 5895 } else if (n->in_redir & NAT_REDIRECT) { 5896 if ((n->in_ndstaddr != 0) || 5897 (n->in_ndstmsk != 0xffffffff)) 5898 continue; 5899 } 5900 } 5901 #ifdef USE_INET6 5902 if (n->in_v[1] == 4) { 5903 if (n->in_redir & NAT_MAP) { 5904 if (!IP6_ISZERO(&n->in_nsrcaddr) || 5905 !IP6_ISONES(&n->in_nsrcmsk)) 5906 continue; 5907 } else if (n->in_redir & NAT_REDIRECT) { 5908 if (!IP6_ISZERO(&n->in_ndstaddr) || 5909 !IP6_ISONES(&n->in_ndstmsk)) 5910 continue; 5911 } 5912 } 5913 #endif 5914 } 5915 5916 if (((ifp == NULL) || (ifp == nat->nat_ifps[0]) || 5917 (ifp == nat->nat_ifps[1]))) { 5918 nat->nat_ifps[0] = GETIFP(nat->nat_ifnames[0], 5919 nat->nat_v[0]); 5920 if ((nat->nat_ifps[0] != NULL) && 5921 (nat->nat_ifps[0] != (void *)-1)) { 5922 nat->nat_mtu[0] = GETIFMTU_4(nat->nat_ifps[0]); 5923 } 5924 if (nat->nat_ifnames[1][0] != '\0') { 5925 nat->nat_ifps[1] = GETIFP(nat->nat_ifnames[1], 5926 nat->nat_v[1]); 5927 } else { 5928 nat->nat_ifps[1] = nat->nat_ifps[0]; 5929 } 5930 if ((nat->nat_ifps[1] != NULL) && 5931 (nat->nat_ifps[1] != (void *)-1)) { 5932 nat->nat_mtu[1] = GETIFMTU_4(nat->nat_ifps[1]); 5933 } 5934 ifp2 = nat->nat_ifps[0]; 5935 if (ifp2 == NULL) 5936 continue; 5937 5938 /* 5939 * Change the map-to address to be the same as the 5940 * new one. 5941 */ 5942 sum1 = NATFSUM(nat, nat->nat_v[1], nat_nsrc6); 5943 if (ipf_ifpaddr(softc, nat->nat_v[0], FRI_NORMAL, ifp2, 5944 &in, NULL) != -1) { 5945 if (nat->nat_v[0] == 4) 5946 nat->nat_nsrcip = in.in4; 5947 } 5948 sum2 = NATFSUM(nat, nat->nat_v[1], nat_nsrc6); 5949 5950 if (sum1 == sum2) 5951 continue; 5952 /* 5953 * Readjust the checksum adjustment to take into 5954 * account the new IP#. 5955 */ 5956 CALC_SUMD(sum1, sum2, sumd); 5957 /* XXX - dont change for TCP when solaris does 5958 * hardware checksumming. 5959 */ 5960 sumd += nat->nat_sumd[0]; 5961 nat->nat_sumd[0] = (sumd & 0xffff) + (sumd >> 16); 5962 nat->nat_sumd[1] = nat->nat_sumd[0]; 5963 } 5964 } 5965 5966 for (n = softn->ipf_nat_list; (n != NULL); n = n->in_next) { 5967 char *base = n->in_names; 5968 5969 if ((ifp == NULL) || (n->in_ifps[0] == ifp)) 5970 n->in_ifps[0] = ipf_resolvenic(softc, 5971 base + n->in_ifnames[0], 5972 n->in_v[0]); 5973 if ((ifp == NULL) || (n->in_ifps[1] == ifp)) 5974 n->in_ifps[1] = ipf_resolvenic(softc, 5975 base + n->in_ifnames[1], 5976 n->in_v[1]); 5977 5978 if (n->in_redir & NAT_REDIRECT) 5979 idx = 1; 5980 else 5981 idx = 0; 5982 5983 if (((ifp == NULL) || (n->in_ifps[idx] == ifp)) && 5984 (n->in_ifps[idx] != NULL && 5985 n->in_ifps[idx] != (void *)-1)) { 5986 5987 ipf_nat_nextaddrinit(softc, n->in_names, &n->in_osrc, 5988 0, n->in_ifps[idx]); 5989 ipf_nat_nextaddrinit(softc, n->in_names, &n->in_odst, 5990 0, n->in_ifps[idx]); 5991 ipf_nat_nextaddrinit(softc, n->in_names, &n->in_nsrc, 5992 0, n->in_ifps[idx]); 5993 ipf_nat_nextaddrinit(softc, n->in_names, &n->in_ndst, 5994 0, n->in_ifps[idx]); 5995 } 5996 } 5997 RWLOCK_EXIT(&softc->ipf_nat); 5998 SPL_X(s); 5999 } 6000 6001 6002 /* ------------------------------------------------------------------------ */ 6003 /* Function: ipf_nat_icmpquerytype */ 6004 /* Returns: int - 1 == success, 0 == failure */ 6005 /* Parameters: icmptype(I) - ICMP type number */ 6006 /* */ 6007 /* Tests to see if the ICMP type number passed is a query/response type or */ 6008 /* not. */ 6009 /* ------------------------------------------------------------------------ */ 6010 static int 6011 ipf_nat_icmpquerytype(int icmptype) 6012 { 6013 6014 /* 6015 * For the ICMP query NAT code, it is essential that both the query 6016 * and the reply match on the NAT rule. Because the NAT structure 6017 * does not keep track of the icmptype, and a single NAT structure 6018 * is used for all icmp types with the same src, dest and id, we 6019 * simply define the replies as queries as well. The funny thing is, 6020 * although it seems silly to call a reply a query, this is exactly 6021 * as it is defined in the IPv4 specification 6022 */ 6023 switch (icmptype) 6024 { 6025 case ICMP_ECHOREPLY: 6026 case ICMP_ECHO: 6027 /* route advertisement/sollicitation is currently unsupported: */ 6028 /* it would require rewriting the ICMP data section */ 6029 case ICMP_TSTAMP: 6030 case ICMP_TSTAMPREPLY: 6031 case ICMP_IREQ: 6032 case ICMP_IREQREPLY: 6033 case ICMP_MASKREQ: 6034 case ICMP_MASKREPLY: 6035 return 1; 6036 default: 6037 return 0; 6038 } 6039 } 6040 6041 6042 /* ------------------------------------------------------------------------ */ 6043 /* Function: nat_log */ 6044 /* Returns: Nil */ 6045 /* Parameters: softc(I) - pointer to soft context main structure */ 6046 /* softn(I) - pointer to NAT context structure */ 6047 /* nat(I) - pointer to NAT structure */ 6048 /* action(I) - action related to NAT structure being performed */ 6049 /* */ 6050 /* Creates a NAT log entry. */ 6051 /* ------------------------------------------------------------------------ */ 6052 void 6053 ipf_nat_log(ipf_main_softc_t *softc, ipf_nat_softc_t *softn, struct nat *nat, 6054 u_int action) 6055 { 6056 #ifdef IPFILTER_LOG 6057 # ifndef LARGE_NAT 6058 struct ipnat *np; 6059 int rulen; 6060 # endif 6061 struct natlog natl; 6062 void *items[1]; 6063 size_t sizes[1]; 6064 int types[1]; 6065 6066 bcopy((char *)&nat->nat_osrc6, (char *)&natl.nl_osrcip, 6067 sizeof(natl.nl_osrcip)); 6068 bcopy((char *)&nat->nat_nsrc6, (char *)&natl.nl_nsrcip, 6069 sizeof(natl.nl_nsrcip)); 6070 bcopy((char *)&nat->nat_odst6, (char *)&natl.nl_odstip, 6071 sizeof(natl.nl_odstip)); 6072 bcopy((char *)&nat->nat_ndst6, (char *)&natl.nl_ndstip, 6073 sizeof(natl.nl_ndstip)); 6074 6075 natl.nl_bytes[0] = nat->nat_bytes[0]; 6076 natl.nl_bytes[1] = nat->nat_bytes[1]; 6077 natl.nl_pkts[0] = nat->nat_pkts[0]; 6078 natl.nl_pkts[1] = nat->nat_pkts[1]; 6079 natl.nl_odstport = nat->nat_odport; 6080 natl.nl_osrcport = nat->nat_osport; 6081 natl.nl_nsrcport = nat->nat_nsport; 6082 natl.nl_ndstport = nat->nat_ndport; 6083 natl.nl_p[0] = nat->nat_pr[0]; 6084 natl.nl_p[1] = nat->nat_pr[1]; 6085 natl.nl_v[0] = nat->nat_v[0]; 6086 natl.nl_v[1] = nat->nat_v[1]; 6087 natl.nl_type = nat->nat_redir; 6088 natl.nl_action = action; 6089 natl.nl_rule = -1; 6090 6091 bcopy(nat->nat_ifnames[0], natl.nl_ifnames[0], 6092 sizeof(nat->nat_ifnames[0])); 6093 bcopy(nat->nat_ifnames[1], natl.nl_ifnames[1], 6094 sizeof(nat->nat_ifnames[1])); 6095 6096 # ifndef LARGE_NAT 6097 if (nat->nat_ptr != NULL) { 6098 for (rulen = 0, np = softn->ipf_nat_list; np != NULL; 6099 np = np->in_next, rulen++) 6100 if (np == nat->nat_ptr) { 6101 natl.nl_rule = rulen; 6102 break; 6103 } 6104 } 6105 # endif 6106 items[0] = &natl; 6107 sizes[0] = sizeof(natl); 6108 types[0] = 0; 6109 6110 (void) ipf_log_items(softc, IPL_LOGNAT, NULL, items, sizes, types, 1); 6111 #endif 6112 } 6113 6114 6115 #if defined(__OpenBSD__) 6116 /* ------------------------------------------------------------------------ */ 6117 /* Function: ipf_nat_ifdetach */ 6118 /* Returns: Nil */ 6119 /* Parameters: ifp(I) - pointer to network interface */ 6120 /* */ 6121 /* Compatibility interface for OpenBSD to trigger the correct updating of */ 6122 /* interface references within IPFilter. */ 6123 /* ------------------------------------------------------------------------ */ 6124 void 6125 ipf_nat_ifdetach(ifp) 6126 void *ifp; 6127 { 6128 ipf_main_softc_t *softc; 6129 6130 softc = ipf_get_softc(0); 6131 6132 ipf_sync(ifp); 6133 return; 6134 } 6135 #endif 6136 6137 6138 /* ------------------------------------------------------------------------ */ 6139 /* Function: ipf_nat_rule_deref */ 6140 /* Returns: Nil */ 6141 /* Parameters: softc(I) - pointer to soft context main structure */ 6142 /* inp(I) - pointer to pointer to NAT rule */ 6143 /* Write Locks: ipf_nat */ 6144 /* */ 6145 /* Dropping the refernce count for a rule means that whatever held the */ 6146 /* pointer to this rule (*inp) is no longer interested in it and when the */ 6147 /* reference count drops to zero, any resources allocated for the rule can */ 6148 /* be released and the rule itself free'd. */ 6149 /* ------------------------------------------------------------------------ */ 6150 void 6151 ipf_nat_rule_deref(ipf_main_softc_t *softc, ipnat_t **inp) 6152 { 6153 ipf_nat_softc_t *softn = softc->ipf_nat_soft; 6154 ipnat_t *n; 6155 6156 n = *inp; 6157 *inp = NULL; 6158 n->in_use--; 6159 if (n->in_use > 0) 6160 return; 6161 6162 if (n->in_apr != NULL) 6163 ipf_proxy_deref(n->in_apr); 6164 6165 ipf_nat_rule_fini(softc, n); 6166 6167 if (n->in_redir & NAT_REDIRECT) { 6168 if ((n->in_flags & IPN_PROXYRULE) == 0) { 6169 ATOMIC_DEC32(softn->ipf_nat_stats.ns_rules_rdr); 6170 } 6171 } 6172 if (n->in_redir & (NAT_MAP|NAT_MAPBLK)) { 6173 if ((n->in_flags & IPN_PROXYRULE) == 0) { 6174 ATOMIC_DEC32(softn->ipf_nat_stats.ns_rules_map); 6175 } 6176 } 6177 6178 if (n->in_tqehead[0] != NULL) { 6179 if (ipf_deletetimeoutqueue(n->in_tqehead[0]) == 0) { 6180 ipf_freetimeoutqueue(softc, n->in_tqehead[0]); 6181 } 6182 } 6183 6184 if (n->in_tqehead[1] != NULL) { 6185 if (ipf_deletetimeoutqueue(n->in_tqehead[1]) == 0) { 6186 ipf_freetimeoutqueue(softc, n->in_tqehead[1]); 6187 } 6188 } 6189 6190 if ((n->in_flags & IPN_PROXYRULE) == 0) { 6191 ATOMIC_DEC32(softn->ipf_nat_stats.ns_rules); 6192 } 6193 6194 MUTEX_DESTROY(&n->in_lock); 6195 6196 KFREES(n, n->in_size); 6197 6198 #if SOLARIS && !defined(INSTANCES) 6199 if (softn->ipf_nat_stats.ns_rules == 0) 6200 pfil_delayed_copy = 1; 6201 #endif 6202 } 6203 6204 6205 /* ------------------------------------------------------------------------ */ 6206 /* Function: ipf_nat_deref */ 6207 /* Returns: Nil */ 6208 /* Parameters: softc(I) - pointer to soft context main structure */ 6209 /* natp(I) - pointer to pointer to NAT table entry */ 6210 /* */ 6211 /* Decrement the reference counter for this NAT table entry and free it if */ 6212 /* there are no more things using it. */ 6213 /* */ 6214 /* IF nat_ref == 1 when this function is called, then we have an orphan nat */ 6215 /* structure *because* it only gets called on paths _after_ nat_ref has been*/ 6216 /* incremented. If nat_ref == 1 then we shouldn't decrement it here */ 6217 /* because nat_delete() will do that and send nat_ref to -1. */ 6218 /* */ 6219 /* Holding the lock on nat_lock is required to serialise nat_delete() being */ 6220 /* called from a NAT flush ioctl with a deref happening because of a packet.*/ 6221 /* ------------------------------------------------------------------------ */ 6222 void 6223 ipf_nat_deref(ipf_main_softc_t *softc, nat_t **natp) 6224 { 6225 nat_t *nat; 6226 6227 nat = *natp; 6228 *natp = NULL; 6229 6230 MUTEX_ENTER(&nat->nat_lock); 6231 if (nat->nat_ref > 1) { 6232 nat->nat_ref--; 6233 ASSERT(nat->nat_ref >= 0); 6234 MUTEX_EXIT(&nat->nat_lock); 6235 return; 6236 } 6237 MUTEX_EXIT(&nat->nat_lock); 6238 6239 WRITE_ENTER(&softc->ipf_nat); 6240 ipf_nat_delete(softc, nat, NL_EXPIRE); 6241 RWLOCK_EXIT(&softc->ipf_nat); 6242 } 6243 6244 6245 /* ------------------------------------------------------------------------ */ 6246 /* Function: ipf_nat_clone */ 6247 /* Returns: ipstate_t* - NULL == cloning failed, */ 6248 /* else pointer to new state structure */ 6249 /* Parameters: fin(I) - pointer to packet information */ 6250 /* is(I) - pointer to master state structure */ 6251 /* Write Lock: ipf_nat */ 6252 /* */ 6253 /* Create a "duplcate" state table entry from the master. */ 6254 /* ------------------------------------------------------------------------ */ 6255 nat_t * 6256 ipf_nat_clone(fr_info_t *fin, nat_t *nat) 6257 { 6258 ipf_main_softc_t *softc = fin->fin_main_soft; 6259 ipf_nat_softc_t *softn = softc->ipf_nat_soft; 6260 frentry_t *fr; 6261 nat_t *clone; 6262 ipnat_t *np; 6263 6264 KMALLOC(clone, nat_t *); 6265 if (clone == NULL) { 6266 NBUMPSIDED(fin->fin_out, ns_clone_nomem); 6267 return NULL; 6268 } 6269 bcopy((char *)nat, (char *)clone, sizeof(*clone)); 6270 6271 MUTEX_NUKE(&clone->nat_lock); 6272 6273 clone->nat_rev = fin->fin_rev; 6274 clone->nat_aps = NULL; 6275 /* 6276 * Initialize all these so that ipf_nat_delete() doesn't cause a crash. 6277 */ 6278 clone->nat_tqe.tqe_pnext = NULL; 6279 clone->nat_tqe.tqe_next = NULL; 6280 clone->nat_tqe.tqe_ifq = NULL; 6281 clone->nat_tqe.tqe_parent = clone; 6282 6283 clone->nat_flags &= ~SI_CLONE; 6284 clone->nat_flags |= SI_CLONED; 6285 6286 if (clone->nat_hm) 6287 clone->nat_hm->hm_ref++; 6288 6289 if (ipf_nat_insert(softc, softn, clone) == -1) { 6290 KFREE(clone); 6291 NBUMPSIDED(fin->fin_out, ns_insert_fail); 6292 return NULL; 6293 } 6294 6295 np = clone->nat_ptr; 6296 if (np != NULL) { 6297 if (softn->ipf_nat_logging) 6298 ipf_nat_log(softc, softn, clone, NL_CLONE); 6299 np->in_use++; 6300 } 6301 fr = clone->nat_fr; 6302 if (fr != NULL) { 6303 MUTEX_ENTER(&fr->fr_lock); 6304 fr->fr_ref++; 6305 MUTEX_EXIT(&fr->fr_lock); 6306 } 6307 6308 6309 /* 6310 * Because the clone is created outside the normal loop of things and 6311 * TCP has special needs in terms of state, initialise the timeout 6312 * state of the new NAT from here. 6313 */ 6314 if (clone->nat_pr[0] == IPPROTO_TCP) { 6315 (void) ipf_tcp_age(&clone->nat_tqe, fin, softn->ipf_nat_tcptq, 6316 clone->nat_flags, 2); 6317 } 6318 clone->nat_sync = ipf_sync_new(softc, SMC_NAT, fin, clone); 6319 if (softn->ipf_nat_logging) 6320 ipf_nat_log(softc, softn, clone, NL_CLONE); 6321 return clone; 6322 } 6323 6324 6325 /* ------------------------------------------------------------------------ */ 6326 /* Function: ipf_nat_wildok */ 6327 /* Returns: int - 1 == packet's ports match wildcards */ 6328 /* 0 == packet's ports don't match wildcards */ 6329 /* Parameters: nat(I) - NAT entry */ 6330 /* sport(I) - source port */ 6331 /* dport(I) - destination port */ 6332 /* flags(I) - wildcard flags */ 6333 /* dir(I) - packet direction */ 6334 /* */ 6335 /* Use NAT entry and packet direction to determine which combination of */ 6336 /* wildcard flags should be used. */ 6337 /* ------------------------------------------------------------------------ */ 6338 int 6339 ipf_nat_wildok(nat_t *nat, int sport, int dport, int flags, int dir) 6340 { 6341 /* 6342 * When called by dir is set to 6343 * nat_inlookup NAT_INBOUND (0) 6344 * nat_outlookup NAT_OUTBOUND (1) 6345 * 6346 * We simply combine the packet's direction in dir with the original 6347 * "intended" direction of that NAT entry in nat->nat_dir to decide 6348 * which combination of wildcard flags to allow. 6349 */ 6350 switch ((dir << 1) | (nat->nat_dir & (NAT_INBOUND|NAT_OUTBOUND))) 6351 { 6352 case 3: /* outbound packet / outbound entry */ 6353 if (((nat->nat_osport == sport) || 6354 (flags & SI_W_SPORT)) && 6355 ((nat->nat_odport == dport) || 6356 (flags & SI_W_DPORT))) 6357 return 1; 6358 break; 6359 case 2: /* outbound packet / inbound entry */ 6360 if (((nat->nat_osport == dport) || 6361 (flags & SI_W_SPORT)) && 6362 ((nat->nat_odport == sport) || 6363 (flags & SI_W_DPORT))) 6364 return 1; 6365 break; 6366 case 1: /* inbound packet / outbound entry */ 6367 if (((nat->nat_osport == dport) || 6368 (flags & SI_W_SPORT)) && 6369 ((nat->nat_odport == sport) || 6370 (flags & SI_W_DPORT))) 6371 return 1; 6372 break; 6373 case 0: /* inbound packet / inbound entry */ 6374 if (((nat->nat_osport == sport) || 6375 (flags & SI_W_SPORT)) && 6376 ((nat->nat_odport == dport) || 6377 (flags & SI_W_DPORT))) 6378 return 1; 6379 break; 6380 default: 6381 break; 6382 } 6383 6384 return(0); 6385 } 6386 6387 6388 /* ------------------------------------------------------------------------ */ 6389 /* Function: nat_mssclamp */ 6390 /* Returns: Nil */ 6391 /* Parameters: tcp(I) - pointer to TCP header */ 6392 /* maxmss(I) - value to clamp the TCP MSS to */ 6393 /* fin(I) - pointer to packet information */ 6394 /* csump(I) - pointer to TCP checksum */ 6395 /* */ 6396 /* Check for MSS option and clamp it if necessary. If found and changed, */ 6397 /* then the TCP header checksum will be updated to reflect the change in */ 6398 /* the MSS. */ 6399 /* ------------------------------------------------------------------------ */ 6400 static void 6401 ipf_nat_mssclamp(tcphdr_t *tcp, u_32_t maxmss, fr_info_t *fin, u_short *csump) 6402 { 6403 u_char *cp, *ep, opt; 6404 int hlen, advance; 6405 u_32_t mss, sumd; 6406 6407 hlen = TCP_OFF(tcp) << 2; 6408 if (hlen > sizeof(*tcp)) { 6409 cp = (u_char *)tcp + sizeof(*tcp); 6410 ep = (u_char *)tcp + hlen; 6411 6412 while (cp < ep) { 6413 opt = cp[0]; 6414 if (opt == TCPOPT_EOL) 6415 break; 6416 else if (opt == TCPOPT_NOP) { 6417 cp++; 6418 continue; 6419 } 6420 6421 if (cp + 1 >= ep) 6422 break; 6423 advance = cp[1]; 6424 if ((cp + advance > ep) || (advance <= 0)) 6425 break; 6426 switch (opt) 6427 { 6428 case TCPOPT_MAXSEG: 6429 if (advance != 4) 6430 break; 6431 mss = cp[2] * 256 + cp[3]; 6432 if (mss > maxmss) { 6433 cp[2] = maxmss / 256; 6434 cp[3] = maxmss & 0xff; 6435 CALC_SUMD(mss, maxmss, sumd); 6436 ipf_fix_outcksum(0, csump, sumd, 0); 6437 } 6438 break; 6439 default: 6440 /* ignore unknown options */ 6441 break; 6442 } 6443 6444 cp += advance; 6445 } 6446 } 6447 } 6448 6449 6450 /* ------------------------------------------------------------------------ */ 6451 /* Function: ipf_nat_setqueue */ 6452 /* Returns: Nil */ 6453 /* Parameters: softc(I) - pointer to soft context main structure */ 6454 /* softn(I) - pointer to NAT context structure */ 6455 /* nat(I)- pointer to NAT structure */ 6456 /* Locks: ipf_nat (read or write) */ 6457 /* */ 6458 /* Put the NAT entry on its default queue entry, using rev as a helped in */ 6459 /* determining which queue it should be placed on. */ 6460 /* ------------------------------------------------------------------------ */ 6461 void 6462 ipf_nat_setqueue(ipf_main_softc_t *softc, ipf_nat_softc_t *softn, nat_t *nat) 6463 { 6464 ipftq_t *oifq, *nifq; 6465 int rev = nat->nat_rev; 6466 6467 if (nat->nat_ptr != NULL) 6468 nifq = nat->nat_ptr->in_tqehead[rev]; 6469 else 6470 nifq = NULL; 6471 6472 if (nifq == NULL) { 6473 switch (nat->nat_pr[0]) 6474 { 6475 case IPPROTO_UDP : 6476 nifq = &softn->ipf_nat_udptq; 6477 break; 6478 case IPPROTO_ICMP : 6479 nifq = &softn->ipf_nat_icmptq; 6480 break; 6481 case IPPROTO_TCP : 6482 nifq = softn->ipf_nat_tcptq + 6483 nat->nat_tqe.tqe_state[rev]; 6484 break; 6485 default : 6486 nifq = &softn->ipf_nat_iptq; 6487 break; 6488 } 6489 } 6490 6491 oifq = nat->nat_tqe.tqe_ifq; 6492 /* 6493 * If it's currently on a timeout queue, move it from one queue to 6494 * another, else put it on the end of the newly determined queue. 6495 */ 6496 if (oifq != NULL) 6497 ipf_movequeue(softc->ipf_ticks, &nat->nat_tqe, oifq, nifq); 6498 else 6499 ipf_queueappend(softc->ipf_ticks, &nat->nat_tqe, nifq, nat); 6500 return; 6501 } 6502 6503 6504 /* ------------------------------------------------------------------------ */ 6505 /* Function: nat_getnext */ 6506 /* Returns: int - 0 == ok, else error */ 6507 /* Parameters: softc(I) - pointer to soft context main structure */ 6508 /* t(I) - pointer to ipftoken structure */ 6509 /* itp(I) - pointer to ipfgeniter_t structure */ 6510 /* */ 6511 /* Fetch the next nat/ipnat structure pointer from the linked list and */ 6512 /* copy it out to the storage space pointed to by itp_data. The next item */ 6513 /* in the list to look at is put back in the ipftoken struture. */ 6514 /* ------------------------------------------------------------------------ */ 6515 static int 6516 ipf_nat_getnext(ipf_main_softc_t *softc, ipftoken_t *t, ipfgeniter_t *itp, 6517 ipfobj_t *objp) 6518 { 6519 ipf_nat_softc_t *softn = softc->ipf_nat_soft; 6520 hostmap_t *hm, *nexthm = NULL, zerohm; 6521 ipnat_t *ipn, *nextipnat = NULL, zeroipn; 6522 nat_t *nat, *nextnat = NULL, zeronat; 6523 int error = 0; 6524 void *nnext; 6525 6526 if (itp->igi_nitems != 1) { 6527 IPFERROR(60075); 6528 return ENOSPC; 6529 } 6530 6531 READ_ENTER(&softc->ipf_nat); 6532 6533 switch (itp->igi_type) 6534 { 6535 case IPFGENITER_HOSTMAP : 6536 hm = t->ipt_data; 6537 if (hm == NULL) { 6538 nexthm = softn->ipf_hm_maplist; 6539 } else { 6540 nexthm = hm->hm_next; 6541 } 6542 if (nexthm != NULL) { 6543 ATOMIC_INC32(nexthm->hm_ref); 6544 t->ipt_data = nexthm; 6545 } else { 6546 bzero(&zerohm, sizeof(zerohm)); 6547 nexthm = &zerohm; 6548 t->ipt_data = NULL; 6549 } 6550 nnext = nexthm->hm_next; 6551 break; 6552 6553 case IPFGENITER_IPNAT : 6554 ipn = t->ipt_data; 6555 if (ipn == NULL) { 6556 nextipnat = softn->ipf_nat_list; 6557 } else { 6558 nextipnat = ipn->in_next; 6559 } 6560 if (nextipnat != NULL) { 6561 ATOMIC_INC32(nextipnat->in_use); 6562 t->ipt_data = nextipnat; 6563 } else { 6564 bzero(&zeroipn, sizeof(zeroipn)); 6565 nextipnat = &zeroipn; 6566 t->ipt_data = NULL; 6567 } 6568 nnext = nextipnat->in_next; 6569 break; 6570 6571 case IPFGENITER_NAT : 6572 nat = t->ipt_data; 6573 if (nat == NULL) { 6574 nextnat = softn->ipf_nat_instances; 6575 } else { 6576 nextnat = nat->nat_next; 6577 } 6578 if (nextnat != NULL) { 6579 MUTEX_ENTER(&nextnat->nat_lock); 6580 nextnat->nat_ref++; 6581 MUTEX_EXIT(&nextnat->nat_lock); 6582 t->ipt_data = nextnat; 6583 } else { 6584 bzero(&zeronat, sizeof(zeronat)); 6585 nextnat = &zeronat; 6586 t->ipt_data = NULL; 6587 } 6588 nnext = nextnat->nat_next; 6589 break; 6590 6591 default : 6592 RWLOCK_EXIT(&softc->ipf_nat); 6593 IPFERROR(60055); 6594 return EINVAL; 6595 } 6596 6597 RWLOCK_EXIT(&softc->ipf_nat); 6598 6599 objp->ipfo_ptr = itp->igi_data; 6600 6601 switch (itp->igi_type) 6602 { 6603 case IPFGENITER_HOSTMAP : 6604 error = COPYOUT(nexthm, objp->ipfo_ptr, sizeof(*nexthm)); 6605 if (error != 0) { 6606 IPFERROR(60049); 6607 error = EFAULT; 6608 } 6609 if (hm != NULL) { 6610 WRITE_ENTER(&softc->ipf_nat); 6611 ipf_nat_hostmapdel(softc, &hm); 6612 RWLOCK_EXIT(&softc->ipf_nat); 6613 } 6614 break; 6615 6616 case IPFGENITER_IPNAT : 6617 objp->ipfo_size = nextipnat->in_size; 6618 objp->ipfo_type = IPFOBJ_IPNAT; 6619 error = ipf_outobjk(softc, objp, nextipnat); 6620 if (ipn != NULL) { 6621 WRITE_ENTER(&softc->ipf_nat); 6622 ipf_nat_rule_deref(softc, &ipn); 6623 RWLOCK_EXIT(&softc->ipf_nat); 6624 } 6625 break; 6626 6627 case IPFGENITER_NAT : 6628 objp->ipfo_size = sizeof(nat_t); 6629 objp->ipfo_type = IPFOBJ_NAT; 6630 error = ipf_outobjk(softc, objp, nextnat); 6631 if (nat != NULL) 6632 ipf_nat_deref(softc, &nat); 6633 6634 break; 6635 } 6636 6637 if (nnext == NULL) 6638 ipf_token_mark_complete(t); 6639 6640 return error; 6641 } 6642 6643 6644 /* ------------------------------------------------------------------------ */ 6645 /* Function: nat_extraflush */ 6646 /* Returns: int - 0 == success, -1 == failure */ 6647 /* Parameters: softc(I) - pointer to soft context main structure */ 6648 /* softn(I) - pointer to NAT context structure */ 6649 /* which(I) - how to flush the active NAT table */ 6650 /* Write Locks: ipf_nat */ 6651 /* */ 6652 /* Flush nat tables. Three actions currently defined: */ 6653 /* which == 0 : flush all nat table entries */ 6654 /* which == 1 : flush TCP connections which have started to close but are */ 6655 /* stuck for some reason. */ 6656 /* which == 2 : flush TCP connections which have been idle for a long time, */ 6657 /* starting at > 4 days idle and working back in successive half-*/ 6658 /* days to at most 12 hours old. If this fails to free enough */ 6659 /* slots then work backwards in half hour slots to 30 minutes. */ 6660 /* If that too fails, then work backwards in 30 second intervals */ 6661 /* for the last 30 minutes to at worst 30 seconds idle. */ 6662 /* ------------------------------------------------------------------------ */ 6663 static int 6664 ipf_nat_extraflush(ipf_main_softc_t *softc, ipf_nat_softc_t *softn, int which) 6665 { 6666 nat_t *nat, **natp; 6667 ipftqent_t *tqn; 6668 ipftq_t *ifq; 6669 int removed; 6670 SPL_INT(s); 6671 6672 removed = 0; 6673 6674 SPL_NET(s); 6675 switch (which) 6676 { 6677 case 0 : 6678 softn->ipf_nat_stats.ns_flush_all++; 6679 /* 6680 * Style 0 flush removes everything... 6681 */ 6682 for (natp = &softn->ipf_nat_instances; 6683 ((nat = *natp) != NULL); ) { 6684 ipf_nat_delete(softc, nat, NL_FLUSH); 6685 removed++; 6686 } 6687 break; 6688 6689 case 1 : 6690 softn->ipf_nat_stats.ns_flush_closing++; 6691 /* 6692 * Since we're only interested in things that are closing, 6693 * we can start with the appropriate timeout queue. 6694 */ 6695 for (ifq = softn->ipf_nat_tcptq + IPF_TCPS_CLOSE_WAIT; 6696 ifq != NULL; ifq = ifq->ifq_next) { 6697 6698 for (tqn = ifq->ifq_head; tqn != NULL; ) { 6699 nat = tqn->tqe_parent; 6700 tqn = tqn->tqe_next; 6701 if (nat->nat_pr[0] != IPPROTO_TCP || 6702 nat->nat_pr[1] != IPPROTO_TCP) 6703 break; 6704 ipf_nat_delete(softc, nat, NL_EXPIRE); 6705 removed++; 6706 } 6707 } 6708 6709 /* 6710 * Also need to look through the user defined queues. 6711 */ 6712 for (ifq = softn->ipf_nat_utqe; ifq != NULL; 6713 ifq = ifq->ifq_next) { 6714 for (tqn = ifq->ifq_head; tqn != NULL; ) { 6715 nat = tqn->tqe_parent; 6716 tqn = tqn->tqe_next; 6717 if (nat->nat_pr[0] != IPPROTO_TCP || 6718 nat->nat_pr[1] != IPPROTO_TCP) 6719 continue; 6720 6721 if ((nat->nat_tcpstate[0] > 6722 IPF_TCPS_ESTABLISHED) && 6723 (nat->nat_tcpstate[1] > 6724 IPF_TCPS_ESTABLISHED)) { 6725 ipf_nat_delete(softc, nat, NL_EXPIRE); 6726 removed++; 6727 } 6728 } 6729 } 6730 break; 6731 6732 /* 6733 * Args 5-11 correspond to flushing those particular states 6734 * for TCP connections. 6735 */ 6736 case IPF_TCPS_CLOSE_WAIT : 6737 case IPF_TCPS_FIN_WAIT_1 : 6738 case IPF_TCPS_CLOSING : 6739 case IPF_TCPS_LAST_ACK : 6740 case IPF_TCPS_FIN_WAIT_2 : 6741 case IPF_TCPS_TIME_WAIT : 6742 case IPF_TCPS_CLOSED : 6743 softn->ipf_nat_stats.ns_flush_state++; 6744 tqn = softn->ipf_nat_tcptq[which].ifq_head; 6745 while (tqn != NULL) { 6746 nat = tqn->tqe_parent; 6747 tqn = tqn->tqe_next; 6748 ipf_nat_delete(softc, nat, NL_FLUSH); 6749 removed++; 6750 } 6751 break; 6752 6753 default : 6754 if (which < 30) 6755 break; 6756 6757 softn->ipf_nat_stats.ns_flush_timeout++; 6758 /* 6759 * Take a large arbitrary number to mean the number of seconds 6760 * for which which consider to be the maximum value we'll allow 6761 * the expiration to be. 6762 */ 6763 which = IPF_TTLVAL(which); 6764 for (natp = &softn->ipf_nat_instances; 6765 ((nat = *natp) != NULL); ) { 6766 if (softc->ipf_ticks - nat->nat_touched > which) { 6767 ipf_nat_delete(softc, nat, NL_FLUSH); 6768 removed++; 6769 } else 6770 natp = &nat->nat_next; 6771 } 6772 break; 6773 } 6774 6775 if (which != 2) { 6776 SPL_X(s); 6777 return removed; 6778 } 6779 6780 softn->ipf_nat_stats.ns_flush_queue++; 6781 6782 /* 6783 * Asked to remove inactive entries because the table is full, try 6784 * again, 3 times, if first attempt failed with a different criteria 6785 * each time. The order tried in must be in decreasing age. 6786 * Another alternative is to implement random drop and drop N entries 6787 * at random until N have been freed up. 6788 */ 6789 if (softc->ipf_ticks - softn->ipf_nat_last_force_flush > 6790 IPF_TTLVAL(5)) { 6791 softn->ipf_nat_last_force_flush = softc->ipf_ticks; 6792 6793 removed = ipf_queueflush(softc, ipf_nat_flush_entry, 6794 softn->ipf_nat_tcptq, 6795 softn->ipf_nat_utqe, 6796 &softn->ipf_nat_stats.ns_active, 6797 softn->ipf_nat_table_sz, 6798 softn->ipf_nat_table_wm_low); 6799 } 6800 6801 SPL_X(s); 6802 return removed; 6803 } 6804 6805 6806 /* ------------------------------------------------------------------------ */ 6807 /* Function: ipf_nat_flush_entry */ 6808 /* Returns: 0 - always succeeds */ 6809 /* Parameters: softc(I) - pointer to soft context main structure */ 6810 /* entry(I) - pointer to NAT entry */ 6811 /* Write Locks: ipf_nat */ 6812 /* */ 6813 /* This function is a stepping stone between ipf_queueflush() and */ 6814 /* nat_dlete(). It is used so we can provide a uniform interface via the */ 6815 /* ipf_queueflush() function. Since the nat_delete() function returns void */ 6816 /* we translate that to mean it always succeeds in deleting something. */ 6817 /* ------------------------------------------------------------------------ */ 6818 static int 6819 ipf_nat_flush_entry(ipf_main_softc_t *softc, void *entry) 6820 { 6821 ipf_nat_delete(softc, entry, NL_FLUSH); 6822 return 0; 6823 } 6824 6825 6826 /* ------------------------------------------------------------------------ */ 6827 /* Function: ipf_nat_iterator */ 6828 /* Returns: int - 0 == ok, else error */ 6829 /* Parameters: softc(I) - pointer to soft context main structure */ 6830 /* token(I) - pointer to ipftoken structure */ 6831 /* itp(I) - pointer to ipfgeniter_t structure */ 6832 /* obj(I) - pointer to data description structure */ 6833 /* */ 6834 /* This function acts as a handler for the SIOCGENITER ioctls that use a */ 6835 /* generic structure to iterate through a list. There are three different */ 6836 /* linked lists of NAT related information to go through: NAT rules, active */ 6837 /* NAT mappings and the NAT fragment cache. */ 6838 /* ------------------------------------------------------------------------ */ 6839 static int 6840 ipf_nat_iterator(ipf_main_softc_t *softc, ipftoken_t *token, ipfgeniter_t *itp, 6841 ipfobj_t *obj) 6842 { 6843 int error; 6844 6845 if (itp->igi_data == NULL) { 6846 IPFERROR(60052); 6847 return EFAULT; 6848 } 6849 6850 switch (itp->igi_type) 6851 { 6852 case IPFGENITER_HOSTMAP : 6853 case IPFGENITER_IPNAT : 6854 case IPFGENITER_NAT : 6855 error = ipf_nat_getnext(softc, token, itp, obj); 6856 break; 6857 6858 case IPFGENITER_NATFRAG : 6859 error = ipf_frag_nat_next(softc, token, itp); 6860 break; 6861 default : 6862 IPFERROR(60053); 6863 error = EINVAL; 6864 break; 6865 } 6866 6867 return error; 6868 } 6869 6870 6871 /* ------------------------------------------------------------------------ */ 6872 /* Function: ipf_nat_setpending */ 6873 /* Returns: Nil */ 6874 /* Parameters: softc(I) - pointer to soft context main structure */ 6875 /* nat(I) - pointer to NAT structure */ 6876 /* Locks: ipf_nat (read or write) */ 6877 /* */ 6878 /* Put the NAT entry on to the pending queue - this queue has a very short */ 6879 /* lifetime where items are put that can't be deleted straight away because */ 6880 /* of locking issues but we want to delete them ASAP, anyway. In calling */ 6881 /* this function, it is assumed that the owner (if there is one, as shown */ 6882 /* by nat_me) is no longer interested in it. */ 6883 /* ------------------------------------------------------------------------ */ 6884 void 6885 ipf_nat_setpending(ipf_main_softc_t *softc, nat_t *nat) 6886 { 6887 ipf_nat_softc_t *softn = softc->ipf_nat_soft; 6888 ipftq_t *oifq; 6889 6890 oifq = nat->nat_tqe.tqe_ifq; 6891 if (oifq != NULL) 6892 ipf_movequeue(softc->ipf_ticks, &nat->nat_tqe, oifq, 6893 &softn->ipf_nat_pending); 6894 else 6895 ipf_queueappend(softc->ipf_ticks, &nat->nat_tqe, 6896 &softn->ipf_nat_pending, nat); 6897 6898 if (nat->nat_me != NULL) { 6899 *nat->nat_me = NULL; 6900 nat->nat_me = NULL; 6901 nat->nat_ref--; 6902 ASSERT(nat->nat_ref >= 0); 6903 } 6904 } 6905 6906 6907 /* ------------------------------------------------------------------------ */ 6908 /* Function: nat_newrewrite */ 6909 /* Returns: int - -1 == error, 0 == success (no move), 1 == success and */ 6910 /* allow rule to be moved if IPN_ROUNDR is set. */ 6911 /* Parameters: fin(I) - pointer to packet information */ 6912 /* nat(I) - pointer to NAT entry */ 6913 /* ni(I) - pointer to structure with misc. information needed */ 6914 /* to create new NAT entry. */ 6915 /* Write Lock: ipf_nat */ 6916 /* */ 6917 /* This function is responsible for setting up an active NAT session where */ 6918 /* we are changing both the source and destination parameters at the same */ 6919 /* time. The loop in here works differently to elsewhere - each iteration */ 6920 /* is responsible for changing a single parameter that can be incremented. */ 6921 /* So one pass may increase the source IP#, next source port, next dest. IP#*/ 6922 /* and the last destination port for a total of 4 iterations to try each. */ 6923 /* This is done to try and exhaustively use the translation space available.*/ 6924 /* ------------------------------------------------------------------------ */ 6925 static int 6926 ipf_nat_newrewrite(fr_info_t *fin, nat_t *nat, natinfo_t *nai) 6927 { 6928 int src_search = 1; 6929 int dst_search = 1; 6930 fr_info_t frnat; 6931 u_32_t flags; 6932 u_short swap; 6933 ipnat_t *np; 6934 nat_t *natl; 6935 int l = 0; 6936 int changed; 6937 6938 natl = NULL; 6939 changed = -1; 6940 np = nai->nai_np; 6941 flags = nat->nat_flags; 6942 bcopy((char *)fin, (char *)&frnat, sizeof(*fin)); 6943 6944 nat->nat_hm = NULL; 6945 6946 do { 6947 changed = -1; 6948 /* TRACE (l, src_search, dst_search, np) */ 6949 6950 if ((src_search == 0) && (np->in_spnext == 0) && 6951 (dst_search == 0) && (np->in_dpnext == 0)) { 6952 if (l > 0) 6953 return -1; 6954 } 6955 6956 /* 6957 * Find a new source address 6958 */ 6959 if (ipf_nat_nextaddr(fin, &np->in_nsrc, &frnat.fin_saddr, 6960 &frnat.fin_saddr) == -1) { 6961 return -1; 6962 } 6963 6964 if ((np->in_nsrcaddr == 0) && (np->in_nsrcmsk == 0xffffffff)) { 6965 src_search = 0; 6966 if (np->in_stepnext == 0) 6967 np->in_stepnext = 1; 6968 6969 } else if ((np->in_nsrcaddr == 0) && (np->in_nsrcmsk == 0)) { 6970 src_search = 0; 6971 if (np->in_stepnext == 0) 6972 np->in_stepnext = 1; 6973 6974 } else if (np->in_nsrcmsk == 0xffffffff) { 6975 src_search = 0; 6976 if (np->in_stepnext == 0) 6977 np->in_stepnext = 1; 6978 6979 } else if (np->in_nsrcmsk != 0xffffffff) { 6980 if (np->in_stepnext == 0 && changed == -1) { 6981 np->in_snip++; 6982 np->in_stepnext++; 6983 changed = 0; 6984 } 6985 } 6986 6987 if ((flags & IPN_TCPUDPICMP) != 0) { 6988 if (np->in_spnext != 0) 6989 frnat.fin_data[0] = np->in_spnext; 6990 6991 /* 6992 * Standard port translation. Select next port. 6993 */ 6994 if ((flags & IPN_FIXEDSPORT) != 0) { 6995 np->in_stepnext = 2; 6996 } else if ((np->in_stepnext == 1) && 6997 (changed == -1) && (natl != NULL)) { 6998 np->in_spnext++; 6999 np->in_stepnext++; 7000 changed = 1; 7001 if (np->in_spnext > np->in_spmax) 7002 np->in_spnext = np->in_spmin; 7003 } 7004 } else { 7005 np->in_stepnext = 2; 7006 } 7007 np->in_stepnext &= 0x3; 7008 7009 /* 7010 * Find a new destination address 7011 */ 7012 /* TRACE (fin, np, l, frnat) */ 7013 7014 if (ipf_nat_nextaddr(fin, &np->in_ndst, &frnat.fin_daddr, 7015 &frnat.fin_daddr) == -1) 7016 return -1; 7017 if ((np->in_ndstaddr == 0) && (np->in_ndstmsk == 0xffffffff)) { 7018 dst_search = 0; 7019 if (np->in_stepnext == 2) 7020 np->in_stepnext = 3; 7021 7022 } else if ((np->in_ndstaddr == 0) && (np->in_ndstmsk == 0)) { 7023 dst_search = 0; 7024 if (np->in_stepnext == 2) 7025 np->in_stepnext = 3; 7026 7027 } else if (np->in_ndstmsk == 0xffffffff) { 7028 dst_search = 0; 7029 if (np->in_stepnext == 2) 7030 np->in_stepnext = 3; 7031 7032 } else if (np->in_ndstmsk != 0xffffffff) { 7033 if ((np->in_stepnext == 2) && (changed == -1) && 7034 (natl != NULL)) { 7035 changed = 2; 7036 np->in_stepnext++; 7037 np->in_dnip++; 7038 } 7039 } 7040 7041 if ((flags & IPN_TCPUDPICMP) != 0) { 7042 if (np->in_dpnext != 0) 7043 frnat.fin_data[1] = np->in_dpnext; 7044 7045 /* 7046 * Standard port translation. Select next port. 7047 */ 7048 if ((flags & IPN_FIXEDDPORT) != 0) { 7049 np->in_stepnext = 0; 7050 } else if (np->in_stepnext == 3 && changed == -1) { 7051 np->in_dpnext++; 7052 np->in_stepnext++; 7053 changed = 3; 7054 if (np->in_dpnext > np->in_dpmax) 7055 np->in_dpnext = np->in_dpmin; 7056 } 7057 } else { 7058 if (np->in_stepnext == 3) 7059 np->in_stepnext = 0; 7060 } 7061 7062 /* TRACE (frnat) */ 7063 7064 /* 7065 * Here we do a lookup of the connection as seen from 7066 * the outside. If an IP# pair already exists, try 7067 * again. So if you have A->B becomes C->B, you can 7068 * also have D->E become C->E but not D->B causing 7069 * another C->B. Also take protocol and ports into 7070 * account when determining whether a pre-existing 7071 * NAT setup will cause an external conflict where 7072 * this is appropriate. 7073 * 7074 * fin_data[] is swapped around because we are doing a 7075 * lookup of the packet is if it were moving in the opposite 7076 * direction of the one we are working with now. 7077 */ 7078 if (flags & IPN_TCPUDP) { 7079 swap = frnat.fin_data[0]; 7080 frnat.fin_data[0] = frnat.fin_data[1]; 7081 frnat.fin_data[1] = swap; 7082 } 7083 if (fin->fin_out == 1) { 7084 natl = ipf_nat_inlookup(&frnat, 7085 flags & ~(SI_WILDP|NAT_SEARCH), 7086 (u_int)frnat.fin_p, 7087 frnat.fin_dst, frnat.fin_src); 7088 7089 } else { 7090 natl = ipf_nat_outlookup(&frnat, 7091 flags & ~(SI_WILDP|NAT_SEARCH), 7092 (u_int)frnat.fin_p, 7093 frnat.fin_dst, frnat.fin_src); 7094 } 7095 if (flags & IPN_TCPUDP) { 7096 swap = frnat.fin_data[0]; 7097 frnat.fin_data[0] = frnat.fin_data[1]; 7098 frnat.fin_data[1] = swap; 7099 } 7100 7101 /* TRACE natl, in_stepnext, l */ 7102 7103 if ((natl != NULL) && (l > 8)) /* XXX 8 is arbitrary */ 7104 return -1; 7105 7106 np->in_stepnext &= 0x3; 7107 7108 l++; 7109 changed = -1; 7110 } while (natl != NULL); 7111 7112 nat->nat_osrcip = fin->fin_src; 7113 nat->nat_odstip = fin->fin_dst; 7114 nat->nat_nsrcip = frnat.fin_src; 7115 nat->nat_ndstip = frnat.fin_dst; 7116 7117 if ((flags & IPN_TCPUDP) != 0) { 7118 nat->nat_osport = htons(fin->fin_data[0]); 7119 nat->nat_odport = htons(fin->fin_data[1]); 7120 nat->nat_nsport = htons(frnat.fin_data[0]); 7121 nat->nat_ndport = htons(frnat.fin_data[1]); 7122 } else if ((flags & IPN_ICMPQUERY) != 0) { 7123 nat->nat_oicmpid = fin->fin_data[1]; 7124 nat->nat_nicmpid = frnat.fin_data[1]; 7125 } 7126 7127 return 0; 7128 } 7129 7130 7131 /* ------------------------------------------------------------------------ */ 7132 /* Function: nat_newdivert */ 7133 /* Returns: int - -1 == error, 0 == success */ 7134 /* Parameters: fin(I) - pointer to packet information */ 7135 /* nat(I) - pointer to NAT entry */ 7136 /* ni(I) - pointer to structure with misc. information needed */ 7137 /* to create new NAT entry. */ 7138 /* Write Lock: ipf_nat */ 7139 /* */ 7140 /* Create a new NAT divert session as defined by the NAT rule. This is */ 7141 /* somewhat different to other NAT session creation routines because we */ 7142 /* do not iterate through either port numbers or IP addresses, searching */ 7143 /* for a unique mapping, however, a complimentary duplicate check is made. */ 7144 /* ------------------------------------------------------------------------ */ 7145 static int 7146 ipf_nat_newdivert(fr_info_t *fin, nat_t *nat, natinfo_t *nai) 7147 { 7148 ipf_main_softc_t *softc = fin->fin_main_soft; 7149 ipf_nat_softc_t *softn = softc->ipf_nat_soft; 7150 fr_info_t frnat; 7151 ipnat_t *np; 7152 nat_t *natl; 7153 int p; 7154 7155 np = nai->nai_np; 7156 bcopy((char *)fin, (char *)&frnat, sizeof(*fin)); 7157 7158 nat->nat_pr[0] = 0; 7159 nat->nat_osrcaddr = fin->fin_saddr; 7160 nat->nat_odstaddr = fin->fin_daddr; 7161 frnat.fin_saddr = htonl(np->in_snip); 7162 frnat.fin_daddr = htonl(np->in_dnip); 7163 if ((nat->nat_flags & IPN_TCPUDP) != 0) { 7164 nat->nat_osport = htons(fin->fin_data[0]); 7165 nat->nat_odport = htons(fin->fin_data[1]); 7166 } else if ((nat->nat_flags & IPN_ICMPQUERY) != 0) { 7167 nat->nat_oicmpid = fin->fin_data[1]; 7168 } 7169 7170 if (np->in_redir & NAT_DIVERTUDP) { 7171 frnat.fin_data[0] = np->in_spnext; 7172 frnat.fin_data[1] = np->in_dpnext; 7173 frnat.fin_flx |= FI_TCPUDP; 7174 p = IPPROTO_UDP; 7175 } else { 7176 frnat.fin_flx &= ~FI_TCPUDP; 7177 p = IPPROTO_IPIP; 7178 } 7179 7180 if (fin->fin_out == 1) { 7181 natl = ipf_nat_inlookup(&frnat, 0, p, 7182 frnat.fin_dst, frnat.fin_src); 7183 7184 } else { 7185 natl = ipf_nat_outlookup(&frnat, 0, p, 7186 frnat.fin_dst, frnat.fin_src); 7187 } 7188 7189 if (natl != NULL) { 7190 NBUMPSIDED(fin->fin_out, ns_divert_exist); 7191 return -1; 7192 } 7193 7194 nat->nat_nsrcaddr = frnat.fin_saddr; 7195 nat->nat_ndstaddr = frnat.fin_daddr; 7196 if ((nat->nat_flags & IPN_TCPUDP) != 0) { 7197 nat->nat_nsport = htons(frnat.fin_data[0]); 7198 nat->nat_ndport = htons(frnat.fin_data[1]); 7199 } else if ((nat->nat_flags & IPN_ICMPQUERY) != 0) { 7200 nat->nat_nicmpid = frnat.fin_data[1]; 7201 } 7202 7203 nat->nat_pr[fin->fin_out] = fin->fin_p; 7204 nat->nat_pr[1 - fin->fin_out] = p; 7205 7206 if (np->in_redir & NAT_REDIRECT) 7207 nat->nat_dir = NAT_DIVERTIN; 7208 else 7209 nat->nat_dir = NAT_DIVERTOUT; 7210 7211 return 0; 7212 } 7213 7214 7215 /* ------------------------------------------------------------------------ */ 7216 /* Function: nat_builddivertmp */ 7217 /* Returns: int - -1 == error, 0 == success */ 7218 /* Parameters: softn(I) - pointer to NAT context structure */ 7219 /* np(I) - pointer to a NAT rule */ 7220 /* */ 7221 /* For divert rules, a skeleton packet representing what will be prepended */ 7222 /* to the real packet is created. Even though we don't have the full */ 7223 /* packet here, a checksum is calculated that we update later when we */ 7224 /* fill in the final details. At present a 0 checksum for UDP is being set */ 7225 /* here because it is expected that divert will be used for localhost. */ 7226 /* ------------------------------------------------------------------------ */ 7227 static int 7228 ipf_nat_builddivertmp(ipf_nat_softc_t *softn, ipnat_t *np) 7229 { 7230 udphdr_t *uh; 7231 size_t len; 7232 ip_t *ip; 7233 7234 if ((np->in_redir & NAT_DIVERTUDP) != 0) 7235 len = sizeof(ip_t) + sizeof(udphdr_t); 7236 else 7237 len = sizeof(ip_t); 7238 7239 ALLOC_MB_T(np->in_divmp, len); 7240 if (np->in_divmp == NULL) { 7241 NBUMPD(ipf_nat_stats, ns_divert_build); 7242 return -1; 7243 } 7244 7245 /* 7246 * First, the header to get the packet diverted to the new destination 7247 */ 7248 ip = MTOD(np->in_divmp, ip_t *); 7249 IP_V_A(ip, 4); 7250 IP_HL_A(ip, 5); 7251 ip->ip_tos = 0; 7252 if ((np->in_redir & NAT_DIVERTUDP) != 0) 7253 ip->ip_p = IPPROTO_UDP; 7254 else 7255 ip->ip_p = IPPROTO_IPIP; 7256 ip->ip_ttl = 255; 7257 ip->ip_off = 0; 7258 ip->ip_sum = 0; 7259 ip->ip_len = htons(len); 7260 ip->ip_id = 0; 7261 ip->ip_src.s_addr = htonl(np->in_snip); 7262 ip->ip_dst.s_addr = htonl(np->in_dnip); 7263 ip->ip_sum = ipf_cksum((u_short *)ip, sizeof(*ip)); 7264 7265 if (np->in_redir & NAT_DIVERTUDP) { 7266 uh = (udphdr_t *)(ip + 1); 7267 uh->uh_sum = 0; 7268 uh->uh_ulen = 8; 7269 uh->uh_sport = htons(np->in_spnext); 7270 uh->uh_dport = htons(np->in_dpnext); 7271 } 7272 7273 return 0; 7274 } 7275 7276 7277 #define MINDECAP (sizeof(ip_t) + sizeof(udphdr_t) + sizeof(ip_t)) 7278 7279 /* ------------------------------------------------------------------------ */ 7280 /* Function: nat_decap */ 7281 /* Returns: int - -1 == error, 0 == success */ 7282 /* Parameters: fin(I) - pointer to packet information */ 7283 /* nat(I) - pointer to current NAT session */ 7284 /* */ 7285 /* This function is responsible for undoing a packet's encapsulation in the */ 7286 /* reverse of an encap/divert rule. After removing the outer encapsulation */ 7287 /* it is necessary to call ipf_makefrip() again so that the contents of 'fin'*/ 7288 /* match the "new" packet as it may still be used by IPFilter elsewhere. */ 7289 /* We use "dir" here as the basis for some of the expectations about the */ 7290 /* outer header. If we return an error, the goal is to leave the original */ 7291 /* packet information undisturbed - this falls short at the end where we'd */ 7292 /* need to back a backup copy of "fin" - expensive. */ 7293 /* ------------------------------------------------------------------------ */ 7294 static int 7295 ipf_nat_decap(fr_info_t *fin, nat_t *nat) 7296 { 7297 ipf_main_softc_t *softc = fin->fin_main_soft; 7298 ipf_nat_softc_t *softn = softc->ipf_nat_soft; 7299 char *hdr; 7300 int hlen; 7301 int skip; 7302 mb_t *m; 7303 7304 if ((fin->fin_flx & FI_ICMPERR) != 0) { 7305 /* 7306 * ICMP packets don't get decapsulated, instead what we need 7307 * to do is change the ICMP reply from including (in the data 7308 * portion for errors) the encapsulated packet that we sent 7309 * out to something that resembles the original packet prior 7310 * to encapsulation. This isn't done here - all we're doing 7311 * here is changing the outer address to ensure that it gets 7312 * targetted back to the correct system. 7313 */ 7314 7315 if (nat->nat_dir & NAT_OUTBOUND) { 7316 u_32_t sum1, sum2, sumd; 7317 7318 sum1 = ntohl(fin->fin_daddr); 7319 sum2 = ntohl(nat->nat_osrcaddr); 7320 CALC_SUMD(sum1, sum2, sumd); 7321 fin->fin_ip->ip_dst = nat->nat_osrcip; 7322 fin->fin_daddr = nat->nat_osrcaddr; 7323 #if !defined(_KERNEL) || defined(MENTAT) || defined(__sgi) || \ 7324 defined(__osf__) || defined(linux) 7325 ipf_fix_outcksum(0, &fin->fin_ip->ip_sum, sumd, 0); 7326 #endif 7327 } 7328 return 0; 7329 } 7330 7331 m = fin->fin_m; 7332 skip = fin->fin_hlen; 7333 7334 switch (nat->nat_dir) 7335 { 7336 case NAT_DIVERTIN : 7337 case NAT_DIVERTOUT : 7338 if (fin->fin_plen < MINDECAP) 7339 return -1; 7340 skip += sizeof(udphdr_t); 7341 break; 7342 7343 case NAT_ENCAPIN : 7344 case NAT_ENCAPOUT : 7345 if (fin->fin_plen < (skip + sizeof(ip_t))) 7346 return -1; 7347 break; 7348 default : 7349 return -1; 7350 /* NOTREACHED */ 7351 } 7352 7353 /* 7354 * The aim here is to keep the original packet details in "fin" for 7355 * as long as possible so that returning with an error is for the 7356 * original packet and there is little undoing work to do. 7357 */ 7358 if (M_LEN(m) < skip + sizeof(ip_t)) { 7359 if (ipf_pr_pullup(fin, skip + sizeof(ip_t)) == -1) 7360 return -1; 7361 } 7362 7363 hdr = MTOD(fin->fin_m, char *); 7364 fin->fin_ip = (ip_t *)(hdr + skip); 7365 hlen = IP_HL(fin->fin_ip) << 2; 7366 7367 if (ipf_pr_pullup(fin, skip + hlen) == -1) { 7368 NBUMPSIDED(fin->fin_out, ns_decap_pullup); 7369 return -1; 7370 } 7371 7372 fin->fin_hlen = hlen; 7373 fin->fin_dlen -= skip; 7374 fin->fin_plen -= skip; 7375 fin->fin_ipoff += skip; 7376 7377 if (ipf_makefrip(hlen, (ip_t *)hdr, fin) == -1) { 7378 NBUMPSIDED(fin->fin_out, ns_decap_bad); 7379 return -1; 7380 } 7381 7382 return skip; 7383 } 7384 7385 7386 /* ------------------------------------------------------------------------ */ 7387 /* Function: nat_nextaddr */ 7388 /* Returns: int - -1 == bad input (no new address), */ 7389 /* 0 == success and dst has new address */ 7390 /* Parameters: fin(I) - pointer to packet information */ 7391 /* na(I) - how to generate new address */ 7392 /* old(I) - original address being replaced */ 7393 /* dst(O) - where to put the new address */ 7394 /* Write Lock: ipf_nat */ 7395 /* */ 7396 /* This function uses the contents of the "na" structure, in combination */ 7397 /* with "old" to produce a new address to store in "dst". Not all of the */ 7398 /* possible uses of "na" will result in a new address. */ 7399 /* ------------------------------------------------------------------------ */ 7400 static int 7401 ipf_nat_nextaddr(fr_info_t *fin, nat_addr_t *na, u_32_t *old, u_32_t *dst) 7402 { 7403 ipf_main_softc_t *softc = fin->fin_main_soft; 7404 ipf_nat_softc_t *softn = softc->ipf_nat_soft; 7405 u_32_t amin, amax, new; 7406 i6addr_t newip; 7407 int error; 7408 7409 new = 0; 7410 amin = na->na_addr[0].in4.s_addr; 7411 7412 switch (na->na_atype) 7413 { 7414 case FRI_RANGE : 7415 amax = na->na_addr[1].in4.s_addr; 7416 break; 7417 7418 case FRI_NETMASKED : 7419 case FRI_DYNAMIC : 7420 case FRI_NORMAL : 7421 /* 7422 * Compute the maximum address by adding the inverse of the 7423 * netmask to the minimum address. 7424 */ 7425 amax = ~na->na_addr[1].in4.s_addr; 7426 amax |= amin; 7427 break; 7428 7429 case FRI_LOOKUP : 7430 break; 7431 7432 case FRI_BROADCAST : 7433 case FRI_PEERADDR : 7434 case FRI_NETWORK : 7435 default : 7436 return -1; 7437 } 7438 7439 error = -1; 7440 7441 if (na->na_atype == FRI_LOOKUP) { 7442 if (na->na_type == IPLT_DSTLIST) { 7443 error = ipf_dstlist_select_node(fin, na->na_ptr, dst, 7444 NULL); 7445 } else { 7446 NBUMPSIDE(fin->fin_out, ns_badnextaddr); 7447 } 7448 7449 } else if (na->na_atype == IPLT_NONE) { 7450 /* 7451 * 0/0 as the new address means leave it alone. 7452 */ 7453 if (na->na_addr[0].in4.s_addr == 0 && 7454 na->na_addr[1].in4.s_addr == 0) { 7455 new = *old; 7456 7457 /* 7458 * 0/32 means get the interface's address 7459 */ 7460 } else if (na->na_addr[0].in4.s_addr == 0 && 7461 na->na_addr[1].in4.s_addr == 0xffffffff) { 7462 if (ipf_ifpaddr(softc, 4, na->na_atype, 7463 fin->fin_ifp, &newip, NULL) == -1) { 7464 NBUMPSIDED(fin->fin_out, ns_ifpaddrfail); 7465 return -1; 7466 } 7467 new = newip.in4.s_addr; 7468 } else { 7469 new = htonl(na->na_nextip); 7470 } 7471 *dst = new; 7472 error = 0; 7473 7474 } else { 7475 NBUMPSIDE(fin->fin_out, ns_badnextaddr); 7476 } 7477 7478 return error; 7479 } 7480 7481 7482 /* ------------------------------------------------------------------------ */ 7483 /* Function: nat_nextaddrinit */ 7484 /* Returns: int - 0 == success, else error number */ 7485 /* Parameters: softc(I) - pointer to soft context main structure */ 7486 /* na(I) - NAT address information for generating new addr*/ 7487 /* initial(I) - flag indicating if it is the first call for */ 7488 /* this "na" structure. */ 7489 /* ifp(I) - network interface to derive address */ 7490 /* information from. */ 7491 /* */ 7492 /* This function is expected to be called in two scenarious: when a new NAT */ 7493 /* rule is loaded into the kernel and when the list of NAT rules is sync'd */ 7494 /* up with the valid network interfaces (possibly due to them changing.) */ 7495 /* To distinguish between these, the "initial" parameter is used. If it is */ 7496 /* 1 then this indicates the rule has just been reloaded and 0 for when we */ 7497 /* are updating information. This difference is important because in */ 7498 /* instances where we are not updating address information associated with */ 7499 /* a network interface, we don't want to disturb what the "next" address to */ 7500 /* come out of ipf_nat_nextaddr() will be. */ 7501 /* ------------------------------------------------------------------------ */ 7502 static int 7503 ipf_nat_nextaddrinit(ipf_main_softc_t *softc, char *base, nat_addr_t *na, 7504 int initial, void *ifp) 7505 { 7506 7507 switch (na->na_atype) 7508 { 7509 case FRI_LOOKUP : 7510 if (na->na_subtype == 0) { 7511 na->na_ptr = ipf_lookup_res_num(softc, IPL_LOGNAT, 7512 na->na_type, 7513 na->na_num, 7514 &na->na_func); 7515 } else if (na->na_subtype == 1) { 7516 na->na_ptr = ipf_lookup_res_name(softc, IPL_LOGNAT, 7517 na->na_type, 7518 base + na->na_num, 7519 &na->na_func); 7520 } 7521 if (na->na_func == NULL) { 7522 IPFERROR(60060); 7523 return ESRCH; 7524 } 7525 if (na->na_ptr == NULL) { 7526 IPFERROR(60056); 7527 return ESRCH; 7528 } 7529 break; 7530 7531 case FRI_DYNAMIC : 7532 case FRI_BROADCAST : 7533 case FRI_NETWORK : 7534 case FRI_NETMASKED : 7535 case FRI_PEERADDR : 7536 if (ifp != NULL) 7537 (void )ipf_ifpaddr(softc, 4, na->na_atype, ifp, 7538 &na->na_addr[0], &na->na_addr[1]); 7539 break; 7540 7541 case FRI_SPLIT : 7542 case FRI_RANGE : 7543 if (initial) 7544 na->na_nextip = ntohl(na->na_addr[0].in4.s_addr); 7545 break; 7546 7547 case FRI_NONE : 7548 na->na_addr[0].in4.s_addr &= na->na_addr[1].in4.s_addr; 7549 return 0; 7550 7551 case FRI_NORMAL : 7552 na->na_addr[0].in4.s_addr &= na->na_addr[1].in4.s_addr; 7553 break; 7554 7555 default : 7556 IPFERROR(60054); 7557 return EINVAL; 7558 } 7559 7560 if (initial && (na->na_atype == FRI_NORMAL)) { 7561 if (na->na_addr[0].in4.s_addr == 0) { 7562 if ((na->na_addr[1].in4.s_addr == 0xffffffff) || 7563 (na->na_addr[1].in4.s_addr == 0)) { 7564 return 0; 7565 } 7566 } 7567 7568 if (na->na_addr[1].in4.s_addr == 0xffffffff) { 7569 na->na_nextip = ntohl(na->na_addr[0].in4.s_addr); 7570 } else { 7571 na->na_nextip = ntohl(na->na_addr[0].in4.s_addr) + 1; 7572 } 7573 } 7574 7575 return 0; 7576 } 7577 7578 7579 /* ------------------------------------------------------------------------ */ 7580 /* Function: ipf_nat_matchflush */ 7581 /* Returns: int - -1 == error, 0 == success */ 7582 /* Parameters: softc(I) - pointer to soft context main structure */ 7583 /* softn(I) - pointer to NAT context structure */ 7584 /* nat(I) - pointer to current NAT session */ 7585 /* */ 7586 /* ------------------------------------------------------------------------ */ 7587 static int 7588 ipf_nat_matchflush(ipf_main_softc_t *softc, ipf_nat_softc_t *softn, void *data) 7589 { 7590 int *array, flushed, error; 7591 nat_t *nat, *natnext; 7592 ipfobj_t obj; 7593 7594 error = ipf_matcharray_load(softc, data, &obj, &array); 7595 if (error != 0) 7596 return error; 7597 7598 flushed = 0; 7599 7600 for (nat = softn->ipf_nat_instances; nat != NULL; nat = natnext) { 7601 natnext = nat->nat_next; 7602 if (ipf_nat_matcharray(nat, array, softc->ipf_ticks) == 0) { 7603 ipf_nat_delete(softc, nat, NL_FLUSH); 7604 flushed++; 7605 } 7606 } 7607 7608 obj.ipfo_retval = flushed; 7609 error = BCOPYOUT(&obj, data, sizeof(obj)); 7610 7611 KFREES(array, array[0] * sizeof(*array)); 7612 7613 return error; 7614 } 7615 7616 7617 /* ------------------------------------------------------------------------ */ 7618 /* Function: ipf_nat_matcharray */ 7619 /* Returns: int - -1 == error, 0 == success */ 7620 /* Parameters: fin(I) - pointer to packet information */ 7621 /* nat(I) - pointer to current NAT session */ 7622 /* */ 7623 /* ------------------------------------------------------------------------ */ 7624 static int 7625 ipf_nat_matcharray(nat_t *nat, int *array, u_long ticks) 7626 { 7627 int i, n, *x, e, p; 7628 7629 e = 0; 7630 n = array[0]; 7631 x = array + 1; 7632 7633 for (; n > 0; x += 3 + x[2]) { 7634 if (x[0] == IPF_EXP_END) 7635 break; 7636 e = 0; 7637 7638 n -= x[2] + 3; 7639 if (n < 0) 7640 break; 7641 7642 p = x[0] >> 16; 7643 if (p != 0 && p != nat->nat_pr[1]) 7644 break; 7645 7646 switch (x[0]) 7647 { 7648 case IPF_EXP_IP_PR : 7649 for (i = 0; !e && i < x[2]; i++) { 7650 e |= (nat->nat_pr[1] == x[i + 3]); 7651 } 7652 break; 7653 7654 case IPF_EXP_IP_SRCADDR : 7655 if (nat->nat_v[0] == 4) { 7656 for (i = 0; !e && i < x[2]; i++) { 7657 e |= ((nat->nat_osrcaddr & x[i + 4]) == 7658 x[i + 3]); 7659 } 7660 } 7661 if (nat->nat_v[1] == 4) { 7662 for (i = 0; !e && i < x[2]; i++) { 7663 e |= ((nat->nat_nsrcaddr & x[i + 4]) == 7664 x[i + 3]); 7665 } 7666 } 7667 break; 7668 7669 case IPF_EXP_IP_DSTADDR : 7670 if (nat->nat_v[0] == 4) { 7671 for (i = 0; !e && i < x[2]; i++) { 7672 e |= ((nat->nat_odstaddr & x[i + 4]) == 7673 x[i + 3]); 7674 } 7675 } 7676 if (nat->nat_v[1] == 4) { 7677 for (i = 0; !e && i < x[2]; i++) { 7678 e |= ((nat->nat_ndstaddr & x[i + 4]) == 7679 x[i + 3]); 7680 } 7681 } 7682 break; 7683 7684 case IPF_EXP_IP_ADDR : 7685 for (i = 0; !e && i < x[2]; i++) { 7686 if (nat->nat_v[0] == 4) { 7687 e |= ((nat->nat_osrcaddr & x[i + 4]) == 7688 x[i + 3]); 7689 } 7690 if (nat->nat_v[1] == 4) { 7691 e |= ((nat->nat_nsrcaddr & x[i + 4]) == 7692 x[i + 3]); 7693 } 7694 if (nat->nat_v[0] == 4) { 7695 e |= ((nat->nat_odstaddr & x[i + 4]) == 7696 x[i + 3]); 7697 } 7698 if (nat->nat_v[1] == 4) { 7699 e |= ((nat->nat_ndstaddr & x[i + 4]) == 7700 x[i + 3]); 7701 } 7702 } 7703 break; 7704 7705 #ifdef USE_INET6 7706 case IPF_EXP_IP6_SRCADDR : 7707 if (nat->nat_v[0] == 6) { 7708 for (i = 0; !e && i < x[3]; i++) { 7709 e |= IP6_MASKEQ(&nat->nat_osrc6, 7710 x + i + 7, x + i + 3); 7711 } 7712 } 7713 if (nat->nat_v[1] == 6) { 7714 for (i = 0; !e && i < x[3]; i++) { 7715 e |= IP6_MASKEQ(&nat->nat_nsrc6, 7716 x + i + 7, x + i + 3); 7717 } 7718 } 7719 break; 7720 7721 case IPF_EXP_IP6_DSTADDR : 7722 if (nat->nat_v[0] == 6) { 7723 for (i = 0; !e && i < x[3]; i++) { 7724 e |= IP6_MASKEQ(&nat->nat_odst6, 7725 x + i + 7, 7726 x + i + 3); 7727 } 7728 } 7729 if (nat->nat_v[1] == 6) { 7730 for (i = 0; !e && i < x[3]; i++) { 7731 e |= IP6_MASKEQ(&nat->nat_ndst6, 7732 x + i + 7, 7733 x + i + 3); 7734 } 7735 } 7736 break; 7737 7738 case IPF_EXP_IP6_ADDR : 7739 for (i = 0; !e && i < x[3]; i++) { 7740 if (nat->nat_v[0] == 6) { 7741 e |= IP6_MASKEQ(&nat->nat_osrc6, 7742 x + i + 7, 7743 x + i + 3); 7744 } 7745 if (nat->nat_v[0] == 6) { 7746 e |= IP6_MASKEQ(&nat->nat_odst6, 7747 x + i + 7, 7748 x + i + 3); 7749 } 7750 if (nat->nat_v[1] == 6) { 7751 e |= IP6_MASKEQ(&nat->nat_nsrc6, 7752 x + i + 7, 7753 x + i + 3); 7754 } 7755 if (nat->nat_v[1] == 6) { 7756 e |= IP6_MASKEQ(&nat->nat_ndst6, 7757 x + i + 7, 7758 x + i + 3); 7759 } 7760 } 7761 break; 7762 #endif 7763 7764 case IPF_EXP_UDP_PORT : 7765 case IPF_EXP_TCP_PORT : 7766 for (i = 0; !e && i < x[2]; i++) { 7767 e |= (nat->nat_nsport == x[i + 3]) || 7768 (nat->nat_ndport == x[i + 3]); 7769 } 7770 break; 7771 7772 case IPF_EXP_UDP_SPORT : 7773 case IPF_EXP_TCP_SPORT : 7774 for (i = 0; !e && i < x[2]; i++) { 7775 e |= (nat->nat_nsport == x[i + 3]); 7776 } 7777 break; 7778 7779 case IPF_EXP_UDP_DPORT : 7780 case IPF_EXP_TCP_DPORT : 7781 for (i = 0; !e && i < x[2]; i++) { 7782 e |= (nat->nat_ndport == x[i + 3]); 7783 } 7784 break; 7785 7786 case IPF_EXP_TCP_STATE : 7787 for (i = 0; !e && i < x[2]; i++) { 7788 e |= (nat->nat_tcpstate[0] == x[i + 3]) || 7789 (nat->nat_tcpstate[1] == x[i + 3]); 7790 } 7791 break; 7792 7793 case IPF_EXP_IDLE_GT : 7794 e |= (ticks - nat->nat_touched > x[3]); 7795 break; 7796 } 7797 e ^= x[1]; 7798 7799 if (!e) 7800 break; 7801 } 7802 7803 return e; 7804 } 7805 7806 7807 /* ------------------------------------------------------------------------ */ 7808 /* Function: ipf_nat_gettable */ 7809 /* Returns: int - 0 = success, else error */ 7810 /* Parameters: softc(I) - pointer to soft context main structure */ 7811 /* softn(I) - pointer to NAT context structure */ 7812 /* data(I) - pointer to ioctl data */ 7813 /* */ 7814 /* This function handles ioctl requests for tables of nat information. */ 7815 /* At present the only table it deals with is the hash bucket statistics. */ 7816 /* ------------------------------------------------------------------------ */ 7817 static int 7818 ipf_nat_gettable(ipf_main_softc_t *softc, ipf_nat_softc_t *softn, char *data) 7819 { 7820 ipftable_t table; 7821 int error; 7822 7823 error = ipf_inobj(softc, data, NULL, &table, IPFOBJ_GTABLE); 7824 if (error != 0) 7825 return error; 7826 7827 switch (table.ita_type) 7828 { 7829 case IPFTABLE_BUCKETS_NATIN : 7830 error = COPYOUT(softn->ipf_nat_stats.ns_side[0].ns_bucketlen, 7831 table.ita_table, 7832 softn->ipf_nat_table_sz * sizeof(u_int)); 7833 break; 7834 7835 case IPFTABLE_BUCKETS_NATOUT : 7836 error = COPYOUT(softn->ipf_nat_stats.ns_side[1].ns_bucketlen, 7837 table.ita_table, 7838 softn->ipf_nat_table_sz * sizeof(u_int)); 7839 break; 7840 7841 default : 7842 IPFERROR(60058); 7843 return EINVAL; 7844 } 7845 7846 if (error != 0) { 7847 IPFERROR(60059); 7848 error = EFAULT; 7849 } 7850 return error; 7851 } 7852 7853 7854 /* ------------------------------------------------------------------------ */ 7855 /* Function: ipf_nat_settimeout */ 7856 /* Returns: int - 0 = success, else failure */ 7857 /* Parameters: softc(I) - pointer to soft context main structure */ 7858 /* t(I) - pointer to tunable */ 7859 /* p(I) - pointer to new tuning data */ 7860 /* */ 7861 /* Apply the timeout change to the NAT timeout queues. */ 7862 /* ------------------------------------------------------------------------ */ 7863 int 7864 ipf_nat_settimeout(struct ipf_main_softc_s *softc, ipftuneable_t *t, 7865 ipftuneval_t *p) 7866 { 7867 ipf_nat_softc_t *softn = softc->ipf_nat_soft; 7868 7869 if (!strncmp(t->ipft_name, "tcp_", 4)) 7870 return ipf_settimeout_tcp(t, p, softn->ipf_nat_tcptq); 7871 7872 if (!strcmp(t->ipft_name, "udp_timeout")) { 7873 ipf_apply_timeout(&softn->ipf_nat_udptq, p->ipftu_int); 7874 } else if (!strcmp(t->ipft_name, "udp_ack_timeout")) { 7875 ipf_apply_timeout(&softn->ipf_nat_udpacktq, p->ipftu_int); 7876 } else if (!strcmp(t->ipft_name, "icmp_timeout")) { 7877 ipf_apply_timeout(&softn->ipf_nat_icmptq, p->ipftu_int); 7878 } else if (!strcmp(t->ipft_name, "icmp_ack_timeout")) { 7879 ipf_apply_timeout(&softn->ipf_nat_icmpacktq, p->ipftu_int); 7880 } else if (!strcmp(t->ipft_name, "ip_timeout")) { 7881 ipf_apply_timeout(&softn->ipf_nat_iptq, p->ipftu_int); 7882 } else { 7883 IPFERROR(60062); 7884 return ESRCH; 7885 } 7886 return 0; 7887 } 7888 7889 7890 /* ------------------------------------------------------------------------ */ 7891 /* Function: ipf_nat_rehash */ 7892 /* Returns: int - 0 = success, else failure */ 7893 /* Parameters: softc(I) - pointer to soft context main structure */ 7894 /* t(I) - pointer to tunable */ 7895 /* p(I) - pointer to new tuning data */ 7896 /* */ 7897 /* To change the size of the basic NAT table, we need to first allocate the */ 7898 /* new tables (lest it fails and we've got nowhere to store all of the NAT */ 7899 /* sessions currently active) and then walk through the entire list and */ 7900 /* insert them into the table. There are two tables here: an inbound one */ 7901 /* and an outbound one. Each NAT entry goes into each table once. */ 7902 /* ------------------------------------------------------------------------ */ 7903 int 7904 ipf_nat_rehash(ipf_main_softc_t *softc, ipftuneable_t *t, ipftuneval_t *p) 7905 { 7906 ipf_nat_softc_t *softn = softc->ipf_nat_soft; 7907 nat_t **newtab[2], *nat, **natp; 7908 u_int *bucketlens[2]; 7909 u_int maxbucket; 7910 u_int newsize; 7911 int error; 7912 u_int hv; 7913 int i; 7914 7915 newsize = p->ipftu_int; 7916 /* 7917 * In case there is nothing to do... 7918 */ 7919 if (newsize == softn->ipf_nat_table_sz) 7920 return 0; 7921 7922 newtab[0] = NULL; 7923 newtab[1] = NULL; 7924 bucketlens[0] = NULL; 7925 bucketlens[1] = NULL; 7926 /* 7927 * 4 tables depend on the NAT table size: the inbound looking table, 7928 * the outbound lookup table and the hash chain length for each. 7929 */ 7930 KMALLOCS(newtab[0], nat_t **, newsize * sizeof(nat_t *)); 7931 if (newtab[0] == NULL) { 7932 error = 60063; 7933 goto badrehash; 7934 } 7935 7936 KMALLOCS(newtab[1], nat_t **, newsize * sizeof(nat_t *)); 7937 if (newtab[1] == NULL) { 7938 error = 60064; 7939 goto badrehash; 7940 } 7941 7942 KMALLOCS(bucketlens[0], u_int *, newsize * sizeof(u_int)); 7943 if (bucketlens[0] == NULL) { 7944 error = 60065; 7945 goto badrehash; 7946 } 7947 7948 KMALLOCS(bucketlens[1], u_int *, newsize * sizeof(u_int)); 7949 if (bucketlens[1] == NULL) { 7950 error = 60066; 7951 goto badrehash; 7952 } 7953 7954 /* 7955 * Recalculate the maximum length based on the new size. 7956 */ 7957 for (maxbucket = 0, i = newsize; i > 0; i >>= 1) 7958 maxbucket++; 7959 maxbucket *= 2; 7960 7961 bzero((char *)newtab[0], newsize * sizeof(nat_t *)); 7962 bzero((char *)newtab[1], newsize * sizeof(nat_t *)); 7963 bzero((char *)bucketlens[0], newsize * sizeof(u_int)); 7964 bzero((char *)bucketlens[1], newsize * sizeof(u_int)); 7965 7966 WRITE_ENTER(&softc->ipf_nat); 7967 7968 if (softn->ipf_nat_table[0] != NULL) { 7969 KFREES(softn->ipf_nat_table[0], 7970 softn->ipf_nat_table_sz * 7971 sizeof(*softn->ipf_nat_table[0])); 7972 } 7973 softn->ipf_nat_table[0] = newtab[0]; 7974 7975 if (softn->ipf_nat_table[1] != NULL) { 7976 KFREES(softn->ipf_nat_table[1], 7977 softn->ipf_nat_table_sz * 7978 sizeof(*softn->ipf_nat_table[1])); 7979 } 7980 softn->ipf_nat_table[1] = newtab[1]; 7981 7982 if (softn->ipf_nat_stats.ns_side[0].ns_bucketlen != NULL) { 7983 KFREES(softn->ipf_nat_stats.ns_side[0].ns_bucketlen, 7984 softn->ipf_nat_table_sz * sizeof(u_int)); 7985 } 7986 softn->ipf_nat_stats.ns_side[0].ns_bucketlen = bucketlens[0]; 7987 7988 if (softn->ipf_nat_stats.ns_side[1].ns_bucketlen != NULL) { 7989 KFREES(softn->ipf_nat_stats.ns_side[1].ns_bucketlen, 7990 softn->ipf_nat_table_sz * sizeof(u_int)); 7991 } 7992 softn->ipf_nat_stats.ns_side[1].ns_bucketlen = bucketlens[1]; 7993 7994 softn->ipf_nat_maxbucket = maxbucket; 7995 softn->ipf_nat_table_sz = newsize; 7996 /* 7997 * Walk through the entire list of NAT table entries and put them 7998 * in the new NAT table, somewhere. Because we have a new table, 7999 * we need to restart the counter of how many chains are in use. 8000 */ 8001 softn->ipf_nat_stats.ns_side[0].ns_inuse = 0; 8002 softn->ipf_nat_stats.ns_side[1].ns_inuse = 0; 8003 8004 for (nat = softn->ipf_nat_instances; nat != NULL; nat = nat->nat_next) { 8005 nat->nat_hnext[0] = NULL; 8006 nat->nat_phnext[0] = NULL; 8007 hv = nat->nat_hv[0] % softn->ipf_nat_table_sz; 8008 8009 natp = &softn->ipf_nat_table[0][hv]; 8010 if (*natp) { 8011 (*natp)->nat_phnext[0] = &nat->nat_hnext[0]; 8012 } else { 8013 NBUMPSIDE(0, ns_inuse); 8014 } 8015 nat->nat_phnext[0] = natp; 8016 nat->nat_hnext[0] = *natp; 8017 *natp = nat; 8018 NBUMPSIDE(0, ns_bucketlen[hv]); 8019 8020 nat->nat_hnext[1] = NULL; 8021 nat->nat_phnext[1] = NULL; 8022 hv = nat->nat_hv[1] % softn->ipf_nat_table_sz; 8023 8024 natp = &softn->ipf_nat_table[1][hv]; 8025 if (*natp) { 8026 (*natp)->nat_phnext[1] = &nat->nat_hnext[1]; 8027 } else { 8028 NBUMPSIDE(1, ns_inuse); 8029 } 8030 nat->nat_phnext[1] = natp; 8031 nat->nat_hnext[1] = *natp; 8032 *natp = nat; 8033 NBUMPSIDE(1, ns_bucketlen[hv]); 8034 } 8035 RWLOCK_EXIT(&softc->ipf_nat); 8036 8037 return 0; 8038 8039 badrehash: 8040 if (bucketlens[1] != NULL) { 8041 KFREES(bucketlens[0], newsize * sizeof(u_int)); 8042 } 8043 if (bucketlens[0] != NULL) { 8044 KFREES(bucketlens[0], newsize * sizeof(u_int)); 8045 } 8046 if (newtab[0] != NULL) { 8047 KFREES(newtab[0], newsize * sizeof(nat_t *)); 8048 } 8049 if (newtab[1] != NULL) { 8050 KFREES(newtab[1], newsize * sizeof(nat_t *)); 8051 } 8052 IPFERROR(error); 8053 return ENOMEM; 8054 } 8055 8056 8057 /* ------------------------------------------------------------------------ */ 8058 /* Function: ipf_nat_rehash_rules */ 8059 /* Returns: int - 0 = success, else failure */ 8060 /* Parameters: softc(I) - pointer to soft context main structure */ 8061 /* t(I) - pointer to tunable */ 8062 /* p(I) - pointer to new tuning data */ 8063 /* */ 8064 /* All of the NAT rules hang off of a hash table that is searched with a */ 8065 /* hash on address after the netmask is applied. There is a different table*/ 8066 /* for both inbound rules (rdr) and outbound (map.) The resizing will only */ 8067 /* affect one of these two tables. */ 8068 /* ------------------------------------------------------------------------ */ 8069 int 8070 ipf_nat_rehash_rules(ipf_main_softc_t *softc, ipftuneable_t *t, ipftuneval_t *p) 8071 { 8072 ipf_nat_softc_t *softn = softc->ipf_nat_soft; 8073 ipnat_t **newtab, *np, ***old, **npp; 8074 u_int newsize; 8075 u_int mask; 8076 u_int hv; 8077 8078 newsize = p->ipftu_int; 8079 /* 8080 * In case there is nothing to do... 8081 */ 8082 if (newsize == *t->ipft_pint) 8083 return 0; 8084 8085 /* 8086 * All inbound rules have the NAT_REDIRECT bit set in in_redir and 8087 * all outbound rules have either NAT_MAP or MAT_MAPBLK set. 8088 * This if statement allows for some more generic code to be below, 8089 * rather than two huge gobs of code that almost do the same thing. 8090 */ 8091 if (t->ipft_pint == &softn->ipf_nat_rdrrules_sz) { 8092 old = &softn->ipf_nat_rdr_rules; 8093 mask = NAT_REDIRECT; 8094 } else { 8095 old = &softn->ipf_nat_map_rules; 8096 mask = NAT_MAP|NAT_MAPBLK; 8097 } 8098 8099 KMALLOCS(newtab, ipnat_t **, newsize * sizeof(ipnat_t *)); 8100 if (newtab == NULL) { 8101 IPFERROR(60067); 8102 return ENOMEM; 8103 } 8104 8105 bzero((char *)newtab, newsize * sizeof(ipnat_t *)); 8106 8107 WRITE_ENTER(&softc->ipf_nat); 8108 8109 if (*old != NULL) { 8110 KFREES(*old, *t->ipft_pint * sizeof(ipnat_t **)); 8111 } 8112 *old = newtab; 8113 *t->ipft_pint = newsize; 8114 8115 for (np = softn->ipf_nat_list; np != NULL; np = np->in_next) { 8116 if ((np->in_redir & mask) == 0) 8117 continue; 8118 8119 if (np->in_redir & NAT_REDIRECT) { 8120 np->in_rnext = NULL; 8121 hv = np->in_hv[0] % newsize; 8122 for (npp = newtab + hv; *npp != NULL; ) 8123 npp = &(*npp)->in_rnext; 8124 np->in_prnext = npp; 8125 *npp = np; 8126 } 8127 if (np->in_redir & NAT_MAP) { 8128 np->in_mnext = NULL; 8129 hv = np->in_hv[1] % newsize; 8130 for (npp = newtab + hv; *npp != NULL; ) 8131 npp = &(*npp)->in_mnext; 8132 np->in_pmnext = npp; 8133 *npp = np; 8134 } 8135 8136 } 8137 RWLOCK_EXIT(&softc->ipf_nat); 8138 8139 return 0; 8140 } 8141 8142 8143 /* ------------------------------------------------------------------------ */ 8144 /* Function: ipf_nat_hostmap_rehash */ 8145 /* Returns: int - 0 = success, else failure */ 8146 /* Parameters: softc(I) - pointer to soft context main structure */ 8147 /* t(I) - pointer to tunable */ 8148 /* p(I) - pointer to new tuning data */ 8149 /* */ 8150 /* Allocate and populate a new hash table that will contain a reference to */ 8151 /* all of the active IP# translations currently in place. */ 8152 /* ------------------------------------------------------------------------ */ 8153 int 8154 ipf_nat_hostmap_rehash(ipf_main_softc_t *softc, ipftuneable_t *t, 8155 ipftuneval_t *p) 8156 { 8157 ipf_nat_softc_t *softn = softc->ipf_nat_soft; 8158 hostmap_t *hm, **newtab; 8159 u_int newsize; 8160 u_int hv; 8161 8162 newsize = p->ipftu_int; 8163 /* 8164 * In case there is nothing to do... 8165 */ 8166 if (newsize == *t->ipft_pint) 8167 return 0; 8168 8169 KMALLOCS(newtab, hostmap_t **, newsize * sizeof(hostmap_t *)); 8170 if (newtab == NULL) { 8171 IPFERROR(60068); 8172 return ENOMEM; 8173 } 8174 8175 bzero((char *)newtab, newsize * sizeof(hostmap_t *)); 8176 8177 WRITE_ENTER(&softc->ipf_nat); 8178 if (softn->ipf_hm_maptable != NULL) { 8179 KFREES(softn->ipf_hm_maptable, 8180 softn->ipf_nat_hostmap_sz * sizeof(hostmap_t *)); 8181 } 8182 softn->ipf_hm_maptable = newtab; 8183 softn->ipf_nat_hostmap_sz = newsize; 8184 8185 for (hm = softn->ipf_hm_maplist; hm != NULL; hm = hm->hm_next) { 8186 hv = hm->hm_hv % softn->ipf_nat_hostmap_sz; 8187 hm->hm_hnext = softn->ipf_hm_maptable[hv]; 8188 hm->hm_phnext = softn->ipf_hm_maptable + hv; 8189 if (softn->ipf_hm_maptable[hv] != NULL) 8190 softn->ipf_hm_maptable[hv]->hm_phnext = &hm->hm_hnext; 8191 softn->ipf_hm_maptable[hv] = hm; 8192 } 8193 RWLOCK_EXIT(&softc->ipf_nat); 8194 8195 return 0; 8196 } 8197 8198 8199 /* ------------------------------------------------------------------------ */ 8200 /* Function: ipf_nat_add_tq */ 8201 /* Parameters: softc(I) - pointer to soft context main structure */ 8202 /* */ 8203 /* ------------------------------------------------------------------------ */ 8204 ipftq_t * 8205 ipf_nat_add_tq(ipf_main_softc_t *softc, int ttl) 8206 { 8207 ipf_nat_softc_t *softs = softc->ipf_nat_soft; 8208 8209 return ipf_addtimeoutqueue(softc, &softs->ipf_nat_utqe, ttl); 8210 } 8211 8212 /* ------------------------------------------------------------------------ */ 8213 /* Function: ipf_nat_uncreate */ 8214 /* Returns: Nil */ 8215 /* Parameters: fin(I) - pointer to packet information */ 8216 /* */ 8217 /* This function is used to remove a NAT entry from the NAT table when we */ 8218 /* decide that the create was actually in error. It is thus assumed that */ 8219 /* fin_flx will have both FI_NATED and FI_NATNEW set. Because we're dealing */ 8220 /* with the translated packet (not the original), we have to reverse the */ 8221 /* lookup. Although doing the lookup is expensive (relatively speaking), it */ 8222 /* is not anticipated that this will be a frequent occurance for normal */ 8223 /* traffic patterns. */ 8224 /* ------------------------------------------------------------------------ */ 8225 void 8226 ipf_nat_uncreate(fr_info_t *fin) 8227 { 8228 ipf_main_softc_t *softc = fin->fin_main_soft; 8229 ipf_nat_softc_t *softn = softc->ipf_nat_soft; 8230 int nflags; 8231 nat_t *nat; 8232 8233 switch (fin->fin_p) 8234 { 8235 case IPPROTO_TCP : 8236 nflags = IPN_TCP; 8237 break; 8238 case IPPROTO_UDP : 8239 nflags = IPN_UDP; 8240 break; 8241 default : 8242 nflags = 0; 8243 break; 8244 } 8245 8246 WRITE_ENTER(&softc->ipf_nat); 8247 8248 if (fin->fin_out == 0) { 8249 nat = ipf_nat_outlookup(fin, nflags, (u_int)fin->fin_p, 8250 fin->fin_dst, fin->fin_src); 8251 } else { 8252 nat = ipf_nat_inlookup(fin, nflags, (u_int)fin->fin_p, 8253 fin->fin_src, fin->fin_dst); 8254 } 8255 8256 if (nat != NULL) { 8257 NBUMPSIDE(fin->fin_out, ns_uncreate[0]); 8258 ipf_nat_delete(softc, nat, NL_DESTROY); 8259 } else { 8260 NBUMPSIDE(fin->fin_out, ns_uncreate[1]); 8261 } 8262 8263 RWLOCK_EXIT(&softc->ipf_nat); 8264 } 8265 8266 8267 /* ------------------------------------------------------------------------ */ 8268 /* Function: ipf_nat_cmp_rules */ 8269 /* Returns: int - 0 == success, else rules do not match. */ 8270 /* Parameters: n1(I) - first rule to compare */ 8271 /* n2(I) - first rule to compare */ 8272 /* */ 8273 /* Compare two rules using pointers to each rule. A straight bcmp will not */ 8274 /* work as some fields (such as in_dst, in_pkts) actually do change once */ 8275 /* the rule has been loaded into the kernel. Whilst this function returns */ 8276 /* various non-zero returns, they're strictly to aid in debugging. Use of */ 8277 /* this function should simply care if the result is zero or not. */ 8278 /* ------------------------------------------------------------------------ */ 8279 static int 8280 ipf_nat_cmp_rules(ipnat_t *n1, ipnat_t *n2) 8281 { 8282 if (n1->in_size != n2->in_size) 8283 return 1; 8284 8285 if (bcmp((char *)&n1->in_v, (char *)&n2->in_v, 8286 offsetof(ipnat_t, in_ndst) - offsetof(ipnat_t, in_v)) != 0) 8287 return 2; 8288 8289 if (bcmp((char *)&n1->in_tuc, (char *)&n2->in_tuc, 8290 n1->in_size - offsetof(ipnat_t, in_tuc)) != 0) 8291 return 3; 8292 if (n1->in_ndst.na_atype != n2->in_ndst.na_atype) 8293 return 5; 8294 if (n1->in_ndst.na_function != n2->in_ndst.na_function) 8295 return 6; 8296 if (bcmp((char *)&n1->in_ndst.na_addr, (char *)&n2->in_ndst.na_addr, 8297 sizeof(n1->in_ndst.na_addr))) 8298 return 7; 8299 if (n1->in_nsrc.na_atype != n2->in_nsrc.na_atype) 8300 return 8; 8301 if (n1->in_nsrc.na_function != n2->in_nsrc.na_function) 8302 return 9; 8303 if (bcmp((char *)&n1->in_nsrc.na_addr, (char *)&n2->in_nsrc.na_addr, 8304 sizeof(n1->in_nsrc.na_addr))) 8305 return 10; 8306 if (n1->in_odst.na_atype != n2->in_odst.na_atype) 8307 return 11; 8308 if (n1->in_odst.na_function != n2->in_odst.na_function) 8309 return 12; 8310 if (bcmp((char *)&n1->in_odst.na_addr, (char *)&n2->in_odst.na_addr, 8311 sizeof(n1->in_odst.na_addr))) 8312 return 13; 8313 if (n1->in_osrc.na_atype != n2->in_osrc.na_atype) 8314 return 14; 8315 if (n1->in_osrc.na_function != n2->in_osrc.na_function) 8316 return 15; 8317 if (bcmp((char *)&n1->in_osrc.na_addr, (char *)&n2->in_osrc.na_addr, 8318 sizeof(n1->in_osrc.na_addr))) 8319 return 16; 8320 return 0; 8321 } 8322 8323 8324 /* ------------------------------------------------------------------------ */ 8325 /* Function: ipf_nat_rule_init */ 8326 /* Returns: int - 0 == success, else rules do not match. */ 8327 /* Parameters: softc(I) - pointer to soft context main structure */ 8328 /* softn(I) - pointer to NAT context structure */ 8329 /* n(I) - first rule to compare */ 8330 /* */ 8331 /* ------------------------------------------------------------------------ */ 8332 static int 8333 ipf_nat_rule_init(ipf_main_softc_t *softc, ipf_nat_softc_t *softn, ipnat_t *n) 8334 { 8335 int error = 0; 8336 8337 if ((n->in_flags & IPN_SIPRANGE) != 0) 8338 n->in_nsrcatype = FRI_RANGE; 8339 8340 if ((n->in_flags & IPN_DIPRANGE) != 0) 8341 n->in_ndstatype = FRI_RANGE; 8342 8343 if ((n->in_flags & IPN_SPLIT) != 0) 8344 n->in_ndstatype = FRI_SPLIT; 8345 8346 if ((n->in_redir & (NAT_MAP|NAT_REWRITE|NAT_DIVERTUDP)) != 0) 8347 n->in_spnext = n->in_spmin; 8348 8349 if ((n->in_redir & (NAT_REWRITE|NAT_DIVERTUDP)) != 0) { 8350 n->in_dpnext = n->in_dpmin; 8351 } else if (n->in_redir == NAT_REDIRECT) { 8352 n->in_dpnext = n->in_dpmin; 8353 } 8354 8355 n->in_stepnext = 0; 8356 8357 switch (n->in_v[0]) 8358 { 8359 case 4 : 8360 error = ipf_nat_ruleaddrinit(softc, softn, n); 8361 if (error != 0) 8362 return error; 8363 break; 8364 #ifdef USE_INET6 8365 case 6 : 8366 error = ipf_nat6_ruleaddrinit(softc, softn, n); 8367 if (error != 0) 8368 return error; 8369 break; 8370 #endif 8371 default : 8372 break; 8373 } 8374 8375 if (n->in_redir == (NAT_DIVERTUDP|NAT_MAP)) { 8376 /* 8377 * Prerecord whether or not the destination of the divert 8378 * is local or not to the interface the packet is going 8379 * to be sent out. 8380 */ 8381 n->in_dlocal = ipf_deliverlocal(softc, n->in_v[1], 8382 n->in_ifps[1], &n->in_ndstip6); 8383 } 8384 8385 return error; 8386 } 8387 8388 8389 /* ------------------------------------------------------------------------ */ 8390 /* Function: ipf_nat_rule_fini */ 8391 /* Returns: int - 0 == success, else rules do not match. */ 8392 /* Parameters: softc(I) - pointer to soft context main structure */ 8393 /* n(I) - rule to work on */ 8394 /* */ 8395 /* This function is used to release any objects that were referenced during */ 8396 /* the rule initialisation. This is useful both when free'ing the rule and */ 8397 /* when handling ioctls that need to initialise these fields but not */ 8398 /* actually use them after the ioctl processing has finished. */ 8399 /* ------------------------------------------------------------------------ */ 8400 static void 8401 ipf_nat_rule_fini(ipf_main_softc_t *softc, ipnat_t *n) 8402 { 8403 if (n->in_odst.na_atype == FRI_LOOKUP && n->in_odst.na_ptr != NULL) 8404 ipf_lookup_deref(softc, n->in_odst.na_type, n->in_odst.na_ptr); 8405 8406 if (n->in_osrc.na_atype == FRI_LOOKUP && n->in_osrc.na_ptr != NULL) 8407 ipf_lookup_deref(softc, n->in_osrc.na_type, n->in_osrc.na_ptr); 8408 8409 if (n->in_ndst.na_atype == FRI_LOOKUP && n->in_ndst.na_ptr != NULL) 8410 ipf_lookup_deref(softc, n->in_ndst.na_type, n->in_ndst.na_ptr); 8411 8412 if (n->in_nsrc.na_atype == FRI_LOOKUP && n->in_nsrc.na_ptr != NULL) 8413 ipf_lookup_deref(softc, n->in_nsrc.na_type, n->in_nsrc.na_ptr); 8414 8415 if (n->in_divmp != NULL) 8416 FREE_MB_T(n->in_divmp); 8417 } 8418