ip_fil_freebsd.c revision 173181
1219820Sjeff/*	$FreeBSD: head/sys/contrib/ipfilter/netinet/ip_fil_freebsd.c 173181 2007-10-30 15:23:27Z darrenr $	*/
2219820Sjeff
3219820Sjeff/*
4219820Sjeff * Copyright (C) 1993-2003 by Darren Reed.
5219820Sjeff *
6219820Sjeff * See the IPFILTER.LICENCE file for details on licencing.
7219820Sjeff */
8219820Sjeff#if !defined(lint)
9219820Sjeffstatic const char sccsid[] = "@(#)ip_fil.c	2.41 6/5/96 (C) 1993-2000 Darren Reed";
10219820Sjeffstatic const char rcsid[] = "@(#)$Id: ip_fil_freebsd.c,v 2.53.2.50 2007/09/20 12:51:50 darrenr Exp $";
11219820Sjeff#endif
12219820Sjeff
13219820Sjeff#if defined(KERNEL) || defined(_KERNEL)
14219820Sjeff# undef KERNEL
15219820Sjeff# undef _KERNEL
16219820Sjeff# define	KERNEL	1
17219820Sjeff# define	_KERNEL	1
18219820Sjeff#endif
19219820Sjeff#if defined(__FreeBSD_version) && (__FreeBSD_version >= 400000) && \
20219820Sjeff    !defined(KLD_MODULE) && !defined(IPFILTER_LKM)
21219820Sjeff# include "opt_inet6.h"
22219820Sjeff#endif
23219820Sjeff#if defined(__FreeBSD_version) && (__FreeBSD_version >= 440000) && \
24219820Sjeff    !defined(KLD_MODULE) && !defined(IPFILTER_LKM)
25219820Sjeff# include "opt_random_ip_id.h"
26219820Sjeff#endif
27219820Sjeff#include <sys/param.h>
28219820Sjeff#if defined(__FreeBSD__) && !defined(__FreeBSD_version)
29219820Sjeff# if defined(IPFILTER_LKM)
30219820Sjeff#  ifndef __FreeBSD_cc_version
31219820Sjeff#   include <osreldate.h>
32219820Sjeff#  else
33219820Sjeff#   if __FreeBSD_cc_version < 430000
34219820Sjeff#    include <osreldate.h>
35219820Sjeff#   endif
36219820Sjeff#  endif
37219820Sjeff# endif
38219820Sjeff#endif
39219820Sjeff#include <sys/errno.h>
40219820Sjeff#include <sys/types.h>
41219820Sjeff#include <sys/file.h>
42219820Sjeff#if __FreeBSD_version >= 220000
43219820Sjeff# include <sys/fcntl.h>
44219820Sjeff# include <sys/filio.h>
45219820Sjeff#else
46219820Sjeff# include <sys/ioctl.h>
47219820Sjeff#endif
48219820Sjeff#include <sys/time.h>
49219820Sjeff#include <sys/systm.h>
50219820Sjeff#if (__FreeBSD_version >= 300000)
51219820Sjeff# include <sys/dirent.h>
52219820Sjeff#else
53219820Sjeff# include <sys/dir.h>
54219820Sjeff#endif
55219820Sjeff#if !defined(__hpux)
56219820Sjeff# include <sys/mbuf.h>
57219820Sjeff#endif
58219820Sjeff#include <sys/protosw.h>
59219820Sjeff#include <sys/socket.h>
60219820Sjeff#if __FreeBSD_version >= 500043
61219820Sjeff# include <sys/selinfo.h>
62219820Sjeff#else
63219820Sjeff# include <sys/select.h>
64219820Sjeff#endif
65219820Sjeff
66219820Sjeff#include <net/if.h>
67219820Sjeff#if __FreeBSD_version >= 300000
68219820Sjeff# include <net/if_var.h>
69219820Sjeff# if __FreeBSD_version >= 500043
70219820Sjeff#  include <net/netisr.h>
71219820Sjeff# endif
72219820Sjeff# if !defined(IPFILTER_LKM)
73219820Sjeff#  include "opt_ipfilter.h"
74219820Sjeff# endif
75219820Sjeff#endif
76219820Sjeff#include <net/route.h>
77219820Sjeff#include <netinet/in.h>
78219820Sjeff#include <netinet/in_var.h>
79219820Sjeff#include <netinet/in_systm.h>
80219820Sjeff#include <netinet/ip.h>
81219820Sjeff#include <netinet/ip_var.h>
82219820Sjeff#include <netinet/tcp.h>
83219820Sjeff#if defined(__osf__)
84219820Sjeff# include <netinet/tcp_timer.h>
85219820Sjeff#endif
86219820Sjeff#include <netinet/udp.h>
87219820Sjeff#include <netinet/tcpip.h>
88219820Sjeff#include <netinet/ip_icmp.h>
89219820Sjeff#ifndef _KERNEL
90219820Sjeff# include "netinet/ipf.h"
91219820Sjeff#endif
92219820Sjeff#include "netinet/ip_compat.h"
93219820Sjeff#ifdef USE_INET6
94219820Sjeff# include <netinet/icmp6.h>
95219820Sjeff#endif
96219820Sjeff#include "netinet/ip_fil.h"
97219820Sjeff#include "netinet/ip_nat.h"
98219820Sjeff#include "netinet/ip_frag.h"
99219820Sjeff#include "netinet/ip_state.h"
100219820Sjeff#include "netinet/ip_proxy.h"
101219820Sjeff#include "netinet/ip_auth.h"
102219820Sjeff#ifdef	IPFILTER_SYNC
103219820Sjeff#include "netinet/ip_sync.h"
104219820Sjeff#endif
105219820Sjeff#ifdef	IPFILTER_SCAN
106219820Sjeff#include "netinet/ip_scan.h"
107219820Sjeff#endif
108219820Sjeff#include "netinet/ip_pool.h"
109219820Sjeff#if defined(__FreeBSD_version) && (__FreeBSD_version >= 300000)
110219820Sjeff# include <sys/malloc.h>
111219820Sjeff#endif
112219820Sjeff#include <sys/kernel.h>
113219820Sjeff#ifdef CSUM_DATA_VALID
114219820Sjeff#include <machine/in_cksum.h>
115219820Sjeff#endif
116219820Sjeffextern	int	ip_optcopy __P((struct ip *, struct ip *));
117219820Sjeff
118219820Sjeff#if (__FreeBSD_version > 460000)
119219820Sjeffextern	int	path_mtu_discovery;
120219820Sjeff#endif
121219820Sjeff
122219820Sjeff# ifdef IPFILTER_M_IPFILTER
123219820SjeffMALLOC_DEFINE(M_IPFILTER, "ipfilter", "IP Filter packet filter data structures");
124219820Sjeff# endif
125219820Sjeff
126219820Sjeff
127219820Sjeff#if !defined(__osf__)
128219820Sjeffextern	struct	protosw	inetsw[];
129219820Sjeff#endif
130219820Sjeff
131219820Sjeffstatic	int	(*fr_savep) __P((ip_t *, int, void *, int, struct mbuf **));
132219820Sjeffstatic	int	fr_send_ip __P((fr_info_t *, mb_t *, mb_t **));
133219820Sjeff# ifdef USE_MUTEXES
134219820Sjeffipfmutex_t	ipl_mutex, ipf_authmx, ipf_rw, ipf_stinsert;
135219820Sjeffipfmutex_t	ipf_nat_new, ipf_natio, ipf_timeoutlock;
136219820Sjeffipfrwlock_t	ipf_mutex, ipf_global, ipf_ipidfrag, ipf_frcache, ipf_tokens;
137219820Sjeffipfrwlock_t	ipf_frag, ipf_state, ipf_nat, ipf_natfrag, ipf_auth;
138219820Sjeff# endif
139219820Sjeffint		ipf_locks_done = 0;
140219820Sjeff
141219820Sjeff#if (__FreeBSD_version >= 300000)
142219820Sjeffstruct callout_handle fr_slowtimer_ch;
143219820Sjeff#endif
144219820Sjeffstruct	selinfo	ipfselwait[IPL_LOGSIZE];
145219820Sjeff
146219820Sjeff#if (__FreeBSD_version >= 500011)
147219820Sjeff# include <sys/conf.h>
148219820Sjeff# if defined(NETBSD_PF)
149219820Sjeff#  include <net/pfil.h>
150219820Sjeff#  include <netinet/ipprotosw.h>
151219820Sjeff/*
152219820Sjeff * We provide the fr_checkp name just to minimize changes later.
153219820Sjeff */
154219820Sjeffint (*fr_checkp) __P((ip_t *ip, int hlen, void *ifp, int out, mb_t **mp));
155219820Sjeff# endif /* NETBSD_PF */
156219820Sjeff#endif /* __FreeBSD_version >= 500011 */
157219820Sjeff
158219820Sjeff
159219820Sjeff#if (__FreeBSD_version >= 502103)
160219820Sjeffstatic eventhandler_tag ipf_arrivetag, ipf_departtag, ipf_clonetag;
161219820Sjeff
162219820Sjeffstatic void ipf_ifevent(void *arg);
163219820Sjeff
164219820Sjeffstatic void ipf_ifevent(arg)
165219820Sjeffvoid *arg;
166219820Sjeff{
167219820Sjeff        frsync(NULL);
168219820Sjeff}
169219820Sjeff#endif
170219820Sjeff
171219820Sjeff
172219820Sjeff#if (__FreeBSD_version >= 501108) && defined(_KERNEL)
173219820Sjeff
174219820Sjeffstatic int
175219820Sjefffr_check_wrapper(void *arg, struct mbuf **mp, struct ifnet *ifp, int dir)
176219820Sjeff{
177219820Sjeff	struct ip *ip = mtod(*mp, struct ip *);
178219820Sjeff	return fr_check(ip, ip->ip_hl << 2, ifp, (dir == PFIL_OUT), mp);
179219820Sjeff}
180219820Sjeff
181219820Sjeff# ifdef USE_INET6
182219820Sjeff#  include <netinet/ip6.h>
183219820Sjeff
184219820Sjeffstatic int
185219820Sjefffr_check_wrapper6(void *arg, struct mbuf **mp, struct ifnet *ifp, int dir)
186219820Sjeff{
187219820Sjeff	return (fr_check(mtod(*mp, struct ip *), sizeof(struct ip6_hdr),
188219820Sjeff	    ifp, (dir == PFIL_OUT), mp));
189219820Sjeff}
190219820Sjeff# endif
191219820Sjeff#endif /* __FreeBSD_version >= 501108 */
192219820Sjeff#if	defined(IPFILTER_LKM)
193219820Sjeffint iplidentify(s)
194219820Sjeffchar *s;
195219820Sjeff{
196219820Sjeff	if (strcmp(s, "ipl") == 0)
197219820Sjeff		return 1;
198219820Sjeff	return 0;
199219820Sjeff}
200219820Sjeff#endif /* IPFILTER_LKM */
201219820Sjeff
202219820Sjeff
203219820Sjeffint ipfattach()
204219820Sjeff{
205219820Sjeff#ifdef USE_SPL
206219820Sjeff	int s;
207219820Sjeff#endif
208219820Sjeff
209219820Sjeff	SPL_NET(s);
210219820Sjeff	if (fr_running > 0) {
211219820Sjeff		SPL_X(s);
212219820Sjeff		return EBUSY;
213219820Sjeff	}
214219820Sjeff
215219820Sjeff	MUTEX_INIT(&ipf_rw, "ipf rw mutex");
216219820Sjeff	MUTEX_INIT(&ipf_timeoutlock, "ipf timeout queue mutex");
217219820Sjeff	RWLOCK_INIT(&ipf_ipidfrag, "ipf IP NAT-Frag rwlock");
218219820Sjeff	RWLOCK_INIT(&ipf_tokens, "ipf token rwlock");
219219820Sjeff	ipf_locks_done = 1;
220219820Sjeff
221219820Sjeff	if (fr_initialise() < 0) {
222219820Sjeff		SPL_X(s);
223219820Sjeff		return EIO;
224219820Sjeff	}
225219820Sjeff
226219820Sjeff
227219820Sjeff	if (fr_checkp != fr_check) {
228219820Sjeff		fr_savep = fr_checkp;
229219820Sjeff		fr_checkp = fr_check;
230219820Sjeff	}
231219820Sjeff
232219820Sjeff	bzero((char *)ipfselwait, sizeof(ipfselwait));
233219820Sjeff	bzero((char *)frcache, sizeof(frcache));
234219820Sjeff	fr_running = 1;
235219820Sjeff
236219820Sjeff	if (fr_control_forwarding & 1)
237219820Sjeff		ipforwarding = 1;
238219820Sjeff
239219820Sjeff	SPL_X(s);
240219820Sjeff#if (__FreeBSD_version >= 300000)
241219820Sjeff	fr_slowtimer_ch = timeout(fr_slowtimer, NULL,
242219820Sjeff				    (hz / IPF_HZ_DIVIDE) * IPF_HZ_MULT);
243219820Sjeff#else
244219820Sjeff	timeout(fr_slowtimer, NULL, (hz / IPF_HZ_DIVIDE) * IPF_HZ_MULT);
245219820Sjeff#endif
246219820Sjeff	return 0;
247219820Sjeff}
248219820Sjeff
249219820Sjeff
250219820Sjeff/*
251219820Sjeff * Disable the filter by removing the hooks from the IP input/output
252219820Sjeff * stream.
253219820Sjeff */
254219820Sjeffint ipfdetach()
255219820Sjeff{
256219820Sjeff#ifdef USE_SPL
257219820Sjeff	int s;
258219820Sjeff#endif
259219820Sjeff	if (fr_control_forwarding & 2)
260219820Sjeff		ipforwarding = 0;
261219820Sjeff
262219820Sjeff	SPL_NET(s);
263219820Sjeff
264219820Sjeff#if (__FreeBSD_version >= 300000)
265219820Sjeff	if (fr_slowtimer_ch.callout != NULL)
266219820Sjeff		untimeout(fr_slowtimer, NULL, fr_slowtimer_ch);
267219820Sjeff	bzero(&fr_slowtimer_ch, sizeof(fr_slowtimer_ch));
268219820Sjeff#else
269219820Sjeff	untimeout(fr_slowtimer, NULL);
270219820Sjeff#endif /* FreeBSD */
271219820Sjeff
272219820Sjeff#ifndef NETBSD_PF
273219820Sjeff	if (fr_checkp != NULL)
274219820Sjeff		fr_checkp = fr_savep;
275219820Sjeff	fr_savep = NULL;
276219820Sjeff#endif
277219820Sjeff
278219820Sjeff	fr_deinitialise();
279219820Sjeff
280219820Sjeff	fr_running = -2;
281219820Sjeff
282219820Sjeff	(void) frflush(IPL_LOGIPF, 0, FR_INQUE|FR_OUTQUE|FR_INACTIVE);
283219820Sjeff	(void) frflush(IPL_LOGIPF, 0, FR_INQUE|FR_OUTQUE);
284219820Sjeff
285219820Sjeff	if (ipf_locks_done == 1) {
286219820Sjeff		MUTEX_DESTROY(&ipf_timeoutlock);
287219820Sjeff		MUTEX_DESTROY(&ipf_rw);
288219820Sjeff		RW_DESTROY(&ipf_ipidfrag);
289219820Sjeff		RW_DESTROY(&ipf_tokens);
290219820Sjeff		ipf_locks_done = 0;
291219820Sjeff	}
292219820Sjeff
293219820Sjeff	SPL_X(s);
294219820Sjeff
295219820Sjeff	return 0;
296219820Sjeff}
297219820Sjeff
298219820Sjeff
299219820Sjeff/*
300219820Sjeff * Filter ioctl interface.
301219820Sjeff */
302219820Sjeffint iplioctl(dev, cmd, data, mode
303219820Sjeff# if defined(_KERNEL) && ((BSD >= 199506) || (__FreeBSD_version >= 220000))
304219820Sjeff, p)
305219820Sjeff#  if (__FreeBSD_version >= 500024)
306219820Sjeffstruct thread *p;
307219820Sjeff#   if (__FreeBSD_version >= 500043)
308219820Sjeff#    define	p_uid	td_ucred->cr_ruid
309219820Sjeff#   else
310219820Sjeff#    define	p_uid	t_proc->p_cred->p_ruid
311219820Sjeff#   endif
312219820Sjeff#  else
313219820Sjeffstruct proc *p;
314219820Sjeff#   define	p_uid	p_cred->p_ruid
315219820Sjeff#  endif /* __FreeBSD_version >= 500024 */
316219820Sjeff# else
317219820Sjeff)
318219820Sjeff# endif
319219820Sjeff#if defined(_KERNEL) && (__FreeBSD_version >= 502116)
320219820Sjeffstruct cdev *dev;
321219820Sjeff#else
322219820Sjeffdev_t dev;
323219820Sjeff#endif
324219820Sjeffioctlcmd_t cmd;
325219820Sjeffcaddr_t data;
326219820Sjeffint mode;
327219820Sjeff{
328219820Sjeff	int error = 0, unit = 0;
329219820Sjeff	SPL_INT(s);
330219820Sjeff
331219820Sjeff#if (BSD >= 199306) && defined(_KERNEL)
332219820Sjeff	if ((securelevel >= 3) && (mode & FWRITE))
333219820Sjeff		return EPERM;
334219820Sjeff#endif
335219820Sjeff
336219820Sjeff	unit = GET_MINOR(dev);
337219820Sjeff	if ((IPL_LOGMAX < unit) || (unit < 0))
338219820Sjeff		return ENXIO;
339219820Sjeff
340219820Sjeff	if (fr_running <= 0) {
341219820Sjeff		if (unit != IPL_LOGIPF)
342219820Sjeff			return EIO;
343219820Sjeff		if (cmd != SIOCIPFGETNEXT && cmd != SIOCIPFGET &&
344219820Sjeff		    cmd != SIOCIPFSET && cmd != SIOCFRENB &&
345219820Sjeff		    cmd != SIOCGETFS && cmd != SIOCGETFF)
346219820Sjeff			return EIO;
347219820Sjeff	}
348219820Sjeff
349219820Sjeff	SPL_NET(s);
350219820Sjeff
351219820Sjeff	error = fr_ioctlswitch(unit, data, cmd, mode, p->p_uid, p);
352219820Sjeff	if (error != -1) {
353219820Sjeff		SPL_X(s);
354219820Sjeff		return error;
355	}
356
357	SPL_X(s);
358
359	return error;
360}
361
362
363#if 0
364void fr_forgetifp(ifp)
365void *ifp;
366{
367	register frentry_t *f;
368
369	WRITE_ENTER(&ipf_mutex);
370	for (f = ipacct[0][fr_active]; (f != NULL); f = f->fr_next)
371		if (f->fr_ifa == ifp)
372			f->fr_ifa = (void *)-1;
373	for (f = ipacct[1][fr_active]; (f != NULL); f = f->fr_next)
374		if (f->fr_ifa == ifp)
375			f->fr_ifa = (void *)-1;
376	for (f = ipfilter[0][fr_active]; (f != NULL); f = f->fr_next)
377		if (f->fr_ifa == ifp)
378			f->fr_ifa = (void *)-1;
379	for (f = ipfilter[1][fr_active]; (f != NULL); f = f->fr_next)
380		if (f->fr_ifa == ifp)
381			f->fr_ifa = (void *)-1;
382#ifdef USE_INET6
383	for (f = ipacct6[0][fr_active]; (f != NULL); f = f->fr_next)
384		if (f->fr_ifa == ifp)
385			f->fr_ifa = (void *)-1;
386	for (f = ipacct6[1][fr_active]; (f != NULL); f = f->fr_next)
387		if (f->fr_ifa == ifp)
388			f->fr_ifa = (void *)-1;
389	for (f = ipfilter6[0][fr_active]; (f != NULL); f = f->fr_next)
390		if (f->fr_ifa == ifp)
391			f->fr_ifa = (void *)-1;
392	for (f = ipfilter6[1][fr_active]; (f != NULL); f = f->fr_next)
393		if (f->fr_ifa == ifp)
394			f->fr_ifa = (void *)-1;
395#endif
396	RWLOCK_EXIT(&ipf_mutex);
397	fr_natsync(ifp);
398}
399#endif
400
401
402/*
403 * routines below for saving IP headers to buffer
404 */
405int iplopen(dev, flags
406#if ((BSD >= 199506) || (__FreeBSD_version >= 220000)) && defined(_KERNEL)
407, devtype, p)
408int devtype;
409# if (__FreeBSD_version >= 500024)
410struct thread *p;
411# else
412struct proc *p;
413# endif /* __FreeBSD_version >= 500024 */
414#else
415)
416#endif
417#if defined(_KERNEL) && (__FreeBSD_version >= 502116)
418struct cdev *dev;
419#else
420dev_t dev;
421#endif
422int flags;
423{
424	u_int min = GET_MINOR(dev);
425
426	if (IPL_LOGMAX < min)
427		min = ENXIO;
428	else
429		min = 0;
430	return min;
431}
432
433
434int iplclose(dev, flags
435#if ((BSD >= 199506) || (__FreeBSD_version >= 220000)) && defined(_KERNEL)
436, devtype, p)
437int devtype;
438# if (__FreeBSD_version >= 500024)
439struct thread *p;
440# else
441struct proc *p;
442# endif /* __FreeBSD_version >= 500024 */
443#else
444)
445#endif
446#if defined(_KERNEL) && (__FreeBSD_version >= 502116)
447struct cdev *dev;
448#else
449dev_t dev;
450#endif
451int flags;
452{
453	u_int	min = GET_MINOR(dev);
454
455	if (IPL_LOGMAX < min)
456		min = ENXIO;
457	else
458		min = 0;
459	return min;
460}
461
462/*
463 * iplread/ipllog
464 * both of these must operate with at least splnet() lest they be
465 * called during packet processing and cause an inconsistancy to appear in
466 * the filter lists.
467 */
468#if (BSD >= 199306)
469int iplread(dev, uio, ioflag)
470int ioflag;
471#else
472int iplread(dev, uio)
473#endif
474#if defined(_KERNEL) && (__FreeBSD_version >= 502116)
475struct cdev *dev;
476#else
477dev_t dev;
478#endif
479register struct uio *uio;
480{
481	u_int	xmin = GET_MINOR(dev);
482
483	if (fr_running < 1)
484		return EIO;
485
486	if (xmin < 0)
487		return ENXIO;
488
489# ifdef	IPFILTER_SYNC
490	if (xmin == IPL_LOGSYNC)
491		return ipfsync_read(uio);
492# endif
493
494#ifdef IPFILTER_LOG
495	return ipflog_read(xmin, uio);
496#else
497	return ENXIO;
498#endif
499}
500
501
502/*
503 * iplwrite
504 * both of these must operate with at least splnet() lest they be
505 * called during packet processing and cause an inconsistancy to appear in
506 * the filter lists.
507 */
508#if (BSD >= 199306)
509int iplwrite(dev, uio, ioflag)
510int ioflag;
511#else
512int iplwrite(dev, uio)
513#endif
514#if defined(_KERNEL) && (__FreeBSD_version >= 502116)
515struct cdev *dev;
516#else
517dev_t dev;
518#endif
519register struct uio *uio;
520{
521
522	if (fr_running < 1)
523		return EIO;
524
525#ifdef	IPFILTER_SYNC
526	if (GET_MINOR(dev) == IPL_LOGSYNC)
527		return ipfsync_write(uio);
528#endif
529	return ENXIO;
530}
531
532
533/*
534 * fr_send_reset - this could conceivably be a call to tcp_respond(), but that
535 * requires a large amount of setting up and isn't any more efficient.
536 */
537int fr_send_reset(fin)
538fr_info_t *fin;
539{
540	struct tcphdr *tcp, *tcp2;
541	int tlen = 0, hlen;
542	struct mbuf *m;
543#ifdef USE_INET6
544	ip6_t *ip6;
545#endif
546	ip_t *ip;
547
548	tcp = fin->fin_dp;
549	if (tcp->th_flags & TH_RST)
550		return -1;		/* feedback loop */
551
552	if (fr_checkl4sum(fin) == -1)
553		return -1;
554
555	tlen = fin->fin_dlen - (TCP_OFF(tcp) << 2) +
556			((tcp->th_flags & TH_SYN) ? 1 : 0) +
557			((tcp->th_flags & TH_FIN) ? 1 : 0);
558
559#ifdef USE_INET6
560	hlen = (fin->fin_v == 6) ? sizeof(ip6_t) : sizeof(ip_t);
561#else
562	hlen = sizeof(ip_t);
563#endif
564#ifdef MGETHDR
565	MGETHDR(m, M_DONTWAIT, MT_HEADER);
566#else
567	MGET(m, M_DONTWAIT, MT_HEADER);
568#endif
569	if (m == NULL)
570		return -1;
571	if (sizeof(*tcp2) + hlen > MLEN) {
572		MCLGET(m, M_DONTWAIT);
573		if ((m->m_flags & M_EXT) == 0) {
574			FREE_MB_T(m);
575			return -1;
576		}
577	}
578
579	m->m_len = sizeof(*tcp2) + hlen;
580#if (BSD >= 199103)
581	m->m_data += max_linkhdr;
582	m->m_pkthdr.len = m->m_len;
583	m->m_pkthdr.rcvif = (struct ifnet *)0;
584#endif
585	ip = mtod(m, struct ip *);
586	bzero((char *)ip, hlen);
587#ifdef USE_INET6
588	ip6 = (ip6_t *)ip;
589#endif
590	tcp2 = (struct tcphdr *)((char *)ip + hlen);
591	tcp2->th_sport = tcp->th_dport;
592	tcp2->th_dport = tcp->th_sport;
593
594	if (tcp->th_flags & TH_ACK) {
595		tcp2->th_seq = tcp->th_ack;
596		tcp2->th_flags = TH_RST;
597		tcp2->th_ack = 0;
598	} else {
599		tcp2->th_seq = 0;
600		tcp2->th_ack = ntohl(tcp->th_seq);
601		tcp2->th_ack += tlen;
602		tcp2->th_ack = htonl(tcp2->th_ack);
603		tcp2->th_flags = TH_RST|TH_ACK;
604	}
605	TCP_X2_A(tcp2, 0);
606	TCP_OFF_A(tcp2, sizeof(*tcp2) >> 2);
607	tcp2->th_win = tcp->th_win;
608	tcp2->th_sum = 0;
609	tcp2->th_urp = 0;
610
611#ifdef USE_INET6
612	if (fin->fin_v == 6) {
613		ip6->ip6_flow = ((ip6_t *)fin->fin_ip)->ip6_flow;
614		ip6->ip6_plen = htons(sizeof(struct tcphdr));
615		ip6->ip6_nxt = IPPROTO_TCP;
616		ip6->ip6_hlim = 0;
617		ip6->ip6_src = fin->fin_dst6;
618		ip6->ip6_dst = fin->fin_src6;
619		tcp2->th_sum = in6_cksum(m, IPPROTO_TCP,
620					 sizeof(*ip6), sizeof(*tcp2));
621		return fr_send_ip(fin, m, &m);
622	}
623#endif
624	ip->ip_p = IPPROTO_TCP;
625	ip->ip_len = htons(sizeof(struct tcphdr));
626	ip->ip_src.s_addr = fin->fin_daddr;
627	ip->ip_dst.s_addr = fin->fin_saddr;
628	tcp2->th_sum = in_cksum(m, hlen + sizeof(*tcp2));
629	ip->ip_len = hlen + sizeof(*tcp2);
630	return fr_send_ip(fin, m, &m);
631}
632
633
634static int fr_send_ip(fin, m, mpp)
635fr_info_t *fin;
636mb_t *m, **mpp;
637{
638	fr_info_t fnew;
639	ip_t *ip, *oip;
640	int hlen;
641
642	ip = mtod(m, ip_t *);
643	bzero((char *)&fnew, sizeof(fnew));
644
645	IP_V_A(ip, fin->fin_v);
646	switch (fin->fin_v)
647	{
648	case 4 :
649		fnew.fin_v = 4;
650		oip = fin->fin_ip;
651		IP_HL_A(ip, sizeof(*oip) >> 2);
652		ip->ip_tos = oip->ip_tos;
653		ip->ip_id = fin->fin_ip->ip_id;
654#if (__FreeBSD_version > 460000)
655		ip->ip_off = path_mtu_discovery ? IP_DF : 0;
656#else
657		ip->ip_off = 0;
658#endif
659		ip->ip_ttl = ip_defttl;
660		ip->ip_sum = 0;
661		hlen = sizeof(*oip);
662		break;
663#ifdef USE_INET6
664	case 6 :
665	{
666		ip6_t *ip6 = (ip6_t *)ip;
667
668		ip6->ip6_vfc = 0x60;
669		ip6->ip6_hlim = IPDEFTTL;
670
671		fnew.fin_v = 6;
672		hlen = sizeof(*ip6);
673		break;
674	}
675#endif
676	default :
677		return EINVAL;
678	}
679#ifdef IPSEC
680	m->m_pkthdr.rcvif = NULL;
681#endif
682
683	fnew.fin_ifp = fin->fin_ifp;
684	fnew.fin_flx = FI_NOCKSUM;
685	fnew.fin_m = m;
686	fnew.fin_ip = ip;
687	fnew.fin_mp = mpp;
688	fnew.fin_hlen = hlen;
689	fnew.fin_dp = (char *)ip + hlen;
690	(void) fr_makefrip(hlen, ip, &fnew);
691
692	return fr_fastroute(m, mpp, &fnew, NULL);
693}
694
695
696int fr_send_icmp_err(type, fin, dst)
697int type;
698fr_info_t *fin;
699int dst;
700{
701	int err, hlen, xtra, iclen, ohlen, avail, code;
702	struct in_addr dst4;
703	struct icmp *icmp;
704	struct mbuf *m;
705	void *ifp;
706#ifdef USE_INET6
707	ip6_t *ip6;
708	struct in6_addr dst6;
709#endif
710	ip_t *ip, *ip2;
711
712	if ((type < 0) || (type >= ICMP_MAXTYPE))
713		return -1;
714
715	code = fin->fin_icode;
716#ifdef USE_INET6
717	if ((code < 0) || (code > sizeof(icmptoicmp6unreach)/sizeof(int)))
718		return -1;
719#endif
720
721	if (fr_checkl4sum(fin) == -1)
722		return -1;
723#ifdef MGETHDR
724	MGETHDR(m, M_DONTWAIT, MT_HEADER);
725#else
726	MGET(m, M_DONTWAIT, MT_HEADER);
727#endif
728	if (m == NULL)
729		return -1;
730	avail = MHLEN;
731
732	xtra = 0;
733	hlen = 0;
734	ohlen = 0;
735	ifp = fin->fin_ifp;
736	if (fin->fin_v == 4) {
737		if ((fin->fin_p == IPPROTO_ICMP) &&
738		    !(fin->fin_flx & FI_SHORT))
739			switch (ntohs(fin->fin_data[0]) >> 8)
740			{
741			case ICMP_ECHO :
742			case ICMP_TSTAMP :
743			case ICMP_IREQ :
744			case ICMP_MASKREQ :
745				break;
746			default :
747				FREE_MB_T(m);
748				return 0;
749			}
750
751		if (dst == 0) {
752			if (fr_ifpaddr(4, FRI_NORMAL, ifp,
753				       &dst4, NULL) == -1) {
754				FREE_MB_T(m);
755				return -1;
756			}
757		} else
758			dst4.s_addr = fin->fin_daddr;
759
760		hlen = sizeof(ip_t);
761		ohlen = fin->fin_hlen;
762		if (fin->fin_hlen < fin->fin_plen)
763			xtra = MIN(fin->fin_dlen, 8);
764		else
765			xtra = 0;
766	}
767
768#ifdef USE_INET6
769	else if (fin->fin_v == 6) {
770		hlen = sizeof(ip6_t);
771		ohlen = sizeof(ip6_t);
772		type = icmptoicmp6types[type];
773		if (type == ICMP6_DST_UNREACH)
774			code = icmptoicmp6unreach[code];
775
776		if (hlen + sizeof(*icmp) + max_linkhdr +
777		    fin->fin_plen > avail) {
778			MCLGET(m, M_DONTWAIT);
779			if ((m->m_flags & M_EXT) == 0) {
780				FREE_MB_T(m);
781				return -1;
782			}
783			avail = MCLBYTES;
784		}
785		xtra = MIN(fin->fin_plen,
786			   avail - hlen - sizeof(*icmp) - max_linkhdr);
787		if (dst == 0) {
788			if (fr_ifpaddr(6, FRI_NORMAL, ifp,
789				       (struct in_addr *)&dst6, NULL) == -1) {
790				FREE_MB_T(m);
791				return -1;
792			}
793		} else
794			dst6 = fin->fin_dst6;
795	}
796#endif
797	else {
798		FREE_MB_T(m);
799		return -1;
800	}
801
802	iclen = hlen + sizeof(*icmp);
803	avail -= (max_linkhdr + iclen);
804	if (avail < 0) {
805		FREE_MB_T(m);
806		return -1;
807	}
808	if (xtra > avail)
809		xtra = avail;
810	iclen += xtra;
811	m->m_data += max_linkhdr;
812	m->m_pkthdr.rcvif = (struct ifnet *)0;
813	m->m_pkthdr.len = iclen;
814	m->m_len = iclen;
815	ip = mtod(m, ip_t *);
816	icmp = (struct icmp *)((char *)ip + hlen);
817	ip2 = (ip_t *)&icmp->icmp_ip;
818
819	icmp->icmp_type = type;
820	icmp->icmp_code = fin->fin_icode;
821	icmp->icmp_cksum = 0;
822#ifdef icmp_nextmtu
823	if (type == ICMP_UNREACH &&
824	    fin->fin_icode == ICMP_UNREACH_NEEDFRAG && ifp)
825		icmp->icmp_nextmtu = htons(((struct ifnet *)ifp)->if_mtu);
826#endif
827
828	bcopy((char *)fin->fin_ip, (char *)ip2, ohlen);
829
830#ifdef USE_INET6
831	ip6 = (ip6_t *)ip;
832	if (fin->fin_v == 6) {
833		ip6->ip6_flow = ((ip6_t *)fin->fin_ip)->ip6_flow;
834		ip6->ip6_plen = htons(iclen - hlen);
835		ip6->ip6_nxt = IPPROTO_ICMPV6;
836		ip6->ip6_hlim = 0;
837		ip6->ip6_src = dst6;
838		ip6->ip6_dst = fin->fin_src6;
839		if (xtra > 0)
840			bcopy((char *)fin->fin_ip + ohlen,
841			      (char *)&icmp->icmp_ip + ohlen, xtra);
842		icmp->icmp_cksum = in6_cksum(m, IPPROTO_ICMPV6,
843					     sizeof(*ip6), iclen - hlen);
844	} else
845#endif
846	{
847		ip2->ip_len = htons(ip2->ip_len);
848		ip2->ip_off = htons(ip2->ip_off);
849		ip->ip_p = IPPROTO_ICMP;
850		ip->ip_src.s_addr = dst4.s_addr;
851		ip->ip_dst.s_addr = fin->fin_saddr;
852
853		if (xtra > 0)
854			bcopy((char *)fin->fin_ip + ohlen,
855			      (char *)&icmp->icmp_ip + ohlen, xtra);
856		icmp->icmp_cksum = ipf_cksum((u_short *)icmp,
857					     sizeof(*icmp) + 8);
858		ip->ip_len = iclen;
859		ip->ip_p = IPPROTO_ICMP;
860	}
861	err = fr_send_ip(fin, m, &m);
862	return err;
863}
864
865
866#if !defined(IPFILTER_LKM) && (__FreeBSD_version < 300000)
867# if	(BSD < 199306)
868int iplinit __P((void));
869
870int
871# else
872void iplinit __P((void));
873
874void
875# endif
876iplinit()
877{
878	if (ipfattach() != 0)
879		printf("IP Filter failed to attach\n");
880	ip_init();
881}
882#endif /* __FreeBSD_version < 300000 */
883
884
885/*
886 * m0 - pointer to mbuf where the IP packet starts
887 * mpp - pointer to the mbuf pointer that is the start of the mbuf chain
888 */
889int fr_fastroute(m0, mpp, fin, fdp)
890mb_t *m0, **mpp;
891fr_info_t *fin;
892frdest_t *fdp;
893{
894	register struct ip *ip, *mhip;
895	register struct mbuf *m = *mpp;
896	register struct route *ro;
897	int len, off, error = 0, hlen, code;
898	struct ifnet *ifp, *sifp;
899	struct sockaddr_in *dst;
900	struct route iproute;
901	u_short ip_off;
902	frentry_t *fr;
903
904	ro = NULL;
905
906#ifdef M_WRITABLE
907	/*
908	* HOT FIX/KLUDGE:
909	*
910	* If the mbuf we're about to send is not writable (because of
911	* a cluster reference, for example) we'll need to make a copy
912	* of it since this routine modifies the contents.
913	*
914	* If you have non-crappy network hardware that can transmit data
915	* from the mbuf, rather than making a copy, this is gonna be a
916	* problem.
917	*/
918	if (M_WRITABLE(m) == 0) {
919		m0 = m_dup(m, M_DONTWAIT);
920		if (m0 != 0) {
921			FREE_MB_T(m);
922			m = m0;
923			*mpp = m;
924		} else {
925			error = ENOBUFS;
926			FREE_MB_T(m);
927			goto done;
928		}
929	}
930#endif
931
932#ifdef USE_INET6
933	if (fin->fin_v == 6) {
934		/*
935		 * currently "to <if>" and "to <if>:ip#" are not supported
936		 * for IPv6
937		 */
938#if  (__FreeBSD_version >= 490000)
939		return ip6_output(m0, NULL, NULL, 0, NULL, NULL, NULL);
940#else
941		return ip6_output(m0, NULL, NULL, 0, NULL, NULL);
942#endif
943	}
944#endif
945
946	hlen = fin->fin_hlen;
947	ip = mtod(m0, struct ip *);
948
949	/*
950	 * Route packet.
951	 */
952	ro = &iproute;
953	bzero((caddr_t)ro, sizeof (*ro));
954	dst = (struct sockaddr_in *)&ro->ro_dst;
955	dst->sin_family = AF_INET;
956	dst->sin_addr = ip->ip_dst;
957
958	fr = fin->fin_fr;
959	if (fdp != NULL)
960		ifp = fdp->fd_ifp;
961	else
962		ifp = fin->fin_ifp;
963
964	if ((ifp == NULL) && (!fr || !(fr->fr_flags & FR_FASTROUTE))) {
965		error = -2;
966		goto bad;
967	}
968
969	if ((fdp != NULL) && (fdp->fd_ip.s_addr != 0))
970		dst->sin_addr = fdp->fd_ip;
971
972	dst->sin_len = sizeof(*dst);
973	rtalloc(ro);
974
975	if ((ifp == NULL) && (ro->ro_rt != NULL))
976		ifp = ro->ro_rt->rt_ifp;
977
978	if ((ro->ro_rt == NULL) || (ifp == NULL)) {
979		if (in_localaddr(ip->ip_dst))
980			error = EHOSTUNREACH;
981		else
982			error = ENETUNREACH;
983		goto bad;
984	}
985	if (ro->ro_rt->rt_flags & RTF_GATEWAY)
986		dst = (struct sockaddr_in *)ro->ro_rt->rt_gateway;
987	if (ro->ro_rt)
988		ro->ro_rt->rt_use++;
989
990	/*
991	 * For input packets which are being "fastrouted", they won't
992	 * go back through output filtering and miss their chance to get
993	 * NAT'd and counted.  Duplicated packets aren't considered to be
994	 * part of the normal packet stream, so do not NAT them or pass
995	 * them through stateful checking, etc.
996	 */
997	if ((fdp != &fr->fr_dif) && (fin->fin_out == 0)) {
998		sifp = fin->fin_ifp;
999		fin->fin_ifp = ifp;
1000		fin->fin_out = 1;
1001		(void) fr_acctpkt(fin, NULL);
1002		fin->fin_fr = NULL;
1003		if (!fr || !(fr->fr_flags & FR_RETMASK)) {
1004			u_32_t pass;
1005
1006			if (fr_checkstate(fin, &pass) != NULL)
1007				fr_statederef((ipstate_t **)&fin->fin_state);
1008		}
1009
1010		switch (fr_checknatout(fin, NULL))
1011		{
1012		case 0 :
1013			break;
1014		case 1 :
1015			fr_natderef((nat_t **)&fin->fin_nat);
1016			ip->ip_sum = 0;
1017			break;
1018		case -1 :
1019			error = -1;
1020			goto bad;
1021			break;
1022		}
1023
1024		fin->fin_ifp = sifp;
1025		fin->fin_out = 0;
1026	} else
1027		ip->ip_sum = 0;
1028	/*
1029	 * If small enough for interface, can just send directly.
1030	 */
1031	if (ip->ip_len <= ifp->if_mtu) {
1032		ip->ip_len = htons(ip->ip_len);
1033		ip->ip_off = htons(ip->ip_off);
1034
1035		if (!ip->ip_sum)
1036			ip->ip_sum = in_cksum(m, hlen);
1037		error = (*ifp->if_output)(ifp, m, (struct sockaddr *)dst,
1038					  ro->ro_rt);
1039		goto done;
1040	}
1041	/*
1042	 * Too large for interface; fragment if possible.
1043	 * Must be able to put at least 8 bytes per fragment.
1044	 */
1045	ip_off = ntohs(ip->ip_off);
1046	if (ip_off & IP_DF) {
1047		error = EMSGSIZE;
1048		goto bad;
1049	}
1050	len = (ifp->if_mtu - hlen) &~ 7;
1051	if (len < 8) {
1052		error = EMSGSIZE;
1053		goto bad;
1054	}
1055
1056    {
1057	int mhlen, firstlen = len;
1058	struct mbuf **mnext = &m->m_act;
1059
1060	/*
1061	 * Loop through length of segment after first fragment,
1062	 * make new header and copy data of each part and link onto chain.
1063	 */
1064	m0 = m;
1065	mhlen = sizeof (struct ip);
1066	for (off = hlen + len; off < ip->ip_len; off += len) {
1067#ifdef MGETHDR
1068		MGETHDR(m, M_DONTWAIT, MT_HEADER);
1069#else
1070		MGET(m, M_DONTWAIT, MT_HEADER);
1071#endif
1072		if (m == 0) {
1073			m = m0;
1074			error = ENOBUFS;
1075			goto bad;
1076		}
1077		m->m_data += max_linkhdr;
1078		mhip = mtod(m, struct ip *);
1079		bcopy((char *)ip, (char *)mhip, sizeof(*ip));
1080		if (hlen > sizeof (struct ip)) {
1081			mhlen = ip_optcopy(ip, mhip) + sizeof (struct ip);
1082			IP_HL_A(mhip, mhlen >> 2);
1083		}
1084		m->m_len = mhlen;
1085		mhip->ip_off = ((off - hlen) >> 3) + ip_off;
1086		if (off + len >= ip->ip_len)
1087			len = ip->ip_len - off;
1088		else
1089			mhip->ip_off |= IP_MF;
1090		mhip->ip_len = htons((u_short)(len + mhlen));
1091		*mnext = m;
1092		m->m_next = m_copy(m0, off, len);
1093		if (m->m_next == 0) {
1094			error = ENOBUFS;	/* ??? */
1095			goto sendorfree;
1096		}
1097		m->m_pkthdr.len = mhlen + len;
1098		m->m_pkthdr.rcvif = NULL;
1099		mhip->ip_off = htons((u_short)mhip->ip_off);
1100		mhip->ip_sum = 0;
1101		mhip->ip_sum = in_cksum(m, mhlen);
1102		mnext = &m->m_act;
1103	}
1104	/*
1105	 * Update first fragment by trimming what's been copied out
1106	 * and updating header, then send each fragment (in order).
1107	 */
1108	m_adj(m0, hlen + firstlen - ip->ip_len);
1109	ip->ip_len = htons((u_short)(hlen + firstlen));
1110	ip->ip_off = htons((u_short)IP_MF);
1111	ip->ip_sum = 0;
1112	ip->ip_sum = in_cksum(m0, hlen);
1113sendorfree:
1114	for (m = m0; m; m = m0) {
1115		m0 = m->m_act;
1116		m->m_act = 0;
1117		if (error == 0)
1118			error = (*ifp->if_output)(ifp, m,
1119			    (struct sockaddr *)dst, ro->ro_rt);
1120		else
1121			FREE_MB_T(m);
1122	}
1123    }
1124done:
1125	if (!error)
1126		fr_frouteok[0]++;
1127	else
1128		fr_frouteok[1]++;
1129
1130	if ((ro != NULL) && (ro->ro_rt != NULL)) {
1131		RTFREE(ro->ro_rt);
1132	}
1133	*mpp = NULL;
1134	return 0;
1135bad:
1136	if (error == EMSGSIZE) {
1137		sifp = fin->fin_ifp;
1138		code = fin->fin_icode;
1139		fin->fin_icode = ICMP_UNREACH_NEEDFRAG;
1140		fin->fin_ifp = ifp;
1141		(void) fr_send_icmp_err(ICMP_UNREACH, fin, 1);
1142		fin->fin_ifp = sifp;
1143		fin->fin_icode = code;
1144	}
1145	FREE_MB_T(m);
1146	goto done;
1147}
1148
1149
1150int fr_verifysrc(fin)
1151fr_info_t *fin;
1152{
1153	struct sockaddr_in *dst;
1154	struct route iproute;
1155
1156	bzero((char *)&iproute, sizeof(iproute));
1157	dst = (struct sockaddr_in *)&iproute.ro_dst;
1158	dst->sin_len = sizeof(*dst);
1159	dst->sin_family = AF_INET;
1160	dst->sin_addr = fin->fin_src;
1161	rtalloc(&iproute);
1162	if (iproute.ro_rt == NULL)
1163		return 0;
1164	return (fin->fin_ifp == iproute.ro_rt->rt_ifp);
1165}
1166
1167
1168/*
1169 * return the first IP Address associated with an interface
1170 */
1171int fr_ifpaddr(v, atype, ifptr, inp, inpmask)
1172int v, atype;
1173void *ifptr;
1174struct in_addr *inp, *inpmask;
1175{
1176#ifdef USE_INET6
1177	struct in6_addr *inp6 = NULL;
1178#endif
1179	struct sockaddr *sock, *mask;
1180	struct sockaddr_in *sin;
1181	struct ifaddr *ifa;
1182	struct ifnet *ifp;
1183
1184	if ((ifptr == NULL) || (ifptr == (void *)-1))
1185		return -1;
1186
1187	sin = NULL;
1188	ifp = ifptr;
1189
1190	if (v == 4)
1191		inp->s_addr = 0;
1192#ifdef USE_INET6
1193	else if (v == 6)
1194		bzero((char *)inp, sizeof(struct in6_addr));
1195#endif
1196#if  (__FreeBSD_version >= 300000)
1197	ifa = TAILQ_FIRST(&ifp->if_addrhead);
1198#else
1199	ifa = ifp->if_addrlist;
1200#endif /* __FreeBSD_version >= 300000 */
1201
1202	sock = ifa->ifa_addr;
1203	while (sock != NULL && ifa != NULL) {
1204		sin = (struct sockaddr_in *)sock;
1205		if ((v == 4) && (sin->sin_family == AF_INET))
1206			break;
1207#ifdef USE_INET6
1208		if ((v == 6) && (sin->sin_family == AF_INET6)) {
1209			inp6 = &((struct sockaddr_in6 *)sin)->sin6_addr;
1210			if (!IN6_IS_ADDR_LINKLOCAL(inp6) &&
1211			    !IN6_IS_ADDR_LOOPBACK(inp6))
1212				break;
1213		}
1214#endif
1215#if (__FreeBSD_version >= 300000)
1216		ifa = TAILQ_NEXT(ifa, ifa_link);
1217#else
1218		ifa = ifa->ifa_next;
1219#endif /* __FreeBSD_version >= 300000 */
1220		if (ifa != NULL)
1221			sock = ifa->ifa_addr;
1222	}
1223
1224	if (ifa == NULL || sin == NULL)
1225		return -1;
1226
1227	mask = ifa->ifa_netmask;
1228	if (atype == FRI_BROADCAST)
1229		sock = ifa->ifa_broadaddr;
1230	else if (atype == FRI_PEERADDR)
1231		sock = ifa->ifa_dstaddr;
1232
1233	if (sock == NULL)
1234		return -1;
1235
1236#ifdef USE_INET6
1237	if (v == 6) {
1238		return fr_ifpfillv6addr(atype, (struct sockaddr_in6 *)sock,
1239					(struct sockaddr_in6 *)mask,
1240					inp, inpmask);
1241	}
1242#endif
1243	return fr_ifpfillv4addr(atype, (struct sockaddr_in *)sock,
1244				(struct sockaddr_in *)mask, inp, inpmask);
1245}
1246
1247
1248u_32_t fr_newisn(fin)
1249fr_info_t *fin;
1250{
1251	u_32_t newiss;
1252#if  (__FreeBSD_version >= 400000)
1253	newiss = arc4random();
1254#else
1255	static iss_seq_off = 0;
1256	u_char hash[16];
1257	MD5_CTX ctx;
1258
1259	/*
1260	 * Compute the base value of the ISS.  It is a hash
1261	 * of (saddr, sport, daddr, dport, secret).
1262	 */
1263	MD5Init(&ctx);
1264
1265	MD5Update(&ctx, (u_char *) &fin->fin_fi.fi_src,
1266		  sizeof(fin->fin_fi.fi_src));
1267	MD5Update(&ctx, (u_char *) &fin->fin_fi.fi_dst,
1268		  sizeof(fin->fin_fi.fi_dst));
1269	MD5Update(&ctx, (u_char *) &fin->fin_dat, sizeof(fin->fin_dat));
1270
1271	MD5Update(&ctx, ipf_iss_secret, sizeof(ipf_iss_secret));
1272
1273	MD5Final(hash, &ctx);
1274
1275	memcpy(&newiss, hash, sizeof(newiss));
1276
1277	/*
1278	 * Now increment our "timer", and add it in to
1279	 * the computed value.
1280	 *
1281	 * XXX Use `addin'?
1282	 * XXX TCP_ISSINCR too large to use?
1283	 */
1284	iss_seq_off += 0x00010000;
1285	newiss += iss_seq_off;
1286#endif
1287	return newiss;
1288}
1289
1290
1291/* ------------------------------------------------------------------------ */
1292/* Function:    fr_nextipid                                                 */
1293/* Returns:     int - 0 == success, -1 == error (packet should be droppped) */
1294/* Parameters:  fin(I) - pointer to packet information                      */
1295/*                                                                          */
1296/* Returns the next IPv4 ID to use for this packet.                         */
1297/* ------------------------------------------------------------------------ */
1298u_short fr_nextipid(fin)
1299fr_info_t *fin;
1300{
1301#ifndef	RANDOM_IP_ID
1302	static u_short ipid = 0;
1303	u_short id;
1304
1305	MUTEX_ENTER(&ipf_rw);
1306	id = ipid++;
1307	MUTEX_EXIT(&ipf_rw);
1308#else
1309	u_short id;
1310
1311	id = ip_randomid();
1312#endif
1313
1314	return id;
1315}
1316
1317
1318INLINE void fr_checkv4sum(fin)
1319fr_info_t *fin;
1320{
1321#ifdef CSUM_DATA_VALID
1322	int manual = 0;
1323	u_short sum;
1324	ip_t *ip;
1325	mb_t *m;
1326
1327	if ((fin->fin_flx & FI_NOCKSUM) != 0)
1328		return;
1329
1330	if (fin->fin_cksum != 0)
1331		return;
1332
1333	m = fin->fin_m;
1334	if (m == NULL) {
1335		manual = 1;
1336		goto skipauto;
1337	}
1338	ip = fin->fin_ip;
1339
1340	if (m->m_pkthdr.csum_flags & CSUM_DATA_VALID) {
1341		if (m->m_pkthdr.csum_flags & CSUM_PSEUDO_HDR)
1342			sum = m->m_pkthdr.csum_data;
1343		else
1344			sum = in_pseudo(ip->ip_src.s_addr, ip->ip_dst.s_addr,
1345					htonl(m->m_pkthdr.csum_data +
1346					fin->fin_ip->ip_len + fin->fin_p));
1347		sum ^= 0xffff;
1348		if (sum != 0) {
1349			fin->fin_flx |= FI_BAD;
1350			fin->fin_cksum = -1;
1351		} else {
1352			fin->fin_cksum = 1;
1353		}
1354	} else
1355		manual = 1;
1356skipauto:
1357# ifdef IPFILTER_CKSUM
1358	if (manual != 0)
1359		if (fr_checkl4sum(fin) == -1)
1360			fin->fin_flx |= FI_BAD;
1361# else
1362	;
1363# endif
1364#else
1365# ifdef IPFILTER_CKSUM
1366	if (fr_checkl4sum(fin) == -1)
1367		fin->fin_flx |= FI_BAD;
1368# endif
1369#endif
1370}
1371
1372
1373#ifdef USE_INET6
1374INLINE void fr_checkv6sum(fin)
1375fr_info_t *fin;
1376{
1377# ifdef IPFILTER_CKSUM
1378	if (fr_checkl4sum(fin) == -1)
1379		fin->fin_flx |= FI_BAD;
1380# endif
1381}
1382#endif /* USE_INET6 */
1383
1384
1385size_t mbufchainlen(m0)
1386struct mbuf *m0;
1387{
1388	size_t len;
1389
1390	if ((m0->m_flags & M_PKTHDR) != 0) {
1391		len = m0->m_pkthdr.len;
1392	} else {
1393		struct mbuf *m;
1394
1395		for (m = m0, len = 0; m != NULL; m = m->m_next)
1396			len += m->m_len;
1397	}
1398	return len;
1399}
1400
1401
1402/* ------------------------------------------------------------------------ */
1403/* Function:    fr_pullup                                                   */
1404/* Returns:     NULL == pullup failed, else pointer to protocol header      */
1405/* Parameters:  m(I)   - pointer to buffer where data packet starts         */
1406/*              fin(I) - pointer to packet information                      */
1407/*              len(I) - number of bytes to pullup                          */
1408/*                                                                          */
1409/* Attempt to move at least len bytes (from the start of the buffer) into a */
1410/* single buffer for ease of access.  Operating system native functions are */
1411/* used to manage buffers - if necessary.  If the entire packet ends up in  */
1412/* a single buffer, set the FI_COALESCE flag even though fr_coalesce() has  */
1413/* not been called.  Both fin_ip and fin_dp are updated before exiting _IF_ */
1414/* and ONLY if the pullup succeeds.                                         */
1415/*                                                                          */
1416/* We assume that 'min' is a pointer to a buffer that is part of the chain  */
1417/* of buffers that starts at *fin->fin_mp.                                  */
1418/* ------------------------------------------------------------------------ */
1419void *fr_pullup(min, fin, len)
1420mb_t *min;
1421fr_info_t *fin;
1422int len;
1423{
1424	int out = fin->fin_out, dpoff, ipoff;
1425	mb_t *m = min;
1426	char *ip;
1427
1428	if (m == NULL)
1429		return NULL;
1430
1431	ip = (char *)fin->fin_ip;
1432	if ((fin->fin_flx & FI_COALESCE) != 0)
1433		return ip;
1434
1435	ipoff = fin->fin_ipoff;
1436	if (fin->fin_dp != NULL)
1437		dpoff = (char *)fin->fin_dp - (char *)ip;
1438	else
1439		dpoff = 0;
1440
1441	if (M_LEN(m) < len) {
1442#ifdef MHLEN
1443		/*
1444		 * Assume that M_PKTHDR is set and just work with what is left
1445		 * rather than check..
1446		 * Should not make any real difference, anyway.
1447		 */
1448		if (len > MHLEN)
1449#else
1450		if (len > MLEN)
1451#endif
1452		{
1453#ifdef HAVE_M_PULLDOWN
1454			if (m_pulldown(m, 0, len, NULL) == NULL)
1455				m = NULL;
1456#else
1457			FREE_MB_T(*fin->fin_mp);
1458			m = NULL;
1459#endif
1460		} else
1461		{
1462			m = m_pullup(m, len);
1463		}
1464		*fin->fin_mp = m;
1465		if (m == NULL) {
1466			fin->fin_m = NULL;
1467			ATOMIC_INCL(frstats[out].fr_pull[1]);
1468			return NULL;
1469		}
1470
1471		while (M_LEN(m) == 0) {
1472			m = m->m_next;
1473		}
1474		fin->fin_m = m;
1475		ip = MTOD(m, char *) + ipoff;
1476	}
1477
1478	ATOMIC_INCL(frstats[out].fr_pull[0]);
1479	fin->fin_ip = (ip_t *)ip;
1480	if (fin->fin_dp != NULL)
1481		fin->fin_dp = (char *)fin->fin_ip + dpoff;
1482
1483	if (len == fin->fin_plen)
1484		fin->fin_flx |= FI_COALESCE;
1485	return ip;
1486}
1487
1488
1489int ipf_inject(fin, m)
1490fr_info_t *fin;
1491mb_t *m;
1492{
1493	int error = 0;
1494
1495	if (fin->fin_out == 0) {
1496#if (__FreeBSD_version >= 501000)
1497		netisr_dispatch(NETISR_IP, m);
1498#else
1499		struct ifqueue *ifq;
1500
1501		ifq = &ipintrq;
1502
1503# ifdef _IF_QFULL
1504		if (_IF_QFULL(ifq))
1505# else
1506		if (IF_QFULL(ifq))
1507# endif
1508		{
1509# ifdef _IF_DROP
1510			_IF_DROP(ifq);
1511# else
1512			IF_DROP(ifq);
1513# endif
1514			FREE_MB_T(m);
1515			error = ENOBUFS;
1516		} else {
1517			IF_ENQUEUE(ifq, m);
1518		}
1519#endif
1520	} else {
1521#if (__FreeBSD_version >= 470102)
1522		error = ip_output(m, NULL, NULL, IP_FORWARDING, NULL, NULL);
1523#else
1524		error = ip_output(m, NULL, NULL, IP_FORWARDING, NULL);
1525#endif
1526	}
1527
1528	return error;
1529}
1530
1531int ipf_pfil_unhook(void) {
1532#if defined(NETBSD_PF) && (__FreeBSD_version >= 500011)
1533# if __FreeBSD_version >= 501108
1534	struct pfil_head *ph_inet;
1535#  ifdef USE_INET6
1536	struct pfil_head *ph_inet6;
1537#  endif
1538# endif
1539#endif
1540
1541#ifdef NETBSD_PF
1542# if (__FreeBSD_version >= 500011)
1543#  if (__FreeBSD_version >= 501108)
1544	ph_inet = pfil_head_get(PFIL_TYPE_AF, AF_INET);
1545	if (ph_inet != NULL)
1546		pfil_remove_hook((void *)fr_check_wrapper, NULL,
1547		    PFIL_IN|PFIL_OUT|PFIL_WAITOK, ph_inet);
1548#  else
1549	pfil_remove_hook((void *)fr_check, PFIL_IN|PFIL_OUT|PFIL_WAITOK,
1550	    &inetsw[ip_protox[IPPROTO_IP]].pr_pfh);
1551#  endif
1552# else
1553	pfil_remove_hook((void *)fr_check, PFIL_IN|PFIL_OUT|PFIL_WAITOK);
1554# endif
1555# ifdef USE_INET6
1556#  if (__FreeBSD_version >= 501108)
1557	ph_inet6 = pfil_head_get(PFIL_TYPE_AF, AF_INET6);
1558	if (ph_inet6 != NULL)
1559		pfil_remove_hook((void *)fr_check_wrapper6, NULL,
1560		    PFIL_IN|PFIL_OUT|PFIL_WAITOK, ph_inet6);
1561#  else
1562	pfil_remove_hook((void *)fr_check, PFIL_IN|PFIL_OUT|PFIL_WAITOK,
1563				 &inet6sw[ip6_protox[IPPROTO_IPV6]].pr_pfh);
1564#  endif
1565# endif
1566#endif
1567
1568	return (0);
1569}
1570
1571int ipf_pfil_hook(void) {
1572#if defined(NETBSD_PF) && (__FreeBSD_version >= 500011)
1573# if __FreeBSD_version >= 501108
1574	struct pfil_head *ph_inet;
1575#  ifdef USE_INET6
1576	struct pfil_head *ph_inet6;
1577#  endif
1578# endif
1579#endif
1580
1581# ifdef NETBSD_PF
1582#  if __FreeBSD_version >= 500011
1583#   if __FreeBSD_version >= 501108
1584	ph_inet = pfil_head_get(PFIL_TYPE_AF, AF_INET);
1585#    ifdef USE_INET6
1586	ph_inet6 = pfil_head_get(PFIL_TYPE_AF, AF_INET6);
1587#    endif
1588	if (ph_inet == NULL
1589#    ifdef USE_INET6
1590	    && ph_inet6 == NULL
1591#    endif
1592	   )
1593		return ENODEV;
1594
1595	if (ph_inet != NULL)
1596		pfil_add_hook((void *)fr_check_wrapper, NULL,
1597		    PFIL_IN|PFIL_OUT|PFIL_WAITOK, ph_inet);
1598#  else
1599	pfil_add_hook((void *)fr_check, PFIL_IN|PFIL_OUT|PFIL_WAITOK,
1600			      &inetsw[ip_protox[IPPROTO_IP]].pr_pfh);
1601#  endif
1602#  else
1603	pfil_add_hook((void *)fr_check, PFIL_IN|PFIL_OUT|PFIL_WAITOK);
1604#  endif
1605#  ifdef USE_INET6
1606#   if __FreeBSD_version >= 501108
1607	if (ph_inet6 != NULL)
1608		pfil_add_hook((void *)fr_check_wrapper6, NULL,
1609				      PFIL_IN|PFIL_OUT|PFIL_WAITOK, ph_inet6);
1610#   else
1611	pfil_add_hook((void *)fr_check, PFIL_IN|PFIL_OUT|PFIL_WAITOK,
1612			      &inet6sw[ip6_protox[IPPROTO_IPV6]].pr_pfh);
1613#   endif
1614#  endif
1615# endif
1616	return (0);
1617}
1618
1619void
1620ipf_event_reg(void)
1621{
1622#if (__FreeBSD_version >= 502103)
1623	ipf_arrivetag =  EVENTHANDLER_REGISTER(ifnet_arrival_event, \
1624					       ipf_ifevent, NULL, \
1625					       EVENTHANDLER_PRI_ANY);
1626	ipf_departtag =  EVENTHANDLER_REGISTER(ifnet_departure_event, \
1627					       ipf_ifevent, NULL, \
1628					       EVENTHANDLER_PRI_ANY);
1629	ipf_clonetag =  EVENTHANDLER_REGISTER(if_clone_event, ipf_ifevent, \
1630					      NULL, EVENTHANDLER_PRI_ANY);
1631#endif
1632}
1633
1634void
1635ipf_event_dereg(void)
1636{
1637#if (__FreeBSD_version >= 502103)
1638	if (ipf_arrivetag != NULL) {
1639		EVENTHANDLER_DEREGISTER(ifnet_arrival_event, ipf_arrivetag);
1640	}
1641	if (ipf_departtag != NULL) {
1642		EVENTHANDLER_DEREGISTER(ifnet_departure_event, ipf_departtag);
1643	}
1644	if (ipf_clonetag != NULL) {
1645		EVENTHANDLER_DEREGISTER(if_clone_event, ipf_clonetag);
1646	}
1647#endif
1648}
1649