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