1/*	$FreeBSD$	*/
2
3/*
4 * Copyright (C) 2001-2006 by Darren Reed.
5 *
6 * See the IPFILTER.LICENCE file for details on licencing.
7 */
8#ifdef	__FreeBSD__
9# ifndef __FreeBSD_cc_version
10#  include <osreldate.h>
11# else
12#  if __FreeBSD_cc_version < 430000
13#   include <osreldate.h>
14#  endif
15# endif
16#endif
17#include <stdio.h>
18#include <unistd.h>
19#include <string.h>
20#include <fcntl.h>
21#include <errno.h>
22#if !defined(__SVR4) && !defined(__GNUC__)
23#include <strings.h>
24#endif
25#include <sys/types.h>
26#include <sys/param.h>
27#include <sys/file.h>
28#include <stdlib.h>
29#include <stddef.h>
30#include <sys/socket.h>
31#include <sys/ioctl.h>
32#include <netinet/in.h>
33#include <netinet/in_systm.h>
34#include <sys/time.h>
35#include <net/if.h>
36#if __FreeBSD_version >= 300000
37# include <net/if_var.h>
38#endif
39#include <netinet/ip.h>
40#include <netdb.h>
41#include <arpa/nameser.h>
42#include <resolv.h>
43#include "ipf.h"
44#include "netinet/ipl.h"
45
46#if !defined(lint)
47static const char rcsid[] = "@(#)Id: ipfs.c,v 1.12 2003/12/01 01:56:53 darrenr Exp";
48#endif
49
50#ifndef	IPF_SAVEDIR
51# define	IPF_SAVEDIR	"/var/db/ipf"
52#endif
53#ifndef IPF_NATFILE
54# define	IPF_NATFILE	"ipnat.ipf"
55#endif
56#ifndef IPF_STATEFILE
57# define	IPF_STATEFILE	"ipstate.ipf"
58#endif
59
60#if !defined(__SVR4) && defined(__GNUC__)
61extern	char	*index __P((const char *, int));
62#endif
63
64extern	char	*optarg;
65extern	int	optind;
66
67int	main __P((int, char *[]));
68void	usage __P((void));
69int	changestateif __P((char *, char *));
70int	changenatif __P((char *, char *));
71int	readstate __P((int, char *));
72int	readnat __P((int, char *));
73int	writestate __P((int, char *));
74int	opendevice __P((char *));
75void	closedevice __P((int));
76int	setlock __P((int, int));
77int	writeall __P((char *));
78int	readall __P((char *));
79int	writenat __P((int, char *));
80
81int	opts = 0;
82char	*progname;
83
84
85void usage()
86{
87	fprintf(stderr, "usage: %s [-nv] -l\n", progname);
88	fprintf(stderr, "usage: %s [-nv] -u\n", progname);
89	fprintf(stderr, "usage: %s [-nv] [-d <dir>] -R\n", progname);
90	fprintf(stderr, "usage: %s [-nv] [-d <dir>] -W\n", progname);
91	fprintf(stderr, "usage: %s [-nNSv] [-f <file>] -r\n", progname);
92	fprintf(stderr, "usage: %s [-nNSv] [-f <file>] -w\n", progname);
93	fprintf(stderr, "usage: %s [-nNSv] -f <filename> -i <if1>,<if2>\n",
94		progname);
95	exit(1);
96}
97
98
99/*
100 * Change interface names in state information saved out to disk.
101 */
102int changestateif(ifs, fname)
103char *ifs, *fname;
104{
105	int fd, olen, nlen, rw;
106	ipstate_save_t ips;
107	off_t pos;
108	char *s;
109
110	s = strchr(ifs, ',');
111	if (!s)
112		usage();
113	*s++ = '\0';
114	nlen = strlen(s);
115	olen = strlen(ifs);
116	if (nlen >= sizeof(ips.ips_is.is_ifname) ||
117	    olen >= sizeof(ips.ips_is.is_ifname))
118		usage();
119
120	fd = open(fname, O_RDWR);
121	if (fd == -1) {
122		perror("open");
123		exit(1);
124	}
125
126	for (pos = 0; read(fd, &ips, sizeof(ips)) == sizeof(ips); ) {
127		rw = 0;
128		if (!strncmp(ips.ips_is.is_ifname[0], ifs, olen + 1)) {
129			strcpy(ips.ips_is.is_ifname[0], s);
130			rw = 1;
131		}
132		if (!strncmp(ips.ips_is.is_ifname[1], ifs, olen + 1)) {
133			strcpy(ips.ips_is.is_ifname[1], s);
134			rw = 1;
135		}
136		if (!strncmp(ips.ips_is.is_ifname[2], ifs, olen + 1)) {
137			strcpy(ips.ips_is.is_ifname[2], s);
138			rw = 1;
139		}
140		if (!strncmp(ips.ips_is.is_ifname[3], ifs, olen + 1)) {
141			strcpy(ips.ips_is.is_ifname[3], s);
142			rw = 1;
143		}
144		if (rw == 1) {
145			if (lseek(fd, pos, SEEK_SET) != pos) {
146				perror("lseek");
147				exit(1);
148			}
149			if (write(fd, &ips, sizeof(ips)) != sizeof(ips)) {
150				perror("write");
151				exit(1);
152			}
153		}
154		pos = lseek(fd, 0, SEEK_CUR);
155	}
156	close(fd);
157
158	return 0;
159}
160
161
162/*
163 * Change interface names in NAT information saved out to disk.
164 */
165int changenatif(ifs, fname)
166char *ifs, *fname;
167{
168	int fd, olen, nlen, rw;
169	nat_save_t ipn;
170	nat_t *nat;
171	off_t pos;
172	char *s;
173
174	s = strchr(ifs, ',');
175	if (!s)
176		usage();
177	*s++ = '\0';
178	nlen = strlen(s);
179	olen = strlen(ifs);
180	nat = &ipn.ipn_nat;
181	if (nlen >= sizeof(nat->nat_ifnames[0]) ||
182	    olen >= sizeof(nat->nat_ifnames[0]))
183		usage();
184
185	fd = open(fname, O_RDWR);
186	if (fd == -1) {
187		perror("open");
188		exit(1);
189	}
190
191	for (pos = 0; read(fd, &ipn, sizeof(ipn)) == sizeof(ipn); ) {
192		rw = 0;
193		if (!strncmp(nat->nat_ifnames[0], ifs, olen + 1)) {
194			strcpy(nat->nat_ifnames[0], s);
195			rw = 1;
196		}
197		if (!strncmp(nat->nat_ifnames[1], ifs, olen + 1)) {
198			strcpy(nat->nat_ifnames[1], s);
199			rw = 1;
200		}
201		if (!strncmp(nat->nat_ifnames[2], ifs, olen + 1)) {
202			strcpy(nat->nat_ifnames[2], s);
203			rw = 1;
204		}
205		if (!strncmp(nat->nat_ifnames[3], ifs, olen + 1)) {
206			strcpy(nat->nat_ifnames[3], s);
207			rw = 1;
208		}
209		if (rw == 1) {
210			if (lseek(fd, pos, SEEK_SET) != pos) {
211				perror("lseek");
212				exit(1);
213			}
214			if (write(fd, &ipn, sizeof(ipn)) != sizeof(ipn)) {
215				perror("write");
216				exit(1);
217			}
218		}
219		pos = lseek(fd, 0, SEEK_CUR);
220	}
221	close(fd);
222
223	return 0;
224}
225
226
227int main(argc,argv)
228int argc;
229char *argv[];
230{
231	int c, lock = -1, devfd = -1, err = 0, rw = -1, ns = -1, set = 0;
232	char *dirname = NULL, *filename = NULL, *ifs = NULL;
233
234	progname = argv[0];
235	while ((c = getopt(argc, argv, "d:f:i:lNnSRruvWw")) != -1)
236		switch (c)
237		{
238		case 'd' :
239			if ((set == 0) && !dirname && !filename)
240				dirname = optarg;
241			else
242				usage();
243			break;
244		case 'f' :
245			if ((set != 0) && !dirname && !filename)
246				filename = optarg;
247			else
248				usage();
249			break;
250		case 'i' :
251			ifs = optarg;
252			set = 1;
253			break;
254		case 'l' :
255			if (filename || dirname || set)
256				usage();
257			lock = 1;
258			set = 1;
259			break;
260		case 'n' :
261			opts |= OPT_DONOTHING;
262			break;
263		case 'N' :
264			if ((ns >= 0) || dirname || (rw != -1) || set)
265				usage();
266			ns = 0;
267			set = 1;
268			break;
269		case 'r' :
270			if (dirname || (rw != -1) || (ns == -1))
271				usage();
272			rw = 0;
273			set = 1;
274			break;
275		case 'R' :
276			rw = 2;
277			set = 1;
278			break;
279		case 'S' :
280			if ((ns >= 0) || dirname || (rw != -1) || set)
281				usage();
282			ns = 1;
283			set = 1;
284			break;
285		case 'u' :
286			if (filename || dirname || set)
287				usage();
288			lock = 0;
289			set = 1;
290			break;
291		case 'v' :
292			opts |= OPT_VERBOSE;
293			break;
294		case 'w' :
295			if (dirname || (rw != -1) || (ns == -1))
296				usage();
297			rw = 1;
298			set = 1;
299			break;
300		case 'W' :
301			rw = 3;
302			set = 1;
303			break;
304		case '?' :
305		default :
306			usage();
307		}
308
309	if (ifs) {
310		if (!filename || ns < 0)
311			usage();
312		if (ns == 0)
313			return changenatif(ifs, filename);
314		else
315			return changestateif(ifs, filename);
316	}
317
318	if ((ns >= 0) || (lock >= 0)) {
319		if (lock >= 0)
320			devfd = opendevice(NULL);
321		else if (ns >= 0) {
322			if (ns == 1)
323				devfd = opendevice(IPSTATE_NAME);
324			else if (ns == 0)
325				devfd = opendevice(IPNAT_NAME);
326		}
327		if (devfd == -1)
328			exit(1);
329	}
330
331	if (lock >= 0)
332		err = setlock(devfd, lock);
333	else if (rw >= 0) {
334		if (rw & 1) {	/* WRITE */
335			if (rw & 2)
336				err = writeall(dirname);
337			else {
338				if (ns == 0)
339					err = writenat(devfd, filename);
340				else if (ns == 1)
341					err = writestate(devfd, filename);
342			}
343		} else {
344			if (rw & 2)
345				err = readall(dirname);
346			else {
347				if (ns == 0)
348					err = readnat(devfd, filename);
349				else if (ns == 1)
350					err = readstate(devfd, filename);
351			}
352		}
353	}
354	return err;
355}
356
357
358int opendevice(ipfdev)
359char *ipfdev;
360{
361	int fd = -1;
362
363	if (opts & OPT_DONOTHING)
364		return -2;
365
366	if (!ipfdev)
367		ipfdev = IPL_NAME;
368
369	if ((fd = open(ipfdev, O_RDWR)) == -1)
370		if ((fd = open(ipfdev, O_RDONLY)) == -1)
371			perror("open device");
372	return fd;
373}
374
375
376void closedevice(fd)
377int fd;
378{
379	close(fd);
380}
381
382
383int setlock(fd, lock)
384int fd, lock;
385{
386	if (opts & OPT_VERBOSE)
387		printf("Turn lock %s\n", lock ? "on" : "off");
388	if (!(opts & OPT_DONOTHING)) {
389		if (ioctl(fd, SIOCSTLCK, &lock) == -1) {
390			perror("SIOCSTLCK");
391			return 1;
392		}
393		if (opts & OPT_VERBOSE)
394			printf("Lock now %s\n", lock ? "on" : "off");
395	}
396	return 0;
397}
398
399
400int writestate(fd, file)
401int fd;
402char *file;
403{
404	ipstate_save_t ips, *ipsp;
405	ipfobj_t obj;
406	int wfd = -1;
407
408	if (!file)
409		file = IPF_STATEFILE;
410
411	wfd = open(file, O_WRONLY|O_TRUNC|O_CREAT, 0600);
412	if (wfd == -1) {
413		fprintf(stderr, "%s ", file);
414		perror("state:open");
415		return 1;
416	}
417
418	ipsp = &ips;
419	bzero((char *)&obj, sizeof(obj));
420	bzero((char *)ipsp, sizeof(ips));
421
422	obj.ipfo_rev = IPFILTER_VERSION;
423	obj.ipfo_size = sizeof(*ipsp);
424	obj.ipfo_type = IPFOBJ_STATESAVE;
425	obj.ipfo_ptr = ipsp;
426
427	do {
428
429		if (opts & OPT_VERBOSE)
430			printf("Getting state from addr %p\n", ips.ips_next);
431		if (ioctl(fd, SIOCSTGET, &obj)) {
432			if (errno == ENOENT)
433				break;
434			perror("state:SIOCSTGET");
435			close(wfd);
436			return 1;
437		}
438		if (opts & OPT_VERBOSE)
439			printf("Got state next %p\n", ips.ips_next);
440		if (write(wfd, ipsp, sizeof(ips)) != sizeof(ips)) {
441			perror("state:write");
442			close(wfd);
443			return 1;
444		}
445	} while (ips.ips_next != NULL);
446	close(wfd);
447
448	return 0;
449}
450
451
452int readstate(fd, file)
453int fd;
454char *file;
455{
456	ipstate_save_t ips, *is, *ipshead = NULL, *is1, *ipstail = NULL;
457	int sfd = -1, i;
458	ipfobj_t obj;
459
460	if (!file)
461		file = IPF_STATEFILE;
462
463	sfd = open(file, O_RDONLY, 0600);
464	if (sfd == -1) {
465		fprintf(stderr, "%s ", file);
466		perror("open");
467		return 1;
468	}
469
470	bzero((char *)&ips, sizeof(ips));
471
472	/*
473	 * 1. Read all state information in.
474	 */
475	do {
476		i = read(sfd, &ips, sizeof(ips));
477		if (i == -1) {
478			perror("read");
479			goto freeipshead;
480		}
481		if (i == 0)
482			break;
483		if (i != sizeof(ips)) {
484			fprintf(stderr, "state:incomplete read: %d != %d\n",
485				i, (int)sizeof(ips));
486			goto freeipshead;
487		}
488		is = (ipstate_save_t *)malloc(sizeof(*is));
489		if (is == NULL) {
490			fprintf(stderr, "malloc failed\n");
491			goto freeipshead;
492		}
493
494		bcopy((char *)&ips, (char *)is, sizeof(ips));
495
496		/*
497		 * Check to see if this is the first state entry that will
498		 * reference a particular rule and if so, flag it as such
499		 * else just adjust the rule pointer to become a pointer to
500		 * the other.  We do this so we have a means later for tracking
501		 * who is referencing us when we get back the real pointer
502		 * in is_rule after doing the ioctl.
503		 */
504		for (is1 = ipshead; is1 != NULL; is1 = is1->ips_next)
505			if (is1->ips_rule == is->ips_rule)
506				break;
507		if (is1 == NULL)
508			is->ips_is.is_flags |= SI_NEWFR;
509		else
510			is->ips_rule = (void *)&is1->ips_rule;
511
512		/*
513		 * Use a tail-queue type list (add things to the end)..
514		 */
515		is->ips_next = NULL;
516		if (!ipshead)
517			ipshead = is;
518		if (ipstail)
519			ipstail->ips_next = is;
520		ipstail = is;
521	} while (1);
522
523	close(sfd);
524
525	obj.ipfo_rev = IPFILTER_VERSION;
526	obj.ipfo_size = sizeof(*is);
527	obj.ipfo_type = IPFOBJ_STATESAVE;
528
529	while ((is = ipshead) != NULL) {
530		if (opts & OPT_VERBOSE)
531			printf("Loading new state table entry\n");
532		if (is->ips_is.is_flags & SI_NEWFR) {
533			if (opts & OPT_VERBOSE)
534				printf("Loading new filter rule\n");
535		}
536
537		obj.ipfo_ptr = is;
538		if (!(opts & OPT_DONOTHING))
539			if (ioctl(fd, SIOCSTPUT, &obj)) {
540				perror("SIOCSTPUT");
541				goto freeipshead;
542			}
543
544		if (is->ips_is.is_flags & SI_NEWFR) {
545			if (opts & OPT_VERBOSE)
546				printf("Real rule addr %p\n", is->ips_rule);
547			for (is1 = is->ips_next; is1; is1 = is1->ips_next)
548				if (is1->ips_rule == (frentry_t *)&is->ips_rule)
549					is1->ips_rule = is->ips_rule;
550		}
551
552		ipshead = is->ips_next;
553		free(is);
554	}
555
556	return 0;
557
558freeipshead:
559	while ((is = ipshead) != NULL) {
560		ipshead = is->ips_next;
561		free(is);
562	}
563	if (sfd != -1)
564		close(sfd);
565	return 1;
566}
567
568
569int readnat(fd, file)
570int fd;
571char *file;
572{
573	nat_save_t ipn, *in, *ipnhead = NULL, *in1, *ipntail = NULL;
574	ipfobj_t obj;
575	int nfd, i;
576	nat_t *nat;
577	char *s;
578	int n;
579
580	nfd = -1;
581	in = NULL;
582	ipnhead = NULL;
583	ipntail = NULL;
584
585	if (!file)
586		file = IPF_NATFILE;
587
588	nfd = open(file, O_RDONLY);
589	if (nfd == -1) {
590		fprintf(stderr, "%s ", file);
591		perror("nat:open");
592		return 1;
593	}
594
595	bzero((char *)&ipn, sizeof(ipn));
596
597	/*
598	 * 1. Read all state information in.
599	 */
600	do {
601		i = read(nfd, &ipn, sizeof(ipn));
602		if (i == -1) {
603			perror("read");
604			goto freenathead;
605		}
606		if (i == 0)
607			break;
608		if (i != sizeof(ipn)) {
609			fprintf(stderr, "nat:incomplete read: %d != %d\n",
610				i, (int)sizeof(ipn));
611			goto freenathead;
612		}
613
614		in = (nat_save_t *)malloc(ipn.ipn_dsize);
615		if (in == NULL) {
616			fprintf(stderr, "nat:cannot malloc nat save atruct\n");
617			goto freenathead;
618		}
619
620		if (ipn.ipn_dsize > sizeof(ipn)) {
621			n = ipn.ipn_dsize - sizeof(ipn);
622			if (n > 0) {
623				s = in->ipn_data + sizeof(in->ipn_data);
624 				i = read(nfd, s, n);
625				if (i == 0)
626					break;
627				if (i != n) {
628					fprintf(stderr,
629					    "nat:incomplete read: %d != %d\n",
630					    i, n);
631					goto freenathead;
632				}
633			}
634		}
635		bcopy((char *)&ipn, (char *)in, sizeof(ipn));
636
637		/*
638		 * Check to see if this is the first NAT entry that will
639		 * reference a particular rule and if so, flag it as such
640		 * else just adjust the rule pointer to become a pointer to
641		 * the other.  We do this so we have a means later for tracking
642		 * who is referencing us when we get back the real pointer
643		 * in is_rule after doing the ioctl.
644		 */
645		nat = &in->ipn_nat;
646		if (nat->nat_fr != NULL) {
647			for (in1 = ipnhead; in1 != NULL; in1 = in1->ipn_next)
648				if (in1->ipn_rule == nat->nat_fr)
649					break;
650			if (in1 == NULL)
651				nat->nat_flags |= SI_NEWFR;
652			else
653				nat->nat_fr = &in1->ipn_fr;
654		}
655
656		/*
657		 * Use a tail-queue type list (add things to the end)..
658		 */
659		in->ipn_next = NULL;
660		if (!ipnhead)
661			ipnhead = in;
662		if (ipntail)
663			ipntail->ipn_next = in;
664		ipntail = in;
665	} while (1);
666
667	close(nfd);
668	nfd = -1;
669
670	obj.ipfo_rev = IPFILTER_VERSION;
671	obj.ipfo_type = IPFOBJ_NATSAVE;
672
673	while ((in = ipnhead) != NULL) {
674		if (opts & OPT_VERBOSE)
675			printf("Loading new NAT table entry\n");
676		nat = &in->ipn_nat;
677		if (nat->nat_flags & SI_NEWFR) {
678			if (opts & OPT_VERBOSE)
679				printf("Loading new filter rule\n");
680		}
681
682		obj.ipfo_ptr = in;
683		obj.ipfo_size = in->ipn_dsize;
684		if (!(opts & OPT_DONOTHING))
685			if (ioctl(fd, SIOCSTPUT, &obj)) {
686				fprintf(stderr, "in=%p:", in);
687				perror("SIOCSTPUT");
688				return 1;
689			}
690
691		if (nat->nat_flags & SI_NEWFR) {
692			if (opts & OPT_VERBOSE)
693				printf("Real rule addr %p\n", nat->nat_fr);
694			for (in1 = in->ipn_next; in1; in1 = in1->ipn_next)
695				if (in1->ipn_rule == &in->ipn_fr)
696					in1->ipn_rule = nat->nat_fr;
697		}
698
699		ipnhead = in->ipn_next;
700		free(in);
701	}
702
703	return 0;
704
705freenathead:
706	while ((in = ipnhead) != NULL) {
707		ipnhead = in->ipn_next;
708		free(in);
709	}
710	if (nfd != -1)
711		close(nfd);
712	return 1;
713}
714
715
716int writenat(fd, file)
717int fd;
718char *file;
719{
720	nat_save_t *ipnp = NULL, *next = NULL;
721	ipfobj_t obj;
722	int nfd = -1;
723	natget_t ng;
724
725	if (!file)
726		file = IPF_NATFILE;
727
728	nfd = open(file, O_WRONLY|O_TRUNC|O_CREAT, 0600);
729	if (nfd == -1) {
730		fprintf(stderr, "%s ", file);
731		perror("nat:open");
732		return 1;
733	}
734
735	obj.ipfo_rev = IPFILTER_VERSION;
736	obj.ipfo_type = IPFOBJ_NATSAVE;
737
738	do {
739		if (opts & OPT_VERBOSE)
740			printf("Getting nat from addr %p\n", ipnp);
741		ng.ng_ptr = next;
742		ng.ng_sz = 0;
743		if (ioctl(fd, SIOCSTGSZ, &ng)) {
744			perror("nat:SIOCSTGSZ");
745			close(nfd);
746			if (ipnp != NULL)
747				free(ipnp);
748			return 1;
749		}
750
751		if (opts & OPT_VERBOSE)
752			printf("NAT size %d from %p\n", ng.ng_sz, ng.ng_ptr);
753
754		if (ng.ng_sz == 0)
755			break;
756
757		if (!ipnp)
758			ipnp = malloc(ng.ng_sz);
759		else
760			ipnp = realloc((char *)ipnp, ng.ng_sz);
761		if (!ipnp) {
762			fprintf(stderr,
763				"malloc for %d bytes failed\n", ng.ng_sz);
764			break;
765		}
766
767		bzero((char *)ipnp, ng.ng_sz);
768		obj.ipfo_size = ng.ng_sz;
769		obj.ipfo_ptr = ipnp;
770		ipnp->ipn_dsize = ng.ng_sz;
771		ipnp->ipn_next = next;
772		if (ioctl(fd, SIOCSTGET, &obj)) {
773			if (errno == ENOENT)
774				break;
775			perror("nat:SIOCSTGET");
776			close(nfd);
777			free(ipnp);
778			return 1;
779		}
780
781		if (opts & OPT_VERBOSE)
782			printf("Got nat next %p ipn_dsize %d ng_sz %d\n",
783				ipnp->ipn_next, ipnp->ipn_dsize, ng.ng_sz);
784		if (write(nfd, ipnp, ipnp->ipn_dsize) != ipnp->ipn_dsize) {
785			perror("nat:write");
786			close(nfd);
787			free(ipnp);
788			return 1;
789		}
790		next = ipnp->ipn_next;
791	} while (ipnp && next);
792	if (ipnp != NULL)
793		free(ipnp);
794	close(nfd);
795
796	return 0;
797}
798
799
800int writeall(dirname)
801char *dirname;
802{
803	int fd, devfd;
804
805	if (!dirname)
806		dirname = IPF_SAVEDIR;
807
808	if (chdir(dirname)) {
809		fprintf(stderr, "IPF_SAVEDIR=%s: ", dirname);
810		perror("chdir(IPF_SAVEDIR)");
811		return 1;
812	}
813
814	fd = opendevice(NULL);
815	if (fd == -1)
816		return 1;
817	if (setlock(fd, 1)) {
818		close(fd);
819		return 1;
820	}
821
822	devfd = opendevice(IPSTATE_NAME);
823	if (devfd == -1)
824		goto bad;
825	if (writestate(devfd, NULL))
826		goto bad;
827	close(devfd);
828
829	devfd = opendevice(IPNAT_NAME);
830	if (devfd == -1)
831		goto bad;
832	if (writenat(devfd, NULL))
833		goto bad;
834	close(devfd);
835
836	if (setlock(fd, 0)) {
837		close(fd);
838		return 1;
839	}
840
841	close(fd);
842	return 0;
843
844bad:
845	setlock(fd, 0);
846	close(fd);
847	return 1;
848}
849
850
851int readall(dirname)
852char *dirname;
853{
854	int fd, devfd;
855
856	if (!dirname)
857		dirname = IPF_SAVEDIR;
858
859	if (chdir(dirname)) {
860		perror("chdir(IPF_SAVEDIR)");
861		return 1;
862	}
863
864	fd = opendevice(NULL);
865	if (fd == -1)
866		return 1;
867	if (setlock(fd, 1)) {
868		close(fd);
869		return 1;
870	}
871
872	devfd = opendevice(IPSTATE_NAME);
873	if (devfd == -1)
874		return 1;
875	if (readstate(devfd, NULL))
876		return 1;
877	close(devfd);
878
879	devfd = opendevice(IPNAT_NAME);
880	if (devfd == -1)
881		return 1;
882	if (readnat(devfd, NULL))
883		return 1;
884	close(devfd);
885
886	if (setlock(fd, 0)) {
887		close(fd);
888		return 1;
889	}
890
891	return 0;
892}
893