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