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