1 /* 2 * Copyright (C) 1995-2003 by Darren Reed. 3 * 4 * See the IPFILTER.LICENCE file for details on licencing. 5 * 6 * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 7 * Use is subject to license terms. 8 */ 9 10 #pragma ident "%Z%%M% %I% %E% SMI" 11 12 #if defined(KERNEL) || defined(_KERNEL) 13 # undef KERNEL 14 # undef _KERNEL 15 # define KERNEL 1 16 # define _KERNEL 1 17 #endif 18 #include <sys/errno.h> 19 #include <sys/types.h> 20 #include <sys/param.h> 21 #include <sys/time.h> 22 #include <sys/file.h> 23 #if defined(__NetBSD__) && (NetBSD >= 199905) && !defined(IPFILTER_LKM) && \ 24 defined(_KERNEL) 25 # include "opt_ipfilter_log.h" 26 #endif 27 #if !defined(_KERNEL) 28 # include <stdio.h> 29 # include <string.h> 30 # include <stdlib.h> 31 # define _KERNEL 32 # ifdef __OpenBSD__ 33 struct file; 34 # endif 35 # include <sys/uio.h> 36 # undef _KERNEL 37 #endif 38 #if defined(_KERNEL) && (__FreeBSD_version >= 220000) 39 # include <sys/filio.h> 40 # include <sys/fcntl.h> 41 #else 42 # include <sys/ioctl.h> 43 #endif 44 #if !defined(AIX) 45 # include <sys/fcntl.h> 46 #endif 47 #if !defined(linux) 48 # include <sys/protosw.h> 49 #endif 50 #include <sys/socket.h> 51 #if defined(_KERNEL) 52 # include <sys/systm.h> 53 # if !defined(__SVR4) && !defined(__svr4__) 54 # include <sys/mbuf.h> 55 # endif 56 #endif 57 #if defined(__SVR4) || defined(__svr4__) 58 # include <sys/filio.h> 59 # include <sys/byteorder.h> 60 # ifdef _KERNEL 61 # include <sys/dditypes.h> 62 # endif 63 # include <sys/stream.h> 64 # include <sys/kmem.h> 65 #endif 66 #if __FreeBSD_version >= 300000 67 # include <sys/queue.h> 68 #endif 69 #include <net/if.h> 70 #if __FreeBSD_version >= 300000 71 # include <net/if_var.h> 72 # if defined(_KERNEL) && !defined(IPFILTER_LKM) 73 # include "opt_ipfilter.h" 74 # endif 75 #endif 76 #ifdef sun 77 # include <net/af.h> 78 #endif 79 #include <net/route.h> 80 #include <netinet/in.h> 81 #include <netinet/in_systm.h> 82 #include <netinet/ip.h> 83 84 #ifdef RFC1825 85 # include <vpn/md5.h> 86 # include <vpn/ipsec.h> 87 extern struct ifnet vpnif; 88 #endif 89 90 #if !defined(linux) 91 # include <netinet/ip_var.h> 92 #endif 93 #include <netinet/tcp.h> 94 #include <netinet/udp.h> 95 #include <netinet/ip_icmp.h> 96 #include "netinet/ip_compat.h" 97 #include <netinet/tcpip.h> 98 #include "netinet/ip_fil.h" 99 #include "netinet/ip_nat.h" 100 #include "netinet/ip_frag.h" 101 #include "netinet/ip_state.h" 102 #include "netinet/ip_proxy.h" 103 #ifdef IPFILTER_SYNC 104 #include "netinet/ip_sync.h" 105 #endif 106 #if (__FreeBSD_version >= 300000) 107 # include <sys/malloc.h> 108 #endif 109 /* END OF INCLUDES */ 110 111 #undef SOCKADDR_IN 112 #define SOCKADDR_IN struct sockaddr_in 113 114 #if !defined(lint) 115 static const char sccsid[] = "@(#)ip_nat.c 1.11 6/5/96 (C) 1995 Darren Reed"; 116 static const char rcsid[] = "@(#)$Id: ip_nat.c,v 2.195.2.42 2005/08/11 19:51:36 darrenr Exp $"; 117 #endif 118 119 120 /* ======================================================================== */ 121 /* How the NAT is organised and works. */ 122 /* */ 123 /* Inside (interface y) NAT Outside (interface x) */ 124 /* -------------------- -+- ------------------------------------- */ 125 /* Packet going | out, processsed by fr_checknatout() for x */ 126 /* ------------> | ------------> */ 127 /* src=10.1.1.1 | src=192.1.1.1 */ 128 /* | */ 129 /* | in, processed by fr_checknatin() for x */ 130 /* <------------ | <------------ */ 131 /* dst=10.1.1.1 | dst=192.1.1.1 */ 132 /* -------------------- -+- ------------------------------------- */ 133 /* fr_checknatout() - changes ip_src and if required, sport */ 134 /* - creates a new mapping, if required. */ 135 /* fr_checknatin() - changes ip_dst and if required, dport */ 136 /* */ 137 /* In the NAT table, internal source is recorded as "in" and externally */ 138 /* seen as "out". */ 139 /* ======================================================================== */ 140 141 142 nat_t **nat_table[2] = { NULL, NULL }, 143 *nat_instances = NULL; 144 ipnat_t *nat_list = NULL; 145 u_int ipf_nattable_max = NAT_TABLE_MAX; 146 u_int ipf_nattable_sz = NAT_TABLE_SZ; 147 u_int ipf_natrules_sz = NAT_SIZE; 148 u_int ipf_rdrrules_sz = RDR_SIZE; 149 u_int ipf_hostmap_sz = HOSTMAP_SIZE; 150 u_int fr_nat_maxbucket = 0, 151 fr_nat_maxbucket_reset = 1; 152 u_32_t nat_masks = 0; 153 u_32_t rdr_masks = 0; 154 ipnat_t **nat_rules = NULL; 155 ipnat_t **rdr_rules = NULL; 156 hostmap_t **maptable = NULL; 157 ipftq_t nat_tqb[IPF_TCP_NSTATES]; 158 ipftq_t nat_udptq; 159 ipftq_t nat_icmptq; 160 ipftq_t nat_iptq; 161 ipftq_t *nat_utqe = NULL; 162 #ifdef IPFILTER_LOG 163 int nat_logging = 1; 164 #else 165 int nat_logging = 0; 166 #endif 167 168 u_long fr_defnatage = DEF_NAT_AGE, 169 fr_defnatipage = 120, /* 60 seconds */ 170 fr_defnaticmpage = 6; /* 3 seconds */ 171 natstat_t nat_stats; 172 int fr_nat_lock = 0; 173 int fr_nat_init = 0; 174 175 static int nat_flushtable __P((void)); 176 static int nat_clearlist __P((void)); 177 static void nat_addnat __P((struct ipnat *)); 178 static void nat_addrdr __P((struct ipnat *)); 179 static void nat_delete __P((struct nat *, int)); 180 static void nat_delrdr __P((struct ipnat *)); 181 static void nat_delnat __P((struct ipnat *)); 182 static int fr_natgetent __P((caddr_t)); 183 static int fr_natgetsz __P((caddr_t)); 184 static int fr_natputent __P((caddr_t, int)); 185 static void nat_tabmove __P((nat_t *)); 186 static int nat_match __P((fr_info_t *, ipnat_t *)); 187 static INLINE int nat_newmap __P((fr_info_t *, nat_t *, natinfo_t *)); 188 static INLINE int nat_newrdr __P((fr_info_t *, nat_t *, natinfo_t *)); 189 static hostmap_t *nat_hostmap __P((ipnat_t *, struct in_addr, 190 struct in_addr, struct in_addr, u_32_t)); 191 static void nat_hostmapdel __P((struct hostmap *)); 192 static INLINE int nat_icmpquerytype4 __P((int)); 193 static int nat_siocaddnat __P((ipnat_t *, ipnat_t **, int)); 194 static void nat_siocdelnat __P((ipnat_t *, ipnat_t **, int)); 195 static INLINE int nat_finalise __P((fr_info_t *, nat_t *, natinfo_t *, 196 tcphdr_t *, nat_t **, int)); 197 static void nat_resolverule __P((ipnat_t *)); 198 static nat_t *fr_natclone __P((fr_info_t *, nat_t *)); 199 static void nat_mssclamp __P((tcphdr_t *, u_32_t, u_short *)); 200 static INLINE int nat_wildok __P((nat_t *, int, int, int, int)); 201 202 203 /* ------------------------------------------------------------------------ */ 204 /* Function: fr_natinit */ 205 /* Returns: int - 0 == success, -1 == failure */ 206 /* Parameters: Nil */ 207 /* */ 208 /* Initialise all of the NAT locks, tables and other structures. */ 209 /* ------------------------------------------------------------------------ */ 210 int fr_natinit() 211 { 212 int i; 213 214 KMALLOCS(nat_table[0], nat_t **, sizeof(nat_t *) * ipf_nattable_sz); 215 if (nat_table[0] != NULL) 216 bzero((char *)nat_table[0], ipf_nattable_sz * sizeof(nat_t *)); 217 else 218 return -1; 219 220 KMALLOCS(nat_table[1], nat_t **, sizeof(nat_t *) * ipf_nattable_sz); 221 if (nat_table[1] != NULL) 222 bzero((char *)nat_table[1], ipf_nattable_sz * sizeof(nat_t *)); 223 else 224 return -2; 225 226 KMALLOCS(nat_rules, ipnat_t **, sizeof(ipnat_t *) * ipf_natrules_sz); 227 if (nat_rules != NULL) 228 bzero((char *)nat_rules, ipf_natrules_sz * sizeof(ipnat_t *)); 229 else 230 return -3; 231 232 KMALLOCS(rdr_rules, ipnat_t **, sizeof(ipnat_t *) * ipf_rdrrules_sz); 233 if (rdr_rules != NULL) 234 bzero((char *)rdr_rules, ipf_rdrrules_sz * sizeof(ipnat_t *)); 235 else 236 return -4; 237 238 KMALLOCS(maptable, hostmap_t **, sizeof(hostmap_t *) * ipf_hostmap_sz); 239 if (maptable != NULL) 240 bzero((char *)maptable, sizeof(hostmap_t *) * ipf_hostmap_sz); 241 else 242 return -5; 243 244 KMALLOCS(nat_stats.ns_bucketlen[0], u_long *, 245 ipf_nattable_sz * sizeof(u_long)); 246 if (nat_stats.ns_bucketlen[0] == NULL) 247 return -6; 248 bzero((char *)nat_stats.ns_bucketlen[0], 249 ipf_nattable_sz * sizeof(u_long)); 250 251 KMALLOCS(nat_stats.ns_bucketlen[1], u_long *, 252 ipf_nattable_sz * sizeof(u_long)); 253 if (nat_stats.ns_bucketlen[1] == NULL) 254 return -7; 255 256 bzero((char *)nat_stats.ns_bucketlen[1], 257 ipf_nattable_sz * sizeof(u_long)); 258 259 if (fr_nat_maxbucket == 0) { 260 for (i = ipf_nattable_sz; i > 0; i >>= 1) 261 fr_nat_maxbucket++; 262 fr_nat_maxbucket *= 2; 263 } 264 265 fr_sttab_init(nat_tqb); 266 /* 267 * Increase this because we may have "keep state" following this too 268 * and packet storms can occur if this is removed too quickly. 269 */ 270 nat_tqb[IPF_TCPS_CLOSED].ifq_ttl = fr_tcplastack; 271 nat_tqb[IPF_TCP_NSTATES - 1].ifq_next = &nat_udptq; 272 nat_udptq.ifq_ttl = fr_defnatage; 273 nat_udptq.ifq_ref = 1; 274 nat_udptq.ifq_head = NULL; 275 nat_udptq.ifq_tail = &nat_udptq.ifq_head; 276 MUTEX_INIT(&nat_udptq.ifq_lock, "nat ipftq udp tab"); 277 nat_udptq.ifq_next = &nat_icmptq; 278 nat_icmptq.ifq_ttl = fr_defnaticmpage; 279 nat_icmptq.ifq_ref = 1; 280 nat_icmptq.ifq_head = NULL; 281 nat_icmptq.ifq_tail = &nat_icmptq.ifq_head; 282 MUTEX_INIT(&nat_icmptq.ifq_lock, "nat icmp ipftq tab"); 283 nat_icmptq.ifq_next = &nat_iptq; 284 nat_iptq.ifq_ttl = fr_defnatipage; 285 nat_iptq.ifq_ref = 1; 286 nat_iptq.ifq_head = NULL; 287 nat_iptq.ifq_tail = &nat_iptq.ifq_head; 288 MUTEX_INIT(&nat_iptq.ifq_lock, "nat ip ipftq tab"); 289 nat_iptq.ifq_next = NULL; 290 291 for (i = 0; i < IPF_TCP_NSTATES; i++) { 292 if (nat_tqb[i].ifq_ttl < fr_defnaticmpage) 293 nat_tqb[i].ifq_ttl = fr_defnaticmpage; 294 #ifdef LARGE_NAT 295 else if (nat_tqb[i].ifq_ttl > fr_defnatage) 296 nat_tqb[i].ifq_ttl = fr_defnatage; 297 #endif 298 } 299 300 /* 301 * Increase this because we may have "keep state" following 302 * this too and packet storms can occur if this is removed 303 * too quickly. 304 */ 305 nat_tqb[IPF_TCPS_CLOSED].ifq_ttl = nat_tqb[IPF_TCPS_LAST_ACK].ifq_ttl; 306 307 RWLOCK_INIT(&ipf_nat, "ipf IP NAT rwlock"); 308 RWLOCK_INIT(&ipf_natfrag, "ipf IP NAT-Frag rwlock"); 309 MUTEX_INIT(&ipf_nat_new, "ipf nat new mutex"); 310 MUTEX_INIT(&ipf_natio, "ipf nat io mutex"); 311 312 fr_nat_init = 1; 313 314 return 0; 315 } 316 317 318 /* ------------------------------------------------------------------------ */ 319 /* Function: nat_addrdr */ 320 /* Returns: Nil */ 321 /* Parameters: n(I) - pointer to NAT rule to add */ 322 /* */ 323 /* Adds a redirect rule to the hash table of redirect rules and the list of */ 324 /* loaded NAT rules. Updates the bitmask indicating which netmasks are in */ 325 /* use by redirect rules. */ 326 /* ------------------------------------------------------------------------ */ 327 static void nat_addrdr(n) 328 ipnat_t *n; 329 { 330 ipnat_t **np; 331 u_32_t j; 332 u_int hv; 333 int k; 334 335 k = count4bits(n->in_outmsk); 336 if ((k >= 0) && (k != 32)) 337 rdr_masks |= 1 << k; 338 j = (n->in_outip & n->in_outmsk); 339 hv = NAT_HASH_FN(j, 0, ipf_rdrrules_sz); 340 np = rdr_rules + hv; 341 while (*np != NULL) 342 np = &(*np)->in_rnext; 343 n->in_rnext = NULL; 344 n->in_prnext = np; 345 n->in_hv = hv; 346 *np = n; 347 } 348 349 350 /* ------------------------------------------------------------------------ */ 351 /* Function: nat_addnat */ 352 /* Returns: Nil */ 353 /* Parameters: n(I) - pointer to NAT rule to add */ 354 /* */ 355 /* Adds a NAT map rule to the hash table of rules and the list of loaded */ 356 /* NAT rules. Updates the bitmask indicating which netmasks are in use by */ 357 /* redirect rules. */ 358 /* ------------------------------------------------------------------------ */ 359 static void nat_addnat(n) 360 ipnat_t *n; 361 { 362 ipnat_t **np; 363 u_32_t j; 364 u_int hv; 365 int k; 366 367 k = count4bits(n->in_inmsk); 368 if ((k >= 0) && (k != 32)) 369 nat_masks |= 1 << k; 370 j = (n->in_inip & n->in_inmsk); 371 hv = NAT_HASH_FN(j, 0, ipf_natrules_sz); 372 np = nat_rules + hv; 373 while (*np != NULL) 374 np = &(*np)->in_mnext; 375 n->in_mnext = NULL; 376 n->in_pmnext = np; 377 n->in_hv = hv; 378 *np = n; 379 } 380 381 382 /* ------------------------------------------------------------------------ */ 383 /* Function: nat_delrdr */ 384 /* Returns: Nil */ 385 /* Parameters: n(I) - pointer to NAT rule to delete */ 386 /* */ 387 /* Removes a redirect rule from the hash table of redirect rules. */ 388 /* ------------------------------------------------------------------------ */ 389 static void nat_delrdr(n) 390 ipnat_t *n; 391 { 392 if (n->in_rnext) 393 n->in_rnext->in_prnext = n->in_prnext; 394 *n->in_prnext = n->in_rnext; 395 } 396 397 398 /* ------------------------------------------------------------------------ */ 399 /* Function: nat_delnat */ 400 /* Returns: Nil */ 401 /* Parameters: n(I) - pointer to NAT rule to delete */ 402 /* */ 403 /* Removes a NAT map rule from the hash table of NAT map rules. */ 404 /* ------------------------------------------------------------------------ */ 405 static void nat_delnat(n) 406 ipnat_t *n; 407 { 408 if (n->in_mnext != NULL) 409 n->in_mnext->in_pmnext = n->in_pmnext; 410 *n->in_pmnext = n->in_mnext; 411 } 412 413 414 /* ------------------------------------------------------------------------ */ 415 /* Function: nat_hostmap */ 416 /* Returns: struct hostmap* - NULL if no hostmap could be created, */ 417 /* else a pointer to the hostmapping to use */ 418 /* Parameters: np(I) - pointer to NAT rule */ 419 /* real(I) - real IP address */ 420 /* map(I) - mapped IP address */ 421 /* port(I) - destination port number */ 422 /* Write Locks: ipf_nat */ 423 /* */ 424 /* Check if an ip address has already been allocated for a given mapping */ 425 /* that is not doing port based translation. If is not yet allocated, then */ 426 /* create a new entry if a non-NULL NAT rule pointer has been supplied. */ 427 /* ------------------------------------------------------------------------ */ 428 static struct hostmap *nat_hostmap(np, src, dst, map, port) 429 ipnat_t *np; 430 struct in_addr src; 431 struct in_addr dst; 432 struct in_addr map; 433 u_32_t port; 434 { 435 hostmap_t *hm; 436 u_int hv; 437 438 hv = (src.s_addr ^ dst.s_addr); 439 hv += src.s_addr; 440 hv += dst.s_addr; 441 hv %= HOSTMAP_SIZE; 442 for (hm = maptable[hv]; hm; hm = hm->hm_next) 443 if ((hm->hm_srcip.s_addr == src.s_addr) && 444 (hm->hm_dstip.s_addr == dst.s_addr) && 445 ((np == NULL) || (np == hm->hm_ipnat)) && 446 ((port == 0) || (port == hm->hm_port))) { 447 hm->hm_ref++; 448 return hm; 449 } 450 451 if (np == NULL) 452 return NULL; 453 454 KMALLOC(hm, hostmap_t *); 455 if (hm) { 456 hm->hm_next = maptable[hv]; 457 hm->hm_pnext = maptable + hv; 458 if (maptable[hv] != NULL) 459 maptable[hv]->hm_pnext = &hm->hm_next; 460 maptable[hv] = hm; 461 hm->hm_ipnat = np; 462 hm->hm_srcip = src; 463 hm->hm_dstip = dst; 464 hm->hm_mapip = map; 465 hm->hm_ref = 1; 466 hm->hm_port = port; 467 } 468 return hm; 469 } 470 471 472 /* ------------------------------------------------------------------------ */ 473 /* Function: nat_hostmapdel */ 474 /* Returns: Nil */ 475 /* Parameters: hm(I) - pointer to hostmap structure */ 476 /* Write Locks: ipf_nat */ 477 /* */ 478 /* Decrement the references to this hostmap structure by one. If this */ 479 /* reaches zero then remove it and free it. */ 480 /* ------------------------------------------------------------------------ */ 481 static void nat_hostmapdel(hm) 482 struct hostmap *hm; 483 { 484 hm->hm_ref--; 485 if (hm->hm_ref == 0) { 486 if (hm->hm_next) 487 hm->hm_next->hm_pnext = hm->hm_pnext; 488 *hm->hm_pnext = hm->hm_next; 489 KFREE(hm); 490 } 491 } 492 493 494 /* ------------------------------------------------------------------------ */ 495 /* Function: fix_outcksum */ 496 /* Returns: Nil */ 497 /* Parameters: sp(I) - location of 16bit checksum to update */ 498 /* n((I) - amount to adjust checksum by */ 499 /* */ 500 /* Adjusts the 16bit checksum by "n" for packets going out. */ 501 /* ------------------------------------------------------------------------ */ 502 void fix_outcksum(sp, n) 503 u_short *sp; 504 u_32_t n; 505 { 506 u_short sumshort; 507 u_32_t sum1; 508 509 if (n == 0) 510 return; 511 512 sum1 = (~ntohs(*sp)) & 0xffff; 513 sum1 += (n); 514 sum1 = (sum1 >> 16) + (sum1 & 0xffff); 515 /* Again */ 516 sum1 = (sum1 >> 16) + (sum1 & 0xffff); 517 sumshort = ~(u_short)sum1; 518 *(sp) = htons(sumshort); 519 } 520 521 522 /* ------------------------------------------------------------------------ */ 523 /* Function: fix_incksum */ 524 /* Returns: Nil */ 525 /* Parameters: sp(I) - location of 16bit checksum to update */ 526 /* n((I) - amount to adjust checksum by */ 527 /* */ 528 /* Adjusts the 16bit checksum by "n" for packets going in. */ 529 /* ------------------------------------------------------------------------ */ 530 void fix_incksum(sp, n) 531 u_short *sp; 532 u_32_t n; 533 { 534 u_short sumshort; 535 u_32_t sum1; 536 537 if (n == 0) 538 return; 539 540 sum1 = (~ntohs(*sp)) & 0xffff; 541 sum1 += ~(n) & 0xffff; 542 sum1 = (sum1 >> 16) + (sum1 & 0xffff); 543 /* Again */ 544 sum1 = (sum1 >> 16) + (sum1 & 0xffff); 545 sumshort = ~(u_short)sum1; 546 *(sp) = htons(sumshort); 547 } 548 549 550 /* ------------------------------------------------------------------------ */ 551 /* Function: fix_datacksum */ 552 /* Returns: Nil */ 553 /* Parameters: sp(I) - location of 16bit checksum to update */ 554 /* n((I) - amount to adjust checksum by */ 555 /* */ 556 /* Fix_datacksum is used *only* for the adjustments of checksums in the */ 557 /* data section of an IP packet. */ 558 /* */ 559 /* The only situation in which you need to do this is when NAT'ing an */ 560 /* ICMP error message. Such a message, contains in its body the IP header */ 561 /* of the original IP packet, that causes the error. */ 562 /* */ 563 /* You can't use fix_incksum or fix_outcksum in that case, because for the */ 564 /* kernel the data section of the ICMP error is just data, and no special */ 565 /* processing like hardware cksum or ntohs processing have been done by the */ 566 /* kernel on the data section. */ 567 /* ------------------------------------------------------------------------ */ 568 void fix_datacksum(sp, n) 569 u_short *sp; 570 u_32_t n; 571 { 572 u_short sumshort; 573 u_32_t sum1; 574 575 if (n == 0) 576 return; 577 578 sum1 = (~ntohs(*sp)) & 0xffff; 579 sum1 += (n); 580 sum1 = (sum1 >> 16) + (sum1 & 0xffff); 581 /* Again */ 582 sum1 = (sum1 >> 16) + (sum1 & 0xffff); 583 sumshort = ~(u_short)sum1; 584 *(sp) = htons(sumshort); 585 } 586 587 588 /* ------------------------------------------------------------------------ */ 589 /* Function: fr_nat_ioctl */ 590 /* Returns: int - 0 == success, != 0 == failure */ 591 /* Parameters: data(I) - pointer to ioctl data */ 592 /* cmd(I) - ioctl command integer */ 593 /* mode(I) - file mode bits used with open */ 594 /* */ 595 /* Processes an ioctl call made to operate on the IP Filter NAT device. */ 596 /* ------------------------------------------------------------------------ */ 597 int fr_nat_ioctl(data, cmd, mode) 598 ioctlcmd_t cmd; 599 caddr_t data; 600 int mode; 601 { 602 ipnat_t *nat, *nt, *n = NULL, **np = NULL; 603 int error = 0, ret, arg, getlock; 604 ipnat_t natd; 605 606 #if (BSD >= 199306) && defined(_KERNEL) 607 if ((securelevel >= 2) && (mode & FWRITE)) 608 return EPERM; 609 #endif 610 611 #if defined(__osf__) && defined(_KERNEL) 612 getlock = 0; 613 #else 614 getlock = (mode & NAT_LOCKHELD) ? 0 : 1; 615 #endif 616 617 nat = NULL; /* XXX gcc -Wuninitialized */ 618 if (cmd == (ioctlcmd_t)SIOCADNAT) { 619 KMALLOC(nt, ipnat_t *); 620 } else { 621 nt = NULL; 622 } 623 624 if ((cmd == (ioctlcmd_t)SIOCADNAT) || (cmd == (ioctlcmd_t)SIOCRMNAT)) { 625 if (mode & NAT_SYSSPACE) { 626 bcopy(data, (char *)&natd, sizeof(natd)); 627 error = 0; 628 } else { 629 error = fr_inobj(data, &natd, IPFOBJ_IPNAT); 630 } 631 632 } else if (cmd == (ioctlcmd_t)SIOCIPFFL) { /* SIOCFLNAT & SIOCCNATL */ 633 BCOPYIN(data, &arg, sizeof(arg)); 634 } 635 636 if (error != 0) 637 goto done; 638 639 /* 640 * For add/delete, look to see if the NAT entry is already present 641 */ 642 if ((cmd == (ioctlcmd_t)SIOCADNAT) || (cmd == (ioctlcmd_t)SIOCRMNAT)) { 643 nat = &natd; 644 if (nat->in_v == 0) /* For backward compat. */ 645 nat->in_v = 4; 646 nat->in_flags &= IPN_USERFLAGS; 647 if ((nat->in_redir & NAT_MAPBLK) == 0) { 648 if ((nat->in_flags & IPN_SPLIT) == 0) 649 nat->in_inip &= nat->in_inmsk; 650 if ((nat->in_flags & IPN_IPRANGE) == 0) 651 nat->in_outip &= nat->in_outmsk; 652 } 653 MUTEX_ENTER(&ipf_natio); 654 for (np = &nat_list; ((n = *np) != NULL); np = &n->in_next) 655 if (!bcmp((char *)&nat->in_flags, (char *)&n->in_flags, 656 IPN_CMPSIZ)) 657 break; 658 } 659 660 switch (cmd) 661 { 662 #ifdef IPFILTER_LOG 663 case SIOCIPFFB : 664 { 665 int tmp; 666 667 if (!(mode & FWRITE)) 668 error = EPERM; 669 else { 670 tmp = ipflog_clear(IPL_LOGNAT); 671 BCOPYOUT((char *)&tmp, (char *)data, sizeof(tmp)); 672 } 673 break; 674 } 675 case SIOCSETLG : 676 if (!(mode & FWRITE)) 677 error = EPERM; 678 else { 679 BCOPYIN((char *)data, (char *)&nat_logging, 680 sizeof(nat_logging)); 681 } 682 break; 683 case SIOCGETLG : 684 BCOPYOUT((char *)&nat_logging, (char *)data, 685 sizeof(nat_logging)); 686 break; 687 case FIONREAD : 688 arg = iplused[IPL_LOGNAT]; 689 BCOPYOUT(&arg, data, sizeof(arg)); 690 break; 691 #endif 692 case SIOCADNAT : 693 if (!(mode & FWRITE)) { 694 error = EPERM; 695 } else if (n != NULL) { 696 error = EEXIST; 697 } else if (nt == NULL) { 698 error = ENOMEM; 699 } 700 if (error != 0) { 701 MUTEX_EXIT(&ipf_natio); 702 break; 703 } 704 bcopy((char *)nat, (char *)nt, sizeof(*n)); 705 error = nat_siocaddnat(nt, np, getlock); 706 MUTEX_EXIT(&ipf_natio); 707 if (error == 0) 708 nt = NULL; 709 break; 710 case SIOCRMNAT : 711 if (!(mode & FWRITE)) { 712 error = EPERM; 713 n = NULL; 714 } else if (n == NULL) { 715 error = ESRCH; 716 } 717 718 if (error != 0) { 719 MUTEX_EXIT(&ipf_natio); 720 break; 721 } 722 nat_siocdelnat(n, np, getlock); 723 724 MUTEX_EXIT(&ipf_natio); 725 n = NULL; 726 break; 727 case SIOCGNATS : 728 nat_stats.ns_table[0] = nat_table[0]; 729 nat_stats.ns_table[1] = nat_table[1]; 730 nat_stats.ns_list = nat_list; 731 nat_stats.ns_maptable = maptable; 732 nat_stats.ns_nattab_sz = ipf_nattable_sz; 733 nat_stats.ns_nattab_max = ipf_nattable_max; 734 nat_stats.ns_rultab_sz = ipf_natrules_sz; 735 nat_stats.ns_rdrtab_sz = ipf_rdrrules_sz; 736 nat_stats.ns_hostmap_sz = ipf_hostmap_sz; 737 nat_stats.ns_instances = nat_instances; 738 nat_stats.ns_apslist = ap_sess_list; 739 error = fr_outobj(data, &nat_stats, IPFOBJ_NATSTAT); 740 break; 741 case SIOCGNATL : 742 { 743 natlookup_t nl; 744 745 if (getlock) { 746 READ_ENTER(&ipf_nat); 747 } 748 error = fr_inobj(data, &nl, IPFOBJ_NATLOOKUP); 749 if (error == 0) { 750 if (nat_lookupredir(&nl) != NULL) { 751 error = fr_outobj(data, &nl, IPFOBJ_NATLOOKUP); 752 } else { 753 error = ESRCH; 754 } 755 } 756 if (getlock) { 757 RWLOCK_EXIT(&ipf_nat); 758 } 759 break; 760 } 761 case SIOCIPFFL : /* old SIOCFLNAT & SIOCCNATL */ 762 if (!(mode & FWRITE)) { 763 error = EPERM; 764 break; 765 } 766 if (getlock) { 767 WRITE_ENTER(&ipf_nat); 768 } 769 error = 0; 770 if (arg == 0) 771 ret = nat_flushtable(); 772 else if (arg == 1) 773 ret = nat_clearlist(); 774 else 775 error = EINVAL; 776 if (getlock) { 777 RWLOCK_EXIT(&ipf_nat); 778 } 779 if (error == 0) { 780 BCOPYOUT(&ret, data, sizeof(ret)); 781 } 782 break; 783 case SIOCPROXY : 784 error = appr_ioctl(data, cmd, mode); 785 break; 786 case SIOCSTLCK : 787 if (!(mode & FWRITE)) { 788 error = EPERM; 789 } else { 790 fr_lock(data, &fr_nat_lock); 791 } 792 break; 793 case SIOCSTPUT : 794 if ((mode & FWRITE) != 0) { 795 error = fr_natputent(data, getlock); 796 } else { 797 error = EACCES; 798 } 799 break; 800 case SIOCSTGSZ : 801 if (fr_nat_lock) { 802 if (getlock) { 803 READ_ENTER(&ipf_nat); 804 } 805 error = fr_natgetsz(data); 806 if (getlock) { 807 RWLOCK_EXIT(&ipf_nat); 808 } 809 } else 810 error = EACCES; 811 break; 812 case SIOCSTGET : 813 if (fr_nat_lock) { 814 if (getlock) { 815 READ_ENTER(&ipf_nat); 816 } 817 error = fr_natgetent(data); 818 if (getlock) { 819 RWLOCK_EXIT(&ipf_nat); 820 } 821 } else 822 error = EACCES; 823 break; 824 default : 825 error = EINVAL; 826 break; 827 } 828 done: 829 if (nt) 830 KFREE(nt); 831 return error; 832 } 833 834 835 /* ------------------------------------------------------------------------ */ 836 /* Function: nat_siocaddnat */ 837 /* Returns: int - 0 == success, != 0 == failure */ 838 /* Parameters: n(I) - pointer to new NAT rule */ 839 /* np(I) - pointer to where to insert new NAT rule */ 840 /* getlock(I) - flag indicating if lock on ipf_nat is held */ 841 /* Mutex Locks: ipf_natio */ 842 /* */ 843 /* Handle SIOCADNAT. Resolve and calculate details inside the NAT rule */ 844 /* from information passed to the kernel, then add it to the appropriate */ 845 /* NAT rule table(s). */ 846 /* ------------------------------------------------------------------------ */ 847 static int nat_siocaddnat(n, np, getlock) 848 ipnat_t *n, **np; 849 int getlock; 850 { 851 int error = 0, i, j; 852 853 nat_resolverule(n); 854 if (n->in_plabel[0] != '\0') { 855 if (n->in_apr == NULL) 856 return ENOENT; 857 } 858 859 if ((n->in_age[0] == 0) && (n->in_age[1] != 0)) 860 return EINVAL; 861 862 n->in_use = 0; 863 if (n->in_redir & NAT_MAPBLK) 864 n->in_space = USABLE_PORTS * ~ntohl(n->in_outmsk); 865 else if (n->in_flags & IPN_AUTOPORTMAP) 866 n->in_space = USABLE_PORTS * ~ntohl(n->in_inmsk); 867 else if (n->in_flags & IPN_IPRANGE) 868 n->in_space = ntohl(n->in_outmsk) - ntohl(n->in_outip); 869 else if (n->in_flags & IPN_SPLIT) 870 n->in_space = 2; 871 else if (n->in_outmsk != 0) 872 n->in_space = ~ntohl(n->in_outmsk); 873 else 874 n->in_space = 1; 875 876 /* 877 * Calculate the number of valid IP addresses in the output 878 * mapping range. In all cases, the range is inclusive of 879 * the start and ending IP addresses. 880 * If to a CIDR address, lose 2: broadcast + network address 881 * (so subtract 1) 882 * If to a range, add one. 883 * If to a single IP address, set to 1. 884 */ 885 if (n->in_space) { 886 if ((n->in_flags & IPN_IPRANGE) != 0) 887 n->in_space += 1; 888 else 889 n->in_space -= 1; 890 } else 891 n->in_space = 1; 892 893 if ((n->in_outmsk != 0xffffffff) && (n->in_outmsk != 0) && 894 ((n->in_flags & (IPN_IPRANGE|IPN_SPLIT)) == 0)) 895 n->in_nip = ntohl(n->in_outip) + 1; 896 else if ((n->in_flags & IPN_SPLIT) && 897 (n->in_redir & NAT_REDIRECT)) 898 n->in_nip = ntohl(n->in_inip); 899 else 900 n->in_nip = ntohl(n->in_outip); 901 if (n->in_redir & NAT_MAP) { 902 n->in_pnext = ntohs(n->in_pmin); 903 /* 904 * Multiply by the number of ports made available. 905 */ 906 if (ntohs(n->in_pmax) >= ntohs(n->in_pmin)) { 907 n->in_space *= (ntohs(n->in_pmax) - 908 ntohs(n->in_pmin) + 1); 909 /* 910 * Because two different sources can map to 911 * different destinations but use the same 912 * local IP#/port #. 913 * If the result is smaller than in_space, then 914 * we may have wrapped around 32bits. 915 */ 916 i = n->in_inmsk; 917 if ((i != 0) && (i != 0xffffffff)) { 918 j = n->in_space * (~ntohl(i) + 1); 919 if (j >= n->in_space) 920 n->in_space = j; 921 else 922 n->in_space = 0xffffffff; 923 } 924 } 925 /* 926 * If no protocol is specified, multiple by 256 to allow for 927 * at least one IP:IP mapping per protocol. 928 */ 929 if ((n->in_flags & IPN_TCPUDPICMP) == 0) { 930 j = n->in_space * 256; 931 if (j >= n->in_space) 932 n->in_space = j; 933 else 934 n->in_space = 0xffffffff; 935 } 936 } 937 938 /* Otherwise, these fields are preset */ 939 940 if (getlock) { 941 WRITE_ENTER(&ipf_nat); 942 } 943 n->in_next = NULL; 944 *np = n; 945 946 if (n->in_age[0] != 0) 947 n->in_tqehead[0] = fr_addtimeoutqueue(&nat_utqe, n->in_age[0]); 948 949 if (n->in_age[1] != 0) 950 n->in_tqehead[1] = fr_addtimeoutqueue(&nat_utqe, n->in_age[1]); 951 952 if (n->in_redir & NAT_REDIRECT) { 953 n->in_flags &= ~IPN_NOTDST; 954 nat_addrdr(n); 955 } 956 if (n->in_redir & (NAT_MAP|NAT_MAPBLK)) { 957 n->in_flags &= ~IPN_NOTSRC; 958 nat_addnat(n); 959 } 960 n = NULL; 961 nat_stats.ns_rules++; 962 if (getlock) { 963 RWLOCK_EXIT(&ipf_nat); /* WRITE */ 964 } 965 966 return error; 967 } 968 969 970 /* ------------------------------------------------------------------------ */ 971 /* Function: nat_resolvrule */ 972 /* Returns: Nil */ 973 /* Parameters: n(I) - pointer to NAT rule */ 974 /* */ 975 /* Handle SIOCADNAT. Resolve and calculate details inside the NAT rule */ 976 /* from information passed to the kernel, then add it to the appropriate */ 977 /* NAT rule table(s). */ 978 /* ------------------------------------------------------------------------ */ 979 static void nat_resolverule(n) 980 ipnat_t *n; 981 { 982 n->in_ifnames[0][LIFNAMSIZ - 1] = '\0'; 983 n->in_ifps[0] = fr_resolvenic(n->in_ifnames[0], 4); 984 985 n->in_ifnames[1][LIFNAMSIZ - 1] = '\0'; 986 if (n->in_ifnames[1][0] == '\0') { 987 (void) strncpy(n->in_ifnames[1], n->in_ifnames[0], LIFNAMSIZ); 988 n->in_ifps[1] = n->in_ifps[0]; 989 } else { 990 n->in_ifps[1] = fr_resolvenic(n->in_ifnames[0], 4); 991 } 992 993 if (n->in_plabel[0] != '\0') { 994 n->in_apr = appr_lookup(n->in_p, n->in_plabel); 995 } 996 } 997 998 999 /* ------------------------------------------------------------------------ */ 1000 /* Function: nat_siocdelnat */ 1001 /* Returns: int - 0 == success, != 0 == failure */ 1002 /* Parameters: n(I) - pointer to new NAT rule */ 1003 /* np(I) - pointer to where to insert new NAT rule */ 1004 /* getlock(I) - flag indicating if lock on ipf_nat is held */ 1005 /* Mutex Locks: ipf_natio */ 1006 /* */ 1007 /* Handle SIOCADNAT. Resolve and calculate details inside the NAT rule */ 1008 /* from information passed to the kernel, then add it to the appropriate */ 1009 /* NAT rule table(s). */ 1010 /* ------------------------------------------------------------------------ */ 1011 static void nat_siocdelnat(n, np, getlock) 1012 ipnat_t *n, **np; 1013 int getlock; 1014 { 1015 if (getlock) { 1016 WRITE_ENTER(&ipf_nat); 1017 } 1018 if (n->in_redir & NAT_REDIRECT) 1019 nat_delrdr(n); 1020 if (n->in_redir & (NAT_MAPBLK|NAT_MAP)) 1021 nat_delnat(n); 1022 if (nat_list == NULL) { 1023 nat_masks = 0; 1024 rdr_masks = 0; 1025 } 1026 1027 if (n->in_tqehead[0] != NULL) { 1028 if (fr_deletetimeoutqueue(n->in_tqehead[0]) == 0) { 1029 fr_freetimeoutqueue(n->in_tqehead[1]); 1030 } 1031 } 1032 1033 if (n->in_tqehead[1] != NULL) { 1034 if (fr_deletetimeoutqueue(n->in_tqehead[1]) == 0) { 1035 fr_freetimeoutqueue(n->in_tqehead[1]); 1036 } 1037 } 1038 1039 *np = n->in_next; 1040 1041 if (n->in_use == 0) { 1042 if (n->in_apr) 1043 appr_free(n->in_apr); 1044 KFREE(n); 1045 nat_stats.ns_rules--; 1046 } else { 1047 n->in_flags |= IPN_DELETE; 1048 n->in_next = NULL; 1049 } 1050 if (getlock) { 1051 RWLOCK_EXIT(&ipf_nat); /* READ/WRITE */ 1052 } 1053 } 1054 1055 1056 /* ------------------------------------------------------------------------ */ 1057 /* Function: fr_natgetsz */ 1058 /* Returns: int - 0 == success, != 0 is the error value. */ 1059 /* Parameters: data(I) - pointer to natget structure with kernel pointer */ 1060 /* get the size of. */ 1061 /* */ 1062 /* Handle SIOCSTGSZ. */ 1063 /* Return the size of the nat list entry to be copied back to user space. */ 1064 /* The size of the entry is stored in the ng_sz field and the enture natget */ 1065 /* structure is copied back to the user. */ 1066 /* ------------------------------------------------------------------------ */ 1067 static int fr_natgetsz(data) 1068 caddr_t data; 1069 { 1070 ap_session_t *aps; 1071 nat_t *nat, *n; 1072 natget_t ng; 1073 1074 BCOPYIN(data, &ng, sizeof(ng)); 1075 1076 nat = ng.ng_ptr; 1077 if (!nat) { 1078 nat = nat_instances; 1079 ng.ng_sz = 0; 1080 /* 1081 * Empty list so the size returned is 0. Simple. 1082 */ 1083 if (nat == NULL) { 1084 BCOPYOUT(&ng, data, sizeof(ng)); 1085 return 0; 1086 } 1087 } else { 1088 /* 1089 * Make sure the pointer we're copying from exists in the 1090 * current list of entries. Security precaution to prevent 1091 * copying of random kernel data. 1092 */ 1093 for (n = nat_instances; n; n = n->nat_next) 1094 if (n == nat) 1095 break; 1096 if (!n) 1097 return ESRCH; 1098 } 1099 1100 /* 1101 * Incluse any space required for proxy data structures. 1102 */ 1103 ng.ng_sz = sizeof(nat_save_t); 1104 aps = nat->nat_aps; 1105 if (aps != NULL) { 1106 ng.ng_sz += sizeof(ap_session_t) - 4; 1107 if (aps->aps_data != 0) 1108 ng.ng_sz += aps->aps_psiz; 1109 } 1110 1111 BCOPYOUT(&ng, data, sizeof(ng)); 1112 return 0; 1113 } 1114 1115 1116 /* ------------------------------------------------------------------------ */ 1117 /* Function: fr_natgetent */ 1118 /* Returns: int - 0 == success, != 0 is the error value. */ 1119 /* Parameters: data(I) - pointer to natget structure with kernel pointer */ 1120 /* to NAT structure to copy out. */ 1121 /* */ 1122 /* Handle SIOCSTGET. */ 1123 /* Copies out NAT entry to user space. Any additional data held for a */ 1124 /* proxy is also copied, as to is the NAT rule which was responsible for it */ 1125 /* ------------------------------------------------------------------------ */ 1126 static int fr_natgetent(data) 1127 caddr_t data; 1128 { 1129 int error, outsize; 1130 ap_session_t *aps; 1131 nat_save_t *ipn, ipns; 1132 nat_t *n, *nat; 1133 1134 error = fr_inobj(data, &ipns, IPFOBJ_NATSAVE); 1135 if (error != 0) 1136 return error; 1137 1138 if ((ipns.ipn_dsize < sizeof(ipns)) || (ipns.ipn_dsize > 81920)) 1139 return EINVAL; 1140 1141 KMALLOCS(ipn, nat_save_t *, ipns.ipn_dsize); 1142 if (ipn == NULL) 1143 return ENOMEM; 1144 1145 ipn->ipn_dsize = ipns.ipn_dsize; 1146 nat = ipns.ipn_next; 1147 if (nat == NULL) { 1148 nat = nat_instances; 1149 if (nat == NULL) { 1150 if (nat_instances == NULL) 1151 error = ENOENT; 1152 goto finished; 1153 } 1154 } else { 1155 /* 1156 * Make sure the pointer we're copying from exists in the 1157 * current list of entries. Security precaution to prevent 1158 * copying of random kernel data. 1159 */ 1160 for (n = nat_instances; n; n = n->nat_next) 1161 if (n == nat) 1162 break; 1163 if (n == NULL) { 1164 error = ESRCH; 1165 goto finished; 1166 } 1167 } 1168 ipn->ipn_next = nat->nat_next; 1169 1170 /* 1171 * Copy the NAT structure. 1172 */ 1173 bcopy((char *)nat, &ipn->ipn_nat, sizeof(*nat)); 1174 1175 /* 1176 * If we have a pointer to the NAT rule it belongs to, save that too. 1177 */ 1178 if (nat->nat_ptr != NULL) 1179 bcopy((char *)nat->nat_ptr, (char *)&ipn->ipn_ipnat, 1180 sizeof(ipn->ipn_ipnat)); 1181 1182 /* 1183 * If we also know the NAT entry has an associated filter rule, 1184 * save that too. 1185 */ 1186 if (nat->nat_fr != NULL) 1187 bcopy((char *)nat->nat_fr, (char *)&ipn->ipn_fr, 1188 sizeof(ipn->ipn_fr)); 1189 1190 /* 1191 * Last but not least, if there is an application proxy session set 1192 * up for this NAT entry, then copy that out too, including any 1193 * private data saved along side it by the proxy. 1194 */ 1195 aps = nat->nat_aps; 1196 outsize = ipn->ipn_dsize - sizeof(*ipn) + sizeof(ipn->ipn_data); 1197 if (aps != NULL) { 1198 char *s; 1199 1200 if (outsize < sizeof(*aps)) { 1201 error = ENOBUFS; 1202 goto finished; 1203 } 1204 1205 s = ipn->ipn_data; 1206 bcopy((char *)aps, s, sizeof(*aps)); 1207 s += sizeof(*aps); 1208 outsize -= sizeof(*aps); 1209 if ((aps->aps_data != NULL) && (outsize >= aps->aps_psiz)) 1210 bcopy(aps->aps_data, s, aps->aps_psiz); 1211 else 1212 error = ENOBUFS; 1213 } 1214 if (error == 0) { 1215 error = fr_outobjsz(data, ipn, IPFOBJ_NATSAVE, ipns.ipn_dsize); 1216 } 1217 1218 finished: 1219 if (ipn != NULL) { 1220 KFREES(ipn, ipns.ipn_dsize); 1221 } 1222 return error; 1223 } 1224 1225 1226 /* ------------------------------------------------------------------------ */ 1227 /* Function: fr_natputent */ 1228 /* Returns: int - 0 == success, != 0 is the error value. */ 1229 /* Parameters: data(I) - pointer to natget structure with NAT */ 1230 /* structure information to load into the kernel */ 1231 /* getlock(I) - flag indicating whether or not a write lock */ 1232 /* on ipf_nat is already held. */ 1233 /* */ 1234 /* Handle SIOCSTPUT. */ 1235 /* Loads a NAT table entry from user space, including a NAT rule, proxy and */ 1236 /* firewall rule data structures, if pointers to them indicate so. */ 1237 /* ------------------------------------------------------------------------ */ 1238 static int fr_natputent(data, getlock) 1239 caddr_t data; 1240 int getlock; 1241 { 1242 nat_save_t ipn, *ipnn; 1243 ap_session_t *aps; 1244 nat_t *n, *nat; 1245 frentry_t *fr; 1246 fr_info_t fin; 1247 ipnat_t *in; 1248 int error; 1249 1250 error = fr_inobj(data, &ipn, IPFOBJ_NATSAVE); 1251 if (error != 0) 1252 return error; 1253 1254 /* 1255 * Initialise early because of code at junkput label. 1256 */ 1257 in = NULL; 1258 aps = NULL; 1259 nat = NULL; 1260 ipnn = NULL; 1261 1262 /* 1263 * New entry, copy in the rest of the NAT entry if it's size is more 1264 * than just the nat_t structure. 1265 */ 1266 fr = NULL; 1267 if (ipn.ipn_dsize > sizeof(ipn)) { 1268 if (ipn.ipn_dsize > 81920) { 1269 error = ENOMEM; 1270 goto junkput; 1271 } 1272 1273 KMALLOCS(ipnn, nat_save_t *, ipn.ipn_dsize); 1274 if (ipnn == NULL) 1275 return ENOMEM; 1276 1277 error = fr_inobjsz(data, ipnn, IPFOBJ_NATSAVE, ipn.ipn_dsize); 1278 if (error != 0) { 1279 error = EFAULT; 1280 goto junkput; 1281 } 1282 } else 1283 ipnn = &ipn; 1284 1285 KMALLOC(nat, nat_t *); 1286 if (nat == NULL) { 1287 error = ENOMEM; 1288 goto junkput; 1289 } 1290 1291 bcopy((char *)&ipnn->ipn_nat, (char *)nat, sizeof(*nat)); 1292 /* 1293 * Initialize all these so that nat_delete() doesn't cause a crash. 1294 */ 1295 bzero((char *)nat, offsetof(struct nat, nat_tqe)); 1296 nat->nat_tqe.tqe_pnext = NULL; 1297 nat->nat_tqe.tqe_next = NULL; 1298 nat->nat_tqe.tqe_ifq = NULL; 1299 nat->nat_tqe.tqe_parent = nat; 1300 1301 /* 1302 * Restore the rule associated with this nat session 1303 */ 1304 in = ipnn->ipn_nat.nat_ptr; 1305 if (in != NULL) { 1306 KMALLOC(in, ipnat_t *); 1307 nat->nat_ptr = in; 1308 if (in == NULL) { 1309 error = ENOMEM; 1310 goto junkput; 1311 } 1312 bzero((char *)in, offsetof(struct ipnat, in_next6)); 1313 bcopy((char *)&ipnn->ipn_ipnat, (char *)in, sizeof(*in)); 1314 in->in_use = 1; 1315 in->in_flags |= IPN_DELETE; 1316 1317 ATOMIC_INC(nat_stats.ns_rules); 1318 1319 nat_resolverule(in); 1320 } 1321 1322 /* 1323 * Check that the NAT entry doesn't already exist in the kernel. 1324 */ 1325 bzero((char *)&fin, sizeof(fin)); 1326 fin.fin_p = nat->nat_p; 1327 if (nat->nat_dir == NAT_OUTBOUND) { 1328 fin.fin_data[0] = ntohs(nat->nat_oport); 1329 fin.fin_data[1] = ntohs(nat->nat_outport); 1330 fin.fin_ifp = nat->nat_ifps[0]; 1331 if (getlock) { 1332 READ_ENTER(&ipf_nat); 1333 } 1334 n = nat_inlookup(&fin, nat->nat_flags, fin.fin_p, 1335 nat->nat_oip, nat->nat_outip); 1336 if (getlock) { 1337 RWLOCK_EXIT(&ipf_nat); 1338 } 1339 if (n != NULL) { 1340 error = EEXIST; 1341 goto junkput; 1342 } 1343 } else if (nat->nat_dir == NAT_INBOUND) { 1344 fin.fin_data[0] = ntohs(nat->nat_inport); 1345 fin.fin_data[1] = ntohs(nat->nat_oport); 1346 fin.fin_ifp = nat->nat_ifps[1]; 1347 if (getlock) { 1348 READ_ENTER(&ipf_nat); 1349 } 1350 n = nat_outlookup(&fin, nat->nat_flags, fin.fin_p, 1351 nat->nat_inip, nat->nat_oip); 1352 if (getlock) { 1353 RWLOCK_EXIT(&ipf_nat); 1354 } 1355 if (n != NULL) { 1356 error = EEXIST; 1357 goto junkput; 1358 } 1359 } else { 1360 error = EINVAL; 1361 goto junkput; 1362 } 1363 1364 /* 1365 * Restore ap_session_t structure. Include the private data allocated 1366 * if it was there. 1367 */ 1368 aps = nat->nat_aps; 1369 if (aps != NULL) { 1370 KMALLOC(aps, ap_session_t *); 1371 nat->nat_aps = aps; 1372 if (aps == NULL) { 1373 error = ENOMEM; 1374 goto junkput; 1375 } 1376 bcopy(ipnn->ipn_data, (char *)aps, sizeof(*aps)); 1377 if (in != NULL) 1378 aps->aps_apr = in->in_apr; 1379 else 1380 aps->aps_apr = NULL; 1381 if (aps->aps_psiz != 0) { 1382 if (aps->aps_psiz > 81920) { 1383 error = ENOMEM; 1384 goto junkput; 1385 } 1386 KMALLOCS(aps->aps_data, void *, aps->aps_psiz); 1387 if (aps->aps_data == NULL) { 1388 error = ENOMEM; 1389 goto junkput; 1390 } 1391 bcopy(ipnn->ipn_data + sizeof(*aps), aps->aps_data, 1392 aps->aps_psiz); 1393 } else { 1394 aps->aps_psiz = 0; 1395 aps->aps_data = NULL; 1396 } 1397 } 1398 1399 /* 1400 * If there was a filtering rule associated with this entry then 1401 * build up a new one. 1402 */ 1403 fr = nat->nat_fr; 1404 if (fr != NULL) { 1405 if ((nat->nat_flags & SI_NEWFR) != 0) { 1406 KMALLOC(fr, frentry_t *); 1407 nat->nat_fr = fr; 1408 if (fr == NULL) { 1409 error = ENOMEM; 1410 goto junkput; 1411 } 1412 ipnn->ipn_nat.nat_fr = fr; 1413 fr->fr_ref = 1; 1414 (void) fr_outobj(data, ipnn, IPFOBJ_NATSAVE); 1415 bcopy((char *)&ipnn->ipn_fr, (char *)fr, sizeof(*fr)); 1416 MUTEX_NUKE(&fr->fr_lock); 1417 MUTEX_INIT(&fr->fr_lock, "nat-filter rule lock"); 1418 } else { 1419 READ_ENTER(&ipf_nat); 1420 for (n = nat_instances; n; n = n->nat_next) 1421 if (n->nat_fr == fr) 1422 break; 1423 1424 if (n != NULL) { 1425 MUTEX_ENTER(&fr->fr_lock); 1426 fr->fr_ref++; 1427 MUTEX_EXIT(&fr->fr_lock); 1428 } 1429 RWLOCK_EXIT(&ipf_nat); 1430 1431 if (!n) { 1432 error = ESRCH; 1433 goto junkput; 1434 } 1435 } 1436 } 1437 1438 if (ipnn != &ipn) { 1439 KFREES(ipnn, ipn.ipn_dsize); 1440 ipnn = NULL; 1441 } 1442 1443 if (getlock) { 1444 WRITE_ENTER(&ipf_nat); 1445 } 1446 error = nat_insert(nat, nat->nat_rev); 1447 if ((error == 0) && (aps != NULL)) { 1448 aps->aps_next = ap_sess_list; 1449 ap_sess_list = aps; 1450 } 1451 if (getlock) { 1452 RWLOCK_EXIT(&ipf_nat); 1453 } 1454 1455 if (error == 0) 1456 return 0; 1457 1458 error = ENOMEM; 1459 1460 junkput: 1461 if (fr != NULL) 1462 (void) fr_derefrule(&fr); 1463 1464 if ((ipnn != NULL) && (ipnn != &ipn)) { 1465 KFREES(ipnn, ipn.ipn_dsize); 1466 } 1467 if (nat != NULL) { 1468 if (aps != NULL) { 1469 if (aps->aps_data != NULL) { 1470 KFREES(aps->aps_data, aps->aps_psiz); 1471 } 1472 KFREE(aps); 1473 } 1474 if (in != NULL) { 1475 if (in->in_apr) 1476 appr_free(in->in_apr); 1477 KFREE(in); 1478 } 1479 KFREE(nat); 1480 } 1481 return error; 1482 } 1483 1484 1485 /* ------------------------------------------------------------------------ */ 1486 /* Function: nat_delete */ 1487 /* Returns: Nil */ 1488 /* Parameters: natd(I) - pointer to NAT structure to delete */ 1489 /* logtype(I) - type of LOG record to create before deleting */ 1490 /* Write Lock: ipf_nat */ 1491 /* */ 1492 /* Delete a nat entry from the various lists and table. If NAT logging is */ 1493 /* enabled then generate a NAT log record for this event. */ 1494 /* ------------------------------------------------------------------------ */ 1495 static void nat_delete(nat, logtype) 1496 struct nat *nat; 1497 int logtype; 1498 { 1499 struct ipnat *ipn; 1500 1501 if (logtype != 0 && nat_logging != 0) 1502 nat_log(nat, logtype); 1503 1504 MUTEX_ENTER(&ipf_nat_new); 1505 1506 /* 1507 * Take it as a general indication that all the pointers are set if 1508 * nat_pnext is set. 1509 */ 1510 if (nat->nat_pnext != NULL) { 1511 nat_stats.ns_bucketlen[0][nat->nat_hv[0]]--; 1512 nat_stats.ns_bucketlen[1][nat->nat_hv[1]]--; 1513 1514 *nat->nat_pnext = nat->nat_next; 1515 if (nat->nat_next != NULL) { 1516 nat->nat_next->nat_pnext = nat->nat_pnext; 1517 nat->nat_next = NULL; 1518 } 1519 nat->nat_pnext = NULL; 1520 1521 *nat->nat_phnext[0] = nat->nat_hnext[0]; 1522 if (nat->nat_hnext[0] != NULL) { 1523 nat->nat_hnext[0]->nat_phnext[0] = nat->nat_phnext[0]; 1524 nat->nat_hnext[0] = NULL; 1525 } 1526 nat->nat_phnext[0] = NULL; 1527 1528 *nat->nat_phnext[1] = nat->nat_hnext[1]; 1529 if (nat->nat_hnext[1] != NULL) { 1530 nat->nat_hnext[1]->nat_phnext[1] = nat->nat_phnext[1]; 1531 nat->nat_hnext[1] = NULL; 1532 } 1533 nat->nat_phnext[1] = NULL; 1534 1535 if ((nat->nat_flags & SI_WILDP) != 0) 1536 nat_stats.ns_wilds--; 1537 } 1538 1539 if (nat->nat_me != NULL) { 1540 *nat->nat_me = NULL; 1541 nat->nat_me = NULL; 1542 } 1543 1544 fr_deletequeueentry(&nat->nat_tqe); 1545 1546 nat->nat_ref--; 1547 if (nat->nat_ref > 0) { 1548 MUTEX_EXIT(&ipf_nat_new); 1549 return; 1550 } 1551 1552 #ifdef IPFILTER_SYNC 1553 if (nat->nat_sync) 1554 ipfsync_del(nat->nat_sync); 1555 #endif 1556 1557 if (nat->nat_fr != NULL) 1558 (void)fr_derefrule(&nat->nat_fr); 1559 1560 if (nat->nat_hm != NULL) 1561 nat_hostmapdel(nat->nat_hm); 1562 1563 /* 1564 * If there is an active reference from the nat entry to its parent 1565 * rule, decrement the rule's reference count and free it too if no 1566 * longer being used. 1567 */ 1568 ipn = nat->nat_ptr; 1569 if (ipn != NULL) { 1570 ipn->in_space++; 1571 ipn->in_use--; 1572 if (ipn->in_use == 0 && (ipn->in_flags & IPN_DELETE)) { 1573 if (ipn->in_apr) 1574 appr_free(ipn->in_apr); 1575 KFREE(ipn); 1576 nat_stats.ns_rules--; 1577 } 1578 } 1579 1580 MUTEX_DESTROY(&nat->nat_lock); 1581 1582 aps_free(nat->nat_aps); 1583 nat_stats.ns_inuse--; 1584 MUTEX_EXIT(&ipf_nat_new); 1585 1586 /* 1587 * If there's a fragment table entry too for this nat entry, then 1588 * dereference that as well. This is after nat_lock is released 1589 * because of Tru64. 1590 */ 1591 fr_forgetnat((void *)nat); 1592 1593 KFREE(nat); 1594 } 1595 1596 1597 /* ------------------------------------------------------------------------ */ 1598 /* Function: nat_flushtable */ 1599 /* Returns: int - number of NAT rules deleted */ 1600 /* Parameters: Nil */ 1601 /* */ 1602 /* Deletes all currently active NAT sessions. In deleting each NAT entry a */ 1603 /* log record should be emitted in nat_delete() if NAT logging is enabled. */ 1604 /* ------------------------------------------------------------------------ */ 1605 /* 1606 * nat_flushtable - clear the NAT table of all mapping entries. 1607 */ 1608 static int nat_flushtable() 1609 { 1610 nat_t *nat; 1611 int j = 0; 1612 1613 /* 1614 * ALL NAT mappings deleted, so lets just make the deletions 1615 * quicker. 1616 */ 1617 if (nat_table[0] != NULL) 1618 bzero((char *)nat_table[0], 1619 sizeof(nat_table[0]) * ipf_nattable_sz); 1620 if (nat_table[1] != NULL) 1621 bzero((char *)nat_table[1], 1622 sizeof(nat_table[1]) * ipf_nattable_sz); 1623 1624 while ((nat = nat_instances) != NULL) { 1625 nat_delete(nat, NL_FLUSH); 1626 j++; 1627 } 1628 1629 nat_stats.ns_inuse = 0; 1630 return j; 1631 } 1632 1633 1634 /* ------------------------------------------------------------------------ */ 1635 /* Function: nat_clearlist */ 1636 /* Returns: int - number of NAT/RDR rules deleted */ 1637 /* Parameters: Nil */ 1638 /* */ 1639 /* Delete all rules in the current list of rules. There is nothing elegant */ 1640 /* about this cleanup: simply free all entries on the list of rules and */ 1641 /* clear out the tables used for hashed NAT rule lookups. */ 1642 /* ------------------------------------------------------------------------ */ 1643 static int nat_clearlist() 1644 { 1645 ipnat_t *n, **np = &nat_list; 1646 int i = 0; 1647 1648 if (nat_rules != NULL) 1649 bzero((char *)nat_rules, sizeof(*nat_rules) * ipf_natrules_sz); 1650 if (rdr_rules != NULL) 1651 bzero((char *)rdr_rules, sizeof(*rdr_rules) * ipf_rdrrules_sz); 1652 1653 while ((n = *np) != NULL) { 1654 *np = n->in_next; 1655 if (n->in_use == 0) { 1656 if (n->in_apr != NULL) 1657 appr_free(n->in_apr); 1658 KFREE(n); 1659 nat_stats.ns_rules--; 1660 } else { 1661 n->in_flags |= IPN_DELETE; 1662 n->in_next = NULL; 1663 } 1664 i++; 1665 } 1666 nat_masks = 0; 1667 rdr_masks = 0; 1668 return i; 1669 } 1670 1671 1672 /* ------------------------------------------------------------------------ */ 1673 /* Function: nat_newmap */ 1674 /* Returns: int - -1 == error, 0 == success */ 1675 /* Parameters: fin(I) - pointer to packet information */ 1676 /* nat(I) - pointer to NAT entry */ 1677 /* ni(I) - pointer to structure with misc. information needed */ 1678 /* to create new NAT entry. */ 1679 /* */ 1680 /* Given an empty NAT structure, populate it with new information about a */ 1681 /* new NAT session, as defined by the matching NAT rule. */ 1682 /* ni.nai_ip is passed in uninitialised and must be set, in host byte order,*/ 1683 /* to the new IP address for the translation. */ 1684 /* ------------------------------------------------------------------------ */ 1685 static INLINE int nat_newmap(fin, nat, ni) 1686 fr_info_t *fin; 1687 nat_t *nat; 1688 natinfo_t *ni; 1689 { 1690 u_short st_port, dport, sport, port, sp, dp; 1691 struct in_addr in, inb; 1692 hostmap_t *hm; 1693 u_32_t flags; 1694 u_32_t st_ip; 1695 ipnat_t *np; 1696 nat_t *natl; 1697 int l; 1698 1699 /* 1700 * If it's an outbound packet which doesn't match any existing 1701 * record, then create a new port 1702 */ 1703 l = 0; 1704 hm = NULL; 1705 np = ni->nai_np; 1706 st_ip = np->in_nip; 1707 st_port = np->in_pnext; 1708 flags = ni->nai_flags; 1709 sport = ni->nai_sport; 1710 dport = ni->nai_dport; 1711 1712 /* 1713 * Do a loop until we either run out of entries to try or we find 1714 * a NAT mapping that isn't currently being used. This is done 1715 * because the change to the source is not (usually) being fixed. 1716 */ 1717 do { 1718 port = 0; 1719 in.s_addr = htonl(np->in_nip); 1720 if (l == 0) { 1721 /* 1722 * Check to see if there is an existing NAT 1723 * setup for this IP address pair. 1724 */ 1725 hm = nat_hostmap(np, fin->fin_src, fin->fin_dst, 1726 in, 0); 1727 if (hm != NULL) 1728 in.s_addr = hm->hm_mapip.s_addr; 1729 } else if ((l == 1) && (hm != NULL)) { 1730 nat_hostmapdel(hm); 1731 hm = NULL; 1732 } 1733 in.s_addr = ntohl(in.s_addr); 1734 1735 nat->nat_hm = hm; 1736 1737 if ((np->in_outmsk == 0xffffffff) && (np->in_pnext == 0)) { 1738 if (l > 0) 1739 return -1; 1740 } 1741 1742 if (np->in_redir == NAT_BIMAP && 1743 np->in_inmsk == np->in_outmsk) { 1744 /* 1745 * map the address block in a 1:1 fashion 1746 */ 1747 in.s_addr = np->in_outip; 1748 in.s_addr |= fin->fin_saddr & ~np->in_inmsk; 1749 in.s_addr = ntohl(in.s_addr); 1750 1751 } else if (np->in_redir & NAT_MAPBLK) { 1752 if ((l >= np->in_ppip) || ((l > 0) && 1753 !(flags & IPN_TCPUDP))) 1754 return -1; 1755 /* 1756 * map-block - Calculate destination address. 1757 */ 1758 in.s_addr = ntohl(fin->fin_saddr); 1759 in.s_addr &= ntohl(~np->in_inmsk); 1760 inb.s_addr = in.s_addr; 1761 in.s_addr /= np->in_ippip; 1762 in.s_addr &= ntohl(~np->in_outmsk); 1763 in.s_addr += ntohl(np->in_outip); 1764 /* 1765 * Calculate destination port. 1766 */ 1767 if ((flags & IPN_TCPUDP) && 1768 (np->in_ppip != 0)) { 1769 port = ntohs(sport) + l; 1770 port %= np->in_ppip; 1771 port += np->in_ppip * 1772 (inb.s_addr % np->in_ippip); 1773 port += MAPBLK_MINPORT; 1774 port = htons(port); 1775 } 1776 1777 } else if ((np->in_outip == 0) && 1778 (np->in_outmsk == 0xffffffff)) { 1779 /* 1780 * 0/32 - use the interface's IP address. 1781 */ 1782 if ((l > 0) || 1783 fr_ifpaddr(4, FRI_NORMAL, fin->fin_ifp, 1784 &in, NULL) == -1) 1785 return -1; 1786 in.s_addr = ntohl(in.s_addr); 1787 1788 } else if ((np->in_outip == 0) && (np->in_outmsk == 0)) { 1789 /* 1790 * 0/0 - use the original source address/port. 1791 */ 1792 if (l > 0) 1793 return -1; 1794 in.s_addr = ntohl(fin->fin_saddr); 1795 1796 } else if ((np->in_outmsk != 0xffffffff) && 1797 (np->in_pnext == 0) && ((l > 0) || (hm == NULL))) 1798 np->in_nip++; 1799 1800 natl = NULL; 1801 1802 if ((flags & IPN_TCPUDP) && 1803 ((np->in_redir & NAT_MAPBLK) == 0) && 1804 (np->in_flags & IPN_AUTOPORTMAP)) { 1805 /* 1806 * "ports auto" (without map-block) 1807 */ 1808 if ((l > 0) && (l % np->in_ppip == 0)) { 1809 if (l > np->in_space) { 1810 return -1; 1811 } else if ((l > np->in_ppip) && 1812 np->in_outmsk != 0xffffffff) 1813 np->in_nip++; 1814 } 1815 if (np->in_ppip != 0) { 1816 port = ntohs(sport); 1817 port += (l % np->in_ppip); 1818 port %= np->in_ppip; 1819 port += np->in_ppip * 1820 (ntohl(fin->fin_saddr) % 1821 np->in_ippip); 1822 port += MAPBLK_MINPORT; 1823 port = htons(port); 1824 } 1825 1826 } else if (((np->in_redir & NAT_MAPBLK) == 0) && 1827 (flags & IPN_TCPUDPICMP) && (np->in_pnext != 0)) { 1828 /* 1829 * Standard port translation. Select next port. 1830 */ 1831 port = htons(np->in_pnext++); 1832 1833 if (np->in_pnext > ntohs(np->in_pmax)) { 1834 np->in_pnext = ntohs(np->in_pmin); 1835 if (np->in_outmsk != 0xffffffff) 1836 np->in_nip++; 1837 } 1838 } 1839 1840 if (np->in_flags & IPN_IPRANGE) { 1841 if (np->in_nip > ntohl(np->in_outmsk)) 1842 np->in_nip = ntohl(np->in_outip); 1843 } else { 1844 if ((np->in_outmsk != 0xffffffff) && 1845 ((np->in_nip + 1) & ntohl(np->in_outmsk)) > 1846 ntohl(np->in_outip)) 1847 np->in_nip = ntohl(np->in_outip) + 1; 1848 } 1849 1850 if ((port == 0) && (flags & (IPN_TCPUDPICMP|IPN_ICMPQUERY))) 1851 port = sport; 1852 1853 /* 1854 * Here we do a lookup of the connection as seen from 1855 * the outside. If an IP# pair already exists, try 1856 * again. So if you have A->B becomes C->B, you can 1857 * also have D->E become C->E but not D->B causing 1858 * another C->B. Also take protocol and ports into 1859 * account when determining whether a pre-existing 1860 * NAT setup will cause an external conflict where 1861 * this is appropriate. 1862 */ 1863 inb.s_addr = htonl(in.s_addr); 1864 sp = fin->fin_data[0]; 1865 dp = fin->fin_data[1]; 1866 fin->fin_data[0] = fin->fin_data[1]; 1867 fin->fin_data[1] = htons(port); 1868 natl = nat_inlookup(fin, flags & ~(SI_WILDP|NAT_SEARCH), 1869 (u_int)fin->fin_p, fin->fin_dst, inb); 1870 fin->fin_data[0] = sp; 1871 fin->fin_data[1] = dp; 1872 1873 /* 1874 * Has the search wrapped around and come back to the 1875 * start ? 1876 */ 1877 if ((natl != NULL) && 1878 (np->in_pnext != 0) && (st_port == np->in_pnext) && 1879 (np->in_nip != 0) && (st_ip == np->in_nip)) 1880 return -1; 1881 l++; 1882 } while (natl != NULL); 1883 1884 if (np->in_space > 0) 1885 np->in_space--; 1886 1887 /* Setup the NAT table */ 1888 nat->nat_inip = fin->fin_src; 1889 nat->nat_outip.s_addr = htonl(in.s_addr); 1890 nat->nat_oip = fin->fin_dst; 1891 if (nat->nat_hm == NULL) 1892 nat->nat_hm = nat_hostmap(np, fin->fin_src, fin->fin_dst, 1893 nat->nat_outip, 0); 1894 1895 /* 1896 * The ICMP checksum does not have a pseudo header containing 1897 * the IP addresses 1898 */ 1899 ni->nai_sum1 = LONG_SUM(ntohl(fin->fin_saddr)); 1900 ni->nai_sum2 = LONG_SUM(in.s_addr); 1901 if ((flags & IPN_TCPUDP)) { 1902 ni->nai_sum1 += ntohs(sport); 1903 ni->nai_sum2 += ntohs(port); 1904 } 1905 1906 if (flags & IPN_TCPUDP) { 1907 nat->nat_inport = sport; 1908 nat->nat_outport = port; /* sport */ 1909 nat->nat_oport = dport; 1910 ((tcphdr_t *)fin->fin_dp)->th_sport = port; 1911 } else if (flags & IPN_ICMPQUERY) { 1912 ((icmphdr_t *)fin->fin_dp)->icmp_id = port; 1913 nat->nat_inport = port; 1914 nat->nat_outport = port; 1915 } 1916 1917 ni->nai_ip.s_addr = in.s_addr; 1918 ni->nai_port = port; 1919 ni->nai_nport = dport; 1920 return 0; 1921 } 1922 1923 1924 /* ------------------------------------------------------------------------ */ 1925 /* Function: nat_newrdr */ 1926 /* Returns: int - -1 == error, 0 == success (no move), 1 == success and */ 1927 /* allow rule to be moved if IPN_ROUNDR is set. */ 1928 /* Parameters: fin(I) - pointer to packet information */ 1929 /* nat(I) - pointer to NAT entry */ 1930 /* ni(I) - pointer to structure with misc. information needed */ 1931 /* to create new NAT entry. */ 1932 /* */ 1933 /* ni.nai_ip is passed in uninitialised and must be set, in host byte order,*/ 1934 /* to the new IP address for the translation. */ 1935 /* ------------------------------------------------------------------------ */ 1936 static INLINE int nat_newrdr(fin, nat, ni) 1937 fr_info_t *fin; 1938 nat_t *nat; 1939 natinfo_t *ni; 1940 { 1941 u_short nport, dport, sport; 1942 struct in_addr in; 1943 hostmap_t *hm; 1944 u_32_t flags; 1945 ipnat_t *np; 1946 int move; 1947 1948 move = 1; 1949 hm = NULL; 1950 in.s_addr = 0; 1951 np = ni->nai_np; 1952 flags = ni->nai_flags; 1953 sport = ni->nai_sport; 1954 dport = ni->nai_dport; 1955 1956 /* 1957 * If the matching rule has IPN_STICKY set, then we want to have the 1958 * same rule kick in as before. Why would this happen? If you have 1959 * a collection of rdr rules with "round-robin sticky", the current 1960 * packet might match a different one to the previous connection but 1961 * we want the same destination to be used. 1962 */ 1963 if ((np->in_flags & (IPN_ROUNDR|IPN_STICKY)) == 1964 (IPN_ROUNDR|IPN_STICKY)) { 1965 hm = nat_hostmap(NULL, fin->fin_src, fin->fin_dst, in, 1966 (u_32_t)dport); 1967 if (hm != NULL) { 1968 in.s_addr = ntohl(hm->hm_mapip.s_addr); 1969 np = hm->hm_ipnat; 1970 ni->nai_np = np; 1971 move = 0; 1972 } 1973 } 1974 1975 /* 1976 * Otherwise, it's an inbound packet. Most likely, we don't 1977 * want to rewrite source ports and source addresses. Instead, 1978 * we want to rewrite to a fixed internal address and fixed 1979 * internal port. 1980 */ 1981 if (np->in_flags & IPN_SPLIT) { 1982 in.s_addr = np->in_nip; 1983 1984 if ((np->in_flags & (IPN_ROUNDR|IPN_STICKY)) == IPN_STICKY) { 1985 hm = nat_hostmap(np, fin->fin_src, fin->fin_dst, 1986 in, (u_32_t)dport); 1987 if (hm != NULL) { 1988 in.s_addr = hm->hm_mapip.s_addr; 1989 move = 0; 1990 } 1991 } 1992 1993 if (hm == NULL || hm->hm_ref == 1) { 1994 if (np->in_inip == htonl(in.s_addr)) { 1995 np->in_nip = ntohl(np->in_inmsk); 1996 move = 0; 1997 } else { 1998 np->in_nip = ntohl(np->in_inip); 1999 } 2000 } 2001 2002 } else if ((np->in_inip == 0) && (np->in_inmsk == 0xffffffff)) { 2003 /* 2004 * 0/32 - use the interface's IP address. 2005 */ 2006 if (fr_ifpaddr(4, FRI_NORMAL, fin->fin_ifp, &in, NULL) == -1) 2007 return -1; 2008 in.s_addr = ntohl(in.s_addr); 2009 2010 } else if ((np->in_inip == 0) && (np->in_inmsk== 0)) { 2011 /* 2012 * 0/0 - use the original destination address/port. 2013 */ 2014 in.s_addr = ntohl(fin->fin_daddr); 2015 2016 } else if (np->in_redir == NAT_BIMAP && 2017 np->in_inmsk == np->in_outmsk) { 2018 /* 2019 * map the address block in a 1:1 fashion 2020 */ 2021 in.s_addr = np->in_inip; 2022 in.s_addr |= fin->fin_daddr & ~np->in_inmsk; 2023 in.s_addr = ntohl(in.s_addr); 2024 } else { 2025 in.s_addr = ntohl(np->in_inip); 2026 } 2027 2028 if ((np->in_pnext == 0) || ((flags & NAT_NOTRULEPORT) != 0)) 2029 nport = dport; 2030 else { 2031 /* 2032 * Whilst not optimized for the case where 2033 * pmin == pmax, the gain is not significant. 2034 */ 2035 if (((np->in_flags & IPN_FIXEDDPORT) == 0) && 2036 (np->in_pmin != np->in_pmax)) { 2037 nport = ntohs(dport) - ntohs(np->in_pmin) + 2038 ntohs(np->in_pnext); 2039 nport = htons(nport); 2040 } else 2041 nport = np->in_pnext; 2042 } 2043 2044 /* 2045 * When the redirect-to address is set to 0.0.0.0, just 2046 * assume a blank `forwarding' of the packet. We don't 2047 * setup any translation for this either. 2048 */ 2049 if (in.s_addr == 0) { 2050 if (nport == dport) 2051 return -1; 2052 in.s_addr = ntohl(fin->fin_daddr); 2053 } 2054 2055 nat->nat_inip.s_addr = htonl(in.s_addr); 2056 nat->nat_outip = fin->fin_dst; 2057 nat->nat_oip = fin->fin_src; 2058 2059 ni->nai_sum1 = LONG_SUM(ntohl(fin->fin_daddr)) + ntohs(dport); 2060 ni->nai_sum2 = LONG_SUM(in.s_addr) + ntohs(nport); 2061 2062 ni->nai_ip.s_addr = in.s_addr; 2063 ni->nai_nport = nport; 2064 ni->nai_port = sport; 2065 2066 if (flags & IPN_TCPUDP) { 2067 nat->nat_inport = nport; 2068 nat->nat_outport = dport; 2069 nat->nat_oport = sport; 2070 ((tcphdr_t *)fin->fin_dp)->th_dport = nport; 2071 } else if (flags & IPN_ICMPQUERY) { 2072 ((icmphdr_t *)fin->fin_dp)->icmp_id = nport; 2073 nat->nat_inport = nport; 2074 nat->nat_outport = nport; 2075 } 2076 2077 return move; 2078 } 2079 2080 /* ------------------------------------------------------------------------ */ 2081 /* Function: nat_new */ 2082 /* Returns: nat_t* - NULL == failure to create new NAT structure, */ 2083 /* else pointer to new NAT structure */ 2084 /* Parameters: fin(I) - pointer to packet information */ 2085 /* np(I) - pointer to NAT rule */ 2086 /* natsave(I) - pointer to where to store NAT struct pointer */ 2087 /* flags(I) - flags describing the current packet */ 2088 /* direction(I) - direction of packet (in/out) */ 2089 /* Write Lock: ipf_nat */ 2090 /* */ 2091 /* Attempts to create a new NAT entry. Does not actually change the packet */ 2092 /* in any way. */ 2093 /* */ 2094 /* This fucntion is in three main parts: (1) deal with creating a new NAT */ 2095 /* structure for a "MAP" rule (outgoing NAT translation); (2) deal with */ 2096 /* creating a new NAT structure for a "RDR" rule (incoming NAT translation) */ 2097 /* and (3) building that structure and putting it into the NAT table(s). */ 2098 /* ------------------------------------------------------------------------ */ 2099 nat_t *nat_new(fin, np, natsave, flags, direction) 2100 fr_info_t *fin; 2101 ipnat_t *np; 2102 nat_t **natsave; 2103 u_int flags; 2104 int direction; 2105 { 2106 u_short port = 0, sport = 0, dport = 0, nport = 0; 2107 tcphdr_t *tcp = NULL; 2108 hostmap_t *hm = NULL; 2109 struct in_addr in; 2110 nat_t *nat, *natl; 2111 u_int nflags; 2112 natinfo_t ni; 2113 u_32_t sumd; 2114 int move; 2115 2116 if (nat_stats.ns_inuse >= ipf_nattable_max) { 2117 nat_stats.ns_memfail++; 2118 return NULL; 2119 } 2120 2121 move = 1; 2122 nflags = np->in_flags & flags; 2123 nflags &= NAT_FROMRULE; 2124 2125 ni.nai_np = np; 2126 ni.nai_nflags = nflags; 2127 ni.nai_flags = flags; 2128 2129 /* Give me a new nat */ 2130 KMALLOC(nat, nat_t *); 2131 if (nat == NULL) { 2132 nat_stats.ns_memfail++; 2133 /* 2134 * Try to automatically tune the max # of entries in the 2135 * table allowed to be less than what will cause kmem_alloc() 2136 * to fail and try to eliminate panics due to out of memory 2137 * conditions arising. 2138 */ 2139 if (ipf_nattable_max > ipf_nattable_sz) { 2140 ipf_nattable_max = nat_stats.ns_inuse - 100; 2141 printf("ipf_nattable_max reduced to %d\n", 2142 ipf_nattable_max); 2143 } 2144 return NULL; 2145 } 2146 2147 if (flags & IPN_TCPUDP) { 2148 tcp = fin->fin_dp; 2149 ni.nai_sport = htons(fin->fin_sport); 2150 ni.nai_dport = htons(fin->fin_dport); 2151 } else if (flags & IPN_ICMPQUERY) { 2152 /* 2153 * In the ICMP query NAT code, we translate the ICMP id fields 2154 * to make them unique. This is indepedent of the ICMP type 2155 * (e.g. in the unlikely event that a host sends an echo and 2156 * an tstamp request with the same id, both packets will have 2157 * their ip address/id field changed in the same way). 2158 */ 2159 /* The icmp_id field is used by the sender to identify the 2160 * process making the icmp request. (the receiver justs 2161 * copies it back in its response). So, it closely matches 2162 * the concept of source port. We overlay sport, so we can 2163 * maximally reuse the existing code. 2164 */ 2165 ni.nai_sport = ((icmphdr_t *)fin->fin_dp)->icmp_id; 2166 ni.nai_dport = ni.nai_sport; 2167 } 2168 2169 bzero((char *)nat, sizeof(*nat)); 2170 nat->nat_flags = flags; 2171 2172 if ((flags & NAT_SLAVE) == 0) { 2173 MUTEX_ENTER(&ipf_nat_new); 2174 } 2175 2176 /* 2177 * Search the current table for a match. 2178 */ 2179 if (direction == NAT_OUTBOUND) { 2180 /* 2181 * We can now arrange to call this for the same connection 2182 * because ipf_nat_new doesn't protect the code path into 2183 * this function. 2184 */ 2185 natl = nat_outlookup(fin, nflags, (u_int)fin->fin_p, 2186 fin->fin_src, fin->fin_dst); 2187 if (natl != NULL) { 2188 nat = natl; 2189 goto done; 2190 } 2191 2192 move = nat_newmap(fin, nat, &ni); 2193 if (move == -1) 2194 goto badnat; 2195 2196 np = ni.nai_np; 2197 in = ni.nai_ip; 2198 } else { 2199 /* 2200 * NAT_INBOUND is used only for redirects rules 2201 */ 2202 natl = nat_inlookup(fin, nflags, (u_int)fin->fin_p, 2203 fin->fin_src, fin->fin_dst); 2204 if (natl != NULL) { 2205 nat = natl; 2206 goto done; 2207 } 2208 2209 move = nat_newrdr(fin, nat, &ni); 2210 if (move == -1) 2211 goto badnat; 2212 2213 np = ni.nai_np; 2214 in = ni.nai_ip; 2215 } 2216 port = ni.nai_port; 2217 nport = ni.nai_nport; 2218 2219 if ((move == 1) && (np->in_flags & IPN_ROUNDR)) { 2220 if (np->in_redir == NAT_REDIRECT) { 2221 nat_delrdr(np); 2222 nat_addrdr(np); 2223 } else if (np->in_redir == NAT_MAP) { 2224 nat_delnat(np); 2225 nat_addnat(np); 2226 } 2227 } 2228 2229 if (flags & IPN_TCPUDP) { 2230 sport = ni.nai_sport; 2231 dport = ni.nai_dport; 2232 } else if (flags & IPN_ICMPQUERY) { 2233 sport = ni.nai_sport; 2234 dport = 0; 2235 } 2236 2237 /* 2238 * nat_sumd[0] stores adjustment value including both IP address and 2239 * port number changes. nat_sumd[1] stores adjustment value only for 2240 * IP address changes, to be used for pseudo header adjustment, in 2241 * case hardware partial checksum offload is offered. 2242 */ 2243 CALC_SUMD(ni.nai_sum1, ni.nai_sum2, sumd); 2244 nat->nat_sumd[0] = (sumd & 0xffff) + (sumd >> 16); 2245 #if SOLARIS && defined(_KERNEL) && (SOLARIS2 >= 6) 2246 if (flags & IPN_TCPUDP) { 2247 ni.nai_sum1 = LONG_SUM(in.s_addr); 2248 if (direction == NAT_OUTBOUND) 2249 ni.nai_sum2 = LONG_SUM(ntohl(fin->fin_saddr)); 2250 else 2251 ni.nai_sum2 = LONG_SUM(ntohl(fin->fin_daddr)); 2252 2253 CALC_SUMD(ni.nai_sum1, ni.nai_sum2, sumd); 2254 nat->nat_sumd[1] = (sumd & 0xffff) + (sumd >> 16); 2255 } else 2256 #endif 2257 nat->nat_sumd[1] = nat->nat_sumd[0]; 2258 2259 if ((flags & IPN_TCPUDPICMP) && ((sport != port) || (dport != nport))) { 2260 if (direction == NAT_OUTBOUND) 2261 ni.nai_sum1 = LONG_SUM(ntohl(fin->fin_saddr)); 2262 else 2263 ni.nai_sum1 = LONG_SUM(ntohl(fin->fin_daddr)); 2264 2265 ni.nai_sum2 = LONG_SUM(in.s_addr); 2266 2267 CALC_SUMD(ni.nai_sum1, ni.nai_sum2, sumd); 2268 nat->nat_ipsumd = (sumd & 0xffff) + (sumd >> 16); 2269 } else { 2270 nat->nat_ipsumd = nat->nat_sumd[0]; 2271 if (!(flags & IPN_TCPUDPICMP)) { 2272 nat->nat_sumd[0] = 0; 2273 nat->nat_sumd[1] = 0; 2274 } 2275 } 2276 2277 if (nat_finalise(fin, nat, &ni, tcp, natsave, direction) == -1) { 2278 goto badnat; 2279 } 2280 if (flags & SI_WILDP) 2281 nat_stats.ns_wilds++; 2282 goto done; 2283 badnat: 2284 nat_stats.ns_badnat++; 2285 if ((hm = nat->nat_hm) != NULL) 2286 nat_hostmapdel(hm); 2287 KFREE(nat); 2288 nat = NULL; 2289 done: 2290 if ((flags & NAT_SLAVE) == 0) { 2291 MUTEX_EXIT(&ipf_nat_new); 2292 } 2293 return nat; 2294 } 2295 2296 2297 /* ------------------------------------------------------------------------ */ 2298 /* Function: nat_finalise */ 2299 /* Returns: int - 0 == sucess, -1 == failure */ 2300 /* Parameters: fin(I) - pointer to packet information */ 2301 /* nat(I) - pointer to NAT entry */ 2302 /* ni(I) - pointer to structure with misc. information needed */ 2303 /* to create new NAT entry. */ 2304 /* Write Lock: ipf_nat */ 2305 /* */ 2306 /* This is the tail end of constructing a new NAT entry and is the same */ 2307 /* for both IPv4 and IPv6. */ 2308 /* ------------------------------------------------------------------------ */ 2309 /*ARGSUSED*/ 2310 static INLINE int nat_finalise(fin, nat, ni, tcp, natsave, direction) 2311 fr_info_t *fin; 2312 nat_t *nat; 2313 natinfo_t *ni; 2314 tcphdr_t *tcp; 2315 nat_t **natsave; 2316 int direction; 2317 { 2318 frentry_t *fr; 2319 ipnat_t *np; 2320 2321 np = ni->nai_np; 2322 2323 COPYIFNAME(fin->fin_ifp, nat->nat_ifnames[0], fin->fin_v); 2324 2325 #ifdef IPFILTER_SYNC 2326 if ((nat->nat_flags & SI_CLONE) == 0) 2327 nat->nat_sync = ipfsync_new(SMC_NAT, fin, nat); 2328 #endif 2329 2330 nat->nat_me = natsave; 2331 nat->nat_dir = direction; 2332 nat->nat_ifps[0] = np->in_ifps[0]; 2333 nat->nat_ifps[1] = np->in_ifps[1]; 2334 nat->nat_ptr = np; 2335 nat->nat_p = fin->fin_p; 2336 nat->nat_mssclamp = np->in_mssclamp; 2337 fr = fin->fin_fr; 2338 nat->nat_fr = fr; 2339 2340 if ((np->in_apr != NULL) && ((ni->nai_flags & NAT_SLAVE) == 0)) 2341 if (appr_new(fin, nat) == -1) 2342 return -1; 2343 2344 if (nat_insert(nat, fin->fin_rev) == 0) { 2345 if (nat_logging) 2346 nat_log(nat, (u_int)np->in_redir); 2347 np->in_use++; 2348 if (fr != NULL) { 2349 MUTEX_ENTER(&fr->fr_lock); 2350 fr->fr_ref++; 2351 MUTEX_EXIT(&fr->fr_lock); 2352 } 2353 return 0; 2354 } 2355 2356 /* 2357 * nat_insert failed, so cleanup time... 2358 */ 2359 return -1; 2360 } 2361 2362 2363 /* ------------------------------------------------------------------------ */ 2364 /* Function: nat_insert */ 2365 /* Returns: int - 0 == sucess, -1 == failure */ 2366 /* Parameters: nat(I) - pointer to NAT structure */ 2367 /* rev(I) - flag indicating forward/reverse direction of packet */ 2368 /* Write Lock: ipf_nat */ 2369 /* */ 2370 /* Insert a NAT entry into the hash tables for searching and add it to the */ 2371 /* list of active NAT entries. Adjust global counters when complete. */ 2372 /* ------------------------------------------------------------------------ */ 2373 int nat_insert(nat, rev) 2374 nat_t *nat; 2375 int rev; 2376 { 2377 u_int hv1, hv2; 2378 nat_t **natp; 2379 2380 /* 2381 * Try and return an error as early as possible, so calculate the hash 2382 * entry numbers first and then proceed. 2383 */ 2384 if ((nat->nat_flags & (SI_W_SPORT|SI_W_DPORT)) == 0) { 2385 hv1 = NAT_HASH_FN(nat->nat_inip.s_addr, nat->nat_inport, 2386 0xffffffff); 2387 hv1 = NAT_HASH_FN(nat->nat_oip.s_addr, hv1 + nat->nat_oport, 2388 ipf_nattable_sz); 2389 hv2 = NAT_HASH_FN(nat->nat_outip.s_addr, nat->nat_outport, 2390 0xffffffff); 2391 hv2 = NAT_HASH_FN(nat->nat_oip.s_addr, hv2 + nat->nat_oport, 2392 ipf_nattable_sz); 2393 } else { 2394 hv1 = NAT_HASH_FN(nat->nat_inip.s_addr, 0, 0xffffffff); 2395 hv1 = NAT_HASH_FN(nat->nat_oip.s_addr, hv1, ipf_nattable_sz); 2396 hv2 = NAT_HASH_FN(nat->nat_outip.s_addr, 0, 0xffffffff); 2397 hv2 = NAT_HASH_FN(nat->nat_oip.s_addr, hv2, ipf_nattable_sz); 2398 } 2399 2400 if (nat_stats.ns_bucketlen[0][hv1] >= fr_nat_maxbucket || 2401 nat_stats.ns_bucketlen[1][hv2] >= fr_nat_maxbucket) { 2402 return -1; 2403 } 2404 2405 nat->nat_hv[0] = hv1; 2406 nat->nat_hv[1] = hv2; 2407 2408 MUTEX_INIT(&nat->nat_lock, "nat entry lock"); 2409 2410 nat->nat_rev = rev; 2411 nat->nat_ref = 1; 2412 nat->nat_bytes[0] = 0; 2413 nat->nat_pkts[0] = 0; 2414 nat->nat_bytes[1] = 0; 2415 nat->nat_pkts[1] = 0; 2416 2417 nat->nat_ifnames[0][LIFNAMSIZ - 1] = '\0'; 2418 nat->nat_ifps[0] = fr_resolvenic(nat->nat_ifnames[0], 4); 2419 2420 if (nat->nat_ifnames[1][0] !='\0') { 2421 nat->nat_ifnames[1][LIFNAMSIZ - 1] = '\0'; 2422 nat->nat_ifps[1] = fr_resolvenic(nat->nat_ifnames[1], 4); 2423 } else { 2424 (void) strncpy(nat->nat_ifnames[1], nat->nat_ifnames[0], 2425 LIFNAMSIZ); 2426 nat->nat_ifnames[1][LIFNAMSIZ - 1] = '\0'; 2427 nat->nat_ifps[1] = nat->nat_ifps[0]; 2428 } 2429 2430 nat->nat_next = nat_instances; 2431 nat->nat_pnext = &nat_instances; 2432 if (nat_instances) 2433 nat_instances->nat_pnext = &nat->nat_next; 2434 nat_instances = nat; 2435 2436 natp = &nat_table[0][hv1]; 2437 if (*natp) 2438 (*natp)->nat_phnext[0] = &nat->nat_hnext[0]; 2439 nat->nat_phnext[0] = natp; 2440 nat->nat_hnext[0] = *natp; 2441 *natp = nat; 2442 nat_stats.ns_bucketlen[0][hv1]++; 2443 2444 natp = &nat_table[1][hv2]; 2445 if (*natp) 2446 (*natp)->nat_phnext[1] = &nat->nat_hnext[1]; 2447 nat->nat_phnext[1] = natp; 2448 nat->nat_hnext[1] = *natp; 2449 *natp = nat; 2450 nat_stats.ns_bucketlen[1][hv2]++; 2451 2452 fr_setnatqueue(nat, rev); 2453 2454 nat_stats.ns_added++; 2455 nat_stats.ns_inuse++; 2456 return 0; 2457 } 2458 2459 2460 /* ------------------------------------------------------------------------ */ 2461 /* Function: nat_icmperrorlookup */ 2462 /* Returns: nat_t* - point to matching NAT structure */ 2463 /* Parameters: fin(I) - pointer to packet information */ 2464 /* dir(I) - direction of packet (in/out) */ 2465 /* */ 2466 /* Check if the ICMP error message is related to an existing TCP, UDP or */ 2467 /* ICMP query nat entry. It is assumed that the packet is already of the */ 2468 /* the required length. */ 2469 /* ------------------------------------------------------------------------ */ 2470 nat_t *nat_icmperrorlookup(fin, dir) 2471 fr_info_t *fin; 2472 int dir; 2473 { 2474 int flags = 0, minlen; 2475 icmphdr_t *orgicmp; 2476 tcphdr_t *tcp = NULL; 2477 u_short data[2]; 2478 nat_t *nat; 2479 ip_t *oip; 2480 u_int p; 2481 2482 /* 2483 * Does it at least have the return (basic) IP header ? 2484 * Only a basic IP header (no options) should be with an ICMP error 2485 * header. Also, if it's not an error type, then return. 2486 */ 2487 if ((fin->fin_hlen != sizeof(ip_t)) || !(fin->fin_flx & FI_ICMPERR)) 2488 return NULL; 2489 2490 /* 2491 * Check packet size 2492 */ 2493 oip = (ip_t *)((char *)fin->fin_dp + 8); 2494 minlen = IP_HL(oip) << 2; 2495 if ((minlen < sizeof(ip_t)) || 2496 (fin->fin_plen < ICMPERR_IPICMPHLEN + minlen)) 2497 return NULL; 2498 /* 2499 * Is the buffer big enough for all of it ? It's the size of the IP 2500 * header claimed in the encapsulated part which is of concern. It 2501 * may be too big to be in this buffer but not so big that it's 2502 * outside the ICMP packet, leading to TCP deref's causing problems. 2503 * This is possible because we don't know how big oip_hl is when we 2504 * do the pullup early in fr_check() and thus can't gaurantee it is 2505 * all here now. 2506 */ 2507 #ifdef _KERNEL 2508 { 2509 mb_t *m; 2510 2511 m = fin->fin_m; 2512 # if defined(MENTAT) 2513 if ((char *)oip + fin->fin_dlen - ICMPERR_ICMPHLEN > (char *)m->b_wptr) 2514 return NULL; 2515 # else 2516 if ((char *)oip + fin->fin_dlen - ICMPERR_ICMPHLEN > 2517 (char *)fin->fin_ip + M_LEN(m)) 2518 return NULL; 2519 # endif 2520 } 2521 #endif 2522 2523 if (fin->fin_daddr != oip->ip_src.s_addr) 2524 return NULL; 2525 2526 p = oip->ip_p; 2527 if (p == IPPROTO_TCP) 2528 flags = IPN_TCP; 2529 else if (p == IPPROTO_UDP) 2530 flags = IPN_UDP; 2531 else if (p == IPPROTO_ICMP) { 2532 orgicmp = (icmphdr_t *)((char *)oip + (IP_HL(oip) << 2)); 2533 2534 /* see if this is related to an ICMP query */ 2535 if (nat_icmpquerytype4(orgicmp->icmp_type)) { 2536 data[0] = fin->fin_data[0]; 2537 data[1] = fin->fin_data[1]; 2538 fin->fin_data[0] = 0; 2539 fin->fin_data[1] = orgicmp->icmp_id; 2540 2541 flags = IPN_ICMPERR|IPN_ICMPQUERY; 2542 /* 2543 * NOTE : dir refers to the direction of the original 2544 * ip packet. By definition the icmp error 2545 * message flows in the opposite direction. 2546 */ 2547 if (dir == NAT_INBOUND) 2548 nat = nat_inlookup(fin, flags, p, oip->ip_dst, 2549 oip->ip_src); 2550 else 2551 nat = nat_outlookup(fin, flags, p, oip->ip_dst, 2552 oip->ip_src); 2553 fin->fin_data[0] = data[0]; 2554 fin->fin_data[1] = data[1]; 2555 return nat; 2556 } 2557 } 2558 2559 if (flags & IPN_TCPUDP) { 2560 minlen += 8; /* + 64bits of data to get ports */ 2561 if (fin->fin_plen < ICMPERR_IPICMPHLEN + minlen) 2562 return NULL; 2563 2564 data[0] = fin->fin_data[0]; 2565 data[1] = fin->fin_data[1]; 2566 tcp = (tcphdr_t *)((char *)oip + (IP_HL(oip) << 2)); 2567 fin->fin_data[0] = ntohs(tcp->th_dport); 2568 fin->fin_data[1] = ntohs(tcp->th_sport); 2569 2570 if (dir == NAT_INBOUND) { 2571 nat = nat_inlookup(fin, flags, p, oip->ip_dst, 2572 oip->ip_src); 2573 } else { 2574 nat = nat_outlookup(fin, flags, p, oip->ip_dst, 2575 oip->ip_src); 2576 } 2577 fin->fin_data[0] = data[0]; 2578 fin->fin_data[1] = data[1]; 2579 return nat; 2580 } 2581 if (dir == NAT_INBOUND) 2582 return nat_inlookup(fin, 0, p, oip->ip_dst, oip->ip_src); 2583 else 2584 return nat_outlookup(fin, 0, p, oip->ip_dst, oip->ip_src); 2585 } 2586 2587 2588 /* ------------------------------------------------------------------------ */ 2589 /* Function: nat_icmperror */ 2590 /* Returns: nat_t* - point to matching NAT structure */ 2591 /* Parameters: fin(I) - pointer to packet information */ 2592 /* nflags(I) - NAT flags for this packet */ 2593 /* dir(I) - direction of packet (in/out) */ 2594 /* */ 2595 /* Fix up an ICMP packet which is an error message for an existing NAT */ 2596 /* session. This will correct both packet header data and checksums. */ 2597 /* */ 2598 /* This should *ONLY* be used for incoming ICMP error packets to make sure */ 2599 /* a NAT'd ICMP packet gets correctly recognised. */ 2600 /* ------------------------------------------------------------------------ */ 2601 nat_t *nat_icmperror(fin, nflags, dir) 2602 fr_info_t *fin; 2603 u_int *nflags; 2604 int dir; 2605 { 2606 u_32_t sum1, sum2, sumd, psum1, psum2, psumd, sumd2; 2607 struct in_addr in; 2608 icmphdr_t *icmp, *orgicmp; 2609 int dlen; 2610 udphdr_t *udp; 2611 tcphdr_t *tcp; 2612 nat_t *nat; 2613 ip_t *oip; 2614 if ((fin->fin_flx & (FI_SHORT|FI_FRAGBODY))) 2615 return NULL; 2616 2617 /* 2618 * nat_icmperrorlookup() looks up nat entry associated with the 2619 * offending IP packet and returns pointer to the entry, or NULL 2620 * if packet wasn't natted or for `defective' packets. 2621 */ 2622 2623 if ((fin->fin_v != 4) || !(nat = nat_icmperrorlookup(fin, dir))) 2624 return NULL; 2625 2626 sumd2 = 0; 2627 *nflags = IPN_ICMPERR; 2628 icmp = fin->fin_dp; 2629 oip = (ip_t *)&icmp->icmp_ip; 2630 udp = (udphdr_t *)((((char *)oip) + (IP_HL(oip) << 2))); 2631 tcp = (tcphdr_t *)udp; 2632 dlen = fin->fin_plen - ((char *)udp - (char *)fin->fin_ip); 2633 2634 /* 2635 * Need to adjust ICMP header to include the real IP#'s and 2636 * port #'s. There are three steps required. 2637 * 2638 * Step 1 2639 * Fix the IP addresses in the offending IP packet and update 2640 * ip header checksum to compensate for the change. 2641 * 2642 * No update needed here for icmp_cksum because the ICMP checksum 2643 * is calculated over the complete ICMP packet, which includes the 2644 * changed oip IP addresses and oip->ip_sum. These two changes 2645 * cancel each other out (if the delta for the IP address is x, 2646 * then the delta for ip_sum is minus x). 2647 */ 2648 2649 if (oip->ip_dst.s_addr == nat->nat_oip.s_addr) { 2650 sum1 = LONG_SUM(ntohl(oip->ip_src.s_addr)); 2651 in = nat->nat_inip; 2652 oip->ip_src = in; 2653 } else { 2654 sum1 = LONG_SUM(ntohl(oip->ip_dst.s_addr)); 2655 in = nat->nat_outip; 2656 oip->ip_dst = in; 2657 } 2658 2659 sum2 = LONG_SUM(ntohl(in.s_addr)); 2660 CALC_SUMD(sum1, sum2, sumd); 2661 fix_datacksum(&oip->ip_sum, sumd); 2662 2663 /* 2664 * Step 2 2665 * Perform other adjustments based on protocol of offending packet. 2666 */ 2667 2668 switch (oip->ip_p) { 2669 case IPPROTO_TCP : 2670 case IPPROTO_UDP : 2671 2672 /* 2673 * For offending TCP/UDP IP packets, translate the ports 2674 * based on the NAT specification. 2675 * 2676 * Advance notice : Now it becomes complicated :-) 2677 * 2678 * Since the port and IP addresse fields are both part 2679 * of the TCP/UDP checksum of the offending IP packet, 2680 * we need to adjust that checksum as well. 2681 * 2682 * To further complicate things, the TCP/UDP checksum 2683 * may not be present. We must check to see if the 2684 * length of the data portion is big enough to hold 2685 * the checksum. In the UDP case, a test to determine 2686 * if the checksum is even set is also required. 2687 * 2688 * Any changes to an IP address, port or checksum within 2689 * the ICMP packet requires a change to icmp_cksum. 2690 * 2691 * Be extremely careful here ... The change is dependent 2692 * upon whether or not the TCP/UPD checksum is present. 2693 * 2694 * If TCP/UPD checksum is present, the icmp_cksum must 2695 * compensate for checksum modification resulting from 2696 * IP address change only. Port change and resulting 2697 * data checksum adjustments cancel each other out. 2698 * 2699 * If TCP/UDP checksum is not present, icmp_cksum must 2700 * compensate for port change only. The IP address 2701 * change does not modify anything else in this case. 2702 */ 2703 2704 psum1 = 0; 2705 psum2 = 0; 2706 psumd = 0; 2707 2708 if ((tcp->th_dport == nat->nat_oport) && 2709 (tcp->th_sport != nat->nat_inport)) { 2710 2711 /* 2712 * Translate the source port. 2713 */ 2714 2715 psum1 = ntohs(tcp->th_sport); 2716 psum2 = ntohs(nat->nat_inport); 2717 tcp->th_sport = nat->nat_inport; 2718 2719 } else if ((tcp->th_sport == nat->nat_oport) && 2720 (tcp->th_dport != nat->nat_outport)) { 2721 2722 /* 2723 * Translate the destination port. 2724 */ 2725 2726 psum1 = ntohs(tcp->th_dport); 2727 psum2 = ntohs(nat->nat_outport); 2728 tcp->th_dport = nat->nat_outport; 2729 } 2730 2731 if ((oip->ip_p == IPPROTO_TCP) && (dlen >= 18)) { 2732 2733 /* 2734 * TCP checksum present. 2735 * 2736 * Adjust data checksum and icmp checksum to 2737 * compensate for any IP address change. 2738 */ 2739 2740 sum1 = ntohs(tcp->th_sum); 2741 fix_datacksum(&tcp->th_sum, sumd); 2742 sum2 = ntohs(tcp->th_sum); 2743 sumd2 = sumd << 1; 2744 CALC_SUMD(sum1, sum2, sumd); 2745 sumd2 += sumd; 2746 2747 /* 2748 * Also make data checksum adjustment to 2749 * compensate for any port change. 2750 */ 2751 2752 if (psum1 != psum2) { 2753 CALC_SUMD(psum1, psum2, psumd); 2754 fix_datacksum(&tcp->th_sum, psumd); 2755 } 2756 2757 } else if ((oip->ip_p == IPPROTO_UDP) && 2758 (dlen >= 8) && (udp->uh_sum != 0)) { 2759 2760 /* 2761 * The UDP checksum is present and set. 2762 * 2763 * Adjust data checksum and icmp checksum to 2764 * compensate for any IP address change. 2765 */ 2766 2767 sum1 = ntohs(udp->uh_sum); 2768 fix_datacksum(&udp->uh_sum, sumd); 2769 sum2 = ntohs(udp->uh_sum); 2770 sumd2 = sumd << 1; 2771 CALC_SUMD(sum1, sum2, sumd); 2772 sumd2 += sumd; 2773 2774 /* 2775 * Also make data checksum adjustment to 2776 * compensate for any port change. 2777 */ 2778 2779 if (psum1 != psum2) { 2780 CALC_SUMD(psum1, psum2, psumd); 2781 fix_datacksum(&udp->uh_sum, psumd); 2782 } 2783 2784 } else { 2785 2786 /* 2787 * Data checksum was not present. 2788 * 2789 * Compensate for any port change. 2790 */ 2791 2792 CALC_SUMD(psum2, psum1, psumd); 2793 sumd2 += psumd; 2794 } 2795 break; 2796 2797 case IPPROTO_ICMP : 2798 2799 orgicmp = (icmphdr_t *)udp; 2800 2801 if ((nat->nat_dir == NAT_OUTBOUND) && 2802 (orgicmp->icmp_id != nat->nat_inport) && 2803 (dlen >= 8)) { 2804 2805 /* 2806 * Fix ICMP checksum (of the offening ICMP 2807 * query packet) to compensate the change 2808 * in the ICMP id of the offending ICMP 2809 * packet. 2810 * 2811 * Since you modify orgicmp->icmp_id with 2812 * a delta (say x) and you compensate that 2813 * in origicmp->icmp_cksum with a delta 2814 * minus x, you don't have to adjust the 2815 * overall icmp->icmp_cksum 2816 */ 2817 2818 sum1 = ntohs(orgicmp->icmp_id); 2819 sum2 = ntohs(nat->nat_inport); 2820 CALC_SUMD(sum1, sum2, sumd); 2821 orgicmp->icmp_id = nat->nat_inport; 2822 fix_datacksum(&orgicmp->icmp_cksum, sumd); 2823 2824 } /* nat_dir can't be NAT_INBOUND for icmp queries */ 2825 2826 break; 2827 2828 default : 2829 2830 break; 2831 2832 } /* switch (oip->ip_p) */ 2833 2834 /* 2835 * Step 3 2836 * Make the adjustments to icmp checksum. 2837 */ 2838 2839 if (sumd2 != 0) { 2840 sumd2 = (sumd2 & 0xffff) + (sumd2 >> 16); 2841 sumd2 = (sumd2 & 0xffff) + (sumd2 >> 16); 2842 fix_incksum(&icmp->icmp_cksum, sumd2); 2843 } 2844 return nat; 2845 } 2846 2847 2848 /* 2849 * NB: these lookups don't lock access to the list, it assumed that it has 2850 * already been done! 2851 */ 2852 2853 /* ------------------------------------------------------------------------ */ 2854 /* Function: nat_inlookup */ 2855 /* Returns: nat_t* - NULL == no match, */ 2856 /* else pointer to matching NAT entry */ 2857 /* Parameters: fin(I) - pointer to packet information */ 2858 /* flags(I) - NAT flags for this packet */ 2859 /* p(I) - protocol for this packet */ 2860 /* src(I) - source IP address */ 2861 /* mapdst(I) - destination IP address */ 2862 /* */ 2863 /* Lookup a nat entry based on the mapped destination ip address/port and */ 2864 /* real source address/port. We use this lookup when receiving a packet, */ 2865 /* we're looking for a table entry, based on the destination address. */ 2866 /* */ 2867 /* NOTE: THE PACKET BEING CHECKED (IF FOUND) HAS A MAPPING ALREADY. */ 2868 /* */ 2869 /* NOTE: IT IS ASSUMED THAT ipf_nat IS ONLY HELD WITH A READ LOCK WHEN */ 2870 /* THIS FUNCTION IS CALLED WITH NAT_SEARCH SET IN nflags. */ 2871 /* */ 2872 /* flags -> relevant are IPN_UDP/IPN_TCP/IPN_ICMPQUERY that indicate if */ 2873 /* the packet is of said protocol */ 2874 /* ------------------------------------------------------------------------ */ 2875 nat_t *nat_inlookup(fin, flags, p, src, mapdst) 2876 fr_info_t *fin; 2877 u_int flags, p; 2878 struct in_addr src , mapdst; 2879 { 2880 u_short sport, dport; 2881 ipnat_t *ipn; 2882 u_int sflags; 2883 nat_t *nat; 2884 int nflags; 2885 u_32_t dst; 2886 void *ifp; 2887 u_int hv; 2888 2889 if (fin != NULL) 2890 ifp = fin->fin_ifp; 2891 else 2892 ifp = NULL; 2893 sport = 0; 2894 dport = 0; 2895 dst = mapdst.s_addr; 2896 sflags = flags & NAT_TCPUDPICMP; 2897 2898 switch (p) 2899 { 2900 case IPPROTO_TCP : 2901 case IPPROTO_UDP : 2902 sport = htons(fin->fin_data[0]); 2903 dport = htons(fin->fin_data[1]); 2904 break; 2905 case IPPROTO_ICMP : 2906 if (flags & IPN_ICMPERR) 2907 sport = fin->fin_data[1]; 2908 else 2909 dport = fin->fin_data[1]; 2910 break; 2911 default : 2912 break; 2913 } 2914 2915 2916 if ((flags & SI_WILDP) != 0) 2917 goto find_in_wild_ports; 2918 2919 hv = NAT_HASH_FN(dst, dport, 0xffffffff); 2920 hv = NAT_HASH_FN(src.s_addr, hv + sport, ipf_nattable_sz); 2921 nat = nat_table[1][hv]; 2922 for (; nat; nat = nat->nat_hnext[1]) { 2923 if (nat->nat_ifps[0] != NULL) { 2924 if ((ifp != NULL) && (ifp != nat->nat_ifps[0])) 2925 continue; 2926 } else if (ifp != NULL) 2927 nat->nat_ifps[0] = ifp; 2928 2929 nflags = nat->nat_flags; 2930 2931 if (nat->nat_oip.s_addr == src.s_addr && 2932 nat->nat_outip.s_addr == dst && 2933 (((p == 0) && 2934 (sflags == (nat->nat_flags & IPN_TCPUDPICMP))) 2935 || (p == nat->nat_p))) { 2936 switch (p) 2937 { 2938 #if 0 2939 case IPPROTO_GRE : 2940 if (nat->nat_call[1] != fin->fin_data[0]) 2941 continue; 2942 break; 2943 #endif 2944 case IPPROTO_ICMP : 2945 if ((flags & IPN_ICMPERR) != 0) { 2946 if (nat->nat_outport != sport) 2947 continue; 2948 } else { 2949 if (nat->nat_outport != dport) 2950 continue; 2951 } 2952 break; 2953 case IPPROTO_TCP : 2954 case IPPROTO_UDP : 2955 if (nat->nat_oport != sport) 2956 continue; 2957 if (nat->nat_outport != dport) 2958 continue; 2959 break; 2960 default : 2961 break; 2962 } 2963 2964 ipn = nat->nat_ptr; 2965 if ((ipn != NULL) && (nat->nat_aps != NULL)) 2966 if (appr_match(fin, nat) != 0) 2967 continue; 2968 return nat; 2969 } 2970 } 2971 2972 /* 2973 * So if we didn't find it but there are wildcard members in the hash 2974 * table, go back and look for them. We do this search and update here 2975 * because it is modifying the NAT table and we want to do this only 2976 * for the first packet that matches. The exception, of course, is 2977 * for "dummy" (FI_IGNORE) lookups. 2978 */ 2979 find_in_wild_ports: 2980 if (!(flags & NAT_TCPUDP) || !(flags & NAT_SEARCH)) 2981 return NULL; 2982 if (nat_stats.ns_wilds == 0) 2983 return NULL; 2984 2985 RWLOCK_EXIT(&ipf_nat); 2986 2987 hv = NAT_HASH_FN(dst, 0, 0xffffffff); 2988 hv = NAT_HASH_FN(src.s_addr, hv, ipf_nattable_sz); 2989 2990 WRITE_ENTER(&ipf_nat); 2991 2992 nat = nat_table[1][hv]; 2993 for (; nat; nat = nat->nat_hnext[1]) { 2994 if (nat->nat_ifps[0] != NULL) { 2995 if ((ifp != NULL) && (ifp != nat->nat_ifps[0])) 2996 continue; 2997 } else if (ifp != NULL) 2998 nat->nat_ifps[0] = ifp; 2999 3000 if (nat->nat_p != fin->fin_p) 3001 continue; 3002 if (nat->nat_oip.s_addr != src.s_addr || 3003 nat->nat_outip.s_addr != dst) 3004 continue; 3005 3006 nflags = nat->nat_flags; 3007 if (!(nflags & (NAT_TCPUDP|SI_WILDP))) 3008 continue; 3009 3010 if (nat_wildok(nat, (int)sport, (int)dport, nflags, 3011 NAT_INBOUND) == 1) { 3012 if ((fin->fin_flx & FI_IGNORE) != 0) 3013 break; 3014 if ((nflags & SI_CLONE) != 0) { 3015 nat = fr_natclone(fin, nat); 3016 if (nat == NULL) 3017 break; 3018 } else { 3019 MUTEX_ENTER(&ipf_nat_new); 3020 nat_stats.ns_wilds--; 3021 MUTEX_EXIT(&ipf_nat_new); 3022 } 3023 nat->nat_oport = sport; 3024 nat->nat_outport = dport; 3025 nat->nat_flags &= ~(SI_W_DPORT|SI_W_SPORT); 3026 nat_tabmove(nat); 3027 break; 3028 } 3029 } 3030 3031 MUTEX_DOWNGRADE(&ipf_nat); 3032 3033 return nat; 3034 } 3035 3036 3037 /* ------------------------------------------------------------------------ */ 3038 /* Function: nat_tabmove */ 3039 /* Returns: Nil */ 3040 /* Parameters: nat(I) - pointer to NAT structure */ 3041 /* Write Lock: ipf_nat */ 3042 /* */ 3043 /* This function is only called for TCP/UDP NAT table entries where the */ 3044 /* original was placed in the table without hashing on the ports and we now */ 3045 /* want to include hashing on port numbers. */ 3046 /* ------------------------------------------------------------------------ */ 3047 static void nat_tabmove(nat) 3048 nat_t *nat; 3049 { 3050 nat_t **natp; 3051 u_int hv; 3052 3053 if (nat->nat_flags & SI_CLONE) 3054 return; 3055 3056 /* 3057 * Remove the NAT entry from the old location 3058 */ 3059 if (nat->nat_hnext[0]) 3060 nat->nat_hnext[0]->nat_phnext[0] = nat->nat_phnext[0]; 3061 *nat->nat_phnext[0] = nat->nat_hnext[0]; 3062 nat_stats.ns_bucketlen[0][nat->nat_hv[0]]--; 3063 3064 if (nat->nat_hnext[1]) 3065 nat->nat_hnext[1]->nat_phnext[1] = nat->nat_phnext[1]; 3066 *nat->nat_phnext[1] = nat->nat_hnext[1]; 3067 nat_stats.ns_bucketlen[1][nat->nat_hv[1]]--; 3068 3069 /* 3070 * Add into the NAT table in the new position 3071 */ 3072 hv = NAT_HASH_FN(nat->nat_inip.s_addr, nat->nat_inport, 0xffffffff); 3073 hv = NAT_HASH_FN(nat->nat_oip.s_addr, hv + nat->nat_oport, 3074 ipf_nattable_sz); 3075 nat->nat_hv[0] = hv; 3076 natp = &nat_table[0][hv]; 3077 if (*natp) 3078 (*natp)->nat_phnext[0] = &nat->nat_hnext[0]; 3079 nat->nat_phnext[0] = natp; 3080 nat->nat_hnext[0] = *natp; 3081 *natp = nat; 3082 nat_stats.ns_bucketlen[0][hv]++; 3083 3084 hv = NAT_HASH_FN(nat->nat_outip.s_addr, nat->nat_outport, 0xffffffff); 3085 hv = NAT_HASH_FN(nat->nat_oip.s_addr, hv + nat->nat_oport, 3086 ipf_nattable_sz); 3087 nat->nat_hv[1] = hv; 3088 natp = &nat_table[1][hv]; 3089 if (*natp) 3090 (*natp)->nat_phnext[1] = &nat->nat_hnext[1]; 3091 nat->nat_phnext[1] = natp; 3092 nat->nat_hnext[1] = *natp; 3093 *natp = nat; 3094 nat_stats.ns_bucketlen[1][hv]++; 3095 } 3096 3097 3098 /* ------------------------------------------------------------------------ */ 3099 /* Function: nat_outlookup */ 3100 /* Returns: nat_t* - NULL == no match, */ 3101 /* else pointer to matching NAT entry */ 3102 /* Parameters: fin(I) - pointer to packet information */ 3103 /* flags(I) - NAT flags for this packet */ 3104 /* p(I) - protocol for this packet */ 3105 /* src(I) - source IP address */ 3106 /* dst(I) - destination IP address */ 3107 /* rw(I) - 1 == write lock on ipf_nat held, 0 == read lock. */ 3108 /* */ 3109 /* Lookup a nat entry based on the source 'real' ip address/port and */ 3110 /* destination address/port. We use this lookup when sending a packet out, */ 3111 /* we're looking for a table entry, based on the source address. */ 3112 /* */ 3113 /* NOTE: THE PACKET BEING CHECKED (IF FOUND) HAS A MAPPING ALREADY. */ 3114 /* */ 3115 /* NOTE: IT IS ASSUMED THAT ipf_nat IS ONLY HELD WITH A READ LOCK WHEN */ 3116 /* THIS FUNCTION IS CALLED WITH NAT_SEARCH SET IN nflags. */ 3117 /* */ 3118 /* flags -> relevant are IPN_UDP/IPN_TCP/IPN_ICMPQUERY that indicate if */ 3119 /* the packet is of said protocol */ 3120 /* ------------------------------------------------------------------------ */ 3121 nat_t *nat_outlookup(fin, flags, p, src, dst) 3122 fr_info_t *fin; 3123 u_int flags, p; 3124 struct in_addr src , dst; 3125 { 3126 u_short sport, dport; 3127 u_int sflags; 3128 ipnat_t *ipn; 3129 u_32_t srcip; 3130 nat_t *nat; 3131 int nflags; 3132 void *ifp; 3133 u_int hv; 3134 frentry_t *fr; 3135 3136 fr = fin->fin_fr; 3137 3138 if ((fr != NULL) && !(fr->fr_flags & FR_DUP) && 3139 fr->fr_tif.fd_ifp && fr->fr_tif.fd_ifp != (void *)-1) 3140 ifp = fr->fr_tif.fd_ifp; 3141 else 3142 ifp = fin->fin_ifp; 3143 3144 srcip = src.s_addr; 3145 sflags = flags & IPN_TCPUDPICMP; 3146 sport = 0; 3147 dport = 0; 3148 3149 switch (p) 3150 { 3151 case IPPROTO_TCP : 3152 case IPPROTO_UDP : 3153 sport = htons(fin->fin_data[0]); 3154 dport = htons(fin->fin_data[1]); 3155 break; 3156 case IPPROTO_ICMP : 3157 if (flags & IPN_ICMPERR) 3158 sport = fin->fin_data[1]; 3159 else 3160 dport = fin->fin_data[1]; 3161 break; 3162 default : 3163 break; 3164 } 3165 3166 if ((flags & SI_WILDP) != 0) 3167 goto find_out_wild_ports; 3168 3169 hv = NAT_HASH_FN(srcip, sport, 0xffffffff); 3170 hv = NAT_HASH_FN(dst.s_addr, hv + dport, ipf_nattable_sz); 3171 nat = nat_table[0][hv]; 3172 for (; nat; nat = nat->nat_hnext[0]) { 3173 if (nat->nat_ifps[1] != NULL) { 3174 if ((ifp != NULL) && (ifp != nat->nat_ifps[1])) 3175 continue; 3176 } else if (ifp != NULL) 3177 nat->nat_ifps[1] = ifp; 3178 3179 nflags = nat->nat_flags; 3180 3181 if (nat->nat_inip.s_addr == srcip && 3182 nat->nat_oip.s_addr == dst.s_addr && 3183 (((p == 0) && (sflags == (nflags & NAT_TCPUDPICMP))) 3184 || (p == nat->nat_p))) { 3185 switch (p) 3186 { 3187 #if 0 3188 case IPPROTO_GRE : 3189 if (nat->nat_call[1] != fin->fin_data[0]) 3190 continue; 3191 break; 3192 #endif 3193 case IPPROTO_TCP : 3194 case IPPROTO_UDP : 3195 if (nat->nat_oport != dport) 3196 continue; 3197 if (nat->nat_inport != sport) 3198 continue; 3199 break; 3200 default : 3201 break; 3202 } 3203 3204 ipn = nat->nat_ptr; 3205 if ((ipn != NULL) && (nat->nat_aps != NULL)) 3206 if (appr_match(fin, nat) != 0) 3207 continue; 3208 return nat; 3209 } 3210 } 3211 3212 /* 3213 * So if we didn't find it but there are wildcard members in the hash 3214 * table, go back and look for them. We do this search and update here 3215 * because it is modifying the NAT table and we want to do this only 3216 * for the first packet that matches. The exception, of course, is 3217 * for "dummy" (FI_IGNORE) lookups. 3218 */ 3219 find_out_wild_ports: 3220 if (!(flags & NAT_TCPUDP) || !(flags & NAT_SEARCH)) 3221 return NULL; 3222 if (nat_stats.ns_wilds == 0) 3223 return NULL; 3224 3225 RWLOCK_EXIT(&ipf_nat); 3226 3227 hv = NAT_HASH_FN(srcip, 0, 0xffffffff); 3228 hv = NAT_HASH_FN(dst.s_addr, hv, ipf_nattable_sz); 3229 3230 WRITE_ENTER(&ipf_nat); 3231 3232 nat = nat_table[0][hv]; 3233 for (; nat; nat = nat->nat_hnext[0]) { 3234 if (nat->nat_ifps[1] != NULL) { 3235 if ((ifp != NULL) && (ifp != nat->nat_ifps[1])) 3236 continue; 3237 } else if (ifp != NULL) 3238 nat->nat_ifps[1] = ifp; 3239 3240 if (nat->nat_p != fin->fin_p) 3241 continue; 3242 if ((nat->nat_inip.s_addr != srcip) || 3243 (nat->nat_oip.s_addr != dst.s_addr)) 3244 continue; 3245 3246 nflags = nat->nat_flags; 3247 if (!(nflags & (NAT_TCPUDP|SI_WILDP))) 3248 continue; 3249 3250 if (nat_wildok(nat, (int)sport, (int)dport, nflags, 3251 NAT_OUTBOUND) == 1) { 3252 if ((fin->fin_flx & FI_IGNORE) != 0) 3253 break; 3254 if ((nflags & SI_CLONE) != 0) { 3255 nat = fr_natclone(fin, nat); 3256 if (nat == NULL) 3257 break; 3258 } else { 3259 MUTEX_ENTER(&ipf_nat_new); 3260 nat_stats.ns_wilds--; 3261 MUTEX_EXIT(&ipf_nat_new); 3262 } 3263 nat->nat_inport = sport; 3264 nat->nat_oport = dport; 3265 if (nat->nat_outport == 0) 3266 nat->nat_outport = sport; 3267 nat->nat_flags &= ~(SI_W_DPORT|SI_W_SPORT); 3268 nat_tabmove(nat); 3269 break; 3270 } 3271 } 3272 3273 MUTEX_DOWNGRADE(&ipf_nat); 3274 3275 return nat; 3276 } 3277 3278 3279 /* ------------------------------------------------------------------------ */ 3280 /* Function: nat_lookupredir */ 3281 /* Returns: nat_t* - NULL == no match, */ 3282 /* else pointer to matching NAT entry */ 3283 /* Parameters: np(I) - pointer to description of packet to find NAT table */ 3284 /* entry for. */ 3285 /* */ 3286 /* Lookup the NAT tables to search for a matching redirect */ 3287 /* ------------------------------------------------------------------------ */ 3288 nat_t *nat_lookupredir(np) 3289 natlookup_t *np; 3290 { 3291 fr_info_t fi; 3292 nat_t *nat; 3293 3294 bzero((char *)&fi, sizeof(fi)); 3295 if (np->nl_flags & IPN_IN) { 3296 fi.fin_data[0] = ntohs(np->nl_realport); 3297 fi.fin_data[1] = ntohs(np->nl_outport); 3298 } else { 3299 fi.fin_data[0] = ntohs(np->nl_inport); 3300 fi.fin_data[1] = ntohs(np->nl_outport); 3301 } 3302 if (np->nl_flags & IPN_TCP) 3303 fi.fin_p = IPPROTO_TCP; 3304 else if (np->nl_flags & IPN_UDP) 3305 fi.fin_p = IPPROTO_UDP; 3306 else if (np->nl_flags & (IPN_ICMPERR|IPN_ICMPQUERY)) 3307 fi.fin_p = IPPROTO_ICMP; 3308 3309 /* 3310 * We can do two sorts of lookups: 3311 * - IPN_IN: we have the `real' and `out' address, look for `in'. 3312 * - default: we have the `in' and `out' address, look for `real'. 3313 */ 3314 if (np->nl_flags & IPN_IN) { 3315 if ((nat = nat_inlookup(&fi, np->nl_flags, fi.fin_p, 3316 np->nl_realip, np->nl_outip))) { 3317 np->nl_inip = nat->nat_inip; 3318 np->nl_inport = nat->nat_inport; 3319 } 3320 } else { 3321 /* 3322 * If nl_inip is non null, this is a lookup based on the real 3323 * ip address. Else, we use the fake. 3324 */ 3325 if ((nat = nat_outlookup(&fi, np->nl_flags, fi.fin_p, 3326 np->nl_inip, np->nl_outip))) { 3327 3328 if ((np->nl_flags & IPN_FINDFORWARD) != 0) { 3329 fr_info_t fin; 3330 bzero((char *)&fin, sizeof(fin)); 3331 fin.fin_p = nat->nat_p; 3332 fin.fin_data[0] = ntohs(nat->nat_outport); 3333 fin.fin_data[1] = ntohs(nat->nat_oport); 3334 if (nat_inlookup(&fin, np->nl_flags, fin.fin_p, 3335 nat->nat_outip, 3336 nat->nat_oip) != NULL) { 3337 np->nl_flags &= ~IPN_FINDFORWARD; 3338 } 3339 } 3340 3341 np->nl_realip = nat->nat_outip; 3342 np->nl_realport = nat->nat_outport; 3343 } 3344 } 3345 3346 return nat; 3347 } 3348 3349 3350 /* ------------------------------------------------------------------------ */ 3351 /* Function: nat_match */ 3352 /* Returns: int - 0 == no match, 1 == match */ 3353 /* Parameters: fin(I) - pointer to packet information */ 3354 /* np(I) - pointer to NAT rule */ 3355 /* */ 3356 /* Pull the matching of a packet against a NAT rule out of that complex */ 3357 /* loop inside fr_checknatin() and lay it out properly in its own function. */ 3358 /* ------------------------------------------------------------------------ */ 3359 static int nat_match(fin, np) 3360 fr_info_t *fin; 3361 ipnat_t *np; 3362 { 3363 frtuc_t *ft; 3364 3365 if (fin->fin_v != 4) 3366 return 0; 3367 3368 if (np->in_p && fin->fin_p != np->in_p) 3369 return 0; 3370 3371 if (fin->fin_out) { 3372 if (!(np->in_redir & (NAT_MAP|NAT_MAPBLK))) 3373 return 0; 3374 if (((fin->fin_fi.fi_saddr & np->in_inmsk) != np->in_inip) 3375 ^ ((np->in_flags & IPN_NOTSRC) != 0)) 3376 return 0; 3377 if (((fin->fin_fi.fi_daddr & np->in_srcmsk) != np->in_srcip) 3378 ^ ((np->in_flags & IPN_NOTDST) != 0)) 3379 return 0; 3380 } else { 3381 if (!(np->in_redir & NAT_REDIRECT)) 3382 return 0; 3383 if (((fin->fin_fi.fi_saddr & np->in_srcmsk) != np->in_srcip) 3384 ^ ((np->in_flags & IPN_NOTSRC) != 0)) 3385 return 0; 3386 if (((fin->fin_fi.fi_daddr & np->in_outmsk) != np->in_outip) 3387 ^ ((np->in_flags & IPN_NOTDST) != 0)) 3388 return 0; 3389 } 3390 3391 ft = &np->in_tuc; 3392 if (!(fin->fin_flx & FI_TCPUDP) || 3393 (fin->fin_flx & (FI_SHORT|FI_FRAGBODY))) { 3394 if (ft->ftu_scmp || ft->ftu_dcmp) 3395 return 0; 3396 return 1; 3397 } 3398 3399 return fr_tcpudpchk(fin, ft); 3400 } 3401 3402 3403 /* ------------------------------------------------------------------------ */ 3404 /* Function: nat_update */ 3405 /* Returns: Nil */ 3406 /* Parameters: nat(I) - pointer to NAT structure */ 3407 /* np(I) - pointer to NAT rule */ 3408 /* */ 3409 /* Updates the lifetime of a NAT table entry for non-TCP packets. Must be */ 3410 /* called with fin_rev updated - i.e. after calling nat_proto(). */ 3411 /* ------------------------------------------------------------------------ */ 3412 void nat_update(fin, nat, np) 3413 fr_info_t *fin; 3414 nat_t *nat; 3415 ipnat_t *np; 3416 { 3417 ipftq_t *ifq, *ifq2; 3418 ipftqent_t *tqe; 3419 3420 MUTEX_ENTER(&nat->nat_lock); 3421 tqe = &nat->nat_tqe; 3422 ifq = tqe->tqe_ifq; 3423 3424 /* 3425 * We allow over-riding of NAT timeouts from NAT rules, even for 3426 * TCP, however, if it is TCP and there is no rule timeout set, 3427 * then do not update the timeout here. 3428 */ 3429 if (np != NULL) 3430 ifq2 = np->in_tqehead[fin->fin_rev]; 3431 else 3432 ifq2 = NULL; 3433 3434 if (nat->nat_p == IPPROTO_TCP && ifq2 == NULL) { 3435 (void) fr_tcp_age(&nat->nat_tqe, fin, nat_tqb, 0); 3436 } else { 3437 if (ifq2 == NULL) { 3438 if (nat->nat_p == IPPROTO_UDP) 3439 ifq2 = &nat_udptq; 3440 else if (nat->nat_p == IPPROTO_ICMP) 3441 ifq2 = &nat_icmptq; 3442 else 3443 ifq2 = &nat_iptq; 3444 } 3445 3446 fr_movequeue(tqe, ifq, ifq2); 3447 } 3448 MUTEX_EXIT(&nat->nat_lock); 3449 } 3450 3451 3452 /* ------------------------------------------------------------------------ */ 3453 /* Function: fr_checknatout */ 3454 /* Returns: int - -1 == packet failed NAT checks so block it, */ 3455 /* 0 == no packet translation occurred, */ 3456 /* 1 == packet was successfully translated. */ 3457 /* Parameters: fin(I) - pointer to packet information */ 3458 /* passp(I) - pointer to filtering result flags */ 3459 /* */ 3460 /* Check to see if an outcoming packet should be changed. ICMP packets are */ 3461 /* first checked to see if they match an existing entry (if an error), */ 3462 /* otherwise a search of the current NAT table is made. If neither results */ 3463 /* in a match then a search for a matching NAT rule is made. Create a new */ 3464 /* NAT entry if a we matched a NAT rule. Lastly, actually change the */ 3465 /* packet header(s) as required. */ 3466 /* ------------------------------------------------------------------------ */ 3467 int fr_checknatout(fin, passp) 3468 fr_info_t *fin; 3469 u_32_t *passp; 3470 { 3471 struct ifnet *ifp, *sifp; 3472 icmphdr_t *icmp = NULL; 3473 tcphdr_t *tcp = NULL; 3474 int rval, natfailed; 3475 ipnat_t *np = NULL; 3476 u_int nflags = 0; 3477 u_32_t ipa, iph; 3478 int natadd = 1; 3479 frentry_t *fr; 3480 nat_t *nat; 3481 3482 if (nat_stats.ns_rules == 0 || fr_nat_lock != 0) 3483 return 0; 3484 3485 natfailed = 0; 3486 fr = fin->fin_fr; 3487 sifp = fin->fin_ifp; 3488 if ((fr != NULL) && !(fr->fr_flags & FR_DUP) && 3489 fr->fr_tif.fd_ifp && fr->fr_tif.fd_ifp != (void *)-1) 3490 fin->fin_ifp = fr->fr_tif.fd_ifp; 3491 ifp = fin->fin_ifp; 3492 3493 if (!(fin->fin_flx & FI_SHORT) && (fin->fin_off == 0)) { 3494 switch (fin->fin_p) 3495 { 3496 case IPPROTO_TCP : 3497 nflags = IPN_TCP; 3498 break; 3499 case IPPROTO_UDP : 3500 nflags = IPN_UDP; 3501 break; 3502 case IPPROTO_ICMP : 3503 icmp = fin->fin_dp; 3504 3505 /* 3506 * This is an incoming packet, so the destination is 3507 * the icmp_id and the source port equals 0 3508 */ 3509 if (nat_icmpquerytype4(icmp->icmp_type)) 3510 nflags = IPN_ICMPQUERY; 3511 break; 3512 default : 3513 break; 3514 } 3515 3516 if ((nflags & IPN_TCPUDP)) 3517 tcp = fin->fin_dp; 3518 } 3519 3520 ipa = fin->fin_saddr; 3521 3522 READ_ENTER(&ipf_nat); 3523 3524 if ((fin->fin_p == IPPROTO_ICMP) && !(nflags & IPN_ICMPQUERY) && 3525 (nat = nat_icmperror(fin, &nflags, NAT_OUTBOUND))) 3526 /*EMPTY*/; 3527 else if ((fin->fin_flx & FI_FRAG) && (nat = fr_nat_knownfrag(fin))) 3528 natadd = 0; 3529 else if ((nat = nat_outlookup(fin, nflags|NAT_SEARCH, (u_int)fin->fin_p, 3530 fin->fin_src, fin->fin_dst))) { 3531 nflags = nat->nat_flags; 3532 } else { 3533 u_32_t hv, msk, nmsk; 3534 3535 /* 3536 * If there is no current entry in the nat table for this IP#, 3537 * create one for it (if there is a matching rule). 3538 */ 3539 RWLOCK_EXIT(&ipf_nat); 3540 msk = 0xffffffff; 3541 nmsk = nat_masks; 3542 WRITE_ENTER(&ipf_nat); 3543 maskloop: 3544 iph = ipa & htonl(msk); 3545 hv = NAT_HASH_FN(iph, 0, ipf_natrules_sz); 3546 for (np = nat_rules[hv]; np; np = np->in_mnext) 3547 { 3548 if ((np->in_ifps[1] && (np->in_ifps[1] != ifp))) 3549 continue; 3550 if (np->in_v != fin->fin_v) 3551 continue; 3552 if (np->in_p && (np->in_p != fin->fin_p)) 3553 continue; 3554 if ((np->in_flags & IPN_RF) && !(np->in_flags & nflags)) 3555 continue; 3556 if (np->in_flags & IPN_FILTER) { 3557 if (!nat_match(fin, np)) 3558 continue; 3559 } else if ((ipa & np->in_inmsk) != np->in_inip) 3560 continue; 3561 3562 if ((fr != NULL) && 3563 !fr_matchtag(&np->in_tag, &fr->fr_nattag)) 3564 continue; 3565 3566 if (*np->in_plabel != '\0') { 3567 if (((np->in_flags & IPN_FILTER) == 0) && 3568 (np->in_dport != tcp->th_dport)) 3569 continue; 3570 if (appr_ok(fin, tcp, np) == 0) 3571 continue; 3572 } 3573 3574 if ((nat = nat_new(fin, np, NULL, nflags, 3575 NAT_OUTBOUND))) { 3576 np->in_hits++; 3577 break; 3578 } else 3579 natfailed = -1; 3580 } 3581 if ((np == NULL) && (nmsk != 0)) { 3582 while (nmsk) { 3583 msk <<= 1; 3584 if (nmsk & 0x80000000) 3585 break; 3586 nmsk <<= 1; 3587 } 3588 if (nmsk != 0) { 3589 nmsk <<= 1; 3590 goto maskloop; 3591 } 3592 } 3593 MUTEX_DOWNGRADE(&ipf_nat); 3594 } 3595 3596 if (nat != NULL) { 3597 rval = fr_natout(fin, nat, natadd, nflags); 3598 if (rval == 1) { 3599 MUTEX_ENTER(&nat->nat_lock); 3600 nat->nat_ref++; 3601 MUTEX_EXIT(&nat->nat_lock); 3602 fin->fin_nat = nat; 3603 } 3604 } else 3605 rval = natfailed; 3606 RWLOCK_EXIT(&ipf_nat); 3607 3608 if (rval == -1) { 3609 if (passp != NULL) 3610 *passp = FR_BLOCK; 3611 fin->fin_flx |= FI_BADNAT; 3612 } 3613 fin->fin_ifp = sifp; 3614 return rval; 3615 } 3616 3617 /* ------------------------------------------------------------------------ */ 3618 /* Function: fr_natout */ 3619 /* Returns: int - -1 == packet failed NAT checks so block it, */ 3620 /* 1 == packet was successfully translated. */ 3621 /* Parameters: fin(I) - pointer to packet information */ 3622 /* nat(I) - pointer to NAT structure */ 3623 /* natadd(I) - flag indicating if it is safe to add frag cache */ 3624 /* nflags(I) - NAT flags set for this packet */ 3625 /* */ 3626 /* Translate a packet coming "out" on an interface. */ 3627 /* ------------------------------------------------------------------------ */ 3628 int fr_natout(fin, nat, natadd, nflags) 3629 fr_info_t *fin; 3630 nat_t *nat; 3631 int natadd; 3632 u_32_t nflags; 3633 { 3634 icmphdr_t *icmp; 3635 u_short *csump; 3636 u_32_t sumd; 3637 tcphdr_t *tcp; 3638 ipnat_t *np; 3639 int i; 3640 3641 #if SOLARIS && defined(_KERNEL) 3642 net_data_t net_data_p; 3643 if (fin->fin_v == 4) 3644 net_data_p = ipf_ipv4; 3645 else 3646 net_data_p = ipf_ipv6; 3647 #endif 3648 3649 tcp = NULL; 3650 icmp = NULL; 3651 csump = NULL; 3652 np = nat->nat_ptr; 3653 3654 if ((natadd != 0) && (fin->fin_flx & FI_FRAG) && (np != NULL)) 3655 (void) fr_nat_newfrag(fin, 0, nat); 3656 3657 MUTEX_ENTER(&nat->nat_lock); 3658 nat->nat_bytes[1] += fin->fin_plen; 3659 nat->nat_pkts[1]++; 3660 MUTEX_EXIT(&nat->nat_lock); 3661 3662 /* 3663 * Fix up checksums, not by recalculating them, but 3664 * simply computing adjustments. 3665 * This is only done for STREAMS based IP implementations where the 3666 * checksum has already been calculated by IP. In all other cases, 3667 * IPFilter is called before the checksum needs calculating so there 3668 * is no call to modify whatever is in the header now. 3669 */ 3670 ASSERT(fin->fin_m != NULL); 3671 if (fin->fin_v == 4 && !NET_IS_HCK_L3_FULL(net_data_p, fin->fin_m)) { 3672 if (nflags == IPN_ICMPERR) { 3673 u_32_t s1, s2; 3674 3675 s1 = LONG_SUM(ntohl(fin->fin_saddr)); 3676 s2 = LONG_SUM(ntohl(nat->nat_outip.s_addr)); 3677 CALC_SUMD(s1, s2, sumd); 3678 3679 fix_outcksum(&fin->fin_ip->ip_sum, sumd); 3680 } 3681 #if !defined(_KERNEL) || defined(MENTAT) || defined(__sgi) || \ 3682 defined(linux) || defined(BRIDGE_IPF) 3683 else { 3684 /* 3685 * Strictly speaking, this isn't necessary on BSD 3686 * kernels because they do checksum calculation after 3687 * this code has run BUT if ipfilter is being used 3688 * to do NAT as a bridge, that code doesn't exist. 3689 */ 3690 if (nat->nat_dir == NAT_OUTBOUND) 3691 fix_outcksum(&fin->fin_ip->ip_sum, 3692 nat->nat_ipsumd); 3693 else 3694 fix_incksum(&fin->fin_ip->ip_sum, 3695 nat->nat_ipsumd); 3696 } 3697 #endif 3698 } 3699 3700 if (!(fin->fin_flx & FI_SHORT) && (fin->fin_off == 0)) { 3701 if ((nat->nat_outport != 0) && (nflags & IPN_TCPUDP)) { 3702 tcp = fin->fin_dp; 3703 3704 tcp->th_sport = nat->nat_outport; 3705 fin->fin_data[0] = ntohs(nat->nat_outport); 3706 } 3707 3708 if ((nat->nat_outport != 0) && (nflags & IPN_ICMPQUERY)) { 3709 icmp = fin->fin_dp; 3710 icmp->icmp_id = nat->nat_outport; 3711 } 3712 3713 csump = nat_proto(fin, nat, nflags); 3714 } 3715 3716 fin->fin_ip->ip_src = nat->nat_outip; 3717 3718 nat_update(fin, nat, np); 3719 3720 /* 3721 * The above comments do not hold for layer 4 (or higher) checksums... 3722 */ 3723 if (csump != NULL && !NET_IS_HCK_L4_FULL(net_data_p, fin->fin_m)) { 3724 if (nflags & IPN_TCPUDP && 3725 NET_IS_HCK_L4_PART(net_data_p, fin->fin_m)) 3726 sumd = nat->nat_sumd[1]; 3727 else 3728 sumd = nat->nat_sumd[0]; 3729 3730 if (nat->nat_dir == NAT_OUTBOUND) 3731 fix_outcksum(csump, sumd); 3732 else 3733 fix_incksum(csump, sumd); 3734 } 3735 #ifdef IPFILTER_SYNC 3736 ipfsync_update(SMC_NAT, fin, nat->nat_sync); 3737 #endif 3738 /* ------------------------------------------------------------- */ 3739 /* A few quick notes: */ 3740 /* Following are test conditions prior to calling the */ 3741 /* appr_check routine. */ 3742 /* */ 3743 /* A NULL tcp indicates a non TCP/UDP packet. When dealing */ 3744 /* with a redirect rule, we attempt to match the packet's */ 3745 /* source port against in_dport, otherwise we'd compare the */ 3746 /* packet's destination. */ 3747 /* ------------------------------------------------------------- */ 3748 if ((np != NULL) && (np->in_apr != NULL)) { 3749 i = appr_check(fin, nat); 3750 if (i == 0) 3751 i = 1; 3752 } else 3753 i = 1; 3754 ATOMIC_INCL(nat_stats.ns_mapped[1]); 3755 fin->fin_flx |= FI_NATED; 3756 return i; 3757 } 3758 3759 3760 /* ------------------------------------------------------------------------ */ 3761 /* Function: fr_checknatin */ 3762 /* Returns: int - -1 == packet failed NAT checks so block it, */ 3763 /* 0 == no packet translation occurred, */ 3764 /* 1 == packet was successfully translated. */ 3765 /* Parameters: fin(I) - pointer to packet information */ 3766 /* passp(I) - pointer to filtering result flags */ 3767 /* */ 3768 /* Check to see if an incoming packet should be changed. ICMP packets are */ 3769 /* first checked to see if they match an existing entry (if an error), */ 3770 /* otherwise a search of the current NAT table is made. If neither results */ 3771 /* in a match then a search for a matching NAT rule is made. Create a new */ 3772 /* NAT entry if a we matched a NAT rule. Lastly, actually change the */ 3773 /* packet header(s) as required. */ 3774 /* ------------------------------------------------------------------------ */ 3775 int fr_checknatin(fin, passp) 3776 fr_info_t *fin; 3777 u_32_t *passp; 3778 { 3779 u_int nflags, natadd; 3780 int rval, natfailed; 3781 struct ifnet *ifp; 3782 struct in_addr in; 3783 icmphdr_t *icmp; 3784 tcphdr_t *tcp; 3785 u_short dport; 3786 ipnat_t *np; 3787 nat_t *nat; 3788 u_32_t iph; 3789 3790 if (nat_stats.ns_rules == 0 || fr_nat_lock != 0) 3791 return 0; 3792 3793 tcp = NULL; 3794 icmp = NULL; 3795 dport = 0; 3796 natadd = 1; 3797 nflags = 0; 3798 natfailed = 0; 3799 ifp = fin->fin_ifp; 3800 3801 if (!(fin->fin_flx & FI_SHORT) && (fin->fin_off == 0)) { 3802 switch (fin->fin_p) 3803 { 3804 case IPPROTO_TCP : 3805 nflags = IPN_TCP; 3806 break; 3807 case IPPROTO_UDP : 3808 nflags = IPN_UDP; 3809 break; 3810 case IPPROTO_ICMP : 3811 icmp = fin->fin_dp; 3812 3813 /* 3814 * This is an incoming packet, so the destination is 3815 * the icmp_id and the source port equals 0 3816 */ 3817 if (nat_icmpquerytype4(icmp->icmp_type)) { 3818 nflags = IPN_ICMPQUERY; 3819 dport = icmp->icmp_id; 3820 } break; 3821 default : 3822 break; 3823 } 3824 3825 if ((nflags & IPN_TCPUDP)) { 3826 tcp = fin->fin_dp; 3827 dport = tcp->th_dport; 3828 } 3829 } 3830 3831 in = fin->fin_dst; 3832 3833 READ_ENTER(&ipf_nat); 3834 3835 if ((fin->fin_p == IPPROTO_ICMP) && !(nflags & IPN_ICMPQUERY) && 3836 (nat = nat_icmperror(fin, &nflags, NAT_INBOUND))) 3837 /*EMPTY*/; 3838 else if ((fin->fin_flx & FI_FRAG) && (nat = fr_nat_knownfrag(fin))) 3839 natadd = 0; 3840 else if ((nat = nat_inlookup(fin, nflags|NAT_SEARCH, (u_int)fin->fin_p, 3841 fin->fin_src, in))) { 3842 nflags = nat->nat_flags; 3843 } else { 3844 u_32_t hv, msk, rmsk; 3845 3846 RWLOCK_EXIT(&ipf_nat); 3847 rmsk = rdr_masks; 3848 msk = 0xffffffff; 3849 WRITE_ENTER(&ipf_nat); 3850 /* 3851 * If there is no current entry in the nat table for this IP#, 3852 * create one for it (if there is a matching rule). 3853 */ 3854 maskloop: 3855 iph = in.s_addr & htonl(msk); 3856 hv = NAT_HASH_FN(iph, 0, ipf_rdrrules_sz); 3857 for (np = rdr_rules[hv]; np; np = np->in_rnext) { 3858 if (np->in_ifps[0] && (np->in_ifps[0] != ifp)) 3859 continue; 3860 if (np->in_v != fin->fin_v) 3861 continue; 3862 if (np->in_p && (np->in_p != fin->fin_p)) 3863 continue; 3864 if ((np->in_flags & IPN_RF) && !(np->in_flags & nflags)) 3865 continue; 3866 if (np->in_flags & IPN_FILTER) { 3867 if (!nat_match(fin, np)) 3868 continue; 3869 } else { 3870 if ((in.s_addr & np->in_outmsk) != np->in_outip) 3871 continue; 3872 if (np->in_pmin && 3873 ((ntohs(np->in_pmax) < ntohs(dport)) || 3874 (ntohs(dport) < ntohs(np->in_pmin)))) 3875 continue; 3876 } 3877 3878 if (*np->in_plabel != '\0') { 3879 if (!appr_ok(fin, tcp, np)) { 3880 continue; 3881 } 3882 } 3883 3884 nat = nat_new(fin, np, NULL, nflags, NAT_INBOUND); 3885 if (nat != NULL) { 3886 np->in_hits++; 3887 break; 3888 } else 3889 natfailed = -1; 3890 } 3891 3892 if ((np == NULL) && (rmsk != 0)) { 3893 while (rmsk) { 3894 msk <<= 1; 3895 if (rmsk & 0x80000000) 3896 break; 3897 rmsk <<= 1; 3898 } 3899 if (rmsk != 0) { 3900 rmsk <<= 1; 3901 goto maskloop; 3902 } 3903 } 3904 MUTEX_DOWNGRADE(&ipf_nat); 3905 } 3906 if (nat != NULL) { 3907 rval = fr_natin(fin, nat, natadd, nflags); 3908 if (rval == 1) { 3909 MUTEX_ENTER(&nat->nat_lock); 3910 nat->nat_ref++; 3911 MUTEX_EXIT(&nat->nat_lock); 3912 fin->fin_nat = nat; 3913 fin->fin_state = nat->nat_state; 3914 } 3915 } else 3916 rval = natfailed; 3917 RWLOCK_EXIT(&ipf_nat); 3918 3919 if (rval == -1) { 3920 if (passp != NULL) 3921 *passp = FR_BLOCK; 3922 fin->fin_flx |= FI_BADNAT; 3923 } 3924 return rval; 3925 } 3926 3927 3928 /* ------------------------------------------------------------------------ */ 3929 /* Function: fr_natin */ 3930 /* Returns: int - -1 == packet failed NAT checks so block it, */ 3931 /* 1 == packet was successfully translated. */ 3932 /* Parameters: fin(I) - pointer to packet information */ 3933 /* nat(I) - pointer to NAT structure */ 3934 /* natadd(I) - flag indicating if it is safe to add frag cache */ 3935 /* nflags(I) - NAT flags set for this packet */ 3936 /* Locks Held: ipf_nat (READ) */ 3937 /* */ 3938 /* Translate a packet coming "in" on an interface. */ 3939 /* ------------------------------------------------------------------------ */ 3940 int fr_natin(fin, nat, natadd, nflags) 3941 fr_info_t *fin; 3942 nat_t *nat; 3943 int natadd; 3944 u_32_t nflags; 3945 { 3946 icmphdr_t *icmp; 3947 u_short *csump, *csump1; 3948 u_32_t sumd; 3949 tcphdr_t *tcp; 3950 ipnat_t *np; 3951 int i; 3952 3953 #if SOLARIS && defined(_KERNEL) 3954 net_data_t net_data_p; 3955 if (fin->fin_v == 4) 3956 net_data_p = ipf_ipv4; 3957 else 3958 net_data_p = ipf_ipv6; 3959 #endif 3960 3961 tcp = NULL; 3962 csump = NULL; 3963 np = nat->nat_ptr; 3964 fin->fin_fr = nat->nat_fr; 3965 3966 if (np != NULL) { 3967 if ((natadd != 0) && (fin->fin_flx & FI_FRAG)) 3968 (void) fr_nat_newfrag(fin, 0, nat); 3969 3970 /* ------------------------------------------------------------- */ 3971 /* A few quick notes: */ 3972 /* Following are test conditions prior to calling the */ 3973 /* appr_check routine. */ 3974 /* */ 3975 /* A NULL tcp indicates a non TCP/UDP packet. When dealing */ 3976 /* with a map rule, we attempt to match the packet's */ 3977 /* source port against in_dport, otherwise we'd compare the */ 3978 /* packet's destination. */ 3979 /* ------------------------------------------------------------- */ 3980 if (np->in_apr != NULL) { 3981 i = appr_check(fin, nat); 3982 if (i == -1) { 3983 return -1; 3984 } 3985 } 3986 } 3987 3988 #ifdef IPFILTER_SYNC 3989 ipfsync_update(SMC_NAT, fin, nat->nat_sync); 3990 #endif 3991 3992 MUTEX_ENTER(&nat->nat_lock); 3993 nat->nat_bytes[0] += fin->fin_plen; 3994 nat->nat_pkts[0]++; 3995 MUTEX_EXIT(&nat->nat_lock); 3996 3997 fin->fin_ip->ip_dst = nat->nat_inip; 3998 fin->fin_fi.fi_daddr = nat->nat_inip.s_addr; 3999 if (nflags & IPN_TCPUDP) 4000 tcp = fin->fin_dp; 4001 4002 /* 4003 * Fix up checksums, not by recalculating them, but 4004 * simply computing adjustments. 4005 * Why only do this for some platforms on inbound packets ? 4006 * Because for those that it is done, IP processing is yet to happen 4007 * and so the IPv4 header checksum has not yet been evaluated. 4008 * Perhaps it should always be done for the benefit of things like 4009 * fast forwarding (so that it doesn't need to be recomputed) but with 4010 * header checksum offloading, perhaps it is a moot point. 4011 */ 4012 #if !defined(_KERNEL) || defined(MENTAT) || defined(__sgi) || \ 4013 defined(__osf__) || defined(linux) 4014 if (nat->nat_dir == NAT_OUTBOUND) 4015 fix_incksum(&fin->fin_ip->ip_sum, nat->nat_ipsumd); 4016 else 4017 fix_outcksum(&fin->fin_ip->ip_sum, nat->nat_ipsumd); 4018 #endif 4019 4020 if (!(fin->fin_flx & FI_SHORT) && (fin->fin_off == 0)) { 4021 if ((nat->nat_inport != 0) && (nflags & IPN_TCPUDP)) { 4022 tcp->th_dport = nat->nat_inport; 4023 fin->fin_data[1] = ntohs(nat->nat_inport); 4024 } 4025 4026 4027 if ((nat->nat_inport != 0) && (nflags & IPN_ICMPQUERY)) { 4028 icmp = fin->fin_dp; 4029 4030 icmp->icmp_id = nat->nat_inport; 4031 } 4032 4033 csump = nat_proto(fin, nat, nflags); 4034 } 4035 4036 nat_update(fin, nat, np); 4037 4038 #if SOLARIS && defined(_KERNEL) 4039 if (nflags & IPN_TCPUDP && 4040 NET_IS_HCK_L4_PART(net_data_p, fin->fin_m)) { 4041 sumd = nat->nat_sumd[1]; 4042 csump1 = &(fin->fin_m->b_datap->db_struioun.cksum.cksum_val.u16); 4043 if (csump1 != NULL) { 4044 if (nat->nat_dir == NAT_OUTBOUND) 4045 fix_incksum(csump1, sumd); 4046 else 4047 fix_outcksum(csump1, sumd); 4048 } 4049 } else 4050 #endif 4051 sumd = nat->nat_sumd[0]; 4052 4053 /* 4054 * Inbound packets always need to have their address adjusted in case 4055 * code following this validates it. 4056 */ 4057 if (csump != NULL) { 4058 if (nat->nat_dir == NAT_OUTBOUND) 4059 fix_incksum(csump, sumd); 4060 else 4061 fix_outcksum(csump, sumd); 4062 } 4063 ATOMIC_INCL(nat_stats.ns_mapped[0]); 4064 fin->fin_flx |= FI_NATED; 4065 if (np != NULL && np->in_tag.ipt_num[0] != 0) 4066 fin->fin_nattag = &np->in_tag; 4067 return 1; 4068 } 4069 4070 4071 /* ------------------------------------------------------------------------ */ 4072 /* Function: nat_proto */ 4073 /* Returns: u_short* - pointer to transport header checksum to update, */ 4074 /* NULL if the transport protocol is not recognised */ 4075 /* as needing a checksum update. */ 4076 /* Parameters: fin(I) - pointer to packet information */ 4077 /* nat(I) - pointer to NAT structure */ 4078 /* nflags(I) - NAT flags set for this packet */ 4079 /* */ 4080 /* Return the pointer to the checksum field for each protocol so understood.*/ 4081 /* If support for making other changes to a protocol header is required, */ 4082 /* that is not strictly 'address' translation, such as clamping the MSS in */ 4083 /* TCP down to a specific value, then do it from here. */ 4084 /* ------------------------------------------------------------------------ */ 4085 u_short *nat_proto(fin, nat, nflags) 4086 fr_info_t *fin; 4087 nat_t *nat; 4088 u_int nflags; 4089 { 4090 icmphdr_t *icmp; 4091 u_short *csump; 4092 tcphdr_t *tcp; 4093 udphdr_t *udp; 4094 4095 csump = NULL; 4096 if (fin->fin_out == 0) { 4097 fin->fin_rev = (nat->nat_dir == NAT_OUTBOUND); 4098 } else { 4099 fin->fin_rev = (nat->nat_dir == NAT_INBOUND); 4100 } 4101 4102 switch (fin->fin_p) 4103 { 4104 case IPPROTO_TCP : 4105 tcp = fin->fin_dp; 4106 4107 csump = &tcp->th_sum; 4108 4109 /* 4110 * Do a MSS CLAMPING on a SYN packet, 4111 * only deal IPv4 for now. 4112 */ 4113 if ((nat->nat_mssclamp != 0) && (tcp->th_flags & TH_SYN) != 0) 4114 nat_mssclamp(tcp, nat->nat_mssclamp, csump); 4115 4116 break; 4117 4118 case IPPROTO_UDP : 4119 udp = fin->fin_dp; 4120 4121 if (udp->uh_sum) 4122 csump = &udp->uh_sum; 4123 break; 4124 4125 case IPPROTO_ICMP : 4126 icmp = fin->fin_dp; 4127 4128 if ((nflags & IPN_ICMPQUERY) != 0) { 4129 if (icmp->icmp_cksum != 0) 4130 csump = &icmp->icmp_cksum; 4131 } 4132 break; 4133 } 4134 return csump; 4135 } 4136 4137 4138 /* ------------------------------------------------------------------------ */ 4139 /* Function: fr_natunload */ 4140 /* Returns: Nil */ 4141 /* Parameters: Nil */ 4142 /* */ 4143 /* Free all memory used by NAT structures allocated at runtime. */ 4144 /* ------------------------------------------------------------------------ */ 4145 void fr_natunload() 4146 { 4147 ipftq_t *ifq, *ifqnext; 4148 4149 (void) nat_clearlist(); 4150 (void) nat_flushtable(); 4151 4152 /* 4153 * Proxy timeout queues are not cleaned here because although they 4154 * exist on the NAT list, appr_unload is called after fr_natunload 4155 * and the proxies actually are responsible for them being created. 4156 * Should the proxy timeouts have their own list? There's no real 4157 * justification as this is the only complication. 4158 */ 4159 for (ifq = nat_utqe; ifq != NULL; ifq = ifqnext) { 4160 ifqnext = ifq->ifq_next; 4161 if (((ifq->ifq_flags & IFQF_PROXY) == 0) && 4162 (fr_deletetimeoutqueue(ifq) == 0)) 4163 fr_freetimeoutqueue(ifq); 4164 } 4165 4166 if (nat_table[0] != NULL) { 4167 KFREES(nat_table[0], sizeof(nat_t *) * ipf_nattable_sz); 4168 nat_table[0] = NULL; 4169 } 4170 if (nat_table[1] != NULL) { 4171 KFREES(nat_table[1], sizeof(nat_t *) * ipf_nattable_sz); 4172 nat_table[1] = NULL; 4173 } 4174 if (nat_rules != NULL) { 4175 KFREES(nat_rules, sizeof(ipnat_t *) * ipf_natrules_sz); 4176 nat_rules = NULL; 4177 } 4178 if (rdr_rules != NULL) { 4179 KFREES(rdr_rules, sizeof(ipnat_t *) * ipf_rdrrules_sz); 4180 rdr_rules = NULL; 4181 } 4182 if (maptable != NULL) { 4183 KFREES(maptable, sizeof(hostmap_t *) * ipf_hostmap_sz); 4184 maptable = NULL; 4185 } 4186 if (nat_stats.ns_bucketlen[0] != NULL) { 4187 KFREES(nat_stats.ns_bucketlen[0], 4188 sizeof(u_long *) * ipf_nattable_sz); 4189 nat_stats.ns_bucketlen[0] = NULL; 4190 } 4191 if (nat_stats.ns_bucketlen[1] != NULL) { 4192 KFREES(nat_stats.ns_bucketlen[1], 4193 sizeof(u_long *) * ipf_nattable_sz); 4194 nat_stats.ns_bucketlen[1] = NULL; 4195 } 4196 4197 if (fr_nat_maxbucket_reset == 1) 4198 fr_nat_maxbucket = 0; 4199 4200 if (fr_nat_init == 1) { 4201 fr_nat_init = 0; 4202 fr_sttab_destroy(nat_tqb); 4203 4204 RW_DESTROY(&ipf_natfrag); 4205 RW_DESTROY(&ipf_nat); 4206 4207 MUTEX_DESTROY(&ipf_nat_new); 4208 MUTEX_DESTROY(&ipf_natio); 4209 4210 MUTEX_DESTROY(&nat_udptq.ifq_lock); 4211 MUTEX_DESTROY(&nat_icmptq.ifq_lock); 4212 MUTEX_DESTROY(&nat_iptq.ifq_lock); 4213 } 4214 } 4215 4216 4217 /* ------------------------------------------------------------------------ */ 4218 /* Function: fr_natexpire */ 4219 /* Returns: Nil */ 4220 /* Parameters: Nil */ 4221 /* */ 4222 /* Check all of the timeout queues for entries at the top which need to be */ 4223 /* expired. */ 4224 /* ------------------------------------------------------------------------ */ 4225 void fr_natexpire() 4226 { 4227 ipftq_t *ifq, *ifqnext; 4228 ipftqent_t *tqe, *tqn; 4229 int i; 4230 SPL_INT(s); 4231 4232 SPL_NET(s); 4233 WRITE_ENTER(&ipf_nat); 4234 for (ifq = nat_tqb, i = 0; ifq != NULL; ifq = ifq->ifq_next) { 4235 for (tqn = ifq->ifq_head; ((tqe = tqn) != NULL); i++) { 4236 if (tqe->tqe_die > fr_ticks) 4237 break; 4238 tqn = tqe->tqe_next; 4239 nat_delete(tqe->tqe_parent, NL_EXPIRE); 4240 } 4241 } 4242 4243 for (ifq = nat_utqe; ifq != NULL; ifq = ifqnext) { 4244 ifqnext = ifq->ifq_next; 4245 4246 for (tqn = ifq->ifq_head; ((tqe = tqn) != NULL); i++) { 4247 if (tqe->tqe_die > fr_ticks) 4248 break; 4249 tqn = tqe->tqe_next; 4250 nat_delete(tqe->tqe_parent, NL_EXPIRE); 4251 } 4252 } 4253 4254 for (ifq = nat_utqe; ifq != NULL; ifq = ifqnext) { 4255 ifqnext = ifq->ifq_next; 4256 4257 if (((ifq->ifq_flags & IFQF_DELETE) != 0) && 4258 (ifq->ifq_ref == 0)) { 4259 fr_freetimeoutqueue(ifq); 4260 } 4261 } 4262 4263 RWLOCK_EXIT(&ipf_nat); 4264 SPL_X(s); 4265 } 4266 4267 4268 /* ------------------------------------------------------------------------ */ 4269 /* Function: fr_nataddrsync */ 4270 /* Returns: Nil */ 4271 /* Parameters: ifp(I) - pointer to network interface */ 4272 /* addr(I) - pointer to new network address */ 4273 /* */ 4274 /* Walk through all of the currently active NAT sessions, looking for those */ 4275 /* which need to have their translated address updated (where the interface */ 4276 /* matches the one passed in) and change it, recalculating the checksum sum */ 4277 /* difference too. */ 4278 /* ------------------------------------------------------------------------ */ 4279 void fr_nataddrsync(ifp, addr) 4280 void *ifp; 4281 struct in_addr *addr; 4282 { 4283 u_32_t sum1, sum2, sumd; 4284 nat_t *nat; 4285 ipnat_t *np; 4286 SPL_INT(s); 4287 4288 if (fr_running <= 0) 4289 return; 4290 4291 SPL_NET(s); 4292 WRITE_ENTER(&ipf_nat); 4293 4294 if (fr_running <= 0) { 4295 RWLOCK_EXIT(&ipf_nat); 4296 return; 4297 } 4298 4299 /* 4300 * Change IP addresses for NAT sessions for any protocol except TCP 4301 * since it will break the TCP connection anyway. The only rules 4302 * which will get changed are those which are "map ... -> 0/32", 4303 * where the rule specifies the address is taken from the interface. 4304 */ 4305 for (nat = nat_instances; nat; nat = nat->nat_next) { 4306 if (addr != NULL) { 4307 if (((ifp != NULL) && ifp != (nat->nat_ifps[0])) || 4308 ((nat->nat_flags & IPN_TCP) != 0)) 4309 continue; 4310 if (((np = nat->nat_ptr) == NULL) || 4311 (np->in_nip || (np->in_outmsk != 0xffffffff))) 4312 continue; 4313 4314 /* 4315 * Change the map-to address to be the same as the 4316 * new one. 4317 */ 4318 sum1 = nat->nat_outip.s_addr; 4319 nat->nat_outip = *addr; 4320 sum2 = nat->nat_outip.s_addr; 4321 4322 } else if (((ifp == NULL) || (ifp == nat->nat_ifps[0])) && 4323 !(nat->nat_flags & IPN_TCP) && (np = nat->nat_ptr) && 4324 (np->in_outmsk == 0xffffffff) && !np->in_nip) { 4325 struct in_addr in; 4326 4327 /* 4328 * Change the map-to address to be the same as the 4329 * new one. 4330 */ 4331 sum1 = nat->nat_outip.s_addr; 4332 if (fr_ifpaddr(4, FRI_NORMAL, nat->nat_ifps[0], 4333 &in, NULL) != -1) 4334 nat->nat_outip = in; 4335 sum2 = nat->nat_outip.s_addr; 4336 } else { 4337 continue; 4338 } 4339 4340 if (sum1 == sum2) 4341 continue; 4342 /* 4343 * Readjust the checksum adjustment to take into 4344 * account the new IP#. 4345 */ 4346 CALC_SUMD(sum1, sum2, sumd); 4347 /* XXX - dont change for TCP when solaris does 4348 * hardware checksumming. 4349 */ 4350 sumd += nat->nat_sumd[0]; 4351 nat->nat_sumd[0] = (sumd & 0xffff) + (sumd >> 16); 4352 nat->nat_sumd[1] = nat->nat_sumd[0]; 4353 } 4354 4355 RWLOCK_EXIT(&ipf_nat); 4356 SPL_X(s); 4357 } 4358 4359 4360 /* ------------------------------------------------------------------------ */ 4361 /* Function: fr_natifpsync */ 4362 /* Returns: Nil */ 4363 /* Parameters: action(I) - how we are syncing */ 4364 /* ifp(I) - pointer to network interface */ 4365 /* name(I) - name of interface to sync to */ 4366 /* */ 4367 /* This function is used to resync the mapping of interface names and their */ 4368 /* respective 'pointers'. For "action == IPFSYNC_RESYNC", resync all */ 4369 /* interfaces by doing a new lookup of name to 'pointer'. For "action == */ 4370 /* IPFSYNC_NEWIFP", treat ifp as the new pointer value associated with */ 4371 /* "name" and for "action == IPFSYNC_OLDIFP", ifp is a pointer for which */ 4372 /* there is no longer any interface associated with it. */ 4373 /* ------------------------------------------------------------------------ */ 4374 void fr_natifpsync(action, ifp, name) 4375 int action; 4376 void *ifp; 4377 char *name; 4378 { 4379 #if defined(_KERNEL) && !defined(MENTAT) && defined(USE_SPL) 4380 int s; 4381 #endif 4382 nat_t *nat; 4383 ipnat_t *n; 4384 4385 if (fr_running <= 0) 4386 return; 4387 4388 SPL_NET(s); 4389 WRITE_ENTER(&ipf_nat); 4390 4391 if (fr_running <= 0) { 4392 RWLOCK_EXIT(&ipf_nat); 4393 return; 4394 } 4395 4396 switch (action) 4397 { 4398 case IPFSYNC_RESYNC : 4399 for (nat = nat_instances; nat; nat = nat->nat_next) { 4400 if ((ifp == nat->nat_ifps[0]) || 4401 (nat->nat_ifps[0] == (void *)-1)) { 4402 nat->nat_ifps[0] = 4403 fr_resolvenic(nat->nat_ifnames[0], 4); 4404 } 4405 4406 if ((ifp == nat->nat_ifps[1]) || 4407 (nat->nat_ifps[1] == (void *)-1)) { 4408 nat->nat_ifps[1] = 4409 fr_resolvenic(nat->nat_ifnames[1], 4); 4410 } 4411 } 4412 4413 for (n = nat_list; (n != NULL); n = n->in_next) { 4414 if (n->in_ifps[0] == ifp || 4415 n->in_ifps[0] == (void *)-1) { 4416 n->in_ifps[0] = 4417 fr_resolvenic(n->in_ifnames[0], 4); 4418 } 4419 if (n->in_ifps[1] == ifp || 4420 n->in_ifps[1] == (void *)-1) { 4421 n->in_ifps[1] = 4422 fr_resolvenic(n->in_ifnames[1], 4); 4423 } 4424 } 4425 break; 4426 case IPFSYNC_NEWIFP : 4427 for (nat = nat_instances; nat; nat = nat->nat_next) { 4428 if (!strncmp(name, nat->nat_ifnames[0], 4429 sizeof(nat->nat_ifnames[0]))) 4430 nat->nat_ifps[0] = ifp; 4431 if (!strncmp(name, nat->nat_ifnames[1], 4432 sizeof(nat->nat_ifnames[1]))) 4433 nat->nat_ifps[1] = ifp; 4434 } 4435 for (n = nat_list; (n != NULL); n = n->in_next) { 4436 if (!strncmp(name, n->in_ifnames[0], 4437 sizeof(n->in_ifnames[0]))) 4438 n->in_ifps[0] = ifp; 4439 if (!strncmp(name, n->in_ifnames[1], 4440 sizeof(n->in_ifnames[1]))) 4441 n->in_ifps[1] = ifp; 4442 } 4443 break; 4444 case IPFSYNC_OLDIFP : 4445 for (nat = nat_instances; nat; nat = nat->nat_next) { 4446 if (ifp == nat->nat_ifps[0]) 4447 nat->nat_ifps[0] = (void *)-1; 4448 if (ifp == nat->nat_ifps[1]) 4449 nat->nat_ifps[1] = (void *)-1; 4450 } 4451 for (n = nat_list; (n != NULL); n = n->in_next) { 4452 if (n->in_ifps[0] == ifp) 4453 n->in_ifps[0] = (void *)-1; 4454 if (n->in_ifps[1] == ifp) 4455 n->in_ifps[1] = (void *)-1; 4456 } 4457 break; 4458 } 4459 RWLOCK_EXIT(&ipf_nat); 4460 SPL_X(s); 4461 } 4462 4463 4464 /* ------------------------------------------------------------------------ */ 4465 /* Function: nat_icmpquerytype4 */ 4466 /* Returns: int - 1 == success, 0 == failure */ 4467 /* Parameters: icmptype(I) - ICMP type number */ 4468 /* */ 4469 /* Tests to see if the ICMP type number passed is a query/response type or */ 4470 /* not. */ 4471 /* ------------------------------------------------------------------------ */ 4472 static INLINE int nat_icmpquerytype4(icmptype) 4473 int icmptype; 4474 { 4475 4476 /* 4477 * For the ICMP query NAT code, it is essential that both the query 4478 * and the reply match on the NAT rule. Because the NAT structure 4479 * does not keep track of the icmptype, and a single NAT structure 4480 * is used for all icmp types with the same src, dest and id, we 4481 * simply define the replies as queries as well. The funny thing is, 4482 * altough it seems silly to call a reply a query, this is exactly 4483 * as it is defined in the IPv4 specification 4484 */ 4485 4486 switch (icmptype) 4487 { 4488 4489 case ICMP_ECHOREPLY: 4490 case ICMP_ECHO: 4491 /* route aedvertisement/solliciation is currently unsupported: */ 4492 /* it would require rewriting the ICMP data section */ 4493 case ICMP_TSTAMP: 4494 case ICMP_TSTAMPREPLY: 4495 case ICMP_IREQ: 4496 case ICMP_IREQREPLY: 4497 case ICMP_MASKREQ: 4498 case ICMP_MASKREPLY: 4499 return 1; 4500 default: 4501 return 0; 4502 } 4503 } 4504 4505 4506 /* ------------------------------------------------------------------------ */ 4507 /* Function: nat_log */ 4508 /* Returns: Nil */ 4509 /* Parameters: nat(I) - pointer to NAT structure */ 4510 /* type(I) - type of log entry to create */ 4511 /* */ 4512 /* Creates a NAT log entry. */ 4513 /* ------------------------------------------------------------------------ */ 4514 void nat_log(nat, type) 4515 struct nat *nat; 4516 u_int type; 4517 { 4518 #ifdef IPFILTER_LOG 4519 # ifndef LARGE_NAT 4520 struct ipnat *np; 4521 int rulen; 4522 # endif 4523 struct natlog natl; 4524 void *items[1]; 4525 size_t sizes[1]; 4526 int types[1]; 4527 4528 natl.nl_inip = nat->nat_inip; 4529 natl.nl_outip = nat->nat_outip; 4530 natl.nl_origip = nat->nat_oip; 4531 natl.nl_bytes[0] = nat->nat_bytes[0]; 4532 natl.nl_bytes[1] = nat->nat_bytes[1]; 4533 natl.nl_pkts[0] = nat->nat_pkts[0]; 4534 natl.nl_pkts[1] = nat->nat_pkts[1]; 4535 natl.nl_origport = nat->nat_oport; 4536 natl.nl_inport = nat->nat_inport; 4537 natl.nl_outport = nat->nat_outport; 4538 natl.nl_p = nat->nat_p; 4539 natl.nl_type = type; 4540 natl.nl_rule = -1; 4541 # ifndef LARGE_NAT 4542 if (nat->nat_ptr != NULL) { 4543 for (rulen = 0, np = nat_list; np; np = np->in_next, rulen++) 4544 if (np == nat->nat_ptr) { 4545 natl.nl_rule = rulen; 4546 break; 4547 } 4548 } 4549 # endif 4550 items[0] = &natl; 4551 sizes[0] = sizeof(natl); 4552 types[0] = 0; 4553 4554 (void) ipllog(IPL_LOGNAT, NULL, items, sizes, types, 1); 4555 #endif 4556 } 4557 4558 4559 #if defined(__OpenBSD__) 4560 /* ------------------------------------------------------------------------ */ 4561 /* Function: nat_ifdetach */ 4562 /* Returns: Nil */ 4563 /* Parameters: ifp(I) - pointer to network interface */ 4564 /* */ 4565 /* Compatibility interface for OpenBSD to trigger the correct updating of */ 4566 /* interface references within IPFilter. */ 4567 /* ------------------------------------------------------------------------ */ 4568 void nat_ifdetach(ifp) 4569 void *ifp; 4570 { 4571 frsync(ifp); 4572 return; 4573 } 4574 #endif 4575 4576 4577 /* ------------------------------------------------------------------------ */ 4578 /* Function: fr_natderef */ 4579 /* Returns: Nil */ 4580 /* Parameters: isp(I) - pointer to pointer to NAT table entry */ 4581 /* */ 4582 /* Decrement the reference counter for this NAT table entry and free it if */ 4583 /* there are no more things using it. */ 4584 /* ------------------------------------------------------------------------ */ 4585 void fr_natderef(natp) 4586 nat_t **natp; 4587 { 4588 nat_t *nat; 4589 4590 nat = *natp; 4591 *natp = NULL; 4592 WRITE_ENTER(&ipf_nat); 4593 nat->nat_ref--; 4594 if (nat->nat_ref == 0) 4595 nat_delete(nat, NL_EXPIRE); 4596 RWLOCK_EXIT(&ipf_nat); 4597 } 4598 4599 4600 /* ------------------------------------------------------------------------ */ 4601 /* Function: fr_natclone */ 4602 /* Returns: ipstate_t* - NULL == cloning failed, */ 4603 /* else pointer to new state structure */ 4604 /* Parameters: fin(I) - pointer to packet information */ 4605 /* is(I) - pointer to master state structure */ 4606 /* Write Lock: ipf_nat */ 4607 /* */ 4608 /* Create a "duplcate" state table entry from the master. */ 4609 /* ------------------------------------------------------------------------ */ 4610 static nat_t *fr_natclone(fin, nat) 4611 fr_info_t *fin; 4612 nat_t *nat; 4613 { 4614 frentry_t *fr; 4615 nat_t *clone; 4616 ipnat_t *np; 4617 4618 KMALLOC(clone, nat_t *); 4619 if (clone == NULL) 4620 return NULL; 4621 bcopy((char *)nat, (char *)clone, sizeof(*clone)); 4622 4623 MUTEX_NUKE(&clone->nat_lock); 4624 4625 clone->nat_aps = NULL; 4626 /* 4627 * Initialize all these so that nat_delete() doesn't cause a crash. 4628 */ 4629 clone->nat_tqe.tqe_pnext = NULL; 4630 clone->nat_tqe.tqe_next = NULL; 4631 clone->nat_tqe.tqe_ifq = NULL; 4632 clone->nat_tqe.tqe_parent = clone; 4633 4634 clone->nat_flags &= ~SI_CLONE; 4635 clone->nat_flags |= SI_CLONED; 4636 4637 if (clone->nat_hm) 4638 clone->nat_hm->hm_ref++; 4639 4640 if (nat_insert(clone, fin->fin_rev) == -1) { 4641 KFREE(clone); 4642 return NULL; 4643 } 4644 np = clone->nat_ptr; 4645 if (np != NULL) { 4646 if (nat_logging) 4647 nat_log(clone, (u_int)np->in_redir); 4648 np->in_use++; 4649 } 4650 fr = clone->nat_fr; 4651 if (fr != NULL) { 4652 MUTEX_ENTER(&fr->fr_lock); 4653 fr->fr_ref++; 4654 MUTEX_EXIT(&fr->fr_lock); 4655 } 4656 4657 /* 4658 * Because the clone is created outside the normal loop of things and 4659 * TCP has special needs in terms of state, initialise the timeout 4660 * state of the new NAT from here. 4661 */ 4662 if (clone->nat_p == IPPROTO_TCP) { 4663 (void) fr_tcp_age(&clone->nat_tqe, fin, nat_tqb, 4664 clone->nat_flags); 4665 } 4666 #ifdef IPFILTER_SYNC 4667 clone->nat_sync = ipfsync_new(SMC_NAT, fin, clone); 4668 #endif 4669 if (nat_logging) 4670 nat_log(clone, NL_CLONE); 4671 return clone; 4672 } 4673 4674 4675 /* ------------------------------------------------------------------------ */ 4676 /* Function: nat_wildok */ 4677 /* Returns: int - 1 == packet's ports match wildcards */ 4678 /* 0 == packet's ports don't match wildcards */ 4679 /* Parameters: nat(I) - NAT entry */ 4680 /* sport(I) - source port */ 4681 /* dport(I) - destination port */ 4682 /* flags(I) - wildcard flags */ 4683 /* dir(I) - packet direction */ 4684 /* */ 4685 /* Use NAT entry and packet direction to determine which combination of */ 4686 /* wildcard flags should be used. */ 4687 /* ------------------------------------------------------------------------ */ 4688 static INLINE int nat_wildok(nat, sport, dport, flags, dir) 4689 nat_t *nat; 4690 int sport; 4691 int dport; 4692 int flags; 4693 int dir; 4694 { 4695 /* 4696 * When called by dir is set to 4697 * nat_inlookup NAT_INBOUND (0) 4698 * nat_outlookup NAT_OUTBOUND (1) 4699 * 4700 * We simply combine the packet's direction in dir with the original 4701 * "intended" direction of that NAT entry in nat->nat_dir to decide 4702 * which combination of wildcard flags to allow. 4703 */ 4704 4705 switch ((dir << 1) | nat->nat_dir) 4706 { 4707 case 3: /* outbound packet / outbound entry */ 4708 if (((nat->nat_inport == sport) || 4709 (flags & SI_W_SPORT)) && 4710 ((nat->nat_oport == dport) || 4711 (flags & SI_W_DPORT))) 4712 return 1; 4713 break; 4714 case 2: /* outbound packet / inbound entry */ 4715 if (((nat->nat_outport == sport) || 4716 (flags & SI_W_DPORT)) && 4717 ((nat->nat_oport == dport) || 4718 (flags & SI_W_SPORT))) 4719 return 1; 4720 break; 4721 case 1: /* inbound packet / outbound entry */ 4722 if (((nat->nat_oport == sport) || 4723 (flags & SI_W_DPORT)) && 4724 ((nat->nat_outport == dport) || 4725 (flags & SI_W_SPORT))) 4726 return 1; 4727 break; 4728 case 0: /* inbound packet / inbound entry */ 4729 if (((nat->nat_oport == sport) || 4730 (flags & SI_W_SPORT)) && 4731 ((nat->nat_outport == dport) || 4732 (flags & SI_W_DPORT))) 4733 return 1; 4734 break; 4735 default: 4736 break; 4737 } 4738 4739 return(0); 4740 } 4741 4742 4743 /* ------------------------------------------------------------------------ */ 4744 /* Function: nat_mssclamp */ 4745 /* Returns: Nil */ 4746 /* Parameters: tcp(I) - pointer to TCP header */ 4747 /* maxmss(I) - value to clamp the TCP MSS to */ 4748 /* csump(I) - pointer to TCP checksum */ 4749 /* */ 4750 /* Check for MSS option and clamp it if necessary. If found and changed, */ 4751 /* then the TCP header checksum will be updated to reflect the change in */ 4752 /* the MSS. */ 4753 /* ------------------------------------------------------------------------ */ 4754 static void nat_mssclamp(tcp, maxmss, csump) 4755 tcphdr_t *tcp; 4756 u_32_t maxmss; 4757 u_short *csump; 4758 { 4759 u_char *cp, *ep, opt; 4760 int hlen, advance; 4761 u_32_t mss, sumd; 4762 4763 hlen = TCP_OFF(tcp) << 2; 4764 if (hlen > sizeof(*tcp)) { 4765 cp = (u_char *)tcp + sizeof(*tcp); 4766 ep = (u_char *)tcp + hlen; 4767 4768 while (cp < ep) { 4769 opt = cp[0]; 4770 if (opt == TCPOPT_EOL) 4771 break; 4772 else if (opt == TCPOPT_NOP) { 4773 cp++; 4774 continue; 4775 } 4776 4777 if (cp + 1 >= ep) 4778 break; 4779 advance = cp[1]; 4780 if ((cp + advance > ep) || (advance <= 0)) 4781 break; 4782 switch (opt) 4783 { 4784 case TCPOPT_MAXSEG: 4785 if (advance != 4) 4786 break; 4787 mss = cp[2] * 256 + cp[3]; 4788 if (mss > maxmss) { 4789 cp[2] = maxmss / 256; 4790 cp[3] = maxmss & 0xff; 4791 CALC_SUMD(mss, maxmss, sumd); 4792 fix_outcksum(csump, sumd); 4793 } 4794 break; 4795 default: 4796 /* ignore unknown options */ 4797 break; 4798 } 4799 4800 cp += advance; 4801 } 4802 } 4803 } 4804 4805 4806 /* ------------------------------------------------------------------------ */ 4807 /* Function: fr_setnatqueue */ 4808 /* Returns: Nil */ 4809 /* Parameters: nat(I)- pointer to NAT structure */ 4810 /* rev(I) - forward(0) or reverse(1) direction */ 4811 /* Locks: ipf_nat (read or write) */ 4812 /* */ 4813 /* Put the NAT entry on its default queue entry, using rev as a helped in */ 4814 /* determining which queue it should be placed on. */ 4815 /* ------------------------------------------------------------------------ */ 4816 void fr_setnatqueue(nat, rev) 4817 nat_t *nat; 4818 int rev; 4819 { 4820 ipftq_t *oifq, *nifq; 4821 4822 if (nat->nat_ptr != NULL) 4823 nifq = nat->nat_ptr->in_tqehead[rev]; 4824 else 4825 nifq = NULL; 4826 4827 if (nifq == NULL) { 4828 switch (nat->nat_p) 4829 { 4830 case IPPROTO_UDP : 4831 nifq = &nat_udptq; 4832 break; 4833 case IPPROTO_ICMP : 4834 nifq = &nat_icmptq; 4835 break; 4836 case IPPROTO_TCP : 4837 nifq = nat_tqb + nat->nat_tqe.tqe_state[rev]; 4838 break; 4839 default : 4840 nifq = &nat_iptq; 4841 break; 4842 } 4843 } 4844 4845 oifq = nat->nat_tqe.tqe_ifq; 4846 /* 4847 * If it's currently on a timeout queue, move it from one queue to 4848 * another, else put it on the end of the newly determined queue. 4849 */ 4850 if (oifq != NULL) 4851 fr_movequeue(&nat->nat_tqe, oifq, nifq); 4852 else 4853 fr_queueappend(&nat->nat_tqe, nifq, nat); 4854 return; 4855 } 4856