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