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