ip_fil_freebsd.c revision 192895
1145516Sdarrenr/*	$FreeBSD: head/sys/contrib/ipfilter/netinet/ip_fil_freebsd.c 192895 2009-05-27 14:11:23Z jamie $	*/
2145516Sdarrenr
3145516Sdarrenr/*
4145516Sdarrenr * Copyright (C) 1993-2003 by Darren Reed.
5145516Sdarrenr *
6145516Sdarrenr * See the IPFILTER.LICENCE file for details on licencing.
7145516Sdarrenr */
8145516Sdarrenr#if !defined(lint)
9145516Sdarrenrstatic const char sccsid[] = "@(#)ip_fil.c	2.41 6/5/96 (C) 1993-2000 Darren Reed";
10172776Sdarrenrstatic const char rcsid[] = "@(#)$Id: ip_fil_freebsd.c,v 2.53.2.50 2007/09/20 12:51:50 darrenr Exp $";
11145516Sdarrenr#endif
12145516Sdarrenr
13145516Sdarrenr#if defined(KERNEL) || defined(_KERNEL)
14145516Sdarrenr# undef KERNEL
15145516Sdarrenr# undef _KERNEL
16145516Sdarrenr# define	KERNEL	1
17145516Sdarrenr# define	_KERNEL	1
18145516Sdarrenr#endif
19145516Sdarrenr#if defined(__FreeBSD_version) && (__FreeBSD_version >= 400000) && \
20145516Sdarrenr    !defined(KLD_MODULE) && !defined(IPFILTER_LKM)
21145516Sdarrenr# include "opt_inet6.h"
22145516Sdarrenr#endif
23145516Sdarrenr#if defined(__FreeBSD_version) && (__FreeBSD_version >= 440000) && \
24145516Sdarrenr    !defined(KLD_MODULE) && !defined(IPFILTER_LKM)
25145516Sdarrenr# include "opt_random_ip_id.h"
26145516Sdarrenr#endif
27145516Sdarrenr#include <sys/param.h>
28145516Sdarrenr#if defined(__FreeBSD__) && !defined(__FreeBSD_version)
29145516Sdarrenr# if defined(IPFILTER_LKM)
30145516Sdarrenr#  ifndef __FreeBSD_cc_version
31145516Sdarrenr#   include <osreldate.h>
32145516Sdarrenr#  else
33145516Sdarrenr#   if __FreeBSD_cc_version < 430000
34145516Sdarrenr#    include <osreldate.h>
35145516Sdarrenr#   endif
36145516Sdarrenr#  endif
37145516Sdarrenr# endif
38145516Sdarrenr#endif
39145516Sdarrenr#include <sys/errno.h>
40145516Sdarrenr#include <sys/types.h>
41145516Sdarrenr#include <sys/file.h>
42145516Sdarrenr#if __FreeBSD_version >= 220000
43145516Sdarrenr# include <sys/fcntl.h>
44145516Sdarrenr# include <sys/filio.h>
45145516Sdarrenr#else
46145516Sdarrenr# include <sys/ioctl.h>
47145516Sdarrenr#endif
48145516Sdarrenr#include <sys/time.h>
49145516Sdarrenr#include <sys/systm.h>
50145516Sdarrenr#if (__FreeBSD_version >= 300000)
51145516Sdarrenr# include <sys/dirent.h>
52145516Sdarrenr#else
53145516Sdarrenr# include <sys/dir.h>
54145516Sdarrenr#endif
55145516Sdarrenr#if !defined(__hpux)
56145516Sdarrenr# include <sys/mbuf.h>
57145516Sdarrenr#endif
58145516Sdarrenr#include <sys/protosw.h>
59145516Sdarrenr#include <sys/socket.h>
60170268Sdarrenr#if __FreeBSD_version >= 500043
61170268Sdarrenr# include <sys/selinfo.h>
62170268Sdarrenr#else
63170268Sdarrenr# include <sys/select.h>
64170268Sdarrenr#endif
65181803Sbz#if __FreeBSD_version >= 800044
66181803Sbz# include <sys/vimage.h>
67181803Sbz#else
68181803Sbz#define V_path_mtu_discovery path_mtu_discovery
69181803Sbz#define V_ipforwarding ipforwarding
70181803Sbz#endif
71145516Sdarrenr
72145516Sdarrenr#include <net/if.h>
73145516Sdarrenr#if __FreeBSD_version >= 300000
74145516Sdarrenr# include <net/if_var.h>
75170268Sdarrenr# if __FreeBSD_version >= 500043
76170268Sdarrenr#  include <net/netisr.h>
77170268Sdarrenr# endif
78145516Sdarrenr# if !defined(IPFILTER_LKM)
79145516Sdarrenr#  include "opt_ipfilter.h"
80145516Sdarrenr# endif
81145516Sdarrenr#endif
82145516Sdarrenr#include <net/route.h>
83145516Sdarrenr#include <netinet/in.h>
84145516Sdarrenr#include <netinet/in_var.h>
85145516Sdarrenr#include <netinet/in_systm.h>
86145516Sdarrenr#include <netinet/ip.h>
87145516Sdarrenr#include <netinet/ip_var.h>
88145516Sdarrenr#include <netinet/tcp.h>
89145516Sdarrenr#if defined(__osf__)
90145516Sdarrenr# include <netinet/tcp_timer.h>
91145516Sdarrenr#endif
92145516Sdarrenr#include <netinet/udp.h>
93145516Sdarrenr#include <netinet/tcpip.h>
94145516Sdarrenr#include <netinet/ip_icmp.h>
95189105Sbz#if defined(__FreeBSD_version) && (__FreeBSD_version >= 800056)
96189105Sbz# include <netinet/vinet.h>
97189105Sbz#endif
98145516Sdarrenr#ifndef _KERNEL
99145516Sdarrenr# include "netinet/ipf.h"
100145516Sdarrenr#endif
101145516Sdarrenr#include "netinet/ip_compat.h"
102145516Sdarrenr#ifdef USE_INET6
103145516Sdarrenr# include <netinet/icmp6.h>
104145516Sdarrenr#endif
105145516Sdarrenr#include "netinet/ip_fil.h"
106145516Sdarrenr#include "netinet/ip_nat.h"
107145516Sdarrenr#include "netinet/ip_frag.h"
108145516Sdarrenr#include "netinet/ip_state.h"
109145516Sdarrenr#include "netinet/ip_proxy.h"
110145516Sdarrenr#include "netinet/ip_auth.h"
111145516Sdarrenr#ifdef	IPFILTER_SYNC
112145516Sdarrenr#include "netinet/ip_sync.h"
113145516Sdarrenr#endif
114145516Sdarrenr#ifdef	IPFILTER_SCAN
115145516Sdarrenr#include "netinet/ip_scan.h"
116145516Sdarrenr#endif
117145516Sdarrenr#include "netinet/ip_pool.h"
118145516Sdarrenr#if defined(__FreeBSD_version) && (__FreeBSD_version >= 300000)
119145516Sdarrenr# include <sys/malloc.h>
120145516Sdarrenr#endif
121145516Sdarrenr#include <sys/kernel.h>
122145516Sdarrenr#ifdef CSUM_DATA_VALID
123145516Sdarrenr#include <machine/in_cksum.h>
124145516Sdarrenr#endif
125145516Sdarrenrextern	int	ip_optcopy __P((struct ip *, struct ip *));
126145516Sdarrenr
127185419Szec#if (__FreeBSD_version > 460000) && (__FreeBSD_version < 800055)
128145516Sdarrenrextern	int	path_mtu_discovery;
129145516Sdarrenr#endif
130145516Sdarrenr
131145516Sdarrenr# ifdef IPFILTER_M_IPFILTER
132151897SrwatsonMALLOC_DEFINE(M_IPFILTER, "ipfilter", "IP Filter packet filter data structures");
133145516Sdarrenr# endif
134145516Sdarrenr
135145516Sdarrenr
136145516Sdarrenr#if !defined(__osf__)
137145516Sdarrenrextern	struct	protosw	inetsw[];
138145516Sdarrenr#endif
139145516Sdarrenr
140145516Sdarrenrstatic	int	(*fr_savep) __P((ip_t *, int, void *, int, struct mbuf **));
141145516Sdarrenrstatic	int	fr_send_ip __P((fr_info_t *, mb_t *, mb_t **));
142145516Sdarrenr# ifdef USE_MUTEXES
143145516Sdarrenripfmutex_t	ipl_mutex, ipf_authmx, ipf_rw, ipf_stinsert;
144145516Sdarrenripfmutex_t	ipf_nat_new, ipf_natio, ipf_timeoutlock;
145170268Sdarrenripfrwlock_t	ipf_mutex, ipf_global, ipf_ipidfrag, ipf_frcache, ipf_tokens;
146145516Sdarrenripfrwlock_t	ipf_frag, ipf_state, ipf_nat, ipf_natfrag, ipf_auth;
147145516Sdarrenr# endif
148145516Sdarrenrint		ipf_locks_done = 0;
149145516Sdarrenr
150145516Sdarrenr#if (__FreeBSD_version >= 300000)
151145516Sdarrenrstruct callout_handle fr_slowtimer_ch;
152145516Sdarrenr#endif
153161356Sguidostruct	selinfo	ipfselwait[IPL_LOGSIZE];
154145516Sdarrenr
155145516Sdarrenr#if (__FreeBSD_version >= 500011)
156145516Sdarrenr# include <sys/conf.h>
157145516Sdarrenr# if defined(NETBSD_PF)
158145516Sdarrenr#  include <net/pfil.h>
159186436Sbz#  if (__FreeBSD_version < 501108)
160186436Sbz#   include <netinet/ipprotosw.h>
161186436Sbz#  endif
162145516Sdarrenr/*
163145516Sdarrenr * We provide the fr_checkp name just to minimize changes later.
164145516Sdarrenr */
165145516Sdarrenrint (*fr_checkp) __P((ip_t *ip, int hlen, void *ifp, int out, mb_t **mp));
166145516Sdarrenr# endif /* NETBSD_PF */
167145516Sdarrenr#endif /* __FreeBSD_version >= 500011 */
168145516Sdarrenr
169145516Sdarrenr
170153876Sguido#if (__FreeBSD_version >= 502103)
171153876Sguidostatic eventhandler_tag ipf_arrivetag, ipf_departtag, ipf_clonetag;
172153876Sguido
173153876Sguidostatic void ipf_ifevent(void *arg);
174153876Sguido
175153876Sguidostatic void ipf_ifevent(arg)
176153876Sguidovoid *arg;
177153876Sguido{
178153876Sguido        frsync(NULL);
179153876Sguido}
180153876Sguido#endif
181153876Sguido
182153876Sguido
183145516Sdarrenr#if (__FreeBSD_version >= 501108) && defined(_KERNEL)
184145516Sdarrenr
185145516Sdarrenrstatic int
186145516Sdarrenrfr_check_wrapper(void *arg, struct mbuf **mp, struct ifnet *ifp, int dir)
187145516Sdarrenr{
188145516Sdarrenr	struct ip *ip = mtod(*mp, struct ip *);
189145516Sdarrenr	return fr_check(ip, ip->ip_hl << 2, ifp, (dir == PFIL_OUT), mp);
190145516Sdarrenr}
191145516Sdarrenr
192145516Sdarrenr# ifdef USE_INET6
193145516Sdarrenr#  include <netinet/ip6.h>
194145516Sdarrenr
195145516Sdarrenrstatic int
196145516Sdarrenrfr_check_wrapper6(void *arg, struct mbuf **mp, struct ifnet *ifp, int dir)
197145516Sdarrenr{
198145516Sdarrenr	return (fr_check(mtod(*mp, struct ip *), sizeof(struct ip6_hdr),
199145516Sdarrenr	    ifp, (dir == PFIL_OUT), mp));
200145516Sdarrenr}
201145516Sdarrenr# endif
202145516Sdarrenr#endif /* __FreeBSD_version >= 501108 */
203145516Sdarrenr#if	defined(IPFILTER_LKM)
204145516Sdarrenrint iplidentify(s)
205145516Sdarrenrchar *s;
206145516Sdarrenr{
207145516Sdarrenr	if (strcmp(s, "ipl") == 0)
208145516Sdarrenr		return 1;
209145516Sdarrenr	return 0;
210145516Sdarrenr}
211145516Sdarrenr#endif /* IPFILTER_LKM */
212145516Sdarrenr
213145516Sdarrenr
214170268Sdarrenrint ipfattach()
215145516Sdarrenr{
216191548Szec	INIT_VNET_INET(curvnet);
217145516Sdarrenr#ifdef USE_SPL
218145516Sdarrenr	int s;
219145516Sdarrenr#endif
220145516Sdarrenr
221145516Sdarrenr	SPL_NET(s);
222145516Sdarrenr	if (fr_running > 0) {
223145516Sdarrenr		SPL_X(s);
224145516Sdarrenr		return EBUSY;
225145516Sdarrenr	}
226145516Sdarrenr
227145516Sdarrenr	MUTEX_INIT(&ipf_rw, "ipf rw mutex");
228145516Sdarrenr	MUTEX_INIT(&ipf_timeoutlock, "ipf timeout queue mutex");
229145516Sdarrenr	RWLOCK_INIT(&ipf_ipidfrag, "ipf IP NAT-Frag rwlock");
230170268Sdarrenr	RWLOCK_INIT(&ipf_tokens, "ipf token rwlock");
231145516Sdarrenr	ipf_locks_done = 1;
232145516Sdarrenr
233145516Sdarrenr	if (fr_initialise() < 0) {
234145516Sdarrenr		SPL_X(s);
235145516Sdarrenr		return EIO;
236145516Sdarrenr	}
237145516Sdarrenr
238145516Sdarrenr
239145516Sdarrenr	if (fr_checkp != fr_check) {
240145516Sdarrenr		fr_savep = fr_checkp;
241145516Sdarrenr		fr_checkp = fr_check;
242145516Sdarrenr	}
243145516Sdarrenr
244161356Sguido	bzero((char *)ipfselwait, sizeof(ipfselwait));
245145516Sdarrenr	bzero((char *)frcache, sizeof(frcache));
246145516Sdarrenr	fr_running = 1;
247145516Sdarrenr
248145516Sdarrenr	if (fr_control_forwarding & 1)
249181803Sbz		V_ipforwarding = 1;
250145516Sdarrenr
251145516Sdarrenr	SPL_X(s);
252145516Sdarrenr#if (__FreeBSD_version >= 300000)
253145516Sdarrenr	fr_slowtimer_ch = timeout(fr_slowtimer, NULL,
254145516Sdarrenr				    (hz / IPF_HZ_DIVIDE) * IPF_HZ_MULT);
255145516Sdarrenr#else
256145516Sdarrenr	timeout(fr_slowtimer, NULL, (hz / IPF_HZ_DIVIDE) * IPF_HZ_MULT);
257145516Sdarrenr#endif
258145516Sdarrenr	return 0;
259145516Sdarrenr}
260145516Sdarrenr
261145516Sdarrenr
262145516Sdarrenr/*
263145516Sdarrenr * Disable the filter by removing the hooks from the IP input/output
264145516Sdarrenr * stream.
265145516Sdarrenr */
266170268Sdarrenrint ipfdetach()
267145516Sdarrenr{
268191548Szec	INIT_VNET_INET(curvnet);
269145516Sdarrenr#ifdef USE_SPL
270145516Sdarrenr	int s;
271145516Sdarrenr#endif
272145516Sdarrenr	if (fr_control_forwarding & 2)
273181803Sbz		V_ipforwarding = 0;
274145516Sdarrenr
275145516Sdarrenr	SPL_NET(s);
276145516Sdarrenr
277145516Sdarrenr#if (__FreeBSD_version >= 300000)
278145516Sdarrenr	if (fr_slowtimer_ch.callout != NULL)
279145516Sdarrenr		untimeout(fr_slowtimer, NULL, fr_slowtimer_ch);
280145516Sdarrenr	bzero(&fr_slowtimer_ch, sizeof(fr_slowtimer_ch));
281145516Sdarrenr#else
282145516Sdarrenr	untimeout(fr_slowtimer, NULL);
283145516Sdarrenr#endif /* FreeBSD */
284145516Sdarrenr
285145516Sdarrenr#ifndef NETBSD_PF
286145516Sdarrenr	if (fr_checkp != NULL)
287145516Sdarrenr		fr_checkp = fr_savep;
288145516Sdarrenr	fr_savep = NULL;
289145516Sdarrenr#endif
290145516Sdarrenr
291145516Sdarrenr	fr_deinitialise();
292145516Sdarrenr
293145516Sdarrenr	fr_running = -2;
294145516Sdarrenr
295145516Sdarrenr	(void) frflush(IPL_LOGIPF, 0, FR_INQUE|FR_OUTQUE|FR_INACTIVE);
296145516Sdarrenr	(void) frflush(IPL_LOGIPF, 0, FR_INQUE|FR_OUTQUE);
297145516Sdarrenr
298145516Sdarrenr	if (ipf_locks_done == 1) {
299145516Sdarrenr		MUTEX_DESTROY(&ipf_timeoutlock);
300145516Sdarrenr		MUTEX_DESTROY(&ipf_rw);
301145516Sdarrenr		RW_DESTROY(&ipf_ipidfrag);
302170268Sdarrenr		RW_DESTROY(&ipf_tokens);
303145516Sdarrenr		ipf_locks_done = 0;
304145516Sdarrenr	}
305145516Sdarrenr
306145516Sdarrenr	SPL_X(s);
307145516Sdarrenr
308145516Sdarrenr	return 0;
309145516Sdarrenr}
310145516Sdarrenr
311145516Sdarrenr
312145516Sdarrenr/*
313145516Sdarrenr * Filter ioctl interface.
314145516Sdarrenr */
315145516Sdarrenrint iplioctl(dev, cmd, data, mode
316145516Sdarrenr# if defined(_KERNEL) && ((BSD >= 199506) || (__FreeBSD_version >= 220000))
317145516Sdarrenr, p)
318145516Sdarrenr#  if (__FreeBSD_version >= 500024)
319145516Sdarrenrstruct thread *p;
320170268Sdarrenr#   if (__FreeBSD_version >= 500043)
321192895Sjamie#    define	p_cred	td_ucred
322170268Sdarrenr#    define	p_uid	td_ucred->cr_ruid
323170268Sdarrenr#   else
324192895Sjamie#    define	p_cred	t_proc->p_cred
325170268Sdarrenr#    define	p_uid	t_proc->p_cred->p_ruid
326170268Sdarrenr#   endif
327145516Sdarrenr#  else
328145516Sdarrenrstruct proc *p;
329170268Sdarrenr#   define	p_uid	p_cred->p_ruid
330145516Sdarrenr#  endif /* __FreeBSD_version >= 500024 */
331145516Sdarrenr# else
332145516Sdarrenr)
333145516Sdarrenr# endif
334145516Sdarrenr#if defined(_KERNEL) && (__FreeBSD_version >= 502116)
335145516Sdarrenrstruct cdev *dev;
336145516Sdarrenr#else
337145516Sdarrenrdev_t dev;
338145516Sdarrenr#endif
339145516Sdarrenrioctlcmd_t cmd;
340145516Sdarrenrcaddr_t data;
341145516Sdarrenrint mode;
342145516Sdarrenr{
343170268Sdarrenr	int error = 0, unit = 0;
344170268Sdarrenr	SPL_INT(s);
345145516Sdarrenr
346145516Sdarrenr#if (BSD >= 199306) && defined(_KERNEL)
347192895Sjamie# if (__FreeBSD_version >= 500034)
348192895Sjamie	if (securelevel_ge(p->p_cred, 3) && (mode & FWRITE))
349192895Sjamie# else
350153876Sguido	if ((securelevel >= 3) && (mode & FWRITE))
351192895Sjamie# endif
352145516Sdarrenr		return EPERM;
353145516Sdarrenr#endif
354145516Sdarrenr
355145516Sdarrenr	unit = GET_MINOR(dev);
356145516Sdarrenr	if ((IPL_LOGMAX < unit) || (unit < 0))
357145516Sdarrenr		return ENXIO;
358145516Sdarrenr
359145516Sdarrenr	if (fr_running <= 0) {
360145516Sdarrenr		if (unit != IPL_LOGIPF)
361145516Sdarrenr			return EIO;
362145516Sdarrenr		if (cmd != SIOCIPFGETNEXT && cmd != SIOCIPFGET &&
363173181Sdarrenr		    cmd != SIOCIPFSET && cmd != SIOCFRENB &&
364145516Sdarrenr		    cmd != SIOCGETFS && cmd != SIOCGETFF)
365145516Sdarrenr			return EIO;
366145516Sdarrenr	}
367145516Sdarrenr
368145516Sdarrenr	SPL_NET(s);
369145516Sdarrenr
370170268Sdarrenr	error = fr_ioctlswitch(unit, data, cmd, mode, p->p_uid, p);
371145516Sdarrenr	if (error != -1) {
372145516Sdarrenr		SPL_X(s);
373145516Sdarrenr		return error;
374145516Sdarrenr	}
375145516Sdarrenr
376145516Sdarrenr	SPL_X(s);
377161356Sguido
378145516Sdarrenr	return error;
379145516Sdarrenr}
380145516Sdarrenr
381145516Sdarrenr
382145516Sdarrenr#if 0
383145516Sdarrenrvoid fr_forgetifp(ifp)
384145516Sdarrenrvoid *ifp;
385145516Sdarrenr{
386145516Sdarrenr	register frentry_t *f;
387145516Sdarrenr
388145516Sdarrenr	WRITE_ENTER(&ipf_mutex);
389145516Sdarrenr	for (f = ipacct[0][fr_active]; (f != NULL); f = f->fr_next)
390145516Sdarrenr		if (f->fr_ifa == ifp)
391145516Sdarrenr			f->fr_ifa = (void *)-1;
392145516Sdarrenr	for (f = ipacct[1][fr_active]; (f != NULL); f = f->fr_next)
393145516Sdarrenr		if (f->fr_ifa == ifp)
394145516Sdarrenr			f->fr_ifa = (void *)-1;
395145516Sdarrenr	for (f = ipfilter[0][fr_active]; (f != NULL); f = f->fr_next)
396145516Sdarrenr		if (f->fr_ifa == ifp)
397145516Sdarrenr			f->fr_ifa = (void *)-1;
398145516Sdarrenr	for (f = ipfilter[1][fr_active]; (f != NULL); f = f->fr_next)
399145516Sdarrenr		if (f->fr_ifa == ifp)
400145516Sdarrenr			f->fr_ifa = (void *)-1;
401145516Sdarrenr#ifdef USE_INET6
402145516Sdarrenr	for (f = ipacct6[0][fr_active]; (f != NULL); f = f->fr_next)
403145516Sdarrenr		if (f->fr_ifa == ifp)
404145516Sdarrenr			f->fr_ifa = (void *)-1;
405145516Sdarrenr	for (f = ipacct6[1][fr_active]; (f != NULL); f = f->fr_next)
406145516Sdarrenr		if (f->fr_ifa == ifp)
407145516Sdarrenr			f->fr_ifa = (void *)-1;
408145516Sdarrenr	for (f = ipfilter6[0][fr_active]; (f != NULL); f = f->fr_next)
409145516Sdarrenr		if (f->fr_ifa == ifp)
410145516Sdarrenr			f->fr_ifa = (void *)-1;
411145516Sdarrenr	for (f = ipfilter6[1][fr_active]; (f != NULL); f = f->fr_next)
412145516Sdarrenr		if (f->fr_ifa == ifp)
413145516Sdarrenr			f->fr_ifa = (void *)-1;
414145516Sdarrenr#endif
415145516Sdarrenr	RWLOCK_EXIT(&ipf_mutex);
416145516Sdarrenr	fr_natsync(ifp);
417145516Sdarrenr}
418145516Sdarrenr#endif
419145516Sdarrenr
420145516Sdarrenr
421145516Sdarrenr/*
422145516Sdarrenr * routines below for saving IP headers to buffer
423145516Sdarrenr */
424145516Sdarrenrint iplopen(dev, flags
425145516Sdarrenr#if ((BSD >= 199506) || (__FreeBSD_version >= 220000)) && defined(_KERNEL)
426145516Sdarrenr, devtype, p)
427145516Sdarrenrint devtype;
428145516Sdarrenr# if (__FreeBSD_version >= 500024)
429145516Sdarrenrstruct thread *p;
430145516Sdarrenr# else
431145516Sdarrenrstruct proc *p;
432145516Sdarrenr# endif /* __FreeBSD_version >= 500024 */
433145516Sdarrenr#else
434145516Sdarrenr)
435145516Sdarrenr#endif
436145516Sdarrenr#if defined(_KERNEL) && (__FreeBSD_version >= 502116)
437145516Sdarrenrstruct cdev *dev;
438145516Sdarrenr#else
439145516Sdarrenrdev_t dev;
440145516Sdarrenr#endif
441145516Sdarrenrint flags;
442145516Sdarrenr{
443145516Sdarrenr	u_int min = GET_MINOR(dev);
444145516Sdarrenr
445145516Sdarrenr	if (IPL_LOGMAX < min)
446145516Sdarrenr		min = ENXIO;
447145516Sdarrenr	else
448145516Sdarrenr		min = 0;
449145516Sdarrenr	return min;
450145516Sdarrenr}
451145516Sdarrenr
452145516Sdarrenr
453145516Sdarrenrint iplclose(dev, flags
454145516Sdarrenr#if ((BSD >= 199506) || (__FreeBSD_version >= 220000)) && defined(_KERNEL)
455145516Sdarrenr, devtype, p)
456145516Sdarrenrint devtype;
457145516Sdarrenr# if (__FreeBSD_version >= 500024)
458145516Sdarrenrstruct thread *p;
459145516Sdarrenr# else
460145516Sdarrenrstruct proc *p;
461145516Sdarrenr# endif /* __FreeBSD_version >= 500024 */
462145516Sdarrenr#else
463145516Sdarrenr)
464145516Sdarrenr#endif
465145516Sdarrenr#if defined(_KERNEL) && (__FreeBSD_version >= 502116)
466145516Sdarrenrstruct cdev *dev;
467145516Sdarrenr#else
468145516Sdarrenrdev_t dev;
469145516Sdarrenr#endif
470145516Sdarrenrint flags;
471145516Sdarrenr{
472145516Sdarrenr	u_int	min = GET_MINOR(dev);
473145516Sdarrenr
474145516Sdarrenr	if (IPL_LOGMAX < min)
475145516Sdarrenr		min = ENXIO;
476145516Sdarrenr	else
477145516Sdarrenr		min = 0;
478145516Sdarrenr	return min;
479145516Sdarrenr}
480145516Sdarrenr
481145516Sdarrenr/*
482145516Sdarrenr * iplread/ipllog
483145516Sdarrenr * both of these must operate with at least splnet() lest they be
484145516Sdarrenr * called during packet processing and cause an inconsistancy to appear in
485145516Sdarrenr * the filter lists.
486145516Sdarrenr */
487145516Sdarrenr#if (BSD >= 199306)
488145516Sdarrenrint iplread(dev, uio, ioflag)
489145516Sdarrenrint ioflag;
490145516Sdarrenr#else
491145516Sdarrenrint iplread(dev, uio)
492145516Sdarrenr#endif
493145516Sdarrenr#if defined(_KERNEL) && (__FreeBSD_version >= 502116)
494145516Sdarrenrstruct cdev *dev;
495145516Sdarrenr#else
496145516Sdarrenrdev_t dev;
497145516Sdarrenr#endif
498145516Sdarrenrregister struct uio *uio;
499145516Sdarrenr{
500161356Sguido	u_int	xmin = GET_MINOR(dev);
501145516Sdarrenr
502170268Sdarrenr	if (fr_running < 1)
503170268Sdarrenr		return EIO;
504170268Sdarrenr
505161356Sguido	if (xmin < 0)
506161356Sguido		return ENXIO;
507161356Sguido
508145516Sdarrenr# ifdef	IPFILTER_SYNC
509161356Sguido	if (xmin == IPL_LOGSYNC)
510145516Sdarrenr		return ipfsync_read(uio);
511145516Sdarrenr# endif
512145516Sdarrenr
513145516Sdarrenr#ifdef IPFILTER_LOG
514161356Sguido	return ipflog_read(xmin, uio);
515145516Sdarrenr#else
516145516Sdarrenr	return ENXIO;
517145516Sdarrenr#endif
518145516Sdarrenr}
519145516Sdarrenr
520145516Sdarrenr
521145516Sdarrenr/*
522145516Sdarrenr * iplwrite
523145516Sdarrenr * both of these must operate with at least splnet() lest they be
524145516Sdarrenr * called during packet processing and cause an inconsistancy to appear in
525145516Sdarrenr * the filter lists.
526145516Sdarrenr */
527145516Sdarrenr#if (BSD >= 199306)
528145516Sdarrenrint iplwrite(dev, uio, ioflag)
529145516Sdarrenrint ioflag;
530145516Sdarrenr#else
531145516Sdarrenrint iplwrite(dev, uio)
532145516Sdarrenr#endif
533145516Sdarrenr#if defined(_KERNEL) && (__FreeBSD_version >= 502116)
534145516Sdarrenrstruct cdev *dev;
535145516Sdarrenr#else
536145516Sdarrenrdev_t dev;
537145516Sdarrenr#endif
538145516Sdarrenrregister struct uio *uio;
539145516Sdarrenr{
540145516Sdarrenr
541170268Sdarrenr	if (fr_running < 1)
542170268Sdarrenr		return EIO;
543170268Sdarrenr
544145516Sdarrenr#ifdef	IPFILTER_SYNC
545145516Sdarrenr	if (GET_MINOR(dev) == IPL_LOGSYNC)
546145516Sdarrenr		return ipfsync_write(uio);
547145516Sdarrenr#endif
548145516Sdarrenr	return ENXIO;
549145516Sdarrenr}
550145516Sdarrenr
551145516Sdarrenr
552145516Sdarrenr/*
553145516Sdarrenr * fr_send_reset - this could conceivably be a call to tcp_respond(), but that
554145516Sdarrenr * requires a large amount of setting up and isn't any more efficient.
555145516Sdarrenr */
556145516Sdarrenrint fr_send_reset(fin)
557145516Sdarrenrfr_info_t *fin;
558145516Sdarrenr{
559145516Sdarrenr	struct tcphdr *tcp, *tcp2;
560145516Sdarrenr	int tlen = 0, hlen;
561145516Sdarrenr	struct mbuf *m;
562145516Sdarrenr#ifdef USE_INET6
563145516Sdarrenr	ip6_t *ip6;
564145516Sdarrenr#endif
565145516Sdarrenr	ip_t *ip;
566145516Sdarrenr
567145516Sdarrenr	tcp = fin->fin_dp;
568145516Sdarrenr	if (tcp->th_flags & TH_RST)
569145516Sdarrenr		return -1;		/* feedback loop */
570145516Sdarrenr
571145516Sdarrenr	if (fr_checkl4sum(fin) == -1)
572145516Sdarrenr		return -1;
573145516Sdarrenr
574145516Sdarrenr	tlen = fin->fin_dlen - (TCP_OFF(tcp) << 2) +
575145516Sdarrenr			((tcp->th_flags & TH_SYN) ? 1 : 0) +
576145516Sdarrenr			((tcp->th_flags & TH_FIN) ? 1 : 0);
577145516Sdarrenr
578145516Sdarrenr#ifdef USE_INET6
579145516Sdarrenr	hlen = (fin->fin_v == 6) ? sizeof(ip6_t) : sizeof(ip_t);
580145516Sdarrenr#else
581145516Sdarrenr	hlen = sizeof(ip_t);
582145516Sdarrenr#endif
583145516Sdarrenr#ifdef MGETHDR
584145516Sdarrenr	MGETHDR(m, M_DONTWAIT, MT_HEADER);
585145516Sdarrenr#else
586145516Sdarrenr	MGET(m, M_DONTWAIT, MT_HEADER);
587145516Sdarrenr#endif
588145516Sdarrenr	if (m == NULL)
589145516Sdarrenr		return -1;
590145516Sdarrenr	if (sizeof(*tcp2) + hlen > MLEN) {
591145516Sdarrenr		MCLGET(m, M_DONTWAIT);
592145516Sdarrenr		if ((m->m_flags & M_EXT) == 0) {
593145516Sdarrenr			FREE_MB_T(m);
594145516Sdarrenr			return -1;
595145516Sdarrenr		}
596145516Sdarrenr	}
597145516Sdarrenr
598145516Sdarrenr	m->m_len = sizeof(*tcp2) + hlen;
599145516Sdarrenr#if (BSD >= 199103)
600145516Sdarrenr	m->m_data += max_linkhdr;
601145516Sdarrenr	m->m_pkthdr.len = m->m_len;
602145516Sdarrenr	m->m_pkthdr.rcvif = (struct ifnet *)0;
603145516Sdarrenr#endif
604145516Sdarrenr	ip = mtod(m, struct ip *);
605145516Sdarrenr	bzero((char *)ip, hlen);
606145516Sdarrenr#ifdef USE_INET6
607145516Sdarrenr	ip6 = (ip6_t *)ip;
608145516Sdarrenr#endif
609145516Sdarrenr	tcp2 = (struct tcphdr *)((char *)ip + hlen);
610145516Sdarrenr	tcp2->th_sport = tcp->th_dport;
611145516Sdarrenr	tcp2->th_dport = tcp->th_sport;
612145516Sdarrenr
613145516Sdarrenr	if (tcp->th_flags & TH_ACK) {
614145516Sdarrenr		tcp2->th_seq = tcp->th_ack;
615145516Sdarrenr		tcp2->th_flags = TH_RST;
616145516Sdarrenr		tcp2->th_ack = 0;
617145516Sdarrenr	} else {
618145516Sdarrenr		tcp2->th_seq = 0;
619145516Sdarrenr		tcp2->th_ack = ntohl(tcp->th_seq);
620145516Sdarrenr		tcp2->th_ack += tlen;
621145516Sdarrenr		tcp2->th_ack = htonl(tcp2->th_ack);
622145516Sdarrenr		tcp2->th_flags = TH_RST|TH_ACK;
623145516Sdarrenr	}
624145516Sdarrenr	TCP_X2_A(tcp2, 0);
625145516Sdarrenr	TCP_OFF_A(tcp2, sizeof(*tcp2) >> 2);
626145516Sdarrenr	tcp2->th_win = tcp->th_win;
627145516Sdarrenr	tcp2->th_sum = 0;
628145516Sdarrenr	tcp2->th_urp = 0;
629145516Sdarrenr
630145516Sdarrenr#ifdef USE_INET6
631145516Sdarrenr	if (fin->fin_v == 6) {
632145516Sdarrenr		ip6->ip6_flow = ((ip6_t *)fin->fin_ip)->ip6_flow;
633145516Sdarrenr		ip6->ip6_plen = htons(sizeof(struct tcphdr));
634145516Sdarrenr		ip6->ip6_nxt = IPPROTO_TCP;
635145516Sdarrenr		ip6->ip6_hlim = 0;
636145516Sdarrenr		ip6->ip6_src = fin->fin_dst6;
637145516Sdarrenr		ip6->ip6_dst = fin->fin_src6;
638145516Sdarrenr		tcp2->th_sum = in6_cksum(m, IPPROTO_TCP,
639145516Sdarrenr					 sizeof(*ip6), sizeof(*tcp2));
640145516Sdarrenr		return fr_send_ip(fin, m, &m);
641145516Sdarrenr	}
642145516Sdarrenr#endif
643145516Sdarrenr	ip->ip_p = IPPROTO_TCP;
644145516Sdarrenr	ip->ip_len = htons(sizeof(struct tcphdr));
645145516Sdarrenr	ip->ip_src.s_addr = fin->fin_daddr;
646145516Sdarrenr	ip->ip_dst.s_addr = fin->fin_saddr;
647145516Sdarrenr	tcp2->th_sum = in_cksum(m, hlen + sizeof(*tcp2));
648145516Sdarrenr	ip->ip_len = hlen + sizeof(*tcp2);
649145516Sdarrenr	return fr_send_ip(fin, m, &m);
650145516Sdarrenr}
651145516Sdarrenr
652145516Sdarrenr
653145516Sdarrenrstatic int fr_send_ip(fin, m, mpp)
654145516Sdarrenrfr_info_t *fin;
655145516Sdarrenrmb_t *m, **mpp;
656145516Sdarrenr{
657191548Szec	INIT_VNET_INET(curvnet);
658145516Sdarrenr	fr_info_t fnew;
659145516Sdarrenr	ip_t *ip, *oip;
660145516Sdarrenr	int hlen;
661145516Sdarrenr
662145516Sdarrenr	ip = mtod(m, ip_t *);
663145516Sdarrenr	bzero((char *)&fnew, sizeof(fnew));
664145516Sdarrenr
665145516Sdarrenr	IP_V_A(ip, fin->fin_v);
666145516Sdarrenr	switch (fin->fin_v)
667145516Sdarrenr	{
668145516Sdarrenr	case 4 :
669145516Sdarrenr		fnew.fin_v = 4;
670145516Sdarrenr		oip = fin->fin_ip;
671145516Sdarrenr		IP_HL_A(ip, sizeof(*oip) >> 2);
672145516Sdarrenr		ip->ip_tos = oip->ip_tos;
673145516Sdarrenr		ip->ip_id = fin->fin_ip->ip_id;
674145516Sdarrenr#if (__FreeBSD_version > 460000)
675181803Sbz		ip->ip_off = V_path_mtu_discovery ? IP_DF : 0;
676145516Sdarrenr#else
677145516Sdarrenr		ip->ip_off = 0;
678145516Sdarrenr#endif
679181803Sbz		ip->ip_ttl = V_ip_defttl;
680145516Sdarrenr		ip->ip_sum = 0;
681145516Sdarrenr		hlen = sizeof(*oip);
682145516Sdarrenr		break;
683145516Sdarrenr#ifdef USE_INET6
684145516Sdarrenr	case 6 :
685145516Sdarrenr	{
686145516Sdarrenr		ip6_t *ip6 = (ip6_t *)ip;
687145516Sdarrenr
688145516Sdarrenr		ip6->ip6_vfc = 0x60;
689145516Sdarrenr		ip6->ip6_hlim = IPDEFTTL;
690145516Sdarrenr
691145516Sdarrenr		fnew.fin_v = 6;
692145516Sdarrenr		hlen = sizeof(*ip6);
693145516Sdarrenr		break;
694145516Sdarrenr	}
695145516Sdarrenr#endif
696145516Sdarrenr	default :
697145516Sdarrenr		return EINVAL;
698145516Sdarrenr	}
699145516Sdarrenr#ifdef IPSEC
700145516Sdarrenr	m->m_pkthdr.rcvif = NULL;
701145516Sdarrenr#endif
702145516Sdarrenr
703145516Sdarrenr	fnew.fin_ifp = fin->fin_ifp;
704145516Sdarrenr	fnew.fin_flx = FI_NOCKSUM;
705145516Sdarrenr	fnew.fin_m = m;
706145516Sdarrenr	fnew.fin_ip = ip;
707145516Sdarrenr	fnew.fin_mp = mpp;
708145516Sdarrenr	fnew.fin_hlen = hlen;
709145516Sdarrenr	fnew.fin_dp = (char *)ip + hlen;
710145516Sdarrenr	(void) fr_makefrip(hlen, ip, &fnew);
711145516Sdarrenr
712145516Sdarrenr	return fr_fastroute(m, mpp, &fnew, NULL);
713145516Sdarrenr}
714145516Sdarrenr
715145516Sdarrenr
716145516Sdarrenrint fr_send_icmp_err(type, fin, dst)
717145516Sdarrenrint type;
718145516Sdarrenrfr_info_t *fin;
719145516Sdarrenrint dst;
720145516Sdarrenr{
721145516Sdarrenr	int err, hlen, xtra, iclen, ohlen, avail, code;
722145516Sdarrenr	struct in_addr dst4;
723145516Sdarrenr	struct icmp *icmp;
724145516Sdarrenr	struct mbuf *m;
725145516Sdarrenr	void *ifp;
726145516Sdarrenr#ifdef USE_INET6
727145516Sdarrenr	ip6_t *ip6;
728145516Sdarrenr	struct in6_addr dst6;
729145516Sdarrenr#endif
730145516Sdarrenr	ip_t *ip, *ip2;
731145516Sdarrenr
732172776Sdarrenr	if ((type < 0) || (type >= ICMP_MAXTYPE))
733145516Sdarrenr		return -1;
734145516Sdarrenr
735145516Sdarrenr	code = fin->fin_icode;
736145516Sdarrenr#ifdef USE_INET6
737145516Sdarrenr	if ((code < 0) || (code > sizeof(icmptoicmp6unreach)/sizeof(int)))
738145516Sdarrenr		return -1;
739145516Sdarrenr#endif
740145516Sdarrenr
741145516Sdarrenr	if (fr_checkl4sum(fin) == -1)
742145516Sdarrenr		return -1;
743145516Sdarrenr#ifdef MGETHDR
744145516Sdarrenr	MGETHDR(m, M_DONTWAIT, MT_HEADER);
745145516Sdarrenr#else
746145516Sdarrenr	MGET(m, M_DONTWAIT, MT_HEADER);
747145516Sdarrenr#endif
748145516Sdarrenr	if (m == NULL)
749145516Sdarrenr		return -1;
750145516Sdarrenr	avail = MHLEN;
751145516Sdarrenr
752145516Sdarrenr	xtra = 0;
753145516Sdarrenr	hlen = 0;
754145516Sdarrenr	ohlen = 0;
755145516Sdarrenr	ifp = fin->fin_ifp;
756145516Sdarrenr	if (fin->fin_v == 4) {
757145516Sdarrenr		if ((fin->fin_p == IPPROTO_ICMP) &&
758145516Sdarrenr		    !(fin->fin_flx & FI_SHORT))
759145516Sdarrenr			switch (ntohs(fin->fin_data[0]) >> 8)
760145516Sdarrenr			{
761145516Sdarrenr			case ICMP_ECHO :
762145516Sdarrenr			case ICMP_TSTAMP :
763145516Sdarrenr			case ICMP_IREQ :
764145516Sdarrenr			case ICMP_MASKREQ :
765145516Sdarrenr				break;
766145516Sdarrenr			default :
767145516Sdarrenr				FREE_MB_T(m);
768145516Sdarrenr				return 0;
769145516Sdarrenr			}
770145516Sdarrenr
771145516Sdarrenr		if (dst == 0) {
772145516Sdarrenr			if (fr_ifpaddr(4, FRI_NORMAL, ifp,
773145516Sdarrenr				       &dst4, NULL) == -1) {
774145516Sdarrenr				FREE_MB_T(m);
775145516Sdarrenr				return -1;
776145516Sdarrenr			}
777145516Sdarrenr		} else
778145516Sdarrenr			dst4.s_addr = fin->fin_daddr;
779145516Sdarrenr
780145516Sdarrenr		hlen = sizeof(ip_t);
781145516Sdarrenr		ohlen = fin->fin_hlen;
782145516Sdarrenr		if (fin->fin_hlen < fin->fin_plen)
783145516Sdarrenr			xtra = MIN(fin->fin_dlen, 8);
784145516Sdarrenr		else
785145516Sdarrenr			xtra = 0;
786145516Sdarrenr	}
787145516Sdarrenr
788145516Sdarrenr#ifdef USE_INET6
789145516Sdarrenr	else if (fin->fin_v == 6) {
790145516Sdarrenr		hlen = sizeof(ip6_t);
791145516Sdarrenr		ohlen = sizeof(ip6_t);
792145516Sdarrenr		type = icmptoicmp6types[type];
793145516Sdarrenr		if (type == ICMP6_DST_UNREACH)
794145516Sdarrenr			code = icmptoicmp6unreach[code];
795145516Sdarrenr
796145516Sdarrenr		if (hlen + sizeof(*icmp) + max_linkhdr +
797145516Sdarrenr		    fin->fin_plen > avail) {
798145516Sdarrenr			MCLGET(m, M_DONTWAIT);
799145516Sdarrenr			if ((m->m_flags & M_EXT) == 0) {
800145516Sdarrenr				FREE_MB_T(m);
801145516Sdarrenr				return -1;
802145516Sdarrenr			}
803145516Sdarrenr			avail = MCLBYTES;
804145516Sdarrenr		}
805145516Sdarrenr		xtra = MIN(fin->fin_plen,
806145516Sdarrenr			   avail - hlen - sizeof(*icmp) - max_linkhdr);
807145516Sdarrenr		if (dst == 0) {
808145516Sdarrenr			if (fr_ifpaddr(6, FRI_NORMAL, ifp,
809145516Sdarrenr				       (struct in_addr *)&dst6, NULL) == -1) {
810145516Sdarrenr				FREE_MB_T(m);
811145516Sdarrenr				return -1;
812145516Sdarrenr			}
813145516Sdarrenr		} else
814145516Sdarrenr			dst6 = fin->fin_dst6;
815145516Sdarrenr	}
816145516Sdarrenr#endif
817145516Sdarrenr	else {
818145516Sdarrenr		FREE_MB_T(m);
819145516Sdarrenr		return -1;
820145516Sdarrenr	}
821145516Sdarrenr
822145516Sdarrenr	iclen = hlen + sizeof(*icmp);
823145516Sdarrenr	avail -= (max_linkhdr + iclen);
824145516Sdarrenr	if (avail < 0) {
825145516Sdarrenr		FREE_MB_T(m);
826145516Sdarrenr		return -1;
827145516Sdarrenr	}
828145516Sdarrenr	if (xtra > avail)
829145516Sdarrenr		xtra = avail;
830145516Sdarrenr	iclen += xtra;
831145516Sdarrenr	m->m_data += max_linkhdr;
832145516Sdarrenr	m->m_pkthdr.rcvif = (struct ifnet *)0;
833145516Sdarrenr	m->m_pkthdr.len = iclen;
834145516Sdarrenr	m->m_len = iclen;
835145516Sdarrenr	ip = mtod(m, ip_t *);
836145516Sdarrenr	icmp = (struct icmp *)((char *)ip + hlen);
837145516Sdarrenr	ip2 = (ip_t *)&icmp->icmp_ip;
838145516Sdarrenr
839145516Sdarrenr	icmp->icmp_type = type;
840145516Sdarrenr	icmp->icmp_code = fin->fin_icode;
841145516Sdarrenr	icmp->icmp_cksum = 0;
842145516Sdarrenr#ifdef icmp_nextmtu
843145516Sdarrenr	if (type == ICMP_UNREACH &&
844145516Sdarrenr	    fin->fin_icode == ICMP_UNREACH_NEEDFRAG && ifp)
845145516Sdarrenr		icmp->icmp_nextmtu = htons(((struct ifnet *)ifp)->if_mtu);
846145516Sdarrenr#endif
847145516Sdarrenr
848145516Sdarrenr	bcopy((char *)fin->fin_ip, (char *)ip2, ohlen);
849145516Sdarrenr
850145516Sdarrenr#ifdef USE_INET6
851145516Sdarrenr	ip6 = (ip6_t *)ip;
852145516Sdarrenr	if (fin->fin_v == 6) {
853145516Sdarrenr		ip6->ip6_flow = ((ip6_t *)fin->fin_ip)->ip6_flow;
854145516Sdarrenr		ip6->ip6_plen = htons(iclen - hlen);
855145516Sdarrenr		ip6->ip6_nxt = IPPROTO_ICMPV6;
856145516Sdarrenr		ip6->ip6_hlim = 0;
857145516Sdarrenr		ip6->ip6_src = dst6;
858145516Sdarrenr		ip6->ip6_dst = fin->fin_src6;
859145516Sdarrenr		if (xtra > 0)
860145516Sdarrenr			bcopy((char *)fin->fin_ip + ohlen,
861145516Sdarrenr			      (char *)&icmp->icmp_ip + ohlen, xtra);
862145516Sdarrenr		icmp->icmp_cksum = in6_cksum(m, IPPROTO_ICMPV6,
863145516Sdarrenr					     sizeof(*ip6), iclen - hlen);
864145516Sdarrenr	} else
865145516Sdarrenr#endif
866145516Sdarrenr	{
867145516Sdarrenr		ip2->ip_len = htons(ip2->ip_len);
868145516Sdarrenr		ip2->ip_off = htons(ip2->ip_off);
869145516Sdarrenr		ip->ip_p = IPPROTO_ICMP;
870145516Sdarrenr		ip->ip_src.s_addr = dst4.s_addr;
871145516Sdarrenr		ip->ip_dst.s_addr = fin->fin_saddr;
872145516Sdarrenr
873145516Sdarrenr		if (xtra > 0)
874145516Sdarrenr			bcopy((char *)fin->fin_ip + ohlen,
875145516Sdarrenr			      (char *)&icmp->icmp_ip + ohlen, xtra);
876145516Sdarrenr		icmp->icmp_cksum = ipf_cksum((u_short *)icmp,
877145516Sdarrenr					     sizeof(*icmp) + 8);
878145516Sdarrenr		ip->ip_len = iclen;
879145516Sdarrenr		ip->ip_p = IPPROTO_ICMP;
880145516Sdarrenr	}
881145516Sdarrenr	err = fr_send_ip(fin, m, &m);
882145516Sdarrenr	return err;
883145516Sdarrenr}
884145516Sdarrenr
885145516Sdarrenr
886145516Sdarrenr#if !defined(IPFILTER_LKM) && (__FreeBSD_version < 300000)
887145516Sdarrenr# if	(BSD < 199306)
888145516Sdarrenrint iplinit __P((void));
889145516Sdarrenr
890145516Sdarrenrint
891145516Sdarrenr# else
892145516Sdarrenrvoid iplinit __P((void));
893145516Sdarrenr
894145516Sdarrenrvoid
895145516Sdarrenr# endif
896145516Sdarrenriplinit()
897145516Sdarrenr{
898170268Sdarrenr	if (ipfattach() != 0)
899145516Sdarrenr		printf("IP Filter failed to attach\n");
900145516Sdarrenr	ip_init();
901145516Sdarrenr}
902145516Sdarrenr#endif /* __FreeBSD_version < 300000 */
903145516Sdarrenr
904145516Sdarrenr
905173181Sdarrenr/*
906173181Sdarrenr * m0 - pointer to mbuf where the IP packet starts
907173181Sdarrenr * mpp - pointer to the mbuf pointer that is the start of the mbuf chain
908173181Sdarrenr */
909145516Sdarrenrint fr_fastroute(m0, mpp, fin, fdp)
910145516Sdarrenrmb_t *m0, **mpp;
911145516Sdarrenrfr_info_t *fin;
912145516Sdarrenrfrdest_t *fdp;
913145516Sdarrenr{
914145516Sdarrenr	register struct ip *ip, *mhip;
915173181Sdarrenr	register struct mbuf *m = *mpp;
916145516Sdarrenr	register struct route *ro;
917145516Sdarrenr	int len, off, error = 0, hlen, code;
918145516Sdarrenr	struct ifnet *ifp, *sifp;
919145516Sdarrenr	struct sockaddr_in *dst;
920145516Sdarrenr	struct route iproute;
921145516Sdarrenr	u_short ip_off;
922145516Sdarrenr	frentry_t *fr;
923145516Sdarrenr
924161356Sguido	ro = NULL;
925161356Sguido
926145516Sdarrenr#ifdef M_WRITABLE
927145516Sdarrenr	/*
928145516Sdarrenr	* HOT FIX/KLUDGE:
929145516Sdarrenr	*
930145516Sdarrenr	* If the mbuf we're about to send is not writable (because of
931145516Sdarrenr	* a cluster reference, for example) we'll need to make a copy
932145516Sdarrenr	* of it since this routine modifies the contents.
933145516Sdarrenr	*
934145516Sdarrenr	* If you have non-crappy network hardware that can transmit data
935145516Sdarrenr	* from the mbuf, rather than making a copy, this is gonna be a
936145516Sdarrenr	* problem.
937145516Sdarrenr	*/
938145516Sdarrenr	if (M_WRITABLE(m) == 0) {
939161356Sguido		m0 = m_dup(m, M_DONTWAIT);
940161356Sguido		if (m0 != 0) {
941145516Sdarrenr			FREE_MB_T(m);
942145516Sdarrenr			m = m0;
943145516Sdarrenr			*mpp = m;
944145516Sdarrenr		} else {
945145516Sdarrenr			error = ENOBUFS;
946145516Sdarrenr			FREE_MB_T(m);
947161356Sguido			goto done;
948145516Sdarrenr		}
949145516Sdarrenr	}
950145516Sdarrenr#endif
951145516Sdarrenr
952145516Sdarrenr#ifdef USE_INET6
953145516Sdarrenr	if (fin->fin_v == 6) {
954145516Sdarrenr		/*
955145516Sdarrenr		 * currently "to <if>" and "to <if>:ip#" are not supported
956145516Sdarrenr		 * for IPv6
957145516Sdarrenr		 */
958145516Sdarrenr#if  (__FreeBSD_version >= 490000)
959145516Sdarrenr		return ip6_output(m0, NULL, NULL, 0, NULL, NULL, NULL);
960145516Sdarrenr#else
961145516Sdarrenr		return ip6_output(m0, NULL, NULL, 0, NULL, NULL);
962145516Sdarrenr#endif
963145516Sdarrenr	}
964145516Sdarrenr#endif
965145516Sdarrenr
966145516Sdarrenr	hlen = fin->fin_hlen;
967145516Sdarrenr	ip = mtod(m0, struct ip *);
968145516Sdarrenr
969145516Sdarrenr	/*
970145516Sdarrenr	 * Route packet.
971145516Sdarrenr	 */
972145516Sdarrenr	ro = &iproute;
973145516Sdarrenr	bzero((caddr_t)ro, sizeof (*ro));
974145516Sdarrenr	dst = (struct sockaddr_in *)&ro->ro_dst;
975145516Sdarrenr	dst->sin_family = AF_INET;
976145516Sdarrenr	dst->sin_addr = ip->ip_dst;
977145516Sdarrenr
978145516Sdarrenr	fr = fin->fin_fr;
979145516Sdarrenr	if (fdp != NULL)
980145516Sdarrenr		ifp = fdp->fd_ifp;
981145516Sdarrenr	else
982145516Sdarrenr		ifp = fin->fin_ifp;
983145516Sdarrenr
984145516Sdarrenr	if ((ifp == NULL) && (!fr || !(fr->fr_flags & FR_FASTROUTE))) {
985145516Sdarrenr		error = -2;
986145516Sdarrenr		goto bad;
987145516Sdarrenr	}
988145516Sdarrenr
989161356Sguido	if ((fdp != NULL) && (fdp->fd_ip.s_addr != 0))
990161356Sguido		dst->sin_addr = fdp->fd_ip;
991145516Sdarrenr
992145516Sdarrenr	dst->sin_len = sizeof(*dst);
993178888Sjulian	in_rtalloc(ro, 0);
994145516Sdarrenr
995145516Sdarrenr	if ((ifp == NULL) && (ro->ro_rt != NULL))
996145516Sdarrenr		ifp = ro->ro_rt->rt_ifp;
997145516Sdarrenr
998145516Sdarrenr	if ((ro->ro_rt == NULL) || (ifp == NULL)) {
999145516Sdarrenr		if (in_localaddr(ip->ip_dst))
1000145516Sdarrenr			error = EHOSTUNREACH;
1001145516Sdarrenr		else
1002145516Sdarrenr			error = ENETUNREACH;
1003145516Sdarrenr		goto bad;
1004145516Sdarrenr	}
1005145516Sdarrenr	if (ro->ro_rt->rt_flags & RTF_GATEWAY)
1006145516Sdarrenr		dst = (struct sockaddr_in *)ro->ro_rt->rt_gateway;
1007145516Sdarrenr	if (ro->ro_rt)
1008145516Sdarrenr		ro->ro_rt->rt_use++;
1009145516Sdarrenr
1010145516Sdarrenr	/*
1011145516Sdarrenr	 * For input packets which are being "fastrouted", they won't
1012145516Sdarrenr	 * go back through output filtering and miss their chance to get
1013170268Sdarrenr	 * NAT'd and counted.  Duplicated packets aren't considered to be
1014170268Sdarrenr	 * part of the normal packet stream, so do not NAT them or pass
1015170268Sdarrenr	 * them through stateful checking, etc.
1016145516Sdarrenr	 */
1017170268Sdarrenr	if ((fdp != &fr->fr_dif) && (fin->fin_out == 0)) {
1018145516Sdarrenr		sifp = fin->fin_ifp;
1019145516Sdarrenr		fin->fin_ifp = ifp;
1020145516Sdarrenr		fin->fin_out = 1;
1021145516Sdarrenr		(void) fr_acctpkt(fin, NULL);
1022145516Sdarrenr		fin->fin_fr = NULL;
1023145516Sdarrenr		if (!fr || !(fr->fr_flags & FR_RETMASK)) {
1024145516Sdarrenr			u_32_t pass;
1025145516Sdarrenr
1026170268Sdarrenr			if (fr_checkstate(fin, &pass) != NULL)
1027170268Sdarrenr				fr_statederef((ipstate_t **)&fin->fin_state);
1028145516Sdarrenr		}
1029145516Sdarrenr
1030145516Sdarrenr		switch (fr_checknatout(fin, NULL))
1031145516Sdarrenr		{
1032145516Sdarrenr		case 0 :
1033145516Sdarrenr			break;
1034145516Sdarrenr		case 1 :
1035170268Sdarrenr			fr_natderef((nat_t **)&fin->fin_nat);
1036145516Sdarrenr			ip->ip_sum = 0;
1037145516Sdarrenr			break;
1038145516Sdarrenr		case -1 :
1039145516Sdarrenr			error = -1;
1040173181Sdarrenr			goto bad;
1041145516Sdarrenr			break;
1042145516Sdarrenr		}
1043145516Sdarrenr
1044145516Sdarrenr		fin->fin_ifp = sifp;
1045145516Sdarrenr		fin->fin_out = 0;
1046145516Sdarrenr	} else
1047145516Sdarrenr		ip->ip_sum = 0;
1048145516Sdarrenr	/*
1049145516Sdarrenr	 * If small enough for interface, can just send directly.
1050145516Sdarrenr	 */
1051145516Sdarrenr	if (ip->ip_len <= ifp->if_mtu) {
1052145516Sdarrenr		ip->ip_len = htons(ip->ip_len);
1053145516Sdarrenr		ip->ip_off = htons(ip->ip_off);
1054145516Sdarrenr
1055145516Sdarrenr		if (!ip->ip_sum)
1056145516Sdarrenr			ip->ip_sum = in_cksum(m, hlen);
1057145516Sdarrenr		error = (*ifp->if_output)(ifp, m, (struct sockaddr *)dst,
1058191148Skmacy					  ro);
1059145516Sdarrenr		goto done;
1060145516Sdarrenr	}
1061145516Sdarrenr	/*
1062145516Sdarrenr	 * Too large for interface; fragment if possible.
1063145516Sdarrenr	 * Must be able to put at least 8 bytes per fragment.
1064145516Sdarrenr	 */
1065145516Sdarrenr	ip_off = ntohs(ip->ip_off);
1066145516Sdarrenr	if (ip_off & IP_DF) {
1067145516Sdarrenr		error = EMSGSIZE;
1068145516Sdarrenr		goto bad;
1069145516Sdarrenr	}
1070145516Sdarrenr	len = (ifp->if_mtu - hlen) &~ 7;
1071145516Sdarrenr	if (len < 8) {
1072145516Sdarrenr		error = EMSGSIZE;
1073145516Sdarrenr		goto bad;
1074145516Sdarrenr	}
1075145516Sdarrenr
1076145516Sdarrenr    {
1077145516Sdarrenr	int mhlen, firstlen = len;
1078145516Sdarrenr	struct mbuf **mnext = &m->m_act;
1079145516Sdarrenr
1080145516Sdarrenr	/*
1081145516Sdarrenr	 * Loop through length of segment after first fragment,
1082145516Sdarrenr	 * make new header and copy data of each part and link onto chain.
1083145516Sdarrenr	 */
1084145516Sdarrenr	m0 = m;
1085145516Sdarrenr	mhlen = sizeof (struct ip);
1086145516Sdarrenr	for (off = hlen + len; off < ip->ip_len; off += len) {
1087145516Sdarrenr#ifdef MGETHDR
1088145516Sdarrenr		MGETHDR(m, M_DONTWAIT, MT_HEADER);
1089145516Sdarrenr#else
1090145516Sdarrenr		MGET(m, M_DONTWAIT, MT_HEADER);
1091145516Sdarrenr#endif
1092145516Sdarrenr		if (m == 0) {
1093145516Sdarrenr			m = m0;
1094145516Sdarrenr			error = ENOBUFS;
1095145516Sdarrenr			goto bad;
1096145516Sdarrenr		}
1097145516Sdarrenr		m->m_data += max_linkhdr;
1098145516Sdarrenr		mhip = mtod(m, struct ip *);
1099145516Sdarrenr		bcopy((char *)ip, (char *)mhip, sizeof(*ip));
1100145516Sdarrenr		if (hlen > sizeof (struct ip)) {
1101145516Sdarrenr			mhlen = ip_optcopy(ip, mhip) + sizeof (struct ip);
1102145516Sdarrenr			IP_HL_A(mhip, mhlen >> 2);
1103145516Sdarrenr		}
1104145516Sdarrenr		m->m_len = mhlen;
1105145516Sdarrenr		mhip->ip_off = ((off - hlen) >> 3) + ip_off;
1106145516Sdarrenr		if (off + len >= ip->ip_len)
1107145516Sdarrenr			len = ip->ip_len - off;
1108145516Sdarrenr		else
1109145516Sdarrenr			mhip->ip_off |= IP_MF;
1110145516Sdarrenr		mhip->ip_len = htons((u_short)(len + mhlen));
1111161356Sguido		*mnext = m;
1112145516Sdarrenr		m->m_next = m_copy(m0, off, len);
1113145516Sdarrenr		if (m->m_next == 0) {
1114145516Sdarrenr			error = ENOBUFS;	/* ??? */
1115145516Sdarrenr			goto sendorfree;
1116145516Sdarrenr		}
1117145516Sdarrenr		m->m_pkthdr.len = mhlen + len;
1118145516Sdarrenr		m->m_pkthdr.rcvif = NULL;
1119145516Sdarrenr		mhip->ip_off = htons((u_short)mhip->ip_off);
1120145516Sdarrenr		mhip->ip_sum = 0;
1121145516Sdarrenr		mhip->ip_sum = in_cksum(m, mhlen);
1122145516Sdarrenr		mnext = &m->m_act;
1123145516Sdarrenr	}
1124145516Sdarrenr	/*
1125145516Sdarrenr	 * Update first fragment by trimming what's been copied out
1126145516Sdarrenr	 * and updating header, then send each fragment (in order).
1127145516Sdarrenr	 */
1128145516Sdarrenr	m_adj(m0, hlen + firstlen - ip->ip_len);
1129145516Sdarrenr	ip->ip_len = htons((u_short)(hlen + firstlen));
1130145516Sdarrenr	ip->ip_off = htons((u_short)IP_MF);
1131145516Sdarrenr	ip->ip_sum = 0;
1132145516Sdarrenr	ip->ip_sum = in_cksum(m0, hlen);
1133145516Sdarrenrsendorfree:
1134145516Sdarrenr	for (m = m0; m; m = m0) {
1135145516Sdarrenr		m0 = m->m_act;
1136145516Sdarrenr		m->m_act = 0;
1137145516Sdarrenr		if (error == 0)
1138145516Sdarrenr			error = (*ifp->if_output)(ifp, m,
1139191148Skmacy			    (struct sockaddr *)dst, ro);
1140145516Sdarrenr		else
1141145516Sdarrenr			FREE_MB_T(m);
1142145516Sdarrenr	}
1143145516Sdarrenr    }
1144145516Sdarrenrdone:
1145145516Sdarrenr	if (!error)
1146145516Sdarrenr		fr_frouteok[0]++;
1147145516Sdarrenr	else
1148145516Sdarrenr		fr_frouteok[1]++;
1149145516Sdarrenr
1150161356Sguido	if ((ro != NULL) && (ro->ro_rt != NULL)) {
1151145516Sdarrenr		RTFREE(ro->ro_rt);
1152145516Sdarrenr	}
1153145516Sdarrenr	*mpp = NULL;
1154145516Sdarrenr	return 0;
1155145516Sdarrenrbad:
1156145516Sdarrenr	if (error == EMSGSIZE) {
1157145516Sdarrenr		sifp = fin->fin_ifp;
1158145516Sdarrenr		code = fin->fin_icode;
1159145516Sdarrenr		fin->fin_icode = ICMP_UNREACH_NEEDFRAG;
1160145516Sdarrenr		fin->fin_ifp = ifp;
1161145516Sdarrenr		(void) fr_send_icmp_err(ICMP_UNREACH, fin, 1);
1162145516Sdarrenr		fin->fin_ifp = sifp;
1163145516Sdarrenr		fin->fin_icode = code;
1164145516Sdarrenr	}
1165145516Sdarrenr	FREE_MB_T(m);
1166145516Sdarrenr	goto done;
1167145516Sdarrenr}
1168145516Sdarrenr
1169145516Sdarrenr
1170145516Sdarrenrint fr_verifysrc(fin)
1171145516Sdarrenrfr_info_t *fin;
1172145516Sdarrenr{
1173145516Sdarrenr	struct sockaddr_in *dst;
1174145516Sdarrenr	struct route iproute;
1175145516Sdarrenr
1176145516Sdarrenr	bzero((char *)&iproute, sizeof(iproute));
1177145516Sdarrenr	dst = (struct sockaddr_in *)&iproute.ro_dst;
1178145516Sdarrenr	dst->sin_len = sizeof(*dst);
1179145516Sdarrenr	dst->sin_family = AF_INET;
1180145516Sdarrenr	dst->sin_addr = fin->fin_src;
1181178888Sjulian	in_rtalloc(&iproute, 0);
1182145516Sdarrenr	if (iproute.ro_rt == NULL)
1183145516Sdarrenr		return 0;
1184145516Sdarrenr	return (fin->fin_ifp == iproute.ro_rt->rt_ifp);
1185145516Sdarrenr}
1186145516Sdarrenr
1187145516Sdarrenr
1188145516Sdarrenr/*
1189145516Sdarrenr * return the first IP Address associated with an interface
1190145516Sdarrenr */
1191145516Sdarrenrint fr_ifpaddr(v, atype, ifptr, inp, inpmask)
1192145516Sdarrenrint v, atype;
1193145516Sdarrenrvoid *ifptr;
1194145516Sdarrenrstruct in_addr *inp, *inpmask;
1195145516Sdarrenr{
1196145516Sdarrenr#ifdef USE_INET6
1197145516Sdarrenr	struct in6_addr *inp6 = NULL;
1198145516Sdarrenr#endif
1199145516Sdarrenr	struct sockaddr *sock, *mask;
1200145516Sdarrenr	struct sockaddr_in *sin;
1201145516Sdarrenr	struct ifaddr *ifa;
1202145516Sdarrenr	struct ifnet *ifp;
1203145516Sdarrenr
1204145516Sdarrenr	if ((ifptr == NULL) || (ifptr == (void *)-1))
1205145516Sdarrenr		return -1;
1206145516Sdarrenr
1207145516Sdarrenr	sin = NULL;
1208145516Sdarrenr	ifp = ifptr;
1209145516Sdarrenr
1210145516Sdarrenr	if (v == 4)
1211145516Sdarrenr		inp->s_addr = 0;
1212145516Sdarrenr#ifdef USE_INET6
1213145516Sdarrenr	else if (v == 6)
1214145516Sdarrenr		bzero((char *)inp, sizeof(struct in6_addr));
1215145516Sdarrenr#endif
1216145516Sdarrenr#if  (__FreeBSD_version >= 300000)
1217145516Sdarrenr	ifa = TAILQ_FIRST(&ifp->if_addrhead);
1218145516Sdarrenr#else
1219145516Sdarrenr	ifa = ifp->if_addrlist;
1220145516Sdarrenr#endif /* __FreeBSD_version >= 300000 */
1221145516Sdarrenr
1222145516Sdarrenr	sock = ifa->ifa_addr;
1223145516Sdarrenr	while (sock != NULL && ifa != NULL) {
1224145516Sdarrenr		sin = (struct sockaddr_in *)sock;
1225145516Sdarrenr		if ((v == 4) && (sin->sin_family == AF_INET))
1226145516Sdarrenr			break;
1227145516Sdarrenr#ifdef USE_INET6
1228145516Sdarrenr		if ((v == 6) && (sin->sin_family == AF_INET6)) {
1229145516Sdarrenr			inp6 = &((struct sockaddr_in6 *)sin)->sin6_addr;
1230145516Sdarrenr			if (!IN6_IS_ADDR_LINKLOCAL(inp6) &&
1231145516Sdarrenr			    !IN6_IS_ADDR_LOOPBACK(inp6))
1232145516Sdarrenr				break;
1233145516Sdarrenr		}
1234145516Sdarrenr#endif
1235145516Sdarrenr#if (__FreeBSD_version >= 300000)
1236145516Sdarrenr		ifa = TAILQ_NEXT(ifa, ifa_link);
1237145516Sdarrenr#else
1238145516Sdarrenr		ifa = ifa->ifa_next;
1239145516Sdarrenr#endif /* __FreeBSD_version >= 300000 */
1240145516Sdarrenr		if (ifa != NULL)
1241145516Sdarrenr			sock = ifa->ifa_addr;
1242145516Sdarrenr	}
1243145516Sdarrenr
1244145516Sdarrenr	if (ifa == NULL || sin == NULL)
1245145516Sdarrenr		return -1;
1246145516Sdarrenr
1247145516Sdarrenr	mask = ifa->ifa_netmask;
1248145516Sdarrenr	if (atype == FRI_BROADCAST)
1249145516Sdarrenr		sock = ifa->ifa_broadaddr;
1250145516Sdarrenr	else if (atype == FRI_PEERADDR)
1251145516Sdarrenr		sock = ifa->ifa_dstaddr;
1252145516Sdarrenr
1253161356Sguido	if (sock == NULL)
1254161356Sguido		return -1;
1255161356Sguido
1256145516Sdarrenr#ifdef USE_INET6
1257145516Sdarrenr	if (v == 6) {
1258145516Sdarrenr		return fr_ifpfillv6addr(atype, (struct sockaddr_in6 *)sock,
1259145516Sdarrenr					(struct sockaddr_in6 *)mask,
1260145516Sdarrenr					inp, inpmask);
1261145516Sdarrenr	}
1262145516Sdarrenr#endif
1263145516Sdarrenr	return fr_ifpfillv4addr(atype, (struct sockaddr_in *)sock,
1264145516Sdarrenr				(struct sockaddr_in *)mask, inp, inpmask);
1265145516Sdarrenr}
1266145516Sdarrenr
1267145516Sdarrenr
1268145516Sdarrenru_32_t fr_newisn(fin)
1269145516Sdarrenrfr_info_t *fin;
1270145516Sdarrenr{
1271145516Sdarrenr	u_32_t newiss;
1272145516Sdarrenr#if  (__FreeBSD_version >= 400000)
1273145516Sdarrenr	newiss = arc4random();
1274145516Sdarrenr#else
1275145516Sdarrenr	static iss_seq_off = 0;
1276145516Sdarrenr	u_char hash[16];
1277145516Sdarrenr	MD5_CTX ctx;
1278145516Sdarrenr
1279145516Sdarrenr	/*
1280145516Sdarrenr	 * Compute the base value of the ISS.  It is a hash
1281145516Sdarrenr	 * of (saddr, sport, daddr, dport, secret).
1282145516Sdarrenr	 */
1283145516Sdarrenr	MD5Init(&ctx);
1284145516Sdarrenr
1285145516Sdarrenr	MD5Update(&ctx, (u_char *) &fin->fin_fi.fi_src,
1286145516Sdarrenr		  sizeof(fin->fin_fi.fi_src));
1287145516Sdarrenr	MD5Update(&ctx, (u_char *) &fin->fin_fi.fi_dst,
1288145516Sdarrenr		  sizeof(fin->fin_fi.fi_dst));
1289145516Sdarrenr	MD5Update(&ctx, (u_char *) &fin->fin_dat, sizeof(fin->fin_dat));
1290145516Sdarrenr
1291145516Sdarrenr	MD5Update(&ctx, ipf_iss_secret, sizeof(ipf_iss_secret));
1292145516Sdarrenr
1293145516Sdarrenr	MD5Final(hash, &ctx);
1294145516Sdarrenr
1295145516Sdarrenr	memcpy(&newiss, hash, sizeof(newiss));
1296145516Sdarrenr
1297145516Sdarrenr	/*
1298145516Sdarrenr	 * Now increment our "timer", and add it in to
1299145516Sdarrenr	 * the computed value.
1300145516Sdarrenr	 *
1301145516Sdarrenr	 * XXX Use `addin'?
1302145516Sdarrenr	 * XXX TCP_ISSINCR too large to use?
1303145516Sdarrenr	 */
1304145516Sdarrenr	iss_seq_off += 0x00010000;
1305145516Sdarrenr	newiss += iss_seq_off;
1306145516Sdarrenr#endif
1307145516Sdarrenr	return newiss;
1308145516Sdarrenr}
1309145516Sdarrenr
1310145516Sdarrenr
1311145516Sdarrenr/* ------------------------------------------------------------------------ */
1312145516Sdarrenr/* Function:    fr_nextipid                                                 */
1313145516Sdarrenr/* Returns:     int - 0 == success, -1 == error (packet should be droppped) */
1314145516Sdarrenr/* Parameters:  fin(I) - pointer to packet information                      */
1315145516Sdarrenr/*                                                                          */
1316145516Sdarrenr/* Returns the next IPv4 ID to use for this packet.                         */
1317145516Sdarrenr/* ------------------------------------------------------------------------ */
1318145516Sdarrenru_short fr_nextipid(fin)
1319145516Sdarrenrfr_info_t *fin;
1320145516Sdarrenr{
1321145516Sdarrenr#ifndef	RANDOM_IP_ID
1322145516Sdarrenr	static u_short ipid = 0;
1323145516Sdarrenr	u_short id;
1324145516Sdarrenr
1325145516Sdarrenr	MUTEX_ENTER(&ipf_rw);
1326145516Sdarrenr	id = ipid++;
1327145516Sdarrenr	MUTEX_EXIT(&ipf_rw);
1328145516Sdarrenr#else
1329145516Sdarrenr	u_short id;
1330145516Sdarrenr
1331145516Sdarrenr	id = ip_randomid();
1332145516Sdarrenr#endif
1333145516Sdarrenr
1334145516Sdarrenr	return id;
1335145516Sdarrenr}
1336145516Sdarrenr
1337145516Sdarrenr
1338145516SdarrenrINLINE void fr_checkv4sum(fin)
1339145516Sdarrenrfr_info_t *fin;
1340145516Sdarrenr{
1341145516Sdarrenr#ifdef CSUM_DATA_VALID
1342145516Sdarrenr	int manual = 0;
1343145516Sdarrenr	u_short sum;
1344145516Sdarrenr	ip_t *ip;
1345145516Sdarrenr	mb_t *m;
1346145516Sdarrenr
1347145516Sdarrenr	if ((fin->fin_flx & FI_NOCKSUM) != 0)
1348145516Sdarrenr		return;
1349145516Sdarrenr
1350172776Sdarrenr	if (fin->fin_cksum != 0)
1351172776Sdarrenr		return;
1352172776Sdarrenr
1353145516Sdarrenr	m = fin->fin_m;
1354145516Sdarrenr	if (m == NULL) {
1355145516Sdarrenr		manual = 1;
1356145516Sdarrenr		goto skipauto;
1357145516Sdarrenr	}
1358145516Sdarrenr	ip = fin->fin_ip;
1359145516Sdarrenr
1360145516Sdarrenr	if (m->m_pkthdr.csum_flags & CSUM_DATA_VALID) {
1361145516Sdarrenr		if (m->m_pkthdr.csum_flags & CSUM_PSEUDO_HDR)
1362145516Sdarrenr			sum = m->m_pkthdr.csum_data;
1363145516Sdarrenr		else
1364145516Sdarrenr			sum = in_pseudo(ip->ip_src.s_addr, ip->ip_dst.s_addr,
1365145516Sdarrenr					htonl(m->m_pkthdr.csum_data +
1366145516Sdarrenr					fin->fin_ip->ip_len + fin->fin_p));
1367145516Sdarrenr		sum ^= 0xffff;
1368172776Sdarrenr		if (sum != 0) {
1369145516Sdarrenr			fin->fin_flx |= FI_BAD;
1370172776Sdarrenr			fin->fin_cksum = -1;
1371172776Sdarrenr		} else {
1372172776Sdarrenr			fin->fin_cksum = 1;
1373172776Sdarrenr		}
1374145516Sdarrenr	} else
1375145516Sdarrenr		manual = 1;
1376145516Sdarrenrskipauto:
1377145516Sdarrenr# ifdef IPFILTER_CKSUM
1378145516Sdarrenr	if (manual != 0)
1379145516Sdarrenr		if (fr_checkl4sum(fin) == -1)
1380145516Sdarrenr			fin->fin_flx |= FI_BAD;
1381145516Sdarrenr# else
1382145516Sdarrenr	;
1383145516Sdarrenr# endif
1384145516Sdarrenr#else
1385145516Sdarrenr# ifdef IPFILTER_CKSUM
1386145516Sdarrenr	if (fr_checkl4sum(fin) == -1)
1387145516Sdarrenr		fin->fin_flx |= FI_BAD;
1388145516Sdarrenr# endif
1389145516Sdarrenr#endif
1390145516Sdarrenr}
1391145516Sdarrenr
1392145516Sdarrenr
1393145516Sdarrenr#ifdef USE_INET6
1394145516SdarrenrINLINE void fr_checkv6sum(fin)
1395145516Sdarrenrfr_info_t *fin;
1396145516Sdarrenr{
1397145516Sdarrenr# ifdef IPFILTER_CKSUM
1398145516Sdarrenr	if (fr_checkl4sum(fin) == -1)
1399145516Sdarrenr		fin->fin_flx |= FI_BAD;
1400145516Sdarrenr# endif
1401145516Sdarrenr}
1402145516Sdarrenr#endif /* USE_INET6 */
1403145516Sdarrenr
1404145516Sdarrenr
1405145516Sdarrenrsize_t mbufchainlen(m0)
1406145516Sdarrenrstruct mbuf *m0;
1407145516Sdarrenr{
1408145516Sdarrenr	size_t len;
1409145516Sdarrenr
1410145516Sdarrenr	if ((m0->m_flags & M_PKTHDR) != 0) {
1411145516Sdarrenr		len = m0->m_pkthdr.len;
1412145516Sdarrenr	} else {
1413145516Sdarrenr		struct mbuf *m;
1414145516Sdarrenr
1415145516Sdarrenr		for (m = m0, len = 0; m != NULL; m = m->m_next)
1416145516Sdarrenr			len += m->m_len;
1417145516Sdarrenr	}
1418145516Sdarrenr	return len;
1419145516Sdarrenr}
1420145516Sdarrenr
1421145516Sdarrenr
1422145516Sdarrenr/* ------------------------------------------------------------------------ */
1423145516Sdarrenr/* Function:    fr_pullup                                                   */
1424145516Sdarrenr/* Returns:     NULL == pullup failed, else pointer to protocol header      */
1425145516Sdarrenr/* Parameters:  m(I)   - pointer to buffer where data packet starts         */
1426145516Sdarrenr/*              fin(I) - pointer to packet information                      */
1427145516Sdarrenr/*              len(I) - number of bytes to pullup                          */
1428145516Sdarrenr/*                                                                          */
1429145516Sdarrenr/* Attempt to move at least len bytes (from the start of the buffer) into a */
1430145516Sdarrenr/* single buffer for ease of access.  Operating system native functions are */
1431145516Sdarrenr/* used to manage buffers - if necessary.  If the entire packet ends up in  */
1432145516Sdarrenr/* a single buffer, set the FI_COALESCE flag even though fr_coalesce() has  */
1433145516Sdarrenr/* not been called.  Both fin_ip and fin_dp are updated before exiting _IF_ */
1434145516Sdarrenr/* and ONLY if the pullup succeeds.                                         */
1435145516Sdarrenr/*                                                                          */
1436145516Sdarrenr/* We assume that 'min' is a pointer to a buffer that is part of the chain  */
1437145516Sdarrenr/* of buffers that starts at *fin->fin_mp.                                  */
1438145516Sdarrenr/* ------------------------------------------------------------------------ */
1439145516Sdarrenrvoid *fr_pullup(min, fin, len)
1440145516Sdarrenrmb_t *min;
1441145516Sdarrenrfr_info_t *fin;
1442145516Sdarrenrint len;
1443145516Sdarrenr{
1444145516Sdarrenr	int out = fin->fin_out, dpoff, ipoff;
1445145516Sdarrenr	mb_t *m = min;
1446145516Sdarrenr	char *ip;
1447145516Sdarrenr
1448145516Sdarrenr	if (m == NULL)
1449145516Sdarrenr		return NULL;
1450145516Sdarrenr
1451145516Sdarrenr	ip = (char *)fin->fin_ip;
1452145516Sdarrenr	if ((fin->fin_flx & FI_COALESCE) != 0)
1453145516Sdarrenr		return ip;
1454145516Sdarrenr
1455145516Sdarrenr	ipoff = fin->fin_ipoff;
1456145516Sdarrenr	if (fin->fin_dp != NULL)
1457145516Sdarrenr		dpoff = (char *)fin->fin_dp - (char *)ip;
1458145516Sdarrenr	else
1459145516Sdarrenr		dpoff = 0;
1460145516Sdarrenr
1461145516Sdarrenr	if (M_LEN(m) < len) {
1462145516Sdarrenr#ifdef MHLEN
1463145516Sdarrenr		/*
1464145516Sdarrenr		 * Assume that M_PKTHDR is set and just work with what is left
1465145516Sdarrenr		 * rather than check..
1466145516Sdarrenr		 * Should not make any real difference, anyway.
1467145516Sdarrenr		 */
1468145516Sdarrenr		if (len > MHLEN)
1469145516Sdarrenr#else
1470145516Sdarrenr		if (len > MLEN)
1471145516Sdarrenr#endif
1472145516Sdarrenr		{
1473145516Sdarrenr#ifdef HAVE_M_PULLDOWN
1474145516Sdarrenr			if (m_pulldown(m, 0, len, NULL) == NULL)
1475145516Sdarrenr				m = NULL;
1476145516Sdarrenr#else
1477145516Sdarrenr			FREE_MB_T(*fin->fin_mp);
1478145516Sdarrenr			m = NULL;
1479145516Sdarrenr#endif
1480145516Sdarrenr		} else
1481145516Sdarrenr		{
1482145516Sdarrenr			m = m_pullup(m, len);
1483145516Sdarrenr		}
1484145516Sdarrenr		*fin->fin_mp = m;
1485145516Sdarrenr		if (m == NULL) {
1486172776Sdarrenr			fin->fin_m = NULL;
1487145516Sdarrenr			ATOMIC_INCL(frstats[out].fr_pull[1]);
1488145516Sdarrenr			return NULL;
1489145516Sdarrenr		}
1490172776Sdarrenr
1491172776Sdarrenr		while (M_LEN(m) == 0) {
1492172776Sdarrenr			m = m->m_next;
1493172776Sdarrenr		}
1494172776Sdarrenr		fin->fin_m = m;
1495145516Sdarrenr		ip = MTOD(m, char *) + ipoff;
1496145516Sdarrenr	}
1497145516Sdarrenr
1498145516Sdarrenr	ATOMIC_INCL(frstats[out].fr_pull[0]);
1499145516Sdarrenr	fin->fin_ip = (ip_t *)ip;
1500145516Sdarrenr	if (fin->fin_dp != NULL)
1501145516Sdarrenr		fin->fin_dp = (char *)fin->fin_ip + dpoff;
1502145516Sdarrenr
1503145516Sdarrenr	if (len == fin->fin_plen)
1504145516Sdarrenr		fin->fin_flx |= FI_COALESCE;
1505145516Sdarrenr	return ip;
1506145516Sdarrenr}
1507170268Sdarrenr
1508170268Sdarrenr
1509170268Sdarrenrint ipf_inject(fin, m)
1510170268Sdarrenrfr_info_t *fin;
1511170268Sdarrenrmb_t *m;
1512170268Sdarrenr{
1513170268Sdarrenr	int error = 0;
1514170268Sdarrenr
1515170268Sdarrenr	if (fin->fin_out == 0) {
1516170268Sdarrenr#if (__FreeBSD_version >= 501000)
1517170268Sdarrenr		netisr_dispatch(NETISR_IP, m);
1518170268Sdarrenr#else
1519170268Sdarrenr		struct ifqueue *ifq;
1520170268Sdarrenr
1521170268Sdarrenr		ifq = &ipintrq;
1522170268Sdarrenr
1523170268Sdarrenr# ifdef _IF_QFULL
1524170268Sdarrenr		if (_IF_QFULL(ifq))
1525170268Sdarrenr# else
1526170268Sdarrenr		if (IF_QFULL(ifq))
1527170268Sdarrenr# endif
1528170268Sdarrenr		{
1529170268Sdarrenr# ifdef _IF_DROP
1530170268Sdarrenr			_IF_DROP(ifq);
1531170268Sdarrenr# else
1532170268Sdarrenr			IF_DROP(ifq);
1533170268Sdarrenr# endif
1534170268Sdarrenr			FREE_MB_T(m);
1535170268Sdarrenr			error = ENOBUFS;
1536170268Sdarrenr		} else {
1537170268Sdarrenr			IF_ENQUEUE(ifq, m);
1538170268Sdarrenr		}
1539170268Sdarrenr#endif
1540170268Sdarrenr	} else {
1541173931Sdarrenr		fin->fin_ip->ip_len = ntohs(fin->fin_ip->ip_len);
1542173931Sdarrenr		fin->fin_ip->ip_off = ntohs(fin->fin_ip->ip_off);
1543170268Sdarrenr#if (__FreeBSD_version >= 470102)
1544170268Sdarrenr		error = ip_output(m, NULL, NULL, IP_FORWARDING, NULL, NULL);
1545170268Sdarrenr#else
1546170268Sdarrenr		error = ip_output(m, NULL, NULL, IP_FORWARDING, NULL);
1547170268Sdarrenr#endif
1548170268Sdarrenr	}
1549170268Sdarrenr
1550170268Sdarrenr	return error;
1551170268Sdarrenr}
1552172776Sdarrenr
1553172776Sdarrenrint ipf_pfil_unhook(void) {
1554172776Sdarrenr#if defined(NETBSD_PF) && (__FreeBSD_version >= 500011)
1555172776Sdarrenr# if __FreeBSD_version >= 501108
1556172776Sdarrenr	struct pfil_head *ph_inet;
1557172776Sdarrenr#  ifdef USE_INET6
1558172776Sdarrenr	struct pfil_head *ph_inet6;
1559172776Sdarrenr#  endif
1560172776Sdarrenr# endif
1561172776Sdarrenr#endif
1562172776Sdarrenr
1563172776Sdarrenr#ifdef NETBSD_PF
1564172776Sdarrenr# if (__FreeBSD_version >= 500011)
1565172776Sdarrenr#  if (__FreeBSD_version >= 501108)
1566172776Sdarrenr	ph_inet = pfil_head_get(PFIL_TYPE_AF, AF_INET);
1567172776Sdarrenr	if (ph_inet != NULL)
1568172776Sdarrenr		pfil_remove_hook((void *)fr_check_wrapper, NULL,
1569172776Sdarrenr		    PFIL_IN|PFIL_OUT|PFIL_WAITOK, ph_inet);
1570172776Sdarrenr#  else
1571172776Sdarrenr	pfil_remove_hook((void *)fr_check, PFIL_IN|PFIL_OUT|PFIL_WAITOK,
1572172776Sdarrenr	    &inetsw[ip_protox[IPPROTO_IP]].pr_pfh);
1573172776Sdarrenr#  endif
1574172776Sdarrenr# else
1575172776Sdarrenr	pfil_remove_hook((void *)fr_check, PFIL_IN|PFIL_OUT|PFIL_WAITOK);
1576172776Sdarrenr# endif
1577172776Sdarrenr# ifdef USE_INET6
1578172776Sdarrenr#  if (__FreeBSD_version >= 501108)
1579172776Sdarrenr	ph_inet6 = pfil_head_get(PFIL_TYPE_AF, AF_INET6);
1580172776Sdarrenr	if (ph_inet6 != NULL)
1581172776Sdarrenr		pfil_remove_hook((void *)fr_check_wrapper6, NULL,
1582172776Sdarrenr		    PFIL_IN|PFIL_OUT|PFIL_WAITOK, ph_inet6);
1583172776Sdarrenr#  else
1584172776Sdarrenr	pfil_remove_hook((void *)fr_check, PFIL_IN|PFIL_OUT|PFIL_WAITOK,
1585172776Sdarrenr				 &inet6sw[ip6_protox[IPPROTO_IPV6]].pr_pfh);
1586172776Sdarrenr#  endif
1587172776Sdarrenr# endif
1588172776Sdarrenr#endif
1589172776Sdarrenr
1590172776Sdarrenr	return (0);
1591172776Sdarrenr}
1592172776Sdarrenr
1593172776Sdarrenrint ipf_pfil_hook(void) {
1594172776Sdarrenr#if defined(NETBSD_PF) && (__FreeBSD_version >= 500011)
1595172776Sdarrenr# if __FreeBSD_version >= 501108
1596172776Sdarrenr	struct pfil_head *ph_inet;
1597172776Sdarrenr#  ifdef USE_INET6
1598172776Sdarrenr	struct pfil_head *ph_inet6;
1599172776Sdarrenr#  endif
1600172776Sdarrenr# endif
1601172776Sdarrenr#endif
1602172776Sdarrenr
1603172776Sdarrenr# ifdef NETBSD_PF
1604172776Sdarrenr#  if __FreeBSD_version >= 500011
1605172776Sdarrenr#   if __FreeBSD_version >= 501108
1606172776Sdarrenr	ph_inet = pfil_head_get(PFIL_TYPE_AF, AF_INET);
1607172776Sdarrenr#    ifdef USE_INET6
1608172776Sdarrenr	ph_inet6 = pfil_head_get(PFIL_TYPE_AF, AF_INET6);
1609172776Sdarrenr#    endif
1610172776Sdarrenr	if (ph_inet == NULL
1611172776Sdarrenr#    ifdef USE_INET6
1612172776Sdarrenr	    && ph_inet6 == NULL
1613172776Sdarrenr#    endif
1614172776Sdarrenr	   )
1615172776Sdarrenr		return ENODEV;
1616172776Sdarrenr
1617172776Sdarrenr	if (ph_inet != NULL)
1618172776Sdarrenr		pfil_add_hook((void *)fr_check_wrapper, NULL,
1619172776Sdarrenr		    PFIL_IN|PFIL_OUT|PFIL_WAITOK, ph_inet);
1620172776Sdarrenr#  else
1621172776Sdarrenr	pfil_add_hook((void *)fr_check, PFIL_IN|PFIL_OUT|PFIL_WAITOK,
1622172776Sdarrenr			      &inetsw[ip_protox[IPPROTO_IP]].pr_pfh);
1623172776Sdarrenr#  endif
1624172776Sdarrenr#  else
1625172776Sdarrenr	pfil_add_hook((void *)fr_check, PFIL_IN|PFIL_OUT|PFIL_WAITOK);
1626172776Sdarrenr#  endif
1627172776Sdarrenr#  ifdef USE_INET6
1628172776Sdarrenr#   if __FreeBSD_version >= 501108
1629172776Sdarrenr	if (ph_inet6 != NULL)
1630172776Sdarrenr		pfil_add_hook((void *)fr_check_wrapper6, NULL,
1631172776Sdarrenr				      PFIL_IN|PFIL_OUT|PFIL_WAITOK, ph_inet6);
1632172776Sdarrenr#   else
1633172776Sdarrenr	pfil_add_hook((void *)fr_check, PFIL_IN|PFIL_OUT|PFIL_WAITOK,
1634172776Sdarrenr			      &inet6sw[ip6_protox[IPPROTO_IPV6]].pr_pfh);
1635172776Sdarrenr#   endif
1636172776Sdarrenr#  endif
1637172776Sdarrenr# endif
1638172776Sdarrenr	return (0);
1639172776Sdarrenr}
1640172776Sdarrenr
1641172776Sdarrenrvoid
1642172776Sdarrenripf_event_reg(void)
1643172776Sdarrenr{
1644172776Sdarrenr#if (__FreeBSD_version >= 502103)
1645172776Sdarrenr	ipf_arrivetag =  EVENTHANDLER_REGISTER(ifnet_arrival_event, \
1646172776Sdarrenr					       ipf_ifevent, NULL, \
1647172776Sdarrenr					       EVENTHANDLER_PRI_ANY);
1648172776Sdarrenr	ipf_departtag =  EVENTHANDLER_REGISTER(ifnet_departure_event, \
1649172776Sdarrenr					       ipf_ifevent, NULL, \
1650172776Sdarrenr					       EVENTHANDLER_PRI_ANY);
1651172776Sdarrenr	ipf_clonetag =  EVENTHANDLER_REGISTER(if_clone_event, ipf_ifevent, \
1652172776Sdarrenr					      NULL, EVENTHANDLER_PRI_ANY);
1653172776Sdarrenr#endif
1654172776Sdarrenr}
1655172776Sdarrenr
1656172776Sdarrenrvoid
1657172776Sdarrenripf_event_dereg(void)
1658172776Sdarrenr{
1659172776Sdarrenr#if (__FreeBSD_version >= 502103)
1660172776Sdarrenr	if (ipf_arrivetag != NULL) {
1661172776Sdarrenr		EVENTHANDLER_DEREGISTER(ifnet_arrival_event, ipf_arrivetag);
1662172776Sdarrenr	}
1663172776Sdarrenr	if (ipf_departtag != NULL) {
1664172776Sdarrenr		EVENTHANDLER_DEREGISTER(ifnet_departure_event, ipf_departtag);
1665172776Sdarrenr	}
1666172776Sdarrenr	if (ipf_clonetag != NULL) {
1667172776Sdarrenr		EVENTHANDLER_DEREGISTER(if_clone_event, ipf_clonetag);
1668172776Sdarrenr	}
1669172776Sdarrenr#endif
1670172776Sdarrenr}
1671