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