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