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