xref: /illumos-gate/usr/src/cmd/ipf/tools/ip_fil.c (revision d6c23f6f)
1 /*
2  * Copyright (C) 1993-2001, 2003 by Darren Reed.
3  *
4  * See the IPFILTER.LICENCE file for details on licencing.
5  *
6  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
7  * Use is subject to license terms.
8  */
9 
10 #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, 4, ifp, NULL, ifs);
483 	fr_natifpsync(IPFSYNC_OLDIFP, 6, ifp, NULL, ifs);
484 }
485 
486 
487 void fr_resolvedest(fdp, v, ifs)
488 frdest_t *fdp;
489 int v;
490 ipf_stack_t *ifs;
491 {
492 	fdp->fd_ifp = NULL;
493 
494 	if (*fdp->fd_ifname) {
495 		fdp->fd_ifp = GETIFP(fdp->fd_ifname, v, ifs);
496 		if (!fdp->fd_ifp)
497 			fdp->fd_ifp = (struct ifnet *)-1;
498 	}
499 }
500 
501 
502 #if defined(__sgi) && (IRIX < 60500)
503 static int no_output(ifp, m, s)
504 #else
505 # if TRU64 >= 1885
506 static int no_output (ifp, m, s, rt, cp)
507 char *cp;
508 # else
509 static int no_output(ifp, m, s, rt)
510 # endif
511 struct rtentry *rt;
512 #endif
513 struct ifnet *ifp;
514 struct mbuf *m;
515 struct sockaddr *s;
516 {
517 	return 0;
518 }
519 
520 
521 #if defined(__sgi) && (IRIX < 60500)
522 static int write_output(ifp, m, s)
523 #else
524 # if TRU64 >= 1885
525 static int write_output (ifp, m, s, rt, cp)
526 char *cp;
527 # else
528 static int write_output(ifp, m, s, rt)
529 # endif
530 struct rtentry *rt;
531 #endif
532 struct ifnet *ifp;
533 struct mbuf *m;
534 struct sockaddr *s;
535 {
536 	char fname[32];
537 	mb_t *mb;
538 	ip_t *ip;
539 	int fd;
540 
541 	mb = (mb_t *)m;
542 	ip = MTOD(mb, ip_t *);
543 
544 #if (defined(NetBSD) && (NetBSD <= 1991011) && (NetBSD >= 199606)) || \
545     (defined(OpenBSD) && (OpenBSD >= 199603)) || defined(linux) || \
546     (defined(__FreeBSD__) && (__FreeBSD_version >= 501113))
547 	sprintf(fname, "/tmp/%s", ifp->if_xname);
548 #else
549 	sprintf(fname, "/tmp/%s%d", ifp->if_name, ifp->if_unit);
550 #endif
551 	fd = open(fname, O_WRONLY|O_APPEND);
552 	if (fd == -1) {
553 		perror("open");
554 		return -1;
555 	}
556 	write(fd, (char *)ip, ntohs(ip->ip_len));
557 	close(fd);
558 	return 0;
559 }
560 
561 
562 static void fr_setifpaddr(ifp, addr)
563 struct ifnet *ifp;
564 char *addr;
565 {
566 #ifdef __sgi
567 	struct in_ifaddr *ifa;
568 #else
569 	struct ifaddr *ifa;
570 #endif
571 
572 #if defined(__NetBSD__) || defined(__OpenBSD__) || defined(__FreeBSD__)
573 	if (ifp->if_addrlist.tqh_first != NULL)
574 #else
575 # ifdef __sgi
576 	if (ifp->in_ifaddr != NULL)
577 # else
578 	if (ifp->if_addrlist != NULL)
579 # endif
580 #endif
581 		return;
582 
583 	ifa = (struct ifaddr *)malloc(sizeof(*ifa));
584 #if defined(__NetBSD__) || defined(__OpenBSD__) || defined(__FreeBSD__)
585 	ifp->if_addrlist.tqh_first = ifa;
586 #else
587 # ifdef __sgi
588 	ifp->in_ifaddr = ifa;
589 # else
590 	ifp->if_addrlist = ifa;
591 # endif
592 #endif
593 
594 	if (ifa != NULL) {
595 		struct sockaddr_in *sin;
596 
597 #ifdef __sgi
598 		sin = (struct sockaddr_in *)&ifa->ia_addr;
599 #else
600 		sin = (struct sockaddr_in *)&ifa->ifa_addr;
601 #endif
602 		sin->sin_addr.s_addr = inet_addr(addr);
603 		if (sin->sin_addr.s_addr == 0)
604 			abort();
605 	}
606 }
607 
608 /*ARGSUSED*/
609 struct ifnet *get_unit(name, v, ifs)
610 char *name;
611 int v;
612 ipf_stack_t *ifs;
613 {
614 	struct ifnet *ifp, **ifpp, **old_ifneta;
615 	char *addr;
616 #if (defined(NetBSD) && (NetBSD <= 1991011) && (NetBSD >= 199606)) || \
617     (defined(OpenBSD) && (OpenBSD >= 199603)) || defined(linux) || \
618     (defined(__FreeBSD__) && (__FreeBSD_version >= 501113))
619 
620 	if (name == NULL)
621 		name = "anon0";
622 
623 	addr = strchr(name, '=');
624 	if (addr != NULL)
625 		*addr++ = '\0';
626 
627 	for (ifpp = ifneta; ifpp && (ifp = *ifpp); ifpp++) {
628 		if (!strcmp(name, ifp->if_xname)) {
629 			if (addr != NULL)
630 				fr_setifpaddr(ifp, addr);
631 			return ifp;
632 		}
633 	}
634 #else
635 	char *s, ifname[LIFNAMSIZ+1];
636 
637 	if (name == NULL)
638 		name = "anon0";
639 
640 	addr = strchr(name, '=');
641 	if (addr != NULL)
642 		*addr++ = '\0';
643 
644 	for (ifpp = ifneta; ifpp && (ifp = *ifpp); ifpp++) {
645 		COPYIFNAME(ifp, ifname, 0);
646 		if (!strcmp(name, ifname)) {
647 			if (addr != NULL)
648 				fr_setifpaddr(ifp, addr);
649 			return ifp;
650 		}
651 	}
652 #endif
653 
654 	if (!ifneta) {
655 		ifneta = (struct ifnet **)malloc(sizeof(ifp) * 2);
656 		if (!ifneta)
657 			return NULL;
658 		ifneta[1] = NULL;
659 		ifneta[0] = (struct ifnet *)calloc(1, sizeof(*ifp));
660 		if (!ifneta[0]) {
661 			free(ifneta);
662 			return NULL;
663 		}
664 		nifs = 1;
665 	} else {
666 		old_ifneta = ifneta;
667 		nifs++;
668 		ifneta = (struct ifnet **)realloc(ifneta,
669 						  (nifs + 1) * sizeof(ifp));
670 		if (!ifneta) {
671 			free(old_ifneta);
672 			nifs = 0;
673 			return NULL;
674 		}
675 		ifneta[nifs] = NULL;
676 		ifneta[nifs - 1] = (struct ifnet *)malloc(sizeof(*ifp));
677 		if (!ifneta[nifs - 1]) {
678 			nifs--;
679 			return NULL;
680 		}
681 	}
682 	ifp = ifneta[nifs - 1];
683 
684 #if (defined(NetBSD) && (NetBSD <= 1991011) && (NetBSD >= 199606)) || \
685     (defined(OpenBSD) && (OpenBSD >= 199603)) || defined(linux) || \
686     (defined(__FreeBSD__) && (__FreeBSD_version >= 501113))
687 	(void) strncpy(ifp->if_xname, name, sizeof(ifp->if_xname));
688 #else
689 	for (s = name; *s && !ISDIGIT(*s); s++)
690 		;
691 	if (*s && ISDIGIT(*s)) {
692 		ifp->if_unit = atoi(s);
693 		ifp->if_name = (char *)malloc(s - name + 1);
694 		if (ifp->if_name == NULL) {
695 			/*
696 			 * XXX do it more elegantly: free up mem,
697 			 * return NULL
698 			 */
699 			perror("malloc");
700 			exit(1);
701 		}
702 		(void) strncpy(ifp->if_name, name, s - name);
703 		ifp->if_name[s - name] = '\0';
704 	} else {
705 		ifp->if_name = strdup(name);
706 		ifp->if_unit = -1;
707 	}
708 #endif
709 	ifp->if_output = no_output;
710 
711 	if (addr != NULL) {
712 		fr_setifpaddr(ifp, addr);
713 	}
714 
715 	return ifp;
716 }
717 
718 
719 char *get_ifname(ifp)
720 struct ifnet *ifp;
721 {
722 	static char ifname[LIFNAMSIZ];
723 
724 #if defined(__OpenBSD__) || defined(__NetBSD__) || defined(linux) || \
725     (defined(__FreeBSD__) && (__FreeBSD_version >= 501113))
726 	sprintf(ifname, "%s", ifp->if_xname);
727 #else
728 	sprintf(ifname, "%s%d", ifp->if_name, ifp->if_unit);
729 #endif
730 	return ifname;
731 }
732 
733 
734 
735 void init_ifp()
736 {
737 	struct ifnet *ifp, **ifpp;
738 	char fname[32];
739 	int fd;
740 
741 #if (defined(NetBSD) && (NetBSD <= 1991011) && (NetBSD >= 199606)) || \
742     (defined(OpenBSD) && (OpenBSD >= 199603)) || defined(linux) || \
743     (defined(__FreeBSD__) && (__FreeBSD_version >= 501113))
744 	for (ifpp = ifneta; ifpp && (ifp = *ifpp); ifpp++) {
745 		ifp->if_output = write_output;
746 		sprintf(fname, "/tmp/%s", ifp->if_xname);
747 		fd = open(fname, O_WRONLY|O_CREAT|O_EXCL|O_TRUNC, 0600);
748 		if (fd == -1)
749 			perror("open");
750 		else
751 			close(fd);
752 	}
753 #else
754 
755 	for (ifpp = ifneta; ifpp && (ifp = *ifpp); ifpp++) {
756 		ifp->if_output = write_output;
757 		sprintf(fname, "/tmp/%s%d", ifp->if_name, ifp->if_unit);
758 		fd = open(fname, O_WRONLY|O_CREAT|O_EXCL|O_TRUNC, 0600);
759 		if (fd == -1)
760 			perror("open");
761 		else
762 			close(fd);
763 	}
764 #endif
765 }
766 
767 
768 int fr_fastroute(m, mpp, fin, fdp)
769 mb_t *m, **mpp;
770 fr_info_t *fin;
771 frdest_t *fdp;
772 {
773 	struct ifnet *ifp = fdp->fd_ifp;
774 	ip_t *ip = fin->fin_ip;
775 
776 	if (!ifp)
777 		return 0;	/* no routing table out here */
778 
779 	ip->ip_len = htons((u_short)ip->ip_len);
780 	ip->ip_off = htons((u_short)(ip->ip_off | IP_MF));
781 	ip->ip_sum = 0;
782 #if defined(__sgi) && (IRIX < 60500)
783 	(*ifp->if_output)(ifp, (void *)ip, NULL);
784 # if TRU64 >= 1885
785 	(*ifp->if_output)(ifp, (void *)m, NULL, 0, 0);
786 # else
787 	(*ifp->if_output)(ifp, (void *)m, NULL, 0);
788 # endif
789 #endif
790 	return 0;
791 }
792 
793 
794 int fr_send_reset(fin)
795 fr_info_t *fin;
796 {
797 	verbose("- TCP RST sent\n");
798 	return 0;
799 }
800 
801 
802 int fr_send_icmp_err(type, fin, dst)
803 int type;
804 fr_info_t *fin;
805 int dst;
806 {
807 	verbose("- ICMP unreachable sent\n");
808 	return 0;
809 }
810 
811 
812 void frsync(command, version, nic, data, ifs)
813 int command, version;
814 void *nic;
815 char *data;
816 ipf_stack_t *ifs;
817 {
818 	return;
819 }
820 
821 
822 void m_freem(m)
823 mb_t *m;
824 {
825 	return;
826 }
827 
828 
829 void m_copydata(m, off, len, cp)
830 mb_t *m;
831 int off, len;
832 caddr_t cp;
833 {
834 	bcopy((char *)m + off, cp, len);
835 }
836 
837 
838 int ipfuiomove(buf, len, rwflag, uio)
839 caddr_t buf;
840 int len, rwflag;
841 struct uio *uio;
842 {
843 	int left, ioc, num, offset;
844 	struct iovec *io;
845 	char *start;
846 
847 	if (rwflag == UIO_READ) {
848 		left = len;
849 		ioc = 0;
850 
851 		offset = uio->uio_offset;
852 
853 		while ((left > 0) && (ioc < uio->uio_iovcnt)) {
854 			io = uio->uio_iov + ioc;
855 			num = io->iov_len;
856 			if (num > left)
857 				num = left;
858 			start = (char *)io->iov_base + offset;
859 			if (start > (char *)io->iov_base + io->iov_len) {
860 				offset -= io->iov_len;
861 				ioc++;
862 				continue;
863 			}
864 			bcopy(buf, start, num);
865 			uio->uio_resid -= num;
866 			uio->uio_offset += num;
867 			left -= num;
868 			if (left > 0)
869 				ioc++;
870 		}
871 		if (left > 0)
872 			return EFAULT;
873 	}
874 	return 0;
875 }
876 
877 
878 u_32_t fr_newisn(fin)
879 fr_info_t *fin;
880 {
881 	static int iss_seq_off = 0;
882 	u_char hash[16];
883 	u_32_t newiss;
884 	MD5_CTX ctx;
885 
886 	/*
887 	 * Compute the base value of the ISS.  It is a hash
888 	 * of (saddr, sport, daddr, dport, secret).
889 	 */
890 	MD5Init(&ctx);
891 
892 	MD5Update(&ctx, (u_char *) &fin->fin_fi.fi_src,
893 		  sizeof(fin->fin_fi.fi_src));
894 	MD5Update(&ctx, (u_char *) &fin->fin_fi.fi_dst,
895 		  sizeof(fin->fin_fi.fi_dst));
896 	MD5Update(&ctx, (u_char *) &fin->fin_dat, sizeof(fin->fin_dat));
897 
898 	/* MD5Update(&ctx, ipf_iss_secret, sizeof(ipf_iss_secret)); */
899 
900 	MD5Final(hash, &ctx);
901 
902 	memcpy(&newiss, hash, sizeof(newiss));
903 
904 	/*
905 	 * Now increment our "timer", and add it in to
906 	 * the computed value.
907 	 *
908 	 * XXX Use `addin'?
909 	 * XXX TCP_ISSINCR too large to use?
910 	 */
911 	iss_seq_off += 0x00010000;
912 	newiss += iss_seq_off;
913 	return newiss;
914 }
915 
916 
917 /* ------------------------------------------------------------------------ */
918 /* Function:    fr_nextipid                                                 */
919 /* Returns:     int - 0 == success, -1 == error (packet should be droppped) */
920 /* Parameters:  fin(I) - pointer to packet information                      */
921 /*                                                                          */
922 /* Returns the next IPv4 ID to use for this packet.                         */
923 /* ------------------------------------------------------------------------ */
924 INLINE u_short fr_nextipid(fin)
925 fr_info_t *fin;
926 {
927 	static u_short ipid = 0;
928 	u_short id;
929 	ipf_stack_t *ifs = fin->fin_ifs;
930 
931 	MUTEX_ENTER(&ifs->ifs_ipf_rw);
932 	id = ipid++;
933 	MUTEX_EXIT(&ifs->ifs_ipf_rw);
934 
935 	return id;
936 }
937 
938 
939 INLINE void fr_checkv4sum(fin)
940 fr_info_t *fin;
941 {
942 	if (fr_checkl4sum(fin) == -1)
943 		fin->fin_flx |= FI_BAD;
944 }
945 
946 
947 #ifdef	USE_INET6
948 INLINE void fr_checkv6sum(fin)
949 fr_info_t *fin;
950 {
951 	if (fr_checkl4sum(fin) == -1)
952 		fin->fin_flx |= FI_BAD;
953 }
954 #endif
955 
956 
957 /*
958  * See above for description, except that all addressing is in user space.
959  */
960 int copyoutptr(src, dst, size)
961 void *src, *dst;
962 size_t size;
963 {
964 	caddr_t ca;
965 
966 	bcopy(dst, (char *)&ca, sizeof(ca));
967 	bcopy(src, ca, size);
968 	return 0;
969 }
970 
971 
972 /*
973  * See above for description, except that all addressing is in user space.
974  */
975 int copyinptr(src, dst, size)
976 void *src, *dst;
977 size_t size;
978 {
979 	caddr_t ca;
980 
981 	bcopy(src, (char *)&ca, sizeof(ca));
982 	bcopy(ca, dst, size);
983 	return 0;
984 }
985 
986 
987 /*
988  * return the first IP Address associated with an interface
989  */
990 int fr_ifpaddr(v, atype, ifptr, inp, inpmask, ifs)
991 int v, atype;
992 void *ifptr;
993 struct in_addr *inp, *inpmask;
994 ipf_stack_t *ifs;
995 {
996 	struct ifnet *ifp = ifptr;
997 #ifdef __sgi
998 	struct in_ifaddr *ifa;
999 #else
1000 	struct ifaddr *ifa;
1001 #endif
1002 
1003 #if defined(__NetBSD__) || defined(__OpenBSD__) || defined(__FreeBSD__)
1004 	ifa = ifp->if_addrlist.tqh_first;
1005 #else
1006 # ifdef __sgi
1007 	ifa = (struct in_ifaddr *)ifp->in_ifaddr;
1008 # else
1009 	ifa = ifp->if_addrlist;
1010 # endif
1011 #endif
1012 	if (ifa != NULL) {
1013 		struct sockaddr_in *sin, mask;
1014 
1015 		mask.sin_addr.s_addr = 0xffffffff;
1016 
1017 #ifdef __sgi
1018 		sin = (struct sockaddr_in *)&ifa->ia_addr;
1019 #else
1020 		sin = (struct sockaddr_in *)&ifa->ifa_addr;
1021 #endif
1022 
1023 		return fr_ifpfillv4addr(atype, sin, &mask, inp, inpmask);
1024 	}
1025 	return 0;
1026 }
1027