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 <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 to perform action aggregation 135 * on duplicate conditions. 136 */ 137 static void 138 save_argv(void) 139 { 140 unsigned int i; 141 142 for (i = 0; i < oldargc; i++) 143 free(oldargv[i]); 144 oldargc = newargc; 145 newargc = 0; 146 for (i = 0; i < oldargc; i++) { 147 oldargv[i] = newargv[i]; 148 newargv[i] = NULL; 149 } 150 } 151 152 /* like puts but with xml encoding */ 153 static void 154 xmlEncode(char *text) 155 { 156 while (text && *text) { 157 if ((unsigned char) (*text) >= 127) 158 printf("&#%d;", (unsigned char) (*text)); 159 else if (*text == '&') 160 printf("&"); 161 else if (*text == '<') 162 printf("<"); 163 else if (*text == '>') 164 printf(">"); 165 else if (*text == '"') 166 printf("""); 167 else 168 putchar(*text); 169 text++; 170 } 171 } 172 173 /* Output text as a comment, avoiding a double hyphen */ 174 static void 175 xmlCommentEscape(char *comment) 176 { 177 int h_count = 0; 178 179 while (comment && *comment) { 180 if (*comment == '-') { 181 h_count++; 182 if (h_count >= 2) { 183 h_count = 0; 184 putchar(' '); 185 } 186 putchar('*'); 187 } 188 /* strip trailing newline */ 189 if (*comment == '\n' && *(comment + 1) == 0); 190 else 191 putchar(*comment); 192 comment++; 193 } 194 } 195 196 static void 197 xmlComment(char *comment) 198 { 199 printf("<!-- "); 200 xmlCommentEscape(comment); 201 printf(" -->\n"); 202 } 203 204 static void 205 xmlAttrS(char *name, char *value) 206 { 207 printf("%s=\"", name); 208 xmlEncode(value); 209 printf("\" "); 210 } 211 212 static void 213 xmlAttrI(char *name, long long int num) 214 { 215 printf("%s=\"%lld\" ", name, num); 216 } 217 218 static void 219 closeChain(void) 220 { 221 if (curChain[0] == 0) 222 return; 223 224 if (closeActionTag[0]) 225 printf("%s\n", closeActionTag); 226 closeActionTag[0] = 0; 227 if (closeRuleTag[0]) 228 printf("%s\n", closeRuleTag); 229 closeRuleTag[0] = 0; 230 if (curChain[0]) 231 printf(" </chain>\n"); 232 curChain[0] = 0; 233 //lastRule[0]=0; 234 } 235 236 static void 237 openChain(char *chain, char *policy, struct xt_counters *ctr, char close) 238 { 239 closeChain(); 240 241 strncpy(curChain, chain, XT_CHAIN_MAXNAMELEN); 242 curChain[XT_CHAIN_MAXNAMELEN] = '\0'; 243 244 printf(" <chain "); 245 xmlAttrS("name", curChain); 246 if (strcmp(policy, "-") != 0) 247 xmlAttrS("policy", policy); 248 xmlAttrI("packet-count", (unsigned long long) ctr->pcnt); 249 xmlAttrI("byte-count", (unsigned long long) ctr->bcnt); 250 if (close) { 251 printf("%c", close); 252 curChain[0] = 0; 253 } 254 printf(">\n"); 255 } 256 257 static int 258 existsChain(char *chain) 259 { 260 /* open a saved chain */ 261 int c = 0; 262 263 if (0 == strcmp(curChain, chain)) 264 return 1; 265 for (c = 0; c < nextChain; c++) 266 if (chains[c].chain && strcmp(chains[c].chain, chain) == 0) 267 return 1; 268 return 0; 269 } 270 271 static void 272 needChain(char *chain) 273 { 274 /* open a saved chain */ 275 int c = 0; 276 277 if (0 == strcmp(curChain, chain)) 278 return; 279 280 for (c = 0; c < nextChain; c++) 281 if (chains[c].chain && strcmp(chains[c].chain, chain) == 0) { 282 openChain(chains[c].chain, chains[c].policy, 283 &(chains[c].count), '\0'); 284 /* And, mark it as done so we don't create 285 an empty chain at table-end time */ 286 chains[c].created = 1; 287 } 288 } 289 290 static void 291 saveChain(char *chain, char *policy, struct xt_counters *ctr) 292 { 293 if (nextChain >= maxChains) { 294 xtables_error(PARAMETER_PROBLEM, 295 "%s: line %u chain name invalid\n", 296 prog_name, line); 297 exit(1); 298 }; 299 chains[nextChain].chain = strdup(chain); 300 chains[nextChain].policy = strdup(policy); 301 chains[nextChain].count = *ctr; 302 chains[nextChain].created = 0; 303 nextChain++; 304 } 305 306 static void 307 finishChains(void) 308 { 309 int c; 310 311 for (c = 0; c < nextChain; c++) 312 if (!chains[c].created) { 313 openChain(chains[c].chain, chains[c].policy, 314 &(chains[c].count), '/'); 315 free(chains[c].chain); 316 free(chains[c].policy); 317 } 318 nextChain = 0; 319 } 320 321 static void 322 closeTable(void) 323 { 324 closeChain(); 325 finishChains(); 326 if (curTable[0]) 327 printf(" </table>\n"); 328 curTable[0] = 0; 329 } 330 331 static void 332 openTable(char *table) 333 { 334 closeTable(); 335 336 strncpy(curTable, table, XT_TABLE_MAXNAMELEN); 337 curTable[XT_TABLE_MAXNAMELEN] = '\0'; 338 339 printf(" <table "); 340 xmlAttrS("name", curTable); 341 printf(">\n"); 342 } 343 344 // is char* -j --jump -g or --goto 345 static int 346 isTarget(char *arg) 347 { 348 return ((arg) 349 && (strcmp((arg), "-j") == 0 || strcmp((arg), "--jump") == 0 350 || strcmp((arg), "-g") == 0 351 || strcmp((arg), "--goto") == 0)); 352 } 353 354 // is it a terminating target like -j ACCEPT, etc 355 // (or I guess -j SNAT in nat table, but we don't check for that yet 356 static int 357 isTerminatingTarget(char *arg) 358 { 359 return ((arg) 360 && (strcmp((arg), "ACCEPT") == 0 361 || strcmp((arg), "DROP") == 0 362 || strcmp((arg), "QUEUE") == 0 363 || strcmp((arg), "RETURN") == 0)); 364 } 365 366 // part=-1 means do conditions, part=1 means do rules, part=0 means do both 367 static void 368 do_rule_part(char *leveltag1, char *leveltag2, int part, int argc, 369 char *argv[], int argvattr[]) 370 { 371 int i; 372 int arg = 2; // ignore leading -A <chain> 373 char invert_next = 0; 374 char *spacer = ""; // space when needed to assemble arguments 375 char *level1 = NULL; 376 char *level2 = NULL; 377 char *leveli1 = " "; 378 char *leveli2 = " "; 379 380 #define CLOSE_LEVEL(LEVEL) \ 381 do { \ 382 if (level ## LEVEL) printf("</%s>\n", \ 383 (leveltag ## LEVEL)?(leveltag ## LEVEL):(level ## LEVEL)); \ 384 level ## LEVEL=NULL;\ 385 } while(0) 386 387 #define OPEN_LEVEL(LEVEL,TAG) \ 388 do {\ 389 level ## LEVEL=TAG;\ 390 if (leveltag ## LEVEL) {\ 391 printf("%s<%s ", (leveli ## LEVEL), \ 392 (leveltag ## LEVEL));\ 393 xmlAttrS("type", (TAG)); \ 394 } else printf("%s<%s ", (leveli ## LEVEL), (level ## LEVEL)); \ 395 } while(0) 396 397 if (part == 1) { /* skip */ 398 /* use argvattr to tell which arguments were quoted 399 to avoid comparing quoted arguments, like comments, to -j, */ 400 while (arg < argc && (argvattr[arg] || !isTarget(argv[arg]))) 401 arg++; 402 } 403 404 /* Before we start, if the first arg is -[^-] and not -m or -j or -g 405 * then start a dummy <match> tag for old style built-in matches. 406 * We would do this in any case, but no need if it would be empty. 407 * In the case of negation, we need to look at arg+1 408 */ 409 if (arg < argc && strcmp(argv[arg], "!") == 0) 410 i = arg + 1; 411 else 412 i = arg; 413 if (i < argc && argv[i][0] == '-' && !isTarget(argv[i]) 414 && strcmp(argv[i], "-m") != 0) { 415 OPEN_LEVEL(1, "match"); 416 printf(">\n"); 417 } 418 while (arg < argc) { 419 // If ! is followed by -* then apply to that else output as data 420 // Stop, if we need to 421 if (part == -1 && !argvattr[arg] && (isTarget(argv[arg]))) { 422 break; 423 } else if (!argvattr[arg] && strcmp(argv[arg], "!") == 0) { 424 if ((arg + 1) < argc && argv[arg + 1][0] == '-') 425 invert_next = '!'; 426 else 427 printf("%s%s", spacer, argv[arg]); 428 spacer = " "; 429 } else if (!argvattr[arg] && isTarget(argv[arg]) 430 && existsChain(argv[arg + 1]) 431 && (2 + arg >= argc)) { 432 if (!((1 + arg) < argc)) 433 // no args to -j, -m or -g, ignore & finish loop 434 break; 435 CLOSE_LEVEL(2); 436 if (level1) 437 printf("%s", leveli1); 438 CLOSE_LEVEL(1); 439 spacer = ""; 440 invert_next = 0; 441 if (strcmp(argv[arg], "-g") == 0 442 || strcmp(argv[arg], "--goto") == 0) { 443 /* goto user chain */ 444 OPEN_LEVEL(1, "goto"); 445 printf(">\n"); 446 arg++; 447 OPEN_LEVEL(2, argv[arg]); 448 printf("/>\n"); 449 level2 = NULL; 450 } else { 451 /* call user chain */ 452 OPEN_LEVEL(1, "call"); 453 printf(">\n"); 454 arg++; 455 OPEN_LEVEL(2, argv[arg]); 456 printf("/>\n"); 457 level2 = NULL; 458 } 459 } else if (!argvattr[arg] 460 && (isTarget(argv[arg]) 461 || strcmp(argv[arg], "-m") == 0 462 || strcmp(argv[arg], "--module") == 0)) { 463 if (!((1 + arg) < argc)) 464 // no args to -j, -m or -g, ignore & finish loop 465 break; 466 CLOSE_LEVEL(2); 467 if (level1) 468 printf("%s", leveli1); 469 CLOSE_LEVEL(1); 470 spacer = ""; 471 invert_next = 0; 472 arg++; 473 OPEN_LEVEL(1, (argv[arg])); 474 // Optimize case, can we close this tag already? 475 if ((arg + 1) >= argc || (!argvattr[arg + 1] 476 && (isTarget(argv[arg + 1]) 477 || strcmp(argv[arg + 1], 478 "-m") == 0 479 || strcmp(argv[arg + 1], 480 "--module") == 481 0))) { 482 printf(" />\n"); 483 level1 = NULL; 484 } else { 485 printf(">\n"); 486 } 487 } else if (!argvattr[arg] && argv[arg][0] == '-') { 488 char *tag; 489 CLOSE_LEVEL(2); 490 // Skip past any - 491 tag = argv[arg]; 492 while (*tag == '-' && *tag) 493 tag++; 494 495 spacer = ""; 496 OPEN_LEVEL(2, tag); 497 if (invert_next) 498 printf(" invert=\"1\""); 499 invert_next = 0; 500 501 // Optimize case, can we close this tag already? 502 if (!((arg + 1) < argc) 503 || (argv[arg + 1][0] == '-' /* NOT QUOTED */ )) { 504 printf(" />\n"); 505 level2 = NULL; 506 } else { 507 printf(">"); 508 } 509 } else { // regular data 510 char *spaces = strchr(argv[arg], ' '); 511 printf("%s", spacer); 512 if (spaces || argvattr[arg]) 513 printf("""); 514 // if argv[arg] contains a space, enclose in quotes 515 xmlEncode(argv[arg]); 516 if (spaces || argvattr[arg]) 517 printf("""); 518 spacer = " "; 519 } 520 arg++; 521 } 522 CLOSE_LEVEL(2); 523 if (level1) 524 printf("%s", leveli1); 525 CLOSE_LEVEL(1); 526 } 527 528 static int 529 compareRules(void) 530 { 531 /* Compare arguments up to -j or -g for match. 532 * NOTE: We don't want to combine actions if there were no criteria 533 * in each rule, or rules didn't have an action. 534 * NOTE: Depends on arguments being in some kind of "normal" order which 535 * is the case when processing the ACTUAL output of actual iptables-save 536 * rather than a file merely in a compatible format. 537 */ 538 539 unsigned int old = 0; 540 unsigned int new = 0; 541 542 int compare = 0; 543 544 while (new < newargc && old < oldargc) { 545 if (isTarget(oldargv[old]) && isTarget(newargv[new])) { 546 /* if oldarg was a terminating action then it makes no sense 547 * to combine further actions into the same xml */ 548 if (((strcmp((oldargv[old]), "-j") == 0 549 || strcmp((oldargv[old]), "--jump") == 0) 550 && old+1 < oldargc 551 && isTerminatingTarget(oldargv[old+1]) ) 552 || strcmp((oldargv[old]), "-g") == 0 553 || strcmp((oldargv[old]), "--goto") == 0 ) { 554 /* Previous rule had terminating action */ 555 compare = 0; 556 } else { 557 compare = 1; 558 } 559 break; 560 } 561 // break when old!=new 562 if (strcmp(oldargv[old], newargv[new]) != 0) { 563 compare = 0; 564 break; 565 } 566 567 old++; 568 new++; 569 } 570 // We won't match unless both rules had a target. 571 // This means we don't combine target-less rules, which is good 572 573 return compare == 1; 574 } 575 576 /* has a nice parsed rule starting with -A */ 577 static void 578 do_rule(char *pcnt, char *bcnt, int argc, char *argv[], int argvattr[]) 579 { 580 /* are these conditions the same as the previous rule? 581 * If so, skip arg straight to -j or -g */ 582 if (combine && argc > 2 && !isTarget(argv[2]) && compareRules()) { 583 xmlComment("Combine action from next rule"); 584 } else { 585 586 if (closeActionTag[0]) { 587 printf("%s\n", closeActionTag); 588 closeActionTag[0] = 0; 589 } 590 if (closeRuleTag[0]) { 591 printf("%s\n", closeRuleTag); 592 closeRuleTag[0] = 0; 593 } 594 595 printf(" <rule "); 596 //xmlAttrS("table",curTable); // not needed in full mode 597 //xmlAttrS("chain",argv[1]); // not needed in full mode 598 if (pcnt) 599 xmlAttrS("packet-count", pcnt); 600 if (bcnt) 601 xmlAttrS("byte-count", bcnt); 602 printf(">\n"); 603 604 strncpy(closeRuleTag, " </rule>\n", XT_TABLE_MAXNAMELEN); 605 closeRuleTag[XT_TABLE_MAXNAMELEN] = '\0'; 606 607 /* no point in writing out condition if there isn't one */ 608 if (argc >= 3 && !isTarget(argv[2])) { 609 printf(" <conditions>\n"); 610 do_rule_part(NULL, NULL, -1, argc, argv, argvattr); 611 printf(" </conditions>\n"); 612 } 613 } 614 /* Write out the action */ 615 //do_rule_part("action","arg",1,argc,argv,argvattr); 616 if (!closeActionTag[0]) { 617 printf(" <actions>\n"); 618 strncpy(closeActionTag, " </actions>\n", 619 XT_TABLE_MAXNAMELEN); 620 closeActionTag[XT_TABLE_MAXNAMELEN] = '\0'; 621 } 622 do_rule_part(NULL, NULL, 1, argc, argv, argvattr); 623 } 624 625 int 626 iptables_xml_main(int argc, char *argv[]) 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 xt_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 char param_buffer[1024]; 746 747 /* reset the newargv */ 748 newargc = 0; 749 750 if (buffer[0] == '[') { 751 /* we have counters in our input */ 752 ptr = strchr(buffer, ']'); 753 if (!ptr) 754 xtables_error(PARAMETER_PROBLEM, 755 "Bad line %u: need ]\n", 756 line); 757 758 pcnt = strtok(buffer + 1, ":"); 759 if (!pcnt) 760 xtables_error(PARAMETER_PROBLEM, 761 "Bad line %u: need :\n", 762 line); 763 764 bcnt = strtok(NULL, "]"); 765 if (!bcnt) 766 xtables_error(PARAMETER_PROBLEM, 767 "Bad line %u: need ]\n", 768 line); 769 770 /* start command parsing after counter */ 771 parsestart = ptr + 1; 772 } else { 773 /* start command parsing at start of line */ 774 parsestart = buffer; 775 } 776 777 778 /* This is a 'real' parser crafted in artist mode 779 * not hacker mode. If the author can live with that 780 * then so can everyone else */ 781 782 quote_open = 0; 783 /* We need to know which args were quoted so we 784 can preserve quote */ 785 quoted = 0; 786 param_start = parsestart; 787 788 for (curchar = parsestart; *curchar; curchar++) { 789 if (*curchar == '"') { 790 /* quote_open cannot be true if there 791 * was no previous character. Thus, 792 * curchar-1 has to be within bounds */ 793 if (quote_open && 794 *(curchar - 1) != '\\') { 795 quote_open = 0; 796 *curchar = ' '; 797 } else { 798 quote_open = 1; 799 quoted = 1; 800 param_start++; 801 } 802 } 803 if (*curchar == ' ' 804 || *curchar == '\t' || *curchar == '\n') { 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 if (!chain) { 851 fprintf(stderr, "%s: line %u failed - no chain found\n", 852 prog_name, line); 853 exit(1); 854 } 855 needChain(chain);// Should we explicitly look for -A 856 do_rule(pcnt, bcnt, newargc, newargv, newargvattr); 857 858 save_argv(); 859 ret = 1; 860 } 861 if (!ret) { 862 fprintf(stderr, "%s: line %u failed\n", 863 prog_name, line); 864 exit(1); 865 } 866 } 867 if (curTable[0]) { 868 fprintf(stderr, "%s: COMMIT expected at line %u\n", 869 prog_name, line + 1); 870 exit(1); 871 } 872 873 fclose(in); 874 printf("</iptables-rules>\n"); 875 free_argv(); 876 877 return 0; 878 } 879