iptables-xml.c 20 KB

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