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