|
|
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[] = "@(#)fil.c 1.36 6/5/96 (C) 1993-1996 Darren Reed"; */ ! 31: #endif ! 32: ! 33: #include "opt_ipfilter.h" ! 34: ! 35: #include <sys/errno.h> ! 36: #include <sys/types.h> ! 37: #include <sys/param.h> ! 38: #include <sys/time.h> ! 39: #include <sys/file.h> ! 40: #if !defined(__FreeBSD__) ! 41: # include <sys/ioctl.h> ! 42: #endif ! 43: ! 44: # include <sys/systm.h> ! 45: ! 46: #include <sys/uio.h> ! 47: #if !defined(__SVR4) && !defined(__svr4__) ! 48: # ifndef linux ! 49: # include <sys/mbuf.h> ! 50: # endif ! 51: #else ! 52: # include <sys/byteorder.h> ! 53: # include <sys/dditypes.h> ! 54: # include <sys/stream.h> ! 55: #endif ! 56: #if defined(__FreeBSD__) ! 57: # include <sys/malloc.h> ! 58: #endif ! 59: #ifndef linux ! 60: # include <sys/protosw.h> ! 61: # include <sys/socket.h> ! 62: #endif ! 63: #include <net/if.h> ! 64: #ifdef sun ! 65: # include <net/af.h> ! 66: #endif ! 67: #include <net/route.h> ! 68: #include <netinet/in.h> ! 69: #include <netinet/in_systm.h> ! 70: #include <netinet/ip.h> ! 71: #ifndef linux ! 72: # include <netinet/ip_var.h> ! 73: #endif ! 74: #include <netinet/tcp.h> ! 75: #include <netinet/udp.h> ! 76: #include <netinet/ip_icmp.h> ! 77: #include "netinet/ip_compat.h" ! 78: #include <netinet/tcpip.h> ! 79: #include "netinet/ip_fil.h" ! 80: #include "netinet/ip_proxy.h" ! 81: #include "netinet/ip_nat.h" ! 82: #include "netinet/ip_frag.h" ! 83: #include "netinet/ip_state.h" ! 84: #include "netinet/ip_auth.h" ! 85: #ifndef MIN ! 86: #define MIN(a,b) (((a)<(b))?(a):(b)) ! 87: #endif ! 88: ! 89: #ifndef KERNEL ! 90: # include "ipf.h" ! 91: # include "ipt.h" ! 92: extern int opts; ! 93: ! 94: # define FR_IFVERBOSE(ex,second,verb_pr) if (ex) { verbose verb_pr; \ ! 95: second; } ! 96: # define FR_IFDEBUG(ex,second,verb_pr) if (ex) { debug verb_pr; \ ! 97: second; } ! 98: # define FR_VERBOSE(verb_pr) verbose verb_pr ! 99: # define FR_DEBUG(verb_pr) debug verb_pr ! 100: # define SEND_RESET(ip, qif, if, m) send_reset(ip, if) ! 101: # define IPLLOG(a, c, d, e) ipllog() ! 102: # define FR_NEWAUTH(m, fi, ip, qif) fr_newauth((mb_t *)m, fi, ip) ! 103: # if SOLARIS ! 104: # define ICMP_ERROR(b, ip, t, c, if, src) icmp_error(ip) ! 105: # else ! 106: # define ICMP_ERROR(b, ip, t, c, if, src) icmp_error(b, ip, if) ! 107: # endif ! 108: #else /* #ifndef KERNEL */ ! 109: # define FR_IFVERBOSE(ex,second,verb_pr) ; ! 110: # define FR_IFDEBUG(ex,second,verb_pr) ; ! 111: # define FR_VERBOSE(verb_pr) ! 112: # define FR_DEBUG(verb_pr) ! 113: # define IPLLOG(a, c, d, e) ipflog(a, c, d, e) ! 114: # if SOLARIS || defined(__sgi) ! 115: extern kmutex_t ipf_mutex, ipf_auth; ! 116: # endif ! 117: # if SOLARIS ! 118: # define FR_NEWAUTH(m, fi, ip, qif) fr_newauth((mb_t *)m, fi, \ ! 119: ip, qif) ! 120: # define SEND_RESET(ip, qif, if) send_reset(ip, qif) ! 121: # define ICMP_ERROR(b, ip, t, c, if, src) \ ! 122: icmp_error(ip, t, c, if, src) ! 123: # else /* SOLARIS */ ! 124: # define FR_NEWAUTH(m, fi, ip, qif) fr_newauth((mb_t *)m, fi, ip) ! 125: # ifdef linux ! 126: # define SEND_RESET(ip, qif, if) send_reset((tcpiphdr_t *)ip,\ ! 127: ifp) ! 128: # else ! 129: # define SEND_RESET(ip, qif, if) send_reset((tcpiphdr_t *)ip) ! 130: # endif ! 131: # ifdef __sgi ! 132: # define ICMP_ERROR(b, ip, t, c, if, src) \ ! 133: icmp_error(b, t, c, if, src, if) ! 134: # else ! 135: # if BSD < 199103 ! 136: # ifdef linux ! 137: # define ICMP_ERROR(b, ip, t, c, if, src) icmp_send(b,t,c,0,if) ! 138: # else ! 139: # define ICMP_ERROR(b, ip, t, c, if, src) \ ! 140: icmp_error(mtod(b, ip_t *), t, c, if, src) ! 141: # endif /* linux */ ! 142: # else ! 143: # define ICMP_ERROR(b, ip, t, c, if, src) \ ! 144: icmp_error(b, t, c, (src).s_addr, if) ! 145: # endif /* BSD < 199103 */ ! 146: # endif /* __sgi */ ! 147: # endif /* SOLARIS || __sgi */ ! 148: #endif /* KERNEL */ ! 149: ! 150: ! 151: struct filterstats frstats[2] = {{0,0,0,0,0},{0,0,0,0,0}}; ! 152: struct frentry *ipfilter[2][2] = { { NULL, NULL }, { NULL, NULL } }, ! 153: *ipacct[2][2] = { { NULL, NULL }, { NULL, NULL } }; ! 154: struct frgroup *ipfgroups[3][2]; ! 155: int fr_flags = IPF_LOGGING, fr_active = 0; ! 156: #if defined(IPFILTER_DEFAULT_BLOCK) ! 157: int fr_pass = FR_NOMATCH|FR_BLOCK; ! 158: #else ! 159: int fr_pass = (IPF_DEFAULT_PASS|FR_NOMATCH); ! 160: #endif ! 161: ! 162: fr_info_t frcache[2]; ! 163: ! 164: static void fr_makefrip __P((int, ip_t *, fr_info_t *)); ! 165: static int fr_tcpudpchk __P((frentry_t *, fr_info_t *)); ! 166: static int frflushlist __P((int, int, int *, frentry_t *, frentry_t **)); ! 167: ! 168: ! 169: /* ! 170: * bit values for identifying presence of individual IP options ! 171: */ ! 172: static struct optlist ipopts[20] = { ! 173: { IPOPT_NOP, 0x000001 }, ! 174: { IPOPT_RR, 0x000002 }, ! 175: { IPOPT_ZSU, 0x000004 }, ! 176: { IPOPT_MTUP, 0x000008 }, ! 177: { IPOPT_MTUR, 0x000010 }, ! 178: { IPOPT_ENCODE, 0x000020 }, ! 179: { IPOPT_TS, 0x000040 }, ! 180: { IPOPT_TR, 0x000080 }, ! 181: { IPOPT_SECURITY, 0x000100 }, ! 182: { IPOPT_LSRR, 0x000200 }, ! 183: { IPOPT_E_SEC, 0x000400 }, ! 184: { IPOPT_CIPSO, 0x000800 }, ! 185: { IPOPT_SATID, 0x001000 }, ! 186: { IPOPT_SSRR, 0x002000 }, ! 187: { IPOPT_ADDEXT, 0x004000 }, ! 188: { IPOPT_VISA, 0x008000 }, ! 189: { IPOPT_IMITD, 0x010000 }, ! 190: { IPOPT_EIP, 0x020000 }, ! 191: { IPOPT_FINN, 0x040000 }, ! 192: { 0, 0x000000 } ! 193: }; ! 194: ! 195: /* ! 196: * bit values for identifying presence of individual IP security options ! 197: */ ! 198: static struct optlist secopt[8] = { ! 199: { IPSO_CLASS_RES4, 0x01 }, ! 200: { IPSO_CLASS_TOPS, 0x02 }, ! 201: { IPSO_CLASS_SECR, 0x04 }, ! 202: { IPSO_CLASS_RES3, 0x08 }, ! 203: { IPSO_CLASS_CONF, 0x10 }, ! 204: { IPSO_CLASS_UNCL, 0x20 }, ! 205: { IPSO_CLASS_RES2, 0x40 }, ! 206: { IPSO_CLASS_RES1, 0x80 } ! 207: }; ! 208: ! 209: ! 210: /* ! 211: * compact the IP header into a structure which contains just the info. ! 212: * which is useful for comparing IP headers with. ! 213: */ ! 214: static void fr_makefrip(hlen, ip, fin) ! 215: int hlen; ! 216: ip_t *ip; ! 217: fr_info_t *fin; ! 218: { ! 219: struct optlist *op; ! 220: tcphdr_t *tcp; ! 221: icmphdr_t *icmp; ! 222: fr_ip_t *fi = &fin->fin_fi; ! 223: u_short optmsk = 0, secmsk = 0, auth = 0; ! 224: int i, mv, ol, off; ! 225: u_char *s, opt; ! 226: ! 227: fin->fin_fr = NULL; ! 228: fin->fin_tcpf = 0; ! 229: fin->fin_data[0] = 0; ! 230: fin->fin_data[1] = 0; ! 231: fin->fin_rule = -1; ! 232: fin->fin_group = -1; ! 233: fin->fin_id = ip->ip_id; ! 234: #ifdef KERNEL ! 235: fin->fin_icode = ipl_unreach; ! 236: #endif ! 237: fi->fi_v = ip->ip_v; ! 238: fi->fi_tos = ip->ip_tos; ! 239: fin->fin_hlen = hlen; ! 240: fin->fin_dlen = ip->ip_len - hlen; ! 241: tcp = (tcphdr_t *)((char *)ip + hlen); ! 242: icmp = (icmphdr_t *)tcp; ! 243: fin->fin_dp = (void *)tcp; ! 244: (*(((u_short *)fi) + 1)) = (*(((u_short *)ip) + 4)); ! 245: (*(((u_32_t *)fi) + 1)) = (*(((u_32_t *)ip) + 3)); ! 246: (*(((u_32_t *)fi) + 2)) = (*(((u_32_t *)ip) + 4)); ! 247: ! 248: fi->fi_fl = (hlen > sizeof(ip_t)) ? FI_OPTIONS : 0; ! 249: off = (ip->ip_off & 0x1fff) << 3; ! 250: if (ip->ip_off & 0x3fff) ! 251: fi->fi_fl |= FI_FRAG; ! 252: switch (ip->ip_p) ! 253: { ! 254: case IPPROTO_ICMP : ! 255: { ! 256: int minicmpsz = sizeof(struct icmp); ! 257: ! 258: if (!off && ip->ip_len > ICMP_MINLEN + hlen && ! 259: (icmp->icmp_type == ICMP_ECHOREPLY || ! 260: icmp->icmp_type == ICMP_UNREACH)) ! 261: minicmpsz = ICMP_MINLEN; ! 262: if ((!(ip->ip_len >= hlen + minicmpsz) && !off) || ! 263: (off && off < sizeof(struct icmp))) ! 264: fi->fi_fl |= FI_SHORT; ! 265: if (fin->fin_dlen > 1) ! 266: fin->fin_data[0] = *(u_short *)tcp; ! 267: break; ! 268: } ! 269: case IPPROTO_TCP : ! 270: fi->fi_fl |= FI_TCPUDP; ! 271: if ((!IPMINLEN(ip, tcphdr) && !off) || ! 272: (off && off < sizeof(struct tcphdr))) ! 273: fi->fi_fl |= FI_SHORT; ! 274: if (!(fi->fi_fl & FI_SHORT) && !off) ! 275: fin->fin_tcpf = tcp->th_flags; ! 276: goto getports; ! 277: case IPPROTO_UDP : ! 278: fi->fi_fl |= FI_TCPUDP; ! 279: if ((!IPMINLEN(ip, udphdr) && !off) || ! 280: (off && off < sizeof(struct udphdr))) ! 281: fi->fi_fl |= FI_SHORT; ! 282: getports: ! 283: if (!off && (fin->fin_dlen > 3)) { ! 284: fin->fin_data[0] = ntohs(tcp->th_sport); ! 285: fin->fin_data[1] = ntohs(tcp->th_dport); ! 286: } ! 287: break; ! 288: default : ! 289: break; ! 290: } ! 291: ! 292: ! 293: for (s = (u_char *)(ip + 1), hlen -= sizeof(*ip); hlen; ) { ! 294: if (!(opt = *s)) ! 295: break; ! 296: ol = (opt == IPOPT_NOP) ? 1 : (int)*(s+1); ! 297: if (opt > 1 && (ol < 2 || ol > hlen)) ! 298: break; ! 299: for (i = 9, mv = 4; mv >= 0; ) { ! 300: op = ipopts + i; ! 301: if (opt == (u_char)op->ol_val) { ! 302: optmsk |= op->ol_bit; ! 303: if (opt == IPOPT_SECURITY) { ! 304: struct optlist *sp; ! 305: u_char sec; ! 306: int j, m; ! 307: ! 308: sec = *(s + 2); /* classification */ ! 309: for (j = 3, m = 2; m >= 0; ) { ! 310: sp = secopt + j; ! 311: if (sec == sp->ol_val) { ! 312: secmsk |= sp->ol_bit; ! 313: auth = *(s + 3); ! 314: auth *= 256; ! 315: auth += *(s + 4); ! 316: break; ! 317: } ! 318: if (sec < sp->ol_val) ! 319: j -= m--; ! 320: else ! 321: j += m--; ! 322: } ! 323: } ! 324: break; ! 325: } ! 326: if (opt < op->ol_val) ! 327: i -= mv--; ! 328: else ! 329: i += mv--; ! 330: } ! 331: hlen -= ol; ! 332: s += ol; ! 333: } ! 334: if (auth && !(auth & 0x0100)) ! 335: auth &= 0xff00; ! 336: fi->fi_optmsk = optmsk; ! 337: fi->fi_secmsk = secmsk; ! 338: fi->fi_auth = auth; ! 339: } ! 340: ! 341: ! 342: /* ! 343: * check an IP packet for TCP/UDP characteristics such as ports and flags. ! 344: */ ! 345: static int fr_tcpudpchk(fr, fin) ! 346: frentry_t *fr; ! 347: fr_info_t *fin; ! 348: { ! 349: register u_short po, tup; ! 350: register char i; ! 351: register int err = 1; ! 352: ! 353: /* ! 354: * Both ports should *always* be in the first fragment. ! 355: * So far, I cannot find any cases where they can not be. ! 356: * ! 357: * compare destination ports ! 358: */ ! 359: if ((i = (int)fr->fr_dcmp)) { ! 360: po = fr->fr_dport; ! 361: tup = fin->fin_data[1]; ! 362: /* ! 363: * Do opposite test to that required and ! 364: * continue if that succeeds. ! 365: */ ! 366: if (!--i && tup != po) /* EQUAL */ ! 367: err = 0; ! 368: else if (!--i && tup == po) /* NOTEQUAL */ ! 369: err = 0; ! 370: else if (!--i && tup >= po) /* LESSTHAN */ ! 371: err = 0; ! 372: else if (!--i && tup <= po) /* GREATERTHAN */ ! 373: err = 0; ! 374: else if (!--i && tup > po) /* LT or EQ */ ! 375: err = 0; ! 376: else if (!--i && tup < po) /* GT or EQ */ ! 377: err = 0; ! 378: else if (!--i && /* Out of range */ ! 379: (tup >= po && tup <= fr->fr_dtop)) ! 380: err = 0; ! 381: else if (!--i && /* In range */ ! 382: (tup <= po || tup >= fr->fr_dtop)) ! 383: err = 0; ! 384: } ! 385: /* ! 386: * compare source ports ! 387: */ ! 388: if (err && (i = (int)fr->fr_scmp)) { ! 389: po = fr->fr_sport; ! 390: tup = fin->fin_data[0]; ! 391: if (!--i && tup != po) ! 392: err = 0; ! 393: else if (!--i && tup == po) ! 394: err = 0; ! 395: else if (!--i && tup >= po) ! 396: err = 0; ! 397: else if (!--i && tup <= po) ! 398: err = 0; ! 399: else if (!--i && tup > po) ! 400: err = 0; ! 401: else if (!--i && tup < po) ! 402: err = 0; ! 403: else if (!--i && /* Out of range */ ! 404: (tup >= po && tup <= fr->fr_stop)) ! 405: err = 0; ! 406: else if (!--i && /* In range */ ! 407: (tup <= po || tup >= fr->fr_stop)) ! 408: err = 0; ! 409: } ! 410: ! 411: /* ! 412: * If we don't have all the TCP/UDP header, then how can we ! 413: * expect to do any sort of match on it ? If we were looking for ! 414: * TCP flags, then NO match. If not, then match (which should ! 415: * satisfy the "short" class too). ! 416: */ ! 417: if (err && (fin->fin_fi.fi_p == IPPROTO_TCP)) { ! 418: if (fin->fin_fi.fi_fl & FI_SHORT) ! 419: return !(fr->fr_tcpf | fr->fr_tcpfm); ! 420: /* ! 421: * Match the flags ? If not, abort this match. ! 422: */ ! 423: if (fr->fr_tcpf && ! 424: fr->fr_tcpf != (fin->fin_tcpf & fr->fr_tcpfm)) { ! 425: FR_DEBUG(("f. %#x & %#x != %#x\n", fin->fin_tcpf, ! 426: fr->fr_tcpfm, fr->fr_tcpf)); ! 427: err = 0; ! 428: } ! 429: } ! 430: return err; ! 431: } ! 432: ! 433: /* ! 434: * Check the input/output list of rules for a match and result. ! 435: * Could be per interface, but this gets real nasty when you don't have ! 436: * kernel sauce. ! 437: */ ! 438: int fr_scanlist(pass, ip, fin, m) ! 439: int pass; ! 440: ip_t *ip; ! 441: register fr_info_t *fin; ! 442: void *m; ! 443: { ! 444: register struct frentry *fr; ! 445: register fr_ip_t *fi = &fin->fin_fi; ! 446: int rulen, portcmp = 0, off, skip = 0; ! 447: ! 448: fr = fin->fin_fr; ! 449: fin->fin_fr = NULL; ! 450: fin->fin_rule = 0; ! 451: fin->fin_group = 0; ! 452: off = ip->ip_off & 0x1fff; ! 453: pass |= (fi->fi_fl << 24); ! 454: ! 455: if ((fi->fi_fl & FI_TCPUDP) && (fin->fin_dlen > 3) && !off) ! 456: portcmp = 1; ! 457: ! 458: for (rulen = 0; fr; fr = fr->fr_next, rulen++) { ! 459: if (skip) { ! 460: skip--; ! 461: continue; ! 462: } ! 463: /* ! 464: * In all checks below, a null (zero) value in the ! 465: * filter struture is taken to mean a wildcard. ! 466: * ! 467: * check that we are working for the right interface ! 468: */ ! 469: #ifdef KERNEL ! 470: if (fr->fr_ifa && fr->fr_ifa != fin->fin_ifp) ! 471: continue; ! 472: #else ! 473: if (opts & (OPT_VERBOSE|OPT_DEBUG)) ! 474: printf("\n"); ! 475: FR_VERBOSE(("%c", (pass & FR_PASS) ? 'p' : ! 476: (pass & FR_AUTH) ? 'a' : 'b')); ! 477: if (fr->fr_ifa && fr->fr_ifa != fin->fin_ifp) ! 478: continue; ! 479: FR_VERBOSE((":i")); ! 480: #endif ! 481: { ! 482: register u_32_t *ld, *lm, *lip; ! 483: register int i; ! 484: ! 485: lip = (u_32_t *)fi; ! 486: lm = (u_32_t *)&fr->fr_mip; ! 487: ld = (u_32_t *)&fr->fr_ip; ! 488: i = ((lip[0] & lm[0]) != ld[0]); ! 489: FR_IFDEBUG(i,continue,("0. %#08x & %#08x != %#08x\n", ! 490: lip[0], lm[0], ld[0])); ! 491: i |= ((lip[1] & lm[1]) != ld[1]) << 21; ! 492: FR_IFDEBUG(i,continue,("1. %#08x & %#08x != %#08x\n", ! 493: lip[1], lm[1], ld[1])); ! 494: i |= ((lip[2] & lm[2]) != ld[2]) << 22; ! 495: FR_IFDEBUG(i,continue,("2. %#08x & %#08x != %#08x\n", ! 496: lip[2], lm[2], ld[2])); ! 497: i |= ((lip[3] & lm[3]) != ld[3]); ! 498: FR_IFDEBUG(i,continue,("3. %#08x & %#08x != %#08x\n", ! 499: lip[3], lm[3], ld[3])); ! 500: i |= ((lip[4] & lm[4]) != ld[4]); ! 501: FR_IFDEBUG(i,continue,("4. %#08x & %#08x != %#08x\n", ! 502: lip[4], lm[4], ld[4])); ! 503: i ^= (fi->fi_fl & (FR_NOTSRCIP|FR_NOTDSTIP)); ! 504: if (i) ! 505: continue; ! 506: } ! 507: ! 508: /* ! 509: * If a fragment, then only the first has what we're looking ! 510: * for here... ! 511: */ ! 512: if (!portcmp && (fr->fr_dcmp || fr->fr_scmp || fr->fr_tcpf || ! 513: fr->fr_tcpfm)) ! 514: continue; ! 515: if (fi->fi_fl & FI_TCPUDP) { ! 516: if (!fr_tcpudpchk(fr, fin)) ! 517: continue; ! 518: } else if (fr->fr_icmpm || fr->fr_icmp) { ! 519: if ((fi->fi_p != IPPROTO_ICMP) || off || ! 520: (fin->fin_dlen < 2)) ! 521: continue; ! 522: if ((fin->fin_data[0] & fr->fr_icmpm) != fr->fr_icmp) { ! 523: FR_DEBUG(("i. %#x & %#x != %#x\n", ! 524: fin->fin_data[0], fr->fr_icmpm, ! 525: fr->fr_icmp)); ! 526: continue; ! 527: } ! 528: } ! 529: FR_VERBOSE(("*")); ! 530: /* ! 531: * Just log this packet... ! 532: */ ! 533: if (!(skip = fr->fr_skip)) ! 534: pass = fr->fr_flags; ! 535: if ((pass & FR_CALLNOW) && fr->fr_func) ! 536: pass = (*fr->fr_func)(pass, ip, fin); ! 537: #if IPFILTER_LOG ! 538: if ((pass & FR_LOGMASK) == FR_LOG) { ! 539: if (!IPLLOG(fr->fr_flags, ip, fin, m)) ! 540: frstats[fin->fin_out].fr_skip++; ! 541: frstats[fin->fin_out].fr_pkl++; ! 542: } ! 543: #endif /* IPFILTER_LOG */ ! 544: FR_DEBUG(("pass %#x\n", pass)); ! 545: fr->fr_hits++; ! 546: if (pass & FR_ACCOUNT) ! 547: fr->fr_bytes += (U_QUAD_T)ip->ip_len; ! 548: else ! 549: fin->fin_icode = fr->fr_icode; ! 550: fin->fin_rule = rulen; ! 551: fin->fin_group = fr->fr_group; ! 552: fin->fin_fr = fr; ! 553: if (fr->fr_grp) { ! 554: fin->fin_fr = fr->fr_grp; ! 555: pass = fr_scanlist(pass, ip, fin, m); ! 556: if (fin->fin_fr == NULL) { ! 557: fin->fin_rule = rulen; ! 558: fin->fin_group = fr->fr_group; ! 559: fin->fin_fr = fr; ! 560: } ! 561: } ! 562: if (pass & FR_QUICK) ! 563: break; ! 564: } ! 565: return pass; ! 566: } ! 567: ! 568: ! 569: /* ! 570: * frcheck - filter check ! 571: * check using source and destination addresses/pors in a packet whether ! 572: * or not to pass it on or not. ! 573: */ ! 574: int fr_check(ip, hlen, ifp, out ! 575: #if defined(KERNEL) && SOLARIS ! 576: , qif, mp) ! 577: qif_t *qif; ! 578: #else ! 579: , mp) ! 580: #endif ! 581: mb_t **mp; ! 582: ip_t *ip; ! 583: int hlen; ! 584: void *ifp; ! 585: int out; ! 586: { ! 587: /* ! 588: * The above is really bad, but short of writing a diff ! 589: */ ! 590: fr_info_t frinfo, *fc; ! 591: register fr_info_t *fin = &frinfo; ! 592: frentry_t *fr = NULL; ! 593: int pass, changed, apass, error = EHOSTUNREACH; ! 594: #if !SOLARIS || !defined(KERNEL) ! 595: register mb_t *m = *mp; ! 596: #endif ! 597: ! 598: #if KERNEL ! 599: mb_t *mc = NULL; ! 600: # if !defined(__SVR4) && !defined(__svr4__) ! 601: # ifdef __sgi ! 602: char hbuf[(0xf << 2) + sizeof(struct icmp) + sizeof(ip_t) + 8]; ! 603: # endif ! 604: int up; ! 605: ! 606: #if M_CANFASTFWD ! 607: /* ! 608: * XXX For now, IP Filter and fast-forwarding of cached flows ! 609: * XXX are mutually exclusive. Eventually, IP Filter should ! 610: * XXX get a "can-fast-forward" filter rule. ! 611: */ ! 612: m->m_flags &= ~M_CANFASTFWD; ! 613: #endif /* M_CANFASTFWD */ ! 614: ! 615: if ((ip->ip_p == IPPROTO_TCP || ip->ip_p == IPPROTO_UDP || ! 616: ip->ip_p == IPPROTO_ICMP)) { ! 617: int plen = 0; ! 618: ! 619: switch(ip->ip_p) ! 620: { ! 621: case IPPROTO_TCP: ! 622: plen = sizeof(tcphdr_t); ! 623: break; ! 624: case IPPROTO_UDP: ! 625: plen = sizeof(udphdr_t); ! 626: break; ! 627: case IPPROTO_ICMP: ! 628: /* 96 - enough for complete ICMP error IP header */ ! 629: plen = sizeof(struct icmp) + sizeof(ip_t) + 8; ! 630: break; ! 631: } ! 632: up = MIN(hlen + plen, ip->ip_len); ! 633: ! 634: if (up > m->m_len) { ! 635: #ifdef __sgi /* Under IRIX, avoid m_pullup as it makes ping <hostname> panic */ ! 636: if ((up > sizeof(hbuf)) || (m_length(m) < up)) { ! 637: frstats[out].fr_pull[1]++; ! 638: return -1; ! 639: } ! 640: m_copydata(m, 0, up, hbuf); ! 641: frstats[out].fr_pull[0]++; ! 642: ip = (ip_t *)hbuf; ! 643: #else ! 644: # ifndef linux ! 645: if ((*mp = m_pullup(m, up)) == 0) { ! 646: frstats[out].fr_pull[1]++; ! 647: return -1; ! 648: } else { ! 649: frstats[out].fr_pull[0]++; ! 650: m = *mp; ! 651: ip = mtod(m, ip_t *); ! 652: } ! 653: # endif ! 654: #endif ! 655: } else ! 656: up = 0; ! 657: } else ! 658: up = 0; ! 659: # endif ! 660: # if SOLARIS ! 661: mb_t *m = qif->qf_m; ! 662: # endif ! 663: #endif ! 664: fr_makefrip(hlen, ip, fin); ! 665: fin->fin_ifp = ifp; ! 666: fin->fin_out = out; ! 667: fin->fin_mp = mp; ! 668: ! 669: MUTEX_ENTER(&ipf_mutex); ! 670: ! 671: /* ! 672: * Check auth now. This, combined with the check below to see if apass ! 673: * is 0 is to ensure that we don't count the packet twice, which can ! 674: * otherwise occur when we reprocess it. As it is, we only count it ! 675: * after it has no auth. table matchup. This also stops NAT from ! 676: * occuring until after the packet has been auth'd. ! 677: */ ! 678: apass = fr_checkauth(ip, fin); ! 679: ! 680: if (!out) { ! 681: changed = ip_natin(ip, hlen, fin); ! 682: if (!apass && (fin->fin_fr = ipacct[0][fr_active]) && ! 683: (FR_SCANLIST(FR_NOMATCH, ip, fin, m) & FR_ACCOUNT)) ! 684: frstats[0].fr_acct++; ! 685: } ! 686: ! 687: if (apass || (!(pass = ipfr_knownfrag(ip, fin)) && ! 688: !(pass = fr_checkstate(ip, fin)))) { ! 689: /* ! 690: * If a packet is found in the auth table, then skip checking ! 691: * the access lists for permission but we do need to consider ! 692: * the result as if it were from the ACL's. ! 693: */ ! 694: if (!apass) { ! 695: fc = frcache + out; ! 696: if (!bcmp((char *)fin, (char *)fc, FI_CSIZE)) { ! 697: /* ! 698: * copy cached data so we can unlock the mutex ! 699: * earlier. ! 700: */ ! 701: bcopy((char *)fc, (char *)fin, FI_COPYSIZE); ! 702: frstats[out].fr_chit++; ! 703: if ((fr = fin->fin_fr)) { ! 704: fr->fr_hits++; ! 705: pass = fr->fr_flags; ! 706: } else ! 707: pass = fr_pass; ! 708: } else { ! 709: pass = fr_pass; ! 710: if ((fin->fin_fr = ipfilter[out][fr_active])) ! 711: pass = FR_SCANLIST(fr_pass, ip, fin, m); ! 712: bcopy((char *)fin, (char *)fc, FI_COPYSIZE); ! 713: if (pass & FR_NOMATCH) ! 714: frstats[out].fr_nom++; ! 715: } ! 716: fr = fin->fin_fr; ! 717: } else ! 718: pass = apass; ! 719: ! 720: /* ! 721: * If we fail to add a packet to the authorization queue, ! 722: * then we drop the packet later. However, if it was added ! 723: * then pretend we've dropped it already. ! 724: */ ! 725: if ((pass & FR_AUTH)) ! 726: if (FR_NEWAUTH(m, fin, ip, qif) != 0) ! 727: #ifdef KERNEL ! 728: m = *mp = NULL; ! 729: #else ! 730: ; ! 731: #endif ! 732: ! 733: if (pass & FR_PREAUTH) { ! 734: MUTEX_ENTER(&ipf_auth); ! 735: if ((fin->fin_fr = ipauth) && ! 736: (pass = FR_SCANLIST(0, ip, fin, m))) ! 737: fr_authstats.fas_hits++; ! 738: else ! 739: fr_authstats.fas_miss++; ! 740: MUTEX_EXIT(&ipf_auth); ! 741: } ! 742: ! 743: if (pass & FR_KEEPFRAG) { ! 744: if (fin->fin_fi.fi_fl & FI_FRAG) { ! 745: if (ipfr_newfrag(ip, fin, pass) == -1) ! 746: frstats[out].fr_bnfr++; ! 747: else ! 748: frstats[out].fr_nfr++; ! 749: } else ! 750: frstats[out].fr_cfr++; ! 751: } ! 752: if (pass & FR_KEEPSTATE) { ! 753: if (fr_addstate(ip, fin, pass) == -1) ! 754: frstats[out].fr_bads++; ! 755: else ! 756: frstats[out].fr_ads++; ! 757: } ! 758: } ! 759: ! 760: if (fr && fr->fr_func && !(pass & FR_CALLNOW)) ! 761: pass = (*fr->fr_func)(pass, ip, fin); ! 762: ! 763: /* ! 764: * Only count/translate packets which will be passed on, out the ! 765: * interface. ! 766: */ ! 767: if (out && (pass & FR_PASS)) { ! 768: if ((fin->fin_fr = ipacct[1][fr_active]) && ! 769: (FR_SCANLIST(FR_NOMATCH, ip, fin, m) & FR_ACCOUNT)) ! 770: frstats[1].fr_acct++; ! 771: fin->fin_fr = NULL; ! 772: changed = ip_natout(ip, hlen, fin); ! 773: } ! 774: fin->fin_fr = fr; ! 775: MUTEX_EXIT(&ipf_mutex); ! 776: ! 777: #if IPFILTER_LOG ! 778: if ((fr_flags & FF_LOGGING) || (pass & FR_LOGMASK)) { ! 779: if ((fr_flags & FF_LOGNOMATCH) && (pass & FR_NOMATCH)) { ! 780: pass |= FF_LOGNOMATCH; ! 781: frstats[out].fr_npkl++; ! 782: goto logit; ! 783: } else if (((pass & FR_LOGMASK) == FR_LOGP) || ! 784: ((pass & FR_PASS) && (fr_flags & FF_LOGPASS))) { ! 785: if ((pass & FR_LOGMASK) != FR_LOGP) ! 786: pass |= FF_LOGPASS; ! 787: frstats[out].fr_ppkl++; ! 788: goto logit; ! 789: } else if (((pass & FR_LOGMASK) == FR_LOGB) || ! 790: ((pass & FR_BLOCK) && (fr_flags & FF_LOGBLOCK))) { ! 791: if ((pass & FR_LOGMASK) != FR_LOGB) ! 792: pass |= FF_LOGBLOCK; ! 793: frstats[out].fr_bpkl++; ! 794: logit: ! 795: if (!IPLLOG(pass, ip, fin, m)) { ! 796: frstats[out].fr_skip++; ! 797: if ((pass & (FR_PASS|FR_LOGORBLOCK)) == ! 798: (FR_PASS|FR_LOGORBLOCK)) ! 799: pass ^= FR_PASS|FR_BLOCK; ! 800: } ! 801: } ! 802: } ! 803: #endif /* IPFILTER_LOG */ ! 804: #ifdef KERNEL ! 805: /* ! 806: * Only allow FR_DUP to work if a rule matched - it makes no sense to ! 807: * set FR_DUP as a "default" as there are no instructions about where ! 808: * to send the packet. ! 809: */ ! 810: if (fr && (pass & FR_DUP)) ! 811: # if SOLARIS ! 812: mc = dupmsg(m); ! 813: # else ! 814: # ifndef linux ! 815: mc = m_copy(m, 0, M_COPYALL); ! 816: # else ! 817: ; ! 818: # endif ! 819: # endif ! 820: #endif ! 821: if (pass & FR_PASS) ! 822: frstats[out].fr_pass++; ! 823: else if (pass & FR_BLOCK) { ! 824: frstats[out].fr_block++; ! 825: /* ! 826: * Should we return an ICMP packet to indicate error ! 827: * status passing through the packet filter ? ! 828: * WARNING: ICMP error packets AND TCP RST packets should ! 829: * ONLY be sent in repsonse to incoming packets. Sending them ! 830: * in response to outbound packets can result in a panic on ! 831: * some operating systems. ! 832: */ ! 833: if (!out) { ! 834: #ifdef KERNEL ! 835: if (pass & FR_RETICMP) { ! 836: # if SOLARIS ! 837: ICMP_ERROR(q, ip, ICMP_UNREACH, fin->fin_icode, ! 838: qif, ip->ip_src); ! 839: # else ! 840: ICMP_ERROR(m, ip, ICMP_UNREACH, fin->fin_icode, ! 841: ifp, ip->ip_src); ! 842: m = *mp = NULL; /* freed by icmp_error() */ ! 843: # endif ! 844: ! 845: frstats[0].fr_ret++; ! 846: } else if ((pass & FR_RETRST) && ! 847: !(fin->fin_fi.fi_fl & FI_SHORT)) { ! 848: if (SEND_RESET(ip, qif, ifp) == 0) ! 849: frstats[1].fr_ret++; ! 850: } ! 851: #else ! 852: if (pass & FR_RETICMP) { ! 853: verbose("- ICMP unreachable sent\n"); ! 854: frstats[0].fr_ret++; ! 855: } else if ((pass & FR_RETRST) && ! 856: !(fin->fin_fi.fi_fl & FI_SHORT)) { ! 857: verbose("- TCP RST sent\n"); ! 858: frstats[1].fr_ret++; ! 859: } ! 860: #endif ! 861: } else { ! 862: if (pass & FR_RETRST) ! 863: error = ECONNRESET; ! 864: } ! 865: } ! 866: ! 867: /* ! 868: * If we didn't drop off the bottom of the list of rules (and thus ! 869: * the 'current' rule fr is not NULL), then we may have some extra ! 870: * instructions about what to do with a packet. ! 871: * Once we're finished return to our caller, freeing the packet if ! 872: * we are dropping it (* BSD ONLY *). ! 873: */ ! 874: #if defined(KERNEL) ! 875: # if !SOLARIS ! 876: # if !defined(linux) ! 877: if (fr) { ! 878: frdest_t *fdp = &fr->fr_tif; ! 879: ! 880: if ((pass & FR_FASTROUTE) || ! 881: (fdp->fd_ifp && fdp->fd_ifp != (struct ifnet *)-1)) { ! 882: ipfr_fastroute(m, fin, fdp); ! 883: m = *mp = NULL; ! 884: } ! 885: if (mc) ! 886: ipfr_fastroute(mc, fin, &fr->fr_dif); ! 887: } ! 888: if (!(pass & FR_PASS) && m) ! 889: m_freem(m); ! 890: # ifdef __sgi ! 891: else if (changed && up && m) ! 892: m_copyback(m, 0, up, hbuf); ! 893: # endif ! 894: # endif /* !linux */ ! 895: return (pass & FR_PASS) ? 0 : error; ! 896: # else /* !SOLARIS */ ! 897: if (fr) { ! 898: frdest_t *fdp = &fr->fr_tif; ! 899: ! 900: if ((pass & FR_FASTROUTE) || ! 901: (fdp->fd_ifp && fdp->fd_ifp != (struct ifnet *)-1)) { ! 902: ipfr_fastroute(qif, ip, m, mp, fin, fdp); ! 903: m = *mp = NULL; ! 904: } ! 905: if (mc) ! 906: ipfr_fastroute(qif, ip, mc, mp, fin, &fr->fr_dif); ! 907: } ! 908: return (pass & FR_PASS) ? changed : error; ! 909: # endif /* !SOLARIS */ ! 910: #else /* KERNEL */ ! 911: if (pass & FR_NOMATCH) ! 912: return 1; ! 913: if (pass & FR_PASS) ! 914: return 0; ! 915: if (pass & FR_AUTH) ! 916: return -2; ! 917: return -1; ! 918: #endif /* KERNEL */ ! 919: } ! 920: ! 921: ! 922: /* ! 923: * ipf_cksum ! 924: * addr should be 16bit aligned and len is in bytes. ! 925: * length is in bytes ! 926: */ ! 927: u_short ipf_cksum(addr, len) ! 928: register u_short *addr; ! 929: register int len; ! 930: { ! 931: register u_32_t sum = 0; ! 932: ! 933: for (sum = 0; len > 1; len -= 2) ! 934: sum += *addr++; ! 935: ! 936: /* mop up an odd byte, if necessary */ ! 937: if (len == 1) ! 938: sum += *(u_char *)addr; ! 939: ! 940: /* ! 941: * add back carry outs from top 16 bits to low 16 bits ! 942: */ ! 943: sum = (sum >> 16) + (sum & 0xffff); /* add hi 16 to low 16 */ ! 944: sum += (sum >> 16); /* add carry */ ! 945: return (u_short)(~sum); ! 946: } ! 947: ! 948: ! 949: /* ! 950: * NB: This function assumes we've pullup'd enough for all of the IP header ! 951: * and the TCP header. We also assume that data blocks aren't allocated in ! 952: * odd sizes. ! 953: */ ! 954: u_short fr_tcpsum(m, ip, tcp, len) ! 955: mb_t *m; ! 956: ip_t *ip; ! 957: tcphdr_t *tcp; ! 958: int len; ! 959: { ! 960: union { ! 961: u_char c[2]; ! 962: u_short s; ! 963: } bytes; ! 964: u_32_t sum; ! 965: u_short *sp; ! 966: # if SOLARIS || defined(__sgi) ! 967: int add, hlen; ! 968: # endif ! 969: ! 970: # if SOLARIS ! 971: /* skip any leading M_PROTOs */ ! 972: while(m && (MTYPE(m) != M_DATA)) ! 973: m = m->b_cont; ! 974: PANIC((!m),("fr_tcpsum: no M_DATA")); ! 975: # endif ! 976: ! 977: /* ! 978: * Add up IP Header portion ! 979: */ ! 980: bytes.c[0] = 0; ! 981: bytes.c[1] = IPPROTO_TCP; ! 982: len -= (ip->ip_hl << 2); ! 983: sum = bytes.s; ! 984: sum += htons((u_short)len); ! 985: sp = (u_short *)&ip->ip_src; ! 986: sum += *sp++; ! 987: sum += *sp++; ! 988: sum += *sp++; ! 989: sum += *sp++; ! 990: if (sp != (u_short *)tcp) ! 991: sp = (u_short *)tcp; ! 992: sum += *sp++; ! 993: sum += *sp++; ! 994: sum += *sp++; ! 995: sum += *sp++; ! 996: sum += *sp++; ! 997: sum += *sp++; ! 998: sum += *sp++; ! 999: sum += *sp; ! 1000: sp += 2; /* Skip over checksum */ ! 1001: sum += *sp++; ! 1002: ! 1003: #if SOLARIS ! 1004: /* ! 1005: * In case we had to copy the IP & TCP header out of mblks, ! 1006: * skip over the mblk bits which are the header ! 1007: */ ! 1008: if ((caddr_t)ip != (caddr_t)m->b_rptr) { ! 1009: hlen = (caddr_t)sp - (caddr_t)ip; ! 1010: while (hlen) { ! 1011: add = MIN(hlen, m->b_wptr - m->b_rptr); ! 1012: sp = (u_short *)((caddr_t)m->b_rptr + add); ! 1013: hlen -= add; ! 1014: if ((caddr_t)sp >= (caddr_t)m->b_wptr) { ! 1015: m = m->b_cont; ! 1016: PANIC((!m),("fr_tcpsum: not enough data")); ! 1017: if (!hlen) ! 1018: sp = (u_short *)m->b_rptr; ! 1019: } ! 1020: } ! 1021: } ! 1022: #endif ! 1023: #ifdef __sgi ! 1024: /* ! 1025: * In case we had to copy the IP & TCP header out of mbufs, ! 1026: * skip over the mbuf bits which are the header ! 1027: */ ! 1028: if ((caddr_t)ip != mtod(m, caddr_t)) { ! 1029: hlen = (caddr_t)sp - (caddr_t)ip; ! 1030: while (hlen) { ! 1031: add = MIN(hlen, m->m_len); ! 1032: sp = (u_short *)(mtod(m, caddr_t) + add); ! 1033: hlen -= add; ! 1034: if (add >= m->m_len) { ! 1035: m = m->m_next; ! 1036: PANIC((!m),("fr_tcpsum: not enough data")); ! 1037: if (!hlen) ! 1038: sp = mtod(m, u_short *); ! 1039: } ! 1040: } ! 1041: } ! 1042: #endif ! 1043: ! 1044: if (!(len -= sizeof(*tcp))) ! 1045: goto nodata; ! 1046: while (len > 0) { ! 1047: #if SOLARIS ! 1048: while ((caddr_t)sp >= (caddr_t)m->b_wptr) { ! 1049: m = m->b_cont; ! 1050: PANIC((!m),("fr_tcpsum: not enough data")); ! 1051: sp = (u_short *)m->b_rptr; ! 1052: } ! 1053: #else ! 1054: while (((caddr_t)sp - mtod(m, caddr_t)) >= m->m_len) ! 1055: { ! 1056: m = m->m_next; ! 1057: PANIC((!m),("fr_tcpsum: not enough data")); ! 1058: sp = mtod(m, u_short *); ! 1059: } ! 1060: #endif /* SOLARIS */ ! 1061: if (len < 2) ! 1062: break; ! 1063: if((u_32_t)sp & 1) { ! 1064: bcopy((char *)sp++, (char *)&bytes.s, sizeof(bytes.s)); ! 1065: sum += bytes.s; ! 1066: } else ! 1067: sum += *sp++; ! 1068: len -= 2; ! 1069: } ! 1070: if (len) { ! 1071: bytes.c[1] = 0; ! 1072: bytes.c[0] = *(u_char *)sp; ! 1073: sum += bytes.s; ! 1074: } ! 1075: nodata: ! 1076: sum = (sum >> 16) + (sum & 0xffff); ! 1077: sum += (sum >> 16); ! 1078: sum = (u_short)((~sum) & 0xffff); ! 1079: return sum; ! 1080: } ! 1081: ! 1082: ! 1083: #if defined(KERNEL) && ( ((BSD < 199306) && !SOLARIS) || defined(__sgi) ) ! 1084: /* ! 1085: * Copyright (c) 1982, 1986, 1988, 1991, 1993 ! 1086: * The Regents of the University of California. All rights reserved. ! 1087: * ! 1088: * Redistribution and use in source and binary forms, with or without ! 1089: * modification, are permitted provided that the following conditions ! 1090: * are met: ! 1091: * 1. Redistributions of source code must retain the above copyright ! 1092: * notice, this list of conditions and the following disclaimer. ! 1093: * 2. Redistributions in binary form must reproduce the above copyright ! 1094: * notice, this list of conditions and the following disclaimer in the ! 1095: * documentation and/or other materials provided with the distribution. ! 1096: * 3. All advertising materials mentioning features or use of this software ! 1097: * must display the following acknowledgement: ! 1098: * This product includes software developed by the University of ! 1099: * California, Berkeley and its contributors. ! 1100: * 4. Neither the name of the University nor the names of its contributors ! 1101: * may be used to endorse or promote products derived from this software ! 1102: * without specific prior written permission. ! 1103: * ! 1104: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ! 1105: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ! 1106: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ! 1107: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE ! 1108: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL ! 1109: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS ! 1110: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ! 1111: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT ! 1112: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY ! 1113: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF ! 1114: * SUCH DAMAGE. ! 1115: * ! 1116: * @(#)uipc_mbuf.c 8.2 (Berkeley) 1/4/94 ! 1117: */ ! 1118: /* ! 1119: * Copy data from an mbuf chain starting "off" bytes from the beginning, ! 1120: * continuing for "len" bytes, into the indicated buffer. ! 1121: */ ! 1122: void ! 1123: m_copydata(m, off, len, cp) ! 1124: register mb_t *m; ! 1125: register int off; ! 1126: register int len; ! 1127: caddr_t cp; ! 1128: { ! 1129: register unsigned count; ! 1130: ! 1131: if (off < 0 || len < 0) ! 1132: panic("m_copydata"); ! 1133: while (off > 0) { ! 1134: if (m == 0) ! 1135: panic("m_copydata"); ! 1136: if (off < m->m_len) ! 1137: break; ! 1138: off -= m->m_len; ! 1139: m = m->m_next; ! 1140: } ! 1141: while (len > 0) { ! 1142: if (m == 0) ! 1143: panic("m_copydata"); ! 1144: count = MIN(m->m_len - off, len); ! 1145: bcopy(mtod(m, caddr_t) + off, cp, count); ! 1146: len -= count; ! 1147: cp += count; ! 1148: off = 0; ! 1149: m = m->m_next; ! 1150: } ! 1151: } ! 1152: ! 1153: ! 1154: # ifndef linux ! 1155: /* ! 1156: * Copy data from a buffer back into the indicated mbuf chain, ! 1157: * starting "off" bytes from the beginning, extending the mbuf ! 1158: * chain if necessary. ! 1159: */ ! 1160: void ! 1161: m_copyback(m0, off, len, cp) ! 1162: struct mbuf *m0; ! 1163: register int off; ! 1164: register int len; ! 1165: caddr_t cp; ! 1166: { ! 1167: register int mlen; ! 1168: register struct mbuf *m = m0, *n; ! 1169: int totlen = 0; ! 1170: ! 1171: if (m0 == 0) ! 1172: return; ! 1173: while (off > (mlen = m->m_len)) { ! 1174: off -= mlen; ! 1175: totlen += mlen; ! 1176: if (m->m_next == 0) { ! 1177: n = m_getclr(M_DONTWAIT, m->m_type); ! 1178: if (n == 0) ! 1179: goto out; ! 1180: n->m_len = min(MLEN, len + off); ! 1181: m->m_next = n; ! 1182: } ! 1183: m = m->m_next; ! 1184: } ! 1185: while (len > 0) { ! 1186: mlen = min (m->m_len - off, len); ! 1187: bcopy(cp, off + mtod(m, caddr_t), (unsigned)mlen); ! 1188: cp += mlen; ! 1189: len -= mlen; ! 1190: mlen += off; ! 1191: off = 0; ! 1192: totlen += mlen; ! 1193: if (len == 0) ! 1194: break; ! 1195: if (m->m_next == 0) { ! 1196: n = m_get(M_DONTWAIT, m->m_type); ! 1197: if (n == 0) ! 1198: break; ! 1199: n->m_len = min(MLEN, len); ! 1200: m->m_next = n; ! 1201: } ! 1202: m = m->m_next; ! 1203: } ! 1204: out: ! 1205: #if 0 ! 1206: if (((m = m0)->m_flags & M_PKTHDR) && (m->m_pkthdr.len < totlen)) ! 1207: m->m_pkthdr.len = totlen; ! 1208: #endif ! 1209: return; ! 1210: } ! 1211: # endif /* linux */ ! 1212: #endif /* (KERNEL) && ( ((BSD < 199306) && !SOLARIS) || __sgi) */ ! 1213: ! 1214: ! 1215: frgroup_t *fr_findgroup(num, flags, which, set, fgpp) ! 1216: u_short num; ! 1217: u_32_t flags; ! 1218: int which, set; ! 1219: frgroup_t ***fgpp; ! 1220: { ! 1221: frgroup_t *fg, **fgp; ! 1222: ! 1223: if (which == IPL_LOGAUTH) ! 1224: fgp = &ipfgroups[2][set]; ! 1225: else if (flags & FR_ACCOUNT) ! 1226: fgp = &ipfgroups[1][set]; ! 1227: else if (flags & (FR_OUTQUE|FR_INQUE)) ! 1228: fgp = &ipfgroups[0][set]; ! 1229: else ! 1230: return NULL; ! 1231: ! 1232: while ((fg = *fgp)) ! 1233: if (fg->fg_num == num) ! 1234: break; ! 1235: else ! 1236: fgp = &fg->fg_next; ! 1237: if (fgpp) ! 1238: *fgpp = fgp; ! 1239: return fg; ! 1240: } ! 1241: ! 1242: ! 1243: frgroup_t *fr_addgroup(num, fp, which, set) ! 1244: u_short num; ! 1245: frentry_t *fp; ! 1246: int which, set; ! 1247: { ! 1248: frgroup_t *fg, **fgp; ! 1249: ! 1250: if ((fg = fr_findgroup(num, fp->fr_flags, which, set, &fgp))) ! 1251: return fg; ! 1252: ! 1253: KMALLOC(fg, frgroup_t *, sizeof(*fg)); ! 1254: if (fg) { ! 1255: fg->fg_num = num; ! 1256: fg->fg_next = *fgp; ! 1257: fg->fg_head = fp; ! 1258: fg->fg_start = &fp->fr_grp; ! 1259: *fgp = fg; ! 1260: } ! 1261: return fg; ! 1262: } ! 1263: ! 1264: ! 1265: void fr_delgroup(num, flags, which, set) ! 1266: u_short num; ! 1267: u_32_t flags; ! 1268: int which, set; ! 1269: { ! 1270: frgroup_t *fg, **fgp; ! 1271: ! 1272: if (!(fg = fr_findgroup(num, flags, which, set, &fgp))) ! 1273: return; ! 1274: ! 1275: *fgp = fg->fg_next; ! 1276: KFREE(fg); ! 1277: } ! 1278: ! 1279: ! 1280: ! 1281: /* ! 1282: * recursively flush rules from the list, descending groups as they are ! 1283: * encountered. if a rule is the head of a group and it has lost all its ! 1284: * group members, then also delete the group reference. ! 1285: */ ! 1286: static int frflushlist(set, unit, nfreedp, list, listp) ! 1287: int set, unit, *nfreedp; ! 1288: frentry_t *list, **listp; ! 1289: { ! 1290: register frentry_t *fp = list, *fpn; ! 1291: register int freed = 0; ! 1292: ! 1293: while (fp) { ! 1294: fpn = fp->fr_next; ! 1295: if (fp->fr_grp) { ! 1296: fp->fr_ref -= frflushlist(set, unit, nfreedp, ! 1297: fp->fr_grp, &fp->fr_grp); ! 1298: } ! 1299: ! 1300: if (fp->fr_ref == 1) { ! 1301: if (fp->fr_grhead) ! 1302: fr_delgroup(fp->fr_grhead, fp->fr_flags, unit, ! 1303: set); ! 1304: KFREE(fp); ! 1305: *listp = fpn; ! 1306: freed++; ! 1307: } ! 1308: fp = fpn; ! 1309: } ! 1310: *nfreedp += freed; ! 1311: return freed; ! 1312: } ! 1313: ! 1314: ! 1315: void frflush(unit, result) ! 1316: int unit; ! 1317: int *result; ! 1318: { ! 1319: int flags = *result, flushed = 0, set = fr_active; ! 1320: ! 1321: bzero((char *)frcache, sizeof(frcache[0]) * 2); ! 1322: ! 1323: if (flags & FR_INACTIVE) ! 1324: set = 1 - set; ! 1325: ! 1326: if (unit == IPL_LOGIPF) { ! 1327: if (flags & FR_OUTQUE) { ! 1328: (void) frflushlist(set, unit, &flushed, ! 1329: ipfilter[1][set], ! 1330: &ipfilter[1][set]); ! 1331: (void) frflushlist(set, unit, &flushed, ! 1332: ipacct[1][set], &ipacct[1][set]); ! 1333: } ! 1334: if (flags & FR_INQUE) { ! 1335: (void) frflushlist(set, unit, &flushed, ! 1336: ipfilter[0][set], ! 1337: &ipfilter[0][set]); ! 1338: (void) frflushlist(set, unit, &flushed, ! 1339: ipacct[0][set], &ipacct[0][set]); ! 1340: } ! 1341: } ! 1342: ! 1343: *result = flushed; ! 1344: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.