blob: 5be8a1f5eaa83b18d7baf09d60ffc42593d7261b [file] [log] [blame]
András Kis-Szabó2f523792001-02-27 09:59:48 +00001/* 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 *
9 */
10
11#include <getopt.h>
12#include <sys/errno.h>
13#include <string.h>
14#include <stdio.h>
15#include <stdlib.h>
16#include "ip6tables.h"
17#include "libiptc/libip6tc.h"
18
19#ifdef DEBUG
20#define DEBUGP(x, args...) fprintf(stderr, x, ## args)
21#else
22#define DEBUGP(x, args...)
23#endif
24
25extern int for_each_chain(int (*fn)(const ip6t_chainlabel, int, ip6tc_handle_t *), int verbose, int builtinstoo, ip6tc_handle_t *handle);
26extern int flush_entries(const ip6t_chainlabel chain, int verbose, ip6tc_handle_t *handle);
27extern int delete_chain(const ip6t_chainlabel chain, int verbose, ip6tc_handle_t *handle);
28
29static int binary = 0, counters = 0, verbose = 0, noflush = 0;
30
31/* Keeping track of external matches and targets. */
32static struct option options[] = {
33 { "binary", 0, 0, 'b' },
34 { "counters", 0, 0, 'c' },
35/* { "verbose", 1, 0, 'v' }, */
36 { "help", 0, 0, 'h' },
37 { "noflush", 0, 0, 'n'},
Harald Welte58918652001-06-16 18:25:25 +000038 { "modprobe", 1, 0, 'M'},
András Kis-Szabó2f523792001-02-27 09:59:48 +000039 { 0 }
40};
41
42static void print_usage(const char *name, const char *version) __attribute__((noreturn));
43
44static void print_usage(const char *name, const char *version)
45{
46 fprintf(stderr, "Usage: %s [-b] [-c] [-v] [-h]\n"
47 " [ --binary ]\n"
48 " [ --counters ]\n"
49 " [ --verbose ]\n"
50 " [ --help ]\n"
Harald Welte58918652001-06-16 18:25:25 +000051 " [ --noflush ]\n"
52 " [ --modprobe=<command>]\n", name);
András Kis-Szabó2f523792001-02-27 09:59:48 +000053
54 exit(1);
55}
56
Harald Welte58918652001-06-16 18:25:25 +000057ip6tc_handle_t create_handle(const char *tablename, const char* modprobe)
András Kis-Szabó2f523792001-02-27 09:59:48 +000058{
59 ip6tc_handle_t handle;
60
61 handle = ip6tc_init(tablename);
Harald Welte58918652001-06-16 18:25:25 +000062
63 if (!handle) {
64 /* try to insmod the module if iptc_init failed */
65 ip6tables_insmod("ip6_tables", modprobe);
66 handle = ip6tc_init(tablename);
67 }
68
András Kis-Szabó2f523792001-02-27 09:59:48 +000069 if (!handle) {
70 exit_error(PARAMETER_PROBLEM, "%s: unable to initialize"
71 "table '%s'\n", program_name, tablename);
72 exit(1);
73 }
74 return handle;
75}
76
77int parse_counters(char *string, struct ip6t_counters *ctr)
78{
79 return (sscanf(string, "[%llu:%llu]", &ctr->pcnt, &ctr->bcnt) == 2);
80}
81
Harald Welte885c6eb2001-10-04 08:30:46 +000082/* global new argv and argc */
83static char *newargv[255];
84static int newargc;
85
86/* function adding one argument to newargv, updating newargc
87 * * returns true if argument added, false otherwise */
88static int add_argv(char *what) {
89 if (what && ((newargc + 1) < sizeof(newargv)/sizeof(char *))) {
90 newargv[newargc] = strdup(what);
91 newargc++;
92 return 1;
93 } else
94 return 0;
95}
96
97static void free_argv(void) {
98 int i;
99
100 for (i = 0; i < newargc; i++)
101 free(newargv[i]);
102}
103
András Kis-Szabó2f523792001-02-27 09:59:48 +0000104int main(int argc, char *argv[])
105{
106 ip6tc_handle_t handle;
107 char buffer[10240];
108 unsigned int line = 0;
109 int c;
110 char curtable[IP6T_TABLE_MAXNAMELEN + 1];
András Kis-Szabó2f523792001-02-27 09:59:48 +0000111 FILE *in;
Harald Welte58918652001-06-16 18:25:25 +0000112 const char *modprobe = 0;
András Kis-Szabó2f523792001-02-27 09:59:48 +0000113
114 program_name = "ip6tables-restore";
115 program_version = NETFILTER_VERSION;
116
Harald Welte3efb6ea2001-08-06 18:50:21 +0000117#ifdef NO_SHARED_LIBS
118 init_extensions();
119#endif
120
Harald Welte58918652001-06-16 18:25:25 +0000121 while ((c = getopt_long(argc, argv, "bcvhnM:", options, NULL)) != -1) {
András Kis-Szabó2f523792001-02-27 09:59:48 +0000122 switch (c) {
123 case 'b':
124 binary = 1;
125 break;
126 case 'c':
127 counters = 1;
128 break;
129 case 'h':
130 print_usage("ip6tables-restore",
131 NETFILTER_VERSION);
132 break;
133 case 'n':
134 noflush = 1;
135 break;
Harald Welte58918652001-06-16 18:25:25 +0000136 case 'M':
137 modprobe = optarg;
138 break;
András Kis-Szabó2f523792001-02-27 09:59:48 +0000139 }
140 }
141
142 if (optind == argc - 1) {
143 in = fopen(argv[optind], "r");
144 if (!in) {
145 fprintf(stderr, "Can't open %s: %s", argv[optind],
146 strerror(errno));
147 exit(1);
148 }
149 }
150 else if (optind < argc) {
151 fprintf(stderr, "Unknown arguments found on commandline");
152 exit(1);
153 }
154 else in = stdin;
András Kis-Szabó2f523792001-02-27 09:59:48 +0000155
András Kis-Szabó2f523792001-02-27 09:59:48 +0000156 /* Grab standard input. */
157 while (fgets(buffer, sizeof(buffer), in)) {
158 int ret;
159
160 line++;
161 if (buffer[0] == '\n') continue;
162 else if (buffer[0] == '#') {
163 if (verbose) fputs(buffer, stdout);
164 continue;
165 } else if (strcmp(buffer, "COMMIT\n") == 0) {
166 DEBUGP("Calling commit\n");
167 ret = ip6tc_commit(&handle);
168 } else if (buffer[0] == '*') {
169 /* New table */
170 char *table;
171
172 table = strtok(buffer+1, " \t\n");
173 DEBUGP("line %u, table '%s'\n", line, table);
174 if (!table) {
175 exit_error(PARAMETER_PROBLEM,
176 "%s: line %u table name invalid\n",
177 program_name, line);
178 exit(1);
179 }
180 strncpy(curtable, table, IP6T_TABLE_MAXNAMELEN);
181
Harald Welte58918652001-06-16 18:25:25 +0000182 handle = create_handle(table, modprobe);
András Kis-Szabó2f523792001-02-27 09:59:48 +0000183 if (noflush == 0) {
184 DEBUGP("Cleaning all chains of table '%s'\n",
185 table);
186 for_each_chain(flush_entries, verbose, 1,
187 &handle);
188
189 DEBUGP("Deleting all user-defined chains "
190 "of table '%s'\n", table);
191 for_each_chain(delete_chain, verbose, 0,
192 &handle) ;
193 }
194
195 ret = 1;
196
197 } else if (buffer[0] == ':') {
198 /* New chain. */
199 char *policy, *chain;
200
201 chain = strtok(buffer+1, " \t\n");
202 DEBUGP("line %u, chain '%s'\n", line, chain);
203 if (!chain) {
204 exit_error(PARAMETER_PROBLEM,
205 "%s: line %u chain name invalid\n",
206 program_name, line);
207 exit(1);
208 }
András Kis-Szabó2f523792001-02-27 09:59:48 +0000209
Harald Welte885c6eb2001-10-04 08:30:46 +0000210 if (!ip6tc_builtin(chain, handle)) {
András Kis-Szabó2f523792001-02-27 09:59:48 +0000211 DEBUGP("Creating new chain '%s'\n", curchain);
Harald Welte885c6eb2001-10-04 08:30:46 +0000212 if (!ip6tc_create_chain(chain, &handle))
213 exit_error(PARAMETER_PROBLEM,
214 "error creating chain "
215 "'%s':%s\n", chain,
216 strerror(errno));
217 }
András Kis-Szabó2f523792001-02-27 09:59:48 +0000218
219 policy = strtok(NULL, " \t\n");
220 DEBUGP("line %u, policy '%s'\n", line, policy);
221 if (!policy) {
222 exit_error(PARAMETER_PROBLEM,
223 "%s: line %u policy invalid\n",
224 program_name, line);
225 exit(1);
226 }
227
228 if (strcmp(policy, "-") != 0) {
229 struct ip6t_counters count;
230
231 if (counters) {
232 char *ctrs;
233 ctrs = strtok(NULL, " \t\n");
234
235 parse_counters(ctrs, &count);
236
237 } else {
238 memset(&count, 0,
239 sizeof(struct ip6t_counters));
240 }
241
242 DEBUGP("Setting policy of chain %s to %s\n",
243 chain, policy);
244
245 if (!ip6tc_set_policy(chain, policy, &count,
246 &handle))
247 exit_error(OTHER_PROBLEM,
248 "Can't set policy `%s'"
249 " on `%s' line %u: %s\n",
250 chain, policy, line,
251 ip6tc_strerror(errno));
252 }
253
254 ret = 1;
255
256 } else {
Harald Welte885c6eb2001-10-04 08:30:46 +0000257 int a;
András Kis-Szabó2f523792001-02-27 09:59:48 +0000258 char *ptr = buffer;
259 char *pcnt = NULL;
260 char *bcnt = NULL;
Harald Welte885c6eb2001-10-04 08:30:46 +0000261 char *parsestart;
262
263 /* the parser */
264 char *param_start, *curchar;
265 int quote_open;
266
267 /* reset the newargv */
268 newargc = 0;
András Kis-Szabó2f523792001-02-27 09:59:48 +0000269
270 if (buffer[0] == '[') {
Harald Welte885c6eb2001-10-04 08:30:46 +0000271 /* we have counters in our input */
András Kis-Szabó2f523792001-02-27 09:59:48 +0000272 ptr = strchr(buffer, ']');
273 if (!ptr)
274 exit_error(PARAMETER_PROBLEM,
275 "Bad line %u: need ]\n",
276 line);
Harald Welte885c6eb2001-10-04 08:30:46 +0000277
András Kis-Szabó2f523792001-02-27 09:59:48 +0000278 pcnt = strtok(buffer+1, ":");
Harald Welte885c6eb2001-10-04 08:30:46 +0000279 if (!pcnt)
280 exit_error(PARAMETER_PROBLEM,
281 "Bad line %u: need :\n",
282 line);
283
András Kis-Szabó2f523792001-02-27 09:59:48 +0000284 bcnt = strtok(NULL, "]");
Harald Welte885c6eb2001-10-04 08:30:46 +0000285 if (!bcnt)
286 exit_error(PARAMETER_PROBLEM,
287 "Bad line %u: need ]\n",
288 line);
András Kis-Szabó2f523792001-02-27 09:59:48 +0000289
Harald Welte885c6eb2001-10-04 08:30:46 +0000290 /* start command parsing after counter */
291 parsestart = ptr + 1;
292 } else {
293 /* start command parsing at start of line */
294 parsestart = buffer;
295 }
András Kis-Szabó2f523792001-02-27 09:59:48 +0000296
Harald Welte885c6eb2001-10-04 08:30:46 +0000297 add_argv(argv[0]);
298 add_argv("-t");
299 add_argv((char *) &curtable);
300
301/* IP6TABLES doesn't support this
András Kis-Szabó2f523792001-02-27 09:59:48 +0000302 if (counters && pcnt && bcnt) {
303 newargv[5] = "--set-counters";
304 newargv[6] = (char *) pcnt;
305 newargv[7] = (char *) bcnt;
András Kis-Szabó2f523792001-02-27 09:59:48 +0000306 }
Harald Welte885c6eb2001-10-04 08:30:46 +0000307*/
András Kis-Szabó2f523792001-02-27 09:59:48 +0000308
Harald Welte885c6eb2001-10-04 08:30:46 +0000309 /* After fighting with strtok enough, here's now
310 * a 'real' parser. According to Rusty I'm now no
311 * longer a real hacker, but I can live with that */
András Kis-Szabó2f523792001-02-27 09:59:48 +0000312
Harald Welte885c6eb2001-10-04 08:30:46 +0000313 quote_open = 0;
314 param_start = parsestart;
András Kis-Szabó2f523792001-02-27 09:59:48 +0000315
Harald Welte885c6eb2001-10-04 08:30:46 +0000316 for (curchar = parsestart; *curchar; curchar++) {
317 if (*curchar == '"') {
318 if (quote_open) {
319 quote_open = 0;
320 *curchar = ' ';
321 } else {
322 quote_open = 1;
323 param_start++;
324 }
325 }
326 if (*curchar == ' '
327 || *curchar == '\t'
328 || * curchar == '\n') {
329 char param_buffer[1024];
330 int param_len = curchar-param_start;
András Kis-Szabó2f523792001-02-27 09:59:48 +0000331
Harald Welte885c6eb2001-10-04 08:30:46 +0000332 if (quote_open)
333 continue;
334
335 if (!param_len) {
336 /* two spaces? */
337 param_start++;
338 continue;
339 }
340
341 /* end of one parameter */
342 strncpy(param_buffer, param_start,
343 param_len);
344 *(param_buffer+param_len) = '\0';
345 add_argv(param_buffer);
346 param_start += param_len + 1;
347 } else {
348 /* regular character, skip */
349 }
350 }
351
352 DEBUGP("calling do_command6(%u, argv, &%s, handle):\n",
353 newargc, curtable);
354
355 for (a = 0; a <= newargc; a++)
András Kis-Szabó2f523792001-02-27 09:59:48 +0000356 DEBUGP("argv[%u]: %s\n", a, newargv[a]);
357
Harald Welte885c6eb2001-10-04 08:30:46 +0000358 ret = do_command6(newargc, newargv,
359 &newargv[2], &handle);
360
361 free_argv();
András Kis-Szabó2f523792001-02-27 09:59:48 +0000362 }
363 if (!ret) {
364 fprintf(stderr, "%s: line %u failed\n",
365 program_name, line);
366 exit(1);
367 }
368 }
369
370 return 0;
371}