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
16 #include "libiptc/libiptc.h"
17 #include "iptables-multi.h"
20 #define DEBUGP(x, args...) fprintf(stderr, x, ## args)
22 #define DEBUGP(x, args...)
25 static int binary = 0, counters = 0, verbose = 0, noflush = 0;
27 /* Keeping track of external matches and targets. */
28 static const struct option options[] = {
29 {.name = "binary", .has_arg = false, .val = 'b'},
30 {.name = "counters", .has_arg = false, .val = 'c'},
31 {.name = "verbose", .has_arg = false, .val = 'v'},
32 {.name = "test", .has_arg = false, .val = 't'},
33 {.name = "help", .has_arg = false, .val = 'h'},
34 {.name = "noflush", .has_arg = false, .val = 'n'},
35 {.name = "modprobe", .has_arg = true, .val = 'M'},
36 {.name = "table", .has_arg = true, .val = 'T'},
40 static void print_usage(const char *name, const char *version) __attribute__((noreturn));
42 #define prog_name iptables_globals.program_name
44 static void print_usage(const char *name, const char *version)
46 fprintf(stderr, "Usage: %s [-b] [-c] [-v] [-t] [-h]\n"
53 " [ --table=<TABLE> ]\n"
54 " [ --modprobe=<command>]\n", name);
59 static struct xtc_handle *create_handle(const char *tablename)
61 struct xtc_handle *handle;
63 handle = iptc_init(tablename);
66 /* try to insmod the module if iptc_init failed */
67 xtables_load_ko(xtables_modprobe_program, false);
68 handle = iptc_init(tablename);
72 xtables_error(PARAMETER_PROBLEM, "%s: unable to initialize "
73 "table '%s'\n", prog_name, tablename);
79 static int parse_counters(char *string, struct xt_counters *ctr)
81 unsigned long long pcnt, bcnt;
84 ret = sscanf(string, "[%llu:%llu]", &pcnt, &bcnt);
90 /* global new argv and argc */
91 static char *newargv[255];
94 /* function adding one argument to newargv, updating newargc
95 * returns true if argument added, false otherwise */
96 static int add_argv(char *what) {
97 DEBUGP("add_argv: %s\n", what);
98 if (what && newargc + 1 < ARRAY_SIZE(newargv)) {
99 newargv[newargc] = strdup(what);
100 newargv[++newargc] = NULL;
103 xtables_error(PARAMETER_PROBLEM,
104 "Parser cannot handle more arguments\n");
109 static void free_argv(void) {
112 for (i = 0; i < newargc; i++)
116 static void add_param_to_argv(char *parsestart)
118 int quote_open = 0, escaped = 0, param_len = 0;
119 char param_buffer[1024], *curchar;
121 /* After fighting with strtok enough, here's now
122 * a 'real' parser. According to Rusty I'm now no
123 * longer a real hacker, but I can live with that */
125 for (curchar = parsestart; *curchar; curchar++) {
128 param_buffer[param_len++] = *curchar;
131 } else if (*curchar == '\\') {
134 } else if (*curchar == '"') {
138 param_buffer[param_len++] = *curchar;
142 if (*curchar == '"') {
150 || * curchar == '\n') {
156 param_buffer[param_len] = '\0';
158 /* check if table name specified */
159 if (!strncmp(param_buffer, "-t", 2)
160 || !strncmp(param_buffer, "--table", 8)) {
161 xtables_error(PARAMETER_PROBLEM,
162 "The -t option (seen in line %u) cannot be "
163 "used in iptables-restore.\n", line);
167 add_argv(param_buffer);
170 /* regular character, copy to buffer */
171 param_buffer[param_len++] = *curchar;
173 if (param_len >= sizeof(param_buffer))
174 xtables_error(PARAMETER_PROBLEM,
175 "Parameter too long!");
181 iptables_restore_main(int argc, char *argv[])
183 struct xtc_handle *handle = NULL;
186 char curtable[XT_TABLE_MAXNAMELEN + 1];
188 int in_table = 0, testing = 0;
189 const char *tablename = NULL;
190 const struct xtc_ops *ops = &iptc_ops;
194 iptables_globals.program_name = "iptables-restore";
195 c = xtables_init_all(&iptables_globals, NFPROTO_IPV4);
197 fprintf(stderr, "%s/%s Failed to initialize xtables\n",
198 iptables_globals.program_name,
199 iptables_globals.program_version);
202 #if defined(ALL_INCLUSIVE) || defined(NO_SHARED_LIBS)
207 while ((c = getopt_long(argc, argv, "bcvthnM:T:", options, NULL)) != -1) {
222 print_usage("iptables-restore",
229 xtables_modprobe_program = optarg;
237 if (optind == argc - 1) {
238 in = fopen(argv[optind], "re");
240 fprintf(stderr, "Can't open %s: %s\n", argv[optind],
245 else if (optind < argc) {
246 fprintf(stderr, "Unknown arguments found on commandline\n");
251 /* Grab standard input. */
252 while (fgets(buffer, sizeof(buffer), in)) {
256 if (buffer[0] == '\n')
258 else if (buffer[0] == '#') {
260 fputs(buffer, stdout);
262 } else if ((strcmp(buffer, "COMMIT\n") == 0) && (in_table)) {
264 DEBUGP("Calling commit\n");
265 ret = ops->commit(handle);
269 DEBUGP("Not calling commit, testing\n");
273 } else if ((buffer[0] == '*') && (!in_table)) {
277 table = strtok(buffer+1, " \t\n");
278 DEBUGP("line %u, table '%s'\n", line, table);
280 xtables_error(PARAMETER_PROBLEM,
281 "%s: line %u table name invalid\n",
282 xt_params->program_name, line);
285 strncpy(curtable, table, XT_TABLE_MAXNAMELEN);
286 curtable[XT_TABLE_MAXNAMELEN] = '\0';
288 if (tablename && (strcmp(tablename, table) != 0))
293 handle = create_handle(table);
295 DEBUGP("Cleaning all chains of table '%s'\n",
297 for_each_chain4(flush_entries4, verbose, 1,
300 DEBUGP("Deleting all user-defined chains "
301 "of table '%s'\n", table);
302 for_each_chain4(delete_chain4, verbose, 0,
309 } else if ((buffer[0] == ':') && (in_table)) {
311 char *policy, *chain;
313 chain = strtok(buffer+1, " \t\n");
314 DEBUGP("line %u, chain '%s'\n", line, chain);
316 xtables_error(PARAMETER_PROBLEM,
317 "%s: line %u chain name invalid\n",
318 xt_params->program_name, line);
322 if (strlen(chain) >= XT_EXTENSION_MAXNAMELEN)
323 xtables_error(PARAMETER_PROBLEM,
324 "Invalid chain name `%s' "
326 chain, XT_EXTENSION_MAXNAMELEN - 1);
328 if (ops->builtin(chain, handle) <= 0) {
329 if (noflush && ops->is_chain(chain, handle)) {
330 DEBUGP("Flushing existing user defined chain '%s'\n", chain);
331 if (!ops->flush_entries(chain, handle))
332 xtables_error(PARAMETER_PROBLEM,
333 "error flushing chain "
337 DEBUGP("Creating new chain '%s'\n", chain);
338 if (!ops->create_chain(chain, handle))
339 xtables_error(PARAMETER_PROBLEM,
340 "error creating chain "
346 policy = strtok(NULL, " \t\n");
347 DEBUGP("line %u, policy '%s'\n", line, policy);
349 xtables_error(PARAMETER_PROBLEM,
350 "%s: line %u policy invalid\n",
351 xt_params->program_name, line);
355 if (strcmp(policy, "-") != 0) {
356 struct xt_counters count;
360 ctrs = strtok(NULL, " \t\n");
362 if (!ctrs || !parse_counters(ctrs, &count))
363 xtables_error(PARAMETER_PROBLEM,
364 "invalid policy counters "
365 "for chain '%s'\n", chain);
368 memset(&count, 0, sizeof(count));
371 DEBUGP("Setting policy of chain %s to %s\n",
374 if (!ops->set_policy(chain, policy, &count,
376 xtables_error(OTHER_PROBLEM,
377 "Can't set policy `%s'"
378 " on `%s' line %u: %s\n",
380 ops->strerror(errno));
385 } else if (in_table) {
392 /* reset the newargv */
395 if (buffer[0] == '[') {
396 /* we have counters in our input */
397 ptr = strchr(buffer, ']');
399 xtables_error(PARAMETER_PROBLEM,
400 "Bad line %u: need ]\n",
403 pcnt = strtok(buffer+1, ":");
405 xtables_error(PARAMETER_PROBLEM,
406 "Bad line %u: need :\n",
409 bcnt = strtok(NULL, "]");
411 xtables_error(PARAMETER_PROBLEM,
412 "Bad line %u: need ]\n",
415 /* start command parsing after counter */
416 parsestart = ptr + 1;
418 /* start command parsing at start of line */
426 if (counters && pcnt && bcnt) {
427 add_argv("--set-counters");
428 add_argv((char *) pcnt);
429 add_argv((char *) bcnt);
432 add_param_to_argv(parsestart);
434 DEBUGP("calling do_command4(%u, argv, &%s, handle):\n",
437 for (a = 0; a < newargc; a++)
438 DEBUGP("argv[%u]: %s\n", a, newargv[a]);
440 ret = do_command4(newargc, newargv,
441 &newargv[2], &handle, true);
446 if (tablename && (strcmp(tablename, curtable) != 0))
449 fprintf(stderr, "%s: line %u failed\n",
450 xt_params->program_name, line);
455 fprintf(stderr, "%s: COMMIT expected at line %u\n",
456 xt_params->program_name, line + 1);