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