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