]>
Commit | Line | Data |
---|---|---|
3f663635 | 1 | --- |
2 | Makefile.am | 12 + | |
3 | iptables-batch.c | 468 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ | |
4 | 2 files changed, 478 insertions(+), 2 deletions(-) | |
5 | ||
6 | Index: iptables-1.4.7/Makefile.am | |
7 | =================================================================== | |
8 | --- iptables-1.4.7.orig/Makefile.am | |
9 | +++ iptables-1.4.7/Makefile.am | |
10 | @@ -54,6 +54,14 @@ endif | |
11 | ip6tables_multi_LDFLAGS = -rdynamic | |
12 | ip6tables_multi_LDADD = libiptc/libip6tc.la extensions/libext6.a libxtables.la -lm | |
a8c9e3da | 13 | |
3f663635 | 14 | +iptables_batch_SOURCES = iptables-batch.c iptables.c xshared.c |
15 | +iptables_batch_LDFLAGS = ${iptables_multi_LDFLAGS} | |
16 | +iptables_batch_LDADD = ${iptables_multi_LDADD} | |
17 | +ip6tables_batch_SOURCES = iptables-batch.c ip6tables.c xshared.c | |
18 | +ip6tables_batch_CFLAGS = ${AM_CFLAGS} -DIP6T | |
19 | +ip6tables_batch_LDFLAGS = ${ip6tables_multi_LDFLAGS} | |
20 | +ip6tables_batch_LDADD = ${ip6tables_multi_LDADD} | |
21 | + | |
22 | sbin_PROGRAMS = | |
23 | man_MANS = iptables.8 iptables-restore.8 iptables-save.8 \ | |
24 | iptables-xml.8 ip6tables.8 ip6tables-restore.8 \ | |
25 | @@ -61,12 +69,12 @@ man_MANS = iptables.8 iptables-r | |
26 | CLEANFILES = iptables.8 ip6tables.8 | |
27 | ||
28 | if ENABLE_IPV4 | |
29 | -sbin_PROGRAMS += iptables-multi | |
30 | +sbin_PROGRAMS += iptables-multi iptables-batch | |
31 | v4_bin_links = iptables-xml | |
32 | v4_sbin_links = iptables iptables-restore iptables-save | |
33 | endif | |
34 | if ENABLE_IPV6 | |
35 | -sbin_PROGRAMS += ip6tables-multi | |
36 | +sbin_PROGRAMS += ip6tables-multi ip6tables-batch | |
37 | v6_sbin_links = ip6tables ip6tables-restore ip6tables-save | |
38 | endif | |
39 | ||
40 | Index: iptables-1.4.7/iptables-batch.c | |
41 | =================================================================== | |
42 | --- /dev/null | |
43 | +++ iptables-1.4.7/iptables-batch.c | |
44 | @@ -0,0 +1,468 @@ | |
a8c9e3da | 45 | +/* |
46 | + * Author: Ludwig Nussel <ludwig.nussel@suse.de> | |
3f663635 | 47 | + * Update for iptables 1.4.3.x: Petr Uzel <petr.uzel@suse.cz> |
a8c9e3da | 48 | + * |
49 | + * Based on the ipchains code by Paul Russell and Michael Neuling | |
50 | + * | |
51 | + * (C) 2000-2002 by the netfilter coreteam <coreteam@netfilter.org>: | |
52 | + * Paul 'Rusty' Russell <rusty@rustcorp.com.au> | |
53 | + * Marc Boucher <marc+nf@mbsi.ca> | |
54 | + * James Morris <jmorris@intercode.com.au> | |
55 | + * Harald Welte <laforge@gnumonks.org> | |
56 | + * Jozsef Kadlecsik <kadlec@blackhole.kfki.hu> | |
57 | + * | |
58 | + * iptables-batch -- iptables batch processor | |
59 | + * | |
60 | + * See the accompanying manual page iptables(8) for information | |
61 | + * about proper usage of this program. | |
62 | + * | |
63 | + * This program is free software; you can redistribute it and/or modify | |
64 | + * it under the terms of the GNU General Public License as published by | |
65 | + * the Free Software Foundation; either version 2 of the License, or | |
66 | + * (at your option) any later version. | |
67 | + * | |
68 | + * This program is distributed in the hope that it will be useful, | |
69 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
70 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
71 | + * GNU General Public License for more details. | |
72 | + * | |
73 | + * You should have received a copy of the GNU General Public License | |
74 | + * along with this program; if not, write to the Free Software | |
75 | + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |
76 | + */ | |
77 | + | |
78 | +#define _GNU_SOURCE | |
79 | +#include <stdio.h> | |
80 | +#include <ctype.h> | |
81 | +#include <stdlib.h> | |
82 | +#include <errno.h> | |
83 | +#include <string.h> | |
84 | + | |
3f663635 | 85 | +#ifdef IP6T |
a8c9e3da | 86 | +#include <ip6tables.h> |
87 | +#else | |
88 | +#include <iptables.h> | |
3f663635 | 89 | +#endif |
90 | +#include <xtables.h> | |
91 | + | |
92 | +#ifdef IP6T | |
93 | +#define prog_name ip6tables_globals.program_name | |
94 | +#define prog_ver ip6tables_globals.program_version | |
95 | +#else | |
96 | +#define prog_name iptables_globals.program_name | |
97 | +#define prog_ver iptables_globals.program_version | |
a8c9e3da | 98 | +#endif |
99 | + | |
100 | +static char* errstr = NULL; | |
101 | + | |
102 | +static unsigned current_line = 0; | |
103 | + | |
104 | +static char* | |
105 | +skipspace(char* ptr) | |
106 | +{ | |
107 | + while(*ptr && isspace(*ptr)) | |
108 | + ++ptr; | |
109 | + return ptr; | |
110 | +} | |
111 | + | |
112 | +static char* | |
113 | +getliteral(char** ptr) | |
114 | +{ | |
115 | + char* start = *ptr; | |
116 | + char* p = start; | |
117 | + | |
118 | + while(*p && !isspace(*p)) | |
119 | + ++p; | |
120 | + | |
121 | + if(*p) | |
122 | + { | |
123 | + *p = '\0'; | |
124 | + ++p; | |
125 | + } | |
126 | + | |
127 | + *ptr = p; | |
128 | + return start; | |
129 | +} | |
130 | + | |
131 | +static char* | |
132 | +getstring(char** ptr) | |
133 | +{ | |
134 | + char* start = *ptr+1; // skip leading " | |
135 | + char* p = start; | |
136 | + char* o = start; | |
137 | + int backslash = 0; | |
138 | + int done = 0; | |
139 | + | |
140 | + while(*p && !done) | |
141 | + { | |
142 | + if(backslash) | |
143 | + { | |
144 | + backslash = 0; | |
145 | + // no escapes supported, just eat the backslash | |
146 | + *o++ = *p++; | |
147 | + } | |
148 | + else if(*p == '\\') | |
149 | + { | |
150 | + backslash = 1; | |
151 | + p++; | |
152 | + } | |
153 | + else if(*p == '"') | |
154 | + { | |
155 | + done = 1; | |
156 | + } | |
157 | + else | |
158 | + { | |
159 | + *o++ = *p++; | |
160 | + } | |
161 | + } | |
162 | + | |
163 | + if(done) | |
164 | + { | |
165 | + *o = '\0'; | |
166 | + *p = '\0'; | |
167 | + ++p; | |
168 | + *ptr = p; | |
169 | + } | |
170 | + else | |
171 | + { | |
172 | + errstr = "missing \" at end of string"; | |
173 | + start = NULL; | |
174 | + } | |
175 | + return start; | |
176 | +} | |
177 | + | |
178 | +// this is just a very basic method, not 100% shell compatible | |
179 | +static char* | |
180 | +getword(char** ptr) | |
181 | +{ | |
182 | + *ptr = skipspace(*ptr); | |
183 | + if(**ptr == '"') | |
184 | + return getstring(ptr); | |
185 | + return getliteral(ptr); | |
186 | +} | |
187 | + | |
188 | +// destructive | |
189 | +static int | |
3f663635 | 190 | +tokenize(int* argc, char* argv[], size_t nargvsize, char* iline) |
a8c9e3da | 191 | +{ |
3f663635 | 192 | + char* ptr = skipspace(iline); |
a8c9e3da | 193 | + int ret = 0; |
194 | + char* word; | |
195 | + | |
196 | + while(ptr && *ptr) | |
197 | + { | |
198 | + if(*ptr == '#') | |
199 | + break; | |
200 | + if(*argc >= nargvsize) | |
201 | + { | |
202 | + errstr = "too many arguments"; | |
203 | + ret = -1; | |
204 | + break; | |
205 | + } | |
206 | + word = getword(&ptr); | |
207 | + if(!word) | |
208 | + { | |
209 | + ret = -1; | |
210 | + break; | |
211 | + } | |
212 | + argv[(*argc)++] = word; | |
213 | + ++ret; | |
214 | + } | |
215 | + return ret; | |
216 | +} | |
217 | + | |
218 | +#ifdef DEBUG | |
219 | +static void | |
220 | +dumpargv(int argc, char* argv[]) | |
221 | +{ | |
222 | + int i; | |
223 | + for(i=0; i < argc; ++i) | |
224 | + { | |
225 | + printf("%s\"%s\"",i?" ":"", argv[i]); | |
226 | + } | |
227 | + puts(""); | |
228 | +} | |
229 | +#endif | |
230 | + | |
231 | +struct table_handle | |
232 | +{ | |
233 | + char* name; | |
3f663635 | 234 | +#ifdef IP6T |
0f39174f | 235 | + struct ip6tc_handle *handle; |
a8c9e3da | 236 | +#else |
0f39174f | 237 | + struct iptc_handle *handle; |
a8c9e3da | 238 | +#endif |
239 | +}; | |
240 | + | |
241 | +static struct table_handle* tables = NULL; | |
242 | +static unsigned num_tables; | |
243 | +struct table_handle* current_table; | |
244 | + | |
245 | +static void | |
3f663635 | 246 | +alloc_tables(void) |
a8c9e3da | 247 | +{ |
248 | + tables = realloc(tables, sizeof(struct table_handle) * num_tables); | |
249 | +} | |
250 | + | |
251 | +static void | |
252 | +set_current_table(const char* name) | |
253 | +{ | |
254 | + unsigned i; | |
255 | + | |
256 | + if(!strcmp(name, current_table->name)) // same as last time? | |
257 | + return; | |
258 | + | |
259 | + for(i = 0; i < num_tables; ++i) // find already known table | |
260 | + { | |
261 | + if(!strcmp(name, tables[i].name)) | |
262 | + { | |
263 | + current_table = &tables[i]; | |
264 | + return; | |
265 | + } | |
266 | + } | |
267 | + | |
268 | + // table name not known, create new | |
269 | + i = num_tables++; | |
270 | + alloc_tables(); | |
271 | + current_table = &tables[i]; | |
272 | + current_table->name = strdup(name); | |
273 | + current_table->handle = NULL; | |
274 | +} | |
275 | + | |
276 | +static int | |
277 | +find_table(int argc, char* argv[]) | |
278 | +{ | |
279 | + int i; | |
280 | + for(i = 0; i < argc; ++i) | |
281 | + { | |
282 | + if(!strcmp(argv[i], "-t") || !strcmp(argv[i], "--table")) | |
283 | + { | |
284 | + ++i; | |
285 | + if(i >= argc) | |
286 | + { | |
287 | + fprintf(stderr, "line %d: missing table name after %s\n", | |
288 | + current_line, argv[i]); | |
289 | + return 0; | |
290 | + } | |
291 | + set_current_table(argv[i]); | |
292 | + return 1; | |
293 | + } | |
294 | + } | |
295 | + | |
296 | + // no -t specified | |
297 | + set_current_table("filter"); | |
298 | + | |
299 | + return 1; | |
300 | +} | |
301 | + | |
302 | +static int | |
303 | +do_iptables(int argc, char* argv[]) | |
304 | +{ | |
305 | + char *table = "filter"; | |
306 | + int ret = 0; | |
307 | + | |
308 | + if(!find_table(argc, argv)) | |
309 | + return 0; | |
310 | + | |
3f663635 | 311 | +#ifdef IP6T |
a8c9e3da | 312 | + ret = do_command6(argc, argv, &table, ¤t_table->handle); |
313 | + | |
314 | + if (!ret) | |
315 | + { | |
316 | + fprintf(stderr, "line %d: %s\n", current_line, ip6tc_strerror(errno)); | |
317 | + } | |
318 | + else | |
319 | + { | |
320 | + if(!table || strcmp(table, current_table->name)) | |
321 | + { | |
322 | + fprintf(stderr, "line %d: expected table %s, got %s\n", | |
323 | + current_line, current_table->name, table); | |
324 | + exit(1); | |
325 | + } | |
326 | + } | |
327 | +#else | |
328 | + ret = do_command(argc, argv, &table, ¤t_table->handle); | |
329 | + | |
330 | + if (!ret) | |
331 | + { | |
332 | + fprintf(stderr, "line %d: %s\n", current_line, iptc_strerror(errno)); | |
333 | + } | |
334 | + else | |
335 | + { | |
336 | + if(!table || strcmp(table, current_table->name)) | |
337 | + { | |
338 | + fprintf(stderr, "line %d: expected table %s, got %s\n", | |
339 | + current_line, current_table->name, table); | |
340 | + exit(1); | |
341 | + } | |
342 | + } | |
343 | +#endif | |
344 | + | |
345 | + return ret; | |
346 | +} | |
347 | + | |
348 | +static int | |
3f663635 | 349 | +do_commit(void) |
a8c9e3da | 350 | +{ |
351 | + unsigned i; | |
352 | + int ret = 1; | |
353 | + | |
354 | + for(i = 0; i < num_tables; ++i) | |
355 | + { | |
356 | + if(tables[i].handle) | |
357 | + { | |
3f663635 | 358 | +#ifdef IP6T |
359 | + ret = ip6tc_commit(tables[i].handle); | |
360 | + if (!ret) | |
a8c9e3da | 361 | + fprintf(stderr, "commit failed on table %s: %s\n", tables[i].name, ip6tc_strerror(errno)); |
3f663635 | 362 | + ip6tc_free(tables[i].handle); |
363 | + tables[i].handle = NULL; | |
a8c9e3da | 364 | +#else |
3f663635 | 365 | + ret = iptc_commit(tables[i].handle); |
366 | + if (!ret) | |
a8c9e3da | 367 | + fprintf(stderr, "commit failed on table %s: %s\n", tables[i].name, iptc_strerror(errno)); |
3f663635 | 368 | + iptc_free(tables[i].handle); |
369 | + tables[i].handle = NULL; | |
a8c9e3da | 370 | +#endif |
371 | + } | |
372 | + } | |
373 | + | |
374 | + return ret; | |
375 | +} | |
376 | + | |
377 | +static void | |
3f663635 | 378 | +help(void) |
a8c9e3da | 379 | +{ |
3f663635 | 380 | + fprintf(stderr, "Usage: %s [FILE]\n\n", prog_name); |
a8c9e3da | 381 | + puts("Read iptables commands from FILE, commit them at EOF\n"); |
382 | + puts("In addition to normal iptables calls the commands"); | |
383 | + puts("'commit' and 'exit' are understood."); | |
384 | + exit(0); | |
385 | +} | |
386 | + | |
387 | +int | |
388 | +main(int argc, char *argv[]) | |
389 | +{ | |
390 | + int ret = 1; | |
3f663635 | 391 | + int c; |
a8c9e3da | 392 | + int numtok; |
393 | + size_t llen = 0; | |
3f663635 | 394 | + char* iline = NULL; |
a8c9e3da | 395 | + ssize_t r = -1; |
396 | + int nargc = 0; | |
397 | + char* nargv[256]; | |
398 | + FILE* fp = stdin; | |
399 | + | |
3f663635 | 400 | +#ifdef IP6T |
401 | + prog_name = "ip6tables-batch"; | |
a8c9e3da | 402 | +#else |
3f663635 | 403 | + prog_name = "iptables-batch"; |
404 | +#endif | |
405 | + | |
406 | +#ifdef IP6T | |
407 | + c = xtables_init_all(&ip6tables_globals, NFPROTO_IPV6); | |
408 | +#else | |
409 | + c = xtables_init_all(&iptables_globals, NFPROTO_IPV4); | |
410 | +#endif | |
411 | + | |
412 | + if(c < 0) { | |
60a6afcf | 413 | + fprintf(stderr, "%s/%s Failed to initialize xtables\n", |
3f663635 | 414 | + prog_name, |
415 | + prog_ver); | |
60a6afcf | 416 | + exit(1); |
c0b9dae7 | 417 | + } |
418 | + | |
a8c9e3da | 419 | +#ifdef NO_SHARED_LIBS |
420 | + init_extensions(); | |
421 | +#endif | |
422 | + if(argc > 1) | |
423 | + { | |
3f663635 | 424 | + if(!strcmp(argv[1], "--help") || !strcmp(argv[1], "-h")) |
a8c9e3da | 425 | + { |
426 | + help(); | |
427 | + } | |
428 | + else if(strcmp(argv[1], "-")) | |
429 | + { | |
430 | + fp = fopen(argv[1], "r"); | |
431 | + if(!fp) | |
432 | + { | |
433 | + perror("fopen"); | |
434 | + exit(1); | |
435 | + } | |
436 | + } | |
437 | + } | |
438 | + | |
439 | + num_tables = 4; | |
440 | + alloc_tables(); | |
441 | + tables[0].name = "filter"; | |
442 | + tables[0].handle = NULL; | |
443 | + tables[1].name = "mangle"; | |
444 | + tables[1].handle = NULL; | |
445 | + tables[2].name = "nat"; | |
446 | + tables[2].handle = NULL; | |
447 | + tables[3].name = "raw"; | |
448 | + tables[3].handle = NULL; | |
449 | + current_table = &tables[0]; | |
450 | + | |
3f663635 | 451 | + while((r = getline(&iline, &llen, fp)) != -1) |
a8c9e3da | 452 | + { |
3f663635 | 453 | + if(llen < 1 || !*iline) |
a8c9e3da | 454 | + continue; |
3f663635 | 455 | + if(iline[strlen(iline)-1] == '\n') |
456 | + iline[strlen(iline) -1 ] = '\0'; | |
a8c9e3da | 457 | + |
458 | + ++current_line; | |
459 | + nargc = 0; | |
460 | + errstr = NULL; | |
3f663635 | 461 | + numtok = tokenize(&nargc, nargv, (sizeof(nargv)/sizeof(nargv[0])), iline); |
a8c9e3da | 462 | + if(numtok == -1) |
463 | + { | |
464 | + } | |
465 | + else if (numtok == 0) | |
466 | + { | |
467 | + continue; | |
468 | + } | |
469 | + else if(nargc < 1) | |
470 | + { | |
471 | + errstr = "insufficient number of arguments"; | |
472 | + } | |
473 | + | |
474 | + if(errstr) | |
475 | + { | |
476 | + fprintf(stderr, "parse error in line %d: %s\n", current_line, errstr); | |
477 | + ret = 0; | |
478 | + break; | |
479 | + } | |
480 | + | |
481 | +#ifdef DEBUG | |
482 | + dumpargv(nargc, nargv); | |
483 | +#endif | |
484 | + | |
3f663635 | 485 | +#ifdef IP6T |
a8c9e3da | 486 | + if(!strcmp(nargv[0], "ip6tables")) |
487 | +#else | |
488 | + if(!strcmp(nargv[0], "iptables")) | |
489 | +#endif | |
490 | + { | |
491 | + ret = do_iptables(nargc, nargv); | |
492 | + if(!ret) break; | |
493 | + } | |
494 | + else if(!strcmp(nargv[0], "exit")) | |
495 | + { | |
496 | + break; | |
497 | + } | |
498 | + else if(!strcmp(nargv[0], "commit")) | |
499 | + { | |
3f663635 | 500 | + /* do nothing - see bnc#500990, comment #16 */ |
a8c9e3da | 501 | + } |
502 | + else | |
503 | + { | |
504 | + fprintf(stderr, "line %d: invalid command '%s'\n", current_line, nargv[0]); | |
505 | + } | |
506 | + } | |
507 | + | |
508 | + if(ret) | |
509 | + ret = do_commit(); | |
510 | + | |
511 | + exit(!ret); | |
512 | +} |