Imported Upstream version 1.38
[platform/upstream/connman.git] / src / iptables.c
1 /*
2  *
3  *  Connection Manager
4  *
5  *  Copyright (C) 2007-2013  Intel Corporation. All rights reserved.
6  *
7  *  This program is free software; you can redistribute it and/or modify
8  *  it under the terms of the GNU General Public License version 2 as
9  *  published by the Free Software Foundation.
10  *
11  *  This program is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *  GNU General Public License for more details.
15  *
16  *  You should have received a copy of the GNU General Public License
17  *  along with this program; if not, write to the Free Software
18  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
19  *
20  */
21
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25
26 #include <getopt.h>
27 #include <stdlib.h>
28 #include <stdio.h>
29 #include <string.h>
30 #include <unistd.h>
31 #include <errno.h>
32 #include <sys/socket.h>
33 #include <xtables.h>
34 #include <inttypes.h>
35 #include <setjmp.h>
36
37 #include <linux/netfilter_ipv4/ip_tables.h>
38 #include <linux/netfilter_ipv6/ip6_tables.h>
39
40 #include "connman.h"
41 #include "src/shared/util.h"
42
43 /*
44  * Some comments on how the iptables API works (some of them from the
45  * source code from iptables and the kernel):
46  *
47  * - valid_hooks: bit indicates valid IDs for hook_entry
48  * - hook_entry[ID] offset to the chain start
49  * - overflows should be end of entry chains, and uncodintional policy nodes.
50  * - policy entry: last entry in a chain
51  * - user chain: end of last builtin + policy entry
52  * - final entry must be error node
53  * - Underflows must be unconditional and use the STANDARD target with
54  *   ACCEPT/DROP
55  * - IPT_SO_GET_INFO and IPT_SO_GET_ENTRIES are used to read a table
56  * - IPT_SO_GET_INFO: struct ipt_getinfo (note the lack of table content)
57  * - IPT_SO_GET_ENTRIES: struct ipt_get_entries (contains only parts of the
58  *   table header/meta info. The table is appended after the header. The entries
59  *   are of the type struct ipt_entry.
60  * - After the ipt_entry the matches are appended. After the matches
61  *   the target is appended.
62  * - ipt_entry->target_offset =  Size of ipt_entry + matches
63  * - ipt_entry->next_offset =  Size of ipt_entry + matches + target
64  * - IPT_SO_SET_REPLACE is used to write a table (contains the complete
65  * - hook_entry and overflow mark the beginning and the end of a chain, e.g
66  *     entry hook: pre/in/fwd/out/post -1/0/352/504/-1
67  *     underflow:  pre/in/fwd/out/post -1/200/352/904/-1
68  *   means that INPUT starts at offset 0 and ends at 200 (the start offset to
69  *   the last element). FORWARD has one entry starting/ending at 352. The entry
70  *   has a size of 152. 352 + 152 = 504 which is the start of the OUTPUT chain
71  *   which then ends at 904. PREROUTING and POSTROUTING are invalid hooks in
72  *   the filter table.
73  * - 'iptables -t filter -A INPUT -m mark --mark 999 -j LOG'
74  *   writing that table looks like this:
75  *
76  *   filter valid_hooks 0x0000000e  num_entries 5  size 856
77  *   entry hook: pre/in/fwd/out/post -1/0/376/528/-1
78  *   underflow:  pre/in/fwd/out/post -1/224/376/528/-1
79  *   entry 0x699d30  offset 0  size 224
80  *     RULE  match 0x699da0  target 0x699dd0
81  *             match  mark match 0x3e7
82  *             target  LOG flags 0 level 4
83  *             src 0.0.0.0/0.0.0.0
84  *             dst 0.0.0.0/0.0.0.0
85  *   entry 0x699e10  offset 224  size 152
86  *     RULE  match 0x699e80  target 0x699e80
87  *             target ACCEPT
88  *             src 0.0.0.0/0.0.0.0
89  *             dst 0.0.0.0/0.0.0.0
90  *   entry 0x699ea8  offset 376  size 152
91  *     RULE  match 0x699f18  target 0x699f18
92  *             target ACCEPT
93  *             src 0.0.0.0/0.0.0.0
94  *             dst 0.0.0.0/0.0.0.0
95  *   entry 0x699f40  offset 528  size 152
96  *     RULE  match 0x699fb0  target 0x699fb0
97  *             target ACCEPT
98  *             src 0.0.0.0/0.0.0.0
99  *             dst 0.0.0.0/0.0.0.0
100  *   entry 0x699fd8  offset 680  size 176
101  *     USER CHAIN (ERROR)  match 0x69a048  target 0x69a048
102  *
103  *   Reading the filter table looks like this:
104  *
105  *   filter valid_hooks 0x0000000e  num_entries 5  size 856
106  *   entry hook: pre/in/fwd/out/post -1/0/376/528/-1
107  *   underflow:  pre/in/fwd/out/post -1/224/376/528/-1
108  *   entry 0x25fec28  offset 0  size 224
109  *     CHAIN (INPUT)  match 0x25fec98  target 0x25fecc8
110  *             match  mark match 0x3e7
111  *             target  LOG flags 0 level 4
112  *             src 0.0.0.0/0.0.0.0
113  *             dst 0.0.0.0/0.0.0.0
114  *   entry 0x25fed08  offset 224  size 152
115  *     RULE  match 0x25fed78  target 0x25fed78
116  *             target ACCEPT
117  *             src 0.0.0.0/0.0.0.0
118  *             dst 0.0.0.0/0.0.0.0
119  *   entry 0x25feda0  offset 376  size 152
120  *     CHAIN (FORWARD)  match 0x25fee10  target 0x25fee10
121  *             target ACCEPT
122  *             src 0.0.0.0/0.0.0.0
123  *             dst 0.0.0.0/0.0.0.0
124  *   entry 0x25fee38  offset 528  size 152
125  *     CHAIN (OUTPUT)  match 0x25feea8  target 0x25feea8
126  *             target ACCEPT
127  *             src 0.0.0.0/0.0.0.0
128  *             dst 0.0.0.0/0.0.0.0
129  *   entry 0x25feed0  offset 680  size 176
130  *     End of CHAIN
131  */
132
133 /*
134  * Values for the index values used here  are defined as equal for both IPv4
135  * and IPv6 (NF_IP_* and NF_IP6_*) in Netfilter headers.
136  */
137 static const char *hooknames[] = {
138         [NF_IP_PRE_ROUTING]     = "PREROUTING",
139         [NF_IP_LOCAL_IN]        = "INPUT",
140         [NF_IP_FORWARD]         = "FORWARD",
141         [NF_IP_LOCAL_OUT]       = "OUTPUT",
142         [NF_IP_POST_ROUTING]    = "POSTROUTING",
143 };
144
145 #define LABEL_ACCEPT  "ACCEPT"
146 #define LABEL_DROP    "DROP"
147 #define LABEL_QUEUE   "QUEUE"
148 #define LABEL_RETURN  "RETURN"
149
150 #define XT_OPTION_OFFSET_SCALE 256
151
152 struct connman_iptables_entry {
153         int type;
154         unsigned int offset;
155         int builtin;
156         int counter_idx;
157
158         struct ipt_entry *entry;
159         struct ip6t_entry *entry6;
160 };
161
162 struct connman_iptables {
163         int type;
164         char *name;
165         int ipt_sock;
166
167         struct ipt_getinfo *info;
168         struct ipt_get_entries *blob_entries;
169         struct ip6t_getinfo *info6;
170         struct ip6t_get_entries *blob_entries6;
171
172         unsigned int num_entries;
173         unsigned int old_entries;
174         unsigned int size;
175
176         unsigned int underflow[NF_INET_NUMHOOKS];
177         unsigned int hook_entry[NF_INET_NUMHOOKS];
178
179         GList *entries;
180 };
181
182 static GHashTable *table_hash = NULL;
183 static GHashTable *table_hash_ipv6 = NULL;
184 static bool debug_enabled = false;
185
186 struct iptables_ip {
187         int type;
188         struct ipt_ip *ip;
189         struct ip6t_ip6 *ip6;
190 };
191
192 struct iptables_replace {
193         int type;
194         struct ipt_replace *r;
195         struct ip6t_replace *r6;
196 };
197
198 static jmp_buf env_state;
199 static bool jmp_set = false;
200
201 static void enable_jmp()
202 {
203         jmp_set = true;
204 }
205
206 static void disable_jmp()
207 {
208         jmp_set = false;
209 }
210
211 static bool can_jmp()
212 {
213         DBG("%s", jmp_set ? "true" : "false");
214         return jmp_set;
215 }
216
217 typedef int (*iterate_entries_cb_t)(struct connman_iptables_entry *entry,
218                                         int builtin, unsigned int hook,
219                                         size_t size, unsigned int offset,
220                                         void *user_data);
221
222 static u_int16_t iptables_entry_get_next_offset(
223                                         struct connman_iptables_entry *entry)
224 {
225         if (!entry)
226                 return 0;
227
228         switch (entry->type) {
229         case AF_INET:
230                 return entry->entry ? entry->entry->next_offset : 0;
231         case AF_INET6:
232                 return entry->entry6 ? entry->entry6->next_offset : 0;
233         }
234
235         return 0;
236 }
237
238 static u_int16_t iptables_entry_get_target_offset(
239                                         struct connman_iptables_entry *entry)
240 {
241         if (!entry)
242                 return 0;
243
244         switch (entry->type) {
245         case AF_INET:
246                 return entry->entry ? entry->entry->target_offset : 0;
247         case AF_INET6:
248                 return entry->entry6 ? entry->entry6->target_offset : 0;
249         }
250
251         return 0;
252 }
253
254 static unsigned char *iptables_entry_get_elems(
255                                         struct connman_iptables_entry *entry)
256 {
257         if (!entry)
258                 return NULL;
259
260         switch (entry->type) {
261         case AF_INET:
262                 return entry->entry ? entry->entry->elems : NULL;
263         case AF_INET6:
264                 return entry->entry6 ? entry->entry6->elems : NULL;
265         }
266
267         return NULL;
268 }
269
270 static struct xt_entry_target *iptables_entry_get_target(
271                                         struct connman_iptables_entry *entry)
272 {
273         if (!entry)
274                 return NULL;
275
276         switch (entry->type) {
277         case AF_INET:
278                 return entry->entry ? ipt_get_target(entry->entry) : NULL;
279         case AF_INET6:
280                 return entry->entry6 ? ip6t_get_target(entry->entry6) : NULL;
281         }
282
283         return NULL;
284 }
285
286 static struct xt_counters *iptables_entry_get_counters(
287                                         struct connman_iptables_entry *entry)
288 {
289         if (!entry)
290                 return NULL;
291
292         switch (entry->type) {
293         case AF_INET:
294                 return entry->entry ? &entry->entry->counters : NULL;
295         case AF_INET6:
296                 return entry->entry6 ? &entry->entry6->counters : NULL;
297         }
298
299         return NULL;
300 }
301
302 static void iptables_entry_free(struct connman_iptables_entry *entry)
303 {
304         if (!entry)
305                 return;
306
307         g_free(entry->entry);
308         g_free(entry->entry6);
309         g_free(entry);
310 }
311
312 static const char *iptables_table_get_info_name(struct connman_iptables* table)
313 {
314         if (!table)
315                 return NULL;
316
317         switch (table->type) {
318         case AF_INET:
319                 return table->info->name;
320         case AF_INET6:
321                 return table->info6->name;
322         }
323
324         return NULL;
325 }
326
327 static unsigned int iptables_table_get_info_num_entries(
328                                         struct connman_iptables* table)
329 {
330         if (!table)
331                 return 0;
332
333         switch (table->type) {
334         case AF_INET:
335                 return table->info->num_entries;
336         case AF_INET6:
337                 return table->info6->num_entries;
338         }
339
340         return 0;
341 }
342
343 static unsigned int iptables_table_get_info_size(struct connman_iptables* table)
344 {
345         if (!table)
346                 return 0;
347
348         switch (table->type) {
349         case AF_INET:
350                 return table->info->size;
351         case AF_INET6:
352                 return table->info6->size;
353         }
354
355         return 0;
356 }
357
358 static unsigned int iptables_table_get_info_valid_hooks(
359                                         struct connman_iptables* table)
360 {
361         if (!table)
362                 return 0;
363
364         switch (table->type) {
365         case AF_INET:
366                 return table->info->valid_hooks;
367         case AF_INET6:
368                 return table->info6->valid_hooks;
369         }
370
371         return 0;
372 }
373
374 static unsigned int *iptables_table_get_info_hook_entry(
375                                         struct connman_iptables* table)
376 {
377         if (!table)
378                 return NULL;
379
380         switch (table->type) {
381         case AF_INET:
382                 return table->info->hook_entry;
383         case AF_INET6:
384                 return table->info6->hook_entry;
385         }
386
387         return NULL;
388 }
389
390 static unsigned int *iptables_table_get_info_underflow(
391                                         struct connman_iptables* table)
392 {
393         if (!table)
394                 return NULL;
395
396         switch (table->type) {
397         case AF_INET:
398                 return table->info->underflow;
399         case AF_INET6:
400                 return table->info6->underflow;
401         }
402
403         return NULL;
404 }
405
406 static unsigned int iptables_table_get_entries_size(
407                                         struct connman_iptables* table)
408 {
409         if (!table)
410                 return 0;
411
412         switch (table->type) {
413         case AF_INET:
414                 return table->blob_entries->size;
415         case AF_INET6:
416                 return table->blob_entries6->size;
417         }
418
419         return 0;
420 }
421
422 static const char *get_error_target(int type)
423 {
424         switch (type) {
425         case AF_INET:
426                 return IPT_ERROR_TARGET;
427         case AF_INET6:
428                 return IP6T_ERROR_TARGET;
429         default:
430                 return XT_ERROR_TARGET;
431         }
432 }
433
434 static const char *get_standard_target(int type)
435 {
436         switch (type) {
437         case AF_INET:
438                 return IPT_STANDARD_TARGET;
439         case AF_INET6:
440                 return IP6T_STANDARD_TARGET;
441         default:
442                 return XT_STANDARD_TARGET;
443         }
444 }
445
446 static struct connman_iptables *hash_table_lookup(int type,
447                                         const char *table_name) {
448
449         switch (type) {
450         case AF_INET:
451                 return g_hash_table_lookup(table_hash, table_name);
452         case AF_INET6:
453                 return g_hash_table_lookup(table_hash_ipv6, table_name);
454         }
455         
456         return NULL;
457 }
458
459 static bool hash_table_replace(int type,
460                                         char *table_name,
461                                         struct connman_iptables *table) {
462
463         switch (type) {
464         case AF_INET:
465                 return g_hash_table_replace(table_hash, table_name, table);
466         case AF_INET6:
467                 return g_hash_table_replace(table_hash_ipv6, table_name, table);
468         }
469         
470         return false;
471 }
472
473 static bool hash_table_remove(int type, const char *table_name)
474 {
475         switch (type) {
476         case AF_INET:
477                 return g_hash_table_remove(table_hash, table_name);
478         case AF_INET6:
479                 return g_hash_table_remove(table_hash_ipv6, table_name);
480         }
481         
482         return false;
483 }
484
485 static unsigned int next_hook_entry_index(unsigned int *valid_hooks)
486 {
487         unsigned int h;
488
489         if (*valid_hooks == 0)
490                 return NF_INET_NUMHOOKS;
491
492         h = __builtin_ffs(*valid_hooks) - 1;
493         *valid_hooks ^= (1 << h);
494
495         return h;
496 }
497
498 static int iterate_entries(struct connman_iptables_entry *entries,
499                                 unsigned int valid_hooks,
500                                 unsigned int *hook_entry,
501                                 unsigned int *underflow,
502                                 size_t size, iterate_entries_cb_t cb,
503                                 void *user_data)
504 {
505         unsigned int offset, h, hook;
506         int builtin, err;
507         struct connman_iptables_entry entry;
508
509         if (!entries)
510                 return -EINVAL;
511
512         switch (entries->type) {
513         case AF_INET:
514                 if (!entries->entry)
515                         return -EINVAL;
516
517                 break;
518         case AF_INET6:
519                 if (!entries->entry6)
520                         return -EINVAL;
521
522                 break;
523         default:
524                 return -EINVAL;
525         }
526
527         h = next_hook_entry_index(&valid_hooks);
528         hook = h;
529
530         entry.type = entries->type;
531         entry.entry = entries->entry;
532         entry.entry6 = entries->entry6;
533
534         for (offset = 0; offset < size;
535                         offset += iptables_entry_get_next_offset(&entry)) {
536                 builtin = -1;
537                 
538                 switch (entries->type) {
539                 case AF_INET:
540                         entry.entry = (void* )entries->entry + offset;
541                         break;
542                 case AF_INET6:
543                         entry.entry6 = (void* )entries->entry6 + offset;
544                         break;
545                 }
546
547                 /*
548                  * Updating builtin, hook and h is very tricky.
549                  * The rules are:
550                  * - builtin is only set to the current hook number
551                  *   if the current entry is the hook entry (aka chain
552                  *   head). And only for builtin chains, never for
553                  *   the user chains.
554                  * - hook is the current hook number. If we
555                  *   look at user chains it needs to be NF_INET_NETNUMHOOKS.
556                  * - h is the next hook entry. Thous we need to be carefully
557                  *   not to access the table when h is NF_INET_NETNUMHOOKS.
558                  */
559                 if (h < NF_INET_NUMHOOKS && hook_entry[h] == offset) {
560                         builtin = h;
561                         hook = h;
562                 }
563
564                 if (h == NF_INET_NUMHOOKS)
565                         hook = h;
566
567                 if (h < NF_INET_NUMHOOKS && underflow[h] <= offset)
568                         h = next_hook_entry_index(&valid_hooks);
569
570                 err = cb(&entry, builtin, hook, size, offset, user_data);
571                 if (err < 0)
572                         return err;
573         }
574
575         return 0;
576 }
577
578 static int print_entry(struct connman_iptables_entry *entry, int builtin,
579                                         unsigned int hook, size_t size,
580                                         unsigned int offset, void *user_data)
581 {
582         iterate_entries_cb_t cb;
583         struct xt_counters *counters;
584
585         cb = user_data;
586         counters = iptables_entry_get_counters(entry);
587
588         DBG("entry %p  hook %u  offset %u  size %u  packets %"PRIu64"  "
589                 "bytes %"PRIu64, entry, hook, offset,
590                         iptables_entry_get_next_offset(entry),
591                         (uint64_t) counters->pcnt, (uint64_t) counters->bcnt);
592
593         return cb(entry, builtin, hook, size, offset, NULL);
594 }
595
596 static int target_to_verdict(const char *target_name)
597 {
598         if (!g_strcmp0(target_name, LABEL_ACCEPT))
599                 return -NF_ACCEPT - 1;
600
601         if (!g_strcmp0(target_name, LABEL_DROP))
602                 return -NF_DROP - 1;
603
604         if (!g_strcmp0(target_name, LABEL_QUEUE))
605                 return -NF_QUEUE - 1;
606
607         if (!g_strcmp0(target_name, LABEL_RETURN))
608                 return XT_RETURN;
609
610         return 0;
611 }
612
613 static bool is_builtin_target(const char *target_name)
614 {
615         if (!g_strcmp0(target_name, LABEL_ACCEPT) ||
616                 !g_strcmp0(target_name, LABEL_DROP) ||
617                 !g_strcmp0(target_name, LABEL_QUEUE) ||
618                 !g_strcmp0(target_name, LABEL_RETURN))
619                 return true;
620
621         return false;
622 }
623
624 static bool is_jump(struct connman_iptables_entry *e)
625 {
626         struct xt_entry_target *target;
627
628         target = iptables_entry_get_target(e);
629
630         if (!target)
631                 return false;
632
633         if (!g_strcmp0(target->u.user.name, get_standard_target(e->type))) {
634                 struct xt_standard_target *t;
635
636                 t = (struct xt_standard_target *)target;
637
638                 switch (t->verdict) {
639                 case XT_RETURN:
640                 case -NF_ACCEPT - 1:
641                 case -NF_DROP - 1:
642                 case -NF_QUEUE - 1:
643                 case -NF_STOP - 1:
644                         return false;
645
646                 default:
647                         return true;
648                 }
649         }
650
651         return false;
652 }
653
654 static bool is_fallthrough(struct connman_iptables_entry *e)
655 {
656         struct xt_entry_target *target;
657
658         target = iptables_entry_get_target(e);
659
660         if (!target)
661                 return false;
662
663         if (!g_strcmp0(target->u.user.name, get_standard_target(e->type))) {
664                 struct xt_standard_target *t;
665
666                 t = (struct xt_standard_target *)target;
667                 if (t->verdict == 0)
668                         return true;
669         }
670         return false;
671 }
672
673 static bool is_chain(struct connman_iptables *table,
674                                 struct connman_iptables_entry *e)
675 {
676         struct xt_entry_target *target;
677
678         if (!e)
679                 return false;
680
681         if (e->builtin >= 0)
682                 return true;
683
684         target = iptables_entry_get_target(e);
685         
686         if (!target)
687                 return false;
688
689         if (!g_strcmp0(target->u.user.name, get_error_target(e->type)))
690                 return true;
691
692         return false;
693 }
694
695 static GList *find_chain_head(struct connman_iptables *table,
696                                 const char *chain_name)
697 {
698         GList *list;
699         struct connman_iptables_entry *head;
700         struct xt_entry_target *target;
701         int builtin;
702         
703         switch (table->type) {
704         case AF_INET:
705         case AF_INET6:
706                 break;
707         default:
708                 return NULL;
709         }
710
711         for (list = table->entries; list; list = list->next) {
712                 head = list->data;
713
714                 /* Buit-in chain */
715                 builtin = head->builtin;
716
717                 if (builtin >= 0 && !g_strcmp0(hooknames[builtin], chain_name))
718                         break;
719
720                 /* User defined chain */
721                 target = iptables_entry_get_target(head);
722                 
723                 if (!target)
724                         continue;
725
726                 if (!g_strcmp0(target->u.user.name,
727                         get_error_target(table->type)) &&
728                         !g_strcmp0((char *)target->data, chain_name))
729                         break;
730         }
731
732         return list;
733 }
734
735 static GList *find_chain_tail(struct connman_iptables *table,
736                                 const char *chain_name)
737 {
738         struct connman_iptables_entry *tail;
739         GList *chain_head, *list;
740
741         chain_head = find_chain_head(table, chain_name);
742         if (!chain_head)
743                 return NULL;
744
745         /* Then we look for the next chain */
746         for (list = chain_head->next; list; list = list->next) {
747                 tail = list->data;
748
749                 if (is_chain(table, tail))
750                         return list;
751         }
752
753         /* Nothing found, we return the table end */
754         return g_list_last(table->entries);
755 }
756
757 static void update_offsets(struct connman_iptables *table)
758 {
759         GList *list, *prev;
760         struct connman_iptables_entry *entry, *prev_entry;
761
762         for (list = table->entries; list; list = list->next) {
763                 entry = list->data;
764
765                 if (list == table->entries) {
766                         entry->offset = 0;
767
768                         continue;
769                 }
770
771                 prev = list->prev;
772                 prev_entry = prev->data;
773
774                 entry->offset = prev_entry->offset +
775                                         iptables_entry_get_next_offset(
776                                                 prev_entry);
777         }
778 }
779
780 static void update_targets_reference(struct connman_iptables *table,
781                                 struct connman_iptables_entry *entry_before,
782                                 struct connman_iptables_entry *modified_entry,
783                                 bool is_removing)
784 {
785         struct connman_iptables_entry *tmp;
786         struct xt_standard_target *t;
787         GList *list;
788         unsigned int offset;
789
790         offset = iptables_entry_get_next_offset(modified_entry);
791
792         for (list = table->entries; list; list = list->next) {
793                 tmp = list->data;
794
795                 if (!is_jump(tmp))
796                         continue;
797
798                 t = (struct xt_standard_target *)
799                         iptables_entry_get_target(tmp);
800
801                 if (!t)
802                         continue;
803
804                 if (is_removing) {
805                         if (t->verdict >= entry_before->offset)
806                                 t->verdict -= offset;
807                 } else {
808                         if (t->verdict > entry_before->offset)
809                                 t->verdict += offset;
810                 }
811         }
812
813         if (is_fallthrough(modified_entry)) {
814                 t = (struct xt_standard_target *)
815                         iptables_entry_get_target(modified_entry);
816                 
817                 if (!t)
818                         return;
819
820                 t->verdict = entry_before->offset +
821                         iptables_entry_get_target_offset(modified_entry) +
822                         XT_ALIGN(sizeof(struct xt_standard_target));
823                 t->target.u.target_size =
824                         XT_ALIGN(sizeof(struct xt_standard_target));
825         }
826 }
827
828 static int iptables_add_entry(struct connman_iptables *table,
829                                 struct connman_iptables_entry *entry,
830                                 GList *before, int builtin, int counter_idx)
831 {
832         struct connman_iptables_entry *e, *entry_before;
833
834         if (!table) {
835                 return -EINVAL;
836         }
837
838         e = g_try_malloc0(sizeof(struct connman_iptables_entry));
839         if (!e)
840                 return -ENOMEM;
841
842         switch (table->type) {
843         case AF_INET:
844                 e->entry = entry->entry;
845                 break;
846         case AF_INET6:
847                 e->entry6 = entry->entry6;
848                 break;
849         default:
850                 g_free(e);
851                 return -EINVAL;
852         }
853
854         e->type = entry->type;
855         e->builtin = builtin;
856         e->counter_idx = counter_idx;
857
858         table->entries = g_list_insert_before(table->entries, before, e);
859         table->num_entries++;
860         table->size += iptables_entry_get_next_offset(e);
861
862         if (!before) {
863                 e->offset = table->size -
864                                 iptables_entry_get_next_offset(e);
865                 return 0;
866         }
867
868         entry_before = before->data;
869
870         /*
871          * We've just appended/inserted a new entry. All references
872          * should be bumped accordingly.
873          */
874         update_targets_reference(table, entry_before, e, false);
875
876         update_offsets(table);
877
878         return 0;
879 }
880
881 static int remove_table_entry(struct connman_iptables *table,
882                                 struct connman_iptables_entry *entry)
883 {
884         int removed = 0;
885         u_int16_t next_offset;
886
887         next_offset = iptables_entry_get_next_offset(entry);
888         table->num_entries--;
889
890         table->size -= next_offset;
891         removed = next_offset;
892
893         table->entries = g_list_remove(table->entries, entry);
894
895         iptables_entry_free(entry);
896
897         return removed;
898 }
899
900 static void delete_update_hooks(struct connman_iptables *table,
901                                 int builtin, GList *chain_head,
902                                 int removed)
903 {
904         struct connman_iptables_entry *e;
905         GList *list;
906
907         e = chain_head->data;
908         e->builtin = builtin;
909
910         table->underflow[builtin] -= removed;
911
912         for (list = chain_head->next; list; list = list->next) {
913                 e = list->data;
914
915                 if (e->builtin < 0)
916                         continue;
917
918                 table->hook_entry[e->builtin] -= removed;
919                 table->underflow[e->builtin] -= removed;
920         }
921 }
922
923 static int iptables_flush_chain(struct connman_iptables *table,
924                                                 const char *name)
925 {
926         GList *chain_head, *chain_tail, *list, *next;
927         struct connman_iptables_entry *entry;
928         int builtin, removed = 0;
929
930         DBG("table %s chain %s", table->name, name);
931
932         chain_head = find_chain_head(table, name);
933         if (!chain_head)
934                 return -EINVAL;
935
936         chain_tail = find_chain_tail(table, name);
937         if (!chain_tail)
938                 return -EINVAL;
939
940         entry = chain_head->data;
941         builtin = entry->builtin;
942
943         if (builtin >= 0)
944                 list = chain_head;
945         else
946                 list = chain_head->next;
947
948         if (list == chain_tail->prev)
949                 return 0;
950
951         while (list != chain_tail->prev) {
952                 entry = list->data;
953                 next = g_list_next(list);
954
955                 removed += remove_table_entry(table, entry);
956
957                 list = next;
958         }
959
960         if (builtin >= 0)
961                 delete_update_hooks(table, builtin, chain_tail->prev, removed);
962
963         update_offsets(table);
964
965         return 0;
966 }
967
968 static int iptables_add_chain(struct connman_iptables *table,
969                                 const char *name)
970 {
971         GList *last;
972         struct ipt_entry *entry_head = NULL;
973         struct ipt_entry *entry_return = NULL;
974         struct ip6t_entry *entry6_head = NULL;
975         struct ip6t_entry *entry6_return = NULL;
976         struct connman_iptables_entry entry = { 0 };
977         struct xt_error_target *error = NULL;
978         struct ipt_standard_target *standard = NULL;
979         u_int16_t entry_head_size, entry_return_size;
980         size_t entry_struct_size = 0;
981         size_t xt_error_target_size = 0;
982         size_t standard_target_size = 0;
983
984         DBG("table %s chain %s", table->name, name);
985
986         entry.type = table->type;
987
988         /* Do not allow to add duplicate chains */
989         if (find_chain_head(table, name))
990                 return -EEXIST;
991
992         last = g_list_last(table->entries);
993
994         xt_error_target_size = XT_ALIGN(sizeof(struct xt_error_target));
995
996         /*
997          * An empty chain is composed of:
998          * - A head entry, with no match and an error target.
999          *   The error target data is the chain name.
1000          * - A tail entry, with no match and a standard target.
1001          *   The standard target verdict is XT_RETURN (return to the
1002          *   caller).
1003          */
1004
1005         /* head entry */
1006         switch (entry.type) {
1007         case AF_INET:
1008                 entry_struct_size = XT_ALIGN(sizeof(struct ipt_entry));
1009                 entry_head_size = entry_struct_size + xt_error_target_size;
1010
1011                 entry_head = g_try_malloc0(entry_head_size);
1012                 if (!entry_head)
1013                         goto err_head;
1014
1015                 entry_head->target_offset = entry_struct_size;
1016                 entry_head->next_offset = entry_head_size;
1017
1018                 error = (struct xt_error_target *) entry_head->elems;
1019
1020                 entry.entry = entry_head;
1021                 break;
1022         case AF_INET6:
1023                 entry_struct_size = XT_ALIGN(sizeof(struct ip6t_entry));
1024                 entry_head_size = entry_struct_size + xt_error_target_size;
1025
1026                 entry6_head = g_try_malloc0(entry_head_size);
1027                 if (!entry6_head)
1028                         goto err_head;
1029
1030                 entry6_head->target_offset = entry_struct_size;
1031                 entry6_head->next_offset = entry_head_size;
1032
1033                 error = (struct xt_error_target *) entry6_head->elems;
1034
1035                 entry.entry6 = entry6_head;
1036                 break;
1037         default:
1038                 return -EINVAL;
1039         }
1040
1041         g_stpcpy(error->target.u.user.name, get_error_target(entry.type));
1042         error->target.u.user.target_size = xt_error_target_size;
1043         g_stpcpy(error->errorname, name);
1044
1045         if (iptables_add_entry(table, &entry, last, -1, -1) < 0)
1046                 goto err_head;
1047
1048         standard_target_size = XT_ALIGN(sizeof(struct ipt_standard_target));
1049         entry_return_size = entry_struct_size + standard_target_size;
1050
1051         /* tail entry */
1052         switch (entry.type) {
1053         case AF_INET:
1054                 entry_return = g_try_malloc0(entry_return_size);
1055                 if (!entry_return)
1056                         goto err;
1057
1058                 entry_return->target_offset = entry_struct_size;
1059                 entry_return->next_offset = entry_return_size;
1060
1061                 standard = (struct ipt_standard_target *) entry_return->elems;
1062
1063                 entry.entry = entry_return;
1064                 break;
1065         case AF_INET6:
1066                 entry6_return = g_try_malloc0(entry_return_size);
1067                 if (!entry6_return)
1068                         goto err;
1069
1070                 entry6_return->target_offset = entry_struct_size;
1071                 entry6_return->next_offset = entry_return_size;
1072
1073                 standard = (struct ipt_standard_target *) entry6_return->elems;
1074
1075                 entry.entry6 = entry6_return;
1076                 break;
1077         }
1078
1079         standard->target.u.user.target_size = standard_target_size;
1080         standard->verdict = XT_RETURN;
1081
1082         if (iptables_add_entry(table, &entry, last, -1, -1) < 0)
1083                 goto err;
1084
1085         return 0;
1086
1087 err:
1088         g_free(entry_return);
1089         g_free(entry6_return);
1090 err_head:
1091         g_free(entry_head);
1092         g_free(entry6_head);
1093
1094         return -ENOMEM;
1095 }
1096
1097 static int iptables_delete_chain(struct connman_iptables *table,
1098                                         const char *name)
1099 {
1100         struct connman_iptables_entry *entry;
1101         GList *chain_head, *chain_tail;
1102
1103         DBG("table %s chain %s", table->name, name);
1104
1105         chain_head = find_chain_head(table, name);
1106         if (!chain_head)
1107                 return -EINVAL;
1108
1109         entry = chain_head->data;
1110
1111         /* We cannot remove builtin chain */
1112         if (entry->builtin >= 0)
1113                 return -EINVAL;
1114
1115         chain_tail = find_chain_tail(table, name);
1116         if (!chain_tail)
1117                 return -EINVAL;
1118
1119         /* Chain must be flushed */
1120         if (chain_head->next != chain_tail->prev)
1121                 return -EINVAL;
1122
1123         remove_table_entry(table, entry);
1124
1125         entry = chain_tail->prev->data;
1126         remove_table_entry(table, entry);
1127
1128         update_offsets(table);
1129
1130         return 0;
1131 }
1132
1133 static struct connman_iptables_entry *new_rule(struct iptables_ip *ip,
1134                 const char *target_name, struct xtables_target *xt_t,
1135                 struct xtables_rule_match *xt_rm)
1136 {
1137         struct xtables_rule_match *tmp_xt_rm;
1138         struct connman_iptables_entry *new_entry;
1139         size_t match_size, target_size;
1140
1141         new_entry = g_try_malloc0(sizeof(struct connman_iptables_entry));
1142
1143         if (!new_entry)
1144                 return NULL;
1145
1146         new_entry->type = ip->type;
1147
1148         match_size = 0;
1149         for (tmp_xt_rm = xt_rm; tmp_xt_rm; tmp_xt_rm = tmp_xt_rm->next)
1150                 match_size += tmp_xt_rm->match->m->u.match_size;
1151
1152         if (xt_t)
1153                 target_size = xt_t->t->u.target_size;
1154         else
1155                 target_size = XT_ALIGN(sizeof(struct xt_standard_target));
1156
1157         switch (ip->type) {
1158         case AF_INET:
1159                 new_entry->entry = g_try_malloc0(
1160                                         XT_ALIGN(sizeof(struct ipt_entry)) +
1161                                         target_size + match_size);
1162                 if (!new_entry->entry)
1163                         goto err;
1164
1165                 memcpy(&new_entry->entry->ip, ip->ip, sizeof(struct ipt_ip));
1166
1167                 new_entry->entry->target_offset =
1168                                         XT_ALIGN(sizeof(struct ipt_entry)) +
1169                                         match_size;
1170                 new_entry->entry->next_offset =
1171                                         XT_ALIGN(sizeof(struct ipt_entry)) +
1172                                         target_size + match_size;
1173                 break;
1174         case AF_INET6:
1175                 new_entry->entry6 = g_try_malloc0(
1176                                         XT_ALIGN(sizeof(struct ip6t_entry)) +
1177                                         target_size + match_size);
1178                 if (!new_entry->entry6)
1179                         goto err;
1180
1181                 memcpy(&new_entry->entry6->ipv6, ip->ip6,
1182                                                 sizeof(struct ip6t_ip6));
1183
1184                 new_entry->entry6->target_offset =
1185                                         XT_ALIGN(sizeof(struct ip6t_entry)) +
1186                                         match_size;
1187                 new_entry->entry6->next_offset =
1188                                         XT_ALIGN(sizeof(struct ip6t_entry)) +
1189                                         target_size + match_size;
1190                 break;
1191         default:
1192                 goto err;
1193         }
1194
1195         match_size = 0;
1196         for (tmp_xt_rm = xt_rm; tmp_xt_rm;
1197                                 tmp_xt_rm = tmp_xt_rm->next) {
1198
1199                 switch (new_entry->type) {
1200                 case AF_INET:
1201                         memcpy(new_entry->entry->elems + match_size,
1202                                         tmp_xt_rm->match->m,
1203                                         tmp_xt_rm->match->m->u.match_size);
1204                         break;
1205                 case AF_INET6:
1206                         memcpy(new_entry->entry6->elems + match_size,
1207                                         tmp_xt_rm->match->m,
1208                                         tmp_xt_rm->match->m->u.match_size);
1209                         break;
1210                 }
1211                 match_size += tmp_xt_rm->match->m->u.match_size;
1212         }
1213
1214         if (xt_t) {
1215                 struct xt_entry_target *entry_target;
1216
1217                 entry_target = iptables_entry_get_target(new_entry);
1218                 memcpy(entry_target, xt_t->t, target_size);
1219         }
1220
1221         return new_entry;
1222
1223 err:
1224         g_free(new_entry);
1225
1226         return NULL;
1227 }
1228
1229 static void update_hooks(struct connman_iptables *table, GList *chain_head,
1230                                 struct connman_iptables_entry *entry)
1231 {
1232         GList *list;
1233         struct connman_iptables_entry *head, *e;
1234         int builtin;
1235         u_int16_t next_offset;
1236
1237         if (!table || !chain_head)
1238                 return;
1239
1240         head = chain_head->data;
1241
1242         builtin = head->builtin;
1243         if (builtin < 0)
1244                 return;
1245
1246         next_offset = iptables_entry_get_next_offset(entry);
1247
1248         table->underflow[builtin] += next_offset;
1249
1250         for (list = chain_head->next; list; list = list->next) {
1251                 e = list->data;
1252
1253                 builtin = e->builtin;
1254                 if (builtin < 0)
1255                         continue;
1256
1257                 table->hook_entry[builtin] += next_offset;
1258                 table->underflow[builtin] += next_offset;
1259         }
1260 }
1261
1262 static struct connman_iptables_entry *prepare_rule_inclusion(
1263                                 struct connman_iptables *table,
1264                                 struct iptables_ip *ip,
1265                                 const char *chain_name,
1266                                 const char *target_name,
1267                                 struct xtables_target *xt_t,
1268                                 int *builtin,
1269                                 struct xtables_rule_match *xt_rm,
1270                                 bool insert)
1271 {
1272         GList *chain_tail, *chain_head;
1273         struct connman_iptables_entry *head;
1274         struct connman_iptables_entry *new_entry;
1275
1276         chain_head = find_chain_head(table, chain_name);
1277         if (!chain_head)
1278                 return NULL;
1279
1280         chain_tail = find_chain_tail(table, chain_name);
1281         if (!chain_tail)
1282                 return NULL;
1283
1284         new_entry = new_rule(ip, target_name, xt_t, xt_rm);
1285
1286         switch (new_entry->type) {
1287         case AF_INET:
1288                 if (new_entry->entry)
1289                         break;
1290         case AF_INET6:
1291                 if (new_entry->entry6)
1292                         break;
1293         default:
1294                 goto err;
1295         }
1296
1297         update_hooks(table, chain_head, new_entry);
1298
1299         /*
1300          * If the chain is builtin, and does not have any rule,
1301          * then the one that we're inserting is becoming the head
1302          * and thus needs the builtin flag.
1303          */
1304         head = chain_head->data;
1305         if (head->builtin < 0)
1306                 *builtin = -1;
1307         else if (insert || chain_head == chain_tail->prev) {
1308                 *builtin = head->builtin;
1309                 head->builtin = -1;
1310         }
1311
1312         return new_entry;
1313
1314 err:
1315         g_free(new_entry);
1316
1317         return NULL;
1318 }
1319
1320 static int iptables_append_rule(struct connman_iptables *table,
1321                                 struct iptables_ip *ip,
1322                                 const char *chain_name,
1323                                 const char *target_name,
1324                                 struct xtables_target *xt_t,
1325                                 struct xtables_rule_match *xt_rm)
1326 {
1327         struct connman_iptables_entry *new_entry;
1328         int builtin = -1, ret;
1329         GList *chain_tail;
1330
1331         DBG("table %s chain %s", table->name, chain_name);
1332
1333         chain_tail = find_chain_tail(table, chain_name);
1334         if (!chain_tail)
1335                 return -EINVAL;
1336
1337         new_entry = prepare_rule_inclusion(table, ip, chain_name, target_name,
1338                                         xt_t, &builtin, xt_rm, false);
1339
1340         if (!new_entry)
1341                 return -EINVAL;
1342
1343         switch (new_entry->type) {
1344         case AF_INET:
1345                 if (new_entry->entry)
1346                         break;
1347         case AF_INET6:
1348                 if (new_entry->entry6)
1349                         break;
1350         default:
1351                 ret = -EINVAL;
1352                 goto err;
1353         }
1354
1355         ret = iptables_add_entry(table, new_entry, chain_tail->prev,
1356                                         builtin, -1);
1357         if (ret < 0)
1358                 goto err;
1359
1360         /*
1361          * Free only the container, not the content  iptables_add_entry()
1362          * allocates new containers for entries.
1363          */
1364         g_free(new_entry);
1365
1366         return ret;
1367
1368 err:
1369         iptables_entry_free(new_entry);
1370
1371         return ret;
1372 }
1373
1374 static int iptables_insert_rule(struct connman_iptables *table,
1375                                 struct iptables_ip *ip,
1376                                 const char *chain_name,
1377                                 const char *target_name,
1378                                 struct xtables_target *xt_t,
1379                                 struct xtables_rule_match *xt_rm)
1380 {
1381         struct connman_iptables_entry *new_entry;
1382         int builtin = -1, ret;
1383         GList *chain_head;
1384
1385         DBG("table %s chain %s", table->name, chain_name);
1386
1387         chain_head = find_chain_head(table, chain_name);
1388         if (!chain_head)
1389                 return -EINVAL;
1390
1391         new_entry = prepare_rule_inclusion(table, ip, chain_name, target_name,
1392                                         xt_t, &builtin, xt_rm, true);
1393
1394         if (!new_entry)
1395                 return -EINVAL;
1396
1397         switch (new_entry->type) {
1398         case AF_INET:
1399                 if (new_entry->entry)
1400                         break;
1401         case AF_INET6:
1402                 if (new_entry->entry6)
1403                         break;
1404         default:
1405                 ret = -EINVAL;
1406                 goto err;
1407         }
1408
1409         if (builtin == -1)
1410                 chain_head = chain_head->next;
1411
1412         ret = iptables_add_entry(table, new_entry, chain_head, builtin, -1);
1413         if (ret < 0)
1414                 goto err;
1415
1416         /*
1417          * Free only the container, not the content  iptables_add_entry()
1418          * allocates new containers for entries.
1419          */
1420         g_free(new_entry);
1421
1422         return ret;
1423
1424 err:
1425         iptables_entry_free(new_entry);
1426
1427         return ret;
1428 }
1429
1430 static bool is_same_ipt_entry(struct ipt_entry *i_e1,
1431                                         struct ipt_entry *i_e2)
1432 {
1433         if (memcmp(&i_e1->ip, &i_e2->ip, sizeof(struct ipt_ip)) != 0)
1434                 return false;
1435
1436         if (i_e1->target_offset != i_e2->target_offset)
1437                 return false;
1438
1439         if (i_e1->next_offset != i_e2->next_offset)
1440                 return false;
1441
1442         return true;
1443 }
1444
1445 /* A copy of is_same_ipt_entry with IPv6 structures */
1446 static bool is_same_ip6t_entry(struct ip6t_entry *i_e1,
1447                                         struct ip6t_entry *i_e2)
1448 {
1449         if (memcmp(&i_e1->ipv6, &i_e2->ipv6, sizeof(struct ip6t_ip6)) != 0)
1450                 return false;
1451
1452         if (i_e1->target_offset != i_e2->target_offset)
1453                 return false;
1454
1455         if (i_e1->next_offset != i_e2->next_offset)
1456                 return false;
1457
1458         return true;
1459 }
1460
1461 static bool is_same_iptables_entry(struct connman_iptables_entry *e1,
1462                                                 struct connman_iptables_entry *e2)
1463 {
1464         if (e1->type != e2->type)
1465                 return false;
1466
1467         switch (e1->type) {
1468         case AF_INET:
1469                 return is_same_ipt_entry(e1->entry, e2->entry);
1470         case AF_INET6:
1471                 return is_same_ip6t_entry(e1->entry6, e2->entry6);
1472         }
1473
1474         return false;
1475 }
1476
1477 static bool is_same_target(struct xt_entry_target *xt_e_t1,
1478                                         struct xt_entry_target *xt_e_t2)
1479 {
1480         unsigned int i;
1481
1482         if (!xt_e_t1 || !xt_e_t2)
1483                 return false;
1484
1485         if (g_strcmp0(xt_e_t1->u.user.name, "") == 0 &&
1486                         g_strcmp0(xt_e_t2->u.user.name, "") == 0) {
1487                 /* fallthrough */
1488                 return true;
1489
1490         /*
1491          * IPT_STANDARD_TARGET and IP6T_STANDARD_TARGET are defined by
1492          * XT_STANDARD_TARGET
1493          */
1494         } else if (g_strcmp0(xt_e_t1->u.user.name, XT_STANDARD_TARGET) == 0) {
1495                 struct xt_standard_target *xt_s_t1;
1496                 struct xt_standard_target *xt_s_t2;
1497
1498                 xt_s_t1 = (struct xt_standard_target *) xt_e_t1;
1499                 xt_s_t2 = (struct xt_standard_target *) xt_e_t2;
1500
1501                 if (xt_s_t1->verdict != xt_s_t2->verdict)
1502                         return false;
1503         } else {
1504                 if (xt_e_t1->u.target_size != xt_e_t2->u.target_size)
1505                         return false;
1506
1507                 if (g_strcmp0(xt_e_t1->u.user.name, xt_e_t2->u.user.name) != 0)
1508                         return false;
1509
1510                 for (i = 0; i < xt_e_t1->u.target_size -
1511                                 sizeof(struct xt_standard_target); i++) {
1512                         if ((xt_e_t1->data[i] ^ xt_e_t2->data[i]) != 0)
1513                                 return false;
1514                 }
1515         }
1516
1517         return true;
1518 }
1519
1520 static bool is_same_match(struct xt_entry_match *xt_e_m1,
1521                                 struct xt_entry_match *xt_e_m2)
1522 {
1523         unsigned int i;
1524
1525         if (!xt_e_m1 || !xt_e_m2)
1526                 return false;
1527
1528         if (xt_e_m1->u.match_size != xt_e_m2->u.match_size)
1529                 return false;
1530
1531         if (xt_e_m1->u.user.revision != xt_e_m2->u.user.revision)
1532                 return false;
1533
1534         if (g_strcmp0(xt_e_m1->u.user.name, xt_e_m2->u.user.name) != 0)
1535                 return false;
1536
1537         for (i = 0; i < xt_e_m1->u.match_size - sizeof(struct xt_entry_match);
1538                         i++) {
1539                 if ((xt_e_m1->data[i] ^ xt_e_m2->data[i]) != 0)
1540                         return false;
1541         }
1542
1543         return true;
1544 }
1545
1546 static GList *find_existing_rule(struct connman_iptables *table,
1547                                 struct iptables_ip *ip,
1548                                 const char *chain_name,
1549                                 const char *target_name,
1550                                 struct xtables_target *xt_t,
1551                                 GList *matches,
1552                                 struct xtables_rule_match *xt_rm)
1553 {
1554         GList *chain_tail, *chain_head, *list;
1555         struct xt_entry_target *xt_e_t = NULL;
1556         struct xt_entry_match *xt_e_m = NULL;
1557         struct connman_iptables_entry *entry;
1558         struct connman_iptables_entry *entry_test;
1559         int builtin;
1560
1561         chain_head = find_chain_head(table, chain_name);
1562         if (!chain_head)
1563                 return NULL;
1564
1565         chain_tail = find_chain_tail(table, chain_name);
1566         if (!chain_tail)
1567                 return NULL;
1568
1569         if (!xt_t && !matches)
1570                 return NULL;
1571
1572         entry_test = new_rule(ip, target_name, xt_t, xt_rm);
1573
1574         switch (entry_test->type) {
1575         case AF_INET:
1576                 if (!entry_test->entry)
1577                         return NULL;
1578                 break;
1579         case AF_INET6:
1580                 if (!entry_test->entry6)
1581                         return NULL;
1582                 break;
1583         default:
1584                 return NULL;
1585         }
1586
1587         if (xt_t)
1588                 xt_e_t = iptables_entry_get_target(entry_test);
1589         if (matches)
1590                 xt_e_m = (struct xt_entry_match *)
1591                                 iptables_entry_get_elems(entry_test);
1592
1593         entry = chain_head->data;
1594         builtin = entry->builtin;
1595
1596         if (builtin >= 0)
1597                 list = chain_head;
1598         else
1599                 list = chain_head->next;
1600
1601         for (; list != chain_tail->prev; list = list->next) {
1602                 struct connman_iptables_entry *tmp;
1603
1604                 tmp = list->data;
1605
1606                 if (!is_same_iptables_entry(entry_test, tmp))
1607                         continue;
1608
1609                 if (xt_t) {
1610                         struct xt_entry_target *tmp_xt_e_t = NULL;
1611
1612                         tmp_xt_e_t = iptables_entry_get_target(tmp);
1613
1614                         if (!is_same_target(tmp_xt_e_t, xt_e_t))
1615                                 continue;
1616                 }
1617
1618                 if (matches) {
1619                         struct xt_entry_match *tmp_xt_e_m;
1620
1621                         tmp_xt_e_m = (struct xt_entry_match *)
1622                                         iptables_entry_get_elems(tmp);
1623
1624                         if (!is_same_match(tmp_xt_e_m, xt_e_m))
1625                                 continue;
1626                 }
1627
1628                 break;
1629         }
1630
1631         iptables_entry_free(entry_test);
1632
1633         if (list != chain_tail->prev)
1634                 return list;
1635
1636         return NULL;
1637 }
1638
1639 static int iptables_delete_rule(struct connman_iptables *table,
1640                                 struct iptables_ip *ip,
1641                                 const char *chain_name,
1642                                 const char *target_name,
1643                                 struct xtables_target *xt_t,
1644                                 GList *matches,
1645                                 struct xtables_rule_match *xt_rm)
1646 {
1647         struct connman_iptables_entry *entry;
1648         GList *chain_head, *chain_tail, *list;
1649         int builtin, removed;
1650
1651         DBG("table %s chain %s", table->name, chain_name);
1652
1653         removed = 0;
1654
1655         chain_head = find_chain_head(table, chain_name);
1656         if (!chain_head)
1657                 return -EINVAL;
1658
1659         chain_tail = find_chain_tail(table, chain_name);
1660         if (!chain_tail)
1661                 return -EINVAL;
1662
1663         list = find_existing_rule(table, ip, chain_name, target_name,
1664                                                 xt_t, matches, xt_rm);
1665
1666         if (!list)
1667                 return -EINVAL;
1668
1669         entry = chain_head->data;
1670         builtin = entry->builtin;
1671
1672         if (builtin >= 0 && list == chain_head) {
1673                 /*
1674                  * We are about to remove the first rule in the
1675                  * chain. In this case we need to store the builtin
1676                  * value to the new chain_head.
1677                  *
1678                  * Note, for builtin chains, chain_head->next is
1679                  * always valid. A builtin chain has always a policy
1680                  * rule at the end.
1681                  */
1682                 chain_head = chain_head->next;
1683
1684                 entry = chain_head->data;
1685                 entry->builtin = builtin;
1686         }
1687
1688         entry = list->data;
1689         if (!entry)
1690                 return -EINVAL;
1691
1692         /* We have deleted a rule,
1693          * all references should be bumped accordingly */
1694         if (list->next)
1695                 update_targets_reference(table, list->next->data,
1696                                                 list->data, true);
1697
1698         removed += remove_table_entry(table, entry);
1699
1700         if (builtin >= 0)
1701                 delete_update_hooks(table, builtin, chain_head, removed);
1702
1703         update_offsets(table);
1704
1705         return 0;
1706 }
1707
1708 static int iptables_change_policy(struct connman_iptables *table,
1709                                 const char *chain_name, const char *policy)
1710 {
1711         GList *chain_head, *chain_tail;
1712         struct connman_iptables_entry *entry;
1713         struct xt_entry_target *target;
1714         struct xt_standard_target *t;
1715         int verdict;
1716
1717         DBG("table %s chain %s policy %s", table->name, chain_name, policy);
1718
1719         verdict = target_to_verdict(policy);
1720         switch (verdict) {
1721         case -NF_ACCEPT - 1:
1722         case -NF_DROP - 1:
1723                 break;
1724         default:
1725                 return -EINVAL;
1726         }
1727
1728         chain_head = find_chain_head(table, chain_name);
1729         if (!chain_head)
1730                 return -EINVAL;
1731
1732         entry = chain_head->data;
1733         if (entry->builtin < 0)
1734                 return -EINVAL;
1735
1736         chain_tail = find_chain_tail(table, chain_name);
1737         if (!chain_tail)
1738                 return -EINVAL;
1739
1740         entry = chain_tail->prev->data;
1741
1742         target = iptables_entry_get_target(entry);
1743
1744         if (!target)
1745                 return -EINVAL;
1746
1747         t = (struct xt_standard_target *)target;
1748         if (t->verdict != verdict)
1749                 entry->counter_idx = -1;
1750         t->verdict = verdict;
1751
1752         return 0;
1753 }
1754
1755 static struct ipt_replace *iptables_blob(struct connman_iptables *table)
1756 {
1757         struct ipt_replace *r;
1758         GList *list;
1759         struct connman_iptables_entry *e;
1760         unsigned char *entry_index;
1761
1762         r = g_try_malloc0(sizeof(struct ipt_replace) + table->size);
1763         if (!r)
1764                 return NULL;
1765
1766         memset(r, 0, sizeof(*r) + table->size);
1767
1768         r->counters = g_try_malloc0(sizeof(struct xt_counters)
1769                                 * table->old_entries);
1770         if (!r->counters) {
1771                 g_free(r);
1772                 return NULL;
1773         }
1774
1775         g_stpcpy(r->name, table->info->name);
1776         r->num_entries = table->num_entries;
1777         r->size = table->size;
1778
1779         r->num_counters = table->old_entries;
1780         r->valid_hooks  = table->info->valid_hooks;
1781
1782         memcpy(r->hook_entry, table->hook_entry, sizeof(table->hook_entry));
1783         memcpy(r->underflow, table->underflow, sizeof(table->underflow));
1784
1785         entry_index = (unsigned char *)r->entries;
1786         for (list = table->entries; list; list = list->next) {
1787                 e = list->data;
1788
1789                 memcpy(entry_index, e->entry, e->entry->next_offset);
1790                 entry_index += e->entry->next_offset;
1791         }
1792
1793         return r;
1794 }
1795
1796 /* A copy of iptables_blob() with IPv6 structures */
1797 static struct ip6t_replace *ip6tables_blob(struct connman_iptables *table)
1798 {
1799         struct ip6t_replace *r;
1800         GList *list;
1801         struct connman_iptables_entry *e;
1802         unsigned char *entry_index;
1803
1804         r = g_try_malloc0(sizeof(struct ip6t_replace) + table->size);
1805         if (!r)
1806                 return NULL;
1807
1808         memset(r, 0, sizeof(*r) + table->size);
1809
1810         r->counters = g_try_malloc0(sizeof(struct xt_counters)
1811                                 * table->old_entries);
1812         if (!r->counters) {
1813                 g_free(r);
1814                 return NULL;
1815         }
1816
1817         g_stpcpy(r->name, table->info6->name);
1818         r->num_entries = table->num_entries;
1819         r->size = table->size;
1820
1821         r->num_counters = table->old_entries;
1822         r->valid_hooks  = table->info6->valid_hooks;
1823
1824         memcpy(r->hook_entry, table->hook_entry, sizeof(table->hook_entry));
1825         memcpy(r->underflow, table->underflow, sizeof(table->underflow));
1826
1827         entry_index = (unsigned char *)r->entries;
1828         for (list = table->entries; list; list = list->next) {
1829                 e = list->data;
1830
1831                 memcpy(entry_index, e->entry6, e->entry6->next_offset);
1832                 entry_index += e->entry6->next_offset;
1833         }
1834
1835         return r;
1836 }
1837
1838 static void dump_ip(struct connman_iptables_entry *entry)
1839 {
1840         char *iniface, *outiface;
1841         char ip_string[INET6_ADDRSTRLEN];
1842         char ip_mask[INET6_ADDRSTRLEN];
1843
1844         switch (entry->type) {
1845         case AF_INET:
1846                 iniface = entry->entry->ip.iniface;
1847                 outiface = entry->entry->ip.outiface;
1848                 break;
1849         case AF_INET6:
1850                 iniface = entry->entry6->ipv6.iniface;
1851                 outiface = entry->entry6->ipv6.outiface;
1852                 break;
1853         default:
1854                 return;
1855         }
1856
1857         if (strlen(iniface))
1858                 DBG("\tin %s", iniface);
1859
1860         if (strlen(outiface))
1861                 DBG("\tout %s", outiface);
1862
1863         if (entry->type == AF_INET) {
1864                 if (inet_ntop(entry->type, &entry->entry->ip.src, ip_string,
1865                                 INET6_ADDRSTRLEN) && inet_ntop(entry->type,
1866                                 &entry->entry->ip.smsk, ip_mask,
1867                                 INET6_ADDRSTRLEN))
1868                         DBG("\tsrc %s/%s", ip_string, ip_mask);
1869
1870                 if (inet_ntop(entry->type, &entry->entry->ip.dst, ip_string,
1871                                 INET6_ADDRSTRLEN) && inet_ntop(entry->type,
1872                                 &entry->entry->ip.dmsk, ip_mask,
1873                                 INET6_ADDRSTRLEN))
1874                         DBG("\tdst %s/%s", ip_string, ip_mask);
1875         }
1876
1877         if (entry->type == AF_INET6) {
1878                 if (inet_ntop(entry->type, &entry->entry6->ipv6.src, ip_string,
1879                                 INET6_ADDRSTRLEN) && inet_ntop(entry->type,
1880                                 &entry->entry6->ipv6.smsk, ip_mask,
1881                                 INET6_ADDRSTRLEN))
1882                         DBG("\tsrc %s/%s", ip_string, ip_mask);
1883
1884                 if (inet_ntop(entry->type, &entry->entry6->ipv6.dst, ip_string,
1885                                 INET6_ADDRSTRLEN) && inet_ntop(entry->type,
1886                                 &entry->entry6->ipv6.dmsk, ip_mask,
1887                                 INET6_ADDRSTRLEN))
1888                         DBG("\tdst %s/%s", ip_string, ip_mask);
1889         }
1890 }
1891
1892 static void dump_target(struct connman_iptables_entry *entry)
1893 {
1894         struct xtables_target *xt_t;
1895         struct xt_entry_target *target;
1896         int err;
1897
1898         target = iptables_entry_get_target(entry);
1899
1900         if (!target)
1901                 return;
1902
1903         if (!g_strcmp0(target->u.user.name, get_standard_target(entry->type))) {
1904                 struct xt_standard_target *t;
1905
1906                 t = (struct xt_standard_target *)target;
1907
1908                 switch (t->verdict) {
1909                 case XT_RETURN:
1910                         DBG("\ttarget RETURN");
1911                         break;
1912
1913                 case -NF_ACCEPT - 1:
1914                         DBG("\ttarget ACCEPT");
1915                         break;
1916
1917                 case -NF_DROP - 1:
1918                         DBG("\ttarget DROP");
1919                         break;
1920
1921                 case -NF_QUEUE - 1:
1922                         DBG("\ttarget QUEUE");
1923                         break;
1924
1925                 case -NF_STOP - 1:
1926                         DBG("\ttarget STOP");
1927                         break;
1928
1929                 default:
1930                         DBG("\tJUMP %u", t->verdict);
1931                         break;
1932                 }
1933
1934                 enable_jmp();
1935
1936                 if ((err = setjmp(env_state)) != 0) {
1937                         DBG("setjmp() called by longjmp() with value %d", err);
1938                         disable_jmp();
1939                         return;
1940                 }
1941
1942                 xt_t = xtables_find_target(get_standard_target(entry->type),
1943                                                 XTF_LOAD_MUST_SUCCEED);
1944
1945                 disable_jmp();
1946
1947                 if (xt_t->print)
1948                         xt_t->print(NULL, target, 1);
1949         } else {
1950                 enable_jmp();
1951
1952                 if ((err = setjmp(env_state)) != 0) {
1953                         DBG("setjmp() called by longjmp() with value %d", err);
1954                         disable_jmp();
1955                         return;
1956                 }
1957
1958                 xt_t = xtables_find_target(target->u.user.name, XTF_TRY_LOAD);
1959
1960                 disable_jmp();
1961
1962                 if (!xt_t) {
1963                         DBG("\ttarget %s", target->u.user.name);
1964                         return;
1965                 }
1966
1967                 if (xt_t->print) {
1968                         DBG("\ttarget ");
1969                         xt_t->print(NULL, target, 1);
1970                 }
1971         }
1972
1973         if (xt_t == xt_t->next)
1974                 free(xt_t);
1975 }
1976
1977 static void dump_match(struct connman_iptables_entry *entry)
1978 {
1979         struct xtables_match *xt_m;
1980         struct xt_entry_match *match;
1981         u_int16_t target_offset;
1982         int err;
1983
1984         target_offset = iptables_entry_get_target_offset(entry);
1985
1986         switch (entry->type) {
1987         case AF_INET:
1988                 if (entry->entry->elems == (unsigned char *)entry->entry +
1989                                 target_offset)
1990                         return;
1991                 break;
1992         case AF_INET6:
1993                 if (entry->entry6->elems == (unsigned char *)entry->entry6 +
1994                                 target_offset)
1995                         return;
1996                 break;
1997         default:
1998                 return;
1999         }
2000
2001         match = (struct xt_entry_match *) iptables_entry_get_elems(entry);
2002
2003         if (!strlen(match->u.user.name))
2004                 return;
2005
2006         enable_jmp();
2007
2008         if ((err = setjmp(env_state)) != 0) {
2009                 DBG("setjmp() called by longjmp() with value %d", err);
2010                 disable_jmp();
2011                 return;
2012         }
2013
2014         xt_m = xtables_find_match(match->u.user.name, XTF_TRY_LOAD, NULL);
2015
2016         disable_jmp();
2017
2018         if (!xt_m)
2019                 goto out;
2020
2021         if (xt_m->print) {
2022                 DBG("\tmatch ");
2023                 xt_m->print(NULL, match, 1);
2024
2025                 return;
2026         }
2027         if (xt_m == xt_m->next)
2028                 free(xt_m);
2029
2030 out:
2031         DBG("\tmatch %s", match->u.user.name);
2032
2033 }
2034
2035 static int dump_entry(struct connman_iptables_entry *entry, int builtin,
2036                         unsigned int hook, size_t size, unsigned int offset,
2037                         void *user_data)
2038 {
2039         struct xt_entry_target *target;
2040         char *char_entry;
2041
2042         target = iptables_entry_get_target(entry);
2043
2044         if (!target)
2045                 return -EINVAL;
2046
2047         if (offset + iptables_entry_get_next_offset(entry) == size) {
2048                 DBG("\tEnd of CHAIN");
2049                 return 0;
2050         }
2051
2052         switch (entry->type) {
2053         case AF_INET:
2054                 char_entry = (char *)entry->entry;
2055                 break;
2056         case AF_INET6:
2057                 char_entry = (char *)entry->entry6;
2058                 break;
2059         default:
2060                 return 0;
2061         }
2062
2063         if (!g_strcmp0(target->u.user.name, IPT_ERROR_TARGET)) {
2064                 DBG("\tUSER CHAIN (%s) match %p  target %p",
2065                         target->data, iptables_entry_get_elems(entry),
2066                         char_entry + iptables_entry_get_target_offset(entry));
2067
2068                 return 0;
2069         } else if (builtin >= 0) {
2070                 DBG("\tCHAIN (%s) match %p  target %p",
2071                         hooknames[builtin], iptables_entry_get_elems(entry),
2072                         char_entry + iptables_entry_get_target_offset(entry));
2073         } else {
2074                 DBG("\tRULE  match %p  target %p",
2075                         iptables_entry_get_elems(entry),
2076                         char_entry + iptables_entry_get_target_offset(entry));
2077         }
2078
2079         dump_match(entry);
2080         dump_target(entry);
2081         dump_ip(entry);
2082
2083         return 0;
2084 }
2085
2086 static void dump_table(struct connman_iptables *table)
2087 {
2088         struct connman_iptables_entry entry = { 0 };
2089         unsigned int *hook_entry;
2090         unsigned int *underflow;
2091         unsigned int valid_hooks;
2092         unsigned int size;
2093
2094         hook_entry = iptables_table_get_info_hook_entry(table);
2095         underflow = iptables_table_get_info_underflow(table);
2096         valid_hooks = iptables_table_get_info_valid_hooks(table);
2097         size = iptables_table_get_info_size(table);
2098         
2099         DBG("%s valid_hooks=0x%08x, num_entries=%u, size=%u",
2100                 iptables_table_get_info_name(table),
2101                 valid_hooks,
2102                 iptables_table_get_info_num_entries(table),
2103                 size);
2104
2105         DBG("entry hook: pre/in/fwd/out/post %d/%d/%d/%d/%d",
2106                 hook_entry[NF_IP_PRE_ROUTING],
2107                 hook_entry[NF_IP_LOCAL_IN],
2108                 hook_entry[NF_IP_FORWARD],
2109                 hook_entry[NF_IP_LOCAL_OUT],
2110                 hook_entry[NF_IP_POST_ROUTING]);
2111         DBG("underflow:  pre/in/fwd/out/post %d/%d/%d/%d/%d",
2112                 underflow[NF_IP_PRE_ROUTING],
2113                 underflow[NF_IP_LOCAL_IN],
2114                 underflow[NF_IP_FORWARD],
2115                 underflow[NF_IP_LOCAL_OUT],
2116                 underflow[NF_IP_POST_ROUTING]);
2117
2118         entry.type = table->type;
2119
2120         switch (table->type) {
2121         case AF_INET:
2122                 entry.entry = table->blob_entries->entrytable;
2123                 break;
2124         case AF_INET6:
2125                 entry.entry6 = table->blob_entries6->entrytable;
2126         }
2127
2128         iterate_entries(&entry,
2129                 valid_hooks,
2130                 hook_entry,
2131                 underflow,
2132                 size,
2133                 print_entry, dump_entry);
2134 }
2135
2136 static const char *iptables_replace_get_name(struct iptables_replace *replace)
2137 {
2138         if (!replace)
2139                 return NULL;
2140
2141         switch (replace->type) {
2142         case AF_INET:
2143                 return replace->r->name;
2144         case AF_INET6:
2145                 return replace->r6->name;
2146         }
2147
2148         return NULL;
2149 }
2150
2151 static unsigned int iptables_replace_get_valid_hooks(
2152                                         struct iptables_replace *replace)
2153 {
2154         if (!replace)
2155                 return 0;
2156
2157         switch (replace->type) {
2158         case AF_INET:
2159                 return replace->r->valid_hooks;
2160         case AF_INET6:
2161                 return replace->r6->valid_hooks;
2162         }
2163
2164         return 0;
2165 }
2166
2167 static unsigned int iptables_replace_get_num_entries(
2168                                         struct iptables_replace *replace)
2169 {
2170         if (!replace)
2171                 return 0;
2172
2173         switch (replace->type) {
2174         case AF_INET:
2175                 return replace->r->num_entries;
2176         case AF_INET6:
2177                 return replace->r6->num_entries;
2178         }
2179
2180         return 0;
2181 }
2182
2183 static unsigned int *iptables_replace_get_hook_entry(
2184                                         struct iptables_replace *replace)
2185 {
2186         if (!replace)
2187                 return NULL;
2188
2189         switch (replace->type) {
2190         case AF_INET:
2191                 return replace->r->hook_entry;
2192         case AF_INET6:
2193                 return replace->r6->hook_entry;
2194         }
2195
2196         return NULL;
2197 }
2198
2199 static unsigned int *iptables_replace_get_underflow(
2200                                         struct iptables_replace *replace)
2201 {
2202         if (!replace)
2203                 return NULL;
2204
2205         switch (replace->type) {
2206         case AF_INET:
2207                 return replace->r->underflow;
2208         case AF_INET6:
2209                 return replace->r6->underflow;
2210         }
2211
2212         return NULL;
2213 }
2214
2215 static unsigned int iptables_replace_get_size(struct iptables_replace *replace)
2216 {
2217         if (!replace)
2218                 return 0;
2219
2220         switch (replace->type) {
2221         case AF_INET:
2222                 return replace->r->size;
2223         case AF_INET6:
2224                 return replace->r6->size;
2225         }
2226
2227         return 0;
2228 }
2229
2230 static void dump_replace(struct iptables_replace *repl)
2231 {
2232         struct connman_iptables_entry entry = { 0 };
2233         unsigned int *hook_entry;
2234         unsigned int *underflow;
2235         unsigned int valid_hooks;
2236         unsigned int size;
2237         
2238         hook_entry = iptables_replace_get_hook_entry(repl);
2239         underflow = iptables_replace_get_underflow(repl);
2240         valid_hooks = iptables_replace_get_valid_hooks(repl);
2241         size = iptables_replace_get_size(repl);
2242
2243         switch (repl->type) {
2244         case AF_INET:
2245                 entry.entry = repl->r->entries;
2246                 break;
2247         case AF_INET6:
2248                 entry.entry6 = repl->r6->entries;
2249                 break;
2250         default:
2251                 return;
2252         }
2253
2254         DBG("%s valid_hooks 0x%08x  num_entries %u  size %u",
2255                         iptables_replace_get_name(repl),
2256                         valid_hooks,
2257                         iptables_replace_get_num_entries(repl), size);
2258
2259         DBG("entry hook: pre/in/fwd/out/post %d/%d/%d/%d/%d",
2260                 hook_entry[NF_IP_PRE_ROUTING],
2261                 hook_entry[NF_IP_LOCAL_IN],
2262                 hook_entry[NF_IP_FORWARD],
2263                 hook_entry[NF_IP_LOCAL_OUT],
2264                 hook_entry[NF_IP_POST_ROUTING]);
2265         DBG("underflow:  pre/in/fwd/out/post %d/%d/%d/%d/%d",
2266                 underflow[NF_IP_PRE_ROUTING],
2267                 underflow[NF_IP_LOCAL_IN],
2268                 underflow[NF_IP_FORWARD],
2269                 underflow[NF_IP_LOCAL_OUT],
2270                 underflow[NF_IP_POST_ROUTING]);
2271
2272         iterate_entries(&entry, valid_hooks, hook_entry, underflow,
2273                         size, print_entry, dump_entry);
2274 }
2275
2276 static int iptables_get_entries(struct connman_iptables *table)
2277 {
2278         socklen_t entry_size;
2279         int err;
2280
2281         switch (table->type) {
2282         case AF_INET:
2283                 entry_size = sizeof(struct ipt_get_entries) + table->info->size;
2284
2285                 err = getsockopt(table->ipt_sock, IPPROTO_IP,
2286                                 IPT_SO_GET_ENTRIES, table->blob_entries,
2287                                 &entry_size);
2288                 break;
2289         case AF_INET6:
2290                 entry_size = sizeof(struct ip6t_get_entries) +
2291                                         table->info6->size;
2292
2293                 err = getsockopt(table->ipt_sock, IPPROTO_IPV6,
2294                                 IP6T_SO_GET_ENTRIES, table->blob_entries6,
2295                                 &entry_size);
2296                 break;
2297         default:
2298                 return -EINVAL;
2299         }
2300
2301         if (err < 0)
2302                 return -errno;
2303
2304         return 0;
2305 }
2306
2307 static int iptables_replace(struct connman_iptables *table,
2308                                         struct iptables_replace *r)
2309 {
2310         int err;
2311
2312         switch (r->type) {
2313         case AF_INET:
2314                 if (!r->r)
2315                         return -EINVAL;
2316
2317                 err = setsockopt(table->ipt_sock, IPPROTO_IP,
2318                                 IPT_SO_SET_REPLACE, r->r,
2319                                 sizeof(*r->r) + r->r->size);
2320                 break;
2321         case AF_INET6:
2322                 if (!r->r6)
2323                         return -EINVAL;
2324
2325                 err = setsockopt(table->ipt_sock, IPPROTO_IPV6,
2326                                 IP6T_SO_SET_REPLACE, r->r6,
2327                                 sizeof(*r->r6) + r->r6->size);
2328                 break;
2329         default:
2330                 return -EINVAL;
2331         }
2332
2333         if (err < 0)
2334                 return -errno;
2335
2336         return 0;
2337 }
2338
2339 static int iptables_add_counters(struct connman_iptables *table,
2340                 struct xt_counters_info *c)
2341 {
2342         int err;
2343         int level;
2344         int optname;
2345
2346         switch (table->type) {
2347         case AF_INET:
2348                 level = IPPROTO_IP;
2349                 optname = IPT_SO_SET_ADD_COUNTERS;
2350                 break;
2351         case AF_INET6:
2352                 level = IPPROTO_IPV6;
2353                 optname = IP6T_SO_SET_ADD_COUNTERS;
2354                 break;
2355         default:
2356                 return -EINVAL;
2357         }
2358
2359         err = setsockopt(table->ipt_sock, level, optname, c,
2360                 sizeof(*c) + sizeof(struct xt_counters) * c->num_counters);
2361
2362         if (err < 0)
2363                 return -errno;
2364
2365         return 0;
2366 }
2367
2368 static int add_entry(struct connman_iptables_entry *entry, int builtin,
2369                         unsigned int hook, size_t size, unsigned offset,
2370                         void *user_data)
2371 {
2372         struct connman_iptables *table = user_data;
2373         struct connman_iptables_entry new_entry = { 0 };
2374         u_int16_t next_offset;
2375         
2376         new_entry.type = entry->type;
2377         next_offset = iptables_entry_get_next_offset(entry);
2378
2379         switch (entry->type) {
2380         case AF_INET:
2381                 new_entry.entry = g_try_malloc0(next_offset);
2382                 if (!new_entry.entry)
2383                         return -ENOMEM;
2384
2385                 memcpy(new_entry.entry, entry->entry, next_offset);
2386                 break;
2387         case AF_INET6:
2388                 new_entry.entry6 = g_try_malloc0(next_offset);
2389                 if (!new_entry.entry6)
2390                         return -ENOMEM;
2391
2392                 memcpy(new_entry.entry6, entry->entry6, next_offset);
2393                 break;
2394         default:
2395                 return -EINVAL;
2396         }
2397         
2398         return iptables_add_entry(table, &new_entry, NULL, builtin,
2399                                 table->num_entries);
2400 }
2401
2402 static void table_cleanup(struct connman_iptables *table)
2403 {
2404         GList *list;
2405         struct connman_iptables_entry *entry;
2406
2407         if (!table)
2408                 return;
2409
2410         if (table->ipt_sock >= 0)
2411                 close(table->ipt_sock);
2412
2413         for (list = table->entries; list; list = list->next) {
2414                 entry = list->data;
2415
2416                 iptables_entry_free(entry);
2417         }
2418
2419         g_list_free(table->entries);
2420         g_free(table->name);
2421         
2422         if (table->type == AF_INET) {
2423                 g_free(table->info);
2424                 g_free(table->blob_entries);
2425         }
2426
2427         if (table->type == AF_INET6) {
2428                 g_free(table->info6);
2429                 g_free(table->blob_entries6);
2430         }
2431
2432         g_free(table);
2433 }
2434
2435 static int setup_xtables(int type);
2436 static void reset_xtables();
2437
2438 static struct connman_iptables *iptables_init(int type, const char *table_name)
2439 {
2440         struct connman_iptables *table = NULL;
2441         struct connman_iptables_entry entry = { 0 };
2442         char *iptables_mod = NULL;
2443         char *module = NULL;
2444         socklen_t s;
2445
2446         switch(type) {
2447         case AF_INET:
2448                 iptables_mod = g_strdup("ip_tables");
2449                 module = g_strconcat("iptable_", table_name, NULL);
2450                 break;
2451         case AF_INET6:
2452                 iptables_mod = g_strdup("ip6_tables");
2453                 module = g_strconcat("ip6table_", table_name, NULL);
2454                 break;
2455         default:
2456                 return NULL;
2457         }
2458
2459         DBG("%d %s", type, table_name);
2460
2461         if (setup_xtables(type))
2462                 return NULL;
2463
2464         if (xtables_insmod(iptables_mod, NULL, TRUE) != 0)
2465                 DBG("%s module loading gives error but trying anyway",
2466                                 iptables_mod);
2467
2468         g_free(iptables_mod);
2469
2470         if (xtables_insmod(module, NULL, TRUE) != 0)
2471                 DBG("%s module loading gives error but trying anyway", module);
2472
2473         g_free(module);
2474
2475         table = g_try_new0(struct connman_iptables, 1);
2476         if (!table)
2477                 return NULL;
2478
2479         table->type = entry.type = type;
2480
2481         table->ipt_sock = socket(type, SOCK_RAW | SOCK_CLOEXEC, IPPROTO_RAW);
2482         if (table->ipt_sock < 0)
2483                 goto err;
2484
2485         switch (type) {
2486         case AF_INET:
2487                 table->info = g_try_new0(struct ipt_getinfo, 1);
2488                 if (!table->info)
2489                         goto err;
2490
2491                 s = sizeof(*table->info);
2492                 g_stpcpy(table->info->name, table_name);
2493
2494                 if (getsockopt(table->ipt_sock, IPPROTO_IP, IPT_SO_GET_INFO,
2495                                                         table->info, &s) < 0) {
2496                         connman_error("iptables support missing error %d (%s)",
2497                                                         errno, strerror(errno));
2498                         goto err;
2499                 }
2500
2501                 table->blob_entries = g_try_malloc0(
2502                                         sizeof(struct ipt_get_entries) +
2503                                         table->info->size);
2504                 if (!table->blob_entries)
2505                         goto err;
2506
2507                 g_stpcpy(table->blob_entries->name, table_name);
2508                 table->blob_entries->size = table->info->size;
2509
2510                 break;
2511         case AF_INET6:
2512                 table->info6 = g_try_new0(struct ip6t_getinfo, 1);
2513                 if (!table->info6)
2514                         goto err;
2515
2516                 s = sizeof(*table->info6);
2517                 g_stpcpy(table->info6->name, table_name);
2518
2519                 if (getsockopt(table->ipt_sock, IPPROTO_IPV6, IP6T_SO_GET_INFO,
2520                                                 table->info6, &s) < 0) {
2521                         connman_error("ip6tables support missing error %d (%s)",
2522                                         errno, strerror(errno));
2523                         goto err;
2524                 }
2525
2526                 table->blob_entries6 = g_try_malloc0(
2527                                         sizeof(struct ip6t_get_entries) +
2528                                         table->info6->size);
2529                 if (!table->blob_entries6)
2530                         goto err;
2531
2532                 g_stpcpy(table->blob_entries6->name, table_name);
2533                 table->blob_entries6->size = table->info6->size;
2534
2535                 break;
2536         }
2537
2538         if (iptables_get_entries(table) < 0)
2539                 goto err;
2540
2541         table->num_entries = 0;
2542         table->size = 0;
2543
2544         switch (type) {
2545         case AF_INET:
2546                 table->old_entries = table->info->num_entries;
2547
2548                 memcpy(table->underflow, table->info->underflow,
2549                                         sizeof(table->info->underflow));
2550                 memcpy(table->hook_entry, table->info->hook_entry,
2551                                         sizeof(table->info->hook_entry));
2552
2553                 entry.entry = table->blob_entries->entrytable;
2554                 break;
2555         case AF_INET6:
2556                 table->old_entries = table->info6->num_entries;
2557
2558                 memcpy(table->underflow, table->info6->underflow,
2559                                 sizeof(table->info6->underflow));
2560                 memcpy(table->hook_entry, table->info6->hook_entry,
2561                                         sizeof(table->info6->hook_entry));
2562
2563                 entry.entry6 = table->blob_entries6->entrytable;
2564                 break;
2565         }
2566
2567         iterate_entries(&entry,
2568                         iptables_table_get_info_valid_hooks(table),
2569                         iptables_table_get_info_hook_entry(table),
2570                         iptables_table_get_info_underflow(table),
2571                         iptables_table_get_entries_size(table),
2572                         add_entry,
2573                         table);
2574
2575         if (debug_enabled)
2576                 dump_table(table);
2577
2578         reset_xtables();
2579
2580         return table;
2581
2582 err:
2583         table_cleanup(table);
2584         reset_xtables();
2585
2586         return NULL;
2587 }
2588
2589 static struct option iptables_opts[] = {
2590         {.name = "append",        .has_arg = 1, .val = 'A'},
2591         {.name = "compare",       .has_arg = 1, .val = 'C'},
2592         {.name = "delete",        .has_arg = 1, .val = 'D'},
2593         {.name = "flush-chain",   .has_arg = 1, .val = 'F'},
2594         {.name = "insert",        .has_arg = 1, .val = 'I'},
2595         {.name = "list",          .has_arg = 2, .val = 'L'},
2596         {.name = "new-chain",     .has_arg = 1, .val = 'N'},
2597         {.name = "policy",        .has_arg = 1, .val = 'P'},
2598         {.name = "delete-chain",  .has_arg = 1, .val = 'X'},
2599         {.name = "destination",   .has_arg = 1, .val = 'd'},
2600         {.name = "in-interface",  .has_arg = 1, .val = 'i'},
2601         {.name = "jump",          .has_arg = 1, .val = 'j'},
2602         {.name = "match",         .has_arg = 1, .val = 'm'},
2603         {.name = "out-interface", .has_arg = 1, .val = 'o'},
2604         {.name = "source",        .has_arg = 1, .val = 's'},
2605         {.name = "table",         .has_arg = 1, .val = 't'},
2606         {.name = "protocol",      .has_arg = 1, .val = 'p'},
2607         {NULL},
2608 };
2609
2610 void iptables_exit(enum xtables_exittype status, const char *msg, ...)
2611                         __attribute__((noreturn, format(printf,2,3)));
2612
2613 void iptables_exit(enum xtables_exittype status, const char *msg, ...)
2614 {
2615         va_list args;
2616         gchar str[256] = { 0 };
2617
2618         switch (status) {
2619         case OTHER_PROBLEM:
2620                 DBG("OTHER_PROBLEM");
2621                 break;
2622         case PARAMETER_PROBLEM:
2623                 DBG("PARAMETER_PROBLEM");
2624                 break;
2625         case VERSION_PROBLEM:
2626                 DBG("VERSION_PROBLEM");
2627                 break;
2628         case RESOURCE_PROBLEM:
2629                 DBG("RESOURCE_PROBLEM");
2630                 break;
2631         case XTF_ONLY_ONCE:
2632                 DBG("XTF_ONLY_ONCE");
2633                 break;
2634         case XTF_NO_INVERT:
2635                 DBG("XTF_NO_INVERT");
2636                 break;
2637         case XTF_BAD_VALUE:
2638                 DBG("XTF_BAD_VALUE");
2639                 break;
2640         case XTF_ONE_ACTION:
2641                 DBG("XTF_ONE_ACTION");
2642                 break;
2643         }
2644
2645         va_start(args, msg);
2646         vsnprintf(str, 256, msg, args);
2647         va_end(args);
2648
2649         connman_error("iptables rule error: %s", str);
2650
2651         if (can_jmp()) {
2652                 DBG("calling longjmp()");
2653                  /* enum xtables_exittype begins from 1 */
2654                 longjmp(env_state, status);
2655         }
2656
2657         connman_error("exit because of iptables error");
2658
2659         exit(status);
2660 }
2661
2662 struct xtables_globals iptables_globals = {
2663         .option_offset = 0,
2664         .opts = iptables_opts,
2665         .orig_opts = iptables_opts,
2666         .exit_err = iptables_exit,
2667 #if XTABLES_VERSION_CODE > 10
2668         .compat_rev = xtables_compatible_revision,
2669 #endif
2670 };
2671
2672 struct xtables_globals ip6tables_globals = {
2673         .option_offset = 0,
2674         .opts = iptables_opts,
2675         .orig_opts = iptables_opts,
2676         .exit_err = iptables_exit,
2677 #if XTABLES_VERSION_CODE > 10
2678         .compat_rev = xtables_compatible_revision,
2679 #endif
2680 };
2681
2682 static struct xtables_target *prepare_target(struct connman_iptables *table,
2683                                                         const char *target_name)
2684 {
2685         struct xtables_target *xt_t = NULL;
2686         bool is_builtin, is_user_defined;
2687         GList *chain_head = NULL;
2688         size_t target_size;
2689         int err;
2690
2691         is_builtin = false;
2692         is_user_defined = false;
2693         
2694         DBG("target %s", target_name);
2695         
2696         if (!table)
2697                 return NULL;
2698
2699         if (is_builtin_target(target_name))
2700                 is_builtin = true;
2701         else {
2702                 chain_head = find_chain_head(table, target_name);
2703                 if (chain_head && chain_head->next)
2704                         is_user_defined = true;
2705         }
2706
2707         enable_jmp();
2708
2709         if ((err = setjmp(env_state)) != 0) {
2710                 DBG("setjmp() called by longjmp() with value %d", err);
2711                 disable_jmp();
2712                 return NULL;
2713         }
2714
2715         if (is_builtin || is_user_defined)
2716                 xt_t = xtables_find_target(get_standard_target(table->type),
2717                                                 XTF_LOAD_MUST_SUCCEED);
2718         else 
2719                 xt_t = xtables_find_target(target_name, XTF_TRY_LOAD);
2720
2721         disable_jmp();
2722
2723         if (!xt_t)
2724                 return NULL;
2725
2726         switch (table->type) {
2727         case AF_INET:
2728                 target_size = XT_ALIGN(sizeof(struct ipt_entry_target)) +
2729                                         xt_t->size;
2730                 break;
2731         case AF_INET6:
2732                 target_size = XT_ALIGN(sizeof(struct ip6t_entry_target)) +
2733                                         xt_t->size;
2734                 break;
2735         default:
2736                 return NULL;
2737         }
2738
2739         xt_t->t = g_try_malloc0(target_size);
2740         if (!xt_t->t)
2741                 return NULL;
2742
2743         xt_t->t->u.target_size = target_size;
2744
2745         if (is_builtin || is_user_defined) {
2746                 struct xt_standard_target *target;
2747
2748                 target = (struct xt_standard_target *)(xt_t->t);
2749                 g_stpcpy(target->target.u.user.name,
2750                                 get_standard_target(table->type));
2751
2752                 if (is_builtin)
2753                         target->verdict = target_to_verdict(target_name);
2754                 else if (is_user_defined) {
2755                         struct connman_iptables_entry *target_rule;
2756
2757                         target_rule = chain_head->next->data;
2758                         target->verdict = target_rule->offset;
2759                 }
2760         } else {
2761                 g_stpcpy(xt_t->t->u.user.name, target_name);
2762                 xt_t->t->u.user.revision = xt_t->revision;
2763                 if (xt_t->init)
2764                         xt_t->init(xt_t->t);
2765         }
2766
2767         switch (table->type) {
2768         case AF_INET:
2769                 if (xt_t->x6_options)
2770                         iptables_globals.opts =
2771                                 xtables_options_xfrm(
2772                                         iptables_globals.orig_opts,
2773                                         iptables_globals.opts,
2774                                         xt_t->x6_options,
2775                                         &xt_t->option_offset);
2776                 else
2777                         iptables_globals.opts =
2778                                 xtables_merge_options(
2779                                         iptables_globals.orig_opts,
2780                                         iptables_globals.opts,
2781                                         xt_t->extra_opts,
2782                                         &xt_t->option_offset);
2783
2784                 if (!iptables_globals.opts) {
2785                         g_free(xt_t->t);
2786                         xt_t = NULL;
2787                 }
2788
2789                 break;
2790         case AF_INET6:
2791                 if (xt_t->x6_options)
2792                         ip6tables_globals.opts =
2793                                 xtables_options_xfrm(
2794                                         ip6tables_globals.orig_opts,
2795                                         ip6tables_globals.opts,
2796                                         xt_t->x6_options,
2797                                         &xt_t->option_offset);
2798                 else
2799                         ip6tables_globals.opts =
2800                                 xtables_merge_options(
2801                                         ip6tables_globals.orig_opts,
2802                                         ip6tables_globals.opts,
2803                                         xt_t->extra_opts,
2804                                         &xt_t->option_offset);
2805
2806                 if (!ip6tables_globals.opts) {
2807                         g_free(xt_t->t);
2808                         xt_t = NULL;
2809                 }
2810
2811                 break;
2812         }
2813
2814         return xt_t;
2815 }
2816
2817 static struct xtables_match *prepare_matches(struct connman_iptables *table,
2818                                         struct xtables_rule_match **xt_rm,
2819                                         const char *match_name)
2820 {
2821         struct xtables_match *xt_m;
2822         size_t match_size;
2823         int err;
2824
2825         if (!table || !match_name)
2826                 return NULL;
2827
2828         enable_jmp();
2829
2830         if ((err = setjmp(env_state)) != 0) {
2831                 DBG("setjmp() called by longjmp() with value %d", err);
2832                 disable_jmp();
2833                 return NULL;
2834         }
2835
2836         xt_m = xtables_find_match(match_name, XTF_LOAD_MUST_SUCCEED, xt_rm);
2837
2838         disable_jmp();
2839
2840         switch (table->type) {
2841         case AF_INET:
2842                 match_size = XT_ALIGN(sizeof(struct ipt_entry_match)) +
2843                                                 xt_m->size;
2844                 break;
2845         case AF_INET6:
2846                 match_size = XT_ALIGN(sizeof(struct ip6t_entry_match)) +
2847                                                 xt_m->size;
2848                 break;
2849         default:
2850                 return NULL;
2851         }
2852
2853         xt_m->m = g_try_malloc0(match_size);
2854         if (!xt_m->m)
2855                 return NULL;
2856
2857         xt_m->m->u.match_size = match_size;
2858         g_stpcpy(xt_m->m->u.user.name, xt_m->name);
2859         xt_m->m->u.user.revision = xt_m->revision;
2860
2861         if (xt_m->init)
2862                 xt_m->init(xt_m->m);
2863
2864         switch (table->type) {
2865         case AF_INET:
2866                 if (xt_m->x6_options)
2867                         iptables_globals.opts =
2868                                 xtables_options_xfrm(
2869                                         iptables_globals.orig_opts,
2870                                         iptables_globals.opts,
2871                                         xt_m->x6_options,
2872                                         &xt_m->option_offset);
2873                 else
2874                         iptables_globals.opts =
2875                                 xtables_merge_options(
2876                                         iptables_globals.orig_opts,
2877                                         iptables_globals.opts,
2878                                         xt_m->extra_opts,
2879                                         &xt_m->option_offset);
2880
2881                 if (!iptables_globals.opts) {
2882                         g_free(xt_m->m);
2883
2884                         if (xt_m == xt_m->next)
2885                                 free(xt_m);
2886
2887                         xt_m = NULL;
2888                 }
2889
2890                 break;
2891         case AF_INET6:
2892                 if (xt_m->x6_options)
2893                         ip6tables_globals.opts =
2894                                 xtables_options_xfrm(
2895                                         ip6tables_globals.orig_opts,
2896                                         ip6tables_globals.opts,
2897                                         xt_m->x6_options,
2898                                         &xt_m->option_offset);
2899                 else
2900                         ip6tables_globals.opts =
2901                                 xtables_merge_options(
2902                                         ip6tables_globals.orig_opts,
2903                                         ip6tables_globals.opts,
2904                                         xt_m->extra_opts,
2905                                         &xt_m->option_offset);
2906
2907                 if (!ip6tables_globals.opts) {
2908                         g_free(xt_m->m);
2909
2910                         if (xt_m == xt_m->next)
2911                                 free(xt_m);
2912
2913                         xt_m = NULL;
2914                 }
2915
2916                 break;
2917         }
2918
2919         return xt_m;
2920 }
2921
2922 static int parse_ip_and_mask(const char *str, struct in_addr *ip,
2923                                 struct in_addr *mask)
2924 {
2925         char **tokens;
2926         uint32_t prefixlength;
2927         uint32_t tmp;
2928         int err;
2929
2930         tokens = g_strsplit(str, "/", 2);
2931         if (!tokens)
2932                 return -1;
2933
2934         if (!inet_pton(AF_INET, tokens[0], ip)) {
2935                 err = -1;
2936                 goto out;
2937         }
2938
2939         if (tokens[1]) {
2940                 prefixlength = strtol(tokens[1], NULL, 10);
2941                 if (prefixlength > 32) {
2942                         err = -1;
2943                         goto out;
2944                 } else if (prefixlength == 32) {
2945                         tmp = 0xffffffff;
2946                 } else {
2947                         tmp = ~(0xffffffff >> prefixlength);
2948                 }
2949         } else {
2950                 tmp = 0xffffffff;
2951         }
2952
2953         mask->s_addr = htonl(tmp);
2954         ip->s_addr = ip->s_addr & mask->s_addr;
2955         err = 0;
2956 out:
2957         g_strfreev(tokens);
2958
2959         return err;
2960 }
2961
2962 static int parse_ipv6_and_mask(const char *str, struct in6_addr *ip,
2963                                 struct in6_addr *mask)
2964 {
2965         char **tokens;
2966         uint32_t prefixlength;
2967         struct in6_addr in6;
2968         int i, j;
2969         int err;
2970
2971         tokens = g_strsplit(str, "/", 2);
2972         if (!tokens)
2973                 return -1;
2974
2975         if (!inet_pton(AF_INET6, tokens[0], ip)) {
2976                 err = -1;
2977                 goto out;
2978         }
2979
2980         if (tokens[1]) {
2981                 prefixlength = strtol(tokens[1], NULL, 10);
2982                 if (prefixlength > 128) {
2983                         err = -1;
2984                         goto out;
2985                 }
2986         } else {
2987                 prefixlength = 128;
2988         }
2989
2990         /*
2991          * This part was adapted from (no need to re-invent the wheel):
2992          * https://gitlab.com/ipcalc/ipcalc/blob/master/ipcalc.c#L733
2993          */
2994         memset(&in6, 0, sizeof(struct in6_addr));
2995
2996         for (i = prefixlength, j = 0; i > 0; i -= 8, j++) {
2997                 if (i >= 8)
2998                         in6.s6_addr[j] = 0xff;
2999                 else
3000                         in6.s6_addr[j] = (unsigned long)(0xffU << (8 - i));
3001         }
3002
3003         memcpy(mask, &in6, sizeof(struct in6_addr));
3004
3005         for (i = 0; i < 16 ; i++)
3006                 ip->s6_addr[i] = ip->s6_addr[i] & mask->s6_addr[i];
3007
3008         err = 0;
3009 out:
3010         g_strfreev(tokens);
3011
3012         return err;
3013 }
3014
3015 static struct connman_iptables *get_table(int type, const char *table_name)
3016 {
3017         struct connman_iptables *table = NULL;
3018
3019         if (!table_name)
3020                 table_name = "filter";
3021
3022         table = hash_table_lookup(type, table_name);
3023
3024         if (table)
3025                 return table;
3026
3027         table = iptables_init(type, table_name);
3028
3029         if (!table)
3030                 return NULL;
3031
3032         if (table->name)
3033                 g_free(table->name);
3034
3035         table->name = g_strdup(table_name);
3036         
3037         hash_table_replace(type, table->name, table);
3038
3039         return table;
3040 }
3041
3042 struct parse_context {
3043         int type;
3044         int argc;
3045         char **argv;
3046         struct ipt_ip *ip;
3047         struct ip6t_ip6 *ipv6;
3048         struct xtables_target *xt_t;
3049         GList *xt_m;
3050         struct xtables_rule_match *xt_rm;
3051         uint16_t proto;
3052 };
3053
3054 static int prepare_getopt_args(const char *str, struct parse_context *ctx)
3055 {
3056         char **tokens;
3057         int i;
3058
3059         tokens = g_strsplit_set(str, " ", -1);
3060
3061         i = g_strv_length(tokens);
3062
3063         /* Add space for the argv[0] value */
3064         ctx->argc = i + 1;
3065
3066         /* Don't forget the last NULL entry */
3067         ctx->argv = g_try_malloc0((ctx->argc + 1) * sizeof(char *));
3068         if (!ctx->argv) {
3069                 g_strfreev(tokens);
3070                 return -ENOMEM;
3071         }
3072
3073         /*
3074          * getopt_long() jumps over the first token; we need to add some
3075          * random argv[0] entry.
3076          */
3077         ctx->argv[0] = g_strdup("argh");
3078         for (i = 1; i < ctx->argc; i++)
3079                 ctx->argv[i] = tokens[i - 1];
3080
3081         g_free(tokens);
3082
3083         return 0;
3084 }
3085
3086 static int parse_xt_modules(int c, bool invert,
3087                                 struct parse_context *ctx)
3088 {
3089         struct xtables_match *m;
3090         struct xtables_rule_match *rm;
3091         struct ipt_entry fw;
3092         struct ip6t_entry fw6;
3093         int err;
3094
3095         switch (ctx->type) {
3096         case AF_INET:
3097                 memset(&fw, 0, sizeof(fw));
3098
3099                 /* The SNAT parser wants to know the protocol. */
3100                 if (ctx->proto == 0)
3101                         ctx->proto = IPPROTO_IP;
3102
3103                 fw.ip.proto = ctx->proto;
3104                 break;
3105         case AF_INET6:
3106                 memset(&fw6, 0, sizeof(fw6));
3107
3108                 if (ctx->proto == 0)
3109                         ctx->proto = IPPROTO_IPV6;
3110
3111                 fw6.ipv6.proto = ctx->proto;
3112
3113                 /* Flags must be set for IPv6 if protocol is set. */
3114                 fw6.ipv6.flags |= IP6T_F_PROTO;
3115
3116                 break;
3117         default:
3118                 return 0;
3119         }
3120
3121         for (rm = ctx->xt_rm; rm; rm = rm->next) {
3122                 if (rm->completed != 0)
3123                         continue;
3124
3125                 m = rm->match;
3126
3127                 if (!m->x6_parse && !m->parse)
3128                         continue;
3129
3130                 if (c < (int) m->option_offset ||
3131                                 c >= (int) m->option_offset
3132                                         + XT_OPTION_OFFSET_SCALE)
3133                         continue;
3134
3135                 enable_jmp();
3136
3137                 if ((err = setjmp(env_state)) != 0) {
3138                         DBG("setjmp() called by longjmp() with value %d", err);
3139                         disable_jmp();
3140                         return -EINVAL;
3141                 }
3142
3143                 switch (ctx->type) {
3144                 case AF_INET:
3145                         xtables_option_mpcall(c, ctx->argv, invert, m, &fw);
3146                         break;
3147                 case AF_INET6:
3148                         xtables_option_mpcall(c, ctx->argv, invert, m, &fw6);
3149                         break;
3150                 }
3151
3152                 disable_jmp();
3153         }
3154
3155         if (!ctx->xt_t)
3156                 return 0;
3157
3158         if (!ctx->xt_t->x6_parse && !ctx->xt_t->parse)
3159                 return 0;
3160
3161         if (c < (int) ctx->xt_t->option_offset ||
3162                         c >= (int) ctx->xt_t->option_offset
3163                                         + XT_OPTION_OFFSET_SCALE)
3164                 return 0;
3165
3166         enable_jmp();
3167
3168         if ((err = setjmp(env_state)) != 0) {
3169                 DBG("setjmp() called by longjmp() with value %d", err);
3170                 disable_jmp();
3171                 return -EINVAL;
3172         }
3173
3174         switch (ctx->type) {
3175         case AF_INET:
3176                 xtables_option_tpcall(c, ctx->argv, invert, ctx->xt_t, &fw);
3177                 break;
3178         case AF_INET6:
3179                 xtables_option_tpcall(c, ctx->argv, invert, ctx->xt_t, &fw6);
3180                 break;
3181         }
3182
3183         disable_jmp();
3184
3185         return 0;
3186 }
3187
3188 static int final_check_xt_modules(struct parse_context *ctx)
3189 {
3190         struct xtables_rule_match *rm;
3191         int err;
3192
3193         for (rm = ctx->xt_rm; rm; rm = rm->next) {
3194                 enable_jmp();
3195
3196                 if ((err = setjmp(env_state)) != 0) {
3197                         DBG("setjmp() called by longjmp() with value %d", err);
3198                         disable_jmp();
3199                         return -EINVAL;
3200                 }
3201
3202                 xtables_option_mfcall(rm->match);
3203
3204                 disable_jmp();
3205         }
3206
3207         enable_jmp();
3208
3209         if ((err = setjmp(env_state)) != 0) {
3210                 DBG("setjmp() called by longjmp() with value %d", err);
3211                 disable_jmp();
3212                 return -EINVAL;
3213         }
3214
3215         if (ctx->xt_t)
3216                 xtables_option_tfcall(ctx->xt_t);
3217
3218         disable_jmp();
3219
3220         return 0;
3221 }
3222
3223 static int parse_rule_spec(struct connman_iptables *table,
3224                                 struct parse_context *ctx)
3225 {
3226         /*
3227          * How the parser works:
3228          *
3229          *  - If getopt finds 's', 'd', 'i', 'o'.
3230          *    just extract the information.
3231          *  - if '!' is found, set the invert flag to true and
3232          *    removes the '!' from the optarg string and jumps
3233          *    back to getopt to reparse the current optarg string.
3234          *    After reparsing the invert flag is reset to false.
3235          *  - If 'm' or 'j' is found then call either
3236          *    prepare_matches() or prepare_target(). Those function
3237          *    will modify (extend) the longopts for getopt_long.
3238          *    That means getopt will change its matching context according
3239          *    the loaded target.
3240          *
3241          *    Here an example with iptables-test
3242          *
3243          *    argv[0] = ./tools/iptables-test
3244          *    argv[1] = -t
3245          *    argv[2] = filter
3246          *    argv[3] = -A
3247          *    argv[4] = INPUT
3248          *    argv[5] = -m
3249          *    argv[6] = mark
3250          *    argv[7] = --mark
3251          *    argv[8] = 999
3252          *    argv[9] = -j
3253          *    argv[10] = LOG
3254          *
3255          *    getopt found 'm' then the optarg is "mark" and optind 7
3256          *    The longopts array containts before hitting the `case 'm'`
3257          *
3258          *    val A has_arg 1 name append
3259          *    val C has_arg 1 name compare
3260          *    val D has_arg 1 name delete
3261          *    val F has_arg 1 name flush-chain
3262          *    val I has_arg 1 name insert
3263          *    val L has_arg 2 name list
3264          *    val N has_arg 1 name new-chain
3265          *    val P has_arg 1 name policy
3266          *    val X has_arg 1 name delete-chain
3267          *    val d has_arg 1 name destination
3268          *    val i has_arg 1 name in-interface
3269          *    val j has_arg 1 name jump
3270          *    val m has_arg 1 name match
3271          *    val o has_arg 1 name out-interface
3272          *    val s has_arg 1 name source
3273          *    val t has_arg 1 name table
3274          *
3275          *    After executing the `case 'm'` block longopts is
3276          *
3277          *    val A has_arg 1 name append
3278          *    val C has_arg 1 name compare
3279          *    val D has_arg 1 name delete
3280          *    val F has_arg 1 name flush-chain
3281          *    val I has_arg 1 name insert
3282          *    val L has_arg 2 name list
3283          *    val N has_arg 1 name new-chain
3284          *    val P has_arg 1 name policy
3285          *    val X has_arg 1 name delete-chain
3286          *    val d has_arg 1 name destination
3287          *    val i has_arg 1 name in-interface
3288          *    val j has_arg 1 name jump
3289          *    val m has_arg 1 name match
3290          *    val o has_arg 1 name out-interface
3291          *    val s has_arg 1 name source
3292          *    val t has_arg 1 name table
3293          *    val   has_arg 1 name mark
3294          *
3295          *    So the 'mark' matcher has added the 'mark' options
3296          *    and getopt will then return c '256' optarg "999" optind 9
3297          *    And we will hit the 'default' statement which then
3298          *    will call the matchers parser (xt_m->parser() or
3299          *    xtables_option_mpcall() depending on which version
3300          *    of libxtables is found.
3301          */
3302         struct xtables_match *xt_m;
3303         bool invert = false;
3304         int len, c, err;
3305
3306         if (ctx->type != table->type) {
3307                 DBG("ctx->type %d does not match table->type %d", ctx->type,
3308                                 table->type);
3309                 return -EINVAL;
3310         }
3311
3312         switch (ctx->type) {
3313         case AF_INET:
3314                 ctx->ip = g_try_new0(struct ipt_ip, 1);
3315                 if (!ctx->ip)
3316                         return -ENOMEM;
3317
3318                 break;
3319         case AF_INET6:
3320                 ctx->ipv6 = g_try_new0(struct ip6t_ip6, 1);
3321                 if (!ctx->ipv6)
3322                         return -ENOMEM;
3323
3324                 break;
3325         default:
3326                 return -EINVAL;
3327         }
3328
3329         /*
3330          * Tell getopt_long not to generate error messages for unknown
3331          * options and also reset optind back to 0.
3332          */
3333         opterr = 0;
3334         optind = 0;
3335
3336         while ((c = getopt_long(ctx->argc, ctx->argv,
3337                                         "-:d:i:o:s:m:j:p:",
3338                                         ctx->type == AF_INET ?
3339                                                 iptables_globals.opts :
3340                                                 ip6tables_globals.opts,
3341                                         NULL)) != -1) {
3342                 switch (c) {
3343                 case 's':
3344                         if (ctx->type == AF_INET) {
3345                                 /* Source specification */
3346                                 if (!parse_ip_and_mask(optarg,
3347                                                         &ctx->ip->src,
3348                                                         &ctx->ip->smsk))
3349                                         break;
3350
3351                                 if (invert)
3352                                         ctx->ip->invflags |= IPT_INV_SRCIP;
3353                         }
3354
3355                         if (ctx->type == AF_INET6) {
3356                                 if (!parse_ipv6_and_mask(optarg,
3357                                                         &ctx->ipv6->src,
3358                                                         &ctx->ipv6->smsk))
3359                                         break;
3360
3361                                 if (invert)
3362                                         ctx->ipv6->invflags |= IP6T_INV_SRCIP;
3363                         }
3364
3365                         break;
3366                 case 'd':
3367                         if (ctx->type == AF_INET) {
3368                                 /* Destination specification */
3369                                 if (!parse_ip_and_mask(optarg,
3370                                                         &ctx->ip->dst,
3371                                                         &ctx->ip->dmsk))
3372                                         break;
3373
3374                                 if (invert)
3375                                         ctx->ip->invflags |= IPT_INV_DSTIP;
3376                         }
3377
3378                         if (ctx->type == AF_INET6) {
3379                                 /* Destination specification */
3380                                 if (!parse_ipv6_and_mask(optarg,
3381                                                         &ctx->ipv6->dst,
3382                                                         &ctx->ipv6->dmsk))
3383                                         break;
3384
3385                                 if (invert)
3386                                         ctx->ip->invflags |= IP6T_INV_DSTIP;
3387                         }
3388                         
3389                         break;
3390                 case 'i':
3391                         /* In interface specification */
3392                         len = strlen(optarg);
3393
3394                         if (len + 1 > IFNAMSIZ)
3395                                 break;
3396
3397                         if (ctx->type == AF_INET) {
3398                                 g_stpcpy(ctx->ip->iniface, optarg);
3399                                 memset(ctx->ip->iniface_mask, 0xff, len + 1);
3400
3401                                 if (invert)
3402                                         ctx->ip->invflags |= IPT_INV_VIA_IN;
3403                         }
3404                         
3405                         if (ctx->type == AF_INET6) {
3406                                 g_stpcpy(ctx->ipv6->iniface, optarg);
3407                                 memset(ctx->ipv6->iniface_mask, 0xff, len + 1);
3408
3409                                 if (invert)
3410                                         ctx->ipv6->invflags |= IP6T_INV_VIA_IN;
3411                         }
3412
3413                         break;
3414                 case 'o':
3415                         /* Out interface specification */
3416                         len = strlen(optarg);
3417
3418                         if (len + 1 > IFNAMSIZ)
3419                                 break;
3420
3421                         if (ctx->type == AF_INET) {
3422                                 g_stpcpy(ctx->ip->outiface, optarg);
3423                                 memset(ctx->ip->outiface_mask, 0xff, len + 1);
3424
3425                                 if (invert)
3426                                         ctx->ip->invflags |= IPT_INV_VIA_OUT;
3427                         }
3428
3429                         if (ctx->type == AF_INET6) {
3430                                 g_stpcpy(ctx->ipv6->outiface, optarg);
3431                                 memset(ctx->ipv6->outiface_mask, 0xff, len + 1);
3432
3433                                 if (invert)
3434                                         ctx->ipv6->invflags |= IP6T_INV_VIA_OUT;
3435                         }
3436
3437                         break;
3438                 case 'm':
3439                         /* Matches */
3440                         xt_m = prepare_matches(table, &ctx->xt_rm, optarg);
3441                         if (!xt_m) {
3442                                 err = -EINVAL;
3443                                 goto out;
3444                         }
3445                         ctx->xt_m = g_list_append(ctx->xt_m, xt_m);
3446
3447                         break;
3448                 case 'p':
3449                         enable_jmp();
3450
3451                         if ((err = setjmp(env_state)) != 0) {
3452                                 DBG("setjmp() called by longjmp() with value "
3453                                                         "%d", err);
3454                                 disable_jmp();
3455
3456                                 /* Errors from parse_rule_spec are negative */
3457                                 err = -EINVAL;
3458                                 goto out;
3459                         }
3460
3461                         ctx->proto = xtables_parse_protocol(optarg);
3462
3463                         disable_jmp();
3464
3465                         /*
3466                          * If protocol was set add it to ipt_ip.
3467                          * xtables_parse_protocol() returns 0 or
3468                          * UINT16_MAX (-1) on error
3469                          */
3470                         if (ctx->proto > 0 && ctx->proto < UINT16_MAX) {
3471                                 if (ctx->type == AF_INET)
3472                                         ctx->ip->proto = ctx->proto;
3473
3474                                 if (ctx->type == AF_INET6) {
3475                                         ctx->ipv6->proto = ctx->proto;
3476
3477                                         /*
3478                                          * Flags must be set for IPv6 if
3479                                          * protocol is set.
3480                                          */
3481                                         ctx->ipv6->flags |= IP6T_F_PROTO;
3482                                 }
3483                         }
3484                         break;
3485                 case 'j':
3486                         /* Target */
3487                         ctx->xt_t = prepare_target(table, optarg);
3488                         if (!ctx->xt_t) {
3489                                 err = -EINVAL;
3490                                 goto out;
3491                         }
3492
3493                         break;
3494                 case 1:
3495                         if (optarg[0] == '!' && optarg[1] == '\0') {
3496                                 invert = true;
3497
3498                                 /* Remove the '!' from the optarg */
3499                                 optarg[0] = '\0';
3500
3501                                 /*
3502                                  * And recall getopt_long without resetting
3503                                  * invert.
3504                                  */
3505                                 continue;
3506                         }
3507
3508                         break;
3509                 default:
3510                         err = parse_xt_modules(c, invert, ctx);
3511                         if (err == 1)
3512                                 continue;
3513                         else if (err == -EINVAL)
3514                                 goto out;
3515
3516                         break;
3517                 }
3518
3519                 invert = false;
3520         }
3521
3522         err = final_check_xt_modules(ctx);
3523
3524 out:
3525         return err;
3526 }
3527
3528 static int current_type = -1;
3529
3530 static int setup_xtables(int type)
3531 {
3532         int err;
3533
3534         DBG("%d", type);
3535
3536         if (type == current_type)
3537                 return 0;
3538
3539         if (current_type != -1)
3540                 reset_xtables();
3541
3542         switch (type) {
3543         case AF_INET:
3544                 err = xtables_init_all(&iptables_globals, NFPROTO_IPV4);
3545                 break;
3546         case AF_INET6:
3547                 err = xtables_init_all(&ip6tables_globals, NFPROTO_IPV6);
3548                 break;
3549         default:
3550                 return -1;
3551         }
3552         
3553         if (!err) {
3554                 current_type = type;
3555         } else {
3556                 connman_error("error initializing xtables");
3557                 current_type = -1;
3558                 reset_xtables();
3559         }
3560
3561         return err;
3562 }
3563
3564 static void reset_xtables(void)
3565 {
3566         struct xtables_match *xt_m;
3567         struct xtables_target *xt_t;
3568
3569         /*
3570          * As side effect parsing a rule sets some global flags
3571          * which will be evaluated/verified. Let's reset them
3572          * to ensure we can parse more than one rule.
3573          *
3574          * Clear all flags because the flags are only valid
3575          * for one rule.
3576          */
3577         for (xt_m = xtables_matches; xt_m; xt_m = xt_m->next)
3578                 xt_m->mflags = 0;
3579
3580         for (xt_t = xtables_targets; xt_t; xt_t = xt_t->next) {
3581                 xt_t->tflags = 0;
3582                 xt_t->used = 0;
3583         }
3584
3585         /*
3586          * We need also to free the memory implicitly allocated
3587          * during parsing (see xtables_options_xfrm()).
3588          * Note xt_params is actually iptables_globals.
3589          */
3590         if (xt_params->opts != xt_params->orig_opts) {
3591                 g_free(xt_params->opts);
3592                 xt_params->opts = xt_params->orig_opts;
3593         }
3594         xt_params->option_offset = 0;
3595 }
3596
3597 static void cleanup_parse_context(struct parse_context *ctx)
3598 {
3599         struct xtables_rule_match *rm, *tmp;
3600         GList *list;
3601
3602         g_strfreev(ctx->argv);
3603
3604         g_free(ctx->ip);
3605         g_free(ctx->ipv6);
3606
3607         if (ctx->xt_t) {
3608                 g_free(ctx->xt_t->t);
3609                 ctx->xt_t->t = NULL;
3610         }
3611
3612         for (list = ctx->xt_m; list; list = list->next) {
3613                 struct xtables_match *xt_m = list->data;
3614
3615                 g_free(xt_m->m);
3616
3617                 if (xt_m != xt_m->next)
3618                         continue;
3619
3620                 g_free(xt_m);
3621         }
3622         g_list_free(ctx->xt_m);
3623
3624         for (tmp = NULL, rm = ctx->xt_rm; rm; rm = rm->next) {
3625                 if (tmp)
3626                         g_free(tmp);
3627                 tmp = rm;
3628         }
3629         g_free(tmp);
3630
3631         g_free(ctx);
3632 }
3633
3634 int __connman_iptables_dump(int type, const char *table_name)
3635 {
3636         struct connman_iptables *table;
3637
3638         DBG("%d -t %s -L", type, table_name);
3639
3640         table = get_table(type, table_name);
3641         if (!table)
3642                 return -EINVAL;
3643
3644         dump_table(table);
3645
3646         return 0;
3647 }
3648
3649 int __connman_iptables_new_chain(int type,
3650                                         const char *table_name,
3651                                         const char *chain)
3652 {
3653         struct connman_iptables *table;
3654
3655         DBG("%d -t %s -N %s", type, table_name, chain);
3656
3657         table = get_table(type, table_name);
3658         if (!table) {
3659                 return -EINVAL;
3660         }
3661
3662         switch (type) {
3663         case AF_INET:
3664         case AF_INET6:
3665                 return iptables_add_chain(table, chain);
3666         }
3667
3668         return -EINVAL;
3669 }
3670
3671 int __connman_iptables_delete_chain(int type,
3672                                         const char *table_name,
3673                                         const char *chain)
3674 {
3675         struct connman_iptables *table;
3676
3677         DBG("%d -t %s -X %s", type, table_name, chain);
3678
3679         table = get_table(type, table_name);
3680         if (!table)
3681                 return -EINVAL;
3682
3683         return iptables_delete_chain(table, chain);
3684 }
3685
3686 int __connman_iptables_flush_chain(int type,
3687                                         const char *table_name,
3688                                         const char *chain)
3689 {
3690         struct connman_iptables *table;
3691
3692         DBG("%d -t %s -F %s", type, table_name, chain);
3693
3694         table = get_table(type, table_name);
3695         if (!table)
3696                 return -EINVAL;
3697
3698         return iptables_flush_chain(table, chain);
3699 }
3700
3701 int __connman_iptables_find_chain(int type,
3702                                         const char *table_name,
3703                                         const char *chain)
3704 {
3705         struct connman_iptables *table;
3706
3707         DBG("%d -t %s -F %s", type, table_name, chain);
3708
3709         table = get_table(type, table_name);
3710         if (!table)
3711                 return -EINVAL;
3712
3713         if(!find_chain_head(table, chain))
3714                 return -ENOENT; // Not Found
3715         
3716         return 0; // Found
3717 }
3718
3719 int __connman_iptables_change_policy(int type,
3720                                         const char *table_name,
3721                                         const char *chain,
3722                                         const char *policy)
3723 {
3724         struct connman_iptables *table;
3725
3726         DBG("%d -t %s -F %s", type, table_name, chain);
3727
3728         table = get_table(type, table_name);
3729         if (!table)
3730                 return -EINVAL;
3731
3732         return iptables_change_policy(table, chain, policy);
3733 }
3734
3735 static void iptables_ip_setup(struct iptables_ip *ip, struct parse_context *ctx)
3736 {
3737         if (!ip || !ctx)
3738                 return;
3739
3740         ip->type = ctx->type;
3741         ip->ip = ctx->ip;
3742         ip->ip6 = ctx->ipv6;
3743 }
3744
3745 int __connman_iptables_append(int type,
3746                                 const char *table_name,
3747                                 const char *chain,
3748                                 const char *rule_spec)
3749 {
3750         struct connman_iptables *table;
3751         struct parse_context *ctx;
3752         struct iptables_ip ip = { 0 };
3753         const char *target_name;
3754         int err;
3755
3756         err = setup_xtables(type);
3757         
3758         if (err < 0)
3759                 return err;
3760
3761         ctx = g_try_new0(struct parse_context, 1);
3762         if (!ctx)
3763                 return -ENOMEM;
3764
3765         ctx->type = type;
3766
3767         DBG("%d -t %s -A %s %s", type, table_name, chain, rule_spec);
3768
3769         err = prepare_getopt_args(rule_spec, ctx);
3770         if (err < 0)
3771                 goto out;
3772
3773         table = get_table(type, table_name);
3774         if (!table) {
3775                 err = -EINVAL;
3776                 goto out;
3777         }
3778
3779         err = parse_rule_spec(table, ctx);
3780         if (err < 0)
3781                 goto out;
3782
3783         if (!ctx->xt_t)
3784                 target_name = NULL;
3785         else
3786                 target_name = ctx->xt_t->name;
3787
3788         iptables_ip_setup(&ip, ctx);
3789
3790         err = iptables_append_rule(table, &ip, chain, target_name, ctx->xt_t,
3791                                                                 ctx->xt_rm);
3792 out:
3793         cleanup_parse_context(ctx);
3794         reset_xtables();
3795
3796         return err;
3797 }
3798
3799 int __connman_iptables_insert(int type,
3800                                 const char *table_name,
3801                                 const char *chain,
3802                                 const char *rule_spec)
3803 {
3804         struct connman_iptables *table;
3805         struct parse_context *ctx;
3806         struct iptables_ip ip = { 0 };
3807         const char *target_name;
3808         int err;
3809
3810         err = setup_xtables(type);
3811         
3812         if (err < 0)
3813                 return err;
3814
3815         ctx = g_try_new0(struct parse_context, 1);
3816         if (!ctx)
3817                 return -ENOMEM;
3818         
3819         ctx->type = type;
3820
3821         DBG("%d -t %s -I %s %s", type, table_name, chain, rule_spec);
3822
3823         err = prepare_getopt_args(rule_spec, ctx);
3824         if (err < 0)
3825                 goto out;
3826
3827         table = get_table(type, table_name);
3828         if (!table) {
3829                 err = -EINVAL;
3830                 goto out;
3831         }
3832
3833         err = parse_rule_spec(table, ctx);
3834         if (err < 0)
3835                 goto out;
3836
3837         if (!ctx->xt_t)
3838                 target_name = NULL;
3839         else
3840                 target_name = ctx->xt_t->name;
3841
3842         iptables_ip_setup(&ip, ctx);
3843
3844         err = iptables_insert_rule(table, &ip, chain, target_name, ctx->xt_t,
3845                                                                 ctx->xt_rm);
3846 out:
3847         cleanup_parse_context(ctx);
3848         reset_xtables();
3849
3850         return err;
3851 }
3852
3853 int __connman_iptables_delete(int type,
3854                                 const char *table_name,
3855                                 const char *chain,
3856                                 const char *rule_spec)
3857 {
3858         struct connman_iptables *table;
3859         struct parse_context *ctx;
3860         struct iptables_ip ip = { 0 };
3861         const char *target_name;
3862         int err;
3863
3864         err = setup_xtables(type);
3865         
3866         if (err < 0)
3867                 return err;
3868
3869         ctx = g_try_new0(struct parse_context, 1);
3870         if (!ctx)
3871                 return -ENOMEM;
3872         
3873         ctx->type = type;
3874
3875         DBG("%d -t %s -D %s %s", type, table_name, chain, rule_spec);
3876
3877         err = prepare_getopt_args(rule_spec, ctx);
3878         if (err < 0)
3879                 goto out;
3880
3881         table = get_table(type, table_name);
3882         if (!table) {
3883                 err = -EINVAL;
3884                 goto out;
3885         }
3886
3887         err = parse_rule_spec(table, ctx);
3888         if (err < 0)
3889                 goto out;
3890
3891         if (!ctx->xt_t)
3892                 target_name = NULL;
3893         else
3894                 target_name = ctx->xt_t->name;
3895
3896         iptables_ip_setup(&ip, ctx);
3897
3898         err = iptables_delete_rule(table, &ip, chain, target_name, ctx->xt_t,
3899                                 ctx->xt_m, ctx->xt_rm);
3900 out:
3901         cleanup_parse_context(ctx);
3902         reset_xtables();
3903
3904         return err;
3905 }
3906
3907 int __connman_iptables_commit(int type, const char *table_name)
3908 {
3909         struct connman_iptables *table;
3910         struct iptables_replace repl = { 0 };
3911         int err;
3912         struct xt_counters_info *counters;
3913         struct connman_iptables_entry *e;
3914         GList *list;
3915         unsigned int cnt;
3916
3917         err = setup_xtables(type);
3918         
3919         if (err < 0)
3920                 return err;
3921
3922         DBG("%d %s", type, table_name);
3923
3924         repl.type = type;
3925
3926         table = hash_table_lookup(type, table_name);
3927         if (!table)
3928                 return -EINVAL;
3929
3930         switch (type) {
3931         case AF_INET:
3932                 repl.r = iptables_blob(table);
3933                 if (!repl.r)
3934                         return -ENOMEM;
3935                 
3936                 break;
3937         case AF_INET6:
3938                 repl.r6 = ip6tables_blob(table);
3939                 if (!repl.r6)
3940                         return -ENOMEM;
3941         }
3942
3943         if (debug_enabled)
3944                 dump_replace(&repl);
3945
3946         err = iptables_replace(table, &repl);
3947
3948         if (err < 0)
3949                 goto out_free;
3950
3951         counters = g_try_malloc0(sizeof(*counters) +
3952                         sizeof(struct xt_counters) * table->num_entries);
3953         if (!counters) {
3954                 err = -ENOMEM;
3955                 goto out_hash_remove;
3956         }
3957         g_stpcpy(counters->name, iptables_table_get_info_name(table));
3958         counters->num_counters = table->num_entries;
3959         for (list = table->entries, cnt = 0; list; list = list->next, cnt++) {
3960                 e = list->data;
3961                 if (e->counter_idx >= 0) {
3962                 
3963                         switch (type) {
3964                         case AF_INET:
3965                                 counters->counters[cnt] =
3966                                         repl.r->counters[e->counter_idx];
3967                                 break;
3968                         case AF_INET6:
3969                                 counters->counters[cnt] =
3970                                         repl.r6->counters[e->counter_idx];
3971                                 break;
3972                         }
3973                 }
3974         }
3975         err = iptables_add_counters(table, counters);
3976         g_free(counters);
3977
3978         if (err < 0)
3979                 goto out_hash_remove;
3980
3981         err = 0;
3982
3983 out_hash_remove:
3984         hash_table_remove(type, table_name);
3985 out_free:
3986         if (type == AF_INET && repl.r)
3987                 g_free(repl.r->counters);
3988
3989         if (type == AF_INET6 && repl.r6)
3990                 g_free(repl.r6->counters);
3991
3992         g_free(repl.r);
3993         g_free(repl.r6);
3994         
3995         reset_xtables();
3996
3997         return err;
3998 }
3999
4000 static void remove_table(gpointer user_data)
4001 {
4002         struct connman_iptables *table = user_data;
4003
4004         table_cleanup(table);
4005 }
4006
4007 static int iterate_chains_cb(struct connman_iptables_entry *entry, int builtin,
4008                                 unsigned int hook, size_t size,
4009                                 unsigned int offset, void *user_data)
4010 {
4011         struct cb_data *cbd = user_data;
4012         connman_iptables_iterate_chains_cb_t cb = cbd->cb;
4013         struct xt_entry_target *target;
4014
4015         if (offset + iptables_entry_get_next_offset(entry) == size)
4016                 return 0;
4017
4018         target = iptables_entry_get_target(entry);
4019
4020         if (!g_strcmp0(target->u.user.name, get_error_target(entry->type))) {
4021                 (*cb)((const char *)target->data, cbd->user_data);
4022         } else if (builtin >= 0) {
4023                 (*cb)(hooknames[builtin], cbd->user_data);
4024         }
4025
4026         return 0;
4027 }
4028
4029 int __connman_iptables_iterate_chains(int type, const char *table_name,
4030                                 connman_iptables_iterate_chains_cb_t cb,
4031                                 void *user_data)
4032 {
4033         struct cb_data *cbd = cb_data_new(cb, user_data);
4034         struct connman_iptables *table;
4035         struct connman_iptables_entry entry = { 0 };
4036         int err;
4037
4038         err = setup_xtables(type);
4039         
4040         if (err < 0)
4041                 return err;
4042
4043         table = get_table(type, table_name);
4044         if (!table) {
4045                 g_free(cbd);
4046                 return -EINVAL;
4047         }
4048
4049         entry.type = type;
4050
4051         if (type == AF_INET)
4052                 entry.entry = table->blob_entries->entrytable;
4053
4054         if (type == AF_INET6)
4055                 entry.entry6 = table->blob_entries6->entrytable;
4056
4057         iterate_entries(&entry,
4058                         iptables_table_get_info_valid_hooks(table),
4059                         iptables_table_get_info_hook_entry(table),
4060                         iptables_table_get_info_underflow(table),
4061                         iptables_table_get_entries_size(table),
4062                         iterate_chains_cb, cbd);
4063
4064         g_free(cbd);
4065         
4066         reset_xtables();
4067
4068         return 0;
4069 }
4070
4071 int __connman_iptables_init(void)
4072 {
4073         DBG("");
4074
4075         if (getenv("CONNMAN_IPTABLES_DEBUG"))
4076                 debug_enabled = true;
4077
4078         table_hash = g_hash_table_new_full(g_str_hash, g_str_equal,
4079                                                 NULL, remove_table);
4080
4081         table_hash_ipv6 = g_hash_table_new_full(g_str_hash, g_str_equal,
4082                                                 NULL, remove_table);
4083
4084         return 0;
4085 }
4086
4087 void __connman_iptables_cleanup(void)
4088 {
4089         DBG("");
4090
4091         g_hash_table_destroy(table_hash);
4092         g_hash_table_destroy(table_hash_ipv6);
4093 }
4094