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