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