xref: /illumos-gate/usr/src/cmd/ipf/tools/ip_fil.c (revision 2f0fcb93196badcdd803715656c809058d9f3114)
1 /*
2  * Copyright (C) 1993-2001, 2003 by Darren Reed.
3  *
4  * See the IPFILTER.LICENCE file for details on licencing.
5  *
6  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
7  * Use is subject to license terms.
8  */
9 
10 #if !defined(lint)
11 static const char sccsid[] = "@(#)ip_fil.c	2.41 6/5/96 (C) 1993-2000 Darren Reed";
12 static const char rcsid[] = "@(#)$Id: ip_fil.c,v 2.133.2.9 2005/01/08 14:22:18 darrenr Exp $";
13 #endif
14 
15 #ifndef	SOLARIS
16 #define	SOLARIS	(defined(sun) && (defined(__svr4__) || defined(__SVR4)))
17 #endif
18 
19 #include <sys/param.h>
20 #if defined(__FreeBSD__) && !defined(__FreeBSD_version)
21 # if defined(IPFILTER_LKM)
22 #  ifndef __FreeBSD_cc_version
23 #   include <osreldate.h>
24 #  else
25 #   if __FreeBSD_cc_version < 430000
26 #    include <osreldate.h>
27 #   endif
28 #  endif
29 # endif
30 #endif
31 #include <sys/errno.h>
32 #if defined(__hpux) && (HPUXREV >= 1111) && !defined(_KERNEL)
33 # include <sys/kern_svcs.h>
34 #endif
35 #include <sys/types.h>
36 #define _KERNEL
37 #define KERNEL
38 #ifdef __OpenBSD__
39 struct file;
40 #endif
41 #include <sys/uio.h>
42 #undef _KERNEL
43 #undef KERNEL
44 #include <sys/file.h>
45 #include <sys/ioctl.h>
46 #ifdef __sgi
47 # include <sys/ptimers.h>
48 #endif
49 #include <sys/time.h>
50 #if !SOLARIS
51 # if (NetBSD > 199609) || (OpenBSD > 199603) || (__FreeBSD_version >= 300000)
52 #  include <sys/dirent.h>
53 # else
54 #  include <sys/dir.h>
55 # endif
56 #else
57 # include <sys/filio.h>
58 #endif
59 #ifndef linux
60 # include <sys/protosw.h>
61 #endif
62 #include <sys/socket.h>
63 
64 #include <stdio.h>
65 #include <string.h>
66 #include <stdlib.h>
67 #include <ctype.h>
68 #include <fcntl.h>
69 #include <sys/zone.h>
70 #include <arpa/inet.h>
71 
72 #ifdef __hpux
73 # define _NET_ROUTE_INCLUDED
74 #endif
75 #include <net/if.h>
76 #ifdef sun
77 # include <net/af.h>
78 #endif
79 #if __FreeBSD_version >= 300000
80 # include <net/if_var.h>
81 #endif
82 #ifdef __sgi
83 #include <sys/debug.h>
84 # ifdef IFF_DRVRLOCK /* IRIX6 */
85 #include <sys/hashing.h>
86 # endif
87 #endif
88 #if defined(__FreeBSD__)
89 # include "radix_ipf.h"
90 #endif
91 #include <net/route.h>
92 #include <netinet/in.h>
93 #if !(defined(__sgi) && !defined(IFF_DRVRLOCK)) /* IRIX < 6 */ && \
94     !defined(__hpux) && !defined(linux)
95 # include <netinet/in_var.h>
96 #endif
97 #include <netinet/in_systm.h>
98 #include <netinet/ip.h>
99 #if !defined(linux)
100 # include <netinet/ip_var.h>
101 #endif
102 #include <netinet/tcp.h>
103 #if defined(__osf__)
104 # include <netinet/tcp_timer.h>
105 #endif
106 #if defined(__osf__) || defined(__hpux) || defined(__sgi)
107 # include "radix_ipf_local.h"
108 # define _RADIX_H_
109 #endif
110 #include <netinet/udp.h>
111 #include <netinet/tcpip.h>
112 #include <netinet/ip_icmp.h>
113 #include <unistd.h>
114 #include <syslog.h>
115 #ifdef __hpux
116 # undef _NET_ROUTE_INCLUDED
117 #endif
118 #include "netinet/ip_compat.h"
119 #include "netinet/ip_fil.h"
120 #include "netinet/ip_nat.h"
121 #include "netinet/ip_frag.h"
122 #include "netinet/ip_state.h"
123 #include "netinet/ip_proxy.h"
124 #include "netinet/ip_auth.h"
125 #ifdef	IPFILTER_SYNC
126 #include "netinet/ip_sync.h"
127 #endif
128 #ifdef	IPFILTER_SCAN
129 #include "netinet/ip_scan.h"
130 #endif
131 #include "netinet/ip_pool.h"
132 #ifdef IPFILTER_COMPILED
133 # include "netinet/ip_rules.h"
134 #endif
135 #include "netinet/ipf_stack.h"
136 #if defined(__FreeBSD_version) && (__FreeBSD_version >= 300000)
137 # include <sys/malloc.h>
138 #endif
139 #ifdef __hpux
140 struct rtentry;
141 #endif
142 #include "md5.h"
143 
144 
145 #if !defined(__osf__)
146 extern	struct	protosw	inetsw[];
147 #endif
148 
149 #include "ipt.h"
150 static	struct	ifnet **ifneta = NULL;
151 static	int	nifs = 0;
152 
153 static	int	frzerostats __P((caddr_t, ipf_stack_t *ifs));
154 static	void	fr_setifpaddr __P((struct ifnet *, char *));
155 void	init_ifp __P((void));
156 #if defined(__sgi) && (IRIX < 60500)
157 static int 	no_output __P((struct ifnet *, struct mbuf *,
158 			       struct sockaddr *));
159 static int	write_output __P((struct ifnet *, struct mbuf *,
160 				  struct sockaddr *));
161 #else
162 # if TRU64 >= 1885
163 static int 	no_output __P((struct ifnet *, struct mbuf *,
164 			       struct sockaddr *, struct rtentry *, char *));
165 static int	write_output __P((struct ifnet *, struct mbuf *,
166 				  struct sockaddr *, struct rtentry *, char *));
167 # else
168 static int 	no_output __P((struct ifnet *, struct mbuf *,
169 			       struct sockaddr *, struct rtentry *));
170 static int	write_output __P((struct ifnet *, struct mbuf *,
171 				  struct sockaddr *, struct rtentry *));
172 # endif
173 #endif
174 
175 
176 int iplattach(ifs)
177 ipf_stack_t *ifs;
178 {
179 	ifs->ifs_fr_running = 1;
180 	return 0;
181 }
182 
183 
184 int ipldetach(ifs)
185 ipf_stack_t *ifs;
186 {
187 	ifs->ifs_fr_running = -1;
188 	return 0;
189 }
190 
191 
192 static	int	frzerostats(data, ifs)
193 caddr_t	data;
194 ipf_stack_t *ifs;
195 {
196 	friostat_t fio;
197 	int error;
198 
199 	fr_getstat(&fio, ifs);
200 	error = copyoutptr(&fio, data, sizeof(fio));
201 	if (error)
202 		return EFAULT;
203 
204 	bzero((char *)ifs->ifs_frstats, sizeof(*ifs->ifs_frstats) * 2);
205 
206 	return 0;
207 }
208 
209 
210 /*
211  * Filter ioctl interface.
212  */
213 int iplioctl(dev, cmd, data, mode)
214 int dev;
215 ioctlcmd_t cmd;
216 caddr_t data;
217 int mode;
218 {
219 	int error = 0, unit = 0, tmp, uid;
220 	friostat_t fio;
221 	ipf_stack_t *ifs;
222 	extern ipf_stack_t *get_ifs();
223 
224 	unit = dev;
225 	uid = getuid();
226 
227 	ifs = get_ifs();
228 
229 	SPL_NET(s);
230 
231 	if (unit == IPL_LOGNAT) {
232 		if (ifs->ifs_fr_running > 0)
233 			error = fr_nat_ioctl(data, cmd, mode, uid, NULL, ifs);
234 		else
235 			error = EIO;
236 		SPL_X(s);
237 		return error;
238 	}
239 	if (unit == IPL_LOGSTATE) {
240 		if (ifs->ifs_fr_running > 0)
241 			error = fr_state_ioctl(data, cmd, mode, uid, NULL, ifs);
242 		else
243 			error = EIO;
244 		SPL_X(s);
245 		return error;
246 	}
247 	if (unit == IPL_LOGAUTH) {
248 		if (ifs->ifs_fr_running > 0) {
249 			if ((cmd == (ioctlcmd_t)SIOCADAFR) ||
250 			    (cmd == (ioctlcmd_t)SIOCRMAFR)) {
251 				if (!(mode & FWRITE)) {
252 					error = EPERM;
253 				} else {
254 					error = frrequest(unit, cmd, data,
255 					    ifs->ifs_fr_active, 1, ifs);
256 				}
257 			} else {
258 				error = fr_auth_ioctl(data, mode, cmd, uid, NULL, ifs);
259 			}
260 		} else
261 			error = EIO;
262 		SPL_X(s);
263 		return error;
264 	}
265 	if (unit == IPL_LOGSYNC) {
266 #ifdef	IPFILTER_SYNC
267 		if (ifs->ifs_fr_running > 0)
268 			error = fr_sync_ioctl(data, cmd, mode);
269 		else
270 #endif
271 			error = EIO;
272 		SPL_X(s);
273 		return error;
274 	}
275 	if (unit == IPL_LOGSCAN) {
276 #ifdef	IPFILTER_SCAN
277 		if (ifs->ifs_fr_running > 0)
278 			error = fr_scan_ioctl(data, cmd, mode);
279 		else
280 #endif
281 			error = EIO;
282 		SPL_X(s);
283 		return error;
284 	}
285 	if (unit == IPL_LOGLOOKUP) {
286 		if (ifs->ifs_fr_running > 0)
287 			error = ip_lookup_ioctl(data, cmd, mode, uid,
288 			    NULL, ifs);
289 		else
290 			error = EIO;
291 		SPL_X(s);
292 		return error;
293 	}
294 
295 	switch (cmd)
296 	{
297 	case FIONREAD :
298 #ifdef IPFILTER_LOG
299 		error = COPYOUT(&ifs->ifs_iplused[IPL_LOGIPF], (caddr_t)data,
300 			       sizeof(ifs->ifs_iplused[IPL_LOGIPF]));
301 #endif
302 		break;
303 	case SIOCFRENB :
304 		if (!(mode & FWRITE))
305 			error = EPERM;
306 		else {
307 			error = COPYIN(data, &tmp, sizeof(tmp));
308 			if (error)
309 				break;
310 			if (tmp)
311 				error = iplattach(ifs);
312 			else
313 				error = ipldetach(ifs);
314 		}
315 		break;
316 	case SIOCIPFSET :
317 		if (!(mode & FWRITE)) {
318 			error = EPERM;
319 			break;
320 		}
321 	case SIOCIPFGETNEXT :
322 	case SIOCIPFGET :
323 		error = fr_ipftune(cmd, (void *)data, ifs);
324 		break;
325 	case SIOCSETFF :
326 		if (!(mode & FWRITE))
327 			error = EPERM;
328 		else
329 			error = COPYIN(data, &ifs->ifs_fr_flags,
330 			    sizeof(ifs->ifs_fr_flags));
331 		break;
332 	case SIOCGETFF :
333 		error = COPYOUT(&ifs->ifs_fr_flags, data,
334 		    sizeof(ifs->ifs_fr_flags));
335 		break;
336 	case SIOCFUNCL :
337 		error = fr_resolvefunc(data);
338 		break;
339 	case SIOCINAFR :
340 	case SIOCRMAFR :
341 	case SIOCADAFR :
342 	case SIOCZRLST :
343 		if (!(mode & FWRITE))
344 			error = EPERM;
345 		else
346 			error = frrequest(unit, cmd, data,
347 			    ifs->ifs_fr_active, 1, ifs);
348 		break;
349 	case SIOCINIFR :
350 	case SIOCRMIFR :
351 	case SIOCADIFR :
352 		if (!(mode & FWRITE))
353 			error = EPERM;
354 		else
355 			error = frrequest(unit, cmd, data,
356 			    1 - ifs->ifs_fr_active, 1, ifs);
357 		break;
358 	case SIOCSWAPA :
359 		if (!(mode & FWRITE))
360 			error = EPERM;
361 		else {
362 			*(u_int *)data = ifs->ifs_fr_active;
363 			ifs->ifs_fr_active = 1 - ifs->ifs_fr_active;
364 		}
365 		break;
366 	case SIOCGETFS :
367 		fr_getstat(&fio, ifs);
368 		error = fr_outobj(data, &fio, IPFOBJ_IPFSTAT);
369 		break;
370 	case	SIOCFRZST :
371 		if (!(mode & FWRITE))
372 			error = EPERM;
373 		else
374 			error = frzerostats(data, ifs);
375 		break;
376 	case	SIOCIPFFL :
377 		if (!(mode & FWRITE))
378 			error = EPERM;
379 		else {
380 			error = COPYIN(data, &tmp, sizeof(tmp));
381 			if (!error) {
382 				tmp = frflush(unit, 4, tmp, ifs);
383 				error = COPYOUT(&tmp, data, sizeof(tmp));
384 			}
385 		}
386 		break;
387 #ifdef	USE_INET6
388 	case	SIOCIPFL6 :
389 		if (!(mode & FWRITE))
390 			error = EPERM;
391 		else {
392 			error = COPYIN(data, &tmp, sizeof(tmp));
393 			if (!error) {
394 				tmp = frflush(unit, 6, tmp, ifs);
395 				error = COPYOUT(&tmp, data, sizeof(tmp));
396 			}
397 		}
398 		break;
399 #endif
400 	case SIOCSTLCK :
401 		error = COPYIN(data, &tmp, sizeof(tmp));
402 		if (error == 0) {
403 			ifs->ifs_fr_state_lock = tmp;
404 			ifs->ifs_fr_nat_lock = tmp;
405 			ifs->ifs_fr_frag_lock = tmp;
406 			ifs->ifs_fr_auth_lock = tmp;
407 		} else
408 			error = EFAULT;
409 		break;
410 #ifdef	IPFILTER_LOG
411 	case	SIOCIPFFB :
412 		if (!(mode & FWRITE))
413 			error = EPERM;
414 		else
415 			*(int *)data = ipflog_clear(unit, ifs);
416 		break;
417 #endif /* IPFILTER_LOG */
418 	case SIOCGFRST :
419 		error = fr_outobj(data, fr_fragstats(ifs), IPFOBJ_FRAGSTAT);
420 		break;
421 	case SIOCFRSYN :
422 		if (!(mode & FWRITE))
423 			error = EPERM;
424 		else {
425 			frsync(IPFSYNC_RESYNC, IPFSYNC_RESYNC, NULL, NULL, ifs);
426 		}
427 		break;
428 	default :
429 		error = EINVAL;
430 		break;
431 	}
432 	SPL_X(s);
433 	return error;
434 }
435 
436 
437 void fr_forgetifp(ifp, ifs)
438 void *ifp;
439 ipf_stack_t *ifs;
440 {
441 	register frentry_t *f;
442 
443 	WRITE_ENTER(&ifs->ifs_ipf_mutex);
444 	for (f = ifs->ifs_ipacct[0][ifs->ifs_fr_active]; (f != NULL);
445 	    f = f->fr_next)
446 		if (f->fr_ifa == ifp)
447 			f->fr_ifa = (void *)-1;
448 	for (f = ifs->ifs_ipacct[1][ifs->ifs_fr_active]; (f != NULL);
449 	    f = f->fr_next)
450 		if (f->fr_ifa == ifp)
451 			f->fr_ifa = (void *)-1;
452 	for (f = ifs->ifs_ipfilter[0][ifs->ifs_fr_active]; (f != NULL);
453 	    f = f->fr_next)
454 		if (f->fr_ifa == ifp)
455 			f->fr_ifa = (void *)-1;
456 	for (f = ifs->ifs_ipfilter[1][ifs->ifs_fr_active]; (f != NULL);
457 	    f = f->fr_next)
458 		if (f->fr_ifa == ifp)
459 			f->fr_ifa = (void *)-1;
460 #ifdef	USE_INET6
461 	for (f = ifs->ifs_ipacct6[0][ifs->ifs_fr_active]; (f != NULL);
462 	    f = f->fr_next)
463 		if (f->fr_ifa == ifp)
464 			f->fr_ifa = (void *)-1;
465 	for (f = ifs->ifs_ipacct6[1][ifs->ifs_fr_active]; (f != NULL);
466 	    f = f->fr_next)
467 		if (f->fr_ifa == ifp)
468 			f->fr_ifa = (void *)-1;
469 	for (f = ifs->ifs_ipfilter6[0][ifs->ifs_fr_active]; (f != NULL);
470 	    f = f->fr_next)
471 		if (f->fr_ifa == ifp)
472 			f->fr_ifa = (void *)-1;
473 	for (f = ifs->ifs_ipfilter6[1][ifs->ifs_fr_active]; (f != NULL);
474 	    f = f->fr_next)
475 		if (f->fr_ifa == ifp)
476 			f->fr_ifa = (void *)-1;
477 #endif
478 	RWLOCK_EXIT(&ifs->ifs_ipf_mutex);
479 	fr_natifpsync(IPFSYNC_OLDIFP, 4, ifp, NULL, ifs);
480 	fr_natifpsync(IPFSYNC_OLDIFP, 6, ifp, NULL, ifs);
481 }
482 
483 
484 void fr_resolvedest(fdp, v, ifs)
485 frdest_t *fdp;
486 int v;
487 ipf_stack_t *ifs;
488 {
489 	fdp->fd_ifp = NULL;
490 
491 	if (*fdp->fd_ifname) {
492 		fdp->fd_ifp = GETIFP(fdp->fd_ifname, v, ifs);
493 		if (!fdp->fd_ifp)
494 			fdp->fd_ifp = (struct ifnet *)-1;
495 	}
496 }
497 
498 
499 #if defined(__sgi) && (IRIX < 60500)
500 static int no_output(ifp, m, s)
501 #else
502 # if TRU64 >= 1885
503 static int no_output (ifp, m, s, rt, cp)
504 char *cp;
505 # else
506 static int no_output(ifp, m, s, rt)
507 # endif
508 struct rtentry *rt;
509 #endif
510 struct ifnet *ifp;
511 struct mbuf *m;
512 struct sockaddr *s;
513 {
514 	return 0;
515 }
516 
517 
518 #if defined(__sgi) && (IRIX < 60500)
519 static int write_output(ifp, m, s)
520 #else
521 # if TRU64 >= 1885
522 static int write_output (ifp, m, s, rt, cp)
523 char *cp;
524 # else
525 static int write_output(ifp, m, s, rt)
526 # endif
527 struct rtentry *rt;
528 #endif
529 struct ifnet *ifp;
530 struct mbuf *m;
531 struct sockaddr *s;
532 {
533 	char fname[32];
534 	mb_t *mb;
535 	ip_t *ip;
536 	int fd;
537 
538 	mb = (mb_t *)m;
539 	ip = MTOD(mb, ip_t *);
540 
541 #if (defined(NetBSD) && (NetBSD <= 1991011) && (NetBSD >= 199606)) || \
542     (defined(OpenBSD) && (OpenBSD >= 199603)) || defined(linux) || \
543     (defined(__FreeBSD__) && (__FreeBSD_version >= 501113))
544 	sprintf(fname, "/tmp/%s", ifp->if_xname);
545 #else
546 	sprintf(fname, "/tmp/%s%d", ifp->if_name, ifp->if_unit);
547 #endif
548 	fd = open(fname, O_WRONLY|O_APPEND);
549 	if (fd == -1) {
550 		perror("open");
551 		return -1;
552 	}
553 	write(fd, (char *)ip, ntohs(ip->ip_len));
554 	close(fd);
555 	return 0;
556 }
557 
558 
559 static void fr_setifpaddr(ifp, addr)
560 struct ifnet *ifp;
561 char *addr;
562 {
563 #ifdef __sgi
564 	struct in_ifaddr *ifa;
565 #else
566 	struct ifaddr *ifa;
567 #endif
568 
569 #if defined(__NetBSD__) || defined(__OpenBSD__) || defined(__FreeBSD__)
570 	if (ifp->if_addrlist.tqh_first != NULL)
571 #else
572 # ifdef __sgi
573 	if (ifp->in_ifaddr != NULL)
574 # else
575 	if (ifp->if_addrlist != NULL)
576 # endif
577 #endif
578 		return;
579 
580 	ifa = (struct ifaddr *)malloc(sizeof(*ifa));
581 #if defined(__NetBSD__) || defined(__OpenBSD__) || defined(__FreeBSD__)
582 	ifp->if_addrlist.tqh_first = ifa;
583 #else
584 # ifdef __sgi
585 	ifp->in_ifaddr = ifa;
586 # else
587 	ifp->if_addrlist = ifa;
588 # endif
589 #endif
590 
591 	if (ifa != NULL) {
592 		struct sockaddr_in *sin;
593 
594 #ifdef __sgi
595 		sin = (struct sockaddr_in *)&ifa->ia_addr;
596 #else
597 		sin = (struct sockaddr_in *)&ifa->ifa_addr;
598 #endif
599 		sin->sin_addr.s_addr = inet_addr(addr);
600 		if (sin->sin_addr.s_addr == 0)
601 			abort();
602 	}
603 }
604 
605 /*ARGSUSED*/
606 struct ifnet *get_unit(name, v, ifs)
607 char *name;
608 int v;
609 ipf_stack_t *ifs;
610 {
611 	struct ifnet *ifp, **ifpp, **old_ifneta;
612 	char *addr;
613 #if (defined(NetBSD) && (NetBSD <= 1991011) && (NetBSD >= 199606)) || \
614     (defined(OpenBSD) && (OpenBSD >= 199603)) || defined(linux) || \
615     (defined(__FreeBSD__) && (__FreeBSD_version >= 501113))
616 
617 	if (name == NULL)
618 		name = "anon0";
619 
620 	addr = strchr(name, '=');
621 	if (addr != NULL)
622 		*addr++ = '\0';
623 
624 	for (ifpp = ifneta; ifpp && (ifp = *ifpp); ifpp++) {
625 		if (!strcmp(name, ifp->if_xname)) {
626 			if (addr != NULL)
627 				fr_setifpaddr(ifp, addr);
628 			return ifp;
629 		}
630 	}
631 #else
632 	char *s, ifname[LIFNAMSIZ+1];
633 
634 	if (name == NULL)
635 		name = "anon0";
636 
637 	addr = strchr(name, '=');
638 	if (addr != NULL)
639 		*addr++ = '\0';
640 
641 	for (ifpp = ifneta; ifpp && (ifp = *ifpp); ifpp++) {
642 		COPYIFNAME(ifp, ifname, 0);
643 		if (!strcmp(name, ifname)) {
644 			if (addr != NULL)
645 				fr_setifpaddr(ifp, addr);
646 			return ifp;
647 		}
648 	}
649 #endif
650 
651 	if (!ifneta) {
652 		ifneta = (struct ifnet **)malloc(sizeof(ifp) * 2);
653 		if (!ifneta)
654 			return NULL;
655 		ifneta[1] = NULL;
656 		ifneta[0] = (struct ifnet *)calloc(1, sizeof(*ifp));
657 		if (!ifneta[0]) {
658 			free(ifneta);
659 			return NULL;
660 		}
661 		nifs = 1;
662 	} else {
663 		old_ifneta = ifneta;
664 		nifs++;
665 		ifneta = (struct ifnet **)realloc(ifneta,
666 						  (nifs + 1) * sizeof(ifp));
667 		if (!ifneta) {
668 			free(old_ifneta);
669 			nifs = 0;
670 			return NULL;
671 		}
672 		ifneta[nifs] = NULL;
673 		ifneta[nifs - 1] = (struct ifnet *)malloc(sizeof(*ifp));
674 		if (!ifneta[nifs - 1]) {
675 			nifs--;
676 			return NULL;
677 		}
678 	}
679 	ifp = ifneta[nifs - 1];
680 
681 #if (defined(NetBSD) && (NetBSD <= 1991011) && (NetBSD >= 199606)) || \
682     (defined(OpenBSD) && (OpenBSD >= 199603)) || defined(linux) || \
683     (defined(__FreeBSD__) && (__FreeBSD_version >= 501113))
684 	(void) strncpy(ifp->if_xname, name, sizeof(ifp->if_xname));
685 #else
686 	for (s = name; *s && !ISDIGIT(*s); s++)
687 		;
688 	if (*s && ISDIGIT(*s)) {
689 		ifp->if_unit = atoi(s);
690 		ifp->if_name = (char *)malloc(s - name + 1);
691 		if (ifp->if_name == NULL) {
692 			/*
693 			 * XXX do it more elegantly: free up mem,
694 			 * return NULL
695 			 */
696 			perror("malloc");
697 			exit(1);
698 		}
699 		(void) strncpy(ifp->if_name, name, s - name);
700 		ifp->if_name[s - name] = '\0';
701 	} else {
702 		ifp->if_name = strdup(name);
703 		ifp->if_unit = -1;
704 	}
705 #endif
706 	ifp->if_output = no_output;
707 
708 	if (addr != NULL) {
709 		fr_setifpaddr(ifp, addr);
710 	}
711 
712 	return ifp;
713 }
714 
715 
716 char *get_ifname(ifp)
717 struct ifnet *ifp;
718 {
719 	static char ifname[LIFNAMSIZ];
720 
721 #if defined(__OpenBSD__) || defined(__NetBSD__) || defined(linux) || \
722     (defined(__FreeBSD__) && (__FreeBSD_version >= 501113))
723 	sprintf(ifname, "%s", ifp->if_xname);
724 #else
725 	sprintf(ifname, "%s%d", ifp->if_name, ifp->if_unit);
726 #endif
727 	return ifname;
728 }
729 
730 
731 
732 void init_ifp()
733 {
734 	struct ifnet *ifp, **ifpp;
735 	char fname[32];
736 	int fd;
737 
738 #if (defined(NetBSD) && (NetBSD <= 1991011) && (NetBSD >= 199606)) || \
739     (defined(OpenBSD) && (OpenBSD >= 199603)) || defined(linux) || \
740     (defined(__FreeBSD__) && (__FreeBSD_version >= 501113))
741 	for (ifpp = ifneta; ifpp && (ifp = *ifpp); ifpp++) {
742 		ifp->if_output = write_output;
743 		sprintf(fname, "/tmp/%s", ifp->if_xname);
744 		fd = open(fname, O_WRONLY|O_CREAT|O_EXCL|O_TRUNC, 0600);
745 		if (fd == -1)
746 			perror("open");
747 		else
748 			close(fd);
749 	}
750 #else
751 
752 	for (ifpp = ifneta; ifpp && (ifp = *ifpp); ifpp++) {
753 		ifp->if_output = write_output;
754 		sprintf(fname, "/tmp/%s%d", ifp->if_name, ifp->if_unit);
755 		fd = open(fname, O_WRONLY|O_CREAT|O_EXCL|O_TRUNC, 0600);
756 		if (fd == -1)
757 			perror("open");
758 		else
759 			close(fd);
760 	}
761 #endif
762 }
763 
764 
765 int fr_fastroute(m, mpp, fin, fdp)
766 mb_t *m, **mpp;
767 fr_info_t *fin;
768 frdest_t *fdp;
769 {
770 	struct ifnet *ifp = fdp->fd_ifp;
771 	ip_t *ip = fin->fin_ip;
772 
773 	if (!ifp)
774 		return 0;	/* no routing table out here */
775 
776 	ip->ip_len = htons((u_short)ip->ip_len);
777 	ip->ip_off = htons((u_short)(ip->ip_off | IP_MF));
778 	ip->ip_sum = 0;
779 #if defined(__sgi) && (IRIX < 60500)
780 	(*ifp->if_output)(ifp, (void *)ip, NULL);
781 # if TRU64 >= 1885
782 	(*ifp->if_output)(ifp, (void *)m, NULL, 0, 0);
783 # else
784 	(*ifp->if_output)(ifp, (void *)m, NULL, 0);
785 # endif
786 #endif
787 	return 0;
788 }
789 
790 
791 int fr_send_reset(fin)
792 fr_info_t *fin;
793 {
794 	verbose("- TCP RST sent\n");
795 	return 0;
796 }
797 
798 
799 int fr_send_icmp_err(type, fin, dst)
800 int type;
801 fr_info_t *fin;
802 int dst;
803 {
804 	verbose("- ICMP unreachable sent\n");
805 	return 0;
806 }
807 
808 
809 void frsync(command, version, nic, data, ifs)
810 int command, version;
811 void *nic;
812 char *data;
813 ipf_stack_t *ifs;
814 {
815 	return;
816 }
817 
818 
819 void m_freem(m)
820 mb_t *m;
821 {
822 	return;
823 }
824 
825 
826 void m_copydata(m, off, len, cp)
827 mb_t *m;
828 int off, len;
829 caddr_t cp;
830 {
831 	bcopy((char *)m + off, cp, len);
832 }
833 
834 
835 int ipfuiomove(buf, len, rwflag, uio)
836 caddr_t buf;
837 int len, rwflag;
838 struct uio *uio;
839 {
840 	int left, ioc, num, offset;
841 	struct iovec *io;
842 	char *start;
843 
844 	if (rwflag == UIO_READ) {
845 		left = len;
846 		ioc = 0;
847 
848 		offset = uio->uio_offset;
849 
850 		while ((left > 0) && (ioc < uio->uio_iovcnt)) {
851 			io = uio->uio_iov + ioc;
852 			num = io->iov_len;
853 			if (num > left)
854 				num = left;
855 			start = (char *)io->iov_base + offset;
856 			if (start > (char *)io->iov_base + io->iov_len) {
857 				offset -= io->iov_len;
858 				ioc++;
859 				continue;
860 			}
861 			bcopy(buf, start, num);
862 			uio->uio_resid -= num;
863 			uio->uio_offset += num;
864 			left -= num;
865 			if (left > 0)
866 				ioc++;
867 		}
868 		if (left > 0)
869 			return EFAULT;
870 	}
871 	return 0;
872 }
873 
874 
875 u_32_t fr_newisn(fin)
876 fr_info_t *fin;
877 {
878 	static int iss_seq_off = 0;
879 	u_char hash[16];
880 	u_32_t newiss;
881 	MD5_CTX ctx;
882 
883 	/*
884 	 * Compute the base value of the ISS.  It is a hash
885 	 * of (saddr, sport, daddr, dport, secret).
886 	 */
887 	MD5Init(&ctx);
888 
889 	MD5Update(&ctx, (u_char *) &fin->fin_fi.fi_src,
890 		  sizeof(fin->fin_fi.fi_src));
891 	MD5Update(&ctx, (u_char *) &fin->fin_fi.fi_dst,
892 		  sizeof(fin->fin_fi.fi_dst));
893 	MD5Update(&ctx, (u_char *) &fin->fin_dat, sizeof(fin->fin_dat));
894 
895 	/* MD5Update(&ctx, ipf_iss_secret, sizeof(ipf_iss_secret)); */
896 
897 	MD5Final(hash, &ctx);
898 
899 	memcpy(&newiss, hash, sizeof(newiss));
900 
901 	/*
902 	 * Now increment our "timer", and add it in to
903 	 * the computed value.
904 	 *
905 	 * XXX Use `addin'?
906 	 * XXX TCP_ISSINCR too large to use?
907 	 */
908 	iss_seq_off += 0x00010000;
909 	newiss += iss_seq_off;
910 	return newiss;
911 }
912 
913 
914 /* ------------------------------------------------------------------------ */
915 /* Function:    fr_nextipid                                                 */
916 /* Returns:     int - 0 == success, -1 == error (packet should be droppped) */
917 /* Parameters:  fin(I) - pointer to packet information                      */
918 /*                                                                          */
919 /* Returns the next IPv4 ID to use for this packet.                         */
920 /* ------------------------------------------------------------------------ */
921 INLINE u_short fr_nextipid(fin)
922 fr_info_t *fin;
923 {
924 	static u_short ipid = 0;
925 	u_short id;
926 	ipf_stack_t *ifs = fin->fin_ifs;
927 
928 	MUTEX_ENTER(&ifs->ifs_ipf_rw);
929 	id = ipid++;
930 	MUTEX_EXIT(&ifs->ifs_ipf_rw);
931 
932 	return id;
933 }
934 
935 
936 INLINE void fr_checkv4sum(fin)
937 fr_info_t *fin;
938 {
939 	if (fr_checkl4sum(fin) == -1)
940 		fin->fin_flx |= FI_BAD;
941 }
942 
943 
944 #ifdef	USE_INET6
945 INLINE void fr_checkv6sum(fin)
946 fr_info_t *fin;
947 {
948 	if (fr_checkl4sum(fin) == -1)
949 		fin->fin_flx |= FI_BAD;
950 }
951 #endif
952 
953 
954 /*
955  * See above for description, except that all addressing is in user space.
956  */
957 int copyoutptr(src, dst, size)
958 void *src, *dst;
959 size_t size;
960 {
961 	caddr_t ca;
962 
963 	bcopy(dst, (char *)&ca, sizeof(ca));
964 	bcopy(src, ca, size);
965 	return 0;
966 }
967 
968 
969 /*
970  * See above for description, except that all addressing is in user space.
971  */
972 int copyinptr(src, dst, size)
973 void *src, *dst;
974 size_t size;
975 {
976 	caddr_t ca;
977 
978 	bcopy(src, (char *)&ca, sizeof(ca));
979 	bcopy(ca, dst, size);
980 	return 0;
981 }
982 
983 
984 /*
985  * return the first IP Address associated with an interface
986  */
987 int fr_ifpaddr(v, atype, ifptr, inp, inpmask, ifs)
988 int v, atype;
989 void *ifptr;
990 struct in_addr *inp, *inpmask;
991 ipf_stack_t *ifs;
992 {
993 	struct ifnet *ifp = ifptr;
994 #ifdef __sgi
995 	struct in_ifaddr *ifa;
996 #else
997 	struct ifaddr *ifa;
998 #endif
999 
1000 #if defined(__NetBSD__) || defined(__OpenBSD__) || defined(__FreeBSD__)
1001 	ifa = ifp->if_addrlist.tqh_first;
1002 #else
1003 # ifdef __sgi
1004 	ifa = (struct in_ifaddr *)ifp->in_ifaddr;
1005 # else
1006 	ifa = ifp->if_addrlist;
1007 # endif
1008 #endif
1009 	if (ifa != NULL) {
1010 		struct sockaddr_in *sin, mask;
1011 
1012 		mask.sin_addr.s_addr = 0xffffffff;
1013 
1014 #ifdef __sgi
1015 		sin = (struct sockaddr_in *)&ifa->ia_addr;
1016 #else
1017 		sin = (struct sockaddr_in *)&ifa->ifa_addr;
1018 #endif
1019 
1020 		return fr_ifpfillv4addr(atype, sin, &mask, inp, inpmask);
1021 	}
1022 	return 0;
1023 }
1024 
1025 
1026 /*
1027  * This function is not meant to be random, rather just produce a
1028  * sequence of numbers that isn't linear to show "randomness".
1029  */
1030 u_32_t ipf_random()
1031 {
1032 	static u_int last = 0xa5a5a5a5;
1033 	static int calls = 0;
1034 	int number;
1035 
1036 	calls++;
1037 
1038 	/*
1039 	 * These are deliberately chosen to ensure that there is some
1040 	 * attempt to test whether the output covers the range in test n18.
1041 	 */
1042 	switch (calls)
1043 	{
1044 	case 1 :
1045 		number = 0;
1046 		break;
1047 	case 2 :
1048 		number = 4;
1049 		break;
1050 	case 3 :
1051 		number = 3999;
1052 		break;
1053 	case 4 :
1054 		number = 4000;
1055 		break;
1056 	case 5 :
1057 		number = 48999;
1058 		break;
1059 	case 6 :
1060 		number = 49000;
1061 		break;
1062 	default :
1063 		number = last;
1064 		last *= calls;
1065 		last++;
1066 		number ^= last;
1067 		break;
1068 	}
1069 	return number;
1070 }
1071