ipfs.c revision 145519
1145519Sdarrenr/*	$FreeBSD: head/contrib/ipfilter/tools/ipfs.c 145519 2005-04-25 18:20:15Z darrenr $	*/
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"
44145510Sdarrenr#include "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");
463145510Sdarrenr			close(sfd);
464145510Sdarrenr			return 1;
465145510Sdarrenr		}
466145510Sdarrenr		if (i == 0)
467145510Sdarrenr			break;
468145510Sdarrenr		if (i != sizeof(ips)) {
469145510Sdarrenr			fprintf(stderr, "state:incomplete read: %d != %d\n",
470145510Sdarrenr				i, (int)sizeof(ips));
471145510Sdarrenr			close(sfd);
472145510Sdarrenr			return 1;
473145510Sdarrenr		}
474145510Sdarrenr		is = (ipstate_save_t *)malloc(sizeof(*is));
475145510Sdarrenr		if(!is) {
476145510Sdarrenr			fprintf(stderr, "malloc failed\n");
477145510Sdarrenr			return 1;
478145510Sdarrenr		}
479145510Sdarrenr
480145510Sdarrenr		bcopy((char *)&ips, (char *)is, sizeof(ips));
481145510Sdarrenr
482145510Sdarrenr		/*
483145510Sdarrenr		 * Check to see if this is the first state entry that will
484145510Sdarrenr		 * reference a particular rule and if so, flag it as such
485145510Sdarrenr		 * else just adjust the rule pointer to become a pointer to
486145510Sdarrenr		 * the other.  We do this so we have a means later for tracking
487145510Sdarrenr		 * who is referencing us when we get back the real pointer
488145510Sdarrenr		 * in is_rule after doing the ioctl.
489145510Sdarrenr		 */
490145510Sdarrenr		for (is1 = ipshead; is1 != NULL; is1 = is1->ips_next)
491145510Sdarrenr			if (is1->ips_rule == is->ips_rule)
492145510Sdarrenr				break;
493145510Sdarrenr		if (is1 == NULL)
494145510Sdarrenr			is->ips_is.is_flags |= SI_NEWFR;
495145510Sdarrenr		else
496145510Sdarrenr			is->ips_rule = (void *)&is1->ips_rule;
497145510Sdarrenr
498145510Sdarrenr		/*
499145510Sdarrenr		 * Use a tail-queue type list (add things to the end)..
500145510Sdarrenr		 */
501145510Sdarrenr		is->ips_next = NULL;
502145510Sdarrenr		if (!ipshead)
503145510Sdarrenr			ipshead = is;
504145510Sdarrenr		if (ipstail)
505145510Sdarrenr			ipstail->ips_next = is;
506145510Sdarrenr		ipstail = is;
507145510Sdarrenr	} while (1);
508145510Sdarrenr
509145510Sdarrenr	close(sfd);
510145510Sdarrenr
511145510Sdarrenr	obj.ipfo_rev = IPFILTER_VERSION;
512145510Sdarrenr	obj.ipfo_size = sizeof(*is);
513145510Sdarrenr	obj.ipfo_type = IPFOBJ_STATESAVE;
514145510Sdarrenr
515145510Sdarrenr	for (is = ipshead; is; is = is->ips_next) {
516145510Sdarrenr		if (opts & OPT_VERBOSE)
517145510Sdarrenr			printf("Loading new state table entry\n");
518145510Sdarrenr		if (is->ips_is.is_flags & SI_NEWFR) {
519145510Sdarrenr			if (opts & OPT_VERBOSE)
520145510Sdarrenr				printf("Loading new filter rule\n");
521145510Sdarrenr		}
522145510Sdarrenr
523145510Sdarrenr		obj.ipfo_ptr = is;
524145510Sdarrenr		if (!(opts & OPT_DONOTHING))
525145510Sdarrenr			if (ioctl(fd, SIOCSTPUT, &obj)) {
526145510Sdarrenr				perror("SIOCSTPUT");
527145510Sdarrenr				return 1;
528145510Sdarrenr			}
529145510Sdarrenr
530145510Sdarrenr		if (is->ips_is.is_flags & SI_NEWFR) {
531145510Sdarrenr			if (opts & OPT_VERBOSE)
532145510Sdarrenr				printf("Real rule addr %p\n", is->ips_rule);
533145510Sdarrenr			for (is1 = is->ips_next; is1; is1 = is1->ips_next)
534145510Sdarrenr				if (is1->ips_rule == (frentry_t *)&is->ips_rule)
535145510Sdarrenr					is1->ips_rule = is->ips_rule;
536145510Sdarrenr		}
537145510Sdarrenr	}
538145510Sdarrenr
539145510Sdarrenr	return 0;
540145510Sdarrenr}
541145510Sdarrenr
542145510Sdarrenr
543145510Sdarrenrint readnat(fd, file)
544145510Sdarrenrint fd;
545145510Sdarrenrchar *file;
546145510Sdarrenr{
547145510Sdarrenr	nat_save_t ipn, *in, *ipnhead = NULL, *in1, *ipntail = NULL;
548145510Sdarrenr	ipfobj_t obj;
549145510Sdarrenr	int nfd, i;
550145510Sdarrenr	nat_t *nat;
551145510Sdarrenr	char *s;
552145510Sdarrenr	int n;
553145510Sdarrenr
554145510Sdarrenr	nfd = -1;
555145510Sdarrenr	in = NULL;
556145510Sdarrenr	ipnhead = NULL;
557145510Sdarrenr	ipntail = NULL;
558145510Sdarrenr
559145510Sdarrenr	if (!file)
560145510Sdarrenr		file = IPF_NATFILE;
561145510Sdarrenr
562145510Sdarrenr	nfd = open(file, O_RDONLY);
563145510Sdarrenr	if (nfd == -1) {
564145510Sdarrenr		fprintf(stderr, "%s ", file);
565145510Sdarrenr		perror("nat:open");
566145510Sdarrenr		return 1;
567145510Sdarrenr	}
568145510Sdarrenr
569145510Sdarrenr	bzero((char *)&ipn, sizeof(ipn));
570145510Sdarrenr
571145510Sdarrenr	/*
572145510Sdarrenr	 * 1. Read all state information in.
573145510Sdarrenr	 */
574145510Sdarrenr	do {
575145510Sdarrenr		i = read(nfd, &ipn, sizeof(ipn));
576145510Sdarrenr		if (i == -1) {
577145510Sdarrenr			perror("read");
578145510Sdarrenr			close(nfd);
579145510Sdarrenr			return 1;
580145510Sdarrenr		}
581145510Sdarrenr		if (i == 0)
582145510Sdarrenr			break;
583145510Sdarrenr		if (i != sizeof(ipn)) {
584145510Sdarrenr			fprintf(stderr, "nat:incomplete read: %d != %d\n",
585145510Sdarrenr				i, (int)sizeof(ipn));
586145510Sdarrenr			close(nfd);
587145510Sdarrenr			return 1;
588145510Sdarrenr		}
589145510Sdarrenr
590145510Sdarrenr		in = (nat_save_t *)malloc(ipn.ipn_dsize);
591145510Sdarrenr		if (!in)
592145510Sdarrenr			break;
593145510Sdarrenr
594145510Sdarrenr		if (ipn.ipn_dsize > sizeof(ipn)) {
595145510Sdarrenr			n = ipn.ipn_dsize - sizeof(ipn);
596145510Sdarrenr			if (n > 0) {
597145510Sdarrenr				s = in->ipn_data + sizeof(in->ipn_data);
598145510Sdarrenr 				i = read(nfd, s, n);
599145510Sdarrenr				if (i == 0)
600145510Sdarrenr					break;
601145510Sdarrenr				if (i != n) {
602145510Sdarrenr					fprintf(stderr,
603145510Sdarrenr					    "nat:incomplete read: %d != %d\n",
604145510Sdarrenr					    i, n);
605145510Sdarrenr					close(nfd);
606145510Sdarrenr					return 1;
607145510Sdarrenr				}
608145510Sdarrenr			}
609145510Sdarrenr		}
610145510Sdarrenr		bcopy((char *)&ipn, (char *)in, sizeof(ipn));
611145510Sdarrenr
612145510Sdarrenr		/*
613145510Sdarrenr		 * Check to see if this is the first NAT entry that will
614145510Sdarrenr		 * reference a particular rule and if so, flag it as such
615145510Sdarrenr		 * else just adjust the rule pointer to become a pointer to
616145510Sdarrenr		 * the other.  We do this so we have a means later for tracking
617145510Sdarrenr		 * who is referencing us when we get back the real pointer
618145510Sdarrenr		 * in is_rule after doing the ioctl.
619145510Sdarrenr		 */
620145510Sdarrenr		nat = &in->ipn_nat;
621145510Sdarrenr		if (nat->nat_fr != NULL) {
622145510Sdarrenr			for (in1 = ipnhead; in1 != NULL; in1 = in1->ipn_next)
623145510Sdarrenr				if (in1->ipn_rule == nat->nat_fr)
624145510Sdarrenr					break;
625145510Sdarrenr			if (in1 == NULL)
626145510Sdarrenr				nat->nat_flags |= SI_NEWFR;
627145510Sdarrenr			else
628145510Sdarrenr				nat->nat_fr = &in1->ipn_fr;
629145510Sdarrenr		}
630145510Sdarrenr
631145510Sdarrenr		/*
632145510Sdarrenr		 * Use a tail-queue type list (add things to the end)..
633145510Sdarrenr		 */
634145510Sdarrenr		in->ipn_next = NULL;
635145510Sdarrenr		if (!ipnhead)
636145510Sdarrenr			ipnhead = in;
637145510Sdarrenr		if (ipntail)
638145510Sdarrenr			ipntail->ipn_next = in;
639145510Sdarrenr		ipntail = in;
640145510Sdarrenr	} while (1);
641145510Sdarrenr
642145510Sdarrenr	close(nfd);
643145510Sdarrenr	nfd = -1;
644145510Sdarrenr
645145510Sdarrenr	obj.ipfo_rev = IPFILTER_VERSION;
646145510Sdarrenr	obj.ipfo_type = IPFOBJ_NATSAVE;
647145510Sdarrenr
648145510Sdarrenr	for (in = ipnhead; in; in = in->ipn_next) {
649145510Sdarrenr		if (opts & OPT_VERBOSE)
650145510Sdarrenr			printf("Loading new NAT table entry\n");
651145510Sdarrenr		nat = &in->ipn_nat;
652145510Sdarrenr		if (nat->nat_flags & SI_NEWFR) {
653145510Sdarrenr			if (opts & OPT_VERBOSE)
654145510Sdarrenr				printf("Loading new filter rule\n");
655145510Sdarrenr		}
656145510Sdarrenr
657145510Sdarrenr		obj.ipfo_ptr = in;
658145510Sdarrenr		obj.ipfo_size = in->ipn_dsize;
659145510Sdarrenr		if (!(opts & OPT_DONOTHING))
660145510Sdarrenr			if (ioctl(fd, SIOCSTPUT, &obj)) {
661145510Sdarrenr				fprintf(stderr, "in=%p:", in);
662145510Sdarrenr				perror("SIOCSTPUT");
663145510Sdarrenr				return 1;
664145510Sdarrenr			}
665145510Sdarrenr
666145510Sdarrenr		if (nat->nat_flags & SI_NEWFR) {
667145510Sdarrenr			if (opts & OPT_VERBOSE)
668145510Sdarrenr				printf("Real rule addr %p\n", nat->nat_fr);
669145510Sdarrenr			for (in1 = in->ipn_next; in1; in1 = in1->ipn_next)
670145510Sdarrenr				if (in1->ipn_rule == &in->ipn_fr)
671145510Sdarrenr					in1->ipn_rule = nat->nat_fr;
672145510Sdarrenr		}
673145510Sdarrenr	}
674145510Sdarrenr
675145510Sdarrenr	return 0;
676145510Sdarrenr}
677145510Sdarrenr
678145510Sdarrenr
679145510Sdarrenrint writenat(fd, file)
680145510Sdarrenrint fd;
681145510Sdarrenrchar *file;
682145510Sdarrenr{
683145510Sdarrenr	nat_save_t *ipnp = NULL, *next = NULL;
684145510Sdarrenr	ipfobj_t obj;
685145510Sdarrenr	int nfd = -1;
686145510Sdarrenr	natget_t ng;
687145510Sdarrenr
688145510Sdarrenr	if (!file)
689145510Sdarrenr		file = IPF_NATFILE;
690145510Sdarrenr
691145510Sdarrenr	nfd = open(file, O_WRONLY|O_TRUNC|O_CREAT, 0600);
692145510Sdarrenr	if (nfd == -1) {
693145510Sdarrenr		fprintf(stderr, "%s ", file);
694145510Sdarrenr		perror("nat:open");
695145510Sdarrenr		return 1;
696145510Sdarrenr	}
697145510Sdarrenr
698145510Sdarrenr	obj.ipfo_rev = IPFILTER_VERSION;
699145510Sdarrenr	obj.ipfo_type = IPFOBJ_NATSAVE;
700145510Sdarrenr
701145510Sdarrenr	do {
702145510Sdarrenr		if (opts & OPT_VERBOSE)
703145510Sdarrenr			printf("Getting nat from addr %p\n", ipnp);
704145510Sdarrenr		ng.ng_ptr = next;
705145510Sdarrenr		ng.ng_sz = 0;
706145510Sdarrenr		if (ioctl(fd, SIOCSTGSZ, &ng)) {
707145510Sdarrenr			perror("nat:SIOCSTGSZ");
708145510Sdarrenr			close(nfd);
709145510Sdarrenr			if (ipnp != NULL)
710145510Sdarrenr				free(ipnp);
711145510Sdarrenr			return 1;
712145510Sdarrenr		}
713145510Sdarrenr
714145510Sdarrenr		if (opts & OPT_VERBOSE)
715145510Sdarrenr			printf("NAT size %d from %p\n", ng.ng_sz, ng.ng_ptr);
716145510Sdarrenr
717145510Sdarrenr		if (ng.ng_sz == 0)
718145510Sdarrenr			break;
719145510Sdarrenr
720145510Sdarrenr		if (!ipnp)
721145510Sdarrenr			ipnp = malloc(ng.ng_sz);
722145510Sdarrenr		else
723145510Sdarrenr			ipnp = realloc((char *)ipnp, ng.ng_sz);
724145510Sdarrenr		if (!ipnp) {
725145510Sdarrenr			fprintf(stderr,
726145510Sdarrenr				"malloc for %d bytes failed\n", ng.ng_sz);
727145510Sdarrenr			break;
728145510Sdarrenr		}
729145510Sdarrenr
730145510Sdarrenr		bzero((char *)ipnp, ng.ng_sz);
731145510Sdarrenr		obj.ipfo_size = ng.ng_sz;
732145510Sdarrenr		obj.ipfo_ptr = ipnp;
733145510Sdarrenr		ipnp->ipn_dsize = ng.ng_sz;
734145510Sdarrenr		ipnp->ipn_next = next;
735145510Sdarrenr		if (ioctl(fd, SIOCSTGET, &obj)) {
736145510Sdarrenr			if (errno == ENOENT)
737145510Sdarrenr				break;
738145510Sdarrenr			perror("nat:SIOCSTGET");
739145510Sdarrenr			close(nfd);
740145510Sdarrenr			free(ipnp);
741145510Sdarrenr			return 1;
742145510Sdarrenr		}
743145510Sdarrenr
744145510Sdarrenr		if (opts & OPT_VERBOSE)
745145510Sdarrenr			printf("Got nat next %p ipn_dsize %d ng_sz %d\n",
746145510Sdarrenr				ipnp->ipn_next, ipnp->ipn_dsize, ng.ng_sz);
747145510Sdarrenr		if (write(nfd, ipnp, ipnp->ipn_dsize) != ipnp->ipn_dsize) {
748145510Sdarrenr			perror("nat:write");
749145510Sdarrenr			close(nfd);
750145510Sdarrenr			free(ipnp);
751145510Sdarrenr			return 1;
752145510Sdarrenr		}
753145510Sdarrenr		next = ipnp->ipn_next;
754145510Sdarrenr	} while (ipnp && next);
755145510Sdarrenr	if (ipnp != NULL)
756145510Sdarrenr		free(ipnp);
757145510Sdarrenr	close(nfd);
758145510Sdarrenr
759145510Sdarrenr	return 0;
760145510Sdarrenr}
761145510Sdarrenr
762145510Sdarrenr
763145510Sdarrenrint writeall(dirname)
764145510Sdarrenrchar *dirname;
765145510Sdarrenr{
766145510Sdarrenr	int fd, devfd;
767145510Sdarrenr
768145510Sdarrenr	if (!dirname)
769145510Sdarrenr		dirname = IPF_SAVEDIR;
770145510Sdarrenr
771145510Sdarrenr	if (chdir(dirname)) {
772145510Sdarrenr		fprintf(stderr, "IPF_SAVEDIR=%s: ", dirname);
773145510Sdarrenr		perror("chdir(IPF_SAVEDIR)");
774145510Sdarrenr		return 1;
775145510Sdarrenr	}
776145510Sdarrenr
777145510Sdarrenr	fd = opendevice(NULL);
778145510Sdarrenr	if (fd == -1)
779145510Sdarrenr		return 1;
780145510Sdarrenr	if (setlock(fd, 1)) {
781145510Sdarrenr		close(fd);
782145510Sdarrenr		return 1;
783145510Sdarrenr	}
784145510Sdarrenr
785145510Sdarrenr	devfd = opendevice(IPSTATE_NAME);
786145510Sdarrenr	if (devfd == -1)
787145510Sdarrenr		goto bad;
788145510Sdarrenr	if (writestate(devfd, NULL))
789145510Sdarrenr		goto bad;
790145510Sdarrenr	close(devfd);
791145510Sdarrenr
792145510Sdarrenr	devfd = opendevice(IPNAT_NAME);
793145510Sdarrenr	if (devfd == -1)
794145510Sdarrenr		goto bad;
795145510Sdarrenr	if (writenat(devfd, NULL))
796145510Sdarrenr		goto bad;
797145510Sdarrenr	close(devfd);
798145510Sdarrenr
799145510Sdarrenr	if (setlock(fd, 0)) {
800145510Sdarrenr		close(fd);
801145510Sdarrenr		return 1;
802145510Sdarrenr	}
803145510Sdarrenr
804145510Sdarrenr	close(fd);
805145510Sdarrenr	return 0;
806145510Sdarrenr
807145510Sdarrenrbad:
808145510Sdarrenr	setlock(fd, 0);
809145510Sdarrenr	close(fd);
810145510Sdarrenr	return 1;
811145510Sdarrenr}
812145510Sdarrenr
813145510Sdarrenr
814145510Sdarrenrint readall(dirname)
815145510Sdarrenrchar *dirname;
816145510Sdarrenr{
817145510Sdarrenr	int fd, devfd;
818145510Sdarrenr
819145510Sdarrenr	if (!dirname)
820145510Sdarrenr		dirname = IPF_SAVEDIR;
821145510Sdarrenr
822145510Sdarrenr	if (chdir(dirname)) {
823145510Sdarrenr		perror("chdir(IPF_SAVEDIR)");
824145510Sdarrenr		return 1;
825145510Sdarrenr	}
826145510Sdarrenr
827145510Sdarrenr	fd = opendevice(NULL);
828145510Sdarrenr	if (fd == -1)
829145510Sdarrenr		return 1;
830145510Sdarrenr	if (setlock(fd, 1)) {
831145510Sdarrenr		close(fd);
832145510Sdarrenr		return 1;
833145510Sdarrenr	}
834145510Sdarrenr
835145510Sdarrenr	devfd = opendevice(IPSTATE_NAME);
836145510Sdarrenr	if (devfd == -1)
837145510Sdarrenr		return 1;
838145510Sdarrenr	if (readstate(devfd, NULL))
839145510Sdarrenr		return 1;
840145510Sdarrenr	close(devfd);
841145510Sdarrenr
842145510Sdarrenr	devfd = opendevice(IPNAT_NAME);
843145510Sdarrenr	if (devfd == -1)
844145510Sdarrenr		return 1;
845145510Sdarrenr	if (readnat(devfd, NULL))
846145510Sdarrenr		return 1;
847145510Sdarrenr	close(devfd);
848145510Sdarrenr
849145510Sdarrenr	if (setlock(fd, 0)) {
850145510Sdarrenr		close(fd);
851145510Sdarrenr		return 1;
852145510Sdarrenr	}
853145510Sdarrenr
854145510Sdarrenr	return 0;
855145510Sdarrenr}
856