|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. ! 3: * ! 4: * @APPLE_LICENSE_HEADER_START@ ! 5: * ! 6: * The contents of this file constitute Original Code as defined in and ! 7: * are subject to the Apple Public Source License Version 1.1 (the ! 8: * "License"). You may not use this file except in compliance with the ! 9: * License. Please obtain a copy of the License at ! 10: * http://www.apple.com/publicsource and read it before using this file. ! 11: * ! 12: * This Original Code and all software distributed under the License are ! 13: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER ! 14: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, ! 15: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, ! 16: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the ! 17: * License for the specific language governing rights and limitations ! 18: * under the License. ! 19: * ! 20: * @APPLE_LICENSE_HEADER_END@ ! 21: */ ! 22: /* ! 23: * Copyright (C) 1993-1997 by Darren Reed. ! 24: * ! 25: * Redistribution and use in source and binary forms are permitted ! 26: * provided that this notice is preserved and due credit is given ! 27: * to the original author and the contributors. ! 28: */ ! 29: #if !defined(lint) ! 30: /* static const char sccsid[] = "@(#)ip_frag.c 1.11 3/24/96 (C) 1993-1995 Darren Reed"; */ ! 31: #endif ! 32: ! 33: ! 34: #if !defined(KERNEL) ! 35: # include <string.h> ! 36: # include <stdlib.h> ! 37: #endif ! 38: #include <sys/errno.h> ! 39: #include <sys/types.h> ! 40: #include <sys/param.h> ! 41: #include <sys/time.h> ! 42: #include <sys/file.h> ! 43: #if defined(KERNEL) ! 44: #include <sys/filio.h> ! 45: #include <sys/fcntl.h> ! 46: #include <sys/malloc.h> ! 47: #else ! 48: #include <sys/ioctl.h> ! 49: #endif ! 50: #include <sys/uio.h> ! 51: #ifndef linux ! 52: #include <sys/protosw.h> ! 53: #endif ! 54: #include <sys/socket.h> ! 55: #if defined(KERNEL) ! 56: # include <sys/systm.h> ! 57: #endif ! 58: #if !defined(__SVR4) && !defined(__svr4__) ! 59: # ifndef linux ! 60: # include <sys/mbuf.h> ! 61: # endif ! 62: #else ! 63: # include <sys/byteorder.h> ! 64: # include <sys/dditypes.h> ! 65: # include <sys/stream.h> ! 66: # include <sys/kmem.h> ! 67: #endif ! 68: #if defined(KERNEL) ! 69: #include <sys/malloc.h> ! 70: #endif ! 71: ! 72: #include <net/if.h> ! 73: #ifdef sun ! 74: #include <net/af.h> ! 75: #endif ! 76: #include <net/route.h> ! 77: #include <netinet/in.h> ! 78: #include <netinet/in_systm.h> ! 79: #include <netinet/ip.h> ! 80: #ifndef linux ! 81: #include <netinet/ip_var.h> ! 82: #endif ! 83: #include <netinet/tcp.h> ! 84: #include <netinet/udp.h> ! 85: #include <netinet/ip_icmp.h> ! 86: #include "netinet/ip_compat.h" ! 87: #include <netinet/tcpip.h> ! 88: #include "netinet/ip_fil.h" ! 89: #include "netinet/ip_proxy.h" ! 90: #include "netinet/ip_nat.h" ! 91: #include "netinet/ip_frag.h" ! 92: #include "netinet/ip_state.h" ! 93: #include "netinet/ip_auth.h" ! 94: ! 95: static ipfr_t *ipfr_heads[IPFT_SIZE]; ! 96: static ipfr_t *ipfr_nattab[IPFT_SIZE]; ! 97: static ipfrstat_t ipfr_stats; ! 98: static int ipfr_inuse = 0; ! 99: int fr_ipfrttl = 120; /* 60 seconds */ ! 100: #ifdef KERNEL ! 101: extern int ipfr_timer_id; ! 102: #endif ! 103: #if (SOLARIS || defined(__sgi)) && defined(KERNEL) ! 104: extern kmutex_t ipf_frag; ! 105: extern kmutex_t ipf_natfrag; ! 106: extern kmutex_t ipf_nat; ! 107: #endif ! 108: ! 109: ! 110: static ipfr_t *ipfr_new __P((ip_t *, fr_info_t *, int, ipfr_t **)); ! 111: static ipfr_t *ipfr_lookup __P((ip_t *, fr_info_t *, ipfr_t **)); ! 112: ! 113: ! 114: ipfrstat_t *ipfr_fragstats() ! 115: { ! 116: ipfr_stats.ifs_table = ipfr_heads; ! 117: ipfr_stats.ifs_nattab = ipfr_nattab; ! 118: ipfr_stats.ifs_inuse = ipfr_inuse; ! 119: return &ipfr_stats; ! 120: } ! 121: ! 122: ! 123: /* ! 124: * add a new entry to the fragment cache, registering it as having come ! 125: * through this box, with the result of the filter operation. ! 126: */ ! 127: static ipfr_t *ipfr_new(ip, fin, pass, table) ! 128: ip_t *ip; ! 129: fr_info_t *fin; ! 130: int pass; ! 131: ipfr_t *table[]; ! 132: { ! 133: ipfr_t **fp, *fr, frag; ! 134: u_int idx; ! 135: ! 136: frag.ipfr_p = ip->ip_p; ! 137: idx = ip->ip_p; ! 138: frag.ipfr_id = ip->ip_id; ! 139: idx += ip->ip_id; ! 140: frag.ipfr_tos = ip->ip_tos; ! 141: frag.ipfr_src.s_addr = ip->ip_src.s_addr; ! 142: idx += ip->ip_src.s_addr; ! 143: frag.ipfr_dst.s_addr = ip->ip_dst.s_addr; ! 144: idx += ip->ip_dst.s_addr; ! 145: idx *= 127; ! 146: idx %= IPFT_SIZE; ! 147: ! 148: /* ! 149: * first, make sure it isn't already there... ! 150: */ ! 151: for (fp = &table[idx]; (fr = *fp); fp = &fr->ipfr_next) ! 152: if (!bcmp((char *)&frag.ipfr_src, (char *)&fr->ipfr_src, ! 153: IPFR_CMPSZ)) { ! 154: ipfr_stats.ifs_exists++; ! 155: return NULL; ! 156: } ! 157: ! 158: /* ! 159: * allocate some memory, if possible, if not, just record that we ! 160: * failed to do so. ! 161: */ ! 162: KMALLOC(fr, ipfr_t *, sizeof(*fr)); ! 163: if (fr == NULL) { ! 164: ipfr_stats.ifs_nomem++; ! 165: return NULL; ! 166: } ! 167: ! 168: /* ! 169: * Instert the fragment into the fragment table, copy the struct used ! 170: * in the search using bcopy rather than reassign each field. ! 171: * Set the ttl to the default and mask out logging from "pass" ! 172: */ ! 173: if ((fr->ipfr_next = table[idx])) ! 174: table[idx]->ipfr_prev = fr; ! 175: fr->ipfr_prev = NULL; ! 176: fr->ipfr_data = NULL; ! 177: table[idx] = fr; ! 178: bcopy((char *)&frag.ipfr_src, (char *)&fr->ipfr_src, IPFR_CMPSZ); ! 179: fr->ipfr_ttl = fr_ipfrttl; ! 180: fr->ipfr_pass = pass & ~(FR_LOGFIRST|FR_LOG); ! 181: /* ! 182: * Compute the offset of the expected start of the next packet. ! 183: */ ! 184: fr->ipfr_off = (ip->ip_off & 0x1fff) + (fin->fin_dlen >> 3); ! 185: ipfr_stats.ifs_new++; ! 186: ipfr_inuse++; ! 187: return fr; ! 188: } ! 189: ! 190: ! 191: int ipfr_newfrag(ip, fin, pass) ! 192: ip_t *ip; ! 193: fr_info_t *fin; ! 194: int pass; ! 195: { ! 196: ipfr_t *ipf; ! 197: ! 198: MUTEX_ENTER(&ipf_frag); ! 199: ipf = ipfr_new(ip, fin, pass, ipfr_heads); ! 200: MUTEX_EXIT(&ipf_frag); ! 201: return ipf ? 0 : -1; ! 202: } ! 203: ! 204: ! 205: int ipfr_nat_newfrag(ip, fin, pass, nat) ! 206: ip_t *ip; ! 207: fr_info_t *fin; ! 208: int pass; ! 209: nat_t *nat; ! 210: { ! 211: ipfr_t *ipf; ! 212: ! 213: MUTEX_ENTER(&ipf_natfrag); ! 214: if ((ipf = ipfr_new(ip, fin, pass, ipfr_nattab))) { ! 215: ipf->ipfr_data = nat; ! 216: nat->nat_data = ipf; ! 217: } ! 218: MUTEX_EXIT(&ipf_natfrag); ! 219: return ipf ? 0 : -1; ! 220: } ! 221: ! 222: ! 223: /* ! 224: * check the fragment cache to see if there is already a record of this packet ! 225: * with its filter result known. ! 226: */ ! 227: static ipfr_t *ipfr_lookup(ip, fin, table) ! 228: ip_t *ip; ! 229: fr_info_t *fin; ! 230: ipfr_t *table[]; ! 231: { ! 232: ipfr_t *f, frag; ! 233: u_int idx; ! 234: ! 235: /* ! 236: * For fragments, we record protocol, packet id, TOS and both IP#'s ! 237: * (these should all be the same for all fragments of a packet). ! 238: * ! 239: * build up a hash value to index the table with. ! 240: */ ! 241: frag.ipfr_p = ip->ip_p; ! 242: idx = ip->ip_p; ! 243: frag.ipfr_id = ip->ip_id; ! 244: idx += ip->ip_id; ! 245: frag.ipfr_tos = ip->ip_tos; ! 246: frag.ipfr_src.s_addr = ip->ip_src.s_addr; ! 247: idx += ip->ip_src.s_addr; ! 248: frag.ipfr_dst.s_addr = ip->ip_dst.s_addr; ! 249: idx += ip->ip_dst.s_addr; ! 250: idx *= 127; ! 251: idx %= IPFT_SIZE; ! 252: ! 253: /* ! 254: * check the table, careful to only compare the right amount of data ! 255: */ ! 256: for (f = table[idx]; f; f = f->ipfr_next) ! 257: if (!bcmp((char *)&frag.ipfr_src, (char *)&f->ipfr_src, ! 258: IPFR_CMPSZ)) { ! 259: u_short atoff, off; ! 260: ! 261: if (f != table[idx]) { ! 262: /* ! 263: * move fragment info. to the top of the list ! 264: * to speed up searches. ! 265: */ ! 266: if ((f->ipfr_prev->ipfr_next = f->ipfr_next)) ! 267: f->ipfr_next->ipfr_prev = f->ipfr_prev; ! 268: f->ipfr_next = table[idx]; ! 269: table[idx]->ipfr_prev = f; ! 270: f->ipfr_prev = NULL; ! 271: table[idx] = f; ! 272: } ! 273: off = ip->ip_off; ! 274: atoff = off + (fin->fin_dlen >> 3); ! 275: /* ! 276: * If we've follwed the fragments, and this is the ! 277: * last (in order), shrink expiration time. ! 278: */ ! 279: if ((off & 0x1fff) == f->ipfr_off) { ! 280: if (!(off & IP_MF)) ! 281: f->ipfr_ttl = 1; ! 282: else ! 283: f->ipfr_off = atoff; ! 284: } ! 285: ipfr_stats.ifs_hits++; ! 286: return f; ! 287: } ! 288: return NULL; ! 289: } ! 290: ! 291: ! 292: /* ! 293: * functional interface for NAT lookups of the NAT fragment cache ! 294: */ ! 295: nat_t *ipfr_nat_knownfrag(ip, fin) ! 296: ip_t *ip; ! 297: fr_info_t *fin; ! 298: { ! 299: nat_t *nat; ! 300: ipfr_t *ipf; ! 301: ! 302: MUTEX_ENTER(&ipf_natfrag); ! 303: ipf = ipfr_lookup(ip, fin, ipfr_nattab); ! 304: if (ipf) { ! 305: nat = ipf->ipfr_data; ! 306: /* ! 307: * This is the last fragment for this packet. ! 308: */ ! 309: if (ipf->ipfr_ttl == 1) { ! 310: nat->nat_data = NULL; ! 311: ipf->ipfr_data = NULL; ! 312: } ! 313: } else ! 314: nat = NULL; ! 315: MUTEX_EXIT(&ipf_natfrag); ! 316: return nat; ! 317: } ! 318: ! 319: ! 320: /* ! 321: * functional interface for normal lookups of the fragment cache ! 322: */ ! 323: int ipfr_knownfrag(ip, fin) ! 324: ip_t *ip; ! 325: fr_info_t *fin; ! 326: { ! 327: int ret; ! 328: ipfr_t *ipf; ! 329: ! 330: MUTEX_ENTER(&ipf_frag); ! 331: ipf = ipfr_lookup(ip, fin, ipfr_heads); ! 332: ret = ipf ? ipf->ipfr_pass : 0; ! 333: MUTEX_EXIT(&ipf_frag); ! 334: return ret; ! 335: } ! 336: ! 337: ! 338: /* ! 339: * forget any references to this external object. ! 340: */ ! 341: void ipfr_forget(nat) ! 342: void *nat; ! 343: { ! 344: ipfr_t *fr; ! 345: int idx; ! 346: ! 347: MUTEX_ENTER(&ipf_natfrag); ! 348: for (idx = IPFT_SIZE - 1; idx >= 0; idx--) ! 349: for (fr = ipfr_heads[idx]; fr; fr = fr->ipfr_next) ! 350: if (fr->ipfr_data == nat) ! 351: fr->ipfr_data = NULL; ! 352: ! 353: MUTEX_EXIT(&ipf_natfrag); ! 354: } ! 355: ! 356: ! 357: /* ! 358: * Free memory in use by fragment state info. kept. ! 359: */ ! 360: void ipfr_unload() ! 361: { ! 362: ipfr_t **fp, *fr; ! 363: nat_t *nat; ! 364: int idx; ! 365: ! 366: MUTEX_ENTER(&ipf_frag); ! 367: for (idx = IPFT_SIZE - 1; idx >= 0; idx--) ! 368: for (fp = &ipfr_heads[idx]; (fr = *fp); ) { ! 369: *fp = fr->ipfr_next; ! 370: KFREE(fr); ! 371: } ! 372: MUTEX_EXIT(&ipf_frag); ! 373: ! 374: MUTEX_ENTER(&ipf_nat); ! 375: MUTEX_ENTER(&ipf_natfrag); ! 376: for (idx = IPFT_SIZE - 1; idx >= 0; idx--) ! 377: for (fp = &ipfr_nattab[idx]; (fr = *fp); ) { ! 378: *fp = fr->ipfr_next; ! 379: if ((nat = (nat_t *)fr->ipfr_data)) { ! 380: if (nat->nat_data == fr) ! 381: nat->nat_data = NULL; ! 382: } ! 383: KFREE(fr); ! 384: } ! 385: MUTEX_EXIT(&ipf_natfrag); ! 386: MUTEX_EXIT(&ipf_nat); ! 387: } ! 388: ! 389: ! 390: #ifdef KERNEL ! 391: /* ! 392: * Slowly expire held state for fragments. Timeouts are set * in expectation ! 393: * of this being called twice per second. ! 394: */ ! 395: # if (BSD >= 199306) || SOLARIS || defined(__sgi) ! 396: void ipfr_slowtimer() ! 397: # else ! 398: int ipfr_slowtimer() ! 399: # endif ! 400: { ! 401: ipfr_t **fp, *fr; ! 402: nat_t *nat; ! 403: int s, idx; ! 404: ! 405: #ifdef __sgi ! 406: ipfilter_sgi_intfsync(); ! 407: #endif ! 408: ! 409: SPL_NET(s); ! 410: MUTEX_ENTER(&ipf_frag); ! 411: ! 412: /* ! 413: * Go through the entire table, looking for entries to expire, ! 414: * decreasing the ttl by one for each entry. If it reaches 0, ! 415: * remove it from the chain and free it. ! 416: */ ! 417: for (idx = IPFT_SIZE - 1; idx >= 0; idx--) ! 418: for (fp = &ipfr_heads[idx]; (fr = *fp); ) { ! 419: --fr->ipfr_ttl; ! 420: if (fr->ipfr_ttl == 0) { ! 421: if (fr->ipfr_prev) ! 422: fr->ipfr_prev->ipfr_next = ! 423: fr->ipfr_next; ! 424: if (fr->ipfr_next) ! 425: fr->ipfr_next->ipfr_prev = ! 426: fr->ipfr_prev; ! 427: *fp = fr->ipfr_next; ! 428: ipfr_stats.ifs_expire++; ! 429: ipfr_inuse--; ! 430: KFREE(fr); ! 431: } else ! 432: fp = &fr->ipfr_next; ! 433: } ! 434: MUTEX_EXIT(&ipf_frag); ! 435: ! 436: /* ! 437: * Same again for the NAT table, except that if the structure also ! 438: * still points to a NAT structure, and the NAT structure points back ! 439: * at the one to be free'd, NULL the reference from the NAT struct. ! 440: * NOTE: We need to grab both mutex's early, and in this order so as ! 441: * to prevent a deadlock if both try to expire at the same time. ! 442: */ ! 443: MUTEX_ENTER(&ipf_nat); ! 444: MUTEX_ENTER(&ipf_natfrag); ! 445: for (idx = IPFT_SIZE - 1; idx >= 0; idx--) ! 446: for (fp = &ipfr_nattab[idx]; (fr = *fp); ) { ! 447: --fr->ipfr_ttl; ! 448: if (fr->ipfr_ttl == 0) { ! 449: if (fr->ipfr_prev) ! 450: fr->ipfr_prev->ipfr_next = ! 451: fr->ipfr_next; ! 452: if (fr->ipfr_next) ! 453: fr->ipfr_next->ipfr_prev = ! 454: fr->ipfr_prev; ! 455: *fp = fr->ipfr_next; ! 456: ipfr_stats.ifs_expire++; ! 457: ipfr_inuse--; ! 458: if ((nat = (nat_t *)fr->ipfr_data)) { ! 459: if (nat->nat_data == fr) ! 460: nat->nat_data = NULL; ! 461: } ! 462: KFREE(fr); ! 463: } else ! 464: fp = &fr->ipfr_next; ! 465: } ! 466: MUTEX_EXIT(&ipf_natfrag); ! 467: MUTEX_EXIT(&ipf_nat); ! 468: SPL_X(s); ! 469: fr_timeoutstate(); ! 470: ip_natexpire(); ! 471: fr_authexpire(); ! 472: # if SOLARIS ! 473: ipfr_timer_id = timeout(ipfr_slowtimer, NULL, drv_usectohz(500000)); ! 474: # else ! 475: # ifndef linux ! 476: ip_slowtimo(); ! 477: # endif ! 478: # if (BSD < 199306) && !defined(__sgi) ! 479: return 0; ! 480: # endif ! 481: # endif ! 482: } ! 483: #endif /* defined(KERNEL) */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.