ip_fil_freebsd.c revision 145516
133323Sphk/*	$FreeBSD: vendor-sys/ipfilter/dist/sys/contrib/ipfilter/netinet/ip_fil_freebsd.c 145516 2005-04-25 18:15:41Z darrenr $	*/
233323Sphk
333323Sphk/*
433323Sphk * Copyright (C) 1993-2003 by Darren Reed.
533323Sphk *
633323Sphk * See the IPFILTER.LICENCE file for details on licencing.
733323Sphk */
833323Sphk#if !defined(lint)
950477Speterstatic const char sccsid[] = "@(#)ip_fil.c	2.41 6/5/96 (C) 1993-2000 Darren Reed";
1033323Sphkstatic const char rcsid[] = "@(#)Id: ip_fil_freebsd.c,v 2.53.2.25 2005/02/01 03:15:56 darrenr Exp";
1136938Sphk#endif
1236938Sphk
1336938Sphk#if defined(KERNEL) || defined(_KERNEL)
1436938Sphk# undef KERNEL
1536938Sphk# undef _KERNEL
1633323Sphk# define	KERNEL	1
1733323Sphk# define	_KERNEL	1
1833323Sphk#endif
1933323Sphk#if defined(__FreeBSD_version) && (__FreeBSD_version >= 400000) && \
2033323Sphk    !defined(KLD_MODULE) && !defined(IPFILTER_LKM)
2155939Snsouch# include "opt_inet6.h"
2255939Snsouch#endif
2333323Sphk#if defined(__FreeBSD_version) && (__FreeBSD_version >= 440000) && \
2458377Sphk    !defined(KLD_MODULE) && !defined(IPFILTER_LKM)
2536739Sphk# include "opt_random_ip_id.h"
2633323Sphk#endif
2755939Snsouch#include <sys/param.h>
2855939Snsouch#if defined(__FreeBSD__) && !defined(__FreeBSD_version)
2955939Snsouch# if defined(IPFILTER_LKM)
3033323Sphk#  ifndef __FreeBSD_cc_version
3133323Sphk#   include <osreldate.h>
3255939Snsouch#  else
3355939Snsouch#   if __FreeBSD_cc_version < 430000
3433326Sphk#    include <osreldate.h>
3533323Sphk#   endif
3649550Sphk#  endif
3733323Sphk# endif
3849550Sphk#endif
3946053Sphk#include <sys/errno.h>
4033396Sphk#include <sys/types.h>
4144666Sphk#include <sys/file.h>
4255939Snsouch#if __FreeBSD_version >= 220000
4355939Snsouch# include <sys/fcntl.h>
4455939Snsouch# include <sys/filio.h>
4549550Sphk#else
4633323Sphk# include <sys/ioctl.h>
4755939Snsouch#endif
4833323Sphk#include <sys/time.h>
4955939Snsouch#include <sys/systm.h>
5055939Snsouch#if (__FreeBSD_version >= 300000)
5155939Snsouch# include <sys/dirent.h>
5255939Snsouch#else
5355939Snsouch# include <sys/dir.h>
5455939Snsouch#endif
5533323Sphk#if !defined(__hpux)
5655939Snsouch# include <sys/mbuf.h>
5733323Sphk#endif
5833396Sphk#include <sys/protosw.h>
5933396Sphk#include <sys/socket.h>
6036739Sphk
6133323Sphk#include <net/if.h>
6233323Sphk#if __FreeBSD_version >= 300000
6347625Sphk# include <net/if_var.h>
6447625Sphk# if !defined(IPFILTER_LKM)
6547625Sphk#  include "opt_ipfilter.h"
6647625Sphk# endif
6747625Sphk#endif
6847625Sphk#include <net/route.h>
6947625Sphk#include <netinet/in.h>
7047625Sphk#include <netinet/in_var.h>
7147625Sphk#include <netinet/in_systm.h>
7247625Sphk#include <netinet/ip.h>
7347625Sphk#include <netinet/ip_var.h>
7447625Sphk#include <netinet/tcp.h>
7547625Sphk#if defined(__osf__)
7647625Sphk# include <netinet/tcp_timer.h>
7747625Sphk#endif
7847625Sphk#include <netinet/udp.h>
7933323Sphk#include <netinet/tcpip.h>
8056455Speter#include <netinet/ip_icmp.h>
8156455Speter#ifndef _KERNEL
8256455Speter# include "netinet/ipf.h"
8356455Speter#endif
8456455Speter#include "netinet/ip_compat.h"
8556455Speter#ifdef USE_INET6
8656455Speter# include <netinet/icmp6.h>
8755939Snsouch#endif
8855939Snsouch#include "netinet/ip_fil.h"
8933323Sphk#include "netinet/ip_nat.h"
9033396Sphk#include "netinet/ip_frag.h"
9149550Sphk#include "netinet/ip_state.h"
9255939Snsouch#include "netinet/ip_proxy.h"
9333323Sphk#include "netinet/ip_auth.h"
9455939Snsouch#ifdef	IPFILTER_SYNC
9533396Sphk#include "netinet/ip_sync.h"
9633323Sphk#endif
9755939Snsouch#ifdef	IPFILTER_SCAN
9855939Snsouch#include "netinet/ip_scan.h"
9955939Snsouch#endif
10033323Sphk#include "netinet/ip_pool.h"
10155939Snsouch#if defined(__FreeBSD_version) && (__FreeBSD_version >= 300000)
10233323Sphk# include <sys/malloc.h>
10344666Sphk#endif
10444666Sphk#include <sys/kernel.h>
10555939Snsouch#ifdef CSUM_DATA_VALID
10633323Sphk#include <machine/in_cksum.h>
10733323Sphk#endif
10833323Sphkextern	int	ip_optcopy __P((struct ip *, struct ip *));
10955939Snsouch
11033323Sphk#if (__FreeBSD_version > 460000)
11155939Snsouchextern	int	path_mtu_discovery;
11255939Snsouch#endif
11355939Snsouch
11444666Sphk# ifdef IPFILTER_M_IPFILTER
11555939SnsouchMALLOC_DEFINE(M_IPFILTER, "IP Filter", "IP Filter packet filter data structures");
11655939Snsouch# endif
11733323Sphk
11855939Snsouch
11955939Snsouch#if !defined(__osf__)
12055939Snsouchextern	struct	protosw	inetsw[];
12155939Snsouch#endif
12255939Snsouch
12355939Snsouchstatic	int	(*fr_savep) __P((ip_t *, int, void *, int, struct mbuf **));
12455939Snsouchstatic	int	fr_send_ip __P((fr_info_t *, mb_t *, mb_t **));
12555939Snsouch# ifdef USE_MUTEXES
12655939Snsouchipfmutex_t	ipl_mutex, ipf_authmx, ipf_rw, ipf_stinsert;
12755939Snsouchipfmutex_t	ipf_nat_new, ipf_natio, ipf_timeoutlock;
12833323Sphkipfrwlock_t	ipf_mutex, ipf_global, ipf_ipidfrag;
12933323Sphkipfrwlock_t	ipf_frag, ipf_state, ipf_nat, ipf_natfrag, ipf_auth;
13033323Sphk# endif
13133396Sphkint		ipf_locks_done = 0;
13233323Sphk
13333323Sphk#if (__FreeBSD_version >= 300000)
13455939Snsouchstruct callout_handle fr_slowtimer_ch;
13555939Snsouch#endif
13655939Snsouch
13755939Snsouch#if (__FreeBSD_version >= 500011)
13833323Sphk# include <sys/conf.h>
13946053Sphk# if defined(NETBSD_PF)
14055939Snsouch#  include <net/pfil.h>
14146053Sphk#  include <netinet/ipprotosw.h>
14233323Sphk/*
14355939Snsouch * We provide the fr_checkp name just to minimize changes later.
14455939Snsouch */
14555939Snsouchint (*fr_checkp) __P((ip_t *ip, int hlen, void *ifp, int out, mb_t **mp));
14655939Snsouch# endif /* NETBSD_PF */
14755939Snsouch#endif /* __FreeBSD_version >= 500011 */
14855939Snsouch
14955939Snsouch
15055939Snsouch#if (__FreeBSD_version >= 501108) && defined(_KERNEL)
15155939Snsouch
15255939Snsouchstatic int
15346053Sphkfr_check_wrapper(void *arg, struct mbuf **mp, struct ifnet *ifp, int dir)
15446053Sphk{
15533323Sphk	struct ip *ip = mtod(*mp, struct ip *);
15633323Sphk	return fr_check(ip, ip->ip_hl << 2, ifp, (dir == PFIL_OUT), mp);
15733323Sphk}
15833323Sphk
15933323Sphk# ifdef USE_INET6
16033396Sphk#  include <netinet/ip6.h>
16133323Sphk
16255939Snsouchstatic int
16355939Snsouchfr_check_wrapper6(void *arg, struct mbuf **mp, struct ifnet *ifp, int dir)
16455939Snsouch{
16555939Snsouch	return (fr_check(mtod(*mp, struct ip *), sizeof(struct ip6_hdr),
16633323Sphk	    ifp, (dir == PFIL_OUT), mp));
16744666Sphk}
16843433Snsouch# endif
16955939Snsouch#endif /* __FreeBSD_version >= 501108 */
17055939Snsouch#if	defined(IPFILTER_LKM)
17143433Snsouchint iplidentify(s)
17255939Snsouchchar *s;
17355939Snsouch{
17446053Sphk	if (strcmp(s, "ipl") == 0)
17533323Sphk		return 1;
17633323Sphk	return 0;
17733323Sphk}
17833323Sphk#endif /* IPFILTER_LKM */
17955939Snsouch
18033323Sphk
18155939Snsouchint iplattach()
18255939Snsouch{
18355939Snsouch#ifdef USE_SPL
18444666Sphk	int s;
18544666Sphk#endif
18633323Sphk#if defined(NETBSD_PF) && (__FreeBSD_version >= 500011)
18744666Sphk	int error = 0;
18844666Sphk# if __FreeBSD_version >= 501108
18955939Snsouch	struct pfil_head *ph_inet;
19033323Sphk#  ifdef USE_INET6
19144666Sphk	struct pfil_head *ph_inet6;
19255939Snsouch#  endif
19344666Sphk# endif
19444666Sphk#endif
19555939Snsouch
19633323Sphk	SPL_NET(s);
19733323Sphk	if (fr_running > 0) {
19836739Sphk		SPL_X(s);
19936748Sbde		return EBUSY;
20033323Sphk	}
20155939Snsouch
20255939Snsouch	MUTEX_INIT(&ipf_rw, "ipf rw mutex");
20333323Sphk	RWLOCK_INIT(&ipf_global, "ipf filter load/unload mutex");
20444666Sphk	MUTEX_INIT(&ipf_timeoutlock, "ipf timeout queue mutex");
20533323Sphk	RWLOCK_INIT(&ipf_mutex, "ipf filter rwlock");
20633323Sphk	RWLOCK_INIT(&ipf_ipidfrag, "ipf IP NAT-Frag rwlock");
20756455Speter	ipf_locks_done = 1;
20856455Speter
20956455Speter	if (fr_initialise() < 0) {
21056455Speter		SPL_X(s);
21156455Speter		return EIO;
21256455Speter	}
21356455Speter
21456455Speter
21556455Speter# ifdef NETBSD_PF
21656455Speter#  if __FreeBSD_version >= 500011
21756455Speter#   if __FreeBSD_version >= 501108
21856455Speter	ph_inet = pfil_head_get(PFIL_TYPE_AF, AF_INET);
21956455Speter#    ifdef USE_INET6
22056455Speter	ph_inet6 = pfil_head_get(PFIL_TYPE_AF, AF_INET6);
22155939Snsouch#    endif
222	if (ph_inet == NULL
223#    ifdef USE_INET6
224	    && ph_inet6 == NULL
225#    endif
226	   )
227		return ENODEV;
228
229	if (ph_inet != NULL)
230		error = pfil_add_hook((void *)fr_check_wrapper, NULL,
231				      PFIL_IN|PFIL_OUT, ph_inet);
232	else
233		error = 0;
234#  else
235	error = pfil_add_hook((void *)fr_check, PFIL_IN|PFIL_OUT,
236			      &inetsw[ip_protox[IPPROTO_IP]].pr_pfh);
237#  endif
238	if (error) {
239#   ifdef USE_INET6
240		goto pfil_error;
241#   else
242		fr_deinitialise();
243		SPL_X(s);
244		return error;
245#   endif
246	}
247#  else
248	pfil_add_hook((void *)fr_check, PFIL_IN|PFIL_OUT);
249#  endif
250#  ifdef USE_INET6
251#   if __FreeBSD_version >= 501108
252	if (ph_inet6 != NULL)
253		error = pfil_add_hook((void *)fr_check_wrapper6, NULL,
254				      PFIL_IN|PFIL_OUT, ph_inet6);
255	else
256		error = 0;
257	if (error) {
258		pfil_remove_hook((void *)fr_check_wrapper6, NULL,
259				 PFIL_IN|PFIL_OUT, ph_inet6);
260#   else
261	error = pfil_add_hook((void *)fr_check, PFIL_IN|PFIL_OUT,
262			      &inet6sw[ip6_protox[IPPROTO_IPV6]].pr_pfh);
263	if (error) {
264		pfil_remove_hook((void *)fr_check, PFIL_IN|PFIL_OUT,
265				 &inetsw[ip_protox[IPPROTO_IP]].pr_pfh);
266#   endif
267pfil_error:
268		fr_deinitialise();
269		SPL_X(s);
270		return error;
271	}
272#  endif
273# endif
274	if (fr_checkp != fr_check) {
275		fr_savep = fr_checkp;
276		fr_checkp = fr_check;
277	}
278
279	bzero((char *)frcache, sizeof(frcache));
280	fr_running = 1;
281
282	if (fr_control_forwarding & 1)
283		ipforwarding = 1;
284
285	SPL_X(s);
286#if (__FreeBSD_version >= 300000)
287	fr_slowtimer_ch = timeout(fr_slowtimer, NULL,
288				    (hz / IPF_HZ_DIVIDE) * IPF_HZ_MULT);
289#else
290	timeout(fr_slowtimer, NULL, (hz / IPF_HZ_DIVIDE) * IPF_HZ_MULT);
291#endif
292	return 0;
293}
294
295
296/*
297 * Disable the filter by removing the hooks from the IP input/output
298 * stream.
299 */
300int ipldetach()
301{
302#ifdef USE_SPL
303	int s;
304#endif
305#if defined(NETBSD_PF) && (__FreeBSD_version >= 500011)
306	int error = 0;
307# if __FreeBSD_version >= 501108
308	struct pfil_head *ph_inet;
309#  ifdef USE_INET6
310	struct pfil_head *ph_inet6;
311#  endif
312# endif
313#endif
314
315	if (fr_control_forwarding & 2)
316		ipforwarding = 0;
317
318	SPL_NET(s);
319
320#if (__FreeBSD_version >= 300000)
321	if (fr_slowtimer_ch.callout != NULL)
322		untimeout(fr_slowtimer, NULL, fr_slowtimer_ch);
323	bzero(&fr_slowtimer_ch, sizeof(fr_slowtimer_ch));
324#else
325	untimeout(fr_slowtimer, NULL);
326#endif /* FreeBSD */
327
328#ifndef NETBSD_PF
329	if (fr_checkp != NULL)
330		fr_checkp = fr_savep;
331	fr_savep = NULL;
332#endif
333
334#ifdef NETBSD_PF
335# if (__FreeBSD_version >= 500011)
336#  if (__FreeBSD_version >= 501108)
337	ph_inet = pfil_head_get(PFIL_TYPE_AF, AF_INET);
338	if (ph_inet != NULL)
339		error = pfil_remove_hook((void *)fr_check_wrapper, NULL,
340					 PFIL_IN|PFIL_OUT, ph_inet);
341	else
342		error = 0;
343#  else
344	error = pfil_remove_hook((void *)fr_check, PFIL_IN|PFIL_OUT,
345				 &inetsw[ip_protox[IPPROTO_IP]].pr_pfh);
346#  endif
347	if (error) {
348		SPL_X(s);
349		return error;
350	}
351# else
352	pfil_remove_hook((void *)fr_check, PFIL_IN|PFIL_OUT);
353# endif
354# ifdef USE_INET6
355#  if (__FreeBSD_version >= 501108)
356	ph_inet6 = pfil_head_get(PFIL_TYPE_AF, AF_INET6);
357	if (ph_inet6 != NULL)
358		error = pfil_remove_hook((void *)fr_check_wrapper6, NULL,
359					 PFIL_IN|PFIL_OUT, ph_inet6);
360	else
361		error = 0;
362#  else
363	error = pfil_remove_hook((void *)fr_check, PFIL_IN|PFIL_OUT,
364				 &inet6sw[ip6_protox[IPPROTO_IPV6]].pr_pfh);
365#  endif
366	if (error) {
367		SPL_X(s);
368		return error;
369	}
370# endif
371#endif
372	fr_deinitialise();
373
374	fr_running = -2;
375
376	(void) frflush(IPL_LOGIPF, 0, FR_INQUE|FR_OUTQUE|FR_INACTIVE);
377	(void) frflush(IPL_LOGIPF, 0, FR_INQUE|FR_OUTQUE);
378
379	if (ipf_locks_done == 1) {
380		MUTEX_DESTROY(&ipf_timeoutlock);
381		MUTEX_DESTROY(&ipf_rw);
382		RW_DESTROY(&ipf_mutex);
383		RW_DESTROY(&ipf_ipidfrag);
384		RW_DESTROY(&ipf_global);
385		ipf_locks_done = 0;
386	}
387
388	SPL_X(s);
389
390	return 0;
391}
392
393
394/*
395 * Filter ioctl interface.
396 */
397int iplioctl(dev, cmd, data, mode
398# if defined(_KERNEL) && ((BSD >= 199506) || (__FreeBSD_version >= 220000))
399, p)
400#  if (__FreeBSD_version >= 500024)
401struct thread *p;
402#  else
403struct proc *p;
404#  endif /* __FreeBSD_version >= 500024 */
405# else
406)
407# endif
408#if defined(_KERNEL) && (__FreeBSD_version >= 502116)
409struct cdev *dev;
410#else
411dev_t dev;
412#endif
413ioctlcmd_t cmd;
414caddr_t data;
415int mode;
416{
417#ifdef USE_SPL
418	int s;
419#endif
420	int error = 0, unit = 0, tmp;
421	friostat_t fio;
422
423#if (BSD >= 199306) && defined(_KERNEL)
424	if ((securelevel >= 2) && (mode & FWRITE))
425		return EPERM;
426#endif
427
428	unit = GET_MINOR(dev);
429	if ((IPL_LOGMAX < unit) || (unit < 0))
430		return ENXIO;
431
432	if (fr_running <= 0) {
433		if (unit != IPL_LOGIPF)
434			return EIO;
435		if (cmd != SIOCIPFGETNEXT && cmd != SIOCIPFGET &&
436		    cmd != SIOCIPFSET && cmd != SIOCFRENB &&
437		    cmd != SIOCGETFS && cmd != SIOCGETFF)
438			return EIO;
439	}
440
441	SPL_NET(s);
442
443	error = fr_ioctlswitch(unit, data, cmd, mode);
444	if (error != -1) {
445		SPL_X(s);
446		return error;
447	}
448	error = 0;
449
450	switch (cmd)
451	{
452	case FIONREAD :
453#ifdef IPFILTER_LOG
454		BCOPYOUT(&iplused[IPL_LOGIPF], (caddr_t)data,
455			 sizeof(iplused[IPL_LOGIPF]));
456#endif
457		break;
458	case SIOCFRENB :
459		if (!(mode & FWRITE))
460			error = EPERM;
461		else {
462			BCOPYIN(data, &tmp, sizeof(tmp));
463			if (tmp) {
464				if (fr_running > 0)
465					error = 0;
466				else
467					error = iplattach();
468				if (error == 0)
469					fr_running = 1;
470				else
471					(void) ipldetach();
472			} else {
473				error = ipldetach();
474				if (error == 0)
475					fr_running = -1;
476			}
477		}
478		break;
479	case SIOCIPFSET :
480		if (!(mode & FWRITE)) {
481			error = EPERM;
482			break;
483		}
484	case SIOCIPFGETNEXT :
485	case SIOCIPFGET :
486		error = fr_ipftune(cmd, data);
487		break;
488	case SIOCSETFF :
489		if (!(mode & FWRITE))
490			error = EPERM;
491		else
492			BCOPYIN(data, &fr_flags, sizeof(fr_flags));
493		break;
494	case SIOCGETFF :
495		BCOPYOUT(&fr_flags, data, sizeof(fr_flags));
496		break;
497	case SIOCFUNCL :
498		error = fr_resolvefunc(data);
499		break;
500	case SIOCINAFR :
501	case SIOCRMAFR :
502	case SIOCADAFR :
503	case SIOCZRLST :
504		if (!(mode & FWRITE))
505			error = EPERM;
506		else
507			error = frrequest(unit, cmd, data, fr_active, 1);
508		break;
509	case SIOCINIFR :
510	case SIOCRMIFR :
511	case SIOCADIFR :
512		if (!(mode & FWRITE))
513			error = EPERM;
514		else
515			error = frrequest(unit, cmd, data, 1 - fr_active, 1);
516		break;
517	case SIOCSWAPA :
518		if (!(mode & FWRITE))
519			error = EPERM;
520		else {
521			bzero((char *)frcache, sizeof(frcache[0]) * 2);
522			*(u_int *)data = fr_active;
523			fr_active = 1 - fr_active;
524		}
525		break;
526	case SIOCGETFS :
527		fr_getstat(&fio);
528		error = fr_outobj(data, &fio, IPFOBJ_IPFSTAT);
529		break;
530	case SIOCFRZST :
531		if (!(mode & FWRITE))
532			error = EPERM;
533		else
534			error = fr_zerostats(data);
535		break;
536	case SIOCIPFFL :
537		if (!(mode & FWRITE))
538			error = EPERM;
539		else {
540			BCOPYIN(data, &tmp, sizeof(tmp));
541			tmp = frflush(unit, 4, tmp);
542			BCOPYOUT(&tmp, data, sizeof(tmp));
543		}
544		break;
545#ifdef USE_INET6
546	case SIOCIPFL6 :
547		if (!(mode & FWRITE))
548			error = EPERM;
549		else {
550			BCOPYIN(data, &tmp, sizeof(tmp));
551			tmp = frflush(unit, 6, tmp);
552			BCOPYOUT(&tmp, data, sizeof(tmp));
553		}
554		break;
555#endif
556	case SIOCSTLCK :
557		BCOPYIN(data, &tmp, sizeof(tmp));
558		fr_state_lock = tmp;
559		fr_nat_lock = tmp;
560		fr_frag_lock = tmp;
561		fr_auth_lock = tmp;
562		break;
563#ifdef IPFILTER_LOG
564	case SIOCIPFFB :
565		if (!(mode & FWRITE))
566			error = EPERM;
567		else
568			*(int *)data = ipflog_clear(unit);
569		break;
570#endif /* IPFILTER_LOG */
571	case SIOCGFRST :
572		error = fr_outobj(data, fr_fragstats(), IPFOBJ_FRAGSTAT);
573		break;
574	case SIOCFRSYN :
575		if (!(mode & FWRITE))
576			error = EPERM;
577		else {
578			frsync(NULL);
579		}
580		break;
581	default :
582		error = EINVAL;
583		break;
584	}
585	SPL_X(s);
586	return error;
587}
588
589
590#if 0
591void fr_forgetifp(ifp)
592void *ifp;
593{
594	register frentry_t *f;
595
596	WRITE_ENTER(&ipf_mutex);
597	for (f = ipacct[0][fr_active]; (f != NULL); f = f->fr_next)
598		if (f->fr_ifa == ifp)
599			f->fr_ifa = (void *)-1;
600	for (f = ipacct[1][fr_active]; (f != NULL); f = f->fr_next)
601		if (f->fr_ifa == ifp)
602			f->fr_ifa = (void *)-1;
603	for (f = ipfilter[0][fr_active]; (f != NULL); f = f->fr_next)
604		if (f->fr_ifa == ifp)
605			f->fr_ifa = (void *)-1;
606	for (f = ipfilter[1][fr_active]; (f != NULL); f = f->fr_next)
607		if (f->fr_ifa == ifp)
608			f->fr_ifa = (void *)-1;
609#ifdef USE_INET6
610	for (f = ipacct6[0][fr_active]; (f != NULL); f = f->fr_next)
611		if (f->fr_ifa == ifp)
612			f->fr_ifa = (void *)-1;
613	for (f = ipacct6[1][fr_active]; (f != NULL); f = f->fr_next)
614		if (f->fr_ifa == ifp)
615			f->fr_ifa = (void *)-1;
616	for (f = ipfilter6[0][fr_active]; (f != NULL); f = f->fr_next)
617		if (f->fr_ifa == ifp)
618			f->fr_ifa = (void *)-1;
619	for (f = ipfilter6[1][fr_active]; (f != NULL); f = f->fr_next)
620		if (f->fr_ifa == ifp)
621			f->fr_ifa = (void *)-1;
622#endif
623	RWLOCK_EXIT(&ipf_mutex);
624	fr_natsync(ifp);
625}
626#endif
627
628
629/*
630 * routines below for saving IP headers to buffer
631 */
632int iplopen(dev, flags
633#if ((BSD >= 199506) || (__FreeBSD_version >= 220000)) && defined(_KERNEL)
634, devtype, p)
635int devtype;
636# if (__FreeBSD_version >= 500024)
637struct thread *p;
638# else
639struct proc *p;
640# endif /* __FreeBSD_version >= 500024 */
641#else
642)
643#endif
644#if defined(_KERNEL) && (__FreeBSD_version >= 502116)
645struct cdev *dev;
646#else
647dev_t dev;
648#endif
649int flags;
650{
651	u_int min = GET_MINOR(dev);
652
653	if (IPL_LOGMAX < min)
654		min = ENXIO;
655	else
656		min = 0;
657	return min;
658}
659
660
661int iplclose(dev, flags
662#if ((BSD >= 199506) || (__FreeBSD_version >= 220000)) && defined(_KERNEL)
663, devtype, p)
664int devtype;
665# if (__FreeBSD_version >= 500024)
666struct thread *p;
667# else
668struct proc *p;
669# endif /* __FreeBSD_version >= 500024 */
670#else
671)
672#endif
673#if defined(_KERNEL) && (__FreeBSD_version >= 502116)
674struct cdev *dev;
675#else
676dev_t dev;
677#endif
678int flags;
679{
680	u_int	min = GET_MINOR(dev);
681
682	if (IPL_LOGMAX < min)
683		min = ENXIO;
684	else
685		min = 0;
686	return min;
687}
688
689/*
690 * iplread/ipllog
691 * both of these must operate with at least splnet() lest they be
692 * called during packet processing and cause an inconsistancy to appear in
693 * the filter lists.
694 */
695#if (BSD >= 199306)
696int iplread(dev, uio, ioflag)
697int ioflag;
698#else
699int iplread(dev, uio)
700#endif
701#if defined(_KERNEL) && (__FreeBSD_version >= 502116)
702struct cdev *dev;
703#else
704dev_t dev;
705#endif
706register struct uio *uio;
707{
708
709# ifdef	IPFILTER_SYNC
710	if (GET_MINOR(dev) == IPL_LOGSYNC)
711		return ipfsync_read(uio);
712# endif
713
714#ifdef IPFILTER_LOG
715	return ipflog_read(GET_MINOR(dev), uio);
716#else
717	return ENXIO;
718#endif
719}
720
721
722/*
723 * iplwrite
724 * both of these must operate with at least splnet() lest they be
725 * called during packet processing and cause an inconsistancy to appear in
726 * the filter lists.
727 */
728#if (BSD >= 199306)
729int iplwrite(dev, uio, ioflag)
730int ioflag;
731#else
732int iplwrite(dev, uio)
733#endif
734#if defined(_KERNEL) && (__FreeBSD_version >= 502116)
735struct cdev *dev;
736#else
737dev_t dev;
738#endif
739register struct uio *uio;
740{
741
742#ifdef	IPFILTER_SYNC
743	if (GET_MINOR(dev) == IPL_LOGSYNC)
744		return ipfsync_write(uio);
745#endif
746	return ENXIO;
747}
748
749
750/*
751 * fr_send_reset - this could conceivably be a call to tcp_respond(), but that
752 * requires a large amount of setting up and isn't any more efficient.
753 */
754int fr_send_reset(fin)
755fr_info_t *fin;
756{
757	struct tcphdr *tcp, *tcp2;
758	int tlen = 0, hlen;
759	struct mbuf *m;
760#ifdef USE_INET6
761	ip6_t *ip6;
762#endif
763	ip_t *ip;
764
765	tcp = fin->fin_dp;
766	if (tcp->th_flags & TH_RST)
767		return -1;		/* feedback loop */
768
769#ifndef	IPFILTER_CKSUM
770	if (fr_checkl4sum(fin) == -1)
771		return -1;
772#endif
773
774	tlen = fin->fin_dlen - (TCP_OFF(tcp) << 2) +
775			((tcp->th_flags & TH_SYN) ? 1 : 0) +
776			((tcp->th_flags & TH_FIN) ? 1 : 0);
777
778#ifdef USE_INET6
779	hlen = (fin->fin_v == 6) ? sizeof(ip6_t) : sizeof(ip_t);
780#else
781	hlen = sizeof(ip_t);
782#endif
783#ifdef MGETHDR
784	MGETHDR(m, M_DONTWAIT, MT_HEADER);
785#else
786	MGET(m, M_DONTWAIT, MT_HEADER);
787#endif
788	if (m == NULL)
789		return -1;
790	if (sizeof(*tcp2) + hlen > MLEN) {
791		MCLGET(m, M_DONTWAIT);
792		if ((m->m_flags & M_EXT) == 0) {
793			FREE_MB_T(m);
794			return -1;
795		}
796	}
797
798	m->m_len = sizeof(*tcp2) + hlen;
799#if (BSD >= 199103)
800	m->m_data += max_linkhdr;
801	m->m_pkthdr.len = m->m_len;
802	m->m_pkthdr.rcvif = (struct ifnet *)0;
803#endif
804	ip = mtod(m, struct ip *);
805	bzero((char *)ip, hlen);
806#ifdef USE_INET6
807	ip6 = (ip6_t *)ip;
808#endif
809	tcp2 = (struct tcphdr *)((char *)ip + hlen);
810	tcp2->th_sport = tcp->th_dport;
811	tcp2->th_dport = tcp->th_sport;
812
813	if (tcp->th_flags & TH_ACK) {
814		tcp2->th_seq = tcp->th_ack;
815		tcp2->th_flags = TH_RST;
816		tcp2->th_ack = 0;
817	} else {
818		tcp2->th_seq = 0;
819		tcp2->th_ack = ntohl(tcp->th_seq);
820		tcp2->th_ack += tlen;
821		tcp2->th_ack = htonl(tcp2->th_ack);
822		tcp2->th_flags = TH_RST|TH_ACK;
823	}
824	TCP_X2_A(tcp2, 0);
825	TCP_OFF_A(tcp2, sizeof(*tcp2) >> 2);
826	tcp2->th_win = tcp->th_win;
827	tcp2->th_sum = 0;
828	tcp2->th_urp = 0;
829
830#ifdef USE_INET6
831	if (fin->fin_v == 6) {
832		ip6->ip6_flow = ((ip6_t *)fin->fin_ip)->ip6_flow;
833		ip6->ip6_plen = htons(sizeof(struct tcphdr));
834		ip6->ip6_nxt = IPPROTO_TCP;
835		ip6->ip6_hlim = 0;
836		ip6->ip6_src = fin->fin_dst6;
837		ip6->ip6_dst = fin->fin_src6;
838		tcp2->th_sum = in6_cksum(m, IPPROTO_TCP,
839					 sizeof(*ip6), sizeof(*tcp2));
840		return fr_send_ip(fin, m, &m);
841	}
842#endif
843	ip->ip_p = IPPROTO_TCP;
844	ip->ip_len = htons(sizeof(struct tcphdr));
845	ip->ip_src.s_addr = fin->fin_daddr;
846	ip->ip_dst.s_addr = fin->fin_saddr;
847	tcp2->th_sum = in_cksum(m, hlen + sizeof(*tcp2));
848	ip->ip_len = hlen + sizeof(*tcp2);
849	return fr_send_ip(fin, m, &m);
850}
851
852
853static int fr_send_ip(fin, m, mpp)
854fr_info_t *fin;
855mb_t *m, **mpp;
856{
857	fr_info_t fnew;
858	ip_t *ip, *oip;
859	int hlen;
860
861	ip = mtod(m, ip_t *);
862	bzero((char *)&fnew, sizeof(fnew));
863
864	IP_V_A(ip, fin->fin_v);
865	switch (fin->fin_v)
866	{
867	case 4 :
868		fnew.fin_v = 4;
869		oip = fin->fin_ip;
870		IP_HL_A(ip, sizeof(*oip) >> 2);
871		ip->ip_tos = oip->ip_tos;
872		ip->ip_id = fin->fin_ip->ip_id;
873#if (__FreeBSD_version > 460000)
874		ip->ip_off = path_mtu_discovery ? IP_DF : 0;
875#else
876		ip->ip_off = 0;
877#endif
878		ip->ip_ttl = ip_defttl;
879		ip->ip_sum = 0;
880		hlen = sizeof(*oip);
881		break;
882#ifdef USE_INET6
883	case 6 :
884	{
885		ip6_t *ip6 = (ip6_t *)ip;
886
887		ip6->ip6_vfc = 0x60;
888		ip6->ip6_hlim = IPDEFTTL;
889
890		fnew.fin_v = 6;
891		hlen = sizeof(*ip6);
892		break;
893	}
894#endif
895	default :
896		return EINVAL;
897	}
898#ifdef IPSEC
899	m->m_pkthdr.rcvif = NULL;
900#endif
901
902	fnew.fin_ifp = fin->fin_ifp;
903	fnew.fin_flx = FI_NOCKSUM;
904	fnew.fin_m = m;
905	fnew.fin_ip = ip;
906	fnew.fin_mp = mpp;
907	fnew.fin_hlen = hlen;
908	fnew.fin_dp = (char *)ip + hlen;
909	(void) fr_makefrip(hlen, ip, &fnew);
910
911	return fr_fastroute(m, mpp, &fnew, NULL);
912}
913
914
915int fr_send_icmp_err(type, fin, dst)
916int type;
917fr_info_t *fin;
918int dst;
919{
920	int err, hlen, xtra, iclen, ohlen, avail, code;
921	struct in_addr dst4;
922	struct icmp *icmp;
923	struct mbuf *m;
924	void *ifp;
925#ifdef USE_INET6
926	ip6_t *ip6;
927	struct in6_addr dst6;
928#endif
929	ip_t *ip, *ip2;
930
931	if ((type < 0) || (type > ICMP_MAXTYPE))
932		return -1;
933
934	code = fin->fin_icode;
935#ifdef USE_INET6
936	if ((code < 0) || (code > sizeof(icmptoicmp6unreach)/sizeof(int)))
937		return -1;
938#endif
939
940#ifndef	IPFILTER_CKSUM
941	if (fr_checkl4sum(fin) == -1)
942		return -1;
943#endif
944#ifdef MGETHDR
945	MGETHDR(m, M_DONTWAIT, MT_HEADER);
946#else
947	MGET(m, M_DONTWAIT, MT_HEADER);
948#endif
949	if (m == NULL)
950		return -1;
951	avail = MHLEN;
952
953	xtra = 0;
954	hlen = 0;
955	ohlen = 0;
956	ifp = fin->fin_ifp;
957	if (fin->fin_v == 4) {
958		if ((fin->fin_p == IPPROTO_ICMP) &&
959		    !(fin->fin_flx & FI_SHORT))
960			switch (ntohs(fin->fin_data[0]) >> 8)
961			{
962			case ICMP_ECHO :
963			case ICMP_TSTAMP :
964			case ICMP_IREQ :
965			case ICMP_MASKREQ :
966				break;
967			default :
968				FREE_MB_T(m);
969				return 0;
970			}
971
972		if (dst == 0) {
973			if (fr_ifpaddr(4, FRI_NORMAL, ifp,
974				       &dst4, NULL) == -1) {
975				FREE_MB_T(m);
976				return -1;
977			}
978		} else
979			dst4.s_addr = fin->fin_daddr;
980
981		hlen = sizeof(ip_t);
982		ohlen = fin->fin_hlen;
983		if (fin->fin_hlen < fin->fin_plen)
984			xtra = MIN(fin->fin_dlen, 8);
985		else
986			xtra = 0;
987	}
988
989#ifdef USE_INET6
990	else if (fin->fin_v == 6) {
991		hlen = sizeof(ip6_t);
992		ohlen = sizeof(ip6_t);
993		type = icmptoicmp6types[type];
994		if (type == ICMP6_DST_UNREACH)
995			code = icmptoicmp6unreach[code];
996
997		if (hlen + sizeof(*icmp) + max_linkhdr +
998		    fin->fin_plen > avail) {
999			MCLGET(m, M_DONTWAIT);
1000			if ((m->m_flags & M_EXT) == 0) {
1001				FREE_MB_T(m);
1002				return -1;
1003			}
1004			avail = MCLBYTES;
1005		}
1006		xtra = MIN(fin->fin_plen,
1007			   avail - hlen - sizeof(*icmp) - max_linkhdr);
1008		if (dst == 0) {
1009			if (fr_ifpaddr(6, FRI_NORMAL, ifp,
1010				       (struct in_addr *)&dst6, NULL) == -1) {
1011				FREE_MB_T(m);
1012				return -1;
1013			}
1014		} else
1015			dst6 = fin->fin_dst6;
1016	}
1017#endif
1018	else {
1019		FREE_MB_T(m);
1020		return -1;
1021	}
1022
1023	iclen = hlen + sizeof(*icmp);
1024	avail -= (max_linkhdr + iclen);
1025	if (avail < 0) {
1026		FREE_MB_T(m);
1027		return -1;
1028	}
1029	if (xtra > avail)
1030		xtra = avail;
1031	iclen += xtra;
1032	m->m_data += max_linkhdr;
1033	m->m_pkthdr.rcvif = (struct ifnet *)0;
1034	m->m_pkthdr.len = iclen;
1035	m->m_len = iclen;
1036	ip = mtod(m, ip_t *);
1037	icmp = (struct icmp *)((char *)ip + hlen);
1038	ip2 = (ip_t *)&icmp->icmp_ip;
1039
1040	icmp->icmp_type = type;
1041	icmp->icmp_code = fin->fin_icode;
1042	icmp->icmp_cksum = 0;
1043#ifdef icmp_nextmtu
1044	if (type == ICMP_UNREACH &&
1045	    fin->fin_icode == ICMP_UNREACH_NEEDFRAG && ifp)
1046		icmp->icmp_nextmtu = htons(((struct ifnet *)ifp)->if_mtu);
1047#endif
1048
1049	bcopy((char *)fin->fin_ip, (char *)ip2, ohlen);
1050
1051#ifdef USE_INET6
1052	ip6 = (ip6_t *)ip;
1053	if (fin->fin_v == 6) {
1054		ip6->ip6_flow = ((ip6_t *)fin->fin_ip)->ip6_flow;
1055		ip6->ip6_plen = htons(iclen - hlen);
1056		ip6->ip6_nxt = IPPROTO_ICMPV6;
1057		ip6->ip6_hlim = 0;
1058		ip6->ip6_src = dst6;
1059		ip6->ip6_dst = fin->fin_src6;
1060		if (xtra > 0)
1061			bcopy((char *)fin->fin_ip + ohlen,
1062			      (char *)&icmp->icmp_ip + ohlen, xtra);
1063		icmp->icmp_cksum = in6_cksum(m, IPPROTO_ICMPV6,
1064					     sizeof(*ip6), iclen - hlen);
1065	} else
1066#endif
1067	{
1068		ip2->ip_len = htons(ip2->ip_len);
1069		ip2->ip_off = htons(ip2->ip_off);
1070		ip->ip_p = IPPROTO_ICMP;
1071		ip->ip_src.s_addr = dst4.s_addr;
1072		ip->ip_dst.s_addr = fin->fin_saddr;
1073
1074		if (xtra > 0)
1075			bcopy((char *)fin->fin_ip + ohlen,
1076			      (char *)&icmp->icmp_ip + ohlen, xtra);
1077		icmp->icmp_cksum = ipf_cksum((u_short *)icmp,
1078					     sizeof(*icmp) + 8);
1079		ip->ip_len = iclen;
1080		ip->ip_p = IPPROTO_ICMP;
1081	}
1082	err = fr_send_ip(fin, m, &m);
1083	return err;
1084}
1085
1086
1087#if !defined(IPFILTER_LKM) && (__FreeBSD_version < 300000)
1088# if	(BSD < 199306)
1089int iplinit __P((void));
1090
1091int
1092# else
1093void iplinit __P((void));
1094
1095void
1096# endif
1097iplinit()
1098{
1099	if (iplattach() != 0)
1100		printf("IP Filter failed to attach\n");
1101	ip_init();
1102}
1103#endif /* __FreeBSD_version < 300000 */
1104
1105
1106int fr_fastroute(m0, mpp, fin, fdp)
1107mb_t *m0, **mpp;
1108fr_info_t *fin;
1109frdest_t *fdp;
1110{
1111	register struct ip *ip, *mhip;
1112	register struct mbuf *m = m0;
1113	register struct route *ro;
1114	int len, off, error = 0, hlen, code;
1115	struct ifnet *ifp, *sifp;
1116	struct sockaddr_in *dst;
1117	struct route iproute;
1118	u_short ip_off;
1119	frentry_t *fr;
1120
1121#ifdef M_WRITABLE
1122	/*
1123	* HOT FIX/KLUDGE:
1124	*
1125	* If the mbuf we're about to send is not writable (because of
1126	* a cluster reference, for example) we'll need to make a copy
1127	* of it since this routine modifies the contents.
1128	*
1129	* If you have non-crappy network hardware that can transmit data
1130	* from the mbuf, rather than making a copy, this is gonna be a
1131	* problem.
1132	*/
1133	if (M_WRITABLE(m) == 0) {
1134		if ((m0 = m_dup(m, M_DONTWAIT)) != 0) {
1135			FREE_MB_T(m);
1136			m = m0;
1137			*mpp = m;
1138		} else {
1139			error = ENOBUFS;
1140			FREE_MB_T(m);
1141			*mpp = NULL;
1142			fr_frouteok[1]++;
1143		}
1144	}
1145#endif
1146
1147#ifdef USE_INET6
1148	if (fin->fin_v == 6) {
1149		/*
1150		 * currently "to <if>" and "to <if>:ip#" are not supported
1151		 * for IPv6
1152		 */
1153#if  (__FreeBSD_version >= 490000)
1154		return ip6_output(m0, NULL, NULL, 0, NULL, NULL, NULL);
1155#else
1156		return ip6_output(m0, NULL, NULL, 0, NULL, NULL);
1157#endif
1158	}
1159#endif
1160
1161	hlen = fin->fin_hlen;
1162	ip = mtod(m0, struct ip *);
1163
1164	/*
1165	 * Route packet.
1166	 */
1167	ro = &iproute;
1168	bzero((caddr_t)ro, sizeof (*ro));
1169	dst = (struct sockaddr_in *)&ro->ro_dst;
1170	dst->sin_family = AF_INET;
1171	dst->sin_addr = ip->ip_dst;
1172
1173	fr = fin->fin_fr;
1174	if (fdp != NULL)
1175		ifp = fdp->fd_ifp;
1176	else
1177		ifp = fin->fin_ifp;
1178
1179	if ((ifp == NULL) && (!fr || !(fr->fr_flags & FR_FASTROUTE))) {
1180		error = -2;
1181		goto bad;
1182	}
1183
1184	/*
1185	 * In case we're here due to "to <if>" being used with "keep state",
1186	 * check that we're going in the correct direction.
1187	 */
1188	if ((fr != NULL) && (fin->fin_rev != 0)) {
1189		if ((ifp != NULL) && (fdp == &fr->fr_tif))
1190			return -1;
1191	}
1192	if (fdp != NULL) {
1193		if (fdp->fd_ip.s_addr != 0)
1194			dst->sin_addr = fdp->fd_ip;
1195	}
1196
1197	dst->sin_len = sizeof(*dst);
1198	rtalloc(ro);
1199
1200	if ((ifp == NULL) && (ro->ro_rt != NULL))
1201		ifp = ro->ro_rt->rt_ifp;
1202
1203	if ((ro->ro_rt == NULL) || (ifp == NULL)) {
1204		if (in_localaddr(ip->ip_dst))
1205			error = EHOSTUNREACH;
1206		else
1207			error = ENETUNREACH;
1208		goto bad;
1209	}
1210	if (ro->ro_rt->rt_flags & RTF_GATEWAY)
1211		dst = (struct sockaddr_in *)ro->ro_rt->rt_gateway;
1212	if (ro->ro_rt)
1213		ro->ro_rt->rt_use++;
1214
1215	/*
1216	 * For input packets which are being "fastrouted", they won't
1217	 * go back through output filtering and miss their chance to get
1218	 * NAT'd and counted.
1219	 */
1220	if (fin->fin_out == 0) {
1221		sifp = fin->fin_ifp;
1222		fin->fin_ifp = ifp;
1223		fin->fin_out = 1;
1224		(void) fr_acctpkt(fin, NULL);
1225		fin->fin_fr = NULL;
1226		if (!fr || !(fr->fr_flags & FR_RETMASK)) {
1227			u_32_t pass;
1228
1229			(void) fr_checkstate(fin, &pass);
1230		}
1231
1232		switch (fr_checknatout(fin, NULL))
1233		{
1234		case 0 :
1235			break;
1236		case 1 :
1237			ip->ip_sum = 0;
1238			break;
1239		case -1 :
1240			error = -1;
1241			goto done;
1242			break;
1243		}
1244
1245		fin->fin_ifp = sifp;
1246		fin->fin_out = 0;
1247	} else
1248		ip->ip_sum = 0;
1249	/*
1250	 * If small enough for interface, can just send directly.
1251	 */
1252	if (ip->ip_len <= ifp->if_mtu) {
1253		ip->ip_len = htons(ip->ip_len);
1254		ip->ip_off = htons(ip->ip_off);
1255
1256		if (!ip->ip_sum)
1257			ip->ip_sum = in_cksum(m, hlen);
1258		error = (*ifp->if_output)(ifp, m, (struct sockaddr *)dst,
1259					  ro->ro_rt);
1260		goto done;
1261	}
1262	/*
1263	 * Too large for interface; fragment if possible.
1264	 * Must be able to put at least 8 bytes per fragment.
1265	 */
1266	ip_off = ntohs(ip->ip_off);
1267	if (ip_off & IP_DF) {
1268		error = EMSGSIZE;
1269		goto bad;
1270	}
1271	len = (ifp->if_mtu - hlen) &~ 7;
1272	if (len < 8) {
1273		error = EMSGSIZE;
1274		goto bad;
1275	}
1276
1277    {
1278	int mhlen, firstlen = len;
1279	struct mbuf **mnext = &m->m_act;
1280
1281	/*
1282	 * Loop through length of segment after first fragment,
1283	 * make new header and copy data of each part and link onto chain.
1284	 */
1285	m0 = m;
1286	mhlen = sizeof (struct ip);
1287	for (off = hlen + len; off < ip->ip_len; off += len) {
1288#ifdef MGETHDR
1289		MGETHDR(m, M_DONTWAIT, MT_HEADER);
1290#else
1291		MGET(m, M_DONTWAIT, MT_HEADER);
1292#endif
1293		if (m == 0) {
1294			m = m0;
1295			error = ENOBUFS;
1296			goto bad;
1297		}
1298		m->m_data += max_linkhdr;
1299		mhip = mtod(m, struct ip *);
1300		bcopy((char *)ip, (char *)mhip, sizeof(*ip));
1301		if (hlen > sizeof (struct ip)) {
1302			mhlen = ip_optcopy(ip, mhip) + sizeof (struct ip);
1303			IP_HL_A(mhip, mhlen >> 2);
1304		}
1305		m->m_len = mhlen;
1306		mhip->ip_off = ((off - hlen) >> 3) + ip_off;
1307		if (off + len >= ip->ip_len)
1308			len = ip->ip_len - off;
1309		else
1310			mhip->ip_off |= IP_MF;
1311		mhip->ip_len = htons((u_short)(len + mhlen));
1312		m->m_next = m_copy(m0, off, len);
1313		if (m->m_next == 0) {
1314			error = ENOBUFS;	/* ??? */
1315			goto sendorfree;
1316		}
1317		m->m_pkthdr.len = mhlen + len;
1318		m->m_pkthdr.rcvif = NULL;
1319		mhip->ip_off = htons((u_short)mhip->ip_off);
1320		mhip->ip_sum = 0;
1321		mhip->ip_sum = in_cksum(m, mhlen);
1322		*mnext = m;
1323		mnext = &m->m_act;
1324	}
1325	/*
1326	 * Update first fragment by trimming what's been copied out
1327	 * and updating header, then send each fragment (in order).
1328	 */
1329	m_adj(m0, hlen + firstlen - ip->ip_len);
1330	ip->ip_len = htons((u_short)(hlen + firstlen));
1331	ip->ip_off = htons((u_short)IP_MF);
1332	ip->ip_sum = 0;
1333	ip->ip_sum = in_cksum(m0, hlen);
1334sendorfree:
1335	for (m = m0; m; m = m0) {
1336		m0 = m->m_act;
1337		m->m_act = 0;
1338		if (error == 0)
1339			error = (*ifp->if_output)(ifp, m,
1340			    (struct sockaddr *)dst, ro->ro_rt);
1341		else
1342			FREE_MB_T(m);
1343	}
1344    }
1345done:
1346	if (!error)
1347		fr_frouteok[0]++;
1348	else
1349		fr_frouteok[1]++;
1350
1351	if (ro->ro_rt) {
1352		RTFREE(ro->ro_rt);
1353	}
1354	*mpp = NULL;
1355	return 0;
1356bad:
1357	if (error == EMSGSIZE) {
1358		sifp = fin->fin_ifp;
1359		code = fin->fin_icode;
1360		fin->fin_icode = ICMP_UNREACH_NEEDFRAG;
1361		fin->fin_ifp = ifp;
1362		(void) fr_send_icmp_err(ICMP_UNREACH, fin, 1);
1363		fin->fin_ifp = sifp;
1364		fin->fin_icode = code;
1365	}
1366	FREE_MB_T(m);
1367	goto done;
1368}
1369
1370
1371int fr_verifysrc(fin)
1372fr_info_t *fin;
1373{
1374	struct sockaddr_in *dst;
1375	struct route iproute;
1376
1377	bzero((char *)&iproute, sizeof(iproute));
1378	dst = (struct sockaddr_in *)&iproute.ro_dst;
1379	dst->sin_len = sizeof(*dst);
1380	dst->sin_family = AF_INET;
1381	dst->sin_addr = fin->fin_src;
1382	rtalloc(&iproute);
1383	if (iproute.ro_rt == NULL)
1384		return 0;
1385	return (fin->fin_ifp == iproute.ro_rt->rt_ifp);
1386}
1387
1388
1389/*
1390 * return the first IP Address associated with an interface
1391 */
1392int fr_ifpaddr(v, atype, ifptr, inp, inpmask)
1393int v, atype;
1394void *ifptr;
1395struct in_addr *inp, *inpmask;
1396{
1397#ifdef USE_INET6
1398	struct in6_addr *inp6 = NULL;
1399#endif
1400	struct sockaddr *sock, *mask;
1401	struct sockaddr_in *sin;
1402	struct ifaddr *ifa;
1403	struct ifnet *ifp;
1404
1405	if ((ifptr == NULL) || (ifptr == (void *)-1))
1406		return -1;
1407
1408	sin = NULL;
1409	ifp = ifptr;
1410
1411	if (v == 4)
1412		inp->s_addr = 0;
1413#ifdef USE_INET6
1414	else if (v == 6)
1415		bzero((char *)inp, sizeof(struct in6_addr));
1416#endif
1417#if  (__FreeBSD_version >= 300000)
1418	ifa = TAILQ_FIRST(&ifp->if_addrhead);
1419#else
1420	ifa = ifp->if_addrlist;
1421#endif /* __FreeBSD_version >= 300000 */
1422
1423	sock = ifa->ifa_addr;
1424	while (sock != NULL && ifa != NULL) {
1425		sin = (struct sockaddr_in *)sock;
1426		if ((v == 4) && (sin->sin_family == AF_INET))
1427			break;
1428#ifdef USE_INET6
1429		if ((v == 6) && (sin->sin_family == AF_INET6)) {
1430			inp6 = &((struct sockaddr_in6 *)sin)->sin6_addr;
1431			if (!IN6_IS_ADDR_LINKLOCAL(inp6) &&
1432			    !IN6_IS_ADDR_LOOPBACK(inp6))
1433				break;
1434		}
1435#endif
1436#if (__FreeBSD_version >= 300000)
1437		ifa = TAILQ_NEXT(ifa, ifa_link);
1438#else
1439		ifa = ifa->ifa_next;
1440#endif /* __FreeBSD_version >= 300000 */
1441		if (ifa != NULL)
1442			sock = ifa->ifa_addr;
1443	}
1444
1445	if (ifa == NULL || sin == NULL)
1446		return -1;
1447
1448	mask = ifa->ifa_netmask;
1449	if (atype == FRI_BROADCAST)
1450		sock = ifa->ifa_broadaddr;
1451	else if (atype == FRI_PEERADDR)
1452		sock = ifa->ifa_dstaddr;
1453
1454#ifdef USE_INET6
1455	if (v == 6) {
1456		return fr_ifpfillv6addr(atype, (struct sockaddr_in6 *)sock,
1457					(struct sockaddr_in6 *)mask,
1458					inp, inpmask);
1459	}
1460#endif
1461	return fr_ifpfillv4addr(atype, (struct sockaddr_in *)sock,
1462				(struct sockaddr_in *)mask, inp, inpmask);
1463}
1464
1465
1466u_32_t fr_newisn(fin)
1467fr_info_t *fin;
1468{
1469	u_32_t newiss;
1470#if  (__FreeBSD_version >= 400000)
1471	newiss = arc4random();
1472#else
1473	static iss_seq_off = 0;
1474	u_char hash[16];
1475	MD5_CTX ctx;
1476
1477	/*
1478	 * Compute the base value of the ISS.  It is a hash
1479	 * of (saddr, sport, daddr, dport, secret).
1480	 */
1481	MD5Init(&ctx);
1482
1483	MD5Update(&ctx, (u_char *) &fin->fin_fi.fi_src,
1484		  sizeof(fin->fin_fi.fi_src));
1485	MD5Update(&ctx, (u_char *) &fin->fin_fi.fi_dst,
1486		  sizeof(fin->fin_fi.fi_dst));
1487	MD5Update(&ctx, (u_char *) &fin->fin_dat, sizeof(fin->fin_dat));
1488
1489	MD5Update(&ctx, ipf_iss_secret, sizeof(ipf_iss_secret));
1490
1491	MD5Final(hash, &ctx);
1492
1493	memcpy(&newiss, hash, sizeof(newiss));
1494
1495	/*
1496	 * Now increment our "timer", and add it in to
1497	 * the computed value.
1498	 *
1499	 * XXX Use `addin'?
1500	 * XXX TCP_ISSINCR too large to use?
1501	 */
1502	iss_seq_off += 0x00010000;
1503	newiss += iss_seq_off;
1504#endif
1505	return newiss;
1506}
1507
1508
1509/* ------------------------------------------------------------------------ */
1510/* Function:    fr_nextipid                                                 */
1511/* Returns:     int - 0 == success, -1 == error (packet should be droppped) */
1512/* Parameters:  fin(I) - pointer to packet information                      */
1513/*                                                                          */
1514/* Returns the next IPv4 ID to use for this packet.                         */
1515/* ------------------------------------------------------------------------ */
1516u_short fr_nextipid(fin)
1517fr_info_t *fin;
1518{
1519#ifndef	RANDOM_IP_ID
1520	static u_short ipid = 0;
1521	u_short id;
1522
1523	MUTEX_ENTER(&ipf_rw);
1524	id = ipid++;
1525	MUTEX_EXIT(&ipf_rw);
1526#else
1527	u_short id;
1528
1529	id = ip_randomid();
1530#endif
1531
1532	return id;
1533}
1534
1535
1536INLINE void fr_checkv4sum(fin)
1537fr_info_t *fin;
1538{
1539#ifdef CSUM_DATA_VALID
1540	int manual = 0;
1541	u_short sum;
1542	ip_t *ip;
1543	mb_t *m;
1544
1545	if ((fin->fin_flx & FI_NOCKSUM) != 0)
1546		return;
1547
1548	m = fin->fin_m;
1549	if (m == NULL) {
1550		manual = 1;
1551		goto skipauto;
1552	}
1553	ip = fin->fin_ip;
1554
1555	if (m->m_pkthdr.csum_flags & CSUM_DATA_VALID) {
1556		if (m->m_pkthdr.csum_flags & CSUM_PSEUDO_HDR)
1557			sum = m->m_pkthdr.csum_data;
1558		else
1559			sum = in_pseudo(ip->ip_src.s_addr, ip->ip_dst.s_addr,
1560					htonl(m->m_pkthdr.csum_data +
1561					fin->fin_ip->ip_len + fin->fin_p));
1562		sum ^= 0xffff;
1563		if (sum != 0)
1564			fin->fin_flx |= FI_BAD;
1565	} else
1566		manual = 1;
1567skipauto:
1568# ifdef IPFILTER_CKSUM
1569	if (manual != 0)
1570		if (fr_checkl4sum(fin) == -1)
1571			fin->fin_flx |= FI_BAD;
1572# else
1573	;
1574# endif
1575#else
1576# ifdef IPFILTER_CKSUM
1577	if (fr_checkl4sum(fin) == -1)
1578		fin->fin_flx |= FI_BAD;
1579# endif
1580#endif
1581}
1582
1583
1584#ifdef USE_INET6
1585INLINE void fr_checkv6sum(fin)
1586fr_info_t *fin;
1587{
1588# ifdef IPFILTER_CKSUM
1589	if (fr_checkl4sum(fin) == -1)
1590		fin->fin_flx |= FI_BAD;
1591# endif
1592}
1593#endif /* USE_INET6 */
1594
1595
1596size_t mbufchainlen(m0)
1597struct mbuf *m0;
1598{
1599	size_t len;
1600
1601	if ((m0->m_flags & M_PKTHDR) != 0) {
1602		len = m0->m_pkthdr.len;
1603	} else {
1604		struct mbuf *m;
1605
1606		for (m = m0, len = 0; m != NULL; m = m->m_next)
1607			len += m->m_len;
1608	}
1609	return len;
1610}
1611
1612
1613/* ------------------------------------------------------------------------ */
1614/* Function:    fr_pullup                                                   */
1615/* Returns:     NULL == pullup failed, else pointer to protocol header      */
1616/* Parameters:  m(I)   - pointer to buffer where data packet starts         */
1617/*              fin(I) - pointer to packet information                      */
1618/*              len(I) - number of bytes to pullup                          */
1619/*                                                                          */
1620/* Attempt to move at least len bytes (from the start of the buffer) into a */
1621/* single buffer for ease of access.  Operating system native functions are */
1622/* used to manage buffers - if necessary.  If the entire packet ends up in  */
1623/* a single buffer, set the FI_COALESCE flag even though fr_coalesce() has  */
1624/* not been called.  Both fin_ip and fin_dp are updated before exiting _IF_ */
1625/* and ONLY if the pullup succeeds.                                         */
1626/*                                                                          */
1627/* We assume that 'min' is a pointer to a buffer that is part of the chain  */
1628/* of buffers that starts at *fin->fin_mp.                                  */
1629/* ------------------------------------------------------------------------ */
1630void *fr_pullup(min, fin, len)
1631mb_t *min;
1632fr_info_t *fin;
1633int len;
1634{
1635	int out = fin->fin_out, dpoff, ipoff;
1636	mb_t *m = min;
1637	char *ip;
1638
1639	if (m == NULL)
1640		return NULL;
1641
1642	ip = (char *)fin->fin_ip;
1643	if ((fin->fin_flx & FI_COALESCE) != 0)
1644		return ip;
1645
1646	ipoff = fin->fin_ipoff;
1647	if (fin->fin_dp != NULL)
1648		dpoff = (char *)fin->fin_dp - (char *)ip;
1649	else
1650		dpoff = 0;
1651
1652	if (M_LEN(m) < len) {
1653#ifdef MHLEN
1654		/*
1655		 * Assume that M_PKTHDR is set and just work with what is left
1656		 * rather than check..
1657		 * Should not make any real difference, anyway.
1658		 */
1659		if (len > MHLEN)
1660#else
1661		if (len > MLEN)
1662#endif
1663		{
1664#ifdef HAVE_M_PULLDOWN
1665			if (m_pulldown(m, 0, len, NULL) == NULL)
1666				m = NULL;
1667#else
1668			FREE_MB_T(*fin->fin_mp);
1669			m = NULL;
1670#endif
1671		} else
1672		{
1673			m = m_pullup(m, len);
1674		}
1675		*fin->fin_mp = m;
1676		fin->fin_m = m;
1677		if (m == NULL) {
1678			ATOMIC_INCL(frstats[out].fr_pull[1]);
1679			return NULL;
1680		}
1681		ip = MTOD(m, char *) + ipoff;
1682	}
1683
1684	ATOMIC_INCL(frstats[out].fr_pull[0]);
1685	fin->fin_ip = (ip_t *)ip;
1686	if (fin->fin_dp != NULL)
1687		fin->fin_dp = (char *)fin->fin_ip + dpoff;
1688
1689	if (len == fin->fin_plen)
1690		fin->fin_flx |= FI_COALESCE;
1691	return ip;
1692}
1693