ip_nat.c revision 87394
1/* 2 * Copyright (C) 1995-2001 by Darren Reed. 3 * 4 * See the IPFILTER.LICENCE file for details on licencing. 5 * 6 * Added redirect stuff and a LOT of bug fixes. (mcn@EnGarde.com) 7 */ 8 9#if defined(__FreeBSD__) && defined(KERNEL) && !defined(_KERNEL) 10#define _KERNEL 11#endif 12 13#include <sys/errno.h> 14#include <sys/types.h> 15#include <sys/param.h> 16#include <sys/time.h> 17#include <sys/file.h> 18#if defined(__NetBSD__) && (NetBSD >= 199905) && !defined(IPFILTER_LKM) && \ 19 defined(_KERNEL) 20# include "opt_ipfilter_log.h" 21#endif 22#if !defined(_KERNEL) && !defined(KERNEL) 23# include <stdio.h> 24# include <string.h> 25# include <stdlib.h> 26#endif 27#if (defined(KERNEL) || defined(_KERNEL)) && (__FreeBSD_version >= 220000) 28# include <sys/filio.h> 29# include <sys/fcntl.h> 30#else 31# include <sys/ioctl.h> 32#endif 33#include <sys/fcntl.h> 34#include <sys/uio.h> 35#ifndef linux 36# include <sys/protosw.h> 37#endif 38#include <sys/socket.h> 39#if defined(_KERNEL) && !defined(linux) 40# include <sys/systm.h> 41#endif 42#if !defined(__SVR4) && !defined(__svr4__) 43# ifndef linux 44# include <sys/mbuf.h> 45# endif 46#else 47# include <sys/filio.h> 48# include <sys/byteorder.h> 49# ifdef _KERNEL 50# include <sys/dditypes.h> 51# endif 52# include <sys/stream.h> 53# include <sys/kmem.h> 54#endif 55#if __FreeBSD_version >= 300000 56# include <sys/queue.h> 57#endif 58#include <net/if.h> 59#if __FreeBSD_version >= 300000 60# include <net/if_var.h> 61# if defined(_KERNEL) && !defined(IPFILTER_LKM) 62# include "opt_ipfilter.h" 63# endif 64#endif 65#ifdef sun 66# include <net/af.h> 67#endif 68#include <net/route.h> 69#include <netinet/in.h> 70#include <netinet/in_systm.h> 71#include <netinet/ip.h> 72 73#ifdef __sgi 74# ifdef IFF_DRVRLOCK /* IRIX6 */ 75#include <sys/hashing.h> 76#include <netinet/in_var.h> 77# endif 78#endif 79 80#ifdef RFC1825 81# include <vpn/md5.h> 82# include <vpn/ipsec.h> 83extern struct ifnet vpnif; 84#endif 85 86#ifndef linux 87# include <netinet/ip_var.h> 88# include <netinet/tcp_fsm.h> 89#endif 90#include <netinet/tcp.h> 91#include <netinet/udp.h> 92#include <netinet/ip_icmp.h> 93#include "netinet/ip_compat.h" 94#include <netinet/tcpip.h> 95#include "netinet/ip_fil.h" 96#include "netinet/ip_proxy.h" 97#include "netinet/ip_nat.h" 98#include "netinet/ip_frag.h" 99#include "netinet/ip_state.h" 100#if (__FreeBSD_version >= 300000) 101# include <sys/malloc.h> 102#endif 103#ifndef MIN 104# define MIN(a,b) (((a)<(b))?(a):(b)) 105#endif 106#undef SOCKADDR_IN 107#define SOCKADDR_IN struct sockaddr_in 108 109#if !defined(lint) 110static const char sccsid[] = "@(#)ip_nat.c 1.11 6/5/96 (C) 1995 Darren Reed"; 111/* static const char rcsid[] = "@(#)$Id: ip_nat.c,v 2.37.2.44 2001/07/21 07:17:22 darrenr Exp $"; */ 112static const char rcsid[] = "@(#)$FreeBSD: head/sys/contrib/ipfilter/netinet/ip_nat.c 87394 2001-12-05 10:46:24Z guido $"; 113#endif 114 115nat_t **nat_table[2] = { NULL, NULL }, 116 *nat_instances = NULL; 117ipnat_t *nat_list = NULL; 118u_int ipf_nattable_sz = NAT_TABLE_SZ; 119u_int ipf_natrules_sz = NAT_SIZE; 120u_int ipf_rdrrules_sz = RDR_SIZE; 121u_int ipf_hostmap_sz = HOSTMAP_SIZE; 122u_32_t nat_masks = 0; 123u_32_t rdr_masks = 0; 124ipnat_t **nat_rules = NULL; 125ipnat_t **rdr_rules = NULL; 126hostmap_t **maptable = NULL; 127 128u_long fr_defnatage = DEF_NAT_AGE, 129 fr_defnaticmpage = 6; /* 3 seconds */ 130natstat_t nat_stats; 131int fr_nat_lock = 0; 132#if (SOLARIS || defined(__sgi)) && defined(_KERNEL) 133extern kmutex_t ipf_rw; 134extern KRWLOCK_T ipf_nat; 135#endif 136 137static int nat_flushtable __P((void)); 138static int nat_clearlist __P((void)); 139static void nat_addnat __P((struct ipnat *)); 140static void nat_addrdr __P((struct ipnat *)); 141static void nat_delete __P((struct nat *)); 142static void nat_delrdr __P((struct ipnat *)); 143static void nat_delnat __P((struct ipnat *)); 144static int fr_natgetent __P((caddr_t)); 145static int fr_natgetsz __P((caddr_t)); 146static int fr_natputent __P((caddr_t)); 147static void nat_tabmove __P((nat_t *, u_32_t)); 148static int nat_match __P((fr_info_t *, ipnat_t *, ip_t *)); 149static hostmap_t *nat_hostmap __P((ipnat_t *, struct in_addr, 150 struct in_addr)); 151static void nat_hostmapdel __P((struct hostmap *)); 152 153 154int nat_init() 155{ 156 KMALLOCS(nat_table[0], nat_t **, sizeof(nat_t *) * ipf_nattable_sz); 157 if (nat_table[0] != NULL) 158 bzero((char *)nat_table[0], ipf_nattable_sz * sizeof(nat_t *)); 159 else 160 return -1; 161 162 KMALLOCS(nat_table[1], nat_t **, sizeof(nat_t *) * ipf_nattable_sz); 163 if (nat_table[1] != NULL) 164 bzero((char *)nat_table[1], ipf_nattable_sz * sizeof(nat_t *)); 165 else 166 return -1; 167 168 KMALLOCS(nat_rules, ipnat_t **, sizeof(ipnat_t *) * ipf_natrules_sz); 169 if (nat_rules != NULL) 170 bzero((char *)nat_rules, ipf_natrules_sz * sizeof(ipnat_t *)); 171 else 172 return -1; 173 174 KMALLOCS(rdr_rules, ipnat_t **, sizeof(ipnat_t *) * ipf_rdrrules_sz); 175 if (rdr_rules != NULL) 176 bzero((char *)rdr_rules, ipf_rdrrules_sz * sizeof(ipnat_t *)); 177 else 178 return -1; 179 180 KMALLOCS(maptable, hostmap_t **, sizeof(hostmap_t *) * ipf_hostmap_sz); 181 if (maptable != NULL) 182 bzero((char *)maptable, sizeof(hostmap_t *) * ipf_hostmap_sz); 183 else 184 return -1; 185 return 0; 186} 187 188 189static void nat_addrdr(n) 190ipnat_t *n; 191{ 192 ipnat_t **np; 193 u_32_t j; 194 u_int hv; 195 int k; 196 197 k = countbits(n->in_outmsk); 198 if ((k >= 0) && (k != 32)) 199 rdr_masks |= 1 << k; 200 j = (n->in_outip & n->in_outmsk); 201 hv = NAT_HASH_FN(j, 0, ipf_rdrrules_sz); 202 np = rdr_rules + hv; 203 while (*np != NULL) 204 np = &(*np)->in_rnext; 205 n->in_rnext = NULL; 206 n->in_prnext = np; 207 *np = n; 208} 209 210 211static void nat_addnat(n) 212ipnat_t *n; 213{ 214 ipnat_t **np; 215 u_32_t j; 216 u_int hv; 217 int k; 218 219 k = countbits(n->in_inmsk); 220 if ((k >= 0) && (k != 32)) 221 nat_masks |= 1 << k; 222 j = (n->in_inip & n->in_inmsk); 223 hv = NAT_HASH_FN(j, 0, ipf_natrules_sz); 224 np = nat_rules + hv; 225 while (*np != NULL) 226 np = &(*np)->in_mnext; 227 n->in_mnext = NULL; 228 n->in_pmnext = np; 229 *np = n; 230} 231 232 233static void nat_delrdr(n) 234ipnat_t *n; 235{ 236 if (n->in_rnext) 237 n->in_rnext->in_prnext = n->in_prnext; 238 *n->in_prnext = n->in_rnext; 239} 240 241 242static void nat_delnat(n) 243ipnat_t *n; 244{ 245 if (n->in_mnext) 246 n->in_mnext->in_pmnext = n->in_pmnext; 247 *n->in_pmnext = n->in_mnext; 248} 249 250 251/* 252 * check if an ip address has already been allocated for a given mapping that 253 * is not doing port based translation. 254 * 255 * Must be called with ipf_nat held as a write lock. 256 */ 257static struct hostmap *nat_hostmap(np, real, map) 258ipnat_t *np; 259struct in_addr real; 260struct in_addr map; 261{ 262 hostmap_t *hm; 263 u_int hv; 264 265 hv = real.s_addr % HOSTMAP_SIZE; 266 for (hm = maptable[hv]; hm; hm = hm->hm_next) 267 if ((hm->hm_realip.s_addr == real.s_addr) && 268 (np == hm->hm_ipnat)) { 269 hm->hm_ref++; 270 return hm; 271 } 272 273 KMALLOC(hm, hostmap_t *); 274 if (hm) { 275 hm->hm_next = maptable[hv]; 276 hm->hm_pnext = maptable + hv; 277 if (maptable[hv]) 278 maptable[hv]->hm_pnext = &hm->hm_next; 279 maptable[hv] = hm; 280 hm->hm_ipnat = np; 281 hm->hm_realip = real; 282 hm->hm_mapip = map; 283 hm->hm_ref = 1; 284 } 285 return hm; 286} 287 288 289/* 290 * Must be called with ipf_nat held as a write lock. 291 */ 292static void nat_hostmapdel(hm) 293struct hostmap *hm; 294{ 295 ATOMIC_DEC32(hm->hm_ref); 296 if (hm->hm_ref == 0) { 297 if (hm->hm_next) 298 hm->hm_next->hm_pnext = hm->hm_pnext; 299 *hm->hm_pnext = hm->hm_next; 300 KFREE(hm); 301 } 302} 303 304 305void fix_outcksum(fin, sp, n) 306fr_info_t *fin; 307u_short *sp; 308u_32_t n; 309{ 310 register u_short sumshort; 311 register u_32_t sum1; 312 313 if (!n) 314 return; 315 else if (n & NAT_HW_CKSUM) { 316 n &= 0xffff; 317 n += fin->fin_dlen; 318 n = (n & 0xffff) + (n >> 16); 319 *sp = n & 0xffff; 320 return; 321 } 322 sum1 = (~ntohs(*sp)) & 0xffff; 323 sum1 += (n); 324 sum1 = (sum1 >> 16) + (sum1 & 0xffff); 325 /* Again */ 326 sum1 = (sum1 >> 16) + (sum1 & 0xffff); 327 sumshort = ~(u_short)sum1; 328 *(sp) = htons(sumshort); 329} 330 331 332void fix_incksum(fin, sp, n) 333fr_info_t *fin; 334u_short *sp; 335u_32_t n; 336{ 337 register u_short sumshort; 338 register u_32_t sum1; 339 340 if (!n) 341 return; 342 else if (n & NAT_HW_CKSUM) { 343 n &= 0xffff; 344 n += fin->fin_dlen; 345 n = (n & 0xffff) + (n >> 16); 346 *sp = n & 0xffff; 347 return; 348 } 349#ifdef sparc 350 sum1 = (~(*sp)) & 0xffff; 351#else 352 sum1 = (~ntohs(*sp)) & 0xffff; 353#endif 354 sum1 += ~(n) & 0xffff; 355 sum1 = (sum1 >> 16) + (sum1 & 0xffff); 356 /* Again */ 357 sum1 = (sum1 >> 16) + (sum1 & 0xffff); 358 sumshort = ~(u_short)sum1; 359 *(sp) = htons(sumshort); 360} 361 362 363/* 364 * fix_datacksum is used *only* for the adjustments of checksums in the data 365 * section of an IP packet. 366 * 367 * The only situation in which you need to do this is when NAT'ing an 368 * ICMP error message. Such a message, contains in its body the IP header 369 * of the original IP packet, that causes the error. 370 * 371 * You can't use fix_incksum or fix_outcksum in that case, because for the 372 * kernel the data section of the ICMP error is just data, and no special 373 * processing like hardware cksum or ntohs processing have been done by the 374 * kernel on the data section. 375 */ 376void fix_datacksum(sp, n) 377u_short *sp; 378u_32_t n; 379{ 380 register u_short sumshort; 381 register u_32_t sum1; 382 383 if (!n) 384 return; 385 386 sum1 = (~ntohs(*sp)) & 0xffff; 387 sum1 += (n); 388 sum1 = (sum1 >> 16) + (sum1 & 0xffff); 389 /* Again */ 390 sum1 = (sum1 >> 16) + (sum1 & 0xffff); 391 sumshort = ~(u_short)sum1; 392 *(sp) = htons(sumshort); 393} 394 395/* 396 * How the NAT is organised and works. 397 * 398 * Inside (interface y) NAT Outside (interface x) 399 * -------------------- -+- ------------------------------------- 400 * Packet going | out, processsed by ip_natout() for x 401 * ------------> | ------------> 402 * src=10.1.1.1 | src=192.1.1.1 403 * | 404 * | in, processed by ip_natin() for x 405 * <------------ | <------------ 406 * dst=10.1.1.1 | dst=192.1.1.1 407 * -------------------- -+- ------------------------------------- 408 * ip_natout() - changes ip_src and if required, sport 409 * - creates a new mapping, if required. 410 * ip_natin() - changes ip_dst and if required, dport 411 * 412 * In the NAT table, internal source is recorded as "in" and externally 413 * seen as "out". 414 */ 415 416/* 417 * Handle ioctls which manipulate the NAT. 418 */ 419int nat_ioctl(data, cmd, mode) 420#if defined(__NetBSD__) || defined(__OpenBSD__) || (__FreeBSD_version >= 300003) 421u_long cmd; 422#else 423int cmd; 424#endif 425caddr_t data; 426int mode; 427{ 428 register ipnat_t *nat, *nt, *n = NULL, **np = NULL; 429 int error = 0, ret, arg; 430 ipnat_t natd; 431 u_32_t i, j; 432 433#if (BSD >= 199306) && defined(_KERNEL) 434 if ((securelevel >= 2) && (mode & FWRITE)) 435 return EPERM; 436#endif 437 438 nat = NULL; /* XXX gcc -Wuninitialized */ 439 KMALLOC(nt, ipnat_t *); 440 if ((cmd == SIOCADNAT) || (cmd == SIOCRMNAT)) 441 error = IRCOPYPTR(data, (char *)&natd, sizeof(natd)); 442 else if (cmd == SIOCIPFFL) { /* SIOCFLNAT & SIOCCNATL */ 443 error = IRCOPY(data, (char *)&arg, sizeof(arg)); 444 if (error) 445 error = EFAULT; 446 } 447 448 if (error) 449 goto done; 450 451 /* 452 * For add/delete, look to see if the NAT entry is already present 453 */ 454 WRITE_ENTER(&ipf_nat); 455 if ((cmd == SIOCADNAT) || (cmd == SIOCRMNAT)) { 456 nat = &natd; 457 nat->in_flags &= IPN_USERFLAGS; 458 if ((nat->in_redir & NAT_MAPBLK) == 0) { 459 if ((nat->in_flags & IPN_SPLIT) == 0) 460 nat->in_inip &= nat->in_inmsk; 461 if ((nat->in_flags & IPN_IPRANGE) == 0) 462 nat->in_outip &= nat->in_outmsk; 463 } 464 for (np = &nat_list; (n = *np); np = &n->in_next) 465 if (!bcmp((char *)&nat->in_flags, (char *)&n->in_flags, 466 IPN_CMPSIZ)) 467 break; 468 } 469 470 switch (cmd) 471 { 472#ifdef IPFILTER_LOG 473 case SIOCIPFFB : 474 { 475 int tmp; 476 477 if (!(mode & FWRITE)) 478 error = EPERM; 479 else { 480 tmp = ipflog_clear(IPL_LOGNAT); 481 IWCOPY((char *)&tmp, (char *)data, sizeof(tmp)); 482 } 483 break; 484 } 485#endif 486 case SIOCADNAT : 487 if (!(mode & FWRITE)) { 488 error = EPERM; 489 break; 490 } 491 if (n) { 492 error = EEXIST; 493 break; 494 } 495 if (nt == NULL) { 496 error = ENOMEM; 497 break; 498 } 499 n = nt; 500 nt = NULL; 501 bcopy((char *)nat, (char *)n, sizeof(*n)); 502 n->in_ifp = (void *)GETUNIT(n->in_ifname, 4); 503 if (!n->in_ifp) 504 n->in_ifp = (void *)-1; 505 if (n->in_plabel[0] != '\0') { 506 n->in_apr = appr_match(n->in_p, n->in_plabel); 507 if (!n->in_apr) { 508 error = ENOENT; 509 break; 510 } 511 } 512 n->in_next = NULL; 513 *np = n; 514 515 if (n->in_redir & NAT_REDIRECT) { 516 n->in_flags &= ~IPN_NOTDST; 517 nat_addrdr(n); 518 } 519 if (n->in_redir & (NAT_MAP|NAT_MAPBLK)) { 520 n->in_flags &= ~IPN_NOTSRC; 521 nat_addnat(n); 522 } 523 524 n->in_use = 0; 525 if (n->in_redir & NAT_MAPBLK) 526 n->in_space = USABLE_PORTS * ~ntohl(n->in_outmsk); 527 else if (n->in_flags & IPN_AUTOPORTMAP) 528 n->in_space = USABLE_PORTS * ~ntohl(n->in_inmsk); 529 else if (n->in_flags & IPN_IPRANGE) 530 n->in_space = ntohl(n->in_outmsk) - ntohl(n->in_outip); 531 else if (n->in_flags & IPN_SPLIT) 532 n->in_space = 2; 533 else 534 n->in_space = ~ntohl(n->in_outmsk); 535 /* 536 * Calculate the number of valid IP addresses in the output 537 * mapping range. In all cases, the range is inclusive of 538 * the start and ending IP addresses. 539 * If to a CIDR address, lose 2: broadcast + network address 540 * (so subtract 1) 541 * If to a range, add one. 542 * If to a single IP address, set to 1. 543 */ 544 if (n->in_space) { 545 if ((n->in_flags & IPN_IPRANGE) != 0) 546 n->in_space += 1; 547 else 548 n->in_space -= 1; 549 } else 550 n->in_space = 1; 551 if ((n->in_outmsk != 0xffffffff) && (n->in_outmsk != 0) && 552 ((n->in_flags & (IPN_IPRANGE|IPN_SPLIT)) == 0)) 553 n->in_nip = ntohl(n->in_outip) + 1; 554 else if ((n->in_flags & IPN_SPLIT) && 555 (n->in_redir & NAT_REDIRECT)) 556 n->in_nip = ntohl(n->in_inip); 557 else 558 n->in_nip = ntohl(n->in_outip); 559 if (n->in_redir & NAT_MAP) { 560 n->in_pnext = ntohs(n->in_pmin); 561 /* 562 * Multiply by the number of ports made available. 563 */ 564 if (ntohs(n->in_pmax) >= ntohs(n->in_pmin)) { 565 n->in_space *= (ntohs(n->in_pmax) - 566 ntohs(n->in_pmin) + 1); 567 /* 568 * Because two different sources can map to 569 * different destinations but use the same 570 * local IP#/port #. 571 * If the result is smaller than in_space, then 572 * we may have wrapped around 32bits. 573 */ 574 i = n->in_inmsk; 575 if ((i != 0) && (i != 0xffffffff)) { 576 j = n->in_space * (~ntohl(i) + 1); 577 if (j >= n->in_space) 578 n->in_space = j; 579 else 580 n->in_space = 0xffffffff; 581 } 582 } 583 /* 584 * If no protocol is specified, multiple by 256. 585 */ 586 if ((n->in_flags & IPN_TCPUDP) == 0) { 587 j = n->in_space * 256; 588 if (j >= n->in_space) 589 n->in_space = j; 590 else 591 n->in_space = 0xffffffff; 592 } 593 } 594 /* Otherwise, these fields are preset */ 595 n = NULL; 596 nat_stats.ns_rules++; 597 break; 598 case SIOCRMNAT : 599 if (!(mode & FWRITE)) { 600 error = EPERM; 601 n = NULL; 602 break; 603 } 604 if (!n) { 605 error = ESRCH; 606 break; 607 } 608 if (n->in_redir & NAT_REDIRECT) 609 nat_delrdr(n); 610 if (n->in_redir & (NAT_MAPBLK|NAT_MAP)) 611 nat_delnat(n); 612 if (nat_list == NULL) { 613 nat_masks = 0; 614 rdr_masks = 0; 615 } 616 *np = n->in_next; 617 if (!n->in_use) { 618 if (n->in_apr) 619 appr_free(n->in_apr); 620 KFREE(n); 621 nat_stats.ns_rules--; 622 } else { 623 n->in_flags |= IPN_DELETE; 624 n->in_next = NULL; 625 } 626 n = NULL; 627 break; 628 case SIOCGNATS : 629 MUTEX_DOWNGRADE(&ipf_nat); 630 nat_stats.ns_table[0] = nat_table[0]; 631 nat_stats.ns_table[1] = nat_table[1]; 632 nat_stats.ns_list = nat_list; 633 nat_stats.ns_maptable = maptable; 634 nat_stats.ns_nattab_sz = ipf_nattable_sz; 635 nat_stats.ns_rultab_sz = ipf_natrules_sz; 636 nat_stats.ns_rdrtab_sz = ipf_rdrrules_sz; 637 nat_stats.ns_hostmap_sz = ipf_hostmap_sz; 638 nat_stats.ns_instances = nat_instances; 639 nat_stats.ns_apslist = ap_sess_list; 640 error = IWCOPYPTR((char *)&nat_stats, (char *)data, 641 sizeof(nat_stats)); 642 break; 643 case SIOCGNATL : 644 { 645 natlookup_t nl; 646 647 MUTEX_DOWNGRADE(&ipf_nat); 648 error = IRCOPYPTR((char *)data, (char *)&nl, sizeof(nl)); 649 if (error) 650 break; 651 652 if (nat_lookupredir(&nl)) { 653 error = IWCOPYPTR((char *)&nl, (char *)data, 654 sizeof(nl)); 655 } else 656 error = ESRCH; 657 break; 658 } 659 case SIOCIPFFL : /* old SIOCFLNAT & SIOCCNATL */ 660 if (!(mode & FWRITE)) { 661 error = EPERM; 662 break; 663 } 664 error = 0; 665 if (arg == 0) 666 ret = nat_flushtable(); 667 else if (arg == 1) 668 ret = nat_clearlist(); 669 else 670 error = EINVAL; 671 MUTEX_DOWNGRADE(&ipf_nat); 672 if (!error) { 673 error = IWCOPY((caddr_t)&ret, data, sizeof(ret)); 674 if (error) 675 error = EFAULT; 676 } 677 break; 678 case SIOCSTLCK : 679 error = IRCOPY(data, (caddr_t)&arg, sizeof(arg)); 680 if (!error) { 681 error = IWCOPY((caddr_t)&fr_nat_lock, data, 682 sizeof(fr_nat_lock)); 683 if (!error) 684 fr_nat_lock = arg; 685 } else 686 error = EFAULT; 687 break; 688 case SIOCSTPUT : 689 if (fr_nat_lock) 690 error = fr_natputent(data); 691 else 692 error = EACCES; 693 break; 694 case SIOCSTGSZ : 695 if (fr_nat_lock) 696 error = fr_natgetsz(data); 697 else 698 error = EACCES; 699 break; 700 case SIOCSTGET : 701 if (fr_nat_lock) 702 error = fr_natgetent(data); 703 else 704 error = EACCES; 705 break; 706 case FIONREAD : 707#ifdef IPFILTER_LOG 708 arg = (int)iplused[IPL_LOGNAT]; 709 MUTEX_DOWNGRADE(&ipf_nat); 710 error = IWCOPY((caddr_t)&arg, (caddr_t)data, sizeof(arg)); 711 if (error) 712 error = EFAULT; 713#endif 714 break; 715 default : 716 error = EINVAL; 717 break; 718 } 719 RWLOCK_EXIT(&ipf_nat); /* READ/WRITE */ 720done: 721 if (nt) 722 KFREE(nt); 723 return error; 724} 725 726 727static int fr_natgetsz(data) 728caddr_t data; 729{ 730 ap_session_t *aps; 731 nat_t *nat, *n; 732 int error = 0; 733 natget_t ng; 734 735 error = IRCOPY(data, (caddr_t)&ng, sizeof(ng)); 736 if (error) 737 return EFAULT; 738 739 nat = ng.ng_ptr; 740 if (!nat) { 741 nat = nat_instances; 742 ng.ng_sz = 0; 743 if (nat == NULL) { 744 error = IWCOPY((caddr_t)&ng, data, sizeof(ng)); 745 if (error) 746 error = EFAULT; 747 return error; 748 } 749 } else { 750 /* 751 * Make sure the pointer we're copying from exists in the 752 * current list of entries. Security precaution to prevent 753 * copying of random kernel data. 754 */ 755 for (n = nat_instances; n; n = n->nat_next) 756 if (n == nat) 757 break; 758 if (!n) 759 return ESRCH; 760 } 761 762 ng.ng_sz = sizeof(nat_save_t); 763 aps = nat->nat_aps; 764 if ((aps != NULL) && (aps->aps_data != 0)) { 765 ng.ng_sz += sizeof(ap_session_t); 766 ng.ng_sz += aps->aps_psiz; 767 } 768 769 error = IWCOPY((caddr_t)&ng, data, sizeof(ng)); 770 if (error) 771 error = EFAULT; 772 return error; 773} 774 775 776static int fr_natgetent(data) 777caddr_t data; 778{ 779 nat_save_t ipn, *ipnp, *ipnn = NULL; 780 register nat_t *n, *nat; 781 ap_session_t *aps; 782 int error; 783 784 error = IRCOPY(data, (caddr_t)&ipnp, sizeof(ipnp)); 785 if (error) 786 return EFAULT; 787 error = IRCOPY((caddr_t)ipnp, (caddr_t)&ipn, sizeof(ipn)); 788 if (error) 789 return EFAULT; 790 791 nat = ipn.ipn_next; 792 if (!nat) { 793 nat = nat_instances; 794 if (nat == NULL) { 795 if (nat_instances == NULL) 796 return ENOENT; 797 return 0; 798 } 799 } else { 800 /* 801 * Make sure the pointer we're copying from exists in the 802 * current list of entries. Security precaution to prevent 803 * copying of random kernel data. 804 */ 805 for (n = nat_instances; n; n = n->nat_next) 806 if (n == nat) 807 break; 808 if (!n) 809 return ESRCH; 810 } 811 812 ipn.ipn_next = nat->nat_next; 813 ipn.ipn_dsize = 0; 814 bcopy((char *)nat, (char *)&ipn.ipn_nat, sizeof(ipn.ipn_nat)); 815 ipn.ipn_nat.nat_data = NULL; 816 817 if (nat->nat_ptr) { 818 bcopy((char *)nat->nat_ptr, (char *)&ipn.ipn_ipnat, 819 sizeof(ipn.ipn_ipnat)); 820 } 821 822 if (nat->nat_fr) 823 bcopy((char *)nat->nat_fr, (char *)&ipn.ipn_rule, 824 sizeof(ipn.ipn_rule)); 825 826 if ((aps = nat->nat_aps)) { 827 ipn.ipn_dsize = sizeof(*aps); 828 if (aps->aps_data) 829 ipn.ipn_dsize += aps->aps_psiz; 830 KMALLOCS(ipnn, nat_save_t *, sizeof(*ipnn) + ipn.ipn_dsize); 831 if (ipnn == NULL) 832 return ENOMEM; 833 bcopy((char *)&ipn, (char *)ipnn, sizeof(ipn)); 834 835 bcopy((char *)aps, ipnn->ipn_data, sizeof(*aps)); 836 if (aps->aps_data) { 837 bcopy(aps->aps_data, ipnn->ipn_data + sizeof(*aps), 838 aps->aps_psiz); 839 ipnn->ipn_dsize += aps->aps_psiz; 840 } 841 error = IWCOPY((caddr_t)ipnn, ipnp, 842 sizeof(ipn) + ipn.ipn_dsize); 843 if (error) 844 error = EFAULT; 845 KFREES(ipnn, sizeof(*ipnn) + ipn.ipn_dsize); 846 } else { 847 error = IWCOPY((caddr_t)&ipn, ipnp, sizeof(ipn)); 848 if (error) 849 error = EFAULT; 850 } 851 return error; 852} 853 854 855static int fr_natputent(data) 856caddr_t data; 857{ 858 nat_save_t ipn, *ipnp, *ipnn = NULL; 859 register nat_t *n, *nat; 860 ap_session_t *aps; 861 frentry_t *fr; 862 ipnat_t *in; 863 864 int error; 865 866 error = IRCOPY(data, (caddr_t)&ipnp, sizeof(ipnp)); 867 if (error) 868 return EFAULT; 869 error = IRCOPY((caddr_t)ipnp, (caddr_t)&ipn, sizeof(ipn)); 870 if (error) 871 return EFAULT; 872 nat = NULL; 873 if (ipn.ipn_dsize) { 874 KMALLOCS(ipnn, nat_save_t *, sizeof(ipn) + ipn.ipn_dsize); 875 if (ipnn == NULL) 876 return ENOMEM; 877 bcopy((char *)&ipn, (char *)ipnn, sizeof(ipn)); 878 error = IRCOPY((caddr_t)ipnp, (caddr_t)ipn.ipn_data, 879 ipn.ipn_dsize); 880 if (error) { 881 error = EFAULT; 882 goto junkput; 883 } 884 } else 885 ipnn = NULL; 886 887 KMALLOC(nat, nat_t *); 888 if (nat == NULL) { 889 error = EFAULT; 890 goto junkput; 891 } 892 893 bcopy((char *)&ipn.ipn_nat, (char *)nat, sizeof(*nat)); 894 /* 895 * Initialize all these so that nat_delete() doesn't cause a crash. 896 */ 897 nat->nat_phnext[0] = NULL; 898 nat->nat_phnext[1] = NULL; 899 fr = nat->nat_fr; 900 nat->nat_fr = NULL; 901 aps = nat->nat_aps; 902 nat->nat_aps = NULL; 903 in = nat->nat_ptr; 904 nat->nat_ptr = NULL; 905 nat->nat_hm = NULL; 906 nat->nat_data = NULL; 907 908 /* 909 * Restore the rule associated with this nat session 910 */ 911 if (in) { 912 KMALLOC(in, ipnat_t *); 913 if (in == NULL) { 914 error = ENOMEM; 915 goto junkput; 916 } 917 nat->nat_ptr = in; 918 bcopy((char *)&ipn.ipn_ipnat, (char *)in, sizeof(*in)); 919 in->in_use = 1; 920 in->in_flags |= IPN_DELETE; 921 in->in_next = NULL; 922 in->in_rnext = NULL; 923 in->in_prnext = NULL; 924 in->in_mnext = NULL; 925 in->in_pmnext = NULL; 926 in->in_ifp = GETUNIT(in->in_ifname, 4); 927 if (in->in_plabel[0] != '\0') { 928 in->in_apr = appr_match(in->in_p, in->in_plabel); 929 } 930 } 931 932 /* 933 * Restore ap_session_t structure. Include the private data allocated 934 * if it was there. 935 */ 936 if (aps) { 937 KMALLOC(aps, ap_session_t *); 938 if (aps == NULL) { 939 error = ENOMEM; 940 goto junkput; 941 } 942 nat->nat_aps = aps; 943 aps->aps_next = ap_sess_list; 944 ap_sess_list = aps; 945 bcopy(ipnn->ipn_data, (char *)aps, sizeof(*aps)); 946 if (in) 947 aps->aps_apr = in->in_apr; 948 if (aps->aps_psiz) { 949 KMALLOCS(aps->aps_data, void *, aps->aps_psiz); 950 if (aps->aps_data == NULL) { 951 error = ENOMEM; 952 goto junkput; 953 } 954 bcopy(ipnn->ipn_data + sizeof(*aps), aps->aps_data, 955 aps->aps_psiz); 956 } else { 957 aps->aps_psiz = 0; 958 aps->aps_data = NULL; 959 } 960 } 961 962 /* 963 * If there was a filtering rule associated with this entry then 964 * build up a new one. 965 */ 966 if (fr != NULL) { 967 if (nat->nat_flags & FI_NEWFR) { 968 KMALLOC(fr, frentry_t *); 969 nat->nat_fr = fr; 970 if (fr == NULL) { 971 error = ENOMEM; 972 goto junkput; 973 } 974 bcopy((char *)&ipn.ipn_fr, (char *)fr, sizeof(*fr)); 975 ipn.ipn_nat.nat_fr = fr; 976 error = IWCOPY((caddr_t)&ipn, ipnp, sizeof(ipn)); 977 if (error) { 978 error = EFAULT; 979 goto junkput; 980 } 981 } else { 982 for (n = nat_instances; n; n = n->nat_next) 983 if (n->nat_fr == fr) 984 break; 985 if (!n) { 986 error = ESRCH; 987 goto junkput; 988 } 989 } 990 } 991 992 if (ipnn) 993 KFREES(ipnn, sizeof(ipn) + ipn.ipn_dsize); 994 nat_insert(nat); 995 return 0; 996junkput: 997 if (ipnn) 998 KFREES(ipnn, sizeof(ipn) + ipn.ipn_dsize); 999 if (nat) 1000 nat_delete(nat); 1001 return error; 1002} 1003 1004 1005/* 1006 * Delete a nat entry from the various lists and table. 1007 */ 1008static void nat_delete(natd) 1009struct nat *natd; 1010{ 1011 struct ipnat *ipn; 1012 1013 if (natd->nat_flags & FI_WILDP) 1014 nat_stats.ns_wilds--; 1015 if (natd->nat_hnext[0]) 1016 natd->nat_hnext[0]->nat_phnext[0] = natd->nat_phnext[0]; 1017 *natd->nat_phnext[0] = natd->nat_hnext[0]; 1018 if (natd->nat_hnext[1]) 1019 natd->nat_hnext[1]->nat_phnext[1] = natd->nat_phnext[1]; 1020 *natd->nat_phnext[1] = natd->nat_hnext[1]; 1021 1022 if (natd->nat_fr != NULL) { 1023 ATOMIC_DEC32(natd->nat_fr->fr_ref); 1024 } 1025 1026 if (natd->nat_hm != NULL) 1027 nat_hostmapdel(natd->nat_hm); 1028 1029 /* 1030 * If there is an active reference from the nat entry to its parent 1031 * rule, decrement the rule's reference count and free it too if no 1032 * longer being used. 1033 */ 1034 ipn = natd->nat_ptr; 1035 if (ipn != NULL) { 1036 ipn->in_space++; 1037 ipn->in_use--; 1038 if (!ipn->in_use && (ipn->in_flags & IPN_DELETE)) { 1039 if (ipn->in_apr) 1040 appr_free(ipn->in_apr); 1041 KFREE(ipn); 1042 nat_stats.ns_rules--; 1043 } 1044 } 1045 1046 MUTEX_DESTROY(&natd->nat_lock); 1047 /* 1048 * If there's a fragment table entry too for this nat entry, then 1049 * dereference that as well. 1050 */ 1051 ipfr_forget((void *)natd); 1052 aps_free(natd->nat_aps); 1053 nat_stats.ns_inuse--; 1054 KFREE(natd); 1055} 1056 1057 1058/* 1059 * nat_flushtable - clear the NAT table of all mapping entries. 1060 */ 1061static int nat_flushtable() 1062{ 1063 register nat_t *nat, **natp; 1064 register int j = 0; 1065 1066 /* 1067 * ALL NAT mappings deleted, so lets just make the deletions 1068 * quicker. 1069 */ 1070 if (nat_table[0] != NULL) 1071 bzero((char *)nat_table[0], 1072 sizeof(nat_table[0]) * ipf_nattable_sz); 1073 if (nat_table[1] != NULL) 1074 bzero((char *)nat_table[1], 1075 sizeof(nat_table[1]) * ipf_nattable_sz); 1076 1077 for (natp = &nat_instances; (nat = *natp); ) { 1078 *natp = nat->nat_next; 1079#ifdef IPFILTER_LOG 1080 nat_log(nat, NL_FLUSH); 1081#endif 1082 nat_delete(nat); 1083 j++; 1084 } 1085 nat_stats.ns_inuse = 0; 1086 return j; 1087} 1088 1089 1090/* 1091 * nat_clearlist - delete all rules in the active NAT mapping list. 1092 */ 1093static int nat_clearlist() 1094{ 1095 register ipnat_t *n, **np = &nat_list; 1096 int i = 0; 1097 1098 if (nat_rules != NULL) 1099 bzero((char *)nat_rules, sizeof(*nat_rules) * ipf_natrules_sz); 1100 if (rdr_rules != NULL) 1101 bzero((char *)rdr_rules, sizeof(*rdr_rules) * ipf_rdrrules_sz); 1102 1103 while ((n = *np)) { 1104 *np = n->in_next; 1105 if (!n->in_use) { 1106 if (n->in_apr) 1107 appr_free(n->in_apr); 1108 KFREE(n); 1109 nat_stats.ns_rules--; 1110 } else { 1111 n->in_flags |= IPN_DELETE; 1112 n->in_next = NULL; 1113 } 1114 i++; 1115 } 1116 nat_masks = 0; 1117 rdr_masks = 0; 1118 return i; 1119} 1120 1121 1122/* 1123 * Create a new NAT table entry. 1124 * NOTE: assumes write lock on ipf_nat has been obtained already. 1125 */ 1126nat_t *nat_new(np, ip, fin, flags, direction) 1127ipnat_t *np; 1128ip_t *ip; 1129fr_info_t *fin; 1130u_int flags; 1131int direction; 1132{ 1133 register u_32_t sum1, sum2, sumd, l; 1134 u_short port = 0, sport = 0, dport = 0, nport = 0; 1135 struct in_addr in, inb; 1136 tcphdr_t *tcp = NULL; 1137 hostmap_t *hm = NULL; 1138 nat_t *nat, *natl; 1139 u_short nflags; 1140#if SOLARIS && defined(_KERNEL) && (SOLARIS2 >= 6) 1141 qif_t *qf = fin->fin_qif; 1142#endif 1143 1144 nflags = flags & np->in_flags; 1145 if (flags & IPN_TCPUDP) { 1146 tcp = (tcphdr_t *)fin->fin_dp; 1147 sport = tcp->th_sport; 1148 dport = tcp->th_dport; 1149 } 1150 1151 /* Give me a new nat */ 1152 KMALLOC(nat, nat_t *); 1153 if (nat == NULL) { 1154 nat_stats.ns_memfail++; 1155 return NULL; 1156 } 1157 1158 bzero((char *)nat, sizeof(*nat)); 1159 nat->nat_flags = flags; 1160 if (flags & FI_WILDP) 1161 nat_stats.ns_wilds++; 1162 /* 1163 * Search the current table for a match. 1164 */ 1165 if (direction == NAT_OUTBOUND) { 1166 /* 1167 * Values at which the search for a free resouce starts. 1168 */ 1169 u_32_t st_ip; 1170 u_short st_port; 1171 1172 /* 1173 * If it's an outbound packet which doesn't match any existing 1174 * record, then create a new port 1175 */ 1176 l = 0; 1177 st_ip = np->in_nip; 1178 st_port = np->in_pnext; 1179 1180 do { 1181 port = 0; 1182 in.s_addr = htonl(np->in_nip); 1183 if (l == 0) { 1184 /* 1185 * Check to see if there is an existing NAT 1186 * setup for this IP address pair. 1187 */ 1188 hm = nat_hostmap(np, ip->ip_src, in); 1189 if (hm != NULL) 1190 in.s_addr = hm->hm_mapip.s_addr; 1191 } else if ((l == 1) && (hm != NULL)) { 1192 nat_hostmapdel(hm); 1193 hm = NULL; 1194 } 1195 in.s_addr = ntohl(in.s_addr); 1196 1197 nat->nat_hm = hm; 1198 1199 if ((np->in_outmsk == 0xffffffff) && 1200 (np->in_pnext == 0)) { 1201 if (l > 0) 1202 goto badnat; 1203 } 1204 1205 if (np->in_redir & NAT_MAPBLK) { 1206 if ((l >= np->in_ppip) || ((l > 0) && 1207 !(flags & IPN_TCPUDP))) 1208 goto badnat; 1209 /* 1210 * map-block - Calculate destination address. 1211 */ 1212 in.s_addr = ntohl(ip->ip_src.s_addr); 1213 in.s_addr &= ntohl(~np->in_inmsk); 1214 inb.s_addr = in.s_addr; 1215 in.s_addr /= np->in_ippip; 1216 in.s_addr &= ntohl(~np->in_outmsk); 1217 in.s_addr += ntohl(np->in_outip); 1218 /* 1219 * Calculate destination port. 1220 */ 1221 if ((flags & IPN_TCPUDP) && 1222 (np->in_ppip != 0)) { 1223 port = ntohs(sport) + l; 1224 port %= np->in_ppip; 1225 port += np->in_ppip * 1226 (inb.s_addr % np->in_ippip); 1227 port += MAPBLK_MINPORT; 1228 port = htons(port); 1229 } 1230 } else if (!np->in_outip && 1231 (np->in_outmsk == 0xffffffff)) { 1232 /* 1233 * 0/32 - use the interface's IP address. 1234 */ 1235 if ((l > 0) || 1236 fr_ifpaddr(4, fin->fin_ifp, &in) == -1) 1237 goto badnat; 1238 in.s_addr = ntohl(in.s_addr); 1239 } else if (!np->in_outip && !np->in_outmsk) { 1240 /* 1241 * 0/0 - use the original source address/port. 1242 */ 1243 if (l > 0) 1244 goto badnat; 1245 in.s_addr = ntohl(ip->ip_src.s_addr); 1246 } else if ((np->in_outmsk != 0xffffffff) && 1247 (np->in_pnext == 0) && 1248 ((l > 0) || (hm == NULL))) 1249 np->in_nip++; 1250 natl = NULL; 1251 1252 if ((nflags & IPN_TCPUDP) && 1253 ((np->in_redir & NAT_MAPBLK) == 0) && 1254 (np->in_flags & IPN_AUTOPORTMAP)) { 1255 if ((l > 0) && (l % np->in_ppip == 0)) { 1256 if (l > np->in_space) { 1257 goto badnat; 1258 } else if ((l > np->in_ppip) && 1259 np->in_outmsk != 0xffffffff) 1260 np->in_nip++; 1261 } 1262 if (np->in_ppip != 0) { 1263 port = ntohs(sport); 1264 port += (l % np->in_ppip); 1265 port %= np->in_ppip; 1266 port += np->in_ppip * 1267 (ntohl(ip->ip_src.s_addr) % 1268 np->in_ippip); 1269 port += MAPBLK_MINPORT; 1270 port = htons(port); 1271 } 1272 } else if (((np->in_redir & NAT_MAPBLK) == 0) && 1273 (nflags & IPN_TCPUDP) && 1274 (np->in_pnext != 0)) { 1275 port = htons(np->in_pnext++); 1276 if (np->in_pnext > ntohs(np->in_pmax)) { 1277 np->in_pnext = ntohs(np->in_pmin); 1278 if (np->in_outmsk != 0xffffffff) 1279 np->in_nip++; 1280 } 1281 } 1282 1283 if (np->in_flags & IPN_IPRANGE) { 1284 if (np->in_nip > ntohl(np->in_outmsk)) 1285 np->in_nip = ntohl(np->in_outip); 1286 } else { 1287 if ((np->in_outmsk != 0xffffffff) && 1288 ((np->in_nip + 1) & ntohl(np->in_outmsk)) > 1289 ntohl(np->in_outip)) 1290 np->in_nip = ntohl(np->in_outip) + 1; 1291 } 1292 1293 if (!port && (flags & IPN_TCPUDP)) 1294 port = sport; 1295 1296 /* 1297 * Here we do a lookup of the connection as seen from 1298 * the outside. If an IP# pair already exists, try 1299 * again. So if you have A->B becomes C->B, you can 1300 * also have D->E become C->E but not D->B causing 1301 * another C->B. Also take protocol and ports into 1302 * account when determining whether a pre-existing 1303 * NAT setup will cause an external conflict where 1304 * this is appropriate. 1305 */ 1306 inb.s_addr = htonl(in.s_addr); 1307 natl = nat_inlookup(fin->fin_ifp, flags & ~FI_WILDP, 1308 (u_int)ip->ip_p, ip->ip_dst, inb, 1309 (port << 16) | dport, 1); 1310 1311 /* 1312 * Has the search wrapped around and come back to the 1313 * start ? 1314 */ 1315 if ((natl != NULL) && 1316 (np->in_pnext != 0) && (st_port == np->in_pnext) && 1317 (np->in_nip != 0) && (st_ip == np->in_nip)) 1318 goto badnat; 1319 l++; 1320 } while (natl != NULL); 1321 1322 if (np->in_space > 0) 1323 np->in_space--; 1324 1325 /* Setup the NAT table */ 1326 nat->nat_inip = ip->ip_src; 1327 nat->nat_outip.s_addr = htonl(in.s_addr); 1328 nat->nat_oip = ip->ip_dst; 1329 if (nat->nat_hm == NULL) 1330 nat->nat_hm = nat_hostmap(np, ip->ip_src, 1331 nat->nat_outip); 1332 1333 sum1 = LONG_SUM(ntohl(ip->ip_src.s_addr)) + ntohs(sport); 1334 sum2 = LONG_SUM(in.s_addr) + ntohs(port); 1335 1336 if (flags & IPN_TCPUDP) { 1337 nat->nat_inport = sport; 1338 nat->nat_outport = port; /* sport */ 1339 nat->nat_oport = dport; 1340 } 1341 } else { 1342 /* 1343 * Otherwise, it's an inbound packet. Most likely, we don't 1344 * want to rewrite source ports and source addresses. Instead, 1345 * we want to rewrite to a fixed internal address and fixed 1346 * internal port. 1347 */ 1348 if (np->in_flags & IPN_SPLIT) { 1349 in.s_addr = np->in_nip; 1350 if (np->in_inip == htonl(in.s_addr)) 1351 np->in_nip = ntohl(np->in_inmsk); 1352 else { 1353 np->in_nip = ntohl(np->in_inip); 1354 if (np->in_flags & IPN_ROUNDR) { 1355 nat_delrdr(np); 1356 nat_addrdr(np); 1357 } 1358 } 1359 } else { 1360 in.s_addr = ntohl(np->in_inip); 1361 if (np->in_flags & IPN_ROUNDR) { 1362 nat_delrdr(np); 1363 nat_addrdr(np); 1364 } 1365 } 1366 if (!np->in_pnext) 1367 nport = dport; 1368 else { 1369 /* 1370 * Whilst not optimized for the case where 1371 * pmin == pmax, the gain is not significant. 1372 */ 1373 nport = ntohs(dport) - ntohs(np->in_pmin) + 1374 ntohs(np->in_pnext); 1375 nport = htons(nport); 1376 } 1377 1378 /* 1379 * When the redirect-to address is set to 0.0.0.0, just 1380 * assume a blank `forwarding' of the packet. We don't 1381 * setup any translation for this either. 1382 */ 1383 if (in.s_addr == 0) { 1384 if (nport == dport) 1385 goto badnat; 1386 in.s_addr = ntohl(ip->ip_dst.s_addr); 1387 } 1388 1389 nat->nat_inip.s_addr = htonl(in.s_addr); 1390 nat->nat_outip = ip->ip_dst; 1391 nat->nat_oip = ip->ip_src; 1392 1393 sum1 = LONG_SUM(ntohl(ip->ip_dst.s_addr)) + ntohs(dport); 1394 sum2 = LONG_SUM(in.s_addr) + ntohs(nport); 1395 1396 if (flags & IPN_TCPUDP) { 1397 nat->nat_inport = nport; 1398 nat->nat_outport = dport; 1399 nat->nat_oport = sport; 1400 } 1401 } 1402 1403 CALC_SUMD(sum1, sum2, sumd); 1404 nat->nat_sumd[0] = (sumd & 0xffff) + (sumd >> 16); 1405#if SOLARIS && defined(_KERNEL) && (SOLARIS2 >= 6) 1406 if ((flags & IPN_TCPUDP) && dohwcksum && 1407 (qf->qf_ill->ill_ick.ick_magic == ICK_M_CTL_MAGIC)) { 1408 if (direction == NAT_OUTBOUND) 1409 sum1 = LONG_SUM(ntohl(in.s_addr)); 1410 else 1411 sum1 = LONG_SUM(ntohl(ip->ip_src.s_addr)); 1412 sum1 += LONG_SUM(ntohl(ip->ip_dst.s_addr)); 1413 sum1 += IPPROTO_TCP; 1414 sum1 = (sum1 & 0xffff) + (sum1 >> 16); 1415 nat->nat_sumd[1] = NAT_HW_CKSUM|(sum1 & 0xffff); 1416 } else 1417#endif 1418 nat->nat_sumd[1] = nat->nat_sumd[0]; 1419 1420 if ((flags & IPN_TCPUDP) && ((sport != port) || (dport != nport))) { 1421 if (direction == NAT_OUTBOUND) 1422 sum1 = LONG_SUM(ntohl(ip->ip_src.s_addr)); 1423 else 1424 sum1 = LONG_SUM(ntohl(ip->ip_dst.s_addr)); 1425 1426 sum2 = LONG_SUM(in.s_addr); 1427 1428 CALC_SUMD(sum1, sum2, sumd); 1429 nat->nat_ipsumd = (sumd & 0xffff) + (sumd >> 16); 1430 } else 1431 nat->nat_ipsumd = nat->nat_sumd[0]; 1432 1433 in.s_addr = htonl(in.s_addr); 1434 1435#ifdef _KERNEL 1436 strncpy(nat->nat_ifname, IFNAME(fin->fin_ifp), IFNAMSIZ); 1437#endif 1438 nat_insert(nat); 1439 1440 nat->nat_dir = direction; 1441 nat->nat_ifp = fin->fin_ifp; 1442 nat->nat_ptr = np; 1443 nat->nat_p = ip->ip_p; 1444 nat->nat_bytes = 0; 1445 nat->nat_pkts = 0; 1446 nat->nat_fr = fin->fin_fr; 1447 if (nat->nat_fr != NULL) { 1448 ATOMIC_INC32(nat->nat_fr->fr_ref); 1449 } 1450 if (direction == NAT_OUTBOUND) { 1451 if (flags & IPN_TCPUDP) 1452 tcp->th_sport = port; 1453 } else { 1454 if (flags & IPN_TCPUDP) 1455 tcp->th_dport = nport; 1456 } 1457 np->in_use++; 1458#ifdef IPFILTER_LOG 1459 nat_log(nat, (u_int)np->in_redir); 1460#endif 1461 return nat; 1462badnat: 1463 nat_stats.ns_badnat++; 1464 if ((hm = nat->nat_hm) != NULL) 1465 nat_hostmapdel(hm); 1466 KFREE(nat); 1467 return NULL; 1468} 1469 1470 1471void nat_insert(nat) 1472nat_t *nat; 1473{ 1474 u_int hv1, hv2; 1475 nat_t **natp; 1476 1477 MUTEX_INIT(&nat->nat_lock, "nat entry lock", NULL); 1478 1479 nat->nat_age = fr_defnatage; 1480 nat->nat_ifname[sizeof(nat->nat_ifname) - 1] = '\0'; 1481 if (nat->nat_ifname[0] !='\0') { 1482 nat->nat_ifp = GETUNIT(nat->nat_ifname, 4); 1483 } 1484 1485 nat->nat_next = nat_instances; 1486 nat_instances = nat; 1487 1488 if (!(nat->nat_flags & (FI_W_SPORT|FI_W_DPORT))) { 1489 hv1 = NAT_HASH_FN(nat->nat_inip.s_addr, nat->nat_inport, 1490 0xffffffff); 1491 hv1 = NAT_HASH_FN(nat->nat_oip.s_addr, hv1 + nat->nat_oport, 1492 ipf_nattable_sz); 1493 hv2 = NAT_HASH_FN(nat->nat_outip.s_addr, nat->nat_outport, 1494 0xffffffff); 1495 hv2 = NAT_HASH_FN(nat->nat_oip.s_addr, hv2 + nat->nat_oport, 1496 ipf_nattable_sz); 1497 } else { 1498 hv1 = NAT_HASH_FN(nat->nat_inip.s_addr, 0, 0xffffffff); 1499 hv1 = NAT_HASH_FN(nat->nat_oip.s_addr, hv1, ipf_nattable_sz); 1500 hv2 = NAT_HASH_FN(nat->nat_outip.s_addr, 0, 0xffffffff); 1501 hv2 = NAT_HASH_FN(nat->nat_oip.s_addr, hv2, ipf_nattable_sz); 1502 } 1503 1504 natp = &nat_table[0][hv1]; 1505 if (*natp) 1506 (*natp)->nat_phnext[0] = &nat->nat_hnext[0]; 1507 nat->nat_phnext[0] = natp; 1508 nat->nat_hnext[0] = *natp; 1509 *natp = nat; 1510 1511 natp = &nat_table[1][hv2]; 1512 if (*natp) 1513 (*natp)->nat_phnext[1] = &nat->nat_hnext[1]; 1514 nat->nat_phnext[1] = natp; 1515 nat->nat_hnext[1] = *natp; 1516 *natp = nat; 1517 1518 nat_stats.ns_added++; 1519 nat_stats.ns_inuse++; 1520} 1521 1522 1523nat_t *nat_icmplookup(ip, fin, dir) 1524ip_t *ip; 1525fr_info_t *fin; 1526int dir; 1527{ 1528 icmphdr_t *icmp; 1529 tcphdr_t *tcp = NULL; 1530 ip_t *oip; 1531 int flags = 0, type, minlen; 1532 1533 icmp = (icmphdr_t *)fin->fin_dp; 1534 /* 1535 * Does it at least have the return (basic) IP header ? 1536 * Only a basic IP header (no options) should be with an ICMP error 1537 * header. 1538 */ 1539 if ((ip->ip_hl != 5) || (ip->ip_len < ICMPERR_MINPKTLEN)) 1540 return NULL; 1541 type = icmp->icmp_type; 1542 /* 1543 * If it's not an error type, then return. 1544 */ 1545 if ((type != ICMP_UNREACH) && (type != ICMP_SOURCEQUENCH) && 1546 (type != ICMP_REDIRECT) && (type != ICMP_TIMXCEED) && 1547 (type != ICMP_PARAMPROB)) 1548 return NULL; 1549 1550 oip = (ip_t *)((char *)fin->fin_dp + 8); 1551 minlen = (oip->ip_hl << 2); 1552 if (minlen < sizeof(ip_t)) 1553 return NULL; 1554 if (ip->ip_len < ICMPERR_IPICMPHLEN + minlen) 1555 return NULL; 1556 /* 1557 * Is the buffer big enough for all of it ? It's the size of the IP 1558 * header claimed in the encapsulated part which is of concern. It 1559 * may be too big to be in this buffer but not so big that it's 1560 * outside the ICMP packet, leading to TCP deref's causing problems. 1561 * This is possible because we don't know how big oip_hl is when we 1562 * do the pullup early in fr_check() and thus can't gaurantee it is 1563 * all here now. 1564 */ 1565#ifdef _KERNEL 1566 { 1567 mb_t *m; 1568 1569# if SOLARIS 1570 m = fin->fin_qfm; 1571 if ((char *)oip + fin->fin_dlen - ICMPERR_ICMPHLEN > (char *)m->b_wptr) 1572 return NULL; 1573# else 1574 m = *(mb_t **)fin->fin_mp; 1575 if ((char *)oip + fin->fin_dlen - ICMPERR_ICMPHLEN > 1576 (char *)ip + m->m_len) 1577 return NULL; 1578# endif 1579 } 1580#endif 1581 1582 if (oip->ip_p == IPPROTO_TCP) 1583 flags = IPN_TCP; 1584 else if (oip->ip_p == IPPROTO_UDP) 1585 flags = IPN_UDP; 1586 if (flags & IPN_TCPUDP) { 1587 minlen += 8; /* + 64bits of data to get ports */ 1588 if (ip->ip_len < ICMPERR_IPICMPHLEN + minlen) 1589 return NULL; 1590 tcp = (tcphdr_t *)((char *)oip + (oip->ip_hl << 2)); 1591 if (dir == NAT_INBOUND) 1592 return nat_inlookup(fin->fin_ifp, flags, 1593 (u_int)oip->ip_p, oip->ip_dst, oip->ip_src, 1594 (tcp->th_sport << 16) | tcp->th_dport, 0); 1595 else 1596 return nat_outlookup(fin->fin_ifp, flags, 1597 (u_int)oip->ip_p, oip->ip_dst, oip->ip_src, 1598 (tcp->th_sport << 16) | tcp->th_dport, 0); 1599 } 1600 if (dir == NAT_INBOUND) 1601 return nat_inlookup(fin->fin_ifp, 0, (u_int)oip->ip_p, 1602 oip->ip_dst, oip->ip_src, 0, 0); 1603 else 1604 return nat_outlookup(fin->fin_ifp, 0, (u_int)oip->ip_p, 1605 oip->ip_dst, oip->ip_src, 0, 0); 1606} 1607 1608 1609/* 1610 * This should *ONLY* be used for incoming packets to make sure a NAT'd ICMP 1611 * packet gets correctly recognised. 1612 */ 1613nat_t *nat_icmp(ip, fin, nflags, dir) 1614ip_t *ip; 1615fr_info_t *fin; 1616u_int *nflags; 1617int dir; 1618{ 1619 u_32_t sum1, sum2, sumd, sumd2 = 0; 1620 struct in_addr in; 1621 icmphdr_t *icmp; 1622 udphdr_t *udp; 1623 nat_t *nat; 1624 ip_t *oip; 1625 int flags = 0; 1626 1627 if ((fin->fin_fl & FI_SHORT) || (fin->fin_off != 0)) 1628 return NULL; 1629 /* 1630 * nat_icmplookup() will return NULL for `defective' packets. 1631 */ 1632 if ((ip->ip_v != 4) || !(nat = nat_icmplookup(ip, fin, dir))) 1633 return NULL; 1634 *nflags = IPN_ICMPERR; 1635 icmp = (icmphdr_t *)fin->fin_dp; 1636 oip = (ip_t *)&icmp->icmp_ip; 1637 if (oip->ip_p == IPPROTO_TCP) 1638 flags = IPN_TCP; 1639 else if (oip->ip_p == IPPROTO_UDP) 1640 flags = IPN_UDP; 1641 udp = (udphdr_t *)((((char *)oip) + (oip->ip_hl << 2))); 1642 /* 1643 * Need to adjust ICMP header to include the real IP#'s and 1644 * port #'s. Only apply a checksum change relative to the 1645 * IP address change as it will be modified again in ip_natout 1646 * for both address and port. Two checksum changes are 1647 * necessary for the two header address changes. Be careful 1648 * to only modify the checksum once for the port # and twice 1649 * for the IP#. 1650 */ 1651 1652 /* 1653 * Step 1 1654 * Fix the IP addresses in the offending IP packet. You also need 1655 * to adjust the IP header checksum of that offending IP packet 1656 * and the ICMP checksum of the ICMP error message itself. 1657 * 1658 * Unfortunately, for UDP and TCP, the IP addresses are also contained 1659 * in the pseudo header that is used to compute the UDP resp. TCP 1660 * checksum. So, we must compensate that as well. Even worse, the 1661 * change in the UDP and TCP checksums require yet another 1662 * adjustment of the ICMP checksum of the ICMP error message. 1663 * 1664 * For the moment we forget about TCP, because that checksum is not 1665 * in the first 8 bytes, so it will not be available in most cases. 1666 */ 1667 1668 if (oip->ip_dst.s_addr == nat->nat_oip.s_addr) { 1669 sum1 = LONG_SUM(ntohl(oip->ip_src.s_addr)); 1670 in = nat->nat_inip; 1671 oip->ip_src = in; 1672 } else { 1673 sum1 = LONG_SUM(ntohl(oip->ip_dst.s_addr)); 1674 in = nat->nat_outip; 1675 oip->ip_dst = in; 1676 } 1677 1678 sum2 = LONG_SUM(ntohl(in.s_addr)); 1679 1680 CALC_SUMD(sum1, sum2, sumd); 1681 1682 if (nat->nat_dir == NAT_OUTBOUND) { 1683 /* 1684 * Fix IP checksum of the offending IP packet to adjust for 1685 * the change in the IP address. 1686 * 1687 * Normally, you would expect that the ICMP checksum of the 1688 * ICMP error message needs to be adjusted as well for the 1689 * IP address change in oip. 1690 * However, this is a NOP, because the ICMP checksum is 1691 * calculated over the complete ICMP packet, which includes the 1692 * changed oip IP addresses and oip->ip_sum. However, these 1693 * two changes cancel each other out (if the delta for 1694 * the IP address is x, then the delta for ip_sum is minus x), 1695 * so no change in the icmp_cksum is necessary. 1696 * 1697 * Be careful that nat_dir refers to the direction of the 1698 * offending IP packet (oip), not to its ICMP response (icmp) 1699 */ 1700 fix_datacksum(&oip->ip_sum, sumd); 1701 1702 /* 1703 * Fix UDP pseudo header checksum to compensate for the 1704 * IP address change. 1705 */ 1706 if (oip->ip_p == IPPROTO_UDP && udp->uh_sum) { 1707 /* 1708 * The UDP checksum is optional, only adjust it 1709 * if it has been set. 1710 */ 1711 sum1 = ntohs(udp->uh_sum); 1712 fix_datacksum(&udp->uh_sum, sumd); 1713 sum2 = ntohs(udp->uh_sum); 1714 1715 /* 1716 * Fix ICMP checksum to compensate the UDP 1717 * checksum adjustment. 1718 */ 1719 CALC_SUMD(sum1, sum2, sumd); 1720 sumd2 = sumd; 1721 } 1722 1723#if 0 1724 /* 1725 * Fix TCP pseudo header checksum to compensate for the 1726 * IP address change. Before we can do the change, we 1727 * must make sure that oip is sufficient large to hold 1728 * the TCP checksum (normally it does not!). 1729 */ 1730 if (oip->ip_p == IPPROTO_TCP) { 1731 1732 } 1733#endif 1734 } else { 1735 1736 /* 1737 * Fix IP checksum of the offending IP packet to adjust for 1738 * the change in the IP address. 1739 * 1740 * Normally, you would expect that the ICMP checksum of the 1741 * ICMP error message needs to be adjusted as well for the 1742 * IP address change in oip. 1743 * However, this is a NOP, because the ICMP checksum is 1744 * calculated over the complete ICMP packet, which includes the 1745 * changed oip IP addresses and oip->ip_sum. However, these 1746 * two changes cancel each other out (if the delta for 1747 * the IP address is x, then the delta for ip_sum is minus x), 1748 * so no change in the icmp_cksum is necessary. 1749 * 1750 * Be careful that nat_dir refers to the direction of the 1751 * offending IP packet (oip), not to its ICMP response (icmp) 1752 */ 1753 fix_datacksum(&oip->ip_sum, sumd); 1754 1755/* XXX FV : without having looked at Solaris source code, it seems unlikely 1756 * that SOLARIS would compensate this in the kernel (a body of an IP packet 1757 * in the data section of an ICMP packet). I have the feeling that this should 1758 * be unconditional, but I'm not in a position to check. 1759 */ 1760#if !SOLARIS && !defined(__sgi) 1761 /* 1762 * Fix UDP pseudo header checksum to compensate for the 1763 * IP address change. 1764 */ 1765 if (oip->ip_p == IPPROTO_UDP && udp->uh_sum) { 1766 /* 1767 * The UDP checksum is optional, only adjust it 1768 * if it has been set 1769 */ 1770 sum1 = ntohs(udp->uh_sum); 1771 fix_datacksum(&udp->uh_sum, sumd); 1772 sum2 = ntohs(udp->uh_sum); 1773 1774 /* 1775 * Fix ICMP checksum to compensate the UDP 1776 * checksum adjustment. 1777 */ 1778 CALC_SUMD(sum1, sum2, sumd); 1779 sumd2 = sumd; 1780 } 1781 1782#if 0 1783 /* 1784 * Fix TCP pseudo header checksum to compensate for the 1785 * IP address change. Before we can do the change, we 1786 * must make sure that oip is sufficient large to hold 1787 * the TCP checksum (normally it does not!). 1788 */ 1789 if (oip->ip_p == IPPROTO_TCP) { 1790 1791 }; 1792#endif 1793 1794#endif 1795 } 1796 1797 if ((flags & IPN_TCPUDP) != 0) { 1798 tcphdr_t *tcp; 1799 1800 /* 1801 * XXX - what if this is bogus hl and we go off the end ? 1802 * In this case, nat_icmpinlookup() will have returned NULL. 1803 */ 1804 tcp = (tcphdr_t *)udp; 1805 1806 /* 1807 * Step 2 : 1808 * For offending TCP/UDP IP packets, translate the ports as 1809 * well, based on the NAT specification. Of course such 1810 * a change must be reflected in the ICMP checksum as well. 1811 * 1812 * Advance notice : Now it becomes complicated :-) 1813 * 1814 * Since the port fields are part of the TCP/UDP checksum 1815 * of the offending IP packet, you need to adjust that checksum 1816 * as well... but, if you change, you must change the icmp 1817 * checksum *again*, to reflect that change. 1818 * 1819 * To further complicate: the TCP checksum is not in the first 1820 * 8 bytes of the offending ip packet, so it most likely is not 1821 * available (we might have to fix that if the encounter a 1822 * device that returns more than 8 data bytes on icmp error) 1823 */ 1824 1825 if (nat->nat_oport == tcp->th_dport) { 1826 if (tcp->th_sport != nat->nat_inport) { 1827 /* 1828 * Fix ICMP checksum to compensate port 1829 * adjustment. 1830 */ 1831 sum1 = ntohs(tcp->th_sport); 1832 sum2 = ntohs(nat->nat_inport); 1833 CALC_SUMD(sum1, sum2, sumd); 1834 sumd2 += sumd; 1835 tcp->th_sport = nat->nat_inport; 1836 1837 /* 1838 * Fix udp checksum to compensate port 1839 * adjustment. NOTE : the offending IP packet 1840 * flows the other direction compared to the 1841 * ICMP message. 1842 * 1843 * The UDP checksum is optional, only adjust 1844 * it if it has been set. 1845 */ 1846 if (oip->ip_p == IPPROTO_UDP && udp->uh_sum) { 1847 1848 sum1 = ntohs(udp->uh_sum); 1849 fix_datacksum(&udp->uh_sum, sumd); 1850 sum2 = ntohs(udp->uh_sum); 1851 1852 /* 1853 * Fix ICMP checksum to 1854 * compensate UDP checksum 1855 * adjustment. 1856 */ 1857 CALC_SUMD(sum1, sum2, sumd); 1858 sumd2 += sumd; 1859 } 1860 } 1861 } else { 1862 if (tcp->th_dport != nat->nat_outport) { 1863 /* 1864 * Fix ICMP checksum to compensate port 1865 * adjustment. 1866 */ 1867 sum1 = ntohs(tcp->th_dport); 1868 sum2 = ntohs(nat->nat_outport); 1869 CALC_SUMD(sum1, sum2, sumd); 1870 sumd2 += sumd; 1871 tcp->th_dport = nat->nat_outport; 1872 1873 /* 1874 * Fix udp checksum to compensate port 1875 * adjustment. NOTE : the offending IP 1876 * packet flows the other direction compared 1877 * to the ICMP message. 1878 * 1879 * The UDP checksum is optional, only adjust 1880 * it if it has been set. 1881 */ 1882 if (oip->ip_p == IPPROTO_UDP && udp->uh_sum) { 1883 1884 sum1 = ntohs(udp->uh_sum); 1885 fix_datacksum(&udp->uh_sum, sumd); 1886 sum2 = ntohs(udp->uh_sum); 1887 1888 /* 1889 * Fix ICMP checksum to compensate 1890 * UDP checksum adjustment. 1891 */ 1892 CALC_SUMD(sum1, sum2, sumd); 1893 sumd2 += sumd; 1894 } 1895 } 1896 } 1897 if (sumd2) { 1898 sumd2 = (sumd2 & 0xffff) + (sumd2 >> 16); 1899 sumd2 = (sumd2 & 0xffff) + (sumd2 >> 16); 1900 if (nat->nat_dir == NAT_OUTBOUND) { 1901 fix_outcksum(fin, &icmp->icmp_cksum, sumd2); 1902 } else { 1903 fix_incksum(fin, &icmp->icmp_cksum, sumd2); 1904 } 1905 } 1906 } 1907 if (oip->ip_p == IPPROTO_ICMP) 1908 nat->nat_age = fr_defnaticmpage; 1909 return nat; 1910} 1911 1912 1913/* 1914 * NB: these lookups don't lock access to the list, it assume it has already 1915 * been done! 1916 */ 1917/* 1918 * Lookup a nat entry based on the mapped destination ip address/port and 1919 * real source address/port. We use this lookup when receiving a packet, 1920 * we're looking for a table entry, based on the destination address. 1921 * NOTE: THE PACKET BEING CHECKED (IF FOUND) HAS A MAPPING ALREADY. 1922 */ 1923nat_t *nat_inlookup(ifp, flags, p, src, mapdst, ports, rw) 1924void *ifp; 1925register u_int flags, p; 1926struct in_addr src , mapdst; 1927u_32_t ports; 1928int rw; 1929{ 1930 register u_short sport, dport; 1931 register nat_t *nat; 1932 register int nflags; 1933 register u_32_t dst; 1934 u_int hv; 1935 1936 dst = mapdst.s_addr; 1937 dport = ports >> 16; 1938 sport = ports & 0xffff; 1939 flags &= IPN_TCPUDP; 1940 1941 hv = NAT_HASH_FN(dst, dport, 0xffffffff); 1942 hv = NAT_HASH_FN(src.s_addr, hv + sport, ipf_nattable_sz); 1943 nat = nat_table[1][hv]; 1944 for (; nat; nat = nat->nat_hnext[1]) { 1945 nflags = nat->nat_flags; 1946 if ((!ifp || ifp == nat->nat_ifp) && 1947 nat->nat_oip.s_addr == src.s_addr && 1948 nat->nat_outip.s_addr == dst && 1949 (((p == 0) && (flags == (nat->nat_flags & IPN_TCPUDP))) 1950 || (p == nat->nat_p)) && (!flags || 1951 (((nat->nat_oport == sport) || (nflags & FI_W_DPORT)) && 1952 ((nat->nat_outport == dport) || (nflags & FI_W_SPORT))))) 1953 return nat; 1954 } 1955 if (!nat_stats.ns_wilds || !(flags & IPN_TCPUDP)) 1956 return NULL; 1957 if (!rw) { 1958 RWLOCK_EXIT(&ipf_nat); 1959 } 1960 hv = NAT_HASH_FN(dst, 0, 0xffffffff); 1961 hv = NAT_HASH_FN(src.s_addr, hv, ipf_nattable_sz); 1962 if (!rw) { 1963 WRITE_ENTER(&ipf_nat); 1964 } 1965 nat = nat_table[1][hv]; 1966 for (; nat; nat = nat->nat_hnext[1]) { 1967 nflags = nat->nat_flags; 1968 if (ifp && ifp != nat->nat_ifp) 1969 continue; 1970 if (!(nflags & IPN_TCPUDP)) 1971 continue; 1972 if (!(nflags & FI_WILDP)) 1973 continue; 1974 if (nat->nat_oip.s_addr != src.s_addr || 1975 nat->nat_outip.s_addr != dst) 1976 continue; 1977 if (((nat->nat_oport == sport) || (nflags & FI_W_DPORT)) && 1978 ((nat->nat_outport == dport) || (nflags & FI_W_SPORT))) { 1979 nat_tabmove(nat, ports); 1980 break; 1981 } 1982 } 1983 if (!rw) { 1984 MUTEX_DOWNGRADE(&ipf_nat); 1985 } 1986 return nat; 1987} 1988 1989 1990/* 1991 * This function is only called for TCP/UDP NAT table entries where the 1992 * original was placed in the table without hashing on the ports and we now 1993 * want to include hashing on port numbers. 1994 */ 1995static void nat_tabmove(nat, ports) 1996nat_t *nat; 1997u_32_t ports; 1998{ 1999 register u_short sport, dport; 2000 nat_t **natp; 2001 u_int hv; 2002 2003 dport = ports >> 16; 2004 sport = ports & 0xffff; 2005 2006 if (nat->nat_oport == dport) { 2007 nat->nat_inport = sport; 2008 nat->nat_outport = sport; 2009 } 2010 2011 /* 2012 * Remove the NAT entry from the old location 2013 */ 2014 if (nat->nat_hnext[0]) 2015 nat->nat_hnext[0]->nat_phnext[0] = nat->nat_phnext[0]; 2016 *nat->nat_phnext[0] = nat->nat_hnext[0]; 2017 2018 if (nat->nat_hnext[1]) 2019 nat->nat_hnext[1]->nat_phnext[1] = nat->nat_phnext[1]; 2020 *nat->nat_phnext[1] = nat->nat_hnext[1]; 2021 2022 /* 2023 * Add into the NAT table in the new position 2024 */ 2025 hv = NAT_HASH_FN(nat->nat_inip.s_addr, sport, 0xffffffff); 2026 hv = NAT_HASH_FN(nat->nat_oip.s_addr, hv + dport, ipf_nattable_sz); 2027 natp = &nat_table[0][hv]; 2028 if (*natp) 2029 (*natp)->nat_phnext[0] = &nat->nat_hnext[0]; 2030 nat->nat_phnext[0] = natp; 2031 nat->nat_hnext[0] = *natp; 2032 *natp = nat; 2033 2034 hv = NAT_HASH_FN(nat->nat_outip.s_addr, sport, 0xffffffff); 2035 hv = NAT_HASH_FN(nat->nat_oip.s_addr, hv + dport, ipf_nattable_sz); 2036 natp = &nat_table[1][hv]; 2037 if (*natp) 2038 (*natp)->nat_phnext[1] = &nat->nat_hnext[1]; 2039 nat->nat_phnext[1] = natp; 2040 nat->nat_hnext[1] = *natp; 2041 *natp = nat; 2042} 2043 2044 2045/* 2046 * Lookup a nat entry based on the source 'real' ip address/port and 2047 * destination address/port. We use this lookup when sending a packet out, 2048 * we're looking for a table entry, based on the source address. 2049 * NOTE: THE PACKET BEING CHECKED (IF FOUND) HAS A MAPPING ALREADY. 2050 */ 2051nat_t *nat_outlookup(ifp, flags, p, src, dst, ports, rw) 2052void *ifp; 2053register u_int flags, p; 2054struct in_addr src , dst; 2055u_32_t ports; 2056int rw; 2057{ 2058 register u_short sport, dport; 2059 register nat_t *nat; 2060 register int nflags; 2061 u_32_t srcip; 2062 u_int hv; 2063 2064 sport = ports & 0xffff; 2065 dport = ports >> 16; 2066 flags &= IPN_TCPUDP; 2067 srcip = src.s_addr; 2068 2069 hv = NAT_HASH_FN(srcip, sport, 0xffffffff); 2070 hv = NAT_HASH_FN(dst.s_addr, hv + dport, ipf_nattable_sz); 2071 nat = nat_table[0][hv]; 2072 for (; nat; nat = nat->nat_hnext[0]) { 2073 nflags = nat->nat_flags; 2074 2075 if ((!ifp || ifp == nat->nat_ifp) && 2076 nat->nat_inip.s_addr == srcip && 2077 nat->nat_oip.s_addr == dst.s_addr && 2078 (((p == 0) && (flags == (nflags & IPN_TCPUDP))) 2079 || (p == nat->nat_p)) && (!flags || 2080 ((nat->nat_inport == sport || nflags & FI_W_SPORT) && 2081 (nat->nat_oport == dport || nflags & FI_W_DPORT)))) 2082 return nat; 2083 } 2084 if (!nat_stats.ns_wilds || !(flags & IPN_TCPUDP)) 2085 return NULL; 2086 if (!rw) { 2087 RWLOCK_EXIT(&ipf_nat); 2088 } 2089 hv = NAT_HASH_FN(srcip, 0, ipf_nattable_sz); 2090 hv = NAT_HASH_FN(dst.s_addr, hv, ipf_nattable_sz); 2091 if (!rw) { 2092 WRITE_ENTER(&ipf_nat); 2093 } 2094 nat = nat_table[0][hv]; 2095 for (; nat; nat = nat->nat_hnext[0]) { 2096 nflags = nat->nat_flags; 2097 if (ifp && ifp != nat->nat_ifp) 2098 continue; 2099 if (!(nflags & IPN_TCPUDP)) 2100 continue; 2101 if (!(nflags & FI_WILDP)) 2102 continue; 2103 if ((nat->nat_inip.s_addr != srcip) || 2104 (nat->nat_oip.s_addr != dst.s_addr)) 2105 continue; 2106 if (((nat->nat_inport == sport) || (nflags & FI_W_SPORT)) && 2107 ((nat->nat_oport == dport) || (nflags & FI_W_DPORT))) { 2108 nat_tabmove(nat, ports); 2109 break; 2110 } 2111 } 2112 if (!rw) { 2113 MUTEX_DOWNGRADE(&ipf_nat); 2114 } 2115 return nat; 2116} 2117 2118 2119/* 2120 * Lookup the NAT tables to search for a matching redirect 2121 */ 2122nat_t *nat_lookupredir(np) 2123register natlookup_t *np; 2124{ 2125 u_32_t ports; 2126 nat_t *nat; 2127 2128 ports = (np->nl_outport << 16) | np->nl_inport; 2129 /* 2130 * If nl_inip is non null, this is a lookup based on the real 2131 * ip address. Else, we use the fake. 2132 */ 2133 if ((nat = nat_outlookup(NULL, np->nl_flags, 0, np->nl_inip, 2134 np->nl_outip, ports, 0))) { 2135 np->nl_realip = nat->nat_outip; 2136 np->nl_realport = nat->nat_outport; 2137 } 2138 return nat; 2139} 2140 2141 2142static int nat_match(fin, np, ip) 2143fr_info_t *fin; 2144ipnat_t *np; 2145ip_t *ip; 2146{ 2147 frtuc_t *ft; 2148 2149 if (ip->ip_v != 4) 2150 return 0; 2151 2152 if (np->in_p && ip->ip_p != np->in_p) 2153 return 0; 2154 if (fin->fin_out) { 2155 if (!(np->in_redir & (NAT_MAP|NAT_MAPBLK))) 2156 return 0; 2157 if (((fin->fin_fi.fi_saddr & np->in_inmsk) != np->in_inip) 2158 ^ ((np->in_flags & IPN_NOTSRC) != 0)) 2159 return 0; 2160 if (((fin->fin_fi.fi_daddr & np->in_srcmsk) != np->in_srcip) 2161 ^ ((np->in_flags & IPN_NOTDST) != 0)) 2162 return 0; 2163 } else { 2164 if (!(np->in_redir & NAT_REDIRECT)) 2165 return 0; 2166 if (((fin->fin_fi.fi_saddr & np->in_srcmsk) != np->in_srcip) 2167 ^ ((np->in_flags & IPN_NOTSRC) != 0)) 2168 return 0; 2169 if (((fin->fin_fi.fi_daddr & np->in_outmsk) != np->in_outip) 2170 ^ ((np->in_flags & IPN_NOTDST) != 0)) 2171 return 0; 2172 } 2173 2174 ft = &np->in_tuc; 2175 if (!(fin->fin_fl & FI_TCPUDP) || 2176 (fin->fin_fl & FI_SHORT) || (fin->fin_off != 0)) { 2177 if (ft->ftu_scmp || ft->ftu_dcmp) 2178 return 0; 2179 return 1; 2180 } 2181 2182 return fr_tcpudpchk(ft, fin); 2183} 2184 2185 2186/* 2187 * Packets going out on the external interface go through this. 2188 * Here, the source address requires alteration, if anything. 2189 */ 2190int ip_natout(ip, fin) 2191ip_t *ip; 2192fr_info_t *fin; 2193{ 2194 register ipnat_t *np = NULL; 2195 register u_32_t ipa; 2196 tcphdr_t *tcp = NULL; 2197 u_short sport = 0, dport = 0, *csump = NULL; 2198 int natadd = 1, i, icmpset = 1; 2199 u_int nflags = 0, hv, msk; 2200 struct ifnet *ifp; 2201 frentry_t *fr; 2202 u_32_t iph; 2203 nat_t *nat; 2204 2205 if (nat_list == NULL || (fr_nat_lock)) 2206 return 0; 2207 2208 if ((fr = fin->fin_fr) && !(fr->fr_flags & FR_DUP) && 2209 fr->fr_tif.fd_ifp && fr->fr_tif.fd_ifp != (void *)-1) 2210 ifp = fr->fr_tif.fd_ifp; 2211 else 2212 ifp = fin->fin_ifp; 2213 2214 if ((fin->fin_off == 0) && !(fin->fin_fl & FI_SHORT)) { 2215 if (ip->ip_p == IPPROTO_TCP) 2216 nflags = IPN_TCP; 2217 else if (ip->ip_p == IPPROTO_UDP) 2218 nflags = IPN_UDP; 2219 if ((nflags & IPN_TCPUDP)) { 2220 tcp = (tcphdr_t *)fin->fin_dp; 2221 sport = tcp->th_sport; 2222 dport = tcp->th_dport; 2223 } 2224 } 2225 2226 ipa = ip->ip_src.s_addr; 2227 2228 READ_ENTER(&ipf_nat); 2229 2230 if ((ip->ip_p == IPPROTO_ICMP) && 2231 (nat = nat_icmp(ip, fin, &nflags, NAT_OUTBOUND))) 2232 icmpset = 1; 2233 else if ((fin->fin_fl & FI_FRAG) && 2234 (nat = ipfr_nat_knownfrag(ip, fin))) 2235 natadd = 0; 2236 else if ((nat = nat_outlookup(ifp, nflags, (u_int)ip->ip_p, 2237 ip->ip_src, ip->ip_dst, 2238 (dport << 16) | sport, 0))) { 2239 nflags = nat->nat_flags; 2240 if ((nflags & (FI_W_SPORT|FI_W_DPORT)) != 0) { 2241 if ((nflags & FI_W_SPORT) && 2242 (nat->nat_inport != sport)) 2243 nat->nat_inport = sport; 2244 else if ((nflags & FI_W_DPORT) && 2245 (nat->nat_oport != dport)) 2246 nat->nat_oport = dport; 2247 if (nat->nat_outport == 0) 2248 nat->nat_outport = sport; 2249 nat->nat_flags &= ~(FI_W_DPORT|FI_W_SPORT); 2250 nflags = nat->nat_flags; 2251 nat_stats.ns_wilds--; 2252 } 2253 } else { 2254 RWLOCK_EXIT(&ipf_nat); 2255 WRITE_ENTER(&ipf_nat); 2256 /* 2257 * If there is no current entry in the nat table for this IP#, 2258 * create one for it (if there is a matching rule). 2259 */ 2260 msk = 0xffffffff; 2261 i = 32; 2262maskloop: 2263 iph = ipa & htonl(msk); 2264 hv = NAT_HASH_FN(iph, 0, ipf_natrules_sz); 2265 for (np = nat_rules[hv]; np; np = np->in_mnext) 2266 { 2267 if (np->in_ifp && (np->in_ifp != ifp)) 2268 continue; 2269 if ((np->in_flags & IPN_RF) && 2270 !(np->in_flags & nflags)) 2271 continue; 2272 if (np->in_flags & IPN_FILTER) { 2273 if (!nat_match(fin, np, ip)) 2274 continue; 2275 } else if ((ipa & np->in_inmsk) != np->in_inip) 2276 continue; 2277 if (np->in_redir & (NAT_MAP|NAT_MAPBLK)) { 2278 if (*np->in_plabel && !appr_ok(ip, tcp, np)) 2279 continue; 2280 /* 2281 * If it's a redirection, then we don't want to 2282 * create new outgoing port stuff. 2283 * Redirections are only for incoming 2284 * connections. 2285 */ 2286 if (!(np->in_redir & (NAT_MAP|NAT_MAPBLK))) 2287 continue; 2288 if ((nat = nat_new(np, ip, fin, (u_int)nflags, 2289 NAT_OUTBOUND))) { 2290 np->in_hits++; 2291 break; 2292 } 2293 } 2294 } 2295 if ((np == NULL) && (i > 0)) { 2296 do { 2297 i--; 2298 msk <<= 1; 2299 } while ((i >= 0) && ((nat_masks & (1 << i)) == 0)); 2300 if (i >= 0) 2301 goto maskloop; 2302 } 2303 MUTEX_DOWNGRADE(&ipf_nat); 2304 } 2305 2306 /* 2307 * NOTE: ipf_nat must now only be held as a read lock 2308 */ 2309 if (nat) { 2310 np = nat->nat_ptr; 2311 if (natadd && (fin->fin_fl & FI_FRAG) && np) 2312 ipfr_nat_newfrag(ip, fin, 0, nat); 2313 MUTEX_ENTER(&nat->nat_lock); 2314 nat->nat_age = fr_defnatage; 2315 nat->nat_bytes += ip->ip_len; 2316 nat->nat_pkts++; 2317 MUTEX_EXIT(&nat->nat_lock); 2318 2319 /* 2320 * Fix up checksums, not by recalculating them, but 2321 * simply computing adjustments. 2322 */ 2323 if (nflags == IPN_ICMPERR) { 2324 u_32_t s1, s2, sumd; 2325 2326 s1 = LONG_SUM(ntohl(ip->ip_src.s_addr)); 2327 s2 = LONG_SUM(ntohl(nat->nat_outip.s_addr)); 2328 CALC_SUMD(s1, s2, sumd); 2329 2330 if (nat->nat_dir == NAT_OUTBOUND) 2331 fix_incksum(fin, &ip->ip_sum, sumd); 2332 else 2333 fix_outcksum(fin, &ip->ip_sum, sumd); 2334 } 2335#if SOLARIS || defined(__sgi) 2336 else { 2337 if (nat->nat_dir == NAT_OUTBOUND) 2338 fix_outcksum(fin, &ip->ip_sum, nat->nat_ipsumd); 2339 else 2340 fix_incksum(fin, &ip->ip_sum, nat->nat_ipsumd); 2341 } 2342#endif 2343 ip->ip_src = nat->nat_outip; 2344 2345 if ((fin->fin_off == 0) && !(fin->fin_fl & FI_SHORT)) { 2346 2347 if ((nat->nat_outport != 0) && (nflags & IPN_TCPUDP)) { 2348 tcp->th_sport = nat->nat_outport; 2349 fin->fin_data[0] = ntohs(tcp->th_sport); 2350 } 2351 2352 if (ip->ip_p == IPPROTO_TCP) { 2353 csump = &tcp->th_sum; 2354 MUTEX_ENTER(&nat->nat_lock); 2355 fr_tcp_age(&nat->nat_age, 2356 nat->nat_tcpstate, fin, 1); 2357 if (nat->nat_age < fr_defnaticmpage) 2358 nat->nat_age = fr_defnaticmpage; 2359#ifdef LARGE_NAT 2360 else if (nat->nat_age > fr_defnatage) 2361 nat->nat_age = fr_defnatage; 2362#endif 2363 /* 2364 * Increase this because we may have 2365 * "keep state" following this too and 2366 * packet storms can occur if this is 2367 * removed too quickly. 2368 */ 2369 if (nat->nat_age == fr_tcpclosed) 2370 nat->nat_age = fr_tcplastack; 2371 MUTEX_EXIT(&nat->nat_lock); 2372 } else if (ip->ip_p == IPPROTO_UDP) { 2373 udphdr_t *udp = (udphdr_t *)tcp; 2374 2375 if (udp->uh_sum) 2376 csump = &udp->uh_sum; 2377 } else if (ip->ip_p == IPPROTO_ICMP) { 2378 if (!icmpset) 2379 nat->nat_age = fr_defnaticmpage; 2380 } 2381 2382 if (csump) { 2383 if (nat->nat_dir == NAT_OUTBOUND) 2384 fix_outcksum(fin, csump, nat->nat_sumd[1]); 2385 else 2386 fix_incksum(fin, csump, nat->nat_sumd[1]); 2387 } 2388 } 2389 2390 if ((np->in_apr != NULL) && (np->in_dport == 0 || 2391 (tcp != NULL && dport == np->in_dport))) { 2392 i = appr_check(ip, fin, nat); 2393 if (i == 0) 2394 i = 1; 2395 } else 2396 i = 1; 2397 ATOMIC_INCL(nat_stats.ns_mapped[1]); 2398 RWLOCK_EXIT(&ipf_nat); /* READ */ 2399 return i; 2400 } 2401 RWLOCK_EXIT(&ipf_nat); /* READ/WRITE */ 2402 return 0; 2403} 2404 2405 2406/* 2407 * Packets coming in from the external interface go through this. 2408 * Here, the destination address requires alteration, if anything. 2409 */ 2410int ip_natin(ip, fin) 2411ip_t *ip; 2412fr_info_t *fin; 2413{ 2414 register struct in_addr src; 2415 register struct in_addr in; 2416 register ipnat_t *np; 2417 u_short sport = 0, dport = 0, *csump = NULL; 2418 u_int nflags = 0, natadd = 1, hv, msk; 2419 struct ifnet *ifp = fin->fin_ifp; 2420 tcphdr_t *tcp = NULL; 2421 int i, icmpset = 0; 2422 nat_t *nat; 2423 u_32_t iph; 2424 2425 if ((nat_list == NULL) || (ip->ip_v != 4) || (fr_nat_lock)) 2426 return 0; 2427 2428 if ((fin->fin_off == 0) && !(fin->fin_fl & FI_SHORT)) { 2429 if (ip->ip_p == IPPROTO_TCP) 2430 nflags = IPN_TCP; 2431 else if (ip->ip_p == IPPROTO_UDP) 2432 nflags = IPN_UDP; 2433 if ((nflags & IPN_TCPUDP)) { 2434 tcp = (tcphdr_t *)fin->fin_dp; 2435 dport = tcp->th_dport; 2436 sport = tcp->th_sport; 2437 } 2438 } 2439 2440 in = ip->ip_dst; 2441 /* make sure the source address is to be redirected */ 2442 src = ip->ip_src; 2443 2444 READ_ENTER(&ipf_nat); 2445 2446 if ((ip->ip_p == IPPROTO_ICMP) && 2447 (nat = nat_icmp(ip, fin, &nflags, NAT_INBOUND))) 2448 icmpset = 1; 2449 else if ((fin->fin_fl & FI_FRAG) && 2450 (nat = ipfr_nat_knownfrag(ip, fin))) 2451 natadd = 0; 2452 else if ((nat = nat_inlookup(fin->fin_ifp, nflags, (u_int)ip->ip_p, 2453 ip->ip_src, in, (dport << 16) | sport, 2454 0))) { 2455 nflags = nat->nat_flags; 2456 if ((nflags & (FI_W_SPORT|FI_W_DPORT)) != 0) { 2457 if ((nat->nat_oport != sport) && (nflags & FI_W_DPORT)) 2458 nat->nat_oport = sport; 2459 else if ((nat->nat_outport != dport) && 2460 (nflags & FI_W_SPORT)) 2461 nat->nat_outport = dport; 2462 nat->nat_flags &= ~(FI_W_SPORT|FI_W_DPORT); 2463 nflags = nat->nat_flags; 2464 nat_stats.ns_wilds--; 2465 } 2466 } else { 2467 RWLOCK_EXIT(&ipf_nat); 2468 WRITE_ENTER(&ipf_nat); 2469 /* 2470 * If there is no current entry in the nat table for this IP#, 2471 * create one for it (if there is a matching rule). 2472 */ 2473 msk = 0xffffffff; 2474 i = 32; 2475maskloop: 2476 iph = in.s_addr & htonl(msk); 2477 hv = NAT_HASH_FN(iph, 0, ipf_rdrrules_sz); 2478 for (np = rdr_rules[hv]; np; np = np->in_rnext) { 2479 if ((np->in_ifp && (np->in_ifp != ifp)) || 2480 (np->in_p && (np->in_p != ip->ip_p)) || 2481 (np->in_flags && !(nflags & np->in_flags))) 2482 continue; 2483 if (np->in_flags & IPN_FILTER) { 2484 if (!nat_match(fin, np, ip)) 2485 continue; 2486 } else if ((in.s_addr & np->in_outmsk) != np->in_outip) 2487 continue; 2488 if ((np->in_redir & NAT_REDIRECT) && 2489 (!np->in_pmin || (np->in_flags & IPN_FILTER) || 2490 ((ntohs(np->in_pmax) >= ntohs(dport)) && 2491 (ntohs(dport) >= ntohs(np->in_pmin))))) 2492 if ((nat = nat_new(np, ip, fin, nflags, 2493 NAT_INBOUND))) { 2494 np->in_hits++; 2495 break; 2496 } 2497 } 2498 2499 if ((np == NULL) && (i > 0)) { 2500 do { 2501 i--; 2502 msk <<= 1; 2503 } while ((i >= 0) && ((rdr_masks & (1 << i)) == 0)); 2504 if (i >= 0) 2505 goto maskloop; 2506 } 2507 MUTEX_DOWNGRADE(&ipf_nat); 2508 } 2509 2510 /* 2511 * NOTE: ipf_nat must now only be held as a read lock 2512 */ 2513 if (nat) { 2514 np = nat->nat_ptr; 2515 fin->fin_fr = nat->nat_fr; 2516 if (natadd && (fin->fin_fl & FI_FRAG) && np) 2517 ipfr_nat_newfrag(ip, fin, 0, nat); 2518 if ((np->in_apr != NULL) && (np->in_dport == 0 || 2519 (tcp != NULL && sport == np->in_dport))) { 2520 i = appr_check(ip, fin, nat); 2521 if (i == -1) { 2522 RWLOCK_EXIT(&ipf_nat); 2523 return i; 2524 } 2525 } 2526 2527 MUTEX_ENTER(&nat->nat_lock); 2528 if (nflags != IPN_ICMPERR) 2529 nat->nat_age = fr_defnatage; 2530 2531 nat->nat_bytes += ip->ip_len; 2532 nat->nat_pkts++; 2533 MUTEX_EXIT(&nat->nat_lock); 2534 ip->ip_dst = nat->nat_inip; 2535 fin->fin_fi.fi_daddr = nat->nat_inip.s_addr; 2536 2537 /* 2538 * Fix up checksums, not by recalculating them, but 2539 * simply computing adjustments. 2540 */ 2541#if SOLARIS || defined(__sgi) 2542 if (nat->nat_dir == NAT_OUTBOUND) 2543 fix_incksum(fin, &ip->ip_sum, nat->nat_ipsumd); 2544 else 2545 fix_outcksum(fin, &ip->ip_sum, nat->nat_ipsumd); 2546#endif 2547 if ((fin->fin_off == 0) && !(fin->fin_fl & FI_SHORT)) { 2548 2549 if ((nat->nat_inport != 0) && (nflags & IPN_TCPUDP)) { 2550 tcp->th_dport = nat->nat_inport; 2551 fin->fin_data[1] = ntohs(tcp->th_dport); 2552 } 2553 2554 if (ip->ip_p == IPPROTO_TCP) { 2555 csump = &tcp->th_sum; 2556 MUTEX_ENTER(&nat->nat_lock); 2557 fr_tcp_age(&nat->nat_age, 2558 nat->nat_tcpstate, fin, 0); 2559 if (nat->nat_age < fr_defnaticmpage) 2560 nat->nat_age = fr_defnaticmpage; 2561#ifdef LARGE_NAT 2562 else if (nat->nat_age > fr_defnatage) 2563 nat->nat_age = fr_defnatage; 2564#endif 2565 /* 2566 * Increase this because we may have 2567 * "keep state" following this too and 2568 * packet storms can occur if this is 2569 * removed too quickly. 2570 */ 2571 if (nat->nat_age == fr_tcpclosed) 2572 nat->nat_age = fr_tcplastack; 2573 MUTEX_EXIT(&nat->nat_lock); 2574 } else if (ip->ip_p == IPPROTO_UDP) { 2575 udphdr_t *udp = (udphdr_t *)tcp; 2576 2577 if (udp->uh_sum) 2578 csump = &udp->uh_sum; 2579 } else if (ip->ip_p == IPPROTO_ICMP) { 2580 if (!icmpset) 2581 nat->nat_age = fr_defnaticmpage; 2582 } 2583 2584 if (csump) { 2585 if (nat->nat_dir == NAT_OUTBOUND) 2586 fix_incksum(fin, csump, nat->nat_sumd[0]); 2587 else 2588 fix_outcksum(fin, csump, nat->nat_sumd[0]); 2589 } 2590 } 2591 ATOMIC_INCL(nat_stats.ns_mapped[0]); 2592 RWLOCK_EXIT(&ipf_nat); /* READ */ 2593 return 1; 2594 } 2595 RWLOCK_EXIT(&ipf_nat); /* READ/WRITE */ 2596 return 0; 2597} 2598 2599 2600/* 2601 * Free all memory used by NAT structures allocated at runtime. 2602 */ 2603void ip_natunload() 2604{ 2605 WRITE_ENTER(&ipf_nat); 2606 (void) nat_clearlist(); 2607 (void) nat_flushtable(); 2608 RWLOCK_EXIT(&ipf_nat); 2609 2610 if (nat_table[0] != NULL) { 2611 KFREES(nat_table[0], sizeof(nat_t *) * ipf_nattable_sz); 2612 nat_table[0] = NULL; 2613 } 2614 if (nat_table[1] != NULL) { 2615 KFREES(nat_table[1], sizeof(nat_t *) * ipf_nattable_sz); 2616 nat_table[1] = NULL; 2617 } 2618 if (nat_rules != NULL) { 2619 KFREES(nat_rules, sizeof(ipnat_t *) * ipf_natrules_sz); 2620 nat_rules = NULL; 2621 } 2622 if (rdr_rules != NULL) { 2623 KFREES(rdr_rules, sizeof(ipnat_t *) * ipf_rdrrules_sz); 2624 rdr_rules = NULL; 2625 } 2626 if (maptable != NULL) { 2627 KFREES(maptable, sizeof(hostmap_t *) * ipf_hostmap_sz); 2628 maptable = NULL; 2629 } 2630} 2631 2632 2633/* 2634 * Slowly expire held state for NAT entries. Timeouts are set in 2635 * expectation of this being called twice per second. 2636 */ 2637void ip_natexpire() 2638{ 2639 register struct nat *nat, **natp; 2640#if defined(_KERNEL) && !SOLARIS 2641 int s; 2642#endif 2643 2644 SPL_NET(s); 2645 WRITE_ENTER(&ipf_nat); 2646 for (natp = &nat_instances; (nat = *natp); ) { 2647 nat->nat_age--; 2648 if (nat->nat_age) { 2649 natp = &nat->nat_next; 2650 continue; 2651 } 2652 *natp = nat->nat_next; 2653#ifdef IPFILTER_LOG 2654 nat_log(nat, NL_EXPIRE); 2655#endif 2656 nat_delete(nat); 2657 nat_stats.ns_expire++; 2658 } 2659 RWLOCK_EXIT(&ipf_nat); 2660 SPL_X(s); 2661} 2662 2663 2664/* 2665 */ 2666void ip_natsync(ifp) 2667void *ifp; 2668{ 2669 register ipnat_t *n; 2670 register nat_t *nat; 2671 register u_32_t sum1, sum2, sumd; 2672 struct in_addr in; 2673 ipnat_t *np; 2674 void *ifp2; 2675#if defined(_KERNEL) && !SOLARIS 2676 int s; 2677#endif 2678 2679 /* 2680 * Change IP addresses for NAT sessions for any protocol except TCP 2681 * since it will break the TCP connection anyway. 2682 */ 2683 SPL_NET(s); 2684 WRITE_ENTER(&ipf_nat); 2685 for (nat = nat_instances; nat; nat = nat->nat_next) 2686 if (((ifp == NULL) || (ifp == nat->nat_ifp)) && 2687 !(nat->nat_flags & IPN_TCP) && (np = nat->nat_ptr) && 2688 (np->in_outmsk == 0xffffffff) && !np->in_nip) { 2689 ifp2 = nat->nat_ifp; 2690 /* 2691 * Change the map-to address to be the same as the 2692 * new one. 2693 */ 2694 sum1 = nat->nat_outip.s_addr; 2695 if (fr_ifpaddr(4, ifp2, &in) != -1) 2696 nat->nat_outip = in; 2697 sum2 = nat->nat_outip.s_addr; 2698 2699 if (sum1 == sum2) 2700 continue; 2701 /* 2702 * Readjust the checksum adjustment to take into 2703 * account the new IP#. 2704 */ 2705 CALC_SUMD(sum1, sum2, sumd); 2706 /* XXX - dont change for TCP when solaris does 2707 * hardware checksumming. 2708 */ 2709 sumd += nat->nat_sumd[0]; 2710 nat->nat_sumd[0] = (sumd & 0xffff) + (sumd >> 16); 2711 nat->nat_sumd[1] = nat->nat_sumd[0]; 2712 } 2713 2714 for (n = nat_list; (n != NULL); n = n->in_next) 2715 if (n->in_ifp == ifp) { 2716 n->in_ifp = (void *)GETUNIT(n->in_ifname, 4); 2717 if (!n->in_ifp) 2718 n->in_ifp = (void *)-1; 2719 } 2720 RWLOCK_EXIT(&ipf_nat); 2721 SPL_X(s); 2722} 2723 2724 2725#ifdef IPFILTER_LOG 2726void nat_log(nat, type) 2727struct nat *nat; 2728u_int type; 2729{ 2730 struct ipnat *np; 2731 struct natlog natl; 2732 void *items[1]; 2733 size_t sizes[1]; 2734 int rulen, types[1]; 2735 2736 natl.nl_inip = nat->nat_inip; 2737 natl.nl_outip = nat->nat_outip; 2738 natl.nl_origip = nat->nat_oip; 2739 natl.nl_bytes = nat->nat_bytes; 2740 natl.nl_pkts = nat->nat_pkts; 2741 natl.nl_origport = nat->nat_oport; 2742 natl.nl_inport = nat->nat_inport; 2743 natl.nl_outport = nat->nat_outport; 2744 natl.nl_p = nat->nat_p; 2745 natl.nl_type = type; 2746 natl.nl_rule = -1; 2747#ifndef LARGE_NAT 2748 if (nat->nat_ptr != NULL) { 2749 for (rulen = 0, np = nat_list; np; np = np->in_next, rulen++) 2750 if (np == nat->nat_ptr) { 2751 natl.nl_rule = rulen; 2752 break; 2753 } 2754 } 2755#endif 2756 items[0] = &natl; 2757 sizes[0] = sizeof(natl); 2758 types[0] = 0; 2759 2760 (void) ipllog(IPL_LOGNAT, NULL, items, sizes, types, 1); 2761} 2762#endif 2763