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