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