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