]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/ipfilter/tools/ipfs.c
Merge lld trunk r351319, resolve conflicts, and update FREEBSD-Xlist.
[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 #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 }