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