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