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