iptables-xml.c revision f643eb37e49a212d40eb060bcdfafbc366c0d616
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 26struct 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 34static void print_usage(const char *name, const char *version) 35 __attribute__ ((noreturn)); 36 37static int verbose = 0; 38/* Whether to combine actions of sequential rules with identical conditions */ 39static int combine = 0; 40/* Keeping track of external matches and targets. */ 41static struct option options[] = { 42 {"verbose", 0, NULL, 'v'}, 43 {"combine", 0, NULL, 'c'}, 44 {"help", 0, NULL, 'h'}, 45 { .name = NULL } 46}; 47 48static void 49print_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 58static int 59parse_counters(char *string, struct ipt_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 */ 75static char *newargv[255]; 76static unsigned int newargc = 0; 77 78static char *oldargv[255]; 79static unsigned int oldargc = 0; 80 81/* arg meta data, were they quoted, frinstance */ 82static int newargvattr[255]; 83 84#define IPT_CHAIN_MAXNAMELEN IPT_TABLE_MAXNAMELEN 85static char closeActionTag[IPT_TABLE_MAXNAMELEN + 1]; 86static char closeRuleTag[IPT_TABLE_MAXNAMELEN + 1]; 87static char curTable[IPT_TABLE_MAXNAMELEN + 1]; 88static char curChain[IPT_CHAIN_MAXNAMELEN + 1]; 89 90struct chain { 91 char *chain; 92 char *policy; 93 struct ipt_counters count; 94 int created; 95}; 96 97#define maxChains 10240 /* max chains per table */ 98static struct chain chains[maxChains]; 99static int nextChain = 0; 100 101/* funCtion adding one argument to newargv, updating newargc 102 * returns true if argument added, false otherwise */ 103static int 104add_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 116static void 117free_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 */ 136static void 137save_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 */ 152static void 153xmlEncode(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 */ 173static void 174xmlCommentEscape(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 195static void 196xmlComment(char *comment) 197{ 198 printf("<!-- "); 199 xmlCommentEscape(comment); 200 printf(" -->\n"); 201} 202 203static void 204xmlAttrS(char *name, char *value) 205{ 206 printf("%s=\"", name); 207 xmlEncode(value); 208 printf("\" "); 209} 210 211static void 212xmlAttrI(char *name, long long int num) 213{ 214 printf("%s=\"%lld\" ", name, num); 215} 216 217static void 218closeChain(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 235static void 236openChain(char *chain, char *policy, struct ipt_counters *ctr, char close) 237{ 238 closeChain(); 239 240 strncpy(curChain, chain, IPT_CHAIN_MAXNAMELEN); 241 curChain[IPT_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 256static int 257existsChain(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 270static void 271needChain(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 289static void 290saveChain(char *chain, char *policy, struct ipt_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 305static void 306finishChains(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 320static void 321closeTable(void) 322{ 323 closeChain(); 324 finishChains(); 325 if (curTable[0]) 326 printf(" </table>\n"); 327 curTable[0] = 0; 328} 329 330static void 331openTable(char *table) 332{ 333 closeTable(); 334 335 strncpy(curTable, table, IPT_TABLE_MAXNAMELEN); 336 curTable[IPT_TABLE_MAXNAMELEN] = '\0'; 337 338 printf(" <table "); 339 xmlAttrS("name", curTable); 340 printf(">\n"); 341} 342 343// is char* -j --jump -g or --goto 344static int 345isTarget(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 355static int 356isTerminatingTarget(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 366static void 367do_rule_part(char *leveltag1, char *leveltag2, int part, int argc, 368 char *argv[], int argvattr[]) 369{ 370 int arg = 1; // ignore leading -A 371 char invert_next = 0; 372 char *spacer = ""; // space when needed to assemble arguments 373 char *level1 = NULL; 374 char *level2 = NULL; 375 char *leveli1 = " "; 376 char *leveli2 = " "; 377 378#define CLOSE_LEVEL(LEVEL) \ 379 do { \ 380 if (level ## LEVEL) printf("</%s>\n", \ 381 (leveltag ## LEVEL)?(leveltag ## LEVEL):(level ## LEVEL)); \ 382 level ## LEVEL=NULL;\ 383 } while(0) 384 385#define OPEN_LEVEL(LEVEL,TAG) \ 386 do {\ 387 level ## LEVEL=TAG;\ 388 if (leveltag ## LEVEL) {\ 389 printf("%s<%s ", (leveli ## LEVEL), \ 390 (leveltag ## LEVEL));\ 391 xmlAttrS("type", (TAG)); \ 392 } else printf("%s<%s ", (leveli ## LEVEL), (level ## LEVEL)); \ 393 } while(0) 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 520static int 521compareRules(void) 522{ 523 /* compare arguments up to -j or -g for match. 524 NOTE: We don't want to combine actions if there were no criteria 525 in each rule, or rules didn't have an action 526 NOTE: Depends on arguments being in some kind of "normal" order which 527 is the case when processing the ACTUAL output of actual iptables-save 528 rather than a file merely in a compatable format */ 529 530 unsigned int old = 0; 531 unsigned int new = 0; 532 533 int compare = 0; 534 535 while (new < newargc && old < oldargc) { 536 if (isTarget(oldargv[old]) && isTarget(newargv[new])) { 537 /* if oldarg was a terminating action then it makes no sense 538 * to combine further actions into the same xml */ 539 if (((strcmp((oldargv[old]), "-j") == 0 540 || strcmp((oldargv[old]), "--jump") == 0) 541 && old+1 < oldargc 542 && isTerminatingTarget(oldargv[old+1]) ) 543 || strcmp((oldargv[old]), "-g") == 0 544 || strcmp((oldargv[old]), "--goto") == 0 ) { 545 /* Previous rule had terminating action */ 546 compare = 0; 547 } else { 548 compare = 1; 549 } 550 break; 551 } 552 // break when old!=new 553 if (strcmp(oldargv[old], newargv[new]) != 0) { 554 compare = 0; 555 break; 556 } 557 558 old++; 559 new++; 560 } 561 // We won't match unless both rules had a target. 562 // This means we don't combine target-less rules, which is good 563 564 return compare == 1; 565} 566 567/* has a nice parsed rule starting with -A */ 568static void 569do_rule(char *pcnt, char *bcnt, int argc, char *argv[], int argvattr[]) 570{ 571 /* are these conditions the same as the previous rule? 572 * If so, skip arg straight to -j or -g */ 573 if (combine && argc > 2 && !isTarget(argv[2]) && compareRules()) { 574 xmlComment("Combine action from next rule"); 575 } else { 576 577 if (closeActionTag[0]) { 578 printf("%s\n", closeActionTag); 579 closeActionTag[0] = 0; 580 } 581 if (closeRuleTag[0]) { 582 printf("%s\n", closeRuleTag); 583 closeRuleTag[0] = 0; 584 } 585 586 printf(" <rule "); 587 //xmlAttrS("table",curTable); // not needed in full mode 588 //xmlAttrS("chain",argv[1]); // not needed in full mode 589 if (pcnt) 590 xmlAttrS("packet-count", pcnt); 591 if (bcnt) 592 xmlAttrS("byte-count", bcnt); 593 printf(">\n"); 594 595 strncpy(closeRuleTag, " </rule>\n", IPT_TABLE_MAXNAMELEN); 596 closeRuleTag[IPT_TABLE_MAXNAMELEN] = '\0'; 597 598 /* no point in writing out condition if there isn't one */ 599 if (argc >= 3 && !isTarget(argv[2])) { 600 printf(" <conditions>\n"); 601 do_rule_part(NULL, NULL, -1, argc, argv, argvattr); 602 printf(" </conditions>\n"); 603 } 604 } 605 /* Write out the action */ 606 //do_rule_part("action","arg",1,argc,argv,argvattr); 607 if (!closeActionTag[0]) { 608 printf(" <actions>\n"); 609 strncpy(closeActionTag, " </actions>\n", 610 IPT_TABLE_MAXNAMELEN); 611 closeActionTag[IPT_TABLE_MAXNAMELEN] = '\0'; 612 } 613 do_rule_part(NULL, NULL, 1, argc, argv, argvattr); 614} 615 616int 617iptables_xml_main(int argc, char *argv[]) 618{ 619 char buffer[10240]; 620 int c; 621 FILE *in; 622 623 line = 0; 624 625 xtables_set_params(&iptables_xml_globals); 626 while ((c = getopt_long(argc, argv, "cvh", options, NULL)) != -1) { 627 switch (c) { 628 case 'c': 629 combine = 1; 630 break; 631 case 'v': 632 printf("xptables-xml\n"); 633 verbose = 1; 634 break; 635 case 'h': 636 print_usage("iptables-xml", IPTABLES_VERSION); 637 break; 638 } 639 } 640 641 if (optind == argc - 1) { 642 in = fopen(argv[optind], "re"); 643 if (!in) { 644 fprintf(stderr, "Can't open %s: %s", argv[optind], 645 strerror(errno)); 646 exit(1); 647 } 648 } else if (optind < argc) { 649 fprintf(stderr, "Unknown arguments found on commandline"); 650 exit(1); 651 } else 652 in = stdin; 653 654 printf("<iptables-rules version=\"1.0\">\n"); 655 656 /* Grab standard input. */ 657 while (fgets(buffer, sizeof(buffer), in)) { 658 int ret = 0; 659 660 line++; 661 662 if (buffer[0] == '\n') 663 continue; 664 else if (buffer[0] == '#') { 665 xmlComment(buffer); 666 continue; 667 } 668 669 if (verbose) { 670 printf("<!-- line %d ", line); 671 xmlCommentEscape(buffer); 672 printf(" -->\n"); 673 } 674 675 if ((strcmp(buffer, "COMMIT\n") == 0) && (curTable[0])) { 676 DEBUGP("Calling commit\n"); 677 closeTable(); 678 ret = 1; 679 } else if ((buffer[0] == '*')) { 680 /* New table */ 681 char *table; 682 683 table = strtok(buffer + 1, " \t\n"); 684 DEBUGP("line %u, table '%s'\n", line, table); 685 if (!table) { 686 xtables_error(PARAMETER_PROBLEM, 687 "%s: line %u table name invalid\n", 688 prog_name, line); 689 exit(1); 690 } 691 openTable(table); 692 693 ret = 1; 694 } else if ((buffer[0] == ':') && (curTable[0])) { 695 /* New chain. */ 696 char *policy, *chain; 697 struct ipt_counters count; 698 char *ctrs; 699 700 chain = strtok(buffer + 1, " \t\n"); 701 DEBUGP("line %u, chain '%s'\n", line, chain); 702 if (!chain) { 703 xtables_error(PARAMETER_PROBLEM, 704 "%s: line %u chain name invalid\n", 705 prog_name, line); 706 exit(1); 707 } 708 709 DEBUGP("Creating new chain '%s'\n", chain); 710 711 policy = strtok(NULL, " \t\n"); 712 DEBUGP("line %u, policy '%s'\n", line, policy); 713 if (!policy) { 714 xtables_error(PARAMETER_PROBLEM, 715 "%s: line %u policy invalid\n", 716 prog_name, line); 717 exit(1); 718 } 719 720 ctrs = strtok(NULL, " \t\n"); 721 parse_counters(ctrs, &count); 722 saveChain(chain, policy, &count); 723 724 ret = 1; 725 } else if (curTable[0]) { 726 unsigned int a; 727 char *ptr = buffer; 728 char *pcnt = NULL; 729 char *bcnt = NULL; 730 char *parsestart; 731 char *chain = NULL; 732 733 /* the parser */ 734 char *param_start, *curchar; 735 int quote_open, quoted; 736 737 /* reset the newargv */ 738 newargc = 0; 739 740 if (buffer[0] == '[') { 741 /* we have counters in our input */ 742 ptr = strchr(buffer, ']'); 743 if (!ptr) 744 xtables_error(PARAMETER_PROBLEM, 745 "Bad line %u: need ]\n", 746 line); 747 748 pcnt = strtok(buffer + 1, ":"); 749 if (!pcnt) 750 xtables_error(PARAMETER_PROBLEM, 751 "Bad line %u: need :\n", 752 line); 753 754 bcnt = strtok(NULL, "]"); 755 if (!bcnt) 756 xtables_error(PARAMETER_PROBLEM, 757 "Bad line %u: need ]\n", 758 line); 759 760 /* start command parsing after counter */ 761 parsestart = ptr + 1; 762 } else { 763 /* start command parsing at start of line */ 764 parsestart = buffer; 765 } 766 767 768 /* This is a 'real' parser crafted in artist mode 769 * not hacker mode. If the author can live with that 770 * then so can everyone else */ 771 772 quote_open = 0; 773 /* We need to know which args were quoted so we 774 can preserve quote */ 775 quoted = 0; 776 param_start = parsestart; 777 778 for (curchar = parsestart; *curchar; curchar++) { 779 if (*curchar == '"') { 780 /* quote_open cannot be true if there 781 * was no previous character. Thus, 782 * curchar-1 has to be within bounds */ 783 if (quote_open && 784 *(curchar - 1) != '\\') { 785 quote_open = 0; 786 *curchar = ' '; 787 } else { 788 quote_open = 1; 789 quoted = 1; 790 param_start++; 791 } 792 } 793 if (*curchar == ' ' 794 || *curchar == '\t' || *curchar == '\n') { 795 char param_buffer[1024]; 796 int param_len = curchar - param_start; 797 798 if (quote_open) 799 continue; 800 801 if (!param_len) { 802 /* two spaces? */ 803 param_start++; 804 continue; 805 } 806 807 /* end of one parameter */ 808 strncpy(param_buffer, param_start, 809 param_len); 810 *(param_buffer + param_len) = '\0'; 811 812 /* check if table name specified */ 813 if (!strncmp(param_buffer, "-t", 3) 814 || !strncmp(param_buffer, 815 "--table", 8)) { 816 xtables_error(PARAMETER_PROBLEM, 817 "Line %u seems to have a " 818 "-t table option.\n", 819 line); 820 exit(1); 821 } 822 823 add_argv(param_buffer, quoted); 824 if (newargc >= 2 825 && 0 == 826 strcmp(newargv[newargc - 2], "-A")) 827 chain = newargv[newargc - 1]; 828 quoted = 0; 829 param_start += param_len + 1; 830 } else { 831 /* regular character, skip */ 832 } 833 } 834 835 DEBUGP("calling do_command4(%u, argv, &%s, handle):\n", 836 newargc, curTable); 837 838 for (a = 0; a < newargc; a++) 839 DEBUGP("argv[%u]: %s\n", a, newargv[a]); 840 841 needChain(chain);// Should we explicitly look for -A 842 do_rule(pcnt, bcnt, newargc, newargv, newargvattr); 843 844 save_argv(); 845 ret = 1; 846 } 847 if (!ret) { 848 fprintf(stderr, "%s: line %u failed\n", 849 prog_name, line); 850 exit(1); 851 } 852 } 853 if (curTable[0]) { 854 fprintf(stderr, "%s: COMMIT expected at line %u\n", 855 prog_name, line + 1); 856 exit(1); 857 } 858 859 fclose(in); 860 printf("</iptables-rules>\n"); 861 free_argv(); 862 863 return 0; 864} 865