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