/* Code to restore the iptables state, from file by iptables-save. */ #include #include #include #include #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; }