1 /* Code to convert iptables-save format to xml format,
2 * (C) 2006 Ufo Mechanic <azez@ufomechanic.net>
3 * based on iptables-restore (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
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"
17 #include "xtables-multi.h"
18 #include <xtables.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 #ifndef IPTABLES_MULTI
27 int line = 0;
28 #endif
29
30 struct 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
38 static void print_usage(const char *name, const char *version)
39 __attribute__ ((noreturn));
40
41 static int verbose = 0;
42 /* Whether to combine actions of sequential rules with identical conditions */
43 static int combine = 0;
44 /* Keeping track of external matches and targets. */
45 static struct option options[] = {
46 {"verbose", 0, NULL, 'v'},
47 {"combine", 0, NULL, 'c'},
48 {"help", 0, NULL, 'h'},
49 { .name = NULL }
50 };
51
52 static void
print_usage(const char * name,const char * version)53 print_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
62 static int
parse_counters(char * string,struct ipt_counters * ctr)63 parse_counters(char *string, struct ipt_counters *ctr)
64 {
65 __u64 *pcnt, *bcnt;
66
67 if (string != NULL) {
68 pcnt = &ctr->pcnt;
69 bcnt = &ctr->bcnt;
70 return (sscanf
71 (string, "[%llu:%llu]",
72 (unsigned long long *)pcnt,
73 (unsigned long long *)bcnt) == 2);
74 } else
75 return (0 == 2);
76 }
77
78 /* global new argv and argc */
79 static char *newargv[255];
80 static unsigned int newargc = 0;
81
82 static char *oldargv[255];
83 static unsigned int oldargc = 0;
84
85 /* arg meta data, were they quoted, frinstance */
86 static int newargvattr[255];
87
88 #define IPT_CHAIN_MAXNAMELEN IPT_TABLE_MAXNAMELEN
89 static char closeActionTag[IPT_TABLE_MAXNAMELEN + 1];
90 static char closeRuleTag[IPT_TABLE_MAXNAMELEN + 1];
91 static char curTable[IPT_TABLE_MAXNAMELEN + 1];
92 static char curChain[IPT_CHAIN_MAXNAMELEN + 1];
93
94 struct chain {
95 char *chain;
96 char *policy;
97 struct ipt_counters count;
98 int created;
99 };
100
101 #define maxChains 10240 /* max chains per table */
102 static struct chain chains[maxChains];
103 static int nextChain = 0;
104
105 /* funCtion adding one argument to newargv, updating newargc
106 * returns true if argument added, false otherwise */
107 static int
add_argv(char * what,int quoted)108 add_argv(char *what, int quoted)
109 {
110 DEBUGP("add_argv: %d %s\n", newargc, what);
111 if (what && newargc + 1 < ARRAY_SIZE(newargv)) {
112 newargv[newargc] = strdup(what);
113 newargvattr[newargc] = quoted;
114 newargc++;
115 return 1;
116 } else
117 return 0;
118 }
119
120 static void
free_argv(void)121 free_argv(void)
122 {
123 unsigned int i;
124
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 */
140 static void
save_argv(void)141 save_argv(void)
142 {
143 unsigned int i;
144
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 */
156 static void
xmlEncode(char * text)157 xmlEncode(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("&");
164 else if (*text == '<')
165 printf("<");
166 else if (*text == '>')
167 printf(">");
168 else if (*text == '"')
169 printf(""");
170 else
171 putchar(*text);
172 text++;
173 }
174 }
175
176 /* Output text as a comment, avoiding a double hyphen */
177 static void
xmlCommentEscape(char * comment)178 xmlCommentEscape(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
199 static void
xmlComment(char * comment)200 xmlComment(char *comment)
201 {
202 printf("<!-- ");
203 xmlCommentEscape(comment);
204 printf(" -->\n");
205 }
206
207 static void
xmlAttrS(char * name,char * value)208 xmlAttrS(char *name, char *value)
209 {
210 printf("%s=\"", name);
211 xmlEncode(value);
212 printf("\" ");
213 }
214
215 static void
xmlAttrI(char * name,long long int num)216 xmlAttrI(char *name, long long int num)
217 {
218 printf("%s=\"%lld\" ", name, num);
219 }
220
221 static void
closeChain(void)222 closeChain(void)
223 {
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
239 static void
openChain(char * chain,char * policy,struct ipt_counters * ctr,char close)240 openChain(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
260 static int
existsChain(char * chain)261 existsChain(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
274 static void
needChain(char * chain)275 needChain(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
293 static void
saveChain(char * chain,char * policy,struct ipt_counters * ctr)294 saveChain(char *chain, char *policy, struct ipt_counters *ctr)
295 {
296 if (nextChain >= maxChains) {
297 xtables_error(PARAMETER_PROBLEM,
298 "%s: line %u chain name invalid\n",
299 prog_name, line);
300 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
309 static void
finishChains(void)310 finishChains(void)
311 {
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
324 static void
closeTable(void)325 closeTable(void)
326 {
327 closeChain();
328 finishChains();
329 if (curTable[0])
330 printf(" </table>\n");
331 curTable[0] = 0;
332 }
333
334 static void
openTable(char * table)335 openTable(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
348 static int
isTarget(char * arg)349 isTarget(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
357 // 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
359 static int
isTerminatingTarget(char * arg)360 isTerminatingTarget(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
369 // part=-1 means do conditions, part=1 means do rules, part=0 means do both
370 static void
do_rule_part(char * leveltag1,char * leveltag2,int part,int argc,char * argv[],int argvattr[])371 do_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 *spacer = ""; // space when needed to assemble arguments
377 char *level1 = NULL;
378 char *level2 = NULL;
379 char *leveli1 = " ";
380 char *leveli2 = " ";
381
382 #define CLOSE_LEVEL(LEVEL) \
383 do { \
384 if (level ## LEVEL) printf("</%s>\n", \
385 (leveltag ## LEVEL)?(leveltag ## LEVEL):(level ## LEVEL)); \
386 level ## LEVEL=NULL;\
387 } while(0)
388
389 #define OPEN_LEVEL(LEVEL,TAG) \
390 do {\
391 level ## LEVEL=TAG;\
392 if (leveltag ## LEVEL) {\
393 printf("%s<%s ", (leveli ## LEVEL), \
394 (leveltag ## LEVEL));\
395 xmlAttrS("type", (TAG)); \
396 } else printf("%s<%s ", (leveli ## LEVEL), (level ## LEVEL)); \
397 } while(0)
398
399 if (part == 1) { /* skip */
400 /* use argvattr to tell which arguments were quoted
401 to avoid comparing quoted arguments, like comments, to -j, */
402 while (arg < argc && (argvattr[arg] || !isTarget(argv[arg])))
403 arg++;
404 }
405
406 /* Before we start, if the first arg is -[^-] and not -m or -j or -g
407 then start a dummy <match> tag for old style built-in matches.
408 We would do this in any case, but no need if it would be empty */
409 if (arg < argc && argv[arg][0] == '-' && !isTarget(argv[arg])
410 && strcmp(argv[arg], "-m") != 0) {
411 OPEN_LEVEL(1, "match");
412 printf(">\n");
413 }
414 while (arg < argc) {
415 // If ! is followed by -* then apply to that else output as data
416 // Stop, if we need to
417 if (part == -1 && !argvattr[arg] && (isTarget(argv[arg]))) {
418 break;
419 } else if (!argvattr[arg] && strcmp(argv[arg], "!") == 0) {
420 if ((arg + 1) < argc && argv[arg + 1][0] == '-')
421 invert_next = '!';
422 else
423 printf("%s%s", spacer, argv[arg]);
424 spacer = " ";
425 } else if (!argvattr[arg] && isTarget(argv[arg])
426 && existsChain(argv[arg + 1])
427 && (2 + arg >= argc)) {
428 if (!((1 + arg) < argc))
429 // no args to -j, -m or -g, ignore & finish loop
430 break;
431 CLOSE_LEVEL(2);
432 if (level1)
433 printf("%s", leveli1);
434 CLOSE_LEVEL(1);
435 spacer = "";
436 invert_next = 0;
437 if (strcmp(argv[arg], "-g") == 0
438 || strcmp(argv[arg], "--goto") == 0) {
439 /* goto user chain */
440 OPEN_LEVEL(1, "goto");
441 printf(">\n");
442 arg++;
443 OPEN_LEVEL(2, argv[arg]);
444 printf("/>\n");
445 level2 = NULL;
446 } else {
447 /* call user chain */
448 OPEN_LEVEL(1, "call");
449 printf(">\n");
450 arg++;
451 OPEN_LEVEL(2, argv[arg]);
452 printf("/>\n");
453 level2 = NULL;
454 }
455 } else if (!argvattr[arg]
456 && (isTarget(argv[arg])
457 || strcmp(argv[arg], "-m") == 0
458 || strcmp(argv[arg], "--module") == 0)) {
459 if (!((1 + arg) < argc))
460 // no args to -j, -m or -g, ignore & finish loop
461 break;
462 CLOSE_LEVEL(2);
463 if (level1)
464 printf("%s", leveli1);
465 CLOSE_LEVEL(1);
466 spacer = "";
467 invert_next = 0;
468 arg++;
469 OPEN_LEVEL(1, (argv[arg]));
470 // Optimize case, can we close this tag already?
471 if ((arg + 1) >= argc || (!argvattr[arg + 1]
472 && (isTarget(argv[arg + 1])
473 || strcmp(argv[arg + 1],
474 "-m") == 0
475 || strcmp(argv[arg + 1],
476 "--module") ==
477 0))) {
478 printf(" />\n");
479 level1 = NULL;
480 } else {
481 printf(">\n");
482 }
483 } else if (!argvattr[arg] && argv[arg][0] == '-') {
484 char *tag;
485 CLOSE_LEVEL(2);
486 // Skip past any -
487 tag = argv[arg];
488 while (*tag == '-' && *tag)
489 tag++;
490
491 spacer = "";
492 OPEN_LEVEL(2, tag);
493 if (invert_next)
494 printf(" invert=\"1\"");
495 invert_next = 0;
496
497 // Optimize case, can we close this tag already?
498 if (!((arg + 1) < argc)
499 || (argv[arg + 1][0] == '-' /* NOT QUOTED */ )) {
500 printf(" />\n");
501 level2 = NULL;
502 } else {
503 printf(">");
504 }
505 } else { // regular data
506 char *spaces = strchr(argv[arg], ' ');
507 printf("%s", spacer);
508 if (spaces || argvattr[arg])
509 printf(""");
510 // if argv[arg] contains a space, enclose in quotes
511 xmlEncode(argv[arg]);
512 if (spaces || argvattr[arg])
513 printf(""");
514 spacer = " ";
515 }
516 arg++;
517 }
518 CLOSE_LEVEL(2);
519 if (level1)
520 printf("%s", leveli1);
521 CLOSE_LEVEL(1);
522 }
523
524 static int
compareRules(void)525 compareRules(void)
526 {
527 /* compare arguments up to -j or -g for match.
528 NOTE: We don't want to combine actions if there were no criteria
529 in each rule, or rules didn't have an action
530 NOTE: Depends on arguments being in some kind of "normal" order which
531 is the case when processing the ACTUAL output of actual iptables-save
532 rather than a file merely in a compatable format */
533
534 unsigned int old = 0;
535 unsigned int new = 0;
536
537 int compare = 0;
538
539 while (new < newargc && old < oldargc) {
540 if (isTarget(oldargv[old]) && isTarget(newargv[new])) {
541 /* if oldarg was a terminating action then it makes no sense
542 * to combine further actions into the same xml */
543 if (((strcmp((oldargv[old]), "-j") == 0
544 || strcmp((oldargv[old]), "--jump") == 0)
545 && old+1 < oldargc
546 && isTerminatingTarget(oldargv[old+1]) )
547 || strcmp((oldargv[old]), "-g") == 0
548 || strcmp((oldargv[old]), "--goto") == 0 ) {
549 /* Previous rule had terminating action */
550 compare = 0;
551 } else {
552 compare = 1;
553 }
554 break;
555 }
556 // break when old!=new
557 if (strcmp(oldargv[old], newargv[new]) != 0) {
558 compare = 0;
559 break;
560 }
561
562 old++;
563 new++;
564 }
565 // We won't match unless both rules had a target.
566 // This means we don't combine target-less rules, which is good
567
568 return compare == 1;
569 }
570
571 /* has a nice parsed rule starting with -A */
572 static void
do_rule(char * pcnt,char * bcnt,int argc,char * argv[],int argvattr[])573 do_rule(char *pcnt, char *bcnt, int argc, char *argv[], int argvattr[])
574 {
575 /* are these conditions the same as the previous rule?
576 * If so, skip arg straight to -j or -g */
577 if (combine && argc > 2 && !isTarget(argv[2]) && compareRules()) {
578 xmlComment("Combine action from next rule");
579 } else {
580
581 if (closeActionTag[0]) {
582 printf("%s\n", closeActionTag);
583 closeActionTag[0] = 0;
584 }
585 if (closeRuleTag[0]) {
586 printf("%s\n", closeRuleTag);
587 closeRuleTag[0] = 0;
588 }
589
590 printf(" <rule ");
591 //xmlAttrS("table",curTable); // not needed in full mode
592 //xmlAttrS("chain",argv[1]); // not needed in full mode
593 if (pcnt)
594 xmlAttrS("packet-count", pcnt);
595 if (bcnt)
596 xmlAttrS("byte-count", bcnt);
597 printf(">\n");
598
599 strncpy(closeRuleTag, " </rule>\n", IPT_TABLE_MAXNAMELEN);
600 closeRuleTag[IPT_TABLE_MAXNAMELEN] = '\0';
601
602 /* no point in writing out condition if there isn't one */
603 if (argc >= 3 && !isTarget(argv[2])) {
604 printf(" <conditions>\n");
605 do_rule_part(NULL, NULL, -1, argc, argv, argvattr);
606 printf(" </conditions>\n");
607 }
608 }
609 /* Write out the action */
610 //do_rule_part("action","arg",1,argc,argv,argvattr);
611 if (!closeActionTag[0]) {
612 printf(" <actions>\n");
613 strncpy(closeActionTag, " </actions>\n",
614 IPT_TABLE_MAXNAMELEN);
615 closeActionTag[IPT_TABLE_MAXNAMELEN] = '\0';
616 }
617 do_rule_part(NULL, NULL, 1, argc, argv, argvattr);
618 }
619
620 #ifdef IPTABLES_MULTI
621 int
iptables_xml_main(int argc,char * argv[])622 iptables_xml_main(int argc, char *argv[])
623 #else
624 int
625 main(int argc, char *argv[])
626 #endif
627 {
628 char buffer[10240];
629 int c;
630 FILE *in;
631
632 line = 0;
633
634 xtables_set_params(&iptables_xml_globals);
635 while ((c = getopt_long(argc, argv, "cvh", options, NULL)) != -1) {
636 switch (c) {
637 case 'c':
638 combine = 1;
639 break;
640 case 'v':
641 printf("xptables-xml\n");
642 verbose = 1;
643 break;
644 case 'h':
645 print_usage("iptables-xml", IPTABLES_VERSION);
646 break;
647 }
648 }
649
650 if (optind == argc - 1) {
651 in = fopen(argv[optind], "re");
652 if (!in) {
653 fprintf(stderr, "Can't open %s: %s", argv[optind],
654 strerror(errno));
655 exit(1);
656 }
657 } else if (optind < argc) {
658 fprintf(stderr, "Unknown arguments found on commandline");
659 exit(1);
660 } else
661 in = stdin;
662
663 printf("<iptables-rules version=\"1.0\">\n");
664
665 /* Grab standard input. */
666 while (fgets(buffer, sizeof(buffer), in)) {
667 int ret = 0;
668
669 line++;
670
671 if (buffer[0] == '\n')
672 continue;
673 else if (buffer[0] == '#') {
674 xmlComment(buffer);
675 continue;
676 }
677
678 if (verbose) {
679 printf("<!-- line %d ", line);
680 xmlCommentEscape(buffer);
681 printf(" -->\n");
682 }
683
684 if ((strcmp(buffer, "COMMIT\n") == 0) && (curTable[0])) {
685 DEBUGP("Calling commit\n");
686 closeTable();
687 ret = 1;
688 } else if ((buffer[0] == '*')) {
689 /* New table */
690 char *table;
691
692 table = strtok(buffer + 1, " \t\n");
693 DEBUGP("line %u, table '%s'\n", line, table);
694 if (!table) {
695 xtables_error(PARAMETER_PROBLEM,
696 "%s: line %u table name invalid\n",
697 prog_name, line);
698 exit(1);
699 }
700 openTable(table);
701
702 ret = 1;
703 } else if ((buffer[0] == ':') && (curTable[0])) {
704 /* New chain. */
705 char *policy, *chain;
706 struct ipt_counters count;
707 char *ctrs;
708
709 chain = strtok(buffer + 1, " \t\n");
710 DEBUGP("line %u, chain '%s'\n", line, chain);
711 if (!chain) {
712 xtables_error(PARAMETER_PROBLEM,
713 "%s: line %u chain name invalid\n",
714 prog_name, line);
715 exit(1);
716 }
717
718 DEBUGP("Creating new chain '%s'\n", chain);
719
720 policy = strtok(NULL, " \t\n");
721 DEBUGP("line %u, policy '%s'\n", line, policy);
722 if (!policy) {
723 xtables_error(PARAMETER_PROBLEM,
724 "%s: line %u policy invalid\n",
725 prog_name, line);
726 exit(1);
727 }
728
729 ctrs = strtok(NULL, " \t\n");
730 parse_counters(ctrs, &count);
731 saveChain(chain, policy, &count);
732
733 ret = 1;
734 } else if (curTable[0]) {
735 unsigned int a;
736 char *ptr = buffer;
737 char *pcnt = NULL;
738 char *bcnt = NULL;
739 char *parsestart;
740 char *chain = NULL;
741
742 /* the parser */
743 char *param_start, *curchar;
744 int quote_open, quoted;
745
746 /* reset the newargv */
747 newargc = 0;
748
749 if (buffer[0] == '[') {
750 /* we have counters in our input */
751 ptr = strchr(buffer, ']');
752 if (!ptr)
753 xtables_error(PARAMETER_PROBLEM,
754 "Bad line %u: need ]\n",
755 line);
756
757 pcnt = strtok(buffer + 1, ":");
758 if (!pcnt)
759 xtables_error(PARAMETER_PROBLEM,
760 "Bad line %u: need :\n",
761 line);
762
763 bcnt = strtok(NULL, "]");
764 if (!bcnt)
765 xtables_error(PARAMETER_PROBLEM,
766 "Bad line %u: need ]\n",
767 line);
768
769 /* start command parsing after counter */
770 parsestart = ptr + 1;
771 } else {
772 /* start command parsing at start of line */
773 parsestart = buffer;
774 }
775
776
777 /* This is a 'real' parser crafted in artist mode
778 * not hacker mode. If the author can live with that
779 * then so can everyone else */
780
781 quote_open = 0;
782 /* We need to know which args were quoted so we
783 can preserve quote */
784 quoted = 0;
785 param_start = parsestart;
786
787 for (curchar = parsestart; *curchar; curchar++) {
788 if (*curchar == '"') {
789 /* quote_open cannot be true if there
790 * was no previous character. Thus,
791 * curchar-1 has to be within bounds */
792 if (quote_open &&
793 *(curchar - 1) != '\\') {
794 quote_open = 0;
795 *curchar = ' ';
796 } else {
797 quote_open = 1;
798 quoted = 1;
799 param_start++;
800 }
801 }
802 if (*curchar == ' '
803 || *curchar == '\t' || *curchar == '\n') {
804 char param_buffer[1024];
805 int param_len = curchar - param_start;
806
807 if (quote_open)
808 continue;
809
810 if (!param_len) {
811 /* two spaces? */
812 param_start++;
813 continue;
814 }
815
816 /* end of one parameter */
817 strncpy(param_buffer, param_start,
818 param_len);
819 *(param_buffer + param_len) = '\0';
820
821 /* check if table name specified */
822 if (!strncmp(param_buffer, "-t", 3)
823 || !strncmp(param_buffer,
824 "--table", 8)) {
825 xtables_error(PARAMETER_PROBLEM,
826 "Line %u seems to have a "
827 "-t table option.\n",
828 line);
829 exit(1);
830 }
831
832 add_argv(param_buffer, quoted);
833 if (newargc >= 2
834 && 0 ==
835 strcmp(newargv[newargc - 2], "-A"))
836 chain = newargv[newargc - 1];
837 quoted = 0;
838 param_start += param_len + 1;
839 } else {
840 /* regular character, skip */
841 }
842 }
843
844 DEBUGP("calling do_command4(%u, argv, &%s, handle):\n",
845 newargc, curTable);
846
847 for (a = 0; a < newargc; a++)
848 DEBUGP("argv[%u]: %s\n", a, newargv[a]);
849
850 needChain(chain);// Should we explicitly look for -A
851 do_rule(pcnt, bcnt, newargc, newargv, newargvattr);
852
853 save_argv();
854 ret = 1;
855 }
856 if (!ret) {
857 fprintf(stderr, "%s: line %u failed\n",
858 prog_name, line);
859 exit(1);
860 }
861 }
862 if (curTable[0]) {
863 fprintf(stderr, "%s: COMMIT expected at line %u\n",
864 prog_name, line + 1);
865 exit(1);
866 }
867
868 if (in != NULL)
869 fclose(in);
870 printf("</iptables-rules>\n");
871 free_argv();
872
873 return 0;
874 }
875