/*-
* Copyright (c) 2010 The NetBSD Foundation, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/*
* The state table must be locked before calling this function
* Return the number of state in case of success, -1 in case of failure
* ps::ps_buf must be freed by user after use (in case of success)
*/
static int
get_states(int fd, int verbose __unused, struct pfioc_states* ps)
{
memset(ps, 0, sizeof(*ps));
ps->ps_len = 0;
char* inbuf;
// ask the kernel how much memory we need to allocate
if (ioctl(fd, DIOCGETSTATES, ps) == -1) {
err(EXIT_FAILURE, "DIOCGETSTATES");
}
/* no state */
if (ps->ps_len == 0)
return 0;
inbuf = malloc(ps->ps_len);
if (inbuf == NULL)
err(EXIT_FAILURE, NULL);
ps->ps_buf = inbuf;
// really retrieve the different states
if (ioctl(fd, DIOCGETSTATES, ps) == -1) {
free(ps->ps_buf);
err(EXIT_FAILURE, "DIOCGETSTATES");
}
static int
dump_states_binary(int fd, int verbose, const char* filename)
{
int wfd;
struct pfioc_states ps;
struct pfsync_state *p = NULL;
int nb_states;
int i;
int error = 0;
int errno_saved = 0;
wfd = open(filename, O_WRONLY|O_TRUNC|O_CREAT, 0600);
if (wfd == -1)
err(EXIT_FAILURE, "Cannot open %s", filename);
/*
* In the file, write the number of states, then store the different states
* When we will switch to text format, we probably don't care any more about the len
*/
if (write(wfd, &nb_states, sizeof(nb_states)) != sizeof(nb_states)) {
error = EXIT_FAILURE;
errno_saved = errno;
goto done;
}
p = ps.ps_states;
for (i = 0; i < nb_states; i++) {
if (write(wfd, &p[i], sizeof(*p)) != sizeof(*p)) {
error = EXIT_FAILURE;
errno_saved = errno;
goto done;
}
}
done:
free(p);
close(wfd);
// close can't modify errno
if (error) {
errno = errno_saved;
err(error, NULL);
}
return 0;
}
static int
restore_states_binary(int fd, int verbose __unused, const char* filename)
{
int rfd;
struct pfioc_states ps;
struct pfsync_state *p;
int nb_states;
int errno_saved = 0;
int i;
rfd = open(filename, O_RDONLY, 0600);
if (rfd == -1)
err(EXIT_FAILURE, "Cannot open %s", filename);
int main(int argc, char *argv[])
{
setprogname(argv[0]);
int lock = 0;
int set = 0;
int dump = 0;
int restore = 0;
int verbose = 0;
int test = 0;
bool binary = false;
char* filename = NULL;
char* filename2 = NULL;
int error = 0;
int fd;
int c;
while ((c = getopt(argc, argv, "ulvw:r:R:W:bt:o:")) != -1)
switch (c) {
case 'u' :
lock = 0;
set = 1;
break;
case 'l' :
lock = 1;
set = 1;
break;
case 'b':
binary = true;
break;
case 'r':
restore = 1;
filename = optarg;
break;
case 'v':
verbose=1;
break;
case 'w':
dump=1;
filename=optarg;
break;
case 'R':
restore = 1;
set = 1;
filename = optarg;
break;
case 'W':
dump = 1;
set = 1;
filename = optarg;
break;
case 't':
test=1;
filename = optarg;
break;
case 'o':
filename2 = optarg;
break;
case '?' :
default:
usage();
}
if (set == 0 && dump == 0 && restore == 0 && test == 0)
usage();
if (dump == 1 && restore == 1)
usage();
if (test == 1) {
if (filename2 == NULL) {
fprintf(stderr, "-o <file> is required when using -t\n");
err(EXIT_FAILURE, NULL);
}
error = test_ascii_dump(verbose, filename, filename2);
} else {
fd = open(pf_device, O_RDWR);
if (fd == -1)
err(EXIT_FAILURE, "Cannot open %s", pf_device);