blob: f9a95952d0e273176f9640a9a035a6792c74e0b4 [file] [log] [blame]
/* Code to restore the iptables state, from file by iptables-save. */
#include <getopt.h>
#include <sys/errno.h>
#include <string.h>
#include <stdio.h>
#include "packet-filter/userspace/iptables.h"
#include "packet-filter/userspace/libiptc/libiptc.h"
/* Keeping track of external matches and targets. */
static struct option options[] = {
{ "binary", 1, 0, 'b' },
{ "counters", 1, 0, 'c' },
{ "verbose", 1, 0, 'v' },
{ "help", 1, 0, 'h' },
{ 0 }
};
static void print_usage(const char *name, const char *version) __attribute__((noreturn));
static void print_usage(const char *name, const char *version)
{
fprintf(stderr, "Usage: %s [-b] [-c] [-v] [-h]\n", name);
exit(1);
}
static int clean_slate(iptc_handle_t *handle)
{
/* Skip over builtins. */
const char *i, *last = IPTC_LABEL_OUTPUT;
/* Be careful iterating: it isn't safe during delete. */
/* Re-iterate after each delete successful */
while ((i = iptc_next_chain(last, handle)) != NULL) {
if (!iptc_flush_entries(i, handle)
|| !iptc_delete_chain(i, handle))
return 0;
}
return 1;
}
int main(int argc, char *argv[])
{
iptc_handle_t handle;
char buffer[10240];
int counters = 0, binary = 0, verbose = 0;
unsigned int line = 0;
int c;
const char *chain;
FILE *in;
program_name = "iptables-restore";
program_version = NETFILTER_VERSION;
/* Don't use getopt here; it would interfere 8-(. */
if (optind == argc - 1) {
in = fopen(argv[optind], "r");
if (!in) {
fprintf(stderr, "Can't open %s: %s", argv[optind],
strerror(errno));
exit(1);
}
}
else if (optind < argc) {
fprintf(stderr, "Unknown arguments found on commandline");
exit(1);
}
else in = stdin;
handle = iptc_init();
if (!handle)
exit_error(VERSION_PROBLEM,
"can't initialize iptables-restore: %s",
iptc_strerror(errno));
if (!clean_slate(&handle))
exit_error(OTHER_PROBLEM, "Deleting old chains: %s",
iptc_strerror(errno));
/* Grab standard input. */
while (fgets(buffer, sizeof(buffer), in)) {
int ret;
line++;
if (buffer[0] == '\n') continue;
else if (buffer[0] == '#') {
if (verbose) fputs(buffer, stdout);
continue;
} else if (strcmp(buffer, "COMMIT\n") == 0)
ret = iptc_commit(&handle);
else if (buffer[0] == ':') {
/* New chain. */
char *chain, *policy;
/* FIXME: Don't ignore counters. */
chain = strtok(buffer+1, " \t\n");
if (!chain) {
exit_error(PARAMETER_PROBLEM,
"%s: line %u chain name invalid\n",
program_name, line);
exit(1);
}
policy = strtok(NULL, " \t\n");
if (!policy) {
exit_error(PARAMETER_PROBLEM,
"%s: line %u policy invalid\n",
program_name, line);
exit(1);
}
if (strcmp(policy, "-") != 0
&& !iptc_set_policy(chain, policy, &handle))
exit_error(OTHER_PROBLEM,
"Can't set policy `%s'"
" on `%s' line %u: %s\n",
chain, policy, line,
iptc_strerror(errno));
} else {
char *newargv[1024];
int i;
char *ptr = buffer;
/* FIXME: Don't ignore counters. */
if (buffer[0] == '[') {
ptr = strchr(buffer, ']');
if (!ptr)
exit_error(PARAMETER_PROBLEM,
"Bad line %u: need ]\n",
line);
}
/* strtok: a function only a coder could love */
newargv[0] = argv[0];
for (i = 1; i < sizeof(newargv)/sizeof(char *); i++) {
if (!(newargv[i] = strtok(ptr, " \t\n")))
break;
ptr = NULL;
}
if (i == sizeof(newargv)/sizeof(char *)) {
fprintf(stderr,
"%s: line %u too many arguments\n",
program_name, line);
exit(1);
}
ret = do_command(i, newargv, &handle);
}
if (!ret) {
fprintf(stderr, "%s: line %u failed\n",
program_name, line);
exit(1);
}
}
return 0;
}