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