~csurbhi/ubuntu/maverick/iptables/iptable-fix.600195

« back to all changes in this revision

Viewing changes to iptables-xml.c

  • Committer: Bazaar Package Importer
  • Author(s): Soren Hansen
  • Date: 2008-06-24 15:06:04 UTC
  • mfrom: (5.1.4 upstream)
  • Revision ID: james.westby@ubuntu.com-20080624150604-5t7r1o1kxq0ycz81
Tags: 1.4.0-4ubuntu1
* Merge from debian unstable, remaining changes:
  - Took references to 2.4 kernel out of doc-base control files (Jordan
    Mantha, Malone #25972) (patches/all/091-fix-2.4-references.patch)
  - Use linux-libc-dev instead of local copy of kernel-headers.

Show diffs side-by-side

added added

removed removed

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