upload tizen1.0 source
[external/iptables.git] / iptables / iptables-restore.c
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>
4  *
5  * This code is distributed under the terms of GNU GPL v2
6  */
7
8 #include <getopt.h>
9 #include <sys/errno.h>
10 #include <stdbool.h>
11 #include <string.h>
12 #include <stdio.h>
13 #include <stdlib.h>
14 #include "iptables.h"
15 #include "xtables.h"
16 #include "libiptc/libiptc.h"
17 #include "iptables-multi.h"
18
19 #ifdef DEBUG
20 #define DEBUGP(x, args...) fprintf(stderr, x, ## args)
21 #else
22 #define DEBUGP(x, args...)
23 #endif
24
25 static int binary = 0, counters = 0, verbose = 0, noflush = 0;
26
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'},
37         {NULL},
38 };
39
40 static void print_usage(const char *name, const char *version) __attribute__((noreturn));
41
42 #define prog_name iptables_globals.program_name
43
44 static void print_usage(const char *name, const char *version)
45 {
46         fprintf(stderr, "Usage: %s [-b] [-c] [-v] [-t] [-h]\n"
47                         "          [ --binary ]\n"
48                         "          [ --counters ]\n"
49                         "          [ --verbose ]\n"
50                         "          [ --test ]\n"
51                         "          [ --help ]\n"
52                         "          [ --noflush ]\n"
53                         "          [ --table=<TABLE> ]\n"
54                         "          [ --modprobe=<command>]\n", name);
55
56         exit(1);
57 }
58
59 static struct xtc_handle *create_handle(const char *tablename)
60 {
61         struct xtc_handle *handle;
62
63         handle = iptc_init(tablename);
64
65         if (!handle) {
66                 /* try to insmod the module if iptc_init failed */
67                 xtables_load_ko(xtables_modprobe_program, false);
68                 handle = iptc_init(tablename);
69         }
70
71         if (!handle) {
72                 xtables_error(PARAMETER_PROBLEM, "%s: unable to initialize "
73                         "table '%s'\n", prog_name, tablename);
74                 exit(1);
75         }
76         return handle;
77 }
78
79 static int parse_counters(char *string, struct xt_counters *ctr)
80 {
81         unsigned long long pcnt, bcnt;
82         int ret;
83
84         ret = sscanf(string, "[%llu:%llu]", &pcnt, &bcnt);
85         ctr->pcnt = pcnt;
86         ctr->bcnt = bcnt;
87         return ret == 2;
88 }
89
90 /* global new argv and argc */
91 static char *newargv[255];
92 static int newargc;
93
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;
101                 return 1;
102         } else {
103                 xtables_error(PARAMETER_PROBLEM,
104                         "Parser cannot handle more arguments\n");
105                 return 0;
106         }
107 }
108
109 static void free_argv(void) {
110         int i;
111
112         for (i = 0; i < newargc; i++)
113                 free(newargv[i]);
114 }
115
116 static void add_param_to_argv(char *parsestart)
117 {
118         int quote_open = 0, escaped = 0, param_len = 0;
119         char param_buffer[1024], *curchar;
120
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 */
124
125         for (curchar = parsestart; *curchar; curchar++) {
126                 if (quote_open) {
127                         if (escaped) {
128                                 param_buffer[param_len++] = *curchar;
129                                 escaped = 0;
130                                 continue;
131                         } else if (*curchar == '\\') {
132                                 escaped = 1;
133                                 continue;
134                         } else if (*curchar == '"') {
135                                 quote_open = 0;
136                                 *curchar = ' ';
137                         } else {
138                                 param_buffer[param_len++] = *curchar;
139                                 continue;
140                         }
141                 } else {
142                         if (*curchar == '"') {
143                                 quote_open = 1;
144                                 continue;
145                         }
146                 }
147
148                 if (*curchar == ' '
149                     || *curchar == '\t'
150                     || * curchar == '\n') {
151                         if (!param_len) {
152                                 /* two spaces? */
153                                 continue;
154                         }
155
156                         param_buffer[param_len] = '\0';
157
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);
164                                 exit(1);
165                         }
166
167                         add_argv(param_buffer);
168                         param_len = 0;
169                 } else {
170                         /* regular character, copy to buffer */
171                         param_buffer[param_len++] = *curchar;
172
173                         if (param_len >= sizeof(param_buffer))
174                                 xtables_error(PARAMETER_PROBLEM,
175                                    "Parameter too long!");
176                 }
177         }
178 }
179
180 int
181 iptables_restore_main(int argc, char *argv[])
182 {
183         struct xtc_handle *handle = NULL;
184         char buffer[10240];
185         int c;
186         char curtable[XT_TABLE_MAXNAMELEN + 1];
187         FILE *in;
188         int in_table = 0, testing = 0;
189         const char *tablename = NULL;
190         const struct xtc_ops *ops = &iptc_ops;
191
192         line = 0;
193
194         iptables_globals.program_name = "iptables-restore";
195         c = xtables_init_all(&iptables_globals, NFPROTO_IPV4);
196         if (c < 0) {
197                 fprintf(stderr, "%s/%s Failed to initialize xtables\n",
198                                 iptables_globals.program_name,
199                                 iptables_globals.program_version);
200                 exit(1);
201         }
202 #if defined(ALL_INCLUSIVE) || defined(NO_SHARED_LIBS)
203         init_extensions();
204         init_extensions4();
205 #endif
206
207         while ((c = getopt_long(argc, argv, "bcvthnM:T:", options, NULL)) != -1) {
208                 switch (c) {
209                         case 'b':
210                                 binary = 1;
211                                 break;
212                         case 'c':
213                                 counters = 1;
214                                 break;
215                         case 'v':
216                                 verbose = 1;
217                                 break;
218                         case 't':
219                                 testing = 1;
220                                 break;
221                         case 'h':
222                                 print_usage("iptables-restore",
223                                             IPTABLES_VERSION);
224                                 break;
225                         case 'n':
226                                 noflush = 1;
227                                 break;
228                         case 'M':
229                                 xtables_modprobe_program = optarg;
230                                 break;
231                         case 'T':
232                                 tablename = optarg;
233                                 break;
234                 }
235         }
236
237         if (optind == argc - 1) {
238                 in = fopen(argv[optind], "re");
239                 if (!in) {
240                         fprintf(stderr, "Can't open %s: %s\n", argv[optind],
241                                 strerror(errno));
242                         exit(1);
243                 }
244         }
245         else if (optind < argc) {
246                 fprintf(stderr, "Unknown arguments found on commandline\n");
247                 exit(1);
248         }
249         else in = stdin;
250
251         /* Grab standard input. */
252         while (fgets(buffer, sizeof(buffer), in)) {
253                 int ret = 0;
254
255                 line++;
256                 if (buffer[0] == '\n')
257                         continue;
258                 else if (buffer[0] == '#') {
259                         if (verbose)
260                                 fputs(buffer, stdout);
261                         continue;
262                 } else if ((strcmp(buffer, "COMMIT\n") == 0) && (in_table)) {
263                         if (!testing) {
264                                 DEBUGP("Calling commit\n");
265                                 ret = ops->commit(handle);
266                                 ops->free(handle);
267                                 handle = NULL;
268                         } else {
269                                 DEBUGP("Not calling commit, testing\n");
270                                 ret = 1;
271                         }
272                         in_table = 0;
273                 } else if ((buffer[0] == '*') && (!in_table)) {
274                         /* New table */
275                         char *table;
276
277                         table = strtok(buffer+1, " \t\n");
278                         DEBUGP("line %u, table '%s'\n", line, table);
279                         if (!table) {
280                                 xtables_error(PARAMETER_PROBLEM,
281                                         "%s: line %u table name invalid\n",
282                                         xt_params->program_name, line);
283                                 exit(1);
284                         }
285                         strncpy(curtable, table, XT_TABLE_MAXNAMELEN);
286                         curtable[XT_TABLE_MAXNAMELEN] = '\0';
287
288                         if (tablename && (strcmp(tablename, table) != 0))
289                                 continue;
290                         if (handle)
291                                 ops->free(handle);
292
293                         handle = create_handle(table);
294                         if (noflush == 0) {
295                                 DEBUGP("Cleaning all chains of table '%s'\n",
296                                         table);
297                                 for_each_chain4(flush_entries4, verbose, 1,
298                                                 handle);
299
300                                 DEBUGP("Deleting all user-defined chains "
301                                        "of table '%s'\n", table);
302                                 for_each_chain4(delete_chain4, verbose, 0,
303                                                 handle);
304                         }
305
306                         ret = 1;
307                         in_table = 1;
308
309                 } else if ((buffer[0] == ':') && (in_table)) {
310                         /* New chain. */
311                         char *policy, *chain;
312
313                         chain = strtok(buffer+1, " \t\n");
314                         DEBUGP("line %u, chain '%s'\n", line, chain);
315                         if (!chain) {
316                                 xtables_error(PARAMETER_PROBLEM,
317                                            "%s: line %u chain name invalid\n",
318                                            xt_params->program_name, line);
319                                 exit(1);
320                         }
321
322                         if (strlen(chain) >= XT_EXTENSION_MAXNAMELEN)
323                                 xtables_error(PARAMETER_PROBLEM,
324                                            "Invalid chain name `%s' "
325                                            "(%u chars max)",
326                                            chain, XT_EXTENSION_MAXNAMELEN - 1);
327
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 "
334                                                            "'%s':%s\n", chain,
335                                                            strerror(errno));
336                                 } else {
337                                         DEBUGP("Creating new chain '%s'\n", chain);
338                                         if (!ops->create_chain(chain, handle))
339                                                 xtables_error(PARAMETER_PROBLEM,
340                                                            "error creating chain "
341                                                            "'%s':%s\n", chain,
342                                                            strerror(errno));
343                                 }
344                         }
345
346                         policy = strtok(NULL, " \t\n");
347                         DEBUGP("line %u, policy '%s'\n", line, policy);
348                         if (!policy) {
349                                 xtables_error(PARAMETER_PROBLEM,
350                                            "%s: line %u policy invalid\n",
351                                            xt_params->program_name, line);
352                                 exit(1);
353                         }
354
355                         if (strcmp(policy, "-") != 0) {
356                                 struct xt_counters count;
357
358                                 if (counters) {
359                                         char *ctrs;
360                                         ctrs = strtok(NULL, " \t\n");
361
362                                         if (!ctrs || !parse_counters(ctrs, &count))
363                                                 xtables_error(PARAMETER_PROBLEM,
364                                                            "invalid policy counters "
365                                                            "for chain '%s'\n", chain);
366
367                                 } else {
368                                         memset(&count, 0, sizeof(count));
369                                 }
370
371                                 DEBUGP("Setting policy of chain %s to %s\n",
372                                         chain, policy);
373
374                                 if (!ops->set_policy(chain, policy, &count,
375                                                      handle))
376                                         xtables_error(OTHER_PROBLEM,
377                                                 "Can't set policy `%s'"
378                                                 " on `%s' line %u: %s\n",
379                                                 policy, chain, line,
380                                                 ops->strerror(errno));
381                         }
382
383                         ret = 1;
384
385                 } else if (in_table) {
386                         int a;
387                         char *ptr = buffer;
388                         char *pcnt = NULL;
389                         char *bcnt = NULL;
390                         char *parsestart;
391
392                         /* reset the newargv */
393                         newargc = 0;
394
395                         if (buffer[0] == '[') {
396                                 /* we have counters in our input */
397                                 ptr = strchr(buffer, ']');
398                                 if (!ptr)
399                                         xtables_error(PARAMETER_PROBLEM,
400                                                    "Bad line %u: need ]\n",
401                                                    line);
402
403                                 pcnt = strtok(buffer+1, ":");
404                                 if (!pcnt)
405                                         xtables_error(PARAMETER_PROBLEM,
406                                                    "Bad line %u: need :\n",
407                                                    line);
408
409                                 bcnt = strtok(NULL, "]");
410                                 if (!bcnt)
411                                         xtables_error(PARAMETER_PROBLEM,
412                                                    "Bad line %u: need ]\n",
413                                                    line);
414
415                                 /* start command parsing after counter */
416                                 parsestart = ptr + 1;
417                         } else {
418                                 /* start command parsing at start of line */
419                                 parsestart = buffer;
420                         }
421
422                         add_argv(argv[0]);
423                         add_argv("-t");
424                         add_argv(curtable);
425
426                         if (counters && pcnt && bcnt) {
427                                 add_argv("--set-counters");
428                                 add_argv((char *) pcnt);
429                                 add_argv((char *) bcnt);
430                         }
431
432                         add_param_to_argv(parsestart);
433
434                         DEBUGP("calling do_command4(%u, argv, &%s, handle):\n",
435                                 newargc, curtable);
436
437                         for (a = 0; a < newargc; a++)
438                                 DEBUGP("argv[%u]: %s\n", a, newargv[a]);
439
440                         ret = do_command4(newargc, newargv,
441                                          &newargv[2], &handle, true);
442
443                         free_argv();
444                         fflush(stdout);
445                 }
446                 if (tablename && (strcmp(tablename, curtable) != 0))
447                         continue;
448                 if (!ret) {
449                         fprintf(stderr, "%s: line %u failed\n",
450                                         xt_params->program_name, line);
451                         exit(1);
452                 }
453         }
454         if (in_table) {
455                 fprintf(stderr, "%s: COMMIT expected at line %u\n",
456                                 xt_params->program_name, line + 1);
457                 exit(1);
458         }
459
460         fclose(in);
461         return 0;
462 }