1145519Sdarrenr/*	$FreeBSD$	*/
2145510Sdarrenr
3145510Sdarrenr/*
4170268Sdarrenr * Copyright (C) 2001-2006 by Darren Reed.
5145510Sdarrenr *
6145510Sdarrenr * See the IPFILTER.LICENCE file for details on licencing.
7145510Sdarrenr */
8145510Sdarrenr#ifdef	__FreeBSD__
9145510Sdarrenr# ifndef __FreeBSD_cc_version
10145510Sdarrenr#  include <osreldate.h>
11145510Sdarrenr# else
12145510Sdarrenr#  if __FreeBSD_cc_version < 430000
13145510Sdarrenr#   include <osreldate.h>
14145510Sdarrenr#  endif
15145510Sdarrenr# endif
16145510Sdarrenr#endif
17145510Sdarrenr#include <stdio.h>
18145510Sdarrenr#include <unistd.h>
19145510Sdarrenr#include <string.h>
20145510Sdarrenr#include <fcntl.h>
21145510Sdarrenr#include <errno.h>
22145510Sdarrenr#if !defined(__SVR4) && !defined(__GNUC__)
23145510Sdarrenr#include <strings.h>
24145510Sdarrenr#endif
25145510Sdarrenr#include <sys/types.h>
26145510Sdarrenr#include <sys/param.h>
27145510Sdarrenr#include <sys/file.h>
28145510Sdarrenr#include <stdlib.h>
29145510Sdarrenr#include <stddef.h>
30145510Sdarrenr#include <sys/socket.h>
31145510Sdarrenr#include <sys/ioctl.h>
32145510Sdarrenr#include <netinet/in.h>
33145510Sdarrenr#include <netinet/in_systm.h>
34145510Sdarrenr#include <sys/time.h>
35145510Sdarrenr#include <net/if.h>
36145510Sdarrenr#if __FreeBSD_version >= 300000
37145510Sdarrenr# include <net/if_var.h>
38145510Sdarrenr#endif
39145510Sdarrenr#include <netinet/ip.h>
40145510Sdarrenr#include <netdb.h>
41145510Sdarrenr#include <arpa/nameser.h>
42145510Sdarrenr#include <resolv.h>
43145510Sdarrenr#include "ipf.h"
44145554Sdarrenr#include "netinet/ipl.h"
45145510Sdarrenr
46145510Sdarrenr#if !defined(lint)
47145510Sdarrenrstatic const char rcsid[] = "@(#)Id: ipfs.c,v 1.12 2003/12/01 01:56:53 darrenr Exp";
48145510Sdarrenr#endif
49145510Sdarrenr
50145510Sdarrenr#ifndef	IPF_SAVEDIR
51145510Sdarrenr# define	IPF_SAVEDIR	"/var/db/ipf"
52145510Sdarrenr#endif
53145510Sdarrenr#ifndef IPF_NATFILE
54145510Sdarrenr# define	IPF_NATFILE	"ipnat.ipf"
55145510Sdarrenr#endif
56145510Sdarrenr#ifndef IPF_STATEFILE
57145510Sdarrenr# define	IPF_STATEFILE	"ipstate.ipf"
58145510Sdarrenr#endif
59145510Sdarrenr
60145510Sdarrenr#if !defined(__SVR4) && defined(__GNUC__)
61145510Sdarrenrextern	char	*index __P((const char *, int));
62145510Sdarrenr#endif
63145510Sdarrenr
64145510Sdarrenrextern	char	*optarg;
65145510Sdarrenrextern	int	optind;
66145510Sdarrenr
67145510Sdarrenrint	main __P((int, char *[]));
68145510Sdarrenrvoid	usage __P((void));
69145510Sdarrenrint	changestateif __P((char *, char *));
70145510Sdarrenrint	changenatif __P((char *, char *));
71145510Sdarrenrint	readstate __P((int, char *));
72145510Sdarrenrint	readnat __P((int, char *));
73145510Sdarrenrint	writestate __P((int, char *));
74145510Sdarrenrint	opendevice __P((char *));
75145510Sdarrenrvoid	closedevice __P((int));
76145510Sdarrenrint	setlock __P((int, int));
77145510Sdarrenrint	writeall __P((char *));
78145510Sdarrenrint	readall __P((char *));
79145510Sdarrenrint	writenat __P((int, char *));
80145510Sdarrenr
81145510Sdarrenrint	opts = 0;
82145510Sdarrenrchar	*progname;
83145510Sdarrenr
84145510Sdarrenr
85145510Sdarrenrvoid usage()
86145510Sdarrenr{
87145510Sdarrenr	fprintf(stderr, "usage: %s [-nv] -l\n", progname);
88145510Sdarrenr	fprintf(stderr, "usage: %s [-nv] -u\n", progname);
89145510Sdarrenr	fprintf(stderr, "usage: %s [-nv] [-d <dir>] -R\n", progname);
90145510Sdarrenr	fprintf(stderr, "usage: %s [-nv] [-d <dir>] -W\n", progname);
91145510Sdarrenr	fprintf(stderr, "usage: %s [-nNSv] [-f <file>] -r\n", progname);
92145510Sdarrenr	fprintf(stderr, "usage: %s [-nNSv] [-f <file>] -w\n", progname);
93145510Sdarrenr	fprintf(stderr, "usage: %s [-nNSv] -f <filename> -i <if1>,<if2>\n",
94145510Sdarrenr		progname);
95145510Sdarrenr	exit(1);
96145510Sdarrenr}
97145510Sdarrenr
98145510Sdarrenr
99145510Sdarrenr/*
100145510Sdarrenr * Change interface names in state information saved out to disk.
101145510Sdarrenr */
102145510Sdarrenrint changestateif(ifs, fname)
103145510Sdarrenrchar *ifs, *fname;
104145510Sdarrenr{
105145510Sdarrenr	int fd, olen, nlen, rw;
106145510Sdarrenr	ipstate_save_t ips;
107145510Sdarrenr	off_t pos;
108145510Sdarrenr	char *s;
109145510Sdarrenr
110145510Sdarrenr	s = strchr(ifs, ',');
111145510Sdarrenr	if (!s)
112145510Sdarrenr		usage();
113145510Sdarrenr	*s++ = '\0';
114145510Sdarrenr	nlen = strlen(s);
115145510Sdarrenr	olen = strlen(ifs);
116145510Sdarrenr	if (nlen >= sizeof(ips.ips_is.is_ifname) ||
117145510Sdarrenr	    olen >= sizeof(ips.ips_is.is_ifname))
118145510Sdarrenr		usage();
119145510Sdarrenr
120145510Sdarrenr	fd = open(fname, O_RDWR);
121145510Sdarrenr	if (fd == -1) {
122145510Sdarrenr		perror("open");
123145510Sdarrenr		exit(1);
124145510Sdarrenr	}
125145510Sdarrenr
126145510Sdarrenr	for (pos = 0; read(fd, &ips, sizeof(ips)) == sizeof(ips); ) {
127145510Sdarrenr		rw = 0;
128145510Sdarrenr		if (!strncmp(ips.ips_is.is_ifname[0], ifs, olen + 1)) {
129145510Sdarrenr			strcpy(ips.ips_is.is_ifname[0], s);
130145510Sdarrenr			rw = 1;
131145510Sdarrenr		}
132145510Sdarrenr		if (!strncmp(ips.ips_is.is_ifname[1], ifs, olen + 1)) {
133145510Sdarrenr			strcpy(ips.ips_is.is_ifname[1], s);
134145510Sdarrenr			rw = 1;
135145510Sdarrenr		}
136170268Sdarrenr		if (!strncmp(ips.ips_is.is_ifname[2], ifs, olen + 1)) {
137170268Sdarrenr			strcpy(ips.ips_is.is_ifname[2], s);
138170268Sdarrenr			rw = 1;
139170268Sdarrenr		}
140170268Sdarrenr		if (!strncmp(ips.ips_is.is_ifname[3], ifs, olen + 1)) {
141170268Sdarrenr			strcpy(ips.ips_is.is_ifname[3], s);
142170268Sdarrenr			rw = 1;
143170268Sdarrenr		}
144145510Sdarrenr		if (rw == 1) {
145145510Sdarrenr			if (lseek(fd, pos, SEEK_SET) != pos) {
146145510Sdarrenr				perror("lseek");
147145510Sdarrenr				exit(1);
148145510Sdarrenr			}
149145510Sdarrenr			if (write(fd, &ips, sizeof(ips)) != sizeof(ips)) {
150145510Sdarrenr				perror("write");
151145510Sdarrenr				exit(1);
152145510Sdarrenr			}
153145510Sdarrenr		}
154145510Sdarrenr		pos = lseek(fd, 0, SEEK_CUR);
155145510Sdarrenr	}
156145510Sdarrenr	close(fd);
157145510Sdarrenr
158145510Sdarrenr	return 0;
159145510Sdarrenr}
160145510Sdarrenr
161145510Sdarrenr
162145510Sdarrenr/*
163145510Sdarrenr * Change interface names in NAT information saved out to disk.
164145510Sdarrenr */
165145510Sdarrenrint changenatif(ifs, fname)
166145510Sdarrenrchar *ifs, *fname;
167145510Sdarrenr{
168145510Sdarrenr	int fd, olen, nlen, rw;
169145510Sdarrenr	nat_save_t ipn;
170145510Sdarrenr	nat_t *nat;
171145510Sdarrenr	off_t pos;
172145510Sdarrenr	char *s;
173145510Sdarrenr
174145510Sdarrenr	s = strchr(ifs, ',');
175145510Sdarrenr	if (!s)
176145510Sdarrenr		usage();
177145510Sdarrenr	*s++ = '\0';
178145510Sdarrenr	nlen = strlen(s);
179145510Sdarrenr	olen = strlen(ifs);
180145510Sdarrenr	nat = &ipn.ipn_nat;
181145510Sdarrenr	if (nlen >= sizeof(nat->nat_ifnames[0]) ||
182145510Sdarrenr	    olen >= sizeof(nat->nat_ifnames[0]))
183145510Sdarrenr		usage();
184145510Sdarrenr
185145510Sdarrenr	fd = open(fname, O_RDWR);
186145510Sdarrenr	if (fd == -1) {
187145510Sdarrenr		perror("open");
188145510Sdarrenr		exit(1);
189145510Sdarrenr	}
190145510Sdarrenr
191145510Sdarrenr	for (pos = 0; read(fd, &ipn, sizeof(ipn)) == sizeof(ipn); ) {
192145510Sdarrenr		rw = 0;
193145510Sdarrenr		if (!strncmp(nat->nat_ifnames[0], ifs, olen + 1)) {
194145510Sdarrenr			strcpy(nat->nat_ifnames[0], s);
195145510Sdarrenr			rw = 1;
196145510Sdarrenr		}
197145510Sdarrenr		if (!strncmp(nat->nat_ifnames[1], ifs, olen + 1)) {
198145510Sdarrenr			strcpy(nat->nat_ifnames[1], s);
199145510Sdarrenr			rw = 1;
200145510Sdarrenr		}
201170268Sdarrenr		if (!strncmp(nat->nat_ifnames[2], ifs, olen + 1)) {
202170268Sdarrenr			strcpy(nat->nat_ifnames[2], s);
203170268Sdarrenr			rw = 1;
204170268Sdarrenr		}
205170268Sdarrenr		if (!strncmp(nat->nat_ifnames[3], ifs, olen + 1)) {
206170268Sdarrenr			strcpy(nat->nat_ifnames[3], s);
207170268Sdarrenr			rw = 1;
208170268Sdarrenr		}
209145510Sdarrenr		if (rw == 1) {
210145510Sdarrenr			if (lseek(fd, pos, SEEK_SET) != pos) {
211145510Sdarrenr				perror("lseek");
212145510Sdarrenr				exit(1);
213145510Sdarrenr			}
214145510Sdarrenr			if (write(fd, &ipn, sizeof(ipn)) != sizeof(ipn)) {
215145510Sdarrenr				perror("write");
216145510Sdarrenr				exit(1);
217145510Sdarrenr			}
218145510Sdarrenr		}
219145510Sdarrenr		pos = lseek(fd, 0, SEEK_CUR);
220145510Sdarrenr	}
221145510Sdarrenr	close(fd);
222145510Sdarrenr
223145510Sdarrenr	return 0;
224145510Sdarrenr}
225145510Sdarrenr
226145510Sdarrenr
227145510Sdarrenrint main(argc,argv)
228145510Sdarrenrint argc;
229145510Sdarrenrchar *argv[];
230145510Sdarrenr{
231145510Sdarrenr	int c, lock = -1, devfd = -1, err = 0, rw = -1, ns = -1, set = 0;
232145510Sdarrenr	char *dirname = NULL, *filename = NULL, *ifs = NULL;
233145510Sdarrenr
234145510Sdarrenr	progname = argv[0];
235170268Sdarrenr	while ((c = getopt(argc, argv, "d:f:i:lNnSRruvWw")) != -1)
236145510Sdarrenr		switch (c)
237145510Sdarrenr		{
238145510Sdarrenr		case 'd' :
239145510Sdarrenr			if ((set == 0) && !dirname && !filename)
240145510Sdarrenr				dirname = optarg;
241145510Sdarrenr			else
242145510Sdarrenr				usage();
243145510Sdarrenr			break;
244145510Sdarrenr		case 'f' :
245145510Sdarrenr			if ((set != 0) && !dirname && !filename)
246145510Sdarrenr				filename = optarg;
247145510Sdarrenr			else
248145510Sdarrenr				usage();
249145510Sdarrenr			break;
250145510Sdarrenr		case 'i' :
251145510Sdarrenr			ifs = optarg;
252145510Sdarrenr			set = 1;
253145510Sdarrenr			break;
254145510Sdarrenr		case 'l' :
255145510Sdarrenr			if (filename || dirname || set)
256145510Sdarrenr				usage();
257145510Sdarrenr			lock = 1;
258145510Sdarrenr			set = 1;
259145510Sdarrenr			break;
260145510Sdarrenr		case 'n' :
261145510Sdarrenr			opts |= OPT_DONOTHING;
262145510Sdarrenr			break;
263145510Sdarrenr		case 'N' :
264145510Sdarrenr			if ((ns >= 0) || dirname || (rw != -1) || set)
265145510Sdarrenr				usage();
266145510Sdarrenr			ns = 0;
267145510Sdarrenr			set = 1;
268145510Sdarrenr			break;
269145510Sdarrenr		case 'r' :
270145510Sdarrenr			if (dirname || (rw != -1) || (ns == -1))
271145510Sdarrenr				usage();
272145510Sdarrenr			rw = 0;
273145510Sdarrenr			set = 1;
274145510Sdarrenr			break;
275145510Sdarrenr		case 'R' :
276145510Sdarrenr			rw = 2;
277145510Sdarrenr			set = 1;
278145510Sdarrenr			break;
279145510Sdarrenr		case 'S' :
280145510Sdarrenr			if ((ns >= 0) || dirname || (rw != -1) || set)
281145510Sdarrenr				usage();
282145510Sdarrenr			ns = 1;
283145510Sdarrenr			set = 1;
284145510Sdarrenr			break;
285145510Sdarrenr		case 'u' :
286145510Sdarrenr			if (filename || dirname || set)
287145510Sdarrenr				usage();
288145510Sdarrenr			lock = 0;
289145510Sdarrenr			set = 1;
290145510Sdarrenr			break;
291145510Sdarrenr		case 'v' :
292145510Sdarrenr			opts |= OPT_VERBOSE;
293145510Sdarrenr			break;
294145510Sdarrenr		case 'w' :
295145510Sdarrenr			if (dirname || (rw != -1) || (ns == -1))
296145510Sdarrenr				usage();
297145510Sdarrenr			rw = 1;
298145510Sdarrenr			set = 1;
299145510Sdarrenr			break;
300145510Sdarrenr		case 'W' :
301145510Sdarrenr			rw = 3;
302145510Sdarrenr			set = 1;
303145510Sdarrenr			break;
304145510Sdarrenr		case '?' :
305145510Sdarrenr		default :
306145510Sdarrenr			usage();
307145510Sdarrenr		}
308145510Sdarrenr
309145510Sdarrenr	if (ifs) {
310145510Sdarrenr		if (!filename || ns < 0)
311145510Sdarrenr			usage();
312145510Sdarrenr		if (ns == 0)
313145510Sdarrenr			return changenatif(ifs, filename);
314145510Sdarrenr		else
315145510Sdarrenr			return changestateif(ifs, filename);
316145510Sdarrenr	}
317145510Sdarrenr
318145510Sdarrenr	if ((ns >= 0) || (lock >= 0)) {
319145510Sdarrenr		if (lock >= 0)
320145510Sdarrenr			devfd = opendevice(NULL);
321145510Sdarrenr		else if (ns >= 0) {
322145510Sdarrenr			if (ns == 1)
323145510Sdarrenr				devfd = opendevice(IPSTATE_NAME);
324145510Sdarrenr			else if (ns == 0)
325145510Sdarrenr				devfd = opendevice(IPNAT_NAME);
326145510Sdarrenr		}
327145510Sdarrenr		if (devfd == -1)
328145510Sdarrenr			exit(1);
329145510Sdarrenr	}
330145510Sdarrenr
331145510Sdarrenr	if (lock >= 0)
332145510Sdarrenr		err = setlock(devfd, lock);
333145510Sdarrenr	else if (rw >= 0) {
334145510Sdarrenr		if (rw & 1) {	/* WRITE */
335145510Sdarrenr			if (rw & 2)
336145510Sdarrenr				err = writeall(dirname);
337145510Sdarrenr			else {
338145510Sdarrenr				if (ns == 0)
339145510Sdarrenr					err = writenat(devfd, filename);
340145510Sdarrenr				else if (ns == 1)
341145510Sdarrenr					err = writestate(devfd, filename);
342145510Sdarrenr			}
343145510Sdarrenr		} else {
344145510Sdarrenr			if (rw & 2)
345145510Sdarrenr				err = readall(dirname);
346145510Sdarrenr			else {
347145510Sdarrenr				if (ns == 0)
348145510Sdarrenr					err = readnat(devfd, filename);
349145510Sdarrenr				else if (ns == 1)
350145510Sdarrenr					err = readstate(devfd, filename);
351145510Sdarrenr			}
352145510Sdarrenr		}
353145510Sdarrenr	}
354145510Sdarrenr	return err;
355145510Sdarrenr}
356145510Sdarrenr
357145510Sdarrenr
358145510Sdarrenrint opendevice(ipfdev)
359145510Sdarrenrchar *ipfdev;
360145510Sdarrenr{
361145510Sdarrenr	int fd = -1;
362145510Sdarrenr
363145510Sdarrenr	if (opts & OPT_DONOTHING)
364145510Sdarrenr		return -2;
365145510Sdarrenr
366145510Sdarrenr	if (!ipfdev)
367145510Sdarrenr		ipfdev = IPL_NAME;
368145510Sdarrenr
369145510Sdarrenr	if ((fd = open(ipfdev, O_RDWR)) == -1)
370145510Sdarrenr		if ((fd = open(ipfdev, O_RDONLY)) == -1)
371145510Sdarrenr			perror("open device");
372145510Sdarrenr	return fd;
373145510Sdarrenr}
374145510Sdarrenr
375145510Sdarrenr
376145510Sdarrenrvoid closedevice(fd)
377145510Sdarrenrint fd;
378145510Sdarrenr{
379145510Sdarrenr	close(fd);
380145510Sdarrenr}
381145510Sdarrenr
382145510Sdarrenr
383145510Sdarrenrint setlock(fd, lock)
384145510Sdarrenrint fd, lock;
385145510Sdarrenr{
386145510Sdarrenr	if (opts & OPT_VERBOSE)
387145510Sdarrenr		printf("Turn lock %s\n", lock ? "on" : "off");
388145510Sdarrenr	if (!(opts & OPT_DONOTHING)) {
389145510Sdarrenr		if (ioctl(fd, SIOCSTLCK, &lock) == -1) {
390145510Sdarrenr			perror("SIOCSTLCK");
391145510Sdarrenr			return 1;
392145510Sdarrenr		}
393145510Sdarrenr		if (opts & OPT_VERBOSE)
394145510Sdarrenr			printf("Lock now %s\n", lock ? "on" : "off");
395145510Sdarrenr	}
396145510Sdarrenr	return 0;
397145510Sdarrenr}
398145510Sdarrenr
399145510Sdarrenr
400145510Sdarrenrint writestate(fd, file)
401145510Sdarrenrint fd;
402145510Sdarrenrchar *file;
403145510Sdarrenr{
404145510Sdarrenr	ipstate_save_t ips, *ipsp;
405145510Sdarrenr	ipfobj_t obj;
406145510Sdarrenr	int wfd = -1;
407145510Sdarrenr
408145510Sdarrenr	if (!file)
409145510Sdarrenr		file = IPF_STATEFILE;
410145510Sdarrenr
411145510Sdarrenr	wfd = open(file, O_WRONLY|O_TRUNC|O_CREAT, 0600);
412145510Sdarrenr	if (wfd == -1) {
413145510Sdarrenr		fprintf(stderr, "%s ", file);
414145510Sdarrenr		perror("state:open");
415145510Sdarrenr		return 1;
416145510Sdarrenr	}
417145510Sdarrenr
418145510Sdarrenr	ipsp = &ips;
419145510Sdarrenr	bzero((char *)&obj, sizeof(obj));
420145510Sdarrenr	bzero((char *)ipsp, sizeof(ips));
421145510Sdarrenr
422145510Sdarrenr	obj.ipfo_rev = IPFILTER_VERSION;
423145510Sdarrenr	obj.ipfo_size = sizeof(*ipsp);
424145510Sdarrenr	obj.ipfo_type = IPFOBJ_STATESAVE;
425145510Sdarrenr	obj.ipfo_ptr = ipsp;
426145510Sdarrenr
427145510Sdarrenr	do {
428145510Sdarrenr
429145510Sdarrenr		if (opts & OPT_VERBOSE)
430145510Sdarrenr			printf("Getting state from addr %p\n", ips.ips_next);
431145510Sdarrenr		if (ioctl(fd, SIOCSTGET, &obj)) {
432145510Sdarrenr			if (errno == ENOENT)
433145510Sdarrenr				break;
434145510Sdarrenr			perror("state:SIOCSTGET");
435145510Sdarrenr			close(wfd);
436145510Sdarrenr			return 1;
437145510Sdarrenr		}
438145510Sdarrenr		if (opts & OPT_VERBOSE)
439145510Sdarrenr			printf("Got state next %p\n", ips.ips_next);
440145510Sdarrenr		if (write(wfd, ipsp, sizeof(ips)) != sizeof(ips)) {
441145510Sdarrenr			perror("state:write");
442145510Sdarrenr			close(wfd);
443145510Sdarrenr			return 1;
444145510Sdarrenr		}
445145510Sdarrenr	} while (ips.ips_next != NULL);
446145510Sdarrenr	close(wfd);
447145510Sdarrenr
448145510Sdarrenr	return 0;
449145510Sdarrenr}
450145510Sdarrenr
451145510Sdarrenr
452145510Sdarrenrint readstate(fd, file)
453145510Sdarrenrint fd;
454145510Sdarrenrchar *file;
455145510Sdarrenr{
456145510Sdarrenr	ipstate_save_t ips, *is, *ipshead = NULL, *is1, *ipstail = NULL;
457145510Sdarrenr	int sfd = -1, i;
458145510Sdarrenr	ipfobj_t obj;
459145510Sdarrenr
460145510Sdarrenr	if (!file)
461145510Sdarrenr		file = IPF_STATEFILE;
462145510Sdarrenr
463145510Sdarrenr	sfd = open(file, O_RDONLY, 0600);
464145510Sdarrenr	if (sfd == -1) {
465145510Sdarrenr		fprintf(stderr, "%s ", file);
466145510Sdarrenr		perror("open");
467145510Sdarrenr		return 1;
468145510Sdarrenr	}
469145510Sdarrenr
470145510Sdarrenr	bzero((char *)&ips, sizeof(ips));
471145510Sdarrenr
472145510Sdarrenr	/*
473145510Sdarrenr	 * 1. Read all state information in.
474145510Sdarrenr	 */
475145510Sdarrenr	do {
476145510Sdarrenr		i = read(sfd, &ips, sizeof(ips));
477145510Sdarrenr		if (i == -1) {
478145510Sdarrenr			perror("read");
479161357Sguido			goto freeipshead;
480145510Sdarrenr		}
481145510Sdarrenr		if (i == 0)
482145510Sdarrenr			break;
483145510Sdarrenr		if (i != sizeof(ips)) {
484145510Sdarrenr			fprintf(stderr, "state:incomplete read: %d != %d\n",
485145510Sdarrenr				i, (int)sizeof(ips));
486161357Sguido			goto freeipshead;
487145510Sdarrenr		}
488145510Sdarrenr		is = (ipstate_save_t *)malloc(sizeof(*is));
489161357Sguido		if (is == NULL) {
490145510Sdarrenr			fprintf(stderr, "malloc failed\n");
491161357Sguido			goto freeipshead;
492145510Sdarrenr		}
493145510Sdarrenr
494145510Sdarrenr		bcopy((char *)&ips, (char *)is, sizeof(ips));
495145510Sdarrenr
496145510Sdarrenr		/*
497145510Sdarrenr		 * Check to see if this is the first state entry that will
498145510Sdarrenr		 * reference a particular rule and if so, flag it as such
499145510Sdarrenr		 * else just adjust the rule pointer to become a pointer to
500145510Sdarrenr		 * the other.  We do this so we have a means later for tracking
501145510Sdarrenr		 * who is referencing us when we get back the real pointer
502145510Sdarrenr		 * in is_rule after doing the ioctl.
503145510Sdarrenr		 */
504145510Sdarrenr		for (is1 = ipshead; is1 != NULL; is1 = is1->ips_next)
505145510Sdarrenr			if (is1->ips_rule == is->ips_rule)
506145510Sdarrenr				break;
507145510Sdarrenr		if (is1 == NULL)
508145510Sdarrenr			is->ips_is.is_flags |= SI_NEWFR;
509145510Sdarrenr		else
510145510Sdarrenr			is->ips_rule = (void *)&is1->ips_rule;
511145510Sdarrenr
512145510Sdarrenr		/*
513145510Sdarrenr		 * Use a tail-queue type list (add things to the end)..
514145510Sdarrenr		 */
515145510Sdarrenr		is->ips_next = NULL;
516145510Sdarrenr		if (!ipshead)
517145510Sdarrenr			ipshead = is;
518145510Sdarrenr		if (ipstail)
519145510Sdarrenr			ipstail->ips_next = is;
520145510Sdarrenr		ipstail = is;
521145510Sdarrenr	} while (1);
522145510Sdarrenr
523145510Sdarrenr	close(sfd);
524145510Sdarrenr
525145510Sdarrenr	obj.ipfo_rev = IPFILTER_VERSION;
526145510Sdarrenr	obj.ipfo_size = sizeof(*is);
527145510Sdarrenr	obj.ipfo_type = IPFOBJ_STATESAVE;
528145510Sdarrenr
529161357Sguido	while ((is = ipshead) != NULL) {
530145510Sdarrenr		if (opts & OPT_VERBOSE)
531145510Sdarrenr			printf("Loading new state table entry\n");
532145510Sdarrenr		if (is->ips_is.is_flags & SI_NEWFR) {
533145510Sdarrenr			if (opts & OPT_VERBOSE)
534145510Sdarrenr				printf("Loading new filter rule\n");
535145510Sdarrenr		}
536145510Sdarrenr
537145510Sdarrenr		obj.ipfo_ptr = is;
538145510Sdarrenr		if (!(opts & OPT_DONOTHING))
539145510Sdarrenr			if (ioctl(fd, SIOCSTPUT, &obj)) {
540145510Sdarrenr				perror("SIOCSTPUT");
541161357Sguido				goto freeipshead;
542145510Sdarrenr			}
543145510Sdarrenr
544145510Sdarrenr		if (is->ips_is.is_flags & SI_NEWFR) {
545145510Sdarrenr			if (opts & OPT_VERBOSE)
546145510Sdarrenr				printf("Real rule addr %p\n", is->ips_rule);
547145510Sdarrenr			for (is1 = is->ips_next; is1; is1 = is1->ips_next)
548145510Sdarrenr				if (is1->ips_rule == (frentry_t *)&is->ips_rule)
549145510Sdarrenr					is1->ips_rule = is->ips_rule;
550145510Sdarrenr		}
551161357Sguido
552161357Sguido		ipshead = is->ips_next;
553161357Sguido		free(is);
554145510Sdarrenr	}
555145510Sdarrenr
556145510Sdarrenr	return 0;
557161357Sguido
558161357Sguidofreeipshead:
559161357Sguido	while ((is = ipshead) != NULL) {
560161357Sguido		ipshead = is->ips_next;
561161357Sguido		free(is);
562161357Sguido	}
563161357Sguido	if (sfd != -1)
564161357Sguido		close(sfd);
565161357Sguido	return 1;
566145510Sdarrenr}
567145510Sdarrenr
568145510Sdarrenr
569145510Sdarrenrint readnat(fd, file)
570145510Sdarrenrint fd;
571145510Sdarrenrchar *file;
572145510Sdarrenr{
573145510Sdarrenr	nat_save_t ipn, *in, *ipnhead = NULL, *in1, *ipntail = NULL;
574145510Sdarrenr	ipfobj_t obj;
575145510Sdarrenr	int nfd, i;
576145510Sdarrenr	nat_t *nat;
577145510Sdarrenr	char *s;
578145510Sdarrenr	int n;
579145510Sdarrenr
580145510Sdarrenr	nfd = -1;
581145510Sdarrenr	in = NULL;
582145510Sdarrenr	ipnhead = NULL;
583145510Sdarrenr	ipntail = NULL;
584145510Sdarrenr
585145510Sdarrenr	if (!file)
586145510Sdarrenr		file = IPF_NATFILE;
587145510Sdarrenr
588145510Sdarrenr	nfd = open(file, O_RDONLY);
589145510Sdarrenr	if (nfd == -1) {
590145510Sdarrenr		fprintf(stderr, "%s ", file);
591145510Sdarrenr		perror("nat:open");
592145510Sdarrenr		return 1;
593145510Sdarrenr	}
594145510Sdarrenr
595145510Sdarrenr	bzero((char *)&ipn, sizeof(ipn));
596145510Sdarrenr
597145510Sdarrenr	/*
598145510Sdarrenr	 * 1. Read all state information in.
599145510Sdarrenr	 */
600145510Sdarrenr	do {
601145510Sdarrenr		i = read(nfd, &ipn, sizeof(ipn));
602145510Sdarrenr		if (i == -1) {
603145510Sdarrenr			perror("read");
604161357Sguido			goto freenathead;
605145510Sdarrenr		}
606145510Sdarrenr		if (i == 0)
607145510Sdarrenr			break;
608145510Sdarrenr		if (i != sizeof(ipn)) {
609145510Sdarrenr			fprintf(stderr, "nat:incomplete read: %d != %d\n",
610145510Sdarrenr				i, (int)sizeof(ipn));
611161357Sguido			goto freenathead;
612145510Sdarrenr		}
613145510Sdarrenr
614145510Sdarrenr		in = (nat_save_t *)malloc(ipn.ipn_dsize);
615161357Sguido		if (in == NULL) {
616161357Sguido			fprintf(stderr, "nat:cannot malloc nat save atruct\n");
617161357Sguido			goto freenathead;
618161357Sguido		}
619145510Sdarrenr
620145510Sdarrenr		if (ipn.ipn_dsize > sizeof(ipn)) {
621145510Sdarrenr			n = ipn.ipn_dsize - sizeof(ipn);
622145510Sdarrenr			if (n > 0) {
623145510Sdarrenr				s = in->ipn_data + sizeof(in->ipn_data);
624145510Sdarrenr 				i = read(nfd, s, n);
625145510Sdarrenr				if (i == 0)
626145510Sdarrenr					break;
627145510Sdarrenr				if (i != n) {
628145510Sdarrenr					fprintf(stderr,
629145510Sdarrenr					    "nat:incomplete read: %d != %d\n",
630145510Sdarrenr					    i, n);
631161357Sguido					goto freenathead;
632145510Sdarrenr				}
633145510Sdarrenr			}
634145510Sdarrenr		}
635145510Sdarrenr		bcopy((char *)&ipn, (char *)in, sizeof(ipn));
636145510Sdarrenr
637145510Sdarrenr		/*
638145510Sdarrenr		 * Check to see if this is the first NAT entry that will
639145510Sdarrenr		 * reference a particular rule and if so, flag it as such
640145510Sdarrenr		 * else just adjust the rule pointer to become a pointer to
641145510Sdarrenr		 * the other.  We do this so we have a means later for tracking
642145510Sdarrenr		 * who is referencing us when we get back the real pointer
643145510Sdarrenr		 * in is_rule after doing the ioctl.
644145510Sdarrenr		 */
645145510Sdarrenr		nat = &in->ipn_nat;
646145510Sdarrenr		if (nat->nat_fr != NULL) {
647145510Sdarrenr			for (in1 = ipnhead; in1 != NULL; in1 = in1->ipn_next)
648145510Sdarrenr				if (in1->ipn_rule == nat->nat_fr)
649145510Sdarrenr					break;
650145510Sdarrenr			if (in1 == NULL)
651145510Sdarrenr				nat->nat_flags |= SI_NEWFR;
652145510Sdarrenr			else
653145510Sdarrenr				nat->nat_fr = &in1->ipn_fr;
654145510Sdarrenr		}
655145510Sdarrenr
656145510Sdarrenr		/*
657145510Sdarrenr		 * Use a tail-queue type list (add things to the end)..
658145510Sdarrenr		 */
659145510Sdarrenr		in->ipn_next = NULL;
660145510Sdarrenr		if (!ipnhead)
661145510Sdarrenr			ipnhead = in;
662145510Sdarrenr		if (ipntail)
663145510Sdarrenr			ipntail->ipn_next = in;
664145510Sdarrenr		ipntail = in;
665145510Sdarrenr	} while (1);
666145510Sdarrenr
667145510Sdarrenr	close(nfd);
668145510Sdarrenr	nfd = -1;
669145510Sdarrenr
670145510Sdarrenr	obj.ipfo_rev = IPFILTER_VERSION;
671145510Sdarrenr	obj.ipfo_type = IPFOBJ_NATSAVE;
672145510Sdarrenr
673161357Sguido	while ((in = ipnhead) != NULL) {
674145510Sdarrenr		if (opts & OPT_VERBOSE)
675145510Sdarrenr			printf("Loading new NAT table entry\n");
676145510Sdarrenr		nat = &in->ipn_nat;
677145510Sdarrenr		if (nat->nat_flags & SI_NEWFR) {
678145510Sdarrenr			if (opts & OPT_VERBOSE)
679145510Sdarrenr				printf("Loading new filter rule\n");
680145510Sdarrenr		}
681145510Sdarrenr
682145510Sdarrenr		obj.ipfo_ptr = in;
683145510Sdarrenr		obj.ipfo_size = in->ipn_dsize;
684145510Sdarrenr		if (!(opts & OPT_DONOTHING))
685145510Sdarrenr			if (ioctl(fd, SIOCSTPUT, &obj)) {
686145510Sdarrenr				fprintf(stderr, "in=%p:", in);
687145510Sdarrenr				perror("SIOCSTPUT");
688145510Sdarrenr				return 1;
689145510Sdarrenr			}
690145510Sdarrenr
691145510Sdarrenr		if (nat->nat_flags & SI_NEWFR) {
692145510Sdarrenr			if (opts & OPT_VERBOSE)
693145510Sdarrenr				printf("Real rule addr %p\n", nat->nat_fr);
694145510Sdarrenr			for (in1 = in->ipn_next; in1; in1 = in1->ipn_next)
695145510Sdarrenr				if (in1->ipn_rule == &in->ipn_fr)
696145510Sdarrenr					in1->ipn_rule = nat->nat_fr;
697145510Sdarrenr		}
698161357Sguido
699161357Sguido		ipnhead = in->ipn_next;
700161357Sguido		free(in);
701145510Sdarrenr	}
702145510Sdarrenr
703145510Sdarrenr	return 0;
704161357Sguido
705161357Sguidofreenathead:
706161357Sguido	while ((in = ipnhead) != NULL) {
707161357Sguido		ipnhead = in->ipn_next;
708161357Sguido		free(in);
709161357Sguido	}
710161357Sguido	if (nfd != -1)
711161357Sguido		close(nfd);
712161357Sguido	return 1;
713145510Sdarrenr}
714145510Sdarrenr
715145510Sdarrenr
716145510Sdarrenrint writenat(fd, file)
717145510Sdarrenrint fd;
718145510Sdarrenrchar *file;
719145510Sdarrenr{
720145510Sdarrenr	nat_save_t *ipnp = NULL, *next = NULL;
721145510Sdarrenr	ipfobj_t obj;
722145510Sdarrenr	int nfd = -1;
723145510Sdarrenr	natget_t ng;
724145510Sdarrenr
725145510Sdarrenr	if (!file)
726145510Sdarrenr		file = IPF_NATFILE;
727145510Sdarrenr
728145510Sdarrenr	nfd = open(file, O_WRONLY|O_TRUNC|O_CREAT, 0600);
729145510Sdarrenr	if (nfd == -1) {
730145510Sdarrenr		fprintf(stderr, "%s ", file);
731145510Sdarrenr		perror("nat:open");
732145510Sdarrenr		return 1;
733145510Sdarrenr	}
734145510Sdarrenr
735145510Sdarrenr	obj.ipfo_rev = IPFILTER_VERSION;
736145510Sdarrenr	obj.ipfo_type = IPFOBJ_NATSAVE;
737145510Sdarrenr
738145510Sdarrenr	do {
739145510Sdarrenr		if (opts & OPT_VERBOSE)
740145510Sdarrenr			printf("Getting nat from addr %p\n", ipnp);
741145510Sdarrenr		ng.ng_ptr = next;
742145510Sdarrenr		ng.ng_sz = 0;
743145510Sdarrenr		if (ioctl(fd, SIOCSTGSZ, &ng)) {
744145510Sdarrenr			perror("nat:SIOCSTGSZ");
745145510Sdarrenr			close(nfd);
746145510Sdarrenr			if (ipnp != NULL)
747145510Sdarrenr				free(ipnp);
748145510Sdarrenr			return 1;
749145510Sdarrenr		}
750145510Sdarrenr
751145510Sdarrenr		if (opts & OPT_VERBOSE)
752145510Sdarrenr			printf("NAT size %d from %p\n", ng.ng_sz, ng.ng_ptr);
753145510Sdarrenr
754145510Sdarrenr		if (ng.ng_sz == 0)
755145510Sdarrenr			break;
756145510Sdarrenr
757145510Sdarrenr		if (!ipnp)
758145510Sdarrenr			ipnp = malloc(ng.ng_sz);
759145510Sdarrenr		else
760145510Sdarrenr			ipnp = realloc((char *)ipnp, ng.ng_sz);
761145510Sdarrenr		if (!ipnp) {
762145510Sdarrenr			fprintf(stderr,
763145510Sdarrenr				"malloc for %d bytes failed\n", ng.ng_sz);
764145510Sdarrenr			break;
765145510Sdarrenr		}
766145510Sdarrenr
767145510Sdarrenr		bzero((char *)ipnp, ng.ng_sz);
768145510Sdarrenr		obj.ipfo_size = ng.ng_sz;
769145510Sdarrenr		obj.ipfo_ptr = ipnp;
770145510Sdarrenr		ipnp->ipn_dsize = ng.ng_sz;
771145510Sdarrenr		ipnp->ipn_next = next;
772145510Sdarrenr		if (ioctl(fd, SIOCSTGET, &obj)) {
773145510Sdarrenr			if (errno == ENOENT)
774145510Sdarrenr				break;
775145510Sdarrenr			perror("nat:SIOCSTGET");
776145510Sdarrenr			close(nfd);
777145510Sdarrenr			free(ipnp);
778145510Sdarrenr			return 1;
779145510Sdarrenr		}
780145510Sdarrenr
781145510Sdarrenr		if (opts & OPT_VERBOSE)
782145510Sdarrenr			printf("Got nat next %p ipn_dsize %d ng_sz %d\n",
783145510Sdarrenr				ipnp->ipn_next, ipnp->ipn_dsize, ng.ng_sz);
784145510Sdarrenr		if (write(nfd, ipnp, ipnp->ipn_dsize) != ipnp->ipn_dsize) {
785145510Sdarrenr			perror("nat:write");
786145510Sdarrenr			close(nfd);
787145510Sdarrenr			free(ipnp);
788145510Sdarrenr			return 1;
789145510Sdarrenr		}
790145510Sdarrenr		next = ipnp->ipn_next;
791145510Sdarrenr	} while (ipnp && next);
792145510Sdarrenr	if (ipnp != NULL)
793145510Sdarrenr		free(ipnp);
794145510Sdarrenr	close(nfd);
795145510Sdarrenr
796145510Sdarrenr	return 0;
797145510Sdarrenr}
798145510Sdarrenr
799145510Sdarrenr
800145510Sdarrenrint writeall(dirname)
801145510Sdarrenrchar *dirname;
802145510Sdarrenr{
803145510Sdarrenr	int fd, devfd;
804145510Sdarrenr
805145510Sdarrenr	if (!dirname)
806145510Sdarrenr		dirname = IPF_SAVEDIR;
807145510Sdarrenr
808145510Sdarrenr	if (chdir(dirname)) {
809145510Sdarrenr		fprintf(stderr, "IPF_SAVEDIR=%s: ", dirname);
810145510Sdarrenr		perror("chdir(IPF_SAVEDIR)");
811145510Sdarrenr		return 1;
812145510Sdarrenr	}
813145510Sdarrenr
814145510Sdarrenr	fd = opendevice(NULL);
815145510Sdarrenr	if (fd == -1)
816145510Sdarrenr		return 1;
817145510Sdarrenr	if (setlock(fd, 1)) {
818145510Sdarrenr		close(fd);
819145510Sdarrenr		return 1;
820145510Sdarrenr	}
821145510Sdarrenr
822145510Sdarrenr	devfd = opendevice(IPSTATE_NAME);
823145510Sdarrenr	if (devfd == -1)
824145510Sdarrenr		goto bad;
825145510Sdarrenr	if (writestate(devfd, NULL))
826145510Sdarrenr		goto bad;
827145510Sdarrenr	close(devfd);
828145510Sdarrenr
829145510Sdarrenr	devfd = opendevice(IPNAT_NAME);
830145510Sdarrenr	if (devfd == -1)
831145510Sdarrenr		goto bad;
832145510Sdarrenr	if (writenat(devfd, NULL))
833145510Sdarrenr		goto bad;
834145510Sdarrenr	close(devfd);
835145510Sdarrenr
836145510Sdarrenr	if (setlock(fd, 0)) {
837145510Sdarrenr		close(fd);
838145510Sdarrenr		return 1;
839145510Sdarrenr	}
840145510Sdarrenr
841145510Sdarrenr	close(fd);
842145510Sdarrenr	return 0;
843145510Sdarrenr
844145510Sdarrenrbad:
845145510Sdarrenr	setlock(fd, 0);
846145510Sdarrenr	close(fd);
847145510Sdarrenr	return 1;
848145510Sdarrenr}
849145510Sdarrenr
850145510Sdarrenr
851145510Sdarrenrint readall(dirname)
852145510Sdarrenrchar *dirname;
853145510Sdarrenr{
854145510Sdarrenr	int fd, devfd;
855145510Sdarrenr
856145510Sdarrenr	if (!dirname)
857145510Sdarrenr		dirname = IPF_SAVEDIR;
858145510Sdarrenr
859145510Sdarrenr	if (chdir(dirname)) {
860145510Sdarrenr		perror("chdir(IPF_SAVEDIR)");
861145510Sdarrenr		return 1;
862145510Sdarrenr	}
863145510Sdarrenr
864145510Sdarrenr	fd = opendevice(NULL);
865145510Sdarrenr	if (fd == -1)
866145510Sdarrenr		return 1;
867145510Sdarrenr	if (setlock(fd, 1)) {
868145510Sdarrenr		close(fd);
869145510Sdarrenr		return 1;
870145510Sdarrenr	}
871145510Sdarrenr
872145510Sdarrenr	devfd = opendevice(IPSTATE_NAME);
873145510Sdarrenr	if (devfd == -1)
874145510Sdarrenr		return 1;
875145510Sdarrenr	if (readstate(devfd, NULL))
876145510Sdarrenr		return 1;
877145510Sdarrenr	close(devfd);
878145510Sdarrenr
879145510Sdarrenr	devfd = opendevice(IPNAT_NAME);
880145510Sdarrenr	if (devfd == -1)
881145510Sdarrenr		return 1;
882145510Sdarrenr	if (readnat(devfd, NULL))
883145510Sdarrenr		return 1;
884145510Sdarrenr	close(devfd);
885145510Sdarrenr
886145510Sdarrenr	if (setlock(fd, 0)) {
887145510Sdarrenr		close(fd);
888145510Sdarrenr		return 1;
889145510Sdarrenr	}
890145510Sdarrenr
891145510Sdarrenr	return 0;
892145510Sdarrenr}
893