ip_fil.c revision 180778
1/*	$FreeBSD: head/contrib/ipfilter/ip_fil.c 180778 2008-07-24 12:35:05Z darrenr $	*/
2
3/*
4 * Copyright (C) 1993-2001 by Darren Reed.
5 *
6 * See the IPFILTER.LICENCE file for details on licencing.
7 */
8#if !defined(lint)
9static const char sccsid[] = "@(#)ip_fil.c	2.41 6/5/96 (C) 1993-2000 Darren Reed";
10static const char rcsid[] = "@(#)$Id: ip_fil.c,v 2.133.2.18 2007/09/09 11:32:05 darrenr Exp $";
11#endif
12
13#ifndef	SOLARIS
14#define	SOLARIS	(defined(sun) && (defined(__svr4__) || defined(__SVR4)))
15#endif
16
17#include <sys/param.h>
18#if defined(__FreeBSD__) && !defined(__FreeBSD_version)
19# if defined(IPFILTER_LKM)
20#  ifndef __FreeBSD_cc_version
21#   include <osreldate.h>
22#  else
23#   if __FreeBSD_cc_version < 430000
24#    include <osreldate.h>
25#   endif
26#  endif
27# endif
28#endif
29#include <sys/errno.h>
30#if defined(__hpux) && (HPUXREV >= 1111) && !defined(_KERNEL)
31# include <sys/kern_svcs.h>
32#endif
33#include <sys/types.h>
34#define _KERNEL
35#define KERNEL
36#ifdef __OpenBSD__
37struct file;
38#endif
39#include <sys/uio.h>
40#undef _KERNEL
41#undef KERNEL
42#include <sys/file.h>
43#include <sys/ioctl.h>
44#ifdef __sgi
45# include <sys/ptimers.h>
46#endif
47#include <sys/time.h>
48#if !SOLARIS
49# if (NetBSD > 199609) || (OpenBSD > 199603) || (__FreeBSD_version >= 300000)
50#  include <sys/dirent.h>
51# else
52#  include <sys/dir.h>
53# endif
54#else
55# include <sys/filio.h>
56#endif
57#ifndef linux
58# include <sys/protosw.h>
59#endif
60#include <sys/socket.h>
61
62#include <stdio.h>
63#include <string.h>
64#include <stdlib.h>
65#include <ctype.h>
66#include <fcntl.h>
67
68#ifdef __hpux
69# define _NET_ROUTE_INCLUDED
70#endif
71#include <net/if.h>
72#ifdef sun
73# include <net/af.h>
74#endif
75#if __FreeBSD_version >= 300000
76# include <net/if_var.h>
77#endif
78#ifdef __sgi
79#include <sys/debug.h>
80# ifdef IFF_DRVRLOCK /* IRIX6 */
81#include <sys/hashing.h>
82# endif
83#endif
84#if defined(__FreeBSD__) || defined(SOLARIS2)
85# include "radix_ipf.h"
86#endif
87#ifndef __osf__
88# include <net/route.h>
89#endif
90#include <netinet/in.h>
91#if !(defined(__sgi) && !defined(IFF_DRVRLOCK)) /* IRIX < 6 */ && \
92    !defined(__hpux) && !defined(linux)
93# include <netinet/in_var.h>
94#endif
95#include <netinet/in_systm.h>
96#include <netinet/ip.h>
97#if !defined(linux)
98# include <netinet/ip_var.h>
99#endif
100#include <netinet/tcp.h>
101#if defined(__osf__)
102# include <netinet/tcp_timer.h>
103#endif
104#if defined(__osf__) || defined(__hpux) || defined(__sgi)
105# include "radix_ipf_local.h"
106# define _RADIX_H_
107#endif
108#include <netinet/udp.h>
109#include <netinet/tcpip.h>
110#include <netinet/ip_icmp.h>
111#include <unistd.h>
112#include <syslog.h>
113#include <arpa/inet.h>
114#ifdef __hpux
115# undef _NET_ROUTE_INCLUDED
116#endif
117#include "netinet/ip_compat.h"
118#include "netinet/ip_fil.h"
119#include "netinet/ip_nat.h"
120#include "netinet/ip_frag.h"
121#include "netinet/ip_state.h"
122#include "netinet/ip_proxy.h"
123#include "netinet/ip_auth.h"
124#ifdef	IPFILTER_SYNC
125#include "netinet/ip_sync.h"
126#endif
127#ifdef	IPFILTER_SCAN
128#include "netinet/ip_scan.h"
129#endif
130#include "netinet/ip_pool.h"
131#ifdef IPFILTER_COMPILED
132# include "netinet/ip_rules.h"
133#endif
134#if defined(__FreeBSD_version) && (__FreeBSD_version >= 300000)
135# include <sys/malloc.h>
136#endif
137#ifdef __hpux
138struct rtentry;
139#endif
140#include "md5.h"
141
142
143#if !defined(__osf__) && !defined(__linux__)
144extern	struct	protosw	inetsw[];
145#endif
146
147#include "ipt.h"
148static	struct	ifnet **ifneta = NULL;
149static	int	nifs = 0;
150
151static	void	fr_setifpaddr __P((struct ifnet *, char *));
152void	init_ifp __P((void));
153#if defined(__sgi) && (IRIX < 60500)
154static int 	no_output __P((struct ifnet *, struct mbuf *,
155			       struct sockaddr *));
156static int	write_output __P((struct ifnet *, struct mbuf *,
157				  struct sockaddr *));
158#else
159# if TRU64 >= 1885
160static int 	no_output __P((struct ifnet *, struct mbuf *,
161			       struct sockaddr *, struct rtentry *, char *));
162static int	write_output __P((struct ifnet *, struct mbuf *,
163				  struct sockaddr *, struct rtentry *, char *));
164# else
165static int 	no_output __P((struct ifnet *, struct mbuf *,
166			       struct sockaddr *, struct rtentry *));
167static int	write_output __P((struct ifnet *, struct mbuf *,
168				  struct sockaddr *, struct rtentry *));
169# endif
170#endif
171
172
173int ipfattach()
174{
175	fr_running = 1;
176	return 0;
177}
178
179
180int ipfdetach()
181{
182	fr_running = -1;
183	return 0;
184}
185
186
187/*
188 * Filter ioctl interface.
189 */
190int iplioctl(dev, cmd, data, mode)
191int dev;
192ioctlcmd_t cmd;
193caddr_t data;
194int mode;
195{
196	int error = 0, unit = 0, uid;
197	SPL_INT(s);
198
199	uid = getuid();
200	unit = dev;
201
202	SPL_NET(s);
203
204	error = fr_ioctlswitch(unit, data, cmd, mode, uid, NULL);
205	if (error != -1) {
206		SPL_X(s);
207		return error;
208	}
209
210	SPL_X(s);
211	return error;
212}
213
214
215void fr_forgetifp(ifp)
216void *ifp;
217{
218	register frentry_t *f;
219
220	WRITE_ENTER(&ipf_mutex);
221	for (f = ipacct[0][fr_active]; (f != NULL); f = f->fr_next)
222		if (f->fr_ifa == ifp)
223			f->fr_ifa = (void *)-1;
224	for (f = ipacct[1][fr_active]; (f != NULL); f = f->fr_next)
225		if (f->fr_ifa == ifp)
226			f->fr_ifa = (void *)-1;
227	for (f = ipfilter[0][fr_active]; (f != NULL); f = f->fr_next)
228		if (f->fr_ifa == ifp)
229			f->fr_ifa = (void *)-1;
230	for (f = ipfilter[1][fr_active]; (f != NULL); f = f->fr_next)
231		if (f->fr_ifa == ifp)
232			f->fr_ifa = (void *)-1;
233#ifdef	USE_INET6
234	for (f = ipacct6[0][fr_active]; (f != NULL); f = f->fr_next)
235		if (f->fr_ifa == ifp)
236			f->fr_ifa = (void *)-1;
237	for (f = ipacct6[1][fr_active]; (f != NULL); f = f->fr_next)
238		if (f->fr_ifa == ifp)
239			f->fr_ifa = (void *)-1;
240	for (f = ipfilter6[0][fr_active]; (f != NULL); f = f->fr_next)
241		if (f->fr_ifa == ifp)
242			f->fr_ifa = (void *)-1;
243	for (f = ipfilter6[1][fr_active]; (f != NULL); f = f->fr_next)
244		if (f->fr_ifa == ifp)
245			f->fr_ifa = (void *)-1;
246#endif
247	RWLOCK_EXIT(&ipf_mutex);
248	fr_natsync(ifp);
249}
250
251
252#if defined(__sgi) && (IRIX < 60500)
253static int no_output(ifp, m, s)
254#else
255# if TRU64 >= 1885
256static int no_output (ifp, m, s, rt, cp)
257char *cp;
258# else
259static int no_output(ifp, m, s, rt)
260# endif
261struct rtentry *rt;
262#endif
263struct ifnet *ifp;
264struct mbuf *m;
265struct sockaddr *s;
266{
267	return 0;
268}
269
270
271#if defined(__sgi) && (IRIX < 60500)
272static int write_output(ifp, m, s)
273#else
274# if TRU64 >= 1885
275static int write_output (ifp, m, s, rt, cp)
276char *cp;
277# else
278static int write_output(ifp, m, s, rt)
279# endif
280struct rtentry *rt;
281#endif
282struct ifnet *ifp;
283struct mbuf *m;
284struct sockaddr *s;
285{
286	char fname[32];
287	mb_t *mb;
288	ip_t *ip;
289	int fd;
290
291	mb = (mb_t *)m;
292	ip = MTOD(mb, ip_t *);
293
294#if (defined(NetBSD) && (NetBSD <= 1991011) && (NetBSD >= 199606)) || \
295    (defined(OpenBSD) && (OpenBSD >= 199603)) || defined(linux) || \
296    (defined(__FreeBSD__) && (__FreeBSD_version >= 501113))
297	sprintf(fname, "/tmp/%s", ifp->if_xname);
298#else
299	sprintf(fname, "/tmp/%s%d", ifp->if_name, ifp->if_unit);
300#endif
301	fd = open(fname, O_WRONLY|O_APPEND);
302	if (fd == -1) {
303		perror("open");
304		return -1;
305	}
306	write(fd, (char *)ip, ntohs(ip->ip_len));
307	close(fd);
308	return 0;
309}
310
311
312static void fr_setifpaddr(ifp, addr)
313struct ifnet *ifp;
314char *addr;
315{
316#ifdef __sgi
317	struct in_ifaddr *ifa;
318#else
319	struct ifaddr *ifa;
320#endif
321
322#if defined(__NetBSD__) || defined(__OpenBSD__) || defined(__FreeBSD__)
323	if (ifp->if_addrlist.tqh_first != NULL)
324#else
325# ifdef __sgi
326	if (ifp->in_ifaddr != NULL)
327# else
328	if (ifp->if_addrlist != NULL)
329# endif
330#endif
331		return;
332
333	ifa = (struct ifaddr *)malloc(sizeof(*ifa));
334#if defined(__NetBSD__) || defined(__OpenBSD__) || defined(__FreeBSD__)
335	ifp->if_addrlist.tqh_first = ifa;
336#else
337# ifdef __sgi
338	ifp->in_ifaddr = ifa;
339# else
340	ifp->if_addrlist = ifa;
341# endif
342#endif
343
344	if (ifa != NULL) {
345		struct sockaddr_in *sin;
346
347#ifdef __sgi
348		sin = (struct sockaddr_in *)&ifa->ia_addr;
349#else
350		sin = (struct sockaddr_in *)&ifa->ifa_addr;
351#endif
352		sin->sin_addr.s_addr = inet_addr(addr);
353		if (sin->sin_addr.s_addr == 0)
354			abort();
355	}
356}
357
358struct ifnet *get_unit(name, v)
359char *name;
360int v;
361{
362	struct ifnet *ifp, **ifpp, **old_ifneta;
363	char *addr;
364#if (defined(NetBSD) && (NetBSD <= 1991011) && (NetBSD >= 199606)) || \
365    (defined(OpenBSD) && (OpenBSD >= 199603)) || defined(linux) || \
366    (defined(__FreeBSD__) && (__FreeBSD_version >= 501113))
367
368	if (name == NULL)
369		name = "anon0";
370
371	addr = strchr(name, '=');
372	if (addr != NULL)
373		*addr++ = '\0';
374
375	for (ifpp = ifneta; ifpp && (ifp = *ifpp); ifpp++) {
376		if (!strcmp(name, ifp->if_xname)) {
377			if (addr != NULL)
378				fr_setifpaddr(ifp, addr);
379			return ifp;
380		}
381	}
382#else
383	char *s, ifname[LIFNAMSIZ+1];
384
385	if (name == NULL)
386		name = "anon0";
387
388	addr = strchr(name, '=');
389	if (addr != NULL)
390		*addr++ = '\0';
391
392	for (ifpp = ifneta; ifpp && (ifp = *ifpp); ifpp++) {
393		COPYIFNAME(v, ifp, ifname);
394		if (!strcmp(name, ifname)) {
395			if (addr != NULL)
396				fr_setifpaddr(ifp, addr);
397			return ifp;
398		}
399	}
400#endif
401
402	if (!ifneta) {
403		ifneta = (struct ifnet **)malloc(sizeof(ifp) * 2);
404		if (!ifneta)
405			return NULL;
406		ifneta[1] = NULL;
407		ifneta[0] = (struct ifnet *)calloc(1, sizeof(*ifp));
408		if (!ifneta[0]) {
409			free(ifneta);
410			return NULL;
411		}
412		nifs = 1;
413	} else {
414		old_ifneta = ifneta;
415		nifs++;
416		ifneta = (struct ifnet **)realloc(ifneta,
417						  (nifs + 1) * sizeof(ifp));
418		if (!ifneta) {
419			free(old_ifneta);
420			nifs = 0;
421			return NULL;
422		}
423		ifneta[nifs] = NULL;
424		ifneta[nifs - 1] = (struct ifnet *)malloc(sizeof(*ifp));
425		if (!ifneta[nifs - 1]) {
426			nifs--;
427			return NULL;
428		}
429	}
430	ifp = ifneta[nifs - 1];
431
432#if defined(__NetBSD__) || defined(__OpenBSD__) || defined(__FreeBSD__)
433	TAILQ_INIT(&ifp->if_addrlist);
434#endif
435#if (defined(NetBSD) && (NetBSD <= 1991011) && (NetBSD >= 199606)) || \
436    (defined(OpenBSD) && (OpenBSD >= 199603)) || defined(linux) || \
437    (defined(__FreeBSD__) && (__FreeBSD_version >= 501113))
438	(void) strncpy(ifp->if_xname, name, sizeof(ifp->if_xname));
439#else
440	for (s = name; *s && !ISDIGIT(*s); s++)
441		;
442	if (*s && ISDIGIT(*s)) {
443		ifp->if_unit = atoi(s);
444		ifp->if_name = (char *)malloc(s - name + 1);
445		(void) strncpy(ifp->if_name, name, s - name);
446		ifp->if_name[s - name] = '\0';
447	} else {
448		ifp->if_name = strdup(name);
449		ifp->if_unit = -1;
450	}
451#endif
452	ifp->if_output = (void *)no_output;
453
454	if (addr != NULL) {
455		fr_setifpaddr(ifp, addr);
456	}
457
458	return ifp;
459}
460
461
462char *get_ifname(ifp)
463struct ifnet *ifp;
464{
465	static char ifname[LIFNAMSIZ];
466
467#if defined(__OpenBSD__) || defined(__NetBSD__) || defined(linux) || \
468    (defined(__FreeBSD__) && (__FreeBSD_version >= 501113))
469	sprintf(ifname, "%s", ifp->if_xname);
470#else
471	sprintf(ifname, "%s%d", ifp->if_name, ifp->if_unit);
472#endif
473	return ifname;
474}
475
476
477
478void init_ifp()
479{
480	struct ifnet *ifp, **ifpp;
481	char fname[32];
482	int fd;
483
484#if (defined(NetBSD) && (NetBSD <= 1991011) && (NetBSD >= 199606)) || \
485    (defined(OpenBSD) && (OpenBSD >= 199603)) || defined(linux) || \
486    (defined(__FreeBSD__) && (__FreeBSD_version >= 501113))
487	for (ifpp = ifneta; ifpp && (ifp = *ifpp); ifpp++) {
488		ifp->if_output = (void *)write_output;
489		sprintf(fname, "/tmp/%s", ifp->if_xname);
490		fd = open(fname, O_WRONLY|O_CREAT|O_EXCL|O_TRUNC, 0600);
491		if (fd == -1)
492			perror("open");
493		else
494			close(fd);
495	}
496#else
497
498	for (ifpp = ifneta; ifpp && (ifp = *ifpp); ifpp++) {
499		ifp->if_output = write_output;
500		sprintf(fname, "/tmp/%s%d", ifp->if_name, ifp->if_unit);
501		fd = open(fname, O_WRONLY|O_CREAT|O_EXCL|O_TRUNC, 0600);
502		if (fd == -1)
503			perror("open");
504		else
505			close(fd);
506	}
507#endif
508}
509
510
511int fr_fastroute(m, mpp, fin, fdp)
512mb_t *m, **mpp;
513fr_info_t *fin;
514frdest_t *fdp;
515{
516	struct ifnet *ifp = fdp->fd_ifp;
517	ip_t *ip = fin->fin_ip;
518	int error = 0;
519	frentry_t *fr;
520	void *sifp;
521
522	if (!ifp)
523		return 0;	/* no routing table out here */
524
525	fr = fin->fin_fr;
526	ip->ip_sum = 0;
527
528	if (fin->fin_out == 0) {
529		sifp = fin->fin_ifp;
530		fin->fin_ifp = ifp;
531		fin->fin_out = 1;
532		(void) fr_acctpkt(fin, NULL);
533		fin->fin_fr = NULL;
534		if (!fr || !(fr->fr_flags & FR_RETMASK)) {
535			u_32_t pass;
536
537			(void) fr_checkstate(fin, &pass);
538		}
539
540		switch (fr_checknatout(fin, NULL))
541		{
542		case 0 :
543			break;
544		case 1 :
545			ip->ip_sum = 0;
546			break;
547		case -1 :
548			error = -1;
549			goto done;
550			break;
551		}
552
553		fin->fin_ifp = sifp;
554		fin->fin_out = 0;
555	}
556
557#if defined(__sgi) && (IRIX < 60500)
558	(*ifp->if_output)(ifp, (void *)ip, NULL);
559# if TRU64 >= 1885
560	(*ifp->if_output)(ifp, (void *)m, NULL, 0, 0);
561# else
562	(*ifp->if_output)(ifp, (void *)m, NULL, 0);
563# endif
564#endif
565done:
566	return error;
567}
568
569
570int fr_send_reset(fin)
571fr_info_t *fin;
572{
573	verbose("- TCP RST sent\n");
574	return 0;
575}
576
577
578int fr_send_icmp_err(type, fin, dst)
579int type;
580fr_info_t *fin;
581int dst;
582{
583	verbose("- ICMP unreachable sent\n");
584	return 0;
585}
586
587
588void frsync(ifp)
589void *ifp;
590{
591	return;
592}
593
594
595void m_freem(m)
596mb_t *m;
597{
598	return;
599}
600
601
602void m_copydata(m, off, len, cp)
603mb_t *m;
604int off, len;
605caddr_t cp;
606{
607	bcopy((char *)m + off, cp, len);
608}
609
610
611int ipfuiomove(buf, len, rwflag, uio)
612caddr_t buf;
613int len, rwflag;
614struct uio *uio;
615{
616	int left, ioc, num, offset;
617	struct iovec *io;
618	char *start;
619
620	if (rwflag == UIO_READ) {
621		left = len;
622		ioc = 0;
623
624		offset = uio->uio_offset;
625
626		while ((left > 0) && (ioc < uio->uio_iovcnt)) {
627			io = uio->uio_iov + ioc;
628			num = io->iov_len;
629			if (num > left)
630				num = left;
631			start = (char *)io->iov_base + offset;
632			if (start > (char *)io->iov_base + io->iov_len) {
633				offset -= io->iov_len;
634				ioc++;
635				continue;
636			}
637			bcopy(buf, start, num);
638			uio->uio_resid -= num;
639			uio->uio_offset += num;
640			left -= num;
641			if (left > 0)
642				ioc++;
643		}
644		if (left > 0)
645			return EFAULT;
646	}
647	return 0;
648}
649
650
651u_32_t fr_newisn(fin)
652fr_info_t *fin;
653{
654	static int iss_seq_off = 0;
655	u_char hash[16];
656	u_32_t newiss;
657	MD5_CTX ctx;
658
659	/*
660	 * Compute the base value of the ISS.  It is a hash
661	 * of (saddr, sport, daddr, dport, secret).
662	 */
663	MD5Init(&ctx);
664
665	MD5Update(&ctx, (u_char *) &fin->fin_fi.fi_src,
666		  sizeof(fin->fin_fi.fi_src));
667	MD5Update(&ctx, (u_char *) &fin->fin_fi.fi_dst,
668		  sizeof(fin->fin_fi.fi_dst));
669	MD5Update(&ctx, (u_char *) &fin->fin_dat, sizeof(fin->fin_dat));
670
671	/* MD5Update(&ctx, ipf_iss_secret, sizeof(ipf_iss_secret)); */
672
673	MD5Final(hash, &ctx);
674
675	memcpy(&newiss, hash, sizeof(newiss));
676
677	/*
678	 * Now increment our "timer", and add it in to
679	 * the computed value.
680	 *
681	 * XXX Use `addin'?
682	 * XXX TCP_ISSINCR too large to use?
683	 */
684	iss_seq_off += 0x00010000;
685	newiss += iss_seq_off;
686	return newiss;
687}
688
689
690/* ------------------------------------------------------------------------ */
691/* Function:    fr_nextipid                                                 */
692/* Returns:     int - 0 == success, -1 == error (packet should be droppped) */
693/* Parameters:  fin(I) - pointer to packet information                      */
694/*                                                                          */
695/* Returns the next IPv4 ID to use for this packet.                         */
696/* ------------------------------------------------------------------------ */
697INLINE u_short fr_nextipid(fin)
698fr_info_t *fin;
699{
700	static u_short ipid = 0;
701	u_short id;
702
703	MUTEX_ENTER(&ipf_rw);
704	id = ipid++;
705	MUTEX_EXIT(&ipf_rw);
706
707	return id;
708}
709
710
711INLINE void fr_checkv4sum(fin)
712fr_info_t *fin;
713{
714	if (fr_checkl4sum(fin) == -1)
715		fin->fin_flx |= FI_BAD;
716}
717
718
719#ifdef	USE_INET6
720INLINE void fr_checkv6sum(fin)
721fr_info_t *fin;
722{
723	if (fr_checkl4sum(fin) == -1)
724		fin->fin_flx |= FI_BAD;
725}
726#endif
727
728
729/*
730 * See above for description, except that all addressing is in user space.
731 */
732int copyoutptr(src, dst, size)
733void *src, *dst;
734size_t size;
735{
736	caddr_t ca;
737
738	bcopy(dst, (char *)&ca, sizeof(ca));
739	bcopy(src, ca, size);
740	return 0;
741}
742
743
744/*
745 * See above for description, except that all addressing is in user space.
746 */
747int copyinptr(src, dst, size)
748void *src, *dst;
749size_t size;
750{
751	caddr_t ca;
752
753	bcopy(src, (char *)&ca, sizeof(ca));
754	bcopy(ca, dst, size);
755	return 0;
756}
757
758
759/*
760 * return the first IP Address associated with an interface
761 */
762int fr_ifpaddr(v, atype, ifptr, inp, inpmask)
763int v, atype;
764void *ifptr;
765struct in_addr *inp, *inpmask;
766{
767	struct ifnet *ifp = ifptr;
768#ifdef __sgi
769	struct in_ifaddr *ifa;
770#else
771	struct ifaddr *ifa;
772#endif
773
774#if defined(__NetBSD__) || defined(__OpenBSD__) || defined(__FreeBSD__)
775	ifa = ifp->if_addrlist.tqh_first;
776#else
777# ifdef __sgi
778	ifa = (struct in_ifaddr *)ifp->in_ifaddr;
779# else
780	ifa = ifp->if_addrlist;
781# endif
782#endif
783	if (ifa != NULL) {
784		struct sockaddr_in *sin, mask;
785
786		mask.sin_addr.s_addr = 0xffffffff;
787
788#ifdef __sgi
789		sin = (struct sockaddr_in *)&ifa->ia_addr;
790#else
791		sin = (struct sockaddr_in *)&ifa->ifa_addr;
792#endif
793
794		return fr_ifpfillv4addr(atype, sin, &mask, inp, inpmask);
795	}
796	return 0;
797}
798
799
800int ipfsync()
801{
802	return 0;
803}
804
805
806u_32_t ipf_random()
807{
808	static int seeded = 0;
809
810	/*
811	 * Choose a non-random seed so that "randomness" can be "tested."
812	 */
813	if (seeded == 0) {
814		srand(0);
815		seeded = 1;
816	}
817	return rand();
818}
819