ipfs.c revision 161357
1145519Sdarrenr/*	$FreeBSD: head/contrib/ipfilter/tools/ipfs.c 161357 2006-08-16 12:23:02Z guido $	*/
2145510Sdarrenr
3145510Sdarrenr/*
4145510Sdarrenr * Copyright (C) 1999-2001, 2003 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		}
136145510Sdarrenr		if (rw == 1) {
137145510Sdarrenr			if (lseek(fd, pos, SEEK_SET) != pos) {
138145510Sdarrenr				perror("lseek");
139145510Sdarrenr				exit(1);
140145510Sdarrenr			}
141145510Sdarrenr			if (write(fd, &ips, sizeof(ips)) != sizeof(ips)) {
142145510Sdarrenr				perror("write");
143145510Sdarrenr				exit(1);
144145510Sdarrenr			}
145145510Sdarrenr		}
146145510Sdarrenr		pos = lseek(fd, 0, SEEK_CUR);
147145510Sdarrenr	}
148145510Sdarrenr	close(fd);
149145510Sdarrenr
150145510Sdarrenr	return 0;
151145510Sdarrenr}
152145510Sdarrenr
153145510Sdarrenr
154145510Sdarrenr/*
155145510Sdarrenr * Change interface names in NAT information saved out to disk.
156145510Sdarrenr */
157145510Sdarrenrint changenatif(ifs, fname)
158145510Sdarrenrchar *ifs, *fname;
159145510Sdarrenr{
160145510Sdarrenr	int fd, olen, nlen, rw;
161145510Sdarrenr	nat_save_t ipn;
162145510Sdarrenr	nat_t *nat;
163145510Sdarrenr	off_t pos;
164145510Sdarrenr	char *s;
165145510Sdarrenr
166145510Sdarrenr	s = strchr(ifs, ',');
167145510Sdarrenr	if (!s)
168145510Sdarrenr		usage();
169145510Sdarrenr	*s++ = '\0';
170145510Sdarrenr	nlen = strlen(s);
171145510Sdarrenr	olen = strlen(ifs);
172145510Sdarrenr	nat = &ipn.ipn_nat;
173145510Sdarrenr	if (nlen >= sizeof(nat->nat_ifnames[0]) ||
174145510Sdarrenr	    olen >= sizeof(nat->nat_ifnames[0]))
175145510Sdarrenr		usage();
176145510Sdarrenr
177145510Sdarrenr	fd = open(fname, O_RDWR);
178145510Sdarrenr	if (fd == -1) {
179145510Sdarrenr		perror("open");
180145510Sdarrenr		exit(1);
181145510Sdarrenr	}
182145510Sdarrenr
183145510Sdarrenr	for (pos = 0; read(fd, &ipn, sizeof(ipn)) == sizeof(ipn); ) {
184145510Sdarrenr		rw = 0;
185145510Sdarrenr		if (!strncmp(nat->nat_ifnames[0], ifs, olen + 1)) {
186145510Sdarrenr			strcpy(nat->nat_ifnames[0], s);
187145510Sdarrenr			rw = 1;
188145510Sdarrenr		}
189145510Sdarrenr		if (!strncmp(nat->nat_ifnames[1], ifs, olen + 1)) {
190145510Sdarrenr			strcpy(nat->nat_ifnames[1], s);
191145510Sdarrenr			rw = 1;
192145510Sdarrenr		}
193145510Sdarrenr		if (rw == 1) {
194145510Sdarrenr			if (lseek(fd, pos, SEEK_SET) != pos) {
195145510Sdarrenr				perror("lseek");
196145510Sdarrenr				exit(1);
197145510Sdarrenr			}
198145510Sdarrenr			if (write(fd, &ipn, sizeof(ipn)) != sizeof(ipn)) {
199145510Sdarrenr				perror("write");
200145510Sdarrenr				exit(1);
201145510Sdarrenr			}
202145510Sdarrenr		}
203145510Sdarrenr		pos = lseek(fd, 0, SEEK_CUR);
204145510Sdarrenr	}
205145510Sdarrenr	close(fd);
206145510Sdarrenr
207145510Sdarrenr	return 0;
208145510Sdarrenr}
209145510Sdarrenr
210145510Sdarrenr
211145510Sdarrenrint main(argc,argv)
212145510Sdarrenrint argc;
213145510Sdarrenrchar *argv[];
214145510Sdarrenr{
215145510Sdarrenr	int c, lock = -1, devfd = -1, err = 0, rw = -1, ns = -1, set = 0;
216145510Sdarrenr	char *dirname = NULL, *filename = NULL, *ifs = NULL;
217145510Sdarrenr
218145510Sdarrenr	progname = argv[0];
219145510Sdarrenr	while ((c = getopt(argc, argv, "d:f:lNnSRruvWw")) != -1)
220145510Sdarrenr		switch (c)
221145510Sdarrenr		{
222145510Sdarrenr		case 'd' :
223145510Sdarrenr			if ((set == 0) && !dirname && !filename)
224145510Sdarrenr				dirname = optarg;
225145510Sdarrenr			else
226145510Sdarrenr				usage();
227145510Sdarrenr			break;
228145510Sdarrenr		case 'f' :
229145510Sdarrenr			if ((set != 0) && !dirname && !filename)
230145510Sdarrenr				filename = optarg;
231145510Sdarrenr			else
232145510Sdarrenr				usage();
233145510Sdarrenr			break;
234145510Sdarrenr		case 'i' :
235145510Sdarrenr			ifs = optarg;
236145510Sdarrenr			set = 1;
237145510Sdarrenr			break;
238145510Sdarrenr		case 'l' :
239145510Sdarrenr			if (filename || dirname || set)
240145510Sdarrenr				usage();
241145510Sdarrenr			lock = 1;
242145510Sdarrenr			set = 1;
243145510Sdarrenr			break;
244145510Sdarrenr		case 'n' :
245145510Sdarrenr			opts |= OPT_DONOTHING;
246145510Sdarrenr			break;
247145510Sdarrenr		case 'N' :
248145510Sdarrenr			if ((ns >= 0) || dirname || (rw != -1) || set)
249145510Sdarrenr				usage();
250145510Sdarrenr			ns = 0;
251145510Sdarrenr			set = 1;
252145510Sdarrenr			break;
253145510Sdarrenr		case 'r' :
254145510Sdarrenr			if (dirname || (rw != -1) || (ns == -1))
255145510Sdarrenr				usage();
256145510Sdarrenr			rw = 0;
257145510Sdarrenr			set = 1;
258145510Sdarrenr			break;
259145510Sdarrenr		case 'R' :
260145510Sdarrenr			rw = 2;
261145510Sdarrenr			set = 1;
262145510Sdarrenr			break;
263145510Sdarrenr		case 'S' :
264145510Sdarrenr			if ((ns >= 0) || dirname || (rw != -1) || set)
265145510Sdarrenr				usage();
266145510Sdarrenr			ns = 1;
267145510Sdarrenr			set = 1;
268145510Sdarrenr			break;
269145510Sdarrenr		case 'u' :
270145510Sdarrenr			if (filename || dirname || set)
271145510Sdarrenr				usage();
272145510Sdarrenr			lock = 0;
273145510Sdarrenr			set = 1;
274145510Sdarrenr			break;
275145510Sdarrenr		case 'v' :
276145510Sdarrenr			opts |= OPT_VERBOSE;
277145510Sdarrenr			break;
278145510Sdarrenr		case 'w' :
279145510Sdarrenr			if (dirname || (rw != -1) || (ns == -1))
280145510Sdarrenr				usage();
281145510Sdarrenr			rw = 1;
282145510Sdarrenr			set = 1;
283145510Sdarrenr			break;
284145510Sdarrenr		case 'W' :
285145510Sdarrenr			rw = 3;
286145510Sdarrenr			set = 1;
287145510Sdarrenr			break;
288145510Sdarrenr		case '?' :
289145510Sdarrenr		default :
290145510Sdarrenr			usage();
291145510Sdarrenr		}
292145510Sdarrenr
293145510Sdarrenr	if (ifs) {
294145510Sdarrenr		if (!filename || ns < 0)
295145510Sdarrenr			usage();
296145510Sdarrenr		if (ns == 0)
297145510Sdarrenr			return changenatif(ifs, filename);
298145510Sdarrenr		else
299145510Sdarrenr			return changestateif(ifs, filename);
300145510Sdarrenr	}
301145510Sdarrenr
302145510Sdarrenr	if ((ns >= 0) || (lock >= 0)) {
303145510Sdarrenr		if (lock >= 0)
304145510Sdarrenr			devfd = opendevice(NULL);
305145510Sdarrenr		else if (ns >= 0) {
306145510Sdarrenr			if (ns == 1)
307145510Sdarrenr				devfd = opendevice(IPSTATE_NAME);
308145510Sdarrenr			else if (ns == 0)
309145510Sdarrenr				devfd = opendevice(IPNAT_NAME);
310145510Sdarrenr		}
311145510Sdarrenr		if (devfd == -1)
312145510Sdarrenr			exit(1);
313145510Sdarrenr	}
314145510Sdarrenr
315145510Sdarrenr	if (lock >= 0)
316145510Sdarrenr		err = setlock(devfd, lock);
317145510Sdarrenr	else if (rw >= 0) {
318145510Sdarrenr		if (rw & 1) {	/* WRITE */
319145510Sdarrenr			if (rw & 2)
320145510Sdarrenr				err = writeall(dirname);
321145510Sdarrenr			else {
322145510Sdarrenr				if (ns == 0)
323145510Sdarrenr					err = writenat(devfd, filename);
324145510Sdarrenr				else if (ns == 1)
325145510Sdarrenr					err = writestate(devfd, filename);
326145510Sdarrenr			}
327145510Sdarrenr		} else {
328145510Sdarrenr			if (rw & 2)
329145510Sdarrenr				err = readall(dirname);
330145510Sdarrenr			else {
331145510Sdarrenr				if (ns == 0)
332145510Sdarrenr					err = readnat(devfd, filename);
333145510Sdarrenr				else if (ns == 1)
334145510Sdarrenr					err = readstate(devfd, filename);
335145510Sdarrenr			}
336145510Sdarrenr		}
337145510Sdarrenr	}
338145510Sdarrenr	return err;
339145510Sdarrenr}
340145510Sdarrenr
341145510Sdarrenr
342145510Sdarrenrint opendevice(ipfdev)
343145510Sdarrenrchar *ipfdev;
344145510Sdarrenr{
345145510Sdarrenr	int fd = -1;
346145510Sdarrenr
347145510Sdarrenr	if (opts & OPT_DONOTHING)
348145510Sdarrenr		return -2;
349145510Sdarrenr
350145510Sdarrenr	if (!ipfdev)
351145510Sdarrenr		ipfdev = IPL_NAME;
352145510Sdarrenr
353145510Sdarrenr	if ((fd = open(ipfdev, O_RDWR)) == -1)
354145510Sdarrenr		if ((fd = open(ipfdev, O_RDONLY)) == -1)
355145510Sdarrenr			perror("open device");
356145510Sdarrenr	return fd;
357145510Sdarrenr}
358145510Sdarrenr
359145510Sdarrenr
360145510Sdarrenrvoid closedevice(fd)
361145510Sdarrenrint fd;
362145510Sdarrenr{
363145510Sdarrenr	close(fd);
364145510Sdarrenr}
365145510Sdarrenr
366145510Sdarrenr
367145510Sdarrenrint setlock(fd, lock)
368145510Sdarrenrint fd, lock;
369145510Sdarrenr{
370145510Sdarrenr	if (opts & OPT_VERBOSE)
371145510Sdarrenr		printf("Turn lock %s\n", lock ? "on" : "off");
372145510Sdarrenr	if (!(opts & OPT_DONOTHING)) {
373145510Sdarrenr		if (ioctl(fd, SIOCSTLCK, &lock) == -1) {
374145510Sdarrenr			perror("SIOCSTLCK");
375145510Sdarrenr			return 1;
376145510Sdarrenr		}
377145510Sdarrenr		if (opts & OPT_VERBOSE)
378145510Sdarrenr			printf("Lock now %s\n", lock ? "on" : "off");
379145510Sdarrenr	}
380145510Sdarrenr	return 0;
381145510Sdarrenr}
382145510Sdarrenr
383145510Sdarrenr
384145510Sdarrenrint writestate(fd, file)
385145510Sdarrenrint fd;
386145510Sdarrenrchar *file;
387145510Sdarrenr{
388145510Sdarrenr	ipstate_save_t ips, *ipsp;
389145510Sdarrenr	ipfobj_t obj;
390145510Sdarrenr	int wfd = -1;
391145510Sdarrenr
392145510Sdarrenr	if (!file)
393145510Sdarrenr		file = IPF_STATEFILE;
394145510Sdarrenr
395145510Sdarrenr	wfd = open(file, O_WRONLY|O_TRUNC|O_CREAT, 0600);
396145510Sdarrenr	if (wfd == -1) {
397145510Sdarrenr		fprintf(stderr, "%s ", file);
398145510Sdarrenr		perror("state:open");
399145510Sdarrenr		return 1;
400145510Sdarrenr	}
401145510Sdarrenr
402145510Sdarrenr	ipsp = &ips;
403145510Sdarrenr	bzero((char *)&obj, sizeof(obj));
404145510Sdarrenr	bzero((char *)ipsp, sizeof(ips));
405145510Sdarrenr
406145510Sdarrenr	obj.ipfo_rev = IPFILTER_VERSION;
407145510Sdarrenr	obj.ipfo_size = sizeof(*ipsp);
408145510Sdarrenr	obj.ipfo_type = IPFOBJ_STATESAVE;
409145510Sdarrenr	obj.ipfo_ptr = ipsp;
410145510Sdarrenr
411145510Sdarrenr	do {
412145510Sdarrenr
413145510Sdarrenr		if (opts & OPT_VERBOSE)
414145510Sdarrenr			printf("Getting state from addr %p\n", ips.ips_next);
415145510Sdarrenr		if (ioctl(fd, SIOCSTGET, &obj)) {
416145510Sdarrenr			if (errno == ENOENT)
417145510Sdarrenr				break;
418145510Sdarrenr			perror("state:SIOCSTGET");
419145510Sdarrenr			close(wfd);
420145510Sdarrenr			return 1;
421145510Sdarrenr		}
422145510Sdarrenr		if (opts & OPT_VERBOSE)
423145510Sdarrenr			printf("Got state next %p\n", ips.ips_next);
424145510Sdarrenr		if (write(wfd, ipsp, sizeof(ips)) != sizeof(ips)) {
425145510Sdarrenr			perror("state:write");
426145510Sdarrenr			close(wfd);
427145510Sdarrenr			return 1;
428145510Sdarrenr		}
429145510Sdarrenr	} while (ips.ips_next != NULL);
430145510Sdarrenr	close(wfd);
431145510Sdarrenr
432145510Sdarrenr	return 0;
433145510Sdarrenr}
434145510Sdarrenr
435145510Sdarrenr
436145510Sdarrenrint readstate(fd, file)
437145510Sdarrenrint fd;
438145510Sdarrenrchar *file;
439145510Sdarrenr{
440145510Sdarrenr	ipstate_save_t ips, *is, *ipshead = NULL, *is1, *ipstail = NULL;
441145510Sdarrenr	int sfd = -1, i;
442145510Sdarrenr	ipfobj_t obj;
443145510Sdarrenr
444145510Sdarrenr	if (!file)
445145510Sdarrenr		file = IPF_STATEFILE;
446145510Sdarrenr
447145510Sdarrenr	sfd = open(file, O_RDONLY, 0600);
448145510Sdarrenr	if (sfd == -1) {
449145510Sdarrenr		fprintf(stderr, "%s ", file);
450145510Sdarrenr		perror("open");
451145510Sdarrenr		return 1;
452145510Sdarrenr	}
453145510Sdarrenr
454145510Sdarrenr	bzero((char *)&ips, sizeof(ips));
455145510Sdarrenr
456145510Sdarrenr	/*
457145510Sdarrenr	 * 1. Read all state information in.
458145510Sdarrenr	 */
459145510Sdarrenr	do {
460145510Sdarrenr		i = read(sfd, &ips, sizeof(ips));
461145510Sdarrenr		if (i == -1) {
462145510Sdarrenr			perror("read");
463161357Sguido			goto freeipshead;
464145510Sdarrenr		}
465145510Sdarrenr		if (i == 0)
466145510Sdarrenr			break;
467145510Sdarrenr		if (i != sizeof(ips)) {
468145510Sdarrenr			fprintf(stderr, "state:incomplete read: %d != %d\n",
469145510Sdarrenr				i, (int)sizeof(ips));
470161357Sguido			goto freeipshead;
471145510Sdarrenr		}
472145510Sdarrenr		is = (ipstate_save_t *)malloc(sizeof(*is));
473161357Sguido		if (is == NULL) {
474145510Sdarrenr			fprintf(stderr, "malloc failed\n");
475161357Sguido			goto freeipshead;
476145510Sdarrenr		}
477145510Sdarrenr
478145510Sdarrenr		bcopy((char *)&ips, (char *)is, sizeof(ips));
479145510Sdarrenr
480145510Sdarrenr		/*
481145510Sdarrenr		 * Check to see if this is the first state entry that will
482145510Sdarrenr		 * reference a particular rule and if so, flag it as such
483145510Sdarrenr		 * else just adjust the rule pointer to become a pointer to
484145510Sdarrenr		 * the other.  We do this so we have a means later for tracking
485145510Sdarrenr		 * who is referencing us when we get back the real pointer
486145510Sdarrenr		 * in is_rule after doing the ioctl.
487145510Sdarrenr		 */
488145510Sdarrenr		for (is1 = ipshead; is1 != NULL; is1 = is1->ips_next)
489145510Sdarrenr			if (is1->ips_rule == is->ips_rule)
490145510Sdarrenr				break;
491145510Sdarrenr		if (is1 == NULL)
492145510Sdarrenr			is->ips_is.is_flags |= SI_NEWFR;
493145510Sdarrenr		else
494145510Sdarrenr			is->ips_rule = (void *)&is1->ips_rule;
495145510Sdarrenr
496145510Sdarrenr		/*
497145510Sdarrenr		 * Use a tail-queue type list (add things to the end)..
498145510Sdarrenr		 */
499145510Sdarrenr		is->ips_next = NULL;
500145510Sdarrenr		if (!ipshead)
501145510Sdarrenr			ipshead = is;
502145510Sdarrenr		if (ipstail)
503145510Sdarrenr			ipstail->ips_next = is;
504145510Sdarrenr		ipstail = is;
505145510Sdarrenr	} while (1);
506145510Sdarrenr
507145510Sdarrenr	close(sfd);
508145510Sdarrenr
509145510Sdarrenr	obj.ipfo_rev = IPFILTER_VERSION;
510145510Sdarrenr	obj.ipfo_size = sizeof(*is);
511145510Sdarrenr	obj.ipfo_type = IPFOBJ_STATESAVE;
512145510Sdarrenr
513161357Sguido	while ((is = ipshead) != NULL) {
514145510Sdarrenr		if (opts & OPT_VERBOSE)
515145510Sdarrenr			printf("Loading new state table entry\n");
516145510Sdarrenr		if (is->ips_is.is_flags & SI_NEWFR) {
517145510Sdarrenr			if (opts & OPT_VERBOSE)
518145510Sdarrenr				printf("Loading new filter rule\n");
519145510Sdarrenr		}
520145510Sdarrenr
521145510Sdarrenr		obj.ipfo_ptr = is;
522145510Sdarrenr		if (!(opts & OPT_DONOTHING))
523145510Sdarrenr			if (ioctl(fd, SIOCSTPUT, &obj)) {
524145510Sdarrenr				perror("SIOCSTPUT");
525161357Sguido				goto freeipshead;
526145510Sdarrenr			}
527145510Sdarrenr
528145510Sdarrenr		if (is->ips_is.is_flags & SI_NEWFR) {
529145510Sdarrenr			if (opts & OPT_VERBOSE)
530145510Sdarrenr				printf("Real rule addr %p\n", is->ips_rule);
531145510Sdarrenr			for (is1 = is->ips_next; is1; is1 = is1->ips_next)
532145510Sdarrenr				if (is1->ips_rule == (frentry_t *)&is->ips_rule)
533145510Sdarrenr					is1->ips_rule = is->ips_rule;
534145510Sdarrenr		}
535161357Sguido
536161357Sguido		ipshead = is->ips_next;
537161357Sguido		free(is);
538145510Sdarrenr	}
539145510Sdarrenr
540145510Sdarrenr	return 0;
541161357Sguido
542161357Sguidofreeipshead:
543161357Sguido	while ((is = ipshead) != NULL) {
544161357Sguido		ipshead = is->ips_next;
545161357Sguido		free(is);
546161357Sguido	}
547161357Sguido	if (sfd != -1)
548161357Sguido		close(sfd);
549161357Sguido	return 1;
550145510Sdarrenr}
551145510Sdarrenr
552145510Sdarrenr
553145510Sdarrenrint readnat(fd, file)
554145510Sdarrenrint fd;
555145510Sdarrenrchar *file;
556145510Sdarrenr{
557145510Sdarrenr	nat_save_t ipn, *in, *ipnhead = NULL, *in1, *ipntail = NULL;
558145510Sdarrenr	ipfobj_t obj;
559145510Sdarrenr	int nfd, i;
560145510Sdarrenr	nat_t *nat;
561145510Sdarrenr	char *s;
562145510Sdarrenr	int n;
563145510Sdarrenr
564145510Sdarrenr	nfd = -1;
565145510Sdarrenr	in = NULL;
566145510Sdarrenr	ipnhead = NULL;
567145510Sdarrenr	ipntail = NULL;
568145510Sdarrenr
569145510Sdarrenr	if (!file)
570145510Sdarrenr		file = IPF_NATFILE;
571145510Sdarrenr
572145510Sdarrenr	nfd = open(file, O_RDONLY);
573145510Sdarrenr	if (nfd == -1) {
574145510Sdarrenr		fprintf(stderr, "%s ", file);
575145510Sdarrenr		perror("nat:open");
576145510Sdarrenr		return 1;
577145510Sdarrenr	}
578145510Sdarrenr
579145510Sdarrenr	bzero((char *)&ipn, sizeof(ipn));
580145510Sdarrenr
581145510Sdarrenr	/*
582145510Sdarrenr	 * 1. Read all state information in.
583145510Sdarrenr	 */
584145510Sdarrenr	do {
585145510Sdarrenr		i = read(nfd, &ipn, sizeof(ipn));
586145510Sdarrenr		if (i == -1) {
587145510Sdarrenr			perror("read");
588161357Sguido			goto freenathead;
589145510Sdarrenr		}
590145510Sdarrenr		if (i == 0)
591145510Sdarrenr			break;
592145510Sdarrenr		if (i != sizeof(ipn)) {
593145510Sdarrenr			fprintf(stderr, "nat:incomplete read: %d != %d\n",
594145510Sdarrenr				i, (int)sizeof(ipn));
595161357Sguido			goto freenathead;
596145510Sdarrenr		}
597145510Sdarrenr
598145510Sdarrenr		in = (nat_save_t *)malloc(ipn.ipn_dsize);
599161357Sguido		if (in == NULL) {
600161357Sguido			fprintf(stderr, "nat:cannot malloc nat save atruct\n");
601161357Sguido			goto freenathead;
602161357Sguido		}
603145510Sdarrenr
604145510Sdarrenr		if (ipn.ipn_dsize > sizeof(ipn)) {
605145510Sdarrenr			n = ipn.ipn_dsize - sizeof(ipn);
606145510Sdarrenr			if (n > 0) {
607145510Sdarrenr				s = in->ipn_data + sizeof(in->ipn_data);
608145510Sdarrenr 				i = read(nfd, s, n);
609145510Sdarrenr				if (i == 0)
610145510Sdarrenr					break;
611145510Sdarrenr				if (i != n) {
612145510Sdarrenr					fprintf(stderr,
613145510Sdarrenr					    "nat:incomplete read: %d != %d\n",
614145510Sdarrenr					    i, n);
615161357Sguido					goto freenathead;
616145510Sdarrenr				}
617145510Sdarrenr			}
618145510Sdarrenr		}
619145510Sdarrenr		bcopy((char *)&ipn, (char *)in, sizeof(ipn));
620145510Sdarrenr
621145510Sdarrenr		/*
622145510Sdarrenr		 * Check to see if this is the first NAT entry that will
623145510Sdarrenr		 * reference a particular rule and if so, flag it as such
624145510Sdarrenr		 * else just adjust the rule pointer to become a pointer to
625145510Sdarrenr		 * the other.  We do this so we have a means later for tracking
626145510Sdarrenr		 * who is referencing us when we get back the real pointer
627145510Sdarrenr		 * in is_rule after doing the ioctl.
628145510Sdarrenr		 */
629145510Sdarrenr		nat = &in->ipn_nat;
630145510Sdarrenr		if (nat->nat_fr != NULL) {
631145510Sdarrenr			for (in1 = ipnhead; in1 != NULL; in1 = in1->ipn_next)
632145510Sdarrenr				if (in1->ipn_rule == nat->nat_fr)
633145510Sdarrenr					break;
634145510Sdarrenr			if (in1 == NULL)
635145510Sdarrenr				nat->nat_flags |= SI_NEWFR;
636145510Sdarrenr			else
637145510Sdarrenr				nat->nat_fr = &in1->ipn_fr;
638145510Sdarrenr		}
639145510Sdarrenr
640145510Sdarrenr		/*
641145510Sdarrenr		 * Use a tail-queue type list (add things to the end)..
642145510Sdarrenr		 */
643145510Sdarrenr		in->ipn_next = NULL;
644145510Sdarrenr		if (!ipnhead)
645145510Sdarrenr			ipnhead = in;
646145510Sdarrenr		if (ipntail)
647145510Sdarrenr			ipntail->ipn_next = in;
648145510Sdarrenr		ipntail = in;
649145510Sdarrenr	} while (1);
650145510Sdarrenr
651145510Sdarrenr	close(nfd);
652145510Sdarrenr	nfd = -1;
653145510Sdarrenr
654145510Sdarrenr	obj.ipfo_rev = IPFILTER_VERSION;
655145510Sdarrenr	obj.ipfo_type = IPFOBJ_NATSAVE;
656145510Sdarrenr
657161357Sguido	while ((in = ipnhead) != NULL) {
658145510Sdarrenr		if (opts & OPT_VERBOSE)
659145510Sdarrenr			printf("Loading new NAT table entry\n");
660145510Sdarrenr		nat = &in->ipn_nat;
661145510Sdarrenr		if (nat->nat_flags & SI_NEWFR) {
662145510Sdarrenr			if (opts & OPT_VERBOSE)
663145510Sdarrenr				printf("Loading new filter rule\n");
664145510Sdarrenr		}
665145510Sdarrenr
666145510Sdarrenr		obj.ipfo_ptr = in;
667145510Sdarrenr		obj.ipfo_size = in->ipn_dsize;
668145510Sdarrenr		if (!(opts & OPT_DONOTHING))
669145510Sdarrenr			if (ioctl(fd, SIOCSTPUT, &obj)) {
670145510Sdarrenr				fprintf(stderr, "in=%p:", in);
671145510Sdarrenr				perror("SIOCSTPUT");
672145510Sdarrenr				return 1;
673145510Sdarrenr			}
674145510Sdarrenr
675145510Sdarrenr		if (nat->nat_flags & SI_NEWFR) {
676145510Sdarrenr			if (opts & OPT_VERBOSE)
677145510Sdarrenr				printf("Real rule addr %p\n", nat->nat_fr);
678145510Sdarrenr			for (in1 = in->ipn_next; in1; in1 = in1->ipn_next)
679145510Sdarrenr				if (in1->ipn_rule == &in->ipn_fr)
680145510Sdarrenr					in1->ipn_rule = nat->nat_fr;
681145510Sdarrenr		}
682161357Sguido
683161357Sguido		ipnhead = in->ipn_next;
684161357Sguido		free(in);
685145510Sdarrenr	}
686145510Sdarrenr
687145510Sdarrenr	return 0;
688161357Sguido
689161357Sguidofreenathead:
690161357Sguido	while ((in = ipnhead) != NULL) {
691161357Sguido		ipnhead = in->ipn_next;
692161357Sguido		free(in);
693161357Sguido	}
694161357Sguido	if (nfd != -1)
695161357Sguido		close(nfd);
696161357Sguido	return 1;
697145510Sdarrenr}
698145510Sdarrenr
699145510Sdarrenr
700145510Sdarrenrint writenat(fd, file)
701145510Sdarrenrint fd;
702145510Sdarrenrchar *file;
703145510Sdarrenr{
704145510Sdarrenr	nat_save_t *ipnp = NULL, *next = NULL;
705145510Sdarrenr	ipfobj_t obj;
706145510Sdarrenr	int nfd = -1;
707145510Sdarrenr	natget_t ng;
708145510Sdarrenr
709145510Sdarrenr	if (!file)
710145510Sdarrenr		file = IPF_NATFILE;
711145510Sdarrenr
712145510Sdarrenr	nfd = open(file, O_WRONLY|O_TRUNC|O_CREAT, 0600);
713145510Sdarrenr	if (nfd == -1) {
714145510Sdarrenr		fprintf(stderr, "%s ", file);
715145510Sdarrenr		perror("nat:open");
716145510Sdarrenr		return 1;
717145510Sdarrenr	}
718145510Sdarrenr
719145510Sdarrenr	obj.ipfo_rev = IPFILTER_VERSION;
720145510Sdarrenr	obj.ipfo_type = IPFOBJ_NATSAVE;
721145510Sdarrenr
722145510Sdarrenr	do {
723145510Sdarrenr		if (opts & OPT_VERBOSE)
724145510Sdarrenr			printf("Getting nat from addr %p\n", ipnp);
725145510Sdarrenr		ng.ng_ptr = next;
726145510Sdarrenr		ng.ng_sz = 0;
727145510Sdarrenr		if (ioctl(fd, SIOCSTGSZ, &ng)) {
728145510Sdarrenr			perror("nat:SIOCSTGSZ");
729145510Sdarrenr			close(nfd);
730145510Sdarrenr			if (ipnp != NULL)
731145510Sdarrenr				free(ipnp);
732145510Sdarrenr			return 1;
733145510Sdarrenr		}
734145510Sdarrenr
735145510Sdarrenr		if (opts & OPT_VERBOSE)
736145510Sdarrenr			printf("NAT size %d from %p\n", ng.ng_sz, ng.ng_ptr);
737145510Sdarrenr
738145510Sdarrenr		if (ng.ng_sz == 0)
739145510Sdarrenr			break;
740145510Sdarrenr
741145510Sdarrenr		if (!ipnp)
742145510Sdarrenr			ipnp = malloc(ng.ng_sz);
743145510Sdarrenr		else
744145510Sdarrenr			ipnp = realloc((char *)ipnp, ng.ng_sz);
745145510Sdarrenr		if (!ipnp) {
746145510Sdarrenr			fprintf(stderr,
747145510Sdarrenr				"malloc for %d bytes failed\n", ng.ng_sz);
748145510Sdarrenr			break;
749145510Sdarrenr		}
750145510Sdarrenr
751145510Sdarrenr		bzero((char *)ipnp, ng.ng_sz);
752145510Sdarrenr		obj.ipfo_size = ng.ng_sz;
753145510Sdarrenr		obj.ipfo_ptr = ipnp;
754145510Sdarrenr		ipnp->ipn_dsize = ng.ng_sz;
755145510Sdarrenr		ipnp->ipn_next = next;
756145510Sdarrenr		if (ioctl(fd, SIOCSTGET, &obj)) {
757145510Sdarrenr			if (errno == ENOENT)
758145510Sdarrenr				break;
759145510Sdarrenr			perror("nat:SIOCSTGET");
760145510Sdarrenr			close(nfd);
761145510Sdarrenr			free(ipnp);
762145510Sdarrenr			return 1;
763145510Sdarrenr		}
764145510Sdarrenr
765145510Sdarrenr		if (opts & OPT_VERBOSE)
766145510Sdarrenr			printf("Got nat next %p ipn_dsize %d ng_sz %d\n",
767145510Sdarrenr				ipnp->ipn_next, ipnp->ipn_dsize, ng.ng_sz);
768145510Sdarrenr		if (write(nfd, ipnp, ipnp->ipn_dsize) != ipnp->ipn_dsize) {
769145510Sdarrenr			perror("nat:write");
770145510Sdarrenr			close(nfd);
771145510Sdarrenr			free(ipnp);
772145510Sdarrenr			return 1;
773145510Sdarrenr		}
774145510Sdarrenr		next = ipnp->ipn_next;
775145510Sdarrenr	} while (ipnp && next);
776145510Sdarrenr	if (ipnp != NULL)
777145510Sdarrenr		free(ipnp);
778145510Sdarrenr	close(nfd);
779145510Sdarrenr
780145510Sdarrenr	return 0;
781145510Sdarrenr}
782145510Sdarrenr
783145510Sdarrenr
784145510Sdarrenrint writeall(dirname)
785145510Sdarrenrchar *dirname;
786145510Sdarrenr{
787145510Sdarrenr	int fd, devfd;
788145510Sdarrenr
789145510Sdarrenr	if (!dirname)
790145510Sdarrenr		dirname = IPF_SAVEDIR;
791145510Sdarrenr
792145510Sdarrenr	if (chdir(dirname)) {
793145510Sdarrenr		fprintf(stderr, "IPF_SAVEDIR=%s: ", dirname);
794145510Sdarrenr		perror("chdir(IPF_SAVEDIR)");
795145510Sdarrenr		return 1;
796145510Sdarrenr	}
797145510Sdarrenr
798145510Sdarrenr	fd = opendevice(NULL);
799145510Sdarrenr	if (fd == -1)
800145510Sdarrenr		return 1;
801145510Sdarrenr	if (setlock(fd, 1)) {
802145510Sdarrenr		close(fd);
803145510Sdarrenr		return 1;
804145510Sdarrenr	}
805145510Sdarrenr
806145510Sdarrenr	devfd = opendevice(IPSTATE_NAME);
807145510Sdarrenr	if (devfd == -1)
808145510Sdarrenr		goto bad;
809145510Sdarrenr	if (writestate(devfd, NULL))
810145510Sdarrenr		goto bad;
811145510Sdarrenr	close(devfd);
812145510Sdarrenr
813145510Sdarrenr	devfd = opendevice(IPNAT_NAME);
814145510Sdarrenr	if (devfd == -1)
815145510Sdarrenr		goto bad;
816145510Sdarrenr	if (writenat(devfd, NULL))
817145510Sdarrenr		goto bad;
818145510Sdarrenr	close(devfd);
819145510Sdarrenr
820145510Sdarrenr	if (setlock(fd, 0)) {
821145510Sdarrenr		close(fd);
822145510Sdarrenr		return 1;
823145510Sdarrenr	}
824145510Sdarrenr
825145510Sdarrenr	close(fd);
826145510Sdarrenr	return 0;
827145510Sdarrenr
828145510Sdarrenrbad:
829145510Sdarrenr	setlock(fd, 0);
830145510Sdarrenr	close(fd);
831145510Sdarrenr	return 1;
832145510Sdarrenr}
833145510Sdarrenr
834145510Sdarrenr
835145510Sdarrenrint readall(dirname)
836145510Sdarrenrchar *dirname;
837145510Sdarrenr{
838145510Sdarrenr	int fd, devfd;
839145510Sdarrenr
840145510Sdarrenr	if (!dirname)
841145510Sdarrenr		dirname = IPF_SAVEDIR;
842145510Sdarrenr
843145510Sdarrenr	if (chdir(dirname)) {
844145510Sdarrenr		perror("chdir(IPF_SAVEDIR)");
845145510Sdarrenr		return 1;
846145510Sdarrenr	}
847145510Sdarrenr
848145510Sdarrenr	fd = opendevice(NULL);
849145510Sdarrenr	if (fd == -1)
850145510Sdarrenr		return 1;
851145510Sdarrenr	if (setlock(fd, 1)) {
852145510Sdarrenr		close(fd);
853145510Sdarrenr		return 1;
854145510Sdarrenr	}
855145510Sdarrenr
856145510Sdarrenr	devfd = opendevice(IPSTATE_NAME);
857145510Sdarrenr	if (devfd == -1)
858145510Sdarrenr		return 1;
859145510Sdarrenr	if (readstate(devfd, NULL))
860145510Sdarrenr		return 1;
861145510Sdarrenr	close(devfd);
862145510Sdarrenr
863145510Sdarrenr	devfd = opendevice(IPNAT_NAME);
864145510Sdarrenr	if (devfd == -1)
865145510Sdarrenr		return 1;
866145510Sdarrenr	if (readnat(devfd, NULL))
867145510Sdarrenr		return 1;
868145510Sdarrenr	close(devfd);
869145510Sdarrenr
870145510Sdarrenr	if (setlock(fd, 0)) {
871145510Sdarrenr		close(fd);
872145510Sdarrenr		return 1;
873145510Sdarrenr	}
874145510Sdarrenr
875145510Sdarrenr	return 0;
876145510Sdarrenr}
877