xref: /illumos-gate/usr/src/cmd/ipf/tools/ip_fil.c (revision 4fa33403ece8f42c56cba2b672d10f6ab4dc32cd)
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 #ifdef SOLARIS
11 #undef	SOLARIS
12 #endif
13 #if (defined(sun) && (defined(__svr4__) || defined(__SVR4)))
14 #define	SOLARIS	(1)
15 #else
16 #define	SOLARIS	(0)
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 !defined(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, cmd, mode, uid,
259 						      NULL, ifs);
260 			}
261 		} else
262 			error = EIO;
263 		SPL_X(s);
264 		return error;
265 	}
266 	if (unit == IPL_LOGSYNC) {
267 #ifdef	IPFILTER_SYNC
268 		if (ifs->ifs_fr_running > 0)
269 			error = fr_sync_ioctl(data, cmd, mode);
270 		else
271 #endif
272 			error = EIO;
273 		SPL_X(s);
274 		return error;
275 	}
276 	if (unit == IPL_LOGSCAN) {
277 #ifdef	IPFILTER_SCAN
278 		if (ifs->ifs_fr_running > 0)
279 			error = fr_scan_ioctl(data, cmd, mode);
280 		else
281 #endif
282 			error = EIO;
283 		SPL_X(s);
284 		return error;
285 	}
286 	if (unit == IPL_LOGLOOKUP) {
287 		if (ifs->ifs_fr_running > 0)
288 			error = ip_lookup_ioctl(data, cmd, mode, uid,
289 			    NULL, ifs);
290 		else
291 			error = EIO;
292 		SPL_X(s);
293 		return error;
294 	}
295 
296 	switch (cmd)
297 	{
298 	case FIONREAD :
299 #ifdef IPFILTER_LOG
300 		error = COPYOUT(&ifs->ifs_iplused[IPL_LOGIPF], (caddr_t)data,
301 			       sizeof(ifs->ifs_iplused[IPL_LOGIPF]));
302 #endif
303 		break;
304 	case SIOCFRENB :
305 		if (!(mode & FWRITE))
306 			error = EPERM;
307 		else {
308 			error = COPYIN(data, &tmp, sizeof(tmp));
309 			if (error)
310 				break;
311 			if (tmp)
312 				error = iplattach(ifs);
313 			else
314 				error = ipldetach(ifs);
315 		}
316 		break;
317 	case SIOCIPFSET :
318 		if (!(mode & FWRITE)) {
319 			error = EPERM;
320 			break;
321 		}
322 		/* FALLTHROUGH */
323 	case SIOCIPFGETNEXT :
324 	case SIOCIPFGET :
325 		error = fr_ipftune(cmd, (void *)data, ifs);
326 		break;
327 	case SIOCSETFF :
328 		if (!(mode & FWRITE))
329 			error = EPERM;
330 		else
331 			error = COPYIN(data, &ifs->ifs_fr_flags,
332 			    sizeof(ifs->ifs_fr_flags));
333 		break;
334 	case SIOCGETFF :
335 		error = COPYOUT(&ifs->ifs_fr_flags, data,
336 		    sizeof(ifs->ifs_fr_flags));
337 		break;
338 	case SIOCFUNCL :
339 		error = fr_resolvefunc(data);
340 		break;
341 	case SIOCINAFR :
342 	case SIOCRMAFR :
343 	case SIOCADAFR :
344 	case SIOCZRLST :
345 		if (!(mode & FWRITE))
346 			error = EPERM;
347 		else
348 			error = frrequest(unit, cmd, data,
349 			    ifs->ifs_fr_active, 1, ifs);
350 		break;
351 	case SIOCINIFR :
352 	case SIOCRMIFR :
353 	case SIOCADIFR :
354 		if (!(mode & FWRITE))
355 			error = EPERM;
356 		else
357 			error = frrequest(unit, cmd, data,
358 			    1 - ifs->ifs_fr_active, 1, ifs);
359 		break;
360 	case SIOCSWAPA :
361 		if (!(mode & FWRITE))
362 			error = EPERM;
363 		else {
364 			*(u_int *)data = ifs->ifs_fr_active;
365 			ifs->ifs_fr_active = 1 - ifs->ifs_fr_active;
366 		}
367 		break;
368 	case SIOCGETFS :
369 		fr_getstat(&fio, ifs);
370 		error = fr_outobj(data, &fio, IPFOBJ_IPFSTAT);
371 		break;
372 	case	SIOCFRZST :
373 		if (!(mode & FWRITE))
374 			error = EPERM;
375 		else
376 			error = frzerostats(data, ifs);
377 		break;
378 	case	SIOCIPFFL :
379 		if (!(mode & FWRITE))
380 			error = EPERM;
381 		else {
382 			error = COPYIN(data, &tmp, sizeof(tmp));
383 			if (!error) {
384 				tmp = frflush(unit, 4, tmp, ifs);
385 				error = COPYOUT(&tmp, data, sizeof(tmp));
386 			}
387 		}
388 		break;
389 #ifdef	USE_INET6
390 	case	SIOCIPFL6 :
391 		if (!(mode & FWRITE))
392 			error = EPERM;
393 		else {
394 			error = COPYIN(data, &tmp, sizeof(tmp));
395 			if (!error) {
396 				tmp = frflush(unit, 6, tmp, ifs);
397 				error = COPYOUT(&tmp, data, sizeof(tmp));
398 			}
399 		}
400 		break;
401 #endif
402 	case SIOCSTLCK :
403 		error = COPYIN(data, &tmp, sizeof(tmp));
404 		if (error == 0) {
405 			ifs->ifs_fr_state_lock = tmp;
406 			ifs->ifs_fr_nat_lock = tmp;
407 			ifs->ifs_fr_frag_lock = tmp;
408 			ifs->ifs_fr_auth_lock = tmp;
409 		} else
410 			error = EFAULT;
411 		break;
412 #ifdef	IPFILTER_LOG
413 	case	SIOCIPFFB :
414 		if (!(mode & FWRITE))
415 			error = EPERM;
416 		else
417 			*(int *)data = ipflog_clear(unit, ifs);
418 		break;
419 #endif /* IPFILTER_LOG */
420 	case SIOCGFRST :
421 		error = fr_outobj(data, fr_fragstats(ifs), IPFOBJ_FRAGSTAT);
422 		break;
423 	case SIOCFRSYN :
424 		if (!(mode & FWRITE))
425 			error = EPERM;
426 		else {
427 			frsync(IPFSYNC_RESYNC, IPFSYNC_RESYNC, NULL, NULL, ifs);
428 		}
429 		break;
430 	default :
431 		error = EINVAL;
432 		break;
433 	}
434 	SPL_X(s);
435 	return error;
436 }
437 
438 
439 void fr_forgetifp(ifp, ifs)
440 void *ifp;
441 ipf_stack_t *ifs;
442 {
443 	register frentry_t *f;
444 
445 	WRITE_ENTER(&ifs->ifs_ipf_mutex);
446 	for (f = ifs->ifs_ipacct[0][ifs->ifs_fr_active]; (f != NULL);
447 	    f = f->fr_next)
448 		if (f->fr_ifa == ifp)
449 			f->fr_ifa = (void *)-1;
450 	for (f = ifs->ifs_ipacct[1][ifs->ifs_fr_active]; (f != NULL);
451 	    f = f->fr_next)
452 		if (f->fr_ifa == ifp)
453 			f->fr_ifa = (void *)-1;
454 	for (f = ifs->ifs_ipfilter[0][ifs->ifs_fr_active]; (f != NULL);
455 	    f = f->fr_next)
456 		if (f->fr_ifa == ifp)
457 			f->fr_ifa = (void *)-1;
458 	for (f = ifs->ifs_ipfilter[1][ifs->ifs_fr_active]; (f != NULL);
459 	    f = f->fr_next)
460 		if (f->fr_ifa == ifp)
461 			f->fr_ifa = (void *)-1;
462 #ifdef	USE_INET6
463 	for (f = ifs->ifs_ipacct6[0][ifs->ifs_fr_active]; (f != NULL);
464 	    f = f->fr_next)
465 		if (f->fr_ifa == ifp)
466 			f->fr_ifa = (void *)-1;
467 	for (f = ifs->ifs_ipacct6[1][ifs->ifs_fr_active]; (f != NULL);
468 	    f = f->fr_next)
469 		if (f->fr_ifa == ifp)
470 			f->fr_ifa = (void *)-1;
471 	for (f = ifs->ifs_ipfilter6[0][ifs->ifs_fr_active]; (f != NULL);
472 	    f = f->fr_next)
473 		if (f->fr_ifa == ifp)
474 			f->fr_ifa = (void *)-1;
475 	for (f = ifs->ifs_ipfilter6[1][ifs->ifs_fr_active]; (f != NULL);
476 	    f = f->fr_next)
477 		if (f->fr_ifa == ifp)
478 			f->fr_ifa = (void *)-1;
479 #endif
480 	RWLOCK_EXIT(&ifs->ifs_ipf_mutex);
481 	fr_natifpsync(IPFSYNC_OLDIFP, 4, ifp, NULL, ifs);
482 	fr_natifpsync(IPFSYNC_OLDIFP, 6, ifp, NULL, ifs);
483 }
484 
485 
486 void fr_resolvedest(fdp, v, ifs)
487 frdest_t *fdp;
488 int v;
489 ipf_stack_t *ifs;
490 {
491 	fdp->fd_ifp = NULL;
492 
493 	if (*fdp->fd_ifname) {
494 		fdp->fd_ifp = GETIFP(fdp->fd_ifname, v, ifs);
495 		if (!fdp->fd_ifp)
496 			fdp->fd_ifp = (struct ifnet *)-1;
497 	}
498 }
499 
500 
501 #if defined(__sgi) && (IRIX < 60500)
502 static int no_output(ifp, m, s)
503 #else
504 # if TRU64 >= 1885
505 static int no_output (ifp, m, s, rt, cp)
506 char *cp;
507 # else
508 static int no_output(ifp, m, s, rt)
509 # endif
510 struct rtentry *rt;
511 #endif
512 struct ifnet *ifp;
513 struct mbuf *m;
514 struct sockaddr *s;
515 {
516 	return 0;
517 }
518 
519 
520 #if defined(__sgi) && (IRIX < 60500)
521 static int write_output(ifp, m, s)
522 #else
523 # if TRU64 >= 1885
524 static int write_output (ifp, m, s, rt, cp)
525 char *cp;
526 # else
527 static int write_output(ifp, m, s, rt)
528 # endif
529 struct rtentry *rt;
530 #endif
531 struct ifnet *ifp;
532 struct mbuf *m;
533 struct sockaddr *s;
534 {
535 	char fname[32];
536 	mb_t *mb;
537 	ip_t *ip;
538 	int fd;
539 
540 	mb = (mb_t *)m;
541 	ip = MTOD(mb, ip_t *);
542 
543 #if (defined(NetBSD) && (NetBSD <= 1991011) && (NetBSD >= 199606)) || \
544     (defined(OpenBSD) && (OpenBSD >= 199603)) || defined(linux) || \
545     (defined(__FreeBSD__) && (__FreeBSD_version >= 501113))
546 	sprintf(fname, "/tmp/%s", ifp->if_xname);
547 #else
548 	sprintf(fname, "/tmp/%s%d", ifp->if_name, ifp->if_unit);
549 #endif
550 	fd = open(fname, O_WRONLY|O_APPEND);
551 	if (fd == -1) {
552 		perror("open");
553 		return -1;
554 	}
555 	write(fd, (char *)ip, ntohs(ip->ip_len));
556 	close(fd);
557 	return 0;
558 }
559 
560 
561 static void fr_setifpaddr(ifp, addr)
562 struct ifnet *ifp;
563 char *addr;
564 {
565 #ifdef __sgi
566 	struct in_ifaddr *ifa;
567 #else
568 	struct ifaddr *ifa;
569 #endif
570 
571 #if defined(__NetBSD__) || defined(__OpenBSD__) || defined(__FreeBSD__)
572 	if (ifp->if_addrlist.tqh_first != NULL)
573 #else
574 # ifdef __sgi
575 	if (ifp->in_ifaddr != NULL)
576 # else
577 	if (ifp->if_addrlist != NULL)
578 # endif
579 #endif
580 		return;
581 
582 	ifa = (struct ifaddr *)malloc(sizeof(*ifa));
583 #if defined(__NetBSD__) || defined(__OpenBSD__) || defined(__FreeBSD__)
584 	ifp->if_addrlist.tqh_first = ifa;
585 #else
586 # ifdef __sgi
587 	ifp->in_ifaddr = ifa;
588 # else
589 	ifp->if_addrlist = ifa;
590 # endif
591 #endif
592 
593 	if (ifa != NULL) {
594 		struct sockaddr_in *sin;
595 
596 #ifdef __sgi
597 		sin = (struct sockaddr_in *)&ifa->ia_addr;
598 #else
599 		sin = (struct sockaddr_in *)&ifa->ifa_addr;
600 #endif
601 		sin->sin_addr.s_addr = inet_addr(addr);
602 		if (sin->sin_addr.s_addr == 0)
603 			abort();
604 	}
605 }
606 
607 /*ARGSUSED*/
608 struct ifnet *get_unit(name, v, ifs)
609 char *name;
610 int v;
611 ipf_stack_t *ifs;
612 {
613 	struct ifnet *ifp, **ifpp, **old_ifneta;
614 	char *addr;
615 #if (defined(NetBSD) && (NetBSD <= 1991011) && (NetBSD >= 199606)) || \
616     (defined(OpenBSD) && (OpenBSD >= 199603)) || defined(linux) || \
617     (defined(__FreeBSD__) && (__FreeBSD_version >= 501113))
618 
619 	if (name == NULL)
620 		name = "anon0";
621 
622 	addr = strchr(name, '=');
623 	if (addr != NULL)
624 		*addr++ = '\0';
625 
626 	for (ifpp = ifneta; ifpp && (ifp = *ifpp); ifpp++) {
627 		if (!strcmp(name, ifp->if_xname)) {
628 			if (addr != NULL)
629 				fr_setifpaddr(ifp, addr);
630 			return ifp;
631 		}
632 	}
633 #else
634 	char *s, ifname[LIFNAMSIZ+1];
635 
636 	if (name == NULL)
637 		name = "anon0";
638 
639 	addr = strchr(name, '=');
640 	if (addr != NULL)
641 		*addr++ = '\0';
642 
643 	for (ifpp = ifneta; ifpp && (ifp = *ifpp); ifpp++) {
644 		COPYIFNAME(ifp, ifname, 0);
645 		if (!strcmp(name, ifname)) {
646 			if (addr != NULL)
647 				fr_setifpaddr(ifp, addr);
648 			return ifp;
649 		}
650 	}
651 #endif
652 
653 	if (!ifneta) {
654 		ifneta = (struct ifnet **)malloc(sizeof(ifp) * 2);
655 		if (!ifneta)
656 			return NULL;
657 		ifneta[1] = NULL;
658 		ifneta[0] = (struct ifnet *)calloc(1, sizeof(*ifp));
659 		if (!ifneta[0]) {
660 			free(ifneta);
661 			return NULL;
662 		}
663 		nifs = 1;
664 	} else {
665 		old_ifneta = ifneta;
666 		nifs++;
667 		ifneta = (struct ifnet **)realloc(ifneta,
668 						  (nifs + 1) * sizeof(ifp));
669 		if (!ifneta) {
670 			free(old_ifneta);
671 			nifs = 0;
672 			return NULL;
673 		}
674 		ifneta[nifs] = NULL;
675 		ifneta[nifs - 1] = (struct ifnet *)malloc(sizeof(*ifp));
676 		if (!ifneta[nifs - 1]) {
677 			nifs--;
678 			return NULL;
679 		}
680 	}
681 	ifp = ifneta[nifs - 1];
682 
683 #if (defined(NetBSD) && (NetBSD <= 1991011) && (NetBSD >= 199606)) || \
684     (defined(OpenBSD) && (OpenBSD >= 199603)) || defined(linux) || \
685     (defined(__FreeBSD__) && (__FreeBSD_version >= 501113))
686 	(void) strncpy(ifp->if_xname, name, sizeof(ifp->if_xname));
687 #else
688 	for (s = name; *s && !ISDIGIT(*s); s++)
689 		;
690 	if (*s && ISDIGIT(*s)) {
691 		ifp->if_unit = atoi(s);
692 		ifp->if_name = (char *)malloc(s - name + 1);
693 		if (ifp->if_name == NULL) {
694 			/*
695 			 * XXX do it more elegantly: free up mem,
696 			 * return NULL
697 			 */
698 			perror("malloc");
699 			exit(1);
700 		}
701 		(void) strncpy(ifp->if_name, name, s - name);
702 		ifp->if_name[s - name] = '\0';
703 	} else {
704 		ifp->if_name = strdup(name);
705 		ifp->if_unit = -1;
706 	}
707 #endif
708 	ifp->if_output = no_output;
709 
710 	if (addr != NULL) {
711 		fr_setifpaddr(ifp, addr);
712 	}
713 
714 	return ifp;
715 }
716 
717 
718 char *get_ifname(ifp)
719 struct ifnet *ifp;
720 {
721 	static char ifname[LIFNAMSIZ];
722 
723 #if defined(__OpenBSD__) || defined(__NetBSD__) || defined(linux) || \
724     (defined(__FreeBSD__) && (__FreeBSD_version >= 501113))
725 	sprintf(ifname, "%s", ifp->if_xname);
726 #else
727 	sprintf(ifname, "%s%d", ifp->if_name, ifp->if_unit);
728 #endif
729 	return ifname;
730 }
731 
732 
733 
734 void init_ifp()
735 {
736 	struct ifnet *ifp, **ifpp;
737 	char fname[32];
738 	int fd;
739 
740 #if (defined(NetBSD) && (NetBSD <= 1991011) && (NetBSD >= 199606)) || \
741     (defined(OpenBSD) && (OpenBSD >= 199603)) || defined(linux) || \
742     (defined(__FreeBSD__) && (__FreeBSD_version >= 501113))
743 	for (ifpp = ifneta; ifpp && (ifp = *ifpp); ifpp++) {
744 		ifp->if_output = write_output;
745 		sprintf(fname, "/tmp/%s", ifp->if_xname);
746 		fd = open(fname, O_WRONLY|O_CREAT|O_EXCL|O_TRUNC, 0600);
747 		if (fd == -1)
748 			perror("open");
749 		else
750 			close(fd);
751 	}
752 #else
753 
754 	for (ifpp = ifneta; ifpp && (ifp = *ifpp); ifpp++) {
755 		ifp->if_output = write_output;
756 		sprintf(fname, "/tmp/%s%d", ifp->if_name, ifp->if_unit);
757 		fd = open(fname, O_WRONLY|O_CREAT|O_EXCL|O_TRUNC, 0600);
758 		if (fd == -1)
759 			perror("open");
760 		else
761 			close(fd);
762 	}
763 #endif
764 }
765 
766 
767 int fr_fastroute(m, mpp, fin, fdp)
768 mb_t *m, **mpp;
769 fr_info_t *fin;
770 frdest_t *fdp;
771 {
772 	struct ifnet *ifp = fdp->fd_ifp;
773 	ip_t *ip = fin->fin_ip;
774 
775 	if (!ifp)
776 		return 0;	/* no routing table out here */
777 
778 	ip->ip_len = htons((u_short)ip->ip_len);
779 	ip->ip_off = htons((u_short)(ip->ip_off | IP_MF));
780 	ip->ip_sum = 0;
781 #if defined(__sgi) && (IRIX < 60500)
782 	(*ifp->if_output)(ifp, (void *)ip, NULL);
783 # if TRU64 >= 1885
784 	(*ifp->if_output)(ifp, (void *)m, NULL, 0, 0);
785 # else
786 	(*ifp->if_output)(ifp, (void *)m, NULL, 0);
787 # endif
788 #endif
789 	return 0;
790 }
791 
792 
793 int fr_send_reset(fin)
794 fr_info_t *fin;
795 {
796 	verbose("- TCP RST sent\n");
797 	return 0;
798 }
799 
800 
801 int fr_send_icmp_err(type, fin, dst)
802 int type;
803 fr_info_t *fin;
804 int dst;
805 {
806 	verbose("- ICMP unreachable sent\n");
807 	return 0;
808 }
809 
810 
811 void frsync(command, version, nic, data, ifs)
812 int command, version;
813 void *nic;
814 char *data;
815 ipf_stack_t *ifs;
816 {
817 	return;
818 }
819 
820 
821 void m_freem(m)
822 mb_t *m;
823 {
824 	return;
825 }
826 
827 
828 void m_copydata(m, off, len, cp)
829 mb_t *m;
830 int off, len;
831 caddr_t cp;
832 {
833 	bcopy((char *)m + off, cp, len);
834 }
835 
836 
837 int ipfuiomove(buf, len, rwflag, uio)
838 caddr_t buf;
839 int len, rwflag;
840 struct uio *uio;
841 {
842 	int left, ioc, num, offset;
843 	struct iovec *io;
844 	char *start;
845 
846 	if (rwflag == UIO_READ) {
847 		left = len;
848 		ioc = 0;
849 
850 		offset = uio->uio_offset;
851 
852 		while ((left > 0) && (ioc < uio->uio_iovcnt)) {
853 			io = uio->uio_iov + ioc;
854 			num = io->iov_len;
855 			if (num > left)
856 				num = left;
857 			start = (char *)io->iov_base + offset;
858 			if (start > (char *)io->iov_base + io->iov_len) {
859 				offset -= io->iov_len;
860 				ioc++;
861 				continue;
862 			}
863 			bcopy(buf, start, num);
864 			uio->uio_resid -= num;
865 			uio->uio_offset += num;
866 			left -= num;
867 			if (left > 0)
868 				ioc++;
869 		}
870 		if (left > 0)
871 			return EFAULT;
872 	}
873 	return 0;
874 }
875 
876 
877 u_32_t fr_newisn(fin)
878 fr_info_t *fin;
879 {
880 	static int iss_seq_off = 0;
881 	u_char hash[16];
882 	u_32_t newiss;
883 	MD5_CTX ctx;
884 
885 	/*
886 	 * Compute the base value of the ISS.  It is a hash
887 	 * of (saddr, sport, daddr, dport, secret).
888 	 */
889 	MD5Init(&ctx);
890 
891 	MD5Update(&ctx, (u_char *) &fin->fin_fi.fi_src,
892 		  sizeof(fin->fin_fi.fi_src));
893 	MD5Update(&ctx, (u_char *) &fin->fin_fi.fi_dst,
894 		  sizeof(fin->fin_fi.fi_dst));
895 	MD5Update(&ctx, (u_char *) &fin->fin_dat, sizeof(fin->fin_dat));
896 
897 	/* MD5Update(&ctx, ipf_iss_secret, sizeof(ipf_iss_secret)); */
898 
899 	MD5Final(hash, &ctx);
900 
901 	memcpy(&newiss, hash, sizeof(newiss));
902 
903 	/*
904 	 * Now increment our "timer", and add it in to
905 	 * the computed value.
906 	 *
907 	 * XXX Use `addin'?
908 	 * XXX TCP_ISSINCR too large to use?
909 	 */
910 	iss_seq_off += 0x00010000;
911 	newiss += iss_seq_off;
912 	return newiss;
913 }
914 
915 
916 /* ------------------------------------------------------------------------ */
917 /* Function:    fr_nextipid                                                 */
918 /* Returns:     int - 0 == success, -1 == error (packet should be droppped) */
919 /* Parameters:  fin(I) - pointer to packet information                      */
920 /*                                                                          */
921 /* Returns the next IPv4 ID to use for this packet.                         */
922 /* ------------------------------------------------------------------------ */
923 INLINE u_short fr_nextipid(fin)
924 fr_info_t *fin;
925 {
926 	static u_short ipid = 0;
927 	u_short id;
928 	ipf_stack_t *ifs = fin->fin_ifs;
929 
930 	MUTEX_ENTER(&ifs->ifs_ipf_rw);
931 	id = ipid++;
932 	MUTEX_EXIT(&ifs->ifs_ipf_rw);
933 
934 	return id;
935 }
936 
937 
938 INLINE void fr_checkv4sum(fin)
939 fr_info_t *fin;
940 {
941 	if (fr_checkl4sum(fin) == -1)
942 		fin->fin_flx |= FI_BAD;
943 }
944 
945 
946 #ifdef	USE_INET6
947 INLINE void fr_checkv6sum(fin)
948 fr_info_t *fin;
949 {
950 	if (fr_checkl4sum(fin) == -1)
951 		fin->fin_flx |= FI_BAD;
952 }
953 #endif
954 
955 
956 /*
957  * See above for description, except that all addressing is in user space.
958  */
959 int copyoutptr(src, dst, size)
960 void *src, *dst;
961 size_t size;
962 {
963 	caddr_t ca;
964 
965 	bcopy(dst, (char *)&ca, sizeof(ca));
966 	bcopy(src, ca, size);
967 	return 0;
968 }
969 
970 
971 /*
972  * See above for description, except that all addressing is in user space.
973  */
974 int copyinptr(src, dst, size)
975 void *src, *dst;
976 size_t size;
977 {
978 	caddr_t ca;
979 
980 	bcopy(src, (char *)&ca, sizeof(ca));
981 	bcopy(ca, dst, size);
982 	return 0;
983 }
984 
985 
986 /*
987  * return the first IP Address associated with an interface
988  */
989 int fr_ifpaddr(v, atype, ifptr, inp, inpmask, ifs)
990 int v, atype;
991 void *ifptr;
992 struct in_addr *inp, *inpmask;
993 ipf_stack_t *ifs;
994 {
995 	struct ifnet *ifp = ifptr;
996 #ifdef __sgi
997 	struct in_ifaddr *ifa;
998 #else
999 	struct ifaddr *ifa;
1000 #endif
1001 
1002 #if defined(__NetBSD__) || defined(__OpenBSD__) || defined(__FreeBSD__)
1003 	ifa = ifp->if_addrlist.tqh_first;
1004 #else
1005 # ifdef __sgi
1006 	ifa = (struct in_ifaddr *)ifp->in_ifaddr;
1007 # else
1008 	ifa = ifp->if_addrlist;
1009 # endif
1010 #endif
1011 	if (ifa != NULL) {
1012 		struct sockaddr_in *sin, mask;
1013 
1014 		mask.sin_addr.s_addr = 0xffffffff;
1015 
1016 #ifdef __sgi
1017 		sin = (struct sockaddr_in *)&ifa->ia_addr;
1018 #else
1019 		sin = (struct sockaddr_in *)&ifa->ifa_addr;
1020 #endif
1021 
1022 		return fr_ifpfillv4addr(atype, sin, &mask, inp, inpmask);
1023 	}
1024 	return 0;
1025 }
1026 
1027 
1028 /*
1029  * This function is not meant to be random, rather just produce a
1030  * sequence of numbers that isn't linear to show "randomness".
1031  */
1032 u_32_t ipf_random()
1033 {
1034 	static u_int last = 0xa5a5a5a5;
1035 	static int calls = 0;
1036 	int number;
1037 
1038 	calls++;
1039 
1040 	/*
1041 	 * These are deliberately chosen to ensure that there is some
1042 	 * attempt to test whether the output covers the range in test n18.
1043 	 */
1044 	switch (calls)
1045 	{
1046 	case 1 :
1047 		number = 0;
1048 		break;
1049 	case 2 :
1050 		number = 4;
1051 		break;
1052 	case 3 :
1053 		number = 3999;
1054 		break;
1055 	case 4 :
1056 		number = 4000;
1057 		break;
1058 	case 5 :
1059 		number = 48999;
1060 		break;
1061 	case 6 :
1062 		number = 49000;
1063 		break;
1064 	default :
1065 		number = last;
1066 		last *= calls;
1067 		last++;
1068 		number ^= last;
1069 		break;
1070 	}
1071 	return number;
1072 }
1073