nft: Drop interface mask leftovers from post_parse callbacks
[iptables-mirror.git] / iptables / xtables-restore.c
blob23cd349819f4f5258054901c7a5807665beacbb7
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
6 */
7 #include "config.h"
8 #include <getopt.h>
9 #include <errno.h>
10 #include <libgen.h>
11 #include <stdbool.h>
12 #include <string.h>
13 #include <stdio.h>
14 #include <stdlib.h>
15 #include "iptables.h"
16 #include "xtables.h"
17 #include "libiptc/libiptc.h"
18 #include "xtables-multi.h"
19 #include "nft.h"
20 #include "nft-bridge.h"
21 #include "nft-cache.h"
22 #include <libnftnl/chain.h>
24 static int counters, verbose;
26 /* Keeping track of external matches and targets. */
27 static const struct option options[] = {
28 {.name = "counters", .has_arg = false, .val = 'c'},
29 {.name = "verbose", .has_arg = false, .val = 'v'},
30 {.name = "version", .has_arg = 0, .val = 'V'},
31 {.name = "test", .has_arg = false, .val = 't'},
32 {.name = "help", .has_arg = false, .val = 'h'},
33 {.name = "noflush", .has_arg = false, .val = 'n'},
34 {.name = "modprobe", .has_arg = true, .val = 'M'},
35 {.name = "table", .has_arg = true, .val = 'T'},
36 {.name = "ipv4", .has_arg = false, .val = '4'},
37 {.name = "ipv6", .has_arg = false, .val = '6'},
38 {.name = "wait", .has_arg = 2, .val = 'w'},
39 {.name = "wait-interval", .has_arg = 2, .val = 'W'},
40 {NULL},
43 #define prog_name xtables_globals.program_name
44 #define prog_vers xtables_globals.program_version
46 static void print_usage(const char *name, const char *version)
48 fprintf(stderr, "Usage: %s [-c] [-v] [-V] [-t] [-h] [-n] [-T table] [-M command] [-4] [-6] [file]\n"
49 " [ --counters ]\n"
50 " [ --verbose ]\n"
51 " [ --version]\n"
52 " [ --test ]\n"
53 " [ --help ]\n"
54 " [ --noflush ]\n"
55 " [ --table=<TABLE> ]\n"
56 " [ --modprobe=<command> ]\n"
57 " [ --ipv4 ]\n"
58 " [ --ipv6 ]\n", name);
61 static const struct nft_xt_restore_cb restore_cb = {
62 .commit = nft_commit,
63 .abort = nft_abort,
64 .table_flush = nft_cmd_table_flush,
65 .do_command = do_commandx,
66 .chain_set = nft_cmd_chain_set,
67 .chain_restore = nft_cmd_chain_restore,
70 struct nft_xt_restore_state {
71 const struct builtin_table *curtable;
72 struct argv_store av_store;
73 bool in_table;
76 static void xtables_restore_parse_line(struct nft_handle *h,
77 const struct nft_xt_restore_parse *p,
78 struct nft_xt_restore_state *state,
79 char *buffer)
81 const struct nft_xt_restore_cb *cb = p->cb;
82 int ret = 0;
84 if (buffer[0] == '\n')
85 return;
86 else if (buffer[0] == '#') {
87 if (verbose) {
88 fputs(buffer, stdout);
89 fflush(stdout);
91 return;
92 } else if (state->in_table &&
93 (strncmp(buffer, "COMMIT", 6) == 0) &&
94 (buffer[6] == '\0' || buffer[6] == '\n')) {
95 if (!p->testing) {
96 /* Commit per table, although we support
97 * global commit at once, stick by now to
98 * the existing behaviour.
100 DEBUGP("Calling commit\n");
101 if (cb->commit)
102 ret = cb->commit(h);
103 } else {
104 DEBUGP("Not calling commit, testing\n");
105 if (cb->abort)
106 ret = cb->abort(h);
108 state->in_table = false;
110 } else if ((buffer[0] == '*') && (!state->in_table || !p->commit)) {
111 /* New table */
112 char *table;
114 table = strtok(buffer+1, " \t\n");
115 DEBUGP("line %u, table '%s'\n", line, table);
116 if (!table)
117 xtables_error(PARAMETER_PROBLEM,
118 "%s: line %u table name invalid",
119 xt_params->program_name, line);
121 state->curtable = nft_table_builtin_find(h, table);
122 if (!state->curtable)
123 xtables_error(PARAMETER_PROBLEM,
124 "%s: line %u table name '%s' invalid",
125 xt_params->program_name, line, table);
127 if (p->tablename && (strcmp(p->tablename, table) != 0))
128 return;
130 /* implicit commit if no explicit COMMIT supported */
131 if (!p->commit)
132 cb->commit(h);
134 if (h->noflush == 0) {
135 DEBUGP("Cleaning all chains of table '%s'\n", table);
136 if (cb->table_flush)
137 cb->table_flush(h, table, verbose);
140 ret = 1;
141 state->in_table = true;
143 if (cb->table_new)
144 cb->table_new(h, table);
146 } else if ((buffer[0] == ':') && state->in_table) {
147 /* New chain. */
148 char *policy, *chain = NULL;
149 struct xt_counters count = {};
151 chain = strtok(buffer+1, " \t\n");
152 DEBUGP("line %u, chain '%s'\n", line, chain);
153 if (!chain)
154 xtables_error(PARAMETER_PROBLEM,
155 "%s: line %u chain name invalid",
156 xt_params->program_name, line);
158 xtables_announce_chain(chain);
159 assert_valid_chain_name(chain);
161 policy = strtok(NULL, " \t\n");
162 DEBUGP("line %u, policy '%s'\n", line, policy);
163 if (!policy)
164 xtables_error(PARAMETER_PROBLEM,
165 "%s: line %u policy invalid",
166 xt_params->program_name, line);
168 if (nft_chain_builtin_find(state->curtable, chain)) {
169 char *ctrs = strtok(NULL, " \t\n");
171 if ((!ctrs && counters) ||
172 (ctrs && !parse_counters(ctrs, &count)))
173 xtables_error(PARAMETER_PROBLEM,
174 "invalid policy counters for chain '%s'",
175 chain);
176 if (cb->chain_set &&
177 cb->chain_set(h, state->curtable->name,
178 chain, policy,
179 counters ? &count : NULL) < 0) {
180 xtables_error(OTHER_PROBLEM,
181 "Can't set policy `%s' on `%s' line %u: %s",
182 policy, chain, line,
183 strerror(errno));
185 DEBUGP("Setting policy of chain %s to %s\n",
186 chain, policy);
187 } else if (cb->chain_restore(h, chain, state->curtable->name) < 0 &&
188 errno != EEXIST) {
189 xtables_error(PARAMETER_PROBLEM,
190 "cannot create chain '%s' (%s)",
191 chain, strerror(errno));
192 } else if (h->family == NFPROTO_BRIDGE &&
193 !ebt_cmd_user_chain_policy(h, state->curtable->name,
194 chain, policy)) {
195 xtables_error(OTHER_PROBLEM,
196 "Can't set policy `%s' on `%s' line %u: %s",
197 policy, chain, line,
198 strerror(errno));
200 ret = 1;
201 } else if (state->in_table) {
202 char *pcnt = NULL;
203 char *bcnt = NULL;
204 char *parsestart = buffer;
205 int i;
207 add_argv(&state->av_store, xt_params->program_name, 0);
208 add_argv(&state->av_store, "-t", 0);
209 add_argv(&state->av_store, state->curtable->name, 0);
211 for (i = 0; !h->noflush && i < verbose; i++)
212 add_argv(&state->av_store, "-v", 0);
214 tokenize_rule_counters(&parsestart, &pcnt, &bcnt, line);
215 if (counters && pcnt && bcnt) {
216 add_argv(&state->av_store, "--set-counters", 0);
217 add_argv(&state->av_store, pcnt, 0);
218 add_argv(&state->av_store, bcnt, 0);
221 add_param_to_argv(&state->av_store, parsestart, line);
223 DEBUGP("calling do_command4(%u, argv, &%s, handle):\n",
224 state->av_store.argc, state->curtable->name);
225 debug_print_argv(&state->av_store);
227 ret = cb->do_command(h, state->av_store.argc,
228 state->av_store.argv,
229 &state->av_store.argv[2], true);
230 if (ret < 0) {
231 if (cb->abort)
232 ret = cb->abort(h);
233 else
234 ret = 0;
236 if (ret < 0) {
237 fprintf(stderr,
238 "failed to abort commit operation\n");
240 exit(1);
243 free_argv(&state->av_store);
244 fflush(stdout);
246 if (p->tablename && state->curtable &&
247 (strcmp(p->tablename, state->curtable->name) != 0))
248 return;
249 if (!ret) {
250 fprintf(stderr, "%s: line %u failed",
251 xt_params->program_name, h->error.lineno);
252 if (errno)
253 fprintf(stderr, ": %s.", nft_strerror(errno));
254 fprintf(stderr, "\n");
255 exit(1);
259 void xtables_restore_parse(struct nft_handle *h,
260 const struct nft_xt_restore_parse *p)
262 struct nft_xt_restore_state state = {};
263 char buffer[10240] = {};
265 if (!verbose && !h->noflush)
266 nft_cache_level_set(h, NFT_CL_FAKE, NULL);
268 line = 0;
269 while (fgets(buffer, sizeof(buffer), p->in)) {
270 h->error.lineno = ++line;
271 DEBUGP("%s: input line %d: '%s'\n", __func__, line, buffer);
272 xtables_restore_parse_line(h, p, &state, buffer);
274 if (state.in_table && p->commit) {
275 fprintf(stderr, "%s: COMMIT expected at line %u\n",
276 xt_params->program_name, line + 1);
277 exit(1);
278 } else if (state.in_table && p->cb->commit && !p->cb->commit(h)) {
279 xtables_error(OTHER_PROBLEM, "%s: final implicit COMMIT failed",
280 xt_params->program_name);
284 static int
285 xtables_restore_main(int family, const char *progname, int argc, char *argv[])
287 struct nft_xt_restore_parse p = {
288 .commit = true,
289 .cb = &restore_cb,
291 bool noflush = false;
292 struct nft_handle h;
293 int c;
295 line = 0;
297 xtables_globals.program_name = progname;
298 c = xtables_init_all(&xtables_globals, family);
299 if (c < 0) {
300 fprintf(stderr, "%s/%s Failed to initialize xtables\n",
301 xtables_globals.program_name,
302 xtables_globals.program_version);
303 exit(1);
306 while ((c = getopt_long(argc, argv, "bcvVthnM:T:wW", options, NULL)) != -1) {
307 switch (c) {
308 case 'b':
309 fprintf(stderr, "-b/--binary option is not implemented\n");
310 break;
311 case 'c':
312 counters = 1;
313 break;
314 case 'v':
315 verbose++;
316 break;
317 case 'V':
318 printf("%s v%s\n", prog_name, prog_vers);
319 exit(0);
320 case 't':
321 p.testing = 1;
322 break;
323 case 'h':
324 print_usage(prog_name, PACKAGE_VERSION);
325 exit(0);
326 case 'n':
327 noflush = true;
328 break;
329 case 'M':
330 xtables_modprobe_program = optarg;
331 break;
332 case 'T':
333 p.tablename = optarg;
334 break;
335 case 'w': /* fallthrough. Ignored by xt-restore */
336 case 'W':
337 if (!optarg && xs_has_arg(argc, argv))
338 optind++;
339 break;
340 default:
341 fprintf(stderr,
342 "Try `%s -h' for more information.\n",
343 prog_name);
344 exit(1);
348 if (optind == argc - 1) {
349 p.in = fopen(argv[optind], "re");
350 if (!p.in) {
351 fprintf(stderr, "Can't open %s: %s\n", argv[optind],
352 strerror(errno));
353 exit(1);
355 } else if (optind < argc) {
356 fprintf(stderr, "Unknown arguments found on commandline\n");
357 exit(1);
358 } else {
359 p.in = stdin;
362 init_extensions();
363 switch (family) {
364 case NFPROTO_IPV4:
365 init_extensions4();
366 break;
367 case NFPROTO_IPV6:
368 init_extensions6();
369 break;
370 case NFPROTO_ARP:
371 init_extensionsa();
372 break;
373 case NFPROTO_BRIDGE:
374 init_extensionsb();
375 break;
376 default:
377 fprintf(stderr, "Unknown family %d\n", family);
378 return 1;
381 if (nft_init(&h, family) < 0) {
382 fprintf(stderr, "%s/%s Failed to initialize nft: %s\n",
383 xtables_globals.program_name,
384 xtables_globals.program_version,
385 strerror(errno));
386 exit(EXIT_FAILURE);
388 h.noflush = noflush;
389 h.restore = true;
391 xtables_restore_parse(&h, &p);
393 nft_fini(&h);
394 xtables_fini();
395 fclose(p.in);
396 return 0;
399 int xtables_ip4_restore_main(int argc, char *argv[])
401 return xtables_restore_main(NFPROTO_IPV4, basename(*argv),
402 argc, argv);
405 int xtables_ip6_restore_main(int argc, char *argv[])
407 return xtables_restore_main(NFPROTO_IPV6, basename(*argv),
408 argc, argv);
411 static const struct nft_xt_restore_cb ebt_restore_cb = {
412 .commit = nft_bridge_commit,
413 .table_flush = nft_cmd_table_flush,
414 .do_command = do_commandeb,
415 .chain_set = nft_cmd_chain_set,
416 .chain_restore = nft_cmd_chain_restore,
419 static const struct option ebt_restore_options[] = {
420 {.name = "noflush", .has_arg = 0, .val = 'n'},
421 {.name = "verbose", .has_arg = 0, .val = 'v'},
422 { 0 }
425 int xtables_eb_restore_main(int argc, char *argv[])
427 struct nft_xt_restore_parse p = {
428 .in = stdin,
429 .cb = &ebt_restore_cb,
431 bool noflush = false;
432 struct nft_handle h;
433 int c;
435 while ((c = getopt_long(argc, argv, "nv",
436 ebt_restore_options, NULL)) != -1) {
437 switch(c) {
438 case 'n':
439 noflush = 1;
440 break;
441 case 'v':
442 verbose++;
443 break;
444 default:
445 fprintf(stderr,
446 "Usage: ebtables-restore [ --verbose ] [ --noflush ]\n");
447 exit(1);
448 break;
452 nft_init_eb(&h, "ebtables-restore");
453 h.noflush = noflush;
454 xtables_restore_parse(&h, &p);
455 nft_fini_eb(&h);
457 return 0;
460 static const struct nft_xt_restore_cb arp_restore_cb = {
461 .commit = nft_commit,
462 .table_flush = nft_cmd_table_flush,
463 .do_command = do_commandx,
464 .chain_set = nft_cmd_chain_set,
465 .chain_restore = nft_cmd_chain_restore,
468 int xtables_arp_restore_main(int argc, char *argv[])
470 struct nft_xt_restore_parse p = {
471 .in = stdin,
472 .cb = &arp_restore_cb,
474 struct nft_handle h;
476 nft_init_arp(&h, "arptables-restore");
477 xtables_restore_parse(&h, &p);
478 nft_fini(&h);
479 xtables_fini();
481 return 0;