xref: /netbsd-src/usr.sbin/pf/pfs/pfs.c (revision 8ee626c9fa19b110a740cae0b27b2678014c2a70)
1*8ee626c9Schristos /* $NetBSD: pfs.c,v 1.2 2015/06/16 23:04:14 christos Exp $ */
2ca38e323Sdegroote 
3ca38e323Sdegroote /*-
4ca38e323Sdegroote  * Copyright (c) 2010 The NetBSD Foundation, Inc.
5ca38e323Sdegroote  * All rights reserved.
6ca38e323Sdegroote  *
7ca38e323Sdegroote  * Redistribution and use in source and binary forms, with or without
8ca38e323Sdegroote  * modification, are permitted provided that the following conditions
9ca38e323Sdegroote  * are met:
10ca38e323Sdegroote  * 1. Redistributions of source code must retain the above copyright
11ca38e323Sdegroote  *    notice, this list of conditions and the following disclaimer.
12ca38e323Sdegroote  * 2. Redistributions in binary form must reproduce the above copyright
13ca38e323Sdegroote  *    notice, this list of conditions and the following disclaimer in the
14ca38e323Sdegroote  *    documentation and/or other materials provided with the distribution.
15ca38e323Sdegroote  *
16ca38e323Sdegroote  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
17ca38e323Sdegroote  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
18ca38e323Sdegroote  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19ca38e323Sdegroote  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
20ca38e323Sdegroote  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21ca38e323Sdegroote  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22ca38e323Sdegroote  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23ca38e323Sdegroote  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24ca38e323Sdegroote  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25ca38e323Sdegroote  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26ca38e323Sdegroote  * POSSIBILITY OF SUCH DAMAGE.
27ca38e323Sdegroote  */
28ca38e323Sdegroote 
29ca38e323Sdegroote #include <sys/cdefs.h>
30ca38e323Sdegroote 
31ca38e323Sdegroote #ifndef lint
32*8ee626c9Schristos __RCSID("$NetBSD: pfs.c,v 1.2 2015/06/16 23:04:14 christos Exp $");
33ca38e323Sdegroote #endif
34ca38e323Sdegroote 
35ca38e323Sdegroote #include <sys/types.h>
36ca38e323Sdegroote #include <sys/ioctl.h>
37ca38e323Sdegroote #include <sys/socket.h>
38ca38e323Sdegroote #include <sys/stat.h>
39ca38e323Sdegroote 
40ca38e323Sdegroote #include <net/if.h>
41ca38e323Sdegroote #include <netinet/in.h>
42ca38e323Sdegroote #define TCPSTATES
43ca38e323Sdegroote #include <netinet/tcp_fsm.h>
44ca38e323Sdegroote #include <net/pfvar.h>
45ca38e323Sdegroote #include <arpa/inet.h>
46ca38e323Sdegroote 
47ca38e323Sdegroote #include <err.h>
48ca38e323Sdegroote #include <errno.h>
49ca38e323Sdegroote #include <fcntl.h>
50ca38e323Sdegroote #include <limits.h>
51ca38e323Sdegroote #include <netdb.h>
52ca38e323Sdegroote #include <stdio.h>
53ca38e323Sdegroote #include <stdlib.h>
54ca38e323Sdegroote #include <string.h>
55ca38e323Sdegroote #include <stdbool.h>
56ca38e323Sdegroote #include <unistd.h>
57ca38e323Sdegroote 
58ca38e323Sdegroote #include "parser.h"
59ca38e323Sdegroote 
60ca38e323Sdegroote __dead static void usage(void);
61ca38e323Sdegroote static int setlock(int, int, int);
62ca38e323Sdegroote static int get_states(int, int, struct pfioc_states*);
63ca38e323Sdegroote static int dump_states_binary(int, int, const char*);
64ca38e323Sdegroote static int restore_states_binary(int, int, const char*);
65ca38e323Sdegroote static int dump_states_ascii(int, int, const char*);
66ca38e323Sdegroote static int restore_states_ascii(int, int, const char*);
67ca38e323Sdegroote static char* print_host(const struct pfsync_state_host *h, sa_family_t, char*, size_t);
68ca38e323Sdegroote static void print_peer(const struct pfsync_state_peer *peer, uint8_t, FILE*);
69ca38e323Sdegroote static int print_states(int, int, FILE*);
70ca38e323Sdegroote static void display_states(const struct pfioc_states*, int, FILE*);
71ca38e323Sdegroote static int test_ascii_dump(int, const char*, const char*);
72ca38e323Sdegroote 
73ca38e323Sdegroote static char pf_device[] = "/dev/pf";
74ca38e323Sdegroote 
75ca38e323Sdegroote __dead static void
usage(void)76ca38e323Sdegroote usage(void)
77ca38e323Sdegroote {
78ca38e323Sdegroote 	fprintf(stderr,
79ca38e323Sdegroote 			"usage : %s [-v] [-u | -l | -w <filename> | -r <filename> |\n"
80ca38e323Sdegroote 			"			[ -W <filename> | -R <filename> ]\n",
81ca38e323Sdegroote 			getprogname());
82ca38e323Sdegroote 	exit(EXIT_FAILURE);
83ca38e323Sdegroote }
84ca38e323Sdegroote 
85ca38e323Sdegroote /*
86ca38e323Sdegroote  * The state table must be locked before calling this function
87ca38e323Sdegroote  * Return the number of state in case of success, -1 in case of failure
88ca38e323Sdegroote  * ps::ps_buf must be freed by user after use (in case of success)
89ca38e323Sdegroote  */
90ca38e323Sdegroote static int
get_states(int fd,int verbose __unused,struct pfioc_states * ps)91ca38e323Sdegroote get_states(int fd, int verbose __unused, struct pfioc_states* ps)
92ca38e323Sdegroote {
93ca38e323Sdegroote 	memset(ps, 0, sizeof(*ps));
94ca38e323Sdegroote 	ps->ps_len = 0;
95ca38e323Sdegroote 	char* inbuf;
96ca38e323Sdegroote 
97ca38e323Sdegroote 	// ask the kernel how much memory we need to allocate
98ca38e323Sdegroote 	if (ioctl(fd, DIOCGETSTATES, ps) == -1) {
99ca38e323Sdegroote 		err(EXIT_FAILURE, "DIOCGETSTATES");
100ca38e323Sdegroote 	}
101ca38e323Sdegroote 
102ca38e323Sdegroote 	/* no state */
103ca38e323Sdegroote 	if (ps->ps_len == 0)
104ca38e323Sdegroote 		return 0;
105ca38e323Sdegroote 
106ca38e323Sdegroote 	inbuf = malloc(ps->ps_len);
107ca38e323Sdegroote 	if (inbuf == NULL)
108ca38e323Sdegroote 		err(EXIT_FAILURE, NULL);
109ca38e323Sdegroote 
110ca38e323Sdegroote 	ps->ps_buf = inbuf;
111ca38e323Sdegroote 
112ca38e323Sdegroote 	// really retrieve the different states
113ca38e323Sdegroote 	if (ioctl(fd, DIOCGETSTATES, ps) == -1) {
114ca38e323Sdegroote 		free(ps->ps_buf);
115ca38e323Sdegroote 		err(EXIT_FAILURE, "DIOCGETSTATES");
116ca38e323Sdegroote 	}
117ca38e323Sdegroote 
118ca38e323Sdegroote 	return (ps->ps_len / sizeof(struct pfsync_state));
119ca38e323Sdegroote }
120ca38e323Sdegroote 
121ca38e323Sdegroote static int
dump_states_binary(int fd,int verbose,const char * filename)122ca38e323Sdegroote dump_states_binary(int fd, int verbose, const char* filename)
123ca38e323Sdegroote {
124ca38e323Sdegroote 	int wfd;
125ca38e323Sdegroote 	struct pfioc_states ps;
126ca38e323Sdegroote 	struct pfsync_state *p = NULL;
127ca38e323Sdegroote 	int nb_states;
128ca38e323Sdegroote 	int i;
129ca38e323Sdegroote 	int error = 0;
130ca38e323Sdegroote 	int errno_saved = 0;
131ca38e323Sdegroote 
132ca38e323Sdegroote 	wfd = open(filename, O_WRONLY|O_TRUNC|O_CREAT, 0600);
133ca38e323Sdegroote 	if (wfd == -1)
134ca38e323Sdegroote 		err(EXIT_FAILURE, "Cannot open %s", filename);
135ca38e323Sdegroote 
136ca38e323Sdegroote 	nb_states = get_states(fd, verbose, &ps);
137ca38e323Sdegroote 	if (nb_states <= 0) {
138ca38e323Sdegroote 		close(wfd);
139ca38e323Sdegroote 		return nb_states;
140ca38e323Sdegroote 	}
141ca38e323Sdegroote 
142ca38e323Sdegroote 	/*
143ca38e323Sdegroote 	 * In the file, write the number of states, then store the different states
144ca38e323Sdegroote 	 * When we will switch to text format, we probably don't care any more about the len
145ca38e323Sdegroote 	 */
146ca38e323Sdegroote 	if (write(wfd, &nb_states, sizeof(nb_states)) != sizeof(nb_states)) {
147ca38e323Sdegroote 		error = EXIT_FAILURE;
148ca38e323Sdegroote 		errno_saved = errno;
149ca38e323Sdegroote 		goto done;
150ca38e323Sdegroote 	}
151ca38e323Sdegroote 
152ca38e323Sdegroote 	p = ps.ps_states;
153ca38e323Sdegroote 	for (i = 0; i < nb_states; i++) {
154ca38e323Sdegroote 		if (write(wfd, &p[i], sizeof(*p)) != sizeof(*p)) {
155ca38e323Sdegroote 			error = EXIT_FAILURE;
156ca38e323Sdegroote 			errno_saved = errno;
157ca38e323Sdegroote 			goto done;
158ca38e323Sdegroote 		}
159ca38e323Sdegroote 	}
160ca38e323Sdegroote 
161ca38e323Sdegroote done:
162ca38e323Sdegroote 	free(p);
163ca38e323Sdegroote 	close(wfd);
164ca38e323Sdegroote 	// close can't modify errno
165ca38e323Sdegroote 	if (error) {
166ca38e323Sdegroote 		errno = errno_saved;
167ca38e323Sdegroote 		err(error, NULL);
168ca38e323Sdegroote 	}
169ca38e323Sdegroote 
170ca38e323Sdegroote 	return 0;
171ca38e323Sdegroote }
172ca38e323Sdegroote 
173ca38e323Sdegroote static int
restore_states_binary(int fd,int verbose __unused,const char * filename)174ca38e323Sdegroote restore_states_binary(int fd, int verbose __unused, const char* filename)
175ca38e323Sdegroote {
176ca38e323Sdegroote 	int rfd;
177ca38e323Sdegroote 	struct pfioc_states ps;
178ca38e323Sdegroote 	struct pfsync_state *p;
179ca38e323Sdegroote 	int nb_states;
180ca38e323Sdegroote 	int errno_saved = 0;
181ca38e323Sdegroote 	int i;
182ca38e323Sdegroote 
183ca38e323Sdegroote 	rfd = open(filename, O_RDONLY, 0600);
184ca38e323Sdegroote 	if (rfd == -1)
185ca38e323Sdegroote 		err(EXIT_FAILURE, "Cannot open %s", filename);
186ca38e323Sdegroote 
187ca38e323Sdegroote 	if (read(rfd, &nb_states, sizeof(nb_states)) != sizeof(nb_states)) {
188ca38e323Sdegroote 		errno_saved = errno;
189ca38e323Sdegroote 		close(rfd);
190ca38e323Sdegroote 		errno = errno_saved;
191ca38e323Sdegroote 		err(EXIT_FAILURE, NULL);
192ca38e323Sdegroote 	}
193ca38e323Sdegroote 
194ca38e323Sdegroote 	ps.ps_len = nb_states * sizeof(struct pfsync_state);
195ca38e323Sdegroote 	ps.ps_states = malloc(ps.ps_len);
196ca38e323Sdegroote 	if (ps.ps_states == NULL) {
197ca38e323Sdegroote 		errno_saved = errno;
198ca38e323Sdegroote 		close(rfd);
199ca38e323Sdegroote 		errno = errno_saved;
200ca38e323Sdegroote 		err(EXIT_FAILURE, NULL);
201ca38e323Sdegroote 	}
202ca38e323Sdegroote 
203ca38e323Sdegroote 	p = ps.ps_states;
204ca38e323Sdegroote 
205ca38e323Sdegroote 	for (i = 0; i < nb_states; i++) {
206ca38e323Sdegroote 		if (read(rfd, &p[i], sizeof(*p)) != sizeof(*p)) {
207ca38e323Sdegroote 			errno_saved = errno;
208ca38e323Sdegroote 			close(rfd);
209ca38e323Sdegroote 			free(ps.ps_states);
210ca38e323Sdegroote 			errno = errno_saved;
211ca38e323Sdegroote 			err(EXIT_FAILURE, NULL);
212ca38e323Sdegroote 		}
213ca38e323Sdegroote 	}
214ca38e323Sdegroote 
215ca38e323Sdegroote 	if (ioctl(fd, DIOCADDSTATES, &ps) == -1) {
216ca38e323Sdegroote 		errno_saved = errno;
217ca38e323Sdegroote 		close(rfd);
218ca38e323Sdegroote 		free(ps.ps_states);
219ca38e323Sdegroote 		errno = errno_saved;
220ca38e323Sdegroote 		err(EXIT_FAILURE, "DIOCADDSTATES");
221ca38e323Sdegroote 	}
222ca38e323Sdegroote 
223ca38e323Sdegroote 	free(ps.ps_states);
224ca38e323Sdegroote 	close(rfd);
225ca38e323Sdegroote 	return 0;
226ca38e323Sdegroote }
227ca38e323Sdegroote 
228ca38e323Sdegroote static char*
print_host(const struct pfsync_state_host * h,sa_family_t af,char * buf,size_t size_buf)229ca38e323Sdegroote print_host(const struct pfsync_state_host *h, sa_family_t af, char* buf,
230ca38e323Sdegroote 		size_t size_buf)
231ca38e323Sdegroote {
232ca38e323Sdegroote 	uint16_t port;
233ca38e323Sdegroote 	char	buf_addr[48];
234ca38e323Sdegroote 
235ca38e323Sdegroote 	port = ntohs(h->port);
236ca38e323Sdegroote 	if (inet_ntop(af, &(h->addr) , buf_addr, sizeof(buf_addr)) == NULL) {
237ca38e323Sdegroote 		strcpy(buf_addr, "?");
238ca38e323Sdegroote 	}
239ca38e323Sdegroote 
240ca38e323Sdegroote 	snprintf(buf, size_buf, "%s:[%d]", buf_addr, port);
241ca38e323Sdegroote 	return buf;
242ca38e323Sdegroote }
243ca38e323Sdegroote 
244ca38e323Sdegroote static void
print_peer(const struct pfsync_state_peer * peer,uint8_t proto,FILE * f)245ca38e323Sdegroote print_peer(const struct pfsync_state_peer* peer, uint8_t proto, FILE* f)
246ca38e323Sdegroote {
247ca38e323Sdegroote 	if (proto == IPPROTO_TCP) {
248ca38e323Sdegroote 		if (peer->state < TCP_NSTATES)
249ca38e323Sdegroote 			fprintf(f, "state %s", tcpstates[peer->state]);
250ca38e323Sdegroote 
251ca38e323Sdegroote 		if (peer->seqdiff != 0)
252ca38e323Sdegroote 			fprintf(f, " seq [%" PRIu32 ":%" PRIu32 ",%" PRIu32"]",
253ca38e323Sdegroote 					peer->seqlo, peer->seqhi, peer->seqdiff);
254ca38e323Sdegroote 		else
255ca38e323Sdegroote 			fprintf(f, " seq [%" PRIu32 ":%" PRIu32 "]",
256ca38e323Sdegroote 					peer->seqlo, peer->seqhi);
257ca38e323Sdegroote 
258ca38e323Sdegroote 		if (peer->mss != 0)
259ca38e323Sdegroote 			fprintf(f, " max_win %" PRIu16 " mss %" PRIu16 " wscale %" PRIu8,
260ca38e323Sdegroote 					peer->max_win, peer->mss, peer->wscale);
261ca38e323Sdegroote 		else
262ca38e323Sdegroote 			fprintf(f, " max_win %" PRIu16 " wscale %" PRIu8, peer->max_win,
263ca38e323Sdegroote 					peer->wscale);
264ca38e323Sdegroote 
265ca38e323Sdegroote 	} else {
266ca38e323Sdegroote 		if (proto == IPPROTO_UDP) {
267ca38e323Sdegroote 			const char *mystates[] = PFUDPS_NAMES;
268ca38e323Sdegroote 			if (peer->state < PFUDPS_NSTATES)
269ca38e323Sdegroote 				fprintf(f, "state %s", mystates[peer->state]);
270ca38e323Sdegroote 		} else if (proto == IPPROTO_ICMP || proto == IPPROTO_ICMPV6) {
271ca38e323Sdegroote 			fprintf(f, " state %" PRIu8, peer->state);
272ca38e323Sdegroote 		} else {
273ca38e323Sdegroote 			const char *mystates[] = PFOTHERS_NAMES;
274ca38e323Sdegroote 			if (peer->state < PFOTHERS_NSTATES)
275ca38e323Sdegroote 				fprintf(f, " state %s", mystates[peer->state]);
276ca38e323Sdegroote 		}
277ca38e323Sdegroote 	}
278ca38e323Sdegroote 
279ca38e323Sdegroote 	if (peer->scrub.scrub_flag == PFSYNC_SCRUB_FLAG_VALID) {
280ca38e323Sdegroote 		fprintf(f, " scrub flags %" PRIu16 "ttl %" PRIu8 "mod %"PRIu32,
281ca38e323Sdegroote 				peer->scrub.pfss_flags, peer->scrub.pfss_ttl, peer->scrub.pfss_ts_mod);
282ca38e323Sdegroote 	} else {
283ca38e323Sdegroote 		fprintf(f, " no-scrub");
284ca38e323Sdegroote 	}
285ca38e323Sdegroote }
286ca38e323Sdegroote 
287ca38e323Sdegroote static void
display_states(const struct pfioc_states * ps,int verbose __unused,FILE * f)288ca38e323Sdegroote display_states(const struct pfioc_states *ps, int verbose __unused, FILE* f)
289ca38e323Sdegroote {
290ca38e323Sdegroote 	struct pfsync_state *p = NULL;
291ca38e323Sdegroote 	struct pfsync_state_peer *src, *dst;
292ca38e323Sdegroote 	struct protoent *proto;
293ca38e323Sdegroote 	int nb_states;
294ca38e323Sdegroote 	int i;
295ca38e323Sdegroote 	uint64_t id;
296ca38e323Sdegroote 
297ca38e323Sdegroote 	p = ps->ps_states;
298ca38e323Sdegroote 	nb_states = ps->ps_len / sizeof(struct pfsync_state);
299ca38e323Sdegroote 
300ca38e323Sdegroote 	for (i = 0; i < nb_states; i++, p++) {
301ca38e323Sdegroote 		fprintf(f, "state %s ", p->direction == PF_OUT ? "out" : "in");
302ca38e323Sdegroote 		fprintf(f, "on %s ", p->ifname);
303ca38e323Sdegroote 
304ca38e323Sdegroote 		if ((proto = getprotobynumber(p->proto)) != NULL)
305ca38e323Sdegroote 			fprintf(f, "proto %s ", proto->p_name);
306ca38e323Sdegroote 		else
307ca38e323Sdegroote 			fprintf(f, "proto %u ", p->proto);
308ca38e323Sdegroote 
309ca38e323Sdegroote 
310ca38e323Sdegroote 		if (PF_ANEQ(&p->lan.addr, &p->gwy.addr, p->af) ||
311ca38e323Sdegroote 				(p->lan.port != p->gwy.port)) {
312ca38e323Sdegroote 
313ca38e323Sdegroote 			char buf1[64], buf2[64], buf3[64];
314ca38e323Sdegroote 			fprintf(f, "from %s to %s using %s",
315ca38e323Sdegroote 					print_host(&p->lan, p->af, buf1, sizeof(buf1)),
316ca38e323Sdegroote 					print_host(&p->ext, p->af, buf2, sizeof(buf2)),
317ca38e323Sdegroote 					print_host(&p->gwy, p->af, buf3, sizeof(buf3)));
318ca38e323Sdegroote 		} else {
319ca38e323Sdegroote 			char buf1[64], buf2[64];
320ca38e323Sdegroote 			fprintf(f, "from %s to %s",
321ca38e323Sdegroote 					print_host(&p->lan, p->af, buf1, sizeof(buf1)),
322ca38e323Sdegroote 					print_host(&p->ext, p->af, buf2, sizeof(buf2)));
323ca38e323Sdegroote 		}
324ca38e323Sdegroote 
325ca38e323Sdegroote 		memcpy(&id, p->id, sizeof(p->id));
326ca38e323Sdegroote 		fprintf(f, " id %" PRIu64 " cid %" PRIu32 " expire %" PRIu32 " timeout %" PRIu8,
327ca38e323Sdegroote 				id , p->creatorid, p->expire, p->timeout);
328ca38e323Sdegroote 
329ca38e323Sdegroote 		if (p->direction == PF_OUT) {
330ca38e323Sdegroote 			src = &p->src;
331ca38e323Sdegroote 			dst = &p->dst;
332ca38e323Sdegroote 		} else {
333ca38e323Sdegroote 			src = &p->dst;
334ca38e323Sdegroote 			dst = &p->src;
335ca38e323Sdegroote 		}
336ca38e323Sdegroote 
337ca38e323Sdegroote 		fprintf(f, " src ");
338ca38e323Sdegroote 		print_peer(src, p->proto, f);
339ca38e323Sdegroote 		fprintf(f, " dst ");
340ca38e323Sdegroote 		print_peer(dst, p->proto, f);
341ca38e323Sdegroote 
342ca38e323Sdegroote 		fprintf(f, "\n");
343ca38e323Sdegroote 	}
344ca38e323Sdegroote }
345ca38e323Sdegroote 
346ca38e323Sdegroote static int
print_states(int fd,int verbose,FILE * f)347ca38e323Sdegroote print_states(int fd, int verbose, FILE* f)
348ca38e323Sdegroote {
349ca38e323Sdegroote 	struct pfioc_states ps;
350ca38e323Sdegroote 	int nb_states;
351ca38e323Sdegroote 
352ca38e323Sdegroote 	nb_states = get_states(fd, verbose, &ps);
353ca38e323Sdegroote 	if (nb_states <= 0) {
354ca38e323Sdegroote 		return nb_states;
355ca38e323Sdegroote 	}
356ca38e323Sdegroote 
357ca38e323Sdegroote 	display_states(&ps, verbose, f);
358ca38e323Sdegroote 
359ca38e323Sdegroote 	free(ps.ps_states);
360ca38e323Sdegroote 	return 0;
361ca38e323Sdegroote }
362ca38e323Sdegroote 
363ca38e323Sdegroote static int
dump_states_ascii(int fd,int verbose,const char * filename)364ca38e323Sdegroote dump_states_ascii(int fd, int verbose, const char* filename)
365ca38e323Sdegroote {
366ca38e323Sdegroote 	FILE *f;
367ca38e323Sdegroote 
368ca38e323Sdegroote 	if (strcmp(filename, "-") == 0) {
369ca38e323Sdegroote 		f = stdout;
370ca38e323Sdegroote 	} else {
371ca38e323Sdegroote 		f = fopen(filename, "w");
372ca38e323Sdegroote 		if (f == NULL)
373*8ee626c9Schristos 			err(EXIT_FAILURE, "Can't open %s", filename);
374ca38e323Sdegroote 	}
375ca38e323Sdegroote 
376ca38e323Sdegroote 	print_states(fd, verbose, f);
377ca38e323Sdegroote 
378ca38e323Sdegroote 	if (f != stdout)
379ca38e323Sdegroote 		fclose(f);
380ca38e323Sdegroote 
381ca38e323Sdegroote 	return 0;
382ca38e323Sdegroote }
383ca38e323Sdegroote 
384ca38e323Sdegroote static int
restore_states_ascii(int fd,int verbose __unused,const char * filename)385ca38e323Sdegroote restore_states_ascii(int fd, int verbose __unused, const char* filename)
386ca38e323Sdegroote {
387ca38e323Sdegroote 	FILE *f;
388ca38e323Sdegroote 	struct pfioc_states ps;
389ca38e323Sdegroote 	int errno_saved;
390ca38e323Sdegroote 
391ca38e323Sdegroote 	f = fopen(filename, "r");
392ca38e323Sdegroote 	if (f == NULL)
393*8ee626c9Schristos 		err(EXIT_FAILURE, "Can't open %s", filename);
394ca38e323Sdegroote 
395ca38e323Sdegroote 	parse(f, &ps);
396ca38e323Sdegroote 
397ca38e323Sdegroote 	if (ioctl(fd, DIOCADDSTATES, &ps) == -1) {
398ca38e323Sdegroote 		errno_saved = errno;
399ca38e323Sdegroote 		fclose(f);
400ca38e323Sdegroote 		free(ps.ps_states);
401ca38e323Sdegroote 		errno = errno_saved;
402ca38e323Sdegroote 		err(EXIT_FAILURE, "DIOCADDSTATES");
403ca38e323Sdegroote 	}
404ca38e323Sdegroote 
405ca38e323Sdegroote 	free(ps.ps_states);
406ca38e323Sdegroote 	fclose(f);
407ca38e323Sdegroote 	return 0;
408ca38e323Sdegroote }
409ca38e323Sdegroote 
410ca38e323Sdegroote static int
setlock(int fd,int verbose,int lock)411ca38e323Sdegroote setlock(int fd, int verbose, int lock)
412ca38e323Sdegroote {
413ca38e323Sdegroote 	if (verbose)
414ca38e323Sdegroote 		printf("Turning lock %s\n", lock ? "on" : "off");
415ca38e323Sdegroote 
416ca38e323Sdegroote 	if (ioctl(fd, DIOCSETLCK, &lock) == -1)
417ca38e323Sdegroote 		err(EXIT_FAILURE, "DIOCSETLCK");
418ca38e323Sdegroote 
419ca38e323Sdegroote 	return 0;
420ca38e323Sdegroote }
421ca38e323Sdegroote 
422ca38e323Sdegroote static int
test_ascii_dump(int verbose,const char * file1,const char * file2)423ca38e323Sdegroote test_ascii_dump(int verbose, const char* file1, const char *file2)
424ca38e323Sdegroote {
425ca38e323Sdegroote 	FILE *f1, *f2;
426ca38e323Sdegroote 	struct pfioc_states ps;
427ca38e323Sdegroote 	int errno_saved;
428ca38e323Sdegroote 
429ca38e323Sdegroote 	f1 = fopen(file1, "r");
430ca38e323Sdegroote 	if (f1 == NULL)
431*8ee626c9Schristos 		err(EXIT_FAILURE, "Can't open %s", file1);
432ca38e323Sdegroote 
433ca38e323Sdegroote 
434ca38e323Sdegroote 	f2 = fopen(file2, "w");
435ca38e323Sdegroote 	if (f2 == NULL) {
436ca38e323Sdegroote 		errno_saved = errno;
437ca38e323Sdegroote 		fclose(f2);
438ca38e323Sdegroote 		errno = errno_saved;
439*8ee626c9Schristos 		err(EXIT_FAILURE, "Can't open %s", file2);
440ca38e323Sdegroote 	}
441ca38e323Sdegroote 
442ca38e323Sdegroote 	parse(f1, &ps);
443ca38e323Sdegroote 	display_states(&ps, verbose, f2);
444ca38e323Sdegroote 
445ca38e323Sdegroote 	free(ps.ps_states);
446ca38e323Sdegroote 	fclose(f1);
447ca38e323Sdegroote 	fclose(f2);
448ca38e323Sdegroote 
449ca38e323Sdegroote 	return 0;
450ca38e323Sdegroote }
451ca38e323Sdegroote 
main(int argc,char * argv[])452ca38e323Sdegroote int main(int argc, char *argv[])
453ca38e323Sdegroote {
454ca38e323Sdegroote 	setprogname(argv[0]);
455ca38e323Sdegroote 
456ca38e323Sdegroote 	int lock = 0;
457ca38e323Sdegroote 	int set = 0;
458ca38e323Sdegroote 	int dump = 0;
459ca38e323Sdegroote 	int restore = 0;
460ca38e323Sdegroote 	int verbose = 0;
461ca38e323Sdegroote 	int test = 0;
462ca38e323Sdegroote 	bool binary = false;
463ca38e323Sdegroote 	char* filename = NULL;
464ca38e323Sdegroote 	char* filename2 = NULL;
465ca38e323Sdegroote 	int error = 0;
466ca38e323Sdegroote 	int fd;
467ca38e323Sdegroote 	int c;
468ca38e323Sdegroote 
469ca38e323Sdegroote 	while ((c = getopt(argc, argv, "ulvw:r:R:W:bt:o:")) != -1)
470ca38e323Sdegroote 		switch (c) {
471ca38e323Sdegroote 		case 'u' :
472ca38e323Sdegroote 			lock = 0;
473ca38e323Sdegroote 			set = 1;
474ca38e323Sdegroote 			break;
475ca38e323Sdegroote 
476ca38e323Sdegroote 		case 'l' :
477ca38e323Sdegroote 			lock = 1;
478ca38e323Sdegroote 			set = 1;
479ca38e323Sdegroote 			break;
480ca38e323Sdegroote 
481ca38e323Sdegroote 		case 'b':
482ca38e323Sdegroote 			binary = true;
483ca38e323Sdegroote 			break;
484ca38e323Sdegroote 
485ca38e323Sdegroote 		case 'r':
486ca38e323Sdegroote 			restore = 1;
487ca38e323Sdegroote 			filename = optarg;
488ca38e323Sdegroote 			break;
489ca38e323Sdegroote 
490ca38e323Sdegroote 		case 'v':
491ca38e323Sdegroote 			verbose=1;
492ca38e323Sdegroote 			break;
493ca38e323Sdegroote 
494ca38e323Sdegroote 		case 'w':
495ca38e323Sdegroote 			dump=1;
496ca38e323Sdegroote 			filename=optarg;
497ca38e323Sdegroote 			break;
498ca38e323Sdegroote 
499ca38e323Sdegroote 		case 'R':
500ca38e323Sdegroote 			restore = 1;
501ca38e323Sdegroote 			set = 1;
502ca38e323Sdegroote 			filename = optarg;
503ca38e323Sdegroote 			break;
504ca38e323Sdegroote 
505ca38e323Sdegroote 		case 'W':
506ca38e323Sdegroote 			dump = 1;
507ca38e323Sdegroote 			set = 1;
508ca38e323Sdegroote 			filename = optarg;
509ca38e323Sdegroote 			break;
510ca38e323Sdegroote 
511ca38e323Sdegroote 		case 't':
512ca38e323Sdegroote 			test=1;
513ca38e323Sdegroote 			filename = optarg;
514ca38e323Sdegroote 			break;
515ca38e323Sdegroote 
516ca38e323Sdegroote 		case 'o':
517ca38e323Sdegroote 			filename2 = optarg;
518ca38e323Sdegroote 			break;
519ca38e323Sdegroote 
520ca38e323Sdegroote 		case '?' :
521ca38e323Sdegroote 		default:
522ca38e323Sdegroote 			usage();
523ca38e323Sdegroote 		}
524ca38e323Sdegroote 
525ca38e323Sdegroote 	if (set == 0 && dump == 0 && restore == 0 && test == 0)
526ca38e323Sdegroote 		usage();
527ca38e323Sdegroote 
528ca38e323Sdegroote 	if (dump == 1 && restore == 1)
529ca38e323Sdegroote 		usage();
530ca38e323Sdegroote 
531ca38e323Sdegroote 	if (test == 1) {
532ca38e323Sdegroote 		if (filename2 == NULL) {
533ca38e323Sdegroote 			fprintf(stderr, "-o <file> is required when using -t\n");
534ca38e323Sdegroote 			err(EXIT_FAILURE, NULL);
535ca38e323Sdegroote 		}
536ca38e323Sdegroote 		error = test_ascii_dump(verbose, filename, filename2);
537ca38e323Sdegroote 	} else {
538ca38e323Sdegroote 		fd = open(pf_device, O_RDWR);
539ca38e323Sdegroote 		if (fd == -1)
540ca38e323Sdegroote 			err(EXIT_FAILURE, "Cannot open %s", pf_device);
541ca38e323Sdegroote 
542ca38e323Sdegroote 		if (set != 0 && dump == 0 && restore == 0)
543ca38e323Sdegroote 			error = setlock(fd, verbose, lock);
544ca38e323Sdegroote 
545ca38e323Sdegroote 		if (dump) {
546ca38e323Sdegroote 			if (set)
547ca38e323Sdegroote 				error = setlock(fd, verbose, 1);
548ca38e323Sdegroote 
549ca38e323Sdegroote 			if (binary)
550ca38e323Sdegroote 				error = dump_states_binary(fd, verbose, filename);
551ca38e323Sdegroote 			else
552ca38e323Sdegroote 				error = dump_states_ascii(fd, verbose, filename);
553ca38e323Sdegroote 
554ca38e323Sdegroote 			if (set)
555ca38e323Sdegroote 				error = setlock(fd, verbose, 0);
556ca38e323Sdegroote 		}
557ca38e323Sdegroote 
558ca38e323Sdegroote 		if (restore) {
559ca38e323Sdegroote 			if (set)
560ca38e323Sdegroote 				error = setlock(fd, verbose, 1);
561ca38e323Sdegroote 
562ca38e323Sdegroote 			if (binary)
563ca38e323Sdegroote 				error = restore_states_binary(fd, verbose, filename);
564ca38e323Sdegroote 			else
565ca38e323Sdegroote 				error = restore_states_ascii(fd, verbose, filename);
566ca38e323Sdegroote 
567ca38e323Sdegroote 			if (set)
568ca38e323Sdegroote 				error = setlock(fd, verbose, 0);
569ca38e323Sdegroote 		}
570ca38e323Sdegroote 
571ca38e323Sdegroote 		close(fd);
572ca38e323Sdegroote 	}
573ca38e323Sdegroote 
574ca38e323Sdegroote 	return error;
575ca38e323Sdegroote }
576