1 /* Code to restore the iptables state, from file by iptables-save.
2 * (C) 2000-2002 by Harald Welte <laforge@gnumonks.org>
3 * based on previous code from Rusty Russell <rusty@linuxcare.com.au>
5 * This code is distributed under the terms of GNU GPL v2
11 #include <sys/errno.h>
18 #include "libiptc/libiptc.h"
19 #include "iptables-multi.h"
22 #define DEBUGP(x, args...) fprintf(stderr, x, ## args)
24 #define DEBUGP(x, args...)
27 static int binary = 0, counters = 0, verbose = 0, noflush = 0;
29 /* Keeping track of external matches and targets. */
30 static const struct option options[] = {
31 {.name = "binary", .has_arg = false, .val = 'b'},
32 {.name = "counters", .has_arg = false, .val = 'c'},
33 {.name = "verbose", .has_arg = false, .val = 'v'},
34 {.name = "test", .has_arg = false, .val = 't'},
35 {.name = "help", .has_arg = false, .val = 'h'},
36 {.name = "noflush", .has_arg = false, .val = 'n'},
37 {.name = "modprobe", .has_arg = true, .val = 'M'},
38 {.name = "table", .has_arg = true, .val = 'T'},
42 static void print_usage(const char *name, const char *version) __attribute__((noreturn));
44 #define prog_name iptables_globals.program_name
46 static void print_usage(const char *name, const char *version)
48 fprintf(stderr, "Usage: %s [-b] [-c] [-v] [-t] [-h]\n"
55 " [ --table=<TABLE> ]\n"
56 " [ --modprobe=<command>]\n", name);
61 static struct iptc_handle *create_handle(const char *tablename)
63 struct iptc_handle *handle;
65 handle = iptc_init(tablename);
68 /* try to insmod the module if iptc_init failed */
69 xtables_load_ko(xtables_modprobe_program, false);
70 handle = iptc_init(tablename);
74 xtables_error(PARAMETER_PROBLEM, "%s: unable to initialize "
75 "table '%s'\n", prog_name, tablename);
81 static int parse_counters(char *string, struct ipt_counters *ctr)
83 unsigned long long pcnt, bcnt;
86 ret = sscanf(string, "[%llu:%llu]",
87 (unsigned long long *)&pcnt,
88 (unsigned long long *)&bcnt);
94 /* global new argv and argc */
95 static char *newargv[255];
98 /* function adding one argument to newargv, updating newargc
99 * returns true if argument added, false otherwise */
100 static int add_argv(char *what) {
101 DEBUGP("add_argv: %s\n", what);
102 if (what && newargc + 1 < ARRAY_SIZE(newargv)) {
103 newargv[newargc] = strdup(what);
110 static void free_argv(void) {
113 for (i = 0; i < newargc; i++)
117 #ifdef IPTABLES_MULTI
119 iptables_restore_main(int argc, char *argv[])
122 main(int argc, char *argv[])
125 struct iptc_handle *handle = NULL;
128 char curtable[IPT_TABLE_MAXNAMELEN + 1];
130 int in_table = 0, testing = 0;
131 const char *tablename = NULL;
135 iptables_globals.program_name = "iptables-restore";
136 c = xtables_init_all(&iptables_globals, NFPROTO_IPV4);
138 fprintf(stderr, "%s/%s Failed to initialize xtables\n",
139 iptables_globals.program_name,
140 iptables_globals.program_version);
143 #if defined(ALL_INCLUSIVE) || defined(NO_SHARED_LIBS)
147 while ((c = getopt_long(argc, argv, "bcvthnM:T:", options, NULL)) != -1) {
162 print_usage("iptables-restore",
169 xtables_modprobe_program = optarg;
177 if (optind == argc - 1) {
178 in = fopen(argv[optind], "r");
180 fprintf(stderr, "Can't open %s: %s\n", argv[optind],
185 else if (optind < argc) {
186 fprintf(stderr, "Unknown arguments found on commandline\n");
191 /* Grab standard input. */
192 while (fgets(buffer, sizeof(buffer), in)) {
196 if (buffer[0] == '\n')
198 else if (buffer[0] == '#') {
200 fputs(buffer, stdout);
202 } else if ((strcmp(buffer, "COMMIT\n") == 0) && (in_table)) {
204 DEBUGP("Calling commit\n");
205 ret = iptc_commit(handle);
209 DEBUGP("Not calling commit, testing\n");
213 } else if ((buffer[0] == '*') && (!in_table)) {
217 table = strtok(buffer+1, " \t\n");
218 DEBUGP("line %u, table '%s'\n", line, table);
220 xtables_error(PARAMETER_PROBLEM,
221 "%s: line %u table name invalid\n",
225 strncpy(curtable, table, IPT_TABLE_MAXNAMELEN);
226 curtable[IPT_TABLE_MAXNAMELEN] = '\0';
228 if (tablename && (strcmp(tablename, table) != 0))
233 handle = create_handle(table);
235 DEBUGP("Cleaning all chains of table '%s'\n",
237 for_each_chain(flush_entries, verbose, 1,
240 DEBUGP("Deleting all user-defined chains "
241 "of table '%s'\n", table);
242 for_each_chain(delete_chain, verbose, 0,
249 } else if ((buffer[0] == ':') && (in_table)) {
251 char *policy, *chain;
253 chain = strtok(buffer+1, " \t\n");
254 DEBUGP("line %u, chain '%s'\n", line, chain);
256 xtables_error(PARAMETER_PROBLEM,
257 "%s: line %u chain name invalid\n",
262 if (strlen(chain) >= XT_EXTENSION_MAXNAMELEN)
263 xtables_error(PARAMETER_PROBLEM,
264 "Invalid chain name `%s' "
266 chain, XT_EXTENSION_MAXNAMELEN - 1);
268 if (iptc_builtin(chain, handle) <= 0) {
269 if (noflush && iptc_is_chain(chain, handle)) {
270 DEBUGP("Flushing existing user defined chain '%s'\n", chain);
271 if (!iptc_flush_entries(chain, handle))
272 xtables_error(PARAMETER_PROBLEM,
273 "error flushing chain "
277 DEBUGP("Creating new chain '%s'\n", chain);
278 if (!iptc_create_chain(chain, handle))
279 xtables_error(PARAMETER_PROBLEM,
280 "error creating chain "
286 policy = strtok(NULL, " \t\n");
287 DEBUGP("line %u, policy '%s'\n", line, policy);
289 xtables_error(PARAMETER_PROBLEM,
290 "%s: line %u policy invalid\n",
295 if (strcmp(policy, "-") != 0) {
296 struct ipt_counters count;
300 ctrs = strtok(NULL, " \t\n");
302 if (!ctrs || !parse_counters(ctrs, &count))
303 xtables_error(PARAMETER_PROBLEM,
304 "invalid policy counters "
305 "for chain '%s'\n", chain);
309 sizeof(struct ipt_counters));
312 DEBUGP("Setting policy of chain %s to %s\n",
315 if (!iptc_set_policy(chain, policy, &count,
317 xtables_error(OTHER_PROBLEM,
318 "Can't set policy `%s'"
319 " on `%s' line %u: %s\n",
321 iptc_strerror(errno));
326 } else if (in_table) {
335 int quote_open, escaped;
338 /* reset the newargv */
341 if (buffer[0] == '[') {
342 /* we have counters in our input */
343 ptr = strchr(buffer, ']');
345 xtables_error(PARAMETER_PROBLEM,
346 "Bad line %u: need ]\n",
349 pcnt = strtok(buffer+1, ":");
351 xtables_error(PARAMETER_PROBLEM,
352 "Bad line %u: need :\n",
355 bcnt = strtok(NULL, "]");
357 xtables_error(PARAMETER_PROBLEM,
358 "Bad line %u: need ]\n",
361 /* start command parsing after counter */
362 parsestart = ptr + 1;
364 /* start command parsing at start of line */
370 add_argv((char *) &curtable);
372 if (counters && pcnt && bcnt) {
373 add_argv("--set-counters");
374 add_argv((char *) pcnt);
375 add_argv((char *) bcnt);
378 /* After fighting with strtok enough, here's now
379 * a 'real' parser. According to Rusty I'm now no
380 * longer a real hacker, but I can live with that */
386 for (curchar = parsestart; *curchar; curchar++) {
387 char param_buffer[1024];
391 param_buffer[param_len++] = *curchar;
394 } else if (*curchar == '\\') {
397 } else if (*curchar == '"') {
401 param_buffer[param_len++] = *curchar;
405 if (*curchar == '"') {
413 || * curchar == '\n') {
419 param_buffer[param_len] = '\0';
421 /* check if table name specified */
422 if (!strncmp(param_buffer, "-t", 2)
423 || !strncmp(param_buffer, "--table", 8)) {
424 xtables_error(PARAMETER_PROBLEM,
425 "Line %u seems to have a "
426 "-t table option.\n", line);
430 add_argv(param_buffer);
433 /* regular character, copy to buffer */
434 param_buffer[param_len++] = *curchar;
436 if (param_len >= sizeof(param_buffer))
437 xtables_error(PARAMETER_PROBLEM,
438 "Parameter too long!");
442 DEBUGP("calling do_command(%u, argv, &%s, handle):\n",
445 for (a = 0; a < newargc; a++)
446 DEBUGP("argv[%u]: %s\n", a, newargv[a]);
448 ret = do_command(newargc, newargv,
449 &newargv[2], &handle);
454 if (tablename && (strcmp(tablename, curtable) != 0))
457 fprintf(stderr, "%s: line %u failed\n",
463 fprintf(stderr, "%s: COMMIT expected at line %u\n",
464 prog_name, line + 1);