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