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