blob: a3f6987236003fc3b53cd8670f864fd1c298cf42 [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
7 *
8 * $Id: iptables-xml.c,v 1.4 2006/11/09 12:02:17 azez Exp $
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 <stdarg.h>
17#include "iptables.h"
18#include "libiptc/libiptc.h"
Jan Engelhardt33690a12008-02-11 00:54:00 +010019#include "iptables-multi.h"
Amin Azez8d3eccb2006-11-13 20:23:36 +000020
21#ifdef DEBUG
22#define DEBUGP(x, args...) fprintf(stderr, x, ## args)
23#else
24#define DEBUGP(x, args...)
25#endif
26
27/* no need to link with iptables.o */
28const char *program_name;
29const char *program_version;
Amin Azez8d3eccb2006-11-13 20:23:36 +000030
Lutz Jaenickee78c69c2006-12-09 13:06:04 +000031#ifndef IPTABLES_MULTI
32int line = 0;
Jan Engelhardtd8840512007-08-01 15:19:15 +000033void exit_error(enum exittype status, const char *msg, ...)
Amin Azez8d3eccb2006-11-13 20:23:36 +000034{
35 va_list args;
36
37 va_start(args, msg);
38 fprintf(stderr, "%s v%s: ", program_name, program_version);
39 vfprintf(stderr, msg, args);
40 va_end(args);
41 fprintf(stderr, "\n");
42 /* On error paths, make sure that we don't leak memory */
43 exit(status);
44}
Lutz Jaenickee78c69c2006-12-09 13:06:04 +000045#endif
Amin Azez8d3eccb2006-11-13 20:23:36 +000046
47static void print_usage(const char *name, const char *version)
48 __attribute__ ((noreturn));
49
50static int verbose = 0;
51/* Whether to combine actions of sequential rules with identical conditions */
52static int combine = 0;
53/* Keeping track of external matches and targets. */
54static struct option options[] = {
Patrick McHardyddffcfb2008-06-07 15:07:18 +020055 {"verbose", 0, NULL, 'v'},
56 {"combine", 0, NULL, 'c'},
57 {"help", 0, NULL, 'h'},
Max Kellermann9ee386a2008-01-29 13:48:05 +000058 { .name = NULL }
Amin Azez8d3eccb2006-11-13 20:23:36 +000059};
60
61static void
62print_usage(const char *name, const char *version)
63{
64 fprintf(stderr, "Usage: %s [-c] [-v] [-h]\n"
65 " [--combine ]\n"
66 " [ --verbose ]\n" " [ --help ]\n", name);
67
68 exit(1);
69}
70
Lutz Jaenickee78c69c2006-12-09 13:06:04 +000071static int
Amin Azez8d3eccb2006-11-13 20:23:36 +000072parse_counters(char *string, struct ipt_counters *ctr)
73{
Patrick McHardyb73691f2007-09-05 14:10:53 +000074 u_int64_t *pcnt, *bcnt;
75
76 if (string != NULL) {
77 pcnt = &ctr->pcnt;
78 bcnt = &ctr->bcnt;
Amin Azez8d3eccb2006-11-13 20:23:36 +000079 return (sscanf
80 (string, "[%llu:%llu]",
Patrick McHardyb73691f2007-09-05 14:10:53 +000081 (unsigned long long *)pcnt,
82 (unsigned long long *)bcnt) == 2);
83 } else
Amin Azez8d3eccb2006-11-13 20:23:36 +000084 return (0 == 2);
85}
86
87/* global new argv and argc */
88static char *newargv[255];
Jan Engelhardt7a236f42008-03-03 12:30:41 +010089static unsigned int newargc = 0;
Amin Azez8d3eccb2006-11-13 20:23:36 +000090
91static char *oldargv[255];
Jan Engelhardt7a236f42008-03-03 12:30:41 +010092static unsigned int oldargc = 0;
Amin Azez8d3eccb2006-11-13 20:23:36 +000093
94/* arg meta data, were they quoted, frinstance */
95static int newargvattr[255];
96
97#define IPT_CHAIN_MAXNAMELEN IPT_TABLE_MAXNAMELEN
Patrick McHardyddffcfb2008-06-07 15:07:18 +020098static char closeActionTag[IPT_TABLE_MAXNAMELEN + 1];
99static char closeRuleTag[IPT_TABLE_MAXNAMELEN + 1];
100static char curTable[IPT_TABLE_MAXNAMELEN + 1];
101static char curChain[IPT_CHAIN_MAXNAMELEN + 1];
Amin Azez8d3eccb2006-11-13 20:23:36 +0000102
Jan Engelhardtdbb77542008-02-11 00:33:30 +0100103struct chain {
Amin Azez8d3eccb2006-11-13 20:23:36 +0000104 char *chain;
105 char *policy;
106 struct ipt_counters count;
107 int created;
Jan Engelhardtdbb77542008-02-11 00:33:30 +0100108};
Amin Azez8d3eccb2006-11-13 20:23:36 +0000109
110#define maxChains 10240 /* max chains per table */
Jan Engelhardtdbb77542008-02-11 00:33:30 +0100111static struct chain chains[maxChains];
Amin Azez8d3eccb2006-11-13 20:23:36 +0000112static int nextChain = 0;
113
114/* funCtion adding one argument to newargv, updating newargc
115 * returns true if argument added, false otherwise */
116static int
117add_argv(char *what, int quoted)
118{
119 DEBUGP("add_argv: %d %s\n", newargc, what);
120 if (what && ((newargc + 1) < sizeof(newargv) / sizeof(char *))) {
121 newargv[newargc] = strdup(what);
122 newargvattr[newargc] = quoted;
123 newargc++;
124 return 1;
125 } else
126 return 0;
127}
128
129static void
130free_argv(void)
131{
Jan Engelhardt7a236f42008-03-03 12:30:41 +0100132 unsigned int i;
Amin Azez8d3eccb2006-11-13 20:23:36 +0000133
134 for (i = 0; i < newargc; i++) {
135 free(newargv[i]);
136 newargv[i] = NULL;
137 }
138 newargc = 0;
139
140 for (i = 0; i < oldargc; i++) {
141 free(oldargv[i]);
142 oldargv[i] = NULL;
143 }
144 oldargc = 0;
145}
146
147/* save parsed rule for comparison with next rule
148 to perform action agregation on duplicate conditions */
149static void
150save_argv(void)
151{
Jan Engelhardt7a236f42008-03-03 12:30:41 +0100152 unsigned int i;
Amin Azez8d3eccb2006-11-13 20:23:36 +0000153
154 for (i = 0; i < oldargc; i++)
155 free(oldargv[i]);
156 oldargc = newargc;
157 newargc = 0;
158 for (i = 0; i < oldargc; i++) {
159 oldargv[i] = newargv[i];
160 newargv[i] = NULL;
161 }
162}
163
164/* like puts but with xml encoding */
165static void
166xmlEncode(char *text)
167{
168 while (text && *text) {
169 if ((unsigned char) (*text) >= 127)
170 printf("&#%d;", (unsigned char) (*text));
171 else if (*text == '&')
172 printf("&amp;");
173 else if (*text == '<')
174 printf("&lt;");
175 else if (*text == '>')
176 printf("&gt;");
177 else if (*text == '"')
178 printf("&quot;");
179 else
180 putchar(*text);
181 text++;
182 }
183}
184
185/* Output text as a comment, avoiding a double hyphen */
186static void
187xmlCommentEscape(char *comment)
188{
189 int h_count = 0;
190
191 while (comment && *comment) {
192 if (*comment == '-') {
193 h_count++;
194 if (h_count >= 2) {
195 h_count = 0;
196 putchar(' ');
197 }
198 putchar('*');
199 }
200 /* strip trailing newline */
201 if (*comment == '\n' && *(comment + 1) == 0);
202 else
203 putchar(*comment);
204 comment++;
205 }
206}
207
208static void
209xmlComment(char *comment)
210{
211 printf("<!-- ");
212 xmlCommentEscape(comment);
213 printf(" -->\n");
214}
215
216static void
217xmlAttrS(char *name, char *value)
218{
219 printf("%s=\"", name);
220 xmlEncode(value);
221 printf("\" ");
222}
223
224static void
225xmlAttrI(char *name, long long int num)
226{
227 printf("%s=\"%lld\" ", name, num);
228}
229
230static void
Max Kellermann9ee386a2008-01-29 13:48:05 +0000231closeChain(void)
Amin Azez8d3eccb2006-11-13 20:23:36 +0000232{
233 if (curChain[0] == 0)
234 return;
235
236 if (closeActionTag[0])
237 printf("%s\n", closeActionTag);
238 closeActionTag[0] = 0;
239 if (closeRuleTag[0])
240 printf("%s\n", closeRuleTag);
241 closeRuleTag[0] = 0;
242 if (curChain[0])
243 printf(" </chain>\n");
244 curChain[0] = 0;
245 //lastRule[0]=0;
246}
247
248static void
249openChain(char *chain, char *policy, struct ipt_counters *ctr, char close)
250{
251 closeChain();
252
253 strncpy(curChain, chain, IPT_CHAIN_MAXNAMELEN);
254 curChain[IPT_CHAIN_MAXNAMELEN] = '\0';
255
256 printf(" <chain ");
257 xmlAttrS("name", curChain);
258 if (strcmp(policy, "-") != 0)
259 xmlAttrS("policy", policy);
260 xmlAttrI("packet-count", (unsigned long long) ctr->pcnt);
261 xmlAttrI("byte-count", (unsigned long long) ctr->bcnt);
262 if (close) {
263 printf("%c", close);
264 curChain[0] = 0;
265 }
266 printf(">\n");
267}
268
269static int
270existsChain(char *chain)
271{
272 /* open a saved chain */
273 int c = 0;
274
275 if (0 == strcmp(curChain, chain))
276 return 1;
277 for (c = 0; c < nextChain; c++)
278 if (chains[c].chain && strcmp(chains[c].chain, chain) == 0)
279 return 1;
280 return 0;
281}
282
283static void
284needChain(char *chain)
285{
286 /* open a saved chain */
287 int c = 0;
288
289 if (0 == strcmp(curChain, chain))
290 return;
291
292 for (c = 0; c < nextChain; c++)
293 if (chains[c].chain && strcmp(chains[c].chain, chain) == 0) {
294 openChain(chains[c].chain, chains[c].policy,
295 &(chains[c].count), '\0');
296 /* And, mark it as done so we don't create
297 an empty chain at table-end time */
298 chains[c].created = 1;
299 }
300}
301
302static void
303saveChain(char *chain, char *policy, struct ipt_counters *ctr)
304{
305 if (nextChain >= maxChains) {
306 exit_error(PARAMETER_PROBLEM,
307 "%s: line %u chain name invalid\n",
308 program_name, line);
309 exit(1);
310 };
311 chains[nextChain].chain = strdup(chain);
312 chains[nextChain].policy = strdup(policy);
313 chains[nextChain].count = *ctr;
314 chains[nextChain].created = 0;
315 nextChain++;
316}
317
318static void
Max Kellermann9ee386a2008-01-29 13:48:05 +0000319finishChains(void)
Amin Azez8d3eccb2006-11-13 20:23:36 +0000320{
321 int c;
322
323 for (c = 0; c < nextChain; c++)
324 if (!chains[c].created) {
325 openChain(chains[c].chain, chains[c].policy,
326 &(chains[c].count), '/');
327 free(chains[c].chain);
328 free(chains[c].policy);
329 }
330 nextChain = 0;
331}
332
333static void
Max Kellermann9ee386a2008-01-29 13:48:05 +0000334closeTable(void)
Amin Azez8d3eccb2006-11-13 20:23:36 +0000335{
336 closeChain();
337 finishChains();
338 if (curTable[0])
339 printf(" </table>\n");
340 curTable[0] = 0;
341}
342
343static void
344openTable(char *table)
345{
346 closeTable();
347
348 strncpy(curTable, table, IPT_TABLE_MAXNAMELEN);
349 curTable[IPT_TABLE_MAXNAMELEN] = '\0';
350
351 printf(" <table ");
352 xmlAttrS("name", curTable);
353 printf(">\n");
354}
355
356// is char* -j --jump -g or --goto
357static int
358isTarget(char *arg)
359{
360 return ((arg)
361 && (strcmp((arg), "-j") == 0 || strcmp((arg), "--jump") == 0
362 || strcmp((arg), "-g") == 0
363 || strcmp((arg), "--goto") == 0));
364}
365
Sam Liddicott8e528152007-07-17 17:02:04 +0000366// is it a terminating target like -j ACCEPT, etc
367// (or I guess -j SNAT in nat table, but we don't check for that yet
368static int
369isTerminatingTarget(char *arg)
370{
371 return ((arg)
372 && (strcmp((arg), "ACCEPT") == 0
373 || strcmp((arg), "DROP") == 0
374 || strcmp((arg), "QUEUE") == 0
375 || strcmp((arg), "RETURN") == 0));
376}
377
Amin Azez8d3eccb2006-11-13 20:23:36 +0000378// part=-1 means do conditions, part=1 means do rules, part=0 means do both
379static void
380do_rule_part(char *leveltag1, char *leveltag2, int part, int argc,
381 char *argv[], int argvattr[])
382{
383 int arg = 1; // ignore leading -A
384 char invert_next = 0;
385 char *thisChain = NULL;
386 char *spacer = ""; // space when needed to assemble arguments
387 char *level1 = NULL;
388 char *level2 = NULL;
389 char *leveli1 = " ";
390 char *leveli2 = " ";
391
392#define CLOSE_LEVEL(LEVEL) \
393 do { \
394 if (level ## LEVEL) printf("</%s>\n", \
395 (leveltag ## LEVEL)?(leveltag ## LEVEL):(level ## LEVEL)); \
396 level ## LEVEL=NULL;\
397 } while(0)
398
399#define OPEN_LEVEL(LEVEL,TAG) \
400 do {\
401 level ## LEVEL=TAG;\
402 if (leveltag ## LEVEL) {\
403 printf("%s<%s ", (leveli ## LEVEL), \
404 (leveltag ## LEVEL));\
405 xmlAttrS("type", (TAG)); \
406 } else printf("%s<%s ", (leveli ## LEVEL), (level ## LEVEL)); \
407 } while(0)
408
409 thisChain = argv[arg++];
410
411 if (part == 1) { /* skip */
412 /* use argvattr to tell which arguments were quoted
413 to avoid comparing quoted arguments, like comments, to -j, */
414 while (arg < argc && (argvattr[arg] || !isTarget(argv[arg])))
415 arg++;
416 }
417
418 /* Before we start, if the first arg is -[^-] and not -m or -j or -g
419 then start a dummy <match> tag for old style built-in matches.
420 We would do this in any case, but no need if it would be empty */
421 if (arg < argc && argv[arg][0] == '-' && !isTarget(argv[arg])
422 && strcmp(argv[arg], "-m") != 0) {
423 OPEN_LEVEL(1, "match");
424 printf(">\n");
425 }
426 while (arg < argc) {
427 // If ! is followed by -* then apply to that else output as data
428 // Stop, if we need to
429 if (part == -1 && !argvattr[arg] && (isTarget(argv[arg]))) {
430 break;
431 } else if (!argvattr[arg] && strcmp(argv[arg], "!") == 0) {
432 if ((arg + 1) < argc && argv[arg + 1][0] == '-')
433 invert_next = '!';
434 else
435 printf("%s%s", spacer, argv[arg]);
436 spacer = " ";
437 } else if (!argvattr[arg] && isTarget(argv[arg])
438 && existsChain(argv[arg + 1])
439 && (2 + arg >= argc)) {
440 if (!((1 + arg) < argc))
441 // no args to -j, -m or -g, ignore & finish loop
442 break;
443 CLOSE_LEVEL(2);
444 if (level1)
445 printf("%s", leveli1);
446 CLOSE_LEVEL(1);
447 spacer = "";
448 invert_next = 0;
449 if (strcmp(argv[arg], "-g") == 0
450 || strcmp(argv[arg], "--goto") == 0) {
451 /* goto user chain */
452 OPEN_LEVEL(1, "goto");
453 printf(">\n");
454 arg++;
455 OPEN_LEVEL(2, argv[arg]);
456 printf("/>\n");
457 level2 = NULL;
458 } else {
459 /* call user chain */
460 OPEN_LEVEL(1, "call");
461 printf(">\n");
462 arg++;
463 OPEN_LEVEL(2, argv[arg]);
464 printf("/>\n");
465 level2 = NULL;
466 }
467 } else if (!argvattr[arg]
468 && (isTarget(argv[arg])
469 || strcmp(argv[arg], "-m") == 0
470 || strcmp(argv[arg], "--module") == 0)) {
471 if (!((1 + arg) < argc))
472 // no args to -j, -m or -g, ignore & finish loop
473 break;
474 CLOSE_LEVEL(2);
475 if (level1)
476 printf("%s", leveli1);
477 CLOSE_LEVEL(1);
478 spacer = "";
479 invert_next = 0;
480 arg++;
481 OPEN_LEVEL(1, (argv[arg]));
482 // Optimize case, can we close this tag already?
483 if ((arg + 1) >= argc || (!argvattr[arg + 1]
484 && (isTarget(argv[arg + 1])
485 || strcmp(argv[arg + 1],
486 "-m") == 0
487 || strcmp(argv[arg + 1],
488 "--module") ==
489 0))) {
490 printf(" />\n");
491 level1 = NULL;
492 } else {
493 printf(">\n");
494 }
495 } else if (!argvattr[arg] && argv[arg][0] == '-') {
496 char *tag;
497 CLOSE_LEVEL(2);
498 // Skip past any -
499 tag = argv[arg];
500 while (*tag == '-' && *tag)
501 tag++;
502
503 spacer = "";
504 OPEN_LEVEL(2, tag);
505 if (invert_next)
506 printf(" invert=\"1\"");
507 invert_next = 0;
508
509 // Optimize case, can we close this tag already?
510 if (!((arg + 1) < argc)
511 || (argv[arg + 1][0] == '-' /* NOT QUOTED */ )) {
512 printf(" />\n");
513 level2 = NULL;
514 } else {
515 printf(">");
516 }
517 } else { // regular data
518 char *spaces = strchr(argv[arg], ' ');
519 printf("%s", spacer);
520 if (spaces || argvattr[arg])
521 printf("&quot;");
522 // if argv[arg] contains a space, enclose in quotes
523 xmlEncode(argv[arg]);
524 if (spaces || argvattr[arg])
525 printf("&quot;");
526 spacer = " ";
527 }
528 arg++;
529 }
530 CLOSE_LEVEL(2);
531 if (level1)
532 printf("%s", leveli1);
533 CLOSE_LEVEL(1);
Amin Azez8d3eccb2006-11-13 20:23:36 +0000534}
535
536static int
Max Kellermann9ee386a2008-01-29 13:48:05 +0000537compareRules(void)
Amin Azez8d3eccb2006-11-13 20:23:36 +0000538{
539 /* compare arguments up to -j or -g for match.
540 NOTE: We don't want to combine actions if there were no criteria
541 in each rule, or rules didn't have an action
542 NOTE: Depends on arguments being in some kind of "normal" order which
543 is the case when processing the ACTUAL output of actual iptables-save
544 rather than a file merely in a compatable format */
545
Jan Engelhardt7a236f42008-03-03 12:30:41 +0100546 unsigned int old = 0;
547 unsigned int new = 0;
Amin Azez8d3eccb2006-11-13 20:23:36 +0000548
549 int compare = 0;
550
551 while (new < newargc && old < oldargc) {
552 if (isTarget(oldargv[old]) && isTarget(newargv[new])) {
Sam Liddicott8e528152007-07-17 17:02:04 +0000553 /* if oldarg was a terminating action then it makes no sense
554 * to combine further actions into the same xml */
555 if (((strcmp((oldargv[old]), "-j") == 0
556 || strcmp((oldargv[old]), "--jump") == 0)
557 && old+1 < oldargc
558 && isTerminatingTarget(oldargv[old+1]) )
559 || strcmp((oldargv[old]), "-g") == 0
560 || strcmp((oldargv[old]), "--goto") == 0 ) {
561 /* Previous rule had terminating action */
562 compare = 0;
563 } else {
564 compare = 1;
565 }
Amin Azez8d3eccb2006-11-13 20:23:36 +0000566 break;
567 }
568 // break when old!=new
569 if (strcmp(oldargv[old], newargv[new]) != 0) {
570 compare = 0;
571 break;
572 }
573
574 old++;
575 new++;
576 }
577 // We won't match unless both rules had a target.
578 // This means we don't combine target-less rules, which is good
579
580 return compare == 1;
581}
582
583/* has a nice parsed rule starting with -A */
584static void
585do_rule(char *pcnt, char *bcnt, int argc, char *argv[], int argvattr[])
586{
587 /* are these conditions the same as the previous rule?
588 * If so, skip arg straight to -j or -g */
589 if (combine && argc > 2 && !isTarget(argv[2]) && compareRules()) {
590 xmlComment("Combine action from next rule");
591 } else {
592
593 if (closeActionTag[0]) {
594 printf("%s\n", closeActionTag);
595 closeActionTag[0] = 0;
596 }
597 if (closeRuleTag[0]) {
598 printf("%s\n", closeRuleTag);
599 closeRuleTag[0] = 0;
600 }
601
602 printf(" <rule ");
603 //xmlAttrS("table",curTable); // not needed in full mode
604 //xmlAttrS("chain",argv[1]); // not needed in full mode
605 if (pcnt)
606 xmlAttrS("packet-count", pcnt);
607 if (bcnt)
608 xmlAttrS("byte-count", bcnt);
609 printf(">\n");
610
611 strncpy(closeRuleTag, " </rule>\n", IPT_TABLE_MAXNAMELEN);
612 closeRuleTag[IPT_TABLE_MAXNAMELEN] = '\0';
613
614 /* no point in writing out condition if there isn't one */
615 if (argc >= 3 && !isTarget(argv[2])) {
616 printf(" <conditions>\n");
617 do_rule_part(NULL, NULL, -1, argc, argv, argvattr);
618 printf(" </conditions>\n");
619 }
620 }
621 /* Write out the action */
622 //do_rule_part("action","arg",1,argc,argv,argvattr);
623 if (!closeActionTag[0]) {
624 printf(" <actions>\n");
625 strncpy(closeActionTag, " </actions>\n",
626 IPT_TABLE_MAXNAMELEN);
627 closeActionTag[IPT_TABLE_MAXNAMELEN] = '\0';
628 }
629 do_rule_part(NULL, NULL, 1, argc, argv, argvattr);
630}
631
632
633#ifdef IPTABLES_MULTI
634int
Lutz Jaenickee78c69c2006-12-09 13:06:04 +0000635iptables_xml_main(int argc, char *argv[])
Amin Azez8d3eccb2006-11-13 20:23:36 +0000636#else
637int
638main(int argc, char *argv[])
639#endif
640{
641 char buffer[10240];
642 int c;
643 FILE *in;
644
645 program_name = "iptables-xml";
Jan Engelhardtdacafa52009-01-27 20:56:23 +0100646 program_version = IPTABLES_VERSION;
Amin Azez8d3eccb2006-11-13 20:23:36 +0000647 line = 0;
648
649 while ((c = getopt_long(argc, argv, "cvh", options, NULL)) != -1) {
650 switch (c) {
651 case 'c':
652 combine = 1;
653 break;
654 case 'v':
655 printf("xptables-xml\n");
656 verbose = 1;
657 break;
658 case 'h':
Jan Engelhardtdacafa52009-01-27 20:56:23 +0100659 print_usage("iptables-xml", IPTABLES_VERSION);
Amin Azez8d3eccb2006-11-13 20:23:36 +0000660 break;
661 }
662 }
663
664 if (optind == argc - 1) {
665 in = fopen(argv[optind], "r");
666 if (!in) {
667 fprintf(stderr, "Can't open %s: %s", argv[optind],
668 strerror(errno));
669 exit(1);
670 }
671 } else if (optind < argc) {
672 fprintf(stderr, "Unknown arguments found on commandline");
673 exit(1);
674 } else
675 in = stdin;
676
677 printf("<iptables-rules version=\"1.0\">\n");
678
679 /* Grab standard input. */
680 while (fgets(buffer, sizeof(buffer), in)) {
681 int ret = 0;
682
683 line++;
684
685 if (buffer[0] == '\n')
686 continue;
687 else if (buffer[0] == '#') {
688 xmlComment(buffer);
689 continue;
690 }
691
692 if (verbose) {
693 printf("<!-- line %d ", line);
694 xmlCommentEscape(buffer);
695 printf(" -->\n");
696 }
697
698 if ((strcmp(buffer, "COMMIT\n") == 0) && (curTable[0])) {
699 DEBUGP("Calling commit\n");
700 closeTable();
701 ret = 1;
702 } else if ((buffer[0] == '*')) {
703 /* New table */
704 char *table;
705
706 table = strtok(buffer + 1, " \t\n");
707 DEBUGP("line %u, table '%s'\n", line, table);
708 if (!table) {
709 exit_error(PARAMETER_PROBLEM,
710 "%s: line %u table name invalid\n",
711 program_name, line);
712 exit(1);
713 }
714 openTable(table);
715
716 ret = 1;
717 } else if ((buffer[0] == ':') && (curTable[0])) {
718 /* New chain. */
719 char *policy, *chain;
720 struct ipt_counters count;
721 char *ctrs;
722
723 chain = strtok(buffer + 1, " \t\n");
724 DEBUGP("line %u, chain '%s'\n", line, chain);
725 if (!chain) {
726 exit_error(PARAMETER_PROBLEM,
727 "%s: line %u chain name invalid\n",
728 program_name, line);
729 exit(1);
730 }
731
732 DEBUGP("Creating new chain '%s'\n", chain);
733
734 policy = strtok(NULL, " \t\n");
735 DEBUGP("line %u, policy '%s'\n", line, policy);
736 if (!policy) {
737 exit_error(PARAMETER_PROBLEM,
738 "%s: line %u policy invalid\n",
739 program_name, line);
740 exit(1);
741 }
742
743 ctrs = strtok(NULL, " \t\n");
744 parse_counters(ctrs, &count);
745 saveChain(chain, policy, &count);
746
747 ret = 1;
748 } else if (curTable[0]) {
Jan Engelhardt7a236f42008-03-03 12:30:41 +0100749 unsigned int a;
Amin Azez8d3eccb2006-11-13 20:23:36 +0000750 char *ptr = buffer;
751 char *pcnt = NULL;
752 char *bcnt = NULL;
753 char *parsestart;
754 char *chain = NULL;
755
756 /* the parser */
757 char *param_start, *curchar;
758 int quote_open, quoted;
759
760 /* reset the newargv */
761 newargc = 0;
762
763 if (buffer[0] == '[') {
764 /* we have counters in our input */
765 ptr = strchr(buffer, ']');
766 if (!ptr)
767 exit_error(PARAMETER_PROBLEM,
768 "Bad line %u: need ]\n",
769 line);
770
771 pcnt = strtok(buffer + 1, ":");
772 if (!pcnt)
773 exit_error(PARAMETER_PROBLEM,
774 "Bad line %u: need :\n",
775 line);
776
777 bcnt = strtok(NULL, "]");
778 if (!bcnt)
779 exit_error(PARAMETER_PROBLEM,
780 "Bad line %u: need ]\n",
781 line);
782
783 /* start command parsing after counter */
784 parsestart = ptr + 1;
785 } else {
786 /* start command parsing at start of line */
787 parsestart = buffer;
788 }
789
790
791 /* This is a 'real' parser crafted in artist mode
792 * not hacker mode. If the author can live with that
793 * then so can everyone else */
794
795 quote_open = 0;
796 /* We need to know which args were quoted so we
797 can preserve quote */
798 quoted = 0;
799 param_start = parsestart;
800
801 for (curchar = parsestart; *curchar; curchar++) {
802 if (*curchar == '"') {
803 /* quote_open cannot be true if there
804 * was no previous character. Thus,
805 * curchar-1 has to be within bounds */
806 if (quote_open &&
807 *(curchar - 1) != '\\') {
808 quote_open = 0;
809 *curchar = ' ';
810 } else {
811 quote_open = 1;
812 quoted = 1;
813 param_start++;
814 }
815 }
816 if (*curchar == ' '
817 || *curchar == '\t' || *curchar == '\n') {
818 char param_buffer[1024];
819 int param_len = curchar - param_start;
820
821 if (quote_open)
822 continue;
823
824 if (!param_len) {
825 /* two spaces? */
826 param_start++;
827 continue;
828 }
829
830 /* end of one parameter */
831 strncpy(param_buffer, param_start,
832 param_len);
833 *(param_buffer + param_len) = '\0';
834
835 /* check if table name specified */
836 if (!strncmp(param_buffer, "-t", 3)
837 || !strncmp(param_buffer,
838 "--table", 8)) {
839 exit_error(PARAMETER_PROBLEM,
840 "Line %u seems to have a "
841 "-t table option.\n",
842 line);
843 exit(1);
844 }
845
846 add_argv(param_buffer, quoted);
847 if (newargc >= 2
848 && 0 ==
849 strcmp(newargv[newargc - 2], "-A"))
850 chain = newargv[newargc - 1];
851 quoted = 0;
852 param_start += param_len + 1;
853 } else {
854 /* regular character, skip */
855 }
856 }
857
858 DEBUGP("calling do_command(%u, argv, &%s, handle):\n",
859 newargc, curTable);
860
861 for (a = 0; a < newargc; a++)
862 DEBUGP("argv[%u]: %s\n", a, newargv[a]);
863
864 needChain(chain);// Should we explicitly look for -A
865 do_rule(pcnt, bcnt, newargc, newargv, newargvattr);
866
867 save_argv();
868 ret = 1;
869 }
870 if (!ret) {
871 fprintf(stderr, "%s: line %u failed\n",
872 program_name, line);
873 exit(1);
874 }
875 }
876 if (curTable[0]) {
877 fprintf(stderr, "%s: COMMIT expected at line %u\n",
878 program_name, line + 1);
879 exit(1);
880 }
881
882 printf("</iptables-rules>\n");
883 free_argv();
884
885 return 0;
886}