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[0], 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 frentry_t *fr; 3212 ipf_stack_t *ifs = fin->fin_ifs; 3213 3214 fr = fin->fin_fr; 3215 3216 if ((fr != NULL) && !(fr->fr_flags & FR_DUP) && 3217 fr->fr_tif.fd_ifp && fr->fr_tif.fd_ifp != (void *)-1) 3218 ifp = fr->fr_tif.fd_ifp; 3219 else 3220 ifp = fin->fin_ifp; 3221 3222 srcip = src.s_addr; 3223 sflags = flags & IPN_TCPUDPICMP; 3224 sport = 0; 3225 dport = 0; 3226 3227 switch (p) 3228 { 3229 case IPPROTO_TCP : 3230 case IPPROTO_UDP : 3231 sport = htons(fin->fin_data[0]); 3232 dport = htons(fin->fin_data[1]); 3233 break; 3234 case IPPROTO_ICMP : 3235 if (flags & IPN_ICMPERR) 3236 sport = fin->fin_data[1]; 3237 else 3238 dport = fin->fin_data[1]; 3239 break; 3240 default : 3241 break; 3242 } 3243 3244 if ((flags & SI_WILDP) != 0) 3245 goto find_out_wild_ports; 3246 3247 hv = NAT_HASH_FN(srcip, sport, 0xffffffff); 3248 hv = NAT_HASH_FN(dst.s_addr, hv + dport, ifs->ifs_ipf_nattable_sz); 3249 nat = ifs->ifs_nat_table[0][hv]; 3250 for (; nat; nat = nat->nat_hnext[0]) { 3251 if (nat->nat_ifps[1] != NULL) { 3252 if ((ifp != NULL) && (ifp != nat->nat_ifps[1])) 3253 continue; 3254 } else if (ifp != NULL) 3255 nat->nat_ifps[1] = ifp; 3256 3257 nflags = nat->nat_flags; 3258 3259 if (nat->nat_inip.s_addr == srcip && 3260 nat->nat_oip.s_addr == dst.s_addr && 3261 (((p == 0) && (sflags == (nflags & NAT_TCPUDPICMP))) 3262 || (p == nat->nat_p))) { 3263 switch (p) 3264 { 3265 #if 0 3266 case IPPROTO_GRE : 3267 if (nat->nat_call[1] != fin->fin_data[0]) 3268 continue; 3269 break; 3270 #endif 3271 case IPPROTO_TCP : 3272 case IPPROTO_UDP : 3273 if (nat->nat_oport != dport) 3274 continue; 3275 if (nat->nat_inport != sport) 3276 continue; 3277 break; 3278 default : 3279 break; 3280 } 3281 3282 ipn = nat->nat_ptr; 3283 if ((ipn != NULL) && (nat->nat_aps != NULL)) 3284 if (appr_match(fin, nat) != 0) 3285 continue; 3286 return nat; 3287 } 3288 } 3289 3290 /* 3291 * So if we didn't find it but there are wildcard members in the hash 3292 * table, go back and look for them. We do this search and update here 3293 * because it is modifying the NAT table and we want to do this only 3294 * for the first packet that matches. The exception, of course, is 3295 * for "dummy" (FI_IGNORE) lookups. 3296 */ 3297 find_out_wild_ports: 3298 if (!(flags & NAT_TCPUDP) || !(flags & NAT_SEARCH)) 3299 return NULL; 3300 if (ifs->ifs_nat_stats.ns_wilds == 0) 3301 return NULL; 3302 3303 RWLOCK_EXIT(&ifs->ifs_ipf_nat); 3304 3305 hv = NAT_HASH_FN(srcip, 0, 0xffffffff); 3306 hv = NAT_HASH_FN(dst.s_addr, hv, ifs->ifs_ipf_nattable_sz); 3307 3308 WRITE_ENTER(&ifs->ifs_ipf_nat); 3309 3310 nat = ifs->ifs_nat_table[0][hv]; 3311 for (; nat; nat = nat->nat_hnext[0]) { 3312 if (nat->nat_ifps[1] != NULL) { 3313 if ((ifp != NULL) && (ifp != nat->nat_ifps[1])) 3314 continue; 3315 } else if (ifp != NULL) 3316 nat->nat_ifps[1] = ifp; 3317 3318 if (nat->nat_p != fin->fin_p) 3319 continue; 3320 if ((nat->nat_inip.s_addr != srcip) || 3321 (nat->nat_oip.s_addr != dst.s_addr)) 3322 continue; 3323 3324 nflags = nat->nat_flags; 3325 if (!(nflags & (NAT_TCPUDP|SI_WILDP))) 3326 continue; 3327 3328 if (nat_wildok(nat, (int)sport, (int)dport, nflags, 3329 NAT_OUTBOUND) == 1) { 3330 if ((fin->fin_flx & FI_IGNORE) != 0) 3331 break; 3332 if ((nflags & SI_CLONE) != 0) { 3333 nat = fr_natclone(fin, nat); 3334 if (nat == NULL) 3335 break; 3336 } else { 3337 MUTEX_ENTER(&ifs->ifs_ipf_nat_new); 3338 ifs->ifs_nat_stats.ns_wilds--; 3339 MUTEX_EXIT(&ifs->ifs_ipf_nat_new); 3340 } 3341 nat->nat_inport = sport; 3342 nat->nat_oport = dport; 3343 if (nat->nat_outport == 0) 3344 nat->nat_outport = sport; 3345 nat->nat_flags &= ~(SI_W_DPORT|SI_W_SPORT); 3346 nat_tabmove(nat, ifs); 3347 break; 3348 } 3349 } 3350 3351 MUTEX_DOWNGRADE(&ifs->ifs_ipf_nat); 3352 3353 return nat; 3354 } 3355 3356 3357 /* ------------------------------------------------------------------------ */ 3358 /* Function: nat_lookupredir */ 3359 /* Returns: nat_t* - NULL == no match, */ 3360 /* else pointer to matching NAT entry */ 3361 /* Parameters: np(I) - pointer to description of packet to find NAT table */ 3362 /* entry for. */ 3363 /* */ 3364 /* Lookup the NAT tables to search for a matching redirect */ 3365 /* ------------------------------------------------------------------------ */ 3366 nat_t *nat_lookupredir(np, ifs) 3367 natlookup_t *np; 3368 ipf_stack_t *ifs; 3369 { 3370 fr_info_t fi; 3371 nat_t *nat; 3372 3373 bzero((char *)&fi, sizeof(fi)); 3374 if (np->nl_flags & IPN_IN) { 3375 fi.fin_data[0] = ntohs(np->nl_realport); 3376 fi.fin_data[1] = ntohs(np->nl_outport); 3377 } else { 3378 fi.fin_data[0] = ntohs(np->nl_inport); 3379 fi.fin_data[1] = ntohs(np->nl_outport); 3380 } 3381 if (np->nl_flags & IPN_TCP) 3382 fi.fin_p = IPPROTO_TCP; 3383 else if (np->nl_flags & IPN_UDP) 3384 fi.fin_p = IPPROTO_UDP; 3385 else if (np->nl_flags & (IPN_ICMPERR|IPN_ICMPQUERY)) 3386 fi.fin_p = IPPROTO_ICMP; 3387 3388 fi.fin_ifs = ifs; 3389 /* 3390 * We can do two sorts of lookups: 3391 * - IPN_IN: we have the `real' and `out' address, look for `in'. 3392 * - default: we have the `in' and `out' address, look for `real'. 3393 */ 3394 if (np->nl_flags & IPN_IN) { 3395 if ((nat = nat_inlookup(&fi, np->nl_flags, fi.fin_p, 3396 np->nl_realip, np->nl_outip))) { 3397 np->nl_inip = nat->nat_inip; 3398 np->nl_inport = nat->nat_inport; 3399 } 3400 } else { 3401 /* 3402 * If nl_inip is non null, this is a lookup based on the real 3403 * ip address. Else, we use the fake. 3404 */ 3405 if ((nat = nat_outlookup(&fi, np->nl_flags, fi.fin_p, 3406 np->nl_inip, np->nl_outip))) { 3407 3408 if ((np->nl_flags & IPN_FINDFORWARD) != 0) { 3409 fr_info_t fin; 3410 bzero((char *)&fin, sizeof(fin)); 3411 fin.fin_p = nat->nat_p; 3412 fin.fin_data[0] = ntohs(nat->nat_outport); 3413 fin.fin_data[1] = ntohs(nat->nat_oport); 3414 fin.fin_ifs = ifs; 3415 if (nat_inlookup(&fin, np->nl_flags, fin.fin_p, 3416 nat->nat_outip, 3417 nat->nat_oip) != NULL) { 3418 np->nl_flags &= ~IPN_FINDFORWARD; 3419 } 3420 } 3421 3422 np->nl_realip = nat->nat_outip; 3423 np->nl_realport = nat->nat_outport; 3424 } 3425 } 3426 3427 return nat; 3428 } 3429 3430 3431 /* ------------------------------------------------------------------------ */ 3432 /* Function: nat_match */ 3433 /* Returns: int - 0 == no match, 1 == match */ 3434 /* Parameters: fin(I) - pointer to packet information */ 3435 /* np(I) - pointer to NAT rule */ 3436 /* */ 3437 /* Pull the matching of a packet against a NAT rule out of that complex */ 3438 /* loop inside fr_checknatin() and lay it out properly in its own function. */ 3439 /* ------------------------------------------------------------------------ */ 3440 static int nat_match(fin, np) 3441 fr_info_t *fin; 3442 ipnat_t *np; 3443 { 3444 frtuc_t *ft; 3445 3446 if (fin->fin_v != 4) 3447 return 0; 3448 3449 if (np->in_p && fin->fin_p != np->in_p) 3450 return 0; 3451 3452 if (fin->fin_out) { 3453 if (!(np->in_redir & (NAT_MAP|NAT_MAPBLK))) 3454 return 0; 3455 if (((fin->fin_fi.fi_saddr & np->in_inmsk) != np->in_inip) 3456 ^ ((np->in_flags & IPN_NOTSRC) != 0)) 3457 return 0; 3458 if (((fin->fin_fi.fi_daddr & np->in_srcmsk) != np->in_srcip) 3459 ^ ((np->in_flags & IPN_NOTDST) != 0)) 3460 return 0; 3461 } else { 3462 if (!(np->in_redir & NAT_REDIRECT)) 3463 return 0; 3464 if (((fin->fin_fi.fi_saddr & np->in_srcmsk) != np->in_srcip) 3465 ^ ((np->in_flags & IPN_NOTSRC) != 0)) 3466 return 0; 3467 if (((fin->fin_fi.fi_daddr & np->in_outmsk) != np->in_outip) 3468 ^ ((np->in_flags & IPN_NOTDST) != 0)) 3469 return 0; 3470 } 3471 3472 ft = &np->in_tuc; 3473 if (!(fin->fin_flx & FI_TCPUDP) || 3474 (fin->fin_flx & (FI_SHORT|FI_FRAGBODY))) { 3475 if (ft->ftu_scmp || ft->ftu_dcmp) 3476 return 0; 3477 return 1; 3478 } 3479 3480 return fr_tcpudpchk(fin, ft); 3481 } 3482 3483 3484 /* ------------------------------------------------------------------------ */ 3485 /* Function: nat_update */ 3486 /* Returns: Nil */ 3487 /* Parameters: nat(I) - pointer to NAT structure */ 3488 /* np(I) - pointer to NAT rule */ 3489 /* */ 3490 /* Updates the lifetime of a NAT table entry for non-TCP packets. Must be */ 3491 /* called with fin_rev updated - i.e. after calling nat_proto(). */ 3492 /* ------------------------------------------------------------------------ */ 3493 void nat_update(fin, nat, np) 3494 fr_info_t *fin; 3495 nat_t *nat; 3496 ipnat_t *np; 3497 { 3498 ipftq_t *ifq, *ifq2; 3499 ipftqent_t *tqe; 3500 ipf_stack_t *ifs = fin->fin_ifs; 3501 3502 MUTEX_ENTER(&nat->nat_lock); 3503 tqe = &nat->nat_tqe; 3504 ifq = tqe->tqe_ifq; 3505 3506 /* 3507 * We allow over-riding of NAT timeouts from NAT rules, even for 3508 * TCP, however, if it is TCP and there is no rule timeout set, 3509 * then do not update the timeout here. 3510 */ 3511 if (np != NULL) 3512 ifq2 = np->in_tqehead[fin->fin_rev]; 3513 else 3514 ifq2 = NULL; 3515 3516 if (nat->nat_p == IPPROTO_TCP && ifq2 == NULL) { 3517 (void) fr_tcp_age(&nat->nat_tqe, fin, ifs->ifs_nat_tqb, 0); 3518 } else { 3519 if (ifq2 == NULL) { 3520 if (nat->nat_p == IPPROTO_UDP) 3521 ifq2 = &ifs->ifs_nat_udptq; 3522 else if (nat->nat_p == IPPROTO_ICMP) 3523 ifq2 = &ifs->ifs_nat_icmptq; 3524 else 3525 ifq2 = &ifs->ifs_nat_iptq; 3526 } 3527 3528 fr_movequeue(tqe, ifq, ifq2, ifs); 3529 } 3530 MUTEX_EXIT(&nat->nat_lock); 3531 } 3532 3533 3534 /* ------------------------------------------------------------------------ */ 3535 /* Function: fr_checknatout */ 3536 /* Returns: int - -1 == packet failed NAT checks so block it, */ 3537 /* 0 == no packet translation occurred, */ 3538 /* 1 == packet was successfully translated. */ 3539 /* Parameters: fin(I) - pointer to packet information */ 3540 /* passp(I) - pointer to filtering result flags */ 3541 /* */ 3542 /* Check to see if an outcoming packet should be changed. ICMP packets are */ 3543 /* first checked to see if they match an existing entry (if an error), */ 3544 /* otherwise a search of the current NAT table is made. If neither results */ 3545 /* in a match then a search for a matching NAT rule is made. Create a new */ 3546 /* NAT entry if a we matched a NAT rule. Lastly, actually change the */ 3547 /* packet header(s) as required. */ 3548 /* ------------------------------------------------------------------------ */ 3549 int fr_checknatout(fin, passp) 3550 fr_info_t *fin; 3551 u_32_t *passp; 3552 { 3553 struct ifnet *ifp, *sifp; 3554 icmphdr_t *icmp = NULL; 3555 tcphdr_t *tcp = NULL; 3556 int rval, natfailed; 3557 ipnat_t *np = NULL; 3558 u_int nflags = 0; 3559 u_32_t ipa, iph; 3560 int natadd = 1; 3561 frentry_t *fr; 3562 nat_t *nat; 3563 ipf_stack_t *ifs = fin->fin_ifs; 3564 3565 if (ifs->ifs_nat_stats.ns_rules == 0 || ifs->ifs_fr_nat_lock != 0) 3566 return 0; 3567 3568 natfailed = 0; 3569 fr = fin->fin_fr; 3570 sifp = fin->fin_ifp; 3571 if ((fr != NULL) && !(fr->fr_flags & FR_DUP) && 3572 fr->fr_tif.fd_ifp && fr->fr_tif.fd_ifp != (void *)-1) 3573 fin->fin_ifp = fr->fr_tif.fd_ifp; 3574 ifp = fin->fin_ifp; 3575 3576 if (!(fin->fin_flx & FI_SHORT) && (fin->fin_off == 0)) { 3577 switch (fin->fin_p) 3578 { 3579 case IPPROTO_TCP : 3580 nflags = IPN_TCP; 3581 break; 3582 case IPPROTO_UDP : 3583 nflags = IPN_UDP; 3584 break; 3585 case IPPROTO_ICMP : 3586 icmp = fin->fin_dp; 3587 3588 /* 3589 * This is an incoming packet, so the destination is 3590 * the icmp_id and the source port equals 0 3591 */ 3592 if (nat_icmpquerytype4(icmp->icmp_type)) 3593 nflags = IPN_ICMPQUERY; 3594 break; 3595 default : 3596 break; 3597 } 3598 3599 if ((nflags & IPN_TCPUDP)) 3600 tcp = fin->fin_dp; 3601 } 3602 3603 ipa = fin->fin_saddr; 3604 3605 READ_ENTER(&ifs->ifs_ipf_nat); 3606 3607 if ((fin->fin_p == IPPROTO_ICMP) && !(nflags & IPN_ICMPQUERY) && 3608 (nat = nat_icmperror(fin, &nflags, NAT_OUTBOUND))) 3609 /*EMPTY*/; 3610 else if ((fin->fin_flx & FI_FRAG) && (nat = fr_nat_knownfrag(fin))) 3611 natadd = 0; 3612 else if ((nat = nat_outlookup(fin, nflags|NAT_SEARCH, (u_int)fin->fin_p, 3613 fin->fin_src, fin->fin_dst))) { 3614 nflags = nat->nat_flags; 3615 } else { 3616 u_32_t hv, msk, nmsk; 3617 3618 /* 3619 * If there is no current entry in the nat table for this IP#, 3620 * create one for it (if there is a matching rule). 3621 */ 3622 RWLOCK_EXIT(&ifs->ifs_ipf_nat); 3623 msk = 0xffffffff; 3624 nmsk = ifs->ifs_nat_masks; 3625 WRITE_ENTER(&ifs->ifs_ipf_nat); 3626 maskloop: 3627 iph = ipa & htonl(msk); 3628 hv = NAT_HASH_FN(iph, 0, ifs->ifs_ipf_natrules_sz); 3629 for (np = ifs->ifs_nat_rules[hv]; np; np = np->in_mnext) 3630 { 3631 if ((np->in_ifps[1] && (np->in_ifps[1] != ifp))) 3632 continue; 3633 if (np->in_v != fin->fin_v) 3634 continue; 3635 if (np->in_p && (np->in_p != fin->fin_p)) 3636 continue; 3637 if ((np->in_flags & IPN_RF) && !(np->in_flags & nflags)) 3638 continue; 3639 if (np->in_flags & IPN_FILTER) { 3640 if (!nat_match(fin, np)) 3641 continue; 3642 } else if ((ipa & np->in_inmsk) != np->in_inip) 3643 continue; 3644 3645 if ((fr != NULL) && 3646 !fr_matchtag(&np->in_tag, &fr->fr_nattag)) 3647 continue; 3648 3649 if (*np->in_plabel != '\0') { 3650 if (((np->in_flags & IPN_FILTER) == 0) && 3651 (np->in_dport != tcp->th_dport)) 3652 continue; 3653 if (appr_ok(fin, tcp, np) == 0) 3654 continue; 3655 } 3656 3657 if ((nat = nat_new(fin, np, NULL, nflags, 3658 NAT_OUTBOUND))) { 3659 np->in_hits++; 3660 break; 3661 } else 3662 natfailed = -1; 3663 } 3664 if ((np == NULL) && (nmsk != 0)) { 3665 while (nmsk) { 3666 msk <<= 1; 3667 if (nmsk & 0x80000000) 3668 break; 3669 nmsk <<= 1; 3670 } 3671 if (nmsk != 0) { 3672 nmsk <<= 1; 3673 goto maskloop; 3674 } 3675 } 3676 MUTEX_DOWNGRADE(&ifs->ifs_ipf_nat); 3677 } 3678 3679 if (nat != NULL) { 3680 rval = fr_natout(fin, nat, natadd, nflags); 3681 if (rval == 1) { 3682 MUTEX_ENTER(&nat->nat_lock); 3683 nat->nat_ref++; 3684 MUTEX_EXIT(&nat->nat_lock); 3685 fin->fin_nat = nat; 3686 } 3687 } else 3688 rval = natfailed; 3689 RWLOCK_EXIT(&ifs->ifs_ipf_nat); 3690 3691 if (rval == -1) { 3692 if (passp != NULL) 3693 *passp = FR_BLOCK; 3694 fin->fin_flx |= FI_BADNAT; 3695 } 3696 fin->fin_ifp = sifp; 3697 return rval; 3698 } 3699 3700 /* ------------------------------------------------------------------------ */ 3701 /* Function: fr_natout */ 3702 /* Returns: int - -1 == packet failed NAT checks so block it, */ 3703 /* 1 == packet was successfully translated. */ 3704 /* Parameters: fin(I) - pointer to packet information */ 3705 /* nat(I) - pointer to NAT structure */ 3706 /* natadd(I) - flag indicating if it is safe to add frag cache */ 3707 /* nflags(I) - NAT flags set for this packet */ 3708 /* */ 3709 /* Translate a packet coming "out" on an interface. */ 3710 /* ------------------------------------------------------------------------ */ 3711 int fr_natout(fin, nat, natadd, nflags) 3712 fr_info_t *fin; 3713 nat_t *nat; 3714 int natadd; 3715 u_32_t nflags; 3716 { 3717 icmphdr_t *icmp; 3718 u_short *csump; 3719 u_32_t sumd; 3720 tcphdr_t *tcp; 3721 ipnat_t *np; 3722 int i; 3723 ipf_stack_t *ifs = fin->fin_ifs; 3724 3725 #if SOLARIS && defined(_KERNEL) 3726 net_data_t net_data_p; 3727 if (fin->fin_v == 4) 3728 net_data_p = ifs->ifs_ipf_ipv4; 3729 else 3730 net_data_p = ifs->ifs_ipf_ipv6; 3731 #endif 3732 3733 tcp = NULL; 3734 icmp = NULL; 3735 csump = NULL; 3736 np = nat->nat_ptr; 3737 3738 if ((natadd != 0) && (fin->fin_flx & FI_FRAG) && (np != NULL)) 3739 (void) fr_nat_newfrag(fin, 0, nat); 3740 3741 MUTEX_ENTER(&nat->nat_lock); 3742 nat->nat_bytes[1] += fin->fin_plen; 3743 nat->nat_pkts[1]++; 3744 MUTEX_EXIT(&nat->nat_lock); 3745 3746 /* 3747 * Fix up checksums, not by recalculating them, but 3748 * simply computing adjustments. 3749 * This is only done for STREAMS based IP implementations where the 3750 * checksum has already been calculated by IP. In all other cases, 3751 * IPFilter is called before the checksum needs calculating so there 3752 * is no call to modify whatever is in the header now. 3753 */ 3754 ASSERT(fin->fin_m != NULL); 3755 if (fin->fin_v == 4 && !NET_IS_HCK_L3_FULL(net_data_p, fin->fin_m)) { 3756 if (nflags == IPN_ICMPERR) { 3757 u_32_t s1, s2; 3758 3759 s1 = LONG_SUM(ntohl(fin->fin_saddr)); 3760 s2 = LONG_SUM(ntohl(nat->nat_outip.s_addr)); 3761 CALC_SUMD(s1, s2, sumd); 3762 3763 fix_outcksum(&fin->fin_ip->ip_sum, sumd); 3764 } 3765 #if !defined(_KERNEL) || defined(MENTAT) || defined(__sgi) || \ 3766 defined(linux) || defined(BRIDGE_IPF) 3767 else { 3768 /* 3769 * Strictly speaking, this isn't necessary on BSD 3770 * kernels because they do checksum calculation after 3771 * this code has run BUT if ipfilter is being used 3772 * to do NAT as a bridge, that code doesn't exist. 3773 */ 3774 if (nat->nat_dir == NAT_OUTBOUND) 3775 fix_outcksum(&fin->fin_ip->ip_sum, 3776 nat->nat_ipsumd); 3777 else 3778 fix_incksum(&fin->fin_ip->ip_sum, 3779 nat->nat_ipsumd); 3780 } 3781 #endif 3782 } 3783 3784 if (!(fin->fin_flx & FI_SHORT) && (fin->fin_off == 0)) { 3785 if ((nat->nat_outport != 0) && (nflags & IPN_TCPUDP)) { 3786 tcp = fin->fin_dp; 3787 3788 tcp->th_sport = nat->nat_outport; 3789 fin->fin_data[0] = ntohs(nat->nat_outport); 3790 } 3791 3792 if ((nat->nat_outport != 0) && (nflags & IPN_ICMPQUERY)) { 3793 icmp = fin->fin_dp; 3794 icmp->icmp_id = nat->nat_outport; 3795 } 3796 3797 csump = nat_proto(fin, nat, nflags); 3798 } 3799 3800 fin->fin_ip->ip_src = nat->nat_outip; 3801 3802 nat_update(fin, nat, np); 3803 3804 /* 3805 * The above comments do not hold for layer 4 (or higher) checksums... 3806 */ 3807 if (csump != NULL && !NET_IS_HCK_L4_FULL(net_data_p, fin->fin_m)) { 3808 if (nflags & IPN_TCPUDP && 3809 NET_IS_HCK_L4_PART(net_data_p, fin->fin_m)) 3810 sumd = nat->nat_sumd[1]; 3811 else 3812 sumd = nat->nat_sumd[0]; 3813 3814 if (nat->nat_dir == NAT_OUTBOUND) 3815 fix_outcksum(csump, sumd); 3816 else 3817 fix_incksum(csump, sumd); 3818 } 3819 #ifdef IPFILTER_SYNC 3820 ipfsync_update(SMC_NAT, fin, nat->nat_sync); 3821 #endif 3822 /* ------------------------------------------------------------- */ 3823 /* A few quick notes: */ 3824 /* Following are test conditions prior to calling the */ 3825 /* appr_check routine. */ 3826 /* */ 3827 /* A NULL tcp indicates a non TCP/UDP packet. When dealing */ 3828 /* with a redirect rule, we attempt to match the packet's */ 3829 /* source port against in_dport, otherwise we'd compare the */ 3830 /* packet's destination. */ 3831 /* ------------------------------------------------------------- */ 3832 if ((np != NULL) && (np->in_apr != NULL)) { 3833 i = appr_check(fin, nat); 3834 if (i == 0) 3835 i = 1; 3836 } else 3837 i = 1; 3838 ATOMIC_INCL(ifs->ifs_nat_stats.ns_mapped[1]); 3839 fin->fin_flx |= FI_NATED; 3840 return i; 3841 } 3842 3843 3844 /* ------------------------------------------------------------------------ */ 3845 /* Function: fr_checknatin */ 3846 /* Returns: int - -1 == packet failed NAT checks so block it, */ 3847 /* 0 == no packet translation occurred, */ 3848 /* 1 == packet was successfully translated. */ 3849 /* Parameters: fin(I) - pointer to packet information */ 3850 /* passp(I) - pointer to filtering result flags */ 3851 /* */ 3852 /* Check to see if an incoming packet should be changed. ICMP packets are */ 3853 /* first checked to see if they match an existing entry (if an error), */ 3854 /* otherwise a search of the current NAT table is made. If neither results */ 3855 /* in a match then a search for a matching NAT rule is made. Create a new */ 3856 /* NAT entry if a we matched a NAT rule. Lastly, actually change the */ 3857 /* packet header(s) as required. */ 3858 /* ------------------------------------------------------------------------ */ 3859 int fr_checknatin(fin, passp) 3860 fr_info_t *fin; 3861 u_32_t *passp; 3862 { 3863 u_int nflags, natadd; 3864 int rval, natfailed; 3865 struct ifnet *ifp; 3866 struct in_addr in; 3867 icmphdr_t *icmp; 3868 tcphdr_t *tcp; 3869 u_short dport; 3870 ipnat_t *np; 3871 nat_t *nat; 3872 u_32_t iph; 3873 ipf_stack_t *ifs = fin->fin_ifs; 3874 3875 if (ifs->ifs_nat_stats.ns_rules == 0 || ifs->ifs_fr_nat_lock != 0) 3876 return 0; 3877 3878 tcp = NULL; 3879 icmp = NULL; 3880 dport = 0; 3881 natadd = 1; 3882 nflags = 0; 3883 natfailed = 0; 3884 ifp = fin->fin_ifp; 3885 3886 if (!(fin->fin_flx & FI_SHORT) && (fin->fin_off == 0)) { 3887 switch (fin->fin_p) 3888 { 3889 case IPPROTO_TCP : 3890 nflags = IPN_TCP; 3891 break; 3892 case IPPROTO_UDP : 3893 nflags = IPN_UDP; 3894 break; 3895 case IPPROTO_ICMP : 3896 icmp = fin->fin_dp; 3897 3898 /* 3899 * This is an incoming packet, so the destination is 3900 * the icmp_id and the source port equals 0 3901 */ 3902 if (nat_icmpquerytype4(icmp->icmp_type)) { 3903 nflags = IPN_ICMPQUERY; 3904 dport = icmp->icmp_id; 3905 } break; 3906 default : 3907 break; 3908 } 3909 3910 if ((nflags & IPN_TCPUDP)) { 3911 tcp = fin->fin_dp; 3912 dport = tcp->th_dport; 3913 } 3914 } 3915 3916 in = fin->fin_dst; 3917 3918 READ_ENTER(&ifs->ifs_ipf_nat); 3919 3920 if ((fin->fin_p == IPPROTO_ICMP) && !(nflags & IPN_ICMPQUERY) && 3921 (nat = nat_icmperror(fin, &nflags, NAT_INBOUND))) 3922 /*EMPTY*/; 3923 else if ((fin->fin_flx & FI_FRAG) && (nat = fr_nat_knownfrag(fin))) 3924 natadd = 0; 3925 else if ((nat = nat_inlookup(fin, nflags|NAT_SEARCH, (u_int)fin->fin_p, 3926 fin->fin_src, in))) { 3927 nflags = nat->nat_flags; 3928 } else { 3929 u_32_t hv, msk, rmsk; 3930 3931 RWLOCK_EXIT(&ifs->ifs_ipf_nat); 3932 rmsk = ifs->ifs_rdr_masks; 3933 msk = 0xffffffff; 3934 WRITE_ENTER(&ifs->ifs_ipf_nat); 3935 /* 3936 * If there is no current entry in the nat table for this IP#, 3937 * create one for it (if there is a matching rule). 3938 */ 3939 maskloop: 3940 iph = in.s_addr & htonl(msk); 3941 hv = NAT_HASH_FN(iph, 0, ifs->ifs_ipf_rdrrules_sz); 3942 for (np = ifs->ifs_rdr_rules[hv]; np; np = np->in_rnext) { 3943 if (np->in_ifps[0] && (np->in_ifps[0] != ifp)) 3944 continue; 3945 if (np->in_v != fin->fin_v) 3946 continue; 3947 if (np->in_p && (np->in_p != fin->fin_p)) 3948 continue; 3949 if ((np->in_flags & IPN_RF) && !(np->in_flags & nflags)) 3950 continue; 3951 if (np->in_flags & IPN_FILTER) { 3952 if (!nat_match(fin, np)) 3953 continue; 3954 } else { 3955 if ((in.s_addr & np->in_outmsk) != np->in_outip) 3956 continue; 3957 if (np->in_pmin && 3958 ((ntohs(np->in_pmax) < ntohs(dport)) || 3959 (ntohs(dport) < ntohs(np->in_pmin)))) 3960 continue; 3961 } 3962 3963 if (*np->in_plabel != '\0') { 3964 if (!appr_ok(fin, tcp, np)) { 3965 continue; 3966 } 3967 } 3968 3969 nat = nat_new(fin, np, NULL, nflags, NAT_INBOUND); 3970 if (nat != NULL) { 3971 np->in_hits++; 3972 break; 3973 } else 3974 natfailed = -1; 3975 } 3976 3977 if ((np == NULL) && (rmsk != 0)) { 3978 while (rmsk) { 3979 msk <<= 1; 3980 if (rmsk & 0x80000000) 3981 break; 3982 rmsk <<= 1; 3983 } 3984 if (rmsk != 0) { 3985 rmsk <<= 1; 3986 goto maskloop; 3987 } 3988 } 3989 MUTEX_DOWNGRADE(&ifs->ifs_ipf_nat); 3990 } 3991 if (nat != NULL) { 3992 rval = fr_natin(fin, nat, natadd, nflags); 3993 if (rval == 1) { 3994 MUTEX_ENTER(&nat->nat_lock); 3995 nat->nat_ref++; 3996 MUTEX_EXIT(&nat->nat_lock); 3997 fin->fin_nat = nat; 3998 fin->fin_state = nat->nat_state; 3999 } 4000 } else 4001 rval = natfailed; 4002 RWLOCK_EXIT(&ifs->ifs_ipf_nat); 4003 4004 if (rval == -1) { 4005 if (passp != NULL) 4006 *passp = FR_BLOCK; 4007 fin->fin_flx |= FI_BADNAT; 4008 } 4009 return rval; 4010 } 4011 4012 4013 /* ------------------------------------------------------------------------ */ 4014 /* Function: fr_natin */ 4015 /* Returns: int - -1 == packet failed NAT checks so block it, */ 4016 /* 1 == packet was successfully translated. */ 4017 /* Parameters: fin(I) - pointer to packet information */ 4018 /* nat(I) - pointer to NAT structure */ 4019 /* natadd(I) - flag indicating if it is safe to add frag cache */ 4020 /* nflags(I) - NAT flags set for this packet */ 4021 /* Locks Held: ipf_nat (READ) */ 4022 /* */ 4023 /* Translate a packet coming "in" on an interface. */ 4024 /* ------------------------------------------------------------------------ */ 4025 int fr_natin(fin, nat, natadd, nflags) 4026 fr_info_t *fin; 4027 nat_t *nat; 4028 int natadd; 4029 u_32_t nflags; 4030 { 4031 icmphdr_t *icmp; 4032 u_short *csump, *csump1; 4033 u_32_t sumd; 4034 tcphdr_t *tcp; 4035 ipnat_t *np; 4036 int i; 4037 ipf_stack_t *ifs = fin->fin_ifs; 4038 4039 #if SOLARIS && defined(_KERNEL) 4040 net_data_t net_data_p; 4041 if (fin->fin_v == 4) 4042 net_data_p = ifs->ifs_ipf_ipv4; 4043 else 4044 net_data_p = ifs->ifs_ipf_ipv6; 4045 #endif 4046 4047 tcp = NULL; 4048 csump = NULL; 4049 np = nat->nat_ptr; 4050 fin->fin_fr = nat->nat_fr; 4051 4052 if (np != NULL) { 4053 if ((natadd != 0) && (fin->fin_flx & FI_FRAG)) 4054 (void) fr_nat_newfrag(fin, 0, nat); 4055 4056 /* ------------------------------------------------------------- */ 4057 /* A few quick notes: */ 4058 /* Following are test conditions prior to calling the */ 4059 /* appr_check routine. */ 4060 /* */ 4061 /* A NULL tcp indicates a non TCP/UDP packet. When dealing */ 4062 /* with a map rule, we attempt to match the packet's */ 4063 /* source port against in_dport, otherwise we'd compare the */ 4064 /* packet's destination. */ 4065 /* ------------------------------------------------------------- */ 4066 if (np->in_apr != NULL) { 4067 i = appr_check(fin, nat); 4068 if (i == -1) { 4069 return -1; 4070 } 4071 } 4072 } 4073 4074 #ifdef IPFILTER_SYNC 4075 ipfsync_update(SMC_NAT, fin, nat->nat_sync); 4076 #endif 4077 4078 MUTEX_ENTER(&nat->nat_lock); 4079 nat->nat_bytes[0] += fin->fin_plen; 4080 nat->nat_pkts[0]++; 4081 MUTEX_EXIT(&nat->nat_lock); 4082 4083 fin->fin_ip->ip_dst = nat->nat_inip; 4084 fin->fin_fi.fi_daddr = nat->nat_inip.s_addr; 4085 if (nflags & IPN_TCPUDP) 4086 tcp = fin->fin_dp; 4087 4088 /* 4089 * Fix up checksums, not by recalculating them, but 4090 * simply computing adjustments. 4091 * Why only do this for some platforms on inbound packets ? 4092 * Because for those that it is done, IP processing is yet to happen 4093 * and so the IPv4 header checksum has not yet been evaluated. 4094 * Perhaps it should always be done for the benefit of things like 4095 * fast forwarding (so that it doesn't need to be recomputed) but with 4096 * header checksum offloading, perhaps it is a moot point. 4097 */ 4098 #if !defined(_KERNEL) || defined(MENTAT) || defined(__sgi) || \ 4099 defined(__osf__) || defined(linux) 4100 if (nat->nat_dir == NAT_OUTBOUND) 4101 fix_incksum(&fin->fin_ip->ip_sum, nat->nat_ipsumd); 4102 else 4103 fix_outcksum(&fin->fin_ip->ip_sum, nat->nat_ipsumd); 4104 #endif 4105 4106 if (!(fin->fin_flx & FI_SHORT) && (fin->fin_off == 0)) { 4107 if ((nat->nat_inport != 0) && (nflags & IPN_TCPUDP)) { 4108 tcp->th_dport = nat->nat_inport; 4109 fin->fin_data[1] = ntohs(nat->nat_inport); 4110 } 4111 4112 4113 if ((nat->nat_inport != 0) && (nflags & IPN_ICMPQUERY)) { 4114 icmp = fin->fin_dp; 4115 4116 icmp->icmp_id = nat->nat_inport; 4117 } 4118 4119 csump = nat_proto(fin, nat, nflags); 4120 } 4121 4122 nat_update(fin, nat, np); 4123 4124 #if SOLARIS && defined(_KERNEL) 4125 if (nflags & IPN_TCPUDP && 4126 NET_IS_HCK_L4_PART(net_data_p, fin->fin_m)) { 4127 sumd = nat->nat_sumd[1]; 4128 csump1 = &(fin->fin_m->b_datap->db_struioun.cksum.cksum_val.u16); 4129 if (csump1 != NULL) { 4130 if (nat->nat_dir == NAT_OUTBOUND) 4131 fix_incksum(csump1, sumd); 4132 else 4133 fix_outcksum(csump1, sumd); 4134 } 4135 } else 4136 #endif 4137 sumd = nat->nat_sumd[0]; 4138 4139 /* 4140 * Inbound packets always need to have their address adjusted in case 4141 * code following this validates it. 4142 */ 4143 if (csump != NULL) { 4144 if (nat->nat_dir == NAT_OUTBOUND) 4145 fix_incksum(csump, sumd); 4146 else 4147 fix_outcksum(csump, sumd); 4148 } 4149 ATOMIC_INCL(ifs->ifs_nat_stats.ns_mapped[0]); 4150 fin->fin_flx |= FI_NATED; 4151 if (np != NULL && np->in_tag.ipt_num[0] != 0) 4152 fin->fin_nattag = &np->in_tag; 4153 return 1; 4154 } 4155 4156 4157 /* ------------------------------------------------------------------------ */ 4158 /* Function: nat_proto */ 4159 /* Returns: u_short* - pointer to transport header checksum to update, */ 4160 /* NULL if the transport protocol is not recognised */ 4161 /* as needing a checksum update. */ 4162 /* Parameters: fin(I) - pointer to packet information */ 4163 /* nat(I) - pointer to NAT structure */ 4164 /* nflags(I) - NAT flags set for this packet */ 4165 /* */ 4166 /* Return the pointer to the checksum field for each protocol so understood.*/ 4167 /* If support for making other changes to a protocol header is required, */ 4168 /* that is not strictly 'address' translation, such as clamping the MSS in */ 4169 /* TCP down to a specific value, then do it from here. */ 4170 /* ------------------------------------------------------------------------ */ 4171 u_short *nat_proto(fin, nat, nflags) 4172 fr_info_t *fin; 4173 nat_t *nat; 4174 u_int nflags; 4175 { 4176 icmphdr_t *icmp; 4177 u_short *csump; 4178 tcphdr_t *tcp; 4179 udphdr_t *udp; 4180 4181 csump = NULL; 4182 if (fin->fin_out == 0) { 4183 fin->fin_rev = (nat->nat_dir == NAT_OUTBOUND); 4184 } else { 4185 fin->fin_rev = (nat->nat_dir == NAT_INBOUND); 4186 } 4187 4188 switch (fin->fin_p) 4189 { 4190 case IPPROTO_TCP : 4191 tcp = fin->fin_dp; 4192 4193 csump = &tcp->th_sum; 4194 4195 /* 4196 * Do a MSS CLAMPING on a SYN packet, 4197 * only deal IPv4 for now. 4198 */ 4199 if ((nat->nat_mssclamp != 0) && (tcp->th_flags & TH_SYN) != 0) 4200 nat_mssclamp(tcp, nat->nat_mssclamp, csump); 4201 4202 break; 4203 4204 case IPPROTO_UDP : 4205 udp = fin->fin_dp; 4206 4207 if (udp->uh_sum) 4208 csump = &udp->uh_sum; 4209 break; 4210 4211 case IPPROTO_ICMP : 4212 icmp = fin->fin_dp; 4213 4214 if ((nflags & IPN_ICMPQUERY) != 0) { 4215 if (icmp->icmp_cksum != 0) 4216 csump = &icmp->icmp_cksum; 4217 } 4218 break; 4219 } 4220 return csump; 4221 } 4222 4223 4224 /* ------------------------------------------------------------------------ */ 4225 /* Function: fr_natunload */ 4226 /* Returns: Nil */ 4227 /* Parameters: Nil */ 4228 /* */ 4229 /* Free all memory used by NAT structures allocated at runtime. */ 4230 /* ------------------------------------------------------------------------ */ 4231 void fr_natunload(ifs) 4232 ipf_stack_t *ifs; 4233 { 4234 ipftq_t *ifq, *ifqnext; 4235 4236 (void) nat_clearlist(ifs); 4237 (void) nat_flushtable(ifs); 4238 4239 /* 4240 * Proxy timeout queues are not cleaned here because although they 4241 * exist on the NAT list, appr_unload is called after fr_natunload 4242 * and the proxies actually are responsible for them being created. 4243 * Should the proxy timeouts have their own list? There's no real 4244 * justification as this is the only complication. 4245 */ 4246 for (ifq = ifs->ifs_nat_utqe; ifq != NULL; ifq = ifqnext) { 4247 ifqnext = ifq->ifq_next; 4248 if (((ifq->ifq_flags & IFQF_PROXY) == 0) && 4249 (fr_deletetimeoutqueue(ifq) == 0)) 4250 fr_freetimeoutqueue(ifq, ifs); 4251 } 4252 4253 if (ifs->ifs_nat_table[0] != NULL) { 4254 KFREES(ifs->ifs_nat_table[0], 4255 sizeof(nat_t *) * ifs->ifs_ipf_nattable_sz); 4256 ifs->ifs_nat_table[0] = NULL; 4257 } 4258 if (ifs->ifs_nat_table[1] != NULL) { 4259 KFREES(ifs->ifs_nat_table[1], 4260 sizeof(nat_t *) * ifs->ifs_ipf_nattable_sz); 4261 ifs->ifs_nat_table[1] = NULL; 4262 } 4263 if (ifs->ifs_nat_rules != NULL) { 4264 KFREES(ifs->ifs_nat_rules, 4265 sizeof(ipnat_t *) * ifs->ifs_ipf_natrules_sz); 4266 ifs->ifs_nat_rules = NULL; 4267 } 4268 if (ifs->ifs_rdr_rules != NULL) { 4269 KFREES(ifs->ifs_rdr_rules, 4270 sizeof(ipnat_t *) * ifs->ifs_ipf_rdrrules_sz); 4271 ifs->ifs_rdr_rules = NULL; 4272 } 4273 if (ifs->ifs_maptable != NULL) { 4274 KFREES(ifs->ifs_maptable, 4275 sizeof(hostmap_t *) * ifs->ifs_ipf_hostmap_sz); 4276 ifs->ifs_maptable = NULL; 4277 } 4278 if (ifs->ifs_nat_stats.ns_bucketlen[0] != NULL) { 4279 KFREES(ifs->ifs_nat_stats.ns_bucketlen[0], 4280 sizeof(u_long *) * ifs->ifs_ipf_nattable_sz); 4281 ifs->ifs_nat_stats.ns_bucketlen[0] = NULL; 4282 } 4283 if (ifs->ifs_nat_stats.ns_bucketlen[1] != NULL) { 4284 KFREES(ifs->ifs_nat_stats.ns_bucketlen[1], 4285 sizeof(u_long *) * ifs->ifs_ipf_nattable_sz); 4286 ifs->ifs_nat_stats.ns_bucketlen[1] = NULL; 4287 } 4288 4289 if (ifs->ifs_fr_nat_maxbucket_reset == 1) 4290 ifs->ifs_fr_nat_maxbucket = 0; 4291 4292 if (ifs->ifs_fr_nat_init == 1) { 4293 ifs->ifs_fr_nat_init = 0; 4294 fr_sttab_destroy(ifs->ifs_nat_tqb); 4295 4296 RW_DESTROY(&ifs->ifs_ipf_natfrag); 4297 RW_DESTROY(&ifs->ifs_ipf_nat); 4298 4299 MUTEX_DESTROY(&ifs->ifs_ipf_nat_new); 4300 MUTEX_DESTROY(&ifs->ifs_ipf_natio); 4301 4302 MUTEX_DESTROY(&ifs->ifs_nat_udptq.ifq_lock); 4303 MUTEX_DESTROY(&ifs->ifs_nat_icmptq.ifq_lock); 4304 MUTEX_DESTROY(&ifs->ifs_nat_iptq.ifq_lock); 4305 } 4306 } 4307 4308 4309 /* ------------------------------------------------------------------------ */ 4310 /* Function: fr_natexpire */ 4311 /* Returns: Nil */ 4312 /* Parameters: Nil */ 4313 /* */ 4314 /* Check all of the timeout queues for entries at the top which need to be */ 4315 /* expired. */ 4316 /* ------------------------------------------------------------------------ */ 4317 void fr_natexpire(ifs) 4318 ipf_stack_t *ifs; 4319 { 4320 ipftq_t *ifq, *ifqnext; 4321 ipftqent_t *tqe, *tqn; 4322 int i; 4323 SPL_INT(s); 4324 4325 SPL_NET(s); 4326 WRITE_ENTER(&ifs->ifs_ipf_nat); 4327 for (ifq = ifs->ifs_nat_tqb, i = 0; ifq != NULL; ifq = ifq->ifq_next) { 4328 for (tqn = ifq->ifq_head; ((tqe = tqn) != NULL); i++) { 4329 if (tqe->tqe_die > ifs->ifs_fr_ticks) 4330 break; 4331 tqn = tqe->tqe_next; 4332 nat_delete(tqe->tqe_parent, NL_EXPIRE, ifs); 4333 } 4334 } 4335 4336 for (ifq = ifs->ifs_nat_utqe; ifq != NULL; ifq = ifqnext) { 4337 ifqnext = ifq->ifq_next; 4338 4339 for (tqn = ifq->ifq_head; ((tqe = tqn) != NULL); i++) { 4340 if (tqe->tqe_die > ifs->ifs_fr_ticks) 4341 break; 4342 tqn = tqe->tqe_next; 4343 nat_delete(tqe->tqe_parent, NL_EXPIRE, ifs); 4344 } 4345 } 4346 4347 for (ifq = ifs->ifs_nat_utqe; ifq != NULL; ifq = ifqnext) { 4348 ifqnext = ifq->ifq_next; 4349 4350 if (((ifq->ifq_flags & IFQF_DELETE) != 0) && 4351 (ifq->ifq_ref == 0)) { 4352 fr_freetimeoutqueue(ifq, ifs); 4353 } 4354 } 4355 4356 RWLOCK_EXIT(&ifs->ifs_ipf_nat); 4357 SPL_X(s); 4358 } 4359 4360 4361 /* ------------------------------------------------------------------------ */ 4362 /* Function: fr_nataddrsync */ 4363 /* Returns: Nil */ 4364 /* Parameters: ifp(I) - pointer to network interface */ 4365 /* addr(I) - pointer to new network address */ 4366 /* */ 4367 /* Walk through all of the currently active NAT sessions, looking for those */ 4368 /* which need to have their translated address updated (where the interface */ 4369 /* matches the one passed in) and change it, recalculating the checksum sum */ 4370 /* difference too. */ 4371 /* ------------------------------------------------------------------------ */ 4372 void fr_nataddrsync(ifp, addr, ifs) 4373 void *ifp; 4374 struct in_addr *addr; 4375 ipf_stack_t *ifs; 4376 { 4377 u_32_t sum1, sum2, sumd; 4378 nat_t *nat; 4379 ipnat_t *np; 4380 SPL_INT(s); 4381 4382 if (ifs->ifs_fr_running <= 0) 4383 return; 4384 4385 SPL_NET(s); 4386 WRITE_ENTER(&ifs->ifs_ipf_nat); 4387 4388 if (ifs->ifs_fr_running <= 0) { 4389 RWLOCK_EXIT(&ifs->ifs_ipf_nat); 4390 return; 4391 } 4392 4393 /* 4394 * Change IP addresses for NAT sessions for any protocol except TCP 4395 * since it will break the TCP connection anyway. The only rules 4396 * which will get changed are those which are "map ... -> 0/32", 4397 * where the rule specifies the address is taken from the interface. 4398 */ 4399 for (nat = ifs->ifs_nat_instances; nat; nat = nat->nat_next) { 4400 if (addr != NULL) { 4401 if (((ifp != NULL) && ifp != (nat->nat_ifps[0])) || 4402 ((nat->nat_flags & IPN_TCP) != 0)) 4403 continue; 4404 if (((np = nat->nat_ptr) == NULL) || 4405 (np->in_nip || (np->in_outmsk != 0xffffffff))) 4406 continue; 4407 4408 /* 4409 * Change the map-to address to be the same as the 4410 * new one. 4411 */ 4412 sum1 = nat->nat_outip.s_addr; 4413 nat->nat_outip = *addr; 4414 sum2 = nat->nat_outip.s_addr; 4415 4416 } else if (((ifp == NULL) || (ifp == nat->nat_ifps[0])) && 4417 !(nat->nat_flags & IPN_TCP) && (np = nat->nat_ptr) && 4418 (np->in_outmsk == 0xffffffff) && !np->in_nip) { 4419 struct in_addr in; 4420 4421 /* 4422 * Change the map-to address to be the same as the 4423 * new one. 4424 */ 4425 sum1 = nat->nat_outip.s_addr; 4426 if (fr_ifpaddr(4, FRI_NORMAL, nat->nat_ifps[0], 4427 &in, NULL, ifs) != -1) 4428 nat->nat_outip = in; 4429 sum2 = nat->nat_outip.s_addr; 4430 } else { 4431 continue; 4432 } 4433 4434 if (sum1 == sum2) 4435 continue; 4436 /* 4437 * Readjust the checksum adjustment to take into 4438 * account the new IP#. 4439 */ 4440 CALC_SUMD(sum1, sum2, sumd); 4441 /* XXX - dont change for TCP when solaris does 4442 * hardware checksumming. 4443 */ 4444 sumd += nat->nat_sumd[0]; 4445 nat->nat_sumd[0] = (sumd & 0xffff) + (sumd >> 16); 4446 nat->nat_sumd[1] = nat->nat_sumd[0]; 4447 } 4448 4449 RWLOCK_EXIT(&ifs->ifs_ipf_nat); 4450 SPL_X(s); 4451 } 4452 4453 4454 /* ------------------------------------------------------------------------ */ 4455 /* Function: fr_natifpsync */ 4456 /* Returns: Nil */ 4457 /* Parameters: action(I) - how we are syncing */ 4458 /* ifp(I) - pointer to network interface */ 4459 /* name(I) - name of interface to sync to */ 4460 /* */ 4461 /* This function is used to resync the mapping of interface names and their */ 4462 /* respective 'pointers'. For "action == IPFSYNC_RESYNC", resync all */ 4463 /* interfaces by doing a new lookup of name to 'pointer'. For "action == */ 4464 /* IPFSYNC_NEWIFP", treat ifp as the new pointer value associated with */ 4465 /* "name" and for "action == IPFSYNC_OLDIFP", ifp is a pointer for which */ 4466 /* there is no longer any interface associated with it. */ 4467 /* ------------------------------------------------------------------------ */ 4468 void fr_natifpsync(action, ifp, name, ifs) 4469 int action; 4470 void *ifp; 4471 char *name; 4472 ipf_stack_t *ifs; 4473 { 4474 #if defined(_KERNEL) && !defined(MENTAT) && defined(USE_SPL) 4475 int s; 4476 #endif 4477 nat_t *nat; 4478 ipnat_t *n; 4479 4480 if (ifs->ifs_fr_running <= 0) 4481 return; 4482 4483 SPL_NET(s); 4484 WRITE_ENTER(&ifs->ifs_ipf_nat); 4485 4486 if (ifs->ifs_fr_running <= 0) { 4487 RWLOCK_EXIT(&ifs->ifs_ipf_nat); 4488 return; 4489 } 4490 4491 switch (action) 4492 { 4493 case IPFSYNC_RESYNC : 4494 for (nat = ifs->ifs_nat_instances; nat; nat = nat->nat_next) { 4495 if ((ifp == nat->nat_ifps[0]) || 4496 (nat->nat_ifps[0] == (void *)-1)) { 4497 nat->nat_ifps[0] = 4498 fr_resolvenic(nat->nat_ifnames[0], 4, ifs); 4499 } 4500 4501 if ((ifp == nat->nat_ifps[1]) || 4502 (nat->nat_ifps[1] == (void *)-1)) { 4503 nat->nat_ifps[1] = 4504 fr_resolvenic(nat->nat_ifnames[1], 4, ifs); 4505 } 4506 } 4507 4508 for (n = ifs->ifs_nat_list; (n != NULL); n = n->in_next) { 4509 if (n->in_ifps[0] == ifp || 4510 n->in_ifps[0] == (void *)-1) { 4511 n->in_ifps[0] = 4512 fr_resolvenic(n->in_ifnames[0], 4, ifs); 4513 } 4514 if (n->in_ifps[1] == ifp || 4515 n->in_ifps[1] == (void *)-1) { 4516 n->in_ifps[1] = 4517 fr_resolvenic(n->in_ifnames[1], 4, ifs); 4518 } 4519 } 4520 break; 4521 case IPFSYNC_NEWIFP : 4522 for (nat = ifs->ifs_nat_instances; nat; nat = nat->nat_next) { 4523 if (!strncmp(name, nat->nat_ifnames[0], 4524 sizeof(nat->nat_ifnames[0]))) 4525 nat->nat_ifps[0] = ifp; 4526 if (!strncmp(name, nat->nat_ifnames[1], 4527 sizeof(nat->nat_ifnames[1]))) 4528 nat->nat_ifps[1] = ifp; 4529 } 4530 for (n = ifs->ifs_nat_list; (n != NULL); n = n->in_next) { 4531 if (!strncmp(name, n->in_ifnames[0], 4532 sizeof(n->in_ifnames[0]))) 4533 n->in_ifps[0] = ifp; 4534 if (!strncmp(name, n->in_ifnames[1], 4535 sizeof(n->in_ifnames[1]))) 4536 n->in_ifps[1] = ifp; 4537 } 4538 break; 4539 case IPFSYNC_OLDIFP : 4540 for (nat = ifs->ifs_nat_instances; nat; nat = nat->nat_next) { 4541 if (ifp == nat->nat_ifps[0]) 4542 nat->nat_ifps[0] = (void *)-1; 4543 if (ifp == nat->nat_ifps[1]) 4544 nat->nat_ifps[1] = (void *)-1; 4545 } 4546 for (n = ifs->ifs_nat_list; (n != NULL); n = n->in_next) { 4547 if (n->in_ifps[0] == ifp) 4548 n->in_ifps[0] = (void *)-1; 4549 if (n->in_ifps[1] == ifp) 4550 n->in_ifps[1] = (void *)-1; 4551 } 4552 break; 4553 } 4554 RWLOCK_EXIT(&ifs->ifs_ipf_nat); 4555 SPL_X(s); 4556 } 4557 4558 4559 /* ------------------------------------------------------------------------ */ 4560 /* Function: nat_icmpquerytype4 */ 4561 /* Returns: int - 1 == success, 0 == failure */ 4562 /* Parameters: icmptype(I) - ICMP type number */ 4563 /* */ 4564 /* Tests to see if the ICMP type number passed is a query/response type or */ 4565 /* not. */ 4566 /* ------------------------------------------------------------------------ */ 4567 static INLINE int nat_icmpquerytype4(icmptype) 4568 int icmptype; 4569 { 4570 4571 /* 4572 * For the ICMP query NAT code, it is essential that both the query 4573 * and the reply match on the NAT rule. Because the NAT structure 4574 * does not keep track of the icmptype, and a single NAT structure 4575 * is used for all icmp types with the same src, dest and id, we 4576 * simply define the replies as queries as well. The funny thing is, 4577 * altough it seems silly to call a reply a query, this is exactly 4578 * as it is defined in the IPv4 specification 4579 */ 4580 4581 switch (icmptype) 4582 { 4583 4584 case ICMP_ECHOREPLY: 4585 case ICMP_ECHO: 4586 /* route aedvertisement/solliciation is currently unsupported: */ 4587 /* it would require rewriting the ICMP data section */ 4588 case ICMP_TSTAMP: 4589 case ICMP_TSTAMPREPLY: 4590 case ICMP_IREQ: 4591 case ICMP_IREQREPLY: 4592 case ICMP_MASKREQ: 4593 case ICMP_MASKREPLY: 4594 return 1; 4595 default: 4596 return 0; 4597 } 4598 } 4599 4600 4601 /* ------------------------------------------------------------------------ */ 4602 /* Function: nat_log */ 4603 /* Returns: Nil */ 4604 /* Parameters: nat(I) - pointer to NAT structure */ 4605 /* type(I) - type of log entry to create */ 4606 /* */ 4607 /* Creates a NAT log entry. */ 4608 /* ------------------------------------------------------------------------ */ 4609 void nat_log(nat, type, ifs) 4610 struct nat *nat; 4611 u_int type; 4612 ipf_stack_t *ifs; 4613 { 4614 #ifdef IPFILTER_LOG 4615 # ifndef LARGE_NAT 4616 struct ipnat *np; 4617 int rulen; 4618 # endif 4619 struct natlog natl; 4620 void *items[1]; 4621 size_t sizes[1]; 4622 int types[1]; 4623 4624 natl.nl_inip = nat->nat_inip; 4625 natl.nl_outip = nat->nat_outip; 4626 natl.nl_origip = nat->nat_oip; 4627 natl.nl_bytes[0] = nat->nat_bytes[0]; 4628 natl.nl_bytes[1] = nat->nat_bytes[1]; 4629 natl.nl_pkts[0] = nat->nat_pkts[0]; 4630 natl.nl_pkts[1] = nat->nat_pkts[1]; 4631 natl.nl_origport = nat->nat_oport; 4632 natl.nl_inport = nat->nat_inport; 4633 natl.nl_outport = nat->nat_outport; 4634 natl.nl_p = nat->nat_p; 4635 natl.nl_type = type; 4636 natl.nl_rule = -1; 4637 # ifndef LARGE_NAT 4638 if (nat->nat_ptr != NULL) { 4639 for (rulen = 0, np = ifs->ifs_nat_list; np; 4640 np = np->in_next, rulen++) 4641 if (np == nat->nat_ptr) { 4642 natl.nl_rule = rulen; 4643 break; 4644 } 4645 } 4646 # endif 4647 items[0] = &natl; 4648 sizes[0] = sizeof(natl); 4649 types[0] = 0; 4650 4651 (void) ipllog(IPL_LOGNAT, NULL, items, sizes, types, 1, ifs); 4652 #endif 4653 } 4654 4655 4656 #if defined(__OpenBSD__) 4657 /* ------------------------------------------------------------------------ */ 4658 /* Function: nat_ifdetach */ 4659 /* Returns: Nil */ 4660 /* Parameters: ifp(I) - pointer to network interface */ 4661 /* */ 4662 /* Compatibility interface for OpenBSD to trigger the correct updating of */ 4663 /* interface references within IPFilter. */ 4664 /* ------------------------------------------------------------------------ */ 4665 void nat_ifdetach(ifp, ifs) 4666 void *ifp; 4667 ipf_stack_t *ifs; 4668 { 4669 frsync(ifp, ifs); 4670 return; 4671 } 4672 #endif 4673 4674 4675 /* ------------------------------------------------------------------------ */ 4676 /* Function: fr_ipnatderef */ 4677 /* Returns: Nil */ 4678 /* Parameters: isp(I) - pointer to pointer to NAT rule */ 4679 /* Write Locks: ipf_nat */ 4680 /* */ 4681 /* ------------------------------------------------------------------------ */ 4682 void fr_ipnatderef(inp, ifs) 4683 ipnat_t **inp; 4684 ipf_stack_t *ifs; 4685 { 4686 ipnat_t *in; 4687 4688 in = *inp; 4689 *inp = NULL; 4690 in->in_space++; 4691 in->in_use--; 4692 if (in->in_use == 0 && (in->in_flags & IPN_DELETE)) { 4693 if (in->in_apr) 4694 appr_free(in->in_apr); 4695 KFREE(in); 4696 ifs->ifs_nat_stats.ns_rules--; 4697 #ifdef notdef 4698 #if SOLARIS 4699 if (ifs->ifs_nat_stats.ns_rules == 0) 4700 ifs->ifs_pfil_delayed_copy = 1; 4701 #endif 4702 #endif 4703 } 4704 } 4705 4706 4707 /* ------------------------------------------------------------------------ */ 4708 /* Function: fr_natderef */ 4709 /* Returns: Nil */ 4710 /* Parameters: isp(I) - pointer to pointer to NAT table entry */ 4711 /* */ 4712 /* Decrement the reference counter for this NAT table entry and free it if */ 4713 /* there are no more things using it. */ 4714 /* ------------------------------------------------------------------------ */ 4715 void fr_natderef(natp, ifs) 4716 nat_t **natp; 4717 ipf_stack_t *ifs; 4718 { 4719 nat_t *nat; 4720 4721 nat = *natp; 4722 *natp = NULL; 4723 WRITE_ENTER(&ifs->ifs_ipf_nat); 4724 nat->nat_ref--; 4725 if (nat->nat_ref == 0) 4726 nat_delete(nat, NL_EXPIRE, ifs); 4727 RWLOCK_EXIT(&ifs->ifs_ipf_nat); 4728 } 4729 4730 4731 /* ------------------------------------------------------------------------ */ 4732 /* Function: fr_natclone */ 4733 /* Returns: ipstate_t* - NULL == cloning failed, */ 4734 /* else pointer to new state structure */ 4735 /* Parameters: fin(I) - pointer to packet information */ 4736 /* is(I) - pointer to master state structure */ 4737 /* Write Lock: ipf_nat */ 4738 /* */ 4739 /* Create a "duplcate" state table entry from the master. */ 4740 /* ------------------------------------------------------------------------ */ 4741 static nat_t *fr_natclone(fin, nat) 4742 fr_info_t *fin; 4743 nat_t *nat; 4744 { 4745 frentry_t *fr; 4746 nat_t *clone; 4747 ipnat_t *np; 4748 ipf_stack_t *ifs = fin->fin_ifs; 4749 4750 KMALLOC(clone, nat_t *); 4751 if (clone == NULL) 4752 return NULL; 4753 bcopy((char *)nat, (char *)clone, sizeof(*clone)); 4754 4755 MUTEX_NUKE(&clone->nat_lock); 4756 4757 clone->nat_aps = NULL; 4758 /* 4759 * Initialize all these so that nat_delete() doesn't cause a crash. 4760 */ 4761 clone->nat_tqe.tqe_pnext = NULL; 4762 clone->nat_tqe.tqe_next = NULL; 4763 clone->nat_tqe.tqe_ifq = NULL; 4764 clone->nat_tqe.tqe_parent = clone; 4765 4766 clone->nat_flags &= ~SI_CLONE; 4767 clone->nat_flags |= SI_CLONED; 4768 4769 if (clone->nat_hm) 4770 clone->nat_hm->hm_ref++; 4771 4772 if (nat_insert(clone, fin->fin_rev, ifs) == -1) { 4773 KFREE(clone); 4774 return NULL; 4775 } 4776 np = clone->nat_ptr; 4777 if (np != NULL) { 4778 if (ifs->ifs_nat_logging) 4779 nat_log(clone, (u_int)np->in_redir, ifs); 4780 np->in_use++; 4781 } 4782 fr = clone->nat_fr; 4783 if (fr != NULL) { 4784 MUTEX_ENTER(&fr->fr_lock); 4785 fr->fr_ref++; 4786 MUTEX_EXIT(&fr->fr_lock); 4787 } 4788 4789 /* 4790 * Because the clone is created outside the normal loop of things and 4791 * TCP has special needs in terms of state, initialise the timeout 4792 * state of the new NAT from here. 4793 */ 4794 if (clone->nat_p == IPPROTO_TCP) { 4795 (void) fr_tcp_age(&clone->nat_tqe, fin, ifs->ifs_nat_tqb, 4796 clone->nat_flags); 4797 } 4798 #ifdef IPFILTER_SYNC 4799 clone->nat_sync = ipfsync_new(SMC_NAT, fin, clone); 4800 #endif 4801 if (ifs->ifs_nat_logging) 4802 nat_log(clone, NL_CLONE, ifs); 4803 return clone; 4804 } 4805 4806 4807 /* ------------------------------------------------------------------------ */ 4808 /* Function: nat_wildok */ 4809 /* Returns: int - 1 == packet's ports match wildcards */ 4810 /* 0 == packet's ports don't match wildcards */ 4811 /* Parameters: nat(I) - NAT entry */ 4812 /* sport(I) - source port */ 4813 /* dport(I) - destination port */ 4814 /* flags(I) - wildcard flags */ 4815 /* dir(I) - packet direction */ 4816 /* */ 4817 /* Use NAT entry and packet direction to determine which combination of */ 4818 /* wildcard flags should be used. */ 4819 /* ------------------------------------------------------------------------ */ 4820 static INLINE int nat_wildok(nat, sport, dport, flags, dir) 4821 nat_t *nat; 4822 int sport; 4823 int dport; 4824 int flags; 4825 int dir; 4826 { 4827 /* 4828 * When called by dir is set to 4829 * nat_inlookup NAT_INBOUND (0) 4830 * nat_outlookup NAT_OUTBOUND (1) 4831 * 4832 * We simply combine the packet's direction in dir with the original 4833 * "intended" direction of that NAT entry in nat->nat_dir to decide 4834 * which combination of wildcard flags to allow. 4835 */ 4836 4837 switch ((dir << 1) | nat->nat_dir) 4838 { 4839 case 3: /* outbound packet / outbound entry */ 4840 if (((nat->nat_inport == sport) || 4841 (flags & SI_W_SPORT)) && 4842 ((nat->nat_oport == dport) || 4843 (flags & SI_W_DPORT))) 4844 return 1; 4845 break; 4846 case 2: /* outbound packet / inbound entry */ 4847 if (((nat->nat_outport == sport) || 4848 (flags & SI_W_DPORT)) && 4849 ((nat->nat_oport == dport) || 4850 (flags & SI_W_SPORT))) 4851 return 1; 4852 break; 4853 case 1: /* inbound packet / outbound entry */ 4854 if (((nat->nat_oport == sport) || 4855 (flags & SI_W_DPORT)) && 4856 ((nat->nat_outport == dport) || 4857 (flags & SI_W_SPORT))) 4858 return 1; 4859 break; 4860 case 0: /* inbound packet / inbound entry */ 4861 if (((nat->nat_oport == sport) || 4862 (flags & SI_W_SPORT)) && 4863 ((nat->nat_outport == dport) || 4864 (flags & SI_W_DPORT))) 4865 return 1; 4866 break; 4867 default: 4868 break; 4869 } 4870 4871 return(0); 4872 } 4873 4874 4875 /* ------------------------------------------------------------------------ */ 4876 /* Function: nat_mssclamp */ 4877 /* Returns: Nil */ 4878 /* Parameters: tcp(I) - pointer to TCP header */ 4879 /* maxmss(I) - value to clamp the TCP MSS to */ 4880 /* csump(I) - pointer to TCP checksum */ 4881 /* */ 4882 /* Check for MSS option and clamp it if necessary. If found and changed, */ 4883 /* then the TCP header checksum will be updated to reflect the change in */ 4884 /* the MSS. */ 4885 /* ------------------------------------------------------------------------ */ 4886 static void nat_mssclamp(tcp, maxmss, csump) 4887 tcphdr_t *tcp; 4888 u_32_t maxmss; 4889 u_short *csump; 4890 { 4891 u_char *cp, *ep, opt; 4892 int hlen, advance; 4893 u_32_t mss, sumd; 4894 4895 hlen = TCP_OFF(tcp) << 2; 4896 if (hlen > sizeof(*tcp)) { 4897 cp = (u_char *)tcp + sizeof(*tcp); 4898 ep = (u_char *)tcp + hlen; 4899 4900 while (cp < ep) { 4901 opt = cp[0]; 4902 if (opt == TCPOPT_EOL) 4903 break; 4904 else if (opt == TCPOPT_NOP) { 4905 cp++; 4906 continue; 4907 } 4908 4909 if (cp + 1 >= ep) 4910 break; 4911 advance = cp[1]; 4912 if ((cp + advance > ep) || (advance <= 0)) 4913 break; 4914 switch (opt) 4915 { 4916 case TCPOPT_MAXSEG: 4917 if (advance != 4) 4918 break; 4919 mss = cp[2] * 256 + cp[3]; 4920 if (mss > maxmss) { 4921 cp[2] = maxmss / 256; 4922 cp[3] = maxmss & 0xff; 4923 CALC_SUMD(mss, maxmss, sumd); 4924 fix_outcksum(csump, sumd); 4925 } 4926 break; 4927 default: 4928 /* ignore unknown options */ 4929 break; 4930 } 4931 4932 cp += advance; 4933 } 4934 } 4935 } 4936 4937 4938 /* ------------------------------------------------------------------------ */ 4939 /* Function: fr_setnatqueue */ 4940 /* Returns: Nil */ 4941 /* Parameters: nat(I)- pointer to NAT structure */ 4942 /* rev(I) - forward(0) or reverse(1) direction */ 4943 /* Locks: ipf_nat (read or write) */ 4944 /* */ 4945 /* Put the NAT entry on its default queue entry, using rev as a helped in */ 4946 /* determining which queue it should be placed on. */ 4947 /* ------------------------------------------------------------------------ */ 4948 void fr_setnatqueue(nat, rev, ifs) 4949 nat_t *nat; 4950 int rev; 4951 ipf_stack_t *ifs; 4952 { 4953 ipftq_t *oifq, *nifq; 4954 4955 if (nat->nat_ptr != NULL) 4956 nifq = nat->nat_ptr->in_tqehead[rev]; 4957 else 4958 nifq = NULL; 4959 4960 if (nifq == NULL) { 4961 switch (nat->nat_p) 4962 { 4963 case IPPROTO_UDP : 4964 nifq = &ifs->ifs_nat_udptq; 4965 break; 4966 case IPPROTO_ICMP : 4967 nifq = &ifs->ifs_nat_icmptq; 4968 break; 4969 case IPPROTO_TCP : 4970 nifq = ifs->ifs_nat_tqb + nat->nat_tqe.tqe_state[rev]; 4971 break; 4972 default : 4973 nifq = &ifs->ifs_nat_iptq; 4974 break; 4975 } 4976 } 4977 4978 oifq = nat->nat_tqe.tqe_ifq; 4979 /* 4980 * If it's currently on a timeout queue, move it from one queue to 4981 * another, else put it on the end of the newly determined queue. 4982 */ 4983 if (oifq != NULL) 4984 fr_movequeue(&nat->nat_tqe, oifq, nifq, ifs); 4985 else 4986 fr_queueappend(&nat->nat_tqe, nifq, nat, ifs); 4987 return; 4988 } 4989 4990 /* Function: nat_getnext */ 4991 /* Returns: int - 0 == ok, else error */ 4992 /* Parameters: t(I) - pointer to ipftoken structure */ 4993 /* itp(I) - pointer to ipfgeniter_t structure */ 4994 /* */ 4995 /* Fetch the next nat/ipnat structure pointer from the linked list and */ 4996 /* copy it out to the storage space pointed to by itp_data. The next item */ 4997 /* in the list to look at is put back in the ipftoken struture. */ 4998 /* If we call ipf_freetoken, the accompanying pointer is set to NULL because*/ 4999 /* ipf_freetoken will call a deref function for us and we dont want to call */ 5000 /* that twice (second time would be in the second switch statement below. */ 5001 /* ------------------------------------------------------------------------ */ 5002 static int nat_getnext(t, itp, ifs) 5003 ipftoken_t *t; 5004 ipfgeniter_t *itp; 5005 ipf_stack_t *ifs; 5006 { 5007 hostmap_t *hm, *nexthm = NULL, zerohm; 5008 ipnat_t *ipn, *nextipnat = NULL, zeroipn; 5009 nat_t *nat, *nextnat = NULL, zeronat; 5010 int error = 0; 5011 5012 READ_ENTER(&ifs->ifs_ipf_nat); 5013 switch (itp->igi_type) 5014 { 5015 case IPFGENITER_HOSTMAP : 5016 hm = t->ipt_data; 5017 if (hm == NULL) { 5018 nexthm = ifs->ifs_ipf_hm_maplist; 5019 } else { 5020 nexthm = hm->hm_hnext; 5021 } 5022 if (nexthm != NULL) { 5023 if (nexthm->hm_hnext == NULL) { 5024 t->ipt_alive = 0; 5025 /* ipf_freetoken(t, ifs); 5026 hm = NULL; */ 5027 } else { 5028 /*MUTEX_ENTER(&nexthm->hm_lock);*/ 5029 nexthm->hm_ref++; 5030 /*MUTEX_EXIT(&nextipnat->hm_lock);*/ 5031 } 5032 5033 } else { 5034 bzero(&zerohm, sizeof(zerohm)); 5035 nexthm = &zerohm; 5036 } 5037 break; 5038 5039 case IPFGENITER_IPNAT : 5040 ipn = t->ipt_data; 5041 if (ipn == NULL) { 5042 nextipnat = ifs->ifs_nat_list; 5043 } else { 5044 nextipnat = ipn->in_next; 5045 } 5046 if (nextipnat != NULL) { 5047 if (nextipnat->in_next == NULL) { 5048 t->ipt_alive = 0; 5049 /*ipf_freetoken(t, ifs); 5050 ipn = NULL;*/ 5051 } else { 5052 /* MUTEX_ENTER(&nextipnat->in_lock); */ 5053 nextipnat->in_use++; 5054 /* MUTEX_EXIT(&nextipnat->in_lock); */ 5055 } 5056 } else { 5057 bzero(&zeroipn, sizeof(zeroipn)); 5058 nextipnat = &zeroipn; 5059 } 5060 break; 5061 5062 case IPFGENITER_NAT : 5063 nat = t->ipt_data; 5064 if (nat == NULL) { 5065 nextnat = ifs->ifs_nat_instances; 5066 } else { 5067 nextnat = nat->nat_next; 5068 } 5069 if (nextnat != NULL) { 5070 if (nextnat->nat_next == NULL) { 5071 t->ipt_alive = 0; 5072 /*ipf_freetoken(t, ifs); 5073 nat = NULL;*/ 5074 } else { 5075 MUTEX_ENTER(&nextnat->nat_lock); 5076 nextnat->nat_ref++; 5077 MUTEX_EXIT(&nextnat->nat_lock); 5078 } 5079 } else { 5080 bzero(&zeronat, sizeof(zeronat)); 5081 nextnat = &zeronat; 5082 } 5083 break; 5084 } 5085 5086 RWLOCK_EXIT(&ifs->ifs_ipf_nat); 5087 5088 switch (itp->igi_type) 5089 { 5090 case IPFGENITER_HOSTMAP : 5091 if (hm != NULL) { 5092 WRITE_ENTER(&ifs->ifs_ipf_nat); 5093 fr_hostmapderef(&hm); 5094 RWLOCK_EXIT(&ifs->ifs_ipf_nat); 5095 } 5096 t->ipt_data = nexthm; 5097 error = COPYOUT(nexthm, itp->igi_data, sizeof(*nexthm)); 5098 if (error != 0) 5099 error = EFAULT; 5100 break; 5101 5102 case IPFGENITER_IPNAT : 5103 if (ipn != NULL) 5104 fr_ipnatderef(&ipn, ifs); 5105 t->ipt_data = nextipnat; 5106 error = COPYOUT(nextipnat, itp->igi_data, sizeof(*nextipnat)); 5107 if (error != 0) 5108 error = EFAULT; 5109 break; 5110 5111 case IPFGENITER_NAT : 5112 if (nat != NULL) 5113 fr_natderef(&nat, ifs); 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