OSDN Git Service

Fix no pic
[uclinux-h8/uClinux-dist.git] / user / iptables / ip6tables-restore.c
1 /* Code to restore the iptables state, from file by ip6tables-save.
2  * Author:  Andras Kis-Szabo <kisza@sch.bme.hu>
3  *
4  * based on iptables-restore
5  * Authors:
6  *      Harald Welte <laforge@gnumonks.org>
7  *      Rusty Russell <rusty@linuxcare.com.au>
8  * This code is distributed under the terms of GNU GPL v2
9  *
10  * $Id$
11  */
12
13 #include <getopt.h>
14 #include <sys/errno.h>
15 #include <stdbool.h>
16 #include <string.h>
17 #include <stdio.h>
18 #include <stdlib.h>
19 #include "ip6tables.h"
20 #include "xtables.h"
21 #include "libiptc/libip6tc.h"
22 #include "ip6tables-multi.h"
23
24 #ifdef DEBUG
25 #define DEBUGP(x, args...) fprintf(stderr, x, ## args)
26 #else
27 #define DEBUGP(x, args...)
28 #endif
29
30 static int binary = 0, counters = 0, verbose = 0, noflush = 0;
31
32 /* Keeping track of external matches and targets.  */
33 static const struct option options[] = {
34         {.name = "binary",   .has_arg = false, .val = 'b'},
35         {.name = "counters", .has_arg = false, .val = 'c'},
36         {.name = "verbose",  .has_arg = false, .val = 'v'},
37         {.name = "test",     .has_arg = false, .val = 't'},
38         {.name = "help",     .has_arg = false, .val = 'h'},
39         {.name = "noflush",  .has_arg = false, .val = 'n'},
40         {.name = "modprobe", .has_arg = true,  .val = 'M'},
41         {NULL},
42 };
43
44 static void print_usage(const char *name, const char *version) __attribute__((noreturn));
45
46 static void print_usage(const char *name, const char *version)
47 {
48         fprintf(stderr, "Usage: %s [-b] [-c] [-v] [-t] [-h]\n"
49                         "          [ --binary ]\n"
50                         "          [ --counters ]\n"
51                         "          [ --verbose ]\n"
52                         "          [ --test ]\n"
53                         "          [ --help ]\n"
54                         "          [ --noflush ]\n"
55                         "          [ --modprobe=<command>]\n", name);
56
57         exit(1);
58 }
59
60 static struct ip6tc_handle *create_handle(const char *tablename)
61 {
62         struct ip6tc_handle *handle;
63
64         handle = ip6tc_init(tablename);
65
66         if (!handle) {
67                 /* try to insmod the module if iptc_init failed */
68                 xtables_load_ko(xtables_modprobe_program, false);
69                 handle = ip6tc_init(tablename);
70         }
71
72         if (!handle) {
73                 xtables_error(PARAMETER_PROBLEM, "%s: unable to initialize "
74                         "table '%s'\n", ip6tables_globals.program_name,
75                         tablename);
76                 exit(1);
77         }
78         return handle;
79 }
80
81 static int parse_counters(char *string, struct ip6t_counters *ctr)
82 {
83         unsigned long long pcnt, bcnt;
84         int ret;
85
86         ret = sscanf(string, "[%llu:%llu]",
87                      (unsigned long long *)&pcnt,
88                      (unsigned long long *)&bcnt);
89         ctr->pcnt = pcnt;
90         ctr->bcnt = bcnt;
91         return ret == 2;
92 }
93
94 /* global new argv and argc */
95 static char *newargv[255];
96 static int newargc;
97
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) < sizeof(newargv)/sizeof(char *))) {
103                 newargv[newargc] = strdup(what);
104                 newargc++;
105                 return 1;
106         } else
107                 return 0;
108 }
109
110 static void free_argv(void) {
111         int i;
112
113         for (i = 0; i < newargc; i++)
114                 free(newargv[i]);
115 }
116
117 #ifdef IPTABLES_MULTI
118 int ip6tables_restore_main(int argc, char *argv[])
119 #else
120 int main(int argc, char *argv[])
121 #endif
122 {
123         struct ip6tc_handle *handle = NULL;
124         char buffer[10240];
125         int c;
126         char curtable[IP6T_TABLE_MAXNAMELEN + 1];
127         FILE *in;
128         int in_table = 0, testing = 0;
129
130         line = 0;
131
132         ip6tables_globals.program_name = "ip6tables-restore";
133         c = xtables_init_all(&ip6tables_globals, NFPROTO_IPV6);
134         if (c < 0) {
135                 fprintf(stderr, "%s/%s Failed to initialize xtables\n",
136                                 ip6tables_globals.program_name,
137                                 ip6tables_globals.program_version);
138                 exit(1);
139         }
140 #ifdef NO_SHARED_LIBS
141         init_extensions();
142 #endif
143
144         while ((c = getopt_long(argc, argv, "bcvthnM:", options, NULL)) != -1) {
145                 switch (c) {
146                         case 'b':
147                                 binary = 1;
148                                 break;
149                         case 'c':
150                                 counters = 1;
151                                 break;
152                         case 'v':
153                                 verbose = 1;
154                                 break;
155                         case 't':
156                                 testing = 1;
157                                 break;
158                         case 'h':
159                                 print_usage("ip6tables-restore",
160                                             IPTABLES_VERSION);
161                                 break;
162                         case 'n':
163                                 noflush = 1;
164                                 break;
165                         case 'M':
166                                 xtables_modprobe_program = optarg;
167                                 break;
168                 }
169         }
170
171         if (optind == argc - 1) {
172                 in = fopen(argv[optind], "r");
173                 if (!in) {
174                         fprintf(stderr, "Can't open %s: %s\n", argv[optind],
175                                 strerror(errno));
176                         exit(1);
177                 }
178         }
179         else if (optind < argc) {
180                 fprintf(stderr, "Unknown arguments found on commandline\n");
181                 exit(1);
182         }
183         else in = stdin;
184
185         /* Grab standard input. */
186         while (fgets(buffer, sizeof(buffer), in)) {
187                 int ret = 0;
188
189                 line++;
190                 if (buffer[0] == '\n')
191                         continue;
192                 else if (buffer[0] == '#') {
193                         if (verbose)
194                                 fputs(buffer, stdout);
195                         continue;
196                 } else if ((strcmp(buffer, "COMMIT\n") == 0) && (in_table)) {
197                         if (!testing) {
198                                 DEBUGP("Calling commit\n");
199                                 ret = ip6tc_commit(handle);
200                                 ip6tc_free(handle);
201                                 handle = NULL;
202                         } else {
203                                 DEBUGP("Not calling commit, testing\n");
204                                 ret = 1;
205                         }
206                         in_table = 0;
207                 } else if ((buffer[0] == '*') && (!in_table)) {
208                         /* New table */
209                         char *table;
210
211                         table = strtok(buffer+1, " \t\n");
212                         DEBUGP("line %u, table '%s'\n", line, table);
213                         if (!table) {
214                                 xtables_error(PARAMETER_PROBLEM,
215                                         "%s: line %u table name invalid\n",
216                                         ip6tables_globals.program_name,
217                                         line);
218                                 exit(1);
219                         }
220                         strncpy(curtable, table, IP6T_TABLE_MAXNAMELEN);
221                         curtable[IP6T_TABLE_MAXNAMELEN] = '\0';
222
223                         if (handle)
224                                 ip6tc_free(handle);
225
226                         handle = create_handle(table);
227                         if (noflush == 0) {
228                                 DEBUGP("Cleaning all chains of table '%s'\n",
229                                         table);
230                                 for_each_chain(flush_entries, verbose, 1,
231                                                 handle);
232
233                                 DEBUGP("Deleting all user-defined chains "
234                                        "of table '%s'\n", table);
235                                 for_each_chain(delete_chain, verbose, 0,
236                                                 handle);
237                         }
238
239                         ret = 1;
240                         in_table = 1;
241
242                 } else if ((buffer[0] == ':') && (in_table)) {
243                         /* New chain. */
244                         char *policy, *chain;
245
246                         chain = strtok(buffer+1, " \t\n");
247                         DEBUGP("line %u, chain '%s'\n", line, chain);
248                         if (!chain) {
249                                 xtables_error(PARAMETER_PROBLEM,
250                                            "%s: line %u chain name invalid\n",
251                                            ip6tables_globals.program_name,
252                                            line);
253                                 exit(1);
254                         }
255
256                         if (ip6tc_builtin(chain, handle) <= 0) {
257                                 if (noflush && ip6tc_is_chain(chain, handle)) {
258                                         DEBUGP("Flushing existing user defined chain '%s'\n", chain);
259                                         if (!ip6tc_flush_entries(chain, handle))
260                                                 xtables_error(PARAMETER_PROBLEM,
261                                                            "error flushing chain "
262                                                            "'%s':%s\n", chain,
263                                                            strerror(errno));
264                                 } else {
265                                         DEBUGP("Creating new chain '%s'\n", chain);
266                                         if (!ip6tc_create_chain(chain, handle))
267                                                 xtables_error(PARAMETER_PROBLEM,
268                                                            "error creating chain "
269                                                            "'%s':%s\n", chain,
270                                                            strerror(errno));
271                                 }
272                         }
273
274                         policy = strtok(NULL, " \t\n");
275                         DEBUGP("line %u, policy '%s'\n", line, policy);
276                         if (!policy) {
277                                 xtables_error(PARAMETER_PROBLEM,
278                                            "%s: line %u policy invalid\n",
279                                            ip6tables_globals.program_name,
280                                            line);
281                                 exit(1);
282                         }
283
284                         if (strcmp(policy, "-") != 0) {
285                                 struct ip6t_counters count;
286
287                                 if (counters) {
288                                         char *ctrs;
289                                         ctrs = strtok(NULL, " \t\n");
290
291                                         if (!ctrs || !parse_counters(ctrs, &count))
292                                                 xtables_error(PARAMETER_PROBLEM,
293                                                           "invalid policy counters "
294                                                           "for chain '%s'\n", chain);
295
296                                 } else {
297                                         memset(&count, 0,
298                                                sizeof(struct ip6t_counters));
299                                 }
300
301                                 DEBUGP("Setting policy of chain %s to %s\n",
302                                         chain, policy);
303
304                                 if (!ip6tc_set_policy(chain, policy, &count,
305                                                      handle))
306                                         xtables_error(OTHER_PROBLEM,
307                                                 "Can't set policy `%s'"
308                                                 " on `%s' line %u: %s\n",
309                                                 chain, policy, line,
310                                                 ip6tc_strerror(errno));
311                         }
312
313                         ret = 1;
314
315                 } else if (in_table) {
316                         int a;
317                         char *ptr = buffer;
318                         char *pcnt = NULL;
319                         char *bcnt = NULL;
320                         char *parsestart;
321
322                         /* the parser */
323                         char *curchar;
324                         int quote_open, escaped;
325                         size_t param_len;
326
327                         /* reset the newargv */
328                         newargc = 0;
329
330                         if (buffer[0] == '[') {
331                                 /* we have counters in our input */
332                                 ptr = strchr(buffer, ']');
333                                 if (!ptr)
334                                         xtables_error(PARAMETER_PROBLEM,
335                                                    "Bad line %u: need ]\n",
336                                                    line);
337
338                                 pcnt = strtok(buffer+1, ":");
339                                 if (!pcnt)
340                                         xtables_error(PARAMETER_PROBLEM,
341                                                    "Bad line %u: need :\n",
342                                                    line);
343
344                                 bcnt = strtok(NULL, "]");
345                                 if (!bcnt)
346                                         xtables_error(PARAMETER_PROBLEM,
347                                                    "Bad line %u: need ]\n",
348                                                    line);
349
350                                 /* start command parsing after counter */
351                                 parsestart = ptr + 1;
352                         } else {
353                                 /* start command parsing at start of line */
354                                 parsestart = buffer;
355                         }
356
357                         add_argv(argv[0]);
358                         add_argv("-t");
359                         add_argv((char *) &curtable);
360
361                         if (counters && pcnt && bcnt) {
362                                 add_argv("--set-counters");
363                                 add_argv((char *) pcnt);
364                                 add_argv((char *) bcnt);
365                         }
366
367                         /* After fighting with strtok enough, here's now
368                          * a 'real' parser. According to Rusty I'm now no
369                          * longer a real hacker, but I can live with that */
370
371                         quote_open = 0;
372                         escaped = 0;
373                         param_len = 0;
374
375                         for (curchar = parsestart; *curchar; curchar++) {
376                                 char param_buffer[1024];
377
378                                 if (quote_open) {
379                                         if (escaped) {
380                                                 param_buffer[param_len++] = *curchar;
381                                                 escaped = 0;
382                                                 continue;
383                                         } else if (*curchar == '\\') {
384                                                 escaped = 1;
385                                                 continue;
386                                         } else if (*curchar == '"') {
387                                                 quote_open = 0;
388                                                 *curchar = ' ';
389                                         } else {
390                                                 param_buffer[param_len++] = *curchar;
391                                                 continue;
392                                         }
393                                 } else {
394                                         if (*curchar == '"') {
395                                                 quote_open = 1;
396                                                 continue;
397                                         }
398                                 }
399
400                                 if (*curchar == ' '
401                                     || *curchar == '\t'
402                                     || * curchar == '\n') {
403                                         if (!param_len) {
404                                                 /* two spaces? */
405                                                 continue;
406                                         }
407
408                                         param_buffer[param_len] = '\0';
409
410                                         /* check if table name specified */
411                                         if (!strncmp(param_buffer, "-t", 2)
412                                             || !strncmp(param_buffer, "--table", 8)) {
413                                                 xtables_error(PARAMETER_PROBLEM,
414                                                    "Line %u seems to have a "
415                                                    "-t table option.\n", line);
416                                                 exit(1);
417                                         }
418
419                                         add_argv(param_buffer);
420                                         param_len = 0;
421                                 } else {
422                                         /* regular character, copy to buffer */
423                                         param_buffer[param_len++] = *curchar;
424
425                                         if (param_len >= sizeof(param_buffer))
426                                                 xtables_error(PARAMETER_PROBLEM,
427                                                    "Parameter too long!");
428                                 }
429                         }
430
431                         DEBUGP("calling do_command6(%u, argv, &%s, handle):\n",
432                                 newargc, curtable);
433
434                         for (a = 0; a < newargc; a++)
435                                 DEBUGP("argv[%u]: %s\n", a, newargv[a]);
436
437                         ret = do_command6(newargc, newargv,
438                                          &newargv[2], &handle);
439
440                         free_argv();
441                         fflush(stdout);
442                 }
443                 if (!ret) {
444                         fprintf(stderr, "%s: line %u failed\n",
445                                         ip6tables_globals.program_name,
446                                         line);
447                         exit(1);
448                 }
449         }
450         if (in_table) {
451                 fprintf(stderr, "%s: COMMIT expected at line %u\n",
452                                 ip6tables_globals.program_name,
453                                 line + 1);
454                 exit(1);
455         }
456
457         return 0;
458 }