/* Code to restore the iptables state, from file by ip6tables-save. * Author: Andras Kis-Szabo * * based on iptables-restore * Authors: * Harald Welte * Rusty Russell * */ #include #include #include #include #include #include "ip6tables.h" #include "libiptc/libip6tc.h" #ifdef DEBUG #define DEBUGP(x, args...) fprintf(stderr, x, ## args) #else #define DEBUGP(x, args...) #endif extern int for_each_chain(int (*fn)(const ip6t_chainlabel, int, ip6tc_handle_t *), int verbose, int builtinstoo, ip6tc_handle_t *handle); extern int flush_entries(const ip6t_chainlabel chain, int verbose, ip6tc_handle_t *handle); extern int delete_chain(const ip6t_chainlabel chain, int verbose, ip6tc_handle_t *handle); static int binary = 0, counters = 0, verbose = 0, noflush = 0; /* Keeping track of external matches and targets. */ static struct option options[] = { { "binary", 0, 0, 'b' }, { "counters", 0, 0, 'c' }, /* { "verbose", 1, 0, 'v' }, */ { "help", 0, 0, 'h' }, { "noflush", 0, 0, 'n'}, { 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" " [ --binary ]\n" " [ --counters ]\n" " [ --verbose ]\n" " [ --help ]\n" " [ --noflush ]\n", name); exit(1); } ip6tc_handle_t create_handle(const char *tablename) { ip6tc_handle_t handle; handle = ip6tc_init(tablename); if (!handle) { exit_error(PARAMETER_PROBLEM, "%s: unable to initialize" "table '%s'\n", program_name, tablename); exit(1); } return handle; } int parse_counters(char *string, struct ip6t_counters *ctr) { return (sscanf(string, "[%llu:%llu]", &ctr->pcnt, &ctr->bcnt) == 2); } int main(int argc, char *argv[]) { ip6tc_handle_t handle; char buffer[10240]; unsigned int line = 0; int c; char curtable[IP6T_TABLE_MAXNAMELEN + 1]; char curchain[IP6T_FUNCTION_MAXNAMELEN + 1]; FILE *in; program_name = "ip6tables-restore"; program_version = NETFILTER_VERSION; while ((c = getopt_long(argc, argv, "bcvhn", options, NULL)) != -1) { switch (c) { case 'b': binary = 1; break; case 'c': counters = 1; break; case 'h': print_usage("ip6tables-restore", NETFILTER_VERSION); break; case 'n': noflush = 1; break; } } 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("filter"); 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) { DEBUGP("Calling commit\n"); ret = ip6tc_commit(&handle); } else if (buffer[0] == '*') { /* New table */ char *table; table = strtok(buffer+1, " \t\n"); DEBUGP("line %u, table '%s'\n", line, table); if (!table) { exit_error(PARAMETER_PROBLEM, "%s: line %u table name invalid\n", program_name, line); exit(1); } strncpy(curtable, table, IP6T_TABLE_MAXNAMELEN); handle = create_handle(table); if (noflush == 0) { DEBUGP("Cleaning all chains of table '%s'\n", table); for_each_chain(flush_entries, verbose, 1, &handle); DEBUGP("Deleting all user-defined chains " "of table '%s'\n", table); for_each_chain(delete_chain, verbose, 0, &handle) ; } ret = 1; } else if (buffer[0] == ':') { /* New chain. */ char *policy, *chain; chain = strtok(buffer+1, " \t\n"); DEBUGP("line %u, chain '%s'\n", line, chain); if (!chain) { exit_error(PARAMETER_PROBLEM, "%s: line %u chain name invalid\n", program_name, line); exit(1); } strncpy(curchain, chain, IP6T_FUNCTION_MAXNAMELEN); /* why the f... does iptc_builtin not work here ? */ /* FIXME: abort if chain creation fails --RR */ // if (!iptc_builtin(curchain, &handle)) { DEBUGP("Creating new chain '%s'\n", curchain); if (!ip6tc_create_chain(curchain, &handle)) DEBUGP("unable to create chain '%s':%s\n", curchain, strerror(errno)); // } policy = strtok(NULL, " \t\n"); DEBUGP("line %u, policy '%s'\n", line, policy); if (!policy) { exit_error(PARAMETER_PROBLEM, "%s: line %u policy invalid\n", program_name, line); exit(1); } if (strcmp(policy, "-") != 0) { struct ip6t_counters count; if (counters) { char *ctrs; ctrs = strtok(NULL, " \t\n"); parse_counters(ctrs, &count); } else { memset(&count, 0, sizeof(struct ip6t_counters)); } DEBUGP("Setting policy of chain %s to %s\n", chain, policy); if (!ip6tc_set_policy(chain, policy, &count, &handle)) exit_error(OTHER_PROBLEM, "Can't set policy `%s'" " on `%s' line %u: %s\n", chain, policy, line, ip6tc_strerror(errno)); } ret = 1; } else { char *newargv[1024]; int i,a, argvsize; char *ptr = buffer; char *pcnt = NULL; char *bcnt = NULL; if (buffer[0] == '[') { ptr = strchr(buffer, ']'); if (!ptr) exit_error(PARAMETER_PROBLEM, "Bad line %u: need ]\n", line); pcnt = strtok(buffer+1, ":"); bcnt = strtok(NULL, "]"); } newargv[0] = argv[0]; newargv[1] = "-t"; newargv[2] = (char *) &curtable; newargv[3] = "-A"; newargv[4] = (char *) &curchain; argvsize = 5; if (counters && pcnt && bcnt) { newargv[5] = "--set-counters"; newargv[6] = (char *) pcnt; newargv[7] = (char *) bcnt; argvsize = 8; } // strtok initcialize! if ( buffer[0]!='[' ) { if (!(newargv[argvsize] = strtok(buffer, " \t\n"))) goto ImLaMeR; //break; argvsize++; } /* strtok: a function only a coder could love */ for (i = argvsize; i < sizeof(newargv)/sizeof(char *); i++) { if (!(newargv[i] = strtok(NULL, " \t\n"))) break; ptr = NULL; } ImLaMeR: if (i == sizeof(newargv)/sizeof(char *)) { fprintf(stderr, "%s: line %u too many arguments\n", program_name, line); exit(1); } DEBUGP("===>calling do_command6(%u, argv, &%s, handle):\n", i, curtable); for (a = 0; a <= i; a++) DEBUGP("argv[%u]: %s\n", a, newargv[a]); ret = do_command6(i, newargv, &newargv[2], &handle); } if (!ret) { fprintf(stderr, "%s: line %u failed\n", program_name, line); exit(1); } } return 0; }