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