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 27int line = 0; 28#endif 29 30struct 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 38static void print_usage(const char *name, const char *version) 39 __attribute__ ((noreturn)); 40 41static int verbose = 0; 42/* Whether to combine actions of sequential rules with identical conditions */ 43static int combine = 0; 44/* Keeping track of external matches and targets. */ 45static struct option options[] = { 46 {"verbose", 0, NULL, 'v'}, 47 {"combine", 0, NULL, 'c'}, 48 {"help", 0, NULL, 'h'}, 49 { .name = NULL } 50}; 51 52static void 53print_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 62static int 63parse_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 */ 79static char *newargv[255]; 80static unsigned int newargc = 0; 81 82static char *oldargv[255]; 83static unsigned int oldargc = 0; 84 85/* arg meta data, were they quoted, frinstance */ 86static int newargvattr[255]; 87 88#define IPT_CHAIN_MAXNAMELEN IPT_TABLE_MAXNAMELEN 89static char closeActionTag[IPT_TABLE_MAXNAMELEN + 1]; 90static char closeRuleTag[IPT_TABLE_MAXNAMELEN + 1]; 91static char curTable[IPT_TABLE_MAXNAMELEN + 1]; 92static char curChain[IPT_CHAIN_MAXNAMELEN + 1]; 93 94struct 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 */ 102static struct chain chains[maxChains]; 103static int nextChain = 0; 104 105/* funCtion adding one argument to newargv, updating newargc 106 * returns true if argument added, false otherwise */ 107static int 108add_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 120static void 121free_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 */ 140static void 141save_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 */ 156static void 157xmlEncode(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 */ 177static void 178xmlCommentEscape(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 199static void 200xmlComment(char *comment) 201{ 202 printf("<!-- "); 203 xmlCommentEscape(comment); 204 printf(" -->\n"); 205} 206 207static void 208xmlAttrS(char *name, char *value) 209{ 210 printf("%s=\"", name); 211 xmlEncode(value); 212 printf("\" "); 213} 214 215static void 216xmlAttrI(char *name, long long int num) 217{ 218 printf("%s=\"%lld\" ", name, num); 219} 220 221static void 222closeChain(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 239static void 240openChain(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 260static int 261existsChain(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 274static void 275needChain(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 293static void 294saveChain(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 309static void 310finishChains(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 324static void 325closeTable(void) 326{ 327 closeChain(); 328 finishChains(); 329 if (curTable[0]) 330 printf(" </table>\n"); 331 curTable[0] = 0; 332} 333 334static void 335openTable(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 348static int 349isTarget(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 359static int 360isTerminatingTarget(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 370static void 371do_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 524static int 525compareRules(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 */ 572static void 573do_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 621int 622iptables_xml_main(int argc, char *argv[]) 623#else 624int 625main(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