~cyphermox/ubuntu/natty/connman/release-0.64

« back to all changes in this revision

Viewing changes to tools/iptables-test.c

  • Committer: Mathieu Trudel-Lapierre
  • Date: 2010-11-30 15:51:10 UTC
  • mfrom: (1.1.13 upstream)
  • Revision ID: mathieu.trudel-lapierre@canonical.com-20101130155110-32g0usyc4jbl131x
New upstream release 0.64.

Show diffs side-by-side

added added

removed removed

Lines of Context:
18
18
 *
19
19
 */
20
20
 
 
21
#include <getopt.h>
21
22
#include <stdlib.h>
22
23
#include <stdio.h>
23
24
#include <string.h>
24
25
#include <unistd.h>
25
26
#include <sys/errno.h>
26
 
#include <libiptc/libiptc.h>
27
 
#include <libiptc/libip6tc.h>
 
27
#include <sys/socket.h>
28
28
#include <xtables.h>
29
29
 
30
 
#include <linux/netfilter/x_tables.h>
31
 
#include <linux/netfilter/xt_quota.h>
32
 
 
33
 
static void print_match(const struct ipt_entry *e)
34
 
{
 
30
#include <linux/netfilter_ipv4/ip_tables.h>
 
31
 
 
32
#include <glib.h>
 
33
 
 
34
static const char *hooknames[] = {
 
35
        [NF_IP_PRE_ROUTING]     = "PREROUTING",
 
36
        [NF_IP_LOCAL_IN]        = "INPUT",
 
37
        [NF_IP_FORWARD]         = "FORWARD",
 
38
        [NF_IP_LOCAL_OUT]       = "OUTPUT",
 
39
        [NF_IP_POST_ROUTING]    = "POSTROUTING",
 
40
};
 
41
 
 
42
#define LABEL_ACCEPT  "ACCEPT"
 
43
#define LABEL_DROP    "DROP"
 
44
#define LABEL_QUEUE   "QUEUE"
 
45
#define LABEL_RETURN  "RETURN"
 
46
 
 
47
/* fn returns 0 to continue iteration */
 
48
#define _XT_ENTRY_ITERATE_CONTINUE(type, entries, size, n, fn, args...) \
 
49
({                                                              \
 
50
        unsigned int __i;                                       \
 
51
        int __n;                                                \
 
52
        int __ret = 0;                                          \
 
53
        type *__entry;                                          \
 
54
                                                                \
 
55
        for (__i = 0, __n = 0; __i < (size);                    \
 
56
             __i += __entry->next_offset, __n++) {              \
 
57
                __entry = (void *)(entries) + __i;              \
 
58
                if (__n < n)                                    \
 
59
                        continue;                               \
 
60
                                                                \
 
61
                __ret = fn(__entry,  ## args);                  \
 
62
                if (__ret != 0)                                 \
 
63
                        break;                                  \
 
64
        }                                                       \
 
65
        __ret;                                                  \
 
66
})
 
67
 
 
68
/* fn returns 0 to continue iteration */
 
69
#define _XT_ENTRY_ITERATE(type, entries, size, fn, args...) \
 
70
        _XT_ENTRY_ITERATE_CONTINUE(type, entries, size, 0, fn, args)
 
71
 
 
72
#define ENTRY_ITERATE(entries, size, fn, args...) \
 
73
        _XT_ENTRY_ITERATE(struct ipt_entry, entries, size, fn, ## args)
 
74
 
 
75
#define MIN_ALIGN (__alignof__(struct ipt_entry))
 
76
 
 
77
#define ALIGN(s) (((s) + ((MIN_ALIGN)-1)) & ~((MIN_ALIGN)-1))
 
78
 
 
79
struct error_target {
 
80
        struct xt_entry_target t;
 
81
        char error[IPT_TABLE_MAXNAMELEN];
 
82
};
 
83
 
 
84
struct connman_iptables_entry {
 
85
        int offset;
 
86
        int builtin;
 
87
 
 
88
        struct ipt_entry *entry;
 
89
};
 
90
 
 
91
struct connman_iptables {
 
92
        int ipt_sock;
 
93
 
 
94
        struct ipt_getinfo *info;
 
95
        struct ipt_get_entries *blob_entries;
 
96
 
 
97
        unsigned int num_entries;
 
98
        unsigned int old_entries;
 
99
        unsigned int size;
 
100
 
 
101
        unsigned int underflow[NF_INET_NUMHOOKS];
 
102
        unsigned int hook_entry[NF_INET_NUMHOOKS];
 
103
 
 
104
        GList *entries;
 
105
};
 
106
 
 
107
 
 
108
static struct ipt_entry *get_entry(struct connman_iptables *table,
 
109
                                        unsigned int offset)
 
110
{
 
111
        return (struct ipt_entry *)((char *)table->blob_entries->entrytable +
 
112
                                                                        offset);
 
113
}
 
114
 
 
115
static int is_hook_entry(struct connman_iptables *table,
 
116
                                struct ipt_entry *entry)
 
117
{
 
118
        unsigned int i;
 
119
 
 
120
        for (i = 0; i < NF_INET_NUMHOOKS; i++) {
 
121
                if ((table->info->valid_hooks & (1 << i))
 
122
                && get_entry(table, table->info->hook_entry[i]) == entry)
 
123
                        return i;
 
124
        }
 
125
 
 
126
        return -1;
 
127
}
 
128
 
 
129
static unsigned long entry_to_offset(struct connman_iptables *table,
 
130
                                        struct ipt_entry *entry)
 
131
{
 
132
        return (void *)entry - (void *)table->blob_entries->entrytable;
 
133
}
 
134
 
 
135
static int target_to_verdict(char *target_name)
 
136
{
 
137
        if (!strcmp(target_name, LABEL_ACCEPT))
 
138
                return -NF_ACCEPT - 1;
 
139
 
 
140
        if (!strcmp(target_name, LABEL_DROP))
 
141
                return -NF_DROP - 1;
 
142
 
 
143
        if (!strcmp(target_name, LABEL_QUEUE))
 
144
                return -NF_QUEUE - 1;
 
145
 
 
146
        if (!strcmp(target_name, LABEL_RETURN))
 
147
                return XT_RETURN;
 
148
 
 
149
        return 0;
 
150
}
 
151
 
 
152
static gboolean is_builtin_target(char *target_name)
 
153
{
 
154
        if (!strcmp(target_name, LABEL_ACCEPT) ||
 
155
                !strcmp(target_name, LABEL_DROP) ||
 
156
                !strcmp(target_name, LABEL_QUEUE) ||
 
157
                !strcmp(target_name, LABEL_RETURN))
 
158
                return TRUE;
 
159
 
 
160
        return FALSE;
 
161
}
 
162
 
 
163
static gboolean is_jump(struct connman_iptables_entry *e)
 
164
{
 
165
        struct xt_entry_target *target;
 
166
 
 
167
        target = ipt_get_target(e->entry);
 
168
 
 
169
        if (!strcmp(target->u.user.name, IPT_STANDARD_TARGET)) {
 
170
                struct xt_standard_target *t;
 
171
 
 
172
                t = (struct xt_standard_target *)target;
 
173
 
 
174
                switch (t->verdict) {
 
175
                case XT_RETURN:
 
176
                case -NF_ACCEPT - 1:
 
177
                case -NF_DROP - 1:
 
178
                case -NF_QUEUE - 1:
 
179
                case -NF_STOP - 1:
 
180
                        return false;
 
181
 
 
182
                default:
 
183
                        return true;
 
184
                }
 
185
        }
 
186
 
 
187
        return false;
 
188
}
 
189
 
 
190
static gboolean is_chain(struct connman_iptables *table,
 
191
                                struct connman_iptables_entry *e)
 
192
{
 
193
        struct ipt_entry *entry;
 
194
        struct xt_entry_target *target;
 
195
 
 
196
        entry = e->entry;
 
197
        if (e->builtin >= 0)
 
198
                return TRUE;
 
199
 
 
200
        target = ipt_get_target(entry);
 
201
        if (!strcmp(target->u.user.name, IPT_ERROR_TARGET))
 
202
                return TRUE;
 
203
 
 
204
        return FALSE;
 
205
}
 
206
 
 
207
static GList *find_chain_head(struct connman_iptables *table,
 
208
                                char *chain_name)
 
209
{
 
210
        GList *list;
 
211
        struct connman_iptables_entry *head;
 
212
        struct ipt_entry *entry;
 
213
        struct xt_entry_target *target;
 
214
        int builtin;
 
215
 
 
216
        for (list = table->entries; list; list = list->next) {
 
217
                head = list->data;
 
218
                entry = head->entry;
 
219
 
 
220
                /* Buit-in chain */
 
221
                builtin = head->builtin;
 
222
                if (builtin >= 0 && !strcmp(hooknames[builtin], chain_name))
 
223
                        break;
 
224
 
 
225
                /* User defined chain */
 
226
                target = ipt_get_target(entry);
 
227
                if (!strcmp(target->u.user.name, IPT_ERROR_TARGET) &&
 
228
                    !strcmp((char *)target->data, chain_name))
 
229
                        break;
 
230
        }
 
231
 
 
232
        return list;
 
233
}
 
234
 
 
235
static GList *find_chain_tail(struct connman_iptables *table,
 
236
                                char *chain_name)
 
237
{
 
238
        GList *chain_head, *list;
 
239
        struct connman_iptables_entry *head, *tail;
 
240
        struct ipt_entry *entry;
 
241
        struct xt_entry_target *target;
 
242
        int builtin;
 
243
 
 
244
        /* First we look for the head */
 
245
        for (list = table->entries; list; list = list->next) {
 
246
                head = list->data;
 
247
                entry = head->entry;
 
248
 
 
249
                /* Buit-in chain */
 
250
                builtin = head->builtin;
 
251
                if (builtin >= 0 && !strcmp(hooknames[builtin], chain_name))
 
252
                        break;
 
253
 
 
254
                /* User defined chain */
 
255
                target = ipt_get_target(entry);
 
256
                if (!strcmp(target->u.user.name, IPT_ERROR_TARGET) &&
 
257
                    !strcmp((char *)target->data, chain_name))
 
258
                        break;
 
259
        }
 
260
 
 
261
        if (list == NULL)
 
262
                return NULL;
 
263
 
 
264
        chain_head = list;
 
265
 
 
266
        /* Then we look for the next chain */
 
267
        for (list = chain_head->next; list; list = list->next) {
 
268
                tail = list->data;
 
269
                entry = tail->entry;
 
270
 
 
271
                if (is_chain(table, tail))
 
272
                        return list;
 
273
        }
 
274
 
 
275
        /* Nothing found, we return the table end */
 
276
        return g_list_last(table->entries);
 
277
}
 
278
 
 
279
static void update_offsets(struct connman_iptables *table)
 
280
{
 
281
        GList *list, *prev;
 
282
        struct connman_iptables_entry *entry, *prev_entry;
 
283
 
 
284
        for (list = table->entries; list; list = list->next) {
 
285
                entry = list->data;
 
286
 
 
287
                if (list == table->entries) {
 
288
                        entry->offset = 0;
 
289
 
 
290
                        continue;
 
291
                }
 
292
 
 
293
                prev = list->prev;
 
294
                prev_entry = prev->data;
 
295
 
 
296
                entry->offset = prev_entry->offset +
 
297
                                        prev_entry->entry->next_offset;
 
298
        }
 
299
}
 
300
 
 
301
static int connman_add_entry(struct connman_iptables *table,
 
302
                                struct ipt_entry *entry, GList *before,
 
303
                                        int builtin)
 
304
{
 
305
        GList *list;
 
306
        struct connman_iptables_entry *e, *tmp, *entry_before;
 
307
        struct xt_standard_target *t;
 
308
 
 
309
        if (table == NULL)
 
310
                return -1;
 
311
 
 
312
        e = g_try_malloc0(sizeof(struct connman_iptables_entry));
 
313
        if (e == NULL)
 
314
                return -1;
 
315
 
 
316
        e->entry = entry;
 
317
        e->builtin = builtin;
 
318
 
 
319
        table->entries = g_list_insert_before(table->entries, before, e);
 
320
        table->num_entries++;
 
321
        table->size += entry->next_offset;
 
322
 
 
323
        if (before == NULL) {
 
324
                e->offset = table->size - entry->next_offset;
 
325
 
 
326
                return 0;
 
327
        }
 
328
 
 
329
        entry_before = before->data;
 
330
 
 
331
        /*
 
332
         * We've just insterted a new entry. All references before it
 
333
         * should be bumped accordingly.
 
334
         */
 
335
        for (list = table->entries; list != before; list = list->next) {
 
336
                tmp = list->data;
 
337
 
 
338
                if (!is_jump(tmp))
 
339
                        continue;
 
340
 
 
341
                t = (struct xt_standard_target *)ipt_get_target(tmp->entry);
 
342
 
 
343
                if (t->verdict >= entry_before->offset)
 
344
                        t->verdict += entry->next_offset;
 
345
        }
 
346
 
 
347
        update_offsets(table);
 
348
 
 
349
        return 0;
 
350
}
 
351
 
 
352
static int connman_iptables_flush_chain(struct connman_iptables *table,
 
353
                                                char *name)
 
354
{
 
355
        GList *chain_head, *chain_tail, *list, *next;
 
356
        struct connman_iptables_entry *entry;
 
357
        int builtin, removed = 0;
 
358
 
 
359
        chain_head = find_chain_head(table, name);
 
360
        if (chain_head == NULL)
 
361
                return -EINVAL;
 
362
 
 
363
        chain_tail = find_chain_tail(table, name);
 
364
        if (chain_tail == NULL)
 
365
                return -EINVAL;
 
366
 
 
367
        entry = chain_head->data;
 
368
        builtin = entry->builtin;
 
369
 
 
370
        if (builtin >= 0)
 
371
                list = chain_head;
 
372
        else
 
373
                list = chain_head->next;
 
374
 
 
375
        if (list == chain_tail->prev)
 
376
                return 0;
 
377
 
 
378
        while (list != chain_tail->prev) {
 
379
                entry = list->data;
 
380
                next = g_list_next(list);
 
381
 
 
382
                table->num_entries--;
 
383
                table->size -= entry->entry->next_offset;
 
384
                removed += entry->entry->next_offset;
 
385
 
 
386
                table->entries = g_list_remove(table->entries, list->data);
 
387
 
 
388
                list = next;
 
389
        }
 
390
 
 
391
        if (builtin >= 0) {
 
392
                struct connman_iptables_entry *e;
 
393
 
 
394
                entry = list->data;
 
395
 
 
396
                entry->builtin = builtin;
 
397
 
 
398
                table->underflow[builtin] -= removed;
 
399
 
 
400
                for (list = chain_tail; list; list = list->next) {
 
401
                        e = list->data;
 
402
 
 
403
                        builtin = e->builtin;
 
404
                        if (builtin < 0)
 
405
                                continue;
 
406
 
 
407
                        table->hook_entry[builtin] -= removed;
 
408
                        table->underflow[builtin] -= removed;
 
409
                }
 
410
        }
 
411
 
 
412
        update_offsets(table);
 
413
 
 
414
        return 0;
 
415
}
 
416
 
 
417
static int connman_iptables_delete_chain(struct connman_iptables *table,
 
418
                                                char *name)
 
419
{
 
420
        GList *chain_head, *chain_tail, *list, *next;
 
421
        struct connman_iptables_entry *entry;
 
422
 
 
423
        chain_head = find_chain_head(table, name);
 
424
        if (chain_head == NULL)
 
425
                return -EINVAL;
 
426
 
 
427
        chain_tail = find_chain_tail(table, name);
 
428
        if (chain_tail == NULL)
 
429
                return -EINVAL;
 
430
 
 
431
        list = chain_head;
 
432
 
 
433
        while (list != chain_tail) {
 
434
                entry = list->data;
 
435
                next = g_list_next(list);
 
436
 
 
437
                table->num_entries--;
 
438
                table->size -= entry->entry->next_offset;
 
439
 
 
440
                table->entries = g_list_remove(table->entries, list->data);
 
441
 
 
442
                list = next;
 
443
        }
 
444
 
 
445
        update_offsets(table);
 
446
 
 
447
        return 0;
 
448
}
 
449
 
 
450
static int connman_iptables_add_chain(struct connman_iptables *table,
 
451
                                        char *name)
 
452
{
 
453
        GList *last;
 
454
        struct ipt_entry *entry_head;
 
455
        struct ipt_entry *entry_return;
 
456
        struct error_target *error;
 
457
        struct ipt_standard_target *standard;
 
458
        u_int16_t entry_head_size, entry_return_size;
 
459
 
 
460
        last = g_list_last(table->entries);
 
461
 
 
462
        /*
 
463
         * An empty chain is composed of:
 
464
         * - A head entry, with no match and an error target.
 
465
         *   The error target data is the chain name.
 
466
         * - A tail entry, with no match and a standard target.
 
467
         *   The standard target verdict is XT_RETURN (return to the
 
468
         *   caller).
 
469
         */
 
470
 
 
471
        /* head entry */
 
472
        entry_head_size = sizeof(struct ipt_entry) +
 
473
                                sizeof(struct error_target);
 
474
        entry_head = g_try_malloc0(entry_head_size);
 
475
        if (entry_head == NULL)
 
476
                goto err;
 
477
 
 
478
        memset(entry_head, 0, entry_head_size);
 
479
 
 
480
        entry_head->target_offset = sizeof(struct ipt_entry);
 
481
        entry_head->next_offset = entry_head_size;
 
482
 
 
483
        error = (struct error_target *) entry_head->elems;
 
484
        strcpy(error->t.u.user.name, IPT_ERROR_TARGET);
 
485
        error->t.u.user.target_size = ALIGN(sizeof(struct error_target));
 
486
        strcpy(error->error, name);
 
487
 
 
488
        if (connman_add_entry(table, entry_head, last, -1) < 0)
 
489
                goto err;
 
490
 
 
491
        /* tail entry */
 
492
        entry_return_size = sizeof(struct ipt_entry) +
 
493
                                sizeof(struct ipt_standard_target);
 
494
        entry_return = g_try_malloc0(entry_return_size);
 
495
        if (entry_return == NULL)
 
496
                goto err;
 
497
 
 
498
        memset(entry_return, 0, entry_return_size);
 
499
 
 
500
        entry_return->target_offset = sizeof(struct ipt_entry);
 
501
        entry_return->next_offset = entry_return_size;
 
502
 
 
503
        standard = (struct ipt_standard_target *) entry_return->elems;
 
504
        standard->target.u.user.target_size =
 
505
                                ALIGN(sizeof(struct ipt_standard_target));
 
506
        standard->verdict = XT_RETURN;
 
507
 
 
508
        if (connman_add_entry(table, entry_return, last, -1) < 0)
 
509
                goto err;
 
510
 
 
511
        return 0;
 
512
 
 
513
err:
 
514
        g_free(entry_head);
 
515
        g_free(entry_return);
 
516
 
 
517
        return -ENOMEM;
 
518
}
 
519
 
 
520
static struct ipt_entry *
 
521
new_rule(struct connman_iptables *table,
 
522
                char *target_name, struct xtables_target *xt_t,
 
523
                char *match_name, struct xtables_match *xt_m)
 
524
{
 
525
        struct ipt_entry *new_entry;
 
526
        size_t match_size, target_size;
 
527
        int is_builtin = is_builtin_target(target_name);
 
528
 
 
529
        if (xt_m)
 
530
                match_size = xt_m->m->u.match_size;
 
531
        else
 
532
                match_size = 0;
 
533
 
 
534
        if (xt_t)
 
535
                target_size = ALIGN(xt_t->t->u.target_size);
 
536
        else
 
537
                target_size = ALIGN(sizeof(struct xt_standard_target));
 
538
 
 
539
        new_entry = g_try_malloc0(sizeof(struct ipt_entry) + target_size +
 
540
                                                                match_size);
 
541
        if (new_entry == NULL)
 
542
                return NULL;
 
543
 
 
544
        new_entry->target_offset = sizeof(struct ipt_entry) + match_size;
 
545
        new_entry->next_offset = sizeof(struct ipt_entry) + target_size +
 
546
                                                                match_size;
 
547
        if (xt_m) {
 
548
                struct xt_entry_match *entry_match;
 
549
 
 
550
                entry_match = (struct xt_entry_match *)new_entry->elems;
 
551
                memcpy(entry_match, xt_m->m, match_size);
 
552
        }
 
553
 
 
554
        if (xt_t) {
 
555
                struct xt_entry_target *entry_target;
 
556
 
 
557
                if (is_builtin) {
 
558
                        struct xt_standard_target *target;
 
559
 
 
560
                        target = (struct xt_standard_target *)(xt_t->t);
 
561
                        strcpy(target->target.u.user.name, IPT_STANDARD_TARGET);
 
562
                        target->verdict = target_to_verdict(target_name);
 
563
                }
 
564
 
 
565
                entry_target = ipt_get_target(new_entry);
 
566
                memcpy(entry_target, xt_t->t, target_size);
 
567
        } else {
 
568
                struct connman_iptables_entry *target_rule;
 
569
                struct xt_standard_target *target;
 
570
                GList *chain_head;
 
571
 
 
572
                /*
 
573
                 * This is a user defined target, i.e. a chain jump.
 
574
                 * We search for the chain head, and the target verdict
 
575
                 * is the first rule's offset on this chain.
 
576
                 * The offset is from the beginning of the table.
 
577
                 */
 
578
 
 
579
                chain_head = find_chain_head(table, target_name);
 
580
                if (chain_head == NULL || chain_head->next == NULL) {
 
581
                        g_free(new_entry);
 
582
                        return NULL;
 
583
                }
 
584
 
 
585
                target_rule = chain_head->next->data;
 
586
 
 
587
                target = (struct xt_standard_target *)ipt_get_target(new_entry);
 
588
                strcpy(target->target.u.user.name, IPT_STANDARD_TARGET);
 
589
                target->target.u.user.target_size = target_size;
 
590
                target->verdict = target_rule->offset;
 
591
        }
 
592
 
 
593
        return new_entry;
 
594
}
 
595
 
 
596
static void update_hooks(struct connman_iptables *table, GList *chain_head, struct ipt_entry *entry)
 
597
{
 
598
        GList *list;
 
599
        struct connman_iptables_entry *head, *e;
 
600
        int builtin;
 
601
 
 
602
        if (chain_head == NULL)
 
603
                return;
 
604
 
 
605
        head = chain_head->data;
 
606
 
 
607
        builtin = head->builtin;
 
608
        if (builtin < 0)
 
609
                return;
 
610
 
 
611
        table->underflow[builtin] += entry->next_offset;
 
612
 
 
613
        for (list = chain_head->next; list; list = list->next) {
 
614
                e = list->data;
 
615
 
 
616
                builtin = e->builtin;
 
617
                if (builtin < 0)
 
618
                        continue;
 
619
 
 
620
                table->hook_entry[builtin] += entry->next_offset;
 
621
                table->underflow[builtin] += entry->next_offset;
 
622
        }
 
623
}
 
624
 
 
625
static int
 
626
connman_iptables_add_rule(struct connman_iptables *table, char *chain_name,
 
627
                                char *target_name, struct xtables_target *xt_t,
 
628
                                char *match_name, struct xtables_match *xt_m)
 
629
{
 
630
        GList *chain_tail, *chain_head;
 
631
        struct ipt_entry *new_entry;
 
632
        struct connman_iptables_entry *head;
 
633
        int builtin = -1;
 
634
 
 
635
        chain_head = find_chain_head(table, chain_name);
 
636
        if (chain_head == NULL)
 
637
                return -EINVAL;
 
638
 
 
639
        chain_tail = find_chain_tail(table, chain_name);
 
640
        if (chain_tail == NULL)
 
641
                return -EINVAL;
 
642
 
 
643
        new_entry = new_rule(table,
 
644
                                target_name, xt_t,
 
645
                                match_name, xt_m);
 
646
        if (new_entry == NULL)
 
647
                return -EINVAL;
 
648
 
 
649
        update_hooks(table, chain_head, new_entry);
 
650
 
 
651
        /*
 
652
         * If the chain is builtin, and does not have any rule,
 
653
         * then the one that we're inserting is becoming the head
 
654
         * and thus needs the builtin flag.
 
655
         */
 
656
        head = chain_head->data;
 
657
        if (head->builtin < 0)
 
658
                builtin = -1;
 
659
        else if (chain_head == chain_tail->prev) {
 
660
                builtin = head->builtin;
 
661
                head->builtin = -1;
 
662
        }
 
663
 
 
664
        return connman_add_entry(table, new_entry, chain_tail->prev, builtin);
 
665
}
 
666
 
 
667
static struct ipt_replace *
 
668
connman_iptables_blob(struct connman_iptables *table)
 
669
{
 
670
        struct ipt_replace *r;
 
671
        GList *list;
 
672
        struct connman_iptables_entry *e;
 
673
        unsigned char *entry_index;
 
674
 
 
675
        r = g_try_malloc0(sizeof(struct ipt_replace) + table->size);
 
676
        if (r == NULL)
 
677
                return NULL;
 
678
 
 
679
        memset(r, 0, sizeof(*r) + table->size);
 
680
 
 
681
        r->counters = g_try_malloc0(sizeof(struct xt_counters)
 
682
                                * table->old_entries);
 
683
        if (r->counters == NULL) {
 
684
                g_free(r);
 
685
                return NULL;
 
686
        }
 
687
 
 
688
        strcpy(r->name, table->info->name);
 
689
        r->num_entries = table->num_entries;
 
690
        r->size = table->size;
 
691
 
 
692
        r->num_counters = table->old_entries;
 
693
        r->valid_hooks  = table->info->valid_hooks;
 
694
 
 
695
        memcpy(r->hook_entry, table->hook_entry, sizeof(table->hook_entry));
 
696
        memcpy(r->underflow, table->underflow, sizeof(table->underflow));
 
697
 
 
698
        entry_index = (unsigned char *)r->entries;
 
699
        for (list = table->entries; list; list = list->next) {
 
700
                e = list->data;
 
701
 
 
702
                memcpy(entry_index, e->entry, e->entry->next_offset);
 
703
                entry_index += e->entry->next_offset;
 
704
        }
 
705
 
 
706
        return r;
 
707
}
 
708
 
 
709
static void dump_target(struct connman_iptables *table,
 
710
                                struct ipt_entry *entry)
 
711
 
 
712
{
 
713
        struct xtables_target *xt_t;
 
714
        struct xt_entry_target *target;
 
715
 
 
716
        target = ipt_get_target(entry);
 
717
 
 
718
        if (!strcmp(target->u.user.name, IPT_STANDARD_TARGET)) {
 
719
                struct xt_standard_target *t;
 
720
 
 
721
                t = (struct xt_standard_target *)target;
 
722
 
 
723
                switch (t->verdict) {
 
724
                case XT_RETURN:
 
725
                        printf("\ttarget RETURN\n");
 
726
                        break;
 
727
 
 
728
                case -NF_ACCEPT - 1:
 
729
                        printf("\ttarget ACCEPT\n");
 
730
                        break;
 
731
 
 
732
                case -NF_DROP - 1:
 
733
                        printf("\ttarget DROP\n");
 
734
                        break;
 
735
 
 
736
                case -NF_QUEUE - 1:
 
737
                        printf("\ttarget QUEUE\n");
 
738
                        break;
 
739
 
 
740
                case -NF_STOP - 1:
 
741
                        printf("\ttarget STOP\n");
 
742
                        break;
 
743
 
 
744
                default:
 
745
                        printf("\tJUMP @%p (0x%x)\n",
 
746
                                (char*)table->blob_entries->entrytable +
 
747
                                t->verdict, t->verdict);
 
748
                        break;
 
749
                }
 
750
 
 
751
                xt_t = xtables_find_target(IPT_STANDARD_TARGET,
 
752
                                                XTF_LOAD_MUST_SUCCEED);
 
753
 
 
754
                if(xt_t->print != NULL)
 
755
                        xt_t->print(NULL, target, 1);
 
756
        } else {
 
757
                xt_t = xtables_find_target(target->u.user.name, XTF_TRY_LOAD);
 
758
                if (xt_t == NULL) {
 
759
                        printf("\ttarget %s\n", target->u.user.name);
 
760
                        return;
 
761
                }
 
762
 
 
763
                if(xt_t->print != NULL) {
 
764
                        printf("\ttarget ");
 
765
                        xt_t->print(NULL, target, 1);
 
766
                        printf("\n");
 
767
                }
 
768
        }
 
769
}
 
770
 
 
771
static void dump_match(struct connman_iptables *table, struct ipt_entry *entry)
 
772
{
 
773
        struct xtables_match *xt_m;
35
774
        struct xt_entry_match *match;
36
 
        struct xtables_match *xt_match;
37
 
 
38
 
        match = (struct xt_entry_match *)e->elems;
39
 
        if (match == NULL)
40
 
                return;
41
 
 
42
 
        xt_match = xtables_find_match(match->u.user.name, XTF_TRY_LOAD, NULL);
43
 
        if (xt_match == NULL)
44
 
                return;
45
 
 
46
 
        printf("\tMATCH:%s\n", xt_match->m->u.user.name);
 
775
 
 
776
        if (entry->elems == (unsigned char *)entry + entry->target_offset)
 
777
                return;
 
778
 
 
779
        match = (struct xt_entry_match *) entry->elems;
 
780
 
 
781
        if (!strlen(match->u.user.name))
 
782
                return;
 
783
 
 
784
        xt_m = xtables_find_match(match->u.user.name, XTF_TRY_LOAD, NULL);
 
785
        if (xt_m == NULL)
 
786
                goto out;
 
787
 
 
788
        if(xt_m->print != NULL) {
 
789
                printf("\tmatch ");
 
790
                xt_m->print(NULL, match, 1);
 
791
                printf("\n");
 
792
 
 
793
                return;
 
794
        }
 
795
 
 
796
out:
 
797
        printf("\tmatch %s\n", match->u.user.name);
 
798
 
47
799
}
48
800
 
49
 
static void print_target(const struct ipt_entry *e)
 
801
static int connman_iptables_dump_entry(struct ipt_entry *entry,
 
802
                                        struct connman_iptables *table)
50
803
{
51
804
        struct xt_entry_target *target;
52
 
        struct xtables_target *xt_target;
53
 
 
54
 
        target = (void *)e + e->target_offset;
55
 
        if (target == NULL)
56
 
                return;
57
 
 
58
 
        xt_target = xtables_find_target(target->u.user.name, XTF_TRY_LOAD);
59
 
        if (xt_target == NULL)
60
 
                return;
61
 
 
62
 
        printf("\tTARGET: %s\n", xt_target->t->u.user.name);
63
 
}
64
 
 
65
 
 
66
 
static void print_rule(const struct ipt_entry *e, const char *chain)
67
 
{
68
 
        /* print chain name */
69
 
        printf("CHAIN %s:\n", chain);
70
 
 
71
 
        print_match(e);
72
 
        print_target(e);
73
 
}
74
 
 
75
 
static void print_tables(struct iptc_handle *h)
76
 
{
77
 
        const char *chain;
78
 
        const struct ipt_entry *rule;
79
 
 
80
 
        chain = iptc_first_chain(h);
81
 
 
82
 
        while(chain) {
83
 
                rule = iptc_first_rule(chain, h);
84
 
                while (rule) {
85
 
                        print_rule(rule, chain);
86
 
 
87
 
                        rule = iptc_next_rule(rule, h);
88
 
                }
89
 
 
90
 
                chain = iptc_next_chain(h);
91
 
        }
92
 
}
93
 
 
94
 
static struct ipt_entry *build_quota_drop_entry(void)
95
 
{
96
 
        struct ipt_entry *e;
97
 
        size_t match_size, target_size;
98
 
        struct xtables_target *t;
99
 
        struct xtables_match *m;
100
 
        struct xtables_rule_match *matches = NULL;
101
 
 
102
 
        m = xtables_find_match("quota", XTF_LOAD_MUST_SUCCEED, &matches);
103
 
        if (m == NULL)
104
 
                return NULL;
105
 
 
106
 
        match_size = IPT_ALIGN(sizeof(struct ipt_entry_match)) + m->size;
107
 
 
108
 
        m->m = xtables_calloc(1, match_size);
109
 
        if (m->m == NULL)
110
 
                return NULL;
111
 
        m->m->u.match_size = match_size;
112
 
        strcpy(m->m->u.user.name, m->name);
113
 
        xtables_set_revision(m->m->u.user.name, m->revision);
114
 
        if (m->init != NULL)
115
 
                m->init(m->m);
116
 
 
117
 
        t = xtables_find_target("DROP", XTF_TRY_LOAD);
118
 
        if (t == NULL) {
119
 
                free(m->m);
120
 
                return NULL;
121
 
        }
122
 
 
123
 
        target_size = IPT_ALIGN(sizeof(struct ipt_entry_target)) + t->size;
124
 
 
125
 
        t->t = xtables_calloc(1, target_size);
126
 
        t->t->u.target_size = target_size;
127
 
        strcpy(t->t->u.user.name, "DROP");
128
 
        xtables_set_revision(t->t->u.user.name, t->revision);
129
 
        if (t->init != NULL)
130
 
                t->init(t->t);
131
 
 
132
 
        e = calloc(1, sizeof(struct ipt_entry) + match_size + target_size);
133
 
        if (e == NULL) {
134
 
                free(m->m);
135
 
                free(t->t);
136
 
        }
137
 
 
138
 
        e->target_offset = sizeof(struct ipt_entry) + match_size;
139
 
        e->next_offset = sizeof(struct ipt_entry) + match_size + target_size;
140
 
 
141
 
        memcpy(e->elems, m->m, match_size);
142
 
        memcpy(e->elems + match_size, t->t, target_size);
143
 
 
144
 
        return e;
145
 
}
146
 
 
147
 
static int add_rule(const ipt_chainlabel chain, struct ipt_entry *e,
148
 
                        struct iptc_handle *h)
149
 
{
150
 
        if (!iptc_create_chain(chain, h)) {
151
 
                printf("Chain creation error (%s)\n", iptc_strerror(errno));
152
 
                return -1;
153
 
        }
154
 
 
155
 
        if (!iptc_insert_entry(chain, e, 0, h)) {
156
 
                printf("Entry insertion error (%s)\n", iptc_strerror(errno));
157
 
                return -1;
158
 
        }
159
 
 
160
 
        if (!iptc_commit(h)) {
161
 
                printf("Commit error (%s)\n", iptc_strerror(errno));
162
 
                return -1;
163
 
        }
 
805
        unsigned int offset;
 
806
        int builtin;
 
807
 
 
808
        offset = (char *)entry - (char *)table->blob_entries->entrytable;
 
809
        target = ipt_get_target(entry);
 
810
        builtin = is_hook_entry(table, entry);
 
811
 
 
812
        if (entry_to_offset(table, entry) + entry->next_offset ==
 
813
                                        table->blob_entries->size) {
 
814
                printf("End of CHAIN 0x%x\n", offset);
 
815
                return 0;
 
816
        }
 
817
 
 
818
        if (!strcmp(target->u.user.name, IPT_ERROR_TARGET)) {
 
819
                printf("USER CHAIN (%s) %p  match %p  target %p  size %d\n",
 
820
                        target->data, entry, entry->elems,
 
821
                        (char *)entry + entry->target_offset,
 
822
                                entry->next_offset);
 
823
 
 
824
                return 0;
 
825
        } else if (builtin >= 0) {
 
826
                printf("CHAIN (%s) %p  match %p  target %p  size %d\n",
 
827
                        hooknames[builtin], entry, entry->elems,
 
828
                        (char *)entry + entry->target_offset,
 
829
                                entry->next_offset);
 
830
        } else {
 
831
                printf("RULE %p  match %p  target %p  size %d\n", entry,
 
832
                        entry->elems,
 
833
                        (char *)entry + entry->target_offset,
 
834
                                entry->next_offset);
 
835
        }
 
836
 
 
837
        dump_match(table, entry);
 
838
        dump_target(table, entry);
164
839
 
165
840
        return 0;
166
841
}
167
842
 
168
 
static void remove_rule(const ipt_chainlabel chain, struct iptc_handle *h)
169
 
{
170
 
        iptc_flush_entries(chain, h);
171
 
        iptc_delete_chain(chain, h);
172
 
        iptc_commit(h);
173
 
}
174
 
 
 
843
static void connman_iptables_dump_hook(struct connman_iptables *table)
 
844
{
 
845
        int i;
 
846
        printf("hooks: \n");
 
847
        for (i = 0; i < NF_INET_NUMHOOKS; i++) {
 
848
                if ((table->info->valid_hooks & (1 << i)))
 
849
                        printf("%s entry %p underflow %p (%#x)\n",
 
850
                                hooknames[i],
 
851
                                table->blob_entries->entrytable +
 
852
                                                table->info->hook_entry[i],
 
853
                                table->blob_entries->entrytable +
 
854
                                                table->info->underflow[i],
 
855
                                        table->info->underflow[i]);
 
856
        }
 
857
}
 
858
 
 
859
static void connman_iptables_dump(struct connman_iptables *table)
 
860
{
 
861
        printf("%s valid_hooks=0x%08x, num_entries=%u, size=%u\n",
 
862
                table->info->name,
 
863
                table->info->valid_hooks, table->info->num_entries,
 
864
                table->info->size);
 
865
 
 
866
        connman_iptables_dump_hook(table);
 
867
 
 
868
        ENTRY_ITERATE(table->blob_entries->entrytable,
 
869
                        table->blob_entries->size,
 
870
                        connman_iptables_dump_entry, table);
 
871
 
 
872
}
 
873
 
 
874
static int connman_iptables_get_entries(struct connman_iptables *table)
 
875
{
 
876
        socklen_t entry_size;
 
877
 
 
878
        entry_size = sizeof(struct ipt_get_entries) + table->info->size;
 
879
 
 
880
        return getsockopt(table->ipt_sock, IPPROTO_IP, IPT_SO_GET_ENTRIES,
 
881
                                table->blob_entries, &entry_size);
 
882
}
 
883
 
 
884
static int connman_iptables_replace(struct connman_iptables *table,
 
885
                                        struct ipt_replace *r)
 
886
{
 
887
        return setsockopt(table->ipt_sock, IPPROTO_IP, IPT_SO_SET_REPLACE, r,
 
888
                         sizeof(*r) + r->size);
 
889
}
 
890
 
 
891
static void connman_iptables_cleanup(struct connman_iptables *table)
 
892
{
 
893
        GList *list;
 
894
        struct connman_iptables_entry *entry;
 
895
 
 
896
        close(table->ipt_sock);
 
897
 
 
898
        for (list = table->entries; list; list = list->next) {
 
899
                entry = list->data;
 
900
 
 
901
                g_free(entry->entry);
 
902
        }
 
903
 
 
904
        g_free(table->info);
 
905
        g_free(table->blob_entries);
 
906
        g_free(table);
 
907
 
 
908
        xtables_free_opts(1);
 
909
}
 
910
 
 
911
static int connman_iptables_commit(struct connman_iptables *table)
 
912
{
 
913
        struct ipt_replace *repl;
 
914
 
 
915
        repl = connman_iptables_blob(table);
 
916
 
 
917
        return connman_iptables_replace(table, repl);
 
918
}
 
919
 
 
920
static int add_entry(struct ipt_entry *entry, struct connman_iptables *table)
 
921
{
 
922
        struct ipt_entry *new_entry;
 
923
        int builtin;
 
924
 
 
925
        new_entry = g_try_malloc0(entry->next_offset);
 
926
        if (new_entry == NULL)
 
927
                return -ENOMEM;
 
928
 
 
929
        memcpy(new_entry, entry, entry->next_offset);
 
930
 
 
931
        builtin = is_hook_entry(table, entry);
 
932
 
 
933
        return connman_add_entry(table, new_entry, NULL, builtin);
 
934
}
 
935
 
 
936
static struct connman_iptables *connman_iptables_init(const char *table_name)
 
937
{
 
938
        struct connman_iptables *table;
 
939
        socklen_t s;
 
940
 
 
941
        table =  g_try_new0(struct connman_iptables, 1);
 
942
        if (table == NULL)
 
943
                return NULL;
 
944
 
 
945
        table->info =  g_try_new0(struct ipt_getinfo, 1);
 
946
        if (table->info == NULL)
 
947
                goto err;
 
948
 
 
949
        table->ipt_sock = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
 
950
        if (table->ipt_sock < 0)
 
951
                goto err;
 
952
 
 
953
        s = sizeof(*table->info);
 
954
        strcpy(table->info->name, table_name);
 
955
        if (getsockopt(table->ipt_sock, IPPROTO_IP, IPT_SO_GET_INFO,
 
956
                                                table->info, &s) < 0)
 
957
                goto err;
 
958
 
 
959
        table->blob_entries = g_try_malloc0(sizeof(struct ipt_get_entries) +
 
960
                                                table->info->size);
 
961
        if (table->blob_entries == NULL)
 
962
                goto err;
 
963
 
 
964
        strcpy(table->blob_entries->name, table_name);
 
965
        table->blob_entries->size = table->info->size;
 
966
 
 
967
        if (connman_iptables_get_entries(table) < 0)
 
968
                goto err;
 
969
 
 
970
        table->num_entries = 0;
 
971
        table->old_entries = table->info->num_entries;
 
972
        table->size = 0;
 
973
 
 
974
        memcpy(table->underflow, table->info->underflow,
 
975
                                sizeof(table->info->underflow));
 
976
        memcpy(table->hook_entry, table->info->hook_entry,
 
977
                                sizeof(table->info->hook_entry));
 
978
 
 
979
        ENTRY_ITERATE(table->blob_entries->entrytable,
 
980
                        table->blob_entries->size,
 
981
                                add_entry, table);
 
982
 
 
983
 
 
984
        return table;
 
985
 
 
986
err:
 
987
 
 
988
        connman_iptables_cleanup(table);
 
989
 
 
990
        return NULL;
 
991
}
 
992
 
 
993
 
 
994
static struct option connman_iptables_opts[] = {
 
995
        {.name = "append",        .has_arg = 1, .val = 'A'},
 
996
        {.name = "flush-chain",   .has_arg = 1, .val = 'F'},
 
997
        {.name = "list",          .has_arg = 2, .val = 'L'},
 
998
        {.name = "new-chain",     .has_arg = 1, .val = 'N'},
 
999
        {.name = "delete-chain",  .has_arg = 1, .val = 'X'},
 
1000
        {.name = "in-interface",  .has_arg = 1, .val = 'i'},
 
1001
        {.name = "jump",          .has_arg = 1, .val = 'j'},
 
1002
        {.name = "match",         .has_arg = 1, .val = 'm'},
 
1003
        {.name = "out-interface", .has_arg = 1, .val = 'o'},
 
1004
        {.name = "table",         .has_arg = 1, .val = 't'},
 
1005
        {NULL},
 
1006
};
 
1007
 
 
1008
struct xtables_globals connman_iptables_globals = {
 
1009
        .option_offset = 0,
 
1010
        .opts = connman_iptables_opts,
 
1011
        .orig_opts = connman_iptables_opts,
 
1012
};
175
1013
 
176
1014
int main(int argc, char *argv[])
177
1015
{
178
 
        struct iptc_handle *h;
179
 
        struct ipt_entry *e;
180
 
 
181
 
        if (argc < 2) {
182
 
                printf("Usage: iptables-test [chain-name]\n");
183
 
                return -1;
184
 
        }
185
 
 
186
 
        h = iptc_init("filter");
187
 
        if (!h) {
188
 
                printf("libiptc initialization error (%s)\n",
189
 
                        iptc_strerror(errno));
190
 
                exit(errno);
191
 
        }
192
 
 
193
 
        xtables_init();
194
 
        xtables_set_nfproto(NFPROTO_IPV4);
195
 
 
196
 
        e = build_quota_drop_entry();
197
 
        if (e == NULL)
198
 
                return -1;
199
 
 
200
 
        add_rule(argv[1], e, h);
201
 
 
202
 
        print_tables(h);
203
 
 
204
 
        remove_rule(argv[1], h);
 
1016
        struct connman_iptables *table;
 
1017
        struct xtables_match *xt_m;
 
1018
        struct xtables_target *xt_t;
 
1019
        char *table_name, *chain, *new_chain, *match_name, *target_name;
 
1020
        char *delete_chain, *flush_chain;
 
1021
        int c;
 
1022
        size_t size;
 
1023
        gboolean dump, invert, delete;
 
1024
 
 
1025
        xtables_init_all(&connman_iptables_globals, NFPROTO_IPV4);
 
1026
 
 
1027
        dump = FALSE;
 
1028
        invert = FALSE;
 
1029
        delete = FALSE;
 
1030
        table_name = chain = new_chain = match_name = target_name = NULL;
 
1031
        delete_chain = flush_chain = NULL;
 
1032
        table = NULL;
 
1033
        xt_m = NULL;
 
1034
        xt_t = NULL;
 
1035
 
 
1036
        while ((c = getopt_long(argc, argv,
 
1037
           "-A:F:L::N:X:j:i:m:o:t:", connman_iptables_globals.opts, NULL)) != -1) {
 
1038
                switch (c) {
 
1039
                case 'A':
 
1040
                        chain = optarg;
 
1041
                        break;
 
1042
 
 
1043
                case 'F':
 
1044
                        flush_chain = optarg;
 
1045
                        break;
 
1046
 
 
1047
                case 'L':
 
1048
                        dump = true;
 
1049
                        break;
 
1050
 
 
1051
                case 'N':
 
1052
                        new_chain = optarg;
 
1053
                        break;
 
1054
 
 
1055
                case 'X':
 
1056
                        delete = true;
 
1057
                        delete_chain = optarg;
 
1058
                        break;
 
1059
 
 
1060
                case 'j':
 
1061
                        target_name = optarg;
 
1062
                        xt_t = xtables_find_target(target_name, XTF_TRY_LOAD);
 
1063
 
 
1064
                        if (xt_t == NULL)
 
1065
                                break;
 
1066
 
 
1067
                        size = ALIGN(sizeof(struct ipt_entry_target)) + xt_t->size;
 
1068
 
 
1069
                        xt_t->t = g_try_malloc0(size);
 
1070
                        if (xt_t->t == NULL)
 
1071
                                goto out;
 
1072
                        xt_t->t->u.target_size = size;
 
1073
                        strcpy(xt_t->t->u.user.name, target_name);
 
1074
                        xt_t->t->u.user.revision = xt_t->revision;
 
1075
                        if (xt_t->init != NULL)
 
1076
                                xt_t->init(xt_t->t);
 
1077
                        connman_iptables_globals.opts =
 
1078
                                xtables_merge_options(connman_iptables_globals.opts,
 
1079
                                                     xt_t->extra_opts,
 
1080
                                                     &xt_t->option_offset);
 
1081
                        if (connman_iptables_globals.opts == NULL)
 
1082
                                goto out;
 
1083
 
 
1084
                        break;
 
1085
 
 
1086
                case 'i':
 
1087
                        break;
 
1088
 
 
1089
                case 'm':
 
1090
                        match_name = optarg;
 
1091
 
 
1092
                        xt_m = xtables_find_match(optarg, XTF_LOAD_MUST_SUCCEED, NULL);
 
1093
                        size = ALIGN(sizeof(struct ipt_entry_match)) + xt_m->size;
 
1094
                        xt_m->m = g_try_malloc0(size);
 
1095
                        if (xt_m == NULL)
 
1096
                                goto out;
 
1097
                        xt_m->m->u.match_size = size;
 
1098
                        strcpy(xt_m->m->u.user.name, xt_m->name);
 
1099
                        xt_m->m->u.user.revision = xt_m->revision;
 
1100
                        if (xt_m->init != NULL)
 
1101
                                xt_m->init(xt_m->m);
 
1102
                        if (xt_m != xt_m->next) {
 
1103
                                connman_iptables_globals.opts =
 
1104
                                        xtables_merge_options(connman_iptables_globals.opts,
 
1105
                                                xt_m->extra_opts,
 
1106
                                                &xt_m->option_offset);
 
1107
                                if (connman_iptables_globals.opts == NULL)
 
1108
                                        goto out;
 
1109
                        }
 
1110
 
 
1111
                        break;
 
1112
 
 
1113
                case 'o':
 
1114
                        break;
 
1115
 
 
1116
                case 't':
 
1117
                        table_name = optarg;
 
1118
                        break;
 
1119
 
 
1120
                case 1:
 
1121
                        if (optarg[0] == '!' && optarg[1] == '\0') {
 
1122
                                if (invert)
 
1123
                                        printf("Consecutive ! not allowed\n");
 
1124
 
 
1125
                                invert = TRUE;
 
1126
                                optarg[0] = '\0';
 
1127
                                continue;
 
1128
                        }
 
1129
 
 
1130
                        printf("Invalid option\n");
 
1131
 
 
1132
                        return -1;
 
1133
 
 
1134
                default:
 
1135
                        if (xt_t == NULL || xt_t->parse == NULL ||
 
1136
                            !xt_t->parse(c - xt_t->option_offset, argv, invert,
 
1137
                                        &xt_t->tflags, NULL, &xt_t->t)) {
 
1138
                                if (xt_m == NULL || xt_m->parse == NULL)
 
1139
                                        break;
 
1140
 
 
1141
                                xt_m->parse(c - xt_m->option_offset, argv,
 
1142
                                        invert, &xt_m->mflags, NULL, &xt_m->m);
 
1143
                        }
 
1144
 
 
1145
                        break;
 
1146
                }
 
1147
        }
 
1148
 
 
1149
        if (table_name == NULL)
 
1150
                table_name = "filter";
 
1151
 
 
1152
        table = connman_iptables_init(table_name);
 
1153
        if (table == NULL)
 
1154
                return -1;
 
1155
 
 
1156
        if (delete) {
 
1157
                if (delete_chain == NULL)
 
1158
                        goto out;
 
1159
 
 
1160
                printf("Delete chain %s\n", delete_chain);
 
1161
 
 
1162
                connman_iptables_delete_chain(table, delete_chain);
 
1163
 
 
1164
                goto commit;
 
1165
        }
 
1166
 
 
1167
        if (flush_chain) {
 
1168
                printf("Flush chain %s\n", flush_chain);
 
1169
 
 
1170
                connman_iptables_flush_chain(table, flush_chain);
 
1171
 
 
1172
                goto commit;
 
1173
        }
 
1174
 
 
1175
        if (dump) {
 
1176
                connman_iptables_dump(table);
 
1177
 
 
1178
                return 0;
 
1179
        }
 
1180
 
 
1181
        if (chain && new_chain)
 
1182
                return -1;
 
1183
 
 
1184
        if (new_chain) {
 
1185
                printf("New chain %s\n", new_chain);
 
1186
 
 
1187
                connman_iptables_add_chain(table, new_chain);
 
1188
 
 
1189
                goto commit;
 
1190
        }
 
1191
 
 
1192
        if (chain) {
 
1193
                if (target_name == NULL)
 
1194
                        return -1;
 
1195
 
 
1196
                printf("Adding %s to %s (match %s)\n", target_name, chain, match_name);
 
1197
 
 
1198
                connman_iptables_add_rule(table, chain, target_name, xt_t,
 
1199
                                        match_name, xt_m);
 
1200
 
 
1201
                goto commit;
 
1202
        }
 
1203
 
 
1204
commit:
 
1205
 
 
1206
        connman_iptables_commit(table);
 
1207
 
 
1208
out:
 
1209
        connman_iptables_cleanup(table);
 
1210
 
 
1211
        if (xt_t)
 
1212
                g_free(xt_t->t);
 
1213
 
 
1214
        if (xt_m)
 
1215
                g_free(xt_m->m);
205
1216
 
206
1217
        return 0;
207
1218
}