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