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