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