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