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