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