|
|
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.