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