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