xref: /illumos-gate/usr/src/cmd/ipf/tools/ip_fil.c (revision cbded9ae11944b2d8ab0ae13e5dbd0881ddba98c)
1 /*
2  * Copyright (C) 1993-2001, 2003 by Darren Reed.
3  *
4  * See the IPFILTER.LICENCE file for details on licencing.
5  *
6  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
7  * Use is subject to license terms.
8  */
9 
10 #pragma ident	"%Z%%M%	%I%	%E% SMI"
11 
12 #if !defined(lint)
13 static const char sccsid[] = "@(#)ip_fil.c	2.41 6/5/96 (C) 1993-2000 Darren Reed";
14 static const char rcsid[] = "@(#)$Id: ip_fil.c,v 2.133.2.9 2005/01/08 14:22:18 darrenr Exp $";
15 #endif
16 
17 #ifndef	SOLARIS
18 #define	SOLARIS	(defined(sun) && (defined(__svr4__) || defined(__SVR4)))
19 #endif
20 
21 #include <sys/param.h>
22 #if defined(__FreeBSD__) && !defined(__FreeBSD_version)
23 # if defined(IPFILTER_LKM)
24 #  ifndef __FreeBSD_cc_version
25 #   include <osreldate.h>
26 #  else
27 #   if __FreeBSD_cc_version < 430000
28 #    include <osreldate.h>
29 #   endif
30 #  endif
31 # endif
32 #endif
33 #include <sys/errno.h>
34 #if defined(__hpux) && (HPUXREV >= 1111) && !defined(_KERNEL)
35 # include <sys/kern_svcs.h>
36 #endif
37 #include <sys/types.h>
38 #define _KERNEL
39 #define KERNEL
40 #ifdef __OpenBSD__
41 struct file;
42 #endif
43 #include <sys/uio.h>
44 #undef _KERNEL
45 #undef KERNEL
46 #include <sys/file.h>
47 #include <sys/ioctl.h>
48 #ifdef __sgi
49 # include <sys/ptimers.h>
50 #endif
51 #include <sys/time.h>
52 #if !SOLARIS
53 # if (NetBSD > 199609) || (OpenBSD > 199603) || (__FreeBSD_version >= 300000)
54 #  include <sys/dirent.h>
55 # else
56 #  include <sys/dir.h>
57 # endif
58 #else
59 # include <sys/filio.h>
60 #endif
61 #ifndef linux
62 # include <sys/protosw.h>
63 #endif
64 #include <sys/socket.h>
65 
66 #include <stdio.h>
67 #include <string.h>
68 #include <stdlib.h>
69 #include <ctype.h>
70 #include <fcntl.h>
71 #include <sys/zone.h>
72 #include <arpa/inet.h>
73 
74 #ifdef __hpux
75 # define _NET_ROUTE_INCLUDED
76 #endif
77 #include <net/if.h>
78 #ifdef sun
79 # include <net/af.h>
80 #endif
81 #if __FreeBSD_version >= 300000
82 # include <net/if_var.h>
83 #endif
84 #ifdef __sgi
85 #include <sys/debug.h>
86 # ifdef IFF_DRVRLOCK /* IRIX6 */
87 #include <sys/hashing.h>
88 # endif
89 #endif
90 #if defined(__FreeBSD__)
91 # include "radix_ipf.h"
92 #endif
93 #include <net/route.h>
94 #include <netinet/in.h>
95 #if !(defined(__sgi) && !defined(IFF_DRVRLOCK)) /* IRIX < 6 */ && \
96     !defined(__hpux) && !defined(linux)
97 # include <netinet/in_var.h>
98 #endif
99 #include <netinet/in_systm.h>
100 #include <netinet/ip.h>
101 #if !defined(linux)
102 # include <netinet/ip_var.h>
103 #endif
104 #include <netinet/tcp.h>
105 #if defined(__osf__)
106 # include <netinet/tcp_timer.h>
107 #endif
108 #if defined(__osf__) || defined(__hpux) || defined(__sgi)
109 # include "radix_ipf_local.h"
110 # define _RADIX_H_
111 #endif
112 #include <netinet/udp.h>
113 #include <netinet/tcpip.h>
114 #include <netinet/ip_icmp.h>
115 #include <unistd.h>
116 #include <syslog.h>
117 #ifdef __hpux
118 # undef _NET_ROUTE_INCLUDED
119 #endif
120 #include "netinet/ip_compat.h"
121 #include "netinet/ip_fil.h"
122 #include "netinet/ip_nat.h"
123 #include "netinet/ip_frag.h"
124 #include "netinet/ip_state.h"
125 #include "netinet/ip_proxy.h"
126 #include "netinet/ip_auth.h"
127 #ifdef	IPFILTER_SYNC
128 #include "netinet/ip_sync.h"
129 #endif
130 #ifdef	IPFILTER_SCAN
131 #include "netinet/ip_scan.h"
132 #endif
133 #include "netinet/ip_pool.h"
134 #ifdef IPFILTER_COMPILED
135 # include "netinet/ip_rules.h"
136 #endif
137 #include "netinet/ipf_stack.h"
138 #if defined(__FreeBSD_version) && (__FreeBSD_version >= 300000)
139 # include <sys/malloc.h>
140 #endif
141 #ifdef __hpux
142 struct rtentry;
143 #endif
144 #include "md5.h"
145 
146 
147 #if !defined(__osf__)
148 extern	struct	protosw	inetsw[];
149 #endif
150 
151 #include "ipt.h"
152 static	struct	ifnet **ifneta = NULL;
153 static	int	nifs = 0;
154 
155 static	int	frzerostats __P((caddr_t, ipf_stack_t *ifs));
156 static	void	fr_setifpaddr __P((struct ifnet *, char *));
157 void	init_ifp __P((void));
158 #if defined(__sgi) && (IRIX < 60500)
159 static int 	no_output __P((struct ifnet *, struct mbuf *,
160 			       struct sockaddr *));
161 static int	write_output __P((struct ifnet *, struct mbuf *,
162 				  struct sockaddr *));
163 #else
164 # if TRU64 >= 1885
165 static int 	no_output __P((struct ifnet *, struct mbuf *,
166 			       struct sockaddr *, struct rtentry *, char *));
167 static int	write_output __P((struct ifnet *, struct mbuf *,
168 				  struct sockaddr *, struct rtentry *, char *));
169 # else
170 static int 	no_output __P((struct ifnet *, struct mbuf *,
171 			       struct sockaddr *, struct rtentry *));
172 static int	write_output __P((struct ifnet *, struct mbuf *,
173 				  struct sockaddr *, struct rtentry *));
174 # endif
175 #endif
176 
177 
178 int iplattach(ifs, ns)
179 ipf_stack_t *ifs;
180 netstack_t *ns;
181 {
182 	ifs->ifs_fr_running = 1;
183 	return 0;
184 }
185 
186 
187 int ipldetach(ifs)
188 ipf_stack_t *ifs;
189 {
190 	ifs->ifs_fr_running = -1;
191 	return 0;
192 }
193 
194 
195 static	int	frzerostats(data, ifs)
196 caddr_t	data;
197 ipf_stack_t *ifs;
198 {
199 	friostat_t fio;
200 	int error;
201 
202 	fr_getstat(&fio, ifs);
203 	error = copyoutptr(&fio, data, sizeof(fio));
204 	if (error)
205 		return EFAULT;
206 
207 	bzero((char *)ifs->ifs_frstats, sizeof(*ifs->ifs_frstats) * 2);
208 
209 	return 0;
210 }
211 
212 
213 /*
214  * Filter ioctl interface.
215  */
216 int iplioctl(dev, cmd, data, mode)
217 int dev;
218 ioctlcmd_t cmd;
219 caddr_t data;
220 int mode;
221 {
222 	int error = 0, unit = 0, tmp, uid;
223 	friostat_t fio;
224 	ipf_stack_t *ifs;
225 	extern ipf_stack_t *get_ifs();
226 
227 	unit = dev;
228 	uid = getuid();
229 
230 	ifs = get_ifs();
231 
232 	SPL_NET(s);
233 
234 	if (unit == IPL_LOGNAT) {
235 		if (ifs->ifs_fr_running > 0)
236 			error = fr_nat_ioctl(data, cmd, mode, uid, NULL, ifs);
237 		else
238 			error = EIO;
239 		SPL_X(s);
240 		return error;
241 	}
242 	if (unit == IPL_LOGSTATE) {
243 		if (ifs->ifs_fr_running > 0)
244 			error = fr_state_ioctl(data, cmd, mode, uid, NULL, ifs);
245 		else
246 			error = EIO;
247 		SPL_X(s);
248 		return error;
249 	}
250 	if (unit == IPL_LOGAUTH) {
251 		if (ifs->ifs_fr_running > 0) {
252 			if ((cmd == (ioctlcmd_t)SIOCADAFR) ||
253 			    (cmd == (ioctlcmd_t)SIOCRMAFR)) {
254 				if (!(mode & FWRITE)) {
255 					error = EPERM;
256 				} else {
257 					error = frrequest(unit, cmd, data,
258 					    ifs->ifs_fr_active, 1, ifs);
259 				}
260 			} else {
261 				error = fr_auth_ioctl(data, mode, cmd, uid, NULL, ifs);
262 			}
263 		} else
264 			error = EIO;
265 		SPL_X(s);
266 		return error;
267 	}
268 	if (unit == IPL_LOGSYNC) {
269 #ifdef	IPFILTER_SYNC
270 		if (ifs->ifs_fr_running > 0)
271 			error = fr_sync_ioctl(data, cmd, mode);
272 		else
273 #endif
274 			error = EIO;
275 		SPL_X(s);
276 		return error;
277 	}
278 	if (unit == IPL_LOGSCAN) {
279 #ifdef	IPFILTER_SCAN
280 		if (ifs->ifs_fr_running > 0)
281 			error = fr_scan_ioctl(data, cmd, mode);
282 		else
283 #endif
284 			error = EIO;
285 		SPL_X(s);
286 		return error;
287 	}
288 	if (unit == IPL_LOGLOOKUP) {
289 		if (ifs->ifs_fr_running > 0)
290 			error = ip_lookup_ioctl(data, cmd, mode, uid,
291 			    NULL, ifs);
292 		else
293 			error = EIO;
294 		SPL_X(s);
295 		return error;
296 	}
297 
298 	switch (cmd)
299 	{
300 	case FIONREAD :
301 #ifdef IPFILTER_LOG
302 		error = COPYOUT(&ifs->ifs_iplused[IPL_LOGIPF], (caddr_t)data,
303 			       sizeof(ifs->ifs_iplused[IPL_LOGIPF]));
304 #endif
305 		break;
306 	case SIOCFRENB :
307 		if (!(mode & FWRITE))
308 			error = EPERM;
309 		else {
310 			error = COPYIN(data, &tmp, sizeof(tmp));
311 			if (error)
312 				break;
313 			if (tmp)
314 				error = iplattach(ifs, NULL);
315 			else
316 				error = ipldetach(ifs);
317 		}
318 		break;
319 	case SIOCIPFSET :
320 		if (!(mode & FWRITE)) {
321 			error = EPERM;
322 			break;
323 		}
324 	case SIOCIPFGETNEXT :
325 	case SIOCIPFGET :
326 		error = fr_ipftune(cmd, (void *)data, ifs);
327 		break;
328 	case SIOCSETFF :
329 		if (!(mode & FWRITE))
330 			error = EPERM;
331 		else
332 			error = COPYIN(data, &ifs->ifs_fr_flags,
333 			    sizeof(ifs->ifs_fr_flags));
334 		break;
335 	case SIOCGETFF :
336 		error = COPYOUT(&ifs->ifs_fr_flags, data,
337 		    sizeof(ifs->ifs_fr_flags));
338 		break;
339 	case SIOCFUNCL :
340 		error = fr_resolvefunc(data);
341 		break;
342 	case SIOCINAFR :
343 	case SIOCRMAFR :
344 	case SIOCADAFR :
345 	case SIOCZRLST :
346 		if (!(mode & FWRITE))
347 			error = EPERM;
348 		else
349 			error = frrequest(unit, cmd, data,
350 			    ifs->ifs_fr_active, 1, ifs);
351 		break;
352 	case SIOCINIFR :
353 	case SIOCRMIFR :
354 	case SIOCADIFR :
355 		if (!(mode & FWRITE))
356 			error = EPERM;
357 		else
358 			error = frrequest(unit, cmd, data,
359 			    1 - ifs->ifs_fr_active, 1, ifs);
360 		break;
361 	case SIOCSWAPA :
362 		if (!(mode & FWRITE))
363 			error = EPERM;
364 		else {
365 			*(u_int *)data = ifs->ifs_fr_active;
366 			ifs->ifs_fr_active = 1 - ifs->ifs_fr_active;
367 		}
368 		break;
369 	case SIOCGETFS :
370 		fr_getstat(&fio, ifs);
371 		error = fr_outobj(data, &fio, IPFOBJ_IPFSTAT);
372 		break;
373 	case	SIOCFRZST :
374 		if (!(mode & FWRITE))
375 			error = EPERM;
376 		else
377 			error = frzerostats(data, ifs);
378 		break;
379 	case	SIOCIPFFL :
380 		if (!(mode & FWRITE))
381 			error = EPERM;
382 		else {
383 			error = COPYIN(data, &tmp, sizeof(tmp));
384 			if (!error) {
385 				tmp = frflush(unit, 4, tmp, ifs);
386 				error = COPYOUT(&tmp, data, sizeof(tmp));
387 			}
388 		}
389 		break;
390 #ifdef	USE_INET6
391 	case	SIOCIPFL6 :
392 		if (!(mode & FWRITE))
393 			error = EPERM;
394 		else {
395 			error = COPYIN(data, &tmp, sizeof(tmp));
396 			if (!error) {
397 				tmp = frflush(unit, 6, tmp, ifs);
398 				error = COPYOUT(&tmp, data, sizeof(tmp));
399 			}
400 		}
401 		break;
402 #endif
403 	case SIOCSTLCK :
404 		error = COPYIN(data, &tmp, sizeof(tmp));
405 		if (error == 0) {
406 			ifs->ifs_fr_state_lock = tmp;
407 			ifs->ifs_fr_nat_lock = tmp;
408 			ifs->ifs_fr_frag_lock = tmp;
409 			ifs->ifs_fr_auth_lock = tmp;
410 		} else
411 			error = EFAULT;
412 		break;
413 #ifdef	IPFILTER_LOG
414 	case	SIOCIPFFB :
415 		if (!(mode & FWRITE))
416 			error = EPERM;
417 		else
418 			*(int *)data = ipflog_clear(unit, ifs);
419 		break;
420 #endif /* IPFILTER_LOG */
421 	case SIOCGFRST :
422 		error = fr_outobj(data, fr_fragstats(ifs), IPFOBJ_FRAGSTAT);
423 		break;
424 	case SIOCFRSYN :
425 		if (!(mode & FWRITE))
426 			error = EPERM;
427 		else {
428 			frsync(IPFSYNC_RESYNC, IPFSYNC_RESYNC, NULL, NULL, ifs);
429 		}
430 		break;
431 	default :
432 		error = EINVAL;
433 		break;
434 	}
435 	SPL_X(s);
436 	return error;
437 }
438 
439 
440 void fr_forgetifp(ifp, ifs)
441 void *ifp;
442 ipf_stack_t *ifs;
443 {
444 	register frentry_t *f;
445 
446 	WRITE_ENTER(&ifs->ifs_ipf_mutex);
447 	for (f = ifs->ifs_ipacct[0][ifs->ifs_fr_active]; (f != NULL);
448 	    f = f->fr_next)
449 		if (f->fr_ifa == ifp)
450 			f->fr_ifa = (void *)-1;
451 	for (f = ifs->ifs_ipacct[1][ifs->ifs_fr_active]; (f != NULL);
452 	    f = f->fr_next)
453 		if (f->fr_ifa == ifp)
454 			f->fr_ifa = (void *)-1;
455 	for (f = ifs->ifs_ipfilter[0][ifs->ifs_fr_active]; (f != NULL);
456 	    f = f->fr_next)
457 		if (f->fr_ifa == ifp)
458 			f->fr_ifa = (void *)-1;
459 	for (f = ifs->ifs_ipfilter[1][ifs->ifs_fr_active]; (f != NULL);
460 	    f = f->fr_next)
461 		if (f->fr_ifa == ifp)
462 			f->fr_ifa = (void *)-1;
463 #ifdef	USE_INET6
464 	for (f = ifs->ifs_ipacct6[0][ifs->ifs_fr_active]; (f != NULL);
465 	    f = f->fr_next)
466 		if (f->fr_ifa == ifp)
467 			f->fr_ifa = (void *)-1;
468 	for (f = ifs->ifs_ipacct6[1][ifs->ifs_fr_active]; (f != NULL);
469 	    f = f->fr_next)
470 		if (f->fr_ifa == ifp)
471 			f->fr_ifa = (void *)-1;
472 	for (f = ifs->ifs_ipfilter6[0][ifs->ifs_fr_active]; (f != NULL);
473 	    f = f->fr_next)
474 		if (f->fr_ifa == ifp)
475 			f->fr_ifa = (void *)-1;
476 	for (f = ifs->ifs_ipfilter6[1][ifs->ifs_fr_active]; (f != NULL);
477 	    f = f->fr_next)
478 		if (f->fr_ifa == ifp)
479 			f->fr_ifa = (void *)-1;
480 #endif
481 	RWLOCK_EXIT(&ifs->ifs_ipf_mutex);
482 	fr_natifpsync(IPFSYNC_OLDIFP, 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