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[1]; 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[0]; 1375 if (getlock) { 1376 READ_ENTER(&ipf_nat); 1377 } 1378 n = nat_outlookup(&fin, nat->nat_flags, fin.fin_p, 1379 nat->nat_outip, 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 COPYIFNAME(fin->fin_ifp, nat->nat_ifnames[0]); 2361 #ifdef IPFILTER_SYNC 2362 if ((nat->nat_flags & SI_CLONE) == 0) 2363 nat->nat_sync = ipfsync_new(SMC_NAT, fin, nat); 2364 #endif 2365 2366 nat->nat_me = natsave; 2367 nat->nat_dir = direction; 2368 nat->nat_ifps[0] = fin->fin_ifp; 2369 nat->nat_ptr = np; 2370 nat->nat_p = fin->fin_p; 2371 nat->nat_mssclamp = np->in_mssclamp; 2372 fr = fin->fin_fr; 2373 nat->nat_fr = fr; 2374 2375 if ((np->in_apr != NULL) && ((ni->nai_flags & NAT_SLAVE) == 0)) 2376 if (appr_new(fin, nat) == -1) 2377 return -1; 2378 2379 if (nat_insert(nat, fin->fin_rev) == 0) { 2380 if (nat_logging) 2381 nat_log(nat, (u_int)np->in_redir); 2382 np->in_use++; 2383 if (fr != NULL) { 2384 MUTEX_ENTER(&fr->fr_lock); 2385 fr->fr_ref++; 2386 MUTEX_EXIT(&fr->fr_lock); 2387 } 2388 return 0; 2389 } 2390 2391 /* 2392 * nat_insert failed, so cleanup time... 2393 */ 2394 return -1; 2395 } 2396 2397 2398 /* ------------------------------------------------------------------------ */ 2399 /* Function: nat_insert */ 2400 /* Returns: int - 0 == sucess, -1 == failure */ 2401 /* Parameters: nat(I) - pointer to NAT structure */ 2402 /* rev(I) - flag indicating forward/reverse direction of packet */ 2403 /* Write Lock: ipf_nat */ 2404 /* */ 2405 /* Insert a NAT entry into the hash tables for searching and add it to the */ 2406 /* list of active NAT entries. Adjust global counters when complete. */ 2407 /* ------------------------------------------------------------------------ */ 2408 int nat_insert(nat, rev) 2409 nat_t *nat; 2410 int rev; 2411 { 2412 u_int hv1, hv2; 2413 nat_t **natp; 2414 2415 /* 2416 * Try and return an error as early as possible, so calculate the hash 2417 * entry numbers first and then proceed. 2418 */ 2419 if ((nat->nat_flags & (SI_W_SPORT|SI_W_DPORT)) == 0) { 2420 hv1 = NAT_HASH_FN(nat->nat_inip.s_addr, nat->nat_inport, 2421 0xffffffff); 2422 hv1 = NAT_HASH_FN(nat->nat_oip.s_addr, hv1 + nat->nat_oport, 2423 ipf_nattable_sz); 2424 hv2 = NAT_HASH_FN(nat->nat_outip.s_addr, nat->nat_outport, 2425 0xffffffff); 2426 hv2 = NAT_HASH_FN(nat->nat_oip.s_addr, hv2 + nat->nat_oport, 2427 ipf_nattable_sz); 2428 } else { 2429 hv1 = NAT_HASH_FN(nat->nat_inip.s_addr, 0, 0xffffffff); 2430 hv1 = NAT_HASH_FN(nat->nat_oip.s_addr, hv1, ipf_nattable_sz); 2431 hv2 = NAT_HASH_FN(nat->nat_outip.s_addr, 0, 0xffffffff); 2432 hv2 = NAT_HASH_FN(nat->nat_oip.s_addr, hv2, ipf_nattable_sz); 2433 } 2434 2435 if (nat_stats.ns_bucketlen[0][hv1] >= fr_nat_maxbucket || 2436 nat_stats.ns_bucketlen[1][hv2] >= fr_nat_maxbucket) { 2437 return -1; 2438 } 2439 2440 nat->nat_hv[0] = hv1; 2441 nat->nat_hv[1] = hv2; 2442 2443 MUTEX_INIT(&nat->nat_lock, "nat entry lock"); 2444 2445 nat->nat_rev = rev; 2446 nat->nat_ref = 1; 2447 nat->nat_bytes[0] = 0; 2448 nat->nat_pkts[0] = 0; 2449 nat->nat_bytes[1] = 0; 2450 nat->nat_pkts[1] = 0; 2451 2452 nat->nat_ifnames[0][LIFNAMSIZ - 1] = '\0'; 2453 nat->nat_ifps[0] = fr_resolvenic(nat->nat_ifnames[0], 4); 2454 2455 if (nat->nat_ifnames[1][0] !='\0') { 2456 nat->nat_ifnames[1][LIFNAMSIZ - 1] = '\0'; 2457 nat->nat_ifps[1] = fr_resolvenic(nat->nat_ifnames[1], 4); 2458 } else { 2459 (void) strncpy(nat->nat_ifnames[1], nat->nat_ifnames[0], 2460 LIFNAMSIZ); 2461 nat->nat_ifnames[1][LIFNAMSIZ - 1] = '\0'; 2462 nat->nat_ifps[1] = nat->nat_ifps[0]; 2463 } 2464 2465 nat->nat_next = nat_instances; 2466 nat->nat_pnext = &nat_instances; 2467 if (nat_instances) 2468 nat_instances->nat_pnext = &nat->nat_next; 2469 nat_instances = nat; 2470 2471 natp = &nat_table[0][hv1]; 2472 if (*natp) 2473 (*natp)->nat_phnext[0] = &nat->nat_hnext[0]; 2474 nat->nat_phnext[0] = natp; 2475 nat->nat_hnext[0] = *natp; 2476 *natp = nat; 2477 nat_stats.ns_bucketlen[0][hv1]++; 2478 2479 natp = &nat_table[1][hv2]; 2480 if (*natp) 2481 (*natp)->nat_phnext[1] = &nat->nat_hnext[1]; 2482 nat->nat_phnext[1] = natp; 2483 nat->nat_hnext[1] = *natp; 2484 *natp = nat; 2485 nat_stats.ns_bucketlen[1][hv2]++; 2486 2487 fr_setnatqueue(nat, rev); 2488 2489 nat_stats.ns_added++; 2490 nat_stats.ns_inuse++; 2491 return 0; 2492 } 2493 2494 2495 /* ------------------------------------------------------------------------ */ 2496 /* Function: nat_icmperrorlookup */ 2497 /* Returns: nat_t* - point to matching NAT structure */ 2498 /* Parameters: fin(I) - pointer to packet information */ 2499 /* dir(I) - direction of packet (in/out) */ 2500 /* */ 2501 /* Check if the ICMP error message is related to an existing TCP, UDP or */ 2502 /* ICMP query nat entry. It is assumed that the packet is already of the */ 2503 /* the required length. */ 2504 /* ------------------------------------------------------------------------ */ 2505 nat_t *nat_icmperrorlookup(fin, dir) 2506 fr_info_t *fin; 2507 int dir; 2508 { 2509 int flags = 0, minlen; 2510 icmphdr_t *orgicmp; 2511 tcphdr_t *tcp = NULL; 2512 u_short data[2]; 2513 nat_t *nat; 2514 ip_t *oip; 2515 u_int p; 2516 2517 /* 2518 * Does it at least have the return (basic) IP header ? 2519 * Only a basic IP header (no options) should be with an ICMP error 2520 * header. Also, if it's not an error type, then return. 2521 */ 2522 if ((fin->fin_hlen != sizeof(ip_t)) || !(fin->fin_flx & FI_ICMPERR)) 2523 return NULL; 2524 2525 /* 2526 * Check packet size 2527 */ 2528 oip = (ip_t *)((char *)fin->fin_dp + 8); 2529 minlen = IP_HL(oip) << 2; 2530 if ((minlen < sizeof(ip_t)) || 2531 (fin->fin_plen < ICMPERR_IPICMPHLEN + minlen)) 2532 return NULL; 2533 /* 2534 * Is the buffer big enough for all of it ? It's the size of the IP 2535 * header claimed in the encapsulated part which is of concern. It 2536 * may be too big to be in this buffer but not so big that it's 2537 * outside the ICMP packet, leading to TCP deref's causing problems. 2538 * This is possible because we don't know how big oip_hl is when we 2539 * do the pullup early in fr_check() and thus can't gaurantee it is 2540 * all here now. 2541 */ 2542 #ifdef _KERNEL 2543 { 2544 mb_t *m; 2545 2546 m = fin->fin_m; 2547 # if defined(MENTAT) 2548 if ((char *)oip + fin->fin_dlen - ICMPERR_ICMPHLEN > (char *)m->b_wptr) 2549 return NULL; 2550 # else 2551 if ((char *)oip + fin->fin_dlen - ICMPERR_ICMPHLEN > 2552 (char *)fin->fin_ip + M_LEN(m)) 2553 return NULL; 2554 # endif 2555 } 2556 #endif 2557 2558 if (fin->fin_daddr != oip->ip_src.s_addr) 2559 return NULL; 2560 2561 p = oip->ip_p; 2562 if (p == IPPROTO_TCP) 2563 flags = IPN_TCP; 2564 else if (p == IPPROTO_UDP) 2565 flags = IPN_UDP; 2566 else if (p == IPPROTO_ICMP) { 2567 orgicmp = (icmphdr_t *)((char *)oip + (IP_HL(oip) << 2)); 2568 2569 /* see if this is related to an ICMP query */ 2570 if (nat_icmpquerytype4(orgicmp->icmp_type)) { 2571 data[0] = fin->fin_data[0]; 2572 data[1] = fin->fin_data[1]; 2573 fin->fin_data[0] = 0; 2574 fin->fin_data[1] = orgicmp->icmp_id; 2575 2576 flags = IPN_ICMPERR|IPN_ICMPQUERY; 2577 /* 2578 * NOTE : dir refers to the direction of the original 2579 * ip packet. By definition the icmp error 2580 * message flows in the opposite direction. 2581 */ 2582 if (dir == NAT_INBOUND) 2583 nat = nat_inlookup(fin, flags, p, oip->ip_dst, 2584 oip->ip_src); 2585 else 2586 nat = nat_outlookup(fin, flags, p, oip->ip_dst, 2587 oip->ip_src); 2588 fin->fin_data[0] = data[0]; 2589 fin->fin_data[1] = data[1]; 2590 return nat; 2591 } 2592 } 2593 2594 if (flags & IPN_TCPUDP) { 2595 minlen += 8; /* + 64bits of data to get ports */ 2596 if (fin->fin_plen < ICMPERR_IPICMPHLEN + minlen) 2597 return NULL; 2598 2599 data[0] = fin->fin_data[0]; 2600 data[1] = fin->fin_data[1]; 2601 tcp = (tcphdr_t *)((char *)oip + (IP_HL(oip) << 2)); 2602 fin->fin_data[0] = ntohs(tcp->th_dport); 2603 fin->fin_data[1] = ntohs(tcp->th_sport); 2604 2605 if (dir == NAT_INBOUND) { 2606 nat = nat_inlookup(fin, flags, p, oip->ip_dst, 2607 oip->ip_src); 2608 } else { 2609 nat = nat_outlookup(fin, flags, p, oip->ip_dst, 2610 oip->ip_src); 2611 } 2612 fin->fin_data[0] = data[0]; 2613 fin->fin_data[1] = data[1]; 2614 return nat; 2615 } 2616 if (dir == NAT_INBOUND) 2617 return nat_inlookup(fin, 0, p, oip->ip_dst, oip->ip_src); 2618 else 2619 return nat_outlookup(fin, 0, p, oip->ip_dst, oip->ip_src); 2620 } 2621 2622 2623 /* ------------------------------------------------------------------------ */ 2624 /* Function: nat_icmperror */ 2625 /* Returns: nat_t* - point to matching NAT structure */ 2626 /* Parameters: fin(I) - pointer to packet information */ 2627 /* nflags(I) - NAT flags for this packet */ 2628 /* dir(I) - direction of packet (in/out) */ 2629 /* */ 2630 /* Fix up an ICMP packet which is an error message for an existing NAT */ 2631 /* session. This will correct both packet header data and checksums. */ 2632 /* */ 2633 /* This should *ONLY* be used for incoming ICMP error packets to make sure */ 2634 /* a NAT'd ICMP packet gets correctly recognised. */ 2635 /* ------------------------------------------------------------------------ */ 2636 nat_t *nat_icmperror(fin, nflags, dir) 2637 fr_info_t *fin; 2638 u_int *nflags; 2639 int dir; 2640 { 2641 u_32_t sum1, sum2, sumd, sumd2; 2642 struct in_addr in; 2643 icmphdr_t *icmp; 2644 int flags, dlen; 2645 u_short *csump; 2646 tcphdr_t *tcp; 2647 nat_t *nat; 2648 ip_t *oip; 2649 void *dp; 2650 2651 if ((fin->fin_flx & (FI_SHORT|FI_FRAGBODY))) 2652 return NULL; 2653 /* 2654 * nat_icmperrorlookup() will return NULL for `defective' packets. 2655 */ 2656 if ((fin->fin_v != 4) || !(nat = nat_icmperrorlookup(fin, dir))) 2657 return NULL; 2658 2659 tcp = NULL; 2660 csump = NULL; 2661 flags = 0; 2662 sumd2 = 0; 2663 *nflags = IPN_ICMPERR; 2664 icmp = fin->fin_dp; 2665 oip = (ip_t *)&icmp->icmp_ip; 2666 dp = (((char *)oip) + (IP_HL(oip) << 2)); 2667 if (oip->ip_p == IPPROTO_TCP) { 2668 tcp = (tcphdr_t *)dp; 2669 csump = (u_short *)&tcp->th_sum; 2670 flags = IPN_TCP; 2671 } else if (oip->ip_p == IPPROTO_UDP) { 2672 udphdr_t *udp; 2673 2674 udp = (udphdr_t *)dp; 2675 tcp = (tcphdr_t *)dp; 2676 csump = (u_short *)&udp->uh_sum; 2677 flags = IPN_UDP; 2678 } else if (oip->ip_p == IPPROTO_ICMP) 2679 flags = IPN_ICMPQUERY; 2680 dlen = fin->fin_plen - ((char *)dp - (char *)fin->fin_ip); 2681 2682 /* 2683 * Need to adjust ICMP header to include the real IP#'s and 2684 * port #'s. Only apply a checksum change relative to the 2685 * IP address change as it will be modified again in fr_checknatout 2686 * for both address and port. Two checksum changes are 2687 * necessary for the two header address changes. Be careful 2688 * to only modify the checksum once for the port # and twice 2689 * for the IP#. 2690 */ 2691 2692 /* 2693 * Step 1 2694 * Fix the IP addresses in the offending IP packet. You also need 2695 * to adjust the IP header checksum of that offending IP packet 2696 * and the ICMP checksum of the ICMP error message itself. 2697 * 2698 * Unfortunately, for UDP and TCP, the IP addresses are also contained 2699 * in the pseudo header that is used to compute the UDP resp. TCP 2700 * checksum. So, we must compensate that as well. Even worse, the 2701 * change in the UDP and TCP checksums require yet another 2702 * adjustment of the ICMP checksum of the ICMP error message. 2703 */ 2704 2705 if (oip->ip_dst.s_addr == nat->nat_oip.s_addr) { 2706 sum1 = LONG_SUM(ntohl(oip->ip_src.s_addr)); 2707 in = nat->nat_inip; 2708 oip->ip_src = in; 2709 } else { 2710 sum1 = LONG_SUM(ntohl(oip->ip_dst.s_addr)); 2711 in = nat->nat_outip; 2712 oip->ip_dst = in; 2713 } 2714 2715 sum2 = LONG_SUM(ntohl(in.s_addr)); 2716 2717 CALC_SUMD(sum1, sum2, sumd); 2718 2719 /* 2720 * Fix IP checksum of the offending IP packet to adjust for 2721 * the change in the IP address. 2722 * 2723 * Normally, you would expect that the ICMP checksum of the 2724 * ICMP error message needs to be adjusted as well for the 2725 * IP address change in oip. 2726 * However, this is a NOP, because the ICMP checksum is 2727 * calculated over the complete ICMP packet, which includes the 2728 * changed oip IP addresses and oip->ip_sum. However, these 2729 * two changes cancel each other out (if the delta for 2730 * the IP address is x, then the delta for ip_sum is minus x), 2731 * so no change in the icmp_cksum is necessary. 2732 * 2733 * Be careful that nat_dir refers to the direction of the 2734 * offending IP packet (oip), not to its ICMP response (icmp) 2735 */ 2736 fix_datacksum(&oip->ip_sum, sumd); 2737 /* Fix icmp cksum : IP Addr + Cksum */ 2738 sumd2 = (sumd >> 16); 2739 2740 /* 2741 * Fix UDP pseudo header checksum to compensate for the 2742 * IP address change. 2743 */ 2744 if ((oip->ip_p == IPPROTO_UDP) && (dlen >= 8) && (*csump != 0)) { 2745 /* 2746 * The UDP checksum is optional, only adjust it 2747 * if it has been set. 2748 */ 2749 sum1 = ntohs(*csump); 2750 fix_datacksum(csump, sumd); 2751 sum2 = ntohs(*csump); 2752 2753 /* 2754 * Fix ICMP checksum to compensate the UDP 2755 * checksum adjustment. 2756 */ 2757 sumd2 = sumd << 1; 2758 CALC_SUMD(sum1, sum2, sumd); 2759 sumd2 += sumd; 2760 } 2761 2762 /* 2763 * Fix TCP pseudo header checksum to compensate for the 2764 * IP address change. Before we can do the change, we 2765 * must make sure that oip is sufficient large to hold 2766 * the TCP checksum (normally it does not!). 2767 * 18 = offsetof(tcphdr_t, th_sum) + 2 2768 */ 2769 else if (oip->ip_p == IPPROTO_TCP && dlen >= 18) { 2770 sum1 = ntohs(*csump); 2771 fix_datacksum(csump, sumd); 2772 sum2 = ntohs(*csump); 2773 2774 /* 2775 * Fix ICMP checksum to compensate the TCP 2776 * checksum adjustment. 2777 */ 2778 sumd2 = sumd << 1; 2779 CALC_SUMD(sum1, sum2, sumd); 2780 sumd2 += sumd; 2781 } else { 2782 if (nat->nat_dir == NAT_OUTBOUND) 2783 sumd2 = ~sumd2; 2784 else 2785 sumd2 = ~sumd2 + 1; 2786 } 2787 2788 if (((flags & IPN_TCPUDP) != 0) && (dlen >= 4)) { 2789 int mode = 0; 2790 2791 /* 2792 * Step 2 : 2793 * For offending TCP/UDP IP packets, translate the ports as 2794 * well, based on the NAT specification. Of course such 2795 * a change must be reflected in the ICMP checksum as well. 2796 * 2797 * Advance notice : Now it becomes complicated :-) 2798 * 2799 * Since the port fields are part of the TCP/UDP checksum 2800 * of the offending IP packet, you need to adjust that checksum 2801 * as well... but, if you change, you must change the icmp 2802 * checksum *again*, to reflect that change. 2803 * 2804 * To further complicate: the TCP checksum is not in the first 2805 * 8 bytes of the offending ip packet, so it most likely is not 2806 * available. Some OSses like Solaris return enough bytes to 2807 * include the TCP checksum. So we have to check if the 2808 * ip->ip_len actually holds the TCP checksum of the oip! 2809 */ 2810 2811 if (nat->nat_oport == tcp->th_dport) { 2812 if (tcp->th_sport != nat->nat_inport) { 2813 mode = 1; 2814 sum1 = ntohs(nat->nat_inport); 2815 sum2 = ntohs(tcp->th_sport); 2816 } 2817 } else if (tcp->th_sport == nat->nat_oport) { 2818 mode = 2; 2819 sum1 = ntohs(nat->nat_outport); 2820 sum2 = ntohs(tcp->th_dport); 2821 } 2822 2823 if (mode == 1) { 2824 /* 2825 * Fix ICMP checksum to compensate port adjustment. 2826 */ 2827 tcp->th_sport = htons(sum1); 2828 2829 /* 2830 * Fix udp checksum to compensate port adjustment. 2831 * NOTE : the offending IP packet flows the other 2832 * direction compared to the ICMP message. 2833 * 2834 * The UDP checksum is optional, only adjust it if 2835 * it has been set. 2836 */ 2837 if ((oip->ip_p == IPPROTO_UDP) && 2838 (dlen >= 8) && (*csump != 0)) { 2839 sumd = sum1 - sum2; 2840 sumd2 += sumd; 2841 2842 sum1 = ntohs(*csump); 2843 fix_datacksum(csump, sumd); 2844 sum2 = ntohs(*csump); 2845 2846 /* 2847 * Fix ICMP checksum to compenstate 2848 * UDP checksum adjustment. 2849 */ 2850 CALC_SUMD(sum1, sum2, sumd); 2851 sumd2 += sumd; 2852 } 2853 2854 /* 2855 * Fix TCP checksum (if present) to compensate port 2856 * adjustment. NOTE : the offending IP packet flows 2857 * the other direction compared to the ICMP message. 2858 */ 2859 if (oip->ip_p == IPPROTO_TCP) { 2860 if (dlen >= 18) { 2861 sumd = sum1 - sum2; 2862 sumd2 += sumd; 2863 2864 sum1 = ntohs(*csump); 2865 fix_datacksum(csump, sumd); 2866 sum2 = ntohs(*csump); 2867 2868 /* 2869 * Fix ICMP checksum to compensate 2870 * TCP checksum adjustment. 2871 */ 2872 CALC_SUMD(sum1, sum2, sumd); 2873 sumd2 += sumd; 2874 } else { 2875 sumd = sum2 - sum1 + 1; 2876 sumd2 += sumd; 2877 } 2878 } 2879 } else if (mode == 2) { 2880 /* 2881 * Fix ICMP checksum to compensate port adjustment. 2882 */ 2883 tcp->th_dport = htons(sum1); 2884 2885 /* 2886 * Fix UDP checksum to compensate port adjustment. 2887 * NOTE : the offending IP packet flows the other 2888 * direction compared to the ICMP message. 2889 * 2890 * The UDP checksum is optional, only adjust 2891 * it if it has been set. 2892 */ 2893 if ((oip->ip_p == IPPROTO_UDP) && 2894 (dlen >= 8) && (*csump != 0)) { 2895 sumd = sum1 - sum2; 2896 sumd2 += sumd; 2897 2898 sum1 = ntohs(*csump); 2899 fix_datacksum(csump, sumd); 2900 sum2 = ntohs(*csump); 2901 2902 /* 2903 * Fix ICMP checksum to compensate 2904 * UDP checksum adjustment. 2905 */ 2906 CALC_SUMD(sum1, sum2, sumd); 2907 sumd2 += sumd; 2908 } 2909 2910 /* 2911 * Fix TCP checksum (if present) to compensate port 2912 * adjustment. NOTE : the offending IP packet flows 2913 * the other direction compared to the ICMP message. 2914 */ 2915 if (oip->ip_p == IPPROTO_TCP) { 2916 if (dlen >= 18) { 2917 sumd = sum1 - sum2; 2918 sumd2 += sumd; 2919 2920 sum1 = ntohs(*csump); 2921 fix_datacksum(csump, sumd); 2922 sum2 = ntohs(*csump); 2923 2924 /* 2925 * Fix ICMP checksum to compensate 2926 * TCP checksum adjustment. 2927 */ 2928 CALC_SUMD(sum1, sum2, sumd); 2929 sumd2 += sumd; 2930 } else { 2931 if (nat->nat_dir == NAT_INBOUND) 2932 sumd = sum2 - sum1; 2933 else 2934 sumd = sum2 - sum1 + 1; 2935 sumd2 += sumd; 2936 } 2937 } 2938 } 2939 if (sumd2 != 0) { 2940 sumd2 = (sumd2 & 0xffff) + (sumd2 >> 16); 2941 sumd2 = (sumd2 & 0xffff) + (sumd2 >> 16); 2942 fix_incksum(fin, &icmp->icmp_cksum, sumd2); 2943 } 2944 } else if (((flags & IPN_ICMPQUERY) != 0) && (dlen >= 8)) { 2945 icmphdr_t *orgicmp; 2946 2947 /* 2948 * XXX - what if this is bogus hl and we go off the end ? 2949 * In this case, nat_icmperrorlookup() will have returned NULL. 2950 */ 2951 orgicmp = (icmphdr_t *)dp; 2952 2953 if (nat->nat_dir == NAT_OUTBOUND) { 2954 if (orgicmp->icmp_id != nat->nat_inport) { 2955 2956 /* 2957 * Fix ICMP checksum (of the offening ICMP 2958 * query packet) to compensate the change 2959 * in the ICMP id of the offending ICMP 2960 * packet. 2961 * 2962 * Since you modify orgicmp->icmp_id with 2963 * a delta (say x) and you compensate that 2964 * in origicmp->icmp_cksum with a delta 2965 * minus x, you don't have to adjust the 2966 * overall icmp->icmp_cksum 2967 */ 2968 sum1 = ntohs(orgicmp->icmp_id); 2969 sum2 = ntohs(nat->nat_inport); 2970 CALC_SUMD(sum1, sum2, sumd); 2971 orgicmp->icmp_id = nat->nat_inport; 2972 fix_datacksum(&orgicmp->icmp_cksum, sumd); 2973 } 2974 } /* nat_dir == NAT_INBOUND is impossible for icmp queries */ 2975 } 2976 return nat; 2977 } 2978 2979 2980 /* 2981 * NB: these lookups don't lock access to the list, it assumed that it has 2982 * already been done! 2983 */ 2984 2985 /* ------------------------------------------------------------------------ */ 2986 /* Function: nat_inlookup */ 2987 /* Returns: nat_t* - NULL == no match, */ 2988 /* else pointer to matching NAT entry */ 2989 /* Parameters: fin(I) - pointer to packet information */ 2990 /* flags(I) - NAT flags for this packet */ 2991 /* p(I) - protocol for this packet */ 2992 /* src(I) - source IP address */ 2993 /* mapdst(I) - destination IP address */ 2994 /* */ 2995 /* Lookup a nat entry based on the mapped destination ip address/port and */ 2996 /* real source address/port. We use this lookup when receiving a packet, */ 2997 /* we're looking for a table entry, based on the destination address. */ 2998 /* */ 2999 /* NOTE: THE PACKET BEING CHECKED (IF FOUND) HAS A MAPPING ALREADY. */ 3000 /* */ 3001 /* NOTE: IT IS ASSUMED THAT ipf_nat IS ONLY HELD WITH A READ LOCK WHEN */ 3002 /* THIS FUNCTION IS CALLED WITH NAT_SEARCH SET IN nflags. */ 3003 /* */ 3004 /* flags -> relevant are IPN_UDP/IPN_TCP/IPN_ICMPQUERY that indicate if */ 3005 /* the packet is of said protocol */ 3006 /* ------------------------------------------------------------------------ */ 3007 nat_t *nat_inlookup(fin, flags, p, src, mapdst) 3008 fr_info_t *fin; 3009 u_int flags, p; 3010 struct in_addr src , mapdst; 3011 { 3012 u_short sport, dport; 3013 ipnat_t *ipn; 3014 u_int sflags; 3015 nat_t *nat; 3016 int nflags; 3017 u_32_t dst; 3018 void *ifp; 3019 u_int hv; 3020 3021 if (fin != NULL) 3022 ifp = fin->fin_ifp; 3023 else 3024 ifp = NULL; 3025 sport = 0; 3026 dport = 0; 3027 dst = mapdst.s_addr; 3028 sflags = flags & NAT_TCPUDPICMP; 3029 3030 switch (p) 3031 { 3032 case IPPROTO_TCP : 3033 case IPPROTO_UDP : 3034 sport = htons(fin->fin_data[0]); 3035 dport = htons(fin->fin_data[1]); 3036 break; 3037 case IPPROTO_ICMP : 3038 if (flags & IPN_ICMPERR) 3039 sport = fin->fin_data[1]; 3040 else 3041 dport = fin->fin_data[1]; 3042 break; 3043 default : 3044 break; 3045 } 3046 3047 3048 if ((flags & SI_WILDP) != 0) 3049 goto find_in_wild_ports; 3050 3051 hv = NAT_HASH_FN(dst, dport, 0xffffffff); 3052 hv = NAT_HASH_FN(src.s_addr, hv + sport, ipf_nattable_sz); 3053 nat = nat_table[1][hv]; 3054 for (; nat; nat = nat->nat_hnext[1]) { 3055 nflags = nat->nat_flags; 3056 3057 if (ifp != NULL) { 3058 if (nat->nat_dir == NAT_REDIRECT) { 3059 if (ifp != nat->nat_ifps[0]) 3060 continue; 3061 } else { 3062 if (ifp != nat->nat_ifps[1]) 3063 continue; 3064 } 3065 } 3066 3067 if (nat->nat_oip.s_addr == src.s_addr && 3068 nat->nat_outip.s_addr == dst && 3069 (((p == 0) && 3070 (sflags == (nat->nat_flags & IPN_TCPUDPICMP))) 3071 || (p == nat->nat_p))) { 3072 switch (p) 3073 { 3074 #if 0 3075 case IPPROTO_GRE : 3076 if (nat->nat_call[1] != fin->fin_data[0]) 3077 continue; 3078 break; 3079 #endif 3080 case IPPROTO_ICMP : 3081 if ((flags & IPN_ICMPERR) != 0) { 3082 if (nat->nat_outport != sport) 3083 continue; 3084 } else { 3085 if (nat->nat_outport != dport) 3086 continue; 3087 } 3088 break; 3089 case IPPROTO_TCP : 3090 case IPPROTO_UDP : 3091 if (nat->nat_oport != sport) 3092 continue; 3093 if (nat->nat_outport != dport) 3094 continue; 3095 break; 3096 default : 3097 break; 3098 } 3099 3100 ipn = nat->nat_ptr; 3101 if ((ipn != NULL) && (nat->nat_aps != NULL)) 3102 if (appr_match(fin, nat) != 0) 3103 continue; 3104 return nat; 3105 } 3106 } 3107 3108 /* 3109 * So if we didn't find it but there are wildcard members in the hash 3110 * table, go back and look for them. We do this search and update here 3111 * because it is modifying the NAT table and we want to do this only 3112 * for the first packet that matches. The exception, of course, is 3113 * for "dummy" (FI_IGNORE) lookups. 3114 */ 3115 find_in_wild_ports: 3116 if (!(flags & NAT_TCPUDP) || !(flags & NAT_SEARCH)) 3117 return NULL; 3118 if (nat_stats.ns_wilds == 0) 3119 return NULL; 3120 3121 RWLOCK_EXIT(&ipf_nat); 3122 3123 hv = NAT_HASH_FN(dst, 0, 0xffffffff); 3124 hv = NAT_HASH_FN(src.s_addr, hv, ipf_nattable_sz); 3125 3126 WRITE_ENTER(&ipf_nat); 3127 3128 nat = nat_table[1][hv]; 3129 for (; nat; nat = nat->nat_hnext[1]) { 3130 if (ifp != NULL) { 3131 if (nat->nat_dir == NAT_REDIRECT) { 3132 if (ifp != nat->nat_ifps[0]) 3133 continue; 3134 } else { 3135 if (ifp != nat->nat_ifps[1]) 3136 continue; 3137 } 3138 } 3139 3140 if (nat->nat_p != fin->fin_p) 3141 continue; 3142 if (nat->nat_oip.s_addr != src.s_addr || 3143 nat->nat_outip.s_addr != dst) 3144 continue; 3145 3146 nflags = nat->nat_flags; 3147 if (!(nflags & (NAT_TCPUDP|SI_WILDP))) 3148 continue; 3149 3150 if (nat_wildok(nat, (int)sport, (int)dport, nflags, 3151 NAT_INBOUND) == 1) { 3152 if ((fin->fin_flx & FI_IGNORE) != 0) 3153 break; 3154 if ((nflags & SI_CLONE) != 0) { 3155 nat = fr_natclone(fin, nat); 3156 if (nat == NULL) 3157 break; 3158 } else { 3159 MUTEX_ENTER(&ipf_nat_new); 3160 nat_stats.ns_wilds--; 3161 MUTEX_EXIT(&ipf_nat_new); 3162 } 3163 nat->nat_oport = sport; 3164 nat->nat_outport = dport; 3165 nat->nat_flags &= ~(SI_W_DPORT|SI_W_SPORT); 3166 nat_tabmove(nat); 3167 break; 3168 } 3169 } 3170 3171 MUTEX_DOWNGRADE(&ipf_nat); 3172 3173 return nat; 3174 } 3175 3176 3177 /* ------------------------------------------------------------------------ */ 3178 /* Function: nat_tabmove */ 3179 /* Returns: Nil */ 3180 /* Parameters: nat(I) - pointer to NAT structure */ 3181 /* Write Lock: ipf_nat */ 3182 /* */ 3183 /* This function is only called for TCP/UDP NAT table entries where the */ 3184 /* original was placed in the table without hashing on the ports and we now */ 3185 /* want to include hashing on port numbers. */ 3186 /* ------------------------------------------------------------------------ */ 3187 static void nat_tabmove(nat) 3188 nat_t *nat; 3189 { 3190 nat_t **natp; 3191 u_int hv; 3192 3193 if (nat->nat_flags & SI_CLONE) 3194 return; 3195 3196 /* 3197 * Remove the NAT entry from the old location 3198 */ 3199 if (nat->nat_hnext[0]) 3200 nat->nat_hnext[0]->nat_phnext[0] = nat->nat_phnext[0]; 3201 *nat->nat_phnext[0] = nat->nat_hnext[0]; 3202 nat_stats.ns_bucketlen[0][nat->nat_hv[0]]--; 3203 3204 if (nat->nat_hnext[1]) 3205 nat->nat_hnext[1]->nat_phnext[1] = nat->nat_phnext[1]; 3206 *nat->nat_phnext[1] = nat->nat_hnext[1]; 3207 nat_stats.ns_bucketlen[1][nat->nat_hv[1]]--; 3208 3209 /* 3210 * Add into the NAT table in the new position 3211 */ 3212 hv = NAT_HASH_FN(nat->nat_inip.s_addr, nat->nat_inport, 0xffffffff); 3213 hv = NAT_HASH_FN(nat->nat_oip.s_addr, hv + nat->nat_oport, 3214 ipf_nattable_sz); 3215 nat->nat_hv[0] = hv; 3216 natp = &nat_table[0][hv]; 3217 if (*natp) 3218 (*natp)->nat_phnext[0] = &nat->nat_hnext[0]; 3219 nat->nat_phnext[0] = natp; 3220 nat->nat_hnext[0] = *natp; 3221 *natp = nat; 3222 nat_stats.ns_bucketlen[0][hv]++; 3223 3224 hv = NAT_HASH_FN(nat->nat_outip.s_addr, nat->nat_outport, 0xffffffff); 3225 hv = NAT_HASH_FN(nat->nat_oip.s_addr, hv + nat->nat_oport, 3226 ipf_nattable_sz); 3227 nat->nat_hv[1] = hv; 3228 natp = &nat_table[1][hv]; 3229 if (*natp) 3230 (*natp)->nat_phnext[1] = &nat->nat_hnext[1]; 3231 nat->nat_phnext[1] = natp; 3232 nat->nat_hnext[1] = *natp; 3233 *natp = nat; 3234 nat_stats.ns_bucketlen[1][hv]++; 3235 } 3236 3237 3238 /* ------------------------------------------------------------------------ */ 3239 /* Function: nat_outlookup */ 3240 /* Returns: nat_t* - NULL == no match, */ 3241 /* else pointer to matching NAT entry */ 3242 /* Parameters: fin(I) - pointer to packet information */ 3243 /* flags(I) - NAT flags for this packet */ 3244 /* p(I) - protocol for this packet */ 3245 /* src(I) - source IP address */ 3246 /* dst(I) - destination IP address */ 3247 /* rw(I) - 1 == write lock on ipf_nat held, 0 == read lock. */ 3248 /* */ 3249 /* Lookup a nat entry based on the source 'real' ip address/port and */ 3250 /* destination address/port. We use this lookup when sending a packet out, */ 3251 /* we're looking for a table entry, based on the source address. */ 3252 /* */ 3253 /* NOTE: THE PACKET BEING CHECKED (IF FOUND) HAS A MAPPING ALREADY. */ 3254 /* */ 3255 /* NOTE: IT IS ASSUMED THAT ipf_nat IS ONLY HELD WITH A READ LOCK WHEN */ 3256 /* THIS FUNCTION IS CALLED WITH NAT_SEARCH SET IN nflags. */ 3257 /* */ 3258 /* flags -> relevant are IPN_UDP/IPN_TCP/IPN_ICMPQUERY that indicate if */ 3259 /* the packet is of said protocol */ 3260 /* ------------------------------------------------------------------------ */ 3261 nat_t *nat_outlookup(fin, flags, p, src, dst) 3262 fr_info_t *fin; 3263 u_int flags, p; 3264 struct in_addr src , dst; 3265 { 3266 u_short sport, dport; 3267 u_int sflags; 3268 ipnat_t *ipn; 3269 u_32_t srcip; 3270 nat_t *nat; 3271 int nflags; 3272 void *ifp; 3273 u_int hv; 3274 3275 ifp = fin->fin_ifp; 3276 srcip = src.s_addr; 3277 sflags = flags & IPN_TCPUDPICMP; 3278 sport = 0; 3279 dport = 0; 3280 3281 switch (p) 3282 { 3283 case IPPROTO_TCP : 3284 case IPPROTO_UDP : 3285 sport = htons(fin->fin_data[0]); 3286 dport = htons(fin->fin_data[1]); 3287 break; 3288 case IPPROTO_ICMP : 3289 if (flags & IPN_ICMPERR) 3290 sport = fin->fin_data[1]; 3291 else 3292 dport = fin->fin_data[1]; 3293 break; 3294 default : 3295 break; 3296 } 3297 3298 if ((flags & SI_WILDP) != 0) 3299 goto find_out_wild_ports; 3300 3301 hv = NAT_HASH_FN(srcip, sport, 0xffffffff); 3302 hv = NAT_HASH_FN(dst.s_addr, hv + dport, ipf_nattable_sz); 3303 nat = nat_table[0][hv]; 3304 for (; nat; nat = nat->nat_hnext[0]) { 3305 nflags = nat->nat_flags; 3306 3307 if (ifp != NULL) { 3308 if (nat->nat_dir == NAT_REDIRECT) { 3309 if (ifp != nat->nat_ifps[1]) 3310 continue; 3311 } else { 3312 if (ifp != nat->nat_ifps[0]) 3313 continue; 3314 } 3315 } 3316 3317 if (nat->nat_inip.s_addr == srcip && 3318 nat->nat_oip.s_addr == dst.s_addr && 3319 (((p == 0) && (sflags == (nflags & NAT_TCPUDPICMP))) 3320 || (p == nat->nat_p))) { 3321 switch (p) 3322 { 3323 #if 0 3324 case IPPROTO_GRE : 3325 if (nat->nat_call[1] != fin->fin_data[0]) 3326 continue; 3327 break; 3328 #endif 3329 case IPPROTO_TCP : 3330 case IPPROTO_UDP : 3331 if (nat->nat_oport != dport) 3332 continue; 3333 if (nat->nat_inport != sport) 3334 continue; 3335 break; 3336 default : 3337 break; 3338 } 3339 3340 ipn = nat->nat_ptr; 3341 if ((ipn != NULL) && (nat->nat_aps != NULL)) 3342 if (appr_match(fin, nat) != 0) 3343 continue; 3344 return nat; 3345 } 3346 } 3347 3348 /* 3349 * So if we didn't find it but there are wildcard members in the hash 3350 * table, go back and look for them. We do this search and update here 3351 * because it is modifying the NAT table and we want to do this only 3352 * for the first packet that matches. The exception, of course, is 3353 * for "dummy" (FI_IGNORE) lookups. 3354 */ 3355 find_out_wild_ports: 3356 if (!(flags & NAT_TCPUDP) || !(flags & NAT_SEARCH)) 3357 return NULL; 3358 if (nat_stats.ns_wilds == 0) 3359 return NULL; 3360 3361 RWLOCK_EXIT(&ipf_nat); 3362 3363 hv = NAT_HASH_FN(srcip, 0, 0xffffffff); 3364 hv = NAT_HASH_FN(dst.s_addr, hv, ipf_nattable_sz); 3365 3366 WRITE_ENTER(&ipf_nat); 3367 3368 nat = nat_table[0][hv]; 3369 for (; nat; nat = nat->nat_hnext[0]) { 3370 if (ifp != NULL) { 3371 if (nat->nat_dir == NAT_REDIRECT) { 3372 if (ifp != nat->nat_ifps[1]) 3373 continue; 3374 } else { 3375 if (ifp != nat->nat_ifps[0]) 3376 continue; 3377 } 3378 } 3379 3380 if (nat->nat_p != fin->fin_p) 3381 continue; 3382 if ((nat->nat_inip.s_addr != srcip) || 3383 (nat->nat_oip.s_addr != dst.s_addr)) 3384 continue; 3385 3386 nflags = nat->nat_flags; 3387 if (!(nflags & (NAT_TCPUDP|SI_WILDP))) 3388 continue; 3389 3390 if (nat_wildok(nat, (int)sport, (int)dport, nflags, 3391 NAT_OUTBOUND) == 1) { 3392 if ((fin->fin_flx & FI_IGNORE) != 0) 3393 break; 3394 if ((nflags & SI_CLONE) != 0) { 3395 nat = fr_natclone(fin, nat); 3396 if (nat == NULL) 3397 break; 3398 } else { 3399 MUTEX_ENTER(&ipf_nat_new); 3400 nat_stats.ns_wilds--; 3401 MUTEX_EXIT(&ipf_nat_new); 3402 } 3403 nat->nat_inport = sport; 3404 nat->nat_oport = dport; 3405 if (nat->nat_outport == 0) 3406 nat->nat_outport = sport; 3407 nat->nat_flags &= ~(SI_W_DPORT|SI_W_SPORT); 3408 nat_tabmove(nat); 3409 break; 3410 } 3411 } 3412 3413 MUTEX_DOWNGRADE(&ipf_nat); 3414 3415 return nat; 3416 } 3417 3418 3419 /* ------------------------------------------------------------------------ */ 3420 /* Function: nat_lookupredir */ 3421 /* Returns: nat_t* - NULL == no match, */ 3422 /* else pointer to matching NAT entry */ 3423 /* Parameters: np(I) - pointer to description of packet to find NAT table */ 3424 /* entry for. */ 3425 /* */ 3426 /* Lookup the NAT tables to search for a matching redirect */ 3427 /* ------------------------------------------------------------------------ */ 3428 nat_t *nat_lookupredir(np) 3429 natlookup_t *np; 3430 { 3431 fr_info_t fi; 3432 nat_t *nat; 3433 3434 bzero((char *)&fi, sizeof(fi)); 3435 if (np->nl_flags & IPN_IN) { 3436 fi.fin_data[0] = ntohs(np->nl_realport); 3437 fi.fin_data[1] = ntohs(np->nl_outport); 3438 } else { 3439 fi.fin_data[0] = ntohs(np->nl_inport); 3440 fi.fin_data[1] = ntohs(np->nl_outport); 3441 } 3442 if (np->nl_flags & IPN_TCP) 3443 fi.fin_p = IPPROTO_TCP; 3444 else if (np->nl_flags & IPN_UDP) 3445 fi.fin_p = IPPROTO_UDP; 3446 else if (np->nl_flags & (IPN_ICMPERR|IPN_ICMPQUERY)) 3447 fi.fin_p = IPPROTO_ICMP; 3448 3449 /* 3450 * We can do two sorts of lookups: 3451 * - IPN_IN: we have the `real' and `out' address, look for `in'. 3452 * - default: we have the `in' and `out' address, look for `real'. 3453 */ 3454 if (np->nl_flags & IPN_IN) { 3455 if ((nat = nat_inlookup(&fi, np->nl_flags, fi.fin_p, 3456 np->nl_realip, np->nl_outip))) { 3457 np->nl_inip = nat->nat_inip; 3458 np->nl_inport = nat->nat_inport; 3459 } 3460 } else { 3461 /* 3462 * If nl_inip is non null, this is a lookup based on the real 3463 * ip address. Else, we use the fake. 3464 */ 3465 if ((nat = nat_outlookup(&fi, np->nl_flags, fi.fin_p, 3466 np->nl_inip, np->nl_outip))) { 3467 3468 if ((np->nl_flags & IPN_FINDFORWARD) != 0) { 3469 fr_info_t fin; 3470 bzero((char *)&fin, sizeof(fin)); 3471 fin.fin_p = nat->nat_p; 3472 fin.fin_data[0] = ntohs(nat->nat_outport); 3473 fin.fin_data[1] = ntohs(nat->nat_oport); 3474 if (nat_inlookup(&fin, np->nl_flags, fin.fin_p, 3475 nat->nat_outip, 3476 nat->nat_oip) != NULL) { 3477 np->nl_flags &= ~IPN_FINDFORWARD; 3478 } 3479 } 3480 3481 np->nl_realip = nat->nat_outip; 3482 np->nl_realport = nat->nat_outport; 3483 } 3484 } 3485 3486 return nat; 3487 } 3488 3489 3490 /* ------------------------------------------------------------------------ */ 3491 /* Function: nat_match */ 3492 /* Returns: int - 0 == no match, 1 == match */ 3493 /* Parameters: fin(I) - pointer to packet information */ 3494 /* np(I) - pointer to NAT rule */ 3495 /* */ 3496 /* Pull the matching of a packet against a NAT rule out of that complex */ 3497 /* loop inside fr_checknatin() and lay it out properly in its own function. */ 3498 /* ------------------------------------------------------------------------ */ 3499 static int nat_match(fin, np) 3500 fr_info_t *fin; 3501 ipnat_t *np; 3502 { 3503 frtuc_t *ft; 3504 3505 if (fin->fin_v != 4) 3506 return 0; 3507 3508 if (np->in_p && fin->fin_p != np->in_p) 3509 return 0; 3510 3511 if (fin->fin_out) { 3512 if (!(np->in_redir & (NAT_MAP|NAT_MAPBLK))) 3513 return 0; 3514 if (((fin->fin_fi.fi_saddr & np->in_inmsk) != np->in_inip) 3515 ^ ((np->in_flags & IPN_NOTSRC) != 0)) 3516 return 0; 3517 if (((fin->fin_fi.fi_daddr & np->in_srcmsk) != np->in_srcip) 3518 ^ ((np->in_flags & IPN_NOTDST) != 0)) 3519 return 0; 3520 } else { 3521 if (!(np->in_redir & NAT_REDIRECT)) 3522 return 0; 3523 if (((fin->fin_fi.fi_saddr & np->in_srcmsk) != np->in_srcip) 3524 ^ ((np->in_flags & IPN_NOTSRC) != 0)) 3525 return 0; 3526 if (((fin->fin_fi.fi_daddr & np->in_outmsk) != np->in_outip) 3527 ^ ((np->in_flags & IPN_NOTDST) != 0)) 3528 return 0; 3529 } 3530 3531 ft = &np->in_tuc; 3532 if (!(fin->fin_flx & FI_TCPUDP) || 3533 (fin->fin_flx & (FI_SHORT|FI_FRAGBODY))) { 3534 if (ft->ftu_scmp || ft->ftu_dcmp) 3535 return 0; 3536 return 1; 3537 } 3538 3539 return fr_tcpudpchk(fin, ft); 3540 } 3541 3542 3543 /* ------------------------------------------------------------------------ */ 3544 /* Function: nat_update */ 3545 /* Returns: Nil */ 3546 /* Parameters: nat(I) - pointer to NAT structure */ 3547 /* np(I) - pointer to NAT rule */ 3548 /* */ 3549 /* Updates the lifetime of a NAT table entry for non-TCP packets. Must be */ 3550 /* called with fin_rev updated - i.e. after calling nat_proto(). */ 3551 /* ------------------------------------------------------------------------ */ 3552 void nat_update(fin, nat, np) 3553 fr_info_t *fin; 3554 nat_t *nat; 3555 ipnat_t *np; 3556 { 3557 ipftq_t *ifq, *ifq2; 3558 ipftqent_t *tqe; 3559 3560 MUTEX_ENTER(&nat->nat_lock); 3561 tqe = &nat->nat_tqe; 3562 ifq = tqe->tqe_ifq; 3563 3564 /* 3565 * We allow over-riding of NAT timeouts from NAT rules, even for 3566 * TCP, however, if it is TCP and there is no rule timeout set, 3567 * then do not update the timeout here. 3568 */ 3569 if (np != NULL) 3570 ifq2 = np->in_tqehead[fin->fin_rev]; 3571 else 3572 ifq2 = NULL; 3573 3574 if (nat->nat_p == IPPROTO_TCP && ifq2 == NULL) { 3575 (void) fr_tcp_age(&nat->nat_tqe, fin, nat_tqb, 0); 3576 } else { 3577 if (ifq2 == NULL) { 3578 if (nat->nat_p == IPPROTO_UDP) 3579 ifq2 = &nat_udptq; 3580 else if (nat->nat_p == IPPROTO_ICMP) 3581 ifq2 = &nat_icmptq; 3582 else 3583 ifq2 = &nat_iptq; 3584 } 3585 3586 fr_movequeue(tqe, ifq, ifq2); 3587 } 3588 MUTEX_EXIT(&nat->nat_lock); 3589 } 3590 3591 3592 /* ------------------------------------------------------------------------ */ 3593 /* Function: fr_checknatout */ 3594 /* Returns: int - -1 == packet failed NAT checks so block it, */ 3595 /* 0 == no packet translation occurred, */ 3596 /* 1 == packet was successfully translated. */ 3597 /* Parameters: fin(I) - pointer to packet information */ 3598 /* passp(I) - pointer to filtering result flags */ 3599 /* */ 3600 /* Check to see if an outcoming packet should be changed. ICMP packets are */ 3601 /* first checked to see if they match an existing entry (if an error), */ 3602 /* otherwise a search of the current NAT table is made. If neither results */ 3603 /* in a match then a search for a matching NAT rule is made. Create a new */ 3604 /* NAT entry if a we matched a NAT rule. Lastly, actually change the */ 3605 /* packet header(s) as required. */ 3606 /* ------------------------------------------------------------------------ */ 3607 int fr_checknatout(fin, passp) 3608 fr_info_t *fin; 3609 u_32_t *passp; 3610 { 3611 struct ifnet *ifp, *sifp; 3612 icmphdr_t *icmp = NULL; 3613 tcphdr_t *tcp = NULL; 3614 int rval, natfailed; 3615 ipnat_t *np = NULL; 3616 u_int nflags = 0; 3617 u_32_t ipa, iph; 3618 int natadd = 1; 3619 frentry_t *fr; 3620 nat_t *nat; 3621 3622 if (nat_stats.ns_rules == 0 || fr_nat_lock != 0) 3623 return 0; 3624 3625 natfailed = 0; 3626 fr = fin->fin_fr; 3627 sifp = fin->fin_ifp; 3628 if ((fr != NULL) && !(fr->fr_flags & FR_DUP) && 3629 fr->fr_tif.fd_ifp && fr->fr_tif.fd_ifp != (void *)-1) 3630 fin->fin_ifp = fr->fr_tif.fd_ifp; 3631 ifp = fin->fin_ifp; 3632 3633 if (!(fin->fin_flx & FI_SHORT) && (fin->fin_off == 0)) { 3634 switch (fin->fin_p) 3635 { 3636 case IPPROTO_TCP : 3637 nflags = IPN_TCP; 3638 break; 3639 case IPPROTO_UDP : 3640 nflags = IPN_UDP; 3641 break; 3642 case IPPROTO_ICMP : 3643 icmp = fin->fin_dp; 3644 3645 /* 3646 * This is an incoming packet, so the destination is 3647 * the icmp_id and the source port equals 0 3648 */ 3649 if (nat_icmpquerytype4(icmp->icmp_type)) 3650 nflags = IPN_ICMPQUERY; 3651 break; 3652 default : 3653 break; 3654 } 3655 3656 if ((nflags & IPN_TCPUDP)) 3657 tcp = fin->fin_dp; 3658 } 3659 3660 ipa = fin->fin_saddr; 3661 3662 READ_ENTER(&ipf_nat); 3663 3664 if ((fin->fin_p == IPPROTO_ICMP) && !(nflags & IPN_ICMPQUERY) && 3665 (nat = nat_icmperror(fin, &nflags, NAT_OUTBOUND))) 3666 /*EMPTY*/; 3667 else if ((fin->fin_flx & FI_FRAG) && (nat = fr_nat_knownfrag(fin))) 3668 natadd = 0; 3669 else if ((nat = nat_outlookup(fin, nflags|NAT_SEARCH, (u_int)fin->fin_p, 3670 fin->fin_src, fin->fin_dst))) { 3671 nflags = nat->nat_flags; 3672 } else { 3673 u_32_t hv, msk, nmsk; 3674 3675 /* 3676 * If there is no current entry in the nat table for this IP#, 3677 * create one for it (if there is a matching rule). 3678 */ 3679 RWLOCK_EXIT(&ipf_nat); 3680 msk = 0xffffffff; 3681 nmsk = nat_masks; 3682 WRITE_ENTER(&ipf_nat); 3683 maskloop: 3684 iph = ipa & htonl(msk); 3685 hv = NAT_HASH_FN(iph, 0, ipf_natrules_sz); 3686 for (np = nat_rules[hv]; np; np = np->in_mnext) 3687 { 3688 if ((np->in_ifps[0] && (np->in_ifps[0] != ifp))) 3689 continue; 3690 if (np->in_v != fin->fin_v) 3691 continue; 3692 if (np->in_p && (np->in_p != fin->fin_p)) 3693 continue; 3694 if ((np->in_flags & IPN_RF) && !(np->in_flags & nflags)) 3695 continue; 3696 if (np->in_flags & IPN_FILTER) { 3697 if (!nat_match(fin, np)) 3698 continue; 3699 } else if ((ipa & np->in_inmsk) != np->in_inip) 3700 continue; 3701 3702 if ((fr != NULL) && 3703 !fr_matchtag(&np->in_tag, &fr->fr_nattag)) 3704 continue; 3705 3706 if (*np->in_plabel != '\0') { 3707 if (((np->in_flags & IPN_FILTER) == 0) && 3708 (np->in_dport != tcp->th_dport)) 3709 continue; 3710 if (appr_ok(fin, tcp, np) == 0) 3711 continue; 3712 } 3713 3714 if ((nat = nat_new(fin, np, NULL, nflags, 3715 NAT_OUTBOUND))) { 3716 np->in_hits++; 3717 break; 3718 } else 3719 natfailed = -1; 3720 } 3721 if ((np == NULL) && (nmsk != 0)) { 3722 while (nmsk) { 3723 msk <<= 1; 3724 if (nmsk & 0x80000000) 3725 break; 3726 nmsk <<= 1; 3727 } 3728 if (nmsk != 0) { 3729 nmsk <<= 1; 3730 goto maskloop; 3731 } 3732 } 3733 MUTEX_DOWNGRADE(&ipf_nat); 3734 } 3735 3736 if (nat != NULL) { 3737 rval = fr_natout(fin, nat, natadd, nflags); 3738 if (rval == 1) { 3739 MUTEX_ENTER(&nat->nat_lock); 3740 nat->nat_ref++; 3741 MUTEX_EXIT(&nat->nat_lock); 3742 fin->fin_nat = nat; 3743 } 3744 } else 3745 rval = natfailed; 3746 RWLOCK_EXIT(&ipf_nat); 3747 3748 if (rval == -1) { 3749 if (passp != NULL) 3750 *passp = FR_BLOCK; 3751 fin->fin_flx |= FI_BADNAT; 3752 } 3753 fin->fin_ifp = sifp; 3754 return rval; 3755 } 3756 3757 /* ------------------------------------------------------------------------ */ 3758 /* Function: fr_natout */ 3759 /* Returns: int - -1 == packet failed NAT checks so block it, */ 3760 /* 1 == packet was successfully translated. */ 3761 /* Parameters: fin(I) - pointer to packet information */ 3762 /* nat(I) - pointer to NAT structure */ 3763 /* natadd(I) - flag indicating if it is safe to add frag cache */ 3764 /* nflags(I) - NAT flags set for this packet */ 3765 /* */ 3766 /* Translate a packet coming "out" on an interface. */ 3767 /* ------------------------------------------------------------------------ */ 3768 int fr_natout(fin, nat, natadd, nflags) 3769 fr_info_t *fin; 3770 nat_t *nat; 3771 int natadd; 3772 u_32_t nflags; 3773 { 3774 icmphdr_t *icmp; 3775 u_short *csump; 3776 tcphdr_t *tcp; 3777 ipnat_t *np; 3778 int i; 3779 3780 tcp = NULL; 3781 icmp = NULL; 3782 csump = NULL; 3783 np = nat->nat_ptr; 3784 3785 if ((natadd != 0) && (fin->fin_flx & FI_FRAG) && (np != NULL)) 3786 (void) fr_nat_newfrag(fin, 0, nat); 3787 3788 MUTEX_ENTER(&nat->nat_lock); 3789 nat->nat_bytes[1] += fin->fin_plen; 3790 nat->nat_pkts[1]++; 3791 MUTEX_EXIT(&nat->nat_lock); 3792 3793 /* 3794 * Fix up checksums, not by recalculating them, but 3795 * simply computing adjustments. 3796 * This is only done for STREAMS based IP implementations where the 3797 * checksum has already been calculated by IP. In all other cases, 3798 * IPFilter is called before the checksum needs calculating so there 3799 * is no call to modify whatever is in the header now. 3800 */ 3801 if (fin->fin_v == 4) { 3802 if (nflags == IPN_ICMPERR) { 3803 u_32_t s1, s2, sumd; 3804 3805 s1 = LONG_SUM(ntohl(fin->fin_saddr)); 3806 s2 = LONG_SUM(ntohl(nat->nat_outip.s_addr)); 3807 CALC_SUMD(s1, s2, sumd); 3808 fix_outcksum(fin, &fin->fin_ip->ip_sum, sumd); 3809 } 3810 #if !defined(_KERNEL) || defined(MENTAT) || defined(__sgi) || \ 3811 defined(linux) || defined(BRIDGE_IPF) 3812 else { 3813 /* 3814 * Strictly speaking, this isn't necessary on BSD 3815 * kernels because they do checksum calculation after 3816 * this code has run BUT if ipfilter is being used 3817 * to do NAT as a bridge, that code doesn't exist. 3818 */ 3819 if (nat->nat_dir == NAT_OUTBOUND) 3820 fix_outcksum(fin, &fin->fin_ip->ip_sum, 3821 nat->nat_ipsumd); 3822 else 3823 fix_incksum(fin, &fin->fin_ip->ip_sum, 3824 nat->nat_ipsumd); 3825 } 3826 #endif 3827 } 3828 3829 if (!(fin->fin_flx & FI_SHORT) && (fin->fin_off == 0)) { 3830 if ((nat->nat_outport != 0) && (nflags & IPN_TCPUDP)) { 3831 tcp = fin->fin_dp; 3832 3833 tcp->th_sport = nat->nat_outport; 3834 fin->fin_data[0] = ntohs(nat->nat_outport); 3835 } 3836 3837 if ((nat->nat_outport != 0) && (nflags & IPN_ICMPQUERY)) { 3838 icmp = fin->fin_dp; 3839 icmp->icmp_id = nat->nat_outport; 3840 } 3841 3842 csump = nat_proto(fin, nat, nflags); 3843 } 3844 3845 fin->fin_ip->ip_src = nat->nat_outip; 3846 3847 nat_update(fin, nat, np); 3848 3849 /* 3850 * The above comments do not hold for layer 4 (or higher) checksums... 3851 */ 3852 if (csump != NULL) { 3853 if (nat->nat_dir == NAT_OUTBOUND) 3854 fix_outcksum(fin, csump, nat->nat_sumd[1]); 3855 else 3856 fix_incksum(fin, csump, nat->nat_sumd[1]); 3857 } 3858 #ifdef IPFILTER_SYNC 3859 ipfsync_update(SMC_NAT, fin, nat->nat_sync); 3860 #endif 3861 /* ------------------------------------------------------------- */ 3862 /* A few quick notes: */ 3863 /* Following are test conditions prior to calling the */ 3864 /* appr_check routine. */ 3865 /* */ 3866 /* A NULL tcp indicates a non TCP/UDP packet. When dealing */ 3867 /* with a redirect rule, we attempt to match the packet's */ 3868 /* source port against in_dport, otherwise we'd compare the */ 3869 /* packet's destination. */ 3870 /* ------------------------------------------------------------- */ 3871 if ((np != NULL) && (np->in_apr != NULL)) { 3872 i = appr_check(fin, nat); 3873 if (i == 0) 3874 i = 1; 3875 } else 3876 i = 1; 3877 ATOMIC_INCL(nat_stats.ns_mapped[1]); 3878 fin->fin_flx |= FI_NATED; 3879 return i; 3880 } 3881 3882 3883 /* ------------------------------------------------------------------------ */ 3884 /* Function: fr_checknatin */ 3885 /* Returns: int - -1 == packet failed NAT checks so block it, */ 3886 /* 0 == no packet translation occurred, */ 3887 /* 1 == packet was successfully translated. */ 3888 /* Parameters: fin(I) - pointer to packet information */ 3889 /* passp(I) - pointer to filtering result flags */ 3890 /* */ 3891 /* Check to see if an incoming packet should be changed. ICMP packets are */ 3892 /* first checked to see if they match an existing entry (if an error), */ 3893 /* otherwise a search of the current NAT table is made. If neither results */ 3894 /* in a match then a search for a matching NAT rule is made. Create a new */ 3895 /* NAT entry if a we matched a NAT rule. Lastly, actually change the */ 3896 /* packet header(s) as required. */ 3897 /* ------------------------------------------------------------------------ */ 3898 int fr_checknatin(fin, passp) 3899 fr_info_t *fin; 3900 u_32_t *passp; 3901 { 3902 u_int nflags, natadd; 3903 int rval, natfailed; 3904 struct ifnet *ifp; 3905 struct in_addr in; 3906 icmphdr_t *icmp; 3907 tcphdr_t *tcp; 3908 u_short dport; 3909 ipnat_t *np; 3910 nat_t *nat; 3911 u_32_t iph; 3912 3913 if (nat_stats.ns_rules == 0 || fr_nat_lock != 0) 3914 return 0; 3915 3916 tcp = NULL; 3917 icmp = NULL; 3918 dport = 0; 3919 natadd = 1; 3920 nflags = 0; 3921 natfailed = 0; 3922 ifp = fin->fin_ifp; 3923 3924 if (!(fin->fin_flx & FI_SHORT) && (fin->fin_off == 0)) { 3925 switch (fin->fin_p) 3926 { 3927 case IPPROTO_TCP : 3928 nflags = IPN_TCP; 3929 break; 3930 case IPPROTO_UDP : 3931 nflags = IPN_UDP; 3932 break; 3933 case IPPROTO_ICMP : 3934 icmp = fin->fin_dp; 3935 3936 /* 3937 * This is an incoming packet, so the destination is 3938 * the icmp_id and the source port equals 0 3939 */ 3940 if (nat_icmpquerytype4(icmp->icmp_type)) { 3941 nflags = IPN_ICMPQUERY; 3942 dport = icmp->icmp_id; 3943 } break; 3944 default : 3945 break; 3946 } 3947 3948 if ((nflags & IPN_TCPUDP)) { 3949 tcp = fin->fin_dp; 3950 dport = tcp->th_dport; 3951 } 3952 } 3953 3954 in = fin->fin_dst; 3955 3956 READ_ENTER(&ipf_nat); 3957 3958 if ((fin->fin_p == IPPROTO_ICMP) && !(nflags & IPN_ICMPQUERY) && 3959 (nat = nat_icmperror(fin, &nflags, NAT_INBOUND))) 3960 /*EMPTY*/; 3961 else if ((fin->fin_flx & FI_FRAG) && (nat = fr_nat_knownfrag(fin))) 3962 natadd = 0; 3963 else if ((nat = nat_inlookup(fin, nflags|NAT_SEARCH, (u_int)fin->fin_p, 3964 fin->fin_src, in))) { 3965 nflags = nat->nat_flags; 3966 } else { 3967 u_32_t hv, msk, rmsk; 3968 3969 RWLOCK_EXIT(&ipf_nat); 3970 rmsk = rdr_masks; 3971 msk = 0xffffffff; 3972 WRITE_ENTER(&ipf_nat); 3973 /* 3974 * If there is no current entry in the nat table for this IP#, 3975 * create one for it (if there is a matching rule). 3976 */ 3977 maskloop: 3978 iph = in.s_addr & htonl(msk); 3979 hv = NAT_HASH_FN(iph, 0, ipf_rdrrules_sz); 3980 for (np = rdr_rules[hv]; np; np = np->in_rnext) { 3981 if (np->in_ifps[0] && (np->in_ifps[0] != ifp)) 3982 continue; 3983 if (np->in_v != fin->fin_v) 3984 continue; 3985 if (np->in_p && (np->in_p != fin->fin_p)) 3986 continue; 3987 if ((np->in_flags & IPN_RF) && !(np->in_flags & nflags)) 3988 continue; 3989 if (np->in_flags & IPN_FILTER) { 3990 if (!nat_match(fin, np)) 3991 continue; 3992 } else { 3993 if ((in.s_addr & np->in_outmsk) != np->in_outip) 3994 continue; 3995 if (np->in_pmin && 3996 ((ntohs(np->in_pmax) < ntohs(dport)) || 3997 (ntohs(dport) < ntohs(np->in_pmin)))) 3998 continue; 3999 } 4000 4001 if (*np->in_plabel != '\0') { 4002 if (!appr_ok(fin, tcp, np)) { 4003 continue; 4004 } 4005 } 4006 4007 nat = nat_new(fin, np, NULL, nflags, NAT_INBOUND); 4008 if (nat != NULL) { 4009 np->in_hits++; 4010 break; 4011 } else 4012 natfailed = -1; 4013 } 4014 4015 if ((np == NULL) && (rmsk != 0)) { 4016 while (rmsk) { 4017 msk <<= 1; 4018 if (rmsk & 0x80000000) 4019 break; 4020 rmsk <<= 1; 4021 } 4022 if (rmsk != 0) { 4023 rmsk <<= 1; 4024 goto maskloop; 4025 } 4026 } 4027 MUTEX_DOWNGRADE(&ipf_nat); 4028 } 4029 if (nat != NULL) { 4030 rval = fr_natin(fin, nat, natadd, nflags); 4031 if (rval == 1) { 4032 MUTEX_ENTER(&nat->nat_lock); 4033 nat->nat_ref++; 4034 MUTEX_EXIT(&nat->nat_lock); 4035 fin->fin_nat = nat; 4036 fin->fin_state = nat->nat_state; 4037 } 4038 } else 4039 rval = natfailed; 4040 RWLOCK_EXIT(&ipf_nat); 4041 4042 if (rval == -1) { 4043 if (passp != NULL) 4044 *passp = FR_BLOCK; 4045 fin->fin_flx |= FI_BADNAT; 4046 } 4047 return rval; 4048 } 4049 4050 4051 /* ------------------------------------------------------------------------ */ 4052 /* Function: fr_natin */ 4053 /* Returns: int - -1 == packet failed NAT checks so block it, */ 4054 /* 1 == packet was successfully translated. */ 4055 /* Parameters: fin(I) - pointer to packet information */ 4056 /* nat(I) - pointer to NAT structure */ 4057 /* natadd(I) - flag indicating if it is safe to add frag cache */ 4058 /* nflags(I) - NAT flags set for this packet */ 4059 /* Locks Held: ipf_nat (READ) */ 4060 /* */ 4061 /* Translate a packet coming "in" on an interface. */ 4062 /* ------------------------------------------------------------------------ */ 4063 int fr_natin(fin, nat, natadd, nflags) 4064 fr_info_t *fin; 4065 nat_t *nat; 4066 int natadd; 4067 u_32_t nflags; 4068 { 4069 icmphdr_t *icmp; 4070 u_short *csump; 4071 tcphdr_t *tcp; 4072 ipnat_t *np; 4073 int i; 4074 4075 tcp = NULL; 4076 csump = NULL; 4077 np = nat->nat_ptr; 4078 fin->fin_fr = nat->nat_fr; 4079 4080 if (np != NULL) { 4081 if ((natadd != 0) && (fin->fin_flx & FI_FRAG)) 4082 (void) fr_nat_newfrag(fin, 0, nat); 4083 4084 /* ------------------------------------------------------------- */ 4085 /* A few quick notes: */ 4086 /* Following are test conditions prior to calling the */ 4087 /* appr_check routine. */ 4088 /* */ 4089 /* A NULL tcp indicates a non TCP/UDP packet. When dealing */ 4090 /* with a map rule, we attempt to match the packet's */ 4091 /* source port against in_dport, otherwise we'd compare the */ 4092 /* packet's destination. */ 4093 /* ------------------------------------------------------------- */ 4094 if (np->in_apr != NULL) { 4095 i = appr_check(fin, nat); 4096 if (i == -1) { 4097 return -1; 4098 } 4099 } 4100 } 4101 4102 #ifdef IPFILTER_SYNC 4103 ipfsync_update(SMC_NAT, fin, nat->nat_sync); 4104 #endif 4105 4106 MUTEX_ENTER(&nat->nat_lock); 4107 nat->nat_bytes[0] += fin->fin_plen; 4108 nat->nat_pkts[0]++; 4109 MUTEX_EXIT(&nat->nat_lock); 4110 4111 fin->fin_ip->ip_dst = nat->nat_inip; 4112 fin->fin_fi.fi_daddr = nat->nat_inip.s_addr; 4113 if (nflags & IPN_TCPUDP) 4114 tcp = fin->fin_dp; 4115 4116 /* 4117 * Fix up checksums, not by recalculating them, but 4118 * simply computing adjustments. 4119 * Why only do this for some platforms on inbound packets ? 4120 * Because for those that it is done, IP processing is yet to happen 4121 * and so the IPv4 header checksum has not yet been evaluated. 4122 * Perhaps it should always be done for the benefit of things like 4123 * fast forwarding (so that it doesn't need to be recomputed) but with 4124 * header checksum offloading, perhaps it is a moot point. 4125 */ 4126 #if !defined(_KERNEL) || defined(MENTAT) || defined(__sgi) || \ 4127 defined(__osf__) || defined(linux) 4128 if (nat->nat_dir == NAT_OUTBOUND) 4129 fix_incksum(fin, &fin->fin_ip->ip_sum, nat->nat_ipsumd); 4130 else 4131 fix_outcksum(fin, &fin->fin_ip->ip_sum, nat->nat_ipsumd); 4132 #endif 4133 4134 if (!(fin->fin_flx & FI_SHORT) && (fin->fin_off == 0)) { 4135 if ((nat->nat_inport != 0) && (nflags & IPN_TCPUDP)) { 4136 tcp->th_dport = nat->nat_inport; 4137 fin->fin_data[1] = ntohs(nat->nat_inport); 4138 } 4139 4140 4141 if ((nat->nat_inport != 0) && (nflags & IPN_ICMPQUERY)) { 4142 icmp = fin->fin_dp; 4143 4144 icmp->icmp_id = nat->nat_inport; 4145 } 4146 4147 csump = nat_proto(fin, nat, nflags); 4148 } 4149 4150 nat_update(fin, nat, np); 4151 4152 /* 4153 * The above comments do not hold for layer 4 (or higher) checksums... 4154 */ 4155 if (csump != NULL) { 4156 if (nat->nat_dir == NAT_OUTBOUND) 4157 fix_incksum(fin, csump, nat->nat_sumd[0]); 4158 else 4159 fix_outcksum(fin, csump, nat->nat_sumd[0]); 4160 } 4161 ATOMIC_INCL(nat_stats.ns_mapped[0]); 4162 fin->fin_flx |= FI_NATED; 4163 if (np != NULL && np->in_tag.ipt_num[0] != 0) 4164 fin->fin_nattag = &np->in_tag; 4165 return 1; 4166 } 4167 4168 4169 /* ------------------------------------------------------------------------ */ 4170 /* Function: nat_proto */ 4171 /* Returns: u_short* - pointer to transport header checksum to update, */ 4172 /* NULL if the transport protocol is not recognised */ 4173 /* as needing a checksum update. */ 4174 /* Parameters: fin(I) - pointer to packet information */ 4175 /* nat(I) - pointer to NAT structure */ 4176 /* nflags(I) - NAT flags set for this packet */ 4177 /* */ 4178 /* Return the pointer to the checksum field for each protocol so understood.*/ 4179 /* If support for making other changes to a protocol header is required, */ 4180 /* that is not strictly 'address' translation, such as clamping the MSS in */ 4181 /* TCP down to a specific value, then do it from here. */ 4182 /* ------------------------------------------------------------------------ */ 4183 u_short *nat_proto(fin, nat, nflags) 4184 fr_info_t *fin; 4185 nat_t *nat; 4186 u_int nflags; 4187 { 4188 icmphdr_t *icmp; 4189 u_short *csump; 4190 tcphdr_t *tcp; 4191 udphdr_t *udp; 4192 4193 csump = NULL; 4194 if (fin->fin_out == 0) { 4195 fin->fin_rev = (nat->nat_dir == NAT_OUTBOUND); 4196 } else { 4197 fin->fin_rev = (nat->nat_dir == NAT_INBOUND); 4198 } 4199 4200 switch (fin->fin_p) 4201 { 4202 case IPPROTO_TCP : 4203 tcp = fin->fin_dp; 4204 4205 csump = &tcp->th_sum; 4206 4207 /* 4208 * Do a MSS CLAMPING on a SYN packet, 4209 * only deal IPv4 for now. 4210 */ 4211 if ((nat->nat_mssclamp != 0) && (tcp->th_flags & TH_SYN) != 0) 4212 nat_mssclamp(tcp, nat->nat_mssclamp, fin, csump); 4213 4214 break; 4215 4216 case IPPROTO_UDP : 4217 udp = fin->fin_dp; 4218 4219 if (udp->uh_sum) 4220 csump = &udp->uh_sum; 4221 break; 4222 4223 case IPPROTO_ICMP : 4224 icmp = fin->fin_dp; 4225 4226 if ((nflags & IPN_ICMPQUERY) != 0) { 4227 if (icmp->icmp_cksum != 0) 4228 csump = &icmp->icmp_cksum; 4229 } 4230 break; 4231 } 4232 return csump; 4233 } 4234 4235 4236 /* ------------------------------------------------------------------------ */ 4237 /* Function: fr_natunload */ 4238 /* Returns: Nil */ 4239 /* Parameters: Nil */ 4240 /* */ 4241 /* Free all memory used by NAT structures allocated at runtime. */ 4242 /* ------------------------------------------------------------------------ */ 4243 void fr_natunload() 4244 { 4245 ipftq_t *ifq, *ifqnext; 4246 4247 (void) nat_clearlist(); 4248 (void) nat_flushtable(); 4249 4250 /* 4251 * Proxy timeout queues are not cleaned here because although they 4252 * exist on the NAT list, appr_unload is called after fr_natunload 4253 * and the proxies actually are responsible for them being created. 4254 * Should the proxy timeouts have their own list? There's no real 4255 * justification as this is the only complication. 4256 */ 4257 for (ifq = nat_utqe; ifq != NULL; ifq = ifqnext) { 4258 ifqnext = ifq->ifq_next; 4259 if (((ifq->ifq_flags & IFQF_PROXY) == 0) && 4260 (fr_deletetimeoutqueue(ifq) == 0)) 4261 fr_freetimeoutqueue(ifq); 4262 } 4263 4264 if (nat_table[0] != NULL) { 4265 KFREES(nat_table[0], sizeof(nat_t *) * ipf_nattable_sz); 4266 nat_table[0] = NULL; 4267 } 4268 if (nat_table[1] != NULL) { 4269 KFREES(nat_table[1], sizeof(nat_t *) * ipf_nattable_sz); 4270 nat_table[1] = NULL; 4271 } 4272 if (nat_rules != NULL) { 4273 KFREES(nat_rules, sizeof(ipnat_t *) * ipf_natrules_sz); 4274 nat_rules = NULL; 4275 } 4276 if (rdr_rules != NULL) { 4277 KFREES(rdr_rules, sizeof(ipnat_t *) * ipf_rdrrules_sz); 4278 rdr_rules = NULL; 4279 } 4280 if (maptable != NULL) { 4281 KFREES(maptable, sizeof(hostmap_t *) * ipf_hostmap_sz); 4282 maptable = NULL; 4283 } 4284 if (nat_stats.ns_bucketlen[0] != NULL) { 4285 KFREES(nat_stats.ns_bucketlen[0], 4286 sizeof(u_long *) * ipf_nattable_sz); 4287 nat_stats.ns_bucketlen[0] = NULL; 4288 } 4289 if (nat_stats.ns_bucketlen[1] != NULL) { 4290 KFREES(nat_stats.ns_bucketlen[1], 4291 sizeof(u_long *) * ipf_nattable_sz); 4292 nat_stats.ns_bucketlen[1] = NULL; 4293 } 4294 4295 if (fr_nat_maxbucket_reset == 1) 4296 fr_nat_maxbucket = 0; 4297 4298 if (fr_nat_init == 1) { 4299 fr_nat_init = 0; 4300 fr_sttab_destroy(nat_tqb); 4301 4302 RW_DESTROY(&ipf_natfrag); 4303 RW_DESTROY(&ipf_nat); 4304 4305 MUTEX_DESTROY(&ipf_nat_new); 4306 MUTEX_DESTROY(&ipf_natio); 4307 4308 MUTEX_DESTROY(&nat_udptq.ifq_lock); 4309 MUTEX_DESTROY(&nat_icmptq.ifq_lock); 4310 MUTEX_DESTROY(&nat_iptq.ifq_lock); 4311 } 4312 } 4313 4314 4315 /* ------------------------------------------------------------------------ */ 4316 /* Function: fr_natexpire */ 4317 /* Returns: Nil */ 4318 /* Parameters: Nil */ 4319 /* */ 4320 /* Check all of the timeout queues for entries at the top which need to be */ 4321 /* expired. */ 4322 /* ------------------------------------------------------------------------ */ 4323 void fr_natexpire() 4324 { 4325 ipftq_t *ifq, *ifqnext; 4326 ipftqent_t *tqe, *tqn; 4327 int i; 4328 SPL_INT(s); 4329 4330 SPL_NET(s); 4331 WRITE_ENTER(&ipf_nat); 4332 for (ifq = nat_tqb, i = 0; ifq != NULL; ifq = ifq->ifq_next) { 4333 for (tqn = ifq->ifq_head; ((tqe = tqn) != NULL); i++) { 4334 if (tqe->tqe_die > fr_ticks) 4335 break; 4336 tqn = tqe->tqe_next; 4337 nat_delete(tqe->tqe_parent, NL_EXPIRE); 4338 } 4339 } 4340 4341 for (ifq = nat_utqe; ifq != NULL; ifq = ifqnext) { 4342 ifqnext = ifq->ifq_next; 4343 4344 for (tqn = ifq->ifq_head; ((tqe = tqn) != NULL); i++) { 4345 if (tqe->tqe_die > fr_ticks) 4346 break; 4347 tqn = tqe->tqe_next; 4348 nat_delete(tqe->tqe_parent, NL_EXPIRE); 4349 } 4350 } 4351 4352 for (ifq = nat_utqe; ifq != NULL; ifq = ifqnext) { 4353 ifqnext = ifq->ifq_next; 4354 4355 if (((ifq->ifq_flags & IFQF_DELETE) != 0) && 4356 (ifq->ifq_ref == 0)) { 4357 fr_freetimeoutqueue(ifq); 4358 } 4359 } 4360 4361 RWLOCK_EXIT(&ipf_nat); 4362 SPL_X(s); 4363 } 4364 4365 4366 /* ------------------------------------------------------------------------ */ 4367 /* Function: fr_natsync */ 4368 /* Returns: Nil */ 4369 /* Parameters: ifp(I) - pointer to network interface */ 4370 /* */ 4371 /* Walk through all of the currently active NAT sessions, looking for those */ 4372 /* which need to have their translated address updated. */ 4373 /* ------------------------------------------------------------------------ */ 4374 void fr_natsync(ifp) 4375 void *ifp; 4376 { 4377 u_32_t sum1, sum2, sumd; 4378 struct in_addr in; 4379 ipnat_t *n; 4380 nat_t *nat; 4381 void *ifp2; 4382 SPL_INT(s); 4383 4384 if (fr_running <= 0) 4385 return; 4386 4387 /* 4388 * Change IP addresses for NAT sessions for any protocol except TCP 4389 * since it will break the TCP connection anyway. The only rules 4390 * which will get changed are those which are "map ... -> 0/32", 4391 * where the rule specifies the address is taken from the interface. 4392 */ 4393 SPL_NET(s); 4394 WRITE_ENTER(&ipf_nat); 4395 4396 if (fr_running <= 0) { 4397 RWLOCK_EXIT(&ipf_nat); 4398 return; 4399 } 4400 4401 for (nat = nat_instances; nat; nat = nat->nat_next) { 4402 if ((nat->nat_flags & IPN_TCP) != 0) 4403 continue; 4404 n = nat->nat_ptr; 4405 if ((n == NULL) || 4406 (n->in_outip != 0) || (n->in_outmsk != 0xffffffff)) 4407 continue; 4408 if (((ifp == NULL) || (ifp == nat->nat_ifps[0]) || 4409 (ifp == nat->nat_ifps[1]))) { 4410 nat->nat_ifps[0] = GETIFP(nat->nat_ifnames[0], 4); 4411 if (nat->nat_ifnames[1][0] != '\0') { 4412 nat->nat_ifps[1] = GETIFP(nat->nat_ifnames[1], 4413 4); 4414 } else 4415 nat->nat_ifps[1] = nat->nat_ifps[0]; 4416 ifp2 = nat->nat_ifps[0]; 4417 if (ifp2 == NULL) 4418 continue; 4419 4420 /* 4421 * Change the map-to address to be the same as the 4422 * new one. 4423 */ 4424 sum1 = nat->nat_outip.s_addr; 4425 if (fr_ifpaddr(4, FRI_NORMAL, ifp2, &in, NULL) != -1) 4426 nat->nat_outip = in; 4427 sum2 = nat->nat_outip.s_addr; 4428 4429 if (sum1 == sum2) 4430 continue; 4431 /* 4432 * Readjust the checksum adjustment to take into 4433 * account the new IP#. 4434 */ 4435 CALC_SUMD(sum1, sum2, sumd); 4436 /* XXX - dont change for TCP when solaris does 4437 * hardware checksumming. 4438 */ 4439 sumd += nat->nat_sumd[0]; 4440 nat->nat_sumd[0] = (sumd & 0xffff) + (sumd >> 16); 4441 nat->nat_sumd[1] = nat->nat_sumd[0]; 4442 } 4443 } 4444 4445 for (n = nat_list; (n != NULL); n = n->in_next) { 4446 if ((ifp == NULL) || (n->in_ifps[0] == ifp)) 4447 n->in_ifps[0] = fr_resolvenic(n->in_ifnames[0], 4); 4448 if ((ifp == NULL) || (n->in_ifps[1] == ifp)) 4449 n->in_ifps[1] = fr_resolvenic(n->in_ifnames[1], 4); 4450 } 4451 RWLOCK_EXIT(&ipf_nat); 4452 SPL_X(s); 4453 } 4454 4455 4456 /* ------------------------------------------------------------------------ */ 4457 /* Function: nat_icmpquerytype4 */ 4458 /* Returns: int - 1 == success, 0 == failure */ 4459 /* Parameters: icmptype(I) - ICMP type number */ 4460 /* */ 4461 /* Tests to see if the ICMP type number passed is a query/response type or */ 4462 /* not. */ 4463 /* ------------------------------------------------------------------------ */ 4464 static INLINE int nat_icmpquerytype4(icmptype) 4465 int icmptype; 4466 { 4467 4468 /* 4469 * For the ICMP query NAT code, it is essential that both the query 4470 * and the reply match on the NAT rule. Because the NAT structure 4471 * does not keep track of the icmptype, and a single NAT structure 4472 * is used for all icmp types with the same src, dest and id, we 4473 * simply define the replies as queries as well. The funny thing is, 4474 * altough it seems silly to call a reply a query, this is exactly 4475 * as it is defined in the IPv4 specification 4476 */ 4477 4478 switch (icmptype) 4479 { 4480 4481 case ICMP_ECHOREPLY: 4482 case ICMP_ECHO: 4483 /* route aedvertisement/solliciation is currently unsupported: */ 4484 /* it would require rewriting the ICMP data section */ 4485 case ICMP_TSTAMP: 4486 case ICMP_TSTAMPREPLY: 4487 case ICMP_IREQ: 4488 case ICMP_IREQREPLY: 4489 case ICMP_MASKREQ: 4490 case ICMP_MASKREPLY: 4491 return 1; 4492 default: 4493 return 0; 4494 } 4495 } 4496 4497 4498 /* ------------------------------------------------------------------------ */ 4499 /* Function: nat_log */ 4500 /* Returns: Nil */ 4501 /* Parameters: nat(I) - pointer to NAT structure */ 4502 /* type(I) - type of log entry to create */ 4503 /* */ 4504 /* Creates a NAT log entry. */ 4505 /* ------------------------------------------------------------------------ */ 4506 void nat_log(nat, type) 4507 struct nat *nat; 4508 u_int type; 4509 { 4510 #ifdef IPFILTER_LOG 4511 # ifndef LARGE_NAT 4512 struct ipnat *np; 4513 int rulen; 4514 # endif 4515 struct natlog natl; 4516 void *items[1]; 4517 size_t sizes[1]; 4518 int types[1]; 4519 4520 natl.nl_inip = nat->nat_inip; 4521 natl.nl_outip = nat->nat_outip; 4522 natl.nl_origip = nat->nat_oip; 4523 natl.nl_bytes[0] = nat->nat_bytes[0]; 4524 natl.nl_bytes[1] = nat->nat_bytes[1]; 4525 natl.nl_pkts[0] = nat->nat_pkts[0]; 4526 natl.nl_pkts[1] = nat->nat_pkts[1]; 4527 natl.nl_origport = nat->nat_oport; 4528 natl.nl_inport = nat->nat_inport; 4529 natl.nl_outport = nat->nat_outport; 4530 natl.nl_p = nat->nat_p; 4531 natl.nl_type = type; 4532 natl.nl_rule = -1; 4533 # ifndef LARGE_NAT 4534 if (nat->nat_ptr != NULL) { 4535 for (rulen = 0, np = nat_list; np; np = np->in_next, rulen++) 4536 if (np == nat->nat_ptr) { 4537 natl.nl_rule = rulen; 4538 break; 4539 } 4540 } 4541 # endif 4542 items[0] = &natl; 4543 sizes[0] = sizeof(natl); 4544 types[0] = 0; 4545 4546 (void) ipllog(IPL_LOGNAT, NULL, items, sizes, types, 1); 4547 #endif 4548 } 4549 4550 4551 #if defined(__OpenBSD__) 4552 /* ------------------------------------------------------------------------ */ 4553 /* Function: nat_ifdetach */ 4554 /* Returns: Nil */ 4555 /* Parameters: ifp(I) - pointer to network interface */ 4556 /* */ 4557 /* Compatibility interface for OpenBSD to trigger the correct updating of */ 4558 /* interface references within IPFilter. */ 4559 /* ------------------------------------------------------------------------ */ 4560 void nat_ifdetach(ifp) 4561 void *ifp; 4562 { 4563 frsync(ifp); 4564 return; 4565 } 4566 #endif 4567 4568 4569 /* ------------------------------------------------------------------------ */ 4570 /* Function: fr_natderef */ 4571 /* Returns: Nil */ 4572 /* Parameters: isp(I) - pointer to pointer to NAT table entry */ 4573 /* */ 4574 /* Decrement the reference counter for this NAT table entry and free it if */ 4575 /* there are no more things using it. */ 4576 /* ------------------------------------------------------------------------ */ 4577 void fr_natderef(natp) 4578 nat_t **natp; 4579 { 4580 nat_t *nat; 4581 4582 nat = *natp; 4583 *natp = NULL; 4584 WRITE_ENTER(&ipf_nat); 4585 nat->nat_ref--; 4586 if (nat->nat_ref == 0) 4587 nat_delete(nat, NL_EXPIRE); 4588 RWLOCK_EXIT(&ipf_nat); 4589 } 4590 4591 4592 /* ------------------------------------------------------------------------ */ 4593 /* Function: fr_natclone */ 4594 /* Returns: ipstate_t* - NULL == cloning failed, */ 4595 /* else pointer to new state structure */ 4596 /* Parameters: fin(I) - pointer to packet information */ 4597 /* is(I) - pointer to master state structure */ 4598 /* Write Lock: ipf_nat */ 4599 /* */ 4600 /* Create a "duplcate" state table entry from the master. */ 4601 /* ------------------------------------------------------------------------ */ 4602 static nat_t *fr_natclone(fin, nat) 4603 fr_info_t *fin; 4604 nat_t *nat; 4605 { 4606 frentry_t *fr; 4607 nat_t *clone; 4608 ipnat_t *np; 4609 4610 KMALLOC(clone, nat_t *); 4611 if (clone == NULL) 4612 return NULL; 4613 bcopy((char *)nat, (char *)clone, sizeof(*clone)); 4614 4615 MUTEX_NUKE(&clone->nat_lock); 4616 4617 clone->nat_aps = NULL; 4618 /* 4619 * Initialize all these so that nat_delete() doesn't cause a crash. 4620 */ 4621 clone->nat_tqe.tqe_pnext = NULL; 4622 clone->nat_tqe.tqe_next = NULL; 4623 clone->nat_tqe.tqe_ifq = NULL; 4624 clone->nat_tqe.tqe_parent = clone; 4625 4626 clone->nat_flags &= ~SI_CLONE; 4627 clone->nat_flags |= SI_CLONED; 4628 4629 if (clone->nat_hm) 4630 clone->nat_hm->hm_ref++; 4631 4632 if (nat_insert(clone, fin->fin_rev) == -1) { 4633 KFREE(clone); 4634 return NULL; 4635 } 4636 np = clone->nat_ptr; 4637 if (np != NULL) { 4638 if (nat_logging) 4639 nat_log(clone, (u_int)np->in_redir); 4640 np->in_use++; 4641 } 4642 fr = clone->nat_fr; 4643 if (fr != NULL) { 4644 MUTEX_ENTER(&fr->fr_lock); 4645 fr->fr_ref++; 4646 MUTEX_EXIT(&fr->fr_lock); 4647 } 4648 4649 /* 4650 * Because the clone is created outside the normal loop of things and 4651 * TCP has special needs in terms of state, initialise the timeout 4652 * state of the new NAT from here. 4653 */ 4654 if (clone->nat_p == IPPROTO_TCP) { 4655 (void) fr_tcp_age(&clone->nat_tqe, fin, nat_tqb, 4656 clone->nat_flags); 4657 } 4658 #ifdef IPFILTER_SYNC 4659 clone->nat_sync = ipfsync_new(SMC_NAT, fin, clone); 4660 #endif 4661 if (nat_logging) 4662 nat_log(clone, NL_CLONE); 4663 return clone; 4664 } 4665 4666 4667 /* ------------------------------------------------------------------------ */ 4668 /* Function: nat_wildok */ 4669 /* Returns: int - 1 == packet's ports match wildcards */ 4670 /* 0 == packet's ports don't match wildcards */ 4671 /* Parameters: nat(I) - NAT entry */ 4672 /* sport(I) - source port */ 4673 /* dport(I) - destination port */ 4674 /* flags(I) - wildcard flags */ 4675 /* dir(I) - packet direction */ 4676 /* */ 4677 /* Use NAT entry and packet direction to determine which combination of */ 4678 /* wildcard flags should be used. */ 4679 /* ------------------------------------------------------------------------ */ 4680 static INLINE int nat_wildok(nat, sport, dport, flags, dir) 4681 nat_t *nat; 4682 int sport; 4683 int dport; 4684 int flags; 4685 int dir; 4686 { 4687 /* 4688 * When called by dir is set to 4689 * nat_inlookup NAT_INBOUND (0) 4690 * nat_outlookup NAT_OUTBOUND (1) 4691 * 4692 * We simply combine the packet's direction in dir with the original 4693 * "intended" direction of that NAT entry in nat->nat_dir to decide 4694 * which combination of wildcard flags to allow. 4695 */ 4696 4697 switch ((dir << 1) | nat->nat_dir) 4698 { 4699 case 3: /* outbound packet / outbound entry */ 4700 if (((nat->nat_inport == sport) || 4701 (flags & SI_W_SPORT)) && 4702 ((nat->nat_oport == dport) || 4703 (flags & SI_W_DPORT))) 4704 return 1; 4705 break; 4706 case 2: /* outbound packet / inbound entry */ 4707 if (((nat->nat_outport == sport) || 4708 (flags & SI_W_DPORT)) && 4709 ((nat->nat_oport == dport) || 4710 (flags & SI_W_SPORT))) 4711 return 1; 4712 break; 4713 case 1: /* inbound packet / outbound entry */ 4714 if (((nat->nat_oport == sport) || 4715 (flags & SI_W_DPORT)) && 4716 ((nat->nat_outport == dport) || 4717 (flags & SI_W_SPORT))) 4718 return 1; 4719 break; 4720 case 0: /* inbound packet / inbound entry */ 4721 if (((nat->nat_oport == sport) || 4722 (flags & SI_W_SPORT)) && 4723 ((nat->nat_outport == dport) || 4724 (flags & SI_W_DPORT))) 4725 return 1; 4726 break; 4727 default: 4728 break; 4729 } 4730 4731 return(0); 4732 } 4733 4734 4735 /* ------------------------------------------------------------------------ */ 4736 /* Function: nat_mssclamp */ 4737 /* Returns: Nil */ 4738 /* Parameters: tcp(I) - pointer to TCP header */ 4739 /* maxmss(I) - value to clamp the TCP MSS to */ 4740 /* fin(I) - pointer to packet information */ 4741 /* csump(I) - pointer to TCP checksum */ 4742 /* */ 4743 /* Check for MSS option and clamp it if necessary. If found and changed, */ 4744 /* then the TCP header checksum will be updated to reflect the change in */ 4745 /* the MSS. */ 4746 /* ------------------------------------------------------------------------ */ 4747 static void nat_mssclamp(tcp, maxmss, fin, csump) 4748 tcphdr_t *tcp; 4749 u_32_t maxmss; 4750 fr_info_t *fin; 4751 u_short *csump; 4752 { 4753 u_char *cp, *ep, opt; 4754 int hlen, advance; 4755 u_32_t mss, sumd; 4756 4757 hlen = TCP_OFF(tcp) << 2; 4758 if (hlen > sizeof(*tcp)) { 4759 cp = (u_char *)tcp + sizeof(*tcp); 4760 ep = (u_char *)tcp + hlen; 4761 4762 while (cp < ep) { 4763 opt = cp[0]; 4764 if (opt == TCPOPT_EOL) 4765 break; 4766 else if (opt == TCPOPT_NOP) { 4767 cp++; 4768 continue; 4769 } 4770 4771 if (cp + 1 >= ep) 4772 break; 4773 advance = cp[1]; 4774 if ((cp + advance > ep) || (advance <= 0)) 4775 break; 4776 switch (opt) 4777 { 4778 case TCPOPT_MAXSEG: 4779 if (advance != 4) 4780 break; 4781 mss = cp[2] * 256 + cp[3]; 4782 if (mss > maxmss) { 4783 cp[2] = maxmss / 256; 4784 cp[3] = maxmss & 0xff; 4785 CALC_SUMD(mss, maxmss, sumd); 4786 fix_outcksum(fin, csump, sumd); 4787 } 4788 break; 4789 default: 4790 /* ignore unknown options */ 4791 break; 4792 } 4793 4794 cp += advance; 4795 } 4796 } 4797 } 4798 4799 4800 /* ------------------------------------------------------------------------ */ 4801 /* Function: fr_setnatqueue */ 4802 /* Returns: Nil */ 4803 /* Parameters: nat(I)- pointer to NAT structure */ 4804 /* rev(I) - forward(0) or reverse(1) direction */ 4805 /* Locks: ipf_nat (read or write) */ 4806 /* */ 4807 /* Put the NAT entry on its default queue entry, using rev as a helped in */ 4808 /* determining which queue it should be placed on. */ 4809 /* ------------------------------------------------------------------------ */ 4810 void fr_setnatqueue(nat, rev) 4811 nat_t *nat; 4812 int rev; 4813 { 4814 ipftq_t *oifq, *nifq; 4815 4816 if (nat->nat_ptr != NULL) 4817 nifq = nat->nat_ptr->in_tqehead[rev]; 4818 else 4819 nifq = NULL; 4820 4821 if (nifq == NULL) { 4822 switch (nat->nat_p) 4823 { 4824 case IPPROTO_UDP : 4825 nifq = &nat_udptq; 4826 break; 4827 case IPPROTO_ICMP : 4828 nifq = &nat_icmptq; 4829 break; 4830 case IPPROTO_TCP : 4831 nifq = nat_tqb + nat->nat_tqe.tqe_state[rev]; 4832 break; 4833 default : 4834 nifq = &nat_iptq; 4835 break; 4836 } 4837 } 4838 4839 oifq = nat->nat_tqe.tqe_ifq; 4840 /* 4841 * If it's currently on a timeout queue, move it from one queue to 4842 * another, else put it on the end of the newly determined queue. 4843 */ 4844 if (oifq != NULL) 4845 fr_movequeue(&nat->nat_tqe, oifq, nifq); 4846 else 4847 fr_queueappend(&nat->nat_tqe, nifq, nat); 4848 return; 4849 } 4850