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