1/*	$FreeBSD$	*/
2
3/*
4 * Copyright (C) 2012 by Darren Reed.
5 *
6 * See the IPFILTER.LICENCE file for details on licencing.
7 *
8 * $Id$
9 */
10#if !defined(lint)
11static const char sccsid[] = "@(#)ip_fil.c	2.41 6/5/96 (C) 1993-2000 Darren Reed";
12static const char rcsid[] = "@(#)$Id$";
13#endif
14
15#include "ipf.h"
16#include "md5.h"
17#include "ipt.h"
18
19ipf_main_softc_t	ipfmain;
20
21static	struct	ifnet **ifneta = NULL;
22static	int	nifs = 0;
23
24struct	rtentry;
25
26static	void	ipf_setifpaddr __P((struct ifnet *, char *));
27void	init_ifp __P((void));
28static int 	no_output __P((struct ifnet *, struct mbuf *,
29			       struct sockaddr *, struct rtentry *));
30static int	write_output __P((struct ifnet *, struct mbuf *,
31				  struct sockaddr *, struct rtentry *));
32
33struct ifaddr {
34	struct sockaddr_storage ifa_addr;
35};
36
37int
38ipfattach(softc)
39	ipf_main_softc_t *softc;
40{
41	return 0;
42}
43
44
45int
46ipfdetach(softc)
47	ipf_main_softc_t *softc;
48{
49	return 0;
50}
51
52
53/*
54 * Filter ioctl interface.
55 */
56int
57ipfioctl(softc, dev, cmd, data, mode)
58	ipf_main_softc_t *softc;
59	int dev;
60	ioctlcmd_t cmd;
61	caddr_t data;
62	int mode;
63{
64	int error = 0, unit = 0, uid;
65
66	uid = getuid();
67	unit = dev;
68
69	SPL_NET(s);
70
71	error = ipf_ioctlswitch(softc, unit, data, cmd, mode, uid, NULL);
72	if (error != -1) {
73		SPL_X(s);
74		return error;
75	}
76	SPL_X(s);
77	return error;
78}
79
80
81void
82ipf_forgetifp(softc, ifp)
83	ipf_main_softc_t *softc;
84	void *ifp;
85{
86	register frentry_t *f;
87
88	WRITE_ENTER(&softc->ipf_mutex);
89	for (f = softc->ipf_acct[0][softc->ipf_active]; (f != NULL);
90	     f = f->fr_next)
91		if (f->fr_ifa == ifp)
92			f->fr_ifa = (void *)-1;
93	for (f = softc->ipf_acct[1][softc->ipf_active]; (f != NULL);
94	     f = f->fr_next)
95		if (f->fr_ifa == ifp)
96			f->fr_ifa = (void *)-1;
97	for (f = softc->ipf_rules[0][softc->ipf_active]; (f != NULL);
98	     f = f->fr_next)
99		if (f->fr_ifa == ifp)
100			f->fr_ifa = (void *)-1;
101	for (f = softc->ipf_rules[1][softc->ipf_active]; (f != NULL);
102	     f = f->fr_next)
103		if (f->fr_ifa == ifp)
104			f->fr_ifa = (void *)-1;
105	RWLOCK_EXIT(&softc->ipf_mutex);
106	ipf_nat_sync(softc, ifp);
107	ipf_lookup_sync(softc, ifp);
108}
109
110
111static int
112no_output(ifp, m, s, rt)
113	struct rtentry *rt;
114	struct ifnet *ifp;
115	struct mbuf *m;
116	struct sockaddr *s;
117{
118	return 0;
119}
120
121
122static int
123write_output(ifp, m, s, rt)
124	struct rtentry *rt;
125	struct ifnet *ifp;
126	struct mbuf *m;
127	struct sockaddr *s;
128{
129	char fname[32];
130	mb_t *mb;
131	ip_t *ip;
132	int fd;
133
134	mb = (mb_t *)m;
135	ip = MTOD(mb, ip_t *);
136
137#if (defined(NetBSD) && (NetBSD <= 1991011) && (NetBSD >= 199606)) || \
138    defined(__FreeBSD__)
139	sprintf(fname, "/tmp/%s", ifp->if_xname);
140#else
141	sprintf(fname, "/tmp/%s%d", ifp->if_name, ifp->if_unit);
142#endif
143	fd = open(fname, O_WRONLY|O_APPEND);
144	if (fd == -1) {
145		perror("open");
146		return -1;
147	}
148	write(fd, (char *)ip, ntohs(ip->ip_len));
149	close(fd);
150	return 0;
151}
152
153
154static void
155ipf_setifpaddr(ifp, addr)
156	struct ifnet *ifp;
157	char *addr;
158{
159	struct ifaddr *ifa;
160
161#if defined(__NetBSD__) || defined(__FreeBSD__)
162	if (ifp->if_addrlist.tqh_first != NULL)
163#else
164	if (ifp->if_addrlist != NULL)
165#endif
166		return;
167
168	ifa = (struct ifaddr *)malloc(sizeof(*ifa));
169#if defined(__NetBSD__) || defined(__FreeBSD__)
170	ifp->if_addrlist.tqh_first = ifa;
171#else
172	ifp->if_addrlist = ifa;
173#endif
174
175	if (ifa != NULL) {
176		struct sockaddr_in *sin;
177
178		sin = (struct sockaddr_in *)&ifa->ifa_addr;
179#ifdef USE_INET6
180		if (index(addr, ':') != NULL) {
181			struct sockaddr_in6 *sin6;
182
183			sin6 = (struct sockaddr_in6 *)&ifa->ifa_addr;
184			sin6->sin6_family = AF_INET6;
185			/* Abort if bad address. */
186			switch (inet_pton(AF_INET6, addr, &sin6->sin6_addr))
187			{
188			case 1:
189				break;
190			case -1:
191				perror("inet_pton");
192				abort();
193				break;
194			default:
195				abort();
196				break;
197			}
198		} else
199#endif
200		{
201			sin->sin_family = AF_INET;
202			sin->sin_addr.s_addr = inet_addr(addr);
203			if (sin->sin_addr.s_addr == 0)
204				abort();
205		}
206	}
207}
208
209struct ifnet *
210get_unit(name, family)
211	char *name;
212	int family;
213{
214	struct ifnet *ifp, **ifpp, **old_ifneta;
215	char *addr;
216#if (defined(NetBSD) && (NetBSD <= 1991011) && (NetBSD >= 199606)) || \
217    defined(__FreeBSD__)
218
219	if (!*name)
220		return NULL;
221
222	if (name == NULL)
223		name = "anon0";
224
225	addr = strchr(name, '=');
226	if (addr != NULL)
227		*addr++ = '\0';
228
229	for (ifpp = ifneta; ifpp && (ifp = *ifpp); ifpp++) {
230		if (!strcmp(name, ifp->if_xname)) {
231			if (addr != NULL)
232				ipf_setifpaddr(ifp, addr);
233			return ifp;
234		}
235	}
236#else
237	char *s, ifname[LIFNAMSIZ+1];
238
239	if (name == NULL)
240		name = "anon0";
241
242	addr = strchr(name, '=');
243	if (addr != NULL)
244		*addr++ = '\0';
245
246	for (ifpp = ifneta; ifpp && (ifp = *ifpp); ifpp++) {
247		COPYIFNAME(family, ifp, ifname);
248		if (!strcmp(name, ifname)) {
249			if (addr != NULL)
250				ipf_setifpaddr(ifp, addr);
251			return ifp;
252		}
253	}
254#endif
255
256	if (!ifneta) {
257		ifneta = (struct ifnet **)malloc(sizeof(ifp) * 2);
258		if (!ifneta)
259			return NULL;
260		ifneta[1] = NULL;
261		ifneta[0] = (struct ifnet *)calloc(1, sizeof(*ifp));
262		if (!ifneta[0]) {
263			free(ifneta);
264			return NULL;
265		}
266		nifs = 1;
267	} else {
268		old_ifneta = ifneta;
269		nifs++;
270		ifneta = (struct ifnet **)reallocarray(ifneta, nifs + 1,
271						  sizeof(ifp));
272		if (!ifneta) {
273			free(old_ifneta);
274			nifs = 0;
275			return NULL;
276		}
277		ifneta[nifs] = NULL;
278		ifneta[nifs - 1] = (struct ifnet *)malloc(sizeof(*ifp));
279		if (!ifneta[nifs - 1]) {
280			nifs--;
281			return NULL;
282		}
283	}
284	ifp = ifneta[nifs - 1];
285
286#if defined(__NetBSD__) || defined(__FreeBSD__)
287	TAILQ_INIT(&ifp->if_addrlist);
288#endif
289#if (defined(NetBSD) && (NetBSD <= 1991011) && (NetBSD >= 199606)) || \
290    defined(__FreeBSD__)
291	(void) strncpy(ifp->if_xname, name, sizeof(ifp->if_xname));
292#else
293	s = name + strlen(name) - 1;
294	for (; s > name; s--) {
295		if (!ISDIGIT(*s)) {
296			s++;
297			break;
298		}
299	}
300
301	if ((s > name) && (*s != 0) && ISDIGIT(*s)) {
302		ifp->if_unit = atoi(s);
303		ifp->if_name = (char *)malloc(s - name + 1);
304		(void) strncpy(ifp->if_name, name, s - name);
305		ifp->if_name[s - name] = '\0';
306	} else {
307		ifp->if_name = strdup(name);
308		ifp->if_unit = -1;
309	}
310#endif
311	ifp->if_output = (void *)no_output;
312
313	if (addr != NULL) {
314		ipf_setifpaddr(ifp, addr);
315	}
316
317	return ifp;
318}
319
320
321char *
322get_ifname(ifp)
323	struct ifnet *ifp;
324{
325	static char ifname[LIFNAMSIZ];
326
327#if defined(__NetBSD__) || defined(__FreeBSD__)
328	sprintf(ifname, "%s", ifp->if_xname);
329#else
330	if (ifp->if_unit != -1)
331		sprintf(ifname, "%s%d", ifp->if_name, ifp->if_unit);
332	else
333		strcpy(ifname, ifp->if_name);
334#endif
335	return ifname;
336}
337
338
339
340void
341init_ifp()
342{
343	struct ifnet *ifp, **ifpp;
344	char fname[32];
345	int fd;
346
347#if (defined(NetBSD) && (NetBSD <= 1991011) && (NetBSD >= 199606)) || \
348    defined(__FreeBSD__)
349	for (ifpp = ifneta; ifpp && (ifp = *ifpp); ifpp++) {
350		ifp->if_output = (void *)write_output;
351		sprintf(fname, "/tmp/%s", ifp->if_xname);
352		fd = open(fname, O_WRONLY|O_CREAT|O_EXCL|O_TRUNC, 0600);
353		if (fd == -1)
354			perror("open");
355		else
356			close(fd);
357	}
358#else
359
360	for (ifpp = ifneta; ifpp && (ifp = *ifpp); ifpp++) {
361		ifp->if_output = (void *)write_output;
362		sprintf(fname, "/tmp/%s%d", ifp->if_name, ifp->if_unit);
363		fd = open(fname, O_WRONLY|O_CREAT|O_EXCL|O_TRUNC, 0600);
364		if (fd == -1)
365			perror("open");
366		else
367			close(fd);
368	}
369#endif
370}
371
372
373int
374ipf_fastroute(m, mpp, fin, fdp)
375	mb_t *m, **mpp;
376	fr_info_t *fin;
377	frdest_t *fdp;
378{
379	struct ifnet *ifp;
380	ip_t *ip = fin->fin_ip;
381	frdest_t node;
382	int error = 0;
383	frentry_t *fr;
384	void *sifp;
385	int sout;
386
387	sifp = fin->fin_ifp;
388	sout = fin->fin_out;
389	fr = fin->fin_fr;
390	ip->ip_sum = 0;
391
392	if (!(fr->fr_flags & FR_KEEPSTATE) && (fdp != NULL) &&
393	    (fdp->fd_type == FRD_DSTLIST)) {
394		bzero(&node, sizeof(node));
395		ipf_dstlist_select_node(fin, fdp->fd_ptr, NULL, &node);
396		fdp = &node;
397	}
398	ifp = fdp->fd_ptr;
399
400	if (ifp == NULL)
401		return 0;	/* no routing table out here */
402
403	if (fin->fin_out == 0) {
404		fin->fin_ifp = ifp;
405		fin->fin_out = 1;
406		(void) ipf_acctpkt(fin, NULL);
407		fin->fin_fr = NULL;
408		if (!fr || !(fr->fr_flags & FR_RETMASK)) {
409			u_32_t pass;
410
411			(void) ipf_state_check(fin, &pass);
412		}
413
414		switch (ipf_nat_checkout(fin, NULL))
415		{
416		case 0 :
417			break;
418		case 1 :
419			ip->ip_sum = 0;
420			break;
421		case -1 :
422			error = -1;
423			goto done;
424			break;
425		}
426
427	}
428
429	m->mb_ifp = ifp;
430	printpacket(fin->fin_out, m);
431
432	(*ifp->if_output)(ifp, (void *)m, NULL, 0);
433done:
434	fin->fin_ifp = sifp;
435	fin->fin_out = sout;
436	return error;
437}
438
439
440int
441ipf_send_reset(fin)
442	fr_info_t *fin;
443{
444	ipfkverbose("- TCP RST sent\n");
445	return 0;
446}
447
448
449int
450ipf_send_icmp_err(type, fin, dst)
451	int type;
452	fr_info_t *fin;
453	int dst;
454{
455	ipfkverbose("- ICMP unreachable sent\n");
456	return 0;
457}
458
459
460void
461m_freem(m)
462	mb_t *m;
463{
464	return;
465}
466
467
468void
469m_copydata(m, off, len, cp)
470	mb_t *m;
471	int off, len;
472	caddr_t cp;
473{
474	bcopy((char *)m + off, cp, len);
475}
476
477
478int
479ipfuiomove(buf, len, rwflag, uio)
480	caddr_t buf;
481	int len, rwflag;
482	struct uio *uio;
483{
484	int left, ioc, num, offset;
485	struct iovec *io;
486	char *start;
487
488	if (rwflag == UIO_READ) {
489		left = len;
490		ioc = 0;
491
492		offset = uio->uio_offset;
493
494		while ((left > 0) && (ioc < uio->uio_iovcnt)) {
495			io = uio->uio_iov + ioc;
496			num = io->iov_len;
497			if (num > left)
498				num = left;
499			start = (char *)io->iov_base + offset;
500			if (start > (char *)io->iov_base + io->iov_len) {
501				offset -= io->iov_len;
502				ioc++;
503				continue;
504			}
505			bcopy(buf, start, num);
506			uio->uio_resid -= num;
507			uio->uio_offset += num;
508			left -= num;
509			if (left > 0)
510				ioc++;
511		}
512		if (left > 0)
513			return EFAULT;
514	}
515	return 0;
516}
517
518
519u_32_t
520ipf_newisn(fin)
521	fr_info_t *fin;
522{
523	static int iss_seq_off = 0;
524	u_char hash[16];
525	u_32_t newiss;
526	MD5_CTX ctx;
527
528	/*
529	 * Compute the base value of the ISS.  It is a hash
530	 * of (saddr, sport, daddr, dport, secret).
531	 */
532	MD5Init(&ctx);
533
534	MD5Update(&ctx, (u_char *) &fin->fin_fi.fi_src,
535		  sizeof(fin->fin_fi.fi_src));
536	MD5Update(&ctx, (u_char *) &fin->fin_fi.fi_dst,
537		  sizeof(fin->fin_fi.fi_dst));
538	MD5Update(&ctx, (u_char *) &fin->fin_dat, sizeof(fin->fin_dat));
539
540	/* MD5Update(&ctx, ipf_iss_secret, sizeof(ipf_iss_secret)); */
541
542	MD5Final(hash, &ctx);
543
544	memcpy(&newiss, hash, sizeof(newiss));
545
546	/*
547	 * Now increment our "timer", and add it in to
548	 * the computed value.
549	 *
550	 * XXX Use `addin'?
551	 * XXX TCP_ISSINCR too large to use?
552	 */
553	iss_seq_off += 0x00010000;
554	newiss += iss_seq_off;
555	return newiss;
556}
557
558
559/* ------------------------------------------------------------------------ */
560/* Function:    ipf_nextipid                                                */
561/* Returns:     int - 0 == success, -1 == error (packet should be droppped) */
562/* Parameters:  fin(I) - pointer to packet information                      */
563/*                                                                          */
564/* Returns the next IPv4 ID to use for this packet.                         */
565/* ------------------------------------------------------------------------ */
566INLINE u_short
567ipf_nextipid(fin)
568	fr_info_t *fin;
569{
570	static u_short ipid = 0;
571	ipf_main_softc_t *softc = fin->fin_main_soft;
572	u_short id;
573
574	MUTEX_ENTER(&softc->ipf_rw);
575	if (fin->fin_pktnum != 0) {
576		/*
577		 * The -1 is for aligned test results.
578		 */
579		id = (fin->fin_pktnum - 1) & 0xffff;
580	} else {
581	}
582		id = ipid++;
583	MUTEX_EXIT(&softc->ipf_rw);
584
585	return id;
586}
587
588
589INLINE int
590ipf_checkv4sum(fin)
591	fr_info_t *fin;
592{
593
594	if (fin->fin_flx & FI_SHORT)
595		return 1;
596
597	if (ipf_checkl4sum(fin) == -1) {
598		fin->fin_flx |= FI_BAD;
599		return -1;
600	}
601	return 0;
602}
603
604
605#ifdef	USE_INET6
606INLINE int
607ipf_checkv6sum(fin)
608	fr_info_t *fin;
609{
610	if (fin->fin_flx & FI_SHORT)
611		return 1;
612
613	if (ipf_checkl4sum(fin) == -1) {
614		fin->fin_flx |= FI_BAD;
615		return -1;
616	}
617	return 0;
618}
619#endif
620
621
622#if 0
623/*
624 * See above for description, except that all addressing is in user space.
625 */
626int
627copyoutptr(softc, src, dst, size)
628	void *src, *dst;
629	size_t size;
630{
631	caddr_t ca;
632
633	bcopy(dst, (char *)&ca, sizeof(ca));
634	bcopy(src, ca, size);
635	return 0;
636}
637
638
639/*
640 * See above for description, except that all addressing is in user space.
641 */
642int
643copyinptr(src, dst, size)
644	void *src, *dst;
645	size_t size;
646{
647	caddr_t ca;
648
649	bcopy(src, (char *)&ca, sizeof(ca));
650	bcopy(ca, dst, size);
651	return 0;
652}
653#endif
654
655
656/*
657 * return the first IP Address associated with an interface
658 */
659int
660ipf_ifpaddr(softc, v, atype, ifptr, inp, inpmask)
661	ipf_main_softc_t *softc;
662	int v, atype;
663	void *ifptr;
664	i6addr_t *inp, *inpmask;
665{
666	struct ifnet *ifp = ifptr;
667	struct ifaddr *ifa;
668
669#if defined(__NetBSD__) || defined(__FreeBSD__)
670	ifa = ifp->if_addrlist.tqh_first;
671#else
672	ifa = ifp->if_addrlist;
673#endif
674	if (ifa != NULL) {
675		if (v == 4) {
676			struct sockaddr_in *sin, mask;
677
678			mask.sin_addr.s_addr = 0xffffffff;
679
680			sin = (struct sockaddr_in *)&ifa->ifa_addr;
681
682			return ipf_ifpfillv4addr(atype, sin, &mask,
683						 &inp->in4, &inpmask->in4);
684		}
685#ifdef USE_INET6
686		if (v == 6) {
687			struct sockaddr_in6 *sin6, mask;
688
689			sin6 = (struct sockaddr_in6 *)&ifa->ifa_addr;
690			((i6addr_t *)&mask.sin6_addr)->i6[0] = 0xffffffff;
691			((i6addr_t *)&mask.sin6_addr)->i6[1] = 0xffffffff;
692			((i6addr_t *)&mask.sin6_addr)->i6[2] = 0xffffffff;
693			((i6addr_t *)&mask.sin6_addr)->i6[3] = 0xffffffff;
694			return ipf_ifpfillv6addr(atype, sin6, &mask,
695						 inp, inpmask);
696		}
697#endif
698	}
699	return 0;
700}
701
702
703/*
704 * This function is not meant to be random, rather just produce a
705 * sequence of numbers that isn't linear to show "randomness".
706 */
707u_32_t
708ipf_random()
709{
710	static unsigned int last = 0xa5a5a5a5;
711	static int calls = 0;
712	int number;
713
714	calls++;
715
716	/*
717	 * These are deliberately chosen to ensure that there is some
718	 * attempt to test whether the output covers the range in test n18.
719	 */
720	switch (calls)
721	{
722	case 1 :
723		number = 0;
724		break;
725	case 2 :
726		number = 4;
727		break;
728	case 3 :
729		number = 3999;
730		break;
731	case 4 :
732		number = 4000;
733		break;
734	case 5 :
735		number = 48999;
736		break;
737	case 6 :
738		number = 49000;
739		break;
740	default :
741		number = last;
742		last *= calls;
743		last++;
744		number ^= last;
745		break;
746	}
747	return number;
748}
749
750
751int
752ipf_verifysrc(fin)
753	fr_info_t *fin;
754{
755	return 1;
756}
757
758
759int
760ipf_inject(fin, m)
761	fr_info_t *fin;
762	mb_t *m;
763{
764	FREE_MB_T(m);
765
766	return 0;
767}
768
769
770u_int
771ipf_pcksum(fin, hlen, sum)
772	fr_info_t *fin;
773	int hlen;
774	u_int sum;
775{
776	u_short *sp;
777	u_int sum2;
778	int slen;
779
780	slen = fin->fin_plen - hlen;
781	sp = (u_short *)((u_char *)fin->fin_ip + hlen);
782
783	for (; slen > 1; slen -= 2)
784		sum += *sp++;
785	if (slen)
786		sum += ntohs(*(u_char *)sp << 8);
787	while (sum > 0xffff)
788		sum = (sum & 0xffff) + (sum >> 16);
789	sum2 = (u_short)(~sum & 0xffff);
790
791	return sum2;
792}
793
794
795void *
796ipf_pullup(m, fin, plen)
797	mb_t *m;
798	fr_info_t *fin;
799	int plen;
800{
801	if (M_LEN(m) >= plen)
802		return fin->fin_ip;
803
804	/*
805	 * Fake ipf_pullup failing
806	 */
807	fin->fin_reason = FRB_PULLUP;
808	*fin->fin_mp = NULL;
809	fin->fin_m = NULL;
810	fin->fin_ip = NULL;
811	return NULL;
812}
813