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