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