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