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