Home | History | Annotate | Line # | Download | only in tools
ipfs.c revision 1.1
      1 /*	$NetBSD: ipfs.c,v 1.1 2012/03/23 21:20:23 christos Exp $	*/
      2 
      3 /*
      4  * Copyright (C) 2008 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)
     47 static 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__)
     61 extern	char	*index __P((const char *, int));
     62 #endif
     63 
     64 extern	char	*optarg;
     65 extern	int	optind;
     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 
     81 int	opts = 0;
     82 char	*progname;
     83 
     84 
     85 void 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  */
    102 int 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  */
    165 int 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 
    219 int 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 
    350 int 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 
    368 void closedevice(fd)
    369 	int fd;
    370 {
    371 	close(fd);
    372 }
    373 
    374 
    375 int 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 
    392 int 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 
    444 int 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 
    550 freeipshead:
    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 
    561 int 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 
    697 freenathead:
    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 
    708 int 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 
    792 int 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 
    836 bad:
    837 	setlock(fd, 0);
    838 	close(fd);
    839 	return 1;
    840 }
    841 
    842 
    843 int 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