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)
47static 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__)
61extern	char	*index __P((const char *, int));
62#endif
63
64extern	char	*optarg;
65extern	int	optind;
66
67int	main __P((int, char *[]));
68void	usage __P((void));
69int	changestateif __P((char *, char *));
70int	changenatif __P((char *, char *));
71int	readstate __P((int, char *));
72int	readnat __P((int, char *));
73int	writestate __P((int, char *));
74int	opendevice __P((char *));
75void	closedevice __P((int));
76int	setlock __P((int, int));
77int	writeall __P((char *));
78int	readall __P((char *));
79int	writenat __P((int, char *));
80
81int	opts = 0;
82char	*progname;
83
84
85void 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 */
102int 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 */
165int 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
219int 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
350int 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
368void closedevice(fd)
369	int fd;
370{
371	close(fd);
372}
373
374
375int 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
392int 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
444int 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
550freeipshead:
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
561int 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
697freenathead:
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
708int 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
792int 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
836bad:
837	setlock(fd, 0);
838	close(fd);
839	return 1;
840}
841
842
843int 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}
885