ip_fil.c revision 170268
1/*	$FreeBSD: head/contrib/ipfilter/ip_fil.c 170268 2007-06-04 02:54:36Z darrenr $	*/
2
3/*
4 * Copyright (C) 1993-2001 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.c,v 2.133.2.16 2007/05/28 11:56:22 darrenr Exp $";
11#endif
12
13#ifndef	SOLARIS
14#define	SOLARIS	(defined(sun) && (defined(__svr4__) || defined(__SVR4)))
15#endif
16
17#include <sys/param.h>
18#if defined(__FreeBSD__) && !defined(__FreeBSD_version)
19# if defined(IPFILTER_LKM)
20#  ifndef __FreeBSD_cc_version
21#   include <osreldate.h>
22#  else
23#   if __FreeBSD_cc_version < 430000
24#    include <osreldate.h>
25#   endif
26#  endif
27# endif
28#endif
29#include <sys/errno.h>
30#if defined(__hpux) && (HPUXREV >= 1111) && !defined(_KERNEL)
31# include <sys/kern_svcs.h>
32#endif
33#include <sys/types.h>
34#define _KERNEL
35#define KERNEL
36#ifdef __OpenBSD__
37struct file;
38#endif
39#include <sys/uio.h>
40#undef _KERNEL
41#undef KERNEL
42#include <sys/file.h>
43#include <sys/ioctl.h>
44#ifdef __sgi
45# include <sys/ptimers.h>
46#endif
47#include <sys/time.h>
48#if !SOLARIS
49# if (NetBSD > 199609) || (OpenBSD > 199603) || (__FreeBSD_version >= 300000)
50#  include <sys/dirent.h>
51# else
52#  include <sys/dir.h>
53# endif
54#else
55# include <sys/filio.h>
56#endif
57#ifndef linux
58# include <sys/protosw.h>
59#endif
60#include <sys/socket.h>
61
62#include <stdio.h>
63#include <string.h>
64#include <stdlib.h>
65#include <ctype.h>
66#include <fcntl.h>
67
68#ifdef __hpux
69# define _NET_ROUTE_INCLUDED
70#endif
71#include <net/if.h>
72#ifdef sun
73# include <net/af.h>
74#endif
75#if __FreeBSD_version >= 300000
76# include <net/if_var.h>
77#endif
78#ifdef __sgi
79#include <sys/debug.h>
80# ifdef IFF_DRVRLOCK /* IRIX6 */
81#include <sys/hashing.h>
82# endif
83#endif
84#if defined(__FreeBSD__)
85# include "radix_ipf.h"
86#endif
87#ifndef __osf__
88# include <net/route.h>
89#endif
90#include <netinet/in.h>
91#if !(defined(__sgi) && !defined(IFF_DRVRLOCK)) /* IRIX < 6 */ && \
92    !defined(__hpux) && !defined(linux)
93# include <netinet/in_var.h>
94#endif
95#include <netinet/in_systm.h>
96#include <netinet/ip.h>
97#if !defined(linux)
98# include <netinet/ip_var.h>
99#endif
100#include <netinet/tcp.h>
101#if defined(__osf__)
102# include <netinet/tcp_timer.h>
103#endif
104#if defined(__osf__) || defined(__hpux) || defined(__sgi)
105# include "radix_ipf_local.h"
106# define _RADIX_H_
107#endif
108#include <netinet/udp.h>
109#include <netinet/tcpip.h>
110#include <netinet/ip_icmp.h>
111#include <unistd.h>
112#include <syslog.h>
113#include <arpa/inet.h>
114#ifdef __hpux
115# undef _NET_ROUTE_INCLUDED
116#endif
117#include "netinet/ip_compat.h"
118#include "netinet/ip_fil.h"
119#include "netinet/ip_nat.h"
120#include "netinet/ip_frag.h"
121#include "netinet/ip_state.h"
122#include "netinet/ip_proxy.h"
123#include "netinet/ip_auth.h"
124#ifdef	IPFILTER_SYNC
125#include "netinet/ip_sync.h"
126#endif
127#ifdef	IPFILTER_SCAN
128#include "netinet/ip_scan.h"
129#endif
130#include "netinet/ip_pool.h"
131#ifdef IPFILTER_COMPILED
132# include "netinet/ip_rules.h"
133#endif
134#if defined(__FreeBSD_version) && (__FreeBSD_version >= 300000)
135# include <sys/malloc.h>
136#endif
137#ifdef __hpux
138struct rtentry;
139#endif
140#include "md5.h"
141
142
143#if !defined(__osf__) && !defined(__linux__)
144extern	struct	protosw	inetsw[];
145#endif
146
147#include "ipt.h"
148static	struct	ifnet **ifneta = NULL;
149static	int	nifs = 0;
150
151static	void	fr_setifpaddr __P((struct ifnet *, char *));
152void	init_ifp __P((void));
153#if defined(__sgi) && (IRIX < 60500)
154static int 	no_output __P((struct ifnet *, struct mbuf *,
155			       struct sockaddr *));
156static int	write_output __P((struct ifnet *, struct mbuf *,
157				  struct sockaddr *));
158#else
159# if TRU64 >= 1885
160static int 	no_output __P((struct ifnet *, struct mbuf *,
161			       struct sockaddr *, struct rtentry *, char *));
162static int	write_output __P((struct ifnet *, struct mbuf *,
163				  struct sockaddr *, struct rtentry *, char *));
164# else
165static int 	no_output __P((struct ifnet *, struct mbuf *,
166			       struct sockaddr *, struct rtentry *));
167static int	write_output __P((struct ifnet *, struct mbuf *,
168				  struct sockaddr *, struct rtentry *));
169# endif
170#endif
171
172
173int ipfattach()
174{
175	fr_running = 1;
176	return 0;
177}
178
179
180int ipfdetach()
181{
182	fr_running = -1;
183	return 0;
184}
185
186
187/*
188 * Filter ioctl interface.
189 */
190int iplioctl(dev, cmd, data, mode)
191int dev;
192ioctlcmd_t cmd;
193caddr_t data;
194int mode;
195{
196	int error = 0, unit = 0, uid;
197	SPL_INT(s);
198
199	uid = getuid();
200	unit = dev;
201
202	SPL_NET(s);
203
204	error = fr_ioctlswitch(unit, data, cmd, mode, uid, NULL);
205	if (error != -1) {
206		SPL_X(s);
207		return error;
208	}
209
210	SPL_X(s);
211	return error;
212}
213
214
215void fr_forgetifp(ifp)
216void *ifp;
217{
218	register frentry_t *f;
219
220	WRITE_ENTER(&ipf_mutex);
221	for (f = ipacct[0][fr_active]; (f != NULL); f = f->fr_next)
222		if (f->fr_ifa == ifp)
223			f->fr_ifa = (void *)-1;
224	for (f = ipacct[1][fr_active]; (f != NULL); f = f->fr_next)
225		if (f->fr_ifa == ifp)
226			f->fr_ifa = (void *)-1;
227	for (f = ipfilter[0][fr_active]; (f != NULL); f = f->fr_next)
228		if (f->fr_ifa == ifp)
229			f->fr_ifa = (void *)-1;
230	for (f = ipfilter[1][fr_active]; (f != NULL); f = f->fr_next)
231		if (f->fr_ifa == ifp)
232			f->fr_ifa = (void *)-1;
233#ifdef	USE_INET6
234	for (f = ipacct6[0][fr_active]; (f != NULL); f = f->fr_next)
235		if (f->fr_ifa == ifp)
236			f->fr_ifa = (void *)-1;
237	for (f = ipacct6[1][fr_active]; (f != NULL); f = f->fr_next)
238		if (f->fr_ifa == ifp)
239			f->fr_ifa = (void *)-1;
240	for (f = ipfilter6[0][fr_active]; (f != NULL); f = f->fr_next)
241		if (f->fr_ifa == ifp)
242			f->fr_ifa = (void *)-1;
243	for (f = ipfilter6[1][fr_active]; (f != NULL); f = f->fr_next)
244		if (f->fr_ifa == ifp)
245			f->fr_ifa = (void *)-1;
246#endif
247	RWLOCK_EXIT(&ipf_mutex);
248	fr_natsync(ifp);
249}
250
251
252#if defined(__sgi) && (IRIX < 60500)
253static int no_output(ifp, m, s)
254#else
255# if TRU64 >= 1885
256static int no_output (ifp, m, s, rt, cp)
257char *cp;
258# else
259static int no_output(ifp, m, s, rt)
260# endif
261struct rtentry *rt;
262#endif
263struct ifnet *ifp;
264struct mbuf *m;
265struct sockaddr *s;
266{
267	return 0;
268}
269
270
271#if defined(__sgi) && (IRIX < 60500)
272static int write_output(ifp, m, s)
273#else
274# if TRU64 >= 1885
275static int write_output (ifp, m, s, rt, cp)
276char *cp;
277# else
278static int write_output(ifp, m, s, rt)
279# endif
280struct rtentry *rt;
281#endif
282struct ifnet *ifp;
283struct mbuf *m;
284struct sockaddr *s;
285{
286	char fname[32];
287	mb_t *mb;
288	ip_t *ip;
289	int fd;
290
291	mb = (mb_t *)m;
292	ip = MTOD(mb, ip_t *);
293
294#if (defined(NetBSD) && (NetBSD <= 1991011) && (NetBSD >= 199606)) || \
295    (defined(OpenBSD) && (OpenBSD >= 199603)) || defined(linux) || \
296    (defined(__FreeBSD__) && (__FreeBSD_version >= 501113))
297	sprintf(fname, "/tmp/%s", ifp->if_xname);
298#else
299	sprintf(fname, "/tmp/%s%d", ifp->if_name, ifp->if_unit);
300#endif
301	fd = open(fname, O_WRONLY|O_APPEND);
302	if (fd == -1) {
303		perror("open");
304		return -1;
305	}
306	write(fd, (char *)ip, ntohs(ip->ip_len));
307	close(fd);
308	return 0;
309}
310
311
312static void fr_setifpaddr(ifp, addr)
313struct ifnet *ifp;
314char *addr;
315{
316#ifdef __sgi
317	struct in_ifaddr *ifa;
318#else
319	struct ifaddr *ifa;
320#endif
321
322#if defined(__NetBSD__) || defined(__OpenBSD__) || defined(__FreeBSD__)
323	if (ifp->if_addrlist.tqh_first != NULL)
324#else
325# ifdef __sgi
326	if (ifp->in_ifaddr != NULL)
327# else
328	if (ifp->if_addrlist != NULL)
329# endif
330#endif
331		return;
332
333	ifa = (struct ifaddr *)malloc(sizeof(*ifa));
334#if defined(__NetBSD__) || defined(__OpenBSD__) || defined(__FreeBSD__)
335	ifp->if_addrlist.tqh_first = ifa;
336#else
337# ifdef __sgi
338	ifp->in_ifaddr = ifa;
339# else
340	ifp->if_addrlist = ifa;
341# endif
342#endif
343
344	if (ifa != NULL) {
345		struct sockaddr_in *sin;
346
347#ifdef __sgi
348		sin = (struct sockaddr_in *)&ifa->ia_addr;
349#else
350		sin = (struct sockaddr_in *)&ifa->ifa_addr;
351#endif
352		sin->sin_addr.s_addr = inet_addr(addr);
353		if (sin->sin_addr.s_addr == 0)
354			abort();
355	}
356}
357
358struct ifnet *get_unit(name, v)
359char *name;
360int v;
361{
362	struct ifnet *ifp, **ifpp, **old_ifneta;
363	char *addr;
364#if (defined(NetBSD) && (NetBSD <= 1991011) && (NetBSD >= 199606)) || \
365    (defined(OpenBSD) && (OpenBSD >= 199603)) || defined(linux) || \
366    (defined(__FreeBSD__) && (__FreeBSD_version >= 501113))
367
368	if (name == NULL)
369		name = "anon0";
370
371	addr = strchr(name, '=');
372	if (addr != NULL)
373		*addr++ = '\0';
374
375	for (ifpp = ifneta; ifpp && (ifp = *ifpp); ifpp++) {
376		if (!strcmp(name, ifp->if_xname)) {
377			if (addr != NULL)
378				fr_setifpaddr(ifp, addr);
379			return ifp;
380		}
381	}
382#else
383	char *s, ifname[LIFNAMSIZ+1];
384
385	if (name == NULL)
386		name = "anon0";
387
388	addr = strchr(name, '=');
389	if (addr != NULL)
390		*addr++ = '\0';
391
392	for (ifpp = ifneta; ifpp && (ifp = *ifpp); ifpp++) {
393		COPYIFNAME(ifp, ifname);
394		if (!strcmp(name, ifname)) {
395			if (addr != NULL)
396				fr_setifpaddr(ifp, addr);
397			return ifp;
398		}
399	}
400#endif
401
402	if (!ifneta) {
403		ifneta = (struct ifnet **)malloc(sizeof(ifp) * 2);
404		if (!ifneta)
405			return NULL;
406		ifneta[1] = NULL;
407		ifneta[0] = (struct ifnet *)calloc(1, sizeof(*ifp));
408		if (!ifneta[0]) {
409			free(ifneta);
410			return NULL;
411		}
412		nifs = 1;
413	} else {
414		old_ifneta = ifneta;
415		nifs++;
416		ifneta = (struct ifnet **)realloc(ifneta,
417						  (nifs + 1) * sizeof(ifp));
418		if (!ifneta) {
419			free(old_ifneta);
420			nifs = 0;
421			return NULL;
422		}
423		ifneta[nifs] = NULL;
424		ifneta[nifs - 1] = (struct ifnet *)malloc(sizeof(*ifp));
425		if (!ifneta[nifs - 1]) {
426			nifs--;
427			return NULL;
428		}
429	}
430	ifp = ifneta[nifs - 1];
431
432#if (defined(NetBSD) && (NetBSD <= 1991011) && (NetBSD >= 199606)) || \
433    (defined(OpenBSD) && (OpenBSD >= 199603)) || defined(linux) || \
434    (defined(__FreeBSD__) && (__FreeBSD_version >= 501113))
435	(void) strncpy(ifp->if_xname, name, sizeof(ifp->if_xname));
436#else
437	for (s = name; *s && !ISDIGIT(*s); s++)
438		;
439	if (*s && ISDIGIT(*s)) {
440		ifp->if_unit = atoi(s);
441		ifp->if_name = (char *)malloc(s - name + 1);
442		(void) strncpy(ifp->if_name, name, s - name);
443		ifp->if_name[s - name] = '\0';
444	} else {
445		ifp->if_name = strdup(name);
446		ifp->if_unit = -1;
447	}
448#endif
449	ifp->if_output = (void *)no_output;
450
451	if (addr != NULL) {
452		fr_setifpaddr(ifp, addr);
453	}
454
455	return ifp;
456}
457
458
459char *get_ifname(ifp)
460struct ifnet *ifp;
461{
462	static char ifname[LIFNAMSIZ];
463
464#if defined(__OpenBSD__) || defined(__NetBSD__) || defined(linux) || \
465    (defined(__FreeBSD__) && (__FreeBSD_version >= 501113))
466	sprintf(ifname, "%s", ifp->if_xname);
467#else
468	sprintf(ifname, "%s%d", ifp->if_name, ifp->if_unit);
469#endif
470	return ifname;
471}
472
473
474
475void init_ifp()
476{
477	struct ifnet *ifp, **ifpp;
478	char fname[32];
479	int fd;
480
481#if (defined(NetBSD) && (NetBSD <= 1991011) && (NetBSD >= 199606)) || \
482    (defined(OpenBSD) && (OpenBSD >= 199603)) || defined(linux) || \
483    (defined(__FreeBSD__) && (__FreeBSD_version >= 501113))
484	for (ifpp = ifneta; ifpp && (ifp = *ifpp); ifpp++) {
485		ifp->if_output = (void *)write_output;
486		sprintf(fname, "/tmp/%s", ifp->if_xname);
487		fd = open(fname, O_WRONLY|O_CREAT|O_EXCL|O_TRUNC, 0600);
488		if (fd == -1)
489			perror("open");
490		else
491			close(fd);
492	}
493#else
494
495	for (ifpp = ifneta; ifpp && (ifp = *ifpp); ifpp++) {
496		ifp->if_output = write_output;
497		sprintf(fname, "/tmp/%s%d", ifp->if_name, ifp->if_unit);
498		fd = open(fname, O_WRONLY|O_CREAT|O_EXCL|O_TRUNC, 0600);
499		if (fd == -1)
500			perror("open");
501		else
502			close(fd);
503	}
504#endif
505}
506
507
508int fr_fastroute(m, mpp, fin, fdp)
509mb_t *m, **mpp;
510fr_info_t *fin;
511frdest_t *fdp;
512{
513	struct ifnet *ifp = fdp->fd_ifp;
514	ip_t *ip = fin->fin_ip;
515	int error = 0;
516	frentry_t *fr;
517	void *sifp;
518
519	if (!ifp)
520		return 0;	/* no routing table out here */
521
522	fr = fin->fin_fr;
523	ip->ip_sum = 0;
524
525	if (fin->fin_out == 0) {
526		sifp = fin->fin_ifp;
527		fin->fin_ifp = ifp;
528		fin->fin_out = 1;
529		(void) fr_acctpkt(fin, NULL);
530		fin->fin_fr = NULL;
531		if (!fr || !(fr->fr_flags & FR_RETMASK)) {
532			u_32_t pass;
533
534			(void) fr_checkstate(fin, &pass);
535		}
536
537		switch (fr_checknatout(fin, NULL))
538		{
539		case 0 :
540			break;
541		case 1 :
542			ip->ip_sum = 0;
543			break;
544		case -1 :
545			error = -1;
546			goto done;
547			break;
548		}
549
550		fin->fin_ifp = sifp;
551		fin->fin_out = 0;
552	}
553
554#if defined(__sgi) && (IRIX < 60500)
555	(*ifp->if_output)(ifp, (void *)ip, NULL);
556# if TRU64 >= 1885
557	(*ifp->if_output)(ifp, (void *)m, NULL, 0, 0);
558# else
559	(*ifp->if_output)(ifp, (void *)m, NULL, 0);
560# endif
561#endif
562done:
563	return error;
564}
565
566
567int fr_send_reset(fin)
568fr_info_t *fin;
569{
570	verbose("- TCP RST sent\n");
571	return 0;
572}
573
574
575int fr_send_icmp_err(type, fin, dst)
576int type;
577fr_info_t *fin;
578int dst;
579{
580	verbose("- ICMP unreachable sent\n");
581	return 0;
582}
583
584
585void frsync(ifp)
586void *ifp;
587{
588	return;
589}
590
591
592void m_freem(m)
593mb_t *m;
594{
595	return;
596}
597
598
599void m_copydata(m, off, len, cp)
600mb_t *m;
601int off, len;
602caddr_t cp;
603{
604	bcopy((char *)m + off, cp, len);
605}
606
607
608int ipfuiomove(buf, len, rwflag, uio)
609caddr_t buf;
610int len, rwflag;
611struct uio *uio;
612{
613	int left, ioc, num, offset;
614	struct iovec *io;
615	char *start;
616
617	if (rwflag == UIO_READ) {
618		left = len;
619		ioc = 0;
620
621		offset = uio->uio_offset;
622
623		while ((left > 0) && (ioc < uio->uio_iovcnt)) {
624			io = uio->uio_iov + ioc;
625			num = io->iov_len;
626			if (num > left)
627				num = left;
628			start = (char *)io->iov_base + offset;
629			if (start > (char *)io->iov_base + io->iov_len) {
630				offset -= io->iov_len;
631				ioc++;
632				continue;
633			}
634			bcopy(buf, start, num);
635			uio->uio_resid -= num;
636			uio->uio_offset += num;
637			left -= num;
638			if (left > 0)
639				ioc++;
640		}
641		if (left > 0)
642			return EFAULT;
643	}
644	return 0;
645}
646
647
648u_32_t fr_newisn(fin)
649fr_info_t *fin;
650{
651	static int iss_seq_off = 0;
652	u_char hash[16];
653	u_32_t newiss;
654	MD5_CTX ctx;
655
656	/*
657	 * Compute the base value of the ISS.  It is a hash
658	 * of (saddr, sport, daddr, dport, secret).
659	 */
660	MD5Init(&ctx);
661
662	MD5Update(&ctx, (u_char *) &fin->fin_fi.fi_src,
663		  sizeof(fin->fin_fi.fi_src));
664	MD5Update(&ctx, (u_char *) &fin->fin_fi.fi_dst,
665		  sizeof(fin->fin_fi.fi_dst));
666	MD5Update(&ctx, (u_char *) &fin->fin_dat, sizeof(fin->fin_dat));
667
668	/* MD5Update(&ctx, ipf_iss_secret, sizeof(ipf_iss_secret)); */
669
670	MD5Final(hash, &ctx);
671
672	memcpy(&newiss, hash, sizeof(newiss));
673
674	/*
675	 * Now increment our "timer", and add it in to
676	 * the computed value.
677	 *
678	 * XXX Use `addin'?
679	 * XXX TCP_ISSINCR too large to use?
680	 */
681	iss_seq_off += 0x00010000;
682	newiss += iss_seq_off;
683	return newiss;
684}
685
686
687/* ------------------------------------------------------------------------ */
688/* Function:    fr_nextipid                                                 */
689/* Returns:     int - 0 == success, -1 == error (packet should be droppped) */
690/* Parameters:  fin(I) - pointer to packet information                      */
691/*                                                                          */
692/* Returns the next IPv4 ID to use for this packet.                         */
693/* ------------------------------------------------------------------------ */
694INLINE u_short fr_nextipid(fin)
695fr_info_t *fin;
696{
697	static u_short ipid = 0;
698	u_short id;
699
700	MUTEX_ENTER(&ipf_rw);
701	id = ipid++;
702	MUTEX_EXIT(&ipf_rw);
703
704	return id;
705}
706
707
708INLINE void fr_checkv4sum(fin)
709fr_info_t *fin;
710{
711	if (fr_checkl4sum(fin) == -1)
712		fin->fin_flx |= FI_BAD;
713}
714
715
716#ifdef	USE_INET6
717INLINE void fr_checkv6sum(fin)
718fr_info_t *fin;
719{
720	if (fr_checkl4sum(fin) == -1)
721		fin->fin_flx |= FI_BAD;
722}
723#endif
724
725
726/*
727 * See above for description, except that all addressing is in user space.
728 */
729int copyoutptr(src, dst, size)
730void *src, *dst;
731size_t size;
732{
733	caddr_t ca;
734
735	bcopy(dst, (char *)&ca, sizeof(ca));
736	bcopy(src, ca, size);
737	return 0;
738}
739
740
741/*
742 * See above for description, except that all addressing is in user space.
743 */
744int copyinptr(src, dst, size)
745void *src, *dst;
746size_t size;
747{
748	caddr_t ca;
749
750	bcopy(src, (char *)&ca, sizeof(ca));
751	bcopy(ca, dst, size);
752	return 0;
753}
754
755
756/*
757 * return the first IP Address associated with an interface
758 */
759int fr_ifpaddr(v, atype, ifptr, inp, inpmask)
760int v, atype;
761void *ifptr;
762struct in_addr *inp, *inpmask;
763{
764	struct ifnet *ifp = ifptr;
765#ifdef __sgi
766	struct in_ifaddr *ifa;
767#else
768	struct ifaddr *ifa;
769#endif
770
771#if defined(__NetBSD__) || defined(__OpenBSD__) || defined(__FreeBSD__)
772	ifa = ifp->if_addrlist.tqh_first;
773#else
774# ifdef __sgi
775	ifa = (struct in_ifaddr *)ifp->in_ifaddr;
776# else
777	ifa = ifp->if_addrlist;
778# endif
779#endif
780	if (ifa != NULL) {
781		struct sockaddr_in *sin, mask;
782
783		mask.sin_addr.s_addr = 0xffffffff;
784
785#ifdef __sgi
786		sin = (struct sockaddr_in *)&ifa->ia_addr;
787#else
788		sin = (struct sockaddr_in *)&ifa->ifa_addr;
789#endif
790
791		return fr_ifpfillv4addr(atype, sin, &mask, inp, inpmask);
792	}
793	return 0;
794}
795
796
797int ipfsync()
798{
799	return 0;
800}
801