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