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
17 #include "libiptc/libiptc.h"
18 #include "xtables-multi.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'},
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"
55 " [ --table=<TABLE> ]\n"
56 " [ --modprobe=<command> ]\n"
58 " [ --ipv6 ]\n", name
);
61 static const struct nft_xt_restore_cb restore_cb
= {
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
;
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
,
81 const struct nft_xt_restore_cb
*cb
= p
->cb
;
84 if (buffer
[0] == '\n')
86 else if (buffer
[0] == '#') {
88 fputs(buffer
, stdout
);
92 } else if (state
->in_table
&&
93 (strncmp(buffer
, "COMMIT", 6) == 0) &&
94 (buffer
[6] == '\0' || buffer
[6] == '\n')) {
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");
104 DEBUGP("Not calling commit, testing\n");
108 state
->in_table
= false;
110 } else if ((buffer
[0] == '*') && (!state
->in_table
|| !p
->commit
)) {
114 table
= strtok(buffer
+1, " \t\n");
115 DEBUGP("line %u, table '%s'\n", line
, 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))
130 /* implicit commit if no explicit COMMIT supported */
134 if (h
->noflush
== 0) {
135 DEBUGP("Cleaning all chains of table '%s'\n", table
);
137 cb
->table_flush(h
, table
, verbose
);
141 state
->in_table
= true;
144 cb
->table_new(h
, table
);
146 } else if ((buffer
[0] == ':') && state
->in_table
) {
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
);
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
);
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'",
177 cb
->chain_set(h
, state
->curtable
->name
,
179 counters
? &count
: NULL
) < 0) {
180 xtables_error(OTHER_PROBLEM
,
181 "Can't set policy `%s' on `%s' line %u: %s",
185 DEBUGP("Setting policy of chain %s to %s\n",
187 } else if (cb
->chain_restore(h
, chain
, state
->curtable
->name
) < 0 &&
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
,
195 xtables_error(OTHER_PROBLEM
,
196 "Can't set policy `%s' on `%s' line %u: %s",
201 } else if (state
->in_table
) {
204 char *parsestart
= buffer
;
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);
238 "failed to abort commit operation\n");
243 free_argv(&state
->av_store
);
246 if (p
->tablename
&& state
->curtable
&&
247 (strcmp(p
->tablename
, state
->curtable
->name
) != 0))
250 fprintf(stderr
, "%s: line %u failed",
251 xt_params
->program_name
, h
->error
.lineno
);
253 fprintf(stderr
, ": %s.", nft_strerror(errno
));
254 fprintf(stderr
, "\n");
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
);
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);
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
);
285 xtables_restore_main(int family
, const char *progname
, int argc
, char *argv
[])
287 struct nft_xt_restore_parse p
= {
291 bool noflush
= false;
297 xtables_globals
.program_name
= progname
;
298 c
= xtables_init_all(&xtables_globals
, family
);
300 fprintf(stderr
, "%s/%s Failed to initialize xtables\n",
301 xtables_globals
.program_name
,
302 xtables_globals
.program_version
);
306 while ((c
= getopt_long(argc
, argv
, "bcvVthnM:T:wW", options
, NULL
)) != -1) {
309 fprintf(stderr
, "-b/--binary option is not implemented\n");
318 printf("%s v%s\n", prog_name
, prog_vers
);
324 print_usage(prog_name
, PACKAGE_VERSION
);
330 xtables_modprobe_program
= optarg
;
333 p
.tablename
= optarg
;
335 case 'w': /* fallthrough. Ignored by xt-restore */
337 if (!optarg
&& xs_has_arg(argc
, argv
))
342 "Try `%s -h' for more information.\n",
348 if (optind
== argc
- 1) {
349 p
.in
= fopen(argv
[optind
], "re");
351 fprintf(stderr
, "Can't open %s: %s\n", argv
[optind
],
355 } else if (optind
< argc
) {
356 fprintf(stderr
, "Unknown arguments found on commandline\n");
377 fprintf(stderr
, "Unknown family %d\n", family
);
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
,
391 xtables_restore_parse(&h
, &p
);
399 int xtables_ip4_restore_main(int argc
, char *argv
[])
401 return xtables_restore_main(NFPROTO_IPV4
, basename(*argv
),
405 int xtables_ip6_restore_main(int argc
, char *argv
[])
407 return xtables_restore_main(NFPROTO_IPV6
, basename(*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'},
425 int xtables_eb_restore_main(int argc
, char *argv
[])
427 struct nft_xt_restore_parse p
= {
429 .cb
= &ebt_restore_cb
,
431 bool noflush
= false;
435 while ((c
= getopt_long(argc
, argv
, "nv",
436 ebt_restore_options
, NULL
)) != -1) {
446 "Usage: ebtables-restore [ --verbose ] [ --noflush ]\n");
452 nft_init_eb(&h
, "ebtables-restore");
454 xtables_restore_parse(&h
, &p
);
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
= {
472 .cb
= &arp_restore_cb
,
476 nft_init_arp(&h
, "arptables-restore");
477 xtables_restore_parse(&h
, &p
);