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