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