blob: 57c7486d496a7bbdfb4b08cf763b167aa6b08445 [file] [log] [blame]
Amin Azez8d3eccb2006-11-13 20:23:36 +00001/* Code to convert iptables-save format to xml format,
2 * (C) 2006 Ufo Mechanic <azez@ufomechanic.net>
3 * based on iptables-restor (C) 2000-2002 by Harald Welte <laforge@gnumonks.org>
4 * based on previous code from Rusty Russell <rusty@linuxcare.com.au>
5 *
6 * This code is distributed under the terms of GNU GPL v2
Amin Azez8d3eccb2006-11-13 20:23:36 +00007 */
8
9#include <getopt.h>
10#include <sys/errno.h>
11#include <string.h>
12#include <stdio.h>
13#include <stdlib.h>
14#include <stdarg.h>
15#include "iptables.h"
16#include "libiptc/libiptc.h"
Jan Engelhardt33690a12008-02-11 00:54:00 +010017#include "iptables-multi.h"
Jamal Hadi Salim4dcdc9b2009-02-11 13:03:34 +010018#include <xtables.h>
Amin Azez8d3eccb2006-11-13 20:23:36 +000019
20#ifdef DEBUG
21#define DEBUGP(x, args...) fprintf(stderr, x, ## args)
22#else
23#define DEBUGP(x, args...)
24#endif
25
Lutz Jaenickee78c69c2006-12-09 13:06:04 +000026#ifndef IPTABLES_MULTI
27int line = 0;
Lutz Jaenickee78c69c2006-12-09 13:06:04 +000028#endif
Amin Azez8d3eccb2006-11-13 20:23:36 +000029
Jamal Hadi Salim5dd19de2009-02-13 10:42:24 -050030struct xtables_globals iptables_xml_globals = {
31 .option_offset = 0,
32 .program_version = IPTABLES_VERSION,
33 .program_name = "iptables-xml",
34};
35#define prog_name iptables_xml_globals.program_name
36#define prog_vers iptables_xml_globals.program_version
37
Amin Azez8d3eccb2006-11-13 20:23:36 +000038static void print_usage(const char *name, const char *version)
39 __attribute__ ((noreturn));
40
41static int verbose = 0;
42/* Whether to combine actions of sequential rules with identical conditions */
43static int combine = 0;
44/* Keeping track of external matches and targets. */
45static struct option options[] = {
Patrick McHardyddffcfb2008-06-07 15:07:18 +020046 {"verbose", 0, NULL, 'v'},
47 {"combine", 0, NULL, 'c'},
48 {"help", 0, NULL, 'h'},
Max Kellermann9ee386a2008-01-29 13:48:05 +000049 { .name = NULL }
Amin Azez8d3eccb2006-11-13 20:23:36 +000050};
51
52static void
53print_usage(const char *name, const char *version)
54{
55 fprintf(stderr, "Usage: %s [-c] [-v] [-h]\n"
56 " [--combine ]\n"
57 " [ --verbose ]\n" " [ --help ]\n", name);
58
59 exit(1);
60}
61
Lutz Jaenickee78c69c2006-12-09 13:06:04 +000062static int
Amin Azez8d3eccb2006-11-13 20:23:36 +000063parse_counters(char *string, struct ipt_counters *ctr)
64{
Jan Engelhardt01958362010-09-13 15:35:18 +020065 __u64 *pcnt, *bcnt;
Patrick McHardyb73691f2007-09-05 14:10:53 +000066
67 if (string != NULL) {
68 pcnt = &ctr->pcnt;
69 bcnt = &ctr->bcnt;
Amin Azez8d3eccb2006-11-13 20:23:36 +000070 return (sscanf
71 (string, "[%llu:%llu]",
Patrick McHardyb73691f2007-09-05 14:10:53 +000072 (unsigned long long *)pcnt,
73 (unsigned long long *)bcnt) == 2);
74 } else
Amin Azez8d3eccb2006-11-13 20:23:36 +000075 return (0 == 2);
76}
77
78/* global new argv and argc */
79static char *newargv[255];
Jan Engelhardt7a236f42008-03-03 12:30:41 +010080static unsigned int newargc = 0;
Amin Azez8d3eccb2006-11-13 20:23:36 +000081
82static char *oldargv[255];
Jan Engelhardt7a236f42008-03-03 12:30:41 +010083static unsigned int oldargc = 0;
Amin Azez8d3eccb2006-11-13 20:23:36 +000084
85/* arg meta data, were they quoted, frinstance */
86static int newargvattr[255];
87
88#define IPT_CHAIN_MAXNAMELEN IPT_TABLE_MAXNAMELEN
Patrick McHardyddffcfb2008-06-07 15:07:18 +020089static char closeActionTag[IPT_TABLE_MAXNAMELEN + 1];
90static char closeRuleTag[IPT_TABLE_MAXNAMELEN + 1];
91static char curTable[IPT_TABLE_MAXNAMELEN + 1];
92static char curChain[IPT_CHAIN_MAXNAMELEN + 1];
Amin Azez8d3eccb2006-11-13 20:23:36 +000093
Jan Engelhardtdbb77542008-02-11 00:33:30 +010094struct chain {
Amin Azez8d3eccb2006-11-13 20:23:36 +000095 char *chain;
96 char *policy;
97 struct ipt_counters count;
98 int created;
Jan Engelhardtdbb77542008-02-11 00:33:30 +010099};
Amin Azez8d3eccb2006-11-13 20:23:36 +0000100
101#define maxChains 10240 /* max chains per table */
Jan Engelhardtdbb77542008-02-11 00:33:30 +0100102static struct chain chains[maxChains];
Amin Azez8d3eccb2006-11-13 20:23:36 +0000103static int nextChain = 0;
104
105/* funCtion adding one argument to newargv, updating newargc
106 * returns true if argument added, false otherwise */
107static int
108add_argv(char *what, int quoted)
109{
110 DEBUGP("add_argv: %d %s\n", newargc, what);
Jan Engelhardt2c69b552009-04-30 19:32:02 +0200111 if (what && newargc + 1 < ARRAY_SIZE(newargv)) {
Amin Azez8d3eccb2006-11-13 20:23:36 +0000112 newargv[newargc] = strdup(what);
113 newargvattr[newargc] = quoted;
114 newargc++;
115 return 1;
116 } else
117 return 0;
118}
119
120static void
121free_argv(void)
122{
Jan Engelhardt7a236f42008-03-03 12:30:41 +0100123 unsigned int i;
Amin Azez8d3eccb2006-11-13 20:23:36 +0000124
125 for (i = 0; i < newargc; i++) {
126 free(newargv[i]);
127 newargv[i] = NULL;
128 }
129 newargc = 0;
130
131 for (i = 0; i < oldargc; i++) {
132 free(oldargv[i]);
133 oldargv[i] = NULL;
134 }
135 oldargc = 0;
136}
137
138/* save parsed rule for comparison with next rule
139 to perform action agregation on duplicate conditions */
140static void
141save_argv(void)
142{
Jan Engelhardt7a236f42008-03-03 12:30:41 +0100143 unsigned int i;
Amin Azez8d3eccb2006-11-13 20:23:36 +0000144
145 for (i = 0; i < oldargc; i++)
146 free(oldargv[i]);
147 oldargc = newargc;
148 newargc = 0;
149 for (i = 0; i < oldargc; i++) {
150 oldargv[i] = newargv[i];
151 newargv[i] = NULL;
152 }
153}
154
155/* like puts but with xml encoding */
156static void
157xmlEncode(char *text)
158{
159 while (text && *text) {
160 if ((unsigned char) (*text) >= 127)
161 printf("&#%d;", (unsigned char) (*text));
162 else if (*text == '&')
163 printf("&amp;");
164 else if (*text == '<')
165 printf("&lt;");
166 else if (*text == '>')
167 printf("&gt;");
168 else if (*text == '"')
169 printf("&quot;");
170 else
171 putchar(*text);
172 text++;
173 }
174}
175
176/* Output text as a comment, avoiding a double hyphen */
177static void
178xmlCommentEscape(char *comment)
179{
180 int h_count = 0;
181
182 while (comment && *comment) {
183 if (*comment == '-') {
184 h_count++;
185 if (h_count >= 2) {
186 h_count = 0;
187 putchar(' ');
188 }
189 putchar('*');
190 }
191 /* strip trailing newline */
192 if (*comment == '\n' && *(comment + 1) == 0);
193 else
194 putchar(*comment);
195 comment++;
196 }
197}
198
199static void
200xmlComment(char *comment)
201{
202 printf("<!-- ");
203 xmlCommentEscape(comment);
204 printf(" -->\n");
205}
206
207static void
208xmlAttrS(char *name, char *value)
209{
210 printf("%s=\"", name);
211 xmlEncode(value);
212 printf("\" ");
213}
214
215static void
216xmlAttrI(char *name, long long int num)
217{
218 printf("%s=\"%lld\" ", name, num);
219}
220
221static void
Max Kellermann9ee386a2008-01-29 13:48:05 +0000222closeChain(void)
Amin Azez8d3eccb2006-11-13 20:23:36 +0000223{
224 if (curChain[0] == 0)
225 return;
226
227 if (closeActionTag[0])
228 printf("%s\n", closeActionTag);
229 closeActionTag[0] = 0;
230 if (closeRuleTag[0])
231 printf("%s\n", closeRuleTag);
232 closeRuleTag[0] = 0;
233 if (curChain[0])
234 printf(" </chain>\n");
235 curChain[0] = 0;
236 //lastRule[0]=0;
237}
238
239static void
240openChain(char *chain, char *policy, struct ipt_counters *ctr, char close)
241{
242 closeChain();
243
244 strncpy(curChain, chain, IPT_CHAIN_MAXNAMELEN);
245 curChain[IPT_CHAIN_MAXNAMELEN] = '\0';
246
247 printf(" <chain ");
248 xmlAttrS("name", curChain);
249 if (strcmp(policy, "-") != 0)
250 xmlAttrS("policy", policy);
251 xmlAttrI("packet-count", (unsigned long long) ctr->pcnt);
252 xmlAttrI("byte-count", (unsigned long long) ctr->bcnt);
253 if (close) {
254 printf("%c", close);
255 curChain[0] = 0;
256 }
257 printf(">\n");
258}
259
260static int
261existsChain(char *chain)
262{
263 /* open a saved chain */
264 int c = 0;
265
266 if (0 == strcmp(curChain, chain))
267 return 1;
268 for (c = 0; c < nextChain; c++)
269 if (chains[c].chain && strcmp(chains[c].chain, chain) == 0)
270 return 1;
271 return 0;
272}
273
274static void
275needChain(char *chain)
276{
277 /* open a saved chain */
278 int c = 0;
279
280 if (0 == strcmp(curChain, chain))
281 return;
282
283 for (c = 0; c < nextChain; c++)
284 if (chains[c].chain && strcmp(chains[c].chain, chain) == 0) {
285 openChain(chains[c].chain, chains[c].policy,
286 &(chains[c].count), '\0');
287 /* And, mark it as done so we don't create
288 an empty chain at table-end time */
289 chains[c].created = 1;
290 }
291}
292
293static void
294saveChain(char *chain, char *policy, struct ipt_counters *ctr)
295{
296 if (nextChain >= maxChains) {
Jan Engelhardt1829ed42009-02-21 03:29:44 +0100297 xtables_error(PARAMETER_PROBLEM,
Amin Azez8d3eccb2006-11-13 20:23:36 +0000298 "%s: line %u chain name invalid\n",
Jamal Hadi Salim5dd19de2009-02-13 10:42:24 -0500299 prog_name, line);
Amin Azez8d3eccb2006-11-13 20:23:36 +0000300 exit(1);
301 };
302 chains[nextChain].chain = strdup(chain);
303 chains[nextChain].policy = strdup(policy);
304 chains[nextChain].count = *ctr;
305 chains[nextChain].created = 0;
306 nextChain++;
307}
308
309static void
Max Kellermann9ee386a2008-01-29 13:48:05 +0000310finishChains(void)
Amin Azez8d3eccb2006-11-13 20:23:36 +0000311{
312 int c;
313
314 for (c = 0; c < nextChain; c++)
315 if (!chains[c].created) {
316 openChain(chains[c].chain, chains[c].policy,
317 &(chains[c].count), '/');
318 free(chains[c].chain);
319 free(chains[c].policy);
320 }
321 nextChain = 0;
322}
323
324static void
Max Kellermann9ee386a2008-01-29 13:48:05 +0000325closeTable(void)
Amin Azez8d3eccb2006-11-13 20:23:36 +0000326{
327 closeChain();
328 finishChains();
329 if (curTable[0])
330 printf(" </table>\n");
331 curTable[0] = 0;
332}
333
334static void
335openTable(char *table)
336{
337 closeTable();
338
339 strncpy(curTable, table, IPT_TABLE_MAXNAMELEN);
340 curTable[IPT_TABLE_MAXNAMELEN] = '\0';
341
342 printf(" <table ");
343 xmlAttrS("name", curTable);
344 printf(">\n");
345}
346
347// is char* -j --jump -g or --goto
348static int
349isTarget(char *arg)
350{
351 return ((arg)
352 && (strcmp((arg), "-j") == 0 || strcmp((arg), "--jump") == 0
353 || strcmp((arg), "-g") == 0
354 || strcmp((arg), "--goto") == 0));
355}
356
Sam Liddicott8e528152007-07-17 17:02:04 +0000357// is it a terminating target like -j ACCEPT, etc
358// (or I guess -j SNAT in nat table, but we don't check for that yet
359static int
360isTerminatingTarget(char *arg)
361{
362 return ((arg)
363 && (strcmp((arg), "ACCEPT") == 0
364 || strcmp((arg), "DROP") == 0
365 || strcmp((arg), "QUEUE") == 0
366 || strcmp((arg), "RETURN") == 0));
367}
368
Amin Azez8d3eccb2006-11-13 20:23:36 +0000369// part=-1 means do conditions, part=1 means do rules, part=0 means do both
370static void
371do_rule_part(char *leveltag1, char *leveltag2, int part, int argc,
372 char *argv[], int argvattr[])
373{
374 int arg = 1; // ignore leading -A
375 char invert_next = 0;
376 char *thisChain = NULL;
377 char *spacer = ""; // space when needed to assemble arguments
378 char *level1 = NULL;
379 char *level2 = NULL;
380 char *leveli1 = " ";
381 char *leveli2 = " ";
382
383#define CLOSE_LEVEL(LEVEL) \
384 do { \
385 if (level ## LEVEL) printf("</%s>\n", \
386 (leveltag ## LEVEL)?(leveltag ## LEVEL):(level ## LEVEL)); \
387 level ## LEVEL=NULL;\
388 } while(0)
389
390#define OPEN_LEVEL(LEVEL,TAG) \
391 do {\
392 level ## LEVEL=TAG;\
393 if (leveltag ## LEVEL) {\
394 printf("%s<%s ", (leveli ## LEVEL), \
395 (leveltag ## LEVEL));\
396 xmlAttrS("type", (TAG)); \
397 } else printf("%s<%s ", (leveli ## LEVEL), (level ## LEVEL)); \
398 } while(0)
399
400 thisChain = argv[arg++];
401
402 if (part == 1) { /* skip */
403 /* use argvattr to tell which arguments were quoted
404 to avoid comparing quoted arguments, like comments, to -j, */
405 while (arg < argc && (argvattr[arg] || !isTarget(argv[arg])))
406 arg++;
407 }
408
409 /* Before we start, if the first arg is -[^-] and not -m or -j or -g
410 then start a dummy <match> tag for old style built-in matches.
411 We would do this in any case, but no need if it would be empty */
412 if (arg < argc && argv[arg][0] == '-' && !isTarget(argv[arg])
413 && strcmp(argv[arg], "-m") != 0) {
414 OPEN_LEVEL(1, "match");
415 printf(">\n");
416 }
417 while (arg < argc) {
418 // If ! is followed by -* then apply to that else output as data
419 // Stop, if we need to
420 if (part == -1 && !argvattr[arg] && (isTarget(argv[arg]))) {
421 break;
422 } else if (!argvattr[arg] && strcmp(argv[arg], "!") == 0) {
423 if ((arg + 1) < argc && argv[arg + 1][0] == '-')
424 invert_next = '!';
425 else
426 printf("%s%s", spacer, argv[arg]);
427 spacer = " ";
428 } else if (!argvattr[arg] && isTarget(argv[arg])
429 && existsChain(argv[arg + 1])
430 && (2 + arg >= argc)) {
431 if (!((1 + arg) < argc))
432 // no args to -j, -m or -g, ignore & finish loop
433 break;
434 CLOSE_LEVEL(2);
435 if (level1)
436 printf("%s", leveli1);
437 CLOSE_LEVEL(1);
438 spacer = "";
439 invert_next = 0;
440 if (strcmp(argv[arg], "-g") == 0
441 || strcmp(argv[arg], "--goto") == 0) {
442 /* goto user chain */
443 OPEN_LEVEL(1, "goto");
444 printf(">\n");
445 arg++;
446 OPEN_LEVEL(2, argv[arg]);
447 printf("/>\n");
448 level2 = NULL;
449 } else {
450 /* call user chain */
451 OPEN_LEVEL(1, "call");
452 printf(">\n");
453 arg++;
454 OPEN_LEVEL(2, argv[arg]);
455 printf("/>\n");
456 level2 = NULL;
457 }
458 } else if (!argvattr[arg]
459 && (isTarget(argv[arg])
460 || strcmp(argv[arg], "-m") == 0
461 || strcmp(argv[arg], "--module") == 0)) {
462 if (!((1 + arg) < argc))
463 // no args to -j, -m or -g, ignore & finish loop
464 break;
465 CLOSE_LEVEL(2);
466 if (level1)
467 printf("%s", leveli1);
468 CLOSE_LEVEL(1);
469 spacer = "";
470 invert_next = 0;
471 arg++;
472 OPEN_LEVEL(1, (argv[arg]));
473 // Optimize case, can we close this tag already?
474 if ((arg + 1) >= argc || (!argvattr[arg + 1]
475 && (isTarget(argv[arg + 1])
476 || strcmp(argv[arg + 1],
477 "-m") == 0
478 || strcmp(argv[arg + 1],
479 "--module") ==
480 0))) {
481 printf(" />\n");
482 level1 = NULL;
483 } else {
484 printf(">\n");
485 }
486 } else if (!argvattr[arg] && argv[arg][0] == '-') {
487 char *tag;
488 CLOSE_LEVEL(2);
489 // Skip past any -
490 tag = argv[arg];
491 while (*tag == '-' && *tag)
492 tag++;
493
494 spacer = "";
495 OPEN_LEVEL(2, tag);
496 if (invert_next)
497 printf(" invert=\"1\"");
498 invert_next = 0;
499
500 // Optimize case, can we close this tag already?
501 if (!((arg + 1) < argc)
502 || (argv[arg + 1][0] == '-' /* NOT QUOTED */ )) {
503 printf(" />\n");
504 level2 = NULL;
505 } else {
506 printf(">");
507 }
508 } else { // regular data
509 char *spaces = strchr(argv[arg], ' ');
510 printf("%s", spacer);
511 if (spaces || argvattr[arg])
512 printf("&quot;");
513 // if argv[arg] contains a space, enclose in quotes
514 xmlEncode(argv[arg]);
515 if (spaces || argvattr[arg])
516 printf("&quot;");
517 spacer = " ";
518 }
519 arg++;
520 }
521 CLOSE_LEVEL(2);
522 if (level1)
523 printf("%s", leveli1);
524 CLOSE_LEVEL(1);
Amin Azez8d3eccb2006-11-13 20:23:36 +0000525}
526
527static int
Max Kellermann9ee386a2008-01-29 13:48:05 +0000528compareRules(void)
Amin Azez8d3eccb2006-11-13 20:23:36 +0000529{
530 /* compare arguments up to -j or -g for match.
531 NOTE: We don't want to combine actions if there were no criteria
532 in each rule, or rules didn't have an action
533 NOTE: Depends on arguments being in some kind of "normal" order which
534 is the case when processing the ACTUAL output of actual iptables-save
535 rather than a file merely in a compatable format */
536
Jan Engelhardt7a236f42008-03-03 12:30:41 +0100537 unsigned int old = 0;
538 unsigned int new = 0;
Amin Azez8d3eccb2006-11-13 20:23:36 +0000539
540 int compare = 0;
541
542 while (new < newargc && old < oldargc) {
543 if (isTarget(oldargv[old]) && isTarget(newargv[new])) {
Sam Liddicott8e528152007-07-17 17:02:04 +0000544 /* if oldarg was a terminating action then it makes no sense
545 * to combine further actions into the same xml */
546 if (((strcmp((oldargv[old]), "-j") == 0
547 || strcmp((oldargv[old]), "--jump") == 0)
548 && old+1 < oldargc
549 && isTerminatingTarget(oldargv[old+1]) )
550 || strcmp((oldargv[old]), "-g") == 0
551 || strcmp((oldargv[old]), "--goto") == 0 ) {
552 /* Previous rule had terminating action */
553 compare = 0;
554 } else {
555 compare = 1;
556 }
Amin Azez8d3eccb2006-11-13 20:23:36 +0000557 break;
558 }
559 // break when old!=new
560 if (strcmp(oldargv[old], newargv[new]) != 0) {
561 compare = 0;
562 break;
563 }
564
565 old++;
566 new++;
567 }
568 // We won't match unless both rules had a target.
569 // This means we don't combine target-less rules, which is good
570
571 return compare == 1;
572}
573
574/* has a nice parsed rule starting with -A */
575static void
576do_rule(char *pcnt, char *bcnt, int argc, char *argv[], int argvattr[])
577{
578 /* are these conditions the same as the previous rule?
579 * If so, skip arg straight to -j or -g */
580 if (combine && argc > 2 && !isTarget(argv[2]) && compareRules()) {
581 xmlComment("Combine action from next rule");
582 } else {
583
584 if (closeActionTag[0]) {
585 printf("%s\n", closeActionTag);
586 closeActionTag[0] = 0;
587 }
588 if (closeRuleTag[0]) {
589 printf("%s\n", closeRuleTag);
590 closeRuleTag[0] = 0;
591 }
592
593 printf(" <rule ");
594 //xmlAttrS("table",curTable); // not needed in full mode
595 //xmlAttrS("chain",argv[1]); // not needed in full mode
596 if (pcnt)
597 xmlAttrS("packet-count", pcnt);
598 if (bcnt)
599 xmlAttrS("byte-count", bcnt);
600 printf(">\n");
601
602 strncpy(closeRuleTag, " </rule>\n", IPT_TABLE_MAXNAMELEN);
603 closeRuleTag[IPT_TABLE_MAXNAMELEN] = '\0';
604
605 /* no point in writing out condition if there isn't one */
606 if (argc >= 3 && !isTarget(argv[2])) {
607 printf(" <conditions>\n");
608 do_rule_part(NULL, NULL, -1, argc, argv, argvattr);
609 printf(" </conditions>\n");
610 }
611 }
612 /* Write out the action */
613 //do_rule_part("action","arg",1,argc,argv,argvattr);
614 if (!closeActionTag[0]) {
615 printf(" <actions>\n");
616 strncpy(closeActionTag, " </actions>\n",
617 IPT_TABLE_MAXNAMELEN);
618 closeActionTag[IPT_TABLE_MAXNAMELEN] = '\0';
619 }
620 do_rule_part(NULL, NULL, 1, argc, argv, argvattr);
621}
622
Amin Azez8d3eccb2006-11-13 20:23:36 +0000623#ifdef IPTABLES_MULTI
624int
Lutz Jaenickee78c69c2006-12-09 13:06:04 +0000625iptables_xml_main(int argc, char *argv[])
Amin Azez8d3eccb2006-11-13 20:23:36 +0000626#else
627int
628main(int argc, char *argv[])
629#endif
630{
631 char buffer[10240];
632 int c;
633 FILE *in;
634
Amin Azez8d3eccb2006-11-13 20:23:36 +0000635 line = 0;
636
Jamal Hadi Salim4dcdc9b2009-02-11 13:03:34 +0100637 xtables_set_params(&iptables_xml_globals);
Amin Azez8d3eccb2006-11-13 20:23:36 +0000638 while ((c = getopt_long(argc, argv, "cvh", options, NULL)) != -1) {
639 switch (c) {
640 case 'c':
641 combine = 1;
642 break;
643 case 'v':
644 printf("xptables-xml\n");
645 verbose = 1;
646 break;
647 case 'h':
Jan Engelhardtdacafa52009-01-27 20:56:23 +0100648 print_usage("iptables-xml", IPTABLES_VERSION);
Amin Azez8d3eccb2006-11-13 20:23:36 +0000649 break;
650 }
651 }
652
653 if (optind == argc - 1) {
Maciej Zenczykowskia2397282011-04-04 15:30:32 +0200654 in = fopen(argv[optind], "re");
Amin Azez8d3eccb2006-11-13 20:23:36 +0000655 if (!in) {
656 fprintf(stderr, "Can't open %s: %s", argv[optind],
657 strerror(errno));
658 exit(1);
659 }
660 } else if (optind < argc) {
661 fprintf(stderr, "Unknown arguments found on commandline");
662 exit(1);
663 } else
664 in = stdin;
665
666 printf("<iptables-rules version=\"1.0\">\n");
667
668 /* Grab standard input. */
669 while (fgets(buffer, sizeof(buffer), in)) {
670 int ret = 0;
671
672 line++;
673
674 if (buffer[0] == '\n')
675 continue;
676 else if (buffer[0] == '#') {
677 xmlComment(buffer);
678 continue;
679 }
680
681 if (verbose) {
682 printf("<!-- line %d ", line);
683 xmlCommentEscape(buffer);
684 printf(" -->\n");
685 }
686
687 if ((strcmp(buffer, "COMMIT\n") == 0) && (curTable[0])) {
688 DEBUGP("Calling commit\n");
689 closeTable();
690 ret = 1;
691 } else if ((buffer[0] == '*')) {
692 /* New table */
693 char *table;
694
695 table = strtok(buffer + 1, " \t\n");
696 DEBUGP("line %u, table '%s'\n", line, table);
697 if (!table) {
Jan Engelhardt1829ed42009-02-21 03:29:44 +0100698 xtables_error(PARAMETER_PROBLEM,
Amin Azez8d3eccb2006-11-13 20:23:36 +0000699 "%s: line %u table name invalid\n",
Jamal Hadi Salim5dd19de2009-02-13 10:42:24 -0500700 prog_name, line);
Amin Azez8d3eccb2006-11-13 20:23:36 +0000701 exit(1);
702 }
703 openTable(table);
704
705 ret = 1;
706 } else if ((buffer[0] == ':') && (curTable[0])) {
707 /* New chain. */
708 char *policy, *chain;
709 struct ipt_counters count;
710 char *ctrs;
711
712 chain = strtok(buffer + 1, " \t\n");
713 DEBUGP("line %u, chain '%s'\n", line, chain);
714 if (!chain) {
Jan Engelhardt1829ed42009-02-21 03:29:44 +0100715 xtables_error(PARAMETER_PROBLEM,
Amin Azez8d3eccb2006-11-13 20:23:36 +0000716 "%s: line %u chain name invalid\n",
Jamal Hadi Salim5dd19de2009-02-13 10:42:24 -0500717 prog_name, line);
Amin Azez8d3eccb2006-11-13 20:23:36 +0000718 exit(1);
719 }
720
721 DEBUGP("Creating new chain '%s'\n", chain);
722
723 policy = strtok(NULL, " \t\n");
724 DEBUGP("line %u, policy '%s'\n", line, policy);
725 if (!policy) {
Jan Engelhardt1829ed42009-02-21 03:29:44 +0100726 xtables_error(PARAMETER_PROBLEM,
Amin Azez8d3eccb2006-11-13 20:23:36 +0000727 "%s: line %u policy invalid\n",
Jamal Hadi Salim5dd19de2009-02-13 10:42:24 -0500728 prog_name, line);
Amin Azez8d3eccb2006-11-13 20:23:36 +0000729 exit(1);
730 }
731
732 ctrs = strtok(NULL, " \t\n");
733 parse_counters(ctrs, &count);
734 saveChain(chain, policy, &count);
735
736 ret = 1;
737 } else if (curTable[0]) {
Jan Engelhardt7a236f42008-03-03 12:30:41 +0100738 unsigned int a;
Amin Azez8d3eccb2006-11-13 20:23:36 +0000739 char *ptr = buffer;
740 char *pcnt = NULL;
741 char *bcnt = NULL;
742 char *parsestart;
743 char *chain = NULL;
744
745 /* the parser */
746 char *param_start, *curchar;
747 int quote_open, quoted;
748
749 /* reset the newargv */
750 newargc = 0;
751
752 if (buffer[0] == '[') {
753 /* we have counters in our input */
754 ptr = strchr(buffer, ']');
755 if (!ptr)
Jan Engelhardt1829ed42009-02-21 03:29:44 +0100756 xtables_error(PARAMETER_PROBLEM,
Amin Azez8d3eccb2006-11-13 20:23:36 +0000757 "Bad line %u: need ]\n",
758 line);
759
760 pcnt = strtok(buffer + 1, ":");
761 if (!pcnt)
Jan Engelhardt1829ed42009-02-21 03:29:44 +0100762 xtables_error(PARAMETER_PROBLEM,
Amin Azez8d3eccb2006-11-13 20:23:36 +0000763 "Bad line %u: need :\n",
764 line);
765
766 bcnt = strtok(NULL, "]");
767 if (!bcnt)
Jan Engelhardt1829ed42009-02-21 03:29:44 +0100768 xtables_error(PARAMETER_PROBLEM,
Amin Azez8d3eccb2006-11-13 20:23:36 +0000769 "Bad line %u: need ]\n",
770 line);
771
772 /* start command parsing after counter */
773 parsestart = ptr + 1;
774 } else {
775 /* start command parsing at start of line */
776 parsestart = buffer;
777 }
778
779
780 /* This is a 'real' parser crafted in artist mode
781 * not hacker mode. If the author can live with that
782 * then so can everyone else */
783
784 quote_open = 0;
785 /* We need to know which args were quoted so we
786 can preserve quote */
787 quoted = 0;
788 param_start = parsestart;
789
790 for (curchar = parsestart; *curchar; curchar++) {
791 if (*curchar == '"') {
792 /* quote_open cannot be true if there
793 * was no previous character. Thus,
794 * curchar-1 has to be within bounds */
795 if (quote_open &&
796 *(curchar - 1) != '\\') {
797 quote_open = 0;
798 *curchar = ' ';
799 } else {
800 quote_open = 1;
801 quoted = 1;
802 param_start++;
803 }
804 }
805 if (*curchar == ' '
806 || *curchar == '\t' || *curchar == '\n') {
807 char param_buffer[1024];
808 int param_len = curchar - param_start;
809
810 if (quote_open)
811 continue;
812
813 if (!param_len) {
814 /* two spaces? */
815 param_start++;
816 continue;
817 }
818
819 /* end of one parameter */
820 strncpy(param_buffer, param_start,
821 param_len);
822 *(param_buffer + param_len) = '\0';
823
824 /* check if table name specified */
825 if (!strncmp(param_buffer, "-t", 3)
826 || !strncmp(param_buffer,
827 "--table", 8)) {
Jan Engelhardt1829ed42009-02-21 03:29:44 +0100828 xtables_error(PARAMETER_PROBLEM,
Amin Azez8d3eccb2006-11-13 20:23:36 +0000829 "Line %u seems to have a "
830 "-t table option.\n",
831 line);
832 exit(1);
833 }
834
835 add_argv(param_buffer, quoted);
836 if (newargc >= 2
837 && 0 ==
838 strcmp(newargv[newargc - 2], "-A"))
839 chain = newargv[newargc - 1];
840 quoted = 0;
841 param_start += param_len + 1;
842 } else {
843 /* regular character, skip */
844 }
845 }
846
847 DEBUGP("calling do_command(%u, argv, &%s, handle):\n",
848 newargc, curTable);
849
850 for (a = 0; a < newargc; a++)
851 DEBUGP("argv[%u]: %s\n", a, newargv[a]);
852
853 needChain(chain);// Should we explicitly look for -A
854 do_rule(pcnt, bcnt, newargc, newargv, newargvattr);
855
856 save_argv();
857 ret = 1;
858 }
859 if (!ret) {
860 fprintf(stderr, "%s: line %u failed\n",
Jamal Hadi Salim5dd19de2009-02-13 10:42:24 -0500861 prog_name, line);
Amin Azez8d3eccb2006-11-13 20:23:36 +0000862 exit(1);
863 }
864 }
865 if (curTable[0]) {
866 fprintf(stderr, "%s: COMMIT expected at line %u\n",
Jamal Hadi Salim5dd19de2009-02-13 10:42:24 -0500867 prog_name, line + 1);
Amin Azez8d3eccb2006-11-13 20:23:36 +0000868 exit(1);
869 }
870
Jan Engelhardtf1afcc82009-06-10 13:52:58 +0200871 if (in != NULL)
872 fclose(in);
Amin Azez8d3eccb2006-11-13 20:23:36 +0000873 printf("</iptables-rules>\n");
874 free_argv();
875
876 return 0;
877}