|
|
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) 1995-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_state.c 1.8 6/5/96 (C) 1993-1995 Darren Reed"; */ ! 31: #endif ! 32: ! 33: #include "opt_ipfilter.h" ! 34: #if defined(KERNEL) && !defined(_KERNEL) ! 35: #define _KERNEL ! 36: #endif ! 37: #define __FreeBSD_version 300000 /* it's a hack, but close enough */ ! 38: ! 39: #if !defined(_KERNEL) && !defined(KERNEL) && !defined(__KERNEL__) ! 40: # include <stdlib.h> ! 41: # include <string.h> ! 42: #else ! 43: # ifdef linux ! 44: # include <linux/kernel.h> ! 45: # include <linux/module.h> ! 46: # endif ! 47: #endif ! 48: #include <sys/errno.h> ! 49: #include <sys/types.h> ! 50: #include <sys/param.h> ! 51: #include <sys/file.h> ! 52: #if defined(KERNEL) && (__FreeBSD_version >= 220000) ! 53: # include <sys/filio.h> ! 54: # include <sys/fcntl.h> ! 55: # include <sys/malloc.h> ! 56: #else ! 57: # include <sys/ioctl.h> ! 58: #endif ! 59: #include <sys/time.h> ! 60: #include <sys/uio.h> ! 61: #ifndef linux ! 62: #include <sys/protosw.h> ! 63: #endif ! 64: #include <sys/socket.h> ! 65: #if defined(_KERNEL) && !defined(linux) ! 66: # include <sys/systm.h> ! 67: #endif ! 68: #if !defined(__SVR4) && !defined(__svr4__) ! 69: # ifndef linux ! 70: # include <sys/mbuf.h> ! 71: # endif ! 72: #else ! 73: # include <sys/filio.h> ! 74: # include <sys/byteorder.h> ! 75: # include <sys/dditypes.h> ! 76: # include <sys/stream.h> ! 77: # include <sys/kmem.h> ! 78: #endif ! 79: ! 80: #include <net/if.h> ! 81: #if sun ! 82: #include <net/af.h> ! 83: #endif ! 84: #include <net/route.h> ! 85: #include <netinet/in.h> ! 86: #include <netinet/in_systm.h> ! 87: #include <netinet/ip.h> ! 88: #include <netinet/tcp.h> ! 89: #ifndef linux ! 90: # include <netinet/ip_var.h> ! 91: # include <netinet/tcp_fsm.h> ! 92: #endif ! 93: #include <netinet/udp.h> ! 94: #include <netinet/ip_icmp.h> ! 95: #include "netinet/ip_compat.h" ! 96: #include <netinet/tcpip.h> ! 97: #include "netinet/ip_fil.h" ! 98: #include "netinet/ip_nat.h" ! 99: #include "netinet/ip_frag.h" ! 100: #include "netinet/ip_proxy.h" ! 101: #include "netinet/ip_state.h" ! 102: #ifndef MIN ! 103: #define MIN(a,b) (((a)<(b))?(a):(b)) ! 104: #endif ! 105: ! 106: #define TCP_CLOSE (TH_FIN|TH_RST) ! 107: ! 108: static ipstate_t *ips_table[IPSTATE_SIZE]; ! 109: static int ips_num = 0; ! 110: static ips_stat_t ips_stats; ! 111: #if (SOLARIS || defined(__sgi)) && defined(_KERNEL) ! 112: extern kmutex_t ipf_state; ! 113: #endif ! 114: ! 115: static int fr_matchsrcdst __P((ipstate_t *, struct in_addr, struct in_addr, ! 116: fr_info_t *, void *, u_short, u_short)); ! 117: static int fr_state_flush __P((int)); ! 118: static ips_stat_t *fr_statetstats __P((void)); ! 119: ! 120: ! 121: #define FIVE_DAYS (2 * 5 * 86400) /* 5 days: half closed session */ ! 122: ! 123: u_long fr_tcpidletimeout = FIVE_DAYS, ! 124: fr_tcpclosewait = 60, ! 125: fr_tcplastack = 20, ! 126: fr_tcptimeout = 120, ! 127: fr_tcpclosed = 1, ! 128: fr_udptimeout = 120, ! 129: fr_icmptimeout = 120; ! 130: ! 131: ! 132: static ips_stat_t *fr_statetstats() ! 133: { ! 134: ips_stats.iss_active = ips_num; ! 135: ips_stats.iss_table = ips_table; ! 136: return &ips_stats; ! 137: } ! 138: ! 139: ! 140: /* ! 141: * flush state tables. two actions currently defined: ! 142: * which == 0 : flush all state table entries ! 143: * which == 1 : flush TCP connections which have started to close but are ! 144: * stuck for some reason. ! 145: */ ! 146: static int fr_state_flush(which) ! 147: int which; ! 148: { ! 149: register int i; ! 150: register ipstate_t *is, **isp; ! 151: #if defined(_KERNEL) && !SOLARIS ! 152: int s; ! 153: #endif ! 154: int delete, removed = 0; ! 155: ! 156: SPL_NET(s); ! 157: MUTEX_ENTER(&ipf_state); ! 158: for (i = 0; i < IPSTATE_SIZE; i++) ! 159: for (isp = &ips_table[i]; (is = *isp); ) { ! 160: delete = 0; ! 161: ! 162: switch (which) ! 163: { ! 164: case 0 : ! 165: delete = 1; ! 166: break; ! 167: case 1 : ! 168: if ((is->is_p == IPPROTO_TCP) && ! 169: (((is->is_state[0] <= TCPS_ESTABLISHED) && ! 170: (is->is_state[1] > TCPS_ESTABLISHED)) || ! 171: ((is->is_state[1] <= TCPS_ESTABLISHED) && ! 172: (is->is_state[0] > TCPS_ESTABLISHED)))) ! 173: delete = 1; ! 174: break; ! 175: } ! 176: ! 177: if (delete) { ! 178: *isp = is->is_next; ! 179: if (is->is_p == IPPROTO_TCP) ! 180: ips_stats.iss_fin++; ! 181: else ! 182: ips_stats.iss_expire++; ! 183: #if IPFILTER_LOG ! 184: ipstate_log(is, ISL_FLUSH); ! 185: #endif ! 186: KFREE(is); ! 187: ips_num--; ! 188: removed++; ! 189: } else ! 190: isp = &is->is_next; ! 191: } ! 192: MUTEX_EXIT(&ipf_state); ! 193: SPL_X(s); ! 194: return removed; ! 195: } ! 196: ! 197: ! 198: int fr_state_ioctl(data, cmd, mode) ! 199: caddr_t data; ! 200: #if defined(__NetBSD__) || defined(__OpenBSD__) ! 201: u_long cmd; ! 202: #else ! 203: int cmd; ! 204: #endif ! 205: int mode; ! 206: { ! 207: int arg, ret, error = 0; ! 208: ! 209: switch (cmd) ! 210: { ! 211: case SIOCIPFFL : ! 212: IRCOPY(data, (caddr_t)&arg, sizeof(arg)); ! 213: if (arg == 0 || arg == 1) { ! 214: ret = fr_state_flush(arg); ! 215: IWCOPY((caddr_t)&ret, data, sizeof(ret)); ! 216: } else ! 217: error = EINVAL; ! 218: break; ! 219: case SIOCGIPST : ! 220: IWCOPY((caddr_t)fr_statetstats(), data, sizeof(ips_stat_t)); ! 221: break; ! 222: case FIONREAD : ! 223: #if IPFILTER_LOG ! 224: IWCOPY((caddr_t)&iplused[IPL_LOGSTATE], (caddr_t)data, ! 225: sizeof(iplused[IPL_LOGSTATE])); ! 226: #endif ! 227: break; ! 228: default : ! 229: return EINVAL; ! 230: } ! 231: return error; ! 232: } ! 233: ! 234: ! 235: /* ! 236: * Create a new ipstate structure and hang it off the hash table. ! 237: */ ! 238: int fr_addstate(ip, fin, pass) ! 239: ip_t *ip; ! 240: fr_info_t *fin; ! 241: u_int pass; ! 242: { ! 243: ipstate_t ips; ! 244: register ipstate_t *is = &ips; ! 245: register u_int hv; ! 246: ! 247: if ((ip->ip_off & 0x1fff) || (fin->fin_fi.fi_fl & FI_SHORT)) ! 248: return -1; ! 249: if (ips_num == IPSTATE_MAX) { ! 250: ips_stats.iss_max++; ! 251: return -1; ! 252: } ! 253: ips.is_age = 1; ! 254: ips.is_state[0] = 0; ! 255: ips.is_state[1] = 0; ! 256: /* ! 257: * Copy and calculate... ! 258: */ ! 259: hv = (is->is_p = ip->ip_p); ! 260: hv += (is->is_src.s_addr = ip->ip_src.s_addr); ! 261: hv += (is->is_dst.s_addr = ip->ip_dst.s_addr); ! 262: ! 263: switch (ip->ip_p) ! 264: { ! 265: case IPPROTO_ICMP : ! 266: { ! 267: struct icmp *ic = (struct icmp *)fin->fin_dp; ! 268: ! 269: switch (ic->icmp_type) ! 270: { ! 271: case ICMP_ECHO : ! 272: is->is_icmp.ics_type = ICMP_ECHOREPLY; /* XXX */ ! 273: hv += (is->is_icmp.ics_id = ic->icmp_id); ! 274: hv += (is->is_icmp.ics_seq = ic->icmp_seq); ! 275: break; ! 276: case ICMP_TSTAMP : ! 277: case ICMP_IREQ : ! 278: case ICMP_MASKREQ : ! 279: is->is_icmp.ics_type = ic->icmp_type + 1; ! 280: break; ! 281: default : ! 282: return -1; ! 283: } ! 284: ips_stats.iss_icmp++; ! 285: is->is_age = fr_icmptimeout; ! 286: break; ! 287: } ! 288: case IPPROTO_TCP : ! 289: { ! 290: register tcphdr_t *tcp = (tcphdr_t *)fin->fin_dp; ! 291: ! 292: /* ! 293: * The endian of the ports doesn't matter, but the ack and ! 294: * sequence numbers do as we do mathematics on them later. ! 295: */ ! 296: hv += (is->is_dport = tcp->th_dport); ! 297: hv += (is->is_sport = tcp->th_sport); ! 298: is->is_seq = ntohl(tcp->th_seq); ! 299: is->is_ack = ntohl(tcp->th_ack); ! 300: is->is_swin = ntohs(tcp->th_win); ! 301: is->is_dwin = is->is_swin; /* start them the same */ ! 302: ips_stats.iss_tcp++; ! 303: /* ! 304: * If we're creating state for a starting connection, start the ! 305: * timer on it as we'll never see an error if it fails to ! 306: * connect. ! 307: */ ! 308: if ((tcp->th_flags & (TH_SYN|TH_ACK)) == TH_SYN) ! 309: is->is_ack = 0; /* Trumpet WinSock 'ism */ ! 310: fr_tcp_age(&is->is_age, is->is_state, ip, fin, ! 311: tcp->th_sport == is->is_sport); ! 312: break; ! 313: } ! 314: case IPPROTO_UDP : ! 315: { ! 316: register tcphdr_t *tcp = (tcphdr_t *)fin->fin_dp; ! 317: ! 318: hv += (is->is_dport = tcp->th_dport); ! 319: hv += (is->is_sport = tcp->th_sport); ! 320: ips_stats.iss_udp++; ! 321: is->is_age = fr_udptimeout; ! 322: break; ! 323: } ! 324: default : ! 325: return -1; ! 326: } ! 327: ! 328: KMALLOC(is, ipstate_t *, sizeof(*is)); ! 329: if (is == NULL) { ! 330: ips_stats.iss_nomem++; ! 331: return -1; ! 332: } ! 333: bcopy((char *)&ips, (char *)is, sizeof(*is)); ! 334: hv %= IPSTATE_SIZE; ! 335: MUTEX_ENTER(&ipf_state); ! 336: ! 337: is->is_pass = pass; ! 338: is->is_pkts = 1; ! 339: is->is_bytes = ip->ip_len; ! 340: /* ! 341: * Copy these from the rule itself. ! 342: */ ! 343: is->is_opt = fin->fin_fr->fr_ip.fi_optmsk; ! 344: is->is_optmsk = fin->fin_fr->fr_mip.fi_optmsk; ! 345: is->is_sec = fin->fin_fr->fr_ip.fi_secmsk; ! 346: is->is_secmsk = fin->fin_fr->fr_mip.fi_secmsk; ! 347: is->is_auth = fin->fin_fr->fr_ip.fi_auth; ! 348: is->is_authmsk = fin->fin_fr->fr_mip.fi_auth; ! 349: is->is_flags = fin->fin_fr->fr_ip.fi_fl; ! 350: is->is_flags |= fin->fin_fr->fr_mip.fi_fl << 4; ! 351: /* ! 352: * add into table. ! 353: */ ! 354: is->is_next = ips_table[hv]; ! 355: ips_table[hv] = is; ! 356: if (fin->fin_out) { ! 357: is->is_ifpin = NULL; ! 358: is->is_ifpout = fin->fin_ifp; ! 359: } else { ! 360: is->is_ifpin = fin->fin_ifp; ! 361: is->is_ifpout = NULL; ! 362: } ! 363: if (pass & FR_LOGFIRST) ! 364: is->is_pass &= ~(FR_LOGFIRST|FR_LOG); ! 365: ips_num++; ! 366: #if IPFILTER_LOG ! 367: ipstate_log(is, ISL_NEW); ! 368: #endif ! 369: MUTEX_EXIT(&ipf_state); ! 370: if (fin->fin_fi.fi_fl & FI_FRAG) ! 371: ipfr_newfrag(ip, fin, pass ^ FR_KEEPSTATE); ! 372: return 0; ! 373: } ! 374: ! 375: ! 376: /* ! 377: * check to see if a packet with TCP headers fits within the TCP window. ! 378: * change timeout depending on whether new packet is a SYN-ACK returning for a ! 379: * SYN or a RST or FIN which indicate time to close up shop. ! 380: */ ! 381: int fr_tcpstate(is, fin, ip, tcp) ! 382: register ipstate_t *is; ! 383: fr_info_t *fin; ! 384: ip_t *ip; ! 385: tcphdr_t *tcp; ! 386: { ! 387: register int seqskew, ackskew; ! 388: register u_short swin, dwin; ! 389: register tcp_seq seq, ack; ! 390: int source; ! 391: ! 392: /* ! 393: * Find difference between last checked packet and this packet. ! 394: */ ! 395: seq = ntohl(tcp->th_seq); ! 396: ack = ntohl(tcp->th_ack); ! 397: source = (ip->ip_src.s_addr == is->is_src.s_addr); ! 398: ! 399: if (!(tcp->th_flags & TH_ACK)) /* Pretend an ack was sent */ ! 400: ack = source ? is->is_ack : is->is_seq; ! 401: ! 402: if (source) { ! 403: if (!is->is_seq) ! 404: /* ! 405: * Must be an outgoing SYN-ACK in reply to a SYN. ! 406: */ ! 407: is->is_seq = seq; ! 408: seqskew = seq - is->is_seq; ! 409: ackskew = ack - is->is_ack; ! 410: } else { ! 411: if (!is->is_ack) ! 412: /* ! 413: * Must be a SYN-ACK in reply to a SYN. ! 414: */ ! 415: is->is_ack = seq; ! 416: ackskew = seq - is->is_ack; ! 417: seqskew = ack - is->is_seq; ! 418: } ! 419: ! 420: /* ! 421: * Make skew values absolute ! 422: */ ! 423: if (seqskew < 0) ! 424: seqskew = -seqskew; ! 425: if (ackskew < 0) ! 426: ackskew = -ackskew; ! 427: ! 428: /* ! 429: * If the difference in sequence and ack numbers is within the ! 430: * window size of the connection, store these values and match ! 431: * the packet. ! 432: */ ! 433: if (source) { ! 434: swin = is->is_swin; ! 435: dwin = is->is_dwin; ! 436: } else { ! 437: dwin = is->is_swin; ! 438: swin = is->is_dwin; ! 439: } ! 440: ! 441: if ((seqskew <= dwin) && (ackskew <= swin)) { ! 442: if (source) { ! 443: is->is_seq = seq; ! 444: is->is_ack = ack; ! 445: is->is_swin = ntohs(tcp->th_win); ! 446: } else { ! 447: is->is_seq = ack; ! 448: is->is_ack = seq; ! 449: is->is_dwin = ntohs(tcp->th_win); ! 450: } ! 451: ips_stats.iss_hits++; ! 452: is->is_pkts++; ! 453: is->is_bytes += ip->ip_len; ! 454: /* ! 455: * Nearing end of connection, start timeout. ! 456: */ ! 457: fr_tcp_age(&is->is_age, is->is_state, ip, fin, source); ! 458: return 1; ! 459: } ! 460: return 0; ! 461: } ! 462: ! 463: ! 464: static int fr_matchsrcdst(is, src, dst, fin, tcp, sp, dp) ! 465: ipstate_t *is; ! 466: struct in_addr src, dst; ! 467: fr_info_t *fin; ! 468: void *tcp; ! 469: u_short sp, dp; ! 470: { ! 471: int ret = 0, rev, out; ! 472: void *ifp; ! 473: ! 474: rev = (is->is_dst.s_addr != dst.s_addr); ! 475: ifp = fin->fin_ifp; ! 476: out = fin->fin_out; ! 477: ! 478: if (!rev) { ! 479: if (out) { ! 480: if (!is->is_ifpout) ! 481: is->is_ifpout = ifp; ! 482: } else { ! 483: if (!is->is_ifpin) ! 484: is->is_ifpin = ifp; ! 485: } ! 486: } else { ! 487: if (out) { ! 488: if (!is->is_ifpin) ! 489: is->is_ifpin = ifp; ! 490: } else { ! 491: if (!is->is_ifpout) ! 492: is->is_ifpout = ifp; ! 493: } ! 494: } ! 495: ! 496: if (!rev) { ! 497: if (((out && is->is_ifpout == ifp) || ! 498: (!out && is->is_ifpin == ifp)) && ! 499: (is->is_dst.s_addr == dst.s_addr) && ! 500: (is->is_src.s_addr == src.s_addr) && ! 501: (!tcp || (sp == is->is_sport) && ! 502: (dp == is->is_dport))) { ! 503: ret = 1; ! 504: } ! 505: } else { ! 506: if (((out && is->is_ifpin == ifp) || ! 507: (!out && is->is_ifpout == ifp)) && ! 508: (is->is_dst.s_addr == src.s_addr) && ! 509: (is->is_src.s_addr == dst.s_addr) && ! 510: (!tcp || (sp == is->is_dport) && ! 511: (dp == is->is_sport))) { ! 512: ret = 1; ! 513: } ! 514: } ! 515: ! 516: /* ! 517: * Whether or not this should be here, is questionable, but the aim ! 518: * is to get this out of the main line. ! 519: */ ! 520: if (ret) { ! 521: if (((fin->fin_fi.fi_optmsk & is->is_optmsk) != is->is_opt) || ! 522: ((fin->fin_fi.fi_secmsk & is->is_secmsk) != is->is_sec) || ! 523: ((fin->fin_fi.fi_auth & is->is_authmsk) != is->is_auth) || ! 524: ((fin->fin_fi.fi_fl & (is->is_flags >> 4)) != ! 525: (is->is_flags & 0xf))) ! 526: ret = 0; ! 527: } ! 528: return ret; ! 529: } ! 530: ! 531: ! 532: /* ! 533: * Check if a packet has a registered state. ! 534: */ ! 535: int fr_checkstate(ip, fin) ! 536: ip_t *ip; ! 537: fr_info_t *fin; ! 538: { ! 539: register struct in_addr dst, src; ! 540: register ipstate_t *is, **isp; ! 541: register u_char pr; ! 542: struct icmp *ic; ! 543: tcphdr_t *tcp; ! 544: u_int hv, hlen, pass; ! 545: ! 546: if ((ip->ip_off & 0x1fff) || (fin->fin_fi.fi_fl & FI_SHORT)) ! 547: return 0; ! 548: ! 549: hlen = fin->fin_hlen; ! 550: tcp = (tcphdr_t *)((char *)ip + hlen); ! 551: ic = (struct icmp *)tcp; ! 552: hv = (pr = ip->ip_p); ! 553: hv += (src.s_addr = ip->ip_src.s_addr); ! 554: hv += (dst.s_addr = ip->ip_dst.s_addr); ! 555: ! 556: /* ! 557: * Search the hash table for matching packet header info. ! 558: */ ! 559: switch (ip->ip_p) ! 560: { ! 561: case IPPROTO_ICMP : ! 562: hv += ic->icmp_id; ! 563: hv += ic->icmp_seq; ! 564: hv %= IPSTATE_SIZE; ! 565: MUTEX_ENTER(&ipf_state); ! 566: for (isp = &ips_table[hv]; (is = *isp); isp = &is->is_next) ! 567: if ((is->is_p == pr) && ! 568: (ic->icmp_id == is->is_icmp.ics_id) && ! 569: (ic->icmp_seq == is->is_icmp.ics_seq) && ! 570: fr_matchsrcdst(is, src, dst, fin, NULL, 0, 0)) { ! 571: if (is->is_icmp.ics_type != ic->icmp_type) ! 572: continue; ! 573: is->is_age = fr_icmptimeout; ! 574: is->is_pkts++; ! 575: is->is_bytes += ip->ip_len; ! 576: ips_stats.iss_hits++; ! 577: pass = is->is_pass; ! 578: MUTEX_EXIT(&ipf_state); ! 579: return pass; ! 580: } ! 581: MUTEX_EXIT(&ipf_state); ! 582: break; ! 583: case IPPROTO_TCP : ! 584: { ! 585: register u_short dport = tcp->th_dport, sport = tcp->th_sport; ! 586: ! 587: hv += dport; ! 588: hv += sport; ! 589: hv %= IPSTATE_SIZE; ! 590: MUTEX_ENTER(&ipf_state); ! 591: for (isp = &ips_table[hv]; (is = *isp); isp = &is->is_next) ! 592: if ((is->is_p == pr) && ! 593: fr_matchsrcdst(is, src, dst, fin, tcp, ! 594: sport, dport)) { ! 595: if (fr_tcpstate(is, fin, ip, tcp)) { ! 596: pass = is->is_pass; ! 597: #ifdef _KERNEL ! 598: MUTEX_EXIT(&ipf_state); ! 599: #else ! 600: ! 601: if (tcp->th_flags & TCP_CLOSE) { ! 602: *isp = is->is_next; ! 603: isp = &ips_table[hv]; ! 604: KFREE(is); ! 605: } ! 606: #endif ! 607: return pass; ! 608: } ! 609: } ! 610: MUTEX_EXIT(&ipf_state); ! 611: break; ! 612: } ! 613: case IPPROTO_UDP : ! 614: { ! 615: register u_short dport = tcp->th_dport, sport = tcp->th_sport; ! 616: ! 617: hv += dport; ! 618: hv += sport; ! 619: hv %= IPSTATE_SIZE; ! 620: /* ! 621: * Nothing else to match on but ports. and IP#'s ! 622: */ ! 623: MUTEX_ENTER(&ipf_state); ! 624: for (is = ips_table[hv]; is; is = is->is_next) ! 625: if ((is->is_p == pr) && ! 626: fr_matchsrcdst(is, src, dst, fin, ! 627: tcp, sport, dport)) { ! 628: ips_stats.iss_hits++; ! 629: is->is_pkts++; ! 630: is->is_bytes += ip->ip_len; ! 631: is->is_age = fr_udptimeout; ! 632: pass = is->is_pass; ! 633: MUTEX_EXIT(&ipf_state); ! 634: return pass; ! 635: } ! 636: MUTEX_EXIT(&ipf_state); ! 637: break; ! 638: } ! 639: default : ! 640: break; ! 641: } ! 642: ips_stats.iss_miss++; ! 643: return 0; ! 644: } ! 645: ! 646: ! 647: /* ! 648: * Free memory in use by all state info. kept. ! 649: */ ! 650: void fr_stateunload() ! 651: { ! 652: register int i; ! 653: register ipstate_t *is, **isp; ! 654: ! 655: MUTEX_ENTER(&ipf_state); ! 656: for (i = 0; i < IPSTATE_SIZE; i++) ! 657: for (isp = &ips_table[i]; (is = *isp); ) { ! 658: *isp = is->is_next; ! 659: KFREE(is); ! 660: } ! 661: MUTEX_EXIT(&ipf_state); ! 662: } ! 663: ! 664: ! 665: /* ! 666: * Slowly expire held state for thingslike UDP and ICMP. Timeouts are set ! 667: * in expectation of this being called twice per second. ! 668: */ ! 669: void fr_timeoutstate() ! 670: { ! 671: register int i; ! 672: register ipstate_t *is, **isp; ! 673: #if defined(_KERNEL) && !SOLARIS ! 674: int s; ! 675: #endif ! 676: ! 677: SPL_NET(s); ! 678: MUTEX_ENTER(&ipf_state); ! 679: for (i = 0; i < IPSTATE_SIZE; i++) ! 680: for (isp = &ips_table[i]; (is = *isp); ) ! 681: if (is->is_age && !--is->is_age) { ! 682: *isp = is->is_next; ! 683: if (is->is_p == IPPROTO_TCP) ! 684: ips_stats.iss_fin++; ! 685: else ! 686: ips_stats.iss_expire++; ! 687: #if IPFILTER_LOG ! 688: ipstate_log(is, ISL_EXPIRE); ! 689: #endif ! 690: KFREE(is); ! 691: ips_num--; ! 692: } else ! 693: isp = &is->is_next; ! 694: MUTEX_EXIT(&ipf_state); ! 695: SPL_X(s); ! 696: } ! 697: ! 698: ! 699: /* ! 700: * Original idea freom Pradeep Krishnan for use primarily with NAT code. ! 701: * ([email protected]) ! 702: */ ! 703: void fr_tcp_age(age, state, ip, fin, dir) ! 704: u_long *age; ! 705: u_char *state; ! 706: ip_t *ip; ! 707: fr_info_t *fin; ! 708: int dir; ! 709: { ! 710: tcphdr_t *tcp = (tcphdr_t *)fin->fin_dp; ! 711: u_char flags = tcp->th_flags; ! 712: int dlen, ostate; ! 713: ! 714: ostate = state[1 - dir]; ! 715: ! 716: dlen = ip->ip_len - fin->fin_hlen - (tcp->th_off << 2); ! 717: ! 718: if (flags & TH_RST) { ! 719: if (!(tcp->th_flags & TH_PUSH) && !dlen) { ! 720: *age = fr_tcpclosed; ! 721: state[dir] = TCPS_CLOSED; ! 722: } else { ! 723: *age = fr_tcpclosewait; ! 724: state[dir] = TCPS_CLOSE_WAIT; ! 725: } ! 726: return; ! 727: } ! 728: ! 729: *age = fr_tcptimeout; /* 1 min */ ! 730: ! 731: switch(state[dir]) ! 732: { ! 733: case TCPS_FIN_WAIT_2: ! 734: case TCPS_CLOSED: ! 735: if ((flags & TH_OPENING) == TH_OPENING) ! 736: state[dir] = TCPS_SYN_RECEIVED; ! 737: else if (flags & TH_SYN) ! 738: state[dir] = TCPS_SYN_SENT; ! 739: break; ! 740: case TCPS_SYN_RECEIVED: ! 741: if ((flags & (TH_FIN|TH_ACK)) == TH_ACK) { ! 742: state[dir] = TCPS_ESTABLISHED; ! 743: *age = fr_tcpidletimeout; ! 744: } ! 745: break; ! 746: case TCPS_SYN_SENT: ! 747: if ((flags & (TH_FIN|TH_ACK)) == TH_ACK) { ! 748: state[dir] = TCPS_ESTABLISHED; ! 749: *age = fr_tcpidletimeout; ! 750: } ! 751: break; ! 752: case TCPS_ESTABLISHED: ! 753: if (flags & TH_FIN) { ! 754: state[dir] = TCPS_CLOSE_WAIT; ! 755: if (!(flags & TH_PUSH) && !dlen && ! 756: ostate > TCPS_ESTABLISHED) ! 757: *age = fr_tcplastack; ! 758: else ! 759: *age = fr_tcpclosewait; ! 760: } else ! 761: *age = fr_tcpidletimeout; ! 762: break; ! 763: case TCPS_CLOSE_WAIT: ! 764: if ((flags & TH_FIN) && !(flags & TH_PUSH) && !dlen && ! 765: ostate > TCPS_ESTABLISHED) { ! 766: *age = fr_tcplastack; ! 767: state[dir] = TCPS_LAST_ACK; ! 768: } else ! 769: *age = fr_tcpclosewait; ! 770: break; ! 771: case TCPS_LAST_ACK: ! 772: if (flags & TH_ACK) { ! 773: state[dir] = TCPS_FIN_WAIT_2; ! 774: if (!(flags & TH_PUSH) && !dlen && ! 775: ostate > TCPS_ESTABLISHED) ! 776: *age = fr_tcplastack; ! 777: else { ! 778: *age = fr_tcpclosewait; ! 779: state[dir] = TCPS_CLOSE_WAIT; ! 780: } ! 781: } ! 782: break; ! 783: } ! 784: } ! 785: ! 786: ! 787: #if IPFILTER_LOG ! 788: void ipstate_log(is, type) ! 789: struct ipstate *is; ! 790: u_short type; ! 791: { ! 792: struct ipslog ipsl; ! 793: void *items[1]; ! 794: size_t sizes[1]; ! 795: int types[1]; ! 796: ! 797: ipsl.isl_pkts = is->is_pkts; ! 798: ipsl.isl_bytes = is->is_bytes; ! 799: ipsl.isl_src = is->is_src; ! 800: ipsl.isl_dst = is->is_dst; ! 801: ipsl.isl_p = is->is_p; ! 802: ipsl.isl_flags = is->is_flags; ! 803: ipsl.isl_type = type; ! 804: if (ipsl.isl_p == IPPROTO_TCP || ipsl.isl_p == IPPROTO_UDP) { ! 805: ipsl.isl_sport = is->is_sport; ! 806: ipsl.isl_dport = is->is_dport; ! 807: } else if (ipsl.isl_p == IPPROTO_ICMP) ! 808: ipsl.isl_itype = is->is_icmp.ics_type; ! 809: else { ! 810: ipsl.isl_ps.isl_filler[0] = 0; ! 811: ipsl.isl_ps.isl_filler[1] = 0; ! 812: } ! 813: items[0] = &ipsl; ! 814: sizes[0] = sizeof(ipsl); ! 815: types[0] = 0; ! 816: ! 817: (void) ipllog(IPL_LOGSTATE, 0, items, sizes, types, 1); ! 818: } ! 819: #endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.