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